Linux-2.6.12-rc2

Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
new file mode 100644
index 0000000..a2b18f5
--- /dev/null
+++ b/drivers/scsi/3w-9xxx.c
@@ -0,0 +1,2167 @@
+/*
+   3w-9xxx.c -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004-2005 Applied Micro Circuits Corporation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+
+   Note: This version of the driver does not contain a bundled firmware
+         image.
+
+   History
+   -------
+   2.26.02.000 - Driver cleanup for kernel submission.
+   2.26.02.001 - Replace schedule_timeout() calls with msleep().
+   2.26.02.002 - Add support for PAE mode.
+                 Add lun support.
+                 Fix twa_remove() to free irq handler/unregister_chrdev()
+                 before shutting down card.
+                 Change to new 'change_queue_depth' api.
+                 Fix 'handled=1' ISR usage, remove bogus IRQ check.
+                 Remove un-needed eh_abort handler.
+                 Add support for embedded firmware error strings.
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-9xxx.h"
+
+/* Globals */
+#define TW_DRIVER_VERSION "2.26.02.002"
+static TW_Device_Extension *twa_device_extension_list[TW_MAX_SLOT];
+static unsigned int twa_device_extension_count;
+static int twa_major = -1;
+extern struct timezone sys_tz;
+
+/* Module parameters */
+MODULE_AUTHOR ("AMCC");
+MODULE_DESCRIPTION ("3ware 9000 Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
+
+/* Function prototypes */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header);
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_aen_severity_lookup(unsigned char severity_code);
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id);
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+static int twa_chrdev_open(struct inode *inode, struct file *file);
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host);
+static void twa_free_request_id(TW_Device_Extension *tw_dev,int request_id);
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id);
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl, 
+			      unsigned short current_fw_arch_id, 
+			      unsigned short current_fw_branch, 
+			      unsigned short current_fw_build, 
+			      unsigned short *fw_on_ctlr_srl, 
+			      unsigned short *fw_on_ctlr_arch_id, 
+			      unsigned short *fw_on_ctlr_branch, 
+			      unsigned short *fw_on_ctlr_build, 
+			      u32 *init_connect_result);
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length);
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds);
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal);
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset);
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg);
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id);
+static char *twa_string_lookup(twa_message_type *table, unsigned int aen_code);
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id);
+
+/* Functions */
+
+/* Show some statistics about the card */
+static ssize_t twa_show_stats(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE, "3w-9xxx Driver version: %s\n"
+		       "Current commands posted:   %4d\n"
+		       "Max commands posted:       %4d\n"
+		       "Current pending commands:  %4d\n"
+		       "Max pending commands:      %4d\n"
+		       "Last sgl length:           %4d\n"
+		       "Max sgl length:            %4d\n"
+		       "Last sector count:         %4d\n"
+		       "Max sector count:          %4d\n"
+		       "SCSI Host Resets:          %4d\n"
+		       "AEN's:                     %4d\n", 
+		       TW_DRIVER_VERSION,
+		       tw_dev->posted_request_count,
+		       tw_dev->max_posted_request_count,
+		       tw_dev->pending_request_count,
+		       tw_dev->max_pending_request_count,
+		       tw_dev->sgl_entries,
+		       tw_dev->max_sgl_entries,
+		       tw_dev->sector_count,
+		       tw_dev->max_sector_count,
+		       tw_dev->num_resets,
+		       tw_dev->aen_count);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+	return len;
+} /* End twa_show_stats() */
+
+/* This function will set a devices queue depth */
+static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+	if (queue_depth > TW_Q_LENGTH-2)
+		queue_depth = TW_Q_LENGTH-2;
+	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+	return queue_depth;
+} /* End twa_change_queue_depth() */
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute twa_host_stats_attr = {
+	.attr = {
+		.name = 	"stats",
+		.mode =		S_IRUGO,
+	},
+	.show = twa_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *twa_host_attrs[] = {
+	&twa_host_stats_attr,
+	NULL,
+};
+
+/* File operations struct for character device */
+static struct file_operations twa_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= twa_chrdev_ioctl,
+	.open		= twa_chrdev_open,
+	.release	= NULL
+};
+
+/* This function will complete an aen request from the isr */
+static int twa_aen_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int retval = 1;
+
+	header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+	tw_dev->posted_request_count--;
+	aen = header->status_block.error;
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	command_packet = &full_command_packet->command.oldcommand;
+
+	/* First check for internal completion of set param for time sync */
+	if (TW_OP_OUT(command_packet->opcode__sgloffset) == TW_OP_SET_PARAM) {
+		/* Keep reading the queue in case there are more aen's */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+	        else {
+			retval = 0;
+			goto out;
+		}
+	}
+
+	switch (aen) {
+	case TW_AEN_QUEUE_EMPTY:
+		/* Quit reading the queue if this is the last one */
+		break;
+	case TW_AEN_SYNC_TIME_WITH_HOST:
+		twa_aen_sync_time(tw_dev, request_id);
+		retval = 0;
+		goto out;
+	default:
+		twa_aen_queue_event(tw_dev, header);
+
+		/* If there are more aen's, keep reading the queue */
+		if (twa_aen_read_queue(tw_dev, request_id))
+			goto out2;
+		else {
+			retval = 0;
+			goto out;
+		}
+	}
+	retval = 0;
+out2:
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	twa_free_request_id(tw_dev, request_id);
+	clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+out:
+	return retval;
+} /* End twa_aen_complete() */
+
+/* This function will drain aen queue */
+static int twa_aen_drain_queue(TW_Device_Extension *tw_dev, int no_check_reset)
+{
+	int request_id = 0;
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Entry sglist[1];
+	int finished = 0, count = 0;
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache_Header *header;
+	unsigned short aen;
+	int first_reset = 0, queue = 0, retval = 1;
+
+	if (no_check_reset)
+		first_reset = 0;
+	else
+		first_reset = 1;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Entry));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	if (sglist[0].address & TW_ALIGNMENT_9000_SGL) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1, "Found unaligned address during AEN drain");
+		goto out;
+	}
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	do {
+		/* Send command to the board */
+		if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2, "Error posting request sense");
+			goto out;
+		}
+
+		/* Now poll for completion */
+		if (twa_poll_response(tw_dev, request_id, 30)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x3, "No valid response while draining AEN queue");
+			tw_dev->posted_request_count--;
+			goto out;
+		}
+
+		tw_dev->posted_request_count--;
+		header = (TW_Command_Apache_Header *)tw_dev->generic_buffer_virt[request_id];
+		aen = header->status_block.error;
+		queue = 0;
+		count++;
+
+		switch (aen) {
+		case TW_AEN_QUEUE_EMPTY:
+			if (first_reset != 1)
+				goto out;
+			else
+				finished = 1;
+			break;
+		case TW_AEN_SOFT_RESET:
+			if (first_reset == 0)
+				first_reset = 1;
+			else
+				queue = 1;
+			break;
+		case TW_AEN_SYNC_TIME_WITH_HOST:
+			break;
+		default:
+			queue = 1;
+		}
+
+		/* Now queue an event info */
+		if (queue)
+			twa_aen_queue_event(tw_dev, header);
+	} while ((finished == 0) && (count < TW_MAX_AEN_DRAIN));
+
+	if (count == TW_MAX_AEN_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	tw_dev->state[request_id] = TW_S_INITIAL;
+	return retval;
+} /* End twa_aen_drain_queue() */
+
+/* This function will queue an event */
+static void twa_aen_queue_event(TW_Device_Extension *tw_dev, TW_Command_Apache_Header *header)
+{
+	u32 local_time;
+	struct timeval time;
+	TW_Event *event;
+	unsigned short aen;
+	char host[16];
+	char *error_str;
+
+	tw_dev->aen_count++;
+
+	/* Fill out event info */
+	event = tw_dev->event_queue[tw_dev->error_index];
+
+	/* Check for clobber */
+	host[0] = '\0';
+	if (tw_dev->host) {
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+		if (event->retrieved == TW_AEN_NOT_RETRIEVED)
+			tw_dev->aen_clobber = 1;
+	}
+
+	aen = header->status_block.error;
+	memset(event, 0, sizeof(TW_Event));
+
+	event->severity = TW_SEV_OUT(header->status_block.severity__reserved);
+	do_gettimeofday(&time);
+	local_time = (u32)(time.tv_sec - (sys_tz.tz_minuteswest * 60));
+	event->time_stamp_sec = local_time;
+	event->aen_code = aen;
+	event->retrieved = TW_AEN_NOT_RETRIEVED;
+	event->sequence_id = tw_dev->error_sequence_id;
+	tw_dev->error_sequence_id++;
+
+	/* Check for embedded error string */
+	error_str = &(header->err_specific_desc[strlen(header->err_specific_desc)+1]);
+
+	header->err_specific_desc[sizeof(header->err_specific_desc) - 1] = '\0';
+	event->parameter_len = strlen(header->err_specific_desc);
+	memcpy(event->parameter_data, header->err_specific_desc, event->parameter_len);
+	if (event->severity != TW_AEN_SEVERITY_DEBUG)
+		printk(KERN_WARNING "3w-9xxx:%s AEN: %s (0x%02X:0x%04X): %s:%s.\n",
+		       host,
+		       twa_aen_severity_lookup(TW_SEV_OUT(header->status_block.severity__reserved)),
+		       TW_MESSAGE_SOURCE_CONTROLLER_EVENT, aen,
+		       error_str[0] == '\0' ? twa_string_lookup(twa_aen_table, aen) : error_str,
+		       header->err_specific_desc);
+	else
+		tw_dev->aen_count--;
+
+	if ((tw_dev->error_index + 1) == TW_Q_LENGTH)
+		tw_dev->event_queue_wrapped = 1;
+	tw_dev->error_index = (tw_dev->error_index + 1 ) % TW_Q_LENGTH;
+} /* End twa_aen_queue_event() */
+
+/* This function will read the aen queue from the isr */
+static int twa_aen_read_queue(TW_Device_Extension *tw_dev, int request_id)
+{
+	char cdb[TW_MAX_CDB_LEN];
+	TW_SG_Entry sglist[1];
+	TW_Command_Full *full_command_packet;
+	int retval = 1;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+
+	/* Initialize cdb */
+	memset(&cdb, 0, TW_MAX_CDB_LEN);
+	cdb[0] = REQUEST_SENSE; /* opcode */
+	cdb[4] = TW_ALLOCATION_LENGTH; /* allocation length */
+
+	/* Initialize sglist */
+	memset(&sglist, 0, sizeof(TW_SG_Entry));
+	sglist[0].length = TW_SECTOR_SIZE;
+	sglist[0].address = tw_dev->generic_buffer_phys[request_id];
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command packet */
+	if (twa_scsiop_execute_scsi(tw_dev, request_id, cdb, 1, sglist)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x4, "Post failed while reading AEN queue");
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_aen_read_queue() */
+
+/* This function will look up an AEN severity string */
+static char *twa_aen_severity_lookup(unsigned char severity_code)
+{
+	char *retval = NULL;
+
+	if ((severity_code < (unsigned char) TW_AEN_SEVERITY_ERROR) ||
+	    (severity_code > (unsigned char) TW_AEN_SEVERITY_DEBUG))
+		goto out;
+
+	retval = twa_aen_severity_table[severity_code];
+out:
+	return retval;
+} /* End twa_aen_severity_lookup() */
+
+/* This function will sync firmware time with the host time */
+static void twa_aen_sync_time(TW_Device_Extension *tw_dev, int request_id)
+{
+	u32 schedulertime;
+	struct timeval utc;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	u32 local_time;
+
+	/* Fill out the command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+	command_packet->request_id = request_id;
+	command_packet->byte8_offset.param.sgl[0].address = tw_dev->generic_buffer_phys[request_id];
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+	command_packet->size = TW_COMMAND_SIZE;
+	command_packet->byte6_offset.parameter_count = 1;
+
+	/* Setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = TW_TIMEKEEP_TABLE | 0x8000; /* Controller time keep table */
+	param->parameter_id = 0x3; /* SchedulerTime */
+	param->parameter_size_bytes = 4;
+
+	/* Convert system time in UTC to local time seconds since last 
+           Sunday 12:00AM */
+	do_gettimeofday(&utc);
+	local_time = (u32)(utc.tv_sec - (sys_tz.tz_minuteswest * 60));
+	schedulertime = local_time - (3 * 86400);
+	schedulertime = schedulertime % 604800;
+
+	memcpy(param->data, &schedulertime, sizeof(u32));
+
+	/* Mark internal command */
+	tw_dev->srb[request_id] = NULL;
+
+	/* Now post the command */
+	twa_post_command_packet(tw_dev, request_id, 1);
+} /* End twa_aen_sync_time() */
+
+/* This function will allocate memory and check if it is correctly aligned */
+static int twa_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+	int i;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr;
+	int retval = 1;
+
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+	if (!cpu_addr) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x5, "Memory allocation failed");
+		goto out;
+	}
+
+	if ((unsigned long)cpu_addr % (TW_ALIGNMENT_9000)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x6, "Failed to allocate correctly aligned memory");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+		goto out;
+	}
+
+	memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_phys[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virt[i] = (TW_Command_Full *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		case 1:
+			tw_dev->generic_buffer_phys[i] = dma_handle+(i*size);
+			tw_dev->generic_buffer_virt[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_allocate_memory() */
+
+/* This function will check the status register for unexpected bits */
+static int twa_check_bits(u32 status_reg_value)
+{
+	int retval = 1;
+
+	if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS)
+		goto out;
+	if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_bits() */
+
+/* This function will check the srl and decide if we are compatible  */
+static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
+{
+	int retval = 1;
+	unsigned short fw_on_ctlr_srl = 0, fw_on_ctlr_arch_id = 0;
+	unsigned short fw_on_ctlr_branch = 0, fw_on_ctlr_build = 0;
+	u32 init_connect_result = 0;
+
+	if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+			       TW_EXTENDED_INIT_CONNECT, TW_CURRENT_DRIVER_SRL,
+			       TW_9000_ARCH_ID, TW_CURRENT_DRIVER_BRANCH,
+			       TW_CURRENT_DRIVER_BUILD, &fw_on_ctlr_srl,
+			       &fw_on_ctlr_arch_id, &fw_on_ctlr_branch,
+			       &fw_on_ctlr_build, &init_connect_result)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x7, "Initconnection failed while checking SRL");
+		goto out;
+	}
+
+	tw_dev->working_srl = fw_on_ctlr_srl;
+	tw_dev->working_branch = fw_on_ctlr_branch;
+	tw_dev->working_build = fw_on_ctlr_build;
+
+	/* Try base mode compatibility */
+	if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+		if (twa_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS,
+				       TW_EXTENDED_INIT_CONNECT,
+				       TW_BASE_FW_SRL, TW_9000_ARCH_ID,
+				       TW_BASE_FW_BRANCH, TW_BASE_FW_BUILD,
+				       &fw_on_ctlr_srl, &fw_on_ctlr_arch_id,
+				       &fw_on_ctlr_branch, &fw_on_ctlr_build,
+				       &init_connect_result)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0xa, "Initconnection (base mode) failed while checking SRL");
+			goto out;
+		}
+		if (!(init_connect_result & TW_CTLR_FW_COMPATIBLE)) {
+			if (TW_CURRENT_DRIVER_SRL > fw_on_ctlr_srl) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x32, "Firmware and driver incompatibility: please upgrade firmware");
+			} else {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x33, "Firmware and driver incompatibility: please upgrade driver");
+			}
+			goto out;
+		}
+		tw_dev->working_srl = TW_BASE_FW_SRL;
+		tw_dev->working_branch = TW_BASE_FW_BRANCH;
+		tw_dev->working_build = TW_BASE_FW_BUILD;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_check_srl() */
+
+/* This function handles ioctl for the character device */
+static int twa_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long timeout;
+	unsigned long *cpu_addr, data_buffer_length_adjusted = 0, flags = 0;
+	dma_addr_t dma_handle;
+	int request_id = 0;
+	unsigned int sequence_id = 0;
+	unsigned char event_index, start_index;
+	TW_Ioctl_Driver_Command driver_command;
+	TW_Ioctl_Buf_Apache *tw_ioctl;
+	TW_Lock *tw_lock;
+	TW_Command_Full *full_command_packet;
+	TW_Compatibility_Info *tw_compat_info;
+	TW_Event *event;
+	struct timeval current_time;
+	u32 current_time_ms;
+	TW_Device_Extension *tw_dev = twa_device_extension_list[iminor(inode)];
+	int retval = TW_IOCTL_ERROR_OS_EFAULT;
+	void __user *argp = (void __user *)arg;
+
+	/* Only let one of these through at a time */
+	if (down_interruptible(&tw_dev->ioctl_sem)) {
+		retval = TW_IOCTL_ERROR_OS_EINTR;
+		goto out;
+	}
+
+	/* First copy down the driver command */
+	if (copy_from_user(&driver_command, argp, sizeof(TW_Ioctl_Driver_Command)))
+		goto out2;
+
+	/* Check data buffer size */
+	if (driver_command.buffer_length > TW_MAX_SECTORS * 512) {
+		retval = TW_IOCTL_ERROR_OS_EINVAL;
+		goto out2;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	data_buffer_length_adjusted = (driver_command.buffer_length + 511) & ~511;
+
+	/* Now allocate ioctl buf memory */
+	cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, &dma_handle, GFP_KERNEL);
+	if (!cpu_addr) {
+		retval = TW_IOCTL_ERROR_OS_ENOMEM;
+		goto out2;
+	}
+
+	tw_ioctl = (TW_Ioctl_Buf_Apache *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	if (copy_from_user(tw_ioctl, argp, driver_command.buffer_length + sizeof(TW_Ioctl_Buf_Apache) - 1))
+		goto out3;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+	case TW_IOCTL_FIRMWARE_PASS_THROUGH:
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		twa_get_request_id(tw_dev, &request_id);
+
+		/* Flag internal command */
+		tw_dev->srb[request_id] = NULL;
+
+		/* Flag chrdev ioctl */
+		tw_dev->chrdev_request_id = request_id;
+
+		full_command_packet = &tw_ioctl->firmware_command;
+
+		/* Load request id and sglist for both command types */
+		twa_load_sgl(full_command_packet, request_id, dma_handle, data_buffer_length_adjusted);
+
+		memcpy(tw_dev->command_packet_virt[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command_Full));
+
+		/* Now post the command packet to the controller */
+		twa_post_command_packet(tw_dev, request_id, 1);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+		timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+		/* Now wait for command to complete */
+		timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+		/* See if we reset while waiting for the ioctl to complete */
+		if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+			clear_bit(TW_IN_RESET, &tw_dev->flags);
+			retval = TW_IOCTL_ERROR_OS_ERESTARTSYS;
+			goto out3;
+		}
+
+		/* We timed out, and didn't get an interrupt */
+		if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+			/* Now we need to reset the board */
+			printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Character ioctl (0x%x) timed out, resetting card.\n",
+			       tw_dev->host->host_no, TW_DRIVER, 0xc,
+			       cmd);
+			retval = TW_IOCTL_ERROR_OS_EIO;
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			twa_free_request_id(tw_dev, request_id);
+			tw_dev->posted_request_count--;
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			twa_reset_device_extension(tw_dev, 1);
+			goto out3;
+		}
+
+		/* Now copy in the command packet response */
+		memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virt[request_id], sizeof(TW_Command_Full));
+		
+		/* Now complete the io */
+		spin_lock_irqsave(tw_dev->host->host_lock, flags);
+		tw_dev->posted_request_count--;
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+		break;
+	case TW_IOCTL_GET_COMPATIBILITY_INFO:
+		tw_ioctl->driver_command.status = 0;
+		/* Copy compatiblity struct into ioctl data buffer */
+		tw_compat_info = (TW_Compatibility_Info *)tw_ioctl->data_buffer;
+		strncpy(tw_compat_info->driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
+		tw_compat_info->working_srl = tw_dev->working_srl;
+		tw_compat_info->working_branch = tw_dev->working_branch;
+		tw_compat_info->working_build = tw_dev->working_build;
+		tw_compat_info->driver_srl_high = TW_CURRENT_DRIVER_SRL;
+		tw_compat_info->driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
+		tw_compat_info->driver_build_high = TW_CURRENT_DRIVER_BUILD;
+		tw_compat_info->driver_srl_low = TW_BASE_FW_SRL;
+		tw_compat_info->driver_branch_low = TW_BASE_FW_BRANCH;
+		tw_compat_info->driver_build_low = TW_BASE_FW_BUILD;
+		break;
+	case TW_IOCTL_GET_LAST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else
+				tw_ioctl->driver_command.status = 0;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+		}
+		event_index = (tw_dev->error_index - 1 + TW_Q_LENGTH) % TW_Q_LENGTH;
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_FIRST_EVENT:
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			} else 
+				tw_ioctl->driver_command.status = 0;
+			event_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			tw_ioctl->driver_command.status = 0;
+			event_index = 0;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_NEXT_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id + 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id > sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_PREVIOUS_EVENT:
+		event = (TW_Event *)tw_ioctl->data_buffer;
+		sequence_id = event->sequence_id;
+		tw_ioctl->driver_command.status = 0;
+
+		if (tw_dev->event_queue_wrapped) {
+			if (tw_dev->aen_clobber) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_AEN_CLOBBER;
+				tw_dev->aen_clobber = 0;
+			}
+			start_index = tw_dev->error_index;
+		} else {
+			if (!tw_dev->error_index) {
+				tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+				break;
+			}
+			start_index = 0;
+		}
+		event_index = (start_index + sequence_id - tw_dev->event_queue[start_index]->sequence_id - 1) % TW_Q_LENGTH;
+
+		if (!(tw_dev->event_queue[event_index]->sequence_id < sequence_id)) {
+			if (tw_ioctl->driver_command.status == TW_IOCTL_ERROR_STATUS_AEN_CLOBBER)
+				tw_dev->aen_clobber = 1;
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS;
+			break;
+		}
+		memcpy(tw_ioctl->data_buffer, tw_dev->event_queue[event_index], sizeof(TW_Event));
+		tw_dev->event_queue[event_index]->retrieved = TW_AEN_RETRIEVED;
+		break;
+	case TW_IOCTL_GET_LOCK:
+		tw_lock = (TW_Lock *)tw_ioctl->data_buffer;
+		do_gettimeofday(&current_time);
+		current_time_ms = (current_time.tv_sec * 1000) + (current_time.tv_usec / 1000);
+
+		if ((tw_lock->force_flag == 1) || (tw_dev->ioctl_sem_lock == 0) || (current_time_ms >= tw_dev->ioctl_msec)) {
+			tw_dev->ioctl_sem_lock = 1;
+			tw_dev->ioctl_msec = current_time_ms + tw_lock->timeout_msec;
+			tw_ioctl->driver_command.status = 0;
+			tw_lock->time_remaining_msec = tw_lock->timeout_msec;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_LOCKED;
+			tw_lock->time_remaining_msec = tw_dev->ioctl_msec - current_time_ms;
+		}
+		break;
+	case TW_IOCTL_RELEASE_LOCK:
+		if (tw_dev->ioctl_sem_lock == 1) {
+			tw_dev->ioctl_sem_lock = 0;
+			tw_ioctl->driver_command.status = 0;
+		} else {
+			tw_ioctl->driver_command.status = TW_IOCTL_ERROR_STATUS_NOT_LOCKED;
+		}
+		break;
+	default:
+		retval = TW_IOCTL_ERROR_OS_ENOTTY;
+		goto out3;
+	}
+
+	/* Now copy the entire response to userspace */
+	if (copy_to_user(argp, tw_ioctl, sizeof(TW_Ioctl_Buf_Apache) + driver_command.buffer_length - 1) == 0)
+		retval = 0;
+out3:
+	/* Now free ioctl buf memory */
+	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_Ioctl_Buf_Apache) - 1, cpu_addr, dma_handle);
+out2:
+	up(&tw_dev->ioctl_sem);
+out:
+	return retval;
+} /* End twa_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int twa_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+	int retval = TW_IOCTL_ERROR_OS_ENODEV;
+
+	minor_number = iminor(inode);
+	if (minor_number >= twa_device_extension_count)
+		goto out;
+	retval = 0;
+out:
+	return retval;
+} /* End twa_chrdev_open() */
+
+/* This function will print readable messages from status register errors */
+static int twa_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value)
+{
+	int retval = 1;
+
+	/* Check for various error conditions and handle them appropriately */
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xc, "PCI Parity Error: clearing");
+		writel(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xd, "PCI Abort: clearing");
+		writel(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+	}
+
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xe, "Controller Queue Error: clearing");
+		writel(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0xf, "SBUF Write Error: clearing");
+		writel(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x10, "Microcontroller Error: clearing");
+			tw_dev->reset_print = 1;
+		}
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_decode_bits() */
+
+/* This function will empty the response queue */
+static int twa_empty_response_queue(TW_Device_Extension *tw_dev)
+{
+	u32 status_reg_value, response_que_value;
+	int count = 0, retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	while (((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) && (count < TW_MAX_RESPONSE_DRAIN)) {
+		response_que_value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		count++;
+	}
+	if (count == TW_MAX_RESPONSE_DRAIN)
+		goto out;
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_empty_response_queue() */
+
+/* This function passes sense keys from firmware to scsi layer */
+static int twa_fill_sense(TW_Device_Extension *tw_dev, int request_id, int copy_sense, int print_host)
+{
+	TW_Command_Full *full_command_packet;
+	unsigned short error;
+	int retval = 1;
+	char *error_str;
+
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+
+	/* Check for embedded error string */
+	error_str = &(full_command_packet->header.err_specific_desc[strlen(full_command_packet->header.err_specific_desc) + 1]);
+
+	/* Don't print error for Logical unit not supported during rollcall */
+	error = full_command_packet->header.status_block.error;
+	if ((error != TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED) && (error != TW_ERROR_UNIT_OFFLINE)) {
+		if (print_host)
+			printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+			       tw_dev->host->host_no,
+			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+			       full_command_packet->header.status_block.error,
+			       error_str[0] == '\0' ?
+			       twa_string_lookup(twa_error_table,
+						 full_command_packet->header.status_block.error) : error_str,
+			       full_command_packet->header.err_specific_desc);
+		else
+			printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s:%s.\n",
+			       TW_MESSAGE_SOURCE_CONTROLLER_ERROR,
+			       full_command_packet->header.status_block.error,
+			       error_str[0] == '\0' ?
+			       twa_string_lookup(twa_error_table,
+						 full_command_packet->header.status_block.error) : error_str,
+			       full_command_packet->header.err_specific_desc);
+	}
+
+	if (copy_sense) {
+		memcpy(tw_dev->srb[request_id]->sense_buffer, full_command_packet->header.sense_data, TW_SENSE_DATA_LENGTH);
+		tw_dev->srb[request_id]->result = (full_command_packet->command.newcommand.status << 1);
+		retval = TW_ISR_DONT_RESULT;
+		goto out;
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_fill_sense() */
+
+/* This function will free up device extension resources */
+static void twa_free_device_extension(TW_Device_Extension *tw_dev)
+{
+	if (tw_dev->command_packet_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev,
+				    sizeof(TW_Command_Full)*TW_Q_LENGTH,
+				    tw_dev->command_packet_virt[0],
+				    tw_dev->command_packet_phys[0]);
+
+	if (tw_dev->generic_buffer_virt[0])
+		pci_free_consistent(tw_dev->tw_pci_dev,
+				    TW_SECTOR_SIZE*TW_Q_LENGTH,
+				    tw_dev->generic_buffer_virt[0],
+				    tw_dev->generic_buffer_phys[0]);
+
+	if (tw_dev->event_queue[0])
+		kfree(tw_dev->event_queue[0]);
+} /* End twa_free_device_extension() */
+
+/* This function will free a request id */
+static void twa_free_request_id(TW_Device_Extension *tw_dev, int request_id)
+{
+	tw_dev->free_queue[tw_dev->free_tail] = request_id;
+	tw_dev->state[request_id] = TW_S_FINISHED;
+	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End twa_free_request_id() */
+
+/* This function will get parameter table entires from the firmware */
+static void *twa_get_param(TW_Device_Extension *tw_dev, int request_id, int table_id, int parameter_id, int parameter_size_bytes)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Param_Apache *param;
+	unsigned long param_value;
+	void *retval = NULL;
+
+	/* Setup the command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	command_packet = &full_command_packet->command.oldcommand;
+
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size              = TW_COMMAND_SIZE;
+	command_packet->request_id        = request_id;
+	command_packet->byte6_offset.block_count = 1;
+
+	/* Now setup the param */
+	param = (TW_Param_Apache *)tw_dev->generic_buffer_virt[request_id];
+	memset(param, 0, TW_SECTOR_SIZE);
+	param->table_id = table_id | 0x8000;
+	param->parameter_id = parameter_id;
+	param->parameter_size_bytes = parameter_size_bytes;
+	param_value = tw_dev->generic_buffer_phys[request_id];
+
+	command_packet->byte8_offset.param.sgl[0].address = param_value;
+	command_packet->byte8_offset.param.sgl[0].length = TW_SECTOR_SIZE;
+
+	/* Post the command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30))
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x13, "No valid response during get param")
+	else
+		retval = (void *)&(param->data[0]);
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_get_param() */
+
+/* This function will assign an available request id */
+static void twa_get_request_id(TW_Device_Extension *tw_dev, int *request_id)
+{
+	*request_id = tw_dev->free_queue[tw_dev->free_head];
+	tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+	tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End twa_get_request_id() */
+
+/* This function will send an initconnection command to controller */
+static int twa_initconnection(TW_Device_Extension *tw_dev, int message_credits,
+ 			      u32 set_features, unsigned short current_fw_srl, 
+			      unsigned short current_fw_arch_id, 
+			      unsigned short current_fw_branch, 
+			      unsigned short current_fw_build, 
+			      unsigned short *fw_on_ctlr_srl, 
+			      unsigned short *fw_on_ctlr_arch_id, 
+			      unsigned short *fw_on_ctlr_branch, 
+			      unsigned short *fw_on_ctlr_build, 
+			      u32 *init_connect_result)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Initconnect *tw_initconnect;
+	int request_id = 0, retval = 1;
+
+	/* Initialize InitConnection command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	memset(full_command_packet, 0, sizeof(TW_Command_Full));
+	full_command_packet->header.header_desc.size_header = 128;
+	
+	tw_initconnect = (TW_Initconnect *)&full_command_packet->command.oldcommand;
+	tw_initconnect->opcode__reserved = TW_OPRES_IN(0, TW_OP_INIT_CONNECTION);
+	tw_initconnect->request_id = request_id;
+	tw_initconnect->message_credits = message_credits;
+	tw_initconnect->features = set_features;
+
+	/* Turn on 64-bit sgl support if we need to */
+	tw_initconnect->features |= sizeof(dma_addr_t) > 4 ? 1 : 0;
+
+	if (set_features & TW_EXTENDED_INIT_CONNECT) {
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE_EXTENDED;
+		tw_initconnect->fw_srl = current_fw_srl;
+		tw_initconnect->fw_arch_id = current_fw_arch_id;
+		tw_initconnect->fw_branch = current_fw_branch;
+		tw_initconnect->fw_build = current_fw_build;
+	} else 
+		tw_initconnect->size = TW_INIT_COMMAND_PACKET_SIZE;
+
+	/* Send command packet to the board */
+	twa_post_command_packet(tw_dev, request_id, 1);
+
+	/* Poll for completion */
+	if (twa_poll_response(tw_dev, request_id, 30)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x15, "No valid response during init connection");
+	} else {
+		if (set_features & TW_EXTENDED_INIT_CONNECT) {
+			*fw_on_ctlr_srl = tw_initconnect->fw_srl;
+			*fw_on_ctlr_arch_id = tw_initconnect->fw_arch_id;
+			*fw_on_ctlr_branch = tw_initconnect->fw_branch;
+			*fw_on_ctlr_build = tw_initconnect->fw_build;
+			*init_connect_result = tw_initconnect->result;
+		}
+		retval = 0;
+	}
+
+	tw_dev->posted_request_count--;
+	tw_dev->state[request_id] = TW_S_INITIAL;
+
+	return retval;
+} /* End twa_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+static int twa_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i, retval = 1;
+
+	/* Initialize command packet buffers */
+	if (twa_allocate_memory(tw_dev, sizeof(TW_Command_Full), 0)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x16, "Command packet memory allocation failed");
+		goto out;
+	}
+
+	/* Initialize generic buffer */
+	if (twa_allocate_memory(tw_dev, TW_SECTOR_SIZE, 1)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x17, "Generic memory allocation failed");
+		goto out;
+	}
+
+	/* Allocate event info space */
+	tw_dev->event_queue[0] = kmalloc(sizeof(TW_Event) * TW_Q_LENGTH, GFP_KERNEL);
+	if (!tw_dev->event_queue[0]) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x18, "Event info memory allocation failed");
+		goto out;
+	}
+
+	memset(tw_dev->event_queue[0], 0, sizeof(TW_Event) * TW_Q_LENGTH);
+
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->event_queue[i] = (TW_Event *)((unsigned char *)tw_dev->event_queue[0] + (i * sizeof(TW_Event)));
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->error_sequence_id = 1;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+	init_MUTEX(&tw_dev->ioctl_sem);
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+	retval = 0;
+out:
+	return retval;
+} /* End twa_initialize_device_extension() */
+
+/* This function is the interrupt service routine */
+static irqreturn_t twa_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	int request_id, error = 0;
+	u32 status_reg_value;
+	TW_Response_Queue response_que;
+	TW_Command_Full *full_command_packet;
+	TW_Command *command_packet;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+	int handled = 0;
+
+	/* Get the per adapter lock */
+	spin_lock(tw_dev->host->host_lock);
+
+	/* Read the registers */
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	/* Check if this is our interrupt, otherwise bail */
+	if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+		goto twa_interrupt_bail;
+
+	handled = 1;
+
+	/* Check controller for errors */
+	if (twa_check_bits(status_reg_value)) {
+		if (twa_decode_bits(tw_dev, status_reg_value)) {
+			TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+			goto twa_interrupt_bail;
+		}
+	}
+
+	/* Handle host interrupt */
+	if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+		TW_CLEAR_HOST_INTERRUPT(tw_dev);
+
+	/* Handle attention interrupt */
+	if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+		TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+		if (!(test_and_set_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags))) {
+			twa_get_request_id(tw_dev, &request_id);
+
+			error = twa_aen_read_queue(tw_dev, request_id);
+			if (error) {
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				twa_free_request_id(tw_dev, request_id);
+				clear_bit(TW_IN_ATTENTION_LOOP, &tw_dev->flags);
+			}
+		}
+	}
+
+	/* Handle command interrupt */
+	if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+		TW_MASK_COMMAND_INTERRUPT(tw_dev);
+		/* Drain as many pending commands as we can */
+		while (tw_dev->pending_request_count > 0) {
+			request_id = tw_dev->pending_queue[tw_dev->pending_head];
+			if (tw_dev->state[request_id] != TW_S_PENDING) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x19, "Found request id that wasn't pending");
+				TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+				goto twa_interrupt_bail;
+			}
+			if (twa_post_command_packet(tw_dev, request_id, 1)==0) {
+				tw_dev->pending_head = (tw_dev->pending_head + 1) % TW_Q_LENGTH;
+				tw_dev->pending_request_count--;
+			} else {
+				/* If we get here, we will continue re-posting on the next command interrupt */
+				break;
+			}
+		}
+	}
+
+	/* Handle response interrupt */
+	if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+
+		/* Drain the response queue from the board */
+		while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+			/* Complete the response */
+			response_que.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+			request_id = TW_RESID_OUT(response_que.response_id);
+			full_command_packet = tw_dev->command_packet_virt[request_id];
+			error = 0;
+			command_packet = &full_command_packet->command.oldcommand;
+			/* Check for command packet errors */
+			if (full_command_packet->command.newcommand.status != 0) {
+				if (tw_dev->srb[request_id] != 0) {
+					error = twa_fill_sense(tw_dev, request_id, 1, 1);
+				} else {
+					/* Skip ioctl error prints */
+					if (request_id != tw_dev->chrdev_request_id) {
+						error = twa_fill_sense(tw_dev, request_id, 0, 1);
+					}
+				}
+			}
+
+			/* Check for correct state */
+			if (tw_dev->state[request_id] != TW_S_POSTED) {
+				if (tw_dev->srb[request_id] != 0) {
+					TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1a, "Received a request id that wasn't posted");
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto twa_interrupt_bail;
+				}
+			}
+
+			/* Check for internal command completion */
+			if (tw_dev->srb[request_id] == 0) {
+				if (request_id != tw_dev->chrdev_request_id) {
+					if (twa_aen_complete(tw_dev, request_id))
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1b, "Error completing AEN during attention interrupt");
+				} else {
+					tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+					wake_up(&tw_dev->ioctl_wqueue);
+				}
+			} else {
+				twa_scsiop_execute_scsi_complete(tw_dev, request_id);
+				/* If no error command was a success */
+				if (error == 0) {
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
+				}
+
+				/* If error, command failed */
+				if (error == 1) {
+					/* Ask for a host reset */
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
+
+				/* Report residual bytes for single sgl */
+				if ((tw_dev->srb[request_id]->use_sg <= 1) && (full_command_packet->command.newcommand.status == 0)) {
+					if (full_command_packet->command.newcommand.sg_list[0].length < tw_dev->srb[request_id]->request_bufflen)
+						tw_dev->srb[request_id]->resid = tw_dev->srb[request_id]->request_bufflen - full_command_packet->command.newcommand.sg_list[0].length;
+				}
+
+				/* Now complete the io */
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				twa_free_request_id(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+				twa_unmap_scsi_data(tw_dev, request_id);
+			}
+
+			/* Check for valid status after each drain */
+			status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+			if (twa_check_bits(status_reg_value)) {
+				if (twa_decode_bits(tw_dev, status_reg_value)) {
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto twa_interrupt_bail;
+				}
+			}
+		}
+	}
+
+twa_interrupt_bail:
+	spin_unlock(tw_dev->host->host_lock);
+	return IRQ_RETVAL(handled);
+} /* End twa_interrupt() */
+
+/* This function will load the request id and various sgls for ioctls */
+static void twa_load_sgl(TW_Command_Full *full_command_packet, int request_id, dma_addr_t dma_handle, int length)
+{
+	TW_Command *oldcommand;
+	TW_Command_Apache *newcommand;
+	TW_SG_Entry *sgl;
+
+	if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+		newcommand = &full_command_packet->command.newcommand;
+		newcommand->request_id__lunl = 
+			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->request_id__lunl), request_id);
+		newcommand->sg_list[0].address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+		newcommand->sg_list[0].length = length;
+		newcommand->sgl_entries__lunh =
+			TW_REQ_LUN_IN(TW_LUN_OUT(newcommand->sgl_entries__lunh), 1);
+	} else {
+		oldcommand = &full_command_packet->command.oldcommand;
+		oldcommand->request_id = request_id;
+
+		if (TW_SGL_OUT(oldcommand->opcode__sgloffset)) {
+			/* Load the sg list */
+			sgl = (TW_SG_Entry *)((u32 *)oldcommand+TW_SGL_OUT(oldcommand->opcode__sgloffset));
+			sgl->address = dma_handle + sizeof(TW_Ioctl_Buf_Apache) - 1;
+			sgl->length = length;
+
+			if ((sizeof(long) < 8) && (sizeof(dma_addr_t) > 4))
+				oldcommand->size += 1;
+		}
+	}
+} /* End twa_load_sgl() */
+
+/* This function will perform a pci-dma mapping for a scatter gather list */
+static int twa_map_scsi_sg_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	int use_sg;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->use_sg == 0)
+		goto out;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+	if (use_sg == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1c, "Failed to map scatter gather list");
+		goto out;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SGLIST;
+	cmd->SCp.have_data_in = use_sg;
+	retval = use_sg;
+out:
+	return retval;
+} /* End twa_map_scsi_sg_data() */
+
+/* This function will perform a pci-dma map for a single buffer */
+static dma_addr_t twa_map_scsi_single_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	dma_addr_t mapping;
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+	int retval = 0;
+
+	if (cmd->request_bufflen == 0) {
+		retval = 0;
+		goto out;
+	}
+
+	mapping = pci_map_single(pdev, cmd->request_buffer, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+	if (mapping == 0) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1d, "Failed to map page");
+		goto out;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SINGLE;
+	cmd->SCp.have_data_in = mapping;
+	retval = mapping;
+out:
+	return retval;
+} /* End twa_map_scsi_single_data() */
+
+/* This function will poll for a response interrupt of a request */
+static int twa_poll_response(TW_Device_Extension *tw_dev, int request_id, int seconds)
+{
+	int retval = 1, found = 0, response_request_id;
+	TW_Response_Queue response_queue;
+	TW_Command_Full *full_command_packet = tw_dev->command_packet_virt[request_id];
+
+	if (twa_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, seconds) == 0) {
+		response_queue.value = readl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		response_request_id = TW_RESID_OUT(response_queue.response_id);
+		if (request_id != response_request_id) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1e, "Found unexpected request id while polling for response");
+			goto out;
+		}
+		if (TW_OP_OUT(full_command_packet->command.newcommand.opcode__reserved) == TW_OP_EXECUTE_SCSI) {
+			if (full_command_packet->command.newcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		} else {
+			if (full_command_packet->command.oldcommand.status != 0) {
+				/* bad response */
+				twa_fill_sense(tw_dev, request_id, 0, 0);
+				goto out;
+			}
+			found = 1;
+		}
+	}
+
+	if (found)
+		retval = 0;
+out:
+	return retval;
+} /* End twa_poll_response() */
+
+/* This function will poll the status register for a flag */
+static int twa_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value; 
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != flag) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status() */
+
+/* This function will poll the status register for disappearance of a flag */
+static int twa_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	while ((status_reg_value & flag) != 0) {
+		status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+		if (twa_check_bits(status_reg_value))
+			twa_decode_bits(tw_dev, status_reg_value);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int twa_post_command_packet(TW_Device_Extension *tw_dev, int request_id, char internal)
+{
+	u32 status_reg_value;
+	dma_addr_t command_que_value;
+	int retval = 1;
+
+	command_que_value = tw_dev->command_packet_phys[request_id];
+	status_reg_value = readl(TW_STATUS_REG_ADDR(tw_dev));
+
+	if (twa_check_bits(status_reg_value))
+		twa_decode_bits(tw_dev, status_reg_value);
+
+	if (((tw_dev->pending_request_count > 0) && (tw_dev->state[request_id] != TW_S_PENDING)) || (status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL)) {
+
+		/* Only pend internal driver commands */
+		if (!internal) {
+			retval = SCSI_MLQUEUE_HOST_BUSY;
+			goto out;
+		}
+
+		/* Couldn't post the command packet, so we do it later */
+		if (tw_dev->state[request_id] != TW_S_PENDING) {
+			tw_dev->state[request_id] = TW_S_PENDING;
+			tw_dev->pending_request_count++;
+			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+				tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+			}
+			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+			tw_dev->pending_tail = (tw_dev->pending_tail + 1) % TW_Q_LENGTH;
+		}
+		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
+		goto out;
+	} else {
+		/* We successfully posted the command packet */
+		if (sizeof(dma_addr_t) > 4) {
+			command_que_value += TW_COMMAND_OFFSET;
+			writel((u32)command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+			writel((u32)((u64)command_que_value >> 32), TW_COMMAND_QUEUE_REG_ADDR(tw_dev) + 0x4);
+		} else {
+			writel(TW_COMMAND_OFFSET + command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+		}
+		tw_dev->state[request_id] = TW_S_POSTED;
+		tw_dev->posted_request_count++;
+		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+			tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+		}
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_post_command_packet() */
+
+/* This function will reset a device extension */
+static int twa_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset)
+{
+	int i = 0;
+	int retval = 1;
+	unsigned long flags = 0;
+
+	set_bit(TW_IN_RESET, &tw_dev->flags);
+	TW_DISABLE_INTERRUPTS(tw_dev);
+	TW_MASK_COMMAND_INTERRUPT(tw_dev);
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+	/* Abort all requests that are in progress */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) &&
+		    (tw_dev->state[i] != TW_S_INITIAL) &&
+		    (tw_dev->state[i] != TW_S_COMPLETED)) {
+			if (tw_dev->srb[i]) {
+				tw_dev->srb[i]->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				twa_unmap_scsi_data(tw_dev, i);
+			}
+		}
+	}
+
+	/* Reset queues and counts */
+	for (i = 0; i < TW_Q_LENGTH; i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->posted_request_count = 0;
+	tw_dev->pending_request_count = 0;
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
+
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+	if (twa_reset_sequence(tw_dev, 1))
+		goto out;
+
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Wake up any ioctl that was pending before the reset */
+	if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
+		clear_bit(TW_IN_RESET, &tw_dev->flags);
+	} else {
+		tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+		wake_up(&tw_dev->ioctl_wqueue);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End twa_reset_device_extension() */
+
+/* This function will reset a controller */
+static int twa_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset)
+{
+	int tries = 0, retval = 1, flashed = 0, do_soft_reset = soft_reset;
+
+	while (tries < TW_MAX_RESET_TRIES) {
+		if (do_soft_reset)
+			TW_SOFT_RESET(tw_dev);
+
+		/* Make sure controller is in a good state */
+		if (twa_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY | (do_soft_reset == 1 ? TW_STATUS_ATTENTION_INTERRUPT : 0), 60)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x1f, "Microcontroller not ready during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* Empty response queue */
+		if (twa_empty_response_queue(tw_dev)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x20, "Response queue empty failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		flashed = 0;
+
+		/* Check for compatibility/flash */
+		if (twa_check_srl(tw_dev, &flashed)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x21, "Compatibility check failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		} else {
+			if (flashed) {
+				tries++;
+				continue;
+			}
+		}
+
+		/* Drain the AEN queue */
+		if (twa_aen_drain_queue(tw_dev, soft_reset)) {
+			TW_PRINTK(tw_dev->host, TW_DRIVER, 0x22, "AEN drain failed during reset sequence");
+			do_soft_reset = 1;
+			tries++;
+			continue;
+		}
+
+		/* If we got here, controller is in a good state */
+		retval = 0;
+		goto out;
+	}
+out:
+	return retval;
+} /* End twa_reset_sequence() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int twa_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int geom[])
+{
+	int heads, sectors, cylinders;
+	TW_Device_Extension *tw_dev;
+
+	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = sector_div(capacity, heads * sectors);
+	} else {
+		heads = 64;
+		sectors = 32;
+		cylinders = sector_div(capacity, heads * sectors);
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+} /* End twa_scsi_biosparam() */
+
+/* This is the new scsi eh reset function */
+static int twa_scsi_eh_reset(struct scsi_cmnd *SCpnt)
+{
+	TW_Device_Extension *tw_dev = NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	spin_unlock_irq(tw_dev->host->host_lock);
+
+	tw_dev->num_resets++;
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: WARNING: (0x%02X:0x%04X): Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, TW_DRIVER, 0x2c, SCpnt->device->id, SCpnt->cmnd[0]);
+
+	/* Now reset the card and some of the device extension data */
+	if (twa_reset_device_extension(tw_dev, 0)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2b, "Controller reset failed during scsi host reset");
+		goto out;
+	}
+
+	retval = SUCCESS;
+out:
+	spin_lock_irq(tw_dev->host->host_lock);
+	return retval;
+} /* End twa_scsi_eh_reset() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int twa_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	int request_id, retval;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	/* Check if this FW supports luns */
+	if ((SCpnt->device->lun != 0) && (tw_dev->working_srl < TW_FW_SRL_LUNS_SUPPORTED)) {
+		SCpnt->result = (DID_BAD_TARGET << 16);
+		done(SCpnt);
+		retval = 0;
+		goto out;
+	}
+
+	/* Save done function into scsi_cmnd struct */
+	SCpnt->scsi_done = done;
+		
+	/* Get a free request id */
+	twa_get_request_id(tw_dev, &request_id);
+
+	/* Save the scsi command for use by the ISR */
+	tw_dev->srb[request_id] = SCpnt;
+
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = TW_PHASE_INITIAL;
+
+	retval = twa_scsiop_execute_scsi(tw_dev, request_id, NULL, 0, NULL);
+	switch (retval) {
+	case SCSI_MLQUEUE_HOST_BUSY:
+		twa_free_request_id(tw_dev, request_id);
+		break;
+	case 1:
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		twa_free_request_id(tw_dev, request_id);
+		SCpnt->result = (DID_ERROR << 16);
+		done(SCpnt);
+		retval = 0;
+	}
+out:
+	return retval;
+} /* End twa_scsi_queue() */
+
+/* This function hands scsi cdb's to the firmware */
+static int twa_scsiop_execute_scsi(TW_Device_Extension *tw_dev, int request_id, char *cdb, int use_sg, TW_SG_Entry *sglistarg)
+{
+	TW_Command_Full *full_command_packet;
+	TW_Command_Apache *command_packet;
+	u32 num_sectors = 0x0;
+	int i, sg_count;
+	struct scsi_cmnd *srb = NULL;
+	struct scatterlist *sglist = NULL;
+	u32 buffaddr = 0x0;
+	int retval = 1;
+
+	if (tw_dev->srb[request_id]) {
+		if (tw_dev->srb[request_id]->request_buffer) {
+			sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+		}
+		srb = tw_dev->srb[request_id];
+	}
+
+	/* Initialize command packet */
+	full_command_packet = tw_dev->command_packet_virt[request_id];
+	full_command_packet->header.header_desc.size_header = 128;
+	full_command_packet->header.status_block.error = 0;
+	full_command_packet->header.status_block.severity__reserved = 0;
+
+	command_packet = &full_command_packet->command.newcommand;
+	command_packet->status = 0;
+	command_packet->opcode__reserved = TW_OPRES_IN(0, TW_OP_EXECUTE_SCSI);
+
+	/* We forced 16 byte cdb use earlier */
+	if (!cdb)
+		memcpy(command_packet->cdb, srb->cmnd, TW_MAX_CDB_LEN);
+	else
+		memcpy(command_packet->cdb, cdb, TW_MAX_CDB_LEN);
+
+	if (srb) {
+		command_packet->unit = srb->device->id;
+		command_packet->request_id__lunl =
+			TW_REQ_LUN_IN(srb->device->lun, request_id);
+	} else {
+		command_packet->request_id__lunl =
+			TW_REQ_LUN_IN(0, request_id);
+		command_packet->unit = 0;
+	}
+
+	command_packet->sgl_offset = 16;
+
+	if (!sglistarg) {
+		/* Map sglist from scsi layer to cmd packet */
+		if (tw_dev->srb[request_id]->use_sg == 0) {
+			if (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH) {
+				command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+			} else {
+				buffaddr = twa_map_scsi_single_data(tw_dev, request_id);
+				if (buffaddr == 0)
+					goto out;
+
+				command_packet->sg_list[0].address = buffaddr;
+				command_packet->sg_list[0].length = tw_dev->srb[request_id]->request_bufflen;
+			}
+			command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), 1);
+
+			if (command_packet->sg_list[0].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2d, "Found unaligned address during execute scsi");
+				goto out;
+			}
+		}
+
+		if (tw_dev->srb[request_id]->use_sg > 0) {
+			if ((tw_dev->srb[request_id]->use_sg == 1) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+				command_packet->sg_list[0].address = tw_dev->generic_buffer_phys[request_id];
+				command_packet->sg_list[0].length = TW_MIN_SGL_LENGTH;
+			} else {
+				sg_count = twa_map_scsi_sg_data(tw_dev, request_id);
+				if (sg_count == 0)
+					goto out;
+
+				for (i = 0; i < sg_count; i++) {
+					command_packet->sg_list[i].address = sg_dma_address(&sglist[i]);
+					command_packet->sg_list[i].length = sg_dma_len(&sglist[i]);
+					if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+						TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2e, "Found unaligned sgl address during execute scsi");
+						goto out;
+					}
+				}
+			}
+			command_packet->sgl_entries__lunh = TW_REQ_LUN_IN((srb->device->lun >> 4), tw_dev->srb[request_id]->use_sg);
+		}
+	} else {
+		/* Internal cdb post */
+		for (i = 0; i < use_sg; i++) {
+			command_packet->sg_list[i].address = sglistarg[i].address;
+			command_packet->sg_list[i].length = sglistarg[i].length;
+			if (command_packet->sg_list[i].address & TW_ALIGNMENT_9000_SGL) {
+				TW_PRINTK(tw_dev->host, TW_DRIVER, 0x2f, "Found unaligned sgl address during internal post");
+				goto out;
+			}
+		}
+		command_packet->sgl_entries__lunh = TW_REQ_LUN_IN(0, use_sg);
+	}
+
+	if (srb) {
+		if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6)
+			num_sectors = (u32)srb->cmnd[4];
+
+		if (srb->cmnd[0] == READ_10 || srb->cmnd[0] == WRITE_10)
+			num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+	}
+
+	/* Update sector statistic */
+	tw_dev->sector_count = num_sectors;
+	if (tw_dev->sector_count > tw_dev->max_sector_count)
+		tw_dev->max_sector_count = tw_dev->sector_count;
+
+	/* Update SG statistics */
+	if (srb) {
+		tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+		if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+			tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+	}
+
+	/* Now post the command to the board */
+	if (srb) {
+		retval = twa_post_command_packet(tw_dev, request_id, 0);
+	} else {
+		twa_post_command_packet(tw_dev, request_id, 1);
+		retval = 0;
+	}
+out:
+	return retval;
+} /* End twa_scsiop_execute_scsi() */
+
+/* This function completes an execute scsi operation */
+static void twa_scsiop_execute_scsi_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	/* Copy the response if too small */
+	if ((tw_dev->srb[request_id]->request_buffer) && (tw_dev->srb[request_id]->request_bufflen < TW_MIN_SGL_LENGTH)) {
+		memcpy(tw_dev->srb[request_id]->request_buffer,
+		       tw_dev->generic_buffer_virt[request_id],
+		       tw_dev->srb[request_id]->request_bufflen);
+	}
+} /* End twa_scsiop_execute_scsi_complete() */
+
+/* This function tells the controller to shut down */
+static void __twa_shutdown(TW_Device_Extension *tw_dev)
+{
+	/* Disable interrupts */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	printk(KERN_WARNING "3w-9xxx: Shutting down host %d.\n", tw_dev->host->host_no);
+
+	/* Tell the card we are shutting down */
+	if (twa_initconnection(tw_dev, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x31, "Connection shutdown failed");
+	} else {
+		printk(KERN_WARNING "3w-9xxx: Shutdown complete.\n");
+	}
+
+	/* Clear all interrupts just before exit */
+	TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+} /* End __twa_shutdown() */
+
+/* Wrapper for __twa_shutdown */
+static void twa_shutdown(struct device *dev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	__twa_shutdown(tw_dev);
+} /* End twa_shutdown() */
+
+/* This function will look up a string */
+static char *twa_string_lookup(twa_message_type *table, unsigned int code)
+{
+	int index;
+
+	for (index = 0; ((code != table[index].code) &&
+		      (table[index].text != (char *)0)); index++);
+	return(table[index].text);
+} /* End twa_string_lookup() */
+
+/* This function will perform a pci-dma unmap */
+static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id)
+{
+	struct scsi_cmnd *cmd = tw_dev->srb[request_id];
+	struct pci_dev *pdev = tw_dev->tw_pci_dev;
+
+	switch(cmd->SCp.phase) {
+	case TW_PHASE_SINGLE:
+		pci_unmap_single(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+		break;
+	case TW_PHASE_SGLIST:
+		pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+		break;
+	}
+} /* End twa_unmap_scsi_data() */
+
+/* scsi_host_template initializer */
+static struct scsi_host_template driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "3ware 9000 Storage Controller",
+	.queuecommand		= twa_scsi_queue,
+	.eh_host_reset_handler	= twa_scsi_eh_reset,
+	.bios_param		= twa_scsi_biosparam,
+	.change_queue_depth	= twa_change_queue_depth,
+	.can_queue		= TW_Q_LENGTH-2,
+	.this_id		= -1,
+	.sg_tablesize		= TW_APACHE_MAX_SGL_LENGTH,
+	.max_sectors		= TW_MAX_SECTORS,
+	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= twa_host_attrs,
+	.emulated		= 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit twa_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+	struct Scsi_Host *host = NULL;
+	TW_Device_Extension *tw_dev;
+	u32 mem_addr;
+	int retval = -ENODEV;
+
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		TW_PRINTK(host, TW_DRIVER, 0x34, "Failed to enable pci device");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	retval = pci_set_dma_mask(pdev, sizeof(dma_addr_t) > 4 ? DMA_64BIT_MASK : DMA_32BIT_MASK);
+	if (retval) {
+		TW_PRINTK(host, TW_DRIVER, 0x23, "Failed to set dma mask");
+		goto out_disable_device;
+	}
+
+	host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+	if (!host) {
+		TW_PRINTK(host, TW_DRIVER, 0x24, "Failed to allocate memory for device extension");
+		retval = -ENOMEM;
+		goto out_disable_device;
+	}
+	tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+	/* Save values to device extension */
+	tw_dev->host = host;
+	tw_dev->tw_pci_dev = pdev;
+
+	if (twa_initialize_device_extension(tw_dev)) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x25, "Failed to initialize device extension");
+		goto out_free_device_extension;
+	}
+
+	/* Request IO regions */
+	retval = pci_request_regions(pdev, "3w-9xxx");
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x26, "Failed to get mem region");
+		goto out_free_device_extension;
+	}
+
+	mem_addr = pci_resource_start(pdev, 1);
+
+	/* Save base address */
+	tw_dev->base_addr = ioremap(mem_addr, PAGE_SIZE);
+	if (!tw_dev->base_addr) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x35, "Failed to ioremap");
+		goto out_release_mem_region;
+	}
+
+	/* Disable interrupts on the card */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	/* Initialize the card */
+	if (twa_reset_sequence(tw_dev, 0))
+		goto out_release_mem_region;
+
+	/* Set host specific parameters */
+	host->max_id = TW_MAX_UNITS;
+	host->max_cmd_len = TW_MAX_CDB_LEN;
+
+	/* Channels aren't supported by adapter */
+	host->max_lun = TW_MAX_LUNS(tw_dev->working_srl);
+	host->max_channel = 0;
+
+	/* Register the card with the kernel SCSI layer */
+	retval = scsi_add_host(host, &pdev->dev);
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x27, "scsi add host failed");
+		goto out_release_mem_region;
+	}
+
+	pci_set_drvdata(pdev, host);
+
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Found a 3ware 9000 Storage Controller at 0x%x, IRQ: %d.\n",
+	       host->host_no, mem_addr, pdev->irq);
+	printk(KERN_WARNING "3w-9xxx: scsi%d: Firmware %s, BIOS %s, Ports: %d.\n",
+	       host->host_no,
+	       (char *)twa_get_param(tw_dev, 0, TW_VERSION_TABLE,
+				     TW_PARAM_FWVER, TW_PARAM_FWVER_LENGTH),
+	       (char *)twa_get_param(tw_dev, 1, TW_VERSION_TABLE,
+				     TW_PARAM_BIOSVER, TW_PARAM_BIOSVER_LENGTH),
+	       *(int *)twa_get_param(tw_dev, 2, TW_INFORMATION_TABLE,
+				     TW_PARAM_PORTCOUNT, TW_PARAM_PORTCOUNT_LENGTH));
+
+	/* Now setup the interrupt handler */
+	retval = request_irq(pdev->irq, twa_interrupt, SA_SHIRQ, "3w-9xxx", tw_dev);
+	if (retval) {
+		TW_PRINTK(tw_dev->host, TW_DRIVER, 0x30, "Error requesting IRQ");
+		goto out_remove_host;
+	}
+
+	twa_device_extension_list[twa_device_extension_count] = tw_dev;
+	twa_device_extension_count++;
+
+	/* Re-enable interrupts on the card */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Finally, scan the host */
+	scsi_scan_host(host);
+
+	if (twa_major == -1) {
+		if ((twa_major = register_chrdev (0, "twa", &twa_fops)) < 0)
+			TW_PRINTK(host, TW_DRIVER, 0x29, "Failed to register character device");
+	}
+	return 0;
+
+out_remove_host:
+	scsi_remove_host(host);
+out_release_mem_region:
+	pci_release_regions(pdev);
+out_free_device_extension:
+	twa_free_device_extension(tw_dev);
+	scsi_host_put(host);
+out_disable_device:
+	pci_disable_device(pdev);
+
+	return retval;
+} /* End twa_probe() */
+
+/* This function is called to remove a device */
+static void twa_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	scsi_remove_host(tw_dev->host);
+
+	/* Unregister character device */
+	if (twa_major >= 0) {
+		unregister_chrdev(twa_major, "twa");
+		twa_major = -1;
+	}
+
+	/* Free up the IRQ */
+	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+	/* Shutdown the card */
+	__twa_shutdown(tw_dev);
+
+	/* Free up the mem region */
+	pci_release_regions(pdev);
+
+	/* Free up device extension resources */
+	twa_free_device_extension(tw_dev);
+
+	scsi_host_put(tw_dev->host);
+	pci_disable_device(pdev);
+	twa_device_extension_count--;
+} /* End twa_remove() */
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id twa_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_9000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, twa_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver twa_driver = {
+	.name		= "3w-9xxx",
+	.id_table	= twa_pci_tbl,
+	.probe		= twa_probe,
+	.remove		= twa_remove,
+	.driver		= {
+		.shutdown = twa_shutdown
+	}
+};
+
+/* This function is called on driver initialization */
+static int __init twa_init(void)
+{
+	printk(KERN_WARNING "3ware 9000 Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
+
+	return pci_module_init(&twa_driver);
+} /* End twa_init() */
+
+/* This function is called on driver exit */
+static void __exit twa_exit(void)
+{
+	pci_unregister_driver(&twa_driver);
+} /* End twa_exit() */
+
+module_init(twa_init);
+module_exit(twa_exit);
+
diff --git a/drivers/scsi/3w-9xxx.h b/drivers/scsi/3w-9xxx.h
new file mode 100644
index 0000000..8c8ecbe
--- /dev/null
+++ b/drivers/scsi/3w-9xxx.h
@@ -0,0 +1,682 @@
+/*
+   3w-9xxx.h -- 3ware 9000 Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+
+   Copyright (C) 2004-2005 Applied Micro Circuits Corporation.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   NO WARRANTY
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
+   solely responsible for determining the appropriateness of using and
+   distributing the Program and assumes all risks associated with its
+   exercise of rights under this Agreement, including but not limited to
+   the risks and costs of program errors, damage to or loss of data,
+   programs or equipment, and unavailability or interruption of operations.
+
+   DISCLAIMER OF LIABILITY
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+   Bugs/Comments/Suggestions should be mailed to:
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+*/
+
+#ifndef _3W_9XXX_H
+#define _3W_9XXX_H
+
+/* AEN string type */
+typedef struct TAG_twa_message_type {
+  unsigned int   code;
+  char*          text;
+} twa_message_type;
+
+/* AEN strings */
+static twa_message_type twa_aen_table[] = {
+	{0x0000, "AEN queue empty"},
+	{0x0001, "Controller reset occurred"},
+	{0x0002, "Degraded unit detected"},
+	{0x0003, "Controller error occured"},
+	{0x0004, "Background rebuild failed"},
+	{0x0005, "Background rebuild done"},
+	{0x0006, "Incomplete unit detected"},
+	{0x0007, "Background initialize done"},
+	{0x0008, "Unclean shutdown detected"},
+	{0x0009, "Drive timeout detected"},
+	{0x000A, "Drive error detected"},
+	{0x000B, "Rebuild started"},
+	{0x000C, "Background initialize started"},
+	{0x000D, "Entire logical unit was deleted"},
+	{0x000E, "Background initialize failed"},
+	{0x000F, "SMART attribute exceeded threshold"},
+	{0x0010, "Power supply reported AC under range"},
+	{0x0011, "Power supply reported DC out of range"},
+	{0x0012, "Power supply reported a malfunction"},
+	{0x0013, "Power supply predicted malfunction"},
+	{0x0014, "Battery charge is below threshold"},
+	{0x0015, "Fan speed is below threshold"},
+	{0x0016, "Temperature sensor is above threshold"},
+	{0x0017, "Power supply was removed"},
+	{0x0018, "Power supply was inserted"},
+	{0x0019, "Drive was removed from a bay"},
+	{0x001A, "Drive was inserted into a bay"},
+	{0x001B, "Drive bay cover door was opened"},
+	{0x001C, "Drive bay cover door was closed"},
+	{0x001D, "Product case was opened"},
+	{0x0020, "Prepare for shutdown (power-off)"},
+	{0x0021, "Downgrade UDMA mode to lower speed"},
+	{0x0022, "Upgrade UDMA mode to higher speed"},
+	{0x0023, "Sector repair completed"},
+	{0x0024, "Sbuf memory test failed"},
+	{0x0025, "Error flushing cached write data to array"},
+	{0x0026, "Drive reported data ECC error"},
+	{0x0027, "DCB has checksum error"},
+	{0x0028, "DCB version is unsupported"},
+	{0x0029, "Background verify started"},
+	{0x002A, "Background verify failed"},
+	{0x002B, "Background verify done"},
+	{0x002C, "Bad sector overwritten during rebuild"},
+	{0x002D, "Background rebuild error on source drive"},
+	{0x002E, "Replace failed because replacement drive too small"},
+	{0x002F, "Verify failed because array was never initialized"},
+	{0x0030, "Unsupported ATA drive"},
+	{0x0031, "Synchronize host/controller time"},
+	{0x0032, "Spare capacity is inadequate for some units"},
+	{0x0033, "Background migration started"},
+	{0x0034, "Background migration failed"},
+	{0x0035, "Background migration done"},
+	{0x0036, "Verify detected and fixed data/parity mismatch"},
+	{0x0037, "SO-DIMM incompatible"},
+	{0x0038, "SO-DIMM not detected"},
+	{0x0039, "Corrected Sbuf ECC error"},
+	{0x003A, "Drive power on reset detected"},
+	{0x003B, "Background rebuild paused"},
+	{0x003C, "Background initialize paused"},
+	{0x003D, "Background verify paused"},
+	{0x003E, "Background migration paused"},
+	{0x003F, "Corrupt flash file system detected"},
+	{0x0040, "Flash file system repaired"},
+	{0x0041, "Unit number assignments were lost"},
+	{0x0042, "Error during read of primary DCB"},
+	{0x0043, "Latent error found in backup DCB"},
+	{0x00FC, "Recovered/finished array membership update"},
+	{0x00FD, "Handler lockup"},
+	{0x00FE, "Retrying PCI transfer"},
+	{0x00FF, "AEN queue is full"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* AEN severity table */
+static char *twa_aen_severity_table[] =
+{
+	"None", "ERROR", "WARNING", "INFO", "DEBUG", (char*) 0
+};
+
+/* Error strings */
+static twa_message_type twa_error_table[] = {
+	{0x0100, "SGL entry contains zero data"},
+	{0x0101, "Invalid command opcode"},
+	{0x0102, "SGL entry has unaligned address"},
+	{0x0103, "SGL size does not match command"},
+	{0x0104, "SGL entry has illegal length"},
+	{0x0105, "Command packet is not aligned"},
+	{0x0106, "Invalid request ID"},
+	{0x0107, "Duplicate request ID"},
+	{0x0108, "ID not locked"},
+	{0x0109, "LBA out of range"},
+	{0x010A, "Logical unit not supported"},
+	{0x010B, "Parameter table does not exist"},
+	{0x010C, "Parameter index does not exist"},
+	{0x010D, "Invalid field in CDB"},
+	{0x010E, "Specified port has invalid drive"},
+	{0x010F, "Parameter item size mismatch"},
+	{0x0110, "Failed memory allocation"},
+	{0x0111, "Memory request too large"},
+	{0x0112, "Out of memory segments"},
+	{0x0113, "Invalid address to deallocate"},
+	{0x0114, "Out of memory"},
+	{0x0115, "Out of heap"},
+	{0x0120, "Double degrade"},
+	{0x0121, "Drive not degraded"},
+	{0x0122, "Reconstruct error"},
+	{0x0123, "Replace not accepted"},
+	{0x0124, "Replace drive capacity too small"},
+	{0x0125, "Sector count not allowed"},
+	{0x0126, "No spares left"},
+	{0x0127, "Reconstruct error"},
+	{0x0128, "Unit is offline"},
+	{0x0129, "Cannot update status to DCB"},
+	{0x0130, "Invalid stripe handle"},
+	{0x0131, "Handle that was not locked"},
+	{0x0132, "Handle that was not empty"},
+	{0x0133, "Handle has different owner"},
+	{0x0140, "IPR has parent"},
+	{0x0150, "Illegal Pbuf address alignment"},
+	{0x0151, "Illegal Pbuf transfer length"},
+	{0x0152, "Illegal Sbuf address alignment"},
+	{0x0153, "Illegal Sbuf transfer length"},
+	{0x0160, "Command packet too large"},
+	{0x0161, "SGL exceeds maximum length"},
+	{0x0162, "SGL has too many entries"},
+	{0x0170, "Insufficient resources for rebuilder"},
+	{0x0171, "Verify error (data != parity)"},
+	{0x0180, "Requested segment not in directory of this DCB"},
+	{0x0181, "DCB segment has unsupported version"},
+	{0x0182, "DCB segment has checksum error"},
+	{0x0183, "DCB support (settings) segment invalid"},
+	{0x0184, "DCB UDB (unit descriptor block) segment invalid"},
+	{0x0185, "DCB GUID (globally unique identifier) segment invalid"},
+	{0x01A0, "Could not clear Sbuf"},
+	{0x01C0, "Flash identify failed"},
+	{0x01C1, "Flash out of bounds"},
+	{0x01C2, "Flash verify error"},
+	{0x01C3, "Flash file object not found"},
+	{0x01C4, "Flash file already present"},
+	{0x01C5, "Flash file system full"},
+	{0x01C6, "Flash file not present"},
+	{0x01C7, "Flash file size error"},
+	{0x01C8, "Bad flash file checksum"},
+	{0x01CA, "Corrupt flash file system detected"},
+	{0x01D0, "Invalid field in parameter list"},
+	{0x01D1, "Parameter list length error"},
+	{0x01D2, "Parameter item is not changeable"},
+	{0x01D3, "Parameter item is not saveable"},
+	{0x0200, "UDMA CRC error"},
+	{0x0201, "Internal CRC error"},
+	{0x0202, "Data ECC error"},
+	{0x0203, "ADP level 1 error"},
+	{0x0204, "Port timeout"},
+	{0x0205, "Drive power on reset"},
+	{0x0206, "ADP level 2 error"},
+	{0x0207, "Soft reset failed"},
+	{0x0208, "Drive not ready"},
+	{0x0209, "Unclassified port error"},
+	{0x020A, "Drive aborted command"},
+	{0x0210, "Internal CRC error"},
+	{0x0211, "PCI abort error"},
+	{0x0212, "PCI parity error"},
+	{0x0213, "Port handler error"},
+	{0x0214, "Token interrupt count error"},
+	{0x0215, "Timeout waiting for PCI transfer"},
+	{0x0216, "Corrected buffer ECC"},
+	{0x0217, "Uncorrected buffer ECC"},
+	{0x0230, "Unsupported command during flash recovery"},
+	{0x0231, "Next image buffer expected"},
+	{0x0232, "Binary image architecture incompatible"},
+	{0x0233, "Binary image has no signature"},
+	{0x0234, "Binary image has bad checksum"},
+	{0x0235, "Image downloaded overflowed buffer"},
+	{0x0240, "I2C device not found"},
+	{0x0241, "I2C transaction aborted"},
+	{0x0242, "SO-DIMM parameter(s) incompatible using defaults"},
+	{0x0243, "SO-DIMM unsupported"},
+	{0x0248, "SPI transfer status error"},
+	{0x0249, "SPI transfer timeout error"},
+	{0x0250, "Invalid unit descriptor size in CreateUnit"},
+	{0x0251, "Unit descriptor size exceeds data buffer in CreateUnit"},
+	{0x0252, "Invalid value in CreateUnit descriptor"},
+	{0x0253, "Inadequate disk space to support descriptor in CreateUnit"},
+	{0x0254, "Unable to create data channel for this unit descriptor"},
+	{0x0255, "CreateUnit descriptor specifies a drive already in use"},
+	{0x0256, "Unable to write configuration to all disks during CreateUnit"},
+	{0x0257, "CreateUnit does not support this descriptor version"},
+	{0x0258, "Invalid subunit for RAID 0 or 5 in CreateUnit"},
+	{0x0259, "Too many descriptors in CreateUnit"},
+	{0x025A, "Invalid configuration specified in CreateUnit descriptor"},
+	{0x025B, "Invalid LBA offset specified in CreateUnit descriptor"},
+	{0x025C, "Invalid stripelet size specified in CreateUnit descriptor"},
+	{0x0260, "SMART attribute exceeded threshold"},
+	{0xFFFFFFFF, (char*) 0}
+};
+
+/* Control register bit definitions */
+#define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
+#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT   0x00040000
+#define TW_CONTROL_MASK_COMMAND_INTERRUPT      0x00020000
+#define TW_CONTROL_MASK_RESPONSE_INTERRUPT     0x00010000
+#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT    0x00008000
+#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT   0x00004000
+#define TW_CONTROL_CLEAR_ERROR_STATUS	       0x00000200
+#define TW_CONTROL_ISSUE_SOFT_RESET	       0x00000100
+#define TW_CONTROL_ENABLE_INTERRUPTS	       0x00000080
+#define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
+#define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
+#define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
+
+/* Status register bit definitions */
+#define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
+#define TW_STATUS_MINOR_VERSION_MASK	       0x0F000000
+#define TW_STATUS_PCI_PARITY_ERROR	       0x00800000
+#define TW_STATUS_QUEUE_ERROR		       0x00400000
+#define TW_STATUS_MICROCONTROLLER_ERROR	       0x00200000
+#define TW_STATUS_PCI_ABORT		       0x00100000
+#define TW_STATUS_HOST_INTERRUPT	       0x00080000
+#define TW_STATUS_ATTENTION_INTERRUPT	       0x00040000
+#define TW_STATUS_COMMAND_INTERRUPT	       0x00020000
+#define TW_STATUS_RESPONSE_INTERRUPT	       0x00010000
+#define TW_STATUS_COMMAND_QUEUE_FULL	       0x00008000
+#define TW_STATUS_RESPONSE_QUEUE_EMPTY	       0x00004000
+#define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
+#define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
+#define TW_STATUS_EXPECTED_BITS		       0x00002000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
+
+/* RESPONSE QUEUE BIT DEFINITIONS */
+#define TW_RESPONSE_ID_MASK		       0x00000FF0
+
+/* PCI related defines */
+#define TW_NUMDEVICES 1
+#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000
+
+/* Command packet opcodes used by the driver */
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_GET_PARAM	      0x12
+#define TW_OP_SET_PARAM	      0x13
+#define TW_OP_EXECUTE_SCSI    0x10
+#define TW_OP_DOWNLOAD_FIRMWARE 0x16
+#define TW_OP_RESET             0x1C
+
+/* Asynchronous Event Notification (AEN) codes used by the driver */
+#define TW_AEN_QUEUE_EMPTY       0x0000
+#define TW_AEN_SOFT_RESET        0x0001
+#define TW_AEN_SYNC_TIME_WITH_HOST 0x031
+#define TW_AEN_SEVERITY_ERROR    0x1
+#define TW_AEN_SEVERITY_DEBUG    0x4
+#define TW_AEN_NOT_RETRIEVED 0x1
+#define TW_AEN_RETRIEVED 0x2
+
+/* Command state defines */
+#define TW_S_INITIAL   0x1  /* Initial state */
+#define TW_S_STARTED   0x2  /* Id in use */
+#define TW_S_POSTED    0x4  /* Posted to the controller */
+#define TW_S_PENDING   0x8  /* Waiting to be posted in isr */
+#define TW_S_COMPLETED 0x10 /* Completed by isr */
+#define TW_S_FINISHED  0x20 /* I/O completely done */
+
+/* Compatibility defines */
+#define TW_9000_ARCH_ID 0x5
+#define TW_CURRENT_DRIVER_SRL 28
+#define TW_CURRENT_DRIVER_BUILD 9
+#define TW_CURRENT_DRIVER_BRANCH 4
+
+/* Phase defines */
+#define TW_PHASE_INITIAL 0
+#define TW_PHASE_SINGLE  1
+#define TW_PHASE_SGLIST  2
+
+/* Misc defines */
+#define TW_SECTOR_SIZE                        512
+#define TW_ALIGNMENT_9000                     4  /* 4 bytes */
+#define TW_ALIGNMENT_9000_SGL                 0x3
+#define TW_MAX_UNITS			      16
+#define TW_INIT_MESSAGE_CREDITS		      0x100
+#define TW_INIT_COMMAND_PACKET_SIZE	      0x3
+#define TW_INIT_COMMAND_PACKET_SIZE_EXTENDED  0x6
+#define TW_EXTENDED_INIT_CONNECT	      0x2
+#define TW_BUNDLED_FW_SAFE_TO_FLASH	      0x4
+#define TW_CTLR_FW_RECOMMENDS_FLASH	      0x8
+#define TW_CTLR_FW_COMPATIBLE		      0x2
+#define TW_BASE_FW_SRL			      24
+#define TW_BASE_FW_BRANCH		      0
+#define TW_BASE_FW_BUILD		      1
+#define TW_FW_SRL_LUNS_SUPPORTED              28
+#define TW_Q_LENGTH			      256
+#define TW_Q_START			      0
+#define TW_MAX_SLOT			      32
+#define TW_MAX_RESET_TRIES		      2
+#define TW_MAX_CMDS_PER_LUN		      254
+#define TW_MAX_RESPONSE_DRAIN		      256
+#define TW_MAX_AEN_DRAIN		      40
+#define TW_IN_RESET                           2
+#define TW_IN_CHRDEV_IOCTL                    3
+#define TW_IN_ATTENTION_LOOP		      4
+#define TW_MAX_SECTORS                        256
+#define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
+#define TW_MAX_CDB_LEN                        16
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
+#define TW_COMMAND_OFFSET                     128 /* 128 bytes */
+#define TW_VERSION_TABLE                      0x0402
+#define TW_TIMEKEEP_TABLE		      0x040A
+#define TW_INFORMATION_TABLE		      0x0403
+#define TW_PARAM_FWVER			      3
+#define TW_PARAM_FWVER_LENGTH		      16
+#define TW_PARAM_BIOSVER		      4
+#define TW_PARAM_BIOSVER_LENGTH		      16
+#define TW_PARAM_PORTCOUNT		      3
+#define TW_PARAM_PORTCOUNT_LENGTH	      1
+#define TW_MIN_SGL_LENGTH                     0x200 /* 512 bytes */
+#define TW_MAX_SENSE_LENGTH                   256
+#define TW_EVENT_SOURCE_AEN                   0x1000
+#define TW_EVENT_SOURCE_COMMAND               0x1001
+#define TW_EVENT_SOURCE_PCHIP                 0x1002
+#define TW_EVENT_SOURCE_DRIVER                0x1003
+#define TW_IOCTL_GET_COMPATIBILITY_INFO	      0x101
+#define TW_IOCTL_GET_LAST_EVENT               0x102
+#define TW_IOCTL_GET_FIRST_EVENT              0x103
+#define TW_IOCTL_GET_NEXT_EVENT               0x104
+#define TW_IOCTL_GET_PREVIOUS_EVENT           0x105
+#define TW_IOCTL_GET_LOCK                     0x106
+#define TW_IOCTL_RELEASE_LOCK                 0x107
+#define TW_IOCTL_FIRMWARE_PASS_THROUGH        0x108
+#define TW_IOCTL_ERROR_STATUS_NOT_LOCKED      0x1001 // Not locked
+#define TW_IOCTL_ERROR_STATUS_LOCKED          0x1002 // Already locked
+#define TW_IOCTL_ERROR_STATUS_NO_MORE_EVENTS  0x1003 // No more events
+#define TW_IOCTL_ERROR_STATUS_AEN_CLOBBER     0x1004 // AEN clobber occurred
+#define TW_IOCTL_ERROR_OS_EFAULT	      -EFAULT // Bad address
+#define TW_IOCTL_ERROR_OS_EINTR		      -EINTR  // Interrupted system call
+#define TW_IOCTL_ERROR_OS_EINVAL	      -EINVAL // Invalid argument
+#define TW_IOCTL_ERROR_OS_ENOMEM	      -ENOMEM // Out of memory
+#define TW_IOCTL_ERROR_OS_ERESTARTSYS	      -ERESTARTSYS // Restart system call
+#define TW_IOCTL_ERROR_OS_EIO		      -EIO // I/O error
+#define TW_IOCTL_ERROR_OS_ENOTTY	      -ENOTTY // Not a typewriter
+#define TW_IOCTL_ERROR_OS_ENODEV	      -ENODEV // No such device
+#define TW_ALLOCATION_LENGTH		      128
+#define TW_SENSE_DATA_LENGTH		      18
+#define TW_STATUS_CHECK_CONDITION	      2
+#define TW_ERROR_LOGICAL_UNIT_NOT_SUPPORTED   0x10a
+#define TW_ERROR_UNIT_OFFLINE                 0x128
+#define TW_MESSAGE_SOURCE_CONTROLLER_ERROR    3
+#define TW_MESSAGE_SOURCE_CONTROLLER_EVENT    4
+#define TW_MESSAGE_SOURCE_LINUX_DRIVER        6
+#define TW_DRIVER TW_MESSAGE_SOURCE_LINUX_DRIVER
+#define TW_MESSAGE_SOURCE_LINUX_OS            9
+#define TW_OS TW_MESSAGE_SOURCE_LINUX_OS
+#ifndef PCI_DEVICE_ID_3WARE_9000
+#define PCI_DEVICE_ID_3WARE_9000 0x1002
+#endif
+
+/* Bitmask macros to eliminate bitfields */
+
+/* opcode: 5, reserved: 3 */
+#define TW_OPRES_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_OP_OUT(x) (x & 0x1f)
+
+/* opcode: 5, sgloffset: 3 */
+#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_SGL_OUT(x) ((x >> 5) & 0x7)
+
+/* severity: 3, reserved: 5 */
+#define TW_SEV_OUT(x) (x & 0x7)
+
+/* reserved_1: 4, response_id: 8, reserved_2: 20 */
+#define TW_RESID_OUT(x) ((x >> 4) & 0xff)
+
+/* request_id: 12, lun: 4 */
+#define TW_REQ_LUN_IN(lun, request_id) (((lun << 12) & 0xf000) | (request_id & 0xfff))
+#define TW_LUN_OUT(lun) ((lun >> 12) & 0xf)
+
+/* Macros */
+#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
+#define TW_STATUS_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0x4)
+#define TW_COMMAND_QUEUE_REG_ADDR(x) (sizeof(dma_addr_t) > 4 ? ((unsigned char __iomem *)x->base_addr + 0x20) : ((unsigned char __iomem *)x->base_addr + 0x8))
+#define TW_RESPONSE_QUEUE_REG_ADDR(x) ((unsigned char __iomem *)x->base_addr + 0xC)
+#define TW_CLEAR_ALL_INTERRUPTS(x) (writel(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_ATTENTION_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_HOST_INTERRUPT(x) (writel(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_DISABLE_INTERRUPTS(x) (writel(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (writel(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_MASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_UNMASK_COMMAND_INTERRUPT(x) (writel(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_SOFT_RESET(x) (writel(TW_CONTROL_ISSUE_SOFT_RESET | \
+			TW_CONTROL_CLEAR_HOST_INTERRUPT | \
+			TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
+			TW_CONTROL_MASK_COMMAND_INTERRUPT | \
+			TW_CONTROL_MASK_RESPONSE_INTERRUPT | \
+			TW_CONTROL_CLEAR_ERROR_STATUS | \
+			TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_PRINTK(h,a,b,c) { \
+if (h) \
+printk(KERN_WARNING "3w-9xxx: scsi%d: ERROR: (0x%02X:0x%04X): %s.\n",h->host_no,a,b,c); \
+else \
+printk(KERN_WARNING "3w-9xxx: ERROR: (0x%02X:0x%04X): %s.\n",a,b,c); \
+}
+#define TW_MAX_LUNS(srl) (srl < TW_FW_SRL_LUNS_SUPPORTED ? 1 : 16)
+#define TW_COMMAND_SIZE (sizeof(dma_addr_t) > 4 ? 5 : 4)
+#define TW_APACHE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 72 : 109)
+#define TW_ESCALADE_MAX_SGL_LENGTH (sizeof(dma_addr_t) > 4 ? 41 : 62)
+#define TW_PADDING_LENGTH (sizeof(dma_addr_t) > 4 ? 8 : 0)
+
+#pragma pack(1)
+
+/* Scatter Gather List Entry */
+typedef struct TAG_TW_SG_Entry {
+	dma_addr_t address;
+	u32 length;
+} TW_SG_Entry;
+
+/* Command Packet */
+typedef struct TW_Command {
+	unsigned char opcode__sgloffset;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char unit__hostid;
+	/* Second DWORD */
+	unsigned char status;
+	unsigned char flags;
+	union {
+		unsigned short block_count;
+		unsigned short parameter_count;
+	} byte6_offset;
+	union {
+		struct {
+			u32 lba;
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+			dma_addr_t padding;
+		} io;
+		struct {
+			TW_SG_Entry sgl[TW_ESCALADE_MAX_SGL_LENGTH];
+			u32 padding;
+			dma_addr_t padding2;
+		} param;
+	} byte8_offset;
+} TW_Command;
+
+/* Command Packet for 9000+ controllers */
+typedef struct TAG_TW_Command_Apache {
+	unsigned char opcode__reserved;
+	unsigned char unit;
+	unsigned short request_id__lunl;
+	unsigned char status;
+	unsigned char sgl_offset;
+	unsigned short sgl_entries__lunh;
+	unsigned char cdb[16];
+	TW_SG_Entry sg_list[TW_APACHE_MAX_SGL_LENGTH];
+	unsigned char padding[TW_PADDING_LENGTH];
+} TW_Command_Apache;
+
+/* New command packet header */
+typedef struct TAG_TW_Command_Apache_Header {
+	unsigned char sense_data[TW_SENSE_DATA_LENGTH];
+	struct {
+		char reserved[4];
+		unsigned short error;
+		unsigned char padding;
+		unsigned char severity__reserved;
+	} status_block;
+	unsigned char err_specific_desc[98];
+	struct {
+		unsigned char size_header;
+		unsigned short reserved;
+		unsigned char size_sense;
+	} header_desc;
+} TW_Command_Apache_Header;
+
+/* This struct is a union of the 2 command packets */
+typedef struct TAG_TW_Command_Full {
+	TW_Command_Apache_Header header;
+	union {
+		TW_Command oldcommand;
+		TW_Command_Apache newcommand;
+	} command;
+} TW_Command_Full;
+
+/* Initconnection structure */
+typedef struct TAG_TW_Initconnect {
+	unsigned char opcode__reserved;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char res2;
+	unsigned char status;
+	unsigned char flags;
+	unsigned short message_credits;
+	u32 features;
+	unsigned short fw_srl;
+	unsigned short fw_arch_id;
+	unsigned short fw_branch;
+	unsigned short fw_build;
+	u32 result;
+} TW_Initconnect;
+
+/* Event info structure */
+typedef struct TAG_TW_Event
+{
+	unsigned int sequence_id;
+	unsigned int time_stamp_sec;
+	unsigned short aen_code;
+	unsigned char severity;
+	unsigned char retrieved;
+	unsigned char repeat_count;
+	unsigned char parameter_len;
+	unsigned char parameter_data[98];
+} TW_Event;
+
+typedef struct TAG_TW_Ioctl_Driver_Command {
+	unsigned int control_code;
+	unsigned int status;
+	unsigned int unique_id;
+	unsigned int sequence_id;
+	unsigned int os_specific;
+	unsigned int buffer_length;
+} TW_Ioctl_Driver_Command;
+
+typedef struct TAG_TW_Ioctl_Apache {
+	TW_Ioctl_Driver_Command driver_command;
+        char padding[488];
+	TW_Command_Full firmware_command;
+	char data_buffer[1];
+} TW_Ioctl_Buf_Apache;
+
+/* Lock structure for ioctl get/release lock */
+typedef struct TAG_TW_Lock {
+	unsigned long timeout_msec;
+	unsigned long time_remaining_msec;
+	unsigned long force_flag;
+} TW_Lock;
+
+/* GetParam descriptor */
+typedef struct {
+	unsigned short	table_id;
+	unsigned short	parameter_id;
+	unsigned short	parameter_size_bytes;
+	unsigned short  actual_parameter_size_bytes;
+	unsigned char	data[1];
+} TW_Param_Apache, *PTW_Param_Apache;
+
+/* Response queue */
+typedef union TAG_TW_Response_Queue {
+	u32 response_id;
+	u32 value;
+} TW_Response_Queue;
+
+typedef struct TAG_TW_Info {
+	char *buffer;
+	int length;
+	int offset;
+	int position;
+} TW_Info;
+
+/* Compatibility information structure */
+typedef struct TAG_TW_Compatibility_Info
+{
+	char driver_version[32];
+	unsigned short working_srl;
+	unsigned short working_branch;
+	unsigned short working_build;
+	unsigned short driver_srl_high;
+	unsigned short driver_branch_high;
+	unsigned short driver_build_high;
+	unsigned short driver_srl_low;
+	unsigned short driver_branch_low;
+	unsigned short driver_build_low;
+} TW_Compatibility_Info;
+
+typedef struct TAG_TW_Device_Extension {
+	u32                     __iomem *base_addr;
+	unsigned long	       	*generic_buffer_virt[TW_Q_LENGTH];
+	dma_addr_t	       	generic_buffer_phys[TW_Q_LENGTH];
+	TW_Command_Full	       	*command_packet_virt[TW_Q_LENGTH];
+	dma_addr_t		command_packet_phys[TW_Q_LENGTH];
+	struct pci_dev		*tw_pci_dev;
+	struct scsi_cmnd	*srb[TW_Q_LENGTH];
+	unsigned char		free_queue[TW_Q_LENGTH];
+	unsigned char		free_head;
+	unsigned char		free_tail;
+	unsigned char		pending_queue[TW_Q_LENGTH];
+	unsigned char		pending_head;
+	unsigned char		pending_tail;
+	int     		state[TW_Q_LENGTH];
+	unsigned int		posted_request_count;
+	unsigned int		max_posted_request_count;
+	unsigned int	        pending_request_count;
+	unsigned int		max_pending_request_count;
+	unsigned int		max_sgl_entries;
+	unsigned int		sgl_entries;
+	unsigned int		num_resets;
+	unsigned int		sector_count;
+	unsigned int		max_sector_count;
+	unsigned int		aen_count;
+	struct Scsi_Host	*host;
+	long			flags;
+	int			reset_print;
+	TW_Event                *event_queue[TW_Q_LENGTH];
+	unsigned char           error_index;
+	unsigned char		event_queue_wrapped;
+	unsigned int            error_sequence_id;
+	int                     ioctl_sem_lock;
+	u32                     ioctl_msec;
+	int			chrdev_request_id;
+	wait_queue_head_t	ioctl_wqueue;
+	struct semaphore	ioctl_sem;
+	char			aen_clobber;
+	unsigned short		working_srl;
+	unsigned short		working_branch;
+	unsigned short		working_build;
+} TW_Device_Extension;
+
+#pragma pack()
+
+#endif /* _3W_9XXX_H */
+
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
new file mode 100644
index 0000000..48f9ece
--- /dev/null
+++ b/drivers/scsi/3w-xxxx.c
@@ -0,0 +1,2478 @@
+/* 
+   3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linuxraid@amcc.com>
+   Modifications By: Joel Jacobson <linux@3ware.com>
+   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+                     Brad Strand <linux@3ware.com>
+
+   Copyright (C) 1999-2005 3ware Inc.
+
+   Kernel compatiblity By: 	Andre Hedrick <andre@suse.com>
+   Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
+   
+   Further tiny build fixes and trivial hoovering    Alan Cox
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,           
+   but WITHOUT ANY WARRANTY; without even the implied warranty of            
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
+   GNU General Public License for more details.                              
+
+   NO WARRANTY                                                               
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
+   solely responsible for determining the appropriateness of using and       
+   distributing the Program and assumes all risks associated with its        
+   exercise of rights under this Agreement, including but not limited to     
+   the risks and costs of program errors, damage to or loss of data,         
+   programs or equipment, and unavailability or interruption of operations.  
+
+   DISCLAIMER OF LIABILITY                                                   
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
+
+   You should have received a copy of the GNU General Public License         
+   along with this program; if not, write to the Free Software               
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+
+   Bugs/Comments/Suggestions should be mailed to:                            
+   linuxraid@amcc.com
+
+   For more information, goto:
+   http://www.amcc.com
+
+   History
+   -------
+   0.1.000 -     Initial release.
+   0.4.000 -     Added support for Asynchronous Event Notification through
+                 ioctls for 3DM.
+   1.0.000 -     Added DPO & FUA bit support for WRITE_10 & WRITE_6 cdb
+                 to disable drive write-cache before writes.
+   1.1.000 -     Fixed performance bug with DPO & FUA not existing for WRITE_6.
+   1.2.000 -     Added support for clean shutdown notification/feature table.
+   1.02.00.001 - Added support for full command packet posts through ioctls
+                 for 3DM.
+                 Bug fix so hot spare drives don't show up.
+   1.02.00.002 - Fix bug with tw_setfeature() call that caused oops on some
+                 systems.
+   08/21/00    - release previously allocated resources on failure at
+                 tw_allocate_memory (acme)
+   1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
+                 controller status is non-zero.
+                 Added handling of request_sense opcode.
+                 Fix possible null pointer dereference in 
+                 tw_reset_device_extension()
+   1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
+                 Make tw_setfeature() call with interrupts disabled.
+                 Register interrupt handler before enabling interrupts.
+                 Clear attention interrupt before draining aen queue.
+   1.02.00.005 - Allocate bounce buffers and custom queue depth for raid5 for
+                 6000 and 5000 series controllers.
+                 Reduce polling mdelays causing problems on some systems.
+                 Fix use_sg = 1 calculation bug.
+                 Check for scsi_register returning NULL.
+                 Add aen count to /proc/scsi/3w-xxxx.
+                 Remove aen code unit masking in tw_aen_complete().
+   1.02.00.006 - Remove unit from printk in tw_scsi_eh_abort(), causing
+                 possible oops.
+                 Fix possible null pointer dereference in tw_scsi_queue()
+                 if done function pointer was invalid.
+   1.02.00.007 - Fix possible null pointer dereferences in tw_ioctl().
+                 Remove check for invalid done function pointer from
+                 tw_scsi_queue().
+   1.02.00.008 - Set max sectors per io to TW_MAX_SECTORS in tw_findcards().
+                 Add tw_decode_error() for printing readable error messages.
+                 Print some useful information on certain aen codes.
+                 Add tw_decode_bits() for interpreting status register output.
+                 Make scsi_set_pci_device() for kernels >= 2.4.4
+                 Fix bug where aen's could be lost before a reset.
+                 Re-add spinlocks in tw_scsi_detect().
+                 Fix possible null pointer dereference in tw_aen_drain_queue()
+                 during initialization.
+                 Clear pci parity errors during initialization and during io.
+   1.02.00.009 - Remove redundant increment in tw_state_request_start().
+                 Add ioctl support for direct ATA command passthru.
+                 Add entire aen code string list.
+   1.02.00.010 - Cleanup queueing code, fix jbod thoughput.
+                 Fix get_param for specific units.
+   1.02.00.011 - Fix bug in tw_aen_complete() where aen's could be lost.
+                 Fix tw_aen_drain_queue() to display useful info at init.
+                 Set tw_host->max_id for 12 port cards.
+                 Add ioctl support for raw command packet post from userspace
+                 with sglist fragments (parameter and io).
+   1.02.00.012 - Fix read capacity to under report by 1 sector to fix get
+                 last sector ioctl.
+   1.02.00.013 - Fix bug where more AEN codes weren't coming out during
+                 driver initialization.
+                 Improved handling of PCI aborts.
+   1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost.
+                 Increase timeout in tw_aen_drain_queue() to 30 seconds.
+   1.02.00.015 - Re-write raw command post with data ioctl method.
+                 Remove raid5 bounce buffers for raid5 for 6XXX for kernel 2.5
+                 Add tw_map/unmap_scsi_sg/single_data() for kernel 2.5
+                 Replace io_request_lock with host_lock for kernel 2.5
+                 Set max_cmd_len to 16 for 3dm for kernel 2.5
+   1.02.00.016 - Set host->max_sectors back up to 256.
+   1.02.00.017 - Modified pci parity error handling/clearing from config space
+                 during initialization.
+   1.02.00.018 - Better handling of request sense opcode and sense information
+                 for failed commands.  Add tw_decode_sense().
+                 Replace all mdelay()'s with scsi_sleep().
+   1.02.00.019 - Revert mdelay's and scsi_sleep's, this caused problems on
+                 some SMP systems.
+   1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
+                 pci_alloc/free_consistent().
+                 Better alignment checking in tw_allocate_memory().
+                 Cleanup tw_initialize_device_extension().
+   1.02.00.021 - Bump cmd_per_lun in SHT to 255 for better jbod performance.
+                 Improve handling of errors in tw_interrupt().
+                 Add handling/clearing of controller queue error.
+                 Empty stale responses before draining aen queue.
+                 Fix tw_scsi_eh_abort() to not reset on every io abort.
+                 Set can_queue in SHT to 255 to prevent hang from AEN.
+   1.02.00.022 - Fix possible null pointer dereference in tw_scsi_release().
+   1.02.00.023 - Fix bug in tw_aen_drain_queue() where unit # was always zero.
+   1.02.00.024 - Add severity levels to AEN strings.
+   1.02.00.025 - Fix command interrupt spurious error messages.
+                 Fix bug in raw command post with data ioctl method.
+                 Fix bug where rollcall sometimes failed with cable errors.
+                 Print unit # on all command timeouts.
+   1.02.00.026 - Fix possible infinite retry bug with power glitch induced
+                 drive timeouts.
+                 Cleanup some AEN severity levels.
+   1.02.00.027 - Add drive not supported AEN code for SATA controllers.
+                 Remove spurious unknown ioctl error message.
+   1.02.00.028 - Fix bug where multiple controllers with no units were the
+                 same card number.
+                 Fix bug where cards were being shut down more than once.
+   1.02.00.029 - Add missing pci_free_consistent() in tw_allocate_memory().
+                 Replace pci_map_single() with pci_map_page() for highmem.
+                 Check for tw_setfeature() failure.
+   1.02.00.030 - Make driver 64-bit clean.
+   1.02.00.031 - Cleanup polling timeouts/routines in several places.
+                 Add support for mode sense opcode.
+                 Add support for cache mode page.
+                 Add support for synchronize cache opcode.
+   1.02.00.032 - Fix small multicard rollcall bug.
+                 Make driver stay loaded with no units for hot add/swap.
+                 Add support for "twe" character device for ioctls.
+                 Clean up request_id queueing code.
+                 Fix tw_scsi_queue() spinlocks.
+   1.02.00.033 - Fix tw_aen_complete() to not queue 'queue empty' AEN's.
+                 Initialize queues correctly when loading with no valid units.
+   1.02.00.034 - Fix tw_decode_bits() to handle multiple errors.
+                 Add support for user configurable cmd_per_lun.
+                 Add support for sht->slave_configure().
+   1.02.00.035 - Improve tw_allocate_memory() memory allocation.
+                 Fix tw_chrdev_ioctl() to sleep correctly.
+   1.02.00.036 - Increase character ioctl timeout to 60 seconds.
+   1.02.00.037 - Fix tw_ioctl() to handle all non-data ATA passthru cmds
+                 for 'smartmontools' support.
+   1.26.00.038 - Roll driver minor version to 26 to denote kernel 2.6.
+                 Add support for cmds_per_lun module parameter.
+   1.26.00.039 - Fix bug in tw_chrdev_ioctl() polling code.
+                 Fix data_buffer_length usage in tw_chrdev_ioctl().
+                 Update contact information.
+   1.26.02.000 - Convert driver to pci_driver format.
+   1.26.02.001 - Increase max ioctl buffer size to 512 sectors.
+                 Make tw_scsi_queue() return 0 for 'Unknown scsi opcode'.
+                 Fix tw_remove() to free irq handler/unregister_chrdev()
+                 before shutting down card.
+                 Change to new 'change_queue_depth' api.
+                 Fix 'handled=1' ISR usage, remove bogus IRQ check.
+*/
+
+#include <linux/module.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_cmnd.h>
+#include "3w-xxxx.h"
+
+/* Globals */
+#define TW_DRIVER_VERSION "1.26.02.001"
+static TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
+static int tw_device_extension_count = 0;
+static int twe_major = -1;
+
+/* Module parameters */
+MODULE_AUTHOR("AMCC");
+MODULE_DESCRIPTION("3ware Storage Controller Linux Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(TW_DRIVER_VERSION);
+
+/* Function prototypes */
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset);
+
+/* Functions */
+
+/* This function will check the status register for unexpected bits */
+static int tw_check_bits(u32 status_reg_value)
+{
+	if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != TW_STATUS_EXPECTED_BITS) {  
+		dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n", status_reg_value);
+		return 1;
+	}
+	if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected bits (0x%x).\n", status_reg_value);
+		return 1;
+	}
+
+	return 0;
+} /* End tw_check_bits() */
+
+/* This function will print readable messages from status register errors */
+static int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host)
+{
+	char host[16];
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n");
+
+	if (print_host)
+		sprintf(host, " scsi%d:", tw_dev->host->host_no);
+	else
+		host[0] = '\0';
+
+	if (status_reg_value & TW_STATUS_PCI_PARITY_ERROR) {
+		printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_PARITY_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_PCI_ABORT) {
+		printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_PCI_ABORT, TW_CONTROL_REG_ADDR(tw_dev));
+		pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT);
+	}
+
+	if (status_reg_value & TW_STATUS_QUEUE_ERROR) {
+		printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_QUEUE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_SBUF_WRITE_ERROR) {
+		printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host);
+		outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, TW_CONTROL_REG_ADDR(tw_dev));
+	}
+
+	if (status_reg_value & TW_STATUS_MICROCONTROLLER_ERROR) {
+		if (tw_dev->reset_print == 0) {
+			printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host);
+			tw_dev->reset_print = 1;
+		}
+		return 1;
+	}
+	
+	return 0;
+} /* End tw_decode_bits() */
+
+/* This function will poll the status register for a flag */
+static int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (tw_check_bits(status_reg_value))
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+
+	while ((status_reg_value & flag) != flag) {
+		status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+		if (tw_check_bits(status_reg_value))
+			tw_decode_bits(tw_dev, status_reg_value, 0);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End tw_poll_status() */
+
+/* This function will poll the status register for disappearance of a flag */
+static int tw_poll_status_gone(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+	u32 status_reg_value;
+	unsigned long before;
+	int retval = 1;
+
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+	before = jiffies;
+
+	if (tw_check_bits(status_reg_value))
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+
+	while ((status_reg_value & flag) != 0) {
+		status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+		if (tw_check_bits(status_reg_value))
+			tw_decode_bits(tw_dev, status_reg_value, 0);
+
+		if (time_after(jiffies, before + HZ * seconds))
+			goto out;
+
+		msleep(50);
+	}
+	retval = 0;
+out:
+	return retval;
+} /* End tw_poll_status_gone() */
+
+/* This function will attempt to post a command packet to the board */
+static int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+{
+	u32 status_reg_value;
+	unsigned long command_que_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value, 1);
+	}
+
+	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
+		/* We successfully posted the command packet */
+		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+		tw_dev->state[request_id] = TW_S_POSTED;
+		tw_dev->posted_request_count++;
+		if (tw_dev->posted_request_count > tw_dev->max_posted_request_count) {
+			tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+		}
+	} else {
+		/* Couldn't post the command packet, so we do it in the isr */
+		if (tw_dev->state[request_id] != TW_S_PENDING) {
+			tw_dev->state[request_id] = TW_S_PENDING;
+			tw_dev->pending_request_count++;
+			if (tw_dev->pending_request_count > tw_dev->max_pending_request_count) {
+				tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+			}
+			tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+			if (tw_dev->pending_tail == TW_Q_LENGTH-1) {
+				tw_dev->pending_tail = TW_Q_START;
+			} else {
+				tw_dev->pending_tail = tw_dev->pending_tail + 1;
+			}
+		} 
+		TW_UNMASK_COMMAND_INTERRUPT(tw_dev);
+		return 1;
+	}
+	return 0;
+} /* End tw_post_command_packet() */
+
+/* This function will return valid sense buffer information for failed cmds */
+static int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+{
+	int i;
+	TW_Command *command;
+
+        dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
+	command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, TW_UNIT_OUT(command->unit__hostid));
+
+	/* Attempt to return intelligent sense information */
+	if (fill_sense) {
+		if ((command->status == 0xc7) || (command->status == 0xcb)) {
+			for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) {
+				if (command->flags == tw_sense_table[i][0]) {
+
+					/* Valid bit and 'current errors' */
+					tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
+
+					/* Sense key */
+					tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1];
+
+					/* Additional sense length */
+					tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */
+
+					/* Additional sense code */
+					tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2];
+
+					/* Additional sense code qualifier */
+					tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3];
+
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+					return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */
+				}
+			}
+		}
+
+		/* If no table match, error so we get a reset */
+		return 1;
+	}
+
+	return 0;
+} /* End tw_decode_sense() */
+
+/* This function will report controller error status */
+static int tw_check_errors(TW_Device_Extension *tw_dev) 
+{
+	u32 status_reg_value;
+  
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+	if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
+		tw_decode_bits(tw_dev, status_reg_value, 0);
+		return 1;
+	}
+
+	return 0;
+} /* End tw_check_errors() */
+
+/* This function will empty the response que */
+static void tw_empty_response_que(TW_Device_Extension *tw_dev) 
+{
+	u32 status_reg_value, response_que_value;
+
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+	while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+		response_que_value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+	}
+} /* End tw_empty_response_que() */
+
+/* This function will free a request_id */
+static void tw_state_request_finish(TW_Device_Extension *tw_dev, int request_id)
+{
+	tw_dev->free_queue[tw_dev->free_tail] = request_id;
+	tw_dev->state[request_id] = TW_S_FINISHED;
+	tw_dev->free_tail = (tw_dev->free_tail + 1) % TW_Q_LENGTH;
+} /* End tw_state_request_finish() */
+
+/* This function will assign an available request_id */
+static void tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
+{
+	*request_id = tw_dev->free_queue[tw_dev->free_head];
+	tw_dev->free_head = (tw_dev->free_head + 1) % TW_Q_LENGTH;
+	tw_dev->state[*request_id] = TW_S_STARTED;
+} /* End tw_state_request_start() */
+
+/* Show some statistics about the card */
+static ssize_t tw_show_stats(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(class_dev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+	unsigned long flags = 0;
+	ssize_t len;
+
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+	len = snprintf(buf, PAGE_SIZE, "3w-xxxx Driver version: %s\n"
+		       "Current commands posted:   %4d\n"
+		       "Max commands posted:       %4d\n"
+		       "Current pending commands:  %4d\n"
+		       "Max pending commands:      %4d\n"
+		       "Last sgl length:           %4d\n"
+		       "Max sgl length:            %4d\n"
+		       "Last sector count:         %4d\n"
+		       "Max sector count:          %4d\n"
+		       "SCSI Host Resets:          %4d\n"
+		       "AEN's:                     %4d\n", 
+		       TW_DRIVER_VERSION,
+		       tw_dev->posted_request_count,
+		       tw_dev->max_posted_request_count,
+		       tw_dev->pending_request_count,
+		       tw_dev->max_pending_request_count,
+		       tw_dev->sgl_entries,
+		       tw_dev->max_sgl_entries,
+		       tw_dev->sector_count,
+		       tw_dev->max_sector_count,
+		       tw_dev->num_resets,
+		       tw_dev->aen_count);
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+	return len;
+} /* End tw_show_stats() */
+
+/* This function will set a devices queue depth */
+static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth)
+{
+	if (queue_depth > TW_Q_LENGTH-2)
+		queue_depth = TW_Q_LENGTH-2;
+	scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
+	return queue_depth;
+} /* End tw_change_queue_depth() */
+
+/* Create sysfs 'stats' entry */
+static struct class_device_attribute tw_host_stats_attr = {
+	.attr = {
+		.name = 	"stats",
+		.mode =		S_IRUGO,
+	},
+	.show = tw_show_stats
+};
+
+/* Host attributes initializer */
+static struct class_device_attribute *tw_host_attrs[] = {
+	&tw_host_stats_attr,
+	NULL,
+};
+
+/* This function will read the aen queue from the isr */
+static int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) 
+{
+	TW_Command *command_packet;
+	TW_Param *param;
+	unsigned long command_que_value;
+	u32 status_reg_value;
+	unsigned long param_value = 0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
+
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
+		tw_decode_bits(tw_dev, status_reg_value, 1);
+		return 1;
+	}
+	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet physical address.\n");
+		return 1;
+	}
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 0x401; /* AEN table */
+	param->parameter_id = 2; /* Unit code */
+	param->parameter_size_bytes = 2;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment physical address.\n");
+		return 1;
+	}
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+	/* Now post the command packet */
+	if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n");
+		tw_dev->srb[request_id] = NULL; /* Flag internal command */
+		tw_dev->state[request_id] = TW_S_POSTED;
+		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+	} else {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will retry.\n");
+		return 1;
+	}
+
+	return 0;
+} /* End tw_aen_read_queue() */
+
+/* This function will complete an aen request from the isr */
+static int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
+{
+	TW_Param *param;
+	unsigned short aen;
+	int error = 0, table_max = 0;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_aen_complete()\n");
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	aen = *(unsigned short *)(param->data);
+	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", aen);
+
+	/* Print some useful info when certain aen codes come out */
+	if (aen == 0x0ff) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: INFO: AEN queue overflow.\n", tw_dev->host->host_no);
+	} else {
+		table_max = sizeof(tw_aen_string)/sizeof(char *);
+		if ((aen & 0x0ff) < table_max) {
+			if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+				printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s%d.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff], aen >> 8);
+			} else {
+				if (aen != 0x0) 
+					printk(KERN_WARNING "3w-xxxx: scsi%d: AEN: %s.\n", tw_dev->host->host_no, tw_aen_string[aen & 0xff]);
+			}
+		} else {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Received AEN %d.\n", tw_dev->host->host_no, aen);
+		}
+	}
+	if (aen != TW_AEN_QUEUE_EMPTY) {
+		tw_dev->aen_count++;
+
+		/* Now queue the code */
+		tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+		if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+			tw_dev->aen_tail = TW_Q_START;
+		} else {
+			tw_dev->aen_tail = tw_dev->aen_tail + 1;
+		}
+		if (tw_dev->aen_head == tw_dev->aen_tail) {
+			if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+				tw_dev->aen_head = TW_Q_START;
+			} else {
+				tw_dev->aen_head = tw_dev->aen_head + 1;
+			}
+		}
+
+		error = tw_aen_read_queue(tw_dev, request_id);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing AEN.\n", tw_dev->host->host_no);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+		}
+	} else {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+	}
+
+	return 0;
+} /* End tw_aen_complete() */
+
+/* This function will drain the aen queue after a soft reset */
+static int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
+{
+	TW_Command *command_packet;
+	TW_Param *param;
+	int request_id = 0;
+	unsigned long command_que_value;
+	unsigned long param_value;
+	TW_Response_Queue response_queue;
+	unsigned short aen;
+	unsigned short aen_code;
+	int finished = 0;
+	int first_reset = 0;
+	int queue = 0;
+	int found = 0, table_max = 0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
+
+	if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT | TW_STATUS_MICROCONTROLLER_READY, 30)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention interrupt for card %d.\n", tw_device_extension_count);
+		return 1;
+	}
+	TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+
+	/* Empty response queue */
+	tw_empty_response_que(tw_dev);
+
+	/* Initialize command packet */
+	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 0x401; /* AEN table */
+	param->parameter_id = 2; /* Unit code */
+	param->parameter_size_bytes = 2;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment physical address.\n");
+		return 1;
+	}
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+	/* Now drain the controller's aen queue */
+	do {
+		/* Post command packet */
+		outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+
+		/* Now poll for completion */
+		if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+			response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+			request_id = TW_RESID_OUT(response_queue.response_id);
+
+			if (request_id != 0) {
+				/* Unexpected request id */
+				printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected request id.\n");
+				return 1;
+			}
+			
+			if (command_packet->status != 0) {
+				if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
+					/* Bad response */
+					tw_decode_sense(tw_dev, request_id, 0);
+					return 1;
+				} else {
+					/* We know this is a 3w-1x00, and doesn't support aen's */
+					return 0;
+				}
+			}
+
+			/* Now check the aen */
+			aen = *(unsigned short *)(param->data);
+			aen_code = (aen & 0x0ff);
+			queue = 0;
+			switch (aen_code) {
+				case TW_AEN_QUEUE_EMPTY:
+					dprintk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+					if (first_reset != 1) {
+						return 1;
+					} else {
+						finished = 1;
+					}
+					break;
+				case TW_AEN_SOFT_RESET:
+					if (first_reset == 0) {
+						first_reset = 1;
+					} else {
+						printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+						tw_dev->aen_count++;
+						queue = 1;
+					}
+					break;
+				default:
+					if (aen == 0x0ff) {
+						printk(KERN_WARNING "3w-xxxx: AEN: INFO: AEN queue overflow.\n");
+					} else {
+						table_max = sizeof(tw_aen_string)/sizeof(char *);
+						if ((aen & 0x0ff) < table_max) {
+							if ((tw_aen_string[aen & 0xff][strlen(tw_aen_string[aen & 0xff])-1]) == '#') {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s%d.\n", tw_aen_string[aen & 0xff], aen >> 8);
+							} else {
+								printk(KERN_WARNING "3w-xxxx: AEN: %s.\n", tw_aen_string[aen & 0xff]);
+							}
+						} else
+							printk(KERN_WARNING "3w-xxxx: Received AEN %d.\n", aen);
+					}
+					tw_dev->aen_count++;
+					queue = 1;
+			}
+
+			/* Now put the aen on the aen_queue */
+			if (queue == 1) {
+				tw_dev->aen_queue[tw_dev->aen_tail] = aen;
+				if (tw_dev->aen_tail == TW_Q_LENGTH - 1) {
+					tw_dev->aen_tail = TW_Q_START;
+				} else {
+					tw_dev->aen_tail = tw_dev->aen_tail + 1;
+				}
+				if (tw_dev->aen_head == tw_dev->aen_tail) {
+					if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+						tw_dev->aen_head = TW_Q_START;
+					} else {
+						tw_dev->aen_head = tw_dev->aen_head + 1;
+					}
+				}
+			}
+			found = 1;
+		}
+		if (found == 0) {
+			printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never received.\n");
+			return 1;
+		}
+	} while (finished == 0);
+
+	return 0;
+} /* End tw_aen_drain_queue() */
+
+/* This function will allocate memory */
+static int tw_allocate_memory(TW_Device_Extension *tw_dev, int size, int which)
+{
+	int i;
+	dma_addr_t dma_handle;
+	unsigned long *cpu_addr = NULL;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
+
+	cpu_addr = pci_alloc_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, &dma_handle);
+	if (cpu_addr == NULL) {
+		printk(KERN_WARNING "3w-xxxx: pci_alloc_consistent() failed.\n");
+		return 1;
+	}
+
+	if ((unsigned long)cpu_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) {
+		printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n");
+		pci_free_consistent(tw_dev->tw_pci_dev, size*TW_Q_LENGTH, cpu_addr, dma_handle);
+		return 1;
+	}
+
+	memset(cpu_addr, 0, size*TW_Q_LENGTH);
+
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		switch(which) {
+		case 0:
+			tw_dev->command_packet_physical_address[i] = dma_handle+(i*size);
+			tw_dev->command_packet_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		case 1:
+			tw_dev->alignment_physical_address[i] = dma_handle+(i*size);
+			tw_dev->alignment_virtual_address[i] = (unsigned long *)((unsigned char *)cpu_addr + (i*size));
+			break;
+		default:
+			printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): case slip in tw_allocate_memory()\n");
+			return 1;
+		}
+	}
+
+	return 0;
+} /* End tw_allocate_memory() */
+
+/* This function handles ioctl for the character device */
+static int tw_chrdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int request_id;
+	dma_addr_t dma_handle;
+	unsigned short tw_aen_code;
+	unsigned long flags;
+	unsigned int data_buffer_length = 0;
+	unsigned long data_buffer_length_adjusted = 0;
+	unsigned long *cpu_addr;
+	long timeout;
+	TW_New_Ioctl *tw_ioctl;
+	TW_Passthru *passthru;
+	TW_Device_Extension *tw_dev = tw_device_extension_list[iminor(inode)];
+	int retval = -EFAULT;
+	void __user *argp = (void __user *)arg;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl()\n");
+
+	/* Only let one of these through at a time */
+	if (down_interruptible(&tw_dev->ioctl_sem))
+		return -EINTR;
+
+	/* First copy down the buffer length */
+	if (copy_from_user(&data_buffer_length, argp, sizeof(unsigned int)))
+		goto out;
+
+	/* Check size */
+	if (data_buffer_length > TW_MAX_IOCTL_SECTORS * 512) {
+		retval = -EINVAL;
+		goto out;
+	}
+
+	/* Hardware can only do multiple of 512 byte transfers */
+	data_buffer_length_adjusted = (data_buffer_length + 511) & ~511;
+	
+	/* Now allocate ioctl buf memory */
+	cpu_addr = dma_alloc_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, &dma_handle, GFP_KERNEL);
+	if (cpu_addr == NULL) {
+		retval = -ENOMEM;
+		goto out;
+	}
+
+	tw_ioctl = (TW_New_Ioctl *)cpu_addr;
+
+	/* Now copy down the entire ioctl */
+	if (copy_from_user(tw_ioctl, argp, data_buffer_length + sizeof(TW_New_Ioctl) - 1))
+		goto out2;
+
+	passthru = (TW_Passthru *)&tw_ioctl->firmware_command;
+
+	/* See which ioctl we are doing */
+	switch (cmd) {
+		case TW_OP_NOP:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_OP_NOP.\n");
+			break;
+		case TW_OP_AEN_LISTEN:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_AEN_LISTEN.\n");
+			memset(tw_ioctl->data_buffer, 0, data_buffer_length);
+
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+			if (tw_dev->aen_head == tw_dev->aen_tail) {
+				tw_aen_code = TW_AEN_QUEUE_EMPTY;
+			} else {
+				tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
+				if (tw_dev->aen_head == TW_Q_LENGTH - 1) {
+					tw_dev->aen_head = TW_Q_START;
+				} else {
+					tw_dev->aen_head = tw_dev->aen_head + 1;
+				}
+			}
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			memcpy(tw_ioctl->data_buffer, &tw_aen_code, sizeof(tw_aen_code));
+			break;
+		case TW_CMD_PACKET_WITH_DATA:
+			dprintk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): caught TW_CMD_PACKET_WITH_DATA.\n");
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+			tw_state_request_start(tw_dev, &request_id);
+
+			/* Flag internal command */
+			tw_dev->srb[request_id] = NULL;
+
+			/* Flag chrdev ioctl */
+			tw_dev->chrdev_request_id = request_id;
+
+			tw_ioctl->firmware_command.request_id = request_id;
+
+			/* Load the sg list */
+			switch (TW_SGL_OUT(tw_ioctl->firmware_command.opcode__sgloffset)) {
+			case 2:
+				tw_ioctl->firmware_command.byte8.param.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.param.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 3:
+				tw_ioctl->firmware_command.byte8.io.sgl[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				tw_ioctl->firmware_command.byte8.io.sgl[0].length = data_buffer_length_adjusted;
+				break;
+			case 5:
+				passthru->sg_list[0].address = dma_handle + sizeof(TW_New_Ioctl) - 1;
+				passthru->sg_list[0].length = data_buffer_length_adjusted;
+				break;
+			}
+
+			memcpy(tw_dev->command_packet_virtual_address[request_id], &(tw_ioctl->firmware_command), sizeof(TW_Command));
+
+			/* Now post the command packet to the controller */
+			tw_post_command_packet(tw_dev, request_id);
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+			timeout = TW_IOCTL_CHRDEV_TIMEOUT*HZ;
+
+			/* Now wait for the command to complete */
+			timeout = wait_event_timeout(tw_dev->ioctl_wqueue, tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE, timeout);
+
+			/* See if we reset while waiting for the ioctl to complete */
+			if (test_bit(TW_IN_RESET, &tw_dev->flags)) {
+				clear_bit(TW_IN_RESET, &tw_dev->flags);
+				retval = -ERESTARTSYS;
+				goto out2;
+			}
+
+			/* We timed out, and didn't get an interrupt */
+			if (tw_dev->chrdev_request_id != TW_IOCTL_CHRDEV_FREE) {
+				/* Now we need to reset the board */
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Character ioctl (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, cmd);
+				retval = -EIO;
+				spin_lock_irqsave(tw_dev->host->host_lock, flags);
+				tw_dev->state[request_id] = TW_S_COMPLETED;
+				tw_state_request_finish(tw_dev, request_id);
+				tw_dev->posted_request_count--;
+				spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+				if (tw_reset_device_extension(tw_dev, 1)) {
+					printk(KERN_WARNING "3w-xxxx: tw_chrdev_ioctl(): Reset failed for card %d.\n", tw_dev->host->host_no);
+				}
+				goto out2;
+			}
+
+			/* Now copy in the command packet response */
+			memcpy(&(tw_ioctl->firmware_command), tw_dev->command_packet_virtual_address[request_id], sizeof(TW_Command));
+
+			/* Now complete the io */
+			spin_lock_irqsave(tw_dev->host->host_lock, flags);
+			tw_dev->posted_request_count--;
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+			spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+			break;
+		default:
+			retval = -ENOTTY;
+			goto out2;
+	}
+
+	/* Now copy the response to userspace */
+	if (copy_to_user(argp, tw_ioctl, sizeof(TW_New_Ioctl) + data_buffer_length - 1))
+		goto out2;
+	retval = 0;
+out2:
+	/* Now free ioctl buf memory */
+	dma_free_coherent(&tw_dev->tw_pci_dev->dev, data_buffer_length_adjusted+sizeof(TW_New_Ioctl) - 1, cpu_addr, dma_handle);
+out:
+	up(&tw_dev->ioctl_sem);
+	return retval;
+} /* End tw_chrdev_ioctl() */
+
+/* This function handles open for the character device */
+static int tw_chrdev_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor_number;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_open()\n");
+
+	minor_number = iminor(inode);
+	if (minor_number >= tw_device_extension_count)
+		return -ENODEV;
+
+	return 0;
+} /* End tw_chrdev_open() */
+
+/* File operations struct for character device */
+static struct file_operations tw_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= tw_chrdev_ioctl,
+	.open		= tw_chrdev_open,
+	.release	= NULL
+};
+
+/* This function will free up device extension resources */
+static void tw_free_device_extension(TW_Device_Extension *tw_dev)
+{
+	dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
+
+	/* Free command packet and generic buffer memory */
+	if (tw_dev->command_packet_virtual_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Command)*TW_Q_LENGTH, tw_dev->command_packet_virtual_address[0], tw_dev->command_packet_physical_address[0]);
+
+	if (tw_dev->alignment_virtual_address[0])
+		pci_free_consistent(tw_dev->tw_pci_dev, sizeof(TW_Sector)*TW_Q_LENGTH, tw_dev->alignment_virtual_address[0], tw_dev->alignment_physical_address[0]);
+} /* End tw_free_device_extension() */
+
+/* This function will send an initconnection command to controller */
+static int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) 
+{
+	unsigned long command_que_value;
+	TW_Command  *command_packet;
+	TW_Response_Queue response_queue;
+	int request_id = 0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
+
+	/* Initialize InitConnection command packet */
+	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_INIT_CONNECTION);
+	command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;
+	command_packet->request_id = request_id;
+	command_packet->status = 0x0;
+	command_packet->flags = 0x0;
+	command_packet->byte6.message_credits = message_credits; 
+	command_packet->byte8.init_connection.response_queue_pointer = 0x0;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad command packet physical address.\n");
+		return 1;
+	}
+  
+	/* Send command packet to the board */
+	outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+    
+	/* Poll for completion */
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		request_id = TW_RESID_OUT(response_queue.response_id);
+
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected request id.\n");
+			return 1;
+		}
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
+		}
+	}
+	return 0;
+} /* End tw_initconnection() */
+
+/* Set a value in the features table */
+static int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size,
+                  unsigned char *val)
+{
+	TW_Param *param;
+	TW_Command  *command_packet;
+	TW_Response_Queue response_queue;
+	int request_id = 0;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+  	/* Initialize SetParam command packet */
+	if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	memset(command_packet, 0, sizeof(TW_Sector));
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_SET_PARAM);
+	param->table_id = 0x404;  /* Features table */
+	param->parameter_id = parm;
+	param->parameter_size_bytes = param_size;
+	memcpy(param->data, val, param_size);
+
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad alignment physical address.\n");
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		tw_dev->srb[request_id]->result = (DID_OK << 16);
+		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	}
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->byte6.parameter_count = 1;
+
+  	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad command packet physical address.\n");
+	return 1;
+	}
+
+	/* Send command packet to the board */
+	outl(command_que_value, TW_COMMAND_QUEUE_REG_ADDR(tw_dev));
+
+	/* Poll for completion */
+	if (tw_poll_status_gone(tw_dev, TW_STATUS_RESPONSE_QUEUE_EMPTY, 30) == 0) {
+		response_queue.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+		request_id = TW_RESID_OUT(response_queue.response_id);
+
+		if (request_id != 0) {
+			/* unexpected request id */
+			printk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected request id.\n");
+			return 1;
+		}
+		if (command_packet->status != 0) {
+			/* bad response */
+			tw_decode_sense(tw_dev, request_id, 0);
+			return 1;
+		}
+	}
+
+	return 0;
+} /* End tw_setfeature() */
+
+/* This function will reset a controller */
+static int tw_reset_sequence(TW_Device_Extension *tw_dev) 
+{
+	int error = 0;
+	int tries = 0;
+	unsigned char c = 1;
+
+	/* Reset the board */
+	while (tries < TW_MAX_RESET_TRIES) {
+		TW_SOFT_RESET(tw_dev);
+
+		error = tw_aen_drain_queue(tw_dev);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: AEN drain failed, retrying.\n", tw_dev->host->host_no);
+			tries++;
+			continue;
+		}
+
+		/* Check for controller errors */
+		if (tw_check_errors(tw_dev)) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors found, retrying.\n", tw_dev->host->host_no);
+			tries++;
+			continue;
+		}
+
+		/* Now the controller is in a good state */
+		break;
+	}
+
+	if (tries >= TW_MAX_RESET_TRIES) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Controller errors, card not responding, check all cabling.\n", tw_dev->host->host_no);
+		return 1;
+	}
+
+	error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Connection initialization failed.\n", tw_dev->host->host_no);
+		return 1;
+	}
+
+	error = tw_setfeature(tw_dev, 2, 1, &c);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Unable to set features for card, probable old firmware or card.\n");
+	}
+
+	return 0;
+} /* End tw_reset_sequence() */
+
+/* This function will initialize the fields of a device extension */
+static int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+	int i, error=0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
+
+	/* Initialize command packet buffers */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Command), 0);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Command packet memory allocation failed.\n");
+		return 1;
+	}
+
+	/* Initialize generic buffer */
+	error = tw_allocate_memory(tw_dev, sizeof(TW_Sector), 1);
+	if (error) {
+		printk(KERN_WARNING "3w-xxxx: Generic memory allocation failed.\n");
+		return 1;
+	}
+
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+
+	init_MUTEX(&tw_dev->ioctl_sem);
+	init_waitqueue_head(&tw_dev->ioctl_wqueue);
+
+	return 0;
+} /* End tw_initialize_device_extension() */
+
+static int tw_map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	int use_sg;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data()\n");
+	
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+	
+	if (use_sg == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_sg_data(): pci_map_sg() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SGLIST;
+	cmd->SCp.have_data_in = use_sg;
+	
+	return use_sg;
+} /* End tw_map_scsi_sg_data() */
+
+static u32 tw_map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	dma_addr_t mapping;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data()\n");
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = pci_map_page(pdev, virt_to_page(cmd->request_buffer), offset_in_page(cmd->request_buffer), cmd->request_bufflen, DMA_BIDIRECTIONAL);
+
+	if (mapping == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_map_scsi_single_data(): pci_map_page() failed.\n");
+		return 0;
+	}
+
+	cmd->SCp.phase = TW_PHASE_SINGLE;
+	cmd->SCp.have_data_in = mapping;
+
+	return mapping;
+} /* End tw_map_scsi_single_data() */
+
+static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n");
+
+	switch(cmd->SCp.phase) {
+		case TW_PHASE_SINGLE:
+			pci_unmap_page(pdev, cmd->SCp.have_data_in, cmd->request_bufflen, DMA_BIDIRECTIONAL);
+			break;
+		case TW_PHASE_SGLIST:
+			pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, DMA_BIDIRECTIONAL);
+			break;
+	}
+} /* End tw_unmap_scsi_data() */
+
+/* This function will reset a device extension */
+static int tw_reset_device_extension(TW_Device_Extension *tw_dev, int ioctl_reset) 
+{
+	int i = 0;
+	struct scsi_cmnd *srb;
+	unsigned long flags = 0;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
+
+	set_bit(TW_IN_RESET, &tw_dev->flags);
+	TW_DISABLE_INTERRUPTS(tw_dev);
+	TW_MASK_COMMAND_INTERRUPT(tw_dev);
+	spin_lock_irqsave(tw_dev->host->host_lock, flags);
+
+	/* Abort all requests that are in progress */
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		if ((tw_dev->state[i] != TW_S_FINISHED) && 
+		    (tw_dev->state[i] != TW_S_INITIAL) &&
+		    (tw_dev->state[i] != TW_S_COMPLETED)) {
+			srb = tw_dev->srb[i];
+			if (srb != NULL) {
+				srb->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+				tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
+			}
+		}
+	}
+
+	/* Reset queues and counts */
+	for (i=0;i<TW_Q_LENGTH;i++) {
+		tw_dev->free_queue[i] = i;
+		tw_dev->state[i] = TW_S_INITIAL;
+	}
+	tw_dev->free_head = TW_Q_START;
+	tw_dev->free_tail = TW_Q_START;
+	tw_dev->posted_request_count = 0;
+	tw_dev->pending_request_count = 0;
+	tw_dev->pending_head = TW_Q_START;
+	tw_dev->pending_tail = TW_Q_START;
+	tw_dev->reset_print = 0;
+
+	spin_unlock_irqrestore(tw_dev->host->host_lock, flags);
+
+	if (tw_reset_sequence(tw_dev)) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset sequence failed.\n", tw_dev->host->host_no);
+		return 1;
+	}
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Wake up any ioctl that was pending before the reset */
+	if ((tw_dev->chrdev_request_id == TW_IOCTL_CHRDEV_FREE) || (ioctl_reset)) {
+		clear_bit(TW_IN_RESET, &tw_dev->flags);
+	} else {
+		tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+		wake_up(&tw_dev->ioctl_wqueue);
+	}
+
+	return 0;
+} /* End tw_reset_device_extension() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+static int tw_scsi_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int geom[]) 
+{
+	int heads, sectors, cylinders;
+	TW_Device_Extension *tw_dev;
+	
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
+	tw_dev = (TW_Device_Extension *)sdev->host->hostdata;
+
+	heads = 64;
+	sectors = 32;
+	cylinders = sector_div(capacity, heads * sectors);
+
+	if (capacity >= 0x200000) {
+		heads = 255;
+		sectors = 63;
+		cylinders = sector_div(capacity, heads * sectors);
+	}
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
+	geom[0] = heads;			 
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+} /* End tw_scsi_biosparam() */
+
+/* This is the new scsi eh reset function */
+static int tw_scsi_eh_reset(struct scsi_cmnd *SCpnt) 
+{
+	TW_Device_Extension *tw_dev=NULL;
+	int retval = FAILED;
+
+	tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	spin_unlock_irq(tw_dev->host->host_lock);
+
+	tw_dev->num_resets++;
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: WARNING: Unit #%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, SCpnt->device->id, SCpnt->cmnd[0]);
+
+	/* Now reset the card and some of the device extension data */
+	if (tw_reset_device_extension(tw_dev, 0)) {
+		printk(KERN_WARNING "3w-xxxx: scsi%d: Reset failed.\n", tw_dev->host->host_no);
+		goto out;
+	}
+
+	retval = SUCCESS;
+out:
+	spin_lock_irq(tw_dev->host->host_lock);
+	return retval;
+} /* End tw_scsi_eh_reset() */
+
+/* This function handles scsi inquiry commands */
+static int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
+
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
+	param->parameter_size_bytes = TW_MAX_UNITS;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_inquiry() */
+
+/* This function is called by the isr to complete an inquiry command */
+static int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *is_unit_present;
+	unsigned char *request_buffer;
+	TW_Param *param;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
+
+	/* Fill request buffer */
+	if (tw_dev->srb[request_id]->request_buffer == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request buffer NULL.\n");
+		return 1;
+	}
+	request_buffer = tw_dev->srb[request_id]->request_buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	request_buffer[0] = TYPE_DISK; /* Peripheral device type */
+	request_buffer[1] = 0;	       /* Device type modifier */
+	request_buffer[2] = 0;	       /* No ansi/iso compliance */
+	request_buffer[4] = 31;	       /* Additional length */
+	memcpy(&request_buffer[8], "3ware   ", 8);	 /* Vendor ID */
+	sprintf(&request_buffer[16], "Logical Disk %-2d ", tw_dev->srb[request_id]->device->id);
+	memcpy(&request_buffer[32], TW_DRIVER_VERSION, 3);
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	is_unit_present = &(param->data[0]);
+
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
+	}
+
+	return 0;
+} /* End tw_scsiop_inquiry_complete() */
+
+/* This function handles scsi mode_sense commands */
+static int tw_scsiop_mode_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense()\n");
+
+	/* Only page control = 0, page code = 0x8 (cache page) supported */
+	if (tw_dev->srb[request_id]->cmnd[2] != 0x8) {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		tw_dev->srb[request_id]->result = (DID_OK << 16);
+		tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+		return 0;
+	}
+
+	/* Now read firmware cache setting for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment virtual address.\n");
+		return 1;
+	}
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + tw_dev->srb[request_id]->device->id;
+	param->parameter_id = 7; /* unit flags */
+	param->parameter_size_bytes = 1;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+	
+	return 0;
+} /* End tw_scsiop_mode_sense() */
+
+/* This function is called by the isr to complete a mode sense command */
+static int tw_scsiop_mode_sense_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	unsigned char *flags;
+	unsigned char *request_buffer;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_mode_sense_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_mode_sense_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	flags = (char *)&(param->data[0]);
+	request_buffer = tw_dev->srb[request_id]->buffer;
+	memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+
+	request_buffer[0] = 0xf;        /* mode data length */
+	request_buffer[1] = 0;          /* default medium type */
+	request_buffer[2] = 0x10;       /* dpo/fua support on */
+	request_buffer[3] = 0;          /* no block descriptors */
+	request_buffer[4] = 0x8;        /* caching page */
+	request_buffer[5] = 0xa;        /* page length */
+	if (*flags & 0x1)
+		request_buffer[6] = 0x4;        /* WCE on */
+	else
+		request_buffer[6] = 0x0;        /* WCE off */
+
+	return 0;
+} /* End tw_scsiop_mode_sense_complete() */
+
+/* This function handles scsi read_capacity commands */
+static int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
+
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+
+	if (command_packet == NULL) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.block_count = 1;
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + 
+	tw_dev->srb[request_id]->device->id;
+	param->parameter_id = 4;	/* unitcapacity parameter */
+	param->parameter_size_bytes = 4;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment physical address.\n");
+		return 1;
+	}
+  
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command to the board */
+	tw_post_command_packet(tw_dev, request_id);
+  
+	return 0;
+} /* End tw_scsiop_read_capacity() */
+
+/* This function is called by the isr to complete a readcapacity command */
+static int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *param_data;
+	u32 capacity;
+	char *buff;
+	TW_Param *param;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
+
+	buff = tw_dev->srb[request_id]->request_buffer;
+	if (buff == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Request buffer NULL.\n");
+		return 1;
+	}
+	memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param_data = &(param->data[0]);
+
+	capacity = (param_data[3] << 24) | (param_data[2] << 16) | 
+		   (param_data[1] << 8) | param_data[0];
+
+	/* Subtract one sector to fix get last sector ioctl */
+	capacity -= 1;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): Capacity = 0x%x.\n", capacity);
+
+	/* Number of LBA's */
+	buff[0] = (capacity >> 24);
+	buff[1] = (capacity >> 16) & 0xff;
+	buff[2] = (capacity >> 8) & 0xff;
+	buff[3] = capacity & 0xff;
+
+	/* Block size in bytes (512) */
+	buff[4] = (TW_BLOCK_SIZE >> 24);
+	buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
+	buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
+	buff[7] = TW_BLOCK_SIZE & 0xff;
+
+	return 0;
+} /* End tw_scsiop_read_capacity_complete() */
+
+/* This function handles scsi read or write commands */
+static int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
+{
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	u32 lba = 0x0, num_sectors = 0x0, buffaddr = 0x0;
+	int i, use_sg;
+	struct scsi_cmnd *srb;
+	struct scatterlist *sglist;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
+
+	if (tw_dev->srb[request_id]->request_buffer == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer NULL.\n");
+		return 1;
+	}
+	sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+	srb = tw_dev->srb[request_id];
+
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) {
+		command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_READ);
+	} else {
+		command_packet->opcode__sgloffset = TW_OPSGL_IN(3, TW_OP_WRITE);
+	}
+
+	command_packet->size = 3;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, srb->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
+
+	if (srb->cmnd[0] == WRITE_10) {
+		if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10))
+			command_packet->flags = 1;
+	}
+
+	if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
+		lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | (u32)srb->cmnd[3];
+		num_sectors = (u32)srb->cmnd[4];
+	} else {
+		lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
+		num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+	}
+  
+	/* Update sector statistic */
+	tw_dev->sector_count = num_sectors;
+	if (tw_dev->sector_count > tw_dev->max_sector_count)
+		tw_dev->max_sector_count = tw_dev->sector_count;
+  
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x num_sectors = 0x%x\n", lba, num_sectors);
+	command_packet->byte8.io.lba = lba;
+	command_packet->byte6.block_count = num_sectors;
+
+	/* Do this if there are no sg list entries */
+	if (tw_dev->srb[request_id]->use_sg == 0) {    
+		dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+		buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		if (buffaddr == 0)
+			return 1;
+
+		command_packet->byte8.io.sgl[0].address = buffaddr;
+		command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen;
+		command_packet->size+=2;
+	}
+
+	/* Do this if we have multiple sg list entries */
+	if (tw_dev->srb[request_id]->use_sg > 0) {
+		use_sg = tw_map_scsi_sg_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+		if (use_sg == 0)
+			return 1;
+
+		for (i=0;i<use_sg; i++) {
+			command_packet->byte8.io.sgl[i].address = sg_dma_address(&sglist[i]);
+			command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
+			command_packet->size+=2;
+		}
+	}
+
+	/* Update SG statistics */
+	tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+	if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+		tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command packet physical address.\n");
+		return 1;
+	}
+      
+	/* Now try to post the command to the board */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_read_write() */
+
+/* This function will handle the request sense scsi command */
+static int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+
+	/* For now we just zero the request buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+	return 0;
+} /* End tw_scsiop_request_sense() */
+
+/* This function will handle synchronize cache scsi command */
+static int tw_scsiop_synchronize_cache(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_synchronize_cache()\n");
+
+	/* Send firmware flush command for this unit */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet virtual address.\n");
+		return 1;
+	}
+
+	/* Setup the command packet */
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(0, TW_OP_FLUSH_CACHE);
+	command_packet->size = 2;
+	command_packet->request_id = request_id;
+	command_packet->unit__hostid = TW_UNITHOST_IN(0, tw_dev->srb[request_id]->device->id);
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_synchronize_cache(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_synchronize_cache() */
+
+/* This function will handle test unit ready scsi command */
+static int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
+{
+	TW_Param *param;
+	TW_Command *command_packet;
+	unsigned long command_que_value;
+	unsigned long param_value;
+
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
+
+	/* Initialize command packet */
+	command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet virtual address.\n");
+		return 1;
+	}
+	memset(command_packet, 0, sizeof(TW_Sector));
+	command_packet->opcode__sgloffset = TW_OPSGL_IN(2, TW_OP_GET_PARAM);
+	command_packet->size = 4;
+	command_packet->request_id = request_id;
+	command_packet->status = 0;
+	command_packet->flags = 0;
+	command_packet->byte6.parameter_count = 1;
+
+	/* Now setup the param */
+	if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	memset(param, 0, sizeof(TW_Sector));
+	param->table_id = 3;	 /* unit summary table */
+	param->parameter_id = 3; /* unitsstatus parameter */
+	param->parameter_size_bytes = TW_MAX_UNITS;
+	param_value = tw_dev->alignment_physical_address[request_id];
+	if (param_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad alignment physical address.\n");
+		return 1;
+	}
+
+	command_packet->byte8.param.sgl[0].address = param_value;
+	command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+	command_que_value = tw_dev->command_packet_physical_address[request_id];
+	if (command_que_value == 0) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready(): Bad command packet physical address.\n");
+		return 1;
+	}
+
+	/* Now try to post the command packet */
+	tw_post_command_packet(tw_dev, request_id);
+
+	return 0;
+} /* End tw_scsiop_test_unit_ready() */
+
+/* This function is called by the isr to complete a testunitready command */
+static int tw_scsiop_test_unit_ready_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+	unsigned char *is_unit_present;
+	TW_Param *param;
+
+	dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete()\n");
+
+	param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+	if (param == NULL) {
+		printk(KERN_WARNING "3w-xxxx: tw_scsiop_test_unit_ready_complete(): Bad alignment virtual address.\n");
+		return 1;
+	}
+	is_unit_present = &(param->data[0]);
+
+	if (is_unit_present[tw_dev->srb[request_id]->device->id] & TW_UNIT_ONLINE) {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 1;
+	} else {
+		tw_dev->is_unit_present[tw_dev->srb[request_id]->device->id] = 0;
+		tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+		return TW_ISR_DONT_RESULT;
+	}
+
+	return 0;
+} /* End tw_scsiop_test_unit_ready_complete() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+static int tw_scsi_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) 
+{
+	unsigned char *command = SCpnt->cmnd;
+	int request_id = 0;
+	int retval = 1;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->device->host->hostdata;
+
+	/* Save done function into Scsi_Cmnd struct */
+	SCpnt->scsi_done = done;
+		 
+	/* Queue the command and get a request id */
+	tw_state_request_start(tw_dev, &request_id);
+
+	/* Save the scsi command for use by the ISR */
+	tw_dev->srb[request_id] = SCpnt;
+
+	/* Initialize phase to zero */
+	SCpnt->SCp.phase = TW_PHASE_INITIAL;
+
+	switch (*command) {
+		case READ_10:
+		case READ_6:
+		case WRITE_10:
+		case WRITE_6:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ/WRITE.\n");
+			retval = tw_scsiop_read_write(tw_dev, request_id);
+			break;
+		case TEST_UNIT_READY:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n");
+			retval = tw_scsiop_test_unit_ready(tw_dev, request_id);
+			break;
+		case INQUIRY:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n");
+			retval = tw_scsiop_inquiry(tw_dev, request_id);
+			break;
+		case READ_CAPACITY:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
+			retval = tw_scsiop_read_capacity(tw_dev, request_id);
+			break;
+	        case REQUEST_SENSE:
+		        dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
+		        retval = tw_scsiop_request_sense(tw_dev, request_id);
+		        break;
+		case MODE_SENSE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught MODE_SENSE.\n");
+			retval = tw_scsiop_mode_sense(tw_dev, request_id);
+			break;
+		case SYNCHRONIZE_CACHE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught SYNCHRONIZE_CACHE.\n");
+			retval = tw_scsiop_synchronize_cache(tw_dev, request_id);
+			break;
+		case TW_IOCTL:
+			printk(KERN_WARNING "3w-xxxx: SCSI_IOCTL_SEND_COMMAND deprecated, please update your 3ware tools.\n");
+			break;
+		default:
+			printk(KERN_NOTICE "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x\n", tw_dev->host->host_no, *command);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+			SCpnt->result = (DID_BAD_TARGET << 16);
+			done(SCpnt);
+			retval = 0;
+	}
+	if (retval) {
+		tw_dev->state[request_id] = TW_S_COMPLETED;
+		tw_state_request_finish(tw_dev, request_id);
+		SCpnt->result = (DID_ERROR << 16);
+		done(SCpnt);
+		retval = 0;
+	}
+	return retval;
+} /* End tw_scsi_queue() */
+
+/* This function is the interrupt service routine */
+static irqreturn_t tw_interrupt(int irq, void *dev_instance,
+		     struct pt_regs *regs) 
+{
+	int request_id;
+	u32 status_reg_value;
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+	TW_Response_Queue response_que;
+	int error = 0, retval = 0;
+	TW_Command *command_packet;
+	int handled = 0;
+
+	/* Get the host lock for io completions */
+	spin_lock(tw_dev->host->host_lock);
+
+	/* Read the registers */
+	status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+
+	/* Check if this is our interrupt, otherwise bail */
+	if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT))
+		goto tw_interrupt_bail;
+
+	handled = 1;
+
+	/* Check controller for errors */
+	if (tw_check_bits(status_reg_value)) {
+		dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+		if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+			TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+			goto tw_interrupt_bail;
+		}
+	}
+
+	/* Handle host interrupt */
+	if (status_reg_value & TW_STATUS_HOST_INTERRUPT) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n");
+		TW_CLEAR_HOST_INTERRUPT(tw_dev);
+	}
+
+	/* Handle attention interrupt */
+	if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) {
+		dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+		TW_CLEAR_ATTENTION_INTERRUPT(tw_dev);
+		tw_state_request_start(tw_dev, &request_id);
+		error = tw_aen_read_queue(tw_dev, request_id);
+		if (error) {
+			printk(KERN_WARNING "3w-xxxx: scsi%d: Error reading aen queue.\n", tw_dev->host->host_no);
+			tw_dev->state[request_id] = TW_S_COMPLETED;
+			tw_state_request_finish(tw_dev, request_id);
+		}
+	}
+
+	/* Handle command interrupt */
+	if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) {
+		/* Drain as many pending commands as we can */
+		while (tw_dev->pending_request_count > 0) {
+			request_id = tw_dev->pending_queue[tw_dev->pending_head];
+			if (tw_dev->state[request_id] != TW_S_PENDING) {
+				printk(KERN_WARNING "3w-xxxx: scsi%d: Found request id that wasn't pending.\n", tw_dev->host->host_no);
+				break;
+			}
+			if (tw_post_command_packet(tw_dev, request_id)==0) {
+				if (tw_dev->pending_head == TW_Q_LENGTH-1) {
+					tw_dev->pending_head = TW_Q_START;
+				} else {
+					tw_dev->pending_head = tw_dev->pending_head + 1;
+				}
+				tw_dev->pending_request_count--;
+			} else {
+				/* If we get here, we will continue re-posting on the next command interrupt */
+				break;
+			}
+		}
+		/* If there are no more pending requests, we mask command interrupt */
+		if (tw_dev->pending_request_count == 0) 
+			TW_MASK_COMMAND_INTERRUPT(tw_dev);
+	}
+
+	/* Handle response interrupt */
+	if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) {
+		/* Drain the response queue from the board */
+		while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+			/* Read response queue register */
+			response_que.value = inl(TW_RESPONSE_QUEUE_REG_ADDR(tw_dev));
+			request_id = TW_RESID_OUT(response_que.response_id);
+			command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+			error = 0;
+
+			/* Check for bad response */
+			if (command_packet->status != 0) {
+				/* If internal command, don't error, don't fill sense */
+				if (tw_dev->srb[request_id] == NULL) {
+					tw_decode_sense(tw_dev, request_id, 0);
+				} else {
+					error = tw_decode_sense(tw_dev, request_id, 1);
+				}
+			}
+
+			/* Check for correct state */
+			if (tw_dev->state[request_id] != TW_S_POSTED) {
+				if (tw_dev->srb[request_id] != NULL) {
+					printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id that wasn't posted.\n", tw_dev->host->host_no);
+					error = 1;
+				}
+			}
+
+			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
+
+			/* Check for internal command completion */
+			if (tw_dev->srb[request_id] == NULL) {
+				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n");
+				/* Check for chrdev ioctl completion */
+				if (request_id != tw_dev->chrdev_request_id) {
+					retval = tw_aen_complete(tw_dev, request_id);
+					if (retval) {
+						printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no);
+					}
+				} else {
+					tw_dev->chrdev_request_id = TW_IOCTL_CHRDEV_FREE;
+					wake_up(&tw_dev->ioctl_wqueue);
+				}
+			} else {
+				switch (tw_dev->srb[request_id]->cmnd[0]) {
+				case READ_10:
+				case READ_6:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10/READ_6\n");
+					break;
+				case WRITE_10:
+				case WRITE_6:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10/WRITE_6\n");
+					break;
+				case TEST_UNIT_READY:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TEST_UNIT_READY\n");
+					error = tw_scsiop_test_unit_ready_complete(tw_dev, request_id);
+					break;
+				case INQUIRY:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
+					error = tw_scsiop_inquiry_complete(tw_dev, request_id);
+					break;
+				case READ_CAPACITY:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_CAPACITY\n");
+					error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
+					break;
+				case MODE_SENSE:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught MODE_SENSE\n");
+					error = tw_scsiop_mode_sense_complete(tw_dev, request_id);
+					break;
+				case SYNCHRONIZE_CACHE:
+					dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught SYNCHRONIZE_CACHE\n");
+					break;
+				default:
+					printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n");
+					error = 1;
+				}
+
+				/* If no error command was a success */
+				if (error == 0) {
+					tw_dev->srb[request_id]->result = (DID_OK << 16);
+				}
+
+				/* If error, command failed */
+				if (error == 1) {
+					/* Ask for a host reset */
+					tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+				}
+
+				/* Now complete the io */
+				if ((error != TW_ISR_DONT_COMPLETE)) {
+					tw_dev->state[request_id] = TW_S_COMPLETED;
+					tw_state_request_finish(tw_dev, request_id);
+					tw_dev->posted_request_count--;
+					tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+					
+					tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
+				}
+			}
+				
+			/* Check for valid status after each drain */
+			status_reg_value = inl(TW_STATUS_REG_ADDR(tw_dev));
+			if (tw_check_bits(status_reg_value)) {
+				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+				if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+					TW_CLEAR_ALL_INTERRUPTS(tw_dev);
+					goto tw_interrupt_bail;
+				}
+			}
+		}
+	}
+
+tw_interrupt_bail:
+	spin_unlock(tw_dev->host->host_lock);
+	return IRQ_RETVAL(handled);
+} /* End tw_interrupt() */
+
+/* This function tells the controller to shut down */
+static void __tw_shutdown(TW_Device_Extension *tw_dev)
+{
+	/* Disable interrupts */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	printk(KERN_WARNING "3w-xxxx: Shutting down host %d.\n", tw_dev->host->host_no);
+
+	/* Tell the card we are shutting down */
+	if (tw_initconnection(tw_dev, 1)) {
+		printk(KERN_WARNING "3w-xxxx: Connection shutdown failed.\n");
+	} else {
+		printk(KERN_WARNING "3w-xxxx: Shutdown complete.\n");
+	}
+
+	/* Clear all interrupts just before exit */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+} /* End __tw_shutdown() */
+
+/* Wrapper for __tw_shutdown */
+static void tw_shutdown(struct device *dev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	__tw_shutdown(tw_dev);
+} /* End tw_shutdown() */
+
+static struct scsi_host_template driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "3ware Storage Controller",
+	.queuecommand		= tw_scsi_queue,
+	.eh_host_reset_handler	= tw_scsi_eh_reset,
+	.bios_param		= tw_scsi_biosparam,
+	.change_queue_depth	= tw_change_queue_depth,
+	.can_queue		= TW_Q_LENGTH-2,
+	.this_id		= -1,
+	.sg_tablesize		= TW_MAX_SGL_LENGTH,
+	.max_sectors		= TW_MAX_SECTORS,
+	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,	
+	.use_clustering		= ENABLE_CLUSTERING,
+	.shost_attrs		= tw_host_attrs,
+	.emulated		= 1
+};
+
+/* This function will probe and initialize a card */
+static int __devinit tw_probe(struct pci_dev *pdev, const struct pci_device_id *dev_id)
+{
+	struct Scsi_Host *host = NULL;
+	TW_Device_Extension *tw_dev;
+	int retval = -ENODEV;
+
+	retval = pci_enable_device(pdev);
+	if (retval) {
+		printk(KERN_WARNING "3w-xxxx: Failed to enable pci device.");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	retval = pci_set_dma_mask(pdev, TW_DMA_MASK);
+	if (retval) {
+		printk(KERN_WARNING "3w-xxxx: Failed to set dma mask.");
+		goto out_disable_device;
+	}
+
+	host = scsi_host_alloc(&driver_template, sizeof(TW_Device_Extension));
+	if (!host) {
+		printk(KERN_WARNING "3w-xxxx: Failed to allocate memory for device extension.");
+		retval = -ENOMEM;
+		goto out_disable_device;
+	}
+	tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+	/* Save values to device extension */
+	tw_dev->host = host;
+	tw_dev->tw_pci_dev = pdev;
+
+	if (tw_initialize_device_extension(tw_dev)) {
+		printk(KERN_WARNING "3w-xxxx: Failed to initialize device extension.");
+		goto out_free_device_extension;
+	}
+
+	/* Request IO regions */
+	retval = pci_request_regions(pdev, "3w-xxxx");
+	if (retval) {
+		printk(KERN_WARNING "3w-xxxx: Failed to get mem region.");
+		goto out_free_device_extension;
+	}
+
+	/* Save base address */
+	tw_dev->base_addr = pci_resource_start(pdev, 0);
+	if (!tw_dev->base_addr) {
+		printk(KERN_WARNING "3w-xxxx: Failed to get io address.");
+		goto out_release_mem_region;
+	}
+
+	/* Disable interrupts on the card */
+	TW_DISABLE_INTERRUPTS(tw_dev);
+
+	/* Initialize the card */
+	if (tw_reset_sequence(tw_dev))
+		goto out_release_mem_region;
+
+	/* Set host specific parameters */
+	host->max_id = TW_MAX_UNITS;
+	host->max_cmd_len = TW_MAX_CDB_LEN;
+
+	/* Luns and channels aren't supported by adapter */
+	host->max_lun = 0;
+	host->max_channel = 0;
+
+	/* Register the card with the kernel SCSI layer */
+	retval = scsi_add_host(host, &pdev->dev);
+	if (retval) {
+		printk(KERN_WARNING "3w-xxxx: scsi add host failed");
+		goto out_release_mem_region;
+	}
+
+	pci_set_drvdata(pdev, host);
+
+	printk(KERN_WARNING "3w-xxxx: scsi%d: Found a 3ware Storage Controller at 0x%x, IRQ: %d.\n", host->host_no, tw_dev->base_addr, pdev->irq);
+
+	/* Now setup the interrupt handler */
+	retval = request_irq(pdev->irq, tw_interrupt, SA_SHIRQ, "3w-xxxx", tw_dev);
+	if (retval) {
+		printk(KERN_WARNING "3w-xxxx: Error requesting IRQ.");
+		goto out_remove_host;
+	}
+
+	tw_device_extension_list[tw_device_extension_count] = tw_dev;
+	tw_device_extension_count++;
+
+	/* Re-enable interrupts on the card */
+	TW_ENABLE_AND_CLEAR_INTERRUPTS(tw_dev);
+
+	/* Finally, scan the host */
+	scsi_scan_host(host);
+
+	if (twe_major == -1) {
+		if ((twe_major = register_chrdev (0, "twe", &tw_fops)) < 0)
+			printk(KERN_WARNING "3w-xxxx: Failed to register character device.");
+	}
+	return 0;
+
+out_remove_host:
+	scsi_remove_host(host);
+out_release_mem_region:
+	pci_release_regions(pdev);
+out_free_device_extension:
+	tw_free_device_extension(tw_dev);
+	scsi_host_put(host);
+out_disable_device:
+	pci_disable_device(pdev);
+
+	return retval;
+} /* End tw_probe() */
+
+/* This function is called to remove a device */
+static void tw_remove(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	TW_Device_Extension *tw_dev = (TW_Device_Extension *)host->hostdata;
+
+	scsi_remove_host(tw_dev->host);
+
+	/* Unregister character device */
+	if (twe_major >= 0) {
+		unregister_chrdev(twe_major, "twe");
+		twe_major = -1;
+	}
+
+	/* Free up the IRQ */
+	free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+	/* Shutdown the card */
+	__tw_shutdown(tw_dev);
+
+	/* Free up the mem region */
+	pci_release_regions(pdev);
+
+	/* Free up device extension resources */
+	tw_free_device_extension(tw_dev);
+
+	scsi_host_put(tw_dev->host);
+	pci_disable_device(pdev);
+	tw_device_extension_count--;
+} /* End tw_remove() */
+
+/* PCI Devices supported by this driver */
+static struct pci_device_id tw_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_1000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ PCI_VENDOR_ID_3WARE, PCI_DEVICE_ID_3WARE_7000,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, tw_pci_tbl);
+
+/* pci_driver initializer */
+static struct pci_driver tw_driver = {
+	.name		= "3w-xxxx",
+	.id_table	= tw_pci_tbl,
+	.probe		= tw_probe,
+	.remove		= tw_remove,
+	.driver		= {
+		.shutdown = tw_shutdown
+	}
+};
+
+/* This function is called on driver initialization */
+static int __init tw_init(void)
+{
+	printk(KERN_WARNING "3ware Storage Controller device driver for Linux v%s.\n", TW_DRIVER_VERSION);
+
+	return pci_module_init(&tw_driver);
+} /* End tw_init() */
+
+/* This function is called on driver exit */
+static void __exit tw_exit(void)
+{
+	pci_unregister_driver(&tw_driver);
+} /* End tw_exit() */
+
+module_init(tw_init);
+module_exit(tw_exit);
+
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
new file mode 100644
index 0000000..98bad77
--- /dev/null
+++ b/drivers/scsi/3w-xxxx.h
@@ -0,0 +1,436 @@
+/* 
+   3w-xxxx.h -- 3ware Storage Controller device driver for Linux.
+   
+   Written By: Adam Radford <linuxraid@amcc.com>
+   Modifications By: Joel Jacobson <linux@3ware.com>
+   		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+                     Brad Strand <linux@3ware.com>
+
+   Copyright (C) 1999-2005 3ware Inc.
+
+   Kernel compatiblity By:	Andre Hedrick <andre@suse.com>
+   Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; version 2 of the License.
+
+   This program is distributed in the hope that it will be useful,           
+   but WITHOUT ANY WARRANTY; without even the implied warranty of            
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             
+   GNU General Public License for more details.                              
+
+   NO WARRANTY                                                               
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
+   solely responsible for determining the appropriateness of using and       
+   distributing the Program and assumes all risks associated with its        
+   exercise of rights under this Agreement, including but not limited to     
+   the risks and costs of program errors, damage to or loss of data,         
+   programs or equipment, and unavailability or interruption of operations.  
+
+   DISCLAIMER OF LIABILITY                                                   
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
+
+   You should have received a copy of the GNU General Public License         
+   along with this program; if not, write to the Free Software               
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+
+   Bugs/Comments/Suggestions should be mailed to:                            
+   linuxraid@amcc.com
+   
+   For more information, goto:
+   http://www.amcc.com
+*/
+
+#ifndef _3W_XXXX_H
+#define _3W_XXXX_H
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+/* AEN strings */
+static char *tw_aen_string[] = {
+	[0x000] = "INFO: AEN queue empty",
+	[0x001] = "INFO: Soft reset occurred",
+	[0x002] = "ERROR: Unit degraded: Unit #",
+	[0x003] = "ERROR: Controller error",
+	[0x004] = "ERROR: Rebuild failed: Unit #",
+	[0x005] = "INFO: Rebuild complete: Unit #",
+	[0x006] = "ERROR: Incomplete unit detected: Unit #",
+	[0x007] = "INFO: Initialization complete: Unit #",
+	[0x008] = "WARNING: Unclean shutdown detected: Unit #",
+	[0x009] = "WARNING: ATA port timeout: Port #",
+	[0x00A] = "ERROR: Drive error: Port #",
+	[0x00B] = "INFO: Rebuild started: Unit #",
+	[0x00C] = "INFO: Initialization started: Unit #",
+	[0x00D] = "ERROR: Logical unit deleted: Unit #",
+	[0x00F] = "WARNING: SMART threshold exceeded: Port #",
+	[0x021] = "WARNING: ATA UDMA downgrade: Port #",
+	[0x021] = "WARNING: ATA UDMA upgrade: Port #",
+	[0x023] = "WARNING: Sector repair occurred: Port #",
+	[0x024] = "ERROR: SBUF integrity check failure",
+	[0x025] = "ERROR: Lost cached write: Port #",
+	[0x026] = "ERROR: Drive ECC error detected: Port #",
+	[0x027] = "ERROR: DCB checksum error: Port #",
+	[0x028] = "ERROR: DCB unsupported version: Port #",
+	[0x029] = "INFO: Verify started: Unit #",
+	[0x02A] = "ERROR: Verify failed: Port #",
+	[0x02B] = "INFO: Verify complete: Unit #",
+	[0x02C] = "WARNING: Overwrote bad sector during rebuild: Port #",
+	[0x02D] = "ERROR: Encountered bad sector during rebuild: Port #",
+	[0x02E] = "ERROR: Replacement drive is too small: Port #",
+	[0x02F] = "WARNING: Verify error: Unit not previously initialized: Unit #",
+	[0x030] = "ERROR: Drive not supported: Port #"
+};
+
+/*
+   Sense key lookup table
+   Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier
+*/
+static unsigned char tw_sense_table[][4] =
+{
+  /* Codes for newer firmware */
+                            // ATA Error                    SCSI Error
+  {0x01, 0x03, 0x13, 0x00}, // Address mark not found       Address mark not found for data field
+  {0x04, 0x0b, 0x00, 0x00}, // Aborted command              Aborted command
+  {0x10, 0x0b, 0x14, 0x00}, // ID not found                 Recorded entity not found
+  {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error      Unrecovered read error
+  {0x61, 0x04, 0x00, 0x00}, // Device fault                 Hardware error
+  {0x84, 0x0b, 0x47, 0x00}, // Data CRC error               SCSI parity error
+  {0xd0, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0xd1, 0x0b, 0x00, 0x00}, // Device busy                  Aborted command
+  {0x37, 0x02, 0x04, 0x00}, // Unit offline                 Not ready
+  {0x09, 0x02, 0x04, 0x00}, // Unrecovered disk error       Not ready
+
+  /* Codes for older firmware */
+                            // 3ware Error                  SCSI Error
+  {0x51, 0x0b, 0x00, 0x00}  // Unspecified                  Aborted command
+};
+
+/* Control register bit definitions */
+#define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
+#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT   0x00040000
+#define TW_CONTROL_MASK_COMMAND_INTERRUPT      0x00020000
+#define TW_CONTROL_MASK_RESPONSE_INTERRUPT     0x00010000
+#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT    0x00008000
+#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT   0x00004000
+#define TW_CONTROL_CLEAR_ERROR_STATUS	       0x00000200
+#define TW_CONTROL_ISSUE_SOFT_RESET	       0x00000100
+#define TW_CONTROL_ENABLE_INTERRUPTS	       0x00000080
+#define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
+#define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
+#define TW_CONTROL_CLEAR_PARITY_ERROR          0x00800000
+#define TW_CONTROL_CLEAR_QUEUE_ERROR           0x00400000
+#define TW_CONTROL_CLEAR_PCI_ABORT             0x00100000
+#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR      0x00000008
+
+/* Status register bit definitions */
+#define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
+#define TW_STATUS_MINOR_VERSION_MASK	       0x0F000000
+#define TW_STATUS_PCI_PARITY_ERROR	       0x00800000
+#define TW_STATUS_QUEUE_ERROR		       0x00400000
+#define TW_STATUS_MICROCONTROLLER_ERROR	       0x00200000
+#define TW_STATUS_PCI_ABORT		       0x00100000
+#define TW_STATUS_HOST_INTERRUPT	       0x00080000
+#define TW_STATUS_ATTENTION_INTERRUPT	       0x00040000
+#define TW_STATUS_COMMAND_INTERRUPT	       0x00020000
+#define TW_STATUS_RESPONSE_INTERRUPT	       0x00010000
+#define TW_STATUS_COMMAND_QUEUE_FULL	       0x00008000
+#define TW_STATUS_RESPONSE_QUEUE_EMPTY	       0x00004000
+#define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
+#define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
+#define TW_STATUS_ALL_INTERRUPTS	       0x000F0000
+#define TW_STATUS_CLEARABLE_BITS	       0x00D00000
+#define TW_STATUS_EXPECTED_BITS		       0x00002000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F00008
+#define TW_STATUS_SBUF_WRITE_ERROR             0x00000008
+#define TW_STATUS_VALID_INTERRUPT              0x00DF0008
+
+/* RESPONSE QUEUE BIT DEFINITIONS */
+#define TW_RESPONSE_ID_MASK		       0x00000FF0
+
+/* PCI related defines */
+#define TW_IO_ADDRESS_RANGE		       0x10
+#define TW_DEVICE_NAME			       "3ware Storage Controller"
+#define TW_VENDOR_ID (0x13C1)	/* 3ware */
+#define TW_DEVICE_ID (0x1000)	/* Storage Controller */
+#define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
+#define TW_NUMDEVICES 2
+#define TW_PCI_CLEAR_PARITY_ERRORS 0xc100
+#define TW_PCI_CLEAR_PCI_ABORT     0x2000
+
+/* Command packet opcodes */
+#define TW_OP_NOP	      0x0
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_READ	      0x2
+#define TW_OP_WRITE	      0x3
+#define TW_OP_VERIFY	      0x4
+#define TW_OP_GET_PARAM	      0x12
+#define TW_OP_SET_PARAM	      0x13
+#define TW_OP_SECTOR_INFO     0x1a
+#define TW_OP_AEN_LISTEN      0x1c
+#define TW_OP_FLUSH_CACHE     0x0e
+#define TW_CMD_PACKET         0x1d
+#define TW_CMD_PACKET_WITH_DATA 0x1f
+
+/* Asynchronous Event Notification (AEN) Codes */
+#define TW_AEN_QUEUE_EMPTY       0x0000
+#define TW_AEN_SOFT_RESET        0x0001
+#define TW_AEN_DEGRADED_MIRROR   0x0002
+#define TW_AEN_CONTROLLER_ERROR  0x0003
+#define TW_AEN_REBUILD_FAIL      0x0004
+#define TW_AEN_REBUILD_DONE      0x0005
+#define TW_AEN_QUEUE_FULL        0x00ff
+#define TW_AEN_TABLE_UNDEFINED   0x15
+#define TW_AEN_APORT_TIMEOUT     0x0009
+#define TW_AEN_DRIVE_ERROR       0x000A
+#define TW_AEN_SMART_FAIL        0x000F
+#define TW_AEN_SBUF_FAIL         0x0024
+
+/* Phase defines */
+#define TW_PHASE_INITIAL 0
+#define TW_PHASE_SINGLE 1
+#define TW_PHASE_SGLIST 2
+
+/* Misc defines */
+#define TW_ALIGNMENT_6000		      64 /* 64 bytes */
+#define TW_ALIGNMENT_7000                     4  /* 4 bytes */
+#define TW_MAX_UNITS			      16
+#define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
+#define TW_INIT_MESSAGE_CREDITS		      0x100
+#define TW_INIT_COMMAND_PACKET_SIZE	      0x3
+#define TW_POLL_MAX_RETRIES        	      20000
+#define TW_MAX_SGL_LENGTH		      62
+#define TW_ATA_PASS_SGL_MAX                   60
+#define TW_Q_LENGTH			      256
+#define TW_Q_START			      0
+#define TW_MAX_SLOT			      32
+#define TW_MAX_PCI_BUSES		      255
+#define TW_MAX_RESET_TRIES		      3
+#define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
+#define TW_MAX_CMDS_PER_LUN		      254 /* 254 for io, 1 for
+                                                     chrdev ioctl, one for
+                                                     internal aen post */
+#define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
+#define TW_IOCTL                              0x80
+#define TW_UNIT_ONLINE                        1
+#define TW_IN_INTR                            1
+#define TW_IN_RESET                           2
+#define TW_IN_CHRDEV_IOCTL                    3
+#define TW_MAX_SECTORS                        256
+#define TW_MAX_IOCTL_SECTORS		      512
+#define TW_AEN_WAIT_TIME                      1000
+#define TW_IOCTL_WAIT_TIME                    (1 * HZ) /* 1 second */
+#define TW_ISR_DONT_COMPLETE                  2
+#define TW_ISR_DONT_RESULT                    3
+#define TW_IOCTL_TIMEOUT                      25 /* 25 seconds */
+#define TW_IOCTL_CHRDEV_TIMEOUT               60 /* 60 seconds */
+#define TW_IOCTL_CHRDEV_FREE                  -1
+#define TW_DMA_MASK			      DMA_32BIT_MASK
+#define TW_MAX_CDB_LEN			      16
+
+/* Bitmask macros to eliminate bitfields */
+
+/* opcode: 5, sgloffset: 3 */
+#define TW_OPSGL_IN(x,y) ((x << 5) | (y & 0x1f))
+#define TW_SGL_OUT(x) ((x >> 5) & 0x7)
+
+/* reserved_1: 4, response_id: 8, reserved_2: 20 */
+#define TW_RESID_OUT(x) ((x >> 4) & 0xff)
+
+/* unit: 4, host_id: 4 */
+#define TW_UNITHOST_IN(x,y) ((x << 4) | ( y & 0xf))
+#define TW_UNIT_OUT(x) (x & 0xf)
+
+/* Macros */
+#define TW_CONTROL_REG_ADDR(x) (x->base_addr)
+#define TW_STATUS_REG_ADDR(x) (x->base_addr + 0x4)
+#define TW_COMMAND_QUEUE_REG_ADDR(x) (x->base_addr + 0x8)
+#define TW_RESPONSE_QUEUE_REG_ADDR(x) (x->base_addr + 0xC)
+#define TW_CLEAR_ALL_INTERRUPTS(x) (outl(TW_STATUS_VALID_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_ATTENTION_INTERRUPT(x) (outl(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_CLEAR_HOST_INTERRUPT(x) (outl(TW_CONTROL_CLEAR_HOST_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_DISABLE_INTERRUPTS(x) (outl(TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_ENABLE_AND_CLEAR_INTERRUPTS(x) (outl(TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | TW_CONTROL_UNMASK_RESPONSE_INTERRUPT | TW_CONTROL_ENABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_MASK_COMMAND_INTERRUPT(x) (outl(TW_CONTROL_MASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_UNMASK_COMMAND_INTERRUPT(x) (outl(TW_CONTROL_UNMASK_COMMAND_INTERRUPT, TW_CONTROL_REG_ADDR(x)))
+#define TW_SOFT_RESET(x) (outl(TW_CONTROL_ISSUE_SOFT_RESET | \
+			TW_CONTROL_CLEAR_HOST_INTERRUPT | \
+			TW_CONTROL_CLEAR_ATTENTION_INTERRUPT | \
+			TW_CONTROL_MASK_COMMAND_INTERRUPT | \
+			TW_CONTROL_MASK_RESPONSE_INTERRUPT | \
+			TW_CONTROL_CLEAR_ERROR_STATUS | \
+			TW_CONTROL_DISABLE_INTERRUPTS, TW_CONTROL_REG_ADDR(x)))
+#define TW_STATUS_ERRORS(x) \
+	(((x & TW_STATUS_PCI_ABORT) || \
+	(x & TW_STATUS_PCI_PARITY_ERROR) || \
+	(x & TW_STATUS_QUEUE_ERROR) || \
+	(x & TW_STATUS_MICROCONTROLLER_ERROR)) && \
+	(x & TW_STATUS_MICROCONTROLLER_READY))
+
+#ifdef TW_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0)
+#endif
+
+#pragma pack(1)
+
+/* Scatter Gather List Entry */
+typedef struct TAG_TW_SG_Entry {
+	u32 address;
+	u32 length;
+} TW_SG_Entry;
+
+typedef unsigned char TW_Sector[512];
+
+/* Command Packet */
+typedef struct TW_Command {
+	unsigned char opcode__sgloffset;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char unit__hostid;
+	/* Second DWORD */
+	unsigned char status;
+	unsigned char flags;
+	union {
+		unsigned short block_count;
+		unsigned short parameter_count;
+		unsigned short message_credits;
+	} byte6;
+	union {
+		struct {
+			u32 lba;
+			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
+			u32 padding;	/* pad to 512 bytes */
+		} io;
+		struct {
+			TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
+			u32 padding[2];
+		} param;
+		struct {
+			u32 response_queue_pointer;
+			u32 padding[125];
+		} init_connection;
+		struct {
+			char version[504];
+		} ioctl_miniport_version;
+	} byte8;
+} TW_Command;
+
+#pragma pack()
+
+typedef struct TAG_TW_Ioctl {
+	unsigned char opcode;
+	unsigned short table_id;
+	unsigned char parameter_id;
+	unsigned char parameter_size_bytes;
+	unsigned char unit_index;
+	unsigned char data[1];
+} TW_Ioctl;
+
+#pragma pack(1)
+
+/* Structure for new chardev ioctls */
+typedef struct TAG_TW_New_Ioctl {
+	unsigned int data_buffer_length;
+	unsigned char padding [508];
+	TW_Command firmware_command;
+	char data_buffer[1];
+} TW_New_Ioctl;
+
+/* GetParam descriptor */
+typedef struct {
+	unsigned short	table_id;
+	unsigned char	parameter_id;
+	unsigned char	parameter_size_bytes;
+	unsigned char	data[1];
+} TW_Param, *PTW_Param;
+
+/* Response queue */
+typedef union TAG_TW_Response_Queue {
+	u32 response_id;
+	u32 value;
+} TW_Response_Queue;
+
+typedef int TW_Cmd_State;
+
+#define TW_S_INITIAL   0x1  /* Initial state */
+#define TW_S_STARTED   0x2  /* Id in use */
+#define TW_S_POSTED    0x4  /* Posted to the controller */
+#define TW_S_PENDING   0x8  /* Waiting to be posted in isr */
+#define TW_S_COMPLETED 0x10 /* Completed by isr */
+#define TW_S_FINISHED  0x20 /* I/O completely done */
+#define TW_START_MASK (TW_S_STARTED | TW_S_POSTED | TW_S_PENDING | TW_S_COMPLETED)
+
+/* Command header for ATA pass-thru */
+typedef struct TAG_TW_Passthru
+{
+	unsigned char opcode__sgloffset;
+	unsigned char size;
+	unsigned char request_id;
+	unsigned char aport__hostid;
+	unsigned char status;
+	unsigned char flags;
+	unsigned short param;
+	unsigned short features;
+	unsigned short sector_count;
+	unsigned short sector_num;
+	unsigned short cylinder_lo;
+	unsigned short cylinder_hi;
+	unsigned char drive_head;
+	unsigned char command;
+	TW_SG_Entry sg_list[TW_ATA_PASS_SGL_MAX];
+	unsigned char padding[12];
+} TW_Passthru;
+
+typedef struct TAG_TW_Device_Extension {
+	u32			base_addr;
+	unsigned long		*alignment_virtual_address[TW_Q_LENGTH];
+	unsigned long		alignment_physical_address[TW_Q_LENGTH];
+	int			is_unit_present[TW_MAX_UNITS];
+	unsigned long		*command_packet_virtual_address[TW_Q_LENGTH];
+	unsigned long		command_packet_physical_address[TW_Q_LENGTH];
+	struct pci_dev		*tw_pci_dev;
+	struct scsi_cmnd	*srb[TW_Q_LENGTH];
+	unsigned char		free_queue[TW_Q_LENGTH];
+	unsigned char		free_head;
+	unsigned char		free_tail;
+	unsigned char		pending_queue[TW_Q_LENGTH];
+	unsigned char		pending_head;
+	unsigned char		pending_tail;
+	TW_Cmd_State		state[TW_Q_LENGTH];
+	u32			posted_request_count;
+	u32			max_posted_request_count;
+	u32			request_count_marked_pending;
+	u32			pending_request_count;
+	u32			max_pending_request_count;
+	u32			max_sgl_entries;
+	u32			sgl_entries;
+	u32			num_resets;
+	u32			sector_count;
+	u32			max_sector_count;
+	u32			aen_count;
+	struct Scsi_Host	*host;
+	struct semaphore	ioctl_sem;
+	unsigned short		aen_queue[TW_Q_LENGTH];
+	unsigned char		aen_head;
+	unsigned char		aen_tail;
+	volatile long		flags; /* long req'd for set_bit --RR */
+	int			reset_print;
+	volatile int		chrdev_request_id;
+	wait_queue_head_t	ioctl_wqueue;
+} TW_Device_Extension;
+
+#pragma pack()
+
+#endif /* _3W_XXXX_H */
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
new file mode 100644
index 0000000..a591fcb
--- /dev/null
+++ b/drivers/scsi/53c700.c
@@ -0,0 +1,2175 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR (or Symbios) 53c700 and 53c700-66 Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/* Notes:
+ *
+ * This driver is designed exclusively for these chips (virtually the
+ * earliest of the scripts engine chips).  They need their own drivers
+ * because they are missing so many of the scripts and snazzy register
+ * features of their elder brothers (the 710, 720 and 770).
+ *
+ * The 700 is the lowliest of the line, it can only do async SCSI.
+ * The 700-66 can at least do synchronous SCSI up to 10MHz.
+ * 
+ * The 700 chip has no host bus interface logic of its own.  However,
+ * it is usually mapped to a location with well defined register
+ * offsets.  Therefore, if you can determine the base address and the
+ * irq your board incorporating this chip uses, you can probably use
+ * this driver to run it (although you'll probably have to write a
+ * minimal wrapper for the purpose---see the NCR_D700 driver for
+ * details about how to do this).
+ *
+ *
+ * TODO List:
+ *
+ * 1. Better statistics in the proc fs
+ *
+ * 2. Implement message queue (queues SCSI messages like commands) and make
+ *    the abort and device reset functions use them.
+ * */
+
+/* CHANGELOG
+ *
+ * Version 2.8
+ *
+ * Fixed bad bug affecting tag starvation processing (previously the
+ * driver would hang the system if too many tags starved.  Also fixed
+ * bad bug having to do with 10 byte command processing and REQUEST
+ * SENSE (the command would loop forever getting a transfer length
+ * mismatch in the CMD phase).
+ *
+ * Version 2.7
+ *
+ * Fixed scripts problem which caused certain devices (notably CDRWs)
+ * to hang on initial INQUIRY.  Updated NCR_700_readl/writel to use
+ * __raw_readl/writel for parisc compatibility (Thomas
+ * Bogendoerfer). Added missing SCp->request_bufflen initialisation
+ * for sense requests (Ryan Bradetich).
+ *
+ * Version 2.6
+ *
+ * Following test of the 64 bit parisc kernel by Richard Hirst,
+ * several problems have now been corrected.  Also adds support for
+ * consistent memory allocation.
+ *
+ * Version 2.5
+ * 
+ * More Compatibility changes for 710 (now actually works).  Enhanced
+ * support for odd clock speeds which constrain SDTR negotiations.
+ * correct cacheline separation for scsi messages and status for
+ * incoherent architectures.  Use of the pci mapping functions on
+ * buffers to begin support for 64 bit drivers.
+ *
+ * Version 2.4
+ *
+ * Added support for the 53c710 chip (in 53c700 emulation mode only---no 
+ * special 53c710 instructions or registers are used).
+ *
+ * Version 2.3
+ *
+ * More endianness/cache coherency changes.
+ *
+ * Better bad device handling (handles devices lying about tag
+ * queueing support and devices which fail to provide sense data on
+ * contingent allegiance conditions)
+ *
+ * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
+ * debugging this driver on the parisc architecture and suggesting
+ * many improvements and bug fixes.
+ *
+ * Thanks also go to Linuxcare Inc. for providing several PARISC
+ * machines for me to debug the driver on.
+ *
+ * Version 2.2
+ *
+ * Made the driver mem or io mapped; added endian invariance; added
+ * dma cache flushing operations for architectures which need it;
+ * added support for more varied clocking speeds.
+ *
+ * Version 2.1
+ *
+ * Initial modularisation from the D700.  See NCR_D700.c for the rest of
+ * the changelog.
+ * */
+#define NCR_700_VERSION "2.8"
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/byteorder.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+/* NOTE: For 64 bit drivers there are points in the code where we use
+ * a non dereferenceable pointer to point to a structure in dma-able
+ * memory (which is 32 bits) so that we can use all of the structure
+ * operations but take the address at the end.  This macro allows us
+ * to truncate the 64 bit pointer down to 32 bits without the compiler
+ * complaining */
+#define to32bit(x)	((__u32)((unsigned long)(x)))
+
+#ifdef NCR_700_DEBUG
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("53c700 and 53c700-66 Driver");
+MODULE_LICENSE("GPL");
+
+/* This is the script */
+#include "53c700_d.h"
+
+
+STATIC int NCR_700_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+STATIC int NCR_700_abort(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_bus_reset(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_dev_reset(struct scsi_cmnd * SCpnt);
+STATIC int NCR_700_host_reset(struct scsi_cmnd * SCpnt);
+STATIC void NCR_700_chip_setup(struct Scsi_Host *host);
+STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
+STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
+STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
+static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
+static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
+
+STATIC struct device_attribute *NCR_700_dev_attrs[];
+
+STATIC struct scsi_transport_template *NCR_700_transport_template = NULL;
+
+static char *NCR_700_phase[] = {
+	"",
+	"after selection",
+	"before command phase",
+	"after command phase",
+	"after status phase",
+	"after data in phase",
+	"after data out phase",
+	"during data phase",
+};
+
+static char *NCR_700_condition[] = {
+	"",
+	"NOT MSG_OUT",
+	"UNEXPECTED PHASE",
+	"NOT MSG_IN",
+	"UNEXPECTED MSG",
+	"MSG_IN",
+	"SDTR_MSG RECEIVED",
+	"REJECT_MSG RECEIVED",
+	"DISCONNECT_MSG RECEIVED",
+	"MSG_OUT",
+	"DATA_IN",
+	
+};
+
+static char *NCR_700_fatal_messages[] = {
+	"unexpected message after reselection",
+	"still MSG_OUT after message injection",
+	"not MSG_IN after selection",
+	"Illegal message length received",
+};
+
+static char *NCR_700_SBCL_bits[] = {
+	"IO ",
+	"CD ",
+	"MSG ",
+	"ATN ",
+	"SEL ",
+	"BSY ",
+	"ACK ",
+	"REQ ",
+};
+
+static char *NCR_700_SBCL_to_phase[] = {
+	"DATA_OUT",
+	"DATA_IN",
+	"CMD_OUT",
+	"STATE",
+	"ILLEGAL PHASE",
+	"ILLEGAL PHASE",
+	"MSG OUT",
+	"MSG IN",
+};
+
+static __u8 NCR_700_SDTR_msg[] = {
+	0x01,			/* Extended message */
+	0x03,			/* Extended message Length */
+	0x01,			/* SDTR Extended message */
+	NCR_700_MIN_PERIOD,
+	NCR_700_MAX_OFFSET
+};
+
+/* This translates the SDTR message offset and period to a value
+ * which can be loaded into the SXFER_REG.
+ *
+ * NOTE: According to SCSI-2, the true transfer period (in ns) is
+ *       actually four times this period value */
+static inline __u8
+NCR_700_offset_period_to_sxfer(struct NCR_700_Host_Parameters *hostdata,
+			       __u8 offset, __u8 period)
+{
+	int XFERP;
+
+	__u8 min_xferp = (hostdata->chip710
+			  ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+	__u8 max_offset = (hostdata->chip710
+			   ? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET);
+
+	if(offset == 0)
+		return 0;
+
+	if(period < hostdata->min_period) {
+		printk(KERN_WARNING "53c700: Period %dns is less than this chip's minimum, setting to %d\n", period*4, NCR_700_SDTR_msg[3]*4);
+		period = hostdata->min_period;
+	}
+	XFERP = (period*4 * hostdata->sync_clock)/1000 - 4;
+	if(offset > max_offset) {
+		printk(KERN_WARNING "53c700: Offset %d exceeds chip maximum, setting to %d\n",
+		       offset, max_offset);
+		offset = max_offset;
+	}
+	if(XFERP < min_xferp) {
+		printk(KERN_WARNING "53c700: XFERP %d is less than minium, setting to %d\n",
+		       XFERP,  min_xferp);
+		XFERP =  min_xferp;
+	}
+	return (offset & 0x0f) | (XFERP & 0x07)<<4;
+}
+
+static inline __u8
+NCR_700_get_SXFER(struct scsi_device *SDp)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+	return NCR_700_offset_period_to_sxfer(hostdata,
+					      spi_offset(SDp->sdev_target),
+					      spi_period(SDp->sdev_target));
+}
+
+struct Scsi_Host *
+NCR_700_detect(struct scsi_host_template *tpnt,
+	       struct NCR_700_Host_Parameters *hostdata, struct device *dev)
+{
+	dma_addr_t pScript, pSlots;
+	__u8 *memory;
+	__u32 *script;
+	struct Scsi_Host *host;
+	static int banner = 0;
+	int j;
+
+	if(tpnt->sdev_attrs == NULL)
+		tpnt->sdev_attrs = NCR_700_dev_attrs;
+
+	memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE,
+				       &pScript, GFP_KERNEL);
+	if(memory == NULL) {
+		printk(KERN_ERR "53c700: Failed to allocate memory for driver, detatching\n");
+		return NULL;
+	}
+
+	script = (__u32 *)memory;
+	hostdata->msgin = memory + MSGIN_OFFSET;
+	hostdata->msgout = memory + MSGOUT_OFFSET;
+	hostdata->status = memory + STATUS_OFFSET;
+	/* all of these offsets are L1_CACHE_BYTES separated.  It is fatal
+	 * if this isn't sufficient separation to avoid dma flushing issues */
+	BUG_ON(!dma_is_consistent(pScript) && L1_CACHE_BYTES < dma_get_cache_alignment());
+	hostdata->slots = (struct NCR_700_command_slot *)(memory + SLOTS_OFFSET);
+	hostdata->dev = dev;
+		
+	pSlots = pScript + SLOTS_OFFSET;
+
+	/* Fill in the missing routines from the host template */
+	tpnt->queuecommand = NCR_700_queuecommand;
+	tpnt->eh_abort_handler = NCR_700_abort;
+	tpnt->eh_device_reset_handler = NCR_700_dev_reset;
+	tpnt->eh_bus_reset_handler = NCR_700_bus_reset;
+	tpnt->eh_host_reset_handler = NCR_700_host_reset;
+	tpnt->can_queue = NCR_700_COMMAND_SLOTS_PER_HOST;
+	tpnt->sg_tablesize = NCR_700_SG_SEGMENTS;
+	tpnt->cmd_per_lun = NCR_700_CMD_PER_LUN;
+	tpnt->use_clustering = ENABLE_CLUSTERING;
+	tpnt->slave_configure = NCR_700_slave_configure;
+	tpnt->slave_destroy = NCR_700_slave_destroy;
+	tpnt->change_queue_depth = NCR_700_change_queue_depth;
+	tpnt->change_queue_type = NCR_700_change_queue_type;
+	
+	if(tpnt->name == NULL)
+		tpnt->name = "53c700";
+	if(tpnt->proc_name == NULL)
+		tpnt->proc_name = "53c700";
+	
+
+	host = scsi_host_alloc(tpnt, 4);
+	if (!host)
+		return NULL;
+	memset(hostdata->slots, 0, sizeof(struct NCR_700_command_slot)
+	       * NCR_700_COMMAND_SLOTS_PER_HOST);
+	for(j = 0; j < NCR_700_COMMAND_SLOTS_PER_HOST; j++) {
+		dma_addr_t offset = (dma_addr_t)((unsigned long)&hostdata->slots[j].SG[0]
+					  - (unsigned long)&hostdata->slots[0].SG[0]);
+		hostdata->slots[j].pSG = (struct NCR_700_SG_List *)((unsigned long)(pSlots + offset));
+		if(j == 0)
+			hostdata->free_list = &hostdata->slots[j];
+		else
+			hostdata->slots[j-1].ITL_forw = &hostdata->slots[j];
+		hostdata->slots[j].state = NCR_700_SLOT_FREE;
+	}
+
+	for(j = 0; j < sizeof(SCRIPT)/sizeof(SCRIPT[0]); j++) {
+		script[j] = bS_to_host(SCRIPT[j]);
+	}
+
+	/* adjust all labels to be bus physical */
+	for(j = 0; j < PATCHES; j++) {
+		script[LABELPATCHES[j]] = bS_to_host(pScript + SCRIPT[LABELPATCHES[j]]);
+	}
+	/* now patch up fixed addresses. */
+	script_patch_32(script, MessageLocation,
+			pScript + MSGOUT_OFFSET);
+	script_patch_32(script, StatusAddress,
+			pScript + STATUS_OFFSET);
+	script_patch_32(script, ReceiveMsgAddress,
+			pScript + MSGIN_OFFSET);
+
+	hostdata->script = script;
+	hostdata->pScript = pScript;
+	dma_sync_single_for_device(hostdata->dev, pScript, sizeof(SCRIPT), DMA_TO_DEVICE);
+	hostdata->state = NCR_700_HOST_FREE;
+	hostdata->cmd = NULL;
+	host->max_id = 7;
+	host->max_lun = NCR_700_MAX_LUNS;
+	BUG_ON(NCR_700_transport_template == NULL);
+	host->transportt = NCR_700_transport_template;
+	host->unique_id = hostdata->base;
+	host->base = hostdata->base;
+	hostdata->eh_complete = NULL;
+	host->hostdata[0] = (unsigned long)hostdata;
+	/* kick the chip */
+	NCR_700_writeb(0xff, host, CTEST9_REG);
+	if(hostdata->chip710) 
+		hostdata->rev = (NCR_700_readb(host, CTEST8_REG)>>4) & 0x0f;
+	else
+		hostdata->rev = (NCR_700_readb(host, CTEST7_REG)>>4) & 0x0f;
+	hostdata->fast = (NCR_700_readb(host, CTEST9_REG) == 0);
+	if(banner == 0) {
+		printk(KERN_NOTICE "53c700: Version " NCR_700_VERSION " By James.Bottomley@HansenPartnership.com\n");
+		banner = 1;
+	}
+	printk(KERN_NOTICE "scsi%d: %s rev %d %s\n", host->host_no,
+	       hostdata->chip710 ? "53c710" : 
+	       (hostdata->fast ? "53c700-66" : "53c700"),
+	       hostdata->rev, hostdata->differential ?
+	       "(Differential)" : "");
+	/* reset the chip */
+	NCR_700_chip_reset(host);
+
+	if (scsi_add_host(host, dev)) {
+		dev_printk(KERN_ERR, dev, "53c700: scsi_add_host failed\n");
+		scsi_host_put(host);
+		return NULL;
+	}
+
+	spi_signalling(host) = hostdata->differential ? SPI_SIGNAL_HVD :
+		SPI_SIGNAL_SE;
+
+	return host;
+}
+
+int
+NCR_700_release(struct Scsi_Host *host)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	dma_free_noncoherent(hostdata->dev, TOTAL_MEM_SIZE,
+			       hostdata->script, hostdata->pScript);
+	return 1;
+}
+
+static inline __u8
+NCR_700_identify(int can_disconnect, __u8 lun)
+{
+	return IDENTIFY_BASE |
+		((can_disconnect) ? 0x40 : 0) |
+		(lun & NCR_700_LUN_MASK);
+}
+
+/*
+ * Function : static int data_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.  If you
+ * really want to know what this function is doing, it's almost a
+ * direct transcription of the algorithm described in the 53c710
+ * guide, except that the DBC and DFIFO registers are only 6 bits
+ * wide on a 53c700.
+ *
+ * Inputs : host - SCSI host */
+static inline int
+NCR_700_data_residual (struct Scsi_Host *host) {
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	int count, synchronous = 0;
+	unsigned int ddir;
+
+	if(hostdata->chip710) {
+		count = ((NCR_700_readb(host, DFIFO_REG) & 0x7f) -
+			 (NCR_700_readl(host, DBC_REG) & 0x7f)) & 0x7f;
+	} else {
+		count = ((NCR_700_readb(host, DFIFO_REG) & 0x3f) -
+			 (NCR_700_readl(host, DBC_REG) & 0x3f)) & 0x3f;
+	}
+	
+	if(hostdata->fast)
+		synchronous = NCR_700_readb(host, SXFER_REG) & 0x0f;
+	
+	/* get the data direction */
+	ddir = NCR_700_readb(host, CTEST0_REG) & 0x01;
+
+	if (ddir) {
+		/* Receive */
+		if (synchronous) 
+			count += (NCR_700_readb(host, SSTAT2_REG) & 0xf0) >> 4;
+		else
+			if (NCR_700_readb(host, SSTAT1_REG) & SIDL_REG_FULL)
+				++count;
+	} else {
+		/* Send */
+		__u8 sstat = NCR_700_readb(host, SSTAT1_REG);
+		if (sstat & SODL_REG_FULL)
+			++count;
+		if (synchronous && (sstat & SODR_REG_FULL))
+			++count;
+	}
+#ifdef NCR_700_DEBUG
+	if(count)
+		printk("RESIDUAL IS %d (ddir %d)\n", count, ddir);
+#endif
+	return count;
+}
+
+/* print out the SCSI wires and corresponding phase from the SBCL register
+ * in the chip */
+static inline char *
+sbcl_to_string(__u8 sbcl)
+{
+	int i;
+	static char ret[256];
+
+	ret[0]='\0';
+	for(i=0; i<8; i++) {
+		if((1<<i) & sbcl) 
+			strcat(ret, NCR_700_SBCL_bits[i]);
+	}
+	strcat(ret, NCR_700_SBCL_to_phase[sbcl & 0x07]);
+	return ret;
+}
+
+static inline __u8
+bitmap_to_number(__u8 bitmap)
+{
+	__u8 i;
+
+	for(i=0; i<8 && !(bitmap &(1<<i)); i++)
+		;
+	return i;
+}
+
+/* Pull a slot off the free list */
+STATIC struct NCR_700_command_slot *
+find_empty_slot(struct NCR_700_Host_Parameters *hostdata)
+{
+	struct NCR_700_command_slot *slot = hostdata->free_list;
+
+	if(slot == NULL) {
+		/* sanity check */
+		if(hostdata->command_slot_count != NCR_700_COMMAND_SLOTS_PER_HOST)
+			printk(KERN_ERR "SLOTS FULL, but count is %d, should be %d\n", hostdata->command_slot_count, NCR_700_COMMAND_SLOTS_PER_HOST);
+		return NULL;
+	}
+
+	if(slot->state != NCR_700_SLOT_FREE)
+		/* should panic! */
+		printk(KERN_ERR "BUSY SLOT ON FREE LIST!!!\n");
+		
+
+	hostdata->free_list = slot->ITL_forw;
+	slot->ITL_forw = NULL;
+
+
+	/* NOTE: set the state to busy here, not queued, since this
+	 * indicates the slot is in use and cannot be run by the IRQ
+	 * finish routine.  If we cannot queue the command when it
+	 * is properly build, we then change to NCR_700_SLOT_QUEUED */
+	slot->state = NCR_700_SLOT_BUSY;
+	hostdata->command_slot_count++;
+	
+	return slot;
+}
+
+STATIC void 
+free_slot(struct NCR_700_command_slot *slot,
+	  struct NCR_700_Host_Parameters *hostdata)
+{
+	if((slot->state & NCR_700_SLOT_MASK) != NCR_700_SLOT_MAGIC) {
+		printk(KERN_ERR "53c700: SLOT %p is not MAGIC!!!\n", slot);
+	}
+	if(slot->state == NCR_700_SLOT_FREE) {
+		printk(KERN_ERR "53c700: SLOT %p is FREE!!!\n", slot);
+	}
+	
+	slot->resume_offset = 0;
+	slot->cmnd = NULL;
+	slot->state = NCR_700_SLOT_FREE;
+	slot->ITL_forw = hostdata->free_list;
+	hostdata->free_list = slot;
+	hostdata->command_slot_count--;
+}
+
+
+/* This routine really does very little.  The command is indexed on
+   the ITL and (if tagged) the ITLQ lists in _queuecommand */
+STATIC void
+save_for_reselection(struct NCR_700_Host_Parameters *hostdata,
+		     struct scsi_cmnd *SCp, __u32 dsp)
+{
+	/* Its just possible that this gets executed twice */
+	if(SCp != NULL) {
+		struct NCR_700_command_slot *slot =
+			(struct NCR_700_command_slot *)SCp->host_scribble;
+
+		slot->resume_offset = dsp;
+	}
+	hostdata->state = NCR_700_HOST_FREE;
+	hostdata->cmd = NULL;
+}
+
+STATIC inline void
+NCR_700_unmap(struct NCR_700_Host_Parameters *hostdata, struct scsi_cmnd *SCp,
+	      struct NCR_700_command_slot *slot)
+{
+	if(SCp->sc_data_direction != DMA_NONE &&
+	   SCp->sc_data_direction != DMA_BIDIRECTIONAL) {
+		if(SCp->use_sg) {
+			dma_unmap_sg(hostdata->dev, SCp->buffer,
+				     SCp->use_sg, SCp->sc_data_direction);
+		} else {
+			dma_unmap_single(hostdata->dev, slot->dma_handle,
+					 SCp->request_bufflen,
+					 SCp->sc_data_direction);
+		}
+	}
+}
+
+STATIC inline void
+NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
+	       struct scsi_cmnd *SCp, int result)
+{
+	hostdata->state = NCR_700_HOST_FREE;
+	hostdata->cmd = NULL;
+
+	if(SCp != NULL) {
+		struct NCR_700_command_slot *slot = 
+			(struct NCR_700_command_slot *)SCp->host_scribble;
+		
+		NCR_700_unmap(hostdata, SCp, slot);
+		dma_unmap_single(hostdata->dev, slot->pCmd,
+				 sizeof(SCp->cmnd), DMA_TO_DEVICE);
+		if(SCp->cmnd[0] == REQUEST_SENSE && SCp->cmnd[6] == NCR_700_INTERNAL_SENSE_MAGIC) {
+#ifdef NCR_700_DEBUG
+			printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
+			       SCp, SCp->cmnd[7], result);
+			scsi_print_sense("53c700", SCp);
+
+#endif
+			/* restore the old result if the request sense was
+			 * successful */
+			if(result == 0)
+				result = SCp->cmnd[7];
+			/* now restore the original command */
+			memcpy((void *) SCp->cmnd, (void *) SCp->data_cmnd,
+			       sizeof(SCp->data_cmnd));
+			SCp->request_buffer = SCp->buffer;
+			SCp->request_bufflen = SCp->bufflen;
+			SCp->use_sg = SCp->old_use_sg;
+			SCp->cmd_len = SCp->old_cmd_len;
+			SCp->sc_data_direction = SCp->sc_old_data_direction;
+			SCp->underflow = SCp->old_underflow;
+			
+		}
+		free_slot(slot, hostdata);
+#ifdef NCR_700_DEBUG
+		if(NCR_700_get_depth(SCp->device) == 0 ||
+		   NCR_700_get_depth(SCp->device) > SCp->device->queue_depth)
+			printk(KERN_ERR "Invalid depth in NCR_700_scsi_done(): %d\n",
+			       NCR_700_get_depth(SCp->device));
+#endif /* NCR_700_DEBUG */
+		NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) - 1);
+
+		SCp->host_scribble = NULL;
+		SCp->result = result;
+		SCp->scsi_done(SCp);
+	} else {
+		printk(KERN_ERR "53c700: SCSI DONE HAS NULL SCp\n");
+	}
+}
+
+
+STATIC void
+NCR_700_internal_bus_reset(struct Scsi_Host *host)
+{
+	/* Bus reset */
+	NCR_700_writeb(ASSERT_RST, host, SCNTL1_REG);
+	udelay(50);
+	NCR_700_writeb(0, host, SCNTL1_REG);
+
+}
+
+STATIC void
+NCR_700_chip_setup(struct Scsi_Host *host)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	__u32 dcntl_extra = 0;
+	__u8 min_period;
+	__u8 min_xferp = (hostdata->chip710 ? NCR_710_MIN_XFERP : NCR_700_MIN_XFERP);
+
+	if(hostdata->chip710) {
+		__u8 burst_disable = hostdata->burst_disable
+			? BURST_DISABLE : 0;
+		dcntl_extra = COMPAT_700_MODE;
+
+		NCR_700_writeb(dcntl_extra, host, DCNTL_REG);
+		NCR_700_writeb(BURST_LENGTH_8  | hostdata->dmode_extra,
+			       host, DMODE_710_REG);
+		NCR_700_writeb(burst_disable | (hostdata->differential ? 
+						DIFF : 0), host, CTEST7_REG);
+		NCR_700_writeb(BTB_TIMER_DISABLE, host, CTEST0_REG);
+		NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY | PARITY
+			       | AUTO_ATN, host, SCNTL0_REG);
+	} else {
+		NCR_700_writeb(BURST_LENGTH_8 | hostdata->dmode_extra,
+			       host, DMODE_700_REG);
+		NCR_700_writeb(hostdata->differential ? 
+			       DIFF : 0, host, CTEST7_REG);
+		if(hostdata->fast) {
+			/* this is for 700-66, does nothing on 700 */
+			NCR_700_writeb(LAST_DIS_ENBL | ENABLE_ACTIVE_NEGATION 
+				       | GENERATE_RECEIVE_PARITY, host,
+				       CTEST8_REG);
+		} else {
+			NCR_700_writeb(FULL_ARBITRATION | ENABLE_PARITY
+				       | PARITY | AUTO_ATN, host, SCNTL0_REG);
+		}
+	}
+
+	NCR_700_writeb(1 << host->this_id, host, SCID_REG);
+	NCR_700_writeb(0, host, SBCL_REG);
+	NCR_700_writeb(ASYNC_OPERATION, host, SXFER_REG);
+
+	NCR_700_writeb(PHASE_MM_INT | SEL_TIMEOUT_INT | GROSS_ERR_INT | UX_DISC_INT
+	     | RST_INT | PAR_ERR_INT | SELECT_INT, host, SIEN_REG);
+
+	NCR_700_writeb(ABORT_INT | INT_INST_INT | ILGL_INST_INT, host, DIEN_REG);
+	NCR_700_writeb(ENABLE_SELECT, host, SCNTL1_REG);
+	if(hostdata->clock > 75) {
+		printk(KERN_ERR "53c700: Clock speed %dMHz is too high: 75Mhz is the maximum this chip can be driven at\n", hostdata->clock);
+		/* do the best we can, but the async clock will be out
+		 * of spec: sync divider 2, async divider 3 */
+		DEBUG(("53c700: sync 2 async 3\n"));
+		NCR_700_writeb(SYNC_DIV_2_0, host, SBCL_REG);
+		NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+		hostdata->sync_clock = hostdata->clock/2;
+	} else	if(hostdata->clock > 50  && hostdata->clock <= 75) {
+		/* sync divider 1.5, async divider 3 */
+		DEBUG(("53c700: sync 1.5 async 3\n"));
+		NCR_700_writeb(SYNC_DIV_1_5, host, SBCL_REG);
+		NCR_700_writeb(ASYNC_DIV_3_0 | dcntl_extra, host, DCNTL_REG);
+		hostdata->sync_clock = hostdata->clock*2;
+		hostdata->sync_clock /= 3;
+		
+	} else if(hostdata->clock > 37 && hostdata->clock <= 50) {
+		/* sync divider 1, async divider 2 */
+		DEBUG(("53c700: sync 1 async 2\n"));
+		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+		NCR_700_writeb(ASYNC_DIV_2_0 | dcntl_extra, host, DCNTL_REG);
+		hostdata->sync_clock = hostdata->clock;
+	} else if(hostdata->clock > 25 && hostdata->clock <=37) {
+		/* sync divider 1, async divider 1.5 */
+		DEBUG(("53c700: sync 1 async 1.5\n"));
+		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+		NCR_700_writeb(ASYNC_DIV_1_5 | dcntl_extra, host, DCNTL_REG);
+		hostdata->sync_clock = hostdata->clock;
+	} else {
+		DEBUG(("53c700: sync 1 async 1\n"));
+		NCR_700_writeb(SYNC_DIV_1_0, host, SBCL_REG);
+		NCR_700_writeb(ASYNC_DIV_1_0 | dcntl_extra, host, DCNTL_REG);
+		/* sync divider 1, async divider 1 */
+		hostdata->sync_clock = hostdata->clock;
+	}
+	/* Calculate the actual minimum period that can be supported
+	 * by our synchronous clock speed.  See the 710 manual for
+	 * exact details of this calculation which is based on a
+	 * setting of the SXFER register */
+	min_period = 1000*(4+min_xferp)/(4*hostdata->sync_clock);
+	hostdata->min_period = NCR_700_MIN_PERIOD;
+	if(min_period > NCR_700_MIN_PERIOD)
+		hostdata->min_period = min_period;
+}
+
+STATIC void
+NCR_700_chip_reset(struct Scsi_Host *host)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(SOFTWARE_RESET_710, host, ISTAT_REG);
+		udelay(100);
+
+		NCR_700_writeb(0, host, ISTAT_REG);
+	} else {
+		NCR_700_writeb(SOFTWARE_RESET, host, DCNTL_REG);
+		udelay(100);
+		
+		NCR_700_writeb(0, host, DCNTL_REG);
+	}
+
+	mdelay(1000);
+
+	NCR_700_chip_setup(host);
+}
+
+/* The heart of the message processing engine is that the instruction
+ * immediately after the INT is the normal case (and so must be CLEAR
+ * ACK).  If we want to do something else, we call that routine in
+ * scripts and set temp to be the normal case + 8 (skipping the CLEAR
+ * ACK) so that the routine returns correctly to resume its activity
+ * */
+STATIC __u32
+process_extended_message(struct Scsi_Host *host, 
+			 struct NCR_700_Host_Parameters *hostdata,
+			 struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+	__u32 resume_offset = dsp, temp = dsp + 8;
+	__u8 pun = 0xff, lun = 0xff;
+
+	if(SCp != NULL) {
+		pun = SCp->device->id;
+		lun = SCp->device->lun;
+	}
+
+	switch(hostdata->msgin[2]) {
+	case A_SDTR_MSG:
+		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+			struct scsi_target *starget = SCp->device->sdev_target;
+			__u8 period = hostdata->msgin[3];
+			__u8 offset = hostdata->msgin[4];
+
+			if(offset == 0 || period == 0) {
+				offset = 0;
+				period = 0;
+			}
+
+			spi_offset(starget) = offset;
+			spi_period(starget) = period;
+			
+			if(NCR_700_is_flag_set(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION)) {
+				spi_display_xfer_agreement(starget);
+				NCR_700_clear_flag(SCp->device, NCR_700_DEV_PRINT_SYNC_NEGOTIATION);
+			}
+			
+			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+			
+			NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+				       host, SXFER_REG);
+
+		} else {
+			/* SDTR message out of the blue, reject it */
+			printk(KERN_WARNING "scsi%d Unexpected SDTR msg\n",
+			       host->host_no);
+			hostdata->msgout[0] = A_REJECT_MSG;
+			dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
+			script_patch_16(hostdata->script, MessageCount, 1);
+			/* SendMsgOut returns, so set up the return
+			 * address */
+			resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+		}
+		break;
+	
+	case A_WDTR_MSG:
+		printk(KERN_INFO "scsi%d: (%d:%d), Unsolicited WDTR after CMD, Rejecting\n",
+		       host->host_no, pun, lun);
+		hostdata->msgout[0] = A_REJECT_MSG;
+		dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
+		script_patch_16(hostdata->script, MessageCount, 1);
+		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+		break;
+
+	default:
+		printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+		       host->host_no, pun, lun,
+		       NCR_700_phase[(dsps & 0xf00) >> 8]);
+		scsi_print_msg(hostdata->msgin);
+		printk("\n");
+		/* just reject it */
+		hostdata->msgout[0] = A_REJECT_MSG;
+		dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
+		script_patch_16(hostdata->script, MessageCount, 1);
+		/* SendMsgOut returns, so set up the return
+		 * address */
+		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+	}
+	NCR_700_writel(temp, host, TEMP_REG);
+	return resume_offset;
+}
+
+STATIC __u32
+process_message(struct Scsi_Host *host,	struct NCR_700_Host_Parameters *hostdata,
+		struct scsi_cmnd *SCp, __u32 dsp, __u32 dsps)
+{
+	/* work out where to return to */
+	__u32 temp = dsp + 8, resume_offset = dsp;
+	__u8 pun = 0xff, lun = 0xff;
+
+	if(SCp != NULL) {
+		pun = SCp->device->id;
+		lun = SCp->device->lun;
+	}
+
+#ifdef NCR_700_DEBUG
+	printk("scsi%d (%d:%d): message %s: ", host->host_no, pun, lun,
+	       NCR_700_phase[(dsps & 0xf00) >> 8]);
+	scsi_print_msg(hostdata->msgin);
+	printk("\n");
+#endif
+
+	switch(hostdata->msgin[0]) {
+
+	case A_EXTENDED_MSG:
+		resume_offset =  process_extended_message(host, hostdata, SCp,
+							  dsp, dsps);
+		break;
+
+	case A_REJECT_MSG:
+		if(SCp != NULL && NCR_700_is_flag_set(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION)) {
+			/* Rejected our sync negotiation attempt */
+			spi_period(SCp->device->sdev_target) =
+				spi_offset(SCp->device->sdev_target) = 0;
+			NCR_700_set_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+			NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+		} else if(SCp != NULL && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION) {
+			/* rejected our first simple tag message */
+			printk(KERN_WARNING "scsi%d (%d:%d) Rejected first tag queue attempt, turning off tag queueing\n", host->host_no, pun, lun);
+			/* we're done negotiating */
+			NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
+			hostdata->tag_negotiated &= ~(1<<SCp->device->id);
+			SCp->device->tagged_supported = 0;
+			scsi_deactivate_tcq(SCp->device, host->cmd_per_lun);
+		} else {
+			printk(KERN_WARNING "scsi%d (%d:%d) Unexpected REJECT Message %s\n",
+			       host->host_no, pun, lun,
+			       NCR_700_phase[(dsps & 0xf00) >> 8]);
+			/* however, just ignore it */
+		}
+		break;
+
+	case A_PARITY_ERROR_MSG:
+		printk(KERN_ERR "scsi%d (%d:%d) Parity Error!\n", host->host_no,
+		       pun, lun);
+		NCR_700_internal_bus_reset(host);
+		break;
+	case A_SIMPLE_TAG_MSG:
+		printk(KERN_INFO "scsi%d (%d:%d) SIMPLE TAG %d %s\n", host->host_no,
+		       pun, lun, hostdata->msgin[1],
+		       NCR_700_phase[(dsps & 0xf00) >> 8]);
+		/* just ignore it */
+		break;
+	default:
+		printk(KERN_INFO "scsi%d (%d:%d): Unexpected message %s: ",
+		       host->host_no, pun, lun,
+		       NCR_700_phase[(dsps & 0xf00) >> 8]);
+
+		scsi_print_msg(hostdata->msgin);
+		printk("\n");
+		/* just reject it */
+		hostdata->msgout[0] = A_REJECT_MSG;
+		dma_cache_sync(hostdata->msgout, 1, DMA_TO_DEVICE);
+		script_patch_16(hostdata->script, MessageCount, 1);
+		/* SendMsgOut returns, so set up the return
+		 * address */
+		resume_offset = hostdata->pScript + Ent_SendMessageWithATN;
+
+		break;
+	}
+	NCR_700_writel(temp, host, TEMP_REG);
+	/* set us up to receive another message */
+	dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE, DMA_FROM_DEVICE);
+	return resume_offset;
+}
+
+STATIC __u32
+process_script_interrupt(__u32 dsps, __u32 dsp, struct scsi_cmnd *SCp,
+			 struct Scsi_Host *host,
+			 struct NCR_700_Host_Parameters *hostdata)
+{
+	__u32 resume_offset = 0;
+	__u8 pun = 0xff, lun=0xff;
+
+	if(SCp != NULL) {
+		pun = SCp->device->id;
+		lun = SCp->device->lun;
+	}
+
+	if(dsps == A_GOOD_STATUS_AFTER_STATUS) {
+		DEBUG(("  COMMAND COMPLETE, status=%02x\n",
+		       hostdata->status[0]));
+		/* OK, if TCQ still under negotiation, we now know it works */
+		if (NCR_700_get_tag_neg_state(SCp->device) == NCR_700_DURING_TAG_NEGOTIATION)
+			NCR_700_set_tag_neg_state(SCp->device,
+						  NCR_700_FINISHED_TAG_NEGOTIATION);
+			
+		/* check for contingent allegiance contitions */
+		if(status_byte(hostdata->status[0]) == CHECK_CONDITION ||
+		   status_byte(hostdata->status[0]) == COMMAND_TERMINATED) {
+			struct NCR_700_command_slot *slot =
+				(struct NCR_700_command_slot *)SCp->host_scribble;
+			if(SCp->cmnd[0] == REQUEST_SENSE) {
+				/* OOPS: bad device, returning another
+				 * contingent allegiance condition */
+				printk(KERN_ERR "scsi%d (%d:%d) broken device is looping in contingent allegiance: ignoring\n", host->host_no, pun, lun);
+				NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
+			} else {
+#ifdef NCR_DEBUG
+				scsi_print_command(SCp);
+				printk("  cmd %p has status %d, requesting sense\n",
+				       SCp, hostdata->status[0]);
+#endif
+				/* we can destroy the command here
+				 * because the contingent allegiance
+				 * condition will cause a retry which
+				 * will re-copy the command from the
+				 * saved data_cmnd.  We also unmap any
+				 * data associated with the command
+				 * here */
+				NCR_700_unmap(hostdata, SCp, slot);
+
+				SCp->cmnd[0] = REQUEST_SENSE;
+				SCp->cmnd[1] = (SCp->device->lun & 0x7) << 5;
+				SCp->cmnd[2] = 0;
+				SCp->cmnd[3] = 0;
+				SCp->cmnd[4] = sizeof(SCp->sense_buffer);
+				SCp->cmnd[5] = 0;
+				SCp->cmd_len = 6;
+				/* Here's a quiet hack: the
+				 * REQUEST_SENSE command is six bytes,
+				 * so store a flag indicating that
+				 * this was an internal sense request
+				 * and the original status at the end
+				 * of the command */
+				SCp->cmnd[6] = NCR_700_INTERNAL_SENSE_MAGIC;
+				SCp->cmnd[7] = hostdata->status[0];
+				SCp->use_sg = 0;
+				SCp->sc_data_direction = DMA_FROM_DEVICE;
+				dma_sync_single_for_device(hostdata->dev, slot->pCmd,
+							   SCp->cmd_len, DMA_TO_DEVICE);
+				SCp->request_bufflen = sizeof(SCp->sense_buffer);
+				slot->dma_handle = dma_map_single(hostdata->dev, SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+				slot->SG[0].ins = bS_to_host(SCRIPT_MOVE_DATA_IN | sizeof(SCp->sense_buffer));
+				slot->SG[0].pAddr = bS_to_host(slot->dma_handle);
+				slot->SG[1].ins = bS_to_host(SCRIPT_RETURN);
+				slot->SG[1].pAddr = 0;
+				slot->resume_offset = hostdata->pScript;
+				dma_cache_sync(slot->SG, sizeof(slot->SG[0])*2, DMA_TO_DEVICE);
+				dma_cache_sync(SCp->sense_buffer, sizeof(SCp->sense_buffer), DMA_FROM_DEVICE);
+				
+				/* queue the command for reissue */
+				slot->state = NCR_700_SLOT_QUEUED;
+				hostdata->state = NCR_700_HOST_FREE;
+				hostdata->cmd = NULL;
+			}
+		} else {
+			// Currently rely on the mid layer evaluation
+			// of the tag queuing capability
+			//
+			//if(status_byte(hostdata->status[0]) == GOOD &&
+			//   SCp->cmnd[0] == INQUIRY && SCp->use_sg == 0) {
+			//	/* Piggy back the tag queueing support
+			//	 * on this command */
+			//	dma_sync_single_for_cpu(hostdata->dev,
+			//			    slot->dma_handle,
+			//			    SCp->request_bufflen,
+			//			    DMA_FROM_DEVICE);
+			//	if(((char *)SCp->request_buffer)[7] & 0x02) {
+			//		printk(KERN_INFO "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", host->host_no, pun, lun);
+			//		hostdata->tag_negotiated |= (1<<SCp->device->id);
+			//		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+			//	} else {
+			//		NCR_700_clear_flag(SCp->device, NCR_700_DEV_BEGIN_TAG_QUEUEING);
+			//		hostdata->tag_negotiated &= ~(1<<SCp->device->id);
+			//	}
+			//}
+			NCR_700_scsi_done(hostdata, SCp, hostdata->status[0]);
+		}
+	} else if((dsps & 0xfffff0f0) == A_UNEXPECTED_PHASE) {
+		__u8 i = (dsps & 0xf00) >> 8;
+
+		printk(KERN_ERR "scsi%d: (%d:%d), UNEXPECTED PHASE %s (%s)\n",
+		       host->host_no, pun, lun,
+		       NCR_700_phase[i],
+		       sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+		printk(KERN_ERR "         len = %d, cmd =", SCp->cmd_len);
+		scsi_print_command(SCp);
+
+		NCR_700_internal_bus_reset(host);
+	} else if((dsps & 0xfffff000) == A_FATAL) {
+		int i = (dsps & 0xfff);
+
+		printk(KERN_ERR "scsi%d: (%d:%d) FATAL ERROR: %s\n",
+		       host->host_no, pun, lun, NCR_700_fatal_messages[i]);
+		if(dsps == A_FATAL_ILLEGAL_MSG_LENGTH) {
+			printk(KERN_ERR "     msg begins %02x %02x\n",
+			       hostdata->msgin[0], hostdata->msgin[1]);
+		}
+		NCR_700_internal_bus_reset(host);
+	} else if((dsps & 0xfffff0f0) == A_DISCONNECT) {
+#ifdef NCR_700_DEBUG
+		__u8 i = (dsps & 0xf00) >> 8;
+
+		printk("scsi%d: (%d:%d), DISCONNECTED (%d) %s\n",
+		       host->host_no, pun, lun,
+		       i, NCR_700_phase[i]);
+#endif
+		save_for_reselection(hostdata, SCp, dsp);
+
+	} else if(dsps == A_RESELECTION_IDENTIFIED) {
+		__u8 lun;
+		struct NCR_700_command_slot *slot;
+		__u8 reselection_id = hostdata->reselection_id;
+		struct scsi_device *SDp;
+
+		lun = hostdata->msgin[0] & 0x1f;
+
+		hostdata->reselection_id = 0xff;
+		DEBUG(("scsi%d: (%d:%d) RESELECTED!\n",
+		       host->host_no, reselection_id, lun));
+		/* clear the reselection indicator */
+		SDp = __scsi_device_lookup(host, 0, reselection_id, lun);
+		if(unlikely(SDp == NULL)) {
+			printk(KERN_ERR "scsi%d: (%d:%d) HAS NO device\n",
+			       host->host_no, reselection_id, lun);
+			BUG();
+		}
+		if(hostdata->msgin[1] == A_SIMPLE_TAG_MSG) {
+			struct scsi_cmnd *SCp = scsi_find_tag(SDp, hostdata->msgin[2]);
+			if(unlikely(SCp == NULL)) {
+				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for tag %d\n", 
+				       host->host_no, reselection_id, lun, hostdata->msgin[2]);
+				BUG();
+			}
+
+			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+			DEBUG(("53c700: %d:%d:%d, reselection is tag %d, slot %p(%d)\n",
+			       host->host_no, SDp->id, SDp->lun,
+			       hostdata->msgin[2], slot, slot->tag));
+		} else {
+			struct scsi_cmnd *SCp = scsi_find_tag(SDp, SCSI_NO_TAG);
+			if(unlikely(SCp == NULL)) {
+				printk(KERN_ERR "scsi%d: (%d:%d) no saved request for untagged cmd\n", 
+				       host->host_no, reselection_id, lun);
+				BUG();
+			}
+			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+		}
+
+		if(slot == NULL) {
+			printk(KERN_ERR "scsi%d: (%d:%d) RESELECTED but no saved command (MSG = %02x %02x %02x)!!\n",
+			       host->host_no, reselection_id, lun,
+			       hostdata->msgin[0], hostdata->msgin[1],
+			       hostdata->msgin[2]);
+		} else {
+			if(hostdata->state != NCR_700_HOST_BUSY)
+				printk(KERN_ERR "scsi%d: FATAL, host not busy during valid reselection!\n",
+				       host->host_no);
+			resume_offset = slot->resume_offset;
+			hostdata->cmd = slot->cmnd;
+
+			/* re-patch for this command */
+			script_patch_32_abs(hostdata->script, CommandAddress, 
+					    slot->pCmd);
+			script_patch_16(hostdata->script,
+					CommandCount, slot->cmnd->cmd_len);
+			script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+					    to32bit(&slot->pSG[0].ins));
+
+			/* Note: setting SXFER only works if we're
+			 * still in the MESSAGE phase, so it is vital
+			 * that ACK is still asserted when we process
+			 * the reselection message.  The resume offset
+			 * should therefore always clear ACK */
+			NCR_700_writeb(NCR_700_get_SXFER(hostdata->cmd->device),
+				       host, SXFER_REG);
+			dma_cache_sync(hostdata->msgin,
+				       MSG_ARRAY_SIZE, DMA_FROM_DEVICE);
+			dma_cache_sync(hostdata->msgout,
+				       MSG_ARRAY_SIZE, DMA_TO_DEVICE);
+			/* I'm just being paranoid here, the command should
+			 * already have been flushed from the cache */
+			dma_cache_sync(slot->cmnd->cmnd,
+				       slot->cmnd->cmd_len, DMA_TO_DEVICE);
+
+
+			
+		}
+	} else if(dsps == A_RESELECTED_DURING_SELECTION) {
+
+		/* This section is full of debugging code because I've
+		 * never managed to reach it.  I think what happens is
+		 * that, because the 700 runs with selection
+		 * interrupts enabled the whole time that we take a
+		 * selection interrupt before we manage to get to the
+		 * reselected script interrupt */
+
+		__u8 reselection_id = NCR_700_readb(host, SFBR_REG);
+		struct NCR_700_command_slot *slot;
+		
+		/* Take out our own ID */
+		reselection_id &= ~(1<<host->this_id);
+		
+		/* I've never seen this happen, so keep this as a printk rather
+		 * than a debug */
+		printk(KERN_INFO "scsi%d: (%d:%d) RESELECTION DURING SELECTION, dsp=%08x[%04x] state=%d, count=%d\n",
+		       host->host_no, reselection_id, lun, dsp, dsp - hostdata->pScript, hostdata->state, hostdata->command_slot_count);
+
+		{
+			/* FIXME: DEBUGGING CODE */
+			__u32 SG = (__u32)bS_to_cpu(hostdata->script[A_SGScriptStartAddress_used[0]]);
+			int i;
+
+			for(i=0; i< NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+				if(SG >= to32bit(&hostdata->slots[i].pSG[0])
+				   && SG <= to32bit(&hostdata->slots[i].pSG[NCR_700_SG_SEGMENTS]))
+					break;
+			}
+			printk(KERN_INFO "IDENTIFIED SG segment as being %08x in slot %p, cmd %p, slot->resume_offset=%08x\n", SG, &hostdata->slots[i], hostdata->slots[i].cmnd, hostdata->slots[i].resume_offset);
+			SCp =  hostdata->slots[i].cmnd;
+		}
+
+		if(SCp != NULL) {
+			slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+			/* change slot from busy to queued to redo command */
+			slot->state = NCR_700_SLOT_QUEUED;
+		}
+		hostdata->cmd = NULL;
+		
+		if(reselection_id == 0) {
+			if(hostdata->reselection_id == 0xff) {
+				printk(KERN_ERR "scsi%d: Invalid reselection during selection!!\n", host->host_no);
+				return 0;
+			} else {
+				printk(KERN_ERR "scsi%d: script reselected and we took a selection interrupt\n",
+				       host->host_no);
+				reselection_id = hostdata->reselection_id;
+			}
+		} else {
+			
+			/* convert to real ID */
+			reselection_id = bitmap_to_number(reselection_id);
+		}
+		hostdata->reselection_id = reselection_id;
+		/* just in case we have a stale simple tag message, clear it */
+		hostdata->msgin[1] = 0;
+		dma_cache_sync(hostdata->msgin,
+			       MSG_ARRAY_SIZE, DMA_BIDIRECTIONAL);
+		if(hostdata->tag_negotiated & (1<<reselection_id)) {
+			resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+		} else {
+			resume_offset = hostdata->pScript + Ent_GetReselectionData;
+		}
+	} else if(dsps == A_COMPLETED_SELECTION_AS_TARGET) {
+		/* we've just disconnected from the bus, do nothing since
+		 * a return here will re-run the queued command slot
+		 * that may have been interrupted by the initial selection */
+		DEBUG((" SELECTION COMPLETED\n"));
+	} else if((dsps & 0xfffff0f0) == A_MSG_IN) { 
+		resume_offset = process_message(host, hostdata, SCp,
+						dsp, dsps);
+	} else if((dsps &  0xfffff000) == 0) {
+		__u8 i = (dsps & 0xf0) >> 4, j = (dsps & 0xf00) >> 8;
+		printk(KERN_ERR "scsi%d: (%d:%d), unhandled script condition %s %s at %04x\n",
+		       host->host_no, pun, lun, NCR_700_condition[i],
+		       NCR_700_phase[j], dsp - hostdata->pScript);
+		if(SCp != NULL) {
+			scsi_print_command(SCp);
+
+			if(SCp->use_sg) {
+				for(i = 0; i < SCp->use_sg + 1; i++) {
+					printk(KERN_INFO " SG[%d].length = %d, move_insn=%08x, addr %08x\n", i, ((struct scatterlist *)SCp->buffer)[i].length, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].ins, ((struct NCR_700_command_slot *)SCp->host_scribble)->SG[i].pAddr);
+				}
+			}
+		}	       
+		NCR_700_internal_bus_reset(host);
+	} else if((dsps & 0xfffff000) == A_DEBUG_INTERRUPT) {
+		printk(KERN_NOTICE "scsi%d (%d:%d) DEBUG INTERRUPT %d AT %08x[%04x], continuing\n",
+		       host->host_no, pun, lun, dsps & 0xfff, dsp, dsp - hostdata->pScript);
+		resume_offset = dsp;
+	} else {
+		printk(KERN_ERR "scsi%d: (%d:%d), unidentified script interrupt 0x%x at %04x\n",
+		       host->host_no, pun, lun, dsps, dsp - hostdata->pScript);
+		NCR_700_internal_bus_reset(host);
+	}
+	return resume_offset;
+}
+
+/* We run the 53c700 with selection interrupts always enabled.  This
+ * means that the chip may be selected as soon as the bus frees.  On a
+ * busy bus, this can be before the scripts engine finishes its
+ * processing.  Therefore, part of the selection processing has to be
+ * to find out what the scripts engine is doing and complete the
+ * function if necessary (i.e. process the pending disconnect or save
+ * the interrupted initial selection */
+STATIC inline __u32
+process_selection(struct Scsi_Host *host, __u32 dsp)
+{
+	__u8 id = 0;	/* Squash compiler warning */
+	int count = 0;
+	__u32 resume_offset = 0;
+	struct NCR_700_Host_Parameters *hostdata =
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	struct scsi_cmnd *SCp = hostdata->cmd;
+	__u8 sbcl;
+
+	for(count = 0; count < 5; count++) {
+		id = NCR_700_readb(host, hostdata->chip710 ?
+				   CTEST9_REG : SFBR_REG);
+
+		/* Take out our own ID */
+		id &= ~(1<<host->this_id);
+		if(id != 0) 
+			break;
+		udelay(5);
+	}
+	sbcl = NCR_700_readb(host, SBCL_REG);
+	if((sbcl & SBCL_IO) == 0) {
+		/* mark as having been selected rather than reselected */
+		id = 0xff;
+	} else {
+		/* convert to real ID */
+		hostdata->reselection_id = id = bitmap_to_number(id);
+		DEBUG(("scsi%d:  Reselected by %d\n",
+		       host->host_no, id));
+	}
+	if(hostdata->state == NCR_700_HOST_BUSY && SCp != NULL) {
+		struct NCR_700_command_slot *slot =
+			(struct NCR_700_command_slot *)SCp->host_scribble;
+		DEBUG(("  ID %d WARNING: RESELECTION OF BUSY HOST, saving cmd %p, slot %p, addr %x [%04x], resume %x!\n", id, hostdata->cmd, slot, dsp, dsp - hostdata->pScript, resume_offset));
+		
+		switch(dsp - hostdata->pScript) {
+		case Ent_Disconnect1:
+		case Ent_Disconnect2:
+			save_for_reselection(hostdata, SCp, Ent_Disconnect2 + hostdata->pScript);
+			break;
+		case Ent_Disconnect3:
+		case Ent_Disconnect4:
+			save_for_reselection(hostdata, SCp, Ent_Disconnect4 + hostdata->pScript);
+			break;
+		case Ent_Disconnect5:
+		case Ent_Disconnect6:
+			save_for_reselection(hostdata, SCp, Ent_Disconnect6 + hostdata->pScript);
+			break;
+		case Ent_Disconnect7:
+		case Ent_Disconnect8:
+			save_for_reselection(hostdata, SCp, Ent_Disconnect8 + hostdata->pScript);
+			break;
+		case Ent_Finish1:
+		case Ent_Finish2:
+			process_script_interrupt(A_GOOD_STATUS_AFTER_STATUS, dsp, SCp, host, hostdata);
+			break;
+			
+		default:
+			slot->state = NCR_700_SLOT_QUEUED;
+			break;
+			}
+	}
+	hostdata->state = NCR_700_HOST_BUSY;
+	hostdata->cmd = NULL;
+	/* clear any stale simple tag message */
+	hostdata->msgin[1] = 0;
+	dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE,
+		       DMA_BIDIRECTIONAL);
+
+	if(id == 0xff) {
+		/* Selected as target, Ignore */
+		resume_offset = hostdata->pScript + Ent_SelectedAsTarget;
+	} else if(hostdata->tag_negotiated & (1<<id)) {
+		resume_offset = hostdata->pScript + Ent_GetReselectionWithTag;
+	} else {
+		resume_offset = hostdata->pScript + Ent_GetReselectionData;
+	}
+	return resume_offset;
+}
+
+static inline void
+NCR_700_clear_fifo(struct Scsi_Host *host) {
+	const struct NCR_700_Host_Parameters *hostdata
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(CLR_FIFO_710, host, CTEST8_REG);
+	} else {
+		NCR_700_writeb(CLR_FIFO, host, DFIFO_REG);
+	}
+}
+
+static inline void
+NCR_700_flush_fifo(struct Scsi_Host *host) {
+	const struct NCR_700_Host_Parameters *hostdata
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+	if(hostdata->chip710) {
+		NCR_700_writeb(FLUSH_DMA_FIFO_710, host, CTEST8_REG);
+		udelay(10);
+		NCR_700_writeb(0, host, CTEST8_REG);
+	} else {
+		NCR_700_writeb(FLUSH_DMA_FIFO, host, DFIFO_REG);
+		udelay(10);
+		NCR_700_writeb(0, host, DFIFO_REG);
+	}
+}
+
+
+/* The queue lock with interrupts disabled must be held on entry to
+ * this function */
+STATIC int
+NCR_700_start_command(struct scsi_cmnd *SCp)
+{
+	struct NCR_700_command_slot *slot =
+		(struct NCR_700_command_slot *)SCp->host_scribble;
+	struct NCR_700_Host_Parameters *hostdata =
+		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
+	__u16 count = 1;	/* for IDENTIFY message */
+	
+	if(hostdata->state != NCR_700_HOST_FREE) {
+		/* keep this inside the lock to close the race window where
+		 * the running command finishes on another CPU while we don't
+		 * change the state to queued on this one */
+		slot->state = NCR_700_SLOT_QUEUED;
+
+		DEBUG(("scsi%d: host busy, queueing command %p, slot %p\n",
+		       SCp->device->host->host_no, slot->cmnd, slot));
+		return 0;
+	}
+	hostdata->state = NCR_700_HOST_BUSY;
+	hostdata->cmd = SCp;
+	slot->state = NCR_700_SLOT_BUSY;
+	/* keep interrupts disabled until we have the command correctly
+	 * set up so we cannot take a selection interrupt */
+
+	hostdata->msgout[0] = NCR_700_identify(SCp->cmnd[0] != REQUEST_SENSE,
+					       SCp->device->lun);
+	/* for INQUIRY or REQUEST_SENSE commands, we cannot be sure
+	 * if the negotiated transfer parameters still hold, so
+	 * always renegotiate them */
+	if(SCp->cmnd[0] == INQUIRY || SCp->cmnd[0] == REQUEST_SENSE) {
+		NCR_700_clear_flag(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC);
+	}
+
+	/* REQUEST_SENSE is asking for contingent I_T_L(_Q) status.
+	 * If a contingent allegiance condition exists, the device
+	 * will refuse all tags, so send the request sense as untagged
+	 * */
+	if((hostdata->tag_negotiated & (1<<SCp->device->id))
+	   && (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE)) {
+		count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]);
+	}
+
+	if(hostdata->fast &&
+	   NCR_700_is_flag_clear(SCp->device, NCR_700_DEV_NEGOTIATED_SYNC)) {
+		memcpy(&hostdata->msgout[count], NCR_700_SDTR_msg,
+		       sizeof(NCR_700_SDTR_msg));
+		hostdata->msgout[count+3] = spi_period(SCp->device->sdev_target);
+		hostdata->msgout[count+4] = spi_offset(SCp->device->sdev_target);
+		count += sizeof(NCR_700_SDTR_msg);
+		NCR_700_set_flag(SCp->device, NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	}
+
+	script_patch_16(hostdata->script, MessageCount, count);
+
+
+	script_patch_ID(hostdata->script,
+			Device_ID, 1<<SCp->device->id);
+
+	script_patch_32_abs(hostdata->script, CommandAddress, 
+			    slot->pCmd);
+	script_patch_16(hostdata->script, CommandCount, SCp->cmd_len);
+	/* finally plumb the beginning of the SG list into the script
+	 * */
+	script_patch_32_abs(hostdata->script, SGScriptStartAddress,
+			    to32bit(&slot->pSG[0].ins));
+	NCR_700_clear_fifo(SCp->device->host);
+
+	if(slot->resume_offset == 0)
+		slot->resume_offset = hostdata->pScript;
+	/* now perform all the writebacks and invalidates */
+	dma_cache_sync(hostdata->msgout, count, DMA_TO_DEVICE);
+	dma_cache_sync(hostdata->msgin, MSG_ARRAY_SIZE,
+		       DMA_FROM_DEVICE);
+	dma_cache_sync(SCp->cmnd, SCp->cmd_len, DMA_TO_DEVICE);
+	dma_cache_sync(hostdata->status, 1, DMA_FROM_DEVICE);
+
+	/* set the synchronous period/offset */
+	NCR_700_writeb(NCR_700_get_SXFER(SCp->device),
+		       SCp->device->host, SXFER_REG);
+	NCR_700_writel(slot->temp, SCp->device->host, TEMP_REG);
+	NCR_700_writel(slot->resume_offset, SCp->device->host, DSP_REG);
+
+	return 1;
+}
+
+irqreturn_t
+NCR_700_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+	struct NCR_700_Host_Parameters *hostdata =
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+	__u8 istat;
+	__u32 resume_offset = 0;
+	__u8 pun = 0xff, lun = 0xff;
+	unsigned long flags;
+	int handled = 0;
+
+	/* Use the host lock to serialise acess to the 53c700
+	 * hardware.  Note: In future, we may need to take the queue
+	 * lock to enter the done routines.  When that happens, we
+	 * need to ensure that for this driver, the host lock and the
+	 * queue lock point to the same thing. */
+	spin_lock_irqsave(host->host_lock, flags);
+	if((istat = NCR_700_readb(host, ISTAT_REG))
+	      & (SCSI_INT_PENDING | DMA_INT_PENDING)) {
+		__u32 dsps;
+		__u8 sstat0 = 0, dstat = 0;
+		__u32 dsp;
+		struct scsi_cmnd *SCp = hostdata->cmd;
+		enum NCR_700_Host_State state;
+
+		handled = 1;
+		state = hostdata->state;
+		SCp = hostdata->cmd;
+
+		if(istat & SCSI_INT_PENDING) {
+			udelay(10);
+
+			sstat0 = NCR_700_readb(host, SSTAT0_REG);
+		}
+
+		if(istat & DMA_INT_PENDING) {
+			udelay(10);
+
+			dstat = NCR_700_readb(host, DSTAT_REG);
+		}
+
+		dsps = NCR_700_readl(host, DSPS_REG);
+		dsp = NCR_700_readl(host, DSP_REG);
+
+		DEBUG(("scsi%d: istat %02x sstat0 %02x dstat %02x dsp %04x[%08x] dsps 0x%x\n",
+		       host->host_no, istat, sstat0, dstat,
+		       (dsp - (__u32)(hostdata->pScript))/4,
+		       dsp, dsps));
+
+		if(SCp != NULL) {
+			pun = SCp->device->id;
+			lun = SCp->device->lun;
+		}
+
+		if(sstat0 & SCSI_RESET_DETECTED) {
+			struct scsi_device *SDp;
+			int i;
+
+			hostdata->state = NCR_700_HOST_BUSY;
+
+			printk(KERN_ERR "scsi%d: Bus Reset detected, executing command %p, slot %p, dsp %08x[%04x]\n",
+			       host->host_no, SCp, SCp == NULL ? NULL : SCp->host_scribble, dsp, dsp - hostdata->pScript);
+
+			scsi_report_bus_reset(host, 0);
+
+			/* clear all the negotiated parameters */
+			__shost_for_each_device(SDp, host)
+				SDp->hostdata = NULL;
+			
+			/* clear all the slots and their pending commands */
+			for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+				struct scsi_cmnd *SCp;
+				struct NCR_700_command_slot *slot =
+					&hostdata->slots[i];
+
+				if(slot->state == NCR_700_SLOT_FREE)
+					continue;
+				
+				SCp = slot->cmnd;
+				printk(KERN_ERR " failing command because of reset, slot %p, cmnd %p\n",
+				       slot, SCp);
+				free_slot(slot, hostdata);
+				SCp->host_scribble = NULL;
+				NCR_700_set_depth(SCp->device, 0);
+				/* NOTE: deadlock potential here: we
+				 * rely on mid-layer guarantees that
+				 * scsi_done won't try to issue the
+				 * command again otherwise we'll
+				 * deadlock on the
+				 * hostdata->state_lock */
+				SCp->result = DID_RESET << 16;
+				SCp->scsi_done(SCp);
+			}
+			mdelay(25);
+			NCR_700_chip_setup(host);
+
+			hostdata->state = NCR_700_HOST_FREE;
+			hostdata->cmd = NULL;
+			/* signal back if this was an eh induced reset */
+			if(hostdata->eh_complete != NULL)
+				complete(hostdata->eh_complete);
+			goto out_unlock;
+		} else if(sstat0 & SELECTION_TIMEOUT) {
+			DEBUG(("scsi%d: (%d:%d) selection timeout\n",
+			       host->host_no, pun, lun));
+			NCR_700_scsi_done(hostdata, SCp, DID_NO_CONNECT<<16);
+		} else if(sstat0 & PHASE_MISMATCH) {
+			struct NCR_700_command_slot *slot = (SCp == NULL) ? NULL :
+				(struct NCR_700_command_slot *)SCp->host_scribble;
+
+			if(dsp == Ent_SendMessage + 8 + hostdata->pScript) {
+				/* It wants to reply to some part of
+				 * our message */
+#ifdef NCR_700_DEBUG
+				__u32 temp = NCR_700_readl(host, TEMP_REG);
+				int count = (hostdata->script[Ent_SendMessage/4] & 0xffffff) - ((NCR_700_readl(host, DBC_REG) & 0xffffff) + NCR_700_data_residual(host));
+				printk("scsi%d (%d:%d) PHASE MISMATCH IN SEND MESSAGE %d remain, return %p[%04x], phase %s\n", host->host_no, pun, lun, count, (void *)temp, temp - hostdata->pScript, sbcl_to_string(NCR_700_readb(host, SBCL_REG)));
+#endif
+				resume_offset = hostdata->pScript + Ent_SendMessagePhaseMismatch;
+			} else if(dsp >= to32bit(&slot->pSG[0].ins) &&
+				  dsp <= to32bit(&slot->pSG[NCR_700_SG_SEGMENTS].ins)) {
+				int data_transfer = NCR_700_readl(host, DBC_REG) & 0xffffff;
+				int SGcount = (dsp - to32bit(&slot->pSG[0].ins))/sizeof(struct NCR_700_SG_List);
+				int residual = NCR_700_data_residual(host);
+				int i;
+#ifdef NCR_700_DEBUG
+				__u32 naddr = NCR_700_readl(host, DNAD_REG);
+
+				printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x\n",
+				       host->host_no, pun, lun,
+				       SGcount, data_transfer);
+				scsi_print_command(SCp);
+				if(residual) {
+					printk("scsi%d: (%d:%d) Expected phase mismatch in slot->SG[%d], transferred 0x%x, residual %d\n",
+				       host->host_no, pun, lun,
+				       SGcount, data_transfer, residual);
+				}
+#endif
+				data_transfer += residual;
+
+				if(data_transfer != 0) {
+					int count; 
+					__u32 pAddr;
+
+					SGcount--;
+
+					count = (bS_to_cpu(slot->SG[SGcount].ins) & 0x00ffffff);
+					DEBUG(("DATA TRANSFER MISMATCH, count = %d, transferred %d\n", count, count-data_transfer));
+					slot->SG[SGcount].ins &= bS_to_host(0xff000000);
+					slot->SG[SGcount].ins |= bS_to_host(data_transfer);
+					pAddr = bS_to_cpu(slot->SG[SGcount].pAddr);
+					pAddr += (count - data_transfer);
+#ifdef NCR_700_DEBUG
+					if(pAddr != naddr) {
+						printk("scsi%d (%d:%d) transfer mismatch pAddr=%lx, naddr=%lx, data_transfer=%d, residual=%d\n", host->host_no, pun, lun, (unsigned long)pAddr, (unsigned long)naddr, data_transfer, residual);
+					}
+#endif
+					slot->SG[SGcount].pAddr = bS_to_host(pAddr);
+				}
+				/* set the executed moves to nops */
+				for(i=0; i<SGcount; i++) {
+					slot->SG[i].ins = bS_to_host(SCRIPT_NOP);
+					slot->SG[i].pAddr = 0;
+				}
+				dma_cache_sync(slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
+				/* and pretend we disconnected after
+				 * the command phase */
+				resume_offset = hostdata->pScript + Ent_MsgInDuringData;
+				/* make sure all the data is flushed */
+				NCR_700_flush_fifo(host);
+			} else {
+				__u8 sbcl = NCR_700_readb(host, SBCL_REG);
+				printk(KERN_ERR "scsi%d: (%d:%d) phase mismatch at %04x, phase %s\n",
+				       host->host_no, pun, lun, dsp - hostdata->pScript, sbcl_to_string(sbcl));
+				NCR_700_internal_bus_reset(host);
+			}
+
+		} else if(sstat0 & SCSI_GROSS_ERROR) {
+			printk(KERN_ERR "scsi%d: (%d:%d) GROSS ERROR\n",
+			       host->host_no, pun, lun);
+			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+		} else if(sstat0 & PARITY_ERROR) {
+			printk(KERN_ERR "scsi%d: (%d:%d) PARITY ERROR\n",
+			       host->host_no, pun, lun);
+			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+		} else if(dstat & SCRIPT_INT_RECEIVED) {
+			DEBUG(("scsi%d: (%d:%d) ====>SCRIPT INTERRUPT<====\n",
+			       host->host_no, pun, lun));
+			resume_offset = process_script_interrupt(dsps, dsp, SCp, host, hostdata);
+		} else if(dstat & (ILGL_INST_DETECTED)) {
+			printk(KERN_ERR "scsi%d: (%d:%d) Illegal Instruction detected at 0x%08x[0x%x]!!!\n"
+			       "         Please email James.Bottomley@HansenPartnership.com with the details\n",
+			       host->host_no, pun, lun,
+			       dsp, dsp - hostdata->pScript);
+			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+		} else if(dstat & (WATCH_DOG_INTERRUPT|ABORTED)) {
+			printk(KERN_ERR "scsi%d: (%d:%d) serious DMA problem, dstat=%02x\n",
+			       host->host_no, pun, lun, dstat);
+			NCR_700_scsi_done(hostdata, SCp, DID_ERROR<<16);
+		}
+
+		
+		/* NOTE: selection interrupt processing MUST occur
+		 * after script interrupt processing to correctly cope
+		 * with the case where we process a disconnect and
+		 * then get reselected before we process the
+		 * disconnection */
+		if(sstat0 & SELECTED) {
+			/* FIXME: It currently takes at least FOUR
+			 * interrupts to complete a command that
+			 * disconnects: one for the disconnect, one
+			 * for the reselection, one to get the
+			 * reselection data and one to complete the
+			 * command.  If we guess the reselected
+			 * command here and prepare it, we only need
+			 * to get a reselection data interrupt if we
+			 * guessed wrongly.  Since the interrupt
+			 * overhead is much greater than the command
+			 * setup, this would be an efficient
+			 * optimisation particularly as we probably
+			 * only have one outstanding command on a
+			 * target most of the time */
+
+			resume_offset = process_selection(host, dsp);
+
+		}
+
+	}
+
+	if(resume_offset) {
+		if(hostdata->state != NCR_700_HOST_BUSY) {
+			printk(KERN_ERR "scsi%d: Driver error: resume at 0x%08x [0x%04x] with non busy host!\n",
+			       host->host_no, resume_offset, resume_offset - hostdata->pScript);
+			hostdata->state = NCR_700_HOST_BUSY;
+		}
+
+		DEBUG(("Attempting to resume at %x\n", resume_offset));
+		NCR_700_clear_fifo(host);
+		NCR_700_writel(resume_offset, host, DSP_REG);
+	} 
+	/* There is probably a technical no-no about this: If we're a
+	 * shared interrupt and we got this interrupt because the
+	 * other device needs servicing not us, we're still going to
+	 * check our queued commands here---of course, there shouldn't
+	 * be any outstanding.... */
+	if(hostdata->state == NCR_700_HOST_FREE) {
+		int i;
+
+		for(i = 0; i < NCR_700_COMMAND_SLOTS_PER_HOST; i++) {
+			/* fairness: always run the queue from the last
+			 * position we left off */
+			int j = (i + hostdata->saved_slot_position)
+				% NCR_700_COMMAND_SLOTS_PER_HOST;
+			
+			if(hostdata->slots[j].state != NCR_700_SLOT_QUEUED)
+				continue;
+			if(NCR_700_start_command(hostdata->slots[j].cmnd)) {
+				DEBUG(("scsi%d: Issuing saved command slot %p, cmd %p\t\n",
+				       host->host_no, &hostdata->slots[j],
+				       hostdata->slots[j].cmnd));
+				hostdata->saved_slot_position = j + 1;
+			}
+
+			break;
+		}
+	}
+ out_unlock:
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return IRQ_RETVAL(handled);
+}
+
+STATIC int
+NCR_700_queuecommand(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *))
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
+	__u32 move_ins;
+	enum dma_data_direction direction;
+	struct NCR_700_command_slot *slot;
+
+	if(hostdata->command_slot_count >= NCR_700_COMMAND_SLOTS_PER_HOST) {
+		/* We're over our allocation, this should never happen
+		 * since we report the max allocation to the mid layer */
+		printk(KERN_WARNING "scsi%d: Command depth has gone over queue depth\n", SCp->device->host->host_no);
+		return 1;
+	}
+	/* check for untagged commands.  We cannot have any outstanding
+	 * commands if we accept them.  Commands could be untagged because:
+	 *
+	 * - The tag negotiated bitmap is clear
+	 * - The blk layer sent and untagged command
+	 */
+	if(NCR_700_get_depth(SCp->device) != 0
+	   && (!(hostdata->tag_negotiated & (1<<SCp->device->id))
+	       || !blk_rq_tagged(SCp->request))) {
+		DEBUG((KERN_ERR "scsi%d (%d:%d) has non zero depth %d\n",
+		       SCp->device->host->host_no, SCp->device->id, SCp->device->lun,
+		       NCR_700_get_depth(SCp->device)));
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+	if(NCR_700_get_depth(SCp->device) >= SCp->device->queue_depth) {
+		DEBUG((KERN_ERR "scsi%d (%d:%d) has max tag depth %d\n",
+		       SCp->device->host->host_no, SCp->device->id, SCp->device->lun,
+		       NCR_700_get_depth(SCp->device)));
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+	}
+	NCR_700_set_depth(SCp->device, NCR_700_get_depth(SCp->device) + 1);
+
+	/* begin the command here */
+	/* no need to check for NULL, test for command_slot_count above
+	 * ensures a slot is free */
+	slot = find_empty_slot(hostdata);
+
+	slot->cmnd = SCp;
+
+	SCp->scsi_done = done;
+	SCp->host_scribble = (unsigned char *)slot;
+	SCp->SCp.ptr = NULL;
+	SCp->SCp.buffer = NULL;
+
+#ifdef NCR_700_DEBUG
+	printk("53c700: scsi%d, command ", SCp->device->host->host_no);
+	scsi_print_command(SCp);
+#endif
+	if(blk_rq_tagged(SCp->request)
+	   && (hostdata->tag_negotiated &(1<<SCp->device->id)) == 0
+	   && NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
+		printk(KERN_ERR "scsi%d: (%d:%d) Enabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+		hostdata->tag_negotiated |= (1<<SCp->device->id);
+		NCR_700_set_tag_neg_state(SCp->device, NCR_700_DURING_TAG_NEGOTIATION);
+	}
+
+	/* here we may have to process an untagged command.  The gate
+	 * above ensures that this will be the only one outstanding,
+	 * so clear the tag negotiated bit.
+	 *
+	 * FIXME: This will royally screw up on multiple LUN devices
+	 * */
+	if(!blk_rq_tagged(SCp->request)
+	   && (hostdata->tag_negotiated &(1<<SCp->device->id))) {
+		printk(KERN_INFO "scsi%d: (%d:%d) Disabling Tag Command Queuing\n", SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+		hostdata->tag_negotiated &= ~(1<<SCp->device->id);
+	}
+
+	if((hostdata->tag_negotiated &(1<<SCp->device->id))
+	   && scsi_get_tag_type(SCp->device)) {
+		slot->tag = SCp->request->tag;
+		DEBUG(("53c700 %d:%d:%d, sending out tag %d, slot %p\n",
+		       SCp->device->host->host_no, SCp->device->id, SCp->device->lun, slot->tag,
+		       slot));
+	} else {
+		slot->tag = SCSI_NO_TAG;
+		/* must populate current_cmnd for scsi_find_tag to work */
+		SCp->device->current_cmnd = SCp;
+	}
+	/* sanity check: some of the commands generated by the mid-layer
+	 * have an eccentric idea of their sc_data_direction */
+	if(!SCp->use_sg && !SCp->request_bufflen 
+	   && SCp->sc_data_direction != DMA_NONE) {
+#ifdef NCR_700_DEBUG
+		printk("53c700: Command");
+		scsi_print_command(SCp);
+		printk("Has wrong data direction %d\n", SCp->sc_data_direction);
+#endif
+		SCp->sc_data_direction = DMA_NONE;
+	}
+
+	switch (SCp->cmnd[0]) {
+	case REQUEST_SENSE:
+		/* clear the internal sense magic */
+		SCp->cmnd[6] = 0;
+		/* fall through */
+	default:
+		/* OK, get it from the command */
+		switch(SCp->sc_data_direction) {
+		case DMA_BIDIRECTIONAL:
+		default:
+			printk(KERN_ERR "53c700: Unknown command for data direction ");
+			scsi_print_command(SCp);
+			
+			move_ins = 0;
+			break;
+		case DMA_NONE:
+			move_ins = 0;
+			break;
+		case DMA_FROM_DEVICE:
+			move_ins = SCRIPT_MOVE_DATA_IN;
+			break;
+		case DMA_TO_DEVICE:
+			move_ins = SCRIPT_MOVE_DATA_OUT;
+			break;
+		}
+	}
+
+	/* now build the scatter gather list */
+	direction = SCp->sc_data_direction;
+	if(move_ins != 0) {
+		int i;
+		int sg_count;
+		dma_addr_t vPtr = 0;
+		__u32 count = 0;
+
+		if(SCp->use_sg) {
+			sg_count = dma_map_sg(hostdata->dev, SCp->buffer,
+					      SCp->use_sg, direction);
+		} else {
+			vPtr = dma_map_single(hostdata->dev,
+					      SCp->request_buffer, 
+					      SCp->request_bufflen,
+					      direction);
+			count = SCp->request_bufflen;
+			slot->dma_handle = vPtr;
+			sg_count = 1;
+		}
+			
+
+		for(i = 0; i < sg_count; i++) {
+
+			if(SCp->use_sg) {
+				struct scatterlist *sg = SCp->buffer;
+
+				vPtr = sg_dma_address(&sg[i]);
+				count = sg_dma_len(&sg[i]);
+			}
+
+			slot->SG[i].ins = bS_to_host(move_ins | count);
+			DEBUG((" scatter block %d: move %d[%08x] from 0x%lx\n",
+			       i, count, slot->SG[i].ins, (unsigned long)vPtr));
+			slot->SG[i].pAddr = bS_to_host(vPtr);
+		}
+		slot->SG[i].ins = bS_to_host(SCRIPT_RETURN);
+		slot->SG[i].pAddr = 0;
+		dma_cache_sync(slot->SG, sizeof(slot->SG), DMA_TO_DEVICE);
+		DEBUG((" SETTING %08lx to %x\n",
+		       (&slot->pSG[i].ins), 
+		       slot->SG[i].ins));
+	}
+	slot->resume_offset = 0;
+	slot->pCmd = dma_map_single(hostdata->dev, SCp->cmnd,
+				    sizeof(SCp->cmnd), DMA_TO_DEVICE);
+	NCR_700_start_command(SCp);
+	return 0;
+}
+
+STATIC int
+NCR_700_abort(struct scsi_cmnd * SCp)
+{
+	struct NCR_700_command_slot *slot;
+
+	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants to abort command\n\t",
+	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+	scsi_print_command(SCp);
+
+	slot = (struct NCR_700_command_slot *)SCp->host_scribble;
+
+	if(slot == NULL)
+		/* no outstanding command to abort */
+		return SUCCESS;
+	if(SCp->cmnd[0] == TEST_UNIT_READY) {
+		/* FIXME: This is because of a problem in the new
+		 * error handler.  When it is in error recovery, it
+		 * will send a TUR to a device it thinks may still be
+		 * showing a problem.  If the TUR isn't responded to,
+		 * it will abort it and mark the device off line.
+		 * Unfortunately, it does no other error recovery, so
+		 * this would leave us with an outstanding command
+		 * occupying a slot.  Rather than allow this to
+		 * happen, we issue a bus reset to force all
+		 * outstanding commands to terminate here. */
+		NCR_700_internal_bus_reset(SCp->device->host);
+		/* still drop through and return failed */
+	}
+	return FAILED;
+
+}
+
+STATIC int
+NCR_700_bus_reset(struct scsi_cmnd * SCp)
+{
+	DECLARE_COMPLETION(complete);
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SCp->device->host->hostdata[0];
+
+	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants BUS reset, cmd %p\n\t",
+	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun, SCp);
+	scsi_print_command(SCp);
+	/* In theory, eh_complete should always be null because the
+	 * eh is single threaded, but just in case we're handling a
+	 * reset via sg or something */
+	while(hostdata->eh_complete != NULL) {
+		spin_unlock_irq(SCp->device->host->host_lock);
+		msleep_interruptible(100);
+		spin_lock_irq(SCp->device->host->host_lock);
+	}
+	hostdata->eh_complete = &complete;
+	NCR_700_internal_bus_reset(SCp->device->host);
+	spin_unlock_irq(SCp->device->host->host_lock);
+	wait_for_completion(&complete);
+	spin_lock_irq(SCp->device->host->host_lock);
+	hostdata->eh_complete = NULL;
+	/* Revalidate the transport parameters of the failing device */
+	if(hostdata->fast)
+		spi_schedule_dv_device(SCp->device);
+	return SUCCESS;
+}
+
+STATIC int
+NCR_700_dev_reset(struct scsi_cmnd * SCp)
+{
+	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants device reset\n\t",
+	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+	scsi_print_command(SCp);
+	
+	return FAILED;
+}
+
+STATIC int
+NCR_700_host_reset(struct scsi_cmnd * SCp)
+{
+	printk(KERN_INFO "scsi%d (%d:%d) New error handler wants HOST reset\n\t",
+	       SCp->device->host->host_no, SCp->device->id, SCp->device->lun);
+	scsi_print_command(SCp);
+
+	NCR_700_internal_bus_reset(SCp->device->host);
+	NCR_700_chip_reset(SCp->device->host);
+	return SUCCESS;
+}
+
+STATIC void
+NCR_700_set_period(struct scsi_target *STp, int period)
+{
+	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
+	
+	if(!hostdata->fast)
+		return;
+
+	if(period < hostdata->min_period)
+		period = hostdata->min_period;
+
+	spi_period(STp) = period;
+	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
+}
+
+STATIC void
+NCR_700_set_offset(struct scsi_target *STp, int offset)
+{
+	struct Scsi_Host *SHp = dev_to_shost(STp->dev.parent);
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SHp->hostdata[0];
+	int max_offset = hostdata->chip710
+		? NCR_710_MAX_OFFSET : NCR_700_MAX_OFFSET;
+	
+	if(!hostdata->fast)
+		return;
+
+	if(offset > max_offset)
+		offset = max_offset;
+
+	/* if we're currently async, make sure the period is reasonable */
+	if(spi_offset(STp) == 0 && (spi_period(STp) < hostdata->min_period ||
+				    spi_period(STp) > 0xff))
+		spi_period(STp) = hostdata->min_period;
+
+	spi_offset(STp) = offset;
+	spi_flags(STp) &= ~(NCR_700_DEV_NEGOTIATED_SYNC |
+			    NCR_700_DEV_BEGIN_SYNC_NEGOTIATION);
+	spi_flags(STp) |= NCR_700_DEV_PRINT_SYNC_NEGOTIATION;
+}
+
+
+
+STATIC int
+NCR_700_slave_configure(struct scsi_device *SDp)
+{
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+	/* to do here: allocate memory; build a queue_full list */
+	if(SDp->tagged_supported) {
+		scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
+		scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS);
+		NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
+	} else {
+		/* initialise to default depth */
+		scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
+	}
+	if(hostdata->fast) {
+		/* Find the correct offset and period via domain validation */
+		if (!spi_initial_dv(SDp->sdev_target))
+			spi_dv_device(SDp);
+	} else {
+		spi_offset(SDp->sdev_target) = 0;
+		spi_period(SDp->sdev_target) = 0;
+	}
+	return 0;
+}
+
+STATIC void
+NCR_700_slave_destroy(struct scsi_device *SDp)
+{
+	/* to do here: deallocate memory */
+}
+
+static int
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
+{
+	if (depth > NCR_700_MAX_TAGS)
+		depth = NCR_700_MAX_TAGS;
+
+	scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth);
+	return depth;
+}
+
+static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
+{
+	int change_tag = ((tag_type ==0 &&  scsi_get_tag_type(SDp) != 0)
+			  || (tag_type != 0 && scsi_get_tag_type(SDp) == 0));
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
+
+	scsi_set_tag_type(SDp, tag_type);
+
+	/* We have a global (per target) flag to track whether TCQ is
+	 * enabled, so we'll be turning it off for the entire target here.
+	 * our tag algorithm will fail if we mix tagged and untagged commands,
+	 * so quiesce the device before doing this */
+	if (change_tag)
+		scsi_target_quiesce(SDp->sdev_target);
+
+	if (!tag_type) {
+		/* shift back to the default unqueued number of commands
+		 * (the user can still raise this) */
+		scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun);
+		hostdata->tag_negotiated &= ~(1 << SDp->id);
+	} else {
+		/* Here, we cleared the negotiation flag above, so this
+		 * will force the driver to renegotiate */
+		scsi_activate_tcq(SDp, SDp->queue_depth);
+		if (change_tag)
+			NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
+	}
+	if (change_tag)
+		scsi_target_resume(SDp->sdev_target);
+
+	return tag_type;
+}
+
+static ssize_t
+NCR_700_show_active_tags(struct device *dev, char *buf)
+{
+	struct scsi_device *SDp = to_scsi_device(dev);
+
+	return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp));
+}
+
+static struct device_attribute NCR_700_active_tags_attr = {
+	.attr = {
+		.name =		"active_tags",
+		.mode =		S_IRUGO,
+	},
+	.show = NCR_700_show_active_tags,
+};
+
+STATIC struct device_attribute *NCR_700_dev_attrs[] = {
+	&NCR_700_active_tags_attr,
+	NULL,
+};
+
+EXPORT_SYMBOL(NCR_700_detect);
+EXPORT_SYMBOL(NCR_700_release);
+EXPORT_SYMBOL(NCR_700_intr);
+
+static struct spi_function_template NCR_700_transport_functions =  {
+	.set_period	= NCR_700_set_period,
+	.show_period	= 1,
+	.set_offset	= NCR_700_set_offset,
+	.show_offset	= 1,
+};
+
+static int __init NCR_700_init(void)
+{
+	NCR_700_transport_template = spi_attach_transport(&NCR_700_transport_functions);
+	if(!NCR_700_transport_template)
+		return -ENODEV;
+	return 0;
+}
+
+static void __exit NCR_700_exit(void)
+{
+	spi_release_transport(NCR_700_transport_template);
+}
+
+module_init(NCR_700_init);
+module_exit(NCR_700_exit);
+
diff --git a/drivers/scsi/53c700.h b/drivers/scsi/53c700.h
new file mode 100644
index 0000000..df4aa30
--- /dev/null
+++ b/drivers/scsi/53c700.h
@@ -0,0 +1,649 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* Driver for 53c700 and 53c700-66 chips from NCR and Symbios
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+ */
+
+#ifndef _53C700_H
+#define _53C700_H
+
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include <scsi/scsi_device.h>
+
+
+#if defined(CONFIG_53C700_MEM_MAPPED) && defined(CONFIG_53C700_IO_MAPPED)
+#define CONFIG_53C700_BOTH_MAPPED
+#endif
+
+/* Turn on for general debugging---too verbose for normal use */
+#undef	NCR_700_DEBUG
+/* Debug the tag queues, checking hash queue allocation and deallocation
+ * and search for duplicate tags */
+#undef NCR_700_TAG_DEBUG
+
+#ifdef NCR_700_DEBUG
+#define DEBUG(x)	printk x
+#else
+#define DEBUG(x)
+#endif
+
+/* The number of available command slots */
+#define NCR_700_COMMAND_SLOTS_PER_HOST	64
+/* The maximum number of Scatter Gathers we allow */
+#define NCR_700_SG_SEGMENTS		32
+/* The maximum number of luns (make this of the form 2^n) */
+#define NCR_700_MAX_LUNS		32
+#define NCR_700_LUN_MASK		(NCR_700_MAX_LUNS - 1)
+/* Maximum number of tags the driver ever allows per device */
+#define NCR_700_MAX_TAGS		16
+/* Tag depth the driver starts out with (can be altered in sysfs) */
+#define NCR_700_DEFAULT_TAGS		4
+/* This is the default number of commands per LUN in the untagged case.
+ * two is a good value because it means we can have one command active and
+ * one command fully prepared and waiting
+ */
+#define NCR_700_CMD_PER_LUN		2
+/* magic byte identifying an internally generated REQUEST_SENSE command */
+#define NCR_700_INTERNAL_SENSE_MAGIC	0x42
+
+/* WARNING: Leave this in for now: the dependency preprocessor doesn't
+ * pick up file specific flags, so must define here if they are not
+ * set */
+#if !defined(CONFIG_53C700_IO_MAPPED) && !defined(CONFIG_53C700_MEM_MAPPED)
+#error "Config.in must define either CONFIG_53C700_IO_MAPPED or CONFIG_53C700_MEM_MAPPED to use this scsi core."
+#endif
+
+struct NCR_700_Host_Parameters;
+
+/* These are the externally used routines */
+struct Scsi_Host *NCR_700_detect(struct scsi_host_template *,
+		struct NCR_700_Host_Parameters *, struct device *);
+int NCR_700_release(struct Scsi_Host *host);
+irqreturn_t NCR_700_intr(int, void *, struct pt_regs *);
+
+
+enum NCR_700_Host_State {
+	NCR_700_HOST_BUSY,
+	NCR_700_HOST_FREE,
+};
+
+struct NCR_700_SG_List {
+	/* The following is a script fragment to move the buffer onto the
+	 * bus and then link the next fragment or return */
+	#define	SCRIPT_MOVE_DATA_IN		0x09000000
+	#define	SCRIPT_MOVE_DATA_OUT		0x08000000
+	__u32	ins;
+	__u32	pAddr;
+	#define	SCRIPT_NOP			0x80000000
+	#define	SCRIPT_RETURN			0x90080000
+};
+
+/* We use device->hostdata to store negotiated parameters.  This is
+ * supposed to be a pointer to a device private area, but we cannot
+ * really use it as such since it will never be freed, so just use the
+ * 32 bits to cram the information.  The SYNC negotiation sequence looks
+ * like:
+ * 
+ * If DEV_NEGOTIATED_SYNC not set, tack and SDTR message on to the
+ * initial identify for the device and set DEV_BEGIN_SYNC_NEGOTATION
+ * If we get an SDTR reply, work out the SXFER parameters, squirrel
+ * them away here, clear DEV_BEGIN_SYNC_NEGOTIATION and set
+ * DEV_NEGOTIATED_SYNC.  If we get a REJECT msg, squirrel
+ *
+ *
+ * 0:7	SXFER_REG negotiated value for this device
+ * 8:15 Current queue depth
+ * 16	negotiated SYNC flag
+ * 17 begin SYNC negotiation flag 
+ * 18 device supports tag queueing */
+#define NCR_700_DEV_NEGOTIATED_SYNC	(1<<16)
+#define NCR_700_DEV_BEGIN_SYNC_NEGOTIATION	(1<<17)
+#define NCR_700_DEV_PRINT_SYNC_NEGOTIATION (1<<19)
+
+static inline void
+NCR_700_set_depth(struct scsi_device *SDp, __u8 depth)
+{
+	long l = (long)SDp->hostdata;
+
+	l &= 0xffff00ff;
+	l |= 0xff00 & (depth << 8);
+	SDp->hostdata = (void *)l;
+}
+static inline __u8
+NCR_700_get_depth(struct scsi_device *SDp)
+{
+	return ((((unsigned long)SDp->hostdata) & 0xff00)>>8);
+}
+static inline int
+NCR_700_is_flag_set(struct scsi_device *SDp, __u32 flag)
+{
+	return (spi_flags(SDp->sdev_target) & flag) == flag;
+}
+static inline int
+NCR_700_is_flag_clear(struct scsi_device *SDp, __u32 flag)
+{
+	return (spi_flags(SDp->sdev_target) & flag) == 0;
+}
+static inline void
+NCR_700_set_flag(struct scsi_device *SDp, __u32 flag)
+{
+	spi_flags(SDp->sdev_target) |= flag;
+}
+static inline void
+NCR_700_clear_flag(struct scsi_device *SDp, __u32 flag)
+{
+	spi_flags(SDp->sdev_target) &= ~flag;
+}
+
+enum NCR_700_tag_neg_state {
+	NCR_700_START_TAG_NEGOTIATION = 0,
+	NCR_700_DURING_TAG_NEGOTIATION = 1,
+	NCR_700_FINISHED_TAG_NEGOTIATION = 2,
+};
+
+static inline enum NCR_700_tag_neg_state
+NCR_700_get_tag_neg_state(struct scsi_device *SDp)
+{
+	return (enum NCR_700_tag_neg_state)((spi_flags(SDp->sdev_target)>>20) & 0x3);
+}
+
+static inline void
+NCR_700_set_tag_neg_state(struct scsi_device *SDp,
+			  enum NCR_700_tag_neg_state state)
+{
+	/* clear the slot */
+	spi_flags(SDp->sdev_target) &= ~(0x3 << 20);
+	spi_flags(SDp->sdev_target) |= ((__u32)state) << 20;
+}
+
+struct NCR_700_command_slot {
+	struct NCR_700_SG_List	SG[NCR_700_SG_SEGMENTS+1];
+	struct NCR_700_SG_List	*pSG;
+	#define NCR_700_SLOT_MASK 0xFC
+	#define NCR_700_SLOT_MAGIC 0xb8
+	#define	NCR_700_SLOT_FREE (0|NCR_700_SLOT_MAGIC) /* slot may be used */
+	#define NCR_700_SLOT_BUSY (1|NCR_700_SLOT_MAGIC) /* slot has command active on HA */
+	#define NCR_700_SLOT_QUEUED (2|NCR_700_SLOT_MAGIC) /* slot has command to be made active on HA */
+	__u8	state;
+	int	tag;
+	__u32	resume_offset;
+	struct scsi_cmnd *cmnd;
+	/* The pci_mapped address of the actual command in cmnd */
+	dma_addr_t	pCmd;
+	__u32		temp;
+	/* if this command is a pci_single mapping, holds the dma address
+	 * for later unmapping in the done routine */
+	dma_addr_t	dma_handle;
+	/* historical remnant, now used to link free commands */
+	struct NCR_700_command_slot *ITL_forw;
+};
+
+struct NCR_700_Host_Parameters {
+	/* These must be filled in by the calling driver */
+	int	clock;			/* board clock speed in MHz */
+	unsigned long	base;		/* the base for the port (copied to host) */
+	struct device	*dev;
+	__u32	dmode_extra;	/* adjustable bus settings */
+	__u32	differential:1;	/* if we are differential */
+#ifdef CONFIG_53C700_LE_ON_BE
+	/* This option is for HP only.  Set it if your chip is wired for
+	 * little endian on this platform (which is big endian) */
+	__u32	force_le_on_be:1;
+#endif
+	__u32	chip710:1;	/* set if really a 710 not 700 */
+	__u32	burst_disable:1;	/* set to 1 to disable 710 bursting */
+
+	/* NOTHING BELOW HERE NEEDS ALTERING */
+	__u32	fast:1;		/* if we can alter the SCSI bus clock
+                                   speed (so can negiotiate sync) */
+#ifdef CONFIG_53C700_BOTH_MAPPED
+	__u32	mem_mapped;	/* set if memory mapped */
+#endif
+	int	sync_clock;	/* The speed of the SYNC core */
+
+	__u32	*script;		/* pointer to script location */
+	__u32	pScript;		/* physical mem addr of script */
+
+	enum NCR_700_Host_State state; /* protected by state lock */
+	struct scsi_cmnd *cmd;
+	/* Note: pScript contains the single consistent block of
+	 * memory.  All the msgin, msgout and status are allocated in
+	 * this memory too (at separate cache lines).  TOTAL_MEM_SIZE
+	 * represents the total size of this area */
+#define	MSG_ARRAY_SIZE	8
+#define	MSGOUT_OFFSET	(L1_CACHE_ALIGN(sizeof(SCRIPT)))
+	__u8	*msgout;
+#define MSGIN_OFFSET	(MSGOUT_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
+	__u8	*msgin;
+#define STATUS_OFFSET	(MSGIN_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
+	__u8	*status;
+#define SLOTS_OFFSET	(STATUS_OFFSET + L1_CACHE_ALIGN(MSG_ARRAY_SIZE))
+	struct NCR_700_command_slot	*slots;
+#define	TOTAL_MEM_SIZE	(SLOTS_OFFSET + L1_CACHE_ALIGN(sizeof(struct NCR_700_command_slot) * NCR_700_COMMAND_SLOTS_PER_HOST))
+	int	saved_slot_position;
+	int	command_slot_count; /* protected by state lock */
+	__u8	tag_negotiated;
+	__u8	rev;
+	__u8	reselection_id;
+	__u8	min_period;
+
+	/* Free list, singly linked by ITL_forw elements */
+	struct NCR_700_command_slot *free_list;
+	/* Completion for waited for ops, like reset, abort or
+	 * device reset.
+	 *
+	 * NOTE: relies on single threading in the error handler to
+	 * have only one outstanding at once */
+	struct completion *eh_complete;
+};
+
+/*
+ *	53C700 Register Interface - the offset from the Selected base
+ *	I/O address */
+#ifdef CONFIG_53C700_LE_ON_BE
+#define bE	(hostdata->force_le_on_be ? 0 : 3)
+#define	bSWAP	(hostdata->force_le_on_be)
+#elif defined(__BIG_ENDIAN)
+#define bE	3
+#define bSWAP	0
+#elif defined(__LITTLE_ENDIAN)
+#define bE	0
+#define bSWAP	0
+#else
+#error "__BIG_ENDIAN or __LITTLE_ENDIAN must be defined, did you include byteorder.h?"
+#endif
+#define bS_to_cpu(x)	(bSWAP ? le32_to_cpu(x) : (x))
+#define bS_to_host(x)	(bSWAP ? cpu_to_le32(x) : (x))
+
+/* NOTE: These registers are in the LE register space only, the required byte
+ * swapping is done by the NCR_700_{read|write}[b] functions */
+#define	SCNTL0_REG			0x00
+#define		FULL_ARBITRATION	0xc0
+#define 	PARITY			0x08
+#define		ENABLE_PARITY		0x04
+#define 	AUTO_ATN		0x02
+#define	SCNTL1_REG			0x01
+#define 	SLOW_BUS		0x80
+#define		ENABLE_SELECT		0x20
+#define		ASSERT_RST		0x08
+#define		ASSERT_EVEN_PARITY	0x04
+#define	SDID_REG			0x02
+#define	SIEN_REG			0x03
+#define 	PHASE_MM_INT		0x80
+#define 	FUNC_COMP_INT		0x40
+#define 	SEL_TIMEOUT_INT		0x20
+#define 	SELECT_INT		0x10
+#define 	GROSS_ERR_INT		0x08
+#define 	UX_DISC_INT		0x04
+#define 	RST_INT			0x02
+#define 	PAR_ERR_INT		0x01
+#define	SCID_REG			0x04
+#define SXFER_REG			0x05
+#define		ASYNC_OPERATION		0x00
+#define SODL_REG                        0x06
+#define	SOCL_REG			0x07
+#define	SFBR_REG			0x08
+#define	SIDL_REG			0x09
+#define	SBDL_REG			0x0A
+#define	SBCL_REG			0x0B
+/* read bits */
+#define		SBCL_IO			0x01
+/*write bits */
+#define		SYNC_DIV_AS_ASYNC	0x00
+#define		SYNC_DIV_1_0		0x01
+#define		SYNC_DIV_1_5		0x02
+#define		SYNC_DIV_2_0		0x03
+#define	DSTAT_REG			0x0C
+#define		ILGL_INST_DETECTED	0x01
+#define		WATCH_DOG_INTERRUPT	0x02
+#define		SCRIPT_INT_RECEIVED	0x04
+#define		ABORTED			0x10
+#define	SSTAT0_REG			0x0D
+#define		PARITY_ERROR		0x01
+#define		SCSI_RESET_DETECTED	0x02
+#define		UNEXPECTED_DISCONNECT	0x04
+#define		SCSI_GROSS_ERROR	0x08
+#define		SELECTED		0x10
+#define		SELECTION_TIMEOUT	0x20
+#define		FUNCTION_COMPLETE	0x40
+#define		PHASE_MISMATCH 		0x80
+#define	SSTAT1_REG			0x0E
+#define		SIDL_REG_FULL		0x80
+#define		SODR_REG_FULL		0x40
+#define		SODL_REG_FULL		0x20
+#define SSTAT2_REG                      0x0F
+#define CTEST0_REG                      0x14
+#define		BTB_TIMER_DISABLE	0x40
+#define CTEST1_REG                      0x15
+#define CTEST2_REG                      0x16
+#define CTEST3_REG                      0x17
+#define CTEST4_REG                      0x18
+#define         DISABLE_FIFO            0x00
+#define         SLBE                    0x10
+#define         SFWR                    0x08
+#define         BYTE_LANE0              0x04
+#define         BYTE_LANE1              0x05
+#define         BYTE_LANE2              0x06
+#define         BYTE_LANE3              0x07
+#define         SCSI_ZMODE              0x20
+#define         ZMODE                   0x40
+#define CTEST5_REG                      0x19
+#define         MASTER_CONTROL          0x10
+#define         DMA_DIRECTION           0x08
+#define CTEST7_REG                      0x1B
+#define		BURST_DISABLE		0x80 /* 710 only */
+#define		SEL_TIMEOUT_DISABLE	0x10 /* 710 only */
+#define         DFP                     0x08
+#define         EVP                     0x04
+#define		DIFF			0x01
+#define CTEST6_REG                      0x1A
+#define	TEMP_REG			0x1C
+#define	DFIFO_REG			0x20
+#define		FLUSH_DMA_FIFO		0x80
+#define		CLR_FIFO		0x40
+#define	ISTAT_REG			0x21
+#define		ABORT_OPERATION		0x80
+#define		SOFTWARE_RESET_710	0x40
+#define		DMA_INT_PENDING		0x01
+#define		SCSI_INT_PENDING	0x02
+#define		CONNECTED		0x08
+#define CTEST8_REG                      0x22
+#define         LAST_DIS_ENBL           0x01
+#define		SHORTEN_FILTERING	0x04
+#define		ENABLE_ACTIVE_NEGATION	0x10
+#define		GENERATE_RECEIVE_PARITY	0x20
+#define		CLR_FIFO_710		0x04
+#define		FLUSH_DMA_FIFO_710	0x08
+#define CTEST9_REG                      0x23
+#define	DBC_REG				0x24
+#define	DCMD_REG			0x27
+#define	DNAD_REG			0x28
+#define	DIEN_REG			0x39
+#define		BUS_FAULT		0x20
+#define 	ABORT_INT		0x10
+#define 	INT_INST_INT		0x04
+#define 	WD_INT			0x02
+#define 	ILGL_INST_INT		0x01
+#define	DCNTL_REG			0x3B
+#define		SOFTWARE_RESET		0x01
+#define		COMPAT_700_MODE		0x01
+#define 	SCRPTS_16BITS		0x20
+#define		ASYNC_DIV_2_0		0x00
+#define		ASYNC_DIV_1_5		0x40
+#define		ASYNC_DIV_1_0		0x80
+#define		ASYNC_DIV_3_0		0xc0
+#define DMODE_710_REG			0x38
+#define	DMODE_700_REG			0x34
+#define		BURST_LENGTH_1		0x00
+#define		BURST_LENGTH_2		0x40
+#define		BURST_LENGTH_4		0x80
+#define		BURST_LENGTH_8		0xC0
+#define		DMODE_FC1		0x10
+#define		DMODE_FC2		0x20
+#define 	BW16			32 
+#define 	MODE_286		16
+#define 	IO_XFER			8
+#define 	FIXED_ADDR		4
+
+#define DSP_REG                         0x2C
+#define DSPS_REG                        0x30
+
+/* Parameters to begin SDTR negotiations.  Empirically, I find that
+ * the 53c700-66 cannot handle an offset >8, so don't change this  */
+#define NCR_700_MAX_OFFSET	8
+/* Was hoping the max offset would be greater for the 710, but
+ * empirically it seems to be 8 also */
+#define NCR_710_MAX_OFFSET	8
+#define NCR_700_MIN_XFERP	1
+#define NCR_710_MIN_XFERP	0
+#define NCR_700_MIN_PERIOD	25 /* for SDTR message, 100ns */
+
+#define script_patch_32(script, symbol, value) \
+{ \
+	int i; \
+	for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+		__u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]) + value; \
+		(script)[A_##symbol##_used[i]] = bS_to_host(val); \
+		dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+		DEBUG((" script, patching %s at %d to 0x%lx\n", \
+		       #symbol, A_##symbol##_used[i], (value))); \
+	} \
+}
+
+#define script_patch_32_abs(script, symbol, value) \
+{ \
+	int i; \
+	for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+		(script)[A_##symbol##_used[i]] = bS_to_host(value); \
+		dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+		DEBUG((" script, patching %s at %d to 0x%lx\n", \
+		       #symbol, A_##symbol##_used[i], (value))); \
+	} \
+}
+
+/* Used for patching the SCSI ID in the SELECT instruction */
+#define script_patch_ID(script, symbol, value) \
+{ \
+	int i; \
+	for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+		__u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \
+		val &= 0xff00ffff; \
+		val |= ((value) & 0xff) << 16; \
+		(script)[A_##symbol##_used[i]] = bS_to_host(val); \
+		dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+		DEBUG((" script, patching ID field %s at %d to 0x%x\n", \
+		       #symbol, A_##symbol##_used[i], val)); \
+	} \
+}
+
+#define script_patch_16(script, symbol, value) \
+{ \
+	int i; \
+	for(i=0; i< (sizeof(A_##symbol##_used) / sizeof(__u32)); i++) { \
+		__u32 val = bS_to_cpu((script)[A_##symbol##_used[i]]); \
+		val &= 0xffff0000; \
+		val |= ((value) & 0xffff); \
+		(script)[A_##symbol##_used[i]] = bS_to_host(val); \
+		dma_cache_sync(&(script)[A_##symbol##_used[i]], 4, DMA_TO_DEVICE); \
+		DEBUG((" script, patching short field %s at %d to 0x%x\n", \
+		       #symbol, A_##symbol##_used[i], val)); \
+	} \
+}
+
+
+static inline __u8
+NCR_700_mem_readb(struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	return readb(host->base + (reg^bE));
+}
+
+static inline __u32
+NCR_700_mem_readl(struct Scsi_Host *host, __u32 reg)
+{
+	__u32 value = __raw_readl(host->base + reg);
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+#if 1
+	/* sanity check the register */
+	if((reg & 0x3) != 0)
+		BUG();
+#endif
+
+	return bS_to_cpu(value);
+}
+
+static inline void
+NCR_700_mem_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	writeb(value, host->base + (reg^bE));
+}
+
+static inline void
+NCR_700_mem_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+	/* sanity check the register */
+	if((reg & 0x3) != 0)
+		BUG();
+#endif
+
+	__raw_writel(bS_to_host(value), host->base + reg);
+}
+
+static inline __u8
+NCR_700_io_readb(struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	return inb(host->base + (reg^bE));
+}
+
+static inline __u32
+NCR_700_io_readl(struct Scsi_Host *host, __u32 reg)
+{
+	__u32 value = inl(host->base + reg);
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+	/* sanity check the register */
+	if((reg & 0x3) != 0)
+		BUG();
+#endif
+
+	return bS_to_cpu(value);
+}
+
+static inline void
+NCR_700_io_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	outb(value, host->base + (reg^bE));
+}
+
+static inline void
+NCR_700_io_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+#if 1
+	/* sanity check the register */
+	if((reg & 0x3) != 0)
+		BUG();
+#endif
+
+	outl(bS_to_host(value), host->base + reg);
+}
+
+#ifdef CONFIG_53C700_BOTH_MAPPED
+
+static inline __u8
+NCR_700_readb(struct Scsi_Host *host, __u32 reg)
+{
+	__u8 val;
+
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	if(hostdata->mem_mapped)
+		val = NCR_700_mem_readb(host, reg);
+	else
+		val = NCR_700_io_readb(host, reg);
+
+	return val;
+}
+
+static inline __u32
+NCR_700_readl(struct Scsi_Host *host, __u32 reg)
+{
+	__u32 val;
+
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	if(hostdata->mem_mapped)
+		val = NCR_700_mem_readl(host, reg);
+	else
+		val = NCR_700_io_readl(host, reg);
+
+	return val;
+}
+
+static inline void
+NCR_700_writeb(__u8 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	if(hostdata->mem_mapped)
+		NCR_700_mem_writeb(value, host, reg);
+	else
+		NCR_700_io_writeb(value, host, reg);
+}
+
+static inline void
+NCR_700_writel(__u32 value, struct Scsi_Host *host, __u32 reg)
+{
+	const struct NCR_700_Host_Parameters *hostdata __attribute__((unused))
+		= (struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	if(hostdata->mem_mapped)
+		NCR_700_mem_writel(value, host, reg);
+	else
+		NCR_700_io_writel(value, host, reg);
+}
+
+static inline void
+NCR_700_set_mem_mapped(struct NCR_700_Host_Parameters *hostdata)
+{
+	hostdata->mem_mapped = 1;
+}
+
+static inline void
+NCR_700_set_io_mapped(struct NCR_700_Host_Parameters *hostdata)
+{
+	hostdata->mem_mapped = 0;
+}
+
+
+#elif defined(CONFIG_53C700_IO_MAPPED)
+
+#define NCR_700_readb NCR_700_io_readb
+#define NCR_700_readl NCR_700_io_readl
+#define NCR_700_writeb NCR_700_io_writeb
+#define NCR_700_writel NCR_700_io_writel
+
+#define NCR_700_set_io_mapped(x)
+#define NCR_700_set_mem_mapped(x)	error I/O mapped only
+
+#elif defined(CONFIG_53C700_MEM_MAPPED)
+
+#define NCR_700_readb NCR_700_mem_readb
+#define NCR_700_readl NCR_700_mem_readl
+#define NCR_700_writeb NCR_700_mem_writeb
+#define NCR_700_writel NCR_700_mem_writel
+
+#define NCR_700_set_io_mapped(x)	error MEM mapped only
+#define NCR_700_set_mem_mapped(x)
+
+#else
+#error neither CONFIG_53C700_MEM_MAPPED nor CONFIG_53C700_IO_MAPPED is set
+#endif
+
+#endif
diff --git a/drivers/scsi/53c700.scr b/drivers/scsi/53c700.scr
new file mode 100644
index 0000000..a064a09
--- /dev/null
+++ b/drivers/scsi/53c700.scr
@@ -0,0 +1,411 @@
+; Script for the NCR (or symbios) 53c700 and 53c700-66 chip
+;
+; Copyright (C) 2001 James.Bottomley@HansenPartnership.com
+;;-----------------------------------------------------------------------------
+;;  
+;;  This program is free software; you can redistribute it and/or modify
+;;  it under the terms of the GNU General Public License as published by
+;;  the Free Software Foundation; either version 2 of the License, or
+;;  (at your option) any later version.
+;;
+;;  This program is distributed in the hope that it will be useful,
+;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;  GNU General Public License for more details.
+;;
+;;  You should have received a copy of the GNU General Public License
+;;  along with this program; if not, write to the Free Software
+;;  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;
+;;-----------------------------------------------------------------------------
+;
+; This script is designed to be modified for the particular command in
+; operation.  The particular variables pertaining to the commands are:
+;
+ABSOLUTE	Device_ID = 0		; ID of target for command
+ABSOLUTE	MessageCount = 0	; Number of bytes in message
+ABSOLUTE	MessageLocation = 0	; Addr of message
+ABSOLUTE	CommandCount = 0	; Number of bytes in command
+ABSOLUTE	CommandAddress = 0	; Addr of Command
+ABSOLUTE	StatusAddress = 0	; Addr to receive status return
+ABSOLUTE	ReceiveMsgAddress = 0	; Addr to receive msg
+;
+; This is the magic component for handling scatter-gather.  Each of the
+; SG components is preceeded by a script fragment which moves the
+; necessary amount of data and jumps to the next SG segment.  The final
+; SG segment jumps back to .  However, this address is the first SG script
+; segment.
+;
+ABSOLUTE	SGScriptStartAddress = 0
+
+; The following represent status interrupts we use 3 hex digits for
+; this: 0xPRS where 
+
+; P:
+ABSOLUTE	AFTER_SELECTION 	= 0x100
+ABSOLUTE	BEFORE_CMD 		= 0x200
+ABSOLUTE	AFTER_CMD 		= 0x300
+ABSOLUTE	AFTER_STATUS 		= 0x400
+ABSOLUTE	AFTER_DATA_IN		= 0x500
+ABSOLUTE	AFTER_DATA_OUT		= 0x600
+ABSOLUTE	DURING_DATA_IN		= 0x700
+
+; R:
+ABSOLUTE	NOT_MSG_OUT 		= 0x10
+ABSOLUTE	UNEXPECTED_PHASE 	= 0x20
+ABSOLUTE	NOT_MSG_IN 		= 0x30
+ABSOLUTE	UNEXPECTED_MSG		= 0x40
+ABSOLUTE	MSG_IN			= 0x50
+ABSOLUTE	SDTR_MSG_R		= 0x60
+ABSOLUTE	REJECT_MSG_R		= 0x70
+ABSOLUTE	DISCONNECT		= 0x80
+ABSOLUTE	MSG_OUT			= 0x90
+ABSOLUTE	WDTR_MSG_R		= 0xA0
+
+; S:
+ABSOLUTE	GOOD_STATUS 		= 0x1
+
+; Combinations, since the script assembler can't process |
+ABSOLUTE	NOT_MSG_OUT_AFTER_SELECTION = 0x110
+ABSOLUTE	UNEXPECTED_PHASE_BEFORE_CMD = 0x220
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_CMD = 0x320
+ABSOLUTE	NOT_MSG_IN_AFTER_STATUS = 0x430
+ABSOLUTE	GOOD_STATUS_AFTER_STATUS = 0x401
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_DATA_IN = 0x520
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_DATA_OUT = 0x620
+ABSOLUTE	UNEXPECTED_MSG_BEFORE_CMD = 0x240
+ABSOLUTE	MSG_IN_BEFORE_CMD = 0x250
+ABSOLUTE	MSG_IN_AFTER_CMD = 0x350
+ABSOLUTE	SDTR_MSG_BEFORE_CMD = 0x260
+ABSOLUTE	REJECT_MSG_BEFORE_CMD = 0x270
+ABSOLUTE	DISCONNECT_AFTER_CMD = 0x380
+ABSOLUTE	SDTR_MSG_AFTER_CMD = 0x360
+ABSOLUTE	WDTR_MSG_AFTER_CMD = 0x3A0
+ABSOLUTE	MSG_IN_AFTER_STATUS = 0x440
+ABSOLUTE	DISCONNECT_AFTER_DATA = 0x580
+ABSOLUTE	MSG_IN_AFTER_DATA_IN = 0x550
+ABSOLUTE	MSG_IN_AFTER_DATA_OUT = 0x650
+ABSOLUTE	MSG_OUT_AFTER_DATA_IN = 0x590
+ABSOLUTE	DATA_IN_AFTER_DATA_IN = 0x5a0
+ABSOLUTE	MSG_IN_DURING_DATA_IN = 0x750
+ABSOLUTE	DISCONNECT_DURING_DATA = 0x780
+
+;
+; Other interrupt conditions
+; 
+ABSOLUTE	RESELECTED_DURING_SELECTION = 0x1000
+ABSOLUTE	COMPLETED_SELECTION_AS_TARGET = 0x1001
+ABSOLUTE	RESELECTION_IDENTIFIED = 0x1003
+;
+; Fatal interrupt conditions.  If you add to this, also add to the
+; array of corresponding messages
+;
+ABSOLUTE	FATAL = 0x2000
+ABSOLUTE	FATAL_UNEXPECTED_RESELECTION_MSG = 0x2000
+ABSOLUTE	FATAL_SEND_MSG = 0x2001
+ABSOLUTE	FATAL_NOT_MSG_IN_AFTER_SELECTION = 0x2002
+ABSOLUTE	FATAL_ILLEGAL_MSG_LENGTH = 0x2003
+
+ABSOLUTE	DEBUG_INTERRUPT	= 0x3000
+ABSOLUTE	DEBUG_INTERRUPT1 = 0x3001
+ABSOLUTE	DEBUG_INTERRUPT2 = 0x3002
+ABSOLUTE	DEBUG_INTERRUPT3 = 0x3003
+ABSOLUTE	DEBUG_INTERRUPT4 = 0x3004
+ABSOLUTE	DEBUG_INTERRUPT5 = 0x3005
+ABSOLUTE	DEBUG_INTERRUPT6 = 0x3006
+
+
+;
+; SCSI Messages we interpret in the script
+;
+ABSOLUTE	COMMAND_COMPLETE_MSG	= 0x00
+ABSOLUTE	EXTENDED_MSG		= 0x01
+ABSOLUTE	SDTR_MSG		= 0x01
+ABSOLUTE	SAVE_DATA_PTRS_MSG	= 0x02
+ABSOLUTE	RESTORE_DATA_PTRS_MSG	= 0x03
+ABSOLUTE	WDTR_MSG		= 0x03
+ABSOLUTE	DISCONNECT_MSG		= 0x04
+ABSOLUTE	REJECT_MSG		= 0x07
+ABSOLUTE	PARITY_ERROR_MSG	= 0x09
+ABSOLUTE	SIMPLE_TAG_MSG		= 0x20
+ABSOLUTE	IDENTIFY_MSG		= 0x80
+ABSOLUTE	IDENTIFY_MSG_MASK	= 0x7F
+ABSOLUTE	TWO_BYTE_MSG		= 0x20
+ABSOLUTE	TWO_BYTE_MSG_MASK	= 0x0F
+
+; This is where the script begins
+
+ENTRY	StartUp
+
+StartUp:
+	SELECT	ATN Device_ID, Reselect
+	JUMP	Finish, WHEN STATUS
+	JUMP	SendIdentifyMsg, IF MSG_OUT
+	INT	NOT_MSG_OUT_AFTER_SELECTION
+
+Reselect:
+	WAIT	RESELECT SelectedAsTarget
+	INT	RESELECTED_DURING_SELECTION, WHEN MSG_IN
+	INT	FATAL_NOT_MSG_IN_AFTER_SELECTION
+
+	ENTRY	GetReselectionData
+GetReselectionData:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	INT	RESELECTION_IDENTIFIED
+
+	ENTRY	GetReselectionWithTag
+GetReselectionWithTag:
+	MOVE	3, ReceiveMsgAddress, WHEN MSG_IN
+	INT	RESELECTION_IDENTIFIED
+	
+	ENTRY	SelectedAsTarget
+SelectedAsTarget:
+; Basically tell the selecting device that there's nothing here
+	SET	TARGET
+	DISCONNECT
+	CLEAR	TARGET
+	INT	COMPLETED_SELECTION_AS_TARGET
+;
+; These are the messaging entries
+;
+; Send a message.  Message count should be correctly patched
+	ENTRY	SendMessage
+SendMessage:
+	MOVE	MessageCount, MessageLocation, WHEN MSG_OUT
+ResumeSendMessage:
+	RETURN,	WHEN NOT MSG_OUT
+	INT	FATAL_SEND_MSG
+
+	ENTRY	SendMessagePhaseMismatch
+SendMessagePhaseMismatch:
+	CLEAR	ACK
+	JUMP	ResumeSendMessage
+;
+; Receive a message.  Need to identify the message to
+; receive it correctly
+	ENTRY	ReceiveMessage
+ReceiveMessage:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+;
+; Use this entry if we've just tried to look at the first byte
+; of the message and want to process it further
+ProcessReceiveMessage:
+	JUMP	ReceiveExtendedMessage, IF EXTENDED_MSG
+	RETURN,	IF NOT TWO_BYTE_MSG, AND MASK TWO_BYTE_MSG_MASK
+	CLEAR	ACK
+	MOVE	1, ReceiveMsgAddress + 1, WHEN MSG_IN
+	RETURN
+ReceiveExtendedMessage:
+	CLEAR	ACK
+	MOVE	1, ReceiveMsgAddress + 1, WHEN MSG_IN
+	JUMP	Receive1Byte, IF 0x01
+	JUMP	Receive2Byte, IF 0x02
+	JUMP	Receive3Byte, IF 0x03
+	JUMP	Receive4Byte, IF 0x04
+	JUMP	Receive5Byte, IF 0x05
+	INT	FATAL_ILLEGAL_MSG_LENGTH
+Receive1Byte:
+	CLEAR	ACK
+	MOVE	1, ReceiveMsgAddress + 2, WHEN MSG_IN
+	RETURN
+Receive2Byte:
+	CLEAR	ACK
+	MOVE	2, ReceiveMsgAddress + 2, WHEN MSG_IN
+	RETURN
+Receive3Byte:
+	CLEAR	ACK
+	MOVE	3, ReceiveMsgAddress + 2, WHEN MSG_IN
+	RETURN
+Receive4Byte:
+	CLEAR	ACK
+	MOVE	4, ReceiveMsgAddress + 2, WHEN MSG_IN
+	RETURN
+Receive5Byte:
+	CLEAR	ACK
+	MOVE	5, ReceiveMsgAddress + 2, WHEN MSG_IN
+	RETURN
+;
+; Come here from the message processor to ignore the message
+;
+	ENTRY	IgnoreMessage
+IgnoreMessage:
+	CLEAR	ACK
+	RETURN
+;
+; Come here to send a reply to a message
+;
+	ENTRY	SendMessageWithATN
+SendMessageWithATN:
+	SET	ATN
+	CLEAR	ACK
+	JUMP	SendMessage
+
+SendIdentifyMsg:
+	CALL	SendMessage
+	CLEAR	ATN
+
+IgnoreMsgBeforeCommand:
+	CLEAR	ACK
+	ENTRY	SendCommand
+SendCommand:
+	JUMP	Finish, WHEN STATUS
+	JUMP	MsgInBeforeCommand, IF MSG_IN
+	INT	UNEXPECTED_PHASE_BEFORE_CMD, IF NOT CMD
+	MOVE	CommandCount, CommandAddress, WHEN CMD
+ResumeSendCommand:
+	JUMP	Finish, WHEN STATUS
+	JUMP	MsgInAfterCmd, IF MSG_IN
+	JUMP	DataIn, IF DATA_IN
+	JUMP	DataOut, IF DATA_OUT
+	INT	UNEXPECTED_PHASE_AFTER_CMD
+
+IgnoreMsgDuringData:
+	CLEAR	ACK
+	; fall through to MsgInDuringData
+
+Entry MsgInDuringData
+MsgInDuringData:
+;
+; Could be we have nothing more to transfer
+;
+	JUMP	Finish, WHEN STATUS
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	DisconnectDuringDataIn, IF DISCONNECT_MSG
+	JUMP	IgnoreMsgDuringData, IF SAVE_DATA_PTRS_MSG
+	JUMP	IgnoreMsgDuringData, IF RESTORE_DATA_PTRS_MSG
+	INT	MSG_IN_DURING_DATA_IN
+
+MsgInAfterCmd:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	DisconnectAfterCmd, IF DISCONNECT_MSG
+	JUMP	IgnoreMsgInAfterCmd, IF SAVE_DATA_PTRS_MSG
+	JUMP	IgnoreMsgInAfterCmd, IF RESTORE_DATA_PTRS_MSG
+	CALL	ProcessReceiveMessage
+	INT	MSG_IN_AFTER_CMD
+	CLEAR	ACK
+	JUMP	ResumeSendCommand
+
+IgnoreMsgInAfterCmd:
+	CLEAR	ACK
+	JUMP	ResumeSendCommand
+
+DisconnectAfterCmd:
+	CLEAR	ACK
+	WAIT	DISCONNECT
+	ENTRY	Disconnect1
+Disconnect1:
+	INT	DISCONNECT_AFTER_CMD
+	ENTRY	Disconnect2
+Disconnect2:
+; We return here after a reselection
+	CLEAR	ACK
+	JUMP	ResumeSendCommand
+
+MsgInBeforeCommand:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	IgnoreMsgBeforeCommand, IF SAVE_DATA_PTRS_MSG
+	JUMP	IgnoreMsgBeforeCommand, IF RESTORE_DATA_PTRS_MSG
+	CALL	ProcessReceiveMessage
+	INT	MSG_IN_BEFORE_CMD
+	CLEAR	ACK
+	JUMP	SendCommand
+
+DataIn:
+	CALL	SGScriptStartAddress
+ResumeDataIn:
+	JUMP	Finish, WHEN STATUS
+	JUMP	MsgInAfterDataIn, IF MSG_IN
+	JUMP	DataInAfterDataIn, if DATA_IN
+	INT	MSG_OUT_AFTER_DATA_IN, if MSG_OUT
+	INT	UNEXPECTED_PHASE_AFTER_DATA_IN
+
+DataInAfterDataIn:
+	INT	DATA_IN_AFTER_DATA_IN
+	JUMP	ResumeDataIn
+
+DataOut:
+	CALL	SGScriptStartAddress
+ResumeDataOut:
+	JUMP	Finish, WHEN STATUS
+	JUMP	MsgInAfterDataOut, IF MSG_IN
+	INT	UNEXPECTED_PHASE_AFTER_DATA_OUT
+
+MsgInAfterDataIn:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	DisconnectAfterDataIn, IF DISCONNECT_MSG
+	JUMP	IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+	JUMP	IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+	CALL	ProcessReceiveMessage
+	INT	MSG_IN_AFTER_DATA_IN
+	CLEAR	ACK
+	JUMP	ResumeDataIn
+
+DisconnectDuringDataIn:
+	CLEAR	ACK
+	WAIT	DISCONNECT
+	ENTRY	Disconnect3
+Disconnect3:
+	INT	DISCONNECT_DURING_DATA
+	ENTRY	Disconnect4
+Disconnect4:
+; we return here after a reselection
+	CLEAR	ACK
+	JUMP	ResumeSendCommand
+
+
+DisconnectAfterDataIn:
+	CLEAR	ACK
+	WAIT	DISCONNECT
+	ENTRY	Disconnect5
+Disconnect5:
+	INT	DISCONNECT_AFTER_DATA
+	ENTRY	Disconnect6
+Disconnect6:
+; we return here after a reselection
+	CLEAR	ACK
+	JUMP	ResumeDataIn
+
+MsgInAfterDataOut:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	DisconnectAfterDataOut, if DISCONNECT_MSG
+	JUMP	IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+	JUMP	IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+	CALL	ProcessReceiveMessage
+	INT	MSG_IN_AFTER_DATA_OUT
+	CLEAR	ACK
+	JUMP	ResumeDataOut
+
+IgnoreMsgAfterData:
+	CLEAR	ACK
+; Data in and out do the same thing on resume, so pick one
+	JUMP	ResumeDataIn
+
+DisconnectAfterDataOut:
+	CLEAR	ACK
+	WAIT	DISCONNECT
+	ENTRY	Disconnect7
+Disconnect7:
+	INT	DISCONNECT_AFTER_DATA
+	ENTRY	Disconnect8
+Disconnect8:
+; we return here after a reselection
+	CLEAR	ACK
+	JUMP	ResumeDataOut
+
+Finish:
+	MOVE	1, StatusAddress, WHEN STATUS
+	INT	NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+	JUMP	FinishCommandComplete, IF COMMAND_COMPLETE_MSG
+	CALL	ProcessReceiveMessage
+	INT	MSG_IN_AFTER_STATUS
+	ENTRY	FinishCommandComplete
+FinishCommandComplete:
+	CLEAR	ACK
+	WAIT	DISCONNECT
+	ENTRY	Finish1
+Finish1:
+	INT	GOOD_STATUS_AFTER_STATUS
+	ENTRY	Finish2
+Finish2:
+
diff --git a/drivers/scsi/53c700_d.h_shipped b/drivers/scsi/53c700_d.h_shipped
new file mode 100644
index 0000000..0b42a51
--- /dev/null
+++ b/drivers/scsi/53c700_d.h_shipped
@@ -0,0 +1,1329 @@
+/* DO NOT EDIT - Generated automatically by script_asm.pl */
+static u32 SCRIPT[] = {
+/*
+; Script for the NCR (or symbios) 53c700 and 53c700-66 chip
+;
+; Copyright (C) 2001 James.Bottomley@HansenPartnership.com
+;;-----------------------------------------------------------------------------
+;;  
+;;  This program is free software; you can redistribute it and/or modify
+;;  it under the terms of the GNU General Public License as published by
+;;  the Free Software Foundation; either version 2 of the License, or
+;;  (at your option) any later version.
+;;
+;;  This program is distributed in the hope that it will be useful,
+;;  but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;  GNU General Public License for more details.
+;;
+;;  You should have received a copy of the GNU General Public License
+;;  along with this program; if not, write to the Free Software
+;;  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+;;
+;;-----------------------------------------------------------------------------
+;
+; This script is designed to be modified for the particular command in
+; operation.  The particular variables pertaining to the commands are:
+;
+ABSOLUTE	Device_ID = 0		; ID of target for command
+ABSOLUTE	MessageCount = 0	; Number of bytes in message
+ABSOLUTE	MessageLocation = 0	; Addr of message
+ABSOLUTE	CommandCount = 0	; Number of bytes in command
+ABSOLUTE	CommandAddress = 0	; Addr of Command
+ABSOLUTE	StatusAddress = 0	; Addr to receive status return
+ABSOLUTE	ReceiveMsgAddress = 0	; Addr to receive msg
+;
+; This is the magic component for handling scatter-gather.  Each of the
+; SG components is preceeded by a script fragment which moves the
+; necessary amount of data and jumps to the next SG segment.  The final
+; SG segment jumps back to .  However, this address is the first SG script
+; segment.
+;
+ABSOLUTE	SGScriptStartAddress = 0
+
+; The following represent status interrupts we use 3 hex digits for
+; this: 0xPRS where 
+
+; P:
+ABSOLUTE	AFTER_SELECTION 	= 0x100
+ABSOLUTE	BEFORE_CMD 		= 0x200
+ABSOLUTE	AFTER_CMD 		= 0x300
+ABSOLUTE	AFTER_STATUS 		= 0x400
+ABSOLUTE	AFTER_DATA_IN		= 0x500
+ABSOLUTE	AFTER_DATA_OUT		= 0x600
+ABSOLUTE	DURING_DATA_IN		= 0x700
+
+; R:
+ABSOLUTE	NOT_MSG_OUT 		= 0x10
+ABSOLUTE	UNEXPECTED_PHASE 	= 0x20
+ABSOLUTE	NOT_MSG_IN 		= 0x30
+ABSOLUTE	UNEXPECTED_MSG		= 0x40
+ABSOLUTE	MSG_IN			= 0x50
+ABSOLUTE	SDTR_MSG_R		= 0x60
+ABSOLUTE	REJECT_MSG_R		= 0x70
+ABSOLUTE	DISCONNECT		= 0x80
+ABSOLUTE	MSG_OUT			= 0x90
+ABSOLUTE	WDTR_MSG_R		= 0xA0
+
+; S:
+ABSOLUTE	GOOD_STATUS 		= 0x1
+
+; Combinations, since the script assembler can't process |
+ABSOLUTE	NOT_MSG_OUT_AFTER_SELECTION = 0x110
+ABSOLUTE	UNEXPECTED_PHASE_BEFORE_CMD = 0x220
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_CMD = 0x320
+ABSOLUTE	NOT_MSG_IN_AFTER_STATUS = 0x430
+ABSOLUTE	GOOD_STATUS_AFTER_STATUS = 0x401
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_DATA_IN = 0x520
+ABSOLUTE	UNEXPECTED_PHASE_AFTER_DATA_OUT = 0x620
+ABSOLUTE	UNEXPECTED_MSG_BEFORE_CMD = 0x240
+ABSOLUTE	MSG_IN_BEFORE_CMD = 0x250
+ABSOLUTE	MSG_IN_AFTER_CMD = 0x350
+ABSOLUTE	SDTR_MSG_BEFORE_CMD = 0x260
+ABSOLUTE	REJECT_MSG_BEFORE_CMD = 0x270
+ABSOLUTE	DISCONNECT_AFTER_CMD = 0x380
+ABSOLUTE	SDTR_MSG_AFTER_CMD = 0x360
+ABSOLUTE	WDTR_MSG_AFTER_CMD = 0x3A0
+ABSOLUTE	MSG_IN_AFTER_STATUS = 0x440
+ABSOLUTE	DISCONNECT_AFTER_DATA = 0x580
+ABSOLUTE	MSG_IN_AFTER_DATA_IN = 0x550
+ABSOLUTE	MSG_IN_AFTER_DATA_OUT = 0x650
+ABSOLUTE	MSG_OUT_AFTER_DATA_IN = 0x590
+ABSOLUTE	DATA_IN_AFTER_DATA_IN = 0x5a0
+ABSOLUTE	MSG_IN_DURING_DATA_IN = 0x750
+ABSOLUTE	DISCONNECT_DURING_DATA = 0x780
+
+;
+; Other interrupt conditions
+; 
+ABSOLUTE	RESELECTED_DURING_SELECTION = 0x1000
+ABSOLUTE	COMPLETED_SELECTION_AS_TARGET = 0x1001
+ABSOLUTE	RESELECTION_IDENTIFIED = 0x1003
+;
+; Fatal interrupt conditions.  If you add to this, also add to the
+; array of corresponding messages
+;
+ABSOLUTE	FATAL = 0x2000
+ABSOLUTE	FATAL_UNEXPECTED_RESELECTION_MSG = 0x2000
+ABSOLUTE	FATAL_SEND_MSG = 0x2001
+ABSOLUTE	FATAL_NOT_MSG_IN_AFTER_SELECTION = 0x2002
+ABSOLUTE	FATAL_ILLEGAL_MSG_LENGTH = 0x2003
+
+ABSOLUTE	DEBUG_INTERRUPT	= 0x3000
+ABSOLUTE	DEBUG_INTERRUPT1 = 0x3001
+ABSOLUTE	DEBUG_INTERRUPT2 = 0x3002
+ABSOLUTE	DEBUG_INTERRUPT3 = 0x3003
+ABSOLUTE	DEBUG_INTERRUPT4 = 0x3004
+ABSOLUTE	DEBUG_INTERRUPT5 = 0x3005
+ABSOLUTE	DEBUG_INTERRUPT6 = 0x3006
+
+
+;
+; SCSI Messages we interpret in the script
+;
+ABSOLUTE	COMMAND_COMPLETE_MSG	= 0x00
+ABSOLUTE	EXTENDED_MSG		= 0x01
+ABSOLUTE	SDTR_MSG		= 0x01
+ABSOLUTE	SAVE_DATA_PTRS_MSG	= 0x02
+ABSOLUTE	RESTORE_DATA_PTRS_MSG	= 0x03
+ABSOLUTE	WDTR_MSG		= 0x03
+ABSOLUTE	DISCONNECT_MSG		= 0x04
+ABSOLUTE	REJECT_MSG		= 0x07
+ABSOLUTE	PARITY_ERROR_MSG	= 0x09
+ABSOLUTE	SIMPLE_TAG_MSG		= 0x20
+ABSOLUTE	IDENTIFY_MSG		= 0x80
+ABSOLUTE	IDENTIFY_MSG_MASK	= 0x7F
+ABSOLUTE	TWO_BYTE_MSG		= 0x20
+ABSOLUTE	TWO_BYTE_MSG_MASK	= 0x0F
+
+; This is where the script begins
+
+ENTRY	StartUp
+
+StartUp:
+	SELECT	ATN Device_ID, Reselect
+
+at 0x00000000 : */	0x41000000,0x00000020,
+/*
+	JUMP	Finish, WHEN STATUS
+
+at 0x00000002 : */	0x830b0000,0x00000460,
+/*
+	JUMP	SendIdentifyMsg, IF MSG_OUT
+
+at 0x00000004 : */	0x860a0000,0x000001b0,
+/*
+	INT	NOT_MSG_OUT_AFTER_SELECTION
+
+at 0x00000006 : */	0x98080000,0x00000110,
+/*
+
+Reselect:
+	WAIT	RESELECT SelectedAsTarget
+
+at 0x00000008 : */	0x50000000,0x00000058,
+/*
+	INT	RESELECTED_DURING_SELECTION, WHEN MSG_IN
+
+at 0x0000000a : */	0x9f0b0000,0x00001000,
+/*
+	INT	FATAL_NOT_MSG_IN_AFTER_SELECTION
+
+at 0x0000000c : */	0x98080000,0x00002002,
+/*
+
+	ENTRY	GetReselectionData
+GetReselectionData:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x0000000e : */	0x0f000001,0x00000000,
+/*
+	INT	RESELECTION_IDENTIFIED
+
+at 0x00000010 : */	0x98080000,0x00001003,
+/*
+
+	ENTRY	GetReselectionWithTag
+GetReselectionWithTag:
+	MOVE	3, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x00000012 : */	0x0f000003,0x00000000,
+/*
+	INT	RESELECTION_IDENTIFIED
+
+at 0x00000014 : */	0x98080000,0x00001003,
+/*
+	
+	ENTRY	SelectedAsTarget
+SelectedAsTarget:
+; Basically tell the selecting device that there's nothing here
+	SET	TARGET
+
+at 0x00000016 : */	0x58000200,0x00000000,
+/*
+	DISCONNECT
+
+at 0x00000018 : */	0x48000000,0x00000000,
+/*
+	CLEAR	TARGET
+
+at 0x0000001a : */	0x60000200,0x00000000,
+/*
+	INT	COMPLETED_SELECTION_AS_TARGET
+
+at 0x0000001c : */	0x98080000,0x00001001,
+/*
+;
+; These are the messaging entries
+;
+; Send a message.  Message count should be correctly patched
+	ENTRY	SendMessage
+SendMessage:
+	MOVE	MessageCount, MessageLocation, WHEN MSG_OUT
+
+at 0x0000001e : */	0x0e000000,0x00000000,
+/*
+ResumeSendMessage:
+	RETURN,	WHEN NOT MSG_OUT
+
+at 0x00000020 : */	0x96030000,0x00000000,
+/*
+	INT	FATAL_SEND_MSG
+
+at 0x00000022 : */	0x98080000,0x00002001,
+/*
+
+	ENTRY	SendMessagePhaseMismatch
+SendMessagePhaseMismatch:
+	CLEAR	ACK
+
+at 0x00000024 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeSendMessage
+
+at 0x00000026 : */	0x80080000,0x00000080,
+/*
+;
+; Receive a message.  Need to identify the message to
+; receive it correctly
+	ENTRY	ReceiveMessage
+ReceiveMessage:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x00000028 : */	0x0f000001,0x00000000,
+/*
+;
+; Use this entry if we've just tried to look at the first byte
+; of the message and want to process it further
+ProcessReceiveMessage:
+	JUMP	ReceiveExtendedMessage, IF EXTENDED_MSG
+
+at 0x0000002a : */	0x800c0001,0x000000d0,
+/*
+	RETURN,	IF NOT TWO_BYTE_MSG, AND MASK TWO_BYTE_MSG_MASK
+
+at 0x0000002c : */	0x90040f20,0x00000000,
+/*
+	CLEAR	ACK
+
+at 0x0000002e : */	0x60000040,0x00000000,
+/*
+	MOVE	1, ReceiveMsgAddress + 1, WHEN MSG_IN
+
+at 0x00000030 : */	0x0f000001,0x00000001,
+/*
+	RETURN
+
+at 0x00000032 : */	0x90080000,0x00000000,
+/*
+ReceiveExtendedMessage:
+	CLEAR	ACK
+
+at 0x00000034 : */	0x60000040,0x00000000,
+/*
+	MOVE	1, ReceiveMsgAddress + 1, WHEN MSG_IN
+
+at 0x00000036 : */	0x0f000001,0x00000001,
+/*
+	JUMP	Receive1Byte, IF 0x01
+
+at 0x00000038 : */	0x800c0001,0x00000110,
+/*
+	JUMP	Receive2Byte, IF 0x02
+
+at 0x0000003a : */	0x800c0002,0x00000128,
+/*
+	JUMP	Receive3Byte, IF 0x03
+
+at 0x0000003c : */	0x800c0003,0x00000140,
+/*
+	JUMP	Receive4Byte, IF 0x04
+
+at 0x0000003e : */	0x800c0004,0x00000158,
+/*
+	JUMP	Receive5Byte, IF 0x05
+
+at 0x00000040 : */	0x800c0005,0x00000170,
+/*
+	INT	FATAL_ILLEGAL_MSG_LENGTH
+
+at 0x00000042 : */	0x98080000,0x00002003,
+/*
+Receive1Byte:
+	CLEAR	ACK
+
+at 0x00000044 : */	0x60000040,0x00000000,
+/*
+	MOVE	1, ReceiveMsgAddress + 2, WHEN MSG_IN
+
+at 0x00000046 : */	0x0f000001,0x00000002,
+/*
+	RETURN
+
+at 0x00000048 : */	0x90080000,0x00000000,
+/*
+Receive2Byte:
+	CLEAR	ACK
+
+at 0x0000004a : */	0x60000040,0x00000000,
+/*
+	MOVE	2, ReceiveMsgAddress + 2, WHEN MSG_IN
+
+at 0x0000004c : */	0x0f000002,0x00000002,
+/*
+	RETURN
+
+at 0x0000004e : */	0x90080000,0x00000000,
+/*
+Receive3Byte:
+	CLEAR	ACK
+
+at 0x00000050 : */	0x60000040,0x00000000,
+/*
+	MOVE	3, ReceiveMsgAddress + 2, WHEN MSG_IN
+
+at 0x00000052 : */	0x0f000003,0x00000002,
+/*
+	RETURN
+
+at 0x00000054 : */	0x90080000,0x00000000,
+/*
+Receive4Byte:
+	CLEAR	ACK
+
+at 0x00000056 : */	0x60000040,0x00000000,
+/*
+	MOVE	4, ReceiveMsgAddress + 2, WHEN MSG_IN
+
+at 0x00000058 : */	0x0f000004,0x00000002,
+/*
+	RETURN
+
+at 0x0000005a : */	0x90080000,0x00000000,
+/*
+Receive5Byte:
+	CLEAR	ACK
+
+at 0x0000005c : */	0x60000040,0x00000000,
+/*
+	MOVE	5, ReceiveMsgAddress + 2, WHEN MSG_IN
+
+at 0x0000005e : */	0x0f000005,0x00000002,
+/*
+	RETURN
+
+at 0x00000060 : */	0x90080000,0x00000000,
+/*
+;
+; Come here from the message processor to ignore the message
+;
+	ENTRY	IgnoreMessage
+IgnoreMessage:
+	CLEAR	ACK
+
+at 0x00000062 : */	0x60000040,0x00000000,
+/*
+	RETURN
+
+at 0x00000064 : */	0x90080000,0x00000000,
+/*
+;
+; Come here to send a reply to a message
+;
+	ENTRY	SendMessageWithATN
+SendMessageWithATN:
+	SET	ATN
+
+at 0x00000066 : */	0x58000008,0x00000000,
+/*
+	CLEAR	ACK
+
+at 0x00000068 : */	0x60000040,0x00000000,
+/*
+	JUMP	SendMessage
+
+at 0x0000006a : */	0x80080000,0x00000078,
+/*
+
+SendIdentifyMsg:
+	CALL	SendMessage
+
+at 0x0000006c : */	0x88080000,0x00000078,
+/*
+	CLEAR	ATN
+
+at 0x0000006e : */	0x60000008,0x00000000,
+/*
+
+IgnoreMsgBeforeCommand:
+	CLEAR	ACK
+
+at 0x00000070 : */	0x60000040,0x00000000,
+/*
+	ENTRY	SendCommand
+SendCommand:
+	JUMP	Finish, WHEN STATUS
+
+at 0x00000072 : */	0x830b0000,0x00000460,
+/*
+	JUMP	MsgInBeforeCommand, IF MSG_IN
+
+at 0x00000074 : */	0x870a0000,0x000002c0,
+/*
+	INT	UNEXPECTED_PHASE_BEFORE_CMD, IF NOT CMD
+
+at 0x00000076 : */	0x9a020000,0x00000220,
+/*
+	MOVE	CommandCount, CommandAddress, WHEN CMD
+
+at 0x00000078 : */	0x0a000000,0x00000000,
+/*
+ResumeSendCommand:
+	JUMP	Finish, WHEN STATUS
+
+at 0x0000007a : */	0x830b0000,0x00000460,
+/*
+	JUMP	MsgInAfterCmd, IF MSG_IN
+
+at 0x0000007c : */	0x870a0000,0x00000248,
+/*
+	JUMP	DataIn, IF DATA_IN
+
+at 0x0000007e : */	0x810a0000,0x000002f8,
+/*
+	JUMP	DataOut, IF DATA_OUT
+
+at 0x00000080 : */	0x800a0000,0x00000338,
+/*
+	INT	UNEXPECTED_PHASE_AFTER_CMD
+
+at 0x00000082 : */	0x98080000,0x00000320,
+/*
+
+IgnoreMsgDuringData:
+	CLEAR	ACK
+
+at 0x00000084 : */	0x60000040,0x00000000,
+/*
+	; fall through to MsgInDuringData
+
+Entry MsgInDuringData
+MsgInDuringData:
+;
+; Could be we have nothing more to transfer
+;
+	JUMP	Finish, WHEN STATUS
+
+at 0x00000086 : */	0x830b0000,0x00000460,
+/*
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x00000088 : */	0x0f000001,0x00000000,
+/*
+	JUMP	DisconnectDuringDataIn, IF DISCONNECT_MSG
+
+at 0x0000008a : */	0x800c0004,0x00000398,
+/*
+	JUMP	IgnoreMsgDuringData, IF SAVE_DATA_PTRS_MSG
+
+at 0x0000008c : */	0x800c0002,0x00000210,
+/*
+	JUMP	IgnoreMsgDuringData, IF RESTORE_DATA_PTRS_MSG
+
+at 0x0000008e : */	0x800c0003,0x00000210,
+/*
+	INT	MSG_IN_DURING_DATA_IN
+
+at 0x00000090 : */	0x98080000,0x00000750,
+/*
+
+MsgInAfterCmd:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x00000092 : */	0x0f000001,0x00000000,
+/*
+	JUMP	DisconnectAfterCmd, IF DISCONNECT_MSG
+
+at 0x00000094 : */	0x800c0004,0x00000298,
+/*
+	JUMP	IgnoreMsgInAfterCmd, IF SAVE_DATA_PTRS_MSG
+
+at 0x00000096 : */	0x800c0002,0x00000288,
+/*
+	JUMP	IgnoreMsgInAfterCmd, IF RESTORE_DATA_PTRS_MSG
+
+at 0x00000098 : */	0x800c0003,0x00000288,
+/*
+	CALL	ProcessReceiveMessage
+
+at 0x0000009a : */	0x88080000,0x000000a8,
+/*
+	INT	MSG_IN_AFTER_CMD
+
+at 0x0000009c : */	0x98080000,0x00000350,
+/*
+	CLEAR	ACK
+
+at 0x0000009e : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeSendCommand
+
+at 0x000000a0 : */	0x80080000,0x000001e8,
+/*
+
+IgnoreMsgInAfterCmd:
+	CLEAR	ACK
+
+at 0x000000a2 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeSendCommand
+
+at 0x000000a4 : */	0x80080000,0x000001e8,
+/*
+
+DisconnectAfterCmd:
+	CLEAR	ACK
+
+at 0x000000a6 : */	0x60000040,0x00000000,
+/*
+	WAIT	DISCONNECT
+
+at 0x000000a8 : */	0x48000000,0x00000000,
+/*
+	ENTRY	Disconnect1
+Disconnect1:
+	INT	DISCONNECT_AFTER_CMD
+
+at 0x000000aa : */	0x98080000,0x00000380,
+/*
+	ENTRY	Disconnect2
+Disconnect2:
+; We return here after a reselection
+	CLEAR	ACK
+
+at 0x000000ac : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeSendCommand
+
+at 0x000000ae : */	0x80080000,0x000001e8,
+/*
+
+MsgInBeforeCommand:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x000000b0 : */	0x0f000001,0x00000000,
+/*
+	JUMP	IgnoreMsgBeforeCommand, IF SAVE_DATA_PTRS_MSG
+
+at 0x000000b2 : */	0x800c0002,0x000001c0,
+/*
+	JUMP	IgnoreMsgBeforeCommand, IF RESTORE_DATA_PTRS_MSG
+
+at 0x000000b4 : */	0x800c0003,0x000001c0,
+/*
+	CALL	ProcessReceiveMessage
+
+at 0x000000b6 : */	0x88080000,0x000000a8,
+/*
+	INT	MSG_IN_BEFORE_CMD
+
+at 0x000000b8 : */	0x98080000,0x00000250,
+/*
+	CLEAR	ACK
+
+at 0x000000ba : */	0x60000040,0x00000000,
+/*
+	JUMP	SendCommand
+
+at 0x000000bc : */	0x80080000,0x000001c8,
+/*
+
+DataIn:
+	CALL	SGScriptStartAddress
+
+at 0x000000be : */	0x88080000,0x00000000,
+/*
+ResumeDataIn:
+	JUMP	Finish, WHEN STATUS
+
+at 0x000000c0 : */	0x830b0000,0x00000460,
+/*
+	JUMP	MsgInAfterDataIn, IF MSG_IN
+
+at 0x000000c2 : */	0x870a0000,0x00000358,
+/*
+	JUMP	DataInAfterDataIn, if DATA_IN
+
+at 0x000000c4 : */	0x810a0000,0x00000328,
+/*
+	INT	MSG_OUT_AFTER_DATA_IN, if MSG_OUT
+
+at 0x000000c6 : */	0x9e0a0000,0x00000590,
+/*
+	INT	UNEXPECTED_PHASE_AFTER_DATA_IN
+
+at 0x000000c8 : */	0x98080000,0x00000520,
+/*
+
+DataInAfterDataIn:
+	INT	DATA_IN_AFTER_DATA_IN
+
+at 0x000000ca : */	0x98080000,0x000005a0,
+/*
+	JUMP	ResumeDataIn
+
+at 0x000000cc : */	0x80080000,0x00000300,
+/*
+
+DataOut:
+	CALL	SGScriptStartAddress
+
+at 0x000000ce : */	0x88080000,0x00000000,
+/*
+ResumeDataOut:
+	JUMP	Finish, WHEN STATUS
+
+at 0x000000d0 : */	0x830b0000,0x00000460,
+/*
+	JUMP	MsgInAfterDataOut, IF MSG_IN
+
+at 0x000000d2 : */	0x870a0000,0x000003e8,
+/*
+	INT	UNEXPECTED_PHASE_AFTER_DATA_OUT
+
+at 0x000000d4 : */	0x98080000,0x00000620,
+/*
+
+MsgInAfterDataIn:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x000000d6 : */	0x0f000001,0x00000000,
+/*
+	JUMP	DisconnectAfterDataIn, IF DISCONNECT_MSG
+
+at 0x000000d8 : */	0x800c0004,0x000003c0,
+/*
+	JUMP	IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+
+at 0x000000da : */	0x800c0002,0x00000428,
+/*
+	JUMP	IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+
+at 0x000000dc : */	0x800c0003,0x00000428,
+/*
+	CALL	ProcessReceiveMessage
+
+at 0x000000de : */	0x88080000,0x000000a8,
+/*
+	INT	MSG_IN_AFTER_DATA_IN
+
+at 0x000000e0 : */	0x98080000,0x00000550,
+/*
+	CLEAR	ACK
+
+at 0x000000e2 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeDataIn
+
+at 0x000000e4 : */	0x80080000,0x00000300,
+/*
+
+DisconnectDuringDataIn:
+	CLEAR	ACK
+
+at 0x000000e6 : */	0x60000040,0x00000000,
+/*
+	WAIT	DISCONNECT
+
+at 0x000000e8 : */	0x48000000,0x00000000,
+/*
+	ENTRY	Disconnect3
+Disconnect3:
+	INT	DISCONNECT_DURING_DATA
+
+at 0x000000ea : */	0x98080000,0x00000780,
+/*
+	ENTRY	Disconnect4
+Disconnect4:
+; we return here after a reselection
+	CLEAR	ACK
+
+at 0x000000ec : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeSendCommand
+
+at 0x000000ee : */	0x80080000,0x000001e8,
+/*
+
+
+DisconnectAfterDataIn:
+	CLEAR	ACK
+
+at 0x000000f0 : */	0x60000040,0x00000000,
+/*
+	WAIT	DISCONNECT
+
+at 0x000000f2 : */	0x48000000,0x00000000,
+/*
+	ENTRY	Disconnect5
+Disconnect5:
+	INT	DISCONNECT_AFTER_DATA
+
+at 0x000000f4 : */	0x98080000,0x00000580,
+/*
+	ENTRY	Disconnect6
+Disconnect6:
+; we return here after a reselection
+	CLEAR	ACK
+
+at 0x000000f6 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeDataIn
+
+at 0x000000f8 : */	0x80080000,0x00000300,
+/*
+
+MsgInAfterDataOut:
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x000000fa : */	0x0f000001,0x00000000,
+/*
+	JUMP	DisconnectAfterDataOut, if DISCONNECT_MSG
+
+at 0x000000fc : */	0x800c0004,0x00000438,
+/*
+	JUMP	IgnoreMsgAfterData, IF SAVE_DATA_PTRS_MSG
+
+at 0x000000fe : */	0x800c0002,0x00000428,
+/*
+	JUMP	IgnoreMsgAfterData, IF RESTORE_DATA_PTRS_MSG
+
+at 0x00000100 : */	0x800c0003,0x00000428,
+/*
+	CALL	ProcessReceiveMessage
+
+at 0x00000102 : */	0x88080000,0x000000a8,
+/*
+	INT	MSG_IN_AFTER_DATA_OUT
+
+at 0x00000104 : */	0x98080000,0x00000650,
+/*
+	CLEAR	ACK
+
+at 0x00000106 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeDataOut
+
+at 0x00000108 : */	0x80080000,0x00000340,
+/*
+
+IgnoreMsgAfterData:
+	CLEAR	ACK
+
+at 0x0000010a : */	0x60000040,0x00000000,
+/*
+; Data in and out do the same thing on resume, so pick one
+	JUMP	ResumeDataIn
+
+at 0x0000010c : */	0x80080000,0x00000300,
+/*
+
+DisconnectAfterDataOut:
+	CLEAR	ACK
+
+at 0x0000010e : */	0x60000040,0x00000000,
+/*
+	WAIT	DISCONNECT
+
+at 0x00000110 : */	0x48000000,0x00000000,
+/*
+	ENTRY	Disconnect7
+Disconnect7:
+	INT	DISCONNECT_AFTER_DATA
+
+at 0x00000112 : */	0x98080000,0x00000580,
+/*
+	ENTRY	Disconnect8
+Disconnect8:
+; we return here after a reselection
+	CLEAR	ACK
+
+at 0x00000114 : */	0x60000040,0x00000000,
+/*
+	JUMP	ResumeDataOut
+
+at 0x00000116 : */	0x80080000,0x00000340,
+/*
+
+Finish:
+	MOVE	1, StatusAddress, WHEN STATUS
+
+at 0x00000118 : */	0x0b000001,0x00000000,
+/*
+	INT	NOT_MSG_IN_AFTER_STATUS, WHEN NOT MSG_IN
+
+at 0x0000011a : */	0x9f030000,0x00000430,
+/*
+	MOVE	1, ReceiveMsgAddress, WHEN MSG_IN
+
+at 0x0000011c : */	0x0f000001,0x00000000,
+/*
+	JUMP	FinishCommandComplete, IF COMMAND_COMPLETE_MSG
+
+at 0x0000011e : */	0x800c0000,0x00000490,
+/*
+	CALL	ProcessReceiveMessage
+
+at 0x00000120 : */	0x88080000,0x000000a8,
+/*
+	INT	MSG_IN_AFTER_STATUS
+
+at 0x00000122 : */	0x98080000,0x00000440,
+/*
+	ENTRY	FinishCommandComplete
+FinishCommandComplete:
+	CLEAR	ACK
+
+at 0x00000124 : */	0x60000040,0x00000000,
+/*
+	WAIT	DISCONNECT
+
+at 0x00000126 : */	0x48000000,0x00000000,
+/*
+	ENTRY	Finish1
+Finish1:
+	INT	GOOD_STATUS_AFTER_STATUS
+
+at 0x00000128 : */	0x98080000,0x00000401,
+};
+
+#define A_AFTER_CMD	0x00000300
+static u32 A_AFTER_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_AFTER_DATA_IN	0x00000500
+static u32 A_AFTER_DATA_IN_used[] __attribute((unused)) = {
+};
+
+#define A_AFTER_DATA_OUT	0x00000600
+static u32 A_AFTER_DATA_OUT_used[] __attribute((unused)) = {
+};
+
+#define A_AFTER_SELECTION	0x00000100
+static u32 A_AFTER_SELECTION_used[] __attribute((unused)) = {
+};
+
+#define A_AFTER_STATUS	0x00000400
+static u32 A_AFTER_STATUS_used[] __attribute((unused)) = {
+};
+
+#define A_BEFORE_CMD	0x00000200
+static u32 A_BEFORE_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_COMMAND_COMPLETE_MSG	0x00000000
+static u32 A_COMMAND_COMPLETE_MSG_used[] __attribute((unused)) = {
+	0x0000011e,
+};
+
+#define A_COMPLETED_SELECTION_AS_TARGET	0x00001001
+static u32 A_COMPLETED_SELECTION_AS_TARGET_used[] __attribute((unused)) = {
+	0x0000001d,
+};
+
+#define A_CommandAddress	0x00000000
+static u32 A_CommandAddress_used[] __attribute((unused)) = {
+	0x00000079,
+};
+
+#define A_CommandCount	0x00000000
+static u32 A_CommandCount_used[] __attribute((unused)) = {
+	0x00000078,
+};
+
+#define A_DATA_IN_AFTER_DATA_IN	0x000005a0
+static u32 A_DATA_IN_AFTER_DATA_IN_used[] __attribute((unused)) = {
+	0x000000cb,
+};
+
+#define A_DEBUG_INTERRUPT	0x00003000
+static u32 A_DEBUG_INTERRUPT_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT1	0x00003001
+static u32 A_DEBUG_INTERRUPT1_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT2	0x00003002
+static u32 A_DEBUG_INTERRUPT2_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT3	0x00003003
+static u32 A_DEBUG_INTERRUPT3_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT4	0x00003004
+static u32 A_DEBUG_INTERRUPT4_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT5	0x00003005
+static u32 A_DEBUG_INTERRUPT5_used[] __attribute((unused)) = {
+};
+
+#define A_DEBUG_INTERRUPT6	0x00003006
+static u32 A_DEBUG_INTERRUPT6_used[] __attribute((unused)) = {
+};
+
+#define A_DISCONNECT	0x00000080
+static u32 A_DISCONNECT_used[] __attribute((unused)) = {
+};
+
+#define A_DISCONNECT_AFTER_CMD	0x00000380
+static u32 A_DISCONNECT_AFTER_CMD_used[] __attribute((unused)) = {
+	0x000000ab,
+};
+
+#define A_DISCONNECT_AFTER_DATA	0x00000580
+static u32 A_DISCONNECT_AFTER_DATA_used[] __attribute((unused)) = {
+	0x000000f5,
+	0x00000113,
+};
+
+#define A_DISCONNECT_DURING_DATA	0x00000780
+static u32 A_DISCONNECT_DURING_DATA_used[] __attribute((unused)) = {
+	0x000000eb,
+};
+
+#define A_DISCONNECT_MSG	0x00000004
+static u32 A_DISCONNECT_MSG_used[] __attribute((unused)) = {
+	0x0000008a,
+	0x00000094,
+	0x000000d8,
+	0x000000fc,
+};
+
+#define A_DURING_DATA_IN	0x00000700
+static u32 A_DURING_DATA_IN_used[] __attribute((unused)) = {
+};
+
+#define A_Device_ID	0x00000000
+static u32 A_Device_ID_used[] __attribute((unused)) = {
+	0x00000000,
+};
+
+#define A_EXTENDED_MSG	0x00000001
+static u32 A_EXTENDED_MSG_used[] __attribute((unused)) = {
+	0x0000002a,
+};
+
+#define A_FATAL	0x00002000
+static u32 A_FATAL_used[] __attribute((unused)) = {
+};
+
+#define A_FATAL_ILLEGAL_MSG_LENGTH	0x00002003
+static u32 A_FATAL_ILLEGAL_MSG_LENGTH_used[] __attribute((unused)) = {
+	0x00000043,
+};
+
+#define A_FATAL_NOT_MSG_IN_AFTER_SELECTION	0x00002002
+static u32 A_FATAL_NOT_MSG_IN_AFTER_SELECTION_used[] __attribute((unused)) = {
+	0x0000000d,
+};
+
+#define A_FATAL_SEND_MSG	0x00002001
+static u32 A_FATAL_SEND_MSG_used[] __attribute((unused)) = {
+	0x00000023,
+};
+
+#define A_FATAL_UNEXPECTED_RESELECTION_MSG	0x00002000
+static u32 A_FATAL_UNEXPECTED_RESELECTION_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_GOOD_STATUS	0x00000001
+static u32 A_GOOD_STATUS_used[] __attribute((unused)) = {
+};
+
+#define A_GOOD_STATUS_AFTER_STATUS	0x00000401
+static u32 A_GOOD_STATUS_AFTER_STATUS_used[] __attribute((unused)) = {
+	0x00000129,
+};
+
+#define A_IDENTIFY_MSG	0x00000080
+static u32 A_IDENTIFY_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_IDENTIFY_MSG_MASK	0x0000007f
+static u32 A_IDENTIFY_MSG_MASK_used[] __attribute((unused)) = {
+};
+
+#define A_MSG_IN	0x00000050
+static u32 A_MSG_IN_used[] __attribute((unused)) = {
+};
+
+#define A_MSG_IN_AFTER_CMD	0x00000350
+static u32 A_MSG_IN_AFTER_CMD_used[] __attribute((unused)) = {
+	0x0000009d,
+};
+
+#define A_MSG_IN_AFTER_DATA_IN	0x00000550
+static u32 A_MSG_IN_AFTER_DATA_IN_used[] __attribute((unused)) = {
+	0x000000e1,
+};
+
+#define A_MSG_IN_AFTER_DATA_OUT	0x00000650
+static u32 A_MSG_IN_AFTER_DATA_OUT_used[] __attribute((unused)) = {
+	0x00000105,
+};
+
+#define A_MSG_IN_AFTER_STATUS	0x00000440
+static u32 A_MSG_IN_AFTER_STATUS_used[] __attribute((unused)) = {
+	0x00000123,
+};
+
+#define A_MSG_IN_BEFORE_CMD	0x00000250
+static u32 A_MSG_IN_BEFORE_CMD_used[] __attribute((unused)) = {
+	0x000000b9,
+};
+
+#define A_MSG_IN_DURING_DATA_IN	0x00000750
+static u32 A_MSG_IN_DURING_DATA_IN_used[] __attribute((unused)) = {
+	0x00000091,
+};
+
+#define A_MSG_OUT	0x00000090
+static u32 A_MSG_OUT_used[] __attribute((unused)) = {
+};
+
+#define A_MSG_OUT_AFTER_DATA_IN	0x00000590
+static u32 A_MSG_OUT_AFTER_DATA_IN_used[] __attribute((unused)) = {
+	0x000000c7,
+};
+
+#define A_MessageCount	0x00000000
+static u32 A_MessageCount_used[] __attribute((unused)) = {
+	0x0000001e,
+};
+
+#define A_MessageLocation	0x00000000
+static u32 A_MessageLocation_used[] __attribute((unused)) = {
+	0x0000001f,
+};
+
+#define A_NOT_MSG_IN	0x00000030
+static u32 A_NOT_MSG_IN_used[] __attribute((unused)) = {
+};
+
+#define A_NOT_MSG_IN_AFTER_STATUS	0x00000430
+static u32 A_NOT_MSG_IN_AFTER_STATUS_used[] __attribute((unused)) = {
+	0x0000011b,
+};
+
+#define A_NOT_MSG_OUT	0x00000010
+static u32 A_NOT_MSG_OUT_used[] __attribute((unused)) = {
+};
+
+#define A_NOT_MSG_OUT_AFTER_SELECTION	0x00000110
+static u32 A_NOT_MSG_OUT_AFTER_SELECTION_used[] __attribute((unused)) = {
+	0x00000007,
+};
+
+#define A_PARITY_ERROR_MSG	0x00000009
+static u32 A_PARITY_ERROR_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_REJECT_MSG	0x00000007
+static u32 A_REJECT_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_REJECT_MSG_BEFORE_CMD	0x00000270
+static u32 A_REJECT_MSG_BEFORE_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_REJECT_MSG_R	0x00000070
+static u32 A_REJECT_MSG_R_used[] __attribute((unused)) = {
+};
+
+#define A_RESELECTED_DURING_SELECTION	0x00001000
+static u32 A_RESELECTED_DURING_SELECTION_used[] __attribute((unused)) = {
+	0x0000000b,
+};
+
+#define A_RESELECTION_IDENTIFIED	0x00001003
+static u32 A_RESELECTION_IDENTIFIED_used[] __attribute((unused)) = {
+	0x00000011,
+	0x00000015,
+};
+
+#define A_RESTORE_DATA_PTRS_MSG	0x00000003
+static u32 A_RESTORE_DATA_PTRS_MSG_used[] __attribute((unused)) = {
+	0x0000008e,
+	0x00000098,
+	0x000000b4,
+	0x000000dc,
+	0x00000100,
+};
+
+#define A_ReceiveMsgAddress	0x00000000
+static u32 A_ReceiveMsgAddress_used[] __attribute((unused)) = {
+	0x0000000f,
+	0x00000013,
+	0x00000029,
+	0x00000031,
+	0x00000037,
+	0x00000047,
+	0x0000004d,
+	0x00000053,
+	0x00000059,
+	0x0000005f,
+	0x00000089,
+	0x00000093,
+	0x000000b1,
+	0x000000d7,
+	0x000000fb,
+	0x0000011d,
+};
+
+#define A_SAVE_DATA_PTRS_MSG	0x00000002
+static u32 A_SAVE_DATA_PTRS_MSG_used[] __attribute((unused)) = {
+	0x0000008c,
+	0x00000096,
+	0x000000b2,
+	0x000000da,
+	0x000000fe,
+};
+
+#define A_SDTR_MSG	0x00000001
+static u32 A_SDTR_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_SDTR_MSG_AFTER_CMD	0x00000360
+static u32 A_SDTR_MSG_AFTER_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_SDTR_MSG_BEFORE_CMD	0x00000260
+static u32 A_SDTR_MSG_BEFORE_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_SDTR_MSG_R	0x00000060
+static u32 A_SDTR_MSG_R_used[] __attribute((unused)) = {
+};
+
+#define A_SGScriptStartAddress	0x00000000
+static u32 A_SGScriptStartAddress_used[] __attribute((unused)) = {
+	0x000000bf,
+	0x000000cf,
+};
+
+#define A_SIMPLE_TAG_MSG	0x00000020
+static u32 A_SIMPLE_TAG_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_StatusAddress	0x00000000
+static u32 A_StatusAddress_used[] __attribute((unused)) = {
+	0x00000119,
+};
+
+#define A_TWO_BYTE_MSG	0x00000020
+static u32 A_TWO_BYTE_MSG_used[] __attribute((unused)) = {
+	0x0000002c,
+};
+
+#define A_TWO_BYTE_MSG_MASK	0x0000000f
+static u32 A_TWO_BYTE_MSG_MASK_used[] __attribute((unused)) = {
+	0x0000002c,
+};
+
+#define A_UNEXPECTED_MSG	0x00000040
+static u32 A_UNEXPECTED_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_UNEXPECTED_MSG_BEFORE_CMD	0x00000240
+static u32 A_UNEXPECTED_MSG_BEFORE_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_UNEXPECTED_PHASE	0x00000020
+static u32 A_UNEXPECTED_PHASE_used[] __attribute((unused)) = {
+};
+
+#define A_UNEXPECTED_PHASE_AFTER_CMD	0x00000320
+static u32 A_UNEXPECTED_PHASE_AFTER_CMD_used[] __attribute((unused)) = {
+	0x00000083,
+};
+
+#define A_UNEXPECTED_PHASE_AFTER_DATA_IN	0x00000520
+static u32 A_UNEXPECTED_PHASE_AFTER_DATA_IN_used[] __attribute((unused)) = {
+	0x000000c9,
+};
+
+#define A_UNEXPECTED_PHASE_AFTER_DATA_OUT	0x00000620
+static u32 A_UNEXPECTED_PHASE_AFTER_DATA_OUT_used[] __attribute((unused)) = {
+	0x000000d5,
+};
+
+#define A_UNEXPECTED_PHASE_BEFORE_CMD	0x00000220
+static u32 A_UNEXPECTED_PHASE_BEFORE_CMD_used[] __attribute((unused)) = {
+	0x00000077,
+};
+
+#define A_WDTR_MSG	0x00000003
+static u32 A_WDTR_MSG_used[] __attribute((unused)) = {
+};
+
+#define A_WDTR_MSG_AFTER_CMD	0x000003a0
+static u32 A_WDTR_MSG_AFTER_CMD_used[] __attribute((unused)) = {
+};
+
+#define A_WDTR_MSG_R	0x000000a0
+static u32 A_WDTR_MSG_R_used[] __attribute((unused)) = {
+};
+
+#define Ent_Disconnect1	0x000002a8
+#define Ent_Disconnect2	0x000002b0
+#define Ent_Disconnect3	0x000003a8
+#define Ent_Disconnect4	0x000003b0
+#define Ent_Disconnect5	0x000003d0
+#define Ent_Disconnect6	0x000003d8
+#define Ent_Disconnect7	0x00000448
+#define Ent_Disconnect8	0x00000450
+#define Ent_Finish1	0x000004a0
+#define Ent_Finish2	0x000004a8
+#define Ent_FinishCommandComplete	0x00000490
+#define Ent_GetReselectionData	0x00000038
+#define Ent_GetReselectionWithTag	0x00000048
+#define Ent_IgnoreMessage	0x00000188
+#define Ent_MsgInDuringData	0x00000218
+#define Ent_ReceiveMessage	0x000000a0
+#define Ent_SelectedAsTarget	0x00000058
+#define Ent_SendCommand	0x000001c8
+#define Ent_SendMessage	0x00000078
+#define Ent_SendMessagePhaseMismatch	0x00000090
+#define Ent_SendMessageWithATN	0x00000198
+#define Ent_StartUp	0x00000000
+static u32 LABELPATCHES[] __attribute((unused)) = {
+	0x00000001,
+	0x00000003,
+	0x00000005,
+	0x00000009,
+	0x00000027,
+	0x0000002b,
+	0x00000039,
+	0x0000003b,
+	0x0000003d,
+	0x0000003f,
+	0x00000041,
+	0x0000006b,
+	0x0000006d,
+	0x00000073,
+	0x00000075,
+	0x0000007b,
+	0x0000007d,
+	0x0000007f,
+	0x00000081,
+	0x00000087,
+	0x0000008b,
+	0x0000008d,
+	0x0000008f,
+	0x00000095,
+	0x00000097,
+	0x00000099,
+	0x0000009b,
+	0x000000a1,
+	0x000000a5,
+	0x000000af,
+	0x000000b3,
+	0x000000b5,
+	0x000000b7,
+	0x000000bd,
+	0x000000c1,
+	0x000000c3,
+	0x000000c5,
+	0x000000cd,
+	0x000000d1,
+	0x000000d3,
+	0x000000d9,
+	0x000000db,
+	0x000000dd,
+	0x000000df,
+	0x000000e5,
+	0x000000ef,
+	0x000000f9,
+	0x000000fd,
+	0x000000ff,
+	0x00000101,
+	0x00000103,
+	0x00000109,
+	0x0000010d,
+	0x00000117,
+	0x0000011f,
+	0x00000121,
+};
+
+static struct {
+	u32	offset;
+	void		*address;
+} EXTERNAL_PATCHES[] __attribute((unused)) = {
+};
+
+static u32 INSTRUCTIONS __attribute((unused))	= 149;
+static u32 PATCHES __attribute((unused))	= 56;
+static u32 EXTERNAL_PATCHES_LEN __attribute((unused))	= 0;
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
new file mode 100644
index 0000000..8ead55f
--- /dev/null
+++ b/drivers/scsi/53c7xx.c
@@ -0,0 +1,6102 @@
+/*
+ * 53c710 driver.  Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ * Check out PERM_OPTIONS and EXPECTED_CLOCK, which may be defined in the
+ * relevant machine specific file (eg. mvme16x.[ch], amiga7xx.[ch]).
+ * There are also currently some defines at the top of 53c7xx.scr.
+ * The chip type is #defined in script_asm.pl, as well as the Makefile.
+ * Host scsi ID expected to be 7 - see NCR53c7x0_init().
+ *
+ * I have removed the PCI code and some of the 53c8xx specific code - 
+ * simply to make this file smaller and easier to manage.
+ *
+ * MVME16x issues:
+ *   Problems trying to read any chip registers in NCR53c7x0_init(), as they
+ *   may never have been set by 16xBug (eg. If kernel has come in over tftp).
+ */
+
+/*
+ * Adapted for Linux/m68k Amiga platforms for the A4000T/A4091 and
+ * WarpEngine SCSI controllers.
+ * By Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * Thanks to Richard Hirst for making it possible with the MVME additions
+ */
+
+/*
+ * 53c710 rev 0 doesn't support add with carry.  Rev 1 and 2 does.  To
+ * overcome this problem you can define FORCE_DSA_ALIGNMENT, which ensures
+ * that the DSA address is always xxxxxx00.  If disconnection is not allowed,
+ * then the script only ever tries to add small (< 256) positive offsets to
+ * DSA, so lack of carry isn't a problem.  FORCE_DSA_ALIGNMENT can, of course,
+ * be defined for all chip revisions at a small cost in memory usage.
+ */
+
+#define FORCE_DSA_ALIGNMENT
+
+/*
+ * Selection timer does not always work on the 53c710, depending on the
+ * timing at the last disconnect, if this is a problem for you, try
+ * using validids as detailed below.
+ *
+ * Options for the NCR7xx driver
+ *
+ * noasync:0		-	disables sync and asynchronous negotiation
+ * nosync:0		-	disables synchronous negotiation (does async)
+ * nodisconnect:0	-	disables disconnection
+ * validids:0x??	-	Bitmask field that disallows certain ID's.
+ *			-	e.g.	0x03	allows ID 0,1
+ *			-		0x1F	allows ID 0,1,2,3,4
+ * opthi:n		-	replace top word of options with 'n'
+ * optlo:n		-	replace bottom word of options with 'n'
+ *			-	ALWAYS SPECIFY opthi THEN optlo <<<<<<<<<<
+ */
+
+/*
+ * PERM_OPTIONS are driver options which will be enabled for all NCR boards
+ * in the system at driver initialization time.
+ *
+ * Don't THINK about touching these in PERM_OPTIONS : 
+ *   OPTION_MEMORY_MAPPED 
+ * 	680x0 doesn't have an IO map!
+ *
+ *   OPTION_DEBUG_TEST1
+ *	Test 1 does bus mastering and interrupt tests, which will help weed 
+ *	out brain damaged main boards.
+ *
+ * Other PERM_OPTIONS settings are listed below.  Note the actual options
+ * required are set in the relevant file (mvme16x.c, amiga7xx.c, etc):
+ *
+ *   OPTION_NO_ASYNC
+ *	Don't negotiate for asynchronous transfers on the first command 
+ *	when OPTION_ALWAYS_SYNCHRONOUS is set.  Useful for dain bramaged
+ *	devices which do something bad rather than sending a MESSAGE 
+ *	REJECT back to us like they should if they can't cope.
+ *
+ *   OPTION_SYNCHRONOUS
+ *	Enable support for synchronous transfers.  Target negotiated 
+ *	synchronous transfers will be responded to.  To initiate 
+ *	a synchronous transfer request,  call 
+ *
+ *	    request_synchronous (hostno, target) 
+ *
+ *	from within KGDB.
+ *
+ *   OPTION_ALWAYS_SYNCHRONOUS
+ *	Negotiate for synchronous transfers with every target after
+ *	driver initialization or a SCSI bus reset.  This is a bit dangerous, 
+ *	since there are some dain bramaged SCSI devices which will accept
+ *	SDTR messages but keep talking asynchronously.
+ *
+ *   OPTION_DISCONNECT
+ *	Enable support for disconnect/reconnect.  To change the 
+ *	default setting on a given host adapter, call
+ *
+ *	    request_disconnect (hostno, allow)
+ *
+ *	where allow is non-zero to allow, 0 to disallow.
+ * 
+ *  If you really want to run 10MHz FAST SCSI-II transfers, you should 
+ *  know that the NCR driver currently ignores parity information.  Most
+ *  systems do 5MHz SCSI fine.  I've seen a lot that have problems faster
+ *  than 8MHz.  To play it safe, we only request 5MHz transfers.
+ *
+ *  If you'd rather get 10MHz transfers, edit sdtr_message and change 
+ *  the fourth byte from 50 to 25.
+ */
+
+/*
+ * Sponsored by 
+ *	iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@PoohSticks.ORG
+ *	+1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ * 
+ * For more information, please consult 
+ *
+ * NCR53C810 
+ * SCSI I/O Processor
+ * Programmer's Guide
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810/53C820
+ * PCI-SCSI I/O Processor Design In Guide
+ *
+ * For literature on Symbios Logic Inc. formerly NCR, SCSI, 
+ * and Communication products please call (800) 334-5454 or
+ * (719) 536-3300. 
+ * 
+ * PCI BIOS Specification Revision
+ * PCI Local Bus Specification
+ * PCI System Design Guide
+ *
+ * PCI Special Interest Group
+ * M/S HF3-15A
+ * 5200 N.E. Elam Young Parkway
+ * Hillsboro, Oregon 97124-6497
+ * +1 (503) 696-2000 
+ * +1 (800) 433-5177
+ */
+
+/*
+ * Design issues : 
+ * The cumulative latency needed to propagate a read/write request 
+ * through the file system, buffer cache, driver stacks, SCSI host, and 
+ * SCSI device is ultimately the limiting factor in throughput once we 
+ * have a sufficiently fast host adapter.
+ *  
+ * So, to maximize performance we want to keep the ratio of latency to data 
+ * transfer time to a minimum by
+ * 1.  Minimizing the total number of commands sent (typical command latency
+ *	including drive and bus mastering host overhead is as high as 4.5ms)
+ *	to transfer a given amount of data.  
+ *
+ *      This is accomplished by placing no arbitrary limit on the number
+ *	of scatter/gather buffers supported, since we can transfer 1K
+ *	per scatter/gather buffer without Eric's cluster patches, 
+ *	4K with.  
+ *
+ * 2.  Minimizing the number of fatal interrupts serviced, since
+ * 	fatal interrupts halt the SCSI I/O processor.  Basically,
+ *	this means offloading the practical maximum amount of processing 
+ *	to the SCSI chip.
+ * 
+ *	On the NCR53c810/820/720,  this is accomplished by using 
+ *		interrupt-on-the-fly signals when commands complete, 
+ *		and only handling fatal errors and SDTR / WDTR 	messages 
+ *		in the host code.
+ *
+ *	On the NCR53c710, interrupts are generated as on the NCR53c8x0,
+ *		only the lack of a interrupt-on-the-fly facility complicates
+ *		things.   Also, SCSI ID registers and commands are 
+ *		bit fielded rather than binary encoded.
+ *		
+ * 	On the NCR53c700 and NCR53c700-66, operations that are done via 
+ *		indirect, table mode on the more advanced chips must be
+ *	        replaced by calls through a jump table which 
+ *		acts as a surrogate for the DSA.  Unfortunately, this 
+ * 		will mean that we must service an interrupt for each 
+ *		disconnect/reconnect.
+ * 
+ * 3.  Eliminating latency by pipelining operations at the different levels.
+ * 	
+ *	This driver allows a configurable number of commands to be enqueued
+ *	for each target/lun combination (experimentally, I have discovered
+ *	that two seems to work best) and will ultimately allow for 
+ *	SCSI-II tagged queuing.
+ * 	
+ *
+ * Architecture : 
+ * This driver is built around a Linux queue of commands waiting to 
+ * be executed, and a shared Linux/NCR array of commands to start.  Commands
+ * are transferred to the array  by the run_process_issue_queue() function 
+ * which is called whenever a command completes.
+ *
+ * As commands are completed, the interrupt routine is triggered,
+ * looks for commands in the linked list of completed commands with
+ * valid status, removes these commands from a list of running commands, 
+ * calls the done routine, and flags their target/luns as not busy.
+ *
+ * Due to limitations in the intelligence of the NCR chips, certain
+ * concessions are made.  In many cases, it is easier to dynamically 
+ * generate/fix-up code rather than calculate on the NCR at run time.  
+ * So, code is generated or fixed up for
+ *
+ * - Handling data transfers, using a variable number of MOVE instructions
+ *	interspersed with CALL MSG_IN, WHEN MSGIN instructions.
+ *
+ * 	The DATAIN and DATAOUT routines	are separate, so that an incorrect
+ *	direction can be trapped, and space isn't wasted. 
+ *
+ *	It may turn out that we're better off using some sort 
+ *	of table indirect instruction in a loop with a variable
+ *	sized table on the NCR53c710 and newer chips.
+ *
+ * - Checking for reselection (NCR53c710 and better)
+ *
+ * - Handling the details of SCSI context switches (NCR53c710 and better),
+ *	such as reprogramming appropriate synchronous parameters, 
+ *	removing the dsa structure from the NCR's queue of outstanding
+ *	commands, etc.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <linux/config.h>
+
+#include <linux/types.h>
+#include <asm/setup.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/time.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/pgtable.h>
+
+#ifdef CONFIG_AMIGA
+#include <asm/amigahw.h>
+#include <asm/amigaints.h>
+#include <asm/irq.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#endif
+
+#ifdef CONFIG_MVME16x
+#include <asm/mvme16xhw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#define VALID_IDS
+#endif
+
+#ifdef CONFIG_BVME6000
+#include <asm/bvme6000hw.h>
+
+#define BIG_ENDIAN
+#define NO_IO_SPACE
+#define VALID_IDS
+#endif
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "53c7xx.h"
+#include <linux/stat.h>
+#include <linux/stddef.h>
+
+#ifdef NO_IO_SPACE
+/*
+ * The following make the definitions in 53c7xx.h (write8, etc) smaller,
+ * we don't have separate i/o space anyway.
+ */
+#undef inb
+#undef outb
+#undef inw
+#undef outw
+#undef inl
+#undef outl
+#define inb(x)          1
+#define inw(x)          1
+#define inl(x)          1
+#define outb(x,y)       1
+#define outw(x,y)       1
+#define outl(x,y)       1
+#endif
+
+static int check_address (unsigned long addr, int size);
+static void dump_events (struct Scsi_Host *host, int count);
+static Scsi_Cmnd * return_outstanding_commands (struct Scsi_Host *host, 
+    int free, int issue);
+static void hard_reset (struct Scsi_Host *host);
+static void ncr_scsi_reset (struct Scsi_Host *host);
+static void print_lots (struct Scsi_Host *host);
+static void set_synchronous (struct Scsi_Host *host, int target, int sxfer, 
+    int scntl3, int now_connected);
+static int datapath_residual (struct Scsi_Host *host);
+static const char * sbcl_to_phase (int sbcl);
+static void print_progress (Scsi_Cmnd *cmd);
+static void print_queues (struct Scsi_Host *host);
+static void process_issue_queue (unsigned long flags);
+static int shutdown (struct Scsi_Host *host);
+static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int result);
+static int disable (struct Scsi_Host *host);
+static int NCR53c7xx_run_tests (struct Scsi_Host *host);
+static irqreturn_t NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+static void NCR53c7x0_intfly (struct Scsi_Host *host);
+static int ncr_halt (struct Scsi_Host *host);
+static void intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd 
+    *cmd);
+static void intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+static void print_dsa (struct Scsi_Host *host, u32 *dsa,
+    const char *prefix);
+static int print_insn (struct Scsi_Host *host, const u32 *insn,
+    const char *prefix, int kernel);
+
+static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_init_fixup (struct Scsi_Host *host);
+static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd);
+static void NCR53c7x0_soft_reset (struct Scsi_Host *host);
+
+/* Size of event list (per host adapter) */
+static int track_events = 0;
+static struct Scsi_Host *first_host = NULL;	/* Head of list of NCR boards */
+static Scsi_Host_Template *the_template = NULL;	
+
+/* NCR53c710 script handling code */
+
+#include "53c7xx_d.h"
+#ifdef A_int_debug_sync
+#define DEBUG_SYNC_INTR A_int_debug_sync
+#endif
+int NCR53c7xx_script_len = sizeof (SCRIPT);
+int NCR53c7xx_dsa_len = A_dsa_end + Ent_dsa_zero - Ent_dsa_code_template;
+#ifdef FORCE_DSA_ALIGNMENT
+int CmdPageStart = (0 - Ent_dsa_zero - sizeof(struct NCR53c7x0_cmd)) & 0xff;
+#endif
+
+static char *setup_strings[] =
+	{"","","","","","","",""};
+
+#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_STRINGS];
+
+void ncr53c7xx_setup (char *str, int *ints)
+{
+   int i;
+   char *p1, *p2;
+
+   p1 = setup_buffer;
+   *p1 = '\0';
+   if (str)
+      strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+   setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+   p1 = setup_buffer;
+   i = 0;
+   while (*p1 && (i < MAX_SETUP_STRINGS)) {
+      p2 = strchr(p1, ',');
+      if (p2) {
+         *p2 = '\0';
+         if (p1 != p2)
+            setup_strings[i] = p1;
+         p1 = p2 + 1;
+         i++;
+         }
+      else {
+         setup_strings[i] = p1;
+         break;
+         }
+      }
+   for (i=0; i<MAX_SETUP_STRINGS; i++)
+      setup_used[i] = 0;
+}
+
+
+/* check_setup_strings() returns index if key found, 0 if not
+ */
+
+static int check_setup_strings(char *key, int *flags, int *val, char *buf)
+{
+int x;
+char *cp;
+
+   for  (x=0; x<MAX_SETUP_STRINGS; x++) {
+      if (setup_used[x])
+         continue;
+      if (!strncmp(setup_strings[x], key, strlen(key)))
+         break;
+      if (!strncmp(setup_strings[x], "next", strlen("next")))
+         return 0;
+      }
+   if (x == MAX_SETUP_STRINGS)
+      return 0;
+   setup_used[x] = 1;
+   cp = setup_strings[x] + strlen(key);
+   *val = -1;
+   if (*cp != ':')
+      return ++x;
+   cp++;
+   if ((*cp >= '0') && (*cp <= '9')) {
+      *val = simple_strtoul(cp,NULL,0);
+      }
+   return ++x;
+}
+
+
+
+/*
+ * KNOWN BUGS :
+ * - There is some sort of conflict when the PPP driver is compiled with 
+ * 	support for 16 channels?
+ * 
+ * - On systems which predate the 1.3.x initialization order change,
+ *      the NCR driver will cause Cannot get free page messages to appear.  
+ *      These are harmless, but I don't know of an easy way to avoid them.
+ *
+ * - With OPTION_DISCONNECT, on two systems under unknown circumstances,
+ *	we get a PHASE MISMATCH with DSA set to zero (suggests that we 
+ *	are occurring somewhere in the reselection code) where 
+ *	DSP=some value DCMD|DBC=same value.  
+ * 	
+ *	Closer inspection suggests that we may be trying to execute
+ *	some portion of the DSA?
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : handling residual transfer (+ 0 bytes from DMA FIFO)
+ * scsi0 : no current command : unexpected phase MSGIN.
+ *         DSP=0x1c46cc, DCMD|DBC=0x1c46ac, DSA=0x0
+ *         DSPS=0x0, TEMP=0x1c3e70, DMODE=0x80
+ * scsi0 : DSP->
+ * 001c46cc : 0x001c46cc 0x00000000
+ * 001c46d4 : 0x001c5ea0 0x000011f8
+ *
+ *	Changed the print code in the phase_mismatch handler so
+ *	that we call print_lots to try to diagnose this.
+ *
+ */
+
+/* 
+ * Possible future direction of architecture for max performance :
+ *
+ * We're using a single start array for the NCR chip.  This is 
+ * sub-optimal, because we cannot add a command which would conflict with 
+ * an executing command to this start queue, and therefore must insert the 
+ * next command for a given I/T/L combination after the first has completed;
+ * incurring our interrupt latency between SCSI commands.
+ *
+ * To allow further pipelining of the NCR and host CPU operation, we want 
+ * to set things up so that immediately on termination of a command destined 
+ * for a given LUN, we get that LUN busy again.  
+ * 
+ * To do this, we need to add a 32 bit pointer to which is jumped to 
+ * on completion of a command.  If no new command is available, this 
+ * would point to the usual DSA issue queue select routine.
+ *
+ * If one were, it would point to a per-NCR53c7x0_cmd select routine 
+ * which starts execution immediately, inserting the command at the head 
+ * of the start queue if the NCR chip is selected or reselected.
+ *
+ * We would change so that we keep a list of outstanding commands 
+ * for each unit, rather than a single running_list.  We'd insert 
+ * a new command into the right running list; if the NCR didn't 
+ * have something running for that yet, we'd put it in the 
+ * start queue as well.  Some magic needs to happen to handle the 
+ * race condition between the first command terminating before the 
+ * new one is written.
+ *
+ * Potential for profiling : 
+ * Call do_gettimeofday(struct timeval *tv) to get 800ns resolution.
+ */
+
+
+/*
+ * TODO : 
+ * 1.  To support WIDE transfers, not much needs to happen.  We
+ *	should do CHMOVE instructions instead of MOVEs when
+ *	we have scatter/gather segments of uneven length.  When
+ * 	we do this, we need to handle the case where we disconnect
+ *	between segments.
+ * 
+ * 2.  Currently, when Icky things happen we do a FATAL().  Instead,
+ *     we want to do an integrity check on the parts of the NCR hostdata
+ *     structure which were initialized at boot time; FATAL() if that 
+ *     fails, and otherwise try to recover.  Keep track of how many
+ *     times this has happened within a single SCSI command; if it 
+ *     gets excessive, then FATAL().
+ *
+ * 3.  Parity checking is currently disabled, and a few things should 
+ *     happen here now that we support synchronous SCSI transfers :
+ *     1.  On soft-reset, we shoould set the EPC (Enable Parity Checking)
+ *	   and AAP (Assert SATN/ on parity error) bits in SCNTL0.
+ *	
+ *     2.  We should enable the parity interrupt in the SIEN0 register.
+ * 
+ *     3.  intr_phase_mismatch() needs to believe that message out is 
+ *	   always an "acceptable" phase to have a mismatch in.  If 
+ *	   the old phase was MSG_IN, we should send a MESSAGE PARITY 
+ *	   error.  If the old phase was something else, we should send
+ *	   a INITIATOR_DETECTED_ERROR message.  Note that this could
+ *	   cause a RESTORE POINTERS message; so we should handle that 
+ *	   correctly first.  Instead, we should probably do an 
+ *	   initiator_abort.
+ *
+ * 4.  MPEE bit of CTEST4 should be set so we get interrupted if 
+ *     we detect an error.
+ *
+ *  
+ * 5.  The initial code has been tested on the NCR53c810.  I don't 
+ *     have access to NCR53c700, 700-66 (Forex boards), NCR53c710
+ *     (NCR Pentium systems), NCR53c720, NCR53c820, or NCR53c825 boards to 
+ *     finish development on those platforms.
+ *
+ *     NCR53c820/825/720 - need to add wide transfer support, including WDTR 
+ *     		negotiation, programming of wide transfer capabilities
+ *		on reselection and table indirect selection.
+ *
+ *     NCR53c710 - need to add fatal interrupt or GEN code for 
+ *		command completion signaling.   Need to modify all 
+ *		SDID, SCID, etc. registers, and table indirect select code 
+ *		since these use bit fielded (ie 1<<target) instead of 
+ *		binary encoded target ids.  Need to accommodate
+ *		different register mappings, probably scan through
+ *		the SCRIPT code and change the non SFBR register operand
+ *		of all MOVE instructions.
+ *
+ *		It is rather worse than this actually, the 710 corrupts
+ *		both TEMP and DSA when you do a MOVE MEMORY.  This
+ *		screws you up all over the place.  MOVE MEMORY 4 with a
+ *		destination of DSA seems to work OK, which helps some.
+ *		Richard Hirst  richard@sleepie.demon.co.uk
+ * 
+ *     NCR53c700/700-66 - need to add code to refix addresses on 
+ *		every nexus change, eliminate all table indirect code,
+ *		very messy.
+ *
+ * 6.  The NCR53c7x0 series is very popular on other platforms that 
+ *     could be running Linux - ie, some high performance AMIGA SCSI 
+ *     boards use it.  
+ *	
+ *     So, I should include #ifdef'd code so that it is 
+ *     compatible with these systems.
+ *	
+ *     Specifically, the little Endian assumptions I made in my 
+ *     bit fields need to change, and if the NCR doesn't see memory
+ *     the right way, we need to provide options to reverse words
+ *     when the scripts are relocated.
+ *
+ * 7.  Use vremap() to access memory mapped boards.  
+ */
+
+/* 
+ * Allow for simultaneous existence of multiple SCSI scripts so we 
+ * can have a single driver binary for all of the family.
+ *
+ * - one for NCR53c700 and NCR53c700-66 chips	(not yet supported)
+ * - one for rest (only the NCR53c810, 815, 820, and 825 are currently 
+ *	supported)
+ * 
+ * So that we only need two SCSI scripts, we need to modify things so
+ * that we fixup register accesses in READ/WRITE instructions, and 
+ * we'll also have to accommodate the bit vs. binary encoding of IDs
+ * with the 7xx chips.
+ */
+
+#define ROUNDUP(adr,type)	\
+  ((void *) (((long) (adr) + sizeof(type) - 1) & ~(sizeof(type) - 1)))
+
+
+/*
+ * Function: issue_to_cmd
+ *
+ * Purpose: convert jump instruction in issue array to NCR53c7x0_cmd
+ *	structure pointer.  
+ *
+ * Inputs; issue - pointer to start of NOP or JUMP instruction
+ *	in issue array.
+ *
+ * Returns: pointer to command on success; 0 if opcode is NOP.
+ */
+
+static inline struct NCR53c7x0_cmd *
+issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+    u32 *issue)
+{
+    return (issue[0] != hostdata->NOP_insn) ? 
+    /* 
+     * If the IF TRUE bit is set, it's a JUMP instruction.  The
+     * operand is a bus pointer to the dsa_begin routine for this DSA.  The
+     * dsa field of the NCR53c7x0_cmd structure starts with the 
+     * DSA code template.  By converting to a virtual address,
+     * subtracting the code template size, and offset of the 
+     * dsa field, we end up with a pointer to the start of the 
+     * structure (alternatively, we could use the 
+     * dsa_cmnd field, an anachronism from when we weren't
+     * sure what the relationship between the NCR structures
+     * and host structures were going to be.
+     */
+	(struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) - 
+	    (hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
+	    offsetof(struct NCR53c7x0_cmd, dsa)) 
+    /* If the IF TRUE bit is not set, it's a NOP */
+	: NULL;
+}
+
+
+/* 
+ * FIXME: we should junk these, in favor of synchronous_want and 
+ * wide_want in the NCR53c7x0_hostdata structure.
+ */
+
+/* Template for "preferred" synchronous transfer parameters. */
+
+static const unsigned char sdtr_message[] = {
+#ifdef CONFIG_SCSI_NCR53C7xx_FAST
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 25 /* *4ns */, 8 /* off */
+#else
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 50 /* *4ns */, 8 /* off */ 
+#endif
+};
+
+/* Template to request asynchronous transfers */
+
+static const unsigned char async_message[] = {
+    EXTENDED_MESSAGE, 3 /* length */, EXTENDED_SDTR, 0, 0 /* asynchronous */
+};
+
+/* Template for "preferred" WIDE transfer parameters */
+
+static const unsigned char wdtr_message[] = {
+    EXTENDED_MESSAGE, 2 /* length */, EXTENDED_WDTR, 1 /* 2^1 bytes */
+};
+
+#if 0
+/*
+ * Function : struct Scsi_Host *find_host (int host)
+ * 
+ * Purpose : KGDB support function which translates a host number 
+ * 	to a host structure. 
+ *
+ * Inputs : host - number of SCSI host
+ *
+ * Returns : NULL on failure, pointer to host structure on success.
+ */
+
+static struct Scsi_Host *
+find_host (int host) {
+    struct Scsi_Host *h;
+    for (h = first_host; h && h->host_no != host; h = h->next);
+    if (!h) {
+	printk (KERN_ALERT "scsi%d not found\n", host);
+	return NULL;
+    } else if (h->hostt != the_template) {
+	printk (KERN_ALERT "scsi%d is not a NCR board\n", host);
+	return NULL;
+    }
+    return h;
+}
+
+#if 0
+/*
+ * Function : request_synchronous (int host, int target)
+ * 
+ * Purpose : KGDB interface which will allow us to negotiate for 
+ * 	synchronous transfers.  This ill be replaced with a more 
+ * 	integrated function; perhaps a new entry in the scsi_host 
+ *	structure, accessible via an ioctl() or perhaps /proc/scsi.
+ *
+ * Inputs : host - number of SCSI host; target - number of target.
+ *
+ * Returns : 0 when negotiation has been setup for next SCSI command,
+ *	-1 on failure.
+ */
+
+static int
+request_synchronous (int host, int target) {
+    struct Scsi_Host *h;
+    struct NCR53c7x0_hostdata *hostdata;
+    unsigned long flags;
+    if (target < 0) {
+	printk (KERN_ALERT "target %d is bogus\n", target);
+	return -1;
+    }
+    if (!(h = find_host (host)))
+	return -1;
+    else if (h->this_id == target) {
+	printk (KERN_ALERT "target %d is host ID\n", target);
+	return -1;
+    } 
+    else if (target > h->max_id) {
+	printk (KERN_ALERT "target %d exceeds maximum of %d\n", target,
+	    h->max_id);
+	return -1;
+    }
+    hostdata = (struct NCR53c7x0_hostdata *)h->hostdata[0];
+
+    local_irq_save(flags);
+    if (hostdata->initiate_sdtr & (1 << target)) {
+	local_irq_restore(flags);
+	printk (KERN_ALERT "target %d already doing SDTR\n", target);
+	return -1;
+    } 
+    hostdata->initiate_sdtr |= (1 << target);
+    local_irq_restore(flags);
+    return 0;
+}
+#endif
+
+/*
+ * Function : request_disconnect (int host, int on_or_off)
+ * 
+ * Purpose : KGDB support function, tells us to allow or disallow 
+ *	disconnections.
+ *
+ * Inputs : host - number of SCSI host; on_or_off - non-zero to allow,
+ *	zero to disallow.
+ *
+ * Returns : 0 on success, *	-1 on failure.
+ */
+
+static int 
+request_disconnect (int host, int on_or_off) {
+    struct Scsi_Host *h;
+    struct NCR53c7x0_hostdata *hostdata;
+    if (!(h = find_host (host)))
+	return -1;
+    hostdata = (struct NCR53c7x0_hostdata *) h->hostdata[0];
+    if (on_or_off) 
+	hostdata->options |= OPTION_DISCONNECT;
+    else
+	hostdata->options &= ~OPTION_DISCONNECT;
+    return 0;
+}
+#endif
+
+/*
+ * Function : static void NCR53c7x0_driver_init (struct Scsi_Host *host)
+ *
+ * Purpose : Initialize internal structures, as required on startup, or 
+ *	after a SCSI bus reset.
+ * 
+ * Inputs : host - pointer to this host adapter's structure
+ */
+
+static void 
+NCR53c7x0_driver_init (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    int i, j;
+    u32 *ncrcurrent;
+
+    for (i = 0; i < 16; ++i) {
+	hostdata->request_sense[i] = 0;
+    	for (j = 0; j < 8; ++j) 
+	    hostdata->busy[i][j] = 0;
+	set_synchronous (host, i, /* sxfer */ 0, hostdata->saved_scntl3, 0);
+    }
+    hostdata->issue_queue = NULL;
+    hostdata->running_list = hostdata->finished_queue = 
+	hostdata->ncrcurrent = NULL;
+    for (i = 0, ncrcurrent = (u32 *) hostdata->schedule; 
+	i < host->can_queue; ++i, ncrcurrent += 2) {
+	ncrcurrent[0] = hostdata->NOP_insn;
+	ncrcurrent[1] = 0xdeadbeef;
+    }
+    ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
+    ncrcurrent[1] = (u32) virt_to_bus (hostdata->script) +
+	hostdata->E_wait_reselect;
+    hostdata->reconnect_dsa_head = 0;
+    hostdata->addr_reconnect_dsa_head = (u32) 
+	virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+    hostdata->expecting_iid = 0;
+    hostdata->expecting_sto = 0;
+    if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS) 
+	hostdata->initiate_sdtr = 0xffff; 
+    else
+    	hostdata->initiate_sdtr = 0;
+    hostdata->talked_to = 0;
+    hostdata->idle = 1;
+}
+
+/* 
+ * Function : static int clock_to_ccf_710 (int clock)
+ *
+ * Purpose :  Return the clock conversion factor for a given SCSI clock.
+ *
+ * Inputs : clock - SCSI clock expressed in Hz.
+ *
+ * Returns : ccf on success, -1 on failure.
+ */
+
+static int 
+clock_to_ccf_710 (int clock) {
+    if (clock <= 16666666)
+	return -1;
+    if (clock <= 25000000)
+	return 2; 	/* Divide by 1.0 */
+    else if (clock <= 37500000)
+	return 1; 	/* Divide by 1.5 */
+    else if (clock <= 50000000)
+	return 0;	/* Divide by 2.0 */
+    else if (clock <= 66000000)
+	return 3;	/* Divide by 3.0 */
+    else 
+	return -1;
+}
+    
+/* 
+ * Function : static int NCR53c7x0_init (struct Scsi_Host *host)
+ *
+ * Purpose :  initialize the internal structures for a given SCSI host
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : when this function is called, the chip_type 
+ * 	field of the hostdata structure MUST have been set.
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int 
+NCR53c7x0_init (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    int i, ccf;
+    unsigned char revision;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    /* 
+     * There are some things which we need to know about in order to provide
+     * a semblance of support.  Print 'em if they aren't what we expect, 
+     * otherwise don't add to the noise.
+     * 
+     * -1 means we don't know what to expect.
+     */
+    int val, flags;
+    char buf[32];
+    int expected_id = -1;
+    int expected_clock = -1;
+    int uninitialized = 0;
+#ifdef NO_IO_SPACE
+    int expected_mapping = OPTION_MEMORY_MAPPED;
+#else
+    int expected_mapping = OPTION_IO_MAPPED;
+#endif
+    for (i=0;i<7;i++)
+	hostdata->valid_ids[i] = 1;	/* Default all ID's to scan */
+
+    /* Parse commandline flags */
+    if (check_setup_strings("noasync",&flags,&val,buf))
+    {
+	hostdata->options |= OPTION_NO_ASYNC;
+	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
+    if (check_setup_strings("nosync",&flags,&val,buf))
+    {
+	hostdata->options &= ~(OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
+    if (check_setup_strings("nodisconnect",&flags,&val,buf))
+	hostdata->options &= ~OPTION_DISCONNECT;
+
+    if (check_setup_strings("validids",&flags,&val,buf))
+    {
+	for (i=0;i<7;i++) 
+		hostdata->valid_ids[i] = val & (1<<i);
+    }
+ 
+    if  ((i = check_setup_strings("next",&flags,&val,buf)))
+    {
+	while (i)
+		setup_used[--i] = 1;
+    }
+
+    if (check_setup_strings("opthi",&flags,&val,buf))
+	hostdata->options = (long long)val << 32;
+    if (check_setup_strings("optlo",&flags,&val,buf))
+	hostdata->options |= val;
+
+    NCR53c7x0_local_setup(host);
+    switch (hostdata->chip) {
+    case 710:
+    case 770:
+    	hostdata->dstat_sir_intr = NCR53c7x0_dstat_sir_intr;
+    	hostdata->init_save_regs = NULL;
+    	hostdata->dsa_fixup = NCR53c7xx_dsa_fixup;
+    	hostdata->init_fixup = NCR53c7x0_init_fixup;
+    	hostdata->soft_reset = NCR53c7x0_soft_reset;
+	hostdata->run_tests = NCR53c7xx_run_tests;
+	expected_clock = hostdata->scsi_clock;
+	expected_id = 7;
+    	break;
+    default:
+	printk ("scsi%d : chip type of %d is not supported yet, detaching.\n",
+	    host->host_no, hostdata->chip);
+	scsi_unregister (host);
+	return -1;
+    }
+
+    /* Assign constants accessed by NCR */
+    hostdata->NCR53c7xx_zero = 0;			
+    hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
+    hostdata->NCR53c7xx_msg_abort = ABORT;
+    hostdata->NCR53c7xx_msg_nop = NOP;
+    hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+    if (expected_mapping == -1 || 
+	(hostdata->options & (OPTION_MEMORY_MAPPED)) != 
+	(expected_mapping & OPTION_MEMORY_MAPPED))
+	printk ("scsi%d : using %s mapped access\n", host->host_no, 
+	    (hostdata->options & OPTION_MEMORY_MAPPED) ? "memory" : 
+	    "io");
+
+    hostdata->dmode = (hostdata->chip == 700 || hostdata->chip == 70066) ? 
+	DMODE_REG_00 : DMODE_REG_10;
+    hostdata->istat = ((hostdata->chip / 100) == 8) ? 
+    	ISTAT_REG_800 : ISTAT_REG_700;
+
+/* We have to assume that this may be the first access to the chip, so
+ * we must set EA in DCNTL. */
+
+    NCR53c7x0_write8 (DCNTL_REG, DCNTL_10_EA|DCNTL_10_COM);
+
+
+/* Only the ISTAT register is readable when the NCR is running, so make 
+   sure it's halted. */
+    ncr_halt(host);
+
+/* 
+ * XXX - the NCR53c700 uses bitfielded registers for SCID, SDID, etc,
+ *	as does the 710 with one bit per SCSI ID.  Conversely, the NCR
+ * 	uses a normal, 3 bit binary representation of these values.
+ *
+ * Get the rest of the NCR documentation, and FIND OUT where the change
+ * was.
+ */
+
+#if 0
+	/* May not be able to do this - chip my not have been set up yet */
+	tmp = hostdata->this_id_mask = NCR53c7x0_read8(SCID_REG);
+	for (host->this_id = 0; tmp != 1; tmp >>=1, ++host->this_id);
+#else
+	host->this_id = 7;
+#endif
+
+/*
+ * Note : we should never encounter a board setup for ID0.  So,
+ * 	if we see ID0, assume that it was uninitialized and set it
+ * 	to the industry standard 7.
+ */
+    if (!host->this_id) {
+	printk("scsi%d : initiator ID was %d, changing to 7\n",
+	    host->host_no, host->this_id);
+	host->this_id = 7;
+	hostdata->this_id_mask = 1 << 7;
+	uninitialized = 1;
+    };
+
+    if (expected_id == -1 || host->this_id != expected_id)
+    	printk("scsi%d : using initiator ID %d\n", host->host_no,
+    	    host->this_id);
+
+    /*
+     * Save important registers to allow a soft reset.
+     */
+
+    /*
+     * CTEST7 controls cache snooping, burst mode, and support for 
+     * external differential drivers.  This isn't currently used - the
+     * default value may not be optimal anyway.
+     * Even worse, it may never have been set up since reset.
+     */
+    hostdata->saved_ctest7 = NCR53c7x0_read8(CTEST7_REG) & CTEST7_SAVE;
+    revision = (NCR53c7x0_read8(CTEST8_REG) & 0xF0) >> 4;
+    switch (revision) {
+	case 1: revision = 0;    break;
+	case 2: revision = 1;    break;
+	case 4: revision = 2;    break;
+	case 8: revision = 3;    break;
+	default: revision = 255; break;
+    }
+    printk("scsi%d: Revision 0x%x\n",host->host_no,revision);
+
+    if ((revision == 0 || revision == 255) && (hostdata->options & (OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS)))
+    {
+	printk ("scsi%d: Disabling sync working and disconnect/reselect\n",
+							host->host_no);
+	hostdata->options &= ~(OPTION_SYNCHRONOUS|OPTION_DISCONNECT|OPTION_ALWAYS_SYNCHRONOUS);
+    }
+
+    /*
+     * On NCR53c700 series chips, DCNTL controls the SCSI clock divisor,
+     * on 800 series chips, it allows for a totem-pole IRQ driver.
+     * NOTE saved_dcntl currently overwritten in init function.
+     * The value read here may be garbage anyway, MVME16x board at least
+     * does not initialise chip if kernel arrived via tftp.
+     */
+
+    hostdata->saved_dcntl = NCR53c7x0_read8(DCNTL_REG);
+
+    /*
+     * DMODE controls DMA burst length, and on 700 series chips,
+     * 286 mode and bus width  
+     * NOTE:  On MVME16x, chip may have been reset, so this could be a
+     * power-on/reset default value.
+     */
+    hostdata->saved_dmode = NCR53c7x0_read8(hostdata->dmode);
+
+    /* 
+     * Now that burst length and enabled/disabled status is known, 
+     * clue the user in on it.  
+     */
+   
+    ccf = clock_to_ccf_710 (expected_clock);
+
+    for (i = 0; i < 16; ++i) 
+	hostdata->cmd_allocated[i] = 0;
+
+    if (hostdata->init_save_regs)
+    	hostdata->init_save_regs (host);
+    if (hostdata->init_fixup)
+    	hostdata->init_fixup (host);
+
+    if (!the_template) {
+	the_template = host->hostt;
+	first_host = host;
+    }
+
+    /* 
+     * Linux SCSI drivers have always been plagued with initialization 
+     * problems - some didn't work with the BIOS disabled since they expected
+     * initialization from it, some didn't work when the networking code
+     * was enabled and registers got scrambled, etc.
+     *
+     * To avoid problems like this, in the future, we will do a soft 
+     * reset on the SCSI chip, taking it back to a sane state.
+     */
+
+    hostdata->soft_reset (host);
+
+#if 1
+    hostdata->debug_count_limit = -1;
+#else
+    hostdata->debug_count_limit = 1;
+#endif
+    hostdata->intrs = -1;
+    hostdata->resets = -1;
+    memcpy ((void *) hostdata->synchronous_want, (void *) sdtr_message, 
+	sizeof (hostdata->synchronous_want));
+
+    NCR53c7x0_driver_init (host);
+
+    if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7xx", host))
+    {
+	printk("scsi%d : IRQ%d not free, detaching\n",
+		host->host_no, host->irq);
+	goto err_unregister;
+    } 
+
+    if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
+        (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+    	/* XXX Should disable interrupts, etc. here */
+	goto err_free_irq;
+    } else {
+	if (host->io_port)  {
+	    host->n_io_port = 128;
+	    if (!request_region (host->io_port, host->n_io_port, "ncr53c7xx"))
+		goto err_free_irq;
+	}
+    }
+    
+    if (NCR53c7x0_read8 (SBCL_REG) & SBCL_BSY) {
+	printk ("scsi%d : bus wedge, doing SCSI reset\n", host->host_no);
+	hard_reset (host);
+    }
+    return 0;
+
+ err_free_irq:
+    free_irq(host->irq,  NCR53c7x0_intr);
+ err_unregister:
+    scsi_unregister(host);
+    return -1;
+}
+
+/* 
+ * Function : int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+ *	unsigned long base, int io_port, int irq, int dma, long long options,
+ *	int clock);
+ *
+ * Purpose : initializes a NCR53c7,8x0 based on base addresses,
+ *	IRQ, and DMA channel.	
+ *	
+ * Inputs : tpnt - Template for this SCSI adapter, board - board level
+ *	product, chip - 710
+ * 
+ * Returns : 0 on success, -1 on failure.
+ *
+ */
+
+int 
+ncr53c7xx_init (Scsi_Host_Template *tpnt, int board, int chip,
+    unsigned long base, int io_port, int irq, int dma, 
+    long long options, int clock)
+{
+    struct Scsi_Host *instance;
+    struct NCR53c7x0_hostdata *hostdata;
+    char chip_str[80];
+    int script_len = 0, dsa_len = 0, size = 0, max_cmd_size = 0,
+	schedule_size = 0, ok = 0;
+    void *tmp;
+    unsigned long page;
+
+    switch (chip) {
+    case 710:
+    case 770:
+	schedule_size = (tpnt->can_queue + 1) * 8 /* JUMP instruction size */;
+	script_len = NCR53c7xx_script_len;
+    	dsa_len = NCR53c7xx_dsa_len;
+    	options |= OPTION_INTFLY;
+    	sprintf (chip_str, "NCR53c%d", chip);
+    	break;
+    default:
+    	printk("scsi-ncr53c7xx : unsupported SCSI chip %d\n", chip);
+    	return -1;
+    }
+
+    printk("scsi-ncr53c7xx : %s at memory 0x%lx, io 0x%x, irq %d",
+    	chip_str, base, io_port, irq);
+    if (dma == DMA_NONE)
+    	printk("\n");
+    else 
+    	printk(", dma %d\n", dma);
+
+    if (options & OPTION_DEBUG_PROBE_ONLY) {
+    	printk ("scsi-ncr53c7xx : probe only enabled, aborting initialization\n");
+    	return -1;
+    }
+
+    max_cmd_size = sizeof(struct NCR53c7x0_cmd) + dsa_len +
+    	/* Size of dynamic part of command structure : */
+	2 * /* Worst case : we don't know if we need DATA IN or DATA out */
+		( 2 * /* Current instructions per scatter/gather segment */ 
+        	  tpnt->sg_tablesize + 
+                  3 /* Current startup / termination required per phase */
+		) *
+	8 /* Each instruction is eight bytes */;
+
+    /* Allocate fixed part of hostdata, dynamic part to hold appropriate
+       SCSI SCRIPT(tm) plus a single, maximum-sized NCR53c7x0_cmd structure.
+
+       We need a NCR53c7x0_cmd structure for scan_scsis() when we are 
+       not loaded as a module, and when we're loaded as a module, we 
+       can't use a non-dynamically allocated structure because modules
+       are vmalloc()'d, which can allow structures to cross page 
+       boundaries and breaks our physical/virtual address assumptions
+       for DMA.
+
+       So, we stick it past the end of our hostdata structure.
+
+       ASSUMPTION : 
+       	 Regardless of how many simultaneous SCSI commands we allow,
+	 the probe code only executes a _single_ instruction at a time,
+	 so we only need one here, and don't need to allocate NCR53c7x0_cmd
+	 structures for each target until we are no longer in scan_scsis
+	 and kmalloc() has become functional (memory_init() happens 
+	 after all device driver initialization).
+    */
+
+    size = sizeof(struct NCR53c7x0_hostdata) + script_len + 
+    /* Note that alignment will be guaranteed, since we put the command
+       allocated at probe time after the fixed-up SCSI script, which 
+       consists of 32 bit words, aligned on a 32 bit boundary.  But
+       on a 64bit machine we need 8 byte alignment for hostdata->free, so
+       we add in another 4 bytes to take care of potential misalignment
+       */
+	(sizeof(void *) - sizeof(u32)) + max_cmd_size + schedule_size;
+
+    page = __get_free_pages(GFP_ATOMIC,1);
+    if(page==0)
+    {
+    	printk(KERN_ERR "53c7xx: out of memory.\n");
+    	return -ENOMEM;
+    }
+#ifdef FORCE_DSA_ALIGNMENT
+    /*
+     * 53c710 rev.0 doesn't have an add-with-carry instruction.
+     * Ensure we allocate enough memory to force DSA alignment.
+    */
+    size += 256;
+#endif
+    /* Size should be < 8K, so we can fit it in two pages. */
+    if (size > 8192) {
+      printk(KERN_ERR "53c7xx: hostdata > 8K\n");
+      return -1;
+    }
+
+    instance = scsi_register (tpnt, 4);
+    if (!instance)
+    {
+        free_page(page);
+	return -1;
+    }
+    instance->hostdata[0] = page;
+    memset((void *)instance->hostdata[0], 0, 8192);
+    cache_push(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    cache_clear(virt_to_phys((void *)(instance->hostdata[0])), 8192);
+    kernel_set_cachemode((void *)instance->hostdata[0], 8192, IOMAP_NOCACHE_SER);
+
+    /* FIXME : if we ever support an ISA NCR53c7xx based board, we
+       need to check if the chip is running in a 16 bit mode, and if so 
+       unregister it if it is past the 16M (0x1000000) mark */
+
+    hostdata = (struct NCR53c7x0_hostdata *)instance->hostdata[0];
+    hostdata->size = size;
+    hostdata->script_count = script_len / sizeof(u32);
+    hostdata->board = board;
+    hostdata->chip = chip;
+
+    /*
+     * Being memory mapped is more desirable, since 
+     *
+     * - Memory accesses may be faster.
+     *
+     * - The destination and source address spaces are the same for 
+     *	 all instructions, meaning we don't have to twiddle dmode or 
+     *	 any other registers.
+     *
+     * So, we try for memory mapped, and if we don't get it,
+     * we go for port mapped, and that failing we tell the user
+     * it can't work.
+     */
+
+    if (base) {
+	instance->base = base;
+	/* Check for forced I/O mapping */
+    	if (!(options & OPTION_IO_MAPPED)) {
+	    options |= OPTION_MEMORY_MAPPED;
+	    ok = 1;
+	}
+    } else {
+	options &= ~OPTION_MEMORY_MAPPED;
+    }
+
+    if (io_port) {
+	instance->io_port = io_port;
+	options |= OPTION_IO_MAPPED;
+	ok = 1;
+    } else {
+	options &= ~OPTION_IO_MAPPED;
+    }
+
+    if (!ok) {
+	printk ("scsi%d : not initializing, no I/O or memory mapping known \n",
+	    instance->host_no);
+	scsi_unregister (instance);
+	return -1;
+    }
+    instance->irq = irq;
+    instance->dma_channel = dma;
+
+    hostdata->options = options;
+    hostdata->dsa_len = dsa_len;
+    hostdata->max_cmd_size = max_cmd_size;
+    hostdata->num_cmds = 1;
+    hostdata->scsi_clock = clock;
+    /* Initialize single command */
+    tmp = (hostdata->script + hostdata->script_count);
+#ifdef FORCE_DSA_ALIGNMENT
+    {
+	void *t = ROUNDUP(tmp, void *);
+	if (((u32)t & 0xff) > CmdPageStart)
+	    t = (void *)((u32)t + 255);
+	t = (void *)(((u32)t & ~0xff) + CmdPageStart);
+        hostdata->free = t;
+#if 0
+	printk ("scsi: Registered size increased by 256 to %d\n", size);
+	printk ("scsi: CmdPageStart = 0x%02x\n", CmdPageStart);
+	printk ("scsi: tmp = 0x%08x, hostdata->free set to 0x%08x\n",
+			(u32)tmp, (u32)t);
+#endif
+    }
+#else
+    hostdata->free = ROUNDUP(tmp, void *);
+#endif
+    hostdata->free->real = tmp;
+    hostdata->free->size = max_cmd_size;
+    hostdata->free->free = NULL;
+    hostdata->free->next = NULL;
+    hostdata->extra_allocate = 0;
+
+    /* Allocate command start code space */
+    hostdata->schedule = (chip == 700 || chip == 70066) ?
+	NULL : (u32 *) ((char *)hostdata->free + max_cmd_size);
+
+/* 
+ * For diagnostic purposes, we don't really care how fast things blaze.
+ * For profiling, we want to access the 800ns resolution system clock,
+ * using a 'C' call on the host processor.
+ *
+ * Therefore, there's no need for the NCR chip to directly manipulate
+ * this data, and we should put it wherever is most convenient for 
+ * Linux.
+ */
+    if (track_events) 
+	hostdata->events = (struct NCR53c7x0_event *) (track_events ? 
+	    vmalloc (sizeof (struct NCR53c7x0_event) * track_events) : NULL);
+    else
+	hostdata->events = NULL;
+
+    if (hostdata->events) {
+	memset ((void *) hostdata->events, 0, sizeof(struct NCR53c7x0_event) *
+	    track_events);	
+	hostdata->event_size = track_events;
+	hostdata->event_index = 0;
+    } else 
+	hostdata->event_size = 0;
+
+    return NCR53c7x0_init(instance);
+}
+
+
+/* 
+ * Function : static void NCR53c7x0_init_fixup (struct Scsi_Host *host)
+ *
+ * Purpose :  copy and fixup the SCSI SCRIPTS(tm) code for this device.
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ */
+
+static void 
+NCR53c7x0_init_fixup (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    unsigned char tmp;
+    int i, ncr_to_memory, memory_to_ncr;
+    u32 base;
+    NCR53c7x0_local_setup(host);
+
+
+    /* XXX - NOTE : this code MUST be made endian aware */
+    /*  Copy code into buffer that was allocated at detection time.  */
+    memcpy ((void *) hostdata->script, (void *) SCRIPT, 
+	sizeof(SCRIPT));
+    /* Fixup labels */
+    for (i = 0; i < PATCHES; ++i) 
+	hostdata->script[LABELPATCHES[i]] += 
+    	    virt_to_bus(hostdata->script);
+    /* Fixup addresses of constants that used to be EXTERNAL */
+
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_abort, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_msg_abort)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_msg_reject, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_msg_reject)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_zero, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_zero)));
+    patch_abs_32 (hostdata->script, 0, NCR53c7xx_sink, 
+    	virt_to_bus(&(hostdata->NCR53c7xx_sink)));
+    patch_abs_32 (hostdata->script, 0, NOP_insn,
+	virt_to_bus(&(hostdata->NOP_insn)));
+    patch_abs_32 (hostdata->script, 0, schedule,
+	virt_to_bus((void *) hostdata->schedule));
+
+    /* Fixup references to external variables: */
+    for (i = 0; i < EXTERNAL_PATCHES_LEN; ++i)
+       hostdata->script[EXTERNAL_PATCHES[i].offset] +=
+         virt_to_bus(EXTERNAL_PATCHES[i].address);
+
+    /* 
+     * Fixup absolutes set at boot-time.
+     * 
+     * All non-code absolute variables suffixed with "dsa_" and "int_"
+     * are constants, and need no fixup provided the assembler has done 
+     * it for us (I don't know what the "real" NCR assembler does in 
+     * this case, my assembler does the right magic).
+     */
+
+    patch_abs_rwri_data (hostdata->script, 0, dsa_save_data_pointer, 
+    	Ent_dsa_code_save_data_pointer - Ent_dsa_zero);
+    patch_abs_rwri_data (hostdata->script, 0, dsa_restore_pointers,
+    	Ent_dsa_code_restore_pointers - Ent_dsa_zero);
+    patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect,
+    	Ent_dsa_code_check_reselect - Ent_dsa_zero);
+
+    /*
+     * Just for the hell of it, preserve the settings of 
+     * Burst Length and Enable Read Line bits from the DMODE 
+     * register.  Make sure SCRIPTS start automagically.
+     */
+
+#if defined(CONFIG_MVME16x) || defined(CONFIG_BVME6000)
+    /* We know better what we want than 16xBug does! */
+    tmp = DMODE_10_BL_8 | DMODE_10_FC2;
+#else
+    tmp = NCR53c7x0_read8(DMODE_REG_10);
+    tmp &= (DMODE_BL_MASK | DMODE_10_FC2 | DMODE_10_FC1 | DMODE_710_PD |
+								DMODE_710_UO);
+#endif
+
+    if (!(hostdata->options & OPTION_MEMORY_MAPPED)) {
+    	base = (u32) host->io_port;
+    	memory_to_ncr = tmp|DMODE_800_DIOM;
+    	ncr_to_memory = tmp|DMODE_800_SIOM;
+    } else {
+    	base = virt_to_bus((void *)host->base);
+	memory_to_ncr = ncr_to_memory = tmp;
+    }
+
+    /* SCRATCHB_REG_10 == SCRATCHA_REG_800, as it happens */
+    patch_abs_32 (hostdata->script, 0, addr_scratch, base + SCRATCHA_REG_800);
+    patch_abs_32 (hostdata->script, 0, addr_temp, base + TEMP_REG);
+    patch_abs_32 (hostdata->script, 0, addr_dsa, base + DSA_REG);
+
+    /*
+     * I needed some variables in the script to be accessible to 
+     * both the NCR chip and the host processor. For these variables,
+     * I made the arbitrary decision to store them directly in the 
+     * hostdata structure rather than in the RELATIVE area of the 
+     * SCRIPTS.
+     */
+    
+
+    patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_memory, tmp);
+    patch_abs_rwri_data (hostdata->script, 0, dmode_memory_to_ncr, memory_to_ncr);
+    patch_abs_rwri_data (hostdata->script, 0, dmode_ncr_to_memory, ncr_to_memory);
+
+    patch_abs_32 (hostdata->script, 0, msg_buf, 
+	virt_to_bus((void *)&(hostdata->msg_buf)));
+    patch_abs_32 (hostdata->script, 0, reconnect_dsa_head, 
+    	virt_to_bus((void *)&(hostdata->reconnect_dsa_head)));
+    patch_abs_32 (hostdata->script, 0, addr_reconnect_dsa_head, 
+	virt_to_bus((void *)&(hostdata->addr_reconnect_dsa_head)));
+    patch_abs_32 (hostdata->script, 0, reselected_identify, 
+    	virt_to_bus((void *)&(hostdata->reselected_identify)));
+/* reselected_tag is currently unused */
+#if 0
+    patch_abs_32 (hostdata->script, 0, reselected_tag, 
+    	virt_to_bus((void *)&(hostdata->reselected_tag)));
+#endif
+
+    patch_abs_32 (hostdata->script, 0, test_dest, 
+	virt_to_bus((void*)&hostdata->test_dest));
+    patch_abs_32 (hostdata->script, 0, test_src, 
+	virt_to_bus(&hostdata->test_source));
+    patch_abs_32 (hostdata->script, 0, saved_dsa,
+	virt_to_bus((void *)&hostdata->saved2_dsa));
+    patch_abs_32 (hostdata->script, 0, emulfly,
+	virt_to_bus((void *)&hostdata->emulated_intfly));
+
+    patch_abs_rwri_data (hostdata->script, 0, dsa_check_reselect, 
+	(unsigned char)(Ent_dsa_code_check_reselect - Ent_dsa_zero));
+
+/* These are for event logging; the ncr_event enum contains the 
+   actual interrupt numbers. */
+#ifdef A_int_EVENT_SELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT, (u32) EVENT_SELECT);
+#endif
+#ifdef A_int_EVENT_DISCONNECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_DISCONNECT, (u32) EVENT_DISCONNECT);
+#endif
+#ifdef A_int_EVENT_RESELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT, (u32) EVENT_RESELECT);
+#endif
+#ifdef A_int_EVENT_COMPLETE
+   patch_abs_32 (hostdata->script, 0, int_EVENT_COMPLETE, (u32) EVENT_COMPLETE);
+#endif
+#ifdef A_int_EVENT_IDLE
+   patch_abs_32 (hostdata->script, 0, int_EVENT_IDLE, (u32) EVENT_IDLE);
+#endif
+#ifdef A_int_EVENT_SELECT_FAILED
+   patch_abs_32 (hostdata->script, 0, int_EVENT_SELECT_FAILED, 
+	(u32) EVENT_SELECT_FAILED);
+#endif
+#ifdef A_int_EVENT_BEFORE_SELECT
+   patch_abs_32 (hostdata->script, 0, int_EVENT_BEFORE_SELECT,
+	(u32) EVENT_BEFORE_SELECT);
+#endif
+#ifdef A_int_EVENT_RESELECT_FAILED
+   patch_abs_32 (hostdata->script, 0, int_EVENT_RESELECT_FAILED, 
+	(u32) EVENT_RESELECT_FAILED);
+#endif
+
+    /*
+     * Make sure the NCR and Linux code agree on the location of 
+     * certain fields.
+     */
+
+    hostdata->E_accept_message = Ent_accept_message;
+    hostdata->E_command_complete = Ent_command_complete;		
+    hostdata->E_cmdout_cmdout = Ent_cmdout_cmdout;
+    hostdata->E_data_transfer = Ent_data_transfer;
+    hostdata->E_debug_break = Ent_debug_break;	
+    hostdata->E_dsa_code_template = Ent_dsa_code_template;
+    hostdata->E_dsa_code_template_end = Ent_dsa_code_template_end;
+    hostdata->E_end_data_transfer = Ent_end_data_transfer;
+    hostdata->E_initiator_abort = Ent_initiator_abort;
+    hostdata->E_msg_in = Ent_msg_in;
+    hostdata->E_other_transfer = Ent_other_transfer;
+    hostdata->E_other_in = Ent_other_in;
+    hostdata->E_other_out = Ent_other_out;
+    hostdata->E_reject_message = Ent_reject_message;
+    hostdata->E_respond_message = Ent_respond_message;
+    hostdata->E_select = Ent_select;
+    hostdata->E_select_msgout = Ent_select_msgout;
+    hostdata->E_target_abort = Ent_target_abort;
+#ifdef Ent_test_0
+    hostdata->E_test_0 = Ent_test_0;
+#endif
+    hostdata->E_test_1 = Ent_test_1;
+    hostdata->E_test_2 = Ent_test_2;
+#ifdef Ent_test_3
+    hostdata->E_test_3 = Ent_test_3;
+#endif
+    hostdata->E_wait_reselect = Ent_wait_reselect;
+    hostdata->E_dsa_code_begin = Ent_dsa_code_begin;
+
+    hostdata->dsa_cmdout = A_dsa_cmdout;
+    hostdata->dsa_cmnd = A_dsa_cmnd;
+    hostdata->dsa_datain = A_dsa_datain;
+    hostdata->dsa_dataout = A_dsa_dataout;
+    hostdata->dsa_end = A_dsa_end;			
+    hostdata->dsa_msgin = A_dsa_msgin;
+    hostdata->dsa_msgout = A_dsa_msgout;
+    hostdata->dsa_msgout_other = A_dsa_msgout_other;
+    hostdata->dsa_next = A_dsa_next;
+    hostdata->dsa_select = A_dsa_select;
+    hostdata->dsa_start = Ent_dsa_code_template - Ent_dsa_zero;
+    hostdata->dsa_status = A_dsa_status;
+    hostdata->dsa_jump_dest = Ent_dsa_code_fix_jump - Ent_dsa_zero + 
+	8 /* destination operand */;
+
+    /* sanity check */
+    if (A_dsa_fields_start != Ent_dsa_code_template_end - 
+    	Ent_dsa_zero) 
+    	printk("scsi%d : NCR dsa_fields start is %d not %d\n",
+    	    host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end - 
+    	    Ent_dsa_zero);
+
+    printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
+	virt_to_bus(hostdata->script), hostdata->script);
+}
+
+/*
+ * Function : static int NCR53c7xx_run_tests (struct Scsi_Host *host)
+ *
+ * Purpose : run various verification tests on the NCR chip, 
+ *	including interrupt generation, and proper bus mastering
+ * 	operation.
+ * 
+ * Inputs : host - a properly initialized Scsi_Host structure
+ *
+ * Preconditions : the NCR chip must be in a halted state.
+ *
+ * Returns : 0 if all tests were successful, -1 on error.
+ * 
+ */
+
+static int 
+NCR53c7xx_run_tests (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    unsigned long timeout;
+    u32 start;
+    int failed, i;
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    /* The NCR chip _must_ be idle to run the test scripts */
+
+    local_irq_save(flags);
+    if (!hostdata->idle) {
+	printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+	local_irq_restore(flags);
+	return -1;
+    }
+
+    /* 
+     * Check for functional interrupts, this could work as an
+     * autoprobe routine.
+     */
+
+    if ((hostdata->options & OPTION_DEBUG_TEST1) && 
+	    hostdata->state != STATE_DISABLED) {
+	hostdata->idle = 0;
+	hostdata->test_running = 1;
+	hostdata->test_completed = -1;
+	hostdata->test_dest = 0;
+	hostdata->test_source = 0xdeadbeef;
+	start = virt_to_bus (hostdata->script) + hostdata->E_test_1;
+    	hostdata->state = STATE_RUNNING;
+	printk ("scsi%d : test 1", host->host_no);
+	NCR53c7x0_write32 (DSP_REG, start);
+	if (hostdata->options & OPTION_DEBUG_TRACE)
+	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM |
+						DCNTL_STD);
+	printk (" started\n");
+	local_irq_restore(flags);
+
+	/* 
+	 * This is currently a .5 second timeout, since (in theory) no slow 
+	 * board will take that long.  In practice, we've seen one 
+	 * pentium which occassionally fails with this, but works with 
+	 * 10 times as much?
+	 */
+
+	timeout = jiffies + 5 * HZ / 10;
+	while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
+		barrier();
+
+	failed = 1;
+	if (hostdata->test_completed == -1)
+	    printk ("scsi%d : driver test 1 timed out%s\n",host->host_no ,
+		(hostdata->test_dest == 0xdeadbeef) ? 
+		    " due to lost interrupt.\n"
+		    "         Please verify that the correct IRQ is being used for your board,\n"
+		    : "");
+	else if (hostdata->test_completed != 1) 
+	    printk ("scsi%d : test 1 bad interrupt value (%d)\n", 
+		host->host_no, hostdata->test_completed);
+	else 
+	    failed = (hostdata->test_dest != 0xdeadbeef);
+
+	if (hostdata->test_dest != 0xdeadbeef) {
+	    printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
+                    "         probable cache invalidation problem.  Please configure caching\n"
+		    "         as write-through or disabled\n",
+		host->host_no, hostdata->test_dest);
+	}
+
+	if (failed) {
+	    printk ("scsi%d : DSP = 0x%p (script at 0x%p, start at 0x%x)\n",
+		host->host_no, bus_to_virt(NCR53c7x0_read32(DSP_REG)),
+		hostdata->script, start);
+	    printk ("scsi%d : DSPS = 0x%x\n", host->host_no,
+		NCR53c7x0_read32(DSPS_REG));
+	    local_irq_restore(flags);
+	    return -1;
+	}
+    	hostdata->test_running = 0;
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_TEST2) && 
+	hostdata->state != STATE_DISABLED) {
+	u32 dsa[48];
+    	unsigned char identify = IDENTIFY(0, 0);
+	unsigned char cmd[6];
+	unsigned char data[36];
+    	unsigned char status = 0xff;
+    	unsigned char msg = 0xff;
+
+    	cmd[0] = INQUIRY;
+    	cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
+    	cmd[4] = sizeof(data); 
+
+    	dsa[2] = 1;
+    	dsa[3] = virt_to_bus(&identify);
+    	dsa[4] = 6;
+    	dsa[5] = virt_to_bus(&cmd);
+    	dsa[6] = sizeof(data);
+    	dsa[7] = virt_to_bus(&data);
+    	dsa[8] = 1;
+    	dsa[9] = virt_to_bus(&status);
+    	dsa[10] = 1;
+    	dsa[11] = virt_to_bus(&msg);
+
+	for (i = 0; i < 6; ++i) {
+#ifdef VALID_IDS
+	    if (!hostdata->valid_ids[i])
+		continue;
+#endif
+	    local_irq_disable();
+	    if (!hostdata->idle) {
+		printk ("scsi%d : chip not idle, aborting tests\n", host->host_no);
+		local_irq_restore(flags);
+		return -1;
+	    }
+
+	    /* 710: bit mapped scsi ID, async   */
+            dsa[0] = (1 << i) << 16;
+	    hostdata->idle = 0;
+	    hostdata->test_running = 2;
+	    hostdata->test_completed = -1;
+	    start = virt_to_bus(hostdata->script) + hostdata->E_test_2;
+	    hostdata->state = STATE_RUNNING;
+	    NCR53c7x0_write32 (DSA_REG, virt_to_bus(dsa));
+	    NCR53c7x0_write32 (DSP_REG, start);
+	    if (hostdata->options & OPTION_DEBUG_TRACE)
+	        NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+				DCNTL_SSM | DCNTL_STD);
+	    local_irq_restore(flags);
+
+	    timeout = jiffies + 5 * HZ;	/* arbitrary */
+	    while ((hostdata->test_completed == -1) && time_before(jiffies, timeout))
+	    	barrier();
+
+	    NCR53c7x0_write32 (DSA_REG, 0);
+
+	    if (hostdata->test_completed == 2) {
+		data[35] = 0;
+		printk ("scsi%d : test 2 INQUIRY to target %d, lun 0 : %s\n",
+		    host->host_no, i, data + 8);
+		printk ("scsi%d : status ", host->host_no);
+		print_status (status);
+		printk ("\nscsi%d : message ", host->host_no);
+		print_msg (&msg);
+		printk ("\n");
+	    } else if (hostdata->test_completed == 3) {
+		printk("scsi%d : test 2 no connection with target %d\n",
+		    host->host_no, i);
+		if (!hostdata->idle) {
+		    printk("scsi%d : not idle\n", host->host_no);
+		    local_irq_restore(flags);
+		    return -1;
+		}
+	    } else if (hostdata->test_completed == -1) {
+		printk ("scsi%d : test 2 timed out\n", host->host_no);
+		local_irq_restore(flags);
+		return -1;
+	    } 
+	    hostdata->test_running = 0;
+	}
+    }
+
+    local_irq_restore(flags);
+    return 0;
+}
+
+/*
+ * Function : static void NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : copy the NCR53c8xx dsa structure into cmd's dsa buffer,
+ * 	performing all necessary relocation.
+ *
+ * Inputs : cmd, a NCR53c7x0_cmd structure with a dsa area large
+ *	enough to hold the NCR53c8xx dsa.
+ */
+
+static void 
+NCR53c7xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
+    Scsi_Cmnd *c = cmd->cmd;
+    struct Scsi_Host *host = c->device->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata[0];
+    int i;
+
+    memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
+    	hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+
+    /* 
+     * Note : within the NCR 'C' code, dsa points to the _start_
+     * of the DSA structure, and _not_ the offset of dsa_zero within
+     * that structure used to facilitate shorter signed offsets
+     * for the 8 bit ALU.
+     * 
+     * The implications of this are that 
+     * 
+     * - 32 bit A_dsa_* absolute values require an additional 
+     * 	 dsa_zero added to their value to be correct, since they are 
+     *   relative to dsa_zero which is in essentially a separate
+     *   space from the code symbols.
+     *
+     * - All other symbols require no special treatment.
+     */
+
+    patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_lun, c->device->lun);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+	dsa_temp_addr_next, virt_to_bus(&cmd->dsa_next_addr));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_next, virt_to_bus(cmd->dsa) + Ent_dsa_zero -
+	Ent_dsa_code_template + A_dsa_next);
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
+    	dsa_temp_sync, virt_to_bus((void *)hostdata->sync[c->device->id].script));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32), 
+    	dsa_sscf_710, virt_to_bus((void *)&hostdata->sync[c->device->id].sscf_710));
+    patch_abs_tci_data (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	    dsa_temp_target, 1 << c->device->id);
+    /* XXX - new pointer stuff */
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_saved_pointer, virt_to_bus(&cmd->saved_data_pointer));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_saved_residual, virt_to_bus(&cmd->saved_residual));
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+    	dsa_temp_addr_residual, virt_to_bus(&cmd->residual));
+
+    /*  XXX - new start stuff */
+
+    patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
+	dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+}
+
+/* 
+ * Function : run_process_issue_queue (void)
+ * 
+ * Purpose : insure that the coroutine is running and will process our 
+ * 	request.  process_issue_queue_running is checked/set here (in an 
+ *	inline function) rather than in process_issue_queue itself to reduce 
+ * 	the chances of stack overflow.
+ *
+ */
+
+static volatile int process_issue_queue_running = 0;
+
+static __inline__ void 
+run_process_issue_queue(void) {
+    unsigned long flags;
+    local_irq_save(flags);
+    if (!process_issue_queue_running) {
+	process_issue_queue_running = 1;
+        process_issue_queue(flags);
+	/* 
+         * process_issue_queue_running is cleared in process_issue_queue 
+	 * once it can't do more work, and process_issue_queue exits with 
+	 * interrupts disabled.
+	 */
+    }
+    local_irq_restore(flags);
+}
+
+/*
+ * Function : static void abnormal_finished (struct NCR53c7x0_cmd *cmd, int
+ *	result)
+ *
+ * Purpose : mark SCSI command as finished, OR'ing the host portion 
+ *	of the result word into the result field of the corresponding
+ *	Scsi_Cmnd structure, and removing it from the internal queues.
+ *
+ * Inputs : cmd - command, result - entire result field
+ *
+ * Preconditions : the 	NCR chip should be in a halted state when 
+ *	abnormal_finished is run, since it modifies structures which
+ *	the NCR expects to have exclusive access to.
+ */
+
+static void 
+abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
+    Scsi_Cmnd *c = cmd->cmd;
+    struct Scsi_Host *host = c->device->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata[0];
+    unsigned long flags;
+    int left, found;
+    volatile struct NCR53c7x0_cmd * linux_search;
+    volatile struct NCR53c7x0_cmd * volatile *linux_prev;
+    volatile u32 *ncr_prev, *ncrcurrent, ncr_search;
+
+#if 0
+    printk ("scsi%d: abnormal finished\n", host->host_no);
+#endif
+
+    local_irq_save(flags);
+    found = 0;
+    /* 
+     * Traverse the NCR issue array until we find a match or run out 
+     * of instructions.  Instructions in the NCR issue array are 
+     * either JUMP or NOP instructions, which are 2 words in length.
+     */
+
+
+    for (found = 0, left = host->can_queue, ncrcurrent = hostdata->schedule; 
+	left > 0; --left, ncrcurrent += 2)
+    {
+	if (issue_to_cmd (host, hostdata, (u32 *) ncrcurrent) == cmd) 
+	{
+	    ncrcurrent[0] = hostdata->NOP_insn;
+	    ncrcurrent[1] = 0xdeadbeef;
+	    ++found;
+	    break;
+	}
+    }
+	
+    /* 
+     * Traverse the NCR reconnect list of DSA structures until we find 
+     * a pointer to this dsa or have found too many command structures.  
+     * We let prev point at the next field of the previous element or 
+     * head of the list, so we don't do anything different for removing 
+     * the head element.  
+     */
+
+    for (left = host->can_queue,
+	    ncr_search = hostdata->reconnect_dsa_head, 
+	    ncr_prev = &hostdata->reconnect_dsa_head;
+	left >= 0 && ncr_search && 
+	    ((char*)bus_to_virt(ncr_search) + hostdata->dsa_start) 
+		!= (char *) cmd->dsa;
+	ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) + 
+	    hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+
+    if (left < 0) 
+	printk("scsi%d: loop detected in ncr reconncect list\n",
+	    host->host_no);
+    else if (ncr_search) {
+	if (found)
+	    printk("scsi%d: scsi %ld in ncr issue array and reconnect lists\n",
+		host->host_no, c->pid);
+	else {
+	    volatile u32 * next = (u32 *) 
+	    	((char *)bus_to_virt(ncr_search) + hostdata->dsa_next);
+	    *ncr_prev = *next;
+/* If we're at the tail end of the issue queue, update that pointer too. */
+	    found = 1;
+	}
+    }
+
+    /*
+     * Traverse the host running list until we find this command or discover
+     * we have too many elements, pointing linux_prev at the next field of the 
+     * linux_previous element or head of the list, search at this element.
+     */
+
+    for (left = host->can_queue, linux_search = hostdata->running_list, 
+	    linux_prev = &hostdata->running_list;
+	left >= 0 && linux_search && linux_search != cmd;
+	linux_prev = &(linux_search->next), 
+	    linux_search = linux_search->next, --left);
+    
+    if (left < 0) 
+	printk ("scsi%d: loop detected in host running list for scsi pid %ld\n",
+	    host->host_no, c->pid);
+    else if (linux_search) {
+	*linux_prev = linux_search->next;
+	--hostdata->busy[c->device->id][c->device->lun];
+    }
+
+    /* Return the NCR command structure to the free list */
+    cmd->next = hostdata->free;
+    hostdata->free = cmd;
+    c->host_scribble = NULL;
+
+    /* And return */
+    c->result = result;
+    c->scsi_done(c);
+
+    local_irq_restore(flags);
+    run_process_issue_queue();
+}
+
+/* 
+ * Function : static void intr_break (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose :  Handler for breakpoint interrupts from a SCSI script
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * 	cmd - pointer to the command (if any) dsa was pointing 
+ * 	to.
+ *
+ */
+
+static void 
+intr_break (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_break *bp;
+#if 0
+    Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+#endif
+    u32 *dsp;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];		
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    /*
+     * Find the break point corresponding to this address, and 
+     * dump the appropriate debugging information to standard 
+     * output.  
+     */
+    local_irq_save(flags);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+    for (bp = hostdata->breakpoints; bp && bp->address != dsp; 
+    	bp = bp->next);
+    if (!bp) 
+    	panic("scsi%d : break point interrupt from %p with no breakpoint!",
+    	    host->host_no, dsp);
+
+    /*
+     * Configure the NCR chip for manual start mode, so that we can 
+     * point the DSP register at the instruction that follows the 
+     * INT int_debug_break instruction.
+     */
+
+    NCR53c7x0_write8 (hostdata->dmode, 
+	NCR53c7x0_read8(hostdata->dmode)|DMODE_MAN);
+
+    /*
+     * And update the DSP register, using the size of the old 
+     * instruction in bytes.
+     */
+
+    local_irq_restore(flags);
+}
+/*
+ * Function : static void print_synchronous (const char *prefix, 
+ *	const unsigned char *msg)
+ * 
+ * Purpose : print a pretty, user and machine parsable representation
+ *	of a SDTR message, including the "real" parameters, data
+ *	clock so we can tell transfer rate at a glance.
+ *
+ * Inputs ; prefix - text to prepend, msg - SDTR message (5 bytes)
+ */
+
+static void
+print_synchronous (const char *prefix, const unsigned char *msg) {
+    if (msg[4]) {
+	int Hz = 1000000000 / (msg[3] * 4);
+	int integer = Hz / 1000000;
+	int fraction = (Hz - (integer * 1000000)) / 10000;
+	printk ("%speriod %dns offset %d %d.%02dMHz %s SCSI%s\n",
+	    prefix, (int) msg[3] * 4, (int) msg[4], integer, fraction,
+	    (((msg[3] * 4) < 200) ? "FAST" : "synchronous"),
+	    (((msg[3] * 4) < 200) ? "-II" : ""));
+    } else 
+	printk ("%sasynchronous SCSI\n", prefix);
+}
+
+/*
+ * Function : static void set_synchronous (struct Scsi_Host *host, 
+ *	 	int target, int sxfer, int scntl3, int now_connected)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and 
+ *	target with the given register values; in the indirect
+ *	select operand, reselection script, and chip registers.
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ *	sxfer and scntl3 - NCR registers. now_connected - if non-zero, 
+ *	we should reprogram the registers now too.
+ *
+ *      NOTE:  For 53c710, scntl3 is actually used for SCF bits from
+ *	SBCL, as we don't have a SCNTL3.
+ */
+
+static void
+set_synchronous (struct Scsi_Host *host, int target, int sxfer, int scntl3,
+    int now_connected) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *) 
+	host->hostdata[0];
+    u32 *script;
+    NCR53c7x0_local_setup(host);
+
+    /* These are eight bit registers */
+    sxfer &= 0xff;
+    scntl3 &= 0xff;
+
+    hostdata->sync[target].sxfer_sanity = sxfer;
+    hostdata->sync[target].scntl3_sanity = scntl3;
+
+/* 
+ * HARD CODED : synchronous script is EIGHT words long.  This 
+ * must agree with 53c7.8xx.h
+ */
+
+    if ((hostdata->chip != 700) && (hostdata->chip != 70066)) {
+	hostdata->sync[target].select_indirect = (1 << target) << 16 |
+		(sxfer << 8);
+	hostdata->sync[target].sscf_710 = scntl3;
+
+	script = (u32 *) hostdata->sync[target].script;
+
+	/* XXX - add NCR53c7x0 code to reprogram SCF bits if we want to */
+	script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+		DCMD_RWRI_OP_MOVE) << 24) |
+		(SBCL_REG << 16) | (scntl3 << 8);
+	script[1] = 0;
+	script += 2;
+
+	script[0] = ((DCMD_TYPE_RWRI | DCMD_RWRI_OPC_MODIFY |
+	    DCMD_RWRI_OP_MOVE) << 24) |
+		(SXFER_REG << 16) | (sxfer << 8);
+	script[1] = 0;
+	script += 2;
+
+#ifdef DEBUG_SYNC_INTR
+	if (hostdata->options & OPTION_DEBUG_DISCONNECT) {
+	    script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_INT) << 24) | DBC_TCI_TRUE;
+	    script[1] = DEBUG_SYNC_INTR;
+	    script += 2;
+	}
+#endif
+
+	script[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_RETURN) << 24) | DBC_TCI_TRUE;
+	script[1] = 0;
+	script += 2;
+    }
+
+    if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) 
+	printk ("scsi%d : target %d sync parameters are sxfer=0x%x, scntl3=0x%x\n",
+	host->host_no, target, sxfer, scntl3);
+
+    if (now_connected) {
+	NCR53c7x0_write8(SBCL_REG, scntl3);
+	NCR53c7x0_write8(SXFER_REG, sxfer);
+    }
+}
+
+
+/*
+ * Function : static int asynchronous (struct Scsi_Host *host, int target)
+ *
+ * Purpose : reprogram between the selected SCSI Host adapter and target 
+ *      (assumed to be currently connected) for asynchronous transfers.
+ *
+ * Inputs : host - SCSI host structure, target - numeric target ID.
+ *
+ * Preconditions : the NCR chip should be in one of the halted states
+ */
+    
+static void
+asynchronous (struct Scsi_Host *host, int target) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    NCR53c7x0_local_setup(host);
+    set_synchronous (host, target, /* no offset */ 0, hostdata->saved_scntl3,
+	1);
+    printk ("scsi%d : setting target %d to asynchronous SCSI\n",
+	host->host_no, target);
+}
+
+/* 
+ * XXX - do we want to go out of our way (ie, add extra code to selection
+ * 	in the NCR53c710/NCR53c720 script) to reprogram the synchronous
+ * 	conversion bits, or can we be content in just setting the 
+ * 	sxfer bits?  I chose to do so [richard@sleepie.demon.co.uk]
+ */
+
+/* Table for NCR53c8xx synchronous values */
+
+/* This table is also correct for 710, allowing that scf=4 is equivalent
+ * of SSCF=0 (ie use DCNTL, divide by 3) for a 50.01-66.00MHz clock.
+ * For any other clock values, we cannot use entries with SCF values of
+ * 4.  I guess that for a 66MHz clock, the slowest it will set is 2MHz,
+ * and for a 50MHz clock, the slowest will be 2.27Mhz.  Should check
+ * that a device doesn't try and negotiate sync below these limits!
+ */
+ 
+static const struct {
+    int div;		/* Total clock divisor * 10 */
+    unsigned char scf;	/* */
+    unsigned char tp;	/* 4 + tp = xferp divisor */
+} syncs[] = {
+/*	div	scf	tp	div	scf	tp	div	scf	tp */
+    {	40,	1,	0}, {	50,	1,	1}, {	60,	1,	2}, 
+    {	70,	1,	3}, {	75,	2,	1}, {	80,	1,	4},
+    {	90,	1,	5}, {	100,	1,	6}, {	105,	2,	3},
+    {	110,	1,	7}, {	120,	2,	4}, {	135,	2,	5},
+    {	140,	3,	3}, {	150,	2,	6}, {	160,	3,	4},
+    {	165,	2,	7}, {	180,	3,	5}, {	200,	3,	6},
+    {	210,	4,	3}, {	220,	3,	7}, {	240,	4,	4},
+    {	270,	4,	5}, {	300,	4,	6}, {	330,	4,	7}
+};
+
+/*
+ * Function : static void synchronous (struct Scsi_Host *host, int target, 
+ *	char *msg)
+ *
+ * Purpose : reprogram transfers between the selected SCSI initiator and 
+ *	target for synchronous SCSI transfers such that the synchronous 
+ *	offset is less than that requested and period at least as long 
+ *	as that requested.  Also modify *msg such that it contains 
+ *	an appropriate response. 
+ *
+ * Inputs : host - NCR53c7,8xx SCSI host, target - number SCSI target id,
+ *	msg - synchronous transfer request.
+ */
+
+
+static void 
+synchronous (struct Scsi_Host *host, int target, char *msg) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    int desire, divisor, i, limit;
+    unsigned char scntl3, sxfer;
+/* The diagnostic message fits on one line, even with max. width integers */
+    char buf[80];	
+   
+/* Desired transfer clock in Hz */
+    desire = 1000000000L / (msg[3] * 4);
+/* Scale the available SCSI clock by 10 so we get tenths */
+    divisor = (hostdata->scsi_clock * 10) / desire;
+
+/* NCR chips can handle at most an offset of 8 */
+    if (msg[4] > 8)
+	msg[4] = 8;
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : optimal synchronous divisor of %d.%01d\n", 
+	    host->host_no, divisor / 10, divisor % 10);
+
+    limit = (sizeof(syncs) / sizeof(syncs[0]) -1);
+    for (i = 0; (i < limit) && (divisor > syncs[i].div); ++i);
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : selected synchronous divisor of %d.%01d\n", 
+	    host->host_no, syncs[i].div / 10, syncs[i].div % 10);
+
+    msg[3] = ((1000000000L / hostdata->scsi_clock) * syncs[i].div / 10 / 4);
+
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk("scsi%d : selected synchronous period of %dns\n", host->host_no,
+	    msg[3] * 4);
+
+    scntl3 = syncs[i].scf;
+    sxfer = (msg[4] << SXFER_MO_SHIFT) | (syncs[i].tp << 4);
+    if (hostdata->options & OPTION_DEBUG_SDTR)
+    	printk ("scsi%d : sxfer=0x%x scntl3=0x%x\n", 
+	    host->host_no, (int) sxfer, (int) scntl3);
+    set_synchronous (host, target, sxfer, scntl3, 1);
+    sprintf (buf, "scsi%d : setting target %d to ", host->host_no, target);
+    print_synchronous (buf, msg);
+}
+
+/* 
+ * Function : static int NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose :  Handler for INT generated instructions for the 
+ * 	NCR53c810/820 SCSI SCRIPT
+ *
+ * Inputs : host - pointer to this host adapter's structure,
+ * 	cmd - pointer to the command (if any) dsa was pointing 
+ * 	to.
+ *
+ */
+
+static int 
+NCR53c7x0_dstat_sir_intr (struct Scsi_Host *host, struct 
+    NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    int print;
+    Scsi_Cmnd *c = cmd ? cmd->cmd : NULL;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];		
+    u32 dsps,*dsp;	/* Argument of the INT instruction */
+
+    NCR53c7x0_local_setup(host);
+    dsps = NCR53c7x0_read32(DSPS_REG);
+    dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+    /* RGH 150597:  Frig.  Commands which fail with Check Condition are
+     * Flagged as successful - hack dsps to indicate check condition */
+#if 0
+    /* RGH 200597:  Need to disable for BVME6000, as it gets Check Conditions
+     * and then dies.  Seems to handle Check Condition at startup, but
+     * not mid kernel build. */
+    if (dsps == A_int_norm_emulateintfly && cmd && cmd->result == 2)
+        dsps = A_int_err_check_condition;
+#endif
+
+    if (hostdata->options & OPTION_DEBUG_INTR) 
+	printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
+
+    switch (dsps) {
+    case A_int_msg_1:
+	print = 1;
+	switch (hostdata->msg_buf[0]) {
+	/* 
+	 * Unless we've initiated synchronous negotiation, I don't
+	 * think that this should happen.
+	 */
+	case MESSAGE_REJECT:
+	    hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    if (cmd && (cmd->flags & CMD_FLAG_SDTR)) {
+		printk ("scsi%d : target %d rejected SDTR\n", host->host_no, 
+		    c->device->id);
+		cmd->flags &= ~CMD_FLAG_SDTR;
+		asynchronous (host, c->device->id);
+		print = 0;
+	    } 
+	    break;
+	case INITIATE_RECOVERY:
+	    printk ("scsi%d : extended contingent allegiance not supported yet, rejecting\n",
+		host->host_no);
+	    /* Fall through to default */
+	    hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    break;
+	default:
+	    printk ("scsi%d : unsupported message, rejecting\n",
+		host->host_no);
+	    hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	}
+	if (print) {
+	    printk ("scsi%d : received message", host->host_no);
+	    if (c) 
+	    	printk (" from target %d lun %d ", c->device->id, c->device->lun);
+	    print_msg ((unsigned char *) hostdata->msg_buf);
+	    printk("\n");
+	}
+	
+	return SPECIFIC_INT_NOTHING;
+
+
+    case A_int_msg_sdtr:
+/*
+ * At this point, hostdata->msg_buf contains
+ * 0 EXTENDED MESSAGE
+ * 1 length 
+ * 2 SDTR
+ * 3 period * 4ns
+ * 4 offset
+ */
+
+	if (cmd) {
+	    char buf[80];
+	    sprintf (buf, "scsi%d : target %d %s ", host->host_no, c->device->id,
+		(cmd->flags & CMD_FLAG_SDTR) ? "accepting" : "requesting");
+	    print_synchronous (buf, (unsigned char *) hostdata->msg_buf);
+
+	/* 
+	 * Initiator initiated, won't happen unless synchronous 
+	 * 	transfers are enabled.  If we get a SDTR message in
+	 * 	response to our SDTR, we should program our parameters
+	 * 	such that 
+	 *		offset <= requested offset
+	 *		period >= requested period		 	
+   	 */
+	    if (cmd->flags & CMD_FLAG_SDTR) {
+		cmd->flags &= ~CMD_FLAG_SDTR; 
+		if (hostdata->msg_buf[4]) 
+		    synchronous (host, c->device->id, (unsigned char *) 
+		    	hostdata->msg_buf);
+		else 
+		    asynchronous (host, c->device->id);
+		hostdata->dsp = hostdata->script + hostdata->E_accept_message /
+		    sizeof(u32);
+		hostdata->dsp_changed = 1;
+		return SPECIFIC_INT_NOTHING;
+	    } else {
+		if (hostdata->options & OPTION_SYNCHRONOUS)  {
+		    cmd->flags |= CMD_FLAG_DID_SDTR;
+		    synchronous (host, c->device->id, (unsigned char *) 
+			hostdata->msg_buf);
+		} else {
+		    hostdata->msg_buf[4] = 0;		/* 0 offset = async */
+		    asynchronous (host, c->device->id);
+		}
+		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+		patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32) 
+		    virt_to_bus ((void *)&hostdata->msg_buf));
+		hostdata->dsp = hostdata->script + 
+		    hostdata->E_respond_message / sizeof(u32);
+		hostdata->dsp_changed = 1;
+	    }
+	    return SPECIFIC_INT_NOTHING;
+	}
+	/* Fall through to abort if we couldn't find a cmd, and 
+	   therefore a dsa structure to twiddle */
+    case A_int_msg_wdtr:
+	hostdata->dsp = hostdata->script + hostdata->E_reject_message /
+	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_err_unexpected_phase:
+	if (hostdata->options & OPTION_DEBUG_INTR) 
+	    printk ("scsi%d : unexpected phase\n", host->host_no);
+	return SPECIFIC_INT_ABORT;
+    case A_int_err_selected:
+	if ((hostdata->chip / 100) == 8)
+	    printk ("scsi%d : selected by target %d\n", host->host_no,
+	        (int) NCR53c7x0_read8(SDID_REG_800) &7);
+	else
+            printk ("scsi%d : selected by target LCRC=0x%02x\n", host->host_no,
+                (int) NCR53c7x0_read8(LCRC_REG_10));
+	hostdata->dsp = hostdata->script + hostdata->E_target_abort / 
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_err_unexpected_reselect:
+	if ((hostdata->chip / 100) == 8)
+	    printk ("scsi%d : unexpected reselect by target %d lun %d\n", 
+	        host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & 7,
+	        hostdata->reselected_identify & 7);
+	else
+            printk ("scsi%d : unexpected reselect LCRC=0x%02x\n", host->host_no,
+                (int) NCR53c7x0_read8(LCRC_REG_10));
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+/*
+ * Since contingent allegiance conditions are cleared by the next 
+ * command issued to a target, we must issue a REQUEST SENSE 
+ * command after receiving a CHECK CONDITION status, before
+ * another command is issued.
+ * 
+ * Since this NCR53c7x0_cmd will be freed after use, we don't 
+ * care if we step on the various fields, so modify a few things.
+ */
+    case A_int_err_check_condition: 
+#if 0
+	if (hostdata->options & OPTION_DEBUG_INTR) 
+#endif
+	    printk ("scsi%d : CHECK CONDITION\n", host->host_no);
+	if (!c) {
+	    printk("scsi%d : CHECK CONDITION with no SCSI command\n",
+		host->host_no);
+	    return SPECIFIC_INT_PANIC;
+	}
+
+	/* 
+	 * FIXME : this uses the normal one-byte selection message.
+	 * 	We may want to renegotiate for synchronous & WIDE transfers
+	 * 	since these could be the crux of our problem.
+	 *
+	 hostdata->NOP_insn* FIXME : once SCSI-II tagged queuing is implemented, we'll
+	 * 	have to set this up so that the rest of the DSA
+	 *	agrees with this being an untagged queue'd command.
+	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+
+    	/* 
+    	 * Modify the table indirect for COMMAND OUT phase, since 
+    	 * Request Sense is a six byte command.
+    	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+
+        /*
+         * The CDB is now mirrored in our local non-cached
+         * structure, but keep the old structure up to date as well,
+         * just in case anyone looks at it.
+         */
+
+	/*
+	 * XXX Need to worry about data buffer alignment/cache state
+	 * XXX here, but currently never get A_int_err_check_condition,
+	 * XXX so ignore problem for now.
+         */
+	cmd->cmnd[0] = c->cmnd[0] = REQUEST_SENSE;
+	cmd->cmnd[0] = c->cmnd[1] &= 0xe0;	/* Zero all but LUN */
+	cmd->cmnd[0] = c->cmnd[2] = 0;
+	cmd->cmnd[0] = c->cmnd[3] = 0;
+	cmd->cmnd[0] = c->cmnd[4] = sizeof(c->sense_buffer);
+	cmd->cmnd[0] = c->cmnd[5] = 0; 
+
+	/*
+	 * Disable dataout phase, and program datain to transfer to the 
+	 * sense buffer, and add a jump to other_transfer after the 
+    	 * command so overflow/underrun conditions are detected.
+	 */
+
+    	patch_dsa_32 (cmd->dsa, dsa_dataout, 0, 
+	    virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+    	patch_dsa_32 (cmd->dsa, dsa_datain, 0, 
+	    virt_to_bus(cmd->data_transfer_start));
+    	cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | 
+    	    DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
+    	cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+
+	cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) 
+    	    << 24) | DBC_TCI_TRUE;
+	cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) + 
+	    hostdata->E_other_transfer;
+
+    	/*
+    	 * Currently, this command is flagged as completed, ie 
+    	 * it has valid status and message data.  Reflag it as
+    	 * incomplete.  Q - need to do something so that original
+	 * status, etc are used.
+    	 */
+
+	cmd->result = cmd->cmd->result = 0xffff;		
+
+	/* 
+	 * Restart command as a REQUEST SENSE.
+	 */
+	hostdata->dsp = (u32 *) hostdata->script + hostdata->E_select /
+	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+	return SPECIFIC_INT_NOTHING;
+    case A_int_debug_break:
+	return SPECIFIC_INT_BREAK;
+    case A_int_norm_aborted:
+	hostdata->dsp = (u32 *) hostdata->schedule;
+	hostdata->dsp_changed = 1;
+	if (cmd)
+	    abnormal_finished (cmd, DID_ERROR << 16);
+	return SPECIFIC_INT_NOTHING;
+    case A_int_norm_emulateintfly:
+	NCR53c7x0_intfly(host);
+	return SPECIFIC_INT_NOTHING;
+    case A_int_test_1:
+    case A_int_test_2:
+	hostdata->idle = 1;
+	hostdata->test_completed = (dsps - A_int_test_1) / 0x00010000 + 1;
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk("scsi%d : test%d complete\n", host->host_no,
+		hostdata->test_completed);
+	return SPECIFIC_INT_NOTHING;
+#ifdef A_int_debug_reselected_ok
+    case A_int_debug_reselected_ok:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    	OPTION_DEBUG_DISCONNECT)) {
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    u32 *dsa;
+	    dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+	    printk("scsi%d : reselected_ok (DSA = 0x%x (virt 0x%p)\n", 
+		host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
+	    printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt(cmd->saved_data_pointer));
+	    print_insn (host, hostdata->script + Ent_reselected_ok / 
+    	    	    sizeof(u32), "", 1);
+	    if ((hostdata->chip / 100) == 8)
+    	        printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+		    host->host_no, NCR53c7x0_read8(SXFER_REG),
+		    NCR53c7x0_read8(SCNTL3_REG_800));
+	    else
+    	        printk ("scsi%d : sxfer=0x%x, cannot read SBCL\n",
+		    host->host_no, NCR53c7x0_read8(SXFER_REG));
+	    if (c) {
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->device->id].script, "", 1);
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->device->id].script + 2, "", 1);
+	    }
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_reselect_check
+    case A_int_debug_reselect_check:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    u32 *dsa;
+#if 0
+	    u32 *code;
+#endif
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+	    printk("scsi%d : reselected_check_next (DSA = 0x%lx (virt 0x%p))\n",
+		host->host_no, virt_to_bus(dsa), dsa);
+	    if (dsa) {
+		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt (cmd->saved_data_pointer));
+#if 0
+		printk("scsi%d : template code :\n", host->host_no);
+		for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero) 
+		    / sizeof(u32); code < (dsa + Ent_dsa_zero / sizeof(u32)); 
+		    code += print_insn (host, code, "", 1));
+#endif
+	    }
+	    print_insn (host, hostdata->script + Ent_reselected_ok / 
+    	    	    sizeof(u32), "", 1);
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_schedule
+    case A_int_debug_dsa_schedule:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    u32 *dsa;
+	    /* 
+	     * Note - this dsa is not based on location relative to 
+	     * the command structure, but to location relative to the 
+	     * DSA register 
+	     */	
+	    dsa = (u32 *) bus_to_virt (NCR53c7x0_read32(DSA_REG));
+	    printk("scsi%d : dsa_schedule (old DSA = 0x%lx (virt 0x%p))\n", 
+		host->host_no, virt_to_bus(dsa), dsa);
+	    if (dsa) 
+		printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
+		       "         (temp was 0x%x (virt 0x%p))\n",
+		    host->host_no, cmd->saved_data_pointer,
+		    bus_to_virt (cmd->saved_data_pointer),
+		    NCR53c7x0_read32 (TEMP_REG),
+		    bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_scheduled
+    case A_int_debug_scheduled:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : new I/O 0x%x (virt 0x%p) scheduled\n", 
+		host->host_no, NCR53c7x0_read32(DSA_REG),
+	    	bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_idle
+    case A_int_debug_idle:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : idle\n", host->host_no);
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_cmd
+    case A_int_debug_cmd:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : command sent\n");
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_dsa_loaded
+    case A_int_debug_dsa_loaded:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    printk("scsi%d : DSA loaded with 0x%x (virt 0x%p)\n", host->host_no,
+		NCR53c7x0_read32(DSA_REG), 
+		bus_to_virt(NCR53c7x0_read32(DSA_REG)));
+	}
+	return SPECIFIC_INT_RESTART; 
+#endif
+#ifdef A_int_debug_reselected
+    case A_int_debug_reselected:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+	    OPTION_DEBUG_DISCONNECT)) {
+	    if ((hostdata->chip / 100) == 8)
+		printk("scsi%d : reselected by target %d lun %d\n",
+		    host->host_no, (int) NCR53c7x0_read8(SDID_REG_800) & ~0x80, 
+		    (int) hostdata->reselected_identify & 7);
+	    else
+		printk("scsi%d : reselected by LCRC=0x%02x lun %d\n",
+                    host->host_no, (int) NCR53c7x0_read8(LCRC_REG_10),
+                    (int) hostdata->reselected_identify & 7);
+	    print_queues(host);
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnect_msg
+    case A_int_debug_disconnect_msg:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR)) {
+	    if (c)
+		printk("scsi%d : target %d lun %d disconnecting\n", 
+		    host->host_no, c->device->id, c->device->lun);
+	    else
+		printk("scsi%d : unknown target disconnecting\n",
+		    host->host_no);
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_disconnected
+    case A_int_debug_disconnected:
+	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+		OPTION_DEBUG_DISCONNECT)) {
+	    printk ("scsi%d : disconnected, new queues are\n", 
+		host->host_no);
+	    print_queues(host);
+#if 0
+	    /* Not valid on ncr53c710! */
+    	    printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
+		host->host_no, NCR53c7x0_read8(SXFER_REG),
+		NCR53c7x0_read8(SCNTL3_REG_800));
+#endif
+	    if (c) {
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->device->id].script, "", 1);
+		print_insn (host, (u32 *) 
+		    hostdata->sync[c->device->id].script + 2, "", 1);
+	    }
+	}
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_panic
+    case A_int_debug_panic:
+	printk("scsi%d : int_debug_panic received\n", host->host_no);
+	print_lots (host);
+	return SPECIFIC_INT_PANIC;
+#endif
+#ifdef A_int_debug_saved
+    case A_int_debug_saved:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT)) {
+    	    printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
+    	    	host->host_no, cmd->saved_data_pointer,
+		bus_to_virt (cmd->saved_data_pointer));
+    	    print_progress (c);
+    	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_restored
+    case A_int_debug_restored:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT)) {
+    	    if (cmd) {
+		int size;
+    	    	printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
+    	    	    host->host_no, cmd->saved_data_pointer, bus_to_virt (
+		    cmd->saved_data_pointer));
+		size = print_insn (host, (u32 *) 
+		    bus_to_virt(cmd->saved_data_pointer), "", 1);
+		size = print_insn (host, (u32 *) 
+		    bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+    	    	print_progress (c);
+	    }
+#if 0
+	    printk ("scsi%d : datapath residual %d\n",
+		host->host_no, datapath_residual (host)) ;
+#endif
+    	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_sync
+    case A_int_debug_sync:
+    	if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+    	    OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+	    unsigned char sxfer = NCR53c7x0_read8 (SXFER_REG), scntl3;
+	    if ((hostdata->chip / 100) == 8) {
+		scntl3 = NCR53c7x0_read8 (SCNTL3_REG_800);
+		if (c) {
+		  if (sxfer != hostdata->sync[c->device->id].sxfer_sanity ||
+		    scntl3 != hostdata->sync[c->device->id].scntl3_sanity) {
+		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x, scntl3=0x%x",
+			    host->host_no, sxfer, scntl3);
+			NCR53c7x0_write8 (SXFER_REG, sxfer);
+			NCR53c7x0_write8 (SCNTL3_REG_800, scntl3);
+		    }
+		} else 
+    	    	  printk ("scsi%d : unknown command sxfer=0x%x, scntl3=0x%x\n",
+		    host->host_no, (int) sxfer, (int) scntl3);
+	    } else {
+		if (c) {
+		  if (sxfer != hostdata->sync[c->device->id].sxfer_sanity) {
+		   	printk ("scsi%d :  sync sanity check failed sxfer=0x%x",
+			    host->host_no, sxfer);
+			NCR53c7x0_write8 (SXFER_REG, sxfer);
+			NCR53c7x0_write8 (SBCL_REG,
+				hostdata->sync[c->device->id].sscf_710);
+		    }
+		} else 
+    	    	  printk ("scsi%d : unknown command sxfer=0x%x\n",
+		    host->host_no, (int) sxfer);
+	    }
+	}
+    	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_datain
+	case A_int_debug_datain:
+	    if (hostdata->options & (OPTION_DEBUG_SCRIPT|OPTION_DEBUG_INTR|
+		OPTION_DEBUG_DISCONNECT|OPTION_DEBUG_SDTR)) {
+		int size;
+		if ((hostdata->chip / 100) == 8)
+		  printk ("scsi%d : In do_datain (%s) sxfer=0x%x, scntl3=0x%x\n"
+			"         datapath residual=%d\n",
+		    host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+		    (int) NCR53c7x0_read8(SXFER_REG), 
+		    (int) NCR53c7x0_read8(SCNTL3_REG_800),
+		    datapath_residual (host)) ;
+		else
+		  printk ("scsi%d : In do_datain (%s) sxfer=0x%x\n"
+			"         datapath residual=%d\n",
+		    host->host_no, sbcl_to_phase (NCR53c7x0_read8 (SBCL_REG)),
+		    (int) NCR53c7x0_read8(SXFER_REG), 
+		    datapath_residual (host)) ;
+		print_insn (host, dsp, "", 1);
+		size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
+		print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+	   } 
+	return SPECIFIC_INT_RESTART;
+#endif
+#ifdef A_int_debug_check_dsa
+	case A_int_debug_check_dsa:
+	    if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+		int sdid;
+		int tmp;
+		char *where;
+		if (hostdata->chip / 100 == 8)
+		    sdid = NCR53c7x0_read8 (SDID_REG_800) & 15;
+		else {
+		    tmp = NCR53c7x0_read8 (SDID_REG_700);
+		    if (!tmp)
+			panic ("SDID_REG_700 = 0");
+		    tmp >>= 1;
+		    sdid = 0;
+		    while (tmp) {
+			tmp >>= 1;
+			sdid++;
+		    }
+		}
+		where = dsp - NCR53c7x0_insn_size(NCR53c7x0_read8 
+			(DCMD_REG)) == hostdata->script + 
+		    	Ent_select_check_dsa / sizeof(u32) ?
+		    "selection" : "reselection";
+		if (c && sdid != c->device->id) {
+		    printk ("scsi%d : SDID target %d != DSA target %d at %s\n",
+			host->host_no, sdid, c->device->id, where);
+		    print_lots(host);
+		    dump_events (host, 20);
+		    return SPECIFIC_INT_PANIC;
+		}
+	    }
+	    return SPECIFIC_INT_RESTART;
+#endif
+    default:
+	if ((dsps & 0xff000000) == 0x03000000) {
+	     printk ("scsi%d : misc debug interrupt 0x%x\n",
+		host->host_no, dsps);
+	    return SPECIFIC_INT_RESTART;
+	} else if ((dsps & 0xff000000) == 0x05000000) {
+	    if (hostdata->events) {
+		struct NCR53c7x0_event *event;
+		++hostdata->event_index;
+		if (hostdata->event_index >= hostdata->event_size)
+		    hostdata->event_index = 0;
+		event = (struct NCR53c7x0_event *) hostdata->events + 
+		    hostdata->event_index;
+		event->event = (enum ncr_event) dsps;
+		event->dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+		if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON) {
+		    if (hostdata->chip / 100 == 8)
+			event->target = NCR53c7x0_read8(SSID_REG_800);
+		    else {
+			unsigned char tmp, sdid;
+		        tmp = NCR53c7x0_read8 (SDID_REG_700);
+		        if (!tmp)
+			    panic ("SDID_REG_700 = 0");
+		        tmp >>= 1;
+		        sdid = 0;
+		        while (tmp) {
+			    tmp >>= 1;
+			    sdid++;
+		        }
+			event->target = sdid;
+		    }
+		}
+		else 
+			event->target = 255;
+
+		if (event->event == EVENT_RESELECT)
+		    event->lun = hostdata->reselected_identify & 0xf;
+		else if (c)
+		    event->lun = c->device->lun;
+		else
+		    event->lun = 255;
+		do_gettimeofday(&(event->time));
+		if (c) {
+		    event->pid = c->pid;
+		    memcpy ((void *) event->cmnd, (void *) c->cmnd, 
+			sizeof (event->cmnd));
+		} else {
+		    event->pid = -1;
+		}
+	    }
+	    return SPECIFIC_INT_RESTART;
+	}
+
+	printk ("scsi%d : unknown user interrupt 0x%x\n", 
+	    host->host_no, (unsigned) dsps);
+	return SPECIFIC_INT_PANIC;
+    }
+}
+
+/* 
+ * XXX - the stock NCR assembler won't output the scriptu.h file,
+ * which undefine's all #define'd CPP symbols from the script.h
+ * file, which will create problems if you use multiple scripts
+ * with the same  symbol names.
+ *
+ * If you insist on using NCR's assembler, you could generate
+ * scriptu.h from script.h using something like 
+ *
+ * grep #define script.h | \
+ * sed 's/#define[ 	][ 	]*\([_a-zA-Z][_a-zA-Z0-9]*\).*$/#undefine \1/' \
+ * > scriptu.h
+ */
+
+#include "53c7xx_u.h"
+
+/* XXX - add alternate script handling code here */
+
+
+/* 
+ * Function : static void NCR537xx_soft_reset (struct Scsi_Host *host)
+ *
+ * Purpose :  perform a soft reset of the NCR53c7xx chip
+ *
+ * Inputs : host - pointer to this host adapter's structure
+ *
+ * Preconditions : NCR53c7x0_init must have been called for this 
+ *      host.
+ * 
+ */
+
+static void 
+NCR53c7x0_soft_reset (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    NCR53c7x0_local_setup(host);
+
+    local_irq_save(flags);
+
+    /* Disable scsi chip and s/w level 7 ints */
+
+#ifdef CONFIG_MVME16x
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
+
+        v = *(volatile unsigned long *)0xfff4006c;
+        v &= ~0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v &= ~0x10;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
+#endif
+    /* Anything specific for your hardware? */
+
+    /*
+     * Do a soft reset of the chip so that everything is 
+     * reinitialized to the power-on state.
+     *
+     * Basically follow the procedure outlined in the NCR53c700
+     * data manual under Chapter Six, How to Use, Steps Necessary to
+     * Start SCRIPTS, with the exception of actually starting the 
+     * script and setting up the synchronous transfer gunk.
+     */
+
+    /* Should we reset the scsi bus here??????????????????? */
+
+    NCR53c7x0_write8(ISTAT_REG_700, ISTAT_10_SRST);
+    NCR53c7x0_write8(ISTAT_REG_700, 0);
+
+    /*
+     * saved_dcntl is set up in NCR53c7x0_init() before it is overwritten
+     * here.  We should have some better way of working out the CF bit
+     * setting..
+     */
+
+    hostdata->saved_dcntl = DCNTL_10_EA|DCNTL_10_COM;
+    if (hostdata->scsi_clock > 50000000)
+	hostdata->saved_dcntl |= DCNTL_700_CF_3;
+    else
+    if (hostdata->scsi_clock > 37500000)
+        hostdata->saved_dcntl |= DCNTL_700_CF_2;
+#if 0
+    else
+	/* Any clocks less than 37.5MHz? */
+#endif
+
+    if (hostdata->options & OPTION_DEBUG_TRACE)
+    	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl | DCNTL_SSM);
+    else
+    	NCR53c7x0_write8(DCNTL_REG, hostdata->saved_dcntl);
+    /* Following disables snooping - snooping is not required, as non-
+     * cached pages are used for shared data, and appropriate use is
+     * made of cache_push/cache_clear.  Indeed, for 68060
+     * enabling snooping causes disk corruption of ext2fs free block
+     * bitmaps and the like.  If you have a 68060 with snooping hardwared
+     * on, then you need to enable CONFIG_060_WRITETHROUGH.
+     */
+    NCR53c7x0_write8(CTEST7_REG, CTEST7_10_TT1|CTEST7_STD);
+    /* Actually burst of eight, according to my 53c710 databook */
+    NCR53c7x0_write8(hostdata->dmode, DMODE_10_BL_8 | DMODE_10_FC2);
+    NCR53c7x0_write8(SCID_REG, 1 << host->this_id);
+    NCR53c7x0_write8(SBCL_REG, 0);
+    NCR53c7x0_write8(SCNTL1_REG, SCNTL1_ESR_700);
+    NCR53c7x0_write8(SCNTL0_REG, ((hostdata->options & OPTION_PARITY) ? 
+            SCNTL0_EPC : 0) | SCNTL0_EPG_700 | SCNTL0_ARB1 | SCNTL0_ARB2);
+
+    /*
+     * Enable all interrupts, except parity which we only want when
+     * the user requests it.
+     */
+
+    NCR53c7x0_write8(DIEN_REG, DIEN_700_BF |
+		DIEN_ABRT | DIEN_SSI | DIEN_SIR | DIEN_700_OPC);
+
+    NCR53c7x0_write8(SIEN_REG_700, ((hostdata->options & OPTION_PARITY) ?
+	    SIEN_PAR : 0) | SIEN_700_STO | SIEN_RST | SIEN_UDC |
+		SIEN_SGE | SIEN_MA);
+
+#ifdef CONFIG_MVME16x
+    if (MACH_IS_MVME16x)
+    {
+        volatile unsigned long v;
+
+        /* Enable scsi chip and s/w level 7 ints */
+        v = *(volatile unsigned long *)0xfff40080;
+        v = (v & ~(0xf << 28)) | (4 << 28);
+        *(volatile unsigned long *)0xfff40080 = v;
+        v = *(volatile unsigned long *)0xfff4006c;
+        v |= 0x8000;
+        *(volatile unsigned long *)0xfff4006c = v;
+        v = *(volatile unsigned long *)0xfff4202c;
+        v = (v & ~0xff) | 0x10 | 4;
+        *(volatile unsigned long *)0xfff4202c = v;
+    }
+#endif
+    /* Anything needed for your hardware? */
+    local_irq_restore(flags);
+}
+
+
+/*
+ * Function static struct NCR53c7x0_cmd *allocate_cmd (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : Return the first free NCR53c7x0_cmd structure (which are 
+ * 	reused in a LIFO manner to minimize cache thrashing).
+ *
+ * Side effects : If we haven't yet scheduled allocation of NCR53c7x0_cmd
+ *	structures for this device, do so.  Attempt to complete all scheduled
+ *	allocations using get_zeroed_page(), putting NCR53c7x0_cmd structures on
+ *	the free list.  Teach programmers not to drink and hack.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure allocated on behalf of cmd;
+ *	NULL on failure.
+ */
+
+static void
+my_free_page (void *addr, int dummy)
+{
+    /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((void *)addr, 4096, IOMAP_FULL_CACHING);
+    free_page ((u32)addr);
+}
+
+static struct NCR53c7x0_cmd *
+allocate_cmd (Scsi_Cmnd *cmd) {
+    struct Scsi_Host *host = cmd->device->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    u32 real;			/* Real address */
+    int size;			/* Size of *tmp */
+    struct NCR53c7x0_cmd *tmp;
+    unsigned long flags;
+
+    if (hostdata->options & OPTION_DEBUG_ALLOCATION)
+	printk ("scsi%d : num_cmds = %d, can_queue = %d\n"
+		"         target = %d, lun = %d, %s\n",
+	    host->host_no, hostdata->num_cmds, host->can_queue,
+	    cmd->device->id, cmd->device->lun, (hostdata->cmd_allocated[cmd->device->id] &
+		(1 << cmd->device->lun)) ? "already allocated" : "not allocated");
+
+/*
+ * If we have not yet reserved commands for this I_T_L nexus, and
+ * the device exists (as indicated by permanent Scsi_Cmnd structures
+ * being allocated under 1.3.x, or being outside of scan_scsis in
+ * 1.2.x), do so now.
+ */
+    if (!(hostdata->cmd_allocated[cmd->device->id] & (1 << cmd->device->lun)) &&
+				cmd->device && cmd->device->has_cmdblocks) {
+      if ((hostdata->extra_allocate + hostdata->num_cmds) < host->can_queue)
+          hostdata->extra_allocate += host->cmd_per_lun;
+      hostdata->cmd_allocated[cmd->device->id] |= (1 << cmd->device->lun);
+    }
+
+    for (; hostdata->extra_allocate > 0 ; --hostdata->extra_allocate, 
+    	++hostdata->num_cmds) {
+    /* historically, kmalloc has returned unaligned addresses; pad so we
+       have enough room to ROUNDUP */
+	size = hostdata->max_cmd_size + sizeof (void *);
+#ifdef FORCE_DSA_ALIGNMENT
+	/*
+	 * 53c710 rev.0 doesn't have an add-with-carry instruction.
+	 * Ensure we allocate enough memory to force alignment.
+	 */
+	size += 256;
+#endif
+/* FIXME: for ISA bus '7xx chips, we need to or GFP_DMA in here */
+
+        if (size > 4096) {
+            printk (KERN_ERR "53c7xx: allocate_cmd size > 4K\n");
+	    return NULL;
+	}
+        real = get_zeroed_page(GFP_ATOMIC);
+        if (real == 0)
+        	return NULL;
+        memset((void *)real, 0, 4096);
+        cache_push(virt_to_phys((void *)real), 4096);
+        cache_clear(virt_to_phys((void *)real), 4096);
+        kernel_set_cachemode((void *)real, 4096, IOMAP_NOCACHE_SER);
+	tmp = ROUNDUP(real, void *);
+#ifdef FORCE_DSA_ALIGNMENT
+	{
+	    if (((u32)tmp & 0xff) > CmdPageStart)
+		tmp = (struct NCR53c7x0_cmd *)((u32)tmp + 255);
+	    tmp = (struct NCR53c7x0_cmd *)(((u32)tmp & ~0xff) + CmdPageStart);
+#if 0
+	    printk ("scsi: size = %d, real = 0x%08x, tmp set to 0x%08x\n",
+			size, real, (u32)tmp);
+#endif
+	}
+#endif
+	tmp->real = (void *)real;
+	tmp->size = size;			
+	tmp->free = ((void (*)(void *, int)) my_free_page);
+	local_irq_save(flags);
+	tmp->next = hostdata->free;
+	hostdata->free = tmp;
+	local_irq_restore(flags);
+    }
+    local_irq_save(flags);
+    tmp = (struct NCR53c7x0_cmd *) hostdata->free;
+    if (tmp) {
+	hostdata->free = tmp->next;
+    }
+    local_irq_restore(flags);
+    if (!tmp)
+	printk ("scsi%d : can't allocate command for target %d lun %d\n",
+	    host->host_no, cmd->device->id, cmd->device->lun);
+    return tmp;
+}
+
+/*
+ * Function static struct NCR53c7x0_cmd *create_cmd (Scsi_Cmnd *cmd) 
+ *
+ *
+ * Purpose : allocate a NCR53c7x0_cmd structure, initialize it based on the 
+ * 	Scsi_Cmnd structure passed in cmd, including dsa and Linux field 
+ * 	initialization, and dsa code relocation.
+ *
+ * Inputs : cmd - SCSI command
+ *
+ * Returns : NCR53c7x0_cmd structure corresponding to cmd,
+ *	NULL on failure.
+ */
+static struct NCR53c7x0_cmd *
+create_cmd (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host = cmd->device->host;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+        host->hostdata[0];	
+    struct NCR53c7x0_cmd *tmp; 	/* NCR53c7x0_cmd structure for this command */
+    int datain,  		/* Number of instructions per phase */
+	dataout;
+    int data_transfer_instructions, /* Count of dynamic instructions */
+    	i;			/* Counter */
+    u32 *cmd_datain,		/* Address of datain/dataout code */
+	*cmd_dataout;		/* Incremented as we assemble */
+#ifdef notyet
+    unsigned char *msgptr;	/* Current byte in select message */
+    int msglen;			/* Length of whole select message */
+#endif
+    unsigned long flags;
+    u32 exp_select_indirect;	/* Used in sanity check */
+    NCR53c7x0_local_setup(cmd->device->host);
+
+    if (!(tmp = allocate_cmd (cmd)))
+	return NULL;
+
+    /*
+     * Copy CDB and initialised result fields from Scsi_Cmnd to NCR53c7x0_cmd.
+     * We do this because NCR53c7x0_cmd may have a special cache mode
+     * selected to cope with lack of bus snooping, etc.
+     */
+
+    memcpy(tmp->cmnd, cmd->cmnd, 12);
+    tmp->result = cmd->result;
+
+    /*
+     * Decide whether we need to generate commands for DATA IN,
+     * DATA OUT, neither, or both based on the SCSI command 
+     */
+
+    switch (cmd->cmnd[0]) {
+    /* These commands do DATA IN */
+    case INQUIRY:
+    case MODE_SENSE:
+    case READ_6:
+    case READ_10:
+    case READ_CAPACITY:
+    case REQUEST_SENSE:
+    case READ_BLOCK_LIMITS:
+    case READ_TOC:
+	datain = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+    	dataout = 0;
+	break;
+    /* These commands do DATA OUT */
+    case MODE_SELECT: 
+    case WRITE_6:
+    case WRITE_10:
+#if 0
+	printk("scsi%d : command is ", host->host_no);
+	print_command(cmd->cmnd);
+#endif
+#if 0
+	printk ("scsi%d : %d scatter/gather segments\n", host->host_no,
+	    cmd->use_sg);
+#endif
+    	datain = 0;
+	dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+#if 0
+	hostdata->options |= OPTION_DEBUG_INTR;
+#endif
+	break;
+    /* 
+     * These commands do no data transfer, we should force an
+     * interrupt if a data phase is attempted on them.
+     */
+    case TEST_UNIT_READY:
+    case ALLOW_MEDIUM_REMOVAL:
+    case START_STOP:
+    	datain = dataout = 0;
+	break;
+    /*
+     * We don't know about these commands, so generate code to handle
+     * both DATA IN and DATA OUT phases.  More efficient to identify them
+     * and add them to the above cases.
+     */
+    default:
+	printk("scsi%d : datain+dataout for command ", host->host_no);
+	print_command(cmd->cmnd);
+	datain = dataout = 2 * (cmd->use_sg ? cmd->use_sg : 1) + 3;
+    }
+
+    /*
+     * New code : so that active pointers work correctly regardless
+     * 	of where the saved data pointer is at, we want to immediately
+     * 	enter the dynamic code after selection, and on a non-data
+     * 	phase perform a CALL to the non-data phase handler, with
+     * 	returns back to this address.
+     *
+     * 	If a phase mismatch is encountered in the middle of a 
+     * 	Block MOVE instruction, we want to _leave_ that instruction
+     *	unchanged as the current case is, modify a temporary buffer,
+     *	and point the active pointer (TEMP) at that.
+     *
+     * 	Furthermore, we want to implement a saved data pointer, 
+     * 	set by the SAVE_DATA_POINTERs message.
+     *
+     * 	So, the data transfer segments will change to 
+     *		CALL data_transfer, WHEN NOT data phase
+     *		MOVE x, x, WHEN data phase
+     *		( repeat )
+     *		JUMP other_transfer
+     */
+
+    data_transfer_instructions = datain + dataout;
+
+    /*
+     * When we perform a request sense, we overwrite various things,
+     * including the data transfer code.  Make sure we have enough
+     * space to do that.
+     */
+
+    if (data_transfer_instructions < 2)
+    	data_transfer_instructions = 2;
+
+
+    /*
+     * The saved data pointer is set up so that a RESTORE POINTERS message 
+     * will start the data transfer over at the beginning.
+     */
+
+    tmp->saved_data_pointer = virt_to_bus (hostdata->script) + 
+	hostdata->E_data_transfer;
+
+    /*
+     * Initialize Linux specific fields.
+     */
+
+    tmp->cmd = cmd;
+    tmp->next = NULL;
+    tmp->flags = 0;
+    tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next - 
+	hostdata->dsa_start;
+    tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+
+    /* 
+     * Calculate addresses of dynamic code to fill in DSA
+     */
+
+    tmp->data_transfer_start = tmp->dsa + (hostdata->dsa_end - 
+    	hostdata->dsa_start) / sizeof(u32);
+    tmp->data_transfer_end = tmp->data_transfer_start + 
+    	2 * data_transfer_instructions;
+
+    cmd_datain = datain ? tmp->data_transfer_start : NULL;
+    cmd_dataout = dataout ? (datain ? cmd_datain + 2 * datain : tmp->
+    	data_transfer_start) : NULL;
+
+    /*
+     * Fill in the NCR53c7x0_cmd structure as follows
+     * dsa, with fixed up DSA code
+     * datain code
+     * dataout code
+     */
+
+    /* Copy template code into dsa and perform all necessary fixups */
+    if (hostdata->dsa_fixup)
+    	hostdata->dsa_fixup(tmp);
+
+    patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
+    /*
+     * XXX is this giving 53c710 access to the Scsi_Cmnd in some way?
+     * Do we need to change it for caching reasons?
+     */
+    patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+
+    if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS) {
+
+	exp_select_indirect = ((1 << cmd->device->id) << 16) |
+			(hostdata->sync[cmd->device->id].sxfer_sanity << 8);
+
+	if (hostdata->sync[cmd->device->id].select_indirect !=
+				exp_select_indirect) {
+	    printk ("scsi%d :  sanity check failed select_indirect=0x%x\n",
+		host->host_no, hostdata->sync[cmd->device->id].select_indirect);
+	    FATAL(host);
+
+	}
+    }
+
+    patch_dsa_32(tmp->dsa, dsa_select, 0,
+		hostdata->sync[cmd->device->id].select_indirect);
+
+    /*
+     * Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
+     * different commands; although it should be trivial to do them
+     * both at the same time.
+     */
+    if (hostdata->initiate_wdtr & (1 << cmd->device->id)) {
+	memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
+	    sizeof(wdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+	local_irq_save(flags);
+	hostdata->initiate_wdtr &= ~(1 << cmd->device->id);
+	local_irq_restore(flags);
+    } else if (hostdata->initiate_sdtr & (1 << cmd->device->id)) {
+	memcpy ((void *) (tmp->select + 1), (void *) sdtr_message, 
+	    sizeof(sdtr_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+	tmp->flags |= CMD_FLAG_SDTR;
+	local_irq_save(flags);
+	hostdata->initiate_sdtr &= ~(1 << cmd->device->id);
+	local_irq_restore(flags);
+    
+    }
+#if 1
+    else if (!(hostdata->talked_to & (1 << cmd->device->id)) &&
+		!(hostdata->options & OPTION_NO_ASYNC)) {
+
+	memcpy ((void *) (tmp->select + 1), (void *) async_message, 
+	    sizeof(async_message));
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+	tmp->flags |= CMD_FLAG_SDTR;
+    } 
+#endif
+    else 
+    	patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+
+    hostdata->talked_to |= (1 << cmd->device->id);
+    tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ? 
+	IDENTIFY (1, cmd->device->lun) : IDENTIFY (0, cmd->device->lun);
+    patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
+    patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(tmp->cmnd));
+    patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ? 
+    	    virt_to_bus (cmd_dataout)
+	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+    patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ? 
+    	    virt_to_bus (cmd_datain) 
+	: virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+    /* 
+     * XXX - need to make endian aware, should use separate variables
+     * for both status and message bytes.
+     */
+    patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+/* 
+ * FIXME : these only works for little endian.  We probably want to 
+ * 	provide message and status fields in the NCR53c7x0_cmd 
+ *	structure, and assign them to cmd->result when we're done.
+ */
+#ifdef BIG_ENDIAN
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 2);
+    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result) + 3);
+#else
+    patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&tmp->result) + 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&tmp->result));
+#endif
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+    patch_dsa_32(tmp->dsa, dsa_msgout_other, 1, 
+	virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+    
+    /*
+     * Generate code for zero or more of the DATA IN, DATA OUT phases 
+     * in the format 
+     *
+     * CALL data_transfer, WHEN NOT phase
+     * MOVE first buffer length, first buffer address, WHEN phase
+     * ...
+     * MOVE last buffer length, last buffer address, WHEN phase
+     * JUMP other_transfer
+     */
+
+/* 
+ * See if we're getting to data transfer by generating an unconditional 
+ * interrupt.
+ */
+#if 0
+    if (datain) {
+	cmd_datain[0] = 0x98080000;
+	cmd_datain[1] = 0x03ffd00d;
+	cmd_datain += 2;
+    }
+#endif
+
+/* 
+ * XXX - I'm undecided whether all of this nonsense is faster
+ * in the long run, or whether I should just go and implement a loop
+ * on the NCR chip using table indirect mode?
+ *
+ * In any case, this is how it _must_ be done for 53c700/700-66 chips,
+ * so this stays even when we come up with something better.
+ *
+ * When we're limited to 1 simultaneous command, no overlapping processing,
+ * we're seeing 630K/sec, with 7% CPU usage on a slow Syquest 45M
+ * drive.
+ *
+ * Not bad, not good. We'll see.
+ */
+
+    tmp->bounce.len = 0;	/* Assume aligned buffer */
+
+    for (i = 0; cmd->use_sg ? (i < cmd->use_sg) : !i; cmd_datain += 4, 
+	cmd_dataout += 4, ++i) {
+	u32 vbuf = cmd->use_sg
+	    ? (u32)page_address(((struct scatterlist *)cmd->buffer)[i].page)+
+	      ((struct scatterlist *)cmd->buffer)[i].offset
+	    : (u32)(cmd->request_buffer);
+	u32 bbuf = virt_to_bus((void *)vbuf);
+	u32 count = cmd->use_sg ?
+	    ((struct scatterlist *)cmd->buffer)[i].length :
+	    cmd->request_bufflen;
+
+	/*
+	 * If we have buffers which are not aligned with 16 byte cache
+	 * lines, then we just hope nothing accesses the other parts of
+	 * those cache lines while the transfer is in progress.  That would
+	 * fill the cache, and subsequent reads of the dma data would pick
+	 * up the wrong thing.
+	 * XXX We need a bounce buffer to handle that correctly.
+	 */
+
+	if (((bbuf & 15) || (count & 15)) && (datain || dataout))
+	{
+	    /* Bounce buffer needed */
+	    if (cmd->use_sg)
+		printk ("53c7xx: Non-aligned buffer with use_sg\n");
+	    else if (datain && dataout)
+                printk ("53c7xx: Non-aligned buffer with datain && dataout\n");
+            else if (count > 256)
+		printk ("53c7xx: Non-aligned transfer > 256 bytes\n");
+	    else
+	    {
+		    if (datain)
+		    {
+			tmp->bounce.len = count;
+			tmp->bounce.addr = vbuf;
+			bbuf = virt_to_bus(tmp->bounce.buf);
+			tmp->bounce.buf[0] = 0xff;
+			tmp->bounce.buf[1] = 0xfe;
+			tmp->bounce.buf[2] = 0xfd;
+			tmp->bounce.buf[3] = 0xfc;
+	    	    }
+	    	    if (dataout)
+	    	    {
+			memcpy ((void *)tmp->bounce.buf, (void *)vbuf, count);
+			bbuf = virt_to_bus(tmp->bounce.buf);
+		    }
+	    }
+	}
+
+	if (datain) {
+            cache_clear(virt_to_phys((void *)vbuf), count);
+	    /* CALL other_in, WHEN NOT DATA_IN */  
+	    cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL | 
+		DCMD_TCI_IO) << 24) | 
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+	    cmd_datain[1] = virt_to_bus (hostdata->script) + 
+		hostdata->E_other_in;
+	    /* MOVE count, buf, WHEN DATA_IN */
+	    cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO) 
+    	    	<< 24) | count;
+	    cmd_datain[3] = bbuf;
+#if 0
+	    print_insn (host, cmd_datain, "dynamic ", 1);
+	    print_insn (host, cmd_datain + 2, "dynamic ", 1);
+#endif
+	}
+	if (dataout) {
+            cache_push(virt_to_phys((void *)vbuf), count);
+	    /* CALL other_out, WHEN NOT DATA_OUT */
+	    cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) | 
+		DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+	    cmd_dataout[1] = virt_to_bus(hostdata->script) + 
+    	    	hostdata->E_other_out;
+	    /* MOVE count, buf, WHEN DATA+OUT */
+	    cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24) 
+		| count;
+	    cmd_dataout[3] = bbuf;
+#if 0
+	    print_insn (host, cmd_dataout, "dynamic ", 1);
+	    print_insn (host, cmd_dataout + 2, "dynamic ", 1);
+#endif
+	}
+    }
+
+    /*
+     * Install JUMP instructions after the data transfer routines to return
+     * control to the do_other_transfer routines.
+     */
+  
+    
+    if (datain) {
+	cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE;
+	cmd_datain[1] = virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer;
+#if 0
+	print_insn (host, cmd_datain, "dynamic jump ", 1);
+#endif
+	cmd_datain += 2; 
+    }
+#if 0
+    if (datain) {
+	cmd_datain[0] = 0x98080000;
+	cmd_datain[1] = 0x03ffdeed;
+	cmd_datain += 2;
+    }
+#endif
+    if (dataout) {
+	cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+    	    DBC_TCI_TRUE;
+	cmd_dataout[1] = virt_to_bus(hostdata->script) + 
+    	    hostdata->E_other_transfer;
+#if 0
+	print_insn (host, cmd_dataout, "dynamic jump ", 1);
+#endif
+	cmd_dataout += 2;
+    }
+
+    return tmp;
+}
+
+/*
+ * Function : int NCR53c7xx_queue_command (Scsi_Cmnd *cmd,
+ *      void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *      a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ *      cmd is added to the per instance driver issue_queue, with major
+ *      twiddling done to the host specific fields of cmd.  If the
+ *      process_issue_queue coroutine isn't running, it is restarted.
+ * 
+ * NOTE : we use the host_scribble field of the Scsi_Cmnd structure to 
+ *	hold our own data, and pervert the ptr field of the SCp field
+ *	to create a linked list.
+ */
+
+int
+NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
+    struct Scsi_Host *host = cmd->device->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    unsigned long flags;
+    Scsi_Cmnd *tmp;
+
+    cmd->scsi_done = done;
+    cmd->host_scribble = NULL;
+    cmd->SCp.ptr = NULL;
+    cmd->SCp.buffer = NULL;
+
+#ifdef VALID_IDS
+    /* Ignore commands on invalid IDs */
+    if (!hostdata->valid_ids[cmd->device->id]) {
+        printk("scsi%d : ignoring target %d lun %d\n", host->host_no,
+            cmd->device->id, cmd->device->lun);
+        cmd->result = (DID_BAD_TARGET << 16);
+        done(cmd);
+        return 0;
+    }
+#endif
+
+    local_irq_save(flags);
+    if ((hostdata->options & (OPTION_DEBUG_INIT_ONLY|OPTION_DEBUG_PROBE_ONLY)) 
+	|| ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+	    !(hostdata->debug_lun_limit[cmd->device->id] & (1 << cmd->device->lun)))
+#ifdef LINUX_1_2
+	|| cmd->device->id > 7
+#else
+	|| cmd->device->id > host->max_id
+#endif
+	|| cmd->device->id == host->this_id
+	|| hostdata->state == STATE_DISABLED) {
+	printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
+	    cmd->device->id, cmd->device->lun);
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	local_irq_restore(flags);
+	return 0;
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
+	(hostdata->debug_count_limit == 0)) {
+	printk("scsi%d : maximum commands exceeded\n", host->host_no);
+	cmd->result = (DID_BAD_TARGET << 16);
+	done(cmd);
+	local_irq_restore(flags);
+	return 0;
+    }
+
+    if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	    printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
+		host->host_no);
+	    cmd->result = (DID_BAD_TARGET << 16);
+	    done(cmd);
+	    local_irq_restore(flags);
+	    return 0;
+	}
+    }
+
+    if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
+	    hostdata->debug_count_limit != -1) 
+	--hostdata->debug_count_limit;
+
+    cmd->result = 0xffff;	/* The NCR will overwrite message
+				       and status with valid data */
+    cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
+
+    /*
+     * REQUEST SENSE commands are inserted at the head of the queue 
+     * so that we do not clear the contingent allegiance condition
+     * they may be looking at.
+     */
+
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	cmd->SCp.ptr = (unsigned char *) hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->SCp.ptr; 
+		tmp = (Scsi_Cmnd *) tmp->SCp.ptr);
+	tmp->SCp.ptr = (unsigned char *) cmd;
+    }
+    local_irq_restore(flags);
+    run_process_issue_queue();
+    return 0;
+}
+
+/*
+ * Function : void to_schedule_list (struct Scsi_Host *host,
+ * 	struct NCR53c7x0_hostdata * hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : takes a SCSI command which was just removed from the 
+ *	issue queue, and deals with it by inserting it in the first
+ *	free slot in the schedule list or by terminating it immediately.
+ *
+ * Inputs : 
+ *	host - SCSI host adapter; hostdata - hostdata structure for 
+ *	this adapter; cmd - a pointer to the command; should have 
+ *	the host_scribble field initialized to point to a valid 
+ *	
+ * Side effects : 
+ *      cmd is added to the per instance schedule list, with minor 
+ *      twiddling done to the host specific fields of cmd.
+ *
+ */
+
+static __inline__ void
+to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
+    struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    Scsi_Cmnd *tmp = cmd->cmd;
+    unsigned long flags;
+    /* dsa start is negative, so subtraction is used */
+    volatile u32 *ncrcurrent;
+
+    int i;
+    NCR53c7x0_local_setup(host);
+#if 0
+    printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no, 
+	virt_to_bus(hostdata->dsa), hostdata->dsa);
+#endif
+
+    local_irq_save(flags);
+    
+    /* 
+     * Work around race condition : if an interrupt fired and we 
+     * got disabled forget about this command.
+     */
+
+    if (hostdata->state == STATE_DISABLED) {
+	printk("scsi%d : driver disabled\n", host->host_no);
+	tmp->result = (DID_BAD_TARGET << 16);
+	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	hostdata->free = cmd;
+	tmp->scsi_done(tmp);
+	local_irq_restore(flags);
+	return;
+    }
+
+    for (i = host->can_queue, ncrcurrent = hostdata->schedule; 
+	i > 0  && ncrcurrent[0] != hostdata->NOP_insn;
+	--i, ncrcurrent += 2 /* JUMP instructions are two words */);
+
+    if (i > 0) {
+	++hostdata->busy[tmp->device->id][tmp->device->lun];
+	cmd->next = hostdata->running_list;
+	hostdata->running_list = cmd;
+
+	/* Restore this instruction to a NOP once the command starts */
+	cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) / 
+	    sizeof(u32)] = (u32) virt_to_bus ((void *)ncrcurrent);
+	/* Replace the current jump operand.  */
+	ncrcurrent[1] =
+	    virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+	    hostdata->E_dsa_code_template;
+	/* Replace the NOP instruction with a JUMP */
+	ncrcurrent[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+	    DBC_TCI_TRUE;
+    }  else {
+	printk ("scsi%d: no free slot\n", host->host_no);
+	disable(host);
+	tmp->result = (DID_ERROR << 16);
+	cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	hostdata->free = cmd;
+	tmp->scsi_done(tmp);
+	local_irq_restore(flags);
+	return;
+    }
+
+    /* 
+     * If the NCR chip is in an idle state, start it running the scheduler
+     * immediately.  Otherwise, signal the chip to jump to schedule as 
+     * soon as it is idle.
+     */
+
+    if (hostdata->idle) {
+	hostdata->idle = 0;
+	hostdata->state = STATE_RUNNING;
+	NCR53c7x0_write32 (DSP_REG,  virt_to_bus ((void *)hostdata->schedule));
+	if (hostdata->options & OPTION_DEBUG_TRACE)
+	    NCR53c7x0_write8 (DCNTL_REG, hostdata->saved_dcntl |
+				DCNTL_SSM | DCNTL_STD);
+    } else {
+	NCR53c7x0_write8(hostdata->istat, ISTAT_10_SIGP);
+    }
+
+    local_irq_restore(flags);
+}
+
+/*
+ * Function : busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata 
+ *	*hostdata, Scsi_Cmnd *cmd)
+ *
+ * Purpose : decide if we can pass the given SCSI command on to the 
+ *	device in question or not.
+ *  
+ * Returns : non-zero when we're busy, 0 when we aren't.
+ */
+
+static __inline__ int
+busyp (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata, 
+    Scsi_Cmnd *cmd) {
+    /* FIXME : in the future, this needs to accommodate SCSI-II tagged
+       queuing, and we may be able to play with fairness here a bit.
+     */
+    return hostdata->busy[cmd->device->id][cmd->device->lun];
+}
+
+/*
+ * Function : process_issue_queue (void)
+ *
+ * Purpose : transfer commands from the issue queue to NCR start queue 
+ *	of each NCR53c7/8xx in the system, avoiding kernel stack 
+ *	overflows when the scsi_done() function is invoked recursively.
+ * 
+ * NOTE : process_issue_queue exits with interrupts *disabled*, so the 
+ *	caller must reenable them if it desires.
+ * 
+ * NOTE : process_issue_queue should be called from both 
+ *	NCR53c7x0_queue_command() and from the interrupt handler 
+ *	after command completion in case NCR53c7x0_queue_command()
+ * 	isn't invoked again but we've freed up resources that are
+ *	needed.
+ */
+
+static void 
+process_issue_queue (unsigned long flags) {
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *host;
+    struct NCR53c7x0_hostdata *hostdata;
+    int done;
+
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set process_issue_queue_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     */
+
+    do {
+	local_irq_disable(); /* Freeze request queues */
+	done = 1;
+	for (host = first_host; host && host->hostt == the_template;
+	    host = host->next) {
+	    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
+	    local_irq_disable();
+	    if (hostdata->issue_queue) {
+	    	if (hostdata->state == STATE_DISABLED) {
+		    tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+		    hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
+		    tmp->result = (DID_BAD_TARGET << 16);
+		    if (tmp->host_scribble) {
+			((struct NCR53c7x0_cmd *)tmp->host_scribble)->next = 
+			    hostdata->free;
+			hostdata->free = 
+			    (struct NCR53c7x0_cmd *)tmp->host_scribble;
+			tmp->host_scribble = NULL;
+		    }
+		    tmp->scsi_done (tmp);
+		    done = 0;
+		} else 
+		    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+			prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) 
+			tmp->SCp.ptr) 
+			if (!tmp->host_scribble || 
+			    !busyp (host, hostdata, tmp)) {
+				if (prev)
+				    prev->SCp.ptr = tmp->SCp.ptr;
+				else
+				    hostdata->issue_queue = (Scsi_Cmnd *) 
+					tmp->SCp.ptr;
+			    tmp->SCp.ptr = NULL;
+			    if (tmp->host_scribble) {
+				if (hostdata->options & OPTION_DEBUG_QUEUES) 
+				    printk ("scsi%d : moving command for target %d lun %d to start list\n",
+					host->host_no, tmp->device->id, tmp->device->lun);
+		
+
+			    	to_schedule_list (host, hostdata, 
+				    (struct NCR53c7x0_cmd *)
+				    tmp->host_scribble);
+			    } else {
+				if (((tmp->result & 0xff) == 0xff) ||
+			    	    ((tmp->result & 0xff00) == 0xff00)) {
+				    printk ("scsi%d : danger Will Robinson!\n",
+					host->host_no);
+				    tmp->result = DID_ERROR << 16;
+				    disable (host);
+				}
+				tmp->scsi_done(tmp);
+			    }
+			    done = 0;
+			} /* if target/lun is not busy */
+	    } /* if hostdata->issue_queue */
+	    if (!done)
+		local_irq_restore(flags);
+    	} /* for host */
+    } while (!done);
+    process_issue_queue_running = 0;
+}
+
+/*
+ * Function : static void intr_scsi (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all SCSI interrupts, indicated by the setting 
+ * 	of the SIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void 
+intr_scsi (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = 
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    unsigned char sstat0_sist0, sist1, 		/* Registers */
+	    fatal; 				/* Did a fatal interrupt 
+						   occur ? */
+   
+    NCR53c7x0_local_setup(host);
+
+    fatal = 0;
+
+    sstat0_sist0 = NCR53c7x0_read8(SSTAT0_REG);
+    sist1 = 0;
+
+    if (hostdata->options & OPTION_DEBUG_INTR) 
+	printk ("scsi%d : SIST0 0x%0x, SIST1 0x%0x\n", host->host_no,
+	    sstat0_sist0, sist1);
+
+    /* 250ms selection timeout */
+    if (sstat0_sist0 & SSTAT0_700_STO) {
+	fatal = 1;
+	if (hostdata->options & OPTION_DEBUG_INTR) {
+	    printk ("scsi%d : Selection Timeout\n", host->host_no);
+    	    if (cmd) {
+    	    	printk("scsi%d : target %d, lun %d, command ",
+		    host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
+    	    	print_command (cmd->cmd->cmnd);
+		printk("scsi%d : dsp = 0x%x (virt 0x%p)\n", host->host_no,
+		    NCR53c7x0_read32(DSP_REG),
+		    bus_to_virt(NCR53c7x0_read32(DSP_REG)));
+    	    } else {
+    	    	printk("scsi%d : no command\n", host->host_no);
+    	    }
+    	}
+/*
+ * XXX - question : how do we want to handle the Illegal Instruction
+ * 	interrupt, which may occur before or after the Selection Timeout
+ * 	interrupt?
+ */
+
+	if (1) {
+	    hostdata->idle = 1;
+	    hostdata->expecting_sto = 0;
+
+	    if (hostdata->test_running) {
+		hostdata->test_running = 0;
+		hostdata->test_completed = 3;
+	    } else if (cmd) {
+		abnormal_finished(cmd, DID_BAD_TARGET << 16);
+	    }
+#if 0	    
+	    hostdata->intrs = 0;
+#endif
+	}
+    } 
+
+/*
+ * FIXME : in theory, we can also get a UDC when a STO occurs.
+ */
+    if (sstat0_sist0 & SSTAT0_UDC) {
+	fatal = 1;
+	if (cmd) {
+	    printk("scsi%d : target %d lun %d unexpected disconnect\n",
+		host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
+	    print_lots (host);
+	    abnormal_finished(cmd, DID_ERROR << 16);
+	} else 
+	     printk("scsi%d : unexpected disconnect (no command)\n",
+		host->host_no);
+
+	hostdata->dsp = (u32 *) hostdata->schedule;
+	hostdata->dsp_changed = 1;
+    }
+
+    /* SCSI PARITY error */
+    if (sstat0_sist0 & SSTAT0_PAR) {
+	fatal = 1;
+	if (cmd && cmd->cmd) {
+	    printk("scsi%d : target %d lun %d parity error.\n",
+		host->host_no, cmd->cmd->device->id, cmd->cmd->device->lun);
+	    abnormal_finished (cmd, DID_PARITY << 16); 
+	} else
+	    printk("scsi%d : parity error\n", host->host_no);
+	/* Should send message out, parity error */
+
+	/* XXX - Reduce synchronous transfer rate! */
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1; 
+    /* SCSI GROSS error */
+    } 
+
+    if (sstat0_sist0 & SSTAT0_SGE) {
+	fatal = 1;
+	printk("scsi%d : gross error, saved2_dsa = 0x%x\n", host->host_no,
+					(unsigned int)hostdata->saved2_dsa);
+	print_lots (host);
+	
+	/* 
+         * A SCSI gross error may occur when we have 
+	 *
+	 * - A synchronous offset which causes the SCSI FIFO to be overwritten.
+	 *
+	 * - A REQ which causes the maximum synchronous offset programmed in 
+	 * 	the SXFER register to be exceeded.
+	 *
+	 * - A phase change with an outstanding synchronous offset.
+	 *
+	 * - Residual data in the synchronous data FIFO, with a transfer
+	 *	other than a synchronous receive is started.$#
+	 */
+		
+
+	/* XXX Should deduce synchronous transfer rate! */
+	hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+    	    sizeof(u32);
+	hostdata->dsp_changed = 1;
+    /* Phase mismatch */
+    } 
+
+    if (sstat0_sist0 & SSTAT0_MA) {
+	fatal = 1;
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk ("scsi%d : SSTAT0_MA\n", host->host_no);
+	intr_phase_mismatch (host, cmd);
+    }
+
+#if 0
+    if (sstat0_sist0 & SIST0_800_RSL) 
+	printk ("scsi%d : Oh no Mr. Bill!\n", host->host_no);
+#endif
+    
+/*
+ * If a fatal SCSI interrupt occurs, we must insure that the DMA and
+ * SCSI FIFOs were flushed.
+ */
+
+    if (fatal) {
+	if (!hostdata->dstat_valid) {
+	    hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	    hostdata->dstat_valid = 1;
+	}
+
+	if (!(hostdata->dstat & DSTAT_DFE)) {
+	  printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+	  /*
+	   * Really need to check this code for 710  RGH.
+	   * Havn't seen any problems, but maybe we should FLUSH before
+	   * clearing sometimes.
+	   */
+          NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+          while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
+		;
+	  hostdata->dstat |= DSTAT_DFE;
+    	}
+    }
+}
+
+#ifdef CYCLIC_TRACE
+
+/*
+ * The following implements a cyclic log of instructions executed, if you turn
+ * TRACE on.  It will also print the log for you.  Very useful when debugging
+ * 53c710 support, possibly not really needed any more.
+ */
+
+u32 insn_log[4096];
+u32 insn_log_index = 0;
+
+void log1 (u32 i)
+{
+	insn_log[insn_log_index++] = i;
+	if (insn_log_index == 4096)
+		insn_log_index = 0;
+}
+
+void log_insn (u32 *ip)
+{
+	log1 ((u32)ip);
+	log1 (*ip);
+	log1 (*(ip+1));
+	if (((*ip >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)
+		log1 (*(ip+2));
+}
+
+void dump_log(void)
+{
+	int cnt = 0;
+	int i = insn_log_index;
+	int size;
+	struct Scsi_Host *host = first_host;
+
+	while (cnt < 4096) {
+		printk ("%08x (+%6x): ", insn_log[i], (insn_log[i] - (u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4);
+		if (++i == 4096)
+			i = 0;
+		cnt++;
+		if (((insn_log[i]  >> 24) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) 
+			size = 3;
+		else
+			size = 2;
+		while (size--) {
+			printk ("%08x ", insn_log[i]);
+			if (++i == 4096)
+				i = 0;
+			cnt++;
+		}
+		printk ("\n");
+	}
+}
+#endif
+
+
+/*
+ * Function : static void NCR53c7x0_intfly (struct Scsi_Host *host)
+ *
+ * Purpose : Scan command queue for specified host, looking for completed
+ *           commands.
+ * 
+ * Inputs : Scsi_Host pointer.
+ *
+ * 	This is called from the interrupt handler, when a simulated INTFLY
+ * 	interrupt occurs.
+ */
+
+static void
+NCR53c7x0_intfly (struct Scsi_Host *host)
+{
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata[0] */
+    struct NCR53c7x0_cmd *cmd,			/* command which halted */
+	**cmd_prev_ptr;
+    unsigned long flags;				
+    char search_found = 0;			/* Got at least one ? */
+
+    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
+    NCR53c7x0_local_setup(host);
+
+    if (hostdata->options & OPTION_DEBUG_INTR)
+    printk ("scsi%d : INTFLY\n", host->host_no); 
+
+    /*
+    * Traverse our list of running commands, and look
+    * for those with valid (non-0xff ff) status and message
+    * bytes encoded in the result which signify command
+    * completion.
+    */
+
+    local_irq_save(flags);
+restart:
+    for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)&(hostdata->running_list),
+	cmd = (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+	cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next), 
+    	cmd = (struct NCR53c7x0_cmd *) cmd->next)
+    {
+	Scsi_Cmnd *tmp;
+
+	if (!cmd) {
+	    printk("scsi%d : very weird.\n", host->host_no);
+	    break;
+	}
+
+	if (!(tmp = cmd->cmd)) {
+	    printk("scsi%d : weird.  NCR53c7x0_cmd has no Scsi_Cmnd\n",
+		    host->host_no);
+	    continue;
+	}
+	/* Copy the result over now; may not be complete,
+	 * but subsequent tests may as well be done on
+	 * cached memory.
+	 */
+	tmp->result = cmd->result;
+
+	if (((tmp->result & 0xff) == 0xff) ||
+			    ((tmp->result & 0xff00) == 0xff00))
+	    continue;
+
+	search_found = 1;
+
+	if (cmd->bounce.len)
+	    memcpy ((void *)cmd->bounce.addr,
+				(void *)cmd->bounce.buf, cmd->bounce.len);
+
+	/* Important - remove from list _before_ done is called */
+	if (cmd_prev_ptr)
+	    *cmd_prev_ptr = (struct NCR53c7x0_cmd *) cmd->next;
+
+	--hostdata->busy[tmp->device->id][tmp->device->lun];
+	cmd->next = hostdata->free;
+	hostdata->free = cmd;
+
+	tmp->host_scribble = NULL;
+
+	if (hostdata->options & OPTION_DEBUG_INTR) {
+	    printk ("scsi%d : command complete : pid %lu, id %d,lun %d result 0x%x ", 
+		  host->host_no, tmp->pid, tmp->device->id, tmp->device->lun, tmp->result);
+	    print_command (tmp->cmnd);
+	}
+
+	tmp->scsi_done(tmp);
+	goto restart;
+    }
+    local_irq_restore(flags);
+
+    if (!search_found)  {
+	printk ("scsi%d : WARNING : INTFLY with no completed commands.\n",
+			    host->host_no);
+    } else {
+	run_process_issue_queue();
+    }
+    return;
+}
+
+/*
+ * Function : static irqreturn_t NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+ *
+ * Purpose : handle NCR53c7x0 interrupts for all NCR devices sharing
+ *	the same IRQ line.  
+ * 
+ * Inputs : Since we're using the SA_INTERRUPT interrupt handler
+ *	semantics, irq indicates the interrupt which invoked 
+ *	this handler.  
+ *
+ * On the 710 we simualte an INTFLY with a script interrupt, and the
+ * script interrupt handler will call back to this function.
+ */
+
+static irqreturn_t
+NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs)
+{
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host;			/* Host we are looking at */
+    unsigned char istat; 			/* Values of interrupt regs */
+    struct NCR53c7x0_hostdata *hostdata;	/* host->hostdata[0] */
+    struct NCR53c7x0_cmd *cmd;			/* command which halted */
+    u32 *dsa;					/* DSA */
+    int handled = 0;
+
+#ifdef NCR_DEBUG
+    char buf[80];				/* Debugging sprintf buffer */
+    size_t buflen;				/* Length of same */
+#endif
+
+    host     = (struct Scsi_Host *)dev_id;
+    hostdata = (struct NCR53c7x0_hostdata *) host->hostdata[0];
+    NCR53c7x0_local_setup(host);
+
+    /*
+     * Only read istat once per loop, since reading it again will unstack
+     * interrupts
+     */
+
+    while ((istat = NCR53c7x0_read8(hostdata->istat)) & (ISTAT_SIP|ISTAT_DIP)) {
+	handled = 1;
+	hostdata->dsp_changed = 0;
+	hostdata->dstat_valid = 0;
+    	hostdata->state = STATE_HALTED;
+
+	if (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) 
+	    printk ("scsi%d : SCSI FIFO not empty\n", host->host_no);
+
+	/*
+	 * NCR53c700 and NCR53c700-66 change the current SCSI
+	 * process, hostdata->ncrcurrent, in the Linux driver so
+	 * cmd = hostdata->ncrcurrent.
+	 *
+	 * With other chips, we must look through the commands
+	 * executing and find the command structure which 
+	 * corresponds to the DSA register.
+	 */
+
+	if (hostdata->options & OPTION_700) {
+	    cmd = (struct NCR53c7x0_cmd *) hostdata->ncrcurrent;
+	} else {
+	    dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+	    for (cmd = (struct NCR53c7x0_cmd *) hostdata->running_list;
+		cmd && (dsa + (hostdata->dsa_start / sizeof(u32))) != cmd->dsa;
+		    cmd = (struct NCR53c7x0_cmd *)(cmd->next))
+		;
+	}
+	if (hostdata->options & OPTION_DEBUG_INTR) {
+	    if (cmd) {
+		printk("scsi%d : interrupt for pid %lu, id %d, lun %d ", 
+		    host->host_no, cmd->cmd->pid, (int) cmd->cmd->device->id,
+		    (int) cmd->cmd->device->lun);
+		print_command (cmd->cmd->cmnd);
+	    } else {
+		printk("scsi%d : no active command\n", host->host_no);
+	    }
+	}
+	
+	if (istat & ISTAT_SIP) {
+	    if (hostdata->options & OPTION_DEBUG_INTR) 
+		printk ("scsi%d : ISTAT_SIP\n", host->host_no);
+	    intr_scsi (host, cmd);
+	}
+	
+	if (istat & ISTAT_DIP) {
+	    if (hostdata->options & OPTION_DEBUG_INTR) 
+		printk ("scsi%d : ISTAT_DIP\n", host->host_no);
+	    intr_dma (host, cmd);
+	}
+	
+	if (!hostdata->dstat_valid) {
+	    hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	    hostdata->dstat_valid = 1;
+	}
+	
+	if (!(hostdata->dstat & DSTAT_DFE)) {
+	    printk ("scsi%d : DMA FIFO not empty\n", host->host_no);
+	    /* Really need to check this out for 710 RGH */
+	    NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+	    while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF)
+		;
+	    hostdata->dstat |= DSTAT_DFE;
+	}
+
+	if (!hostdata->idle && hostdata->state == STATE_HALTED) {
+	    if (!hostdata->dsp_changed)
+		hostdata->dsp = (u32 *)bus_to_virt(NCR53c7x0_read32(DSP_REG));
+#if 0
+	    printk("scsi%d : new dsp is 0x%lx (virt 0x%p)\n",
+		host->host_no,  virt_to_bus(hostdata->dsp), hostdata->dsp);
+#endif
+		
+	    hostdata->state = STATE_RUNNING;
+	    NCR53c7x0_write32 (DSP_REG, virt_to_bus(hostdata->dsp));
+	    if (hostdata->options & OPTION_DEBUG_TRACE) {
+#ifdef CYCLIC_TRACE
+		log_insn (hostdata->dsp);
+#else
+	    	print_insn (host, hostdata->dsp, "t ", 1);
+#endif
+		NCR53c7x0_write8 (DCNTL_REG,
+			hostdata->saved_dcntl | DCNTL_SSM | DCNTL_STD);
+	    }
+	}
+    }
+    return IRQ_HANDLED;
+}
+
+
+/* 
+ * Function : static int abort_connected (struct Scsi_Host *host)
+ *
+ * Purpose : Assuming that the NCR SCSI processor is currently 
+ * 	halted, break the currently established nexus.  Clean
+ *	up of the NCR53c7x0_cmd and Scsi_Cmnd structures should
+ *	be done on receipt of the abort interrupt.
+ *
+ * Inputs : host - SCSI host
+ *
+ */
+
+static int 
+abort_connected (struct Scsi_Host *host) {
+#ifdef NEW_ABORT
+    NCR53c7x0_local_declare();
+#endif
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+/* FIXME : this probably should change for production kernels; at the 
+   least, counter should move to a per-host structure. */
+    static int counter = 5;
+#ifdef NEW_ABORT
+    int sstat, phase, offset;
+    u32 *script;
+    NCR53c7x0_local_setup(host);
+#endif
+
+    if (--counter <= 0) {
+	disable(host);
+	return 0;
+    }
+
+    printk ("scsi%d : DANGER : abort_connected() called \n",
+	host->host_no);
+
+#ifdef NEW_ABORT
+
+/*
+ * New strategy : Rather than using a generic abort routine,
+ * we'll specifically try to source or sink the appropriate
+ * amount of data for the phase we're currently in (taking into 
+ * account the current synchronous offset) 
+ */
+
+    sstat = (NCR53c8x0_read8 (SSTAT2_REG);
+    offset = OFFSET (sstat & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+    phase = sstat & SSTAT2_PHASE_MASK;
+
+/*
+ * SET ATN
+ * MOVE source_or_sink, WHEN CURRENT PHASE 
+ * < repeat for each outstanding byte >
+ * JUMP send_abort_message
+ */
+
+    script = hostdata->abort_script = kmalloc (
+	8  /* instruction size */ * (
+	    1 /* set ATN */ +
+	    (!offset ? 1 : offset) /* One transfer per outstanding byte */ +
+	    1 /* send abort message */),
+	GFP_ATOMIC);
+
+
+#else /* def NEW_ABORT */
+    hostdata->dsp = hostdata->script + hostdata->E_initiator_abort /
+	    sizeof(u32);
+#endif /* def NEW_ABORT */
+    hostdata->dsp_changed = 1;
+
+/* XXX - need to flag the command as aborted after the abort_connected
+ 	 code runs 
+ */
+    return 0;
+}
+
+/*
+ * Function : static int datapath_residual (Scsi_Host *host)
+ *
+ * Purpose : return residual data count of what's in the chip.
+ *
+ * Inputs : host - SCSI host
+ */
+
+static int
+datapath_residual (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    int count, synchronous, sstat;
+    unsigned int ddir;
+
+    NCR53c7x0_local_setup(host);
+    /* COMPAT : the 700 and 700-66 need to use DFIFO_00_BO_MASK */
+    count = ((NCR53c7x0_read8 (DFIFO_REG) & DFIFO_10_BO_MASK) -
+	(NCR53c7x0_read32 (DBC_REG) & DFIFO_10_BO_MASK)) & DFIFO_10_BO_MASK;
+    synchronous = NCR53c7x0_read8 (SXFER_REG) & SXFER_MO_MASK;
+    /* COMPAT : DDIR is elsewhere on non-'8xx chips. */
+    ddir = NCR53c7x0_read8 (CTEST0_REG_700) & CTEST0_700_DDIR;
+
+    if (ddir) {
+    /* Receive */
+	if (synchronous) 
+	    count += (NCR53c7x0_read8 (SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT;
+	else
+	    if (NCR53c7x0_read8 (SSTAT1_REG) & SSTAT1_ILF)
+		++count;
+    } else {
+    /* Send */
+	sstat = NCR53c7x0_read8 (SSTAT1_REG);
+	if (sstat & SSTAT1_OLF)
+	    ++count;
+	if (synchronous && (sstat & SSTAT1_ORF))
+	    ++count;
+    }
+    return count;
+}
+
+/* 
+ * Function : static const char * sbcl_to_phase (int sbcl)_
+ *
+ * Purpose : Convert SBCL register to user-parsable phase representation
+ *
+ * Inputs : sbcl - value of sbcl register
+ */
+
+
+static const char *
+sbcl_to_phase (int sbcl) {
+    switch (sbcl & SBCL_PHASE_MASK) {
+    case SBCL_PHASE_DATAIN:
+	return "DATAIN";
+    case SBCL_PHASE_DATAOUT:
+	return "DATAOUT";
+    case SBCL_PHASE_MSGIN:
+	return "MSGIN";
+    case SBCL_PHASE_MSGOUT:
+	return "MSGOUT";
+    case SBCL_PHASE_CMDOUT:
+	return "CMDOUT";
+    case SBCL_PHASE_STATIN:
+	return "STATUSIN";
+    default:
+	return "unknown";
+    }
+}
+
+/* 
+ * Function : static const char * sstat2_to_phase (int sstat)_
+ *
+ * Purpose : Convert SSTAT2 register to user-parsable phase representation
+ *
+ * Inputs : sstat - value of sstat register
+ */
+
+
+static const char *
+sstat2_to_phase (int sstat) {
+    switch (sstat & SSTAT2_PHASE_MASK) {
+    case SSTAT2_PHASE_DATAIN:
+	return "DATAIN";
+    case SSTAT2_PHASE_DATAOUT:
+	return "DATAOUT";
+    case SSTAT2_PHASE_MSGIN:
+	return "MSGIN";
+    case SSTAT2_PHASE_MSGOUT:
+	return "MSGOUT";
+    case SSTAT2_PHASE_CMDOUT:
+	return "CMDOUT";
+    case SSTAT2_PHASE_STATIN:
+	return "STATUSIN";
+    default:
+	return "unknown";
+    }
+}
+
+/* 
+ * Function : static void intr_phase_mismatch (struct Scsi_Host *host, 
+ *	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : Handle phase mismatch interrupts
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ *
+ * Side effects : The abort_connected() routine is called or the NCR chip 
+ *	is restarted, jumping to the command_complete entry point, or 
+ *	patching the address and transfer count of the current instruction 
+ *	and calling the msg_in entry point as appropriate.
+ */
+
+static void 
+intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    u32 dbc_dcmd, *dsp, *dsp_next;
+    unsigned char dcmd, sbcl;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+    	host->hostdata[0];
+    int residual;
+    enum {ACTION_ABORT, ACTION_ABORT_PRINT, ACTION_CONTINUE} action = 
+	ACTION_ABORT_PRINT;
+    const char *where = NULL;
+
+    NCR53c7x0_local_setup(host);
+
+    /*
+     * Corrective action is based on where in the SCSI SCRIPT(tm) the error 
+     * occurred, as well as which SCSI phase we are currently in.
+     */
+    dsp_next = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+
+    /* 
+     * Fetch the current instruction, and remove the operands for easier 
+     * interpretation.
+     */
+    dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+    dcmd = (dbc_dcmd & 0xff000000) >> 24;
+    /*
+     * Like other processors, the NCR adjusts the instruction pointer before
+     * instruction decode.  Set the DSP address back to what it should
+     * be for this instruction based on its size (2 or 3 32 bit words).
+     */
+    dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+
+
+    /*
+     * Read new SCSI phase from the SBCL lines.  Since all of our code uses 
+     * a WHEN conditional instead of an IF conditional, we don't need to 
+     * wait for a new REQ.
+     */
+    sbcl = NCR53c7x0_read8(SBCL_REG) & SBCL_PHASE_MASK;
+
+    if (!cmd) {
+	action = ACTION_ABORT_PRINT;
+	where = "no current command";
+    /*
+     * The way my SCSI SCRIPTS(tm) are architected, recoverable phase
+     * mismatches should only occur where we're doing a multi-byte  
+     * BMI instruction.  Specifically, this means 
+     *
+     *  - select messages (a SCSI-I target may ignore additional messages
+     * 		after the IDENTIFY; any target may reject a SDTR or WDTR)
+     *
+     *  - command out (targets may send a message to signal an error 
+     * 		condition, or go into STATUSIN after they've decided 
+     *		they don't like the command.
+     *
+     *	- reply_message (targets may reject a multi-byte message in the 
+     *		middle)
+     *
+     * 	- data transfer routines (command completion with buffer space
+     *		left, disconnect message, or error message)
+     */
+    } else if (((dsp >= cmd->data_transfer_start && 
+	dsp < cmd->data_transfer_end)) || dsp == (cmd->residual + 2)) {
+	if ((dcmd & (DCMD_TYPE_MASK|DCMD_BMI_OP_MASK|DCMD_BMI_INDIRECT|
+		DCMD_BMI_MSG|DCMD_BMI_CD)) == (DCMD_TYPE_BMI|
+		DCMD_BMI_OP_MOVE_I)) {
+	    residual = datapath_residual (host);
+	    if (hostdata->options & OPTION_DEBUG_DISCONNECT)
+	    	printk ("scsi%d : handling residual transfer (+ %d bytes from DMA FIFO)\n", 
+		    host->host_no, residual);
+
+	    /*
+	     * The first instruction is a CALL to the alternate handler for 
+	     * this data transfer phase, so we can do calls to 
+	     * munge_msg_restart as we would if control were passed 
+	     * from normal dynamic code.
+	     */
+	    if (dsp != cmd->residual + 2) {
+		cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+			((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) | 
+		    DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
+		cmd->residual[1] = virt_to_bus(hostdata->script)
+		    + ((dcmd & DCMD_BMI_IO)
+		       ? hostdata->E_other_in : hostdata->E_other_out);
+	    }
+
+	    /*
+	     * The second instruction is the a data transfer block
+	     * move instruction, reflecting the pointer and count at the 
+	     * time of the phase mismatch.
+	     */
+	    cmd->residual[2] = dbc_dcmd + residual;
+	    cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+
+	    /*
+	     * The third and final instruction is a jump to the instruction
+	     * which follows the instruction which had to be 'split'
+	     */
+	    if (dsp != cmd->residual + 2) {
+		cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) 
+		    << 24) | DBC_TCI_TRUE;
+		cmd->residual[5] = virt_to_bus(dsp_next);
+	    }
+
+	    /*
+	     * For the sake of simplicity, transfer control to the 
+	     * conditional CALL at the start of the residual buffer.
+	     */
+	    hostdata->dsp = cmd->residual;
+	    hostdata->dsp_changed = 1;
+	    action = ACTION_CONTINUE;
+	} else {
+	    where = "non-BMI dynamic DSA code";
+	    action = ACTION_ABORT_PRINT;
+	}
+    } else if (dsp == (hostdata->script + hostdata->E_select_msgout / 4 + 2)) {
+	/* RGH 290697:  Added +2 above, to compensate for the script
+	 * instruction which disables the selection timer. */
+	/* Release ATN */
+	NCR53c7x0_write8 (SOCL_REG, 0);
+	switch (sbcl) {
+    /* 
+     * Some devices (SQ555 come to mind) grab the IDENTIFY message
+     * sent on selection, and decide to go into COMMAND OUT phase
+     * rather than accepting the rest of the messages or rejecting
+     * them.  Handle these devices gracefully.
+     */
+	case SBCL_PHASE_CMDOUT:
+	    hostdata->dsp = dsp + 2 /* two _words_ */;
+	    hostdata->dsp_changed = 1;
+	    printk ("scsi%d : target %d ignored SDTR and went into COMMAND OUT\n", 
+		host->host_no, cmd->cmd->device->id);
+	    cmd->flags &= ~CMD_FLAG_SDTR;
+	    action = ACTION_CONTINUE;
+	    break;
+	case SBCL_PHASE_MSGIN:
+	    hostdata->dsp = hostdata->script + hostdata->E_msg_in / 
+		sizeof(u32);
+	    hostdata->dsp_changed = 1;
+	    action = ACTION_CONTINUE;
+	    break;
+	default:
+	    where="select message out";
+	    action = ACTION_ABORT_PRINT;
+	}
+    /*
+     * Some SCSI devices will interpret a command as they read the bytes
+     * off the SCSI bus, and may decide that the command is Bogus before 
+     * they've read the entire command off the bus.
+     */
+    } else if (dsp == hostdata->script + hostdata->E_cmdout_cmdout / sizeof 
+	(u32)) {
+	hostdata->dsp = hostdata->script + hostdata->E_data_transfer /
+	    sizeof (u32);
+	hostdata->dsp_changed = 1;
+	action = ACTION_CONTINUE;
+    /* FIXME : we need to handle message reject, etc. within msg_respond. */
+#ifdef notyet
+    } else if (dsp == hostdata->script + hostdata->E_reply_message) {
+	switch (sbcl) {
+    /* Any other phase mismatches abort the currently executing command.  */
+#endif
+    } else {
+	where = "unknown location";
+	action = ACTION_ABORT_PRINT;
+    }
+
+    /* Flush DMA FIFO */
+    if (!hostdata->dstat_valid) {
+	hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	hostdata->dstat_valid = 1;
+    }
+    if (!(hostdata->dstat & DSTAT_DFE)) {
+      /* Really need to check this out for 710 RGH */
+      NCR53c7x0_write8 (CTEST8_REG, CTEST8_10_CLF);
+      while (NCR53c7x0_read8 (CTEST8_REG) & CTEST8_10_CLF);
+      hostdata->dstat |= DSTAT_DFE;
+    }
+
+    switch (action) {
+    case ACTION_ABORT_PRINT:
+	printk("scsi%d : %s : unexpected phase %s.\n",
+	     host->host_no, where ? where : "unknown location", 
+	     sbcl_to_phase(sbcl));
+	print_lots (host);
+    /* Fall through to ACTION_ABORT */
+    case ACTION_ABORT:
+	abort_connected (host);
+	break;
+    case ACTION_CONTINUE:
+	break;
+    }
+
+#if 0
+    if (hostdata->dsp_changed) {
+	printk("scsi%d: new dsp 0x%p\n", host->host_no, hostdata->dsp);
+	print_insn (host, hostdata->dsp, "", 1);
+    }
+#endif
+}
+
+/*
+ * Function : static void intr_bf (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle BUS FAULT interrupts 
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void
+intr_bf (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    u32 *dsp,
+	*next_dsp,		/* Current dsp */
+    	*dsa,
+	dbc_dcmd;		/* DCMD (high eight bits) + DBC */
+    char *reason = NULL;
+    /* Default behavior is for a silent error, with a retry until we've
+       exhausted retries. */
+    enum {MAYBE, ALWAYS, NEVER} retry = MAYBE;
+    int report = 0;
+    NCR53c7x0_local_setup(host);
+
+    dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+    next_dsp = bus_to_virt (NCR53c7x0_read32(DSP_REG));
+    dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* FIXME - check chip type  */
+    dsa = bus_to_virt (NCR53c7x0_read32(DSA_REG));
+
+    /*
+     * Bus faults can be caused by either a Bad Address or 
+     * Target Abort. We should check the Received Target Abort
+     * bit of the PCI status register and Master Abort Bit.
+     *
+     * 	- Master Abort bit indicates that no device claimed
+     *		the address with DEVSEL within five clocks
+     *
+     *	- Target Abort bit indicates that a target claimed it,
+     *		but changed its mind once it saw the byte enables.
+     *
+     */
+
+    /* 53c710, not PCI system */
+    report = 1;
+    reason = "Unknown";
+
+#ifndef notyet
+    report = 1;
+#endif
+    if (report && reason)
+    {
+	printk(KERN_ALERT "scsi%d : BUS FAULT reason = %s\n",
+	     host->host_no, reason ? reason : "unknown");
+	print_lots (host);
+    }
+
+#ifndef notyet
+    retry = NEVER;
+#endif
+
+    /* 
+     * TODO : we should attempt to recover from any spurious bus 
+     * faults.  After X retries, we should figure that things are 
+     * sufficiently wedged, and call NCR53c7xx_reset.
+     *
+     * This code should only get executed once we've decided that we 
+     * cannot retry.
+     */
+
+    if (retry == NEVER) {
+    	printk(KERN_ALERT "          mail richard@sleepie.demon.co.uk\n");
+    	FATAL (host);
+    }
+}
+
+/*
+ * Function : static void intr_dma (struct Scsi_Host *host, 
+ * 	struct NCR53c7x0_cmd *cmd)
+ *
+ * Purpose : handle all DMA interrupts, indicated by the setting 
+ * 	of the DIP bit in the ISTAT register.
+ *
+ * Inputs : host, cmd - host and NCR command causing the interrupt, cmd
+ * 	may be NULL.
+ */
+
+static void 
+intr_dma (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    unsigned char dstat;	/* DSTAT */	
+    u32 *dsp,
+	*next_dsp,		/* Current dsp */
+    	*dsa,
+	dbc_dcmd;		/* DCMD (high eight bits) + DBC */
+    int tmp;
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+
+    if (!hostdata->dstat_valid) {
+	hostdata->dstat = NCR53c7x0_read8(DSTAT_REG);
+	hostdata->dstat_valid = 1;
+    }
+    
+    dstat = hostdata->dstat;
+    
+    if (hostdata->options & OPTION_DEBUG_INTR)
+	printk("scsi%d : DSTAT=0x%x\n", host->host_no, (int) dstat);
+
+    dbc_dcmd = NCR53c7x0_read32 (DBC_REG);
+    next_dsp = bus_to_virt(NCR53c7x0_read32(DSP_REG));
+    dsp = next_dsp - NCR53c7x0_insn_size ((dbc_dcmd >> 24) & 0xff);
+/* XXX - check chip type */
+    dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+
+    /*
+     * DSTAT_ABRT is the aborted interrupt.  This is set whenever the 
+     * SCSI chip is aborted.  
+     * 
+     * With NCR53c700 and NCR53c700-66 style chips, we should only 
+     * get this when the chip is currently running the accept 
+     * reselect/select code and we have set the abort bit in the 
+     * ISTAT register.
+     *
+     */
+    
+    if (dstat & DSTAT_ABRT) {
+#if 0
+	/* XXX - add code here to deal with normal abort */
+	if ((hostdata->options & OPTION_700) && (hostdata->state ==
+	    STATE_ABORTING)) {
+	} else 
+#endif
+	{
+	    printk(KERN_ALERT "scsi%d : unexpected abort interrupt at\n" 
+		   "         ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "s ", 1);
+	    FATAL (host);
+	}
+    }
+
+    /*
+     * DSTAT_SSI is the single step interrupt.  Should be generated 
+     * whenever we have single stepped or are tracing.
+     */
+
+    if (dstat & DSTAT_SSI) {
+	if (hostdata->options & OPTION_DEBUG_TRACE) {
+	    /* Don't print instr. until we write DSP at end of intr function */
+	} else if (hostdata->options & OPTION_DEBUG_SINGLE) {
+	    print_insn (host, dsp, "s ", 0);
+	    local_irq_save(flags);
+/* XXX - should we do this, or can we get away with writing dsp? */
+
+	    NCR53c7x0_write8 (DCNTL_REG, (NCR53c7x0_read8(DCNTL_REG) & 
+    	    	~DCNTL_SSM) | DCNTL_STD);
+	    local_irq_restore(flags);
+	} else {
+	    printk(KERN_ALERT "scsi%d : unexpected single step interrupt at\n"
+		   "         ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT "         mail drew@PoohSticks.ORG\n");
+    	    FATAL (host);
+    	}
+    }
+
+    /*
+     * DSTAT_IID / DSTAT_OPC (same bit, same meaning, only the name 
+     * is different) is generated whenever an illegal instruction is 
+     * encountered.  
+     * 
+     * XXX - we may want to emulate INTFLY here, so we can use 
+     *    the same SCSI SCRIPT (tm) for NCR53c710 through NCR53c810  
+     *	  chips.
+     */
+
+    if (dstat & DSTAT_OPC) {
+    /* 
+     * Ascertain if this IID interrupts occurred before or after a STO 
+     * interrupt.  Since the interrupt handling code now leaves 
+     * DSP unmodified until _after_ all stacked interrupts have been
+     * processed, reading the DSP returns the original DSP register.
+     * This means that if dsp lies between the select code, and 
+     * message out following the selection code (where the IID interrupt
+     * would have to have occurred by due to the implicit wait for REQ),
+     * we have an IID interrupt resulting from a STO condition and 
+     * can ignore it.
+     */
+
+	if (((dsp >= (hostdata->script + hostdata->E_select / sizeof(u32))) &&
+	    (dsp <= (hostdata->script + hostdata->E_select_msgout / 
+    	    sizeof(u32) + 8))) || (hostdata->test_running == 2)) {
+	    if (hostdata->options & OPTION_DEBUG_INTR) 
+		printk ("scsi%d : ignoring DSTAT_IID for SSTAT_STO\n",
+		    host->host_no);
+	    if (hostdata->expecting_iid) {
+		hostdata->expecting_iid = 0;
+		hostdata->idle = 1;
+		if (hostdata->test_running == 2) {
+		    hostdata->test_running = 0;
+		    hostdata->test_completed = 3;
+		} else if (cmd) 
+			abnormal_finished (cmd, DID_BAD_TARGET << 16);
+	    } else {
+		hostdata->expecting_sto = 1;
+	    }
+    /*
+     * We can't guarantee we'll be able to execute the WAIT DISCONNECT
+     * instruction within the 3.4us of bus free and arbitration delay
+     * that a target can RESELECT in and assert REQ after we've dropped
+     * ACK.  If this happens, we'll get an illegal instruction interrupt.
+     * Doing away with the WAIT DISCONNECT instructions broke everything,
+     * so instead I'll settle for moving one WAIT DISCONNECT a few 
+     * instructions closer to the CLEAR ACK before it to minimize the
+     * chances of this happening, and handle it if it occurs anyway.
+     *
+     * Simply continue with what we were doing, and control should
+     * be transferred to the schedule routine which will ultimately
+     * pass control onto the reselection or selection (not yet)
+     * code.
+     */
+	} else if (dbc_dcmd == 0x48000000 && (NCR53c7x0_read8 (SBCL_REG) &
+	    SBCL_REQ)) {
+	    if (!(hostdata->options & OPTION_NO_PRINT_RACE))
+	    {
+		printk("scsi%d: REQ before WAIT DISCONNECT IID\n", 
+		    host->host_no);
+		hostdata->options |= OPTION_NO_PRINT_RACE;
+	    }
+	} else {
+	    printk(KERN_ALERT "scsi%d : invalid instruction\n", host->host_no);
+	    print_lots (host);
+	    printk(KERN_ALERT "         mail Richard@sleepie.demon.co.uk with ALL\n"
+		              "         boot messages and diagnostic output\n");
+    	    FATAL (host);
+	}
+    }
+
+    /* 
+     * DSTAT_BF are bus fault errors.  DSTAT_800_BF is valid for 710 also.
+     */
+    
+    if (dstat & DSTAT_800_BF) {
+	intr_bf (host, cmd);
+    }
+	
+
+    /* 
+     * DSTAT_SIR interrupts are generated by the execution of 
+     * the INT instruction.  Since the exact values available 
+     * are determined entirely by the SCSI script running, 
+     * and are local to a particular script, a unique handler
+     * is called for each script.
+     */
+
+    if (dstat & DSTAT_SIR) {
+	if (hostdata->options & OPTION_DEBUG_INTR)
+	    printk ("scsi%d : DSTAT_SIR\n", host->host_no);
+	switch ((tmp = hostdata->dstat_sir_intr (host, cmd))) {
+	case SPECIFIC_INT_NOTHING:
+	case SPECIFIC_INT_RESTART:
+	    break;
+	case SPECIFIC_INT_ABORT:
+	    abort_connected(host);
+	    break;
+	case SPECIFIC_INT_PANIC:
+	    printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT "          dstat_sir_intr() returned SPECIFIC_INT_PANIC\n");
+    	    FATAL (host);
+	    break;
+	case SPECIFIC_INT_BREAK:
+	    intr_break (host, cmd);
+	    break;
+	default:
+	    printk(KERN_ALERT "scsi%d : failure at ", host->host_no);
+	    print_insn (host, dsp, KERN_ALERT "", 1);
+	    printk(KERN_ALERT"          dstat_sir_intr() returned unknown value %d\n", 
+		tmp);
+    	    FATAL (host);
+	}
+    } 
+}
+
+/*
+ * Function : static int print_insn (struct Scsi_Host *host, 
+ * 	u32 *insn, int kernel)
+ *
+ * Purpose : print numeric representation of the instruction pointed
+ * 	to by insn to the debugging or kernel message buffer
+ *	as appropriate.  
+ *
+ * 	If desired, a user level program can interpret this 
+ * 	information.
+ *
+ * Inputs : host, insn - host, pointer to instruction, prefix - 
+ *	string to prepend, kernel - use printk instead of debugging buffer.
+ *
+ * Returns : size, in u32s, of instruction printed.
+ */
+
+/*
+ * FIXME: should change kernel parameter so that it takes an ENUM
+ * 	specifying severity - either KERN_ALERT or KERN_PANIC so
+ *	all panic messages are output with the same severity.
+ */
+
+static int 
+print_insn (struct Scsi_Host *host, const u32 *insn, 
+    const char *prefix, int kernel) {
+    char buf[160], 		/* Temporary buffer and pointer.  ICKY 
+				   arbitrary length.  */
+
+		
+	*tmp;			
+    unsigned char dcmd;		/* dcmd register for *insn */
+    int size;
+
+    /* 
+     * Check to see if the instruction pointer is not bogus before 
+     * indirecting through it; avoiding red-zone at start of 
+     * memory.
+     *
+     * FIXME: icky magic needs to happen here on non-intel boxes which
+     * don't have kernel memory mapped in like this.  Might be reasonable
+     * to use vverify()?
+     */
+
+    if (virt_to_phys((void *)insn) < PAGE_SIZE || 
+	virt_to_phys((void *)(insn + 8)) > virt_to_phys(high_memory) ||
+	((((dcmd = (insn[0] >> 24) & 0xff) & DCMD_TYPE_MMI) == DCMD_TYPE_MMI) &&
+	virt_to_phys((void *)(insn + 12)) > virt_to_phys(high_memory))) {
+	size = 0;
+	sprintf (buf, "%s%p: address out of range\n",
+	    prefix, insn);
+    } else {
+/* 
+ * FIXME : (void *) cast in virt_to_bus should be unnecessary, because
+ * 	it should take const void * as argument.
+ */
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
+	sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)", 
+	    (prefix ? prefix : ""), virt_to_bus((void *) insn), insn,  
+	    insn[0], insn[1], bus_to_virt (insn[1]));
+#else
+	/* Remove virtual addresses to reduce output, as they are the same */
+	sprintf(buf, "%s0x%x (+%x) : 0x%08x 0x%08x", 
+	    (prefix ? prefix : ""), (u32)insn, ((u32)insn -
+		(u32)&(((struct NCR53c7x0_hostdata *)host->hostdata[0])->script))/4, 
+	    insn[0], insn[1]);
+#endif
+	tmp = buf + strlen(buf);
+	if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI)  {
+#if !defined(CONFIG_MVME16x) && !defined(CONFIG_BVME6000)
+	    sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2], 
+		bus_to_virt(insn[2]));
+#else
+	    /* Remove virtual addr to reduce output, as it is the same */
+	    sprintf (tmp, " 0x%08x\n", insn[2]);
+#endif
+	    size = 3;
+	} else {
+	    sprintf (tmp, "\n");
+	    size = 2;
+	}
+    }
+
+    if (kernel) 
+	printk ("%s", buf);
+#ifdef NCR_DEBUG
+    else {
+	size_t len = strlen(buf);
+	debugger_kernel_write(host, buf, len);
+    }
+#endif
+    return size;
+}
+
+/*
+ * Function : int NCR53c7xx_abort (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : Abort an errant SCSI command, doing all necessary
+ *	cleanup of the issue_queue, running_list, shared Linux/NCR
+ *	dsa issue and reconnect queues.
+ *
+ * Inputs : cmd - command to abort, code - entire result field
+ *
+ * Returns : 0 on success, -1 on failure.
+ */
+
+int 
+NCR53c7xx_abort (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct Scsi_Host *host = cmd->device->host;
+    struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *) 
+	host->hostdata[0] : NULL;
+    unsigned long flags;
+    struct NCR53c7x0_cmd *curr, **prev;
+    Scsi_Cmnd *me, **last;
+#if 0
+    static long cache_pid = -1;
+#endif
+
+
+    if (!host) {
+	printk ("Bogus SCSI command pid %ld; no host structure\n",
+	    cmd->pid);
+	return SCSI_ABORT_ERROR;
+    } else if (!hostdata) {
+	printk ("Bogus SCSI host %d; no hostdata\n", host->host_no);
+	return SCSI_ABORT_ERROR;
+    }
+    NCR53c7x0_local_setup(host);
+
+/*
+ * CHECK : I don't think that reading ISTAT will unstack any interrupts,
+ *	since we need to write the INTF bit to clear it, and SCSI/DMA
+ * 	interrupts don't clear until we read SSTAT/SIST and DSTAT registers.
+ *	
+ *	See that this is the case.  Appears to be correct on the 710, at least.
+ *
+ * I suspect that several of our failures may be coming from a new fatal
+ * interrupt (possibly due to a phase mismatch) happening after we've left
+ * the interrupt handler, but before the PIC has had the interrupt condition
+ * cleared.
+ */
+
+    if (NCR53c7x0_read8(hostdata->istat) & (ISTAT_DIP|ISTAT_SIP)) {
+	printk ("scsi%d : dropped interrupt for command %ld\n", host->host_no,
+	    cmd->pid);
+	NCR53c7x0_intr (host->irq, NULL, NULL);
+	return SCSI_ABORT_BUSY;
+    }
+	
+    local_irq_save(flags);
+#if 0
+    if (cache_pid == cmd->pid) 
+	panic ("scsi%d : bloody fetus %d\n", host->host_no, cmd->pid);
+    else
+	cache_pid = cmd->pid;
+#endif
+	
+
+/*
+ * The command could be hiding in the issue_queue.  This would be very
+ * nice, as commands can't be moved from the high level driver's issue queue 
+ * into the shared queue until an interrupt routine is serviced, and this
+ * moving is atomic.  
+ *
+ * If this is the case, we don't have to worry about anything - we simply
+ * pull the command out of the old queue, and call it aborted.
+ */
+
+    for (me = (Scsi_Cmnd *) hostdata->issue_queue, 
+         last = (Scsi_Cmnd **) &(hostdata->issue_queue);
+	 me && me != cmd;  last = (Scsi_Cmnd **)&(me->SCp.ptr), 
+	 me = (Scsi_Cmnd *)me->SCp.ptr);
+
+    if (me) {
+	*last = (Scsi_Cmnd *) me->SCp.ptr;
+	if (me->host_scribble) {
+	    ((struct NCR53c7x0_cmd *)me->host_scribble)->next = hostdata->free;
+	    hostdata->free = (struct NCR53c7x0_cmd *) me->host_scribble;
+	    me->host_scribble = NULL;
+	}
+	cmd->result = DID_ABORT << 16;
+	cmd->scsi_done(cmd);
+	printk ("scsi%d : found command %ld in Linux issue queue\n", 
+	    host->host_no, me->pid);
+	local_irq_restore(flags);
+    	run_process_issue_queue();
+	return SCSI_ABORT_SUCCESS;
+    }
+
+/* 
+ * That failing, the command could be in our list of already executing 
+ * commands.  If this is the case, drastic measures are called for.  
+ */ 
+
+    for (curr = (struct NCR53c7x0_cmd *) hostdata->running_list, 
+    	 prev = (struct NCR53c7x0_cmd **) &(hostdata->running_list);
+	 curr && curr->cmd != cmd; prev = (struct NCR53c7x0_cmd **) 
+         &(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
+
+    if (curr) {
+	if ((curr->result & 0xff) != 0xff && (curr->result & 0xff00) != 0xff00) {
+            cmd->result = curr->result;
+	    if (prev)
+		*prev = (struct NCR53c7x0_cmd *) curr->next;
+	    curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
+	    cmd->host_scribble = NULL;
+	    hostdata->free = curr;
+	    cmd->scsi_done(cmd);
+	printk ("scsi%d : found finished command %ld in running list\n", 
+	    host->host_no, cmd->pid);
+	    local_irq_restore(flags);
+	    return SCSI_ABORT_NOT_RUNNING;
+	} else {
+	    printk ("scsi%d : DANGER : command running, can not abort.\n",
+		cmd->device->host->host_no);
+	    local_irq_restore(flags);
+	    return SCSI_ABORT_BUSY;
+	}
+    }
+
+/* 
+ * And if we couldn't find it in any of our queues, it must have been 
+ * a dropped interrupt.
+ */
+
+    curr = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+    if (curr) {
+	curr->next = hostdata->free;
+	hostdata->free = curr;
+	cmd->host_scribble = NULL;
+    }
+
+    if (curr == NULL || ((curr->result & 0xff00) == 0xff00) ||
+		((curr->result & 0xff) == 0xff)) {
+	printk ("scsi%d : did this command ever run?\n", host->host_no);
+	    cmd->result = DID_ABORT << 16;
+    } else {
+	printk ("scsi%d : probably lost INTFLY, normal completion\n", 
+	    host->host_no);
+        cmd->result = curr->result;
+/* 
+ * FIXME : We need to add an additional flag which indicates if a 
+ * command was ever counted as BUSY, so if we end up here we can
+ * decrement the busy count if and only if it is necessary.
+ */
+        --hostdata->busy[cmd->device->id][cmd->device->lun];
+    }
+    local_irq_restore(flags);
+    cmd->scsi_done(cmd);
+
+/* 
+ * We need to run process_issue_queue since termination of this command 
+ * may allow another queued command to execute first? 
+ */
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+/*
+ * Function : int NCR53c7xx_reset (Scsi_Cmnd *cmd) 
+ * 
+ * Purpose : perform a hard reset of the SCSI bus and NCR
+ * 	chip.
+ *
+ * Inputs : cmd - command which caused the SCSI RESET
+ *
+ * Returns : 0 on success.
+ */
+ 
+int 
+NCR53c7xx_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    int found = 0;
+    struct NCR53c7x0_cmd * c;
+    Scsi_Cmnd *tmp;
+    /*
+     * When we call scsi_done(), it's going to wake up anything sleeping on the
+     * resources which were in use by the aborted commands, and we'll start to 
+     * get new commands.
+     *
+     * We can't let this happen until after we've re-initialized the driver
+     * structures, and can't reinitialize those structures until after we've 
+     * dealt with their contents.
+     *
+     * So, we need to find all of the commands which were running, stick
+     * them on a linked list of completed commands (we'll use the host_scribble
+     * pointer), do our reinitialization, and then call the done function for
+     * each command.  
+     */
+    Scsi_Cmnd *nuke_list = NULL;
+    struct Scsi_Host *host = cmd->device->host;
+    struct NCR53c7x0_hostdata *hostdata = 
+    	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+
+    NCR53c7x0_local_setup(host);
+    local_irq_save(flags);
+    ncr_halt (host);
+    print_lots (host);
+    dump_events (host, 30);
+    ncr_scsi_reset (host);
+    for (tmp = nuke_list = return_outstanding_commands (host, 1 /* free */,
+	0 /* issue */ ); tmp; tmp = (Scsi_Cmnd *) tmp->SCp.buffer)
+	if (tmp == cmd) {
+	    found = 1;
+	    break;
+	}
+	    
+    /* 
+     * If we didn't find the command which caused this reset in our running
+     * list, then we've lost it.  See that it terminates normally anyway.
+     */
+    if (!found) {
+    	c = (struct NCR53c7x0_cmd *) cmd->host_scribble;
+    	if (c) {
+	    cmd->host_scribble = NULL;
+    	    c->next = hostdata->free;
+    	    hostdata->free = c;
+    	} else
+	    printk ("scsi%d: lost command %ld\n", host->host_no, cmd->pid);
+	cmd->SCp.buffer = (struct scatterlist *) nuke_list;
+	nuke_list = cmd;
+    }
+
+    NCR53c7x0_driver_init (host);
+    hostdata->soft_reset (host);
+    if (hostdata->resets == 0) 
+	disable(host);
+    else if (hostdata->resets != -1)
+	--hostdata->resets;
+    local_irq_restore(flags);
+    for (; nuke_list; nuke_list = tmp) {
+	tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+    	nuke_list->result = DID_RESET << 16;
+	nuke_list->scsi_done (nuke_list);
+    }
+    local_irq_restore(flags);
+    return SCSI_RESET_SUCCESS;
+}
+
+/*
+ * The NCR SDMS bios follows Annex A of the SCSI-CAM draft, and 
+ * therefore shares the scsicam_bios_param function.
+ */
+
+/*
+ * Function : int insn_to_offset (Scsi_Cmnd *cmd, u32 *insn)
+ *
+ * Purpose : convert instructions stored at NCR pointer into data 
+ *	pointer offset.
+ * 
+ * Inputs : cmd - SCSI command; insn - pointer to instruction.  Either current
+ *	DSP, or saved data pointer.
+ *
+ * Returns : offset on success, -1 on failure.
+ */
+
+
+static int 
+insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) cmd->device->host->hostdata[0];
+    struct NCR53c7x0_cmd *ncmd = 
+	(struct NCR53c7x0_cmd *) cmd->host_scribble;
+    int offset = 0, buffers;
+    struct scatterlist *segment;
+    char *ptr;
+    int found = 0;
+
+/*
+ * With the current code implementation, if the insn is inside dynamically 
+ * generated code, the data pointer will be the instruction preceding 
+ * the next transfer segment.
+ */
+
+    if (!check_address ((unsigned long) ncmd, sizeof (struct NCR53c7x0_cmd)) &&
+	((insn >= ncmd->data_transfer_start &&  
+    	    insn < ncmd->data_transfer_end) ||
+    	(insn >= ncmd->residual &&
+    	    insn < (ncmd->residual + 
+    	    	sizeof(ncmd->residual))))) {
+	    ptr = bus_to_virt(insn[3]);
+
+	    if ((buffers = cmd->use_sg)) {
+    	    	for (offset = 0, 
+		     	segment = (struct scatterlist *) cmd->buffer;
+    	    	     buffers && !((found = ((ptr >= (char *)page_address(segment->page)+segment->offset) && 
+    	    	    	    (ptr < ((char *)page_address(segment->page)+segment->offset+segment->length)))));
+    	    	     --buffers, offset += segment->length, ++segment)
+#if 0
+		    printk("scsi%d: comparing 0x%p to 0x%p\n", 
+			cmd->device->host->host_no, saved, page_address(segment->page+segment->offset);
+#else
+		    ;
+#endif
+    	    	    offset += ptr - ((char *)page_address(segment->page)+segment->offset);
+    	    } else {
+		found = 1;
+    	    	offset = ptr - (char *) (cmd->request_buffer);
+    	    }
+    } else if ((insn >= hostdata->script + 
+		hostdata->E_data_transfer / sizeof(u32)) &&
+	       (insn <= hostdata->script +
+		hostdata->E_end_data_transfer / sizeof(u32))) {
+    	found = 1;
+	offset = 0;
+    }
+    return found ? offset : -1;
+}
+
+
+
+/*
+ * Function : void print_progress (Scsi_Cmnd *cmd) 
+ * 
+ * Purpose : print the current location of the saved data pointer
+ *
+ * Inputs : cmd - command we are interested in
+ *
+ */
+
+static void 
+print_progress (Scsi_Cmnd *cmd) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_cmd *ncmd = 
+	(struct NCR53c7x0_cmd *) cmd->host_scribble;
+    int offset, i;
+    char *where;
+    u32 *ptr;
+    NCR53c7x0_local_setup (cmd->device->host);
+
+    if (check_address ((unsigned long) ncmd,sizeof (struct NCR53c7x0_cmd)) == 0)
+    {
+	printk("\nNCR53c7x0_cmd fields:\n");
+	printk("  bounce.len=0x%x, addr=0x%0x, buf[]=0x%02x %02x %02x %02x\n",
+	    ncmd->bounce.len, ncmd->bounce.addr, ncmd->bounce.buf[0],
+	    ncmd->bounce.buf[1], ncmd->bounce.buf[2], ncmd->bounce.buf[3]);
+	printk("  result=%04x, cdb[0]=0x%02x\n", ncmd->result, ncmd->cmnd[0]);
+    }
+
+    for (i = 0; i < 2; ++i) {
+	if (check_address ((unsigned long) ncmd, 
+	    sizeof (struct NCR53c7x0_cmd)) == -1) 
+	    continue;
+	if (!i) {
+	    where = "saved";
+	    ptr = bus_to_virt(ncmd->saved_data_pointer);
+	} else {
+	    where = "active";
+	    ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
+		NCR53c7x0_insn_size (NCR53c7x0_read8 (DCMD_REG)) *
+		sizeof(u32));
+	} 
+	offset = insn_to_offset (cmd, ptr);
+
+	if (offset != -1) 
+	    printk ("scsi%d : %s data pointer at offset %d\n",
+		cmd->device->host->host_no, where, offset);
+	else {
+	    int size;
+	    printk ("scsi%d : can't determine %s data pointer offset\n",
+		cmd->device->host->host_no, where);
+	    if (ncmd) {
+		size = print_insn (cmd->device->host,
+		    bus_to_virt(ncmd->saved_data_pointer), "", 1);
+		print_insn (cmd->device->host,
+		    bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+		    "", 1);
+	    }
+	}
+    }
+}
+
+
+static void 
+print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    int i, len;
+    char *ptr;
+    Scsi_Cmnd *cmd;
+
+    if (check_address ((unsigned long) dsa, hostdata->dsa_end - 
+	hostdata->dsa_start) == -1) {
+	printk("scsi%d : bad dsa virt 0x%p\n", host->host_no, dsa);
+	return;
+    }
+    printk("%sscsi%d : dsa at phys 0x%lx (virt 0x%p)\n"
+	    "        + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
+    	    prefix ? prefix : "",
+    	    host->host_no,  virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
+    	    dsa[hostdata->dsa_msgout / sizeof(u32)],
+	    dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
+	    bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+
+    /* 
+     * Only print messages if they're sane in length so we don't
+     * blow the kernel printk buffer on something which won't buy us
+     * anything.
+     */
+
+    if (dsa[hostdata->dsa_msgout / sizeof(u32)] < 
+	    sizeof (hostdata->free->select)) 
+	for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
+	    ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]); 
+	    i > 0 && !check_address ((unsigned long) ptr, 1);
+	    ptr += len, i -= len) {
+	    printk("               ");
+	    len = print_msg (ptr);
+	    printk("\n");
+	    if (!len)
+		break;
+	}
+
+    printk("        + %d : select_indirect = 0x%x\n",
+	hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
+    cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+    printk("        + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
+	   (u32) virt_to_bus(cmd));
+    /* XXX Maybe we should access cmd->host_scribble->result here. RGH */
+    if (cmd) {
+	printk("               result = 0x%x, target = %d, lun = %d, cmd = ",
+	    cmd->result, cmd->device->id, cmd->device->lun);
+	print_command(cmd->cmnd);
+    } else
+	printk("\n");
+    printk("        + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
+	dsa[hostdata->dsa_next / sizeof(u32)]);
+    if (cmd) { 
+	printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
+	       "                   script : ",
+	    host->host_no, cmd->device->id,
+	    hostdata->sync[cmd->device->id].sxfer_sanity,
+	    hostdata->sync[cmd->device->id].scntl3_sanity);
+	for (i = 0; i < (sizeof(hostdata->sync[cmd->device->id].script) / 4); ++i)
+	    printk ("0x%x ", hostdata->sync[cmd->device->id].script[i]);
+	printk ("\n");
+    	print_progress (cmd);
+    }
+}
+/*
+ * Function : void print_queues (Scsi_Host *host) 
+ * 
+ * Purpose : print the contents of the NCR issue and reconnect queues
+ *
+ * Inputs : host - SCSI host we are interested in
+ *
+ */
+
+static void 
+print_queues (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    u32 *dsa, *next_dsa;
+    volatile u32 *ncrcurrent;
+    int left;
+    Scsi_Cmnd *cmd, *next_cmd;
+    unsigned long flags;
+
+    printk ("scsi%d : issue queue\n", host->host_no);
+
+    for (left = host->can_queue, cmd = (Scsi_Cmnd *) hostdata->issue_queue; 
+	    left >= 0 && cmd; 
+	    cmd = next_cmd) {
+	next_cmd = (Scsi_Cmnd *) cmd->SCp.ptr;
+	local_irq_save(flags);
+	if (cmd->host_scribble) {
+	    if (check_address ((unsigned long) (cmd->host_scribble), 
+		sizeof (cmd->host_scribble)) == -1)
+		printk ("scsi%d: scsi pid %ld bad pointer to NCR53c7x0_cmd\n",
+		    host->host_no, cmd->pid);
+	    /* print_dsa does sanity check on address, no need to check */
+	    else
+	    	print_dsa (host, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
+		    -> dsa, "");
+	} else 
+	    printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
+		host->host_no, cmd->pid, cmd->device->id, cmd->device->lun);
+	local_irq_restore(flags);
+    }
+
+    if (left <= 0) {
+	printk ("scsi%d : loop detected in issue queue\n",
+	    host->host_no);
+    }
+
+    /*
+     * Traverse the NCR reconnect and start DSA structures, printing out 
+     * each element until we hit the end or detect a loop.  Currently,
+     * the reconnect structure is a linked list; and the start structure
+     * is an array.  Eventually, the reconnect structure will become a 
+     * list as well, since this simplifies the code.
+     */
+
+    printk ("scsi%d : schedule dsa array :\n", host->host_no);
+    for (left = host->can_queue, ncrcurrent = hostdata->schedule;
+	    left > 0; ncrcurrent += 2, --left)
+	if (ncrcurrent[0] != hostdata->NOP_insn) 
+/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
+	    print_dsa (host, bus_to_virt (ncrcurrent[1] - 
+		(hostdata->E_dsa_code_begin - 
+		hostdata->E_dsa_code_template)), "");
+    printk ("scsi%d : end schedule dsa array\n", host->host_no);
+    
+    printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
+	    
+    for (left = host->can_queue, 
+	dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+	left >= 0 && dsa; 
+	dsa = next_dsa) {
+	local_irq_save(flags);
+	if (check_address ((unsigned long) dsa, sizeof(dsa)) == -1) {
+	    printk ("scsi%d: bad DSA pointer 0x%p", host->host_no,
+		dsa);
+	    next_dsa = NULL;
+	}
+	else 
+	{
+	    next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+	    print_dsa (host, dsa, "");
+	}
+	local_irq_restore(flags);
+    }
+    printk ("scsi%d : end reconnect_dsa_head\n", host->host_no);
+    if (left < 0)
+	printk("scsi%d: possible loop in ncr reconnect list\n",
+	    host->host_no);
+}
+
+static void
+print_lots (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    u32 *dsp_next, *dsp, *dsa, dbc_dcmd;
+    unsigned char dcmd, sbcl;
+    int i, size;
+    NCR53c7x0_local_setup(host);
+
+    if ((dsp_next = bus_to_virt(NCR53c7x0_read32 (DSP_REG)))) {
+    	dbc_dcmd = NCR53c7x0_read32(DBC_REG);
+    	dcmd = (dbc_dcmd & 0xff000000) >> 24;
+    	dsp = dsp_next - NCR53c7x0_insn_size(dcmd);
+	dsa = bus_to_virt(NCR53c7x0_read32(DSA_REG));
+	sbcl = NCR53c7x0_read8 (SBCL_REG);
+	    
+	/*
+	 * For the 53c710, the following will report value 0 for SCNTL3
+	 * and STEST0 - we don't have these registers.
+	 */
+    	printk ("scsi%d : DCMD|DBC=0x%x, DNAD=0x%x (virt 0x%p)\n"
+		"         DSA=0x%lx (virt 0x%p)\n"
+	        "         DSPS=0x%x, TEMP=0x%x (virt 0x%p), DMODE=0x%x\n"
+		"         SXFER=0x%x, SCNTL3=0x%x\n"
+		"         %s%s%sphase=%s, %d bytes in SCSI FIFO\n"
+		"         SCRATCH=0x%x, saved2_dsa=0x%0lx\n",
+	    host->host_no, dbc_dcmd, NCR53c7x0_read32(DNAD_REG),
+		bus_to_virt(NCR53c7x0_read32(DNAD_REG)),
+	    virt_to_bus(dsa), dsa,
+	    NCR53c7x0_read32(DSPS_REG), NCR53c7x0_read32(TEMP_REG), 
+	    bus_to_virt (NCR53c7x0_read32(TEMP_REG)),
+	    (int) NCR53c7x0_read8(hostdata->dmode),
+	    (int) NCR53c7x0_read8(SXFER_REG), 
+	    ((hostdata->chip / 100) == 8) ?
+		(int) NCR53c7x0_read8(SCNTL3_REG_800) : 0,
+	    (sbcl & SBCL_BSY) ? "BSY " : "",
+	    (sbcl & SBCL_SEL) ? "SEL " : "",
+	    (sbcl & SBCL_REQ) ? "REQ " : "",
+	    sstat2_to_phase(NCR53c7x0_read8 (((hostdata->chip / 100) == 8) ?
+	    	SSTAT1_REG : SSTAT2_REG)),
+	    (NCR53c7x0_read8 ((hostdata->chip / 100) == 8 ? 
+		SSTAT1_REG : SSTAT2_REG) & SSTAT2_FF_MASK) >> SSTAT2_FF_SHIFT,
+	    ((hostdata->chip / 100) == 8) ? NCR53c7x0_read8 (STEST0_REG_800) :
+		NCR53c7x0_read32(SCRATCHA_REG_800),
+	    hostdata->saved2_dsa);
+	printk ("scsi%d : DSP 0x%lx (virt 0x%p) ->\n", host->host_no, 
+	    virt_to_bus(dsp), dsp);
+    	for (i = 6; i > 0; --i, dsp += size)
+	    size = print_insn (host, dsp, "", 1);
+	if (NCR53c7x0_read8 (SCNTL1_REG) & SCNTL1_CON)  {
+	    if ((hostdata->chip / 100) == 8)
+	        printk ("scsi%d : connected (SDID=0x%x, SSID=0x%x)\n",
+		    host->host_no, NCR53c7x0_read8 (SDID_REG_800),
+		    NCR53c7x0_read8 (SSID_REG_800));
+	    else
+		printk ("scsi%d : connected (SDID=0x%x)\n",
+		    host->host_no, NCR53c7x0_read8 (SDID_REG_700));
+	    print_dsa (host, dsa, "");
+	}
+
+#if 1
+	print_queues (host);
+#endif
+    }
+}
+
+/*
+ * Function : static int shutdown (struct Scsi_Host *host)
+ * 
+ * Purpose : does a clean (we hope) shutdown of the NCR SCSI 
+ *	chip.  Use prior to dumping core, unloading the NCR driver,
+ * 
+ * Returns : 0 on success
+ */
+static int 
+shutdown (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    NCR53c7x0_local_setup(host);
+    local_irq_save(flags);
+/* Get in a state where we can reset the SCSI bus */
+    ncr_halt (host);
+    ncr_scsi_reset (host);
+    hostdata->soft_reset(host);
+
+    disable (host);
+    local_irq_restore(flags);
+    return 0;
+}
+
+/*
+ * Function : void ncr_scsi_reset (struct Scsi_Host *host)
+ *
+ * Purpose : reset the SCSI bus.
+ */
+
+static void 
+ncr_scsi_reset (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    NCR53c7x0_local_setup(host);
+    local_irq_save(flags);
+    NCR53c7x0_write8(SCNTL1_REG, SCNTL1_RST);
+    udelay(25);	/* Minimum amount of time to assert RST */
+    NCR53c7x0_write8(SCNTL1_REG, 0);
+    local_irq_restore(flags);
+}
+
+/* 
+ * Function : void hard_reset (struct Scsi_Host *host)
+ *
+ */
+
+static void 
+hard_reset (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    unsigned long flags;
+    local_irq_save(flags);
+    ncr_scsi_reset(host);
+    NCR53c7x0_driver_init (host);
+    if (hostdata->soft_reset)
+	hostdata->soft_reset (host);
+    local_irq_restore(flags);
+}
+
+
+/*
+ * Function : Scsi_Cmnd *return_outstanding_commands (struct Scsi_Host *host,
+ *	int free, int issue)
+ *
+ * Purpose : return a linked list (using the SCp.buffer field as next,
+ *	so we don't perturb hostdata.  We don't use a field of the 
+ *	NCR53c7x0_cmd structure since we may not have allocated one 
+ *	for the command causing the reset.) of Scsi_Cmnd structures that 
+ *  	had propagated below the Linux issue queue level.  If free is set, 
+ *	free the NCR53c7x0_cmd structures which are associated with 
+ *	the Scsi_Cmnd structures, and clean up any internal 
+ *	NCR lists that the commands were on.  If issue is set,
+ *	also return commands in the issue queue.
+ *
+ * Returns : linked list of commands
+ *
+ * NOTE : the caller should insure that the NCR chip is halted
+ *	if the free flag is set. 
+ */
+
+static Scsi_Cmnd *
+return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    struct NCR53c7x0_cmd *c;
+    int i;
+    u32 *ncrcurrent;
+    Scsi_Cmnd *list = NULL, *tmp;
+    for (c = (struct NCR53c7x0_cmd *) hostdata->running_list; c; 
+    	c = (struct NCR53c7x0_cmd *) c->next)  {
+	if (c->cmd->SCp.buffer) {
+	    printk ("scsi%d : loop detected in running list!\n", host->host_no);
+	    break;
+	} else {
+	    printk ("Duh? Bad things happening in the NCR driver\n");
+	    break;
+	}
+
+	c->cmd->SCp.buffer = (struct scatterlist *) list;
+	list = c->cmd;
+	if (free) {
+    	    c->next = hostdata->free;
+    	    hostdata->free = c;
+	}
+    }
+
+    if (free) { 
+	for (i = 0, ncrcurrent = (u32 *) hostdata->schedule; 
+	    i < host->can_queue; ++i, ncrcurrent += 2) {
+	    ncrcurrent[0] = hostdata->NOP_insn;
+	    ncrcurrent[1] = 0xdeadbeef;
+	}
+	hostdata->ncrcurrent = NULL;
+    }
+
+    if (issue) {
+	for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; tmp = tmp->next) {
+	    if (tmp->SCp.buffer) {
+		printk ("scsi%d : loop detected in issue queue!\n", 
+			host->host_no);
+		break;
+	    }
+	    tmp->SCp.buffer = (struct scatterlist *) list;
+	    list = tmp;
+	}
+	if (free)
+	    hostdata->issue_queue = NULL;
+		
+    }
+    return list;
+}
+
+/* 
+ * Function : static int disable (struct Scsi_Host *host)
+ *
+ * Purpose : disables the given NCR host, causing all commands
+ * 	to return a driver error.  Call this so we can unload the
+ * 	module during development and try again.  Eventually, 
+ * 	we should be able to find clean workarounds for these
+ * 	problems.
+ *
+ * Inputs : host - hostadapter to twiddle
+ *
+ * Returns : 0 on success.
+ */
+
+static int 
+disable (struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    unsigned long flags;
+    Scsi_Cmnd *nuke_list, *tmp;
+    local_irq_save(flags);
+    if (hostdata->state != STATE_HALTED)
+	ncr_halt (host);
+    nuke_list = return_outstanding_commands (host, 1 /* free */, 1 /* issue */);
+    hard_reset (host);
+    hostdata->state = STATE_DISABLED;
+    local_irq_restore(flags);
+    printk ("scsi%d : nuking commands\n", host->host_no);
+    for (; nuke_list; nuke_list = tmp) {
+	    tmp = (Scsi_Cmnd *) nuke_list->SCp.buffer;
+	    nuke_list->result = DID_ERROR << 16;
+	    nuke_list->scsi_done(nuke_list);
+    }
+    printk ("scsi%d : done. \n", host->host_no);
+    printk (KERN_ALERT "scsi%d : disabled.  Unload and reload\n",
+    	host->host_no);
+    return 0;
+}
+
+/*
+ * Function : static int ncr_halt (struct Scsi_Host *host)
+ * 
+ * Purpose : halts the SCSI SCRIPTS(tm) processor on the NCR chip
+ *
+ * Inputs : host - SCSI chip to halt
+ *
+ * Returns : 0 on success
+ */
+
+static int 
+ncr_halt (struct Scsi_Host *host) {
+    NCR53c7x0_local_declare();
+    unsigned long flags;
+    unsigned char istat, tmp;
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    int stage;
+    NCR53c7x0_local_setup(host);
+
+    local_irq_save(flags);
+    /* Stage 0 : eat all interrupts
+       Stage 1 : set ABORT
+       Stage 2 : eat all but abort interrupts
+       Stage 3 : eat all interrupts
+     */
+    for (stage = 0;;) {
+	if (stage == 1) {
+	    NCR53c7x0_write8(hostdata->istat, ISTAT_ABRT);
+	    ++stage;
+	}
+	istat = NCR53c7x0_read8 (hostdata->istat);
+	if (istat & ISTAT_SIP) {
+	    tmp = NCR53c7x0_read8(SSTAT0_REG);
+	} else if (istat & ISTAT_DIP) {
+	    tmp = NCR53c7x0_read8(DSTAT_REG);
+	    if (stage == 2) {
+		if (tmp & DSTAT_ABRT) {
+		    NCR53c7x0_write8(hostdata->istat, 0);
+		    ++stage;
+		} else {
+		    printk(KERN_ALERT "scsi%d : could not halt NCR chip\n", 
+			host->host_no);
+		    disable (host);
+	    	}
+    	    }
+	}
+	if (!(istat & (ISTAT_SIP|ISTAT_DIP))) {
+	    if (stage == 0)
+	    	++stage;
+	    else if (stage == 3)
+		break;
+	}
+    }
+    hostdata->state = STATE_HALTED;
+    local_irq_restore(flags);
+#if 0
+    print_lots (host);
+#endif
+    return 0;
+}
+
+/* 
+ * Function: event_name (int event)
+ * 
+ * Purpose: map event enum into user-readable strings.
+ */
+
+static const char *
+event_name (int event) {
+    switch (event) {
+    case EVENT_NONE:		return "none";
+    case EVENT_ISSUE_QUEUE:	return "to issue queue";
+    case EVENT_START_QUEUE:	return "to start queue";
+    case EVENT_SELECT:		return "selected";
+    case EVENT_DISCONNECT:	return "disconnected";
+    case EVENT_RESELECT:	return "reselected";
+    case EVENT_COMPLETE:	return "completed";
+    case EVENT_IDLE:		return "idle";
+    case EVENT_SELECT_FAILED:	return "select failed";
+    case EVENT_BEFORE_SELECT:	return "before select";
+    case EVENT_RESELECT_FAILED:	return "reselect failed";
+    default:			return "unknown";
+    }
+}
+
+/*
+ * Function : void dump_events (struct Scsi_Host *host, count)
+ *
+ * Purpose : print last count events which have occurred.
+ */ 
+static void
+dump_events (struct Scsi_Host *host, int count) {
+    struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
+	host->hostdata[0];
+    struct NCR53c7x0_event event;
+    int i;
+    unsigned long flags;
+    if (hostdata->events) {
+	if (count > hostdata->event_size)
+	    count = hostdata->event_size;
+	for (i = hostdata->event_index; count > 0; 
+	    i = (i ? i - 1 : hostdata->event_size -1), --count) {
+/*
+ * By copying the event we're currently examining with interrupts
+ * disabled, we can do multiple printk(), etc. operations and 
+ * still be guaranteed that they're happening on the same 
+ * event structure.
+ */
+	    local_irq_save(flags);
+#if 0
+	    event = hostdata->events[i];
+#else
+	    memcpy ((void *) &event, (void *) &(hostdata->events[i]),
+		sizeof(event));
+#endif
+
+	    local_irq_restore(flags);
+	    printk ("scsi%d : %s event %d at %ld secs %ld usecs target %d lun %d\n",
+		host->host_no, event_name (event.event), count,
+		(long) event.time.tv_sec, (long) event.time.tv_usec,
+		event.target, event.lun);
+	    if (event.dsa) 
+		printk ("         event for dsa 0x%lx (virt 0x%p)\n", 
+		    virt_to_bus(event.dsa), event.dsa);
+	    if (event.pid != -1) {
+		printk ("         event for pid %ld ", event.pid);
+		print_command (event.cmnd);
+	    }
+	}
+    }
+}
+
+/*
+ * Function: check_address
+ *
+ * Purpose: Check to see if a possibly corrupt pointer will fault the 
+ *	kernel.
+ *
+ * Inputs: addr - address; size - size of area
+ *
+ * Returns: 0 if area is OK, -1 on error.
+ *
+ * NOTES: should be implemented in terms of vverify on kernels 
+ *	that have it.
+ */
+
+static int 
+check_address (unsigned long addr, int size) {
+    return (virt_to_phys((void *)addr) < PAGE_SIZE || virt_to_phys((void *)(addr + size)) > virt_to_phys(high_memory) ?  -1 : 0);
+}
+
+#ifdef MODULE
+int 
+NCR53c7x0_release(struct Scsi_Host *host) {
+    struct NCR53c7x0_hostdata *hostdata = 
+	(struct NCR53c7x0_hostdata *) host->hostdata[0];
+    struct NCR53c7x0_cmd *cmd, *tmp;
+    shutdown (host);
+    if (host->irq != SCSI_IRQ_NONE)
+	{
+	    int irq_count;
+	    struct Scsi_Host *tmp;
+	    for (irq_count = 0, tmp = first_host; tmp; tmp = tmp->next)
+		if (tmp->hostt == the_template && tmp->irq == host->irq)
+		    ++irq_count;
+	    if (irq_count == 1)
+		free_irq(host->irq, NULL);
+	}
+    if (host->dma_channel != DMA_NONE)
+	free_dma(host->dma_channel);
+    if (host->io_port)
+	release_region(host->io_port, host->n_io_port);
+    
+    for (cmd = (struct NCR53c7x0_cmd *) hostdata->free; cmd; cmd = tmp, 
+	--hostdata->num_cmds) {
+	tmp = (struct NCR53c7x0_cmd *) cmd->next;
+    /* 
+     * If we're going to loop, try to stop it to get a more accurate
+     * count of the leaked commands.
+     */
+	cmd->next = NULL;
+	if (cmd->free)
+	    cmd->free ((void *) cmd->real, cmd->size);
+    }
+    if (hostdata->num_cmds)
+	printk ("scsi%d : leaked %d NCR53c7x0_cmd structures\n",
+	    host->host_no, hostdata->num_cmds);
+    if (hostdata->events) 
+	vfree ((void *)hostdata->events);
+
+    /* XXX This assumes default cache mode to be IOMAP_FULL_CACHING, which
+     * XXX may be invalid (CONFIG_060_WRITETHROUGH)
+     */
+    kernel_set_cachemode((void *)hostdata, 8192, IOMAP_FULL_CACHING);
+    free_pages ((u32)hostdata, 1);
+    return 1;
+}
+#endif /* def MODULE */
diff --git a/drivers/scsi/53c7xx.h b/drivers/scsi/53c7xx.h
new file mode 100644
index 0000000..d9098bd
--- /dev/null
+++ b/drivers/scsi/53c7xx.h
@@ -0,0 +1,1608 @@
+/*
+ * 53c710 driver.  Modified from Drew Eckhardts driver
+ * for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+ *
+ * I have left the code for the 53c8xx family in here, because it didn't
+ * seem worth removing it.  The possibility of IO_MAPPED chips rather
+ * than MEMORY_MAPPED remains, in case someone wants to add support for
+ * 53c710 chips on Intel PCs (some older machines have them on the
+ * motherboard).
+ *
+ * NOTE THERE MAY BE PROBLEMS WITH CASTS IN read8 AND Co.
+ */
+
+/*
+ * NCR 53c{7,8}0x0 driver, header file
+ *
+ * Sponsored by
+ *      iX Multiuser Multitasking Magazine
+ *	Hannover, Germany
+ *	hm@ix.de	
+ *
+ * Copyright 1993, 1994, 1995 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@PoohSticks.ORG
+ *	+1 (303) 786-7975
+ *
+ * TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+ * 
+ * PRE-ALPHA
+ *
+ * For more information, please consult 
+ *
+ * NCR 53C700/53C700-66
+ * SCSI I/O Processor
+ * Data Manual
+ *
+ * NCR 53C810
+ * PCI-SCSI I/O Processor 
+ * Data Manual
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * +1 (719) 578-3400
+ *
+ * Toll free literature number
+ * +1 (800) 334-5454
+ *
+ */
+
+#ifndef NCR53c710_H
+#define NCR53c710_H
+
+#ifndef HOSTS_C
+
+/* SCSI control 0 rw, default = 0xc0 */ 
+#define SCNTL0_REG 		0x00	
+#define SCNTL0_ARB1		0x80	/* 0 0 = simple arbitration */
+#define SCNTL0_ARB2		0x40	/* 1 1 = full arbitration */
+#define SCNTL0_STRT		0x20	/* Start Sequence */
+#define SCNTL0_WATN		0x10	/* Select with ATN */
+#define SCNTL0_EPC		0x08	/* Enable parity checking */
+/* Bit 2 is reserved on 800 series chips */
+#define SCNTL0_EPG_700		0x04	/* Enable parity generation */
+#define SCNTL0_AAP		0x02	/*  ATN/ on parity error */
+#define SCNTL0_TRG		0x01	/* Target mode */
+
+/* SCSI control 1 rw, default = 0x00 */
+
+#define SCNTL1_REG 		0x01	
+#define SCNTL1_EXC		0x80	/* Extra Clock Cycle of Data setup */
+#define SCNTL1_ADB		0x40	/*  contents of SODL on bus */
+#define SCNTL1_ESR_700		0x20	/* Enable SIOP response to selection 
+					   and reselection */
+#define SCNTL1_DHP_800		0x20	/* Disable halt on parity error or ATN
+					   target mode only */
+#define SCNTL1_CON		0x10	/* Connected */
+#define SCNTL1_RST		0x08	/* SCSI RST/ */
+#define SCNTL1_AESP		0x04	/* Force bad parity */
+#define SCNTL1_SND_700		0x02	/* Start SCSI send */
+#define SCNTL1_IARB_800		0x02	/* Immediate Arbitration, start
+					   arbitration immediately after
+					   busfree is detected */
+#define SCNTL1_RCV_700		0x01	/* Start SCSI receive */
+#define SCNTL1_SST_800		0x01	/* Start SCSI transfer */
+
+/* SCSI control 2 rw, */
+
+#define SCNTL2_REG_800		0x02	
+#define SCNTL2_800_SDU		0x80	/* SCSI disconnect unexpected */
+
+/* SCSI control 3 rw */
+
+#define SCNTL3_REG_800 		0x03	
+#define SCNTL3_800_SCF_SHIFT	4
+#define SCNTL3_800_SCF_MASK	0x70
+#define SCNTL3_800_SCF2		0x40	/* Synchronous divisor */
+#define SCNTL3_800_SCF1		0x20	/* 0x00 = SCLK/3 */
+#define SCNTL3_800_SCF0		0x10	/* 0x10 = SCLK/1 */
+					/* 0x20 = SCLK/1.5 
+					   0x30 = SCLK/2 
+					   0x40 = SCLK/3 */
+	    
+#define SCNTL3_800_CCF_SHIFT	0
+#define SCNTL3_800_CCF_MASK	0x07
+#define SCNTL3_800_CCF2		0x04	/* 0x00 50.01 to 66 */
+#define SCNTL3_800_CCF1		0x02	/* 0x01 16.67 to 25 */
+#define SCNTL3_800_CCF0		0x01	/* 0x02	25.01 - 37.5 
+					   0x03	37.51 - 50 
+					   0x04 50.01 - 66 */
+
+/*  
+ * SCSI destination ID rw - the appropriate bit is set for the selected
+ * target ID.  This is written by the SCSI SCRIPTS processor.
+ * default = 0x00
+ */
+#define SDID_REG_700  		0x02	
+#define SDID_REG_800		0x06
+
+#define GP_REG_800		0x07	/* General purpose IO */
+#define GP_800_IO1		0x02
+#define GP_800_IO2		0x01
+
+/* SCSI interrupt enable rw, default = 0x00 */
+#define SIEN_REG_700		0x03	
+#define SIEN0_REG_800		0x40
+#define SIEN_MA			0x80	/* Phase mismatch (ini) or ATN (tgt) */
+#define SIEN_FC			0x40	/* Function complete */
+#define SIEN_700_STO		0x20	/* Selection or reselection timeout */
+#define SIEN_800_SEL		0x20	/* Selected */
+#define SIEN_700_SEL		0x10	/* Selected or reselected */
+#define SIEN_800_RESEL		0x10	/* Reselected */
+#define SIEN_SGE		0x08	/* SCSI gross error */
+#define SIEN_UDC		0x04	/* Unexpected disconnect */
+#define SIEN_RST		0x02	/* SCSI RST/ received */
+#define SIEN_PAR		0x01	/* Parity error */
+
+/* 
+ * SCSI chip ID rw
+ * NCR53c700 : 
+ * 	When arbitrating, the highest bit is used, when reselection or selection
+ * 	occurs, the chip responds to all IDs for which a bit is set.
+ * 	default = 0x00 
+ * NCR53c810 : 
+ *	Uses bit mapping
+ */
+#define SCID_REG		0x04	
+/* Bit 7 is reserved on 800 series chips */
+#define SCID_800_RRE		0x40	/* Enable response to reselection */
+#define SCID_800_SRE		0x20	/* Enable response to selection */
+/* Bits four and three are reserved on 800 series chips */
+#define SCID_800_ENC_MASK	0x07	/* Encoded SCSI ID */
+
+/* SCSI transfer rw, default = 0x00 */
+#define SXFER_REG		0x05
+#define SXFER_DHP		0x80	/* Disable halt on parity */
+
+#define SXFER_TP2		0x40	/* Transfer period msb */
+#define SXFER_TP1		0x20
+#define SXFER_TP0		0x10	/* lsb */
+#define SXFER_TP_MASK		0x70
+/* FIXME : SXFER_TP_SHIFT == 5 is right for '8xx chips */
+#define SXFER_TP_SHIFT		5
+#define SXFER_TP_4		0x00	/* Divisors */
+#define SXFER_TP_5		0x10<<1
+#define SXFER_TP_6		0x20<<1
+#define SXFER_TP_7		0x30<<1
+#define SXFER_TP_8		0x40<<1
+#define SXFER_TP_9		0x50<<1
+#define SXFER_TP_10		0x60<<1
+#define SXFER_TP_11		0x70<<1
+
+#define SXFER_MO3		0x08	/* Max offset msb */
+#define SXFER_MO2		0x04
+#define SXFER_MO1		0x02
+#define SXFER_MO0		0x01	/* lsb */
+#define SXFER_MO_MASK		0x0f
+#define SXFER_MO_SHIFT		0
+
+/* 
+ * SCSI output data latch rw
+ * The contents of this register are driven onto the SCSI bus when 
+ * the Assert Data Bus bit of the SCNTL1 register is set and 
+ * the CD, IO, and MSG bits of the SOCL register match the SCSI phase
+ */
+#define SODL_REG_700		0x06	
+#define SODL_REG_800		0x54
+
+
+/* 
+ * SCSI output control latch rw, default = 0 
+ * Note that when the chip is being manually programmed as an initiator,
+ * the MSG, CD, and IO bits must be set correctly for the phase the target
+ * is driving the bus in.  Otherwise no data transfer will occur due to 
+ * phase mismatch.
+ */
+
+#define SOCL_REG		0x07
+#define SOCL_REQ		0x80	/*  REQ */
+#define SOCL_ACK		0x40	/*  ACK */
+#define SOCL_BSY		0x20	/*  BSY */
+#define SOCL_SEL		0x10	/*  SEL */
+#define SOCL_ATN		0x08	/*  ATN */
+#define SOCL_MSG		0x04	/*  MSG */
+#define SOCL_CD			0x02	/*  C/D */
+#define SOCL_IO			0x01	/*  I/O */
+
+/* 
+ * SCSI first byte received latch ro 
+ * This register contains the first byte received during a block MOVE 
+ * SCSI SCRIPTS instruction, including
+ * 
+ * Initiator mode	Target mode
+ * Message in		Command
+ * Status		Message out
+ * Data in		Data out
+ *
+ * It also contains the selecting or reselecting device's ID and our 
+ * ID.
+ *
+ * Note that this is the register the various IF conditionals can 
+ * operate on.
+ */
+#define SFBR_REG		0x08	
+
+/* 
+ * SCSI input data latch ro
+ * In initiator mode, data is latched into this register on the rising
+ * edge of REQ/. In target mode, data is latched on the rising edge of 
+ * ACK/
+ */
+#define SIDL_REG_700		0x09
+#define SIDL_REG_800		0x50
+
+/* 
+ * SCSI bus data lines ro 
+ * This register reflects the instantaneous status of the SCSI data 
+ * lines.  Note that SCNTL0 must be set to disable parity checking, 
+ * otherwise reading this register will latch new parity.
+ */
+#define SBDL_REG_700		0x0a
+#define SBDL_REG_800		0x58
+
+#define SSID_REG_800		0x0a
+#define SSID_800_VAL		0x80	/* Exactly two bits asserted at sel */
+#define SSID_800_ENCID_MASK	0x07	/* Device which performed operation */
+
+
+/* 
+ * SCSI bus control lines rw, 
+ * instantaneous readout of control lines 
+ */
+#define SBCL_REG		0x0b 	
+#define SBCL_REQ		0x80	/*  REQ ro */
+#define SBCL_ACK		0x40	/*  ACK ro */
+#define SBCL_BSY		0x20	/*  BSY ro */
+#define SBCL_SEL		0x10	/*  SEL ro */
+#define SBCL_ATN		0x08	/*  ATN ro */
+#define SBCL_MSG		0x04	/*  MSG ro */
+#define SBCL_CD			0x02	/*  C/D ro */
+#define SBCL_IO			0x01	/*  I/O ro */
+#define SBCL_PHASE_CMDOUT	SBCL_CD
+#define SBCL_PHASE_DATAIN	SBCL_IO
+#define SBCL_PHASE_DATAOUT	0
+#define SBCL_PHASE_MSGIN	(SBCL_CD|SBCL_IO|SBCL_MSG)
+#define SBCL_PHASE_MSGOUT	(SBCL_CD|SBCL_MSG)
+#define SBCL_PHASE_STATIN	(SBCL_CD|SBCL_IO)
+#define SBCL_PHASE_MASK		(SBCL_CD|SBCL_IO|SBCL_MSG)
+/* 
+ * Synchronous SCSI Clock Control bits 
+ * 0 - set by DCNTL 
+ * 1 - SCLK / 1.0
+ * 2 - SCLK / 1.5
+ * 3 - SCLK / 2.0 
+ */
+#define SBCL_SSCF1		0x02	/* wo, -66 only */
+#define SBCL_SSCF0		0x01	/* wo, -66 only */
+#define SBCL_SSCF_MASK		0x03
+
+/* 
+ * XXX note : when reading the DSTAT and STAT registers to clear interrupts,
+ * insure that 10 clocks elapse between the two  
+ */
+/* DMA status ro */
+#define DSTAT_REG		0x0c	
+#define DSTAT_DFE		0x80	/* DMA FIFO empty */
+#define DSTAT_800_MDPE		0x40	/* Master Data Parity Error */
+#define DSTAT_800_BF		0x20	/* Bus Fault */
+#define DSTAT_ABRT		0x10	/* Aborted - set on error */
+#define DSTAT_SSI		0x08	/* SCRIPTS single step interrupt */
+#define DSTAT_SIR		0x04	/* SCRIPTS interrupt received - 
+					   set when INT instruction is 
+					   executed */
+#define DSTAT_WTD		0x02	/* Watchdog timeout detected */
+#define DSTAT_OPC		0x01	/* Illegal instruction */
+#define DSTAT_800_IID		0x01	/* Same thing, different name */
+
+
+/* NCR53c800 moves this stuff into SIST0 */
+#define SSTAT0_REG		0x0d	/* SCSI status 0 ro */
+#define SIST0_REG_800		0x42	
+#define SSTAT0_MA		0x80	/* ini : phase mismatch,
+					 * tgt : ATN/ asserted 
+					 */
+#define SSTAT0_CMP		0x40	/* function complete */
+#define SSTAT0_700_STO		0x20	/* Selection or reselection timeout */
+#define SIST0_800_SEL		0x20	/* Selected */
+#define SSTAT0_700_SEL		0x10	/* Selected or reselected */
+#define SIST0_800_RSL		0x10	/* Reselected */
+#define SSTAT0_SGE		0x08	/* SCSI gross error */
+#define SSTAT0_UDC		0x04	/* Unexpected disconnect */
+#define SSTAT0_RST		0x02	/* SCSI RST/ received */
+#define SSTAT0_PAR		0x01	/* Parity error */
+
+/* And uses SSTAT0 for what was SSTAT1 */
+
+#define SSTAT1_REG		0x0e	/* SCSI status 1 ro */
+#define SSTAT1_ILF		0x80	/* SIDL full */
+#define SSTAT1_ORF		0x40	/* SODR full */
+#define SSTAT1_OLF		0x20	/* SODL full */
+#define SSTAT1_AIP		0x10	/* Arbitration in progress */
+#define SSTAT1_LOA		0x08	/* Lost arbitration */
+#define SSTAT1_WOA		0x04	/* Won arbitration */
+#define SSTAT1_RST		0x02	/* Instant readout of RST/ */
+#define SSTAT1_SDP		0x01	/* Instant readout of SDP/ */
+
+#define SSTAT2_REG		0x0f	/* SCSI status 2 ro */
+#define SSTAT2_FF3		0x80 	/* number of bytes in synchronous */
+#define SSTAT2_FF2		0x40	/* data FIFO */
+#define SSTAT2_FF1		0x20	
+#define SSTAT2_FF0		0x10
+#define SSTAT2_FF_MASK		0xf0
+#define SSTAT2_FF_SHIFT		4
+
+/* 
+ * Latched signals, latched on the leading edge of REQ/ for initiators,
+ * ACK/ for targets.
+ */
+#define SSTAT2_SDP		0x08	/* SDP */
+#define SSTAT2_MSG		0x04	/* MSG */
+#define SSTAT2_CD		0x02	/* C/D */
+#define SSTAT2_IO		0x01	/* I/O */
+#define SSTAT2_PHASE_CMDOUT	SSTAT2_CD
+#define SSTAT2_PHASE_DATAIN	SSTAT2_IO
+#define SSTAT2_PHASE_DATAOUT	0
+#define SSTAT2_PHASE_MSGIN	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+#define SSTAT2_PHASE_MSGOUT	(SSTAT2_CD|SSTAT2_MSG)
+#define SSTAT2_PHASE_STATIN	(SSTAT2_CD|SSTAT2_IO)
+#define SSTAT2_PHASE_MASK	(SSTAT2_CD|SSTAT2_IO|SSTAT2_MSG)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHA_REG_00		0x10    /* through  0x13 Scratch A rw */
+/* NCR53c710 and higher */
+#define DSA_REG			0x10	/* DATA structure address */
+
+#define CTEST0_REG_700		0x14	/* Chip test 0 ro */
+#define CTEST0_REG_800		0x18	/* Chip test 0 rw, general purpose */
+/* 0x80 - 0x04 are reserved */
+#define CTEST0_700_RTRG		0x02	/* Real target mode */
+#define CTEST0_700_DDIR		0x01	/* Data direction, 1 = 
+					 * SCSI bus to host, 0  =
+					 * host to SCSI.
+					 */
+
+#define CTEST1_REG_700		0x15	/* Chip test 1 ro */
+#define CTEST1_REG_800		0x19	/* Chip test 1 ro */
+#define CTEST1_FMT3		0x80	/* Identify which byte lanes are empty */
+#define CTEST1_FMT2		0x40 	/* in the DMA FIFO */
+#define CTEST1_FMT1		0x20
+#define CTEST1_FMT0		0x10
+
+#define CTEST1_FFL3		0x08	/* Identify which bytes lanes are full */
+#define CTEST1_FFL2		0x04	/* in the DMA FIFO */
+#define CTEST1_FFL1		0x02
+#define CTEST1_FFL0		0x01
+
+#define CTEST2_REG_700		0x16	/* Chip test 2 ro */
+#define CTEST2_REG_800		0x1a	/* Chip test 2 ro */
+
+#define CTEST2_800_DDIR		0x80	/* 1 = SCSI->host */
+#define CTEST2_800_SIGP		0x40	/* A copy of SIGP in ISTAT.
+					   Reading this register clears */
+#define CTEST2_800_CIO		0x20	/* Configured as IO */.
+#define CTEST2_800_CM		0x10	/* Configured as memory */
+
+/* 0x80 - 0x40 are reserved on 700 series chips */
+#define CTEST2_700_SOFF		0x20	/* SCSI Offset Compare,
+					 * As an initiator, this bit is 
+					 * one when the synchronous offset
+					 * is zero, as a target this bit 
+					 * is one when the synchronous 
+					 * offset is at the maximum
+					 * defined in SXFER
+					 */
+#define CTEST2_700_SFP		0x10	/* SCSI FIFO parity bit,
+					 * reading CTEST3 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_700_DFP		0x08	/* DMA FIFO parity bit,
+					 * reading CTEST6 unloads a byte
+					 * from the FIFO and sets this
+					 */
+#define CTEST2_TEOP		0x04	/* SCSI true end of process,
+					 * indicates a totally finished
+					 * transfer
+					 */
+#define CTEST2_DREQ		0x02	/* Data request signal */
+/* 0x01 is reserved on 700 series chips */
+#define CTEST2_800_DACK		0x01	
+
+/* 
+ * Chip test 3 ro 
+ * Unloads the bottom byte of the eight deep SCSI synchronous FIFO,
+ * check SSTAT2 FIFO full bits to determine size.  Note that a GROSS
+ * error results if a read is attempted on this register.  Also note 
+ * that 16 and 32 bit reads of this register will cause corruption.
+ */
+#define CTEST3_REG_700		0x17	
+/*  Chip test 3 rw */
+#define CTEST3_REG_800		0x1b
+#define CTEST3_800_V3		0x80	/* Chip revision */
+#define CTEST3_800_V2		0x40
+#define CTEST3_800_V1		0x20
+#define CTEST3_800_V0		0x10
+#define CTEST3_800_FLF		0x08	/* Flush DMA FIFO */
+#define CTEST3_800_CLF		0x04	/* Clear DMA FIFO */
+#define CTEST3_800_FM		0x02	/* Fetch mode pin */
+/* bit 0 is reserved on 800 series chips */
+
+#define CTEST4_REG_700		0x18	/* Chip test 4 rw */
+#define CTEST4_REG_800		0x21	/* Chip test 4 rw */
+/* 0x80 is reserved on 700 series chips */
+#define CTEST4_800_BDIS		0x80	/* Burst mode disable */
+#define CTEST4_ZMOD		0x40	/* High impedance mode */
+#define CTEST4_SZM		0x20	/* SCSI bus high impedance */
+#define CTEST4_700_SLBE		0x10	/* SCSI loopback enabled */
+#define CTEST4_800_SRTM		0x10	/* Shadow Register Test Mode */
+#define CTEST4_700_SFWR		0x08	/* SCSI FIFO write enable, 
+					 * redirects writes from SODL
+					 * to the SCSI FIFO.
+					 */
+#define CTEST4_800_MPEE		0x08	/* Enable parity checking
+					   during master cycles on PCI
+					   bus */
+
+/* 
+ * These bits send the contents of the CTEST6 register to the appropriate
+ * byte lane of the 32 bit DMA FIFO.  Normal operation is zero, otherwise 
+ * the high bit means the low two bits select the byte lane.
+ */
+#define CTEST4_FBL2		0x04	
+#define CTEST4_FBL1		0x02
+#define CTEST4_FBL0		0x01	
+#define CTEST4_FBL_MASK		0x07
+#define CTEST4_FBL_0		0x04	/* Select DMA FIFO byte lane 0 */
+#define CTEST4_FBL_1		0x05	/* Select DMA FIFO byte lane 1 */
+#define CTEST4_FBL_2		0x06	/* Select DMA FIFO byte lane 2 */
+#define CTEST4_FBL_3		0x07	/* Select DMA FIFO byte lane 3 */
+#define CTEST4_800_SAVE		(CTEST4_800_BDIS)
+
+
+#define CTEST5_REG_700		0x19	/* Chip test 5 rw */
+#define CTEST5_REG_800		0x22	/* Chip test 5 rw */
+/* 
+ * Clock Address Incrementor.  When set, it increments the 
+ * DNAD register to the next bus size boundary.  It automatically 
+ * resets itself when the operation is complete.
+ */
+#define CTEST5_ADCK		0x80
+/*
+ * Clock Byte Counter.  When set, it decrements the DBC register to
+ * the next bus size boundary.
+ */
+#define CTEST5_BBCK		0x40
+/*
+ * Reset SCSI Offset.  Setting this bit to 1 clears the current offset
+ * pointer in the SCSI synchronous offset counter (SSTAT).  This bit
+ * is set to 1 if a SCSI Gross Error Condition occurs.  The offset should
+ * be cleared when a synchronous transfer fails.  When written, it is 
+ * automatically cleared after the SCSI synchronous offset counter is 
+ * reset.
+ */
+/* Bit 5 is reserved on 800 series chips */
+#define CTEST5_700_ROFF		0x20
+/* 
+ * Master Control for Set or Reset pulses. When 1, causes the low 
+ * four bits of register to set when set, 0 causes the low bits to
+ * clear when set.
+ */
+#define CTEST5_MASR 		0x10	
+#define CTEST5_DDIR		0x08	/* DMA direction */
+/*
+ * Bits 2-0 are reserved on 800 series chips
+ */
+#define CTEST5_700_EOP		0x04	/* End of process */
+#define CTEST5_700_DREQ		0x02	/* Data request */
+#define CTEST5_700_DACK		0x01	/* Data acknowledge */
+
+/* 
+ * Chip test 6 rw - writing to this register writes to the byte 
+ * lane in the DMA FIFO as determined by the FBL bits in the CTEST4
+ * register.
+ */
+#define CTEST6_REG_700		0x1a
+#define CTEST6_REG_800		0x23
+
+#define CTEST7_REG		0x1b	/* Chip test 7 rw */
+/* 0x80 - 0x40 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define CTEST7_10_CDIS		0x80	/* Cache burst disable */
+#define CTEST7_10_SC1		0x40	/* Snoop control bits */
+#define CTEST7_10_SC0		0x20	
+#define CTEST7_10_SC_MASK	0x60
+/* 0x20 is reserved on the NCR53c700 */
+#define CTEST7_0060_FM		0x20	/* Fetch mode */
+#define CTEST7_STD		0x10	/* Selection timeout disable */
+#define CTEST7_DFP		0x08	/* DMA FIFO parity bit for CTEST6 */
+#define CTEST7_EVP		0x04	/* 1 = host bus even parity, 0 = odd */
+#define CTEST7_10_TT1		0x02	/* Transfer type */
+#define CTEST7_00_DC		0x02	/* Set to drive DC low during instruction 
+					   fetch */
+#define CTEST7_DIFF		0x01	/* Differential mode */
+
+#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
+
+
+#define TEMP_REG		0x1c	/* through 0x1f Temporary stack rw */
+
+#define DFIFO_REG		0x20	/* DMA FIFO rw */
+/* 
+ * 0x80 is reserved on the NCR53c710, the CLF and FLF bits have been
+ * moved into the CTEST8 register.
+ */
+#define DFIFO_00_FLF		0x80	/* Flush DMA FIFO to memory */
+#define DFIFO_00_CLF		0x40	/* Clear DMA and SCSI FIFOs */
+#define DFIFO_BO6		0x40
+#define DFIFO_BO5		0x20
+#define DFIFO_BO4		0x10
+#define DFIFO_BO3		0x08
+#define DFIFO_BO2		0x04 
+#define DFIFO_BO1		0x02
+#define DFIFO_BO0		0x01
+#define DFIFO_10_BO_MASK	0x7f	/* 7 bit counter */
+#define DFIFO_00_BO_MASK	0x3f	/* 6 bit counter */
+
+/* 
+ * Interrupt status rw 
+ * Note that this is the only register which can be read while SCSI
+ * SCRIPTS are being executed.
+ */
+#define ISTAT_REG_700		0x21
+#define ISTAT_REG_800		0x14
+#define ISTAT_ABRT		0x80	/* Software abort, write 
+					 *1 to abort, wait for interrupt. */
+/* 0x40 and 0x20 are reserved on NCR53c700 and NCR53c700-66 chips */
+#define ISTAT_10_SRST		0x40	/* software reset */
+#define ISTAT_10_SIGP		0x20	/* signal script */
+/* 0x10 is reserved on NCR53c700 series chips */
+#define ISTAT_800_SEM		0x10	/* semaphore */
+#define ISTAT_CON		0x08	/* 1 when connected */
+#define ISTAT_800_INTF		0x04	/* Interrupt on the fly */
+#define ISTAT_700_PRE		0x04	/* Pointer register empty.
+					 * Set to 1 when DSPS and DSP
+					 * registers are empty in pipeline
+					 * mode, always set otherwise.
+					 */
+#define ISTAT_SIP		0x02	/* SCSI interrupt pending from
+					 * SCSI portion of SIOP see
+					 * SSTAT0
+					 */
+#define ISTAT_DIP		0x01	/* DMA interrupt pending 
+					 * see DSTAT
+					 */
+
+/* NCR53c700-66 and NCR53c710 only */
+#define CTEST8_REG		0x22	/* Chip test 8 rw */
+#define CTEST8_0066_EAS		0x80	/* Enable alternate SCSI clock,
+					 * ie read from SCLK/ rather than CLK/
+					 */
+#define CTEST8_0066_EFM		0x40	/* Enable fetch and master outputs */
+#define CTEST8_0066_GRP		0x20	/* Generate Receive Parity for 
+					 * pass through.  This insures that 
+					 * bad parity won't reach the host 
+					 * bus.
+					 */
+#define CTEST8_0066_TE		0x10	/* TolerANT enable.  Enable 
+					 * active negation, should only
+					 * be used for slow SCSI 
+					 * non-differential.
+					 */
+#define CTEST8_0066_HSC		0x08	/* Halt SCSI clock */
+#define CTEST8_0066_SRA		0x04	/* Shorten REQ/ACK filtering,
+					 * must be set for fast SCSI-II
+					 * speeds.
+					 */
+#define CTEST8_0066_DAS		0x02	/* Disable automatic target/initiator
+					 * switching.
+					 */
+#define CTEST8_0066_LDE		0x01	/* Last disconnect enable.
+					 * The status of pending 
+					 * disconnect is maintained by
+					 * the core, eliminating
+					 * the possibility of missing a 
+					 * selection or reselection
+					 * while waiting to fetch a 
+					 * WAIT DISCONNECT opcode.
+					 */
+
+#define CTEST8_10_V3		0x80	/* Chip revision */
+#define CTEST8_10_V2		0x40
+#define CTEST8_10_V1		0x20	
+#define CTEST8_10_V0		0x10
+#define CTEST8_10_V_MASK	0xf0	
+#define CTEST8_10_FLF		0x08	/* Flush FIFOs */
+#define CTEST8_10_CLF		0x04	/* Clear FIFOs */
+#define CTEST8_10_FM		0x02	/* Fetch pin mode */
+#define CTEST8_10_SM		0x01	/* Snoop pin mode */
+
+
+/* 
+ * The CTEST9 register may be used to differentiate between a
+ * NCR53c700 and a NCR53c710.  
+ *
+ * Write 0xff to this register.
+ * Read it.
+ * If the contents are 0xff, it is a NCR53c700
+ * If the contents are 0x00, it is a NCR53c700-66 first revision
+ * If the contents are some other value, it is some other NCR53c700-66
+ */
+#define CTEST9_REG_00		0x23	/* Chip test 9 ro */
+#define LCRC_REG_10		0x23	
+
+/*
+ * 0x24 through 0x27 are the DMA byte counter register.  Instructions
+ * write their high 8 bits into the DCMD register, the low 24 bits into
+ * the DBC register.
+ *
+ * Function is dependent on the command type being executed.
+ */
+
+ 
+#define DBC_REG			0x24
+/* 
+ * For Block Move Instructions, DBC is a 24 bit quantity representing 
+ *     the number of bytes to transfer.
+ * For Transfer Control Instructions, DBC is bit fielded as follows : 
+ */
+/* Bits 20 - 23 should be clear */
+#define DBC_TCI_TRUE		(1 << 19) 	/* Jump when true */
+#define DBC_TCI_COMPARE_DATA	(1 << 18)	/* Compare data */
+#define DBC_TCI_COMPARE_PHASE	(1 << 17)	/* Compare phase with DCMD field */
+#define DBC_TCI_WAIT_FOR_VALID	(1 << 16)	/* Wait for REQ */
+/* Bits 8 - 15 are reserved on some implementations ? */
+#define DBC_TCI_MASK_MASK	0xff00 		/* Mask for data compare */
+#define DBC_TCI_MASK_SHIFT	8
+#define DBC_TCI_DATA_MASK	0xff		/* Data to be compared */ 
+#define DBC_TCI_DATA_SHIFT	0
+
+#define DBC_RWRI_IMMEDIATE_MASK	0xff00		/* Immediate data */
+#define DBC_RWRI_IMMEDIATE_SHIFT 8		/* Amount to shift */
+#define DBC_RWRI_ADDRESS_MASK	0x3f0000	/* Register address */
+#define DBC_RWRI_ADDRESS_SHIFT 	16
+
+
+/*
+ * DMA command r/w
+ */
+#define DCMD_REG		0x27	
+#define DCMD_TYPE_MASK		0xc0	/* Masks off type */
+#define DCMD_TYPE_BMI		0x00	/* Indicates a Block Move instruction */
+#define DCMD_BMI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_BMI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_BMI_MSG		0x04	/* instruction 			     */
+
+#define DCMD_BMI_OP_MASK	0x18	/* mask for opcode */
+#define DCMD_BMI_OP_MOVE_T	0x00	/* MOVE */
+#define DCMD_BMI_OP_MOVE_I	0x08	/* MOVE Initiator */
+
+#define DCMD_BMI_INDIRECT	0x20	/*  Indirect addressing */
+
+#define DCMD_TYPE_TCI		0x80	/* Indicates a Transfer Control 
+					   instruction */
+#define DCMD_TCI_IO		0x01	/* I/O, CD, and MSG bits selecting   */
+#define DCMD_TCI_CD		0x02	/* the phase for the block MOVE      */
+#define DCMD_TCI_MSG		0x04	/* instruction 			     */
+#define DCMD_TCI_OP_MASK	0x38	/* mask for opcode */
+#define DCMD_TCI_OP_JUMP	0x00	/* JUMP */
+#define DCMD_TCI_OP_CALL	0x08	/* CALL */
+#define DCMD_TCI_OP_RETURN	0x10	/* RETURN */
+#define DCMD_TCI_OP_INT		0x18	/* INT */
+
+#define DCMD_TYPE_RWRI		0x40	/* Indicates I/O or register Read/Write
+					   instruction */
+#define DCMD_RWRI_OPC_MASK	0x38	/* Opcode mask */
+#define DCMD_RWRI_OPC_WRITE	0x28	/* Write SFBR to register */
+#define DCMD_RWRI_OPC_READ	0x30	/* Read register to SFBR */
+#define DCMD_RWRI_OPC_MODIFY	0x38	/* Modify in place */
+
+#define DCMD_RWRI_OP_MASK	0x07
+#define DCMD_RWRI_OP_MOVE	0x00
+#define DCMD_RWRI_OP_SHL	0x01
+#define DCMD_RWRI_OP_OR		0x02
+#define DCMD_RWRI_OP_XOR	0x03
+#define DCMD_RWRI_OP_AND	0x04
+#define DCMD_RWRI_OP_SHR	0x05
+#define DCMD_RWRI_OP_ADD	0x06
+#define DCMD_RWRI_OP_ADDC	0x07
+
+#define DCMD_TYPE_MMI		0xc0	/* Indicates a Memory Move instruction 
+					   (three words) */
+
+
+#define DNAD_REG		0x28	/* through 0x2b DMA next address for 
+					   data */
+#define DSP_REG			0x2c	/* through 0x2f DMA SCRIPTS pointer rw */
+#define DSPS_REG		0x30	/* through 0x33 DMA SCRIPTS pointer 
+					   save rw */
+#define DMODE_REG_00		0x34 	/* DMA mode rw */
+#define DMODE_00_BL1	0x80	/* Burst length bits */
+#define DMODE_00_BL0	0x40
+#define DMODE_BL_MASK	0xc0
+/* Burst lengths (800) */
+#define DMODE_BL_2	0x00	/* 2 transfer */
+#define DMODE_BL_4	0x40	/* 4 transfers */
+#define DMODE_BL_8	0x80	/* 8 transfers */
+#define DMODE_BL_16	0xc0	/* 16 transfers */
+
+#define DMODE_10_BL_1	0x00	/* 1 transfer */
+#define DMODE_10_BL_2	0x40	/* 2 transfers */
+#define DMODE_10_BL_4	0x80	/* 4 transfers */
+#define DMODE_10_BL_8	0xc0	/* 8 transfers */
+#define DMODE_10_FC2	0x20	/* Driven to FC2 pin */
+#define DMODE_10_FC1	0x10	/* Driven to FC1 pin */
+#define DMODE_710_PD	0x08	/* Program/data on FC0 pin */
+#define DMODE_710_UO	0x02	/* User prog. output */
+
+#define DMODE_700_BW16	0x20	/* Host buswidth = 16 */
+#define DMODE_700_286	0x10	/* 286 mode */
+#define DMODE_700_IOM	0x08	/* Transfer to IO port */
+#define DMODE_700_FAM	0x04	/* Fixed address mode */
+#define DMODE_700_PIPE	0x02	/* Pipeline mode disables 
+					 * automatic fetch / exec 
+					 */
+#define DMODE_MAN	0x01		/* Manual start mode, 
+					 * requires a 1 to be written
+					 * to the start DMA bit in the DCNTL
+					 * register to run scripts 
+					 */
+
+#define DMODE_700_SAVE ( DMODE_00_BL_MASK | DMODE_00_BW16 | DMODE_00_286 )
+
+/* NCR53c800 series only */
+#define SCRATCHA_REG_800	0x34	/* through 0x37 Scratch A rw */
+/* NCR53c710 only */
+#define SCRATCHB_REG_10		0x34	/* through 0x37 scratch B rw */
+
+#define DMODE_REG_10    	0x38	/* DMA mode rw, NCR53c710 and newer */
+#define DMODE_800_SIOM		0x20	/* Source IO = 1 */
+#define DMODE_800_DIOM		0x10	/* Destination IO = 1 */
+#define DMODE_800_ERL		0x08	/* Enable Read Line */
+
+/* 35-38 are reserved on 700 and 700-66 series chips */
+#define DIEN_REG		0x39	/* DMA interrupt enable rw */
+/* 0x80, 0x40, and 0x20 are reserved on 700-series chips */
+#define DIEN_800_MDPE		0x40	/* Master data parity error */
+#define DIEN_800_BF		0x20	/* BUS fault */
+#define DIEN_700_BF		0x20	/* BUS fault */
+#define DIEN_ABRT		0x10	/* Enable aborted interrupt */
+#define DIEN_SSI		0x08	/* Enable single step interrupt */
+#define DIEN_SIR		0x04	/* Enable SCRIPTS INT command 
+					 * interrupt
+					 */
+/* 0x02 is reserved on 800 series chips */
+#define DIEN_700_WTD		0x02	/* Enable watchdog timeout interrupt */
+#define DIEN_700_OPC		0x01	/* Enable illegal instruction 
+					 * interrupt 
+					 */
+#define DIEN_800_IID		0x01	/*  Same meaning, different name */ 
+
+/*
+ * DMA watchdog timer rw
+ * set in 16 CLK input periods.
+ */
+#define DWT_REG			0x3a
+
+/* DMA control rw */
+#define DCNTL_REG		0x3b
+#define DCNTL_700_CF1		0x80	/* Clock divisor bits */
+#define DCNTL_700_CF0		0x40
+#define DCNTL_700_CF_MASK	0xc0
+/* Clock divisors 			   Divisor SCLK range (MHZ) */
+#define DCNTL_700_CF_2		0x00    /* 2.0	   37.51-50.00 */
+#define DCNTL_700_CF_1_5	0x40	/* 1.5	   25.01-37.50 */
+#define DCNTL_700_CF_1		0x80	/* 1.0     16.67-25.00 */
+#define DCNTL_700_CF_3		0xc0	/* 3.0	   50.01-66.67 (53c700-66) */
+
+#define DCNTL_700_S16		0x20	/* Load scripts 16 bits at a time */
+#define DCNTL_SSM		0x10	/* Single step mode */
+#define DCNTL_700_LLM		0x08	/* Low level mode, can only be set 
+					 * after selection */
+#define DCNTL_800_IRQM		0x08	/* Totem pole IRQ pin */
+#define DCNTL_STD		0x04	/* Start DMA / SCRIPTS */
+/* 0x02 is reserved */
+#define DCNTL_00_RST		0x01	/* Software reset, resets everything
+					 * but 286 mode bit  in DMODE. On the
+					 * NCR53c710, this bit moved to CTEST8
+					 */
+#define DCNTL_10_COM		0x01	/* 700 software compatibility mode */
+#define DCNTL_10_EA		0x20	/* Enable Ack - needed for MVME16x */
+
+#define DCNTL_700_SAVE ( DCNTL_CF_MASK | DCNTL_S16)
+
+
+/* NCR53c700-66 only */
+#define SCRATCHB_REG_00		0x3c	/* through 0x3f scratch b rw */
+#define SCRATCHB_REG_800	0x5c	/* through 0x5f scratch b rw */
+/* NCR53c710 only */
+#define ADDER_REG_10		0x3c	/* Adder, NCR53c710 only */
+
+#define SIEN1_REG_800		0x41
+#define SIEN1_800_STO		0x04	/* selection/reselection timeout */
+#define SIEN1_800_GEN		0x02	/* general purpose timer */
+#define SIEN1_800_HTH		0x01	/* handshake to handshake */
+
+#define SIST1_REG_800		0x43
+#define SIST1_800_STO		0x04	/* selection/reselection timeout */
+#define SIST1_800_GEN		0x02	/* general purpose timer */
+#define SIST1_800_HTH		0x01	/* handshake to handshake */
+
+#define SLPAR_REG_800		0x44	/* Parity */
+
+#define MACNTL_REG_800		0x46	/* Memory access control */
+#define MACNTL_800_TYP3		0x80
+#define MACNTL_800_TYP2		0x40
+#define MACNTL_800_TYP1		0x20
+#define MACNTL_800_TYP0		0x10
+#define MACNTL_800_DWR		0x08
+#define MACNTL_800_DRD		0x04
+#define MACNTL_800_PSCPT	0x02
+#define MACNTL_800_SCPTS	0x01
+
+#define GPCNTL_REG_800		0x47	/* General Purpose Pin Control */
+
+/* Timeouts are expressed such that 0=off, 1=100us, doubling after that */
+#define STIME0_REG_800		0x48	/* SCSI Timer Register 0 */
+#define STIME0_800_HTH_MASK	0xf0	/* Handshake to Handshake timeout */
+#define STIME0_800_HTH_SHIFT	4
+#define STIME0_800_SEL_MASK	0x0f	/* Selection timeout */
+#define STIME0_800_SEL_SHIFT	0
+
+#define STIME1_REG_800		0x49
+#define STIME1_800_GEN_MASK	0x0f	/* General purpose timer */
+
+#define RESPID_REG_800		0x4a	/* Response ID, bit fielded.  8
+					   bits on narrow chips, 16 on WIDE */
+
+#define STEST0_REG_800		0x4c	
+#define STEST0_800_SLT		0x08	/* Selection response logic test */
+#define STEST0_800_ART		0x04	/* Arbitration priority encoder test */
+#define STEST0_800_SOZ		0x02	/* Synchronous offset zero */
+#define STEST0_800_SOM		0x01	/* Synchronous offset maximum */
+
+#define STEST1_REG_800		0x4d
+#define STEST1_800_SCLK		0x80	/* Disable SCSI clock */
+
+#define STEST2_REG_800		0x4e	
+#define STEST2_800_SCE		0x80	/* Enable SOCL/SODL */
+#define STEST2_800_ROF		0x40	/* Reset SCSI sync offset */
+#define STEST2_800_SLB		0x10	/* Enable SCSI loopback mode */
+#define STEST2_800_SZM		0x08	/* SCSI high impedance mode */
+#define STEST2_800_EXT		0x02	/* Extend REQ/ACK filter 30 to 60ns */
+#define STEST2_800_LOW		0x01	/* SCSI low level mode */
+
+#define STEST3_REG_800		0x4f	 
+#define STEST3_800_TE		0x80	/* Enable active negation */
+#define STEST3_800_STR		0x40	/* SCSI FIFO test read */
+#define STEST3_800_HSC		0x20	/* Halt SCSI clock */
+#define STEST3_800_DSI		0x10	/* Disable single initiator response */
+#define STEST3_800_TTM		0x04	/* Time test mode */
+#define STEST3_800_CSF		0x02	/* Clear SCSI FIFO */
+#define STEST3_800_STW		0x01	/* SCSI FIFO test write */
+
+#define OPTION_PARITY 		0x1	/* Enable parity checking */
+#define OPTION_TAGGED_QUEUE	0x2	/* Enable SCSI-II tagged queuing */
+#define OPTION_700		0x8	/* Always run NCR53c700 scripts */
+#define OPTION_INTFLY		0x10	/* Use INTFLY interrupts */
+#define OPTION_DEBUG_INTR	0x20	/* Debug interrupts */
+#define OPTION_DEBUG_INIT_ONLY	0x40	/* Run initialization code and 
+					   simple test code, return
+					   DID_NO_CONNECT if any SCSI
+					   commands are attempted. */
+#define OPTION_DEBUG_READ_ONLY	0x80	/* Return DID_ERROR if any 
+					   SCSI write is attempted */
+#define OPTION_DEBUG_TRACE	0x100	/* Animated trace mode, print 
+					   each address and instruction 
+					   executed to debug buffer. */
+#define OPTION_DEBUG_SINGLE	0x200	/* stop after executing one 
+					   instruction */
+#define OPTION_SYNCHRONOUS	0x400	/* Enable sync SCSI.  */
+#define OPTION_MEMORY_MAPPED	0x800	/* NCR registers have valid 
+					   memory mapping */
+#define OPTION_IO_MAPPED	0x1000  /* NCR registers have valid
+					     I/O mapping */
+#define OPTION_DEBUG_PROBE_ONLY	0x2000  /* Probe only, don't even init */
+#define OPTION_DEBUG_TESTS_ONLY	0x4000  /* Probe, init, run selected tests */
+#define OPTION_DEBUG_TEST0	0x08000 /* Run test 0 */
+#define OPTION_DEBUG_TEST1	0x10000 /* Run test 1 */
+#define OPTION_DEBUG_TEST2	0x20000 /* Run test 2 */
+#define OPTION_DEBUG_DUMP	0x40000 /* Dump commands */
+#define OPTION_DEBUG_TARGET_LIMIT 0x80000 /* Only talk to target+luns specified */
+#define OPTION_DEBUG_NCOMMANDS_LIMIT 0x100000 /* Limit the number of commands */
+#define OPTION_DEBUG_SCRIPT 0x200000 /* Print when checkpoints are passed */
+#define OPTION_DEBUG_FIXUP 0x400000 /* print fixup values */
+#define OPTION_DEBUG_DSA 0x800000
+#define OPTION_DEBUG_CORRUPTION	0x1000000	/* Detect script corruption */
+#define OPTION_DEBUG_SDTR       0x2000000	/* Debug SDTR problem */
+#define OPTION_DEBUG_MISMATCH 	0x4000000 	/* Debug phase mismatches */
+#define OPTION_DISCONNECT	0x8000000	/* Allow disconnect */
+#define OPTION_DEBUG_DISCONNECT 0x10000000	
+#define OPTION_ALWAYS_SYNCHRONOUS 0x20000000	/* Negotiate sync. transfers
+						   on power up */
+#define OPTION_DEBUG_QUEUES	0x80000000	
+#define OPTION_DEBUG_ALLOCATION 0x100000000LL
+#define OPTION_DEBUG_SYNCHRONOUS 0x200000000LL	/* Sanity check SXFER and 
+						   SCNTL3 registers */
+#define OPTION_NO_ASYNC	0x400000000LL		/* Don't automagically send
+						   SDTR for async transfers when
+						   we haven't been told to do
+						   a synchronous transfer. */
+#define OPTION_NO_PRINT_RACE 0x800000000LL	/* Don't print message when
+						   the reselect/WAIT DISCONNECT
+						   race condition hits */
+#if !defined(PERM_OPTIONS)
+#define PERM_OPTIONS 0
+#endif
+				
+/*
+ * Some data which is accessed by the NCR chip must be 4-byte aligned.
+ * For some hosts the default is less than that (eg. 68K uses 2-byte).
+ * Alignment has only been forced where it is important; also if one
+ * 32 bit structure field is aligned then it is assumed that following
+ * 32 bit fields are also aligned.  Take care when adding fields
+ * which are other than 32 bit.
+ */
+
+struct NCR53c7x0_synchronous {
+    u32 select_indirect			/* Value used for indirect selection */
+	__attribute__ ((aligned (4)));
+    u32 sscf_710;			/* Used to set SSCF bits for 710 */
+    u32 script[8];			/* Size ?? Script used when target is 
+						reselected */
+    unsigned char synchronous_want[5];	/* Per target desired SDTR */
+/* 
+ * Set_synchronous programs these, select_indirect and current settings after
+ * int_debug_should show a match.
+ */
+    unsigned char sxfer_sanity, scntl3_sanity;
+};
+
+#define CMD_FLAG_SDTR 		1	/* Initiating synchronous 
+					   transfer negotiation */
+#define CMD_FLAG_WDTR		2	/* Initiating wide transfer
+					   negotiation */
+#define CMD_FLAG_DID_SDTR	4	/* did SDTR */
+#define CMD_FLAG_DID_WDTR	8	/* did WDTR */
+
+struct NCR53c7x0_table_indirect {
+    u32 count;
+    void *address;
+};
+
+enum ncr_event { 
+    EVENT_NONE = 0,
+/* 
+ * Order is IMPORTANT, since these must correspond to the event interrupts
+ * in 53c7,8xx.scr 
+ */
+
+    EVENT_ISSUE_QUEUE = 0x5000000,	/* 0 Command was added to issue queue */
+    EVENT_START_QUEUE,			/* 1 Command moved to start queue */
+    EVENT_SELECT,			/* 2 Command completed selection */
+    EVENT_DISCONNECT,			/* 3 Command disconnected */
+    EVENT_RESELECT,			/* 4 Command reselected */
+    EVENT_COMPLETE,		        /* 5 Command completed */
+    EVENT_IDLE,				/* 6 */
+    EVENT_SELECT_FAILED,		/* 7 */
+    EVENT_BEFORE_SELECT,		/* 8 */
+    EVENT_RESELECT_FAILED		/* 9 */
+};
+
+struct NCR53c7x0_event {
+    enum ncr_event event;	/* What type of event */
+    unsigned char target;
+    unsigned char lun;
+    struct timeval time;	
+    u32 *dsa;			/* What's in the DSA register now (virt) */
+/* 
+ * A few things from that SCSI pid so we know what happened after 
+ * the Scsi_Cmnd structure in question may have disappeared.
+ */
+    unsigned long pid;		/* The SCSI PID which caused this 
+				   event */
+    unsigned char cmnd[12];
+};
+
+/*
+ * Things in the NCR53c7x0_cmd structure are split into two parts :
+ *
+ * 1.  A fixed portion, for things which are not accessed directly by static NCR
+ *	code (ie, are referenced only by the Linux side of the driver,
+ *	or only by dynamically generated code).  
+ *
+ * 2.  The DSA portion, for things which are accessed directly by static NCR
+ *	code.
+ *
+ * This is a little ugly, but it 
+ * 1.  Avoids conflicts between the NCR code's picture of the structure, and 
+ * 	Linux code's idea of what it looks like.
+ *
+ * 2.  Minimizes the pain in the Linux side of the code needed 
+ * 	to calculate real dsa locations for things, etc.
+ * 
+ */
+
+struct NCR53c7x0_cmd {
+    void *real;				/* Real, unaligned address for
+					   free function */
+    void (* free)(void *, int);		/* Command to deallocate; NULL
+					   for structures allocated with
+					   scsi_register, etc. */
+    Scsi_Cmnd *cmd;			/* Associated Scsi_Cmnd 
+					   structure, Scsi_Cmnd points
+					   at NCR53c7x0_cmd using 
+					   host_scribble structure */
+
+    int size;				/* scsi_malloc'd size of this 
+					   structure */
+
+    int flags;				/* CMD_* flags */
+
+    unsigned char      cmnd[12];	/* CDB, copied from Scsi_Cmnd */
+    int                result;		/* Copy to Scsi_Cmnd when done */
+
+    struct {				/* Private non-cached bounce buffer */
+        unsigned char buf[256];
+	u32	      addr;
+        u32           len;
+    } bounce;
+
+/*
+ * SDTR and WIDE messages are an either/or affair
+ * in this message, since we will go into message out and send
+ * _the whole mess_ without dropping out of message out to 
+ * let the target go into message in after sending the first 
+ * message.
+ */
+
+    unsigned char select[11];		/* Select message, includes
+					   IDENTIFY
+					   (optional) QUEUE TAG
+ 				 	   (optional) SDTR or WDTR
+					 */
+
+
+    volatile struct NCR53c7x0_cmd *next; /* Linux maintained lists (free,
+					    running, eventually finished */
+    					 
+
+    u32 *data_transfer_start;		/* Start of data transfer routines */
+    u32 *data_transfer_end;		/* Address after end of data transfer o
+    	    	    	    	    	   routines */
+/* 
+ * The following three fields were moved from the DSA proper to here
+ * since only dynamically generated NCR code refers to them, meaning
+ * we don't need dsa_* absolutes, and it is simpler to let the 
+ * host code refer to them directly.
+ */
+
+/* 
+ * HARD CODED : residual and saved_residual need to agree with the sizes
+ * used in NCR53c7,8xx.scr.  
+ * 
+ * FIXME: we want to consider the case where we have odd-length 
+ *	scatter/gather buffers and a WIDE transfer, in which case 
+ *	we'll need to use the CHAIN MOVE instruction.  Ick.
+ */
+    u32 residual[6] __attribute__ ((aligned (4)));
+					/* Residual data transfer which
+					   allows pointer code to work
+					   right.
+
+    	    	    	    	    	    [0-1] : Conditional call to 
+    	    	    	    	    	    	appropriate other transfer 
+    	    	    	    	    	    	routine.
+    	    	    	    	    	    [2-3] : Residual block transfer
+    	    	    	    	    	    	instruction.
+    	    	    	    	    	    [4-5] : Jump to instruction
+    	    	    	    	    	    	after splice.
+					 */
+    u32 saved_residual[6]; 		/* Copy of old residual, so we 
+					   can get another partial 
+					   transfer and still recover 
+    	    	    	    	    	 */
+    	    	
+    u32 saved_data_pointer;		/* Saved data pointer */
+
+    u32 dsa_next_addr;		        /* _Address_ of dsa_next field  
+					   in this dsa for RISCy 
+					   style constant. */
+
+    u32 dsa_addr;			/* Address of dsa; RISCy style
+					   constant */
+
+    u32 dsa[0];				/* Variable length (depending
+					   on host type, number of scatter /
+					   gather buffers, etc).  */
+};
+
+struct NCR53c7x0_break {
+    u32 *address, old_instruction[2];
+    struct NCR53c7x0_break *next;
+    unsigned char old_size;		/* Size of old instruction */
+};
+
+/* Indicates that the NCR is not executing code */
+#define STATE_HALTED	0		
+/* 
+ * Indicates that the NCR is executing the wait for select / reselect 
+ * script.  Only used when running NCR53c700 compatible scripts, only 
+ * state during which an ABORT is _not_ considered an error condition.
+ */
+#define STATE_WAITING	1		
+/* Indicates that the NCR is executing other code. */
+#define STATE_RUNNING	2		
+/* 
+ * Indicates that the NCR was being aborted.
+ */
+#define STATE_ABORTING	3
+/* Indicates that the NCR was successfully aborted. */
+#define STATE_ABORTED 4
+/* Indicates that the NCR has been disabled due to a fatal error */
+#define STATE_DISABLED 5
+
+/* 
+ * Where knowledge of SCSI SCRIPT(tm) specified values are needed 
+ * in an interrupt handler, an interrupt handler exists for each 
+ * different SCSI script so we don't have name space problems.
+ * 
+ * Return values of these handlers are as follows : 
+ */
+#define SPECIFIC_INT_NOTHING 	0	/* don't even restart */
+#define SPECIFIC_INT_RESTART	1	/* restart at the next instruction */
+#define SPECIFIC_INT_ABORT	2	/* recoverable error, abort cmd */
+#define SPECIFIC_INT_PANIC	3	/* unrecoverable error, panic */
+#define SPECIFIC_INT_DONE	4	/* normal command completion */
+#define SPECIFIC_INT_BREAK	5	/* break point encountered */
+
+struct NCR53c7x0_hostdata {
+    int size;				/* Size of entire Scsi_Host
+					   structure */
+    int board;				/* set to board type, useful if 
+					   we have host specific things,
+					   ie, a general purpose I/O 
+					   bit is being used to enable
+					   termination, etc. */
+
+    int chip;				/* set to chip type; 700-66 is
+					   700-66, rest are last three
+					   digits of part number */
+
+    char valid_ids[8];			/* Valid SCSI ID's for adapter */
+
+    u32 *dsp;				/* dsp to restart with after
+					   all stacked interrupts are
+					   handled. */
+
+    unsigned dsp_changed:1;		/* Has dsp changed within this
+					   set of stacked interrupts ? */
+
+    unsigned char dstat;		/* Most recent value of dstat */
+    unsigned dstat_valid:1;
+
+    unsigned expecting_iid:1;		/* Expect IID interrupt */
+    unsigned expecting_sto:1;		/* Expect STO interrupt */
+    
+    /* 
+     * The code stays cleaner if we use variables with function
+     * pointers and offsets that are unique for the different
+     * scripts rather than having a slew of switch(hostdata->chip) 
+     * statements.
+     * 
+     * It also means that the #defines from the SCSI SCRIPTS(tm)
+     * don't have to be visible outside of the script-specific
+     * instructions, preventing name space pollution.
+     */
+
+    void (* init_fixup)(struct Scsi_Host *host);
+    void (* init_save_regs)(struct Scsi_Host *host);
+    void (* dsa_fixup)(struct NCR53c7x0_cmd *cmd);
+    void (* soft_reset)(struct Scsi_Host *host);
+    int (* run_tests)(struct Scsi_Host *host);
+
+    /*
+     * Called when DSTAT_SIR is set, indicating an interrupt generated
+     * by the INT instruction, where values are unique for each SCSI
+     * script.  Should return one of the SPEC_* values.
+     */
+
+    int (* dstat_sir_intr)(struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd);
+
+    int dsa_len; /* Size of DSA structure */
+
+    /*
+     * Location of DSA fields for the SCSI SCRIPT corresponding to this 
+     * chip.  
+     */
+
+    s32 dsa_start;			
+    s32 dsa_end;			
+    s32 dsa_next;
+    s32 dsa_prev;
+    s32 dsa_cmnd;
+    s32 dsa_select;
+    s32 dsa_msgout;
+    s32 dsa_cmdout;
+    s32 dsa_dataout;
+    s32 dsa_datain;
+    s32 dsa_msgin;
+    s32 dsa_msgout_other;
+    s32 dsa_write_sync;
+    s32 dsa_write_resume;
+    s32 dsa_check_reselect;
+    s32 dsa_status;
+    s32 dsa_saved_pointer;
+    s32 dsa_jump_dest;
+
+    /* 
+     * Important entry points that generic fixup code needs
+     * to know about, fixed up.
+     */
+
+    s32 E_accept_message;
+    s32 E_command_complete;		
+    s32 E_data_transfer;
+    s32 E_dsa_code_template;
+    s32 E_dsa_code_template_end;
+    s32 E_end_data_transfer;
+    s32 E_msg_in;
+    s32 E_initiator_abort;
+    s32 E_other_transfer;
+    s32 E_other_in;
+    s32 E_other_out;
+    s32 E_target_abort;
+    s32 E_debug_break;	
+    s32 E_reject_message;
+    s32 E_respond_message;
+    s32 E_select;
+    s32 E_select_msgout;
+    s32 E_test_0;
+    s32 E_test_1;
+    s32 E_test_2;
+    s32 E_test_3;
+    s32 E_dsa_zero;
+    s32 E_cmdout_cmdout;
+    s32 E_wait_reselect;
+    s32 E_dsa_code_begin;
+
+    long long options;			/* Bitfielded set of options enabled */
+    volatile u32 test_completed;	/* Test completed */
+    int test_running;			/* Test currently running */
+    s32 test_source
+	__attribute__ ((aligned (4)));
+    volatile s32 test_dest;
+
+    volatile int state;			/* state of driver, only used for 
+					   OPTION_700 */
+
+    unsigned char  dmode;		/* 
+					 * set to the address of the DMODE 
+					 * register for this chip.
+					 */
+    unsigned char istat;		/* 
+    	    	    	    	    	 * set to the address of the ISTAT 
+    	    	    	    	    	 * register for this chip.
+    	    	    	    	    	 */
+  
+    int scsi_clock;			/* 
+					 * SCSI clock in HZ. 0 may be used 
+					 * for unknown, although this will
+					 * disable synchronous negotiation.
+					 */
+
+    volatile int intrs;			/* Number of interrupts */
+    volatile int resets;		/* Number of SCSI resets */
+    unsigned char saved_dmode;	
+    unsigned char saved_ctest4;
+    unsigned char saved_ctest7;
+    unsigned char saved_dcntl;
+    unsigned char saved_scntl3;
+
+    unsigned char this_id_mask;
+
+    /* Debugger information */
+    struct NCR53c7x0_break *breakpoints, /* Linked list of all break points */
+	*breakpoint_current;		/* Current breakpoint being stepped 
+					   through, NULL if we are running 
+					   normally. */
+#ifdef NCR_DEBUG
+    int debug_size;			/* Size of debug buffer */
+    volatile int debug_count;		/* Current data count */
+    volatile char *debug_buf;		/* Output ring buffer */
+    volatile char *debug_write;		/* Current write pointer */
+    volatile char *debug_read;		/* Current read pointer */
+#endif /* def NCR_DEBUG */
+
+    /* XXX - primitive debugging junk, remove when working ? */
+    int debug_print_limit;		/* Number of commands to print
+					   out exhaustive debugging
+					   information for if 
+					   OPTION_DEBUG_DUMP is set */ 
+
+    unsigned char debug_lun_limit[16];	/* If OPTION_DEBUG_TARGET_LIMIT
+					   set, puke if commands are sent
+					   to other target/lun combinations */
+
+    int debug_count_limit;		/* Number of commands to execute
+					   before puking to limit debugging 
+					   output */
+				    
+
+    volatile unsigned idle:1;			/* set to 1 if idle */
+
+    /* 
+     * Table of synchronous+wide transfer parameters set on a per-target
+     * basis.
+     */
+    
+    volatile struct NCR53c7x0_synchronous sync[16]
+	__attribute__ ((aligned (4)));
+
+    volatile Scsi_Cmnd *issue_queue
+	__attribute__ ((aligned (4)));
+						/* waiting to be issued by
+						   Linux driver */
+    volatile struct NCR53c7x0_cmd *running_list;	
+						/* commands running, maintained
+						   by Linux driver */
+
+    volatile struct NCR53c7x0_cmd *ncrcurrent;	/* currently connected 
+						   nexus, ONLY valid for
+						   NCR53c700/NCR53c700-66
+						 */
+
+    volatile struct NCR53c7x0_cmd *spare;	/* pointer to spare,
+    	    	    	    	    	    	   allocated at probe time,
+    	    	    	    	    	    	   which we can use for 
+						   initialization */
+    volatile struct NCR53c7x0_cmd *free;
+    int max_cmd_size;				/* Maximum size of NCR53c7x0_cmd
+					    	   based on number of 
+						   scatter/gather segments, etc.
+						   */
+    volatile int num_cmds;			/* Number of commands 
+						   allocated */
+    volatile int extra_allocate;
+    volatile unsigned char cmd_allocated[16];	/* Have we allocated commands
+						   for this target yet?  If not,
+						   do so ASAP */
+    volatile unsigned char busy[16][8];     	/* number of commands 
+						   executing on each target
+    	    	    	    	    	    	 */
+    /* 
+     * Eventually, I'll switch to a coroutine for calling 
+     * cmd->done(cmd), etc. so that we can overlap interrupt
+     * processing with this code for maximum performance.
+     */
+    
+    volatile struct NCR53c7x0_cmd *finished_queue;	
+						
+    /* Shared variables between SCRIPT and host driver */
+    volatile u32 *schedule
+	__attribute__ ((aligned (4)));		/* Array of JUMPs to dsa_begin
+						   routines of various DSAs.  
+						   When not in use, replace
+						   with jump to next slot */
+
+
+    volatile unsigned char msg_buf[16];		/* buffer for messages
+						   other than the command
+						   complete message */
+
+    /* Per-target default synchronous and WIDE messages */
+    volatile unsigned char synchronous_want[16][5];
+    volatile unsigned char wide_want[16][4];
+
+    /* Bit fielded set of targets we want to speak synchronously with */ 
+    volatile u16 initiate_sdtr;	
+    /* Bit fielded set of targets we want to speak wide with */
+    volatile u16 initiate_wdtr;
+    /* Bit fielded list of targets we've talked to. */
+    volatile u16 talked_to;
+
+    /* Array of bit-fielded lun lists that we need to request_sense */
+    volatile unsigned char request_sense[16];
+
+    u32 addr_reconnect_dsa_head
+	__attribute__ ((aligned (4)));		/* RISCy style constant,
+						   address of following */
+    volatile u32 reconnect_dsa_head;	
+    /* Data identifying nexus we are trying to match during reselection */
+    volatile unsigned char reselected_identify; /* IDENTIFY message */
+    volatile unsigned char reselected_tag;	/* second byte of queue tag 
+						   message or 0 */
+
+    /* These were static variables before we moved them */
+
+    s32 NCR53c7xx_zero
+	__attribute__ ((aligned (4)));
+    s32 NCR53c7xx_sink;
+    u32 NOP_insn;
+    char NCR53c7xx_msg_reject;
+    char NCR53c7xx_msg_abort;
+    char NCR53c7xx_msg_nop;
+
+    /*
+     * Following item introduced by RGH to support NCRc710, which is
+     * VERY brain-dead when it come to memory moves
+     */
+
+			  /* DSA save area used only by the NCR chip */
+    volatile unsigned long saved2_dsa
+	__attribute__ ((aligned (4)));
+
+    volatile unsigned long emulated_intfly
+	__attribute__ ((aligned (4)));
+
+    volatile int event_size, event_index;
+    volatile struct NCR53c7x0_event *events;
+
+    /* If we need to generate code to kill off the currently connected 
+       command, this is where we do it. Should have a BMI instruction
+       to source or sink the current data, followed by a JUMP
+       to abort_connected */
+
+    u32 *abort_script;
+
+    int script_count;				/* Size of script in words */
+    u32 script[0];				/* Relocated SCSI script */
+
+};
+
+#define SCSI_IRQ_NONE	255
+#define DMA_NONE	255
+#define IRQ_AUTO	254
+#define DMA_AUTO	254
+
+#define BOARD_GENERIC	0
+
+#define NCR53c7x0_insn_size(insn)					\
+    (((insn) & DCMD_TYPE_MASK) == DCMD_TYPE_MMI ? 3 : 2)
+    
+
+#define NCR53c7x0_local_declare()					\
+    volatile unsigned char *NCR53c7x0_address_memory;			\
+    unsigned int NCR53c7x0_address_io;					\
+    int NCR53c7x0_memory_mapped
+
+#define NCR53c7x0_local_setup(host)					\
+    NCR53c7x0_address_memory = (void *) (host)->base;			\
+    NCR53c7x0_address_io = (unsigned int) (host)->io_port;		\
+    NCR53c7x0_memory_mapped = ((struct NCR53c7x0_hostdata *) 		\
+	host->hostdata[0])-> options & OPTION_MEMORY_MAPPED 
+
+#ifdef BIG_ENDIAN
+/* These could be more efficient, given that we are always memory mapped,
+ * but they don't give the same problems as the write macros, so leave
+ * them. */
+#ifdef __mc68000__
+#define NCR53c7x0_read8(address) 					\
+    ((unsigned int)raw_inb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) )
+
+#define NCR53c7x0_read16(address) 					\
+    ((unsigned int)raw_inw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)))
+#else
+#define NCR53c7x0_read8(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readb((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) :	\
+	inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readw((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) :	\
+	inw(NCR53c7x0_address_io + (address)))
+#endif /* mc68000 */
+#else
+#define NCR53c7x0_read8(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readb((u32)NCR53c7x0_address_memory + (u32)(address)) :	\
+	inb(NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_read16(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int)readw((u32)NCR53c7x0_address_memory + (u32)(address)) :	\
+	inw(NCR53c7x0_address_io + (address)))
+#endif
+
+#ifdef __mc68000__
+#define NCR53c7x0_read32(address) 					\
+    ((unsigned int) raw_inl((u32)NCR53c7x0_address_memory + (u32)(address)))
+#else
+#define NCR53c7x0_read32(address) 					\
+    (NCR53c7x0_memory_mapped ? 						\
+	(unsigned int) readl((u32)NCR53c7x0_address_memory + (u32)(address)) : 	\
+	inl(NCR53c7x0_address_io + (address)))
+#endif /* mc68000*/
+
+#ifdef BIG_ENDIAN
+/* If we are big-endian, then we are not Intel, so probably don't have
+ * an i/o map as well as a memory map.  So, let's assume memory mapped.
+ * Also, I am having terrible problems trying to persuade the compiler
+ * not to lay down code which does a read after write for these macros.
+ * If you remove 'volatile' from writeb() and friends it is ok....
+ */
+
+#define NCR53c7x0_write8(address,value) 				\
+	*(volatile unsigned char *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address)^3)) = (value)
+
+#define NCR53c7x0_write16(address,value) 				\
+	*(volatile unsigned short *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address)^2)) = (value)
+
+#define NCR53c7x0_write32(address,value) 				\
+	*(volatile unsigned long *)					\
+		((u32)NCR53c7x0_address_memory + ((u32)(address))) = (value)
+
+#else
+
+#define NCR53c7x0_write8(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writeb((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outb((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write16(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writew((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outw((value), NCR53c7x0_address_io + (address)))
+
+#define NCR53c7x0_write32(address,value) 				\
+    (NCR53c7x0_memory_mapped ? 						\
+     ({writel((value), (u32)NCR53c7x0_address_memory + (u32)(address)); mb();}) :	\
+	outl((value), NCR53c7x0_address_io + (address)))
+
+#endif
+
+/* Patch arbitrary 32 bit words in the script */
+#define patch_abs_32(script, offset, symbol, value)			\
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i) {					\
+	    (script)[A_##symbol##_used[i] - (offset)] += (value);	\
+	    if (hostdata->options & OPTION_DEBUG_FIXUP) 		\
+	      printk("scsi%d : %s reference %d at 0x%x in %s is now 0x%x\n",\
+		host->host_no, #symbol, i, A_##symbol##_used[i] - 	\
+		(int)(offset), #script, (script)[A_##symbol##_used[i] -	\
+		(offset)]);						\
+    	}
+
+/* Patch read/write instruction immediate field */
+#define patch_abs_rwri_data(script, offset, symbol, value)		\
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i)					\
+    	    (script)[A_##symbol##_used[i] - (offset)] =			\
+	    	((script)[A_##symbol##_used[i] - (offset)] & 		\
+	    	~DBC_RWRI_IMMEDIATE_MASK) | 				\
+    	    	(((value) << DBC_RWRI_IMMEDIATE_SHIFT) &		\
+		 DBC_RWRI_IMMEDIATE_MASK)
+
+/* Patch transfer control instruction data field */
+#define patch_abs_tci_data(script, offset, symbol, value)	        \
+    	for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof 		\
+    	    (u32)); ++i)					\
+    	    (script)[A_##symbol##_used[i] - (offset)] =			\
+	    	((script)[A_##symbol##_used[i] - (offset)] & 		\
+	    	~DBC_TCI_DATA_MASK) | 					\
+    	    	(((value) << DBC_TCI_DATA_SHIFT) &			\
+		 DBC_TCI_DATA_MASK)
+
+/* Patch field in dsa structure (assignment should be +=?) */
+#define patch_dsa_32(dsa, symbol, word, value)				\
+	{								\
+	(dsa)[(hostdata->##symbol - hostdata->dsa_start) / sizeof(u32)	\
+	    + (word)] = (value);					\
+	if (hostdata->options & OPTION_DEBUG_DSA)			\
+	    printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n",	\
+		#dsa, #symbol, hostdata->##symbol, 			\
+		(word), (u32) (value));					\
+	}
+
+/* Paranoid people could use panic() here. */
+#define FATAL(host) shutdown((host));
+
+extern int ncr53c7xx_init(Scsi_Host_Template *tpnt, int board, int chip,
+			  unsigned long base, int io_port, int irq, int dma,
+			  long long options, int clock);
+
+#endif /* NCR53c710_C */
+#endif /* NCR53c710_H */
diff --git a/drivers/scsi/53c7xx.scr b/drivers/scsi/53c7xx.scr
new file mode 100644
index 0000000..9c5694a
--- /dev/null
+++ b/drivers/scsi/53c7xx.scr
@@ -0,0 +1,1591 @@
+#undef DEBUG
+#undef EVENTS
+#undef NO_SELECTION_TIMEOUT
+#define BIG_ENDIAN
+
+; 53c710 driver.  Modified from Drew Eckhardts driver
+; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+;
+; I have left the script for the 53c8xx family in here, as it is likely
+; to be useful to see what I changed when bug hunting.
+
+; NCR 53c810 driver, main script
+; Sponsored by 
+;	iX Multiuser Multitasking Magazine
+;	hm@ix.de
+;
+; Copyright 1993, 1994, 1995 Drew Eckhardt
+;      Visionary Computing 
+;      (Unix and Linux consulting and custom programming)
+;      drew@PoohSticks.ORG
+;      +1 (303) 786-7975
+;
+; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+;
+; PRE-ALPHA
+;
+; For more information, please consult 
+;
+; NCR 53C810
+; PCI-SCSI I/O Processor
+; Data Manual
+;
+; NCR 53C710 
+; SCSI I/O Processor
+; Programmers Guide
+;
+; NCR Microelectronics
+; 1635 Aeroplaza Drive
+; Colorado Springs, CO 80916
+; 1+ (719) 578-3400
+;
+; Toll free literature number
+; +1 (800) 334-5454
+;
+; IMPORTANT : This code is self modifying due to the limitations of 
+;	the NCR53c7,8xx series chips.  Persons debugging this code with
+;	the remote debugger should take this into account, and NOT set
+;	breakpoints in modified instructions.
+;
+; Design:
+; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 
+; microcontroller using a simple instruction set.   
+;
+; So, to minimize the effects of interrupt latency, and to maximize 
+; throughput, this driver offloads the practical maximum amount 
+; of processing to the SCSI chip while still maintaining a common
+; structure.
+;
+; Where tradeoffs were needed between efficiency on the older
+; chips and the newer NCR53c800 series, the NCR53c800 series 
+; was chosen.
+;
+; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
+; automate SCSI transfers without host processor intervention, this 
+; isn't the case with the NCR53c710 and newer chips which allow 
+;
+; - reads and writes to the internal registers from within the SCSI
+; 	scripts, allowing the SCSI SCRIPTS(tm) code to save processor
+; 	state so that multiple threads of execution are possible, and also
+; 	provide an ALU for loop control, etc.
+; 
+; - table indirect addressing for some instructions. This allows 
+;	pointers to be located relative to the DSA ((Data Structure
+;	Address) register.
+;
+; These features make it possible to implement a mailbox style interface,
+; where the same piece of code is run to handle I/O for multiple threads
+; at once minimizing our need to relocate code.  Since the NCR53c700/
+; NCR53c800 series have a unique combination of features, making a 
+; a standard ingoing/outgoing mailbox system, costly, I've modified it.
+;
+; - Mailboxes are a mixture of code and data.  This lets us greatly
+; 	simplify the NCR53c810 code and do things that would otherwise
+;	not be possible.
+;
+; The saved data pointer is now implemented as follows :
+;
+; 	Control flow has been architected such that if control reaches
+;	munge_save_data_pointer, on a restore pointers message or 
+;	reconnection, a jump to the address formerly in the TEMP register
+;	will allow the SCSI command to resume execution.
+;
+
+;
+; Note : the DSA structures must be aligned on 32 bit boundaries,
+; since the source and destination of MOVE MEMORY instructions 
+; must share the same alignment and this is the alignment of the
+; NCR registers.
+;
+
+; For some systems (MVME166, for example) dmode is always the same, so don't
+; waste time writing it
+
+#if 1
+#define DMODE_MEMORY_TO_NCR
+#define DMODE_MEMORY_TO_MEMORY
+#define DMODE_NCR_TO_MEMORY
+#else
+#define DMODE_MEMORY_TO_NCR    MOVE dmode_memory_to_ncr TO DMODE
+#define DMODE_MEMORY_TO_MEMORY MOVE dmode_memory_to_memory TO DMODE
+#define DMODE_NCR_TO_MEMORY    MOVE dmode_ncr_to_memory TO DMODE
+#endif
+
+ABSOLUTE dsa_temp_lun = 0		; Patch to lun for current dsa
+ABSOLUTE dsa_temp_next = 0		; Patch to dsa next for current dsa
+ABSOLUTE dsa_temp_addr_next = 0		; Patch to address of dsa next address 
+					; 	for current dsa
+ABSOLUTE dsa_temp_sync = 0		; Patch to address of per-target
+					;	sync routine
+ABSOLUTE dsa_sscf_710 = 0		; Patch to address of per-target
+					;	sscf value (53c710)
+ABSOLUTE dsa_temp_target = 0		; Patch to id for current dsa
+ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
+					; 	saved data pointer
+ABSOLUTE dsa_temp_addr_residual = 0	; Patch to address of per-command
+					;	current residual code
+ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
+					; saved residual code
+ABSOLUTE dsa_temp_addr_new_value = 0	; Address of value for JUMP operand
+ABSOLUTE dsa_temp_addr_array_value = 0 	; Address to copy to
+ABSOLUTE dsa_temp_addr_dsa_value = 0	; Address of this DSA value
+
+;
+; Once a device has initiated reselection, we need to compare it 
+; against the singly linked list of commands which have disconnected
+; and are pending reselection.  These commands are maintained in 
+; an unordered singly linked list of DSA structures, through the
+; DSA pointers at their 'centers' headed by the reconnect_dsa_head
+; pointer.
+; 
+; To avoid complications in removing commands from the list,
+; I minimize the amount of expensive (at eight operations per
+; addition @ 500-600ns each) pointer operations which must
+; be done in the NCR driver by precomputing them on the 
+; host processor during dsa structure generation.
+;
+; The fixed-up per DSA code knows how to recognize the nexus
+; associated with the corresponding SCSI command, and modifies
+; the source and destination pointers for the MOVE MEMORY 
+; instruction which is executed when reselected_ok is called
+; to remove the command from the list.  Similarly, DSA is 
+; loaded with the address of the next DSA structure and
+; reselected_check_next is called if a failure occurs.
+;
+; Perhaps more concisely, the net effect of the mess is 
+;
+; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, 
+;     src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
+; 	src = &dsa->next;
+; 	if (target_id == dsa->id && target_lun == dsa->lun) {
+; 		*dest = *src;
+; 		break;
+;         }	
+; }
+;
+; if (!dsa)
+;           error (int_err_unexpected_reselect);
+; else  
+;     longjmp (dsa->jump_resume, 0);
+;
+; 	
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Define DSA structure used for mailboxes
+ENTRY dsa_code_template
+dsa_code_template:
+ENTRY dsa_code_begin
+dsa_code_begin:
+; RGH: Don't care about TEMP and DSA here
+	DMODE_MEMORY_TO_NCR
+	MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+	; We are about to go and select the device, so must set SSCF bits
+	MOVE MEMORY 4, dsa_sscf_710, addr_scratch
+#ifdef BIG_ENDIAN
+	MOVE SCRATCH3 TO SFBR
+#else
+	MOVE SCRATCH0 TO SFBR
+#endif
+	MOVE SFBR TO SBCL
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+	CALL scratch_to_dsa
+#endif
+	CALL select
+; Handle the phase mismatch which may have resulted from the 
+; MOVE FROM dsa_msgout if we returned here.  The CLEAR ATN 
+; may or may not be necessary, and we should update script_asm.pl
+; to handle multiple pieces.
+    CLEAR ATN
+    CLEAR ACK
+
+; Replace second operand with address of JUMP instruction dest operand
+; in schedule table for this DSA.  Becomes dsa_jump_dest in 53c7,8xx.c.
+ENTRY dsa_code_fix_jump
+dsa_code_fix_jump:
+	MOVE MEMORY 4, NOP_insn, 0
+	JUMP select_done
+
+; wrong_dsa loads the DSA register with the value of the dsa_next
+; field.
+;
+wrong_dsa:
+#if (CHIP == 710)
+;                NOTE DSA is corrupt when we arrive here!
+#endif
+;		Patch the MOVE MEMORY INSTRUCTION such that 
+;		the destination address is the address of the OLD 
+;		next pointer.
+;
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
+	DMODE_MEMORY_TO_NCR
+;
+; 	Move the _contents_ of the next pointer into the DSA register as 
+;	the next I_T_L or I_T_L_Q tupple to check against the established
+;	nexus.
+;
+	MOVE MEMORY 4, dsa_temp_next, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#else
+	CALL scratch_to_dsa
+#endif
+	JUMP reselected_check_next
+
+ABSOLUTE dsa_save_data_pointer = 0
+ENTRY dsa_code_save_data_pointer
+dsa_code_save_data_pointer:
+#if (CHIP == 710)
+	; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
+	; We MUST return with DSA correct
+    	MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_saved
+#endif
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+	JUMP jump_temp
+#else
+    	DMODE_NCR_TO_MEMORY
+    	MOVE MEMORY 4, addr_temp, dsa_temp_addr_saved_pointer
+    	DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_saved
+#endif
+    	RETURN
+#endif
+ABSOLUTE dsa_restore_pointers = 0
+ENTRY dsa_code_restore_pointers
+dsa_code_restore_pointers:
+#if (CHIP == 710)
+	; TEMP and DSA are corrupt when we get here, but who cares!
+    	MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+        CLEAR ACK
+	; Restore DSA, note we don't care about TEMP
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#ifdef DEBUG
+        INT int_debug_restored
+#endif
+	JUMP jump_temp
+#else
+    	DMODE_MEMORY_TO_NCR
+    	MOVE MEMORY 4, dsa_temp_addr_saved_pointer, addr_temp
+    	DMODE_MEMORY_TO_MEMORY
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+        CLEAR ACK
+#ifdef DEBUG
+        INT int_debug_restored
+#endif
+    	RETURN
+#endif
+
+ABSOLUTE dsa_check_reselect = 0
+; dsa_check_reselect determines whether or not the current target and
+; lun match the current DSA
+ENTRY dsa_code_check_reselect
+dsa_code_check_reselect:
+#if (CHIP == 710)
+	/* Arrives here with DSA correct */
+	/* Assumes we are always ID 7 */
+	MOVE LCRC TO SFBR		; LCRC has our ID and his ID bits set
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
+#else
+	MOVE SSID TO SFBR		; SSID contains 3 bit target ID
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0xf8
+#endif
+;
+; Hack - move to scratch first, since SFBR is not writeable
+; 	via the CPU and hence a MOVE MEMORY instruction.
+;
+	DMODE_MEMORY_TO_NCR
+	MOVE MEMORY 1, reselected_identify, addr_scratch
+	DMODE_MEMORY_TO_MEMORY
+#ifdef BIG_ENDIAN
+	; BIG ENDIAN ON MVME16x
+	MOVE SCRATCH3 TO SFBR
+#else
+	MOVE SCRATCH0 TO SFBR
+#endif
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+; Are you sure about that?  richard@sleepie.demon.co.uk
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
+;		Patch the MOVE MEMORY INSTRUCTION such that
+;		the source address is the address of this dsa's
+;		next pointer.
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
+	CALL reselected_ok
+#if (CHIP == 710)
+;	Restore DSA following memory moves in reselected_ok
+;	dsa_temp_sync doesn't really care about DSA, but it has an
+;	optional debug INT so a valid DSA is a good idea.
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+	CALL dsa_temp_sync	
+; Release ACK on the IDENTIFY message _after_ we've set the synchronous 
+; transfer parameters! 
+	CLEAR ACK
+; Implicitly restore pointers on reselection, so a RETURN
+; will transfer control back to the right spot.
+    	CALL REL (dsa_code_restore_pointers)
+    	RETURN
+ENTRY dsa_zero
+dsa_zero:
+ENTRY dsa_code_template_end
+dsa_code_template_end:
+
+; Perform sanity check for dsa_fields_start == dsa_code_template_end - 
+; dsa_zero, puke.
+
+ABSOLUTE dsa_fields_start =  0	; Sanity marker
+				; 	pad 48 bytes (fix this RSN)
+ABSOLUTE dsa_next = 48		; len 4 Next DSA
+ 				; del 4 Previous DSA address
+ABSOLUTE dsa_cmnd = 56		; len 4 Scsi_Cmnd * for this thread.
+ABSOLUTE dsa_select = 60	; len 4 Device ID, Period, Offset for 
+			 	;	table indirect select
+ABSOLUTE dsa_msgout = 64	; len 8 table indirect move parameter for 
+				;       select message
+ABSOLUTE dsa_cmdout = 72	; len 8 table indirect move parameter for 
+				;	command
+ABSOLUTE dsa_dataout = 80	; len 4 code pointer for dataout
+ABSOLUTE dsa_datain = 84	; len 4 code pointer for datain
+ABSOLUTE dsa_msgin = 88		; len 8 table indirect move for msgin
+ABSOLUTE dsa_status = 96 	; len 8 table indirect move for status byte
+ABSOLUTE dsa_msgout_other = 104	; len 8 table indirect for normal message out
+				; (Synchronous transfer negotiation, etc).
+ABSOLUTE dsa_end = 112
+
+ABSOLUTE schedule = 0 		; Array of JUMP dsa_begin or JUMP (next),
+				; terminated by a call to JUMP wait_reselect
+
+; Linked lists of DSA structures
+ABSOLUTE reconnect_dsa_head = 0	; Link list of DSAs which can reconnect
+ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
+				; address of reconnect_dsa_head
+
+; These select the source and destination of a MOVE MEMORY instruction
+ABSOLUTE dmode_memory_to_memory = 0x0
+ABSOLUTE dmode_memory_to_ncr = 0x0
+ABSOLUTE dmode_ncr_to_memory = 0x0
+
+ABSOLUTE addr_scratch = 0x0
+ABSOLUTE addr_temp = 0x0
+#if (CHIP == 710)
+ABSOLUTE saved_dsa = 0x0
+ABSOLUTE emulfly = 0x0
+ABSOLUTE addr_dsa = 0x0
+#endif
+#endif /* CHIP != 700 && CHIP != 70066 */
+
+; Interrupts - 
+; MSB indicates type
+; 0	handle error condition
+; 1 	handle message 
+; 2 	handle normal condition
+; 3	debugging interrupt
+; 4 	testing interrupt 
+; Next byte indicates specific error
+
+; XXX not yet implemented, I'm not sure if I want to - 
+; Next byte indicates the routine the error occurred in
+; The LSB indicates the specific place the error occurred
+ 
+ABSOLUTE int_err_unexpected_phase = 0x00000000	; Unexpected phase encountered
+ABSOLUTE int_err_selected = 0x00010000		; SELECTED (nee RESELECTED)
+ABSOLUTE int_err_unexpected_reselect = 0x00020000 
+ABSOLUTE int_err_check_condition = 0x00030000	
+ABSOLUTE int_err_no_phase = 0x00040000
+ABSOLUTE int_msg_wdtr = 0x01000000		; WDTR message received
+ABSOLUTE int_msg_sdtr = 0x01010000		; SDTR received
+ABSOLUTE int_msg_1 = 0x01020000			; single byte special message
+						; received
+
+ABSOLUTE int_norm_select_complete = 0x02000000	; Select complete, reprogram
+						; registers.
+ABSOLUTE int_norm_reselect_complete = 0x02010000	; Nexus established
+ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
+ABSOLUTE int_norm_disconnected = 0x02030000	; Disconnected 
+ABSOLUTE int_norm_aborted =0x02040000		; Aborted *dsa
+ABSOLUTE int_norm_reset = 0x02050000		; Generated BUS reset.
+ABSOLUTE int_norm_emulateintfly = 0x02060000	; 53C710 Emulated intfly
+ABSOLUTE int_debug_break = 0x03000000		; Break point
+#ifdef DEBUG
+ABSOLUTE int_debug_scheduled = 0x03010000	; new I/O scheduled 
+ABSOLUTE int_debug_idle = 0x03020000		; scheduler is idle
+ABSOLUTE int_debug_dsa_loaded = 0x03030000	; dsa reloaded
+ABSOLUTE int_debug_reselected = 0x03040000	; NCR reselected
+ABSOLUTE int_debug_head = 0x03050000		; issue head overwritten
+ABSOLUTE int_debug_disconnected = 0x03060000	; disconnected
+ABSOLUTE int_debug_disconnect_msg = 0x03070000	; got message to disconnect
+ABSOLUTE int_debug_dsa_schedule = 0x03080000	; in dsa_schedule
+ABSOLUTE int_debug_reselect_check = 0x03090000  ; Check for reselection of DSA
+ABSOLUTE int_debug_reselected_ok = 0x030a0000 	; Reselection accepted
+#endif
+ABSOLUTE int_debug_panic = 0x030b0000		; Panic driver
+#ifdef DEBUG
+ABSOLUTE int_debug_saved = 0x030c0000 		; save/restore pointers
+ABSOLUTE int_debug_restored = 0x030d0000
+ABSOLUTE int_debug_sync = 0x030e0000		; Sanity check synchronous 
+						; parameters. 
+ABSOLUTE int_debug_datain = 0x030f0000		; going into data in phase 
+						; now.
+ABSOLUTE int_debug_check_dsa = 0x03100000	; Sanity check DSA against
+						; SDID.
+#endif
+
+ABSOLUTE int_test_1 = 0x04000000		; Test 1 complete
+ABSOLUTE int_test_2 = 0x04010000		; Test 2 complete
+ABSOLUTE int_test_3 = 0x04020000		; Test 3 complete
+
+
+; These should start with 0x05000000, with low bits incrementing for 
+; each one.
+
+#ifdef EVENTS
+ABSOLUTE int_EVENT_SELECT = 0
+ABSOLUTE int_EVENT_DISCONNECT = 0
+ABSOLUTE int_EVENT_RESELECT = 0
+ABSOLUTE int_EVENT_COMPLETE = 0
+ABSOLUTE int_EVENT_IDLE = 0
+ABSOLUTE int_EVENT_SELECT_FAILED = 0
+ABSOLUTE int_EVENT_BEFORE_SELECT = 0
+ABSOLUTE int_EVENT_RESELECT_FAILED = 0
+#endif
+						
+ABSOLUTE NCR53c7xx_msg_abort = 0	; Pointer to abort message
+ABSOLUTE NCR53c7xx_msg_reject = 0       ; Pointer to reject message
+ABSOLUTE NCR53c7xx_zero	= 0		; long with zero in it, use for source
+ABSOLUTE NCR53c7xx_sink = 0		; long to dump worthless data in
+ABSOLUTE NOP_insn = 0			; NOP instruction
+
+; Pointer to message, potentially multi-byte
+ABSOLUTE msg_buf = 0
+
+; Pointer to holding area for reselection information
+ABSOLUTE reselected_identify = 0
+ABSOLUTE reselected_tag = 0
+
+; Request sense command pointer, it's a 6 byte command, should
+; be constant for all commands since we always want 16 bytes of 
+; sense and we don't need to change any fields as we did under 
+; SCSI-I when we actually cared about the LUN field.
+;EXTERNAL NCR53c7xx_sense		; Request sense command
+
+#if (CHIP != 700) && (CHIP != 70066)
+; dsa_schedule  
+; PURPOSE : after a DISCONNECT message has been received, and pointers
+;	saved, insert the current DSA structure at the head of the 
+; 	disconnected queue and fall through to the scheduler.
+;
+; CALLS : OK
+;
+; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
+;	of disconnected commands
+;
+; MODIFIES : SCRATCH, reconnect_dsa_head
+; 
+; EXITS : always passes control to schedule
+
+ENTRY dsa_schedule
+dsa_schedule:
+#ifdef DEBUG
+    INT int_debug_dsa_schedule
+#endif
+
+;
+; Calculate the address of the next pointer within the DSA 
+; structure of the command that is currently disconnecting
+;
+#if (CHIP == 710)
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_next TO SCRATCH0
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+
+; Point the next field of this DSA structure at the current disconnected 
+; list
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
+    DMODE_MEMORY_TO_MEMORY
+dsa_schedule_insert:
+    MOVE MEMORY 4, reconnect_dsa_head, 0 
+
+; And update the head pointer.
+#if (CHIP == 710)
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
+    DMODE_MEMORY_TO_MEMORY
+/* Temporarily, see what happens. */
+#ifndef ORIGINAL
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+#endif
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+    WAIT DISCONNECT
+#ifdef EVENTS
+    INT int_EVENT_DISCONNECT;
+#endif
+#ifdef DEBUG
+    INT int_debug_disconnected
+#endif
+    JUMP schedule
+#endif 
+
+;
+; select
+;
+; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
+;	On success, the current DSA structure is removed from the issue 
+;	queue.  Usually, this is entered as a fall-through from schedule,
+;	although the contingent allegiance handling code will write
+;	the select entry address to the DSP to restart a command as a 
+;	REQUEST SENSE.  A message is sent (usually IDENTIFY, although
+;	additional SDTR or WDTR messages may be sent).  COMMAND OUT
+;	is handled.
+;
+; INPUTS : DSA - SCSI command, issue_dsa_head
+;
+; CALLS : NOT OK
+;
+; MODIFIES : SCRATCH, issue_dsa_head
+;
+; EXITS : on reselection or selection, go to select_failed
+;	otherwise, RETURN so control is passed back to 
+;	dsa_begin.
+;
+
+ENTRY select
+select:
+
+#ifdef EVENTS
+    INT int_EVENT_BEFORE_SELECT
+#endif
+
+#ifdef DEBUG
+    INT int_debug_scheduled
+#endif
+    CLEAR TARGET
+
+; XXX
+;
+; In effect, SELECTION operations are backgrounded, with execution
+; continuing until code which waits for REQ or a fatal interrupt is 
+; encountered.
+;
+; So, for more performance, we could overlap the code which removes 
+; the command from the NCRs issue queue with the selection, but 
+; at this point I don't want to deal with the error recovery.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+#if (CHIP == 710)
+    ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+    MOVE CTEST7 & 0xff TO CTEST7
+#else
+    MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+    SELECT ATN FROM dsa_select, select_failed
+    JUMP select_msgout, WHEN MSG_OUT
+ENTRY select_msgout
+select_msgout:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    MOVE FROM dsa_msgout, WHEN MSG_OUT
+#else
+ENTRY select_msgout
+    SELECT ATN 0, select_failed
+select_msgout:
+    MOVE 0, 0, WHEN MSGOUT
+#endif
+
+#ifdef EVENTS
+   INT int_EVENT_SELECT
+#endif
+   RETURN
+
+; 
+; select_done
+; 
+; PURPOSE: continue on to normal data transfer; called as the exit 
+;	point from dsa_begin.
+;
+; INPUTS: dsa
+;
+; CALLS: OK
+;
+;
+
+select_done:
+#if (CHIP == 710)
+; NOTE DSA is corrupt when we arrive here!
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+#ifdef DEBUG
+ENTRY select_check_dsa
+select_check_dsa:
+    INT int_debug_check_dsa
+#endif
+
+; After a successful selection, we should get either a CMD phase or 
+; some transfer request negotiation message.
+
+    JUMP cmdout, WHEN CMD
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN 
+
+select_msg_in:
+    CALL msg_in, WHEN MSG_IN
+    JUMP select_msg_in, WHEN MSG_IN
+
+cmdout:
+    INT int_err_unexpected_phase, WHEN NOT CMD
+#if (CHIP == 700)
+    INT int_norm_selected
+#endif
+ENTRY cmdout_cmdout
+cmdout_cmdout:
+#if (CHIP != 700) && (CHIP != 70066)
+    MOVE FROM dsa_cmdout, WHEN CMD
+#else
+    MOVE 0, 0, WHEN CMD
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+;
+; data_transfer  
+; other_out
+; other_in
+; other_transfer
+;
+; PURPOSE : handle the main data transfer for a SCSI command in 
+;	several parts.  In the first part, data_transfer, DATA_IN
+;	and DATA_OUT phases are allowed, with the user provided
+;	code (usually dynamically generated based on the scatter/gather
+;	list associated with a SCSI command) called to handle these 
+;	phases.
+;
+;	After control has passed to one of the user provided 
+;	DATA_IN or DATA_OUT routines, back calls are made to 
+;	other_transfer_in or other_transfer_out to handle non-DATA IN
+;	and DATA OUT phases respectively, with the state of the active
+;	data pointer being preserved in TEMP.
+;
+;	On completion, the user code passes control to other_transfer
+;	which causes DATA_IN and DATA_OUT to result in unexpected_phase
+;	interrupts so that data overruns may be trapped.
+;
+; INPUTS : DSA - SCSI command
+;
+; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
+;	other_transfer
+;
+; MODIFIES : SCRATCH
+;
+; EXITS : if STATUS IN is detected, signifying command completion,
+;	the NCR jumps to command_complete.  If MSG IN occurs, a 
+;	CALL is made to msg_in.  Otherwise, other_transfer runs in 
+;	an infinite loop.
+;	
+
+ENTRY data_transfer
+data_transfer:
+    JUMP cmdout_cmdout, WHEN CMD
+    CALL msg_in, WHEN MSG_IN
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    JUMP do_dataout, WHEN DATA_OUT
+    JUMP do_datain, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP data_transfer
+ENTRY end_data_transfer
+end_data_transfer:
+
+;
+; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain 
+; should be fixed up whenever the nexus changes so it can point to the 
+; correct routine for that command.
+;
+
+#if (CHIP != 700) && (CHIP != 70066)
+; Nasty jump to dsa->dataout
+do_dataout:
+#if (CHIP == 710)
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_dataout TO SCRATCH0	
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
+    DMODE_MEMORY_TO_MEMORY
+dataout_to_jump:
+    MOVE MEMORY 4, 0, dataout_jump + 4 
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+dataout_jump:
+    JUMP 0
+
+; Nasty jump to dsa->dsain
+do_datain:
+#if (CHIP == 710)
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+#else
+    CALL dsa_to_scratch
+#endif
+    MOVE SCRATCH0 + dsa_datain TO SCRATCH0	
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
+    DMODE_MEMORY_TO_MEMORY
+ENTRY datain_to_jump
+datain_to_jump:
+    MOVE MEMORY 4, 0, datain_jump + 4
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef DEBUG
+    INT int_debug_datain
+#endif
+datain_jump:
+    JUMP 0
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+
+; Note that other_out and other_in loop until a non-data phase
+; is discovered, so we only execute return statements when we
+; can go on to the next data phase block move statement.
+
+ENTRY other_out
+other_out:
+#if 0
+    INT 0x03ffdead
+#endif
+    INT int_err_unexpected_phase, WHEN CMD
+    JUMP msg_in_restart, WHEN MSG_IN 
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP other_out, WHEN NOT DATA_OUT
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user dataout code.
+#endif
+    RETURN
+
+ENTRY other_in
+other_in:
+#if 0
+    INT 0x03ffdead
+#endif
+    INT int_err_unexpected_phase, WHEN CMD
+    JUMP msg_in_restart, WHEN MSG_IN 
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+    JUMP command_complete, WHEN STATUS
+    JUMP other_in, WHEN NOT DATA_IN
+#if (CHIP == 710)
+; TEMP should be OK, as we got here from a call in the user datain code.
+#endif
+    RETURN
+
+
+ENTRY other_transfer
+other_transfer:
+    INT int_err_unexpected_phase, WHEN CMD
+    CALL msg_in, WHEN MSG_IN
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+    INT int_err_unexpected_phase, WHEN DATA_IN
+    JUMP command_complete, WHEN STATUS
+    JUMP other_transfer
+
+;
+; msg_in_restart
+; msg_in
+; munge_msg
+;
+; PURPOSE : process messages from a target.  msg_in is called when the 
+;	caller hasn't read the first byte of the message.  munge_message
+;	is called when the caller has read the first byte of the message,
+;	and left it in SFBR.  msg_in_restart is called when the caller 
+;	hasn't read the first byte of the message, and wishes RETURN
+;	to transfer control back to the address of the conditional
+;	CALL instruction rather than to the instruction after it.
+;
+;	Various int_* interrupts are generated when the host system
+;	needs to intervene, as is the case with SDTR, WDTR, and
+;	INITIATE RECOVERY messages.
+;
+;	When the host system handles one of these interrupts,
+;	it can respond by reentering at reject_message, 
+;	which rejects the message and returns control to
+;	the caller of msg_in or munge_msg, accept_message
+;	which clears ACK and returns control, or reply_message
+;	which sends the message pointed to by the DSA 
+;	msgout_other table indirect field.
+;
+;	DISCONNECT messages are handled by moving the command
+;	to the reconnect_dsa_queue.
+#if (CHIP == 710)
+; NOTE: DSA should be valid when we get here - we cannot save both it
+;	and TEMP in this routine.
+#endif
+;
+; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
+;	only)
+;
+; CALLS : NO.  The TEMP register isn't backed up to allow nested calls.
+;
+; MODIFIES : SCRATCH, DSA on DISCONNECT
+;
+; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
+;	and normal return from message handlers running under
+;	Linux, control is returned to the caller.  Receipt
+;	of DISCONNECT messages pass control to dsa_schedule.
+;
+ENTRY msg_in_restart
+msg_in_restart:
+; XXX - hackish
+;
+; Since it's easier to debug changes to the statically 
+; compiled code, rather than the dynamically generated 
+; stuff, such as
+;
+; 	MOVE x, y, WHEN data_phase
+; 	CALL other_z, WHEN NOT data_phase
+; 	MOVE x, y, WHEN data_phase
+;
+; I'd like to have certain routines (notably the message handler)
+; restart on the conditional call rather than the next instruction.
+;
+; So, subtract 8 from the return address
+
+    MOVE TEMP0 + 0xf8 TO TEMP0
+    MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
+    MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
+    MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
+
+ENTRY msg_in
+msg_in:
+    MOVE 1, msg_buf, WHEN MSG_IN
+
+munge_msg:
+    JUMP munge_extended, IF 0x01		; EXTENDED MESSAGE
+    JUMP munge_2, IF 0x20, AND MASK 0xdf	; two byte message
+;
+; XXX - I've seen a handful of broken SCSI devices which fail to issue
+; 	a SAVE POINTERS message before disconnecting in the middle of 
+; 	a transfer, assuming that the DATA POINTER will be implicitly 
+; 	restored.  
+;
+; Historically, I've often done an implicit save when the DISCONNECT
+; message is processed.  We may want to consider having the option of 
+; doing that here. 
+;
+    JUMP munge_save_data_pointer, IF 0x02	; SAVE DATA POINTER
+    JUMP munge_restore_pointers, IF 0x03	; RESTORE POINTERS 
+    JUMP munge_disconnect, IF 0x04		; DISCONNECT
+    INT int_msg_1, IF 0x07			; MESSAGE REJECT
+    INT int_msg_1, IF 0x0f			; INITIATE RECOVERY
+#ifdef EVENTS 
+    INT int_EVENT_SELECT_FAILED 
+#endif
+    JUMP reject_message
+
+munge_2:
+    JUMP reject_message
+;
+; The SCSI standard allows targets to recover from transient 
+; error conditions by backing up the data pointer with a 
+; RESTORE POINTERS message.  
+;	
+; So, we must save and restore the _residual_ code as well as 
+; the current instruction pointer.  Because of this messiness,
+; it is simpler to put dynamic code in the dsa for this and to
+; just do a simple jump down there. 
+;
+
+munge_save_data_pointer:
+#if (CHIP == 710)
+    ; We have something in TEMP here, so first we must save that
+    MOVE TEMP0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE TEMP1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE TEMP2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE TEMP3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, jump_temp + 4
+    ; Now restore DSA
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+    MOVE DSA0 + dsa_save_data_pointer TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY 
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH3
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
+    DMODE_MEMORY_TO_MEMORY
+jump_dsa_save:
+    JUMP 0
+
+munge_restore_pointers:
+#if (CHIP == 710)
+    ; The code at dsa_restore_pointers will RETURN, but we don't care
+    ; about TEMP here, as it will overwrite it anyway.
+#endif
+    MOVE DSA0 + dsa_restore_pointers TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+    MOVE SFBR TO SCRATCH3
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
+    DMODE_MEMORY_TO_MEMORY
+jump_dsa_restore:
+    JUMP 0
+
+
+munge_disconnect:
+#ifdef DEBUG
+    INT int_debug_disconnect_msg
+#endif
+
+/* 
+ * Before, we overlapped processing with waiting for disconnect, but
+ * debugging was beginning to appear messy.  Temporarily move things
+ * to just before the WAIT DISCONNECT.
+ */
+ 
+#ifdef ORIGINAL
+#if (CHIP == 710)
+; Following clears Unexpected Disconnect bit.  What do we do?
+#else
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+#endif
+
+#if (CHIP != 700) && (CHIP != 70066)
+    JUMP dsa_schedule
+#else
+    WAIT DISCONNECT
+    INT int_norm_disconnected
+#endif
+
+munge_extended:
+    CLEAR ACK
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN
+    MOVE 1, msg_buf + 1, WHEN MSG_IN
+    JUMP munge_extended_2, IF 0x02
+    JUMP munge_extended_3, IF 0x03 
+    JUMP reject_message
+
+munge_extended_2:
+    CLEAR ACK
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+    JUMP reject_message, IF NOT 0x02	; Must be WDTR
+    CLEAR ACK
+    MOVE 1, msg_buf + 3, WHEN MSG_IN
+    INT int_msg_wdtr
+
+munge_extended_3:
+    CLEAR ACK
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+    JUMP reject_message, IF NOT 0x01	; Must be SDTR
+    CLEAR ACK
+    MOVE 2, msg_buf + 3, WHEN MSG_IN
+    INT int_msg_sdtr
+
+ENTRY reject_message
+reject_message:
+    SET ATN
+    CLEAR ACK
+    MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
+    RETURN
+
+ENTRY accept_message
+accept_message:
+    CLEAR ATN
+    CLEAR ACK
+    RETURN
+
+ENTRY respond_message
+respond_message:
+    SET ATN
+    CLEAR ACK
+    MOVE FROM dsa_msgout_other, WHEN MSG_OUT
+    RETURN
+
+;
+; command_complete
+;
+; PURPOSE : handle command termination when STATUS IN is detected by reading
+;	a status byte followed by a command termination message. 
+;
+;	Normal termination results in an INTFLY instruction, and 
+;	the host system can pick out which command terminated by 
+;	examining the MESSAGE and STATUS buffers of all currently 
+;	executing commands;
+;
+;	Abnormal (CHECK_CONDITION) termination results in an
+;	int_err_check_condition interrupt so that a REQUEST SENSE
+;	command can be issued out-of-order so that no other command
+;	clears the contingent allegiance condition.
+;	
+;
+; INPUTS : DSA - command	
+;
+; CALLS : OK
+;
+; EXITS : On successful termination, control is passed to schedule.
+;	On abnormal termination, the user will usually modify the 
+;	DSA fields and corresponding buffers and return control
+;	to select.
+;
+
+ENTRY command_complete
+command_complete:
+    MOVE FROM dsa_status, WHEN STATUS
+#if (CHIP != 700) && (CHIP != 70066)
+    MOVE SFBR TO SCRATCH0		; Save status
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+ENTRY command_complete_msgin
+command_complete_msgin:
+    MOVE FROM dsa_msgin, WHEN MSG_IN
+; Indicate that we should be expecting a disconnect
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#else
+    ; Above code cleared the Unexpected Disconnect bit, what do we do?
+#endif
+    CLEAR ACK
+#if (CHIP != 700) && (CHIP != 70066)
+    WAIT DISCONNECT
+
+;
+; The SCSI specification states that when a UNIT ATTENTION condition
+; is pending, as indicated by a CHECK CONDITION status message,
+; the target shall revert to asynchronous transfers.  Since
+; synchronous transfers parameters are maintained on a per INITIATOR/TARGET 
+; basis, and returning control to our scheduler could work on a command
+; running on another lun on that target using the old parameters, we must
+; interrupt the host processor to get them changed, or change them ourselves.
+;
+; Once SCSI-II tagged queueing is implemented, things will be even more
+; hairy, since contingent allegiance conditions exist on a per-target/lun
+; basis, and issuing a new command with a different tag would clear it.
+; In these cases, we must interrupt the host processor to get a request 
+; added to the HEAD of the queue with the request sense command, or we
+; must automatically issue the request sense command.
+
+#if 0
+    MOVE SCRATCH0 TO SFBR			
+    JUMP command_failed, IF 0x02
+#endif
+#if (CHIP == 710)
+#if defined(MVME16x_INTFLY)
+; For MVME16x (ie CHIP=710) we will force an INTFLY by triggering a software
+; interrupt (SW7).  We can use SCRATCH, as we are about to jump to
+; schedule, which corrupts it anyway.  Will probably remove this later,
+; but want to check performance effects first.
+
+#define INTFLY_ADDR     0xfff40070
+
+    MOVE 0 TO SCRATCH0
+    MOVE 0x80 TO SCRATCH1
+    MOVE 0 TO SCRATCH2
+    MOVE 0 TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, INTFLY_ADDR
+#else
+    INT int_norm_emulateintfly
+#endif
+#else
+    INTFLY
+#endif
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+#ifdef EVENTS
+    INT int_EVENT_COMPLETE
+#endif
+#if (CHIP != 700) && (CHIP != 70066)
+    JUMP schedule
+command_failed:
+    INT int_err_check_condition
+#else
+    INT int_norm_command_complete
+#endif
+
+;
+; wait_reselect
+;
+; PURPOSE : This is essentially the idle routine, where control lands
+;	when there are no new processes to schedule.  wait_reselect
+;	waits for reselection, selection, and new commands.
+;
+;	When a successful reselection occurs, with the aid 
+;	of fixed up code in each DSA, wait_reselect walks the 
+;	reconnect_dsa_queue, asking each dsa if the target ID
+;	and LUN match its.
+;
+;	If a match is found, a call is made back to reselected_ok,
+;	which through the miracles of self modifying code, extracts
+;	the found DSA from the reconnect_dsa_queue and then 
+;	returns control to the DSAs thread of execution.
+;
+; INPUTS : NONE
+;
+; CALLS : OK
+;
+; MODIFIES : DSA,
+;
+; EXITS : On successful reselection, control is returned to the 
+;	DSA which called reselected_ok.  If the WAIT RESELECT
+;	was interrupted by a new commands arrival signaled by 
+;	SIG_P, control is passed to schedule.  If the NCR is 
+;	selected, the host system is interrupted with an 
+;	int_err_selected which is usually responded to by
+;	setting DSP to the target_abort address.
+
+ENTRY wait_reselect
+wait_reselect:
+#ifdef EVENTS
+    int int_EVENT_IDLE
+#endif
+#ifdef DEBUG
+    int int_debug_idle
+#endif
+    WAIT RESELECT wait_reselect_failed
+
+reselected:
+#ifdef EVENTS
+    int int_EVENT_RESELECT
+#endif
+    CLEAR TARGET
+    DMODE_MEMORY_TO_MEMORY
+    ; Read all data needed to reestablish the nexus - 
+    MOVE 1, reselected_identify, WHEN MSG_IN
+    ; We used to CLEAR ACK here.
+#if (CHIP != 700) && (CHIP != 70066)
+#ifdef DEBUG
+    int int_debug_reselected
+#endif
+
+    ; Point DSA at the current head of the disconnected queue.
+    DMODE_MEMORY_TO_NCR
+    MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
+    DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+    MOVE MEMORY 4, addr_scratch, saved_dsa
+#else
+    CALL scratch_to_dsa
+#endif
+
+    ; Fix the update-next pointer so that the reconnect_dsa_head
+    ; pointer is the one that will be updated if this DSA is a hit 
+    ; and we remove it from the queue.
+
+    MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+
+ENTRY reselected_check_next
+reselected_check_next:
+#ifdef DEBUG
+    INT int_debug_reselect_check
+#endif
+    ; Check for a NULL pointer.
+    MOVE DSA0 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA1 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA2 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    MOVE DSA3 TO SFBR
+    JUMP reselected_not_end, IF NOT 0
+    INT int_err_unexpected_reselect
+
+reselected_not_end:
+    ;
+    ; XXX the ALU is only eight bits wide, and the assembler
+    ; wont do the dirt work for us.  As long as dsa_check_reselect
+    ; is negative, we need to sign extend with 1 bits to the full
+    ; 32 bit width of the address.
+    ;
+    ; A potential work around would be to have a known alignment 
+    ; of the DSA structure such that the base address plus 
+    ; dsa_check_reselect doesn't require carrying from bytes 
+    ; higher than the LSB.
+    ;
+
+    MOVE DSA0 TO SFBR
+    MOVE SFBR + dsa_check_reselect TO SCRATCH0
+    MOVE DSA1 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
+    MOVE DSA2 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
+    MOVE DSA3 TO SFBR
+    MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
+
+    DMODE_NCR_TO_MEMORY
+    MOVE MEMORY 4, addr_scratch, reselected_check + 4
+    DMODE_MEMORY_TO_MEMORY
+#if (CHIP == 710)
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+#endif
+reselected_check:
+    JUMP 0
+
+
+;
+;
+#if (CHIP == 710)
+; We have problems here - the memory move corrupts TEMP and DSA.  This
+; routine is called from DSA code, and patched from many places.  Scratch
+; is probably free when it is called.
+; We have to:
+;   copy temp to scratch, one byte at a time
+;   write scratch to patch a jump in place of the return
+;   do the move memory
+;   jump to the patched in return address
+; DSA is corrupt when we get here, and can be left corrupt
+
+ENTRY reselected_ok
+reselected_ok:
+    MOVE TEMP0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE TEMP1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE TEMP2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE TEMP3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
+reselected_ok_patch:
+    MOVE MEMORY 4, 0, 0
+reselected_ok_jump:
+    JUMP 0
+#else
+ENTRY reselected_ok
+reselected_ok:
+reselected_ok_patch:
+    MOVE MEMORY 4, 0, 0				; Patched : first word
+						; 	is address of 
+						;       successful dsa_next
+						; Second word is last 
+						;	unsuccessful dsa_next,
+						;	starting with 
+						;       dsa_reconnect_head
+    ; We used to CLEAR ACK here.
+#ifdef DEBUG
+    INT int_debug_reselected_ok
+#endif
+#ifdef DEBUG
+    INT int_debug_check_dsa
+#endif
+    RETURN					; Return control to where
+#endif
+#else
+    INT int_norm_reselected
+#endif /* (CHIP != 700) && (CHIP != 70066) */
+
+selected:
+    INT int_err_selected;
+
+;
+; A select or reselect failure can be caused by one of two conditions : 
+; 1.  SIG_P was set.  This will be the case if the user has written
+;	a new value to a previously NULL head of the issue queue.
+;
+; 2.  The NCR53c810 was selected or reselected by another device.
+;
+; 3.  The bus was already busy since we were selected or reselected
+;	before starting the command.
+
+wait_reselect_failed:
+#ifdef EVENTS 
+	INT int_EVENT_RESELECT_FAILED
+#endif
+; Check selected bit.  
+#if (CHIP == 710)
+    ; Must work out how to tell if we are selected....
+#else
+    MOVE SIST0 & 0x20 TO SFBR
+    JUMP selected, IF 0x20
+#endif
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+    JUMP schedule, IF 0x40
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+    MOVE ISTAT & 0x08 TO SFBR
+    JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+    JUMP schedule
+#else
+    INT int_debug_panic
+#endif
+
+
+select_failed:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+#ifdef EVENTS
+  int int_EVENT_SELECT_FAILED
+#endif
+; Otherwise, mask the selected and reselected bits off SIST0
+#if (CHIP ==710)
+    ; Let's assume we don't get selected for now
+    MOVE SSTAT0 & 0x10 TO SFBR
+#else
+    MOVE SIST0 & 0x30 TO SFBR
+    JUMP selected, IF 0x20
+#endif
+    JUMP reselected, IF 0x10 
+; If SIGP is set, the user just gave us another command, and
+; we should restart or return to the scheduler.
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+    JUMP select, IF 0x40
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+; FIXME: is this really necessary? 
+    MOVE ISTAT & 0x08 TO SFBR
+    JUMP reselected, IF 0x08
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+#if 0
+    JUMP schedule
+#else
+    INT int_debug_panic
+#endif
+
+;
+; test_1
+; test_2
+;
+; PURPOSE : run some verification tests on the NCR.  test_1
+;	copies test_src to test_dest and interrupts the host
+;	processor, testing for cache coherency and interrupt
+; 	problems in the processes.
+;
+;	test_2 runs a command with offsets relative to the 
+;	DSA on entry, and is useful for miscellaneous experimentation.
+;
+
+; Verify that interrupts are working correctly and that we don't 
+; have a cache invalidation problem.
+
+ABSOLUTE test_src = 0, test_dest = 0
+ENTRY test_1
+test_1:
+    MOVE MEMORY 4, test_src, test_dest
+    INT int_test_1
+
+;
+; Run arbitrary commands, with test code establishing a DSA
+;
+ 
+ENTRY test_2
+test_2:
+    CLEAR TARGET
+#if (CHIP == 710)
+    ; Enable selection timer
+#ifdef NO_SELECTION_TIMEOUT
+    MOVE CTEST7 & 0xff TO CTEST7
+#else
+    MOVE CTEST7 & 0xef TO CTEST7
+#endif
+#endif
+    SELECT ATN FROM 0, test_2_fail
+    JUMP test_2_msgout, WHEN MSG_OUT
+ENTRY test_2_msgout
+test_2_msgout:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    MOVE FROM 8, WHEN MSG_OUT
+    MOVE FROM 16, WHEN CMD 
+    MOVE FROM 24, WHEN DATA_IN
+    MOVE FROM 32, WHEN STATUS
+    MOVE FROM 40, WHEN MSG_IN
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    CLEAR ACK
+    WAIT DISCONNECT
+test_2_fail:
+#if (CHIP == 710)
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+#endif
+    INT int_test_2
+
+ENTRY debug_break
+debug_break:
+    INT int_debug_break
+
+;
+; initiator_abort
+; target_abort
+;
+; PURPOSE : Abort the currently established nexus from with initiator
+;	or target mode.
+;
+;  
+
+ENTRY target_abort
+target_abort:
+    SET TARGET
+    DISCONNECT
+    CLEAR TARGET
+    JUMP schedule
+    
+ENTRY initiator_abort
+initiator_abort:
+    SET ATN
+;
+; The SCSI-I specification says that targets may go into MSG out at 
+; their leisure upon receipt of the ATN single.  On all versions of the 
+; specification, we can't change phases until REQ transitions true->false, 
+; so we need to sink/source one byte of data to allow the transition.
+;
+; For the sake of safety, we'll only source one byte of data in all 
+; cases, but to accommodate the SCSI-I dain bramage, we'll sink an  
+; arbitrary number of bytes.
+    JUMP spew_cmd, WHEN CMD
+    JUMP eat_msgin, WHEN MSG_IN
+    JUMP eat_datain, WHEN DATA_IN
+    JUMP eat_status, WHEN STATUS
+    JUMP spew_dataout, WHEN DATA_OUT
+    JUMP sated
+spew_cmd:
+    MOVE 1, NCR53c7xx_zero, WHEN CMD
+    JUMP sated
+eat_msgin:
+    MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
+    JUMP eat_msgin, WHEN MSG_IN
+    JUMP sated
+eat_status:
+    MOVE 1, NCR53c7xx_sink, WHEN STATUS
+    JUMP eat_status, WHEN STATUS
+    JUMP sated
+eat_datain:
+    MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
+    JUMP eat_datain, WHEN DATA_IN
+    JUMP sated
+spew_dataout:
+    MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
+sated:
+#if (CHIP != 710)
+    MOVE SCNTL2 & 0x7f TO SCNTL2
+#endif
+    MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
+    WAIT DISCONNECT
+    INT int_norm_aborted
+
+#if (CHIP != 710)
+;
+; dsa_to_scratch
+; scratch_to_dsa
+;
+; PURPOSE :
+; 	The NCR chips cannot do a move memory instruction with the DSA register 
+; 	as the source or destination.  So, we provide a couple of subroutines
+; 	that let us switch between the DSA register and scratch register.
+;
+; 	Memory moves to/from the DSPS  register also don't work, but we 
+; 	don't use them.
+;
+;
+
+ 
+dsa_to_scratch:
+    MOVE DSA0 TO SFBR
+    MOVE SFBR TO SCRATCH0
+    MOVE DSA1 TO SFBR
+    MOVE SFBR TO SCRATCH1
+    MOVE DSA2 TO SFBR
+    MOVE SFBR TO SCRATCH2
+    MOVE DSA3 TO SFBR
+    MOVE SFBR TO SCRATCH3
+    RETURN
+
+scratch_to_dsa:
+    MOVE SCRATCH0 TO SFBR
+    MOVE SFBR TO DSA0
+    MOVE SCRATCH1 TO SFBR
+    MOVE SFBR TO DSA1
+    MOVE SCRATCH2 TO SFBR
+    MOVE SFBR TO DSA2
+    MOVE SCRATCH3 TO SFBR
+    MOVE SFBR TO DSA3
+    RETURN
+#endif
+ 
+#if (CHIP == 710)
+; Little patched jump, used to overcome problems with TEMP getting
+; corrupted on memory moves.
+
+jump_temp:
+    JUMP 0
+#endif
diff --git a/drivers/scsi/53c7xx_d.h_shipped b/drivers/scsi/53c7xx_d.h_shipped
new file mode 100644
index 0000000..21d31b0
--- /dev/null
+++ b/drivers/scsi/53c7xx_d.h_shipped
@@ -0,0 +1,2874 @@
+/* DO NOT EDIT - Generated automatically by script_asm.pl */
+static u32 SCRIPT[] = {
+/*
+
+
+
+
+
+; 53c710 driver.  Modified from Drew Eckhardts driver
+; for 53c810 by Richard Hirst [richard@sleepie.demon.co.uk]
+;
+; I have left the script for the 53c8xx family in here, as it is likely
+; to be useful to see what I changed when bug hunting.
+
+; NCR 53c810 driver, main script
+; Sponsored by 
+;	iX Multiuser Multitasking Magazine
+;	hm@ix.de
+;
+; Copyright 1993, 1994, 1995 Drew Eckhardt
+;      Visionary Computing 
+;      (Unix and Linux consulting and custom programming)
+;      drew@PoohSticks.ORG
+;      +1 (303) 786-7975
+;
+; TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+;
+; PRE-ALPHA
+;
+; For more information, please consult 
+;
+; NCR 53C810
+; PCI-SCSI I/O Processor
+; Data Manual
+;
+; NCR 53C710 
+; SCSI I/O Processor
+; Programmers Guide
+;
+; NCR Microelectronics
+; 1635 Aeroplaza Drive
+; Colorado Springs, CO 80916
+; 1+ (719) 578-3400
+;
+; Toll free literature number
+; +1 (800) 334-5454
+;
+; IMPORTANT : This code is self modifying due to the limitations of 
+;	the NCR53c7,8xx series chips.  Persons debugging this code with
+;	the remote debugger should take this into account, and NOT set
+;	breakpoints in modified instructions.
+;
+; Design:
+; The NCR53c7,8xx family of SCSI chips are busmasters with an onboard 
+; microcontroller using a simple instruction set.   
+;
+; So, to minimize the effects of interrupt latency, and to maximize 
+; throughput, this driver offloads the practical maximum amount 
+; of processing to the SCSI chip while still maintaining a common
+; structure.
+;
+; Where tradeoffs were needed between efficiency on the older
+; chips and the newer NCR53c800 series, the NCR53c800 series 
+; was chosen.
+;
+; While the NCR53c700 and NCR53c700-66 lacked the facilities to fully
+; automate SCSI transfers without host processor intervention, this 
+; isn't the case with the NCR53c710 and newer chips which allow 
+;
+; - reads and writes to the internal registers from within the SCSI
+; 	scripts, allowing the SCSI SCRIPTS(tm) code to save processor
+; 	state so that multiple threads of execution are possible, and also
+; 	provide an ALU for loop control, etc.
+; 
+; - table indirect addressing for some instructions. This allows 
+;	pointers to be located relative to the DSA ((Data Structure
+;	Address) register.
+;
+; These features make it possible to implement a mailbox style interface,
+; where the same piece of code is run to handle I/O for multiple threads
+; at once minimizing our need to relocate code.  Since the NCR53c700/
+; NCR53c800 series have a unique combination of features, making a 
+; a standard ingoing/outgoing mailbox system, costly, I've modified it.
+;
+; - Mailboxes are a mixture of code and data.  This lets us greatly
+; 	simplify the NCR53c810 code and do things that would otherwise
+;	not be possible.
+;
+; The saved data pointer is now implemented as follows :
+;
+; 	Control flow has been architected such that if control reaches
+;	munge_save_data_pointer, on a restore pointers message or 
+;	reconnection, a jump to the address formerly in the TEMP register
+;	will allow the SCSI command to resume execution.
+;
+
+;
+; Note : the DSA structures must be aligned on 32 bit boundaries,
+; since the source and destination of MOVE MEMORY instructions 
+; must share the same alignment and this is the alignment of the
+; NCR registers.
+;
+
+; For some systems (MVME166, for example) dmode is always the same, so don't
+; waste time writing it
+
+
+
+
+
+
+
+
+
+
+
+ABSOLUTE dsa_temp_lun = 0		; Patch to lun for current dsa
+ABSOLUTE dsa_temp_next = 0		; Patch to dsa next for current dsa
+ABSOLUTE dsa_temp_addr_next = 0		; Patch to address of dsa next address 
+					; 	for current dsa
+ABSOLUTE dsa_temp_sync = 0		; Patch to address of per-target
+					;	sync routine
+ABSOLUTE dsa_sscf_710 = 0		; Patch to address of per-target
+					;	sscf value (53c710)
+ABSOLUTE dsa_temp_target = 0		; Patch to id for current dsa
+ABSOLUTE dsa_temp_addr_saved_pointer = 0; Patch to address of per-command
+					; 	saved data pointer
+ABSOLUTE dsa_temp_addr_residual = 0	; Patch to address of per-command
+					;	current residual code
+ABSOLUTE dsa_temp_addr_saved_residual = 0; Patch to address of per-command
+					; saved residual code
+ABSOLUTE dsa_temp_addr_new_value = 0	; Address of value for JUMP operand
+ABSOLUTE dsa_temp_addr_array_value = 0 	; Address to copy to
+ABSOLUTE dsa_temp_addr_dsa_value = 0	; Address of this DSA value
+
+;
+; Once a device has initiated reselection, we need to compare it 
+; against the singly linked list of commands which have disconnected
+; and are pending reselection.  These commands are maintained in 
+; an unordered singly linked list of DSA structures, through the
+; DSA pointers at their 'centers' headed by the reconnect_dsa_head
+; pointer.
+; 
+; To avoid complications in removing commands from the list,
+; I minimize the amount of expensive (at eight operations per
+; addition @ 500-600ns each) pointer operations which must
+; be done in the NCR driver by precomputing them on the 
+; host processor during dsa structure generation.
+;
+; The fixed-up per DSA code knows how to recognize the nexus
+; associated with the corresponding SCSI command, and modifies
+; the source and destination pointers for the MOVE MEMORY 
+; instruction which is executed when reselected_ok is called
+; to remove the command from the list.  Similarly, DSA is 
+; loaded with the address of the next DSA structure and
+; reselected_check_next is called if a failure occurs.
+;
+; Perhaps more concisely, the net effect of the mess is 
+;
+; for (dsa = reconnect_dsa_head, dest = &reconnect_dsa_head, 
+;     src = NULL; dsa; dest = &dsa->next, dsa = dsa->next) {
+; 	src = &dsa->next;
+; 	if (target_id == dsa->id && target_lun == dsa->lun) {
+; 		*dest = *src;
+; 		break;
+;         }	
+; }
+;
+; if (!dsa)
+;           error (int_err_unexpected_reselect);
+; else  
+;     longjmp (dsa->jump_resume, 0);
+;
+; 	
+
+
+; Define DSA structure used for mailboxes
+ENTRY dsa_code_template
+dsa_code_template:
+ENTRY dsa_code_begin
+dsa_code_begin:
+; RGH: Don't care about TEMP and DSA here
+	
+	MOVE MEMORY 4, dsa_temp_addr_dsa_value, addr_scratch
+
+at 0x00000000 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	
+
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+
+at 0x00000003 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	; We are about to go and select the device, so must set SSCF bits
+	MOVE MEMORY 4, dsa_sscf_710, addr_scratch
+
+at 0x00000006 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+	MOVE SCRATCH3 TO SFBR
+
+at 0x00000009 : */	0x72370000,0x00000000,
+/*
+
+
+
+	MOVE SFBR TO SBCL
+
+at 0x0000000b : */	0x6a0b0000,0x00000000,
+/*
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x0000000d : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+	CALL select
+
+at 0x00000010 : */	0x88080000,0x000001f8,
+/*
+; Handle the phase mismatch which may have resulted from the 
+; MOVE FROM dsa_msgout if we returned here.  The CLEAR ATN 
+; may or may not be necessary, and we should update script_asm.pl
+; to handle multiple pieces.
+    CLEAR ATN
+
+at 0x00000012 : */	0x60000008,0x00000000,
+/*
+    CLEAR ACK
+
+at 0x00000014 : */	0x60000040,0x00000000,
+/*
+
+; Replace second operand with address of JUMP instruction dest operand
+; in schedule table for this DSA.  Becomes dsa_jump_dest in 53c7,8xx.c.
+ENTRY dsa_code_fix_jump
+dsa_code_fix_jump:
+	MOVE MEMORY 4, NOP_insn, 0
+
+at 0x00000016 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	JUMP select_done
+
+at 0x00000019 : */	0x80080000,0x00000230,
+/*
+
+; wrong_dsa loads the DSA register with the value of the dsa_next
+; field.
+;
+wrong_dsa:
+
+;                NOTE DSA is corrupt when we arrive here!
+
+;		Patch the MOVE MEMORY INSTRUCTION such that 
+;		the destination address is the address of the OLD 
+;		next pointer.
+;
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 8
+
+at 0x0000001b : */	0xc0000004,0x00000000,0x000007ec,
+/*
+	
+;
+; 	Move the _contents_ of the next pointer into the DSA register as 
+;	the next I_T_L or I_T_L_Q tupple to check against the established
+;	nexus.
+;
+	MOVE MEMORY 4, dsa_temp_next, addr_scratch
+
+at 0x0000001e : */	0xc0000004,0x00000000,0x00000000,
+/*
+	
+
+	MOVE MEMORY 4, addr_scratch, saved_dsa
+
+at 0x00000021 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x00000024 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+	JUMP reselected_check_next
+
+at 0x00000027 : */	0x80080000,0x000006f0,
+/*
+
+ABSOLUTE dsa_save_data_pointer = 0
+ENTRY dsa_code_save_data_pointer
+dsa_code_save_data_pointer:
+
+	; When we get here, TEMP has been saved in jump_temp+4, DSA is corrupt
+	; We MUST return with DSA correct
+    	MOVE MEMORY 4, jump_temp+4, dsa_temp_addr_saved_pointer
+
+at 0x00000029 : */	0xc0000004,0x000009c8,0x00000000,
+/*
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_residual, dsa_temp_addr_saved_residual
+
+at 0x0000002c : */	0xc0000018,0x00000000,0x00000000,
+/*
+        CLEAR ACK
+
+at 0x0000002f : */	0x60000040,0x00000000,
+/*
+
+
+
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x00000031 : */	0xc0000004,0x00000000,0x00000000,
+/*
+	JUMP jump_temp
+
+at 0x00000034 : */	0x80080000,0x000009c4,
+/*
+
+ABSOLUTE dsa_restore_pointers = 0
+ENTRY dsa_code_restore_pointers
+dsa_code_restore_pointers:
+
+	; TEMP and DSA are corrupt when we get here, but who cares!
+    	MOVE MEMORY 4, dsa_temp_addr_saved_pointer, jump_temp + 4
+
+at 0x00000036 : */	0xc0000004,0x00000000,0x000009c8,
+/*
+; HARD CODED : 24 bytes needs to agree with 53c7,8xx.h
+    	MOVE MEMORY 24, dsa_temp_addr_saved_residual, dsa_temp_addr_residual
+
+at 0x00000039 : */	0xc0000018,0x00000000,0x00000000,
+/*
+        CLEAR ACK
+
+at 0x0000003c : */	0x60000040,0x00000000,
+/*
+	; Restore DSA, note we don't care about TEMP
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x0000003e : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+	JUMP jump_temp
+
+at 0x00000041 : */	0x80080000,0x000009c4,
+/*
+
+
+ABSOLUTE dsa_check_reselect = 0
+; dsa_check_reselect determines whether or not the current target and
+; lun match the current DSA
+ENTRY dsa_code_check_reselect
+dsa_code_check_reselect:
+
+	
+	
+	MOVE LCRC TO SFBR		; LCRC has our ID and his ID bits set
+
+at 0x00000043 : */	0x72230000,0x00000000,
+/*
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_target, AND MASK 0x80
+
+at 0x00000045 : */	0x80848000,0x00ffff50,
+/*
+
+
+
+
+
+;
+; Hack - move to scratch first, since SFBR is not writeable
+; 	via the CPU and hence a MOVE MEMORY instruction.
+;
+	
+	MOVE MEMORY 1, reselected_identify, addr_scratch
+
+at 0x00000047 : */	0xc0000001,0x00000000,0x00000000,
+/*
+	
+
+	; BIG ENDIAN ON MVME16x
+	MOVE SCRATCH3 TO SFBR
+
+at 0x0000004a : */	0x72370000,0x00000000,
+/*
+
+
+
+; FIXME : we need to accommodate bit fielded and binary here for '7xx/'8xx chips
+; Are you sure about that?  richard@sleepie.demon.co.uk
+	JUMP REL (wrong_dsa), IF NOT dsa_temp_lun, AND MASK 0xf8
+
+at 0x0000004c : */	0x8084f800,0x00ffff34,
+/*
+;		Patch the MOVE MEMORY INSTRUCTION such that
+;		the source address is the address of this dsa's
+;		next pointer.
+	MOVE MEMORY 4, dsa_temp_addr_next, reselected_ok_patch + 4
+
+at 0x0000004e : */	0xc0000004,0x00000000,0x000007e8,
+/*
+	CALL reselected_ok
+
+at 0x00000051 : */	0x88080000,0x00000798,
+/*
+
+;	Restore DSA following memory moves in reselected_ok
+;	dsa_temp_sync doesn't really care about DSA, but it has an
+;	optional debug INT so a valid DSA is a good idea.
+	MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x00000053 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+	CALL dsa_temp_sync	
+
+at 0x00000056 : */	0x88080000,0x00000000,
+/*
+; Release ACK on the IDENTIFY message _after_ we've set the synchronous 
+; transfer parameters! 
+	CLEAR ACK
+
+at 0x00000058 : */	0x60000040,0x00000000,
+/*
+; Implicitly restore pointers on reselection, so a RETURN
+; will transfer control back to the right spot.
+    	CALL REL (dsa_code_restore_pointers)
+
+at 0x0000005a : */	0x88880000,0x00ffff68,
+/*
+    	RETURN
+
+at 0x0000005c : */	0x90080000,0x00000000,
+/*
+ENTRY dsa_zero
+dsa_zero:
+ENTRY dsa_code_template_end
+dsa_code_template_end:
+
+; Perform sanity check for dsa_fields_start == dsa_code_template_end - 
+; dsa_zero, puke.
+
+ABSOLUTE dsa_fields_start =  0	; Sanity marker
+				; 	pad 48 bytes (fix this RSN)
+ABSOLUTE dsa_next = 48		; len 4 Next DSA
+ 				; del 4 Previous DSA address
+ABSOLUTE dsa_cmnd = 56		; len 4 Scsi_Cmnd * for this thread.
+ABSOLUTE dsa_select = 60	; len 4 Device ID, Period, Offset for 
+			 	;	table indirect select
+ABSOLUTE dsa_msgout = 64	; len 8 table indirect move parameter for 
+				;       select message
+ABSOLUTE dsa_cmdout = 72	; len 8 table indirect move parameter for 
+				;	command
+ABSOLUTE dsa_dataout = 80	; len 4 code pointer for dataout
+ABSOLUTE dsa_datain = 84	; len 4 code pointer for datain
+ABSOLUTE dsa_msgin = 88		; len 8 table indirect move for msgin
+ABSOLUTE dsa_status = 96 	; len 8 table indirect move for status byte
+ABSOLUTE dsa_msgout_other = 104	; len 8 table indirect for normal message out
+				; (Synchronous transfer negotiation, etc).
+ABSOLUTE dsa_end = 112
+
+ABSOLUTE schedule = 0 		; Array of JUMP dsa_begin or JUMP (next),
+				; terminated by a call to JUMP wait_reselect
+
+; Linked lists of DSA structures
+ABSOLUTE reconnect_dsa_head = 0	; Link list of DSAs which can reconnect
+ABSOLUTE addr_reconnect_dsa_head = 0 ; Address of variable containing
+				; address of reconnect_dsa_head
+
+; These select the source and destination of a MOVE MEMORY instruction
+ABSOLUTE dmode_memory_to_memory = 0x0
+ABSOLUTE dmode_memory_to_ncr = 0x0
+ABSOLUTE dmode_ncr_to_memory = 0x0
+
+ABSOLUTE addr_scratch = 0x0
+ABSOLUTE addr_temp = 0x0
+
+ABSOLUTE saved_dsa = 0x0
+ABSOLUTE emulfly = 0x0
+ABSOLUTE addr_dsa = 0x0
+
+
+
+; Interrupts - 
+; MSB indicates type
+; 0	handle error condition
+; 1 	handle message 
+; 2 	handle normal condition
+; 3	debugging interrupt
+; 4 	testing interrupt 
+; Next byte indicates specific error
+
+; XXX not yet implemented, I'm not sure if I want to - 
+; Next byte indicates the routine the error occurred in
+; The LSB indicates the specific place the error occurred
+ 
+ABSOLUTE int_err_unexpected_phase = 0x00000000	; Unexpected phase encountered
+ABSOLUTE int_err_selected = 0x00010000		; SELECTED (nee RESELECTED)
+ABSOLUTE int_err_unexpected_reselect = 0x00020000 
+ABSOLUTE int_err_check_condition = 0x00030000	
+ABSOLUTE int_err_no_phase = 0x00040000
+ABSOLUTE int_msg_wdtr = 0x01000000		; WDTR message received
+ABSOLUTE int_msg_sdtr = 0x01010000		; SDTR received
+ABSOLUTE int_msg_1 = 0x01020000			; single byte special message
+						; received
+
+ABSOLUTE int_norm_select_complete = 0x02000000	; Select complete, reprogram
+						; registers.
+ABSOLUTE int_norm_reselect_complete = 0x02010000	; Nexus established
+ABSOLUTE int_norm_command_complete = 0x02020000 ; Command complete
+ABSOLUTE int_norm_disconnected = 0x02030000	; Disconnected 
+ABSOLUTE int_norm_aborted =0x02040000		; Aborted *dsa
+ABSOLUTE int_norm_reset = 0x02050000		; Generated BUS reset.
+ABSOLUTE int_norm_emulateintfly = 0x02060000	; 53C710 Emulated intfly
+ABSOLUTE int_debug_break = 0x03000000		; Break point
+
+ABSOLUTE int_debug_panic = 0x030b0000		; Panic driver
+
+
+ABSOLUTE int_test_1 = 0x04000000		; Test 1 complete
+ABSOLUTE int_test_2 = 0x04010000		; Test 2 complete
+ABSOLUTE int_test_3 = 0x04020000		; Test 3 complete
+
+
+; These should start with 0x05000000, with low bits incrementing for 
+; each one.
+
+
+						
+ABSOLUTE NCR53c7xx_msg_abort = 0	; Pointer to abort message
+ABSOLUTE NCR53c7xx_msg_reject = 0       ; Pointer to reject message
+ABSOLUTE NCR53c7xx_zero	= 0		; long with zero in it, use for source
+ABSOLUTE NCR53c7xx_sink = 0		; long to dump worthless data in
+ABSOLUTE NOP_insn = 0			; NOP instruction
+
+; Pointer to message, potentially multi-byte
+ABSOLUTE msg_buf = 0
+
+; Pointer to holding area for reselection information
+ABSOLUTE reselected_identify = 0
+ABSOLUTE reselected_tag = 0
+
+; Request sense command pointer, it's a 6 byte command, should
+; be constant for all commands since we always want 16 bytes of 
+; sense and we don't need to change any fields as we did under 
+; SCSI-I when we actually cared about the LUN field.
+;EXTERNAL NCR53c7xx_sense		; Request sense command
+
+
+; dsa_schedule  
+; PURPOSE : after a DISCONNECT message has been received, and pointers
+;	saved, insert the current DSA structure at the head of the 
+; 	disconnected queue and fall through to the scheduler.
+;
+; CALLS : OK
+;
+; INPUTS : dsa - current DSA structure, reconnect_dsa_head - list
+;	of disconnected commands
+;
+; MODIFIES : SCRATCH, reconnect_dsa_head
+; 
+; EXITS : always passes control to schedule
+
+ENTRY dsa_schedule
+dsa_schedule:
+
+
+
+
+;
+; Calculate the address of the next pointer within the DSA 
+; structure of the command that is currently disconnecting
+;
+
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+
+at 0x0000005e : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+    MOVE SCRATCH0 + dsa_next TO SCRATCH0
+
+at 0x00000061 : */	0x7e343000,0x00000000,
+/*
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY
+
+at 0x00000063 : */	0x7f350000,0x00000000,
+/*
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY
+
+at 0x00000065 : */	0x7f360000,0x00000000,
+/*
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY
+
+at 0x00000067 : */	0x7f370000,0x00000000,
+/*
+
+; Point the next field of this DSA structure at the current disconnected 
+; list
+    
+    MOVE MEMORY 4, addr_scratch, dsa_schedule_insert + 8
+
+at 0x00000069 : */	0xc0000004,0x00000000,0x000001b8,
+/*
+    
+dsa_schedule_insert:
+    MOVE MEMORY 4, reconnect_dsa_head, 0 
+
+at 0x0000006c : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+; And update the head pointer.
+
+    ; Read what should be the current DSA from memory - actual DSA
+    ; register is probably corrupt
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+
+at 0x0000006f : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+    
+    MOVE MEMORY 4, addr_scratch, reconnect_dsa_head
+
+at 0x00000072 : */	0xc0000004,0x00000000,0x00000000,
+/*
+    
+
+
+
+
+
+    CLEAR ACK
+
+at 0x00000075 : */	0x60000040,0x00000000,
+/*
+
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x00000077 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+    WAIT DISCONNECT
+
+at 0x0000007a : */	0x48000000,0x00000000,
+/*
+
+
+
+
+
+
+    JUMP schedule
+
+at 0x0000007c : */	0x80080000,0x00000000,
+/*
+
+
+;
+; select
+;
+; PURPOSE : establish a nexus for the SCSI command referenced by DSA.
+;	On success, the current DSA structure is removed from the issue 
+;	queue.  Usually, this is entered as a fall-through from schedule,
+;	although the contingent allegiance handling code will write
+;	the select entry address to the DSP to restart a command as a 
+;	REQUEST SENSE.  A message is sent (usually IDENTIFY, although
+;	additional SDTR or WDTR messages may be sent).  COMMAND OUT
+;	is handled.
+;
+; INPUTS : DSA - SCSI command, issue_dsa_head
+;
+; CALLS : NOT OK
+;
+; MODIFIES : SCRATCH, issue_dsa_head
+;
+; EXITS : on reselection or selection, go to select_failed
+;	otherwise, RETURN so control is passed back to 
+;	dsa_begin.
+;
+
+ENTRY select
+select:
+
+
+
+
+
+
+
+
+    CLEAR TARGET
+
+at 0x0000007e : */	0x60000200,0x00000000,
+/*
+
+; XXX
+;
+; In effect, SELECTION operations are backgrounded, with execution
+; continuing until code which waits for REQ or a fatal interrupt is 
+; encountered.
+;
+; So, for more performance, we could overlap the code which removes 
+; the command from the NCRs issue queue with the selection, but 
+; at this point I don't want to deal with the error recovery.
+;
+
+
+
+    ; Enable selection timer
+
+
+
+    MOVE CTEST7 & 0xef TO CTEST7
+
+at 0x00000080 : */	0x7c1bef00,0x00000000,
+/*
+
+
+    SELECT ATN FROM dsa_select, select_failed
+
+at 0x00000082 : */	0x4300003c,0x00000828,
+/*
+    JUMP select_msgout, WHEN MSG_OUT
+
+at 0x00000084 : */	0x860b0000,0x00000218,
+/*
+ENTRY select_msgout
+select_msgout:
+
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000086 : */	0x7a1b1000,0x00000000,
+/*
+
+    MOVE FROM dsa_msgout, WHEN MSG_OUT
+
+at 0x00000088 : */	0x1e000000,0x00000040,
+/*
+
+
+
+
+
+
+
+
+
+
+   RETURN
+
+at 0x0000008a : */	0x90080000,0x00000000,
+/*
+
+; 
+; select_done
+; 
+; PURPOSE: continue on to normal data transfer; called as the exit 
+;	point from dsa_begin.
+;
+; INPUTS: dsa
+;
+; CALLS: OK
+;
+;
+
+select_done:
+
+; NOTE DSA is corrupt when we arrive here!
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x0000008c : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+
+
+
+
+
+; After a successful selection, we should get either a CMD phase or 
+; some transfer request negotiation message.
+
+    JUMP cmdout, WHEN CMD
+
+at 0x0000008f : */	0x820b0000,0x0000025c,
+/*
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN 
+
+at 0x00000091 : */	0x9f030000,0x00000000,
+/*
+
+select_msg_in:
+    CALL msg_in, WHEN MSG_IN
+
+at 0x00000093 : */	0x8f0b0000,0x0000041c,
+/*
+    JUMP select_msg_in, WHEN MSG_IN
+
+at 0x00000095 : */	0x870b0000,0x0000024c,
+/*
+
+cmdout:
+    INT int_err_unexpected_phase, WHEN NOT CMD
+
+at 0x00000097 : */	0x9a030000,0x00000000,
+/*
+
+
+
+ENTRY cmdout_cmdout
+cmdout_cmdout:
+
+    MOVE FROM dsa_cmdout, WHEN CMD
+
+at 0x00000099 : */	0x1a000000,0x00000048,
+/*
+
+
+
+
+;
+; data_transfer  
+; other_out
+; other_in
+; other_transfer
+;
+; PURPOSE : handle the main data transfer for a SCSI command in 
+;	several parts.  In the first part, data_transfer, DATA_IN
+;	and DATA_OUT phases are allowed, with the user provided
+;	code (usually dynamically generated based on the scatter/gather
+;	list associated with a SCSI command) called to handle these 
+;	phases.
+;
+;	After control has passed to one of the user provided 
+;	DATA_IN or DATA_OUT routines, back calls are made to 
+;	other_transfer_in or other_transfer_out to handle non-DATA IN
+;	and DATA OUT phases respectively, with the state of the active
+;	data pointer being preserved in TEMP.
+;
+;	On completion, the user code passes control to other_transfer
+;	which causes DATA_IN and DATA_OUT to result in unexpected_phase
+;	interrupts so that data overruns may be trapped.
+;
+; INPUTS : DSA - SCSI command
+;
+; CALLS : OK in data_transfer_start, not ok in other_out and other_in, ok in
+;	other_transfer
+;
+; MODIFIES : SCRATCH
+;
+; EXITS : if STATUS IN is detected, signifying command completion,
+;	the NCR jumps to command_complete.  If MSG IN occurs, a 
+;	CALL is made to msg_in.  Otherwise, other_transfer runs in 
+;	an infinite loop.
+;	
+
+ENTRY data_transfer
+data_transfer:
+    JUMP cmdout_cmdout, WHEN CMD
+
+at 0x0000009b : */	0x820b0000,0x00000264,
+/*
+    CALL msg_in, WHEN MSG_IN
+
+at 0x0000009d : */	0x8f0b0000,0x0000041c,
+/*
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+
+at 0x0000009f : */	0x9e0b0000,0x00000000,
+/*
+    JUMP do_dataout, WHEN DATA_OUT
+
+at 0x000000a1 : */	0x800b0000,0x000002a4,
+/*
+    JUMP do_datain, WHEN DATA_IN
+
+at 0x000000a3 : */	0x810b0000,0x000002fc,
+/*
+    JUMP command_complete, WHEN STATUS
+
+at 0x000000a5 : */	0x830b0000,0x0000065c,
+/*
+    JUMP data_transfer
+
+at 0x000000a7 : */	0x80080000,0x0000026c,
+/*
+ENTRY end_data_transfer
+end_data_transfer:
+
+;
+; FIXME: On NCR53c700 and NCR53c700-66 chips, do_dataout/do_datain 
+; should be fixed up whenever the nexus changes so it can point to the 
+; correct routine for that command.
+;
+
+
+; Nasty jump to dsa->dataout
+do_dataout:
+
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+
+at 0x000000a9 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+    MOVE SCRATCH0 + dsa_dataout TO SCRATCH0	
+
+at 0x000000ac : */	0x7e345000,0x00000000,
+/*
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+
+at 0x000000ae : */	0x7f350000,0x00000000,
+/*
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+
+at 0x000000b0 : */	0x7f360000,0x00000000,
+/*
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+
+at 0x000000b2 : */	0x7f370000,0x00000000,
+/*
+    
+    MOVE MEMORY 4, addr_scratch, dataout_to_jump + 4
+
+at 0x000000b4 : */	0xc0000004,0x00000000,0x000002e0,
+/*
+    
+dataout_to_jump:
+    MOVE MEMORY 4, 0, dataout_jump + 4 
+
+at 0x000000b7 : */	0xc0000004,0x00000000,0x000002f8,
+/*
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x000000ba : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+dataout_jump:
+    JUMP 0
+
+at 0x000000bd : */	0x80080000,0x00000000,
+/*
+
+; Nasty jump to dsa->dsain
+do_datain:
+
+    MOVE MEMORY 4, saved_dsa, addr_scratch
+
+at 0x000000bf : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+    MOVE SCRATCH0 + dsa_datain TO SCRATCH0	
+
+at 0x000000c2 : */	0x7e345400,0x00000000,
+/*
+    MOVE SCRATCH1 + 0 TO SCRATCH1 WITH CARRY 
+
+at 0x000000c4 : */	0x7f350000,0x00000000,
+/*
+    MOVE SCRATCH2 + 0 TO SCRATCH2 WITH CARRY 
+
+at 0x000000c6 : */	0x7f360000,0x00000000,
+/*
+    MOVE SCRATCH3 + 0 TO SCRATCH3 WITH CARRY 
+
+at 0x000000c8 : */	0x7f370000,0x00000000,
+/*
+    
+    MOVE MEMORY 4, addr_scratch, datain_to_jump + 4
+
+at 0x000000ca : */	0xc0000004,0x00000000,0x00000338,
+/*
+    
+ENTRY datain_to_jump
+datain_to_jump:
+    MOVE MEMORY 4, 0, datain_jump + 4
+
+at 0x000000cd : */	0xc0000004,0x00000000,0x00000350,
+/*
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x000000d0 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+
+datain_jump:
+    JUMP 0
+
+at 0x000000d3 : */	0x80080000,0x00000000,
+/*
+
+
+
+; Note that other_out and other_in loop until a non-data phase
+; is discovered, so we only execute return statements when we
+; can go on to the next data phase block move statement.
+
+ENTRY other_out
+other_out:
+
+
+
+    INT int_err_unexpected_phase, WHEN CMD
+
+at 0x000000d5 : */	0x9a0b0000,0x00000000,
+/*
+    JUMP msg_in_restart, WHEN MSG_IN 
+
+at 0x000000d7 : */	0x870b0000,0x000003fc,
+/*
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+
+at 0x000000d9 : */	0x9e0b0000,0x00000000,
+/*
+    INT int_err_unexpected_phase, WHEN DATA_IN
+
+at 0x000000db : */	0x990b0000,0x00000000,
+/*
+    JUMP command_complete, WHEN STATUS
+
+at 0x000000dd : */	0x830b0000,0x0000065c,
+/*
+    JUMP other_out, WHEN NOT DATA_OUT
+
+at 0x000000df : */	0x80030000,0x00000354,
+/*
+
+; TEMP should be OK, as we got here from a call in the user dataout code.
+
+    RETURN
+
+at 0x000000e1 : */	0x90080000,0x00000000,
+/*
+
+ENTRY other_in
+other_in:
+
+
+
+    INT int_err_unexpected_phase, WHEN CMD
+
+at 0x000000e3 : */	0x9a0b0000,0x00000000,
+/*
+    JUMP msg_in_restart, WHEN MSG_IN 
+
+at 0x000000e5 : */	0x870b0000,0x000003fc,
+/*
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+
+at 0x000000e7 : */	0x9e0b0000,0x00000000,
+/*
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+
+at 0x000000e9 : */	0x980b0000,0x00000000,
+/*
+    JUMP command_complete, WHEN STATUS
+
+at 0x000000eb : */	0x830b0000,0x0000065c,
+/*
+    JUMP other_in, WHEN NOT DATA_IN
+
+at 0x000000ed : */	0x81030000,0x0000038c,
+/*
+
+; TEMP should be OK, as we got here from a call in the user datain code.
+
+    RETURN
+
+at 0x000000ef : */	0x90080000,0x00000000,
+/*
+
+
+ENTRY other_transfer
+other_transfer:
+    INT int_err_unexpected_phase, WHEN CMD
+
+at 0x000000f1 : */	0x9a0b0000,0x00000000,
+/*
+    CALL msg_in, WHEN MSG_IN
+
+at 0x000000f3 : */	0x8f0b0000,0x0000041c,
+/*
+    INT int_err_unexpected_phase, WHEN MSG_OUT
+
+at 0x000000f5 : */	0x9e0b0000,0x00000000,
+/*
+    INT int_err_unexpected_phase, WHEN DATA_OUT
+
+at 0x000000f7 : */	0x980b0000,0x00000000,
+/*
+    INT int_err_unexpected_phase, WHEN DATA_IN
+
+at 0x000000f9 : */	0x990b0000,0x00000000,
+/*
+    JUMP command_complete, WHEN STATUS
+
+at 0x000000fb : */	0x830b0000,0x0000065c,
+/*
+    JUMP other_transfer
+
+at 0x000000fd : */	0x80080000,0x000003c4,
+/*
+
+;
+; msg_in_restart
+; msg_in
+; munge_msg
+;
+; PURPOSE : process messages from a target.  msg_in is called when the 
+;	caller hasn't read the first byte of the message.  munge_message
+;	is called when the caller has read the first byte of the message,
+;	and left it in SFBR.  msg_in_restart is called when the caller 
+;	hasn't read the first byte of the message, and wishes RETURN
+;	to transfer control back to the address of the conditional
+;	CALL instruction rather than to the instruction after it.
+;
+;	Various int_* interrupts are generated when the host system
+;	needs to intervene, as is the case with SDTR, WDTR, and
+;	INITIATE RECOVERY messages.
+;
+;	When the host system handles one of these interrupts,
+;	it can respond by reentering at reject_message, 
+;	which rejects the message and returns control to
+;	the caller of msg_in or munge_msg, accept_message
+;	which clears ACK and returns control, or reply_message
+;	which sends the message pointed to by the DSA 
+;	msgout_other table indirect field.
+;
+;	DISCONNECT messages are handled by moving the command
+;	to the reconnect_dsa_queue.
+
+; NOTE: DSA should be valid when we get here - we cannot save both it
+;	and TEMP in this routine.
+
+;
+; INPUTS : DSA - SCSI COMMAND, SFBR - first byte of message (munge_msg
+;	only)
+;
+; CALLS : NO.  The TEMP register isn't backed up to allow nested calls.
+;
+; MODIFIES : SCRATCH, DSA on DISCONNECT
+;
+; EXITS : On receipt of SAVE DATA POINTER, RESTORE POINTERS,
+;	and normal return from message handlers running under
+;	Linux, control is returned to the caller.  Receipt
+;	of DISCONNECT messages pass control to dsa_schedule.
+;
+ENTRY msg_in_restart
+msg_in_restart:
+; XXX - hackish
+;
+; Since it's easier to debug changes to the statically 
+; compiled code, rather than the dynamically generated 
+; stuff, such as
+;
+; 	MOVE x, y, WHEN data_phase
+; 	CALL other_z, WHEN NOT data_phase
+; 	MOVE x, y, WHEN data_phase
+;
+; I'd like to have certain routines (notably the message handler)
+; restart on the conditional call rather than the next instruction.
+;
+; So, subtract 8 from the return address
+
+    MOVE TEMP0 + 0xf8 TO TEMP0
+
+at 0x000000ff : */	0x7e1cf800,0x00000000,
+/*
+    MOVE TEMP1 + 0xff TO TEMP1 WITH CARRY
+
+at 0x00000101 : */	0x7f1dff00,0x00000000,
+/*
+    MOVE TEMP2 + 0xff TO TEMP2 WITH CARRY
+
+at 0x00000103 : */	0x7f1eff00,0x00000000,
+/*
+    MOVE TEMP3 + 0xff TO TEMP3 WITH CARRY
+
+at 0x00000105 : */	0x7f1fff00,0x00000000,
+/*
+
+ENTRY msg_in
+msg_in:
+    MOVE 1, msg_buf, WHEN MSG_IN
+
+at 0x00000107 : */	0x0f000001,0x00000000,
+/*
+
+munge_msg:
+    JUMP munge_extended, IF 0x01		; EXTENDED MESSAGE
+
+at 0x00000109 : */	0x800c0001,0x00000574,
+/*
+    JUMP munge_2, IF 0x20, AND MASK 0xdf	; two byte message
+
+at 0x0000010b : */	0x800cdf20,0x00000464,
+/*
+;
+; XXX - I've seen a handful of broken SCSI devices which fail to issue
+; 	a SAVE POINTERS message before disconnecting in the middle of 
+; 	a transfer, assuming that the DATA POINTER will be implicitly 
+; 	restored.  
+;
+; Historically, I've often done an implicit save when the DISCONNECT
+; message is processed.  We may want to consider having the option of 
+; doing that here. 
+;
+    JUMP munge_save_data_pointer, IF 0x02	; SAVE DATA POINTER
+
+at 0x0000010d : */	0x800c0002,0x0000046c,
+/*
+    JUMP munge_restore_pointers, IF 0x03	; RESTORE POINTERS 
+
+at 0x0000010f : */	0x800c0003,0x00000518,
+/*
+    JUMP munge_disconnect, IF 0x04		; DISCONNECT
+
+at 0x00000111 : */	0x800c0004,0x0000056c,
+/*
+    INT int_msg_1, IF 0x07			; MESSAGE REJECT
+
+at 0x00000113 : */	0x980c0007,0x01020000,
+/*
+    INT int_msg_1, IF 0x0f			; INITIATE RECOVERY
+
+at 0x00000115 : */	0x980c000f,0x01020000,
+/*
+
+
+
+    JUMP reject_message
+
+at 0x00000117 : */	0x80080000,0x00000604,
+/*
+
+munge_2:
+    JUMP reject_message
+
+at 0x00000119 : */	0x80080000,0x00000604,
+/*
+;
+; The SCSI standard allows targets to recover from transient 
+; error conditions by backing up the data pointer with a 
+; RESTORE POINTERS message.  
+;	
+; So, we must save and restore the _residual_ code as well as 
+; the current instruction pointer.  Because of this messiness,
+; it is simpler to put dynamic code in the dsa for this and to
+; just do a simple jump down there. 
+;
+
+munge_save_data_pointer:
+
+    ; We have something in TEMP here, so first we must save that
+    MOVE TEMP0 TO SFBR
+
+at 0x0000011b : */	0x721c0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH0
+
+at 0x0000011d : */	0x6a340000,0x00000000,
+/*
+    MOVE TEMP1 TO SFBR
+
+at 0x0000011f : */	0x721d0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH1
+
+at 0x00000121 : */	0x6a350000,0x00000000,
+/*
+    MOVE TEMP2 TO SFBR
+
+at 0x00000123 : */	0x721e0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH2
+
+at 0x00000125 : */	0x6a360000,0x00000000,
+/*
+    MOVE TEMP3 TO SFBR
+
+at 0x00000127 : */	0x721f0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH3
+
+at 0x00000129 : */	0x6a370000,0x00000000,
+/*
+    MOVE MEMORY 4, addr_scratch, jump_temp + 4
+
+at 0x0000012b : */	0xc0000004,0x00000000,0x000009c8,
+/*
+    ; Now restore DSA
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x0000012e : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+    MOVE DSA0 + dsa_save_data_pointer TO SFBR
+
+at 0x00000131 : */	0x76100000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH0
+
+at 0x00000133 : */	0x6a340000,0x00000000,
+/*
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+
+at 0x00000135 : */	0x7711ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH1
+
+at 0x00000137 : */	0x6a350000,0x00000000,
+/*
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY 
+
+at 0x00000139 : */	0x7712ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH2
+
+at 0x0000013b : */	0x6a360000,0x00000000,
+/*
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+
+at 0x0000013d : */	0x7713ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH3
+
+at 0x0000013f : */	0x6a370000,0x00000000,
+/*
+
+    
+    MOVE MEMORY 4, addr_scratch, jump_dsa_save + 4
+
+at 0x00000141 : */	0xc0000004,0x00000000,0x00000514,
+/*
+    
+jump_dsa_save:
+    JUMP 0
+
+at 0x00000144 : */	0x80080000,0x00000000,
+/*
+
+munge_restore_pointers:
+
+    ; The code at dsa_restore_pointers will RETURN, but we don't care
+    ; about TEMP here, as it will overwrite it anyway.
+
+    MOVE DSA0 + dsa_restore_pointers TO SFBR
+
+at 0x00000146 : */	0x76100000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH0
+
+at 0x00000148 : */	0x6a340000,0x00000000,
+/*
+    MOVE DSA1 + 0xff TO SFBR WITH CARRY
+
+at 0x0000014a : */	0x7711ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH1
+
+at 0x0000014c : */	0x6a350000,0x00000000,
+/*
+    MOVE DSA2 + 0xff TO SFBR WITH CARRY
+
+at 0x0000014e : */	0x7712ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH2
+
+at 0x00000150 : */	0x6a360000,0x00000000,
+/*
+    MOVE DSA3 + 0xff TO SFBR WITH CARRY
+
+at 0x00000152 : */	0x7713ff00,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH3
+
+at 0x00000154 : */	0x6a370000,0x00000000,
+/*
+
+    
+    MOVE MEMORY 4, addr_scratch, jump_dsa_restore + 4
+
+at 0x00000156 : */	0xc0000004,0x00000000,0x00000568,
+/*
+    
+jump_dsa_restore:
+    JUMP 0
+
+at 0x00000159 : */	0x80080000,0x00000000,
+/*
+
+
+munge_disconnect:
+
+
+
+
+
+
+
+
+
+ 
+
+
+
+
+
+
+
+
+
+
+    JUMP dsa_schedule
+
+at 0x0000015b : */	0x80080000,0x00000178,
+/*
+
+
+
+
+
+munge_extended:
+    CLEAR ACK
+
+at 0x0000015d : */	0x60000040,0x00000000,
+/*
+    INT int_err_unexpected_phase, WHEN NOT MSG_IN
+
+at 0x0000015f : */	0x9f030000,0x00000000,
+/*
+    MOVE 1, msg_buf + 1, WHEN MSG_IN
+
+at 0x00000161 : */	0x0f000001,0x00000001,
+/*
+    JUMP munge_extended_2, IF 0x02
+
+at 0x00000163 : */	0x800c0002,0x000005a4,
+/*
+    JUMP munge_extended_3, IF 0x03 
+
+at 0x00000165 : */	0x800c0003,0x000005d4,
+/*
+    JUMP reject_message
+
+at 0x00000167 : */	0x80080000,0x00000604,
+/*
+
+munge_extended_2:
+    CLEAR ACK
+
+at 0x00000169 : */	0x60000040,0x00000000,
+/*
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+
+at 0x0000016b : */	0x0f000001,0x00000002,
+/*
+    JUMP reject_message, IF NOT 0x02	; Must be WDTR
+
+at 0x0000016d : */	0x80040002,0x00000604,
+/*
+    CLEAR ACK
+
+at 0x0000016f : */	0x60000040,0x00000000,
+/*
+    MOVE 1, msg_buf + 3, WHEN MSG_IN
+
+at 0x00000171 : */	0x0f000001,0x00000003,
+/*
+    INT int_msg_wdtr
+
+at 0x00000173 : */	0x98080000,0x01000000,
+/*
+
+munge_extended_3:
+    CLEAR ACK
+
+at 0x00000175 : */	0x60000040,0x00000000,
+/*
+    MOVE 1, msg_buf + 2, WHEN MSG_IN
+
+at 0x00000177 : */	0x0f000001,0x00000002,
+/*
+    JUMP reject_message, IF NOT 0x01	; Must be SDTR
+
+at 0x00000179 : */	0x80040001,0x00000604,
+/*
+    CLEAR ACK
+
+at 0x0000017b : */	0x60000040,0x00000000,
+/*
+    MOVE 2, msg_buf + 3, WHEN MSG_IN
+
+at 0x0000017d : */	0x0f000002,0x00000003,
+/*
+    INT int_msg_sdtr
+
+at 0x0000017f : */	0x98080000,0x01010000,
+/*
+
+ENTRY reject_message
+reject_message:
+    SET ATN
+
+at 0x00000181 : */	0x58000008,0x00000000,
+/*
+    CLEAR ACK
+
+at 0x00000183 : */	0x60000040,0x00000000,
+/*
+    MOVE 1, NCR53c7xx_msg_reject, WHEN MSG_OUT
+
+at 0x00000185 : */	0x0e000001,0x00000000,
+/*
+    RETURN
+
+at 0x00000187 : */	0x90080000,0x00000000,
+/*
+
+ENTRY accept_message
+accept_message:
+    CLEAR ATN
+
+at 0x00000189 : */	0x60000008,0x00000000,
+/*
+    CLEAR ACK
+
+at 0x0000018b : */	0x60000040,0x00000000,
+/*
+    RETURN
+
+at 0x0000018d : */	0x90080000,0x00000000,
+/*
+
+ENTRY respond_message
+respond_message:
+    SET ATN
+
+at 0x0000018f : */	0x58000008,0x00000000,
+/*
+    CLEAR ACK
+
+at 0x00000191 : */	0x60000040,0x00000000,
+/*
+    MOVE FROM dsa_msgout_other, WHEN MSG_OUT
+
+at 0x00000193 : */	0x1e000000,0x00000068,
+/*
+    RETURN
+
+at 0x00000195 : */	0x90080000,0x00000000,
+/*
+
+;
+; command_complete
+;
+; PURPOSE : handle command termination when STATUS IN is detected by reading
+;	a status byte followed by a command termination message. 
+;
+;	Normal termination results in an INTFLY instruction, and 
+;	the host system can pick out which command terminated by 
+;	examining the MESSAGE and STATUS buffers of all currently 
+;	executing commands;
+;
+;	Abnormal (CHECK_CONDITION) termination results in an
+;	int_err_check_condition interrupt so that a REQUEST SENSE
+;	command can be issued out-of-order so that no other command
+;	clears the contingent allegiance condition.
+;	
+;
+; INPUTS : DSA - command	
+;
+; CALLS : OK
+;
+; EXITS : On successful termination, control is passed to schedule.
+;	On abnormal termination, the user will usually modify the 
+;	DSA fields and corresponding buffers and return control
+;	to select.
+;
+
+ENTRY command_complete
+command_complete:
+    MOVE FROM dsa_status, WHEN STATUS
+
+at 0x00000197 : */	0x1b000000,0x00000060,
+/*
+
+    MOVE SFBR TO SCRATCH0		; Save status
+
+at 0x00000199 : */	0x6a340000,0x00000000,
+/*
+
+ENTRY command_complete_msgin
+command_complete_msgin:
+    MOVE FROM dsa_msgin, WHEN MSG_IN
+
+at 0x0000019b : */	0x1f000000,0x00000058,
+/*
+; Indicate that we should be expecting a disconnect
+
+
+
+    ; Above code cleared the Unexpected Disconnect bit, what do we do?
+
+    CLEAR ACK
+
+at 0x0000019d : */	0x60000040,0x00000000,
+/*
+
+    WAIT DISCONNECT
+
+at 0x0000019f : */	0x48000000,0x00000000,
+/*
+
+;
+; The SCSI specification states that when a UNIT ATTENTION condition
+; is pending, as indicated by a CHECK CONDITION status message,
+; the target shall revert to asynchronous transfers.  Since
+; synchronous transfers parameters are maintained on a per INITIATOR/TARGET 
+; basis, and returning control to our scheduler could work on a command
+; running on another lun on that target using the old parameters, we must
+; interrupt the host processor to get them changed, or change them ourselves.
+;
+; Once SCSI-II tagged queueing is implemented, things will be even more
+; hairy, since contingent allegiance conditions exist on a per-target/lun
+; basis, and issuing a new command with a different tag would clear it.
+; In these cases, we must interrupt the host processor to get a request 
+; added to the HEAD of the queue with the request sense command, or we
+; must automatically issue the request sense command.
+
+
+
+
+
+
+
+    INT int_norm_emulateintfly
+
+at 0x000001a1 : */	0x98080000,0x02060000,
+/*
+
+
+
+
+
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x000001a3 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+
+
+    JUMP schedule
+
+at 0x000001a6 : */	0x80080000,0x00000000,
+/*
+command_failed:
+    INT int_err_check_condition
+
+at 0x000001a8 : */	0x98080000,0x00030000,
+/*
+
+
+
+
+;
+; wait_reselect
+;
+; PURPOSE : This is essentially the idle routine, where control lands
+;	when there are no new processes to schedule.  wait_reselect
+;	waits for reselection, selection, and new commands.
+;
+;	When a successful reselection occurs, with the aid 
+;	of fixed up code in each DSA, wait_reselect walks the 
+;	reconnect_dsa_queue, asking each dsa if the target ID
+;	and LUN match its.
+;
+;	If a match is found, a call is made back to reselected_ok,
+;	which through the miracles of self modifying code, extracts
+;	the found DSA from the reconnect_dsa_queue and then 
+;	returns control to the DSAs thread of execution.
+;
+; INPUTS : NONE
+;
+; CALLS : OK
+;
+; MODIFIES : DSA,
+;
+; EXITS : On successful reselection, control is returned to the 
+;	DSA which called reselected_ok.  If the WAIT RESELECT
+;	was interrupted by a new commands arrival signaled by 
+;	SIG_P, control is passed to schedule.  If the NCR is 
+;	selected, the host system is interrupted with an 
+;	int_err_selected which is usually responded to by
+;	setting DSP to the target_abort address.
+
+ENTRY wait_reselect
+wait_reselect:
+
+
+
+
+
+
+    WAIT RESELECT wait_reselect_failed
+
+at 0x000001aa : */	0x50000000,0x00000800,
+/*
+
+reselected:
+
+
+
+    CLEAR TARGET
+
+at 0x000001ac : */	0x60000200,0x00000000,
+/*
+    
+    ; Read all data needed to reestablish the nexus - 
+    MOVE 1, reselected_identify, WHEN MSG_IN
+
+at 0x000001ae : */	0x0f000001,0x00000000,
+/*
+    ; We used to CLEAR ACK here.
+
+
+
+
+
+    ; Point DSA at the current head of the disconnected queue.
+    
+    MOVE MEMORY 4, reconnect_dsa_head, addr_scratch
+
+at 0x000001b0 : */	0xc0000004,0x00000000,0x00000000,
+/*
+    
+
+    MOVE MEMORY 4, addr_scratch, saved_dsa
+
+at 0x000001b3 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+
+
+    ; Fix the update-next pointer so that the reconnect_dsa_head
+    ; pointer is the one that will be updated if this DSA is a hit 
+    ; and we remove it from the queue.
+
+    MOVE MEMORY 4, addr_reconnect_dsa_head, reselected_ok_patch + 8
+
+at 0x000001b6 : */	0xc0000004,0x00000000,0x000007ec,
+/*
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x000001b9 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+
+ENTRY reselected_check_next
+reselected_check_next:
+
+
+
+    ; Check for a NULL pointer.
+    MOVE DSA0 TO SFBR
+
+at 0x000001bc : */	0x72100000,0x00000000,
+/*
+    JUMP reselected_not_end, IF NOT 0
+
+at 0x000001be : */	0x80040000,0x00000738,
+/*
+    MOVE DSA1 TO SFBR
+
+at 0x000001c0 : */	0x72110000,0x00000000,
+/*
+    JUMP reselected_not_end, IF NOT 0
+
+at 0x000001c2 : */	0x80040000,0x00000738,
+/*
+    MOVE DSA2 TO SFBR
+
+at 0x000001c4 : */	0x72120000,0x00000000,
+/*
+    JUMP reselected_not_end, IF NOT 0
+
+at 0x000001c6 : */	0x80040000,0x00000738,
+/*
+    MOVE DSA3 TO SFBR
+
+at 0x000001c8 : */	0x72130000,0x00000000,
+/*
+    JUMP reselected_not_end, IF NOT 0
+
+at 0x000001ca : */	0x80040000,0x00000738,
+/*
+    INT int_err_unexpected_reselect
+
+at 0x000001cc : */	0x98080000,0x00020000,
+/*
+
+reselected_not_end:
+    ;
+    ; XXX the ALU is only eight bits wide, and the assembler
+    ; wont do the dirt work for us.  As long as dsa_check_reselect
+    ; is negative, we need to sign extend with 1 bits to the full
+    ; 32 bit width of the address.
+    ;
+    ; A potential work around would be to have a known alignment 
+    ; of the DSA structure such that the base address plus 
+    ; dsa_check_reselect doesn't require carrying from bytes 
+    ; higher than the LSB.
+    ;
+
+    MOVE DSA0 TO SFBR
+
+at 0x000001ce : */	0x72100000,0x00000000,
+/*
+    MOVE SFBR + dsa_check_reselect TO SCRATCH0
+
+at 0x000001d0 : */	0x6e340000,0x00000000,
+/*
+    MOVE DSA1 TO SFBR
+
+at 0x000001d2 : */	0x72110000,0x00000000,
+/*
+    MOVE SFBR + 0xff TO SCRATCH1 WITH CARRY
+
+at 0x000001d4 : */	0x6f35ff00,0x00000000,
+/*
+    MOVE DSA2 TO SFBR
+
+at 0x000001d6 : */	0x72120000,0x00000000,
+/*
+    MOVE SFBR + 0xff TO SCRATCH2 WITH CARRY
+
+at 0x000001d8 : */	0x6f36ff00,0x00000000,
+/*
+    MOVE DSA3 TO SFBR
+
+at 0x000001da : */	0x72130000,0x00000000,
+/*
+    MOVE SFBR + 0xff TO SCRATCH3 WITH CARRY
+
+at 0x000001dc : */	0x6f37ff00,0x00000000,
+/*
+
+    
+    MOVE MEMORY 4, addr_scratch, reselected_check + 4
+
+at 0x000001de : */	0xc0000004,0x00000000,0x00000794,
+/*
+    
+
+    ; Time to correct DSA following memory move
+    MOVE MEMORY 4, saved_dsa, addr_dsa
+
+at 0x000001e1 : */	0xc0000004,0x00000000,0x00000000,
+/*
+
+reselected_check:
+    JUMP 0
+
+at 0x000001e4 : */	0x80080000,0x00000000,
+/*
+
+
+;
+;
+
+; We have problems here - the memory move corrupts TEMP and DSA.  This
+; routine is called from DSA code, and patched from many places.  Scratch
+; is probably free when it is called.
+; We have to:
+;   copy temp to scratch, one byte at a time
+;   write scratch to patch a jump in place of the return
+;   do the move memory
+;   jump to the patched in return address
+; DSA is corrupt when we get here, and can be left corrupt
+
+ENTRY reselected_ok
+reselected_ok:
+    MOVE TEMP0 TO SFBR
+
+at 0x000001e6 : */	0x721c0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH0
+
+at 0x000001e8 : */	0x6a340000,0x00000000,
+/*
+    MOVE TEMP1 TO SFBR
+
+at 0x000001ea : */	0x721d0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH1
+
+at 0x000001ec : */	0x6a350000,0x00000000,
+/*
+    MOVE TEMP2 TO SFBR
+
+at 0x000001ee : */	0x721e0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH2
+
+at 0x000001f0 : */	0x6a360000,0x00000000,
+/*
+    MOVE TEMP3 TO SFBR
+
+at 0x000001f2 : */	0x721f0000,0x00000000,
+/*
+    MOVE SFBR TO SCRATCH3
+
+at 0x000001f4 : */	0x6a370000,0x00000000,
+/*
+    MOVE MEMORY 4, addr_scratch, reselected_ok_jump + 4
+
+at 0x000001f6 : */	0xc0000004,0x00000000,0x000007f4,
+/*
+reselected_ok_patch:
+    MOVE MEMORY 4, 0, 0
+
+at 0x000001f9 : */	0xc0000004,0x00000000,0x00000000,
+/*
+reselected_ok_jump:
+    JUMP 0
+
+at 0x000001fc : */	0x80080000,0x00000000,
+/*
+
+
+
+
+
+selected:
+    INT int_err_selected;
+
+at 0x000001fe : */	0x98080000,0x00010000,
+/*
+
+;
+; A select or reselect failure can be caused by one of two conditions : 
+; 1.  SIG_P was set.  This will be the case if the user has written
+;	a new value to a previously NULL head of the issue queue.
+;
+; 2.  The NCR53c810 was selected or reselected by another device.
+;
+; 3.  The bus was already busy since we were selected or reselected
+;	before starting the command.
+
+wait_reselect_failed:
+
+
+
+; Check selected bit.  
+
+    ; Must work out how to tell if we are selected....
+
+
+
+
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+
+at 0x00000200 : */	0x74164000,0x00000000,
+/*
+    JUMP schedule, IF 0x40
+
+at 0x00000202 : */	0x800c0040,0x00000000,
+/*
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+    MOVE ISTAT & 0x08 TO SFBR
+
+at 0x00000204 : */	0x74210800,0x00000000,
+/*
+    JUMP reselected, IF 0x08
+
+at 0x00000206 : */	0x800c0008,0x000006b0,
+/*
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+
+
+
+    INT int_debug_panic
+
+at 0x00000208 : */	0x98080000,0x030b0000,
+/*
+
+
+
+select_failed:
+
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x0000020a : */	0x7a1b1000,0x00000000,
+/*
+
+
+
+
+; Otherwise, mask the selected and reselected bits off SIST0
+
+    ; Let's assume we don't get selected for now
+    MOVE SSTAT0 & 0x10 TO SFBR
+
+at 0x0000020c : */	0x740d1000,0x00000000,
+/*
+
+
+
+
+    JUMP reselected, IF 0x10 
+
+at 0x0000020e : */	0x800c0010,0x000006b0,
+/*
+; If SIGP is set, the user just gave us another command, and
+; we should restart or return to the scheduler.
+; Reading CTEST2 clears the SIG_P bit in the ISTAT register.
+    MOVE CTEST2 & 0x40 TO SFBR	
+
+at 0x00000210 : */	0x74164000,0x00000000,
+/*
+    JUMP select, IF 0x40
+
+at 0x00000212 : */	0x800c0040,0x000001f8,
+/*
+; Check connected bit.  
+; FIXME: this needs to change if we support target mode
+; FIXME: is this really necessary? 
+    MOVE ISTAT & 0x08 TO SFBR
+
+at 0x00000214 : */	0x74210800,0x00000000,
+/*
+    JUMP reselected, IF 0x08
+
+at 0x00000216 : */	0x800c0008,0x000006b0,
+/*
+; FIXME : Something bogus happened, and we shouldn't fail silently.
+
+
+
+    INT int_debug_panic
+
+at 0x00000218 : */	0x98080000,0x030b0000,
+/*
+
+
+;
+; test_1
+; test_2
+;
+; PURPOSE : run some verification tests on the NCR.  test_1
+;	copies test_src to test_dest and interrupts the host
+;	processor, testing for cache coherency and interrupt
+; 	problems in the processes.
+;
+;	test_2 runs a command with offsets relative to the 
+;	DSA on entry, and is useful for miscellaneous experimentation.
+;
+
+; Verify that interrupts are working correctly and that we don't 
+; have a cache invalidation problem.
+
+ABSOLUTE test_src = 0, test_dest = 0
+ENTRY test_1
+test_1:
+    MOVE MEMORY 4, test_src, test_dest
+
+at 0x0000021a : */	0xc0000004,0x00000000,0x00000000,
+/*
+    INT int_test_1
+
+at 0x0000021d : */	0x98080000,0x04000000,
+/*
+
+;
+; Run arbitrary commands, with test code establishing a DSA
+;
+ 
+ENTRY test_2
+test_2:
+    CLEAR TARGET
+
+at 0x0000021f : */	0x60000200,0x00000000,
+/*
+
+    ; Enable selection timer
+
+
+
+    MOVE CTEST7 & 0xef TO CTEST7
+
+at 0x00000221 : */	0x7c1bef00,0x00000000,
+/*
+
+
+    SELECT ATN FROM 0, test_2_fail
+
+at 0x00000223 : */	0x43000000,0x000008dc,
+/*
+    JUMP test_2_msgout, WHEN MSG_OUT
+
+at 0x00000225 : */	0x860b0000,0x0000089c,
+/*
+ENTRY test_2_msgout
+test_2_msgout:
+
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000227 : */	0x7a1b1000,0x00000000,
+/*
+
+    MOVE FROM 8, WHEN MSG_OUT
+
+at 0x00000229 : */	0x1e000000,0x00000008,
+/*
+    MOVE FROM 16, WHEN CMD 
+
+at 0x0000022b : */	0x1a000000,0x00000010,
+/*
+    MOVE FROM 24, WHEN DATA_IN
+
+at 0x0000022d : */	0x19000000,0x00000018,
+/*
+    MOVE FROM 32, WHEN STATUS
+
+at 0x0000022f : */	0x1b000000,0x00000020,
+/*
+    MOVE FROM 40, WHEN MSG_IN
+
+at 0x00000231 : */	0x1f000000,0x00000028,
+/*
+
+
+
+    CLEAR ACK
+
+at 0x00000233 : */	0x60000040,0x00000000,
+/*
+    WAIT DISCONNECT
+
+at 0x00000235 : */	0x48000000,0x00000000,
+/*
+test_2_fail:
+
+    ; Disable selection timer
+    MOVE CTEST7 | 0x10 TO CTEST7
+
+at 0x00000237 : */	0x7a1b1000,0x00000000,
+/*
+
+    INT int_test_2
+
+at 0x00000239 : */	0x98080000,0x04010000,
+/*
+
+ENTRY debug_break
+debug_break:
+    INT int_debug_break
+
+at 0x0000023b : */	0x98080000,0x03000000,
+/*
+
+;
+; initiator_abort
+; target_abort
+;
+; PURPOSE : Abort the currently established nexus from with initiator
+;	or target mode.
+;
+;  
+
+ENTRY target_abort
+target_abort:
+    SET TARGET
+
+at 0x0000023d : */	0x58000200,0x00000000,
+/*
+    DISCONNECT
+
+at 0x0000023f : */	0x48000000,0x00000000,
+/*
+    CLEAR TARGET
+
+at 0x00000241 : */	0x60000200,0x00000000,
+/*
+    JUMP schedule
+
+at 0x00000243 : */	0x80080000,0x00000000,
+/*
+    
+ENTRY initiator_abort
+initiator_abort:
+    SET ATN
+
+at 0x00000245 : */	0x58000008,0x00000000,
+/*
+;
+; The SCSI-I specification says that targets may go into MSG out at 
+; their leisure upon receipt of the ATN single.  On all versions of the 
+; specification, we can't change phases until REQ transitions true->false, 
+; so we need to sink/source one byte of data to allow the transition.
+;
+; For the sake of safety, we'll only source one byte of data in all 
+; cases, but to accommodate the SCSI-I dain bramage, we'll sink an  
+; arbitrary number of bytes.
+    JUMP spew_cmd, WHEN CMD
+
+at 0x00000247 : */	0x820b0000,0x0000094c,
+/*
+    JUMP eat_msgin, WHEN MSG_IN
+
+at 0x00000249 : */	0x870b0000,0x0000095c,
+/*
+    JUMP eat_datain, WHEN DATA_IN
+
+at 0x0000024b : */	0x810b0000,0x0000098c,
+/*
+    JUMP eat_status, WHEN STATUS
+
+at 0x0000024d : */	0x830b0000,0x00000974,
+/*
+    JUMP spew_dataout, WHEN DATA_OUT
+
+at 0x0000024f : */	0x800b0000,0x000009a4,
+/*
+    JUMP sated
+
+at 0x00000251 : */	0x80080000,0x000009ac,
+/*
+spew_cmd:
+    MOVE 1, NCR53c7xx_zero, WHEN CMD
+
+at 0x00000253 : */	0x0a000001,0x00000000,
+/*
+    JUMP sated
+
+at 0x00000255 : */	0x80080000,0x000009ac,
+/*
+eat_msgin:
+    MOVE 1, NCR53c7xx_sink, WHEN MSG_IN
+
+at 0x00000257 : */	0x0f000001,0x00000000,
+/*
+    JUMP eat_msgin, WHEN MSG_IN
+
+at 0x00000259 : */	0x870b0000,0x0000095c,
+/*
+    JUMP sated
+
+at 0x0000025b : */	0x80080000,0x000009ac,
+/*
+eat_status:
+    MOVE 1, NCR53c7xx_sink, WHEN STATUS
+
+at 0x0000025d : */	0x0b000001,0x00000000,
+/*
+    JUMP eat_status, WHEN STATUS
+
+at 0x0000025f : */	0x830b0000,0x00000974,
+/*
+    JUMP sated
+
+at 0x00000261 : */	0x80080000,0x000009ac,
+/*
+eat_datain:
+    MOVE 1, NCR53c7xx_sink, WHEN DATA_IN
+
+at 0x00000263 : */	0x09000001,0x00000000,
+/*
+    JUMP eat_datain, WHEN DATA_IN
+
+at 0x00000265 : */	0x810b0000,0x0000098c,
+/*
+    JUMP sated
+
+at 0x00000267 : */	0x80080000,0x000009ac,
+/*
+spew_dataout:
+    MOVE 1, NCR53c7xx_zero, WHEN DATA_OUT
+
+at 0x00000269 : */	0x08000001,0x00000000,
+/*
+sated:
+
+
+
+    MOVE 1, NCR53c7xx_msg_abort, WHEN MSG_OUT
+
+at 0x0000026b : */	0x0e000001,0x00000000,
+/*
+    WAIT DISCONNECT
+
+at 0x0000026d : */	0x48000000,0x00000000,
+/*
+    INT int_norm_aborted
+
+at 0x0000026f : */	0x98080000,0x02040000,
+/*
+
+
+ 
+
+; Little patched jump, used to overcome problems with TEMP getting
+; corrupted on memory moves.
+
+jump_temp:
+    JUMP 0
+
+at 0x00000271 : */	0x80080000,0x00000000,
+};
+
+#define A_NCR53c7xx_msg_abort	0x00000000
+static u32 A_NCR53c7xx_msg_abort_used[] __attribute((unused)) = {
+	0x0000026c,
+};
+
+#define A_NCR53c7xx_msg_reject	0x00000000
+static u32 A_NCR53c7xx_msg_reject_used[] __attribute((unused)) = {
+	0x00000186,
+};
+
+#define A_NCR53c7xx_sink	0x00000000
+static u32 A_NCR53c7xx_sink_used[] __attribute((unused)) = {
+	0x00000258,
+	0x0000025e,
+	0x00000264,
+};
+
+#define A_NCR53c7xx_zero	0x00000000
+static u32 A_NCR53c7xx_zero_used[] __attribute((unused)) = {
+	0x00000254,
+	0x0000026a,
+};
+
+#define A_NOP_insn	0x00000000
+static u32 A_NOP_insn_used[] __attribute((unused)) = {
+	0x00000017,
+};
+
+#define A_addr_dsa	0x00000000
+static u32 A_addr_dsa_used[] __attribute((unused)) = {
+	0x0000000f,
+	0x00000026,
+	0x00000033,
+	0x00000040,
+	0x00000055,
+	0x00000079,
+	0x0000008e,
+	0x000000bc,
+	0x000000d2,
+	0x00000130,
+	0x000001a5,
+	0x000001bb,
+	0x000001e3,
+};
+
+#define A_addr_reconnect_dsa_head	0x00000000
+static u32 A_addr_reconnect_dsa_head_used[] __attribute((unused)) = {
+	0x000001b7,
+};
+
+#define A_addr_scratch	0x00000000
+static u32 A_addr_scratch_used[] __attribute((unused)) = {
+	0x00000002,
+	0x00000004,
+	0x00000008,
+	0x00000020,
+	0x00000022,
+	0x00000049,
+	0x00000060,
+	0x0000006a,
+	0x00000071,
+	0x00000073,
+	0x000000ab,
+	0x000000b5,
+	0x000000c1,
+	0x000000cb,
+	0x0000012c,
+	0x00000142,
+	0x00000157,
+	0x000001b2,
+	0x000001b4,
+	0x000001df,
+	0x000001f7,
+};
+
+#define A_addr_temp	0x00000000
+static u32 A_addr_temp_used[] __attribute((unused)) = {
+};
+
+#define A_dmode_memory_to_memory	0x00000000
+static u32 A_dmode_memory_to_memory_used[] __attribute((unused)) = {
+};
+
+#define A_dmode_memory_to_ncr	0x00000000
+static u32 A_dmode_memory_to_ncr_used[] __attribute((unused)) = {
+};
+
+#define A_dmode_ncr_to_memory	0x00000000
+static u32 A_dmode_ncr_to_memory_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_check_reselect	0x00000000
+static u32 A_dsa_check_reselect_used[] __attribute((unused)) = {
+	0x000001d0,
+};
+
+#define A_dsa_cmdout	0x00000048
+static u32 A_dsa_cmdout_used[] __attribute((unused)) = {
+	0x0000009a,
+};
+
+#define A_dsa_cmnd	0x00000038
+static u32 A_dsa_cmnd_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_datain	0x00000054
+static u32 A_dsa_datain_used[] __attribute((unused)) = {
+	0x000000c2,
+};
+
+#define A_dsa_dataout	0x00000050
+static u32 A_dsa_dataout_used[] __attribute((unused)) = {
+	0x000000ac,
+};
+
+#define A_dsa_end	0x00000070
+static u32 A_dsa_end_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_fields_start	0x00000000
+static u32 A_dsa_fields_start_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_msgin	0x00000058
+static u32 A_dsa_msgin_used[] __attribute((unused)) = {
+	0x0000019c,
+};
+
+#define A_dsa_msgout	0x00000040
+static u32 A_dsa_msgout_used[] __attribute((unused)) = {
+	0x00000089,
+};
+
+#define A_dsa_msgout_other	0x00000068
+static u32 A_dsa_msgout_other_used[] __attribute((unused)) = {
+	0x00000194,
+};
+
+#define A_dsa_next	0x00000030
+static u32 A_dsa_next_used[] __attribute((unused)) = {
+	0x00000061,
+};
+
+#define A_dsa_restore_pointers	0x00000000
+static u32 A_dsa_restore_pointers_used[] __attribute((unused)) = {
+	0x00000146,
+};
+
+#define A_dsa_save_data_pointer	0x00000000
+static u32 A_dsa_save_data_pointer_used[] __attribute((unused)) = {
+	0x00000131,
+};
+
+#define A_dsa_select	0x0000003c
+static u32 A_dsa_select_used[] __attribute((unused)) = {
+	0x00000082,
+};
+
+#define A_dsa_sscf_710	0x00000000
+static u32 A_dsa_sscf_710_used[] __attribute((unused)) = {
+	0x00000007,
+};
+
+#define A_dsa_status	0x00000060
+static u32 A_dsa_status_used[] __attribute((unused)) = {
+	0x00000198,
+};
+
+#define A_dsa_temp_addr_array_value	0x00000000
+static u32 A_dsa_temp_addr_array_value_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_temp_addr_dsa_value	0x00000000
+static u32 A_dsa_temp_addr_dsa_value_used[] __attribute((unused)) = {
+	0x00000001,
+};
+
+#define A_dsa_temp_addr_new_value	0x00000000
+static u32 A_dsa_temp_addr_new_value_used[] __attribute((unused)) = {
+};
+
+#define A_dsa_temp_addr_next	0x00000000
+static u32 A_dsa_temp_addr_next_used[] __attribute((unused)) = {
+	0x0000001c,
+	0x0000004f,
+};
+
+#define A_dsa_temp_addr_residual	0x00000000
+static u32 A_dsa_temp_addr_residual_used[] __attribute((unused)) = {
+	0x0000002d,
+	0x0000003b,
+};
+
+#define A_dsa_temp_addr_saved_pointer	0x00000000
+static u32 A_dsa_temp_addr_saved_pointer_used[] __attribute((unused)) = {
+	0x0000002b,
+	0x00000037,
+};
+
+#define A_dsa_temp_addr_saved_residual	0x00000000
+static u32 A_dsa_temp_addr_saved_residual_used[] __attribute((unused)) = {
+	0x0000002e,
+	0x0000003a,
+};
+
+#define A_dsa_temp_lun	0x00000000
+static u32 A_dsa_temp_lun_used[] __attribute((unused)) = {
+	0x0000004c,
+};
+
+#define A_dsa_temp_next	0x00000000
+static u32 A_dsa_temp_next_used[] __attribute((unused)) = {
+	0x0000001f,
+};
+
+#define A_dsa_temp_sync	0x00000000
+static u32 A_dsa_temp_sync_used[] __attribute((unused)) = {
+	0x00000057,
+};
+
+#define A_dsa_temp_target	0x00000000
+static u32 A_dsa_temp_target_used[] __attribute((unused)) = {
+	0x00000045,
+};
+
+#define A_emulfly	0x00000000
+static u32 A_emulfly_used[] __attribute((unused)) = {
+};
+
+#define A_int_debug_break	0x03000000
+static u32 A_int_debug_break_used[] __attribute((unused)) = {
+	0x0000023c,
+};
+
+#define A_int_debug_panic	0x030b0000
+static u32 A_int_debug_panic_used[] __attribute((unused)) = {
+	0x00000209,
+	0x00000219,
+};
+
+#define A_int_err_check_condition	0x00030000
+static u32 A_int_err_check_condition_used[] __attribute((unused)) = {
+	0x000001a9,
+};
+
+#define A_int_err_no_phase	0x00040000
+static u32 A_int_err_no_phase_used[] __attribute((unused)) = {
+};
+
+#define A_int_err_selected	0x00010000
+static u32 A_int_err_selected_used[] __attribute((unused)) = {
+	0x000001ff,
+};
+
+#define A_int_err_unexpected_phase	0x00000000
+static u32 A_int_err_unexpected_phase_used[] __attribute((unused)) = {
+	0x00000092,
+	0x00000098,
+	0x000000a0,
+	0x000000d6,
+	0x000000da,
+	0x000000dc,
+	0x000000e4,
+	0x000000e8,
+	0x000000ea,
+	0x000000f2,
+	0x000000f6,
+	0x000000f8,
+	0x000000fa,
+	0x00000160,
+};
+
+#define A_int_err_unexpected_reselect	0x00020000
+static u32 A_int_err_unexpected_reselect_used[] __attribute((unused)) = {
+	0x000001cd,
+};
+
+#define A_int_msg_1	0x01020000
+static u32 A_int_msg_1_used[] __attribute((unused)) = {
+	0x00000114,
+	0x00000116,
+};
+
+#define A_int_msg_sdtr	0x01010000
+static u32 A_int_msg_sdtr_used[] __attribute((unused)) = {
+	0x00000180,
+};
+
+#define A_int_msg_wdtr	0x01000000
+static u32 A_int_msg_wdtr_used[] __attribute((unused)) = {
+	0x00000174,
+};
+
+#define A_int_norm_aborted	0x02040000
+static u32 A_int_norm_aborted_used[] __attribute((unused)) = {
+	0x00000270,
+};
+
+#define A_int_norm_command_complete	0x02020000
+static u32 A_int_norm_command_complete_used[] __attribute((unused)) = {
+};
+
+#define A_int_norm_disconnected	0x02030000
+static u32 A_int_norm_disconnected_used[] __attribute((unused)) = {
+};
+
+#define A_int_norm_emulateintfly	0x02060000
+static u32 A_int_norm_emulateintfly_used[] __attribute((unused)) = {
+	0x000001a2,
+};
+
+#define A_int_norm_reselect_complete	0x02010000
+static u32 A_int_norm_reselect_complete_used[] __attribute((unused)) = {
+};
+
+#define A_int_norm_reset	0x02050000
+static u32 A_int_norm_reset_used[] __attribute((unused)) = {
+};
+
+#define A_int_norm_select_complete	0x02000000
+static u32 A_int_norm_select_complete_used[] __attribute((unused)) = {
+};
+
+#define A_int_test_1	0x04000000
+static u32 A_int_test_1_used[] __attribute((unused)) = {
+	0x0000021e,
+};
+
+#define A_int_test_2	0x04010000
+static u32 A_int_test_2_used[] __attribute((unused)) = {
+	0x0000023a,
+};
+
+#define A_int_test_3	0x04020000
+static u32 A_int_test_3_used[] __attribute((unused)) = {
+};
+
+#define A_msg_buf	0x00000000
+static u32 A_msg_buf_used[] __attribute((unused)) = {
+	0x00000108,
+	0x00000162,
+	0x0000016c,
+	0x00000172,
+	0x00000178,
+	0x0000017e,
+};
+
+#define A_reconnect_dsa_head	0x00000000
+static u32 A_reconnect_dsa_head_used[] __attribute((unused)) = {
+	0x0000006d,
+	0x00000074,
+	0x000001b1,
+};
+
+#define A_reselected_identify	0x00000000
+static u32 A_reselected_identify_used[] __attribute((unused)) = {
+	0x00000048,
+	0x000001af,
+};
+
+#define A_reselected_tag	0x00000000
+static u32 A_reselected_tag_used[] __attribute((unused)) = {
+};
+
+#define A_saved_dsa	0x00000000
+static u32 A_saved_dsa_used[] __attribute((unused)) = {
+	0x00000005,
+	0x0000000e,
+	0x00000023,
+	0x00000025,
+	0x00000032,
+	0x0000003f,
+	0x00000054,
+	0x0000005f,
+	0x00000070,
+	0x00000078,
+	0x0000008d,
+	0x000000aa,
+	0x000000bb,
+	0x000000c0,
+	0x000000d1,
+	0x0000012f,
+	0x000001a4,
+	0x000001b5,
+	0x000001ba,
+	0x000001e2,
+};
+
+#define A_schedule	0x00000000
+static u32 A_schedule_used[] __attribute((unused)) = {
+	0x0000007d,
+	0x000001a7,
+	0x00000203,
+	0x00000244,
+};
+
+#define A_test_dest	0x00000000
+static u32 A_test_dest_used[] __attribute((unused)) = {
+	0x0000021c,
+};
+
+#define A_test_src	0x00000000
+static u32 A_test_src_used[] __attribute((unused)) = {
+	0x0000021b,
+};
+
+#define Ent_accept_message	0x00000624
+#define Ent_cmdout_cmdout	0x00000264
+#define Ent_command_complete	0x0000065c
+#define Ent_command_complete_msgin	0x0000066c
+#define Ent_data_transfer	0x0000026c
+#define Ent_datain_to_jump	0x00000334
+#define Ent_debug_break	0x000008ec
+#define Ent_dsa_code_begin	0x00000000
+#define Ent_dsa_code_check_reselect	0x0000010c
+#define Ent_dsa_code_fix_jump	0x00000058
+#define Ent_dsa_code_restore_pointers	0x000000d8
+#define Ent_dsa_code_save_data_pointer	0x000000a4
+#define Ent_dsa_code_template	0x00000000
+#define Ent_dsa_code_template_end	0x00000178
+#define Ent_dsa_schedule	0x00000178
+#define Ent_dsa_zero	0x00000178
+#define Ent_end_data_transfer	0x000002a4
+#define Ent_initiator_abort	0x00000914
+#define Ent_msg_in	0x0000041c
+#define Ent_msg_in_restart	0x000003fc
+#define Ent_other_in	0x0000038c
+#define Ent_other_out	0x00000354
+#define Ent_other_transfer	0x000003c4
+#define Ent_reject_message	0x00000604
+#define Ent_reselected_check_next	0x000006f0
+#define Ent_reselected_ok	0x00000798
+#define Ent_respond_message	0x0000063c
+#define Ent_select	0x000001f8
+#define Ent_select_msgout	0x00000218
+#define Ent_target_abort	0x000008f4
+#define Ent_test_1	0x00000868
+#define Ent_test_2	0x0000087c
+#define Ent_test_2_msgout	0x0000089c
+#define Ent_wait_reselect	0x000006a8
+static u32 LABELPATCHES[] __attribute((unused)) = {
+	0x00000011,
+	0x0000001a,
+	0x0000001d,
+	0x00000028,
+	0x0000002a,
+	0x00000035,
+	0x00000038,
+	0x00000042,
+	0x00000050,
+	0x00000052,
+	0x0000006b,
+	0x00000083,
+	0x00000085,
+	0x00000090,
+	0x00000094,
+	0x00000096,
+	0x0000009c,
+	0x0000009e,
+	0x000000a2,
+	0x000000a4,
+	0x000000a6,
+	0x000000a8,
+	0x000000b6,
+	0x000000b9,
+	0x000000cc,
+	0x000000cf,
+	0x000000d8,
+	0x000000de,
+	0x000000e0,
+	0x000000e6,
+	0x000000ec,
+	0x000000ee,
+	0x000000f4,
+	0x000000fc,
+	0x000000fe,
+	0x0000010a,
+	0x0000010c,
+	0x0000010e,
+	0x00000110,
+	0x00000112,
+	0x00000118,
+	0x0000011a,
+	0x0000012d,
+	0x00000143,
+	0x00000158,
+	0x0000015c,
+	0x00000164,
+	0x00000166,
+	0x00000168,
+	0x0000016e,
+	0x0000017a,
+	0x000001ab,
+	0x000001b8,
+	0x000001bf,
+	0x000001c3,
+	0x000001c7,
+	0x000001cb,
+	0x000001e0,
+	0x000001f8,
+	0x00000207,
+	0x0000020f,
+	0x00000213,
+	0x00000217,
+	0x00000224,
+	0x00000226,
+	0x00000248,
+	0x0000024a,
+	0x0000024c,
+	0x0000024e,
+	0x00000250,
+	0x00000252,
+	0x00000256,
+	0x0000025a,
+	0x0000025c,
+	0x00000260,
+	0x00000262,
+	0x00000266,
+	0x00000268,
+};
+
+static struct {
+	u32	offset;
+	void		*address;
+} EXTERNAL_PATCHES[] __attribute((unused)) = {
+};
+
+static u32 INSTRUCTIONS __attribute((unused))	= 290;
+static u32 PATCHES __attribute((unused))	= 78;
+static u32 EXTERNAL_PATCHES_LEN __attribute((unused))	= 0;
diff --git a/drivers/scsi/53c7xx_u.h_shipped b/drivers/scsi/53c7xx_u.h_shipped
new file mode 100644
index 0000000..7b33717
--- /dev/null
+++ b/drivers/scsi/53c7xx_u.h_shipped
@@ -0,0 +1,102 @@
+#undef A_NCR53c7xx_msg_abort
+#undef A_NCR53c7xx_msg_reject
+#undef A_NCR53c7xx_sink
+#undef A_NCR53c7xx_zero
+#undef A_NOP_insn
+#undef A_addr_dsa
+#undef A_addr_reconnect_dsa_head
+#undef A_addr_scratch
+#undef A_addr_temp
+#undef A_dmode_memory_to_memory
+#undef A_dmode_memory_to_ncr
+#undef A_dmode_ncr_to_memory
+#undef A_dsa_check_reselect
+#undef A_dsa_cmdout
+#undef A_dsa_cmnd
+#undef A_dsa_datain
+#undef A_dsa_dataout
+#undef A_dsa_end
+#undef A_dsa_fields_start
+#undef A_dsa_msgin
+#undef A_dsa_msgout
+#undef A_dsa_msgout_other
+#undef A_dsa_next
+#undef A_dsa_restore_pointers
+#undef A_dsa_save_data_pointer
+#undef A_dsa_select
+#undef A_dsa_sscf_710
+#undef A_dsa_status
+#undef A_dsa_temp_addr_array_value
+#undef A_dsa_temp_addr_dsa_value
+#undef A_dsa_temp_addr_new_value
+#undef A_dsa_temp_addr_next
+#undef A_dsa_temp_addr_residual
+#undef A_dsa_temp_addr_saved_pointer
+#undef A_dsa_temp_addr_saved_residual
+#undef A_dsa_temp_lun
+#undef A_dsa_temp_next
+#undef A_dsa_temp_sync
+#undef A_dsa_temp_target
+#undef A_emulfly
+#undef A_int_debug_break
+#undef A_int_debug_panic
+#undef A_int_err_check_condition
+#undef A_int_err_no_phase
+#undef A_int_err_selected
+#undef A_int_err_unexpected_phase
+#undef A_int_err_unexpected_reselect
+#undef A_int_msg_1
+#undef A_int_msg_sdtr
+#undef A_int_msg_wdtr
+#undef A_int_norm_aborted
+#undef A_int_norm_command_complete
+#undef A_int_norm_disconnected
+#undef A_int_norm_emulateintfly
+#undef A_int_norm_reselect_complete
+#undef A_int_norm_reset
+#undef A_int_norm_select_complete
+#undef A_int_test_1
+#undef A_int_test_2
+#undef A_int_test_3
+#undef A_msg_buf
+#undef A_reconnect_dsa_head
+#undef A_reselected_identify
+#undef A_reselected_tag
+#undef A_saved_dsa
+#undef A_schedule
+#undef A_test_dest
+#undef A_test_src
+#undef Ent_accept_message
+#undef Ent_cmdout_cmdout
+#undef Ent_command_complete
+#undef Ent_command_complete_msgin
+#undef Ent_data_transfer
+#undef Ent_datain_to_jump
+#undef Ent_debug_break
+#undef Ent_dsa_code_begin
+#undef Ent_dsa_code_check_reselect
+#undef Ent_dsa_code_fix_jump
+#undef Ent_dsa_code_restore_pointers
+#undef Ent_dsa_code_save_data_pointer
+#undef Ent_dsa_code_template
+#undef Ent_dsa_code_template_end
+#undef Ent_dsa_schedule
+#undef Ent_dsa_zero
+#undef Ent_end_data_transfer
+#undef Ent_initiator_abort
+#undef Ent_msg_in
+#undef Ent_msg_in_restart
+#undef Ent_other_in
+#undef Ent_other_out
+#undef Ent_other_transfer
+#undef Ent_reject_message
+#undef Ent_reselected_check_next
+#undef Ent_reselected_ok
+#undef Ent_respond_message
+#undef Ent_select
+#undef Ent_select_msgout
+#undef Ent_target_abort
+#undef Ent_test_1
+#undef Ent_test_2
+#undef Ent_test_2_msgout
+#undef Ent_wait_reselect
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
new file mode 100644
index 0000000..41b5197
--- /dev/null
+++ b/drivers/scsi/BusLogic.c
@@ -0,0 +1,3574 @@
+
+/*
+
+  Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
+
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+  This program is free software; you may redistribute and/or modify it under
+  the terms of the GNU General Public License Version 2 as published by the
+  Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  for complete details.
+
+  The author respectfully requests that any modifications to this software be
+  sent directly to him for evaluation and testing.
+
+  Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose
+  advice has been invaluable, to David Gentzel, for writing the original Linux
+  BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site.
+
+  Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB
+  Manager available as freely redistributable source code.
+
+*/
+
+#define BusLogic_DriverVersion		"2.1.16"
+#define BusLogic_DriverDate		"18 July 2002"
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <scsi/scsicam.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include "BusLogic.h"
+#include "FlashPoint.c"
+
+#ifndef FAILURE
+#define FAILURE (-1)
+#endif
+
+static struct scsi_host_template Bus_Logic_template;
+
+/*
+  BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver
+  Options specifications provided via the Linux Kernel Command Line or via
+  the Loadable Kernel Module Installation Facility.
+*/
+
+static int BusLogic_DriverOptionsCount;
+
+
+/*
+  BusLogic_DriverOptions is an array of Driver Options structures representing
+  BusLogic Driver Options specifications provided via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.
+*/
+
+static struct BusLogic_DriverOptions BusLogic_DriverOptions[BusLogic_MaxHostAdapters];
+
+
+/*
+  BusLogic can be assigned a string by insmod.
+*/
+
+MODULE_LICENSE("GPL");
+#ifdef MODULE
+static char *BusLogic;
+module_param(BusLogic, charp, 0);
+#endif
+
+
+/*
+  BusLogic_ProbeOptions is a set of Probe Options to be applied across
+  all BusLogic Host Adapters.
+*/
+
+static struct BusLogic_ProbeOptions BusLogic_ProbeOptions;
+
+
+/*
+  BusLogic_GlobalOptions is a set of Global Options to be applied across
+  all BusLogic Host Adapters.
+*/
+
+static struct BusLogic_GlobalOptions BusLogic_GlobalOptions;
+
+static LIST_HEAD(BusLogic_host_list);
+
+/*
+  BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
+*/
+
+static int BusLogic_ProbeInfoCount;
+
+
+/*
+  BusLogic_ProbeInfoList is the list of I/O Addresses and Bus Probe Information
+  to be checked for potential BusLogic Host Adapters.  It is initialized by
+  interrogating the PCI Configuration Space on PCI machines as well as from the
+  list of standard BusLogic I/O Addresses.
+*/
+
+static struct BusLogic_ProbeInfo *BusLogic_ProbeInfoList;
+
+
+/*
+  BusLogic_CommandFailureReason holds a string identifying the reason why a
+  call to BusLogic_Command failed.  It is only non-NULL when BusLogic_Command
+  returns a failure code.
+*/
+
+static char *BusLogic_CommandFailureReason;
+
+/*
+  BusLogic_AnnounceDriver announces the Driver Version and Date, Author's
+  Name, Copyright Notice, and Electronic Mail Address.
+*/
+
+static void BusLogic_AnnounceDriver(struct BusLogic_HostAdapter *HostAdapter)
+{
+	BusLogic_Announce("***** BusLogic SCSI Driver Version " BusLogic_DriverVersion " of " BusLogic_DriverDate " *****\n", HostAdapter);
+	BusLogic_Announce("Copyright 1995-1998 by Leonard N. Zubkoff " "<lnz@dandelion.com>\n", HostAdapter);
+}
+
+
+/*
+  BusLogic_DriverInfo returns the Host Adapter Name to identify this SCSI
+  Driver and Host Adapter.
+*/
+
+static const char *BusLogic_DriverInfo(struct Scsi_Host *Host)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata;
+	return HostAdapter->FullModelName;
+}
+
+/*
+  BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs)
+  for Host Adapter from the BlockSize bytes located at BlockPointer.  The newly
+  created CCBs are added to Host Adapter's free list.
+*/
+
+static void BusLogic_InitializeCCBs(struct BusLogic_HostAdapter *HostAdapter, void *BlockPointer, int BlockSize, dma_addr_t BlockPointerHandle)
+{
+	struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) BlockPointer;
+	unsigned int offset = 0;
+	memset(BlockPointer, 0, BlockSize);
+	CCB->AllocationGroupHead = BlockPointerHandle;
+	CCB->AllocationGroupSize = BlockSize;
+	while ((BlockSize -= sizeof(struct BusLogic_CCB)) >= 0) {
+		CCB->Status = BusLogic_CCB_Free;
+		CCB->HostAdapter = HostAdapter;
+		CCB->DMA_Handle = (u32) BlockPointerHandle + offset;
+		if (BusLogic_FlashPointHostAdapterP(HostAdapter)) {
+			CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
+			CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress;
+		}
+		CCB->Next = HostAdapter->Free_CCBs;
+		CCB->NextAll = HostAdapter->All_CCBs;
+		HostAdapter->Free_CCBs = CCB;
+		HostAdapter->All_CCBs = CCB;
+		HostAdapter->AllocatedCCBs++;
+		CCB++;
+		offset += sizeof(struct BusLogic_CCB);
+	}
+}
+
+
+/*
+  BusLogic_CreateInitialCCBs allocates the initial CCBs for Host Adapter.
+*/
+
+static boolean __init BusLogic_CreateInitialCCBs(struct BusLogic_HostAdapter *HostAdapter)
+{
+	int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB);
+	void *BlockPointer;
+	dma_addr_t BlockPointerHandle;
+	while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs) {
+		BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle);
+		if (BlockPointer == NULL) {
+			BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n", HostAdapter);
+			return false;
+		}
+		BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle);
+	}
+	return true;
+}
+
+
+/*
+  BusLogic_DestroyCCBs deallocates the CCBs for Host Adapter.
+*/
+
+static void BusLogic_DestroyCCBs(struct BusLogic_HostAdapter *HostAdapter)
+{
+	struct BusLogic_CCB *NextCCB = HostAdapter->All_CCBs, *CCB, *Last_CCB = NULL;
+	HostAdapter->All_CCBs = NULL;
+	HostAdapter->Free_CCBs = NULL;
+	while ((CCB = NextCCB) != NULL) {
+		NextCCB = CCB->NextAll;
+		if (CCB->AllocationGroupHead) {
+			if (Last_CCB)
+				pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead);
+			Last_CCB = CCB;
+		}
+	}
+	if (Last_CCB)
+		pci_free_consistent(HostAdapter->PCI_Device, Last_CCB->AllocationGroupSize, Last_CCB, Last_CCB->AllocationGroupHead);
+}
+
+
+/*
+  BusLogic_CreateAdditionalCCBs allocates Additional CCBs for Host Adapter.  If
+  allocation fails and there are no remaining CCBs available, the Driver Queue
+  Depth is decreased to a known safe value to avoid potential deadlocks when
+  multiple host adapters share the same IRQ Channel.
+*/
+
+static void BusLogic_CreateAdditionalCCBs(struct BusLogic_HostAdapter *HostAdapter, int AdditionalCCBs, boolean SuccessMessageP)
+{
+	int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(struct BusLogic_CCB);
+	int PreviouslyAllocated = HostAdapter->AllocatedCCBs;
+	void *BlockPointer;
+	dma_addr_t BlockPointerHandle;
+	if (AdditionalCCBs <= 0)
+		return;
+	while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs) {
+		BlockPointer = pci_alloc_consistent(HostAdapter->PCI_Device, BlockSize, &BlockPointerHandle);
+		if (BlockPointer == NULL)
+			break;
+		BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize, BlockPointerHandle);
+	}
+	if (HostAdapter->AllocatedCCBs > PreviouslyAllocated) {
+		if (SuccessMessageP)
+			BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n", HostAdapter, HostAdapter->AllocatedCCBs - PreviouslyAllocated, HostAdapter->AllocatedCCBs);
+		return;
+	}
+	BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter);
+	if (HostAdapter->DriverQueueDepth > HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount) {
+		HostAdapter->DriverQueueDepth = HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount;
+		HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+	}
+}
+
+/*
+  BusLogic_AllocateCCB allocates a CCB from Host Adapter's free list,
+  allocating more memory from the Kernel if necessary.  The Host Adapter's
+  Lock should already have been acquired by the caller.
+*/
+
+static struct BusLogic_CCB *BusLogic_AllocateCCB(struct BusLogic_HostAdapter
+						 *HostAdapter)
+{
+	static unsigned long SerialNumber = 0;
+	struct BusLogic_CCB *CCB;
+	CCB = HostAdapter->Free_CCBs;
+	if (CCB != NULL) {
+		CCB->SerialNumber = ++SerialNumber;
+		HostAdapter->Free_CCBs = CCB->Next;
+		CCB->Next = NULL;
+		if (HostAdapter->Free_CCBs == NULL)
+			BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true);
+		return CCB;
+	}
+	BusLogic_CreateAdditionalCCBs(HostAdapter, HostAdapter->IncrementalCCBs, true);
+	CCB = HostAdapter->Free_CCBs;
+	if (CCB == NULL)
+		return NULL;
+	CCB->SerialNumber = ++SerialNumber;
+	HostAdapter->Free_CCBs = CCB->Next;
+	CCB->Next = NULL;
+	return CCB;
+}
+
+
+/*
+  BusLogic_DeallocateCCB deallocates a CCB, returning it to the Host Adapter's
+  free list.  The Host Adapter's Lock should already have been acquired by the
+  caller.
+*/
+
+static void BusLogic_DeallocateCCB(struct BusLogic_CCB *CCB)
+{
+	struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter;
+	struct scsi_cmnd *cmd = CCB->Command;
+
+	if (cmd->use_sg != 0) {
+		pci_unmap_sg(HostAdapter->PCI_Device,
+				(struct scatterlist *)cmd->request_buffer,
+				cmd->use_sg, cmd->sc_data_direction);
+	} else if (cmd->request_bufflen != 0) {
+		pci_unmap_single(HostAdapter->PCI_Device, CCB->DataPointer,
+				CCB->DataLength, cmd->sc_data_direction);
+	}
+	pci_unmap_single(HostAdapter->PCI_Device, CCB->SenseDataPointer,
+			CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
+
+	CCB->Command = NULL;
+	CCB->Status = BusLogic_CCB_Free;
+	CCB->Next = HostAdapter->Free_CCBs;
+	HostAdapter->Free_CCBs = CCB;
+}
+
+
+/*
+  BusLogic_Command sends the command OperationCode to HostAdapter, optionally
+  providing ParameterLength bytes of ParameterData and receiving at most
+  ReplyLength bytes of ReplyData; any excess reply data is received but
+  discarded.
+
+  On success, this function returns the number of reply bytes read from
+  the Host Adapter (including any discarded data); on failure, it returns
+  -1 if the command was invalid, or -2 if a timeout occurred.
+
+  BusLogic_Command is called exclusively during host adapter detection and
+  initialization, so performance and latency are not critical, and exclusive
+  access to the Host Adapter hardware is assumed.  Once the host adapter and
+  driver are initialized, the only Host Adapter command that is issued is the
+  single byte Execute Mailbox Command operation code, which does not require
+  waiting for the Host Adapter Ready bit to be set in the Status Register.
+*/
+
+static int BusLogic_Command(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_OperationCode OperationCode, void *ParameterData, int ParameterLength, void *ReplyData, int ReplyLength)
+{
+	unsigned char *ParameterPointer = (unsigned char *) ParameterData;
+	unsigned char *ReplyPointer = (unsigned char *) ReplyData;
+	union BusLogic_StatusRegister StatusRegister;
+	union BusLogic_InterruptRegister InterruptRegister;
+	unsigned long ProcessorFlags = 0;
+	int ReplyBytes = 0, Result;
+	long TimeoutCounter;
+	/*
+	   Clear out the Reply Data if provided.
+	 */
+	if (ReplyLength > 0)
+		memset(ReplyData, 0, ReplyLength);
+	/*
+	   If the IRQ Channel has not yet been acquired, then interrupts must be
+	   disabled while issuing host adapter commands since a Command Complete
+	   interrupt could occur if the IRQ Channel was previously enabled by another
+	   BusLogic Host Adapter or another driver sharing the same IRQ Channel.
+	 */
+	if (!HostAdapter->IRQ_ChannelAcquired) {
+		local_irq_save(ProcessorFlags);
+		local_irq_disable();
+	}
+	/*
+	   Wait for the Host Adapter Ready bit to be set and the Command/Parameter
+	   Register Busy bit to be reset in the Status Register.
+	 */
+	TimeoutCounter = 10000;
+	while (--TimeoutCounter >= 0) {
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (StatusRegister.sr.HostAdapterReady && !StatusRegister.sr.CommandParameterRegisterBusy)
+			break;
+		udelay(100);
+	}
+	if (TimeoutCounter < 0) {
+		BusLogic_CommandFailureReason = "Timeout waiting for Host Adapter Ready";
+		Result = -2;
+		goto Done;
+	}
+	/*
+	   Write the OperationCode to the Command/Parameter Register.
+	 */
+	HostAdapter->HostAdapterCommandCompleted = false;
+	BusLogic_WriteCommandParameterRegister(HostAdapter, OperationCode);
+	/*
+	   Write any additional Parameter Bytes.
+	 */
+	TimeoutCounter = 10000;
+	while (ParameterLength > 0 && --TimeoutCounter >= 0) {
+		/*
+		   Wait 100 microseconds to give the Host Adapter enough time to determine
+		   whether the last value written to the Command/Parameter Register was
+		   valid or not.  If the Command Complete bit is set in the Interrupt
+		   Register, then the Command Invalid bit in the Status Register will be
+		   reset if the Operation Code or Parameter was valid and the command
+		   has completed, or set if the Operation Code or Parameter was invalid.
+		   If the Data In Register Ready bit is set in the Status Register, then
+		   the Operation Code was valid, and data is waiting to be read back
+		   from the Host Adapter.  Otherwise, wait for the Command/Parameter
+		   Register Busy bit in the Status Register to be reset.
+		 */
+		udelay(100);
+		InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (InterruptRegister.ir.CommandComplete)
+			break;
+		if (HostAdapter->HostAdapterCommandCompleted)
+			break;
+		if (StatusRegister.sr.DataInRegisterReady)
+			break;
+		if (StatusRegister.sr.CommandParameterRegisterBusy)
+			continue;
+		BusLogic_WriteCommandParameterRegister(HostAdapter, *ParameterPointer++);
+		ParameterLength--;
+	}
+	if (TimeoutCounter < 0) {
+		BusLogic_CommandFailureReason = "Timeout waiting for Parameter Acceptance";
+		Result = -2;
+		goto Done;
+	}
+	/*
+	   The Modify I/O Address command does not cause a Command Complete Interrupt.
+	 */
+	if (OperationCode == BusLogic_ModifyIOAddress) {
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (StatusRegister.sr.CommandInvalid) {
+			BusLogic_CommandFailureReason = "Modify I/O Address Invalid";
+			Result = -1;
+			goto Done;
+		}
+		if (BusLogic_GlobalOptions.TraceConfiguration)
+			BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: " "(Modify I/O Address)\n", HostAdapter, OperationCode, StatusRegister.All);
+		Result = 0;
+		goto Done;
+	}
+	/*
+	   Select an appropriate timeout value for awaiting command completion.
+	 */
+	switch (OperationCode) {
+	case BusLogic_InquireInstalledDevicesID0to7:
+	case BusLogic_InquireInstalledDevicesID8to15:
+	case BusLogic_InquireTargetDevices:
+		/* Approximately 60 seconds. */
+		TimeoutCounter = 60 * 10000;
+		break;
+	default:
+		/* Approximately 1 second. */
+		TimeoutCounter = 10000;
+		break;
+	}
+	/*
+	   Receive any Reply Bytes, waiting for either the Command Complete bit to
+	   be set in the Interrupt Register, or for the Interrupt Handler to set the
+	   Host Adapter Command Completed bit in the Host Adapter structure.
+	 */
+	while (--TimeoutCounter >= 0) {
+		InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (InterruptRegister.ir.CommandComplete)
+			break;
+		if (HostAdapter->HostAdapterCommandCompleted)
+			break;
+		if (StatusRegister.sr.DataInRegisterReady) {
+			if (++ReplyBytes <= ReplyLength)
+				*ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
+			else
+				BusLogic_ReadDataInRegister(HostAdapter);
+		}
+		if (OperationCode == BusLogic_FetchHostAdapterLocalRAM && StatusRegister.sr.HostAdapterReady)
+			break;
+		udelay(100);
+	}
+	if (TimeoutCounter < 0) {
+		BusLogic_CommandFailureReason = "Timeout waiting for Command Complete";
+		Result = -2;
+		goto Done;
+	}
+	/*
+	   Clear any pending Command Complete Interrupt.
+	 */
+	BusLogic_InterruptReset(HostAdapter);
+	/*
+	   Provide tracing information if requested.
+	 */
+	if (BusLogic_GlobalOptions.TraceConfiguration) {
+		int i;
+		BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:", HostAdapter, OperationCode, StatusRegister.All, ReplyLength, ReplyBytes);
+		if (ReplyLength > ReplyBytes)
+			ReplyLength = ReplyBytes;
+		for (i = 0; i < ReplyLength; i++)
+			BusLogic_Notice(" %02X", HostAdapter, ((unsigned char *) ReplyData)[i]);
+		BusLogic_Notice("\n", HostAdapter);
+	}
+	/*
+	   Process Command Invalid conditions.
+	 */
+	if (StatusRegister.sr.CommandInvalid) {
+		/*
+		   Some early BusLogic Host Adapters may not recover properly from
+		   a Command Invalid condition, so if this appears to be the case,
+		   a Soft Reset is issued to the Host Adapter.  Potentially invalid
+		   commands are never attempted after Mailbox Initialization is
+		   performed, so there should be no Host Adapter state lost by a
+		   Soft Reset in response to a Command Invalid condition.
+		 */
+		udelay(1000);
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (StatusRegister.sr.CommandInvalid ||
+		    StatusRegister.sr.Reserved ||
+		    StatusRegister.sr.DataInRegisterReady ||
+		    StatusRegister.sr.CommandParameterRegisterBusy || !StatusRegister.sr.HostAdapterReady || !StatusRegister.sr.InitializationRequired || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.DiagnosticFailure) {
+			BusLogic_SoftReset(HostAdapter);
+			udelay(1000);
+		}
+		BusLogic_CommandFailureReason = "Command Invalid";
+		Result = -1;
+		goto Done;
+	}
+	/*
+	   Handle Excess Parameters Supplied conditions.
+	 */
+	if (ParameterLength > 0) {
+		BusLogic_CommandFailureReason = "Excess Parameters Supplied";
+		Result = -1;
+		goto Done;
+	}
+	/*
+	   Indicate the command completed successfully.
+	 */
+	BusLogic_CommandFailureReason = NULL;
+	Result = ReplyBytes;
+	/*
+	   Restore the interrupt status if necessary and return.
+	 */
+      Done:
+	if (!HostAdapter->IRQ_ChannelAcquired)
+		local_irq_restore(ProcessorFlags);
+	return Result;
+}
+
+
+/*
+  BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list
+  of I/O Address and Bus Probe Information to be checked for potential BusLogic
+  Host Adapters.
+*/
+
+static void __init BusLogic_AppendProbeAddressISA(unsigned long IO_Address)
+{
+	struct BusLogic_ProbeInfo *ProbeInfo;
+	if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
+		return;
+	ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+	ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+	ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+	ProbeInfo->IO_Address = IO_Address;
+	ProbeInfo->PCI_Device = NULL;
+}
+
+
+/*
+  BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and
+  Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters
+  only from the list of standard BusLogic MultiMaster ISA I/O Addresses.
+*/
+
+static void __init BusLogic_InitializeProbeInfoListISA(struct BusLogic_HostAdapter
+						       *PrototypeHostAdapter)
+{
+	/*
+	   If BusLogic Driver Options specifications requested that ISA Bus Probes
+	   be inhibited, do not proceed further.
+	 */
+	if (BusLogic_ProbeOptions.NoProbeISA)
+		return;
+	/*
+	   Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
+	 */
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x330);
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x334);
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x230);
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x234);
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x130);
+	if (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+		BusLogic_AppendProbeAddressISA(0x134);
+}
+
+
+#ifdef CONFIG_PCI
+
+
+/*
+  BusLogic_SortProbeInfo sorts a section of BusLogic_ProbeInfoList in order
+  of increasing PCI Bus and Device Number.
+*/
+
+static void __init BusLogic_SortProbeInfo(struct BusLogic_ProbeInfo *ProbeInfoList, int ProbeInfoCount)
+{
+	int LastInterchange = ProbeInfoCount - 1, Bound, j;
+	while (LastInterchange > 0) {
+		Bound = LastInterchange;
+		LastInterchange = 0;
+		for (j = 0; j < Bound; j++) {
+			struct BusLogic_ProbeInfo *ProbeInfo1 = &ProbeInfoList[j];
+			struct BusLogic_ProbeInfo *ProbeInfo2 = &ProbeInfoList[j + 1];
+			if (ProbeInfo1->Bus > ProbeInfo2->Bus || (ProbeInfo1->Bus == ProbeInfo2->Bus && (ProbeInfo1->Device > ProbeInfo2->Device))) {
+				struct BusLogic_ProbeInfo TempProbeInfo;
+				memcpy(&TempProbeInfo, ProbeInfo1, sizeof(struct BusLogic_ProbeInfo));
+				memcpy(ProbeInfo1, ProbeInfo2, sizeof(struct BusLogic_ProbeInfo));
+				memcpy(ProbeInfo2, &TempProbeInfo, sizeof(struct BusLogic_ProbeInfo));
+				LastInterchange = j;
+			}
+		}
+	}
+}
+
+
+/*
+  BusLogic_InitializeMultiMasterProbeInfo initializes the list of I/O Address
+  and Bus Probe Information to be checked for potential BusLogic MultiMaster
+  SCSI Host Adapters by interrogating the PCI Configuration Space on PCI
+  machines as well as from the list of standard BusLogic MultiMaster ISA
+  I/O Addresses.  It returns the number of PCI MultiMaster Host Adapters found.
+*/
+
+static int __init BusLogic_InitializeMultiMasterProbeInfo(struct BusLogic_HostAdapter
+							  *PrototypeHostAdapter)
+{
+	struct BusLogic_ProbeInfo *PrimaryProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount];
+	int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1;
+	int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0;
+	boolean ForceBusDeviceScanningOrder = false;
+	boolean ForceBusDeviceScanningOrderChecked = false;
+	boolean StandardAddressSeen[6];
+	struct pci_dev *PCI_Device = NULL;
+	int i;
+	if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
+		return 0;
+	BusLogic_ProbeInfoCount++;
+	for (i = 0; i < 6; i++)
+		StandardAddressSeen[i] = false;
+	/*
+	   Iterate over the MultiMaster PCI Host Adapters.  For each enumerated host
+	   adapter, determine whether its ISA Compatible I/O Port is enabled and if
+	   so, whether it is assigned the Primary I/O Address.  A host adapter that is
+	   assigned the Primary I/O Address will always be the preferred boot device.
+	   The MultiMaster BIOS will first recognize a host adapter at the Primary I/O
+	   Address, then any other PCI host adapters, and finally any host adapters
+	   located at the remaining standard ISA I/O Addresses.  When a PCI host
+	   adapter is found with its ISA Compatible I/O Port enabled, a command is
+	   issued to disable the ISA Compatible I/O Port, and it is noted that the
+	   particular standard ISA I/O Address need not be probed.
+	 */
+	PrimaryProbeInfo->IO_Address = 0;
+	while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER, PCI_Device)) != NULL) {
+		struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
+		struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation;
+		enum BusLogic_ISACompatibleIOPort ModifyIOAddressRequest;
+		unsigned char Bus;
+		unsigned char Device;
+		unsigned int IRQ_Channel;
+		unsigned long BaseAddress0;
+		unsigned long BaseAddress1;
+		unsigned long IO_Address;
+		unsigned long PCI_Address;
+
+		if (pci_enable_device(PCI_Device))
+			continue;
+
+		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+			continue;
+
+		Bus = PCI_Device->bus->number;
+		Device = PCI_Device->devfn >> 3;
+		IRQ_Channel = PCI_Device->irq;
+		IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0);
+		PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1);
+
+		if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) {
+			BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "MultiMaster Host Adapter\n", NULL, BaseAddress0);
+			BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address);
+			continue;
+		}
+		if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) {
+			BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "MultiMaster Host Adapter\n", NULL, BaseAddress1);
+			BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address);
+			continue;
+		}
+		if (IRQ_Channel == 0) {
+			BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "MultiMaster Host Adapter\n", NULL, IRQ_Channel);
+			BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address);
+			continue;
+		}
+		if (BusLogic_GlobalOptions.TraceProbe) {
+			BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter " "detected at\n", NULL);
+			BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address);
+		}
+		/*
+		   Issue the Inquire PCI Host Adapter Information command to determine
+		   the ISA Compatible I/O Port.  If the ISA Compatible I/O Port is
+		   known and enabled, note that the particular Standard ISA I/O
+		   Address should not be probed.
+		 */
+		HostAdapter->IO_Address = IO_Address;
+		BusLogic_InterruptReset(HostAdapter);
+		if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation))
+		    == sizeof(PCIHostAdapterInformation)) {
+			if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
+				StandardAddressSeen[PCIHostAdapterInformation.ISACompatibleIOPort] = true;
+		} else
+			PCIHostAdapterInformation.ISACompatibleIOPort = BusLogic_IO_Disable;
+		/*
+		 * Issue the Modify I/O Address command to disable the ISA Compatible
+		 * I/O Port.  On PCI Host Adapters, the Modify I/O Address command
+		 * allows modification of the ISA compatible I/O Address that the Host
+		 * Adapter responds to; it does not affect the PCI compliant I/O Address
+		 * assigned at system initialization.
+		 */
+		ModifyIOAddressRequest = BusLogic_IO_Disable;
+		BusLogic_Command(HostAdapter, BusLogic_ModifyIOAddress, &ModifyIOAddressRequest, sizeof(ModifyIOAddressRequest), NULL, 0);
+		/*
+		   For the first MultiMaster Host Adapter enumerated, issue the Fetch
+		   Host Adapter Local RAM command to read byte 45 of the AutoSCSI area,
+		   for the setting of the "Use Bus And Device # For PCI Scanning Seq."
+		   option.  Issue the Inquire Board ID command since this option is
+		   only valid for the BT-948/958/958D.
+		 */
+		if (!ForceBusDeviceScanningOrderChecked) {
+			struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest;
+			struct BusLogic_AutoSCSIByte45 AutoSCSIByte45;
+			struct BusLogic_BoardID BoardID;
+			FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset + 45;
+			FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIByte45);
+			BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIByte45, sizeof(AutoSCSIByte45));
+			BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID));
+			if (BoardID.FirmwareVersion1stDigit == '5')
+				ForceBusDeviceScanningOrder = AutoSCSIByte45.ForceBusDeviceScanningOrder;
+			ForceBusDeviceScanningOrderChecked = true;
+		}
+		/*
+		   Determine whether this MultiMaster Host Adapter has its ISA
+		   Compatible I/O Port enabled and is assigned the Primary I/O Address.
+		   If it does, then it is the Primary MultiMaster Host Adapter and must
+		   be recognized first.  If it does not, then it is added to the list
+		   for probing after any Primary MultiMaster Host Adapter is probed.
+		 */
+		if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330) {
+			PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+			PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+			PrimaryProbeInfo->IO_Address = IO_Address;
+			PrimaryProbeInfo->PCI_Address = PCI_Address;
+			PrimaryProbeInfo->Bus = Bus;
+			PrimaryProbeInfo->Device = Device;
+			PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
+			PrimaryProbeInfo->PCI_Device = PCI_Device;
+			PCIMultiMasterCount++;
+		} else if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) {
+			struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+			ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+			ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+			ProbeInfo->IO_Address = IO_Address;
+			ProbeInfo->PCI_Address = PCI_Address;
+			ProbeInfo->Bus = Bus;
+			ProbeInfo->Device = Device;
+			ProbeInfo->IRQ_Channel = IRQ_Channel;
+			ProbeInfo->PCI_Device = PCI_Device;
+			NonPrimaryPCIMultiMasterCount++;
+			PCIMultiMasterCount++;
+		} else
+			BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL);
+	}
+	/*
+	   If the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option is ON
+	   for the first enumerated MultiMaster Host Adapter, and if that host adapter
+	   is a BT-948/958/958D, then the MultiMaster BIOS will recognize MultiMaster
+	   Host Adapters in the order of increasing PCI Bus and Device Number.  In
+	   that case, sort the probe information into the same order the BIOS uses.
+	   If this option is OFF, then the MultiMaster BIOS will recognize MultiMaster
+	   Host Adapters in the order they are enumerated by the PCI BIOS, and hence
+	   no sorting is necessary.
+	 */
+	if (ForceBusDeviceScanningOrder)
+		BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[NonPrimaryPCIMultiMasterIndex], NonPrimaryPCIMultiMasterCount);
+	/*
+	   If no PCI MultiMaster Host Adapter is assigned the Primary I/O Address,
+	   then the Primary I/O Address must be probed explicitly before any PCI
+	   host adapters are probed.
+	 */
+	if (!BusLogic_ProbeOptions.NoProbeISA)
+		if (PrimaryProbeInfo->IO_Address == 0 && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe330 : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)) {
+			PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+			PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+			PrimaryProbeInfo->IO_Address = 0x330;
+		}
+	/*
+	   Append the list of standard BusLogic MultiMaster ISA I/O Addresses,
+	   omitting the Primary I/O Address which has already been handled.
+	 */
+	if (!BusLogic_ProbeOptions.NoProbeISA) {
+		if (!StandardAddressSeen[1] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe334 : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+			BusLogic_AppendProbeAddressISA(0x334);
+		if (!StandardAddressSeen[2] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe230 : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+			BusLogic_AppendProbeAddressISA(0x230);
+		if (!StandardAddressSeen[3] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe234 : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+			BusLogic_AppendProbeAddressISA(0x234);
+		if (!StandardAddressSeen[4] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe130 : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+			BusLogic_AppendProbeAddressISA(0x130);
+		if (!StandardAddressSeen[5] && (BusLogic_ProbeOptions.LimitedProbeISA ? BusLogic_ProbeOptions.Probe134 : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+			BusLogic_AppendProbeAddressISA(0x134);
+	}
+	/*
+	   Iterate over the older non-compliant MultiMaster PCI Host Adapters,
+	   noting the PCI bus location and assigned IRQ Channel.
+	 */
+	PCI_Device = NULL;
+	while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_MULTIMASTER_NC, PCI_Device)) != NULL) {
+		unsigned char Bus;
+		unsigned char Device;
+		unsigned int IRQ_Channel;
+		unsigned long IO_Address;
+
+		if (pci_enable_device(PCI_Device))
+			continue;
+
+		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+			continue;
+
+		Bus = PCI_Device->bus->number;
+		Device = PCI_Device->devfn >> 3;
+		IRQ_Channel = PCI_Device->irq;
+		IO_Address = pci_resource_start(PCI_Device, 0);
+
+		if (IO_Address == 0 || IRQ_Channel == 0)
+			continue;
+		for (i = 0; i < BusLogic_ProbeInfoCount; i++) {
+			struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[i];
+			if (ProbeInfo->IO_Address == IO_Address && ProbeInfo->HostAdapterType == BusLogic_MultiMaster) {
+				ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+				ProbeInfo->PCI_Address = 0;
+				ProbeInfo->Bus = Bus;
+				ProbeInfo->Device = Device;
+				ProbeInfo->IRQ_Channel = IRQ_Channel;
+				ProbeInfo->PCI_Device = PCI_Device;
+				break;
+			}
+		}
+	}
+	return PCIMultiMasterCount;
+}
+
+
+/*
+  BusLogic_InitializeFlashPointProbeInfo initializes the list of I/O Address
+  and Bus Probe Information to be checked for potential BusLogic FlashPoint
+  Host Adapters by interrogating the PCI Configuration Space.  It returns the
+  number of FlashPoint Host Adapters found.
+*/
+
+static int __init BusLogic_InitializeFlashPointProbeInfo(struct BusLogic_HostAdapter
+							 *PrototypeHostAdapter)
+{
+	int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
+	struct pci_dev *PCI_Device = NULL;
+	/*
+	   Interrogate PCI Configuration Space for any FlashPoint Host Adapters.
+	 */
+	while ((PCI_Device = pci_find_device(PCI_VENDOR_ID_BUSLOGIC, PCI_DEVICE_ID_BUSLOGIC_FLASHPOINT, PCI_Device)) != NULL) {
+		unsigned char Bus;
+		unsigned char Device;
+		unsigned int IRQ_Channel;
+		unsigned long BaseAddress0;
+		unsigned long BaseAddress1;
+		unsigned long IO_Address;
+		unsigned long PCI_Address;
+
+		if (pci_enable_device(PCI_Device))
+			continue;
+
+		if (pci_set_dma_mask(PCI_Device, (u64) 0xffffffff))
+			continue;
+
+		Bus = PCI_Device->bus->number;
+		Device = PCI_Device->devfn >> 3;
+		IRQ_Channel = PCI_Device->irq;
+		IO_Address = BaseAddress0 = pci_resource_start(PCI_Device, 0);
+		PCI_Address = BaseAddress1 = pci_resource_start(PCI_Device, 1);
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+		if (pci_resource_flags(PCI_Device, 0) & IORESOURCE_MEM) {
+			BusLogic_Error("BusLogic: Base Address0 0x%X not I/O for " "FlashPoint Host Adapter\n", NULL, BaseAddress0);
+			BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address);
+			continue;
+		}
+		if (pci_resource_flags(PCI_Device, 1) & IORESOURCE_IO) {
+			BusLogic_Error("BusLogic: Base Address1 0x%X not Memory for " "FlashPoint Host Adapter\n", NULL, BaseAddress1);
+			BusLogic_Error("at PCI Bus %d Device %d PCI Address 0x%X\n", NULL, Bus, Device, PCI_Address);
+			continue;
+		}
+		if (IRQ_Channel == 0) {
+			BusLogic_Error("BusLogic: IRQ Channel %d invalid for " "FlashPoint Host Adapter\n", NULL, IRQ_Channel);
+			BusLogic_Error("at PCI Bus %d Device %d I/O Address 0x%X\n", NULL, Bus, Device, IO_Address);
+			continue;
+		}
+		if (BusLogic_GlobalOptions.TraceProbe) {
+			BusLogic_Notice("BusLogic: FlashPoint Host Adapter " "detected at\n", NULL);
+			BusLogic_Notice("BusLogic: PCI Bus %d Device %d I/O Address " "0x%X PCI Address 0x%X\n", NULL, Bus, Device, IO_Address, PCI_Address);
+		}
+		if (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters) {
+			struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+			ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
+			ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+			ProbeInfo->IO_Address = IO_Address;
+			ProbeInfo->PCI_Address = PCI_Address;
+			ProbeInfo->Bus = Bus;
+			ProbeInfo->Device = Device;
+			ProbeInfo->IRQ_Channel = IRQ_Channel;
+			ProbeInfo->PCI_Device = PCI_Device;
+			FlashPointCount++;
+		} else
+			BusLogic_Warning("BusLogic: Too many Host Adapters " "detected\n", NULL);
+#else
+		BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", NULL, Bus, Device);
+		BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, irq %d, " "but FlashPoint\n", NULL, IO_Address, PCI_Address, IRQ_Channel);
+		BusLogic_Error("BusLogic: support was omitted in this kernel " "configuration.\n", NULL);
+#endif
+	}
+	/*
+	   The FlashPoint BIOS will scan for FlashPoint Host Adapters in the order of
+	   increasing PCI Bus and Device Number, so sort the probe information into
+	   the same order the BIOS uses.
+	 */
+	BusLogic_SortProbeInfo(&BusLogic_ProbeInfoList[FlashPointIndex], FlashPointCount);
+	return FlashPointCount;
+}
+
+
+/*
+  BusLogic_InitializeProbeInfoList initializes the list of I/O Address and Bus
+  Probe Information to be checked for potential BusLogic SCSI Host Adapters by
+  interrogating the PCI Configuration Space on PCI machines as well as from the
+  list of standard BusLogic MultiMaster ISA I/O Addresses.  By default, if both
+  FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
+  probe for FlashPoint Host Adapters first unless the BIOS primary disk is
+  controlled by the first PCI MultiMaster Host Adapter, in which case
+  MultiMaster Host Adapters will be probed first.  The BusLogic Driver Options
+  specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force
+  a particular probe order.
+*/
+
+static void __init BusLogic_InitializeProbeInfoList(struct BusLogic_HostAdapter
+						    *PrototypeHostAdapter)
+{
+	/*
+	   If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
+	   Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
+	 */
+	if (!BusLogic_ProbeOptions.NoProbePCI) {
+		if (BusLogic_ProbeOptions.MultiMasterFirst) {
+			BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+			BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+		} else if (BusLogic_ProbeOptions.FlashPointFirst) {
+			BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+			BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+		} else {
+			int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+			int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+			if (FlashPointCount > 0 && PCIMultiMasterCount > 0) {
+				struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[FlashPointCount];
+				struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
+				struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest;
+				struct BusLogic_BIOSDriveMapByte Drive0MapByte;
+				while (ProbeInfo->HostAdapterBusType != BusLogic_PCI_Bus)
+					ProbeInfo++;
+				HostAdapter->IO_Address = ProbeInfo->IO_Address;
+				FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_BIOS_BaseOffset + BusLogic_BIOS_DriveMapOffset + 0;
+				FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(Drive0MapByte);
+				BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &Drive0MapByte, sizeof(Drive0MapByte));
+				/*
+				   If the Map Byte for BIOS Drive 0 indicates that BIOS Drive 0
+				   is controlled by this PCI MultiMaster Host Adapter, then
+				   reverse the probe order so that MultiMaster Host Adapters are
+				   probed before FlashPoint Host Adapters.
+				 */
+				if (Drive0MapByte.DiskGeometry != BusLogic_BIOS_Disk_Not_Installed) {
+					struct BusLogic_ProbeInfo SavedProbeInfo[BusLogic_MaxHostAdapters];
+					int MultiMasterCount = BusLogic_ProbeInfoCount - FlashPointCount;
+					memcpy(SavedProbeInfo, BusLogic_ProbeInfoList, BusLogic_ProbeInfoCount * sizeof(struct BusLogic_ProbeInfo));
+					memcpy(&BusLogic_ProbeInfoList[0], &SavedProbeInfo[FlashPointCount], MultiMasterCount * sizeof(struct BusLogic_ProbeInfo));
+					memcpy(&BusLogic_ProbeInfoList[MultiMasterCount], &SavedProbeInfo[0], FlashPointCount * sizeof(struct BusLogic_ProbeInfo));
+				}
+			}
+		}
+	} else
+		BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter);
+}
+
+
+#endif				/* CONFIG_PCI */
+
+
+/*
+  BusLogic_Failure prints a standardized error message, and then returns false.
+*/
+
+static boolean BusLogic_Failure(struct BusLogic_HostAdapter *HostAdapter, char *ErrorMessage)
+{
+	BusLogic_AnnounceDriver(HostAdapter);
+	if (HostAdapter->HostAdapterBusType == BusLogic_PCI_Bus) {
+		BusLogic_Error("While configuring BusLogic PCI Host Adapter at\n", HostAdapter);
+		BusLogic_Error("Bus %d Device %d I/O Address 0x%X PCI Address 0x%X:\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device, HostAdapter->IO_Address, HostAdapter->PCI_Address);
+	} else
+		BusLogic_Error("While configuring BusLogic Host Adapter at " "I/O Address 0x%X:\n", HostAdapter, HostAdapter->IO_Address);
+	BusLogic_Error("%s FAILED - DETACHING\n", HostAdapter, ErrorMessage);
+	if (BusLogic_CommandFailureReason != NULL)
+		BusLogic_Error("ADDITIONAL FAILURE INFO - %s\n", HostAdapter, BusLogic_CommandFailureReason);
+	return false;
+}
+
+
+/*
+  BusLogic_ProbeHostAdapter probes for a BusLogic Host Adapter.
+*/
+
+static boolean __init BusLogic_ProbeHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
+{
+	union BusLogic_StatusRegister StatusRegister;
+	union BusLogic_InterruptRegister InterruptRegister;
+	union BusLogic_GeometryRegister GeometryRegister;
+	/*
+	   FlashPoint Host Adapters are Probed by the FlashPoint SCCB Manager.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter)) {
+		struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo;
+		FlashPointInfo->BaseAddress = (u32) HostAdapter->IO_Address;
+		FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel;
+		FlashPointInfo->Present = false;
+		if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 && FlashPointInfo->Present)) {
+			BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at " "PCI Bus %d Device %d\n", HostAdapter, HostAdapter->Bus, HostAdapter->Device);
+			BusLogic_Error("BusLogic: I/O Address 0x%X PCI Address 0x%X, " "but FlashPoint\n", HostAdapter, HostAdapter->IO_Address, HostAdapter->PCI_Address);
+			BusLogic_Error("BusLogic: Probe Function failed to validate it.\n", HostAdapter);
+			return false;
+		}
+		if (BusLogic_GlobalOptions.TraceProbe)
+			BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n", HostAdapter, HostAdapter->IO_Address);
+		/*
+		   Indicate the Host Adapter Probe completed successfully.
+		 */
+		return true;
+	}
+	/*
+	   Read the Status, Interrupt, and Geometry Registers to test if there are I/O
+	   ports that respond, and to check the values to determine if they are from a
+	   BusLogic Host Adapter.  A nonexistent I/O port will return 0xFF, in which
+	   case there is definitely no BusLogic Host Adapter at this base I/O Address.
+	   The test here is a subset of that used by the BusLogic Host Adapter BIOS.
+	 */
+	StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+	InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+	GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter);
+	if (BusLogic_GlobalOptions.TraceProbe)
+		BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, " "Geometry 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All, InterruptRegister.All, GeometryRegister.All);
+	if (StatusRegister.All == 0 || StatusRegister.sr.DiagnosticActive || StatusRegister.sr.CommandParameterRegisterBusy || StatusRegister.sr.Reserved || StatusRegister.sr.CommandInvalid || InterruptRegister.ir.Reserved != 0)
+		return false;
+	/*
+	   Check the undocumented Geometry Register to test if there is an I/O port
+	   that responded.  Adaptec Host Adapters do not implement the Geometry
+	   Register, so this test helps serve to avoid incorrectly recognizing an
+	   Adaptec 1542A or 1542B as a BusLogic.  Unfortunately, the Adaptec 1542C
+	   series does respond to the Geometry Register I/O port, but it will be
+	   rejected later when the Inquire Extended Setup Information command is
+	   issued in BusLogic_CheckHostAdapter.  The AMI FastDisk Host Adapter is a
+	   BusLogic clone that implements the same interface as earlier BusLogic
+	   Host Adapters, including the undocumented commands, and is therefore
+	   supported by this driver.  However, the AMI FastDisk always returns 0x00
+	   upon reading the Geometry Register, so the extended translation option
+	   should always be left disabled on the AMI FastDisk.
+	 */
+	if (GeometryRegister.All == 0xFF)
+		return false;
+	/*
+	   Indicate the Host Adapter Probe completed successfully.
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter
+  and waits for Host Adapter Diagnostics to complete.  If HardReset is true, a
+  Hard Reset is performed which also initiates a SCSI Bus Reset.  Otherwise, a
+  Soft Reset is performed which only resets the Host Adapter without forcing a
+  SCSI Bus Reset.
+*/
+
+static boolean BusLogic_HardwareResetHostAdapter(struct BusLogic_HostAdapter
+						 *HostAdapter, boolean HardReset)
+{
+	union BusLogic_StatusRegister StatusRegister;
+	int TimeoutCounter;
+	/*
+	   FlashPoint Host Adapters are Hard Reset by the FlashPoint SCCB Manager.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter)) {
+		struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo;
+		FlashPointInfo->HostSoftReset = !HardReset;
+		FlashPointInfo->ReportDataUnderrun = true;
+		HostAdapter->CardHandle = FlashPoint_HardwareResetHostAdapter(FlashPointInfo);
+		if (HostAdapter->CardHandle == FlashPoint_BadCardHandle)
+			return false;
+		/*
+		   Indicate the Host Adapter Hard Reset completed successfully.
+		 */
+		return true;
+	}
+	/*
+	   Issue a Hard Reset or Soft Reset Command to the Host Adapter.  The Host
+	   Adapter should respond by setting Diagnostic Active in the Status Register.
+	 */
+	if (HardReset)
+		BusLogic_HardReset(HostAdapter);
+	else
+		BusLogic_SoftReset(HostAdapter);
+	/*
+	   Wait until Diagnostic Active is set in the Status Register.
+	 */
+	TimeoutCounter = 5 * 10000;
+	while (--TimeoutCounter >= 0) {
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (StatusRegister.sr.DiagnosticActive)
+			break;
+		udelay(100);
+	}
+	if (BusLogic_GlobalOptions.TraceHardwareReset)
+		BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All);
+	if (TimeoutCounter < 0)
+		return false;
+	/*
+	   Wait 100 microseconds to allow completion of any initial diagnostic
+	   activity which might leave the contents of the Status Register
+	   unpredictable.
+	 */
+	udelay(100);
+	/*
+	   Wait until Diagnostic Active is reset in the Status Register.
+	 */
+	TimeoutCounter = 10 * 10000;
+	while (--TimeoutCounter >= 0) {
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (!StatusRegister.sr.DiagnosticActive)
+			break;
+		udelay(100);
+	}
+	if (BusLogic_GlobalOptions.TraceHardwareReset)
+		BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All);
+	if (TimeoutCounter < 0)
+		return false;
+	/*
+	   Wait until at least one of the Diagnostic Failure, Host Adapter Ready,
+	   or Data In Register Ready bits is set in the Status Register.
+	 */
+	TimeoutCounter = 10000;
+	while (--TimeoutCounter >= 0) {
+		StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
+		if (StatusRegister.sr.DiagnosticFailure || StatusRegister.sr.HostAdapterReady || StatusRegister.sr.DataInRegisterReady)
+			break;
+		udelay(100);
+	}
+	if (BusLogic_GlobalOptions.TraceHardwareReset)
+		BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, " "Status 0x%02X\n", HostAdapter, HostAdapter->IO_Address, StatusRegister.All);
+	if (TimeoutCounter < 0)
+		return false;
+	/*
+	   If Diagnostic Failure is set or Host Adapter Ready is reset, then an
+	   error occurred during the Host Adapter diagnostics.  If Data In Register
+	   Ready is set, then there is an Error Code available.
+	 */
+	if (StatusRegister.sr.DiagnosticFailure || !StatusRegister.sr.HostAdapterReady) {
+		BusLogic_CommandFailureReason = NULL;
+		BusLogic_Failure(HostAdapter, "HARD RESET DIAGNOSTICS");
+		BusLogic_Error("HOST ADAPTER STATUS REGISTER = %02X\n", HostAdapter, StatusRegister.All);
+		if (StatusRegister.sr.DataInRegisterReady) {
+			unsigned char ErrorCode = BusLogic_ReadDataInRegister(HostAdapter);
+			BusLogic_Error("HOST ADAPTER ERROR CODE = %d\n", HostAdapter, ErrorCode);
+		}
+		return false;
+	}
+	/*
+	   Indicate the Host Adapter Hard Reset completed successfully.
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_CheckHostAdapter checks to be sure this really is a BusLogic
+  Host Adapter.
+*/
+
+static boolean __init BusLogic_CheckHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
+{
+	struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation;
+	unsigned char RequestedReplyLength;
+	boolean Result = true;
+	/*
+	   FlashPoint Host Adapters do not require this protection.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+		return true;
+	/*
+	   Issue the Inquire Extended Setup Information command.  Only genuine
+	   BusLogic Host Adapters and true clones support this command.  Adaptec 1542C
+	   series Host Adapters that respond to the Geometry Register I/O port will
+	   fail this command.
+	 */
+	RequestedReplyLength = sizeof(ExtendedSetupInformation);
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation))
+	    != sizeof(ExtendedSetupInformation))
+		Result = false;
+	/*
+	   Provide tracing information if requested and return.
+	 */
+	if (BusLogic_GlobalOptions.TraceProbe)
+		BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter, HostAdapter->IO_Address, (Result ? "Found" : "Not Found"));
+	return Result;
+}
+
+
+/*
+  BusLogic_ReadHostAdapterConfiguration reads the Configuration Information
+  from Host Adapter and initializes the Host Adapter structure.
+*/
+
+static boolean __init BusLogic_ReadHostAdapterConfiguration(struct BusLogic_HostAdapter
+							    *HostAdapter)
+{
+	struct BusLogic_BoardID BoardID;
+	struct BusLogic_Configuration Configuration;
+	struct BusLogic_SetupInformation SetupInformation;
+	struct BusLogic_ExtendedSetupInformation ExtendedSetupInformation;
+	unsigned char HostAdapterModelNumber[5];
+	unsigned char FirmwareVersion3rdDigit;
+	unsigned char FirmwareVersionLetter;
+	struct BusLogic_PCIHostAdapterInformation PCIHostAdapterInformation;
+	struct BusLogic_FetchHostAdapterLocalRAMRequest FetchHostAdapterLocalRAMRequest;
+	struct BusLogic_AutoSCSIData AutoSCSIData;
+	union BusLogic_GeometryRegister GeometryRegister;
+	unsigned char RequestedReplyLength;
+	unsigned char *TargetPointer, Character;
+	int TargetID, i;
+	/*
+	   Configuration Information for FlashPoint Host Adapters is provided in the
+	   FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function.
+	   Initialize fields in the Host Adapter structure from the FlashPoint_Info
+	   structure.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter)) {
+		struct FlashPoint_Info *FlashPointInfo = &HostAdapter->FlashPointInfo;
+		TargetPointer = HostAdapter->ModelName;
+		*TargetPointer++ = 'B';
+		*TargetPointer++ = 'T';
+		*TargetPointer++ = '-';
+		for (i = 0; i < sizeof(FlashPointInfo->ModelNumber); i++)
+			*TargetPointer++ = FlashPointInfo->ModelNumber[i];
+		*TargetPointer++ = '\0';
+		strcpy(HostAdapter->FirmwareVersion, FlashPoint_FirmwareVersion);
+		HostAdapter->SCSI_ID = FlashPointInfo->SCSI_ID;
+		HostAdapter->ExtendedTranslationEnabled = FlashPointInfo->ExtendedTranslationEnabled;
+		HostAdapter->ParityCheckingEnabled = FlashPointInfo->ParityCheckingEnabled;
+		HostAdapter->BusResetEnabled = !FlashPointInfo->HostSoftReset;
+		HostAdapter->LevelSensitiveInterrupt = true;
+		HostAdapter->HostWideSCSI = FlashPointInfo->HostWideSCSI;
+		HostAdapter->HostDifferentialSCSI = false;
+		HostAdapter->HostSupportsSCAM = true;
+		HostAdapter->HostUltraSCSI = true;
+		HostAdapter->ExtendedLUNSupport = true;
+		HostAdapter->TerminationInfoValid = true;
+		HostAdapter->LowByteTerminated = FlashPointInfo->LowByteTerminated;
+		HostAdapter->HighByteTerminated = FlashPointInfo->HighByteTerminated;
+		HostAdapter->SCAM_Enabled = FlashPointInfo->SCAM_Enabled;
+		HostAdapter->SCAM_Level2 = FlashPointInfo->SCAM_Level2;
+		HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
+		HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
+		HostAdapter->MaxLogicalUnits = 32;
+		HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+		HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
+		HostAdapter->DriverQueueDepth = 255;
+		HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth;
+		HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted;
+		HostAdapter->FastPermitted = FlashPointInfo->FastPermitted;
+		HostAdapter->UltraPermitted = FlashPointInfo->UltraPermitted;
+		HostAdapter->WidePermitted = FlashPointInfo->WidePermitted;
+		HostAdapter->DisconnectPermitted = FlashPointInfo->DisconnectPermitted;
+		HostAdapter->TaggedQueuingPermitted = 0xFFFF;
+		goto Common;
+	}
+	/*
+	   Issue the Inquire Board ID command.
+	 */
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireBoardID, NULL, 0, &BoardID, sizeof(BoardID)) != sizeof(BoardID))
+		return BusLogic_Failure(HostAdapter, "INQUIRE BOARD ID");
+	/*
+	   Issue the Inquire Configuration command.
+	 */
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration, NULL, 0, &Configuration, sizeof(Configuration))
+	    != sizeof(Configuration))
+		return BusLogic_Failure(HostAdapter, "INQUIRE CONFIGURATION");
+	/*
+	   Issue the Inquire Setup Information command.
+	 */
+	RequestedReplyLength = sizeof(SetupInformation);
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation))
+	    != sizeof(SetupInformation))
+		return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION");
+	/*
+	   Issue the Inquire Extended Setup Information command.
+	 */
+	RequestedReplyLength = sizeof(ExtendedSetupInformation);
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireExtendedSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &ExtendedSetupInformation, sizeof(ExtendedSetupInformation))
+	    != sizeof(ExtendedSetupInformation))
+		return BusLogic_Failure(HostAdapter, "INQUIRE EXTENDED SETUP INFORMATION");
+	/*
+	   Issue the Inquire Firmware Version 3rd Digit command.
+	 */
+	FirmwareVersion3rdDigit = '\0';
+	if (BoardID.FirmwareVersion1stDigit > '0')
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersion3rdDigit, NULL, 0, &FirmwareVersion3rdDigit, sizeof(FirmwareVersion3rdDigit))
+		    != sizeof(FirmwareVersion3rdDigit))
+			return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT");
+	/*
+	   Issue the Inquire Host Adapter Model Number command.
+	 */
+	if (ExtendedSetupInformation.BusType == 'A' && BoardID.FirmwareVersion1stDigit == '2')
+		/* BusLogic BT-542B ISA 2.xx */
+		strcpy(HostAdapterModelNumber, "542B");
+	else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '2' && (BoardID.FirmwareVersion2ndDigit <= '1' || (BoardID.FirmwareVersion2ndDigit == '2' && FirmwareVersion3rdDigit == '0')))
+		/* BusLogic BT-742A EISA 2.1x or 2.20 */
+		strcpy(HostAdapterModelNumber, "742A");
+	else if (ExtendedSetupInformation.BusType == 'E' && BoardID.FirmwareVersion1stDigit == '0')
+		/* AMI FastDisk EISA Series 441 0.x */
+		strcpy(HostAdapterModelNumber, "747A");
+	else {
+		RequestedReplyLength = sizeof(HostAdapterModelNumber);
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireHostAdapterModelNumber, &RequestedReplyLength, sizeof(RequestedReplyLength), &HostAdapterModelNumber, sizeof(HostAdapterModelNumber))
+		    != sizeof(HostAdapterModelNumber))
+			return BusLogic_Failure(HostAdapter, "INQUIRE HOST ADAPTER MODEL NUMBER");
+	}
+	/*
+	   BusLogic MultiMaster Host Adapters can be identified by their model number
+	   and the major version number of their firmware as follows:
+
+	   5.xx       BusLogic "W" Series Host Adapters:
+	   BT-948/958/958D
+	   4.xx       BusLogic "C" Series Host Adapters:
+	   BT-946C/956C/956CD/747C/757C/757CD/445C/545C/540CF
+	   3.xx       BusLogic "S" Series Host Adapters:
+	   BT-747S/747D/757S/757D/445S/545S/542D
+	   BT-542B/742A (revision H)
+	   2.xx       BusLogic "A" Series Host Adapters:
+	   BT-542B/742A (revision G and below)
+	   0.xx       AMI FastDisk VLB/EISA BusLogic Clone Host Adapter
+	 */
+	/*
+	   Save the Model Name and Host Adapter Name in the Host Adapter structure.
+	 */
+	TargetPointer = HostAdapter->ModelName;
+	*TargetPointer++ = 'B';
+	*TargetPointer++ = 'T';
+	*TargetPointer++ = '-';
+	for (i = 0; i < sizeof(HostAdapterModelNumber); i++) {
+		Character = HostAdapterModelNumber[i];
+		if (Character == ' ' || Character == '\0')
+			break;
+		*TargetPointer++ = Character;
+	}
+	*TargetPointer++ = '\0';
+	/*
+	   Save the Firmware Version in the Host Adapter structure.
+	 */
+	TargetPointer = HostAdapter->FirmwareVersion;
+	*TargetPointer++ = BoardID.FirmwareVersion1stDigit;
+	*TargetPointer++ = '.';
+	*TargetPointer++ = BoardID.FirmwareVersion2ndDigit;
+	if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0')
+		*TargetPointer++ = FirmwareVersion3rdDigit;
+	*TargetPointer = '\0';
+	/*
+	   Issue the Inquire Firmware Version Letter command.
+	 */
+	if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) {
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, NULL, 0, &FirmwareVersionLetter, sizeof(FirmwareVersionLetter))
+		    != sizeof(FirmwareVersionLetter))
+			return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER");
+		if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0')
+			*TargetPointer++ = FirmwareVersionLetter;
+		*TargetPointer = '\0';
+	}
+	/*
+	   Save the Host Adapter SCSI ID in the Host Adapter structure.
+	 */
+	HostAdapter->SCSI_ID = Configuration.HostAdapterID;
+	/*
+	   Determine the Bus Type and save it in the Host Adapter structure, determine
+	   and save the IRQ Channel if necessary, and determine and save the DMA
+	   Channel for ISA Host Adapters.
+	 */
+	HostAdapter->HostAdapterBusType = BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
+	if (HostAdapter->IRQ_Channel == 0) {
+		if (Configuration.IRQ_Channel9)
+			HostAdapter->IRQ_Channel = 9;
+		else if (Configuration.IRQ_Channel10)
+			HostAdapter->IRQ_Channel = 10;
+		else if (Configuration.IRQ_Channel11)
+			HostAdapter->IRQ_Channel = 11;
+		else if (Configuration.IRQ_Channel12)
+			HostAdapter->IRQ_Channel = 12;
+		else if (Configuration.IRQ_Channel14)
+			HostAdapter->IRQ_Channel = 14;
+		else if (Configuration.IRQ_Channel15)
+			HostAdapter->IRQ_Channel = 15;
+	}
+	if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus) {
+		if (Configuration.DMA_Channel5)
+			HostAdapter->DMA_Channel = 5;
+		else if (Configuration.DMA_Channel6)
+			HostAdapter->DMA_Channel = 6;
+		else if (Configuration.DMA_Channel7)
+			HostAdapter->DMA_Channel = 7;
+	}
+	/*
+	   Determine whether Extended Translation is enabled and save it in
+	   the Host Adapter structure.
+	 */
+	GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter);
+	HostAdapter->ExtendedTranslationEnabled = GeometryRegister.gr.ExtendedTranslationEnabled;
+	/*
+	   Save the Scatter Gather Limits, Level Sensitive Interrupt flag, Wide
+	   SCSI flag, Differential SCSI flag, SCAM Supported flag, and
+	   Ultra SCSI flag in the Host Adapter structure.
+	 */
+	HostAdapter->HostAdapterScatterGatherLimit = ExtendedSetupInformation.ScatterGatherLimit;
+	HostAdapter->DriverScatterGatherLimit = HostAdapter->HostAdapterScatterGatherLimit;
+	if (HostAdapter->HostAdapterScatterGatherLimit > BusLogic_ScatterGatherLimit)
+		HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
+	if (ExtendedSetupInformation.Misc.LevelSensitiveInterrupt)
+		HostAdapter->LevelSensitiveInterrupt = true;
+	HostAdapter->HostWideSCSI = ExtendedSetupInformation.HostWideSCSI;
+	HostAdapter->HostDifferentialSCSI = ExtendedSetupInformation.HostDifferentialSCSI;
+	HostAdapter->HostSupportsSCAM = ExtendedSetupInformation.HostSupportsSCAM;
+	HostAdapter->HostUltraSCSI = ExtendedSetupInformation.HostUltraSCSI;
+	/*
+	   Determine whether Extended LUN Format CCBs are supported and save the
+	   information in the Host Adapter structure.
+	 */
+	if (HostAdapter->FirmwareVersion[0] == '5' || (HostAdapter->FirmwareVersion[0] == '4' && HostAdapter->HostWideSCSI))
+		HostAdapter->ExtendedLUNSupport = true;
+	/*
+	   Issue the Inquire PCI Host Adapter Information command to read the
+	   Termination Information from "W" series MultiMaster Host Adapters.
+	 */
+	if (HostAdapter->FirmwareVersion[0] == '5') {
+		if (BusLogic_Command(HostAdapter, BusLogic_InquirePCIHostAdapterInformation, NULL, 0, &PCIHostAdapterInformation, sizeof(PCIHostAdapterInformation))
+		    != sizeof(PCIHostAdapterInformation))
+			return BusLogic_Failure(HostAdapter, "INQUIRE PCI HOST ADAPTER INFORMATION");
+		/*
+		   Save the Termination Information in the Host Adapter structure.
+		 */
+		if (PCIHostAdapterInformation.GenericInfoValid) {
+			HostAdapter->TerminationInfoValid = true;
+			HostAdapter->LowByteTerminated = PCIHostAdapterInformation.LowByteTerminated;
+			HostAdapter->HighByteTerminated = PCIHostAdapterInformation.HighByteTerminated;
+		}
+	}
+	/*
+	   Issue the Fetch Host Adapter Local RAM command to read the AutoSCSI data
+	   from "W" and "C" series MultiMaster Host Adapters.
+	 */
+	if (HostAdapter->FirmwareVersion[0] >= '4') {
+		FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset;
+		FetchHostAdapterLocalRAMRequest.ByteCount = sizeof(AutoSCSIData);
+		if (BusLogic_Command(HostAdapter, BusLogic_FetchHostAdapterLocalRAM, &FetchHostAdapterLocalRAMRequest, sizeof(FetchHostAdapterLocalRAMRequest), &AutoSCSIData, sizeof(AutoSCSIData))
+		    != sizeof(AutoSCSIData))
+			return BusLogic_Failure(HostAdapter, "FETCH HOST ADAPTER LOCAL RAM");
+		/*
+		   Save the Parity Checking Enabled, Bus Reset Enabled, and Termination
+		   Information in the Host Adapter structure.
+		 */
+		HostAdapter->ParityCheckingEnabled = AutoSCSIData.ParityCheckingEnabled;
+		HostAdapter->BusResetEnabled = AutoSCSIData.BusResetEnabled;
+		if (HostAdapter->FirmwareVersion[0] == '4') {
+			HostAdapter->TerminationInfoValid = true;
+			HostAdapter->LowByteTerminated = AutoSCSIData.LowByteTerminated;
+			HostAdapter->HighByteTerminated = AutoSCSIData.HighByteTerminated;
+		}
+		/*
+		   Save the Wide Permitted, Fast Permitted, Synchronous Permitted,
+		   Disconnect Permitted, Ultra Permitted, and SCAM Information in the
+		   Host Adapter structure.
+		 */
+		HostAdapter->WidePermitted = AutoSCSIData.WidePermitted;
+		HostAdapter->FastPermitted = AutoSCSIData.FastPermitted;
+		HostAdapter->SynchronousPermitted = AutoSCSIData.SynchronousPermitted;
+		HostAdapter->DisconnectPermitted = AutoSCSIData.DisconnectPermitted;
+		if (HostAdapter->HostUltraSCSI)
+			HostAdapter->UltraPermitted = AutoSCSIData.UltraPermitted;
+		if (HostAdapter->HostSupportsSCAM) {
+			HostAdapter->SCAM_Enabled = AutoSCSIData.SCAM_Enabled;
+			HostAdapter->SCAM_Level2 = AutoSCSIData.SCAM_Level2;
+		}
+	}
+	/*
+	   Initialize fields in the Host Adapter structure for "S" and "A" series
+	   MultiMaster Host Adapters.
+	 */
+	if (HostAdapter->FirmwareVersion[0] < '4') {
+		if (SetupInformation.SynchronousInitiationEnabled) {
+			HostAdapter->SynchronousPermitted = 0xFF;
+			if (HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus) {
+				if (ExtendedSetupInformation.Misc.FastOnEISA)
+					HostAdapter->FastPermitted = 0xFF;
+				if (strcmp(HostAdapter->ModelName, "BT-757") == 0)
+					HostAdapter->WidePermitted = 0xFF;
+			}
+		}
+		HostAdapter->DisconnectPermitted = 0xFF;
+		HostAdapter->ParityCheckingEnabled = SetupInformation.ParityCheckingEnabled;
+		HostAdapter->BusResetEnabled = true;
+	}
+	/*
+	   Determine the maximum number of Target IDs and Logical Units supported by
+	   this driver for Wide and Narrow Host Adapters.
+	 */
+	HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
+	HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
+	/*
+	   Select appropriate values for the Mailbox Count, Driver Queue Depth,
+	   Initial CCBs, and Incremental CCBs variables based on whether or not Strict
+	   Round Robin Mode is supported.  If Strict Round Robin Mode is supported,
+	   then there is no performance degradation in using the maximum possible
+	   number of Outgoing and Incoming Mailboxes and allowing the Tagged and
+	   Untagged Queue Depths to determine the actual utilization.  If Strict Round
+	   Robin Mode is not supported, then the Host Adapter must scan all the
+	   Outgoing Mailboxes whenever an Outgoing Mailbox entry is made, which can
+	   cause a substantial performance penalty.  The host adapters actually have
+	   room to store the following number of CCBs internally; that is, they can
+	   internally queue and manage this many active commands on the SCSI bus
+	   simultaneously.  Performance measurements demonstrate that the Driver Queue
+	   Depth should be set to the Mailbox Count, rather than the Host Adapter
+	   Queue Depth (internal CCB capacity), as it is more efficient to have the
+	   queued commands waiting in Outgoing Mailboxes if necessary than to block
+	   the process in the higher levels of the SCSI Subsystem.
+
+	   192          BT-948/958/958D
+	   100          BT-946C/956C/956CD/747C/757C/757CD/445C
+	   50   BT-545C/540CF
+	   30   BT-747S/747D/757S/757D/445S/545S/542D/542B/742A
+	 */
+	if (HostAdapter->FirmwareVersion[0] == '5')
+		HostAdapter->HostAdapterQueueDepth = 192;
+	else if (HostAdapter->FirmwareVersion[0] == '4')
+		HostAdapter->HostAdapterQueueDepth = (HostAdapter->HostAdapterBusType != BusLogic_ISA_Bus ? 100 : 50);
+	else
+		HostAdapter->HostAdapterQueueDepth = 30;
+	if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0) {
+		HostAdapter->StrictRoundRobinModeSupport = true;
+		HostAdapter->MailboxCount = BusLogic_MaxMailboxes;
+	} else {
+		HostAdapter->StrictRoundRobinModeSupport = false;
+		HostAdapter->MailboxCount = 32;
+	}
+	HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount;
+	HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+	HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
+	/*
+	   Tagged Queuing support is available and operates properly on all "W" series
+	   MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with
+	   firmware version 4.22 and above, and on "S" series MultiMaster Host
+	   Adapters with firmware version 3.35 and above.
+	 */
+	HostAdapter->TaggedQueuingPermitted = 0;
+	switch (HostAdapter->FirmwareVersion[0]) {
+	case '5':
+		HostAdapter->TaggedQueuingPermitted = 0xFFFF;
+		break;
+	case '4':
+		if (strcmp(HostAdapter->FirmwareVersion, "4.22") >= 0)
+			HostAdapter->TaggedQueuingPermitted = 0xFFFF;
+		break;
+	case '3':
+		if (strcmp(HostAdapter->FirmwareVersion, "3.35") >= 0)
+			HostAdapter->TaggedQueuingPermitted = 0xFFFF;
+		break;
+	}
+	/*
+	   Determine the Host Adapter BIOS Address if the BIOS is enabled and
+	   save it in the Host Adapter structure.  The BIOS is disabled if the
+	   BIOS_Address is 0.
+	 */
+	HostAdapter->BIOS_Address = ExtendedSetupInformation.BIOS_Address << 12;
+	/*
+	   ISA Host Adapters require Bounce Buffers if there is more than 16MB memory.
+	 */
+	if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus && (void *) high_memory > (void *) MAX_DMA_ADDRESS)
+		HostAdapter->BounceBuffersRequired = true;
+	/*
+	   BusLogic BT-445S Host Adapters prior to board revision E have a hardware
+	   bug whereby when the BIOS is enabled, transfers to/from the same address
+	   range the BIOS occupies modulo 16MB are handled incorrectly.  Only properly
+	   functioning BT-445S Host Adapters have firmware version 3.37, so require
+	   that ISA Bounce Buffers be used for the buggy BT-445S models if there is
+	   more than 16MB memory.
+	 */
+	if (HostAdapter->BIOS_Address > 0 && strcmp(HostAdapter->ModelName, "BT-445S") == 0 && strcmp(HostAdapter->FirmwareVersion, "3.37") < 0 && (void *) high_memory > (void *) MAX_DMA_ADDRESS)
+		HostAdapter->BounceBuffersRequired = true;
+	/*
+	   Initialize parameters common to MultiMaster and FlashPoint Host Adapters.
+	 */
+      Common:
+	/*
+	   Initialize the Host Adapter Full Model Name from the Model Name.
+	 */
+	strcpy(HostAdapter->FullModelName, "BusLogic ");
+	strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
+	/*
+	   Select an appropriate value for the Tagged Queue Depth either from a
+	   BusLogic Driver Options specification, or based on whether this Host
+	   Adapter requires that ISA Bounce Buffers be used.  The Tagged Queue Depth
+	   is left at 0 for automatic determination in BusLogic_SelectQueueDepths.
+	   Initialize the Untagged Queue Depth.
+	 */
+	for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) {
+		unsigned char QueueDepth = 0;
+		if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->QueueDepth[TargetID] > 0)
+			QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID];
+		else if (HostAdapter->BounceBuffersRequired)
+			QueueDepth = BusLogic_TaggedQueueDepthBB;
+		HostAdapter->QueueDepth[TargetID] = QueueDepth;
+	}
+	if (HostAdapter->BounceBuffersRequired)
+		HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
+	else
+		HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
+	if (HostAdapter->DriverOptions != NULL)
+		HostAdapter->CommonQueueDepth = HostAdapter->DriverOptions->CommonQueueDepth;
+	if (HostAdapter->CommonQueueDepth > 0 && HostAdapter->CommonQueueDepth < HostAdapter->UntaggedQueueDepth)
+		HostAdapter->UntaggedQueueDepth = HostAdapter->CommonQueueDepth;
+	/*
+	   Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
+	   Therefore, mask the Tagged Queuing Permitted Default bits with the
+	   Disconnect/Reconnect Permitted bits.
+	 */
+	HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted;
+	/*
+	   Combine the default Tagged Queuing Permitted bits with any BusLogic Driver
+	   Options Tagged Queuing specification.
+	 */
+	if (HostAdapter->DriverOptions != NULL)
+		HostAdapter->TaggedQueuingPermitted =
+		    (HostAdapter->DriverOptions->TaggedQueuingPermitted & HostAdapter->DriverOptions->TaggedQueuingPermittedMask) | (HostAdapter->TaggedQueuingPermitted & ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask);
+
+	/*
+	   Select an appropriate value for Bus Settle Time either from a BusLogic
+	   Driver Options specification, or from BusLogic_DefaultBusSettleTime.
+	 */
+	if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->BusSettleTime > 0)
+		HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime;
+	else
+		HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
+	/*
+	   Indicate reading the Host Adapter Configuration completed successfully.
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_ReportHostAdapterConfiguration reports the configuration of
+  Host Adapter.
+*/
+
+static boolean __init BusLogic_ReportHostAdapterConfiguration(struct BusLogic_HostAdapter
+							      *HostAdapter)
+{
+	unsigned short AllTargetsMask = (1 << HostAdapter->MaxTargetDevices) - 1;
+	unsigned short SynchronousPermitted, FastPermitted;
+	unsigned short UltraPermitted, WidePermitted;
+	unsigned short DisconnectPermitted, TaggedQueuingPermitted;
+	boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth;
+	char SynchronousString[BusLogic_MaxTargetDevices + 1];
+	char WideString[BusLogic_MaxTargetDevices + 1];
+	char DisconnectString[BusLogic_MaxTargetDevices + 1];
+	char TaggedQueuingString[BusLogic_MaxTargetDevices + 1];
+	char *SynchronousMessage = SynchronousString;
+	char *WideMessage = WideString;
+	char *DisconnectMessage = DisconnectString;
+	char *TaggedQueuingMessage = TaggedQueuingString;
+	int TargetID;
+	BusLogic_Info("Configuring BusLogic Model %s %s%s%s%s SCSI Host Adapter\n",
+		      HostAdapter, HostAdapter->ModelName,
+		      BusLogic_HostAdapterBusNames[HostAdapter->HostAdapterBusType], (HostAdapter->HostWideSCSI ? " Wide" : ""), (HostAdapter->HostDifferentialSCSI ? " Differential" : ""), (HostAdapter->HostUltraSCSI ? " Ultra" : ""));
+	BusLogic_Info("  Firmware Version: %s, I/O Address: 0x%X, " "IRQ Channel: %d/%s\n", HostAdapter, HostAdapter->FirmwareVersion, HostAdapter->IO_Address, HostAdapter->IRQ_Channel, (HostAdapter->LevelSensitiveInterrupt ? "Level" : "Edge"));
+	if (HostAdapter->HostAdapterBusType != BusLogic_PCI_Bus) {
+		BusLogic_Info("  DMA Channel: ", HostAdapter);
+		if (HostAdapter->DMA_Channel > 0)
+			BusLogic_Info("%d, ", HostAdapter, HostAdapter->DMA_Channel);
+		else
+			BusLogic_Info("None, ", HostAdapter);
+		if (HostAdapter->BIOS_Address > 0)
+			BusLogic_Info("BIOS Address: 0x%X, ", HostAdapter, HostAdapter->BIOS_Address);
+		else
+			BusLogic_Info("BIOS Address: None, ", HostAdapter);
+	} else {
+		BusLogic_Info("  PCI Bus: %d, Device: %d, Address: ", HostAdapter, HostAdapter->Bus, HostAdapter->Device);
+		if (HostAdapter->PCI_Address > 0)
+			BusLogic_Info("0x%X, ", HostAdapter, HostAdapter->PCI_Address);
+		else
+			BusLogic_Info("Unassigned, ", HostAdapter);
+	}
+	BusLogic_Info("Host Adapter SCSI ID: %d\n", HostAdapter, HostAdapter->SCSI_ID);
+	BusLogic_Info("  Parity Checking: %s, Extended Translation: %s\n", HostAdapter, (HostAdapter->ParityCheckingEnabled ? "Enabled" : "Disabled"), (HostAdapter->ExtendedTranslationEnabled ? "Enabled" : "Disabled"));
+	AllTargetsMask &= ~(1 << HostAdapter->SCSI_ID);
+	SynchronousPermitted = HostAdapter->SynchronousPermitted & AllTargetsMask;
+	FastPermitted = HostAdapter->FastPermitted & AllTargetsMask;
+	UltraPermitted = HostAdapter->UltraPermitted & AllTargetsMask;
+	if ((BusLogic_MultiMasterHostAdapterP(HostAdapter) && (HostAdapter->FirmwareVersion[0] >= '4' || HostAdapter->HostAdapterBusType == BusLogic_EISA_Bus)) || BusLogic_FlashPointHostAdapterP(HostAdapter)) {
+		CommonSynchronousNegotiation = false;
+		if (SynchronousPermitted == 0) {
+			SynchronousMessage = "Disabled";
+			CommonSynchronousNegotiation = true;
+		} else if (SynchronousPermitted == AllTargetsMask) {
+			if (FastPermitted == 0) {
+				SynchronousMessage = "Slow";
+				CommonSynchronousNegotiation = true;
+			} else if (FastPermitted == AllTargetsMask) {
+				if (UltraPermitted == 0) {
+					SynchronousMessage = "Fast";
+					CommonSynchronousNegotiation = true;
+				} else if (UltraPermitted == AllTargetsMask) {
+					SynchronousMessage = "Ultra";
+					CommonSynchronousNegotiation = true;
+				}
+			}
+		}
+		if (!CommonSynchronousNegotiation) {
+			for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+				SynchronousString[TargetID] = ((!(SynchronousPermitted & (1 << TargetID))) ? 'N' : (!(FastPermitted & (1 << TargetID)) ? 'S' : (!(UltraPermitted & (1 << TargetID)) ? 'F' : 'U')));
+			SynchronousString[HostAdapter->SCSI_ID] = '#';
+			SynchronousString[HostAdapter->MaxTargetDevices] = '\0';
+		}
+	} else
+		SynchronousMessage = (SynchronousPermitted == 0 ? "Disabled" : "Enabled");
+	WidePermitted = HostAdapter->WidePermitted & AllTargetsMask;
+	if (WidePermitted == 0)
+		WideMessage = "Disabled";
+	else if (WidePermitted == AllTargetsMask)
+		WideMessage = "Enabled";
+	else {
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			WideString[TargetID] = ((WidePermitted & (1 << TargetID)) ? 'Y' : 'N');
+		WideString[HostAdapter->SCSI_ID] = '#';
+		WideString[HostAdapter->MaxTargetDevices] = '\0';
+	}
+	DisconnectPermitted = HostAdapter->DisconnectPermitted & AllTargetsMask;
+	if (DisconnectPermitted == 0)
+		DisconnectMessage = "Disabled";
+	else if (DisconnectPermitted == AllTargetsMask)
+		DisconnectMessage = "Enabled";
+	else {
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			DisconnectString[TargetID] = ((DisconnectPermitted & (1 << TargetID)) ? 'Y' : 'N');
+		DisconnectString[HostAdapter->SCSI_ID] = '#';
+		DisconnectString[HostAdapter->MaxTargetDevices] = '\0';
+	}
+	TaggedQueuingPermitted = HostAdapter->TaggedQueuingPermitted & AllTargetsMask;
+	if (TaggedQueuingPermitted == 0)
+		TaggedQueuingMessage = "Disabled";
+	else if (TaggedQueuingPermitted == AllTargetsMask)
+		TaggedQueuingMessage = "Enabled";
+	else {
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			TaggedQueuingString[TargetID] = ((TaggedQueuingPermitted & (1 << TargetID)) ? 'Y' : 'N');
+		TaggedQueuingString[HostAdapter->SCSI_ID] = '#';
+		TaggedQueuingString[HostAdapter->MaxTargetDevices] = '\0';
+	}
+	BusLogic_Info("  Synchronous Negotiation: %s, Wide Negotiation: %s\n", HostAdapter, SynchronousMessage, WideMessage);
+	BusLogic_Info("  Disconnect/Reconnect: %s, Tagged Queuing: %s\n", HostAdapter, DisconnectMessage, TaggedQueuingMessage);
+	if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) {
+		BusLogic_Info("  Scatter/Gather Limit: %d of %d segments, " "Mailboxes: %d\n", HostAdapter, HostAdapter->DriverScatterGatherLimit, HostAdapter->HostAdapterScatterGatherLimit, HostAdapter->MailboxCount);
+		BusLogic_Info("  Driver Queue Depth: %d, " "Host Adapter Queue Depth: %d\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->HostAdapterQueueDepth);
+	} else
+		BusLogic_Info("  Driver Queue Depth: %d, " "Scatter/Gather Limit: %d segments\n", HostAdapter, HostAdapter->DriverQueueDepth, HostAdapter->DriverScatterGatherLimit);
+	BusLogic_Info("  Tagged Queue Depth: ", HostAdapter);
+	CommonTaggedQueueDepth = true;
+	for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+		if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0]) {
+			CommonTaggedQueueDepth = false;
+			break;
+		}
+	if (CommonTaggedQueueDepth) {
+		if (HostAdapter->QueueDepth[0] > 0)
+			BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]);
+		else
+			BusLogic_Info("Automatic", HostAdapter);
+	} else
+		BusLogic_Info("Individual", HostAdapter);
+	BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter, HostAdapter->UntaggedQueueDepth);
+	if (HostAdapter->TerminationInfoValid) {
+		if (HostAdapter->HostWideSCSI)
+			BusLogic_Info("  SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? (HostAdapter->HighByteTerminated ? "Both Enabled" : "Low Enabled")
+										  : (HostAdapter->HighByteTerminated ? "High Enabled" : "Both Disabled")));
+		else
+			BusLogic_Info("  SCSI Bus Termination: %s", HostAdapter, (HostAdapter->LowByteTerminated ? "Enabled" : "Disabled"));
+		if (HostAdapter->HostSupportsSCAM)
+			BusLogic_Info(", SCAM: %s", HostAdapter, (HostAdapter->SCAM_Enabled ? (HostAdapter->SCAM_Level2 ? "Enabled, Level 2" : "Enabled, Level 1")
+								  : "Disabled"));
+		BusLogic_Info("\n", HostAdapter);
+	}
+	/*
+	   Indicate reporting the Host Adapter configuration completed successfully.
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_AcquireResources acquires the system resources necessary to use
+  Host Adapter.
+*/
+
+static boolean __init BusLogic_AcquireResources(struct BusLogic_HostAdapter *HostAdapter)
+{
+	if (HostAdapter->IRQ_Channel == 0) {
+		BusLogic_Error("NO LEGAL INTERRUPT CHANNEL ASSIGNED - DETACHING\n", HostAdapter);
+		return false;
+	}
+	/*
+	   Acquire shared access to the IRQ Channel.
+	 */
+	if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_SHIRQ, HostAdapter->FullModelName, HostAdapter) < 0) {
+		BusLogic_Error("UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->IRQ_Channel);
+		return false;
+	}
+	HostAdapter->IRQ_ChannelAcquired = true;
+	/*
+	   Acquire exclusive access to the DMA Channel.
+	 */
+	if (HostAdapter->DMA_Channel > 0) {
+		if (request_dma(HostAdapter->DMA_Channel, HostAdapter->FullModelName) < 0) {
+			BusLogic_Error("UNABLE TO ACQUIRE DMA CHANNEL %d - DETACHING\n", HostAdapter, HostAdapter->DMA_Channel);
+			return false;
+		}
+		set_dma_mode(HostAdapter->DMA_Channel, DMA_MODE_CASCADE);
+		enable_dma(HostAdapter->DMA_Channel);
+		HostAdapter->DMA_ChannelAcquired = true;
+	}
+	/*
+	   Indicate the System Resource Acquisition completed successfully,
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_ReleaseResources releases any system resources previously acquired
+  by BusLogic_AcquireResources.
+*/
+
+static void BusLogic_ReleaseResources(struct BusLogic_HostAdapter *HostAdapter)
+{
+	/*
+	   Release shared access to the IRQ Channel.
+	 */
+	if (HostAdapter->IRQ_ChannelAcquired)
+		free_irq(HostAdapter->IRQ_Channel, HostAdapter);
+	/*
+	   Release exclusive access to the DMA Channel.
+	 */
+	if (HostAdapter->DMA_ChannelAcquired)
+		free_dma(HostAdapter->DMA_Channel);
+	/*
+	   Release any allocated memory structs not released elsewhere
+	 */
+	if (HostAdapter->MailboxSpace)
+		pci_free_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, HostAdapter->MailboxSpace, HostAdapter->MailboxSpaceHandle);
+	HostAdapter->MailboxSpace = NULL;
+	HostAdapter->MailboxSpaceHandle = 0;
+	HostAdapter->MailboxSize = 0;
+}
+
+
+/*
+  BusLogic_InitializeHostAdapter initializes Host Adapter.  This is the only
+  function called during SCSI Host Adapter detection which modifies the state
+  of the Host Adapter from its initial power on or hard reset state.
+*/
+
+static boolean BusLogic_InitializeHostAdapter(struct BusLogic_HostAdapter
+					      *HostAdapter)
+{
+	struct BusLogic_ExtendedMailboxRequest ExtendedMailboxRequest;
+	enum BusLogic_RoundRobinModeRequest RoundRobinModeRequest;
+	enum BusLogic_SetCCBFormatRequest SetCCBFormatRequest;
+	int TargetID;
+	/*
+	   Initialize the pointers to the first and last CCBs that are queued for
+	   completion processing.
+	 */
+	HostAdapter->FirstCompletedCCB = NULL;
+	HostAdapter->LastCompletedCCB = NULL;
+	/*
+	   Initialize the Bus Device Reset Pending CCB, Tagged Queuing Active,
+	   Command Successful Flag, Active Commands, and Commands Since Reset
+	   for each Target Device.
+	 */
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+		HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
+		HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
+		HostAdapter->ActiveCommands[TargetID] = 0;
+		HostAdapter->CommandsSinceReset[TargetID] = 0;
+	}
+	/*
+	   FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+		goto Done;
+	/*
+	   Initialize the Outgoing and Incoming Mailbox pointers.
+	 */
+	HostAdapter->MailboxSize = HostAdapter->MailboxCount * (sizeof(struct BusLogic_OutgoingMailbox) + sizeof(struct BusLogic_IncomingMailbox));
+	HostAdapter->MailboxSpace = pci_alloc_consistent(HostAdapter->PCI_Device, HostAdapter->MailboxSize, &HostAdapter->MailboxSpaceHandle);
+	if (HostAdapter->MailboxSpace == NULL)
+		return BusLogic_Failure(HostAdapter, "MAILBOX ALLOCATION");
+	HostAdapter->FirstOutgoingMailbox = (struct BusLogic_OutgoingMailbox *) HostAdapter->MailboxSpace;
+	HostAdapter->LastOutgoingMailbox = HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+	HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
+	HostAdapter->FirstIncomingMailbox = (struct BusLogic_IncomingMailbox *) (HostAdapter->LastOutgoingMailbox + 1);
+	HostAdapter->LastIncomingMailbox = HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+	HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
+
+	/*
+	   Initialize the Outgoing and Incoming Mailbox structures.
+	 */
+	memset(HostAdapter->FirstOutgoingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_OutgoingMailbox));
+	memset(HostAdapter->FirstIncomingMailbox, 0, HostAdapter->MailboxCount * sizeof(struct BusLogic_IncomingMailbox));
+	/*
+	   Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
+	 */
+	ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
+	ExtendedMailboxRequest.BaseMailboxAddress = (u32) HostAdapter->MailboxSpaceHandle;
+	if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0)
+		return BusLogic_Failure(HostAdapter, "MAILBOX INITIALIZATION");
+	/*
+	   Enable Strict Round Robin Mode if supported by the Host Adapter.  In
+	   Strict Round Robin Mode, the Host Adapter only looks at the next Outgoing
+	   Mailbox for each new command, rather than scanning through all the
+	   Outgoing Mailboxes to find any that have new commands in them.  Strict
+	   Round Robin Mode is significantly more efficient.
+	 */
+	if (HostAdapter->StrictRoundRobinModeSupport) {
+		RoundRobinModeRequest = BusLogic_StrictRoundRobinMode;
+		if (BusLogic_Command(HostAdapter, BusLogic_EnableStrictRoundRobinMode, &RoundRobinModeRequest, sizeof(RoundRobinModeRequest), NULL, 0) < 0)
+			return BusLogic_Failure(HostAdapter, "ENABLE STRICT ROUND ROBIN MODE");
+	}
+	/*
+	   For Host Adapters that support Extended LUN Format CCBs, issue the Set CCB
+	   Format command to allow 32 Logical Units per Target Device.
+	 */
+	if (HostAdapter->ExtendedLUNSupport) {
+		SetCCBFormatRequest = BusLogic_ExtendedLUNFormatCCB;
+		if (BusLogic_Command(HostAdapter, BusLogic_SetCCBFormat, &SetCCBFormatRequest, sizeof(SetCCBFormatRequest), NULL, 0) < 0)
+			return BusLogic_Failure(HostAdapter, "SET CCB FORMAT");
+	}
+	/*
+	   Announce Successful Initialization.
+	 */
+      Done:
+	if (!HostAdapter->HostAdapterInitialized) {
+		BusLogic_Info("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName);
+		BusLogic_Info("\n", HostAdapter);
+	} else
+		BusLogic_Warning("*** %s Initialized Successfully ***\n", HostAdapter, HostAdapter->FullModelName);
+	HostAdapter->HostAdapterInitialized = true;
+	/*
+	   Indicate the Host Adapter Initialization completed successfully.
+	 */
+	return true;
+}
+
+
+/*
+  BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible
+  through Host Adapter.
+*/
+
+static boolean __init BusLogic_TargetDeviceInquiry(struct BusLogic_HostAdapter
+						   *HostAdapter)
+{
+	u16 InstalledDevices;
+	u8 InstalledDevicesID0to7[8];
+	struct BusLogic_SetupInformation SetupInformation;
+	u8 SynchronousPeriod[BusLogic_MaxTargetDevices];
+	unsigned char RequestedReplyLength;
+	int TargetID;
+	/*
+	   Wait a few seconds between the Host Adapter Hard Reset which initiates
+	   a SCSI Bus Reset and issuing any SCSI Commands.  Some SCSI devices get
+	   confused if they receive SCSI Commands too soon after a SCSI Bus Reset.
+	 */
+	BusLogic_Delay(HostAdapter->BusSettleTime);
+	/*
+	   FlashPoint Host Adapters do not provide for Target Device Inquiry.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+		return true;
+	/*
+	   Inhibit the Target Device Inquiry if requested.
+	 */
+	if (HostAdapter->DriverOptions != NULL && HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+		return true;
+	/*
+	   Issue the Inquire Target Devices command for host adapters with firmware
+	   version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command
+	   for older host adapters.  This is necessary to force Synchronous Transfer
+	   Negotiation so that the Inquire Setup Information and Inquire Synchronous
+	   Period commands will return valid data.  The Inquire Target Devices command
+	   is preferable to Inquire Installed Devices ID 0 to 7 since it only probes
+	   Logical Unit 0 of each Target Device.
+	 */
+	if (strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) {
+
+		/*
+		 * Issue a Inquire Target Devices command.  Inquire Target Devices only
+		 * tests Logical Unit 0 of each Target Device unlike the Inquire Installed
+		 * Devices commands which test Logical Units 0 - 7.  Two bytes are
+		 * returned, where byte 0 bit 0 set indicates that Target Device 0 exists,
+		 * and so on.
+		 */
+
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireTargetDevices, NULL, 0, &InstalledDevices, sizeof(InstalledDevices))
+		    != sizeof(InstalledDevices))
+			return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES");
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevices & (1 << TargetID) ? true : false);
+	} else {
+
+		/*
+		 * Issue an Inquire Installed Devices command.  For each Target Device,
+		 * a byte is returned where bit 0 set indicates that Logical Unit 0
+		 * exists, bit 1 set indicates that Logical Unit 1 exists, and so on.
+		 */
+
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireInstalledDevicesID0to7, NULL, 0, &InstalledDevicesID0to7, sizeof(InstalledDevicesID0to7))
+		    != sizeof(InstalledDevicesID0to7))
+			return BusLogic_Failure(HostAdapter, "INQUIRE INSTALLED DEVICES ID 0 TO 7");
+		for (TargetID = 0; TargetID < 8; TargetID++)
+			HostAdapter->TargetFlags[TargetID].TargetExists = (InstalledDevicesID0to7[TargetID] != 0 ? true : false);
+	}
+	/*
+	   Issue the Inquire Setup Information command.
+	 */
+	RequestedReplyLength = sizeof(SetupInformation);
+	if (BusLogic_Command(HostAdapter, BusLogic_InquireSetupInformation, &RequestedReplyLength, sizeof(RequestedReplyLength), &SetupInformation, sizeof(SetupInformation))
+	    != sizeof(SetupInformation))
+		return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+		HostAdapter->SynchronousOffset[TargetID] = (TargetID < 8 ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset : SetupInformation.SynchronousValuesID8to15[TargetID - 8].Offset);
+	if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0)
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			HostAdapter->TargetFlags[TargetID].WideTransfersActive = (TargetID < 8 ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID)
+												  ? true : false)
+										  : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID - 8))
+										     ? true : false));
+	/*
+	   Issue the Inquire Synchronous Period command.
+	 */
+	if (HostAdapter->FirmwareVersion[0] >= '3') {
+
+		/* Issue a Inquire Synchronous Period command.  For each Target Device,
+		 * a byte is returned which represents the Synchronous Transfer Period
+		 * in units of 10 nanoseconds.
+		 */
+
+		RequestedReplyLength = sizeof(SynchronousPeriod);
+		if (BusLogic_Command(HostAdapter, BusLogic_InquireSynchronousPeriod, &RequestedReplyLength, sizeof(RequestedReplyLength), &SynchronousPeriod, sizeof(SynchronousPeriod))
+		    != sizeof(SynchronousPeriod))
+			return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID];
+	} else
+		for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+			if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
+				HostAdapter->SynchronousPeriod[TargetID] = 20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
+				    .TransferPeriod;
+	/*
+	   Indicate the Target Device Inquiry completed successfully.
+	 */
+	return true;
+}
+
+/*
+  BusLogic_InitializeHostStructure initializes the fields in the SCSI Host
+  structure.  The base, io_port, n_io_ports, irq, and dma_channel fields in the
+  SCSI Host structure are intentionally left uninitialized, as this driver
+  handles acquisition and release of these resources explicitly, as well as
+  ensuring exclusive access to the Host Adapter hardware and data structures
+  through explicit acquisition and release of the Host Adapter's Lock.
+*/
+
+static void __init BusLogic_InitializeHostStructure(struct BusLogic_HostAdapter
+						    *HostAdapter, struct Scsi_Host *Host)
+{
+	Host->max_id = HostAdapter->MaxTargetDevices;
+	Host->max_lun = HostAdapter->MaxLogicalUnits;
+	Host->max_channel = 0;
+	Host->unique_id = HostAdapter->IO_Address;
+	Host->this_id = HostAdapter->SCSI_ID;
+	Host->can_queue = HostAdapter->DriverQueueDepth;
+	Host->sg_tablesize = HostAdapter->DriverScatterGatherLimit;
+	Host->unchecked_isa_dma = HostAdapter->BounceBuffersRequired;
+	Host->cmd_per_lun = HostAdapter->UntaggedQueueDepth;
+}
+
+/*
+  BusLogic_SlaveConfigure will actually set the queue depth on individual
+  scsi devices as they are permanently added to the device chain.  We
+  shamelessly rip off the SelectQueueDepths code to make this work mostly
+  like it used to.  Since we don't get called once at the end of the scan
+  but instead get called for each device, we have to do things a bit
+  differently.
+*/
+static int BusLogic_SlaveConfigure(struct scsi_device *Device)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Device->host->hostdata;
+	int TargetID = Device->id;
+	int QueueDepth = HostAdapter->QueueDepth[TargetID];
+
+	if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) {
+		if (QueueDepth == 0)
+			QueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+		HostAdapter->QueueDepth[TargetID] = QueueDepth;
+		scsi_adjust_queue_depth(Device, MSG_SIMPLE_TAG, QueueDepth);
+	} else {
+		HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
+		QueueDepth = HostAdapter->UntaggedQueueDepth;
+		HostAdapter->QueueDepth[TargetID] = QueueDepth;
+		scsi_adjust_queue_depth(Device, 0, QueueDepth);
+	}
+	QueueDepth = 0;
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+		if (HostAdapter->TargetFlags[TargetID].TargetExists) {
+			QueueDepth += HostAdapter->QueueDepth[TargetID];
+		}
+	if (QueueDepth > HostAdapter->AllocatedCCBs)
+		BusLogic_CreateAdditionalCCBs(HostAdapter, QueueDepth - HostAdapter->AllocatedCCBs, false);
+	return 0;
+}
+
+/*
+  BusLogic_DetectHostAdapter probes for BusLogic Host Adapters at the standard
+  I/O Addresses where they may be located, initializing, registering, and
+  reporting the configuration of each BusLogic Host Adapter it finds.  It
+  returns the number of BusLogic Host Adapters successfully initialized and
+  registered.
+*/
+
+static int __init BusLogic_init(void)
+{
+	int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
+	struct BusLogic_HostAdapter *PrototypeHostAdapter;
+
+#ifdef MODULE
+	if (BusLogic)
+		BusLogic_Setup(BusLogic);
+#endif
+
+	if (BusLogic_ProbeOptions.NoProbe)
+		return -ENODEV;
+	BusLogic_ProbeInfoList = (struct BusLogic_ProbeInfo *)
+	    kmalloc(BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo), GFP_ATOMIC);
+	if (BusLogic_ProbeInfoList == NULL) {
+		BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
+		return -ENOMEM;
+	}
+	memset(BusLogic_ProbeInfoList, 0, BusLogic_MaxHostAdapters * sizeof(struct BusLogic_ProbeInfo));
+	PrototypeHostAdapter = (struct BusLogic_HostAdapter *)
+	    kmalloc(sizeof(struct BusLogic_HostAdapter), GFP_ATOMIC);
+	if (PrototypeHostAdapter == NULL) {
+		kfree(BusLogic_ProbeInfoList);
+		BusLogic_Error("BusLogic: Unable to allocate Prototype " "Host Adapter\n", NULL);
+		return -ENOMEM;
+	}
+	memset(PrototypeHostAdapter, 0, sizeof(struct BusLogic_HostAdapter));
+#ifdef MODULE
+	if (BusLogic != NULL)
+		BusLogic_Setup(BusLogic);
+#endif
+	BusLogic_InitializeProbeInfoList(PrototypeHostAdapter);
+	for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++) {
+		struct BusLogic_ProbeInfo *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex];
+		struct BusLogic_HostAdapter *HostAdapter = PrototypeHostAdapter;
+		struct Scsi_Host *Host;
+		if (ProbeInfo->IO_Address == 0)
+			continue;
+		memset(HostAdapter, 0, sizeof(struct BusLogic_HostAdapter));
+		HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType;
+		HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType;
+		HostAdapter->IO_Address = ProbeInfo->IO_Address;
+		HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
+		HostAdapter->Bus = ProbeInfo->Bus;
+		HostAdapter->Device = ProbeInfo->Device;
+		HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
+		HostAdapter->AddressCount = BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
+		/*
+		   Probe the Host Adapter.  If unsuccessful, abort further initialization.
+		 */
+		if (!BusLogic_ProbeHostAdapter(HostAdapter))
+			continue;
+		/*
+		   Hard Reset the Host Adapter.  If unsuccessful, abort further
+		   initialization.
+		 */
+		if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true))
+			continue;
+		/*
+		   Check the Host Adapter.  If unsuccessful, abort further initialization.
+		 */
+		if (!BusLogic_CheckHostAdapter(HostAdapter))
+			continue;
+		/*
+		   Initialize the Driver Options field if provided.
+		 */
+		if (DriverOptionsIndex < BusLogic_DriverOptionsCount)
+			HostAdapter->DriverOptions = &BusLogic_DriverOptions[DriverOptionsIndex++];
+		/*
+		   Announce the Driver Version and Date, Author's Name, Copyright Notice,
+		   and Electronic Mail Address.
+		 */
+		BusLogic_AnnounceDriver(HostAdapter);
+		/*
+		   Register usage of the I/O Address range.  From this point onward, any
+		   failure will be assumed to be due to a problem with the Host Adapter,
+		   rather than due to having mistakenly identified this port as belonging
+		   to a BusLogic Host Adapter.  The I/O Address range will not be
+		   released, thereby preventing it from being incorrectly identified as
+		   any other type of Host Adapter.
+		 */
+		if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, "BusLogic"))
+			continue;
+		/*
+		   Register the SCSI Host structure.
+		 */
+
+		Host = scsi_host_alloc(&Bus_Logic_template, sizeof(struct BusLogic_HostAdapter));
+		if (Host == NULL) {
+			release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
+			continue;
+		}
+		HostAdapter = (struct BusLogic_HostAdapter *) Host->hostdata;
+		memcpy(HostAdapter, PrototypeHostAdapter, sizeof(struct BusLogic_HostAdapter));
+		HostAdapter->SCSI_Host = Host;
+		HostAdapter->HostNumber = Host->host_no;
+		/*
+		   Add Host Adapter to the end of the list of registered BusLogic
+		   Host Adapters.
+		 */
+		list_add_tail(&HostAdapter->host_list, &BusLogic_host_list);
+
+		/*
+		   Read the Host Adapter Configuration, Configure the Host Adapter,
+		   Acquire the System Resources necessary to use the Host Adapter, then
+		   Create the Initial CCBs, Initialize the Host Adapter, and finally
+		   perform Target Device Inquiry.
+		 */
+		if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
+		    BusLogic_ReportHostAdapterConfiguration(HostAdapter) && BusLogic_AcquireResources(HostAdapter) && BusLogic_CreateInitialCCBs(HostAdapter) && BusLogic_InitializeHostAdapter(HostAdapter) && BusLogic_TargetDeviceInquiry(HostAdapter)) {
+			/*
+			   Initialization has been completed successfully.  Release and
+			   re-register usage of the I/O Address range so that the Model
+			   Name of the Host Adapter will appear, and initialize the SCSI
+			   Host structure.
+			 */
+			release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
+			if (!request_region(HostAdapter->IO_Address, HostAdapter->AddressCount, HostAdapter->FullModelName)) {
+				printk(KERN_WARNING "BusLogic: Release and re-register of " "port 0x%04lx failed \n", (unsigned long) HostAdapter->IO_Address);
+				BusLogic_DestroyCCBs(HostAdapter);
+				BusLogic_ReleaseResources(HostAdapter);
+				list_del(&HostAdapter->host_list);
+				scsi_host_put(Host);
+			} else {
+				BusLogic_InitializeHostStructure(HostAdapter, Host);
+				scsi_add_host(Host, NULL);
+				scsi_scan_host(Host);
+				BusLogicHostAdapterCount++;
+			}
+		} else {
+			/*
+			   An error occurred during Host Adapter Configuration Querying, Host
+			   Adapter Configuration, Resource Acquisition, CCB Creation, Host
+			   Adapter Initialization, or Target Device Inquiry, so remove Host
+			   Adapter from the list of registered BusLogic Host Adapters, destroy
+			   the CCBs, Release the System Resources, and Unregister the SCSI
+			   Host.
+			 */
+			BusLogic_DestroyCCBs(HostAdapter);
+			BusLogic_ReleaseResources(HostAdapter);
+			list_del(&HostAdapter->host_list);
+			scsi_host_put(Host);
+		}
+	}
+	kfree(PrototypeHostAdapter);
+	kfree(BusLogic_ProbeInfoList);
+	BusLogic_ProbeInfoList = NULL;
+	return 0;
+}
+
+
+/*
+  BusLogic_ReleaseHostAdapter releases all resources previously acquired to
+  support a specific Host Adapter, including the I/O Address range, and
+  unregisters the BusLogic Host Adapter.
+*/
+
+static int __exit BusLogic_ReleaseHostAdapter(struct BusLogic_HostAdapter *HostAdapter)
+{
+	struct Scsi_Host *Host = HostAdapter->SCSI_Host;
+
+	scsi_remove_host(Host);
+
+	/*
+	   FlashPoint Host Adapters must first be released by the FlashPoint
+	   SCCB Manager.
+	 */
+	if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+		FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
+	/*
+	   Destroy the CCBs and release any system resources acquired to
+	   support Host Adapter.
+	 */
+	BusLogic_DestroyCCBs(HostAdapter);
+	BusLogic_ReleaseResources(HostAdapter);
+	/*
+	   Release usage of the I/O Address range.
+	 */
+	release_region(HostAdapter->IO_Address, HostAdapter->AddressCount);
+	/*
+	   Remove Host Adapter from the list of registered BusLogic Host Adapters.
+	 */
+	list_del(&HostAdapter->host_list);
+
+	scsi_host_put(Host);
+	return 0;
+}
+
+
+/*
+  BusLogic_QueueCompletedCCB queues CCB for completion processing.
+*/
+
+static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *CCB)
+{
+	struct BusLogic_HostAdapter *HostAdapter = CCB->HostAdapter;
+	CCB->Status = BusLogic_CCB_Completed;
+	CCB->Next = NULL;
+	if (HostAdapter->FirstCompletedCCB == NULL) {
+		HostAdapter->FirstCompletedCCB = CCB;
+		HostAdapter->LastCompletedCCB = CCB;
+	} else {
+		HostAdapter->LastCompletedCCB->Next = CCB;
+		HostAdapter->LastCompletedCCB = CCB;
+	}
+	HostAdapter->ActiveCommands[CCB->TargetID]--;
+}
+
+
+/*
+  BusLogic_ComputeResultCode computes a SCSI Subsystem Result Code from
+  the Host Adapter Status and Target Device Status.
+*/
+
+static int BusLogic_ComputeResultCode(struct BusLogic_HostAdapter *HostAdapter, enum BusLogic_HostAdapterStatus HostAdapterStatus, enum BusLogic_TargetDeviceStatus TargetDeviceStatus)
+{
+	int HostStatus;
+	switch (HostAdapterStatus) {
+	case BusLogic_CommandCompletedNormally:
+	case BusLogic_LinkedCommandCompleted:
+	case BusLogic_LinkedCommandCompletedWithFlag:
+		HostStatus = DID_OK;
+		break;
+	case BusLogic_SCSISelectionTimeout:
+		HostStatus = DID_TIME_OUT;
+		break;
+	case BusLogic_InvalidOutgoingMailboxActionCode:
+	case BusLogic_InvalidCommandOperationCode:
+	case BusLogic_InvalidCommandParameter:
+		BusLogic_Warning("BusLogic Driver Protocol Error 0x%02X\n", HostAdapter, HostAdapterStatus);
+	case BusLogic_DataUnderRun:
+	case BusLogic_DataOverRun:
+	case BusLogic_UnexpectedBusFree:
+	case BusLogic_LinkedCCBhasInvalidLUN:
+	case BusLogic_AutoRequestSenseFailed:
+	case BusLogic_TaggedQueuingMessageRejected:
+	case BusLogic_UnsupportedMessageReceived:
+	case BusLogic_HostAdapterHardwareFailed:
+	case BusLogic_TargetDeviceReconnectedImproperly:
+	case BusLogic_AbortQueueGenerated:
+	case BusLogic_HostAdapterSoftwareError:
+	case BusLogic_HostAdapterHardwareTimeoutError:
+	case BusLogic_SCSIParityErrorDetected:
+		HostStatus = DID_ERROR;
+		break;
+	case BusLogic_InvalidBusPhaseRequested:
+	case BusLogic_TargetFailedResponseToATN:
+	case BusLogic_HostAdapterAssertedRST:
+	case BusLogic_OtherDeviceAssertedRST:
+	case BusLogic_HostAdapterAssertedBusDeviceReset:
+		HostStatus = DID_RESET;
+		break;
+	default:
+		BusLogic_Warning("Unknown Host Adapter Status 0x%02X\n", HostAdapter, HostAdapterStatus);
+		HostStatus = DID_ERROR;
+		break;
+	}
+	return (HostStatus << 16) | TargetDeviceStatus;
+}
+
+
+/*
+  BusLogic_ScanIncomingMailboxes scans the Incoming Mailboxes saving any
+  Incoming Mailbox entries for completion processing.
+*/
+
+static void BusLogic_ScanIncomingMailboxes(struct BusLogic_HostAdapter *HostAdapter)
+{
+	/*
+	   Scan through the Incoming Mailboxes in Strict Round Robin fashion, saving
+	   any completed CCBs for further processing.  It is essential that for each
+	   CCB and SCSI Command issued, command completion processing is performed
+	   exactly once.  Therefore, only Incoming Mailboxes with completion code
+	   Command Completed Without Error, Command Completed With Error, or Command
+	   Aborted At Host Request are saved for completion processing.  When an
+	   Incoming Mailbox has a completion code of Aborted Command Not Found, the
+	   CCB had already completed or been aborted before the current Abort request
+	   was processed, and so completion processing has already occurred and no
+	   further action should be taken.
+	 */
+	struct BusLogic_IncomingMailbox *NextIncomingMailbox = HostAdapter->NextIncomingMailbox;
+	enum BusLogic_CompletionCode CompletionCode;
+	while ((CompletionCode = NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) {
+		/*
+		   We are only allowed to do this because we limit our architectures we
+		   run on to machines where bus_to_virt() actually works.  There *needs*
+		   to be a dma_addr_to_virt() in the new PCI DMA mapping interface to
+		   replace bus_to_virt() or else this code is going to become very
+		   innefficient.
+		 */
+		struct BusLogic_CCB *CCB = (struct BusLogic_CCB *) Bus_to_Virtual(NextIncomingMailbox->CCB);
+		if (CompletionCode != BusLogic_AbortedCommandNotFound) {
+			if (CCB->Status == BusLogic_CCB_Active || CCB->Status == BusLogic_CCB_Reset) {
+				/*
+				   Save the Completion Code for this CCB and queue the CCB
+				   for completion processing.
+				 */
+				CCB->CompletionCode = CompletionCode;
+				BusLogic_QueueCompletedCCB(CCB);
+			} else {
+				/*
+				   If a CCB ever appears in an Incoming Mailbox and is not marked
+				   as status Active or Reset, then there is most likely a bug in
+				   the Host Adapter firmware.
+				 */
+				BusLogic_Warning("Illegal CCB #%ld status %d in " "Incoming Mailbox\n", HostAdapter, CCB->SerialNumber, CCB->Status);
+			}
+		}
+		NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree;
+		if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox)
+			NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
+	}
+	HostAdapter->NextIncomingMailbox = NextIncomingMailbox;
+}
+
+
+/*
+  BusLogic_ProcessCompletedCCBs iterates over the completed CCBs for Host
+  Adapter setting the SCSI Command Result Codes, deallocating the CCBs, and
+  calling the SCSI Subsystem Completion Routines.  The Host Adapter's Lock
+  should already have been acquired by the caller.
+*/
+
+static void BusLogic_ProcessCompletedCCBs(struct BusLogic_HostAdapter *HostAdapter)
+{
+	if (HostAdapter->ProcessCompletedCCBsActive)
+		return;
+	HostAdapter->ProcessCompletedCCBsActive = true;
+	while (HostAdapter->FirstCompletedCCB != NULL) {
+		struct BusLogic_CCB *CCB = HostAdapter->FirstCompletedCCB;
+		struct scsi_cmnd *Command = CCB->Command;
+		HostAdapter->FirstCompletedCCB = CCB->Next;
+		if (HostAdapter->FirstCompletedCCB == NULL)
+			HostAdapter->LastCompletedCCB = NULL;
+		/*
+		   Process the Completed CCB.
+		 */
+		if (CCB->Opcode == BusLogic_BusDeviceReset) {
+			int TargetID = CCB->TargetID;
+			BusLogic_Warning("Bus Device Reset CCB #%ld to Target " "%d Completed\n", HostAdapter, CCB->SerialNumber, TargetID);
+			BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted);
+			HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
+			HostAdapter->CommandsSinceReset[TargetID] = 0;
+			HostAdapter->LastResetCompleted[TargetID] = jiffies;
+			/*
+			   Place CCB back on the Host Adapter's free list.
+			 */
+			BusLogic_DeallocateCCB(CCB);
+#if 0				/* this needs to be redone different for new EH */
+			/*
+			   Bus Device Reset CCBs have the Command field non-NULL only when a
+			   Bus Device Reset was requested for a Command that did not have a
+			   currently active CCB in the Host Adapter (i.e., a Synchronous
+			   Bus Device Reset), and hence would not have its Completion Routine
+			   called otherwise.
+			 */
+			while (Command != NULL) {
+				struct scsi_cmnd *NextCommand = Command->reset_chain;
+				Command->reset_chain = NULL;
+				Command->result = DID_RESET << 16;
+				Command->scsi_done(Command);
+				Command = NextCommand;
+			}
+#endif
+			/*
+			   Iterate over the CCBs for this Host Adapter performing completion
+			   processing for any CCBs marked as Reset for this Target.
+			 */
+			for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+				if (CCB->Status == BusLogic_CCB_Reset && CCB->TargetID == TargetID) {
+					Command = CCB->Command;
+					BusLogic_DeallocateCCB(CCB);
+					HostAdapter->ActiveCommands[TargetID]--;
+					Command->result = DID_RESET << 16;
+					Command->scsi_done(Command);
+				}
+			HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+		} else {
+			/*
+			   Translate the Completion Code, Host Adapter Status, and Target
+			   Device Status into a SCSI Subsystem Result Code.
+			 */
+			switch (CCB->CompletionCode) {
+			case BusLogic_IncomingMailboxFree:
+			case BusLogic_AbortedCommandNotFound:
+			case BusLogic_InvalidCCB:
+				BusLogic_Warning("CCB #%ld to Target %d Impossible State\n", HostAdapter, CCB->SerialNumber, CCB->TargetID);
+				break;
+			case BusLogic_CommandCompletedWithoutError:
+				HostAdapter->TargetStatistics[CCB->TargetID]
+				    .CommandsCompleted++;
+				HostAdapter->TargetFlags[CCB->TargetID]
+				    .CommandSuccessfulFlag = true;
+				Command->result = DID_OK << 16;
+				break;
+			case BusLogic_CommandAbortedAtHostRequest:
+				BusLogic_Warning("CCB #%ld to Target %d Aborted\n", HostAdapter, CCB->SerialNumber, CCB->TargetID);
+				BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[CCB->TargetID]
+							       .CommandAbortsCompleted);
+				Command->result = DID_ABORT << 16;
+				break;
+			case BusLogic_CommandCompletedWithError:
+				Command->result = BusLogic_ComputeResultCode(HostAdapter, CCB->HostAdapterStatus, CCB->TargetDeviceStatus);
+				if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) {
+					HostAdapter->TargetStatistics[CCB->TargetID]
+					    .CommandsCompleted++;
+					if (BusLogic_GlobalOptions.TraceErrors) {
+						int i;
+						BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
+								"Adapter Status %02X " "Target Status %02X\n", HostAdapter, CCB->SerialNumber, CCB->TargetID, Command->result, CCB->HostAdapterStatus, CCB->TargetDeviceStatus);
+						BusLogic_Notice("CDB   ", HostAdapter);
+						for (i = 0; i < CCB->CDB_Length; i++)
+							BusLogic_Notice(" %02X", HostAdapter, CCB->CDB[i]);
+						BusLogic_Notice("\n", HostAdapter);
+						BusLogic_Notice("Sense ", HostAdapter);
+						for (i = 0; i < CCB->SenseDataLength; i++)
+							BusLogic_Notice(" %02X", HostAdapter, Command->sense_buffer[i]);
+						BusLogic_Notice("\n", HostAdapter);
+					}
+				}
+				break;
+			}
+			/*
+			   When an INQUIRY command completes normally, save the
+			   CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit
+			   Wide Data Transfers Supported) bits.
+			 */
+			if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 && CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally) {
+				struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[CCB->TargetID];
+				struct SCSI_Inquiry *InquiryResult = (struct SCSI_Inquiry *) Command->request_buffer;
+				TargetFlags->TargetExists = true;
+				TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
+				TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
+			}
+			/*
+			   Place CCB back on the Host Adapter's free list.
+			 */
+			BusLogic_DeallocateCCB(CCB);
+			/*
+			   Call the SCSI Command Completion Routine.
+			 */
+			Command->scsi_done(Command);
+		}
+	}
+	HostAdapter->ProcessCompletedCCBsActive = false;
+}
+
+
+/*
+  BusLogic_InterruptHandler handles hardware interrupts from BusLogic Host
+  Adapters.
+*/
+
+static irqreturn_t BusLogic_InterruptHandler(int IRQ_Channel, void *DeviceIdentifier, struct pt_regs *InterruptRegisters)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) DeviceIdentifier;
+	unsigned long ProcessorFlags;
+	/*
+	   Acquire exclusive access to Host Adapter.
+	 */
+	spin_lock_irqsave(HostAdapter->SCSI_Host->host_lock, ProcessorFlags);
+	/*
+	   Handle Interrupts appropriately for each Host Adapter type.
+	 */
+	if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) {
+		union BusLogic_InterruptRegister InterruptRegister;
+		/*
+		   Read the Host Adapter Interrupt Register.
+		 */
+		InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
+		if (InterruptRegister.ir.InterruptValid) {
+			/*
+			   Acknowledge the interrupt and reset the Host Adapter
+			   Interrupt Register.
+			 */
+			BusLogic_InterruptReset(HostAdapter);
+			/*
+			   Process valid External SCSI Bus Reset and Incoming Mailbox
+			   Loaded Interrupts.  Command Complete Interrupts are noted,
+			   and Outgoing Mailbox Available Interrupts are ignored, as
+			   they are never enabled.
+			 */
+			if (InterruptRegister.ir.ExternalBusReset)
+				HostAdapter->HostAdapterExternalReset = true;
+			else if (InterruptRegister.ir.IncomingMailboxLoaded)
+				BusLogic_ScanIncomingMailboxes(HostAdapter);
+			else if (InterruptRegister.ir.CommandComplete)
+				HostAdapter->HostAdapterCommandCompleted = true;
+		}
+	} else {
+		/*
+		   Check if there is a pending interrupt for this Host Adapter.
+		 */
+		if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
+			switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)) {
+			case FlashPoint_NormalInterrupt:
+				break;
+			case FlashPoint_ExternalBusReset:
+				HostAdapter->HostAdapterExternalReset = true;
+				break;
+			case FlashPoint_InternalError:
+				BusLogic_Warning("Internal FlashPoint Error detected" " - Resetting Host Adapter\n", HostAdapter);
+				HostAdapter->HostAdapterInternalError = true;
+				break;
+			}
+	}
+	/*
+	   Process any completed CCBs.
+	 */
+	if (HostAdapter->FirstCompletedCCB != NULL)
+		BusLogic_ProcessCompletedCCBs(HostAdapter);
+	/*
+	   Reset the Host Adapter if requested.
+	 */
+	if (HostAdapter->HostAdapterExternalReset) {
+		BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n", HostAdapter, HostAdapter->FullModelName);
+		BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
+		BusLogic_ResetHostAdapter(HostAdapter, false);
+		HostAdapter->HostAdapterExternalReset = false;
+	} else if (HostAdapter->HostAdapterInternalError) {
+		BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n", HostAdapter, HostAdapter->FullModelName);
+		BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors);
+		BusLogic_ResetHostAdapter(HostAdapter, true);
+		HostAdapter->HostAdapterInternalError = false;
+	}
+	/*
+	   Release exclusive access to Host Adapter.
+	 */
+	spin_unlock_irqrestore(HostAdapter->SCSI_Host->host_lock, ProcessorFlags);
+	return IRQ_HANDLED;
+}
+
+
+/*
+  BusLogic_WriteOutgoingMailbox places CCB and Action Code into an Outgoing
+  Mailbox for execution by Host Adapter.  The Host Adapter's Lock should
+  already have been acquired by the caller.
+*/
+
+static boolean BusLogic_WriteOutgoingMailbox(struct BusLogic_HostAdapter
+					     *HostAdapter, enum BusLogic_ActionCode ActionCode, struct BusLogic_CCB *CCB)
+{
+	struct BusLogic_OutgoingMailbox *NextOutgoingMailbox;
+	NextOutgoingMailbox = HostAdapter->NextOutgoingMailbox;
+	if (NextOutgoingMailbox->ActionCode == BusLogic_OutgoingMailboxFree) {
+		CCB->Status = BusLogic_CCB_Active;
+		/*
+		   The CCB field must be written before the Action Code field since
+		   the Host Adapter is operating asynchronously and the locking code
+		   does not protect against simultaneous access by the Host Adapter.
+		 */
+		NextOutgoingMailbox->CCB = CCB->DMA_Handle;
+		NextOutgoingMailbox->ActionCode = ActionCode;
+		BusLogic_StartMailboxCommand(HostAdapter);
+		if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox)
+			NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
+		HostAdapter->NextOutgoingMailbox = NextOutgoingMailbox;
+		if (ActionCode == BusLogic_MailboxStartCommand) {
+			HostAdapter->ActiveCommands[CCB->TargetID]++;
+			if (CCB->Opcode != BusLogic_BusDeviceReset)
+				HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++;
+		}
+		return true;
+	}
+	return false;
+}
+
+/* Error Handling (EH) support */
+
+static int BusLogic_host_reset(struct scsi_cmnd * SCpnt)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) SCpnt->device->host->hostdata;
+
+	unsigned int id = SCpnt->device->id;
+	struct BusLogic_TargetStatistics *stats = &HostAdapter->TargetStatistics[id];
+	BusLogic_IncrementErrorCounter(&stats->HostAdapterResetsRequested);
+
+	return BusLogic_ResetHostAdapter(HostAdapter, false);
+}
+
+/*
+  BusLogic_QueueCommand creates a CCB for Command and places it into an
+  Outgoing Mailbox for execution by the associated Host Adapter.
+*/
+
+static int BusLogic_QueueCommand(struct scsi_cmnd *Command, void (*CompletionRoutine) (struct scsi_cmnd *))
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata;
+	struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[Command->device->id];
+	struct BusLogic_TargetStatistics *TargetStatistics = HostAdapter->TargetStatistics;
+	unsigned char *CDB = Command->cmnd;
+	int CDB_Length = Command->cmd_len;
+	int TargetID = Command->device->id;
+	int LogicalUnit = Command->device->lun;
+	void *BufferPointer = Command->request_buffer;
+	int BufferLength = Command->request_bufflen;
+	int SegmentCount = Command->use_sg;
+	struct BusLogic_CCB *CCB;
+	/*
+	   SCSI REQUEST_SENSE commands will be executed automatically by the Host
+	   Adapter for any errors, so they should not be executed explicitly unless
+	   the Sense Data is zero indicating that no error occurred.
+	 */
+	if (CDB[0] == REQUEST_SENSE && Command->sense_buffer[0] != 0) {
+		Command->result = DID_OK << 16;
+		CompletionRoutine(Command);
+		return 0;
+	}
+	/*
+	   Allocate a CCB from the Host Adapter's free list.  In the unlikely event
+	   that there are none available and memory allocation fails, wait 1 second
+	   and try again.  If that fails, the Host Adapter is probably hung so signal
+	   an error as a Host Adapter Hard Reset should be initiated soon.
+	 */
+	CCB = BusLogic_AllocateCCB(HostAdapter);
+	if (CCB == NULL) {
+		spin_unlock_irq(HostAdapter->SCSI_Host->host_lock);
+		BusLogic_Delay(1);
+		spin_lock_irq(HostAdapter->SCSI_Host->host_lock);
+		CCB = BusLogic_AllocateCCB(HostAdapter);
+		if (CCB == NULL) {
+			Command->result = DID_ERROR << 16;
+			CompletionRoutine(Command);
+			return 0;
+		}
+	}
+	/*
+	   Initialize the fields in the BusLogic Command Control Block (CCB).
+	 */
+	if (SegmentCount == 0 && BufferLength != 0) {
+		CCB->Opcode = BusLogic_InitiatorCCB;
+		CCB->DataLength = BufferLength;
+		CCB->DataPointer = pci_map_single(HostAdapter->PCI_Device,
+				BufferPointer, BufferLength,
+				Command->sc_data_direction);
+	} else if (SegmentCount != 0) {
+		struct scatterlist *ScatterList = (struct scatterlist *) BufferPointer;
+		int Segment, Count;
+
+		Count = pci_map_sg(HostAdapter->PCI_Device, ScatterList, SegmentCount,
+				Command->sc_data_direction);
+		CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
+		CCB->DataLength = Count * sizeof(struct BusLogic_ScatterGatherSegment);
+		if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
+			CCB->DataPointer = (unsigned int) CCB->DMA_Handle + ((unsigned long) &CCB->ScatterGatherList - (unsigned long) CCB);
+		else
+			CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
+		for (Segment = 0; Segment < Count; Segment++) {
+			CCB->ScatterGatherList[Segment].SegmentByteCount = sg_dma_len(ScatterList + Segment);
+			CCB->ScatterGatherList[Segment].SegmentDataPointer = sg_dma_address(ScatterList + Segment);
+		}
+	} else {
+		CCB->Opcode = BusLogic_InitiatorCCB;
+		CCB->DataLength = BufferLength;
+		CCB->DataPointer = 0;
+	}
+	switch (CDB[0]) {
+	case READ_6:
+	case READ_10:
+		CCB->DataDirection = BusLogic_DataInLengthChecked;
+		TargetStatistics[TargetID].ReadCommands++;
+		BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesRead, BufferLength);
+		BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength);
+		break;
+	case WRITE_6:
+	case WRITE_10:
+		CCB->DataDirection = BusLogic_DataOutLengthChecked;
+		TargetStatistics[TargetID].WriteCommands++;
+		BusLogic_IncrementByteCounter(&TargetStatistics[TargetID].TotalBytesWritten, BufferLength);
+		BusLogic_IncrementSizeBucket(TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength);
+		break;
+	default:
+		CCB->DataDirection = BusLogic_UncheckedDataTransfer;
+		break;
+	}
+	CCB->CDB_Length = CDB_Length;
+	CCB->HostAdapterStatus = 0;
+	CCB->TargetDeviceStatus = 0;
+	CCB->TargetID = TargetID;
+	CCB->LogicalUnit = LogicalUnit;
+	CCB->TagEnable = false;
+	CCB->LegacyTagEnable = false;
+	/*
+	   BusLogic recommends that after a Reset the first couple of commands that
+	   are sent to a Target Device be sent in a non Tagged Queue fashion so that
+	   the Host Adapter and Target Device can establish Synchronous and Wide
+	   Transfer before Queue Tag messages can interfere with the Synchronous and
+	   Wide Negotiation messages.  By waiting to enable Tagged Queuing until after
+	   the first BusLogic_MaxTaggedQueueDepth commands have been queued, it is
+	   assured that after a Reset any pending commands are requeued before Tagged
+	   Queuing is enabled and that the Tagged Queuing message will not occur while
+	   the partition table is being printed.  In addition, some devices do not
+	   properly handle the transition from non-tagged to tagged commands, so it is
+	   necessary to wait until there are no pending commands for a target device
+	   before queuing tagged commands.
+	 */
+	if (HostAdapter->CommandsSinceReset[TargetID]++ >=
+	    BusLogic_MaxTaggedQueueDepth && !TargetFlags->TaggedQueuingActive && HostAdapter->ActiveCommands[TargetID] == 0 && TargetFlags->TaggedQueuingSupported && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID))) {
+		TargetFlags->TaggedQueuingActive = true;
+		BusLogic_Notice("Tagged Queuing now active for Target %d\n", HostAdapter, TargetID);
+	}
+	if (TargetFlags->TaggedQueuingActive) {
+		enum BusLogic_QueueTag QueueTag = BusLogic_SimpleQueueTag;
+		/*
+		   When using Tagged Queuing with Simple Queue Tags, it appears that disk
+		   drive controllers do not guarantee that a queued command will not
+		   remain in a disconnected state indefinitely if commands that read or
+		   write nearer the head position continue to arrive without interruption.
+		   Therefore, for each Target Device this driver keeps track of the last
+		   time either the queue was empty or an Ordered Queue Tag was issued.  If
+		   more than 4 seconds (one fifth of the 20 second disk timeout) have
+		   elapsed since this last sequence point, this command will be issued
+		   with an Ordered Queue Tag rather than a Simple Queue Tag, which forces
+		   the Target Device to complete all previously queued commands before
+		   this command may be executed.
+		 */
+		if (HostAdapter->ActiveCommands[TargetID] == 0)
+			HostAdapter->LastSequencePoint[TargetID] = jiffies;
+		else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4 * HZ) {
+			HostAdapter->LastSequencePoint[TargetID] = jiffies;
+			QueueTag = BusLogic_OrderedQueueTag;
+		}
+		if (HostAdapter->ExtendedLUNSupport) {
+			CCB->TagEnable = true;
+			CCB->QueueTag = QueueTag;
+		} else {
+			CCB->LegacyTagEnable = true;
+			CCB->LegacyQueueTag = QueueTag;
+		}
+	}
+	memcpy(CCB->CDB, CDB, CDB_Length);
+	CCB->SenseDataLength = sizeof(Command->sense_buffer);
+	CCB->SenseDataPointer = pci_map_single(HostAdapter->PCI_Device, Command->sense_buffer, CCB->SenseDataLength, PCI_DMA_FROMDEVICE);
+	CCB->Command = Command;
+	Command->scsi_done = CompletionRoutine;
+	if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) {
+		/*
+		   Place the CCB in an Outgoing Mailbox.  The higher levels of the SCSI
+		   Subsystem should not attempt to queue more commands than can be placed
+		   in Outgoing Mailboxes, so there should always be one free.  In the
+		   unlikely event that there are none available, wait 1 second and try
+		   again.  If that fails, the Host Adapter is probably hung so signal an
+		   error as a Host Adapter Hard Reset should be initiated soon.
+		 */
+		if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) {
+			spin_unlock_irq(HostAdapter->SCSI_Host->host_lock);
+			BusLogic_Warning("Unable to write Outgoing Mailbox - " "Pausing for 1 second\n", HostAdapter);
+			BusLogic_Delay(1);
+			spin_lock_irq(HostAdapter->SCSI_Host->host_lock);
+			if (!BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxStartCommand, CCB)) {
+				BusLogic_Warning("Still unable to write Outgoing Mailbox - " "Host Adapter Dead?\n", HostAdapter);
+				BusLogic_DeallocateCCB(CCB);
+				Command->result = DID_ERROR << 16;
+				Command->scsi_done(Command);
+			}
+		}
+	} else {
+		/*
+		   Call the FlashPoint SCCB Manager to start execution of the CCB.
+		 */
+		CCB->Status = BusLogic_CCB_Active;
+		HostAdapter->ActiveCommands[TargetID]++;
+		TargetStatistics[TargetID].CommandsAttempted++;
+		FlashPoint_StartCCB(HostAdapter->CardHandle, CCB);
+		/*
+		   The Command may have already completed and BusLogic_QueueCompletedCCB
+		   been called, or it may still be pending.
+		 */
+		if (CCB->Status == BusLogic_CCB_Completed)
+			BusLogic_ProcessCompletedCCBs(HostAdapter);
+	}
+	return 0;
+}
+
+
+/*
+  BusLogic_AbortCommand aborts Command if possible.
+*/
+
+static int BusLogic_AbortCommand(struct scsi_cmnd *Command)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) Command->device->host->hostdata;
+
+	int TargetID = Command->device->id;
+	struct BusLogic_CCB *CCB;
+	BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested);
+	/*
+	   If this Command has already completed, then no Abort is necessary.
+	 */
+	if (Command->serial_number != Command->serial_number_at_timeout) {
+		BusLogic_Warning("Unable to Abort Command to Target %d - " "Already Completed\n", HostAdapter, TargetID);
+		return SUCCESS;
+	}
+	/*
+	   Attempt to find an Active CCB for this Command.  If no Active CCB for this
+	   Command is found, then no Abort is necessary.
+	 */
+	for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+		if (CCB->Command == Command)
+			break;
+	if (CCB == NULL) {
+		BusLogic_Warning("Unable to Abort Command to Target %d - " "No CCB Found\n", HostAdapter, TargetID);
+		return SUCCESS;
+	} else if (CCB->Status == BusLogic_CCB_Completed) {
+		BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Completed\n", HostAdapter, TargetID);
+		return SUCCESS;
+	} else if (CCB->Status == BusLogic_CCB_Reset) {
+		BusLogic_Warning("Unable to Abort Command to Target %d - " "CCB Reset\n", HostAdapter, TargetID);
+		return SUCCESS;
+	}
+	if (BusLogic_MultiMasterHostAdapterP(HostAdapter)) {
+		/*
+		   Attempt to Abort this CCB.  MultiMaster Firmware versions prior to 5.xx
+		   do not generate Abort Tag messages, but only generate the non-tagged
+		   Abort message.  Since non-tagged commands are not sent by the Host
+		   Adapter until the queue of outstanding tagged commands has completed,
+		   and the Abort message is treated as a non-tagged command, it is
+		   effectively impossible to abort commands when Tagged Queuing is active.
+		   Firmware version 5.xx does generate Abort Tag messages, so it is
+		   possible to abort commands when Tagged Queuing is active.
+		 */
+		if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive && HostAdapter->FirmwareVersion[0] < '5') {
+			BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "Abort Tag Not Supported\n", HostAdapter, CCB->SerialNumber, TargetID);
+			return FAILURE;
+		} else if (BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxAbortCommand, CCB)) {
+			BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID);
+			BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
+			return SUCCESS;
+		} else {
+			BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - " "No Outgoing Mailboxes\n", HostAdapter, CCB->SerialNumber, TargetID);
+			return FAILURE;
+		}
+	} else {
+		/*
+		   Call the FlashPoint SCCB Manager to abort execution of the CCB.
+		 */
+		BusLogic_Warning("Aborting CCB #%ld to Target %d\n", HostAdapter, CCB->SerialNumber, TargetID);
+		BusLogic_IncrementErrorCounter(&HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
+		FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB);
+		/*
+		   The Abort may have already been completed and
+		   BusLogic_QueueCompletedCCB been called, or it
+		   may still be pending.
+		 */
+		if (CCB->Status == BusLogic_CCB_Completed) {
+			BusLogic_ProcessCompletedCCBs(HostAdapter);
+		}
+		return SUCCESS;
+	}
+	return SUCCESS;
+}
+
+/*
+  BusLogic_ResetHostAdapter resets Host Adapter if possible, marking all
+  currently executing SCSI Commands as having been Reset.
+*/
+
+static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *HostAdapter, boolean HardReset)
+{
+	struct BusLogic_CCB *CCB;
+	int TargetID;
+
+	/*
+	 * Attempt to Reset and Reinitialize the Host Adapter.
+	 */
+
+	if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) && BusLogic_InitializeHostAdapter(HostAdapter))) {
+		BusLogic_Error("Resetting %s Failed\n", HostAdapter, HostAdapter->FullModelName);
+		return FAILURE;
+	}
+
+	/*
+	 * Deallocate all currently executing CCBs.
+	 */
+
+	for (CCB = HostAdapter->All_CCBs; CCB != NULL; CCB = CCB->NextAll)
+		if (CCB->Status == BusLogic_CCB_Active)
+			BusLogic_DeallocateCCB(CCB);
+	/*
+	 * Wait a few seconds between the Host Adapter Hard Reset which
+	 * initiates a SCSI Bus Reset and issuing any SCSI Commands.  Some
+	 * SCSI devices get confused if they receive SCSI Commands too soon
+	 * after a SCSI Bus Reset.
+	 */
+
+	if (HardReset) {
+		spin_unlock_irq(HostAdapter->SCSI_Host->host_lock);
+		BusLogic_Delay(HostAdapter->BusSettleTime);
+		spin_lock_irq(HostAdapter->SCSI_Host->host_lock);
+	}
+
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		HostAdapter->LastResetAttempted[TargetID] = jiffies;
+		HostAdapter->LastResetCompleted[TargetID] = jiffies;
+	}
+	return SUCCESS;
+}
+
+/*
+  BusLogic_BIOSDiskParameters returns the Heads/Sectors/Cylinders BIOS Disk
+  Parameters for Disk.  The default disk geometry is 64 heads, 32 sectors, and
+  the appropriate number of cylinders so as not to exceed drive capacity.  In
+  order for disks equal to or larger than 1 GB to be addressable by the BIOS
+  without exceeding the BIOS limitation of 1024 cylinders, Extended Translation
+  may be enabled in AutoSCSI on FlashPoint Host Adapters and on "W" and "C"
+  series MultiMaster Host Adapters, or by a dip switch setting on "S" and "A"
+  series MultiMaster Host Adapters.  With Extended Translation enabled, drives
+  between 1 GB inclusive and 2 GB exclusive are given a disk geometry of 128
+  heads and 32 sectors, and drives above 2 GB inclusive are given a disk
+  geometry of 255 heads and 63 sectors.  However, if the BIOS detects that the
+  Extended Translation setting does not match the geometry in the partition
+  table, then the translation inferred from the partition table will be used by
+  the BIOS, and a warning may be displayed.
+*/
+
+static int BusLogic_BIOSDiskParameters(struct scsi_device *sdev, struct block_device *Device, sector_t capacity, int *Parameters)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) sdev->host->hostdata;
+	struct BIOS_DiskParameters *DiskParameters = (struct BIOS_DiskParameters *) Parameters;
+	unsigned char *buf;
+	if (HostAdapter->ExtendedTranslationEnabled && capacity >= 2 * 1024 * 1024 /* 1 GB in 512 byte sectors */ ) {
+		if (capacity >= 4 * 1024 * 1024 /* 2 GB in 512 byte sectors */ ) {
+			DiskParameters->Heads = 255;
+			DiskParameters->Sectors = 63;
+		} else {
+			DiskParameters->Heads = 128;
+			DiskParameters->Sectors = 32;
+		}
+	} else {
+		DiskParameters->Heads = 64;
+		DiskParameters->Sectors = 32;
+	}
+	DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+	buf = scsi_bios_ptable(Device);
+	if (buf == NULL)
+		return 0;
+	/*
+	   If the boot sector partition table flag is valid, search for a partition
+	   table entry whose end_head matches one of the standard BusLogic geometry
+	   translations (64/32, 128/32, or 255/63).
+	 */
+	if (*(unsigned short *) (buf + 64) == 0xAA55) {
+		struct partition *FirstPartitionEntry = (struct partition *) buf;
+		struct partition *PartitionEntry = FirstPartitionEntry;
+		int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+		unsigned char PartitionEntryEndHead = 0, PartitionEntryEndSector = 0;
+		for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++) {
+			PartitionEntryEndHead = PartitionEntry->end_head;
+			PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F;
+			if (PartitionEntryEndHead == 64 - 1) {
+				DiskParameters->Heads = 64;
+				DiskParameters->Sectors = 32;
+				break;
+			} else if (PartitionEntryEndHead == 128 - 1) {
+				DiskParameters->Heads = 128;
+				DiskParameters->Sectors = 32;
+				break;
+			} else if (PartitionEntryEndHead == 255 - 1) {
+				DiskParameters->Heads = 255;
+				DiskParameters->Sectors = 63;
+				break;
+			}
+			PartitionEntry++;
+		}
+		if (PartitionNumber == 4) {
+			PartitionEntryEndHead = FirstPartitionEntry->end_head;
+			PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F;
+		}
+		DiskParameters->Cylinders = (unsigned long) capacity / (DiskParameters->Heads * DiskParameters->Sectors);
+		if (PartitionNumber < 4 && PartitionEntryEndSector == DiskParameters->Sectors) {
+			if (DiskParameters->Cylinders != SavedCylinders)
+				BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors);
+		} else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0) {
+			BusLogic_Warning("Warning: Partition Table appears to " "have Geometry %d/%d which is\n", HostAdapter, PartitionEntryEndHead + 1, PartitionEntryEndSector);
+			BusLogic_Warning("not compatible with current BusLogic " "Host Adapter Geometry %d/%d\n", HostAdapter, DiskParameters->Heads, DiskParameters->Sectors);
+		}
+	}
+	kfree(buf);
+	return 0;
+}
+
+
+/*
+  BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>.
+*/
+
+static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, int WriteFlag)
+{
+	struct BusLogic_HostAdapter *HostAdapter = (struct BusLogic_HostAdapter *) shost->hostdata;
+	struct BusLogic_TargetStatistics *TargetStatistics;
+	int TargetID, Length;
+	char *Buffer;
+
+	TargetStatistics = HostAdapter->TargetStatistics;
+	if (WriteFlag) {
+		HostAdapter->ExternalHostAdapterResets = 0;
+		HostAdapter->HostAdapterInternalErrors = 0;
+		memset(TargetStatistics, 0, BusLogic_MaxTargetDevices * sizeof(struct BusLogic_TargetStatistics));
+		return 0;
+	}
+	Buffer = HostAdapter->MessageBuffer;
+	Length = HostAdapter->MessageBufferLength;
+	Length += sprintf(&Buffer[Length], "\n\
+Current Driver Queue Depth:	%d\n\
+Currently Allocated CCBs:	%d\n", HostAdapter->DriverQueueDepth, HostAdapter->AllocatedCCBs);
+	Length += sprintf(&Buffer[Length], "\n\n\
+			   DATA TRANSFER STATISTICS\n\
+\n\
+Target	Tagged Queuing	Queue Depth  Active  Attempted	Completed\n\
+======	==============	===========  ======  =========	=========\n");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+		if (!TargetFlags->TargetExists)
+			continue;
+		Length += sprintf(&Buffer[Length], "  %2d	%s", TargetID, (TargetFlags->TaggedQueuingSupported ? (TargetFlags->TaggedQueuingActive ? "    Active" : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
+																				    ? "  Permitted" : "   Disabled"))
+									  : "Not Supported"));
+		Length += sprintf(&Buffer[Length],
+				  "	    %3d       %3u    %9u	%9u\n", HostAdapter->QueueDepth[TargetID], HostAdapter->ActiveCommands[TargetID], TargetStatistics[TargetID].CommandsAttempted, TargetStatistics[TargetID].CommandsCompleted);
+	}
+	Length += sprintf(&Buffer[Length], "\n\
+Target  Read Commands  Write Commands   Total Bytes Read    Total Bytes Written\n\
+======  =============  ==============  ===================  ===================\n");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+		if (!TargetFlags->TargetExists)
+			continue;
+		Length += sprintf(&Buffer[Length], "  %2d	  %9u	 %9u", TargetID, TargetStatistics[TargetID].ReadCommands, TargetStatistics[TargetID].WriteCommands);
+		if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0)
+			Length += sprintf(&Buffer[Length], "     %9u%09u", TargetStatistics[TargetID].TotalBytesRead.Billions, TargetStatistics[TargetID].TotalBytesRead.Units);
+		else
+			Length += sprintf(&Buffer[Length], "		%9u", TargetStatistics[TargetID].TotalBytesRead.Units);
+		if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0)
+			Length += sprintf(&Buffer[Length], "   %9u%09u\n", TargetStatistics[TargetID].TotalBytesWritten.Billions, TargetStatistics[TargetID].TotalBytesWritten.Units);
+		else
+			Length += sprintf(&Buffer[Length], "	     %9u\n", TargetStatistics[TargetID].TotalBytesWritten.Units);
+	}
+	Length += sprintf(&Buffer[Length], "\n\
+Target  Command    0-1KB      1-2KB      2-4KB      4-8KB     8-16KB\n\
+======  =======  =========  =========  =========  =========  =========\n");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+		if (!TargetFlags->TargetExists)
+			continue;
+		Length +=
+		    sprintf(&Buffer[Length],
+			    "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+			    TargetStatistics[TargetID].ReadCommandSizeBuckets[0],
+			    TargetStatistics[TargetID].ReadCommandSizeBuckets[1], TargetStatistics[TargetID].ReadCommandSizeBuckets[2], TargetStatistics[TargetID].ReadCommandSizeBuckets[3], TargetStatistics[TargetID].ReadCommandSizeBuckets[4]);
+		Length +=
+		    sprintf(&Buffer[Length],
+			    "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+			    TargetStatistics[TargetID].WriteCommandSizeBuckets[0],
+			    TargetStatistics[TargetID].WriteCommandSizeBuckets[1], TargetStatistics[TargetID].WriteCommandSizeBuckets[2], TargetStatistics[TargetID].WriteCommandSizeBuckets[3], TargetStatistics[TargetID].WriteCommandSizeBuckets[4]);
+	}
+	Length += sprintf(&Buffer[Length], "\n\
+Target  Command   16-32KB    32-64KB   64-128KB   128-256KB   256KB+\n\
+======  =======  =========  =========  =========  =========  =========\n");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+		if (!TargetFlags->TargetExists)
+			continue;
+		Length +=
+		    sprintf(&Buffer[Length],
+			    "  %2d	 Read	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+			    TargetStatistics[TargetID].ReadCommandSizeBuckets[5],
+			    TargetStatistics[TargetID].ReadCommandSizeBuckets[6], TargetStatistics[TargetID].ReadCommandSizeBuckets[7], TargetStatistics[TargetID].ReadCommandSizeBuckets[8], TargetStatistics[TargetID].ReadCommandSizeBuckets[9]);
+		Length +=
+		    sprintf(&Buffer[Length],
+			    "  %2d	 Write	 %9u  %9u  %9u  %9u  %9u\n", TargetID,
+			    TargetStatistics[TargetID].WriteCommandSizeBuckets[5],
+			    TargetStatistics[TargetID].WriteCommandSizeBuckets[6], TargetStatistics[TargetID].WriteCommandSizeBuckets[7], TargetStatistics[TargetID].WriteCommandSizeBuckets[8], TargetStatistics[TargetID].WriteCommandSizeBuckets[9]);
+	}
+	Length += sprintf(&Buffer[Length], "\n\n\
+			   ERROR RECOVERY STATISTICS\n\
+\n\
+	  Command Aborts      Bus Device Resets	  Host Adapter Resets\n\
+Target	Requested Completed  Requested Completed  Requested Completed\n\
+  ID	\\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////  \\\\\\\\ Attempted ////\n\
+======	 ===== ===== =====    ===== ===== =====	   ===== ===== =====\n");
+	for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++) {
+		struct BusLogic_TargetFlags *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+		if (!TargetFlags->TargetExists)
+			continue;
+		Length += sprintf(&Buffer[Length], "\
+  %2d	 %5d %5d %5d    %5d %5d %5d	   %5d %5d %5d\n", TargetID, TargetStatistics[TargetID].CommandAbortsRequested, TargetStatistics[TargetID].CommandAbortsAttempted, TargetStatistics[TargetID].CommandAbortsCompleted, TargetStatistics[TargetID].BusDeviceResetsRequested, TargetStatistics[TargetID].BusDeviceResetsAttempted, TargetStatistics[TargetID].BusDeviceResetsCompleted, TargetStatistics[TargetID].HostAdapterResetsRequested, TargetStatistics[TargetID].HostAdapterResetsAttempted, TargetStatistics[TargetID].HostAdapterResetsCompleted);
+	}
+	Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n", HostAdapter->ExternalHostAdapterResets);
+	Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n", HostAdapter->HostAdapterInternalErrors);
+	if (Length >= BusLogic_MessageBufferSize)
+		BusLogic_Error("Message Buffer length %d exceeds size %d\n", HostAdapter, Length, BusLogic_MessageBufferSize);
+	if ((Length -= Offset) <= 0)
+		return 0;
+	if (Length >= BytesAvailable)
+		Length = BytesAvailable;
+	memcpy(ProcBuffer, HostAdapter->MessageBuffer + Offset, Length);
+	*StartPointer = ProcBuffer;
+	return Length;
+}
+
+
+/*
+  BusLogic_Message prints Driver Messages.
+*/
+
+static void BusLogic_Message(enum BusLogic_MessageLevel MessageLevel, char *Format, struct BusLogic_HostAdapter *HostAdapter, ...)
+{
+	static char Buffer[BusLogic_LineBufferSize];
+	static boolean BeginningOfLine = true;
+	va_list Arguments;
+	int Length = 0;
+	va_start(Arguments, HostAdapter);
+	Length = vsprintf(Buffer, Format, Arguments);
+	va_end(Arguments);
+	if (MessageLevel == BusLogic_AnnounceLevel) {
+		static int AnnouncementLines = 0;
+		strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer);
+		HostAdapter->MessageBufferLength += Length;
+		if (++AnnouncementLines <= 2)
+			printk("%sscsi: %s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+	} else if (MessageLevel == BusLogic_InfoLevel) {
+		strcpy(&HostAdapter->MessageBuffer[HostAdapter->MessageBufferLength], Buffer);
+		HostAdapter->MessageBufferLength += Length;
+		if (BeginningOfLine) {
+			if (Buffer[0] != '\n' || Length > 1)
+				printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer);
+		} else
+			printk("%s", Buffer);
+	} else {
+		if (BeginningOfLine) {
+			if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
+				printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel], HostAdapter->HostNumber, Buffer);
+			else
+				printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+		} else
+			printk("%s", Buffer);
+	}
+	BeginningOfLine = (Buffer[Length - 1] == '\n');
+}
+
+
+/*
+  BusLogic_ParseKeyword parses an individual option keyword.  It returns true
+  and updates the pointer if the keyword is recognized and false otherwise.
+*/
+
+static boolean __init BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
+{
+	char *Pointer = *StringPointer;
+	while (*Keyword != '\0') {
+		char StringChar = *Pointer++;
+		char KeywordChar = *Keyword++;
+		if (StringChar >= 'A' && StringChar <= 'Z')
+			StringChar += 'a' - 'Z';
+		if (KeywordChar >= 'A' && KeywordChar <= 'Z')
+			KeywordChar += 'a' - 'Z';
+		if (StringChar != KeywordChar)
+			return false;
+	}
+	*StringPointer = Pointer;
+	return true;
+}
+
+
+/*
+  BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options
+  specifications.
+
+  BusLogic Driver Options may be specified either via the Linux Kernel Command
+  Line or via the Loadable Kernel Module Installation Facility.  Driver Options
+  for multiple host adapters may be specified either by separating the option
+  strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+  command line.  Individual option specifications for a single host adapter are
+  separated by commas.  The Probing and Debugging Options apply to all host
+  adapters whereas the remaining options apply individually only to the
+  selected host adapter.
+
+  The BusLogic Driver Probing Options are described in
+  <file:Documentation/scsi/BusLogic.txt>.
+*/
+
+static int __init BusLogic_ParseDriverOptions(char *OptionsString)
+{
+	while (true) {
+		struct BusLogic_DriverOptions *DriverOptions = &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++];
+		int TargetID;
+		memset(DriverOptions, 0, sizeof(struct BusLogic_DriverOptions));
+		while (*OptionsString != '\0' && *OptionsString != ';') {
+			/* Probing Options. */
+			if (BusLogic_ParseKeyword(&OptionsString, "IO:")) {
+				unsigned long IO_Address = simple_strtoul(OptionsString, &OptionsString, 0);
+				BusLogic_ProbeOptions.LimitedProbeISA = true;
+				switch (IO_Address) {
+				case 0x330:
+					BusLogic_ProbeOptions.Probe330 = true;
+					break;
+				case 0x334:
+					BusLogic_ProbeOptions.Probe334 = true;
+					break;
+				case 0x230:
+					BusLogic_ProbeOptions.Probe230 = true;
+					break;
+				case 0x234:
+					BusLogic_ProbeOptions.Probe234 = true;
+					break;
+				case 0x130:
+					BusLogic_ProbeOptions.Probe130 = true;
+					break;
+				case 0x134:
+					BusLogic_ProbeOptions.Probe134 = true;
+					break;
+				default:
+					BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid I/O Address 0x%X)\n", NULL, IO_Address);
+					return 0;
+				}
+			} else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA"))
+				BusLogic_ProbeOptions.NoProbeISA = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI"))
+				BusLogic_ProbeOptions.NoProbePCI = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe"))
+				BusLogic_ProbeOptions.NoProbe = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI"))
+				BusLogic_ProbeOptions.NoSortPCI = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst"))
+				BusLogic_ProbeOptions.MultiMasterFirst = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst"))
+				BusLogic_ProbeOptions.FlashPointFirst = true;
+			/* Tagged Queuing Options. */
+			else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") || BusLogic_ParseKeyword(&OptionsString, "QD:[")) {
+				for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++) {
+					unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0);
+					if (QueueDepth > BusLogic_MaxTaggedQueueDepth) {
+						BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth);
+						return 0;
+					}
+					DriverOptions->QueueDepth[TargetID] = QueueDepth;
+					if (*OptionsString == ',')
+						OptionsString++;
+					else if (*OptionsString == ']')
+						break;
+					else {
+						BusLogic_Error("BusLogic: Invalid Driver Options " "(',' or ']' expected at '%s')\n", NULL, OptionsString);
+						return 0;
+					}
+				}
+				if (*OptionsString != ']') {
+					BusLogic_Error("BusLogic: Invalid Driver Options " "(']' expected at '%s')\n", NULL, OptionsString);
+					return 0;
+				} else
+					OptionsString++;
+			} else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") || BusLogic_ParseKeyword(&OptionsString, "QD:")) {
+				unsigned short QueueDepth = simple_strtoul(OptionsString, &OptionsString, 0);
+				if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth) {
+					BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Queue Depth %d)\n", NULL, QueueDepth);
+					return 0;
+				}
+				DriverOptions->CommonQueueDepth = QueueDepth;
+				for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+					DriverOptions->QueueDepth[TargetID] = QueueDepth;
+			} else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") || BusLogic_ParseKeyword(&OptionsString, "TQ:")) {
+				if (BusLogic_ParseKeyword(&OptionsString, "Default")) {
+					DriverOptions->TaggedQueuingPermitted = 0x0000;
+					DriverOptions->TaggedQueuingPermittedMask = 0x0000;
+				} else if (BusLogic_ParseKeyword(&OptionsString, "Enable")) {
+					DriverOptions->TaggedQueuingPermitted = 0xFFFF;
+					DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+				} else if (BusLogic_ParseKeyword(&OptionsString, "Disable")) {
+					DriverOptions->TaggedQueuingPermitted = 0x0000;
+					DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+				} else {
+					unsigned short TargetBit;
+					for (TargetID = 0, TargetBit = 1; TargetID < BusLogic_MaxTargetDevices; TargetID++, TargetBit <<= 1)
+						switch (*OptionsString++) {
+						case 'Y':
+							DriverOptions->TaggedQueuingPermitted |= TargetBit;
+							DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+							break;
+						case 'N':
+							DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+							DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+							break;
+						case 'X':
+							break;
+						default:
+							OptionsString--;
+							TargetID = BusLogic_MaxTargetDevices;
+							break;
+						}
+				}
+			}
+			/* Miscellaneous Options. */
+			else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") || BusLogic_ParseKeyword(&OptionsString, "BST:")) {
+				unsigned short BusSettleTime = simple_strtoul(OptionsString, &OptionsString, 0);
+				if (BusSettleTime > 5 * 60) {
+					BusLogic_Error("BusLogic: Invalid Driver Options " "(invalid Bus Settle Time %d)\n", NULL, BusSettleTime);
+					return 0;
+				}
+				DriverOptions->BusSettleTime = BusSettleTime;
+			} else if (BusLogic_ParseKeyword(&OptionsString, "InhibitTargetInquiry"))
+				DriverOptions->LocalOptions.InhibitTargetInquiry = true;
+			/* Debugging Options. */
+			else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe"))
+				BusLogic_GlobalOptions.TraceProbe = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset"))
+				BusLogic_GlobalOptions.TraceHardwareReset = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration"))
+				BusLogic_GlobalOptions.TraceConfiguration = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors"))
+				BusLogic_GlobalOptions.TraceErrors = true;
+			else if (BusLogic_ParseKeyword(&OptionsString, "Debug")) {
+				BusLogic_GlobalOptions.TraceProbe = true;
+				BusLogic_GlobalOptions.TraceHardwareReset = true;
+				BusLogic_GlobalOptions.TraceConfiguration = true;
+				BusLogic_GlobalOptions.TraceErrors = true;
+			}
+			if (*OptionsString == ',')
+				OptionsString++;
+			else if (*OptionsString != ';' && *OptionsString != '\0') {
+				BusLogic_Error("BusLogic: Unexpected Driver Option '%s' " "ignored\n", NULL, OptionsString);
+				*OptionsString = '\0';
+			}
+		}
+		if (!(BusLogic_DriverOptionsCount == 0 || BusLogic_ProbeInfoCount == 0 || BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount)) {
+			BusLogic_Error("BusLogic: Invalid Driver Options " "(all or no I/O Addresses must be specified)\n", NULL);
+			return 0;
+		}
+		/*
+		   Tagged Queuing is disabled when the Queue Depth is 1 since queuing
+		   multiple commands is not possible.
+		 */
+		for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+			if (DriverOptions->QueueDepth[TargetID] == 1) {
+				unsigned short TargetBit = 1 << TargetID;
+				DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+				DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+			}
+		if (*OptionsString == ';')
+			OptionsString++;
+		if (*OptionsString == '\0')
+			return 0;
+	}
+	return 1;
+}
+
+/*
+  Get it all started
+*/
+
+static struct scsi_host_template Bus_Logic_template = {
+	.module = THIS_MODULE,
+	.proc_name = "BusLogic",
+	.proc_info = BusLogic_ProcDirectoryInfo,
+	.name = "BusLogic",
+	.info = BusLogic_DriverInfo,
+	.queuecommand = BusLogic_QueueCommand,
+	.slave_configure = BusLogic_SlaveConfigure,
+	.bios_param = BusLogic_BIOSDiskParameters,
+	.eh_host_reset_handler = BusLogic_host_reset,
+#if 0
+	.eh_abort_handler = BusLogic_AbortCommand,
+#endif
+	.unchecked_isa_dma = 1,
+	.max_sectors = 128,
+	.use_clustering = ENABLE_CLUSTERING,
+};
+
+/*
+  BusLogic_Setup handles processing of Kernel Command Line Arguments.
+*/
+
+static int __init BusLogic_Setup(char *str)
+{
+	int ints[3];
+
+	(void) get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] != 0) {
+		BusLogic_Error("BusLogic: Obsolete Command Line Entry " "Format Ignored\n", NULL);
+		return 0;
+	}
+	if (str == NULL || *str == '\0')
+		return 0;
+	return BusLogic_ParseDriverOptions(str);
+}
+
+/*
+ * Exit function.  Deletes all hosts associated with this driver.
+ */
+
+static void __exit BusLogic_exit(void)
+{
+	struct BusLogic_HostAdapter *ha, *next;
+
+	list_for_each_entry_safe(ha, next, &BusLogic_host_list, host_list)
+		BusLogic_ReleaseHostAdapter(ha);
+}
+
+__setup("BusLogic=", BusLogic_Setup);
+
+module_init(BusLogic_init);
+module_exit(BusLogic_exit);
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
new file mode 100644
index 0000000..1aaa656
--- /dev/null
+++ b/drivers/scsi/BusLogic.h
@@ -0,0 +1,1359 @@
+/*
+
+  Linux Driver for BusLogic MultiMaster and FlashPoint SCSI Host Adapters
+
+  Copyright 1995-1998 by Leonard N. Zubkoff <lnz@dandelion.com>
+
+  This program is free software; you may redistribute and/or modify it under
+  the terms of the GNU General Public License Version 2 as published by the
+  Free Software Foundation.
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
+  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+  for complete details.
+
+  The author respectfully requests that any modifications to this software be
+  sent directly to him for evaluation and testing.
+
+  Special thanks to Wayne Yen, Jin-Lon Hon, and Alex Win of BusLogic, whose
+  advice has been invaluable, to David Gentzel, for writing the original Linux
+  BusLogic driver, and to Paul Gortmaker, for being such a dedicated test site.
+
+  Finally, special thanks to Mylex/BusLogic for making the FlashPoint SCCB
+  Manager available as freely redistributable source code.
+
+*/
+
+#ifndef _BUSLOGIC_H
+#define _BUSLOGIC_H
+
+#include <linux/config.h>
+
+#ifndef PACKED
+#define PACKED __attribute__((packed))
+#endif
+
+/*
+  FlashPoint support is only available for the Intel x86 Architecture with
+  CONFIG_PCI set.
+*/
+
+#ifndef __i386__
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#endif
+
+#ifndef CONFIG_PCI
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList
+#endif
+
+
+/*
+  Define the maximum number of BusLogic Host Adapters supported by this driver.
+*/
+
+#define BusLogic_MaxHostAdapters		16
+
+
+/*
+  Define the maximum number of Target Devices supported by this driver.
+*/
+
+#define BusLogic_MaxTargetDevices		16
+
+
+/*
+  Define the maximum number of Scatter/Gather Segments used by this driver.
+  For optimal performance, it is important that this limit be at least as
+  large as the largest single request generated by the I/O Subsystem.
+*/
+
+#define BusLogic_ScatterGatherLimit		128
+
+
+/*
+  Define the maximum, maximum automatic, minimum automatic, and default Queue
+  Depth to allow for Target Devices depending on whether or not they support
+  Tagged Queuing and whether or not ISA Bounce Buffers are required.
+*/
+
+#define BusLogic_MaxTaggedQueueDepth		64
+#define BusLogic_MaxAutomaticTaggedQueueDepth	28
+#define BusLogic_MinAutomaticTaggedQueueDepth	7
+#define BusLogic_TaggedQueueDepthBB		3
+#define BusLogic_UntaggedQueueDepth		3
+#define BusLogic_UntaggedQueueDepthBB		2
+
+
+/*
+  Define the default amount of time in seconds to wait between a Host Adapter
+  Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI commands.
+  Some SCSI devices get confused if they receive SCSI commands too soon after
+  a SCSI Bus Reset.
+*/
+
+#define BusLogic_DefaultBusSettleTime		2
+
+
+/*
+  Define the maximum number of Mailboxes that should be used for MultiMaster
+  Host Adapters.  This number is chosen to be larger than the maximum Host
+  Adapter Queue Depth and small enough so that the Host Adapter structure
+  does not cross an allocation block size boundary.
+*/
+
+#define BusLogic_MaxMailboxes			211
+
+
+/*
+  Define the number of CCBs that should be allocated as a group to optimize
+  Kernel memory allocation.
+*/
+
+#define BusLogic_CCB_AllocationGroupSize	7
+
+
+/*
+  Define the Host Adapter Line and Message Buffer Sizes.
+*/
+
+#define BusLogic_LineBufferSize			100
+#define BusLogic_MessageBufferSize		9700
+
+
+/*
+  Define the Driver Message Levels.
+*/
+
+enum BusLogic_MessageLevel {
+	BusLogic_AnnounceLevel = 0,
+	BusLogic_InfoLevel = 1,
+	BusLogic_NoticeLevel = 2,
+	BusLogic_WarningLevel = 3,
+	BusLogic_ErrorLevel = 4
+};
+
+static char *BusLogic_MessageLevelMap[] = { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+
+
+/*
+  Define Driver Message macros.
+*/
+
+#define BusLogic_Announce(Format, Arguments...) \
+  BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
+
+#define BusLogic_Info(Format, Arguments...) \
+  BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
+
+#define BusLogic_Notice(Format, Arguments...) \
+  BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
+
+#define BusLogic_Warning(Format, Arguments...) \
+  BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
+
+#define BusLogic_Error(Format, Arguments...) \
+  BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
+
+
+/*
+  Define the types of BusLogic Host Adapters that are supported and the number
+  of I/O Addresses required by each type.
+*/
+
+enum BusLogic_HostAdapterType {
+	BusLogic_MultiMaster = 1,
+	BusLogic_FlashPoint = 2
+} PACKED;
+
+#define BusLogic_MultiMasterAddressCount	4
+#define BusLogic_FlashPointAddressCount		256
+
+static int BusLogic_HostAdapterAddressCount[3] = { 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount };
+
+
+/*
+  Define macros for testing the Host Adapter Type.
+*/
+
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
+
+#else
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+  (true)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+  (false)
+
+#endif
+
+
+/*
+  Define the possible Host Adapter Bus Types.
+*/
+
+enum BusLogic_HostAdapterBusType {
+	BusLogic_Unknown_Bus = 0,
+	BusLogic_ISA_Bus = 1,
+	BusLogic_EISA_Bus = 2,
+	BusLogic_PCI_Bus = 3,
+	BusLogic_VESA_Bus = 4,
+	BusLogic_MCA_Bus = 5
+} PACKED;
+
+static char *BusLogic_HostAdapterBusNames[] = { "Unknown", "ISA", "EISA", "PCI", "VESA", "MCA" };
+
+static enum BusLogic_HostAdapterBusType BusLogic_HostAdapterBusTypes[] = {
+	BusLogic_VESA_Bus,	/* BT-4xx */
+	BusLogic_ISA_Bus,	/* BT-5xx */
+	BusLogic_MCA_Bus,	/* BT-6xx */
+	BusLogic_EISA_Bus,	/* BT-7xx */
+	BusLogic_Unknown_Bus,	/* BT-8xx */
+	BusLogic_PCI_Bus	/* BT-9xx */
+};
+
+/*
+  Define the possible Host Adapter BIOS Disk Geometry Translations.
+*/
+
+enum BusLogic_BIOS_DiskGeometryTranslation {
+	BusLogic_BIOS_Disk_Not_Installed = 0,
+	BusLogic_BIOS_Disk_Installed_64x32 = 1,
+	BusLogic_BIOS_Disk_Installed_128x32 = 2,
+	BusLogic_BIOS_Disk_Installed_255x63 = 3
+} PACKED;
+
+
+/*
+  Define a Boolean data type.
+*/
+
+typedef enum {
+	false,
+	true
+} PACKED boolean;
+
+/*
+  Define a 10^18 Statistics Byte Counter data type.
+*/
+
+struct BusLogic_ByteCounter {
+	unsigned int Units;
+	unsigned int Billions;
+};
+
+
+/*
+  Define the structure for I/O Address and Bus Probing Information.
+*/
+
+struct BusLogic_ProbeInfo {
+	enum BusLogic_HostAdapterType HostAdapterType;
+	enum BusLogic_HostAdapterBusType HostAdapterBusType;
+	unsigned long IO_Address;
+	unsigned long PCI_Address;
+	struct pci_dev *PCI_Device;
+	unsigned char Bus;
+	unsigned char Device;
+	unsigned char IRQ_Channel;
+};
+
+/*
+  Define the Probe Options.
+*/
+
+struct BusLogic_ProbeOptions {
+	boolean NoProbe:1;	/* Bit 0 */
+	boolean NoProbeISA:1;	/* Bit 1 */
+	boolean NoProbePCI:1;	/* Bit 2 */
+	boolean NoSortPCI:1;	/* Bit 3 */
+	boolean MultiMasterFirst:1;	/* Bit 4 */
+	boolean FlashPointFirst:1;	/* Bit 5 */
+	boolean LimitedProbeISA:1;	/* Bit 6 */
+	boolean Probe330:1;	/* Bit 7 */
+	boolean Probe334:1;	/* Bit 8 */
+	boolean Probe230:1;	/* Bit 9 */
+	boolean Probe234:1;	/* Bit 10 */
+	boolean Probe130:1;	/* Bit 11 */
+	boolean Probe134:1;	/* Bit 12 */
+};
+
+/*
+  Define the Global Options.
+*/
+
+struct BusLogic_GlobalOptions {
+	boolean TraceProbe:1;	/* Bit 0 */
+	boolean TraceHardwareReset:1;	/* Bit 1 */
+	boolean TraceConfiguration:1;	/* Bit 2 */
+	boolean TraceErrors:1;	/* Bit 3 */
+};
+
+/*
+  Define the Local Options.
+*/
+
+struct BusLogic_LocalOptions {
+	boolean InhibitTargetInquiry:1;	/* Bit 0 */
+};
+
+/*
+  Define the BusLogic SCSI Host Adapter I/O Register Offsets.
+*/
+
+#define BusLogic_ControlRegisterOffset		0	/* WO register */
+#define BusLogic_StatusRegisterOffset		0	/* RO register */
+#define BusLogic_CommandParameterRegisterOffset	1	/* WO register */
+#define BusLogic_DataInRegisterOffset		1	/* RO register */
+#define BusLogic_InterruptRegisterOffset	2	/* RO register */
+#define BusLogic_GeometryRegisterOffset		3	/* RO register */
+
+/*
+  Define the structure of the write-only Control Register.
+*/
+
+union BusLogic_ControlRegister {
+	unsigned char All;
+	struct {
+		unsigned char:4;	/* Bits 0-3 */
+		boolean SCSIBusReset:1;	/* Bit 4 */
+		boolean InterruptReset:1;	/* Bit 5 */
+		boolean SoftReset:1;	/* Bit 6 */
+		boolean HardReset:1;	/* Bit 7 */
+	} cr;
+};
+
+/*
+  Define the structure of the read-only Status Register.
+*/
+
+union BusLogic_StatusRegister {
+	unsigned char All;
+	struct {
+		boolean CommandInvalid:1;	/* Bit 0 */
+		boolean Reserved:1;	/* Bit 1 */
+		boolean DataInRegisterReady:1;	/* Bit 2 */
+		boolean CommandParameterRegisterBusy:1;	/* Bit 3 */
+		boolean HostAdapterReady:1;	/* Bit 4 */
+		boolean InitializationRequired:1;	/* Bit 5 */
+		boolean DiagnosticFailure:1;	/* Bit 6 */
+		boolean DiagnosticActive:1;	/* Bit 7 */
+	} sr;
+};
+
+/*
+  Define the structure of the read-only Interrupt Register.
+*/
+
+union BusLogic_InterruptRegister {
+	unsigned char All;
+	struct {
+		boolean IncomingMailboxLoaded:1;	/* Bit 0 */
+		boolean OutgoingMailboxAvailable:1;	/* Bit 1 */
+		boolean CommandComplete:1;	/* Bit 2 */
+		boolean ExternalBusReset:1;	/* Bit 3 */
+		unsigned char Reserved:3;	/* Bits 4-6 */
+		boolean InterruptValid:1;	/* Bit 7 */
+	} ir;
+};
+
+/*
+  Define the structure of the read-only Geometry Register.
+*/
+
+union BusLogic_GeometryRegister {
+	unsigned char All;
+	struct {
+		enum BusLogic_BIOS_DiskGeometryTranslation Drive0Geometry:2;	/* Bits 0-1 */
+		enum BusLogic_BIOS_DiskGeometryTranslation Drive1Geometry:2;	/* Bits 2-3 */
+		unsigned char:3;	/* Bits 4-6 */
+		boolean ExtendedTranslationEnabled:1;	/* Bit 7 */
+	} gr;
+};
+
+/*
+  Define the BusLogic SCSI Host Adapter Command Register Operation Codes.
+*/
+
+enum BusLogic_OperationCode {
+	BusLogic_TestCommandCompleteInterrupt = 0x00,
+	BusLogic_InitializeMailbox = 0x01,
+	BusLogic_ExecuteMailboxCommand = 0x02,
+	BusLogic_ExecuteBIOSCommand = 0x03,
+	BusLogic_InquireBoardID = 0x04,
+	BusLogic_EnableOutgoingMailboxAvailableInt = 0x05,
+	BusLogic_SetSCSISelectionTimeout = 0x06,
+	BusLogic_SetPreemptTimeOnBus = 0x07,
+	BusLogic_SetTimeOffBus = 0x08,
+	BusLogic_SetBusTransferRate = 0x09,
+	BusLogic_InquireInstalledDevicesID0to7 = 0x0A,
+	BusLogic_InquireConfiguration = 0x0B,
+	BusLogic_EnableTargetMode = 0x0C,
+	BusLogic_InquireSetupInformation = 0x0D,
+	BusLogic_WriteAdapterLocalRAM = 0x1A,
+	BusLogic_ReadAdapterLocalRAM = 0x1B,
+	BusLogic_WriteBusMasterChipFIFO = 0x1C,
+	BusLogic_ReadBusMasterChipFIFO = 0x1D,
+	BusLogic_EchoCommandData = 0x1F,
+	BusLogic_HostAdapterDiagnostic = 0x20,
+	BusLogic_SetAdapterOptions = 0x21,
+	BusLogic_InquireInstalledDevicesID8to15 = 0x23,
+	BusLogic_InquireTargetDevices = 0x24,
+	BusLogic_DisableHostAdapterInterrupt = 0x25,
+	BusLogic_InitializeExtendedMailbox = 0x81,
+	BusLogic_ExecuteSCSICommand = 0x83,
+	BusLogic_InquireFirmwareVersion3rdDigit = 0x84,
+	BusLogic_InquireFirmwareVersionLetter = 0x85,
+	BusLogic_InquirePCIHostAdapterInformation = 0x86,
+	BusLogic_InquireHostAdapterModelNumber = 0x8B,
+	BusLogic_InquireSynchronousPeriod = 0x8C,
+	BusLogic_InquireExtendedSetupInformation = 0x8D,
+	BusLogic_EnableStrictRoundRobinMode = 0x8F,
+	BusLogic_StoreHostAdapterLocalRAM = 0x90,
+	BusLogic_FetchHostAdapterLocalRAM = 0x91,
+	BusLogic_StoreLocalDataInEEPROM = 0x92,
+	BusLogic_UploadAutoSCSICode = 0x94,
+	BusLogic_ModifyIOAddress = 0x95,
+	BusLogic_SetCCBFormat = 0x96,
+	BusLogic_WriteInquiryBuffer = 0x9A,
+	BusLogic_ReadInquiryBuffer = 0x9B,
+	BusLogic_FlashROMUploadDownload = 0xA7,
+	BusLogic_ReadSCAMData = 0xA8,
+	BusLogic_WriteSCAMData = 0xA9
+};
+
+/*
+  Define the Inquire Board ID reply structure.
+*/
+
+struct BusLogic_BoardID {
+	unsigned char BoardType;	/* Byte 0 */
+	unsigned char CustomFeatures;	/* Byte 1 */
+	unsigned char FirmwareVersion1stDigit;	/* Byte 2 */
+	unsigned char FirmwareVersion2ndDigit;	/* Byte 3 */
+};
+
+/*
+  Define the Inquire Configuration reply structure.
+*/
+
+struct BusLogic_Configuration {
+	unsigned char:5;	/* Byte 0 Bits 0-4 */
+	boolean DMA_Channel5:1;	/* Byte 0 Bit 5 */
+	boolean DMA_Channel6:1;	/* Byte 0 Bit 6 */
+	boolean DMA_Channel7:1;	/* Byte 0 Bit 7 */
+	boolean IRQ_Channel9:1;	/* Byte 1 Bit 0 */
+	boolean IRQ_Channel10:1;	/* Byte 1 Bit 1 */
+	boolean IRQ_Channel11:1;	/* Byte 1 Bit 2 */
+	boolean IRQ_Channel12:1;	/* Byte 1 Bit 3 */
+	unsigned char:1;	/* Byte 1 Bit 4 */
+	boolean IRQ_Channel14:1;	/* Byte 1 Bit 5 */
+	boolean IRQ_Channel15:1;	/* Byte 1 Bit 6 */
+	unsigned char:1;	/* Byte 1 Bit 7 */
+	unsigned char HostAdapterID:4;	/* Byte 2 Bits 0-3 */
+	unsigned char:4;	/* Byte 2 Bits 4-7 */
+};
+
+/*
+  Define the Inquire Setup Information reply structure.
+*/
+
+struct BusLogic_SynchronousValue {
+	unsigned char Offset:4;	/* Bits 0-3 */
+	unsigned char TransferPeriod:3;	/* Bits 4-6 */
+	boolean Synchronous:1;	/* Bit 7 */
+};
+
+struct BusLogic_SetupInformation {
+	boolean SynchronousInitiationEnabled:1;	/* Byte 0 Bit 0 */
+	boolean ParityCheckingEnabled:1;	/* Byte 0 Bit 1 */
+	unsigned char:6;	/* Byte 0 Bits 2-7 */
+	unsigned char BusTransferRate;	/* Byte 1 */
+	unsigned char PreemptTimeOnBus;	/* Byte 2 */
+	unsigned char TimeOffBus;	/* Byte 3 */
+	unsigned char MailboxCount;	/* Byte 4 */
+	unsigned char MailboxAddress[3];	/* Bytes 5-7 */
+	struct BusLogic_SynchronousValue SynchronousValuesID0to7[8];	/* Bytes 8-15 */
+	unsigned char DisconnectPermittedID0to7;	/* Byte 16 */
+	unsigned char Signature;	/* Byte 17 */
+	unsigned char CharacterD;	/* Byte 18 */
+	unsigned char HostBusType;	/* Byte 19 */
+	unsigned char WideTransfersPermittedID0to7;	/* Byte 20 */
+	unsigned char WideTransfersActiveID0to7;	/* Byte 21 */
+	struct BusLogic_SynchronousValue SynchronousValuesID8to15[8];	/* Bytes 22-29 */
+	unsigned char DisconnectPermittedID8to15;	/* Byte 30 */
+	unsigned char:8;	/* Byte 31 */
+	unsigned char WideTransfersPermittedID8to15;	/* Byte 32 */
+	unsigned char WideTransfersActiveID8to15;	/* Byte 33 */
+};
+
+/*
+  Define the Initialize Extended Mailbox request structure.
+*/
+
+struct BusLogic_ExtendedMailboxRequest {
+	unsigned char MailboxCount;	/* Byte 0 */
+	u32 BaseMailboxAddress;	/* Bytes 1-4 */
+} PACKED;
+
+
+/*
+  Define the Inquire PCI Host Adapter Information reply type.  The ISA
+  Compatible I/O Port values are defined here and are also used with
+  the Modify I/O Address command.
+*/
+
+enum BusLogic_ISACompatibleIOPort {
+	BusLogic_IO_330 = 0,
+	BusLogic_IO_334 = 1,
+	BusLogic_IO_230 = 2,
+	BusLogic_IO_234 = 3,
+	BusLogic_IO_130 = 4,
+	BusLogic_IO_134 = 5,
+	BusLogic_IO_Disable = 6,
+	BusLogic_IO_Disable2 = 7
+} PACKED;
+
+struct BusLogic_PCIHostAdapterInformation {
+	enum BusLogic_ISACompatibleIOPort ISACompatibleIOPort;	/* Byte 0 */
+	unsigned char PCIAssignedIRQChannel;	/* Byte 1 */
+	boolean LowByteTerminated:1;	/* Byte 2 Bit 0 */
+	boolean HighByteTerminated:1;	/* Byte 2 Bit 1 */
+	unsigned char:2;	/* Byte 2 Bits 2-3 */
+	boolean JP1:1;		/* Byte 2 Bit 4 */
+	boolean JP2:1;		/* Byte 2 Bit 5 */
+	boolean JP3:1;		/* Byte 2 Bit 6 */
+	boolean GenericInfoValid:1;	/* Byte 2 Bit 7 */
+	unsigned char:8;	/* Byte 3 */
+};
+
+/*
+  Define the Inquire Extended Setup Information reply structure.
+*/
+
+struct BusLogic_ExtendedSetupInformation {
+	unsigned char BusType;	/* Byte 0 */
+	unsigned char BIOS_Address;	/* Byte 1 */
+	unsigned short ScatterGatherLimit;	/* Bytes 2-3 */
+	unsigned char MailboxCount;	/* Byte 4 */
+	u32 BaseMailboxAddress;	/* Bytes 5-8 */
+	struct {
+		unsigned char:2;	/* Byte 9 Bits 0-1 */
+		boolean FastOnEISA:1;	/* Byte 9 Bit 2 */
+		unsigned char:3;	/* Byte 9 Bits 3-5 */
+		boolean LevelSensitiveInterrupt:1;	/* Byte 9 Bit 6 */
+		unsigned char:1;	/* Byte 9 Bit 7 */
+	} Misc;
+	unsigned char FirmwareRevision[3];	/* Bytes 10-12 */
+	boolean HostWideSCSI:1;	/* Byte 13 Bit 0 */
+	boolean HostDifferentialSCSI:1;	/* Byte 13 Bit 1 */
+	boolean HostSupportsSCAM:1;	/* Byte 13 Bit 2 */
+	boolean HostUltraSCSI:1;	/* Byte 13 Bit 3 */
+	boolean HostSmartTermination:1;	/* Byte 13 Bit 4 */
+	unsigned char:3;	/* Byte 13 Bits 5-7 */
+} PACKED;
+
+/*
+  Define the Enable Strict Round Robin Mode request type.
+*/
+
+enum BusLogic_RoundRobinModeRequest {
+	BusLogic_AggressiveRoundRobinMode = 0,
+	BusLogic_StrictRoundRobinMode = 1
+} PACKED;
+
+
+/*
+  Define the Fetch Host Adapter Local RAM request type.
+*/
+
+#define BusLogic_BIOS_BaseOffset		0
+#define BusLogic_AutoSCSI_BaseOffset		64
+
+struct BusLogic_FetchHostAdapterLocalRAMRequest {
+	unsigned char ByteOffset;	/* Byte 0 */
+	unsigned char ByteCount;	/* Byte 1 */
+};
+
+/*
+  Define the Host Adapter Local RAM AutoSCSI structure.
+*/
+
+struct BusLogic_AutoSCSIData {
+	unsigned char InternalFactorySignature[2];	/* Bytes 0-1 */
+	unsigned char InformationByteCount;	/* Byte 2 */
+	unsigned char HostAdapterType[6];	/* Bytes 3-8 */
+	unsigned char:8;	/* Byte 9 */
+	boolean FloppyEnabled:1;	/* Byte 10 Bit 0 */
+	boolean FloppySecondary:1;	/* Byte 10 Bit 1 */
+	boolean LevelSensitiveInterrupt:1;	/* Byte 10 Bit 2 */
+	unsigned char:2;	/* Byte 10 Bits 3-4 */
+	unsigned char SystemRAMAreaForBIOS:3;	/* Byte 10 Bits 5-7 */
+	unsigned char DMA_Channel:7;	/* Byte 11 Bits 0-6 */
+	boolean DMA_AutoConfiguration:1;	/* Byte 11 Bit 7 */
+	unsigned char IRQ_Channel:7;	/* Byte 12 Bits 0-6 */
+	boolean IRQ_AutoConfiguration:1;	/* Byte 12 Bit 7 */
+	unsigned char DMA_TransferRate;	/* Byte 13 */
+	unsigned char SCSI_ID;	/* Byte 14 */
+	boolean LowByteTerminated:1;	/* Byte 15 Bit 0 */
+	boolean ParityCheckingEnabled:1;	/* Byte 15 Bit 1 */
+	boolean HighByteTerminated:1;	/* Byte 15 Bit 2 */
+	boolean NoisyCablingEnvironment:1;	/* Byte 15 Bit 3 */
+	boolean FastSynchronousNegotiation:1;	/* Byte 15 Bit 4 */
+	boolean BusResetEnabled:1;	/* Byte 15 Bit 5 */
+	 boolean:1;		/* Byte 15 Bit 6 */
+	boolean ActiveNegationEnabled:1;	/* Byte 15 Bit 7 */
+	unsigned char BusOnDelay;	/* Byte 16 */
+	unsigned char BusOffDelay;	/* Byte 17 */
+	boolean HostAdapterBIOSEnabled:1;	/* Byte 18 Bit 0 */
+	boolean BIOSRedirectionOfINT19Enabled:1;	/* Byte 18 Bit 1 */
+	boolean ExtendedTranslationEnabled:1;	/* Byte 18 Bit 2 */
+	boolean MapRemovableAsFixedEnabled:1;	/* Byte 18 Bit 3 */
+	 boolean:1;		/* Byte 18 Bit 4 */
+	boolean BIOSSupportsMoreThan2DrivesEnabled:1;	/* Byte 18 Bit 5 */
+	boolean BIOSInterruptModeEnabled:1;	/* Byte 18 Bit 6 */
+	boolean FlopticalSupportEnabled:1;	/* Byte 19 Bit 7 */
+	unsigned short DeviceEnabled;	/* Bytes 19-20 */
+	unsigned short WidePermitted;	/* Bytes 21-22 */
+	unsigned short FastPermitted;	/* Bytes 23-24 */
+	unsigned short SynchronousPermitted;	/* Bytes 25-26 */
+	unsigned short DisconnectPermitted;	/* Bytes 27-28 */
+	unsigned short SendStartUnitCommand;	/* Bytes 29-30 */
+	unsigned short IgnoreInBIOSScan;	/* Bytes 31-32 */
+	unsigned char PCIInterruptPin:2;	/* Byte 33 Bits 0-1 */
+	unsigned char HostAdapterIOPortAddress:2;	/* Byte 33 Bits 2-3 */
+	boolean StrictRoundRobinModeEnabled:1;	/* Byte 33 Bit 4 */
+	boolean VESABusSpeedGreaterThan33MHz:1;	/* Byte 33 Bit 5 */
+	boolean VESABurstWriteEnabled:1;	/* Byte 33 Bit 6 */
+	boolean VESABurstReadEnabled:1;	/* Byte 33 Bit 7 */
+	unsigned short UltraPermitted;	/* Bytes 34-35 */
+	unsigned int:32;	/* Bytes 36-39 */
+	unsigned char:8;	/* Byte 40 */
+	unsigned char AutoSCSIMaximumLUN;	/* Byte 41 */
+	 boolean:1;		/* Byte 42 Bit 0 */
+	boolean SCAM_Dominant:1;	/* Byte 42 Bit 1 */
+	boolean SCAM_Enabled:1;	/* Byte 42 Bit 2 */
+	boolean SCAM_Level2:1;	/* Byte 42 Bit 3 */
+	unsigned char:4;	/* Byte 42 Bits 4-7 */
+	boolean INT13ExtensionEnabled:1;	/* Byte 43 Bit 0 */
+	 boolean:1;		/* Byte 43 Bit 1 */
+	boolean CDROMBootEnabled:1;	/* Byte 43 Bit 2 */
+	unsigned char:5;	/* Byte 43 Bits 3-7 */
+	unsigned char BootTargetID:4;	/* Byte 44 Bits 0-3 */
+	unsigned char BootChannel:4;	/* Byte 44 Bits 4-7 */
+	unsigned char ForceBusDeviceScanningOrder:1;	/* Byte 45 Bit 0 */
+	unsigned char:7;	/* Byte 45 Bits 1-7 */
+	unsigned short NonTaggedToAlternateLUNPermitted;	/* Bytes 46-47 */
+	unsigned short RenegotiateSyncAfterCheckCondition;	/* Bytes 48-49 */
+	unsigned char Reserved[10];	/* Bytes 50-59 */
+	unsigned char ManufacturingDiagnostic[2];	/* Bytes 60-61 */
+	unsigned short Checksum;	/* Bytes 62-63 */
+} PACKED;
+
+/*
+  Define the Host Adapter Local RAM Auto SCSI Byte 45 structure.
+*/
+
+struct BusLogic_AutoSCSIByte45 {
+	unsigned char ForceBusDeviceScanningOrder:1;	/* Bit 0 */
+	unsigned char:7;	/* Bits 1-7 */
+};
+
+/*
+  Define the Host Adapter Local RAM BIOS Drive Map Byte structure.
+*/
+
+#define BusLogic_BIOS_DriveMapOffset		17
+
+struct BusLogic_BIOSDriveMapByte {
+	unsigned char TargetIDBit3:1;	/* Bit 0 */
+	unsigned char:2;	/* Bits 1-2 */
+	enum BusLogic_BIOS_DiskGeometryTranslation DiskGeometry:2;	/* Bits 3-4 */
+	unsigned char TargetID:3;	/* Bits 5-7 */
+};
+
+/*
+  Define the Set CCB Format request type.  Extended LUN Format CCBs are
+  necessary to support more than 8 Logical Units per Target Device.
+*/
+
+enum BusLogic_SetCCBFormatRequest {
+	BusLogic_LegacyLUNFormatCCB = 0,
+	BusLogic_ExtendedLUNFormatCCB = 1
+} PACKED;
+
+/*
+  Define the Outgoing Mailbox Action Codes.
+*/
+
+enum BusLogic_ActionCode {
+	BusLogic_OutgoingMailboxFree = 0x00,
+	BusLogic_MailboxStartCommand = 0x01,
+	BusLogic_MailboxAbortCommand = 0x02
+} PACKED;
+
+
+/*
+  Define the Incoming Mailbox Completion Codes.  The MultiMaster Firmware
+  only uses codes 0 - 4.  The FlashPoint SCCB Manager has no mailboxes, so
+  completion codes are stored in the CCB; it only uses codes 1, 2, 4, and 5.
+*/
+
+enum BusLogic_CompletionCode {
+	BusLogic_IncomingMailboxFree = 0x00,
+	BusLogic_CommandCompletedWithoutError = 0x01,
+	BusLogic_CommandAbortedAtHostRequest = 0x02,
+	BusLogic_AbortedCommandNotFound = 0x03,
+	BusLogic_CommandCompletedWithError = 0x04,
+	BusLogic_InvalidCCB = 0x05
+} PACKED;
+
+/*
+  Define the Command Control Block (CCB) Opcodes.
+*/
+
+enum BusLogic_CCB_Opcode {
+	BusLogic_InitiatorCCB = 0x00,
+	BusLogic_TargetCCB = 0x01,
+	BusLogic_InitiatorCCB_ScatterGather = 0x02,
+	BusLogic_InitiatorCCB_ResidualDataLength = 0x03,
+	BusLogic_InitiatorCCB_ScatterGatherResidual = 0x04,
+	BusLogic_BusDeviceReset = 0x81
+} PACKED;
+
+
+/*
+  Define the CCB Data Direction Codes.
+*/
+
+enum BusLogic_DataDirection {
+	BusLogic_UncheckedDataTransfer = 0,
+	BusLogic_DataInLengthChecked = 1,
+	BusLogic_DataOutLengthChecked = 2,
+	BusLogic_NoDataTransfer = 3
+};
+
+
+/*
+  Define the Host Adapter Status Codes.  The MultiMaster Firmware does not
+  return status code 0x0C; it uses 0x12 for both overruns and underruns.
+*/
+
+enum BusLogic_HostAdapterStatus {
+	BusLogic_CommandCompletedNormally = 0x00,
+	BusLogic_LinkedCommandCompleted = 0x0A,
+	BusLogic_LinkedCommandCompletedWithFlag = 0x0B,
+	BusLogic_DataUnderRun = 0x0C,
+	BusLogic_SCSISelectionTimeout = 0x11,
+	BusLogic_DataOverRun = 0x12,
+	BusLogic_UnexpectedBusFree = 0x13,
+	BusLogic_InvalidBusPhaseRequested = 0x14,
+	BusLogic_InvalidOutgoingMailboxActionCode = 0x15,
+	BusLogic_InvalidCommandOperationCode = 0x16,
+	BusLogic_LinkedCCBhasInvalidLUN = 0x17,
+	BusLogic_InvalidCommandParameter = 0x1A,
+	BusLogic_AutoRequestSenseFailed = 0x1B,
+	BusLogic_TaggedQueuingMessageRejected = 0x1C,
+	BusLogic_UnsupportedMessageReceived = 0x1D,
+	BusLogic_HostAdapterHardwareFailed = 0x20,
+	BusLogic_TargetFailedResponseToATN = 0x21,
+	BusLogic_HostAdapterAssertedRST = 0x22,
+	BusLogic_OtherDeviceAssertedRST = 0x23,
+	BusLogic_TargetDeviceReconnectedImproperly = 0x24,
+	BusLogic_HostAdapterAssertedBusDeviceReset = 0x25,
+	BusLogic_AbortQueueGenerated = 0x26,
+	BusLogic_HostAdapterSoftwareError = 0x27,
+	BusLogic_HostAdapterHardwareTimeoutError = 0x30,
+	BusLogic_SCSIParityErrorDetected = 0x34
+} PACKED;
+
+
+/*
+  Define the SCSI Target Device Status Codes.
+*/
+
+enum BusLogic_TargetDeviceStatus {
+	BusLogic_OperationGood = 0x00,
+	BusLogic_CheckCondition = 0x02,
+	BusLogic_DeviceBusy = 0x08
+} PACKED;
+
+/*
+  Define the Queue Tag Codes.
+*/
+
+enum BusLogic_QueueTag {
+	BusLogic_SimpleQueueTag = 0,
+	BusLogic_HeadOfQueueTag = 1,
+	BusLogic_OrderedQueueTag = 2,
+	BusLogic_ReservedQT = 3
+};
+
+/*
+  Define the SCSI Command Descriptor Block (CDB).
+*/
+
+#define BusLogic_CDB_MaxLength			12
+
+typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength];
+
+
+/*
+  Define the Scatter/Gather Segment structure required by the MultiMaster
+  Firmware Interface and the FlashPoint SCCB Manager.
+*/
+
+struct BusLogic_ScatterGatherSegment {
+	u32 SegmentByteCount;	/* Bytes 0-3 */
+	u32 SegmentDataPointer;	/* Bytes 4-7 */
+};
+
+/*
+  Define the Driver CCB Status Codes.
+*/
+
+enum BusLogic_CCB_Status {
+	BusLogic_CCB_Free = 0,
+	BusLogic_CCB_Active = 1,
+	BusLogic_CCB_Completed = 2,
+	BusLogic_CCB_Reset = 3
+} PACKED;
+
+
+/*
+  Define the 32 Bit Mode Command Control Block (CCB) structure.  The first 40
+  bytes are defined by and common to both the MultiMaster Firmware and the
+  FlashPoint SCCB Manager.  The next 60 bytes are defined by the FlashPoint
+  SCCB Manager.  The remaining components are defined by the Linux BusLogic
+  Driver.  Extended LUN Format CCBs differ from Legacy LUN Format 32 Bit Mode
+  CCBs only in having the TagEnable and QueueTag fields moved from byte 17 to
+  byte 1, and the Logical Unit field in byte 17 expanded to 6 bits.  In theory,
+  Extended LUN Format CCBs can support up to 64 Logical Units, but in practice
+  many devices will respond improperly to Logical Units between 32 and 63, and
+  the SCSI-2 specification defines Bit 5 as LUNTAR.  Extended LUN Format CCBs
+  are used by recent versions of the MultiMaster Firmware, as well as by the
+  FlashPoint SCCB Manager; the FlashPoint SCCB Manager only supports 32 Logical
+  Units.  Since 64 Logical Units are unlikely to be needed in practice, and
+  since they are problematic for the above reasons, and since limiting them to
+  5 bits simplifies the CCB structure definition, this driver only supports
+  32 Logical Units per Target Device.
+*/
+
+struct BusLogic_CCB {
+	/*
+	   MultiMaster Firmware and FlashPoint SCCB Manager Common Portion.
+	 */
+	enum BusLogic_CCB_Opcode Opcode;	/* Byte 0 */
+	unsigned char:3;	/* Byte 1 Bits 0-2 */
+	enum BusLogic_DataDirection DataDirection:2;	/* Byte 1 Bits 3-4 */
+	boolean TagEnable:1;	/* Byte 1 Bit 5 */
+	enum BusLogic_QueueTag QueueTag:2;	/* Byte 1 Bits 6-7 */
+	unsigned char CDB_Length;	/* Byte 2 */
+	unsigned char SenseDataLength;	/* Byte 3 */
+	u32 DataLength;		/* Bytes 4-7 */
+	u32 DataPointer;	/* Bytes 8-11 */
+	unsigned char:8;	/* Byte 12 */
+	unsigned char:8;	/* Byte 13 */
+	enum BusLogic_HostAdapterStatus HostAdapterStatus;	/* Byte 14 */
+	enum BusLogic_TargetDeviceStatus TargetDeviceStatus;	/* Byte 15 */
+	unsigned char TargetID;	/* Byte 16 */
+	unsigned char LogicalUnit:5;	/* Byte 17 Bits 0-4 */
+	boolean LegacyTagEnable:1;	/* Byte 17 Bit 5 */
+	enum BusLogic_QueueTag LegacyQueueTag:2;	/* Byte 17 Bits 6-7 */
+	SCSI_CDB_T CDB;		/* Bytes 18-29 */
+	unsigned char:8;	/* Byte 30 */
+	unsigned char:8;	/* Byte 31 */
+	unsigned int:32;	/* Bytes 32-35 */
+	u32 SenseDataPointer;	/* Bytes 36-39 */
+	/*
+	   FlashPoint SCCB Manager Defined Portion.
+	 */
+	void (*CallbackFunction) (struct BusLogic_CCB *);	/* Bytes 40-43 */
+	u32 BaseAddress;	/* Bytes 44-47 */
+	enum BusLogic_CompletionCode CompletionCode;	/* Byte 48 */
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+	unsigned char:8;	/* Byte 49 */
+	unsigned short OS_Flags;	/* Bytes 50-51 */
+	unsigned char Private[48];	/* Bytes 52-99 */
+#endif
+	/*
+	   BusLogic Linux Driver Defined Portion.
+	 */
+	dma_addr_t AllocationGroupHead;
+	unsigned int AllocationGroupSize;
+	u32 DMA_Handle;
+	enum BusLogic_CCB_Status Status;
+	unsigned long SerialNumber;
+	struct scsi_cmnd *Command;
+	struct BusLogic_HostAdapter *HostAdapter;
+	struct BusLogic_CCB *Next;
+	struct BusLogic_CCB *NextAll;
+	struct BusLogic_ScatterGatherSegment
+	 ScatterGatherList[BusLogic_ScatterGatherLimit];
+};
+
+/*
+  Define the 32 Bit Mode Outgoing Mailbox structure.
+*/
+
+struct BusLogic_OutgoingMailbox {
+	u32 CCB;		/* Bytes 0-3 */
+	unsigned int:24;	/* Bytes 4-6 */
+	enum BusLogic_ActionCode ActionCode;	/* Byte 7 */
+};
+
+/*
+  Define the 32 Bit Mode Incoming Mailbox structure.
+*/
+
+struct BusLogic_IncomingMailbox {
+	u32 CCB;		/* Bytes 0-3 */
+	enum BusLogic_HostAdapterStatus HostAdapterStatus;	/* Byte 4 */
+	enum BusLogic_TargetDeviceStatus TargetDeviceStatus;	/* Byte 5 */
+	unsigned char:8;	/* Byte 6 */
+	enum BusLogic_CompletionCode CompletionCode;	/* Byte 7 */
+};
+
+
+/*
+  Define the BusLogic Driver Options structure.
+*/
+
+struct BusLogic_DriverOptions {
+	unsigned short TaggedQueuingPermitted;
+	unsigned short TaggedQueuingPermittedMask;
+	unsigned short BusSettleTime;
+	struct BusLogic_LocalOptions LocalOptions;
+	unsigned char CommonQueueDepth;
+	unsigned char QueueDepth[BusLogic_MaxTargetDevices];
+};
+
+/*
+  Define the Host Adapter Target Flags structure.
+*/
+
+struct BusLogic_TargetFlags {
+	boolean TargetExists:1;
+	boolean TaggedQueuingSupported:1;
+	boolean WideTransfersSupported:1;
+	boolean TaggedQueuingActive:1;
+	boolean WideTransfersActive:1;
+	boolean CommandSuccessfulFlag:1;
+	boolean TargetInfoReported:1;
+};
+
+/*
+  Define the Host Adapter Target Statistics structure.
+*/
+
+#define BusLogic_SizeBuckets			10
+
+typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets];
+
+struct BusLogic_TargetStatistics {
+	unsigned int CommandsAttempted;
+	unsigned int CommandsCompleted;
+	unsigned int ReadCommands;
+	unsigned int WriteCommands;
+	struct BusLogic_ByteCounter TotalBytesRead;
+	struct BusLogic_ByteCounter TotalBytesWritten;
+	BusLogic_CommandSizeBuckets_T ReadCommandSizeBuckets;
+	BusLogic_CommandSizeBuckets_T WriteCommandSizeBuckets;
+	unsigned short CommandAbortsRequested;
+	unsigned short CommandAbortsAttempted;
+	unsigned short CommandAbortsCompleted;
+	unsigned short BusDeviceResetsRequested;
+	unsigned short BusDeviceResetsAttempted;
+	unsigned short BusDeviceResetsCompleted;
+	unsigned short HostAdapterResetsRequested;
+	unsigned short HostAdapterResetsAttempted;
+	unsigned short HostAdapterResetsCompleted;
+};
+
+/*
+  Define the FlashPoint Card Handle data type.
+*/
+
+#define FlashPoint_BadCardHandle		0xFFFFFFFF
+
+typedef unsigned int FlashPoint_CardHandle_T;
+
+
+/*
+  Define the FlashPoint Information structure.  This structure is defined
+  by the FlashPoint SCCB Manager.
+*/
+
+struct FlashPoint_Info {
+	u32 BaseAddress;	/* Bytes 0-3 */
+	boolean Present;	/* Byte 4 */
+	unsigned char IRQ_Channel;	/* Byte 5 */
+	unsigned char SCSI_ID;	/* Byte 6 */
+	unsigned char SCSI_LUN;	/* Byte 7 */
+	unsigned short FirmwareRevision;	/* Bytes 8-9 */
+	unsigned short SynchronousPermitted;	/* Bytes 10-11 */
+	unsigned short FastPermitted;	/* Bytes 12-13 */
+	unsigned short UltraPermitted;	/* Bytes 14-15 */
+	unsigned short DisconnectPermitted;	/* Bytes 16-17 */
+	unsigned short WidePermitted;	/* Bytes 18-19 */
+	boolean ParityCheckingEnabled:1;	/* Byte 20 Bit 0 */
+	boolean HostWideSCSI:1;	/* Byte 20 Bit 1 */
+	boolean HostSoftReset:1;	/* Byte 20 Bit 2 */
+	boolean ExtendedTranslationEnabled:1;	/* Byte 20 Bit 3 */
+	boolean LowByteTerminated:1;	/* Byte 20 Bit 4 */
+	boolean HighByteTerminated:1;	/* Byte 20 Bit 5 */
+	boolean ReportDataUnderrun:1;	/* Byte 20 Bit 6 */
+	boolean SCAM_Enabled:1;	/* Byte 20 Bit 7 */
+	boolean SCAM_Level2:1;	/* Byte 21 Bit 0 */
+	unsigned char:7;	/* Byte 21 Bits 1-7 */
+	unsigned char Family;	/* Byte 22 */
+	unsigned char BusType;	/* Byte 23 */
+	unsigned char ModelNumber[3];	/* Bytes 24-26 */
+	unsigned char RelativeCardNumber;	/* Byte 27 */
+	unsigned char Reserved[4];	/* Bytes 28-31 */
+	unsigned int OS_Reserved;	/* Bytes 32-35 */
+	unsigned char TranslationInfo[4];	/* Bytes 36-39 */
+	unsigned int Reserved2[5];	/* Bytes 40-59 */
+	unsigned int SecondaryRange;	/* Bytes 60-63 */
+};
+
+/*
+  Define the BusLogic Driver Host Adapter structure.
+*/
+
+struct BusLogic_HostAdapter {
+	struct Scsi_Host *SCSI_Host;
+	struct pci_dev *PCI_Device;
+	enum BusLogic_HostAdapterType HostAdapterType;
+	enum BusLogic_HostAdapterBusType HostAdapterBusType;
+	unsigned long IO_Address;
+	unsigned long PCI_Address;
+	unsigned short AddressCount;
+	unsigned char HostNumber;
+	unsigned char ModelName[9];
+	unsigned char FirmwareVersion[6];
+	unsigned char FullModelName[18];
+	unsigned char Bus;
+	unsigned char Device;
+	unsigned char IRQ_Channel;
+	unsigned char DMA_Channel;
+	unsigned char SCSI_ID;
+	boolean IRQ_ChannelAcquired:1;
+	boolean DMA_ChannelAcquired:1;
+	boolean ExtendedTranslationEnabled:1;
+	boolean ParityCheckingEnabled:1;
+	boolean BusResetEnabled:1;
+	boolean LevelSensitiveInterrupt:1;
+	boolean HostWideSCSI:1;
+	boolean HostDifferentialSCSI:1;
+	boolean HostSupportsSCAM:1;
+	boolean HostUltraSCSI:1;
+	boolean ExtendedLUNSupport:1;
+	boolean TerminationInfoValid:1;
+	boolean LowByteTerminated:1;
+	boolean HighByteTerminated:1;
+	boolean BounceBuffersRequired:1;
+	boolean StrictRoundRobinModeSupport:1;
+	boolean SCAM_Enabled:1;
+	boolean SCAM_Level2:1;
+	boolean HostAdapterInitialized:1;
+	boolean HostAdapterExternalReset:1;
+	boolean HostAdapterInternalError:1;
+	boolean ProcessCompletedCCBsActive;
+	volatile boolean HostAdapterCommandCompleted;
+	unsigned short HostAdapterScatterGatherLimit;
+	unsigned short DriverScatterGatherLimit;
+	unsigned short MaxTargetDevices;
+	unsigned short MaxLogicalUnits;
+	unsigned short MailboxCount;
+	unsigned short InitialCCBs;
+	unsigned short IncrementalCCBs;
+	unsigned short AllocatedCCBs;
+	unsigned short DriverQueueDepth;
+	unsigned short HostAdapterQueueDepth;
+	unsigned short UntaggedQueueDepth;
+	unsigned short CommonQueueDepth;
+	unsigned short BusSettleTime;
+	unsigned short SynchronousPermitted;
+	unsigned short FastPermitted;
+	unsigned short UltraPermitted;
+	unsigned short WidePermitted;
+	unsigned short DisconnectPermitted;
+	unsigned short TaggedQueuingPermitted;
+	unsigned short ExternalHostAdapterResets;
+	unsigned short HostAdapterInternalErrors;
+	unsigned short TargetDeviceCount;
+	unsigned short MessageBufferLength;
+	u32 BIOS_Address;
+	struct BusLogic_DriverOptions *DriverOptions;
+	struct FlashPoint_Info FlashPointInfo;
+	FlashPoint_CardHandle_T CardHandle;
+	struct list_head host_list;
+	struct BusLogic_CCB *All_CCBs;
+	struct BusLogic_CCB *Free_CCBs;
+	struct BusLogic_CCB *FirstCompletedCCB;
+	struct BusLogic_CCB *LastCompletedCCB;
+	struct BusLogic_CCB *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
+	struct BusLogic_TargetFlags TargetFlags[BusLogic_MaxTargetDevices];
+	unsigned char QueueDepth[BusLogic_MaxTargetDevices];
+	unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices];
+	unsigned char SynchronousOffset[BusLogic_MaxTargetDevices];
+	unsigned char ActiveCommands[BusLogic_MaxTargetDevices];
+	unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices];
+	unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
+	unsigned long LastResetAttempted[BusLogic_MaxTargetDevices];
+	unsigned long LastResetCompleted[BusLogic_MaxTargetDevices];
+	struct BusLogic_OutgoingMailbox *FirstOutgoingMailbox;
+	struct BusLogic_OutgoingMailbox *LastOutgoingMailbox;
+	struct BusLogic_OutgoingMailbox *NextOutgoingMailbox;
+	struct BusLogic_IncomingMailbox *FirstIncomingMailbox;
+	struct BusLogic_IncomingMailbox *LastIncomingMailbox;
+	struct BusLogic_IncomingMailbox *NextIncomingMailbox;
+	struct BusLogic_TargetStatistics TargetStatistics[BusLogic_MaxTargetDevices];
+	unsigned char *MailboxSpace;
+	dma_addr_t MailboxSpaceHandle;
+	unsigned int MailboxSize;
+	unsigned long CCB_Offset;
+	char MessageBuffer[BusLogic_MessageBufferSize];
+};
+
+/*
+  Define a structure for the BIOS Disk Parameters.
+*/
+
+struct BIOS_DiskParameters {
+	int Heads;
+	int Sectors;
+	int Cylinders;
+};
+
+/*
+  Define a structure for the SCSI Inquiry command results.
+*/
+
+struct SCSI_Inquiry {
+	unsigned char PeripheralDeviceType:5;	/* Byte 0 Bits 0-4 */
+	unsigned char PeripheralQualifier:3;	/* Byte 0 Bits 5-7 */
+	unsigned char DeviceTypeModifier:7;	/* Byte 1 Bits 0-6 */
+	boolean RMB:1;		/* Byte 1 Bit 7 */
+	unsigned char ANSI_ApprovedVersion:3;	/* Byte 2 Bits 0-2 */
+	unsigned char ECMA_Version:3;	/* Byte 2 Bits 3-5 */
+	unsigned char ISO_Version:2;	/* Byte 2 Bits 6-7 */
+	unsigned char ResponseDataFormat:4;	/* Byte 3 Bits 0-3 */
+	unsigned char:2;	/* Byte 3 Bits 4-5 */
+	boolean TrmIOP:1;	/* Byte 3 Bit 6 */
+	boolean AENC:1;		/* Byte 3 Bit 7 */
+	unsigned char AdditionalLength;	/* Byte 4 */
+	unsigned char:8;	/* Byte 5 */
+	unsigned char:8;	/* Byte 6 */
+	boolean SftRe:1;	/* Byte 7 Bit 0 */
+	boolean CmdQue:1;	/* Byte 7 Bit 1 */
+	 boolean:1;		/* Byte 7 Bit 2 */
+	boolean Linked:1;	/* Byte 7 Bit 3 */
+	boolean Sync:1;		/* Byte 7 Bit 4 */
+	boolean WBus16:1;	/* Byte 7 Bit 5 */
+	boolean WBus32:1;	/* Byte 7 Bit 6 */
+	boolean RelAdr:1;	/* Byte 7 Bit 7 */
+	unsigned char VendorIdentification[8];	/* Bytes 8-15 */
+	unsigned char ProductIdentification[16];	/* Bytes 16-31 */
+	unsigned char ProductRevisionLevel[4];	/* Bytes 32-35 */
+};
+
+
+/*
+  Define functions to provide an abstraction for reading and writing the
+  Host Adapter I/O Registers.
+*/
+
+static inline void BusLogic_SCSIBusReset(struct BusLogic_HostAdapter *HostAdapter)
+{
+	union BusLogic_ControlRegister ControlRegister;
+	ControlRegister.All = 0;
+	ControlRegister.cr.SCSIBusReset = true;
+	outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset);
+}
+
+static inline void BusLogic_InterruptReset(struct BusLogic_HostAdapter *HostAdapter)
+{
+	union BusLogic_ControlRegister ControlRegister;
+	ControlRegister.All = 0;
+	ControlRegister.cr.InterruptReset = true;
+	outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset);
+}
+
+static inline void BusLogic_SoftReset(struct BusLogic_HostAdapter *HostAdapter)
+{
+	union BusLogic_ControlRegister ControlRegister;
+	ControlRegister.All = 0;
+	ControlRegister.cr.SoftReset = true;
+	outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset);
+}
+
+static inline void BusLogic_HardReset(struct BusLogic_HostAdapter *HostAdapter)
+{
+	union BusLogic_ControlRegister ControlRegister;
+	ControlRegister.All = 0;
+	ControlRegister.cr.HardReset = true;
+	outb(ControlRegister.All, HostAdapter->IO_Address + BusLogic_ControlRegisterOffset);
+}
+
+static inline unsigned char BusLogic_ReadStatusRegister(struct BusLogic_HostAdapter *HostAdapter)
+{
+	return inb(HostAdapter->IO_Address + BusLogic_StatusRegisterOffset);
+}
+
+static inline void BusLogic_WriteCommandParameterRegister(struct BusLogic_HostAdapter
+							  *HostAdapter, unsigned char Value)
+{
+	outb(Value, HostAdapter->IO_Address + BusLogic_CommandParameterRegisterOffset);
+}
+
+static inline unsigned char BusLogic_ReadDataInRegister(struct BusLogic_HostAdapter *HostAdapter)
+{
+	return inb(HostAdapter->IO_Address + BusLogic_DataInRegisterOffset);
+}
+
+static inline unsigned char BusLogic_ReadInterruptRegister(struct BusLogic_HostAdapter *HostAdapter)
+{
+	return inb(HostAdapter->IO_Address + BusLogic_InterruptRegisterOffset);
+}
+
+static inline unsigned char BusLogic_ReadGeometryRegister(struct BusLogic_HostAdapter *HostAdapter)
+{
+	return inb(HostAdapter->IO_Address + BusLogic_GeometryRegisterOffset);
+}
+
+/*
+  BusLogic_StartMailboxCommand issues an Execute Mailbox Command, which
+  notifies the Host Adapter that an entry has been made in an Outgoing
+  Mailbox.
+*/
+
+static inline void BusLogic_StartMailboxCommand(struct BusLogic_HostAdapter *HostAdapter)
+{
+	BusLogic_WriteCommandParameterRegister(HostAdapter, BusLogic_ExecuteMailboxCommand);
+}
+
+/*
+  BusLogic_Delay waits for Seconds to elapse.
+*/
+
+static inline void BusLogic_Delay(int Seconds)
+{
+	mdelay(1000 * Seconds);
+}
+
+/*
+  Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses
+  and PCI/VLB/EISA/ISA Bus Addresses.
+*/
+
+static inline u32 Virtual_to_Bus(void *VirtualAddress)
+{
+	return (u32) virt_to_bus(VirtualAddress);
+}
+
+static inline void *Bus_to_Virtual(u32 BusAddress)
+{
+	return (void *) bus_to_virt(BusAddress);
+}
+
+/*
+  Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
+  32 bit Kernel Virtual Addresses.  This avoids compilation warnings
+  on 64 bit architectures.
+*/
+
+static inline u32 Virtual_to_32Bit_Virtual(void *VirtualAddress)
+{
+	return (u32) (unsigned long) VirtualAddress;
+}
+
+/*
+  BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at
+  65535 rather than wrapping around to 0.
+*/
+
+static inline void BusLogic_IncrementErrorCounter(unsigned short *ErrorCounter)
+{
+	if (*ErrorCounter < 65535)
+		(*ErrorCounter)++;
+}
+
+/*
+  BusLogic_IncrementByteCounter increments Byte Counter by Amount.
+*/
+
+static inline void BusLogic_IncrementByteCounter(struct BusLogic_ByteCounter
+						 *ByteCounter, unsigned int Amount)
+{
+	ByteCounter->Units += Amount;
+	if (ByteCounter->Units > 999999999) {
+		ByteCounter->Units -= 1000000000;
+		ByteCounter->Billions++;
+	}
+}
+
+/*
+  BusLogic_IncrementSizeBucket increments the Bucket for Amount.
+*/
+
+static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T CommandSizeBuckets, unsigned int Amount)
+{
+	int Index = 0;
+	if (Amount < 8 * 1024) {
+		if (Amount < 2 * 1024)
+			Index = (Amount < 1 * 1024 ? 0 : 1);
+		else
+			Index = (Amount < 4 * 1024 ? 2 : 3);
+	} else if (Amount < 128 * 1024) {
+		if (Amount < 32 * 1024)
+			Index = (Amount < 16 * 1024 ? 4 : 5);
+		else
+			Index = (Amount < 64 * 1024 ? 6 : 7);
+	} else
+		Index = (Amount < 256 * 1024 ? 8 : 9);
+	CommandSizeBuckets[Index]++;
+}
+
+/*
+  Define the version number of the FlashPoint Firmware (SCCB Manager).
+*/
+
+#define FlashPoint_FirmwareVersion		"5.02"
+
+/*
+  Define the possible return values from FlashPoint_HandleInterrupt.
+*/
+
+#define FlashPoint_NormalInterrupt		0x00
+#define FlashPoint_InternalError		0xFE
+#define FlashPoint_ExternalBusReset		0xFF
+
+/*
+  Define prototypes for the forward referenced BusLogic Driver
+  Internal Functions.
+*/
+
+static const char *BusLogic_DriverInfo(struct Scsi_Host *);
+static int BusLogic_QueueCommand(struct scsi_cmnd *, void (*CompletionRoutine) (struct scsi_cmnd *));
+static int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *);
+static int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int);
+static int BusLogic_SlaveConfigure(struct scsi_device *);
+static void BusLogic_QueueCompletedCCB(struct BusLogic_CCB *);
+static irqreturn_t BusLogic_InterruptHandler(int, void *, struct pt_regs *);
+static int BusLogic_ResetHostAdapter(struct BusLogic_HostAdapter *, boolean HardReset);
+static void BusLogic_Message(enum BusLogic_MessageLevel, char *, struct BusLogic_HostAdapter *, ...);
+static int __init BusLogic_Setup(char *);
+
+#endif				/* _BUSLOGIC_H */
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
new file mode 100644
index 0000000..56a695c
--- /dev/null
+++ b/drivers/scsi/FlashPoint.c
@@ -0,0 +1,12159 @@
+/*
+
+  FlashPoint.c -- FlashPoint SCCB Manager for Linux
+
+  This file contains the FlashPoint SCCB Manager from BusLogic's FlashPoint
+  Driver Developer's Kit, with minor modifications by Leonard N. Zubkoff for
+  Linux compatibility.  It was provided by BusLogic in the form of 16 separate
+  source files, which would have unnecessarily cluttered the scsi directory, so
+  the individual files have been combined into this single file.
+
+  Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+
+  This file is available under both the GNU General Public License
+  and a BSD-style copyright; see LICENSE.FlashPoint for details.
+
+*/
+
+
+#include <linux/config.h>
+
+
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+
+
+#define UNIX
+#define FW_TYPE		_SCCB_MGR_
+#define MAX_CARDS	8
+#undef BUSTYPE_PCI
+
+
+#define OS_InPortByte(port)		inb(port)
+#define OS_InPortWord(port)		inw(port)
+#define OS_InPortLong(port)		inl(port)
+#define OS_OutPortByte(port, value)	outb(value, port)
+#define OS_OutPortWord(port, value)	outw(value, port)
+#define OS_OutPortLong(port, value)	outl(value, port)
+#define OS_Lock(x)
+#define OS_UnLock(x)
+
+
+/*
+  Define name replacements for compatibility with the Linux BusLogic Driver.
+*/
+
+#define SccbMgr_sense_adapter		FlashPoint_ProbeHostAdapter
+#define SccbMgr_config_adapter		FlashPoint_HardwareResetHostAdapter
+#define SccbMgr_unload_card		FlashPoint_ReleaseHostAdapter
+#define SccbMgr_start_sccb		FlashPoint_StartCCB
+#define SccbMgr_abort_sccb		FlashPoint_AbortCCB
+#define SccbMgr_my_int			FlashPoint_InterruptPending
+#define SccbMgr_isr			FlashPoint_HandleInterrupt
+
+
+/*
+  Define name replacements to avoid kernel namespace pollution.
+*/
+
+#define BL_Card				FPT_BL_Card
+#define BusMasterInit			FPT_BusMasterInit
+#define CalcCrc16			FPT_CalcCrc16
+#define CalcLrc				FPT_CalcLrc
+#define ChkIfChipInitialized		FPT_ChkIfChipInitialized
+#define DiagBusMaster			FPT_DiagBusMaster
+#define DiagEEPROM			FPT_DiagEEPROM
+#define DiagXbow			FPT_DiagXbow
+#define GetTarLun			FPT_GetTarLun
+#define RNVRamData			FPT_RNVRamData
+#define RdStack				FPT_RdStack
+#define SccbMgrTableInitAll		FPT_SccbMgrTableInitAll
+#define SccbMgrTableInitCard		FPT_SccbMgrTableInitCard
+#define SccbMgrTableInitTarget		FPT_SccbMgrTableInitTarget
+#define SccbMgr_bad_isr			FPT_SccbMgr_bad_isr
+#define SccbMgr_scsi_reset		FPT_SccbMgr_scsi_reset
+#define SccbMgr_timer_expired		FPT_SccbMgr_timer_expired
+#define SendMsg				FPT_SendMsg
+#define Wait				FPT_Wait
+#define Wait1Second			FPT_Wait1Second
+#define WrStack				FPT_WrStack
+#define XbowInit			FPT_XbowInit
+#define autoCmdCmplt			FPT_autoCmdCmplt
+#define autoLoadDefaultMap		FPT_autoLoadDefaultMap
+#define busMstrDataXferStart		FPT_busMstrDataXferStart
+#define busMstrSGDataXferStart		FPT_busMstrSGDataXferStart
+#define busMstrTimeOut			FPT_busMstrTimeOut
+#define dataXferProcessor		FPT_dataXferProcessor
+#define default_intena			FPT_default_intena
+#define hostDataXferAbort		FPT_hostDataXferAbort
+#define hostDataXferRestart		FPT_hostDataXferRestart
+#define inisci				FPT_inisci
+#define mbCards				FPT_mbCards
+#define nvRamInfo			FPT_nvRamInfo
+#define phaseBusFree			FPT_phaseBusFree
+#define phaseChkFifo			FPT_phaseChkFifo
+#define phaseCommand			FPT_phaseCommand
+#define phaseDataIn			FPT_phaseDataIn
+#define phaseDataOut			FPT_phaseDataOut
+#define phaseDecode			FPT_phaseDecode
+#define phaseIllegal			FPT_phaseIllegal
+#define phaseMsgIn			FPT_phaseMsgIn
+#define phaseMsgOut			FPT_phaseMsgOut
+#define phaseStatus			FPT_phaseStatus
+#define queueAddSccb			FPT_queueAddSccb
+#define queueCmdComplete		FPT_queueCmdComplete
+#define queueDisconnect			FPT_queueDisconnect
+#define queueFindSccb			FPT_queueFindSccb
+#define queueFlushSccb			FPT_queueFlushSccb
+#define queueFlushTargSccb		FPT_queueFlushTargSccb
+#define queueSearchSelect		FPT_queueSearchSelect
+#define queueSelectFail			FPT_queueSelectFail
+#define s_PhaseTbl			FPT_s_PhaseTbl
+#define scamHAString			FPT_scamHAString
+#define scamInfo			FPT_scamInfo
+#define scarb				FPT_scarb
+#define scasid				FPT_scasid
+#define scbusf				FPT_scbusf
+#define sccbMgrTbl			FPT_sccbMgrTbl
+#define schkdd				FPT_schkdd
+#define scini				FPT_scini
+#define sciso				FPT_sciso
+#define scmachid			FPT_scmachid
+#define scsavdi				FPT_scsavdi
+#define scsel				FPT_scsel
+#define scsell				FPT_scsell
+#define scsendi				FPT_scsendi
+#define scvalq				FPT_scvalq
+#define scwirod				FPT_scwirod
+#define scwiros				FPT_scwiros
+#define scwtsel				FPT_scwtsel
+#define scxferc				FPT_scxferc
+#define sdecm				FPT_sdecm
+#define sfm				FPT_sfm
+#define shandem				FPT_shandem
+#define sinits				FPT_sinits
+#define sisyncn				FPT_sisyncn
+#define sisyncr				FPT_sisyncr
+#define siwidn				FPT_siwidn
+#define siwidr				FPT_siwidr
+#define sres				FPT_sres
+#define sresb				FPT_sresb
+#define ssel				FPT_ssel
+#define ssenss				FPT_ssenss
+#define sssyncv				FPT_sssyncv
+#define stsyncn				FPT_stsyncn
+#define stwidn				FPT_stwidn
+#define sxfrp				FPT_sxfrp
+#define utilEERead			FPT_utilEERead
+#define utilEEReadOrg			FPT_utilEEReadOrg
+#define utilEESendCmdAddr		FPT_utilEESendCmdAddr
+#define utilEEWrite			FPT_utilEEWrite
+#define utilEEWriteOnOff		FPT_utilEEWriteOnOff
+#define utilUpdateResidual		FPT_utilUpdateResidual
+
+
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   globals.h  $
+ *
+ *   Description:  Common shared global defines.
+ *
+ *   $Date: 1996/09/04 01:26:13 $
+ *
+ *   $Revision: 1.11 $
+ *
+ *----------------------------------------------------------------------*/
+#ifndef __GLOBALS_H__
+#define __GLOBALS_H__
+
+#define _UCB_MGR_  1
+#define _SCCB_MGR_ 2
+
+/*#include <osflags.h>*/
+
+#define MAX_CDBLEN  12
+
+#define SCAM_LEV_2	1
+
+#define CRCMASK	0xA001
+
+/*  In your osflags.h file, please ENSURE that only ONE OS FLAG 
+    is on at a time !!! Also, please make sure you turn set the 
+ 	 variable FW_TYPE to either _UCB_MGR_ or _SCCB_MGR_  !!! */
+
+#if defined(DOS) || defined(WIN95_16) || defined(OS2) || defined(OTHER_16)
+   #define       COMPILER_16_BIT 1
+#elif defined(NETWARE) || defined(NT) || defined(WIN95_32) || defined(UNIX) || defined(OTHER_32) || defined(SOLARIS_REAL_MODE)
+   #define       COMPILER_32_BIT 1
+#endif
+
+
+#define     BL_VENDOR_ID      0x104B
+#define     FP_DEVICE_ID      0x8130
+#define     MM_DEVICE_ID      0x1040
+
+
+#ifndef FALSE
+#define FALSE           0
+#endif
+#ifndef TRUE
+#define TRUE            (!(FALSE))
+#endif
+
+#ifndef NULL
+#define NULL            0
+#endif
+
+#define FAILURE         0xFFFFFFFFL
+
+
+typedef unsigned char   UCHAR;
+typedef unsigned short  USHORT;
+typedef unsigned int    UINT;
+typedef unsigned long   ULONG;
+typedef unsigned char * PUCHAR;
+typedef unsigned short* PUSHORT;
+typedef unsigned long * PULONG;
+typedef void *          PVOID;
+
+
+#if defined(COMPILER_16_BIT)
+typedef unsigned char far       * uchar_ptr;
+typedef unsigned short far      * ushort_ptr;
+typedef unsigned long far       * ulong_ptr;
+#endif  /* 16_BIT_COMPILER */
+
+#if defined(COMPILER_32_BIT)
+typedef unsigned char           * uchar_ptr;
+typedef unsigned short          * ushort_ptr;
+typedef unsigned long           * ulong_ptr;
+#endif  /* 32_BIT_COMPILER */
+
+
+/*	 			NEW TYPE DEFINITIONS (shared with Mylex North)
+
+**  Use following type defines to avoid confusion in 16 and 32-bit
+**  environments.  Avoid using 'int' as it denotes 16 bits in 16-bit
+**  environment and 32 in 32-bit environments.
+
+*/
+
+#define s08bits	char
+#define s16bits 	short
+#define s32bits	long
+
+#define u08bits	unsigned s08bits
+#define u16bits	unsigned s16bits
+#define u32bits	unsigned s32bits
+
+#if defined(COMPILER_16_BIT)
+
+typedef u08bits far 	* pu08bits;
+typedef u16bits far 	* pu16bits;
+typedef u32bits far	* pu32bits;
+
+#endif	/* COMPILER_16_BIT */
+
+#if defined(COMPILER_32_BIT)
+
+typedef u08bits 	* pu08bits;
+typedef u16bits 	* pu16bits;
+typedef u32bits 	* pu32bits;
+
+#endif	/* COMPILER_32_BIT */
+
+
+#define BIT(x)          ((UCHAR)(1<<(x)))    /* single-bit mask in bit position x */
+#define BITW(x)          ((USHORT)(1<<(x)))  /* single-bit mask in bit position x */
+
+
+
+#if defined(DOS)
+/*#include <dos.h>*/
+	#undef inportb          /* undefine for Borland Lib */
+	#undef inport           /* they may have define I/O function in LIB */
+	#undef outportb
+	#undef outport
+
+	#define OS_InPortByte(ioport) 		inportb(ioport)
+	#define OS_InPortWord(ioport) 		inport(ioport)
+	#define OS_InPortLong(ioport)			inportq(ioport, val)
+	#define OS_OutPortByte(ioport, val) outportb(ioport, val)
+	#define OS_OutPortWord(ioport, val)	outport(ioport, val)
+	#define OS_OutPortLong(ioport)		outportq(ioport, val)
+#endif	/* DOS */
+
+#if defined(NETWARE) || defined(OTHER_32) ||  defined(OTHER_16)
+	extern u08bits	OS_InPortByte(u32bits ioport);
+	extern u16bits	OS_InPortWord(u32bits ioport);
+	extern u32bits	OS_InPortLong(u32bits ioport);
+
+	extern OS_InPortByteBuffer(u32bits ioport, pu08bits buffer, u32bits count);
+	extern OS_InPortWordBuffer(u32bits ioport, pu16bits buffer, u32bits count);
+	extern OS_OutPortByte(u32bits ioport, u08bits val);
+	extern OS_OutPortWord(u32bits ioport, u16bits val);
+	extern OS_OutPortLong(u32bits ioport, u32bits val);
+	extern OS_OutPortByteBuffer(u32bits ioport, pu08bits buffer, u32bits count);
+	extern OS_OutPortWordBuffer(u32bits ioport, pu16bits buffer, u32bits count);
+#endif	/* NETWARE || OTHER_32 || OTHER_16 */
+
+#if defined (NT) || defined(WIN95_32) || defined(WIN95_16)
+	#if defined(NT)
+
+		extern __declspec(dllimport) u08bits ScsiPortReadPortUchar(pu08bits ioport);
+		extern __declspec(dllimport) u16bits ScsiPortReadPortUshort(pu16bits ioport);
+		extern __declspec(dllimport) u32bits ScsiPortReadPortUlong(pu32bits ioport);
+		extern __declspec(dllimport) void ScsiPortWritePortUchar(pu08bits ioport, u08bits val);
+		extern __declspec(dllimport) void ScsiPortWritePortUshort(pu16bits port, u16bits val);
+		extern __declspec(dllimport) void ScsiPortWritePortUlong(pu32bits port, u32bits val);
+
+	#else
+
+		extern u08bits ScsiPortReadPortUchar(pu08bits ioport);
+		extern u16bits ScsiPortReadPortUshort(pu16bits ioport);
+		extern u32bits ScsiPortReadPortUlong(pu32bits ioport);
+		extern void ScsiPortWritePortUchar(pu08bits ioport, u08bits val);
+		extern void ScsiPortWritePortUshort(pu16bits port, u16bits val);
+		extern void ScsiPortWritePortUlong(pu32bits port, u32bits val);
+	#endif
+
+
+	#define OS_InPortByte(ioport) ScsiPortReadPortUchar((pu08bits) ioport)
+	#define OS_InPortWord(ioport) ScsiPortReadPortUshort((pu16bits) ioport)
+	#define OS_InPortLong(ioport) ScsiPortReadPortUlong((pu32bits) ioport)
+
+	#define OS_OutPortByte(ioport, val) ScsiPortWritePortUchar((pu08bits) ioport, (u08bits) val)
+	#define OS_OutPortWord(ioport, val) ScsiPortWritePortUshort((pu16bits) ioport, (u16bits) val)
+	#define OS_OutPortLong(ioport, val) ScsiPortWritePortUlong((pu32bits) ioport, (u32bits) val)
+	#define OS_OutPortByteBuffer(ioport, buffer, count) \
+		ScsiPortWritePortBufferUchar((pu08bits)&port, (pu08bits) buffer, (u32bits) count)
+	#define OS_OutPortWordBuffer(ioport, buffer, count) \
+		ScsiPortWritePortBufferUshort((pu16bits)&port, (pu16bits) buffer, (u32bits) count)
+
+	#define OS_Lock(x)
+	#define OS_UnLock(x)
+#endif /* NT || WIN95_32 || WIN95_16 */
+
+#if defined (UNIX) && !defined(OS_InPortByte)
+	#define OS_InPortByte(ioport)    inb((u16bits)ioport)
+	#define OS_InPortWord(ioport)    inw((u16bits)ioport)
+	#define OS_InPortLong(ioport)    inl((u16bits)ioport)
+	#define OS_OutPortByte(ioport,val)  outb((u16bits)ioport, (u08bits)val)
+	#define OS_OutPortWord(ioport,val)  outw((u16bits)ioport, (u16bits)val)
+	#define OS_OutPortLong(ioport,val)  outl((u16bits)ioport, (u32bits)val)
+
+	#define OS_Lock(x)
+	#define OS_UnLock(x)
+#endif /* UNIX */
+
+
+#if defined(OS2)
+	extern u08bits	inb(u32bits ioport);
+	extern u16bits	inw(u32bits ioport);
+	extern void	outb(u32bits ioport, u08bits val);
+	extern void	outw(u32bits ioport, u16bits val);
+
+	#define OS_InPortByte(ioport)			inb(ioport)
+	#define OS_InPortWord(ioport)			inw(ioport)
+	#define OS_OutPortByte(ioport, val)	outb(ioport, val)
+	#define OS_OutPortWord(ioport, val)	outw(ioport, val)
+	extern u32bits	OS_InPortLong(u32bits ioport);
+	extern void	OS_OutPortLong(u32bits ioport, u32bits val);
+
+	#define OS_Lock(x)
+	#define OS_UnLock(x)
+#endif /* OS2 */
+
+#if defined(SOLARIS_REAL_MODE)
+
+extern unsigned char    inb(unsigned long ioport);
+extern unsigned short   inw(unsigned long ioport);
+
+#define OS_InPortByte(ioport)    inb(ioport)
+#define OS_InPortWord(ioport)    inw(ioport)
+
+extern void OS_OutPortByte(unsigned long ioport, unsigned char val);
+extern void OS_OutPortWord(unsigned long ioport, unsigned short val);
+extern unsigned long  OS_InPortLong(unsigned long ioport);
+extern void     OS_OutPortLong(unsigned long ioport, unsigned long val);
+
+#define OS_Lock(x)
+#define OS_UnLock(x)
+
+#endif  /* SOLARIS_REAL_MODE */
+
+#endif  /* __GLOBALS_H__ */
+
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   sccbmgr.h  $
+ *
+ *   Description:  Common shared SCCB Interface defines and SCCB 
+ *						 Manager specifics defines.
+ *
+ *   $Date: 1996/10/24 23:09:33 $
+ *
+ *   $Revision: 1.14 $
+ *
+ *----------------------------------------------------------------------*/
+
+#ifndef __SCCB_H__
+#define __SCCB_H__
+
+/*#include <osflags.h>*/
+/*#include <globals.h>*/
+
+#if defined(BUGBUG)
+#define debug_size 32
+#endif
+
+#if defined(DOS)
+
+   typedef struct _SCCB near *PSCCB;
+	#if (FW_TYPE == _SCCB_MGR_)
+   	typedef void (*CALL_BK_FN)(PSCCB);
+	#endif
+
+#elif defined(OS2)
+
+   typedef struct _SCCB far *PSCCB;
+	#if (FW_TYPE == _SCCB_MGR_)
+   	typedef void (far *CALL_BK_FN)(PSCCB);
+	#endif
+
+#else
+
+   typedef struct _SCCB *PSCCB;
+	#if (FW_TYPE == _SCCB_MGR_)
+   	typedef void (*CALL_BK_FN)(PSCCB);
+	#endif
+
+#endif
+
+
+typedef struct SCCBMgr_info {
+   ULONG    si_baseaddr;
+   UCHAR    si_present;
+   UCHAR    si_intvect;
+   UCHAR    si_id;
+   UCHAR    si_lun;
+   USHORT   si_fw_revision;
+   USHORT   si_per_targ_init_sync;
+   USHORT   si_per_targ_fast_nego;
+   USHORT   si_per_targ_ultra_nego;
+   USHORT   si_per_targ_no_disc;
+   USHORT   si_per_targ_wide_nego;
+   USHORT   si_flags;
+   UCHAR    si_card_family;
+   UCHAR    si_bustype;
+   UCHAR    si_card_model[3];
+   UCHAR    si_relative_cardnum;
+   UCHAR    si_reserved[4];
+   ULONG    si_OS_reserved;
+   UCHAR    si_XlatInfo[4];
+   ULONG    si_reserved2[5];
+   ULONG    si_secondary_range;
+} SCCBMGR_INFO;
+
+#if defined(DOS)
+   typedef SCCBMGR_INFO *      PSCCBMGR_INFO;
+#else
+   #if defined (COMPILER_16_BIT)
+   typedef SCCBMGR_INFO far *  PSCCBMGR_INFO;
+   #else
+   typedef SCCBMGR_INFO *      PSCCBMGR_INFO;
+   #endif
+#endif // defined(DOS)
+
+
+
+
+#if (FW_TYPE==_SCCB_MGR_)
+	#define SCSI_PARITY_ENA		  0x0001
+	#define LOW_BYTE_TERM		  0x0010
+	#define HIGH_BYTE_TERM		  0x0020
+	#define BUSTYPE_PCI	  0x3
+#endif
+
+#define SUPPORT_16TAR_32LUN	  0x0002
+#define SOFT_RESET		  0x0004
+#define EXTENDED_TRANSLATION	  0x0008
+#define POST_ALL_UNDERRRUNS	  0x0040
+#define FLAG_SCAM_ENABLED	  0x0080
+#define FLAG_SCAM_LEVEL2	  0x0100
+
+
+
+
+#define HARPOON_FAMILY        0x02
+
+
+#define ISA_BUS_CARD          0x01
+#define EISA_BUS_CARD         0x02
+#define PCI_BUS_CARD          0x03
+#define VESA_BUS_CARD         0x04
+
+/* SCCB struc used for both SCCB and UCB manager compiles! 
+ * The UCB Manager treats the SCCB as it's 'native hardware structure' 
+ */
+
+
+#pragma pack(1)
+typedef struct _SCCB {
+   UCHAR OperationCode;
+   UCHAR ControlByte;
+   UCHAR CdbLength;
+   UCHAR RequestSenseLength;
+   ULONG DataLength;
+   ULONG DataPointer;
+   UCHAR CcbRes[2];
+   UCHAR HostStatus;
+   UCHAR TargetStatus;
+   UCHAR TargID;
+   UCHAR Lun;
+   UCHAR Cdb[12];
+   UCHAR CcbRes1;
+   UCHAR Reserved1;
+   ULONG Reserved2;
+   ULONG SensePointer;
+
+
+   CALL_BK_FN SccbCallback;                  /* VOID (*SccbCallback)(); */
+   ULONG  SccbIOPort;                        /* Identifies board base port */
+   UCHAR  SccbStatus;
+   UCHAR  SCCBRes2;
+   USHORT SccbOSFlags;
+
+
+   ULONG   Sccb_XferCnt;            /* actual transfer count */
+   ULONG   Sccb_ATC;
+   ULONG   SccbVirtDataPtr;         /* virtual addr for OS/2 */
+   ULONG   Sccb_res1;
+   USHORT  Sccb_MGRFlags;
+   USHORT  Sccb_sgseg;
+   UCHAR   Sccb_scsimsg;            /* identify msg for selection */
+   UCHAR   Sccb_tag;
+   UCHAR   Sccb_scsistat;
+   UCHAR   Sccb_idmsg;              /* image of last msg in */
+   PSCCB   Sccb_forwardlink;
+   PSCCB   Sccb_backlink;
+   ULONG   Sccb_savedATC;
+   UCHAR   Save_Cdb[6];
+   UCHAR   Save_CdbLen;
+   UCHAR   Sccb_XferState;
+   ULONG   Sccb_SGoffset;
+#if (FW_TYPE == _UCB_MGR_)
+   PUCB    Sccb_ucb_ptr;
+#endif
+   } SCCB;
+
+#define SCCB_SIZE sizeof(SCCB)
+
+#pragma pack()
+
+
+
+#define SCSI_INITIATOR_COMMAND    0x00
+#define TARGET_MODE_COMMAND       0x01
+#define SCATTER_GATHER_COMMAND    0x02
+#define RESIDUAL_COMMAND          0x03
+#define RESIDUAL_SG_COMMAND       0x04
+#define RESET_COMMAND             0x81
+
+
+#define F_USE_CMD_Q              0x20     /*Inidcates TAGGED command. */
+#define TAG_TYPE_MASK            0xC0     /*Type of tag msg to send. */
+#define TAG_Q_MASK               0xE0
+#define SCCB_DATA_XFER_OUT       0x10     /* Write */
+#define SCCB_DATA_XFER_IN        0x08     /* Read */
+
+
+#define FOURTEEN_BYTES           0x00     /* Request Sense Buffer size */
+#define NO_AUTO_REQUEST_SENSE    0x01     /* No Request Sense Buffer */
+
+
+#define BUS_FREE_ST     0       
+#define SELECT_ST       1
+#define SELECT_BDR_ST   2     /* Select w\ Bus Device Reset */
+#define SELECT_SN_ST    3     /* Select w\ Sync Nego */
+#define SELECT_WN_ST    4     /* Select w\ Wide Data Nego */
+#define SELECT_Q_ST     5     /* Select w\ Tagged Q'ing */
+#define COMMAND_ST      6
+#define DATA_OUT_ST     7
+#define DATA_IN_ST      8
+#define DISCONNECT_ST   9
+#define STATUS_ST       10
+#define ABORT_ST        11
+#define MESSAGE_ST      12
+
+
+#define F_HOST_XFER_DIR                0x01
+#define F_ALL_XFERRED                  0x02
+#define F_SG_XFER                      0x04
+#define F_AUTO_SENSE                   0x08
+#define F_ODD_BALL_CNT                 0x10
+#define F_NO_DATA_YET                  0x80
+
+
+#define F_STATUSLOADED                 0x01
+#define F_MSGLOADED                    0x02
+#define F_DEV_SELECTED                 0x04
+
+
+#define SCCB_COMPLETE               0x00  /* SCCB completed without error */
+#define SCCB_DATA_UNDER_RUN         0x0C
+#define SCCB_SELECTION_TIMEOUT      0x11  /* Set SCSI selection timed out */
+#define SCCB_DATA_OVER_RUN          0x12
+#define SCCB_UNEXPECTED_BUS_FREE    0x13  /* Target dropped SCSI BSY */
+#define SCCB_PHASE_SEQUENCE_FAIL    0x14  /* Target bus phase sequence failure */
+
+#define SCCB_INVALID_OP_CODE        0x16  /* SCCB invalid operation code */
+#define SCCB_INVALID_SCCB           0x1A  /* Invalid SCCB - bad parameter */
+#define SCCB_GROSS_FW_ERR           0x27  /* Major problem! */
+#define SCCB_BM_ERR                 0x30  /* BusMaster error. */
+#define SCCB_PARITY_ERR             0x34  /* SCSI parity error */
+
+
+
+#if (FW_TYPE==_UCB_MGR_)  
+   #define  HBA_AUTO_SENSE_FAIL        0x1B  
+   #define  HBA_TQ_REJECTED            0x1C  
+   #define  HBA_UNSUPPORTED_MSG         0x1D  
+   #define  HBA_HW_ERROR               0x20  
+   #define  HBA_ATN_NOT_RESPONDED      0x21  
+   #define  HBA_SCSI_RESET_BY_ADAPTER  0x22
+   #define  HBA_SCSI_RESET_BY_TARGET   0x23
+   #define  HBA_WRONG_CONNECTION       0x24
+   #define  HBA_BUS_DEVICE_RESET       0x25
+   #define  HBA_ABORT_QUEUE            0x26
+
+#else // these are not defined in BUDI/UCB
+
+   #define SCCB_INVALID_DIRECTION      0x18  /* Invalid target direction */
+   #define SCCB_DUPLICATE_SCCB         0x19  /* Duplicate SCCB */
+   #define SCCB_SCSI_RST               0x35  /* SCSI RESET detected. */
+
+#endif // (FW_TYPE==_UCB_MGR_)  
+
+
+#define SCCB_IN_PROCESS            0x00
+#define SCCB_SUCCESS               0x01
+#define SCCB_ABORT                 0x02
+#define SCCB_NOT_FOUND             0x03
+#define SCCB_ERROR                 0x04
+#define SCCB_INVALID               0x05
+
+#define SCCB_SIZE sizeof(SCCB)
+
+
+
+
+#if (FW_TYPE == _UCB_MGR_)
+	void SccbMgr_start_sccb(CARD_HANDLE pCurrCard, PUCB p_ucb);
+	s32bits SccbMgr_abort_sccb(CARD_HANDLE pCurrCard, PUCB p_ucb);
+	u08bits SccbMgr_my_int(CARD_HANDLE pCurrCard);
+	s32bits SccbMgr_isr(CARD_HANDLE pCurrCard);
+	void SccbMgr_scsi_reset(CARD_HANDLE pCurrCard);
+	void SccbMgr_timer_expired(CARD_HANDLE pCurrCard);
+	void SccbMgr_unload_card(CARD_HANDLE pCurrCard);
+	void SccbMgr_restore_foreign_state(CARD_HANDLE pCurrCard);
+	void SccbMgr_restore_native_state(CARD_HANDLE pCurrCard);
+	void SccbMgr_save_foreign_state(PADAPTER_INFO pAdapterInfo);
+
+#endif
+
+
+#if (FW_TYPE == _SCCB_MGR_)
+
+ #if defined (DOS)
+	int    SccbMgr_sense_adapter(PSCCBMGR_INFO pCardInfo);
+	USHORT SccbMgr_config_adapter(PSCCBMGR_INFO pCardInfo);
+	void  SccbMgr_start_sccb(USHORT pCurrCard, PSCCB p_SCCB);
+	int   SccbMgr_abort_sccb(USHORT pCurrCard, PSCCB p_SCCB);
+	UCHAR SccbMgr_my_int(USHORT pCurrCard);
+	int   SccbMgr_isr(USHORT pCurrCard);
+	void  SccbMgr_scsi_reset(USHORT pCurrCard);
+	void  SccbMgr_timer_expired(USHORT pCurrCard);
+	USHORT SccbMgr_status(USHORT pCurrCard);
+	void SccbMgr_unload_card(USHORT pCurrCard);
+
+ #else    //non-DOS
+
+	int   SccbMgr_sense_adapter(PSCCBMGR_INFO pCardInfo);
+	ULONG SccbMgr_config_adapter(PSCCBMGR_INFO pCardInfo);
+	void  SccbMgr_start_sccb(ULONG pCurrCard, PSCCB p_SCCB);
+	int   SccbMgr_abort_sccb(ULONG pCurrCard, PSCCB p_SCCB);
+	UCHAR SccbMgr_my_int(ULONG pCurrCard);
+	int   SccbMgr_isr(ULONG pCurrCard);
+	void  SccbMgr_scsi_reset(ULONG pCurrCard);
+	void  SccbMgr_enable_int(ULONG pCurrCard);
+	void  SccbMgr_disable_int(ULONG pCurrCard);
+	void  SccbMgr_timer_expired(ULONG pCurrCard);
+	void SccbMgr_unload_card(ULONG pCurrCard);
+
+  #endif
+#endif  // (FW_TYPE == _SCCB_MGR_)
+
+#endif  /* __SCCB_H__ */
+
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   blx30.h  $
+ *
+ *   Description: This module contains SCCB/UCB Manager implementation
+ *                specific stuff.
+ *
+ *   $Date: 1996/11/13 18:34:22 $
+ *
+ *   $Revision: 1.10 $
+ *
+ *----------------------------------------------------------------------*/
+
+
+#ifndef __blx30_H__
+#define __blx30_H__
+
+/*#include <globals.h>*/
+
+#define  ORION_FW_REV      3110
+
+
+
+
+#define HARP_REVD    1
+
+
+#if defined(DOS)
+#define QUEUE_DEPTH     8+1            /*1 for Normal disconnect 0 for Q'ing. */
+#else
+#define QUEUE_DEPTH     254+1            /*1 for Normal disconnect 32 for Q'ing. */
+#endif   // defined(DOS)
+
+#define	MAX_MB_CARDS	4					/* Max. no of cards suppoerted on Mother Board */
+
+#define WIDE_SCSI       1
+
+#if defined(WIDE_SCSI)
+   #if defined(DOS)
+      #define MAX_SCSI_TAR    16
+      #define MAX_LUN         8
+		#define LUN_MASK			0x07
+   #else
+      #define MAX_SCSI_TAR    16
+      #define MAX_LUN         32
+		#define LUN_MASK			0x1f
+	
+   #endif
+#else
+   #define MAX_SCSI_TAR    8
+   #define MAX_LUN         8
+	#define LUN_MASK			0x07
+#endif 
+
+#if defined(HARP_REVA)
+#define SG_BUF_CNT      15             /*Number of prefetched elements. */
+#else
+#define SG_BUF_CNT      16             /*Number of prefetched elements. */
+#endif
+
+#define SG_ELEMENT_SIZE 8              /*Eight byte per element. */
+#define SG_LOCAL_MASK   0x00000000L
+#define SG_ELEMENT_MASK 0xFFFFFFFFL
+
+
+#if (FW_TYPE == _UCB_MGR_)
+	#define OPC_DECODE_NORMAL       0x0f7f
+#endif   // _UCB_MGR_
+
+
+
+#if defined(DOS)
+
+/*#include <dos.h>*/
+	#define RD_HARPOON(ioport)          (OS_InPortByte(ioport))
+	#define RDW_HARPOON(ioport)         (OS_InPortWord(ioport))
+	#define WR_HARPOON(ioport,val)      (OS_OutPortByte(ioport,val))
+	#define WRW_HARPOON(ioport,val)     (OS_OutPortWord(ioport,val))
+
+	#define RD_HARP32(port,offset,data)  asm{db 66h;         \
+                                       push ax;             \
+                                       mov dx,port;         \
+                                       add dx, offset;      \
+                                       db 66h;              \
+                                       in ax,dx;            \
+                                       db 66h;              \
+                                       mov word ptr data,ax;\
+                                       db 66h;              \
+                                       pop ax}
+
+	#define WR_HARP32(port,offset,data) asm{db 66h;          \
+                                       push ax;             \
+                                       mov dx,port;         \
+                                       add dx, offset;      \
+                                       db 66h;              \
+                                       mov ax,word ptr data;\
+                                       db 66h;              \
+                                       out dx,ax;           \
+                                       db 66h;              \
+                                       pop ax}
+#endif	/* DOS */
+
+#if defined(NETWARE) || defined(OTHER_32) ||  defined(OTHER_16)
+	#define RD_HARPOON(ioport)     OS_InPortByte((unsigned long)ioport)
+	#define RDW_HARPOON(ioport)    OS_InPortWord((unsigned long)ioport)
+	#define RD_HARP32(ioport,offset,data) (data = OS_InPortLong(ioport + offset))
+	#define WR_HARPOON(ioport,val) OS_OutPortByte((ULONG)ioport,(UCHAR) val)
+	#define WRW_HARPOON(ioport,val)  OS_OutPortWord((ULONG)ioport,(USHORT)val)
+	#define WR_HARP32(ioport,offset,data)  OS_OutPortLong((ioport + offset), data)
+#endif	/* NETWARE || OTHER_32 || OTHER_16 */
+
+#if defined(NT) || defined(WIN95_32) || defined(WIN95_16)
+	#define RD_HARPOON(ioport)          OS_InPortByte((ULONG)ioport)
+	#define RDW_HARPOON(ioport)         OS_InPortWord((ULONG)ioport)
+	#define RD_HARP32(ioport,offset,data) (data = OS_InPortLong((ULONG)(ioport + offset)))
+	#define WR_HARPOON(ioport,val)      OS_OutPortByte((ULONG)ioport,(UCHAR) val)
+	#define WRW_HARPOON(ioport,val)     OS_OutPortWord((ULONG)ioport,(USHORT)val)
+	#define WR_HARP32(ioport,offset,data)  OS_OutPortLong((ULONG)(ioport + offset), data)
+#endif /* NT || WIN95_32 || WIN95_16 */
+
+#if defined (UNIX)
+	#define RD_HARPOON(ioport)          OS_InPortByte((u32bits)ioport)
+	#define RDW_HARPOON(ioport)         OS_InPortWord((u32bits)ioport)
+	#define RD_HARP32(ioport,offset,data) (data = OS_InPortLong((u32bits)(ioport + offset)))
+	#define WR_HARPOON(ioport,val)      OS_OutPortByte((u32bits)ioport,(u08bits) val)
+	#define WRW_HARPOON(ioport,val)       OS_OutPortWord((u32bits)ioport,(u16bits)val)
+	#define WR_HARP32(ioport,offset,data)  OS_OutPortLong((u32bits)(ioport + offset), data)
+#endif /* UNIX */
+
+#if defined(OS2)
+	#define RD_HARPOON(ioport)          OS_InPortByte((unsigned long)ioport)
+	#define RDW_HARPOON(ioport)         OS_InPortWord((unsigned long)ioport)
+	#define RD_HARP32(ioport,offset,data) (data = OS_InPortLong((ULONG)(ioport + offset)))
+	#define WR_HARPOON(ioport,val)      OS_OutPortByte((ULONG)ioport,(UCHAR) val)
+	#define WRW_HARPOON(ioport,val)       OS_OutPortWord((ULONG)ioport,(USHORT)val)
+	#define WR_HARP32(ioport,offset,data)  OS_OutPortLong(((ULONG)(ioport + offset)), data)
+#endif /* OS2 */
+
+#if defined(SOLARIS_REAL_MODE)
+
+	#define RD_HARPOON(ioport)          OS_InPortByte((unsigned long)ioport)
+	#define RDW_HARPOON(ioport)         OS_InPortWord((unsigned long)ioport)
+	#define RD_HARP32(ioport,offset,data) (data = OS_InPortLong((ULONG)(ioport + offset)))
+	#define WR_HARPOON(ioport,val)      OS_OutPortByte((ULONG)ioport,(UCHAR) val)
+	#define WRW_HARPOON(ioport,val)       OS_OutPortWord((ULONG)ioport,(USHORT)val)
+	#define WR_HARP32(ioport,offset,data)  OS_OutPortLong((ULONG)(ioport + offset), (ULONG)data)
+
+#endif  /* SOLARIS_REAL_MODE */
+
+#endif  /* __BLX30_H__ */
+
+
+/*----------------------------------------------------------------------
+ * 
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   target.h  $
+ *
+ *   Description:  Definitions for Target related structures
+ *
+ *   $Date: 1996/12/11 22:06:20 $
+ *
+ *   $Revision: 1.9 $
+ *
+ *----------------------------------------------------------------------*/
+
+#ifndef __TARGET__
+#define __TARGET__
+
+/*#include <globals.h>*/
+/*#include <blx30.h>*/
+
+
+#define  TAR_SYNC_MASK     (BIT(7)+BIT(6))
+#define  SYNC_UNKNOWN      0x00
+#define  SYNC_TRYING               BIT(6)
+#define  SYNC_SUPPORTED    (BIT(7)+BIT(6))
+
+#define  TAR_WIDE_MASK     (BIT(5)+BIT(4))
+#define  WIDE_DISABLED     0x00
+#define  WIDE_ENABLED              BIT(4)
+#define  WIDE_NEGOCIATED   BIT(5)
+
+#define  TAR_TAG_Q_MASK    (BIT(3)+BIT(2))
+#define  TAG_Q_UNKNOWN     0x00
+#define  TAG_Q_TRYING              BIT(2)
+#define  TAG_Q_REJECT      BIT(3)
+#define  TAG_Q_SUPPORTED   (BIT(3)+BIT(2))
+
+#define  TAR_ALLOW_DISC    BIT(0)
+
+
+#define  EE_SYNC_MASK      (BIT(0)+BIT(1))
+#define  EE_SYNC_ASYNC     0x00
+#define  EE_SYNC_5MB       BIT(0)
+#define  EE_SYNC_10MB      BIT(1)
+#define  EE_SYNC_20MB      (BIT(0)+BIT(1))
+
+#define  EE_ALLOW_DISC     BIT(6)
+#define  EE_WIDE_SCSI      BIT(7)
+
+
+#if defined(DOS)
+   typedef struct SCCBMgr_tar_info near *PSCCBMgr_tar_info;
+
+#elif defined(OS2)
+   typedef struct SCCBMgr_tar_info far *PSCCBMgr_tar_info;
+
+#else
+   typedef struct SCCBMgr_tar_info *PSCCBMgr_tar_info;
+
+#endif
+
+
+typedef struct SCCBMgr_tar_info {
+
+   PSCCB    TarSelQ_Head;
+   PSCCB    TarSelQ_Tail;
+   UCHAR    TarLUN_CA;        /*Contingent Allgiance */
+   UCHAR    TarTagQ_Cnt;
+   UCHAR    TarSelQ_Cnt;
+   UCHAR    TarStatus;
+   UCHAR    TarEEValue;
+   UCHAR 	TarSyncCtrl;
+   UCHAR 	TarReserved[2];			/* for alignment */ 
+   UCHAR 	LunDiscQ_Idx[MAX_LUN];
+   UCHAR    TarLUNBusy[MAX_LUN];
+} SCCBMGR_TAR_INFO;
+
+typedef struct NVRAMInfo {
+	UCHAR		niModel;								/* Model No. of card */
+	UCHAR		niCardNo;							/* Card no. */
+#if defined(DOS)
+	USHORT	niBaseAddr;							/* Port Address of card */
+#else
+	ULONG		niBaseAddr;							/* Port Address of card */
+#endif
+	UCHAR		niSysConf;							/* Adapter Configuration byte - Byte 16 of eeprom map */
+	UCHAR		niScsiConf;							/* SCSI Configuration byte - Byte 17 of eeprom map */
+	UCHAR		niScamConf;							/* SCAM Configuration byte - Byte 20 of eeprom map */
+	UCHAR		niAdapId;							/* Host Adapter ID - Byte 24 of eerpom map */
+	UCHAR		niSyncTbl[MAX_SCSI_TAR / 2];	/* Sync/Wide byte of targets */
+	UCHAR		niScamTbl[MAX_SCSI_TAR][4];	/* Compressed Scam name string of Targets */
+}NVRAMINFO;
+
+#if defined(DOS)
+typedef NVRAMINFO near *PNVRamInfo;
+#elif defined (OS2)
+typedef NVRAMINFO far *PNVRamInfo;
+#else
+typedef NVRAMINFO *PNVRamInfo;
+#endif
+
+#define	MODEL_LT		1
+#define	MODEL_DL		2
+#define	MODEL_LW		3
+#define	MODEL_DW		4
+
+
+typedef struct SCCBcard {
+   PSCCB currentSCCB;
+#if (FW_TYPE==_SCCB_MGR_)
+   PSCCBMGR_INFO cardInfo;
+#else
+   PADAPTER_INFO cardInfo;
+#endif
+
+#if defined(DOS)
+   USHORT ioPort;
+#else
+   ULONG ioPort;
+#endif
+
+   USHORT cmdCounter;
+   UCHAR  discQCount;
+   UCHAR  tagQ_Lst; 
+   UCHAR cardIndex;
+   UCHAR scanIndex;
+   UCHAR globalFlags;
+   UCHAR ourId;
+   PNVRamInfo pNvRamInfo;
+   PSCCB discQ_Tbl[QUEUE_DEPTH]; 
+      
+}SCCBCARD;
+
+#if defined(DOS)
+typedef struct SCCBcard near *PSCCBcard;
+#elif defined (OS2)
+typedef struct SCCBcard far *PSCCBcard;
+#else
+typedef struct SCCBcard *PSCCBcard;
+#endif
+
+
+#define F_TAG_STARTED		0x01
+#define F_CONLUN_IO			0x02
+#define F_DO_RENEGO			0x04
+#define F_NO_FILTER			0x08
+#define F_GREEN_PC			0x10
+#define F_HOST_XFER_ACT		0x20
+#define F_NEW_SCCB_CMD		0x40
+#define F_UPDATE_EEPROM		0x80
+
+
+#define  ID_STRING_LENGTH  32
+#define  TYPE_CODE0        0x63           /*Level2 Mstr (bits 7-6),  */
+
+#define  TYPE_CODE1        00             /*No ID yet */
+
+#define  SLV_TYPE_CODE0    0xA3           /*Priority Bit set (bits 7-6),  */
+
+#define  ASSIGN_ID   0x00
+#define  SET_P_FLAG  0x01
+#define  CFG_CMPLT   0x03
+#define  DOM_MSTR    0x0F
+#define  SYNC_PTRN   0x1F
+
+#define  ID_0_7      0x18
+#define  ID_8_F      0x11
+#define  ID_10_17    0x12
+#define  ID_18_1F    0x0B
+#define  MISC_CODE   0x14
+#define  CLR_P_FLAG  0x18
+#define  LOCATE_ON   0x12
+#define  LOCATE_OFF  0x0B
+
+#define  LVL_1_MST   0x00
+#define  LVL_2_MST   0x40
+#define  DOM_LVL_2   0xC0
+
+
+#define  INIT_SELTD  0x01
+#define  LEVEL2_TAR  0x02
+
+
+enum scam_id_st { ID0,ID1,ID2,ID3,ID4,ID5,ID6,ID7,ID8,ID9,ID10,ID11,ID12,
+                  ID13,ID14,ID15,ID_UNUSED,ID_UNASSIGNED,ID_ASSIGNED,LEGACY,
+                  CLR_PRIORITY,NO_ID_AVAIL };
+
+typedef struct SCCBscam_info {
+
+   UCHAR    id_string[ID_STRING_LENGTH];
+   enum scam_id_st state;
+    
+} SCCBSCAM_INFO, *PSCCBSCAM_INFO;
+
+#endif
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   scsi2.h  $
+ *
+ *   Description:  Register definitions for HARPOON ASIC.
+ *
+ *   $Date: 1996/11/13 18:32:57 $
+ *
+ *   $Revision: 1.4 $
+ *
+ *----------------------------------------------------------------------*/
+
+#ifndef __SCSI_H__
+#define __SCSI_H__
+
+
+
+#define  SCSI_TEST_UNIT_READY    0x00
+#define  SCSI_REZERO_UNIT        0x01
+#define  SCSI_REQUEST_SENSE      0x03
+#define  SCSI_FORMAT_UNIT        0x04
+#define  SCSI_REASSIGN           0x07
+#define  SCSI_READ               0x08
+#define  SCSI_WRITE              0x0A
+#define  SCSI_SEEK               0x0B
+#define  SCSI_INQUIRY            0x12
+#define  SCSI_MODE_SELECT        0x15
+#define  SCSI_RESERVE_UNIT       0x16
+#define  SCSI_RELEASE_UNIT       0x17
+#define  SCSI_MODE_SENSE         0x1A
+#define  SCSI_START_STOP_UNIT    0x1B
+#define  SCSI_SEND_DIAGNOSTIC    0x1D
+#define  SCSI_READ_CAPACITY      0x25
+#define  SCSI_READ_EXTENDED      0x28
+#define  SCSI_WRITE_EXTENDED     0x2A
+#define  SCSI_SEEK_EXTENDED      0x2B
+#define  SCSI_WRITE_AND_VERIFY   0x2E
+#define  SCSI_VERIFY             0x2F
+#define  SCSI_READ_DEFECT_DATA   0x37
+#define  SCSI_WRITE_BUFFER       0x3B
+#define  SCSI_READ_BUFFER        0x3C
+#define  SCSI_RECV_DIAGNOSTIC    0x1C
+#define  SCSI_READ_LONG          0x3E
+#define  SCSI_WRITE_LONG         0x3F
+#define  SCSI_LAST_SCSI_CMND     SCSI_WRITE_LONG
+#define  SCSI_INVALID_CMND       0xFF
+
+
+
+#define  SSGOOD                  0x00
+#define  SSCHECK                 0x02
+#define  SSCOND_MET              0x04
+#define  SSBUSY                  0x08
+#define  SSRESERVATION_CONFLICT  0x18
+#define  SSCMD_TERM              0x22
+#define  SSQ_FULL                0x28
+
+
+#define  SKNO_SEN                0x00
+#define  SKRECOV_ERR             0x01
+#define  SKNOT_RDY               0x02
+#define  SKMED_ERR               0x03
+#define  SKHW_ERR                0x04
+#define  SKILL_REQ               0x05
+#define  SKUNIT_ATTN             0x06
+#define  SKDATA_PROTECT          0x07
+#define  SKBLNK_CHK              0x08
+#define  SKCPY_ABORT             0x0A
+#define  SKABORT_CMD             0x0B
+#define  SKEQUAL                 0x0C
+#define  SKVOL_OVF               0x0D
+#define  SKMIS_CMP               0x0E
+
+
+#define  SMCMD_COMP              0x00
+#define  SMEXT                   0x01
+#define  SMSAVE_DATA_PTR         0x02
+#define  SMREST_DATA_PTR         0x03
+#define  SMDISC                  0x04
+#define  SMINIT_DETEC_ERR        0x05
+#define  SMABORT                 0x06
+#define  SMREJECT                0x07
+#define  SMNO_OP                 0x08
+#define  SMPARITY                0x09
+#define  SMDEV_RESET             0x0C
+#define	SMABORT_TAG					0x0D
+#define	SMINIT_RECOVERY			0x0F
+#define	SMREL_RECOVERY				0x10
+
+#define  SMIDENT                 0x80
+#define  DISC_PRIV               0x40
+
+
+#define  SMSYNC                  0x01
+#define  SM10MBS                 0x19     /* 100ns           */
+#define  SM5MBS                  0x32     /* 200ns           */
+#define  SMOFFSET                0x0F     /* Maxoffset value */
+#define  SMWDTR                  0x03
+#define  SM8BIT                  0x00
+#define  SM16BIT                 0x01
+#define  SM32BIT                 0x02
+#define  SMIGNORWR               0x23     /* Ignore Wide Residue */
+
+
+#define  ARBITRATION_DELAY       0x01     /* 2.4us using a 40Mhz clock */
+#define  BUS_SETTLE_DELAY        0x01     /* 400ns */
+#define  BUS_CLEAR_DELAY         0x01     /* 800ns */
+
+
+
+#define  SPHASE_TO               0x0A  /* 10 second timeout waiting for */
+#define  SCMD_TO                 0x0F  /* Overall command timeout */
+
+
+
+#define  SIX_BYTE_CMD            0x06
+#define  TEN_BYTE_CMD            0x0A
+#define  TWELVE_BYTE_CMD         0x0C
+
+#define  ASYNC                   0x00
+#define  PERI25NS                0x06  /* 25/4ns to next clock for xbow. */
+#define  SYNC10MBS               0x19
+#define  SYNC5MBS                0x32
+#define  MAX_OFFSET              0x0F  /* Maxbyteoffset for Sync Xfers */
+
+#endif
+/*----------------------------------------------------------------------
+ *  
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   eeprom.h  $
+ *
+ *   Description:  Definitions for EEPROM related structures
+ *
+ *   $Date: 1996/11/13 18:28:39 $
+ *
+ *   $Revision: 1.4 $
+ *
+ *----------------------------------------------------------------------*/
+
+#ifndef __EEPROM__
+#define __EEPROM__
+
+/*#include <globals.h>*/
+
+#define  EEPROM_WD_CNT     256
+
+#define  EEPROM_CHECK_SUM  0
+#define  FW_SIGNATURE      2
+#define  MODEL_NUMB_0      4
+#define  MODEL_NUMB_1      5
+#define  MODEL_NUMB_2      6
+#define  MODEL_NUMB_3      7
+#define  MODEL_NUMB_4      8
+#define  MODEL_NUMB_5      9
+#define  IO_BASE_ADDR      10
+#define  IRQ_NUMBER        12
+#define  PCI_INT_PIN       13
+#define  BUS_DELAY         14       /*On time in byte 14 off delay in 15 */
+#define  SYSTEM_CONFIG     16
+#define  SCSI_CONFIG       17
+#define  BIOS_CONFIG       18
+#define  SPIN_UP_DELAY     19
+#define  SCAM_CONFIG       20
+#define  ADAPTER_SCSI_ID   24
+
+
+#define  IGNORE_B_SCAN     32
+#define  SEND_START_ENA    34
+#define  DEVICE_ENABLE     36
+
+#define  SYNC_RATE_TBL     38
+#define  SYNC_RATE_TBL01   38
+#define  SYNC_RATE_TBL23   40
+#define  SYNC_RATE_TBL45   42
+#define  SYNC_RATE_TBL67   44
+#define  SYNC_RATE_TBL89   46
+#define  SYNC_RATE_TBLab   48
+#define  SYNC_RATE_TBLcd   50
+#define  SYNC_RATE_TBLef   52
+
+
+
+#define  EE_SCAMBASE      256 
+
+
+
+   #define  DOM_MASTER     (BIT(0) + BIT(1))
+   #define  SCAM_ENABLED   BIT(2)
+   #define  SCAM_LEVEL2    BIT(3)
+
+
+	#define	RENEGO_ENA		BITW(10)
+	#define	CONNIO_ENA		BITW(11)
+   #define  GREEN_PC_ENA   BITW(12)
+
+
+   #define  AUTO_RATE_00   00
+   #define  AUTO_RATE_05   01
+   #define  AUTO_RATE_10   02
+   #define  AUTO_RATE_20   03
+
+   #define  WIDE_NEGO_BIT     BIT(7)
+   #define  DISC_ENABLE_BIT   BIT(6)
+
+
+#endif
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   harpoon.h  $
+ *
+ *   Description:  Register definitions for HARPOON ASIC.
+ *
+ *   $Date: 1997/07/09 21:44:36 $
+ *
+ *   $Revision: 1.9 $
+ *
+ *----------------------------------------------------------------------*/
+
+
+/*#include <globals.h>*/
+
+#ifndef __HARPOON__
+#define __HARPOON__
+
+
+   #define  hp_vendor_id_0       0x00		/* LSB */
+      #define  ORION_VEND_0   0x4B
+ 
+   #define  hp_vendor_id_1       0x01		/* MSB */
+      #define  ORION_VEND_1   0x10
+
+   #define  hp_device_id_0       0x02		/* LSB */
+      #define  ORION_DEV_0    0x30 
+
+   #define  hp_device_id_1       0x03		/* MSB */
+      #define  ORION_DEV_1    0x81 
+
+	/* Sub Vendor ID and Sub Device ID only available in
+		Harpoon Version 2 and higher */
+
+   #define  hp_sub_vendor_id_0   0x04		/* LSB */
+   #define  hp_sub_vendor_id_1   0x05		/* MSB */
+   #define  hp_sub_device_id_0   0x06		/* LSB */
+   #define  hp_sub_device_id_1   0x07		/* MSB */
+
+
+   #define  hp_dual_addr_lo      0x08
+   #define  hp_dual_addr_lmi     0x09
+   #define  hp_dual_addr_hmi     0x0A
+   #define  hp_dual_addr_hi      0x0B
+
+   #define  hp_semaphore         0x0C
+      #define SCCB_MGR_ACTIVE    BIT(0)
+      #define TICKLE_ME          BIT(1)
+      #define SCCB_MGR_PRESENT   BIT(3)
+      #define BIOS_IN_USE        BIT(4)
+
+   #define  hp_user_defined_D    0x0D
+
+   #define  hp_reserved_E        0x0E
+
+   #define  hp_sys_ctrl          0x0F
+
+      #define  STOP_CLK          BIT(0)      /*Turn off BusMaster Clock */
+      #define  DRVR_RST          BIT(1)      /*Firmware Reset to 80C15 chip */
+      #define  HALT_MACH         BIT(3)      /*Halt State Machine      */
+      #define  HARD_ABORT        BIT(4)      /*Hard Abort              */
+      #define  DIAG_MODE         BIT(5)      /*Diagnostic Mode         */
+
+      #define  BM_ABORT_TMOUT    0x50        /*Halt State machine time out */
+
+   #define  hp_sys_cfg           0x10
+
+      #define  DONT_RST_FIFO     BIT(7)      /*Don't reset FIFO      */
+
+
+   #define  hp_host_ctrl0        0x11
+
+      #define  DUAL_ADDR_MODE    BIT(0)   /*Enable 64-bit addresses */
+      #define  IO_MEM_SPACE      BIT(1)   /*I/O Memory Space    */
+      #define  RESOURCE_LOCK     BIT(2)   /*Enable Resource Lock */
+      #define  IGNOR_ACCESS_ERR  BIT(3)   /*Ignore Access Error */
+      #define  HOST_INT_EDGE     BIT(4)   /*Host interrupt level/edge mode sel */
+      #define  SIX_CLOCKS        BIT(5)   /*6 Clocks between Strobe   */
+      #define  DMA_EVEN_PARITY   BIT(6)   /*Enable DMA Enen Parity */
+
+/*
+      #define  BURST_MODE        BIT(0)
+*/
+
+   #define  hp_reserved_12       0x12
+
+   #define  hp_host_blk_cnt      0x13
+
+      #define  XFER_BLK1         0x00     /*     0 0 0  1 byte per block*/
+      #define  XFER_BLK2         0x01     /*     0 0 1  2 byte per block*/
+      #define  XFER_BLK4         0x02     /*     0 1 0  4 byte per block*/
+      #define  XFER_BLK8         0x03     /*     0 1 1  8 byte per block*/
+      #define  XFER_BLK16        0x04     /*     1 0 0 16 byte per block*/
+      #define  XFER_BLK32        0x05     /*     1 0 1 32 byte per block*/
+      #define  XFER_BLK64        0x06     /*     1 1 0 64 byte per block*/
+   
+      #define  BM_THRESHOLD      0x40     /* PCI mode can only xfer 16 bytes*/
+
+
+   #define  hp_reserved_14       0x14
+   #define  hp_reserved_15       0x15
+   #define  hp_reserved_16       0x16
+
+   #define  hp_int_mask          0x17
+
+      #define  INT_CMD_COMPL     BIT(0)   /* DMA command complete   */
+      #define  INT_EXT_STATUS    BIT(1)   /* Extended Status Set    */
+      #define  INT_SCSI          BIT(2)   /* Scsi block interrupt   */
+      #define  INT_FIFO_RDY      BIT(4)   /* FIFO data ready        */
+
+
+   #define  hp_xfer_cnt_lo       0x18
+   #define  hp_xfer_cnt_mi       0x19
+   #define  hp_xfer_cnt_hi       0x1A
+   #define  hp_xfer_cmd          0x1B
+
+      #define  XFER_HOST_DMA     0x00     /*     0 0 0 Transfer Host -> DMA */
+      #define  XFER_DMA_HOST     0x01     /*     0 0 1 Transfer DMA  -> Host */
+      #define  XFER_HOST_MPU     0x02     /*     0 1 0 Transfer Host -> MPU  */
+      #define  XFER_MPU_HOST     0x03     /*     0 1 1 Transfer MPU  -> Host */
+      #define  XFER_DMA_MPU      0x04     /*     1 0 0 Transfer DMA  -> MPU  */
+      #define  XFER_MPU_DMA      0x05     /*     1 0 1 Transfer MPU  -> DMA  */
+      #define  SET_SEMAPHORE     0x06     /*     1 1 0 Set Semaphore         */
+      #define  XFER_NOP          0x07     /*     1 1 1 Transfer NOP          */
+      #define  XFER_MB_MPU       0x06     /*     1 1 0 Transfer MB -> MPU */
+      #define  XFER_MB_DMA       0x07     /*     1 1 1 Transfer MB -> DMA */
+
+
+      #define  XFER_HOST_AUTO    0x00     /*     0 0 Auto Transfer Size   */
+      #define  XFER_HOST_8BIT    0x08     /*     0 1 8 BIT Transfer Size  */
+      #define  XFER_HOST_16BIT   0x10     /*     1 0 16 BIT Transfer Size */
+      #define  XFER_HOST_32BIT   0x18     /*     1 1 32 BIT Transfer Size */
+
+      #define  XFER_DMA_8BIT     0x20     /*     0 1 8 BIT  Transfer Size */
+      #define  XFER_DMA_16BIT    0x40     /*     1 0 16 BIT Transfer Size */
+
+      #define  DISABLE_INT       BIT(7)   /*Do not interrupt at end of cmd. */
+
+      #define  HOST_WRT_CMD      ((DISABLE_INT + XFER_HOST_DMA + XFER_HOST_AUTO + XFER_DMA_8BIT))
+      #define  HOST_RD_CMD       ((DISABLE_INT + XFER_DMA_HOST + XFER_HOST_AUTO + XFER_DMA_8BIT))
+      #define  WIDE_HOST_WRT_CMD ((DISABLE_INT + XFER_HOST_DMA + XFER_HOST_AUTO + XFER_DMA_16BIT))
+      #define  WIDE_HOST_RD_CMD  ((DISABLE_INT + XFER_DMA_HOST + XFER_HOST_AUTO + XFER_DMA_16BIT))
+
+   #define  hp_host_addr_lo      0x1C
+   #define  hp_host_addr_lmi     0x1D
+   #define  hp_host_addr_hmi     0x1E
+   #define  hp_host_addr_hi      0x1F
+
+   #define  hp_pio_data          0x20
+   #define  hp_reserved_21       0x21
+   #define  hp_ee_ctrl           0x22
+
+      #define  EXT_ARB_ACK       BIT(7)
+      #define  SCSI_TERM_ENA_H   BIT(6)   /* SCSI high byte terminator */
+      #define  SEE_MS            BIT(5)
+      #define  SEE_CS            BIT(3)
+      #define  SEE_CLK           BIT(2)
+      #define  SEE_DO            BIT(1)
+      #define  SEE_DI            BIT(0)
+
+      #define  EE_READ           0x06
+      #define  EE_WRITE          0x05
+      #define  EWEN              0x04
+      #define  EWEN_ADDR         0x03C0
+      #define  EWDS              0x04
+      #define  EWDS_ADDR         0x0000
+
+   #define  hp_brdctl            0x23
+
+      #define  DAT_7             BIT(7)
+      #define  DAT_6             BIT(6)
+      #define  DAT_5             BIT(5)
+      #define  BRD_STB           BIT(4)
+      #define  BRD_CS            BIT(3)
+      #define  BRD_WR            BIT(2)
+
+   #define  hp_reserved_24       0x24
+   #define  hp_reserved_25       0x25
+
+
+
+
+   #define  hp_bm_ctrl           0x26
+
+      #define  SCSI_TERM_ENA_L   BIT(0)   /*Enable/Disable external terminators */
+      #define  FLUSH_XFER_CNTR   BIT(1)   /*Flush transfer counter */
+      #define  BM_XFER_MIN_8     BIT(2)   /*Enable bus master transfer of 9 */
+      #define  BIOS_ENA          BIT(3)   /*Enable BIOS/FLASH Enable */
+      #define  FORCE1_XFER       BIT(5)   /*Always xfer one byte in byte mode */
+      #define  FAST_SINGLE       BIT(6)   /*?? */
+
+      #define  BMCTRL_DEFAULT    (FORCE1_XFER|FAST_SINGLE|SCSI_TERM_ENA_L)
+
+   #define  hp_reserved_27       0x27
+
+   #define  hp_sg_addr           0x28
+   #define  hp_page_ctrl         0x29
+
+      #define  SCATTER_EN        BIT(0)   
+      #define  SGRAM_ARAM        BIT(1)   
+      #define  BIOS_SHADOW       BIT(2)   
+      #define  G_INT_DISABLE     BIT(3)   /* Enable/Disable all Interrupts */
+      #define  NARROW_SCSI_CARD  BIT(4)   /* NARROW/WIDE SCSI config pin */
+
+   #define  hp_reserved_2A       0x2A
+   #define  hp_pci_cmd_cfg       0x2B
+
+      #define  IO_SPACE_ENA      BIT(0)   /*enable I/O space */
+      #define  MEM_SPACE_ENA     BIT(1)   /*enable memory space */
+      #define  BUS_MSTR_ENA      BIT(2)   /*enable bus master operation */
+      #define  MEM_WI_ENA        BIT(4)   /*enable Write and Invalidate */
+      #define  PAR_ERR_RESP      BIT(6)   /*enable parity error responce. */
+
+   #define  hp_reserved_2C       0x2C
+
+   #define  hp_pci_stat_cfg      0x2D
+
+      #define  DATA_PARITY_ERR   BIT(0)   
+      #define  REC_TARGET_ABORT  BIT(4)   /*received Target abort */
+      #define  REC_MASTER_ABORT  BIT(5)   /*received Master abort */
+      #define  SIG_SYSTEM_ERR    BIT(6)   
+      #define  DETECTED_PAR_ERR  BIT(7)   
+
+   #define  hp_reserved_2E       0x2E
+
+   #define  hp_sys_status        0x2F
+
+      #define  SLV_DATA_RDY      BIT(0)   /*Slave data ready */
+      #define  XFER_CNT_ZERO     BIT(1)   /*Transfer counter = 0 */
+      #define  BM_FIFO_EMPTY     BIT(2)   /*FIFO empty */
+      #define  BM_FIFO_FULL      BIT(3)   /*FIFO full */
+      #define  HOST_OP_DONE      BIT(4)   /*host operation done */
+      #define  DMA_OP_DONE       BIT(5)   /*DMA operation done */
+      #define  SLV_OP_DONE       BIT(6)   /*Slave operation done */
+      #define  PWR_ON_FLAG       BIT(7)   /*Power on flag */
+
+   #define  hp_reserved_30       0x30
+
+   #define  hp_host_status0      0x31
+
+      #define  HOST_TERM         BIT(5)   /*Host Terminal Count */
+      #define  HOST_TRSHLD       BIT(6)   /*Host Threshold      */
+      #define  CONNECTED_2_HOST  BIT(7)   /*Connected to Host   */
+
+   #define  hp_reserved_32       0x32
+
+   #define  hp_rev_num           0x33
+
+      #define  REV_A_CONST       0x0E
+      #define  REV_B_CONST       0x0E
+
+   #define  hp_stack_data        0x34
+   #define  hp_stack_addr        0x35
+
+   #define  hp_ext_status        0x36
+
+      #define  BM_FORCE_OFF      BIT(0)   /*Bus Master is forced to get off */
+      #define  PCI_TGT_ABORT     BIT(0)   /*PCI bus master transaction aborted */
+      #define  PCI_DEV_TMOUT     BIT(1)   /*PCI Device Time out */
+      #define  FIFO_TC_NOT_ZERO  BIT(2)   /*FIFO or transfer counter not zero */
+      #define  CHIP_RST_OCCUR    BIT(3)   /*Chip reset occurs */
+      #define  CMD_ABORTED       BIT(4)   /*Command aborted */
+      #define  BM_PARITY_ERR     BIT(5)   /*parity error on data received   */
+      #define  PIO_OVERRUN       BIT(6)   /*Slave data overrun */
+      #define  BM_CMD_BUSY       BIT(7)   /*Bus master transfer command busy */
+      #define  BAD_EXT_STATUS    (BM_FORCE_OFF | PCI_DEV_TMOUT | CMD_ABORTED | \
+                                  BM_PARITY_ERR | PIO_OVERRUN)
+
+   #define  hp_int_status        0x37
+      
+      #define  BM_CMD_CMPL       BIT(0)   /*Bus Master command complete */
+      #define  EXT_STATUS_ON     BIT(1)   /*Extended status is valid */
+      #define  SCSI_INTERRUPT    BIT(2)   /*Global indication of a SCSI int. */
+      #define  BM_FIFO_RDY       BIT(4)   
+      #define  INT_ASSERTED      BIT(5)   /* */
+      #define  SRAM_BUSY         BIT(6)   /*Scatter/Gather RAM busy */
+      #define  CMD_REG_BUSY      BIT(7)                                       
+
+
+   #define  hp_fifo_cnt          0x38
+   #define  hp_curr_host_cnt     0x39
+   #define  hp_reserved_3A       0x3A
+   #define  hp_fifo_in_addr      0x3B
+
+   #define  hp_fifo_out_addr     0x3C
+   #define  hp_reserved_3D       0x3D
+   #define  hp_reserved_3E       0x3E
+   #define  hp_reserved_3F       0x3F
+
+
+
+   extern USHORT default_intena;
+
+   #define  hp_intena		 0x40
+
+      #define  RESET		 BITW(7)
+      #define  PROG_HLT		 BITW(6)  
+      #define  PARITY		 BITW(5)
+      #define  FIFO		 BITW(4)
+      #define  SEL		 BITW(3)
+      #define  SCAM_SEL		 BITW(2) 
+      #define  RSEL		 BITW(1)
+      #define  TIMEOUT		 BITW(0)
+      #define  BUS_FREE		 BITW(15)
+      #define  XFER_CNT_0	 BITW(14)
+      #define  PHASE		 BITW(13)
+      #define  IUNKWN		 BITW(12)
+      #define  ICMD_COMP	 BITW(11)
+      #define  ITICKLE		 BITW(10)
+      #define  IDO_STRT		 BITW(9)
+      #define  ITAR_DISC	 BITW(8)
+      #define  AUTO_INT		 (BITW(12)+BITW(11)+BITW(10)+BITW(9)+BITW(8))
+      #define  CLR_ALL_INT	 0xFFFF
+      #define  CLR_ALL_INT_1	 0xFF00
+
+   #define  hp_intstat		 0x42
+
+   #define  hp_scsisig           0x44
+
+      #define  SCSI_SEL          BIT(7)
+      #define  SCSI_BSY          BIT(6)
+      #define  SCSI_REQ          BIT(5)
+      #define  SCSI_ACK          BIT(4)
+      #define  SCSI_ATN          BIT(3)
+      #define  SCSI_CD           BIT(2)
+      #define  SCSI_MSG          BIT(1)
+      #define  SCSI_IOBIT        BIT(0)
+
+      #define  S_SCSI_PHZ        (BIT(2)+BIT(1)+BIT(0))
+      #define  S_CMD_PH          (BIT(2)              )
+      #define  S_MSGO_PH         (BIT(2)+BIT(1)       )
+      #define  S_STAT_PH         (BIT(2)       +BIT(0))
+      #define  S_MSGI_PH         (BIT(2)+BIT(1)+BIT(0))
+      #define  S_DATAI_PH        (              BIT(0))
+      #define  S_DATAO_PH        0x00
+      #define  S_ILL_PH          (       BIT(1)       )
+
+   #define  hp_scsictrl_0        0x45
+
+      #define  NO_ARB            BIT(7)
+      #define  SEL_TAR           BIT(6)
+      #define  ENA_ATN           BIT(4)
+      #define  ENA_RESEL         BIT(2)
+      #define  SCSI_RST          BIT(1)
+      #define  ENA_SCAM_SEL      BIT(0)
+
+
+
+   #define  hp_portctrl_0        0x46
+
+      #define  SCSI_PORT         BIT(7)
+      #define  SCSI_INBIT        BIT(6)
+      #define  DMA_PORT          BIT(5)
+      #define  DMA_RD            BIT(4)
+      #define  HOST_PORT         BIT(3)
+      #define  HOST_WRT          BIT(2)
+      #define  SCSI_BUS_EN       BIT(1)
+      #define  START_TO          BIT(0)
+
+   #define  hp_scsireset         0x47
+
+      #define  SCSI_TAR          BIT(7)
+      #define  SCSI_INI          BIT(6)
+      #define  SCAM_EN           BIT(5)
+      #define  ACK_HOLD          BIT(4)
+      #define  DMA_RESET         BIT(3)
+      #define  HPSCSI_RESET      BIT(2)
+      #define  PROG_RESET        BIT(1)
+      #define  FIFO_CLR          BIT(0)
+
+   #define  hp_xfercnt_0         0x48
+   #define  hp_xfercnt_1         0x49
+   #define  hp_xfercnt_2         0x4A
+   #define  hp_xfercnt_3         0x4B
+
+   #define  hp_fifodata_0        0x4C
+   #define  hp_fifodata_1        0x4D
+   #define  hp_addstat           0x4E
+
+      #define  SCAM_TIMER        BIT(7)
+      #define  AUTO_RUNNING      BIT(6)
+      #define  FAST_SYNC         BIT(5)
+      #define  SCSI_MODE8        BIT(3)
+      #define  SCSI_PAR_ERR      BIT(0)
+
+   #define  hp_prgmcnt_0         0x4F
+
+      #define  AUTO_PC_MASK      0x3F
+
+   #define  hp_selfid_0          0x50
+   #define  hp_selfid_1          0x51
+   #define  hp_arb_id            0x52
+
+      #define  ARB_ID            (BIT(3) + BIT(2) + BIT(1) + BIT(0))
+
+   #define  hp_select_id         0x53
+
+      #define  RESEL_ID          (BIT(7) + BIT(6) + BIT(5) + BIT(4))
+      #define  SELECT_ID         (BIT(3) + BIT(2) + BIT(1) + BIT(0))
+
+   #define  hp_synctarg_base     0x54
+   #define  hp_synctarg_12       0x54
+   #define  hp_synctarg_13       0x55
+   #define  hp_synctarg_14       0x56
+   #define  hp_synctarg_15       0x57
+
+   #define  hp_synctarg_8        0x58
+   #define  hp_synctarg_9        0x59
+   #define  hp_synctarg_10       0x5A
+   #define  hp_synctarg_11       0x5B
+
+   #define  hp_synctarg_4        0x5C
+   #define  hp_synctarg_5        0x5D
+   #define  hp_synctarg_6        0x5E
+   #define  hp_synctarg_7        0x5F
+
+   #define  hp_synctarg_0        0x60
+   #define  hp_synctarg_1        0x61
+   #define  hp_synctarg_2        0x62
+   #define  hp_synctarg_3        0x63
+
+      #define  RATE_20MB         0x00
+      #define  RATE_10MB         (              BIT(5))
+      #define  RATE_6_6MB        (       BIT(6)       )   
+      #define  RATE_5MB          (       BIT(6)+BIT(5))
+      #define  RATE_4MB          (BIT(7)              )
+      #define  RATE_3_33MB       (BIT(7)       +BIT(5))
+      #define  RATE_2_85MB       (BIT(7)+BIT(6)       )
+      #define  RATE_2_5MB        (BIT(7)+BIT(5)+BIT(6))
+      #define  NEXT_CLK          BIT(5)
+      #define  SLOWEST_SYNC      (BIT(7)+BIT(6)+BIT(5))
+      #define  NARROW_SCSI       BIT(4)
+      #define  SYNC_OFFSET       (BIT(3) + BIT(2) + BIT(1) + BIT(0))
+      #define  DEFAULT_ASYNC     0x00
+      #define  DEFAULT_OFFSET    0x0F
+
+   #define  hp_autostart_0       0x64
+   #define  hp_autostart_1       0x65
+   #define  hp_autostart_2       0x66
+   #define  hp_autostart_3       0x67
+
+
+
+      #define  DISABLE  0x00
+      #define  AUTO_IMMED    BIT(5)
+      #define  SELECT   BIT(6)
+      #define  RESELECT (BIT(6)+BIT(5))
+      #define  BUSFREE  BIT(7)
+      #define  XFER_0   (BIT(7)+BIT(5))
+      #define  END_DATA (BIT(7)+BIT(6))
+      #define  MSG_PHZ  (BIT(7)+BIT(6)+BIT(5))
+
+   #define  hp_gp_reg_0          0x68
+   #define  hp_gp_reg_1          0x69
+   #define  hp_gp_reg_2          0x6A
+   #define  hp_gp_reg_3          0x6B
+
+   #define  hp_seltimeout        0x6C
+
+
+      #define  TO_2ms            0x54      /* 2.0503ms */
+      #define  TO_4ms            0x67      /* 3.9959ms */
+
+      #define  TO_5ms            0x03      /* 4.9152ms */
+      #define  TO_10ms           0x07      /* 11.xxxms */
+      #define  TO_250ms          0x99      /* 250.68ms */
+      #define  TO_290ms          0xB1      /* 289.99ms */
+      #define  TO_350ms          0xD6      /* 350.62ms */
+      #define  TO_417ms          0xFF      /* 417.79ms */
+
+   #define  hp_clkctrl_0         0x6D
+
+      #define  PWR_DWN           BIT(6)
+      #define  ACTdeassert       BIT(4)
+      #define  ATNonErr          BIT(3)
+      #define  CLK_30MHZ         BIT(1)
+      #define  CLK_40MHZ         (BIT(1) + BIT(0))
+      #define  CLK_50MHZ         BIT(2)
+
+      #define  CLKCTRL_DEFAULT   (ACTdeassert | CLK_40MHZ)
+
+   #define  hp_fiforead          0x6E
+   #define  hp_fifowrite         0x6F
+
+   #define  hp_offsetctr         0x70
+   #define  hp_xferstat          0x71
+
+      #define  FIFO_FULL         BIT(7)
+      #define  FIFO_EMPTY        BIT(6)
+      #define  FIFO_MASK         0x3F   /* Mask for the FIFO count value. */
+      #define  FIFO_LEN          0x20
+
+   #define  hp_portctrl_1        0x72
+
+      #define  EVEN_HOST_P       BIT(5)
+      #define  INVT_SCSI         BIT(4)
+      #define  CHK_SCSI_P        BIT(3)
+      #define  HOST_MODE8        BIT(0)
+      #define  HOST_MODE16       0x00
+
+   #define  hp_xfer_pad          0x73
+
+      #define  ID_UNLOCK         BIT(3)
+      #define  XFER_PAD          BIT(2)
+
+   #define  hp_scsidata_0        0x74
+   #define  hp_scsidata_1        0x75
+   #define  hp_timer_0           0x76
+   #define  hp_timer_1           0x77
+
+   #define  hp_reserved_78       0x78
+   #define  hp_reserved_79       0x79
+   #define  hp_reserved_7A       0x7A
+   #define  hp_reserved_7B       0x7B
+
+   #define  hp_reserved_7C       0x7C
+   #define  hp_reserved_7D       0x7D
+   #define  hp_reserved_7E       0x7E
+   #define  hp_reserved_7F       0x7F
+
+   #define  hp_aramBase          0x80
+   #define  BIOS_DATA_OFFSET     0x60
+   #define  BIOS_RELATIVE_CARD   0x64
+
+
+
+
+      #define  AUTO_LEN 0x80
+      #define  AR0      0x00
+      #define  AR1      BITW(8)
+      #define  AR2      BITW(9)
+      #define  AR3      (BITW(9) + BITW(8))
+      #define  SDATA    BITW(10)
+
+      #define  NOP_OP   0x00        /* Nop command */
+
+      #define  CRD_OP   BITW(11)     /* Cmp Reg. w/ Data */
+
+      #define  CRR_OP   BITW(12)     /* Cmp Reg. w. Reg. */
+
+      #define  CBE_OP   (BITW(14)+BITW(12)+BITW(11)) /* Cmp SCSI cmd class & Branch EQ */
+      
+      #define  CBN_OP   (BITW(14)+BITW(13))  /* Cmp SCSI cmd class & Branch NOT EQ */
+      
+      #define  CPE_OP   (BITW(14)+BITW(11))  /* Cmp SCSI phs & Branch EQ */
+
+      #define  CPN_OP   (BITW(14)+BITW(12))  /* Cmp SCSI phs & Branch NOT EQ */
+
+
+      #define  ADATA_OUT   0x00     
+      #define  ADATA_IN    BITW(8)
+      #define  ACOMMAND    BITW(10)
+      #define  ASTATUS     (BITW(10)+BITW(8))
+      #define  AMSG_OUT    (BITW(10)+BITW(9))
+      #define  AMSG_IN     (BITW(10)+BITW(9)+BITW(8))
+      #define  AILLEGAL    (BITW(9)+BITW(8))
+
+
+      #define  BRH_OP   BITW(13)   /* Branch */
+
+      
+      #define  ALWAYS   0x00
+      #define  EQUAL    BITW(8)
+      #define  NOT_EQ   BITW(9)
+
+      #define  TCB_OP   (BITW(13)+BITW(11))    /* Test condition & branch */
+
+      
+      #define  ATN_SET     BITW(8)
+      #define  ATN_RESET   BITW(9)
+      #define  XFER_CNT    (BITW(9)+BITW(8))
+      #define  FIFO_0      BITW(10)
+      #define  FIFO_NOT0   (BITW(10)+BITW(8))
+      #define  T_USE_SYNC0 (BITW(10)+BITW(9))
+
+
+      #define  MPM_OP   BITW(15)        /* Match phase and move data */
+
+      #define  MDR_OP   (BITW(12)+BITW(11)) /* Move data to Reg. */
+
+      #define  MRR_OP   BITW(14)        /* Move DReg. to Reg. */
+
+
+      #define  S_IDREG  (BIT(2)+BIT(1)+BIT(0))
+
+
+      #define  D_AR0    0x00
+      #define  D_AR1    BIT(0)
+      #define  D_AR2    BIT(1)
+      #define  D_AR3    (BIT(1) + BIT(0))
+      #define  D_SDATA  BIT(2)
+      #define  D_BUCKET (BIT(2) + BIT(1) + BIT(0))
+
+
+      #define  ADR_OP   (BITW(13)+BITW(12)) /* Logical AND Reg. w. Data */
+
+      #define  ADS_OP   (BITW(14)+BITW(13)+BITW(12)) 
+
+      #define  ODR_OP   (BITW(13)+BITW(12)+BITW(11))  
+
+      #define  ODS_OP   (BITW(14)+BITW(13)+BITW(12)+BITW(11))  
+
+      #define  STR_OP   (BITW(15)+BITW(14)) /* Store to A_Reg. */
+
+      #define  AINT_ENA1   0x00
+      #define  AINT_STAT1  BITW(8)
+      #define  ASCSI_SIG   BITW(9)
+      #define  ASCSI_CNTL  (BITW(9)+BITW(8))
+      #define  APORT_CNTL  BITW(10)
+      #define  ARST_CNTL   (BITW(10)+BITW(8))
+      #define  AXFERCNT0   (BITW(10)+BITW(9))
+      #define  AXFERCNT1   (BITW(10)+BITW(9)+BITW(8))
+      #define  AXFERCNT2   BITW(11)
+      #define  AFIFO_DATA  (BITW(11)+BITW(8))
+      #define  ASCSISELID  (BITW(11)+BITW(9))
+      #define  ASCSISYNC0  (BITW(11)+BITW(9)+BITW(8))
+
+
+      #define  RAT_OP      (BITW(14)+BITW(13)+BITW(11))
+
+      #define  SSI_OP      (BITW(15)+BITW(11))
+
+
+      #define  SSI_ITAR_DISC	(ITAR_DISC >> 8)
+      #define  SSI_IDO_STRT	(IDO_STRT >> 8)
+      #define  SSI_IDI_STRT	(IDO_STRT >> 8)
+
+      #define  SSI_ICMD_COMP	(ICMD_COMP >> 8)
+      #define  SSI_ITICKLE	(ITICKLE >> 8)
+
+      #define  SSI_IUNKWN	(IUNKWN >> 8)
+      #define  SSI_INO_CC	(IUNKWN >> 8)
+      #define  SSI_IRFAIL	(IUNKWN >> 8)
+
+
+      #define  NP    0x10     /*Next Phase */
+      #define  NTCMD 0x02     /*Non- Tagged Command start */
+      #define  CMDPZ 0x04     /*Command phase */
+      #define  DINT  0x12     /*Data Out/In interrupt */
+      #define  DI    0x13     /*Data Out */
+      #define  MI    0x14     /*Message In */
+      #define  DC    0x19     /*Disconnect Message */
+      #define  ST    0x1D     /*Status Phase */
+      #define  UNKNWN 0x24    /*Unknown bus action */
+      #define  CC    0x25     /*Command Completion failure */
+      #define  TICK  0x26     /*New target reselected us. */
+      #define  RFAIL 0x27     /*Reselection failed */
+      #define  SELCHK 0x28     /*Select & Check SCSI ID latch reg */
+
+
+      #define  ID_MSG_STRT    hp_aramBase + 0x00
+      #define  NON_TAG_ID_MSG hp_aramBase + 0x06
+      #define  CMD_STRT       hp_aramBase + 0x08
+      #define  SYNC_MSGS      hp_aramBase + 0x08
+
+
+
+
+
+      #define  TAG_STRT          0x00
+      #define  SELECTION_START   0x00
+      #define  DISCONNECT_START  0x10/2
+      #define  END_DATA_START    0x14/2
+      #define  NONTAG_STRT       0x02/2
+      #define  CMD_ONLY_STRT     CMDPZ/2
+      #define  TICKLE_STRT     TICK/2
+      #define  SELCHK_STRT     SELCHK/2
+
+
+
+
+#define mEEPROM_CLK_DELAY(port) (RD_HARPOON(port+hp_intstat_1))
+
+#define mWAIT_10MS(port) (RD_HARPOON(port+hp_intstat_1))
+
+
+#define CLR_XFER_CNT(port) (WR_HARPOON(port+hp_xfercnt_0, 0x00))
+
+#define SET_XFER_CNT(port, data) (WR_HARP32(port,hp_xfercnt_0,data))
+
+#define GET_XFER_CNT(port, xfercnt) {RD_HARP32(port,hp_xfercnt_0,xfercnt); xfercnt &= 0xFFFFFF;}
+/* #define GET_XFER_CNT(port, xfercnt) (xfercnt = RD_HARPOON(port+hp_xfercnt_2), \
+                                 xfercnt <<= 16,\
+                                 xfercnt |= RDW_HARPOON((USHORT)(port+hp_xfercnt_0)))
+ */
+#if defined(DOS)
+#define HP_SETUP_ADDR_CNT(port,addr,count) (WRW_HARPOON((USHORT)(port+hp_host_addr_lo), (USHORT)(addr & 0x0000FFFFL)),\
+         addr >>= 16,\
+         WRW_HARPOON((USHORT)(port+hp_host_addr_hmi), (USHORT)(addr & 0x0000FFFFL)),\
+         WR_HARP32(port,hp_xfercnt_0,count),\
+         WRW_HARPOON((USHORT)(port+hp_xfer_cnt_lo), (USHORT)(count & 0x0000FFFFL)),\
+         count >>= 16,\
+         WR_HARPOON(port+hp_xfer_cnt_hi, (count & 0xFF)))
+#else
+#define HP_SETUP_ADDR_CNT(port,addr,count) (WRW_HARPOON((port+hp_host_addr_lo), (USHORT)(addr & 0x0000FFFFL)),\
+         addr >>= 16,\
+         WRW_HARPOON((port+hp_host_addr_hmi), (USHORT)(addr & 0x0000FFFFL)),\
+         WR_HARP32(port,hp_xfercnt_0,count),\
+         WRW_HARPOON((port+hp_xfer_cnt_lo), (USHORT)(count & 0x0000FFFFL)),\
+         count >>= 16,\
+         WR_HARPOON(port+hp_xfer_cnt_hi, (count & 0xFF)))
+#endif
+
+#define ACCEPT_MSG(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\
+                          WR_HARPOON(port+hp_scsisig, S_ILL_PH);}
+
+
+#define ACCEPT_MSG_ATN(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\
+                          WR_HARPOON(port+hp_scsisig, (S_ILL_PH|SCSI_ATN));}
+
+#define ACCEPT_STAT(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\
+                          WR_HARPOON(port+hp_scsisig, S_ILL_PH);}
+
+#define ACCEPT_STAT_ATN(port) {while(RD_HARPOON(port+hp_scsisig) & SCSI_REQ){}\
+                          WR_HARPOON(port+hp_scsisig, (S_ILL_PH|SCSI_ATN));}
+
+#define DISABLE_AUTO(port) (WR_HARPOON(port+hp_scsireset, PROG_RESET),\
+                        WR_HARPOON(port+hp_scsireset, 0x00))
+
+#define ARAM_ACCESS(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \
+                             (RD_HARPOON(p_port+hp_page_ctrl) | SGRAM_ARAM)))
+
+#define SGRAM_ACCESS(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \
+                             (RD_HARPOON(p_port+hp_page_ctrl) & ~SGRAM_ARAM)))
+
+#define MDISABLE_INT(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \
+                             (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE)))
+
+#define MENABLE_INT(p_port) (WR_HARPOON(p_port+hp_page_ctrl, \
+                             (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE)))
+
+
+
+#endif
+
+
+#if (FW_TYPE==_UCB_MGR_)
+void ReadNVRam(PSCCBcard pCurrCard,PUCB p_ucb);
+void WriteNVRam(PSCCBcard pCurrCard,PUCB p_ucb);
+void UpdateCheckSum(u32bits baseport);
+#endif // (FW_TYPE==_UCB_MGR_)
+
+#if defined(DOS)
+UCHAR sfm(USHORT port, PSCCB pcurrSCCB);
+void  scsiStartAuto(USHORT port);
+UCHAR sisyncn(USHORT port, UCHAR p_card, UCHAR syncFlag);
+void  ssel(USHORT port, UCHAR p_card);
+void  sres(USHORT port, UCHAR p_card, PSCCBcard pCurrCard);
+void  sdecm(UCHAR message, USHORT port, UCHAR p_card);
+void  shandem(USHORT port, UCHAR p_card,PSCCB pCurrSCCB);
+void  stsyncn(USHORT port, UCHAR p_card);
+void  sisyncr(USHORT port,UCHAR sync_pulse, UCHAR offset);
+void  sssyncv(USHORT p_port, UCHAR p_id, UCHAR p_sync_value, PSCCBMgr_tar_info currTar_Info);
+void  sresb(USHORT port, UCHAR p_card);
+void  sxfrp(USHORT p_port, UCHAR p_card);
+void  schkdd(USHORT port, UCHAR p_card);
+UCHAR RdStack(USHORT port, UCHAR index);
+void  WrStack(USHORT portBase, UCHAR index, UCHAR data);
+UCHAR ChkIfChipInitialized(USHORT ioPort);
+
+#if defined(V302)
+UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun);
+#endif
+
+void SendMsg(USHORT port, UCHAR message);
+void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id);
+#else
+UCHAR sfm(ULONG port, PSCCB pcurrSCCB);
+void  scsiStartAuto(ULONG port);
+UCHAR sisyncn(ULONG port, UCHAR p_card, UCHAR syncFlag);
+void  ssel(ULONG port, UCHAR p_card);
+void  sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard);
+void  sdecm(UCHAR message, ULONG port, UCHAR p_card);
+void  shandem(ULONG port, UCHAR p_card,PSCCB pCurrSCCB);
+void  stsyncn(ULONG port, UCHAR p_card);
+void  sisyncr(ULONG port,UCHAR sync_pulse, UCHAR offset);
+void  sssyncv(ULONG p_port, UCHAR p_id, UCHAR p_sync_value, PSCCBMgr_tar_info currTar_Info);
+void  sresb(ULONG port, UCHAR p_card);
+void  sxfrp(ULONG p_port, UCHAR p_card);
+void  schkdd(ULONG port, UCHAR p_card);
+UCHAR RdStack(ULONG port, UCHAR index);
+void  WrStack(ULONG portBase, UCHAR index, UCHAR data);
+UCHAR ChkIfChipInitialized(ULONG ioPort);
+
+#if defined(V302)
+UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun);
+#endif
+
+void SendMsg(ULONG port, UCHAR message);
+void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
+#endif
+
+void  ssenss(PSCCBcard pCurrCard);
+void  sinits(PSCCB p_sccb, UCHAR p_card);
+void  RNVRamData(PNVRamInfo pNvRamInfo);
+
+#if defined(WIDE_SCSI)
+   #if defined(DOS)
+   UCHAR siwidn(USHORT port, UCHAR p_card);
+   void  stwidn(USHORT port, UCHAR p_card);
+   void  siwidr(USHORT port, UCHAR width);
+   #else
+   UCHAR siwidn(ULONG port, UCHAR p_card);
+   void  stwidn(ULONG port, UCHAR p_card);
+   void  siwidr(ULONG port, UCHAR width);
+   #endif
+#endif
+
+
+void  queueSelectFail(PSCCBcard pCurrCard, UCHAR p_card);
+void  queueDisconnect(PSCCB p_SCCB, UCHAR p_card);
+void  queueCmdComplete(PSCCBcard pCurrCard, PSCCB p_SCCB, UCHAR p_card);
+void  queueSearchSelect(PSCCBcard pCurrCard, UCHAR p_card);
+void  queueFlushSccb(UCHAR p_card, UCHAR error_code);
+void  queueAddSccb(PSCCB p_SCCB, UCHAR card);
+UCHAR queueFindSccb(PSCCB p_SCCB, UCHAR p_card);
+void  utilUpdateResidual(PSCCB p_SCCB);
+USHORT CalcCrc16(UCHAR buffer[]);
+UCHAR  CalcLrc(UCHAR buffer[]);
+
+
+#if defined(DOS)
+void  Wait1Second(USHORT p_port);
+void  Wait(USHORT p_port, UCHAR p_delay);
+void  utilEEWriteOnOff(USHORT p_port,UCHAR p_mode);
+void  utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr);
+USHORT utilEERead(USHORT p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr);
+void  utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr);
+#else
+void  Wait1Second(ULONG p_port);
+void  Wait(ULONG p_port, UCHAR p_delay);
+void  utilEEWriteOnOff(ULONG p_port,UCHAR p_mode);
+void  utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr);
+USHORT utilEERead(ULONG p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr);
+void  utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr);
+#endif
+
+
+
+#if defined(OS2)
+   void  far phaseDataOut(ULONG port, UCHAR p_card);
+   void  far phaseDataIn(ULONG port, UCHAR p_card);
+   void  far phaseCommand(ULONG port, UCHAR p_card);
+   void  far phaseStatus(ULONG port, UCHAR p_card);
+   void  far phaseMsgOut(ULONG port, UCHAR p_card);
+   void  far phaseMsgIn(ULONG port, UCHAR p_card);
+   void  far phaseIllegal(ULONG port, UCHAR p_card);
+#else
+   #if defined(DOS)
+      void  phaseDataOut(USHORT port, UCHAR p_card);
+      void  phaseDataIn(USHORT port, UCHAR p_card);
+      void  phaseCommand(USHORT port, UCHAR p_card);
+      void  phaseStatus(USHORT port, UCHAR p_card);
+      void  phaseMsgOut(USHORT port, UCHAR p_card);
+      void  phaseMsgIn(USHORT port, UCHAR p_card);
+      void  phaseIllegal(USHORT port, UCHAR p_card);
+   #else
+      void  phaseDataOut(ULONG port, UCHAR p_card);
+      void  phaseDataIn(ULONG port, UCHAR p_card);
+      void  phaseCommand(ULONG port, UCHAR p_card);
+      void  phaseStatus(ULONG port, UCHAR p_card);
+      void  phaseMsgOut(ULONG port, UCHAR p_card);
+      void  phaseMsgIn(ULONG port, UCHAR p_card);
+      void  phaseIllegal(ULONG port, UCHAR p_card);
+   #endif
+#endif
+
+#if defined(DOS)
+void  phaseDecode(USHORT port, UCHAR p_card);
+void  phaseChkFifo(USHORT port, UCHAR p_card);
+void  phaseBusFree(USHORT p_port, UCHAR p_card);
+#else
+void  phaseDecode(ULONG port, UCHAR p_card);
+void  phaseChkFifo(ULONG port, UCHAR p_card);
+void  phaseBusFree(ULONG p_port, UCHAR p_card);
+#endif
+
+
+
+
+#if defined(DOS)
+void  XbowInit(USHORT port, UCHAR scamFlg);
+void  BusMasterInit(USHORT p_port);
+int   DiagXbow(USHORT port);
+int   DiagBusMaster(USHORT port);
+void  DiagEEPROM(USHORT p_port);
+#else
+void  XbowInit(ULONG port, UCHAR scamFlg);
+void  BusMasterInit(ULONG p_port);
+int   DiagXbow(ULONG port);
+int   DiagBusMaster(ULONG port);
+void  DiagEEPROM(ULONG p_port);
+#endif
+
+
+
+
+#if defined(DOS)
+void  busMstrAbort(USHORT port);
+UCHAR busMstrTimeOut(USHORT port);
+void  dataXferProcessor(USHORT port, PSCCBcard pCurrCard);
+void  busMstrSGDataXferStart(USHORT port, PSCCB pCurrSCCB);
+void  busMstrDataXferStart(USHORT port, PSCCB pCurrSCCB);
+void  hostDataXferAbort(USHORT port, UCHAR p_card, PSCCB pCurrSCCB);
+#else
+void  busMstrAbort(ULONG port);
+UCHAR busMstrTimeOut(ULONG port);
+void  dataXferProcessor(ULONG port, PSCCBcard pCurrCard);
+void  busMstrSGDataXferStart(ULONG port, PSCCB pCurrSCCB);
+void  busMstrDataXferStart(ULONG port, PSCCB pCurrSCCB);
+void  hostDataXferAbort(ULONG port, UCHAR p_card, PSCCB pCurrSCCB);
+#endif
+void  hostDataXferRestart(PSCCB currSCCB);
+
+
+#if defined (DOS)
+UCHAR SccbMgr_bad_isr(USHORT p_port, UCHAR p_card, PSCCBcard pCurrCard, USHORT p_int);
+#else
+UCHAR SccbMgr_bad_isr(ULONG p_port, UCHAR p_card, PSCCBcard pCurrCard, USHORT p_int);
+
+#endif
+
+void  SccbMgrTableInitAll(void);
+void  SccbMgrTableInitCard(PSCCBcard pCurrCard, UCHAR p_card);
+void  SccbMgrTableInitTarget(UCHAR p_card, UCHAR target);
+
+
+
+void  scini(UCHAR p_card, UCHAR p_our_id, UCHAR p_power_up);
+
+#if defined(DOS)
+int   scarb(USHORT p_port, UCHAR p_sel_type);
+void  scbusf(USHORT p_port);
+void  scsel(USHORT p_port);
+void  scasid(UCHAR p_card, USHORT p_port);
+UCHAR scxferc(USHORT p_port, UCHAR p_data);
+UCHAR scsendi(USHORT p_port, UCHAR p_id_string[]);
+UCHAR sciso(USHORT p_port, UCHAR p_id_string[]);
+void  scwirod(USHORT p_port, UCHAR p_data_bit);
+void  scwiros(USHORT p_port, UCHAR p_data_bit);
+UCHAR scvalq(UCHAR p_quintet);
+UCHAR scsell(USHORT p_port, UCHAR targ_id);
+void  scwtsel(USHORT p_port);
+void  inisci(UCHAR p_card, USHORT p_port, UCHAR p_our_id);
+void  scsavdi(UCHAR p_card, USHORT p_port);
+#else
+int   scarb(ULONG p_port, UCHAR p_sel_type);
+void  scbusf(ULONG p_port);
+void  scsel(ULONG p_port);
+void  scasid(UCHAR p_card, ULONG p_port);
+UCHAR scxferc(ULONG p_port, UCHAR p_data);
+UCHAR scsendi(ULONG p_port, UCHAR p_id_string[]);
+UCHAR sciso(ULONG p_port, UCHAR p_id_string[]);
+void  scwirod(ULONG p_port, UCHAR p_data_bit);
+void  scwiros(ULONG p_port, UCHAR p_data_bit);
+UCHAR scvalq(UCHAR p_quintet);
+UCHAR scsell(ULONG p_port, UCHAR targ_id);
+void  scwtsel(ULONG p_port);
+void  inisci(UCHAR p_card, ULONG p_port, UCHAR p_our_id);
+void  scsavdi(UCHAR p_card, ULONG p_port);
+#endif
+UCHAR scmachid(UCHAR p_card, UCHAR p_id_string[]);
+
+
+#if defined(DOS)
+void  autoCmdCmplt(USHORT p_port, UCHAR p_card);
+void  autoLoadDefaultMap(USHORT p_port);
+#else
+void  autoCmdCmplt(ULONG p_port, UCHAR p_card);
+void  autoLoadDefaultMap(ULONG p_port);
+#endif
+
+
+
+#if (FW_TYPE==_SCCB_MGR_)
+	void  OS_start_timer(unsigned long ioport, unsigned long timeout);
+	void  OS_stop_timer(unsigned long ioport, unsigned long timeout);
+	void  OS_disable_int(unsigned char intvec);
+	void  OS_enable_int(unsigned char intvec);
+	void  OS_delay(unsigned long count);
+	int   OS_VirtToPhys(u32bits CardHandle, u32bits *physaddr, u32bits *virtaddr);
+	#if !(defined(UNIX) || defined(OS2) || defined(SOLARIS_REAL_MODE)) 
+	void  OS_Lock(PSCCBMGR_INFO pCardInfo);
+	void  OS_UnLock(PSCCBMGR_INFO pCardInfo);
+#endif // if FW_TYPE == ...
+
+#endif
+
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+
+
+#if defined(OS2)
+   extern void (far *s_PhaseTbl[8]) (ULONG, UCHAR);
+#else
+   #if defined(DOS)
+      extern void (*s_PhaseTbl[8]) (USHORT, UCHAR);
+   #else
+      extern void (*s_PhaseTbl[8]) (ULONG, UCHAR);
+   #endif
+#endif
+
+extern SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR];
+extern NVRAMINFO nvRamInfo[MAX_MB_CARDS];
+#if defined(DOS) || defined(OS2)
+extern UCHAR temp_id_string[ID_STRING_LENGTH];
+#endif
+extern UCHAR scamHAString[];
+
+
+extern UCHAR mbCards;
+#if defined(BUGBUG)
+extern UCHAR debug_int[MAX_CARDS][debug_size];
+extern UCHAR debug_index[MAX_CARDS];
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
+#endif
+
+#if (FW_TYPE==_SCCB_MGR_)
+#if defined(DOS)
+   extern UCHAR first_time;
+#endif
+#endif /* (FW_TYPE==_SCCB_MGR_) */
+
+#if (FW_TYPE==_UCB_MGR_)
+#if defined(DOS)
+   extern u08bits first_time;
+#endif
+#endif /* (FW_TYPE==_UCB_MGR_) */
+
+#if defined(BUGBUG)
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
+#endif
+
+extern unsigned int SccbGlobalFlags;
+
+
+#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   sccb.c  $
+ *
+ *   Description:  Functions relating to handling of the SCCB interface
+ *                 between the device driver and the HARPOON.
+ *
+ *   $Date: 1997/06/10 16:47:04 $
+ *
+ *   $Revision: 1.18 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+	/*#include <budioctl.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <eeprom.h>*/
+/*#include <scsi2.h>*/
+/*#include <harpoon.h>*/
+
+
+
+#if (FW_TYPE==_SCCB_MGR_)
+#define mOS_Lock(card)    OS_Lock((PSCCBMGR_INFO)(((PSCCBcard)card)->cardInfo))
+#define mOS_UnLock(card)  OS_UnLock((PSCCBMGR_INFO)(((PSCCBcard)card)->cardInfo))
+#else /* FW_TYPE==_UCB_MGR_ */
+#define mOS_Lock(card)    OS_Lock((u32bits)(((PSCCBcard)card)->ioPort))
+#define mOS_UnLock(card)  OS_UnLock((u32bits)(((PSCCBcard)card)->ioPort))
+#endif
+
+
+/*
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+extern SCCBCARD BL_Card[MAX_CARDS];
+
+extern NVRAMINFO nvRamInfo[MAX_MB_CARDS];
+extern UCHAR mbCards;
+
+#if defined (OS2)
+   extern void (far *s_PhaseTbl[8]) (ULONG, UCHAR);
+#else
+   #if defined(DOS)
+      extern void (*s_PhaseTbl[8]) (USHORT, UCHAR);
+   #else
+      extern void (*s_PhaseTbl[8]) (ULONG, UCHAR);
+   #endif
+#endif
+
+
+#if defined(BUGBUG)
+extern UCHAR debug_int[MAX_CARDS][debug_size];
+extern UCHAR debug_index[MAX_CARDS];
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
+#endif
+*/
+
+#if (FW_TYPE==_SCCB_MGR_)
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_sense_adapter
+ *
+ * Description: Setup and/or Search for cards and return info to caller.
+ *
+ *---------------------------------------------------------------------*/
+
+int SccbMgr_sense_adapter(PSCCBMGR_INFO pCardInfo)
+{
+#if defined(DOS)
+#else
+   static UCHAR first_time = 1;
+#endif
+
+   UCHAR i,j,id,ScamFlg;
+   USHORT temp,temp2,temp3,temp4,temp5,temp6;
+#if defined(DOS)
+   USHORT ioport;
+#else
+   ULONG ioport;
+#endif
+	PNVRamInfo pCurrNvRam;
+
+#if defined(DOS)
+   ioport = (USHORT)pCardInfo->si_baseaddr;
+#else
+   ioport = pCardInfo->si_baseaddr;
+#endif
+
+
+   if (RD_HARPOON(ioport+hp_vendor_id_0) != ORION_VEND_0)
+      return((int)FAILURE);
+
+   if ((RD_HARPOON(ioport+hp_vendor_id_1) != ORION_VEND_1))
+      return((int)FAILURE);
+
+   if ((RD_HARPOON(ioport+hp_device_id_0) != ORION_DEV_0))
+      return((int)FAILURE);
+
+   if ((RD_HARPOON(ioport+hp_device_id_1) != ORION_DEV_1))
+      return((int)FAILURE);
+
+
+   if (RD_HARPOON(ioport+hp_rev_num) != 0x0f){
+
+/* For new Harpoon then check for sub_device ID LSB
+   the bits(0-3) must be all ZERO for compatible with
+   current version of SCCBMgr, else skip this Harpoon
+	device. */
+
+	   if (RD_HARPOON(ioport+hp_sub_device_id_0) & 0x0f)
+	      return((int)FAILURE);
+	}
+
+   if (first_time)
+      {
+      SccbMgrTableInitAll();
+      first_time = 0;
+		mbCards = 0;
+      }
+
+	if(RdStack(ioport, 0) != 0x00) {
+		if(ChkIfChipInitialized(ioport) == FALSE)
+		{
+			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
+			XbowInit(ioport, 0);             /*Must Init the SCSI before attempting */
+			DiagEEPROM(ioport);
+		}
+		else
+		{
+			if(mbCards < MAX_MB_CARDS) {
+				pCurrNvRam = &nvRamInfo[mbCards];
+				mbCards++;
+				pCurrNvRam->niBaseAddr = ioport;
+				RNVRamData(pCurrNvRam);
+			}else
+				return((int) FAILURE);
+		}
+	}else
+		pCurrNvRam = NULL;
+#if defined (NO_BIOS_OPTION)
+	pCurrNvRam = NULL;
+   XbowInit(ioport, 0);                /*Must Init the SCSI before attempting */
+   DiagEEPROM(ioport);
+#endif  /* No BIOS Option */
+
+   WR_HARPOON(ioport+hp_clkctrl_0, CLKCTRL_DEFAULT);
+   WR_HARPOON(ioport+hp_sys_ctrl, 0x00);
+
+	if(pCurrNvRam)
+		pCardInfo->si_id = pCurrNvRam->niAdapId;
+	else
+	   pCardInfo->si_id = (UCHAR)(utilEERead(ioport, (ADAPTER_SCSI_ID/2)) &
+   	   (UCHAR)0x0FF);
+
+   pCardInfo->si_lun = 0x00;
+   pCardInfo->si_fw_revision = ORION_FW_REV;
+   temp2 = 0x0000;
+   temp3 = 0x0000;
+   temp4 = 0x0000;
+   temp5 = 0x0000;
+   temp6 = 0x0000;
+
+   for (id = 0; id < (16/2); id++) {
+
+		if(pCurrNvRam){
+			temp = (USHORT) pCurrNvRam->niSyncTbl[id];
+			temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) +
+					 (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000));
+		}else
+	      temp = utilEERead(ioport, (USHORT)((SYNC_RATE_TBL/2)+id));
+
+      for (i = 0; i < 2; temp >>=8,i++) {
+
+         temp2 >>= 1;
+         temp3 >>= 1;
+         temp4 >>= 1;
+         temp5 >>= 1;
+         temp6 >>= 1;
+	 switch (temp & 0x3)
+	   {
+	   case AUTO_RATE_20:	/* Synchronous, 20 mega-transfers/second */
+	     temp6 |= 0x8000;	/* Fall through */
+	   case AUTO_RATE_10:	/* Synchronous, 10 mega-transfers/second */
+	     temp5 |= 0x8000;	/* Fall through */
+	   case AUTO_RATE_05:	/* Synchronous, 5 mega-transfers/second */
+	     temp2 |= 0x8000;	/* Fall through */
+	   case AUTO_RATE_00:	/* Asynchronous */
+	     break;
+	   }
+
+         if (temp & DISC_ENABLE_BIT)
+	   temp3 |= 0x8000;
+
+         if (temp & WIDE_NEGO_BIT)
+	   temp4 |= 0x8000;
+
+         }
+      }
+
+   pCardInfo->si_per_targ_init_sync = temp2;
+   pCardInfo->si_per_targ_no_disc = temp3;
+   pCardInfo->si_per_targ_wide_nego = temp4;
+   pCardInfo->si_per_targ_fast_nego = temp5;
+   pCardInfo->si_per_targ_ultra_nego = temp6;
+
+	if(pCurrNvRam)
+		i = pCurrNvRam->niSysConf;
+	else
+	   i = (UCHAR)(utilEERead(ioport, (SYSTEM_CONFIG/2)));
+
+	if(pCurrNvRam)
+		ScamFlg = pCurrNvRam->niScamConf;
+	else
+	   ScamFlg = (UCHAR) utilEERead(ioport, SCAM_CONFIG/2);
+
+   pCardInfo->si_flags = 0x0000;
+
+   if (i & 0x01)
+      pCardInfo->si_flags |= SCSI_PARITY_ENA;
+
+   if (!(i & 0x02))
+      pCardInfo->si_flags |= SOFT_RESET;
+
+   if (i & 0x10)
+      pCardInfo->si_flags |= EXTENDED_TRANSLATION;
+
+   if (ScamFlg & SCAM_ENABLED)
+     pCardInfo->si_flags |= FLAG_SCAM_ENABLED;
+
+   if (ScamFlg & SCAM_LEVEL2)
+     pCardInfo->si_flags |= FLAG_SCAM_LEVEL2;
+
+   j = (RD_HARPOON(ioport+hp_bm_ctrl) & ~SCSI_TERM_ENA_L);
+   if (i & 0x04) {
+      j |= SCSI_TERM_ENA_L;
+      }
+   WR_HARPOON(ioport+hp_bm_ctrl, j );
+
+   j = (RD_HARPOON(ioport+hp_ee_ctrl) & ~SCSI_TERM_ENA_H);
+   if (i & 0x08) {
+      j |= SCSI_TERM_ENA_H;
+      }
+   WR_HARPOON(ioport+hp_ee_ctrl, j );
+
+   if (!(RD_HARPOON(ioport+hp_page_ctrl) & NARROW_SCSI_CARD))
+
+      pCardInfo->si_flags |= SUPPORT_16TAR_32LUN;
+
+   pCardInfo->si_card_family = HARPOON_FAMILY;
+   pCardInfo->si_bustype = BUSTYPE_PCI;
+
+	if(pCurrNvRam){
+   	pCardInfo->si_card_model[0] = '9';
+		switch(pCurrNvRam->niModel & 0x0f){
+			case MODEL_LT:
+		   	pCardInfo->si_card_model[1] = '3';
+		   	pCardInfo->si_card_model[2] = '0';
+				break;
+			case MODEL_LW:
+		   	pCardInfo->si_card_model[1] = '5';
+		   	pCardInfo->si_card_model[2] = '0';
+				break;
+			case MODEL_DL:
+		   	pCardInfo->si_card_model[1] = '3';
+		   	pCardInfo->si_card_model[2] = '2';
+				break;
+			case MODEL_DW:
+		   	pCardInfo->si_card_model[1] = '5';
+		   	pCardInfo->si_card_model[2] = '2';
+				break;
+		}
+	}else{
+	   temp = utilEERead(ioport, (MODEL_NUMB_0/2));
+   	pCardInfo->si_card_model[0] = (UCHAR)(temp >> 8);
+	   temp = utilEERead(ioport, (MODEL_NUMB_2/2));
+
+   	pCardInfo->si_card_model[1] = (UCHAR)(temp & 0x00FF);
+	   pCardInfo->si_card_model[2] = (UCHAR)(temp >> 8);
+	}
+
+   if (pCardInfo->si_card_model[1] == '3')
+     {
+       if (RD_HARPOON(ioport+hp_ee_ctrl) & BIT(7))
+	 pCardInfo->si_flags |= LOW_BYTE_TERM;
+     }
+   else if (pCardInfo->si_card_model[2] == '0')
+     {
+       temp = RD_HARPOON(ioport+hp_xfer_pad);
+       WR_HARPOON(ioport+hp_xfer_pad, (temp & ~BIT(4)));
+       if (RD_HARPOON(ioport+hp_ee_ctrl) & BIT(7))
+	 pCardInfo->si_flags |= LOW_BYTE_TERM;
+       WR_HARPOON(ioport+hp_xfer_pad, (temp | BIT(4)));
+       if (RD_HARPOON(ioport+hp_ee_ctrl) & BIT(7))
+	 pCardInfo->si_flags |= HIGH_BYTE_TERM;
+       WR_HARPOON(ioport+hp_xfer_pad, temp);
+     }
+   else
+     {
+       temp = RD_HARPOON(ioport+hp_ee_ctrl);
+       temp2 = RD_HARPOON(ioport+hp_xfer_pad);
+       WR_HARPOON(ioport+hp_ee_ctrl, (temp | SEE_CS));
+       WR_HARPOON(ioport+hp_xfer_pad, (temp2 | BIT(4)));
+       temp3 = 0;
+       for (i = 0; i < 8; i++)
+	 {
+	   temp3 <<= 1;
+	   if (!(RD_HARPOON(ioport+hp_ee_ctrl) & BIT(7)))
+	     temp3 |= 1;
+	   WR_HARPOON(ioport+hp_xfer_pad, (temp2 & ~BIT(4)));
+	   WR_HARPOON(ioport+hp_xfer_pad, (temp2 | BIT(4)));
+	 }
+       WR_HARPOON(ioport+hp_ee_ctrl, temp);
+       WR_HARPOON(ioport+hp_xfer_pad, temp2);
+       if (!(temp3 & BIT(7)))
+	 pCardInfo->si_flags |= LOW_BYTE_TERM;
+       if (!(temp3 & BIT(6)))
+	 pCardInfo->si_flags |= HIGH_BYTE_TERM;
+     }
+
+
+   ARAM_ACCESS(ioport);
+
+   for ( i = 0; i < 4; i++ ) {
+
+      pCardInfo->si_XlatInfo[i] =
+         RD_HARPOON(ioport+hp_aramBase+BIOS_DATA_OFFSET+i);
+      }
+
+	/* return with -1 if no sort, else return with
+	   logical card number sorted by BIOS (zero-based) */
+
+	pCardInfo->si_relative_cardnum =
+	(UCHAR)(RD_HARPOON(ioport+hp_aramBase+BIOS_RELATIVE_CARD)-1);
+
+   SGRAM_ACCESS(ioport);
+
+   s_PhaseTbl[0] = phaseDataOut;
+   s_PhaseTbl[1] = phaseDataIn;
+   s_PhaseTbl[2] = phaseIllegal;
+   s_PhaseTbl[3] = phaseIllegal;
+   s_PhaseTbl[4] = phaseCommand;
+   s_PhaseTbl[5] = phaseStatus;
+   s_PhaseTbl[6] = phaseMsgOut;
+   s_PhaseTbl[7] = phaseMsgIn;
+
+   pCardInfo->si_present = 0x01;
+
+#if defined(BUGBUG)
+
+
+   for (i = 0; i < MAX_CARDS; i++) {
+
+      for (id=0; id<debug_size; id++)
+         debug_int[i][id] =  (UCHAR)0x00;
+      debug_index[i] = 0;
+      }
+
+#endif
+
+   return(0);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_config_adapter
+ *
+ * Description: Setup adapter for normal operation (hard reset).
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT SccbMgr_config_adapter(PSCCBMGR_INFO pCardInfo)
+#else
+ULONG SccbMgr_config_adapter(PSCCBMGR_INFO pCardInfo)
+#endif
+{
+   PSCCBcard CurrCard = NULL;
+	PNVRamInfo pCurrNvRam;
+   UCHAR i,j,thisCard, ScamFlg;
+   USHORT temp,sync_bit_map,id;
+#if defined(DOS)
+   USHORT ioport;
+#else
+   ULONG ioport;
+#endif
+
+#if defined(DOS)
+   ioport = (USHORT)pCardInfo->si_baseaddr;
+#else
+   ioport = pCardInfo->si_baseaddr;
+#endif
+
+   for(thisCard =0; thisCard <= MAX_CARDS; thisCard++) {
+
+      if (thisCard == MAX_CARDS) {
+
+	 return(FAILURE);
+         }
+
+      if (BL_Card[thisCard].ioPort == ioport) {
+
+         CurrCard = &BL_Card[thisCard];
+         SccbMgrTableInitCard(CurrCard,thisCard);
+         break;
+         }
+
+      else if (BL_Card[thisCard].ioPort == 0x00) {
+
+         BL_Card[thisCard].ioPort = ioport;
+         CurrCard = &BL_Card[thisCard];
+
+			if(mbCards)
+				for(i = 0; i < mbCards; i++){
+					if(CurrCard->ioPort == nvRamInfo[i].niBaseAddr)
+						CurrCard->pNvRamInfo = &nvRamInfo[i];
+				}
+         SccbMgrTableInitCard(CurrCard,thisCard);
+         CurrCard->cardIndex = thisCard;
+         CurrCard->cardInfo = pCardInfo;
+
+	 break;
+         }
+      }
+
+	pCurrNvRam = CurrCard->pNvRamInfo;
+
+	if(pCurrNvRam){
+		ScamFlg = pCurrNvRam->niScamConf;
+	}
+	else{
+	   ScamFlg = (UCHAR) utilEERead(ioport, SCAM_CONFIG/2);
+	}
+
+
+   BusMasterInit(ioport);
+   XbowInit(ioport, ScamFlg);
+
+#if defined (NO_BIOS_OPTION)
+
+
+   if (DiagXbow(ioport)) return(FAILURE);
+   if (DiagBusMaster(ioport)) return(FAILURE);
+
+#endif  /* No BIOS Option */
+
+   autoLoadDefaultMap(ioport);
+
+
+   for (i = 0,id = 0x01; i != pCardInfo->si_id; i++,id <<= 1){}
+
+   WR_HARPOON(ioport+hp_selfid_0, id);
+   WR_HARPOON(ioport+hp_selfid_1, 0x00);
+   WR_HARPOON(ioport+hp_arb_id, pCardInfo->si_id);
+   CurrCard->ourId = pCardInfo->si_id;
+
+   i = (UCHAR) pCardInfo->si_flags;
+   if (i & SCSI_PARITY_ENA)
+       WR_HARPOON(ioport+hp_portctrl_1,(HOST_MODE8 | CHK_SCSI_P));
+
+   j = (RD_HARPOON(ioport+hp_bm_ctrl) & ~SCSI_TERM_ENA_L);
+   if (i & LOW_BYTE_TERM)
+      j |= SCSI_TERM_ENA_L;
+   WR_HARPOON(ioport+hp_bm_ctrl, j);
+
+   j = (RD_HARPOON(ioport+hp_ee_ctrl) & ~SCSI_TERM_ENA_H);
+   if (i & HIGH_BYTE_TERM)
+      j |= SCSI_TERM_ENA_H;
+   WR_HARPOON(ioport+hp_ee_ctrl, j );
+
+
+   if (!(pCardInfo->si_flags & SOFT_RESET)) {
+
+      sresb(ioport,thisCard);
+
+         scini(thisCard, pCardInfo->si_id, 0);
+      }
+
+
+
+   if (pCardInfo->si_flags & POST_ALL_UNDERRRUNS)
+      CurrCard->globalFlags |= F_NO_FILTER;
+
+	if(pCurrNvRam){
+		if(pCurrNvRam->niSysConf & 0x10)
+			CurrCard->globalFlags |= F_GREEN_PC;
+	}
+	else{
+	   if (utilEERead(ioport, (SYSTEM_CONFIG/2)) & GREEN_PC_ENA)
+   	   CurrCard->globalFlags |= F_GREEN_PC;
+	}
+
+	/* Set global flag to indicate Re-Negotiation to be done on all
+		ckeck condition */
+	if(pCurrNvRam){
+		if(pCurrNvRam->niScsiConf & 0x04)
+			CurrCard->globalFlags |= F_DO_RENEGO;
+	}
+	else{
+	   if (utilEERead(ioport, (SCSI_CONFIG/2)) & RENEGO_ENA)
+   	   CurrCard->globalFlags |= F_DO_RENEGO;
+	}
+
+	if(pCurrNvRam){
+		if(pCurrNvRam->niScsiConf & 0x08)
+			CurrCard->globalFlags |= F_CONLUN_IO;
+	}
+	else{
+	   if (utilEERead(ioport, (SCSI_CONFIG/2)) & CONNIO_ENA)
+   	   CurrCard->globalFlags |= F_CONLUN_IO;
+	}
+
+
+   temp = pCardInfo->si_per_targ_no_disc;
+
+   for (i = 0,id = 1; i < MAX_SCSI_TAR; i++, id <<= 1) {
+
+      if (temp & id)
+	 sccbMgrTbl[thisCard][i].TarStatus |= TAR_ALLOW_DISC;
+      }
+
+   sync_bit_map = 0x0001;
+
+   for (id = 0; id < (MAX_SCSI_TAR/2); id++) {
+
+		if(pCurrNvRam){
+			temp = (USHORT) pCurrNvRam->niSyncTbl[id];
+			temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) +
+					 (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000));
+		}else
+	      temp = utilEERead(ioport, (USHORT)((SYNC_RATE_TBL/2)+id));
+
+      for (i = 0; i < 2; temp >>=8,i++) {
+
+         if (pCardInfo->si_per_targ_init_sync & sync_bit_map) {
+
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue = (UCHAR)temp;
+            }
+
+         else {
+	    sccbMgrTbl[thisCard][id*2+i].TarStatus |= SYNC_SUPPORTED;
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue =
+               (UCHAR)(temp & ~EE_SYNC_MASK);
+            }
+
+#if defined(WIDE_SCSI)
+/*         if ((pCardInfo->si_per_targ_wide_nego & sync_bit_map) ||
+            (id*2+i >= 8)){
+*/
+         if (pCardInfo->si_per_targ_wide_nego & sync_bit_map){
+
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue |= EE_WIDE_SCSI;
+
+            }
+
+         else { /* NARROW SCSI */
+            sccbMgrTbl[thisCard][id*2+i].TarStatus |= WIDE_NEGOCIATED;
+            }
+
+#else
+         sccbMgrTbl[thisCard][id*2+i].TarStatus |= WIDE_NEGOCIATED;
+#endif
+
+
+	 sync_bit_map <<= 1;
+
+
+
+         }
+      }
+
+   WR_HARPOON((ioport+hp_semaphore),
+      (UCHAR)(RD_HARPOON((ioport+hp_semaphore)) | SCCB_MGR_PRESENT));
+
+#if defined(DOS)
+   return((USHORT)CurrCard);
+#else
+   return((ULONG)CurrCard);
+#endif
+}
+
+#else  			/* end (FW_TYPE==_SCCB_MGR_)  */
+
+
+
+STATIC s16bits FP_PresenceCheck(PMGR_INFO pMgrInfo)
+{
+	PMGR_ENTRYPNTS	pMgr_EntryPnts = &pMgrInfo->mi_Functions;
+
+      pMgr_EntryPnts->UCBMgr_probe_adapter = probe_adapter;
+      pMgr_EntryPnts->UCBMgr_init_adapter = init_adapter;
+      pMgr_EntryPnts->UCBMgr_start_UCB = SccbMgr_start_sccb;
+      pMgr_EntryPnts->UCBMgr_build_UCB = build_UCB;
+      pMgr_EntryPnts->UCBMgr_abort_UCB = SccbMgr_abort_sccb;
+      pMgr_EntryPnts->UCBMgr_my_int = SccbMgr_my_int;
+      pMgr_EntryPnts->UCBMgr_isr = SccbMgr_isr;
+      pMgr_EntryPnts->UCBMgr_scsi_reset = SccbMgr_scsi_reset;
+      pMgr_EntryPnts->UCBMgr_timer_expired = SccbMgr_timer_expired;
+#ifndef NO_IOCTLS
+	  pMgr_EntryPnts->UCBMgr_unload_card = SccbMgr_unload_card;
+	  pMgr_EntryPnts->UCBMgr_save_foreign_state =
+	  									SccbMgr_save_foreign_state;
+	  pMgr_EntryPnts->UCBMgr_restore_foreign_state =
+	  									SccbMgr_restore_foreign_state;
+	  pMgr_EntryPnts->UCBMgr_restore_native_state =
+	  									SccbMgr_restore_native_state;
+#endif /*NO_IOCTLS*/
+
+      pMgrInfo->mi_SGListFormat=0x01;
+      pMgrInfo->mi_DataPtrFormat=0x01;
+      pMgrInfo->mi_MaxSGElements= (u16bits) 0xffffffff;
+      pMgrInfo->mi_MgrPrivateLen=sizeof(SCCB);
+      pMgrInfo->mi_PCIVendorID=BL_VENDOR_ID;
+      pMgrInfo->mi_PCIDeviceID=FP_DEVICE_ID;
+      pMgrInfo->mi_MgrAttributes= ATTR_IO_MAPPED +
+											 ATTR_PHYSICAL_ADDRESS +
+											 ATTR_VIRTUAL_ADDRESS +
+											 ATTR_OVERLAPPED_IO_IOCTLS_OK;
+      pMgrInfo->mi_IoRangeLen = 256;
+      return(0);
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: probe_adapter
+ *
+ * Description: Setup and/or Search for cards and return info to caller.
+ *
+ *---------------------------------------------------------------------*/
+STATIC s32bits probe_adapter(PADAPTER_INFO pAdapterInfo)
+{
+   u16bits temp,temp2,temp3,temp4;
+   u08bits i,j,id;
+
+#if defined(DOS)
+#else
+   static u08bits first_time = 1;
+#endif
+   BASE_PORT ioport;
+	PNVRamInfo pCurrNvRam;
+
+   ioport = (BASE_PORT)pAdapterInfo->ai_baseaddr;
+
+
+
+   if (RD_HARPOON(ioport+hp_vendor_id_0) != ORION_VEND_0)
+      return(1);
+
+   if ((RD_HARPOON(ioport+hp_vendor_id_1) != ORION_VEND_1))
+      return(2);
+
+   if ((RD_HARPOON(ioport+hp_device_id_0) != ORION_DEV_0))
+      return(3);
+
+   if ((RD_HARPOON(ioport+hp_device_id_1) != ORION_DEV_1))
+      return(4);
+
+
+   if (RD_HARPOON(ioport+hp_rev_num) != 0x0f){
+
+
+/* For new Harpoon then check for sub_device ID LSB
+   the bits(0-3) must be all ZERO for compatible with
+   current version of SCCBMgr, else skip this Harpoon
+	device. */
+
+	   if (RD_HARPOON(ioport+hp_sub_device_id_0) & 0x0f)
+	      return(5);
+	}
+
+   if (first_time) {
+
+      SccbMgrTableInitAll();
+      first_time = 0;
+		mbCards = 0;
+      }
+
+	if(RdStack(ioport, 0) != 0x00) {
+		if(ChkIfChipInitialized(ioport) == FALSE)
+		{
+			pCurrNvRam = NULL;
+		   WR_HARPOON(ioport+hp_semaphore, 0x00);
+			XbowInit(ioport, 0);                /*Must Init the SCSI before attempting */
+			DiagEEPROM(ioport);
+		}
+		else
+		{
+			if(mbCards < MAX_MB_CARDS) {
+				pCurrNvRam = &nvRamInfo[mbCards];
+				mbCards++;
+				pCurrNvRam->niBaseAddr = ioport;
+				RNVRamData(pCurrNvRam);
+			}else
+				return((int) FAILURE);
+		}
+	}else
+		pCurrNvRam = NULL;
+
+#if defined (NO_BIOS_OPTION)
+	pCurrNvRam = NULL;
+   XbowInit(ioport, 0);                /*Must Init the SCSI before attempting */
+   DiagEEPROM(ioport);
+#endif  /* No BIOS Option */
+
+   WR_HARPOON(ioport+hp_clkctrl_0, CLKCTRL_DEFAULT);
+   WR_HARPOON(ioport+hp_sys_ctrl, 0x00);
+
+	if(pCurrNvRam)
+		pAdapterInfo->ai_id = pCurrNvRam->niAdapId;
+	else
+   	pAdapterInfo->ai_id = (u08bits)(utilEERead(ioport, (ADAPTER_SCSI_ID/2)) &
+      	(u08bits)0x0FF);
+
+   pAdapterInfo->ai_lun = 0x00;
+   pAdapterInfo->ai_fw_revision[0] = '3';
+   pAdapterInfo->ai_fw_revision[1] = '1';
+   pAdapterInfo->ai_fw_revision[2] = '1';
+   pAdapterInfo->ai_fw_revision[3] = ' ';
+   pAdapterInfo->ai_NumChannels = 1;
+
+   temp2 = 0x0000;
+   temp3 = 0x0000;
+   temp4 = 0x0000;
+
+   for (id = 0; id < (16/2); id++) {
+
+		if(pCurrNvRam){
+			temp = (USHORT) pCurrNvRam->niSyncTbl[id];
+			temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) +
+					 (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000));
+		}else
+	      temp = utilEERead(ioport, (u16bits)((SYNC_RATE_TBL/2)+id));
+
+      for (i = 0; i < 2; temp >>=8,i++) {
+
+         if ((temp & 0x03) != AUTO_RATE_00) {
+
+            temp2 >>= 0x01;
+            temp2 |= 0x8000;
+            }
+
+         else {
+            temp2 >>= 0x01;
+            }
+
+         if (temp & DISC_ENABLE_BIT) {
+
+            temp3 >>= 0x01;
+            temp3 |= 0x8000;
+            }
+
+         else {
+            temp3 >>= 0x01;
+            }
+
+         if (temp & WIDE_NEGO_BIT) {
+
+            temp4 >>= 0x01;
+            temp4 |= 0x8000;
+            }
+
+         else {
+            temp4 >>= 0x01;
+            }
+
+         }
+      }
+
+   pAdapterInfo->ai_per_targ_init_sync = temp2;
+   pAdapterInfo->ai_per_targ_no_disc = temp3;
+   pAdapterInfo->ai_per_targ_wide_nego = temp4;
+	if(pCurrNvRam)
+		i = pCurrNvRam->niSysConf;
+	else
+   	i = (u08bits)(utilEERead(ioport, (SYSTEM_CONFIG/2)));
+
+   /*
+   ** interrupts always level-triggered for FlashPoint
+   */
+   pAdapterInfo->ai_stateinfo |= LEVEL_TRIG;
+
+   if (i & 0x01)
+      pAdapterInfo->ai_stateinfo |= SCSI_PARITY_ENA;
+
+	if (i & 0x02)	/* SCSI Bus reset in AutoSCSI Set ? */
+	{
+		if(pCurrNvRam)
+		{
+			j = pCurrNvRam->niScamConf;
+		}
+		else
+		{
+		j = (u08bits) utilEERead(ioport, SCAM_CONFIG/2);
+		}
+		if(j & SCAM_ENABLED)
+		{
+			if(j & SCAM_LEVEL2)
+			{
+				pAdapterInfo->ai_stateinfo |= SCAM2_ENA;
+			}
+			else
+			{
+				pAdapterInfo->ai_stateinfo |= SCAM1_ENA;
+			}
+		}
+	}
+   j = (RD_HARPOON(ioport+hp_bm_ctrl) & ~SCSI_TERM_ENA_L);
+   if (i & 0x04) {
+      j |= SCSI_TERM_ENA_L;
+      pAdapterInfo->ai_stateinfo |= LOW_BYTE_TERM_ENA;
+      }
+   WR_HARPOON(ioport+hp_bm_ctrl, j );
+
+   j = (RD_HARPOON(ioport+hp_ee_ctrl) & ~SCSI_TERM_ENA_H);
+   if (i & 0x08) {
+      j |= SCSI_TERM_ENA_H;
+      pAdapterInfo->ai_stateinfo |= HIGH_BYTE_TERM_ENA;
+      }
+   WR_HARPOON(ioport+hp_ee_ctrl, j );
+
+	if(RD_HARPOON(ioport + hp_page_ctrl) & BIOS_SHADOW)
+	{
+		pAdapterInfo->ai_FlashRomSize = 64 * 1024;	/* 64k ROM */
+	}
+	else
+	{
+		pAdapterInfo->ai_FlashRomSize = 32 * 1024;	/* 32k ROM */
+	}
+
+   pAdapterInfo->ai_stateinfo |= (FAST20_ENA | TAG_QUEUE_ENA);
+   if (!(RD_HARPOON(ioport+hp_page_ctrl) & NARROW_SCSI_CARD))
+	{
+      pAdapterInfo->ai_attributes |= (WIDE_CAPABLE | FAST20_CAPABLE
+													| SCAM2_CAPABLE
+													| TAG_QUEUE_CAPABLE
+													| SUPRESS_UNDERRRUNS_CAPABLE
+													| SCSI_PARITY_CAPABLE);
+		pAdapterInfo->ai_MaxTarg = 16;
+		pAdapterInfo->ai_MaxLun  = 32;
+	}
+	else
+	{
+      pAdapterInfo->ai_attributes |= (FAST20_CAPABLE | SCAM2_CAPABLE
+													| TAG_QUEUE_CAPABLE
+													| SUPRESS_UNDERRRUNS_CAPABLE
+													| SCSI_PARITY_CAPABLE);
+		pAdapterInfo->ai_MaxTarg = 8;
+		pAdapterInfo->ai_MaxLun  = 8;
+	}
+
+   pAdapterInfo->ai_product_family = HARPOON_FAMILY;
+   pAdapterInfo->ai_HBAbustype = BUSTYPE_PCI;
+
+   for (i=0;i<CARD_MODEL_NAMELEN;i++)
+   {
+      pAdapterInfo->ai_card_model[i]=' '; /* initialize the ai_card_model */
+   }
+
+	if(pCurrNvRam){
+	pAdapterInfo->ai_card_model[0] = '9';
+		switch(pCurrNvRam->niModel & 0x0f){
+			case MODEL_LT:
+			pAdapterInfo->ai_card_model[1] = '3';
+			pAdapterInfo->ai_card_model[2] = '0';
+				break;
+			case MODEL_LW:
+			pAdapterInfo->ai_card_model[1] = '5';
+			pAdapterInfo->ai_card_model[2] = '0';
+				break;
+			case MODEL_DL:
+			pAdapterInfo->ai_card_model[1] = '3';
+			pAdapterInfo->ai_card_model[2] = '2';
+				break;
+			case MODEL_DW:
+			pAdapterInfo->ai_card_model[1] = '5';
+			pAdapterInfo->ai_card_model[2] = '2';
+				break;
+		}
+	}else{
+	   temp = utilEERead(ioport, (MODEL_NUMB_0/2));
+		pAdapterInfo->ai_card_model[0] = (u08bits)(temp >> 8);
+	   temp = utilEERead(ioport, (MODEL_NUMB_2/2));
+
+		pAdapterInfo->ai_card_model[1] = (u08bits)(temp & 0x00FF);
+	   pAdapterInfo->ai_card_model[2] = (u08bits)(temp >> 8);
+	}
+
+
+
+   pAdapterInfo->ai_FiberProductType = 0;
+
+   pAdapterInfo->ai_secondary_range = 0;
+
+   for (i=0;i<WORLD_WIDE_NAMELEN;i++)
+   {
+      pAdapterInfo->ai_worldwidename[i]='\0';
+   }
+
+   for (i=0;i<VENDOR_NAMELEN;i++)
+   {
+      pAdapterInfo->ai_vendorstring[i]='\0';
+   }
+   	pAdapterInfo->ai_vendorstring[0]='B';
+   	pAdapterInfo->ai_vendorstring[1]='U';
+   	pAdapterInfo->ai_vendorstring[2]='S';
+   	pAdapterInfo->ai_vendorstring[3]='L';
+   	pAdapterInfo->ai_vendorstring[4]='O';
+   	pAdapterInfo->ai_vendorstring[5]='G';
+   	pAdapterInfo->ai_vendorstring[6]='I';
+   	pAdapterInfo->ai_vendorstring[7]='C';
+
+	for (i=0;i<FAMILY_NAMELEN;i++)
+	{
+	   pAdapterInfo->ai_AdapterFamilyString[i]='\0';
+	}
+   	pAdapterInfo->ai_AdapterFamilyString[0]='F';
+   	pAdapterInfo->ai_AdapterFamilyString[1]='L';
+   	pAdapterInfo->ai_AdapterFamilyString[2]='A';
+   	pAdapterInfo->ai_AdapterFamilyString[3]='S';
+   	pAdapterInfo->ai_AdapterFamilyString[4]='H';
+   	pAdapterInfo->ai_AdapterFamilyString[5]='P';
+   	pAdapterInfo->ai_AdapterFamilyString[6]='O';
+   	pAdapterInfo->ai_AdapterFamilyString[7]='I';
+   	pAdapterInfo->ai_AdapterFamilyString[8]='N';
+   	pAdapterInfo->ai_AdapterFamilyString[9]='T';
+
+   ARAM_ACCESS(ioport);
+
+   for ( i = 0; i < 4; i++ ) {
+
+      pAdapterInfo->ai_XlatInfo[i] =
+         RD_HARPOON(ioport+hp_aramBase+BIOS_DATA_OFFSET+i);
+      }
+
+	/* return with -1 if no sort, else return with
+	   logical card number sorted by BIOS (zero-based) */
+
+
+	pAdapterInfo->ai_relative_cardnum = 
+      (u08bits)(RD_HARPOON(ioport+hp_aramBase+BIOS_RELATIVE_CARD)-1); 
+
+   SGRAM_ACCESS(ioport);
+
+   s_PhaseTbl[0] = phaseDataOut;
+   s_PhaseTbl[1] = phaseDataIn;
+   s_PhaseTbl[2] = phaseIllegal;
+   s_PhaseTbl[3] = phaseIllegal;
+   s_PhaseTbl[4] = phaseCommand;
+   s_PhaseTbl[5] = phaseStatus;
+   s_PhaseTbl[6] = phaseMsgOut;
+   s_PhaseTbl[7] = phaseMsgIn;
+
+   pAdapterInfo->ai_present = 0x01;
+
+#if defined(BUGBUG)
+
+
+   for (i = 0; i < MAX_CARDS; i++) {
+
+      for (id=0; id<debug_size; id++)
+         debug_int[i][id] =  (u08bits)0x00;
+      debug_index[i] = 0;
+      }
+
+#endif
+
+   return(0);
+}
+
+
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: init_adapter, exported to BUDI via UCBMgr_init_adapter entry
+ *
+ *
+ * Description: Setup adapter for normal operation (hard reset).
+ *
+ *---------------------------------------------------------------------*/
+STATIC CARD_HANDLE init_adapter(PADAPTER_INFO pCardInfo)
+{
+   PSCCBcard CurrCard;
+	PNVRamInfo pCurrNvRam;
+   u08bits i,j,thisCard, ScamFlg;
+   u16bits temp,sync_bit_map,id;
+   BASE_PORT ioport;
+
+   ioport = (BASE_PORT)pCardInfo->ai_baseaddr;
+
+   for(thisCard =0; thisCard <= MAX_CARDS; thisCard++) {
+
+      if (thisCard == MAX_CARDS) {
+
+         return(FAILURE);
+         }
+
+      if (BL_Card[thisCard].ioPort == ioport) {
+
+         CurrCard = &BL_Card[thisCard];
+         SccbMgrTableInitCard(CurrCard,thisCard);
+         break;
+         }
+
+      else if (BL_Card[thisCard].ioPort == 0x00) {
+
+         BL_Card[thisCard].ioPort = ioport;
+         CurrCard = &BL_Card[thisCard];
+
+			if(mbCards)
+				for(i = 0; i < mbCards; i++){
+					if(CurrCard->ioPort == nvRamInfo[i].niBaseAddr)
+						CurrCard->pNvRamInfo = &nvRamInfo[i];
+				}
+         SccbMgrTableInitCard(CurrCard,thisCard);
+         CurrCard->cardIndex = thisCard;
+         CurrCard->cardInfo = pCardInfo;
+
+         break;
+         }
+      }
+
+	pCurrNvRam = CurrCard->pNvRamInfo;
+
+   
+	if(pCurrNvRam){
+		ScamFlg = pCurrNvRam->niScamConf;
+	}
+	else{
+	   ScamFlg = (UCHAR) utilEERead(ioport, SCAM_CONFIG/2);
+	}
+	
+
+   BusMasterInit(ioport);
+   XbowInit(ioport, ScamFlg);
+
+#if defined (NO_BIOS_OPTION)
+
+
+   if (DiagXbow(ioport)) return(FAILURE);
+   if (DiagBusMaster(ioport)) return(FAILURE);
+
+#endif  /* No BIOS Option */
+
+   autoLoadDefaultMap(ioport);
+
+
+   for (i = 0,id = 0x01; i != pCardInfo->ai_id; i++,id <<= 1){}
+
+   WR_HARPOON(ioport+hp_selfid_0, id);
+   WR_HARPOON(ioport+hp_selfid_1, 0x00);
+   WR_HARPOON(ioport+hp_arb_id, pCardInfo->ai_id);
+   CurrCard->ourId = (unsigned char) pCardInfo->ai_id;
+
+   i = (u08bits) pCardInfo->ai_stateinfo;
+   if (i & SCSI_PARITY_ENA)
+       WR_HARPOON(ioport+hp_portctrl_1,(HOST_MODE8 | CHK_SCSI_P));
+
+   j = (RD_HARPOON(ioport+hp_bm_ctrl) & ~SCSI_TERM_ENA_L);
+   if (i & LOW_BYTE_TERM_ENA)
+      j |= SCSI_TERM_ENA_L;
+   WR_HARPOON(ioport+hp_bm_ctrl, j);
+
+   j = (RD_HARPOON(ioport+hp_ee_ctrl) & ~SCSI_TERM_ENA_H);
+   if (i & HIGH_BYTE_TERM_ENA)
+      j |= SCSI_TERM_ENA_H;
+   WR_HARPOON(ioport+hp_ee_ctrl, j );
+
+
+   if (!(pCardInfo->ai_stateinfo & NO_RESET_IN_INIT)) {
+
+      sresb(ioport,thisCard);
+
+         scini(thisCard, (u08bits) pCardInfo->ai_id, 0);
+      }
+
+
+
+   if (pCardInfo->ai_stateinfo & SUPRESS_UNDERRRUNS_ENA)
+      CurrCard->globalFlags |= F_NO_FILTER;
+
+	if(pCurrNvRam){
+		if(pCurrNvRam->niSysConf & 0x10)
+			CurrCard->globalFlags |= F_GREEN_PC;
+	}
+	else{
+	   if (utilEERead(ioport, (SYSTEM_CONFIG/2)) & GREEN_PC_ENA)
+   	   CurrCard->globalFlags |= F_GREEN_PC;
+	}
+
+	/* Set global flag to indicate Re-Negotiation to be done on all
+		ckeck condition */
+	if(pCurrNvRam){
+		if(pCurrNvRam->niScsiConf & 0x04)
+			CurrCard->globalFlags |= F_DO_RENEGO;
+	}
+	else{
+	   if (utilEERead(ioport, (SCSI_CONFIG/2)) & RENEGO_ENA)
+   	   CurrCard->globalFlags |= F_DO_RENEGO;
+	}
+
+	if(pCurrNvRam){
+		if(pCurrNvRam->niScsiConf & 0x08)
+			CurrCard->globalFlags |= F_CONLUN_IO;
+	}
+	else{
+	   if (utilEERead(ioport, (SCSI_CONFIG/2)) & CONNIO_ENA)
+   	   CurrCard->globalFlags |= F_CONLUN_IO;
+	}
+
+   temp = pCardInfo->ai_per_targ_no_disc;
+
+   for (i = 0,id = 1; i < MAX_SCSI_TAR; i++, id <<= 1) {
+
+      if (temp & id)
+         sccbMgrTbl[thisCard][i].TarStatus |= TAR_ALLOW_DISC;
+      }
+
+   sync_bit_map = 0x0001;
+
+   for (id = 0; id < (MAX_SCSI_TAR/2); id++){
+
+		if(pCurrNvRam){
+			temp = (USHORT) pCurrNvRam->niSyncTbl[id];
+			temp = ((temp & 0x03) + ((temp << 4) & 0xc0)) +
+					 (((temp << 4) & 0x0300) + ((temp << 8) & 0xc000));
+		}else
+	      temp = utilEERead(ioport, (u16bits)((SYNC_RATE_TBL/2)+id));
+
+      for (i = 0; i < 2; temp >>=8,i++){
+
+         if (pCardInfo->ai_per_targ_init_sync & sync_bit_map){
+
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue = (u08bits)temp;
+            }
+
+         else {
+            sccbMgrTbl[thisCard][id*2+i].TarStatus |= SYNC_SUPPORTED;
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue =
+               (u08bits)(temp & ~EE_SYNC_MASK);
+            }
+
+#if defined(WIDE_SCSI)
+/*         if ((pCardInfo->ai_per_targ_wide_nego & sync_bit_map) ||
+            (id*2+i >= 8)){
+*/
+         if (pCardInfo->ai_per_targ_wide_nego & sync_bit_map){
+
+            sccbMgrTbl[thisCard][id*2+i].TarEEValue |= EE_WIDE_SCSI;
+
+            }
+
+         else { /* NARROW SCSI */
+            sccbMgrTbl[thisCard][id*2+i].TarStatus |= WIDE_NEGOCIATED;
+            }
+
+#else
+         sccbMgrTbl[thisCard][id*2+i].TarStatus |= WIDE_NEGOCIATED;
+#endif
+
+
+         sync_bit_map <<= 1;
+         }
+      }
+
+
+   pCardInfo->ai_SGListFormat=0x01;
+   pCardInfo->ai_DataPtrFormat=0x01;
+   pCardInfo->ai_AEN_mask &= SCSI_RESET_COMPLETE;
+
+   WR_HARPOON((ioport+hp_semaphore),
+      (u08bits)(RD_HARPOON((ioport+hp_semaphore)) | SCCB_MGR_PRESENT));
+
+   return((u32bits)CurrCard);
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: build_ucb, exported to BUDI via UCBMgr_build_ucb entry
+ *
+ * Description: prepare fw portion of ucb. do not start, resource not guaranteed
+ *             so don't manipulate anything that's derived from states which
+ *             may change
+ *
+ *---------------------------------------------------------------------*/
+void build_UCB(CARD_HANDLE pCurrCard, PUCB p_ucb)
+{
+
+   u08bits thisCard;
+   u08bits i,j;
+
+   PSCCB p_sccb;
+
+
+   thisCard = ((PSCCBcard) pCurrCard)->cardIndex;
+
+
+   p_sccb=(PSCCB)p_ucb->UCB_MgrPrivatePtr;
+
+
+   p_sccb->Sccb_ucb_ptr=p_ucb;
+
+   switch (p_ucb->UCB_opcode & (OPC_DEVICE_RESET+OPC_XFER_SG+OPC_CHK_RESIDUAL))
+   {
+      case OPC_DEVICE_RESET:
+         p_sccb->OperationCode=RESET_COMMAND;
+         break;
+      case OPC_XFER_SG:
+         p_sccb->OperationCode=SCATTER_GATHER_COMMAND;
+         break;
+      case OPC_XFER_SG+OPC_CHK_RESIDUAL:
+         p_sccb->OperationCode=RESIDUAL_SG_COMMAND;
+         break;
+      case OPC_CHK_RESIDUAL:
+
+	      p_sccb->OperationCode=RESIDUAL_COMMAND;
+	      break;
+      default:
+	      p_sccb->OperationCode=SCSI_INITIATOR_COMMAND;
+	      break;
+   }
+
+   if (p_ucb->UCB_opcode & OPC_TQ_ENABLE)
+   {
+      p_sccb->ControlByte = (u08bits)((p_ucb->UCB_opcode & OPC_TQ_MASK)>>2) | F_USE_CMD_Q;
+   }
+   else
+   {
+      p_sccb->ControlByte = 0;
+   }
+
+
+   p_sccb->CdbLength = (u08bits)p_ucb->UCB_cdblen;
+
+   if (p_ucb->UCB_opcode & OPC_NO_AUTO_SENSE)
+   {
+      p_sccb->RequestSenseLength = 0;
+   }
+   else
+   {
+      p_sccb->RequestSenseLength = (unsigned char) p_ucb->UCB_senselen;
+   }
+
+
+   if (p_ucb->UCB_opcode & OPC_XFER_SG)
+   {
+      p_sccb->DataPointer=p_ucb->UCB_virt_dataptr;
+      p_sccb->DataLength = (((u32bits)p_ucb->UCB_NumSgElements)<<3);
+   }
+   else
+   {
+      p_sccb->DataPointer=p_ucb->UCB_phys_dataptr;
+      p_sccb->DataLength=p_ucb->UCB_datalen;
+   };
+
+   p_sccb->HostStatus=0;
+   p_sccb->TargetStatus=0;
+   p_sccb->TargID=(unsigned char)p_ucb->UCB_targid;
+   p_sccb->Lun=(unsigned char) p_ucb->UCB_lun;
+   p_sccb->SccbIOPort=((PSCCBcard)pCurrCard)->ioPort;
+
+   j=p_ucb->UCB_cdblen;
+   for (i=0;i<j;i++)
+   {
+      p_sccb->Cdb[i] = p_ucb->UCB_cdb[i];
+   }
+
+   p_sccb->SensePointer=p_ucb->UCB_phys_senseptr;
+
+   sinits(p_sccb,thisCard);
+
+}
+#ifndef NO_IOCTLS
+
+/*---------------------------------------------------------------------
+ *
+ * Function: GetDevSyncRate
+ *
+ *---------------------------------------------------------------------*/
+STATIC  int GetDevSyncRate(PSCCBcard pCurrCard,PUCB p_ucb)
+{
+	struct _SYNC_RATE_INFO * pSyncStr;
+   PSCCBMgr_tar_info currTar_Info;
+	BASE_PORT ioport;
+	u08bits scsiID, j;
+
+#if (FW_TYPE != _SCCB_MGR_)
+	if( p_ucb->UCB_targid >= pCurrCard->cardInfo->ai_MaxTarg )
+	{
+		return(1);
+	}
+#endif
+
+	ioport  = pCurrCard->ioPort;
+	pSyncStr	= (struct _SYNC_RATE_INFO *) p_ucb->UCB_virt_dataptr;
+	scsiID = (u08bits) p_ucb->UCB_targid;
+   currTar_Info = &sccbMgrTbl[pCurrCard->cardIndex][scsiID];
+	j = currTar_Info->TarSyncCtrl;
+
+	switch (currTar_Info->TarEEValue & EE_SYNC_MASK)
+	{
+		case EE_SYNC_ASYNC:
+			pSyncStr->RequestMegaXferRate = 0x00;
+			break;
+		case EE_SYNC_5MB:
+			pSyncStr->RequestMegaXferRate = (j & NARROW_SCSI) ? 50 : 100;
+			break;
+		case EE_SYNC_10MB:
+			pSyncStr->RequestMegaXferRate = (j & NARROW_SCSI) ? 100 : 200;
+			break;
+		case EE_SYNC_20MB:
+			pSyncStr->RequestMegaXferRate = (j & NARROW_SCSI) ? 200 : 400;
+			break;
+	}
+
+	switch ((j >> 5) & 0x07)
+	{
+		case 0x00:
+			if((j & 0x07) == 0x00)
+			{
+				pSyncStr->ActualMegaXferRate = 0x00;	/* Async Mode */
+			}
+			else
+			{
+				pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 200 : 400;
+			}
+			break;
+		case 0x01:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 100 : 200;
+			break;
+		case 0x02:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 66 : 122;
+			break;
+		case 0x03:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 50 : 100;
+			break;
+		case 0x04:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 40 : 80;
+			break;
+		case 0x05:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 33 : 66;
+			break;
+		case 0x06:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 28 : 56;
+			break;
+		case 0x07:
+			pSyncStr->ActualMegaXferRate = (j & NARROW_SCSI) ? 25 : 50;
+			break;
+	}
+	pSyncStr->NegotiatedOffset = j & 0x0f;
+
+	return(0);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SetDevSyncRate
+ *
+ *---------------------------------------------------------------------*/
+STATIC int SetDevSyncRate(PSCCBcard pCurrCard, PUCB p_ucb)
+{
+	struct _SYNC_RATE_INFO * pSyncStr;
+   PSCCBMgr_tar_info currTar_Info;
+	BASE_PORT ioPort;
+	u08bits scsiID, i, j, syncVal;
+	u16bits syncOffset, actualXferRate;
+	union {
+		u08bits tempb[2];
+		u16bits tempw;
+	}temp2;
+
+#if (FW_TYPE != _SCCB_MGR_)
+	if( p_ucb->UCB_targid >= pCurrCard->cardInfo->ai_MaxTarg )
+	{
+		return(1);
+	}
+#endif
+
+	ioPort  = pCurrCard->ioPort;
+	pSyncStr	= (struct _SYNC_RATE_INFO *) p_ucb->UCB_virt_dataptr;
+	scsiID = (u08bits) p_ucb->UCB_targid;
+   currTar_Info = &sccbMgrTbl[pCurrCard->cardIndex][scsiID];
+	i = RD_HARPOON(ioPort+hp_xfer_pad);		/* Save current value */
+	WR_HARPOON(ioPort+hp_xfer_pad, (i | ID_UNLOCK));
+	WR_HARPOON(ioPort+hp_select_id, ((scsiID << 4) | scsiID));
+	j = RD_HARPOON(ioPort+hp_synctarg_0);
+	WR_HARPOON(ioPort+hp_xfer_pad, i);		/* restore value */
+
+	actualXferRate = pSyncStr->ActualMegaXferRate;
+	if(!(j & NARROW_SCSI))
+	{
+		actualXferRate <<= 1;
+	}
+	if(actualXferRate == 0x00)
+	{
+		syncVal = EE_SYNC_ASYNC;			/* Async Mode */
+	}
+	if(actualXferRate == 0x0200)
+	{
+		syncVal = EE_SYNC_20MB;				/* 20/40 MB Mode */
+	}
+	if(actualXferRate > 0x0050 && actualXferRate < 0x0200 )
+	{
+		syncVal = EE_SYNC_10MB;				/* 10/20 MB Mode */
+	}
+	else
+	{
+		syncVal = EE_SYNC_5MB;				/* 5/10 MB Mode */
+	}
+	if(currTar_Info->TarEEValue && EE_SYNC_MASK == syncVal)
+		return(0);
+	currTar_Info->TarEEValue = (currTar_Info->TarEEValue & !EE_SYNC_MASK)
+											| syncVal;
+	syncOffset = (SYNC_RATE_TBL + scsiID) / 2;
+	temp2.tempw = utilEERead(ioPort, syncOffset);
+	if(scsiID & 0x01)
+	{
+		temp2.tempb[0] = (temp2.tempb[0] & !EE_SYNC_MASK) | syncVal;
+	}
+	else
+	{
+		temp2.tempb[1] = (temp2.tempb[1] & !EE_SYNC_MASK) | syncVal;
+	}
+	utilEEWriteOnOff(ioPort, 1);
+	utilEEWrite(ioPort, temp2.tempw, syncOffset);
+	utilEEWriteOnOff(ioPort, 0);
+	UpdateCheckSum(ioPort);
+
+	return(0);
+}
+/*---------------------------------------------------------------------
+ *
+ * Function: GetDevWideMode
+ *
+ *---------------------------------------------------------------------*/
+int GetDevWideMode(PSCCBcard pCurrCard,PUCB p_ucb)
+{
+	u08bits *pData;
+
+	pData = (u08bits *)p_ucb->UCB_virt_dataptr;
+	if(sccbMgrTbl[pCurrCard->cardIndex][p_ucb->UCB_targid].TarEEValue
+				& EE_WIDE_SCSI)
+	{
+		*pData = 1;
+	}
+	else
+	{
+		*pData = 0;
+	}
+
+	return(0);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SetDevWideMode
+ *
+ *---------------------------------------------------------------------*/
+int SetDevWideMode(PSCCBcard pCurrCard,PUCB p_ucb)
+{
+	u08bits *pData;
+   PSCCBMgr_tar_info currTar_Info;
+	BASE_PORT ioPort;
+	u08bits scsiID, scsiWideMode;
+	u16bits syncOffset;
+	union {
+		u08bits tempb[2];
+		u16bits tempw;
+	}temp2;
+
+#if (FW_TYPE != _SCCB_MGR_)
+	if( !(pCurrCard->cardInfo->ai_attributes & WIDE_CAPABLE) )
+	{
+		return(1);
+	}
+
+	if( p_ucb->UCB_targid >= pCurrCard->cardInfo->ai_MaxTarg )
+	{
+		return(1);
+	}
+#endif
+
+	ioPort  = pCurrCard->ioPort;
+	pData = (u08bits *)p_ucb->UCB_virt_dataptr;
+	scsiID = (u08bits) p_ucb->UCB_targid;
+	currTar_Info = &sccbMgrTbl[pCurrCard->cardIndex][scsiID];
+
+	if(*pData)
+	{
+		if(currTar_Info->TarEEValue & EE_WIDE_SCSI)
+		{
+			return(0);
+		}
+		else
+		{
+			scsiWideMode = EE_WIDE_SCSI;
+		}
+	}
+	else
+	{
+		if(!(currTar_Info->TarEEValue & EE_WIDE_SCSI))
+		{
+			return(0);
+		}
+		else
+		{
+			scsiWideMode = 0;
+		}
+	}
+	currTar_Info->TarEEValue = (currTar_Info->TarEEValue & !EE_WIDE_SCSI)
+											| scsiWideMode;
+
+	syncOffset = (SYNC_RATE_TBL + scsiID) / 2;
+	temp2.tempw = utilEERead(ioPort, syncOffset);
+	if(scsiID & 0x01)
+	{
+		temp2.tempb[0] = (temp2.tempb[0] & !EE_WIDE_SCSI) | scsiWideMode;
+	}
+	else
+	{
+		temp2.tempb[1] = (temp2.tempb[1] & !EE_WIDE_SCSI) | scsiWideMode;
+	}
+	utilEEWriteOnOff(ioPort, 1);
+	utilEEWrite(ioPort, temp2.tempw, syncOffset);
+	utilEEWriteOnOff(ioPort, 0);
+	UpdateCheckSum(ioPort);
+
+	return(0);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: ReadNVRam
+ *
+ *---------------------------------------------------------------------*/
+void ReadNVRam(PSCCBcard pCurrCard,PUCB p_ucb)
+{
+	u08bits *pdata;
+	u16bits i,numwrds,numbytes,offset,temp;
+	u08bits OneMore = FALSE;
+#if defined(DOS)
+	u16bits ioport;
+#else
+	u32bits ioport;
+#endif
+
+	numbytes = (u16bits) p_ucb->UCB_datalen;
+	ioport  = pCurrCard->ioPort;
+   pdata   = (u08bits *) p_ucb->UCB_virt_dataptr;
+	offset  = (u16bits) (p_ucb->UCB_IOCTLParams[0]);
+
+
+
+   if (offset & 0x1)
+	{
+	    *((u16bits*) pdata) = utilEERead(ioport,(u16bits)((offset - 1) / 2)); /* 16 bit read */
+		 *pdata = *(pdata + 1);
+		 ++offset;
+   	 ++pdata;
+		 --numbytes;
+	}
+
+	numwrds = numbytes / 2;
+	if (numbytes & 1)
+	 	OneMore = TRUE;
+
+	for (i = 0; i < numwrds; i++)
+	{
+   	*((u16bits*) pdata) = utilEERead(ioport,(u16bits)(offset / 2));
+		pdata += 2;
+		offset += 2;
+   }
+	if (OneMore)
+	{
+		--pdata;
+		-- offset;
+   	temp = utilEERead(ioport,(u16bits)(offset / 2));
+		*pdata = (u08bits) (temp);
+	}
+
+} /* end proc ReadNVRam */
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: WriteNVRam
+ *
+ *---------------------------------------------------------------------*/
+void WriteNVRam(PSCCBcard pCurrCard,PUCB p_ucb)
+{
+	u08bits *pdata;
+	u16bits i,numwrds,numbytes,offset, eeprom_end;
+	u08bits OneMore = FALSE;
+	union {
+		u08bits  tempb[2];
+		u16bits  tempw;
+	} temp2;
+
+#if defined(DOS)
+	u16bits ioport;
+#else
+	u32bits ioport;
+#endif
+
+	numbytes = (u16bits) p_ucb->UCB_datalen;
+	ioport  = pCurrCard->ioPort;
+   pdata   = (u08bits *) p_ucb->UCB_virt_dataptr;
+	offset  = (u16bits) (p_ucb->UCB_IOCTLParams[0]);
+
+   if (RD_HARPOON(ioport+hp_page_ctrl) & NARROW_SCSI_CARD)
+      eeprom_end = 512;
+   else
+      eeprom_end = 768;
+	
+	if(offset > eeprom_end)
+		return;
+
+	if((offset + numbytes) > eeprom_end)
+		numbytes = eeprom_end - offset;
+
+    utilEEWriteOnOff(ioport,1);   /* Enable write access to the EEPROM */
+
+
+
+   if (offset & 0x1)
+	{
+	    temp2.tempw = utilEERead(ioport,(u16bits)((offset - 1) / 2)); /* 16 bit read */
+		 temp2.tempb[1] = *pdata;
+	    utilEEWrite(ioport, temp2.tempw, (u16bits)((offset -1) / 2));
+		 *pdata = *(pdata + 1);
+		 ++offset;
+   	 ++pdata;
+		 --numbytes;
+	}
+
+	numwrds = numbytes / 2;
+	if (numbytes & 1)
+	 	OneMore = TRUE;
+
+	for (i = 0; i < numwrds; i++)
+	{
+   	utilEEWrite(ioport, *((pu16bits)pdata),(u16bits)(offset / 2));
+		pdata += 2;
+		offset += 2;
+   }
+	if (OneMore)
+	{
+
+   	temp2.tempw = utilEERead(ioport,(u16bits)(offset / 2));
+		temp2.tempb[0] = *pdata;
+   	utilEEWrite(ioport, temp2.tempw, (u16bits)(offset / 2));
+	}
+   utilEEWriteOnOff(ioport,0);   /* Turn off write access */
+   UpdateCheckSum((u32bits)ioport);
+
+} /* end proc WriteNVRam */
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: UpdateCheckSum
+ *
+ * Description: Update Check Sum in EEPROM
+ *
+ *---------------------------------------------------------------------*/
+
+
+void UpdateCheckSum(u32bits baseport)
+{
+	USHORT i,sum_data, eeprom_end;
+
+	sum_data = 0x0000;
+
+
+   if (RD_HARPOON(baseport+hp_page_ctrl) & NARROW_SCSI_CARD)
+      eeprom_end = 512;
+   else
+      eeprom_end = 768;
+
+	for (i = 1; i < eeprom_end/2; i++)
+	{
+		sum_data += utilEERead(baseport, i);
+	}
+
+   utilEEWriteOnOff(baseport,1);   /* Enable write access to the EEPROM */
+
+   utilEEWrite(baseport, sum_data, EEPROM_CHECK_SUM/2);
+   utilEEWriteOnOff(baseport,0);   /* Turn off write access */
+}
+
+void SccbMgr_save_foreign_state(PADAPTER_INFO pAdapterInfo)
+{
+}
+
+
+void SccbMgr_restore_foreign_state(CARD_HANDLE pCurrCard)
+{
+}
+
+void SccbMgr_restore_native_state(CARD_HANDLE pCurrCard)
+{
+}
+
+#endif /* NO_IOCTLS */
+
+#endif /* (FW_TYPE==_UCB_MGR_)   */
+
+#ifndef NO_IOCTLS
+#if (FW_TYPE==_UCB_MGR_)
+void SccbMgr_unload_card(CARD_HANDLE pCurrCard)
+#else
+#if defined(DOS)
+void SccbMgr_unload_card(USHORT pCurrCard)
+#else
+void SccbMgr_unload_card(ULONG pCurrCard)
+#endif
+#endif
+{
+	UCHAR i;
+#if defined(DOS)
+	USHORT portBase;
+	USHORT regOffset;
+#else
+	ULONG portBase;
+	ULONG regOffset;
+#endif
+	ULONG scamData;
+#if defined(OS2)
+	ULONG far *pScamTbl;
+#else
+	ULONG *pScamTbl;
+#endif
+	PNVRamInfo pCurrNvRam;
+
+	pCurrNvRam = ((PSCCBcard)pCurrCard)->pNvRamInfo;
+
+	if(pCurrNvRam){
+		WrStack(pCurrNvRam->niBaseAddr, 0, pCurrNvRam->niModel);
+		WrStack(pCurrNvRam->niBaseAddr, 1, pCurrNvRam->niSysConf);
+		WrStack(pCurrNvRam->niBaseAddr, 2, pCurrNvRam->niScsiConf);
+		WrStack(pCurrNvRam->niBaseAddr, 3, pCurrNvRam->niScamConf);
+		WrStack(pCurrNvRam->niBaseAddr, 4, pCurrNvRam->niAdapId);
+
+		for(i = 0; i < MAX_SCSI_TAR / 2; i++)
+			WrStack(pCurrNvRam->niBaseAddr, (UCHAR)(i+5), pCurrNvRam->niSyncTbl[i]);
+
+		portBase = pCurrNvRam->niBaseAddr;
+
+		for(i = 0; i < MAX_SCSI_TAR; i++){
+			regOffset = hp_aramBase + 64 + i*4;
+#if defined(OS2)
+			pScamTbl = (ULONG far *) &pCurrNvRam->niScamTbl[i];
+#else
+			pScamTbl = (ULONG *) &pCurrNvRam->niScamTbl[i];
+#endif
+			scamData = *pScamTbl;
+			WR_HARP32(portBase, regOffset, scamData);
+		}
+
+	}else{
+		WrStack(((PSCCBcard)pCurrCard)->ioPort, 0, 0);
+	}
+}
+#endif /* NO_IOCTLS */
+
+
+void RNVRamData(PNVRamInfo pNvRamInfo)
+{
+	UCHAR i;
+#if defined(DOS)
+	USHORT portBase;
+	USHORT regOffset;
+#else
+	ULONG portBase;
+	ULONG regOffset;
+#endif
+	ULONG scamData;
+#if defined (OS2)
+	ULONG far *pScamTbl;
+#else
+	ULONG *pScamTbl;
+#endif
+
+	pNvRamInfo->niModel    = RdStack(pNvRamInfo->niBaseAddr, 0);
+	pNvRamInfo->niSysConf  = RdStack(pNvRamInfo->niBaseAddr, 1);
+	pNvRamInfo->niScsiConf = RdStack(pNvRamInfo->niBaseAddr, 2);
+	pNvRamInfo->niScamConf = RdStack(pNvRamInfo->niBaseAddr, 3);
+	pNvRamInfo->niAdapId   = RdStack(pNvRamInfo->niBaseAddr, 4);
+
+	for(i = 0; i < MAX_SCSI_TAR / 2; i++)
+		pNvRamInfo->niSyncTbl[i] = RdStack(pNvRamInfo->niBaseAddr, (UCHAR)(i+5));
+
+	portBase = pNvRamInfo->niBaseAddr;
+
+	for(i = 0; i < MAX_SCSI_TAR; i++){
+		regOffset = hp_aramBase + 64 + i*4;
+		RD_HARP32(portBase, regOffset, scamData);
+#if defined(OS2)
+		pScamTbl = (ULONG far *) &pNvRamInfo->niScamTbl[i];
+#else
+		pScamTbl = (ULONG *) &pNvRamInfo->niScamTbl[i];
+#endif
+		*pScamTbl = scamData;
+	}
+
+}
+
+#if defined(DOS)
+UCHAR RdStack(USHORT portBase, UCHAR index)
+#else
+UCHAR RdStack(ULONG portBase, UCHAR index)
+#endif
+{
+	WR_HARPOON(portBase + hp_stack_addr, index);
+	return(RD_HARPOON(portBase + hp_stack_data));
+}
+
+#if defined(DOS)
+void WrStack(USHORT portBase, UCHAR index, UCHAR data)
+#else
+void WrStack(ULONG portBase, UCHAR index, UCHAR data)
+#endif
+{
+	WR_HARPOON(portBase + hp_stack_addr, index);
+	WR_HARPOON(portBase + hp_stack_data, data);
+}
+
+
+#if (FW_TYPE==_UCB_MGR_)
+u08bits ChkIfChipInitialized(BASE_PORT ioPort)
+#else
+#if defined(DOS)
+UCHAR ChkIfChipInitialized(USHORT ioPort)
+#else
+UCHAR ChkIfChipInitialized(ULONG ioPort)
+#endif
+#endif
+{
+	if((RD_HARPOON(ioPort + hp_arb_id) & 0x0f) != RdStack(ioPort, 4))
+		return(FALSE);
+	if((RD_HARPOON(ioPort + hp_clkctrl_0) & CLKCTRL_DEFAULT)
+								!= CLKCTRL_DEFAULT)
+		return(FALSE);
+	if((RD_HARPOON(ioPort + hp_seltimeout) == TO_250ms) ||
+		(RD_HARPOON(ioPort + hp_seltimeout) == TO_290ms))
+		return(TRUE);
+	return(FALSE);
+
+}
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_start_sccb
+ *
+ * Description: Start a command pointed to by p_Sccb. When the
+ *              command is completed it will be returned via the
+ *              callback function.
+ *
+ *---------------------------------------------------------------------*/
+#if (FW_TYPE==_UCB_MGR_)
+void SccbMgr_start_sccb(CARD_HANDLE pCurrCard, PUCB p_ucb)
+#else
+#if defined(DOS)
+void SccbMgr_start_sccb(USHORT pCurrCard, PSCCB p_Sccb)
+#else
+void SccbMgr_start_sccb(ULONG pCurrCard, PSCCB p_Sccb)
+#endif
+#endif
+{
+#if defined(DOS)
+   USHORT ioport;
+#else
+   ULONG ioport;
+#endif
+   UCHAR thisCard, lun;
+	PSCCB pSaveSccb;
+   CALL_BK_FN callback;
+
+#if (FW_TYPE==_UCB_MGR_)
+   PSCCB p_Sccb;
+#endif
+
+   mOS_Lock((PSCCBcard)pCurrCard);
+   thisCard = ((PSCCBcard) pCurrCard)->cardIndex;
+   ioport = ((PSCCBcard) pCurrCard)->ioPort;
+
+#if (FW_TYPE==_UCB_MGR_)
+   p_Sccb = (PSCCB)p_ucb->UCB_MgrPrivatePtr;
+#endif
+
+	if((p_Sccb->TargID > MAX_SCSI_TAR) || (p_Sccb->Lun > MAX_LUN))
+	{
+
+#if (FW_TYPE==_UCB_MGR_)
+		p_ucb->UCB_hbastat = SCCB_COMPLETE;
+		p_ucb->UCB_status=SCCB_ERROR;
+		callback = (CALL_BK_FN)p_ucb->UCB_callback;
+		if (callback)
+			callback(p_ucb);
+#endif
+
+#if (FW_TYPE==_SCCB_MGR_)
+		p_Sccb->HostStatus = SCCB_COMPLETE;
+		p_Sccb->SccbStatus = SCCB_ERROR;
+		callback = (CALL_BK_FN)p_Sccb->SccbCallback;
+		if (callback)
+			callback(p_Sccb);
+#endif
+
+		mOS_UnLock((PSCCBcard)pCurrCard);
+		return;
+	}
+
+#if (FW_TYPE==_SCCB_MGR_)
+   sinits(p_Sccb,thisCard);
+#endif
+
+
+#if (FW_TYPE==_UCB_MGR_)
+#ifndef NO_IOCTLS
+
+   if (p_ucb->UCB_opcode & OPC_IOCTL)
+	{
+
+		switch (p_ucb->UCB_IOCTLCommand) 
+		{
+			case READ_NVRAM:
+				ReadNVRam((PSCCBcard)pCurrCard,p_ucb);
+				p_ucb->UCB_status=UCB_SUCCESS;
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+
+			case WRITE_NVRAM:
+				WriteNVRam((PSCCBcard)pCurrCard,p_ucb);
+				p_ucb->UCB_status=UCB_SUCCESS;
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+
+			case SEND_SCSI_PASSTHRU:
+#if (FW_TYPE != _SCCB_MGR_)
+				if( p_ucb->UCB_targid >=
+				    ((PSCCBcard)pCurrCard)->cardInfo->ai_MaxTarg )
+				{
+					p_ucb->UCB_status = UCB_ERROR;
+					p_ucb->UCB_hbastat = HASTAT_HW_ERROR;
+					callback = (CALL_BK_FN)p_ucb->UCB_callback;
+					if (callback)
+						callback(p_ucb);
+					mOS_UnLock((PSCCBcard)pCurrCard);
+					return;
+				}
+#endif
+				break;
+
+			case HARD_RESET:
+				p_ucb->UCB_status = UCB_INVALID;
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+			case GET_DEVICE_SYNCRATE:
+				if( !GetDevSyncRate((PSCCBcard)pCurrCard,p_ucb) )
+				{
+					p_ucb->UCB_status = UCB_SUCCESS;
+				}
+				else
+				{
+					p_ucb->UCB_status = UCB_ERROR;
+					p_ucb->UCB_hbastat = HASTAT_HW_ERROR;
+				}
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+			case SET_DEVICE_SYNCRATE:
+				if( !SetDevSyncRate((PSCCBcard)pCurrCard,p_ucb) )
+				{
+					p_ucb->UCB_status = UCB_SUCCESS;
+				}
+				else
+				{
+					p_ucb->UCB_status = UCB_ERROR;
+					p_ucb->UCB_hbastat = HASTAT_HW_ERROR;
+				}
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+			case GET_WIDE_MODE:
+				if( !GetDevWideMode((PSCCBcard)pCurrCard,p_ucb) )
+				{
+					p_ucb->UCB_status = UCB_SUCCESS;
+				}
+				else
+				{
+					p_ucb->UCB_status = UCB_ERROR;
+					p_ucb->UCB_hbastat = HASTAT_HW_ERROR;
+				}
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+			case SET_WIDE_MODE:
+				if( !SetDevWideMode((PSCCBcard)pCurrCard,p_ucb) )
+				{
+					p_ucb->UCB_status = UCB_SUCCESS;
+				}
+				else
+				{
+					p_ucb->UCB_status = UCB_ERROR;
+					p_ucb->UCB_hbastat = HASTAT_HW_ERROR;
+				}
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+			default:
+				p_ucb->UCB_status=UCB_INVALID;
+				callback = (CALL_BK_FN)p_ucb->UCB_callback;
+				if (callback)
+					callback(p_ucb);
+				mOS_UnLock((PSCCBcard)pCurrCard);
+				return;
+		}
+	}
+#endif /* NO_IOCTLS */
+#endif /* (FW_TYPE==_UCB_MGR_) */
+
+
+   if (!((PSCCBcard) pCurrCard)->cmdCounter)
+      {
+      WR_HARPOON(ioport+hp_semaphore, (RD_HARPOON(ioport+hp_semaphore)
+         | SCCB_MGR_ACTIVE));
+
+      if (((PSCCBcard) pCurrCard)->globalFlags & F_GREEN_PC)
+         {
+		 WR_HARPOON(ioport+hp_clkctrl_0, CLKCTRL_DEFAULT);
+		 WR_HARPOON(ioport+hp_sys_ctrl, 0x00);
+         }
+      }
+
+   ((PSCCBcard)pCurrCard)->cmdCounter++;
+
+   if (RD_HARPOON(ioport+hp_semaphore) & BIOS_IN_USE) {
+
+      WR_HARPOON(ioport+hp_semaphore, (RD_HARPOON(ioport+hp_semaphore)
+         | TICKLE_ME));
+		if(p_Sccb->OperationCode == RESET_COMMAND)
+			{
+				pSaveSccb = ((PSCCBcard) pCurrCard)->currentSCCB;
+				((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+				queueSelectFail(&BL_Card[thisCard], thisCard);
+				((PSCCBcard) pCurrCard)->currentSCCB = pSaveSccb;
+			}
+		else
+			{
+	      queueAddSccb(p_Sccb,thisCard);
+			}
+      }
+
+   else if ((RD_HARPOON(ioport+hp_page_ctrl) & G_INT_DISABLE)) {
+
+			if(p_Sccb->OperationCode == RESET_COMMAND)
+				{
+					pSaveSccb = ((PSCCBcard) pCurrCard)->currentSCCB;
+					((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+					queueSelectFail(&BL_Card[thisCard], thisCard);
+					((PSCCBcard) pCurrCard)->currentSCCB = pSaveSccb;
+				}
+			else
+				{
+		      queueAddSccb(p_Sccb,thisCard);
+				}
+      }
+
+   else {
+
+      MDISABLE_INT(ioport);
+
+		if((((PSCCBcard) pCurrCard)->globalFlags & F_CONLUN_IO) && 
+			((sccbMgrTbl[thisCard][p_Sccb->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+			lun = p_Sccb->Lun;
+		else
+			lun = 0;
+      if ((((PSCCBcard) pCurrCard)->currentSCCB == NULL) &&
+         (sccbMgrTbl[thisCard][p_Sccb->TargID].TarSelQ_Cnt == 0) &&
+         (sccbMgrTbl[thisCard][p_Sccb->TargID].TarLUNBusy[lun]
+         == FALSE)) {
+
+            ((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+			   mOS_UnLock((PSCCBcard)pCurrCard);
+#if defined(DOS)
+            ssel((USHORT)p_Sccb->SccbIOPort,thisCard);
+#else
+	    ssel(p_Sccb->SccbIOPort,thisCard);
+#endif
+			   mOS_Lock((PSCCBcard)pCurrCard);
+         }
+
+      else {
+
+			if(p_Sccb->OperationCode == RESET_COMMAND)
+				{
+					pSaveSccb = ((PSCCBcard) pCurrCard)->currentSCCB;
+					((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+					queueSelectFail(&BL_Card[thisCard], thisCard);
+					((PSCCBcard) pCurrCard)->currentSCCB = pSaveSccb;
+				}
+			else
+				{
+	         	queueAddSccb(p_Sccb,thisCard);
+				}
+         }
+
+
+      MENABLE_INT(ioport);
+      }
+
+   mOS_UnLock((PSCCBcard)pCurrCard);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_abort_sccb
+ *
+ * Description: Abort the command pointed to by p_Sccb.  When the
+ *              command is completed it will be returned via the
+ *              callback function.
+ *
+ *---------------------------------------------------------------------*/
+#if (FW_TYPE==_UCB_MGR_)
+s32bits SccbMgr_abort_sccb(CARD_HANDLE pCurrCard, PUCB p_ucb)
+#else
+#if defined(DOS)
+int SccbMgr_abort_sccb(USHORT pCurrCard, PSCCB p_Sccb)
+#else
+int SccbMgr_abort_sccb(ULONG pCurrCard, PSCCB p_Sccb)
+#endif
+#endif
+
+{
+#if defined(DOS)
+	USHORT ioport;
+#else
+	ULONG ioport;
+#endif
+
+	UCHAR thisCard;
+	CALL_BK_FN callback;
+	UCHAR TID;
+	PSCCB pSaveSCCB;
+	PSCCBMgr_tar_info currTar_Info;
+
+
+#if (FW_TYPE==_UCB_MGR_)
+	PSCCB    p_Sccb;
+	p_Sccb=(PSCCB)p_ucb->UCB_MgrPrivatePtr;
+#endif
+
+	ioport = ((PSCCBcard) pCurrCard)->ioPort;
+
+	thisCard = ((PSCCBcard)pCurrCard)->cardIndex;
+
+	mOS_Lock((PSCCBcard)pCurrCard);
+
+	if (RD_HARPOON(ioport+hp_page_ctrl) & G_INT_DISABLE)
+	{
+		mOS_UnLock((PSCCBcard)pCurrCard);
+	}
+
+	else
+	{
+
+		if (queueFindSccb(p_Sccb,thisCard))
+		{
+
+			mOS_UnLock((PSCCBcard)pCurrCard);
+
+			((PSCCBcard)pCurrCard)->cmdCounter--;
+
+			if (!((PSCCBcard)pCurrCard)->cmdCounter)
+				WR_HARPOON(ioport+hp_semaphore,(RD_HARPOON(ioport+hp_semaphore)
+					& (UCHAR)(~(SCCB_MGR_ACTIVE | TICKLE_ME)) ));
+
+#if (FW_TYPE==_SCCB_MGR_)
+			p_Sccb->SccbStatus = SCCB_ABORT;
+			callback = p_Sccb->SccbCallback;
+			callback(p_Sccb);
+#else
+			p_ucb->UCB_status=SCCB_ABORT;
+			callback = (CALL_BK_FN)p_ucb->UCB_callback;
+			callback(p_ucb);
+#endif
+
+			return(0);
+		}
+
+		else
+		{
+			mOS_UnLock((PSCCBcard)pCurrCard);
+
+			if (((PSCCBcard)pCurrCard)->currentSCCB == p_Sccb)
+			{
+				p_Sccb->SccbStatus = SCCB_ABORT;
+				return(0);
+
+			}
+
+			else
+			{
+
+				TID = p_Sccb->TargID;
+
+
+				if(p_Sccb->Sccb_tag)
+				{
+					MDISABLE_INT(ioport);
+					if (((PSCCBcard) pCurrCard)->discQ_Tbl[p_Sccb->Sccb_tag]==p_Sccb)
+					{
+						p_Sccb->SccbStatus = SCCB_ABORT;
+						p_Sccb->Sccb_scsistat = ABORT_ST;
+#if (FW_TYPE==_UCB_MGR_)
+						p_ucb->UCB_status=SCCB_ABORT;
+#endif
+						p_Sccb->Sccb_scsimsg = SMABORT_TAG;
+
+						if(((PSCCBcard) pCurrCard)->currentSCCB == NULL)
+						{
+							((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+							ssel(ioport, thisCard);
+						}
+						else
+						{
+							pSaveSCCB = ((PSCCBcard) pCurrCard)->currentSCCB;
+							((PSCCBcard) pCurrCard)->currentSCCB = p_Sccb;
+							queueSelectFail((PSCCBcard) pCurrCard, thisCard);
+							((PSCCBcard) pCurrCard)->currentSCCB = pSaveSCCB;
+						}
+					}
+					MENABLE_INT(ioport);
+					return(0);
+				}
+				else
+				{
+					currTar_Info = &sccbMgrTbl[thisCard][p_Sccb->TargID];
+
+					if(BL_Card[thisCard].discQ_Tbl[currTar_Info->LunDiscQ_Idx[p_Sccb->Lun]] 
+							== p_Sccb)
+					{
+						p_Sccb->SccbStatus = SCCB_ABORT;
+						return(0);
+					}
+				}
+			}
+		}
+	}
+	return(-1);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_my_int
+ *
+ * Description: Do a quick check to determine if there is a pending
+ *              interrupt for this card and disable the IRQ Pin if so.
+ *
+ *---------------------------------------------------------------------*/
+#if (FW_TYPE==_UCB_MGR_)
+u08bits SccbMgr_my_int(CARD_HANDLE pCurrCard)
+#else
+#if defined(DOS)
+UCHAR SccbMgr_my_int(USHORT pCurrCard)
+#else
+UCHAR SccbMgr_my_int(ULONG pCurrCard)
+#endif
+#endif
+{
+#if defined(DOS)
+   USHORT ioport;
+#else
+   ULONG ioport;
+#endif
+
+   ioport = ((PSCCBcard)pCurrCard)->ioPort;
+
+   if (RD_HARPOON(ioport+hp_int_status) & INT_ASSERTED)
+   {
+
+#if defined(DOS)
+      MDISABLE_INT(ioport);
+#endif
+
+      return(TRUE);
+   }
+
+   else
+
+      return(FALSE);
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_isr
+ *
+ * Description: This is our entry point when an interrupt is generated
+ *              by the card and the upper level driver passes it on to
+ *              us.
+ *
+ *---------------------------------------------------------------------*/
+#if (FW_TYPE==_UCB_MGR_)
+s32bits SccbMgr_isr(CARD_HANDLE pCurrCard)
+#else
+#if defined(DOS)
+int SccbMgr_isr(USHORT pCurrCard)
+#else
+int SccbMgr_isr(ULONG pCurrCard)
+#endif
+#endif
+{
+   PSCCB currSCCB;
+   UCHAR thisCard,result,bm_status, bm_int_st;
+   USHORT hp_int;
+   UCHAR i, target;
+#if defined(DOS)
+   USHORT ioport;
+#else
+   ULONG ioport;
+#endif
+
+   mOS_Lock((PSCCBcard)pCurrCard);
+
+   thisCard = ((PSCCBcard)pCurrCard)->cardIndex;
+   ioport = ((PSCCBcard)pCurrCard)->ioPort;
+
+   MDISABLE_INT(ioport);
+
+#if defined(BUGBUG)
+   WR_HARPOON(ioport+hp_user_defined_D, RD_HARPOON(ioport+hp_int_status));
+#endif
+
+   if ((bm_int_st=RD_HARPOON(ioport+hp_int_status)) & EXT_STATUS_ON)
+		bm_status = RD_HARPOON(ioport+hp_ext_status) & (UCHAR)BAD_EXT_STATUS;
+   else
+      bm_status = 0;
+
+   WR_HARPOON(ioport+hp_int_mask, (INT_CMD_COMPL | SCSI_INTERRUPT));
+
+   mOS_UnLock((PSCCBcard)pCurrCard);
+
+   while ((hp_int = RDW_HARPOON((ioport+hp_intstat)) & default_intena) |
+	  bm_status)
+     {
+
+       currSCCB = ((PSCCBcard)pCurrCard)->currentSCCB;
+
+#if defined(BUGBUG)
+   Debug_Load(thisCard,(UCHAR) 0XFF);
+   Debug_Load(thisCard,bm_int_st);
+
+   Debug_Load(thisCard,hp_int_0);
+   Debug_Load(thisCard,hp_int_1);
+#endif
+
+
+      if (hp_int & (FIFO | TIMEOUT | RESET | SCAM_SEL) || bm_status) {
+         result = SccbMgr_bad_isr(ioport,thisCard,((PSCCBcard)pCurrCard),hp_int);
+         WRW_HARPOON((ioport+hp_intstat), (FIFO | TIMEOUT | RESET | SCAM_SEL));
+         bm_status = 0;
+
+         if (result) {
+
+			   mOS_Lock((PSCCBcard)pCurrCard);
+            MENABLE_INT(ioport);
+			   mOS_UnLock((PSCCBcard)pCurrCard);
+            return(result);
+            }
+         }
+
+
+      else if (hp_int & ICMD_COMP) {
+
+         if ( !(hp_int & BUS_FREE) ) {
+            /* Wait for the BusFree before starting a new command.  We
+               must also check for being reselected since the BusFree
+               may not show up if another device reselects us in 1.5us or
+               less.  SRR Wednesday, 3/8/1995.
+	         */
+	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ;
+	 }
+
+         if (((PSCCBcard)pCurrCard)->globalFlags & F_HOST_XFER_ACT)
+
+            phaseChkFifo(ioport, thisCard);
+
+/*         WRW_HARPOON((ioport+hp_intstat),
+            (BUS_FREE | ICMD_COMP | ITAR_DISC | XFER_CNT_0));
+         */
+
+		 WRW_HARPOON((ioport+hp_intstat), CLR_ALL_INT_1);
+
+         autoCmdCmplt(ioport,thisCard);
+
+         }
+
+
+      else if (hp_int & ITAR_DISC)
+         {
+
+         if (((PSCCBcard)pCurrCard)->globalFlags & F_HOST_XFER_ACT) {
+
+            phaseChkFifo(ioport, thisCard);
+
+            }
+
+         if (RD_HARPOON(ioport+hp_gp_reg_1) == SMSAVE_DATA_PTR) {
+
+            WR_HARPOON(ioport+hp_gp_reg_1, 0x00);
+            currSCCB->Sccb_XferState |= F_NO_DATA_YET;
+
+            currSCCB->Sccb_savedATC = currSCCB->Sccb_ATC;
+            }
+
+         currSCCB->Sccb_scsistat = DISCONNECT_ST;
+         queueDisconnect(currSCCB,thisCard);
+
+            /* Wait for the BusFree before starting a new command.  We
+               must also check for being reselected since the BusFree
+               may not show up if another device reselects us in 1.5us or
+               less.  SRR Wednesday, 3/8/1995.
+             */
+	   while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) &&
+		  !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) &&
+		    RD_HARPOON((ioport+hp_scsisig)) ==
+		    (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ;
+
+	   /*
+	     The additional loop exit condition above detects a timing problem
+	     with the revision D/E harpoon chips.  The caller should reset the
+	     host adapter to recover when 0xFE is returned.
+	   */
+	   if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)))
+	     {
+	       mOS_Lock((PSCCBcard)pCurrCard);
+	       MENABLE_INT(ioport);
+	       mOS_UnLock((PSCCBcard)pCurrCard);
+	       return 0xFE;
+	     }
+
+         WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC));
+
+
+         ((PSCCBcard)pCurrCard)->globalFlags |= F_NEW_SCCB_CMD;
+
+      	}
+
+
+      else if (hp_int & RSEL) {
+
+         WRW_HARPOON((ioport+hp_intstat), (PROG_HLT | RSEL | PHASE | BUS_FREE));
+
+         if (RDW_HARPOON((ioport+hp_intstat)) & ITAR_DISC)
+		      {
+            if (((PSCCBcard)pCurrCard)->globalFlags & F_HOST_XFER_ACT)
+			      {
+               phaseChkFifo(ioport, thisCard);
+               }
+
+            if (RD_HARPOON(ioport+hp_gp_reg_1) == SMSAVE_DATA_PTR)
+			      {
+               WR_HARPOON(ioport+hp_gp_reg_1, 0x00);
+               currSCCB->Sccb_XferState |= F_NO_DATA_YET;
+               currSCCB->Sccb_savedATC = currSCCB->Sccb_ATC;
+               }
+
+            WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC));
+            currSCCB->Sccb_scsistat = DISCONNECT_ST;
+            queueDisconnect(currSCCB,thisCard);
+            }
+
+         sres(ioport,thisCard,((PSCCBcard)pCurrCard));
+         phaseDecode(ioport,thisCard);
+
+         }
+
+
+      else if ((hp_int & IDO_STRT) && (!(hp_int & BUS_FREE)))
+         {
+
+            WRW_HARPOON((ioport+hp_intstat), (IDO_STRT | XFER_CNT_0));
+            phaseDecode(ioport,thisCard);
+
+         }
+
+
+      else if ( (hp_int & IUNKWN) || (hp_int & PROG_HLT) )
+		   {
+	 	   WRW_HARPOON((ioport+hp_intstat), (PHASE | IUNKWN | PROG_HLT));
+	 	   if ((RD_HARPOON(ioport+hp_prgmcnt_0) & (UCHAR)0x3f)< (UCHAR)SELCHK)
+	    		{
+	    		phaseDecode(ioport,thisCard);
+	    		}
+	 	   else
+	    		{
+   /* Harpoon problem some SCSI target device respond to selection
+   with short BUSY pulse (<400ns) this will make the Harpoon is not able
+   to latch the correct Target ID into reg. x53.
+   The work around require to correct this reg. But when write to this
+   reg. (0x53) also increment the FIFO write addr reg (0x6f), thus we
+   need to read this reg first then restore it later. After update to 0x53 */
+
+	    		i = (UCHAR)(RD_HARPOON(ioport+hp_fifowrite));
+	    		target = (UCHAR)(RD_HARPOON(ioport+hp_gp_reg_3));
+	    		WR_HARPOON(ioport+hp_xfer_pad, (UCHAR) ID_UNLOCK);
+	    		WR_HARPOON(ioport+hp_select_id, (UCHAR)(target | target<<4));
+	    		WR_HARPOON(ioport+hp_xfer_pad, (UCHAR) 0x00);
+	    		WR_HARPOON(ioport+hp_fifowrite, i);
+	    		WR_HARPOON(ioport+hp_autostart_3, (AUTO_IMMED+TAG_STRT));
+	    		}
+	 	   }
+
+      else if (hp_int & XFER_CNT_0) {
+
+         WRW_HARPOON((ioport+hp_intstat), XFER_CNT_0);
+
+         schkdd(ioport,thisCard);
+
+         }
+
+
+      else if (hp_int & BUS_FREE) {
+
+         WRW_HARPOON((ioport+hp_intstat), BUS_FREE);
+
+        	if (((PSCCBcard)pCurrCard)->globalFlags & F_HOST_XFER_ACT) {
+
+           	hostDataXferAbort(ioport,thisCard,currSCCB);
+				}
+
+         phaseBusFree(ioport,thisCard);
+			}
+
+
+      else if (hp_int & ITICKLE) {
+
+         WRW_HARPOON((ioport+hp_intstat), ITICKLE);
+         ((PSCCBcard)pCurrCard)->globalFlags |= F_NEW_SCCB_CMD;
+         }
+
+
+
+      if (((PSCCBcard)pCurrCard)->globalFlags & F_NEW_SCCB_CMD) {
+
+
+         ((PSCCBcard)pCurrCard)->globalFlags &= ~F_NEW_SCCB_CMD;
+
+
+         if (((PSCCBcard)pCurrCard)->currentSCCB == NULL) {
+
+            queueSearchSelect(((PSCCBcard)pCurrCard),thisCard);
+            }
+
+         if (((PSCCBcard)pCurrCard)->currentSCCB != NULL) {
+            ((PSCCBcard)pCurrCard)->globalFlags &= ~F_NEW_SCCB_CMD;
+            ssel(ioport,thisCard);
+            }
+
+         break;
+
+         }
+
+      }  /*end while */
+
+   mOS_Lock((PSCCBcard)pCurrCard);
+   MENABLE_INT(ioport);
+   mOS_UnLock((PSCCBcard)pCurrCard);
+
+   return(0);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Sccb_bad_isr
+ *
+ * Description: Some type of interrupt has occurred which is slightly
+ *              out of the ordinary.  We will now decode it fully, in
+ *              this routine.  This is broken up in an attempt to save
+ *              processing time.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+UCHAR SccbMgr_bad_isr(USHORT p_port, UCHAR p_card, PSCCBcard pCurrCard, USHORT p_int)
+#else
+UCHAR SccbMgr_bad_isr(ULONG p_port, UCHAR p_card, PSCCBcard pCurrCard, USHORT p_int)
+#endif
+{
+#if defined(HARP_REVX)
+   ULONG timer;
+#endif
+UCHAR temp, ScamFlg;
+PSCCBMgr_tar_info currTar_Info;
+PNVRamInfo pCurrNvRam;
+
+
+   if (RD_HARPOON(p_port+hp_ext_status) &
+         (BM_FORCE_OFF | PCI_DEV_TMOUT | BM_PARITY_ERR | PIO_OVERRUN) )
+      {
+
+      if (pCurrCard->globalFlags & F_HOST_XFER_ACT)
+         {
+
+         hostDataXferAbort(p_port,p_card, pCurrCard->currentSCCB);
+         }
+
+      if (RD_HARPOON(p_port+hp_pci_stat_cfg) & REC_MASTER_ABORT)
+
+         {
+         WR_HARPOON(p_port+hp_pci_stat_cfg,
+            (RD_HARPOON(p_port+hp_pci_stat_cfg) & ~REC_MASTER_ABORT));
+
+         WR_HARPOON(p_port+hp_host_blk_cnt, 0x00);
+
+         }
+
+      if (pCurrCard->currentSCCB != NULL)
+         {
+
+         if (!pCurrCard->currentSCCB->HostStatus)
+            pCurrCard->currentSCCB->HostStatus = SCCB_BM_ERR;
+
+         sxfrp(p_port,p_card);
+
+	     temp = (UCHAR)(RD_HARPOON(p_port+hp_ee_ctrl) &
+							(EXT_ARB_ACK | SCSI_TERM_ENA_H));
+      	WR_HARPOON(p_port+hp_ee_ctrl, ((UCHAR)temp | SEE_MS | SEE_CS));
+         WR_HARPOON(p_port+hp_ee_ctrl, temp);
+
+         if (!(RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | RESET)))
+            {
+            phaseDecode(p_port,p_card);
+            }
+         }
+      }
+
+
+   else if (p_int & RESET)
+         {
+
+				WR_HARPOON(p_port+hp_clkctrl_0, CLKCTRL_DEFAULT);
+				WR_HARPOON(p_port+hp_sys_ctrl, 0x00);
+           if (pCurrCard->currentSCCB != NULL) {
+
+               if (pCurrCard->globalFlags & F_HOST_XFER_ACT)
+
+               hostDataXferAbort(p_port,p_card, pCurrCard->currentSCCB);
+               }
+
+
+           DISABLE_AUTO(p_port);
+
+           sresb(p_port,p_card);
+
+           while(RD_HARPOON(p_port+hp_scsictrl_0) & SCSI_RST) {}
+
+				pCurrNvRam = pCurrCard->pNvRamInfo;
+				if(pCurrNvRam){
+					ScamFlg = pCurrNvRam->niScamConf;
+				}
+				else{
+				   ScamFlg = (UCHAR) utilEERead(p_port, SCAM_CONFIG/2);
+				}
+
+           XbowInit(p_port, ScamFlg);
+
+               scini(p_card, pCurrCard->ourId, 0);
+
+           return(0xFF);
+         }
+
+
+   else if (p_int & FIFO) {
+
+      WRW_HARPOON((p_port+hp_intstat), FIFO);
+
+#if defined(HARP_REVX)
+
+      for (timer=0x00FFFFFFL; timer != 0x00000000L; timer--) {
+
+         if (RD_HARPOON(p_port+hp_xferstat) & FIFO_EMPTY)
+            break;
+
+         if (RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)
+            break;
+         }
+
+
+      if ( (RD_HARPOON(p_port+hp_xferstat) & FIFO_EMPTY) &&
+           (RD_HARPOON(p_port+hp_fiforead) !=
+            RD_HARPOON(p_port+hp_fifowrite)) &&
+           (RD_HARPOON(p_port+hp_xfercnt_0))
+         )
+
+            WR_HARPOON((p_port+hp_xferstat), 0x01);
+
+/*      else
+ */
+/*         sxfrp(p_port,p_card);
+ */
+#else
+      if (pCurrCard->currentSCCB != NULL)
+         sxfrp(p_port,p_card);
+#endif
+      }
+
+   else if (p_int & TIMEOUT)
+      {
+
+      DISABLE_AUTO(p_port);
+
+      WRW_HARPOON((p_port+hp_intstat),
+		  (PROG_HLT | TIMEOUT | SEL |BUS_FREE | PHASE | IUNKWN));
+
+      pCurrCard->currentSCCB->HostStatus = SCCB_SELECTION_TIMEOUT;
+
+
+		currTar_Info = &sccbMgrTbl[p_card][pCurrCard->currentSCCB->TargID];
+		if((pCurrCard->globalFlags & F_CONLUN_IO) &&
+			((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+	      currTar_Info->TarLUNBusy[pCurrCard->currentSCCB->Lun] = FALSE;
+		else
+	      currTar_Info->TarLUNBusy[0] = FALSE;
+
+
+      if (currTar_Info->TarEEValue & EE_SYNC_MASK)
+         {
+	       currTar_Info->TarSyncCtrl = 0;
+         currTar_Info->TarStatus &= ~TAR_SYNC_MASK;
+         }
+
+      if (currTar_Info->TarEEValue & EE_WIDE_SCSI)
+         {
+         currTar_Info->TarStatus &= ~TAR_WIDE_MASK;
+         }
+
+      sssyncv(p_port, pCurrCard->currentSCCB->TargID, NARROW_SCSI,currTar_Info);
+
+      queueCmdComplete(pCurrCard, pCurrCard->currentSCCB, p_card);
+
+      }
+
+#if defined(SCAM_LEV_2)
+
+   else if (p_int & SCAM_SEL)
+      {
+
+      scarb(p_port,LEVEL2_TAR);
+      scsel(p_port);
+      scasid(p_card, p_port);
+
+      scbusf(p_port);
+
+      WRW_HARPOON((p_port+hp_intstat), SCAM_SEL);
+      }
+#endif
+
+   return(0x00);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_scsi_reset
+ *
+ * Description: A SCSI bus reset will be generated and all outstanding
+ *              Sccbs will be returned via the callback.
+ *
+ *---------------------------------------------------------------------*/
+#if (FW_TYPE==_UCB_MGR_)
+void SccbMgr_scsi_reset(CARD_HANDLE pCurrCard)
+#else
+#if defined(DOS)
+void SccbMgr_scsi_reset(USHORT pCurrCard)
+#else
+void SccbMgr_scsi_reset(ULONG pCurrCard)
+#endif
+#endif
+{
+   UCHAR thisCard;
+
+   thisCard = ((PSCCBcard)pCurrCard)->cardIndex;
+
+   mOS_Lock((PSCCBcard)pCurrCard);
+
+   if (((PSCCBcard) pCurrCard)->globalFlags & F_GREEN_PC)
+      {
+      WR_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_clkctrl_0, CLKCTRL_DEFAULT);
+      WR_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_sys_ctrl, 0x00);
+      }
+
+   sresb(((PSCCBcard)pCurrCard)->ioPort,thisCard);
+
+   if (RD_HARPOON(((PSCCBcard)pCurrCard)->ioPort+hp_ext_status) & BM_CMD_BUSY)
+      {
+      WR_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_page_ctrl,
+         (RD_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_page_ctrl)
+         & ~SCATTER_EN));
+
+      WR_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_sg_addr,0x00);
+
+      ((PSCCBcard) pCurrCard)->globalFlags &= ~F_HOST_XFER_ACT;
+      busMstrTimeOut(((PSCCBcard) pCurrCard)->ioPort);
+
+      WR_HARPOON(((PSCCBcard) pCurrCard)->ioPort+hp_int_mask,
+         (INT_CMD_COMPL | SCSI_INTERRUPT));
+      }
+
+/*
+      if (utilEERead(((PSCCBcard)pCurrCard)->ioPort, (SCAM_CONFIG/2))
+            & SCAM_ENABLED)
+*/
+         scini(thisCard, ((PSCCBcard)pCurrCard)->ourId, 0);
+
+#if (FW_TYPE==_UCB_MGR_)
+   ((PSCCBcard)pCurrCard)->cardInfo->ai_AEN_routine(0x01,pCurrCard,0,0,0,0);
+#endif
+
+   mOS_UnLock((PSCCBcard)pCurrCard);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_timer_expired
+ *
+ * Description: This function allow me to kill my own job that has not
+ *              yet completed, and has cause a timeout to occur.  This
+ *              timeout has caused the upper level driver to call this
+ *              function.
+ *
+ *---------------------------------------------------------------------*/
+
+#if (FW_TYPE==_UCB_MGR_)
+void SccbMgr_timer_expired(CARD_HANDLE pCurrCard)
+#else
+#if defined(DOS)
+void SccbMgr_timer_expired(USHORT pCurrCard)
+#else
+void SccbMgr_timer_expired(ULONG pCurrCard)
+#endif
+#endif
+{
+}
+
+#if defined(DOS)
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgr_status
+ *
+ * Description: This function returns the number of outstanding SCCB's.
+ *              This is specific to the DOS enviroment, which needs this
+ *              to help them keep protected and real mode commands staight.
+ *
+ *---------------------------------------------------------------------*/
+
+USHORT SccbMgr_status(USHORT pCurrCard)
+{
+   return(BL_Card[pCurrCard].cmdCounter);
+}
+#endif
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgrTableInit
+ *
+ * Description: Initialize all Sccb manager data structures.
+ *
+ *---------------------------------------------------------------------*/
+
+void SccbMgrTableInitAll()
+{
+   UCHAR thisCard;
+
+   for (thisCard = 0; thisCard < MAX_CARDS; thisCard++)
+      {
+      SccbMgrTableInitCard(&BL_Card[thisCard],thisCard);
+
+      BL_Card[thisCard].ioPort      = 0x00;
+      BL_Card[thisCard].cardInfo    = NULL;
+      BL_Card[thisCard].cardIndex   = 0xFF;
+      BL_Card[thisCard].ourId       = 0x00;
+		BL_Card[thisCard].pNvRamInfo	= NULL;
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgrTableInit
+ *
+ * Description: Initialize all Sccb manager data structures.
+ *
+ *---------------------------------------------------------------------*/
+
+void SccbMgrTableInitCard(PSCCBcard pCurrCard, UCHAR p_card)
+{
+   UCHAR scsiID, qtag;
+
+	for (qtag = 0; qtag < QUEUE_DEPTH; qtag++)
+	{
+		BL_Card[p_card].discQ_Tbl[qtag] = NULL;
+	}
+
+   for (scsiID = 0; scsiID < MAX_SCSI_TAR; scsiID++)
+      {
+      sccbMgrTbl[p_card][scsiID].TarStatus = 0;
+      sccbMgrTbl[p_card][scsiID].TarEEValue = 0;
+      SccbMgrTableInitTarget(p_card, scsiID);
+      }
+
+   pCurrCard->scanIndex = 0x00;
+   pCurrCard->currentSCCB = NULL;
+   pCurrCard->globalFlags = 0x00;
+   pCurrCard->cmdCounter  = 0x00;
+	pCurrCard->tagQ_Lst = 0x01;
+	pCurrCard->discQCount = 0; 
+
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: SccbMgrTableInit
+ *
+ * Description: Initialize all Sccb manager data structures.
+ *
+ *---------------------------------------------------------------------*/
+
+void SccbMgrTableInitTarget(UCHAR p_card, UCHAR target)
+{
+
+	UCHAR lun, qtag;
+	PSCCBMgr_tar_info currTar_Info;
+
+	currTar_Info = &sccbMgrTbl[p_card][target];
+
+	currTar_Info->TarSelQ_Cnt = 0;
+	currTar_Info->TarSyncCtrl = 0;
+
+	currTar_Info->TarSelQ_Head = NULL;
+	currTar_Info->TarSelQ_Tail = NULL;
+	currTar_Info->TarTagQ_Cnt = 0;
+	currTar_Info->TarLUN_CA = FALSE;
+
+
+	for (lun = 0; lun < MAX_LUN; lun++)
+	{
+		currTar_Info->TarLUNBusy[lun] = FALSE;
+		currTar_Info->LunDiscQ_Idx[lun] = 0;
+	}
+
+	for (qtag = 0; qtag < QUEUE_DEPTH; qtag++)
+	{
+		if(BL_Card[p_card].discQ_Tbl[qtag] != NULL)
+		{
+			if(BL_Card[p_card].discQ_Tbl[qtag]->TargID == target)
+			{
+				BL_Card[p_card].discQ_Tbl[qtag] = NULL;
+				BL_Card[p_card].discQCount--;
+			}
+		}
+	}
+}
+
+#if defined(BUGBUG)
+
+/*****************************************************************
+ * Save the current byte in the debug array
+ *****************************************************************/
+
+
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data)
+{
+   debug_int[p_card][debug_index[p_card]] = p_bug_data;
+   debug_index[p_card]++;
+
+   if (debug_index[p_card] == debug_size)
+
+      debug_index[p_card] = 0;
+}
+
+#endif
+#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   sccb_dat.c  $
+ *
+ *   Description:  Functions relating to handling of the SCCB interface 
+ *                 between the device driver and the HARPOON.
+ *
+ *   $Date: 1997/02/22 03:16:02 $
+ *
+ *   $Revision: 1.10 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <harpoon.h>*/
+
+/*
+**  IMPORTANT NOTE!!!
+**
+**  You MUST preassign all data to a valid value or zero.  This is
+**  required due to the MS compiler bug under OS/2 and Solaris Real-Mode
+**  driver environment.
+*/
+
+
+SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } };
+SCCBCARD BL_Card[MAX_CARDS] = { { 0 } };
+SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } };
+NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } };
+
+
+#if defined(OS2)
+void (far *s_PhaseTbl[8]) (ULONG, UCHAR) = { 0 };
+UCHAR temp_id_string[ID_STRING_LENGTH] = { 0 };
+#elif defined(SOLARIS_REAL_MODE) || defined(__STDC__)
+void (*s_PhaseTbl[8]) (ULONG, UCHAR) = { 0 };
+#else
+void (*s_PhaseTbl[8]) ();
+#endif
+
+#if defined(DOS)
+UCHAR first_time = 0;
+#endif
+
+UCHAR mbCards = 0;
+UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \
+								' ', 'B', 'T', '-', '9', '3', '0', \
+								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \
+								0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
+
+USHORT default_intena = 0;
+
+#if defined(BUGBUG)
+UCHAR    debug_int[MAX_CARDS][debug_size] = { 0 };
+UCHAR    debug_index[MAX_CARDS] = { 0 };
+UCHAR    reserved_1[3] = { 0 };
+#endif
+#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   scsi.c  $
+ *
+ *   Description:  Functions for handling SCSI bus functions such as
+ *                 selection/reselection, sync negotiation, message-in
+ *                 decoding.
+ *
+ *   $Date: 1997/07/09 21:42:54 $
+ *
+ *   $Revision: 1.23 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <eeprom.h>*/
+/*#include <harpoon.h>*/
+
+
+/*
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+#if defined(BUGBUG)
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
+#endif
+*/
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sfetm
+ *
+ * Description: Read in a message byte from the SCSI bus, and check
+ *              for a parity error.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR sfm(USHORT port, PSCCB pCurrSCCB)
+#else
+UCHAR sfm(ULONG port, PSCCB pCurrSCCB)
+#endif
+{
+	UCHAR message;
+	USHORT TimeOutLoop;
+
+	TimeOutLoop = 0;
+	while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
+			(TimeOutLoop++ < 20000) ){}
+
+
+	WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+
+	message = RD_HARPOON(port+hp_scsidata_0);
+
+	WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH);
+
+
+	if (TimeOutLoop > 20000)
+		message = 0x00;   /* force message byte = 0 if Time Out on Req */
+
+	if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
+		(RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR))
+	{
+		WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+		WR_HARPOON(port+hp_xferstat, 0);
+		WR_HARPOON(port+hp_fiforead, 0);
+		WR_HARPOON(port+hp_fifowrite, 0);
+		if (pCurrSCCB != NULL)
+		{
+			pCurrSCCB->Sccb_scsimsg = SMPARITY;
+		}
+		message = 0x00;
+		do
+		{
+			ACCEPT_MSG_ATN(port);
+			TimeOutLoop = 0;
+			while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
+				(TimeOutLoop++ < 20000) ){}
+			if (TimeOutLoop > 20000)
+			{
+				WRW_HARPOON((port+hp_intstat), PARITY);
+				return(message);
+			}
+			if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) != S_MSGI_PH)
+			{
+				WRW_HARPOON((port+hp_intstat), PARITY);
+				return(message);
+			}
+			WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+
+			RD_HARPOON(port+hp_scsidata_0);
+
+			WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+
+		}while(1);
+
+	}
+	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+	WR_HARPOON(port+hp_xferstat, 0);
+	WR_HARPOON(port+hp_fiforead, 0);
+	WR_HARPOON(port+hp_fifowrite, 0);
+	return(message);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: ssel
+ *
+ * Description: Load up automation and select target device.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void ssel(USHORT port, UCHAR p_card)
+#else
+void ssel(ULONG port, UCHAR p_card)
+#endif
+{
+
+#if defined(DOS)
+   UCHAR auto_loaded, i, target, *theCCB;
+#elif defined(OS2)
+   UCHAR auto_loaded, i, target;
+   UCHAR far *theCCB;
+#else
+   UCHAR auto_loaded, i, target, *theCCB;
+#endif
+
+#if defined(DOS)
+   USHORT cdb_reg;
+#else
+   ULONG cdb_reg;
+#endif
+   PSCCBcard CurrCard;
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+   UCHAR lastTag, lun;
+
+   CurrCard = &BL_Card[p_card];
+   currSCCB = CurrCard->currentSCCB;
+   target = currSCCB->TargID;
+   currTar_Info = &sccbMgrTbl[p_card][target];
+   lastTag = CurrCard->tagQ_Lst;
+
+   ARAM_ACCESS(port);
+
+
+	if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_REJECT)
+		currSCCB->ControlByte &= ~F_USE_CMD_Q;
+
+	if(((CurrCard->globalFlags & F_CONLUN_IO) && 
+		((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+
+	   lun = currSCCB->Lun;
+	else
+		lun = 0;
+
+
+#if defined(DOS)
+   currTar_Info->TarLUNBusy[lun] = TRUE;
+
+#else
+
+   if (CurrCard->globalFlags & F_TAG_STARTED)
+      {
+      if (!(currSCCB->ControlByte & F_USE_CMD_Q))
+         {
+      	if ((currTar_Info->TarLUN_CA == FALSE)
+      	    && ((currTar_Info->TarStatus & TAR_TAG_Q_MASK)
+      	    == TAG_Q_TRYING))
+            {
+
+	         if (currTar_Info->TarTagQ_Cnt !=0)
+                  {
+         		   currTar_Info->TarLUNBusy[lun] = TRUE;
+            		queueSelectFail(CurrCard,p_card);
+					   SGRAM_ACCESS(port);
+         		   return;
+         		   }
+
+            else {
+         		  currTar_Info->TarLUNBusy[lun] = TRUE;
+         		  }
+
+   	      }  /*End non-tagged */
+
+	      else {
+	         currTar_Info->TarLUNBusy[lun] = TRUE;
+	         }
+
+	      }  /*!Use cmd Q Tagged */
+
+	   else {
+   	     if (currTar_Info->TarLUN_CA == TRUE)
+               {
+      	      queueSelectFail(CurrCard,p_card);
+				   SGRAM_ACCESS(port);
+      	      return;
+	            }
+
+	        currTar_Info->TarLUNBusy[lun] = TRUE;
+
+   	     }  /*else use cmd Q tagged */
+
+      }  /*if glob tagged started */
+
+   else {
+        currTar_Info->TarLUNBusy[lun] = TRUE;
+        }
+
+#endif /* DOS */
+
+
+
+	if((((CurrCard->globalFlags & F_CONLUN_IO) && 
+		((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)) 
+		|| (!(currSCCB->ControlByte & F_USE_CMD_Q))))
+	{
+		if(CurrCard->discQCount >= QUEUE_DEPTH)
+		{
+			currTar_Info->TarLUNBusy[lun] = TRUE;
+			queueSelectFail(CurrCard,p_card);
+			SGRAM_ACCESS(port);
+			return;
+		}
+		for (i = 1; i < QUEUE_DEPTH; i++)
+		{
+			if (++lastTag >= QUEUE_DEPTH) lastTag = 1;
+			if (CurrCard->discQ_Tbl[lastTag] == NULL)
+			{
+				CurrCard->tagQ_Lst = lastTag;
+				currTar_Info->LunDiscQ_Idx[lun] = lastTag;
+				CurrCard->discQ_Tbl[lastTag] = currSCCB;
+				CurrCard->discQCount++;
+				break;
+			}
+		}
+		if(i == QUEUE_DEPTH)
+		{
+			currTar_Info->TarLUNBusy[lun] = TRUE;
+			queueSelectFail(CurrCard,p_card);
+			SGRAM_ACCESS(port);
+			return;
+		}
+	}
+
+
+
+   auto_loaded = FALSE;
+
+   WR_HARPOON(port+hp_select_id, target);
+   WR_HARPOON(port+hp_gp_reg_3, target);  /* Use by new automation logic */
+
+   if (currSCCB->OperationCode == RESET_COMMAND) {
+      WRW_HARPOON((port+ID_MSG_STRT), (MPM_OP+AMSG_OUT+
+               	 (currSCCB->Sccb_idmsg & ~DISC_PRIV)));
+
+      WRW_HARPOON((port+ID_MSG_STRT+2),BRH_OP+ALWAYS+NP);
+
+      currSCCB->Sccb_scsimsg = SMDEV_RESET;
+
+      WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+      auto_loaded = TRUE;
+      currSCCB->Sccb_scsistat = SELECT_BDR_ST;
+
+      if (currTar_Info->TarEEValue & EE_SYNC_MASK)
+         {
+	       currTar_Info->TarSyncCtrl = 0;
+	      currTar_Info->TarStatus &= ~TAR_SYNC_MASK;
+	      }
+
+#if defined(WIDE_SCSI)
+
+      if (currTar_Info->TarEEValue & EE_WIDE_SCSI)
+         {
+      	currTar_Info->TarStatus &= ~TAR_WIDE_MASK;
+      	}
+#endif
+
+      sssyncv(port, target, NARROW_SCSI,currTar_Info);
+      SccbMgrTableInitTarget(p_card, target);
+
+      }
+
+		else if(currSCCB->Sccb_scsistat == ABORT_ST)
+		{
+			WRW_HARPOON((port+ID_MSG_STRT), (MPM_OP+AMSG_OUT+
+								(currSCCB->Sccb_idmsg & ~DISC_PRIV)));
+
+      WRW_HARPOON((port+ID_MSG_STRT+2),BRH_OP+ALWAYS+CMDPZ);
+
+			WRW_HARPOON((port+SYNC_MSGS+0), (MPM_OP+AMSG_OUT+
+								(((UCHAR)(currSCCB->ControlByte & TAG_TYPE_MASK)
+								>> 6) | (UCHAR)0x20)));
+			WRW_HARPOON((port+SYNC_MSGS+2),
+							(MPM_OP+AMSG_OUT+currSCCB->Sccb_tag));
+			WRW_HARPOON((port+SYNC_MSGS+4), (BRH_OP+ALWAYS+NP ));
+
+			WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+			auto_loaded = TRUE;
+		
+		}
+
+#if defined(WIDE_SCSI)
+
+
+   else if (!(currTar_Info->TarStatus & WIDE_NEGOCIATED))  {
+      auto_loaded = siwidn(port,p_card);
+      currSCCB->Sccb_scsistat = SELECT_WN_ST;
+      }
+
+#endif
+
+
+   else if (!((currTar_Info->TarStatus & TAR_SYNC_MASK)
+      == SYNC_SUPPORTED))  {
+      auto_loaded = sisyncn(port,p_card, FALSE);
+      currSCCB->Sccb_scsistat = SELECT_SN_ST;
+      }
+
+
+   if (!auto_loaded)
+      {
+
+#if !defined(DOS)
+      if (currSCCB->ControlByte & F_USE_CMD_Q)
+         {
+
+         CurrCard->globalFlags |= F_TAG_STARTED;
+
+         if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK)
+            == TAG_Q_REJECT)
+            {
+            currSCCB->ControlByte &= ~F_USE_CMD_Q;
+
+            /* Fix up the start instruction with a jump to
+               Non-Tag-CMD handling */
+            WRW_HARPOON((port+ID_MSG_STRT),BRH_OP+ALWAYS+NTCMD);
+
+            WRW_HARPOON((port+NON_TAG_ID_MSG),
+	                     (MPM_OP+AMSG_OUT+currSCCB->Sccb_idmsg));
+
+	         WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+
+	         /* Setup our STATE so we know what happend when
+               the wheels fall off. */
+            currSCCB->Sccb_scsistat = SELECT_ST;
+
+	         currTar_Info->TarLUNBusy[lun] = TRUE;
+            }
+
+         else
+            {
+            WRW_HARPOON((port+ID_MSG_STRT), (MPM_OP+AMSG_OUT+currSCCB->Sccb_idmsg));
+
+            WRW_HARPOON((port+ID_MSG_STRT+2), (MPM_OP+AMSG_OUT+
+                        (((UCHAR)(currSCCB->ControlByte & TAG_TYPE_MASK)
+                        >> 6) | (UCHAR)0x20)));
+
+				for (i = 1; i < QUEUE_DEPTH; i++)
+				{
+					if (++lastTag >= QUEUE_DEPTH) lastTag = 1;
+					if (CurrCard->discQ_Tbl[lastTag] == NULL)
+					{
+						WRW_HARPOON((port+ID_MSG_STRT+6),
+							(MPM_OP+AMSG_OUT+lastTag));
+						CurrCard->tagQ_Lst = lastTag;
+						currSCCB->Sccb_tag = lastTag;
+						CurrCard->discQ_Tbl[lastTag] = currSCCB;
+						CurrCard->discQCount++;
+						break;
+					}
+				}
+
+
+            if ( i == QUEUE_DEPTH )
+               {
+   	         currTar_Info->TarLUNBusy[lun] = TRUE;
+               queueSelectFail(CurrCard,p_card);
+				   SGRAM_ACCESS(port);
+   	         return;
+   	         }
+
+            currSCCB->Sccb_scsistat = SELECT_Q_ST;
+
+   	      WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+            }
+         }
+
+      else
+         {
+#endif   /* !DOS */
+
+         WRW_HARPOON((port+ID_MSG_STRT),BRH_OP+ALWAYS+NTCMD);
+
+      	WRW_HARPOON((port+NON_TAG_ID_MSG),
+            (MPM_OP+AMSG_OUT+currSCCB->Sccb_idmsg));
+
+         currSCCB->Sccb_scsistat = SELECT_ST;
+
+         WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+#if !defined(DOS)
+         }
+#endif
+
+
+#if defined(OS2)
+      theCCB = (UCHAR far *)&currSCCB->Cdb[0];
+#else
+      theCCB = (UCHAR *)&currSCCB->Cdb[0];
+#endif
+
+      cdb_reg = port + CMD_STRT;
+
+      for (i=0; i < currSCCB->CdbLength; i++)
+         {
+         WRW_HARPOON(cdb_reg, (MPM_OP + ACOMMAND + *theCCB));
+         cdb_reg +=2;
+         theCCB++;
+         }
+
+      if (currSCCB->CdbLength != TWELVE_BYTE_CMD)
+         WRW_HARPOON(cdb_reg, (BRH_OP+ALWAYS+    NP));
+
+      }  /* auto_loaded */
+
+#if defined(WIDE_SCSI)
+   WRW_HARPOON((port+hp_fiforead), (USHORT) 0x00);
+   WR_HARPOON(port+hp_xferstat, 0x00);
+#endif
+
+   WRW_HARPOON((port+hp_intstat), (PROG_HLT | TIMEOUT | SEL | BUS_FREE));
+
+   WR_HARPOON(port+hp_portctrl_0,(SCSI_PORT));
+
+
+   if (!(currSCCB->Sccb_MGRFlags & F_DEV_SELECTED))
+      {
+      WR_HARPOON(port+hp_scsictrl_0, (SEL_TAR | ENA_ATN | ENA_RESEL | ENA_SCAM_SEL));
+      }
+   else
+      {
+
+/*      auto_loaded =  (RD_HARPOON(port+hp_autostart_3) & (UCHAR)0x1F);
+      auto_loaded |= AUTO_IMMED; */
+      auto_loaded = AUTO_IMMED;
+
+      DISABLE_AUTO(port);
+
+      WR_HARPOON(port+hp_autostart_3, auto_loaded);
+      }
+
+   SGRAM_ACCESS(port);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sres
+ *
+ * Description: Hookup the correct CCB and handle the incoming messages.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void sres(USHORT port, UCHAR p_card, PSCCBcard pCurrCard)
+#else
+void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
+#endif
+{
+
+#if defined(V302)
+#ifdef DOS
+   UCHAR our_target,message, msgRetryCount;
+   extern UCHAR lun, tag;
+#else
+   UCHAR our_target,message,lun,tag, msgRetryCount;
+#endif
+
+#else  /* V302 */
+   UCHAR our_target, message, lun = 0, tag, msgRetryCount;
+#endif /* V302 */
+
+
+   PSCCBMgr_tar_info currTar_Info;
+	PSCCB currSCCB;
+
+
+
+
+	if(pCurrCard->currentSCCB != NULL)
+	{
+		currTar_Info = &sccbMgrTbl[p_card][pCurrCard->currentSCCB->TargID];
+		DISABLE_AUTO(port);
+
+
+		WR_HARPOON((port+hp_scsictrl_0),(ENA_RESEL | ENA_SCAM_SEL));
+
+
+		currSCCB = pCurrCard->currentSCCB;
+		if(currSCCB->Sccb_scsistat == SELECT_WN_ST)
+		{
+			currTar_Info->TarStatus &= ~TAR_WIDE_MASK;
+			currSCCB->Sccb_scsistat = BUS_FREE_ST;
+		}
+		if(currSCCB->Sccb_scsistat == SELECT_SN_ST)
+		{
+			currTar_Info->TarStatus &= ~TAR_SYNC_MASK;
+			currSCCB->Sccb_scsistat = BUS_FREE_ST;
+		}
+		if(((pCurrCard->globalFlags & F_CONLUN_IO) &&
+			((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+		{
+      	currTar_Info->TarLUNBusy[currSCCB->Lun] = FALSE;
+			if(currSCCB->Sccb_scsistat != ABORT_ST)
+			{
+				pCurrCard->discQCount--;
+				pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[currSCCB->Lun]] 
+													= NULL;
+			}
+		}
+		else
+		{
+	      currTar_Info->TarLUNBusy[0] = FALSE;
+			if(currSCCB->Sccb_tag)
+			{
+				if(currSCCB->Sccb_scsistat != ABORT_ST)
+				{
+					pCurrCard->discQCount--;
+					pCurrCard->discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+				}
+			}else
+			{
+				if(currSCCB->Sccb_scsistat != ABORT_ST)
+				{
+					pCurrCard->discQCount--;
+					pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]] = NULL;
+				}
+			}
+		}
+
+      queueSelectFail(&BL_Card[p_card],p_card);
+	}
+
+#if defined(WIDE_SCSI)
+	WRW_HARPOON((port+hp_fiforead), (USHORT) 0x00);
+#endif
+
+
+	our_target = (UCHAR)(RD_HARPOON(port+hp_select_id) >> 4);
+	currTar_Info = &sccbMgrTbl[p_card][our_target];
+
+
+	msgRetryCount = 0;
+	do
+	{
+
+#if defined(V302)
+
+		message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun);
+
+#else /* V302 */
+
+		currTar_Info = &sccbMgrTbl[p_card][our_target];
+		tag = 0;
+
+
+		while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+		{
+			if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+			{
+
+				WRW_HARPOON((port+hp_intstat), PHASE);
+				return;
+			}
+		}
+
+		WRW_HARPOON((port+hp_intstat), PHASE);
+		if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH)
+		{
+
+			message = sfm(port,pCurrCard->currentSCCB);
+			if (message)
+			{
+
+				if (message <= (0x80 | LUN_MASK))
+				{
+					lun = message & (UCHAR)LUN_MASK;
+
+#if !defined(DOS)
+					if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING)
+					{
+						if (currTar_Info->TarTagQ_Cnt != 0)
+						{
+
+							if (!(currTar_Info->TarLUN_CA))
+							{
+								ACCEPT_MSG(port);    /*Release the ACK for ID msg. */
+
+
+								message = sfm(port,pCurrCard->currentSCCB);
+								if (message)
+								{
+									ACCEPT_MSG(port);
+								}
+
+								else
+   								message = FALSE;
+
+								if(message != FALSE)
+								{
+									tag = sfm(port,pCurrCard->currentSCCB);
+
+									if (!(tag)) 
+										message = FALSE;
+								}
+
+							} /*C.A. exists! */
+
+						} /*End Q cnt != 0 */
+
+					} /*End Tag cmds supported! */
+#endif /* !DOS */
+
+				} /*End valid ID message.  */
+
+				else
+				{
+
+					ACCEPT_MSG_ATN(port);
+				}
+
+			} /* End good id message. */
+
+			else
+			{
+
+				message = FALSE;
+			}
+		}
+		else
+		{
+			ACCEPT_MSG_ATN(port);
+
+		   while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) &&
+			  !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) &&
+			  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
+
+			return;
+		}
+	
+#endif /* V302 */
+
+		if(message == FALSE)
+		{
+			msgRetryCount++;
+			if(msgRetryCount == 1)
+			{
+				SendMsg(port, SMPARITY);
+			}
+			else
+			{
+				SendMsg(port, SMDEV_RESET);
+
+				sssyncv(port, our_target, NARROW_SCSI,currTar_Info);
+
+				if (sccbMgrTbl[p_card][our_target].TarEEValue & EE_SYNC_MASK) 
+				{
+			
+					sccbMgrTbl[p_card][our_target].TarStatus &= ~TAR_SYNC_MASK;
+
+				}
+
+				if (sccbMgrTbl[p_card][our_target].TarEEValue & EE_WIDE_SCSI) 
+				{
+
+					sccbMgrTbl[p_card][our_target].TarStatus &= ~TAR_WIDE_MASK;
+				}
+
+
+				queueFlushTargSccb(p_card, our_target, SCCB_COMPLETE);
+				SccbMgrTableInitTarget(p_card,our_target);
+				return;
+			}
+		}
+	}while(message == FALSE);
+
+
+
+	if(((pCurrCard->globalFlags & F_CONLUN_IO) &&
+		((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+	{
+		currTar_Info->TarLUNBusy[lun] = TRUE;
+		pCurrCard->currentSCCB = pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[lun]];
+		if(pCurrCard->currentSCCB != NULL)
+		{
+			ACCEPT_MSG(port);
+		}
+		else 
+		{
+			ACCEPT_MSG_ATN(port);
+		}
+	}
+	else
+	{
+		currTar_Info->TarLUNBusy[0] = TRUE;
+
+
+		if (tag)
+		{
+			if (pCurrCard->discQ_Tbl[tag] != NULL)
+			{
+				pCurrCard->currentSCCB = pCurrCard->discQ_Tbl[tag];
+		 		currTar_Info->TarTagQ_Cnt--;
+				ACCEPT_MSG(port);
+			}
+			else
+			{
+			ACCEPT_MSG_ATN(port);
+			}
+		}else
+		{
+			pCurrCard->currentSCCB = pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]];
+			if(pCurrCard->currentSCCB != NULL)
+			{
+				ACCEPT_MSG(port);
+			}
+			else 
+			{
+				ACCEPT_MSG_ATN(port);
+			}
+		}
+	}
+
+	if(pCurrCard->currentSCCB != NULL)
+	{
+		if(pCurrCard->currentSCCB->Sccb_scsistat == ABORT_ST)
+		{
+		/* During Abort Tag command, the target could have got re-selected
+			and completed the command. Check the select Q and remove the CCB
+			if it is in the Select Q */
+			queueFindSccb(pCurrCard->currentSCCB, p_card);
+		}
+	}
+
+
+   while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) &&
+	  !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) &&
+	  (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
+}
+
+#if defined(V302)
+
+#if defined(DOS)
+UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun)
+#else
+UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun)
+#endif
+{
+   UCHAR message;
+   PSCCBMgr_tar_info currTar_Info;
+
+
+	currTar_Info = &sccbMgrTbl[p_card][our_target];
+	*tag = 0;
+
+
+	while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+	{
+		if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+		{
+
+			WRW_HARPOON((port+hp_intstat), PHASE);
+			return(TRUE);
+		}
+	}
+
+	WRW_HARPOON((port+hp_intstat), PHASE);
+	if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH)
+	{
+
+		message = sfm(port,pCurrCard->currentSCCB);
+		if (message)
+		{
+
+			if (message <= (0x80 | LUN_MASK))
+			{
+				*lun = message & (UCHAR)LUN_MASK;
+
+#if !defined(DOS)
+				if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING)
+				{
+					if (currTar_Info->TarTagQ_Cnt != 0)
+					{
+
+						if (!(currTar_Info->TarLUN_CA))
+						{
+							ACCEPT_MSG(port);    /*Release the ACK for ID msg. */
+
+
+							message = sfm(port,pCurrCard->currentSCCB);
+							if (message)
+							{
+								ACCEPT_MSG(port);
+							}
+
+							else
+   							return(FALSE);
+
+							*tag = sfm(port,pCurrCard->currentSCCB);
+
+							if (!(*tag)) return(FALSE);
+
+						} /*C.A. exists! */
+
+					} /*End Q cnt != 0 */
+
+				} /*End Tag cmds supported! */
+#endif /* !DOS */
+
+			} /*End valid ID message.  */
+
+			else
+			{
+
+				ACCEPT_MSG_ATN(port);
+			}
+
+		} /* End good id message. */
+
+		else
+		{
+
+			return(FALSE);
+		}
+	}
+	else
+	{
+		ACCEPT_MSG_ATN(port);
+		return(TRUE);
+	}
+	return(TRUE);
+}
+
+#endif /* V302 */
+
+#if defined(DOS)
+void SendMsg(USHORT port, UCHAR message)
+#else
+void SendMsg(ULONG port, UCHAR message)
+#endif
+{
+	while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+	{
+		if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+		{
+
+			WRW_HARPOON((port+hp_intstat), PHASE);
+			return;
+		}
+	}
+
+	WRW_HARPOON((port+hp_intstat), PHASE);
+	if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGO_PH)
+	{
+		WRW_HARPOON((port+hp_intstat), (BUS_FREE | PHASE | XFER_CNT_0));
+
+
+		WR_HARPOON(port+hp_portctrl_0, SCSI_BUS_EN);
+
+		WR_HARPOON(port+hp_scsidata_0,message);
+
+		WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+
+		ACCEPT_MSG(port);
+
+		WR_HARPOON(port+hp_portctrl_0, 0x00);
+
+		if ((message == SMABORT) || (message == SMDEV_RESET) ||
+				(message == SMABORT_TAG) )
+		{
+			while(!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | PHASE))) {}
+
+			if (RDW_HARPOON((port+hp_intstat)) & BUS_FREE)
+			{
+			WRW_HARPOON((port+hp_intstat), BUS_FREE);
+			}
+		}
+	}
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sdecm
+ *
+ * Description: Determine the proper responce to the message from the
+ *              target device.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void sdecm(UCHAR message, USHORT port, UCHAR p_card)
+#else
+void sdecm(UCHAR message, ULONG port, UCHAR p_card)
+#endif
+{
+	PSCCB currSCCB;
+	PSCCBcard CurrCard;
+	PSCCBMgr_tar_info currTar_Info;
+
+	CurrCard = &BL_Card[p_card];
+	currSCCB = CurrCard->currentSCCB;
+
+	currTar_Info = &sccbMgrTbl[p_card][currSCCB->TargID];
+
+	if (message == SMREST_DATA_PTR)
+	{
+		if (!(currSCCB->Sccb_XferState & F_NO_DATA_YET))
+		{
+			currSCCB->Sccb_ATC = currSCCB->Sccb_savedATC;
+
+			hostDataXferRestart(currSCCB);
+		}
+
+		ACCEPT_MSG(port);
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+	}
+
+	else if (message == SMCMD_COMP)
+	{
+
+
+		if (currSCCB->Sccb_scsistat == SELECT_Q_ST)
+		{
+			currTar_Info->TarStatus &= ~(UCHAR)TAR_TAG_Q_MASK;
+			currTar_Info->TarStatus |= (UCHAR)TAG_Q_REJECT;
+		}
+
+		ACCEPT_MSG(port);
+
+	}
+
+	else if ((message == SMNO_OP) || (message >= SMIDENT) 
+			|| (message == SMINIT_RECOVERY) || (message == SMREL_RECOVERY))
+	{
+
+		ACCEPT_MSG(port);
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+	}
+
+	else if (message == SMREJECT)
+	{
+
+		if ((currSCCB->Sccb_scsistat == SELECT_SN_ST) ||
+				(currSCCB->Sccb_scsistat == SELECT_WN_ST) ||
+				((currTar_Info->TarStatus & TAR_SYNC_MASK) == SYNC_TRYING ) ||
+				((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING ) )
+
+		{
+			WRW_HARPOON((port+hp_intstat), BUS_FREE);
+
+			ACCEPT_MSG(port);
+
+
+			while ((!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
+				(!(RDW_HARPOON((port+hp_intstat)) & BUS_FREE))) {}
+
+			if(currSCCB->Lun == 0x00)
+			{
+				if ((currSCCB->Sccb_scsistat == SELECT_SN_ST))
+				{
+
+					currTar_Info->TarStatus |= (UCHAR)SYNC_SUPPORTED;
+
+					currTar_Info->TarEEValue &= ~EE_SYNC_MASK;
+				}
+
+#if defined(WIDE_SCSI)
+				else if ((currSCCB->Sccb_scsistat == SELECT_WN_ST))
+				{
+
+
+					currTar_Info->TarStatus = (currTar_Info->TarStatus &
+													~WIDE_ENABLED) | WIDE_NEGOCIATED;
+
+					currTar_Info->TarEEValue &= ~EE_WIDE_SCSI;
+
+				}
+#endif
+
+				else if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING )
+				{
+					currTar_Info->TarStatus = (currTar_Info->TarStatus &
+													~(UCHAR)TAR_TAG_Q_MASK) | TAG_Q_REJECT;
+
+
+					currSCCB->ControlByte &= ~F_USE_CMD_Q;
+					CurrCard->discQCount--;
+					CurrCard->discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+					currSCCB->Sccb_tag = 0x00;
+
+				}
+			}
+
+			if (RDW_HARPOON((port+hp_intstat)) & BUS_FREE)
+			{
+
+
+				if(currSCCB->Lun == 0x00)
+				{
+					WRW_HARPOON((port+hp_intstat), BUS_FREE);
+					CurrCard->globalFlags |= F_NEW_SCCB_CMD;
+				}
+			}
+
+			else 
+			{
+
+				if((CurrCard->globalFlags & F_CONLUN_IO) &&
+					((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+					currTar_Info->TarLUNBusy[currSCCB->Lun] = TRUE;
+				else
+					currTar_Info->TarLUNBusy[0] = TRUE;
+
+
+				currSCCB->ControlByte &= ~(UCHAR)F_USE_CMD_Q;
+
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+
+			}
+		}
+
+		else
+		{
+			ACCEPT_MSG(port);
+
+			while ((!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
+				(!(RDW_HARPOON((port+hp_intstat)) & BUS_FREE))) {}
+	
+			if (!(RDW_HARPOON((port+hp_intstat)) & BUS_FREE))
+			{
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+			}
+		}
+	}
+
+	else if (message == SMEXT)
+	{
+
+		ACCEPT_MSG(port);
+		shandem(port,p_card,currSCCB);
+	}
+
+	else if (message == SMIGNORWR)
+	{
+
+		ACCEPT_MSG(port);          /* ACK the RESIDUE MSG */
+
+		message = sfm(port,currSCCB);
+
+		if(currSCCB->Sccb_scsimsg != SMPARITY)
+			ACCEPT_MSG(port);
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+	}
+
+
+	else
+	{
+
+		currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
+		currSCCB->Sccb_scsimsg = SMREJECT;
+
+		ACCEPT_MSG_ATN(port);
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+	}
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: shandem
+ *
+ * Description: Decide what to do with the extended message.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void shandem(USHORT port, UCHAR p_card, PSCCB pCurrSCCB)
+#else
+void shandem(ULONG port, UCHAR p_card, PSCCB pCurrSCCB)
+#endif
+{
+	UCHAR length,message;
+
+	length = sfm(port,pCurrSCCB);
+	if (length) 
+	{
+
+		ACCEPT_MSG(port);
+		message = sfm(port,pCurrSCCB);
+		if (message) 
+		{
+
+			if (message == SMSYNC) 
+			{
+
+				if (length == 0x03)
+				{
+
+					ACCEPT_MSG(port);
+					stsyncn(port,p_card);
+				}
+				else 
+				{
+
+					pCurrSCCB->Sccb_scsimsg = SMREJECT;
+					ACCEPT_MSG_ATN(port);
+				}
+			}
+#if defined(WIDE_SCSI)
+			else if (message == SMWDTR) 
+			{
+
+				if (length == 0x02)
+				{
+
+					ACCEPT_MSG(port);
+					stwidn(port,p_card);
+				}
+				else 
+				{
+
+					pCurrSCCB->Sccb_scsimsg = SMREJECT;
+					ACCEPT_MSG_ATN(port);
+
+					WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+				}
+			}
+#endif
+			else 
+			{
+
+				pCurrSCCB->Sccb_scsimsg = SMREJECT;
+				ACCEPT_MSG_ATN(port);
+
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+			}
+		}
+		else
+		{
+			if(pCurrSCCB->Sccb_scsimsg != SMPARITY)
+				ACCEPT_MSG(port);
+			WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		}
+	}else
+	{
+			if(pCurrSCCB->Sccb_scsimsg == SMPARITY)
+				WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+	}
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sisyncn
+ *
+ * Description: Read in a message byte from the SCSI bus, and check
+ *              for a parity error.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR sisyncn(USHORT port, UCHAR p_card, UCHAR syncFlag)
+#else
+UCHAR sisyncn(ULONG port, UCHAR p_card, UCHAR syncFlag)
+#endif
+{
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+   currTar_Info = &sccbMgrTbl[p_card][currSCCB->TargID];
+
+   if (!((currTar_Info->TarStatus & TAR_SYNC_MASK) == SYNC_TRYING)) {
+
+
+      WRW_HARPOON((port+ID_MSG_STRT),
+                 (MPM_OP+AMSG_OUT+(currSCCB->Sccb_idmsg & ~(UCHAR)DISC_PRIV)));
+
+      WRW_HARPOON((port+ID_MSG_STRT+2),BRH_OP+ALWAYS+CMDPZ);
+
+      WRW_HARPOON((port+SYNC_MSGS+0), (MPM_OP+AMSG_OUT+SMEXT ));
+      WRW_HARPOON((port+SYNC_MSGS+2), (MPM_OP+AMSG_OUT+0x03  ));
+      WRW_HARPOON((port+SYNC_MSGS+4), (MPM_OP+AMSG_OUT+SMSYNC));
+
+
+      if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_20MB)
+
+	 WRW_HARPOON((port+SYNC_MSGS+6), (MPM_OP+AMSG_OUT+ 12));
+
+      else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_10MB)
+
+	 WRW_HARPOON((port+SYNC_MSGS+6), (MPM_OP+AMSG_OUT+ 25));
+
+      else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_5MB)
+
+	 WRW_HARPOON((port+SYNC_MSGS+6), (MPM_OP+AMSG_OUT+ 50));
+
+      else
+	 WRW_HARPOON((port+SYNC_MSGS+6), (MPM_OP+AMSG_OUT+ 00));
+
+
+      WRW_HARPOON((port+SYNC_MSGS+8), (RAT_OP                ));
+      WRW_HARPOON((port+SYNC_MSGS+10),(MPM_OP+AMSG_OUT+DEFAULT_OFFSET));
+      WRW_HARPOON((port+SYNC_MSGS+12),(BRH_OP+ALWAYS+NP      ));
+
+
+		if(syncFlag == FALSE)
+		{
+		   WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+	      currTar_Info->TarStatus = ((currTar_Info->TarStatus &
+   	      ~(UCHAR)TAR_SYNC_MASK) | (UCHAR)SYNC_TRYING);
+		}
+		else
+		{
+		   WR_HARPOON(port+hp_autostart_3, (AUTO_IMMED + CMD_ONLY_STRT));
+		}
+
+
+      return(TRUE);
+      }
+
+   else {
+
+      currTar_Info->TarStatus |=	 (UCHAR)SYNC_SUPPORTED;
+      currTar_Info->TarEEValue &= ~EE_SYNC_MASK;
+      return(FALSE);
+      }
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: stsyncn
+ *
+ * Description: The has sent us a Sync Nego message so handle it as
+ *              necessary.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void stsyncn(USHORT port, UCHAR p_card)
+#else
+void stsyncn(ULONG port, UCHAR p_card)
+#endif
+{
+   UCHAR sync_msg,offset,sync_reg,our_sync_msg;
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+   currTar_Info = &sccbMgrTbl[p_card][currSCCB->TargID];
+
+   sync_msg = sfm(port,currSCCB);
+
+	if((sync_msg == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY))
+	{
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		return;
+	}
+
+   ACCEPT_MSG(port);
+
+
+   offset = sfm(port,currSCCB);
+
+	if((offset == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY))
+	{
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		return;
+	}
+
+   if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_20MB)
+
+      our_sync_msg = 12;              /* Setup our Message to 20mb/s */
+
+   else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_10MB)
+
+      our_sync_msg = 25;              /* Setup our Message to 10mb/s */
+
+   else if ((currTar_Info->TarEEValue & EE_SYNC_MASK) == EE_SYNC_5MB)
+
+      our_sync_msg = 50;              /* Setup our Message to 5mb/s */
+   else
+
+      our_sync_msg = 0;               /* Message = Async */
+
+   if (sync_msg < our_sync_msg) {
+      sync_msg = our_sync_msg;    /*if faster, then set to max. */
+      }
+
+   if (offset == ASYNC)
+      sync_msg = ASYNC;
+
+   if (offset > MAX_OFFSET)
+      offset = MAX_OFFSET;
+
+   sync_reg = 0x00;
+
+   if (sync_msg > 12)
+
+      sync_reg = 0x20;        /* Use 10MB/s */
+
+   if (sync_msg > 25)
+
+      sync_reg = 0x40;        /* Use 6.6MB/s */
+
+   if (sync_msg > 38)
+
+      sync_reg = 0x60;        /* Use 5MB/s */
+
+   if (sync_msg > 50)
+
+      sync_reg = 0x80;        /* Use 4MB/s */
+
+   if (sync_msg > 62)
+
+      sync_reg = 0xA0;        /* Use 3.33MB/s */
+
+   if (sync_msg > 75)
+
+      sync_reg = 0xC0;        /* Use 2.85MB/s */
+
+   if (sync_msg > 87)
+
+      sync_reg = 0xE0;        /* Use 2.5MB/s */
+
+   if (sync_msg > 100) {
+
+      sync_reg = 0x00;        /* Use ASYNC */
+      offset = 0x00;
+      }
+
+
+#if defined(WIDE_SCSI)
+   if (currTar_Info->TarStatus & WIDE_ENABLED)
+
+      sync_reg |= offset;
+
+   else
+
+      sync_reg |= (offset | NARROW_SCSI);
+
+#else
+   sync_reg |= (offset | NARROW_SCSI);
+#endif
+
+   sssyncv(port,currSCCB->TargID,sync_reg,currTar_Info);
+
+
+   if (currSCCB->Sccb_scsistat == SELECT_SN_ST) {
+
+
+      ACCEPT_MSG(port);
+
+      currTar_Info->TarStatus = ((currTar_Info->TarStatus &
+         ~(UCHAR)TAR_SYNC_MASK) | (UCHAR)SYNC_SUPPORTED);
+
+      WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+      }
+
+   else {
+
+
+      ACCEPT_MSG_ATN(port);
+
+      sisyncr(port,sync_msg,offset);
+
+      currTar_Info->TarStatus = ((currTar_Info->TarStatus &
+         ~(UCHAR)TAR_SYNC_MASK) | (UCHAR)SYNC_SUPPORTED);
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sisyncr
+ *
+ * Description: Answer the targets sync message.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void sisyncr(USHORT port,UCHAR sync_pulse, UCHAR offset)
+#else
+void sisyncr(ULONG port,UCHAR sync_pulse, UCHAR offset)
+#endif
+{
+   ARAM_ACCESS(port);
+   WRW_HARPOON((port+SYNC_MSGS+0), (MPM_OP+AMSG_OUT+SMEXT ));
+   WRW_HARPOON((port+SYNC_MSGS+2), (MPM_OP+AMSG_OUT+0x03  ));
+   WRW_HARPOON((port+SYNC_MSGS+4), (MPM_OP+AMSG_OUT+SMSYNC));
+   WRW_HARPOON((port+SYNC_MSGS+6), (MPM_OP+AMSG_OUT+sync_pulse));
+   WRW_HARPOON((port+SYNC_MSGS+8), (RAT_OP                ));
+   WRW_HARPOON((port+SYNC_MSGS+10),(MPM_OP+AMSG_OUT+offset));
+   WRW_HARPOON((port+SYNC_MSGS+12),(BRH_OP+ALWAYS+NP      ));
+   SGRAM_ACCESS(port);
+
+   WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT_1);
+
+   WR_HARPOON(port+hp_autostart_3, (AUTO_IMMED+CMD_ONLY_STRT));
+
+   while (!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | AUTO_INT))) {}
+}
+
+
+
+#if defined(WIDE_SCSI)
+
+/*---------------------------------------------------------------------
+ *
+ * Function: siwidn
+ *
+ * Description: Read in a message byte from the SCSI bus, and check
+ *              for a parity error.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR siwidn(USHORT port, UCHAR p_card)
+#else
+UCHAR siwidn(ULONG port, UCHAR p_card)
+#endif
+{
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+   currTar_Info = &sccbMgrTbl[p_card][currSCCB->TargID];
+
+   if (!((currTar_Info->TarStatus & TAR_WIDE_MASK) == WIDE_NEGOCIATED)) {
+
+
+      WRW_HARPOON((port+ID_MSG_STRT),
+	              (MPM_OP+AMSG_OUT+(currSCCB->Sccb_idmsg & ~(UCHAR)DISC_PRIV)));
+
+      WRW_HARPOON((port+ID_MSG_STRT+2),BRH_OP+ALWAYS+CMDPZ);
+
+      WRW_HARPOON((port+SYNC_MSGS+0), (MPM_OP+AMSG_OUT+SMEXT ));
+      WRW_HARPOON((port+SYNC_MSGS+2), (MPM_OP+AMSG_OUT+0x02  ));
+      WRW_HARPOON((port+SYNC_MSGS+4), (MPM_OP+AMSG_OUT+SMWDTR));
+      WRW_HARPOON((port+SYNC_MSGS+6), (RAT_OP                ));
+      WRW_HARPOON((port+SYNC_MSGS+8), (MPM_OP+AMSG_OUT+ SM16BIT));
+      WRW_HARPOON((port+SYNC_MSGS+10),(BRH_OP+ALWAYS+NP      ));
+
+      WR_HARPOON(port+hp_autostart_3, (SELECT+SELCHK_STRT));
+
+
+      currTar_Info->TarStatus = ((currTar_Info->TarStatus &
+         ~(UCHAR)TAR_WIDE_MASK) | (UCHAR)WIDE_ENABLED);
+
+      return(TRUE);
+      }
+
+   else {
+
+      currTar_Info->TarStatus = ((currTar_Info->TarStatus &
+               ~(UCHAR)TAR_WIDE_MASK) | WIDE_NEGOCIATED);
+
+      currTar_Info->TarEEValue &= ~EE_WIDE_SCSI;
+      return(FALSE);
+      }
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: stwidn
+ *
+ * Description: The has sent us a Wide Nego message so handle it as
+ *              necessary.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void stwidn(USHORT port, UCHAR p_card)
+#else
+void stwidn(ULONG port, UCHAR p_card)
+#endif
+{
+   UCHAR width;
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+   currTar_Info = &sccbMgrTbl[p_card][currSCCB->TargID];
+
+   width = sfm(port,currSCCB);
+
+	if((width == 0x00) && (currSCCB->Sccb_scsimsg == SMPARITY))
+	{
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		return;
+	}
+
+
+   if (!(currTar_Info->TarEEValue & EE_WIDE_SCSI))
+      width = 0;
+
+   if (width) {
+      currTar_Info->TarStatus |= WIDE_ENABLED;
+      width = 0;
+      }
+   else {
+      width = NARROW_SCSI;
+      currTar_Info->TarStatus &= ~WIDE_ENABLED;
+      }
+
+
+   sssyncv(port,currSCCB->TargID,width,currTar_Info);
+
+
+   if (currSCCB->Sccb_scsistat == SELECT_WN_ST)
+	{
+
+
+
+      currTar_Info->TarStatus |=	 WIDE_NEGOCIATED;
+
+	   if (!((currTar_Info->TarStatus & TAR_SYNC_MASK) == SYNC_SUPPORTED))
+		{
+	      ACCEPT_MSG_ATN(port);
+		   ARAM_ACCESS(port);
+	     	sisyncn(port,p_card, TRUE);
+	      currSCCB->Sccb_scsistat = SELECT_SN_ST;
+		   SGRAM_ACCESS(port);
+		}
+		else
+		{
+	      ACCEPT_MSG(port);
+  		   WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		}
+   }
+
+   else {
+
+
+      ACCEPT_MSG_ATN(port);
+
+      if (currTar_Info->TarEEValue & EE_WIDE_SCSI)
+      	 width = SM16BIT;
+      else
+      	 width = SM8BIT;
+
+      siwidr(port,width);
+
+      currTar_Info->TarStatus |= (WIDE_NEGOCIATED | WIDE_ENABLED);
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: siwidr
+ *
+ * Description: Answer the targets Wide nego message.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void siwidr(USHORT port, UCHAR width)
+#else
+void siwidr(ULONG port, UCHAR width)
+#endif
+{
+   ARAM_ACCESS(port);
+   WRW_HARPOON((port+SYNC_MSGS+0), (MPM_OP+AMSG_OUT+SMEXT ));
+   WRW_HARPOON((port+SYNC_MSGS+2), (MPM_OP+AMSG_OUT+0x02  ));
+   WRW_HARPOON((port+SYNC_MSGS+4), (MPM_OP+AMSG_OUT+SMWDTR));
+   WRW_HARPOON((port+SYNC_MSGS+6), (RAT_OP                ));
+   WRW_HARPOON((port+SYNC_MSGS+8),(MPM_OP+AMSG_OUT+width));
+   WRW_HARPOON((port+SYNC_MSGS+10),(BRH_OP+ALWAYS+NP      ));
+   SGRAM_ACCESS(port);
+
+   WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT_1);
+
+   WR_HARPOON(port+hp_autostart_3, (AUTO_IMMED+CMD_ONLY_STRT));
+
+   while (!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | AUTO_INT))) {}
+}
+
+#endif
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sssyncv
+ *
+ * Description: Write the desired value to the Sync Register for the
+ *              ID specified.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void sssyncv(USHORT p_port, UCHAR p_id, UCHAR p_sync_value,PSCCBMgr_tar_info currTar_Info)
+#else
+void sssyncv(ULONG p_port, UCHAR p_id, UCHAR p_sync_value,PSCCBMgr_tar_info currTar_Info)
+#endif
+{
+   UCHAR index;
+
+   index = p_id;
+
+   switch (index) {
+
+      case 0:
+	 index = 12;             /* hp_synctarg_0 */
+	 break;
+      case 1:
+	 index = 13;             /* hp_synctarg_1 */
+	 break;
+      case 2:
+	 index = 14;             /* hp_synctarg_2 */
+	 break;
+      case 3:
+	 index = 15;             /* hp_synctarg_3 */
+	 break;
+      case 4:
+	 index = 8;              /* hp_synctarg_4 */
+	 break;
+      case 5:
+	 index = 9;              /* hp_synctarg_5 */
+	 break;
+      case 6:
+	 index = 10;             /* hp_synctarg_6 */
+	 break;
+      case 7:
+	 index = 11;             /* hp_synctarg_7 */
+	 break;
+      case 8:
+	 index = 4;              /* hp_synctarg_8 */
+	 break;
+      case 9:
+	 index = 5;              /* hp_synctarg_9 */
+	 break;
+      case 10:
+	 index = 6;              /* hp_synctarg_10 */
+	 break;
+      case 11:
+	 index = 7;              /* hp_synctarg_11 */
+	 break;
+      case 12:
+	 index = 0;              /* hp_synctarg_12 */
+	 break;
+      case 13:
+	 index = 1;              /* hp_synctarg_13 */
+	 break;
+      case 14:
+	 index = 2;              /* hp_synctarg_14 */
+	 break;
+      case 15:
+	 index = 3;              /* hp_synctarg_15 */
+
+      }
+
+   WR_HARPOON(p_port+hp_synctarg_base+index, p_sync_value);
+
+	currTar_Info->TarSyncCtrl = p_sync_value;
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sresb
+ *
+ * Description: Reset the desired card's SCSI bus.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void sresb(USHORT port, UCHAR p_card)
+#else
+void sresb(ULONG port, UCHAR p_card)
+#endif
+{
+   UCHAR scsiID, i;
+
+   PSCCBMgr_tar_info currTar_Info;
+
+   WR_HARPOON(port+hp_page_ctrl,
+      (RD_HARPOON(port+hp_page_ctrl) | G_INT_DISABLE));
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT);
+
+   WR_HARPOON(port+hp_scsictrl_0, SCSI_RST);
+
+   scsiID = RD_HARPOON(port+hp_seltimeout);
+   WR_HARPOON(port+hp_seltimeout,TO_5ms);
+   WRW_HARPOON((port+hp_intstat), TIMEOUT);
+
+   WR_HARPOON(port+hp_portctrl_0,(SCSI_PORT | START_TO));
+
+   while (!(RDW_HARPOON((port+hp_intstat)) & TIMEOUT)) {}
+
+   WR_HARPOON(port+hp_seltimeout,scsiID);
+
+   WR_HARPOON(port+hp_scsictrl_0, ENA_SCAM_SEL);
+
+   Wait(port, TO_5ms);
+
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT);
+
+   WR_HARPOON(port+hp_int_mask, (RD_HARPOON(port+hp_int_mask) | 0x00));
+
+   for (scsiID = 0; scsiID < MAX_SCSI_TAR; scsiID++)
+      {
+      currTar_Info = &sccbMgrTbl[p_card][scsiID];
+
+      if (currTar_Info->TarEEValue & EE_SYNC_MASK)
+         {
+	      	currTar_Info->TarSyncCtrl = 0;
+	      	currTar_Info->TarStatus &= ~TAR_SYNC_MASK;
+	      }
+
+      if (currTar_Info->TarEEValue & EE_WIDE_SCSI)
+         {
+      	currTar_Info->TarStatus &= ~TAR_WIDE_MASK;
+      	}
+
+      sssyncv(port, scsiID, NARROW_SCSI,currTar_Info);
+
+      SccbMgrTableInitTarget(p_card, scsiID);
+      }
+
+   BL_Card[p_card].scanIndex = 0x00;
+   BL_Card[p_card].currentSCCB = NULL;
+   BL_Card[p_card].globalFlags &= ~(F_TAG_STARTED | F_HOST_XFER_ACT 
+													| F_NEW_SCCB_CMD);
+   BL_Card[p_card].cmdCounter  = 0x00;
+	BL_Card[p_card].discQCount = 0x00;
+   BL_Card[p_card].tagQ_Lst = 0x01; 
+
+	for(i = 0; i < QUEUE_DEPTH; i++)
+		BL_Card[p_card].discQ_Tbl[i] = NULL;
+
+   WR_HARPOON(port+hp_page_ctrl,
+      (RD_HARPOON(port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: ssenss
+ *
+ * Description: Setup for the Auto Sense command.
+ *
+ *---------------------------------------------------------------------*/
+void ssenss(PSCCBcard pCurrCard)
+{
+   UCHAR i;
+   PSCCB currSCCB;
+
+   currSCCB = pCurrCard->currentSCCB;
+
+
+   currSCCB->Save_CdbLen = currSCCB->CdbLength;
+
+   for (i = 0; i < 6; i++) {
+
+      currSCCB->Save_Cdb[i] = currSCCB->Cdb[i];
+      }
+
+   currSCCB->CdbLength = SIX_BYTE_CMD;
+   currSCCB->Cdb[0]    = SCSI_REQUEST_SENSE;
+   currSCCB->Cdb[1]    = currSCCB->Cdb[1] & (UCHAR)0xE0; /*Keep LUN. */
+   currSCCB->Cdb[2]    = 0x00;
+   currSCCB->Cdb[3]    = 0x00;
+   currSCCB->Cdb[4]    = currSCCB->RequestSenseLength;
+   currSCCB->Cdb[5]    = 0x00;
+
+   currSCCB->Sccb_XferCnt = (unsigned long)currSCCB->RequestSenseLength;
+
+   currSCCB->Sccb_ATC = 0x00;
+
+   currSCCB->Sccb_XferState |= F_AUTO_SENSE;
+
+   currSCCB->Sccb_XferState &= ~F_SG_XFER;
+
+   currSCCB->Sccb_idmsg = currSCCB->Sccb_idmsg & ~(UCHAR)DISC_PRIV;
+
+   currSCCB->ControlByte = 0x00;
+
+   currSCCB->Sccb_MGRFlags &= F_STATUSLOADED;
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sxfrp
+ *
+ * Description: Transfer data into the bit bucket until the device
+ *              decides to switch phase.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void sxfrp(USHORT p_port, UCHAR p_card)
+#else
+void sxfrp(ULONG p_port, UCHAR p_card)
+#endif
+{
+   UCHAR curr_phz;
+
+
+   DISABLE_AUTO(p_port);
+
+   if (BL_Card[p_card].globalFlags & F_HOST_XFER_ACT) {
+
+      hostDataXferAbort(p_port,p_card,BL_Card[p_card].currentSCCB);
+
+      }
+
+   /* If the Automation handled the end of the transfer then do not
+      match the phase or we will get out of sync with the ISR.       */
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | XFER_CNT_0 | AUTO_INT))
+      return;
+
+   WR_HARPOON(p_port+hp_xfercnt_0, 0x00);
+
+   curr_phz = RD_HARPOON(p_port+hp_scsisig) & (UCHAR)S_SCSI_PHZ;
+
+   WRW_HARPOON((p_port+hp_intstat), XFER_CNT_0);
+
+
+   WR_HARPOON(p_port+hp_scsisig, curr_phz);
+
+   while ( !(RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | RESET)) &&
+      (curr_phz == (RD_HARPOON(p_port+hp_scsisig) & (UCHAR)S_SCSI_PHZ)) )
+      {
+      if (curr_phz & (UCHAR)SCSI_IOBIT)
+         {
+      	WR_HARPOON(p_port+hp_portctrl_0, (SCSI_PORT | HOST_PORT | SCSI_INBIT));
+
+	      if (!(RD_HARPOON(p_port+hp_xferstat) & FIFO_EMPTY))
+            {
+	         RD_HARPOON(p_port+hp_fifodata_0);
+	         }
+	      }
+      else
+         {
+      	WR_HARPOON(p_port+hp_portctrl_0, (SCSI_PORT | HOST_PORT | HOST_WRT));
+   	   if (RD_HARPOON(p_port+hp_xferstat) & FIFO_EMPTY)
+            {
+	         WR_HARPOON(p_port+hp_fifodata_0,0xFA);
+	         }
+	      }
+      } /* End of While loop for padding data I/O phase */
+
+      while ( !(RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | RESET)))
+         {
+         if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+      	   break;
+         }
+
+      WR_HARPOON(p_port+hp_portctrl_0, (SCSI_PORT | HOST_PORT | SCSI_INBIT));
+      while (!(RD_HARPOON(p_port+hp_xferstat) & FIFO_EMPTY))
+         {
+         RD_HARPOON(p_port+hp_fifodata_0);
+         }
+
+      if ( !(RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | RESET)))
+         {
+         WR_HARPOON(p_port+hp_autostart_0, (AUTO_IMMED+DISCONNECT_START));
+         while (!(RDW_HARPOON((p_port+hp_intstat)) & AUTO_INT)) {}
+
+         if (RDW_HARPOON((p_port+hp_intstat)) & (ICMD_COMP | ITAR_DISC))
+   	   while (!(RDW_HARPOON((p_port+hp_intstat)) & (BUS_FREE | RSEL))) ;
+         }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: schkdd
+ *
+ * Description: Make sure data has been flushed from both FIFOs and abort
+ *              the operations if necessary.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void schkdd(USHORT port, UCHAR p_card)
+#else
+void schkdd(ULONG port, UCHAR p_card)
+#endif
+{
+   USHORT TimeOutLoop;
+	UCHAR sPhase;
+
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+
+   if ((currSCCB->Sccb_scsistat != DATA_OUT_ST) &&
+       (currSCCB->Sccb_scsistat != DATA_IN_ST)) {
+      return;
+      }
+
+
+
+   if (currSCCB->Sccb_XferState & F_ODD_BALL_CNT)
+      {
+
+      currSCCB->Sccb_ATC += (currSCCB->Sccb_XferCnt-1);
+
+      currSCCB->Sccb_XferCnt = 1;
+
+      currSCCB->Sccb_XferState &= ~F_ODD_BALL_CNT;
+      WRW_HARPOON((port+hp_fiforead), (USHORT) 0x00);
+      WR_HARPOON(port+hp_xferstat, 0x00);
+      }
+
+   else
+      {
+
+      currSCCB->Sccb_ATC += currSCCB->Sccb_XferCnt;
+
+      currSCCB->Sccb_XferCnt = 0;
+      }
+
+   if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
+      (currSCCB->HostStatus == SCCB_COMPLETE)) {
+
+      currSCCB->HostStatus = SCCB_PARITY_ERR;
+      WRW_HARPOON((port+hp_intstat), PARITY);
+      }
+
+
+   hostDataXferAbort(port,p_card,currSCCB);
+
+
+   while (RD_HARPOON(port+hp_scsisig) & SCSI_ACK) {}
+
+   TimeOutLoop = 0;
+
+   while(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY)
+      {
+      if (RDW_HARPOON((port+hp_intstat)) & BUS_FREE) {
+	      return;
+   	   }
+      if (RD_HARPOON(port+hp_offsetctr) & (UCHAR)0x1F) {
+	      break;
+   	   }
+      if (RDW_HARPOON((port+hp_intstat)) & RESET) {
+	      return;
+   	   }
+      if ((RD_HARPOON(port+hp_scsisig) & SCSI_REQ) || (TimeOutLoop++>0x3000) )
+   	   break;
+      }
+
+	sPhase = RD_HARPOON(port+hp_scsisig) & (SCSI_BSY | S_SCSI_PHZ);
+   if ((!(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY))                     ||
+      (RD_HARPOON(port+hp_offsetctr) & (UCHAR)0x1F)                       ||
+      (sPhase == (SCSI_BSY | S_DATAO_PH)) ||
+      (sPhase == (SCSI_BSY | S_DATAI_PH)))
+      {
+
+	   WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+
+	   if (!(currSCCB->Sccb_XferState & F_ALL_XFERRED))
+         {
+	      if (currSCCB->Sccb_XferState & F_HOST_XFER_DIR) {
+	         phaseDataIn(port,p_card);
+	      	}
+
+	   	else {
+	       phaseDataOut(port,p_card);
+	       	}
+	   	}
+		else
+      	{
+	   	sxfrp(port,p_card);
+	   	if (!(RDW_HARPOON((port+hp_intstat)) &
+		      (BUS_FREE | ICMD_COMP | ITAR_DISC | RESET)))
+         {
+   		WRW_HARPOON((port+hp_intstat), AUTO_INT);
+		   phaseDecode(port,p_card);
+		   }
+	   }
+
+   }
+
+   else {
+      WR_HARPOON(port+hp_portctrl_0, 0x00);
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sinits
+ *
+ * Description: Setup SCCB manager fields in this SCCB.
+ *
+ *---------------------------------------------------------------------*/
+
+void sinits(PSCCB p_sccb, UCHAR p_card)
+{
+   PSCCBMgr_tar_info currTar_Info;
+
+	if((p_sccb->TargID > MAX_SCSI_TAR) || (p_sccb->Lun > MAX_LUN))
+	{
+		return;
+	}
+   currTar_Info = &sccbMgrTbl[p_card][p_sccb->TargID];
+
+   p_sccb->Sccb_XferState     = 0x00;
+   p_sccb->Sccb_XferCnt       = p_sccb->DataLength;
+
+   if ((p_sccb->OperationCode == SCATTER_GATHER_COMMAND) ||
+      (p_sccb->OperationCode == RESIDUAL_SG_COMMAND)) {
+
+      p_sccb->Sccb_SGoffset   = 0;
+      p_sccb->Sccb_XferState  = F_SG_XFER;
+      p_sccb->Sccb_XferCnt    = 0x00;
+      }
+
+   if (p_sccb->DataLength == 0x00)
+
+      p_sccb->Sccb_XferState |= F_ALL_XFERRED;
+
+   if (p_sccb->ControlByte & F_USE_CMD_Q)
+      {
+      if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_REJECT)
+         p_sccb->ControlByte &= ~F_USE_CMD_Q;
+
+      else
+	      currTar_Info->TarStatus |= TAG_Q_TRYING;
+      }
+
+/*      For !single SCSI device in system  & device allow Disconnect
+	or command is tag_q type then send Cmd with Disconnect Enable
+	else send Cmd with Disconnect Disable */
+
+/*
+   if (((!(BL_Card[p_card].globalFlags & F_SINGLE_DEVICE)) &&
+      (currTar_Info->TarStatus & TAR_ALLOW_DISC)) ||
+      (currTar_Info->TarStatus & TAG_Q_TRYING)) {
+*/
+   if ((currTar_Info->TarStatus & TAR_ALLOW_DISC) ||
+      (currTar_Info->TarStatus & TAG_Q_TRYING)) {
+      p_sccb->Sccb_idmsg      = (UCHAR)(SMIDENT | DISC_PRIV) | p_sccb->Lun;
+      }
+
+   else {
+
+      p_sccb->Sccb_idmsg      = (UCHAR)SMIDENT | p_sccb->Lun;
+      }
+
+   p_sccb->HostStatus         = 0x00;
+   p_sccb->TargetStatus       = 0x00;
+   p_sccb->Sccb_tag           = 0x00;
+   p_sccb->Sccb_MGRFlags      = 0x00;
+   p_sccb->Sccb_sgseg         = 0x00;
+   p_sccb->Sccb_ATC           = 0x00;
+   p_sccb->Sccb_savedATC      = 0x00;
+/*
+   p_sccb->SccbVirtDataPtr    = 0x00;
+   p_sccb->Sccb_forwardlink   = NULL;
+   p_sccb->Sccb_backlink      = NULL;
+ */
+   p_sccb->Sccb_scsistat      = BUS_FREE_ST;
+   p_sccb->SccbStatus         = SCCB_IN_PROCESS;
+   p_sccb->Sccb_scsimsg       = SMNO_OP;
+
+}
+
+
+#ident "$Id: phase.c 1.11 1997/01/31 02:08:49 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   phase.c  $
+ *
+ *   Description:  Functions to initially handle the SCSI bus phase when
+ *                 the target asserts request (and the automation is not
+ *                 enabled to handle the situation).
+ *
+ *   $Date: 1997/01/31 02:08:49 $
+ *
+ *   $Revision: 1.11 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <harpoon.h>*/
+
+
+/*
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+
+#if defined(OS2)
+   extern void (far *s_PhaseTbl[8]) (ULONG, UCHAR);
+#else
+   #if defined(DOS)
+      extern void (*s_PhaseTbl[8]) (USHORT, UCHAR);
+   #else
+      extern void (*s_PhaseTbl[8]) (ULONG, UCHAR);
+   #endif
+#endif
+*/
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Phase Decode
+ *
+ * Description: Determine the phase and call the appropriate function.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void phaseDecode(USHORT p_port, UCHAR p_card)
+#else
+void phaseDecode(ULONG p_port, UCHAR p_card)
+#endif
+{
+   unsigned char phase_ref;
+#if defined(OS2)
+   void (far *phase) (ULONG, UCHAR);
+#else
+   #if defined(DOS)
+      void (*phase) (USHORT, UCHAR);
+   #else
+      void (*phase) (ULONG, UCHAR);
+   #endif
+#endif
+
+
+   DISABLE_AUTO(p_port);
+
+   phase_ref = (UCHAR) (RD_HARPOON(p_port+hp_scsisig) & S_SCSI_PHZ);
+
+   phase = s_PhaseTbl[phase_ref];
+
+   (*phase)(p_port, p_card);           /* Call the correct phase func */
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Data Out Phase
+ *
+ * Description: Start up both the BusMaster and Xbow.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseDataOut(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseDataOut(USHORT port, UCHAR p_card)
+#else
+void phaseDataOut(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+   if (currSCCB == NULL)
+      {
+      return;  /* Exit if No SCCB record */
+      }
+
+   currSCCB->Sccb_scsistat = DATA_OUT_ST;
+   currSCCB->Sccb_XferState &= ~(F_HOST_XFER_DIR | F_NO_DATA_YET);
+
+   WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+
+   WRW_HARPOON((port+hp_intstat), XFER_CNT_0);
+
+   WR_HARPOON(port+hp_autostart_0, (END_DATA+END_DATA_START));
+
+   dataXferProcessor(port, &BL_Card[p_card]);
+
+#if defined(NOBUGBUG)
+   if (RDW_HARPOON((port+hp_intstat)) & XFER_CNT_0)
+      WRW_HARPOON((port+hp_intstat), XFER_CNT_0);
+
+#endif
+
+
+   if (currSCCB->Sccb_XferCnt == 0) {
+
+
+      if ((currSCCB->ControlByte & SCCB_DATA_XFER_OUT) &&
+	 (currSCCB->HostStatus == SCCB_COMPLETE))
+	 currSCCB->HostStatus = SCCB_DATA_OVER_RUN;
+
+      sxfrp(port,p_card);
+      if (!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | RESET)))
+	    phaseDecode(port,p_card);
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Data In Phase
+ *
+ * Description: Startup the BusMaster and the XBOW.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseDataIn(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseDataIn(USHORT port, UCHAR p_card)
+#else
+void phaseDataIn(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   if (currSCCB == NULL)
+      {
+      return;  /* Exit if No SCCB record */
+      }
+
+
+   currSCCB->Sccb_scsistat = DATA_IN_ST;
+   currSCCB->Sccb_XferState |= F_HOST_XFER_DIR;
+   currSCCB->Sccb_XferState &= ~F_NO_DATA_YET;
+
+   WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
+
+   WRW_HARPOON((port+hp_intstat), XFER_CNT_0);
+
+   WR_HARPOON(port+hp_autostart_0, (END_DATA+END_DATA_START));
+
+   dataXferProcessor(port, &BL_Card[p_card]);
+
+   if (currSCCB->Sccb_XferCnt == 0) {
+
+
+      if ((currSCCB->ControlByte & SCCB_DATA_XFER_IN) &&
+	 (currSCCB->HostStatus == SCCB_COMPLETE))
+	 currSCCB->HostStatus = SCCB_DATA_OVER_RUN;
+
+      sxfrp(port,p_card);
+      if (!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | RESET)))
+	    phaseDecode(port,p_card);
+
+      }
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Command Phase
+ *
+ * Description: Load the CDB into the automation and start it up.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseCommand(ULONG p_port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseCommand(USHORT p_port, UCHAR p_card)
+#else
+void phaseCommand(ULONG p_port, UCHAR p_card)
+#endif
+#endif
+{
+   PSCCB currSCCB;
+#if defined(DOS)
+   USHORT cdb_reg;
+#else
+   ULONG cdb_reg;
+#endif
+   UCHAR i;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   if (currSCCB->OperationCode == RESET_COMMAND) {
+
+      currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
+      currSCCB->CdbLength = SIX_BYTE_CMD;
+      }
+
+   WR_HARPOON(p_port+hp_scsisig, 0x00);
+
+   ARAM_ACCESS(p_port);
+
+
+   cdb_reg = p_port + CMD_STRT;
+
+   for (i=0; i < currSCCB->CdbLength; i++) {
+
+      if (currSCCB->OperationCode == RESET_COMMAND)
+
+	 WRW_HARPOON(cdb_reg, (MPM_OP + ACOMMAND + 0x00));
+
+      else
+	 WRW_HARPOON(cdb_reg, (MPM_OP + ACOMMAND + currSCCB->Cdb[i]));
+      cdb_reg +=2;
+      }
+
+   if (currSCCB->CdbLength != TWELVE_BYTE_CMD)
+      WRW_HARPOON(cdb_reg, (BRH_OP+ALWAYS+    NP));
+
+   WR_HARPOON(p_port+hp_portctrl_0,(SCSI_PORT));
+
+   currSCCB->Sccb_scsistat = COMMAND_ST;
+
+   WR_HARPOON(p_port+hp_autostart_3, (AUTO_IMMED | CMD_ONLY_STRT));
+   SGRAM_ACCESS(p_port);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Status phase
+ *
+ * Description: Bring in the status and command complete message bytes
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseStatus(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseStatus(USHORT port, UCHAR p_card)
+#else
+void phaseStatus(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+   /* Start-up the automation to finish off this command and let the
+      isr handle the interrupt for command complete when it comes in.
+      We could wait here for the interrupt to be generated?
+    */
+
+   WR_HARPOON(port+hp_scsisig, 0x00);
+
+   WR_HARPOON(port+hp_autostart_0, (AUTO_IMMED+END_DATA_START));
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Phase Message Out
+ *
+ * Description: Send out our message (if we have one) and handle whatever
+ *              else is involed.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseMsgOut(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseMsgOut(USHORT port, UCHAR p_card)
+#else
+void phaseMsgOut(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+	UCHAR message,scsiID;
+	PSCCB currSCCB;
+	PSCCBMgr_tar_info currTar_Info;
+
+	currSCCB = BL_Card[p_card].currentSCCB;
+
+	if (currSCCB != NULL) {
+
+		message = currSCCB->Sccb_scsimsg;
+		scsiID = currSCCB->TargID;
+
+		if (message == SMDEV_RESET) 
+		{
+
+
+			currTar_Info = &sccbMgrTbl[p_card][scsiID];
+			currTar_Info->TarSyncCtrl = 0;
+			sssyncv(port, scsiID, NARROW_SCSI,currTar_Info);
+
+			if (sccbMgrTbl[p_card][scsiID].TarEEValue & EE_SYNC_MASK) 
+			{
+
+				sccbMgrTbl[p_card][scsiID].TarStatus &= ~TAR_SYNC_MASK;
+
+			}
+
+			if (sccbMgrTbl[p_card][scsiID].TarEEValue & EE_WIDE_SCSI) 
+			{
+
+				sccbMgrTbl[p_card][scsiID].TarStatus &= ~TAR_WIDE_MASK;
+			}
+
+
+			queueFlushSccb(p_card,SCCB_COMPLETE);
+			SccbMgrTableInitTarget(p_card,scsiID);
+		}
+		else if (currSCCB->Sccb_scsistat == ABORT_ST)
+		{
+			currSCCB->HostStatus = SCCB_COMPLETE;
+			if(BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] != NULL)
+			{
+				BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+				sccbMgrTbl[p_card][scsiID].TarTagQ_Cnt--;
+			}
+					
+		}
+
+		else if (currSCCB->Sccb_scsistat < COMMAND_ST) 
+		{
+
+
+			if(message == SMNO_OP)
+			{
+				currSCCB->Sccb_MGRFlags |= F_DEV_SELECTED;
+		
+				ssel(port,p_card);
+				return;
+			}
+		}
+		else 
+		{
+
+
+			if (message == SMABORT)
+
+				queueFlushSccb(p_card,SCCB_COMPLETE);
+		}
+
+	}
+	else 
+	{
+		message = SMABORT;
+	}
+
+	WRW_HARPOON((port+hp_intstat), (BUS_FREE | PHASE | XFER_CNT_0));
+
+
+	WR_HARPOON(port+hp_portctrl_0, SCSI_BUS_EN);
+
+	WR_HARPOON(port+hp_scsidata_0,message);
+
+	WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+
+	ACCEPT_MSG(port);
+
+	WR_HARPOON(port+hp_portctrl_0, 0x00);
+
+	if ((message == SMABORT) || (message == SMDEV_RESET) || 
+				(message == SMABORT_TAG) ) 
+	{
+
+		while(!(RDW_HARPOON((port+hp_intstat)) & (BUS_FREE | PHASE))) {}
+
+		if (RDW_HARPOON((port+hp_intstat)) & BUS_FREE) 
+		{
+			WRW_HARPOON((port+hp_intstat), BUS_FREE);
+
+			if (currSCCB != NULL) 
+			{
+
+				if((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+					((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+					sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = FALSE;
+				else
+					sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = FALSE;
+
+				queueCmdComplete(&BL_Card[p_card],currSCCB, p_card);
+			}
+
+			else 
+			{
+				BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+			}
+		}
+
+		else 
+		{
+
+			sxfrp(port,p_card);
+		}
+	}
+
+	else 
+	{
+
+		if(message == SMPARITY)
+		{
+			currSCCB->Sccb_scsimsg = SMNO_OP;
+			WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		}
+		else
+		{
+			sxfrp(port,p_card);
+		}
+	}
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Message In phase
+ *
+ * Description: Bring in the message and determine what to do with it.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseMsgIn(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseMsgIn(USHORT port, UCHAR p_card)
+#else
+void phaseMsgIn(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+	UCHAR message;
+	PSCCB currSCCB;
+
+	currSCCB = BL_Card[p_card].currentSCCB;
+
+	if (BL_Card[p_card].globalFlags & F_HOST_XFER_ACT) 
+	{
+
+		phaseChkFifo(port, p_card);
+	}
+
+	message = RD_HARPOON(port+hp_scsidata_0);
+	if ((message == SMDISC) || (message == SMSAVE_DATA_PTR)) 
+	{
+
+		WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+END_DATA_START));
+
+	}
+
+	else 
+	{
+
+		message = sfm(port,currSCCB);
+		if (message) 
+		{
+
+
+			sdecm(message,port,p_card);
+
+		}
+		else
+		{
+			if(currSCCB->Sccb_scsimsg != SMPARITY)
+				ACCEPT_MSG(port);
+			WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
+		}
+	}
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Illegal phase
+ *
+ * Description: Target switched to some illegal phase, so all we can do
+ *              is report an error back to the host (if that is possible)
+ *              and send an ABORT message to the misbehaving target.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(OS2)
+void far phaseIllegal(ULONG port, UCHAR p_card)
+#else
+#if defined(DOS)
+void phaseIllegal(USHORT port, UCHAR p_card)
+#else
+void phaseIllegal(ULONG port, UCHAR p_card)
+#endif
+#endif
+{
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   WR_HARPOON(port+hp_scsisig, RD_HARPOON(port+hp_scsisig));
+   if (currSCCB != NULL) {
+
+      currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
+      currSCCB->Sccb_scsistat = ABORT_ST;
+      currSCCB->Sccb_scsimsg = SMABORT;
+      }
+
+   ACCEPT_MSG_ATN(port);
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Phase Check FIFO
+ *
+ * Description: Make sure data has been flushed from both FIFOs and abort
+ *              the operations if necessary.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void phaseChkFifo(USHORT port, UCHAR p_card)
+#else
+void phaseChkFifo(ULONG port, UCHAR p_card)
+#endif
+{
+   ULONG xfercnt;
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   if (currSCCB->Sccb_scsistat == DATA_IN_ST)
+      {
+
+      while((!(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY)) &&
+	      (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY)) {}
+
+
+      if (!(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY))
+         {
+	      currSCCB->Sccb_ATC += currSCCB->Sccb_XferCnt;
+
+	      currSCCB->Sccb_XferCnt = 0;
+
+	      if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
+	            (currSCCB->HostStatus == SCCB_COMPLETE))
+            {
+	         currSCCB->HostStatus = SCCB_PARITY_ERR;
+	         WRW_HARPOON((port+hp_intstat), PARITY);
+	         }
+
+	      hostDataXferAbort(port,p_card,currSCCB);
+
+	      dataXferProcessor(port, &BL_Card[p_card]);
+
+	      while((!(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY)) &&
+	         (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY)) {}
+
+	      }
+      }  /*End Data In specific code. */
+
+
+
+#if defined(DOS)
+   asm { mov dx,port;
+      add dx,hp_xfercnt_2;
+      in  al,dx;
+      dec dx;
+      xor ah,ah;
+      mov word ptr xfercnt+2,ax;
+      in  al,dx;
+      dec dx;
+      mov ah,al;
+      in  al,dx;
+      mov word ptr xfercnt,ax;
+      }
+#else
+   GET_XFER_CNT(port,xfercnt);
+#endif
+
+
+   WR_HARPOON(port+hp_xfercnt_0, 0x00);
+
+
+   WR_HARPOON(port+hp_portctrl_0, 0x00);
+
+   currSCCB->Sccb_ATC += (currSCCB->Sccb_XferCnt - xfercnt);
+
+   currSCCB->Sccb_XferCnt = xfercnt;
+
+   if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
+      (currSCCB->HostStatus == SCCB_COMPLETE)) {
+
+      currSCCB->HostStatus = SCCB_PARITY_ERR;
+      WRW_HARPOON((port+hp_intstat), PARITY);
+      }
+
+
+   hostDataXferAbort(port,p_card,currSCCB);
+
+
+   WR_HARPOON(port+hp_fifowrite, 0x00);
+   WR_HARPOON(port+hp_fiforead, 0x00);
+   WR_HARPOON(port+hp_xferstat, 0x00);
+
+   WRW_HARPOON((port+hp_intstat), XFER_CNT_0);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Phase Bus Free
+ *
+ * Description: We just went bus free so figure out if it was
+ *              because of command complete or from a disconnect.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void phaseBusFree(USHORT port, UCHAR p_card)
+#else
+void phaseBusFree(ULONG port, UCHAR p_card)
+#endif
+{
+   PSCCB currSCCB;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   if (currSCCB != NULL)
+      {
+
+      DISABLE_AUTO(port);
+
+
+      if (currSCCB->OperationCode == RESET_COMMAND)
+         {
+
+			if((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+				((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+	   		 sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = FALSE;
+			else
+		   	 sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = FALSE;
+
+	      queueCmdComplete(&BL_Card[p_card], currSCCB, p_card);
+
+	      queueSearchSelect(&BL_Card[p_card],p_card);
+
+	      }
+
+      else if(currSCCB->Sccb_scsistat == SELECT_SN_ST)
+	      {
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarStatus |=
+			         (UCHAR)SYNC_SUPPORTED;
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= ~EE_SYNC_MASK;
+	      }
+
+      else if(currSCCB->Sccb_scsistat == SELECT_WN_ST)
+	      {
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarStatus =
+		            (sccbMgrTbl[p_card][currSCCB->TargID].
+		   TarStatus & ~WIDE_ENABLED) | WIDE_NEGOCIATED;
+
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= ~EE_WIDE_SCSI;
+	      }
+
+#if !defined(DOS)
+      else if(currSCCB->Sccb_scsistat == SELECT_Q_ST)
+	      {
+	      /* Make sure this is not a phony BUS_FREE.  If we were
+	      reselected or if BUSY is NOT on then this is a
+	      valid BUS FREE.  SRR Wednesday, 5/10/1995.     */
+
+	      if ((!(RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ||
+	         (RDW_HARPOON((port+hp_intstat)) & RSEL))
+	         {
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarStatus &= ~TAR_TAG_Q_MASK;
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarStatus |= TAG_Q_REJECT;
+	         }
+
+	      else
+            {
+	         return;
+	         }
+         }
+#endif
+
+      else
+	      {
+
+	      currSCCB->Sccb_scsistat = BUS_FREE_ST;
+
+         if (!currSCCB->HostStatus)
+	         {
+	         currSCCB->HostStatus = SCCB_PHASE_SEQUENCE_FAIL;
+	         }
+
+			if((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+				((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+	   		 sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = FALSE;
+			else
+		   	 sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = FALSE;
+
+	      queueCmdComplete(&BL_Card[p_card], currSCCB, p_card);
+	      return;
+	      }
+
+
+      BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+
+      } /*end if !=null */
+}
+
+
+
+
+#ident "$Id: automate.c 1.14 1997/01/31 02:11:46 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   automate.c  $
+ *
+ *   Description:  Functions relating to programming the automation of
+ *                 the HARPOON.
+ *
+ *   $Date: 1997/01/31 02:11:46 $
+ *
+ *   $Revision: 1.14 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <harpoon.h>*/
+
+/*
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+extern SCCBCARD BL_Card[MAX_CARDS];
+*/
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Auto Load Default Map
+ *
+ * Description: Load the Automation RAM with the defualt map values.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void autoLoadDefaultMap(USHORT p_port)
+#else
+void autoLoadDefaultMap(ULONG p_port)
+#endif
+{
+#if defined(DOS)
+   USHORT map_addr;
+#else
+   ULONG map_addr;
+#endif
+
+   ARAM_ACCESS(p_port);
+   map_addr = p_port + hp_aramBase;
+
+   WRW_HARPOON(map_addr, (MPM_OP+AMSG_OUT+ 0xC0));  /*ID MESSAGE */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+AMSG_OUT+ 0x20));  /*SIMPLE TAG QUEUEING MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, RAT_OP);                   /*RESET ATTENTION */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+AMSG_OUT+ 0x00));  /*TAG ID MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 0 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 1 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 2 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 3 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 4 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 5 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 6 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 7 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 8 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 9 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 10 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MPM_OP+ACOMMAND+ 0x00));  /*CDB BYTE 11 */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPE_OP+ADATA_OUT+ DINT)); /*JUMP IF DATA OUT */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (TCB_OP+FIFO_0+ DI));     /*JUMP IF NO DATA IN FIFO */
+   map_addr +=2;                                   /*This means AYNC DATA IN */
+   WRW_HARPOON(map_addr, (SSI_OP+   SSI_IDO_STRT)); /*STOP AND INTERRUPT */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPE_OP+ADATA_IN+DINT));   /*JUMP IF NOT DATA IN PHZ */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPN_OP+AMSG_IN+  ST));    /*IF NOT MSG IN CHECK 4 DATA IN */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CRD_OP+SDATA+    0x02));  /*SAVE DATA PTR MSG? */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (BRH_OP+NOT_EQ+   DC));    /*GO CHECK FOR DISCONNECT MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MRR_OP+SDATA+    D_AR1)); /*SAVE DATA PTRS MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPN_OP+AMSG_IN+  ST));    /*IF NOT MSG IN CHECK DATA IN */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CRD_OP+SDATA+    0x04));  /*DISCONNECT MSG? */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (BRH_OP+NOT_EQ+   UNKNWN));/*UKNKNOWN MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MRR_OP+SDATA+    D_BUCKET));/*XFER DISCONNECT MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+          SSI_ITAR_DISC));/*STOP AND INTERRUPT */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPN_OP+ASTATUS+  UNKNWN));/*JUMP IF NOT STATUS PHZ. */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MRR_OP+SDATA+  D_AR0));   /*GET STATUS BYTE */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CPN_OP+AMSG_IN+  CC));    /*ERROR IF NOT MSG IN PHZ */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (CRD_OP+SDATA+    0x00));  /*CHECK FOR CMD COMPLETE MSG. */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (BRH_OP+NOT_EQ+   CC));    /*ERROR IF NOT CMD COMPLETE MSG. */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (MRR_OP+SDATA+  D_BUCKET));/*GET CMD COMPLETE MSG */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+       SSI_ICMD_COMP));/*END OF COMMAND */
+   map_addr +=2;
+
+   WRW_HARPOON(map_addr, (SSI_OP+ SSI_IUNKWN));  /*RECEIVED UNKNOWN MSG BYTE */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+ SSI_INO_CC));  /*NO COMMAND COMPLETE AFTER STATUS */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+ SSI_ITICKLE)); /*BIOS Tickled the Mgr */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+ SSI_IRFAIL));  /*EXPECTED ID/TAG MESSAGES AND */
+   map_addr +=2;                             /* DIDN'T GET ONE */
+   WRW_HARPOON(map_addr, (CRR_OP+AR3+  S_IDREG)); /* comp SCSI SEL ID & AR3*/
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (BRH_OP+EQUAL+   0x00));    /*SEL ID OK then Conti. */
+   map_addr +=2;
+   WRW_HARPOON(map_addr, (SSI_OP+ SSI_INO_CC));  /*NO COMMAND COMPLETE AFTER STATUS */
+
+
+
+   SGRAM_ACCESS(p_port);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Auto Command Complete
+ *
+ * Description: Post command back to host and find another command
+ *              to execute.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void autoCmdCmplt(USHORT p_port, UCHAR p_card)
+#else
+void autoCmdCmplt(ULONG p_port, UCHAR p_card)
+#endif
+{
+   PSCCB currSCCB;
+   UCHAR status_byte;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+
+   status_byte = RD_HARPOON(p_port+hp_gp_reg_0);
+
+   sccbMgrTbl[p_card][currSCCB->TargID].TarLUN_CA = FALSE;
+
+   if (status_byte != SSGOOD) {
+
+      if (status_byte == SSQ_FULL) {
+
+
+			if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+				((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = TRUE;
+				if(BL_Card[p_card].discQCount != 0)
+					BL_Card[p_card].discQCount--;
+				BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[currSCCB->Lun]] = NULL;
+			}
+			else
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = TRUE;
+				if(currSCCB->Sccb_tag)
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+				}else
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[0]] = NULL;
+				}
+			}
+
+         currSCCB->Sccb_MGRFlags |= F_STATUSLOADED;
+
+         queueSelectFail(&BL_Card[p_card],p_card);
+
+         return;
+         }
+
+      if(currSCCB->Sccb_scsistat == SELECT_SN_ST)
+         {
+         sccbMgrTbl[p_card][currSCCB->TargID].TarStatus |=
+            (UCHAR)SYNC_SUPPORTED;
+
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= ~EE_SYNC_MASK;
+         BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+
+			if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+				((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = TRUE;
+				if(BL_Card[p_card].discQCount != 0)
+					BL_Card[p_card].discQCount--;
+				BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[currSCCB->Lun]] = NULL;
+			}
+			else
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = TRUE;
+				if(currSCCB->Sccb_tag)
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+				}else
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[0]] = NULL;
+				}
+			}
+         return;
+
+         }
+
+      if(currSCCB->Sccb_scsistat == SELECT_WN_ST)
+         {
+
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarStatus =
+	         (sccbMgrTbl[p_card][currSCCB->TargID].
+	         TarStatus & ~WIDE_ENABLED) | WIDE_NEGOCIATED;
+
+	      sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue &= ~EE_WIDE_SCSI;
+         BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+
+			if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+				((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = TRUE;
+				if(BL_Card[p_card].discQCount != 0)
+					BL_Card[p_card].discQCount--;
+				BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[currSCCB->Lun]] = NULL;
+			}
+			else
+			{
+	         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = TRUE;
+				if(currSCCB->Sccb_tag)
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+				}else
+				{
+					if(BL_Card[p_card].discQCount != 0)
+						BL_Card[p_card].discQCount--;
+					BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[0]] = NULL;
+				}
+			}
+         return;
+      
+         }
+     
+	   if (status_byte == SSCHECK) 
+		{
+			if(BL_Card[p_card].globalFlags & F_DO_RENEGO)
+			{
+				if (sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue & EE_SYNC_MASK)
+				{
+					sccbMgrTbl[p_card][currSCCB->TargID].TarStatus &= ~TAR_SYNC_MASK;
+				}
+				if (sccbMgrTbl[p_card][currSCCB->TargID].TarEEValue & EE_WIDE_SCSI)
+				{
+					sccbMgrTbl[p_card][currSCCB->TargID].TarStatus &= ~TAR_WIDE_MASK;
+				}
+			}
+		}
+
+      if (!(currSCCB->Sccb_XferState & F_AUTO_SENSE)) {
+
+         currSCCB->SccbStatus = SCCB_ERROR;
+         currSCCB->TargetStatus = status_byte;
+
+         if (status_byte == SSCHECK) {
+
+            sccbMgrTbl[p_card][currSCCB->TargID].TarLUN_CA
+               = TRUE;
+     
+
+#if (FW_TYPE==_SCCB_MGR_)
+            if (currSCCB->RequestSenseLength != NO_AUTO_REQUEST_SENSE) {
+
+               if (currSCCB->RequestSenseLength == 0)
+                  currSCCB->RequestSenseLength = 14;
+
+               ssenss(&BL_Card[p_card]);
+               BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+
+ 					if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+						((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+					{
+			         sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = TRUE;
+						if(BL_Card[p_card].discQCount != 0)
+							BL_Card[p_card].discQCount--;
+						BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[currSCCB->Lun]] = NULL;
+					}
+					else
+					{
+	   		      sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = TRUE;
+						if(currSCCB->Sccb_tag)
+						{
+							if(BL_Card[p_card].discQCount != 0)
+								BL_Card[p_card].discQCount--;
+							BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+						}else
+						{
+							if(BL_Card[p_card].discQCount != 0)
+								BL_Card[p_card].discQCount--;
+							BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[0]] = NULL;
+						}
+					}
+               return;
+               }
+#else
+				   if ((!(currSCCB->Sccb_ucb_ptr->UCB_opcode & OPC_NO_AUTO_SENSE)) &&
+			   		(currSCCB->RequestSenseLength))
+				   {
+				   	ssenss(&BL_Card[p_card]);
+				      BL_Card[p_card].globalFlags |= F_NEW_SCCB_CMD;
+
+						if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+							((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+						{
+	      			   sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = TRUE;
+							if(BL_Card[p_card].discQCount != 0)
+								BL_Card[p_card].discQCount--;
+							BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[currSCCB->Lun]] = NULL;
+						}
+						else
+						{
+	      			   sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = TRUE;
+							if(currSCCB->Sccb_tag)
+							{
+								if(BL_Card[p_card].discQCount != 0)
+									BL_Card[p_card].discQCount--;
+								BL_Card[p_card].discQ_Tbl[currSCCB->Sccb_tag] = NULL;
+							}else
+							{
+								if(BL_Card[p_card].discQCount != 0)
+									BL_Card[p_card].discQCount--;
+								BL_Card[p_card].discQ_Tbl[sccbMgrTbl[p_card][currSCCB->TargID].LunDiscQ_Idx[0]] = NULL;
+							}
+						}
+				      return;
+				   }
+
+#endif
+            }
+         }
+      }
+
+
+	if((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+		((sccbMgrTbl[p_card][currSCCB->TargID].TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+	   sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[currSCCB->Lun] = FALSE;
+	else
+	   sccbMgrTbl[p_card][currSCCB->TargID].TarLUNBusy[0] = FALSE;
+
+
+   queueCmdComplete(&BL_Card[p_card], currSCCB, p_card);
+}
+#ident "$Id: busmstr.c 1.8 1997/01/31 02:10:27 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   busmstr.c  $
+ *
+ *   Description:  Functions to start, stop, and abort BusMaster operations.
+ *
+ *   $Date: 1997/01/31 02:10:27 $
+ *
+ *   $Revision: 1.8 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <harpoon.h>*/
+
+
+/*
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+*/
+
+#define SHORT_WAIT   0x0000000F
+#define LONG_WAIT    0x0000FFFFL
+
+#if defined(BUGBUG)
+void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
+#endif
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Data Transfer Processor
+ *
+ * Description: This routine performs two tasks.
+ *              (1) Start data transfer by calling HOST_DATA_XFER_START
+ *              function.  Once data transfer is started, (2) Depends
+ *              on the type of data transfer mode Scatter/Gather mode
+ *              or NON Scatter/Gather mode.  In NON Scatter/Gather mode,
+ *              this routine checks Sccb_MGRFlag (F_HOST_XFER_ACT bit) for
+ *              data transfer done.  In Scatter/Gather mode, this routine
+ *              checks bus master command complete and dual rank busy
+ *              bit to keep chaining SC transfer command.  Similarly,
+ *              in Scatter/Gather mode, it checks Sccb_MGRFlag
+ *              (F_HOST_XFER_ACT bit) for data transfer done.
+ *              
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void dataXferProcessor(USHORT port, PSCCBcard pCurrCard)
+#else
+void dataXferProcessor(ULONG port, PSCCBcard pCurrCard)
+#endif
+{
+   PSCCB currSCCB;
+
+   currSCCB = pCurrCard->currentSCCB;
+
+      if (currSCCB->Sccb_XferState & F_SG_XFER)
+			{
+			if (pCurrCard->globalFlags & F_HOST_XFER_ACT)
+
+				{
+		   	currSCCB->Sccb_sgseg += (UCHAR)SG_BUF_CNT;
+         	currSCCB->Sccb_SGoffset = 0x00; 
+ 				}
+			pCurrCard->globalFlags |= F_HOST_XFER_ACT;
+         
+         busMstrSGDataXferStart(port, currSCCB);
+			}
+
+      else
+			{
+			if (!(pCurrCard->globalFlags & F_HOST_XFER_ACT))
+				{
+				pCurrCard->globalFlags |= F_HOST_XFER_ACT;
+         
+         	busMstrDataXferStart(port, currSCCB);
+         	}
+			}
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: BusMaster Scatter Gather Data Transfer Start
+ *
+ * Description:
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void busMstrSGDataXferStart(USHORT p_port, PSCCB pcurrSCCB)
+#else
+void busMstrSGDataXferStart(ULONG p_port, PSCCB pcurrSCCB)
+#endif
+{
+   ULONG count,addr,tmpSGCnt;
+   UINT sg_index;
+   UCHAR sg_count, i;
+#if defined(DOS)
+   USHORT reg_offset;
+#else
+   ULONG reg_offset;
+#endif
+
+
+   if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) {
+
+      count =  ((ULONG) HOST_RD_CMD)<<24;
+      }
+
+   else {
+      count =  ((ULONG) HOST_WRT_CMD)<<24;
+      }
+
+   sg_count = 0;
+   tmpSGCnt = 0;
+   sg_index = pcurrSCCB->Sccb_sgseg;
+   reg_offset = hp_aramBase;
+
+
+	i = (UCHAR) (RD_HARPOON(p_port+hp_page_ctrl) & ~(SGRAM_ARAM|SCATTER_EN));
+
+
+	WR_HARPOON(p_port+hp_page_ctrl, i);
+
+   while ((sg_count < (UCHAR)SG_BUF_CNT) &&
+      ((ULONG)(sg_index * (UINT)SG_ELEMENT_SIZE) < pcurrSCCB->DataLength) ) {
+
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+      tmpSGCnt += *(((ULONG far *)pcurrSCCB->DataPointer)+
+         (sg_index * 2));
+
+      count |= *(((ULONG far *)pcurrSCCB->DataPointer)+
+         (sg_index * 2));
+
+      addr = *(((ULONG far *)pcurrSCCB->DataPointer)+
+         ((sg_index * 2) + 1));
+
+#else
+      tmpSGCnt += *(((ULONG *)pcurrSCCB->DataPointer)+
+         (sg_index * 2));
+
+      count |= *(((ULONG *)pcurrSCCB->DataPointer)+
+         (sg_index * 2));
+
+      addr = *(((ULONG *)pcurrSCCB->DataPointer)+
+         ((sg_index * 2) + 1));
+#endif
+
+
+      if ((!sg_count) && (pcurrSCCB->Sccb_SGoffset)) {
+
+         addr += ((count & 0x00FFFFFFL) - pcurrSCCB->Sccb_SGoffset);
+         count = (count & 0xFF000000L) | pcurrSCCB->Sccb_SGoffset;
+
+         tmpSGCnt = count & 0x00FFFFFFL;
+         }
+
+      WR_HARP32(p_port,reg_offset,addr);
+      reg_offset +=4;
+
+      WR_HARP32(p_port,reg_offset,count);
+      reg_offset +=4;
+
+      count &= 0xFF000000L;
+      sg_index++;
+      sg_count++;
+
+      } /*End While */
+
+   pcurrSCCB->Sccb_XferCnt = tmpSGCnt;
+
+   WR_HARPOON(p_port+hp_sg_addr,(sg_count<<4));
+
+   if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) {
+
+      WR_HARP32(p_port,hp_xfercnt_0,tmpSGCnt);
+
+
+      WR_HARPOON(p_port+hp_portctrl_0,(DMA_PORT | SCSI_PORT | SCSI_INBIT));
+      WR_HARPOON(p_port+hp_scsisig, S_DATAI_PH);
+      }
+
+   else {
+
+
+      if ((!(RD_HARPOON(p_port+hp_synctarg_0) & NARROW_SCSI)) &&
+         (tmpSGCnt & 0x000000001))
+         {
+
+         pcurrSCCB->Sccb_XferState |= F_ODD_BALL_CNT;
+         tmpSGCnt--;
+         }
+
+
+      WR_HARP32(p_port,hp_xfercnt_0,tmpSGCnt);
+
+      WR_HARPOON(p_port+hp_portctrl_0,(SCSI_PORT | DMA_PORT | DMA_RD));
+      WR_HARPOON(p_port+hp_scsisig, S_DATAO_PH);
+      }
+
+
+   WR_HARPOON(p_port+hp_page_ctrl, (UCHAR) (i | SCATTER_EN));
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: BusMaster Data Transfer Start
+ *
+ * Description: 
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void busMstrDataXferStart(USHORT p_port, PSCCB pcurrSCCB)
+#else
+void busMstrDataXferStart(ULONG p_port, PSCCB pcurrSCCB)
+#endif
+{
+   ULONG addr,count;
+
+   if (!(pcurrSCCB->Sccb_XferState & F_AUTO_SENSE)) {
+
+      count = pcurrSCCB->Sccb_XferCnt;
+
+      addr = (ULONG) pcurrSCCB->DataPointer + pcurrSCCB->Sccb_ATC;
+      }
+
+   else {
+      addr = pcurrSCCB->SensePointer;
+      count = pcurrSCCB->RequestSenseLength;
+
+      }
+
+#if defined(DOS)
+   asm { mov dx,p_port;
+         mov ax,word ptr count;
+         add dx,hp_xfer_cnt_lo;
+         out dx,al;
+         inc dx;
+         xchg ah,al
+         out dx,al;
+         inc dx;
+         mov ax,word ptr count+2;
+         out dx,al;
+         inc dx;
+         inc dx;
+         mov ax,word ptr addr;
+         out dx,al;
+         inc dx;
+         xchg ah,al
+         out dx,al;
+         inc dx;
+         mov ax,word ptr addr+2;
+         out dx,al;
+         inc dx;
+         xchg ah,al
+         out dx,al;
+         }
+
+   WR_HARP32(p_port,hp_xfercnt_0,count);
+
+#else
+   HP_SETUP_ADDR_CNT(p_port,addr,count);
+#endif
+
+
+   if (pcurrSCCB->Sccb_XferState & F_HOST_XFER_DIR) {
+
+      WR_HARPOON(p_port+hp_portctrl_0,(DMA_PORT | SCSI_PORT | SCSI_INBIT));
+      WR_HARPOON(p_port+hp_scsisig, S_DATAI_PH);
+
+      WR_HARPOON(p_port+hp_xfer_cmd,
+         (XFER_DMA_HOST | XFER_HOST_AUTO | XFER_DMA_8BIT));
+      }
+
+   else {
+
+      WR_HARPOON(p_port+hp_portctrl_0,(SCSI_PORT | DMA_PORT | DMA_RD));
+      WR_HARPOON(p_port+hp_scsisig, S_DATAO_PH);
+
+      WR_HARPOON(p_port+hp_xfer_cmd,
+         (XFER_HOST_DMA | XFER_HOST_AUTO | XFER_DMA_8BIT));
+
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: BusMaster Timeout Handler
+ *
+ * Description: This function is called after a bus master command busy time
+ *               out is detected.  This routines issue halt state machine
+ *               with a software time out for command busy.  If command busy
+ *               is still asserted at the end of the time out, it issues
+ *               hard abort with another software time out.  It hard abort
+ *               command busy is also time out, it'll just give up.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+UCHAR busMstrTimeOut(USHORT p_port)
+#else
+UCHAR busMstrTimeOut(ULONG p_port)
+#endif
+{
+   ULONG timeout;
+
+   timeout = LONG_WAIT;
+
+   WR_HARPOON(p_port+hp_sys_ctrl, HALT_MACH);
+
+   while ((!(RD_HARPOON(p_port+hp_ext_status) & CMD_ABORTED)) && timeout--) {}
+
+   
+   
+   if (RD_HARPOON(p_port+hp_ext_status) & BM_CMD_BUSY) {
+      WR_HARPOON(p_port+hp_sys_ctrl, HARD_ABORT);
+
+      timeout = LONG_WAIT;
+      while ((RD_HARPOON(p_port+hp_ext_status) & BM_CMD_BUSY) && timeout--) {}
+      }
+
+   RD_HARPOON(p_port+hp_int_status);           /*Clear command complete */
+
+   if (RD_HARPOON(p_port+hp_ext_status) & BM_CMD_BUSY) {
+      return(TRUE);
+      }
+
+   else {
+      return(FALSE);
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Host Data Transfer Abort
+ *
+ * Description: Abort any in progress transfer.
+ *
+ *---------------------------------------------------------------------*/
+#if defined(DOS)
+void hostDataXferAbort(USHORT port, UCHAR p_card, PSCCB pCurrSCCB)
+#else
+void hostDataXferAbort(ULONG port, UCHAR p_card, PSCCB pCurrSCCB)
+#endif
+{
+
+   ULONG timeout;
+   ULONG remain_cnt;
+   UINT sg_ptr;
+
+   BL_Card[p_card].globalFlags &= ~F_HOST_XFER_ACT;
+
+   if (pCurrSCCB->Sccb_XferState & F_AUTO_SENSE) {
+
+
+      if (!(RD_HARPOON(port+hp_int_status) & INT_CMD_COMPL)) {
+
+         WR_HARPOON(port+hp_bm_ctrl, (RD_HARPOON(port+hp_bm_ctrl) | FLUSH_XFER_CNTR));
+         timeout = LONG_WAIT;
+
+         while ((RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) && timeout--) {}
+
+         WR_HARPOON(port+hp_bm_ctrl, (RD_HARPOON(port+hp_bm_ctrl) & ~FLUSH_XFER_CNTR));
+
+         if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+            if (busMstrTimeOut(port)) {
+
+               if (pCurrSCCB->HostStatus == 0x00)
+
+                  pCurrSCCB->HostStatus = SCCB_BM_ERR;
+
+               }
+
+            if (RD_HARPOON(port+hp_int_status) & INT_EXT_STATUS) 
+
+               if (RD_HARPOON(port+hp_ext_status) & BAD_EXT_STATUS) 
+
+                  if (pCurrSCCB->HostStatus == 0x00)
+
+                     {
+                     pCurrSCCB->HostStatus = SCCB_BM_ERR;
+#if defined(BUGBUG)
+                     WR_HARPOON(port+hp_dual_addr_lo,
+                        RD_HARPOON(port+hp_ext_status));
+#endif
+                     }
+            }
+         }
+      }
+
+   else if (pCurrSCCB->Sccb_XferCnt) {
+
+      if (pCurrSCCB->Sccb_XferState & F_SG_XFER) {
+
+
+              WR_HARPOON(port+hp_page_ctrl, (RD_HARPOON(port+hp_page_ctrl) &
+            ~SCATTER_EN));
+
+         WR_HARPOON(port+hp_sg_addr,0x00);
+
+         sg_ptr = pCurrSCCB->Sccb_sgseg + SG_BUF_CNT;
+
+         if (sg_ptr > (UINT)(pCurrSCCB->DataLength / SG_ELEMENT_SIZE)) {
+
+            sg_ptr = (UINT)(pCurrSCCB->DataLength / SG_ELEMENT_SIZE);
+            }
+
+         remain_cnt = pCurrSCCB->Sccb_XferCnt;
+
+         while (remain_cnt < 0x01000000L) {
+
+            sg_ptr--;
+
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+            if (remain_cnt > (ULONG)(*(((ULONG far *)pCurrSCCB->
+               DataPointer) + (sg_ptr * 2)))) {
+
+               remain_cnt -= (ULONG)(*(((ULONG far *)pCurrSCCB->
+                  DataPointer) + (sg_ptr * 2)));
+               }
+
+#else
+            if (remain_cnt > (ULONG)(*(((ULONG *)pCurrSCCB->
+               DataPointer) + (sg_ptr * 2)))) {
+
+               remain_cnt -= (ULONG)(*(((ULONG *)pCurrSCCB->
+                  DataPointer) + (sg_ptr * 2)));
+               }
+#endif
+
+            else {
+
+               break;
+               }
+            }
+
+
+
+         if (remain_cnt < 0x01000000L) {
+
+
+            pCurrSCCB->Sccb_SGoffset = remain_cnt;
+
+            pCurrSCCB->Sccb_sgseg = (USHORT)sg_ptr;
+
+
+            if ((ULONG)(sg_ptr * SG_ELEMENT_SIZE) == pCurrSCCB->DataLength 
+                && (remain_cnt == 0))
+
+               pCurrSCCB->Sccb_XferState |= F_ALL_XFERRED;
+            }
+
+         else {
+
+
+            if (pCurrSCCB->HostStatus == 0x00) {
+
+               pCurrSCCB->HostStatus = SCCB_GROSS_FW_ERR;
+               }
+            }
+         }
+
+
+      if (!(pCurrSCCB->Sccb_XferState & F_HOST_XFER_DIR)) {
+
+
+         if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+            busMstrTimeOut(port);
+            }
+
+         else {
+
+            if (RD_HARPOON(port+hp_int_status) & INT_EXT_STATUS) {
+
+               if (RD_HARPOON(port+hp_ext_status) & BAD_EXT_STATUS) {
+
+                  if (pCurrSCCB->HostStatus == 0x00) {
+
+                     pCurrSCCB->HostStatus = SCCB_BM_ERR;
+#if defined(BUGBUG)
+                     WR_HARPOON(port+hp_dual_addr_lo,
+                        RD_HARPOON(port+hp_ext_status));
+#endif
+                     }
+                  }
+               }
+
+            }
+         }
+
+      else {
+
+
+         if ((RD_HARPOON(port+hp_fifo_cnt)) >= BM_THRESHOLD) {
+
+            timeout = SHORT_WAIT;
+
+            while ((RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) &&
+               ((RD_HARPOON(port+hp_fifo_cnt)) >= BM_THRESHOLD) &&
+               timeout--) {}
+            }
+
+         if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+            WR_HARPOON(port+hp_bm_ctrl, (RD_HARPOON(port+hp_bm_ctrl) |
+               FLUSH_XFER_CNTR));
+
+            timeout = LONG_WAIT;
+
+            while ((RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) &&
+               timeout--) {}
+
+            WR_HARPOON(port+hp_bm_ctrl, (RD_HARPOON(port+hp_bm_ctrl) &
+               ~FLUSH_XFER_CNTR));
+
+
+            if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+               if (pCurrSCCB->HostStatus == 0x00) {
+
+                  pCurrSCCB->HostStatus = SCCB_BM_ERR;
+                  }
+
+               busMstrTimeOut(port);
+               }
+            }
+
+         if (RD_HARPOON(port+hp_int_status) & INT_EXT_STATUS) {
+
+            if (RD_HARPOON(port+hp_ext_status) & BAD_EXT_STATUS) {
+
+               if (pCurrSCCB->HostStatus == 0x00) {
+
+                  pCurrSCCB->HostStatus = SCCB_BM_ERR;
+#if defined(BUGBUG)
+                  WR_HARPOON(port+hp_dual_addr_lo,
+                     RD_HARPOON(port+hp_ext_status));
+#endif
+                  }
+               }
+            }
+         }
+
+      }
+
+   else {
+
+
+      if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+         timeout = LONG_WAIT;
+
+         while ((RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) && timeout--) {}
+
+         if (RD_HARPOON(port+hp_ext_status) & BM_CMD_BUSY) {
+
+            if (pCurrSCCB->HostStatus == 0x00) {
+
+               pCurrSCCB->HostStatus = SCCB_BM_ERR;
+               }
+
+            busMstrTimeOut(port);
+            }
+         }
+
+
+      if (RD_HARPOON(port+hp_int_status) & INT_EXT_STATUS) {
+
+         if (RD_HARPOON(port+hp_ext_status) & BAD_EXT_STATUS) {
+
+            if (pCurrSCCB->HostStatus == 0x00) {
+
+               pCurrSCCB->HostStatus = SCCB_BM_ERR;
+#if defined(BUGBUG)
+               WR_HARPOON(port+hp_dual_addr_lo,
+                  RD_HARPOON(port+hp_ext_status));
+#endif
+               }
+            }
+
+         }
+
+      if (pCurrSCCB->Sccb_XferState & F_SG_XFER) {
+
+         WR_HARPOON(port+hp_page_ctrl, (RD_HARPOON(port+hp_page_ctrl) &
+                 ~SCATTER_EN));
+
+         WR_HARPOON(port+hp_sg_addr,0x00);
+
+         pCurrSCCB->Sccb_sgseg += SG_BUF_CNT;
+
+         pCurrSCCB->Sccb_SGoffset = 0x00; 
+
+
+         if ((ULONG)(pCurrSCCB->Sccb_sgseg * SG_ELEMENT_SIZE) >=
+            pCurrSCCB->DataLength) {
+
+            pCurrSCCB->Sccb_XferState |= F_ALL_XFERRED;
+
+            pCurrSCCB->Sccb_sgseg = (USHORT)(pCurrSCCB->DataLength / SG_ELEMENT_SIZE);
+
+            }
+         }
+
+      else {
+
+         if (!(pCurrSCCB->Sccb_XferState & F_AUTO_SENSE))
+
+            pCurrSCCB->Sccb_XferState |= F_ALL_XFERRED;
+         }
+      }
+
+   WR_HARPOON(port+hp_int_mask,(INT_CMD_COMPL | SCSI_INTERRUPT));
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Host Data Transfer Restart
+ *
+ * Description: Reset the available count due to a restore data
+ *              pointers message.
+ *
+ *---------------------------------------------------------------------*/
+void hostDataXferRestart(PSCCB currSCCB)
+{
+   ULONG data_count;
+   UINT  sg_index;
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+   ULONG far *sg_ptr;
+#else
+   ULONG *sg_ptr;
+#endif
+
+   if (currSCCB->Sccb_XferState & F_SG_XFER) {
+
+      currSCCB->Sccb_XferCnt = 0;
+
+      sg_index = 0xffff;         /*Index by long words into sg list. */
+      data_count = 0;            /*Running count of SG xfer counts. */
+
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+      sg_ptr = (ULONG far *)currSCCB->DataPointer;
+#else
+      sg_ptr = (ULONG *)currSCCB->DataPointer;
+#endif
+
+      while (data_count < currSCCB->Sccb_ATC) {
+
+         sg_index++;
+         data_count += *(sg_ptr+(sg_index * 2));
+         }
+
+      if (data_count == currSCCB->Sccb_ATC) {
+
+         currSCCB->Sccb_SGoffset = 0;
+         sg_index++;
+         }
+
+      else {
+         currSCCB->Sccb_SGoffset = data_count - currSCCB->Sccb_ATC;
+         }
+
+      currSCCB->Sccb_sgseg = (USHORT)sg_index;
+      }
+
+   else {
+      currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC;
+      }
+}
+#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   scam.c  $
+ *
+ *   Description:  Functions relating to handling of the SCAM selection
+ *                 and the determination of the SCSI IDs to be assigned
+ *                 to all perspective SCSI targets.
+ *
+ *   $Date: 1997/03/20 23:49:37 $
+ *
+ *   $Revision: 1.17 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <eeprom.h>*/
+/*#include <harpoon.h>*/
+
+
+
+/*
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR];
+extern NVRAMINFO nvRamInfo[MAX_MB_CARDS];
+#if defined(DOS) || defined(OS2)
+extern UCHAR temp_id_string[ID_STRING_LENGTH];
+#endif
+extern UCHAR scamHAString[];
+*/
+/*---------------------------------------------------------------------
+ *
+ * Function: scini
+ *
+ * Description: Setup all data structures necessary for SCAM selection.
+ *
+ *---------------------------------------------------------------------*/
+
+void scini(UCHAR p_card, UCHAR p_our_id, UCHAR p_power_up)
+{
+
+#if defined(SCAM_LEV_2)
+   UCHAR loser,assigned_id;
+#endif
+#if defined(DOS)
+
+   USHORT p_port;
+#else
+   ULONG p_port;
+#endif
+
+   UCHAR i,k,ScamFlg ;
+   PSCCBcard currCard;
+	PNVRamInfo pCurrNvRam;
+
+   currCard = &BL_Card[p_card];
+   p_port = currCard->ioPort;
+	pCurrNvRam = currCard->pNvRamInfo;
+
+
+	if(pCurrNvRam){
+		ScamFlg = pCurrNvRam->niScamConf;
+		i = pCurrNvRam->niSysConf;
+	}
+	else{
+	   ScamFlg = (UCHAR) utilEERead(p_port, SCAM_CONFIG/2);
+	   i = (UCHAR)(utilEERead(p_port, (SYSTEM_CONFIG/2)));
+	}
+	if(!(i & 0x02))	/* check if reset bus in AutoSCSI parameter set */
+		return;
+
+   inisci(p_card,p_port, p_our_id);
+
+   /* Force to wait 1 sec after SCSI bus reset. Some SCAM device FW
+      too slow to return to SCAM selection */
+
+   /* if (p_power_up)
+         Wait1Second(p_port);
+      else
+         Wait(p_port, TO_250ms); */
+
+   Wait1Second(p_port);
+
+#if defined(SCAM_LEV_2)
+
+   if ((ScamFlg & SCAM_ENABLED) && (ScamFlg & SCAM_LEVEL2))
+      {
+      while (!(scarb(p_port,INIT_SELTD))) {}
+
+      scsel(p_port);
+
+      do {
+         scxferc(p_port,SYNC_PTRN);
+         scxferc(p_port,DOM_MSTR);
+         loser = scsendi(p_port,&scamInfo[p_our_id].id_string[0]);
+         } while ( loser == 0xFF );
+
+      scbusf(p_port);
+
+      if ((p_power_up) && (!loser))
+         {
+         sresb(p_port,p_card);
+         Wait(p_port, TO_250ms);
+
+         while (!(scarb(p_port,INIT_SELTD))) {}
+
+         scsel(p_port);
+
+         do {
+            scxferc(p_port, SYNC_PTRN);
+            scxferc(p_port, DOM_MSTR);
+            loser = scsendi(p_port,&scamInfo[p_our_id].
+               id_string[0]);
+            } while ( loser == 0xFF );
+
+         scbusf(p_port);
+         }
+      }
+
+   else
+      {
+      loser = FALSE;
+      }
+
+
+   if (!loser)
+      {
+
+#endif  /* SCAM_LEV_2 */
+
+      scamInfo[p_our_id].state = ID_ASSIGNED;
+
+
+		if (ScamFlg & SCAM_ENABLED)
+		{
+
+	      for (i=0; i < MAX_SCSI_TAR; i++)
+  		   {
+      	   if ((scamInfo[i].state == ID_UNASSIGNED) ||
+  	      	   (scamInfo[i].state == ID_UNUSED))
+	  	      {
+   	     	   if (scsell(p_port,i))
+      	  	   {
+            	   scamInfo[i].state = LEGACY;
+  	            	if ((scamInfo[i].id_string[0] != 0xFF) ||
+     	            	(scamInfo[i].id_string[1] != 0xFA))
+	     	         {
+
+   	        	      scamInfo[i].id_string[0] = 0xFF;
+      	        	   scamInfo[i].id_string[1] = 0xFA;
+							if(pCurrNvRam == NULL)
+	         	         currCard->globalFlags |= F_UPDATE_EEPROM;
+               	}
+	  	         }
+   	  	   }
+      	}
+
+	      sresb(p_port,p_card);
+      	Wait1Second(p_port);
+         while (!(scarb(p_port,INIT_SELTD))) {}
+         scsel(p_port);
+         scasid(p_card, p_port);
+         }
+
+#if defined(SCAM_LEV_2)
+
+      }
+
+   else if ((loser) && (ScamFlg & SCAM_ENABLED))
+      {
+      scamInfo[p_our_id].id_string[0] = SLV_TYPE_CODE0;
+      assigned_id = FALSE;
+      scwtsel(p_port);
+
+      do {
+         while (scxferc(p_port,0x00) != SYNC_PTRN) {}
+
+         i = scxferc(p_port,0x00);
+         if (i == ASSIGN_ID)
+            {
+            if (!(scsendi(p_port,&scamInfo[p_our_id].id_string[0])))
+                  {
+                  i = scxferc(p_port,0x00);
+                  if (scvalq(i))
+                     {
+                     k = scxferc(p_port,0x00);
+
+                     if (scvalq(k))
+                        {
+                        currCard->ourId =
+                           ((UCHAR)(i<<3)+(k & (UCHAR)7)) & (UCHAR) 0x3F;
+                        inisci(p_card, p_port, p_our_id);
+                        scamInfo[currCard->ourId].state = ID_ASSIGNED;
+                        scamInfo[currCard->ourId].id_string[0]
+                           = SLV_TYPE_CODE0;
+                        assigned_id = TRUE;
+                        }
+                     }
+                  }
+            }
+
+         else if (i == SET_P_FLAG)
+            {
+               if (!(scsendi(p_port,
+                        &scamInfo[p_our_id].id_string[0])))
+                        scamInfo[p_our_id].id_string[0] |= 0x80;
+            }
+         }while (!assigned_id);
+
+      while (scxferc(p_port,0x00) != CFG_CMPLT) {}
+      }
+
+#endif   /* SCAM_LEV_2 */
+   if (ScamFlg & SCAM_ENABLED)
+      {
+      scbusf(p_port);
+      if (currCard->globalFlags & F_UPDATE_EEPROM)
+         {
+         scsavdi(p_card, p_port);
+         currCard->globalFlags &= ~F_UPDATE_EEPROM;
+         }
+      }
+
+
+#if defined(DOS)
+   for (i=0; i < MAX_SCSI_TAR; i++)
+   {
+     	if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY))
+			|| (i != p_our_id))
+        	{
+         scsellDOS(p_port,i);
+  	      }
+  	}
+#endif
+
+/*
+   for (i=0,k=0; i < MAX_SCSI_TAR; i++)
+      {
+      if ((scamInfo[i].state == ID_ASSIGNED) ||
+         (scamInfo[i].state == LEGACY))
+         k++;
+      }
+
+   if (k==2)
+      currCard->globalFlags |= F_SINGLE_DEVICE;
+   else
+      currCard->globalFlags &= ~F_SINGLE_DEVICE;
+*/
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scarb
+ *
+ * Description: Gain control of the bus and wait SCAM select time (250ms)
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+int scarb(USHORT p_port, UCHAR p_sel_type)
+#else
+int scarb(ULONG p_port, UCHAR p_sel_type)
+#endif
+{
+   if (p_sel_type == INIT_SELTD)
+      {
+
+      while (RD_HARPOON(p_port+hp_scsisig) & (SCSI_SEL | SCSI_BSY)) {}
+
+
+      if (RD_HARPOON(p_port+hp_scsisig) & SCSI_SEL)
+         return(FALSE);
+
+      if (RD_HARPOON(p_port+hp_scsidata_0) != 00)
+         return(FALSE);
+
+      WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig) | SCSI_BSY));
+
+      if (RD_HARPOON(p_port+hp_scsisig) & SCSI_SEL) {
+
+         WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig) &
+            ~SCSI_BSY));
+         return(FALSE);
+         }
+
+
+      WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig) | SCSI_SEL));
+
+      if (RD_HARPOON(p_port+hp_scsidata_0) != 00) {
+
+         WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig) &
+            ~(SCSI_BSY | SCSI_SEL)));
+         return(FALSE);
+         }
+      }
+
+
+   WR_HARPOON(p_port+hp_clkctrl_0, (RD_HARPOON(p_port+hp_clkctrl_0)
+      & ~ACTdeassert));
+   WR_HARPOON(p_port+hp_scsireset, SCAM_EN);
+   WR_HARPOON(p_port+hp_scsidata_0, 0x00);
+#if defined(WIDE_SCSI)
+   WR_HARPOON(p_port+hp_scsidata_1, 0x00);
+#endif
+   WR_HARPOON(p_port+hp_portctrl_0, SCSI_BUS_EN);
+
+   WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig) | SCSI_MSG));
+
+   WR_HARPOON(p_port+hp_scsisig, (RD_HARPOON(p_port+hp_scsisig)
+      & ~SCSI_BSY));
+
+   Wait(p_port,TO_250ms);
+
+   return(TRUE);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scbusf
+ *
+ * Description: Release the SCSI bus and disable SCAM selection.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scbusf(USHORT p_port)
+#else
+void scbusf(ULONG p_port)
+#endif
+{
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+
+   WR_HARPOON(p_port+hp_scsidata_0, 0x00);
+
+   WR_HARPOON(p_port+hp_portctrl_0, (RD_HARPOON(p_port+hp_portctrl_0)
+      & ~SCSI_BUS_EN));
+
+   WR_HARPOON(p_port+hp_scsisig, 0x00);
+
+
+   WR_HARPOON(p_port+hp_scsireset,  (RD_HARPOON(p_port+hp_scsireset)
+      & ~SCAM_EN));
+
+   WR_HARPOON(p_port+hp_clkctrl_0, (RD_HARPOON(p_port+hp_clkctrl_0)
+      | ACTdeassert));
+
+#if defined(SCAM_LEV_2)
+   WRW_HARPOON((p_port+hp_intstat), (BUS_FREE | AUTO_INT | SCAM_SEL));
+#else
+   WRW_HARPOON((p_port+hp_intstat), (BUS_FREE | AUTO_INT));
+#endif
+
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scasid
+ *
+ * Description: Assign an ID to all the SCAM devices.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scasid(UCHAR p_card, USHORT p_port)
+#else
+void scasid(UCHAR p_card, ULONG p_port)
+#endif
+{
+#if defined(DOS) || defined(OS2)
+   /* Use external defined in global space area, instead of Stack
+      space. WIN/95 DOS doesnot work TINY mode. The OS doesnot intialize
+      SS equal to DS. Thus the array allocated on stack doesnot get
+      access correctly */
+#else
+   UCHAR temp_id_string[ID_STRING_LENGTH];
+#endif
+
+   UCHAR i,k,scam_id;
+	UCHAR crcBytes[3];
+	PNVRamInfo pCurrNvRam;
+	ushort_ptr pCrcBytes;
+
+	pCurrNvRam = BL_Card[p_card].pNvRamInfo;
+
+   i=FALSE;
+
+   while (!i)
+      {
+
+      for (k=0; k < ID_STRING_LENGTH; k++)
+         {
+         temp_id_string[k] = (UCHAR) 0x00;
+         }
+
+      scxferc(p_port,SYNC_PTRN);
+      scxferc(p_port,ASSIGN_ID);
+
+      if (!(sciso(p_port,&temp_id_string[0])))
+         {
+			if(pCurrNvRam){
+				pCrcBytes = (ushort_ptr)&crcBytes[0];
+				*pCrcBytes = CalcCrc16(&temp_id_string[0]);
+				crcBytes[2] = CalcLrc(&temp_id_string[0]);
+				temp_id_string[1] = crcBytes[2];
+				temp_id_string[2] = crcBytes[0];
+				temp_id_string[3] = crcBytes[1];
+				for(k = 4; k < ID_STRING_LENGTH; k++)
+					temp_id_string[k] = (UCHAR) 0x00;
+			}
+         i = scmachid(p_card,temp_id_string);
+
+         if (i == CLR_PRIORITY)
+            {
+            scxferc(p_port,MISC_CODE);
+            scxferc(p_port,CLR_P_FLAG);
+            i = FALSE;  /*Not the last ID yet. */
+            }
+
+         else if (i != NO_ID_AVAIL)
+            {
+            if (i < 8 )
+               scxferc(p_port,ID_0_7);
+            else
+               scxferc(p_port,ID_8_F);
+
+            scam_id = (i & (UCHAR) 0x07);
+
+
+            for (k=1; k < 0x08; k <<= 1)
+               if (!( k & i ))
+                  scam_id += 0x08;        /*Count number of zeros in DB0-3. */
+
+            scxferc(p_port,scam_id);
+
+            i = FALSE;  /*Not the last ID yet. */
+            }
+         }
+
+      else
+         {
+         i = TRUE;
+         }
+
+      }  /*End while */
+
+   scxferc(p_port,SYNC_PTRN);
+   scxferc(p_port,CFG_CMPLT);
+}
+
+
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scsel
+ *
+ * Description: Select all the SCAM devices.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scsel(USHORT p_port)
+#else
+void scsel(ULONG p_port)
+#endif
+{
+
+   WR_HARPOON(p_port+hp_scsisig, SCSI_SEL);
+   scwiros(p_port, SCSI_MSG);
+
+   WR_HARPOON(p_port+hp_scsisig, (SCSI_SEL | SCSI_BSY));
+
+
+   WR_HARPOON(p_port+hp_scsisig, (SCSI_SEL | SCSI_BSY | SCSI_IOBIT | SCSI_CD));
+   WR_HARPOON(p_port+hp_scsidata_0, (UCHAR)(RD_HARPOON(p_port+hp_scsidata_0) |
+      (UCHAR)(BIT(7)+BIT(6))));
+
+
+   WR_HARPOON(p_port+hp_scsisig, (SCSI_BSY | SCSI_IOBIT | SCSI_CD));
+   scwiros(p_port, SCSI_SEL);
+
+   WR_HARPOON(p_port+hp_scsidata_0, (UCHAR)(RD_HARPOON(p_port+hp_scsidata_0) &
+      ~(UCHAR)BIT(6)));
+   scwirod(p_port, BIT(6));
+
+   WR_HARPOON(p_port+hp_scsisig, (SCSI_SEL | SCSI_BSY | SCSI_IOBIT | SCSI_CD));
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scxferc
+ *
+ * Description: Handshake the p_data (DB4-0) across the bus.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR scxferc(USHORT p_port, UCHAR p_data)
+#else
+UCHAR scxferc(ULONG p_port, UCHAR p_data)
+#endif
+{
+   UCHAR curr_data, ret_data;
+
+   curr_data = p_data | BIT(7) | BIT(5);   /*Start with DB7 & DB5 asserted. */
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   curr_data &= ~BIT(7);
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   scwirod(p_port,BIT(7));              /*Wait for DB7 to be released. */
+	while (!(RD_HARPOON(p_port+hp_scsidata_0) & BIT(5)));
+
+   ret_data = (RD_HARPOON(p_port+hp_scsidata_0) & (UCHAR) 0x1F);
+
+   curr_data |= BIT(6);
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   curr_data &= ~BIT(5);
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   scwirod(p_port,BIT(5));              /*Wait for DB5 to be released. */
+
+   curr_data &= ~(BIT(4)|BIT(3)|BIT(2)|BIT(1)|BIT(0)); /*Release data bits */
+   curr_data |= BIT(7);
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   curr_data &= ~BIT(6);
+
+   WR_HARPOON(p_port+hp_scsidata_0, curr_data);
+
+   scwirod(p_port,BIT(6));              /*Wait for DB6 to be released. */
+
+   return(ret_data);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scsendi
+ *
+ * Description: Transfer our Identification string to determine if we
+ *              will be the dominant master.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR scsendi(USHORT p_port, UCHAR p_id_string[])
+#else
+UCHAR scsendi(ULONG p_port, UCHAR p_id_string[])
+#endif
+{
+   UCHAR ret_data,byte_cnt,bit_cnt,defer;
+
+   defer = FALSE;
+
+   for (byte_cnt = 0; byte_cnt < ID_STRING_LENGTH; byte_cnt++) {
+
+      for (bit_cnt = 0x80; bit_cnt != 0 ; bit_cnt >>= 1) {
+
+         if (defer)
+            ret_data = scxferc(p_port,00);
+
+         else if (p_id_string[byte_cnt] & bit_cnt)
+
+               ret_data = scxferc(p_port,02);
+
+            else {
+
+               ret_data = scxferc(p_port,01);
+               if (ret_data & 02)
+                  defer = TRUE;
+               }
+
+         if ((ret_data & 0x1C) == 0x10)
+            return(0x00);  /*End of isolation stage, we won! */
+
+         if (ret_data & 0x1C)
+            return(0xFF);
+
+         if ((defer) && (!(ret_data & 0x1F)))
+            return(0x01);  /*End of isolation stage, we lost. */
+
+         } /*bit loop */
+
+      } /*byte loop */
+
+   if (defer)
+      return(0x01);  /*We lost */
+   else
+      return(0);  /*We WON! Yeeessss! */
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: sciso
+ *
+ * Description: Transfer the Identification string.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR sciso(USHORT p_port, UCHAR p_id_string[])
+#else
+UCHAR sciso(ULONG p_port, UCHAR p_id_string[])
+#endif
+{
+   UCHAR ret_data,the_data,byte_cnt,bit_cnt;
+
+   the_data = 0;
+
+   for (byte_cnt = 0; byte_cnt < ID_STRING_LENGTH; byte_cnt++) {
+
+      for (bit_cnt = 0; bit_cnt < 8; bit_cnt++) {
+
+         ret_data = scxferc(p_port,0);
+
+         if (ret_data & 0xFC)
+            return(0xFF);
+
+         else {
+
+            the_data <<= 1;
+            if (ret_data & BIT(1)) {
+               the_data |= 1;
+               }
+            }
+
+         if ((ret_data & 0x1F) == 0)
+	   {
+/*
+				if(bit_cnt != 0 || bit_cnt != 8)
+				{
+					byte_cnt = 0;
+					bit_cnt = 0;
+					scxferc(p_port, SYNC_PTRN);
+					scxferc(p_port, ASSIGN_ID);
+					continue;
+				}
+*/
+            if (byte_cnt)
+               return(0x00);
+            else
+               return(0xFF);
+	   }
+
+         } /*bit loop */
+
+      p_id_string[byte_cnt] = the_data;
+
+      } /*byte loop */
+
+   return(0);
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scwirod
+ *
+ * Description: Sample the SCSI data bus making sure the signal has been
+ *              deasserted for the correct number of consecutive samples.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scwirod(USHORT p_port, UCHAR p_data_bit)
+#else
+void scwirod(ULONG p_port, UCHAR p_data_bit)
+#endif
+{
+   UCHAR i;
+
+   i = 0;
+   while ( i < MAX_SCSI_TAR ) {
+
+      if (RD_HARPOON(p_port+hp_scsidata_0) & p_data_bit)
+
+         i = 0;
+
+      else
+
+         i++;
+
+      }
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scwiros
+ *
+ * Description: Sample the SCSI Signal lines making sure the signal has been
+ *              deasserted for the correct number of consecutive samples.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scwiros(USHORT p_port, UCHAR p_data_bit)
+#else
+void scwiros(ULONG p_port, UCHAR p_data_bit)
+#endif
+{
+   UCHAR i;
+
+   i = 0;
+   while ( i < MAX_SCSI_TAR ) {
+
+      if (RD_HARPOON(p_port+hp_scsisig) & p_data_bit)
+
+         i = 0;
+
+      else
+
+         i++;
+
+      }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scvalq
+ *
+ * Description: Make sure we received a valid data byte.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scvalq(UCHAR p_quintet)
+{
+   UCHAR count;
+
+   for (count=1; count < 0x08; count<<=1) {
+      if (!(p_quintet & count))
+         p_quintet -= 0x80;
+      }
+
+   if (p_quintet & 0x18)
+      return(FALSE);
+
+   else
+      return(TRUE);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scsell
+ *
+ * Description: Select the specified device ID using a selection timeout
+ *              less than 4ms.  If somebody responds then it is a legacy
+ *              drive and this ID must be marked as such.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+UCHAR scsell(USHORT p_port, UCHAR targ_id)
+#else
+UCHAR scsell(ULONG p_port, UCHAR targ_id)
+#endif
+{
+#if defined(DOS)
+   USHORT i;
+#else
+   ULONG i;
+#endif
+
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+   ARAM_ACCESS(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_4ms);
+
+
+   for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) {
+      WRW_HARPOON(i, (MPM_OP+ACOMMAND));
+      }
+   WRW_HARPOON(i, (BRH_OP+ALWAYS+    NP));
+
+   WRW_HARPOON((p_port+hp_intstat),
+	       (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT));
+
+   WR_HARPOON(p_port+hp_select_id, targ_id);
+
+   WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT);
+   WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT));
+   WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL));
+
+
+   while (!(RDW_HARPOON((p_port+hp_intstat)) &
+	    (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {}
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & RESET)
+         Wait(p_port, TO_250ms);
+
+   DISABLE_AUTO(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_290ms);
+
+   SGRAM_ACCESS(p_port);
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) {
+
+      WRW_HARPOON((p_port+hp_intstat),
+		  (RESET | TIMEOUT | SEL | BUS_FREE | PHASE));
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(FALSE);  /*No legacy device */
+      }
+
+   else {
+
+      while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) {
+				if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+					{
+					WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+      			ACCEPT_MSG(p_port);
+					}
+		}
+
+      WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1);
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(TRUE);  /*Found one of them oldies! */
+      }
+}
+
+#if defined(DOS)
+/*---------------------------------------------------------------------
+ *
+ * Function: scsell for DOS
+ *
+ * Description: Select the specified device ID using a selection timeout
+ *              less than 2ms.  This was specially required to solve
+ *              the problem with Plextor 12X CD-ROM drive. This drive
+ *					 was responding the Selection at the end of 4ms and 
+ *					 hanging the system.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id)
+{
+   USHORT i;
+
+   WR_HARPOON(p_port+hp_page_ctrl,
+      (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+   ARAM_ACCESS(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_2ms);
+
+
+   for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) {
+      WRW_HARPOON(i, (MPM_OP+ACOMMAND));
+      }
+   WRW_HARPOON(i, (BRH_OP+ALWAYS+    NP));
+
+   WRW_HARPOON((p_port+hp_intstat),
+	       (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT));
+
+   WR_HARPOON(p_port+hp_select_id, targ_id);
+
+   WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT);
+   WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT));
+   WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL));
+
+
+   while (!(RDW_HARPOON((p_port+hp_intstat)) &
+	    (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {}
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & RESET)
+         Wait(p_port, TO_250ms);
+
+   DISABLE_AUTO(p_port);
+
+   WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER));
+   WR_HARPOON(p_port+hp_seltimeout,TO_290ms);
+
+   SGRAM_ACCESS(p_port);
+
+   if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) {
+
+      WRW_HARPOON((p_port+hp_intstat),
+		  (RESET | TIMEOUT | SEL | BUS_FREE | PHASE));
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(FALSE);  /*No legacy device */
+      }
+
+   else {
+
+      while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) {
+				if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+					{
+					WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+      			ACCEPT_MSG(p_port);
+					}
+		}
+
+      WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1);
+
+      WR_HARPOON(p_port+hp_page_ctrl,
+         (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+      return(TRUE);  /*Found one of them oldies! */
+      }
+}
+#endif  /* DOS */
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scwtsel
+ *
+ * Description: Wait to be selected by another SCAM initiator.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scwtsel(USHORT p_port)
+#else
+void scwtsel(ULONG p_port)
+#endif
+{
+   while(!(RDW_HARPOON((p_port+hp_intstat)) & SCAM_SEL)) {}
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: inisci
+ *
+ * Description: Setup the data Structure with the info from the EEPROM.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void inisci(UCHAR p_card, USHORT p_port, UCHAR p_our_id)
+#else
+void inisci(UCHAR p_card, ULONG p_port, UCHAR p_our_id)
+#endif
+{
+   UCHAR i,k,max_id;
+   USHORT ee_data;
+	PNVRamInfo pCurrNvRam;
+
+	pCurrNvRam = BL_Card[p_card].pNvRamInfo;
+
+   if (RD_HARPOON(p_port+hp_page_ctrl) & NARROW_SCSI_CARD)
+      max_id = 0x08;
+
+   else
+      max_id = 0x10;
+
+	if(pCurrNvRam){
+		for(i = 0; i < max_id; i++){
+
+			for(k = 0; k < 4; k++)
+				scamInfo[i].id_string[k] = pCurrNvRam->niScamTbl[i][k];
+			for(k = 4; k < ID_STRING_LENGTH; k++)
+				scamInfo[i].id_string[k] = (UCHAR) 0x00;
+
+	      if(scamInfo[i].id_string[0] == 0x00)
+      	   scamInfo[i].state = ID_UNUSED;  /*Default to unused ID. */
+	      else
+   	      scamInfo[i].state = ID_UNASSIGNED;  /*Default to unassigned ID. */
+
+		}
+	}else {
+	   for (i=0; i < max_id; i++)
+   	   {
+      	for (k=0; k < ID_STRING_LENGTH; k+=2)
+	         {
+   	      ee_data = utilEERead(p_port, (USHORT)((EE_SCAMBASE/2) +
+      	     (USHORT) (i*((USHORT)ID_STRING_LENGTH/2)) + (USHORT)(k/2)));
+         	scamInfo[i].id_string[k] = (UCHAR) ee_data;
+	         ee_data >>= 8;
+   	      scamInfo[i].id_string[k+1] = (UCHAR) ee_data;
+      	   }
+
+	      if ((scamInfo[i].id_string[0] == 0x00) ||
+   	       (scamInfo[i].id_string[0] == 0xFF))
+
+      	   scamInfo[i].state = ID_UNUSED;  /*Default to unused ID. */
+
+	      else
+   	      scamInfo[i].state = ID_UNASSIGNED;  /*Default to unassigned ID. */
+
+      	}
+	}
+	for(k = 0; k < ID_STRING_LENGTH; k++)
+		scamInfo[p_our_id].id_string[k] = scamHAString[k];
+
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scmachid
+ *
+ * Description: Match the Device ID string with our values stored in
+ *              the EEPROM.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scmachid(UCHAR p_card, UCHAR p_id_string[])
+{
+
+   UCHAR i,k,match;
+
+
+   for (i=0; i < MAX_SCSI_TAR; i++) {
+
+#if !defined(SCAM_LEV_2)
+      if (scamInfo[i].state == ID_UNASSIGNED)
+         {
+#endif
+         match = TRUE;
+
+         for (k=0; k < ID_STRING_LENGTH; k++)
+            {
+            if (p_id_string[k] != scamInfo[i].id_string[k])
+               match = FALSE;
+            }
+
+         if (match)
+            {
+            scamInfo[i].state = ID_ASSIGNED;
+            return(i);
+            }
+
+#if !defined(SCAM_LEV_2)
+         }
+#endif
+
+      }
+
+
+
+   if (p_id_string[0] & BIT(5))
+      i = 8;
+   else
+      i = MAX_SCSI_TAR;
+
+   if (((p_id_string[0] & 0x06) == 0x02) || ((p_id_string[0] & 0x06) == 0x04))
+      match = p_id_string[1] & (UCHAR) 0x1F;
+   else
+      match = 7;
+
+   while (i > 0)
+      {
+      i--;
+
+      if (scamInfo[match].state == ID_UNUSED)
+         {
+         for (k=0; k < ID_STRING_LENGTH; k++)
+            {
+            scamInfo[match].id_string[k] = p_id_string[k];
+            }
+
+         scamInfo[match].state = ID_ASSIGNED;
+
+			if(BL_Card[p_card].pNvRamInfo == NULL)
+	         BL_Card[p_card].globalFlags |= F_UPDATE_EEPROM;
+         return(match);
+
+         }
+
+
+      match--;
+
+      if (match == 0xFF)
+	{
+         if (p_id_string[0] & BIT(5))
+            match = 7;
+         else
+            match = MAX_SCSI_TAR-1;
+	}
+      }
+
+
+
+   if (p_id_string[0] & BIT(7))
+      {
+      return(CLR_PRIORITY);
+      }
+
+
+   if (p_id_string[0] & BIT(5))
+      i = 8;
+   else
+      i = MAX_SCSI_TAR;
+
+   if (((p_id_string[0] & 0x06) == 0x02) || ((p_id_string[0] & 0x06) == 0x04))
+      match = p_id_string[1] & (UCHAR) 0x1F;
+   else
+      match = 7;
+
+   while (i > 0)
+      {
+
+      i--;
+
+      if (scamInfo[match].state == ID_UNASSIGNED)
+         {
+         for (k=0; k < ID_STRING_LENGTH; k++)
+            {
+            scamInfo[match].id_string[k] = p_id_string[k];
+            }
+
+         scamInfo[match].id_string[0] |= BIT(7);
+         scamInfo[match].state = ID_ASSIGNED;
+			if(BL_Card[p_card].pNvRamInfo == NULL)
+	         BL_Card[p_card].globalFlags |= F_UPDATE_EEPROM;
+         return(match);
+
+         }
+
+
+      match--;
+
+      if (match == 0xFF)
+	{
+         if (p_id_string[0] & BIT(5))
+            match = 7;
+         else
+            match = MAX_SCSI_TAR-1;
+	}
+      }
+
+   return(NO_ID_AVAIL);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: scsavdi
+ *
+ * Description: Save off the device SCAM ID strings.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void scsavdi(UCHAR p_card, USHORT p_port)
+#else
+void scsavdi(UCHAR p_card, ULONG p_port)
+#endif
+{
+   UCHAR i,k,max_id;
+   USHORT ee_data,sum_data;
+
+
+   sum_data = 0x0000;
+
+   for (i = 1; i < EE_SCAMBASE/2; i++)
+      {
+      sum_data += utilEERead(p_port, i);
+      }
+
+
+   utilEEWriteOnOff(p_port,1);   /* Enable write access to the EEPROM */
+
+   if (RD_HARPOON(p_port+hp_page_ctrl) & NARROW_SCSI_CARD)
+      max_id = 0x08;
+
+   else
+      max_id = 0x10;
+
+   for (i=0; i < max_id; i++)
+      {
+
+      for (k=0; k < ID_STRING_LENGTH; k+=2)
+         {
+         ee_data = scamInfo[i].id_string[k+1];
+         ee_data <<= 8;
+         ee_data |= scamInfo[i].id_string[k];
+         sum_data += ee_data;
+         utilEEWrite(p_port, ee_data, (USHORT)((EE_SCAMBASE/2) +
+            (USHORT)(i*((USHORT)ID_STRING_LENGTH/2)) + (USHORT)(k/2)));
+         }
+      }
+
+
+   utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2);
+   utilEEWriteOnOff(p_port,0);   /* Turn off write access */
+}
+#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   diagnose.c  $
+ *
+ *   Description:  Diagnostic funtions for testing the integrity of
+ *                 the HARPOON.
+ *
+ *   $Date: 1997/06/10 16:51:47 $
+ *
+ *   $Revision: 1.10 $
+ *
+ *----------------------------------------------------------------------*/
+
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <eeprom.h>*/
+/*#include <harpoon.h>*/
+
+/*---------------------------------------------------------------------
+ *
+ * Function: XbowInit
+ *
+ * Description: Setup the Xbow for normal operation.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void XbowInit(USHORT port, UCHAR ScamFlg)
+#else
+void XbowInit(ULONG port, UCHAR ScamFlg)
+#endif
+{
+UCHAR i;
+
+	i = RD_HARPOON(port+hp_page_ctrl);
+	WR_HARPOON(port+hp_page_ctrl, (UCHAR) (i | G_INT_DISABLE));
+
+   WR_HARPOON(port+hp_scsireset,0x00);
+   WR_HARPOON(port+hp_portctrl_1,HOST_MODE8);
+
+   WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \
+				 FIFO_CLR));
+
+   WR_HARPOON(port+hp_scsireset,SCSI_INI);
+
+   WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT);
+
+   WR_HARPOON(port+hp_scsisig,0x00);         /*  Clear any signals we might */
+   WR_HARPOON(port+hp_scsictrl_0,ENA_SCAM_SEL);
+
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT);
+
+#if defined(SCAM_LEV_2)
+   default_intena = RESET | RSEL | PROG_HLT | TIMEOUT |
+		    BUS_FREE | XFER_CNT_0 | AUTO_INT;
+
+   if ((ScamFlg & SCAM_ENABLED) && (ScamFlg & SCAM_LEVEL2))
+		default_intena |= SCAM_SEL;
+
+#else
+   default_intena = RESET | RSEL | PROG_HLT | TIMEOUT |
+		    BUS_FREE | XFER_CNT_0 | AUTO_INT;
+#endif
+   WRW_HARPOON((port+hp_intena), default_intena);
+
+   WR_HARPOON(port+hp_seltimeout,TO_290ms);
+
+   /* Turn on SCSI_MODE8 for narrow cards to fix the
+      strapping issue with the DUAL CHANNEL card */
+   if (RD_HARPOON(port+hp_page_ctrl) & NARROW_SCSI_CARD)
+      WR_HARPOON(port+hp_addstat,SCSI_MODE8);
+
+#if defined(NO_BIOS_OPTION)
+
+   WR_HARPOON(port+hp_synctarg_0,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_1,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_2,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_3,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_4,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_5,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_6,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_7,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_8,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_9,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_10,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_11,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_12,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_13,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_14,NARROW_SCSI);
+   WR_HARPOON(port+hp_synctarg_15,NARROW_SCSI);
+
+#endif
+	WR_HARPOON(port+hp_page_ctrl, i);
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: BusMasterInit
+ *
+ * Description: Initialize the BusMaster for normal operations.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void BusMasterInit(USHORT p_port)
+#else
+void BusMasterInit(ULONG p_port)
+#endif
+{
+
+
+   WR_HARPOON(p_port+hp_sys_ctrl, DRVR_RST);
+   WR_HARPOON(p_port+hp_sys_ctrl, 0x00);
+
+   WR_HARPOON(p_port+hp_host_blk_cnt, XFER_BLK64);
+
+
+   WR_HARPOON(p_port+hp_bm_ctrl, (BMCTRL_DEFAULT));
+
+   WR_HARPOON(p_port+hp_ee_ctrl, (SCSI_TERM_ENA_H));
+
+
+#if defined(NT)
+
+   WR_HARPOON(p_port+hp_pci_cmd_cfg, (RD_HARPOON(p_port+hp_pci_cmd_cfg)
+      & ~MEM_SPACE_ENA));
+
+#endif
+
+   RD_HARPOON(p_port+hp_int_status);        /*Clear interrupts. */
+   WR_HARPOON(p_port+hp_int_mask, (INT_CMD_COMPL | SCSI_INTERRUPT));
+   WR_HARPOON(p_port+hp_page_ctrl, (RD_HARPOON(p_port+hp_page_ctrl) &
+      ~SCATTER_EN));
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: DiagXbow
+ *
+ * Description: Test Xbow integrity.  Non-zero return indicates an error.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+int DiagXbow(USHORT port)
+#else
+int DiagXbow(ULONG port)
+#endif
+{
+   unsigned char fifo_cnt,loop_cnt;
+
+   unsigned char fifodata[5];
+   fifodata[0] = 0x00;
+   fifodata[1] = 0xFF;
+   fifodata[2] = 0x55;
+   fifodata[3] = 0xAA;
+   fifodata[4] = 0x00;
+
+
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT);
+   WRW_HARPOON((port+hp_intena), 0x0000);
+
+   WR_HARPOON(port+hp_seltimeout,TO_5ms);
+
+   WR_HARPOON(port+hp_portctrl_0,START_TO);
+
+
+   for(fifodata[4] = 0x01; fifodata[4] != (UCHAR) 0; fifodata[4] = fifodata[4] << 1) {
+
+      WR_HARPOON(port+hp_selfid_0,fifodata[4]);
+      WR_HARPOON(port+hp_selfid_1,fifodata[4]);
+
+      if ((RD_HARPOON(port+hp_selfid_0) != fifodata[4]) ||
+          (RD_HARPOON(port+hp_selfid_1) != fifodata[4]))
+         return(1);
+      }
+
+
+   for(loop_cnt = 0; loop_cnt < 4; loop_cnt++) {
+
+      WR_HARPOON(port+hp_portctrl_0,(HOST_PORT | HOST_WRT | START_TO));
+
+
+      for (fifo_cnt = 0; fifo_cnt < FIFO_LEN; fifo_cnt++) {
+
+         WR_HARPOON(port+hp_fifodata_0, fifodata[loop_cnt]);
+         }
+
+
+      if (!(RD_HARPOON(port+hp_xferstat) & FIFO_FULL))
+         return(1);
+
+
+      WR_HARPOON(port+hp_portctrl_0,(HOST_PORT | START_TO));
+
+      for (fifo_cnt = 0; fifo_cnt < FIFO_LEN; fifo_cnt++) {
+
+         if (RD_HARPOON(port+hp_fifodata_0) != fifodata[loop_cnt])
+            return(1);
+         }
+
+
+      if (!(RD_HARPOON(port+hp_xferstat) & FIFO_EMPTY))
+         return(1);
+      }
+
+
+   while(!(RDW_HARPOON((port+hp_intstat)) & TIMEOUT)) {}
+
+
+   WR_HARPOON(port+hp_seltimeout,TO_290ms);
+
+   WRW_HARPOON((port+hp_intstat), CLR_ALL_INT);
+
+   WRW_HARPOON((port+hp_intena), default_intena);
+
+   return(0);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: DiagBusMaster
+ *
+ * Description: Test BusMaster integrity.  Non-zero return indicates an
+ *              error.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+int DiagBusMaster(USHORT port)
+#else
+int DiagBusMaster(ULONG port)
+#endif
+{
+   UCHAR testdata;
+
+   for(testdata = (UCHAR) 1; testdata != (UCHAR)0; testdata = testdata << 1) {
+
+      WR_HARPOON(port+hp_xfer_cnt_lo,testdata);
+      WR_HARPOON(port+hp_xfer_cnt_mi,testdata);
+      WR_HARPOON(port+hp_xfer_cnt_hi,testdata);
+      WR_HARPOON(port+hp_host_addr_lo,testdata);
+      WR_HARPOON(port+hp_host_addr_lmi,testdata);
+      WR_HARPOON(port+hp_host_addr_hmi,testdata);
+      WR_HARPOON(port+hp_host_addr_hi,testdata);
+
+      if ((RD_HARPOON(port+hp_xfer_cnt_lo) != testdata)   ||
+          (RD_HARPOON(port+hp_xfer_cnt_mi) != testdata)   ||
+          (RD_HARPOON(port+hp_xfer_cnt_hi) != testdata)   ||
+          (RD_HARPOON(port+hp_host_addr_lo) != testdata)  ||
+          (RD_HARPOON(port+hp_host_addr_lmi) != testdata) ||
+          (RD_HARPOON(port+hp_host_addr_hmi) != testdata) ||
+          (RD_HARPOON(port+hp_host_addr_hi) != testdata))
+
+         return(1);
+      }
+   RD_HARPOON(port+hp_int_status);        /*Clear interrupts. */
+   return(0);
+}
+
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: DiagEEPROM
+ *
+ * Description: Verfiy checksum and 'Key' and initialize the EEPROM if
+ *              necessary.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void DiagEEPROM(USHORT p_port)
+#else
+void DiagEEPROM(ULONG p_port)
+#endif
+
+{
+   USHORT index,temp,max_wd_cnt;
+
+   if (RD_HARPOON(p_port+hp_page_ctrl) & NARROW_SCSI_CARD)
+      max_wd_cnt = EEPROM_WD_CNT;
+   else
+      max_wd_cnt = EEPROM_WD_CNT * 2;
+
+   temp = utilEERead(p_port, FW_SIGNATURE/2);
+
+   if (temp == 0x4641) {
+
+      for (index = 2; index < max_wd_cnt; index++) {
+
+         temp += utilEERead(p_port, index);
+
+         }
+
+      if (temp == utilEERead(p_port, EEPROM_CHECK_SUM/2)) {
+
+         return;          /*EEPROM is Okay so return now! */
+         }
+      }
+
+
+   utilEEWriteOnOff(p_port,(UCHAR)1);
+
+   for (index = 0; index < max_wd_cnt; index++) {
+
+      utilEEWrite(p_port, 0x0000, index);
+      }
+
+   temp = 0;
+
+   utilEEWrite(p_port, 0x4641, FW_SIGNATURE/2);
+   temp += 0x4641;
+   utilEEWrite(p_port, 0x3920, MODEL_NUMB_0/2);
+   temp += 0x3920;
+   utilEEWrite(p_port, 0x3033, MODEL_NUMB_2/2);
+   temp += 0x3033;
+   utilEEWrite(p_port, 0x2020, MODEL_NUMB_4/2);
+   temp += 0x2020;
+   utilEEWrite(p_port, 0x70D3, SYSTEM_CONFIG/2);
+   temp += 0x70D3;
+   utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2);
+   temp += 0x0010;
+   utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2);
+   temp += 0x0003;
+   utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2);
+   temp += 0x0007;
+
+   utilEEWrite(p_port, 0x0000, IGNORE_B_SCAN/2);
+   temp += 0x0000;
+   utilEEWrite(p_port, 0x0000, SEND_START_ENA/2);
+   temp += 0x0000;
+   utilEEWrite(p_port, 0x0000, DEVICE_ENABLE/2);
+   temp += 0x0000;
+
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL01/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL23/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL45/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL67/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBL89/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLab/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLcd/2);
+   temp += 0x4242;
+   utilEEWrite(p_port, 0x4242, SYNC_RATE_TBLef/2);
+   temp += 0x4242;
+
+
+   utilEEWrite(p_port, 0x6C46, 64/2);  /*PRODUCT ID */
+   temp += 0x6C46;
+   utilEEWrite(p_port, 0x7361, 66/2);  /* FlashPoint LT   */
+   temp += 0x7361;
+   utilEEWrite(p_port, 0x5068, 68/2);
+   temp += 0x5068;
+   utilEEWrite(p_port, 0x696F, 70/2);
+   temp += 0x696F;
+   utilEEWrite(p_port, 0x746E, 72/2);
+   temp += 0x746E;
+   utilEEWrite(p_port, 0x4C20, 74/2);
+   temp += 0x4C20;
+   utilEEWrite(p_port, 0x2054, 76/2);
+   temp += 0x2054;
+   utilEEWrite(p_port, 0x2020, 78/2);
+   temp += 0x2020;
+
+   index = ((EE_SCAMBASE/2)+(7*16));
+   utilEEWrite(p_port, (0x0700+TYPE_CODE0), index);
+   temp += (0x0700+TYPE_CODE0);
+   index++;
+   utilEEWrite(p_port, 0x5542, index);            /*Vendor ID code */
+   temp += 0x5542;                                /* BUSLOGIC      */
+   index++;
+   utilEEWrite(p_port, 0x4C53, index);
+   temp += 0x4C53;
+   index++;
+   utilEEWrite(p_port, 0x474F, index);
+   temp += 0x474F;
+   index++;
+   utilEEWrite(p_port, 0x4349, index);
+   temp += 0x4349;
+   index++;
+   utilEEWrite(p_port, 0x5442, index);            /*Vendor unique code */
+   temp += 0x5442;                         /* BT- 930           */
+   index++;
+   utilEEWrite(p_port, 0x202D, index);
+   temp += 0x202D;
+   index++;
+   utilEEWrite(p_port, 0x3339, index);
+   temp += 0x3339;
+   index++;                                 /*Serial #          */
+   utilEEWrite(p_port, 0x2030, index);             /* 01234567         */
+   temp += 0x2030;
+   index++;
+   utilEEWrite(p_port, 0x5453, index);
+   temp += 0x5453;
+   index++;
+   utilEEWrite(p_port, 0x5645, index);
+   temp += 0x5645;
+   index++;
+   utilEEWrite(p_port, 0x2045, index);
+   temp += 0x2045;
+   index++;
+   utilEEWrite(p_port, 0x202F, index);
+   temp += 0x202F;
+   index++;
+   utilEEWrite(p_port, 0x4F4A, index);
+   temp += 0x4F4A;
+   index++;
+   utilEEWrite(p_port, 0x204E, index);
+   temp += 0x204E;
+   index++;
+   utilEEWrite(p_port, 0x3539, index);
+   temp += 0x3539;
+
+
+
+   utilEEWrite(p_port, temp, EEPROM_CHECK_SUM/2);
+
+   utilEEWriteOnOff(p_port,(UCHAR)0);
+
+}
+
+#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $"
+/*----------------------------------------------------------------------
+ *
+ *
+ *   Copyright 1995-1996 by Mylex Corporation.  All Rights Reserved
+ *
+ *   This file is available under both the GNU General Public License
+ *   and a BSD-style copyright; see LICENSE.FlashPoint for details.
+ *
+ *   $Workfile:   utility.c  $
+ *
+ *   Description:  Utility functions relating to queueing and EEPROM
+ *                 manipulation and any other garbage functions.
+ *
+ *   $Date: 1997/06/10 16:55:06 $
+ *
+ *   $Revision: 1.23 $
+ *
+ *----------------------------------------------------------------------*/
+/*#include <globals.h>*/
+
+#if (FW_TYPE==_UCB_MGR_)
+	/*#include <budi.h>*/
+#endif
+
+/*#include <sccbmgr.h>*/
+/*#include <blx30.h>*/
+/*#include <target.h>*/
+/*#include <scsi2.h>*/
+/*#include <harpoon.h>*/
+
+
+/*
+extern SCCBCARD BL_Card[MAX_CARDS];
+extern SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
+extern unsigned int SccbGlobalFlags;
+*/
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Search Select
+ *
+ * Description: Try to find a new command to execute.
+ *
+ *---------------------------------------------------------------------*/
+
+void queueSearchSelect(PSCCBcard pCurrCard, UCHAR p_card)
+{
+   UCHAR scan_ptr, lun;
+   PSCCBMgr_tar_info currTar_Info;
+	PSCCB pOldSccb;
+
+   scan_ptr = pCurrCard->scanIndex;
+	do 
+	{
+		currTar_Info = &sccbMgrTbl[p_card][scan_ptr];
+		if((pCurrCard->globalFlags & F_CONLUN_IO) && 
+			((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING))
+		{
+			if (currTar_Info->TarSelQ_Cnt != 0)
+			{
+
+				scan_ptr++;
+				if (scan_ptr == MAX_SCSI_TAR)
+					scan_ptr = 0;
+				
+				for(lun=0; lun < MAX_LUN; lun++)
+				{
+					if(currTar_Info->TarLUNBusy[lun] == FALSE)
+					{
+
+						pCurrCard->currentSCCB = currTar_Info->TarSelQ_Head;
+						pOldSccb = NULL;
+
+						while((pCurrCard->currentSCCB != NULL) &&
+								 (lun != pCurrCard->currentSCCB->Lun))
+						{
+							pOldSccb = pCurrCard->currentSCCB;
+							pCurrCard->currentSCCB = (PSCCB)(pCurrCard->currentSCCB)->
+																	Sccb_forwardlink;
+						}
+						if(pCurrCard->currentSCCB == NULL)
+							continue;
+						if(pOldSccb != NULL)
+						{
+							pOldSccb->Sccb_forwardlink = (PSCCB)(pCurrCard->currentSCCB)->
+																	Sccb_forwardlink;
+							pOldSccb->Sccb_backlink = (PSCCB)(pCurrCard->currentSCCB)->
+																	Sccb_backlink;
+							currTar_Info->TarSelQ_Cnt--;
+						}
+						else
+						{
+							currTar_Info->TarSelQ_Head = (PSCCB)(pCurrCard->currentSCCB)->Sccb_forwardlink;
+					
+							if (currTar_Info->TarSelQ_Head == NULL)
+							{
+								currTar_Info->TarSelQ_Tail = NULL;
+								currTar_Info->TarSelQ_Cnt = 0;
+							}
+							else
+							{
+								currTar_Info->TarSelQ_Cnt--;
+								currTar_Info->TarSelQ_Head->Sccb_backlink = (PSCCB)NULL;
+							}
+						}
+					pCurrCard->scanIndex = scan_ptr;
+
+					pCurrCard->globalFlags |= F_NEW_SCCB_CMD;
+
+					break;
+					}
+				}
+			}
+
+			else 
+			{
+				scan_ptr++;
+				if (scan_ptr == MAX_SCSI_TAR) {
+					scan_ptr = 0;
+				}
+			}
+
+		}
+		else
+		{
+			if ((currTar_Info->TarSelQ_Cnt != 0) &&
+				(currTar_Info->TarLUNBusy[0] == FALSE))
+			{
+
+				pCurrCard->currentSCCB = currTar_Info->TarSelQ_Head;
+
+				currTar_Info->TarSelQ_Head = (PSCCB)(pCurrCard->currentSCCB)->Sccb_forwardlink;
+
+				if (currTar_Info->TarSelQ_Head == NULL)
+				{
+					currTar_Info->TarSelQ_Tail = NULL;
+					currTar_Info->TarSelQ_Cnt = 0;
+				}
+				else
+				{
+					currTar_Info->TarSelQ_Cnt--;
+					currTar_Info->TarSelQ_Head->Sccb_backlink = (PSCCB)NULL;
+				}
+
+				scan_ptr++;
+				if (scan_ptr == MAX_SCSI_TAR)
+					scan_ptr = 0;
+
+				pCurrCard->scanIndex = scan_ptr;
+
+				pCurrCard->globalFlags |= F_NEW_SCCB_CMD;
+
+				break;
+			}
+
+			else 
+			{
+				scan_ptr++;
+				if (scan_ptr == MAX_SCSI_TAR) 
+				{
+					scan_ptr = 0;
+				}
+			}
+		}
+	} while (scan_ptr != pCurrCard->scanIndex);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Select Fail
+ *
+ * Description: Add the current SCCB to the head of the Queue.
+ *
+ *---------------------------------------------------------------------*/
+
+void queueSelectFail(PSCCBcard pCurrCard, UCHAR p_card)
+{
+   UCHAR thisTarg;
+   PSCCBMgr_tar_info currTar_Info;
+
+   if (pCurrCard->currentSCCB != NULL)
+	  {
+	  thisTarg = (UCHAR)(((PSCCB)(pCurrCard->currentSCCB))->TargID);
+      currTar_Info = &sccbMgrTbl[p_card][thisTarg];
+
+      pCurrCard->currentSCCB->Sccb_backlink = (PSCCB)NULL;
+
+      pCurrCard->currentSCCB->Sccb_forwardlink = currTar_Info->TarSelQ_Head;
+
+	  if (currTar_Info->TarSelQ_Cnt == 0)
+		 {
+		 currTar_Info->TarSelQ_Tail = pCurrCard->currentSCCB;
+		 }
+
+	  else
+		 {
+		 currTar_Info->TarSelQ_Head->Sccb_backlink = pCurrCard->currentSCCB;
+		 }
+
+
+	  currTar_Info->TarSelQ_Head = pCurrCard->currentSCCB;
+
+	  pCurrCard->currentSCCB = NULL;
+	  currTar_Info->TarSelQ_Cnt++;
+	  }
+}
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Command Complete
+ *
+ * Description: Call the callback function with the current SCCB.
+ *
+ *---------------------------------------------------------------------*/
+
+void queueCmdComplete(PSCCBcard pCurrCard, PSCCB p_sccb, UCHAR p_card)
+{
+
+#if (FW_TYPE==_UCB_MGR_)
+
+   u08bits SCSIcmd;
+   CALL_BK_FN callback;
+   PSCCBMgr_tar_info currTar_Info;
+
+   PUCB p_ucb;
+   p_ucb=p_sccb->Sccb_ucb_ptr;
+
+   SCSIcmd = p_sccb->Cdb[0];
+
+
+   if (!(p_sccb->Sccb_XferState & F_ALL_XFERRED))
+   {
+
+      if ((p_ucb->UCB_opcode & OPC_CHK_UNDER_OVER_RUN)                     &&
+         (p_sccb->HostStatus == SCCB_COMPLETE)                             &&
+         (p_sccb->TargetStatus != SSCHECK))
+
+         if ((SCSIcmd == SCSI_READ)             ||
+             (SCSIcmd == SCSI_WRITE)            ||
+             (SCSIcmd == SCSI_READ_EXTENDED)    ||
+             (SCSIcmd == SCSI_WRITE_EXTENDED)   ||
+             (SCSIcmd == SCSI_WRITE_AND_VERIFY) ||
+             (SCSIcmd == SCSI_START_STOP_UNIT)  ||
+             (pCurrCard->globalFlags & F_NO_FILTER)
+            )
+               p_sccb->HostStatus = SCCB_DATA_UNDER_RUN;
+   }
+
+   p_ucb->UCB_status=SCCB_SUCCESS;
+
+   if ((p_ucb->UCB_hbastat=p_sccb->HostStatus) || (p_ucb->UCB_scsistat=p_sccb->TargetStatus))
+   {
+      p_ucb->UCB_status=SCCB_ERROR;
+   }
+
+   if ((p_sccb->OperationCode == RESIDUAL_SG_COMMAND) ||
+      (p_sccb->OperationCode == RESIDUAL_COMMAND))
+   {
+
+         utilUpdateResidual(p_sccb);
+
+         p_ucb->UCB_datalen=p_sccb->DataLength;
+   }
+
+   pCurrCard->cmdCounter--;
+   if (!pCurrCard->cmdCounter)
+   {
+
+      if (pCurrCard->globalFlags & F_GREEN_PC)
+      {
+         WR_HARPOON(pCurrCard->ioPort+hp_clkctrl_0,(PWR_DWN | CLKCTRL_DEFAULT));
+         WR_HARPOON(pCurrCard->ioPort+hp_sys_ctrl, STOP_CLK);
+      }
+
+      WR_HARPOON(pCurrCard->ioPort+hp_semaphore,
+      (RD_HARPOON(pCurrCard->ioPort+hp_semaphore) & ~SCCB_MGR_ACTIVE));
+   }
+
+	if(pCurrCard->discQCount != 0)
+	{
+      currTar_Info = &sccbMgrTbl[p_card][p_sccb->TargID];
+		if(((pCurrCard->globalFlags & F_CONLUN_IO) &&
+			((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+		{
+			pCurrCard->discQCount--;
+			pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[p_sccb->Lun]] = NULL;
+		}
+		else
+		{
+			if(p_sccb->Sccb_tag)
+			{
+				pCurrCard->discQCount--;
+				pCurrCard->discQ_Tbl[p_sccb->Sccb_tag] = NULL;
+			}else
+			{
+				pCurrCard->discQCount--;
+				pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]] = NULL;
+			}
+		}
+
+	}
+   callback = (CALL_BK_FN)p_ucb->UCB_callback;
+   callback(p_ucb);
+   pCurrCard->globalFlags |= F_NEW_SCCB_CMD;
+   pCurrCard->currentSCCB = NULL;
+}
+
+
+
+
+#else
+
+   UCHAR i, SCSIcmd;
+   CALL_BK_FN callback;
+   PSCCBMgr_tar_info currTar_Info;
+
+   SCSIcmd = p_sccb->Cdb[0];
+
+
+   if (!(p_sccb->Sccb_XferState & F_ALL_XFERRED)) {
+
+	  if ((p_sccb->ControlByte & (SCCB_DATA_XFER_OUT | SCCB_DATA_XFER_IN)) &&
+		 (p_sccb->HostStatus == SCCB_COMPLETE)                             &&
+		 (p_sccb->TargetStatus != SSCHECK))
+
+		 if ((SCSIcmd == SCSI_READ)             ||
+			 (SCSIcmd == SCSI_WRITE)            ||
+			 (SCSIcmd == SCSI_READ_EXTENDED)    ||
+			 (SCSIcmd == SCSI_WRITE_EXTENDED)   ||
+			 (SCSIcmd == SCSI_WRITE_AND_VERIFY) ||
+			 (SCSIcmd == SCSI_START_STOP_UNIT)  ||
+			 (pCurrCard->globalFlags & F_NO_FILTER)
+			)
+			   p_sccb->HostStatus = SCCB_DATA_UNDER_RUN;
+	  }
+
+
+	if(p_sccb->SccbStatus == SCCB_IN_PROCESS)
+	{
+	   if (p_sccb->HostStatus || p_sccb->TargetStatus)
+		  p_sccb->SccbStatus = SCCB_ERROR;
+	   else
+		  p_sccb->SccbStatus = SCCB_SUCCESS;
+	}
+
+   if (p_sccb->Sccb_XferState & F_AUTO_SENSE) {
+
+	  p_sccb->CdbLength = p_sccb->Save_CdbLen;
+	  for (i=0; i < 6; i++) {
+		 p_sccb->Cdb[i] = p_sccb->Save_Cdb[i];
+		 }
+	  }
+
+   if ((p_sccb->OperationCode == RESIDUAL_SG_COMMAND) ||
+	  (p_sccb->OperationCode == RESIDUAL_COMMAND)) {
+
+		 utilUpdateResidual(p_sccb);
+		 }
+
+   pCurrCard->cmdCounter--;
+   if (!pCurrCard->cmdCounter) {
+
+	  if (pCurrCard->globalFlags & F_GREEN_PC) {
+		 WR_HARPOON(pCurrCard->ioPort+hp_clkctrl_0,(PWR_DWN | CLKCTRL_DEFAULT));
+		 WR_HARPOON(pCurrCard->ioPort+hp_sys_ctrl, STOP_CLK);
+		 }
+
+	  WR_HARPOON(pCurrCard->ioPort+hp_semaphore,
+	  (RD_HARPOON(pCurrCard->ioPort+hp_semaphore) & ~SCCB_MGR_ACTIVE));
+
+	  }
+
+	if(pCurrCard->discQCount != 0)
+	{
+      currTar_Info = &sccbMgrTbl[p_card][p_sccb->TargID];
+		if(((pCurrCard->globalFlags & F_CONLUN_IO) &&
+			((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+		{
+			pCurrCard->discQCount--;
+			pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[p_sccb->Lun]] = NULL;
+		}
+		else
+		{
+			if(p_sccb->Sccb_tag)
+			{
+				pCurrCard->discQCount--;
+				pCurrCard->discQ_Tbl[p_sccb->Sccb_tag] = NULL;
+			}else
+			{
+				pCurrCard->discQCount--;
+				pCurrCard->discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]] = NULL;
+			}
+		}
+
+	}
+
+	callback = (CALL_BK_FN)p_sccb->SccbCallback;
+   callback(p_sccb);
+   pCurrCard->globalFlags |= F_NEW_SCCB_CMD;
+   pCurrCard->currentSCCB = NULL;
+}
+#endif /* ( if FW_TYPE==...) */
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Disconnect
+ *
+ * Description: Add SCCB to our disconnect array.
+ *
+ *---------------------------------------------------------------------*/
+void queueDisconnect(PSCCB p_sccb, UCHAR p_card)
+{
+   PSCCBMgr_tar_info currTar_Info;
+
+	currTar_Info = &sccbMgrTbl[p_card][p_sccb->TargID];
+
+	if(((BL_Card[p_card].globalFlags & F_CONLUN_IO) &&
+		((currTar_Info->TarStatus & TAR_TAG_Q_MASK) != TAG_Q_TRYING)))
+	{
+		BL_Card[p_card].discQ_Tbl[currTar_Info->LunDiscQ_Idx[p_sccb->Lun]] = p_sccb;
+	}
+	else
+	{
+		if (p_sccb->Sccb_tag)
+		{
+			BL_Card[p_card].discQ_Tbl[p_sccb->Sccb_tag] = p_sccb;
+			sccbMgrTbl[p_card][p_sccb->TargID].TarLUNBusy[0] = FALSE;
+			sccbMgrTbl[p_card][p_sccb->TargID].TarTagQ_Cnt++;
+		}else
+		{
+			BL_Card[p_card].discQ_Tbl[currTar_Info->LunDiscQ_Idx[0]] = p_sccb;
+		}
+	}
+	BL_Card[p_card].currentSCCB = NULL;
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Flush SCCB
+ *
+ * Description: Flush all SCCB's back to the host driver for this target.
+ *
+ *---------------------------------------------------------------------*/
+
+void  queueFlushSccb(UCHAR p_card, UCHAR error_code)
+{
+   UCHAR qtag,thisTarg;
+   PSCCB currSCCB;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currSCCB = BL_Card[p_card].currentSCCB;
+	if(currSCCB != NULL)
+	{
+	   thisTarg = (UCHAR)currSCCB->TargID;
+   	currTar_Info = &sccbMgrTbl[p_card][thisTarg];
+
+	   for (qtag=0; qtag<QUEUE_DEPTH; qtag++) {
+
+		  if (BL_Card[p_card].discQ_Tbl[qtag] && 
+					(BL_Card[p_card].discQ_Tbl[qtag]->TargID == thisTarg))
+			 {
+
+			 BL_Card[p_card].discQ_Tbl[qtag]->HostStatus = (UCHAR)error_code;
+			
+			 queueCmdComplete(&BL_Card[p_card],BL_Card[p_card].discQ_Tbl[qtag], p_card);
+
+			 BL_Card[p_card].discQ_Tbl[qtag] = NULL;
+			 currTar_Info->TarTagQ_Cnt--;
+
+			 }
+		  }
+	}
+
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Flush Target SCCB
+ *
+ * Description: Flush all SCCB's back to the host driver for this target.
+ *
+ *---------------------------------------------------------------------*/
+
+void  queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code)
+{
+   UCHAR qtag;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currTar_Info = &sccbMgrTbl[p_card][thisTarg];
+
+   for (qtag=0; qtag<QUEUE_DEPTH; qtag++) {
+
+	  if (BL_Card[p_card].discQ_Tbl[qtag] && 
+				(BL_Card[p_card].discQ_Tbl[qtag]->TargID == thisTarg))
+		 {
+
+		 BL_Card[p_card].discQ_Tbl[qtag]->HostStatus = (UCHAR)error_code;
+
+		 queueCmdComplete(&BL_Card[p_card],BL_Card[p_card].discQ_Tbl[qtag], p_card);
+
+		 BL_Card[p_card].discQ_Tbl[qtag] = NULL;
+		 currTar_Info->TarTagQ_Cnt--;
+
+		 }
+	  }
+
+}
+
+
+
+
+
+void queueAddSccb(PSCCB p_SCCB, UCHAR p_card)
+{
+   PSCCBMgr_tar_info currTar_Info;
+   currTar_Info = &sccbMgrTbl[p_card][p_SCCB->TargID];
+
+   p_SCCB->Sccb_forwardlink = NULL;
+
+   p_SCCB->Sccb_backlink = currTar_Info->TarSelQ_Tail;
+
+   if (currTar_Info->TarSelQ_Cnt == 0) {
+
+	  currTar_Info->TarSelQ_Head = p_SCCB;
+	  }
+
+   else {
+
+	  currTar_Info->TarSelQ_Tail->Sccb_forwardlink = p_SCCB;
+	  }
+
+
+   currTar_Info->TarSelQ_Tail = p_SCCB;
+   currTar_Info->TarSelQ_Cnt++;
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Queue Find SCCB
+ *
+ * Description: Search the target select Queue for this SCCB, and
+ *              remove it if found.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR queueFindSccb(PSCCB p_SCCB, UCHAR p_card)
+{
+   PSCCB q_ptr;
+   PSCCBMgr_tar_info currTar_Info;
+
+   currTar_Info = &sccbMgrTbl[p_card][p_SCCB->TargID];
+
+   q_ptr = currTar_Info->TarSelQ_Head;
+
+   while(q_ptr != NULL) {
+
+	  if (q_ptr == p_SCCB) {
+
+
+		 if (currTar_Info->TarSelQ_Head == q_ptr) {
+
+			currTar_Info->TarSelQ_Head = q_ptr->Sccb_forwardlink;
+			}
+
+		 if (currTar_Info->TarSelQ_Tail == q_ptr) {
+
+			currTar_Info->TarSelQ_Tail = q_ptr->Sccb_backlink;
+			}
+
+		 if (q_ptr->Sccb_forwardlink != NULL) {
+			q_ptr->Sccb_forwardlink->Sccb_backlink = q_ptr->Sccb_backlink;
+			}
+
+		 if (q_ptr->Sccb_backlink != NULL) {
+			q_ptr->Sccb_backlink->Sccb_forwardlink = q_ptr->Sccb_forwardlink;
+			}
+
+		 currTar_Info->TarSelQ_Cnt--;
+
+		 return(TRUE);
+		 }
+
+	  else {
+		 q_ptr = q_ptr->Sccb_forwardlink;
+		 }
+	  }
+
+
+   return(FALSE);
+
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Utility Update Residual Count
+ *
+ * Description: Update the XferCnt to the remaining byte count.
+ *              If we transferred all the data then just write zero.
+ *              If Non-SG transfer then report Total Cnt - Actual Transfer
+ *              Cnt.  For SG transfers add the count fields of all
+ *              remaining SG elements, as well as any partial remaining
+ *              element.
+ *
+ *---------------------------------------------------------------------*/
+
+void  utilUpdateResidual(PSCCB p_SCCB)
+{
+   ULONG partial_cnt;
+   UINT  sg_index;
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+   ULONG far *sg_ptr;
+#else
+   ULONG *sg_ptr;
+#endif
+
+   if (p_SCCB->Sccb_XferState & F_ALL_XFERRED) {
+
+	  p_SCCB->DataLength = 0x0000;
+	  }
+
+   else if (p_SCCB->Sccb_XferState & F_SG_XFER) {
+
+		 partial_cnt = 0x0000;
+
+		 sg_index = p_SCCB->Sccb_sgseg;
+
+#if defined(COMPILER_16_BIT) && !defined(DOS)
+		 sg_ptr = (ULONG far *)p_SCCB->DataPointer;
+#else
+		 sg_ptr = (ULONG *)p_SCCB->DataPointer;
+#endif
+
+		 if (p_SCCB->Sccb_SGoffset) {
+
+			partial_cnt = p_SCCB->Sccb_SGoffset;
+			sg_index++;
+			}
+
+		 while ( ((ULONG)sg_index * (ULONG)SG_ELEMENT_SIZE) <
+			p_SCCB->DataLength ) {
+
+			partial_cnt += *(sg_ptr+(sg_index * 2));
+			sg_index++;
+			}
+
+		 p_SCCB->DataLength = partial_cnt;
+		 }
+
+	  else {
+
+		 p_SCCB->DataLength -= p_SCCB->Sccb_ATC;
+		 }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Wait 1 Second
+ *
+ * Description: Wait for 1 second.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void Wait1Second(USHORT p_port)
+#else
+void Wait1Second(ULONG p_port)
+#endif
+{
+   UCHAR i;
+
+   for(i=0; i < 4; i++) {
+
+	  Wait(p_port, TO_250ms);
+
+	  if ((RD_HARPOON(p_port+hp_scsictrl_0) & SCSI_RST))
+		 break;
+
+	  if((RDW_HARPOON((p_port+hp_intstat)) & SCAM_SEL))
+		 break;
+	  }
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Wait
+ *
+ * Description: Wait the desired delay.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void Wait(USHORT p_port, UCHAR p_delay)
+#else
+void Wait(ULONG p_port, UCHAR p_delay)
+#endif
+{
+   UCHAR old_timer;
+   UCHAR green_flag;
+
+   old_timer = RD_HARPOON(p_port+hp_seltimeout);
+
+   green_flag=RD_HARPOON(p_port+hp_clkctrl_0);
+   WR_HARPOON(p_port+hp_clkctrl_0, CLKCTRL_DEFAULT);
+
+   WR_HARPOON(p_port+hp_seltimeout,p_delay);
+   WRW_HARPOON((p_port+hp_intstat), TIMEOUT);
+   WRW_HARPOON((p_port+hp_intena), (default_intena & ~TIMEOUT));
+
+
+   WR_HARPOON(p_port+hp_portctrl_0,
+	  (RD_HARPOON(p_port+hp_portctrl_0) | START_TO));
+
+   while (!(RDW_HARPOON((p_port+hp_intstat)) & TIMEOUT)) {
+
+	  if ((RD_HARPOON(p_port+hp_scsictrl_0) & SCSI_RST))
+		 break;
+
+	  if ((RDW_HARPOON((p_port+hp_intstat)) & SCAM_SEL))
+		 break;
+	  }
+
+   WR_HARPOON(p_port+hp_portctrl_0,
+	  (RD_HARPOON(p_port+hp_portctrl_0) & ~START_TO));
+
+   WRW_HARPOON((p_port+hp_intstat), TIMEOUT);
+   WRW_HARPOON((p_port+hp_intena), default_intena);
+
+   WR_HARPOON(p_port+hp_clkctrl_0,green_flag);
+
+   WR_HARPOON(p_port+hp_seltimeout,old_timer);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Enable/Disable Write to EEPROM
+ *
+ * Description: The EEPROM must first be enabled for writes
+ *              A total of 9 clocks are needed.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void utilEEWriteOnOff(USHORT p_port,UCHAR p_mode)
+#else
+void utilEEWriteOnOff(ULONG p_port,UCHAR p_mode)
+#endif
+{
+   UCHAR ee_value;
+
+   ee_value = (UCHAR)(RD_HARPOON(p_port+hp_ee_ctrl) & (EXT_ARB_ACK | SCSI_TERM_ENA_H));
+
+   if (p_mode)
+
+	  utilEESendCmdAddr(p_port, EWEN, EWEN_ADDR);
+
+   else
+
+
+	  utilEESendCmdAddr(p_port, EWDS, EWDS_ADDR);
+
+   WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS)); /*Turn off CS */
+   WR_HARPOON(p_port+hp_ee_ctrl, ee_value);       /*Turn off Master Select */
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Write EEPROM
+ *
+ * Description: Write a word to the EEPROM at the specified
+ *              address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr)
+#else
+void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr)
+#endif
+{
+
+   UCHAR ee_value;
+   USHORT i;
+
+   ee_value = (UCHAR)((RD_HARPOON(p_port+hp_ee_ctrl) & (EXT_ARB_ACK | SCSI_TERM_ENA_H))|
+		   (SEE_MS | SEE_CS));
+
+
+
+   utilEESendCmdAddr(p_port, EE_WRITE, ee_addr);
+
+
+   ee_value |= (SEE_MS + SEE_CS);
+
+   for(i = 0x8000; i != 0; i>>=1) {
+
+	  if (i & ee_data)
+	 ee_value |= SEE_DO;
+	  else
+	 ee_value &= ~SEE_DO;
+
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value |= SEE_CLK;          /* Clock  data! */
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value &= ~SEE_CLK;
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  }
+   ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H);
+   WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS));
+
+   Wait(p_port, TO_10ms);
+
+   WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS | SEE_CS)); /* Set CS to EEPROM */
+   WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS));       /* Turn off CS */
+   WR_HARPOON(p_port+hp_ee_ctrl, ee_value);       /* Turn off Master Select */
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Read EEPROM
+ *
+ * Description: Read a word from the EEPROM at the desired
+ *              address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT utilEERead(USHORT p_port, USHORT ee_addr)
+#else
+USHORT utilEERead(ULONG p_port, USHORT ee_addr)
+#endif
+{
+   USHORT i, ee_data1, ee_data2;
+
+	i = 0;
+	ee_data1 = utilEEReadOrg(p_port, ee_addr);
+	do
+	{
+		ee_data2 = utilEEReadOrg(p_port, ee_addr);
+
+		if(ee_data1 == ee_data2)
+			return(ee_data1);
+
+		ee_data1 = ee_data2;
+		i++;
+
+	}while(i < 4);
+
+	return(ee_data1);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Read EEPROM Original 
+ *
+ * Description: Read a word from the EEPROM at the desired
+ *              address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr)
+#else
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr)
+#endif
+{
+
+   UCHAR ee_value;
+   USHORT i, ee_data;
+
+   ee_value = (UCHAR)((RD_HARPOON(p_port+hp_ee_ctrl) & (EXT_ARB_ACK | SCSI_TERM_ENA_H))|
+		   (SEE_MS | SEE_CS));
+
+
+   utilEESendCmdAddr(p_port, EE_READ, ee_addr);
+
+
+   ee_value |= (SEE_MS + SEE_CS);
+   ee_data = 0;
+
+   for(i = 1; i <= 16; i++) {
+
+	  ee_value |= SEE_CLK;          /* Clock  data! */
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value &= ~SEE_CLK;
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+
+	  ee_data <<= 1;
+
+	  if (RD_HARPOON(p_port+hp_ee_ctrl) & SEE_DI)
+		 ee_data |= 1;
+	  }
+
+   ee_value &= ~(SEE_MS + SEE_CS);
+   WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS)); /*Turn off CS */
+   WR_HARPOON(p_port+hp_ee_ctrl, ee_value);   /*Turn off Master Select */
+
+   return(ee_data);
+}
+
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Send EE command and Address to the EEPROM
+ *
+ * Description: Transfers the correct command and sends the address
+ *              to the eeprom.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+void utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr)
+#else
+void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr)
+#endif
+{
+   UCHAR ee_value;
+   UCHAR narrow_flg;
+
+   USHORT i;
+
+
+   narrow_flg= (UCHAR)(RD_HARPOON(p_port+hp_page_ctrl) & NARROW_SCSI_CARD);
+
+
+   ee_value = SEE_MS;
+   WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+
+   ee_value |= SEE_CS;                             /* Set CS to EEPROM */
+   WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+
+
+   for(i = 0x04; i != 0; i>>=1) {
+
+	  if (i & ee_cmd)
+		 ee_value |= SEE_DO;
+	  else
+		 ee_value &= ~SEE_DO;
+
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value |= SEE_CLK;                         /* Clock  data! */
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value &= ~SEE_CLK;
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  }
+
+
+   if (narrow_flg)
+	  i = 0x0080;
+
+   else
+	  i = 0x0200;
+
+
+   while (i != 0) {
+
+	  if (i & ee_addr)
+		 ee_value |= SEE_DO;
+	  else
+		 ee_value &= ~SEE_DO;
+
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value |= SEE_CLK;                         /* Clock  data! */
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  ee_value &= ~SEE_CLK;
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+	  WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+
+	  i >>= 1;
+	  }
+}
+
+USHORT CalcCrc16(UCHAR buffer[])
+{
+   USHORT crc=0;
+	int i,j;
+   USHORT ch;
+   for (i=0; i < ID_STRING_LENGTH; i++)
+   {
+      ch = (USHORT) buffer[i];
+	   for(j=0; j < 8; j++)
+	   {
+		   if ((crc ^ ch) & 1)
+            crc = (crc >> 1) ^ CRCMASK;
+		   else
+            crc >>= 1;
+		   ch >>= 1;
+	   }
+   }
+	return(crc);
+}
+
+UCHAR CalcLrc(UCHAR buffer[])
+{
+	int i;
+	UCHAR lrc;
+	lrc = 0;
+	for(i = 0; i < ID_STRING_LENGTH; i++)
+		lrc ^= buffer[i];
+	return(lrc);
+}
+
+
+
+/*
+  The following inline definitions avoid type conflicts.
+*/
+
+static inline unsigned char
+FlashPoint__ProbeHostAdapter(struct FlashPoint_Info *FlashPointInfo)
+{
+  return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+
+static inline FlashPoint_CardHandle_T
+FlashPoint__HardwareResetHostAdapter(struct FlashPoint_Info *FlashPointInfo)
+{
+  return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+static inline void
+FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle)
+{
+  FlashPoint_ReleaseHostAdapter(CardHandle);
+}
+
+
+static inline void
+FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, struct BusLogic_CCB *CCB)
+{
+  FlashPoint_StartCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline void
+FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, struct BusLogic_CCB *CCB)
+{
+  FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline boolean
+FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_InterruptPending(CardHandle);
+}
+
+
+static inline int
+FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle)
+{
+  return FlashPoint_HandleInterrupt(CardHandle);
+}
+
+
+#define FlashPoint_ProbeHostAdapter	    FlashPoint__ProbeHostAdapter
+#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter
+#define FlashPoint_ReleaseHostAdapter	    FlashPoint__ReleaseHostAdapter
+#define FlashPoint_StartCCB		    FlashPoint__StartCCB
+#define FlashPoint_AbortCCB		    FlashPoint__AbortCCB
+#define FlashPoint_InterruptPending	    FlashPoint__InterruptPending
+#define FlashPoint_HandleInterrupt	    FlashPoint__HandleInterrupt
+
+
+/*
+  FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous
+  Offset, and Wide Transfers Active information for TargetID on CardHandle.
+*/
+
+void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle,
+				  int TargetID,
+				  unsigned char *SynchronousPeriod,
+				  unsigned char *SynchronousOffset,
+				  unsigned char *WideTransfersActive)
+{
+  SCCBMGR_TAR_INFO *TargetInfo =
+    &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID];
+  if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0)
+    {
+      *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1);
+      *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET;
+    }
+  else
+    {
+      *SynchronousPeriod = 0;
+      *SynchronousOffset = 0;
+    }
+  *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1);
+}
+
+
+#else  /* CONFIG_SCSI_OMIT_FLASHPOINT */
+
+
+/*
+  Define prototypes for the FlashPoint SCCB Manager Functions.
+*/
+
+extern unsigned char FlashPoint_ProbeHostAdapter(struct FlashPoint_Info *);
+extern FlashPoint_CardHandle_T
+       FlashPoint_HardwareResetHostAdapter(struct FlashPoint_Info *);
+extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *);
+extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, struct BusLogic_CCB *);
+extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
+extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
+extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
+extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T,
+					 int, unsigned char *,
+					 unsigned char *, unsigned char *);
+
+
+#endif /* CONFIG_SCSI_OMIT_FLASHPOINT */
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
new file mode 100644
index 0000000..d22b32f
--- /dev/null
+++ b/drivers/scsi/Kconfig
@@ -0,0 +1,1802 @@
+menu "SCSI device support"
+
+config SCSI
+	tristate "SCSI device support"
+	---help---
+	  If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or
+	  any other SCSI device under Linux, say Y and make sure that you know
+	  the name of your SCSI host adapter (the card inside your computer
+	  that "speaks" the SCSI protocol, also called SCSI controller),
+	  because you will be asked for it.
+
+	  You also need to say Y here if you have a device which speaks
+	  the SCSI protocol.  Examples of this include the parallel port
+	  version of the IOMEGA ZIP drive, USB storage devices, Fibre
+	  Channel, FireWire storage and the IDE-SCSI emulation driver.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>.
+	  The module will be called scsi_mod.
+
+	  However, do not compile this as a module if your root file system
+	  (the one containing the directory /) is located on a SCSI device.
+
+config SCSI_PROC_FS
+	bool "legacy /proc/scsi/ support"
+	depends on SCSI && PROC_FS
+	default y
+	---help---
+	  This option enables support for the various files in
+	  /proc/scsi.  In Linux 2.6 this has been superceeded by
+	  files in sysfs but many legacy applications rely on this.
+
+	  If unusure say Y.
+
+comment "SCSI support type (disk, tape, CD-ROM)"
+	depends on SCSI
+
+config BLK_DEV_SD
+	tristate "SCSI disk support"
+	depends on SCSI
+	---help---
+	  If you want to use SCSI hard disks, Fibre Channel disks,
+	  USB storage or the SCSI or parallel port version of
+	  the IOMEGA ZIP drive, say Y and read the SCSI-HOWTO,
+	  the Disk-HOWTO and the Multi-Disk-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. This is NOT for SCSI
+	  CD-ROMs.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>.
+	  The module will be called sd_mod.
+
+	  Do not compile this driver as a module if your root file system
+	  (the one containing the directory /) is located on a SCSI disk.
+	  In this case, do not compile the driver for your SCSI host adapter
+	  (below) as a module either.
+
+config CHR_DEV_ST
+	tristate "SCSI tape support"
+	depends on SCSI
+	---help---
+	  If you want to use a SCSI tape drive under Linux, say Y and read the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, and
+	  <file:Documentation/scsi/st.txt> in the kernel source.  This is NOT
+	  for SCSI CD-ROMs.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>. The module will be called st.
+
+config CHR_DEV_OSST
+	tristate "SCSI OnStream SC-x0 tape support"
+	depends on SCSI
+	---help---
+	  The OnStream SC-x0 SCSI tape drives can not be driven by the
+	  standard st driver, but instead need this special osst driver and
+	  use the  /dev/osstX char device nodes (major 206).  Via usb-storage
+	  and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
+	  as well.  Note that there is also a second generation of OnStream
+	  tape drives (ADR-x0) that supports the standard SCSI-2 commands for
+	  tapes (QIC-157) and can be driven by the standard driver st.
+	  For more information, you may have a look at the SCSI-HOWTO
+	  <http://www.tldp.org/docs.html#howto>  and
+	  <file:Documentation/scsi/osst.txt>  in the kernel source.
+	  More info on the OnStream driver may be found on
+	  <http://linux1.onstream.nl/test/>
+	  Please also have a look at the standard st docu, as most of it
+	  applies to osst as well.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>. The module will be called osst.
+
+config BLK_DEV_SR
+	tristate "SCSI CDROM support"
+	depends on SCSI
+	---help---
+	  If you want to use a SCSI or FireWire CD-ROM under Linux,
+	  say Y and read the SCSI-HOWTO and the CDROM-HOWTO at
+	  <http://www.tldp.org/docs.html#howto>. Also make sure to say
+	  Y or M to "ISO 9660 CD-ROM file system support" later.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>.
+	  The module will be called sr_mod.
+
+config BLK_DEV_SR_VENDOR
+	bool "Enable vendor-specific extensions (for SCSI CDROM)"
+	depends on BLK_DEV_SR
+	help
+	  This enables the usage of vendor specific SCSI commands. This is
+	  required to support multisession CDs with old NEC/TOSHIBA cdrom
+	  drives (and HP Writers). If you have such a drive and get the first
+	  session only, try saying Y here; everybody else says N.
+
+config CHR_DEV_SG
+	tristate "SCSI generic support"
+	depends on SCSI
+	---help---
+	  If you want to use SCSI scanners, synthesizers or CD-writers or just
+	  about anything having "SCSI" in its name other than hard disks,
+	  CD-ROMs or tapes, say Y here. These won't be supported by the kernel
+	  directly, so you need some additional software which knows how to
+	  talk to these devices using the SCSI protocol:
+
+	  For scanners, look at SANE (<http://www.mostang.com/sane/>). For CD
+	  writer software look at Cdrtools
+	  (<http://www.fokus.gmd.de/research/cc/glone/employees/joerg.schilling/private/cdrecord.html>)
+	  and for burning a "disk at once": CDRDAO
+	  (<http://cdrdao.sourceforge.net/>). Cdparanoia is a high
+	  quality digital reader of audio CDs (<http://www.xiph.org/paranoia/>).
+	  For other devices, it's possible that you'll have to write the
+	  driver software yourself. Please read the file
+	  <file:Documentation/scsi/scsi-generic.txt> for more information.
+
+	  To compile this driver as a module, choose M here and read
+	  <file:Documentation/scsi/scsi.txt>. The module will be called sg.
+
+	  If unsure, say N.
+
+comment "Some SCSI devices (e.g. CD jukebox) support multiple LUNs"
+	depends on SCSI
+
+config SCSI_MULTI_LUN
+	bool "Probe all LUNs on each SCSI device"
+	depends on SCSI
+	help
+	  If you have a SCSI device that supports more than one LUN (Logical
+	  Unit Number), e.g. a CD jukebox, and only one LUN is detected, you
+	  can say Y here to force the SCSI driver to probe for multiple LUNs.
+	  A SCSI device with multiple LUNs acts logically like multiple SCSI
+	  devices. The vast majority of SCSI devices have only one LUN, and
+	  so most people can say N here. The max_luns boot/module parameter 
+	  allows to override this setting.
+
+config SCSI_CONSTANTS
+	bool "Verbose SCSI error reporting (kernel size +=12K)"
+	depends on SCSI
+	help
+	  The error messages regarding your SCSI hardware will be easier to
+	  understand if you say Y here; it will enlarge your kernel by about
+	  12 KB. If in doubt, say Y.
+
+config SCSI_LOGGING
+	bool "SCSI logging facility"
+	depends on SCSI
+	---help---
+	  This turns on a logging facility that can be used to debug a number
+	  of SCSI related problems.
+
+	  If you say Y here, no logging output will appear by default, but you
+	  can enable logging by saying Y to "/proc file system support" and
+	  "Sysctl support" below and executing the command
+
+	  echo "scsi log token [level]" > /proc/scsi/scsi
+
+	  at boot time after the /proc file system has been mounted.
+
+	  There are a number of things that can be used for 'token' (you can
+	  find them in the source: <file:drivers/scsi/scsi.c>), and this
+	  allows you to select the types of information you want, and the
+	  level allows you to select the level of verbosity.
+
+	  If you say N here, it may be harder to track down some types of SCSI
+	  problems. If you say Y here your kernel will be somewhat larger, but
+	  there should be no noticeable performance impact as long as you have
+	  logging turned off.
+
+menu "SCSI Transport Attributes"
+	depends on SCSI
+
+config SCSI_SPI_ATTRS
+	tristate "Parallel SCSI (SPI) Transport Attributes"
+	depends on SCSI
+	help
+	  If you wish to export transport-specific information about
+	  each attached SCSI device to sysfs, say Y.  Otherwise, say N.
+
+config SCSI_FC_ATTRS
+	tristate "FiberChannel Transport Attributes"
+	depends on SCSI
+	help
+	  If you wish to export transport-specific information about
+	  each attached FiberChannel device to sysfs, say Y.
+	  Otherwise, say N.
+
+config SCSI_ISCSI_ATTRS
+	tristate "iSCSI Transport Attributes"
+	depends on SCSI
+	help
+	  If you wish to export transport-specific information about
+	  each attached iSCSI device to sysfs, say Y.
+	  Otherwise, say N.
+
+endmenu
+
+menu "SCSI low-level drivers"
+	depends on SCSI!=n
+
+config SGIWD93_SCSI
+	tristate "SGI WD93C93 SCSI Driver"
+	depends on SGI_IP22 && SCSI
+  	help
+	  If you have a Western Digital WD93 SCSI controller on
+	  an SGI MIPS system, say Y.  Otherwise, say N.
+
+config SCSI_DECNCR
+	tristate "DEC NCR53C94 Scsi Driver"
+	depends on MACH_DECSTATION && SCSI && TC
+	help
+	  Say Y here to support the NCR53C94 SCSI controller chips on IOASIC
+	  based TURBOchannel DECstations and TURBOchannel PMAZ-A cards.
+
+config SCSI_DECSII
+	tristate "DEC SII Scsi Driver"
+	depends on MACH_DECSTATION && SCSI && MIPS32
+
+config BLK_DEV_3W_XXXX_RAID
+	tristate "3ware 5/6/7/8xxx ATA-RAID support"
+	depends on PCI && SCSI
+	help
+	  3ware is the only hardware ATA-Raid product in Linux to date.
+	  This card is 2,4, or 8 channel master mode support only.
+	  SCSI support required!!!
+
+	  <http://www.3ware.com/>
+
+	  Please read the comments at the top of
+	  <file:drivers/scsi/3w-xxxx.c>.
+
+config SCSI_3W_9XXX
+	tristate "3ware 9xxx SATA-RAID support"
+	depends on PCI && SCSI
+	help
+	  This driver supports the 9000 series 3ware SATA-RAID cards.
+
+	  <http://www.amcc.com>
+
+	  Please read the comments at the top of
+	  <file:drivers/scsi/3w-9xxx.c>.
+
+config SCSI_7000FASST
+	tristate "7000FASST SCSI support"
+	depends on ISA && SCSI
+	help
+	  This driver supports the Western Digital 7000 SCSI host adapter
+	  family.  Some information is in the source:
+	  <file:drivers/scsi/wd7000.c>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wd7000.
+
+config SCSI_ACARD
+	tristate "ACARD SCSI support"
+	depends on PCI && SCSI
+	help
+	  This driver supports the ACARD SCSI host adapter.
+	  Support Chip <ATP870 ATP876 ATP880 ATP885>
+	  To compile this driver as a module, choose M here: the
+	  module will be called atp870u.
+
+config SCSI_AHA152X
+	tristate "Adaptec AHA152X/2825 support"
+	depends on ISA && SCSI && !64BIT
+	---help---
+	  This is a driver for the AHA-1510, AHA-1520, AHA-1522, and AHA-2825
+	  SCSI host adapters. It also works for the AVA-1505, but the IRQ etc.
+	  must be manually specified in this case.
+
+	  It is explained in section 3.3 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>. You might also want to
+	  read the file <file:Documentation/scsi/aha152x.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aha152x.
+
+config SCSI_AHA1542
+	tristate "Adaptec AHA1542 support"
+	depends on ISA && SCSI
+	---help---
+	  This is support for a SCSI host adapter.  It is explained in section
+	  3.4 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Note that Trantor was
+	  purchased by Adaptec, and some former Trantor products are being
+	  sold under the Adaptec name.  If it doesn't work out of the box, you
+	  may have to change some settings in <file:drivers/scsi/aha1542.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aha1542.
+
+config SCSI_AHA1740
+	tristate "Adaptec AHA1740 support"
+	depends on EISA && SCSI
+	---help---
+	  This is support for a SCSI host adapter.  It is explained in section
+	  3.5 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/aha1740.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aha1740.
+
+config SCSI_AACRAID
+	tristate "Adaptec AACRAID support"
+	depends on SCSI && PCI
+
+source "drivers/scsi/aic7xxx/Kconfig.aic7xxx"
+
+config SCSI_AIC7XXX_OLD
+	tristate "Adaptec AIC7xxx support (old driver)"
+	depends on (ISA || EISA || PCI ) && SCSI
+	help
+	  WARNING This driver is an older aic7xxx driver and is no longer
+	  under active development.  Adaptec, Inc. is writing a new driver to
+	  take the place of this one, and it is recommended that whenever
+	  possible, people should use the new Adaptec written driver instead
+	  of this one.  This driver will eventually be phased out entirely.
+
+	  This is support for the various aic7xxx based Adaptec SCSI
+	  controllers. These include the 274x EISA cards; 284x VLB cards;
+	  2902, 2910, 293x, 294x, 394x, 3985 and several other PCI and
+	  motherboard based SCSI controllers from Adaptec. It does not support
+	  the AAA-13x RAID controllers from Adaptec, nor will it likely ever
+	  support them. It does not support the 2920 cards from Adaptec that
+	  use the Future Domain SCSI controller chip. For those cards, you
+	  need the "Future Domain 16xx SCSI support" driver.
+
+	  In general, if the controller is based on an Adaptec SCSI controller
+	  chip from the aic777x series or the aic78xx series, this driver
+	  should work. The only exception is the 7810 which is specifically
+	  not supported (that's the RAID controller chip on the AAA-13x
+	  cards).
+
+	  Note that the AHA2920 SCSI host adapter is *not* supported by this
+	  driver; choose "Future Domain 16xx SCSI support" instead if you have
+	  one of those.
+
+	  Information on the configuration options for this controller can be
+	  found by checking the help file for each of the available
+	  configuration options. You should read
+	  <file:Documentation/scsi/aic7xxx_old.txt> at a minimum before
+	  contacting the maintainer with any questions.  The SCSI-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>, can also
+	  be of great help.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aic7xxx_old.
+
+source "drivers/scsi/aic7xxx/Kconfig.aic79xx"
+
+# All the I2O code and drivers do not seem to be 64bit safe.
+config SCSI_DPT_I2O
+	tristate "Adaptec I2O RAID support "
+	depends on !64BIT && SCSI && PCI
+	help
+	  This driver supports all of Adaptec's I2O based RAID controllers as 
+	  well as the DPT SmartRaid V cards.  This is an Adaptec maintained
+	  driver by Deanna Bonds.  See <file:Documentation/scsi/dpti.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dpt_i2o.
+
+config SCSI_ADVANSYS
+	tristate "AdvanSys SCSI support"
+	depends on (ISA || EISA || PCI) && SCSI && BROKEN
+	help
+	  This is a driver for all SCSI host adapters manufactured by
+	  AdvanSys. It is documented in the kernel source in
+	  <file:drivers/scsi/advansys.c>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called advansys.
+
+config SCSI_IN2000
+	tristate "Always IN2000 SCSI support"
+	depends on ISA && SCSI
+	help
+	  This is support for an ISA bus SCSI host adapter.  You'll find more
+	  information in <file:Documentation/scsi/in2000.txt>. If it doesn't work
+	  out of the box, you may have to change the jumpers for IRQ or
+	  address selection.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called in2000.
+
+source "drivers/scsi/megaraid/Kconfig.megaraid"
+
+config SCSI_SATA
+	bool "Serial ATA (SATA) support"
+	depends on SCSI
+	help
+	  This driver family supports Serial ATA host controllers
+	  and devices.
+
+	  If unsure, say N.
+
+config SCSI_SATA_AHCI
+	tristate "AHCI SATA support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for AHCI Serial ATA.
+
+	  If unsure, say N.
+
+config SCSI_SATA_SVW
+	tristate "ServerWorks Frodo / Apple K2 SATA support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for Broadcom/Serverworks/Apple K2
+	  SATA support.
+
+	  If unsure, say N.
+
+config SCSI_ATA_PIIX
+	tristate "Intel PIIX/ICH SATA support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for ICH5 Serial ATA.
+	  If PATA support was enabled previously, this enables
+	  support for select Intel PIIX/ICH PATA host controllers.
+
+	  If unsure, say N.
+
+config SCSI_SATA_NV
+	tristate "NVIDIA SATA support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for NVIDIA Serial ATA.
+
+	  If unsure, say N.
+
+config SCSI_SATA_PROMISE
+	tristate "Promise SATA TX2/TX4 support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for Promise Serial ATA TX2/TX4.
+
+	  If unsure, say N.
+
+config SCSI_SATA_QSTOR
+	tristate "Pacific Digital SATA QStor support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for Pacific Digital Serial ATA QStor.
+
+	  If unsure, say N.
+
+config SCSI_SATA_SX4
+	tristate "Promise SATA SX4 support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for Promise Serial ATA SX4.
+
+	  If unsure, say N.
+
+config SCSI_SATA_SIL
+	tristate "Silicon Image SATA support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for Silicon Image Serial ATA.
+
+	  If unsure, say N.
+
+config SCSI_SATA_SIS
+	tristate "SiS 964/180 SATA support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for SiS Serial ATA 964/180.
+
+	  If unsure, say N.
+
+config SCSI_SATA_ULI
+	tristate "ULi Electronics SATA support"
+	depends on SCSI_SATA && PCI && EXPERIMENTAL
+	help
+	  This option enables support for ULi Electronics SATA.
+
+	  If unsure, say N.
+
+config SCSI_SATA_VIA
+	tristate "VIA SATA support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for VIA Serial ATA.
+
+	  If unsure, say N.
+
+config SCSI_SATA_VITESSE
+	tristate "VITESSE VSC-7174 SATA support"
+	depends on SCSI_SATA && PCI
+	help
+	  This option enables support for Vitesse VSC7174 Serial ATA.
+
+	  If unsure, say N.
+
+config SCSI_BUSLOGIC
+	tristate "BusLogic SCSI support"
+	depends on (PCI || ISA || MCA) && SCSI && (BROKEN || !SPARC64)
+	---help---
+	  This is support for BusLogic MultiMaster and FlashPoint SCSI Host
+	  Adapters. Consult the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, and the files
+	  <file:Documentation/scsi/BusLogic.txt> and
+	  <file:Documentation/scsi/FlashPoint.txt> for more information.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called BusLogic.
+
+config SCSI_OMIT_FLASHPOINT
+	bool "Omit FlashPoint support"
+	depends on SCSI_BUSLOGIC
+	help
+	  This option allows you to omit the FlashPoint support from the
+	  BusLogic SCSI driver. The FlashPoint SCCB Manager code is
+	  substantial, so users of MultiMaster Host Adapters may wish to omit
+	  it.
+
+#
+# This is marked broken because it uses over 4kB of stack in
+# just two routines:
+#     2076  CpqTsProcessIMQEntry
+#     2052  PeekIMQEntry
+#
+config SCSI_CPQFCTS
+	tristate "Compaq Fibre Channel 64-bit/66Mhz HBA support"
+	depends on PCI && SCSI && BROKEN
+	help
+	  Say Y here to compile in support for the Compaq StorageWorks Fibre
+	  Channel 64-bit/66Mhz Host Bus Adapter.
+
+config SCSI_DMX3191D
+	tristate "DMX3191D SCSI support"
+	depends on PCI && SCSI
+	help
+	  This is support for Domex DMX3191D SCSI Host Adapters.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dmx3191d.
+
+config SCSI_DTC3280
+	tristate "DTC3180/3280 SCSI support"
+	depends on ISA && SCSI
+	help
+	  This is support for DTC 3180/3280 SCSI Host Adapters.  Please read
+	  the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>, and the file
+	  <file:Documentation/scsi/dtc3x80.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dtc.
+
+config SCSI_EATA
+	tristate "EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support"
+	depends on (ISA || EISA || PCI) && SCSI && (BROKEN || !SPARC64)
+	---help---
+	  This driver supports all EATA/DMA-compliant SCSI host adapters.  DPT
+	  ISA and all EISA I/O addresses are probed looking for the "EATA"
+	  signature. The addresses of all the PCI SCSI controllers reported
+          by the PCI subsystem are probed as well.
+
+	  You want to read the start of <file:drivers/scsi/eata.c> and the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called eata.
+
+config SCSI_EATA_TAGGED_QUEUE
+	bool "enable tagged command queueing"
+	depends on SCSI_EATA
+	help
+	  This is a feature of SCSI-2 which improves performance: the host
+	  adapter can send several SCSI commands to a device's queue even if
+	  previous commands haven't finished yet.
+	  This is equivalent to the "eata=tc:y" boot option.
+
+config SCSI_EATA_LINKED_COMMANDS
+	bool "enable elevator sorting"
+	depends on SCSI_EATA
+	help
+	  This option enables elevator sorting for all probed SCSI disks and
+	  CD-ROMs. It definitely reduces the average seek distance when doing
+	  random seeks, but this does not necessarily result in a noticeable
+	  performance improvement: your mileage may vary...
+	  This is equivalent to the "eata=lc:y" boot option.
+
+config SCSI_EATA_MAX_TAGS
+	int "maximum number of queued commands"
+	depends on SCSI_EATA
+	default "16"
+	help
+	  This specifies how many SCSI commands can be maximally queued for
+	  each probed SCSI device. You should reduce the default value of 16
+	  only if you have disks with buggy or limited tagged command support.
+	  Minimum is 2 and maximum is 62. This value is also the window size
+	  used by the elevator sorting option above. The effective value used
+	  by the driver for each probed SCSI device is reported at boot time.
+	  This is equivalent to the "eata=mq:8" boot option.
+
+config SCSI_EATA_PIO
+	tristate "EATA-PIO (old DPT PM2001, PM2012A) support"
+	depends on (ISA || EISA || PCI) && SCSI && BROKEN
+	---help---
+	  This driver supports all EATA-PIO protocol compliant SCSI Host
+	  Adapters like the DPT PM2001 and the PM2012A.  EATA-DMA compliant
+	  host adapters could also use this driver but are discouraged from
+	  doing so, since this driver only supports hard disks and lacks
+	  numerous features.  You might want to have a look at the SCSI-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called eata_pio.
+
+config SCSI_FUTURE_DOMAIN
+	tristate "Future Domain 16xx SCSI/AHA-2920A support"
+	depends on (ISA || PCI) && SCSI
+	---help---
+	  This is support for Future Domain's 16-bit SCSI host adapters
+	  (TMC-1660/1680, TMC-1650/1670, TMC-3260, TMC-1610M/MER/MEX) and
+	  other adapters based on the Future Domain chipsets (Quantum
+	  ISA-200S, ISA-250MG; Adaptec AHA-2920A; and at least one IBM board).
+	  It is explained in section 3.7 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  NOTE: Newer Adaptec AHA-2920C boards use the Adaptec AIC-7850 chip
+	  and should use the aic7xxx driver ("Adaptec AIC7xxx chipset SCSI
+	  controller support"). This Future Domain driver works with the older
+	  Adaptec AHA-2920A boards with a Future Domain chip on them.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fdomain.
+
+config SCSI_FD_MCS
+	tristate "Future Domain MCS-600/700 SCSI support"
+	depends on MCA_LEGACY && SCSI
+	---help---
+	  This is support for Future Domain MCS 600/700 MCA SCSI adapters.
+	  Some PS/2 computers are equipped with IBM Fast SCSI Adapter/A which
+	  is identical to the MCS 700 and hence also supported by this driver.
+	  This driver also supports the Reply SB16/SCSI card (the SCSI part).
+	  It supports multiple adapters in the same system.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fd_mcs.
+
+config SCSI_GDTH
+	tristate "Intel/ICP (former GDT SCSI Disk Array) RAID Controller support"
+	depends on (ISA || EISA || PCI) && SCSI && (BROKEN || !SPARC64)
+	---help---
+	  Formerly called GDT SCSI Disk Array Controller Support.
+
+	  This is a driver for RAID/SCSI Disk Array Controllers (EISA/ISA/PCI) 
+	  manufactured by Intel Corporation/ICP vortex GmbH. It is documented
+	  in the kernel source in <file:drivers/scsi/gdth.c> and
+	  <file:drivers/scsi/gdth.h.>
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gdth.
+
+config SCSI_GENERIC_NCR5380
+	tristate "Generic NCR5380/53c400 SCSI PIO support"
+	depends on ISA && SCSI
+	---help---
+	  This is a driver for the old NCR 53c80 series of SCSI controllers
+	  on boards using PIO. Most boards such as the Trantor T130 fit this
+	  category, along with a large number of ISA 8bit controllers shipped
+	  for free with SCSI scanners. If you have a PAS16, T128 or DMX3191
+	  you should select the specific driver for that card rather than
+	  generic 5380 support.
+
+	  It is explained in section 3.8 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/g_NCR5380.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called g_NCR5380.
+
+config SCSI_GENERIC_NCR5380_MMIO
+	tristate "Generic NCR5380/53c400 SCSI MMIO support"
+	depends on ISA && SCSI
+	---help---
+	  This is a driver for the old NCR 53c80 series of SCSI controllers
+	  on boards using memory mapped I/O. 
+	  It is explained in section 3.8 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/g_NCR5380.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called g_NCR5380_mmio.
+
+config SCSI_GENERIC_NCR53C400
+	bool "Enable NCR53c400 extensions"
+	depends on SCSI_GENERIC_NCR5380
+	help
+	  This enables certain optimizations for the NCR53c400 SCSI cards.
+	  You might as well try it out.  Note that this driver will only probe
+	  for the Trantor T130B in its default configuration; you might have
+	  to pass a command line option to the kernel at boot time if it does
+	  not detect your card.  See the file
+	  <file:Documentation/scsi/g_NCR5380.txt> for details.
+
+config SCSI_IBMMCA
+	tristate "IBMMCA SCSI support"
+	depends on MCA_LEGACY && SCSI
+	---help---
+	  This is support for the IBM SCSI adapter found in many of the PS/2
+	  series computers.  These machines have an MCA bus, so you need to
+	  answer Y to "MCA support" as well and read
+	  <file:Documentation/mca.txt>.
+
+	  If the adapter isn't found during boot (a common problem for models
+	  56, 57, 76, and 77) you'll need to use the 'ibmmcascsi=<pun>' kernel
+	  option, where <pun> is the id of the SCSI subsystem (usually 7, but
+	  if that doesn't work check your reference diskette).  Owners of
+	  model 95 with a LED-matrix-display can in addition activate some
+	  activity info like under OS/2, but more informative, by setting
+	  'ibmmcascsi=display' as an additional kernel parameter.  Try "man
+	  bootparam" or see the documentation of your boot loader about how to
+	  pass options to the kernel.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ibmmca.
+
+config IBMMCA_SCSI_ORDER_STANDARD
+	bool "Standard SCSI-order"
+	depends on SCSI_IBMMCA
+	---help---
+	  In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
+	  are assigned to the drive letters, starting with the lowest SCSI-id
+	  (physical number -- pun) to be drive C:, as seen from DOS and
+	  similar operating systems. When looking into papers describing the
+	  ANSI-SCSI-standard, this assignment of drives appears to be wrong.
+	  The SCSI-standard follows a hardware-hierarchy which says that id 7
+	  has the highest priority and id 0 the lowest. Therefore, the host
+	  adapters are still today everywhere placed as SCSI-id 7 by default.
+	  In the SCSI-standard, the drive letters express the priority of the
+	  disk. C: should be the hard disk, or a partition on it, with the
+	  highest priority. This must therefore be the disk with the highest
+	  SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
+	  original definition of the SCSI-standard as also industrial- and
+	  process-control-machines, like VME-CPUs running under realtime-OSes
+	  (e.g. LynxOS, OS9) do.
+
+	  If you like to run Linux on your MCA-machine with the same
+	  assignment of hard disks as seen from e.g. DOS or OS/2 on your
+	  machine, which is in addition conformant to the SCSI-standard, you
+	  must say Y here. This is also necessary for MCA-Linux users who want
+	  to keep downward compatibility to older releases of the
+	  IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
+	  June 1997).
+
+	  If you like to have the lowest SCSI-id assigned as drive C:, as
+	  modern SCSI-BIOSes do, which does not conform to the standard, but
+	  is widespread and common in the PC-world of today, you must say N
+	  here. If unsure, say Y.
+
+config IBMMCA_SCSI_DEV_RESET
+	bool "Reset SCSI-devices at boottime"
+	depends on SCSI_IBMMCA
+	---help---
+	  By default, SCSI-devices are reset when the machine is powered on.
+	  However, some devices exist, like special-control-devices,
+	  SCSI-CNC-machines, SCSI-printer or scanners of older type, that do
+	  not reset when switched on. If you say Y here, each device connected
+	  to your SCSI-bus will be issued a reset-command after it has been
+	  probed, while the kernel is booting. This may cause problems with
+	  more modern devices, like hard disks, which do not appreciate these
+	  reset commands, and can cause your system to hang. So say Y only if
+	  you know that one of your older devices needs it; N is the safe
+	  answer.
+
+config SCSI_IPS
+	tristate "IBM ServeRAID support"
+	depends on PCI && SCSI
+	---help---
+	  This is support for the IBM ServeRAID hardware RAID controllers.
+	  See <http://www.developer.ibm.com/welcome/netfinity/serveraid.html>
+	  for more information.  If this driver does not work correctly
+	  without modification please contact the author by email at
+	  <ipslinux@adaptec.com>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ips.
+
+config SCSI_IBMVSCSI
+	tristate "IBM Virtual SCSI support"
+	depends on PPC_PSERIES || PPC_ISERIES
+	help
+	  This is the IBM POWER Virtual SCSI Client
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ibmvscsic.
+
+config SCSI_INITIO
+	tristate "Initio 9100U(W) support"
+	depends on PCI && SCSI
+	help
+	  This is support for the Initio 91XXU(W) SCSI host adapter.  Please
+	  read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called initio.
+
+config SCSI_INIA100
+	tristate "Initio INI-A100U2W support"
+	depends on PCI && SCSI
+	help
+	  This is support for the Initio INI-A100U2W SCSI host adapter.
+	  Please read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called a100u2w.
+
+config SCSI_PPA
+	tristate "IOMEGA parallel port (ppa - older drives)"
+	depends on SCSI && PARPORT
+	---help---
+	  This driver supports older versions of IOMEGA's parallel port ZIP
+	  drive (a 100 MB removable media device).
+
+	  Note that you can say N here if you have the SCSI version of the ZIP
+	  drive: it will be supported automatically if you said Y to the
+	  generic "SCSI disk support", above.
+
+	  If you have the ZIP Plus drive or a more recent parallel port ZIP
+	  drive (if the supplied cable with the drive is labeled "AutoDetect")
+	  then you should say N here and Y to "IOMEGA parallel port (imm -
+	  newer drives)", below.
+
+	  For more information about this driver and how to use it you should
+	  read the file <file:Documentation/scsi/ppa.txt>.  You should also read
+	  the SCSI-HOWTO, which is available from
+	  <http://www.tldp.org/docs.html#howto>.  If you use this driver,
+	  you will still be able to use the parallel port for other tasks,
+	  such as a printer; it is safe to compile both drivers into the
+	  kernel.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ppa.
+
+config SCSI_IMM
+	tristate "IOMEGA parallel port (imm - newer drives)"
+	depends on SCSI && PARPORT
+	---help---
+	  This driver supports newer versions of IOMEGA's parallel port ZIP
+	  drive (a 100 MB removable media device).
+
+	  Note that you can say N here if you have the SCSI version of the ZIP
+	  drive: it will be supported automatically if you said Y to the
+	  generic "SCSI disk support", above.
+
+	  If you have the ZIP Plus drive or a more recent parallel port ZIP
+	  drive (if the supplied cable with the drive is labeled "AutoDetect")
+	  then you should say Y here; if you have an older ZIP drive, say N
+	  here and Y to "IOMEGA Parallel Port (ppa - older drives)", above.
+
+	  For more information about this driver and how to use it you should
+	  read the file <file:Documentation/scsi/ppa.txt>.  You should also read
+	  the SCSI-HOWTO, which is available from
+	  <http://www.tldp.org/docs.html#howto>.  If you use this driver,
+	  you will still be able to use the parallel port for other tasks,
+	  such as a printer; it is safe to compile both drivers into the
+	  kernel.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called imm.
+
+config SCSI_IZIP_EPP16
+	bool "ppa/imm option - Use slow (but safe) EPP-16"
+	depends on PARPORT && (SCSI_PPA || SCSI_IMM)
+	---help---
+	  EPP (Enhanced Parallel Port) is a standard for parallel ports which
+	  allows them to act as expansion buses that can handle up to 64
+	  peripheral devices.
+
+	  Some parallel port chipsets are slower than their motherboard, and
+	  so we have to control the state of the chipset's FIFO queue every
+	  now and then to avoid data loss. This will be done if you say Y
+	  here.
+
+	  Generally, saying Y is the safe option and slows things down a bit.
+
+config SCSI_IZIP_SLOW_CTR
+	bool "ppa/imm option - Assume slow parport control register"
+	depends on PARPORT && (SCSI_PPA || SCSI_IMM)
+	help
+	  Some parallel ports are known to have excessive delays between
+	  changing the parallel port control register and good data being
+	  available on the parallel port data/status register. This option
+	  forces a small delay (1.0 usec to be exact) after changing the
+	  control register to let things settle out. Enabling this option may
+	  result in a big drop in performance but some very old parallel ports
+	  (found in 386 vintage machines) will not work properly.
+
+	  Generally, saying N is fine.
+
+config SCSI_NCR53C406A
+	tristate "NCR53c406a SCSI support"
+	depends on ISA && SCSI
+	help
+	  This is support for the NCR53c406a SCSI host adapter.  For user
+	  configurable parameters, check out <file:drivers/scsi/NCR53c406a.c>
+	  in the kernel source.  Also read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called NCR53c406.
+
+config SCSI_NCR_D700
+	tristate "NCR Dual 700 MCA SCSI support"
+	depends on MCA && SCSI
+	select SCSI_SPI_ATTRS
+	help
+	  This is a driver for the MicroChannel Dual 700 card produced by
+	  NCR and commonly used in 345x/35xx/4100 class machines.  It always
+	  tries to negotiate sync and uses tag command queueing.
+
+	  Unless you have an NCR manufactured machine, the chances are that
+	  you do not have this SCSI card, so say N.
+
+config 53C700_IO_MAPPED
+	bool
+	depends on SCSI_NCR_D700
+	default y
+
+config SCSI_LASI700
+	tristate "HP Lasi SCSI support for 53c700/710"
+	depends on GSC && SCSI
+	select SCSI_SPI_ATTRS
+	help
+	  This is a driver for the SCSI controller in the Lasi chip found in
+	  many PA-RISC workstations & servers.  If you do not know whether you
+	  have a Lasi chip, it is safe to say "Y" here.
+
+config 53C700_MEM_MAPPED
+	bool
+	depends on SCSI_LASI700
+	default y
+
+config 53C700_LE_ON_BE
+	bool
+	depends on SCSI_LASI700
+	default y
+
+config SCSI_SYM53C8XX_2
+	tristate "SYM53C8XX Version 2 SCSI support"
+	depends on PCI && SCSI
+	select SCSI_SPI_ATTRS
+	---help---
+	  This driver supports the whole NCR53C8XX/SYM53C8XX family of
+	  PCI-SCSI controllers.  It also supports the subset of LSI53C10XX
+	  Ultra-160 controllers that are based on the SYM53C8XX SCRIPTS
+	  language.  It does not support LSI53C10XX Ultra-320 PCI-X SCSI
+	  controllers; you need to use the Fusion MPT driver for that.
+
+	  Please read <file:Documentation/scsi/sym53c8xx_2.txt> for more
+	  information.
+
+config SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
+	int "DMA addressing mode"
+	depends on SCSI_SYM53C8XX_2
+	default "1"
+	---help---
+	  This option only applies to PCI-SCSI chips that are PCI DAC
+	  capable (875A, 895A, 896, 1010-33, 1010-66, 1000).
+
+	  When set to 0, the driver will program the chip to only perform
+	  32-bit DMA.  When set to 1, the chip will be able to perform DMA
+	  to addresses up to 1TB.  When set to 2, the driver supports the
+	  full 64-bit DMA address range, but can only address 16 segments
+	  of 4 GB each.  This limits the total addressable range to 64 GB.
+
+	  Most machines with less than 4GB of memory should use a setting
+	  of 0 for best performance.  If your machine has 4GB of memory
+	  or more, you should set this option to 1 (the default).
+
+	  The still experimental value 2 (64 bit DMA addressing with 16
+	  x 4GB segments limitation) can be used on systems that require
+	  PCI address bits past bit 39 to be set for the addressing of
+	  memory using PCI DAC cycles.
+
+config SCSI_SYM53C8XX_DEFAULT_TAGS
+	int "default tagged command queue depth"
+	depends on SCSI_SYM53C8XX_2
+	default "16"
+	help
+	  This is the default value of the command queue depth the
+	  driver will announce to the generic SCSI layer for devices
+	  that support tagged command queueing. This value can be changed
+	  from the boot command line.  This is a soft limit that cannot
+	  exceed CONFIG_SCSI_SYM53C8XX_MAX_TAGS.
+
+config SCSI_SYM53C8XX_MAX_TAGS
+	int "maximum number of queued commands"
+	depends on SCSI_SYM53C8XX_2
+	default "64"
+	help
+	  This option allows you to specify the maximum number of commands
+	  that can be queued to any device, when tagged command queuing is
+	  possible. The driver supports up to 256 queued commands per device.
+	  This value is used as a compiled-in hard limit.
+
+config SCSI_SYM53C8XX_IOMAPPED
+	bool "use port IO"
+	depends on SCSI_SYM53C8XX_2
+	help
+	  If you say Y here, the driver will use port IO to access
+	  the card.  This is significantly slower then using memory
+	  mapped IO.  Most people should answer N.
+
+config SCSI_IPR
+	tristate "IBM Power Linux RAID adapter support"
+	depends on PCI && SCSI
+	select FW_LOADER
+	---help---
+	  This driver supports the IBM Power Linux family RAID adapters.
+	  This includes IBM pSeries 5712, 5703, 5709, and 570A, as well
+	  as IBM iSeries 5702, 5703, 5709, and 570A.
+
+config SCSI_IPR_TRACE
+	bool "enable driver internal trace"
+	depends on SCSI_IPR
+	help
+	  If you say Y here, the driver will trace all commands issued
+	  to the adapter. Performance impact is minimal. Trace can be
+	  dumped using /sys/bus/class/scsi_host/hostXX/trace.
+
+config SCSI_IPR_DUMP
+	bool "enable adapter dump support"
+	depends on SCSI_IPR
+	help
+	  If you say Y here, the driver will support adapter crash dump.
+	  If you enable this support, the iprdump daemon can be used
+	  to capture adapter failure analysis information.
+
+config SCSI_ZALON
+	tristate "Zalon SCSI support"
+	depends on GSC && SCSI
+	select SCSI_SPI_ATTRS
+	help
+	  The Zalon is a GSC/HSC bus interface chip that sits between the
+	  PA-RISC processor and the NCR 53c720 SCSI controller on C100,
+	  C110, J200, J210 and some D, K & R-class machines.  It's also
+	  used on the add-in Bluefish, Barracuda & Shrike SCSI cards.
+	  Say Y here if you have one of these machines or cards.
+
+config SCSI_NCR_Q720
+	tristate "NCR Quad 720 MCA SCSI support"
+	depends on MCA && SCSI
+	select SCSI_SPI_ATTRS
+	help
+	  This is a driver for the MicroChannel Quad 720 card produced by
+	  NCR and commonly used in 345x/35xx/4100 class machines.  It always
+	  tries to negotiate sync and uses tag command queueing.
+
+	  Unless you have an NCR manufactured machine, the chances are that
+	  you do not have this SCSI card, so say N.
+
+config SCSI_NCR53C8XX_DEFAULT_TAGS
+	int "  default tagged command queue depth"
+	depends on SCSI_ZALON || SCSI_NCR_Q720
+	default "8"
+	---help---
+	  "Tagged command queuing" is a feature of SCSI-2 which improves
+	  performance: the host adapter can send several SCSI commands to a
+	  device's queue even if previous commands haven't finished yet.
+	  Because the device is intelligent, it can optimize its operations
+	  (like head positioning) based on its own request queue. Some SCSI
+	  devices don't implement this properly; if you want to disable this
+	  feature, enter 0 or 1 here (it doesn't matter which).
+
+	  The default value is 8 and should be supported by most hard disks.
+	  This value can be overridden from the boot command line using the
+	  'tags' option as follows (example):
+	  'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to
+	  4, set queue depth to 16 for target 2 and target 3 on controller 0
+	  and set queue depth to 10 for target 0 / lun 2 on controller 1.
+
+	  The normal answer therefore is to go with the default 8 and to use
+	  a boot command line option for devices that need to use a different
+	  command queue depth.
+
+	  There is no safe option other than using good SCSI devices.
+
+config SCSI_NCR53C8XX_MAX_TAGS
+	int "  maximum number of queued commands"
+	depends on SCSI_ZALON || SCSI_NCR_Q720
+	default "32"
+	---help---
+	  This option allows you to specify the maximum number of commands
+	  that can be queued to any device, when tagged command queuing is
+	  possible. The default value is 32. Minimum is 2, maximum is 64.
+	  Modern hard disks are able to support 64 tags and even more, but
+	  do not seem to be faster when more than 32 tags are being used.
+
+	  So, the normal answer here is to go with the default value 32 unless
+	  you are using very large hard disks with large cache (>= 1 MB) that
+	  are able to take advantage of more than 32 tagged commands.
+
+	  There is no safe option and the default answer is recommended.
+
+config SCSI_NCR53C8XX_SYNC
+	int "  synchronous transfers frequency in MHz"
+	depends on SCSI_ZALON || SCSI_NCR_Q720
+	default "20"
+	---help---
+	  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
+	  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80.  The numbers
+	  are respectively the maximum data transfer rates in mega-transfers
+	  per second for each class.  For example, a FAST-20 Wide 16 device is
+	  able to transfer data at 20 million 16 bit packets per second for a
+	  total rate of 40 MB/s.
+
+	  You may specify 0 if you want to only use asynchronous data
+	  transfers. This is the safest and slowest option. Otherwise, specify
+	  a value between 5 and 80, depending on the capability of your SCSI
+	  controller.  The higher the number, the faster the data transfer.
+	  Note that 80 should normally be ok since the driver decreases the
+	  value automatically according to the controller's capabilities.
+
+	  Your answer to this question is ignored for controllers with NVRAM,
+	  since the driver will get this information from the user set-up.  It
+	  also can be overridden using a boot setup option, as follows
+	  (example): 'ncr53c8xx=sync:12' will allow the driver to negotiate
+	  for FAST-20 synchronous data transfer (20 mega-transfers per
+	  second).
+
+	  The normal answer therefore is not to go with the default but to
+	  select the maximum value 80 allowing the driver to use the maximum
+	  value supported by each controller. If this causes problems with
+	  your SCSI devices, you should come back and decrease the value.
+
+	  There is no safe option other than using good cabling, right
+	  terminations and SCSI conformant devices.
+
+config SCSI_NCR53C8XX_PROFILE
+	bool "  enable profiling"
+	depends on SCSI_ZALON || SCSI_NCR_Q720
+	help
+	  This option allows you to enable profiling information gathering.
+	  These statistics are not very accurate due to the low frequency
+	  of the kernel clock (100 Hz on i386) and have performance impact
+	  on systems that use very fast devices.
+
+	  The normal answer therefore is N.
+
+config SCSI_NCR53C8XX_NO_DISCONNECT
+	bool "  not allow targets to disconnect"
+	depends on (SCSI_ZALON || SCSI_NCR_Q720) && SCSI_NCR53C8XX_DEFAULT_TAGS=0
+	help
+	  This option is only provided for safety if you suspect some SCSI
+	  device of yours to not support properly the target-disconnect
+	  feature. In that case, you would say Y here. In general however, to
+	  not allow targets to disconnect is not reasonable if there is more
+	  than 1 device on a SCSI bus. The normal answer therefore is N.
+
+config SCSI_MCA_53C9X
+	tristate "NCR MCA 53C9x SCSI support"
+	depends on MCA_LEGACY && SCSI && BROKEN_ON_SMP
+	help
+	  Some MicroChannel machines, notably the NCR 35xx line, use a SCSI
+	  controller based on the NCR 53C94.  This driver will allow use of
+	  the controller on the 3550, and very possibly others.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mca_53c9x.
+
+config SCSI_PAS16
+	tristate "PAS16 SCSI support"
+	depends on ISA && SCSI
+	---help---
+	  This is support for a SCSI host adapter.  It is explained in section
+	  3.10 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/pas16.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pas16.
+
+config SCSI_PCI2000
+	tristate "PCI2000 support"
+	depends on PCI && SCSI && BROKEN
+	help
+	  This is support for the PCI2000I EIDE interface card which acts as a
+	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pci2000.
+
+config SCSI_PCI2220I
+	tristate "PCI2220i support"
+	depends on PCI && SCSI && BROKEN
+	help
+	  This is support for the PCI2220i EIDE interface card which acts as a
+	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called pci2220i.
+
+config SCSI_PSI240I
+	tristate "PSI240i support"
+	depends on ISA && SCSI
+	help
+	  This is support for the PSI240i EIDE interface card which acts as a
+	  SCSI host adapter.  Please read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called psi240i.
+
+config SCSI_QLOGIC_FAS
+	tristate "Qlogic FAS SCSI support"
+	depends on ISA && SCSI
+	---help---
+	  This is a driver for the ISA, VLB, and PCMCIA versions of the Qlogic
+	  FastSCSI! cards as well as any other card based on the FASXX chip
+	  (including the Control Concepts SCSI/IDE/SIO/PIO/FDC cards).
+
+	  This driver does NOT support the PCI versions of these cards. The
+	  PCI versions are supported by the Qlogic ISP driver ("Qlogic ISP
+	  SCSI support"), below.
+
+	  Information about this driver is contained in
+	  <file:Documentation/scsi/qlogicfas.txt>.  You should also read the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qlogicfas.
+
+config SCSI_QLOGIC_ISP
+	tristate "Qlogic ISP SCSI support (old driver)"
+	depends on PCI && SCSI && BROKEN
+	---help---
+	  This driver works for all QLogic PCI SCSI host adapters (IQ-PCI,
+	  IQ-PCI-10, IQ_PCI-D) except for the PCI-basic card.  (This latter
+	  card is supported by the "AM53/79C974 PCI SCSI" driver.)
+
+	  If you say Y here, make sure to choose "BIOS" at the question "PCI
+	  access mode".
+
+	  Please read the file <file:Documentation/scsi/qlogicisp.txt>.  You
+	  should also read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qlogicisp.
+
+	  These days the hardware is also supported by the more modern qla1280
+	  driver.  In doubt use that one instead of qlogicisp.
+
+config SCSI_QLOGIC_FC
+	tristate "Qlogic ISP FC SCSI support"
+	depends on PCI && SCSI
+	help
+	  This is a driver for the QLogic ISP2100 SCSI-FCP host adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qlogicfc.
+
+config SCSI_QLOGIC_FC_FIRMWARE
+	bool "Include loadable firmware in driver"
+	depends on SCSI_QLOGIC_FC
+  	help
+	  Say Y to include ISP2X00 Fabric Initiator/Target Firmware, with
+	  expanded LUN addressing and FcTape (FCP-2) support, in the
+	  qlogicfc driver. This is required on some platforms.
+
+config SCSI_QLOGIC_1280
+	tristate "Qlogic QLA 1240/1x80/1x160 SCSI support"
+	depends on PCI && SCSI
+	help
+	  Say Y if you have a QLogic ISP1240/1x80/1x160 SCSI host adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qla1280.
+
+config SCSI_QLOGIC_1280_1040
+	bool "Qlogic QLA 1020/1040 SCSI support"
+	depends on SCSI_QLOGIC_1280 && SCSI_QLOGIC_ISP!=y
+	help
+	  Say Y here if you have a QLogic ISP1020/1040 SCSI host adapter and
+	  do not want to use the old driver.  This option enables support in
+	  the qla1280 driver for those host adapters.
+
+config SCSI_QLOGICPTI
+	tristate "PTI Qlogic, ISP Driver"
+	depends on SBUS && SCSI
+	help
+	  This driver supports SBUS SCSI controllers from PTI or QLogic. These
+	  controllers are known under Solaris as qpti and in the openprom as
+	  PTI,ptisp or QLGC,isp. Note that PCI QLogic SCSI controllers are
+	  driven by a different driver.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qlogicpti.
+
+source "drivers/scsi/qla2xxx/Kconfig"
+
+config SCSI_SEAGATE
+	tristate "Seagate ST-02 and Future Domain TMC-8xx SCSI support"
+	depends on X86 && ISA && SCSI && BROKEN
+	---help---
+	  These are 8-bit SCSI controllers; the ST-01 is also supported by
+	  this driver.  It is explained in section 3.9 of the SCSI-HOWTO,
+	  available from <http://www.tldp.org/docs.html#howto>.  If it
+	  doesn't work out of the box, you may have to change some settings in
+	  <file:drivers/scsi/seagate.h>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called seagate.
+
+# definitely looks not 64bit safe:
+config SCSI_SIM710
+	tristate "Simple 53c710 SCSI support (Compaq, NCR machines)"
+	depends on (EISA || MCA) && SCSI
+	select SCSI_SPI_ATTRS
+	---help---
+	  This driver for NCR53c710 based SCSI host adapters.
+
+	  It currently supports Compaq EISA cards and NCR MCA cards
+
+config 53C700_IO_MAPPED
+	bool
+	depends on SCSI_SIM710
+	default y
+
+config SCSI_SYM53C416
+	tristate "Symbios 53c416 SCSI support"
+	depends on ISA && SCSI
+	---help---
+	  This is support for the sym53c416 SCSI host adapter, the SCSI
+	  adapter that comes with some HP scanners. This driver requires that
+	  the sym53c416 is configured first using some sort of PnP
+	  configuration program (e.g. isapnp) or by a PnP aware BIOS. If you
+	  are using isapnp then you need to compile this driver as a module
+	  and then load it using insmod after isapnp has run. The parameters
+	  of the configured card(s) should be passed to the driver. The format
+	  is:
+
+	  insmod sym53c416 sym53c416=<base>,<irq> [sym53c416_1=<base>,<irq>]
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sym53c416.
+
+config SCSI_DC395x
+	tristate "Tekram DC395(U/UW/F) and DC315(U) SCSI support (EXPERIMENTAL)"
+	depends on PCI && SCSI && EXPERIMENTAL
+	---help---
+	  This driver supports PCI SCSI host adapters based on the ASIC
+	  TRM-S1040 chip, e.g Tekram DC395(U/UW/F) and DC315(U) variants.
+
+	  This driver works, but is still in experimental status. So better
+	  have a bootable disk and a backup in case of emergency.
+
+	  Documentation can be found in <file:Documentation/scsi/dc395x.txt>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called dc395x.
+
+config SCSI_DC390T
+	tristate "Tekram DC390(T) and Am53/79C974 SCSI support"
+	depends on PCI && SCSI
+	---help---
+	  This driver supports PCI SCSI host adapters based on the Am53C974A
+	  chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
+	  PCscsi/PCnet (Am53/79C974) solutions.
+
+	  Documentation can be found in <file:Documentation/scsi/tmscsim.txt>.
+
+	  Note that this driver does NOT support Tekram DC390W/U/F, which are
+	  based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called tmscsim.
+
+config SCSI_T128
+	tristate "Trantor T128/T128F/T228 SCSI support"
+	depends on ISA && SCSI
+	---help---
+	  This is support for a SCSI host adapter. It is explained in section
+	  3.11 of the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/t128.h>.  Note that Trantor was purchased by
+	  Adaptec, and some former Trantor products are being sold under the
+	  Adaptec name.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called t128.
+
+config SCSI_U14_34F
+	tristate "UltraStor 14F/34F support"
+	depends on ISA && SCSI
+	---help---
+	  This is support for the UltraStor 14F and 34F SCSI-2 host adapters.
+	  The source at <file:drivers/scsi/u14-34f.c> contains some
+	  information about this hardware.  If the driver doesn't work out of
+	  the box, you may have to change some settings in
+	  <file: drivers/scsi/u14-34f.c>.  Read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  Note that there is also
+	  another driver for the same hardware: "UltraStor SCSI support",
+	  below.  You should say Y to both only if you want 24F support as
+	  well.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called u14-34f.
+
+config SCSI_U14_34F_TAGGED_QUEUE
+	bool "enable tagged command queueing"
+	depends on SCSI_U14_34F
+	help
+	  This is a feature of SCSI-2 which improves performance: the host
+	  adapter can send several SCSI commands to a device's queue even if
+	  previous commands haven't finished yet.
+	  This is equivalent to the "u14-34f=tc:y" boot option.
+
+config SCSI_U14_34F_LINKED_COMMANDS
+	bool "enable elevator sorting"
+	depends on SCSI_U14_34F
+	help
+	  This option enables elevator sorting for all probed SCSI disks and
+	  CD-ROMs. It definitely reduces the average seek distance when doing
+	  random seeks, but this does not necessarily result in a noticeable
+	  performance improvement: your mileage may vary...
+	  This is equivalent to the "u14-34f=lc:y" boot option.
+
+config SCSI_U14_34F_MAX_TAGS
+	int "maximum number of queued commands"
+	depends on SCSI_U14_34F
+	default "8"
+	help
+	  This specifies how many SCSI commands can be maximally queued for
+	  each probed SCSI device. You should reduce the default value of 8
+	  only if you have disks with buggy or limited tagged command support.
+	  Minimum is 2 and maximum is 14. This value is also the window size
+	  used by the elevator sorting option above. The effective value used
+	  by the driver for each probed SCSI device is reported at boot time.
+	  This is equivalent to the "u14-34f=mq:8" boot option.
+
+config SCSI_ULTRASTOR
+	tristate "UltraStor SCSI support"
+	depends on X86 && ISA && SCSI
+	---help---
+	  This is support for the UltraStor 14F, 24F and 34F SCSI-2 host
+	  adapter family.  This driver is explained in section 3.12 of the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.  If it doesn't work out
+	  of the box, you may have to change some settings in
+	  <file:drivers/scsi/ultrastor.h>.
+
+	  Note that there is also another driver for the same hardware:
+	  "UltraStor 14F/34F support", above.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ultrastor.
+
+config SCSI_NSP32
+	tristate "Workbit NinjaSCSI-32Bi/UDE support"
+	depends on PCI && SCSI && !64BIT
+	help
+	  This is support for the Workbit NinjaSCSI-32Bi/UDE PCI/Cardbus
+	  SCSI host adapter. Please read the SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nsp32.
+
+config SCSI_DEBUG
+	tristate "SCSI debugging host simulator"
+	depends on SCSI
+	help
+	  This is a host adapter simulator that can simulate multiple hosts
+	  each with multiple dummy SCSI devices (disks). It defaults to one
+	  host adapter with one dummy SCSI disk. Each dummy disk uses kernel
+	  RAM as storage (i.e. it is a ramdisk). To save space when multiple
+	  dummy disks are simulated, they share the same kernel RAM for 
+	  their storage. See <http://www.torque.net/sg/sdebug.html> for more
+	  information. This driver is primarily of use to those testing the
+	  SCSI and block subsystems. If unsure, say N.
+
+config SCSI_MESH
+	tristate "MESH (Power Mac internal SCSI) support"
+	depends on PPC32 && PPC_PMAC && SCSI
+	help
+	  Many Power Macintoshes and clones have a MESH (Macintosh Enhanced
+	  SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the
+	  other Power Macintoshes do). Say Y to include support for this SCSI
+	  adaptor.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mesh.
+
+config SCSI_MESH_SYNC_RATE
+	int "maximum synchronous transfer rate (MB/s) (0 = async)"
+	depends on SCSI_MESH
+	default "5"
+	help
+	  On Power Macintoshes (and clones) where the MESH SCSI bus adaptor
+	  drives a bus which is entirely internal to the machine (such as the
+	  7500, 7600, 8500, etc.), the MESH is capable of synchronous
+	  operation at up to 10 MB/s. On machines where the SCSI bus
+	  controlled by the MESH can have external devices connected, it is
+	  usually rated at 5 MB/s. 5 is a safe value here unless you know the
+	  MESH SCSI bus is internal only; in that case you can say 10. Say 0
+	  to disable synchronous operation.
+
+config SCSI_MESH_RESET_DELAY_MS
+	int "initial bus reset delay (ms) (0 = no reset)"
+	depends on SCSI_MESH
+	default "4000"
+
+config SCSI_MAC53C94
+	tristate "53C94 (Power Mac external SCSI) support"
+	depends on PPC32 && PPC_PMAC && SCSI
+	help
+	  On Power Macintoshes (and clones) with two SCSI buses, the external
+	  SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older
+	  machines which only have one SCSI bus, such as the 7200, also use
+	  the 53C94. Say Y to include support for the 53C94.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mac53c94.
+
+source "drivers/scsi/arm/Kconfig"
+
+config JAZZ_ESP
+	bool "MIPS JAZZ FAS216 SCSI support"
+	depends on MACH_JAZZ && SCSI
+	help
+	  This is the driver for the onboard SCSI host adapter of MIPS Magnum
+	  4000, Acer PICA, Olivetti M700-10 and a few other identical OEM
+	  systems.
+
+config A3000_SCSI
+	tristate "A3000 WD33C93A support"
+	depends on AMIGA && SCSI
+	help
+	  If you have an Amiga 3000 and have SCSI devices connected to the
+	  built-in SCSI controller, say Y. Otherwise, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wd33c93.
+
+config A2091_SCSI
+	tristate "A2091/A590 WD33C93A support"
+	depends on ZORRO && SCSI
+	help
+	  If you have a Commodore A2091 SCSI controller, say Y. Otherwise,
+	  say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called wd33c93.
+
+config GVP11_SCSI
+	tristate "GVP Series II WD33C93A support"
+	depends on ZORRO && SCSI
+	---help---
+	  If you have a Great Valley Products Series II SCSI controller,
+	  answer Y. Also say Y if you have a later model of GVP SCSI
+	  controller (such as the GVP A4008 or a Combo board). Otherwise,
+	  answer N. This driver does NOT work for the T-Rex series of
+	  accelerators from TekMagic and GVP-M.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called gvp11.
+
+config CYBERSTORM_SCSI
+	tristate "CyberStorm SCSI support"
+	depends on ZORRO && SCSI
+	help
+	  If you have an Amiga with an original (MkI) Phase5 Cyberstorm
+	  accelerator board and the optional Cyberstorm SCSI controller,
+	  answer Y. Otherwise, say N.
+
+config CYBERSTORMII_SCSI
+	tristate "CyberStorm Mk II SCSI support"
+	depends on ZORRO && SCSI
+	help
+	  If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
+	  and the optional Cyberstorm SCSI controller, say Y. Otherwise,
+	  answer N.
+
+config BLZ2060_SCSI
+	tristate "Blizzard 2060 SCSI support"
+	depends on ZORRO && SCSI
+	help
+	  If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
+	  and want to use the onboard SCSI controller, say Y. Otherwise,
+	  answer N.
+
+config BLZ1230_SCSI
+	tristate "Blizzard 1230IV/1260 SCSI support"
+	depends on ZORRO && SCSI
+	help
+	  If you have an Amiga 1200 with a Phase5 Blizzard 1230IV or Blizzard
+	  1260 accelerator, and the optional SCSI module, say Y. Otherwise,
+	  say N.
+
+config FASTLANE_SCSI
+	tristate "Fastlane SCSI support"
+	depends on ZORRO && SCSI
+	help
+	  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
+	  one in the near future, say Y to this question. Otherwise, say N.
+
+config SCSI_AMIGA7XX
+	bool "Amiga NCR53c710 SCSI support (EXPERIMENTAL)"
+	depends on AMIGA && SCSI && EXPERIMENTAL && BROKEN
+	help
+	  Support for various NCR53c710-based SCSI controllers on the Amiga.
+	  This includes:
+	    - the builtin SCSI controller on the Amiga 4000T,
+	    - the Amiga 4091 Zorro III SCSI-2 controller,
+	    - the MacroSystem Development's WarpEngine Amiga SCSI-2 controller
+	      (info at
+	      <http://www.lysator.liu.se/amiga/ar/guide/ar310.guide?FEATURE5>),
+	    - the SCSI controller on the Phase5 Blizzard PowerUP 603e+
+	      accelerator card for the Amiga 1200,
+	    - the SCSI controller on the GVP Turbo 040/060 accelerator.
+	  Note that all of the above SCSI controllers, except for the builtin
+	  SCSI controller on the Amiga 4000T, reside on the Zorro expansion
+	  bus, so you also have to enable Zorro bus support if you want to use
+	  them.
+
+config OKTAGON_SCSI
+	tristate "BSC Oktagon SCSI support (EXPERIMENTAL)"
+	depends on ZORRO && SCSI && EXPERIMENTAL
+	help
+	  If you have the BSC Oktagon SCSI disk controller for the Amiga, say
+	  Y to this question.  If you're in doubt about whether you have one,
+	  see the picture at
+	  <http://amiga.resource.cx/exp/search.pl?product=oktagon>.
+
+config ATARI_SCSI
+	tristate "Atari native SCSI support"
+	depends on ATARI && SCSI && BROKEN
+	---help---
+	  If you have an Atari with built-in NCR5380 SCSI controller (TT,
+	  Falcon, ...) say Y to get it supported. Of course also, if you have
+	  a compatible SCSI controller (e.g. for Medusa).
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called atari_scsi.
+
+	  This driver supports both styles of NCR integration into the
+	  system: the TT style (separate DMA), and the Falcon style (via
+	  ST-DMA, replacing ACSI).  It does NOT support other schemes, like
+	  in the Hades (without DMA).
+
+config ATARI_SCSI_TOSHIBA_DELAY
+	bool "Long delays for Toshiba CD-ROMs"
+	depends on ATARI_SCSI
+	help
+	  This option increases the delay after a SCSI arbitration to
+	  accommodate some flaky Toshiba CD-ROM drives. Say Y if you intend to
+	  use a Toshiba CD-ROM drive; otherwise, the option is not needed and
+	  would impact performance a bit, so say N.
+
+config ATARI_SCSI_RESET_BOOT
+	bool "Reset SCSI-devices at boottime"
+	depends on ATARI_SCSI
+	help
+	  Reset the devices on your Atari whenever it boots.  This makes the
+	  boot process fractionally longer but may assist recovery from errors
+	  that leave the devices with SCSI operations partway completed.
+
+config TT_DMA_EMUL
+	bool "Hades SCSI DMA emulator"
+	depends on ATARI_SCSI && HADES
+	help
+	  This option enables code which emulates the TT SCSI DMA chip on the
+	  Hades. This increases the SCSI transfer rates at least ten times
+	  compared to PIO transfers.
+
+config MAC_SCSI
+	bool "Macintosh NCR5380 SCSI"
+	depends on MAC && SCSI
+	help
+	  This is the NCR 5380 SCSI controller included on most of the 68030
+	  based Macintoshes.  If you have one of these say Y and read the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+config SCSI_MAC_ESP
+	tristate "Macintosh NCR53c9[46] SCSI"
+	depends on MAC && SCSI
+	help
+	  This is the NCR 53c9x SCSI controller found on most of the 68040
+	  based Macintoshes.  If you have one of these say Y and read the
+	  SCSI-HOWTO, available from
+	  <http://www.tldp.org/docs.html#howto>.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called mac_esp.
+
+config MVME147_SCSI
+	bool "WD33C93 SCSI driver for MVME147"
+	depends on MVME147 && SCSI
+	help
+	  Support for the on-board SCSI controller on the Motorola MVME147
+	  single-board computer.
+
+config MVME16x_SCSI
+	bool "NCR53C710 SCSI driver for MVME16x"
+	depends on MVME16x && SCSI && BROKEN
+	help
+	  The Motorola MVME162, 166, 167, 172 and 177 boards use the NCR53C710
+	  SCSI controller chip.  Almost everyone using one of these boards
+	  will want to say Y to this question.
+
+config BVME6000_SCSI
+	bool "NCR53C710 SCSI driver for BVME6000"
+	depends on BVME6000 && SCSI && BROKEN
+	help
+	  The BVME4000 and BVME6000 boards from BVM Ltd use the NCR53C710
+	  SCSI controller chip.  Almost everyone using one of these boards
+	  will want to say Y to this question.
+
+config SCSI_NCR53C7xx_FAST
+	bool "allow FAST-SCSI [10MHz]"
+	depends on SCSI_AMIGA7XX || MVME16x_SCSI || BVME6000_SCSI
+	help
+	  This will enable 10MHz FAST-SCSI transfers with your host
+	  adapter. Some systems have problems with that speed, so it's safest
+	  to say N here.
+
+config SUN3_SCSI
+	tristate "Sun3 NCR5380 SCSI"
+	depends on SUN3 && SCSI
+	help
+	  This option will enable support for the OBIO (onboard io) NCR5380
+	  SCSI controller found in the Sun 3/50 and 3/60, as well as for
+	  "Sun3" type VME scsi controllers also based on the NCR5380.
+	  General Linux information on the Sun 3 series (now discontinued)
+	  is at <http://www.angelfire.com/ca2/tech68k/sun3.html>.
+
+config SUN3X_ESP
+	bool "Sun3x ESP SCSI"
+	depends on SUN3X && SCSI
+	help
+	  The ESP was an on-board SCSI controller used on Sun 3/80
+	  machines.  Say Y here to compile in support for it.
+
+config SCSI_SUNESP
+	tristate "Sparc ESP Scsi Driver"
+	depends on SBUS && SCSI
+	help
+	  This is the driver for the Sun ESP SCSI host adapter. The ESP
+	  chipset is present in most SPARC SBUS-based computers.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called esp.
+
+#      bool 'Cyberstorm Mk III SCSI support (EXPERIMENTAL)' CONFIG_CYBERSTORMIII_SCSI
+
+config ZFCP
+	tristate "FCP host bus adapter driver for IBM eServer zSeries"
+	depends on ARCH_S390 && QDIO && SCSI
+	select SCSI_FC_ATTRS
+	help
+          If you want to access SCSI devices attached to your IBM eServer
+          zSeries by means of Fibre Channel interfaces say Y.
+          For details please refer to the documentation provided by IBM at
+          <http://oss.software.ibm.com/developerworks/opensource/linux390>
+
+          This driver is also available as a module. This module will be
+          called zfcp. If you want to compile it as a module, say M here
+          and read <file:Documentation/modules.txt>.
+
+endmenu
+
+source "drivers/scsi/pcmcia/Kconfig"
+
+endmenu
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
new file mode 100644
index 0000000..29fcee3
--- /dev/null
+++ b/drivers/scsi/Makefile
@@ -0,0 +1,184 @@
+#
+# Makefile for linux/drivers/scsi
+#
+# 30 May 2000, Christoph Hellwig <hch@infradead.org>
+# Rewritten to use lists instead of if-statements.
+#
+# 20 Sep 2000, Torben Mathiasen <tmm@image.dk>
+# Changed link order to reflect new scsi initialization.
+#
+# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
+# The link order must be, SCSI Core, SCSI HBA drivers, and
+# lastly SCSI peripheral drivers (disk/tape/cdrom/etc.) to
+# satisfy certain initialization assumptions in the SCSI layer.
+# *!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!*!
+
+
+CFLAGS_aha152x.o =   -DAHA152X_STAT -DAUTOCONF
+CFLAGS_gdth.o    = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
+CFLAGS_seagate.o =   -DARBITRATE -DPARITY -DSEAGATE_USE_ASM
+
+subdir-$(CONFIG_PCMCIA)		+= pcmcia
+
+obj-$(CONFIG_SCSI)		+= scsi_mod.o
+
+# --- NOTE ORDERING HERE ---
+# For kernel non-modular link, transport attributes need to
+# be initialised before drivers
+# --------------------------
+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_AMIGA7XX)	+= amiga7xx.o	53c7xx.o
+obj-$(CONFIG_A3000_SCSI)	+= a3000.o	wd33c93.o
+obj-$(CONFIG_A2091_SCSI)	+= a2091.o	wd33c93.o
+obj-$(CONFIG_GVP11_SCSI)	+= gvp11.o	wd33c93.o
+obj-$(CONFIG_MVME147_SCSI)	+= mvme147.o	wd33c93.o
+obj-$(CONFIG_SGIWD93_SCSI)	+= sgiwd93.o	wd33c93.o
+obj-$(CONFIG_CYBERSTORM_SCSI)	+= NCR53C9x.o	cyberstorm.o
+obj-$(CONFIG_CYBERSTORMII_SCSI)	+= NCR53C9x.o	cyberstormII.o
+obj-$(CONFIG_BLZ2060_SCSI)	+= NCR53C9x.o	blz2060.o
+obj-$(CONFIG_BLZ1230_SCSI)	+= NCR53C9x.o	blz1230.o
+obj-$(CONFIG_FASTLANE_SCSI)	+= NCR53C9x.o	fastlane.o
+obj-$(CONFIG_OKTAGON_SCSI)	+= NCR53C9x.o	oktagon_esp.o	oktagon_io.o
+obj-$(CONFIG_ATARI_SCSI)	+= atari_scsi.o
+obj-$(CONFIG_MAC_SCSI)		+= mac_scsi.o
+obj-$(CONFIG_SCSI_MAC_ESP)	+= mac_esp.o	NCR53C9x.o
+obj-$(CONFIG_SUN3_SCSI)		+= sun3_scsi.o  sun3_scsi_vme.o
+obj-$(CONFIG_MVME16x_SCSI)	+= mvme16x.o	53c7xx.o
+obj-$(CONFIG_BVME6000_SCSI)	+= bvme6000.o	53c7xx.o
+obj-$(CONFIG_SCSI_SIM710)	+= 53c700.o	sim710.o
+obj-$(CONFIG_SCSI_ADVANSYS)	+= advansys.o
+obj-$(CONFIG_SCSI_PCI2000)	+= pci2000.o
+obj-$(CONFIG_SCSI_PCI2220I)	+= pci2220i.o
+obj-$(CONFIG_SCSI_PSI240I)	+= psi240i.o
+obj-$(CONFIG_SCSI_BUSLOGIC)	+= BusLogic.o
+obj-$(CONFIG_SCSI_DPT_I2O)	+= dpt_i2o.o
+obj-$(CONFIG_SCSI_U14_34F)	+= u14-34f.o
+obj-$(CONFIG_SCSI_ULTRASTOR)	+= ultrastor.o
+obj-$(CONFIG_SCSI_AHA152X)	+= aha152x.o
+obj-$(CONFIG_SCSI_AHA1542)	+= aha1542.o
+obj-$(CONFIG_SCSI_AHA1740)	+= aha1740.o
+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_IPS)		+= ips.o
+obj-$(CONFIG_SCSI_FD_MCS)	+= fd_mcs.o
+obj-$(CONFIG_SCSI_FUTURE_DOMAIN)+= fdomain.o
+obj-$(CONFIG_SCSI_IN2000)	+= in2000.o
+obj-$(CONFIG_SCSI_GENERIC_NCR5380) += g_NCR5380.o
+obj-$(CONFIG_SCSI_GENERIC_NCR5380_MMIO) += g_NCR5380_mmio.o
+obj-$(CONFIG_SCSI_NCR53C406A)	+= NCR53c406a.o
+obj-$(CONFIG_SCSI_NCR_D700)	+= 53c700.o NCR_D700.o
+obj-$(CONFIG_SCSI_NCR_Q720)	+= NCR_Q720_mod.o
+obj-$(CONFIG_SCSI_SYM53C416)	+= sym53c416.o
+obj-$(CONFIG_SCSI_QLOGIC_FAS)	+= qlogicfas408.o	qlogicfas.o
+obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogicfas408.o
+obj-$(CONFIG_SCSI_QLOGIC_ISP)	+= qlogicisp.o 
+obj-$(CONFIG_SCSI_QLOGIC_FC)	+= qlogicfc.o 
+obj-$(CONFIG_SCSI_QLOGIC_1280)	+= qla1280.o 
+obj-$(CONFIG_SCSI_QLA2XXX)	+= qla2xxx/
+obj-$(CONFIG_SCSI_PAS16)	+= pas16.o
+obj-$(CONFIG_SCSI_SEAGATE)	+= seagate.o
+obj-$(CONFIG_SCSI_FD_8xx)	+= seagate.o
+obj-$(CONFIG_SCSI_T128)		+= t128.o
+obj-$(CONFIG_SCSI_DMX3191D)	+= dmx3191d.o
+obj-$(CONFIG_SCSI_DTC3280)	+= dtc.o
+obj-$(CONFIG_SCSI_SYM53C8XX_2)	+= sym53c8xx_2/
+obj-$(CONFIG_SCSI_ZALON)	+= zalon7xx.o
+obj-$(CONFIG_SCSI_EATA_PIO)	+= eata_pio.o
+obj-$(CONFIG_SCSI_7000FASST)	+= wd7000.o
+obj-$(CONFIG_SCSI_MCA_53C9X)	+= NCR53C9x.o	mca_53c9x.o
+obj-$(CONFIG_SCSI_IBMMCA)	+= ibmmca.o
+obj-$(CONFIG_SCSI_EATA)		+= eata.o
+obj-$(CONFIG_SCSI_DC395x)	+= dc395x.o
+obj-$(CONFIG_SCSI_DC390T)	+= tmscsim.o
+obj-$(CONFIG_MEGARAID_LEGACY)	+= megaraid.o
+obj-$(CONFIG_MEGARAID_NEWGEN)	+= megaraid/
+obj-$(CONFIG_SCSI_ACARD)	+= atp870u.o
+obj-$(CONFIG_SCSI_SUNESP)	+= esp.o
+obj-$(CONFIG_SCSI_GDTH)		+= gdth.o
+obj-$(CONFIG_SCSI_INITIO)	+= initio.o
+obj-$(CONFIG_SCSI_INIA100)	+= a100u2w.o
+obj-$(CONFIG_SCSI_QLOGICPTI)	+= qlogicpti.o
+obj-$(CONFIG_BLK_DEV_IDESCSI)	+= ide-scsi.o
+obj-$(CONFIG_SCSI_MESH)		+= mesh.o
+obj-$(CONFIG_SCSI_MAC53C94)	+= mac53c94.o
+obj-$(CONFIG_SCSI_PLUTO)	+= pluto.o
+obj-$(CONFIG_SCSI_DECNCR)	+= NCR53C9x.o	dec_esp.o
+obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
+obj-$(CONFIG_SCSI_3W_9XXX)	+= 3w-9xxx.o
+obj-$(CONFIG_SCSI_PPA)		+= ppa.o
+obj-$(CONFIG_SCSI_IMM)		+= imm.o
+obj-$(CONFIG_JAZZ_ESP)		+= NCR53C9x.o	jazz_esp.o
+obj-$(CONFIG_SUN3X_ESP)		+= NCR53C9x.o	sun3x_esp.o
+obj-$(CONFIG_SCSI_DEBUG)	+= scsi_debug.o
+obj-$(CONFIG_SCSI_FCAL)		+= fcal.o
+obj-$(CONFIG_SCSI_CPQFCTS)	+= cpqfc.o
+obj-$(CONFIG_SCSI_LASI700)	+= 53c700.o lasi700.o
+obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
+obj-$(CONFIG_SCSI_IPR)		+= ipr.o
+obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsi/
+obj-$(CONFIG_SCSI_SATA_AHCI)	+= libata.o ahci.o
+obj-$(CONFIG_SCSI_SATA_SVW)	+= libata.o sata_svw.o
+obj-$(CONFIG_SCSI_ATA_PIIX)	+= libata.o ata_piix.o
+obj-$(CONFIG_SCSI_SATA_PROMISE)	+= libata.o sata_promise.o
+obj-$(CONFIG_SCSI_SATA_QSTOR)	+= libata.o sata_qstor.o
+obj-$(CONFIG_SCSI_SATA_SIL)	+= libata.o sata_sil.o
+obj-$(CONFIG_SCSI_SATA_VIA)	+= libata.o sata_via.o
+obj-$(CONFIG_SCSI_SATA_VITESSE)	+= libata.o sata_vsc.o
+obj-$(CONFIG_SCSI_SATA_SIS)	+= libata.o sata_sis.o
+obj-$(CONFIG_SCSI_SATA_SX4)	+= libata.o sata_sx4.o
+obj-$(CONFIG_SCSI_SATA_NV)	+= libata.o sata_nv.o
+obj-$(CONFIG_SCSI_SATA_ULI)	+= libata.o sata_uli.o
+
+obj-$(CONFIG_ARM)		+= arm/
+
+obj-$(CONFIG_CHR_DEV_ST)	+= st.o
+obj-$(CONFIG_CHR_DEV_OSST)	+= osst.o
+obj-$(CONFIG_BLK_DEV_SD)	+= sd_mod.o
+obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
+obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
+
+scsi_mod-y			+= scsi.o hosts.o scsi_ioctl.o constants.o \
+				   scsicam.o scsi_error.o scsi_lib.o \
+				   scsi_scan.o scsi_sysfs.o \
+				   scsi_devinfo.o
+scsi_mod-$(CONFIG_SYSCTL)	+= scsi_sysctl.o
+scsi_mod-$(CONFIG_SCSI_PROC_FS)	+= scsi_proc.o
+
+sd_mod-objs	:= sd.o
+sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
+ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
+		:= -DCONFIG_NCR53C8XX_PREFETCH -DSCSI_NCR_BIG_ENDIAN \
+			-DCONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS
+CFLAGS_ncr53c8xx.o	:= $(ncr53c8xx-flags-y) $(ncr53c8xx-flags-m)
+zalon7xx-objs	:= zalon.o ncr53c8xx.o
+NCR_Q720_mod-objs	:= NCR_Q720.o ncr53c8xx.o
+cpqfc-objs	:= cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \
+		   cpqfcTSworker.o cpqfcTStrigger.o
+libata-objs	:= libata-core.o libata-scsi.o
+
+# Files generated that shall be removed upon make clean
+clean-files :=	53c7xx_d.h 53c700_d.h	\
+		53c7xx_u.h 53c700_u.h
+
+$(obj)/53c7xx.o:   $(obj)/53c7xx_d.h $(obj)/53c7xx_u.h
+$(obj)/53c700.o $(MODVERDIR)/$(obj)/53c700.ver: $(obj)/53c700_d.h
+
+# If you want to play with the firmware, uncomment
+# GENERATE_FIRMWARE := 1
+
+ifdef GENERATE_FIRMWARE
+
+$(obj)/53c7xx_d.h: $(src)/53c7xx.scr $(src)/script_asm.pl
+	$(CPP) -traditional -DCHIP=710 - < $< | grep -v '^#' | $(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h)
+
+$(obj)/53c7xx_u.h: $(obj)/53c7xx_d.h
+
+$(obj)/53c700_d.h: $(src)/53c700.scr $(src)/script_asm.pl
+	$(PERL) -s $(src)/script_asm.pl -ncr7x0_family $@ $(@:_d.h=_u.h) < $<
+
+endif
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
new file mode 100644
index 0000000..5e71a0b
--- /dev/null
+++ b/drivers/scsi/NCR5380.c
@@ -0,0 +1,2862 @@
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ *      to implement 5380 SCSI drivers under Linux with a non-trantor
+ *      architecture.
+ *
+ *      Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@colorado.edu
+ *      +1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: NCR5380.c,v $
+
+ * Revision 1.10 1998/9/2	Alan Cox
+ *				(alan@redhat.com)
+ * Fixed up the timer lockups reported so far. Things still suck. Looking 
+ * forward to 2.3 and per device request queues. Then it'll be possible to
+ * SMP thread this beast and improve life no end.
+ 
+ * Revision 1.9  1997/7/27	Ronald van Cuijlenborg
+ *				(ronald.van.cuijlenborg@tip.nl or nutty@dds.nl)
+ * (hopefully) fixed and enhanced USLEEP
+ * added support for DTC3181E card (for Mustek scanner)
+ *
+
+ * Revision 1.8			Ingmar Baumgart
+ *				(ingmar@gonzo.schwaben.de)
+ * added support for NCR53C400a card
+ *
+
+ * Revision 1.7  1996/3/2       Ray Van Tassle (rayvt@comm.mot.com)
+ * added proc_info
+ * added support needed for DTC 3180/3280
+ * fixed a couple of bugs
+ *
+
+ * Revision 1.5  1994/01/19  09:14:57  drew
+ * Fixed udelay() hack that was being used on DATAOUT phases
+ * instead of a proper wait for the final handshake.
+ *
+ * Revision 1.4  1994/01/19  06:44:25  drew
+ * *** empty log message ***
+ *
+ * Revision 1.3  1994/01/19  05:24:40  drew
+ * Added support for TCR LAST_BYTE_SENT bit.
+ *
+ * Revision 1.2  1994/01/15  06:14:11  drew
+ * REAL DMA support, bug fixes.
+ *
+ * Revision 1.1  1994/01/15  06:00:54  drew
+ * Initial revision
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Cleanup the NCR5380_transfer_dma function and DMA operation complete
+ *     code so that everything does the same thing that's done at the 
+ *     end of a pseudo-DMA read operation.
+ *
+ * 2.  Fix REAL_DMA (interrupt driven, polled works fine) -
+ *     basically, transfer size needs to be reduced by one 
+ *     and the last byte read as is done with PSEUDO_DMA.
+ * 
+ * 4.  Test SCSI-II tagged queueing (I have no devices which support 
+ *      tagged queueing)
+ *
+ * 5.  Test linked command handling code after Eric is ready with 
+ *      the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) {printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) {printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, (void*)(w), (void*)(x), (void*)(y), (void*)(z)); if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#undef REAL_DMA
+#endif
+
+#ifdef REAL_DMA_POLL
+#undef READ_OVERRUNS
+#define READ_OVERRUNS
+#endif
+
+#ifdef BOARD_REQUIRES_NO_DELAY
+#define io_recovery_delay(x)
+#else
+#define io_recovery_delay(x)	udelay(x)
+#endif
+
+/*
+ * Design
+ *
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * (Note from hch:  unfortunately it was not enough for the different
+ * m68k folks and instead of improving this driver they copied it
+ * and hacked it up for their needs.  As a consequence they lost
+ * most updates to this driver.  Maybe someone will fix all these
+ * drivers to use a common core one day..)
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started from a workqueue for each NCR5380 host in the
+ * system.  It attempts to establish I_T_L or I_T_L_Q nexuses by
+ * removing the commands from the issue queue and calling
+ * NCR5380_select() if a nexus is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If the target is 
+ * idle for too long, the system will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write an architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be 
+ *      defined.
+ * 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *      for commands that return with a CHECK CONDITION status. 
+ *
+ * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
+ *      transceivers. 
+ *
+ * DONT_USE_INTR - if defined, never use interrupts, even if we probe or
+ *      override-configure an IRQ.
+ *
+ * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
+ *      bytes at a time.  Since interrupts are disabled by default during
+ *      these transfers, we might need this to give reasonable interrupt
+ *      service time if the transfer size gets too large.
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't
+ *      rely on phase mismatch and EOP interrupts to determine end 
+ *      of phase.
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
+ *          only really want to use this if you're having a problem with
+ *          dropped characters during high speed communications, and even
+ *          then, you're going to be better off twiddling with transfersize
+ *          in the high level code.
+ *
+ * Defaults for these will be provided although the user may want to adjust 
+ * these to allocate CPU resources to the SCSI driver or "real" code.
+ * 
+ * USLEEP_SLEEP - amount of time, in jiffies, to sleep
+ *
+ * USLEEP_POLL - amount of time, in jiffies, to poll
+ *
+ * These macros MUST be defined :
+ * NCR5380_local_declare() - declare any local variables needed for your
+ *      transfer routines.
+ *
+ * NCR5380_setup(instance) - initialize any local variables needed from a given
+ *      instance of the host adapter for NCR5380_{read,write,pread,pwrite}
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * NCR5380_implementation_fields  - additional fields needed for this 
+ *      specific implementation of the NCR5380
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *      that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *      available as NCR5380_i386_dma_write_setup,
+ *      NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.
+ */
+
+static int do_abort(struct Scsi_Host *host);
+static void do_reset(struct Scsi_Host *host);
+
+/*
+ *	initialize_SCp		-	init the scsi pointer field
+ *	@cmd: command block to set up
+ *
+ *	Set up the internal fields in the SCSI command.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
+{
+	/* 
+	 * Initialize the Scsi Pointer field so that all of the commands in the 
+	 * various queues are valid.
+	 */
+
+	if (cmd->use_sg) {
+		cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+			       cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	} else {
+		cmd->SCp.buffer = NULL;
+		cmd->SCp.buffers_residual = 0;
+		cmd->SCp.ptr = (char *) cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+	}
+}
+
+/**
+ *	NCR5380_poll_politely	-	wait for NCR5380 status bits
+ *	@instance: controller to poll
+ *	@reg: 5380 register to poll
+ *	@bit: Bitmask to check
+ *	@val: Value required to exit
+ *
+ *	Polls the NCR5380 in a reasonably efficient manner waiting for
+ *	an event to occur, after a short quick poll we begin giving the
+ *	CPU back in non IRQ contexts
+ *
+ *	Returns the value of the register or a negative error code.
+ */
+ 
+static int NCR5380_poll_politely(struct Scsi_Host *instance, int reg, int bit, int val, int t)
+{
+	NCR5380_local_declare();
+	int n = 500;		/* At about 8uS a cycle for the cpu access */
+	unsigned long end = jiffies + t;
+	int r;
+	
+	NCR5380_setup(instance);
+
+	while( n-- > 0)
+	{
+		r = NCR5380_read(reg);
+		if((r & bit) == val)
+			return 0;
+		cpu_relax();
+	}
+	
+	/* t time yet ? */
+	while(time_before(jiffies, end))
+	{
+		r = NCR5380_read(reg);
+		if((r & bit) == val)
+			return 0;
+		if(!in_interrupt())
+			yield();
+		else
+			cpu_relax();
+	}
+	return -ETIMEDOUT;
+}
+
+static struct {
+	unsigned char value;
+	const char *name;
+} phases[] = {
+	{PHASE_DATAOUT, "DATAOUT"}, 
+	{PHASE_DATAIN, "DATAIN"}, 
+	{PHASE_CMDOUT, "CMDOUT"}, 
+	{PHASE_STATIN, "STATIN"}, 
+	{PHASE_MSGOUT, "MSGOUT"}, 
+	{PHASE_MSGIN, "MSGIN"}, 
+	{PHASE_UNKNOWN, "UNKNOWN"}
+};
+
+#ifdef NDEBUG
+static struct {
+	unsigned char mask;
+	const char *name;
+} signals[] = { 
+	{SR_DBP, "PARITY"}, 
+	{SR_RST, "RST"}, 
+	{SR_BSY, "BSY"}, 
+	{SR_REQ, "REQ"}, 
+	{SR_MSG, "MSG"}, 
+	{SR_CD, "CD"}, 
+	{SR_IO, "IO"}, 
+	{SR_SEL, "SEL"}, 
+	{0, NULL}
+}, 
+basrs[] = {
+	{BASR_ATN, "ATN"}, 
+	{BASR_ACK, "ACK"}, 
+	{0, NULL}
+}, 
+icrs[] = { 
+	{ICR_ASSERT_RST, "ASSERT RST"}, 
+	{ICR_ASSERT_ACK, "ASSERT ACK"}, 
+	{ICR_ASSERT_BSY, "ASSERT BSY"}, 
+	{ICR_ASSERT_SEL, "ASSERT SEL"}, 
+	{ICR_ASSERT_ATN, "ASSERT ATN"}, 
+	{ICR_ASSERT_DATA, "ASSERT DATA"}, 
+	{0, NULL}
+}, 
+mrs[] = { 
+	{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, 
+	{MR_TARGET, "MODE TARGET"}, 
+	{MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, 
+	{MR_ENABLE_PAR_INTR, "MODE PARITY INTR"}, 
+	{MR_MONITOR_BSY, "MODE MONITOR BSY"}, 
+	{MR_DMA_MODE, "MODE DMA"}, 
+	{MR_ARBITRATE, "MODE ARBITRATION"}, 
+	{0, NULL}
+};
+
+/**
+ *	NCR5380_print	-	print scsi bus signals
+ *	@instance:	adapter state to dump
+ *
+ *	Print the SCSI bus signals for debugging purposes
+ *
+ *	Locks: caller holds hostdata lock (not essential)
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance)
+{
+	NCR5380_local_declare();
+	unsigned char status, data, basr, mr, icr, i;
+	NCR5380_setup(instance);
+
+	data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+	status = NCR5380_read(STATUS_REG);
+	mr = NCR5380_read(MODE_REG);
+	icr = NCR5380_read(INITIATOR_COMMAND_REG);
+	basr = NCR5380_read(BUS_AND_STATUS_REG);
+
+	printk("STATUS_REG: %02x ", status);
+	for (i = 0; signals[i].mask; ++i)
+		if (status & signals[i].mask)
+			printk(",%s", signals[i].name);
+	printk("\nBASR: %02x ", basr);
+	for (i = 0; basrs[i].mask; ++i)
+		if (basr & basrs[i].mask)
+			printk(",%s", basrs[i].name);
+	printk("\nICR: %02x ", icr);
+	for (i = 0; icrs[i].mask; ++i)
+		if (icr & icrs[i].mask)
+			printk(",%s", icrs[i].name);
+	printk("\nMODE: %02x ", mr);
+	for (i = 0; mrs[i].mask; ++i)
+		if (mr & mrs[i].mask)
+			printk(",%s", mrs[i].name);
+	printk("\n");
+}
+
+
+/* 
+ *	NCR5380_print_phase	-	show SCSI phase
+ *	@instance: adapter to dump
+ *
+ * 	Print the current SCSI phase for debugging purposes
+ *
+ *	Locks: none
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+	NCR5380_local_declare();
+	unsigned char status;
+	int i;
+	NCR5380_setup(instance);
+
+	status = NCR5380_read(STATUS_REG);
+	if (!(status & SR_REQ))
+		printk("scsi%d : REQ not asserted, phase unknown.\n", instance->host_no);
+	else {
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
+		printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
+	}
+}
+#endif
+
+/*
+ * These need tweaking, and would probably work best as per-device 
+ * flags initialized differently for disk, tape, cd, etc devices.
+ * People with broken devices are free to experiment as to what gives
+ * the best results for them.
+ *
+ * USLEEP_SLEEP should be a minimum seek time.
+ *
+ * USLEEP_POLL should be a maximum rotational latency.
+ */
+#ifndef USLEEP_SLEEP
+/* 20 ms (reasonable hard disk speed) */
+#define USLEEP_SLEEP (20*HZ/1000)
+#endif
+/* 300 RPM (floppy speed) */
+#ifndef USLEEP_POLL
+#define USLEEP_POLL (200*HZ/1000)
+#endif
+#ifndef USLEEP_WAITLONG
+/* RvC: (reasonable time to wait on select error) */
+#define USLEEP_WAITLONG USLEEP_SLEEP
+#endif
+
+/* 
+ * Function : int should_disconnect (unsigned char cmd)
+ *
+ * Purpose : decide weather a command would normally disconnect or 
+ *      not, since if it won't disconnect we should go to sleep.
+ *
+ * Input : cmd - opcode of SCSI command
+ *
+ * Returns : DISCONNECT_LONG if we should disconnect for a really long 
+ *      time (ie always, sleep, look for REQ active, sleep), 
+ *      DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
+ *      time-to-data delay, DISCONNECT_NONE if this command would return
+ *      immediately.
+ *
+ *      Future sleep algorithms based on time to data can exploit 
+ *      something like this so they can differentiate between "normal" 
+ *      (ie, read, write, seek) and unusual commands (ie, * format).
+ *
+ * Note : We don't deal with commands that handle an immediate disconnect,
+ *        
+ */
+
+static int should_disconnect(unsigned char cmd)
+{
+	switch (cmd) {
+	case READ_6:
+	case WRITE_6:
+	case SEEK_6:
+	case READ_10:
+	case WRITE_10:
+	case SEEK_10:
+		return DISCONNECT_TIME_TO_DATA;
+	case FORMAT_UNIT:
+	case SEARCH_HIGH:
+	case SEARCH_LOW:
+	case SEARCH_EQUAL:
+		return DISCONNECT_LONG;
+	default:
+		return DISCONNECT_NONE;
+	}
+}
+
+static void NCR5380_set_timer(struct NCR5380_hostdata *hostdata, unsigned long timeout)
+{
+	hostdata->time_expires = jiffies + timeout;
+	schedule_delayed_work(&hostdata->coroutine, timeout);
+}
+
+
+static int probe_irq __initdata = 0;
+
+/**
+ *	probe_intr	-	helper for IRQ autoprobe
+ *	@irq: interrupt number
+ *	@dev_id: unused
+ *	@regs: unused
+ *
+ *	Set a flag to indicate the IRQ in question was received. This is
+ *	used by the IRQ probe code.
+ */
+ 
+static irqreturn_t __init probe_intr(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	probe_irq = irq;
+	return IRQ_HANDLED;
+}
+
+/**
+ *	NCR5380_probe_irq	-	find the IRQ of an NCR5380
+ *	@instance: NCR5380 controller
+ *	@possible: bitmask of ISA IRQ lines
+ *
+ *	Autoprobe for the IRQ line used by the NCR5380 by triggering an IRQ
+ *	and then looking to see what interrupt actually turned up.
+ *
+ *	Locks: none, irqs must be enabled on entry
+ */
+
+static int __init NCR5380_probe_irq(struct Scsi_Host *instance, int possible)
+{
+	NCR5380_local_declare();
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	unsigned long timeout;
+	int trying_irqs, i, mask;
+	NCR5380_setup(instance);
+
+	for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+		if ((mask & possible) && (request_irq(i, &probe_intr, SA_INTERRUPT, "NCR-probe", NULL) == 0))
+			trying_irqs |= mask;
+
+	timeout = jiffies + (250 * HZ / 1000);
+	probe_irq = SCSI_IRQ_NONE;
+
+	/*
+	 * A interrupt is triggered whenever BSY = false, SEL = true
+	 * and a bit set in the SELECT_ENABLE_REG is asserted on the 
+	 * SCSI bus.
+	 *
+	 * Note that the bus is only driven when the phase control signals
+	 * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
+	 * to zero.
+	 */
+
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
+
+	while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout))
+	{
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	
+	NCR5380_write(SELECT_ENABLE_REG, 0);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+		if (trying_irqs & mask)
+			free_irq(i, NULL);
+
+	return probe_irq;
+}
+
+/**
+ *	NCR58380_print_options	-	show options
+ *	@instance: unused for now
+ *
+ *	Called by probe code indicating the NCR5380 driver options that 
+ *	were selected. At some point this will switch to runtime options
+ *	read from the adapter in question
+ *
+ *	Locks: none
+ */
+
+static void __init NCR5380_print_options(struct Scsi_Host *instance)
+{
+	printk(" generic options"
+#ifdef AUTOPROBE_IRQ
+	       " AUTOPROBE_IRQ"
+#endif
+#ifdef AUTOSENSE
+	       " AUTOSENSE"
+#endif
+#ifdef DIFFERENTIAL
+	       " DIFFERENTIAL"
+#endif
+#ifdef REAL_DMA
+	       " REAL DMA"
+#endif
+#ifdef REAL_DMA_POLL
+	       " REAL DMA POLL"
+#endif
+#ifdef PARITY
+	       " PARITY"
+#endif
+#ifdef PSEUDO_DMA
+	       " PSEUDO DMA"
+#endif
+#ifdef UNSAFE
+	       " UNSAFE "
+#endif
+	    );
+	printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
+	printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {
+		printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);
+	}
+}
+
+/**
+ *	NCR5380_print_status 	-	dump controller info
+ *	@instance: controller to dump
+ *
+ *	Print commands in the various queues, called from NCR5380_abort 
+ *	and NCR5380_debug to aid debugging.
+ *
+ *	Locks: called functions disable irqs
+ */
+
+static void NCR5380_print_status(struct Scsi_Host *instance)
+{
+	NCR5380_dprint(NDEBUG_ANY, instance);
+	NCR5380_dprint_phase(NDEBUG_ANY, instance);
+}
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+ */
+
+#undef SPRINTF
+#define SPRINTF(args...) do { if(pos < buffer + length-80) pos += sprintf(pos, ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length);
+static
+char *lprint_command(unsigned char *cmd, char *pos, char *buffer, int len);
+static
+char *lprint_opcode(int opcode, char *pos, char *buffer, int length);
+
+static
+int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	char *pos = buffer;
+	struct NCR5380_hostdata *hostdata;
+	Scsi_Cmnd *ptr;
+
+	hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+
+	if (inout) {		/* Has data been written to the file ? */
+#ifdef DTC_PUBLIC_RELEASE
+		dtc_wmaxi = dtc_maxi = 0;
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+		pas_wmaxi = pas_maxi = 0;
+#endif
+		return (-ENOSYS);	/* Currently this is a no-op */
+	}
+	SPRINTF("NCR5380 core release=%d.   ", NCR5380_PUBLIC_RELEASE);
+	if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400)
+		SPRINTF("ncr53c400 release=%d.  ", NCR53C400_PUBLIC_RELEASE);
+#ifdef DTC_PUBLIC_RELEASE
+	SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);
+#endif
+#ifdef T128_PUBLIC_RELEASE
+	SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);
+#endif
+#ifdef GENERIC_NCR5380_PUBLIC_RELEASE
+	SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+	SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
+#endif
+
+	SPRINTF("\nBase Addr: 0x%05lX    ", (long) instance->base);
+	SPRINTF("io_port: %04x      ", (int) instance->io_port);
+	if (instance->irq == SCSI_IRQ_NONE)
+		SPRINTF("IRQ: None.\n");
+	else
+		SPRINTF("IRQ: %d.\n", instance->irq);
+
+#ifdef DTC_PUBLIC_RELEASE
+	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", dtc_wmaxi, dtc_maxi);
+#endif
+#ifdef PAS16_PUBLIC_RELEASE
+	SPRINTF("Highwater I/O busy_spin_counts -- write: %d  read: %d\n", pas_wmaxi, pas_maxi);
+#endif
+	spin_lock_irq(instance->host_lock);
+	if (!hostdata->connected)
+		SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
+	else
+		pos = lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, pos, buffer, length);
+	SPRINTF("scsi%d: issue_queue\n", instance->host_no);
+	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+
+	SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		pos = lprint_Scsi_Cmnd(ptr, pos, buffer, length);
+	spin_unlock_irq(instance->host_lock);
+	
+	*start = buffer;
+	if (pos - buffer < offset)
+		return 0;
+	else if (pos - buffer - offset < length)
+		return pos - buffer - offset;
+	return length;
+}
+
+static char *lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, char *pos, char *buffer, int length)
+{
+	SPRINTF("scsi%d : destination target %d, lun %d\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
+	SPRINTF("        command = ");
+	pos = lprint_command(cmd->cmnd, pos, buffer, length);
+	return (pos);
+}
+
+static char *lprint_command(unsigned char *command, char *pos, char *buffer, int length)
+{
+	int i, s;
+	pos = lprint_opcode(command[0], pos, buffer, length);
+	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+		SPRINTF("%02x ", command[i]);
+	SPRINTF("\n");
+	return (pos);
+}
+
+static char *lprint_opcode(int opcode, char *pos, char *buffer, int length)
+{
+	SPRINTF("%2d (0x%02x)", opcode, opcode);
+	return (pos);
+}
+
+
+/**
+ *	NCR5380_init	-	initialise an NCR5380
+ *	@instance: adapter to configure
+ *	@flags: control flags
+ *
+ *	Initializes *instance and corresponding 5380 chip,
+ *      with flags OR'd into the initial flags value.
+ *
+ *	Notes : I assume that the host, hostno, and id bits have been
+ *      set correctly.  I don't care about the irq and other fields. 
+ *
+ *	Returns 0 for success
+ *
+ *	Locks: interrupts must be enabled when we are called 
+ */
+
+static int __devinit NCR5380_init(struct Scsi_Host *instance, int flags)
+{
+	NCR5380_local_declare();
+	int i, pass;
+	unsigned long timeout;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+
+	if(in_interrupt())
+		printk(KERN_ERR "NCR5380_init called with interrupts off!\n");
+	/* 
+	 * On NCR53C400 boards, NCR5380 registers are mapped 8 past 
+	 * the base address.
+	 */
+
+#ifdef NCR53C400
+	if (flags & FLAG_NCR53C400)
+		instance->NCR5380_instance_name += NCR53C400_address_adjust;
+#endif
+
+	NCR5380_setup(instance);
+
+	hostdata->aborted = 0;
+	hostdata->id_mask = 1 << instance->this_id;
+	for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+		if (i > hostdata->id_mask)
+			hostdata->id_higher_mask |= i;
+	for (i = 0; i < 8; ++i)
+		hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+	hostdata->dmalen = 0;
+#endif
+	hostdata->targets_present = 0;
+	hostdata->connected = NULL;
+	hostdata->issue_queue = NULL;
+	hostdata->disconnected_queue = NULL;
+	
+	INIT_WORK(&hostdata->coroutine, NCR5380_main, hostdata);
+	
+#ifdef NCR5380_STATS
+	for (i = 0; i < 8; ++i) {
+		hostdata->time_read[i] = 0;
+		hostdata->time_write[i] = 0;
+		hostdata->bytes_read[i] = 0;
+		hostdata->bytes_write[i] = 0;
+	}
+	hostdata->timebase = 0;
+	hostdata->pendingw = 0;
+	hostdata->pendingr = 0;
+#endif
+
+	/* The CHECK code seems to break the 53C400. Will check it later maybe */
+	if (flags & FLAG_NCR53C400)
+		hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
+	else
+		hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT | flags;
+
+	hostdata->host = instance;
+	hostdata->time_expires = 0;
+
+#ifndef AUTOSENSE
+	if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)
+		    printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" "         without AUTOSENSE option, contingent allegiance conditions may\n"
+		    	   "         be incorrectly cleared.\n", instance->host_no);
+#endif				/* def AUTOSENSE */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+	NCR5380_write(SELECT_ENABLE_REG, 0);
+
+#ifdef NCR53C400
+	if (hostdata->flags & FLAG_NCR53C400) {
+		NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
+	}
+#endif
+
+	/* 
+	 * Detect and correct bus wedge problems.
+	 *
+	 * If the system crashed, it may have crashed in a state 
+	 * where a SCSI command was still executing, and the 
+	 * SCSI bus is not in a BUS FREE STATE.
+	 *
+	 * If this is the case, we'll try to abort the currently
+	 * established nexus which we know nothing about, and that
+	 * failing, do a hard reset of the SCSI bus 
+	 */
+
+	for (pass = 1; (NCR5380_read(STATUS_REG) & SR_BSY) && pass <= 6; ++pass) {
+		switch (pass) {
+		case 1:
+		case 3:
+		case 5:
+			printk(KERN_INFO "scsi%d: SCSI bus busy, waiting up to five seconds\n", instance->host_no);
+			timeout = jiffies + 5 * HZ;
+			NCR5380_poll_politely(instance, STATUS_REG, SR_BSY, 0, 5*HZ);
+			break;
+		case 2:
+			printk(KERN_WARNING "scsi%d: bus busy, attempting abort\n", instance->host_no);
+			do_abort(instance);
+			break;
+		case 4:
+			printk(KERN_WARNING "scsi%d: bus busy, attempting reset\n", instance->host_no);
+			do_reset(instance);
+			break;
+		case 6:
+			printk(KERN_ERR "scsi%d: bus locked solid or invalid override\n", instance->host_no);
+			return -ENXIO;
+		}
+	}
+	return 0;
+}
+
+/**
+ *	NCR5380_exit	-	remove an NCR5380
+ *	@instance: adapter to remove
+ */
+
+static void __devexit NCR5380_exit(struct Scsi_Host *instance)
+{
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+
+	cancel_delayed_work(&hostdata->coroutine);
+	flush_scheduled_work();
+}
+
+/**
+ *	NCR5380_queue_command 		-	queue a command
+ *	@cmd: SCSI command
+ *	@done: completion handler
+ *
+ *      cmd is added to the per instance issue_queue, with minor 
+ *      twiddling done to the host specific fields of cmd.  If the 
+ *      main coroutine is not running, it is restarted.
+ *
+ *	Locks: host lock taken by caller
+ */
+
+static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)) 
+{
+	struct Scsi_Host *instance = cmd->device->host;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	Scsi_Cmnd *tmp;
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+		printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n", instance->host_no);
+		cmd->result = (DID_ERROR << 16);
+		done(cmd);
+		return 0;
+	}
+#endif				/* (NDEBUG & NDEBUG_NO_WRITE) */
+
+#ifdef NCR5380_STATS
+	switch (cmd->cmnd[0]) {
+		case WRITE:
+		case WRITE_6:
+		case WRITE_10:
+			hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+			hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+			hostdata->pendingw++;
+			break;
+		case READ:
+		case READ_6:
+		case READ_10:
+			hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+			hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+			hostdata->pendingr++;
+			break;
+	}
+#endif
+
+	/* 
+	 * We use the host_scribble field as a pointer to the next command  
+	 * in a queue 
+	 */
+
+	cmd->host_scribble = NULL;
+	cmd->scsi_done = done;
+	cmd->result = 0;
+
+	/* 
+	 * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+	 * commands are added to the head of the queue since any command will
+	 * clear the contingent allegiance condition that exists and the 
+	 * sense data is only guaranteed to be valid while the condition exists.
+	 */
+
+	if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+		LIST(cmd, hostdata->issue_queue);
+		cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
+		hostdata->issue_queue = cmd;
+	} else {
+		for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
+		LIST(cmd, tmp);
+		tmp->host_scribble = (unsigned char *) cmd;
+	}
+	dprintk(NDEBUG_QUEUES, ("scsi%d : command added to %s of queue\n", instance->host_no, (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail"));
+
+	/* Run the coroutine if it isn't already running. */
+	/* Kick off command processing */
+	schedule_work(&hostdata->coroutine);
+	return 0;
+}
+
+
+/**
+ *	NCR5380_main	-	NCR state machines
+ *
+ *	NCR5380_main is a coroutine that runs as long as more work can 
+ *      be done on the NCR5380 host adapters in a system.  Both 
+ *      NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *      in case it is not running.
+ * 
+ *	Locks: called as its own thread with no locks held. Takes the
+ *	host lock and called routines may take the isa dma lock.
+ */
+
+static void NCR5380_main(void *p)
+{
+	struct NCR5380_hostdata *hostdata = p;
+	struct Scsi_Host *instance = hostdata->host;
+	Scsi_Cmnd *tmp, *prev;
+	int done;
+	
+	spin_lock_irq(instance->host_lock);
+	do {
+		/* Lock held here */
+		done = 1;
+		if (!hostdata->connected && !hostdata->selecting) {
+			dprintk(NDEBUG_MAIN, ("scsi%d : not connected\n", instance->host_no));
+			/*
+			 * Search through the issue_queue for a command destined
+			 * for a target that's not busy.
+			 */
+			for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble) 
+			{
+				if (prev != tmp)
+					dprintk(NDEBUG_LISTS, ("MAIN tmp=%p   target=%d   busy=%d lun=%d\n", tmp, tmp->target, hostdata->busy[tmp->target], tmp->lun));
+				/*  When we find one, remove it from the issue queue. */
+				if (!(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))) {
+					if (prev) {
+						REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
+						prev->host_scribble = tmp->host_scribble;
+					} else {
+						REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
+						hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
+					}
+					tmp->host_scribble = NULL;
+
+					/* 
+					 * Attempt to establish an I_T_L nexus here. 
+					 * On success, instance->hostdata->connected is set.
+					 * On failure, we must add the command back to the
+					 *   issue queue so we can keep trying. 
+					 */
+					dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main() : command for target %d lun %d removed from issue_queue\n", instance->host_no, tmp->target, tmp->lun));
+	
+					/*
+					 * A successful selection is defined as one that 
+					 * leaves us with the command connected and 
+					 * in hostdata->connected, OR has terminated the
+					 * command.
+					 *
+					 * With successful commands, we fall through
+					 * and see if we can do an information transfer,
+					 * with failures we will restart.
+					 */
+					hostdata->selecting = NULL;
+					/* RvC: have to preset this to indicate a new command is being performed */
+
+					if (!NCR5380_select(instance, tmp,
+							    /* 
+							     * REQUEST SENSE commands are issued without tagged
+							     * queueing, even on SCSI-II devices because the 
+							     * contingent allegiance condition exists for the 
+							     * entire unit.
+							     */
+							    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
+						break;
+					} else {
+						LIST(tmp, hostdata->issue_queue);
+						tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
+						hostdata->issue_queue = tmp;
+						done = 0;
+						dprintk(NDEBUG_MAIN|NDEBUG_QUEUES, ("scsi%d : main(): select() failed, returned to issue_queue\n", instance->host_no));
+					}
+					/* lock held here still */
+				}	/* if target/lun is not busy */
+			}	/* for */
+			/* exited locked */
+		}	/* if (!hostdata->connected) */
+		if (hostdata->selecting) {
+			tmp = (Scsi_Cmnd *) hostdata->selecting;
+			/* Selection will drop and retake the lock */
+			if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
+				/* Ok ?? */
+			} else {
+				/* RvC: device failed, so we wait a long time
+				   this is needed for Mustek scanners, that
+				   do not respond to commands immediately
+				   after a scan */
+				printk(KERN_DEBUG "scsi%d: device %d did not respond in time\n", instance->host_no, tmp->device->id);
+				LIST(tmp, hostdata->issue_queue);
+				tmp->host_scribble = (unsigned char *) hostdata->issue_queue;
+				hostdata->issue_queue = tmp;
+				NCR5380_set_timer(hostdata, USLEEP_WAITLONG);
+			}
+		}	/* if hostdata->selecting */
+		if (hostdata->connected
+#ifdef REAL_DMA
+		    && !hostdata->dmalen
+#endif
+		    && (!hostdata->time_expires || time_before_eq(hostdata->time_expires, jiffies))
+		    ) {
+			dprintk(NDEBUG_MAIN, ("scsi%d : main() : performing information transfer\n", instance->host_no));
+			NCR5380_information_transfer(instance);
+			dprintk(NDEBUG_MAIN, ("scsi%d : main() : done set false\n", instance->host_no));
+			done = 0;
+		} else
+			break;
+	} while (!done);
+	
+	spin_unlock_irq(instance->host_lock);
+}
+
+#ifndef DONT_USE_INTR
+
+/**
+ * 	NCR5380_intr	-	generic NCR5380 irq handler
+ *	@irq: interrupt number
+ *	@dev_id: device info
+ *	@regs: registers (unused)
+ *
+ *	Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *      from the disconnected queue, and restarting NCR5380_main() 
+ *      as required.
+ *
+ *	Locks: takes the needed instance locks
+ */
+
+static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs) 
+{
+	NCR5380_local_declare();
+	struct Scsi_Host *instance = (struct Scsi_Host *)dev_id;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	int done;
+	unsigned char basr;
+	unsigned long flags;
+
+	dprintk(NDEBUG_INTR, ("scsi : NCR5380 irq %d triggered\n", irq));
+
+	do {
+		done = 1;
+		spin_lock_irqsave(instance->host_lock, flags);
+		/* Look for pending interrupts */
+		NCR5380_setup(instance);
+		basr = NCR5380_read(BUS_AND_STATUS_REG);
+		/* XXX dispatch to appropriate routine if found and done=0 */
+		if (basr & BASR_IRQ) {
+			NCR5380_dprint(NDEBUG_INTR, instance);
+			if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+				done = 0;
+				dprintk(NDEBUG_INTR, ("scsi%d : SEL interrupt\n", instance->host_no));
+				NCR5380_reselect(instance);
+				(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+			} else if (basr & BASR_PARITY_ERROR) {
+				dprintk(NDEBUG_INTR, ("scsi%d : PARITY interrupt\n", instance->host_no));
+				(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+			} else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+				dprintk(NDEBUG_INTR, ("scsi%d : RESET interrupt\n", instance->host_no));
+				(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+			} else {
+#if defined(REAL_DMA)
+				/*
+				 * We should only get PHASE MISMATCH and EOP interrupts
+				 * if we have DMA enabled, so do a sanity check based on
+				 * the current setting of the MODE register.
+				 */
+
+				if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & BASR_END_DMA_TRANSFER) || !(basr & BASR_PHASE_MATCH))) {
+					int transfered;
+
+					if (!hostdata->connected)
+						panic("scsi%d : received end of DMA interrupt with no connected cmd\n", instance->hostno);
+
+					transfered = (hostdata->dmalen - NCR5380_dma_residual(instance));
+					hostdata->connected->SCp.this_residual -= transferred;
+					hostdata->connected->SCp.ptr += transferred;
+					hostdata->dmalen = 0;
+
+					(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+							
+					/* FIXME: we need to poll briefly then defer a workqueue task ! */
+					NCR5380_poll_politely(hostdata, BUS_AND_STATUS_REG, BASR_ACK, 0, 2*HZ);
+
+					NCR5380_write(MODE_REG, MR_BASE);
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+				}
+#else
+				dprintk(NDEBUG_INTR, ("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)));
+				(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#endif
+			}
+		}	/* if BASR_IRQ */
+		spin_unlock_irqrestore(instance->host_lock, flags);
+		if(!done)
+			schedule_work(&hostdata->coroutine);
+	} while (!done);
+	return IRQ_HANDLED;
+}
+
+#endif 
+
+/**
+ *	collect_stats		-	collect stats on a scsi command
+ *	@hostdata: adapter 
+ *	@cmd: command being issued
+ *
+ *	Update the statistical data by parsing the command in question
+ */
+ 
+static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd) 
+{
+#ifdef NCR5380_STATS
+	switch (cmd->cmnd[0]) {
+	case WRITE:
+	case WRITE_6:
+	case WRITE_10:
+		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+		hostdata->pendingw--;
+		break;
+	case READ:
+	case READ_6:
+	case READ_10:
+		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+		hostdata->pendingr--;
+		break;
+	}
+#endif
+}
+
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *      int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *      including ARBITRATION, SELECTION, and initial message out for 
+ *      IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ *      target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *      new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *      the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *      0 if selection succeeded or failed because the target 
+ *      did not respond.
+ *
+ * Side effects : 
+ *      If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *              with registers as they should have been on entry - ie
+ *              SELECT_ENABLE will be set appropriately, the NCR5380
+ *              will cease to drive any SCSI bus signals.
+ *
+ *      If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *              instance->connected will be set to cmd.  
+ *              SELECT interrupt will be disabled.
+ *
+ *      If failed (no target) : cmd->scsi_done() will be called, and the 
+ *              cmd->result host byte set to DID_BAD_TARGET.
+ *
+ *	Locks: caller holds hostdata lock in IRQ mode
+ */
+ 
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag) 
+{
+	NCR5380_local_declare();
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	unsigned char tmp[3], phase;
+	unsigned char *data;
+	int len;
+	unsigned long timeout;
+	unsigned char value;
+	int err;
+	NCR5380_setup(instance);
+
+	if (hostdata->selecting)
+		goto part2;
+
+	hostdata->restart_select = 0;
+
+	NCR5380_dprint(NDEBUG_ARBITRATION, instance);
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : starting arbitration, id = %d\n", instance->host_no, instance->this_id));
+
+	/* 
+	 * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+	 * data bus during SELECTION.
+	 */
+
+	NCR5380_write(TARGET_COMMAND_REG, 0);
+
+	/* 
+	 * Start arbitration.
+	 */
+
+	NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+	NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+
+	/* We can be relaxed here, interrupts are on, we are
+	   in workqueue context, the birds are singing in the trees */
+	spin_unlock_irq(instance->host_lock);
+	err = NCR5380_poll_politely(instance, INITIATOR_COMMAND_REG, ICR_ARBITRATION_PROGRESS, ICR_ARBITRATION_PROGRESS, 5*HZ);
+	spin_lock_irq(instance->host_lock);
+	if (err < 0) {
+		printk(KERN_DEBUG "scsi: arbitration timeout at %d\n", __LINE__);
+		NCR5380_write(MODE_REG, MR_BASE);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		goto failed;
+	}
+
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : arbitration complete\n", instance->host_no));
+
+	/* 
+	 * The arbitration delay is 2.2us, but this is a minimum and there is 
+	 * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+	 * the integral nature of udelay().
+	 *
+	 */
+
+	udelay(3);
+
+	/* Check for lost arbitration */
+	if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) || (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) || (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n", instance->host_no));
+		goto failed;
+	}
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
+
+	if (!(hostdata->flags & FLAG_DTC3181E) &&
+	    /* RvC: DTC3181E has some trouble with this
+	     *      so we simply removed it. Seems to work with
+	     *      only Mustek scanner attached
+	     */
+	    (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
+		NCR5380_write(MODE_REG, MR_BASE);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		dprintk(NDEBUG_ARBITRATION, ("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n", instance->host_no));
+		goto failed;
+	}
+	/* 
+	 * Again, bus clear + bus settle time is 1.2us, however, this is 
+	 * a minimum so we'll udelay ceil(1.2)
+	 */
+
+	udelay(2);
+
+	dprintk(NDEBUG_ARBITRATION, ("scsi%d : won arbitration\n", instance->host_no));
+
+	/* 
+	 * Now that we have won arbitration, start Selection process, asserting 
+	 * the host and target ID's on the SCSI bus.
+	 */
+
+	NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+	/* 
+	 * Raise ATN while SEL is true before BSY goes false from arbitration,
+	 * since this is the only way to guarantee that we'll get a MESSAGE OUT
+	 * phase immediately after selection.
+	 */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+	NCR5380_write(MODE_REG, MR_BASE);
+
+	/* 
+	 * Reselect interrupts must be turned off prior to the dropping of BSY,
+	 * otherwise we will trigger an interrupt.
+	 */
+	NCR5380_write(SELECT_ENABLE_REG, 0);
+
+	/*
+	 * The initiator shall then wait at least two deskew delays and release 
+	 * the BSY signal.
+	 */
+	udelay(1);		/* wingel -- wait two bus deskew delay >2*45ns */
+
+	/* Reset BSY */
+	NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+	/* 
+	 * Something weird happens when we cease to drive BSY - looks
+	 * like the board/chip is letting us do another read before the 
+	 * appropriate propagation delay has expired, and we're confusing
+	 * a BSY signal from ourselves as the target's response to SELECTION.
+	 *
+	 * A small delay (the 'C++' frontend breaks the pipeline with an
+	 * unnecessary jump, making it work on my 386-33/Trantor T128, the
+	 * tighter 'C' code breaks and requires this) solves the problem - 
+	 * the 1 us delay is arbitrary, and only used because this delay will 
+	 * be the same on other platforms and since it works here, it should 
+	 * work there.
+	 *
+	 * wingel suggests that this could be due to failing to wait
+	 * one deskew delay.
+	 */
+
+	udelay(1);
+
+	dprintk(NDEBUG_SELECTION, ("scsi%d : selecting target %d\n", instance->host_no, cmd->device->id));
+
+	/* 
+	 * The SCSI specification calls for a 250 ms timeout for the actual 
+	 * selection.
+	 */
+
+	timeout = jiffies + (250 * HZ / 1000);
+
+	/* 
+	 * XXX very interesting - we're seeing a bounce where the BSY we 
+	 * asserted is being reflected / still asserted (propagation delay?)
+	 * and it's detecting as true.  Sigh.
+	 */
+
+	hostdata->select_time = 0;	/* we count the clock ticks at which we polled */
+	hostdata->selecting = cmd;
+
+part2:
+	/* RvC: here we enter after a sleeping period, or immediately after
+	   execution of part 1
+	   we poll only once ech clock tick */
+	value = NCR5380_read(STATUS_REG) & (SR_BSY | SR_IO);
+
+	if (!value && (hostdata->select_time < HZ/4)) {
+		/* RvC: we still must wait for a device response */
+		hostdata->select_time++;	/* after 25 ticks the device has failed */
+		NCR5380_set_timer(hostdata, 1);
+		return 0;	/* RvC: we return here with hostdata->selecting set,
+				   to go to sleep */
+	}
+
+	hostdata->selecting = NULL;/* clear this pointer, because we passed the
+					   waiting period */
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == (SR_SEL | SR_IO)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		NCR5380_reselect(instance);
+		printk("scsi%d : reselection after won arbitration?\n", instance->host_no);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		return -1;
+	}
+	/* 
+	 * No less than two deskew delays after the initiator detects the 
+	 * BSY signal is true, it shall release the SEL signal and may 
+	 * change the DATA BUS.                                     -wingel
+	 */
+
+	udelay(1);
+
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+	if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		if (hostdata->targets_present & (1 << cmd->device->id)) {
+			printk(KERN_DEBUG "scsi%d : weirdness\n", instance->host_no);
+			if (hostdata->restart_select)
+				printk(KERN_DEBUG "\trestart select\n");
+			NCR5380_dprint(NDEBUG_SELECTION, instance);
+			NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+			return -1;
+		}
+		cmd->result = DID_BAD_TARGET << 16;
+		collect_stats(hostdata, cmd);
+		cmd->scsi_done(cmd);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		dprintk(NDEBUG_SELECTION, ("scsi%d : target did not respond within 250ms\n", instance->host_no));
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		return 0;
+	}
+	hostdata->targets_present |= (1 << cmd->device->id);
+
+	/*
+	 * Since we followed the SCSI spec, and raised ATN while SEL 
+	 * was true but before BSY was false during selection, the information
+	 * transfer phase should be a MESSAGE OUT phase so that we can send the
+	 * IDENTIFY message.
+	 * 
+	 * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+	 * message (2 bytes) with a tag ID that we increment with every command
+	 * until it wraps back to 0.
+	 *
+	 * XXX - it turns out that there are some broken SCSI-II devices,
+	 *       which claim to support tagged queuing but fail when more than
+	 *       some number of commands are issued at once.
+	 */
+
+	/* Wait for start of REQ/ACK handshake */
+
+	spin_unlock_irq(instance->host_lock);
+	err = NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, HZ);
+	spin_lock_irq(instance->host_lock);
+	
+	if(err) {
+		printk(KERN_ERR "scsi%d: timeout at NCR5380.c:%d\n", instance->host_no, __LINE__);
+		NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		goto failed;
+	}
+
+	dprintk(NDEBUG_SELECTION, ("scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id));
+	tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun);
+
+	len = 1;
+	cmd->tag = 0;
+
+	/* Send message(s) */
+	data = tmp;
+	phase = PHASE_MSGOUT;
+	NCR5380_transfer_pio(instance, &phase, &len, &data);
+	dprintk(NDEBUG_SELECTION, ("scsi%d : nexus established.\n", instance->host_no));
+	/* XXX need to handle errors here */
+	hostdata->connected = cmd;
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+
+	if (cmd->SCp.ptr != (char *)cmd->sense_buffer) {
+		initialize_SCp(cmd);
+	}
+
+	return 0;
+
+	/* Selection failed */
+failed:
+	return -1;
+
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *      what phase is expected, *count - pointer to number of 
+ *      bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *      maximum number of bytes, 0 if all bytes or transfered or exit
+ *      is in same phase.
+ *
+ *      Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
+	NCR5380_local_declare();
+	unsigned char p = *phase, tmp;
+	int c = *count;
+	unsigned char *d = *data;
+	/*
+	 *      RvC: some administrative data to process polling time
+	 */
+	int break_allowed = 0;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	NCR5380_setup(instance);
+
+	if (!(p & SR_IO))
+		dprintk(NDEBUG_PIO, ("scsi%d : pio write %d bytes\n", instance->host_no, c));
+	else
+		dprintk(NDEBUG_PIO, ("scsi%d : pio read %d bytes\n", instance->host_no, c));
+
+	/* 
+	 * The NCR5380 chip will only drive the SCSI bus when the 
+	 * phase specified in the appropriate bits of the TARGET COMMAND
+	 * REGISTER match the STATUS REGISTER
+	 */
+
+	 NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+	/* RvC: don't know if this is necessary, but other SCSI I/O is short
+	 *      so breaks are not necessary there
+	 */
+	if ((p == PHASE_DATAIN) || (p == PHASE_DATAOUT)) {
+		break_allowed = 1;
+	}
+	do {
+		/* 
+		 * Wait for assertion of REQ, after which the phase bits will be 
+		 * valid 
+		 */
+
+		/* RvC: we simply poll once, after that we stop temporarily
+		 *      and let the device buffer fill up
+		 *      if breaking is not allowed, we keep polling as long as needed
+		 */
+
+		/* FIXME */
+		while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ) && !break_allowed);
+		if (!(tmp & SR_REQ)) {
+			/* timeout condition */
+			NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+			break;
+		}
+
+		dprintk(NDEBUG_HANDSHAKE, ("scsi%d : REQ detected\n", instance->host_no));
+
+		/* Check for phase mismatch */
+		if ((tmp & PHASE_MASK) != p) {
+			dprintk(NDEBUG_HANDSHAKE, ("scsi%d : phase mismatch\n", instance->host_no));
+			NCR5380_dprint_phase(NDEBUG_HANDSHAKE, instance);
+			break;
+		}
+		/* Do actual transfer from SCSI bus to / from memory */
+		if (!(p & SR_IO))
+			NCR5380_write(OUTPUT_DATA_REG, *d);
+		else
+			*d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+		++d;
+
+		/* 
+		 * The SCSI standard suggests that in MSGOUT phase, the initiator
+		 * should drop ATN on the last byte of the message phase
+		 * after REQ has been asserted for the handshake but before
+		 * the initiator raises ACK.
+		 */
+
+		if (!(p & SR_IO)) {
+			if (!((p & SR_MSG) && c > 1)) {
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+				NCR5380_dprint(NDEBUG_PIO, instance);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+			} else {
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+				NCR5380_dprint(NDEBUG_PIO, instance);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+			}
+		} else {
+			NCR5380_dprint(NDEBUG_PIO, instance);
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+		}
+
+		/* FIXME - if this fails bus reset ?? */
+		NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, 0, 5*HZ);
+		dprintk(NDEBUG_HANDSHAKE, ("scsi%d : req false, handshake complete\n", instance->host_no));
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *      message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *      message.  We must exit with ACK asserted, so that the calling
+ *      code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+		if (!(p == PHASE_MSGIN && c == 1)) {
+			if (p == PHASE_MSGOUT && c > 1)
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+			else
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		}
+	} while (--c);
+
+	dprintk(NDEBUG_PIO, ("scsi%d : residual %d\n", instance->host_no, c));
+
+	*count = c;
+	*data = d;
+	tmp = NCR5380_read(STATUS_REG);
+	if (tmp & SR_REQ)
+		*phase = tmp & PHASE_MASK;
+	else
+		*phase = PHASE_UNKNOWN;
+
+	if (!c || (*phase == p))
+		return 0;
+	else
+		return -1;
+}
+
+/**
+ *	do_reset	-	issue a reset command
+ *	@host: adapter to reset
+ *
+ *	Issue a reset sequence to the NCR5380 and try and get the bus
+ *	back into sane shape.
+ *
+ *	Locks: caller holds queue lock
+ */
+ 
+static void do_reset(struct Scsi_Host *host) {
+	NCR5380_local_declare();
+	NCR5380_setup(host);
+
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(NCR5380_read(STATUS_REG) & PHASE_MASK));
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+	udelay(25);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ *      called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ *
+ * Locks: queue lock held by caller
+ *	FIXME: sort this out and get new_eh running
+ */
+
+static int do_abort(struct Scsi_Host *host) {
+	NCR5380_local_declare();
+	unsigned char *msgptr, phase, tmp;
+	int len;
+	int rc;
+	NCR5380_setup(host);
+
+
+	/* Request message out phase */
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+	/* 
+	 * Wait for the target to indicate a valid phase by asserting 
+	 * REQ.  Once this happens, we'll have either a MSGOUT phase 
+	 * and can immediately send the ABORT message, or we'll have some 
+	 * other phase and will have to source/sink data.
+	 * 
+	 * We really don't care what value was on the bus or what value
+	 * the target sees, so we just handshake.
+	 */
+
+	rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, SR_REQ, 60 * HZ);
+	
+	if(rc < 0)
+		return -1;
+
+	tmp = (unsigned char)rc;
+	
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+	if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+		rc = NCR5380_poll_politely(host, STATUS_REG, SR_REQ, 0, 3*HZ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+		if(rc == -1)
+			return -1;
+	}
+	tmp = ABORT;
+	msgptr = &tmp;
+	len = 1;
+	phase = PHASE_MSGOUT;
+	NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+
+	/*
+	 * If we got here, and the command completed successfully,
+	 * we're about to go into bus free state.
+	 */
+
+	return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA) || defined(PSEUDO_DMA) || defined (REAL_DMA_POLL)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *      or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *      what phase is expected, *count - pointer to number of 
+ *      bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *      maximum number of bytes, 0 if all bytes or transfered or exit
+ *      is in same phase.
+ *
+ *      Also, *phase, *count, *data are modified in place.
+ *
+ *	Locks: io_request lock held by caller
+ */
+
+
+static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data) {
+	NCR5380_local_declare();
+	register int c = *count;
+	register unsigned char p = *phase;
+	register unsigned char *d = *data;
+	unsigned char tmp;
+	int foo;
+#if defined(REAL_DMA_POLL)
+	int cnt, toPIO;
+	unsigned char saved_data = 0, overrun = 0, residue;
+#endif
+
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+
+	NCR5380_setup(instance);
+
+	if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+		*phase = tmp;
+		return -1;
+	}
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
+#ifdef READ_OVERRUNS
+	if (p & SR_IO) {
+		c -= 2;
+	}
+#endif
+	dprintk(NDEBUG_DMA, ("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d));
+	hostdata->dma_len = (p & SR_IO) ? NCR5380_dma_read_setup(instance, d, c) : NCR5380_dma_write_setup(instance, d, c);
+#endif
+
+	NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+#ifdef REAL_DMA
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#elif defined(REAL_DMA_POLL)
+	NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+#else
+	/*
+	 * Note : on my sample board, watch-dog timeouts occurred when interrupts
+	 * were not disabled for the duration of a single DMA transfer, from 
+	 * before the setting of DMA mode to after transfer of the last byte.
+	 */
+
+#if defined(PSEUDO_DMA) && defined(UNSAFE)
+	spin_unlock_irq(instance->host_lock);
+#endif
+	/* KLL May need eop and parity in 53c400 */
+	if (hostdata->flags & FLAG_NCR53C400)
+		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_PAR_CHECK | MR_ENABLE_PAR_INTR | MR_ENABLE_EOP_INTR | MR_DMA_MODE | MR_MONITOR_BSY);
+	else
+		NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+#endif				/* def REAL_DMA */
+
+	dprintk(NDEBUG_DMA, ("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)));
+
+	/* 
+	 *	On the PAS16 at least I/O recovery delays are not needed here.
+	 *	Everyone else seems to want them.
+	 */
+
+	if (p & SR_IO) {
+		io_recovery_delay(1);
+		NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+	} else {
+		io_recovery_delay(1);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+		io_recovery_delay(1);
+		NCR5380_write(START_DMA_SEND_REG, 0);
+		io_recovery_delay(1);
+	}
+
+#if defined(REAL_DMA_POLL)
+	do {
+		tmp = NCR5380_read(BUS_AND_STATUS_REG);
+	} while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | BASR_END_DMA_TRANSFER)));
+
+/*
+   At this point, either we've completed DMA, or we have a phase mismatch,
+   or we've unexpectedly lost BUSY (which is a real error).
+
+   For write DMAs, we want to wait until the last byte has been
+   transferred out over the bus before we turn off DMA mode.  Alas, there
+   seems to be no terribly good way of doing this on a 5380 under all
+   conditions.  For non-scatter-gather operations, we can wait until REQ
+   and ACK both go false, or until a phase mismatch occurs.  Gather-writes
+   are nastier, since the device will be expecting more data than we
+   are prepared to send it, and REQ will remain asserted.  On a 53C8[01] we
+   could test LAST BIT SENT to assure transfer (I imagine this is precisely
+   why this signal was added to the newer chips) but on the older 538[01]
+   this signal does not exist.  The workaround for this lack is a watchdog;
+   we bail out of the wait-loop after a modest amount of wait-time if
+   the usual exit conditions are not met.  Not a terribly clean or
+   correct solution :-%
+
+   Reads are equally tricky due to a nasty characteristic of the NCR5380.
+   If the chip is in DMA mode for an READ, it will respond to a target's
+   REQ by latching the SCSI data into the INPUT DATA register and asserting
+   ACK, even if it has _already_ been notified by the DMA controller that
+   the current DMA transfer has completed!  If the NCR5380 is then taken
+   out of DMA mode, this already-acknowledged byte is lost.
+
+   This is not a problem for "one DMA transfer per command" reads, because
+   the situation will never arise... either all of the data is DMA'ed
+   properly, or the target switches to MESSAGE IN phase to signal a
+   disconnection (either operation bringing the DMA to a clean halt).
+   However, in order to handle scatter-reads, we must work around the
+   problem.  The chosen fix is to DMA N-2 bytes, then check for the
+   condition before taking the NCR5380 out of DMA mode.  One or two extra
+   bytes are transferred via PIO as necessary to fill out the original
+   request.
+ */
+
+	if (p & SR_IO) {
+#ifdef READ_OVERRUNS
+		udelay(10);
+		if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) == (BASR_PHASE_MATCH | BASR_ACK))) {
+			saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+			overrun = 1;
+		}
+#endif
+	} else {
+		int limit = 100;
+		while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || (NCR5380_read(STATUS_REG) & SR_REQ)) {
+			if (!(tmp & BASR_PHASE_MATCH))
+				break;
+			if (--limit < 0)
+				break;
+		}
+	}
+
+	dprintk(NDEBUG_DMA, ("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", instance->host_no, tmp, NCR5380_read(STATUS_REG)));
+
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	residue = NCR5380_dma_residual(instance);
+	c -= residue;
+	*count -= c;
+	*data += c;
+	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
+
+#ifdef READ_OVERRUNS
+	if (*phase == p && (p & SR_IO) && residue == 0) {
+		if (overrun) {
+			dprintk(NDEBUG_DMA, ("Got an input overrun, using saved byte\n"));
+			**data = saved_data;
+			*data += 1;
+			*count -= 1;
+			cnt = toPIO = 1;
+		} else {
+			printk("No overrun??\n");
+			cnt = toPIO = 2;
+		}
+		dprintk(NDEBUG_DMA, ("Doing %d-byte PIO to 0x%X\n", cnt, *data));
+		NCR5380_transfer_pio(instance, phase, &cnt, data);
+		*count -= toPIO - cnt;
+	}
+#endif
+
+	dprintk(NDEBUG_DMA, ("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", *data, *count, *(*data + *count - 1), *(*data + *count)));
+	return 0;
+
+#elif defined(REAL_DMA)
+	return 0;
+#else				/* defined(REAL_DMA_POLL) */
+	if (p & SR_IO) {
+#ifdef DMA_WORKS_RIGHT
+		foo = NCR5380_pread(instance, d, c);
+#else
+		int diff = 1;
+		if (hostdata->flags & FLAG_NCR53C400) {
+			diff = 0;
+		}
+		if (!(foo = NCR5380_pread(instance, d, c - diff))) {
+			/*
+			 * We can't disable DMA mode after successfully transferring 
+			 * what we plan to be the last byte, since that would open up
+			 * a race condition where if the target asserted REQ before 
+			 * we got the DMA mode reset, the NCR5380 would have latched
+			 * an additional byte into the INPUT DATA register and we'd
+			 * have dropped it.
+			 * 
+			 * The workaround was to transfer one fewer bytes than we 
+			 * intended to with the pseudo-DMA read function, wait for 
+			 * the chip to latch the last byte, read it, and then disable
+			 * pseudo-DMA mode.
+			 * 
+			 * After REQ is asserted, the NCR5380 asserts DRQ and ACK.
+			 * REQ is deasserted when ACK is asserted, and not reasserted
+			 * until ACK goes false.  Since the NCR5380 won't lower ACK
+			 * until DACK is asserted, which won't happen unless we twiddle
+			 * the DMA port or we take the NCR5380 out of DMA mode, we 
+			 * can guarantee that we won't handshake another extra 
+			 * byte.
+			 */
+
+			if (!(hostdata->flags & FLAG_NCR53C400)) {
+				while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ));
+				/* Wait for clean handshake */
+				while (NCR5380_read(STATUS_REG) & SR_REQ);
+				d[c - 1] = NCR5380_read(INPUT_DATA_REG);
+			}
+		}
+#endif
+	} else {
+#ifdef DMA_WORKS_RIGHT
+		foo = NCR5380_pwrite(instance, d, c);
+#else
+		int timeout;
+		dprintk(NDEBUG_C400_PWRITE, ("About to pwrite %d bytes\n", c));
+		if (!(foo = NCR5380_pwrite(instance, d, c))) {
+			/*
+			 * Wait for the last byte to be sent.  If REQ is being asserted for 
+			 * the byte we're interested, we'll ACK it and it will go false.  
+			 */
+			if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) {
+				timeout = 20000;
+				while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH));
+
+				if (!timeout)
+					dprintk(NDEBUG_LAST_BYTE_SENT, ("scsi%d : timed out on last byte\n", instance->host_no));
+
+				if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) {
+					hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT;
+					if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) {
+						hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT;
+						dprintk(NDEBUG_LAST_WRITE_SENT, ("scsi%d : last bit sent works\n", instance->host_no));
+					}
+				}
+			} else {
+				dprintk(NDEBUG_C400_PWRITE, ("Waiting for LASTBYTE\n"));
+				while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT));
+				dprintk(NDEBUG_C400_PWRITE, ("Got LASTBYTE\n"));
+			}
+		}
+#endif
+	}
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	if ((!(p & SR_IO)) && (hostdata->flags & FLAG_NCR53C400)) {
+		dprintk(NDEBUG_C400_PWRITE, ("53C400w: Checking for IRQ\n"));
+		if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
+			dprintk(NDEBUG_C400_PWRITE, ("53C400w:    got it, reading reset interrupt reg\n"));
+			NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+		} else {
+			printk("53C400w:    IRQ NOT THERE!\n");
+		}
+	}
+	*data = d + c;
+	*count = 0;
+	*phase = NCR5380_read(STATUS_REG) & PHASE_MASK;
+#if defined(PSEUDO_DMA) && defined(UNSAFE)
+	spin_lock_irq(instance->host_lock);
+#endif				/* defined(REAL_DMA_POLL) */
+	return foo;
+#endif				/* def REAL_DMA */
+}
+#endif				/* defined(REAL_DMA) | defined(PSEUDO_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ *      directs us to.  Operates on the currently connected command, 
+ *      instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *      modified if a command disconnects, *instance->connected will
+ *      change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ *      to recover from an unexpected bus free condition.
+ *
+ * Locks: io_request_lock held by caller in IRQ mode
+ */
+
+static void NCR5380_information_transfer(struct Scsi_Host *instance) {
+	NCR5380_local_declare();
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+	unsigned char msgout = NOP;
+	int sink = 0;
+	int len;
+#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+	int transfersize;
+#endif
+	unsigned char *data;
+	unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
+	Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+	/* RvC: we need to set the end of the polling time */
+	unsigned long poll_time = jiffies + USLEEP_POLL;
+
+	NCR5380_setup(instance);
+
+	while (1) {
+		tmp = NCR5380_read(STATUS_REG);
+		/* We only have a valid SCSI phase when REQ is asserted */
+		if (tmp & SR_REQ) {
+			phase = (tmp & PHASE_MASK);
+			if (phase != old_phase) {
+				old_phase = phase;
+				NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
+			}
+			if (sink && (phase != PHASE_MSGOUT)) {
+				NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+				while (NCR5380_read(STATUS_REG) & SR_REQ);
+				NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+				sink = 0;
+				continue;
+			}
+			switch (phase) {
+			case PHASE_DATAIN:
+			case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+				printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n", instance->host_no);
+				sink = 1;
+				do_abort(instance);
+				cmd->result = DID_ERROR << 16;
+				cmd->done(cmd);
+				return;
+#endif
+				/* 
+				 * If there is no room left in the current buffer in the
+				 * scatter-gather list, move onto the next one.
+				 */
+
+				if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+					++cmd->SCp.buffer;
+					--cmd->SCp.buffers_residual;
+					cmd->SCp.this_residual = cmd->SCp.buffer->length;
+					cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+						       cmd->SCp.buffer->offset;
+					dprintk(NDEBUG_INFORMATION, ("scsi%d : %d bytes and %d buffers left\n", instance->host_no, cmd->SCp.this_residual, cmd->SCp.buffers_residual));
+				}
+				/*
+				 * The preferred transfer method is going to be 
+				 * PSEUDO-DMA for systems that are strictly PIO,
+				 * since we can let the hardware do the handshaking.
+				 *
+				 * For this to work, we need to know the transfersize
+				 * ahead of time, since the pseudo-DMA code will sit
+				 * in an unconditional loop.
+				 */
+
+#if defined(PSEUDO_DMA) || defined(REAL_DMA_POLL)
+				/* KLL
+				 * PSEUDO_DMA is defined here. If this is the g_NCR5380
+				 * driver then it will always be defined, so the
+				 * FLAG_NO_PSEUDO_DMA is used to inhibit PDMA in the base
+				 * NCR5380 case.  I think this is a fairly clean solution.
+				 * We supplement these 2 if's with the flag.
+				 */
+#ifdef NCR5380_dma_xfer_len
+				if (!cmd->device->borken && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
+#else
+				transfersize = cmd->transfersize;
+
+#ifdef LIMIT_TRANSFERSIZE	/* If we have problems with interrupt service */
+				if (transfersize > 512)
+					transfersize = 512;
+#endif				/* LIMIT_TRANSFERSIZE */
+
+				if (!cmd->device->borken && transfersize && !(hostdata->flags & FLAG_NO_PSEUDO_DMA) && cmd->SCp.this_residual && !(cmd->SCp.this_residual % transfersize)) {
+					/* Limit transfers to 32K, for xx400 & xx406
+					 * pseudoDMA that transfers in 128 bytes blocks. */
+					if (transfersize > 32 * 1024)
+						transfersize = 32 * 1024;
+#endif
+					len = transfersize;
+					if (NCR5380_transfer_dma(instance, &phase, &len, (unsigned char **) &cmd->SCp.ptr)) {
+						/*
+						 * If the watchdog timer fires, all future accesses to this
+						 * device will use the polled-IO.
+						 */
+						printk("scsi%d : switching target %d lun %d to slow handshake\n", instance->host_no, cmd->device->id, cmd->device->lun);
+						cmd->device->borken = 1;
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+						sink = 1;
+						do_abort(instance);
+						cmd->result = DID_ERROR << 16;
+						cmd->done(cmd);
+						/* XXX - need to source or sink data here, as appropriate */
+					} else
+						cmd->SCp.this_residual -= transfersize - len;
+				} else
+#endif				/* defined(PSEUDO_DMA) || defined(REAL_DMA_POLL) */
+					NCR5380_transfer_pio(instance, &phase, (int *) &cmd->SCp.this_residual, (unsigned char **)
+							     &cmd->SCp.ptr);
+				break;
+			case PHASE_MSGIN:
+				len = 1;
+				data = &tmp;
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				cmd->SCp.Message = tmp;
+
+				switch (tmp) {
+					/*
+					 * Linking lets us reduce the time required to get the 
+					 * next command out to the device, hopefully this will
+					 * mean we don't waste another revolution due to the delays
+					 * required by ARBITRATION and another SELECTION.
+					 *
+					 * In the current implementation proposal, low level drivers
+					 * merely have to start the next command, pointed to by 
+					 * next_link, done() is called as with unlinked commands.
+					 */
+#ifdef LINKED
+				case LINKED_CMD_COMPLETE:
+				case LINKED_FLG_CMD_COMPLETE:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked command complete.\n", instance->host_no, cmd->device->id, cmd->device->lun));
+					/* 
+					 * Sanity check : A linked command should only terminate with
+					 * one of these messages if there are more linked commands
+					 * available.
+					 */
+					if (!cmd->next_link) {
+						printk("scsi%d : target %d lun %d linked command complete, no next_link\n" instance->host_no, cmd->device->id, cmd->device->lun);
+						sink = 1;
+						do_abort(instance);
+						return;
+					}
+					initialize_SCp(cmd->next_link);
+					/* The next command is still part of this process */
+					cmd->next_link->tag = cmd->tag;
+					cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+					dprintk(NDEBUG_LINKED, ("scsi%d : target %d lun %d linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun));
+					collect_stats(hostdata, cmd);
+					cmd->scsi_done(cmd);
+					cmd = hostdata->connected;
+					break;
+#endif				/* def LINKED */
+				case ABORT:
+				case COMMAND_COMPLETE:
+					/* Accept message by clearing ACK */
+					sink = 1;
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					hostdata->connected = NULL;
+					dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d, lun %d completed\n", instance->host_no, cmd->device->id, cmd->device->lun));
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+
+					/* 
+					 * I'm not sure what the correct thing to do here is : 
+					 * 
+					 * If the command that just executed is NOT a request 
+					 * sense, the obvious thing to do is to set the result
+					 * code to the values of the stored parameters.
+					 * 
+					 * If it was a REQUEST SENSE command, we need some way 
+					 * to differentiate between the failure code of the original
+					 * and the failure code of the REQUEST sense - the obvious
+					 * case is success, where we fall through and leave the result
+					 * code unchanged.
+					 * 
+					 * The non-obvious place is where the REQUEST SENSE failed 
+					 */
+
+					if (cmd->cmnd[0] != REQUEST_SENSE)
+						cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+					else if (status_byte(cmd->SCp.Status) != GOOD)
+						cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+
+#ifdef AUTOSENSE
+					if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+						dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
+						cmd->cmnd[0] = REQUEST_SENSE;
+						cmd->cmnd[1] &= 0xe0;
+						cmd->cmnd[2] = 0;
+						cmd->cmnd[3] = 0;
+						cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+						cmd->cmnd[5] = 0;
+
+						cmd->SCp.buffer = NULL;
+						cmd->SCp.buffers_residual = 0;
+						cmd->SCp.ptr = (char *) cmd->sense_buffer;
+						cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
+
+						LIST(cmd, hostdata->issue_queue);
+						cmd->host_scribble = (unsigned char *)
+						    hostdata->issue_queue;
+						hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+						dprintk(NDEBUG_QUEUES, ("scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no));
+					} else
+#endif				/* def AUTOSENSE */
+					{
+						collect_stats(hostdata, cmd);
+						cmd->scsi_done(cmd);
+					}
+
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					/* 
+					 * Restore phase bits to 0 so an interrupted selection, 
+					 * arbitration can resume.
+					 */
+					NCR5380_write(TARGET_COMMAND_REG, 0);
+
+					while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+						barrier();
+					return;
+				case MESSAGE_REJECT:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					switch (hostdata->last_message) {
+					case HEAD_OF_QUEUE_TAG:
+					case ORDERED_QUEUE_TAG:
+					case SIMPLE_QUEUE_TAG:
+						cmd->device->simple_tags = 0;
+						hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+						break;
+					default:
+						break;
+					}
+				case DISCONNECT:{
+						/* Accept message by clearing ACK */
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+						cmd->device->disconnect = 1;
+						LIST(cmd, hostdata->disconnected_queue);
+						cmd->host_scribble = (unsigned char *)
+						    hostdata->disconnected_queue;
+						hostdata->connected = NULL;
+						hostdata->disconnected_queue = cmd;
+						dprintk(NDEBUG_QUEUES, ("scsi%d : command for target %d lun %d was moved from connected to" "  the disconnected_queue\n", instance->host_no, cmd->device->id, cmd->device->lun));
+						/* 
+						 * Restore phase bits to 0 so an interrupted selection, 
+						 * arbitration can resume.
+						 */
+						NCR5380_write(TARGET_COMMAND_REG, 0);
+
+						/* Enable reselect interrupts */
+						NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+						/* Wait for bus free to avoid nasty timeouts - FIXME timeout !*/
+						/* NCR538_poll_politely(instance, STATUS_REG, SR_BSY, 0, 30 * HZ); */
+						while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+							barrier();
+						return;
+					}
+					/* 
+					 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+					 * operation, in violation of the SCSI spec so we can safely 
+					 * ignore SAVE/RESTORE pointers calls.
+					 *
+					 * Unfortunately, some disks violate the SCSI spec and 
+					 * don't issue the required SAVE_POINTERS message before
+					 * disconnecting, and we have to break spec to remain 
+					 * compatible.
+					 */
+				case SAVE_POINTERS:
+				case RESTORE_POINTERS:
+					/* Accept message by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					break;
+				case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte         
+ * 0            EXTENDED_MESSAGE == 1
+ * 1            length (includes one byte for code, doesn't 
+ *              include first two bytes)
+ * 2            code
+ * 3..length+1  arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+					extended_msg[0] = EXTENDED_MESSAGE;
+					/* Accept first byte by clearing ACK */
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+					dprintk(NDEBUG_EXTENDED, ("scsi%d : receiving extended message\n", instance->host_no));
+
+					len = 2;
+					data = extended_msg + 1;
+					phase = PHASE_MSGIN;
+					NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+					dprintk(NDEBUG_EXTENDED, ("scsi%d : length=%d, code=0x%02x\n", instance->host_no, (int) extended_msg[1], (int) extended_msg[2]));
+
+					if (!len && extended_msg[1] <= (sizeof(extended_msg) - 1)) {
+						/* Accept third byte by clearing ACK */
+						NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+						len = extended_msg[1] - 1;
+						data = extended_msg + 3;
+						phase = PHASE_MSGIN;
+
+						NCR5380_transfer_pio(instance, &phase, &len, &data);
+						dprintk(NDEBUG_EXTENDED, ("scsi%d : message received, residual %d\n", instance->host_no, len));
+
+						switch (extended_msg[2]) {
+						case EXTENDED_SDTR:
+						case EXTENDED_WDTR:
+						case EXTENDED_MODIFY_DATA_POINTER:
+						case EXTENDED_EXTENDED_IDENTIFY:
+							tmp = 0;
+						}
+					} else if (len) {
+						printk("scsi%d: error receiving extended message\n", instance->host_no);
+						tmp = 0;
+					} else {
+						printk("scsi%d: extended message code %02x length %d is too long\n", instance->host_no, extended_msg[2], extended_msg[1]);
+						tmp = 0;
+					}
+					/* Fall through to reject message */
+
+					/* 
+					 * If we get something weird that we aren't expecting, 
+					 * reject it.
+					 */
+				default:
+					if (!tmp) {
+						printk("scsi%d: rejecting message ", instance->host_no);
+						print_msg(extended_msg);
+						printk("\n");
+					} else if (tmp != EXTENDED_MESSAGE)
+						printk("scsi%d: rejecting unknown message %02x from target %d, lun %d\n", instance->host_no, tmp, cmd->device->id, cmd->device->lun);
+					else
+						printk("scsi%d: rejecting unknown extended message code %02x, length %d from target %d, lun %d\n", instance->host_no, extended_msg[1], extended_msg[0], cmd->device->id, cmd->device->lun);
+
+					msgout = MESSAGE_REJECT;
+					NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+					break;
+				}	/* switch (tmp) */
+				break;
+			case PHASE_MSGOUT:
+				len = 1;
+				data = &msgout;
+				hostdata->last_message = msgout;
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				if (msgout == ABORT) {
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+					hostdata->connected = NULL;
+					cmd->result = DID_ERROR << 16;
+					collect_stats(hostdata, cmd);
+					cmd->scsi_done(cmd);
+					NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+					return;
+				}
+				msgout = NOP;
+				break;
+			case PHASE_CMDOUT:
+				len = cmd->cmd_len;
+				data = cmd->cmnd;
+				/* 
+				 * XXX for performance reasons, on machines with a 
+				 * PSEUDO-DMA architecture we should probably 
+				 * use the dma transfer function.  
+				 */
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				if (!cmd->device->disconnect && should_disconnect(cmd->cmnd[0])) {
+					NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+					dprintk(NDEBUG_USLEEP, ("scsi%d : issued command, sleeping until %ul\n", instance->host_no, hostdata->time_expires));
+					return;
+				}
+				break;
+			case PHASE_STATIN:
+				len = 1;
+				data = &tmp;
+				NCR5380_transfer_pio(instance, &phase, &len, &data);
+				cmd->SCp.Status = tmp;
+				break;
+			default:
+				printk("scsi%d : unknown phase\n", instance->host_no);
+				NCR5380_dprint(NDEBUG_ALL, instance);
+			}	/* switch(phase) */
+		}		/* if (tmp * SR_REQ) */
+		else {
+			/* RvC: go to sleep if polling time expired
+			 */
+			if (!cmd->device->disconnect && time_after_eq(jiffies, poll_time)) {
+				NCR5380_set_timer(hostdata, USLEEP_SLEEP);
+				dprintk(NDEBUG_USLEEP, ("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no, hostdata->time_expires));
+				return;
+			}
+		}
+	}			/* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *      field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *      nexus has been reestablished,
+ *      
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ * Locks: io_request_lock held by caller if IRQ driven
+ */
+
+static void NCR5380_reselect(struct Scsi_Host *instance) {
+	NCR5380_local_declare();
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+	 instance->hostdata;
+	unsigned char target_mask;
+	unsigned char lun, phase;
+	int len;
+	unsigned char msg[3];
+	unsigned char *data;
+	Scsi_Cmnd *tmp = NULL, *prev;
+	int abort = 0;
+	NCR5380_setup(instance);
+
+	/*
+	 * Disable arbitration, etc. since the host adapter obviously
+	 * lost, and tell an interrupted NCR5380_select() to restart.
+	 */
+
+	NCR5380_write(MODE_REG, MR_BASE);
+	hostdata->restart_select = 1;
+
+	target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+	dprintk(NDEBUG_SELECTION, ("scsi%d : reselect\n", instance->host_no));
+
+	/* 
+	 * At this point, we have detected that our SCSI ID is on the bus,
+	 * SEL is true and BSY was false for at least one bus settle delay
+	 * (400 ns).
+	 *
+	 * We must assert BSY ourselves, until the target drops the SEL
+	 * signal.
+	 */
+
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+
+	/* FIXME: timeout too long, must fail to workqueue */	
+	if(NCR5380_poll_politely(instance, STATUS_REG, SR_SEL, 0, 2*HZ)<0)
+		abort = 1;
+		
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	/*
+	 * Wait for target to go into MSGIN.
+	 * FIXME: timeout needed and fail to work queeu
+	 */
+
+	if(NCR5380_poll_politely(instance, STATUS_REG, SR_REQ, SR_REQ, 2*HZ))
+		abort = 1;
+
+	len = 1;
+	data = msg;
+	phase = PHASE_MSGIN;
+	NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+	if (!(msg[0] & 0x80)) {
+		printk(KERN_ERR "scsi%d : expecting IDENTIFY message, got ", instance->host_no);
+		print_msg(msg);
+		abort = 1;
+	} else {
+		/* Accept message by clearing ACK */
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		lun = (msg[0] & 0x07);
+
+		/* 
+		 * We need to add code for SCSI-II to track which devices have
+		 * I_T_L_Q nexuses established, and which have simple I_T_L
+		 * nexuses so we can chose to do additional data transfer.
+		 */
+
+		/* 
+		 * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+		 * just reestablished, and remove it from the disconnected queue.
+		 */
+
+
+		for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
+			if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+			    ) {
+				if (prev) {
+					REMOVE(prev, prev->host_scribble, tmp, tmp->host_scribble);
+					prev->host_scribble = tmp->host_scribble;
+				} else {
+					REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
+					hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
+				}
+				tmp->host_scribble = NULL;
+				break;
+			}
+		if (!tmp) {
+			printk(KERN_ERR "scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n", instance->host_no, target_mask, lun);
+			/* 
+			 * Since we have an established nexus that we can't do anything with,
+			 * we must abort it.  
+			 */
+			abort = 1;
+		}
+	}
+
+	if (abort) {
+		do_abort(instance);
+	} else {
+		hostdata->connected = tmp;
+		dprintk(NDEBUG_RESELECTION, ("scsi%d : nexus established, target = %d, lun = %d, tag = %d\n", instance->host_no, tmp->target, tmp->lun, tmp->tag));
+	}
+}
+
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : called by interrupt handler when DMA finishes or a phase
+ *      mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L
+ *      nexus has been reestablished, on failure NULL is returned.
+ */
+
+#ifdef REAL_DMA
+static void NCR5380_dma_complete(NCR5380_instance * instance) {
+	NCR5380_local_declare();
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata * instance->hostdata);
+	int transferred;
+	NCR5380_setup(instance);
+
+	/*
+	 * XXX this might not be right.
+	 *
+	 * Wait for final byte to transfer, ie wait for ACK to go false.
+	 *
+	 * We should use the Last Byte Sent bit, unfortunately this is 
+	 * not available on the 5380/5381 (only the various CMOS chips)
+	 *
+	 * FIXME: timeout, and need to handle long timeout/irq case
+	 */
+
+	NCR5380_poll_politely(instance, BUS_AND_STATUS_REG, BASR_ACK, 0, 5*HZ);
+
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+	/*
+	 * The only places we should see a phase mismatch and have to send
+	 * data from the same set of pointers will be the data transfer
+	 * phases.  So, residual, requested length are only important here.
+	 */
+
+	if (!(hostdata->connected->SCp.phase & SR_CD)) {
+		transferred = instance->dmalen - NCR5380_dma_residual();
+		hostdata->connected->SCp.this_residual -= transferred;
+		hostdata->connected->SCp.ptr += transferred;
+	}
+}
+#endif				/* def REAL_DMA */
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ *      host byte of the result field to, if zero DID_ABORTED is 
+ *      used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ *	XXX - there is no way to abort the command that is currently 
+ *	connected, you have to wait for it to complete.  If this is 
+ *	a problem, we could implement longjmp() / setjmp(), setjmp()
+ *	called where the loop started in NCR5380_main().
+ *
+ * Locks: host lock taken by caller
+ */
+
+static int NCR5380_abort(Scsi_Cmnd * cmd) {
+	NCR5380_local_declare();
+	struct Scsi_Host *instance = cmd->device->host;
+	struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+	Scsi_Cmnd *tmp, **prev;
+	
+	printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
+	print_Scsi_Cmnd(cmd);
+
+	NCR5380_print_status(instance);
+
+	NCR5380_setup(instance);
+
+	dprintk(NDEBUG_ABORT, ("scsi%d : abort called\n", instance->host_no));
+	dprintk(NDEBUG_ABORT, ("        basr 0x%X, sr 0x%X\n", NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)));
+
+#if 0
+/*
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+	if (hostdata->connected == cmd) {
+		dprintk(NDEBUG_ABORT, ("scsi%d : aborting connected command\n", instance->host_no));
+		hostdata->aborted = 1;
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN);
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */
+
+		return 0;
+	}
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ *          from the issue queue.
+ */
+ 
+	dprintk(NDEBUG_ABORT, ("scsi%d : abort going into loop.\n", instance->host_no));
+	for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
+		if (cmd == tmp) {
+			REMOVE(5, *prev, tmp, tmp->host_scribble);
+			(*prev) = (Scsi_Cmnd *) tmp->host_scribble;
+			tmp->host_scribble = NULL;
+			tmp->result = DID_ABORT << 16;
+			dprintk(NDEBUG_ABORT, ("scsi%d : abort removed command from issue queue.\n", instance->host_no));
+			tmp->done(tmp);
+			return SUCCESS;
+		}
+#if (NDEBUG  & NDEBUG_ABORT)
+	/* KLL */
+		else if (prev == tmp)
+			printk(KERN_ERR "scsi%d : LOOP\n", instance->host_no);
+#endif
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *          and let the high level SCSI driver retry at a later time or 
+ *          issue a reset.
+ *
+ *          Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *          case of noresets less efficient, and would pollute our code.  So,
+ *          we fail.
+ */
+
+	if (hostdata->connected) {
+		dprintk(NDEBUG_ABORT, ("scsi%d : abort failed, command connected.\n", instance->host_no));
+		return FAILED;
+	}
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ *      there are no connected commands, we reconnect the I_T_L or 
+ *      I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
+		if (cmd == tmp) {
+			dprintk(NDEBUG_ABORT, ("scsi%d : aborting disconnected command.\n", instance->host_no));
+
+			if (NCR5380_select(instance, cmd, (int) cmd->tag))
+				return FAILED;
+			dprintk(NDEBUG_ABORT, ("scsi%d : nexus reestablished.\n", instance->host_no));
+
+			do_abort(instance);
+
+			for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
+				if (cmd == tmp) {
+					REMOVE(5, *prev, tmp, tmp->host_scribble);
+					*prev = (Scsi_Cmnd *) tmp->host_scribble;
+					tmp->host_scribble = NULL;
+					tmp->result = DID_ABORT << 16;
+					tmp->done(tmp);
+					return SUCCESS;
+				}
+		}
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *          the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+	printk(KERN_WARNING "scsi%d : warning : SCSI command probably completed successfully\n"
+			"         before abortion\n", instance->host_no);
+	return FAILED;
+}
+
+
+/* 
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SUCCESS
+ *
+ * Locks: host lock taken by caller
+ */
+
+static int NCR5380_bus_reset(Scsi_Cmnd * cmd) {
+	NCR5380_local_declare();
+	NCR5380_setup(cmd->device->host);
+
+	NCR5380_print_status(cmd->device->host);
+	do_reset(cmd->device->host);
+	return SUCCESS;
+}
+
+/* 
+ * Function : int NCR5380_device_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset a SCSI device
+ *
+ * Returns : FAILED
+ *
+ * Locks: io_request_lock held by caller
+ */
+
+static int NCR5380_device_reset(Scsi_Cmnd * cmd) {
+	return FAILED;
+}
+
+/* 
+ * Function : int NCR5380_host_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset a SCSI device
+ *
+ * Returns : FAILED
+ *
+ * Locks: io_request_lock held by caller
+ */
+
+static int NCR5380_host_reset(Scsi_Cmnd * cmd) {
+	return FAILED;
+}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
new file mode 100644
index 0000000..b5103f9
--- /dev/null
+++ b/drivers/scsi/NCR5380.h
@@ -0,0 +1,432 @@
+/* 
+ * NCR 5380 defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix consulting and custom programming)
+ * 	drew@colorado.edu
+ *      +1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 7
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: NCR5380.h,v $
+ */
+
+#ifndef NCR5380_H
+#define NCR5380_H
+
+#include <linux/interrupt.h>
+
+#define NCR5380_PUBLIC_RELEASE 7
+#define NCR53C400_PUBLIC_RELEASE 2
+
+#define NDEBUG_ARBITRATION	0x1
+#define NDEBUG_AUTOSENSE	0x2
+#define NDEBUG_DMA		0x4
+#define NDEBUG_HANDSHAKE	0x8
+#define NDEBUG_INFORMATION	0x10
+#define NDEBUG_INIT		0x20
+#define NDEBUG_INTR		0x40
+#define NDEBUG_LINKED		0x80
+#define NDEBUG_MAIN		0x100
+#define NDEBUG_NO_DATAOUT	0x200
+#define NDEBUG_NO_WRITE		0x400
+#define NDEBUG_PIO		0x800
+#define NDEBUG_PSEUDO_DMA	0x1000
+#define NDEBUG_QUEUES		0x2000
+#define NDEBUG_RESELECTION	0x4000
+#define NDEBUG_SELECTION	0x8000
+#define NDEBUG_USLEEP		0x10000
+#define NDEBUG_LAST_BYTE_SENT	0x20000
+#define NDEBUG_RESTART_SELECT	0x40000
+#define NDEBUG_EXTENDED		0x80000
+#define NDEBUG_C400_PREAD	0x100000
+#define NDEBUG_C400_PWRITE	0x200000
+#define NDEBUG_LISTS		0x400000
+
+#define NDEBUG_ANY		0xFFFFFFFFUL
+
+/* 
+ * The contents of the OUTPUT DATA register are asserted on the bus when
+ * either arbitration is occurring or the phase-indicating signals (
+ * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA
+ * bit in the INITIATOR COMMAND register is set.
+ */
+
+#define OUTPUT_DATA_REG         0	/* wo DATA lines on SCSI bus */
+#define CURRENT_SCSI_DATA_REG   0	/* ro same */
+
+#define INITIATOR_COMMAND_REG	1	/* rw */
+#define ICR_ASSERT_RST		0x80	/* rw Set to assert RST  */
+#define ICR_ARBITRATION_PROGRESS 0x40	/* ro Indicates arbitration complete */
+#define ICR_TRI_STATE		0x40	/* wo Set to tri-state drivers */
+#define ICR_ARBITRATION_LOST	0x20	/* ro Indicates arbitration lost */
+#define ICR_DIFF_ENABLE		0x20	/* wo Set to enable diff. drivers */
+#define ICR_ASSERT_ACK		0x10	/* rw ini Set to assert ACK */
+#define ICR_ASSERT_BSY		0x08	/* rw Set to assert BSY */
+#define ICR_ASSERT_SEL 		0x04	/* rw Set to assert SEL */
+#define ICR_ASSERT_ATN		0x02	/* rw Set to assert ATN */
+#define ICR_ASSERT_DATA		0x01	/* rw SCSI_DATA_REG is asserted */
+
+#ifdef DIFFERENTIAL
+#define ICR_BASE		ICR_DIFF_ENABLE
+#else
+#define ICR_BASE		0
+#endif
+
+#define MODE_REG		2
+/*
+ * Note : BLOCK_DMA code will keep DRQ asserted for the duration of the 
+ * transfer, causing the chip to hog the bus.  You probably don't want 
+ * this.
+ */
+#define MR_BLOCK_DMA_MODE	0x80	/* rw block mode DMA */
+#define MR_TARGET		0x40	/* rw target mode */
+#define MR_ENABLE_PAR_CHECK	0x20	/* rw enable parity checking */
+#define MR_ENABLE_PAR_INTR	0x10	/* rw enable bad parity interrupt */
+#define MR_ENABLE_EOP_INTR	0x08	/* rw enable eop interrupt */
+#define MR_MONITOR_BSY		0x04	/* rw enable int on unexpected bsy fail */
+#define MR_DMA_MODE		0x02	/* rw DMA / pseudo DMA mode */
+#define MR_ARBITRATE		0x01	/* rw start arbitration */
+
+#ifdef PARITY
+#define MR_BASE			MR_ENABLE_PAR_CHECK
+#else
+#define MR_BASE			0
+#endif
+
+#define TARGET_COMMAND_REG	3
+#define TCR_LAST_BYTE_SENT	0x80	/* ro DMA done */
+#define TCR_ASSERT_REQ		0x08	/* tgt rw assert REQ */
+#define TCR_ASSERT_MSG		0x04	/* tgt rw assert MSG */
+#define TCR_ASSERT_CD		0x02	/* tgt rw assert CD */
+#define TCR_ASSERT_IO		0x01	/* tgt rw assert IO */
+
+#define STATUS_REG		4	/* ro */
+/*
+ * Note : a set bit indicates an active signal, driven by us or another 
+ * device.
+ */
+#define SR_RST			0x80
+#define SR_BSY			0x40
+#define SR_REQ			0x20
+#define SR_MSG			0x10
+#define SR_CD			0x08
+#define SR_IO			0x04
+#define SR_SEL			0x02
+#define SR_DBP			0x01
+
+/*
+ * Setting a bit in this register will cause an interrupt to be generated when 
+ * BSY is false and SEL true and this bit is asserted  on the bus.
+ */
+#define SELECT_ENABLE_REG	4	/* wo */
+
+#define BUS_AND_STATUS_REG	5	/* ro */
+#define BASR_END_DMA_TRANSFER	0x80	/* ro set on end of transfer */
+#define BASR_DRQ		0x40	/* ro mirror of DRQ pin */
+#define BASR_PARITY_ERROR	0x20	/* ro parity error detected */
+#define BASR_IRQ		0x10	/* ro mirror of IRQ pin */
+#define BASR_PHASE_MATCH	0x08	/* ro Set when MSG CD IO match TCR */
+#define BASR_BUSY_ERROR		0x04	/* ro Unexpected change to inactive state */
+#define BASR_ATN 		0x02	/* ro BUS status */
+#define BASR_ACK		0x01	/* ro BUS status */
+
+/* Write any value to this register to start a DMA send */
+#define START_DMA_SEND_REG	5	/* wo */
+
+/* 
+ * Used in DMA transfer mode, data is latched from the SCSI bus on
+ * the falling edge of REQ (ini) or ACK (tgt)
+ */
+#define INPUT_DATA_REG			6	/* ro */
+
+/* Write any value to this register to start a DMA receive */
+#define START_DMA_TARGET_RECEIVE_REG	6	/* wo */
+
+/* Read this register to clear interrupt conditions */
+#define RESET_PARITY_INTERRUPT_REG	7	/* ro */
+
+/* Write any value to this register to start an ini mode DMA receive */
+#define START_DMA_INITIATOR_RECEIVE_REG 7	/* wo */
+
+#define C400_CONTROL_STATUS_REG NCR53C400_register_offset-8	/* rw */
+
+#define CSR_RESET              0x80	/* wo  Resets 53c400 */
+#define CSR_53C80_REG          0x80	/* ro  5380 registers busy */
+#define CSR_TRANS_DIR          0x40	/* rw  Data transfer direction */
+#define CSR_SCSI_BUFF_INTR     0x20	/* rw  Enable int on transfer ready */
+#define CSR_53C80_INTR         0x10	/* rw  Enable 53c80 interrupts */
+#define CSR_SHARED_INTR        0x08	/* rw  Interrupt sharing */
+#define CSR_HOST_BUF_NOT_RDY   0x04	/* ro  Is Host buffer ready */
+#define CSR_SCSI_BUF_RDY       0x02	/* ro  SCSI buffer read */
+#define CSR_GATED_53C80_IRQ    0x01	/* ro  Last block xferred */
+
+#if 0
+#define CSR_BASE CSR_SCSI_BUFF_INTR | CSR_53C80_INTR
+#else
+#define CSR_BASE CSR_53C80_INTR
+#endif
+
+/* Number of 128-byte blocks to be transferred */
+#define C400_BLOCK_COUNTER_REG   NCR53C400_register_offset-7	/* rw */
+
+/* Resume transfer after disconnect */
+#define C400_RESUME_TRANSFER_REG NCR53C400_register_offset-6	/* wo */
+
+/* Access to host buffer stack */
+#define C400_HOST_BUFFER         NCR53C400_register_offset-4	/* rw */
+
+
+/* Note : PHASE_* macros are based on the values of the STATUS register */
+#define PHASE_MASK 	(SR_MSG | SR_CD | SR_IO)
+
+#define PHASE_DATAOUT		0
+#define PHASE_DATAIN		SR_IO
+#define PHASE_CMDOUT		SR_CD
+#define PHASE_STATIN		(SR_CD | SR_IO)
+#define PHASE_MSGOUT		(SR_MSG | SR_CD)
+#define PHASE_MSGIN		(SR_MSG | SR_CD | SR_IO)
+#define PHASE_UNKNOWN		0xff
+
+/* 
+ * Convert status register phase to something we can use to set phase in 
+ * the target register so we can get phase mismatch interrupts on DMA 
+ * transfers.
+ */
+
+#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
+
+/*
+ * The internal should_disconnect() function returns these based on the 
+ * expected length of a disconnect if a device supports disconnect/
+ * reconnect.
+ */
+
+#define DISCONNECT_NONE		0
+#define DISCONNECT_TIME_TO_DATA	1
+#define DISCONNECT_LONG		2
+
+/* 
+ * These are "special" values for the tag parameter passed to NCR5380_select.
+ */
+
+#define TAG_NEXT	-1	/* Use next free tag */
+#define TAG_NONE	-2	/* 
+				 * Establish I_T_L nexus instead of I_T_L_Q
+				 * even on SCSI-II devices.
+				 */
+
+/*
+ * These are "special" values for the irq and dma_channel fields of the 
+ * Scsi_Host structure
+ */
+
+#define SCSI_IRQ_NONE	255
+#define DMA_NONE	255
+#define IRQ_AUTO	254
+#define DMA_AUTO	254
+#define PORT_AUTO	0xffff	/* autoprobe io port for 53c400a */
+
+#define FLAG_HAS_LAST_BYTE_SENT		1	/* NCR53c81 or better */
+#define FLAG_CHECK_LAST_BYTE_SENT	2	/* Only test once */
+#define FLAG_NCR53C400			4	/* NCR53c400 */
+#define FLAG_NO_PSEUDO_DMA		8	/* Inhibit DMA */
+#define FLAG_DTC3181E			16	/* DTC3181E */
+
+#ifndef ASM
+struct NCR5380_hostdata {
+	NCR5380_implementation_fields;		/* implementation specific */
+	struct Scsi_Host *host;			/* Host backpointer */
+	unsigned char id_mask, id_higher_mask;	/* 1 << id, all bits greater */
+	unsigned char targets_present;		/* targets we have connected
+						   to, so we can call a select
+						   failure a retryable condition */
+	volatile unsigned char busy[8];		/* index = target, bit = lun */
+#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
+	volatile int dma_len;			/* requested length of DMA */
+#endif
+	volatile unsigned char last_message;	/* last message OUT */
+	volatile Scsi_Cmnd *connected;		/* currently connected command */
+	volatile Scsi_Cmnd *issue_queue;	/* waiting to be issued */
+	volatile Scsi_Cmnd *disconnected_queue;	/* waiting for reconnect */
+	volatile int restart_select;		/* we have disconnected,
+						   used to restart 
+						   NCR5380_select() */
+	volatile unsigned aborted:1;		/* flag, says aborted */
+	int flags;
+	unsigned long time_expires;		/* in jiffies, set prior to sleeping */
+	int select_time;			/* timer in select for target response */
+	volatile Scsi_Cmnd *selecting;
+	struct work_struct coroutine;		/* our co-routine */
+#ifdef NCR5380_STATS
+	unsigned timebase;			/* Base for time calcs */
+	long time_read[8];			/* time to do reads */
+	long time_write[8];			/* time to do writes */
+	unsigned long bytes_read[8];		/* bytes read */
+	unsigned long bytes_write[8];		/* bytes written */
+	unsigned pendingr;
+	unsigned pendingw;
+#endif
+};
+
+#ifdef __KERNEL__
+
+#define dprintk(a,b)			do {} while(0)
+#define NCR5380_dprint(a,b)		do {} while(0)
+#define NCR5380_dprint_phase(a,b)	do {} while(0)
+
+#if defined(AUTOPROBE_IRQ)
+static int NCR5380_probe_irq(struct Scsi_Host *instance, int possible);
+#endif
+static int NCR5380_init(struct Scsi_Host *instance, int flags);
+static void NCR5380_exit(struct Scsi_Host *instance);
+static void NCR5380_information_transfer(struct Scsi_Host *instance);
+#ifndef DONT_USE_INTR
+static irqreturn_t NCR5380_intr(int irq, void *dev_id, struct pt_regs *regs);
+#endif
+static void NCR5380_main(void *ptr);
+static void NCR5380_print_options(struct Scsi_Host *instance);
+#ifdef NDEBUG
+static void NCR5380_print_phase(struct Scsi_Host *instance);
+static void NCR5380_print(struct Scsi_Host *instance);
+#endif
+static int NCR5380_abort(Scsi_Cmnd * cmd);
+static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
+static int NCR5380_host_reset(Scsi_Cmnd * cmd);
+static int NCR5380_device_reset(Scsi_Cmnd * cmd);
+static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+static int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start,
+off_t offset, int length, int inout);
+
+static void NCR5380_reselect(struct Scsi_Host *instance);
+static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
+#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
+static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
+#endif
+static int NCR5380_transfer_pio(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
+
+#if (defined(REAL_DMA) || defined(REAL_DMA_POLL))
+
+#if defined(i386) || defined(__alpha__)
+
+/**
+ *	NCR5380_pc_dma_setup		-	setup ISA DMA
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *	@mode: DMA controller mode to use
+ *
+ *	Program the DMA controller ready to perform an ISA DMA transfer
+ *	on this chip.
+ *
+ *	Locks: takes and releases the ISA DMA lock.
+ */
+ 
+static __inline__ int NCR5380_pc_dma_setup(struct Scsi_Host *instance, unsigned char *ptr, unsigned int count, unsigned char mode)
+{
+	unsigned limit;
+	unsigned long bus_addr = virt_to_bus(ptr);
+	unsigned long flags;
+
+	if (instance->dma_channel <= 3) {
+		if (count > 65536)
+			count = 65536;
+		limit = 65536 - (bus_addr & 0xFFFF);
+	} else {
+		if (count > 65536 * 2)
+			count = 65536 * 2;
+		limit = 65536 * 2 - (bus_addr & 0x1FFFF);
+	}
+
+	if (count > limit)
+		count = limit;
+
+	if ((count & 1) || (bus_addr & 1))
+		panic("scsi%d : attempted unaligned DMA transfer\n", instance->host_no);
+	
+	flags=claim_dma_lock();
+	disable_dma(instance->dma_channel);
+	clear_dma_ff(instance->dma_channel);
+	set_dma_addr(instance->dma_channel, bus_addr);
+	set_dma_count(instance->dma_channel, count);
+	set_dma_mode(instance->dma_channel, mode);
+	enable_dma(instance->dma_channel);
+	release_dma_lock(flags);
+	
+	return count;
+}
+
+/**
+ *	NCR5380_pc_dma_write_setup		-	setup ISA DMA write
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *
+ *	Program the DMA controller ready to perform an ISA DMA write to the
+ *	SCSI controller.
+ *
+ *	Locks: called routines take and release the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_write_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count)
+{
+	return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_WRITE);
+}
+
+/**
+ *	NCR5380_pc_dma_read_setup		-	setup ISA DMA read
+ *	@instance: adapter to set up
+ *	@ptr: block to transfer (virtual address)
+ *	@count: number of bytes to transfer
+ *
+ *	Program the DMA controller ready to perform an ISA DMA read from the
+ *	SCSI controller.
+ *
+ *	Locks: called routines take and release the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_read_setup(struct Scsi_Host *instance, unsigned char *src, unsigned int count)
+{
+	return NCR5380_pc_dma_setup(instance, src, count, DMA_MODE_READ);
+}
+
+/**
+ *	NCR5380_pc_dma_residual		-	return bytes left 
+ *	@instance: adapter
+ *
+ *	Reports the number of bytes left over after the DMA was terminated.
+ *
+ *	Locks: takes and releases the ISA DMA lock.
+ */
+
+static __inline__ int NCR5380_pc_dma_residual(struct Scsi_Host *instance)
+{
+	unsigned long flags;
+	int tmp;
+
+	flags = claim_dma_lock();
+	clear_dma_ff(instance->dma_channel);
+	tmp = get_dma_residue(instance->dma_channel);
+	release_dma_lock(flags);
+	
+	return tmp;
+}
+#endif				/* defined(i386) || defined(__alpha__) */
+#endif				/* defined(REAL_DMA)  */
+#endif				/* __KERNEL__ */
+#endif				/* ndef ASM */
+#endif				/* NCR5380_H */
diff --git a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c
new file mode 100644
index 0000000..3c86655
--- /dev/null
+++ b/drivers/scsi/NCR53C9x.c
@@ -0,0 +1,3649 @@
+/* NCR53C9x.c:  Generic SCSI driver code for NCR53C9x chips.
+ *
+ * Originally esp.c : EnhancedScsiProcessor Sun SCSI driver code.
+ *
+ * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Most DMA dependencies put in driver specific files by 
+ * Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Set up to use esp_read/esp_write (preprocessor macros in NCR53c9x.h) by
+ * Tymm Twillman (tymm@coe.missouri.edu)
+ */
+
+/* TODO:
+ *
+ * 1) Maybe disable parity checking in config register one for SCSI1
+ *    targets.  (Gilmore says parity error on the SBus can lock up
+ *    old sun4c's)
+ * 2) Add support for DMA2 pipelining.
+ * 3) Add tagged queueing.
+ * 4) Maybe change use of "esp" to something more "NCR"'ish.
+ */
+
+#include <linux/module.h>
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+/* Command phase enumeration. */
+enum {
+	not_issued    = 0x00,  /* Still in the issue_SC queue.          */
+
+	/* Various forms of selecting a target. */
+#define in_slct_mask    0x10
+	in_slct_norm  = 0x10,  /* ESP is arbitrating, normal selection  */
+	in_slct_stop  = 0x11,  /* ESP will select, then stop with IRQ   */
+	in_slct_msg   = 0x12,  /* select, then send a message           */
+	in_slct_tag   = 0x13,  /* select and send tagged queue msg      */
+	in_slct_sneg  = 0x14,  /* select and acquire sync capabilities  */
+
+	/* Any post selection activity. */
+#define in_phases_mask  0x20
+	in_datain     = 0x20,  /* Data is transferring from the bus     */
+	in_dataout    = 0x21,  /* Data is transferring to the bus       */
+	in_data_done  = 0x22,  /* Last DMA data operation done (maybe)  */
+	in_msgin      = 0x23,  /* Eating message from target            */
+	in_msgincont  = 0x24,  /* Eating more msg bytes from target     */
+	in_msgindone  = 0x25,  /* Decide what to do with what we got    */
+	in_msgout     = 0x26,  /* Sending message to target             */
+	in_msgoutdone = 0x27,  /* Done sending msg out                  */
+	in_cmdbegin   = 0x28,  /* Sending cmd after abnormal selection  */
+	in_cmdend     = 0x29,  /* Done sending slow cmd                 */
+	in_status     = 0x2a,  /* Was in status phase, finishing cmd    */
+	in_freeing    = 0x2b,  /* freeing the bus for cmd cmplt or disc */
+	in_the_dark   = 0x2c,  /* Don't know what bus phase we are in   */
+
+	/* Special states, ie. not normal bus transitions... */
+#define in_spec_mask    0x80
+	in_abortone   = 0x80,  /* Aborting one command currently        */
+	in_abortall   = 0x81,  /* Blowing away all commands we have     */
+	in_resetdev   = 0x82,  /* SCSI target reset in progress         */
+	in_resetbus   = 0x83,  /* SCSI bus reset in progress            */
+	in_tgterror   = 0x84,  /* Target did something stupid           */
+};
+
+enum {
+	/* Zero has special meaning, see skipahead[12]. */
+/*0*/	do_never,
+
+/*1*/	do_phase_determine,
+/*2*/	do_reset_bus,
+/*3*/	do_reset_complete,
+/*4*/	do_work_bus,
+/*5*/	do_intr_end
+};
+
+/* The master ring of all esp hosts we are managing in this driver. */
+struct NCR_ESP *espchain;
+int nesps = 0, esps_in_use = 0, esps_running = 0;
+
+irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+
+/* Debugging routines */
+static struct esp_cmdstrings {
+	unchar cmdchar;
+	char *text;
+} esp_cmd_strings[] = {
+	/* Miscellaneous */
+	{ ESP_CMD_NULL, "ESP_NOP", },
+	{ ESP_CMD_FLUSH, "FIFO_FLUSH", },
+	{ ESP_CMD_RC, "RSTESP", },
+	{ ESP_CMD_RS, "RSTSCSI", },
+	/* Disconnected State Group */
+	{ ESP_CMD_RSEL, "RESLCTSEQ", },
+	{ ESP_CMD_SEL, "SLCTNATN", },
+	{ ESP_CMD_SELA, "SLCTATN", },
+	{ ESP_CMD_SELAS, "SLCTATNSTOP", },
+	{ ESP_CMD_ESEL, "ENSLCTRESEL", },
+	{ ESP_CMD_DSEL, "DISSELRESEL", },
+	{ ESP_CMD_SA3, "SLCTATN3", },
+	{ ESP_CMD_RSEL3, "RESLCTSEQ", },
+	/* Target State Group */
+	{ ESP_CMD_SMSG, "SNDMSG", },
+	{ ESP_CMD_SSTAT, "SNDSTATUS", },
+	{ ESP_CMD_SDATA, "SNDDATA", },
+	{ ESP_CMD_DSEQ, "DISCSEQ", },
+	{ ESP_CMD_TSEQ, "TERMSEQ", },
+	{ ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
+	{ ESP_CMD_DCNCT, "DISC", },
+	{ ESP_CMD_RMSG, "RCVMSG", },
+	{ ESP_CMD_RCMD, "RCVCMD", },
+	{ ESP_CMD_RDATA, "RCVDATA", },
+	{ ESP_CMD_RCSEQ, "RCVCMDSEQ", },
+	/* Initiator State Group */
+	{ ESP_CMD_TI, "TRANSINFO", },
+	{ ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
+	{ ESP_CMD_MOK, "MSGACCEPTED", },
+	{ ESP_CMD_TPAD, "TPAD", },
+	{ ESP_CMD_SATN, "SATN", },
+	{ ESP_CMD_RATN, "RATN", },
+};
+#define NUM_ESP_COMMANDS  ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
+
+/* Print textual representation of an ESP command */
+static inline void esp_print_cmd(unchar espcmd)
+{
+	unchar dma_bit = espcmd & ESP_CMD_DMA;
+	int i;
+
+	espcmd &= ~dma_bit;
+	for(i=0; i<NUM_ESP_COMMANDS; i++)
+		if(esp_cmd_strings[i].cmdchar == espcmd)
+			break;
+	if(i==NUM_ESP_COMMANDS)
+		printk("ESP_Unknown");
+	else
+		printk("%s%s", esp_cmd_strings[i].text,
+		       ((dma_bit) ? "+DMA" : ""));
+}
+
+/* Print the status register's value */
+static inline void esp_print_statreg(unchar statreg)
+{
+	unchar phase;
+
+	printk("STATUS<");
+	phase = statreg & ESP_STAT_PMASK;
+	printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
+		       (phase == ESP_DIP ? "DATA-IN" :
+			(phase == ESP_CMDP ? "COMMAND" :
+			 (phase == ESP_STATP ? "STATUS" :
+			  (phase == ESP_MOP ? "MSG-OUT" :
+			   (phase == ESP_MIP ? "MSG_IN" :
+			    "unknown")))))));
+	if(statreg & ESP_STAT_TDONE)
+		printk("TRANS_DONE,");
+	if(statreg & ESP_STAT_TCNT)
+		printk("TCOUNT_ZERO,");
+	if(statreg & ESP_STAT_PERR)
+		printk("P_ERROR,");
+	if(statreg & ESP_STAT_SPAM)
+		printk("SPAM,");
+	if(statreg & ESP_STAT_INTR)
+		printk("IRQ,");
+	printk(">");
+}
+
+/* Print the interrupt register's value */
+static inline void esp_print_ireg(unchar intreg)
+{
+	printk("INTREG< ");
+	if(intreg & ESP_INTR_S)
+		printk("SLCT_NATN ");
+	if(intreg & ESP_INTR_SATN)
+		printk("SLCT_ATN ");
+	if(intreg & ESP_INTR_RSEL)
+		printk("RSLCT ");
+	if(intreg & ESP_INTR_FDONE)
+		printk("FDONE ");
+	if(intreg & ESP_INTR_BSERV)
+		printk("BSERV ");
+	if(intreg & ESP_INTR_DC)
+		printk("DISCNCT ");
+	if(intreg & ESP_INTR_IC)
+		printk("ILL_CMD ");
+	if(intreg & ESP_INTR_SR)
+		printk("SCSI_BUS_RESET ");
+	printk(">");
+}
+
+/* Print the sequence step registers contents */
+static inline void esp_print_seqreg(unchar stepreg)
+{
+	stepreg &= ESP_STEP_VBITS;
+	printk("STEP<%s>",
+	       (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
+		(stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
+		 (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
+		  (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
+		   (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
+		    "UNKNOWN"))))));
+}
+
+static char *phase_string(int phase)
+{
+	switch(phase) {
+	case not_issued:
+		return "UNISSUED";
+	case in_slct_norm:
+		return "SLCTNORM";
+	case in_slct_stop:
+		return "SLCTSTOP";
+	case in_slct_msg:
+		return "SLCTMSG";
+	case in_slct_tag:
+		return "SLCTTAG";
+	case in_slct_sneg:
+		return "SLCTSNEG";
+	case in_datain:
+		return "DATAIN";
+	case in_dataout:
+		return "DATAOUT";
+	case in_data_done:
+		return "DATADONE";
+	case in_msgin:
+		return "MSGIN";
+	case in_msgincont:
+		return "MSGINCONT";
+	case in_msgindone:
+		return "MSGINDONE";
+	case in_msgout:
+		return "MSGOUT";
+	case in_msgoutdone:
+		return "MSGOUTDONE";
+	case in_cmdbegin:
+		return "CMDBEGIN";
+	case in_cmdend:
+		return "CMDEND";
+	case in_status:
+		return "STATUS";
+	case in_freeing:
+		return "FREEING";
+	case in_the_dark:
+		return "CLUELESS";
+	case in_abortone:
+		return "ABORTONE";
+	case in_abortall:
+		return "ABORTALL";
+	case in_resetdev:
+		return "RESETDEV";
+	case in_resetbus:
+		return "RESETBUS";
+	case in_tgterror:
+		return "TGTERROR";
+	default:
+		return "UNKNOWN";
+	};
+}
+
+#ifdef DEBUG_STATE_MACHINE
+static inline void esp_advance_phase(Scsi_Cmnd *s, int newphase)
+{
+	ESPLOG(("<%s>", phase_string(newphase)));
+	s->SCp.sent_command = s->SCp.phase;
+	s->SCp.phase = newphase;
+}
+#else
+#define esp_advance_phase(__s, __newphase) \
+	(__s)->SCp.sent_command = (__s)->SCp.phase; \
+	(__s)->SCp.phase = (__newphase);
+#endif
+
+#ifdef DEBUG_ESP_CMDS
+static inline void esp_cmd(struct NCR_ESP *esp, struct ESP_regs *eregs,
+			   unchar cmd)
+{
+	esp->espcmdlog[esp->espcmdent] = cmd;
+	esp->espcmdent = (esp->espcmdent + 1) & 31;
+	esp_write(eregs->esp_cmnd, cmd);
+}
+#else
+#define esp_cmd(__esp, __eregs, __cmd)	esp_write((__eregs)->esp_cmnd, (__cmd))
+#endif
+
+/* How we use the various Linux SCSI data structures for operation.
+ *
+ * struct scsi_cmnd:
+ *
+ *   We keep track of the syncronous capabilities of a target
+ *   in the device member, using sync_min_period and
+ *   sync_max_offset.  These are the values we directly write
+ *   into the ESP registers while running a command.  If offset
+ *   is zero the ESP will use asynchronous transfers.
+ *   If the borken flag is set we assume we shouldn't even bother
+ *   trying to negotiate for synchronous transfer as this target
+ *   is really stupid.  If we notice the target is dropping the
+ *   bus, and we have been allowing it to disconnect, we clear
+ *   the disconnect flag.
+ */
+
+/* Manipulation of the ESP command queues.  Thanks to the aha152x driver
+ * and its author, Juergen E. Fischer, for the methods used here.
+ * Note that these are per-ESP queues, not global queues like
+ * the aha152x driver uses.
+ */
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+	Scsi_Cmnd *end;
+
+	new_SC->host_scribble = (unsigned char *) NULL;
+	if(!*SC)
+		*SC = new_SC;
+	else {
+		for(end=*SC;end->host_scribble;end=(Scsi_Cmnd *)end->host_scribble)
+			;
+		end->host_scribble = (unsigned char *) new_SC;
+	}
+}
+
+static inline void prepend_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+	new_SC->host_scribble = (unsigned char *) *SC;
+	*SC = new_SC;
+}
+
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd **SC)
+{
+	Scsi_Cmnd *ptr;
+
+	ptr = *SC;
+	if(ptr)
+		*SC = (Scsi_Cmnd *) (*SC)->host_scribble;
+	return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, int target, int lun)
+{
+	Scsi_Cmnd *ptr, *prev;
+
+	for(ptr = *SC, prev = NULL;
+	    ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
+	    prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		;
+	if(ptr) {
+		if(prev)
+			prev->host_scribble=ptr->host_scribble;
+		else
+			*SC=(Scsi_Cmnd *)ptr->host_scribble;
+	}
+	return ptr;
+}
+
+/* Resetting various pieces of the ESP scsi driver chipset */
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void esp_reset_esp(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	int family_code, version, i;
+	volatile int trash;
+
+	/* Now reset the ESP chip */
+	esp_cmd(esp, eregs, ESP_CMD_RC);
+	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+	if(esp->erev == fast)
+		esp_write(eregs->esp_cfg2, ESP_CONFIG2_FENAB);
+	esp_cmd(esp, eregs, ESP_CMD_NULL | ESP_CMD_DMA);
+
+	/* This is the only point at which it is reliable to read
+	 * the ID-code for a fast ESP chip variant.
+	 */
+	esp->max_period = ((35 * esp->ccycle) / 1000);
+	if(esp->erev == fast) {
+		char *erev2string[] = {
+			"Emulex FAS236",
+			"Emulex FPESP100A",
+			"fast",
+			"QLogic FAS366",
+			"Emulex FAS216",
+			"Symbios Logic 53CF9x-2",
+			"unknown!"
+		};
+			
+		version = esp_read(eregs->esp_uid);
+		family_code = (version & 0xf8) >> 3;
+		if(family_code == 0x02) {
+		        if ((version & 7) == 2)
+			        esp->erev = fas216;	
+                        else
+			        esp->erev = fas236;
+		} else if(family_code == 0x0a)
+			esp->erev = fas366; /* Version is usually '5'. */
+		else if(family_code == 0x00) {
+			if ((version & 7) == 2)
+				esp->erev = fas100a; /* NCR53C9X */
+			else
+				esp->erev = espunknown;
+		} else if(family_code == 0x14) {
+			if ((version & 7) == 2)
+				esp->erev = fsc;
+		        else
+				esp->erev = espunknown;
+		} else if(family_code == 0x00) {
+			if ((version & 7) == 2)
+				esp->erev = fas100a; /* NCR53C9X */
+			else
+				esp->erev = espunknown;
+		} else
+			esp->erev = espunknown;
+		ESPLOG(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+			esp->esp_id, erev2string[esp->erev - fas236],
+			family_code, (version & 7)));
+
+		esp->min_period = ((4 * esp->ccycle) / 1000);
+	} else {
+		esp->min_period = ((5 * esp->ccycle) / 1000);
+	}
+
+	/* Reload the configuration registers */
+	esp_write(eregs->esp_cfact, esp->cfact);
+	esp->prev_stp = 0;
+	esp_write(eregs->esp_stp, 0);
+	esp->prev_soff = 0;
+	esp_write(eregs->esp_soff, 0);
+	esp_write(eregs->esp_timeo, esp->neg_defp);
+	esp->max_period = (esp->max_period + 3)>>2;
+	esp->min_period = (esp->min_period + 3)>>2;
+
+	esp_write(eregs->esp_cfg1, esp->config1);
+	switch(esp->erev) {
+	case esp100:
+		/* nothing to do */
+		break;
+	case esp100a:
+		esp_write(eregs->esp_cfg2, esp->config2);
+		break;
+	case esp236:
+		/* Slow 236 */
+		esp_write(eregs->esp_cfg2, esp->config2);
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		break;
+	case fas366:
+		panic("esp: FAS366 support not present, please notify "
+		      "jongk@cs.utwente.nl");
+		break;
+	case fas216:
+	case fas236:
+	case fsc:
+		/* Fast ESP variants */
+		esp_write(eregs->esp_cfg2, esp->config2);
+		for(i=0; i<8; i++)
+			esp->config3[i] |= ESP_CONFIG3_FCLK;
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		if(esp->diff)
+			esp->radelay = 0;
+		else
+			esp->radelay = 16;
+		/* Different timeout constant for these chips */
+		esp->neg_defp =
+			FSC_NEG_DEFP(esp->cfreq,
+				     (esp->cfact == ESP_CCF_F0 ?
+				      ESP_CCF_F7 + 1 : esp->cfact));
+		esp_write(eregs->esp_timeo, esp->neg_defp);
+		/* Enable Active Negotiation if possible */
+		if((esp->erev == fsc) && !esp->diff)
+			esp_write(eregs->esp_cfg4, ESP_CONFIG4_EAN);
+		break;
+	case fas100a:
+		/* Fast 100a */
+		esp_write(eregs->esp_cfg2, esp->config2);
+		for(i=0; i<8; i++)
+			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
+		esp->prev_cfg3 = esp->config3[0];
+		esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		esp->radelay = 32;
+		break;
+	default:
+		panic("esp: what could it be... I wonder...");
+		break;
+	};
+
+	/* Eat any bitrot in the chip */
+	trash = esp_read(eregs->esp_intrpt);
+	udelay(100);
+}
+
+/* This places the ESP into a known state at boot time. */
+void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	volatile unchar trash;
+
+	/* Reset the DMA */
+	if(esp->dma_reset)
+		esp->dma_reset(esp);
+
+	/* Reset the ESP */
+	esp_reset_esp(esp, eregs);
+
+	/* Reset the SCSI bus, but tell ESP not to generate an irq */
+	esp_write(eregs->esp_cfg1, (esp_read(eregs->esp_cfg1) | ESP_CONFIG1_SRRDISAB));
+	esp_cmd(esp, eregs, ESP_CMD_RS);
+	udelay(400);
+	esp_write(eregs->esp_cfg1, esp->config1);
+
+	/* Eat any bitrot in the chip and we are done... */
+	trash = esp_read(eregs->esp_intrpt);
+}
+
+/* Allocate structure and insert basic data such as SCSI chip frequency
+ * data and a pointer to the device
+ */
+struct NCR_ESP* esp_allocate(Scsi_Host_Template *tpnt, void *esp_dev)
+{
+	struct NCR_ESP *esp, *elink;
+	struct Scsi_Host *esp_host;
+
+	esp_host = scsi_register(tpnt, sizeof(struct NCR_ESP));
+	if(!esp_host)
+		panic("Cannot register ESP SCSI host");
+	esp = (struct NCR_ESP *) esp_host->hostdata;
+	if(!esp)
+		panic("No esp in hostdata");
+	esp->ehost = esp_host;
+	esp->edev = esp_dev;
+	esp->esp_id = nesps++;
+
+	/* Set bitshift value (only used on Amiga with multiple ESPs) */
+	esp->shift = 2;
+
+	/* Put into the chain of esp chips detected */
+	if(espchain) {
+		elink = espchain;
+		while(elink->next) elink = elink->next;
+		elink->next = esp;
+	} else {
+		espchain = esp;
+	}
+	esp->next = NULL;
+
+	return esp;
+}
+
+void esp_deallocate(struct NCR_ESP *esp)
+{
+	struct NCR_ESP *elink;
+
+	if(espchain == esp) {
+		espchain = NULL;
+	} else {
+		for(elink = espchain; elink && (elink->next != esp); elink = elink->next);
+		if(elink) 
+			elink->next = esp->next;
+	}
+	nesps--;
+}
+
+/* Complete initialization of ESP structure and device
+ * Caller must have initialized appropriate parts of the ESP structure
+ * between the call to esp_allocate and this function.
+ */
+void esp_initialize(struct NCR_ESP *esp)
+{
+	struct ESP_regs *eregs = esp->eregs;
+	unsigned int fmhz;
+	unchar ccf;
+	int i;
+	
+	/* Check out the clock properties of the chip. */
+
+	/* This is getting messy but it has to be done
+	 * correctly or else you get weird behavior all
+	 * over the place.  We are trying to basically
+	 * figure out three pieces of information.
+	 *
+	 * a) Clock Conversion Factor
+	 *
+	 *    This is a representation of the input
+	 *    crystal clock frequency going into the
+	 *    ESP on this machine.  Any operation whose
+	 *    timing is longer than 400ns depends on this
+	 *    value being correct.  For example, you'll
+	 *    get blips for arbitration/selection during
+	 *    high load or with multiple targets if this
+	 *    is not set correctly.
+	 *
+	 * b) Selection Time-Out
+	 *
+	 *    The ESP isn't very bright and will arbitrate
+	 *    for the bus and try to select a target
+	 *    forever if you let it.  This value tells
+	 *    the ESP when it has taken too long to
+	 *    negotiate and that it should interrupt
+	 *    the CPU so we can see what happened.
+	 *    The value is computed as follows (from
+	 *    NCR/Symbios chip docs).
+	 *
+	 *          (Time Out Period) *  (Input Clock)
+	 *    STO = ----------------------------------
+	 *          (8192) * (Clock Conversion Factor)
+	 *
+	 *    You usually want the time out period to be
+	 *    around 250ms, I think we'll set it a little
+	 *    bit higher to account for fully loaded SCSI
+	 *    bus's and slow devices that don't respond so
+	 *    quickly to selection attempts. (yeah, I know
+	 *    this is out of spec. but there is a lot of
+	 *    buggy pieces of firmware out there so bite me)
+	 *
+	 * c) Imperical constants for synchronous offset
+	 *    and transfer period register values
+	 *
+	 *    This entails the smallest and largest sync
+	 *    period we could ever handle on this ESP.
+	 */
+	
+	fmhz = esp->cfreq;
+
+	if(fmhz <= (5000000))
+		ccf = 0;
+	else
+		ccf = (((5000000 - 1) + (fmhz))/(5000000));
+	if(!ccf || ccf > 8) {
+		/* If we can't find anything reasonable,
+		 * just assume 20MHZ.  This is the clock
+		 * frequency of the older sun4c's where I've
+		 * been unable to find the clock-frequency
+		 * PROM property.  All other machines provide
+		 * useful values it seems.
+		 */
+		ccf = ESP_CCF_F4;
+		fmhz = (20000000);
+	}
+	if(ccf==(ESP_CCF_F7+1))
+		esp->cfact = ESP_CCF_F0;
+	else if(ccf == ESP_CCF_NEVER)
+		esp->cfact = ESP_CCF_F2;
+	else
+		esp->cfact = ccf;
+	esp->cfreq = fmhz;
+	esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+	esp->ctick = ESP_TICK(ccf, esp->ccycle);
+	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+	esp->sync_defp = SYNC_DEFP_SLOW;
+
+	printk("SCSI ID %d Clk %dMHz CCF=%d TOut %d ",
+	       esp->scsi_id, (esp->cfreq / 1000000),
+	       ccf, (int) esp->neg_defp);
+
+	/* Fill in ehost data */
+	esp->ehost->base = (unsigned long)eregs;
+	esp->ehost->this_id = esp->scsi_id;
+	esp->ehost->irq = esp->irq;
+
+	/* SCSI id mask */
+	esp->scsi_id_mask = (1 << esp->scsi_id);
+
+	/* Probe the revision of this esp */
+	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+	esp_write(eregs->esp_cfg2, esp->config2);
+	if((esp_read(eregs->esp_cfg2) & ~(ESP_CONFIG2_MAGIC)) !=
+	   (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+		printk("NCR53C90(esp100)\n");
+		esp->erev = esp100;
+	} else {
+		esp->config2 = 0;
+		esp_write(eregs->esp_cfg2, 0);
+		esp_write(eregs->esp_cfg3, 5);
+		if(esp_read(eregs->esp_cfg3) != 5) {
+			printk("NCR53C90A(esp100a)\n");
+			esp->erev = esp100a;
+		} else {
+			int target;
+
+			for(target=0; target<8; target++)
+				esp->config3[target] = 0;
+			esp->prev_cfg3 = 0;
+			esp_write(eregs->esp_cfg3, 0);
+			if(ccf > ESP_CCF_F5) {
+				printk("NCR53C9XF(espfast)\n");
+				esp->erev = fast;
+				esp->sync_defp = SYNC_DEFP_FAST;
+			} else {
+				printk("NCR53C9x(esp236)\n");
+				esp->erev = esp236;
+			}
+		}
+	}				
+
+	/* Initialize the command queues */
+	esp->current_SC = NULL;
+	esp->disconnected_SC = NULL;
+	esp->issue_SC = NULL;
+
+	/* Clear the state machines. */
+	esp->targets_present = 0;
+	esp->resetting_bus = 0;
+	esp->snip = 0;
+
+	init_waitqueue_head(&esp->reset_queue);
+
+	esp->fas_premature_intr_workaround = 0;
+	for(i = 0; i < 32; i++)
+		esp->espcmdlog[i] = 0;
+	esp->espcmdent = 0;
+	for(i = 0; i < 16; i++) {
+		esp->cur_msgout[i] = 0;
+		esp->cur_msgin[i] = 0;
+	}
+	esp->prevmsgout = esp->prevmsgin = 0;
+	esp->msgout_len = esp->msgin_len = 0;
+
+	/* Clear the one behind caches to hold unmatchable values. */
+	esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
+
+	/* Reset the thing before we try anything... */
+	esp_bootup_reset(esp, eregs);
+
+	esps_in_use++;
+}
+
+/* The info function will return whatever useful
+ * information the developer sees fit.  If not provided, then
+ * the name field will be used instead.
+ */
+const char *esp_info(struct Scsi_Host *host)
+{
+	struct NCR_ESP *esp;
+
+	esp = (struct NCR_ESP *) host->hostdata;
+	switch(esp->erev) {
+	case esp100:
+		return "ESP100 (NCR53C90)";
+	case esp100a:
+		return "ESP100A (NCR53C90A)";
+	case esp236:
+		return "ESP236 (NCR53C9x)";
+	case fas216:
+		return "Emulex FAS216";
+	case fas236:
+		return "Emulex FAS236";
+	case fas366:
+		return "QLogic FAS366";
+	case fas100a:
+		return "FPESP100A";
+	case fsc:
+		return "Symbios Logic 53CF9x-2";
+	default:
+		panic("Bogon ESP revision");
+	};
+}
+
+/* From Wolfgang Stanglmeier's NCR scsi driver. */
+struct info_str
+{
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+static int esp_host_info(struct NCR_ESP *esp, char *ptr, off_t offset, int len)
+{
+	struct scsi_device *sdev;
+	struct info_str info;
+	int i;
+
+	info.buffer	= ptr;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "ESP Host Adapter:\n");
+	copy_info(&info, "\tESP Model\t\t");
+	switch(esp->erev) {
+	case esp100:
+		copy_info(&info, "ESP100 (NCR53C90)\n");
+		break;
+	case esp100a:
+		copy_info(&info, "ESP100A (NCR53C90A)\n");
+		break;
+	case esp236:
+		copy_info(&info, "ESP236 (NCR53C9x)\n");
+		break;
+	case fas216:
+		copy_info(&info, "Emulex FAS216\n");
+		break;
+	case fas236:
+		copy_info(&info, "Emulex FAS236\n");
+		break;
+	case fas100a:
+		copy_info(&info, "FPESP100A\n");
+		break;
+	case fast:
+		copy_info(&info, "Generic FAST\n");
+		break;
+	case fas366:
+		copy_info(&info, "QLogic FAS366\n");
+		break;
+	case fsc:
+		copy_info(&info, "Symbios Logic 53C9x-2\n");
+		break;
+	case espunknown:
+	default:
+		copy_info(&info, "Unknown!\n");
+		break;
+	};
+	copy_info(&info, "\tLive Targets\t\t[ ");
+	for(i = 0; i < 15; i++) {
+		if(esp->targets_present & (1 << i))
+			copy_info(&info, "%d ", i);
+	}
+	copy_info(&info, "]\n\n");
+	
+	/* Now describe the state of each existing target. */
+	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\n");
+
+	shost_for_each_device(sdev, esp->ehost) {
+		struct esp_device *esp_dev = sdev->hostdata;
+		uint id = sdev->id;
+
+		if (!(esp->targets_present & (1 << id)))
+			continue;
+
+		copy_info(&info, "%d\t\t", id);
+		copy_info(&info, "%08lx\t", esp->config3[id]);
+		copy_info(&info, "[%02lx,%02lx]\t\t\t",
+			esp_dev->sync_max_offset,
+			esp_dev->sync_min_period);
+		copy_info(&info, "%s\n", esp_dev->disconnect ? "yes" : "no");
+	}
+
+	return info.pos > info.offset? info.pos - info.offset : 0;
+}
+
+/* ESP proc filesystem code. */
+int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+		  int inout)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *)shost->hostdata;
+
+	if(inout)
+		return -EINVAL; /* not yet */
+	if(start)
+		*start = buffer;
+	return esp_host_info(esp, buffer, offset, length);
+}
+
+static void esp_get_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(sp->use_sg == 0) {
+		sp->SCp.this_residual = sp->request_bufflen;
+		sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+		sp->SCp.buffers_residual = 0;
+		if (esp->dma_mmu_get_scsi_one)
+			esp->dma_mmu_get_scsi_one(esp, sp);
+		else
+			sp->SCp.ptr =
+				(char *) virt_to_phys(sp->request_buffer);
+	} else {
+		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+		sp->SCp.buffers_residual = sp->use_sg - 1;
+		sp->SCp.this_residual = sp->SCp.buffer->length;
+		if (esp->dma_mmu_get_scsi_sgl)
+			esp->dma_mmu_get_scsi_sgl(esp, sp);
+		else
+			sp->SCp.ptr =
+				(char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+	}
+}
+
+static void esp_release_dmabufs(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(sp->use_sg == 0) {
+		if (esp->dma_mmu_release_scsi_one)
+			esp->dma_mmu_release_scsi_one(esp, sp);
+	} else {
+		if (esp->dma_mmu_release_scsi_sgl)
+			esp->dma_mmu_release_scsi_sgl(esp, sp);
+	}
+}
+
+static void esp_restore_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
+
+	sp->SCp.ptr = ep->saved_ptr;
+	sp->SCp.buffer = ep->saved_buffer;
+	sp->SCp.this_residual = ep->saved_this_residual;
+	sp->SCp.buffers_residual = ep->saved_buffers_residual;
+}
+
+static void esp_save_pointers(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
+
+	ep->saved_ptr = sp->SCp.ptr;
+	ep->saved_buffer = sp->SCp.buffer;
+	ep->saved_this_residual = sp->SCp.this_residual;
+	ep->saved_buffers_residual = sp->SCp.buffers_residual;
+}
+
+/* Some rules:
+ *
+ *   1) Never ever panic while something is live on the bus.
+ *      If there is to be any chance of syncing the disks this
+ *      rule is to be obeyed.
+ *
+ *   2) Any target that causes a foul condition will no longer
+ *      have synchronous transfers done to it, no questions
+ *      asked.
+ *
+ *   3) Keep register accesses to a minimum.  Think about some
+ *      day when we have Xbus machines this is running on and
+ *      the ESP chip is on the other end of the machine on a
+ *      different board from the cpu where this is running.
+ */
+
+/* Fire off a command.  We assume the bus is free and that the only
+ * case where we could see an interrupt is where we have disconnected
+ * commands active and they are trying to reselect us.
+ */
+static inline void esp_check_cmd(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	switch(sp->cmd_len) {
+	case 6:
+	case 10:
+	case 12:
+		esp->esp_slowcmd = 0;
+		break;
+
+	default:
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = sp->cmd_len;
+		esp->esp_scmdp = &sp->cmnd[0];
+		break;
+	};
+}
+
+static inline void build_sync_nego_msg(struct NCR_ESP *esp, int period, int offset)
+{
+	esp->cur_msgout[0] = EXTENDED_MESSAGE;
+	esp->cur_msgout[1] = 3;
+	esp->cur_msgout[2] = EXTENDED_SDTR;
+	esp->cur_msgout[3] = period;
+	esp->cur_msgout[4] = offset;
+	esp->msgout_len = 5;
+}
+
+static void esp_exec_cmd(struct NCR_ESP *esp)
+{
+	struct ESP_regs *eregs = esp->eregs;
+	struct esp_device *esp_dev;
+	Scsi_Cmnd *SCptr;
+	Scsi_Device *SDptr;
+	volatile unchar *cmdp = esp->esp_command;
+	unsigned char the_esp_command;
+	int lun, target;
+	int i;
+
+	/* Hold off if we have disconnected commands and
+	 * an IRQ is showing...
+	 */
+	if(esp->disconnected_SC && esp->dma_irq_p(esp))
+		return;
+
+	/* Grab first member of the issue queue. */
+	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
+
+	/* Safe to panic here because current_SC is null. */
+	if(!SCptr)
+		panic("esp: esp_exec_cmd and issue queue is NULL");
+
+	SDptr = SCptr->device;
+	esp_dev = SDptr->hostdata;
+	lun = SCptr->device->lun;
+	target = SCptr->device->id;
+
+	esp->snip = 0;
+	esp->msgout_len = 0;
+
+	/* Send it out whole, or piece by piece?   The ESP
+	 * only knows how to automatically send out 6, 10,
+	 * and 12 byte commands.  I used to think that the
+	 * Linux SCSI code would never throw anything other
+	 * than that to us, but then again there is the
+	 * SCSI generic driver which can send us anything.
+	 */
+	esp_check_cmd(esp, SCptr);
+
+	/* If arbitration/selection is successful, the ESP will leave
+	 * ATN asserted, causing the target to go into message out
+	 * phase.  The ESP will feed the target the identify and then
+	 * the target can only legally go to one of command,
+	 * datain/out, status, or message in phase, or stay in message
+	 * out phase (should we be trying to send a sync negotiation
+	 * message after the identify).  It is not allowed to drop
+	 * BSY, but some buggy targets do and we check for this
+	 * condition in the selection complete code.  Most of the time
+	 * we'll make the command bytes available to the ESP and it
+	 * will not interrupt us until it finishes command phase, we
+	 * cannot do this for command sizes the ESP does not
+	 * understand and in this case we'll get interrupted right
+	 * when the target goes into command phase.
+	 *
+	 * It is absolutely _illegal_ in the presence of SCSI-2 devices
+	 * to use the ESP select w/o ATN command.  When SCSI-2 devices are
+	 * present on the bus we _must_ always go straight to message out
+	 * phase with an identify message for the target.  Being that
+	 * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
+	 * selections should not confuse SCSI-1 we hope.
+	 */
+
+	if(esp_dev->sync) {
+		/* this targets sync is known */
+#ifdef CONFIG_SCSI_MAC_ESP
+do_sync_known:
+#endif
+		if(esp_dev->disconnect)
+			*cmdp++ = IDENTIFY(1, lun);
+		else
+			*cmdp++ = IDENTIFY(0, lun);
+
+		if(esp->esp_slowcmd) {
+			the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_stop);
+		} else {
+			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_norm);
+		}
+	} else if(!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
+		/* After the bootup SCSI code sends both the
+		 * TEST_UNIT_READY and INQUIRY commands we want
+		 * to at least attempt allowing the device to
+		 * disconnect.
+		 */
+		ESPMISC(("esp: Selecting device for first time. target=%d "
+			 "lun=%d\n", target, SCptr->device->lun));
+		if(!SDptr->borken && !esp_dev->disconnect)
+			esp_dev->disconnect = 1;
+
+		*cmdp++ = IDENTIFY(0, lun);
+		esp->prevmsgout = NOP;
+		esp_advance_phase(SCptr, in_slct_norm);
+		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+
+		/* Take no chances... */
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+	} else {
+		int toshiba_cdrom_hwbug_wkaround = 0;
+
+#ifdef CONFIG_SCSI_MAC_ESP
+		/* Never allow synchronous transfers (disconnect OK) on
+		 * Macintosh. Well, maybe later when we figured out how to 
+		 * do DMA on the machines that support it ...
+		 */
+		esp_dev->disconnect = 1;
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 1;
+		esp->snip = 0;
+		goto do_sync_known;
+#endif
+		/* We've talked to this guy before,
+		 * but never negotiated.  Let's try
+		 * sync negotiation.
+		 */
+		if(!SDptr->borken) {
+			if((SDptr->type == TYPE_ROM) &&
+			   (!strncmp(SDptr->vendor, "TOSHIBA", 7))) {
+				/* Nice try sucker... */
+				ESPMISC(("esp%d: Disabling sync for buggy "
+					 "Toshiba CDROM.\n", esp->esp_id));
+				toshiba_cdrom_hwbug_wkaround = 1;
+				build_sync_nego_msg(esp, 0, 0);
+			} else {
+				build_sync_nego_msg(esp, esp->sync_defp, 15);
+			}
+		} else {
+			build_sync_nego_msg(esp, 0, 0);
+		}
+		esp_dev->sync = 1;
+		esp->snip = 1;
+
+		/* A fix for broken SCSI1 targets, when they disconnect
+		 * they lock up the bus and confuse ESP.  So disallow
+		 * disconnects for SCSI1 targets for now until we
+		 * find a better fix.
+		 *
+		 * Addendum: This is funny, I figured out what was going
+		 *           on.  The blotzed SCSI1 target would disconnect,
+		 *           one of the other SCSI2 targets or both would be
+		 *           disconnected as well.  The SCSI1 target would
+		 *           stay disconnected long enough that we start
+		 *           up a command on one of the SCSI2 targets.  As
+		 *           the ESP is arbitrating for the bus the SCSI1
+		 *           target begins to arbitrate as well to reselect
+		 *           the ESP.  The SCSI1 target refuses to drop it's
+		 *           ID bit on the data bus even though the ESP is
+		 *           at ID 7 and is the obvious winner for any
+		 *           arbitration.  The ESP is a poor sport and refuses
+		 *           to lose arbitration, it will continue indefinitely
+		 *           trying to arbitrate for the bus and can only be
+		 *           stopped via a chip reset or SCSI bus reset.
+		 *           Therefore _no_ disconnects for SCSI1 targets
+		 *           thank you very much. ;-)
+		 */
+		if(((SDptr->scsi_level < 3) && (SDptr->type != TYPE_TAPE)) ||
+		   toshiba_cdrom_hwbug_wkaround || SDptr->borken) {
+			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+				 "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+			esp_dev->disconnect = 0;
+			*cmdp++ = IDENTIFY(0, lun);
+		} else {
+			*cmdp++ = IDENTIFY(1, lun);
+		}
+
+		/* ESP fifo is only so big...
+		 * Make this look like a slow command.
+		 */
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = SCptr->cmd_len;
+		esp->esp_scmdp = &SCptr->cmnd[0];
+
+		the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+		esp_advance_phase(SCptr, in_slct_msg);
+	}
+
+	if(!esp->esp_slowcmd)
+		for(i = 0; i < SCptr->cmd_len; i++)
+			*cmdp++ = SCptr->cmnd[i];
+
+	esp_write(eregs->esp_busid, (target & 7));
+	if (esp->prev_soff != esp_dev->sync_max_offset ||
+	    esp->prev_stp  != esp_dev->sync_min_period ||
+	    (esp->erev > esp100a &&
+	     esp->prev_cfg3 != esp->config3[target])) {
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp_write(eregs->esp_soff, esp->prev_soff);
+		esp->prev_stp = esp_dev->sync_min_period;
+		esp_write(eregs->esp_stp, esp->prev_stp); 
+		if(esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[target];
+			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		}
+	}
+	i = (cmdp - esp->esp_command);
+
+	/* Set up the DMA and ESP counters */
+	if(esp->do_pio_cmds){
+		int j = 0;
+
+		/* 
+		 * XXX MSch:
+		 *
+		 * It seems this is required, at least to clean up
+		 * after failed commands when using PIO mode ...
+		 */
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+		for(;j<i;j++)
+			esp_write(eregs->esp_fdata, esp->esp_command[j]);
+		the_esp_command &= ~ESP_CMD_DMA;
+
+		/* Tell ESP to "go". */
+		esp_cmd(esp, eregs, the_esp_command);
+	} else {
+		/* Set up the ESP counters */
+		esp_write(eregs->esp_tclow, i);
+		esp_write(eregs->esp_tcmed, 0);
+		esp->dma_init_write(esp, esp->esp_command_dvma, i);
+
+		/* Tell ESP to "go". */
+		esp_cmd(esp, eregs, the_esp_command);
+	}
+}
+
+/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
+int esp_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	struct NCR_ESP *esp;
+
+	/* Set up func ptr and initial driver cmd-phase. */
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.phase = not_issued;
+
+	esp = (struct NCR_ESP *) SCpnt->device->host->hostdata;
+
+	if(esp->dma_led_on)
+		esp->dma_led_on(esp);
+
+	/* We use the scratch area. */
+	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->lun));
+	ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->lun));
+
+	esp_get_dmabufs(esp, SCpnt);
+	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
+
+	SCpnt->SCp.Status           = CHECK_CONDITION;
+	SCpnt->SCp.Message          = 0xff;
+	SCpnt->SCp.sent_command     = 0;
+
+	/* Place into our queue. */
+	if(SCpnt->cmnd[0] == REQUEST_SENSE) {
+		ESPQUEUE(("RQSENSE\n"));
+		prepend_SC(&esp->issue_SC, SCpnt);
+	} else {
+		ESPQUEUE(("\n"));
+		append_SC(&esp->issue_SC, SCpnt);
+	}
+
+	/* Run it now if we can. */
+	if(!esp->current_SC && !esp->resetting_bus)
+		esp_exec_cmd(esp);
+
+	return 0;
+}
+
+/* Dump driver state. */
+static void esp_dump_cmd(Scsi_Cmnd *SCptr)
+{
+	ESPLOG(("[tgt<%02x> lun<%02x> "
+		"pphase<%s> cphase<%s>]",
+		SCptr->device->id, SCptr->device->lun,
+		phase_string(SCptr->SCp.sent_command),
+		phase_string(SCptr->SCp.phase)));
+}
+
+static void esp_dump_state(struct NCR_ESP *esp, 
+			   struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+#ifdef DEBUG_ESP_CMDS
+	int i;
+#endif
+
+	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
+	
+	/* Print DMA status */
+	esp->dma_dump_state(esp);
+
+	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
+	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id, esp_read(eregs->esp_status), esp_read(eregs->esp_sstep),
+		esp_read(eregs->esp_intrpt)));
+#ifdef DEBUG_ESP_CMDS
+	printk("esp%d: last ESP cmds [", esp->esp_id);
+	i = (esp->espcmdent - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	i = (i - 1) & 31;
+	printk("<");
+	esp_print_cmd(esp->espcmdlog[i]);
+	printk(">");
+	printk("]\n");
+#endif /* (DEBUG_ESP_CMDS) */
+
+	if(SCptr) {
+		ESPLOG(("esp%d: current command ", esp->esp_id));
+		esp_dump_cmd(SCptr);
+	}
+	ESPLOG(("\n"));
+	SCptr = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected ", esp->esp_id));
+	while(SCptr) {
+		esp_dump_cmd(SCptr);
+		SCptr = (Scsi_Cmnd *) SCptr->host_scribble;
+	}
+	ESPLOG(("\n"));
+}
+
+/* Abort a command.  The host_lock is acquired by caller. */
+int esp_abort(Scsi_Cmnd *SCptr)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata;
+	struct ESP_regs *eregs = esp->eregs;
+	int don;
+
+	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
+	esp_dump_state(esp, eregs);
+
+	/* Wheee, if this is the current command on the bus, the
+	 * best we can do is assert ATN and wait for msgout phase.
+	 * This should even fix a hung SCSI bus when we lose state
+	 * in the driver and timeout because the eventual phase change
+	 * will cause the ESP to (eventually) give an interrupt.
+	 */
+	if(esp->current_SC == SCptr) {
+		esp->cur_msgout[0] = ABORT;
+		esp->msgout_len = 1;
+		esp->msgout_ctr = 0;
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		return SUCCESS;
+	}
+
+	/* If it is still in the issue queue then we can safely
+	 * call the completion routine and report abort success.
+	 */
+	don = esp->dma_ports_p(esp);
+	if(don) {
+		esp->dma_ints_off(esp);
+		synchronize_irq(esp->irq);
+	}
+	if(esp->issue_SC) {
+		Scsi_Cmnd **prev, *this;
+		for(prev = (&esp->issue_SC), this = esp->issue_SC;
+		    this;
+		    prev = (Scsi_Cmnd **) &(this->host_scribble),
+		    this = (Scsi_Cmnd *) this->host_scribble) {
+			if(this == SCptr) {
+				*prev = (Scsi_Cmnd *) this->host_scribble;
+				this->host_scribble = NULL;
+				esp_release_dmabufs(esp, this);
+				this->result = DID_ABORT << 16;
+				this->done(this);
+				if(don)
+					esp->dma_ints_on(esp);
+				return SUCCESS;
+			}
+		}
+	}
+
+	/* Yuck, the command to abort is disconnected, it is not
+	 * worth trying to abort it now if something else is live
+	 * on the bus at this time.  So, we let the SCSI code wait
+	 * a little bit and try again later.
+	 */
+	if(esp->current_SC) {
+		if(don)
+			esp->dma_ints_on(esp);
+		return FAILED;
+	}
+
+	/* It's disconnected, we have to reconnect to re-establish
+	 * the nexus and tell the device to abort.  However, we really
+	 * cannot 'reconnect' per se.  Don't try to be fancy, just
+	 * indicate failure, which causes our caller to reset the whole
+	 * bus.
+	 */
+
+	if(don)
+		esp->dma_ints_on(esp);
+	return FAILED;
+}
+
+/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
+ * arrived indicating the end of the SCSI bus reset.  Our job
+ * is to clean out the command queues and begin re-execution
+ * of SCSI commands once more.
+ */
+static int esp_finish_reset(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *sp = esp->current_SC;
+
+	/* Clean up currently executing command, if any. */
+	if (sp != NULL) {
+		esp_release_dmabufs(esp, sp);
+		sp->result = (DID_RESET << 16);
+		sp->scsi_done(sp);
+		esp->current_SC = NULL;
+	}
+
+	/* Clean up disconnected queue, they have been invalidated
+	 * by the bus reset.
+	 */
+	if (esp->disconnected_SC) {
+		while((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
+			esp_release_dmabufs(esp, sp);
+			sp->result = (DID_RESET << 16);
+			sp->scsi_done(sp);
+		}
+	}
+
+	/* SCSI bus reset is complete. */
+	esp->resetting_bus = 0;
+	wake_up(&esp->reset_queue);
+
+	/* Ok, now it is safe to get commands going once more. */
+	if(esp->issue_SC)
+		esp_exec_cmd(esp);
+
+	return do_intr_end;
+}
+
+static int esp_do_resetbus(struct NCR_ESP *esp,
+			   struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+	esp->resetting_bus = 1;
+	esp_cmd(esp, eregs, ESP_CMD_RS);
+
+	return do_intr_end;
+}
+
+/* Reset ESP chip, reset hanging bus, then kill active and
+ * disconnected commands for targets without soft reset.
+ *
+ * The host_lock is acquired by caller.
+ */
+int esp_reset(Scsi_Cmnd *SCptr)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *) SCptr->device->host->hostdata;
+
+	(void) esp_do_resetbus(esp, esp->eregs);
+
+	spin_unlock_irq(esp->ehost->host_lock);
+
+	wait_event(esp->reset_queue, (esp->resetting_bus == 0));
+
+	spin_lock_irq(esp->ehost->host_lock);
+
+	return SUCCESS;
+}
+
+/* Internal ESP done function. */
+static void esp_done(struct NCR_ESP *esp, int error)
+{
+	Scsi_Cmnd *done_SC;
+
+	if(esp->current_SC) {
+		done_SC = esp->current_SC;
+		esp->current_SC = NULL;
+		esp_release_dmabufs(esp, done_SC);
+		done_SC->result = error;
+		done_SC->scsi_done(done_SC);
+
+		/* Bus is free, issue any commands in the queue. */
+		if(esp->issue_SC && !esp->current_SC)
+			esp_exec_cmd(esp);
+	} else {
+		/* Panic is safe as current_SC is null so we may still
+		 * be able to accept more commands to sync disk buffers.
+		 */
+		ESPLOG(("panicing\n"));
+		panic("esp: done() called with NULL esp->current_SC");
+	}
+}
+
+/* Wheee, ESP interrupt engine. */  
+
+/* Forward declarations. */
+static int esp_do_phase_determine(struct NCR_ESP *esp, 
+				  struct ESP_regs *eregs);
+static int esp_do_data_finale(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs);
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs);
+
+#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
+
+/* We try to avoid some interrupts by jumping ahead and see if the ESP
+ * has gotten far enough yet.  Hence the following.
+ */
+static inline int skipahead1(struct NCR_ESP *esp, struct ESP_regs *eregs,
+			     Scsi_Cmnd *scp, int prev_phase, int new_phase)
+{
+	if(scp->SCp.sent_command != prev_phase)
+		return 0;
+
+	if(esp->dma_irq_p(esp)) {
+		/* Yes, we are able to save an interrupt. */
+		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = esp_read(eregs->esp_intrpt);
+		if(!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
+}
+
+static inline int skipahead2(struct NCR_ESP *esp,
+			     struct ESP_regs *eregs,
+			     Scsi_Cmnd *scp, int prev_phase1, int prev_phase2,
+			     int new_phase)
+{
+	if(scp->SCp.sent_command != prev_phase1 &&
+	   scp->SCp.sent_command != prev_phase2)
+		return 0;
+	if(esp->dma_irq_p(esp)) {
+		/* Yes, we are able to save an interrupt. */
+		esp->sreg = (esp_read(eregs->esp_status) & ~(ESP_STAT_INTR));
+		esp->ireg = esp_read(eregs->esp_intrpt);
+		if(!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
+}
+
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt) \
+	esp_write((__eregs)->esp_tclow, ((__cnt) & 0xff)); \
+	esp_write((__eregs)->esp_tcmed, (((__cnt) >> 8) & 0xff))
+
+#define esp_getcount(__eregs) \
+	((esp_read((__eregs)->esp_tclow)&0xff) | \
+	 ((esp_read((__eregs)->esp_tcmed)&0xff) << 8))
+
+#define fcount(__esp, __eregs) \
+	(esp_read((__eregs)->esp_fflags) & ESP_FF_FBYTES)
+
+#define fnzero(__esp, __eregs) \
+	(esp_read((__eregs)->esp_fflags) & ESP_FF_ONOTZERO)
+
+/* XXX speculative nops unnecessary when continuing amidst a data phase
+ * XXX even on esp100!!!  another case of flooding the bus with I/O reg
+ * XXX writes...
+ */
+#define esp_maybe_nop(__esp, __eregs) \
+	if((__esp)->erev == esp100) \
+		esp_cmd((__esp), (__eregs), ESP_CMD_NULL)
+
+#define sreg_to_dataphase(__sreg) \
+	((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
+
+/* The ESP100 when in synchronous data phase, can mistake a long final
+ * REQ pulse from the target as an extra byte, it places whatever is on
+ * the data lines into the fifo.  For now, we will assume when this
+ * happens that the target is a bit quirky and we don't want to
+ * be talking synchronously to it anyways.  Regardless, we need to
+ * tell the ESP to eat the extraneous byte so that we can proceed
+ * to the next phase.
+ */
+static inline int esp100_sync_hwbug(struct NCR_ESP *esp, struct ESP_regs *eregs,
+				    Scsi_Cmnd *sp, int fifocnt)
+{
+	/* Do not touch this piece of code. */
+	if((!(esp->erev == esp100)) ||
+	   (!(sreg_datainp((esp->sreg = esp_read(eregs->esp_status))) && !fifocnt) &&
+	    !(sreg_dataoutp(esp->sreg) && !fnzero(esp, eregs)))) {
+		if(sp->SCp.phase == in_dataout)
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+		return 0;
+	} else {
+		/* Async mode for this guy. */
+		build_sync_nego_msg(esp, 0, 0);
+
+		/* Ack the bogus byte, but set ATN first. */
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+		return 1;
+	}
+}
+
+/* This closes the window during a selection with a reselect pending, because
+ * we use DMA for the selection process the FIFO should hold the correct
+ * contents if we get reselected during this process.  So we just need to
+ * ack the possible illegal cmd interrupt pending on the esp100.
+ */
+static inline int esp100_reconnect_hwbug(struct NCR_ESP *esp,
+					 struct ESP_regs *eregs)
+{
+	volatile unchar junk;
+
+	if(esp->erev != esp100)
+		return 0;
+	junk = esp_read(eregs->esp_intrpt);
+
+	if(junk & ESP_INTR_SR)
+		return 1;
+	return 0;
+}
+
+/* This verifies the BUSID bits during a reselection so that we know which
+ * target is talking to us.
+ */
+static inline int reconnect_target(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	int it, me = esp->scsi_id_mask, targ = 0;
+
+	if(2 != fcount(esp, eregs))
+		return -1;
+	it = esp_read(eregs->esp_fdata);
+	if(!(it & me))
+		return -1;
+	it &= ~me;
+	if(it & (it - 1))
+		return -1;
+	while(!(it & 1))
+		targ++, it >>= 1;
+	return targ;
+}
+
+/* This verifies the identify from the target so that we know which lun is
+ * being reconnected.
+ */
+static inline int reconnect_lun(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	int lun;
+
+	if((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
+		return -1;
+	lun = esp_read(eregs->esp_fdata);
+
+	/* Yes, you read this correctly.  We report lun of zero
+	 * if we see parity error.  ESP reports parity error for
+	 * the lun byte, and this is the only way to hope to recover
+	 * because the target is connected.
+	 */
+	if(esp->sreg & ESP_STAT_PERR)
+		return 0;
+
+	/* Check for illegal bits being set in the lun. */
+	if((lun & 0x40) || !(lun & 0x80))
+		return -1;
+
+	return lun & 7;
+}
+
+/* This puts the driver in a state where it can revitalize a command that
+ * is being continued due to reselection.
+ */
+static inline void esp_connect(struct NCR_ESP *esp, struct ESP_regs *eregs,
+			       Scsi_Cmnd *sp)
+{
+	Scsi_Device *dp = sp->device;
+	struct esp_device *esp_dev = dp->hostdata;
+
+	if(esp->prev_soff  != esp_dev->sync_max_offset ||
+	   esp->prev_stp   != esp_dev->sync_min_period ||
+	   (esp->erev > esp100a &&
+	    esp->prev_cfg3 != esp->config3[sp->device->id])) {
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp_write(eregs->esp_soff, esp->prev_soff);
+		esp->prev_stp = esp_dev->sync_min_period;
+		esp_write(eregs->esp_stp, esp->prev_stp);
+		if(esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[sp->device->id];
+			esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+		} 
+	}
+	esp->current_SC = sp;
+}
+
+/* This will place the current working command back into the issue queue
+ * if we are to receive a reselection amidst a selection attempt.
+ */
+static inline void esp_reconnect(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	if(!esp->disconnected_SC)
+		ESPLOG(("esp%d: Weird, being reselected but disconnected "
+			"command queue is empty.\n", esp->esp_id));
+	esp->snip = 0;
+	esp->current_SC = NULL;
+	sp->SCp.phase = not_issued;
+	append_SC(&esp->issue_SC, sp);
+}
+
+/* Begin message in phase. */
+static int esp_do_msgin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	esp_maybe_nop(esp, eregs);
+	esp_cmd(esp, eregs, ESP_CMD_TI);
+	esp->msgin_len = 1;
+	esp->msgin_ctr = 0;
+	esp_advance_phase(esp->current_SC, in_msgindone);
+	return do_work_bus;
+}
+
+static inline void advance_sg(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	++sp->SCp.buffer;
+	--sp->SCp.buffers_residual;
+	sp->SCp.this_residual = sp->SCp.buffer->length;
+	if (esp->dma_advance_sg)
+		esp->dma_advance_sg (sp);
+	else
+		sp->SCp.ptr = (char *) virt_to_phys((page_address(sp->SCp.buffer->page) + sp->SCp.buffer->offset));
+
+}
+
+/* Please note that the way I've coded these routines is that I _always_
+ * check for a disconnect during any and all information transfer
+ * phases.  The SCSI standard states that the target _can_ cause a BUS
+ * FREE condition by dropping all MSG/CD/IO/BSY signals.  Also note
+ * that during information transfer phases the target controls every
+ * change in phase, the only thing the initiator can do is "ask" for
+ * a message out phase by driving ATN true.  The target can, and sometimes
+ * will, completely ignore this request so we cannot assume anything when
+ * we try to force a message out phase to abort/reset a target.  Most of
+ * the time the target will eventually be nice and go to message out, so
+ * we may have to hold on to our state about what we want to tell the target
+ * for some period of time.
+ */
+
+/* I think I have things working here correctly.  Even partial transfers
+ * within a buffer or sub-buffer should not upset us at all no matter
+ * how bad the target and/or ESP fucks things up.
+ */
+static int esp_do_data(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int thisphase, hmuch;
+
+	ESPDATA(("esp_do_data: "));
+	esp_maybe_nop(esp, eregs);
+	thisphase = sreg_to_dataphase(esp->sreg);
+	esp_advance_phase(SCptr, thisphase);
+	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
+	hmuch = esp->dma_can_transfer(esp, SCptr);
+
+	/*
+	 * XXX MSch: cater for PIO transfer here; PIO used if hmuch == 0
+	 */
+	if (hmuch) {	/* DMA */
+		/*
+		 * DMA
+		 */
+		ESPDATA(("hmuch<%d> ", hmuch));
+		esp->current_transfer_size = hmuch;
+		esp_setcount(eregs, (esp->fas_premature_intr_workaround ?
+				     (hmuch + 0x40) : hmuch));
+		esp->dma_setup(esp, (__u32)((unsigned long)SCptr->SCp.ptr), 
+			       hmuch, (thisphase == in_datain));
+		ESPDATA(("DMA|TI --> do_intr_end\n"));
+		esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		return do_intr_end;
+		/*
+		 * end DMA
+		 */
+	} else {
+		/*
+		 * PIO
+		 */
+		int oldphase, i = 0; /* or where we left off last time ?? esp->current_data ?? */
+		int fifocnt = 0;
+
+		oldphase = esp_read(eregs->esp_status) & ESP_STAT_PMASK;
+
+		/*
+		 * polled transfer; ugly, can we make this happen in a DRQ 
+		 * interrupt handler ??
+		 * requires keeping track of state information in host or 
+		 * command struct!
+		 * Problem: I've never seen a DRQ happen on Mac, not even
+		 * with ESP_CMD_DMA ...
+		 */
+
+		/* figure out how much needs to be transferred */
+		hmuch = SCptr->SCp.this_residual;
+		ESPDATA(("hmuch<%d> pio ", hmuch));
+		esp->current_transfer_size = hmuch;
+
+		/* tell the ESP ... */
+		esp_setcount(eregs, hmuch);
+
+		/* loop */
+		while (hmuch) {
+			int j, fifo_stuck = 0, newphase;
+			unsigned long flags, timeout;
+#if 0
+			if ( i % 10 )
+				ESPDATA(("\r"));
+			else
+				ESPDATA(( /*"\n"*/ "\r"));
+#endif
+#if 0
+			local_irq_save(flags);
+#endif
+			if(thisphase == in_datain) {
+				/* 'go' ... */ 
+				esp_cmd(esp, eregs, ESP_CMD_TI);
+
+				/* wait for data */
+				timeout = 1000000;
+				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+					udelay(2);
+				if (timeout == 0)
+					printk("DRQ datain timeout! \n");
+
+				newphase = esp->sreg & ESP_STAT_PMASK;
+
+				/* see how much we got ... */
+				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+				if (!fifocnt)
+					fifo_stuck++;
+				else
+					fifo_stuck = 0;
+
+				ESPDATA(("\rgot %d st %x ph %x", fifocnt, esp->sreg, newphase));
+
+				/* read fifo */
+				for(j=0;j<fifocnt;j++)
+					SCptr->SCp.ptr[i++] = esp_read(eregs->esp_fdata);
+
+				ESPDATA(("(%d) ", i));
+
+				/* how many to go ?? */
+				hmuch -= fifocnt;
+
+				/* break if status phase !! */
+				if(newphase == ESP_STATP) {
+					/* clear int. */
+					esp->ireg = esp_read(eregs->esp_intrpt);
+					break;
+				}
+			} else {
+#define MAX_FIFO 8
+				/* how much will fit ? */
+				int this_count = MAX_FIFO - fifocnt;
+				if (this_count > hmuch)
+					this_count = hmuch;
+
+				/* fill fifo */
+				for(j=0;j<this_count;j++)
+					esp_write(eregs->esp_fdata, SCptr->SCp.ptr[i++]);
+
+				/* how many left if this goes out ?? */
+				hmuch -= this_count;
+
+				/* 'go' ... */ 
+				esp_cmd(esp, eregs, ESP_CMD_TI);
+
+				/* wait for 'got it' */
+				timeout = 1000000;
+				while (!((esp->sreg=esp_read(eregs->esp_status)) & ESP_STAT_INTR) && --timeout)
+					udelay(2);
+				if (timeout == 0)
+					printk("DRQ dataout timeout!  \n");
+
+				newphase = esp->sreg & ESP_STAT_PMASK;
+
+				/* need to check how much was sent ?? */
+				fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+
+				ESPDATA(("\rsent %d st %x ph %x", this_count - fifocnt, esp->sreg, newphase));
+
+				ESPDATA(("(%d) ", i));
+
+				/* break if status phase !! */
+				if(newphase == ESP_STATP) {
+					/* clear int. */
+					esp->ireg = esp_read(eregs->esp_intrpt);
+					break;
+				}
+
+			}
+
+			/* clear int. */
+			esp->ireg = esp_read(eregs->esp_intrpt);
+
+			ESPDATA(("ir %x ... ", esp->ireg));
+
+			if (hmuch == 0)
+				ESPDATA(("done! \n"));
+
+#if 0
+			local_irq_restore(flags);
+#endif
+
+			/* check new bus phase */
+			if (newphase != oldphase && i < esp->current_transfer_size) {
+				/* something happened; disconnect ?? */
+				ESPDATA(("phase change, dropped out with %d done ... ", i));
+				break;
+			}
+
+			/* check int. status */
+			if (esp->ireg & ESP_INTR_DC) {
+				/* disconnect */
+				ESPDATA(("disconnect; %d transferred ... ", i));
+				break;
+			} else if (esp->ireg & ESP_INTR_FDONE) {
+				/* function done */
+				ESPDATA(("function done; %d transferred ... ", i));
+				break;
+			}
+
+			/* XXX fixme: bail out on stall */
+			if (fifo_stuck > 10) {
+				/* we're stuck */
+				ESPDATA(("fifo stall; %d transferred ... ", i));
+				break;
+			}
+		}
+
+		ESPDATA(("\n"));
+		/* check successful completion ?? */
+
+		if (thisphase == in_dataout)
+			hmuch += fifocnt; /* stuck?? adjust data pointer ...*/
+
+		/* tell do_data_finale how much was transferred */
+		esp->current_transfer_size -= hmuch;
+
+		/* still not completely sure on this one ... */		
+		return /*do_intr_end*/ do_work_bus /*do_phase_determine*/ ;
+
+		/*
+		 * end PIO
+		 */
+	}
+	return do_intr_end;
+}
+
+/* See how successful the data transfer was. */
+static int esp_do_data_finale(struct NCR_ESP *esp,
+			      struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
+
+	if(esp->dma_led_off)
+		esp->dma_led_off(esp);
+
+	ESPDATA(("esp_do_data_finale: "));
+
+	if(SCptr->SCp.phase == in_datain) {
+		if(esp->sreg & ESP_STAT_PERR) {
+			/* Yuck, parity error.  The ESP asserts ATN
+			 * so that we can go to message out phase
+			 * immediately and inform the target that
+			 * something bad happened.
+			 */
+			ESPLOG(("esp%d: data bad parity detected.\n",
+				esp->esp_id));
+			esp->cur_msgout[0] = INITIATOR_ERROR;
+			esp->msgout_len = 1;
+		}
+		if(esp->dma_drain)
+			esp->dma_drain(esp);
+	}
+	if(esp->dma_invalidate)
+		esp->dma_invalidate(esp);
+
+	/* This could happen for the above parity error case. */
+	if(!(esp->ireg == ESP_INTR_BSERV)) {
+		/* Please go to msgout phase, please please please... */
+		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
+			esp->esp_id));
+		return esp_do_phase_determine(esp, eregs);
+	}	
+
+	/* Check for partial transfers and other horrible events. */
+	fifocnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+	ecount = esp_getcount(eregs);
+	if(esp->fas_premature_intr_workaround)
+		ecount -= 0x40;
+	bytes_sent = esp->current_transfer_size;
+
+	ESPDATA(("trans_sz=%d, ", bytes_sent));
+	if(!(esp->sreg & ESP_STAT_TCNT))
+		bytes_sent -= ecount;
+	if(SCptr->SCp.phase == in_dataout)
+		bytes_sent -= fifocnt;
+
+	ESPDATA(("bytes_sent=%d (ecount=%d, fifocnt=%d), ", bytes_sent,
+		 ecount, fifocnt));
+
+	/* If we were in synchronous mode, check for peculiarities. */
+	if(esp_dev->sync_max_offset)
+		bogus_data = esp100_sync_hwbug(esp, eregs, SCptr, fifocnt);
+	else
+		esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+	/* Until we are sure of what has happened, we are certainly
+	 * in the dark.
+	 */
+	esp_advance_phase(SCptr, in_the_dark);
+
+	/* Check for premature interrupt condition. Can happen on FAS2x6
+	 * chips. QLogic recommends a workaround by overprogramming the
+	 * transfer counters, but this makes doing scatter-gather impossible.
+	 * Until there is a way to disable scatter-gather for a single target,
+	 * and not only for the entire host adapter as it is now, the workaround
+	 * is way to expensive performance wise.
+	 * Instead, it turns out that when this happens the target has disconnected
+	 * already but it doesn't show in the interrupt register. Compensate for
+	 * that here to try and avoid a SCSI bus reset.
+	 */
+	if(!esp->fas_premature_intr_workaround && (fifocnt == 1) &&
+	   sreg_dataoutp(esp->sreg)) {
+		ESPLOG(("esp%d: Premature interrupt, enabling workaround\n",
+			esp->esp_id));
+#if 0
+		/* Disable scatter-gather operations, they are not possible
+		 * when using this workaround.
+		 */
+		esp->ehost->sg_tablesize = 0;
+		esp->ehost->use_clustering = ENABLE_CLUSTERING;
+		esp->fas_premature_intr_workaround = 1;
+		bytes_sent = 0;
+		if(SCptr->use_sg) {
+			ESPLOG(("esp%d: Aborting scatter-gather operation\n",
+				esp->esp_id));
+			esp->cur_msgout[0] = ABORT;
+			esp->msgout_len = 1;
+			esp->msgout_ctr = 0;
+			esp_cmd(esp, eregs, ESP_CMD_SATN);
+			esp_setcount(eregs, 0xffff);
+			esp_cmd(esp, eregs, ESP_CMD_NULL);
+			esp_cmd(esp, eregs, ESP_CMD_TPAD | ESP_CMD_DMA);
+			return do_intr_end;
+		}
+#else
+		/* Just set the disconnected bit. That's what appears to
+		 * happen anyway. The state machine will pick it up when
+		 * we return.
+		 */
+		esp->ireg |= ESP_INTR_DC;
+#endif
+        }
+
+	if(bytes_sent < 0) {
+		/* I've seen this happen due to lost state in this
+		 * driver.  No idea why it happened, but allowing
+		 * this value to be negative caused things to
+		 * lock up.  This allows greater chance of recovery.
+		 * In fact every time I've seen this, it has been
+		 * a driver bug without question.
+		 */
+		ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
+		ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
+			esp->esp_id,
+			esp->current_transfer_size, fifocnt, ecount));
+		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
+			esp->esp_id,
+			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
+			SCptr->device->id));
+		SCptr->device->borken = 1;
+		esp_dev->sync = 0;
+		bytes_sent = 0;
+	}
+
+	/* Update the state of our transfer. */
+	SCptr->SCp.ptr += bytes_sent;
+	SCptr->SCp.this_residual -= bytes_sent;
+	if(SCptr->SCp.this_residual < 0) {
+		/* shit */
+		ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
+		SCptr->SCp.this_residual = 0;
+	}
+
+	/* Maybe continue. */
+	if(!bogus_data) {
+		ESPDATA(("!bogus_data, "));
+		/* NO MATTER WHAT, we advance the scatterlist,
+		 * if the target should decide to disconnect
+		 * in between scatter chunks (which is common)
+		 * we could die horribly!  I used to have the sg
+		 * advance occur only if we are going back into
+		 * (or are staying in) a data phase, you can
+		 * imagine the hell I went through trying to
+		 * figure this out.
+		 */
+		if(!SCptr->SCp.this_residual && SCptr->SCp.buffers_residual)
+			advance_sg(esp, SCptr);
+#ifdef DEBUG_ESP_DATA
+		if(sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
+			ESPDATA(("to more data\n"));
+		} else {
+			ESPDATA(("to new phase\n"));
+		}
+#endif
+		return esp_do_phase_determine(esp, eregs);
+	}
+	/* Bogus data, just wait for next interrupt. */
+	ESPLOG(("esp%d: bogus_data during end of data phase\n",
+		esp->esp_id));
+	return do_intr_end;
+}
+
+/* We received a non-good status return at the end of
+ * running a SCSI command.  This is used to decide if
+ * we should clear our synchronous transfer state for
+ * such a device when that happens.
+ *
+ * The idea is that when spinning up a disk or rewinding
+ * a tape, we don't want to go into a loop re-negotiating
+ * synchronous capabilities over and over.
+ */
+static int esp_should_clear_sync(Scsi_Cmnd *sp)
+{
+	unchar cmd1 = sp->cmnd[0];
+	unchar cmd2 = sp->data_cmnd[0];
+
+	/* These cases are for spinning up a disk and
+	 * waiting for that spinup to complete.
+	 */
+	if(cmd1 == START_STOP ||
+	   cmd2 == START_STOP)
+		return 0;
+
+	if(cmd1 == TEST_UNIT_READY ||
+	   cmd2 == TEST_UNIT_READY)
+		return 0;
+
+	/* One more special case for SCSI tape drives,
+	 * this is what is used to probe the device for
+	 * completion of a rewind or tape load operation.
+	 */
+	if(sp->device->type == TYPE_TAPE) {
+		if(cmd1 == MODE_SENSE ||
+		   cmd2 == MODE_SENSE)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Either a command is completing or a target is dropping off the bus
+ * to continue the command in the background so we can do other work.
+ */
+static int esp_do_freebus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int rval;
+
+	rval = skipahead2(esp, eregs, SCptr, in_status, in_msgindone, in_freeing);
+	if(rval)
+		return rval;
+
+	if(esp->ireg != ESP_INTR_DC) {
+		ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
+		return do_reset_bus; /* target will not drop BSY... */
+	}
+	esp->msgout_len = 0;
+	esp->prevmsgout = NOP;
+	if(esp->prevmsgin == COMMAND_COMPLETE) {
+		struct esp_device *esp_dev = SCptr->device->hostdata;
+		/* Normal end of nexus. */
+		if(esp->disconnected_SC)
+			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+		if(SCptr->SCp.Status != GOOD &&
+		   SCptr->SCp.Status != CONDITION_GOOD &&
+		   ((1<<SCptr->device->id) & esp->targets_present) &&
+		   esp_dev->sync && esp_dev->sync_max_offset) {
+			/* SCSI standard says that the synchronous capabilities
+			 * should be renegotiated at this point.  Most likely
+			 * we are about to request sense from this target
+			 * in which case we want to avoid using sync
+			 * transfers until we are sure of the current target
+			 * state.
+			 */
+			ESPMISC(("esp: Status <%d> for target %d lun %d\n",
+				 SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
+
+			/* But don't do this when spinning up a disk at
+			 * boot time while we poll for completion as it
+			 * fills up the console with messages.  Also, tapes
+			 * can report not ready many times right after
+			 * loading up a tape.
+			 */
+			if(esp_should_clear_sync(SCptr) != 0)
+				esp_dev->sync = 0;
+		}
+		ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+			       ((SCptr->SCp.Message & 0xff)<<8) |
+			       (DID_OK << 16)));
+	} else if(esp->prevmsgin == DISCONNECT) {
+		/* Normal disconnect. */
+		esp_cmd(esp, eregs, ESP_CMD_ESEL);
+		ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+		append_SC(&esp->disconnected_SC, SCptr);
+		esp->current_SC = NULL;
+		if(esp->issue_SC)
+			esp_exec_cmd(esp);
+	} else {
+		/* Driver bug, we do not expect a disconnect here
+		 * and should not have advanced the state engine
+		 * to in_freeing.
+		 */
+		ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
+			esp->esp_id));
+		return do_reset_bus;
+	}
+	return do_intr_end;
+}
+
+/* When a reselect occurs, and we cannot find the command to
+ * reconnect to in our queues, we do this.
+ */
+static int esp_bad_reconnect(struct NCR_ESP *esp)
+{
+	Scsi_Cmnd *sp;
+
+	ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+		esp->esp_id));
+	ESPLOG(("QUEUE DUMP\n"));
+	sp = esp->issue_SC;
+	ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	sp = esp->current_SC;
+	ESPLOG(("esp%d: current_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	sp = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+	while(sp) {
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+		sp = (Scsi_Cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	return do_reset_bus;
+}
+
+/* Do the needy when a target tries to reconnect to us. */
+static int esp_do_reconnect(struct NCR_ESP *esp, 
+			    struct ESP_regs *eregs)
+{
+	int lun, target;
+	Scsi_Cmnd *SCptr;
+
+	/* Check for all bogus conditions first. */
+	target = reconnect_target(esp, eregs);
+	if(target < 0) {
+		ESPDISC(("bad bus bits\n"));
+		return do_reset_bus;
+	}
+	lun = reconnect_lun(esp, eregs);
+	if(lun < 0) {
+		ESPDISC(("target=%2x, bad identify msg\n", target));
+		return do_reset_bus;
+	}
+
+	/* Things look ok... */
+	ESPDISC(("R<%02x,%02x>", target, lun));
+
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	if(esp100_reconnect_hwbug(esp, eregs))
+		return do_reset_bus;
+	esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+	SCptr = remove_SC(&esp->disconnected_SC, (unchar) target, (unchar) lun);
+	if(!SCptr)
+		return esp_bad_reconnect(esp);
+
+	esp_connect(esp, eregs, SCptr);
+	esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+	/* Reconnect implies a restore pointers operation. */
+	esp_restore_pointers(esp, SCptr);
+
+	esp->snip = 0;
+	esp_advance_phase(SCptr, in_the_dark);
+	return do_intr_end;
+}
+
+/* End of NEXUS (hopefully), pick up status + message byte then leave if
+ * all goes well.
+ */
+static int esp_do_status(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int intr, rval;
+
+	rval = skipahead1(esp, eregs, SCptr, in_the_dark, in_status);
+	if(rval)
+		return rval;
+
+	intr = esp->ireg;
+	ESPSTAT(("esp_do_status: "));
+	if(intr != ESP_INTR_DC) {
+		int message_out = 0; /* for parity problems */
+
+		/* Ack the message. */
+		ESPSTAT(("ack msg, "));
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+
+		if(esp->dma_poll)
+			esp->dma_poll(esp, (unsigned char *) esp->esp_command);
+
+		ESPSTAT(("got something, "));
+		/* ESP chimes in with one of
+		 *
+		 * 1) function done interrupt:
+		 *	both status and message in bytes
+		 *	are available
+		 *
+		 * 2) bus service interrupt:
+		 *	only status byte was acquired
+		 *
+		 * 3) Anything else:
+		 *	can't happen, but we test for it
+		 *	anyways
+		 *
+		 * ALSO: If bad parity was detected on either
+		 *       the status _or_ the message byte then
+		 *       the ESP has asserted ATN on the bus
+		 *       and we must therefore wait for the
+		 *       next phase change.
+		 */
+		if(intr & ESP_INTR_FDONE) {
+			/* We got it all, hallejulia. */
+			ESPSTAT(("got both, "));
+			SCptr->SCp.Status = esp->esp_command[0];
+			SCptr->SCp.Message = esp->esp_command[1];
+			esp->prevmsgin = SCptr->SCp.Message;
+			esp->cur_msgin[0] = SCptr->SCp.Message;
+			if(esp->sreg & ESP_STAT_PERR) {
+				/* There was bad parity for the
+				 * message byte, the status byte
+				 * was ok.
+				 */
+				message_out = MSG_PARITY_ERROR;
+			}
+		} else if(intr == ESP_INTR_BSERV) {
+			/* Only got status byte. */
+			ESPLOG(("esp%d: got status only, ", esp->esp_id));
+			if(!(esp->sreg & ESP_STAT_PERR)) {
+				SCptr->SCp.Status = esp->esp_command[0];
+				SCptr->SCp.Message = 0xff;
+			} else {
+				/* The status byte had bad parity.
+				 * we leave the scsi_pointer Status
+				 * field alone as we set it to a default
+				 * of CHECK_CONDITION in esp_queue.
+				 */
+				message_out = INITIATOR_ERROR;
+			}
+		} else {
+			/* This shouldn't happen ever. */
+			ESPSTAT(("got bolixed\n"));
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp, eregs);
+		}
+
+		if(!message_out) {
+			ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
+				SCptr->SCp.Message));
+			if(SCptr->SCp.Message == COMMAND_COMPLETE) {
+				ESPSTAT(("and was COMMAND_COMPLETE\n"));
+				esp_advance_phase(SCptr, in_freeing);
+				return esp_do_freebus(esp, eregs);
+			} else {
+				ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
+					esp->esp_id));
+				esp->msgin_len = esp->msgin_ctr = 1;
+				esp_advance_phase(SCptr, in_msgindone);
+				return esp_do_msgindone(esp, eregs);
+			}
+		} else {
+			/* With luck we'll be able to let the target
+			 * know that bad parity happened, it will know
+			 * which byte caused the problems and send it
+			 * again.  For the case where the status byte
+			 * receives bad parity, I do not believe most
+			 * targets recover very well.  We'll see.
+			 */
+			ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
+				esp->esp_id, message_out));
+			esp->cur_msgout[0] = message_out;
+			esp->msgout_len = esp->msgout_ctr = 1;
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp, eregs);
+		}
+	} else {
+		/* If we disconnect now, all hell breaks loose. */
+		ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp, eregs);
+	}
+}
+
+static int esp_enter_status(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
+{
+	unchar thecmd = ESP_CMD_ICCSEQ;
+
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+
+	if(esp->do_pio_cmds) {
+		esp_advance_phase(esp->current_SC, in_status);
+		esp_cmd(esp, eregs, thecmd);
+		while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+		esp->esp_command[0] = esp_read(eregs->esp_fdata);
+                while(!(esp_read(esp->eregs->esp_status) & ESP_STAT_INTR));
+                esp->esp_command[1] = esp_read(eregs->esp_fdata);
+	} else {
+		esp->esp_command[0] = esp->esp_command[1] = 0xff;
+		esp_write(eregs->esp_tclow, 2);
+		esp_write(eregs->esp_tcmed, 0);
+		esp->dma_init_read(esp, esp->esp_command_dvma, 2);
+		thecmd |= ESP_CMD_DMA;
+		esp_cmd(esp, eregs, thecmd);
+		esp_advance_phase(esp->current_SC, in_status);
+	}
+
+	return esp_do_status(esp, eregs);
+}
+
+static int esp_disconnect_amidst_phases(struct NCR_ESP *esp,
+					struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *sp = esp->current_SC;
+	struct esp_device *esp_dev = sp->device->hostdata;
+
+	/* This means real problems if we see this
+	 * here.  Unless we were actually trying
+	 * to force the device to abort/reset.
+	 */
+	ESPLOG(("esp%d: Disconnect amidst phases, ", esp->esp_id));
+	ESPLOG(("pphase<%s> cphase<%s>, ",
+		phase_string(sp->SCp.phase),
+		phase_string(sp->SCp.sent_command)));
+
+	if(esp->disconnected_SC)
+		esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+	switch(esp->cur_msgout[0]) {
+	default:
+		/* We didn't expect this to happen at all. */
+		ESPLOG(("device is bolixed\n"));
+		esp_advance_phase(sp, in_tgterror);
+		esp_done(esp, (DID_ERROR << 16));
+		break;
+
+	case BUS_DEVICE_RESET:
+		ESPLOG(("device reset successful\n"));
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 0;
+		esp_advance_phase(sp, in_resetdev);
+		esp_done(esp, (DID_RESET << 16));
+		break;
+
+	case ABORT:
+		ESPLOG(("device abort successful\n"));
+		esp_advance_phase(sp, in_abortone);
+		esp_done(esp, (DID_ABORT << 16));
+		break;
+
+	};
+	return do_intr_end;
+}
+
+static int esp_enter_msgout(struct NCR_ESP *esp,
+			    struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_msgout);
+	return esp_do_msgout(esp, eregs);
+}
+
+static int esp_enter_msgin(struct NCR_ESP *esp,
+			   struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_msgin);
+	return esp_do_msgin(esp, eregs);
+}
+
+static int esp_enter_cmd(struct NCR_ESP *esp,
+			 struct ESP_regs *eregs)
+{
+	esp_advance_phase(esp->current_SC, in_cmdbegin);
+	return esp_do_cmdbegin(esp, eregs);
+}
+
+static int esp_enter_badphase(struct NCR_ESP *esp,
+			      struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+		esp->sreg & ESP_STAT_PMASK));
+	return do_reset_bus;
+}
+
+typedef int (*espfunc_t)(struct NCR_ESP *,
+			 struct ESP_regs *);
+
+static espfunc_t phase_vector[] = {
+	esp_do_data,		/* ESP_DOP */
+	esp_do_data,		/* ESP_DIP */
+	esp_enter_cmd,		/* ESP_CMDP */
+	esp_enter_status,	/* ESP_STATP */
+	esp_enter_badphase,	/* ESP_STAT_PMSG */
+	esp_enter_badphase,	/* ESP_STAT_PMSG | ESP_STAT_PIO */
+	esp_enter_msgout,	/* ESP_MOP */
+	esp_enter_msgin,	/* ESP_MIP */
+};
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct NCR_ESP *esp,
+				  struct ESP_regs *eregs)
+{
+	if ((esp->ireg & ESP_INTR_DC) != 0)
+		return esp_disconnect_amidst_phases(esp, eregs);
+	return phase_vector[esp->sreg & ESP_STAT_PMASK](esp, eregs);
+}
+
+/* First interrupt after exec'ing a cmd comes here. */
+static int esp_select_complete(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	int cmd_bytes_sent, fcnt;
+
+	fcnt = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES);
+	cmd_bytes_sent = esp->dma_bytes_sent(esp, fcnt);
+	if(esp->dma_invalidate)
+		esp->dma_invalidate(esp);
+
+	/* Let's check to see if a reselect happened
+	 * while we we're trying to select.  This must
+	 * be checked first.
+	 */
+	if(esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+		esp_reconnect(esp, SCptr);
+		return esp_do_reconnect(esp, eregs);
+	}
+
+	/* Looks like things worked, we should see a bus service &
+	 * a function complete interrupt at this point.  Note we
+	 * are doing a direct comparison because we don't want to
+	 * be fooled into thinking selection was successful if
+	 * ESP_INTR_DC is set, see below.
+	 */
+	if(esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+		/* target speaks... */
+		esp->targets_present |= (1<<SCptr->device->id);
+
+		/* What if the target ignores the sdtr? */
+		if(esp->snip)
+			esp_dev->sync = 1;
+
+		/* See how far, if at all, we got in getting
+		 * the information out to the target.
+		 */
+		switch(esp->seqreg) {
+		default:
+
+		case ESP_STEP_ASEL:
+			/* Arbitration won, target selected, but
+			 * we are in some phase which is not command
+			 * phase nor is it message out phase.
+			 *
+			 * XXX We've confused the target, obviously.
+			 * XXX So clear it's state, but we also end
+			 * XXX up clearing everyone elses.  That isn't
+			 * XXX so nice.  I'd like to just reset this
+			 * XXX target, but if I cannot even get it's
+			 * XXX attention and finish selection to talk
+			 * XXX to it, there is not much more I can do.
+			 * XXX If we have a loaded bus we're going to
+			 * XXX spend the next second or so renegotiating
+			 * XXX for synchronous transfers.
+			 */
+			ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
+				esp->esp_id, SCptr->device->id));
+
+		case ESP_STEP_SID:
+			/* Arbitration won, target selected, went
+			 * to message out phase, sent one message
+			 * byte, then we stopped.  ATN is asserted
+			 * on the SCSI bus and the target is still
+			 * there hanging on.  This is a legal
+			 * sequence step if we gave the ESP a select
+			 * and stop command.
+			 *
+			 * XXX See above, I could set the borken flag
+			 * XXX in the device struct and retry the
+			 * XXX command.  But would that help for
+			 * XXX tagged capable targets?
+			 */
+
+		case ESP_STEP_NCMD:
+			/* Arbitration won, target selected, maybe
+			 * sent the one message byte in message out
+			 * phase, but we did not go to command phase
+			 * in the end.  Actually, we could have sent
+			 * only some of the message bytes if we tried
+			 * to send out the entire identify and tag
+			 * message using ESP_CMD_SA3.
+			 */
+			cmd_bytes_sent = 0;
+			break;
+
+		case ESP_STEP_PPC:
+			/* No, not the powerPC pinhead.  Arbitration
+			 * won, all message bytes sent if we went to
+			 * message out phase, went to command phase
+			 * but only part of the command was sent.
+			 *
+			 * XXX I've seen this, but usually in conjunction
+			 * XXX with a gross error which appears to have
+			 * XXX occurred between the time I told the
+			 * XXX ESP to arbitrate and when I got the
+			 * XXX interrupt.  Could I have misloaded the
+			 * XXX command bytes into the fifo?  Actually,
+			 * XXX I most likely missed a phase, and therefore
+			 * XXX went into never never land and didn't even
+			 * XXX know it.  That was the old driver though.
+			 * XXX What is even more peculiar is that the ESP
+			 * XXX showed the proper function complete and
+			 * XXX bus service bits in the interrupt register.
+			 */
+
+		case ESP_STEP_FINI4:
+		case ESP_STEP_FINI5:
+		case ESP_STEP_FINI6:
+		case ESP_STEP_FINI7:
+			/* Account for the identify message */
+			if(SCptr->SCp.phase == in_slct_norm)
+				cmd_bytes_sent -= 1;
+		};
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
+
+		/* Be careful, we could really get fucked during synchronous
+		 * data transfers if we try to flush the fifo now.
+		 */
+		if(!fcnt && /* Fifo is empty and... */
+		   /* either we are not doing synchronous transfers or... */
+		   (!esp_dev->sync_max_offset ||
+		    /* We are not going into data in phase. */
+		    ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+			esp_cmd(esp, eregs, ESP_CMD_FLUSH); /* flush is safe */
+
+		/* See how far we got if this is not a slow command. */
+		if(!esp->esp_slowcmd) {
+			if(cmd_bytes_sent < 0)
+				cmd_bytes_sent = 0;
+			if(cmd_bytes_sent != SCptr->cmd_len) {
+				/* Crapola, mark it as a slowcmd
+				 * so that we have some chance of
+				 * keeping the command alive with
+				 * good luck.
+				 *
+				 * XXX Actually, if we didn't send it all
+				 * XXX this means either we didn't set things
+				 * XXX up properly (driver bug) or the target
+				 * XXX or the ESP detected parity on one of
+				 * XXX the command bytes.  This makes much
+				 * XXX more sense, and therefore this code
+				 * XXX should be changed to send out a
+				 * XXX parity error message or if the status
+				 * XXX register shows no parity error then
+				 * XXX just expect the target to bring the
+				 * XXX bus into message in phase so that it
+				 * XXX can send us the parity error message.
+				 * XXX SCSI sucks...
+				 */
+				esp->esp_slowcmd = 1;
+				esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
+				esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
+			}
+		}
+
+		/* Now figure out where we went. */
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp, eregs);
+	}
+
+	/* Did the target even make it? */
+	if(esp->ireg == ESP_INTR_DC) {
+		/* wheee... nobody there or they didn't like
+		 * what we told it to do, clean up.
+		 */
+
+		/* If anyone is off the bus, but working on
+		 * a command in the background for us, tell
+		 * the ESP to listen for them.
+		 */
+		if(esp->disconnected_SC)
+			esp_cmd(esp, eregs, ESP_CMD_ESEL);
+
+		if(((1<<SCptr->device->id) & esp->targets_present) &&
+		   esp->seqreg && esp->cur_msgout[0] == EXTENDED_MESSAGE &&
+		   (SCptr->SCp.phase == in_slct_msg ||
+		    SCptr->SCp.phase == in_slct_stop)) {
+			/* shit */
+			esp->snip = 0;
+			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
+				"lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1; /* so we don't negotiate again */
+
+			/* Run the command again, this time though we
+			 * won't try to negotiate for synchronous transfers.
+			 *
+			 * XXX I'd like to do something like send an
+			 * XXX INITIATOR_ERROR or ABORT message to the
+			 * XXX target to tell it, "Sorry I confused you,
+			 * XXX please come back and I will be nicer next
+			 * XXX time".  But that requires having the target
+			 * XXX on the bus, and it has dropped BSY on us.
+			 */
+			esp->current_SC = NULL;
+			esp_advance_phase(SCptr, not_issued);
+			prepend_SC(&esp->issue_SC, SCptr);
+			esp_exec_cmd(esp);
+			return do_intr_end;
+		}
+
+		/* Ok, this is normal, this is what we see during boot
+		 * or whenever when we are scanning the bus for targets.
+		 * But first make sure that is really what is happening.
+		 */
+		if(((1<<SCptr->device->id) & esp->targets_present)) {
+			ESPLOG(("esp%d: Warning, live target %d not responding to "
+				"selection.\n", esp->esp_id, SCptr->device->id));
+
+			/* This _CAN_ happen.  The SCSI standard states that
+			 * the target is to _not_ respond to selection if
+			 * _it_ detects bad parity on the bus for any reason.
+			 * Therefore, we assume that if we've talked successfully
+			 * to this target before, bad parity is the problem.
+			 */
+			esp_done(esp, (DID_PARITY << 16));
+		} else {
+			/* Else, there really isn't anyone there. */
+			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
+			ESPMISC(("esp: target %d lun %d\n",
+				 SCptr->device->id, SCptr->device->lun));
+			esp_done(esp, (DID_BAD_TARGET << 16));
+		}
+		return do_intr_end;
+	}
+
+
+	ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
+	printk("esp%d: Currently -- ", esp->esp_id);
+	esp_print_ireg(esp->ireg);
+	printk(" ");
+	esp_print_statreg(esp->sreg);
+	printk(" ");
+	esp_print_seqreg(esp->seqreg);
+	printk("\n");
+	printk("esp%d: New -- ", esp->esp_id);
+	esp->sreg = esp_read(eregs->esp_status);
+	esp->seqreg = esp_read(eregs->esp_sstep);
+	esp->ireg = esp_read(eregs->esp_intrpt);
+	esp_print_ireg(esp->ireg);
+	printk(" ");
+	esp_print_statreg(esp->sreg);
+	printk(" ");
+	esp_print_seqreg(esp->seqreg);
+	printk("\n");
+	ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
+	return do_reset_bus; /* ugh... */
+}
+
+/* Continue reading bytes for msgin phase. */
+static int esp_do_msgincont(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	if(esp->ireg & ESP_INTR_BSERV) {
+		/* in the right phase too? */
+		if((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
+			/* phew... */
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+			esp_advance_phase(esp->current_SC, in_msgindone);
+			return do_intr_end;
+		}
+
+		/* We changed phase but ESP shows bus service,
+		 * in this case it is most likely that we, the
+		 * hacker who has been up for 20hrs straight
+		 * staring at the screen, drowned in coffee
+		 * smelling like retched cigarette ashes
+		 * have miscoded something..... so, try to
+		 * recover as best we can.
+		 */
+		ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return do_phase_determine;
+}
+
+static int check_singlebyte_msg(struct NCR_ESP *esp,
+				struct ESP_regs *eregs)
+{
+	esp->prevmsgin = esp->cur_msgin[0];
+	if(esp->cur_msgin[0] & 0x80) {
+		/* wheee... */
+		ESPLOG(("esp%d: target sends identify amidst phases\n",
+			esp->esp_id));
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return 0;
+	} else if(((esp->cur_msgin[0] & 0xf0) == 0x20) ||
+		  (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
+		esp->msgin_len = 2;
+		esp_advance_phase(esp->current_SC, in_msgincont);
+		return 0;
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	switch(esp->cur_msgin[0]) {
+	default:
+		/* We don't want to hear about it. */
+		ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
+			esp->cur_msgin[0]));
+		return MESSAGE_REJECT;
+
+	case NOP:
+		ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
+			esp->current_SC->device->id));
+		return 0;
+
+	case RESTORE_POINTERS:
+		/* In this case we might also have to backup the
+		 * "slow command" pointer.  It is rare to get such
+		 * a save/restore pointer sequence so early in the
+		 * bus transition sequences, but cover it.
+		 */
+		if(esp->esp_slowcmd) {
+			esp->esp_scmdleft = esp->current_SC->cmd_len;
+			esp->esp_scmdp = &esp->current_SC->cmnd[0];
+		}
+		esp_restore_pointers(esp, esp->current_SC);
+		return 0;
+
+	case SAVE_POINTERS:
+		esp_save_pointers(esp, esp->current_SC);
+		return 0;
+
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/* Freeing the bus, let it go. */
+		esp->current_SC->SCp.phase = in_freeing;
+		return 0;
+
+	case MESSAGE_REJECT:
+		ESPMISC(("msg reject, "));
+		if(esp->prevmsgout == EXTENDED_MESSAGE) {
+			struct esp_device *esp_dev = esp->current_SC->device->hostdata;
+
+			/* Doesn't look like this target can
+			 * do synchronous or WIDE transfers.
+			 */
+			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
+			esp_dev->sync = 1;
+			esp_dev->wide = 1;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
+			return 0;
+		} else {
+			ESPMISC(("not sync nego, sending ABORT\n"));
+			return ABORT;
+		}
+	};
+}
+
+/* Target negotiates for synchronous transfers before we do, this
+ * is legal although very strange.  What is even funnier is that
+ * the SCSI2 standard specifically recommends against targets doing
+ * this because so many initiators cannot cope with this occurring.
+ */
+static int target_with_ants_in_pants(struct NCR_ESP *esp,
+				     Scsi_Cmnd *SCptr,
+				     struct esp_device *esp_dev)
+{
+	if(esp_dev->sync || SCptr->device->borken) {
+		/* sorry, no can do */
+		ESPSDTR(("forcing to async, "));
+		build_sync_nego_msg(esp, 0, 0);
+		esp_dev->sync = 1;
+		esp->snip = 1;
+		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return EXTENDED_MESSAGE;
+	}
+
+	/* Ok, we'll check them out... */
+	return 0;
+}
+
+static void sync_report(struct NCR_ESP *esp)
+{
+	int msg3, msg4;
+	char *type;
+
+	msg3 = esp->cur_msgin[3];
+	msg4 = esp->cur_msgin[4];
+	if(msg4) {
+		int hz = 1000000000 / (msg3 * 4);
+		int integer = hz / 1000000;
+		int fraction = (hz - (integer * 1000000)) / 10000;
+		if((msg3 * 4) < 200) {
+			type = "FAST";
+		} else {
+			type = "synchronous";
+		}
+
+		/* Do not transform this back into one big printk
+		 * again, it triggers a bug in our sparc64-gcc272
+		 * sibling call optimization.  -DaveM
+		 */
+		ESPLOG((KERN_INFO "esp%d: target %d ",
+			esp->esp_id, esp->current_SC->device->id));
+		ESPLOG(("[period %dns offset %d %d.%02dMHz ",
+			(int) msg3 * 4, (int) msg4,
+			integer, fraction));
+		ESPLOG(("%s SCSI%s]\n", type,
+			(((msg3 * 4) < 200) ? "-II" : "")));
+	} else {
+		ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
+			esp->esp_id, esp->current_SC->device->id));
+	}
+}
+
+static int check_multibyte_msg(struct NCR_ESP *esp,
+			       struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	unchar regval = 0;
+	int message_out = 0;
+
+	ESPSDTR(("chk multibyte msg: "));
+	if(esp->cur_msgin[2] == EXTENDED_SDTR) {
+		int period = esp->cur_msgin[3];
+		int offset = esp->cur_msgin[4];
+
+		ESPSDTR(("is sync nego response, "));
+		if(!esp->snip) {
+			int rval;
+
+			/* Target negotiates first! */
+			ESPSDTR(("target jumps the gun, "));
+			message_out = EXTENDED_MESSAGE; /* we must respond */
+			rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
+			if(rval)
+				return rval;
+		}
+
+		ESPSDTR(("examining sdtr, "));
+
+		/* Offset cannot be larger than ESP fifo size. */
+		if(offset > 15) {
+			ESPSDTR(("offset too big %2x, ", offset));
+			offset = 15;
+			ESPSDTR(("sending back new offset\n"));
+			build_sync_nego_msg(esp, period, offset);
+			return EXTENDED_MESSAGE;
+		}
+
+		if(offset && period > esp->max_period) {
+			/* Yeee, async for this slow device. */
+			ESPSDTR(("period too long %2x, ", period));
+			build_sync_nego_msg(esp, 0, 0);
+			ESPSDTR(("hoping for msgout\n"));
+			esp_advance_phase(esp->current_SC, in_the_dark);
+			return EXTENDED_MESSAGE;
+		} else if (offset && period < esp->min_period) {
+			ESPSDTR(("period too short %2x, ", period));
+			period = esp->min_period;
+			if(esp->erev > esp236)
+				regval = 4;
+			else
+				regval = 5;
+		} else if(offset) {
+			int tmp;
+
+			ESPSDTR(("period is ok, "));
+			tmp = esp->ccycle / 1000;
+			regval = (((period << 2) + tmp - 1) / tmp);
+			if(regval && (esp->erev > esp236)) {
+				if(period >= 50)
+					regval--;
+			}
+		}
+
+		if(offset) {
+			unchar bit;
+
+			esp_dev->sync_min_period = (regval & 0x1f);
+			esp_dev->sync_max_offset = (offset | esp->radelay);
+			if(esp->erev > esp236) {
+				if(esp->erev == fas100a)
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				if(period < 50)
+					esp->config3[SCptr->device->id] |= bit;
+				else
+					esp->config3[SCptr->device->id] &= ~bit;
+				esp->prev_cfg3 = esp->config3[SCptr->device->id];
+				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+			}
+			esp->prev_soff = esp_dev->sync_min_period;
+			esp_write(eregs->esp_soff, esp->prev_soff);
+			esp->prev_stp = esp_dev->sync_max_offset;
+			esp_write(eregs->esp_stp, esp->prev_stp);
+
+			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
+				esp_dev->sync_max_offset,
+				esp_dev->sync_min_period,
+				esp->config3[SCptr->device->id]));
+
+			esp->snip = 0;
+		} else if(esp_dev->sync_max_offset) {
+			unchar bit;
+
+			/* back to async mode */
+			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp->prev_soff = 0;
+			esp_write(eregs->esp_soff, 0);
+			esp->prev_stp = 0;
+			esp_write(eregs->esp_stp, 0);
+			if(esp->erev > esp236) {
+				if(esp->erev == fas100a)
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				esp->config3[SCptr->device->id] &= ~bit;
+				esp->prev_cfg3 = esp->config3[SCptr->device->id];
+				esp_write(eregs->esp_cfg3, esp->prev_cfg3);
+			}
+		}
+
+		sync_report(esp);
+
+		ESPSDTR(("chk multibyte msg: sync is known, "));
+		esp_dev->sync = 1;
+
+		if(message_out) {
+			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
+				esp->esp_id));
+			build_sync_nego_msg(esp, period, offset);
+			esp_advance_phase(SCptr, in_the_dark);
+			return EXTENDED_MESSAGE;
+		}
+
+		ESPSDTR(("returning zero\n"));
+		esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
+		return 0;
+	} else if(esp->cur_msgin[2] == EXTENDED_WDTR) {
+		ESPLOG(("esp%d: AIEEE wide msg received\n", esp->esp_id));
+		message_out = MESSAGE_REJECT;
+	} else if(esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
+		ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
+		message_out = MESSAGE_REJECT;
+	}
+	esp_advance_phase(SCptr, in_the_dark);
+	return message_out;
+}
+
+static int esp_do_msgindone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	int message_out = 0, it = 0, rval;
+
+	rval = skipahead1(esp, eregs, SCptr, in_msgin, in_msgindone);
+	if(rval)
+		return rval;
+	if(SCptr->SCp.sent_command != in_status) {
+		if(!(esp->ireg & ESP_INTR_DC)) {
+			if(esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
+				message_out = MSG_PARITY_ERROR;
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			} else if((it = (esp_read(eregs->esp_fflags) & ESP_FF_FBYTES))!=1) {
+				/* We certainly dropped the ball somewhere. */
+				message_out = INITIATOR_ERROR;
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			} else if(!esp->msgin_len) {
+				it = esp_read(eregs->esp_fdata);
+				esp_advance_phase(SCptr, in_msgincont);
+			} else {
+				/* it is ok and we want it */
+				it = esp->cur_msgin[esp->msgin_ctr] =
+					esp_read(eregs->esp_fdata);
+				esp->msgin_ctr++;
+			}
+		} else {
+			esp_advance_phase(SCptr, in_the_dark);
+			return do_work_bus;
+		}
+	} else {
+		it = esp->cur_msgin[0];
+	}
+	if(!message_out && esp->msgin_len) {
+		if(esp->msgin_ctr < esp->msgin_len) {
+			esp_advance_phase(SCptr, in_msgincont);
+		} else if(esp->msgin_len == 1) {
+			message_out = check_singlebyte_msg(esp, eregs);
+		} else if(esp->msgin_len == 2) {
+			if(esp->cur_msgin[0] == EXTENDED_MESSAGE) {
+				if((it+2) >= 15) {
+					message_out = MESSAGE_REJECT;
+				} else {
+					esp->msgin_len = (it + 2);
+					esp_advance_phase(SCptr, in_msgincont);
+				}
+			} else {
+				message_out = MESSAGE_REJECT; /* foo on you */
+			}
+		} else {
+			message_out = check_multibyte_msg(esp, eregs);
+		}
+	}
+	if(message_out < 0) {
+		return -message_out;
+	} else if(message_out) {
+		if(((message_out != 1) &&
+		    ((message_out < 0x20) || (message_out & 0x80))))
+			esp->msgout_len = 1;
+		esp->cur_msgout[0] = message_out;
+		esp_cmd(esp, eregs, ESP_CMD_SATN);
+		esp_advance_phase(SCptr, in_the_dark);
+		esp->msgin_len = 0;
+	}
+	esp->sreg = esp_read(eregs->esp_status);
+	esp->sreg &= ~(ESP_STAT_INTR);
+	if((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
+		esp_cmd(esp, eregs, ESP_CMD_MOK);
+	if((SCptr->SCp.sent_command == in_msgindone) &&
+	    (SCptr->SCp.phase == in_freeing))
+		return esp_do_freebus(esp, eregs);
+	return do_intr_end;
+}
+
+static int esp_do_cmdbegin(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	unsigned char tmp;
+	Scsi_Cmnd *SCptr = esp->current_SC;
+
+	esp_advance_phase(SCptr, in_cmdend);
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	tmp = *esp->esp_scmdp++;
+	esp->esp_scmdleft--;
+	esp_write(eregs->esp_fdata, tmp);
+	esp_cmd(esp, eregs, ESP_CMD_TI);
+	return do_intr_end;
+}
+
+static int esp_do_cmddone(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	esp_cmd(esp, eregs, ESP_CMD_NULL);
+	if(esp->ireg & ESP_INTR_BSERV) {
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return esp_do_phase_determine(esp, eregs);
+	}
+	ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
+		esp->esp_id));
+	return do_reset_bus;
+}
+
+static int esp_do_msgout(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+	switch(esp->msgout_len) {
+	case 1:
+		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+		esp_cmd(esp, eregs, ESP_CMD_TI);
+		break;
+
+	case 2:
+		if(esp->do_pio_cmds){
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			esp->esp_command[0] = esp->cur_msgout[0];
+			esp->esp_command[1] = esp->cur_msgout[1];
+			esp->dma_setup(esp, esp->esp_command_dvma, 2, 0);
+			esp_setcount(eregs, 2);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	case 4:
+		esp->snip = 1;
+		if(esp->do_pio_cmds){
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			esp->esp_command[0] = esp->cur_msgout[0];
+			esp->esp_command[1] = esp->cur_msgout[1];
+			esp->esp_command[2] = esp->cur_msgout[2];
+			esp->esp_command[3] = esp->cur_msgout[3];
+			esp->dma_setup(esp, esp->esp_command_dvma, 4, 0);
+			esp_setcount(eregs, 4);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	case 5:
+		esp->snip = 1;
+		if(esp->do_pio_cmds){
+			esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[1]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[2]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[3]);
+			esp_write(eregs->esp_fdata, esp->cur_msgout[4]);
+			esp_cmd(esp, eregs, ESP_CMD_TI);
+		} else {
+			esp->esp_command[0] = esp->cur_msgout[0];
+			esp->esp_command[1] = esp->cur_msgout[1];
+			esp->esp_command[2] = esp->cur_msgout[2];
+			esp->esp_command[3] = esp->cur_msgout[3];
+			esp->esp_command[4] = esp->cur_msgout[4];
+			esp->dma_setup(esp, esp->esp_command_dvma, 5, 0);
+			esp_setcount(eregs, 5);
+			esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	default:
+		/* whoops */
+		ESPMISC(("bogus msgout sending NOP\n"));
+		esp->cur_msgout[0] = NOP;
+		esp_write(eregs->esp_fdata, esp->cur_msgout[0]);
+		esp->msgout_len = 1;
+		esp_cmd(esp, eregs, ESP_CMD_TI);
+		break;
+	}
+	esp_advance_phase(esp->current_SC, in_msgoutdone);
+	return do_intr_end;
+}
+
+static int esp_do_msgoutdone(struct NCR_ESP *esp, 
+			     struct ESP_regs *eregs)
+{
+	if((esp->msgout_len > 1) && esp->dma_barrier)
+		esp->dma_barrier(esp);
+
+	if(!(esp->ireg & ESP_INTR_DC)) {
+		esp_cmd(esp, eregs, ESP_CMD_NULL);
+		switch(esp->sreg & ESP_STAT_PMASK) {
+		case ESP_MOP:
+			/* whoops, parity error */
+			ESPLOG(("esp%d: still in msgout, parity error assumed\n",
+				esp->esp_id));
+			if(esp->msgout_len > 1)
+				esp_cmd(esp, eregs, ESP_CMD_SATN);
+			esp_advance_phase(esp->current_SC, in_msgout);
+			return do_work_bus;
+
+		case ESP_DIP:
+			break;
+
+		default:
+			if(!fcount(esp, eregs) &&
+			   !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
+				esp_cmd(esp, eregs, ESP_CMD_FLUSH);
+			break;
+
+		};
+	}
+
+	/* If we sent out a synchronous negotiation message, update
+	 * our state.
+	 */
+	if(esp->cur_msgout[2] == EXTENDED_MESSAGE &&
+	   esp->cur_msgout[4] == EXTENDED_SDTR) {
+		esp->snip = 1; /* anal retentiveness... */
+	}
+
+	esp->prevmsgout = esp->cur_msgout[0];
+	esp->msgout_len = 0;
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return esp_do_phase_determine(esp, eregs);
+}
+
+static int esp_bus_unexpected(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	ESPLOG(("esp%d: command in weird state %2x\n",
+		esp->esp_id, esp->current_SC->SCp.phase));
+	return do_reset_bus;
+}
+
+static espfunc_t bus_vector[] = {
+	esp_do_data_finale,
+	esp_do_data_finale,
+	esp_bus_unexpected,
+	esp_do_msgin,
+	esp_do_msgincont,
+	esp_do_msgindone,
+	esp_do_msgout,
+	esp_do_msgoutdone,
+	esp_do_cmdbegin,
+	esp_do_cmddone,
+	esp_do_status,
+	esp_do_freebus,
+	esp_do_phase_determine,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+};
+
+/* This is the second tier in our dual-level SCSI state machine. */
+static int esp_work_bus(struct NCR_ESP *esp, struct ESP_regs *eregs)
+{
+	Scsi_Cmnd *SCptr = esp->current_SC;
+	unsigned int phase;
+
+	ESPBUS(("esp_work_bus: "));
+	if(!SCptr) {
+		ESPBUS(("reconnect\n"));
+		return esp_do_reconnect(esp, eregs);
+	}
+	phase = SCptr->SCp.phase;
+	if ((phase & 0xf0) == in_phases_mask)
+		return bus_vector[(phase & 0x0f)](esp, eregs);
+	else if((phase & 0xf0) == in_slct_mask)
+		return esp_select_complete(esp, eregs);
+	else
+		return esp_bus_unexpected(esp, eregs);
+}
+
+static espfunc_t isvc_vector[] = {
+	NULL,
+	esp_do_phase_determine,
+	esp_do_resetbus,
+	esp_finish_reset,
+	esp_work_bus
+};
+
+/* Main interrupt handler for an esp adapter. */
+void esp_handle(struct NCR_ESP *esp)
+{
+	struct ESP_regs *eregs;
+	Scsi_Cmnd *SCptr;
+	int what_next = do_intr_end;
+	eregs = esp->eregs;
+	SCptr = esp->current_SC;
+
+	if(esp->dma_irq_entry)
+		esp->dma_irq_entry(esp);
+
+	/* Check for errors. */
+	esp->sreg = esp_read(eregs->esp_status);
+	esp->sreg &= (~ESP_STAT_INTR);
+	esp->seqreg = (esp_read(eregs->esp_sstep) & ESP_STEP_VBITS);
+	esp->ireg = esp_read(eregs->esp_intrpt);   /* Unlatch intr and stat regs */
+	ESPIRQ(("handle_irq: [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->sreg, esp->seqreg, esp->ireg));
+	if(esp->sreg & (ESP_STAT_SPAM)) {
+		/* Gross error, could be due to one of:
+		 *
+		 * - top of fifo overwritten, could be because
+		 *   we tried to do a synchronous transfer with
+		 *   an offset greater than ESP fifo size
+		 *
+		 * - top of command register overwritten
+		 *
+		 * - DMA setup to go in one direction, SCSI
+		 *   bus points in the other, whoops
+		 *
+		 * - weird phase change during asynchronous
+		 *   data phase while we are initiator
+		 */
+		ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
+
+		/* If a command is live on the bus we cannot safely
+		 * reset the bus, so we'll just let the pieces fall
+		 * where they may.  Here we are hoping that the
+		 * target will be able to cleanly go away soon
+		 * so we can safely reset things.
+		 */
+		if(!SCptr) {
+			ESPLOG(("esp%d: No current cmd during gross error, "
+				"resetting bus\n", esp->esp_id));
+			what_next = do_reset_bus;
+			goto state_machine;
+		}
+	}
+
+	/* No current cmd is only valid at this point when there are
+	 * commands off the bus or we are trying a reset.
+	 */
+	if(!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
+		/* Panic is safe, since current_SC is null. */
+		ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
+		panic("esp_handle: current_SC == penguin within interrupt!");
+	}
+
+	if(esp->ireg & (ESP_INTR_IC)) {
+		/* Illegal command fed to ESP.  Outside of obvious
+		 * software bugs that could cause this, there is
+		 * a condition with ESP100 where we can confuse the
+		 * ESP into an erroneous illegal command interrupt
+		 * because it does not scrape the FIFO properly
+		 * for reselection.  See esp100_reconnect_hwbug()
+		 * to see how we try very hard to avoid this.
+		 */
+		ESPLOG(("esp%d: invalid command\n", esp->esp_id));
+
+		esp_dump_state(esp, eregs);
+
+		if(SCptr) {
+			/* Devices with very buggy firmware can drop BSY
+			 * during a scatter list interrupt when using sync
+			 * mode transfers.  We continue the transfer as
+			 * expected, the target drops the bus, the ESP
+			 * gets confused, and we get a illegal command
+			 * interrupt because the bus is in the disconnected
+			 * state now and ESP_CMD_TI is only allowed when
+			 * a nexus is alive on the bus.
+			 */
+			ESPLOG(("esp%d: Forcing async and disabling disconnect for "
+				"target %d\n", esp->esp_id, SCptr->device->id));
+			SCptr->device->borken = 1; /* foo on you */
+		}
+
+		what_next = do_reset_bus;
+	} else if(!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+		int phase;
+
+		if(SCptr) {
+			phase = SCptr->SCp.phase;
+			if(phase & in_phases_mask) {
+				what_next = esp_work_bus(esp, eregs);
+			} else if(phase & in_slct_mask) {
+				what_next = esp_select_complete(esp, eregs);
+			} else {
+				ESPLOG(("esp%d: interrupt for no good reason...\n",
+					esp->esp_id));
+				what_next = do_intr_end;
+			}
+		} else {
+			ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	} else if(esp->ireg & ESP_INTR_SR) {
+		ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
+		what_next = do_reset_complete;
+	} else if(esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
+		ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
+			esp->esp_id));
+		what_next = do_reset_bus;
+	} else if(esp->ireg & ESP_INTR_RSEL) {
+		if(!SCptr) {
+			/* This is ok. */
+			what_next = esp_do_reconnect(esp, eregs);
+		} else if(SCptr->SCp.phase & in_slct_mask) {
+			/* Only selection code knows how to clean
+			 * up properly.
+			 */
+			ESPDISC(("Reselected during selection attempt\n"));
+			what_next = esp_select_complete(esp, eregs);
+		} else {
+			ESPLOG(("esp%d: Reselected while bus is busy\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	}
+
+	/* This is tier-one in our dual level SCSI state machine. */
+state_machine:
+	while(what_next != do_intr_end) {
+		if (what_next >= do_phase_determine &&
+		    what_next < do_intr_end)
+			what_next = isvc_vector[what_next](esp, eregs);
+		else {
+			/* state is completely lost ;-( */
+			ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	}
+	if(esp->dma_irq_exit)
+		esp->dma_irq_exit(esp);
+}
+
+#ifndef CONFIG_SMP
+irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct NCR_ESP *esp;
+	unsigned long flags;
+	int again;
+	struct Scsi_Host *dev = dev_id;
+
+	/* Handle all ESP interrupts showing at this IRQ level. */
+	spin_lock_irqsave(dev->host_lock, flags);
+repeat:
+	again = 0;
+	for_each_esp(esp) {
+#ifndef __mips__	    
+		if(((esp)->irq & 0xff) == irq) {
+#endif		    
+			if(esp->dma_irq_p(esp)) {
+				again = 1;
+
+				esp->dma_ints_off(esp);
+
+				ESPIRQ(("I%d(", esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				esp->dma_ints_on(esp);
+			}
+#ifndef __mips__		    
+		}
+#endif	    
+	}
+	if(again)
+		goto repeat;
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+#else
+/* For SMP we only service one ESP on the list list at our IRQ level! */
+irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct NCR_ESP *esp;
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+	
+	/* Handle all ESP interrupts showing at this IRQ level. */
+	spin_lock_irqsave(dev->host_lock, flags);
+	for_each_esp(esp) {
+		if(((esp)->irq & 0xf) == irq) {
+			if(esp->dma_irq_p(esp)) {
+				esp->dma_ints_off(esp);
+
+				ESPIRQ(("I[%d:%d](",
+					smp_processor_id(), esp->esp_id));
+				esp_handle(esp);
+				ESPIRQ((")"));
+
+				esp->dma_ints_on(esp);
+				goto out;
+			}
+		}
+	}
+out:
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+#endif
+
+int esp_slave_alloc(Scsi_Device *SDptr)
+{
+	struct esp_device *esp_dev =
+		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+
+	if (!esp_dev)
+		return -ENOMEM;
+	memset(esp_dev, 0, sizeof(struct esp_device));
+	SDptr->hostdata = esp_dev;
+	return 0;
+}
+
+void esp_slave_destroy(Scsi_Device *SDptr)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *) SDptr->host->hostdata;
+
+	esp->targets_present &= ~(1 << SDptr->id);
+	kfree(SDptr->hostdata);
+	SDptr->hostdata = NULL;
+}
+
+#ifdef MODULE
+int init_module(void) { return 0; }
+void cleanup_module(void) {}
+void esp_release(void)
+{
+	esps_in_use--;
+	esps_running = esps_in_use;
+}
+#endif
+
+EXPORT_SYMBOL(esp_abort);
+EXPORT_SYMBOL(esp_allocate);
+EXPORT_SYMBOL(esp_deallocate);
+EXPORT_SYMBOL(esp_initialize);
+EXPORT_SYMBOL(esp_intr);
+EXPORT_SYMBOL(esp_queue);
+EXPORT_SYMBOL(esp_reset);
+EXPORT_SYMBOL(esp_slave_alloc);
+EXPORT_SYMBOL(esp_slave_destroy);
+EXPORT_SYMBOL(esps_in_use);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h
new file mode 100644
index 0000000..06e7edf
--- /dev/null
+++ b/drivers/scsi/NCR53C9x.h
@@ -0,0 +1,669 @@
+/* NCR53C9x.c:  Defines and structures for the NCR53C9x generic driver.
+ *
+ * Originaly esp.h:  Defines and structures for the Sparc ESP 
+ *                   (Enhanced SCSI Processor) driver under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ *
+ * Generalization by Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * More generalization (for i386 stuff) by Tymm Twillman (tymm@computer.org)
+ */
+
+#ifndef NCR53C9X_H
+#define NCR53C9X_H
+
+#include <linux/config.h>
+#include <linux/interrupt.h>
+
+/* djweis for mac driver */
+#if defined(CONFIG_MAC)
+#define PAD_SIZE 15
+#else
+#define PAD_SIZE 3
+#endif
+
+/* Handle multiple hostadapters on Amiga
+ * generally PAD_SIZE = 3
+ * but there is one exception: Oktagon (PAD_SIZE = 1) */
+#if defined(CONFIG_OKTAGON_SCSI) || defined(CONFIG_OKTAGON_SCSI_MODULE)
+#undef PAD_SIZE
+#if defined(CONFIG_BLZ1230_SCSI) || defined(CONFIG_BLZ1230_SCSI_MODULE) || \
+    defined(CONFIG_BLZ2060_SCSI) || defined(CONFIG_BLZ2060_SCSI_MODULE) || \
+    defined(CONFIG_CYBERSTORM_SCSI) || defined(CONFIG_CYBERSTORM_SCSI_MODULE) || \
+    defined(CONFIG_CYBERSTORMII_SCSI) || defined(CONFIG_CYBERSTORMII_SCSI_MODULE) || \
+    defined(CONFIG_FASTLANE_SCSI) || defined(CONFIG_FASTLANE_SCSI_MODULE)
+#define MULTIPLE_PAD_SIZES
+#else
+#define PAD_SIZE 1
+#endif
+#endif
+
+/* Macros for debugging messages */
+
+#define DEBUG_ESP
+/* #define DEBUG_ESP_DATA */
+/* #define DEBUG_ESP_QUEUE */
+/* #define DEBUG_ESP_DISCONNECT */
+/* #define DEBUG_ESP_STATUS */
+/* #define DEBUG_ESP_PHASES */
+/* #define DEBUG_ESP_WORKBUS */
+/* #define DEBUG_STATE_MACHINE */
+/* #define DEBUG_ESP_CMDS */
+/* #define DEBUG_ESP_IRQS */
+/* #define DEBUG_SDTR */
+/* #define DEBUG_ESP_SG */
+
+/* Use the following to sprinkle debugging messages in a way which
+ * suits you if combinations of the above become too verbose when
+ * trying to track down a specific problem.
+ */
+/* #define DEBUG_ESP_MISC */
+
+#if defined(DEBUG_ESP)
+#define ESPLOG(foo)  printk foo
+#else
+#define ESPLOG(foo)
+#endif /* (DEBUG_ESP) */
+
+#if defined(DEBUG_ESP_DATA)
+#define ESPDATA(foo)  printk foo
+#else
+#define ESPDATA(foo)
+#endif
+
+#if defined(DEBUG_ESP_QUEUE)
+#define ESPQUEUE(foo)  printk foo
+#else
+#define ESPQUEUE(foo)
+#endif
+
+#if defined(DEBUG_ESP_DISCONNECT)
+#define ESPDISC(foo)  printk foo
+#else
+#define ESPDISC(foo)
+#endif
+
+#if defined(DEBUG_ESP_STATUS)
+#define ESPSTAT(foo)  printk foo
+#else
+#define ESPSTAT(foo)
+#endif
+
+#if defined(DEBUG_ESP_PHASES)
+#define ESPPHASE(foo)  printk foo
+#else
+#define ESPPHASE(foo)
+#endif
+
+#if defined(DEBUG_ESP_WORKBUS)
+#define ESPBUS(foo)  printk foo
+#else
+#define ESPBUS(foo)
+#endif
+
+#if defined(DEBUG_ESP_IRQS)
+#define ESPIRQ(foo)  printk foo
+#else
+#define ESPIRQ(foo)
+#endif
+
+#if defined(DEBUG_SDTR)
+#define ESPSDTR(foo)  printk foo
+#else
+#define ESPSDTR(foo)
+#endif
+
+#if defined(DEBUG_ESP_MISC)
+#define ESPMISC(foo)  printk foo
+#else
+#define ESPMISC(foo)
+#endif
+
+/*
+ * padding for register structure
+ */
+#ifdef CONFIG_JAZZ_ESP
+#define EREGS_PAD(n)
+#else
+#ifndef MULTIPLE_PAD_SIZES
+#define EREGS_PAD(n)    unchar n[PAD_SIZE];
+#endif
+#endif
+
+/* The ESP SCSI controllers have their register sets in three
+ * "classes":
+ *
+ * 1) Registers which are both read and write.
+ * 2) Registers which are read only.
+ * 3) Registers which are write only.
+ *
+ * Yet, they all live within the same IO space.
+ */
+
+#if !defined(__i386__) && !defined(__x86_64__)
+
+#ifndef MULTIPLE_PAD_SIZES
+
+#ifdef CONFIG_CPU_HAS_WB
+#include <asm/wbflush.h>
+#define esp_write(__reg, __val) do{(__reg) = (__val); wbflush();} while(0)
+#else
+#define esp_write(__reg, __val) ((__reg) = (__val))
+#endif
+#define esp_read(__reg) (__reg)
+
+struct ESP_regs {
+                                /* Access    Description              Offset */
+    volatile unchar esp_tclow;  /* rw  Low bits of the transfer count 0x00   */
+                                EREGS_PAD(tlpad1);
+    volatile unchar esp_tcmed;  /* rw  Mid bits of the transfer count 0x04   */
+                                EREGS_PAD(fdpad);
+    volatile unchar esp_fdata;  /* rw  FIFO data bits                 0x08   */
+                                EREGS_PAD(cbpad);
+    volatile unchar esp_cmnd;   /* rw  SCSI command bits              0x0c   */
+                                EREGS_PAD(stpad);
+    volatile unchar esp_status; /* ro  ESP status register            0x10   */
+#define esp_busid   esp_status  /* wo  Bus ID for select/reselect     0x10   */
+                                EREGS_PAD(irqpd);
+    volatile unchar esp_intrpt; /* ro  Kind of interrupt              0x14   */
+#define esp_timeo   esp_intrpt  /* wo  Timeout value for select/resel 0x14   */
+                                EREGS_PAD(sspad);
+    volatile unchar esp_sstep;  /* ro  Sequence step register         0x18   */
+#define esp_stp     esp_sstep   /* wo  Transfer period per sync       0x18   */
+                                EREGS_PAD(ffpad);
+    volatile unchar esp_fflags; /* ro  Bits of current FIFO info      0x1c   */
+#define esp_soff    esp_fflags  /* wo  Sync offset                    0x1c   */
+                                EREGS_PAD(cf1pd);
+    volatile unchar esp_cfg1;   /* rw  First configuration register   0x20   */
+                                EREGS_PAD(cfpad);
+    volatile unchar esp_cfact;  /* wo  Clock conversion factor        0x24   */
+                                EREGS_PAD(ctpad);
+    volatile unchar esp_ctest;  /* wo  Chip test register             0x28   */
+                                EREGS_PAD(cf2pd);
+    volatile unchar esp_cfg2;   /* rw  Second configuration register  0x2c   */
+                                EREGS_PAD(cf3pd);
+
+    /* The following is only found on the 53C9X series SCSI chips */
+    volatile unchar esp_cfg3;   /* rw  Third configuration register   0x30  */
+                                EREGS_PAD(cf4pd);
+    volatile unchar esp_cfg4;   /* rw  Fourth configuration register  0x34  */
+                                EREGS_PAD(thpd);
+    /* The following is found on all chips except the NCR53C90 (ESP100) */
+    volatile unchar esp_tchi;   /* rw  High bits of transfer count    0x38  */
+#define esp_uid     esp_tchi    /* ro  Unique ID code                 0x38  */
+                                EREGS_PAD(fgpad);    
+    volatile unchar esp_fgrnd;  /* rw  Data base for fifo             0x3c  */
+};
+
+#else /* MULTIPLE_PAD_SIZES */
+
+#define esp_write(__reg, __val) (*(__reg) = (__val))
+#define esp_read(__reg) (*(__reg))
+
+struct ESP_regs {
+    unsigned char io_addr[64]; /* dummy */
+                                                 /* Access    Description              Offset */
+#define esp_tclow   io_addr                      /* rw  Low bits of the transfer count 0x00   */
+#define esp_tcmed   io_addr + (1<<(esp->shift))  /* rw  Mid bits of the transfer count 0x04   */
+#define esp_fdata   io_addr + (2<<(esp->shift))  /* rw  FIFO data bits                 0x08   */
+#define esp_cmnd    io_addr + (3<<(esp->shift))  /* rw  SCSI command bits              0x0c   */
+#define esp_status  io_addr + (4<<(esp->shift))  /* ro  ESP status register            0x10   */
+#define esp_busid   esp_status                   /* wo  Bus ID for select/reselect     0x10   */
+#define esp_intrpt  io_addr + (5<<(esp->shift))  /* ro  Kind of interrupt              0x14   */
+#define esp_timeo   esp_intrpt                   /* wo  Timeout value for select/resel 0x14   */
+#define esp_sstep   io_addr + (6<<(esp->shift))  /* ro  Sequence step register         0x18   */
+#define esp_stp     esp_sstep                    /* wo  Transfer period per sync       0x18   */
+#define esp_fflags  io_addr + (7<<(esp->shift))  /* ro  Bits of current FIFO info      0x1c   */
+#define esp_soff    esp_fflags                   /* wo  Sync offset                    0x1c   */
+#define esp_cfg1    io_addr + (8<<(esp->shift))  /* rw  First configuration register   0x20   */
+#define esp_cfact   io_addr + (9<<(esp->shift))  /* wo  Clock conversion factor        0x24   */
+#define esp_ctest   io_addr + (10<<(esp->shift)) /* wo  Chip test register             0x28   */
+#define esp_cfg2    io_addr + (11<<(esp->shift)) /* rw  Second configuration register  0x2c   */
+
+    /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3    io_addr + (12<<(esp->shift)) /* rw  Third configuration register   0x30  */
+#define esp_cfg4    io_addr + (13<<(esp->shift)) /* rw  Fourth configuration register  0x34  */
+
+    /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi    io_addr + (14<<(esp->shift)) /* rw  High bits of transfer count    0x38  */
+#define esp_uid     esp_tchi                     /* ro  Unique ID code                 0x38  */
+#define esp_fgrnd   io_addr + (15<<(esp->shift)) /* rw  Data base for fifo             0x3c  */
+};
+
+#endif
+
+#else /* !defined(__i386__) && !defined(__x86_64__) */
+
+#define esp_write(__reg, __val) outb((__val), (__reg))
+#define esp_read(__reg) inb((__reg))
+
+struct ESP_regs {
+    unsigned int io_addr;
+                                 /* Access    Description              Offset */
+#define esp_tclow   io_addr      /* rw  Low bits of the transfer count 0x00   */
+#define esp_tcmed   io_addr + 1  /* rw  Mid bits of the transfer count 0x04   */
+#define esp_fdata   io_addr + 2  /* rw  FIFO data bits                 0x08   */
+#define esp_cmnd    io_addr + 3  /* rw  SCSI command bits              0x0c   */
+#define esp_status  io_addr + 4  /* ro  ESP status register            0x10   */
+#define esp_busid   esp_status   /* wo  Bus ID for select/reselect     0x10   */
+#define esp_intrpt  io_addr + 5  /* ro  Kind of interrupt              0x14   */
+#define esp_timeo   esp_intrpt   /* wo  Timeout value for select/resel 0x14   */
+#define esp_sstep   io_addr + 6  /* ro  Sequence step register         0x18   */
+#define esp_stp     esp_sstep    /* wo  Transfer period per sync       0x18   */
+#define esp_fflags  io_addr + 7  /* ro  Bits of current FIFO info      0x1c   */
+#define esp_soff    esp_fflags   /* wo  Sync offset                    0x1c   */
+#define esp_cfg1    io_addr + 8  /* rw  First configuration register   0x20   */
+#define esp_cfact   io_addr + 9  /* wo  Clock conversion factor        0x24   */
+#define esp_ctest   io_addr + 10 /* wo  Chip test register             0x28   */
+#define esp_cfg2    io_addr + 11 /* rw  Second configuration register  0x2c   */
+
+    /* The following is only found on the 53C9X series SCSI chips */
+#define esp_cfg3    io_addr + 12 /* rw  Third configuration register   0x30  */
+#define esp_cfg4    io_addr + 13 /* rw  Fourth configuration register  0x34  */
+
+    /* The following is found on all chips except the NCR53C90 (ESP100) */
+#define esp_tchi    io_addr + 14 /* rw  High bits of transfer count    0x38  */
+#define esp_uid     esp_tchi     /* ro  Unique ID code                 0x38  */
+#define esp_fgrnd   io_addr + 15 /* rw  Data base for fifo             0x3c  */
+};
+
+#endif /* !defined(__i386__) && !defined(__x86_64__) */
+
+/* Various revisions of the ESP board. */
+enum esp_rev {
+  esp100     = 0x00,  /* NCR53C90 - very broken */
+  esp100a    = 0x01,  /* NCR53C90A */
+  esp236     = 0x02,
+  fas236     = 0x03,
+  fas100a    = 0x04,
+  fast       = 0x05,
+  fas366     = 0x06,
+  fas216     = 0x07,
+  fsc        = 0x08,  /* SYM53C94-2 */
+  espunknown = 0x09
+};
+
+/* We allocate one of these for each scsi device and attach it to
+ * SDptr->hostdata for use in the driver
+ */
+struct esp_device {
+  unsigned char sync_min_period;
+  unsigned char sync_max_offset;
+  unsigned sync:1;
+  unsigned wide:1;
+  unsigned disconnect:1;
+};
+
+/* We get one of these for each ESP probed. */
+struct NCR_ESP {
+  struct NCR_ESP *next;                   /* Next ESP on probed or NULL */
+  struct ESP_regs *eregs;	          /* All esp registers */
+  int dma;                                /* Who I do transfers with. */
+  void *dregs;		  		  /* And his registers. */
+  struct Scsi_Host *ehost;                /* Backpointer to SCSI Host */
+
+  void *edev;        		          /* Pointer to controller base/SBus */
+  int esp_id;                             /* Unique per-ESP ID number */
+
+  /* ESP Configuration Registers */
+  unsigned char config1;                  /* Copy of the 1st config register */
+  unsigned char config2;                  /* Copy of the 2nd config register */
+  unsigned char config3[16];              /* Copy of the 3rd config register */
+
+  /* The current command we are sending to the ESP chip.  This esp_command
+   * ptr needs to be mapped in DVMA area so we can send commands and read
+   * from the ESP fifo without burning precious CPU cycles.  Programmed I/O
+   * sucks when we have the DVMA to do it for us.  The ESP is stupid and will
+   * only send out 6, 10, and 12 byte SCSI commands, others we need to send
+   * one byte at a time.  esp_slowcmd being set says that we are doing one
+   * of the command types ESP doesn't understand, esp_scmdp keeps track of
+   * which byte we are sending, esp_scmdleft says how many bytes to go.
+   */
+  volatile unchar *esp_command;           /* Location of command (CPU view)  */
+  __u32            esp_command_dvma;      /* Location of command (DVMA view) */
+  unsigned char esp_clen;                 /* Length of this command */
+  unsigned char esp_slowcmd;
+  unsigned char *esp_scmdp;
+  unsigned char esp_scmdleft;
+
+  /* The following are used to determine the cause of an IRQ. Upon every
+   * IRQ entry we synchronize these with the hardware registers.
+   */
+  unchar ireg;                            /* Copy of ESP interrupt register */
+  unchar sreg;                            /* Same for ESP status register */
+  unchar seqreg;                          /* The ESP sequence register */
+
+  /* The following is set when a premature interrupt condition is detected
+   * in some FAS revisions.
+   */
+  unchar fas_premature_intr_workaround;
+
+  /* To save register writes to the ESP, which can be expensive, we
+   * keep track of the previous value that various registers had for
+   * the last target we connected to.  If they are the same for the
+   * current target, we skip the register writes as they are not needed.
+   */
+  unchar prev_soff, prev_stp, prev_cfg3;
+
+  /* For each target we keep track of save/restore data
+   * pointer information.  This needs to be updated majorly
+   * when we add support for tagged queueing.  -DaveM
+   */
+  struct esp_pointers {
+	  char *saved_ptr;
+	  struct scatterlist *saved_buffer;
+	  int saved_this_residual;
+	  int saved_buffers_residual;
+  } data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
+
+  /* Clock periods, frequencies, synchronization, etc. */
+  unsigned int cfreq;                    /* Clock frequency in HZ */
+  unsigned int cfact;                    /* Clock conversion factor */
+  unsigned int ccycle;                   /* One ESP clock cycle */
+  unsigned int ctick;                    /* One ESP clock time */
+  unsigned int radelay;                  /* FAST chip req/ack delay */
+  unsigned int neg_defp;                 /* Default negotiation period */
+  unsigned int sync_defp;                /* Default sync transfer period */
+  unsigned int max_period;               /* longest our period can be */
+  unsigned int min_period;               /* shortest period we can withstand */
+  /* For slow to medium speed input clock rates we shoot for 5mb/s,
+   * but for high input clock rates we try to do 10mb/s although I
+   * don't think a transfer can even run that fast with an ESP even
+   * with DMA2 scatter gather pipelining.
+   */
+#define SYNC_DEFP_SLOW            0x32   /* 5mb/s  */
+#define SYNC_DEFP_FAST            0x19   /* 10mb/s */
+
+  unsigned int snip;                      /* Sync. negotiation in progress */
+  unsigned int wnip;                      /* WIDE negotiation in progress */
+  unsigned int targets_present;           /* targets spoken to before */
+
+  int current_transfer_size;              /* Set at beginning of data dma */
+
+  unchar espcmdlog[32];                   /* Log of current esp cmds sent. */
+  unchar espcmdent;                       /* Current entry in esp cmd log. */
+
+  /* Misc. info about this ESP */
+  enum esp_rev erev;                      /* ESP revision */
+  int irq;                                /* IRQ for this ESP */
+  int scsi_id;                            /* Who am I as initiator? */
+  int scsi_id_mask;                       /* Bitmask of 'me'. */
+  int diff;                               /* Differential SCSI bus? */
+  int slot;                               /* Slot the adapter occupies */
+
+  /* Our command queues, only one cmd lives in the current_SC queue. */
+  Scsi_Cmnd *issue_SC;           /* Commands to be issued */
+  Scsi_Cmnd *current_SC;         /* Who is currently working the bus */
+  Scsi_Cmnd *disconnected_SC;    /* Commands disconnected from the bus */
+
+  /* Message goo */
+  unchar cur_msgout[16];
+  unchar cur_msgin[16];
+  unchar prevmsgout, prevmsgin;
+  unchar msgout_len, msgin_len;
+  unchar msgout_ctr, msgin_ctr;
+
+  /* States that we cannot keep in the per cmd structure because they
+   * cannot be assosciated with any specific command.
+   */
+  unchar resetting_bus;
+  wait_queue_head_t reset_queue;
+
+  unchar do_pio_cmds;		/* Do command transfer with pio */
+
+  /* How much bits do we have to shift the registers */
+  unsigned char shift;
+
+  /* Functions handling DMA
+   */ 
+  /* Required functions */
+  int  (*dma_bytes_sent)(struct NCR_ESP *, int);
+  int  (*dma_can_transfer)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_dump_state)(struct NCR_ESP *);
+  void (*dma_init_read)(struct NCR_ESP *, __u32, int);
+  void (*dma_init_write)(struct NCR_ESP *, __u32, int);
+  void (*dma_ints_off)(struct NCR_ESP *);
+  void (*dma_ints_on)(struct NCR_ESP *);
+  int  (*dma_irq_p)(struct NCR_ESP *);
+  int  (*dma_ports_p)(struct NCR_ESP *);
+  void (*dma_setup)(struct NCR_ESP *, __u32, int, int);
+
+  /* Optional functions (i.e. may be initialized to 0) */
+  void (*dma_barrier)(struct NCR_ESP *);
+  void (*dma_drain)(struct NCR_ESP *);
+  void (*dma_invalidate)(struct NCR_ESP *);
+  void (*dma_irq_entry)(struct NCR_ESP *);
+  void (*dma_irq_exit)(struct NCR_ESP *);
+  void (*dma_led_off)(struct NCR_ESP *);
+  void (*dma_led_on)(struct NCR_ESP *);
+  void (*dma_poll)(struct NCR_ESP *, unsigned char *);
+  void (*dma_reset)(struct NCR_ESP *);
+    
+  /* Optional virtual DMA functions */
+  void (*dma_mmu_get_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_get_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_one)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_mmu_release_scsi_sgl)(struct NCR_ESP *, Scsi_Cmnd *);
+  void (*dma_advance_sg)(Scsi_Cmnd *);
+};
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID        0x07             /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST    0x08             /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE   0x10             /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST   0x20             /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB  0x40             /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE   0x80             /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236+fsc chips */
+#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236,fsc) */
+#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236,fsc) */
+#define ESP_CONFIG2_BADPARITY 0x04             /* Bad parity target abort  */
+#define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features (tmode only) */
+#define ESP_CONFIG2_HI        0x10             /* High Impedance DREQ ???  */
+#define ESP_CONFIG2_HMEFENAB  0x10             /* HME features enable */
+#define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236,fsc)   */
+#define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216,fsc)      */
+#define ESP_CONFIG2_SPL       0x40             /* Enable status-phase latch (esp236)   */
+#define ESP_CONFIG2_RFB       0x80             /* Reserve FIFO byte (fsc) */
+#define ESP_CONFIG2_MAGIC     0xe0             /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+fsc chips */
+#define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a/fas366) */
+#define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236/fsc)  */
+#define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a) */
+#define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236/fsc)  */
+#define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a) */
+#define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236/fsc)  */
+#define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a) */
+#define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236/fsc)  */
+#define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a) */
+#define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236/fsc)  */
+#define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236/fsc)  */
+#define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236/fsc)  */
+#define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236/fsc)  */
+
+/* ESP config register 4 read-write, found only on fsc chips */
+#define ESP_CONFIG4_BBTE      0x01             /* Back-to-Back transfer enable */
+#define ESP_CONFIG4_TEST      0x02             /* Transfer counter test mode */
+#define ESP_CONFIG4_EAN       0x04             /* Enable Active Negotiation */
+
+/* ESP command register read-write */
+/* Group 1 commands:  These may be sent at any point in time to the ESP
+ *                    chip.  None of them can generate interrupts 'cept
+ *                    the "SCSI bus reset" command if you have not disabled
+ *                    SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL          0x00             /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH         0x01             /* FIFO Flush */
+#define ESP_CMD_RC            0x02             /* Chip reset */
+#define ESP_CMD_RS            0x03             /* SCSI bus reset */
+
+/* Group 2 commands:  ESP must be an initiator and connected to a target
+ *                    for these commands to work.
+ */
+#define ESP_CMD_TI            0x10             /* Transfer Information */
+#define ESP_CMD_ICCSEQ        0x11             /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK           0x12             /* Message okie-dokie */
+#define ESP_CMD_TPAD          0x18             /* Transfer Pad */
+#define ESP_CMD_SATN          0x1a             /* Set ATN */
+#define ESP_CMD_RATN          0x1b             /* De-assert ATN */
+
+/* Group 3 commands:  ESP must be in the MSGOUT or MSGIN state and be connected
+ *                    to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG          0x20             /* Send message */
+#define ESP_CMD_SSTAT         0x21             /* Send status */
+#define ESP_CMD_SDATA         0x22             /* Send data */
+#define ESP_CMD_DSEQ          0x23             /* Discontinue Sequence */
+#define ESP_CMD_TSEQ          0x24             /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ        0x25             /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT         0x27             /* Disconnect */
+#define ESP_CMD_RMSG          0x28             /* Receive Message */
+#define ESP_CMD_RCMD          0x29             /* Receive Command */
+#define ESP_CMD_RDATA         0x2a             /* Receive Data */
+#define ESP_CMD_RCSEQ         0x2b             /* Receive cmd sequence */
+
+/* Group 4 commands:  The ESP must be in the disconnected state and must
+ *                    not be connected to any targets as initiator for
+ *                    these commands to work.
+ */
+#define ESP_CMD_RSEL          0x40             /* Reselect */
+#define ESP_CMD_SEL           0x41             /* Select w/o ATN */
+#define ESP_CMD_SELA          0x42             /* Select w/ATN */
+#define ESP_CMD_SELAS         0x43             /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL          0x44             /* Enable selection */
+#define ESP_CMD_DSEL          0x45             /* Disable selections */
+#define ESP_CMD_SA3           0x46             /* Select w/ATN3 */
+#define ESP_CMD_RSEL3         0x47             /* Reselect3 */
+
+/* This bit enables the ESP's DMA */
+#define ESP_CMD_DMA           0x80             /* Do DMA? */
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO          0x01             /* IO phase bit */
+#define ESP_STAT_PCD          0x02             /* CD phase bit */
+#define ESP_STAT_PMSG         0x04             /* MSG phase bit */
+#define ESP_STAT_PMASK        0x07             /* Mask of phase bits */
+#define ESP_STAT_TDONE        0x08             /* Transfer Completed */
+#define ESP_STAT_TCNT         0x10             /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR         0x20             /* Parity error */
+#define ESP_STAT_SPAM         0x40             /* Real bad error */
+/* This indicates the 'interrupt pending' condition, it is a reserved
+ * bit on old revs of the ESP (ESP100, ESP100A, FAS100A).
+ */
+#define ESP_STAT_INTR         0x80             /* Interrupt */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in.  For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP   (0)                                       /* Data Out  */
+#define ESP_DIP   (ESP_STAT_PIO)                            /* Data In   */
+#define ESP_CMDP  (ESP_STAT_PCD)                            /* Command   */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO)               /* Status    */
+#define ESP_MOP   (ESP_STAT_PMSG|ESP_STAT_PCD)              /* Message Out */
+#define ESP_MIP   (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S            0x01             /* Select w/o ATN */
+#define ESP_INTR_SATN         0x02             /* Select w/ATN */
+#define ESP_INTR_RSEL         0x04             /* Reselected */
+#define ESP_INTR_FDONE        0x08             /* Function done */
+#define ESP_INTR_BSERV        0x10             /* Bus service */
+#define ESP_INTR_DC           0x20             /* Disconnect */
+#define ESP_INTR_IC           0x40             /* Illegal command given */
+#define ESP_INTR_SR           0x80             /* SCSI bus reset detected */
+
+/* Interrupt status macros */
+#define ESP_SRESET_IRQ(esp)  ((esp)->intreg & (ESP_INTR_SR))
+#define ESP_ILLCMD_IRQ(esp)  ((esp)->intreg & (ESP_INTR_IC))
+#define ESP_SELECT_WITH_ATN_IRQ(esp)     ((esp)->intreg & (ESP_INTR_SATN))
+#define ESP_SELECT_WITHOUT_ATN_IRQ(esp)  ((esp)->intreg & (ESP_INTR_S))
+#define ESP_SELECTION_IRQ(esp)  ((ESP_SELECT_WITH_ATN_IRQ(esp)) ||         \
+				 (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
+#define ESP_RESELECTION_IRQ(esp)         ((esp)->intreg & (ESP_INTR_RSEL))
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS        0x07             /* Valid bits */
+#define ESP_STEP_ASEL         0x00             /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID          0x01             /* One msg byte sent */
+#define ESP_STEP_NCMD         0x02             /* Was not in command phase */
+#define ESP_STEP_PPC          0x03             /* Early phase chg caused cmnd
+                                                * bytes to be lost
+                                                */
+#define ESP_STEP_FINI4        0x04             /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5        0x05
+#define ESP_STEP_FINI6        0x06
+#define ESP_STEP_FINI7        0x07
+#define ESP_STEP_SOM          0x08             /* Synchronous Offset Max */
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG         0x01             /* Target test mode */
+#define ESP_TEST_INI          0x02             /* Initiator test mode */
+#define ESP_TEST_TS           0x04             /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a+fsc only */
+#define ESP_UID_F100A         0x00             /* FAS100A  */
+#define ESP_UID_F236          0x02             /* FAS236   */
+#define ESP_UID_FSC           0xa2             /* NCR53CF9x-2  */
+#define ESP_UID_REV           0x07             /* ESP revision */
+#define ESP_UID_FAM           0xf8             /* ESP family   */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES         0x1f             /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100,fsc) */
+#define ESP_FF_SSTEP          0xe0             /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0            0x00             /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER         0x01             /* Set it to this and die */
+#define ESP_CCF_F2            0x02             /* 10MHz */
+#define ESP_CCF_F3            0x03             /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4            0x04             /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5            0x05             /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6            0x06             /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7            0x07             /* 30.01MHz - 35MHz */
+
+#define ESP_BUS_TIMEOUT        275             /* In milli-seconds */
+#define ESP_TIMEO_CONST       8192
+#define FSC_TIMEO_CONST       7668
+#define ESP_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define FSC_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (7668 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
+
+
+/* UGLY, UGLY, UGLY! */
+extern int nesps, esps_in_use, esps_running;
+
+/* For our interrupt engine. */
+#define for_each_esp(esp) \
+        for((esp) = espchain; (esp); (esp) = (esp)->next)
+
+
+/* External functions */
+extern void esp_bootup_reset(struct NCR_ESP *esp, struct ESP_regs *eregs);
+extern struct NCR_ESP *esp_allocate(Scsi_Host_Template *, void *);
+extern void esp_deallocate(struct NCR_ESP *);
+extern void esp_release(void);
+extern void esp_initialize(struct NCR_ESP *);
+extern irqreturn_t esp_intr(int, void *, struct pt_regs *);
+extern const char *esp_info(struct Scsi_Host *);
+extern int esp_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+extern int esp_abort(Scsi_Cmnd *);
+extern int esp_reset(Scsi_Cmnd *);
+extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length,
+			 int inout);
+extern int esp_slave_alloc(Scsi_Device *);
+extern void esp_slave_destroy(Scsi_Device *);
+#endif /* !(NCR53C9X_H) */
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
new file mode 100644
index 0000000..c685d54
--- /dev/null
+++ b/drivers/scsi/NCR53c406a.c
@@ -0,0 +1,1110 @@
+/* 
+ *  NCR53c406.c
+ *  Low-level SCSI driver for NCR53c406a chip.
+ *  Copyright (C) 1994, 1995, 1996 Normunds Saumanis (normunds@fi.ibm.com)
+ * 
+ *  LILO command line usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]
+ *  Specify IRQ = 0 for non-interrupt driven mode.
+ *  FASTPIO = 1 for fast pio mode, 0 for slow mode.
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2, or (at your option) any
+ *  later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ */
+
+#define NCR53C406A_DEBUG 0
+#define VERBOSE_NCR53C406A_DEBUG 0
+
+/* Set this to 1 for PIO mode (recommended) or to 0 for DMA mode */
+#define USE_PIO 1
+
+#define USE_BIOS 0
+				/* #define BIOS_ADDR 0xD8000 *//* define this if autoprobe fails */
+				/* #define PORT_BASE 0x330 *//* define this if autoprobe fails */
+				/* #define IRQ_LEV   0	*//* define this if autoprobe fails */
+#define DMA_CHAN  5		/* this is ignored if DMA is disabled */
+
+/* Set this to 0 if you encounter kernel lockups while transferring 
+ * data in PIO mode */
+#define USE_FAST_PIO 1
+
+/* ============= End of user configurable parameters ============= */
+
+#include <linux/module.h>
+
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+/* ============================================================= */
+
+#define WATCHDOG 5000000
+
+#define SYNC_MODE 0		/* Synchronous transfer mode */
+
+#if DEBUG
+#undef NCR53C406A_DEBUG
+#define NCR53C406A_DEBUG 1
+#endif
+
+#if USE_PIO
+#define USE_DMA 0
+#else
+#define USE_DMA 1
+#endif
+
+/* Default configuration */
+#define C1_IMG   0x07		/* ID=7 */
+#define C2_IMG   0x48		/* FE SCSI2 */
+#if USE_DMA
+#define C3_IMG   0x21		/* CDB TE */
+#else
+#define C3_IMG   0x20		/* CDB */
+#endif
+#define C4_IMG   0x04		/* ANE */
+#define C5_IMG   0xb6		/* AA PI SIE POL */
+
+#define REG0 (outb(C4_IMG, CONFIG4))
+#define REG1 (outb(C5_IMG, CONFIG5))
+
+#if NCR53C406A_DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+#if VERBOSE_NCR53C406A_DEBUG
+#define VDEB(x) x
+#else
+#define VDEB(x)
+#endif
+
+#define LOAD_DMA_COUNT(count) \
+  outb(count & 0xff, TC_LSB); \
+  outb((count >> 8) & 0xff, TC_MSB); \
+  outb((count >> 16) & 0xff, TC_HIGH);
+
+/* Chip commands */
+#define DMA_OP               0x80
+
+#define SCSI_NOP             0x00
+#define FLUSH_FIFO           0x01
+#define CHIP_RESET           0x02
+#define SCSI_RESET           0x03
+#define RESELECT             0x40
+#define SELECT_NO_ATN        0x41
+#define SELECT_ATN           0x42
+#define SELECT_ATN_STOP      0x43
+#define ENABLE_SEL           0x44
+#define DISABLE_SEL          0x45
+#define SELECT_ATN3          0x46
+#define RESELECT3            0x47
+#define TRANSFER_INFO        0x10
+#define INIT_CMD_COMPLETE    0x11
+#define MSG_ACCEPT           0x12
+#define TRANSFER_PAD         0x18
+#define SET_ATN              0x1a
+#define RESET_ATN            0x1b
+#define SEND_MSG             0x20
+#define SEND_STATUS          0x21
+#define SEND_DATA            0x22
+#define DISCONN_SEQ          0x23
+#define TERMINATE_SEQ        0x24
+#define TARG_CMD_COMPLETE    0x25
+#define DISCONN              0x27
+#define RECV_MSG             0x28
+#define RECV_CMD             0x29
+#define RECV_DATA            0x2a
+#define RECV_CMD_SEQ         0x2b
+#define TARGET_ABORT_DMA     0x04
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+   where something crashed or gets stuck at */
+/* 1 = blue
+   2 = green
+   3 = cyan
+   4 = red
+   5 = magenta
+   6 = yellow
+   7 = white
+*/
+
+#if NCR53C406A_DEBUG
+#define rtrc(i) {inb(0x3da);outb(0x31,0x3c0);outb((i),0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+/*----------------------------------------------------------------*/
+
+enum Phase {
+	idle,
+	data_out,
+	data_in,
+	command_ph,
+	status_ph,
+	message_out,
+	message_in
+};
+
+/* Static function prototypes */
+static void NCR53c406a_intr(int, void *, struct pt_regs *);
+static irqreturn_t do_NCR53c406a_intr(int, void *, struct pt_regs *);
+static void chip_init(void);
+static void calc_port_addr(void);
+#ifndef IRQ_LEV
+static int irq_probe(void);
+#endif
+
+/* ================================================================= */
+
+#if USE_BIOS
+static void *bios_base;
+#endif
+
+#if PORT_BASE
+static int port_base = PORT_BASE;
+#else
+static int port_base;
+#endif
+
+#if IRQ_LEV
+static int irq_level = IRQ_LEV;
+#else
+static int irq_level = -1;	/* 0 is 'no irq', so use -1 for 'uninitialized' */
+#endif
+
+#if USE_DMA
+static int dma_chan;
+#endif
+
+#if USE_PIO
+static int fast_pio = USE_FAST_PIO;
+#endif
+
+static Scsi_Cmnd *current_SC;
+static char info_msg[256];
+
+/* ================================================================= */
+
+/* possible BIOS locations */
+#if USE_BIOS
+static void *addresses[] = {
+	(void *) 0xd8000,
+	(void *) 0xc8000
+};
+#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
+#endif				/* USE_BIOS */
+
+/* possible i/o port addresses */
+static unsigned short ports[] = { 0x230, 0x330, 0x280, 0x290, 0x330, 0x340, 0x300, 0x310, 0x348, 0x350 };
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+/* possible interrupt channels */
+static unsigned short intrs[] = { 10, 11, 12, 15 };
+#define INTR_COUNT (sizeof( intrs ) / sizeof( unsigned short ))
+
+/* signatures for NCR 53c406a based controllers */
+#if USE_BIOS
+struct signature {
+	char *signature;
+	int sig_offset;
+	int sig_length;
+} signatures[] __initdata = {
+	/*          1         2         3         4         5         6 */
+	/* 123456789012345678901234567890123456789012345678901234567890 */
+	{
+"Copyright (C) Acculogic, Inc.\r\n2.8M Diskette Extension Bios ver 4.04.03 03/01/1993", 61, 82},};
+
+#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+#endif				/* USE_BIOS */
+
+/* ============================================================ */
+
+/* Control Register Set 0 */
+static int TC_LSB;		/* transfer counter lsb         */
+static int TC_MSB;		/* transfer counter msb */
+static int SCSI_FIFO;		/* scsi fifo register   */
+static int CMD_REG;		/* command register             */
+static int STAT_REG;		/* status register              */
+static int DEST_ID;		/* selection/reselection bus id */
+static int INT_REG;		/* interrupt status register    */
+static int SRTIMOUT;		/* select/reselect timeout reg  */
+static int SEQ_REG;		/* sequence step register       */
+static int SYNCPRD;		/* synchronous transfer period  */
+static int FIFO_FLAGS;		/* indicates # of bytes in fifo */
+static int SYNCOFF;		/* synchronous offset register  */
+static int CONFIG1;		/* configuration register       */
+static int CLKCONV;		/* clock conversion reg */
+				/*static int TESTREG;*//* test mode register           */
+static int CONFIG2;		/* Configuration 2 Register     */
+static int CONFIG3;		/* Configuration 3 Register     */
+static int CONFIG4;		/* Configuration 4 Register     */
+static int TC_HIGH;		/* Transfer Counter High */
+				/*static int FIFO_BOTTOM;*//* Reserve FIFO byte register   */
+
+/* Control Register Set 1 */
+				/*static int JUMPER_SENSE;*//* Jumper sense port reg (r/w) */
+				/*static int SRAM_PTR;*//* SRAM address pointer reg (r/w) */
+				/*static int SRAM_DATA;*//* SRAM data register (r/w) */
+static int PIO_FIFO;		/* PIO FIFO registers (r/w) */
+				/*static int PIO_FIFO1;*//*  */
+				/*static int PIO_FIFO2;*//*  */
+				/*static int PIO_FIFO3;*//*  */
+static int PIO_STATUS;		/* PIO status (r/w) */
+				/*static int ATA_CMD;*//* ATA command/status reg (r/w) */
+				/*static int ATA_ERR;*//* ATA features/error register (r/w) */
+static int PIO_FLAG;		/* PIO flag interrupt enable (r/w) */
+static int CONFIG5;		/* Configuration 5 register (r/w) */
+				/*static int SIGNATURE;*//* Signature Register (r) */
+				/*static int CONFIG6;*//* Configuration 6 register (r) */
+
+/* ============================================================== */
+
+#if USE_DMA
+static __inline__ int NCR53c406a_dma_setup(unsigned char *ptr, unsigned int count, unsigned char mode)
+{
+	unsigned limit;
+	unsigned long flags = 0;
+
+	VDEB(printk("dma: before count=%d   ", count));
+	if (dma_chan <= 3) {
+		if (count > 65536)
+			count = 65536;
+		limit = 65536 - (((unsigned) ptr) & 0xFFFF);
+	} else {
+		if (count > (65536 << 1))
+			count = (65536 << 1);
+		limit = (65536 << 1) - (((unsigned) ptr) & 0x1FFFF);
+	}
+
+	if (count > limit)
+		count = limit;
+
+	VDEB(printk("after count=%d\n", count));
+	if ((count & 1) || (((unsigned) ptr) & 1))
+		panic("NCR53c406a: attempted unaligned DMA transfer\n");
+
+	flags = claim_dma_lock();
+	disable_dma(dma_chan);
+	clear_dma_ff(dma_chan);
+	set_dma_addr(dma_chan, (long) ptr);
+	set_dma_count(dma_chan, count);
+	set_dma_mode(dma_chan, mode);
+	enable_dma(dma_chan);
+	release_dma_lock(flags);
+
+	return count;
+}
+
+static __inline__ int NCR53c406a_dma_write(unsigned char *src, unsigned int count)
+{
+	return NCR53c406a_dma_setup(src, count, DMA_MODE_WRITE);
+}
+
+static __inline__ int NCR53c406a_dma_read(unsigned char *src, unsigned int count)
+{
+	return NCR53c406a_dma_setup(src, count, DMA_MODE_READ);
+}
+
+static __inline__ int NCR53c406a_dma_residual(void)
+{
+	register int tmp;
+	unsigned long flags;
+
+	flags = claim_dma_lock();
+	clear_dma_ff(dma_chan);
+	tmp = get_dma_residue(dma_chan);
+	release_dma_lock(flags);
+
+	return tmp;
+}
+#endif				/* USE_DMA */
+
+#if USE_PIO
+static __inline__ int NCR53c406a_pio_read(unsigned char *request, unsigned int reqlen)
+{
+	int i;
+	int len;		/* current scsi fifo size */
+
+	REG1;
+	while (reqlen) {
+		i = inb(PIO_STATUS);
+		/*    VDEB(printk("pio_status=%x\n", i)); */
+		if (i & 0x80)
+			return 0;
+
+		switch (i & 0x1e) {
+		default:
+		case 0x10:
+			len = 0;
+			break;
+		case 0x0:
+			len = 1;
+			break;
+		case 0x8:
+			len = 42;
+			break;
+		case 0xc:
+			len = 84;
+			break;
+		case 0xe:
+			len = 128;
+			break;
+		}
+
+		if ((i & 0x40) && len == 0) {	/* fifo empty and interrupt occurred */
+			return 0;
+		}
+
+		if (len) {
+			if (len > reqlen)
+				len = reqlen;
+
+			if (fast_pio && len > 3) {
+				insl(PIO_FIFO, request, len >> 2);
+				request += len & 0xfc;
+				reqlen -= len & 0xfc;
+			} else {
+				while (len--) {
+					*request++ = inb(PIO_FIFO);
+					reqlen--;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static __inline__ int NCR53c406a_pio_write(unsigned char *request, unsigned int reqlen)
+{
+	int i = 0;
+	int len;		/* current scsi fifo size */
+
+	REG1;
+	while (reqlen && !(i & 0x40)) {
+		i = inb(PIO_STATUS);
+		/*    VDEB(printk("pio_status=%x\n", i)); */
+		if (i & 0x80)	/* error */
+			return 0;
+
+		switch (i & 0x1e) {
+		case 0x10:
+			len = 128;
+			break;
+		case 0x0:
+			len = 84;
+			break;
+		case 0x8:
+			len = 42;
+			break;
+		case 0xc:
+			len = 1;
+			break;
+		default:
+		case 0xe:
+			len = 0;
+			break;
+		}
+
+		if (len) {
+			if (len > reqlen)
+				len = reqlen;
+
+			if (fast_pio && len > 3) {
+				outsl(PIO_FIFO, request, len >> 2);
+				request += len & 0xfc;
+				reqlen -= len & 0xfc;
+			} else {
+				while (len--) {
+					outb(*request++, PIO_FIFO);
+					reqlen--;
+				}
+			}
+		}
+	}
+	return 0;
+}
+#endif				/* USE_PIO */
+
+static int __init NCR53c406a_detect(Scsi_Host_Template * tpnt)
+{
+	int present = 0;
+	struct Scsi_Host *shpnt = NULL;
+#ifndef PORT_BASE
+	int i;
+#endif
+
+#if USE_BIOS
+	int ii, jj;
+	bios_base = 0;
+	/* look for a valid signature */
+	for (ii = 0; ii < ADDRESS_COUNT && !bios_base; ii++)
+		for (jj = 0; (jj < SIGNATURE_COUNT) && !bios_base; jj++)
+			if (!memcmp((void *) addresses[ii] + signatures[jj].sig_offset, (void *) signatures[jj].signature, (int) signatures[jj].sig_length))
+				bios_base = addresses[ii];
+
+	if (!bios_base) {
+		printk("NCR53c406a: BIOS signature not found\n");
+		return 0;
+	}
+
+	DEB(printk("NCR53c406a BIOS found at 0x%x\n", (unsigned int) bios_base);
+	    );
+#endif				/* USE_BIOS */
+
+#ifdef PORT_BASE
+	if (!request_region(port_base, 0x10, "NCR53c406a"))	/* ports already snatched */
+		port_base = 0;
+
+#else				/* autodetect */
+	if (port_base) {	/* LILO override */
+		if (!request_region(port_base, 0x10, "NCR53c406a"))
+			port_base = 0;
+	} else {
+		for (i = 0; i < PORT_COUNT && !port_base; i++) {
+			if (!request_region(ports[i], 0x10, "NCR53c406a")) {
+				DEB(printk("NCR53c406a: port 0x%x in use\n", ports[i]));
+			} else {
+				VDEB(printk("NCR53c406a: port 0x%x available\n", ports[i]));
+				outb(C5_IMG, ports[i] + 0x0d);	/* reg set 1 */
+				if ((inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) ^ inb(ports[i] + 0x0e)) == 7 && (inb(ports[i] + 0x0e) & 0xf8) == 0x58) {
+					port_base = ports[i];
+					VDEB(printk("NCR53c406a: Sig register valid\n"));
+					VDEB(printk("port_base=0x%x\n", port_base));
+					break;
+				}
+				release_region(ports[i], 0x10);
+			}
+		}
+	}
+#endif				/* PORT_BASE */
+
+	if (!port_base) {	/* no ports found */
+		printk("NCR53c406a: no available ports found\n");
+		return 0;
+	}
+
+	DEB(printk("NCR53c406a detected\n"));
+
+	calc_port_addr();
+	chip_init();
+
+#ifndef IRQ_LEV
+	if (irq_level < 0) {	/* LILO override if >= 0 */
+		irq_level = irq_probe();
+		if (irq_level < 0) {	/* Trouble */
+			printk("NCR53c406a: IRQ problem, irq_level=%d, giving up\n", irq_level);
+			goto err_release;
+		}
+	}
+#endif
+
+	DEB(printk("NCR53c406a: using port_base 0x%x\n", port_base));
+
+	present = 1;
+	tpnt->proc_name = "NCR53c406a";
+
+	shpnt = scsi_register(tpnt, 0);
+	if (!shpnt) {
+		printk("NCR53c406a: Unable to register host, giving up.\n");
+		goto err_release;
+	}
+
+	if (irq_level > 0) {
+		if (request_irq(irq_level, do_NCR53c406a_intr, 0, "NCR53c406a", shpnt)) {
+			printk("NCR53c406a: unable to allocate IRQ %d\n", irq_level);
+			goto err_free_scsi;
+		}
+		tpnt->can_queue = 1;
+		DEB(printk("NCR53c406a: allocated IRQ %d\n", irq_level));
+	} else if (irq_level == 0) {
+		tpnt->can_queue = 0;
+		DEB(printk("NCR53c406a: No interrupts detected\n"));
+		printk("NCR53c406a driver no longer supports polling interface\n");
+		printk("Please email linux-scsi@vger.kernel.org\n");
+                        
+#if USE_DMA
+		printk("NCR53c406a: No interrupts found and DMA mode defined. Giving up.\n");
+#endif				/* USE_DMA */
+		goto err_free_scsi;
+	} else {
+		DEB(printk("NCR53c406a: Shouldn't get here!\n"));
+		goto err_free_scsi;
+	}
+
+#if USE_DMA
+	dma_chan = DMA_CHAN;
+	if (request_dma(dma_chan, "NCR53c406a") != 0) {
+		printk("NCR53c406a: unable to allocate DMA channel %d\n", dma_chan);
+		goto err_free_irq;
+	}
+
+	DEB(printk("Allocated DMA channel %d\n", dma_chan));
+#endif				/* USE_DMA */
+
+	shpnt->irq = irq_level;
+	shpnt->io_port = port_base;
+	shpnt->n_io_port = 0x10;
+#if USE_DMA
+	shpnt->dma = dma_chan;
+#endif
+
+#if USE_DMA
+	sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, DMA channel %d.", port_base, irq_level, dma_chan);
+#else
+	sprintf(info_msg, "NCR53c406a at 0x%x, IRQ %d, %s PIO mode.", port_base, irq_level, fast_pio ? "fast" : "slow");
+#endif
+
+	return (present);
+
+#if USE_DMA
+      err_free_irq:
+	if (irq_level)
+		free_irq(irq_level, shpnt);
+#endif
+      err_free_scsi:
+	scsi_unregister(shpnt);
+      err_release:
+	release_region(port_base, 0x10);
+	return 0;
+}
+
+static int NCR53c406a_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+#ifdef USE_DMA
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+#endif
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+
+	scsi_unregister(shost);
+	return 0;
+}
+
+/* called from init/main.c */
+static int __init NCR53c406a_setup(char *str)
+{
+	static size_t setup_idx = 0;
+	size_t i;
+	int ints[4];
+
+	DEB(printk("NCR53c406a: Setup called\n");
+	    );
+
+	if (setup_idx >= PORT_COUNT - 1) {
+		printk("NCR53c406a: Setup called too many times.  Bad LILO params?\n");
+		return 0;
+	}
+	get_options(str, 4, ints);
+	if (ints[0] < 1 || ints[0] > 3) {
+		printk("NCR53c406a: Malformed command line\n");
+		printk("NCR53c406a: Usage: ncr53c406a=<PORTBASE>[,<IRQ>[,<FASTPIO>]]\n");
+		return 0;
+	}
+	for (i = 0; i < PORT_COUNT && !port_base; i++)
+		if (ports[i] == ints[1]) {
+			port_base = ints[1];
+			DEB(printk("NCR53c406a: Specified port_base 0x%x\n", port_base);
+			    )
+		}
+	if (!port_base) {
+		printk("NCR53c406a: Invalid PORTBASE 0x%x specified\n", ints[1]);
+		return 0;
+	}
+
+	if (ints[0] > 1) {
+		if (ints[2] == 0) {
+			irq_level = 0;
+			DEB(printk("NCR53c406a: Specified irq %d\n", irq_level);
+			    )
+		} else
+			for (i = 0; i < INTR_COUNT && irq_level < 0; i++)
+				if (intrs[i] == ints[2]) {
+					irq_level = ints[2];
+					DEB(printk("NCR53c406a: Specified irq %d\n", port_base);
+					    )
+				}
+		if (irq_level < 0)
+			printk("NCR53c406a: Invalid IRQ %d specified\n", ints[2]);
+	}
+
+	if (ints[0] > 2)
+		fast_pio = ints[3];
+
+	DEB(printk("NCR53c406a: port_base=0x%x, irq=%d, fast_pio=%d\n", port_base, irq_level, fast_pio);)
+	return 1;
+}
+
+__setup("ncr53c406a=", NCR53c406a_setup);
+
+static const char *NCR53c406a_info(struct Scsi_Host *SChost)
+{
+	DEB(printk("NCR53c406a_info called\n"));
+	return (info_msg);
+}
+
+#if 0
+static void wait_intr(void)
+{
+	unsigned long i = jiffies + WATCHDOG;
+
+	while (time_after(i, jiffies) && !(inb(STAT_REG) & 0xe0)) {	/* wait for a pseudo-interrupt */
+		cpu_relax();
+		barrier();
+	}
+
+	if (time_before_eq(i, jiffies)) {	/* Timed out */
+		rtrc(0);
+		current_SC->result = DID_TIME_OUT << 16;
+		current_SC->SCp.phase = idle;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+
+	NCR53c406a_intr(0, NULL, NULL);
+}
+#endif
+
+static int NCR53c406a_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	int i;
+
+	VDEB(printk("NCR53c406a_queue called\n"));
+	DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->target, SCpnt->lun, SCpnt->request_bufflen));
+
+#if 0
+	VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
+	     printk("cmd[%d]=%02x  ", i, SCpnt->cmnd[i]));
+	VDEB(printk("\n"));
+#endif
+
+	current_SC = SCpnt;
+	current_SC->scsi_done = done;
+	current_SC->SCp.phase = command_ph;
+	current_SC->SCp.Status = 0;
+	current_SC->SCp.Message = 0;
+
+	/* We are locked here already by the mid layer */
+	REG0;
+	outb(SCpnt->device->id, DEST_ID);	/* set destination */
+	outb(FLUSH_FIFO, CMD_REG);	/* reset the fifos */
+
+	for (i = 0; i < SCpnt->cmd_len; i++) {
+		outb(SCpnt->cmnd[i], SCSI_FIFO);
+	}
+	outb(SELECT_NO_ATN, CMD_REG);
+
+	rtrc(1);
+	return 0;
+}
+
+static int NCR53c406a_abort(Scsi_Cmnd * SCpnt)
+{
+	DEB(printk("NCR53c406a_abort called\n"));
+	return FAILED;		/* Don't know how to abort */
+}
+
+static int NCR53c406a_host_reset(Scsi_Cmnd * SCpnt)
+{
+	DEB(printk("NCR53c406a_reset called\n"));
+	outb(C4_IMG, CONFIG4);	/* Select reg set 0 */
+	outb(CHIP_RESET, CMD_REG);
+	outb(SCSI_NOP, CMD_REG);	/* required after reset */
+	outb(SCSI_RESET, CMD_REG);
+	chip_init();
+
+	rtrc(2);
+	return SUCCESS;
+}
+
+static int NCR53c406a_device_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+
+static int NCR53c406a_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+
+static int NCR53c406a_biosparm(struct scsi_device *disk,
+                               struct block_device *dev,
+			       sector_t capacity, int *info_array)
+{
+	int size;
+
+	DEB(printk("NCR53c406a_biosparm called\n"));
+
+	size = capacity;
+	info_array[0] = 64;	/* heads */
+	info_array[1] = 32;	/* sectors */
+	info_array[2] = size >> 11;	/* cylinders */
+	if (info_array[2] > 1024) {	/* big disk */
+		info_array[0] = 255;
+		info_array[1] = 63;
+		info_array[2] = size / (255 * 63);
+	}
+	return 0;
+}
+
+static irqreturn_t do_NCR53c406a_intr(int unused, void *dev_id,
+					struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+	NCR53c406a_intr(0, dev_id, regs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void NCR53c406a_intr(int unused, void *dev_id, struct pt_regs *regs)
+{
+	DEB(unsigned char fifo_size;
+	    )
+	    DEB(unsigned char seq_reg;
+	    )
+	unsigned char status, int_reg;
+#if USE_PIO
+	unsigned char pio_status;
+	struct scatterlist *sglist;
+	unsigned int sgcount;
+#endif
+
+	VDEB(printk("NCR53c406a_intr called\n"));
+
+#if USE_PIO
+	REG1;
+	pio_status = inb(PIO_STATUS);
+#endif
+	REG0;
+	status = inb(STAT_REG);
+	DEB(seq_reg = inb(SEQ_REG));
+	int_reg = inb(INT_REG);
+	DEB(fifo_size = inb(FIFO_FLAGS) & 0x1f);
+
+#if NCR53C406A_DEBUG
+	printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", status, seq_reg, int_reg, fifo_size);
+#if (USE_DMA)
+	printk("\n");
+#else
+	printk(", pio=%02x\n", pio_status);
+#endif				/* USE_DMA */
+#endif				/* NCR53C406A_DEBUG */
+
+	if (int_reg & 0x80) {	/* SCSI reset intr */
+		rtrc(3);
+		DEB(printk("NCR53c406a: reset intr received\n"));
+		current_SC->SCp.phase = idle;
+		current_SC->result = DID_RESET << 16;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+#if USE_PIO
+	if (pio_status & 0x80) {
+		printk("NCR53C406A: Warning: PIO error!\n");
+		current_SC->SCp.phase = idle;
+		current_SC->result = DID_ERROR << 16;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+#endif				/* USE_PIO */
+
+	if (status & 0x20) {	/* Parity error */
+		printk("NCR53c406a: Warning: parity error!\n");
+		current_SC->SCp.phase = idle;
+		current_SC->result = DID_PARITY << 16;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+
+	if (status & 0x40) {	/* Gross error */
+		printk("NCR53c406a: Warning: gross error!\n");
+		current_SC->SCp.phase = idle;
+		current_SC->result = DID_ERROR << 16;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+
+	if (int_reg & 0x20) {	/* Disconnect */
+		DEB(printk("NCR53c406a: disconnect intr received\n"));
+		if (current_SC->SCp.phase != message_in) {	/* Unexpected disconnect */
+			current_SC->result = DID_NO_CONNECT << 16;
+		} else {	/* Command complete, return status and message */
+			current_SC->result = (current_SC->SCp.Status & 0xff)
+			    | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16);
+		}
+
+		rtrc(0);
+		current_SC->SCp.phase = idle;
+		current_SC->scsi_done(current_SC);
+		return;
+	}
+
+	switch (status & 0x07) {	/* scsi phase */
+	case 0x00:		/* DATA-OUT */
+		if (int_reg & 0x10) {	/* Target requesting info transfer */
+			rtrc(5);
+			current_SC->SCp.phase = data_out;
+			VDEB(printk("NCR53c406a: Data-Out phase\n"));
+			outb(FLUSH_FIFO, CMD_REG);
+			LOAD_DMA_COUNT(current_SC->request_bufflen);	/* Max transfer size */
+#if USE_DMA			/* No s/g support for DMA */
+			NCR53c406a_dma_write(current_SC->request_buffer, current_SC->request_bufflen);
+#endif				/* USE_DMA */
+			outb(TRANSFER_INFO | DMA_OP, CMD_REG);
+#if USE_PIO
+			if (!current_SC->use_sg)	/* Don't use scatter-gather */
+				NCR53c406a_pio_write(current_SC->request_buffer, current_SC->request_bufflen);
+			else {	/* use scatter-gather */
+				sgcount = current_SC->use_sg;
+				sglist = current_SC->request_buffer;
+				while (sgcount--) {
+					NCR53c406a_pio_write(page_address(sglist->page) + sglist->offset, sglist->length);
+					sglist++;
+				}
+			}
+			REG0;
+#endif				/* USE_PIO */
+		}
+		break;
+
+	case 0x01:		/* DATA-IN */
+		if (int_reg & 0x10) {	/* Target requesting info transfer */
+			rtrc(6);
+			current_SC->SCp.phase = data_in;
+			VDEB(printk("NCR53c406a: Data-In phase\n"));
+			outb(FLUSH_FIFO, CMD_REG);
+			LOAD_DMA_COUNT(current_SC->request_bufflen);	/* Max transfer size */
+#if USE_DMA			/* No s/g support for DMA */
+			NCR53c406a_dma_read(current_SC->request_buffer, current_SC->request_bufflen);
+#endif				/* USE_DMA */
+			outb(TRANSFER_INFO | DMA_OP, CMD_REG);
+#if USE_PIO
+			if (!current_SC->use_sg)	/* Don't use scatter-gather */
+				NCR53c406a_pio_read(current_SC->request_buffer, current_SC->request_bufflen);
+			else {	/* Use scatter-gather */
+				sgcount = current_SC->use_sg;
+				sglist = current_SC->request_buffer;
+				while (sgcount--) {
+					NCR53c406a_pio_read(page_address(sglist->page) + sglist->offset, sglist->length);
+					sglist++;
+				}
+			}
+			REG0;
+#endif				/* USE_PIO */
+		}
+		break;
+
+	case 0x02:		/* COMMAND */
+		current_SC->SCp.phase = command_ph;
+		printk("NCR53c406a: Warning: Unknown interrupt occurred in command phase!\n");
+		break;
+
+	case 0x03:		/* STATUS */
+		rtrc(7);
+		current_SC->SCp.phase = status_ph;
+		VDEB(printk("NCR53c406a: Status phase\n"));
+		outb(FLUSH_FIFO, CMD_REG);
+		outb(INIT_CMD_COMPLETE, CMD_REG);
+		break;
+
+	case 0x04:		/* Reserved */
+	case 0x05:		/* Reserved */
+		printk("NCR53c406a: WARNING: Reserved phase!!!\n");
+		break;
+
+	case 0x06:		/* MESSAGE-OUT */
+		DEB(printk("NCR53c406a: Message-Out phase\n"));
+		current_SC->SCp.phase = message_out;
+		outb(SET_ATN, CMD_REG);	/* Reject the message */
+		outb(MSG_ACCEPT, CMD_REG);
+		break;
+
+	case 0x07:		/* MESSAGE-IN */
+		rtrc(4);
+		VDEB(printk("NCR53c406a: Message-In phase\n"));
+		current_SC->SCp.phase = message_in;
+
+		current_SC->SCp.Status = inb(SCSI_FIFO);
+		current_SC->SCp.Message = inb(SCSI_FIFO);
+
+		VDEB(printk("SCSI FIFO size=%d\n", inb(FIFO_FLAGS) & 0x1f));
+		DEB(printk("Status = %02x  Message = %02x\n", current_SC->SCp.Status, current_SC->SCp.Message));
+
+		if (current_SC->SCp.Message == SAVE_POINTERS || current_SC->SCp.Message == DISCONNECT) {
+			outb(SET_ATN, CMD_REG);	/* Reject message */
+			DEB(printk("Discarding SAVE_POINTERS message\n"));
+		}
+		outb(MSG_ACCEPT, CMD_REG);
+		break;
+	}
+}
+
+#ifndef IRQ_LEV
+static int irq_probe(void)
+{
+	int irqs, irq;
+	unsigned long i;
+
+	inb(INT_REG);		/* clear the interrupt register */
+	irqs = probe_irq_on();
+
+	/* Invalid command will cause an interrupt */
+	REG0;
+	outb(0xff, CMD_REG);
+
+	/* Wait for the interrupt to occur */
+	i = jiffies + WATCHDOG;
+	while (time_after(i, jiffies) && !(inb(STAT_REG) & 0x80))
+		barrier();
+	if (time_before_eq(i, jiffies)) {	/* Timed out, must be hardware trouble */
+		probe_irq_off(irqs);
+		return -1;
+	}
+
+	irq = probe_irq_off(irqs);
+
+	/* Kick the chip */
+	outb(CHIP_RESET, CMD_REG);
+	outb(SCSI_NOP, CMD_REG);
+	chip_init();
+
+	return irq;
+}
+#endif				/* IRQ_LEV */
+
+static void chip_init(void)
+{
+	REG1;
+#if USE_DMA
+	outb(0x00, PIO_STATUS);
+#else				/* USE_PIO */
+	outb(0x01, PIO_STATUS);
+#endif
+	outb(0x00, PIO_FLAG);
+
+	outb(C4_IMG, CONFIG4);	/* REG0; */
+	outb(C3_IMG, CONFIG3);
+	outb(C2_IMG, CONFIG2);
+	outb(C1_IMG, CONFIG1);
+
+	outb(0x05, CLKCONV);	/* clock conversion factor */
+	outb(0x9C, SRTIMOUT);	/* Selection timeout */
+	outb(0x05, SYNCPRD);	/* Synchronous transfer period */
+	outb(SYNC_MODE, SYNCOFF);	/* synchronous mode */
+}
+
+static void __init calc_port_addr(void)
+{
+	/* Control Register Set 0 */
+	TC_LSB = (port_base + 0x00);
+	TC_MSB = (port_base + 0x01);
+	SCSI_FIFO = (port_base + 0x02);
+	CMD_REG = (port_base + 0x03);
+	STAT_REG = (port_base + 0x04);
+	DEST_ID = (port_base + 0x04);
+	INT_REG = (port_base + 0x05);
+	SRTIMOUT = (port_base + 0x05);
+	SEQ_REG = (port_base + 0x06);
+	SYNCPRD = (port_base + 0x06);
+	FIFO_FLAGS = (port_base + 0x07);
+	SYNCOFF = (port_base + 0x07);
+	CONFIG1 = (port_base + 0x08);
+	CLKCONV = (port_base + 0x09);
+	/* TESTREG          = (port_base+0x0A); */
+	CONFIG2 = (port_base + 0x0B);
+	CONFIG3 = (port_base + 0x0C);
+	CONFIG4 = (port_base + 0x0D);
+	TC_HIGH = (port_base + 0x0E);
+	/* FIFO_BOTTOM      = (port_base+0x0F); */
+
+	/* Control Register Set 1 */
+	/* JUMPER_SENSE     = (port_base+0x00); */
+	/* SRAM_PTR         = (port_base+0x01); */
+	/* SRAM_DATA        = (port_base+0x02); */
+	PIO_FIFO = (port_base + 0x04);
+	/* PIO_FIFO1        = (port_base+0x05); */
+	/* PIO_FIFO2        = (port_base+0x06); */
+	/* PIO_FIFO3        = (port_base+0x07); */
+	PIO_STATUS = (port_base + 0x08);
+	/* ATA_CMD          = (port_base+0x09); */
+	/* ATA_ERR          = (port_base+0x0A); */
+	PIO_FLAG = (port_base + 0x0B);
+	CONFIG5 = (port_base + 0x0D);
+	/* SIGNATURE        = (port_base+0x0E); */
+	/* CONFIG6          = (port_base+0x0F); */
+}
+
+MODULE_LICENSE("GPL");
+
+/* NOTE:  scatter-gather support only works in PIO mode.
+ * Use SG_NONE if DMA mode is enabled!
+ */
+
+static Scsi_Host_Template driver_template = 
+{
+     .proc_name         	= "NCR53c406a"		/* proc_name */,        
+     .name              	= "NCR53c406a"		/* name */,             
+     .detect            	= NCR53c406a_detect	/* detect */,           
+     .release            	= NCR53c406a_release,
+     .info              	= NCR53c406a_info		/* info */,             
+     .queuecommand      	= NCR53c406a_queue	/* queuecommand */,     
+     .eh_abort_handler  	= NCR53c406a_abort	/* abort */,            
+     .eh_bus_reset_handler      = NCR53c406a_bus_reset	/* reset */,            
+     .eh_device_reset_handler   = NCR53c406a_device_reset	/* reset */,            
+     .eh_host_reset_handler     = NCR53c406a_host_reset	/* reset */,            
+     .bios_param        	= NCR53c406a_biosparm	/* biosparm */,         
+     .can_queue         	= 1			/* can_queue */,        
+     .this_id           	= 7			/* SCSI ID of the chip */,
+     .sg_tablesize      	= 32			/*SG_ALL*/ /*SG_NONE*/, 
+     .cmd_per_lun       	= 1			/* commands per lun */, 
+     .unchecked_isa_dma 	= 1			/* unchecked_isa_dma */,
+     .use_clustering    	= ENABLE_CLUSTERING                               
+};
+
+#include "scsi_module.c"
+
+/*
+ * Overrides for Emacs so that we get a uniform tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
new file mode 100644
index 0000000..5077519
--- /dev/null
+++ b/drivers/scsi/NCR_D700.c
@@ -0,0 +1,406 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Dual 700 MCA SCSI Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/* Notes:
+ *
+ * Most of the work is done in the chip specific module, 53c700.o
+ *
+ * TODO List:
+ *
+ * 1. Extract the SCSI ID from the voyager CMOS table (necessary to
+ *    support multi-host environments.
+ *
+ * */
+
+
+/* CHANGELOG 
+ *
+ * Version 2.2
+ *
+ * Added mca_set_adapter_name().
+ *
+ * Version 2.1
+ *
+ * Modularise the driver into a Board piece (this file) and a chip
+ * piece 53c700.[ch] and 53c700.scr, added module options.  You can
+ * now specify the scsi id by the parameters
+ *
+ * NCR_D700=slot:<n> [siop:<n>] id:<n> ....
+ *
+ * They need to be comma separated if compiled into the kernel
+ *
+ * Version 2.0
+ *
+ * Initial implementation of TCQ (Tag Command Queueing).  TCQ is full
+ * featured and uses the clock algorithm to keep track of outstanding
+ * tags and guard against individual tag starvation.  Also fixed a bug
+ * in all of the 1.x versions where the D700_data_residue() function
+ * was returning results off by 32 bytes (and thus causing the same 32
+ * bytes to be written twice corrupting the data block).  It turns out
+ * the 53c700 only has a 6 bit DBC and DFIFO registers not 7 bit ones
+ * like the 53c710 (The 710 is the only data manual still available,
+ * which I'd been using to program the 700).
+ *
+ * Version 1.2
+ *
+ * Much improved message handling engine
+ *
+ * Version 1.1
+ *
+ * Add code to handle selection reasonably correctly.  By the time we
+ * get the selection interrupt, we've already responded, but drop off the
+ * bus and hope the selector will go away.
+ *
+ * Version 1.0:
+ *
+ *   Initial release.  Fully functional except for procfs and tag
+ * command queueing.  Has only been tested on cards with 53c700-66
+ * chips and only single ended. Features are
+ *
+ * 1. Synchronous data transfers to offset 8 (limit of 700-66) and
+ *    100ns (10MHz) limit of SCSI-2
+ *
+ * 2. Disconnection and reselection
+ *
+ * Testing:
+ * 
+ *  I've only really tested this with the 700-66 chip, but have done
+ * soak tests in multi-device environments to verify that
+ * disconnections and reselections are being processed correctly.
+ * */
+
+#define NCR_D700_VERSION "2.2"
+
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mca.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+#include "NCR_D700.h"
+
+static char *NCR_D700;		/* command line from insmod */
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("NCR Dual700 SCSI Driver");
+MODULE_LICENSE("GPL");
+module_param(NCR_D700, charp, 0);
+
+static __u8 __initdata id_array[2*(MCA_MAX_SLOT_NR + 1)] =
+	{ [0 ... 2*(MCA_MAX_SLOT_NR + 1)-1] = 7 };
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+static int __init
+param_setup(char *string)
+{
+	char *pos = string, *next;
+	int slot = -1, siop = -1;
+
+	while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
+		int val = (int)simple_strtoul(++next, NULL, 0);
+
+		if(!strncmp(pos, "slot:", 5))
+			slot = val;
+		else if(!strncmp(pos, "siop:", 5))
+			siop = val;
+		else if(!strncmp(pos, "id:", 3)) {
+			if(slot == -1) {
+				printk(KERN_WARNING "NCR D700: Must specify slot for id parameter\n");
+			} else if(slot > MCA_MAX_SLOT_NR) {
+				printk(KERN_WARNING "NCR D700: Illegal slot %d for id %d\n", slot, val);
+			} else {
+				if(siop != 0 && siop != 1) {
+					id_array[slot*2] = val;
+					id_array[slot*2 + 1] =val;
+				} else {
+					id_array[slot*2 + siop] = val;
+				}
+			}
+		}
+		if((pos = strchr(pos, ARG_SEP)) != NULL)
+			pos++;
+	}
+	return 1;
+}
+
+/* Host template.  The 53c700 routine NCR_700_detect will
+ * fill in all of the missing routines */
+static struct scsi_host_template NCR_D700_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "NCR Dual 700 MCA",
+	.proc_name		= "NCR_D700",
+	.this_id		= 7,
+};
+
+/* We needs this helper because we have two hosts per struct device */
+struct NCR_D700_private {
+	struct device		*dev;
+	struct Scsi_Host	*hosts[2];
+	char			name[30];
+	char			pad;
+};
+
+static int 
+NCR_D700_probe_one(struct NCR_D700_private *p, int siop, int irq,
+		   int slot, u32 region, int differential)
+{
+	struct NCR_700_Host_Parameters *hostdata;
+	struct Scsi_Host *host;
+	int ret;
+
+	hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+	if (!hostdata) {
+		printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
+		       "data, detatching\n", siop);
+		return -ENOMEM;
+	}
+	memset(hostdata, 0, sizeof(*hostdata));
+
+	if (!request_region(region, 64, "NCR_D700")) {
+		printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
+				region);
+		ret = -ENODEV;
+		goto region_failed;
+	}
+		
+	/* Fill in the three required pieces of hostdata */
+	hostdata->base = region;
+	hostdata->differential = (((1<<siop) & differential) != 0);
+	hostdata->clock = NCR_D700_CLOCK_MHZ;
+
+	NCR_700_set_io_mapped(hostdata);
+
+	/* and register the siop */
+	host = NCR_700_detect(&NCR_D700_driver_template, hostdata, p->dev);
+	if (!host) {
+		ret = -ENOMEM;
+		goto detect_failed;
+	}
+
+	p->hosts[siop] = host;
+	/* FIXME: read this from SUS */
+	host->this_id = id_array[slot * 2 + siop];
+	host->irq = irq;
+	scsi_scan_host(host);
+
+	return 0;
+
+ detect_failed:
+	release_region(host->base, 64);
+ region_failed:
+	kfree(hostdata);
+
+	return ret;
+}
+
+static int
+NCR_D700_intr(int irq, void *data, struct pt_regs *regs)
+{
+	struct NCR_D700_private *p = (struct NCR_D700_private *)data;
+	int i, found = 0;
+
+	for (i = 0; i < 2; i++)
+		if (p->hosts[i] &&
+		    NCR_700_intr(irq, p->hosts[i], regs) == IRQ_HANDLED)
+			found++;
+
+	return found ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/* Detect a D700 card.  Note, because of the setup --- the chips are
+ * essentially connectecd to the MCA bus independently, it is easier
+ * to set them up as two separate host adapters, rather than one
+ * adapter with two channels */
+static int
+NCR_D700_probe(struct device *dev)
+{
+	struct NCR_D700_private *p;
+	int differential;
+	static int banner = 1;
+	struct mca_device *mca_dev = to_mca_device(dev);
+	int slot = mca_dev->slot;
+	int found = 0;
+	int irq, i;
+	int pos3j, pos3k, pos3a, pos3b, pos4;
+	__u32 base_addr, offset_addr;
+
+	/* enable board interrupt */
+	pos4 = mca_device_read_pos(mca_dev, 4);
+	pos4 |= 0x4;
+	mca_device_write_pos(mca_dev, 4, pos4);
+
+	mca_device_write_pos(mca_dev, 6, 9);
+	pos3j = mca_device_read_pos(mca_dev, 3);
+	mca_device_write_pos(mca_dev, 6, 10);
+	pos3k = mca_device_read_pos(mca_dev, 3);
+	mca_device_write_pos(mca_dev, 6, 0);
+	pos3a = mca_device_read_pos(mca_dev, 3);
+	mca_device_write_pos(mca_dev, 6, 1);
+	pos3b = mca_device_read_pos(mca_dev, 3);
+
+	base_addr = ((pos3j << 8) | pos3k) & 0xfffffff0;
+	offset_addr = ((pos3a << 8) | pos3b) & 0xffffff70;
+
+	irq = (pos4 & 0x3) + 11;
+	if(irq >= 13)
+		irq++;
+	if(banner) {
+		printk(KERN_NOTICE "NCR D700: Driver Version " NCR_D700_VERSION "\n"
+		       "NCR D700:  Copyright (c) 2001 by James.Bottomley@HansenPartnership.com\n"
+		       "NCR D700:\n");
+		banner = 0;
+	}
+	/* now do the bus related transforms */
+	irq = mca_device_transform_irq(mca_dev, irq);
+	base_addr = mca_device_transform_ioport(mca_dev, base_addr);
+	offset_addr = mca_device_transform_ioport(mca_dev, offset_addr);
+
+	printk(KERN_NOTICE "NCR D700: found in slot %d  irq = %d  I/O base = 0x%x\n", slot, irq, offset_addr);
+
+	/*outb(BOARD_RESET, base_addr);*/
+
+	/* clear any pending interrupts */
+	(void)inb(base_addr + 0x08);
+	/* get modctl, used later for setting diff bits */
+	switch(differential = (inb(base_addr + 0x08) >> 6)) {
+	case 0x00:
+		/* only SIOP1 differential */
+		differential = 0x02;
+		break;
+	case 0x01:
+		/* Both SIOPs differential */
+		differential = 0x03;
+		break;
+	case 0x03:
+		/* No SIOPs differential */
+		differential = 0x00;
+		break;
+	default:
+		printk(KERN_ERR "D700: UNEXPECTED DIFFERENTIAL RESULT 0x%02x\n",
+		       differential);
+		differential = 0x00;
+		break;
+	}
+
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	memset(p, '\0', sizeof(*p));
+	p->dev = dev;
+	snprintf(p->name, sizeof(p->name), "D700(%s)", dev->bus_id);
+	if (request_irq(irq, NCR_D700_intr, SA_SHIRQ, p->name, p)) {
+		printk(KERN_ERR "D700: request_irq failed\n");
+		kfree(p);
+		return -EBUSY;
+	}
+	/* plumb in both 700 chips */
+	for (i = 0; i < 2; i++) {
+		int err;
+
+		if ((err = NCR_D700_probe_one(p, i, slot, irq,
+					      offset_addr + (0x80 * i),
+					      differential)) != 0)
+			printk("D700: SIOP%d: probe failed, error = %d\n",
+			       i, err);
+		else
+			found++;
+	}
+
+	if (!found) {
+		kfree(p);
+		return -ENODEV;
+	}
+
+	mca_device_set_claim(mca_dev, 1);
+	mca_device_set_name(mca_dev, "NCR_D700");
+	dev_set_drvdata(dev, p);
+	return 0;
+}
+
+static void
+NCR_D700_remove_one(struct Scsi_Host *host)
+{
+	scsi_remove_host(host);
+	NCR_700_release(host);
+	kfree((struct NCR_700_Host_Parameters *)host->hostdata[0]);
+	free_irq(host->irq, host);
+	release_region(host->base, 64);
+}
+
+static int
+NCR_D700_remove(struct device *dev)
+{
+	struct NCR_D700_private *p = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < 2; i++)
+		NCR_D700_remove_one(p->hosts[i]);
+
+	kfree(p);
+	return 0;
+}
+
+static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
+
+static struct mca_driver NCR_D700_driver = {
+	.id_table = NCR_D700_id_table,
+	.driver = {
+		.name		= "NCR_D700",
+		.bus		= &mca_bus_type,
+		.probe		= NCR_D700_probe,
+		.remove		= NCR_D700_remove,
+	},
+};
+
+static int __init NCR_D700_init(void)
+{
+#ifdef MODULE
+	if (NCR_D700)
+		param_setup(NCR_D700);
+#endif
+
+	return mca_register_driver(&NCR_D700_driver);
+}
+
+static void __exit NCR_D700_exit(void)
+{
+	mca_unregister_driver(&NCR_D700_driver);
+}
+
+module_init(NCR_D700_init);
+module_exit(NCR_D700_exit);
+
+__setup("NCR_D700=", param_setup);
diff --git a/drivers/scsi/NCR_D700.h b/drivers/scsi/NCR_D700.h
new file mode 100644
index 0000000..f167af6
--- /dev/null
+++ b/drivers/scsi/NCR_D700.h
@@ -0,0 +1,29 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Dual 700 MCA SCSI Driver
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+ */
+
+#ifndef _NCR_D700_H
+#define _NCR_D700_H
+
+/* Don't turn on debugging messages */
+#undef NCR_D700_DEBUG
+
+/* The MCA identifier */
+#define NCR_D700_MCA_ID		0x0092
+
+/* Defines for the Board registers */
+#define	BOARD_RESET		0x80	/* board level reset */
+#define ADD_PARENB		0x04	/* Address Parity Enabled */
+#define DAT_PARENB		0x01	/* Data Parity Enabled */
+#define SFBK_ENB		0x10	/* SFDBK Interrupt Enabled */
+#define LED0GREEN		0x20	/* Led 0 (red 0; green 1) */
+#define LED1GREEN		0x40	/* Led 1 (red 0; green 1) */
+#define LED0RED			0xDF	/* Led 0 (red 0; green 1) */
+#define LED1RED			0xBF	/* Led 1 (red 0; green 1) */
+
+#define NCR_D700_CLOCK_MHZ	50
+
+#endif
diff --git a/drivers/scsi/NCR_Q720.c b/drivers/scsi/NCR_Q720.c
new file mode 100644
index 0000000..9d18ec9
--- /dev/null
+++ b/drivers/scsi/NCR_Q720.c
@@ -0,0 +1,377 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Quad 720 MCA SCSI Driver
+ *
+ * Copyright (C) 2003 by James.Bottomley@HansenPartnership.com
+ */
+
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mca.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#include "ncr53c8xx.h"
+
+#include "NCR_Q720.h"
+
+static struct ncr_chip q720_chip __initdata = {
+	.revision_id =	0x0f,
+	.burst_max =	3,
+	.offset_max =	8,
+	.nr_divisor =	4,
+	.features =	FE_WIDE | FE_DIFF | FE_VARCLK,
+};
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("NCR Quad 720 SCSI Driver");
+MODULE_LICENSE("GPL");
+
+#define NCR_Q720_VERSION		"0.9"
+
+/* We needs this helper because we have up to four hosts per struct device */
+struct NCR_Q720_private {
+	struct device		*dev;
+	void __iomem *		mem_base;
+	__u32			phys_mem_base;
+	__u32			mem_size;
+	__u8			irq;
+	__u8			siops;
+	__u8			irq_enable;
+	struct Scsi_Host	*hosts[4];
+};
+
+static struct scsi_host_template NCR_Q720_tpnt = {
+	.module			= THIS_MODULE,
+	.proc_name		= "NCR_Q720",
+};
+
+static irqreturn_t
+NCR_Q720_intr(int irq, void *data, struct pt_regs * regs)
+{
+	struct NCR_Q720_private *p = (struct NCR_Q720_private *)data;
+	__u8 sir = (readb(p->mem_base + 0x0d) & 0xf0) >> 4;
+	__u8 siop;
+
+	sir |= ~p->irq_enable;
+
+	if(sir == 0xff)
+		return IRQ_NONE;
+
+
+	while((siop = ffz(sir)) < p->siops) {
+		sir |= 1<<siop;
+		ncr53c8xx_intr(irq, p->hosts[siop], regs);
+	}
+	return IRQ_HANDLED;
+}
+
+static int __init
+NCR_Q720_probe_one(struct NCR_Q720_private *p, int siop,
+		int irq, int slot, __u32 paddr, void __iomem *vaddr)
+{
+	struct ncr_device device;
+	__u8 scsi_id;
+	static int unit = 0;
+	__u8 scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1);
+	__u8 differential = readb(vaddr + NCR_Q720_SCSR_OFFSET) & 0x20;
+	__u8 version;
+	int error;
+
+	scsi_id = scsr1 >> 4;
+	/* enable burst length 16 (FIXME: should allow this) */
+	scsr1 |= 0x02;
+	/* force a siop reset */
+	scsr1 |= 0x04;
+	writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1);
+	udelay(10);
+	version = readb(vaddr + 0x18) >> 4;
+
+	memset(&device, 0, sizeof(struct ncr_device));
+		/* Initialise ncr_device structure with items required by ncr_attach. */
+	device.chip		= q720_chip;
+	device.chip.revision_id	= version;
+	device.host_id		= scsi_id;
+	device.dev		= p->dev;
+	device.slot.base	= paddr;
+	device.slot.base_c	= paddr;
+	device.slot.base_v	= vaddr;
+	device.slot.irq		= irq;
+	device.differential	= differential ? 2 : 0;
+	printk("Q720 probe unit %d (siop%d) at 0x%lx, diff = %d, vers = %d\n", unit, siop,
+	       (unsigned long)paddr, differential, version);
+
+	p->hosts[siop] = ncr_attach(&NCR_Q720_tpnt, unit++, &device);
+	
+	if (!p->hosts[siop]) 
+		goto fail;
+
+	p->irq_enable |= (1<<siop);
+	scsr1 = readb(vaddr + NCR_Q720_SCSR_OFFSET + 1);
+	/* clear the disable interrupt bit */
+	scsr1 &= ~0x01;
+	writeb(scsr1, vaddr + NCR_Q720_SCSR_OFFSET + 1);
+
+	error = scsi_add_host(p->hosts[siop], p->dev);
+	if (error)
+		ncr53c8xx_release(p->hosts[siop]);
+	else
+		scsi_scan_host(p->hosts[siop]);
+	return error;
+
+ fail:
+	return -ENODEV;
+}
+
+/* Detect a Q720 card.  Note, because of the setup --- the chips are
+ * essentially connectecd to the MCA bus independently, it is easier
+ * to set them up as two separate host adapters, rather than one
+ * adapter with two channels */
+static int __init
+NCR_Q720_probe(struct device *dev)
+{
+	struct NCR_Q720_private *p;
+	static int banner = 1;
+	struct mca_device *mca_dev = to_mca_device(dev);
+	int slot = mca_dev->slot;
+	int found = 0;
+	int irq, i, siops;
+	__u8 pos2, pos4, asr2, asr9, asr10;
+	__u16 io_base;
+	__u32 base_addr, mem_size;
+	void __iomem *mem_base;
+
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+
+	memset(p, 0, sizeof(*p));
+	pos2 = mca_device_read_pos(mca_dev, 2);
+	/* enable device */
+	pos2 |=  NCR_Q720_POS2_BOARD_ENABLE | NCR_Q720_POS2_INTERRUPT_ENABLE;
+	mca_device_write_pos(mca_dev, 2, pos2);
+
+	io_base = (pos2 & NCR_Q720_POS2_IO_MASK) << NCR_Q720_POS2_IO_SHIFT;
+
+
+	if(banner) {
+		printk(KERN_NOTICE "NCR Q720: Driver Version " NCR_Q720_VERSION "\n"
+		       "NCR Q720:  Copyright (c) 2003 by James.Bottomley@HansenPartnership.com\n"
+		       "NCR Q720:\n");
+		banner = 0;
+	}
+	io_base = mca_device_transform_ioport(mca_dev, io_base);
+
+	/* OK, this is phase one of the bootstrap, we now know the
+	 * I/O space base address.  All the configuration registers
+	 * are mapped here (including pos) */
+
+	/* sanity check I/O mapping */
+	i = inb(io_base) | (inb(io_base+1)<<8);
+	if(i != NCR_Q720_MCA_ID) {
+		printk(KERN_ERR "NCR_Q720, adapter failed to I/O map registers correctly at 0x%x(0x%x)\n", io_base, i);
+		kfree(p);
+		return -ENODEV;
+	}
+
+	/* Phase II, find the ram base and memory map the board register */
+	pos4 = inb(io_base + 4);
+	/* enable streaming data */
+	pos4 |= 0x01;
+	outb(pos4, io_base + 4);
+	base_addr = (pos4 & 0x7e) << 20;
+	base_addr += (pos4 & 0x80) << 23;
+	asr10 = inb(io_base + 0x12);
+	base_addr += (asr10 & 0x80) << 24;
+	base_addr += (asr10 & 0x70) << 23;
+
+	/* OK, got the base addr, now we need to find the ram size,
+	 * enable and map it */
+	asr9 = inb(io_base + 0x11);
+	i = (asr9 & 0xc0) >> 6;
+	if(i == 0)
+		mem_size = 1024;
+	else
+		mem_size = 1 << (19 + i);
+
+	/* enable the sram mapping */
+	asr9 |= 0x20;
+
+	/* disable the rom mapping */
+	asr9 &= ~0x10;
+
+	outb(asr9, io_base + 0x11);
+
+	if(!request_mem_region(base_addr, mem_size, "NCR_Q720")) {
+		printk(KERN_ERR "NCR_Q720: Failed to claim memory region 0x%lx\n-0x%lx",
+		       (unsigned long)base_addr,
+		       (unsigned long)(base_addr + mem_size));
+		goto out_free;
+	}
+	
+	if (dma_declare_coherent_memory(dev, base_addr, base_addr,
+					mem_size, DMA_MEMORY_MAP)
+	    != DMA_MEMORY_MAP) {
+		printk(KERN_ERR "NCR_Q720: DMA declare memory failed\n");
+		goto out_release_region;
+	}
+
+	/* The first 1k of the memory buffer is a memory map of the registers
+	 */
+	mem_base = dma_mark_declared_memory_occupied(dev, base_addr,
+							    1024);
+	if (IS_ERR(mem_base)) {
+		printk("NCR_Q720 failed to reserve memory mapped region\n");
+		goto out_release;
+	}
+
+	/* now also enable accesses in asr 2 */
+	asr2 = inb(io_base + 0x0a);
+
+	asr2 |= 0x01;
+
+	outb(asr2, io_base + 0x0a);
+
+	/* get the number of SIOPs (this should be 2 or 4) */
+	siops = ((asr2 & 0xe0) >> 5) + 1;
+
+	/* sanity check mapping (again) */
+	i = readw(mem_base);
+	if(i != NCR_Q720_MCA_ID) {
+		printk(KERN_ERR "NCR_Q720, adapter failed to memory map registers correctly at 0x%lx(0x%x)\n", (unsigned long)base_addr, i);
+		goto out_release;
+	}
+
+	irq = readb(mem_base + 5) & 0x0f;
+	
+	
+	/* now do the bus related transforms */
+	irq = mca_device_transform_irq(mca_dev, irq);
+
+	printk(KERN_NOTICE "NCR Q720: found in slot %d  irq = %d  mem base = 0x%lx siops = %d\n", slot, irq, (unsigned long)base_addr, siops);
+	printk(KERN_NOTICE "NCR Q720: On board ram %dk\n", mem_size/1024);
+
+	p->dev = dev;
+	p->mem_base = mem_base;
+	p->phys_mem_base = base_addr;
+	p->mem_size = mem_size;
+	p->irq = irq;
+	p->siops = siops;
+
+	if (request_irq(irq, NCR_Q720_intr, SA_SHIRQ, "NCR_Q720", p)) {
+		printk(KERN_ERR "NCR_Q720: request irq %d failed\n", irq);
+		goto out_release;
+	}
+	/* disable all the siop interrupts */
+	for(i = 0; i < siops; i++) {
+		void __iomem *reg_scsr1 = mem_base + NCR_Q720_CHIP_REGISTER_OFFSET
+			+ i*NCR_Q720_SIOP_SHIFT + NCR_Q720_SCSR_OFFSET + 1;
+		__u8 scsr1 = readb(reg_scsr1);
+		scsr1 |= 0x01;
+		writeb(scsr1, reg_scsr1);
+	}
+
+	/* plumb in all 720 chips */
+	for (i = 0; i < siops; i++) {
+		void __iomem *siop_v_base = mem_base + NCR_Q720_CHIP_REGISTER_OFFSET
+			+ i*NCR_Q720_SIOP_SHIFT;
+		__u32 siop_p_base = base_addr + NCR_Q720_CHIP_REGISTER_OFFSET
+			+ i*NCR_Q720_SIOP_SHIFT;
+		__u16 port = io_base + NCR_Q720_CHIP_REGISTER_OFFSET
+			+ i*NCR_Q720_SIOP_SHIFT;
+		int err;
+
+		outb(0xff, port + 0x40);
+		outb(0x07, port + 0x41);
+		if ((err = NCR_Q720_probe_one(p, i, irq, slot,
+					      siop_p_base, siop_v_base)) != 0)
+			printk("Q720: SIOP%d: probe failed, error = %d\n",
+			       i, err);
+		else
+			found++;
+	}
+
+	if (!found) {
+		kfree(p);
+		return -ENODEV;
+	}
+
+	mca_device_set_claim(mca_dev, 1);
+	mca_device_set_name(mca_dev, "NCR_Q720");
+	dev_set_drvdata(dev, p);
+
+	return 0;
+
+ out_release:
+	dma_release_declared_memory(dev);
+ out_release_region:
+	release_mem_region(base_addr, mem_size);
+ out_free:
+	kfree(p);
+
+	return -ENODEV;
+}
+
+static void __exit
+NCR_Q720_remove_one(struct Scsi_Host *host)
+{
+	scsi_remove_host(host);
+	ncr53c8xx_release(host);
+}
+
+static int __exit
+NCR_Q720_remove(struct device *dev)
+{
+	struct NCR_Q720_private *p = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < p->siops; i++)
+		if(p->hosts[i])
+			NCR_Q720_remove_one(p->hosts[i]);
+
+	dma_release_declared_memory(dev);
+	release_mem_region(p->phys_mem_base, p->mem_size);
+	free_irq(p->irq, p);
+	kfree(p);
+	return 0;
+}
+
+static short NCR_Q720_id_table[] = { NCR_Q720_MCA_ID, 0 };
+
+static struct mca_driver NCR_Q720_driver = {
+	.id_table = NCR_Q720_id_table,
+	.driver = {
+		.name		= "NCR_Q720",
+		.bus		= &mca_bus_type,
+		.probe		= NCR_Q720_probe,
+		.remove		= __devexit_p(NCR_Q720_remove),
+	},
+};
+
+static int __init
+NCR_Q720_init(void)
+{
+	int ret = ncr53c8xx_init();
+	if (!ret)
+		ret = mca_register_driver(&NCR_Q720_driver);
+	if (ret)
+		ncr53c8xx_exit();
+	return ret;
+}
+
+static void __exit
+NCR_Q720_exit(void)
+{
+	mca_unregister_driver(&NCR_Q720_driver);
+	ncr53c8xx_exit();
+}
+
+module_init(NCR_Q720_init);
+module_exit(NCR_Q720_exit);
diff --git a/drivers/scsi/NCR_Q720.h b/drivers/scsi/NCR_Q720.h
new file mode 100644
index 0000000..7b92090
--- /dev/null
+++ b/drivers/scsi/NCR_Q720.h
@@ -0,0 +1,28 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* NCR Quad 720 MCA SCSI Driver
+ *
+ * Copyright (C) 2003 by James.Bottomley@HansenPartnership.com
+ */
+
+#ifndef _NCR_Q720_H
+#define _NCR_Q720_H
+
+/* The MCA identifier */
+#define NCR_Q720_MCA_ID		0x0720
+
+#define NCR_Q720_CLOCK_MHZ	30
+
+#define NCR_Q720_POS2_BOARD_ENABLE	0x01
+#define NCR_Q720_POS2_INTERRUPT_ENABLE	0x02
+#define NCR_Q720_POS2_PARITY_DISABLE	0x04
+#define NCR_Q720_POS2_IO_MASK		0xf8
+#define NCR_Q720_POS2_IO_SHIFT		8
+
+#define NCR_Q720_CHIP_REGISTER_OFFSET	0x200
+#define NCR_Q720_SCSR_OFFSET		0x070
+#define NCR_Q720_SIOP_SHIFT		0x080
+
+#endif
+
+
diff --git a/drivers/scsi/a100u2w.c b/drivers/scsi/a100u2w.c
new file mode 100644
index 0000000..c34403c
--- /dev/null
+++ b/drivers/scsi/a100u2w.c
@@ -0,0 +1,1202 @@
+/*
+ * Initio A100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 2003-2004 Christoph Hellwig
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Revision History:
+ * 07/02/98 hl	- v.91n Initial drivers.
+ * 09/14/98 hl - v1.01 Support new Kernel.
+ * 09/22/98 hl - v1.01a Support reset.
+ * 09/24/98 hl - v1.01b Fixed reset.
+ * 10/05/98 hl - v1.02 split the source code and release.
+ * 12/19/98 bv - v1.02a Use spinlocks for 2.1.95 and up
+ * 01/31/99 bv - v1.02b Use mdelay instead of waitForPause
+ * 08/08/99 bv - v1.02c Use waitForPause again.
+ * 06/25/02 Doug Ledford <dledford@redhat.com> - v1.02d
+ *          - Remove limit on number of controllers
+ *          - Port to DMA mapping API
+ *          - Clean up interrupt handler registration
+ *          - Fix memory leaks
+ *          - Fix allocation of scsi host structs and private data
+ * 11/18/03 Christoph Hellwig <hch@lst.de>
+ *	    - Port to new probing API
+ *	    - Fix some more leaks in init failure cases
+ * 9/28/04 Christoph Hellwig <hch@lst.de>
+ *	    - merge the two source files
+ *	    - remove internal queueing code
+ */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "a100u2w.h"
+
+
+#define JIFFIES_TO_MS(t) ((t) * 1000 / HZ)
+#define MS_TO_JIFFIES(j) ((j * HZ) / 1000)
+
+static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp);
+static void inia100SCBPost(BYTE * pHcb, BYTE * pScb);
+
+static NVRAM nvram, *nvramp = &nvram;
+static UCHAR dftNvRam[64] =
+{
+/*----------header -------------*/
+	0x01,			/* 0x00: Sub System Vendor ID 0 */
+	0x11,			/* 0x01: Sub System Vendor ID 1 */
+	0x60,			/* 0x02: Sub System ID 0        */
+	0x10,			/* 0x03: Sub System ID 1        */
+	0x00,			/* 0x04: SubClass               */
+	0x01,			/* 0x05: Vendor ID 0            */
+	0x11,			/* 0x06: Vendor ID 1            */
+	0x60,			/* 0x07: Device ID 0            */
+	0x10,			/* 0x08: Device ID 1            */
+	0x00,			/* 0x09: Reserved               */
+	0x00,			/* 0x0A: Reserved               */
+	0x01,			/* 0x0B: Revision of Data Structure     */
+				/* -- Host Adapter Structure --- */
+	0x01,			/* 0x0C: Number Of SCSI Channel */
+	0x01,			/* 0x0D: BIOS Configuration 1   */
+	0x00,			/* 0x0E: BIOS Configuration 2   */
+	0x00,			/* 0x0F: BIOS Configuration 3   */
+				/* --- SCSI Channel 0 Configuration --- */
+	0x07,			/* 0x10: H/A ID                 */
+	0x83,			/* 0x11: Channel Configuration  */
+	0x20,			/* 0x12: MAX TAG per target     */
+	0x0A,			/* 0x13: SCSI Reset Recovering time     */
+	0x00,			/* 0x14: Channel Configuration4 */
+	0x00,			/* 0x15: Channel Configuration5 */
+				/* SCSI Channel 0 Target Configuration  */
+				/* 0x16-0x25                    */
+	0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+	0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+				/* --- SCSI Channel 1 Configuration --- */
+	0x07,			/* 0x26: H/A ID                 */
+	0x83,			/* 0x27: Channel Configuration  */
+	0x20,			/* 0x28: MAX TAG per target     */
+	0x0A,			/* 0x29: SCSI Reset Recovering time     */
+	0x00,			/* 0x2A: Channel Configuration4 */
+	0x00,			/* 0x2B: Channel Configuration5 */
+				/* SCSI Channel 1 Target Configuration  */
+				/* 0x2C-0x3B                    */
+	0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+	0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8, 0xC8,
+	0x00,			/* 0x3C: Reserved               */
+	0x00,			/* 0x3D: Reserved               */
+	0x00,			/* 0x3E: Reserved               */
+	0x00			/* 0x3F: Checksum               */
+};
+
+
+/***************************************************************************/
+static void waitForPause(unsigned amount)
+{
+	ULONG the_time = jiffies + MS_TO_JIFFIES(amount);
+	while (time_before_eq(jiffies, the_time))
+		cpu_relax();
+}
+
+/***************************************************************************/
+static UCHAR waitChipReady(ORC_HCS * hcsp)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
+		if (ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HOSTSTOP)	/* Wait HOSTSTOP set */
+			return 1;
+		waitForPause(100);	/* wait 100ms before try again  */
+	}
+	return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitFWReady(ORC_HCS * hcsp)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
+		if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY)		/* Wait READY set */
+			return 1;
+		waitForPause(100);	/* wait 100ms before try again  */
+	}
+	return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitSCSIRSTdone(ORC_HCS * hcsp)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
+		if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & SCSIRST))	/* Wait SCSIRST done */
+			return 1;
+		waitForPause(100);	/* wait 100ms before try again  */
+	}
+	return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitHDOoff(ORC_HCS * hcsp)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
+		if (!(ORC_RD(hcsp->HCS_Base, ORC_HCTRL) & HDO))		/* Wait HDO off */
+			return 1;
+		waitForPause(100);	/* wait 100ms before try again  */
+	}
+	return 0;
+}
+
+/***************************************************************************/
+static UCHAR waitHDIset(ORC_HCS * hcsp, UCHAR * pData)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {	/* Wait 1 second for report timeout     */
+		if ((*pData = ORC_RD(hcsp->HCS_Base, ORC_HSTUS)) & HDI)
+			return 1;	/* Wait HDI set */
+		waitForPause(100);	/* wait 100ms before try again  */
+	}
+	return 0;
+}
+
+/***************************************************************************/
+static unsigned short get_FW_version(ORC_HCS * hcsp)
+{
+	UCHAR bData;
+	union {
+		unsigned short sVersion;
+		unsigned char cVersion[2];
+	} Version;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_VERSION);
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	if (waitHDIset(hcsp, &bData) == 0)	/* Wait HDI set   */
+		return 0;
+	Version.cVersion[0] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+	ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);	/* Clear HDI            */
+
+	if (waitHDIset(hcsp, &bData) == 0)	/* Wait HDI set   */
+		return 0;
+	Version.cVersion[1] = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+	ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);	/* Clear HDI            */
+
+	return (Version.sVersion);
+}
+
+/***************************************************************************/
+static UCHAR set_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char value)
+{
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_SET_NVM);	/* Write command */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);	/* Write address */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, value);	/* Write value  */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	return 1;
+}
+
+/***************************************************************************/
+static UCHAR get_NVRAM(ORC_HCS * hcsp, unsigned char address, unsigned char *pDataIn)
+{
+	unsigned char bData;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_GET_NVM);	/* Write command */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, address);	/* Write address */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	if (waitHDIset(hcsp, &bData) == 0)	/* Wait HDI set   */
+		return 0;
+	*pDataIn = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+	ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);	/* Clear HDI    */
+
+	return 1;
+}
+
+/***************************************************************************/
+static void orc_exec_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+{
+	scbp->SCB_Status = ORCSCB_POST;
+	ORC_WR(hcsp->HCS_Base + ORC_PQUEUE, scbp->SCB_ScbIdx);
+	return;
+}
+
+
+/***********************************************************************
+ Read SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+static int se2_rd_all(ORC_HCS * hcsp)
+{
+	int i;
+	UCHAR *np, chksum = 0;
+
+	np = (UCHAR *) nvramp;
+	for (i = 0; i < 64; i++, np++) {	/* <01> */
+		if (get_NVRAM(hcsp, (unsigned char) i, np) == 0)
+			return -1;
+//      *np++ = get_NVRAM(hcsp, (unsigned char ) i);
+	}
+
+/*------ Is ckecksum ok ? ------*/
+	np = (UCHAR *) nvramp;
+	for (i = 0; i < 63; i++)
+		chksum += *np++;
+
+	if (nvramp->CheckSum != (UCHAR) chksum)
+		return -1;
+	return 1;
+}
+
+/************************************************************************
+ Update SCSI H/A configuration parameters from serial EEPROM
+*************************************************************************/
+static void se2_update_all(ORC_HCS * hcsp)
+{				/* setup default pattern  */
+	int i;
+	UCHAR *np, *np1, chksum = 0;
+
+	/* Calculate checksum first   */
+	np = (UCHAR *) dftNvRam;
+	for (i = 0; i < 63; i++)
+		chksum += *np++;
+	*np = chksum;
+
+	np = (UCHAR *) dftNvRam;
+	np1 = (UCHAR *) nvramp;
+	for (i = 0; i < 64; i++, np++, np1++) {
+		if (*np != *np1) {
+			set_NVRAM(hcsp, (unsigned char) i, *np);
+		}
+	}
+	return;
+}
+
+/*************************************************************************
+ Function name  : read_eeprom
+**************************************************************************/
+static void read_eeprom(ORC_HCS * hcsp)
+{
+	if (se2_rd_all(hcsp) != 1) {
+		se2_update_all(hcsp);	/* setup default pattern        */
+		se2_rd_all(hcsp);	/* load again                   */
+	}
+}
+
+
+/***************************************************************************/
+static UCHAR load_FW(ORC_HCS * hcsp)
+{
+	U32 dData;
+	USHORT wBIOSAddress;
+	USHORT i;
+	UCHAR *pData, bData;
+
+
+	bData = ORC_RD(hcsp->HCS_Base, ORC_GCFG);
+	ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData | EEPRG);	/* Enable EEPROM programming */
+	ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, 0x00);
+	ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x00);
+	if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0x55) {
+		ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);	/* Disable EEPROM programming */
+		return 0;
+	}
+	ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x01);
+	if (ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA) != 0xAA) {
+		ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);	/* Disable EEPROM programming */
+		return 0;
+	}
+	ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);	/* Enable SRAM programming */
+	pData = (UCHAR *) & dData;
+	dData = 0;		/* Initial FW address to 0 */
+	ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x10);
+	*pData = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);		/* Read from BIOS */
+	ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x11);
+	*(pData + 1) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);	/* Read from BIOS */
+	ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, 0x12);
+	*(pData + 2) = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);	/* Read from BIOS */
+	ORC_WR(hcsp->HCS_Base + ORC_EBIOSADR2, *(pData + 2));
+	ORC_WRLONG(hcsp->HCS_Base + ORC_FWBASEADR, dData);	/* Write FW address */
+
+	wBIOSAddress = (USHORT) dData;	/* FW code locate at BIOS address + ? */
+	for (i = 0, pData = (UCHAR *) & dData;	/* Download the code    */
+	     i < 0x1000;	/* Firmware code size = 4K      */
+	     i++, wBIOSAddress++) {
+		ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
+		*pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);	/* Read from BIOS */
+		if ((i % 4) == 3) {
+			ORC_WRLONG(hcsp->HCS_Base + ORC_RISCRAM, dData);	/* Write every 4 bytes */
+			pData = (UCHAR *) & dData;
+		}
+	}
+
+	ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST | DOWNLOAD);	/* Reset program count 0 */
+	wBIOSAddress -= 0x1000;	/* Reset the BIOS adddress      */
+	for (i = 0, pData = (UCHAR *) & dData;	/* Check the code       */
+	     i < 0x1000;	/* Firmware code size = 4K      */
+	     i++, wBIOSAddress++) {
+		ORC_WRSHORT(hcsp->HCS_Base + ORC_EBIOSADR0, wBIOSAddress);
+		*pData++ = ORC_RD(hcsp->HCS_Base, ORC_EBIOSDATA);	/* Read from BIOS */
+		if ((i % 4) == 3) {
+			if (ORC_RDLONG(hcsp->HCS_Base, ORC_RISCRAM) != dData) {
+				ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);	/* Reset program to 0 */
+				ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);	/*Disable EEPROM programming */
+				return 0;
+			}
+			pData = (UCHAR *) & dData;
+		}
+	}
+	ORC_WR(hcsp->HCS_Base + ORC_RISCCTL, PRGMRST);	/* Reset program to 0   */
+	ORC_WR(hcsp->HCS_Base + ORC_GCFG, bData);	/* Disable EEPROM programming */
+	return 1;
+}
+
+/***************************************************************************/
+static void setup_SCBs(ORC_HCS * hcsp)
+{
+	ORC_SCB *pVirScb;
+	int i;
+	ESCB *pVirEscb;
+	dma_addr_t pPhysEscb;
+
+	/* Setup SCB HCS_Base and SCB Size registers */
+	ORC_WR(hcsp->HCS_Base + ORC_SCBSIZE, ORC_MAXQUEUE);	/* Total number of SCBs */
+	/* SCB HCS_Base address 0      */
+	ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE0, hcsp->HCS_physScbArray);
+	/* SCB HCS_Base address 1      */
+	ORC_WRLONG(hcsp->HCS_Base + ORC_SCBBASE1, hcsp->HCS_physScbArray);
+
+	/* setup scatter list address with one buffer */
+	pVirScb = hcsp->HCS_virScbArray;
+	pVirEscb = hcsp->HCS_virEscbArray;
+
+	for (i = 0; i < ORC_MAXQUEUE; i++) {
+		pPhysEscb = (hcsp->HCS_physEscbArray + (sizeof(ESCB) * i));
+		pVirScb->SCB_SGPAddr = (U32) pPhysEscb;
+		pVirScb->SCB_SensePAddr = (U32) pPhysEscb;
+		pVirScb->SCB_EScb = pVirEscb;
+		pVirScb->SCB_ScbIdx = i;
+		pVirScb++;
+		pVirEscb++;
+	}
+
+	return;
+}
+
+/***************************************************************************/
+static void initAFlag(ORC_HCS * hcsp)
+{
+	UCHAR i, j;
+
+	for (i = 0; i < MAX_CHANNELS; i++) {
+		for (j = 0; j < 8; j++) {
+			hcsp->BitAllocFlag[i][j] = 0xffffffff;
+		}
+	}
+}
+
+/***************************************************************************/
+static int init_orchid(ORC_HCS * hcsp)
+{
+	UBYTE *readBytep;
+	USHORT revision;
+	UCHAR i;
+
+	initAFlag(hcsp);
+	ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFF);	/* Disable all interrupt        */
+	if (ORC_RD(hcsp->HCS_Base, ORC_HSTUS) & RREADY) {	/* Orchid is ready              */
+		revision = get_FW_version(hcsp);
+		if (revision == 0xFFFF) {
+			ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);	/* Reset Host Adapter   */
+			if (waitChipReady(hcsp) == 0)
+				return (-1);
+			load_FW(hcsp);	/* Download FW                  */
+			setup_SCBs(hcsp);	/* Setup SCB HCS_Base and SCB Size registers */
+			ORC_WR(hcsp->HCS_Base + ORC_HCTRL, 0);	/* clear HOSTSTOP       */
+			if (waitFWReady(hcsp) == 0)
+				return (-1);
+			/* Wait for firmware ready     */
+		} else {
+			setup_SCBs(hcsp);	/* Setup SCB HCS_Base and SCB Size registers */
+		}
+	} else {		/* Orchid is not Ready          */
+		ORC_WR(hcsp->HCS_Base + ORC_HCTRL, DEVRST);	/* Reset Host Adapter   */
+		if (waitChipReady(hcsp) == 0)
+			return (-1);
+		load_FW(hcsp);	/* Download FW                  */
+		setup_SCBs(hcsp);	/* Setup SCB HCS_Base and SCB Size registers */
+		ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);	/* Do Hardware Reset &  */
+
+		/*     clear HOSTSTOP  */
+		if (waitFWReady(hcsp) == 0)		/* Wait for firmware ready      */
+			return (-1);
+	}
+
+/*------------- get serial EEProm settting -------*/
+
+	read_eeprom(hcsp);
+
+	if (nvramp->Revision != 1)
+		return (-1);
+
+	hcsp->HCS_SCSI_ID = nvramp->SCSI0Id;
+	hcsp->HCS_BIOS = nvramp->BIOSConfig1;
+	hcsp->HCS_MaxTar = MAX_TARGETS;
+	readBytep = (UCHAR *) & (nvramp->Target00Config);
+	for (i = 0; i < 16; readBytep++, i++) {
+		hcsp->TargetFlag[i] = *readBytep;
+		hcsp->MaximumTags[i] = ORC_MAXTAGS;
+	}			/* for                          */
+
+	if (nvramp->SCSI0Config & NCC_BUSRESET) {	/* Reset SCSI bus               */
+		hcsp->HCS_Flags |= HCF_SCSI_RESET;
+	}
+	ORC_WR(hcsp->HCS_Base + ORC_GIMSK, 0xFB);	/* enable RP FIFO interrupt     */
+	return (0);
+}
+
+/*****************************************************************************
+ Function name  : orc_reset_scsi_bus
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_reset_scsi_bus(ORC_HCS * pHCB)
+{				/* I need Host Control Block Information */
+	ULONG flags;
+
+	spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+
+	initAFlag(pHCB);
+	/* reset scsi bus */
+	ORC_WR(pHCB->HCS_Base + ORC_HCTRL, SCSIRST);
+	if (waitSCSIRSTdone(pHCB) == 0) {
+		spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+		return FAILED;
+	} else {
+		spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+		return SUCCESS;
+	}
+}
+
+/*****************************************************************************
+ Function name  : orc_device_reset
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_device_reset(ORC_HCS * pHCB, struct scsi_cmnd *SCpnt, unsigned int target)
+{				/* I need Host Control Block Information */
+	ORC_SCB *pScb;
+	ESCB *pVirEscb;
+	ORC_SCB *pVirScb;
+	UCHAR i;
+	ULONG flags;
+
+	spin_lock_irqsave(&(pHCB->BitAllocFlagLock), flags);
+	pScb = (ORC_SCB *) NULL;
+	pVirEscb = (ESCB *) NULL;
+
+	/* setup scatter list address with one buffer */
+	pVirScb = pHCB->HCS_virScbArray;
+
+	initAFlag(pHCB);
+	/* device reset */
+	for (i = 0; i < ORC_MAXQUEUE; i++) {
+		pVirEscb = pVirScb->SCB_EScb;
+		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt))
+			break;
+		pVirScb++;
+	}
+
+	if (i == ORC_MAXQUEUE) {
+		printk("Unable to Reset - No SCB Found\n");
+		spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+		return FAILED;
+	}
+	if ((pScb = orc_alloc_scb(pHCB)) == NULL) {
+		spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+		return FAILED;
+	}
+	pScb->SCB_Opcode = ORC_BUSDEVRST;
+	pScb->SCB_Target = target;
+	pScb->SCB_HaStat = 0;
+	pScb->SCB_TaStat = 0;
+	pScb->SCB_Status = 0x0;
+	pScb->SCB_Link = 0xFF;
+	pScb->SCB_Reserved0 = 0;
+	pScb->SCB_Reserved1 = 0;
+	pScb->SCB_XferLen = 0;
+	pScb->SCB_SGLen = 0;
+
+	pVirEscb->SCB_Srb = NULL;
+	pVirEscb->SCB_Srb = SCpnt;
+	orc_exec_scb(pHCB, pScb);	/* Start execute SCB            */
+	spin_unlock_irqrestore(&(pHCB->BitAllocFlagLock), flags);
+	return SUCCESS;
+}
+
+
+/***************************************************************************/
+static ORC_SCB *__orc_alloc_scb(ORC_HCS * hcsp)
+{
+	ORC_SCB *pTmpScb;
+	UCHAR Ch;
+	ULONG idx;
+	UCHAR index;
+	UCHAR i;
+
+	Ch = hcsp->HCS_Index;
+	for (i = 0; i < 8; i++) {
+		for (index = 0; index < 32; index++) {
+			if ((hcsp->BitAllocFlag[Ch][i] >> index) & 0x01) {
+				hcsp->BitAllocFlag[Ch][i] &= ~(1 << index);
+				break;
+			}
+		}
+		idx = index + 32 * i;
+		pTmpScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (idx * sizeof(ORC_SCB)));
+		return (pTmpScb);
+	}
+	return (NULL);
+}
+
+static ORC_SCB *orc_alloc_scb(ORC_HCS * hcsp)
+{
+	ORC_SCB *pTmpScb;
+	ULONG flags;
+
+	spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+	pTmpScb = __orc_alloc_scb(hcsp);
+	spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+	return (pTmpScb);
+}
+
+
+/***************************************************************************/
+static void orc_release_scb(ORC_HCS * hcsp, ORC_SCB * scbp)
+{
+	ULONG flags;
+	UCHAR Index;
+	UCHAR i;
+	UCHAR Ch;
+
+	spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+	Ch = hcsp->HCS_Index;
+	Index = scbp->SCB_ScbIdx;
+	i = Index / 32;
+	Index %= 32;
+	hcsp->BitAllocFlag[Ch][i] |= (1 << Index);
+	spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+}
+
+/*****************************************************************************
+ Function name  : abort_SCB
+ Description    : Abort a queued command.
+	                 (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int abort_SCB(ORC_HCS * hcsp, ORC_SCB * pScb)
+{
+	unsigned char bData, bStatus;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, ORC_CMD_ABORT_SCB);	/* Write command */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	ORC_WR(hcsp->HCS_Base + ORC_HDATA, pScb->SCB_ScbIdx);	/* Write address */
+	ORC_WR(hcsp->HCS_Base + ORC_HCTRL, HDO);
+	if (waitHDOoff(hcsp) == 0)	/* Wait HDO off   */
+		return 0;
+
+	if (waitHDIset(hcsp, &bData) == 0)	/* Wait HDI set   */
+		return 0;
+	bStatus = ORC_RD(hcsp->HCS_Base, ORC_HDATA);
+	ORC_WR(hcsp->HCS_Base + ORC_HSTUS, bData);	/* Clear HDI    */
+
+	if (bStatus == 1)	/* 0 - Successfully               */
+		return 0;	/* 1 - Fail                     */
+	return 1;
+}
+
+/*****************************************************************************
+ Function name  : inia100_abort
+ Description    : Abort a queued command.
+	                 (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int orc_abort_srb(ORC_HCS * hcsp, struct scsi_cmnd *SCpnt)
+{
+	ESCB *pVirEscb;
+	ORC_SCB *pVirScb;
+	UCHAR i;
+	ULONG flags;
+
+	spin_lock_irqsave(&(hcsp->BitAllocFlagLock), flags);
+
+	pVirScb = hcsp->HCS_virScbArray;
+
+	for (i = 0; i < ORC_MAXQUEUE; i++, pVirScb++) {
+		pVirEscb = pVirScb->SCB_EScb;
+		if ((pVirScb->SCB_Status) && (pVirEscb->SCB_Srb == SCpnt)) {
+			if (pVirScb->SCB_TagMsg == 0) {
+				spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+				return FAILED;
+			} else {
+				if (abort_SCB(hcsp, pVirScb)) {
+					pVirEscb->SCB_Srb = NULL;
+					spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+					return SUCCESS;
+				} else {
+					spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+					return FAILED;
+				}
+			}
+		}
+	}
+	spin_unlock_irqrestore(&(hcsp->BitAllocFlagLock), flags);
+	return FAILED;
+}
+
+/***********************************************************************
+ Routine Description:
+	  This is the interrupt service routine for the Orchid SCSI adapter.
+	  It reads the interrupt register to determine if the adapter is indeed
+	  the source of the interrupt and clears the interrupt at the device.
+ Arguments:
+	  HwDeviceExtension - HBA miniport driver's adapter data storage
+ Return Value:
+***********************************************************************/
+static void orc_interrupt(
+			  ORC_HCS * hcsp
+)
+{
+	BYTE bScbIdx;
+	ORC_SCB *pScb;
+
+	if (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT) == 0) {
+		return;		// 0;
+
+	}
+	do {
+		bScbIdx = ORC_RD(hcsp->HCS_Base, ORC_RQUEUE);
+
+		pScb = (ORC_SCB *) ((ULONG) hcsp->HCS_virScbArray + (ULONG) (sizeof(ORC_SCB) * bScbIdx));
+		pScb->SCB_Status = 0x0;
+
+		inia100SCBPost((BYTE *) hcsp, (BYTE *) pScb);
+	} while (ORC_RD(hcsp->HCS_Base, ORC_RQUEUECNT));
+	return;			//1;
+
+}				/* End of I1060Interrupt() */
+
+/*****************************************************************************
+ Function name  : inia100BuildSCB
+ Description    : 
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static void inia100BuildSCB(ORC_HCS * pHCB, ORC_SCB * pSCB, struct scsi_cmnd * SCpnt)
+{				/* Create corresponding SCB     */
+	struct scatterlist *pSrbSG;
+	ORC_SG *pSG;		/* Pointer to SG list           */
+	int i, count_sg;
+	ESCB *pEScb;
+
+	pEScb = pSCB->SCB_EScb;
+	pEScb->SCB_Srb = SCpnt;
+	pSG = NULL;
+
+	pSCB->SCB_Opcode = ORC_EXECSCSI;
+	pSCB->SCB_Flags = SCF_NO_DCHK;	/* Clear done bit               */
+	pSCB->SCB_Target = SCpnt->device->id;
+	pSCB->SCB_Lun = SCpnt->device->lun;
+	pSCB->SCB_Reserved0 = 0;
+	pSCB->SCB_Reserved1 = 0;
+	pSCB->SCB_SGLen = 0;
+
+	if ((pSCB->SCB_XferLen = (U32) SCpnt->request_bufflen)) {
+		pSG = (ORC_SG *) & pEScb->ESCB_SGList[0];
+		if (SCpnt->use_sg) {
+			pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+			count_sg = pci_map_sg(pHCB->pdev, pSrbSG, SCpnt->use_sg,
+					SCpnt->sc_data_direction);
+			pSCB->SCB_SGLen = (U32) (count_sg * 8);
+			for (i = 0; i < count_sg; i++, pSG++, pSrbSG++) {
+				pSG->SG_Ptr = (U32) sg_dma_address(pSrbSG);
+				pSG->SG_Len = (U32) sg_dma_len(pSrbSG);
+			}
+		} else if (SCpnt->request_bufflen != 0) {/* Non SG */
+			pSCB->SCB_SGLen = 0x8;
+			SCpnt->SCp.dma_handle = pci_map_single(pHCB->pdev,
+					SCpnt->request_buffer,
+					SCpnt->request_bufflen,
+					SCpnt->sc_data_direction);
+			pSG->SG_Ptr = (U32) SCpnt->SCp.dma_handle;
+			pSG->SG_Len = (U32) SCpnt->request_bufflen;
+		} else {
+			pSCB->SCB_SGLen = 0;
+			pSG->SG_Ptr = 0;
+			pSG->SG_Len = 0;
+		}
+	}
+	pSCB->SCB_SGPAddr = (U32) pSCB->SCB_SensePAddr;
+	pSCB->SCB_HaStat = 0;
+	pSCB->SCB_TaStat = 0;
+	pSCB->SCB_Link = 0xFF;
+	pSCB->SCB_SenseLen = SENSE_SIZE;
+	pSCB->SCB_CDBLen = SCpnt->cmd_len;
+	if (pSCB->SCB_CDBLen >= IMAX_CDB) {
+		printk("max cdb length= %x\b", SCpnt->cmd_len);
+		pSCB->SCB_CDBLen = IMAX_CDB;
+	}
+	pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
+	if (SCpnt->device->tagged_supported) {	/* Tag Support                  */
+		pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;	/* Do simple tag only   */
+	} else {
+		pSCB->SCB_TagMsg = 0;	/* No tag support               */
+	}
+	memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, pSCB->SCB_CDBLen);
+	return;
+}
+
+/*****************************************************************************
+ Function name  : inia100_queue
+ Description    : Queue a command and setup interrupts for a free bus.
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_queue(struct scsi_cmnd * SCpnt, void (*done) (struct scsi_cmnd *))
+{
+	register ORC_SCB *pSCB;
+	ORC_HCS *pHCB;		/* Point to Host adapter control block */
+
+	pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+	SCpnt->scsi_done = done;
+	/* Get free SCSI control block  */
+	if ((pSCB = orc_alloc_scb(pHCB)) == NULL)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	inia100BuildSCB(pHCB, pSCB, SCpnt);
+	orc_exec_scb(pHCB, pSCB);	/* Start execute SCB            */
+
+	return (0);
+}
+
+/*****************************************************************************
+ Function name  : inia100_abort
+ Description    : Abort a queued command.
+	                 (commands that are on the bus can't be aborted easily)
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_abort(struct scsi_cmnd * SCpnt)
+{
+	ORC_HCS *hcsp;
+
+	hcsp = (ORC_HCS *) SCpnt->device->host->hostdata;
+	return orc_abort_srb(hcsp, SCpnt);
+}
+
+/*****************************************************************************
+ Function name  : inia100_reset
+ Description    : Reset registers, reset a hanging bus and
+                  kill active and disconnected commands for target w/o soft reset
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_bus_reset(struct scsi_cmnd * SCpnt)
+{				/* I need Host Control Block Information */
+	ORC_HCS *pHCB;
+	pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+	return orc_reset_scsi_bus(pHCB);
+}
+
+/*****************************************************************************
+ Function name  : inia100_device_reset
+ Description    : Reset the device
+ Input          : pHCB  -       Pointer to host adapter structure
+ Output         : None.
+ Return         : pSRB  -       Pointer to SCSI request block.
+*****************************************************************************/
+static int inia100_device_reset(struct scsi_cmnd * SCpnt)
+{				/* I need Host Control Block Information */
+	ORC_HCS *pHCB;
+	pHCB = (ORC_HCS *) SCpnt->device->host->hostdata;
+	return orc_device_reset(pHCB, SCpnt, SCpnt->device->id);
+
+}
+
+/*****************************************************************************
+ Function name  : inia100SCBPost
+ Description    : This is callback routine be called when orc finish one
+			SCSI command.
+ Input          : pHCB  -       Pointer to host adapter control block.
+		  pSCB  -       Pointer to SCSI control block.
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void inia100SCBPost(BYTE * pHcb, BYTE * pScb)
+{
+	struct scsi_cmnd *pSRB;	/* Pointer to SCSI request block */
+	ORC_HCS *pHCB;
+	ORC_SCB *pSCB;
+	ESCB *pEScb;
+
+	pHCB = (ORC_HCS *) pHcb;
+	pSCB = (ORC_SCB *) pScb;
+	pEScb = pSCB->SCB_EScb;
+	if ((pSRB = (struct scsi_cmnd *) pEScb->SCB_Srb) == 0) {
+		printk("inia100SCBPost: SRB pointer is empty\n");
+		orc_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
+		return;
+	}
+	pEScb->SCB_Srb = NULL;
+
+	switch (pSCB->SCB_HaStat) {
+	case 0x0:
+	case 0xa:		/* Linked command complete without error and linked normally */
+	case 0xb:		/* Linked command complete without error interrupt generated */
+		pSCB->SCB_HaStat = 0;
+		break;
+
+	case 0x11:		/* Selection time out-The initiator selection or target
+				   reselection was not complete within the SCSI Time out period */
+		pSCB->SCB_HaStat = DID_TIME_OUT;
+		break;
+
+	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
+				   phase sequence was requested by the target. The host adapter
+				   will generate a SCSI Reset Condition, notifying the host with
+				   a SCRD interrupt */
+		pSCB->SCB_HaStat = DID_RESET;
+		break;
+
+	case 0x1a:		/* SCB Aborted. 07/21/98 */
+		pSCB->SCB_HaStat = DID_ABORT;
+		break;
+
+	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
+				   than was allocated by the Data Length field or the sum of the
+				   Scatter / Gather Data Length fields. */
+	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid. */
+
+	default:
+		printk("inia100: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+		pSCB->SCB_HaStat = DID_ERROR;	/* Couldn't find any better */
+		break;
+	}
+
+	if (pSCB->SCB_TaStat == 2) {	/* Check condition              */
+		memcpy((unsigned char *) &pSRB->sense_buffer[0],
+		   (unsigned char *) &pEScb->ESCB_SGList[0], SENSE_SIZE);
+	}
+	pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+
+	if (pSRB->use_sg) {
+		pci_unmap_sg(pHCB->pdev,
+			     (struct scatterlist *)pSRB->request_buffer,
+			     pSRB->use_sg, pSRB->sc_data_direction);
+	} else if (pSRB->request_bufflen != 0) {
+		pci_unmap_single(pHCB->pdev, pSRB->SCp.dma_handle,
+				 pSRB->request_bufflen,
+				 pSRB->sc_data_direction);
+	}
+
+	pSRB->scsi_done(pSRB);	/* Notify system DONE           */
+
+	orc_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
+}
+
+/*
+ * Interrupt handler (main routine of the driver)
+ */
+static irqreturn_t inia100_intr(int irqno, void *devid, struct pt_regs *regs)
+{
+	struct Scsi_Host *host = (struct Scsi_Host *)devid;
+	ORC_HCS *pHcb = (ORC_HCS *)host->hostdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	orc_interrupt(pHcb);
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static struct scsi_host_template inia100_template = {
+	.proc_name		= "inia100",
+	.name			= inia100_REVID,
+	.queuecommand		= inia100_queue,
+	.eh_abort_handler	= inia100_abort,
+	.eh_bus_reset_handler	= inia100_bus_reset,
+	.eh_device_reset_handler = inia100_device_reset,
+	.can_queue		= 1,
+	.this_id		= 1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun 		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+static int __devinit inia100_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	struct Scsi_Host *shost;
+	ORC_HCS *pHCB;
+	unsigned long port, bios;
+	int error = -ENODEV;
+	u32 sz;
+	unsigned long dBiosAdr;
+	char *pbBiosAdr;
+
+	if (pci_enable_device(pdev))
+		goto out;
+	if (pci_set_dma_mask(pdev, 0xffffffffULL)) {
+		printk(KERN_WARNING "Unable to set 32bit DMA "
+				    "on inia100 adapter, ignoring.\n");
+		goto out_disable_device;
+	}
+
+	pci_set_master(pdev);
+
+	port = pci_resource_start(pdev, 0);
+	if (!request_region(port, 256, "inia100")) {
+		printk(KERN_WARNING "inia100: io port 0x%lx, is busy.\n", port);
+		goto out_disable_device;
+	}
+
+	/* <02> read from base address + 0x50 offset to get the bios balue. */
+	bios = ORC_RDWORD(port, 0x50);
+
+
+	shost = scsi_host_alloc(&inia100_template, sizeof(ORC_HCS));
+	if (!shost)
+		goto out_release_region;
+
+	pHCB = (ORC_HCS *)shost->hostdata;
+	pHCB->pdev = pdev;
+	pHCB->HCS_Base = port;
+	pHCB->HCS_BIOS = bios;
+	spin_lock_init(&pHCB->BitAllocFlagLock);
+
+	/* Get total memory needed for SCB */
+	sz = ORC_MAXQUEUE * sizeof(ORC_SCB);
+	pHCB->HCS_virScbArray = pci_alloc_consistent(pdev, sz,
+			&pHCB->HCS_physScbArray);
+	if (!pHCB->HCS_virScbArray) {
+		printk("inia100: SCB memory allocation error\n");
+		goto out_host_put;
+	}
+	memset(pHCB->HCS_virScbArray, 0, sz);
+
+	/* Get total memory needed for ESCB */
+	sz = ORC_MAXQUEUE * sizeof(ESCB);
+	pHCB->HCS_virEscbArray = pci_alloc_consistent(pdev, sz,
+			&pHCB->HCS_physEscbArray);
+	if (!pHCB->HCS_virEscbArray) {
+		printk("inia100: ESCB memory allocation error\n");
+		goto out_free_scb_array;
+	}
+	memset(pHCB->HCS_virEscbArray, 0, sz);
+
+	dBiosAdr = pHCB->HCS_BIOS;
+	dBiosAdr = (dBiosAdr << 4);
+	pbBiosAdr = phys_to_virt(dBiosAdr);
+	if (init_orchid(pHCB)) {	/* Initialize orchid chip */
+		printk("inia100: initial orchid fail!!\n");
+		goto out_free_escb_array;
+	}
+
+	shost->io_port = pHCB->HCS_Base;
+	shost->n_io_port = 0xff;
+	shost->can_queue = ORC_MAXQUEUE;
+	shost->unique_id = shost->io_port;
+	shost->max_id = pHCB->HCS_MaxTar;
+	shost->max_lun = 16;
+	shost->irq = pHCB->HCS_Intr = pdev->irq;
+	shost->this_id = pHCB->HCS_SCSI_ID;	/* Assign HCS index */
+	shost->sg_tablesize = TOTAL_SG_ENTRY;
+
+	/* Initial orc chip           */
+	error = request_irq(pdev->irq, inia100_intr, SA_SHIRQ,
+			"inia100", shost);
+	if (error < 0) {
+		printk(KERN_WARNING "inia100: unable to get irq %d\n",
+				pdev->irq);
+		goto out_free_escb_array;
+	}
+
+	pci_set_drvdata(pdev, shost);
+
+	error = scsi_add_host(shost, &pdev->dev);
+	if (error)
+		goto out_free_irq;
+
+	scsi_scan_host(shost);
+	return 0;
+
+ out_free_irq:
+        free_irq(shost->irq, shost);
+ out_free_escb_array:
+	pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
+			pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+ out_free_scb_array:
+	pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+			pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+ out_host_put:
+	scsi_host_put(shost);
+ out_release_region:
+        release_region(port, 256);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+static void __devexit inia100_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	ORC_HCS *pHCB = (ORC_HCS *)shost->hostdata;
+
+	scsi_remove_host(shost);
+
+        free_irq(shost->irq, shost);
+	pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ESCB),
+			pHCB->HCS_virEscbArray, pHCB->HCS_physEscbArray);
+	pci_free_consistent(pdev, ORC_MAXQUEUE * sizeof(ORC_SCB),
+			pHCB->HCS_virScbArray, pHCB->HCS_physScbArray);
+        release_region(shost->io_port, 256);
+
+	scsi_host_put(shost);
+} 
+
+static struct pci_device_id inia100_pci_tbl[] = {
+	{PCI_VENDOR_ID_INIT, 0x1060, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, inia100_pci_tbl);
+
+static struct pci_driver inia100_pci_driver = {
+	.name		= "inia100",
+	.id_table	= inia100_pci_tbl,
+	.probe		= inia100_probe_one,
+	.remove		= __devexit_p(inia100_remove_one),
+};
+
+static int __init inia100_init(void)
+{
+	return pci_module_init(&inia100_pci_driver);
+}
+
+static void __exit inia100_exit(void)
+{
+	pci_unregister_driver(&inia100_pci_driver);
+}
+
+MODULE_DESCRIPTION("Initio A100U2W SCSI driver");
+MODULE_AUTHOR("Initio Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
+
+module_init(inia100_init);
+module_exit(inia100_exit);
diff --git a/drivers/scsi/a100u2w.h b/drivers/scsi/a100u2w.h
new file mode 100644
index 0000000..6f542d2
--- /dev/null
+++ b/drivers/scsi/a100u2w.h
@@ -0,0 +1,416 @@
+/*
+ * Initio A100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Revision History:
+ * 06/18/98 HL, Initial production Version 1.02
+ * 12/19/98 bv, Use spinlocks for 2.1.95 and up
+ * 06/25/02 Doug Ledford <dledford@redhat.com>
+ *	 - This and the i60uscsi.h file are almost identical,
+ *	   merged them into a single header used by both .c files.
+ */
+
+#define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
+
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#define U32     u32
+
+#if 1
+#define ORC_MAXQUEUE		245
+#define ORC_MAXTAGS		64
+#else
+#define ORC_MAXQUEUE		25
+#define ORC_MAXTAGS		8
+#endif
+
+#define TOTAL_SG_ENTRY		32
+#define MAX_TARGETS		16
+#define IMAX_CDB			15
+#define SENSE_SIZE		14
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct ORC_SG_Struc {
+	U32 SG_Ptr;		/* Data Pointer */
+	U32 SG_Len;		/* Data Length */
+} ORC_SG;
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80	/* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0	/* Disconnect is allowed        */
+
+
+#define ORC_OFFSET_SCB			16
+#define ORC_MAX_SCBS		    250
+#define MAX_CHANNELS       2
+#define MAX_ESCB_ELE				64
+#define TCF_DRV_255_63     0x0400
+
+/********************************************************/
+/*      Orchid Host Command Set                         */
+/********************************************************/
+#define ORC_CMD_NOP		0x00	/* Host command - NOP             */
+#define ORC_CMD_VERSION		0x01	/* Host command - Get F/W version */
+#define ORC_CMD_ECHO		0x02	/* Host command - ECHO            */
+#define ORC_CMD_SET_NVM		0x03	/* Host command - Set NVRAM       */
+#define ORC_CMD_GET_NVM		0x04	/* Host command - Get NVRAM       */
+#define ORC_CMD_GET_BUS_STATUS	0x05	/* Host command - Get SCSI bus status */
+#define ORC_CMD_ABORT_SCB	0x06	/* Host command - Abort SCB       */
+#define ORC_CMD_ISSUE_SCB	0x07	/* Host command - Issue SCB       */
+
+/********************************************************/
+/*              Orchid Register Set                     */
+/********************************************************/
+#define ORC_GINTS	0xA0	/* Global Interrupt Status        */
+#define QINT		0x04	/* Reply Queue Interrupt  */
+#define ORC_GIMSK	0xA1	/* Global Interrupt MASK  */
+#define MQINT		0x04	/* Mask Reply Queue Interrupt     */
+#define	ORC_GCFG	0xA2	/* Global Configure               */
+#define EEPRG		0x01	/* Enable EEPROM programming */
+#define	ORC_GSTAT	0xA3	/* Global status          */
+#define WIDEBUS		0x10	/* Wide SCSI Devices connected    */
+#define ORC_HDATA	0xA4	/* Host Data                      */
+#define ORC_HCTRL	0xA5	/* Host Control                   */
+#define SCSIRST		0x80	/* SCSI bus reset         */
+#define HDO			0x40	/* Host data out          */
+#define HOSTSTOP		0x02	/* Host stop RISC engine  */
+#define DEVRST		0x01	/* Device reset                   */
+#define ORC_HSTUS	0xA6	/* Host Status                    */
+#define HDI			0x02	/* Host data in                   */
+#define RREADY		0x01	/* RISC engine is ready to receive */
+#define	ORC_NVRAM	0xA7	/* Nvram port address             */
+#define SE2CS		0x008
+#define SE2CLK		0x004
+#define SE2DO		0x002
+#define SE2DI		0x001
+#define ORC_PQUEUE	0xA8	/* Posting queue FIFO             */
+#define ORC_PQCNT	0xA9	/* Posting queue FIFO Cnt */
+#define ORC_RQUEUE	0xAA	/* Reply queue FIFO               */
+#define ORC_RQUEUECNT	0xAB	/* Reply queue FIFO Cnt           */
+#define	ORC_FWBASEADR	0xAC	/* Firmware base address  */
+
+#define	ORC_EBIOSADR0 0xB0	/* External Bios address */
+#define	ORC_EBIOSADR1 0xB1	/* External Bios address */
+#define	ORC_EBIOSADR2 0xB2	/* External Bios address */
+#define	ORC_EBIOSDATA 0xB3	/* External Bios address */
+
+#define	ORC_SCBSIZE	0xB7	/* SCB size register              */
+#define	ORC_SCBBASE0	0xB8	/* SCB base address 0             */
+#define	ORC_SCBBASE1	0xBC	/* SCB base address 1             */
+
+#define	ORC_RISCCTL	0xE0	/* RISC Control                   */
+#define PRGMRST		0x002
+#define DOWNLOAD		0x001
+#define	ORC_PRGMCTR0	0xE2	/* RISC program counter           */
+#define	ORC_PRGMCTR1	0xE3	/* RISC program counter           */
+#define	ORC_RISCRAM	0xEC	/* RISC RAM data port 4 bytes     */
+
+typedef struct orc_extended_scb {	/* Extended SCB                 */
+	ORC_SG ESCB_SGList[TOTAL_SG_ENTRY];	/*0 Start of SG list              */
+	struct scsi_cmnd *SCB_Srb;	/*50 SRB Pointer */
+} ESCB;
+
+/***********************************************************************
+		SCSI Control Block
+************************************************************************/
+typedef struct orc_scb {	/* Scsi_Ctrl_Blk                */
+	UBYTE SCB_Opcode;	/*00 SCB command code&residual  */
+	UBYTE SCB_Flags;	/*01 SCB Flags                  */
+	UBYTE SCB_Target;	/*02 Target Id                  */
+	UBYTE SCB_Lun;		/*03 Lun                        */
+	U32 SCB_Reserved0;	/*04 Reserved for ORCHID must 0 */
+	U32 SCB_XferLen;	/*08 Data Transfer Length       */
+	U32 SCB_Reserved1;	/*0C Reserved for ORCHID must 0 */
+	U32 SCB_SGLen;		/*10 SG list # * 8              */
+	U32 SCB_SGPAddr;	/*14 SG List Buf physical Addr  */
+	U32 SCB_SGPAddrHigh;	/*18 SG Buffer high physical Addr */
+	UBYTE SCB_HaStat;	/*1C Host Status                */
+	UBYTE SCB_TaStat;	/*1D Target Status              */
+	UBYTE SCB_Status;	/*1E SCB status                 */
+	UBYTE SCB_Link;		/*1F Link pointer, default 0xFF */
+	UBYTE SCB_SenseLen;	/*20 Sense Allocation Length    */
+	UBYTE SCB_CDBLen;	/*21 CDB Length                 */
+	UBYTE SCB_Ident;	/*22 Identify                   */
+	UBYTE SCB_TagMsg;	/*23 Tag Message                */
+	UBYTE SCB_CDB[IMAX_CDB];	/*24 SCSI CDBs                  */
+	UBYTE SCB_ScbIdx;	/*3C Index for this ORCSCB      */
+	U32 SCB_SensePAddr;	/*34 Sense Buffer physical Addr */
+
+	ESCB *SCB_EScb;		/*38 Extended SCB Pointer       */
+#ifndef ALPHA
+	UBYTE SCB_Reserved2[4];	/*3E Reserved for Driver use    */
+#endif
+} ORC_SCB;
+
+/* Opcodes of ORCSCB_Opcode */
+#define ORC_EXECSCSI	0x00	/* SCSI initiator command with residual */
+#define ORC_BUSDEVRST	0x01	/* SCSI Bus Device Reset  */
+
+/* Status of ORCSCB_Status */
+#define ORCSCB_COMPLETE	0x00	/* SCB request completed  */
+#define ORCSCB_POST	0x01	/* SCB is posted by the HOST      */
+
+/* Bit Definition for ORCSCB_Flags */
+#define SCF_DISINT	0x01	/* Disable HOST interrupt */
+#define SCF_DIR		0x18	/* Direction bits         */
+#define SCF_NO_DCHK	0x00	/* Direction determined by SCSI   */
+#define SCF_DIN		0x08	/* From Target to Initiator       */
+#define SCF_DOUT	0x10	/* From Initiator to Target       */
+#define SCF_NO_XF	0x18	/* No data transfer               */
+#define SCF_POLL   0x40
+
+/* Error Codes for ORCSCB_HaStat */
+#define HOST_SEL_TOUT	0x11
+#define HOST_DO_DU	0x12
+#define HOST_BUS_FREE	0x13
+#define HOST_BAD_PHAS	0x14
+#define HOST_INV_CMD	0x16
+#define HOST_SCSI_RST	0x1B
+#define HOST_DEV_RST	0x1C
+
+
+/* Error Codes for ORCSCB_TaStat */
+#define TARGET_CHK_COND	0x02
+#define TARGET_BUSY	0x08
+#define TARGET_TAG_FULL	0x28
+
+
+/***********************************************************************
+		Target Device Control Structure
+**********************************************************************/
+
+typedef struct ORC_Tar_Ctrl_Struc {
+	UBYTE TCS_DrvDASD;	/* 6 */
+	UBYTE TCS_DrvSCSI;	/* 7 */
+	UBYTE TCS_DrvHead;	/* 8 */
+	UWORD TCS_DrvFlags;	/* 4 */
+	UBYTE TCS_DrvSector;	/* 7 */
+} ORC_TCS;
+
+/* Bit Definition for TCF_DrvFlags */
+#define	TCS_DF_NODASD_SUPT	0x20	/* Suppress OS/2 DASD Mgr support */
+#define	TCS_DF_NOSCSI_SUPT	0x40	/* Suppress OS/2 SCSI Mgr support */
+
+
+/***********************************************************************
+              Host Adapter Control Structure
+************************************************************************/
+typedef struct ORC_Ha_Ctrl_Struc {
+	USHORT HCS_Base;	/* 00 */
+	UBYTE HCS_Index;	/* 02 */
+	UBYTE HCS_Intr;		/* 04 */
+	UBYTE HCS_SCSI_ID;	/* 06    H/A SCSI ID */
+	UBYTE HCS_BIOS;		/* 07    BIOS configuration */
+
+	UBYTE HCS_Flags;	/* 0B */
+	UBYTE HCS_HAConfig1;	/* 1B    SCSI0MAXTags */
+	UBYTE HCS_MaxTar;	/* 1B    SCSI0MAXTags */
+
+	USHORT HCS_Units;	/* Number of units this adapter  */
+	USHORT HCS_AFlags;	/* Adapter info. defined flags   */
+	ULONG HCS_Timeout;	/* Adapter timeout value   */
+	ORC_SCB *HCS_virScbArray;	/* 28 Virtual Pointer to SCB array */
+	dma_addr_t HCS_physScbArray;	/* Scb Physical address */
+	ESCB *HCS_virEscbArray;	/* Virtual pointer to ESCB Scatter list */
+	dma_addr_t HCS_physEscbArray;	/* scatter list Physical address */
+	UBYTE TargetFlag[16];	/* 30  target configuration, TCF_EN_TAG */
+	UBYTE MaximumTags[16];	/* 40  ORC_MAX_SCBS */
+	UBYTE ActiveTags[16][16];	/* 50 */
+	ORC_TCS HCS_Tcs[16];	/* 28 */
+	U32 BitAllocFlag[MAX_CHANNELS][8];	/* Max STB is 256, So 256/32 */
+	spinlock_t BitAllocFlagLock;
+	struct pci_dev *pdev;
+} ORC_HCS;
+
+/* Bit Definition for HCS_Flags */
+
+#define HCF_SCSI_RESET	0x01	/* SCSI BUS RESET         */
+#define HCF_PARITY    	0x02	/* parity card                    */
+#define HCF_LVDS     	0x10	/* parity card                    */
+
+/* Bit Definition for TargetFlag */
+
+#define TCF_EN_255	    0x08
+#define TCF_EN_TAG	    0x10
+#define TCF_BUSY	      0x20
+#define TCF_DISCONNECT	0x40
+#define TCF_SPIN_UP	  0x80
+
+/* Bit Definition for HCS_AFlags */
+#define	HCS_AF_IGNORE		0x01	/* Adapter ignore         */
+#define	HCS_AF_DISABLE_RESET	0x10	/* Adapter disable reset  */
+#define	HCS_AF_DISABLE_ADPT	0x80	/* Adapter disable                */
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+        UCHAR SubVendorID0;     /* 00 - Sub Vendor ID           */
+        UCHAR SubVendorID1;     /* 00 - Sub Vendor ID           */
+        UCHAR SubSysID0;        /* 02 - Sub System ID           */
+        UCHAR SubSysID1;        /* 02 - Sub System ID           */
+        UCHAR SubClass;         /* 04 - Sub Class               */
+        UCHAR VendorID0;        /* 05 - Vendor ID               */
+        UCHAR VendorID1;        /* 05 - Vendor ID               */
+        UCHAR DeviceID0;        /* 07 - Device ID               */
+        UCHAR DeviceID1;        /* 07 - Device ID               */
+        UCHAR Reserved0[2];     /* 09 - Reserved                */
+        UCHAR Revision;         /* 0B - Revision of data structure */
+        /* ----Host Adapter Structure ---- */
+        UCHAR NumOfCh;          /* 0C - Number of SCSI channel  */
+        UCHAR BIOSConfig1;      /* 0D - BIOS configuration 1    */
+        UCHAR BIOSConfig2;      /* 0E - BIOS boot channel&target ID */
+        UCHAR BIOSConfig3;      /* 0F - BIOS configuration 3    */
+        /* ----SCSI channel Structure ---- */
+        /* from "CTRL-I SCSI Host Adapter SetUp menu "  */
+        UCHAR SCSI0Id;          /* 10 - Channel 0 SCSI ID       */
+        UCHAR SCSI0Config;      /* 11 - Channel 0 SCSI configuration */
+        UCHAR SCSI0MaxTags;     /* 12 - Channel 0 Maximum tags  */
+        UCHAR SCSI0ResetTime;   /* 13 - Channel 0 Reset recovering time */
+        UCHAR ReservedforChannel0[2];   /* 14 - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                        */
+        UCHAR Target00Config;   /* 16 - Channel 0 Target 0 config */
+        UCHAR Target01Config;   /* 17 - Channel 0 Target 1 config */
+        UCHAR Target02Config;   /* 18 - Channel 0 Target 2 config */
+        UCHAR Target03Config;   /* 19 - Channel 0 Target 3 config */
+        UCHAR Target04Config;   /* 1A - Channel 0 Target 4 config */
+        UCHAR Target05Config;   /* 1B - Channel 0 Target 5 config */
+        UCHAR Target06Config;   /* 1C - Channel 0 Target 6 config */
+        UCHAR Target07Config;   /* 1D - Channel 0 Target 7 config */
+        UCHAR Target08Config;   /* 1E - Channel 0 Target 8 config */
+        UCHAR Target09Config;   /* 1F - Channel 0 Target 9 config */
+        UCHAR Target0AConfig;   /* 20 - Channel 0 Target A config */
+        UCHAR Target0BConfig;   /* 21 - Channel 0 Target B config */
+        UCHAR Target0CConfig;   /* 22 - Channel 0 Target C config */
+        UCHAR Target0DConfig;   /* 23 - Channel 0 Target D config */
+        UCHAR Target0EConfig;   /* 24 - Channel 0 Target E config */
+        UCHAR Target0FConfig;   /* 25 - Channel 0 Target F config */
+
+        UCHAR SCSI1Id;          /* 26 - Channel 1 SCSI ID       */
+        UCHAR SCSI1Config;      /* 27 - Channel 1 SCSI configuration */
+        UCHAR SCSI1MaxTags;     /* 28 - Channel 1 Maximum tags  */
+        UCHAR SCSI1ResetTime;   /* 29 - Channel 1 Reset recovering time */
+        UCHAR ReservedforChannel1[2];   /* 2A - Reserved                */
+
+        /* ----SCSI target Structure ----  */
+        /* from "CTRL-I SCSI device SetUp menu "                                          */
+        UCHAR Target10Config;   /* 2C - Channel 1 Target 0 config */
+        UCHAR Target11Config;   /* 2D - Channel 1 Target 1 config */
+        UCHAR Target12Config;   /* 2E - Channel 1 Target 2 config */
+        UCHAR Target13Config;   /* 2F - Channel 1 Target 3 config */
+        UCHAR Target14Config;   /* 30 - Channel 1 Target 4 config */
+        UCHAR Target15Config;   /* 31 - Channel 1 Target 5 config */
+        UCHAR Target16Config;   /* 32 - Channel 1 Target 6 config */
+        UCHAR Target17Config;   /* 33 - Channel 1 Target 7 config */
+        UCHAR Target18Config;   /* 34 - Channel 1 Target 8 config */
+        UCHAR Target19Config;   /* 35 - Channel 1 Target 9 config */
+        UCHAR Target1AConfig;   /* 36 - Channel 1 Target A config */
+        UCHAR Target1BConfig;   /* 37 - Channel 1 Target B config */
+        UCHAR Target1CConfig;   /* 38 - Channel 1 Target C config */
+        UCHAR Target1DConfig;   /* 39 - Channel 1 Target D config */
+        UCHAR Target1EConfig;   /* 3A - Channel 1 Target E config */
+        UCHAR Target1FConfig;   /* 3B - Channel 1 Target F config */
+        UCHAR reserved[3];      /* 3C - Reserved                */
+        /* ---------- CheckSum ----------       */
+        UCHAR CheckSum;         /* 3F - Checksum of NVRam       */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC_BIOSENABLE  0x01    /* BIOS enable                    */
+#define NBC_CDROM       0x02    /* Support bootable CDROM */
+#define NBC_REMOVABLE   0x04    /* Support removable drive        */
+
+/* Bios Configuration for nvram->BIOSConfig2                            */
+#define NBB_TARGET_MASK 0x0F    /* Boot SCSI target ID number     */
+#define NBB_CHANL_MASK  0xF0    /* Boot SCSI channel number       */
+
+/* Bit definition for nvram->SCSIConfig                                 */
+#define NCC_BUSRESET    0x01    /* Reset SCSI bus at power up     */
+#define NCC_PARITYCHK   0x02    /* SCSI parity enable             */
+#define NCC_LVDS        0x10    /* Enable LVDS                    */
+#define NCC_ACTTERM1    0x20    /* Enable active terminator 1     */
+#define NCC_ACTTERM2    0x40    /* Enable active terminator 2     */
+#define NCC_AUTOTERM    0x80    /* Enable auto termination        */
+
+/* Bit definition for nvram->TargetxConfig                              */
+#define NTC_PERIOD      0x07    /* Maximum Sync. Speed            */
+#define NTC_1GIGA       0x08    /* 255 head / 63 sectors (64/32) */
+#define NTC_NO_SYNC     0x10    /* NO SYNC. NEGO          */
+#define NTC_NO_WIDESYNC 0x20    /* NO WIDE SYNC. NEGO             */
+#define NTC_DISC_ENABLE 0x40    /* Enable SCSI disconnect */
+#define NTC_SPINUP      0x80    /* Start disk drive               */
+
+/* Default NVRam values                                                 */
+#define NBC_DEFAULT     (NBC_ENABLE)
+#define NCC_DEFAULT     (NCC_BUSRESET | NCC_AUTOTERM | NCC_PARITYCHK)
+#define NCC_MAX_TAGS    0x20    /* Maximum tags per target        */
+#define NCC_RESET_TIME  0x0A    /* SCSI RESET recovering time     */
+#define NTC_DEFAULT     (NTC_1GIGA | NTC_NO_WIDESYNC | NTC_DISC_ENABLE)
+
+#define ORC_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+#define ORC_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+#define ORC_RDLONG(x,y)         (long)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+#define ORC_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define ORC_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define ORC_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c
new file mode 100644
index 0000000..9928a2f
--- /dev/null
+++ b/drivers/scsi/a2091.c
@@ -0,0 +1,260 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <linux/spinlock.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "wd33c93.h"
+#include "a2091.h"
+
+#include<linux/stat.h>
+
+#define DMA(ptr) ((a2091_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static irqreturn_t a2091_intr (int irq, void *_instance, struct pt_regs *fp)
+{
+    unsigned long flags;
+    unsigned int status;
+    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+
+    status = DMA(instance)->ISTR;
+    if (!(status & (ISTR_INT_F|ISTR_INT_P)) || !(status & ISTR_INTS))
+	return IRQ_NONE;
+
+    spin_lock_irqsave(instance->host_lock, flags);
+    wd33c93_intr(instance);
+    spin_unlock_irqrestore(instance->host_lock, flags);
+    return IRQ_HANDLED;
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+    struct Scsi_Host *instance = cmd->device->host;
+
+    /* don't allow DMA if the physical address is bad */
+    if (addr & A2091_XFER_MASK ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(instance)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+	HDATA(instance)->dma_bounce_buffer =
+	    kmalloc (HDATA(instance)->dma_bounce_len, GFP_KERNEL);
+	
+	/* can't allocate memory; use PIO */
+	if (!HDATA(instance)->dma_bounce_buffer) {
+	    HDATA(instance)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	/* get the physical address of the bounce buffer */
+	addr = virt_to_bus(HDATA(instance)->dma_bounce_buffer);
+
+	/* the bounce buffer may not be in the first 16M of physmem */
+	if (addr & A2091_XFER_MASK) {
+	    /* we could use chipmem... maybe later */
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    if (cmd->use_sg)
+#if 0
+		panic ("scsi%ddma: incomplete s/g support",
+		       instance->host_no);
+#else
+		memcpy (HDATA(instance)->dma_bounce_buffer,
+			cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+	    else
+		memcpy (HDATA(instance)->dma_bounce_buffer,
+			cmd->request_buffer, cmd->request_bufflen);
+	}
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= CNTR_DDIR;
+
+    /* remember direction */
+    HDATA(cmd->device->host)->dma_dir = dir_in;
+
+    DMA(cmd->device->host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(cmd->device->host)->ACR = addr;
+
+    if (dir_in){
+	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    }else{
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+      }
+    /* start DMA */
+    DMA(cmd->device->host)->ST_DMA = 1;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, 
+		      int status)
+{
+    /* disable SCSI interrupts */
+    unsigned short cntr = CNTR_PDMD;
+
+    if (!HDATA(instance)->dma_dir)
+	    cntr |= CNTR_DDIR;
+
+    /* disable SCSI interrupts */
+    DMA(instance)->CNTR = cntr;
+
+    /* flush if we were reading */
+    if (HDATA(instance)->dma_dir) {
+	DMA(instance)->FLUSH = 1;
+	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+	    ;
+    }
+
+    /* clear a possible interrupt */
+    DMA(instance)->CINT = 1;
+
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+
+    /* restore the CONTROL bits (minus the direction flag) */
+    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (SCpnt && SCpnt->use_sg) {
+#if 0
+	    panic ("scsi%d: incomplete s/g support",
+		   instance->host_no);
+#else
+	    if( HDATA(instance)->dma_dir )
+		memcpy (SCpnt->SCp.ptr, 
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->SCp.this_residual);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	    
+#endif
+	} else {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->request_buffer,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->request_bufflen);
+
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	}
+    }
+}
+
+int __init a2091_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    struct Scsi_Host *instance;
+    unsigned long address;
+    struct zorro_dev *z = NULL;
+    wd33c93_regs regs;
+    int num_a2091 = 0;
+
+    if (!MACH_IS_AMIGA || called)
+	return 0;
+    called = 1;
+
+    tpnt->proc_name = "A2091";
+    tpnt->proc_info = &wd33c93_proc_info;
+
+    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	if (z->id != ZORRO_PROD_CBM_A590_A2091_1 &&
+	    z->id != ZORRO_PROD_CBM_A590_A2091_2)
+	    continue;
+	address = z->resource.start;
+	if (!request_mem_region(address, 256, "wd33c93"))
+	    continue;
+
+	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
+	if (instance == NULL) {
+	    release_mem_region(address, 256);
+	    continue;
+	}
+	instance->base = ZTWO_VADDR(address);
+	instance->irq = IRQ_AMIGA_PORTS;
+	instance->unique_id = z->slotaddr;
+	DMA(instance)->DAWR = DAWR_A2091;
+	regs.SASR = &(DMA(instance)->SASR);
+	regs.SCMD = &(DMA(instance)->SCMD);
+	wd33c93_init(instance, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+	request_irq(IRQ_AMIGA_PORTS, a2091_intr, SA_SHIRQ, "A2091 SCSI",
+		    instance);
+	DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+	num_a2091++;
+    }
+
+    return num_a2091;
+}
+
+static int a2091_bus_reset(Scsi_Cmnd *cmd)
+{
+	/* FIXME perform bus-specific reset */
+	wd33c93_host_reset(cmd);
+	return SUCCESS;
+}
+
+#define HOSTS_C
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "A2901",
+	.name			= "Commodore A2091/A590 SCSI",
+	.detect			= a2091_detect,
+	.release		= a2091_release,
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_bus_reset_handler	= a2091_bus_reset,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+int a2091_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	DMA(instance)->CNTR = 0;
+	release_mem_region(ZTWO_PADDR(instance->base), 256);
+	free_irq(IRQ_AMIGA_PORTS, instance);
+	wd33c93_release();
+#endif
+	return 1;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
new file mode 100644
index 0000000..5499397
--- /dev/null
+++ b/drivers/scsi/a2091.h
@@ -0,0 +1,76 @@
+#ifndef A2091_H
+#define A2091_H
+
+/* $Id: a2091.h,v 1.4 1997/01/19 23:07:09 davem Exp $
+ *
+ * Header file for the Commodore A2091 Zorro II SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see a2091.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int a2091_detect(Scsi_Host_Template *);
+int a2091_release(struct Scsi_Host *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */
+#define A2091_XFER_MASK  (0xff000001)
+
+typedef struct {
+             unsigned char      pad1[64];
+    volatile unsigned short     ISTR;
+    volatile unsigned short     CNTR;
+             unsigned char      pad2[60];
+    volatile unsigned int       WTC;
+    volatile unsigned long      ACR;
+             unsigned char      pad3[6];
+    volatile unsigned short     DAWR;
+             unsigned char      pad4;
+    volatile unsigned char      SASR;
+             unsigned char      pad5;
+    volatile unsigned char      SCMD;
+             unsigned char      pad6[76];
+    volatile unsigned short     ST_DMA;
+    volatile unsigned short     SP_DMA;
+    volatile unsigned short     CINT;
+             unsigned char      pad7[2];
+    volatile unsigned short     FLUSH;
+} a2091_scsiregs;
+
+#define DAWR_A2091		(3)
+
+/* CNTR bits. */
+#define CNTR_TCEN		(1<<7)
+#define CNTR_PREST		(1<<6)
+#define CNTR_PDMD		(1<<5)
+#define CNTR_INTEN		(1<<4)
+#define CNTR_DDIR		(1<<3)
+
+/* ISTR bits. */
+#define ISTR_INTX		(1<<8)
+#define ISTR_INT_F		(1<<7)
+#define ISTR_INTS		(1<<6)
+#define ISTR_E_INT		(1<<5)
+#define ISTR_INT_P		(1<<4)
+#define ISTR_UE_INT		(1<<3)
+#define ISTR_OE_INT		(1<<2)
+#define ISTR_FF_FLG		(1<<1)
+#define ISTR_FE_FLG		(1<<0)
+
+#endif /* A2091_H */
diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c
new file mode 100644
index 0000000..f8a89ec
--- /dev/null
+++ b/drivers/scsi/a3000.c
@@ -0,0 +1,245 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "wd33c93.h"
+#include "a3000.h"
+
+#include<linux/stat.h>
+
+#define DMA(ptr) ((a3000_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *a3000_host = NULL;
+
+static irqreturn_t a3000_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned long flags;
+	unsigned int status = DMA(a3000_host)->ISTR;
+
+	if (!(status & ISTR_INT_P))
+		return IRQ_NONE;
+	if (status & ISTR_INTS)
+	{
+		spin_lock_irqsave(a3000_host->host_lock, flags);
+		wd33c93_intr (a3000_host);
+		spin_unlock_irqrestore(a3000_host->host_lock, flags);
+		return IRQ_HANDLED;
+	}
+	printk("Non-serviced A3000 SCSI-interrupt? ISTR = %02x\n", status);
+	return IRQ_NONE;
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = CNTR_PDMD | CNTR_INTEN;
+    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+    /*
+     * if the physical address has the wrong alignment, or if
+     * physical address is bad, or if it is a write and at the
+     * end of a physical memory chunk, then allocate a bounce
+     * buffer
+     */
+    if (addr & A3000_XFER_MASK ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(a3000_host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+	HDATA(a3000_host)->dma_bounce_buffer =
+	    kmalloc (HDATA(a3000_host)->dma_bounce_len, GFP_KERNEL);
+	
+	/* can't allocate memory; use PIO */
+	if (!HDATA(a3000_host)->dma_bounce_buffer) {
+	    HDATA(a3000_host)->dma_bounce_len = 0;
+	    return 1;
+	}
+
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    if (cmd->use_sg) {
+		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+			cmd->SCp.ptr, cmd->SCp.this_residual);
+	    } else
+		memcpy (HDATA(a3000_host)->dma_bounce_buffer,
+			cmd->request_buffer, cmd->request_bufflen);
+	}
+
+	addr = virt_to_bus(HDATA(a3000_host)->dma_bounce_buffer);
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= CNTR_DDIR;
+
+    /* remember direction */
+    HDATA(a3000_host)->dma_dir = dir_in;
+
+    DMA(a3000_host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(a3000_host)->ACR = addr;
+
+    if (dir_in)
+  	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    else
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+
+    /* start DMA */
+    mb();			/* make sure setup is completed */
+    DMA(a3000_host)->ST_DMA = 1;
+    mb();			/* make sure DMA has started before next IO */
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		      int status)
+{
+    /* disable SCSI interrupts */
+    unsigned short cntr = CNTR_PDMD;
+
+    if (!HDATA(instance)->dma_dir)
+	cntr |= CNTR_DDIR;
+
+    DMA(instance)->CNTR = cntr;
+    mb();			/* make sure CNTR is updated before next IO */
+
+    /* flush if we were reading */
+    if (HDATA(instance)->dma_dir) {
+	DMA(instance)->FLUSH = 1;
+	mb();			/* don't allow prefetch */
+	while (!(DMA(instance)->ISTR & ISTR_FE_FLG))
+	    barrier();
+	mb();			/* no IO until FLUSH is done */
+    }
+
+    /* clear a possible interrupt */
+    /* I think that this CINT is only necessary if you are
+     * using the terminal count features.   HM 7 Mar 1994
+     */
+    DMA(instance)->CINT = 1;
+
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+    mb();			/* make sure DMA is stopped before next IO */
+
+    /* restore the CONTROL bits (minus the direction flag) */
+    DMA(instance)->CNTR = CNTR_PDMD | CNTR_INTEN;
+    mb();			/* make sure CNTR is updated before next IO */
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (SCpnt && SCpnt->use_sg) {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->SCp.ptr,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->SCp.this_residual);
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	} else {
+	    if (HDATA(instance)->dma_dir && SCpnt)
+		memcpy (SCpnt->request_buffer,
+			HDATA(instance)->dma_bounce_buffer,
+			SCpnt->request_bufflen);
+
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	    HDATA(instance)->dma_bounce_buffer = NULL;
+	    HDATA(instance)->dma_bounce_len = 0;
+	}
+    }
+}
+
+int __init a3000_detect(Scsi_Host_Template *tpnt)
+{
+    wd33c93_regs regs;
+
+    if  (!MACH_IS_AMIGA || !AMIGAHW_PRESENT(A3000_SCSI))
+	return 0;
+    if (!request_mem_region(0xDD0000, 256, "wd33c93"))
+	return 0;
+
+    tpnt->proc_name = "A3000";
+    tpnt->proc_info = &wd33c93_proc_info;
+
+    a3000_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
+    if (a3000_host == NULL)
+	goto fail_register;
+
+    a3000_host->base = ZTWO_VADDR(0xDD0000);
+    a3000_host->irq = IRQ_AMIGA_PORTS;
+    DMA(a3000_host)->DAWR = DAWR_A3000;
+    regs.SASR = &(DMA(a3000_host)->SASR);
+    regs.SCMD = &(DMA(a3000_host)->SCMD);
+    wd33c93_init(a3000_host, regs, dma_setup, dma_stop, WD33C93_FS_12_15);
+    if (request_irq(IRQ_AMIGA_PORTS, a3000_intr, SA_SHIRQ, "A3000 SCSI",
+		    a3000_intr))
+        goto fail_irq;
+    DMA(a3000_host)->CNTR = CNTR_PDMD | CNTR_INTEN;
+
+    return 1;
+
+fail_irq:
+    wd33c93_release();
+    scsi_unregister(a3000_host);
+fail_register:
+    release_mem_region(0xDD0000, 256);
+    return 0;
+}
+
+static int a3000_bus_reset(Scsi_Cmnd *cmd)
+{
+	/* FIXME perform bus-specific reset */
+	wd33c93_host_reset(cmd);
+	return SUCCESS;
+}
+
+#define HOSTS_C
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "A3000",
+	.name			= "Amiga 3000 built-in SCSI",
+	.detect			= a3000_detect,
+	.release		= a3000_release,
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_bus_reset_handler	= a3000_bus_reset,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+int a3000_release(struct Scsi_Host *instance)
+{
+    wd33c93_release();
+    DMA(instance)->CNTR = 0;
+    release_mem_region(0xDD0000, 256);
+    free_irq(IRQ_AMIGA_PORTS, a3000_intr);
+    return 1;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
new file mode 100644
index 0000000..b1eda73
--- /dev/null
+++ b/drivers/scsi/a3000.h
@@ -0,0 +1,79 @@
+#ifndef A3000_H
+#define A3000_H
+
+/* $Id: a3000.h,v 1.4 1997/01/19 23:07:10 davem Exp $
+ *
+ * Header file for the Amiga 3000 built-in SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see a3000.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int a3000_detect(Scsi_Host_Template *);
+int a3000_release(struct Scsi_Host *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */
+#define A3000_XFER_MASK  (0x00000003)
+
+typedef struct {
+             unsigned char      pad1[2];
+    volatile unsigned short     DAWR;
+    volatile unsigned int       WTC;
+             unsigned char      pad2[2];
+    volatile unsigned short     CNTR;
+    volatile unsigned long      ACR;
+             unsigned char      pad3[2];
+    volatile unsigned short     ST_DMA;
+             unsigned char      pad4[2];
+    volatile unsigned short     FLUSH;
+             unsigned char      pad5[2];
+    volatile unsigned short     CINT;
+             unsigned char      pad6[2];
+    volatile unsigned short     ISTR;
+	     unsigned char      pad7[30];
+    volatile unsigned short     SP_DMA;
+             unsigned char      pad8;
+    volatile unsigned char      SASR;
+             unsigned char      pad9;
+    volatile unsigned char      SCMD;
+} a3000_scsiregs;
+
+#define DAWR_A3000		(3)
+
+/* CNTR bits. */
+#define CNTR_TCEN		(1<<5)
+#define CNTR_PREST		(1<<4)
+#define CNTR_PDMD		(1<<3)
+#define CNTR_INTEN		(1<<2)
+#define CNTR_DDIR		(1<<1)
+#define CNTR_IO_DX		(1<<0)
+
+/* ISTR bits. */
+#define ISTR_INTX		(1<<8)
+#define ISTR_INT_F		(1<<7)
+#define ISTR_INTS		(1<<6)
+#define ISTR_E_INT		(1<<5)
+#define ISTR_INT_P		(1<<4)
+#define ISTR_UE_INT		(1<<3)
+#define ISTR_OE_INT		(1<<2)
+#define ISTR_FF_FLG		(1<<1)
+#define ISTR_FE_FLG		(1<<0)
+
+#endif /* A3000_H */
diff --git a/drivers/scsi/aacraid/Makefile b/drivers/scsi/aacraid/Makefile
new file mode 100644
index 0000000..28d133a
--- /dev/null
+++ b/drivers/scsi/aacraid/Makefile
@@ -0,0 +1,8 @@
+# Adaptec aacraid
+
+obj-$(CONFIG_SCSI_AACRAID) := aacraid.o
+
+aacraid-objs	:= linit.o aachba.o commctrl.o comminit.o commsup.o \
+		   dpcsup.o rx.o sa.o rkt.o
+
+EXTRA_CFLAGS	:= -Idrivers/scsi
diff --git a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README
new file mode 100644
index 0000000..fdb0f45
--- /dev/null
+++ b/drivers/scsi/aacraid/README
@@ -0,0 +1,66 @@
+AACRAID Driver for Linux (take two)
+
+Introduction
+-------------------------
+The aacraid driver adds support for Adaptec (http://www.adaptec.com)
+RAID controllers. This is a major rewrite from the original 
+Adaptec supplied driver. It has signficantly cleaned up both the code
+and the running binary size (the module is less than half the size of
+the original).
+
+Supported Cards/Chipsets
+-------------------------
+	Adaptec 2020S
+	Adaptec 2025S
+	Adaptec 2120S
+	Adaptec 2200S
+	Adaptec 2230S
+	Adaptec 2240S
+	Adaptec 2410SA
+	Adaptec 2610SA
+	Adaptec 2810SA
+	Adaptec 21610SA
+	Adaptec 3230S
+	Adaptec 3240S
+	Adaptec 4000SAS
+	Adaptec 4005SAS
+	Adaptec 4800SAS
+	Adaptec 4805SAS
+	Adaptec 5400S
+	Dell PERC 2 Quad Channel
+	Dell PERC 2/Si
+	Dell PERC 3/Si
+	Dell PERC 3/Di
+	Dell CERC 2
+	HP NetRAID-4M
+	Legend S220
+	Legend S230
+
+People
+-------------------------
+Alan Cox <alan@redhat.com>
+Christoph Hellwig <hch@infradead.org>	(updates for new-style PCI probing and SCSI host registration,
+					 small cleanups/fixes)
+Matt Domsch <matt_domsch@dell.com>	(revision ioctl, adapter messages)
+Deanna Bonds                            (non-DASD support, PAE fibs and 64 bit, added new adaptec controllers
+					 added new ioctls, changed scsi interface to use new error handler,
+					 increased the number of fibs and outstanding commands to a container)
+
+					(fixed 64bit and 64G memory model, changed confusing naming convention
+					 where fibs that go to the hardware are consistently called hw_fibs and
+					 not just fibs like the name of the driver tracking structure)
+Mark Salyzyn <Mark_Salyzyn@adaptec.com> Fixed panic issues and added some new product ids for upcoming hbas.
+
+Original Driver
+-------------------------
+Adaptec Unix OEM Product Group
+
+Mailing List
+-------------------------
+linux-scsi@vger.kernel.org (Interested parties troll here)
+Also note this is very different to Brian's original driver
+so don't expect him to support it.
+Adaptec does support this driver.  Contact either tech support or Mark Salyzyn.
+
+Original by Brian Boerner February 2001
+Rewritten by Alan Cox, November 2001
diff --git a/drivers/scsi/aacraid/TODO b/drivers/scsi/aacraid/TODO
new file mode 100644
index 0000000..25856a21
--- /dev/null
+++ b/drivers/scsi/aacraid/TODO
@@ -0,0 +1,6 @@
+o	Testing
+o	More testing
+o	Feature request: display the firmware/bios/etc revisions in the
+	/proc info
+o	Drop irq_mask, basically unused
+o	I/O size increase
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
new file mode 100644
index 0000000..f3fc353
--- /dev/null
+++ b/drivers/scsi/aacraid/aachba.c
@@ -0,0 +1,2037 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+/* values for inqd_pdt: Peripheral device type in plain English */
+#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03	/* Processor device */
+#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
+
+#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
+
+#define MAX_FIB_DATA (sizeof(struct hw_fib) - sizeof(FIB_HEADER))
+
+#define MAX_DRIVER_SG_SEGMENT_COUNT 17
+
+/*
+ *	Sense codes
+ */
+ 
+#define SENCODE_NO_SENSE                        0x00
+#define SENCODE_END_OF_DATA                     0x00
+#define SENCODE_BECOMING_READY                  0x04
+#define SENCODE_INIT_CMD_REQUIRED               0x04
+#define SENCODE_PARAM_LIST_LENGTH_ERROR         0x1A
+#define SENCODE_INVALID_COMMAND                 0x20
+#define SENCODE_LBA_OUT_OF_RANGE                0x21
+#define SENCODE_INVALID_CDB_FIELD               0x24
+#define SENCODE_LUN_NOT_SUPPORTED               0x25
+#define SENCODE_INVALID_PARAM_FIELD             0x26
+#define SENCODE_PARAM_NOT_SUPPORTED             0x26
+#define SENCODE_PARAM_VALUE_INVALID             0x26
+#define SENCODE_RESET_OCCURRED                  0x29
+#define SENCODE_LUN_NOT_SELF_CONFIGURED_YET     0x3E
+#define SENCODE_INQUIRY_DATA_CHANGED            0x3F
+#define SENCODE_SAVING_PARAMS_NOT_SUPPORTED     0x39
+#define SENCODE_DIAGNOSTIC_FAILURE              0x40
+#define SENCODE_INTERNAL_TARGET_FAILURE         0x44
+#define SENCODE_INVALID_MESSAGE_ERROR           0x49
+#define SENCODE_LUN_FAILED_SELF_CONFIG          0x4c
+#define SENCODE_OVERLAPPED_COMMAND              0x4E
+
+/*
+ *	Additional sense codes
+ */
+ 
+#define ASENCODE_NO_SENSE                       0x00
+#define ASENCODE_END_OF_DATA                    0x05
+#define ASENCODE_BECOMING_READY                 0x01
+#define ASENCODE_INIT_CMD_REQUIRED              0x02
+#define ASENCODE_PARAM_LIST_LENGTH_ERROR        0x00
+#define ASENCODE_INVALID_COMMAND                0x00
+#define ASENCODE_LBA_OUT_OF_RANGE               0x00
+#define ASENCODE_INVALID_CDB_FIELD              0x00
+#define ASENCODE_LUN_NOT_SUPPORTED              0x00
+#define ASENCODE_INVALID_PARAM_FIELD            0x00
+#define ASENCODE_PARAM_NOT_SUPPORTED            0x01
+#define ASENCODE_PARAM_VALUE_INVALID            0x02
+#define ASENCODE_RESET_OCCURRED                 0x00
+#define ASENCODE_LUN_NOT_SELF_CONFIGURED_YET    0x00
+#define ASENCODE_INQUIRY_DATA_CHANGED           0x03
+#define ASENCODE_SAVING_PARAMS_NOT_SUPPORTED    0x00
+#define ASENCODE_DIAGNOSTIC_FAILURE             0x80
+#define ASENCODE_INTERNAL_TARGET_FAILURE        0x00
+#define ASENCODE_INVALID_MESSAGE_ERROR          0x00
+#define ASENCODE_LUN_FAILED_SELF_CONFIG         0x00
+#define ASENCODE_OVERLAPPED_COMMAND             0x00
+
+#define BYTE0(x) (unsigned char)(x)
+#define BYTE1(x) (unsigned char)((x) >> 8)
+#define BYTE2(x) (unsigned char)((x) >> 16)
+#define BYTE3(x) (unsigned char)((x) >> 24)
+
+/*------------------------------------------------------------------------------
+ *              S T R U C T S / T Y P E D E F S
+ *----------------------------------------------------------------------------*/
+/* SCSI inquiry data */
+struct inquiry_data {
+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
+	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
+	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
+	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
+	u8 inqd_len;	/* Additional length (n-4) */
+	u8 inqd_pad1[2];/* Reserved - must be zero */
+	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	u8 inqd_vid[8];	/* Vendor ID */
+	u8 inqd_pid[16];/* Product ID */
+	u8 inqd_prl[4];	/* Product Revision Level */
+};
+
+/*
+ *              M O D U L E   G L O B A L S
+ */
+ 
+static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* sgmap);
+static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg);
+static int aac_send_srb_fib(struct scsi_cmnd* scsicmd);
+#ifdef AAC_DETAILED_STATUS_INFO
+static char *aac_get_status_string(u32 status);
+#endif
+
+/*
+ *	Non dasd selection is handled entirely in aachba now
+ */	
+ 
+static int nondasd = -1;
+static int dacmode = -1;
+
+static int commit = -1;
+
+module_param(nondasd, int, 0);
+MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+module_param(dacmode, int, 0);
+MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on");
+module_param(commit, int, 0);
+MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on");
+
+/**
+ *	aac_get_config_status	-	check the adapter configuration
+ *	@common: adapter to query
+ *
+ *	Query config status, and commit the configuration if needed.
+ */
+int aac_get_config_status(struct aac_dev *dev)
+{
+	int status = 0;
+	struct fib * fibptr;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	{
+		struct aac_get_config_status *dinfo;
+		dinfo = (struct aac_get_config_status *) fib_data(fibptr);
+
+		dinfo->command = cpu_to_le32(VM_ContainerConfig);
+		dinfo->type = cpu_to_le32(CT_GET_CONFIG_STATUS);
+		dinfo->count = cpu_to_le32(sizeof(((struct aac_get_config_status_resp *)NULL)->data));
+	}
+
+	status = fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof (struct aac_get_config_status),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL);
+	if (status < 0 ) {
+		printk(KERN_WARNING "aac_get_config_status: SendFIB failed.\n");
+	} else {
+		struct aac_get_config_status_resp *reply
+		  = (struct aac_get_config_status_resp *) fib_data(fibptr);
+		dprintk((KERN_WARNING
+		  "aac_get_config_status: response=%d status=%d action=%d\n",
+		  le32_to_cpu(reply->response),
+		  le32_to_cpu(reply->status),
+		  le32_to_cpu(reply->data.action)));
+		if ((le32_to_cpu(reply->response) != ST_OK) ||
+		     (le32_to_cpu(reply->status) != CT_OK) ||
+		     (le32_to_cpu(reply->data.action) > CFACT_PAUSE)) {
+			printk(KERN_WARNING "aac_get_config_status: Will not issue the Commit Configuration\n");
+			status = -EINVAL;
+		}
+	}
+	fib_complete(fibptr);
+	/* Send a CT_COMMIT_CONFIG to enable discovery of devices */
+	if (status >= 0) {
+		if (commit == 1) {
+			struct aac_commit_config * dinfo;
+			fib_init(fibptr);
+			dinfo = (struct aac_commit_config *) fib_data(fibptr);
+	
+			dinfo->command = cpu_to_le32(VM_ContainerConfig);
+			dinfo->type = cpu_to_le32(CT_COMMIT_CONFIG);
+	
+			status = fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof (struct aac_commit_config),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL);
+			fib_complete(fibptr);
+		} else if (commit == 0) {
+			printk(KERN_WARNING
+			  "aac_get_config_status: Foreign device configurations are being ignored\n");
+		}
+	}
+	fib_free(fibptr);
+	return status;
+}
+
+/**
+ *	aac_get_containers	-	list containers
+ *	@common: adapter to probe
+ *
+ *	Make a list of all containers on this controller
+ */
+int aac_get_containers(struct aac_dev *dev)
+{
+	struct fsa_dev_info *fsa_dev_ptr;
+	u32 index; 
+	int status = 0;
+	struct fib * fibptr;
+	unsigned instance;
+	struct aac_get_container_count *dinfo;
+	struct aac_get_container_count_resp *dresp;
+	int maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
+
+	instance = dev->scsi_host_ptr->unique_id;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	dinfo = (struct aac_get_container_count *) fib_data(fibptr);
+	dinfo->command = cpu_to_le32(VM_ContainerConfig);
+	dinfo->type = cpu_to_le32(CT_GET_CONTAINER_COUNT);
+
+	status = fib_send(ContainerCommand,
+		    fibptr,
+		    sizeof (struct aac_get_container_count),
+		    FsaNormal,
+		    1, 1,
+		    NULL, NULL);
+	if (status >= 0) {
+		dresp = (struct aac_get_container_count_resp *)fib_data(fibptr);
+		maximum_num_containers = le32_to_cpu(dresp->ContainerSwitchEntries);
+		fib_complete(fibptr);
+	}
+
+	if (maximum_num_containers < MAXIMUM_NUM_CONTAINERS)
+		maximum_num_containers = MAXIMUM_NUM_CONTAINERS;
+
+	fsa_dev_ptr = (struct fsa_dev_info *) kmalloc(
+	  sizeof(*fsa_dev_ptr) * maximum_num_containers, GFP_KERNEL);
+	if (!fsa_dev_ptr) {
+		fib_free(fibptr);
+		return -ENOMEM;
+	}
+	memset(fsa_dev_ptr, 0, sizeof(*fsa_dev_ptr) * maximum_num_containers);
+
+	dev->fsa_dev = fsa_dev_ptr;
+	dev->maximum_num_containers = maximum_num_containers;
+
+	for (index = 0; index < dev->maximum_num_containers; index++) {
+		struct aac_query_mount *dinfo;
+		struct aac_mount *dresp;
+
+		fsa_dev_ptr[index].devname[0] = '\0';
+
+		fib_init(fibptr);
+		dinfo = (struct aac_query_mount *) fib_data(fibptr);
+
+		dinfo->command = cpu_to_le32(VM_NameServe);
+		dinfo->count = cpu_to_le32(index);
+		dinfo->type = cpu_to_le32(FT_FILESYS);
+
+		status = fib_send(ContainerCommand,
+				    fibptr,
+				    sizeof (struct aac_query_mount),
+				    FsaNormal,
+				    1, 1,
+				    NULL, NULL);
+		if (status < 0 ) {
+			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
+			break;
+		}
+		dresp = (struct aac_mount *)fib_data(fibptr);
+
+		dprintk ((KERN_DEBUG
+		  "VM_NameServe cid=%d status=%d vol=%d state=%d cap=%u\n",
+		  (int)index, (int)le32_to_cpu(dresp->status),
+		  (int)le32_to_cpu(dresp->mnt[0].vol),
+		  (int)le32_to_cpu(dresp->mnt[0].state),
+		  (unsigned)le32_to_cpu(dresp->mnt[0].capacity)));
+		if ((le32_to_cpu(dresp->status) == ST_OK) &&
+		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
+			fsa_dev_ptr[index].valid = 1;
+			fsa_dev_ptr[index].type = le32_to_cpu(dresp->mnt[0].vol);
+			fsa_dev_ptr[index].size = le32_to_cpu(dresp->mnt[0].capacity);
+			if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
+				    fsa_dev_ptr[index].ro = 1;
+		}
+		fib_complete(fibptr);
+		/*
+		 *	If there are no more containers, then stop asking.
+		 */
+		if ((index + 1) >= le32_to_cpu(dresp->count)){
+			break;
+		}
+	}
+	fib_free(fibptr);
+	return status;
+}
+
+static void aac_io_done(struct scsi_cmnd * scsicmd)
+{
+	unsigned long cpu_flags;
+	struct Scsi_Host *host = scsicmd->device->host;
+	spin_lock_irqsave(host->host_lock, cpu_flags);
+	scsicmd->scsi_done(scsicmd);
+	spin_unlock_irqrestore(host->host_lock, cpu_flags);
+}
+
+static void get_container_name_callback(void *context, struct fib * fibptr)
+{
+	struct aac_get_name_resp * get_name_reply;
+	struct scsi_cmnd * scsicmd;
+
+	scsicmd = (struct scsi_cmnd *) context;
+
+	dprintk((KERN_DEBUG "get_container_name_callback[cpu %d]: t = %ld.\n", smp_processor_id(), jiffies));
+	if (fibptr == NULL)
+		BUG();
+
+	get_name_reply = (struct aac_get_name_resp *) fib_data(fibptr);
+	/* Failure is irrelevant, using default value instead */
+	if ((le32_to_cpu(get_name_reply->status) == CT_OK)
+	 && (get_name_reply->data[0] != '\0')) {
+		int    count;
+		char * dp;
+		char * sp = get_name_reply->data;
+		sp[sizeof(((struct aac_get_name_resp *)NULL)->data)-1] = '\0';
+		while (*sp == ' ')
+			++sp;
+		count = sizeof(((struct inquiry_data *)NULL)->inqd_pid);
+		dp = ((struct inquiry_data *)scsicmd->request_buffer)->inqd_pid;
+		if (*sp) do {
+			*dp++ = (*sp) ? *sp++ : ' ';
+		} while (--count > 0);
+	}
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
+/**
+ *	aac_get_container_name	-	get container name, none blocking.
+ */
+static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid)
+{
+	int status;
+	struct aac_get_name *dinfo;
+	struct fib * cmd_fibcontext;
+	struct aac_dev * dev;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+	if (!(cmd_fibcontext = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(cmd_fibcontext);
+	dinfo = (struct aac_get_name *) fib_data(cmd_fibcontext);
+
+	dinfo->command = cpu_to_le32(VM_ContainerConfig);
+	dinfo->type = cpu_to_le32(CT_READ_NAME);
+	dinfo->cid = cpu_to_le32(cid);
+	dinfo->count = cpu_to_le32(sizeof(((struct aac_get_name_resp *)NULL)->data));
+
+	status = fib_send(ContainerCommand, 
+		  cmd_fibcontext, 
+		  sizeof (struct aac_get_name),
+		  FsaNormal, 
+		  0, 1, 
+		  (fib_callback) get_container_name_callback, 
+		  (void *) scsicmd);
+	
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) 
+		return 0;
+		
+	printk(KERN_WARNING "aac_get_container_name: fib_send failed with status: %d.\n", status);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return -1;
+}
+
+/**
+ *	probe_container		-	query a logical volume
+ *	@dev: device to query
+ *	@cid: container identifier
+ *
+ *	Queries the controller about the given volume. The volume information
+ *	is updated in the struct fsa_dev_info structure rather than returned.
+ */
+ 
+static int probe_container(struct aac_dev *dev, int cid)
+{
+	struct fsa_dev_info *fsa_dev_ptr;
+	int status;
+	struct aac_query_mount *dinfo;
+	struct aac_mount *dresp;
+	struct fib * fibptr;
+	unsigned instance;
+
+	fsa_dev_ptr = dev->fsa_dev;
+	instance = dev->scsi_host_ptr->unique_id;
+
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+
+	dinfo = (struct aac_query_mount *)fib_data(fibptr);
+
+	dinfo->command = cpu_to_le32(VM_NameServe);
+	dinfo->count = cpu_to_le32(cid);
+	dinfo->type = cpu_to_le32(FT_FILESYS);
+
+	status = fib_send(ContainerCommand,
+			    fibptr,
+			    sizeof(struct aac_query_mount),
+			    FsaNormal,
+			    1, 1,
+			    NULL, NULL);
+	if (status < 0) {
+		printk(KERN_WARNING "aacraid: probe_containers query failed.\n");
+		goto error;
+	}
+
+	dresp = (struct aac_mount *) fib_data(fibptr);
+
+	if ((le32_to_cpu(dresp->status) == ST_OK) &&
+	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+	    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
+		fsa_dev_ptr[cid].valid = 1;
+		fsa_dev_ptr[cid].type = le32_to_cpu(dresp->mnt[0].vol);
+		fsa_dev_ptr[cid].size = le32_to_cpu(dresp->mnt[0].capacity);
+		if (le32_to_cpu(dresp->mnt[0].state) & FSCS_READONLY)
+			fsa_dev_ptr[cid].ro = 1;
+	}
+
+error:
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	return status;
+}
+
+/* Local Structure to set SCSI inquiry data strings */
+struct scsi_inq {
+	char vid[8];         /* Vendor ID */
+	char pid[16];        /* Product ID */
+	char prl[4];         /* Product Revision Level */
+};
+
+/**
+ *	InqStrCopy	-	string merge
+ *	@a:	string to copy from
+ *	@b:	string to copy to
+ *
+ * 	Copy a String from one location to another
+ *	without copying \0
+ */
+
+static void inqstrcpy(char *a, char *b)
+{
+
+	while(*a != (char)0) 
+		*b++ = *a++;
+}
+
+static char *container_types[] = {
+        "None",
+        "Volume",
+        "Mirror",
+        "Stripe",
+        "RAID5",
+        "SSRW",
+        "SSRO",
+        "Morph",
+        "Legacy",
+        "RAID4",
+        "RAID10",             
+        "RAID00",             
+        "V-MIRRORS",          
+        "PSEUDO R4",          
+	"RAID50",
+        "Unknown"
+};
+
+
+
+/* Function: setinqstr
+ *
+ * Arguments: [1] pointer to void [1] int
+ *
+ * Purpose: Sets SCSI inquiry data strings for vendor, product
+ * and revision level. Allows strings to be set in platform dependant
+ * files instead of in OS dependant driver source.
+ */
+
+static void setinqstr(int devtype, void *data, int tindex)
+{
+	struct scsi_inq *str;
+	struct aac_driver_ident *mp;
+
+	mp = aac_get_driver_ident(devtype);
+   
+	str = (struct scsi_inq *)(data); /* cast data to scsi inq block */
+
+	inqstrcpy (mp->vname, str->vid); 
+	inqstrcpy (mp->model, str->pid); /* last six chars reserved for vol type */
+
+	if (tindex < (sizeof(container_types)/sizeof(char *))){
+		char *findit = str->pid;
+
+		for ( ; *findit != ' '; findit++); /* walk till we find a space */
+		/* RAID is superfluous in the context of a RAID device */
+		if (memcmp(findit-4, "RAID", 4) == 0)
+			*(findit -= 4) = ' ';
+		inqstrcpy (container_types[tindex], findit + 1);
+	}
+	inqstrcpy ("V1.0", str->prl);
+}
+
+void set_sense(u8 *sense_buf, u8 sense_key, u8 sense_code,
+		    u8 a_sense_code, u8 incorrect_length,
+		    u8 bit_pointer, u16 field_pointer,
+		    u32 residue)
+{
+	sense_buf[0] = 0xF0;	/* Sense data valid, err code 70h (current error) */
+	sense_buf[1] = 0;	/* Segment number, always zero */
+
+	if (incorrect_length) {
+		sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */
+		sense_buf[3] = BYTE3(residue);
+		sense_buf[4] = BYTE2(residue);
+		sense_buf[5] = BYTE1(residue);
+		sense_buf[6] = BYTE0(residue);
+	} else
+		sense_buf[2] = sense_key;	/* Sense key */
+
+	if (sense_key == ILLEGAL_REQUEST)
+		sense_buf[7] = 10;	/* Additional sense length */
+	else
+		sense_buf[7] = 6;	/* Additional sense length */
+
+	sense_buf[12] = sense_code;	/* Additional sense code */
+	sense_buf[13] = a_sense_code;	/* Additional sense code qualifier */
+	if (sense_key == ILLEGAL_REQUEST) {
+		sense_buf[15] = 0;
+
+		if (sense_code == SENCODE_INVALID_PARAM_FIELD)
+			sense_buf[15] = 0x80;/* Std sense key specific field */
+		/* Illegal parameter is in the parameter block */
+
+		if (sense_code == SENCODE_INVALID_CDB_FIELD)
+			sense_buf[15] = 0xc0;/* Std sense key specific field */
+		/* Illegal parameter is in the CDB block */
+		sense_buf[15] |= bit_pointer;
+		sense_buf[16] = field_pointer >> 8;	/* MSB */
+		sense_buf[17] = field_pointer;		/* LSB */
+	}
+}
+
+int aac_get_adapter_info(struct aac_dev* dev)
+{
+	struct fib* fibptr;
+	struct aac_adapter_info* info;
+	int rcode;
+	u32 tmp;
+	if (!(fibptr = fib_alloc(dev)))
+		return -ENOMEM;
+
+	fib_init(fibptr);
+	info = (struct aac_adapter_info*) fib_data(fibptr);
+
+	memset(info,0,sizeof(struct aac_adapter_info));
+
+	rcode = fib_send(RequestAdapterInfo,
+			fibptr, 
+			sizeof(struct aac_adapter_info),
+			FsaNormal, 
+			1, 1, 
+			NULL, 
+			NULL);
+
+	memcpy(&dev->adapter_info, info, sizeof(struct aac_adapter_info));
+
+	tmp = le32_to_cpu(dev->adapter_info.kernelrev);
+	printk(KERN_INFO "%s%d: kernel %d.%d-%d[%d]\n", 
+			dev->name, 
+			dev->id,
+			tmp>>24,
+			(tmp>>16)&0xff,
+			tmp&0xff,
+			le32_to_cpu(dev->adapter_info.kernelbuild));
+	tmp = le32_to_cpu(dev->adapter_info.monitorrev);
+	printk(KERN_INFO "%s%d: monitor %d.%d-%d[%d]\n", 
+			dev->name, dev->id,
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.monitorbuild));
+	tmp = le32_to_cpu(dev->adapter_info.biosrev);
+	printk(KERN_INFO "%s%d: bios %d.%d-%d[%d]\n", 
+			dev->name, dev->id,
+			tmp>>24,(tmp>>16)&0xff,tmp&0xff,
+			le32_to_cpu(dev->adapter_info.biosbuild));
+	if (le32_to_cpu(dev->adapter_info.serial[0]) != 0xBAD0)
+		printk(KERN_INFO "%s%d: serial %x\n",
+			dev->name, dev->id,
+			le32_to_cpu(dev->adapter_info.serial[0]));
+
+	dev->nondasd_support = 0;
+	dev->raid_scsi_mode = 0;
+	if(dev->adapter_info.options & AAC_OPT_NONDASD){
+		dev->nondasd_support = 1;
+	}
+
+	/*
+	 * If the firmware supports ROMB RAID/SCSI mode and we are currently
+	 * in RAID/SCSI mode, set the flag. For now if in this mode we will
+	 * force nondasd support on. If we decide to allow the non-dasd flag
+	 * additional changes changes will have to be made to support
+	 * RAID/SCSI.  the function aac_scsi_cmd in this module will have to be
+	 * changed to support the new dev->raid_scsi_mode flag instead of
+	 * leaching off of the dev->nondasd_support flag. Also in linit.c the
+	 * function aac_detect will have to be modified where it sets up the
+	 * max number of channels based on the aac->nondasd_support flag only.
+	 */
+	if ((dev->adapter_info.options & AAC_OPT_SCSI_MANAGED) &&
+	    (dev->adapter_info.options & AAC_OPT_RAID_SCSI_MODE)) {
+		dev->nondasd_support = 1;
+		dev->raid_scsi_mode = 1;
+	}
+	if (dev->raid_scsi_mode != 0)
+		printk(KERN_INFO "%s%d: ROMB RAID/SCSI mode enabled\n",
+				dev->name, dev->id);
+		
+	if(nondasd != -1) {  
+		dev->nondasd_support = (nondasd!=0);
+	}
+	if(dev->nondasd_support != 0){
+		printk(KERN_INFO "%s%d: Non-DASD support enabled.\n",dev->name, dev->id);
+	}
+
+	dev->dac_support = 0;
+	if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
+		printk(KERN_INFO "%s%d: 64bit support enabled.\n", dev->name, dev->id);
+		dev->dac_support = 1;
+	}
+
+	if(dacmode != -1) {
+		dev->dac_support = (dacmode!=0);
+	}
+	if(dev->dac_support != 0) {
+		if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL) &&
+			!pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFFFFFFFFFULL)) {
+			printk(KERN_INFO"%s%d: 64 Bit DAC enabled\n",
+				dev->name, dev->id);
+		} else if (!pci_set_dma_mask(dev->pdev, 0xFFFFFFFFULL) &&
+			!pci_set_consistent_dma_mask(dev->pdev, 0xFFFFFFFFULL)) {
+			printk(KERN_INFO"%s%d: DMA mask set failed, 64 Bit DAC disabled\n",
+				dev->name, dev->id);
+			dev->dac_support = 0;
+		} else {
+			printk(KERN_WARNING"%s%d: No suitable DMA available.\n",
+				dev->name, dev->id);
+			rcode = -ENOMEM;
+		}
+	}
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	return rcode;
+}
+
+
+static void read_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_read_reply *readreply;
+	struct scsi_cmnd *scsicmd;
+	u32 lba;
+	u32 cid;
+
+	scsicmd = (struct scsi_cmnd *) context;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+
+	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+
+	if (fibptr == NULL)
+		BUG();
+		
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsicmd->sc_data_direction);
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
+				 scsicmd->request_bufflen,
+				 scsicmd->sc_data_direction);
+	readreply = (struct aac_read_reply *)fib_data(fibptr);
+	if (le32_to_cpu(readreply->status) == ST_OK)
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+	else {
+		printk(KERN_WARNING "read_callback: read failed, status = %d\n",
+				le32_to_cpu(readreply->status));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				    HARDWARE_ERROR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+	}
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
+	aac_io_done(scsicmd);
+}
+
+static void write_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_write_reply *writereply;
+	struct scsi_cmnd *scsicmd;
+	u32 lba;
+	u32 cid;
+
+	scsicmd = (struct scsi_cmnd *) context;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+
+	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	if (fibptr == NULL)
+		BUG();
+
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsicmd->sc_data_direction);
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
+				 scsicmd->request_bufflen,
+				 scsicmd->sc_data_direction);
+
+	writereply = (struct aac_write_reply *) fib_data(fibptr);
+	if (le32_to_cpu(writereply->status) == ST_OK)
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+	else {
+		printk(KERN_WARNING "write_callback: write failed, status = %d\n", writereply->status);
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				    HARDWARE_ERROR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, 
+				sizeof(struct sense_data));
+	}
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
+int aac_read(struct scsi_cmnd * scsicmd, int cid)
+{
+	u32 lba;
+	u32 count;
+	int status;
+
+	u16 fibsize;
+	struct aac_dev *dev;
+	struct fib * cmd_fibcontext;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	/*
+	 *	Get block address and transfer length
+	 */
+	if (scsicmd->cmnd[0] == READ_6)	/* 6 byte command */
+	{
+		dprintk((KERN_DEBUG "aachba: received a read(6) command on id %d.\n", cid));
+
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+		count = scsicmd->cmnd[4];
+
+		if (count == 0)
+			count = 256;
+	} else {
+		dprintk((KERN_DEBUG "aachba: received a read(10) command on id %d.\n", cid));
+
+		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+	}
+	dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	/*
+	 *	Alocate and initialize a Fib
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		return -1;
+	}
+
+	fib_init(cmd_fibcontext);
+
+	if(dev->dac_support == 1) {
+		struct aac_read64 *readcmd;
+		readcmd = (struct aac_read64 *) fib_data(cmd_fibcontext);
+		readcmd->command = cpu_to_le32(VM_CtHostRead64);
+		readcmd->cid = cpu_to_le16(cid);
+		readcmd->sector_count = cpu_to_le16(count);
+		readcmd->block = cpu_to_le32(lba);
+		readcmd->pad   = 0;
+		readcmd->flags = 0; 
+
+		aac_build_sg64(scsicmd, &readcmd->sg);
+		fibsize = sizeof(struct aac_read64) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand64, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) read_callback, 
+			  (void *) scsicmd);
+	} else {
+		struct aac_read *readcmd;
+		readcmd = (struct aac_read *) fib_data(cmd_fibcontext);
+		readcmd->command = cpu_to_le32(VM_CtBlockRead);
+		readcmd->cid = cpu_to_le32(cid);
+		readcmd->block = cpu_to_le32(lba);
+		readcmd->count = cpu_to_le32(count * 512);
+
+		if (count * 512 > (64 * 1024))
+			BUG();
+
+		aac_build_sg(scsicmd, &readcmd->sg);
+		fibsize = sizeof(struct aac_read) + 
+			((le32_to_cpu(readcmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) read_callback, 
+			  (void *) scsicmd);
+	}
+
+	
+
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS) 
+		return 0;
+		
+	printk(KERN_WARNING "aac_read: fib_send failed with status: %d.\n", status);
+	/*
+	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+	 */
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
+	aac_io_done(scsicmd);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return 0;
+}
+
+static int aac_write(struct scsi_cmnd * scsicmd, int cid)
+{
+	u32 lba;
+	u32 count;
+	int status;
+	u16 fibsize;
+	struct aac_dev *dev;
+	struct fib * cmd_fibcontext;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	/*
+	 *	Get block address and transfer length
+	 */
+	if (scsicmd->cmnd[0] == WRITE_6)	/* 6 byte command */
+	{
+		lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
+		count = scsicmd->cmnd[4];
+		if (count == 0)
+			count = 256;
+	} else {
+		dprintk((KERN_DEBUG "aachba: received a write(10) command on id %d.\n", cid));
+		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
+		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
+	}
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n",
+	  smp_processor_id(), (unsigned long long)lba, jiffies));
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		scsicmd->result = DID_ERROR << 16;
+		aac_io_done(scsicmd);
+		return 0;
+	}
+	fib_init(cmd_fibcontext);
+
+	if(dev->dac_support == 1) {
+		struct aac_write64 *writecmd;
+		writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
+		writecmd->command = cpu_to_le32(VM_CtHostWrite64);
+		writecmd->cid = cpu_to_le16(cid);
+		writecmd->sector_count = cpu_to_le16(count); 
+		writecmd->block = cpu_to_le32(lba);
+		writecmd->pad	= 0;
+		writecmd->flags	= 0;
+
+		aac_build_sg64(scsicmd, &writecmd->sg);
+		fibsize = sizeof(struct aac_write64) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand64, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) write_callback, 
+			  (void *) scsicmd);
+	} else {
+		struct aac_write *writecmd;
+		writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
+		writecmd->command = cpu_to_le32(VM_CtBlockWrite);
+		writecmd->cid = cpu_to_le32(cid);
+		writecmd->block = cpu_to_le32(lba);
+		writecmd->count = cpu_to_le32(count * 512);
+		writecmd->sg.count = cpu_to_le32(1);
+		/* ->stable is not used - it did mean which type of write */
+
+		if (count * 512 > (64 * 1024)) {
+			BUG();
+		}
+
+		aac_build_sg(scsicmd, &writecmd->sg);
+		fibsize = sizeof(struct aac_write) + 
+			((le32_to_cpu(writecmd->sg.count) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ContainerCommand, 
+			  cmd_fibcontext, 
+			  fibsize, 
+			  FsaNormal, 
+			  0, 1, 
+			  (fib_callback) write_callback, 
+			  (void *) scsicmd);
+	}
+
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS)
+	{
+		dprintk("write queued.\n");
+		return 0;
+	}
+
+	printk(KERN_WARNING "aac_write: fib_send failed with status: %d\n", status);
+	/*
+	 *	For some reason, the Fib didn't queue, return QUEUE_FULL
+	 */
+	scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_TASK_SET_FULL;
+	aac_io_done(scsicmd);
+
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return 0;
+}
+
+static void synchronize_callback(void *context, struct fib *fibptr)
+{
+	struct aac_synchronize_reply *synchronizereply;
+	struct scsi_cmnd *cmd;
+
+	cmd = context;
+
+	dprintk((KERN_DEBUG "synchronize_callback[cpu %d]: t = %ld.\n", 
+				smp_processor_id(), jiffies));
+	BUG_ON(fibptr == NULL);
+
+
+	synchronizereply = fib_data(fibptr);
+	if (le32_to_cpu(synchronizereply->status) == CT_OK)
+		cmd->result = DID_OK << 16 | 
+			COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+	else {
+		struct scsi_device *sdev = cmd->device;
+		struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+		u32 cid = ID_LUN_TO_CONTAINER(sdev->id, sdev->lun);
+		printk(KERN_WARNING 
+		     "synchronize_callback: synchronize failed, status = %d\n",
+		     le32_to_cpu(synchronizereply->status));
+		cmd->result = DID_OK << 16 | 
+			COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *)&dev->fsa_dev[cid].sense_data,
+				    HARDWARE_ERROR,
+				    SENCODE_INTERNAL_TARGET_FAILURE,
+				    ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0,
+				    0, 0);
+		memcpy(cmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  min(sizeof(dev->fsa_dev[cid].sense_data), 
+			  sizeof(cmd->sense_buffer)));
+	}
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(cmd);
+}
+
+static int aac_synchronize(struct scsi_cmnd *scsicmd, int cid)
+{
+	int status;
+	struct fib *cmd_fibcontext;
+	struct aac_synchronize *synchronizecmd;
+	struct scsi_cmnd *cmd;
+	struct scsi_device *sdev = scsicmd->device;
+	int active = 0;
+	unsigned long flags;
+
+	/*
+	 * Wait for all commands to complete to this specific
+	 * target (block).
+	 */
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	list_for_each_entry(cmd, &sdev->cmd_list, list)
+		if (cmd != scsicmd && cmd->serial_number != 0) {
+			++active;
+			break;
+		}
+
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+	/*
+	 *	Yield the processor (requeue for later)
+	 */
+	if (active)
+		return SCSI_MLQUEUE_DEVICE_BUSY;
+
+	/*
+	 *	Alocate and initialize a Fib
+	 */
+	if (!(cmd_fibcontext = 
+	    fib_alloc((struct aac_dev *)scsicmd->device->host->hostdata))) 
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	fib_init(cmd_fibcontext);
+
+	synchronizecmd = fib_data(cmd_fibcontext);
+	synchronizecmd->command = cpu_to_le32(VM_ContainerConfig);
+	synchronizecmd->type = cpu_to_le32(CT_FLUSH_CACHE);
+	synchronizecmd->cid = cpu_to_le32(cid);
+	synchronizecmd->count = 
+	     cpu_to_le32(sizeof(((struct aac_synchronize_reply *)NULL)->data));
+
+	/*
+	 *	Now send the Fib to the adapter
+	 */
+	status = fib_send(ContainerCommand,
+		  cmd_fibcontext,
+		  sizeof(struct aac_synchronize),
+		  FsaNormal,
+		  0, 1,
+		  (fib_callback)synchronize_callback,
+		  (void *)scsicmd);
+
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS)
+		return 0;
+
+	printk(KERN_WARNING 
+		"aac_synchronize: fib_send failed with status: %d.\n", status);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+	return SCSI_MLQUEUE_HOST_BUSY;
+}
+
+/**
+ *	aac_scsi_cmd()		-	Process SCSI command
+ *	@scsicmd:		SCSI command block
+ *
+ *	Emulate a SCSI command and queue the required request for the
+ *	aacraid firmware.
+ */
+ 
+int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
+{
+	u32 cid = 0;
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
+	struct fsa_dev_info *fsa_dev_ptr = dev->fsa_dev;
+	int cardtype = dev->cardtype;
+	int ret;
+	
+	/*
+	 *	If the bus, id or lun is out of range, return fail
+	 *	Test does not apply to ID 16, the pseudo id for the controller
+	 *	itself.
+	 */
+	if (scsicmd->device->id != host->this_id) {
+		if ((scsicmd->device->channel == 0) ){
+			if( (scsicmd->device->id >= dev->maximum_num_containers) || (scsicmd->device->lun != 0)){ 
+				scsicmd->result = DID_NO_CONNECT << 16;
+				scsicmd->scsi_done(scsicmd);
+				return 0;
+			}
+			cid = ID_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
+
+			/*
+			 *	If the target container doesn't exist, it may have
+			 *	been newly created
+			 */
+			if ((fsa_dev_ptr[cid].valid & 1) == 0) {
+				switch (scsicmd->cmnd[0]) {
+				case INQUIRY:
+				case READ_CAPACITY:
+				case TEST_UNIT_READY:
+					spin_unlock_irq(host->host_lock);
+					probe_container(dev, cid);
+					spin_lock_irq(host->host_lock);
+					if (fsa_dev_ptr[cid].valid == 0) {
+						scsicmd->result = DID_NO_CONNECT << 16;
+						scsicmd->scsi_done(scsicmd);
+						return 0;
+					}
+				default:
+					break;
+				}
+			}
+			/*
+			 *	If the target container still doesn't exist, 
+			 *	return failure
+			 */
+			if (fsa_dev_ptr[cid].valid == 0) {
+				scsicmd->result = DID_BAD_TARGET << 16;
+				scsicmd->scsi_done(scsicmd);
+				return 0;
+			}
+		} else {  /* check for physical non-dasd devices */
+			if(dev->nondasd_support == 1){
+				return aac_send_srb_fib(scsicmd);
+			} else {
+				scsicmd->result = DID_NO_CONNECT << 16;
+				scsicmd->scsi_done(scsicmd);
+				return 0;
+			}
+		}
+	}
+	/*
+	 * else Command for the controller itself
+	 */
+	else if ((scsicmd->cmnd[0] != INQUIRY) &&	/* only INQUIRY & TUR cmnd supported for controller */
+		(scsicmd->cmnd[0] != TEST_UNIT_READY)) 
+	{
+		dprintk((KERN_WARNING "Only INQUIRY & TUR command supported for controller, rcvd = 0x%x.\n", scsicmd->cmnd[0]));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+			    ILLEGAL_REQUEST,
+			    SENCODE_INVALID_COMMAND,
+			    ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+		  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+		    ? sizeof(scsicmd->sense_buffer)
+		    : sizeof(dev->fsa_dev[cid].sense_data));
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	}
+
+
+	/* Handle commands here that don't really require going out to the adapter */
+	switch (scsicmd->cmnd[0]) {
+	case INQUIRY:
+	{
+		struct inquiry_data *inq_data_ptr;
+
+		dprintk((KERN_DEBUG "INQUIRY command, ID: %d.\n", scsicmd->device->id));
+		inq_data_ptr = (struct inquiry_data *)scsicmd->request_buffer;
+		memset(inq_data_ptr, 0, sizeof (struct inquiry_data));
+
+		inq_data_ptr->inqd_ver = 2;	/* claim compliance to SCSI-2 */
+		inq_data_ptr->inqd_dtq = 0x80;	/* set RMB bit to one indicating that the medium is removable */
+		inq_data_ptr->inqd_rdf = 2;	/* A response data format value of two indicates that the data shall be in the format specified in SCSI-2 */
+		inq_data_ptr->inqd_len = 31;
+		/*Format for "pad2" is  RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+		inq_data_ptr->inqd_pad2= 0x32 ;	 /*WBus16|Sync|CmdQue */
+		/*
+		 *	Set the Vendor, Product, and Revision Level
+		 *	see: <vendor>.c i.e. aac.c
+		 */
+		if (scsicmd->device->id == host->this_id) {
+			setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), (sizeof(container_types)/sizeof(char *)));
+			inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+			scsicmd->scsi_done(scsicmd);
+			return 0;
+		}
+		setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr[cid].type);
+		inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
+		return aac_get_container_name(scsicmd, cid);
+	}
+	case READ_CAPACITY:
+	{
+		u32 capacity;
+		char *cp;
+
+		dprintk((KERN_DEBUG "READ CAPACITY command.\n"));
+		if (fsa_dev_ptr[cid].size <= 0x100000000LL)
+			capacity = fsa_dev_ptr[cid].size - 1;
+		else
+			capacity = (u32)-1;
+		cp = scsicmd->request_buffer;
+		cp[0] = (capacity >> 24) & 0xff;
+		cp[1] = (capacity >> 16) & 0xff;
+		cp[2] = (capacity >> 8) & 0xff;
+		cp[3] = (capacity >> 0) & 0xff;
+		cp[4] = 0;
+		cp[5] = 0;
+		cp[6] = 2;
+		cp[7] = 0;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+
+		return 0;
+	}
+
+	case MODE_SENSE:
+	{
+		char *mode_buf;
+
+		dprintk((KERN_DEBUG "MODE SENSE command.\n"));
+		mode_buf = scsicmd->request_buffer;
+		mode_buf[0] = 3;	/* Mode data length */
+		mode_buf[1] = 0;	/* Medium type - default */
+		mode_buf[2] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
+		mode_buf[3] = 0;	/* Block descriptor length */
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+
+		return 0;
+	}
+	case MODE_SENSE_10:
+	{
+		char *mode_buf;
+
+		dprintk((KERN_DEBUG "MODE SENSE 10 byte command.\n"));
+		mode_buf = scsicmd->request_buffer;
+		mode_buf[0] = 0;	/* Mode data length (MSB) */
+		mode_buf[1] = 6;	/* Mode data length (LSB) */
+		mode_buf[2] = 0;	/* Medium type - default */
+		mode_buf[3] = 0;	/* Device-specific param, bit 8: 0/1 = write enabled/protected */
+		mode_buf[4] = 0;	/* reserved */
+		mode_buf[5] = 0;	/* reserved */
+		mode_buf[6] = 0;	/* Block descriptor length (MSB) */
+		mode_buf[7] = 0;	/* Block descriptor length (LSB) */
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+
+		return 0;
+	}
+	case REQUEST_SENSE:
+		dprintk((KERN_DEBUG "REQUEST SENSE command.\n"));
+		memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, sizeof (struct sense_data));
+		memset(&dev->fsa_dev[cid].sense_data, 0, sizeof (struct sense_data));
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+
+	case ALLOW_MEDIUM_REMOVAL:
+		dprintk((KERN_DEBUG "LOCK command.\n"));
+		if (scsicmd->cmnd[4])
+			fsa_dev_ptr[cid].locked = 1;
+		else
+			fsa_dev_ptr[cid].locked = 0;
+
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	/*
+	 *	These commands are all No-Ops
+	 */
+	case TEST_UNIT_READY:
+	case RESERVE:
+	case RELEASE:
+	case REZERO_UNIT:
+	case REASSIGN_BLOCKS:
+	case SEEK_10:
+	case START_STOP:
+		scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_GOOD;
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	}
+
+	switch (scsicmd->cmnd[0]) 
+	{
+		case READ_6:
+		case READ_10:
+			/*
+			 *	Hack to keep track of ordinal number of the device that
+			 *	corresponds to a container. Needed to convert
+			 *	containers to /dev/sd device names
+			 */
+			 
+			spin_unlock_irq(host->host_lock);
+			if  (scsicmd->request->rq_disk)
+				memcpy(fsa_dev_ptr[cid].devname,
+					scsicmd->request->rq_disk->disk_name,
+					8);
+
+			ret = aac_read(scsicmd, cid);
+			spin_lock_irq(host->host_lock);
+			return ret;
+
+		case WRITE_6:
+		case WRITE_10:
+			spin_unlock_irq(host->host_lock);
+			ret = aac_write(scsicmd, cid);
+			spin_lock_irq(host->host_lock);
+			return ret;
+
+		case SYNCHRONIZE_CACHE:
+			/* Issue FIB to tell Firmware to flush it's cache */
+			return aac_synchronize(scsicmd, cid);
+			
+		default:
+			/*
+			 *	Unhandled commands
+			 */
+			printk(KERN_WARNING "Unhandled SCSI Command: 0x%x.\n", scsicmd->cmnd[0]);
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+			set_sense((u8 *) &dev->fsa_dev[cid].sense_data,
+				ILLEGAL_REQUEST, SENCODE_INVALID_COMMAND,
+				ASENCODE_INVALID_COMMAND, 0, 0, 0, 0);
+			memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data,
+			  (sizeof(dev->fsa_dev[cid].sense_data) > sizeof(scsicmd->sense_buffer))
+			    ? sizeof(scsicmd->sense_buffer)
+			    : sizeof(dev->fsa_dev[cid].sense_data));
+			scsicmd->scsi_done(scsicmd);
+			return 0;
+	}
+}
+
+static int query_disk(struct aac_dev *dev, void __user *arg)
+{
+	struct aac_query_disk qd;
+	struct fsa_dev_info *fsa_dev_ptr;
+
+	fsa_dev_ptr = dev->fsa_dev;
+	if (copy_from_user(&qd, arg, sizeof (struct aac_query_disk)))
+		return -EFAULT;
+	if (qd.cnum == -1)
+		qd.cnum = ID_LUN_TO_CONTAINER(qd.id, qd.lun);
+	else if ((qd.bus == -1) && (qd.id == -1) && (qd.lun == -1)) 
+	{
+		if (qd.cnum < 0 || qd.cnum >= dev->maximum_num_containers)
+			return -EINVAL;
+		qd.instance = dev->scsi_host_ptr->host_no;
+		qd.bus = 0;
+		qd.id = CONTAINER_TO_ID(qd.cnum);
+		qd.lun = CONTAINER_TO_LUN(qd.cnum);
+	}
+	else return -EINVAL;
+
+	qd.valid = fsa_dev_ptr[qd.cnum].valid;
+	qd.locked = fsa_dev_ptr[qd.cnum].locked;
+	qd.deleted = fsa_dev_ptr[qd.cnum].deleted;
+
+	if (fsa_dev_ptr[qd.cnum].devname[0] == '\0')
+		qd.unmapped = 1;
+	else
+		qd.unmapped = 0;
+
+	strlcpy(qd.name, fsa_dev_ptr[qd.cnum].devname,
+	  min(sizeof(qd.name), sizeof(fsa_dev_ptr[qd.cnum].devname) + 1));
+
+	if (copy_to_user(arg, &qd, sizeof (struct aac_query_disk)))
+		return -EFAULT;
+	return 0;
+}
+
+static int force_delete_disk(struct aac_dev *dev, void __user *arg)
+{
+	struct aac_delete_disk dd;
+	struct fsa_dev_info *fsa_dev_ptr;
+
+	fsa_dev_ptr = dev->fsa_dev;
+
+	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+		return -EFAULT;
+
+	if (dd.cnum >= dev->maximum_num_containers)
+		return -EINVAL;
+	/*
+	 *	Mark this container as being deleted.
+	 */
+	fsa_dev_ptr[dd.cnum].deleted = 1;
+	/*
+	 *	Mark the container as no longer valid
+	 */
+	fsa_dev_ptr[dd.cnum].valid = 0;
+	return 0;
+}
+
+static int delete_disk(struct aac_dev *dev, void __user *arg)
+{
+	struct aac_delete_disk dd;
+	struct fsa_dev_info *fsa_dev_ptr;
+
+	fsa_dev_ptr = dev->fsa_dev;
+
+	if (copy_from_user(&dd, arg, sizeof (struct aac_delete_disk)))
+		return -EFAULT;
+
+	if (dd.cnum >= dev->maximum_num_containers)
+		return -EINVAL;
+	/*
+	 *	If the container is locked, it can not be deleted by the API.
+	 */
+	if (fsa_dev_ptr[dd.cnum].locked)
+		return -EBUSY;
+	else {
+		/*
+		 *	Mark the container as no longer being valid.
+		 */
+		fsa_dev_ptr[dd.cnum].valid = 0;
+		fsa_dev_ptr[dd.cnum].devname[0] = '\0';
+		return 0;
+	}
+}
+
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg)
+{
+	switch (cmd) {
+	case FSACTL_QUERY_DISK:
+		return query_disk(dev, arg);
+	case FSACTL_DELETE_DISK:
+		return delete_disk(dev, arg);
+	case FSACTL_FORCE_DELETE_DISK:
+		return force_delete_disk(dev, arg);
+	case FSACTL_GET_CONTAINERS:
+		return aac_get_containers(dev);
+	default:
+		return -ENOTTY;
+	}
+}
+
+/**
+ *
+ * aac_srb_callback
+ * @context: the context set in the fib - here it is scsi cmd
+ * @fibptr: pointer to the fib
+ *
+ * Handles the completion of a scsi command to a non dasd device
+ *
+ */
+
+static void aac_srb_callback(void *context, struct fib * fibptr)
+{
+	struct aac_dev *dev;
+	struct aac_srb_reply *srbreply;
+	struct scsi_cmnd *scsicmd;
+
+	scsicmd = (struct scsi_cmnd *) context;
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+
+	if (fibptr == NULL)
+		BUG();
+
+	srbreply = (struct aac_srb_reply *) fib_data(fibptr);
+
+	scsicmd->sense_buffer[0] = '\0';  /* Initialize sense valid flag to false */
+	/*
+	 *	Calculate resid for sg 
+	 */
+	 
+	scsicmd->resid = scsicmd->request_bufflen - 
+		le32_to_cpu(srbreply->data_xfer_length);
+
+	if(scsicmd->use_sg)
+		pci_unmap_sg(dev->pdev, 
+			(struct scatterlist *)scsicmd->buffer,
+			scsicmd->use_sg,
+			scsicmd->sc_data_direction);
+	else if(scsicmd->request_bufflen)
+		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle, scsicmd->request_bufflen,
+			scsicmd->sc_data_direction);
+
+	/*
+	 * First check the fib status
+	 */
+
+	if (le32_to_cpu(srbreply->status) != ST_OK){
+		int len;
+		printk(KERN_WARNING "aac_srb_callback: srb failed, status = %d\n", le32_to_cpu(srbreply->status));
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) : 
+				le32_to_cpu(srbreply->sense_data_size);
+		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION;
+		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+	}
+
+	/*
+	 * Next check the srb status
+	 */
+	switch( (le32_to_cpu(srbreply->srb_status))&0x3f){
+	case SRB_STATUS_ERROR_RECOVERY:
+	case SRB_STATUS_PENDING:
+	case SRB_STATUS_SUCCESS:
+		if(scsicmd->cmnd[0] == INQUIRY ){
+			u8 b;
+			u8 b1;
+			/* We can't expose disk devices because we can't tell whether they
+			 * are the raw container drives or stand alone drives.  If they have
+			 * the removable bit set then we should expose them though.
+			 */
+			b = (*(u8*)scsicmd->buffer)&0x1f;
+			b1 = ((u8*)scsicmd->buffer)[1];
+			if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER 
+					|| (b==TYPE_DISK && (b1&0x80)) ){
+				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			/*
+			 * We will allow disk devices if in RAID/SCSI mode and
+			 * the channel is 2
+			 */
+			} else if ((dev->raid_scsi_mode) &&
+					(scsicmd->device->channel == 2)) {
+				scsicmd->result = DID_OK << 16 | 
+						COMMAND_COMPLETE << 8;
+			} else {
+				scsicmd->result = DID_NO_CONNECT << 16 | 
+						COMMAND_COMPLETE << 8;
+			}
+		} else {
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+		}
+		break;
+	case SRB_STATUS_DATA_OVERRUN:
+		switch(scsicmd->cmnd[0]){
+		case  READ_6:
+		case  WRITE_6:
+		case  READ_10:
+		case  WRITE_10:
+		case  READ_12:
+		case  WRITE_12:
+			if(le32_to_cpu(srbreply->data_xfer_length) < scsicmd->underflow ) {
+				printk(KERN_WARNING"aacraid: SCSI CMD underflow\n");
+			} else {
+				printk(KERN_WARNING"aacraid: SCSI CMD Data Overrun\n");
+			}
+			scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+			break;
+		case INQUIRY: {
+			u8 b;
+			u8 b1;
+			/* We can't expose disk devices because we can't tell whether they
+			* are the raw container drives or stand alone drives
+			*/
+			b = (*(u8*)scsicmd->buffer)&0x0f;
+			b1 = ((u8*)scsicmd->buffer)[1];
+			if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER
+					|| (b==TYPE_DISK && (b1&0x80)) ){
+				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			/*
+			 * We will allow disk devices if in RAID/SCSI mode and
+			 * the channel is 2
+			 */
+			} else if ((dev->raid_scsi_mode) &&
+					(scsicmd->device->channel == 2)) {
+				scsicmd->result = DID_OK << 16 | 
+						COMMAND_COMPLETE << 8;
+			} else {
+				scsicmd->result = DID_NO_CONNECT << 16 | 
+						COMMAND_COMPLETE << 8;
+			}
+			break;
+		}
+		default:
+			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			break;
+		}
+		break;
+	case SRB_STATUS_ABORTED:
+		scsicmd->result = DID_ABORT << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_ABORT_FAILED:
+		// Not sure about this one - but assuming the hba was trying to abort for some reason
+		scsicmd->result = DID_ERROR << 16 | ABORT << 8;
+		break;
+	case SRB_STATUS_PARITY_ERROR:
+		scsicmd->result = DID_PARITY << 16 | MSG_PARITY_ERROR << 8;
+		break;
+	case SRB_STATUS_NO_DEVICE:
+	case SRB_STATUS_INVALID_PATH_ID:
+	case SRB_STATUS_INVALID_TARGET_ID:
+	case SRB_STATUS_INVALID_LUN:
+	case SRB_STATUS_SELECTION_TIMEOUT:
+		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_COMMAND_TIMEOUT:
+	case SRB_STATUS_TIMEOUT:
+		scsicmd->result = DID_TIME_OUT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUSY:
+		scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_BUS_RESET:
+		scsicmd->result = DID_RESET << 16 | COMMAND_COMPLETE << 8;
+		break;
+
+	case SRB_STATUS_MESSAGE_REJECTED:
+		scsicmd->result = DID_ERROR << 16 | MESSAGE_REJECT << 8;
+		break;
+	case SRB_STATUS_REQUEST_FLUSHED:
+	case SRB_STATUS_ERROR:
+	case SRB_STATUS_INVALID_REQUEST:
+	case SRB_STATUS_REQUEST_SENSE_FAILED:
+	case SRB_STATUS_NO_HBA:
+	case SRB_STATUS_UNEXPECTED_BUS_FREE:
+	case SRB_STATUS_PHASE_SEQUENCE_FAILURE:
+	case SRB_STATUS_BAD_SRB_BLOCK_LENGTH:
+	case SRB_STATUS_DELAYED_RETRY:
+	case SRB_STATUS_BAD_FUNCTION:
+	case SRB_STATUS_NOT_STARTED:
+	case SRB_STATUS_NOT_IN_USE:
+	case SRB_STATUS_FORCE_ABORT:
+	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
+	default:
+#ifdef AAC_DETAILED_STATUS_INFO
+		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",
+			le32_to_cpu(srbreply->srb_status) & 0x3F,
+			aac_get_status_string(
+				le32_to_cpu(srbreply->srb_status) & 0x3F), 
+			scsicmd->cmnd[0], 
+			le32_to_cpu(srbreply->scsi_status));
+#endif
+		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
+		break;
+	}
+	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
+		int len;
+		scsicmd->result |= SAM_STAT_CHECK_CONDITION;
+		len = (le32_to_cpu(srbreply->sense_data_size) > 
+				sizeof(scsicmd->sense_buffer)) ?
+				sizeof(scsicmd->sense_buffer) :
+				le32_to_cpu(srbreply->sense_data_size);
+#ifdef AAC_DETAILED_STATUS_INFO
+		dprintk((KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", 
+					le32_to_cpu(srbreply->status), len));
+#endif
+		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+		
+	}
+	/*
+	 * OR in the scsi status (already shifted up a bit)
+	 */
+	scsicmd->result |= le32_to_cpu(srbreply->scsi_status);
+
+	fib_complete(fibptr);
+	fib_free(fibptr);
+	aac_io_done(scsicmd);
+}
+
+/**
+ *
+ * aac_send_scb_fib
+ * @scsicmd: the scsi command block
+ *
+ * This routine will form a FIB and fill in the aac_srb from the 
+ * scsicmd passed in.
+ */
+
+static int aac_send_srb_fib(struct scsi_cmnd* scsicmd)
+{
+	struct fib* cmd_fibcontext;
+	struct aac_dev* dev;
+	int status;
+	struct aac_srb *srbcmd;
+	u16 fibsize;
+	u32 flag;
+	u32 timeout;
+
+	if( scsicmd->device->id > 15 || scsicmd->device->lun > 7) {
+		scsicmd->result = DID_NO_CONNECT << 16;
+		scsicmd->scsi_done(scsicmd);
+		return 0;
+	}
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	switch(scsicmd->sc_data_direction){
+	case DMA_TO_DEVICE:
+		flag = SRB_DataOut;
+		break;
+	case DMA_BIDIRECTIONAL:
+		flag = SRB_DataIn | SRB_DataOut;
+		break;
+	case DMA_FROM_DEVICE:
+		flag = SRB_DataIn;
+		break;
+	case DMA_NONE:
+	default:	/* shuts up some versions of gcc */
+		flag = SRB_NoDataXfer;
+		break;
+	}
+
+
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(cmd_fibcontext = fib_alloc(dev))) {
+		return -1;
+	}
+	fib_init(cmd_fibcontext);
+
+	srbcmd = (struct aac_srb*) fib_data(cmd_fibcontext);
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);
+	srbcmd->channel  = cpu_to_le32(aac_logical_to_phys(scsicmd->device->channel));
+	srbcmd->id   = cpu_to_le32(scsicmd->device->id);
+	srbcmd->lun      = cpu_to_le32(scsicmd->device->lun);
+	srbcmd->flags    = cpu_to_le32(flag);
+	timeout = (scsicmd->timeout-jiffies)/HZ;
+	if(timeout == 0){
+		timeout = 1;
+	}
+	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
+	srbcmd->retry_limit = 0; /* Obsolete parameter */
+	srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
+	
+	if( dev->dac_support == 1 ) {
+		aac_build_sg64(scsicmd, (struct sgmap64*) &srbcmd->sg);
+		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
+
+		memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+		memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
+		/*
+		 *	Build Scatter/Gather list
+		 */
+		fibsize = sizeof (struct aac_srb) - sizeof (struct sgentry) +
+			((le32_to_cpu(srbcmd->sg.count) & 0xff) * 
+			 sizeof (struct sgentry64));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ScsiPortCommand64, cmd_fibcontext, 
+				fibsize, FsaNormal, 0, 1,
+				  (fib_callback) aac_srb_callback, 
+				  (void *) scsicmd);
+	} else {
+		aac_build_sg(scsicmd, (struct sgmap*)&srbcmd->sg);
+		srbcmd->count = cpu_to_le32(scsicmd->request_bufflen);
+
+		memset(srbcmd->cdb, 0, sizeof(srbcmd->cdb));
+		memcpy(srbcmd->cdb, scsicmd->cmnd, scsicmd->cmd_len);
+		/*
+		 *	Build Scatter/Gather list
+		 */
+		fibsize = sizeof (struct aac_srb) + 
+			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+			 sizeof (struct sgentry));
+		BUG_ON (fibsize > (sizeof(struct hw_fib) - 
+					sizeof(struct aac_fibhdr)));
+
+		/*
+		 *	Now send the Fib to the adapter
+		 */
+		status = fib_send(ScsiPortCommand, cmd_fibcontext, fibsize, FsaNormal, 0, 1,
+				  (fib_callback) aac_srb_callback, (void *) scsicmd);
+	}
+	/*
+	 *	Check that the command queued to the controller
+	 */
+	if (status == -EINPROGRESS){
+		return 0;
+	}
+
+	printk(KERN_WARNING "aac_srb: fib_send failed with status: %d\n", status);
+	fib_complete(cmd_fibcontext);
+	fib_free(cmd_fibcontext);
+
+	return -1;
+}
+
+static unsigned long aac_build_sg(struct scsi_cmnd* scsicmd, struct sgmap* psg)
+{
+	struct aac_dev *dev;
+	unsigned long byte_count = 0;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	// Get rid of old data
+	psg->count = 0;
+	psg->sg[0].addr = 0;
+	psg->sg[0].count = 0;  
+	if (scsicmd->use_sg) {
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsicmd->sc_data_direction);
+		psg->count = cpu_to_le32(sg_count);
+
+		byte_count = 0;
+
+		for (i = 0; i < sg_count; i++) {
+			psg->sg[i].addr = cpu_to_le32(sg_dma_address(sg));
+			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg_dma_len(sg);
+			sg++;
+		}
+		/* hba wants the size to be exact */
+		if(byte_count > scsicmd->request_bufflen){
+			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			byte_count = scsicmd->request_bufflen;
+		}
+		/* Check for command underflow */
+		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+					byte_count, scsicmd->underflow);
+		}
+	}
+	else if(scsicmd->request_bufflen) {
+		dma_addr_t addr; 
+		addr = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsicmd->sc_data_direction);
+		psg->count = cpu_to_le32(1);
+		psg->sg[0].addr = cpu_to_le32(addr);
+		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+		scsicmd->SCp.dma_handle = addr;
+		byte_count = scsicmd->request_bufflen;
+	}
+	return byte_count;
+}
+
+
+static unsigned long aac_build_sg64(struct scsi_cmnd* scsicmd, struct sgmap64* psg)
+{
+	struct aac_dev *dev;
+	unsigned long byte_count = 0;
+	u64 le_addr;
+
+	dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	// Get rid of old data
+	psg->count = 0;
+	psg->sg[0].addr[0] = 0;
+	psg->sg[0].addr[1] = 0;
+	psg->sg[0].count = 0;
+	if (scsicmd->use_sg) {
+		struct scatterlist *sg;
+		int i;
+		int sg_count;
+		sg = (struct scatterlist *) scsicmd->request_buffer;
+
+		sg_count = pci_map_sg(dev->pdev, sg, scsicmd->use_sg,
+			scsicmd->sc_data_direction);
+		psg->count = cpu_to_le32(sg_count);
+
+		byte_count = 0;
+
+		for (i = 0; i < sg_count; i++) {
+			le_addr = cpu_to_le64(sg_dma_address(sg));
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(sg_dma_len(sg));
+			byte_count += sg_dma_len(sg);
+			sg++;
+		}
+		/* hba wants the size to be exact */
+		if(byte_count > scsicmd->request_bufflen){
+			psg->sg[i-1].count -= (byte_count - scsicmd->request_bufflen);
+			byte_count = scsicmd->request_bufflen;
+		}
+		/* Check for command underflow */
+		if(scsicmd->underflow && (byte_count < scsicmd->underflow)){
+			printk(KERN_WARNING"aacraid: cmd len %08lX cmd underflow %08X\n",
+					byte_count, scsicmd->underflow);
+		}
+	}
+	else if(scsicmd->request_bufflen) {
+		dma_addr_t addr; 
+		addr = pci_map_single(dev->pdev,
+				scsicmd->request_buffer,
+				scsicmd->request_bufflen,
+				scsicmd->sc_data_direction);
+		psg->count = cpu_to_le32(1);
+		le_addr = cpu_to_le64(addr);
+		psg->sg[0].addr[1] = (u32)(le_addr>>32);
+		psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff);
+		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
+		scsicmd->SCp.dma_handle = addr;
+		byte_count = scsicmd->request_bufflen;
+	}
+	return byte_count;
+}
+
+#ifdef AAC_DETAILED_STATUS_INFO
+
+struct aac_srb_status_info {
+	u32	status;
+	char	*str;
+};
+
+
+static struct aac_srb_status_info srb_status_info[] = {
+	{ SRB_STATUS_PENDING,		"Pending Status"},
+	{ SRB_STATUS_SUCCESS,		"Success"},
+	{ SRB_STATUS_ABORTED,		"Aborted Command"},
+	{ SRB_STATUS_ABORT_FAILED,	"Abort Failed"},
+	{ SRB_STATUS_ERROR,		"Error Event"}, 
+	{ SRB_STATUS_BUSY,		"Device Busy"},
+	{ SRB_STATUS_INVALID_REQUEST,	"Invalid Request"},
+	{ SRB_STATUS_INVALID_PATH_ID,	"Invalid Path ID"},
+	{ SRB_STATUS_NO_DEVICE,		"No Device"},
+	{ SRB_STATUS_TIMEOUT,		"Timeout"},
+	{ SRB_STATUS_SELECTION_TIMEOUT,	"Selection Timeout"},
+	{ SRB_STATUS_COMMAND_TIMEOUT,	"Command Timeout"},
+	{ SRB_STATUS_MESSAGE_REJECTED,	"Message Rejected"},
+	{ SRB_STATUS_BUS_RESET,		"Bus Reset"},
+	{ SRB_STATUS_PARITY_ERROR,	"Parity Error"},
+	{ SRB_STATUS_REQUEST_SENSE_FAILED,"Request Sense Failed"},
+	{ SRB_STATUS_NO_HBA,		"No HBA"},
+	{ SRB_STATUS_DATA_OVERRUN,	"Data Overrun/Data Underrun"},
+	{ SRB_STATUS_UNEXPECTED_BUS_FREE,"Unexpected Bus Free"},
+	{ SRB_STATUS_PHASE_SEQUENCE_FAILURE,"Phase Error"},
+	{ SRB_STATUS_BAD_SRB_BLOCK_LENGTH,"Bad Srb Block Length"},
+	{ SRB_STATUS_REQUEST_FLUSHED,	"Request Flushed"},
+	{ SRB_STATUS_DELAYED_RETRY,	"Delayed Retry"},
+	{ SRB_STATUS_INVALID_LUN,	"Invalid LUN"}, 
+	{ SRB_STATUS_INVALID_TARGET_ID,	"Invalid TARGET ID"},
+	{ SRB_STATUS_BAD_FUNCTION,	"Bad Function"},
+	{ SRB_STATUS_ERROR_RECOVERY,	"Error Recovery"},
+	{ SRB_STATUS_NOT_STARTED,	"Not Started"},
+	{ SRB_STATUS_NOT_IN_USE,	"Not In Use"},
+    	{ SRB_STATUS_FORCE_ABORT,	"Force Abort"},
+	{ SRB_STATUS_DOMAIN_VALIDATION_FAIL,"Domain Validation Failure"},
+	{ 0xff,				"Unknown Error"}
+};
+
+char *aac_get_status_string(u32 status)
+{
+	int i;
+
+	for(i=0; i < (sizeof(srb_status_info)/sizeof(struct aac_srb_status_info)); i++ ){
+		if(srb_status_info[i].status == status){
+			return srb_status_info[i].str;
+		}
+	}
+
+	return "Bad Status Code";
+}
+
+#endif
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
new file mode 100644
index 0000000..700d903
--- /dev/null
+++ b/drivers/scsi/aacraid/aacraid.h
@@ -0,0 +1,1623 @@
+#if (!defined(dprintk))
+# define dprintk(x)
+#endif
+
+/*------------------------------------------------------------------------------
+ *              D E F I N E S
+ *----------------------------------------------------------------------------*/
+
+#define MAXIMUM_NUM_CONTAINERS	32
+
+#define AAC_NUM_FIB		(256 + 64)
+#define AAC_NUM_IO_FIB		100
+
+#define AAC_MAX_LUN		(8)
+
+#define AAC_MAX_HOSTPHYSMEMPAGES (0xfffff)
+
+/*
+ * These macros convert from physical channels to virtual channels
+ */
+#define CONTAINER_CHANNEL		(0)
+#define ID_LUN_TO_CONTAINER(id, lun)	(id)
+#define CONTAINER_TO_CHANNEL(cont)	(CONTAINER_CHANNEL)
+#define CONTAINER_TO_ID(cont)		(cont)
+#define CONTAINER_TO_LUN(cont)		(0)
+
+#define aac_phys_to_logical(x)  (x+1)
+#define aac_logical_to_phys(x)  (x?x-1:0)
+
+/* #define AAC_DETAILED_STATUS_INFO */
+
+struct diskparm
+{
+	int heads;
+	int sectors;
+	int cylinders;
+};
+
+
+/*
+ *	DON'T CHANGE THE ORDER, this is set by the firmware
+ */
+ 
+#define		CT_NONE			0
+#define		CT_VOLUME		1
+#define		CT_MIRROR		2
+#define		CT_STRIPE		3
+#define		CT_RAID5		4
+#define		CT_SSRW			5
+#define		CT_SSRO			6
+#define		CT_MORPH		7
+#define		CT_PASSTHRU		8
+#define		CT_RAID4		9
+#define		CT_RAID10		10	/* stripe of mirror */
+#define		CT_RAID00		11	/* stripe of stripe */
+#define		CT_VOLUME_OF_MIRRORS	12	/* volume of mirror */
+#define		CT_PSEUDO_RAID		13	/* really raid4 */
+#define		CT_LAST_VOLUME_TYPE	14
+#define 	CT_OK        		218
+
+/*
+ *	Types of objects addressable in some fashion by the client.
+ *	This is a superset of those objects handled just by the filesystem
+ *	and includes "raw" objects that an administrator would use to
+ *	configure containers and filesystems.
+ */
+
+#define		FT_REG		1	/* regular file */
+#define		FT_DIR		2	/* directory */
+#define		FT_BLK		3	/* "block" device - reserved */
+#define		FT_CHR		4	/* "character special" device - reserved */
+#define		FT_LNK		5	/* symbolic link */
+#define		FT_SOCK		6	/* socket */
+#define		FT_FIFO		7	/* fifo */
+#define		FT_FILESYS	8	/* ADAPTEC's "FSA"(tm) filesystem */
+#define		FT_DRIVE	9	/* physical disk - addressable in scsi by bus/id/lun */
+#define		FT_SLICE	10	/* virtual disk - raw volume - slice */
+#define		FT_PARTITION	11	/* FSA partition - carved out of a slice - building block for containers */
+#define		FT_VOLUME	12	/* Container - Volume Set */
+#define		FT_STRIPE	13	/* Container - Stripe Set */
+#define		FT_MIRROR	14	/* Container - Mirror Set */
+#define		FT_RAID5	15	/* Container - Raid 5 Set */
+#define		FT_DATABASE	16	/* Storage object with "foreign" content manager */
+
+/*
+ *	Host side memory scatter gather list
+ *	Used by the adapter for read, write, and readdirplus operations
+ *	We have separate 32 and 64 bit version because even
+ *	on 64 bit systems not all cards support the 64 bit version
+ */
+struct sgentry {
+	u32	addr;	/* 32-bit address. */
+	u32	count;	/* Length. */
+};
+
+struct sgentry64 {
+	u32	addr[2];	/* 64-bit addr. 2 pieces for data alignment */
+	u32	count;	/* Length. */
+};
+
+/*
+ *	SGMAP
+ *
+ *	This is the SGMAP structure for all commands that use
+ *	32-bit addressing.
+ */
+
+struct sgmap {
+	u32		count;
+	struct sgentry	sg[1]; 
+};
+
+struct sgmap64 {
+	u32		count;
+	struct sgentry64 sg[1];
+};
+
+struct creation_info
+{
+	u8 		buildnum;		/* e.g., 588 */
+	u8 		usec;			/* e.g., 588 */
+	u8	 	via;			/* e.g., 1 = FSU,
+						 * 	 2 = API
+						 */
+	u8	 	year;		 	/* e.g., 1997 = 97 */
+	u32		date;			/*
+						 * unsigned 	Month		:4;	// 1 - 12
+						 * unsigned 	Day		:6;	// 1 - 32
+						 * unsigned 	Hour		:6;	// 0 - 23
+						 * unsigned 	Minute		:6;	// 0 - 60
+						 * unsigned 	Second		:6;	// 0 - 60
+						 */
+	u32		serial[2];			/* e.g., 0x1DEADB0BFAFAF001 */
+};
+
+
+/*
+ *	Define all the constants needed for the communication interface
+ */
+
+/*
+ *	Define how many queue entries each queue will have and the total
+ *	number of entries for the entire communication interface. Also define
+ *	how many queues we support.
+ *
+ *	This has to match the controller
+ */
+
+#define NUMBER_OF_COMM_QUEUES  8   // 4 command; 4 response
+#define HOST_HIGH_CMD_ENTRIES  4
+#define HOST_NORM_CMD_ENTRIES  8
+#define ADAP_HIGH_CMD_ENTRIES  4
+#define ADAP_NORM_CMD_ENTRIES  512
+#define HOST_HIGH_RESP_ENTRIES 4
+#define HOST_NORM_RESP_ENTRIES 512
+#define ADAP_HIGH_RESP_ENTRIES 4
+#define ADAP_NORM_RESP_ENTRIES 8
+
+#define TOTAL_QUEUE_ENTRIES  \
+    (HOST_NORM_CMD_ENTRIES + HOST_HIGH_CMD_ENTRIES + ADAP_NORM_CMD_ENTRIES + ADAP_HIGH_CMD_ENTRIES + \
+	    HOST_NORM_RESP_ENTRIES + HOST_HIGH_RESP_ENTRIES + ADAP_NORM_RESP_ENTRIES + ADAP_HIGH_RESP_ENTRIES)
+
+
+/*
+ *	Set the queues on a 16 byte alignment
+ */
+ 
+#define QUEUE_ALIGNMENT		16
+
+/*
+ *	The queue headers define the Communication Region queues. These
+ *	are physically contiguous and accessible by both the adapter and the
+ *	host. Even though all queue headers are in the same contiguous block
+ *	they will be represented as individual units in the data structures.
+ */
+
+struct aac_entry {
+	u32 size;          /* Size in bytes of Fib which this QE points to */
+	u32 addr; /* Receiver address of the FIB */
+};
+
+/*
+ *	The adapter assumes the ProducerIndex and ConsumerIndex are grouped
+ *	adjacently and in that order.
+ */
+ 
+struct aac_qhdr {
+	u64 header_addr;		/* Address to hand the adapter to access to this queue head */
+	u32 *producer;			/* The producer index for this queue (host address) */
+	u32 *consumer;			/* The consumer index for this queue (host address) */
+};
+
+/*
+ *	Define all the events which the adapter would like to notify
+ *	the host of.
+ */
+ 
+#define		HostNormCmdQue		1	/* Change in host normal priority command queue */
+#define		HostHighCmdQue		2	/* Change in host high priority command queue */
+#define		HostNormRespQue		3	/* Change in host normal priority response queue */
+#define		HostHighRespQue		4	/* Change in host high priority response queue */
+#define		AdapNormRespNotFull	5
+#define		AdapHighRespNotFull	6
+#define		AdapNormCmdNotFull	7
+#define		AdapHighCmdNotFull	8
+#define		SynchCommandComplete	9
+#define		AdapInternalError	0xfe    /* The adapter detected an internal error shutting down */
+
+/*
+ *	Define all the events the host wishes to notify the
+ *	adapter of. The first four values much match the Qid the
+ *	corresponding queue.
+ */
+
+#define		AdapNormCmdQue		2
+#define		AdapHighCmdQue		3
+#define		AdapNormRespQue		6
+#define		AdapHighRespQue		7
+#define		HostShutdown		8
+#define		HostPowerFail		9
+#define		FatalCommError		10
+#define		HostNormRespNotFull	11
+#define		HostHighRespNotFull	12
+#define		HostNormCmdNotFull	13
+#define		HostHighCmdNotFull	14
+#define		FastIo			15
+#define		AdapPrintfDone		16
+
+/*
+ *	Define all the queues that the adapter and host use to communicate
+ *	Number them to match the physical queue layout.
+ */
+
+enum aac_queue_types {
+        HostNormCmdQueue = 0,	/* Adapter to host normal priority command traffic */
+        HostHighCmdQueue,	/* Adapter to host high priority command traffic */
+        AdapNormCmdQueue,	/* Host to adapter normal priority command traffic */
+        AdapHighCmdQueue,	/* Host to adapter high priority command traffic */
+        HostNormRespQueue,	/* Adapter to host normal priority response traffic */
+        HostHighRespQueue,	/* Adapter to host high priority response traffic */
+        AdapNormRespQueue,	/* Host to adapter normal priority response traffic */
+        AdapHighRespQueue	/* Host to adapter high priority response traffic */
+};
+
+/*
+ *	Assign type values to the FSA communication data structures
+ */
+
+#define		FIB_MAGIC	0x0001
+
+/*
+ *	Define the priority levels the FSA communication routines support.
+ */
+
+#define		FsaNormal	1
+#define		FsaHigh		2
+
+/*
+ * Define the FIB. The FIB is the where all the requested data and
+ * command information are put to the application on the FSA adapter.
+ */
+
+struct aac_fibhdr {
+	u32 XferState;			// Current transfer state for this CCB
+	u16 Command;			// Routing information for the destination
+	u8 StructType;			// Type FIB
+	u8 Flags;			// Flags for FIB
+	u16 Size;			// Size of this FIB in bytes
+	u16 SenderSize;			// Size of the FIB in the sender (for response sizing)
+	u32 SenderFibAddress;		// Host defined data in the FIB
+	u32 ReceiverFibAddress;		// Logical address of this FIB for the adapter
+	u32 SenderData;			// Place holder for the sender to store data
+	union {
+		struct {
+		    u32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
+		    u32 _ReceiverTimeDone;	// Timestamp for completion of fib
+		} _s;
+	} _u;
+};
+
+#define FIB_DATA_SIZE_IN_BYTES (512 - sizeof(struct aac_fibhdr))
+
+
+struct hw_fib {
+	struct aac_fibhdr header;
+	u8 data[FIB_DATA_SIZE_IN_BYTES];		// Command specific data
+};
+
+/*
+ *	FIB commands
+ */
+
+#define 	TestCommandResponse		1
+#define		TestAdapterCommand		2
+/*
+ *	Lowlevel and comm commands
+ */
+#define		LastTestCommand			100
+#define		ReinitHostNormCommandQueue	101
+#define		ReinitHostHighCommandQueue	102
+#define		ReinitHostHighRespQueue		103
+#define		ReinitHostNormRespQueue		104
+#define		ReinitAdapNormCommandQueue	105
+#define		ReinitAdapHighCommandQueue	107
+#define		ReinitAdapHighRespQueue		108
+#define		ReinitAdapNormRespQueue		109
+#define		InterfaceShutdown		110
+#define		DmaCommandFib			120
+#define		StartProfile			121
+#define		TermProfile			122
+#define		SpeedTest			123
+#define		TakeABreakPt			124
+#define		RequestPerfData			125
+#define		SetInterruptDefTimer		126
+#define		SetInterruptDefCount		127
+#define		GetInterruptDefStatus		128
+#define		LastCommCommand			129
+/*
+ *	Filesystem commands
+ */
+#define		NuFileSystem			300
+#define		UFS				301
+#define		HostFileSystem			302
+#define		LastFileSystemCommand		303
+/*
+ *	Container Commands
+ */
+#define		ContainerCommand		500
+#define		ContainerCommand64		501
+/*
+ *	Cluster Commands
+ */
+#define		ClusterCommand	 		550
+/*
+ *	Scsi Port commands (scsi passthrough)
+ */
+#define		ScsiPortCommand			600
+#define		ScsiPortCommand64		601
+/*
+ *	Misc house keeping and generic adapter initiated commands
+ */
+#define		AifRequest			700
+#define		CheckRevision			701
+#define		FsaHostShutdown			702
+#define		RequestAdapterInfo		703
+#define		IsAdapterPaused			704
+#define		SendHostTime			705
+#define		LastMiscCommand			706
+
+//
+// Commands that will target the failover level on the FSA adapter
+//
+
+enum fib_xfer_state {
+	HostOwned 			= (1<<0),
+	AdapterOwned 			= (1<<1),
+	FibInitialized 			= (1<<2),
+	FibEmpty 			= (1<<3),
+	AllocatedFromPool 		= (1<<4),
+	SentFromHost 			= (1<<5),
+	SentFromAdapter 		= (1<<6),
+	ResponseExpected 		= (1<<7),
+	NoResponseExpected 		= (1<<8),
+	AdapterProcessed 		= (1<<9),
+	HostProcessed 			= (1<<10),
+	HighPriority 			= (1<<11),
+	NormalPriority 			= (1<<12),
+	Async				= (1<<13),
+	AsyncIo				= (1<<13),	// rpbfix: remove with new regime
+	PageFileIo			= (1<<14),	// rpbfix: remove with new regime
+	ShutdownRequest			= (1<<15),
+	LazyWrite			= (1<<16),	// rpbfix: remove with new regime
+	AdapterMicroFib			= (1<<17),
+	BIOSFibPath			= (1<<18),
+	FastResponseCapable		= (1<<19),
+	ApiFib				= (1<<20)	// Its an API Fib.
+};
+
+/*
+ *	The following defines needs to be updated any time there is an
+ *	incompatible change made to the aac_init structure.
+ */
+
+#define ADAPTER_INIT_STRUCT_REVISION		3
+
+struct aac_init
+{
+	u32	InitStructRevision;
+	u32	MiniPortRevision;
+	u32	fsrev;
+	u32	CommHeaderAddress;
+	u32	FastIoCommAreaAddress;
+	u32	AdapterFibsPhysicalAddress;
+	u32	AdapterFibsVirtualAddress;
+	u32	AdapterFibsSize;
+	u32	AdapterFibAlign;
+	u32	printfbuf;
+	u32	printfbufsiz;
+	u32	HostPhysMemPages;		// number of 4k pages of host physical memory
+	u32	HostElapsedSeconds;		// number of seconds since 1970.
+};
+
+enum aac_log_level {
+	LOG_AAC_INIT			= 10,
+	LOG_AAC_INFORMATIONAL		= 20,
+	LOG_AAC_WARNING			= 30,
+	LOG_AAC_LOW_ERROR		= 40,
+	LOG_AAC_MEDIUM_ERROR		= 50,
+	LOG_AAC_HIGH_ERROR		= 60,
+	LOG_AAC_PANIC			= 70,
+	LOG_AAC_DEBUG			= 80,
+	LOG_AAC_WINDBG_PRINT		= 90
+};
+
+#define FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT	0x030b
+#define FSAFS_NTC_FIB_CONTEXT			0x030c
+
+struct aac_dev;
+
+struct adapter_ops
+{
+	void (*adapter_interrupt)(struct aac_dev *dev);
+	void (*adapter_notify)(struct aac_dev *dev, u32 event);
+	int  (*adapter_sync_cmd)(struct aac_dev *dev, u32 command, u32 p1, u32 *status);
+	int  (*adapter_check_health)(struct aac_dev *dev);
+};
+
+/*
+ *	Define which interrupt handler needs to be installed
+ */
+
+struct aac_driver_ident
+{
+	int 	(*init)(struct aac_dev *dev);
+	char *	name;
+	char *	vname;
+	char *	model;
+	u16	channels;
+	int	quirks;
+};
+/*
+ * Some adapter firmware needs communication memory 
+ * below 2gig. This tells the init function to set the
+ * dma mask such that fib memory will be allocated where the
+ * adapter firmware can get to it.
+ */
+#define AAC_QUIRK_31BIT	0x0001
+
+/*
+ * Some adapter firmware, when the raid card's cache is turned off, can not
+ * split up scatter gathers in order to deal with the limits of the
+ * underlying CHIM. This limit is 34 scatter gather elements.
+ */
+#define AAC_QUIRK_34SG	0x0002
+
+/*
+ * This adapter is a slave (no Firmware)
+ */
+#define AAC_QUIRK_SLAVE 0x0004
+
+/*
+ * This adapter is a master.
+ */
+#define AAC_QUIRK_MASTER 0x0008
+
+/*
+ *	The adapter interface specs all queues to be located in the same
+ *	physically contigous block. The host structure that defines the
+ *	commuication queues will assume they are each a separate physically
+ *	contigous memory region that will support them all being one big
+ *	contigous block. 
+ *	There is a command and response queue for each level and direction of
+ *	commuication. These regions are accessed by both the host and adapter.
+ */
+ 
+struct aac_queue {
+	u64		 	logical;	/*address we give the adapter */
+	struct aac_entry	*base;		/*system virtual address */
+	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
+	u32	 		entries;	/*Number of queue entries */
+	wait_queue_head_t	qfull;		/*Event to wait on if q full */
+	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
+                  /* This is only valid for adapter to host command queues. */ 
+	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
+	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
+	unsigned long		SavedIrql;     	/* Previous IRQL when the spin lock is taken */
+	u32			padding;	/* Padding - FIXME - can remove I believe */
+	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+                                		/* only valid for command queues which receive entries from the adapter. */
+	struct list_head	pendingq;	/* A queue of outstanding fib's to the adapter. */
+	u32			numpending;	/* Number of entries on outstanding queue. */
+	struct aac_dev *	dev;		/* Back pointer to adapter structure */
+};
+
+/*
+ *	Message queues. The order here is important, see also the 
+ *	queue type ordering
+ */
+
+struct aac_queue_block
+{
+	struct aac_queue queue[8];
+};
+
+/*
+ *	SaP1 Message Unit Registers
+ */
+ 
+struct sa_drawbridge_CSR {
+				/*	Offset 	|  Name */
+	__le32	reserved[10];	/*	00h-27h |  Reserved */
+	u8	LUT_Offset;	/*	28h	|  Lookup Table Offset */
+	u8	reserved1[3];	/* 	29h-2bh	|  Reserved */
+	__le32	LUT_Data;	/*	2ch	|  Looup Table Data */
+	__le32	reserved2[26];	/*	30h-97h	|  Reserved */
+	__le16	PRICLEARIRQ;	/*	98h	|  Primary Clear Irq */
+	__le16	SECCLEARIRQ;	/*	9ah	|  Secondary Clear Irq */
+	__le16	PRISETIRQ;	/*	9ch	|  Primary Set Irq */
+	__le16	SECSETIRQ;	/*	9eh	|  Secondary Set Irq */
+	__le16	PRICLEARIRQMASK;/*	a0h	|  Primary Clear Irq Mask */
+	__le16	SECCLEARIRQMASK;/*	a2h	|  Secondary Clear Irq Mask */
+	__le16	PRISETIRQMASK;	/*	a4h	|  Primary Set Irq Mask */
+	__le16	SECSETIRQMASK;	/*	a6h	|  Secondary Set Irq Mask */
+	__le32	MAILBOX0;	/*	a8h	|  Scratchpad 0 */
+	__le32	MAILBOX1;	/*	ach	|  Scratchpad 1 */
+	__le32	MAILBOX2;	/*	b0h	|  Scratchpad 2 */
+	__le32	MAILBOX3;	/*	b4h	|  Scratchpad 3 */
+	__le32	MAILBOX4;	/*	b8h	|  Scratchpad 4 */
+	__le32	MAILBOX5;	/*	bch	|  Scratchpad 5 */
+	__le32	MAILBOX6;	/*	c0h	|  Scratchpad 6 */
+	__le32	MAILBOX7;	/*	c4h	|  Scratchpad 7 */
+	__le32	ROM_Setup_Data;	/*	c8h 	|  Rom Setup and Data */
+	__le32	ROM_Control_Addr;/*	cch 	|  Rom Control and Address */
+	__le32	reserved3[12];	/*	d0h-ffh	|  reserved */
+	__le32	LUT[64];	/*    100h-1ffh	|  Lookup Table Entries */
+};
+
+#define Mailbox0	SaDbCSR.MAILBOX0
+#define Mailbox1	SaDbCSR.MAILBOX1
+#define Mailbox2	SaDbCSR.MAILBOX2
+#define Mailbox3	SaDbCSR.MAILBOX3
+#define Mailbox4	SaDbCSR.MAILBOX4
+#define Mailbox5	SaDbCSR.MAILBOX5
+#define Mailbox7	SaDbCSR.MAILBOX7
+	
+#define DoorbellReg_p SaDbCSR.PRISETIRQ
+#define DoorbellReg_s SaDbCSR.SECSETIRQ
+#define DoorbellClrReg_p SaDbCSR.PRICLEARIRQ
+
+
+#define	DOORBELL_0	0x0001
+#define DOORBELL_1	0x0002
+#define DOORBELL_2	0x0004
+#define DOORBELL_3	0x0008
+#define DOORBELL_4	0x0010
+#define DOORBELL_5	0x0020
+#define DOORBELL_6	0x0040
+
+	
+#define PrintfReady	DOORBELL_5
+#define PrintfDone	DOORBELL_5
+	
+struct sa_registers {
+	struct sa_drawbridge_CSR	SaDbCSR;			/* 98h - c4h */
+};
+	
+
+#define Sa_MINIPORT_REVISION			1
+
+#define sa_readw(AEP, CSR)		readl(&((AEP)->regs.sa->CSR))
+#define sa_readl(AEP,  CSR)		readl(&((AEP)->regs.sa->CSR))
+#define sa_writew(AEP, CSR, value)	writew(value, &((AEP)->regs.sa->CSR))
+#define sa_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.sa->CSR))
+
+/*
+ *	Rx Message Unit Registers
+ */
+
+struct rx_mu_registers {
+			    /*	Local  | PCI*| Name */
+	__le32	ARSR;	    /*	1300h  | 00h | APIC Register Select Register */
+	__le32	reserved0;  /*	1304h  | 04h | Reserved */
+	__le32	AWR;	    /*	1308h  | 08h | APIC Window Register */
+	__le32	reserved1;  /*	130Ch  | 0Ch | Reserved */
+	__le32	IMRx[2];    /*	1310h  | 10h | Inbound Message Registers */
+	__le32	OMRx[2];    /*	1318h  | 18h | Outbound Message Registers */
+	__le32	IDR;	    /*	1320h  | 20h | Inbound Doorbell Register */
+	__le32	IISR;	    /*	1324h  | 24h | Inbound Interrupt 
+						Status Register */
+	__le32	IIMR;	    /*	1328h  | 28h | Inbound Interrupt 
+					 	Mask Register */
+	__le32	ODR;	    /*	132Ch  | 2Ch | Outbound Doorbell Register */
+	__le32	OISR;	    /*	1330h  | 30h | Outbound Interrupt 
+						Status Register */
+	__le32	OIMR;	    /*	1334h  | 34h | Outbound Interrupt 
+						Mask Register */
+			    /* * Must access through ATU Inbound 
+			     	 Translation Window */
+};
+
+struct rx_inbound {
+	__le32	Mailbox[8];
+};
+
+#define	InboundMailbox0		IndexRegs.Mailbox[0]
+#define	InboundMailbox1		IndexRegs.Mailbox[1]
+#define	InboundMailbox2		IndexRegs.Mailbox[2]
+#define	InboundMailbox3		IndexRegs.Mailbox[3]
+#define	InboundMailbox4		IndexRegs.Mailbox[4]
+#define	InboundMailbox5		IndexRegs.Mailbox[5]
+#define	InboundMailbox6		IndexRegs.Mailbox[6]
+
+#define	INBOUNDDOORBELL_0	0x00000001
+#define INBOUNDDOORBELL_1	0x00000002
+#define INBOUNDDOORBELL_2	0x00000004
+#define INBOUNDDOORBELL_3	0x00000008
+#define INBOUNDDOORBELL_4	0x00000010
+#define INBOUNDDOORBELL_5	0x00000020
+#define INBOUNDDOORBELL_6	0x00000040
+
+#define	OUTBOUNDDOORBELL_0	0x00000001
+#define OUTBOUNDDOORBELL_1	0x00000002
+#define OUTBOUNDDOORBELL_2	0x00000004
+#define OUTBOUNDDOORBELL_3	0x00000008
+#define OUTBOUNDDOORBELL_4	0x00000010
+
+#define InboundDoorbellReg	MUnit.IDR
+#define OutboundDoorbellReg	MUnit.ODR
+
+struct rx_registers {
+	struct rx_mu_registers		MUnit;		/* 1300h - 1334h */
+	__le32				reserved1[6];	/* 1338h - 134ch */
+	struct rx_inbound		IndexRegs;
+};
+
+#define rx_readb(AEP, CSR)		readb(&((AEP)->regs.rx->CSR))
+#define rx_readl(AEP, CSR)		readl(&((AEP)->regs.rx->CSR))
+#define rx_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rx->CSR))
+#define rx_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rx->CSR))
+
+/*
+ *	Rkt Message Unit Registers (same as Rx, except a larger reserve region)
+ */
+
+#define rkt_mu_registers rx_mu_registers
+#define rkt_inbound rx_inbound
+
+struct rkt_registers {
+	struct rkt_mu_registers		MUnit;		 /* 1300h - 1334h */
+	__le32				reserved1[1010]; /* 1338h - 22fch */
+	struct rkt_inbound		IndexRegs;	 /* 2300h - */
+};
+
+#define rkt_readb(AEP, CSR)		readb(&((AEP)->regs.rkt->CSR))
+#define rkt_readl(AEP, CSR)		readl(&((AEP)->regs.rkt->CSR))
+#define rkt_writeb(AEP, CSR, value)	writeb(value, &((AEP)->regs.rkt->CSR))
+#define rkt_writel(AEP, CSR, value)	writel(value, &((AEP)->regs.rkt->CSR))
+
+struct fib;
+
+typedef void (*fib_callback)(void *ctxt, struct fib *fibctx);
+
+struct aac_fib_context {
+	s16	 		type;		// used for verification of structure	
+	s16	 		size;
+	u32			unique;		// unique value representing this context
+	ulong			jiffies;	// used for cleanup - dmb changed to ulong
+	struct list_head	next;		// used to link context's into a linked list
+	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
+	int			wait;		// Set to true when thread is in WaitForSingleObject
+	unsigned long		count;		// total number of FIBs on FibList
+	struct list_head	fib_list;	// this holds fibs and their attachd hw_fibs
+};
+
+struct sense_data {
+	u8 error_code;		/* 70h (current errors), 71h(deferred errors) */
+	u8 valid:1;		/* A valid bit of one indicates that the information  */
+				/* field contains valid information as defined in the
+				 * SCSI-2 Standard.
+				 */
+	u8 segment_number;	/* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
+	u8 sense_key:4;		/* Sense Key */
+	u8 reserved:1;
+	u8 ILI:1;		/* Incorrect Length Indicator */
+	u8 EOM:1;		/* End Of Medium - reserved for random access devices */
+	u8 filemark:1;		/* Filemark - reserved for random access devices */
+
+	u8 information[4];	/* for direct-access devices, contains the unsigned 
+				 * logical block address or residue associated with 
+				 * the sense key 
+				 */
+	u8 add_sense_len;	/* number of additional sense bytes to follow this field */
+	u8 cmnd_info[4];	/* not used */
+	u8 ASC;			/* Additional Sense Code */
+	u8 ASCQ;		/* Additional Sense Code Qualifier */
+	u8 FRUC;		/* Field Replaceable Unit Code - not used */
+	u8 bit_ptr:3;		/* indicates which byte of the CDB or parameter data
+				 * was in error
+				 */
+	u8 BPV:1;		/* bit pointer valid (BPV): 1- indicates that 
+				 * the bit_ptr field has valid value
+				 */
+	u8 reserved2:2;
+	u8 CD:1;		/* command data bit: 1- illegal parameter in CDB.
+				 * 0- illegal parameter in data.
+				 */
+	u8 SKSV:1;
+	u8 field_ptr[2];	/* byte of the CDB or parameter data in error */
+};
+
+struct fsa_dev_info {
+	u64		last;
+	u64		size;
+	u32		type;
+	u16		queue_depth;
+	u8		valid;
+	u8		ro;
+	u8		locked;
+	u8		deleted;
+	char		devname[8];
+	struct sense_data sense_data;
+};
+
+struct fib {
+	void			*next;	/* this is used by the allocator */
+	s16			type;
+	s16			size;
+	/*
+	 *	The Adapter that this I/O is destined for.
+	 */
+	struct aac_dev 		*dev;
+	/*
+	 *	This is the event the sendfib routine will wait on if the
+	 *	caller did not pass one and this is synch io.
+	 */
+	struct semaphore 	event_wait;
+	spinlock_t		event_lock;
+
+	u32			done;	/* gets set to 1 when fib is complete */
+	fib_callback 		callback;
+	void 			*callback_data;
+	u32			flags; // u32 dmb was ulong
+	/*
+	 *	The following is used to put this fib context onto the 
+	 *	Outstanding I/O queue.
+	 */
+	struct list_head	queue;
+	/*
+	 *	And for the internal issue/reply queues (we may be able
+	 *	to merge these two)
+	 */
+	struct list_head	fiblink;
+	void 			*data;
+	struct hw_fib		*hw_fib;		/* Actual shared object */
+	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
+};
+
+/*
+ *	Adapter Information Block
+ *
+ *	This is returned by the RequestAdapterInfo block
+ */
+ 
+struct aac_adapter_info
+{
+	u32	platform;
+	u32	cpu;
+	u32	subcpu;
+	u32	clock;
+	u32	execmem;
+	u32	buffermem;
+	u32	totalmem;
+	u32	kernelrev;
+	u32	kernelbuild;
+	u32	monitorrev;
+	u32	monitorbuild;
+	u32	hwrev;
+	u32	hwbuild;
+	u32	biosrev;
+	u32	biosbuild;
+	u32	cluster;
+	u32	clusterchannelmask; 
+	u32	serial[2];
+	u32	battery;
+	u32	options;
+	u32	OEM;
+};
+
+/*
+ * Battery platforms
+ */
+#define AAC_BAT_REQ_PRESENT	(1)
+#define AAC_BAT_REQ_NOTPRESENT	(2)
+#define AAC_BAT_OPT_PRESENT	(3)
+#define AAC_BAT_OPT_NOTPRESENT	(4)
+#define AAC_BAT_NOT_SUPPORTED	(5)
+/*
+ * cpu types
+ */
+#define AAC_CPU_SIMULATOR	(1)
+#define AAC_CPU_I960		(2)
+#define AAC_CPU_STRONGARM	(3)
+
+/*
+ * Supported Options
+ */
+#define AAC_OPT_SNAPSHOT		cpu_to_le32(1)
+#define AAC_OPT_CLUSTERS		cpu_to_le32(1<<1)
+#define AAC_OPT_WRITE_CACHE		cpu_to_le32(1<<2)
+#define AAC_OPT_64BIT_DATA		cpu_to_le32(1<<3)
+#define AAC_OPT_HOST_TIME_FIB		cpu_to_le32(1<<4)
+#define AAC_OPT_RAID50			cpu_to_le32(1<<5)
+#define AAC_OPT_4GB_WINDOW		cpu_to_le32(1<<6)
+#define AAC_OPT_SCSI_UPGRADEABLE 	cpu_to_le32(1<<7)
+#define AAC_OPT_SOFT_ERR_REPORT		cpu_to_le32(1<<8)
+#define AAC_OPT_SUPPORTED_RECONDITION 	cpu_to_le32(1<<9)
+#define AAC_OPT_SGMAP_HOST64		cpu_to_le32(1<<10)
+#define AAC_OPT_ALARM			cpu_to_le32(1<<11)
+#define AAC_OPT_NONDASD			cpu_to_le32(1<<12)
+#define AAC_OPT_SCSI_MANAGED    	cpu_to_le32(1<<13)
+#define AAC_OPT_RAID_SCSI_MODE		cpu_to_le32(1<<14)
+#define AAC_OPT_SUPPLEMENT_ADAPTER_INFO	cpu_to_le32(1<<16)
+#define AAC_OPT_NEW_COMM		cpu_to_le32(1<<17)
+#define AAC_OPT_NEW_COMM_64		cpu_to_le32(1<<18)
+
+struct aac_dev
+{
+	struct list_head	entry;
+	const char		*name;
+	int			id;
+
+	u16			irq_mask;
+	/*
+	 *	Map for 128 fib objects (64k)
+	 */	
+	dma_addr_t		hw_fib_pa;
+	struct hw_fib		*hw_fib_va;
+	struct hw_fib		*aif_base_va;
+	/*
+	 *	Fib Headers
+	 */
+	struct fib              *fibs;
+
+	struct fib		*free_fib;
+	struct fib		*timeout_fib;
+	spinlock_t		fib_lock;
+	
+	struct aac_queue_block *queues;
+	/*
+	 *	The user API will use an IOCTL to register itself to receive
+	 *	FIBs from the adapter.  The following list is used to keep
+	 *	track of all the threads that have requested these FIBs.  The
+	 *	mutex is used to synchronize access to all data associated 
+	 *	with the adapter fibs.
+	 */
+	struct list_head	fib_list;
+
+	struct adapter_ops	a_ops;
+	unsigned long		fsrev;		/* Main driver's revision number */
+	
+	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
+	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
+	
+	struct pci_dev		*pdev;		/* Our PCI interface */
+	void *			printfbuf;	/* pointer to buffer used for printf's from the adapter */
+	void *			comm_addr;	/* Base address of Comm area */
+	dma_addr_t		comm_phys;	/* Physical Address of Comm area */
+	size_t			comm_size;
+
+	struct Scsi_Host	*scsi_host_ptr;
+	int			maximum_num_containers;
+	struct fsa_dev_info	*fsa_dev;
+	pid_t			thread_pid;
+	int			cardtype;
+	
+	/*
+	 *	The following is the device specific extension.
+	 */
+	union
+	{
+		struct sa_registers __iomem *sa;
+		struct rx_registers __iomem *rx;
+		struct rkt_registers __iomem *rkt;
+	} regs;
+	u32			OIMR; /* Mask Register Cache */
+	/*
+	 *	AIF thread states
+	 */
+	u32			aif_thread;
+	struct completion	aif_completion;
+	struct aac_adapter_info adapter_info;
+	/* These are in adapter info but they are in the io flow so
+	 * lets break them out so we don't have to do an AND to check them
+	 */
+	u8			nondasd_support; 
+	u8			dac_support;
+	u8			raid_scsi_mode;
+};
+
+#define aac_adapter_interrupt(dev) \
+	(dev)->a_ops.adapter_interrupt(dev)
+
+#define aac_adapter_notify(dev, event) \
+	(dev)->a_ops.adapter_notify(dev, event)
+
+
+#define aac_adapter_check_health(dev) \
+	(dev)->a_ops.adapter_check_health(dev)
+
+
+#define FIB_CONTEXT_FLAG_TIMED_OUT		(0x00000001)
+
+/*
+ *	Define the command values
+ */
+ 
+#define		Null			0
+#define 	GetAttributes		1
+#define 	SetAttributes		2
+#define 	Lookup			3
+#define 	ReadLink		4
+#define 	Read			5
+#define 	Write			6
+#define		Create			7
+#define		MakeDirectory		8
+#define		SymbolicLink		9
+#define		MakeNode		10
+#define		Removex			11
+#define		RemoveDirectoryx	12
+#define		Rename			13
+#define		Link			14
+#define		ReadDirectory		15
+#define		ReadDirectoryPlus	16
+#define		FileSystemStatus	17
+#define		FileSystemInfo		18
+#define		PathConfigure		19
+#define		Commit			20
+#define		Mount			21
+#define		UnMount			22
+#define		Newfs			23
+#define		FsCheck			24
+#define		FsSync			25
+#define		SimReadWrite		26
+#define		SetFileSystemStatus	27
+#define		BlockRead		28
+#define		BlockWrite		29
+#define		NvramIoctl		30
+#define		FsSyncWait		31
+#define		ClearArchiveBit		32
+#define		SetAcl			33
+#define		GetAcl			34
+#define		AssignAcl		35
+#define		FaultInsertion		36	/* Fault Insertion Command */
+#define		CrazyCache		37	/* Crazycache */
+
+#define		MAX_FSACOMMAND_NUM	38
+
+
+/*
+ *	Define the status returns. These are very unixlike although
+ *	most are not in fact used
+ */
+
+#define		ST_OK		0
+#define		ST_PERM		1
+#define		ST_NOENT	2
+#define		ST_IO		5
+#define		ST_NXIO		6
+#define		ST_E2BIG	7
+#define		ST_ACCES	13
+#define		ST_EXIST	17
+#define		ST_XDEV		18
+#define		ST_NODEV	19
+#define		ST_NOTDIR	20
+#define		ST_ISDIR	21
+#define		ST_INVAL	22
+#define		ST_FBIG		27
+#define		ST_NOSPC	28
+#define		ST_ROFS		30
+#define		ST_MLINK	31
+#define		ST_WOULDBLOCK	35
+#define		ST_NAMETOOLONG	63
+#define		ST_NOTEMPTY	66
+#define		ST_DQUOT	69
+#define		ST_STALE	70
+#define		ST_REMOTE	71
+#define		ST_BADHANDLE	10001
+#define		ST_NOT_SYNC	10002
+#define		ST_BAD_COOKIE	10003
+#define		ST_NOTSUPP	10004
+#define		ST_TOOSMALL	10005
+#define		ST_SERVERFAULT	10006
+#define		ST_BADTYPE	10007
+#define		ST_JUKEBOX	10008
+#define		ST_NOTMOUNTED	10009
+#define		ST_MAINTMODE	10010
+#define		ST_STALEACL	10011
+
+/*
+ *	On writes how does the client want the data written.
+ */
+
+#define	CACHE_CSTABLE		1
+#define CACHE_UNSTABLE		2
+
+/*
+ *	Lets the client know at which level the data was commited on
+ *	a write request
+ */
+
+#define	CMFILE_SYNCH_NVRAM	1
+#define	CMDATA_SYNCH_NVRAM	2
+#define	CMFILE_SYNCH		3
+#define CMDATA_SYNCH		4
+#define CMUNSTABLE		5
+
+struct aac_read
+{
+	u32	 	command;
+	u32 		cid;
+	u32 		block;
+	u32 		count;
+	struct sgmap	sg;	// Must be last in struct because it is variable
+};
+
+struct aac_read64
+{
+	u32	 	command;
+	u16 		cid;
+	u16 		sector_count;
+	u32 		block;
+	u16		pad;
+	u16		flags;
+	struct sgmap64	sg;	// Must be last in struct because it is variable
+};
+
+struct aac_read_reply
+{
+	u32	 	status;
+	u32 		count;
+};
+
+struct aac_write
+{
+	u32		command;
+	u32 		cid;
+	u32 		block;
+	u32 		count;
+	u32	 	stable;	// Not used
+	struct sgmap	sg;	// Must be last in struct because it is variable
+};
+
+struct aac_write64
+{
+	u32	 	command;
+	u16 		cid;
+	u16 		sector_count;
+	u32 		block;
+	u16		pad;
+	u16		flags;
+	struct sgmap64	sg;	// Must be last in struct because it is variable
+};
+struct aac_write_reply
+{
+	u32		status;
+	u32 		count;
+	u32		committed;
+};
+
+#define CT_FLUSH_CACHE 129
+struct aac_synchronize {
+	u32		command;	/* VM_ContainerConfig */
+	u32		type;		/* CT_FLUSH_CACHE */
+	u32		cid;
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		count;	/* sizeof(((struct aac_synchronize_reply *)NULL)->data) */
+};
+
+struct aac_synchronize_reply {
+	u32		dummy0;
+	u32		dummy1;
+	u32		status;	/* CT_OK */
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		parm5;
+	u8		data[16];
+};
+
+struct aac_srb
+{
+	u32		function;
+	u32		channel;
+	u32		id;
+	u32		lun;
+	u32		timeout;
+	u32		flags;
+	u32		count;		// Data xfer size
+	u32		retry_limit;
+	u32		cdb_size;
+	u8		cdb[16];
+	struct	sgmap	sg;
+};
+
+
+
+#define		AAC_SENSE_BUFFERSIZE	 30
+
+struct aac_srb_reply
+{
+	u32		status;
+	u32		srb_status;
+	u32		scsi_status;
+	u32		data_xfer_length;
+	u32		sense_data_size;
+	u8		sense_data[AAC_SENSE_BUFFERSIZE]; // Can this be SCSI_SENSE_BUFFERSIZE
+};
+/*
+ * SRB Flags
+ */
+#define		SRB_NoDataXfer		 0x0000
+#define		SRB_DisableDisconnect	 0x0004
+#define		SRB_DisableSynchTransfer 0x0008
+#define 	SRB_BypassFrozenQueue	 0x0010
+#define		SRB_DisableAutosense	 0x0020
+#define		SRB_DataIn		 0x0040
+#define 	SRB_DataOut		 0x0080
+
+/*
+ * SRB Functions - set in aac_srb->function
+ */
+#define	SRBF_ExecuteScsi	0x0000
+#define	SRBF_ClaimDevice	0x0001
+#define	SRBF_IO_Control		0x0002
+#define	SRBF_ReceiveEvent	0x0003
+#define	SRBF_ReleaseQueue	0x0004
+#define	SRBF_AttachDevice	0x0005
+#define	SRBF_ReleaseDevice	0x0006
+#define	SRBF_Shutdown		0x0007
+#define	SRBF_Flush		0x0008
+#define	SRBF_AbortCommand	0x0010
+#define	SRBF_ReleaseRecovery	0x0011
+#define	SRBF_ResetBus		0x0012
+#define	SRBF_ResetDevice	0x0013
+#define	SRBF_TerminateIO	0x0014
+#define	SRBF_FlushQueue		0x0015
+#define	SRBF_RemoveDevice	0x0016
+#define	SRBF_DomainValidation	0x0017
+
+/* 
+ * SRB SCSI Status - set in aac_srb->scsi_status
+ */
+#define SRB_STATUS_PENDING                  0x00
+#define SRB_STATUS_SUCCESS                  0x01
+#define SRB_STATUS_ABORTED                  0x02
+#define SRB_STATUS_ABORT_FAILED             0x03
+#define SRB_STATUS_ERROR                    0x04
+#define SRB_STATUS_BUSY                     0x05
+#define SRB_STATUS_INVALID_REQUEST          0x06
+#define SRB_STATUS_INVALID_PATH_ID          0x07
+#define SRB_STATUS_NO_DEVICE                0x08
+#define SRB_STATUS_TIMEOUT                  0x09
+#define SRB_STATUS_SELECTION_TIMEOUT        0x0A
+#define SRB_STATUS_COMMAND_TIMEOUT          0x0B
+#define SRB_STATUS_MESSAGE_REJECTED         0x0D
+#define SRB_STATUS_BUS_RESET                0x0E
+#define SRB_STATUS_PARITY_ERROR             0x0F
+#define SRB_STATUS_REQUEST_SENSE_FAILED     0x10
+#define SRB_STATUS_NO_HBA                   0x11
+#define SRB_STATUS_DATA_OVERRUN             0x12
+#define SRB_STATUS_UNEXPECTED_BUS_FREE      0x13
+#define SRB_STATUS_PHASE_SEQUENCE_FAILURE   0x14
+#define SRB_STATUS_BAD_SRB_BLOCK_LENGTH     0x15
+#define SRB_STATUS_REQUEST_FLUSHED          0x16
+#define SRB_STATUS_DELAYED_RETRY	    0x17
+#define SRB_STATUS_INVALID_LUN              0x20
+#define SRB_STATUS_INVALID_TARGET_ID        0x21
+#define SRB_STATUS_BAD_FUNCTION             0x22
+#define SRB_STATUS_ERROR_RECOVERY           0x23
+#define SRB_STATUS_NOT_STARTED		    0x24
+#define SRB_STATUS_NOT_IN_USE		    0x30
+#define SRB_STATUS_FORCE_ABORT		    0x31
+#define SRB_STATUS_DOMAIN_VALIDATION_FAIL   0x32
+
+/*
+ * Object-Server / Volume-Manager Dispatch Classes
+ */
+
+#define		VM_Null			0
+#define		VM_NameServe		1
+#define		VM_ContainerConfig	2
+#define		VM_Ioctl		3
+#define		VM_FilesystemIoctl	4
+#define		VM_CloseAll		5
+#define		VM_CtBlockRead		6
+#define		VM_CtBlockWrite		7
+#define		VM_SliceBlockRead	8	/* raw access to configured "storage objects" */
+#define		VM_SliceBlockWrite	9
+#define		VM_DriveBlockRead	10	/* raw access to physical devices */
+#define		VM_DriveBlockWrite	11
+#define		VM_EnclosureMgt		12	/* enclosure management */
+#define		VM_Unused		13	/* used to be diskset management */
+#define		VM_CtBlockVerify	14
+#define		VM_CtPerf		15	/* performance test */
+#define		VM_CtBlockRead64	16
+#define		VM_CtBlockWrite64	17
+#define		VM_CtBlockVerify64	18
+#define		VM_CtHostRead64		19
+#define		VM_CtHostWrite64	20
+
+#define		MAX_VMCOMMAND_NUM	21	/* used for sizing stats array - leave last */
+
+/*
+ *	Descriptive information (eg, vital stats)
+ *	that a content manager might report.  The
+ *	FileArray filesystem component is one example
+ *	of a content manager.  Raw mode might be
+ *	another.
+ */
+
+struct aac_fsinfo {
+	u32  fsTotalSize;	/* Consumed by fs, incl. metadata */
+	u32  fsBlockSize;
+	u32  fsFragSize;
+	u32  fsMaxExtendSize;
+	u32  fsSpaceUnits;
+	u32  fsMaxNumFiles;
+	u32  fsNumFreeFiles;
+	u32  fsInodeDensity;
+};	/* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */
+
+union aac_contentinfo {
+	struct aac_fsinfo filesys;	/* valid iff ObjType == FT_FILESYS && !(ContentState & FSCS_NOTCLEAN) */
+};
+
+/*
+ *	Query for Container Configuration Status
+ */
+
+#define CT_GET_CONFIG_STATUS 147
+struct aac_get_config_status {
+	u32		command;	/* VM_ContainerConfig */
+	u32		type;		/* CT_GET_CONFIG_STATUS */
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		parm5;
+	u32		count;	/* sizeof(((struct aac_get_config_status_resp *)NULL)->data) */
+};
+
+#define CFACT_CONTINUE 0
+#define CFACT_PAUSE    1
+#define CFACT_ABORT    2
+struct aac_get_config_status_resp {
+	u32		response; /* ST_OK */
+	u32		dummy0;
+	u32		status;	/* CT_OK */
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		parm5;
+	struct {
+		u32	action; /* CFACT_CONTINUE, CFACT_PAUSE or CFACT_ABORT */
+		u16	flags;
+		s16	count;
+	}		data;
+};
+
+/*
+ *	Accept the configuration as-is
+ */
+
+#define CT_COMMIT_CONFIG 152
+
+struct aac_commit_config {
+	u32		command;	/* VM_ContainerConfig */
+	u32		type;		/* CT_COMMIT_CONFIG */
+};
+
+/*
+ *	Query for Container Configuration Count
+ */
+
+#define CT_GET_CONTAINER_COUNT 4
+struct aac_get_container_count {
+	u32		command;	/* VM_ContainerConfig */
+	u32		type;		/* CT_GET_CONTAINER_COUNT */
+};
+
+struct aac_get_container_count_resp {
+	u32		response; /* ST_OK */
+	u32		dummy0;
+	u32		MaxContainers;
+	u32		ContainerSwitchEntries;
+	u32		MaxPartitions;
+};
+
+
+/*
+ *	Query for "mountable" objects, ie, objects that are typically
+ *	associated with a drive letter on the client (host) side.
+ */
+
+struct aac_mntent {
+	u32    			oid;
+	u8			name[16];	// if applicable
+	struct creation_info	create_info;	// if applicable
+	u32			capacity;
+	u32			vol;    	// substrate structure
+	u32			obj;	        // FT_FILESYS, FT_DATABASE, etc.
+	u32			state;		// unready for mounting, readonly, etc.
+	union aac_contentinfo	fileinfo;	// Info specific to content manager (eg, filesystem)
+	u32			altoid;		// != oid <==> snapshot or broken mirror exists
+};
+
+#define FSCS_NOTCLEAN	0x0001  /* fsck is neccessary before mounting */
+#define FSCS_READONLY	0x0002	/* possible result of broken mirror */
+#define FSCS_HIDDEN	0x0004	/* should be ignored - set during a clear */
+
+struct aac_query_mount {
+	u32		command;
+	u32		type;
+	u32		count;
+};
+
+struct aac_mount {
+	u32		status;
+	u32	   	type;           /* should be same as that requested */
+	u32		count;
+	struct aac_mntent mnt[1];
+};
+
+#define CT_READ_NAME 130
+struct aac_get_name {
+	u32		command;	/* VM_ContainerConfig */
+	u32		type;		/* CT_READ_NAME */
+	u32		cid;
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		count;	/* sizeof(((struct aac_get_name_resp *)NULL)->data) */
+};
+
+#define CT_OK        218
+struct aac_get_name_resp {
+	u32		dummy0;
+	u32		dummy1;
+	u32		status;	/* CT_OK */
+	u32		parm1;
+	u32		parm2;
+	u32		parm3;
+	u32		parm4;
+	u32		parm5;
+	u8		data[16];
+};
+
+/*
+ * The following command is sent to shut down each container.
+ */
+
+struct aac_close {
+	u32	command;
+	u32	cid;
+};
+
+struct aac_query_disk
+{
+	s32	cnum;
+	s32	bus;
+	s32	id;
+	s32	lun;
+	u32	valid;
+	u32	locked;
+	u32	deleted;
+	s32	instance;
+	s8	name[10];
+	u32	unmapped;
+};
+
+struct aac_delete_disk {
+	u32	disknum;
+	u32	cnum;
+};
+ 
+struct fib_ioctl
+{
+	u32	fibctx;
+	s32	wait;
+	char	__user *fib;
+};
+
+struct revision
+{
+	u32 compat;
+	u32 version;
+	u32 build;
+};
+	
+/*
+ * 	Ugly - non Linux like ioctl coding for back compat.
+ */
+
+#define CTL_CODE(function, method) (                 \
+    (4<< 16) | ((function) << 2) | (method) \
+)
+
+/*
+ *	Define the method codes for how buffers are passed for I/O and FS 
+ *	controls
+ */
+
+#define METHOD_BUFFERED                 0
+#define METHOD_NEITHER                  3
+
+/*
+ *	Filesystem ioctls
+ */
+
+#define FSACTL_SENDFIB                  	CTL_CODE(2050, METHOD_BUFFERED)
+#define FSACTL_SEND_RAW_SRB               	CTL_CODE(2067, METHOD_BUFFERED)
+#define FSACTL_DELETE_DISK			0x163
+#define FSACTL_QUERY_DISK			0x173
+#define FSACTL_OPEN_GET_ADAPTER_FIB		CTL_CODE(2100, METHOD_BUFFERED)
+#define FSACTL_GET_NEXT_ADAPTER_FIB		CTL_CODE(2101, METHOD_BUFFERED)
+#define FSACTL_CLOSE_GET_ADAPTER_FIB		CTL_CODE(2102, METHOD_BUFFERED)
+#define FSACTL_MINIPORT_REV_CHECK               CTL_CODE(2107, METHOD_BUFFERED)
+#define FSACTL_GET_PCI_INFO               	CTL_CODE(2119, METHOD_BUFFERED)
+#define FSACTL_FORCE_DELETE_DISK		CTL_CODE(2120, METHOD_NEITHER)
+#define FSACTL_GET_CONTAINERS			2131
+
+
+struct aac_common
+{
+	/*
+	 *	If this value is set to 1 then interrupt moderation will occur 
+	 *	in the base commuication support.
+	 */
+	u32 irq_mod;
+	u32 peak_fibs;
+	u32 zero_fibs;
+	u32 fib_timeouts;
+	/*
+	 *	Statistical counters in debug mode
+	 */
+#ifdef DBG
+	u32 FibsSent;
+	u32 FibRecved;
+	u32 NoResponseSent;
+	u32 NoResponseRecved;
+	u32 AsyncSent;
+	u32 AsyncRecved;
+	u32 NormalSent;
+	u32 NormalRecved;
+#endif
+};
+
+extern struct aac_common aac_config;
+
+
+/*
+ *	The following macro is used when sending and receiving FIBs. It is
+ *	only used for debugging.
+ */
+ 
+#ifdef DBG
+#define	FIB_COUNTER_INCREMENT(counter)		(counter)++
+#else
+#define	FIB_COUNTER_INCREMENT(counter)		
+#endif
+
+/*
+ *	Adapter direct commands
+ *	Monitor/Kernel API
+ */
+
+#define	BREAKPOINT_REQUEST		0x00000004
+#define	INIT_STRUCT_BASE_ADDRESS	0x00000005
+#define READ_PERMANENT_PARAMETERS	0x0000000a
+#define WRITE_PERMANENT_PARAMETERS	0x0000000b
+#define HOST_CRASHING			0x0000000d
+#define	SEND_SYNCHRONOUS_FIB		0x0000000c
+#define COMMAND_POST_RESULTS		0x00000014
+#define GET_ADAPTER_PROPERTIES		0x00000019
+#define GET_DRIVER_BUFFER_PROPERTIES	0x00000023
+#define RCV_TEMP_READINGS		0x00000025
+#define GET_COMM_PREFERRED_SETTINGS	0x00000026
+#define IOP_RESET			0x00001000
+#define RE_INIT_ADAPTER			0x000000ee
+
+/*
+ *	Adapter Status Register
+ *
+ *  Phase Staus mailbox is 32bits:
+ *	<31:16> = Phase Status
+ *	<15:0>  = Phase
+ *
+ *	The adapter reports is present state through the phase.  Only
+ *	a single phase should be ever be set.  Each phase can have multiple
+ *	phase status bits to provide more detailed information about the 
+ *	state of the board.  Care should be taken to ensure that any phase 
+ *	status bits that are set when changing the phase are also valid
+ *	for the new phase or be cleared out.  Adapter software (monitor,
+ *	iflash, kernel) is responsible for properly maintining the phase 
+ *	status mailbox when it is running.
+ *											
+ *	MONKER_API Phases							
+ *
+ *	Phases are bit oriented.  It is NOT valid  to have multiple bits set						
+ */					
+
+#define	SELF_TEST_FAILED		0x00000004
+#define	MONITOR_PANIC			0x00000020
+#define	KERNEL_UP_AND_RUNNING		0x00000080
+#define	KERNEL_PANIC			0x00000100
+
+/*
+ *	Doorbell bit defines
+ */
+
+#define DoorBellSyncCmdAvailable	(1<<0)	/* Host -> Adapter */
+#define DoorBellPrintfDone		(1<<5)	/* Host -> Adapter */
+#define DoorBellAdapterNormCmdReady	(1<<1)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespReady	(1<<2)	/* Adapter -> Host */
+#define DoorBellAdapterNormCmdNotFull	(1<<3)	/* Adapter -> Host */
+#define DoorBellAdapterNormRespNotFull	(1<<4)	/* Adapter -> Host */
+#define DoorBellPrintfReady		(1<<5)	/* Adapter -> Host */
+
+/*
+ *	For FIB communication, we need all of the following things
+ *	to send back to the user.
+ */
+ 
+#define 	AifCmdEventNotify	1	/* Notify of event */
+#define			AifEnConfigChange	3	/* Adapter configuration change */
+#define			AifEnContainerChange	4	/* Container configuration change */
+#define			AifEnDeviceFailure	5	/* SCSI device failed */
+#define			AifEnAddContainer	15	/* A new array was created */
+#define			AifEnDeleteContainer	16	/* A container was deleted */
+#define			AifEnExpEvent		23	/* Firmware Event Log */
+#define			AifExeFirmwarePanic	3	/* Firmware Event Panic */
+#define			AifHighPriority		3	/* Highest Priority Event */
+
+#define		AifCmdJobProgress	2	/* Progress report */
+#define			AifJobCtrZero	101	/* Array Zero progress */
+#define			AifJobStsSuccess 1	/* Job completes */
+#define		AifCmdAPIReport		3	/* Report from other user of API */
+#define		AifCmdDriverNotify	4	/* Notify host driver of event */
+#define			AifDenMorphComplete 200	/* A morph operation completed */
+#define			AifDenVolumeExtendComplete 201 /* A volume extend completed */
+#define		AifReqJobList		100	/* Gets back complete job list */
+#define		AifReqJobsForCtr	101	/* Gets back jobs for specific container */
+#define		AifReqJobsForScsi	102	/* Gets back jobs for specific SCSI device */ 
+#define		AifReqJobReport		103	/* Gets back a specific job report or list of them */ 
+#define		AifReqTerminateJob	104	/* Terminates job */
+#define		AifReqSuspendJob	105	/* Suspends a job */
+#define		AifReqResumeJob		106	/* Resumes a job */ 
+#define		AifReqSendAPIReport	107	/* API generic report requests */
+#define		AifReqAPIJobStart	108	/* Start a job from the API */
+#define		AifReqAPIJobUpdate	109	/* Update a job report from the API */
+#define		AifReqAPIJobFinish	110	/* Finish a job from the API */
+
+/*
+ *	Adapter Initiated FIB command structures. Start with the adapter
+ *	initiated FIBs that really come from the adapter, and get responded
+ *	to by the host.
+ */
+
+struct aac_aifcmd {
+	u32 command;		/* Tell host what type of notify this is */
+	u32 seqnum;		/* To allow ordering of reports (if necessary) */
+	u8 data[1];		/* Undefined length (from kernel viewpoint) */
+};
+
+/**
+ * 	Convert capacity to cylinders
+ *  	accounting for the fact capacity could be a 64 bit value
+ *
+ */
+static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
+{
+	sector_div(capacity, divisor);
+	return (u32)capacity;
+}
+
+struct scsi_cmnd;
+
+const char *aac_driverinfo(struct Scsi_Host *);
+struct fib *fib_alloc(struct aac_dev *dev);
+int fib_setup(struct aac_dev *dev);
+void fib_map_free(struct aac_dev *dev);
+void fib_free(struct fib * context);
+void fib_init(struct fib * context);
+void fib_dealloc(struct fib * context);
+void aac_printf(struct aac_dev *dev, u32 val);
+int fib_send(u16 command, struct fib * context, unsigned long size, int priority, int wait, int reply, fib_callback callback, void *ctxt);
+int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry);
+void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
+int fib_complete(struct fib * context);
+#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
+struct aac_dev *aac_init_adapter(struct aac_dev *dev);
+int aac_get_config_status(struct aac_dev *dev);
+int aac_get_containers(struct aac_dev *dev);
+int aac_scsi_cmd(struct scsi_cmnd *cmd);
+int aac_dev_ioctl(struct aac_dev *dev, int cmd, void __user *arg);
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg);
+int aac_rx_init(struct aac_dev *dev);
+int aac_rkt_init(struct aac_dev *dev);
+int aac_sa_init(struct aac_dev *dev);
+unsigned int aac_response_normal(struct aac_queue * q);
+unsigned int aac_command_normal(struct aac_queue * q);
+int aac_command_thread(struct aac_dev * dev);
+int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context *fibctx);
+int fib_adapter_complete(struct fib * fibptr, unsigned short size);
+struct aac_driver_ident* aac_get_driver_ident(int devtype);
+int aac_get_adapter_info(struct aac_dev* dev);
+int aac_send_shutdown(struct aac_dev *dev);
diff --git a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
new file mode 100644
index 0000000..30dd1f7
--- /dev/null
+++ b/drivers/scsi/aacraid/commctrl.c
@@ -0,0 +1,683 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commctrl.c
+ *
+ * Abstract: Contains all routines for control of the AFA comm layer
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/dma-mapping.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+#include <asm/uaccess.h>
+
+#include "aacraid.h"
+
+/**
+ *	ioctl_send_fib	-	send a FIB from userspace
+ *	@dev:	adapter is being processed
+ *	@arg:	arguments to the ioctl call
+ *	
+ *	This routine sends a fib to the adapter on behalf of a user level
+ *	program.
+ */
+ 
+static int ioctl_send_fib(struct aac_dev * dev, void __user *arg)
+{
+	struct hw_fib * kfib;
+	struct fib *fibptr;
+
+	fibptr = fib_alloc(dev);
+	if(fibptr == NULL)
+		return -ENOMEM;
+		
+	kfib = fibptr->hw_fib;
+	/*
+	 *	First copy in the header so that we can check the size field.
+	 */
+	if (copy_from_user((void *)kfib, arg, sizeof(struct aac_fibhdr))) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+	/*
+	 *	Since we copy based on the fib header size, make sure that we
+	 *	will not overrun the buffer when we copy the memory. Return
+	 *	an error if we would.
+	 */
+	if (le16_to_cpu(kfib->header.Size) > 
+			sizeof(struct hw_fib) - sizeof(struct aac_fibhdr)) {
+		fib_free(fibptr);
+		return -EINVAL;
+	}
+
+	if (copy_from_user(kfib, arg, le16_to_cpu(kfib->header.Size) +
+				sizeof(struct aac_fibhdr))) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+
+	if (kfib->header.Command == cpu_to_le32(TakeABreakPt)) {
+		aac_adapter_interrupt(dev);
+		/*
+		 * Since we didn't really send a fib, zero out the state to allow 
+		 * cleanup code not to assert.
+		 */
+		kfib->header.XferState = 0;
+	} else {
+		int retval = fib_send(kfib->header.Command, fibptr,
+				le16_to_cpu(kfib->header.Size) , FsaNormal,
+				1, 1, NULL, NULL);
+		if (retval) {
+			fib_free(fibptr);
+			return retval;
+		}
+		if (fib_complete(fibptr) != 0) {
+			fib_free(fibptr);
+			return -EINVAL;
+		}
+	}
+	/*
+	 *	Make sure that the size returned by the adapter (which includes
+	 *	the header) is less than or equal to the size of a fib, so we
+	 *	don't corrupt application data. Then copy that size to the user
+	 *	buffer. (Don't try to add the header information again, since it
+	 *	was already included by the adapter.)
+	 */
+
+	if (copy_to_user(arg, (void *)kfib, kfib->header.Size)) {
+		fib_free(fibptr);
+		return -EFAULT;
+	}
+	fib_free(fibptr);
+	return 0;
+}
+
+/**
+ *	open_getadapter_fib	-	Get the next fib
+ *
+ *	This routine will get the next Fib, if available, from the AdapterFibContext
+ *	passed in from the user.
+ */
+
+static int open_getadapter_fib(struct aac_dev * dev, void __user *arg)
+{
+	struct aac_fib_context * fibctx;
+	int status;
+
+	fibctx = kmalloc(sizeof(struct aac_fib_context), GFP_KERNEL);
+	if (fibctx == NULL) {
+		status = -ENOMEM;
+	} else {
+		unsigned long flags;
+		struct list_head * entry;
+		struct aac_fib_context * context;
+
+		fibctx->type = FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT;
+		fibctx->size = sizeof(struct aac_fib_context);
+ 		/*
+		 *	Yes yes, I know this could be an index, but we have a
+		 * better guarantee of uniqueness for the locked loop below.
+		 * Without the aid of a persistent history, this also helps
+		 * reduce the chance that the opaque context would be reused.
+		 */
+		fibctx->unique = (u32)((ulong)fibctx & 0xFFFFFFFF);
+		/*
+		 *	Initialize the mutex used to wait for the next AIF.
+		 */
+		init_MUTEX_LOCKED(&fibctx->wait_sem);
+		fibctx->wait = 0;
+		/*
+		 *	Initialize the fibs and set the count of fibs on
+		 *	the list to 0.
+		 */
+		fibctx->count = 0;
+		INIT_LIST_HEAD(&fibctx->fib_list);
+		fibctx->jiffies = jiffies/HZ;
+		/*
+		 *	Now add this context onto the adapter's 
+		 *	AdapterFibContext list.
+		 */
+		spin_lock_irqsave(&dev->fib_lock, flags);
+		/* Ensure that we have a unique identifier */
+		entry = dev->fib_list.next;
+		while (entry != &dev->fib_list) {
+			context = list_entry(entry, struct aac_fib_context, next);
+			if (context->unique == fibctx->unique) {
+				/* Not unique (32 bits) */
+				fibctx->unique++;
+				entry = dev->fib_list.next;
+			} else {
+				entry = entry->next;
+			}
+		}
+		list_add_tail(&fibctx->next, &dev->fib_list);
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (copy_to_user(arg,  &fibctx->unique, 
+						sizeof(fibctx->unique))) {
+			status = -EFAULT;
+		} else {
+			status = 0;
+		}	
+	}
+	return status;
+}
+
+/**
+ *	next_getadapter_fib	-	get the next fib
+ *	@dev: adapter to use
+ *	@arg: ioctl argument
+ *	
+ * 	This routine will get the next Fib, if available, from the AdapterFibContext
+ *	passed in from the user.
+ */
+
+static int next_getadapter_fib(struct aac_dev * dev, void __user *arg)
+{
+	struct fib_ioctl f;
+	struct fib *fib;
+	struct aac_fib_context *fibctx;
+	int status;
+	struct list_head * entry;
+	unsigned long flags;
+	
+	if(copy_from_user((void *)&f, arg, sizeof(struct fib_ioctl)))
+		return -EFAULT;
+	/*
+	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
+	 *
+	 *	Search the list of AdapterFibContext addresses on the adapter
+	 *	to be sure this is a valid address
+	 */
+	entry = dev->fib_list.next;
+	fibctx = NULL;
+
+	while (entry != &dev->fib_list) {
+		fibctx = list_entry(entry, struct aac_fib_context, next);
+		/*
+		 *	Extract the AdapterFibContext from the Input parameters.
+		 */
+		if (fibctx->unique == f.fibctx) {   /* We found a winner */
+			break;
+		}
+		entry = entry->next;
+		fibctx = NULL;
+	}
+	if (!fibctx) {
+		dprintk ((KERN_INFO "Fib Context not found\n"));
+		return -EINVAL;
+	}
+
+	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (fibctx->size != sizeof(struct aac_fib_context))) {
+		dprintk ((KERN_INFO "Fib Context corrupt?\n"));
+		return -EINVAL;
+	}
+	status = 0;
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	/*
+	 *	If there are no fibs to send back, then either wait or return
+	 *	-EAGAIN
+	 */
+return_fib:
+	if (!list_empty(&fibctx->fib_list)) {
+		struct list_head * entry;
+		/*
+		 *	Pull the next fib from the fibs
+		 */
+		entry = fibctx->fib_list.next;
+		list_del(entry);
+		
+		fib = list_entry(entry, struct fib, fiblink);
+		fibctx->count--;
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (copy_to_user(f.fib, fib->hw_fib, sizeof(struct hw_fib))) {
+			kfree(fib->hw_fib);
+			kfree(fib);
+			return -EFAULT;
+		}	
+		/*
+		 *	Free the space occupied by this copy of the fib.
+		 */
+		kfree(fib->hw_fib);
+		kfree(fib);
+		status = 0;
+		fibctx->jiffies = jiffies/HZ;
+	} else {
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		if (f.wait) {
+			if(down_interruptible(&fibctx->wait_sem) < 0) {
+				status = -EINTR;
+			} else {
+				/* Lock again and retry */
+				spin_lock_irqsave(&dev->fib_lock, flags);
+				goto return_fib;
+			}
+		} else {
+			status = -EAGAIN;
+		}	
+	}
+	return status;
+}
+
+int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
+{
+	struct fib *fib;
+
+	/*
+	 *	First free any FIBs that have not been consumed.
+	 */
+	while (!list_empty(&fibctx->fib_list)) {
+		struct list_head * entry;
+		/*
+		 *	Pull the next fib from the fibs
+		 */
+		entry = fibctx->fib_list.next;
+		list_del(entry);
+		fib = list_entry(entry, struct fib, fiblink);
+		fibctx->count--;
+		/*
+		 *	Free the space occupied by this copy of the fib.
+		 */
+		kfree(fib->hw_fib);
+		kfree(fib);
+	}
+	/*
+	 *	Remove the Context from the AdapterFibContext List
+	 */
+	list_del(&fibctx->next);
+	/*
+	 *	Invalidate context
+	 */
+	fibctx->type = 0;
+	/*
+	 *	Free the space occupied by the Context
+	 */
+	kfree(fibctx);
+	return 0;
+}
+
+/**
+ *	close_getadapter_fib	-	close down user fib context
+ *	@dev: adapter
+ *	@arg: ioctl arguments
+ *
+ *	This routine will close down the fibctx passed in from the user.
+ */
+ 
+static int close_getadapter_fib(struct aac_dev * dev, void __user *arg)
+{
+	struct aac_fib_context *fibctx;
+	int status;
+	unsigned long flags;
+	struct list_head * entry;
+
+	/*
+	 *	Verify that the HANDLE passed in was a valid AdapterFibContext
+	 *
+	 *	Search the list of AdapterFibContext addresses on the adapter
+	 *	to be sure this is a valid address
+	 */
+
+	entry = dev->fib_list.next;
+	fibctx = NULL;
+
+	while(entry != &dev->fib_list) {
+		fibctx = list_entry(entry, struct aac_fib_context, next);
+		/*
+		 *	Extract the fibctx from the input parameters
+		 */
+		if (fibctx->unique == (u32)(unsigned long)arg) {   
+			/* We found a winner */
+			break;
+		}
+		entry = entry->next;
+		fibctx = NULL;
+	}
+
+	if (!fibctx)
+		return 0; /* Already gone */
+
+	if((fibctx->type != FSAFS_NTC_GET_ADAPTER_FIB_CONTEXT) ||
+		 (fibctx->size != sizeof(struct aac_fib_context)))
+		return -EINVAL;
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	status = aac_close_fib_context(dev, fibctx);
+	spin_unlock_irqrestore(&dev->fib_lock, flags);
+	return status;
+}
+
+/**
+ *	check_revision	-	close down user fib context
+ *	@dev: adapter
+ *	@arg: ioctl arguments
+ *
+ *	This routine returns the driver version.
+ *      Under Linux, there have been no version incompatibilities, so this is 
+ *      simple!
+ */
+
+static int check_revision(struct aac_dev *dev, void __user *arg)
+{
+	struct revision response;
+
+	response.compat = 1;
+	response.version = dev->adapter_info.kernelrev;
+	response.build = dev->adapter_info.kernelbuild;
+
+	if (copy_to_user(arg, &response, sizeof(response)))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ *
+ * aac_send_raw_scb
+ *
+ */
+
+int aac_send_raw_srb(struct aac_dev* dev, void __user * arg)
+{
+	struct fib* srbfib;
+	int status;
+	struct aac_srb *srbcmd;
+	struct aac_srb __user *user_srb = arg;
+	struct aac_srb_reply __user *user_reply;
+	struct aac_srb_reply* reply;
+	u32 fibsize = 0;
+	u32 flags = 0;
+	s32 rcode = 0;
+	u32 data_dir;
+	void __user *sg_user[32];
+	void *sg_list[32];
+	u32   sg_indx = 0;
+	u32 byte_count = 0;
+	u32 actual_fibsize = 0;
+	int i;
+
+
+	if (!capable(CAP_SYS_ADMIN)){
+		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
+		return -EPERM;
+	}
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(srbfib = fib_alloc(dev))) {
+		return -1;
+	}
+	fib_init(srbfib);
+
+	srbcmd = (struct aac_srb*) fib_data(srbfib);
+
+	if(copy_from_user(&fibsize, &user_srb->count,sizeof(u32))){
+		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	if (fibsize > FIB_DATA_SIZE_IN_BYTES) {
+		rcode = -EINVAL;
+		goto cleanup;
+	}
+
+	if(copy_from_user(srbcmd, user_srb,fibsize)){
+		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	user_reply = arg+fibsize;
+
+	flags = srbcmd->flags;
+	// Fix up srb for endian and force some values
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
+	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
+	srbcmd->id	 = cpu_to_le32(srbcmd->id);
+	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
+	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
+	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
+	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
+	
+	switch (srbcmd->flags & (SRB_DataIn | SRB_DataOut)) {
+	case SRB_DataOut:
+		data_dir = DMA_TO_DEVICE;
+		break;
+	case (SRB_DataIn | SRB_DataOut):
+		data_dir = DMA_BIDIRECTIONAL;
+		break;
+	case SRB_DataIn:
+		data_dir = DMA_FROM_DEVICE;
+		break;
+	default:
+		data_dir = DMA_NONE;
+	}
+	if (dev->dac_support == 1) {
+		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
+		byte_count = 0;
+
+		/*
+		 * This should also catch if user used the 32 bit sgmap
+		 */
+		actual_fibsize = sizeof(struct aac_srb) - 
+			sizeof(struct sgentry) + ((srbcmd->sg.count & 0xff) * 
+			 	sizeof(struct sgentry64));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == DMA_NONE) && psg->count) { 
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			u64 le_addr;
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (void __user *)psg->sg[i].addr;
+			sg_list[i] = p; // save so we can clean up later
+			sg_indx = i;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
+
+			le_addr = cpu_to_le64(addr);
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,NULL,NULL);
+	} else {
+		struct sgmap* psg = &srbcmd->sg;
+		byte_count = 0;
+
+		actual_fibsize = sizeof (struct aac_srb) + 
+			(((le32_to_cpu(srbcmd->sg.count) & 0xff) - 1) * 
+			 sizeof (struct sgentry));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		if ((data_dir == DMA_NONE) && psg->count) {
+			printk(KERN_DEBUG"aacraid: SG with no direction specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (void __user *)(psg->sg[i].addr);
+			sg_list[i] = p; // save so we can clean up later
+			sg_indx = i;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user(p,sg_user[i],psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, data_dir);
+
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, NULL, NULL);
+	}
+
+	if (status != 0){
+		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
+		rcode = -1;
+		goto cleanup;
+	}
+
+	if( flags & SRB_DataIn ) {
+		for(i = 0 ; i <= sg_indx; i++){
+			if(copy_to_user(sg_user[i],sg_list[i],le32_to_cpu(srbcmd->sg.sg[i].count))){
+				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
+				rcode = -EFAULT;
+				goto cleanup;
+
+			}
+		}
+	}
+
+	reply = (struct aac_srb_reply *) fib_data(srbfib);
+	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
+		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+cleanup:
+	for(i=0; i <= sg_indx; i++){
+		kfree(sg_list[i]);
+	}
+	fib_complete(srbfib);
+	fib_free(srbfib);
+
+	return rcode;
+}
+
+
+struct aac_pci_info {
+        u32 bus;
+        u32 slot;
+};
+
+
+int aac_get_pci_info(struct aac_dev* dev, void __user *arg)
+{
+        struct aac_pci_info pci_info;
+
+	pci_info.bus = dev->pdev->bus->number;
+	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
+
+       if (copy_to_user(arg, &pci_info, sizeof(struct aac_pci_info))) {
+		printk(KERN_DEBUG "aacraid: Could not copy pci info\n");
+               return -EFAULT;
+	}
+        return 0;
+ }
+ 
+
+int aac_do_ioctl(struct aac_dev * dev, int cmd, void __user *arg)
+{
+	int status;
+	
+	/*
+	 *	HBA gets first crack
+	 */
+	 
+	status = aac_dev_ioctl(dev, cmd, arg);
+	if(status != -ENOTTY)
+		return status;
+
+	switch (cmd) {
+	case FSACTL_MINIPORT_REV_CHECK:
+		status = check_revision(dev, arg);
+		break;
+	case FSACTL_SENDFIB:
+		status = ioctl_send_fib(dev, arg);
+		break;
+	case FSACTL_OPEN_GET_ADAPTER_FIB:
+		status = open_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_GET_NEXT_ADAPTER_FIB:
+		status = next_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_CLOSE_GET_ADAPTER_FIB:
+		status = close_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_SEND_RAW_SRB:
+		status = aac_send_raw_srb(dev,arg);
+		break;
+	case FSACTL_GET_PCI_INFO:
+		status = aac_get_pci_info(dev,arg);
+		break;
+	default:
+		status = -ENOTTY;
+	  	break;	
+	}
+	return status;
+}
+
diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
new file mode 100644
index 0000000..6832a55
--- /dev/null
+++ b/drivers/scsi/aacraid/comminit.c
@@ -0,0 +1,325 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  comminit.c
+ *
+ * Abstract: This supports the initialization of the host adapter commuication interface.
+ *    This is a platform dependent module for the pci cyclone board.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/mm.h>
+#include <asm/semaphore.h>
+
+#include "aacraid.h"
+
+struct aac_common aac_config;
+
+static int aac_alloc_comm(struct aac_dev *dev, void **commaddr, unsigned long commsize, unsigned long commalign)
+{
+	unsigned char *base;
+	unsigned long size, align;
+	unsigned long fibsize = 4096;
+	unsigned long printfbufsiz = 256;
+	struct aac_init *init;
+	dma_addr_t phys;
+
+	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
+
+ 
+	base = pci_alloc_consistent(dev->pdev, size, &phys);
+
+	if(base == NULL)
+	{
+		printk(KERN_ERR "aacraid: unable to create mapping.\n");
+		return 0;
+	}
+	dev->comm_addr = (void *)base;
+	dev->comm_phys = phys;
+	dev->comm_size = size;
+	
+	dev->init = (struct aac_init *)(base + fibsize);
+	dev->init_pa = phys + fibsize;
+
+	init = dev->init;
+
+	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
+	init->MiniPortRevision = cpu_to_le32(Sa_MINIPORT_REVISION);
+	init->fsrev = cpu_to_le32(dev->fsrev);
+
+	/*
+	 *	Adapter Fibs are the first thing allocated so that they
+	 *	start page aligned
+	 */
+	dev->aif_base_va = (struct hw_fib *)base;
+	
+	init->AdapterFibsVirtualAddress = 0;
+	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
+	init->AdapterFibsSize = cpu_to_le32(fibsize);
+	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
+	/* 
+	 * number of 4k pages of host physical memory. The aacraid fw needs
+	 * this number to be less than 4gb worth of pages. num_physpages is in
+	 * system page units. New firmware doesn't have any issues with the
+	 * mapping system, but older Firmware did, and had *troubles* dealing
+	 * with the math overloading past 32 bits, thus we must limit this
+	 * field.
+	 *
+	 * This assumes the memory is mapped zero->n, which isnt
+	 * always true on real computers. It also has some slight problems
+	 * with the GART on x86-64. I've btw never tried DMA from PCI space
+	 * on this platform but don't be suprised if its problematic.
+	 */
+#ifndef CONFIG_GART_IOMMU
+	if ((num_physpages << (PAGE_SHIFT - 12)) <= AAC_MAX_HOSTPHYSMEMPAGES) {
+		init->HostPhysMemPages = 
+			cpu_to_le32(num_physpages << (PAGE_SHIFT-12));
+	} else 
+#endif	
+	{
+		init->HostPhysMemPages = cpu_to_le32(AAC_MAX_HOSTPHYSMEMPAGES);
+	}
+
+
+	/*
+	 * Increment the base address by the amount already used
+	 */
+	base = base + fibsize + sizeof(struct aac_init);
+	phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init));
+	/*
+	 *	Align the beginning of Headers to commalign
+	 */
+	align = (commalign - ((unsigned long)(base) & (commalign - 1)));
+	base = base + align;
+	phys = phys + align;
+	/*
+	 *	Fill in addresses of the Comm Area Headers and Queues
+	 */
+	*commaddr = base;
+	init->CommHeaderAddress = cpu_to_le32((u32)phys);
+	/*
+	 *	Increment the base address by the size of the CommArea
+	 */
+	base = base + commsize;
+	phys = phys + commsize;
+	/*
+	 *	 Place the Printf buffer area after the Fast I/O comm area.
+	 */
+	dev->printfbuf = (void *)base;
+	init->printfbuf = cpu_to_le32(phys);
+	init->printfbufsiz = cpu_to_le32(printfbufsiz);
+	memset(base, 0, printfbufsiz);
+	return 1;
+}
+    
+static void aac_queue_init(struct aac_dev * dev, struct aac_queue * q, u32 *mem, int qsize)
+{
+	q->numpending = 0;
+	q->dev = dev;
+	INIT_LIST_HEAD(&q->pendingq);
+	init_waitqueue_head(&q->cmdready);
+	INIT_LIST_HEAD(&q->cmdq);
+	init_waitqueue_head(&q->qfull);
+	spin_lock_init(&q->lockdata);
+	q->lock = &q->lockdata;
+	q->headers.producer = mem;
+	q->headers.consumer = mem+1;
+	*(q->headers.producer) = cpu_to_le32(qsize);
+	*(q->headers.consumer) = cpu_to_le32(qsize);
+	q->entries = qsize;
+}
+
+/**
+ *	aac_send_shutdown		-	shutdown an adapter
+ *	@dev: Adapter to shutdown
+ *
+ *	This routine will send a VM_CloseAll (shutdown) request to the adapter.
+ */
+
+int aac_send_shutdown(struct aac_dev * dev)
+{
+	struct fib * fibctx;
+	struct aac_close *cmd;
+	int status;
+
+	fibctx = fib_alloc(dev);
+	fib_init(fibctx);
+
+	cmd = (struct aac_close *) fib_data(fibctx);
+
+	cmd->command = cpu_to_le32(VM_CloseAll);
+	cmd->cid = cpu_to_le32(0xffffffff);
+
+	status = fib_send(ContainerCommand,
+			  fibctx,
+			  sizeof(struct aac_close),
+			  FsaNormal,
+			  1, 1,
+			  NULL, NULL);
+
+	if (status == 0)
+		fib_complete(fibctx);
+	fib_free(fibctx);
+	return status;
+}
+
+/**
+ *	aac_comm_init	-	Initialise FSA data structures
+ *	@dev:	Adapter to initialise
+ *
+ *	Initializes the data structures that are required for the FSA commuication
+ *	interface to operate. 
+ *	Returns
+ *		1 - if we were able to init the commuication interface.
+ *		0 - If there were errors initing. This is a fatal error.
+ */
+ 
+int aac_comm_init(struct aac_dev * dev)
+{
+	unsigned long hdrsize = (sizeof(u32) * NUMBER_OF_COMM_QUEUES) * 2;
+	unsigned long queuesize = sizeof(struct aac_entry) * TOTAL_QUEUE_ENTRIES;
+	u32 *headers;
+	struct aac_entry * queues;
+	unsigned long size;
+	struct aac_queue_block * comm = dev->queues;
+	/*
+	 *	Now allocate and initialize the zone structures used as our 
+	 *	pool of FIB context records.  The size of the zone is based
+	 *	on the system memory size.  We also initialize the mutex used
+	 *	to protect the zone.
+	 */
+	spin_lock_init(&dev->fib_lock);
+
+	/*
+	 *	Allocate the physically contigous space for the commuication
+	 *	queue headers. 
+	 */
+
+	size = hdrsize + queuesize;
+
+	if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT))
+		return -ENOMEM;
+
+	queues = (struct aac_entry *)(((ulong)headers) + hdrsize);
+
+	/* Adapter to Host normal priority Command queue */ 
+	comm->queue[HostNormCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES);
+	queues += HOST_NORM_CMD_ENTRIES;
+	headers += 2;
+
+	/* Adapter to Host high priority command queue */
+	comm->queue[HostHighCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostHighCmdQueue], headers, HOST_HIGH_CMD_ENTRIES);
+    
+	queues += HOST_HIGH_CMD_ENTRIES;
+	headers +=2;
+
+	/* Host to adapter normal priority command queue */
+	comm->queue[AdapNormCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapNormCmdQueue], headers, ADAP_NORM_CMD_ENTRIES);
+    
+	queues += ADAP_NORM_CMD_ENTRIES;
+	headers += 2;
+
+	/* host to adapter high priority command queue */
+	comm->queue[AdapHighCmdQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapHighCmdQueue], headers, ADAP_HIGH_CMD_ENTRIES);
+    
+	queues += ADAP_HIGH_CMD_ENTRIES;
+	headers += 2;
+
+	/* adapter to host normal priority response queue */
+	comm->queue[HostNormRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES);
+	queues += HOST_NORM_RESP_ENTRIES;
+	headers += 2;
+
+	/* adapter to host high priority response queue */
+	comm->queue[HostHighRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[HostHighRespQueue], headers, HOST_HIGH_RESP_ENTRIES);
+   
+	queues += HOST_HIGH_RESP_ENTRIES;
+	headers += 2;
+
+	/* host to adapter normal priority response queue */
+	comm->queue[AdapNormRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapNormRespQueue], headers, ADAP_NORM_RESP_ENTRIES);
+
+	queues += ADAP_NORM_RESP_ENTRIES;
+	headers += 2;
+	
+	/* host to adapter high priority response queue */ 
+	comm->queue[AdapHighRespQueue].base = queues;
+	aac_queue_init(dev, &comm->queue[AdapHighRespQueue], headers, ADAP_HIGH_RESP_ENTRIES);
+
+	comm->queue[AdapNormCmdQueue].lock = comm->queue[HostNormRespQueue].lock;
+	comm->queue[AdapHighCmdQueue].lock = comm->queue[HostHighRespQueue].lock;
+	comm->queue[AdapNormRespQueue].lock = comm->queue[HostNormCmdQueue].lock;
+	comm->queue[AdapHighRespQueue].lock = comm->queue[HostHighCmdQueue].lock;
+
+	return 0;
+}
+
+struct aac_dev *aac_init_adapter(struct aac_dev *dev)
+{
+	/*
+	 *	Ok now init the communication subsystem
+	 */
+
+	dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
+	if (dev->queues == NULL) {
+		printk(KERN_ERR "Error could not allocate comm region.\n");
+		return NULL;
+	}
+	memset(dev->queues, 0, sizeof(struct aac_queue_block));
+
+	if (aac_comm_init(dev)<0){
+		kfree(dev->queues);
+		return NULL;
+	}
+	/*
+	 *	Initialize the list of fibs
+	 */
+	if(fib_setup(dev)<0){
+		kfree(dev->queues);
+		return NULL;
+	}
+		
+	INIT_LIST_HEAD(&dev->fib_list);
+	init_completion(&dev->aif_completion);
+
+	return dev;
+}
+
+    
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
new file mode 100644
index 0000000..3f36dba
--- /dev/null
+++ b/drivers/scsi/aacraid/commsup.c
@@ -0,0 +1,939 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  commsup.c
+ *
+ * Abstract: Contain all routines that are required for FSA host/adapter
+ *    commuication.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+
+#include "aacraid.h"
+
+/**
+ *	fib_map_alloc		-	allocate the fib objects
+ *	@dev: Adapter to allocate for
+ *
+ *	Allocate and map the shared PCI space for the FIB blocks used to
+ *	talk to the Adaptec firmware.
+ */
+ 
+static int fib_map_alloc(struct aac_dev *dev)
+{
+	if((dev->hw_fib_va = pci_alloc_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, &dev->hw_fib_pa))==NULL)
+		return -ENOMEM;
+	return 0;
+}
+
+/**
+ *	fib_map_free		-	free the fib objects
+ *	@dev: Adapter to free
+ *
+ *	Free the PCI mappings and the memory allocated for FIB blocks
+ *	on this adapter.
+ */
+
+void fib_map_free(struct aac_dev *dev)
+{
+	pci_free_consistent(dev->pdev, sizeof(struct hw_fib) * AAC_NUM_FIB, dev->hw_fib_va, dev->hw_fib_pa);
+}
+
+/**
+ *	fib_setup	-	setup the fibs
+ *	@dev: Adapter to set up
+ *
+ *	Allocate the PCI space for the fibs, map it and then intialise the
+ *	fib area, the unmapped fib data and also the free list
+ */
+
+int fib_setup(struct aac_dev * dev)
+{
+	struct fib *fibptr;
+	struct hw_fib *hw_fib_va;
+	dma_addr_t hw_fib_pa;
+	int i;
+	
+	if(fib_map_alloc(dev)<0)
+		return -ENOMEM;
+		
+	hw_fib_va = dev->hw_fib_va;
+	hw_fib_pa = dev->hw_fib_pa;
+	memset(hw_fib_va, 0, sizeof(struct hw_fib) * AAC_NUM_FIB);
+	/*
+	 *	Initialise the fibs
+	 */
+	for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) 
+	{
+		fibptr->dev = dev;
+		fibptr->hw_fib = hw_fib_va;
+		fibptr->data = (void *) fibptr->hw_fib->data;
+		fibptr->next = fibptr+1;	/* Forward chain the fibs */
+		init_MUTEX_LOCKED(&fibptr->event_wait);
+		spin_lock_init(&fibptr->event_lock);
+		hw_fib_va->header.XferState = 0xffffffff;
+		hw_fib_va->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+		fibptr->hw_fib_pa = hw_fib_pa;
+		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + sizeof(struct hw_fib));
+		hw_fib_pa = hw_fib_pa + sizeof(struct hw_fib); 
+	}
+	/*
+	 *	Add the fib chain to the free list
+	 */
+	dev->fibs[AAC_NUM_FIB-1].next = NULL;
+	/*
+	 *	Enable this to debug out of queue space
+	 */
+	dev->free_fib = &dev->fibs[0];
+	return 0;
+}
+
+/**
+ *	fib_alloc	-	allocate a fib
+ *	@dev: Adapter to allocate the fib for
+ *
+ *	Allocate a fib from the adapter fib pool. If the pool is empty we
+ *	wait for fibs to become free.
+ */
+ 
+struct fib * fib_alloc(struct aac_dev *dev)
+{
+	struct fib * fibptr;
+	unsigned long flags;
+	spin_lock_irqsave(&dev->fib_lock, flags);
+	fibptr = dev->free_fib;	
+	/* Cannot sleep here or you get hangs. Instead we did the
+	   maths at compile time. */
+	if(!fibptr)
+		BUG();
+	dev->free_fib = fibptr->next;
+	spin_unlock_irqrestore(&dev->fib_lock, flags);
+	/*
+	 *	Set the proper node type code and node byte size
+	 */
+	fibptr->type = FSAFS_NTC_FIB_CONTEXT;
+	fibptr->size = sizeof(struct fib);
+	/*
+	 *	Null out fields that depend on being zero at the start of
+	 *	each I/O
+	 */
+	fibptr->hw_fib->header.XferState = 0;
+	fibptr->callback = NULL;
+	fibptr->callback_data = NULL;
+
+	return fibptr;
+}
+
+/**
+ *	fib_free	-	free a fib
+ *	@fibptr: fib to free up
+ *
+ *	Frees up a fib and places it on the appropriate queue
+ *	(either free or timed out)
+ */
+ 
+void fib_free(struct fib * fibptr)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
+	if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
+		aac_config.fib_timeouts++;
+		fibptr->next = fibptr->dev->timeout_fib;
+		fibptr->dev->timeout_fib = fibptr;
+	} else {
+		if (fibptr->hw_fib->header.XferState != 0) {
+			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
+				 (void*)fibptr, 
+				 le32_to_cpu(fibptr->hw_fib->header.XferState));
+		}
+		fibptr->next = fibptr->dev->free_fib;
+		fibptr->dev->free_fib = fibptr;
+	}	
+	spin_unlock_irqrestore(&fibptr->dev->fib_lock, flags);
+}
+
+/**
+ *	fib_init	-	initialise a fib
+ *	@fibptr: The fib to initialize
+ *	
+ *	Set up the generic fib fields ready for use
+ */
+ 
+void fib_init(struct fib *fibptr)
+{
+	struct hw_fib *hw_fib = fibptr->hw_fib;
+
+	hw_fib->header.StructType = FIB_MAGIC;
+	hw_fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
+        hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
+	hw_fib->header.SenderFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+	hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+	hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+}
+
+/**
+ *	fib_deallocate		-	deallocate a fib
+ *	@fibptr: fib to deallocate
+ *
+ *	Will deallocate and return to the free pool the FIB pointed to by the
+ *	caller.
+ */
+ 
+void fib_dealloc(struct fib * fibptr)
+{
+	struct hw_fib *hw_fib = fibptr->hw_fib;
+	if(hw_fib->header.StructType != FIB_MAGIC) 
+		BUG();
+	hw_fib->header.XferState = 0;        
+}
+
+/*
+ *	Commuication primitives define and support the queuing method we use to
+ *	support host to adapter commuication. All queue accesses happen through
+ *	these routines and are the only routines which have a knowledge of the
+ *	 how these queues are implemented.
+ */
+ 
+/**
+ *	aac_get_entry		-	get a queue entry
+ *	@dev: Adapter
+ *	@qid: Queue Number
+ *	@entry: Entry return
+ *	@index: Index return
+ *	@nonotify: notification control
+ *
+ *	With a priority the routine returns a queue entry if the queue has free entries. If the queue
+ *	is full(no free entries) than no entry is returned and the function returns 0 otherwise 1 is
+ *	returned.
+ */
+ 
+static int aac_get_entry (struct aac_dev * dev, u32 qid, struct aac_entry **entry, u32 * index, unsigned long *nonotify)
+{
+	struct aac_queue * q;
+
+	/*
+	 *	All of the queues wrap when they reach the end, so we check
+	 *	to see if they have reached the end and if they have we just
+	 *	set the index back to zero. This is a wrap. You could or off
+	 *	the high bits in all updates but this is a bit faster I think.
+	 */
+
+	q = &dev->queues->queue[qid];
+	
+	*index = le32_to_cpu(*(q->headers.producer));
+	if ((*index - 2) == le32_to_cpu(*(q->headers.consumer)))
+			*nonotify = 1; 
+
+	if (qid == AdapHighCmdQueue) {
+	        if (*index >= ADAP_HIGH_CMD_ENTRIES)
+        		*index = 0;
+	} else if (qid == AdapNormCmdQueue) {
+	        if (*index >= ADAP_NORM_CMD_ENTRIES) 
+			*index = 0; /* Wrap to front of the Producer Queue. */
+	}
+	else if (qid == AdapHighRespQueue) 
+	{
+	        if (*index >= ADAP_HIGH_RESP_ENTRIES)
+			*index = 0;
+	}
+	else if (qid == AdapNormRespQueue) 
+	{
+		if (*index >= ADAP_NORM_RESP_ENTRIES) 
+			*index = 0; /* Wrap to front of the Producer Queue. */
+	}
+	else {
+		printk("aacraid: invalid qid\n");
+		BUG();
+	}
+
+        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+		printk(KERN_WARNING "Queue %d full, %d outstanding.\n",
+				qid, q->numpending);
+		return 0;
+	} else {
+	        *entry = q->base + *index;
+		return 1;
+	}
+}   
+
+/**
+ *	aac_queue_get		-	get the next free QE
+ *	@dev: Adapter
+ *	@index: Returned index
+ *	@priority: Priority of fib
+ *	@fib: Fib to associate with the queue entry
+ *	@wait: Wait if queue full
+ *	@fibptr: Driver fib object to go with fib
+ *	@nonotify: Don't notify the adapter
+ *
+ *	Gets the next free QE off the requested priorty adapter command
+ *	queue and associates the Fib with the QE. The QE represented by
+ *	index is ready to insert on the queue when this routine returns
+ *	success.
+ */
+
+static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify)
+{
+	struct aac_entry * entry = NULL;
+	int map = 0;
+	struct aac_queue * q = &dev->queues->queue[qid];
+		
+	spin_lock_irqsave(q->lock, q->SavedIrql);
+	    
+	if (qid == AdapHighCmdQueue || qid == AdapNormCmdQueue) 
+	{
+		/*  if no entries wait for some if caller wants to */
+        	while (!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+        	{
+			printk(KERN_ERR "GetEntries failed\n");
+		}
+	        /*
+	         *	Setup queue entry with a command, status and fib mapped
+	         */
+	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+	        map = 1;
+	}
+	else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue)
+	{
+	        while(!aac_get_entry(dev, qid, &entry, index, nonotify)) 
+	        {
+			/* if no entries wait for some if caller wants to */
+		}
+        	/*
+        	 *	Setup queue entry with command, status and fib mapped
+        	 */
+        	entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+        	entry->addr = hw_fib->header.SenderFibAddress;
+     			/* Restore adapters pointer to the FIB */
+		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
+        	map = 0;
+	}
+	/*
+	 *	If MapFib is true than we need to map the Fib and put pointers
+	 *	in the queue entry.
+	 */
+	if (map)
+		entry->addr = cpu_to_le32(fibptr->hw_fib_pa);
+	return 0;
+}
+
+
+/**
+ *	aac_insert_entry	-	insert a queue entry
+ *	@dev: Adapter
+ *	@index: Index of entry to insert
+ *	@qid: Queue number
+ *	@nonotify: Suppress adapter notification
+ *
+ *	Gets the next free QE off the requested priorty adapter command
+ *	queue and associates the Fib with the QE. The QE represented by
+ *	index is ready to insert on the queue when this routine returns
+ *	success.
+ */
+ 
+static int aac_insert_entry(struct aac_dev * dev, u32 index, u32 qid, unsigned long nonotify) 
+{
+	struct aac_queue * q = &dev->queues->queue[qid];
+
+	if(q == NULL)
+		BUG();
+	*(q->headers.producer) = cpu_to_le32(index + 1);
+	spin_unlock_irqrestore(q->lock, q->SavedIrql);
+
+	if (qid == AdapHighCmdQueue ||
+	    qid == AdapNormCmdQueue ||
+	    qid == AdapHighRespQueue ||
+	    qid == AdapNormRespQueue)
+	{
+		if (!nonotify)
+			aac_adapter_notify(dev, qid);
+	}
+	else
+		printk("Suprise insert!\n");
+	return 0;
+}
+
+/*
+ *	Define the highest level of host to adapter communication routines. 
+ *	These routines will support host to adapter FS commuication. These 
+ *	routines have no knowledge of the commuication method used. This level
+ *	sends and receives FIBs. This level has no knowledge of how these FIBs
+ *	get passed back and forth.
+ */
+
+/**
+ *	fib_send	-	send a fib to the adapter
+ *	@command: Command to send
+ *	@fibptr: The fib
+ *	@size: Size of fib data area
+ *	@priority: Priority of Fib
+ *	@wait: Async/sync select
+ *	@reply: True if a reply is wanted
+ *	@callback: Called with reply
+ *	@callback_data: Passed to callback
+ *
+ *	Sends the requested FIB to the adapter and optionally will wait for a
+ *	response FIB. If the caller does not wish to wait for a response than
+ *	an event to wait on must be supplied. This event will be set when a
+ *	response FIB is received from the adapter.
+ */
+ 
+int fib_send(u16 command, struct fib * fibptr, unsigned long size,  int priority, int wait, int reply, fib_callback callback, void * callback_data)
+{
+	u32 index;
+	u32 qid;
+	struct aac_dev * dev = fibptr->dev;
+	unsigned long nointr = 0;
+	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct aac_queue * q;
+	unsigned long flags = 0;
+	if (!(hw_fib->header.XferState & cpu_to_le32(HostOwned)))
+		return -EBUSY;
+	/*
+	 *	There are 5 cases with the wait and reponse requested flags. 
+	 *	The only invalid cases are if the caller requests to wait and
+	 *	does not request a response and if the caller does not want a
+	 *	response and the Fib is not allocated from pool. If a response
+	 *	is not requesed the Fib will just be deallocaed by the DPC
+	 *	routine when the response comes back from the adapter. No
+	 *	further processing will be done besides deleting the Fib. We 
+	 *	will have a debug mode where the adapter can notify the host
+	 *	it had a problem and the host can log that fact.
+	 */
+	if (wait && !reply) {
+		return -EINVAL;
+	} else if (!wait && reply) {
+		hw_fib->header.XferState |= cpu_to_le32(Async | ResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.AsyncSent);
+	} else if (!wait && !reply) {
+		hw_fib->header.XferState |= cpu_to_le32(NoResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.NoResponseSent);
+	} else if (wait && reply) {
+		hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
+		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
+	} 
+	/*
+	 *	Map the fib into 32bits by using the fib number
+	 */
+
+	hw_fib->header.SenderFibAddress = cpu_to_le32(((u32)(fibptr-dev->fibs)) << 1);
+	hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
+	/*
+	 *	Set FIB state to indicate where it came from and if we want a
+	 *	response from the adapter. Also load the command from the
+	 *	caller.
+	 *
+	 *	Map the hw fib pointer as a 32bit value
+	 */
+	hw_fib->header.Command = cpu_to_le16(command);
+	hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
+	fibptr->hw_fib->header.Flags = 0;	/* 0 the flags field - internal only*/
+	/*
+	 *	Set the size of the Fib we want to send to the adapter
+	 */
+	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
+	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
+		return -EMSGSIZE;
+	}                
+	/*
+	 *	Get a queue entry connect the FIB to it and send an notify
+	 *	the adapter a command is ready.
+	 */
+	if (priority == FsaHigh) {
+		hw_fib->header.XferState |= cpu_to_le32(HighPriority);
+		qid = AdapHighCmdQueue;
+	} else {
+		hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
+		qid = AdapNormCmdQueue;
+	}
+	q = &dev->queues->queue[qid];
+
+	if(wait)
+		spin_lock_irqsave(&fibptr->event_lock, flags);
+	if(aac_queue_get( dev, &index, qid, hw_fib, 1, fibptr, &nointr)<0)
+		return -EWOULDBLOCK;
+	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
+	dprintk((KERN_DEBUG "Fib contents:.\n"));
+	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
+	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
+	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
+	dprintk((KERN_DEBUG "  hw_fib pa being sent=%lx\n",(ulong)fibptr->hw_fib_pa));
+	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
+	/*
+	 *	Fill in the Callback and CallbackContext if we are not
+	 *	going to wait.
+	 */
+	if (!wait) {
+		fibptr->callback = callback;
+		fibptr->callback_data = callback_data;
+	}
+	FIB_COUNTER_INCREMENT(aac_config.FibsSent);
+	list_add_tail(&fibptr->queue, &q->pendingq);
+	q->numpending++;
+
+	fibptr->done = 0;
+	fibptr->flags = 0;
+
+	if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0)
+		return -EWOULDBLOCK;
+	/*
+	 *	If the caller wanted us to wait for response wait now. 
+	 */
+    
+	if (wait) {
+		spin_unlock_irqrestore(&fibptr->event_lock, flags);
+		down(&fibptr->event_wait);
+		if(fibptr->done == 0)
+			BUG();
+			
+		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
+			return -ETIMEDOUT;
+		} else {
+			return 0;
+		}
+	}
+	/*
+	 *	If the user does not want a response than return success otherwise
+	 *	return pending
+	 */
+	if (reply)
+		return -EINPROGRESS;
+	else
+		return 0;
+}
+
+/** 
+ *	aac_consumer_get	-	get the top of the queue
+ *	@dev: Adapter
+ *	@q: Queue
+ *	@entry: Return entry
+ *
+ *	Will return a pointer to the entry on the top of the queue requested that
+ * 	we are a consumer of, and return the address of the queue entry. It does
+ *	not change the state of the queue. 
+ */
+
+int aac_consumer_get(struct aac_dev * dev, struct aac_queue * q, struct aac_entry **entry)
+{
+	u32 index;
+	int status;
+	if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) {
+		status = 0;
+	} else {
+		/*
+		 *	The consumer index must be wrapped if we have reached
+		 *	the end of the queue, else we just use the entry
+		 *	pointed to by the header index
+		 */
+		if (le32_to_cpu(*q->headers.consumer) >= q->entries) 
+			index = 0;		
+		else
+		        index = le32_to_cpu(*q->headers.consumer);
+		*entry = q->base + index;
+		status = 1;
+	}
+	return(status);
+}
+
+/**
+ *	aac_consumer_free	-	free consumer entry
+ *	@dev: Adapter
+ *	@q: Queue
+ *	@qid: Queue ident
+ *
+ *	Frees up the current top of the queue we are a consumer of. If the
+ *	queue was full notify the producer that the queue is no longer full.
+ */
+
+void aac_consumer_free(struct aac_dev * dev, struct aac_queue *q, u32 qid)
+{
+	int wasfull = 0;
+	u32 notify;
+
+	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
+		wasfull = 1;
+        
+	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
+		*q->headers.consumer = cpu_to_le32(1);
+	else
+		*q->headers.consumer = cpu_to_le32(le32_to_cpu(*q->headers.consumer)+1);
+        
+	if (wasfull) {
+		switch (qid) {
+
+		case HostNormCmdQueue:
+			notify = HostNormCmdNotFull;
+			break;
+		case HostHighCmdQueue:
+			notify = HostHighCmdNotFull;
+			break;
+		case HostNormRespQueue:
+			notify = HostNormRespNotFull;
+			break;
+		case HostHighRespQueue:
+			notify = HostHighRespNotFull;
+			break;
+		default:
+			BUG();
+			return;
+		}
+		aac_adapter_notify(dev, notify);
+	}
+}        
+
+/**
+ *	fib_adapter_complete	-	complete adapter issued fib
+ *	@fibptr: fib to complete
+ *	@size: size of fib
+ *
+ *	Will do all necessary work to complete a FIB that was sent from
+ *	the adapter.
+ */
+
+int fib_adapter_complete(struct fib * fibptr, unsigned short size)
+{
+	struct hw_fib * hw_fib = fibptr->hw_fib;
+	struct aac_dev * dev = fibptr->dev;
+	unsigned long nointr = 0;
+	if (hw_fib->header.XferState == 0)
+        	return 0;
+	/*
+	 *	If we plan to do anything check the structure type first.
+	 */ 
+	if ( hw_fib->header.StructType != FIB_MAGIC ) {
+        	return -EINVAL;
+	}
+	/*
+	 *	This block handles the case where the adapter had sent us a
+	 *	command and we have finished processing the command. We
+	 *	call completeFib when we are done processing the command 
+	 *	and want to send a response back to the adapter. This will 
+	 *	send the completed cdb to the adapter.
+	 */
+	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
+	        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
+	        if (hw_fib->header.XferState & cpu_to_le32(HighPriority)) {
+        		u32 index;
+       			if (size) 
+			{
+				size += sizeof(struct aac_fibhdr);
+				if (size > le16_to_cpu(hw_fib->header.SenderSize))
+					return -EMSGSIZE;
+				hw_fib->header.Size = cpu_to_le16(size);
+			}
+			if(aac_queue_get(dev, &index, AdapHighRespQueue, hw_fib, 1, NULL, &nointr) < 0) {
+				return -EWOULDBLOCK;
+			}
+			if (aac_insert_entry(dev, index, AdapHighRespQueue,  (nointr & (int)aac_config.irq_mod)) != 0) {
+			}
+		}
+		else if (hw_fib->header.XferState & NormalPriority) 
+		{
+			u32 index;
+
+			if (size) {
+				size += sizeof(struct aac_fibhdr);
+				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
+					return -EMSGSIZE;
+				hw_fib->header.Size = cpu_to_le16(size);
+			}
+			if (aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr) < 0) 
+				return -EWOULDBLOCK;
+			if (aac_insert_entry(dev, index, AdapNormRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) 
+			{
+			}
+		}
+	}
+	else 
+	{
+        	printk(KERN_WARNING "fib_adapter_complete: Unknown xferstate detected.\n");
+        	BUG();
+	}   
+	return 0;
+}
+
+/**
+ *	fib_complete	-	fib completion handler
+ *	@fib: FIB to complete
+ *
+ *	Will do all necessary work to complete a FIB.
+ */
+ 
+int fib_complete(struct fib * fibptr)
+{
+	struct hw_fib * hw_fib = fibptr->hw_fib;
+
+	/*
+	 *	Check for a fib which has already been completed
+	 */
+
+	if (hw_fib->header.XferState == 0)
+        	return 0;
+	/*
+	 *	If we plan to do anything check the structure type first.
+	 */ 
+
+	if (hw_fib->header.StructType != FIB_MAGIC)
+	        return -EINVAL;
+	/*
+	 *	This block completes a cdb which orginated on the host and we 
+	 *	just need to deallocate the cdb or reinit it. At this point the
+	 *	command is complete that we had sent to the adapter and this
+	 *	cdb could be reused.
+	 */
+	if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) &&
+		(hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)))
+	{
+		fib_dealloc(fibptr);
+	}
+	else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost))
+	{
+		/*
+		 *	This handles the case when the host has aborted the I/O
+		 *	to the adapter because the adapter is not responding
+		 */
+		fib_dealloc(fibptr);
+	} else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) {
+		fib_dealloc(fibptr);
+	} else {
+		BUG();
+	}   
+	return 0;
+}
+
+/**
+ *	aac_printf	-	handle printf from firmware
+ *	@dev: Adapter
+ *	@val: Message info
+ *
+ *	Print a message passed to us by the controller firmware on the
+ *	Adaptec board
+ */
+
+void aac_printf(struct aac_dev *dev, u32 val)
+{
+	int length = val & 0xffff;
+	int level = (val >> 16) & 0xffff;
+	char *cp = dev->printfbuf;
+	
+	/*
+	 *	The size of the printfbuf is set in port.c
+	 *	There is no variable or define for it
+	 */
+	if (length > 255)
+		length = 255;
+	if (cp[length] != 0)
+		cp[length] = 0;
+	if (level == LOG_AAC_HIGH_ERROR)
+		printk(KERN_WARNING "aacraid:%s", cp);
+	else
+		printk(KERN_INFO "aacraid:%s", cp);
+	memset(cp, 0,  256);
+}
+
+/**
+ *	aac_command_thread	-	command processing thread
+ *	@dev: Adapter to monitor
+ *
+ *	Waits on the commandready event in it's queue. When the event gets set
+ *	it will pull FIBs off it's queue. It will continue to pull FIBs off
+ *	until the queue is empty. When the queue is empty it will wait for
+ *	more FIBs.
+ */
+ 
+int aac_command_thread(struct aac_dev * dev)
+{
+	struct hw_fib *hw_fib, *hw_newfib;
+	struct fib *fib, *newfib;
+	struct aac_queue_block *queues = dev->queues;
+	struct aac_fib_context *fibctx;
+	unsigned long flags;
+	DECLARE_WAITQUEUE(wait, current);
+
+	/*
+	 *	We can only have one thread per adapter for AIF's.
+	 */
+	if (dev->aif_thread)
+		return -EINVAL;
+	/*
+	 *	Set up the name that will appear in 'ps'
+	 *	stored in  task_struct.comm[16].
+	 */
+	daemonize("aacraid");
+	allow_signal(SIGKILL);
+	/*
+	 *	Let the DPC know it has a place to send the AIF's to.
+	 */
+	dev->aif_thread = 1;
+	add_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	set_current_state(TASK_INTERRUPTIBLE);
+	while(1) 
+	{
+		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+			struct list_head *entry;
+			struct aac_aifcmd * aifcmd;
+
+			set_current_state(TASK_RUNNING);
+		
+			entry = queues->queue[HostNormCmdQueue].cmdq.next;
+			list_del(entry);
+			
+			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+			fib = list_entry(entry, struct fib, fiblink);
+			/*
+			 *	We will process the FIB here or pass it to a 
+			 *	worker thread that is TBD. We Really can't 
+			 *	do anything at this point since we don't have
+			 *	anything defined for this thread to do.
+			 */
+			hw_fib = fib->hw_fib;
+			memset(fib, 0, sizeof(struct fib));
+			fib->type = FSAFS_NTC_FIB_CONTEXT;
+			fib->size = sizeof( struct fib );
+			fib->hw_fib = hw_fib;
+			fib->data = hw_fib->data;
+			fib->dev = dev;
+			/*
+			 *	We only handle AifRequest fibs from the adapter.
+			 */
+			aifcmd = (struct aac_aifcmd *) hw_fib->data;
+			if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) {
+				/* Handle Driver Notify Events */
+				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+				fib_adapter_complete(fib, sizeof(u32));
+			} else {
+				struct list_head *entry;
+				/* The u32 here is important and intended. We are using
+				   32bit wrapping time to fit the adapter field */
+				   
+				u32 time_now, time_last;
+				unsigned long flagv;
+				
+				time_now = jiffies/HZ;
+
+				spin_lock_irqsave(&dev->fib_lock, flagv);
+				entry = dev->fib_list.next;
+				/*
+				 * For each Context that is on the 
+				 * fibctxList, make a copy of the
+				 * fib, and then set the event to wake up the
+				 * thread that is waiting for it.
+				 */
+				while (entry != &dev->fib_list) {
+					/*
+					 * Extract the fibctx
+					 */
+					fibctx = list_entry(entry, struct aac_fib_context, next);
+					/*
+					 * Check if the queue is getting
+					 * backlogged
+					 */
+					if (fibctx->count > 20)
+					{
+						/*
+						 * It's *not* jiffies folks,
+						 * but jiffies / HZ so do not
+						 * panic ...
+						 */
+						time_last = fibctx->jiffies;
+						/*
+						 * Has it been > 2 minutes 
+						 * since the last read off
+						 * the queue?
+						 */
+						if ((time_now - time_last) > 120) {
+							entry = entry->next;
+							aac_close_fib_context(dev, fibctx);
+							continue;
+						}
+					}
+					/*
+					 * Warning: no sleep allowed while
+					 * holding spinlock
+					 */
+					hw_newfib = kmalloc(sizeof(struct hw_fib), GFP_ATOMIC);
+					newfib = kmalloc(sizeof(struct fib), GFP_ATOMIC);
+					if (newfib && hw_newfib) {
+						/*
+						 * Make the copy of the FIB
+						 */
+						memcpy(hw_newfib, hw_fib, sizeof(struct hw_fib));
+						memcpy(newfib, fib, sizeof(struct fib));
+						newfib->hw_fib = hw_newfib;
+						/*
+						 * Put the FIB onto the
+						 * fibctx's fibs
+						 */
+						list_add_tail(&newfib->fiblink, &fibctx->fib_list);
+						fibctx->count++;
+						/* 
+						 * Set the event to wake up the
+						 * thread that will waiting.
+						 */
+						up(&fibctx->wait_sem);
+					} else {
+						printk(KERN_WARNING "aifd: didn't allocate NewFib.\n");
+						if(newfib)
+							kfree(newfib);
+						if(hw_newfib)
+							kfree(hw_newfib);
+					}
+					entry = entry->next;
+				}
+				/*
+				 *	Set the status of this FIB
+				 */
+				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+				fib_adapter_complete(fib, sizeof(u32));
+				spin_unlock_irqrestore(&dev->fib_lock, flagv);
+			}
+			spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
+			kfree(fib);
+		}
+		/*
+		 *	There are no more AIF's
+		 */
+		spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
+		schedule();
+
+		if(signal_pending(current))
+			break;
+		set_current_state(TASK_INTERRUPTIBLE);
+	}
+	remove_wait_queue(&queues->queue[HostNormCmdQueue].cmdready, &wait);
+	dev->aif_thread = 0;
+	complete_and_exit(&dev->aif_completion, 0);
+}
diff --git a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
new file mode 100644
index 0000000..8480b42
--- /dev/null
+++ b/drivers/scsi/aacraid/dpcsup.c
@@ -0,0 +1,215 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  dpcsup.c
+ *
+ * Abstract: All DPC processing routines for the cyclone board occur here.
+ *
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/completion.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+
+#include "aacraid.h"
+
+/**
+ *	aac_response_normal	-	Handle command replies
+ *	@q: Queue to read from
+ *
+ *	This DPC routine will be run when the adapter interrupts us to let us
+ *	know there is a response on our normal priority queue. We will pull off
+ *	all QE there are and wake up all the waiters before exiting. We will
+ *	take a spinlock out on the queue before operating on it.
+ */
+
+unsigned int aac_response_normal(struct aac_queue * q)
+{
+	struct aac_dev * dev = q->dev;
+	struct aac_entry *entry;
+	struct hw_fib * hwfib;
+	struct fib * fib;
+	int consumed = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->lock, flags);	
+	/*
+	 *	Keep pulling response QEs off the response queue and waking
+	 *	up the waiters until there are no more QEs. We then return
+	 *	back to the system. If no response was requesed we just
+	 *	deallocate the Fib here and continue.
+	 */
+	while(aac_consumer_get(dev, q, &entry))
+	{
+		int fast;
+		u32 index = le32_to_cpu(entry->addr);
+		fast = index & 0x01;
+		fib = &dev->fibs[index >> 1];
+		hwfib = fib->hw_fib;
+		
+		aac_consumer_free(dev, q, HostNormRespQueue);
+		/*
+		 *	Remove this fib from the Outstanding I/O queue.
+		 *	But only if it has not already been timed out.
+		 *
+		 *	If the fib has been timed out already, then just 
+		 *	continue. The caller has already been notified that
+		 *	the fib timed out.
+		 */
+		if (!(fib->flags & FIB_CONTEXT_FLAG_TIMED_OUT)) {
+			list_del(&fib->queue);
+			dev->queues->queue[AdapNormCmdQueue].numpending--;
+		} else {
+			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
+			printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
+			continue;
+		}
+		spin_unlock_irqrestore(q->lock, flags);
+
+		if (fast) {
+			/*
+			 *	Doctor the fib
+			 */
+			*(u32 *)hwfib->data = cpu_to_le32(ST_OK);
+			hwfib->header.XferState |= cpu_to_le32(AdapterProcessed);
+		}
+
+		FIB_COUNTER_INCREMENT(aac_config.FibRecved);
+
+		if (hwfib->header.Command == cpu_to_le16(NuFileSystem))
+		{
+			u32 *pstatus = (u32 *)hwfib->data;
+			if (*pstatus & cpu_to_le32(0xffff0000))
+				*pstatus = cpu_to_le32(ST_OK);
+		}
+		if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected | Async)) 
+		{
+	        	if (hwfib->header.XferState & cpu_to_le32(NoResponseExpected))
+				FIB_COUNTER_INCREMENT(aac_config.NoResponseRecved);
+			else 
+				FIB_COUNTER_INCREMENT(aac_config.AsyncRecved);
+			/*
+			 *	NOTE:  we cannot touch the fib after this
+			 *	    call, because it may have been deallocated.
+			 */
+			fib->callback(fib->callback_data, fib);
+		} else {
+			unsigned long flagv;
+			spin_lock_irqsave(&fib->event_lock, flagv);
+			fib->done = 1;
+			up(&fib->event_wait);
+			spin_unlock_irqrestore(&fib->event_lock, flagv);
+			FIB_COUNTER_INCREMENT(aac_config.NormalRecved);
+		}
+		consumed++;
+		spin_lock_irqsave(q->lock, flags);
+	}
+
+	if (consumed > aac_config.peak_fibs)
+		aac_config.peak_fibs = consumed;
+	if (consumed == 0) 
+		aac_config.zero_fibs++;
+
+	spin_unlock_irqrestore(q->lock, flags);
+	return 0;
+}
+
+
+/**
+ *	aac_command_normal	-	handle commands
+ *	@q: queue to process
+ *
+ *	This DPC routine will be queued when the adapter interrupts us to 
+ *	let us know there is a command on our normal priority queue. We will 
+ *	pull off all QE there are and wake up all the waiters before exiting.
+ *	We will take a spinlock out on the queue before operating on it.
+ */
+ 
+unsigned int aac_command_normal(struct aac_queue *q)
+{
+	struct aac_dev * dev = q->dev;
+	struct aac_entry *entry;
+	unsigned long flags;
+
+	spin_lock_irqsave(q->lock, flags);
+
+	/*
+	 *	Keep pulling response QEs off the response queue and waking
+	 *	up the waiters until there are no more QEs. We then return
+	 *	back to the system.
+	 */
+	while(aac_consumer_get(dev, q, &entry))
+	{
+		struct fib fibctx;
+		struct hw_fib * hw_fib;
+		u32 index;
+		struct fib *fib = &fibctx;
+		
+		index = le32_to_cpu(entry->addr) / sizeof(struct hw_fib);
+		hw_fib = &dev->aif_base_va[index];
+		
+		/*
+		 *	Allocate a FIB at all costs. For non queued stuff
+		 *	we can just use the stack so we are happy. We need
+		 *	a fib object in order to manage the linked lists
+		 */
+		if (dev->aif_thread)
+			if((fib = kmalloc(sizeof(struct fib), GFP_ATOMIC)) == NULL)
+				fib = &fibctx;
+		
+		memset(fib, 0, sizeof(struct fib));
+		INIT_LIST_HEAD(&fib->fiblink);
+		fib->type = FSAFS_NTC_FIB_CONTEXT;
+		fib->size = sizeof(struct fib);
+		fib->hw_fib = hw_fib;
+		fib->data = hw_fib->data;
+		fib->dev = dev;
+		
+				
+		if (dev->aif_thread && fib != &fibctx) {
+		        list_add_tail(&fib->fiblink, &q->cmdq);
+	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
+		        wake_up_interruptible(&q->cmdready);
+		} else {
+	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
+			spin_unlock_irqrestore(q->lock, flags);
+			/*
+			 *	Set the status of this FIB
+			 */
+			*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
+			fib_adapter_complete(fib, sizeof(u32));
+			spin_lock_irqsave(q->lock, flags);
+		}		
+	}
+	spin_unlock_irqrestore(q->lock, flags);
+	return 0;
+}
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
new file mode 100644
index 0000000..c9b8268
--- /dev/null
+++ b/drivers/scsi/aacraid/linit.c
@@ -0,0 +1,749 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *   linit.c
+ *
+ * Abstract: Linux Driver entry module for Adaptec RAID Array Controller
+ */
+
+#define AAC_DRIVER_VERSION		"1.1.2-lk2"
+#define AAC_DRIVER_BUILD_DATE		__DATE__
+#define AAC_DRIVERNAME			"aacraid"
+
+#include <linux/compat.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/syscalls.h>
+#include <linux/ioctl32.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_eh.h>
+
+#include "aacraid.h"
+
+
+MODULE_AUTHOR("Red Hat Inc and Adaptec");
+MODULE_DESCRIPTION("Dell PERC2, 2/Si, 3/Si, 3/Di, "
+		   "Adaptec Advanced Raid Products, "
+		   "and HP NetRAID-4M SCSI driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(AAC_DRIVER_VERSION);
+
+static LIST_HEAD(aac_devices);
+static int aac_cfg_major = -1;
+
+/*
+ * Because of the way Linux names scsi devices, the order in this table has
+ * become important.  Check for on-board Raid first, add-in cards second.
+ *
+ * Note: The last field is used to index into aac_drivers below.
+ */
+static struct pci_device_id aac_pci_tbl[] = {
+	{ 0x1028, 0x0001, 0x1028, 0x0001, 0, 0, 0 }, /* PERC 2/Si (Iguana/PERC2Si) */
+	{ 0x1028, 0x0002, 0x1028, 0x0002, 0, 0, 1 }, /* PERC 3/Di (Opal/PERC3Di) */
+	{ 0x1028, 0x0003, 0x1028, 0x0003, 0, 0, 2 }, /* PERC 3/Si (SlimFast/PERC3Si */
+	{ 0x1028, 0x0004, 0x1028, 0x00d0, 0, 0, 3 }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+	{ 0x1028, 0x0002, 0x1028, 0x00d1, 0, 0, 4 }, /* PERC 3/Di (Viper/PERC3DiV) */
+	{ 0x1028, 0x0002, 0x1028, 0x00d9, 0, 0, 5 }, /* PERC 3/Di (Lexus/PERC3DiL) */
+	{ 0x1028, 0x000a, 0x1028, 0x0106, 0, 0, 6 }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+	{ 0x1028, 0x000a, 0x1028, 0x011b, 0, 0, 7 }, /* PERC 3/Di (Dagger/PERC3DiD) */
+	{ 0x1028, 0x000a, 0x1028, 0x0121, 0, 0, 8 }, /* PERC 3/Di (Boxster/PERC3DiB) */
+	{ 0x9005, 0x0283, 0x9005, 0x0283, 0, 0, 9 }, /* catapult */
+	{ 0x9005, 0x0284, 0x9005, 0x0284, 0, 0, 10 }, /* tomcat */
+	{ 0x9005, 0x0285, 0x9005, 0x0286, 0, 0, 11 }, /* Adaptec 2120S (Crusader) */
+	{ 0x9005, 0x0285, 0x9005, 0x0285, 0, 0, 12 }, /* Adaptec 2200S (Vulcan) */
+	{ 0x9005, 0x0285, 0x9005, 0x0287, 0, 0, 13 }, /* Adaptec 2200S (Vulcan-2m) */
+	{ 0x9005, 0x0285, 0x17aa, 0x0286, 0, 0, 14 }, /* Legend S220 (Legend Crusader) */
+	{ 0x9005, 0x0285, 0x17aa, 0x0287, 0, 0, 15 }, /* Legend S230 (Legend Vulcan) */
+
+	{ 0x9005, 0x0285, 0x9005, 0x0288, 0, 0, 16 }, /* Adaptec 3230S (Harrier) */
+	{ 0x9005, 0x0285, 0x9005, 0x0289, 0, 0, 17 }, /* Adaptec 3240S (Tornado) */
+	{ 0x9005, 0x0285, 0x9005, 0x028a, 0, 0, 18 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
+	{ 0x9005, 0x0285, 0x9005, 0x028b, 0, 0, 19 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
+	{ 0x9005, 0x0286, 0x9005, 0x028c, 0, 0, 20 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x028d, 0, 0, 21 }, /* ASR-2130S (Lancer) */
+	{ 0x9005, 0x0286, 0x9005, 0x029b, 0, 0, 22 }, /* AAR-2820SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x029c, 0, 0, 23 }, /* AAR-2620SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x029d, 0, 0, 24 }, /* AAR-2420SA (Intruder) */
+	{ 0x9005, 0x0286, 0x9005, 0x0800, 0, 0, 25 }, /* Callisto Jupiter Platform */
+	{ 0x9005, 0x0285, 0x9005, 0x028e, 0, 0, 26 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
+	{ 0x9005, 0x0285, 0x9005, 0x028f, 0, 0, 27 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
+	{ 0x9005, 0x0285, 0x9005, 0x0290, 0, 0, 28 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+	{ 0x9005, 0x0285, 0x1028, 0x0291, 0, 0, 29 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ 0x9005, 0x0285, 0x9005, 0x0292, 0, 0, 30 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ 0x9005, 0x0285, 0x9005, 0x0293, 0, 0, 31 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ 0x9005, 0x0285, 0x9005, 0x0294, 0, 0, 32 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ 0x9005, 0x0285, 0x103C, 0x3227, 0, 0, 33 }, /* AAR-2610SA PCI SATA 6ch */
+	{ 0x9005, 0x0285, 0x9005, 0x0296, 0, 0, 34 }, /* ASR-2240S (SabreExpress) */
+	{ 0x9005, 0x0285, 0x9005, 0x0297, 0, 0, 35 }, /* ASR-4005SAS */
+	{ 0x9005, 0x0285, 0x1014, 0x02F2, 0, 0, 36 }, /* IBM 8i (AvonPark) */
+	{ 0x9005, 0x0285, 0x9005, 0x0298, 0, 0, 37 }, /* ASR-4000SAS (BlackBird) */
+	{ 0x9005, 0x0285, 0x9005, 0x0299, 0, 0, 38 }, /* ASR-4800SAS (Marauder-X) */
+	{ 0x9005, 0x0285, 0x9005, 0x029A, 0, 0, 39 }, /* ASR-4805SAS (Marauder-E) */
+
+	{ 0x9005, 0x0285, 0x1028, 0x0287, 0, 0, 40 }, /* Perc 320/DC*/
+	{ 0x1011, 0x0046, 0x9005, 0x0365, 0, 0, 41 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x0364, 0, 0, 42 }, /* Adaptec 5400S (Mustang)*/
+	{ 0x1011, 0x0046, 0x9005, 0x1364, 0, 0, 43 }, /* Dell PERC2/QC */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, 0, 0, 44 }, /* HP NetRAID-4M */
+
+	{ 0x9005, 0x0285, 0x1028, PCI_ANY_ID, 0, 0, 45 }, /* Dell Catchall */
+	{ 0x9005, 0x0285, 0x17aa, PCI_ANY_ID, 0, 0, 46 }, /* Legend Catchall */
+	{ 0x9005, 0x0285, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 47 }, /* Adaptec Catch All */
+	{ 0x9005, 0x0286, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 48 }, /* Adaptec Rocket Catch All */
+	{ 0,}
+};
+MODULE_DEVICE_TABLE(pci, aac_pci_tbl);
+
+/*
+ * dmb - For now we add the number of channels to this structure.  
+ * In the future we should add a fib that reports the number of channels
+ * for the card.  At that time we can remove the channels from here
+ */
+static struct aac_driver_ident aac_drivers[] = {
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 2/Si (Iguana/PERC2Si) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Opal/PERC3Di) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Si (SlimFast/PERC3Si */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Iguana FlipChip/PERC3DiF */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Viper/PERC3DiV) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Lexus/PERC3DiL) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Jaguar/PERC3DiJ) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Dagger/PERC3DiD) */
+	{ aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* PERC 3/Di (Boxster/PERC3DiB) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "catapult        ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* catapult */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "tomcat          ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* tomcat */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2120S (Crusader) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec 2200S (Vulcan-2m) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S220 (Legend Crusader) */
+	{ aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend S230 (Legend Vulcan) */
+
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020ZCR     ", 2 }, /* ASR-2020ZCR SCSI PCI-X ZCR (Skyhawk) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025ZCR     ", 2 }, /* ASR-2025ZCR SCSI SO-DIMM PCI-X ZCR (Terminator) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2230S PCI-X ", 2 }, /* ASR-2230S + ASR-2230SLP PCI-X (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "ASR-2130S PCI-X ", 1 }, /* ASR-2130S (Lancer) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2820SA      ", 1 }, /* AAR-2820SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2620SA      ", 1 }, /* AAR-2620SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "AAR-2420SA      ", 1 }, /* AAR-2420SA (Intruder) */
+	{ aac_rkt_init, "aacraid",  "ADAPTEC ", "Callisto        ", 2, AAC_QUIRK_MASTER }, /* Jupiter Platform */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020SA       ", 1 }, /* ASR-2020SA SATA PCI-X ZCR (Skyhawk) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2025SA       ", 1 }, /* ASR-2025SA SATA SO-DIMM PCI-X ZCR (Terminator) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 1 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II) */
+	{ aac_rx_init, "aacraid",  "DELL    ", "CERC SR2        ", 1 }, /* CERC SATA RAID 2 PCI SATA 6ch (DellCorsair) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2810SA SATA ", 1 }, /* AAR-2810SA PCI SATA 8ch (Corsair-8) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-21610SA SATA", 1 }, /* AAR-21610SA PCI SATA 16ch (Corsair-16) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2026ZCR     ", 1 }, /* ESD SO-DIMM PCI-X SATA ZCR (Prowler) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2610SA      ", 1 }, /* SATA 6Ch (Bearcat) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2240S       ", 1 }, /* ASR-2240S (SabreExpress) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4005SAS     ", 1 }, /* ASR-4005SAS */
+	{ aac_rx_init, "aacraid",  "IBM     ", "ServeRAID 8i    ", 1 }, /* IBM 8i (AvonPark) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4000SAS     ", 1 }, /* ASR-4000SAS (BlackBird & AvonPark) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4800SAS     ", 1 }, /* ASR-4800SAS (Marauder-X) */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-4805SAS     ", 1 }, /* ASR-4805SAS (Marauder-E) */
+
+	{ aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Perc 320/DC*/
+	{ aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
+	{ aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4, AAC_QUIRK_34SG }, /* Adaptec 5400S (Mustang)*/
+	{ aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell PERC2/QC */
+	{ aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4, AAC_QUIRK_34SG }, /* HP NetRAID-4M */
+
+	{ aac_rx_init, "aacraid",  "DELL    ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Dell Catchall */
+	{ aac_rx_init, "aacraid",  "Legend  ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Legend Catchall */
+	{ aac_rx_init, "aacraid",  "ADAPTEC ", "RAID            ", 2, AAC_QUIRK_31BIT | AAC_QUIRK_34SG }, /* Adaptec Catch All */
+	{ aac_rkt_init, "aacraid", "ADAPTEC ", "RAID            ", 2 } /* Adaptec Rocket Catch All */
+};
+
+/**
+ *	aac_queuecommand	-	queue a SCSI command
+ *	@cmd:		SCSI command to queue
+ *	@done:		Function to call on command completion
+ *
+ *	Queues a command for execution by the associated Host Adapter.
+ *
+ *	TODO: unify with aac_scsi_cmd().
+ */ 
+
+static int aac_queuecommand(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	cmd->scsi_done = done;
+	return (aac_scsi_cmd(cmd) ? FAILED : 0);
+} 
+
+/**
+ *	aac_info		-	Returns the host adapter name
+ *	@shost:		Scsi host to report on
+ *
+ *	Returns a static string describing the device in question
+ */
+
+const char *aac_info(struct Scsi_Host *shost)
+{
+	struct aac_dev *dev = (struct aac_dev *)shost->hostdata;
+	return aac_drivers[dev->cardtype].name;
+}
+
+/**
+ *	aac_get_driver_ident
+ * 	@devtype: index into lookup table
+ *
+ * 	Returns a pointer to the entry in the driver lookup table.
+ */
+
+struct aac_driver_ident* aac_get_driver_ident(int devtype)
+{
+	return &aac_drivers[devtype];
+}
+
+/**
+ *	aac_biosparm	-	return BIOS parameters for disk
+ *	@sdev: The scsi device corresponding to the disk
+ *	@bdev: the block device corresponding to the disk
+ *	@capacity: the sector capacity of the disk
+ *	@geom: geometry block to fill in
+ *
+ *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
+ *	The default disk geometry is 64 heads, 32 sectors, and the appropriate 
+ *	number of cylinders so as not to exceed drive capacity.  In order for 
+ *	disks equal to or larger than 1 GB to be addressable by the BIOS
+ *	without exceeding the BIOS limitation of 1024 cylinders, Extended 
+ *	Translation should be enabled.   With Extended Translation enabled, 
+ *	drives between 1 GB inclusive and 2 GB exclusive are given a disk 
+ *	geometry of 128 heads and 32 sectors, and drives above 2 GB inclusive 
+ *	are given a disk geometry of 255 heads and 63 sectors.  However, if 
+ *	the BIOS detects that the Extended Translation setting does not match 
+ *	the geometry in the partition table, then the translation inferred 
+ *	from the partition table will be used by the BIOS, and a warning may 
+ *	be displayed.
+ */
+ 
+static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
+			sector_t capacity, int *geom)
+{
+	struct diskparm *param = (struct diskparm *)geom;
+	unsigned char *buf;
+
+	dprintk((KERN_DEBUG "aac_biosparm.\n"));
+
+	/*
+	 *	Assuming extended translation is enabled - #REVISIT#
+	 */
+	if (capacity >= 2 * 1024 * 1024) { /* 1 GB in 512 byte sectors */
+		if(capacity >= 4 * 1024 * 1024) { /* 2 GB in 512 byte sectors */
+			param->heads = 255;
+			param->sectors = 63;
+		} else {
+			param->heads = 128;
+			param->sectors = 32;
+		}
+	} else {
+		param->heads = 64;
+		param->sectors = 32;
+	}
+
+	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
+
+	/* 
+	 *	Read the first 1024 bytes from the disk device, if the boot
+	 *	sector partition table is valid, search for a partition table
+	 *	entry whose end_head matches one of the standard geometry 
+	 *	translations ( 64/32, 128/32, 255/63 ).
+	 */
+	buf = scsi_bios_ptable(bdev);
+	if(*(unsigned short *)(buf + 0x40) == cpu_to_le16(0xaa55)) {
+		struct partition *first = (struct partition * )buf;
+		struct partition *entry = first;
+		int saved_cylinders = param->cylinders;
+		int num;
+		unsigned char end_head, end_sec;
+
+		for(num = 0; num < 4; num++) {
+			end_head = entry->end_head;
+			end_sec = entry->end_sector & 0x3f;
+
+			if(end_head == 63) {
+				param->heads = 64;
+				param->sectors = 32;
+				break;
+			} else if(end_head == 127) {
+				param->heads = 128;
+				param->sectors = 32;
+				break;
+			} else if(end_head == 254) {
+				param->heads = 255;
+				param->sectors = 63;
+				break;
+			}
+			entry++;
+		}
+
+		if (num == 4) {
+			end_head = first->end_head;
+			end_sec = first->end_sector & 0x3f;
+		}
+
+		param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
+		if (num < 4 && end_sec == param->sectors) {
+			if (param->cylinders != saved_cylinders)
+				dprintk((KERN_DEBUG "Adopting geometry: heads=%d, sectors=%d from partition table %d.\n",
+					param->heads, param->sectors, num));
+		} else if (end_head > 0 || end_sec > 0) {
+			dprintk((KERN_DEBUG "Strange geometry: heads=%d, sectors=%d in partition table %d.\n",
+				end_head + 1, end_sec, num));
+			dprintk((KERN_DEBUG "Using geometry: heads=%d, sectors=%d.\n",
+					param->heads, param->sectors));
+		}
+	}
+	kfree(buf);
+	return 0;
+}
+
+/**
+ *	aac_slave_configure		-	compute queue depths
+ *	@sdev:	SCSI device we are considering
+ *
+ *	Selects queue depths for each target device based on the host adapter's
+ *	total capacity and the queue depth supported by the target device.
+ *	A queue depth of one automatically disables tagged queueing.
+ */
+
+static int aac_slave_configure(struct scsi_device *sdev)
+{
+	if (sdev->tagged_supported)
+		scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, 128);
+	else
+		scsi_adjust_queue_depth(sdev, 0, 1);
+	return 0;
+}
+
+static int aac_ioctl(struct scsi_device *sdev, int cmd, void __user * arg)
+{
+	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+	return aac_do_ioctl(dev, cmd, arg);
+}
+
+/*
+ * XXX: does aac really need no error handling??
+ */
+static int aac_eh_abort(struct scsi_cmnd *cmd)
+{
+	return FAILED;
+}
+
+/*
+ *	aac_eh_reset	- Reset command handling
+ *	@scsi_cmd:	SCSI command block causing the reset
+ *
+ */
+static int aac_eh_reset(struct scsi_cmnd* cmd)
+{
+	struct scsi_device * dev = cmd->device;
+	struct Scsi_Host * host = dev->host;
+	struct scsi_cmnd * command;
+	int count;
+	struct aac_dev * aac;
+	unsigned long flags;
+
+	printk(KERN_ERR "%s: Host adapter reset request. SCSI hang ?\n", 
+					AAC_DRIVERNAME);
+
+
+	aac = (struct aac_dev *)host->hostdata;
+	if (aac_adapter_check_health(aac)) {
+		printk(KERN_ERR "%s: Host adapter appears dead\n", 
+				AAC_DRIVERNAME);
+		return -ENODEV;
+	}
+	/*
+	 * Wait for all commands to complete to this specific
+	 * target (block maximum 60 seconds).
+	 */
+	for (count = 60; count; --count) {
+		int active = 0;
+		__shost_for_each_device(dev, host) {
+			spin_lock_irqsave(&dev->list_lock, flags);
+			list_for_each_entry(command, &dev->cmd_list, list) {
+				if (command->serial_number) {
+					active++;
+					break;
+				}
+			}
+			spin_unlock_irqrestore(&dev->list_lock, flags);
+			if (active)
+				break;
+
+		}
+		/*
+		 * We can exit If all the commands are complete
+		 */
+		if (active == 0)
+			return SUCCESS;
+		spin_unlock_irq(host->host_lock);
+		ssleep(1);
+		spin_lock_irq(host->host_lock);
+	}
+	printk(KERN_ERR "%s: SCSI bus appears hung\n", AAC_DRIVERNAME);
+	return -ETIMEDOUT;
+}
+
+/**
+ *	aac_cfg_open		-	open a configuration file
+ *	@inode: inode being opened
+ *	@file: file handle attached
+ *
+ *	Called when the configuration device is opened. Does the needed
+ *	set up on the handle and then returns
+ *
+ *	Bugs: This needs extending to check a given adapter is present
+ *	so we can support hot plugging, and to ref count adapters.
+ */
+
+static int aac_cfg_open(struct inode *inode, struct file *file)
+{
+	struct aac_dev *aac;
+	unsigned minor = iminor(inode);
+	int err = -ENODEV;
+
+	list_for_each_entry(aac, &aac_devices, entry) {
+		if (aac->id == minor) {
+			file->private_data = aac;
+			err = 0;
+			break;
+		}
+	}
+
+	return 0;
+}
+
+/**
+ *	aac_cfg_ioctl		-	AAC configuration request
+ *	@inode: inode of device
+ *	@file: file handle
+ *	@cmd: ioctl command code
+ *	@arg: argument
+ *
+ *	Handles a configuration ioctl. Currently this involves wrapping it
+ *	up and feeding it into the nasty windowsalike glue layer.
+ *
+ *	Bugs: Needs locking against parallel ioctls lower down
+ *	Bugs: Needs to handle hot plugging
+ */
+ 
+static int aac_cfg_ioctl(struct inode *inode,  struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	return aac_do_ioctl(file->private_data, cmd, (void __user *)arg);
+}
+
+#ifdef CONFIG_COMPAT
+static long aac_compat_do_ioctl(struct aac_dev *dev, unsigned cmd, unsigned long arg)
+{
+	long ret;
+	lock_kernel();
+	switch (cmd) { 
+	case FSACTL_MINIPORT_REV_CHECK:
+	case FSACTL_SENDFIB:
+	case FSACTL_OPEN_GET_ADAPTER_FIB:
+	case FSACTL_CLOSE_GET_ADAPTER_FIB:
+	case FSACTL_SEND_RAW_SRB:
+	case FSACTL_GET_PCI_INFO:
+	case FSACTL_QUERY_DISK:
+	case FSACTL_DELETE_DISK:
+	case FSACTL_FORCE_DELETE_DISK:
+	case FSACTL_GET_CONTAINERS: 
+		ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+
+	case FSACTL_GET_NEXT_ADAPTER_FIB: {
+		struct fib_ioctl __user *f;
+		
+		f = compat_alloc_user_space(sizeof(*f));
+		ret = 0;
+		if (clear_user(f, sizeof(*f) != sizeof(*f)))
+			ret = -EFAULT;
+		if (copy_in_user(f, (void __user *)arg, sizeof(struct fib_ioctl) - sizeof(u32)))
+			ret = -EFAULT;
+		if (!ret)
+			ret = aac_do_ioctl(dev, cmd, (void __user *)arg);
+		break;
+	}
+
+	default:
+		ret = -ENOIOCTLCMD; 
+		break;
+	} 
+	unlock_kernel();
+	return ret;
+}
+
+static int aac_compat_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata;
+	return aac_compat_do_ioctl(dev, cmd, (unsigned long)arg);
+}
+
+static long aac_compat_cfg_ioctl(struct file *file, unsigned cmd, unsigned long arg)
+{
+	return aac_compat_do_ioctl((struct aac_dev *)file->private_data, cmd, arg);
+}
+#endif
+
+static struct file_operations aac_cfg_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= aac_cfg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl   = aac_compat_cfg_ioctl,
+#endif
+	.open		= aac_cfg_open,
+};
+
+static struct scsi_host_template aac_driver_template = {
+	.module				= THIS_MODULE,
+	.name           		= "AAC",
+	.proc_name			= "aacraid",
+	.info           		= aac_info,
+	.ioctl          		= aac_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl			= aac_compat_ioctl,
+#endif
+	.queuecommand   		= aac_queuecommand,
+	.bios_param     		= aac_biosparm,	
+	.slave_configure		= aac_slave_configure,
+	.eh_abort_handler		= aac_eh_abort,
+	.eh_host_reset_handler		= aac_eh_reset,
+	.can_queue      		= AAC_NUM_IO_FIB,	
+	.this_id        		= 16,
+	.sg_tablesize   		= 16,
+	.max_sectors    		= 128,
+#if (AAC_NUM_IO_FIB > 256)
+	.cmd_per_lun			= 256,
+#else		
+	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
+#endif	
+	.use_clustering			= ENABLE_CLUSTERING,
+};
+
+
+static int __devinit aac_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	unsigned index = id->driver_data;
+	struct Scsi_Host *shost;
+	struct aac_dev *aac;
+	struct list_head *insert = &aac_devices;
+	int error = -ENODEV;
+	int unique_id = 0;
+
+	list_for_each_entry(aac, &aac_devices, entry) {
+		if (aac->id > unique_id)
+			break;
+		insert = &aac->entry;
+		unique_id++;
+	}
+
+	if (pci_enable_device(pdev))
+		goto out;
+
+	if (pci_set_dma_mask(pdev, 0xFFFFFFFFULL) || 
+			pci_set_consistent_dma_mask(pdev, 0xFFFFFFFFULL))
+		goto out;
+	/*
+	 * If the quirk31 bit is set, the adapter needs adapter
+	 * to driver communication memory to be allocated below 2gig
+	 */
+	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT) 
+		if (pci_set_dma_mask(pdev, 0x7FFFFFFFULL) ||
+				pci_set_consistent_dma_mask(pdev, 0x7FFFFFFFULL))
+			goto out;
+	
+	pci_set_master(pdev);
+
+	shost = scsi_host_alloc(&aac_driver_template, sizeof(struct aac_dev));
+	if (!shost)
+		goto out_disable_pdev;
+
+	shost->irq = pdev->irq;
+	shost->base = pci_resource_start(pdev, 0);
+	shost->unique_id = unique_id;
+
+	aac = (struct aac_dev *)shost->hostdata;
+	aac->scsi_host_ptr = shost;	
+	aac->pdev = pdev;
+	aac->name = aac_driver_template.name;
+	aac->id = shost->unique_id;
+	aac->cardtype =  index;
+	INIT_LIST_HEAD(&aac->entry);
+
+	aac->fibs = kmalloc(sizeof(struct fib) * AAC_NUM_FIB, GFP_KERNEL);
+	if (!aac->fibs)
+		goto out_free_host;
+	spin_lock_init(&aac->fib_lock);
+
+	if ((*aac_drivers[index].init)(aac))
+		goto out_free_fibs;
+
+	/*
+	 * If we had set a smaller DMA mask earlier, set it to 4gig
+	 * now since the adapter can dma data to at least a 4gig
+	 * address space.
+	 */
+	if (aac_drivers[index].quirks & AAC_QUIRK_31BIT)
+		if (pci_set_dma_mask(pdev, 0xFFFFFFFFULL))
+			goto out_free_fibs;
+
+	aac_get_adapter_info(aac);
+
+	/*
+	 * max channel will be the physical channels plus 1 virtual channel
+	 * all containers are on the virtual channel 0
+	 * physical channels are address by their actual physical number+1
+	 */
+	if (aac->nondasd_support == 1)
+		shost->max_channel = aac_drivers[index].channels+1;
+	else
+		shost->max_channel = 1;
+
+	aac_get_config_status(aac);
+	aac_get_containers(aac);
+	list_add(&aac->entry, insert);
+
+	shost->max_id = aac->maximum_num_containers;
+	if (shost->max_id < MAXIMUM_NUM_CONTAINERS)
+		shost->max_id = MAXIMUM_NUM_CONTAINERS;
+	else
+		shost->this_id = shost->max_id;
+
+	/*
+	 * dmb - we may need to move the setting of these parms somewhere else once
+	 * we get a fib that can report the actual numbers
+	 */
+	shost->max_lun = AAC_MAX_LUN;
+
+	pci_set_drvdata(pdev, shost);
+
+	error = scsi_add_host(shost, &pdev->dev);
+	if (error)
+		goto out_deinit;
+	scsi_scan_host(shost);
+
+	return 0;
+
+out_deinit:
+	kill_proc(aac->thread_pid, SIGKILL, 0);
+	wait_for_completion(&aac->aif_completion);
+
+	aac_send_shutdown(aac);
+	fib_map_free(aac);
+	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr, aac->comm_phys);
+	kfree(aac->queues);
+	free_irq(pdev->irq, aac);
+	iounmap(aac->regs.sa);
+ out_free_fibs:
+	kfree(aac->fibs);
+	kfree(aac->fsa_dev);
+ out_free_host:
+	scsi_host_put(shost);
+ out_disable_pdev:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+static void __devexit aac_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+	struct aac_dev *aac = (struct aac_dev *)shost->hostdata;
+
+	scsi_remove_host(shost);
+
+	kill_proc(aac->thread_pid, SIGKILL, 0);
+	wait_for_completion(&aac->aif_completion);
+
+	aac_send_shutdown(aac);
+	fib_map_free(aac);
+	pci_free_consistent(aac->pdev, aac->comm_size, aac->comm_addr,
+			aac->comm_phys);
+	kfree(aac->queues);
+
+	free_irq(pdev->irq, aac);
+	iounmap(aac->regs.sa);
+	
+	kfree(aac->fibs);
+	
+	list_del(&aac->entry);
+	scsi_host_put(shost);
+	pci_disable_device(pdev);
+}
+
+static struct pci_driver aac_pci_driver = {
+	.name		= AAC_DRIVERNAME,
+	.id_table	= aac_pci_tbl,
+	.probe		= aac_probe_one,
+	.remove		= __devexit_p(aac_remove_one),
+};
+
+static int __init aac_init(void)
+{
+	int error;
+	
+	printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n",
+			AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE);
+
+	error = pci_module_init(&aac_pci_driver);
+	if (error)
+		return error;
+
+	aac_cfg_major = register_chrdev( 0, "aac", &aac_cfg_fops);
+	if (aac_cfg_major < 0) {
+		printk(KERN_WARNING
+		       "aacraid: unable to register \"aac\" device.\n");
+	}
+	return 0;
+}
+
+static void __exit aac_exit(void)
+{
+	unregister_chrdev(aac_cfg_major, "aac");
+	pci_unregister_driver(&aac_pci_driver);
+}
+
+module_init(aac_init);
+module_exit(aac_exit);
diff --git a/drivers/scsi/aacraid/rkt.c b/drivers/scsi/aacraid/rkt.c
new file mode 100644
index 0000000..1b8ed47
--- /dev/null
+++ b/drivers/scsi/aacraid/rkt.c
@@ -0,0 +1,440 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rkt.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_rkt_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned long bellbits;
+	u8 intstat, mask;
+	intstat = rkt_readb(dev, MUnit.OISR);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have 
+	 *	been enabled.
+	 */
+	mask = ~(dev->OIMR);
+	/* Check to see if this is our interrupt.  If it isn't just return */
+	if (intstat & mask) 
+	{
+		bellbits = rkt_readl(dev, OutboundDoorbellReg);
+		if (bellbits & DoorBellPrintfReady) {
+			aac_printf(dev, rkt_readl(dev, IndexRegs.Mailbox[5]));
+			rkt_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+			rkt_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdReady) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+		}
+		else if (bellbits & DoorBellAdapterNormRespReady) {
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			rkt_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+		}
+		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+			rkt_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/**
+ *	rkt_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous command to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int rkt_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
+{
+	unsigned long start;
+	int ok;
+	/*
+	 *	Write the command into Mailbox 0
+	 */
+	rkt_writel(dev, InboundMailbox0, command);
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	rkt_writel(dev, InboundMailbox1, p1);
+	rkt_writel(dev, InboundMailbox2, 0);
+	rkt_writel(dev, InboundMailbox3, 0);
+	rkt_writel(dev, InboundMailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Disable doorbell interrupts
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xff);
+	/*
+	 *	Force the completion of the mask register write before issuing
+	 *	the interrupt.
+	 */
+	rkt_readb (dev, MUnit.OIMR);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	rkt_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	/*
+	 *	Wait up to 30 seconds
+	 */
+	while (time_before(jiffies, start+30*HZ)) 
+	{
+		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+		/*
+		 *	Mon960 will set doorbell0 bit when it has completed the command.
+		 */
+		if (rkt_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+			/*
+			 *	Clear the doorbell.
+			 */
+			rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+			ok = 1;
+			break;
+		}
+		/*
+		 *	Yield the processor in case we are slow 
+		 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (ok != 1) {
+		/*
+		 *	Restore interrupt mask even though we timed out
+		 */
+		rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+		return -ETIMEDOUT;
+	}
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	if (status)
+		*status = rkt_readl(dev, IndexRegs.Mailbox[0]);
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	rkt_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Restore interrupt mask
+	 */
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+	return 0;
+
+}
+
+/**
+ *	aac_rkt_interrupt_adapter	-	interrupt adapter
+ *	@dev: Adapter
+ *
+ *	Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_rkt_interrupt_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	rkt_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_rkt_notify_adapter		-	send an event to the adapter
+ *	@dev: Adapter
+ *	@event: Event to send
+ *
+ *	Notify the i960 that something it probably cares about has
+ *	happened.
+ */
+
+static void aac_rkt_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+		break;
+	case HostShutdown:
+//		rkt_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
+		break;
+	case FastIo:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		rkt_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ *	aac_rkt_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_rkt_start_adapter(struct aac_dev *dev)
+{
+	u32 status;
+	struct aac_init *init;
+
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+	/*
+	 *	Tell the adapter we are back and up and running so it will scan
+	 *	its command queues and enable our interrupts
+	 */
+	dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	rkt_writeb(dev, MUnit.OIMR, 0xff);
+	rkt_writel(dev, MUnit.ODR, 0xffffffff);
+//	rkt_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	rkt_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
+	// We can only use a 32 bit address here
+	rkt_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
+}
+
+/**
+ *	aac_rkt_check_health
+ *	@dev: device to check if healthy
+ *
+ *	Will attempt to determine if the specified adapter is alive and
+ *	capable of handling requests, returning 0 if alive.
+ */
+static int aac_rkt_check_health(struct aac_dev *dev)
+{
+	u32 status = rkt_readl(dev, MUnit.OMRx[0]);
+
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (status & SELF_TEST_FAILED)
+		return -1;
+	/*
+	 *	Check to see if the board panic'd.
+	 */
+	if (status & KERNEL_PANIC) {
+		char * buffer;
+		struct POSTSTATUS {
+			u32 Post_Command;
+			u32 Post_Address;
+		} * post;
+		dma_addr_t paddr, baddr;
+		int ret;
+
+		if ((status & 0xFF000000L) == 0xBC000000L)
+			return (status >> 16) & 0xFF;
+		buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
+		ret = -2;
+		if (buffer == NULL)
+			return ret;
+		post = pci_alloc_consistent(dev->pdev,
+		  sizeof(struct POSTSTATUS), &paddr);
+		if (post == NULL) {
+			pci_free_consistent(dev->pdev, 512, buffer, baddr);
+			return ret;
+		}
+                memset(buffer, 0, 512);
+		post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
+                post->Post_Address = cpu_to_le32(baddr);
+                rkt_writel(dev, MUnit.IMRx[0], paddr);
+                rkt_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, &status);
+		pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
+		  post, paddr);
+                if ((buffer[0] == '0') && (buffer[1] == 'x')) {
+                        ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
+                        ret <<= 4;
+                        ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
+                }
+		pci_free_consistent(dev->pdev, 512, buffer, baddr);
+                return ret;
+        }
+	/*
+	 *	Wait for the adapter to be up and running.
+	 */
+	if (!(status & KERNEL_UP_AND_RUNNING))
+		return -3;
+	/*
+	 *	Everything is OK
+	 */
+	return 0;
+}
+
+/**
+ *	aac_rkt_init	-	initialize an i960 based AAC card
+ *	@dev: device to configure
+ *
+ *	Allocate and set up resources for the i960 based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_rkt_init(struct aac_dev *dev)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char * name;
+
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	if((dev->regs.rkt = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map i960.\n" );
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (rkt_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the monitor panic'd while booting.
+	 */
+	if (rkt_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
+		printk(KERN_ERR "%s%d: adapter kernel panic'd.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	while (!(rkt_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING))
+	{
+		if(time_after(jiffies, start+180*HZ))
+		{
+			status = rkt_readl(dev, MUnit.OMRx[0]);
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					dev->name, instance, status);
+			goto error_iounmap;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (request_irq(dev->scsi_host_ptr->irq, aac_rkt_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
+	{
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_rkt_interrupt_adapter;
+	dev->a_ops.adapter_notify = aac_rkt_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = rkt_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_rkt_check_health;
+
+	if (aac_init_adapter(dev) == NULL)
+		goto error_irq;
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if(dev->thread_pid < 0)
+	{
+		printk(KERN_ERR "aacraid: Unable to create rkt thread.\n");
+		goto error_kfree;
+	}	
+	/*
+	 *	Tell the adapter that all is configured, and it can start
+	 *	accepting requests
+	 */
+	aac_rkt_start_adapter(dev);
+	return 0;
+
+error_kfree:
+	kfree(dev->queues);
+
+error_irq:
+	free_irq(dev->scsi_host_ptr->irq, (void *)dev);
+
+error_iounmap:
+	iounmap(dev->regs.rkt);
+
+	return -1;
+}
diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c
new file mode 100644
index 0000000..630b99e
--- /dev/null
+++ b/drivers/scsi/aacraid/rx.c
@@ -0,0 +1,441 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  rx.c
+ *
+ * Abstract: Hardware miniport for Drawbridge specific hardware functions.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_rx_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned long bellbits;
+	u8 intstat, mask;
+	intstat = rx_readb(dev, MUnit.OISR);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have 
+	 *	been enabled.
+	 */
+	mask = ~(dev->OIMR);
+	/* Check to see if this is our interrupt.  If it isn't just return */
+	if (intstat & mask) 
+	{
+		bellbits = rx_readl(dev, OutboundDoorbellReg);
+		if (bellbits & DoorBellPrintfReady) {
+			aac_printf(dev, le32_to_cpu(rx_readl (dev, IndexRegs.Mailbox[5])));
+			rx_writel(dev, MUnit.ODR,DoorBellPrintfReady);
+			rx_writel(dev, InboundDoorbellReg,DoorBellPrintfDone);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdReady) {
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdReady);
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+		}
+		else if (bellbits & DoorBellAdapterNormRespReady) {
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			rx_writel(dev, MUnit.ODR,DoorBellAdapterNormRespReady);
+		}
+		else if (bellbits & DoorBellAdapterNormCmdNotFull) {
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+		}
+		else if (bellbits & DoorBellAdapterNormRespNotFull) {
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormCmdNotFull);
+			rx_writel(dev, MUnit.ODR, DoorBellAdapterNormRespNotFull);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/**
+ *	rx_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous command to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int rx_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *status)
+{
+	unsigned long start;
+	int ok;
+	/*
+	 *	Write the command into Mailbox 0
+	 */
+	rx_writel(dev, InboundMailbox0, command);
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	rx_writel(dev, InboundMailbox1, p1);
+	rx_writel(dev, InboundMailbox2, 0);
+	rx_writel(dev, InboundMailbox3, 0);
+	rx_writel(dev, InboundMailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Disable doorbell interrupts
+	 */
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR |= 0x04);
+	/*
+	 *	Force the completion of the mask register write before issuing
+	 *	the interrupt.
+	 */
+	rx_readb (dev, MUnit.OIMR);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	rx_writel(dev, InboundDoorbellReg, INBOUNDDOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	/*
+	 *	Wait up to 30 seconds
+	 */
+	while (time_before(jiffies, start+30*HZ)) 
+	{
+		udelay(5);	/* Delay 5 microseconds to let Mon960 get info. */
+		/*
+		 *	Mon960 will set doorbell0 bit when it has completed the command.
+		 */
+		if (rx_readl(dev, OutboundDoorbellReg) & OUTBOUNDDOORBELL_0) {
+			/*
+			 *	Clear the doorbell.
+			 */
+			rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+			ok = 1;
+			break;
+		}
+		/*
+		 *	Yield the processor in case we are slow 
+		 */
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (ok != 1) {
+		/*
+		 *	Restore interrupt mask even though we timed out
+		 */
+		rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+		return -ETIMEDOUT;
+	}
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	if (status)
+		*status = rx_readl(dev, IndexRegs.Mailbox[0]);
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	rx_writel(dev, OutboundDoorbellReg, OUTBOUNDDOORBELL_0);
+	/*
+	 *	Restore interrupt mask
+	 */
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR &= 0xfb);
+	return 0;
+
+}
+
+/**
+ *	aac_rx_interrupt_adapter	-	interrupt adapter
+ *	@dev: Adapter
+ *
+ *	Send an interrupt to the i960 and breakpoint it.
+ */
+
+static void aac_rx_interrupt_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	rx_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_rx_notify_adapter		-	send an event to the adapter
+ *	@dev: Adapter
+ *	@event: Event to send
+ *
+ *	Notify the i960 that something it probably cares about has
+ *	happened.
+ */
+
+static void aac_rx_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_3);
+		break;
+	case HostShutdown:
+//		rx_sync_cmd(dev, HOST_CRASHING, 0, 0, 0, 0, &ret);
+		break;
+	case FastIo:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		rx_writel(dev, MUnit.IDR,INBOUNDDOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+/**
+ *	aac_rx_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an i960 based AAC adapter
+ */
+
+static void aac_rx_start_adapter(struct aac_dev *dev)
+{
+	u32 status;
+	struct aac_init *init;
+
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+	/*
+	 *	Tell the adapter we are back and up and running so it will scan
+	 *	its command queues and enable our interrupts
+	 */
+	dev->irq_mask = (DoorBellPrintfReady | OUTBOUNDDOORBELL_1 | OUTBOUNDDOORBELL_2 | OUTBOUNDDOORBELL_3 | OUTBOUNDDOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that we
+	 *	can handle.
+	 */
+	rx_writeb(dev, MUnit.OIMR, 0xff);
+	rx_writel(dev, MUnit.ODR, 0xffffffff);
+//	rx_writeb(dev, MUnit.OIMR, ~(u8)OUTBOUND_DOORBELL_INTERRUPT_MASK);
+	rx_writeb(dev, MUnit.OIMR, dev->OIMR = 0xfb);
+
+	// We can only use a 32 bit address here
+	rx_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &status);
+}
+
+/**
+ *	aac_rx_check_health
+ *	@dev: device to check if healthy
+ *
+ *	Will attempt to determine if the specified adapter is alive and
+ *	capable of handling requests, returning 0 if alive.
+ */
+static int aac_rx_check_health(struct aac_dev *dev)
+{
+	u32 status = rx_readl(dev, MUnit.OMRx[0]);
+
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (status & SELF_TEST_FAILED)
+		return -1;
+	/*
+	 *	Check to see if the board panic'd.
+	 */
+	if (status & KERNEL_PANIC) {
+		char * buffer;
+		struct POSTSTATUS {
+			u32 Post_Command;
+			u32 Post_Address;
+		} * post;
+		dma_addr_t paddr, baddr;
+		int ret;
+
+		if ((status & 0xFF000000L) == 0xBC000000L)
+			return (status >> 16) & 0xFF;
+		buffer = pci_alloc_consistent(dev->pdev, 512, &baddr);
+		ret = -2;
+		if (buffer == NULL)
+			return ret;
+		post = pci_alloc_consistent(dev->pdev,
+		  sizeof(struct POSTSTATUS), &paddr);
+		if (post == NULL) {
+			pci_free_consistent(dev->pdev, 512, buffer, baddr);
+			return ret;
+		}
+		memset(buffer, 0, 512);
+		post->Post_Command = cpu_to_le32(COMMAND_POST_RESULTS);
+		post->Post_Address = cpu_to_le32(baddr);
+		rx_writel(dev, MUnit.IMRx[0], paddr);
+		rx_sync_cmd(dev, COMMAND_POST_RESULTS, baddr, &status);
+		pci_free_consistent(dev->pdev, sizeof(struct POSTSTATUS),
+		  post, paddr);
+		if ((buffer[0] == '0') && (buffer[1] == 'x')) {
+			ret = (buffer[2] <= '9') ? (buffer[2] - '0') : (buffer[2] - 'A' + 10);
+			ret <<= 4;
+			ret += (buffer[3] <= '9') ? (buffer[3] - '0') : (buffer[3] - 'A' + 10);
+		}
+		pci_free_consistent(dev->pdev, 512, buffer, baddr);
+		return ret;
+	}
+	/*
+	 *	Wait for the adapter to be up and running.
+	 */
+	if (!(status & KERNEL_UP_AND_RUNNING))
+		return -3;
+	/*
+	 *	Everything is OK
+	 */
+	return 0;
+}
+
+/**
+ *	aac_rx_init	-	initialize an i960 based AAC card
+ *	@dev: device to configure
+ *
+ *	Allocate and set up resources for the i960 based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_rx_init(struct aac_dev *dev)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char * name;
+
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+	if((dev->regs.rx = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map i960.\n" );
+		return -1;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (rx_readl(dev, MUnit.OMRx[0]) & SELF_TEST_FAILED) {
+		printk(KERN_ERR "%s%d: adapter self-test failed.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) {
+		printk(KERN_ERR "%s%d: adapter kernel panic.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the monitor panic'd while booting.
+	 */
+	if (rx_readl(dev, MUnit.OMRx[0]) & MONITOR_PANIC) {
+		printk(KERN_ERR "%s%d: adapter monitor panic.\n", dev->name, instance);
+		goto error_iounmap;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	while ((!(rx_readl(dev, IndexRegs.Mailbox[7]) & KERNEL_UP_AND_RUNNING))
+		|| (!(rx_readl(dev, MUnit.OMRx[0]) & KERNEL_UP_AND_RUNNING)))
+	{
+		if(time_after(jiffies, start+180*HZ))
+		{
+			status = rx_readl(dev, IndexRegs.Mailbox[7]);
+			printk(KERN_ERR "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					dev->name, instance, status);
+			goto error_iounmap;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	if (request_irq(dev->scsi_host_ptr->irq, aac_rx_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev)<0) 
+	{
+		printk(KERN_ERR "%s%d: Interrupt unavailable.\n", name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+	dev->a_ops.adapter_interrupt = aac_rx_interrupt_adapter;
+	dev->a_ops.adapter_notify = aac_rx_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = rx_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_rx_check_health;
+
+	if (aac_init_adapter(dev) == NULL)
+		goto error_irq;
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if(dev->thread_pid < 0)
+	{
+		printk(KERN_ERR "aacraid: Unable to create rx thread.\n");
+		goto error_kfree;
+	}
+	/*
+	 *	Tell the adapter that all is configured, and it can start
+	 *	accepting requests
+	 */
+	aac_rx_start_adapter(dev);
+	return 0;
+
+error_kfree:
+	kfree(dev->queues);
+
+error_irq:
+	free_irq(dev->scsi_host_ptr->irq, (void *)dev);
+
+error_iounmap:
+	iounmap(dev->regs.rx);
+
+	return -1;
+}
diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
new file mode 100644
index 0000000..bd6c307
--- /dev/null
+++ b/drivers/scsi/aacraid/sa.c
@@ -0,0 +1,374 @@
+/*
+ *	Adaptec AAC series RAID controller driver
+ *	(c) Copyright 2001 Red Hat Inc.	<alan@redhat.com>
+ *
+ * based on the old aacraid driver that is..
+ * Adaptec aacraid device driver for Linux.
+ *
+ * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Module Name:
+ *  sa.c
+ *
+ * Abstract: Drawbridge specific support functions
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/time.h>
+#include <linux/interrupt.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi_host.h>
+
+#include "aacraid.h"
+
+static irqreturn_t aac_sa_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct aac_dev *dev = dev_id;
+	unsigned short intstat, mask;
+
+	intstat = sa_readw(dev, DoorbellReg_p);
+	/*
+	 *	Read mask and invert because drawbridge is reversed.
+	 *	This allows us to only service interrupts that have been enabled.
+	 */
+	mask = ~(sa_readw(dev, SaDbCSR.PRISETIRQMASK));
+
+	/* Check to see if this is our interrupt.  If it isn't just return */
+
+	if (intstat & mask) {
+		if (intstat & PrintfReady) {
+			aac_printf(dev, sa_readl(dev, Mailbox5));
+			sa_writew(dev, DoorbellClrReg_p, PrintfReady); /* clear PrintfReady */
+			sa_writew(dev, DoorbellReg_s, PrintfDone);
+		} else if (intstat & DOORBELL_1) {	// dev -> Host Normal Command Ready
+			aac_command_normal(&dev->queues->queue[HostNormCmdQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_1);
+		} else if (intstat & DOORBELL_2) {	// dev -> Host Normal Response Ready
+			aac_response_normal(&dev->queues->queue[HostNormRespQueue]);
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_2);
+		} else if (intstat & DOORBELL_3) {	// dev -> Host Normal Command Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_3);
+		} else if (intstat & DOORBELL_4) {	// dev -> Host Normal Response Not Full
+			sa_writew(dev, DoorbellClrReg_p, DOORBELL_4);
+		}
+		return IRQ_HANDLED;
+	}
+	return IRQ_NONE;
+}
+
+/**
+ *	aac_sa_notify_adapter		-	handle adapter notification
+ *	@dev:	Adapter that notification is for
+ *	@event:	Event to notidy
+ *
+ *	Notify the adapter of an event
+ */
+ 
+void aac_sa_notify_adapter(struct aac_dev *dev, u32 event)
+{
+	switch (event) {
+
+	case AdapNormCmdQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_1);
+		break;
+	case HostNormRespNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_4);
+		break;
+	case AdapNormRespQue:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_2);
+		break;
+	case HostNormCmdNotFull:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_3);
+		break;
+	case HostShutdown:
+		//sa_sync_cmd(dev, HOST_CRASHING, 0, &ret);
+		break;
+	case FastIo:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_6);
+		break;
+	case AdapPrintfDone:
+		sa_writew(dev, DoorbellReg_s,DOORBELL_5);
+		break;
+	default:
+		BUG();
+		break;
+	}
+}
+
+
+/**
+ *	sa_sync_cmd	-	send a command and wait
+ *	@dev: Adapter
+ *	@command: Command to execute
+ *	@p1: first parameter
+ *	@ret: adapter status
+ *
+ *	This routine will send a synchronous command to the adapter and wait 
+ *	for its	completion.
+ */
+
+static int sa_sync_cmd(struct aac_dev *dev, u32 command, u32 p1, u32 *ret)
+{
+	unsigned long start;
+ 	int ok;
+	/*
+	 *	Write the Command into Mailbox 0
+	 */
+	sa_writel(dev, Mailbox0, command);
+	/*
+	 *	Write the parameters into Mailboxes 1 - 4
+	 */
+	sa_writel(dev, Mailbox1, p1);
+	sa_writel(dev, Mailbox2, 0);
+	sa_writel(dev, Mailbox3, 0);
+	sa_writel(dev, Mailbox4, 0);
+	/*
+	 *	Clear the synch command doorbell to start on a clean slate.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Signal that there is a new synch command
+	 */
+	sa_writew(dev, DoorbellReg_s, DOORBELL_0);
+
+	ok = 0;
+	start = jiffies;
+
+	while(time_before(jiffies, start+30*HZ))
+	{
+		/*
+		 *	Delay 5uS so that the monitor gets access
+		 */
+		udelay(5);
+		/*
+		 *	Mon110 will set doorbell0 bit when it has 
+		 *	completed the command.
+		 */
+		if(sa_readw(dev, DoorbellReg_p) & DOORBELL_0)  {
+			ok = 1;
+			break;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (ok != 1)
+		return -ETIMEDOUT;
+	/*
+	 *	Clear the synch command doorbell.
+	 */
+	sa_writew(dev, DoorbellClrReg_p, DOORBELL_0);
+	/*
+	 *	Pull the synch status from Mailbox 0.
+	 */
+	if (ret)
+		*ret = sa_readl(dev, Mailbox0);
+	return 0;
+}
+
+/**
+ *	aac_sa_interrupt_adapter	-	interrupt an adapter
+ *	@dev: Which adapter to enable.
+ *
+ *	Breakpoint an adapter.
+ */
+ 
+static void aac_sa_interrupt_adapter (struct aac_dev *dev)
+{
+	u32 ret;
+	sa_sync_cmd(dev, BREAKPOINT_REQUEST, 0, &ret);
+}
+
+/**
+ *	aac_sa_start_adapter		-	activate adapter
+ *	@dev:	Adapter
+ *
+ *	Start up processing on an ARM based AAC adapter
+ */
+
+static void aac_sa_start_adapter(struct aac_dev *dev)
+{
+	u32 ret;
+	struct aac_init *init;
+	/*
+	 * Fill in the remaining pieces of the init.
+	 */
+	init = dev->init;
+	init->HostElapsedSeconds = cpu_to_le32(get_seconds());
+
+	/*
+	 * Tell the adapter we are back and up and running so it will scan its command
+	 * queues and enable our interrupts
+	 */
+	dev->irq_mask =	(PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4);
+	/*
+	 *	First clear out all interrupts.  Then enable the one's that 
+	 *	we can handle.
+	 */
+	sa_writew(dev, SaDbCSR.PRISETIRQMASK, cpu_to_le16(0xffff));
+	sa_writew(dev, SaDbCSR.PRICLEARIRQMASK, (PrintfReady | DOORBELL_1 | DOORBELL_2 | DOORBELL_3 | DOORBELL_4));
+	/* We can only use a 32 bit address here */
+	sa_sync_cmd(dev, INIT_STRUCT_BASE_ADDRESS, (u32)(ulong)dev->init_pa, &ret);
+}
+
+/**
+ *	aac_sa_check_health
+ *	@dev: device to check if healthy
+ *
+ *	Will attempt to determine if the specified adapter is alive and
+ *	capable of handling requests, returning 0 if alive.
+ */
+static int aac_sa_check_health(struct aac_dev *dev)
+{
+	long status = sa_readl(dev, Mailbox7);
+
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (status & SELF_TEST_FAILED)
+		return -1;
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (status & KERNEL_PANIC)
+		return -2;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes
+	 */
+	if (!(status & KERNEL_UP_AND_RUNNING))
+		return -3;
+	/*
+	 *	Everything is OK
+	 */
+	return 0;
+}
+
+/**
+ *	aac_sa_init	-	initialize an ARM based AAC card
+ *	@dev: device to configure
+ *
+ *	Allocate and set up resources for the ARM based AAC variants. The 
+ *	device_interface in the commregion will be allocated and linked 
+ *	to the comm region.
+ */
+
+int aac_sa_init(struct aac_dev *dev)
+{
+	unsigned long start;
+	unsigned long status;
+	int instance;
+	const char *name;
+
+	instance = dev->id;
+	name     = dev->name;
+
+	/*
+	 *	Map in the registers from the adapter.
+	 */
+
+	if((dev->regs.sa = ioremap((unsigned long)dev->scsi_host_ptr->base, 8192))==NULL)
+	{	
+		printk(KERN_WARNING "aacraid: unable to map ARM.\n" );
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the board failed any self tests.
+	 */
+	if (sa_readl(dev, Mailbox7) & SELF_TEST_FAILED) {
+		printk(KERN_WARNING "%s%d: adapter self-test failed.\n", name, instance);
+		goto error_iounmap;
+	}
+	/*
+	 *	Check to see if the board panic'd while booting.
+	 */
+	if (sa_readl(dev, Mailbox7) & KERNEL_PANIC) {
+		printk(KERN_WARNING "%s%d: adapter kernel panic'd.\n", name, instance);
+		goto error_iounmap;
+	}
+	start = jiffies;
+	/*
+	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
+	 */
+	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
+		if (time_after(jiffies, start+180*HZ)) {
+			status = sa_readl(dev, Mailbox7);
+			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %lx.\n", 
+					name, instance, status);
+			goto error_iounmap;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if (request_irq(dev->scsi_host_ptr->irq, aac_sa_intr, SA_SHIRQ|SA_INTERRUPT, "aacraid", (void *)dev ) < 0) {
+		printk(KERN_WARNING "%s%d: Interrupt unavailable.\n", name, instance);
+		goto error_iounmap;
+	}
+
+	/*
+	 *	Fill in the function dispatch table.
+	 */
+
+	dev->a_ops.adapter_interrupt = aac_sa_interrupt_adapter;
+	dev->a_ops.adapter_notify = aac_sa_notify_adapter;
+	dev->a_ops.adapter_sync_cmd = sa_sync_cmd;
+	dev->a_ops.adapter_check_health = aac_sa_check_health;
+
+
+	if(aac_init_adapter(dev) == NULL)
+		goto error_irq;
+
+	/*
+	 *	Start any kernel threads needed
+	 */
+	dev->thread_pid = kernel_thread((int (*)(void *))aac_command_thread, dev, 0);
+	if (dev->thread_pid < 0) {
+		printk(KERN_ERR "aacraid: Unable to create command thread.\n");
+		goto error_kfree;
+	}
+
+	/*
+	 *	Tell the adapter that all is configure, and it can start 
+	 *	accepting requests
+	 */
+	aac_sa_start_adapter(dev);
+	return 0;
+
+
+error_kfree:
+	kfree(dev->queues);
+
+error_irq:
+	free_irq(dev->scsi_host_ptr->irq, (void *)dev);
+
+error_iounmap:
+	iounmap(dev->regs.sa);
+
+	return -1;
+}
+
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
new file mode 100644
index 0000000..9962c51
--- /dev/null
+++ b/drivers/scsi/advansys.c
@@ -0,0 +1,18237 @@
+#define ASC_VERSION "3.3K"    /* AdvanSys Driver Version */
+
+/*
+ * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
+ *
+ * Copyright (c) 1995-2000 Advanced System Products, Inc.
+ * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ *
+ */
+
+/*
+
+  Documentation for the AdvanSys Driver
+
+  A. Linux Kernels Supported by this Driver
+  B. Adapters Supported by this Driver
+  C. Linux source files modified by AdvanSys Driver
+  D. Source Comments
+  E. Driver Compile Time Options and Debugging
+  F. Driver LILO Option
+  G. Tests to run before releasing new driver
+  H. Release History
+  I. Known Problems/Fix List
+  J. Credits (Chronological Order)
+
+  A. Linux Kernels Supported by this Driver
+
+     This driver has been tested in the following Linux kernels: v2.2.18
+     v2.4.0. The driver is supported on v2.2 and v2.4 kernels and on x86,
+     alpha, and PowerPC platforms.
+
+  B. Adapters Supported by this Driver
+
+     AdvanSys (Advanced System Products, Inc.) manufactures the following
+     RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
+     (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
+     buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
+     transfer) SCSI Host Adapters for the PCI bus.
+
+     The CDB counts below indicate the number of SCSI CDB (Command
+     Descriptor Block) requests that can be stored in the RISC chip
+     cache and board LRAM. A CDB is a single SCSI command. The driver
+     detect routine will display the number of CDBs available for each
+     adapter detected. The number of CDBs used by the driver can be
+     lowered in the BIOS by changing the 'Host Queue Size' adapter setting.
+
+     Laptop Products:
+        ABP-480 - Bus-Master CardBus (16 CDB) (2.4 kernel and greater)
+
+     Connectivity Products:
+        ABP510/5150 - Bus-Master ISA (240 CDB)
+        ABP5140 - Bus-Master ISA PnP (16 CDB)
+        ABP5142 - Bus-Master ISA PnP with floppy (16 CDB)
+        ABP902/3902 - Bus-Master PCI (16 CDB)
+        ABP3905 - Bus-Master PCI (16 CDB)
+        ABP915 - Bus-Master PCI (16 CDB)
+        ABP920 - Bus-Master PCI (16 CDB)
+        ABP3922 - Bus-Master PCI (16 CDB)
+        ABP3925 - Bus-Master PCI (16 CDB)
+        ABP930 - Bus-Master PCI (16 CDB)
+        ABP930U - Bus-Master PCI Ultra (16 CDB)
+        ABP930UA - Bus-Master PCI Ultra (16 CDB)
+        ABP960 - Bus-Master PCI MAC/PC (16 CDB)
+        ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+
+     Single Channel Products:
+        ABP542 - Bus-Master ISA with floppy (240 CDB)
+        ABP742 - Bus-Master EISA (240 CDB)
+        ABP842 - Bus-Master VL (240 CDB)
+        ABP940 - Bus-Master PCI (240 CDB)
+        ABP940U - Bus-Master PCI Ultra (240 CDB)
+        ABP940UA/3940UA - Bus-Master PCI Ultra (240 CDB)
+        ABP970 - Bus-Master PCI MAC/PC (240 CDB)
+        ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+        ABP3960UA - Bus-Master PCI MAC/PC Ultra (240 CDB)
+        ABP940UW/3940UW - Bus-Master PCI Ultra-Wide (253 CDB)
+        ABP970UW - Bus-Master PCI MAC/PC Ultra-Wide (253 CDB)
+        ABP3940U2W - Bus-Master PCI LVD/Ultra2-Wide (253 CDB)
+
+     Multi-Channel Products:
+        ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
+        ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
+        ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP950UW - Dual Channel Bus-Master PCI Ultra-Wide (253 CDB Per Channel)
+        ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+        ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
+        ABP980UA/3980UA - Four Channel Bus-Master PCI Ultra (16 CDB Per Chan.)
+        ABP3950U2W - Bus-Master PCI LVD/Ultra2-Wide and Ultra-Wide (253 CDB)
+        ABP3950U3W - Bus-Master PCI Dual LVD2/Ultra3-Wide (253 CDB)
+
+  C. Linux source files modified by AdvanSys Driver
+
+     This section for historical purposes documents the changes
+     originally made to the Linux kernel source to add the advansys
+     driver. As Linux has changed some of these files have also
+     been modified.
+
+     1. linux/arch/i386/config.in:
+
+          bool 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS y
+
+     2. linux/drivers/scsi/hosts.c:
+
+          #ifdef CONFIG_SCSI_ADVANSYS
+          #include "advansys.h"
+          #endif
+
+        and after "static Scsi_Host_Template builtin_scsi_hosts[] =":
+
+          #ifdef CONFIG_SCSI_ADVANSYS
+          ADVANSYS,
+          #endif
+
+     3. linux/drivers/scsi/Makefile:
+
+          ifdef CONFIG_SCSI_ADVANSYS
+          SCSI_SRCS := $(SCSI_SRCS) advansys.c
+          SCSI_OBJS := $(SCSI_OBJS) advansys.o
+          else
+          SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) advansys.o
+          endif
+
+     4. linux/init/main.c:
+
+          extern void advansys_setup(char *str, int *ints);
+
+        and add the following lines to the bootsetups[] array.
+
+          #ifdef CONFIG_SCSI_ADVANSYS
+             { "advansys=", advansys_setup },
+          #endif
+
+  D. Source Comments
+
+     1. Use tab stops set to 4 for the source files. For vi use 'se tabstops=4'.
+
+     2. This driver should be maintained in multiple files. But to make
+        it easier to include with Linux and to follow Linux conventions,
+        the whole driver is maintained in the source files advansys.h and
+        advansys.c. In this file logical sections of the driver begin with
+        a comment that contains '---'. The following are the logical sections
+        of the driver below.
+
+           --- Linux Version
+           --- Linux Include File
+           --- Driver Options
+           --- Debugging Header
+           --- Asc Library Constants and Macros
+           --- Adv Library Constants and Macros
+           --- Driver Constants and Macros
+           --- Driver Structures
+           --- Driver Data
+           --- Driver Function Prototypes
+           --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+           --- Loadable Driver Support
+           --- Miscellaneous Driver Functions
+           --- Functions Required by the Asc Library
+           --- Functions Required by the Adv Library
+           --- Tracing and Debugging Functions
+           --- Asc Library Functions
+           --- Adv Library Functions
+
+     3. The string 'XXX' is used to flag code that needs to be re-written
+        or that contains a problem that needs to be addressed.
+
+     4. I have stripped comments from and reformatted the source for the
+        Asc Library and Adv Library to reduce the size of this file. This
+        source can be found under the following headings. The Asc Library
+        is used to support Narrow Boards. The Adv Library is used to
+        support Wide Boards.
+
+           --- Asc Library Constants and Macros
+           --- Adv Library Constants and Macros
+           --- Asc Library Functions
+           --- Adv Library Functions
+
+  E. Driver Compile Time Options and Debugging
+
+     In this source file the following constants can be defined. They are
+     defined in the source below. Both of these options are enabled by
+     default.
+
+     1. ADVANSYS_ASSERT - Enable driver assertions (Def: Enabled)
+
+        Enabling this option adds assertion logic statements to the
+        driver. If an assertion fails a message will be displayed to
+        the console, but the system will continue to operate. Any
+        assertions encountered should be reported to the person
+        responsible for the driver. Assertion statements may proactively
+        detect problems with the driver and facilitate fixing these
+        problems. Enabling assertions will add a small overhead to the
+        execution of the driver.
+
+     2. ADVANSYS_DEBUG - Enable driver debugging (Def: Disabled)
+
+        Enabling this option adds tracing functions to the driver and
+        the ability to set a driver tracing level at boot time. This
+        option will also export symbols not required outside the driver to
+        the kernel name space. This option is very useful for debugging
+        the driver, but it will add to the size of the driver execution
+        image and add overhead to the execution of the driver.
+
+        The amount of debugging output can be controlled with the global
+        variable 'asc_dbglvl'. The higher the number the more output. By
+        default the debug level is 0.
+
+        If the driver is loaded at boot time and the LILO Driver Option
+        is included in the system, the debug level can be changed by
+        specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
+        first three hex digits of the pseudo I/O Port must be set to
+        'deb' and the fourth hex digit specifies the debug level: 0 - F.
+        The following command line will look for an adapter at 0x330
+        and set the debug level to 2.
+
+           linux advansys=0x330,0,0,0,0xdeb2
+
+        If the driver is built as a loadable module this variable can be
+        defined when the driver is loaded. The following insmod command
+        will set the debug level to one.
+
+           insmod advansys.o asc_dbglvl=1
+
+        Debugging Message Levels:
+           0: Errors Only
+           1: High-Level Tracing
+           2-N: Verbose Tracing
+
+        To enable debug output to console, please make sure that:
+
+        a. System and kernel logging is enabled (syslogd, klogd running).
+        b. Kernel messages are routed to console output. Check
+           /etc/syslog.conf for an entry similar to this:
+
+                kern.*                  /dev/console
+
+        c. klogd is started with the appropriate -c parameter
+           (e.g. klogd -c 8)
+
+        This will cause printk() messages to be be displayed on the
+        current console. Refer to the klogd(8) and syslogd(8) man pages
+        for details.
+
+        Alternatively you can enable printk() to console with this
+        program. However, this is not the 'official' way to do this.
+        Debug output is logged in /var/log/messages.
+
+          main()
+          {
+                  syscall(103, 7, 0, 0);
+          }
+
+        Increasing LOG_BUF_LEN in kernel/printk.c to something like
+        40960 allows more debug messages to be buffered in the kernel
+        and written to the console or log file.
+
+     3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
+
+        Enabling this option adds statistics collection and display
+        through /proc to the driver. The information is useful for
+        monitoring driver and device performance. It will add to the
+        size of the driver execution image and add minor overhead to
+        the execution of the driver.
+
+        Statistics are maintained on a per adapter basis. Driver entry
+        point call counts and transfer size counts are maintained.
+        Statistics are only available for kernels greater than or equal
+        to v1.3.0 with the CONFIG_PROC_FS (/proc) file system configured.
+
+        AdvanSys SCSI adapter files have the following path name format:
+
+           /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
+
+        This information can be displayed with cat. For example:
+
+           cat /proc/scsi/advansys/0
+
+        When ADVANSYS_STATS is not defined the AdvanSys /proc files only
+        contain adapter and device configuration information.
+
+  F. Driver LILO Option
+
+     If init/main.c is modified as described in the 'Directions for Adding
+     the AdvanSys Driver to Linux' section (B.4.) above, the driver will
+     recognize the 'advansys' LILO command line and /etc/lilo.conf option.
+     This option can be used to either disable I/O port scanning or to limit
+     scanning to 1 - 4 I/O ports. Regardless of the option setting EISA and
+     PCI boards will still be searched for and detected. This option only
+     affects searching for ISA and VL boards.
+
+     Examples:
+       1. Eliminate I/O port scanning:
+            boot: linux advansys=
+              or
+            boot: linux advansys=0x0
+       2. Limit I/O port scanning to one I/O port:
+            boot: linux advansys=0x110
+       3. Limit I/O port scanning to four I/O ports:
+            boot: linux advansys=0x110,0x210,0x230,0x330
+
+     For a loadable module the same effect can be achieved by setting
+     the 'asc_iopflag' variable and 'asc_ioport' array when loading
+     the driver, e.g.
+
+           insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
+
+     If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
+     I/O Port may be added to specify the driver debug level. Refer to
+     the 'Driver Compile Time Options and Debugging' section above for
+     more information.
+
+  G. Tests to run before releasing new driver
+
+     1. In the supported kernels verify there are no warning or compile
+        errors when the kernel is built as both a driver and as a module
+        and with the following options:
+
+        ADVANSYS_DEBUG - enabled and disabled
+        CONFIG_SMP - enabled and disabled
+        CONFIG_PROC_FS - enabled and disabled
+
+     2. Run tests on an x86, alpha, and PowerPC with at least one narrow
+        card and one wide card attached to a hard disk and CD-ROM drive:
+        fdisk, mkfs, fsck, bonnie, copy/compare test from the
+        CD-ROM to the hard drive.
+
+  H. Release History
+
+     BETA-1.0 (12/23/95):
+         First Release
+
+     BETA-1.1 (12/28/95):
+         1. Prevent advansys_detect() from being called twice.
+         2. Add LILO 0xdeb[0-f] option to set 'asc_dbglvl'.
+
+     1.2 (1/12/96):
+         1. Prevent re-entrancy in the interrupt handler which
+            resulted in the driver hanging Linux.
+         2. Fix problem that prevented ABP-940 cards from being
+            recognized on some PCI motherboards.
+         3. Add support for the ABP-5140 PnP ISA card.
+         4. Fix check condition return status.
+         5. Add conditionally compiled code for Linux v1.3.X.
+
+     1.3 (2/23/96):
+         1. Fix problem in advansys_biosparam() that resulted in the
+            wrong drive geometry being returned for drives > 1GB with
+            extended translation enabled.
+         2. Add additional tracing during device initialization.
+         3. Change code that only applies to ISA PnP adapter.
+         4. Eliminate 'make dep' warning.
+         5. Try to fix problem with handling resets by increasing their
+            timeout value.
+
+     1.4 (5/8/96):
+         1. Change definitions to eliminate conflicts with other subsystems.
+         2. Add versioning code for the shared interrupt changes.
+         3. Eliminate problem in asc_rmqueue() with iterating after removing
+            a request.
+         4. Remove reset request loop problem from the "Known Problems or
+            Issues" section. This problem was isolated and fixed in the
+            mid-level SCSI driver.
+
+     1.5 (8/8/96):
+         1. Add support for ABP-940U (PCI Ultra) adapter.
+         2. Add support for IRQ sharing by setting the SA_SHIRQ flag for
+            request_irq and supplying a dev_id pointer to both request_irq()
+            and free_irq().
+         3. In AscSearchIOPortAddr11() restore a call to check_region() which
+            should be used before I/O port probing.
+         4. Fix bug in asc_prt_hex() which resulted in the displaying
+            the wrong data.
+         5. Incorporate miscellaneous Asc Library bug fixes and new microcode.
+         6. Change driver versioning to be specific to each Linux sub-level.
+         7. Change statistics gathering to be per adapter instead of global
+            to the driver.
+         8. Add more information and statistics to the adapter /proc file:
+            /proc/scsi/advansys[0...].
+         9. Remove 'cmd_per_lun' from the "Known Problems or Issues" list.
+            This problem has been addressed with the SCSI mid-level changes
+            made in v1.3.89. The advansys_select_queue_depths() function
+            was added for the v1.3.89 changes.
+
+     1.6 (9/10/96):
+         1. Incorporate miscellaneous Asc Library bug fixes and new microcode.
+
+     1.7 (9/25/96):
+         1. Enable clustering and optimize the setting of the maximum number
+            of scatter gather elements for any particular board. Clustering
+            increases CPU utilization, but results in a relatively larger
+            increase in I/O throughput.
+         2. Improve the performance of the request queuing functions by
+            adding a last pointer to the queue structure.
+         3. Correct problems with reset and abort request handling that
+            could have hung or crashed Linux.
+         4. Add more information to the adapter /proc file:
+            /proc/scsi/advansys[0...].
+         5. Remove the request timeout issue form the driver issues list.
+         6. Miscellaneous documentation additions and changes.
+
+     1.8 (10/4/96):
+         1. Make changes to handle the new v2.1.0 kernel memory mapping
+            in which a kernel virtual address may not be equivalent to its
+            bus or DMA memory address.
+         2. Change abort and reset request handling to make it yet even
+            more robust.
+         3. Try to mitigate request starvation by sending ordered requests
+            to heavily loaded, tag queuing enabled devices.
+         4. Maintain statistics on request response time.
+         5. Add request response time statistics and other information to
+            the adapter /proc file: /proc/scsi/advansys[0...].
+
+     1.9 (10/21/96):
+         1. Add conditionally compiled code (ASC_QUEUE_FLOW_CONTROL) to
+            make use of mid-level SCSI driver device queue depth flow
+            control mechanism. This will eliminate aborts caused by a
+            device being unable to keep up with requests and eliminate
+            repeat busy or QUEUE FULL status returned by a device.
+         2. Incorporate miscellaneous Asc Library bug fixes.
+         3. To allow the driver to work in kernels with broken module
+            support set 'cmd_per_lun' if the driver is compiled as a
+            module. This change affects kernels v1.3.89 to present.
+         4. Remove PCI BIOS address from the driver banner. The PCI BIOS
+            is relocated by the motherboard BIOS and its new address can
+            not be determined by the driver.
+         5. Add mid-level SCSI queue depth information to the adapter
+            /proc file: /proc/scsi/advansys[0...].
+
+     2.0 (11/14/96):
+         1. Change allocation of global structures used for device
+            initialization to guarantee they are in DMA-able memory.
+            Previously when the driver was loaded as a module these
+            structures might not have been in DMA-able memory, causing
+            device initialization to fail.
+
+     2.1 (12/30/96):
+         1. In advansys_reset(), if the request is a synchronous reset
+            request, even if the request serial number has changed, then
+            complete the request.
+         2. Add Asc Library bug fixes including new microcode.
+         3. Clear inquiry buffer before using it.
+         4. Correct ifdef typo.
+
+     2.2 (1/15/97):
+         1. Add Asc Library bug fixes including new microcode.
+         2. Add synchronous data transfer rate information to the
+            adapter /proc file: /proc/scsi/advansys[0...].
+         3. Change ADVANSYS_DEBUG to be disabled by default. This
+            will reduce the size of the driver image, eliminate execution
+            overhead, and remove unneeded symbols from the kernel symbol
+            space that were previously added by the driver.
+         4. Add new compile-time option ADVANSYS_ASSERT for assertion
+            code that used to be defined within ADVANSYS_DEBUG. This
+            option is enabled by default.
+
+     2.8 (5/26/97):
+         1. Change version number to 2.8 to synchronize the Linux driver
+            version numbering with other AdvanSys drivers.
+         2. Reformat source files without tabs to present the same view
+            of the file to everyone regardless of the editor tab setting
+            being used.
+         3. Add Asc Library bug fixes.
+
+     3.1A (1/8/98):
+         1. Change version number to 3.1 to indicate that support for
+            Ultra-Wide adapters (ABP-940UW) is included in this release.
+         2. Add Asc Library (Narrow Board) bug fixes.
+         3. Report an underrun condition with the host status byte set
+            to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
+            causes the underrun condition to be ignored. When Linux defines
+            its own DID_UNDERRUN the constant defined in this file can be
+            removed.
+         4. Add patch to AscWaitTixISRDone().
+         5. Add support for up to 16 different AdvanSys host adapter SCSI
+            channels in one system. This allows four cards with four channels
+            to be used in one system.
+
+     3.1B (1/9/98):
+         1. Handle that PCI register base addresses are not always page
+            aligned even though ioremap() requires that the address argument
+            be page aligned.
+
+     3.1C (1/10/98):
+         1. Update latest BIOS version checked for from the /proc file.
+         2. Don't set microcode SDTR variable at initialization. Instead
+            wait until device capabilities have been detected from an Inquiry
+            command.
+
+     3.1D (1/21/98):
+         1. Improve performance when the driver is compiled as module by
+            allowing up to 64 scatter-gather elements instead of 8.
+
+     3.1E (5/1/98):
+         1. Set time delay in AscWaitTixISRDone() to 1000 ms.
+         2. Include SMP locking changes.
+         3. For v2.1.93 and newer kernels use CONFIG_PCI and new PCI BIOS
+            access functions.
+         4. Update board serial number printing.
+         5. Try allocating an IRQ both with and without the SA_INTERRUPT
+            flag set to allow IRQ sharing with drivers that do not set
+            the SA_INTERRUPT flag. Also display a more descriptive error
+            message if request_irq() fails.
+         6. Update to latest Asc and Adv Libraries.
+
+     3.2A (7/22/99):
+         1. Update Adv Library to 4.16 which includes support for
+            the ASC38C0800 (Ultra2/LVD) IC.
+
+     3.2B (8/23/99):
+         1. Correct PCI compile time option for v2.1.93 and greater
+            kernels, advansys_info() string, and debug compile time
+            option.
+         2. Correct DvcSleepMilliSecond() for v2.1.0 and greater
+            kernels. This caused an LVD detection/BIST problem problem
+            among other things.
+         3. Sort PCI cards by PCI Bus, Slot, Function ascending order
+            to be consistent with the BIOS.
+         4. Update to Asc Library S121 and Adv Library 5.2.
+
+     3.2C (8/24/99):
+         1. Correct PCI card detection bug introduced in 3.2B that
+            prevented PCI cards from being detected in kernels older
+            than v2.1.93.
+
+     3.2D (8/26/99):
+         1. Correct /proc device synchronous speed information display.
+            Also when re-negotiation is pending for a target device
+            note this condition with an * and footnote.
+         2. Correct initialization problem with Ultra-Wide cards that
+            have a pre-3.2 BIOS. A microcode variable changed locations
+            in 3.2 and greater BIOSes which caused WDTR to be attempted
+            erroneously with drives that don't support WDTR.
+
+     3.2E (8/30/99):
+         1. Fix compile error caused by v2.3.13 PCI structure change.
+         2. Remove field from ASCEEP_CONFIG that resulted in an EEPROM
+            checksum error for ISA cards.
+         3. Remove ASC_QUEUE_FLOW_CONTROL conditional code. The mid-level
+            SCSI changes that it depended on were never included in Linux.
+
+     3.2F (9/3/99):
+         1. Handle new initial function code added in v2.3.16 for all
+            driver versions.
+
+     3.2G (9/8/99):
+         1. Fix PCI board detection in v2.3.13 and greater kernels.
+         2. Fix comiple errors in v2.3.X with debugging enabled.
+
+     3.2H (9/13/99):
+         1. Add 64-bit address, long support for Alpha and UltraSPARC.
+            The driver has been verified to work on an Alpha system.
+         2. Add partial byte order handling support for Power PC and
+            other big-endian platforms. This support has not yet been
+            completed or verified.
+         3. For wide boards replace block zeroing of request and
+            scatter-gather structures with individual field initialization
+            to improve performance.
+         4. Correct and clarify ROM BIOS version detection.
+
+     3.2I (10/8/99):
+         1. Update to Adv Library 5.4.
+         2. Add v2.3.19 underrun reporting to asc_isr_callback() and
+            adv_isr_callback().  Remove DID_UNDERRUN constant and other
+            no longer needed code that previously documented the lack
+            of underrun handling.
+
+     3.2J (10/14/99):
+         1. Eliminate compile errors for v2.0 and earlier kernels.
+
+     3.2K (11/15/99):
+         1. Correct debug compile error in asc_prt_adv_scsi_req_q().
+         2. Update Adv Library to 5.5.
+         3. Add ifdef handling for /proc changes added in v2.3.28.
+         4. Increase Wide board scatter-gather list maximum length to
+            255 when the driver is compiled into the kernel.
+
+     3.2L (11/18/99):
+         1. Fix bug in adv_get_sglist() that caused an assertion failure
+            at line 7475. The reqp->sgblkp pointer must be initialized
+            to NULL in adv_get_sglist().
+
+     3.2M (11/29/99):
+         1. Really fix bug in adv_get_sglist().
+         2. Incorporate v2.3.29 changes into driver.
+
+     3.2N (4/1/00):
+         1. Add CONFIG_ISA ifdef code.
+         2. Include advansys_interrupts_enabled name change patch.
+         3. For >= v2.3.28 use new SCSI error handling with new function
+            advansys_eh_bus_reset(). Don't include an abort function
+            because of base library limitations.
+         4. For >= v2.3.28 use per board lock instead of io_request_lock.
+         5. For >= v2.3.28 eliminate advansys_command() and
+            advansys_command_done().
+         6. Add some changes for PowerPC (Big Endian) support, but it isn't
+            working yet.
+         7. Fix "nonexistent resource free" problem that occurred on a module
+            unload for boards with an I/O space >= 255. The 'n_io_port' field
+            is only one byte and can not be used to hold an ioport length more
+            than 255.
+
+     3.3A (4/4/00):
+         1. Update to Adv Library 5.8.
+         2. For wide cards add support for CDBs up to 16 bytes.
+         3. Eliminate warnings when CONFIG_PROC_FS is not defined.
+
+     3.3B (5/1/00):
+         1. Support for PowerPC (Big Endian) wide cards. Narrow cards
+            still need work.
+         2. Change bitfields to shift and mask access for endian
+            portability.
+
+     3.3C (10/13/00):
+         1. Update for latest 2.4 kernel.
+         2. Test ABP-480 CardBus support in 2.4 kernel - works!
+         3. Update to Asc Library S123.
+         4. Update to Adv Library 5.12.
+
+     3.3D (11/22/00):
+         1. Update for latest 2.4 kernel.
+         2. Create patches for 2.2 and 2.4 kernels.
+
+     3.3E (1/9/01):
+         1. Now that 2.4 is released remove ifdef code for kernel versions
+            less than 2.2. The driver is now only supported in kernels 2.2,
+            2.4, and greater.
+         2. Add code to release and acquire the io_request_lock in
+            the driver entrypoint functions: advansys_detect and
+            advansys_queuecommand. In kernel 2.4 the SCSI mid-level driver
+            still holds the io_request_lock on entry to SCSI low-level drivers.
+            This was supposed to be removed before 2.4 was released but never
+            happened. When the mid-level SCSI driver is changed all references
+            to the io_request_lock should be removed from the driver.
+         3. Simplify error handling by removing advansys_abort(),
+            AscAbortSRB(), AscResetDevice(). SCSI bus reset requests are
+            now handled by resetting the SCSI bus and fully re-initializing
+            the chip. This simple method of error recovery has proven to work
+            most reliably after attempts at different methods. Also now only
+            support the "new" error handling method and remove the obsolete
+            error handling interface.
+         4. Fix debug build errors.
+
+     3.3F (1/24/01):
+         1. Merge with ConnectCom version from Andy Kellner which
+            updates Adv Library to 5.14.
+         2. Make PowerPC (Big Endian) work for narrow cards and
+            fix problems writing EEPROM for wide cards.
+         3. Remove interrupts_enabled assertion function.
+
+     3.3G (2/16/01):
+         1. Return an error from narrow boards if passed a 16 byte
+            CDB. The wide board can already handle 16 byte CDBs.
+
+     3.3GJ (4/15/02):
+	 1. hacks for lk 2.5 series (D. Gilbert)
+
+     3.3GJD (10/14/02):
+         1. change select_queue_depths to slave_configure
+	 2. make cmd_per_lun be sane again
+
+     3.3K [2004/06/24]:
+         1. continuing cleanup for lk 2.6 series
+         2. Fix problem in lk 2.6.7-bk2 that broke PCI wide cards
+         3. Fix problem that oopsed ISA cards
+
+  I. Known Problems/Fix List (XXX)
+
+     1. Need to add memory mapping workaround. Test the memory mapping.
+        If it doesn't work revert to I/O port access. Can a test be done
+        safely?
+     2. Handle an interrupt not working. Keep an interrupt counter in
+        the interrupt handler. In the timeout function if the interrupt
+        has not occurred then print a message and run in polled mode.
+     3. Allow bus type scanning order to be changed.
+     4. Need to add support for target mode commands, cf. CAM XPT.
+
+  J. Credits (Chronological Order)
+
+     Bob Frey <bfrey@turbolinux.com.cn> wrote the AdvanSys SCSI driver
+     and maintained it up to 3.3F. He continues to answer questions
+     and help maintain the driver.
+
+     Nathan Hartwell <mage@cdc3.cdc.net> provided the directions and
+     basis for the Linux v1.3.X changes which were included in the
+     1.2 release.
+
+     Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
+     in advansys_biosparam() which was fixed in the 1.3 release.
+
+     Erik Ratcliffe <erik@caldera.com> has done testing of the
+     AdvanSys driver in the Caldera releases.
+
+     Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+     AscWaitTixISRDone() which he found necessary to make the
+     driver work with a SCSI-1 disk.
+
+     Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
+     support in the 3.1A driver.
+
+     Doug Gilbert <dgilbert@interlog.com> has made changes and
+     suggestions to improve the driver and done a lot of testing.
+
+     Ken Mort <ken@mort.net> reported a DEBUG compile bug fixed
+     in 3.2K.
+
+     Tom Rini <trini@kernel.crashing.org> provided the CONFIG_ISA
+     patch and helped with PowerPC wide and narrow board support.
+
+     Philip Blundell <philb@gnu.org> provided an
+     advansys_interrupts_enabled patch.
+
+     Dave Jones <dave@denial.force9.co.uk> reported the compiler
+     warnings generated when CONFIG_PROC_FS was not defined in
+     the 3.2M driver.
+
+     Jerry Quinn <jlquinn@us.ibm.com> fixed PowerPC support (endian
+     problems) for wide cards.
+
+     Bryan Henderson <bryanh@giraffe-data.com> helped debug narrow
+     card error handling.
+
+     Manuel Veloso <veloso@pobox.com> worked hard on PowerPC narrow
+     board support and fixed a bug in AscGetEEPConfig().
+
+     Arnaldo Carvalho de Melo <acme@conectiva.com.br> made
+     save_flags/restore_flags changes.
+
+     Andy Kellner <AKellner@connectcom.net> continues the Advansys SCSI
+     driver development for ConnectCom (Version > 3.3F).
+
+  K. ConnectCom (AdvanSys) Contact Information
+
+     Mail:                   ConnectCom Solutions, Inc.
+                             1150 Ringwood Court
+                             San Jose, CA 95131
+     Operator/Sales:         1-408-383-9400
+     FAX:                    1-408-383-9612
+     Tech Support:           1-408-467-2930
+     Tech Support E-Mail:    linux@connectcom.net
+     FTP Site:               ftp.connectcom.net (login: anonymous)
+     Web Site:               http://www.connectcom.net
+
+*/
+
+/*
+ * --- Linux Include Files
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#if defined(CONFIG_X86) && !defined(CONFIG_ISA)
+#define CONFIG_ISA
+#endif /* CONFIG_X86 && !CONFIG_ISA */
+
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/stat.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+
+/* FIXME: (by jejb@steeleye.com) This warning is present for two
+ * reasons:
+ *
+ * 1) This driver badly needs converting to the correct driver model
+ *    probing API
+ *
+ * 2) Although all of the necessary command mapping places have the
+ * appropriate dma_map.. APIs, the driver still processes its internal
+ * queue using bus_to_virt() and virt_to_bus() which are illegal under
+ * the API.  The entire queue processing structure will need to be
+ * altered to fix this.
+ */
+#warning this driver is still not properly converted to the DMA API
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include "advansys.h"
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif /* CONFIG_PCI */
+
+
+/*
+ * --- Driver Options
+ */
+
+/* Enable driver assertions. */
+#define ADVANSYS_ASSERT
+
+/* Enable driver /proc statistics. */
+#define ADVANSYS_STATS
+
+/* Enable driver tracing. */
+/* #define ADVANSYS_DEBUG */
+
+
+/*
+ * --- Debugging Header
+ */
+
+#ifdef ADVANSYS_DEBUG
+#define STATIC
+#else /* ADVANSYS_DEBUG */
+#define STATIC static
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Asc Library Constants and Macros
+ */
+
+#define ASC_LIB_VERSION_MAJOR  1
+#define ASC_LIB_VERSION_MINOR  24
+#define ASC_LIB_SERIAL_NUMBER  123
+
+/*
+ * Portable Data Types
+ *
+ * Any instance where a 32-bit long or pointer type is assumed
+ * for precision or HW defined structures, the following define
+ * types must be used. In Linux the char, short, and int types
+ * are all consistent at 8, 16, and 32 bits respectively. Pointers
+ * and long types are 64 bits on Alpha and UltraSPARC.
+ */
+#define ASC_PADDR __u32         /* Physical/Bus address data type. */
+#define ASC_VADDR __u32         /* Virtual address data type. */
+#define ASC_DCNT  __u32         /* Unsigned Data count type. */
+#define ASC_SDCNT __s32         /* Signed Data count type. */
+
+/*
+ * These macros are used to convert a virtual address to a
+ * 32-bit value. This currently can be used on Linux Alpha
+ * which uses 64-bit virtual address but a 32-bit bus address.
+ * This is likely to break in the future, but doing this now
+ * will give us time to change the HW and FW to handle 64-bit
+ * addresses.
+ */
+#define ASC_VADDR_TO_U32   virt_to_bus
+#define ASC_U32_TO_VADDR   bus_to_virt
+
+typedef unsigned char uchar;
+
+#ifndef TRUE
+#define TRUE     (1)
+#endif
+#ifndef FALSE
+#define FALSE    (0)
+#endif
+
+#define EOF      (-1)
+#define ERR      (-1)
+#define UW_ERR   (uint)(0xFFFF)
+#define isodd_word(val)   ((((uint)val) & (uint)0x0001) != 0)
+#define AscPCIConfigVendorIDRegister      0x0000
+#define AscPCIConfigDeviceIDRegister      0x0002
+#define AscPCIConfigCommandRegister       0x0004
+#define AscPCIConfigStatusRegister        0x0006
+#define AscPCIConfigRevisionIDRegister    0x0008
+#define AscPCIConfigCacheSize             0x000C
+#define AscPCIConfigLatencyTimer          0x000D
+#define AscPCIIOBaseRegister              0x0010
+#define AscPCICmdRegBits_IOMemBusMaster   0x0007
+#define ASC_PCI_ID2BUS(id)    ((id) & 0xFF)
+#define ASC_PCI_ID2DEV(id)    (((id) >> 11) & 0x1F)
+#define ASC_PCI_ID2FUNC(id)   (((id) >> 8) & 0x7)
+#define ASC_PCI_MKID(bus, dev, func) ((((dev) & 0x1F) << 11) | (((func) & 0x7) << 8) | ((bus) & 0xFF))
+#define ASC_PCI_VENDORID                  0x10CD
+#define ASC_PCI_DEVICEID_1200A            0x1100
+#define ASC_PCI_DEVICEID_1200B            0x1200
+#define ASC_PCI_DEVICEID_ULTRA            0x1300
+#define ASC_PCI_REVISION_3150             0x02
+#define ASC_PCI_REVISION_3050             0x03
+
+#define  ASC_DVCLIB_CALL_DONE     (1)
+#define  ASC_DVCLIB_CALL_FAILED   (0)
+#define  ASC_DVCLIB_CALL_ERROR    (-1)
+
+/*
+ * Enable CC_VERY_LONG_SG_LIST to support up to 64K element SG lists.
+ * The SRB structure will have to be changed and the ASC_SRB2SCSIQ()
+ * macro re-defined to be able to obtain a ASC_SCSI_Q pointer from the
+ * SRB structure.
+ */
+#define CC_VERY_LONG_SG_LIST 0
+#define ASC_SRB2SCSIQ(srb_ptr)  (srb_ptr)
+
+#define PortAddr                 unsigned short    /* port address size  */
+#define inp(port)                inb(port)
+#define outp(port, byte)         outb((byte), (port))
+
+#define inpw(port)               inw(port)
+#define outpw(port, word)        outw((word), (port))
+
+#define ASC_MAX_SG_QUEUE    7
+#define ASC_MAX_SG_LIST     255
+
+#define ASC_CS_TYPE  unsigned short
+
+#define ASC_IS_ISA          (0x0001)
+#define ASC_IS_ISAPNP       (0x0081)
+#define ASC_IS_EISA         (0x0002)
+#define ASC_IS_PCI          (0x0004)
+#define ASC_IS_PCI_ULTRA    (0x0104)
+#define ASC_IS_PCMCIA       (0x0008)
+#define ASC_IS_MCA          (0x0020)
+#define ASC_IS_VL           (0x0040)
+#define ASC_ISA_PNP_PORT_ADDR  (0x279)
+#define ASC_ISA_PNP_PORT_WRITE (ASC_ISA_PNP_PORT_ADDR+0x800)
+#define ASC_IS_WIDESCSI_16  (0x0100)
+#define ASC_IS_WIDESCSI_32  (0x0200)
+#define ASC_IS_BIG_ENDIAN   (0x8000)
+#define ASC_CHIP_MIN_VER_VL      (0x01)
+#define ASC_CHIP_MAX_VER_VL      (0x07)
+#define ASC_CHIP_MIN_VER_PCI     (0x09)
+#define ASC_CHIP_MAX_VER_PCI     (0x0F)
+#define ASC_CHIP_VER_PCI_BIT     (0x08)
+#define ASC_CHIP_MIN_VER_ISA     (0x11)
+#define ASC_CHIP_MIN_VER_ISA_PNP (0x21)
+#define ASC_CHIP_MAX_VER_ISA     (0x27)
+#define ASC_CHIP_VER_ISA_BIT     (0x30)
+#define ASC_CHIP_VER_ISAPNP_BIT  (0x20)
+#define ASC_CHIP_VER_ASYN_BUG    (0x21)
+#define ASC_CHIP_VER_PCI             0x08
+#define ASC_CHIP_VER_PCI_ULTRA_3150  (ASC_CHIP_VER_PCI | 0x02)
+#define ASC_CHIP_VER_PCI_ULTRA_3050  (ASC_CHIP_VER_PCI | 0x03)
+#define ASC_CHIP_MIN_VER_EISA (0x41)
+#define ASC_CHIP_MAX_VER_EISA (0x47)
+#define ASC_CHIP_VER_EISA_BIT (0x40)
+#define ASC_CHIP_LATEST_VER_EISA   ((ASC_CHIP_MIN_VER_EISA - 1) + 3)
+#define ASC_MAX_LIB_SUPPORTED_ISA_CHIP_VER   0x21
+#define ASC_MAX_LIB_SUPPORTED_PCI_CHIP_VER   0x0A
+#define ASC_MAX_VL_DMA_ADDR     (0x07FFFFFFL)
+#define ASC_MAX_VL_DMA_COUNT    (0x07FFFFFFL)
+#define ASC_MAX_PCI_DMA_ADDR    (0xFFFFFFFFL)
+#define ASC_MAX_PCI_DMA_COUNT   (0xFFFFFFFFL)
+#define ASC_MAX_ISA_DMA_ADDR    (0x00FFFFFFL)
+#define ASC_MAX_ISA_DMA_COUNT   (0x00FFFFFFL)
+#define ASC_MAX_EISA_DMA_ADDR   (0x07FFFFFFL)
+#define ASC_MAX_EISA_DMA_COUNT  (0x07FFFFFFL)
+
+#define ASC_SCSI_ID_BITS  3
+#define ASC_SCSI_TIX_TYPE     uchar
+#define ASC_ALL_DEVICE_BIT_SET  0xFF
+#define ASC_SCSI_BIT_ID_TYPE  uchar
+#define ASC_MAX_TID       7
+#define ASC_MAX_LUN       7
+#define ASC_SCSI_WIDTH_BIT_SET  0xFF
+#define ASC_MAX_SENSE_LEN   32
+#define ASC_MIN_SENSE_LEN   14
+#define ASC_MAX_CDB_LEN     12
+#define ASC_SCSI_RESET_HOLD_TIME_US  60
+
+#define ADV_INQ_CLOCKING_ST_ONLY    0x0
+#define ADV_INQ_CLOCKING_DT_ONLY    0x1
+#define ADV_INQ_CLOCKING_ST_AND_DT  0x3
+
+/*
+ * Inquiry SPC-2 SPI Byte 1 EVPD (Enable Vital Product Data)
+ * and CmdDt (Command Support Data) field bit definitions.
+ */
+#define ADV_INQ_RTN_VPD_AND_CMDDT           0x3
+#define ADV_INQ_RTN_CMDDT_FOR_OP_CODE       0x2
+#define ADV_INQ_RTN_VPD_FOR_PG_CODE         0x1
+#define ADV_INQ_RTN_STD_INQUIRY_DATA        0x0
+
+#define ASC_SCSIDIR_NOCHK    0x00
+#define ASC_SCSIDIR_T2H      0x08
+#define ASC_SCSIDIR_H2T      0x10
+#define ASC_SCSIDIR_NODATA   0x18
+#define SCSI_ASC_NOMEDIA          0x3A
+#define ASC_SRB_HOST(x)  ((uchar)((uchar)(x) >> 4))
+#define ASC_SRB_TID(x)   ((uchar)((uchar)(x) & (uchar)0x0F))
+#define ASC_SRB_LUN(x)   ((uchar)((uint)(x) >> 13))
+#define PUT_CDB1(x)   ((uchar)((uint)(x) >> 8))
+#define MS_CMD_DONE    0x00
+#define MS_EXTEND      0x01
+#define MS_SDTR_LEN    0x03
+#define MS_SDTR_CODE   0x01
+#define MS_WDTR_LEN    0x02
+#define MS_WDTR_CODE   0x03
+#define MS_MDP_LEN    0x05
+#define MS_MDP_CODE   0x00
+
+/*
+ * Inquiry data structure and bitfield macros
+ *
+ * Only quantities of more than 1 bit are shifted, since the others are
+ * just tested for true or false. C bitfields aren't portable between big
+ * and little-endian platforms so they are not used.
+ */
+
+#define ASC_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
+#define ASC_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
+#define ASC_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
+#define ASC_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
+#define ASC_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
+#define ASC_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
+#define ASC_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
+#define ASC_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
+#define ASC_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
+#define ASC_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
+#define ASC_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
+#define ASC_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
+#define ASC_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
+#define ASC_INQ_SYNC(inq)           ((inq)->flags & 0x10)
+#define ASC_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
+#define ASC_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
+#define ASC_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
+#define ASC_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
+#define ASC_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
+#define ASC_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
+
+typedef struct {
+    uchar               periph;
+    uchar               devtype;
+    uchar               ver;
+    uchar               byte3;
+    uchar               add_len;
+    uchar               res1;
+    uchar               res2;
+    uchar               flags;
+    uchar               vendor_id[8];
+    uchar               product_id[16];
+    uchar               product_rev_level[4];
+} ASC_SCSI_INQUIRY;
+
+#define ASC_SG_LIST_PER_Q   7
+#define QS_FREE        0x00
+#define QS_READY       0x01
+#define QS_DISC1       0x02
+#define QS_DISC2       0x04
+#define QS_BUSY        0x08
+#define QS_ABORTED     0x40
+#define QS_DONE        0x80
+#define QC_NO_CALLBACK   0x01
+#define QC_SG_SWAP_QUEUE 0x02
+#define QC_SG_HEAD       0x04
+#define QC_DATA_IN       0x08
+#define QC_DATA_OUT      0x10
+#define QC_URGENT        0x20
+#define QC_MSG_OUT       0x40
+#define QC_REQ_SENSE     0x80
+#define QCSG_SG_XFER_LIST  0x02
+#define QCSG_SG_XFER_MORE  0x04
+#define QCSG_SG_XFER_END   0x08
+#define QD_IN_PROGRESS       0x00
+#define QD_NO_ERROR          0x01
+#define QD_ABORTED_BY_HOST   0x02
+#define QD_WITH_ERROR        0x04
+#define QD_INVALID_REQUEST   0x80
+#define QD_INVALID_HOST_NUM  0x81
+#define QD_INVALID_DEVICE    0x82
+#define QD_ERR_INTERNAL      0xFF
+#define QHSTA_NO_ERROR               0x00
+#define QHSTA_M_SEL_TIMEOUT          0x11
+#define QHSTA_M_DATA_OVER_RUN        0x12
+#define QHSTA_M_DATA_UNDER_RUN       0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE  0x13
+#define QHSTA_M_BAD_BUS_PHASE_SEQ    0x14
+#define QHSTA_D_QDONE_SG_LIST_CORRUPTED 0x21
+#define QHSTA_D_ASC_DVC_ERROR_CODE_SET  0x22
+#define QHSTA_D_HOST_ABORT_FAILED       0x23
+#define QHSTA_D_EXE_SCSI_Q_FAILED       0x24
+#define QHSTA_D_EXE_SCSI_Q_BUSY_TIMEOUT 0x25
+#define QHSTA_D_ASPI_NO_BUF_POOL        0x26
+#define QHSTA_M_WTM_TIMEOUT         0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_TARGET_STATUS_BUSY  0x45
+#define QHSTA_M_BAD_TAG_CODE        0x46
+#define QHSTA_M_BAD_QUEUE_FULL_OR_BUSY  0x47
+#define QHSTA_M_HUNG_REQ_SCSI_BUS_RESET 0x48
+#define QHSTA_D_LRAM_CMP_ERROR        0x81
+#define QHSTA_M_MICRO_CODE_ERROR_HALT 0xA1
+#define ASC_FLAG_SCSIQ_REQ        0x01
+#define ASC_FLAG_BIOS_SCSIQ_REQ   0x02
+#define ASC_FLAG_BIOS_ASYNC_IO    0x04
+#define ASC_FLAG_SRB_LINEAR_ADDR  0x08
+#define ASC_FLAG_WIN16            0x10
+#define ASC_FLAG_WIN32            0x20
+#define ASC_FLAG_ISA_OVER_16MB    0x40
+#define ASC_FLAG_DOS_VM_CALLBACK  0x80
+#define ASC_TAG_FLAG_EXTRA_BYTES               0x10
+#define ASC_TAG_FLAG_DISABLE_DISCONNECT        0x04
+#define ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX  0x08
+#define ASC_TAG_FLAG_DISABLE_CHK_COND_INT_HOST 0x40
+#define ASC_SCSIQ_CPY_BEG              4
+#define ASC_SCSIQ_SGHD_CPY_BEG         2
+#define ASC_SCSIQ_B_FWD                0
+#define ASC_SCSIQ_B_BWD                1
+#define ASC_SCSIQ_B_STATUS             2
+#define ASC_SCSIQ_B_QNO                3
+#define ASC_SCSIQ_B_CNTL               4
+#define ASC_SCSIQ_B_SG_QUEUE_CNT       5
+#define ASC_SCSIQ_D_DATA_ADDR          8
+#define ASC_SCSIQ_D_DATA_CNT          12
+#define ASC_SCSIQ_B_SENSE_LEN         20
+#define ASC_SCSIQ_DONE_INFO_BEG       22
+#define ASC_SCSIQ_D_SRBPTR            22
+#define ASC_SCSIQ_B_TARGET_IX         26
+#define ASC_SCSIQ_B_CDB_LEN           28
+#define ASC_SCSIQ_B_TAG_CODE          29
+#define ASC_SCSIQ_W_VM_ID             30
+#define ASC_SCSIQ_DONE_STATUS         32
+#define ASC_SCSIQ_HOST_STATUS         33
+#define ASC_SCSIQ_SCSI_STATUS         34
+#define ASC_SCSIQ_CDB_BEG             36
+#define ASC_SCSIQ_DW_REMAIN_XFER_ADDR 56
+#define ASC_SCSIQ_DW_REMAIN_XFER_CNT  60
+#define ASC_SCSIQ_B_FIRST_SG_WK_QP    48
+#define ASC_SCSIQ_B_SG_WK_QP          49
+#define ASC_SCSIQ_B_SG_WK_IX          50
+#define ASC_SCSIQ_W_ALT_DC1           52
+#define ASC_SCSIQ_B_LIST_CNT          6
+#define ASC_SCSIQ_B_CUR_LIST_CNT      7
+#define ASC_SGQ_B_SG_CNTL             4
+#define ASC_SGQ_B_SG_HEAD_QP          5
+#define ASC_SGQ_B_SG_LIST_CNT         6
+#define ASC_SGQ_B_SG_CUR_LIST_CNT     7
+#define ASC_SGQ_LIST_BEG              8
+#define ASC_DEF_SCSI1_QNG    4
+#define ASC_MAX_SCSI1_QNG    4
+#define ASC_DEF_SCSI2_QNG    16
+#define ASC_MAX_SCSI2_QNG    32
+#define ASC_TAG_CODE_MASK    0x23
+#define ASC_STOP_REQ_RISC_STOP      0x01
+#define ASC_STOP_ACK_RISC_STOP      0x03
+#define ASC_STOP_CLEAN_UP_BUSY_Q    0x10
+#define ASC_STOP_CLEAN_UP_DISC_Q    0x20
+#define ASC_STOP_HOST_REQ_RISC_HALT 0x40
+#define ASC_TIDLUN_TO_IX(tid, lun)  (ASC_SCSI_TIX_TYPE)((tid) + ((lun)<<ASC_SCSI_ID_BITS))
+#define ASC_TID_TO_TARGET_ID(tid)   (ASC_SCSI_BIT_ID_TYPE)(0x01 << (tid))
+#define ASC_TIX_TO_TARGET_ID(tix)   (0x01 << ((tix) & ASC_MAX_TID))
+#define ASC_TIX_TO_TID(tix)         ((tix) & ASC_MAX_TID)
+#define ASC_TID_TO_TIX(tid)         ((tid) & ASC_MAX_TID)
+#define ASC_TIX_TO_LUN(tix)         (((tix) >> ASC_SCSI_ID_BITS) & ASC_MAX_LUN)
+#define ASC_QNO_TO_QADDR(q_no)      ((ASC_QADR_BEG)+((int)(q_no) << 6))
+
+typedef struct asc_scsiq_1 {
+    uchar               status;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sg_queue_cnt;
+    uchar               target_id;
+    uchar               target_lun;
+    ASC_PADDR           data_addr;
+    ASC_DCNT            data_cnt;
+    ASC_PADDR           sense_addr;
+    uchar               sense_len;
+    uchar               extra_bytes;
+} ASC_SCSIQ_1;
+
+typedef struct asc_scsiq_2 {
+    ASC_VADDR           srb_ptr;
+    uchar               target_ix;
+    uchar               flag;
+    uchar               cdb_len;
+    uchar               tag_code;
+    ushort              vm_id;
+} ASC_SCSIQ_2;
+
+typedef struct asc_scsiq_3 {
+    uchar               done_stat;
+    uchar               host_stat;
+    uchar               scsi_stat;
+    uchar               scsi_msg;
+} ASC_SCSIQ_3;
+
+typedef struct asc_scsiq_4 {
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               y_first_sg_list_qp;
+    uchar               y_working_sg_qp;
+    uchar               y_working_sg_ix;
+    uchar               y_res;
+    ushort              x_req_count;
+    ushort              x_reconnect_rtn;
+    ASC_PADDR           x_saved_data_addr;
+    ASC_DCNT            x_saved_data_cnt;
+} ASC_SCSIQ_4;
+
+typedef struct asc_q_done_info {
+    ASC_SCSIQ_2         d2;
+    ASC_SCSIQ_3         d3;
+    uchar               q_status;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sense_len;
+    uchar               extra_bytes;
+    uchar               res;
+    ASC_DCNT            remain_bytes;
+} ASC_QDONE_INFO;
+
+typedef struct asc_sg_list {
+    ASC_PADDR           addr;
+    ASC_DCNT            bytes;
+} ASC_SG_LIST;
+
+typedef struct asc_sg_head {
+    ushort              entry_cnt;
+    ushort              queue_cnt;
+    ushort              entry_to_copy;
+    ushort              res;
+    ASC_SG_LIST         sg_list[ASC_MAX_SG_LIST];
+} ASC_SG_HEAD;
+
+#define ASC_MIN_SG_LIST   2
+
+typedef struct asc_min_sg_head {
+    ushort              entry_cnt;
+    ushort              queue_cnt;
+    ushort              entry_to_copy;
+    ushort              res;
+    ASC_SG_LIST         sg_list[ASC_MIN_SG_LIST];
+} ASC_MIN_SG_HEAD;
+
+#define QCX_SORT        (0x0001)
+#define QCX_COALEASE    (0x0002)
+
+typedef struct asc_scsi_q {
+    ASC_SCSIQ_1         q1;
+    ASC_SCSIQ_2         q2;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
+    ushort              remain_sg_entry_cnt;
+    ushort              next_sg_index;
+} ASC_SCSI_Q;
+
+typedef struct asc_scsi_req_q {
+    ASC_SCSIQ_1         r1;
+    ASC_SCSIQ_2         r2;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
+    uchar               *sense_ptr;
+    ASC_SCSIQ_3         r3;
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               sense[ASC_MIN_SENSE_LEN];
+} ASC_SCSI_REQ_Q;
+
+typedef struct asc_scsi_bios_req_q {
+    ASC_SCSIQ_1         r1;
+    ASC_SCSIQ_2         r2;
+    uchar               *cdbptr;
+    ASC_SG_HEAD         *sg_head;
+    uchar               *sense_ptr;
+    ASC_SCSIQ_3         r3;
+    uchar               cdb[ASC_MAX_CDB_LEN];
+    uchar               sense[ASC_MIN_SENSE_LEN];
+} ASC_SCSI_BIOS_REQ_Q;
+
+typedef struct asc_risc_q {
+    uchar               fwd;
+    uchar               bwd;
+    ASC_SCSIQ_1         i1;
+    ASC_SCSIQ_2         i2;
+    ASC_SCSIQ_3         i3;
+    ASC_SCSIQ_4         i4;
+} ASC_RISC_Q;
+
+typedef struct asc_sg_list_q {
+    uchar               seq_no;
+    uchar               q_no;
+    uchar               cntl;
+    uchar               sg_head_qp;
+    uchar               sg_list_cnt;
+    uchar               sg_cur_list_cnt;
+} ASC_SG_LIST_Q;
+
+typedef struct asc_risc_sg_list_q {
+    uchar               fwd;
+    uchar               bwd;
+    ASC_SG_LIST_Q       sg;
+    ASC_SG_LIST         sg_list[7];
+} ASC_RISC_SG_LIST_Q;
+
+#define ASC_EXE_SCSI_IO_MAX_IDLE_LOOP  0x1000000UL
+#define ASC_EXE_SCSI_IO_MAX_WAIT_LOOP  1024
+#define ASCQ_ERR_NO_ERROR             0
+#define ASCQ_ERR_IO_NOT_FOUND         1
+#define ASCQ_ERR_LOCAL_MEM            2
+#define ASCQ_ERR_CHKSUM               3
+#define ASCQ_ERR_START_CHIP           4
+#define ASCQ_ERR_INT_TARGET_ID        5
+#define ASCQ_ERR_INT_LOCAL_MEM        6
+#define ASCQ_ERR_HALT_RISC            7
+#define ASCQ_ERR_GET_ASPI_ENTRY       8
+#define ASCQ_ERR_CLOSE_ASPI           9
+#define ASCQ_ERR_HOST_INQUIRY         0x0A
+#define ASCQ_ERR_SAVED_SRB_BAD        0x0B
+#define ASCQ_ERR_QCNTL_SG_LIST        0x0C
+#define ASCQ_ERR_Q_STATUS             0x0D
+#define ASCQ_ERR_WR_SCSIQ             0x0E
+#define ASCQ_ERR_PC_ADDR              0x0F
+#define ASCQ_ERR_SYN_OFFSET           0x10
+#define ASCQ_ERR_SYN_XFER_TIME        0x11
+#define ASCQ_ERR_LOCK_DMA             0x12
+#define ASCQ_ERR_UNLOCK_DMA           0x13
+#define ASCQ_ERR_VDS_CHK_INSTALL      0x14
+#define ASCQ_ERR_MICRO_CODE_HALT      0x15
+#define ASCQ_ERR_SET_LRAM_ADDR        0x16
+#define ASCQ_ERR_CUR_QNG              0x17
+#define ASCQ_ERR_SG_Q_LINKS           0x18
+#define ASCQ_ERR_SCSIQ_PTR            0x19
+#define ASCQ_ERR_ISR_RE_ENTRY         0x1A
+#define ASCQ_ERR_CRITICAL_RE_ENTRY    0x1B
+#define ASCQ_ERR_ISR_ON_CRITICAL      0x1C
+#define ASCQ_ERR_SG_LIST_ODD_ADDRESS  0x1D
+#define ASCQ_ERR_XFER_ADDRESS_TOO_BIG 0x1E
+#define ASCQ_ERR_SCSIQ_NULL_PTR       0x1F
+#define ASCQ_ERR_SCSIQ_BAD_NEXT_PTR   0x20
+#define ASCQ_ERR_GET_NUM_OF_FREE_Q    0x21
+#define ASCQ_ERR_SEND_SCSI_Q          0x22
+#define ASCQ_ERR_HOST_REQ_RISC_HALT   0x23
+#define ASCQ_ERR_RESET_SDTR           0x24
+
+/*
+ * Warning code values are set in ASC_DVC_VAR  'warn_code'.
+ */
+#define ASC_WARN_NO_ERROR             0x0000
+#define ASC_WARN_IO_PORT_ROTATE       0x0001
+#define ASC_WARN_EEPROM_CHKSUM        0x0002
+#define ASC_WARN_IRQ_MODIFIED         0x0004
+#define ASC_WARN_AUTO_CONFIG          0x0008
+#define ASC_WARN_CMD_QNG_CONFLICT     0x0010
+#define ASC_WARN_EEPROM_RECOVER       0x0020
+#define ASC_WARN_CFG_MSW_RECOVER      0x0040
+#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080
+
+/*
+ * Error code values are set in ASC_DVC_VAR  'err_code'.
+ */
+#define ASC_IERR_WRITE_EEPROM         0x0001
+#define ASC_IERR_MCODE_CHKSUM         0x0002
+#define ASC_IERR_SET_PC_ADDR          0x0004
+#define ASC_IERR_START_STOP_CHIP      0x0008
+#define ASC_IERR_IRQ_NO               0x0010
+#define ASC_IERR_SET_IRQ_NO           0x0020
+#define ASC_IERR_CHIP_VERSION         0x0040
+#define ASC_IERR_SET_SCSI_ID          0x0080
+#define ASC_IERR_GET_PHY_ADDR         0x0100
+#define ASC_IERR_BAD_SIGNATURE        0x0200
+#define ASC_IERR_NO_BUS_TYPE          0x0400
+#define ASC_IERR_SCAM                 0x0800
+#define ASC_IERR_SET_SDTR             0x1000
+#define ASC_IERR_RW_LRAM              0x8000
+
+#define ASC_DEF_IRQ_NO  10
+#define ASC_MAX_IRQ_NO  15
+#define ASC_MIN_IRQ_NO  10
+#define ASC_MIN_REMAIN_Q        (0x02)
+#define ASC_DEF_MAX_TOTAL_QNG   (0xF0)
+#define ASC_MIN_TAG_Q_PER_DVC   (0x04)
+#define ASC_DEF_TAG_Q_PER_DVC   (0x04)
+#define ASC_MIN_FREE_Q        ASC_MIN_REMAIN_Q
+#define ASC_MIN_TOTAL_QNG     ((ASC_MAX_SG_QUEUE)+(ASC_MIN_FREE_Q))
+#define ASC_MAX_TOTAL_QNG 240
+#define ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG 16
+#define ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG   8
+#define ASC_MAX_PCI_INRAM_TOTAL_QNG  20
+#define ASC_MAX_INRAM_TAG_QNG   16
+#define ASC_IOADR_TABLE_MAX_IX  11
+#define ASC_IOADR_GAP   0x10
+#define ASC_SEARCH_IOP_GAP 0x10
+#define ASC_MIN_IOP_ADDR   (PortAddr)0x0100
+#define ASC_MAX_IOP_ADDR   (PortAddr)0x3F0
+#define ASC_IOADR_1     (PortAddr)0x0110
+#define ASC_IOADR_2     (PortAddr)0x0130
+#define ASC_IOADR_3     (PortAddr)0x0150
+#define ASC_IOADR_4     (PortAddr)0x0190
+#define ASC_IOADR_5     (PortAddr)0x0210
+#define ASC_IOADR_6     (PortAddr)0x0230
+#define ASC_IOADR_7     (PortAddr)0x0250
+#define ASC_IOADR_8     (PortAddr)0x0330
+#define ASC_IOADR_DEF   ASC_IOADR_8
+#define ASC_LIB_SCSIQ_WK_SP        256
+#define ASC_MAX_SYN_XFER_NO        16
+#define ASC_SYN_MAX_OFFSET         0x0F
+#define ASC_DEF_SDTR_OFFSET        0x0F
+#define ASC_DEF_SDTR_INDEX         0x00
+#define ASC_SDTR_ULTRA_PCI_10MB_INDEX  0x02
+#define SYN_XFER_NS_0  25
+#define SYN_XFER_NS_1  30
+#define SYN_XFER_NS_2  35
+#define SYN_XFER_NS_3  40
+#define SYN_XFER_NS_4  50
+#define SYN_XFER_NS_5  60
+#define SYN_XFER_NS_6  70
+#define SYN_XFER_NS_7  85
+#define SYN_ULTRA_XFER_NS_0    12
+#define SYN_ULTRA_XFER_NS_1    19
+#define SYN_ULTRA_XFER_NS_2    25
+#define SYN_ULTRA_XFER_NS_3    32
+#define SYN_ULTRA_XFER_NS_4    38
+#define SYN_ULTRA_XFER_NS_5    44
+#define SYN_ULTRA_XFER_NS_6    50
+#define SYN_ULTRA_XFER_NS_7    57
+#define SYN_ULTRA_XFER_NS_8    63
+#define SYN_ULTRA_XFER_NS_9    69
+#define SYN_ULTRA_XFER_NS_10   75
+#define SYN_ULTRA_XFER_NS_11   82
+#define SYN_ULTRA_XFER_NS_12   88
+#define SYN_ULTRA_XFER_NS_13   94
+#define SYN_ULTRA_XFER_NS_14  100
+#define SYN_ULTRA_XFER_NS_15  107
+
+typedef struct ext_msg {
+    uchar               msg_type;
+    uchar               msg_len;
+    uchar               msg_req;
+    union {
+        struct {
+            uchar               sdtr_xfer_period;
+            uchar               sdtr_req_ack_offset;
+        } sdtr;
+        struct {
+            uchar               wdtr_width;
+        } wdtr;
+        struct {
+            uchar               mdp_b3;
+            uchar               mdp_b2;
+            uchar               mdp_b1;
+            uchar               mdp_b0;
+        } mdp;
+    } u_ext_msg;
+    uchar               res;
+} EXT_MSG;
+
+#define xfer_period     u_ext_msg.sdtr.sdtr_xfer_period
+#define req_ack_offset  u_ext_msg.sdtr.sdtr_req_ack_offset
+#define wdtr_width      u_ext_msg.wdtr.wdtr_width
+#define mdp_b3          u_ext_msg.mdp_b3
+#define mdp_b2          u_ext_msg.mdp_b2
+#define mdp_b1          u_ext_msg.mdp_b1
+#define mdp_b0          u_ext_msg.mdp_b0
+
+typedef struct asc_dvc_cfg {
+    ASC_SCSI_BIT_ID_TYPE can_tagged_qng;
+    ASC_SCSI_BIT_ID_TYPE cmd_qng_enabled;
+    ASC_SCSI_BIT_ID_TYPE disc_enable;
+    ASC_SCSI_BIT_ID_TYPE sdtr_enable;
+    uchar               chip_scsi_id;
+    uchar               isa_dma_speed;
+    uchar               isa_dma_channel;
+    uchar               chip_version;
+    ushort              lib_serial_no;
+    ushort              lib_version;
+    ushort              mcode_date;
+    ushort              mcode_version;
+    uchar               max_tag_qng[ASC_MAX_TID + 1];
+    uchar               *overrun_buf;
+    uchar               sdtr_period_offset[ASC_MAX_TID + 1];
+    ushort              pci_slot_info;
+    uchar               adapter_info[6];
+    struct device	*dev;
+} ASC_DVC_CFG;
+
+#define ASC_DEF_DVC_CNTL       0xFFFF
+#define ASC_DEF_CHIP_SCSI_ID   7
+#define ASC_DEF_ISA_DMA_SPEED  4
+#define ASC_INIT_STATE_NULL          0x0000
+#define ASC_INIT_STATE_BEG_GET_CFG   0x0001
+#define ASC_INIT_STATE_END_GET_CFG   0x0002
+#define ASC_INIT_STATE_BEG_SET_CFG   0x0004
+#define ASC_INIT_STATE_END_SET_CFG   0x0008
+#define ASC_INIT_STATE_BEG_LOAD_MC   0x0010
+#define ASC_INIT_STATE_END_LOAD_MC   0x0020
+#define ASC_INIT_STATE_BEG_INQUIRY   0x0040
+#define ASC_INIT_STATE_END_INQUIRY   0x0080
+#define ASC_INIT_RESET_SCSI_DONE     0x0100
+#define ASC_INIT_STATE_WITHOUT_EEP   0x8000
+#define ASC_PCI_DEVICE_ID_REV_A      0x1100
+#define ASC_PCI_DEVICE_ID_REV_B      0x1200
+#define ASC_BUG_FIX_IF_NOT_DWB       0x0001
+#define ASC_BUG_FIX_ASYN_USE_SYN     0x0002
+#define ASYN_SDTR_DATA_FIX_PCI_REV_AB 0x41
+#define ASC_MIN_TAGGED_CMD  7
+#define ASC_MAX_SCSI_RESET_WAIT      30
+
+struct asc_dvc_var;     /* Forward Declaration. */
+
+typedef void (* ASC_ISR_CALLBACK)(struct asc_dvc_var *, ASC_QDONE_INFO *);
+typedef int (* ASC_EXE_CALLBACK)(struct asc_dvc_var *, ASC_SCSI_Q *);
+
+typedef struct asc_dvc_var {
+    PortAddr            iop_base;
+    ushort              err_code;
+    ushort              dvc_cntl;
+    ushort              bug_fix_cntl;
+    ushort              bus_type;
+    ASC_ISR_CALLBACK    isr_callback;
+    ASC_EXE_CALLBACK    exe_callback;
+    ASC_SCSI_BIT_ID_TYPE init_sdtr;
+    ASC_SCSI_BIT_ID_TYPE sdtr_done;
+    ASC_SCSI_BIT_ID_TYPE use_tagged_qng;
+    ASC_SCSI_BIT_ID_TYPE unit_not_ready;
+    ASC_SCSI_BIT_ID_TYPE queue_full_or_busy;
+    ASC_SCSI_BIT_ID_TYPE start_motor;
+    uchar               scsi_reset_wait;
+    uchar               chip_no;
+    char                is_in_int;
+    uchar               max_total_qng;
+    uchar               cur_total_qng;
+    uchar               in_critical_cnt;
+    uchar               irq_no;
+    uchar               last_q_shortage;
+    ushort              init_state;
+    uchar               cur_dvc_qng[ASC_MAX_TID + 1];
+    uchar               max_dvc_qng[ASC_MAX_TID + 1];
+    ASC_SCSI_Q  *scsiq_busy_head[ASC_MAX_TID + 1];
+    ASC_SCSI_Q  *scsiq_busy_tail[ASC_MAX_TID + 1];
+    uchar               sdtr_period_tbl[ASC_MAX_SYN_XFER_NO];
+    ASC_DVC_CFG *cfg;
+    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer_always;
+    char                redo_scam;
+    ushort              res2;
+    uchar               dos_int13_table[ASC_MAX_TID + 1];
+    ASC_DCNT            max_dma_count;
+    ASC_SCSI_BIT_ID_TYPE no_scam;
+    ASC_SCSI_BIT_ID_TYPE pci_fix_asyn_xfer;
+    uchar               max_sdtr_index;
+    uchar               host_init_sdtr_index;
+    struct asc_board    *drv_ptr;
+    ASC_DCNT            uc_break;
+} ASC_DVC_VAR;
+
+typedef struct asc_dvc_inq_info {
+    uchar               type[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+} ASC_DVC_INQ_INFO;
+
+typedef struct asc_cap_info {
+    ASC_DCNT            lba;
+    ASC_DCNT            blk_size;
+} ASC_CAP_INFO;
+
+typedef struct asc_cap_info_array {
+    ASC_CAP_INFO        cap_info[ASC_MAX_TID + 1][ASC_MAX_LUN + 1];
+} ASC_CAP_INFO_ARRAY;
+
+#define ASC_MCNTL_NO_SEL_TIMEOUT  (ushort)0x0001
+#define ASC_MCNTL_NULL_TARGET     (ushort)0x0002
+#define ASC_CNTL_INITIATOR         (ushort)0x0001
+#define ASC_CNTL_BIOS_GT_1GB       (ushort)0x0002
+#define ASC_CNTL_BIOS_GT_2_DISK    (ushort)0x0004
+#define ASC_CNTL_BIOS_REMOVABLE    (ushort)0x0008
+#define ASC_CNTL_NO_SCAM           (ushort)0x0010
+#define ASC_CNTL_INT_MULTI_Q       (ushort)0x0080
+#define ASC_CNTL_NO_LUN_SUPPORT    (ushort)0x0040
+#define ASC_CNTL_NO_VERIFY_COPY    (ushort)0x0100
+#define ASC_CNTL_RESET_SCSI        (ushort)0x0200
+#define ASC_CNTL_INIT_INQUIRY      (ushort)0x0400
+#define ASC_CNTL_INIT_VERBOSE      (ushort)0x0800
+#define ASC_CNTL_SCSI_PARITY       (ushort)0x1000
+#define ASC_CNTL_BURST_MODE        (ushort)0x2000
+#define ASC_CNTL_SDTR_ENABLE_ULTRA (ushort)0x4000
+#define ASC_EEP_DVC_CFG_BEG_VL    2
+#define ASC_EEP_MAX_DVC_ADDR_VL   15
+#define ASC_EEP_DVC_CFG_BEG      32
+#define ASC_EEP_MAX_DVC_ADDR     45
+#define ASC_EEP_DEFINED_WORDS    10
+#define ASC_EEP_MAX_ADDR         63
+#define ASC_EEP_RES_WORDS         0
+#define ASC_EEP_MAX_RETRY        20
+#define ASC_MAX_INIT_BUSY_RETRY   8
+#define ASC_EEP_ISA_PNP_WSIZE    16
+
+/*
+ * These macros keep the chip SCSI id and ISA DMA speed
+ * bitfields in board order. C bitfields aren't portable
+ * between big and little-endian platforms so they are
+ * not used.
+ */
+
+#define ASC_EEP_GET_CHIP_ID(cfg)    ((cfg)->id_speed & 0x0f)
+#define ASC_EEP_GET_DMA_SPD(cfg)    (((cfg)->id_speed & 0xf0) >> 4)
+#define ASC_EEP_SET_CHIP_ID(cfg, sid) \
+   ((cfg)->id_speed = ((cfg)->id_speed & 0xf0) | ((sid) & ASC_MAX_TID))
+#define ASC_EEP_SET_DMA_SPD(cfg, spd) \
+   ((cfg)->id_speed = ((cfg)->id_speed & 0x0f) | ((spd) & 0x0f) << 4)
+
+typedef struct asceep_config {
+    ushort              cfg_lsw;
+    ushort              cfg_msw;
+    uchar               init_sdtr;
+    uchar               disc_enable;
+    uchar               use_cmd_qng;
+    uchar               start_motor;
+    uchar               max_total_qng;
+    uchar               max_tag_qng;
+    uchar               bios_scan;
+    uchar               power_up_wait;
+    uchar               no_scam;
+    uchar               id_speed; /* low order 4 bits is chip scsi id */
+                                  /* high order 4 bits is isa dma speed */
+    uchar               dos_int13_table[ASC_MAX_TID + 1];
+    uchar               adapter_info[6];
+    ushort              cntl;
+    ushort              chksum;
+} ASCEEP_CONFIG;
+
+#define ASC_PCI_CFG_LSW_SCSI_PARITY  0x0800
+#define ASC_PCI_CFG_LSW_BURST_MODE   0x0080
+#define ASC_PCI_CFG_LSW_INTR_ABLE    0x0020
+
+#define ASC_EEP_CMD_READ          0x80
+#define ASC_EEP_CMD_WRITE         0x40
+#define ASC_EEP_CMD_WRITE_ABLE    0x30
+#define ASC_EEP_CMD_WRITE_DISABLE 0x00
+#define ASC_OVERRUN_BSIZE  0x00000048UL
+#define ASC_CTRL_BREAK_ONCE        0x0001
+#define ASC_CTRL_BREAK_STAY_IDLE   0x0002
+#define ASCV_MSGOUT_BEG         0x0000
+#define ASCV_MSGOUT_SDTR_PERIOD (ASCV_MSGOUT_BEG+3)
+#define ASCV_MSGOUT_SDTR_OFFSET (ASCV_MSGOUT_BEG+4)
+#define ASCV_BREAK_SAVED_CODE   (ushort)0x0006
+#define ASCV_MSGIN_BEG          (ASCV_MSGOUT_BEG+8)
+#define ASCV_MSGIN_SDTR_PERIOD  (ASCV_MSGIN_BEG+3)
+#define ASCV_MSGIN_SDTR_OFFSET  (ASCV_MSGIN_BEG+4)
+#define ASCV_SDTR_DATA_BEG      (ASCV_MSGIN_BEG+8)
+#define ASCV_SDTR_DONE_BEG      (ASCV_SDTR_DATA_BEG+8)
+#define ASCV_MAX_DVC_QNG_BEG    (ushort)0x0020
+#define ASCV_BREAK_ADDR           (ushort)0x0028
+#define ASCV_BREAK_NOTIFY_COUNT   (ushort)0x002A
+#define ASCV_BREAK_CONTROL        (ushort)0x002C
+#define ASCV_BREAK_HIT_COUNT      (ushort)0x002E
+
+#define ASCV_ASCDVC_ERR_CODE_W  (ushort)0x0030
+#define ASCV_MCODE_CHKSUM_W   (ushort)0x0032
+#define ASCV_MCODE_SIZE_W     (ushort)0x0034
+#define ASCV_STOP_CODE_B      (ushort)0x0036
+#define ASCV_DVC_ERR_CODE_B   (ushort)0x0037
+#define ASCV_OVERRUN_PADDR_D  (ushort)0x0038
+#define ASCV_OVERRUN_BSIZE_D  (ushort)0x003C
+#define ASCV_HALTCODE_W       (ushort)0x0040
+#define ASCV_CHKSUM_W         (ushort)0x0042
+#define ASCV_MC_DATE_W        (ushort)0x0044
+#define ASCV_MC_VER_W         (ushort)0x0046
+#define ASCV_NEXTRDY_B        (ushort)0x0048
+#define ASCV_DONENEXT_B       (ushort)0x0049
+#define ASCV_USE_TAGGED_QNG_B (ushort)0x004A
+#define ASCV_SCSIBUSY_B       (ushort)0x004B
+#define ASCV_Q_DONE_IN_PROGRESS_B  (ushort)0x004C
+#define ASCV_CURCDB_B         (ushort)0x004D
+#define ASCV_RCLUN_B          (ushort)0x004E
+#define ASCV_BUSY_QHEAD_B     (ushort)0x004F
+#define ASCV_DISC1_QHEAD_B    (ushort)0x0050
+#define ASCV_DISC_ENABLE_B    (ushort)0x0052
+#define ASCV_CAN_TAGGED_QNG_B (ushort)0x0053
+#define ASCV_HOSTSCSI_ID_B    (ushort)0x0055
+#define ASCV_MCODE_CNTL_B     (ushort)0x0056
+#define ASCV_NULL_TARGET_B    (ushort)0x0057
+#define ASCV_FREE_Q_HEAD_W    (ushort)0x0058
+#define ASCV_DONE_Q_TAIL_W    (ushort)0x005A
+#define ASCV_FREE_Q_HEAD_B    (ushort)(ASCV_FREE_Q_HEAD_W+1)
+#define ASCV_DONE_Q_TAIL_B    (ushort)(ASCV_DONE_Q_TAIL_W+1)
+#define ASCV_HOST_FLAG_B      (ushort)0x005D
+#define ASCV_TOTAL_READY_Q_B  (ushort)0x0064
+#define ASCV_VER_SERIAL_B     (ushort)0x0065
+#define ASCV_HALTCODE_SAVED_W (ushort)0x0066
+#define ASCV_WTM_FLAG_B       (ushort)0x0068
+#define ASCV_RISC_FLAG_B      (ushort)0x006A
+#define ASCV_REQ_SG_LIST_QP   (ushort)0x006B
+#define ASC_HOST_FLAG_IN_ISR        0x01
+#define ASC_HOST_FLAG_ACK_INT       0x02
+#define ASC_RISC_FLAG_GEN_INT      0x01
+#define ASC_RISC_FLAG_REQ_SG_LIST  0x02
+#define IOP_CTRL         (0x0F)
+#define IOP_STATUS       (0x0E)
+#define IOP_INT_ACK      IOP_STATUS
+#define IOP_REG_IFC      (0x0D)
+#define IOP_SYN_OFFSET    (0x0B)
+#define IOP_EXTRA_CONTROL (0x0D)
+#define IOP_REG_PC        (0x0C)
+#define IOP_RAM_ADDR      (0x0A)
+#define IOP_RAM_DATA      (0x08)
+#define IOP_EEP_DATA      (0x06)
+#define IOP_EEP_CMD       (0x07)
+#define IOP_VERSION       (0x03)
+#define IOP_CONFIG_HIGH   (0x04)
+#define IOP_CONFIG_LOW    (0x02)
+#define IOP_SIG_BYTE      (0x01)
+#define IOP_SIG_WORD      (0x00)
+#define IOP_REG_DC1      (0x0E)
+#define IOP_REG_DC0      (0x0C)
+#define IOP_REG_SB       (0x0B)
+#define IOP_REG_DA1      (0x0A)
+#define IOP_REG_DA0      (0x08)
+#define IOP_REG_SC       (0x09)
+#define IOP_DMA_SPEED    (0x07)
+#define IOP_REG_FLAG     (0x07)
+#define IOP_FIFO_H       (0x06)
+#define IOP_FIFO_L       (0x04)
+#define IOP_REG_ID       (0x05)
+#define IOP_REG_QP       (0x03)
+#define IOP_REG_IH       (0x02)
+#define IOP_REG_IX       (0x01)
+#define IOP_REG_AX       (0x00)
+#define IFC_REG_LOCK      (0x00)
+#define IFC_REG_UNLOCK    (0x09)
+#define IFC_WR_EN_FILTER  (0x10)
+#define IFC_RD_NO_EEPROM  (0x10)
+#define IFC_SLEW_RATE     (0x20)
+#define IFC_ACT_NEG       (0x40)
+#define IFC_INP_FILTER    (0x80)
+#define IFC_INIT_DEFAULT  (IFC_ACT_NEG | IFC_REG_UNLOCK)
+#define SC_SEL   (uchar)(0x80)
+#define SC_BSY   (uchar)(0x40)
+#define SC_ACK   (uchar)(0x20)
+#define SC_REQ   (uchar)(0x10)
+#define SC_ATN   (uchar)(0x08)
+#define SC_IO    (uchar)(0x04)
+#define SC_CD    (uchar)(0x02)
+#define SC_MSG   (uchar)(0x01)
+#define SEC_SCSI_CTL         (uchar)(0x80)
+#define SEC_ACTIVE_NEGATE    (uchar)(0x40)
+#define SEC_SLEW_RATE        (uchar)(0x20)
+#define SEC_ENABLE_FILTER    (uchar)(0x10)
+#define ASC_HALT_EXTMSG_IN     (ushort)0x8000
+#define ASC_HALT_CHK_CONDITION (ushort)0x8100
+#define ASC_HALT_SS_QUEUE_FULL (ushort)0x8200
+#define ASC_HALT_DISABLE_ASYN_USE_SYN_FIX  (ushort)0x8300
+#define ASC_HALT_ENABLE_ASYN_USE_SYN_FIX   (ushort)0x8400
+#define ASC_HALT_SDTR_REJECTED (ushort)0x4000
+#define ASC_HALT_HOST_COPY_SG_LIST_TO_RISC ( ushort )0x2000
+#define ASC_MAX_QNO        0xF8
+#define ASC_DATA_SEC_BEG   (ushort)0x0080
+#define ASC_DATA_SEC_END   (ushort)0x0080
+#define ASC_CODE_SEC_BEG   (ushort)0x0080
+#define ASC_CODE_SEC_END   (ushort)0x0080
+#define ASC_QADR_BEG       (0x4000)
+#define ASC_QADR_USED      (ushort)(ASC_MAX_QNO * 64)
+#define ASC_QADR_END       (ushort)0x7FFF
+#define ASC_QLAST_ADR      (ushort)0x7FC0
+#define ASC_QBLK_SIZE      0x40
+#define ASC_BIOS_DATA_QBEG 0xF8
+#define ASC_MIN_ACTIVE_QNO 0x01
+#define ASC_QLINK_END      0xFF
+#define ASC_EEPROM_WORDS   0x10
+#define ASC_MAX_MGS_LEN    0x10
+#define ASC_BIOS_ADDR_DEF  0xDC00
+#define ASC_BIOS_SIZE      0x3800
+#define ASC_BIOS_RAM_OFF   0x3800
+#define ASC_BIOS_RAM_SIZE  0x800
+#define ASC_BIOS_MIN_ADDR  0xC000
+#define ASC_BIOS_MAX_ADDR  0xEC00
+#define ASC_BIOS_BANK_SIZE 0x0400
+#define ASC_MCODE_START_ADDR  0x0080
+#define ASC_CFG0_HOST_INT_ON    0x0020
+#define ASC_CFG0_BIOS_ON        0x0040
+#define ASC_CFG0_VERA_BURST_ON  0x0080
+#define ASC_CFG0_SCSI_PARITY_ON 0x0800
+#define ASC_CFG1_SCSI_TARGET_ON 0x0080
+#define ASC_CFG1_LRAM_8BITS_ON  0x0800
+#define ASC_CFG_MSW_CLR_MASK    0x3080
+#define CSW_TEST1             (ASC_CS_TYPE)0x8000
+#define CSW_AUTO_CONFIG       (ASC_CS_TYPE)0x4000
+#define CSW_RESERVED1         (ASC_CS_TYPE)0x2000
+#define CSW_IRQ_WRITTEN       (ASC_CS_TYPE)0x1000
+#define CSW_33MHZ_SELECTED    (ASC_CS_TYPE)0x0800
+#define CSW_TEST2             (ASC_CS_TYPE)0x0400
+#define CSW_TEST3             (ASC_CS_TYPE)0x0200
+#define CSW_RESERVED2         (ASC_CS_TYPE)0x0100
+#define CSW_DMA_DONE          (ASC_CS_TYPE)0x0080
+#define CSW_FIFO_RDY          (ASC_CS_TYPE)0x0040
+#define CSW_EEP_READ_DONE     (ASC_CS_TYPE)0x0020
+#define CSW_HALTED            (ASC_CS_TYPE)0x0010
+#define CSW_SCSI_RESET_ACTIVE (ASC_CS_TYPE)0x0008
+#define CSW_PARITY_ERR        (ASC_CS_TYPE)0x0004
+#define CSW_SCSI_RESET_LATCH  (ASC_CS_TYPE)0x0002
+#define CSW_INT_PENDING       (ASC_CS_TYPE)0x0001
+#define CIW_CLR_SCSI_RESET_INT (ASC_CS_TYPE)0x1000
+#define CIW_INT_ACK      (ASC_CS_TYPE)0x0100
+#define CIW_TEST1        (ASC_CS_TYPE)0x0200
+#define CIW_TEST2        (ASC_CS_TYPE)0x0400
+#define CIW_SEL_33MHZ    (ASC_CS_TYPE)0x0800
+#define CIW_IRQ_ACT      (ASC_CS_TYPE)0x1000
+#define CC_CHIP_RESET   (uchar)0x80
+#define CC_SCSI_RESET   (uchar)0x40
+#define CC_HALT         (uchar)0x20
+#define CC_SINGLE_STEP  (uchar)0x10
+#define CC_DMA_ABLE     (uchar)0x08
+#define CC_TEST         (uchar)0x04
+#define CC_BANK_ONE     (uchar)0x02
+#define CC_DIAG         (uchar)0x01
+#define ASC_1000_ID0W      0x04C1
+#define ASC_1000_ID0W_FIX  0x00C1
+#define ASC_1000_ID1B      0x25
+#define ASC_EISA_BIG_IOP_GAP   (0x1C30-0x0C50)
+#define ASC_EISA_SMALL_IOP_GAP (0x0020)
+#define ASC_EISA_MIN_IOP_ADDR  (0x0C30)
+#define ASC_EISA_MAX_IOP_ADDR  (0xFC50)
+#define ASC_EISA_REV_IOP_MASK  (0x0C83)
+#define ASC_EISA_PID_IOP_MASK  (0x0C80)
+#define ASC_EISA_CFG_IOP_MASK  (0x0C86)
+#define ASC_GET_EISA_SLOT(iop)  (PortAddr)((iop) & 0xF000)
+#define ASC_EISA_ID_740    0x01745004UL
+#define ASC_EISA_ID_750    0x01755004UL
+#define INS_HALTINT        (ushort)0x6281
+#define INS_HALT           (ushort)0x6280
+#define INS_SINT           (ushort)0x6200
+#define INS_RFLAG_WTM      (ushort)0x7380
+#define ASC_MC_SAVE_CODE_WSIZE  0x500
+#define ASC_MC_SAVE_DATA_WSIZE  0x40
+
+typedef struct asc_mc_saved {
+    ushort              data[ASC_MC_SAVE_DATA_WSIZE];
+    ushort              code[ASC_MC_SAVE_CODE_WSIZE];
+} ASC_MC_SAVED;
+
+#define AscGetQDoneInProgress(port)         AscReadLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B)
+#define AscPutQDoneInProgress(port, val)    AscWriteLramByte((port), ASCV_Q_DONE_IN_PROGRESS_B, val)
+#define AscGetVarFreeQHead(port)            AscReadLramWord((port), ASCV_FREE_Q_HEAD_W)
+#define AscGetVarDoneQTail(port)            AscReadLramWord((port), ASCV_DONE_Q_TAIL_W)
+#define AscPutVarFreeQHead(port, val)       AscWriteLramWord((port), ASCV_FREE_Q_HEAD_W, val)
+#define AscPutVarDoneQTail(port, val)       AscWriteLramWord((port), ASCV_DONE_Q_TAIL_W, val)
+#define AscGetRiscVarFreeQHead(port)        AscReadLramByte((port), ASCV_NEXTRDY_B)
+#define AscGetRiscVarDoneQTail(port)        AscReadLramByte((port), ASCV_DONENEXT_B)
+#define AscPutRiscVarFreeQHead(port, val)   AscWriteLramByte((port), ASCV_NEXTRDY_B, val)
+#define AscPutRiscVarDoneQTail(port, val)   AscWriteLramByte((port), ASCV_DONENEXT_B, val)
+#define AscPutMCodeSDTRDoneAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id), (data));
+#define AscGetMCodeSDTRDoneAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DONE_BEG+(ushort)id));
+#define AscPutMCodeInitSDTRAtID(port, id, data)  AscWriteLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id), data);
+#define AscGetMCodeInitSDTRAtID(port, id)        AscReadLramByte((port), (ushort)((ushort)ASCV_SDTR_DATA_BEG+(ushort)id));
+#define AscSynIndexToPeriod(index)        (uchar)(asc_dvc->sdtr_period_tbl[ (index) ])
+#define AscGetChipSignatureByte(port)     (uchar)inp((port)+IOP_SIG_BYTE)
+#define AscGetChipSignatureWord(port)     (ushort)inpw((port)+IOP_SIG_WORD)
+#define AscGetChipVerNo(port)             (uchar)inp((port)+IOP_VERSION)
+#define AscGetChipCfgLsw(port)            (ushort)inpw((port)+IOP_CONFIG_LOW)
+#define AscGetChipCfgMsw(port)            (ushort)inpw((port)+IOP_CONFIG_HIGH)
+#define AscSetChipCfgLsw(port, data)      outpw((port)+IOP_CONFIG_LOW, data)
+#define AscSetChipCfgMsw(port, data)      outpw((port)+IOP_CONFIG_HIGH, data)
+#define AscGetChipEEPCmd(port)            (uchar)inp((port)+IOP_EEP_CMD)
+#define AscSetChipEEPCmd(port, data)      outp((port)+IOP_EEP_CMD, data)
+#define AscGetChipEEPData(port)           (ushort)inpw((port)+IOP_EEP_DATA)
+#define AscSetChipEEPData(port, data)     outpw((port)+IOP_EEP_DATA, data)
+#define AscGetChipLramAddr(port)          (ushort)inpw((PortAddr)((port)+IOP_RAM_ADDR))
+#define AscSetChipLramAddr(port, addr)    outpw((PortAddr)((port)+IOP_RAM_ADDR), addr)
+#define AscGetChipLramData(port)          (ushort)inpw((port)+IOP_RAM_DATA)
+#define AscSetChipLramData(port, data)    outpw((port)+IOP_RAM_DATA, data)
+#define AscGetChipIFC(port)               (uchar)inp((port)+IOP_REG_IFC)
+#define AscSetChipIFC(port, data)          outp((port)+IOP_REG_IFC, data)
+#define AscGetChipStatus(port)            (ASC_CS_TYPE)inpw((port)+IOP_STATUS)
+#define AscSetChipStatus(port, cs_val)    outpw((port)+IOP_STATUS, cs_val)
+#define AscGetChipControl(port)           (uchar)inp((port)+IOP_CTRL)
+#define AscSetChipControl(port, cc_val)   outp((port)+IOP_CTRL, cc_val)
+#define AscGetChipSyn(port)               (uchar)inp((port)+IOP_SYN_OFFSET)
+#define AscSetChipSyn(port, data)         outp((port)+IOP_SYN_OFFSET, data)
+#define AscSetPCAddr(port, data)          outpw((port)+IOP_REG_PC, data)
+#define AscGetPCAddr(port)                (ushort)inpw((port)+IOP_REG_PC)
+#define AscIsIntPending(port)             (AscGetChipStatus(port) & (CSW_INT_PENDING | CSW_SCSI_RESET_LATCH))
+#define AscGetChipScsiID(port)            ((AscGetChipCfgLsw(port) >> 8) & ASC_MAX_TID)
+#define AscGetExtraControl(port)          (uchar)inp((port)+IOP_EXTRA_CONTROL)
+#define AscSetExtraControl(port, data)    outp((port)+IOP_EXTRA_CONTROL, data)
+#define AscReadChipAX(port)               (ushort)inpw((port)+IOP_REG_AX)
+#define AscWriteChipAX(port, data)        outpw((port)+IOP_REG_AX, data)
+#define AscReadChipIX(port)               (uchar)inp((port)+IOP_REG_IX)
+#define AscWriteChipIX(port, data)        outp((port)+IOP_REG_IX, data)
+#define AscReadChipIH(port)               (ushort)inpw((port)+IOP_REG_IH)
+#define AscWriteChipIH(port, data)        outpw((port)+IOP_REG_IH, data)
+#define AscReadChipQP(port)               (uchar)inp((port)+IOP_REG_QP)
+#define AscWriteChipQP(port, data)        outp((port)+IOP_REG_QP, data)
+#define AscReadChipFIFO_L(port)           (ushort)inpw((port)+IOP_REG_FIFO_L)
+#define AscWriteChipFIFO_L(port, data)    outpw((port)+IOP_REG_FIFO_L, data)
+#define AscReadChipFIFO_H(port)           (ushort)inpw((port)+IOP_REG_FIFO_H)
+#define AscWriteChipFIFO_H(port, data)    outpw((port)+IOP_REG_FIFO_H, data)
+#define AscReadChipDmaSpeed(port)         (uchar)inp((port)+IOP_DMA_SPEED)
+#define AscWriteChipDmaSpeed(port, data)  outp((port)+IOP_DMA_SPEED, data)
+#define AscReadChipDA0(port)              (ushort)inpw((port)+IOP_REG_DA0)
+#define AscWriteChipDA0(port)             outpw((port)+IOP_REG_DA0, data)
+#define AscReadChipDA1(port)              (ushort)inpw((port)+IOP_REG_DA1)
+#define AscWriteChipDA1(port)             outpw((port)+IOP_REG_DA1, data)
+#define AscReadChipDC0(port)              (ushort)inpw((port)+IOP_REG_DC0)
+#define AscWriteChipDC0(port)             outpw((port)+IOP_REG_DC0, data)
+#define AscReadChipDC1(port)              (ushort)inpw((port)+IOP_REG_DC1)
+#define AscWriteChipDC1(port)             outpw((port)+IOP_REG_DC1, data)
+#define AscReadChipDvcID(port)            (uchar)inp((port)+IOP_REG_ID)
+#define AscWriteChipDvcID(port, data)     outp((port)+IOP_REG_ID, data)
+
+STATIC int       AscWriteEEPCmdReg(PortAddr iop_base, uchar cmd_reg);
+STATIC int       AscWriteEEPDataReg(PortAddr iop_base, ushort data_reg);
+STATIC void      AscWaitEEPRead(void);
+STATIC void      AscWaitEEPWrite(void);
+STATIC ushort    AscReadEEPWord(PortAddr, uchar);
+STATIC ushort    AscWriteEEPWord(PortAddr, uchar, ushort);
+STATIC ushort    AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscSetEEPConfigOnce(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscSetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int       AscStartChip(PortAddr);
+STATIC int       AscStopChip(PortAddr);
+STATIC void      AscSetChipIH(PortAddr, ushort);
+STATIC int       AscIsChipHalted(PortAddr);
+STATIC void      AscAckInterrupt(PortAddr);
+STATIC void      AscDisableInterrupt(PortAddr);
+STATIC void      AscEnableInterrupt(PortAddr);
+STATIC void      AscSetBank(PortAddr, uchar);
+STATIC int       AscResetChipAndScsiBus(ASC_DVC_VAR *);
+#ifdef CONFIG_ISA
+STATIC ushort    AscGetIsaDmaChannel(PortAddr);
+STATIC ushort    AscSetIsaDmaChannel(PortAddr, ushort);
+STATIC uchar     AscSetIsaDmaSpeed(PortAddr, uchar);
+STATIC uchar     AscGetIsaDmaSpeed(PortAddr);
+#endif /* CONFIG_ISA */
+STATIC uchar     AscReadLramByte(PortAddr, ushort);
+STATIC ushort    AscReadLramWord(PortAddr, ushort);
+#if CC_VERY_LONG_SG_LIST
+STATIC ASC_DCNT  AscReadLramDWord(PortAddr, ushort);
+#endif /* CC_VERY_LONG_SG_LIST */
+STATIC void      AscWriteLramWord(PortAddr, ushort, ushort);
+STATIC void      AscWriteLramByte(PortAddr, ushort, uchar);
+STATIC ASC_DCNT  AscMemSumLramWord(PortAddr, ushort, int);
+STATIC void      AscMemWordSetLram(PortAddr, ushort, ushort, int);
+STATIC void      AscMemWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+STATIC void      AscMemDWordCopyPtrToLram(PortAddr, ushort, uchar *, int);
+STATIC void      AscMemWordCopyPtrFromLram(PortAddr, ushort, uchar *, int);
+STATIC ushort    AscInitAscDvcVar(ASC_DVC_VAR *);
+STATIC ushort    AscInitFromEEP(ASC_DVC_VAR *);
+STATIC ushort    AscInitFromAscDvcVar(ASC_DVC_VAR *);
+STATIC ushort    AscInitMicroCodeVar(ASC_DVC_VAR *);
+STATIC int       AscTestExternalLram(ASC_DVC_VAR *);
+STATIC uchar     AscMsgOutSDTR(ASC_DVC_VAR *, uchar, uchar);
+STATIC uchar     AscCalSDTRData(ASC_DVC_VAR *, uchar, uchar);
+STATIC void      AscSetChipSDTR(PortAddr, uchar, uchar);
+STATIC uchar     AscGetSynPeriodIndex(ASC_DVC_VAR *, uchar);
+STATIC uchar     AscAllocFreeQueue(PortAddr, uchar);
+STATIC uchar     AscAllocMultipleFreeQueue(PortAddr, uchar, uchar);
+STATIC int       AscHostReqRiscHalt(PortAddr);
+STATIC int       AscStopQueueExe(PortAddr);
+STATIC int       AscSendScsiQueue(ASC_DVC_VAR *,
+                    ASC_SCSI_Q * scsiq,
+                    uchar n_q_required);
+STATIC int       AscPutReadyQueue(ASC_DVC_VAR *,
+                    ASC_SCSI_Q *, uchar);
+STATIC int       AscPutReadySgListQueue(ASC_DVC_VAR *,
+                    ASC_SCSI_Q *, uchar);
+STATIC int       AscSetChipSynRegAtID(PortAddr, uchar, uchar);
+STATIC int       AscSetRunChipSynRegAtID(PortAddr, uchar, uchar);
+STATIC ushort    AscInitLram(ASC_DVC_VAR *);
+STATIC ushort    AscInitQLinkVar(ASC_DVC_VAR *);
+STATIC int       AscSetLibErrorCode(ASC_DVC_VAR *, ushort);
+STATIC int       AscIsrChipHalted(ASC_DVC_VAR *);
+STATIC uchar     _AscCopyLramScsiDoneQ(PortAddr, ushort,
+                    ASC_QDONE_INFO *, ASC_DCNT);
+STATIC int       AscIsrQDone(ASC_DVC_VAR *);
+STATIC int       AscCompareString(uchar *, uchar *, int);
+#ifdef CONFIG_ISA
+STATIC ushort    AscGetEisaChipCfg(PortAddr);
+STATIC ASC_DCNT  AscGetEisaProductID(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddrEISA(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddr11(PortAddr);
+STATIC PortAddr  AscSearchIOPortAddr(PortAddr, ushort);
+STATIC void      AscSetISAPNPWaitForKey(void);
+#endif /* CONFIG_ISA */
+STATIC uchar     AscGetChipScsiCtrl(PortAddr);
+STATIC uchar     AscSetChipScsiID(PortAddr, uchar);
+STATIC uchar     AscGetChipVersion(PortAddr, ushort);
+STATIC ushort    AscGetChipBusType(PortAddr);
+STATIC ASC_DCNT  AscLoadMicroCode(PortAddr, ushort, uchar *, ushort);
+STATIC int       AscFindSignature(PortAddr);
+STATIC void      AscToggleIRQAct(PortAddr);
+STATIC uchar     AscGetChipIRQ(PortAddr, ushort);
+STATIC uchar     AscSetChipIRQ(PortAddr, uchar, ushort);
+STATIC ushort    AscGetChipBiosAddress(PortAddr, ushort);
+STATIC inline ulong DvcEnterCritical(void);
+STATIC inline void DvcLeaveCritical(ulong);
+#ifdef CONFIG_PCI
+STATIC uchar     DvcReadPCIConfigByte(ASC_DVC_VAR *, ushort);
+STATIC void      DvcWritePCIConfigByte(ASC_DVC_VAR *,
+                    ushort, uchar);
+#endif /* CONFIG_PCI */
+STATIC ushort      AscGetChipBiosAddress(PortAddr, ushort);
+STATIC void      DvcSleepMilliSecond(ASC_DCNT);
+STATIC void      DvcDelayNanoSecond(ASC_DVC_VAR *, ASC_DCNT);
+STATIC void      DvcPutScsiQ(PortAddr, ushort, uchar *, int);
+STATIC void      DvcGetQinfo(PortAddr, ushort, uchar *, int);
+STATIC ushort    AscInitGetConfig(ASC_DVC_VAR *);
+STATIC ushort    AscInitSetConfig(ASC_DVC_VAR *);
+STATIC ushort    AscInitAsc1000Driver(ASC_DVC_VAR *);
+STATIC void      AscAsyncFix(ASC_DVC_VAR *, uchar,
+                    ASC_SCSI_INQUIRY *);
+STATIC int       AscTagQueuingSafe(ASC_SCSI_INQUIRY *);
+STATIC void      AscInquiryHandling(ASC_DVC_VAR *,
+                    uchar, ASC_SCSI_INQUIRY *);
+STATIC int       AscExeScsiQueue(ASC_DVC_VAR *, ASC_SCSI_Q *);
+STATIC int       AscISR(ASC_DVC_VAR *);
+STATIC uint      AscGetNumOfFreeQueue(ASC_DVC_VAR *, uchar,
+                    uchar);
+STATIC int       AscSgListToQueue(int);
+#ifdef CONFIG_ISA
+STATIC void      AscEnableIsaDma(uchar);
+#endif /* CONFIG_ISA */
+STATIC ASC_DCNT  AscGetMaxDmaCount(ushort);
+
+
+/*
+ * --- Adv Library Constants and Macros
+ */
+
+#define ADV_LIB_VERSION_MAJOR  5
+#define ADV_LIB_VERSION_MINOR  14
+
+/*
+ * Define Adv Library required special types.
+ */
+
+/*
+ * Portable Data Types
+ *
+ * Any instance where a 32-bit long or pointer type is assumed
+ * for precision or HW defined structures, the following define
+ * types must be used. In Linux the char, short, and int types
+ * are all consistent at 8, 16, and 32 bits respectively. Pointers
+ * and long types are 64 bits on Alpha and UltraSPARC.
+ */
+#define ADV_PADDR __u32         /* Physical address data type. */
+#define ADV_VADDR __u32         /* Virtual address data type. */
+#define ADV_DCNT  __u32         /* Unsigned Data count type. */
+#define ADV_SDCNT __s32         /* Signed Data count type. */
+
+/*
+ * These macros are used to convert a virtual address to a
+ * 32-bit value. This currently can be used on Linux Alpha
+ * which uses 64-bit virtual address but a 32-bit bus address.
+ * This is likely to break in the future, but doing this now
+ * will give us time to change the HW and FW to handle 64-bit
+ * addresses.
+ */
+#define ADV_VADDR_TO_U32   virt_to_bus
+#define ADV_U32_TO_VADDR   bus_to_virt
+
+#define AdvPortAddr  ulong              /* Virtual memory address size */
+
+/*
+ * Define Adv Library required memory access macros.
+ */
+#define ADV_MEM_READB(addr) readb(addr)
+#define ADV_MEM_READW(addr) readw(addr)
+#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
+#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
+#define ADV_MEM_WRITEDW(addr, dword) writel(dword, addr)
+
+#define ADV_CARRIER_COUNT (ASC_DEF_MAX_HOST_QNG + 15)
+
+/*
+ * For wide  boards a CDB length maximum of 16 bytes
+ * is supported.
+ */
+#define ADV_MAX_CDB_LEN     16
+
+/*
+ * Define total number of simultaneous maximum element scatter-gather
+ * request blocks per wide adapter. ASC_DEF_MAX_HOST_QNG (253) is the
+ * maximum number of outstanding commands per wide host adapter. Each
+ * command uses one or more ADV_SG_BLOCK each with 15 scatter-gather
+ * elements. Allow each command to have at least one ADV_SG_BLOCK structure.
+ * This allows about 15 commands to have the maximum 17 ADV_SG_BLOCK
+ * structures or 255 scatter-gather elements.
+ *
+ */
+#define ADV_TOT_SG_BLOCK        ASC_DEF_MAX_HOST_QNG
+
+/*
+ * Define Adv Library required maximum number of scatter-gather
+ * elements per request.
+ */
+#define ADV_MAX_SG_LIST         255
+
+/* Number of SG blocks needed. */
+#define ADV_NUM_SG_BLOCK \
+    ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+
+/* Total contiguous memory needed for SG blocks. */
+#define ADV_SG_TOTAL_MEM_SIZE \
+    (sizeof(ADV_SG_BLOCK) *  ADV_NUM_SG_BLOCK)
+
+#define ADV_PAGE_SIZE PAGE_SIZE
+
+#define ADV_NUM_PAGE_CROSSING \
+    ((ADV_SG_TOTAL_MEM_SIZE + (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+/* a_condor.h */
+#define ADV_PCI_VENDOR_ID               0x10CD
+#define ADV_PCI_DEVICE_ID_REV_A         0x2300
+#define ADV_PCI_DEVID_38C0800_REV1      0x2500
+#define ADV_PCI_DEVID_38C1600_REV1      0x2700
+
+#define ADV_EEP_DVC_CFG_BEGIN           (0x00)
+#define ADV_EEP_DVC_CFG_END             (0x15)
+#define ADV_EEP_DVC_CTL_BEGIN           (0x16)  /* location of OEM name */
+#define ADV_EEP_MAX_WORD_ADDR           (0x1E)
+
+#define ADV_EEP_DELAY_MS                100
+
+#define ADV_EEPROM_BIG_ENDIAN          0x8000   /* EEPROM Bit 15 */
+#define ADV_EEPROM_BIOS_ENABLE         0x4000   /* EEPROM Bit 14 */
+/*
+ * For the ASC3550 Bit 13 is Termination Polarity control bit.
+ * For later ICs Bit 13 controls whether the CIS (Card Information
+ * Service Section) is loaded from EEPROM.
+ */
+#define ADV_EEPROM_TERM_POL            0x2000   /* EEPROM Bit 13 */
+#define ADV_EEPROM_CIS_LD              0x2000   /* EEPROM Bit 13 */
+/*
+ * ASC38C1600 Bit 11
+ *
+ * If EEPROM Bit 11 is 0 for Function 0, then Function 0 will specify
+ * INT A in the PCI Configuration Space Int Pin field. If it is 1, then
+ * Function 0 will specify INT B.
+ *
+ * If EEPROM Bit 11 is 0 for Function 1, then Function 1 will specify
+ * INT B in the PCI Configuration Space Int Pin field. If it is 1, then
+ * Function 1 will specify INT A.
+ */
+#define ADV_EEPROM_INTAB               0x0800   /* EEPROM Bit 11 */
+
+typedef struct adveep_3550_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 13 set - Term Polarity Control */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused      */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_able;             /* 04 Synchronous DTR able */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination;           /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  reserved1;             /*    reserved byte (not used) */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 */
+                                /*  bit 14 */
+                                /*  bit 15 */
+  ushort  ultra_able;           /* 13 ULTRA speed able */
+  ushort  reserved2;            /* 14 reserved */
+  uchar   max_host_qng;         /* 15 maximum host queuing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  bug_fix;              /* 17 control bit for bug fix */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  num_of_err;           /* 36 number of error */
+} ADVEEP_3550_CONFIG;
+
+typedef struct adveep_38C0800_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 13 set - Load CIS */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused      */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination_se;        /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  termination_lvd;       /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 */
+                                /*  bit 14 */
+                                /*  bit 15 */
+  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
+  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
+  uchar   max_host_qng;         /* 15 maximum host queueing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  reserved36;           /* 36 reserved */
+  ushort  reserved37;           /* 37 reserved */
+  ushort  reserved38;           /* 38 reserved */
+  ushort  reserved39;           /* 39 reserved */
+  ushort  reserved40;           /* 40 reserved */
+  ushort  reserved41;           /* 41 reserved */
+  ushort  reserved42;           /* 42 reserved */
+  ushort  reserved43;           /* 43 reserved */
+  ushort  reserved44;           /* 44 reserved */
+  ushort  reserved45;           /* 45 reserved */
+  ushort  reserved46;           /* 46 reserved */
+  ushort  reserved47;           /* 47 reserved */
+  ushort  reserved48;           /* 48 reserved */
+  ushort  reserved49;           /* 49 reserved */
+  ushort  reserved50;           /* 50 reserved */
+  ushort  reserved51;           /* 51 reserved */
+  ushort  reserved52;           /* 52 reserved */
+  ushort  reserved53;           /* 53 reserved */
+  ushort  reserved54;           /* 54 reserved */
+  ushort  reserved55;           /* 55 reserved */
+  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
+  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
+  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
+  ushort  subsysid;             /* 59 SubSystem ID */
+  ushort  reserved60;           /* 60 reserved */
+  ushort  reserved61;           /* 61 reserved */
+  ushort  reserved62;           /* 62 reserved */
+  ushort  reserved63;           /* 63 reserved */
+} ADVEEP_38C0800_CONFIG;
+
+typedef struct adveep_38C1600_config
+{
+                                /* Word Offset, Description */
+
+  ushort cfg_lsw;               /* 00 power up initialization */
+                                /*  bit 11 set - Func. 0 INTB, Func. 1 INTA */
+                                /*       clear - Func. 0 INTA, Func. 1 INTB */
+                                /*  bit 13 set - Load CIS */
+                                /*  bit 14 set - BIOS Enable */
+                                /*  bit 15 set - Big Endian Mode */
+  ushort cfg_msw;               /* 01 unused */
+  ushort disc_enable;           /* 02 disconnect enable */
+  ushort wdtr_able;             /* 03 Wide DTR able */
+  ushort sdtr_speed1;           /* 04 SDTR Speed TID 0-3 */
+  ushort start_motor;           /* 05 send start up motor */
+  ushort tagqng_able;           /* 06 tag queuing able */
+  ushort bios_scan;             /* 07 BIOS device control */
+  ushort scam_tolerant;         /* 08 no scam */
+
+  uchar  adapter_scsi_id;       /* 09 Host Adapter ID */
+  uchar  bios_boot_delay;       /*    power up wait */
+
+  uchar  scsi_reset_delay;      /* 10 reset delay */
+  uchar  bios_id_lun;           /*    first boot device scsi id & lun */
+                                /*    high nibble is lun */
+                                /*    low nibble is scsi id */
+
+  uchar  termination_se;        /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  uchar  termination_lvd;       /* 11 0 - automatic */
+                                /*    1 - low off / high off */
+                                /*    2 - low off / high on */
+                                /*    3 - low on  / high on */
+                                /*    There is no low on  / high off */
+
+  ushort bios_ctrl;             /* 12 BIOS control bits */
+                                /*  bit 0  BIOS don't act as initiator. */
+                                /*  bit 1  BIOS > 1 GB support */
+                                /*  bit 2  BIOS > 2 Disk Support */
+                                /*  bit 3  BIOS don't support removables */
+                                /*  bit 4  BIOS support bootable CD */
+                                /*  bit 5  BIOS scan enabled */
+                                /*  bit 6  BIOS support multiple LUNs */
+                                /*  bit 7  BIOS display of message */
+                                /*  bit 8  SCAM disabled */
+                                /*  bit 9  Reset SCSI bus during init. */
+                                /*  bit 10 Basic Integrity Checking disabled */
+                                /*  bit 11 No verbose initialization. */
+                                /*  bit 12 SCSI parity enabled */
+                                /*  bit 13 AIPP (Asyn. Info. Ph. Prot.) dis. */
+                                /*  bit 14 */
+                                /*  bit 15 */
+  ushort  sdtr_speed2;          /* 13 SDTR speed TID 4-7 */
+  ushort  sdtr_speed3;          /* 14 SDTR speed TID 8-11 */
+  uchar   max_host_qng;         /* 15 maximum host queueing */
+  uchar   max_dvc_qng;          /*    maximum per device queuing */
+  ushort  dvc_cntl;             /* 16 control bit for driver */
+  ushort  sdtr_speed4;          /* 17 SDTR speed 4 TID 12-15 */
+  ushort  serial_number_word1;  /* 18 Board serial number word 1 */
+  ushort  serial_number_word2;  /* 19 Board serial number word 2 */
+  ushort  serial_number_word3;  /* 20 Board serial number word 3 */
+  ushort  check_sum;            /* 21 EEP check sum */
+  uchar   oem_name[16];         /* 22 OEM name */
+  ushort  dvc_err_code;         /* 30 last device driver error code */
+  ushort  adv_err_code;         /* 31 last uc and Adv Lib error code */
+  ushort  adv_err_addr;         /* 32 last uc error address */
+  ushort  saved_dvc_err_code;   /* 33 saved last dev. driver error code   */
+  ushort  saved_adv_err_code;   /* 34 saved last uc and Adv Lib error code */
+  ushort  saved_adv_err_addr;   /* 35 saved last uc error address         */
+  ushort  reserved36;           /* 36 reserved */
+  ushort  reserved37;           /* 37 reserved */
+  ushort  reserved38;           /* 38 reserved */
+  ushort  reserved39;           /* 39 reserved */
+  ushort  reserved40;           /* 40 reserved */
+  ushort  reserved41;           /* 41 reserved */
+  ushort  reserved42;           /* 42 reserved */
+  ushort  reserved43;           /* 43 reserved */
+  ushort  reserved44;           /* 44 reserved */
+  ushort  reserved45;           /* 45 reserved */
+  ushort  reserved46;           /* 46 reserved */
+  ushort  reserved47;           /* 47 reserved */
+  ushort  reserved48;           /* 48 reserved */
+  ushort  reserved49;           /* 49 reserved */
+  ushort  reserved50;           /* 50 reserved */
+  ushort  reserved51;           /* 51 reserved */
+  ushort  reserved52;           /* 52 reserved */
+  ushort  reserved53;           /* 53 reserved */
+  ushort  reserved54;           /* 54 reserved */
+  ushort  reserved55;           /* 55 reserved */
+  ushort  cisptr_lsw;           /* 56 CIS PTR LSW */
+  ushort  cisprt_msw;           /* 57 CIS PTR MSW */
+  ushort  subsysvid;            /* 58 SubSystem Vendor ID */
+  ushort  subsysid;             /* 59 SubSystem ID */
+  ushort  reserved60;           /* 60 reserved */
+  ushort  reserved61;           /* 61 reserved */
+  ushort  reserved62;           /* 62 reserved */
+  ushort  reserved63;           /* 63 reserved */
+} ADVEEP_38C1600_CONFIG;
+
+/*
+ * EEPROM Commands
+ */
+#define ASC_EEP_CMD_DONE             0x0200
+#define ASC_EEP_CMD_DONE_ERR         0x0001
+
+/* cfg_word */
+#define EEP_CFG_WORD_BIG_ENDIAN      0x8000
+
+/* bios_ctrl */
+#define BIOS_CTRL_BIOS               0x0001
+#define BIOS_CTRL_EXTENDED_XLAT      0x0002
+#define BIOS_CTRL_GT_2_DISK          0x0004
+#define BIOS_CTRL_BIOS_REMOVABLE     0x0008
+#define BIOS_CTRL_BOOTABLE_CD        0x0010
+#define BIOS_CTRL_MULTIPLE_LUN       0x0040
+#define BIOS_CTRL_DISPLAY_MSG        0x0080
+#define BIOS_CTRL_NO_SCAM            0x0100
+#define BIOS_CTRL_RESET_SCSI_BUS     0x0200
+#define BIOS_CTRL_INIT_VERBOSE       0x0800
+#define BIOS_CTRL_SCSI_PARITY        0x1000
+#define BIOS_CTRL_AIPP_DIS           0x2000
+
+#define ADV_3550_MEMSIZE   0x2000       /* 8 KB Internal Memory */
+#define ADV_3550_IOLEN     0x40         /* I/O Port Range in bytes */
+
+#define ADV_38C0800_MEMSIZE  0x4000     /* 16 KB Internal Memory */
+#define ADV_38C0800_IOLEN    0x100      /* I/O Port Range in bytes */
+
+/*
+ * XXX - Since ASC38C1600 Rev.3 has a local RAM failure issue, there is
+ * a special 16K Adv Library and Microcode version. After the issue is
+ * resolved, should restore 32K support.
+ *
+ * #define ADV_38C1600_MEMSIZE  0x8000L   * 32 KB Internal Memory *
+ */
+#define ADV_38C1600_MEMSIZE  0x4000   /* 16 KB Internal Memory */
+#define ADV_38C1600_IOLEN    0x100     /* I/O Port Range 256 bytes */
+#define ADV_38C1600_MEMLEN   0x1000    /* Memory Range 4KB bytes */
+
+/*
+ * Byte I/O register address from base of 'iop_base'.
+ */
+#define IOPB_INTR_STATUS_REG    0x00
+#define IOPB_CHIP_ID_1          0x01
+#define IOPB_INTR_ENABLES       0x02
+#define IOPB_CHIP_TYPE_REV      0x03
+#define IOPB_RES_ADDR_4         0x04
+#define IOPB_RES_ADDR_5         0x05
+#define IOPB_RAM_DATA           0x06
+#define IOPB_RES_ADDR_7         0x07
+#define IOPB_FLAG_REG           0x08
+#define IOPB_RES_ADDR_9         0x09
+#define IOPB_RISC_CSR           0x0A
+#define IOPB_RES_ADDR_B         0x0B
+#define IOPB_RES_ADDR_C         0x0C
+#define IOPB_RES_ADDR_D         0x0D
+#define IOPB_SOFT_OVER_WR       0x0E
+#define IOPB_RES_ADDR_F         0x0F
+#define IOPB_MEM_CFG            0x10
+#define IOPB_RES_ADDR_11        0x11
+#define IOPB_GPIO_DATA          0x12
+#define IOPB_RES_ADDR_13        0x13
+#define IOPB_FLASH_PAGE         0x14
+#define IOPB_RES_ADDR_15        0x15
+#define IOPB_GPIO_CNTL          0x16
+#define IOPB_RES_ADDR_17        0x17
+#define IOPB_FLASH_DATA         0x18
+#define IOPB_RES_ADDR_19        0x19
+#define IOPB_RES_ADDR_1A        0x1A
+#define IOPB_RES_ADDR_1B        0x1B
+#define IOPB_RES_ADDR_1C        0x1C
+#define IOPB_RES_ADDR_1D        0x1D
+#define IOPB_RES_ADDR_1E        0x1E
+#define IOPB_RES_ADDR_1F        0x1F
+#define IOPB_DMA_CFG0           0x20
+#define IOPB_DMA_CFG1           0x21
+#define IOPB_TICKLE             0x22
+#define IOPB_DMA_REG_WR         0x23
+#define IOPB_SDMA_STATUS        0x24
+#define IOPB_SCSI_BYTE_CNT      0x25
+#define IOPB_HOST_BYTE_CNT      0x26
+#define IOPB_BYTE_LEFT_TO_XFER  0x27
+#define IOPB_BYTE_TO_XFER_0     0x28
+#define IOPB_BYTE_TO_XFER_1     0x29
+#define IOPB_BYTE_TO_XFER_2     0x2A
+#define IOPB_BYTE_TO_XFER_3     0x2B
+#define IOPB_ACC_GRP            0x2C
+#define IOPB_RES_ADDR_2D        0x2D
+#define IOPB_DEV_ID             0x2E
+#define IOPB_RES_ADDR_2F        0x2F
+#define IOPB_SCSI_DATA          0x30
+#define IOPB_RES_ADDR_31        0x31
+#define IOPB_RES_ADDR_32        0x32
+#define IOPB_SCSI_DATA_HSHK     0x33
+#define IOPB_SCSI_CTRL          0x34
+#define IOPB_RES_ADDR_35        0x35
+#define IOPB_RES_ADDR_36        0x36
+#define IOPB_RES_ADDR_37        0x37
+#define IOPB_RAM_BIST           0x38
+#define IOPB_PLL_TEST           0x39
+#define IOPB_PCI_INT_CFG        0x3A
+#define IOPB_RES_ADDR_3B        0x3B
+#define IOPB_RFIFO_CNT          0x3C
+#define IOPB_RES_ADDR_3D        0x3D
+#define IOPB_RES_ADDR_3E        0x3E
+#define IOPB_RES_ADDR_3F        0x3F
+
+/*
+ * Word I/O register address from base of 'iop_base'.
+ */
+#define IOPW_CHIP_ID_0          0x00  /* CID0  */
+#define IOPW_CTRL_REG           0x02  /* CC    */
+#define IOPW_RAM_ADDR           0x04  /* LA    */
+#define IOPW_RAM_DATA           0x06  /* LD    */
+#define IOPW_RES_ADDR_08        0x08
+#define IOPW_RISC_CSR           0x0A  /* CSR   */
+#define IOPW_SCSI_CFG0          0x0C  /* CFG0  */
+#define IOPW_SCSI_CFG1          0x0E  /* CFG1  */
+#define IOPW_RES_ADDR_10        0x10
+#define IOPW_SEL_MASK           0x12  /* SM    */
+#define IOPW_RES_ADDR_14        0x14
+#define IOPW_FLASH_ADDR         0x16  /* FA    */
+#define IOPW_RES_ADDR_18        0x18
+#define IOPW_EE_CMD             0x1A  /* EC    */
+#define IOPW_EE_DATA            0x1C  /* ED    */
+#define IOPW_SFIFO_CNT          0x1E  /* SFC   */
+#define IOPW_RES_ADDR_20        0x20
+#define IOPW_Q_BASE             0x22  /* QB    */
+#define IOPW_QP                 0x24  /* QP    */
+#define IOPW_IX                 0x26  /* IX    */
+#define IOPW_SP                 0x28  /* SP    */
+#define IOPW_PC                 0x2A  /* PC    */
+#define IOPW_RES_ADDR_2C        0x2C
+#define IOPW_RES_ADDR_2E        0x2E
+#define IOPW_SCSI_DATA          0x30  /* SD    */
+#define IOPW_SCSI_DATA_HSHK     0x32  /* SDH   */
+#define IOPW_SCSI_CTRL          0x34  /* SC    */
+#define IOPW_HSHK_CFG           0x36  /* HCFG  */
+#define IOPW_SXFR_STATUS        0x36  /* SXS   */
+#define IOPW_SXFR_CNTL          0x38  /* SXL   */
+#define IOPW_SXFR_CNTH          0x3A  /* SXH   */
+#define IOPW_RES_ADDR_3C        0x3C
+#define IOPW_RFIFO_DATA         0x3E  /* RFD   */
+
+/*
+ * Doubleword I/O register address from base of 'iop_base'.
+ */
+#define IOPDW_RES_ADDR_0         0x00
+#define IOPDW_RAM_DATA           0x04
+#define IOPDW_RES_ADDR_8         0x08
+#define IOPDW_RES_ADDR_C         0x0C
+#define IOPDW_RES_ADDR_10        0x10
+#define IOPDW_COMMA              0x14
+#define IOPDW_COMMB              0x18
+#define IOPDW_RES_ADDR_1C        0x1C
+#define IOPDW_SDMA_ADDR0         0x20
+#define IOPDW_SDMA_ADDR1         0x24
+#define IOPDW_SDMA_COUNT         0x28
+#define IOPDW_SDMA_ERROR         0x2C
+#define IOPDW_RDMA_ADDR0         0x30
+#define IOPDW_RDMA_ADDR1         0x34
+#define IOPDW_RDMA_COUNT         0x38
+#define IOPDW_RDMA_ERROR         0x3C
+
+#define ADV_CHIP_ID_BYTE         0x25
+#define ADV_CHIP_ID_WORD         0x04C1
+
+#define ADV_SC_SCSI_BUS_RESET    0x2000
+
+#define ADV_INTR_ENABLE_HOST_INTR                   0x01
+#define ADV_INTR_ENABLE_SEL_INTR                    0x02
+#define ADV_INTR_ENABLE_DPR_INTR                    0x04
+#define ADV_INTR_ENABLE_RTA_INTR                    0x08
+#define ADV_INTR_ENABLE_RMA_INTR                    0x10
+#define ADV_INTR_ENABLE_RST_INTR                    0x20
+#define ADV_INTR_ENABLE_DPE_INTR                    0x40
+#define ADV_INTR_ENABLE_GLOBAL_INTR                 0x80
+
+#define ADV_INTR_STATUS_INTRA            0x01
+#define ADV_INTR_STATUS_INTRB            0x02
+#define ADV_INTR_STATUS_INTRC            0x04
+
+#define ADV_RISC_CSR_STOP           (0x0000)
+#define ADV_RISC_TEST_COND          (0x2000)
+#define ADV_RISC_CSR_RUN            (0x4000)
+#define ADV_RISC_CSR_SINGLE_STEP    (0x8000)
+
+#define ADV_CTRL_REG_HOST_INTR      0x0100
+#define ADV_CTRL_REG_SEL_INTR       0x0200
+#define ADV_CTRL_REG_DPR_INTR       0x0400
+#define ADV_CTRL_REG_RTA_INTR       0x0800
+#define ADV_CTRL_REG_RMA_INTR       0x1000
+#define ADV_CTRL_REG_RES_BIT14      0x2000
+#define ADV_CTRL_REG_DPE_INTR       0x4000
+#define ADV_CTRL_REG_POWER_DONE     0x8000
+#define ADV_CTRL_REG_ANY_INTR       0xFF00
+
+#define ADV_CTRL_REG_CMD_RESET             0x00C6
+#define ADV_CTRL_REG_CMD_WR_IO_REG         0x00C5
+#define ADV_CTRL_REG_CMD_RD_IO_REG         0x00C4
+#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE  0x00C3
+#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE  0x00C2
+
+#define ADV_TICKLE_NOP                      0x00
+#define ADV_TICKLE_A                        0x01
+#define ADV_TICKLE_B                        0x02
+#define ADV_TICKLE_C                        0x03
+
+#define ADV_SCSI_CTRL_RSTOUT        0x2000
+
+#define AdvIsIntPending(port) \
+    (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
+
+/*
+ * SCSI_CFG0 Register bit definitions
+ */
+#define TIMER_MODEAB    0xC000  /* Watchdog, Second, and Select. Timer Ctrl. */
+#define PARITY_EN       0x2000  /* Enable SCSI Parity Error detection */
+#define EVEN_PARITY     0x1000  /* Select Even Parity */
+#define WD_LONG         0x0800  /* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define QUEUE_128       0x0400  /* Queue Size, 1: 128 byte, 0: 64 byte */
+#define PRIM_MODE       0x0100  /* Primitive SCSI mode */
+#define SCAM_EN         0x0080  /* Enable SCAM selection */
+#define SEL_TMO_LONG    0x0040  /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define CFRM_ID         0x0020  /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define OUR_ID_EN       0x0010  /* Enable OUR_ID bits */
+#define OUR_ID          0x000F  /* SCSI ID */
+
+/*
+ * SCSI_CFG1 Register bit definitions
+ */
+#define BIG_ENDIAN      0x8000  /* Enable Big Endian Mode MIO:15, EEP:15 */
+#define TERM_POL        0x2000  /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define SLEW_RATE       0x1000  /* SCSI output buffer slew rate */
+#define FILTER_SEL      0x0C00  /* Filter Period Selection */
+#define  FLTR_DISABLE    0x0000  /* Input Filtering Disabled */
+#define  FLTR_11_TO_20NS 0x0800  /* Input Filtering 11ns to 20ns */
+#define  FLTR_21_TO_39NS 0x0C00  /* Input Filtering 21ns to 39ns */
+#define ACTIVE_DBL      0x0200  /* Disable Active Negation */
+#define DIFF_MODE       0x0100  /* SCSI differential Mode (Read-Only) */
+#define DIFF_SENSE      0x0080  /* 1: No SE cables, 0: SE cable (Read-Only) */
+#define TERM_CTL_SEL    0x0040  /* Enable TERM_CTL_H and TERM_CTL_L */
+#define TERM_CTL        0x0030  /* External SCSI Termination Bits */
+#define  TERM_CTL_H      0x0020  /* Enable External SCSI Upper Termination */
+#define  TERM_CTL_L      0x0010  /* Enable External SCSI Lower Termination */
+#define CABLE_DETECT    0x000F  /* External SCSI Cable Connection Status */
+
+/*
+ * Addendum for ASC-38C0800 Chip
+ *
+ * The ASC-38C1600 Chip uses the same definitions except that the
+ * bus mode override bits [12:10] have been moved to byte register
+ * offset 0xE (IOPB_SOFT_OVER_WR) bits [12:10]. The [12:10] bits in
+ * SCSI_CFG1 are read-only and always available. Bit 14 (DIS_TERM_DRV)
+ * is not needed. The [12:10] bits in IOPB_SOFT_OVER_WR are write-only.
+ * Also each ASC-38C1600 function or channel uses only cable bits [5:4]
+ * and [1:0]. Bits [14], [7:6], [3:2] are unused.
+ */
+#define DIS_TERM_DRV    0x4000  /* 1: Read c_det[3:0], 0: cannot read */
+#define HVD_LVD_SE      0x1C00  /* Device Detect Bits */
+#define  HVD             0x1000  /* HVD Device Detect */
+#define  LVD             0x0800  /* LVD Device Detect */
+#define  SE              0x0400  /* SE Device Detect */
+#define TERM_LVD        0x00C0  /* LVD Termination Bits */
+#define  TERM_LVD_HI     0x0080  /* Enable LVD Upper Termination */
+#define  TERM_LVD_LO     0x0040  /* Enable LVD Lower Termination */
+#define TERM_SE         0x0030  /* SE Termination Bits */
+#define  TERM_SE_HI      0x0020  /* Enable SE Upper Termination */
+#define  TERM_SE_LO      0x0010  /* Enable SE Lower Termination */
+#define C_DET_LVD       0x000C  /* LVD Cable Detect Bits */
+#define  C_DET3          0x0008  /* Cable Detect for LVD External Wide */
+#define  C_DET2          0x0004  /* Cable Detect for LVD Internal Wide */
+#define C_DET_SE        0x0003  /* SE Cable Detect Bits */
+#define  C_DET1          0x0002  /* Cable Detect for SE Internal Wide */
+#define  C_DET0          0x0001  /* Cable Detect for SE Internal Narrow */
+
+
+#define CABLE_ILLEGAL_A 0x7
+    /* x 0 0 0  | on  on | Illegal (all 3 connectors are used) */
+
+#define CABLE_ILLEGAL_B 0xB
+    /* 0 x 0 0  | on  on | Illegal (all 3 connectors are used) */
+
+/*
+ * MEM_CFG Register bit definitions
+ */
+#define BIOS_EN         0x40    /* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK     0x20    /* Diagnostic Bit */
+#define RAM_SZ          0x1C    /* Specify size of RAM to RISC */
+#define  RAM_SZ_2KB      0x00    /* 2 KB */
+#define  RAM_SZ_4KB      0x04    /* 4 KB */
+#define  RAM_SZ_8KB      0x08    /* 8 KB */
+#define  RAM_SZ_16KB     0x0C    /* 16 KB */
+#define  RAM_SZ_32KB     0x10    /* 32 KB */
+#define  RAM_SZ_64KB     0x14    /* 64 KB */
+
+/*
+ * DMA_CFG0 Register bit definitions
+ *
+ * This register is only accessible to the host.
+ */
+#define BC_THRESH_ENB   0x80    /* PCI DMA Start Conditions */
+#define FIFO_THRESH     0x70    /* PCI DMA FIFO Threshold */
+#define  FIFO_THRESH_16B  0x00   /* 16 bytes */
+#define  FIFO_THRESH_32B  0x20   /* 32 bytes */
+#define  FIFO_THRESH_48B  0x30   /* 48 bytes */
+#define  FIFO_THRESH_64B  0x40   /* 64 bytes */
+#define  FIFO_THRESH_80B  0x50   /* 80 bytes (default) */
+#define  FIFO_THRESH_96B  0x60   /* 96 bytes */
+#define  FIFO_THRESH_112B 0x70   /* 112 bytes */
+#define START_CTL       0x0C    /* DMA start conditions */
+#define  START_CTL_TH    0x00    /* Wait threshold level (default) */
+#define  START_CTL_ID    0x04    /* Wait SDMA/SBUS idle */
+#define  START_CTL_THID  0x08    /* Wait threshold and SDMA/SBUS idle */
+#define  START_CTL_EMFU  0x0C    /* Wait SDMA FIFO empty/full */
+#define READ_CMD        0x03    /* Memory Read Method */
+#define  READ_CMD_MR     0x00    /* Memory Read */
+#define  READ_CMD_MRL    0x02    /* Memory Read Long */
+#define  READ_CMD_MRM    0x03    /* Memory Read Multiple (default) */
+
+/*
+ * ASC-38C0800 RAM BIST Register bit definitions
+ */
+#define RAM_TEST_MODE         0x80
+#define PRE_TEST_MODE         0x40
+#define NORMAL_MODE           0x00
+#define RAM_TEST_DONE         0x10
+#define RAM_TEST_STATUS       0x0F
+#define  RAM_TEST_HOST_ERROR   0x08
+#define  RAM_TEST_INTRAM_ERROR 0x04
+#define  RAM_TEST_RISC_ERROR   0x02
+#define  RAM_TEST_SCSI_ERROR   0x01
+#define  RAM_TEST_SUCCESS      0x00
+#define PRE_TEST_VALUE        0x05
+#define NORMAL_VALUE          0x00
+
+/*
+ * ASC38C1600 Definitions
+ *
+ * IOPB_PCI_INT_CFG Bit Field Definitions
+ */
+
+#define INTAB_LD        0x80    /* Value loaded from EEPROM Bit 11. */
+
+/*
+ * Bit 1 can be set to change the interrupt for the Function to operate in
+ * Totem Pole mode. By default Bit 1 is 0 and the interrupt operates in
+ * Open Drain mode. Both functions of the ASC38C1600 must be set to the same
+ * mode, otherwise the operating mode is undefined.
+ */
+#define TOTEMPOLE       0x02
+
+/*
+ * Bit 0 can be used to change the Int Pin for the Function. The value is
+ * 0 by default for both Functions with Function 0 using INT A and Function
+ * B using INT B. For Function 0 if set, INT B is used. For Function 1 if set,
+ * INT A is used.
+ *
+ * EEPROM Word 0 Bit 11 for each Function may change the initial Int Pin
+ * value specified in the PCI Configuration Space.
+ */
+#define INTAB           0x01
+
+/* a_advlib.h */
+
+/*
+ * Adv Library Status Definitions
+ */
+#define ADV_TRUE        1
+#define ADV_FALSE       0
+#define ADV_NOERROR     1
+#define ADV_SUCCESS     1
+#define ADV_BUSY        0
+#define ADV_ERROR       (-1)
+
+
+/*
+ * ADV_DVC_VAR 'warn_code' values
+ */
+#define ASC_WARN_BUSRESET_ERROR         0x0001 /* SCSI Bus Reset error */
+#define ASC_WARN_EEPROM_CHKSUM          0x0002 /* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION     0x0004 /* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE   0x0080 /* PCI config space set error */
+#define ASC_WARN_ERROR                  0xFFFF /* ADV_ERROR return */
+
+#define ADV_MAX_TID                     15 /* max. target identifier */
+#define ADV_MAX_LUN                     7  /* max. logical unit number */
+
+/*
+ * Error code values are set in ADV_DVC_VAR 'err_code'.
+ */
+#define ASC_IERR_WRITE_EEPROM       0x0001 /* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM       0x0002 /* micro code check sum error */
+#define ASC_IERR_NO_CARRIER         0x0004 /* No more carrier memory. */
+#define ASC_IERR_START_STOP_CHIP    0x0008 /* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION       0x0040 /* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID        0x0080 /* set SCSI ID failed */
+#define ASC_IERR_HVD_DEVICE         0x0100 /* HVD attached to LVD connector. */
+#define ASC_IERR_BAD_SIGNATURE      0x0200 /* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE  0x0800 /* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE     0x1000 /* Narrow flat cable reversed */
+#define ASC_IERR_BIST_PRE_TEST      0x2000 /* BIST pre-test error */
+#define ASC_IERR_BIST_RAM_TEST      0x4000 /* BIST RAM test error */
+#define ASC_IERR_BAD_CHIPTYPE       0x8000 /* Invalid 'chip_type' setting. */
+
+/*
+ * Fixed locations of microcode operating variables.
+ */
+#define ASC_MC_CODE_BEGIN_ADDR          0x0028 /* microcode start address */
+#define ASC_MC_CODE_END_ADDR            0x002A /* microcode end address */
+#define ASC_MC_CODE_CHK_SUM             0x002C /* microcode code checksum */
+#define ASC_MC_VERSION_DATE             0x0038 /* microcode version */
+#define ASC_MC_VERSION_NUM              0x003A /* microcode number */
+#define ASC_MC_BIOSMEM                  0x0040 /* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN                  0x0050 /* BIOS RISC Memory Length */
+#define ASC_MC_BIOS_SIGNATURE           0x0058 /* BIOS Signature 0x55AA */
+#define ASC_MC_BIOS_VERSION             0x005A /* BIOS Version (2 bytes) */
+#define ASC_MC_SDTR_SPEED1              0x0090 /* SDTR Speed for TID 0-3 */
+#define ASC_MC_SDTR_SPEED2              0x0092 /* SDTR Speed for TID 4-7 */
+#define ASC_MC_SDTR_SPEED3              0x0094 /* SDTR Speed for TID 8-11 */
+#define ASC_MC_SDTR_SPEED4              0x0096 /* SDTR Speed for TID 12-15 */
+#define ASC_MC_CHIP_TYPE                0x009A
+#define ASC_MC_INTRB_CODE               0x009B
+#define ASC_MC_WDTR_ABLE                0x009C
+#define ASC_MC_SDTR_ABLE                0x009E
+#define ASC_MC_TAGQNG_ABLE              0x00A0
+#define ASC_MC_DISC_ENABLE              0x00A2
+#define ASC_MC_IDLE_CMD_STATUS          0x00A4
+#define ASC_MC_IDLE_CMD                 0x00A6
+#define ASC_MC_IDLE_CMD_PARAMETER       0x00A8
+#define ASC_MC_DEFAULT_SCSI_CFG0        0x00AC
+#define ASC_MC_DEFAULT_SCSI_CFG1        0x00AE
+#define ASC_MC_DEFAULT_MEM_CFG          0x00B0
+#define ASC_MC_DEFAULT_SEL_MASK         0x00B2
+#define ASC_MC_SDTR_DONE                0x00B6
+#define ASC_MC_NUMBER_OF_QUEUED_CMD     0x00C0
+#define ASC_MC_NUMBER_OF_MAX_CMD        0x00D0
+#define ASC_MC_DEVICE_HSHK_CFG_TABLE    0x0100
+#define ASC_MC_CONTROL_FLAG             0x0122 /* Microcode control flag. */
+#define ASC_MC_WDTR_DONE                0x0124
+#define ASC_MC_CAM_MODE_MASK            0x015E /* CAM mode TID bitmask. */
+#define ASC_MC_ICQ                      0x0160
+#define ASC_MC_IRQ                      0x0164
+#define ASC_MC_PPR_ABLE                 0x017A
+
+/*
+ * BIOS LRAM variable absolute offsets.
+ */
+#define BIOS_CODESEG    0x54
+#define BIOS_CODELEN    0x56
+#define BIOS_SIGNATURE  0x58
+#define BIOS_VERSION    0x5A
+
+/*
+ * Microcode Control Flags
+ *
+ * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
+ * and handled by the microcode.
+ */
+#define CONTROL_FLAG_IGNORE_PERR        0x0001 /* Ignore DMA Parity Errors */
+#define CONTROL_FLAG_ENABLE_AIPP        0x0002 /* Enabled AIPP checking. */
+
+/*
+ * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
+ */
+#define HSHK_CFG_WIDE_XFR       0x8000
+#define HSHK_CFG_RATE           0x0F00
+#define HSHK_CFG_OFFSET         0x001F
+
+#define ASC_DEF_MAX_HOST_QNG    0xFD /* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG    0x10 /* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG     0x3F /* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG     0x04 /* Min. number commands per device (4) */
+
+#define ASC_QC_DATA_CHECK  0x01 /* Require ASC_QC_DATA_OUT set or clear. */
+#define ASC_QC_DATA_OUT    0x02 /* Data out DMA transfer. */
+#define ASC_QC_START_MOTOR 0x04 /* Send auto-start motor before request. */
+#define ASC_QC_NO_OVERRUN  0x08 /* Don't report overrun. */
+#define ASC_QC_FREEZE_TIDQ 0x10 /* Freeze TID queue after request. XXX TBD */
+
+#define ASC_QSC_NO_DISC     0x01 /* Don't allow disconnect for request. */
+#define ASC_QSC_NO_TAGMSG   0x02 /* Don't allow tag queuing for request. */
+#define ASC_QSC_NO_SYNC     0x04 /* Don't use Synch. transfer on request. */
+#define ASC_QSC_NO_WIDE     0x08 /* Don't use Wide transfer on request. */
+#define ASC_QSC_REDO_DTR    0x10 /* Renegotiate WDTR/SDTR before request. */
+/*
+ * Note: If a Tag Message is to be sent and neither ASC_QSC_HEAD_TAG or
+ * ASC_QSC_ORDERED_TAG is set, then a Simple Tag Message (0x20) is used.
+ */
+#define ASC_QSC_HEAD_TAG    0x40 /* Use Head Tag Message (0x21). */
+#define ASC_QSC_ORDERED_TAG 0x80 /* Use Ordered Tag Message (0x22). */
+
+/*
+ * All fields here are accessed by the board microcode and need to be
+ * little-endian.
+ */
+typedef struct adv_carr_t
+{
+    ADV_VADDR   carr_va;       /* Carrier Virtual Address */
+    ADV_PADDR   carr_pa;       /* Carrier Physical Address */
+    ADV_VADDR   areq_vpa;      /* ASC_SCSI_REQ_Q Virtual or Physical Address */
+    /*
+     * next_vpa [31:4]            Carrier Virtual or Physical Next Pointer
+     *
+     * next_vpa [3:1]             Reserved Bits
+     * next_vpa [0]               Done Flag set in Response Queue.
+     */
+    ADV_VADDR   next_vpa;
+} ADV_CARR_T;
+
+/*
+ * Mask used to eliminate low 4 bits of carrier 'next_vpa' field.
+ */
+#define ASC_NEXT_VPA_MASK       0xFFFFFFF0
+
+#define ASC_RQ_DONE             0x00000001
+#define ASC_RQ_GOOD             0x00000002
+#define ASC_CQ_STOPPER          0x00000000
+
+#define ASC_GET_CARRP(carrp) ((carrp) & ASC_NEXT_VPA_MASK)
+
+#define ADV_CARRIER_NUM_PAGE_CROSSING \
+    (((ADV_CARRIER_COUNT * sizeof(ADV_CARR_T)) + \
+        (ADV_PAGE_SIZE - 1))/ADV_PAGE_SIZE)
+
+#define ADV_CARRIER_BUFSIZE \
+    ((ADV_CARRIER_COUNT + ADV_CARRIER_NUM_PAGE_CROSSING) * sizeof(ADV_CARR_T))
+
+/*
+ * ASC_SCSI_REQ_Q 'a_flag' definitions
+ *
+ * The Adv Library should limit use to the lower nibble (4 bits) of
+ * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
+ */
+#define ADV_POLL_REQUEST                0x01   /* poll for request completion */
+#define ADV_SCSIQ_DONE                  0x02   /* request done */
+#define ADV_DONT_RETRY                  0x08   /* don't do retry */
+
+#define ADV_CHIP_ASC3550          0x01   /* Ultra-Wide IC */
+#define ADV_CHIP_ASC38C0800       0x02   /* Ultra2-Wide/LVD IC */
+#define ADV_CHIP_ASC38C1600       0x03   /* Ultra3-Wide/LVD2 IC */
+
+/*
+ * Adapter temporary configuration structure
+ *
+ * This structure can be discarded after initialization. Don't add
+ * fields here needed after initialization.
+ *
+ * Field naming convention:
+ *
+ *  *_enable indicates the field enables or disables a feature. The
+ *  value of the field is never reset.
+ */
+typedef struct adv_dvc_cfg {
+  ushort disc_enable;       /* enable disconnection */
+  uchar  chip_version;      /* chip version */
+  uchar  termination;       /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+  ushort lib_version;       /* Adv Library version number */
+  ushort control_flag;      /* Microcode Control Flag */
+  ushort mcode_date;        /* Microcode date */
+  ushort mcode_version;     /* Microcode version */
+  ushort pci_slot_info;     /* high byte device/function number */
+                            /* bits 7-3 device num., bits 2-0 function num. */
+                            /* low byte bus num. */
+  ushort serial1;           /* EEPROM serial number word 1 */
+  ushort serial2;           /* EEPROM serial number word 2 */
+  ushort serial3;           /* EEPROM serial number word 3 */
+  struct device *dev;  /* pointer to the pci dev structure for this board */
+} ADV_DVC_CFG;
+
+struct adv_dvc_var;
+struct adv_scsi_req_q;
+
+typedef void (* ADV_ISR_CALLBACK)
+    (struct adv_dvc_var *, struct adv_scsi_req_q *);
+
+typedef void (* ADV_ASYNC_CALLBACK)
+    (struct adv_dvc_var *, uchar);
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ *  *_able indicates both whether a feature should be enabled or disabled
+ *  and whether a device isi capable of the feature. At initialization
+ *  this field may be set, but later if a device is found to be incapable
+ *  of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+  AdvPortAddr iop_base;   /* I/O port address */
+  ushort err_code;        /* fatal error code */
+  ushort bios_ctrl;       /* BIOS control word, EEPROM word 12 */
+  ADV_ISR_CALLBACK isr_callback;
+  ADV_ASYNC_CALLBACK async_callback;
+  ushort wdtr_able;       /* try WDTR for a device */
+  ushort sdtr_able;       /* try SDTR for a device */
+  ushort ultra_able;      /* try SDTR Ultra speed for a device */
+  ushort sdtr_speed1;     /* EEPROM SDTR Speed for TID 0-3   */
+  ushort sdtr_speed2;     /* EEPROM SDTR Speed for TID 4-7   */
+  ushort sdtr_speed3;     /* EEPROM SDTR Speed for TID 8-11  */
+  ushort sdtr_speed4;     /* EEPROM SDTR Speed for TID 12-15 */
+  ushort tagqng_able;     /* try tagged queuing with a device */
+  ushort ppr_able;        /* PPR message capable per TID bitmask. */
+  uchar  max_dvc_qng;     /* maximum number of tagged commands per device */
+  ushort start_motor;     /* start motor command allowed */
+  uchar  scsi_reset_wait; /* delay in seconds after scsi bus reset */
+  uchar  chip_no;         /* should be assigned by caller */
+  uchar  max_host_qng;    /* maximum number of Q'ed command allowed */
+  uchar  irq_no;          /* IRQ number */
+  ushort no_scam;         /* scam_tolerant of EEPROM */
+  struct asc_board *drv_ptr; /* driver pointer to private structure */
+  uchar  chip_scsi_id;    /* chip SCSI target ID */
+  uchar  chip_type;
+  uchar  bist_err_code;
+  ADV_CARR_T *carrier_buf;
+  ADV_CARR_T *carr_freelist; /* Carrier free list. */
+  ADV_CARR_T *icq_sp;  /* Initiator command queue stopper pointer. */
+  ADV_CARR_T *irq_sp;  /* Initiator response queue stopper pointer. */
+  ushort carr_pending_cnt;    /* Count of pending carriers. */
+ /*
+  * Note: The following fields will not be used after initialization. The
+  * driver may discard the buffer after initialization is done.
+  */
+  ADV_DVC_CFG *cfg; /* temporary configuration structure  */
+} ADV_DVC_VAR;
+
+#define NO_OF_SG_PER_BLOCK              15
+
+typedef struct asc_sg_block {
+    uchar reserved1;
+    uchar reserved2;
+    uchar reserved3;
+    uchar sg_cnt;                     /* Valid entries in block. */
+    ADV_PADDR sg_ptr;                 /* Pointer to next sg block. */
+    struct  {
+        ADV_PADDR sg_addr;                  /* SG element address. */
+        ADV_DCNT  sg_count;                 /* SG element count. */
+    } sg_list[NO_OF_SG_PER_BLOCK];
+} ADV_SG_BLOCK;
+
+/*
+ * ADV_SCSI_REQ_Q - microcode request structure
+ *
+ * All fields in this structure up to byte 60 are used by the microcode.
+ * The microcode makes assumptions about the size and ordering of fields
+ * in this structure. Do not change the structure definition here without
+ * coordinating the change with the microcode.
+ *
+ * All fields accessed by microcode must be maintained in little_endian
+ * order.
+ */
+typedef struct adv_scsi_req_q {
+    uchar       cntl;           /* Ucode flags and state (ASC_MC_QC_*). */
+    uchar       target_cmd;
+    uchar       target_id;      /* Device target identifier. */
+    uchar       target_lun;     /* Device target logical unit number. */
+    ADV_PADDR   data_addr;      /* Data buffer physical address. */
+    ADV_DCNT    data_cnt;       /* Data count. Ucode sets to residual. */
+    ADV_PADDR   sense_addr;
+    ADV_PADDR   carr_pa;
+    uchar       mflag;
+    uchar       sense_len;
+    uchar       cdb_len;        /* SCSI CDB length. Must <= 16 bytes. */
+    uchar       scsi_cntl;
+    uchar       done_status;    /* Completion status. */
+    uchar       scsi_status;    /* SCSI status byte. */
+    uchar       host_status;    /* Ucode host status. */
+    uchar       sg_working_ix;
+    uchar       cdb[12];        /* SCSI CDB bytes 0-11. */
+    ADV_PADDR   sg_real_addr;   /* SG list physical address. */
+    ADV_PADDR   scsiq_rptr;
+    uchar       cdb16[4];       /* SCSI CDB bytes 12-15. */
+    ADV_VADDR   scsiq_ptr;
+    ADV_VADDR   carr_va;
+    /*
+     * End of microcode structure - 60 bytes. The rest of the structure
+     * is used by the Adv Library and ignored by the microcode.
+     */
+    ADV_VADDR   srb_ptr;
+    ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+    char        *vdata_addr;   /* Data buffer virtual address. */
+    uchar       a_flag;
+    uchar       pad[2];        /* Pad out to a word boundary. */
+} ADV_SCSI_REQ_Q;
+
+/*
+ * Microcode idle loop commands
+ */
+#define IDLE_CMD_COMPLETED           0
+#define IDLE_CMD_STOP_CHIP           0x0001
+#define IDLE_CMD_STOP_CHIP_SEND_INT  0x0002
+#define IDLE_CMD_SEND_INT            0x0004
+#define IDLE_CMD_ABORT               0x0008
+#define IDLE_CMD_DEVICE_RESET        0x0010
+#define IDLE_CMD_SCSI_RESET_START    0x0020 /* Assert SCSI Bus Reset */
+#define IDLE_CMD_SCSI_RESET_END      0x0040 /* Deassert SCSI Bus Reset */
+#define IDLE_CMD_SCSIREQ             0x0080
+
+#define IDLE_CMD_STATUS_SUCCESS      0x0001
+#define IDLE_CMD_STATUS_FAILURE      0x0002
+
+/*
+ * AdvSendIdleCmd() flag definitions.
+ */
+#define ADV_NOWAIT     0x01
+
+/*
+ * Wait loop time out values.
+ */
+#define SCSI_WAIT_10_SEC             10UL    /* 10 seconds */
+#define SCSI_WAIT_100_MSEC           100UL   /* 100 milliseconds */
+#define SCSI_US_PER_MSEC             1000    /* microseconds per millisecond */
+#define SCSI_MS_PER_SEC              1000UL  /* milliseconds per second */
+#define SCSI_MAX_RETRY               10      /* retry count */
+
+#define ADV_ASYNC_RDMA_FAILURE          0x01 /* Fatal RDMA failure. */
+#define ADV_ASYNC_SCSI_BUS_RESET_DET    0x02 /* Detected SCSI Bus Reset. */
+#define ADV_ASYNC_CARRIER_READY_FAILURE 0x03 /* Carrier Ready failure. */
+#define ADV_RDMA_IN_CARR_AND_Q_INVALID  0x04 /* RDMAed-in data invalid. */
+
+
+#define ADV_HOST_SCSI_BUS_RESET      0x80 /* Host Initiated SCSI Bus Reset. */
+
+/*
+ * Device drivers must define the following functions.
+ */
+STATIC inline ulong DvcEnterCritical(void);
+STATIC inline void  DvcLeaveCritical(ulong);
+STATIC void  DvcSleepMilliSecond(ADV_DCNT);
+STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
+STATIC void  DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
+STATIC ADV_PADDR DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+                uchar *, ASC_SDCNT *, int);
+STATIC void  DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
+
+/*
+ * Adv Library functions available to drivers.
+ */
+STATIC int     AdvExeScsiQueue(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int     AdvISR(ADV_DVC_VAR *);
+STATIC int     AdvInitGetConfig(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc3550Driver(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc38C0800Driver(ADV_DVC_VAR *);
+STATIC int     AdvInitAsc38C1600Driver(ADV_DVC_VAR *);
+STATIC int     AdvResetChipAndSB(ADV_DVC_VAR *);
+STATIC int     AdvResetSB(ADV_DVC_VAR *asc_dvc);
+
+/*
+ * Internal Adv Library functions.
+ */
+STATIC int    AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ADV_DCNT);
+STATIC void   AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int    AdvInitFrom3550EEP(ADV_DVC_VAR *);
+STATIC int    AdvInitFrom38C0800EEP(ADV_DVC_VAR *);
+STATIC int    AdvInitFrom38C1600EEP(ADV_DVC_VAR *);
+STATIC ushort AdvGet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC void   AdvSet3550EEPConfig(AdvPortAddr, ADVEEP_3550_CONFIG *);
+STATIC ushort AdvGet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC void   AdvSet38C0800EEPConfig(AdvPortAddr, ADVEEP_38C0800_CONFIG *);
+STATIC ushort AdvGet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+STATIC void   AdvSet38C1600EEPConfig(AdvPortAddr, ADVEEP_38C1600_CONFIG *);
+STATIC void   AdvWaitEEPCmd(AdvPortAddr);
+STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
+
+/*
+ * PCI Bus Definitions
+ */
+#define AscPCICmdRegBits_BusMastering     0x0007
+#define AscPCICmdRegBits_ParErrRespCtrl   0x0040
+
+/* Read byte from a register. */
+#define AdvReadByteRegister(iop_base, reg_off) \
+     (ADV_MEM_READB((iop_base) + (reg_off)))
+
+/* Write byte to a register. */
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+     (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
+
+/* Read word (2 bytes) from a register. */
+#define AdvReadWordRegister(iop_base, reg_off) \
+     (ADV_MEM_READW((iop_base) + (reg_off)))
+
+/* Write word (2 bytes) to a register. */
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+     (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
+
+/* Write dword (4 bytes) to a register. */
+#define AdvWriteDWordRegister(iop_base, reg_off, dword) \
+     (ADV_MEM_WRITEDW((iop_base) + (reg_off), (dword)))
+
+/* Read byte from LRAM. */
+#define AdvReadByteLram(iop_base, addr, byte) \
+do { \
+    ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+    (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define AdvWriteByteLram(iop_base, addr, byte) \
+    (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
+
+/* Read word (2 bytes) from LRAM. */
+#define AdvReadWordLram(iop_base, addr, word) \
+do { \
+    ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+    (word) = (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA)); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define AdvWriteWordLram(iop_base, addr, word) \
+    (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+     ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+/* Write little-endian double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define AdvWriteDWordLramNoSwap(iop_base, addr, dword) \
+    ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+      ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+                     cpu_to_le16((ushort) ((dword) & 0xFFFF)))), \
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
+      ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+                     cpu_to_le16((ushort) ((dword >> 16) & 0xFFFF)))))
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define AdvReadWordAutoIncLram(iop_base) \
+     (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define AdvWriteWordAutoIncLram(iop_base, word) \
+     (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+
+/*
+ * Define macro to check for Condor signature.
+ *
+ * Evaluate to ADV_TRUE if a Condor chip is found the specified port
+ * address 'iop_base'. Otherwise evalue to ADV_FALSE.
+ */
+#define AdvFindSignature(iop_base) \
+    (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
+    ADV_CHIP_ID_BYTE) && \
+     (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
+    ADV_CHIP_ID_WORD)) ?  ADV_TRUE : ADV_FALSE)
+
+/*
+ * Define macro to Return the version number of the chip at 'iop_base'.
+ *
+ * The second parameter 'bus_type' is currently unused.
+ */
+#define AdvGetChipVersion(iop_base, bus_type) \
+    AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
+
+/*
+ * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
+ * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
+ *
+ * If the request has not yet been sent to the device it will simply be
+ * aborted from RISC memory. If the request is disconnected it will be
+ * aborted on reselection by sending an Abort Message to the target ID.
+ *
+ * Return value:
+ *      ADV_TRUE(1) - Queue was successfully aborted.
+ *      ADV_FALSE(0) - Queue was not found on the active queue list.
+ */
+#define AdvAbortQueue(asc_dvc, scsiq) \
+        AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+                       (ADV_DCNT) (scsiq))
+
+/*
+ * Send a Bus Device Reset Message to the specified target ID.
+ *
+ * All outstanding commands will be purged if sending the
+ * Bus Device Reset Message is successful.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) - All requests on the target are purged.
+ *      ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
+ *                     are not purged.
+ */
+#define AdvResetDevice(asc_dvc, target_id) \
+        AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
+                    (ADV_DCNT) (target_id))
+
+/*
+ * SCSI Wide Type definition.
+ */
+#define ADV_SCSI_BIT_ID_TYPE   ushort
+
+/*
+ * AdvInitScsiTarget() 'cntl_flag' options.
+ */
+#define ADV_SCAN_LUN           0x01
+#define ADV_CAPINFO_NOLUN      0x02
+
+/*
+ * Convert target id to target id bit mask.
+ */
+#define ADV_TID_TO_TIDMASK(tid)   (0x01 << ((tid) & ADV_MAX_TID))
+
+/*
+ * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
+ */
+
+#define QD_NO_STATUS         0x00       /* Request not completed yet. */
+#define QD_NO_ERROR          0x01
+#define QD_ABORTED_BY_HOST   0x02
+#define QD_WITH_ERROR        0x04
+
+#define QHSTA_NO_ERROR              0x00
+#define QHSTA_M_SEL_TIMEOUT         0x11
+#define QHSTA_M_DATA_OVER_RUN       0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
+#define QHSTA_M_QUEUE_ABORTED       0x15
+#define QHSTA_M_SXFR_SDMA_ERR       0x16 /* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR      0x17 /* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR           0x18 /* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW       0x19 /* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW       0x20 /* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO         0x21 /* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED     0x22 /* SXFR_STATUS Deselected */
+/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
+#define QHSTA_M_SXFR_XFR_OFLW       0x12 /* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR     0x24 /* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR  0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_SCSI_BUS_RESET      0x30 /* Request aborted from SBR */
+#define QHSTA_M_SCSI_BUS_RESET_UNSOL 0x31 /* Request aborted from unsol. SBR */
+#define QHSTA_M_BUS_DEVICE_RESET    0x32 /* Request aborted from BDR */
+#define QHSTA_M_DIRECTION_ERR       0x35 /* Data Phase mismatch */
+#define QHSTA_M_DIRECTION_ERR_HUNG  0x36 /* Data Phase mismatch and bus hang */
+#define QHSTA_M_WTM_TIMEOUT         0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN  0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE   0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_INVALID_DEVICE      0x45 /* Bad target ID */
+#define QHSTA_M_FROZEN_TIDQ         0x46 /* TID Queue frozen. */
+#define QHSTA_M_SGBACKUP_ERROR      0x47 /* Scatter-Gather backup error */
+
+
+/*
+ * Default EEPROM Configuration structure defined in a_init.c.
+ */
+static ADVEEP_3550_CONFIG Default_3550_EEPROM_Config;
+static ADVEEP_38C0800_CONFIG Default_38C0800_EEPROM_Config;
+static ADVEEP_38C1600_CONFIG Default_38C1600_EEPROM_Config;
+
+/*
+ * DvcGetPhyAddr() flag arguments
+ */
+#define ADV_IS_SCSIQ_FLAG       0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
+#define ADV_ASCGETSGLIST_VADDR  0x02 /* 'addr' is AscGetSGList() virtual addr */
+#define ADV_IS_SENSE_FLAG       0x04 /* 'addr' is sense virtual pointer */
+#define ADV_IS_DATA_FLAG        0x08 /* 'addr' is data virtual pointer */
+#define ADV_IS_SGLIST_FLAG      0x10 /* 'addr' is sglist virtual pointer */
+#define ADV_IS_CARRIER_FLAG     0x20 /* 'addr' is ADV_CARR_T pointer */
+
+/* Return the address that is aligned at the next doubleword >= to 'addr'. */
+#define ADV_8BALIGN(addr)      (((ulong) (addr) + 0x7) & ~0x7)
+#define ADV_16BALIGN(addr)     (((ulong) (addr) + 0xF) & ~0xF)
+#define ADV_32BALIGN(addr)     (((ulong) (addr) + 0x1F) & ~0x1F)
+
+/*
+ * Total contiguous memory needed for driver SG blocks.
+ *
+ * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
+ * number of scatter-gather elements the driver supports in a
+ * single request.
+ */
+
+#define ADV_SG_LIST_MAX_BYTE_SIZE \
+         (sizeof(ADV_SG_BLOCK) * \
+          ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
+
+/*
+ * Inquiry data structure and bitfield macros
+ *
+ * Using bitfields to access the subchar data isn't portable across
+ * endianness, so instead mask and shift. Only quantities of more
+ * than 1 bit are shifted, since the others are just tested for true
+ * or false.
+ */
+
+#define ADV_INQ_DVC_TYPE(inq)       ((inq)->periph & 0x1f)
+#define ADV_INQ_QUALIFIER(inq)      (((inq)->periph & 0xe0) >> 5)
+#define ADV_INQ_DVC_TYPE_MOD(inq)   ((inq)->devtype & 0x7f)
+#define ADV_INQ_REMOVABLE(inq)      ((inq)->devtype & 0x80)
+#define ADV_INQ_ANSI_VER(inq)       ((inq)->ver & 0x07)
+#define ADV_INQ_ECMA_VER(inq)       (((inq)->ver & 0x38) >> 3)
+#define ADV_INQ_ISO_VER(inq)        (((inq)->ver & 0xc0) >> 6)
+#define ADV_INQ_RESPONSE_FMT(inq)   ((inq)->byte3 & 0x0f)
+#define ADV_INQ_TERM_IO(inq)        ((inq)->byte3 & 0x40)
+#define ADV_INQ_ASYNC_NOTIF(inq)    ((inq)->byte3 & 0x80)
+#define ADV_INQ_SOFT_RESET(inq)     ((inq)->flags & 0x01)
+#define ADV_INQ_CMD_QUEUE(inq)      ((inq)->flags & 0x02)
+#define ADV_INQ_LINK_CMD(inq)       ((inq)->flags & 0x08)
+#define ADV_INQ_SYNC(inq)           ((inq)->flags & 0x10)
+#define ADV_INQ_WIDE16(inq)         ((inq)->flags & 0x20)
+#define ADV_INQ_WIDE32(inq)         ((inq)->flags & 0x40)
+#define ADV_INQ_REL_ADDR(inq)       ((inq)->flags & 0x80)
+#define ADV_INQ_INFO_UNIT(inq)      ((inq)->info & 0x01)
+#define ADV_INQ_QUICK_ARB(inq)      ((inq)->info & 0x02)
+#define ADV_INQ_CLOCKING(inq)       (((inq)->info & 0x0c) >> 2)
+
+typedef struct {
+  uchar periph;                 /* peripheral device type [0:4] */
+                                /* peripheral qualifier [5:7] */
+  uchar devtype;                /* device type modifier (for SCSI I) [0:6] */
+                                /* RMB - removable medium bit [7] */
+  uchar ver;                    /* ANSI approved version [0:2] */
+                                /* ECMA version [3:5] */
+                                /* ISO version [6:7] */
+  uchar byte3;                  /* response data format [0:3] */
+                                /* 0 SCSI 1 */
+                                /* 1 CCS */
+                                /* 2 SCSI-2 */
+                                /* 3-F reserved */
+                                /* reserved [4:5] */
+                                /* terminate I/O process bit (see 5.6.22) [6] */
+                                /* asynch. event notification (processor) [7] */
+  uchar add_len;                /* additional length */
+  uchar res1;                   /* reserved */
+  uchar res2;                   /* reserved */
+  uchar flags;                  /* soft reset implemented [0] */
+                                /* command queuing [1] */
+                                /* reserved [2] */
+                                /* linked command for this logical unit [3] */
+                                /* synchronous data transfer [4] */
+                                /* wide bus 16 bit data transfer [5] */
+                                /* wide bus 32 bit data transfer [6] */
+                                /* relative addressing mode [7] */
+  uchar vendor_id[8];           /* vendor identification */
+  uchar product_id[16];         /* product identification */
+  uchar product_rev_level[4];   /* product revision level */
+  uchar vendor_specific[20];    /* vendor specific */
+  uchar info;                   /* information unit supported [0] */
+                                /* quick arbitrate supported [1] */
+                                /* clocking field [2:3] */
+                                /* reserved [4:7] */
+  uchar res3;                   /* reserved */
+} ADV_SCSI_INQUIRY; /* 58 bytes */
+
+
+/*
+ * --- Driver Constants and Macros
+ */
+
+#define ASC_NUM_BOARD_SUPPORTED 16
+#define ASC_NUM_IOPORT_PROBE    4
+#define ASC_NUM_BUS             4
+
+/* Reference Scsi_Host hostdata */
+#define ASC_BOARDP(host) ((asc_board_t *) &((host)->hostdata))
+
+/* asc_board_t flags */
+#define ASC_HOST_IN_RESET       0x01
+#define ASC_IS_WIDE_BOARD       0x04    /* AdvanSys Wide Board */
+#define ASC_SELECT_QUEUE_DEPTHS 0x08
+
+#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
+#define ASC_WIDE_BOARD(boardp)   ((boardp)->flags & ASC_IS_WIDE_BOARD)
+
+#define NO_ISA_DMA              0xff        /* No ISA DMA Channel Used */
+
+#define ASC_INFO_SIZE           128            /* advansys_info() line size */
+
+#ifdef CONFIG_PROC_FS
+/* /proc/scsi/advansys/[0...] related definitions */
+#define ASC_PRTBUF_SIZE         2048
+#define ASC_PRTLINE_SIZE        160
+
+#define ASC_PRT_NEXT() \
+    if (cp) { \
+        totlen += len; \
+        leftlen -= len; \
+        if (leftlen == 0) { \
+            return totlen; \
+        } \
+        cp += len; \
+    }
+#endif /* CONFIG_PROC_FS */
+
+/* Asc Library return codes */
+#define ASC_TRUE        1
+#define ASC_FALSE       0
+#define ASC_NOERROR     1
+#define ASC_BUSY        0
+#define ASC_ERROR       (-1)
+
+/* struct scsi_cmnd function return codes */
+#define STATUS_BYTE(byte)   (byte)
+#define MSG_BYTE(byte)      ((byte) << 8)
+#define HOST_BYTE(byte)     ((byte) << 16)
+#define DRIVER_BYTE(byte)   ((byte) << 24)
+
+/*
+ * The following definitions and macros are OS independent interfaces to
+ * the queue functions:
+ *  REQ - SCSI request structure
+ *  REQP - pointer to SCSI request structure
+ *  REQPTID(reqp) - reqp's target id
+ *  REQPNEXT(reqp) - reqp's next pointer
+ *  REQPNEXTP(reqp) - pointer to reqp's next pointer
+ *  REQPTIME(reqp) - reqp's time stamp value
+ *  REQTIMESTAMP() - system time stamp value
+ */
+typedef struct scsi_cmnd     REQ, *REQP;
+#define REQPNEXT(reqp)       ((REQP) ((reqp)->host_scribble))
+#define REQPNEXTP(reqp)      ((REQP *) &((reqp)->host_scribble))
+#define REQPTID(reqp)        ((reqp)->device->id)
+#define REQPTIME(reqp)       ((reqp)->SCp.this_residual)
+#define REQTIMESTAMP()       (jiffies)
+
+#define REQTIMESTAT(function, ascq, reqp, tid) \
+{ \
+    /*
+     * If the request time stamp is less than the system time stamp, then \
+     * maybe the system time stamp wrapped. Set the request time to zero.\
+     */ \
+    if (REQPTIME(reqp) <= REQTIMESTAMP()) { \
+        REQPTIME(reqp) = REQTIMESTAMP() - REQPTIME(reqp); \
+    } else { \
+        /* Indicate an error occurred with the assertion. */ \
+        ASC_ASSERT(REQPTIME(reqp) <= REQTIMESTAMP()); \
+        REQPTIME(reqp) = 0; \
+    } \
+    /* Handle first minimum time case without external initialization. */ \
+    if (((ascq)->q_tot_cnt[tid] == 1) ||  \
+        (REQPTIME(reqp) < (ascq)->q_min_tim[tid])) { \
+            (ascq)->q_min_tim[tid] = REQPTIME(reqp); \
+            ASC_DBG3(1, "%s: new q_min_tim[%d] %u\n", \
+                (function), (tid), (ascq)->q_min_tim[tid]); \
+        } \
+    if (REQPTIME(reqp) > (ascq)->q_max_tim[tid]) { \
+        (ascq)->q_max_tim[tid] = REQPTIME(reqp); \
+        ASC_DBG3(1, "%s: new q_max_tim[%d] %u\n", \
+            (function), tid, (ascq)->q_max_tim[tid]); \
+    } \
+    (ascq)->q_tot_tim[tid] += REQPTIME(reqp); \
+    /* Reset the time stamp field. */ \
+    REQPTIME(reqp) = 0; \
+}
+
+/* asc_enqueue() flags */
+#define ASC_FRONT       1
+#define ASC_BACK        2
+
+/* asc_dequeue_list() argument */
+#define ASC_TID_ALL        (-1)
+
+/* Return non-zero, if the queue is empty. */
+#define ASC_QUEUE_EMPTY(ascq)    ((ascq)->q_tidmask == 0)
+
+#define PCI_MAX_SLOT            0x1F
+#define PCI_MAX_BUS             0xFF
+#define PCI_IOADDRESS_MASK      0xFFFE
+#define ASC_PCI_VENDORID        0x10CD
+#define ASC_PCI_DEVICE_ID_CNT   6       /* PCI Device ID count. */
+#define ASC_PCI_DEVICE_ID_1100  0x1100
+#define ASC_PCI_DEVICE_ID_1200  0x1200
+#define ASC_PCI_DEVICE_ID_1300  0x1300
+#define ASC_PCI_DEVICE_ID_2300  0x2300  /* ASC-3550 */
+#define ASC_PCI_DEVICE_ID_2500  0x2500  /* ASC-38C0800 */
+#define ASC_PCI_DEVICE_ID_2700  0x2700  /* ASC-38C1600 */
+
+#ifndef ADVANSYS_STATS
+#define ASC_STATS(shp, counter)
+#define ASC_STATS_ADD(shp, counter, count)
+#else /* ADVANSYS_STATS */
+#define ASC_STATS(shp, counter) \
+    (ASC_BOARDP(shp)->asc_stats.counter++)
+
+#define ASC_STATS_ADD(shp, counter, count) \
+    (ASC_BOARDP(shp)->asc_stats.counter += (count))
+#endif /* ADVANSYS_STATS */
+
+#define ASC_CEILING(val, unit) (((val) + ((unit) - 1))/(unit))
+
+/* If the result wraps when calculating tenths, return 0. */
+#define ASC_TENTHS(num, den) \
+    (((10 * ((num)/(den))) > (((num) * 10)/(den))) ? \
+    0 : ((((num) * 10)/(den)) - (10 * ((num)/(den)))))
+
+/*
+ * Display a message to the console.
+ */
+#define ASC_PRINT(s) \
+    { \
+        printk("advansys: "); \
+        printk(s); \
+    }
+
+#define ASC_PRINT1(s, a1) \
+    { \
+        printk("advansys: "); \
+        printk((s), (a1)); \
+    }
+
+#define ASC_PRINT2(s, a1, a2) \
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2)); \
+    }
+
+#define ASC_PRINT3(s, a1, a2, a3) \
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2), (a3)); \
+    }
+
+#define ASC_PRINT4(s, a1, a2, a3, a4) \
+    { \
+        printk("advansys: "); \
+        printk((s), (a1), (a2), (a3), (a4)); \
+    }
+
+
+#ifndef ADVANSYS_DEBUG
+
+#define ASC_DBG(lvl, s)
+#define ASC_DBG1(lvl, s, a1)
+#define ASC_DBG2(lvl, s, a1, a2)
+#define ASC_DBG3(lvl, s, a1, a2, a3)
+#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
+#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
+#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
+#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_HEX(lvl, name, start, length)
+#define ASC_DBG_PRT_CDB(lvl, cdb, len)
+#define ASC_DBG_PRT_SENSE(lvl, sense, len)
+#define ASC_DBG_PRT_INQUIRY(lvl, inq, len)
+
+#else /* ADVANSYS_DEBUG */
+
+/*
+ * Debugging Message Levels:
+ * 0: Errors Only
+ * 1: High-Level Tracing
+ * 2-N: Verbose Tracing
+ */
+
+#define ASC_DBG(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk(s); \
+        } \
+    }
+
+#define ASC_DBG1(lvl, s, a1) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1)); \
+        } \
+    }
+
+#define ASC_DBG2(lvl, s, a1, a2) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2)); \
+        } \
+    }
+
+#define ASC_DBG3(lvl, s, a1, a2, a3) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2), (a3)); \
+        } \
+    }
+
+#define ASC_DBG4(lvl, s, a1, a2, a3, a4) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            printk((s), (a1), (a2), (a3), (a4)); \
+        } \
+    }
+
+#define ASC_DBG_PRT_SCSI_HOST(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_scsi_host(s); \
+        } \
+    }
+
+#define ASC_DBG_PRT_SCSI_CMND(lvl, s) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_scsi_cmnd(s); \
+        } \
+    }
+
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_asc_scsi_q(scsiqp); \
+        } \
+    }
+
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_asc_qdone_info(qdone); \
+        } \
+    }
+
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_adv_scsi_req_q(scsiqp); \
+        } \
+    }
+
+#define ASC_DBG_PRT_HEX(lvl, name, start, length) \
+    { \
+        if (asc_dbglvl >= (lvl)) { \
+            asc_prt_hex((name), (start), (length)); \
+        } \
+    }
+
+#define ASC_DBG_PRT_CDB(lvl, cdb, len) \
+        ASC_DBG_PRT_HEX((lvl), "CDB", (uchar *) (cdb), (len));
+
+#define ASC_DBG_PRT_SENSE(lvl, sense, len) \
+        ASC_DBG_PRT_HEX((lvl), "SENSE", (uchar *) (sense), (len));
+
+#define ASC_DBG_PRT_INQUIRY(lvl, inq, len) \
+        ASC_DBG_PRT_HEX((lvl), "INQUIRY", (uchar *) (inq), (len));
+#endif /* ADVANSYS_DEBUG */
+
+#ifndef ADVANSYS_ASSERT
+#define ASC_ASSERT(a)
+#else /* ADVANSYS_ASSERT */
+
+#define ASC_ASSERT(a) \
+    { \
+        if (!(a)) { \
+            printk("ASC_ASSERT() Failure: file %s, line %d\n", \
+                __FILE__, __LINE__); \
+        } \
+    }
+
+#endif /* ADVANSYS_ASSERT */
+
+
+/*
+ * --- Driver Structures
+ */
+
+#ifdef ADVANSYS_STATS
+
+/* Per board statistics structure */
+struct asc_stats {
+    /* Driver Entrypoint Statistics */
+    ADV_DCNT queuecommand;    /* # calls to advansys_queuecommand() */
+    ADV_DCNT reset;           /* # calls to advansys_eh_bus_reset() */
+    ADV_DCNT biosparam;       /* # calls to advansys_biosparam() */
+    ADV_DCNT interrupt;       /* # advansys_interrupt() calls */
+    ADV_DCNT callback;        /* # calls to asc/adv_isr_callback() */
+    ADV_DCNT done;            /* # calls to request's scsi_done function */
+    ADV_DCNT build_error;     /* # asc/adv_build_req() ASC_ERROR returns. */
+    ADV_DCNT adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
+    ADV_DCNT adv_build_nosg;  /* # adv_build_req() adv_sgblk_t alloc. fail. */
+    /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
+    ADV_DCNT exe_noerror;     /* # ASC_NOERROR returns. */
+    ADV_DCNT exe_busy;        /* # ASC_BUSY returns. */
+    ADV_DCNT exe_error;       /* # ASC_ERROR returns. */
+    ADV_DCNT exe_unknown;     /* # unknown returns. */
+    /* Data Transfer Statistics */
+    ADV_DCNT cont_cnt;        /* # non-scatter-gather I/O requests received */
+    ADV_DCNT cont_xfer;       /* # contiguous transfer 512-bytes */
+    ADV_DCNT sg_cnt;          /* # scatter-gather I/O requests received */
+    ADV_DCNT sg_elem;         /* # scatter-gather elements */
+    ADV_DCNT sg_xfer;         /* # scatter-gather transfer 512-bytes */
+};
+#endif /* ADVANSYS_STATS */
+
+/*
+ * Request queuing structure
+ */
+typedef struct asc_queue {
+    ADV_SCSI_BIT_ID_TYPE  q_tidmask;                /* queue mask */
+    REQP                  q_first[ADV_MAX_TID+1];   /* first queued request */
+    REQP                  q_last[ADV_MAX_TID+1];    /* last queued request */
+#ifdef ADVANSYS_STATS
+    short                 q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
+    short                 q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
+    ADV_DCNT              q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
+    ADV_DCNT              q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
+    ushort                q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
+    ushort                q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
+#endif /* ADVANSYS_STATS */
+} asc_queue_t;
+
+/*
+ * Adv Library Request Structures
+ *
+ * The following two structures are used to process Wide Board requests.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * Zero or more ADV_SG_BLOCK are used with each ADV_SCSI_REQ_Q. Each
+ * ADV_SG_BLOCK structure holds 15 scatter-gather elements. Under Linux
+ * up to 255 scatter-gather elements may be used per request or
+ * ADV_SCSI_REQ_Q.
+ *
+ * Both structures must be 32 byte aligned.
+ */
+typedef struct adv_sgblk {
+    ADV_SG_BLOCK        sg_block;     /* Sgblock structure. */
+    uchar               align[32];    /* Sgblock structure padding. */
+    struct adv_sgblk    *next_sgblkp; /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+    ADV_SCSI_REQ_Q      scsi_req_q;   /* Adv Library request structure. */
+    uchar               align[32];    /* Request structure padding. */
+    struct scsi_cmnd	*cmndp;       /* Mid-Level SCSI command pointer. */
+    adv_sgblk_t         *sgblkp;      /* Adv Library scatter-gather pointer. */
+    struct adv_req      *next_reqp;   /* Next Request Structure. */
+} adv_req_t;
+
+/*
+ * Structure allocated for each board.
+ *
+ * This structure is allocated by scsi_register() at the end
+ * of the 'Scsi_Host' structure starting at the 'hostdata'
+ * field. It is guaranteed to be allocated from DMA-able memory.
+ */
+typedef struct asc_board {
+    int                  id;                    /* Board Id */
+    uint                 flags;                 /* Board flags */
+    union {
+        ASC_DVC_VAR      asc_dvc_var;           /* Narrow board */
+        ADV_DVC_VAR      adv_dvc_var;           /* Wide board */
+    } dvc_var;
+    union {
+        ASC_DVC_CFG      asc_dvc_cfg;           /* Narrow board */
+        ADV_DVC_CFG      adv_dvc_cfg;           /* Wide board */
+    } dvc_cfg;
+    ushort               asc_n_io_port;         /* Number I/O ports. */
+    asc_queue_t          active;                /* Active command queue */
+    asc_queue_t          waiting;               /* Waiting command queue */
+    asc_queue_t          done;                  /* Done command queue */
+    ADV_SCSI_BIT_ID_TYPE init_tidmask;          /* Target init./valid mask */
+    struct scsi_device	*device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
+    ushort               reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
+    ADV_SCSI_BIT_ID_TYPE queue_full;            /* Queue full mask */
+    ushort               queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
+    union {
+        ASCEEP_CONFIG         asc_eep;          /* Narrow EEPROM config. */
+        ADVEEP_3550_CONFIG    adv_3550_eep;     /* 3550 EEPROM config. */
+        ADVEEP_38C0800_CONFIG adv_38C0800_eep;  /* 38C0800 EEPROM config. */
+        ADVEEP_38C1600_CONFIG adv_38C1600_eep;  /* 38C1600 EEPROM config. */
+    } eep_config;
+    ulong                last_reset;            /* Saved last reset time */
+    spinlock_t lock;                            /* Board spinlock */
+#ifdef CONFIG_PROC_FS
+    /* /proc/scsi/advansys/[0...] */
+    char                 *prtbuf;               /* /proc print buffer */
+#endif /* CONFIG_PROC_FS */
+#ifdef ADVANSYS_STATS
+    struct asc_stats     asc_stats;             /* Board statistics */
+#endif /* ADVANSYS_STATS */
+    /*
+     * The following fields are used only for Narrow Boards.
+     */
+    /* The following three structures must be in DMA-able memory. */
+    ASC_SCSI_REQ_Q       scsireqq;
+    ASC_CAP_INFO         cap_info;
+    ASC_SCSI_INQUIRY     inquiry;
+    uchar                sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
+    /*
+     * The following fields are used only for Wide Boards.
+     */
+    void                 *ioremap_addr;         /* I/O Memory remap address. */
+    ushort               ioport;                /* I/O Port address. */
+    ADV_CARR_T           *orig_carrp;           /* ADV_CARR_T memory block. */
+    adv_req_t            *orig_reqp;            /* adv_req_t memory block. */
+    adv_req_t            *adv_reqp;             /* Request structures. */
+    adv_sgblk_t          *adv_sgblkp;           /* Scatter-gather structures. */
+    ushort               bios_signature;        /* BIOS Signature. */
+    ushort               bios_version;          /* BIOS Version. */
+    ushort               bios_codeseg;          /* BIOS Code Segment. */
+    ushort               bios_codelen;          /* BIOS Code Segment Length. */
+} asc_board_t;
+
+/*
+ * PCI configuration structures
+ */
+typedef struct _PCI_DATA_
+{
+    uchar    type;
+    uchar    bus;
+    uchar    slot;
+    uchar    func;
+    uchar    offset;
+} PCI_DATA;
+
+typedef struct _PCI_DEVICE_
+{
+    ushort   vendorID;
+    ushort   deviceID;
+    ushort   slotNumber;
+    ushort   slotFound;
+    uchar    busNumber;
+    uchar    maxBusNumber;
+    uchar    devFunc;
+    ushort   startSlot;
+    ushort   endSlot;
+    uchar    bridge;
+    uchar    type;
+} PCI_DEVICE;
+
+typedef struct _PCI_CONFIG_SPACE_
+{
+    ushort   vendorID;
+    ushort   deviceID;
+    ushort   command;
+    ushort   status;
+    uchar    revision;
+    uchar    classCode[3];
+    uchar    cacheSize;
+    uchar    latencyTimer;
+    uchar    headerType;
+    uchar    bist;
+    ADV_PADDR baseAddress[6];
+    ushort   reserved[4];
+    ADV_PADDR optionRomAddr;
+    ushort   reserved2[4];
+    uchar    irqLine;
+    uchar    irqPin;
+    uchar    minGnt;
+    uchar    maxLatency;
+} PCI_CONFIG_SPACE;
+
+
+/*
+ * --- Driver Data
+ */
+
+/* Note: All driver global data should be initialized. */
+
+/* Number of boards detected in system. */
+STATIC int asc_board_count = 0;
+STATIC struct Scsi_Host    *asc_host[ASC_NUM_BOARD_SUPPORTED] = { 0 };
+
+/* Overrun buffer used by all narrow boards. */
+STATIC uchar overrun_buf[ASC_OVERRUN_BSIZE] = { 0 };
+
+/*
+ * Global structures required to issue a command.
+ */
+STATIC ASC_SCSI_Q asc_scsi_q = { { 0 } };
+STATIC ASC_SG_HEAD asc_sg_head = { 0 };
+
+/* List of supported bus types. */
+STATIC ushort asc_bus[ASC_NUM_BUS] __initdata = {
+    ASC_IS_ISA,
+    ASC_IS_VL,
+    ASC_IS_EISA,
+    ASC_IS_PCI,
+};
+
+/*
+ * Used with the LILO 'advansys' option to eliminate or
+ * limit I/O port probing at boot time, cf. advansys_setup().
+ */
+STATIC int asc_iopflag = ASC_FALSE;
+STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+
+#ifdef ADVANSYS_DEBUG
+STATIC char *
+asc_bus_name[ASC_NUM_BUS] = {
+    "ASC_IS_ISA",
+    "ASC_IS_VL",
+    "ASC_IS_EISA",
+    "ASC_IS_PCI",
+};
+
+STATIC int          asc_dbglvl = 3;
+#endif /* ADVANSYS_DEBUG */
+
+/* Declaration for Asc Library internal data referenced by driver. */
+STATIC PortAddr     _asc_def_iop_base[];
+
+
+/*
+ * --- Driver Function Prototypes
+ *
+ * advansys.h contains function prototypes for functions global to Linux.
+ */
+
+STATIC irqreturn_t advansys_interrupt(int, void *, struct pt_regs *);
+STATIC int	  advansys_slave_configure(struct scsi_device *);
+STATIC void       asc_scsi_done_list(struct scsi_cmnd *);
+STATIC int        asc_execute_scsi_cmnd(struct scsi_cmnd *);
+STATIC int        asc_build_req(asc_board_t *, struct scsi_cmnd *);
+STATIC int        adv_build_req(asc_board_t *, struct scsi_cmnd *, ADV_SCSI_REQ_Q **);
+STATIC int        adv_get_sglist(asc_board_t *, adv_req_t *, struct scsi_cmnd *, int);
+STATIC void       asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+STATIC void       adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void       adv_async_callback(ADV_DVC_VAR *, uchar);
+STATIC void       asc_enqueue(asc_queue_t *, REQP, int);
+STATIC REQP       asc_dequeue(asc_queue_t *, int);
+STATIC REQP       asc_dequeue_list(asc_queue_t *, REQP *, int);
+STATIC int        asc_rmqueue(asc_queue_t *, REQP);
+STATIC void       asc_execute_queue(asc_queue_t *);
+#ifdef CONFIG_PROC_FS
+STATIC int        asc_proc_copy(off_t, off_t, char *, int , char *, int);
+STATIC int        asc_prt_board_devices(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_bios(struct Scsi_Host *, char *, int);
+STATIC int        asc_get_eeprom_string(ushort *serialnum, uchar *cp);
+STATIC int        asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_driver_conf(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
+STATIC int        asc_prt_line(char *, int, char *fmt, ...);
+#endif /* CONFIG_PROC_FS */
+
+/* Declaration for Asc Library internal functions referenced by driver. */
+STATIC int          AscFindSignature(PortAddr);
+STATIC ushort       AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+
+/* Statistics function prototypes. */
+#ifdef ADVANSYS_STATS
+#ifdef CONFIG_PROC_FS
+STATIC int          asc_prt_board_stats(struct Scsi_Host *, char *, int);
+STATIC int          asc_prt_target_stats(struct Scsi_Host *, int, char *, int);
+#endif /* CONFIG_PROC_FS */
+#endif /* ADVANSYS_STATS */
+
+/* Debug function prototypes. */
+#ifdef ADVANSYS_DEBUG
+STATIC void         asc_prt_scsi_host(struct Scsi_Host *);
+STATIC void         asc_prt_scsi_cmnd(struct scsi_cmnd *);
+STATIC void         asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
+STATIC void         asc_prt_asc_dvc_var(ASC_DVC_VAR *);
+STATIC void         asc_prt_asc_scsi_q(ASC_SCSI_Q *);
+STATIC void         asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
+STATIC void         asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
+STATIC void         asc_prt_adv_dvc_var(ADV_DVC_VAR *);
+STATIC void         asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
+STATIC void         asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
+STATIC void         asc_prt_hex(char *f, uchar *, int);
+#endif /* ADVANSYS_DEBUG */
+
+
+/*
+ * --- Linux 'Scsi_Host_Template' and advansys_setup() Functions
+ */
+
+#ifdef CONFIG_PROC_FS
+/*
+ * advansys_proc_info() - /proc/scsi/advansys/[0-(ASC_NUM_BOARD_SUPPORTED-1)]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset into a /proc/scsi/advansys/[0...] file
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written to a
+ * /proc/scsi/advansys/[0...] file.
+ *
+ * Note: This function uses the per board buffer 'prtbuf' which is
+ * allocated when the board is initialized in advansys_detect(). The
+ * buffer is ASC_PRTBUF_SIZE bytes. The function asc_proc_copy() is
+ * used to write to the buffer. The way asc_proc_copy() is written
+ * if 'prtbuf' is too small it will not be overwritten. Instead the
+ * user just won't get all the available statistics.
+ */
+int
+advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+		off_t offset, int length, int inout)
+{
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    int                 i;
+    char                *cp;
+    int			cplen;
+    int                 cnt;
+    int                 totcnt;
+    int                 leftlen;
+    char                *curbuf;
+    off_t               advoffset;
+#ifdef ADVANSYS_STATS
+    int                 tgt_id;
+#endif /* ADVANSYS_STATS */
+
+    ASC_DBG(1, "advansys_proc_info: begin\n");
+
+    /*
+     * User write not supported.
+     */
+    if (inout == TRUE) {
+        return(-ENOSYS);
+    }
+
+    /*
+     * User read of /proc/scsi/advansys/[0...] file.
+     */
+
+    /* Find the specified board. */
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i]->host_no == shost->host_no) {
+            break;
+        }
+    }
+    if (i == asc_board_count) {
+        return(-ENOENT);
+    }
+
+    shp = asc_host[i];
+    boardp = ASC_BOARDP(shp);
+
+    /* Copy read data starting at the beginning of the buffer. */
+    *start = buffer;
+    curbuf = buffer;
+    advoffset = 0;
+    totcnt = 0;
+    leftlen = length;
+
+    /*
+     * Get board configuration information.
+     *
+     * advansys_info() returns the board string from its own static buffer.
+     */
+    cp = (char *) advansys_info(shp);
+    strcat(cp, "\n");
+    cplen = strlen(cp);
+    /* Copy board information. */
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display Wide Board BIOS Information.
+     */
+    if (ASC_WIDE_BOARD(boardp)) {
+        cp = boardp->prtbuf;
+        cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
+        ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+        cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+        totcnt += cnt;
+        leftlen -= cnt;
+        if (leftlen == 0) {
+            ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+            return totcnt;
+        }
+        advoffset += cplen;
+        curbuf += cnt;
+    }
+
+    /*
+     * Display driver information for each device attached to the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_board_devices(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display EEPROM configuration for the board.
+     */
+    cp = boardp->prtbuf;
+    if (ASC_NARROW_BOARD(boardp)) {
+        cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+    } else {
+        cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+    }
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display driver configuration and information for the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_driver_conf(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+#ifdef ADVANSYS_STATS
+    /*
+     * Display driver statistics for the board.
+     */
+    cp = boardp->prtbuf;
+    cplen = asc_prt_board_stats(shp, cp, ASC_PRTBUF_SIZE);
+    ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    /*
+     * Display driver statistics for each target.
+     */
+    for (tgt_id = 0; tgt_id <= ADV_MAX_TID; tgt_id++) {
+      cp = boardp->prtbuf;
+      cplen = asc_prt_target_stats(shp, tgt_id, cp, ASC_PRTBUF_SIZE);
+      ASC_ASSERT(cplen <= ASC_PRTBUF_SIZE);
+      cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+      totcnt += cnt;
+      leftlen -= cnt;
+      if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+      }
+      advoffset += cplen;
+      curbuf += cnt;
+    }
+#endif /* ADVANSYS_STATS */
+
+    /*
+     * Display Asc Library dynamic configuration information
+     * for the board.
+     */
+    cp = boardp->prtbuf;
+    if (ASC_NARROW_BOARD(boardp)) {
+        cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
+    } else {
+        cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
+    }
+    ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+    cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+    totcnt += cnt;
+    leftlen -= cnt;
+    if (leftlen == 0) {
+        ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+        return totcnt;
+    }
+    advoffset += cplen;
+    curbuf += cnt;
+
+    ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+
+    return totcnt;
+}
+#endif /* CONFIG_PROC_FS */
+
+/*
+ * advansys_detect()
+ *
+ * Detect function for AdvanSys adapters.
+ *
+ * Argument is a pointer to the host driver's scsi_hosts entry.
+ *
+ * Return number of adapters found.
+ *
+ * Note: Because this function is called during system initialization
+ * it must not call SCSI mid-level functions including scsi_malloc()
+ * and scsi_free().
+ */
+int __init
+advansys_detect(struct scsi_host_template *tpnt)
+{
+    static int          detect_called = ASC_FALSE;
+    int                 iop;
+    int                 bus;
+    struct Scsi_Host    *shp = NULL;
+    asc_board_t         *boardp = NULL;
+    ASC_DVC_VAR         *asc_dvc_varp = NULL;
+    ADV_DVC_VAR         *adv_dvc_varp = NULL;
+    adv_sgblk_t         *sgp = NULL;
+    int                 ioport = 0;
+    int                 share_irq = FALSE;
+    int                 iolen = 0;
+    struct device	*dev = NULL;
+#ifdef CONFIG_PCI
+    int                 pci_init_search = 0;
+    struct pci_dev      *pci_devicep[ASC_NUM_BOARD_SUPPORTED];
+    int                 pci_card_cnt_max = 0;
+    int                 pci_card_cnt = 0;
+    struct pci_dev      *pci_devp = NULL;
+    int                 pci_device_id_cnt = 0;
+    unsigned int        pci_device_id[ASC_PCI_DEVICE_ID_CNT] = {
+                                    ASC_PCI_DEVICE_ID_1100,
+                                    ASC_PCI_DEVICE_ID_1200,
+                                    ASC_PCI_DEVICE_ID_1300,
+                                    ASC_PCI_DEVICE_ID_2300,
+                                    ASC_PCI_DEVICE_ID_2500,
+                                    ASC_PCI_DEVICE_ID_2700
+                        };
+    ADV_PADDR           pci_memory_address;
+#endif /* CONFIG_PCI */
+    int                 warn_code, err_code;
+    int                 ret;
+
+    if (detect_called == ASC_FALSE) {
+        detect_called = ASC_TRUE;
+    } else {
+        printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
+        return 0;
+    }
+
+    ASC_DBG(1, "advansys_detect: begin\n");
+
+    asc_board_count = 0;
+
+    /*
+     * If I/O port probing has been modified, then verify and
+     * clean-up the 'asc_ioport' list.
+     */
+    if (asc_iopflag == ASC_TRUE) {
+        for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+            ASC_DBG2(1, "advansys_detect: asc_ioport[%d] 0x%x\n",
+                ioport, asc_ioport[ioport]);
+            if (asc_ioport[ioport] != 0) {
+                for (iop = 0; iop < ASC_IOADR_TABLE_MAX_IX; iop++) {
+                    if (_asc_def_iop_base[iop] == asc_ioport[ioport]) {
+                        break;
+                    }
+                }
+                if (iop == ASC_IOADR_TABLE_MAX_IX) {
+                    printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+                        asc_ioport[ioport]);
+                    asc_ioport[ioport] = 0;
+                }
+            }
+        }
+        ioport = 0;
+    }
+
+    for (bus = 0; bus < ASC_NUM_BUS; bus++) {
+
+        ASC_DBG2(1, "advansys_detect: bus search type %d (%s)\n",
+            bus, asc_bus_name[bus]);
+        iop = 0;
+
+        while (asc_board_count < ASC_NUM_BOARD_SUPPORTED) {
+
+            ASC_DBG1(2, "advansys_detect: asc_board_count %d\n",
+                asc_board_count);
+
+            switch (asc_bus[bus]) {
+            case ASC_IS_ISA:
+            case ASC_IS_VL:
+#ifdef CONFIG_ISA
+                if (asc_iopflag == ASC_FALSE) {
+                    iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+                } else {
+                    /*
+                     * ISA and VL I/O port scanning has either been
+                     * eliminated or limited to selected ports on
+                     * the LILO command line, /etc/lilo.conf, or
+                     * by setting variables when the module was loaded.
+                     */
+                    ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
+                ioport_try_again:
+                    iop = 0;
+                    for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
+                        if ((iop = asc_ioport[ioport]) != 0) {
+                            break;
+                        }
+                    }
+                    if (iop) {
+                        ASC_DBG1(1,
+                                "advansys_detect: probing I/O port 0x%x...\n",
+                            iop);
+                        if (check_region(iop, ASC_IOADR_GAP) != 0) {
+                            printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
+                            /* Don't try this I/O port twice. */
+                            asc_ioport[ioport] = 0;
+                            goto ioport_try_again;
+                        } else if (AscFindSignature(iop) == ASC_FALSE) {
+                            printk(
+"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
+                            /* Don't try this I/O port twice. */
+                            asc_ioport[ioport] = 0;
+                            goto ioport_try_again;
+                        } else {
+                            /*
+                             * If this isn't an ISA board, then it must be
+                             * a VL board. If currently looking an ISA
+                             * board is being looked for then try for
+                             * another ISA board in 'asc_ioport'.
+                             */
+                            if (asc_bus[bus] == ASC_IS_ISA &&
+                                (AscGetChipVersion(iop, ASC_IS_ISA) &
+                                 ASC_CHIP_VER_ISA_BIT) == 0) {
+                                 /*
+                                  * Don't clear 'asc_ioport[ioport]'. Try
+                                  * this board again for VL. Increment
+                                  * 'ioport' past this board.
+                                  */
+                                 ioport++;
+                                 goto ioport_try_again;
+                            }
+                        }
+                        /*
+                         * This board appears good, don't try the I/O port
+                         * again by clearing its value. Increment 'ioport'
+                         * for the next iteration.
+                         */
+                        asc_ioport[ioport++] = 0;
+                    }
+                }
+#endif /* CONFIG_ISA */
+                break;
+
+            case ASC_IS_EISA:
+#ifdef CONFIG_ISA
+                iop = AscSearchIOPortAddr(iop, asc_bus[bus]);
+#endif /* CONFIG_ISA */
+                break;
+
+            case ASC_IS_PCI:
+#ifdef CONFIG_PCI
+                if (pci_init_search == 0) {
+                    int i, j;
+
+                    pci_init_search = 1;
+
+                    /* Find all PCI cards. */
+                    while (pci_device_id_cnt < ASC_PCI_DEVICE_ID_CNT) {
+                        if ((pci_devp = pci_find_device(ASC_PCI_VENDORID,
+                            pci_device_id[pci_device_id_cnt], pci_devp)) ==
+                            NULL) {
+                            pci_device_id_cnt++;
+                        } else {
+                            if (pci_enable_device(pci_devp) == 0) {
+                                pci_devicep[pci_card_cnt_max++] = pci_devp;
+                            }
+                        }
+                    }
+
+                    /*
+                     * Sort PCI cards in ascending order by PCI Bus, Slot,
+                     * and Device Number.
+                     */
+                    for (i = 0; i < pci_card_cnt_max - 1; i++)
+                    {
+                        for (j = i + 1; j < pci_card_cnt_max; j++) {
+                            if ((pci_devicep[j]->bus->number <
+                                 pci_devicep[i]->bus->number) ||
+                                ((pci_devicep[j]->bus->number ==
+                                  pci_devicep[i]->bus->number) &&
+                                  (pci_devicep[j]->devfn <
+                                   pci_devicep[i]->devfn))) {
+                                pci_devp = pci_devicep[i];
+                                pci_devicep[i] = pci_devicep[j];
+                                pci_devicep[j] = pci_devp;
+                            }
+                        }
+                    }
+
+                    pci_card_cnt = 0;
+                } else {
+                    pci_card_cnt++;
+                }
+
+                if (pci_card_cnt == pci_card_cnt_max) {
+                    iop = 0;
+                } else {
+                    pci_devp = pci_devicep[pci_card_cnt];
+
+                    ASC_DBG2(2,
+                        "advansys_detect: devfn %d, bus number %d\n",
+                        pci_devp->devfn, pci_devp->bus->number);
+                    iop = pci_resource_start(pci_devp, 0);
+                    ASC_DBG2(1,
+                        "advansys_detect: vendorID %X, deviceID %X\n",
+                        pci_devp->vendor, pci_devp->device);
+                    ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
+                        iop, pci_devp->irq);
+                }
+		if(pci_devp)
+		    dev = &pci_devp->dev;
+
+#endif /* CONFIG_PCI */
+                break;
+
+            default:
+                ASC_PRINT1("advansys_detect: unknown bus type: %d\n",
+                    asc_bus[bus]);
+                break;
+            }
+            ASC_DBG1(1, "advansys_detect: iop 0x%x\n", iop);
+
+            /*
+             * Adapter not found, try next bus type.
+             */
+            if (iop == 0) {
+                break;
+            }
+
+            /*
+             * Adapter found.
+             *
+             * Register the adapter, get its configuration, and
+             * initialize it.
+             */
+            ASC_DBG(2, "advansys_detect: scsi_register()\n");
+            shp = scsi_register(tpnt, sizeof(asc_board_t));
+
+            if (shp == NULL) {
+                continue;
+            }
+
+	    scsi_set_device(shp, dev);
+
+            /* Save a pointer to the Scsi_Host of each board found. */
+            asc_host[asc_board_count++] = shp;
+
+            /* Initialize private per board data */
+            boardp = ASC_BOARDP(shp);
+            memset(boardp, 0, sizeof(asc_board_t));
+            boardp->id = asc_board_count - 1;
+
+            /* Initialize spinlock. */
+            spin_lock_init(&boardp->lock);
+
+            /*
+             * Handle both narrow and wide boards.
+             *
+             * If a Wide board was detected, set the board structure
+             * wide board flag. Set-up the board structure based on
+             * the board type.
+             */
+#ifdef CONFIG_PCI
+            if (asc_bus[bus] == ASC_IS_PCI &&
+                (pci_devp->device == ASC_PCI_DEVICE_ID_2300 ||
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2500 ||
+                 pci_devp->device == ASC_PCI_DEVICE_ID_2700))
+            {
+                boardp->flags |= ASC_IS_WIDE_BOARD;
+            }
+#endif /* CONFIG_PCI */
+
+            if (ASC_NARROW_BOARD(boardp)) {
+                ASC_DBG(1, "advansys_detect: narrow board\n");
+                asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+                asc_dvc_varp->bus_type = asc_bus[bus];
+                asc_dvc_varp->drv_ptr = boardp;
+                asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
+                asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
+                asc_dvc_varp->iop_base = iop;
+                asc_dvc_varp->isr_callback = asc_isr_callback;
+            } else {
+                ASC_DBG(1, "advansys_detect: wide board\n");
+                adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+                adv_dvc_varp->drv_ptr = boardp;
+                adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
+                adv_dvc_varp->isr_callback = adv_isr_callback;
+                adv_dvc_varp->async_callback = adv_async_callback;
+#ifdef CONFIG_PCI
+                if (pci_devp->device == ASC_PCI_DEVICE_ID_2300)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-3550\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC3550;
+                } else if (pci_devp->device == ASC_PCI_DEVICE_ID_2500)
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C0800\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C0800;
+                } else
+                {
+                    ASC_DBG(1, "advansys_detect: ASC-38C1600\n");
+                    adv_dvc_varp->chip_type = ADV_CHIP_ASC38C1600;
+                }
+#endif /* CONFIG_PCI */
+
+                /*
+                 * Map the board's registers into virtual memory for
+                 * PCI slave access. Only memory accesses are used to
+                 * access the board's registers.
+                 *
+                 * Note: The PCI register base address is not always
+                 * page aligned, but the address passed to ioremap()
+                 * must be page aligned. It is guaranteed that the
+                 * PCI register base address will not cross a page
+                 * boundary.
+                 */
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    iolen = ADV_3550_IOLEN;
+                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+                {
+                    iolen = ADV_38C0800_IOLEN;
+                } else
+                {
+                    iolen = ADV_38C1600_IOLEN;
+                }
+#ifdef CONFIG_PCI
+                pci_memory_address = pci_resource_start(pci_devp, 1);
+                ASC_DBG1(1, "advansys_detect: pci_memory_address: 0x%lx\n",
+                    (ulong) pci_memory_address);
+                if ((boardp->ioremap_addr =
+                    ioremap(pci_memory_address & PAGE_MASK,
+                         PAGE_SIZE)) == 0) {
+                   ASC_PRINT3(
+"advansys_detect: board %d: ioremap(%x, %d) returned NULL\n",
+                       boardp->id, pci_memory_address, iolen);
+                   scsi_unregister(shp);
+                   asc_board_count--;
+                   continue;
+                }
+                ASC_DBG1(1, "advansys_detect: ioremap_addr: 0x%lx\n",
+                    (ulong) boardp->ioremap_addr);
+                adv_dvc_varp->iop_base = (AdvPortAddr)
+                    (boardp->ioremap_addr +
+                     (pci_memory_address - (pci_memory_address & PAGE_MASK)));
+                ASC_DBG1(1, "advansys_detect: iop_base: 0x%lx\n",
+                    adv_dvc_varp->iop_base);
+#endif /* CONFIG_PCI */
+
+                /*
+                 * Even though it isn't used to access wide boards, other
+                 * than for the debug line below, save I/O Port address so
+                 * that it can be reported.
+                 */
+                boardp->ioport = iop;
+
+                ASC_DBG2(1,
+"advansys_detect: iopb_chip_id_1 0x%x, iopw_chip_id_0 0x%x\n",
+                    (ushort) inp(iop + 1), (ushort) inpw(iop));
+            }
+
+#ifdef CONFIG_PROC_FS
+            /*
+             * Allocate buffer for printing information from
+             * /proc/scsi/advansys/[0...].
+             */
+            if ((boardp->prtbuf =
+                kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
+                ASC_PRINT3(
+"advansys_detect: board %d: kmalloc(%d, %d) returned NULL\n",
+                    boardp->id, ASC_PRTBUF_SIZE, GFP_ATOMIC);
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+#endif /* CONFIG_PROC_FS */
+
+            if (ASC_NARROW_BOARD(boardp)) {
+		asc_dvc_varp->cfg->dev = dev;
+		/*
+                 * Set the board bus type and PCI IRQ before
+                 * calling AscInitGetConfig().
+                 */
+                switch (asc_dvc_varp->bus_type) {
+#ifdef CONFIG_ISA
+                case ASC_IS_ISA:
+                    shp->unchecked_isa_dma = TRUE;
+                    share_irq = FALSE;
+                    break;
+                case ASC_IS_VL:
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = FALSE;
+                    break;
+                case ASC_IS_EISA:
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = TRUE;
+                    break;
+#endif /* CONFIG_ISA */
+#ifdef CONFIG_PCI
+                case ASC_IS_PCI:
+                    shp->irq = asc_dvc_varp->irq_no = pci_devp->irq;
+                    asc_dvc_varp->cfg->pci_slot_info =
+                        ASC_PCI_MKID(pci_devp->bus->number,
+                            PCI_SLOT(pci_devp->devfn),
+                            PCI_FUNC(pci_devp->devfn));
+                    shp->unchecked_isa_dma = FALSE;
+                    share_irq = TRUE;
+                    break;
+#endif /* CONFIG_PCI */
+                default:
+                    ASC_PRINT2(
+"advansys_detect: board %d: unknown adapter type: %d\n",
+                        boardp->id, asc_dvc_varp->bus_type);
+                    shp->unchecked_isa_dma = TRUE;
+                    share_irq = FALSE;
+                    break;
+                }
+            } else {
+                adv_dvc_varp->cfg->dev = dev;
+                /*
+                 * For Wide boards set PCI information before calling
+                 * AdvInitGetConfig().
+                 */
+#ifdef CONFIG_PCI
+                shp->irq = adv_dvc_varp->irq_no = pci_devp->irq;
+                adv_dvc_varp->cfg->pci_slot_info =
+                    ASC_PCI_MKID(pci_devp->bus->number,
+                        PCI_SLOT(pci_devp->devfn),
+                        PCI_FUNC(pci_devp->devfn));
+                shp->unchecked_isa_dma = FALSE;
+                share_irq = TRUE;
+#endif /* CONFIG_PCI */
+            }
+
+            /*
+             * Read the board configuration.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                 /*
+                  * NOTE: AscInitGetConfig() may change the board's
+                  * bus_type value. The asc_bus[bus] value should no
+                  * longer be used. If the bus_type field must be
+                  * referenced only use the bit-wise AND operator "&".
+                  */
+                ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+                switch(ret = AscInitGetConfig(asc_dvc_varp)) {
+                case 0:    /* No error */
+                    break;
+                case ASC_WARN_IO_PORT_ROTATE:
+                    ASC_PRINT1(
+"AscInitGetConfig: board %d: I/O port address modified\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_AUTO_CONFIG:
+                    ASC_PRINT1(
+"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_EEPROM_CHKSUM:
+                    ASC_PRINT1(
+"AscInitGetConfig: board %d: EEPROM checksum error\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_IRQ_MODIFIED:
+                    ASC_PRINT1(
+"AscInitGetConfig: board %d: IRQ modified\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_CMD_QNG_CONFLICT:
+                    ASC_PRINT1(
+"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
+                        boardp->id);
+                    break;
+                default:
+                    ASC_PRINT2(
+"AscInitGetConfig: board %d: unknown warning: 0x%x\n",
+                        boardp->id, ret);
+                    break;
+                }
+                if ((err_code = asc_dvc_varp->err_code) != 0) {
+                    ASC_PRINT3(
+"AscInitGetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+                        boardp->id, asc_dvc_varp->init_state,
+                        asc_dvc_varp->err_code);
+                }
+            } else {
+                ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
+                if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
+                    ASC_PRINT2("AdvInitGetConfig: board %d: warning: 0x%x\n",
+                        boardp->id, ret);
+                }
+                if ((err_code = adv_dvc_varp->err_code) != 0) {
+                    ASC_PRINT2(
+"AdvInitGetConfig: board %d error: err_code 0x%x\n",
+                        boardp->id, adv_dvc_varp->err_code);
+                }
+            }
+
+            if (err_code != 0) {
+#ifdef CONFIG_PROC_FS
+                kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+
+            /*
+             * Save the EEPROM configuration so that it can be displayed
+             * from /proc/scsi/advansys/[0...].
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+
+                ASCEEP_CONFIG *ep;
+
+                /*
+                 * Set the adapter's target id bit in the 'init_tidmask' field.
+                 */
+                boardp->init_tidmask |=
+                    ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
+
+                /*
+                 * Save EEPROM settings for the board.
+                 */
+                ep = &boardp->eep_config.asc_eep;
+
+                ep->init_sdtr = asc_dvc_varp->cfg->sdtr_enable;
+                ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
+                ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
+                ASC_EEP_SET_DMA_SPD(ep, asc_dvc_varp->cfg->isa_dma_speed);
+                ep->start_motor = asc_dvc_varp->start_motor;
+                ep->cntl = asc_dvc_varp->dvc_cntl;
+                ep->no_scam = asc_dvc_varp->no_scam;
+                ep->max_total_qng = asc_dvc_varp->max_total_qng;
+                ASC_EEP_SET_CHIP_ID(ep, asc_dvc_varp->cfg->chip_scsi_id);
+                /* 'max_tag_qng' is set to the same value for every device. */
+                ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+                ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
+                ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
+                ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
+                ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
+                ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
+                ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
+
+               /*
+                * Modify board configuration.
+                */
+                ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
+                switch (ret = AscInitSetConfig(asc_dvc_varp)) {
+                case 0:    /* No error. */
+                    break;
+                case ASC_WARN_IO_PORT_ROTATE:
+                    ASC_PRINT1(
+"AscInitSetConfig: board %d: I/O port address modified\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_AUTO_CONFIG:
+                    ASC_PRINT1(
+"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_EEPROM_CHKSUM:
+                    ASC_PRINT1(
+"AscInitSetConfig: board %d: EEPROM checksum error\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_IRQ_MODIFIED:
+                    ASC_PRINT1(
+"AscInitSetConfig: board %d: IRQ modified\n",
+                        boardp->id);
+                    break;
+                case ASC_WARN_CMD_QNG_CONFLICT:
+                    ASC_PRINT1(
+"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
+                        boardp->id);
+                    break;
+                default:
+                    ASC_PRINT2(
+"AscInitSetConfig: board %d: unknown warning: 0x%x\n",
+                        boardp->id, ret);
+                    break;
+                }
+                if (asc_dvc_varp->err_code != 0) {
+                    ASC_PRINT3(
+"AscInitSetConfig: board %d error: init_state 0x%x, err_code 0x%x\n",
+                        boardp->id, asc_dvc_varp->init_state,
+                        asc_dvc_varp->err_code);
+#ifdef CONFIG_PROC_FS
+                    kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                    scsi_unregister(shp);
+                    asc_board_count--;
+                    continue;
+                }
+
+                /*
+                 * Finish initializing the 'Scsi_Host' structure.
+                 */
+                /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+                if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
+                    shp->irq = asc_dvc_varp->irq_no;
+                }
+            } else {
+                ADVEEP_3550_CONFIG      *ep_3550;
+                ADVEEP_38C0800_CONFIG   *ep_38C0800;
+                ADVEEP_38C1600_CONFIG   *ep_38C1600;
+
+                /*
+                 * Save Wide EEP Configuration Information.
+                 */
+                if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                {
+                    ep_3550 = &boardp->eep_config.adv_3550_eep;
+
+                    ep_3550->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_3550->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_3550->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_3550->termination = adv_dvc_varp->cfg->termination;
+                    ep_3550->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_3550->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_3550->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_3550->sdtr_able = adv_dvc_varp->sdtr_able;
+                    ep_3550->ultra_able = adv_dvc_varp->ultra_able;
+                    ep_3550->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_3550->start_motor = adv_dvc_varp->start_motor;
+                    ep_3550->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+                    ep_3550->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_3550->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_3550->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+                {
+                    ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+
+                    ep_38C0800->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_38C0800->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_38C0800->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_38C0800->termination_lvd =
+                        adv_dvc_varp->cfg->termination;
+                    ep_38C0800->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_38C0800->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_38C0800->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+                    ep_38C0800->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+                    ep_38C0800->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+                    ep_38C0800->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+                    ep_38C0800->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C0800->start_motor = adv_dvc_varp->start_motor;
+                    ep_38C0800->scsi_reset_delay =
+                        adv_dvc_varp->scsi_reset_wait;
+                    ep_38C0800->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_38C0800->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_38C0800->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                } else
+                {
+                    ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+
+                    ep_38C1600->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+                    ep_38C1600->max_host_qng = adv_dvc_varp->max_host_qng;
+                    ep_38C1600->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+                    ep_38C1600->termination_lvd =
+                        adv_dvc_varp->cfg->termination;
+                    ep_38C1600->disc_enable = adv_dvc_varp->cfg->disc_enable;
+                    ep_38C1600->bios_ctrl = adv_dvc_varp->bios_ctrl;
+                    ep_38C1600->wdtr_able = adv_dvc_varp->wdtr_able;
+                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C1600->sdtr_speed1 = adv_dvc_varp->sdtr_speed1;
+                    ep_38C1600->sdtr_speed2 = adv_dvc_varp->sdtr_speed2;
+                    ep_38C1600->sdtr_speed3 = adv_dvc_varp->sdtr_speed3;
+                    ep_38C1600->sdtr_speed4 = adv_dvc_varp->sdtr_speed4;
+                    ep_38C1600->tagqng_able = adv_dvc_varp->tagqng_able;
+                    ep_38C1600->start_motor = adv_dvc_varp->start_motor;
+                    ep_38C1600->scsi_reset_delay =
+                        adv_dvc_varp->scsi_reset_wait;
+                    ep_38C1600->serial_number_word1 =
+                        adv_dvc_varp->cfg->serial1;
+                    ep_38C1600->serial_number_word2 =
+                        adv_dvc_varp->cfg->serial2;
+                    ep_38C1600->serial_number_word3 =
+                        adv_dvc_varp->cfg->serial3;
+                }
+
+                /*
+                 * Set the adapter's target id bit in the 'init_tidmask' field.
+                 */
+                boardp->init_tidmask |=
+                    ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
+
+                /*
+                 * Finish initializing the 'Scsi_Host' structure.
+                 */
+                shp->irq = adv_dvc_varp->irq_no;
+            }
+
+            /*
+             * Channels are numbered beginning with 0. For AdvanSys one host
+             * structure supports one channel. Multi-channel boards have a
+             * separate host structure for each channel.
+             */
+            shp->max_channel = 0;
+            if (ASC_NARROW_BOARD(boardp)) {
+                shp->max_id = ASC_MAX_TID + 1;
+                shp->max_lun = ASC_MAX_LUN + 1;
+
+                shp->io_port = asc_dvc_varp->iop_base;
+                boardp->asc_n_io_port = ASC_IOADR_GAP;
+                shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+
+                /* Set maximum number of queues the adapter can handle. */
+                shp->can_queue = asc_dvc_varp->max_total_qng;
+            } else {
+                shp->max_id = ADV_MAX_TID + 1;
+                shp->max_lun = ADV_MAX_LUN + 1;
+
+                /*
+                 * Save the I/O Port address and length even though
+                 * I/O ports are not used to access Wide boards.
+                 * Instead the Wide boards are accessed with
+                 * PCI Memory Mapped I/O.
+                 */
+                shp->io_port = iop;
+                boardp->asc_n_io_port = iolen;
+
+                shp->this_id = adv_dvc_varp->chip_scsi_id;
+
+                /* Set maximum number of queues the adapter can handle. */
+                shp->can_queue = adv_dvc_varp->max_host_qng;
+            }
+
+            /*
+             * 'n_io_port' currently is one byte.
+             *
+             * Set a value to 'n_io_port', but never referenced it because
+             * it may be truncated.
+             */
+            shp->n_io_port = boardp->asc_n_io_port <= 255 ?
+                boardp->asc_n_io_port : 255;
+
+            /*
+             * Following v1.3.89, 'cmd_per_lun' is no longer needed
+             * and should be set to zero.
+             *
+             * But because of a bug introduced in v1.3.89 if the driver is
+             * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
+             * SCSI function 'allocate_device' will panic. To allow the driver
+             * to work as a module in these kernels set 'cmd_per_lun' to 1.
+	     *
+	     * Note: This is wrong.  cmd_per_lun should be set to the depth
+	     * you want on untagged devices always.
+#ifdef MODULE
+             */
+            shp->cmd_per_lun = 1;
+/* #else
+            shp->cmd_per_lun = 0;
+#endif */
+
+            /*
+             * Set the maximum number of scatter-gather elements the
+             * adapter can handle.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                /*
+                 * Allow two commands with 'sg_tablesize' scatter-gather
+                 * elements to be executed simultaneously. This value is
+                 * the theoretical hardware limit. It may be decreased
+                 * below.
+                 */
+                shp->sg_tablesize =
+                    (((asc_dvc_varp->max_total_qng - 2) / 2) *
+                    ASC_SG_LIST_PER_Q) + 1;
+            } else {
+                shp->sg_tablesize = ADV_MAX_SG_LIST;
+            }
+
+            /*
+             * The value of 'sg_tablesize' can not exceed the SCSI
+             * mid-level driver definition of SG_ALL. SG_ALL also
+             * must not be exceeded, because it is used to define the
+             * size of the scatter-gather table in 'struct asc_sg_head'.
+             */
+            if (shp->sg_tablesize > SG_ALL) {
+                shp->sg_tablesize = SG_ALL;
+            }
+
+            ASC_DBG1(1, "advansys_detect: sg_tablesize: %d\n",
+                shp->sg_tablesize);
+
+            /* BIOS start address. */
+            if (ASC_NARROW_BOARD(boardp)) {
+                shp->base =
+                        ((ulong) AscGetChipBiosAddress(
+                            asc_dvc_varp->iop_base,
+                            asc_dvc_varp->bus_type));
+            } else {
+                /*
+                 * Fill-in BIOS board variables. The Wide BIOS saves
+                 * information in LRAM that is used by the driver.
+                 */
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE,
+                    boardp->bios_signature);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION,
+                    boardp->bios_version);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG,
+                    boardp->bios_codeseg);
+                AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN,
+                    boardp->bios_codelen);
+
+                ASC_DBG2(1,
+                    "advansys_detect: bios_signature 0x%x, bios_version 0x%x\n",
+                    boardp->bios_signature, boardp->bios_version);
+
+                ASC_DBG2(1,
+                    "advansys_detect: bios_codeseg 0x%x, bios_codelen 0x%x\n",
+                    boardp->bios_codeseg, boardp->bios_codelen);
+
+                /*
+                 * If the BIOS saved a valid signature, then fill in
+                 * the BIOS code segment base address.
+                 */
+                if (boardp->bios_signature == 0x55AA) {
+                    /*
+                     * Convert x86 realmode code segment to a linear
+                     * address by shifting left 4.
+                     */
+                    shp->base = ((ulong) boardp->bios_codeseg << 4);
+                } else {
+                    shp->base = 0;
+                }
+            }
+
+            /*
+             * Register Board Resources - I/O Port, DMA, IRQ
+             */
+
+            /*
+             * Register I/O port range.
+             *
+             * For Wide boards the I/O ports are not used to access
+             * the board, but request the region anyway.
+             *
+             * 'shp->n_io_port' is not referenced, because it may be truncated.
+             */
+            ASC_DBG2(2,
+                "advansys_detect: request_region port 0x%lx, len 0x%x\n",
+                (ulong) shp->io_port, boardp->asc_n_io_port);
+            if (request_region(shp->io_port, boardp->asc_n_io_port,
+                               "advansys") == NULL) {
+                ASC_PRINT3(
+"advansys_detect: board %d: request_region() failed, port 0x%lx, len 0x%x\n",
+                    boardp->id, (ulong) shp->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+                kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+
+            /* Register DMA Channel for Narrow boards. */
+            shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
+#ifdef CONFIG_ISA
+            if (ASC_NARROW_BOARD(boardp)) {
+                /* Register DMA channel for ISA bus. */
+                if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+                    shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
+                    if ((ret =
+                         request_dma(shp->dma_channel, "advansys")) != 0) {
+                        ASC_PRINT3(
+"advansys_detect: board %d: request_dma() %d failed %d\n",
+                            boardp->id, shp->dma_channel, ret);
+                        release_region(shp->io_port, boardp->asc_n_io_port);
+#ifdef CONFIG_PROC_FS
+                        kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                        scsi_unregister(shp);
+                        asc_board_count--;
+                        continue;
+                    }
+                    AscEnableIsaDma(shp->dma_channel);
+                }
+            }
+#endif /* CONFIG_ISA */
+
+            /* Register IRQ Number. */
+            ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
+           /*
+            * If request_irq() fails with the SA_INTERRUPT flag set,
+            * then try again without the SA_INTERRUPT flag set. This
+            * allows IRQ sharing to work even with other drivers that
+            * do not set the SA_INTERRUPT flag.
+            *
+            * If SA_INTERRUPT is not set, then interrupts are enabled
+            * before the driver interrupt function is called.
+            */
+            if (((ret = request_irq(shp->irq, advansys_interrupt,
+                            SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
+                            "advansys", boardp)) != 0) &&
+                ((ret = request_irq(shp->irq, advansys_interrupt,
+                            (share_irq == TRUE ? SA_SHIRQ : 0),
+                            "advansys", boardp)) != 0))
+            {
+                if (ret == -EBUSY) {
+                    ASC_PRINT2(
+"advansys_detect: board %d: request_irq(): IRQ 0x%x already in use.\n",
+                        boardp->id, shp->irq);
+                } else if (ret == -EINVAL) {
+                    ASC_PRINT2(
+"advansys_detect: board %d: request_irq(): IRQ 0x%x not valid.\n",
+                        boardp->id, shp->irq);
+                } else {
+                    ASC_PRINT3(
+"advansys_detect: board %d: request_irq(): IRQ 0x%x failed with %d\n",
+                        boardp->id, shp->irq, ret);
+                }
+                release_region(shp->io_port, boardp->asc_n_io_port);
+                iounmap(boardp->ioremap_addr);
+                if (shp->dma_channel != NO_ISA_DMA) {
+                    free_dma(shp->dma_channel);
+                }
+#ifdef CONFIG_PROC_FS
+                kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+
+            /*
+             * Initialize board RISC chip and enable interrupts.
+             */
+            if (ASC_NARROW_BOARD(boardp)) {
+                ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
+                warn_code = AscInitAsc1000Driver(asc_dvc_varp);
+                err_code = asc_dvc_varp->err_code;
+
+                if (warn_code || err_code) {
+                    ASC_PRINT4(
+"advansys_detect: board %d error: init_state 0x%x, warn 0x%x, error 0x%x\n",
+                        boardp->id, asc_dvc_varp->init_state,
+                        warn_code, err_code);
+                }
+            } else {
+                ADV_CARR_T      *carrp;
+                int             req_cnt = 0;
+                adv_req_t       *reqp = NULL;
+                int             sg_cnt = 0;
+
+                /*
+                 * Allocate buffer carrier structures. The total size
+                 * is about 4 KB, so allocate all at once.
+                 */
+                carrp =
+                    (ADV_CARR_T *) kmalloc(ADV_CARRIER_BUFSIZE, GFP_ATOMIC);
+                ASC_DBG1(1, "advansys_detect: carrp 0x%lx\n", (ulong) carrp);
+
+                if (carrp == NULL) {
+                    goto kmalloc_error;
+                }
+
+                /*
+                 * Allocate up to 'max_host_qng' request structures for
+                 * the Wide board. The total size is about 16 KB, so
+                 * allocate all at once. If the allocation fails decrement
+                 * and try again.
+                 */
+                for (req_cnt = adv_dvc_varp->max_host_qng;
+                    req_cnt > 0; req_cnt--) {
+
+                    reqp = (adv_req_t *)
+                        kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+
+                    ASC_DBG3(1,
+                        "advansys_detect: reqp 0x%lx, req_cnt %d, bytes %lu\n",
+                        (ulong) reqp, req_cnt,
+                        (ulong) sizeof(adv_req_t) * req_cnt);
+
+                    if (reqp != NULL) {
+                        break;
+                    }
+                }
+                if (reqp == NULL)
+                {
+                    goto kmalloc_error;
+                }
+
+                /*
+                 * Allocate up to ADV_TOT_SG_BLOCK request structures for
+                 * the Wide board. Each structure is about 136 bytes.
+                 */
+                boardp->adv_sgblkp = NULL;
+                for (sg_cnt = 0; sg_cnt < ADV_TOT_SG_BLOCK; sg_cnt++) {
+
+                    sgp = (adv_sgblk_t *)
+                        kmalloc(sizeof(adv_sgblk_t), GFP_ATOMIC);
+
+                    if (sgp == NULL) {
+                        break;
+                    }
+
+                    sgp->next_sgblkp = boardp->adv_sgblkp;
+                    boardp->adv_sgblkp = sgp;
+
+                }
+                ASC_DBG3(1,
+                    "advansys_detect: sg_cnt %d * %u = %u bytes\n",
+                    sg_cnt, sizeof(adv_sgblk_t),
+                    (unsigned) (sizeof(adv_sgblk_t) * sg_cnt));
+
+                /*
+                 * If no request structures or scatter-gather structures could
+                 * be allocated, then return an error. Otherwise continue with
+                 * initialization.
+                 */
+    kmalloc_error:
+                if (carrp == NULL)
+                {
+                    ASC_PRINT1(
+"advansys_detect: board %d error: failed to kmalloc() carrier buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else if (reqp == NULL) {
+                    kfree(carrp);
+                    ASC_PRINT1(
+"advansys_detect: board %d error: failed to kmalloc() adv_req_t buffer.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else if (boardp->adv_sgblkp == NULL) {
+                    kfree(carrp);
+                    kfree(reqp);
+                    ASC_PRINT1(
+"advansys_detect: board %d error: failed to kmalloc() adv_sgblk_t buffers.\n",
+                        boardp->id);
+                    err_code = ADV_ERROR;
+                } else {
+
+                    /* Save carrier buffer pointer. */
+                    boardp->orig_carrp = carrp;
+
+                    /*
+                     * Save original pointer for kfree() in case the
+                     * driver is built as a module and can be unloaded.
+                     */
+                    boardp->orig_reqp = reqp;
+
+                    adv_dvc_varp->carrier_buf = carrp;
+
+                    /*
+                     * Point 'adv_reqp' to the request structures and
+                     * link them together.
+                     */
+                    req_cnt--;
+                    reqp[req_cnt].next_reqp = NULL;
+                    for (; req_cnt > 0; req_cnt--) {
+                        reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+                    }
+                    boardp->adv_reqp = &reqp[0];
+
+                    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+                    {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc3550Driver()\n");
+                        warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+                    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800) {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc38C0800Driver()\n");
+                        warn_code = AdvInitAsc38C0800Driver(adv_dvc_varp);
+                    } else {
+                        ASC_DBG(2,
+                            "advansys_detect: AdvInitAsc38C1600Driver()\n");
+                        warn_code = AdvInitAsc38C1600Driver(adv_dvc_varp);
+                    }
+                    err_code = adv_dvc_varp->err_code;
+
+                    if (warn_code || err_code) {
+                        ASC_PRINT3(
+"advansys_detect: board %d error: warn 0x%x, error 0x%x\n",
+                            boardp->id, warn_code, err_code);
+                    }
+                }
+            }
+
+            if (err_code != 0) {
+                release_region(shp->io_port, boardp->asc_n_io_port);
+                if (ASC_WIDE_BOARD(boardp)) {
+                    iounmap(boardp->ioremap_addr);
+                    if (boardp->orig_carrp) {
+                        kfree(boardp->orig_carrp);
+                        boardp->orig_carrp = NULL;
+                    }
+                    if (boardp->orig_reqp) {
+                        kfree(boardp->orig_reqp);
+                        boardp->orig_reqp = boardp->adv_reqp = NULL;
+                    }
+                    while ((sgp = boardp->adv_sgblkp) != NULL)
+                    {
+                        boardp->adv_sgblkp = sgp->next_sgblkp;
+                        kfree(sgp);
+                    }
+                }
+                if (shp->dma_channel != NO_ISA_DMA) {
+                    free_dma(shp->dma_channel);
+                }
+#ifdef CONFIG_PROC_FS
+                kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+                free_irq(shp->irq, boardp);
+                scsi_unregister(shp);
+                asc_board_count--;
+                continue;
+            }
+            ASC_DBG_PRT_SCSI_HOST(2, shp);
+        }
+    }
+
+    ASC_DBG1(1, "advansys_detect: done: asc_board_count %d\n", asc_board_count);
+    return asc_board_count;
+}
+
+/*
+ * advansys_release()
+ *
+ * Release resources allocated for a single AdvanSys adapter.
+ */
+int
+advansys_release(struct Scsi_Host *shp)
+{
+    asc_board_t    *boardp;
+
+    ASC_DBG(1, "advansys_release: begin\n");
+    boardp = ASC_BOARDP(shp);
+    free_irq(shp->irq, boardp);
+    if (shp->dma_channel != NO_ISA_DMA) {
+        ASC_DBG(1, "advansys_release: free_dma()\n");
+        free_dma(shp->dma_channel);
+    }
+    release_region(shp->io_port, boardp->asc_n_io_port);
+    if (ASC_WIDE_BOARD(boardp)) {
+        adv_sgblk_t    *sgp = NULL;
+
+        iounmap(boardp->ioremap_addr);
+        if (boardp->orig_carrp) {
+            kfree(boardp->orig_carrp);
+            boardp->orig_carrp = NULL;
+        }
+        if (boardp->orig_reqp) {
+            kfree(boardp->orig_reqp);
+            boardp->orig_reqp = boardp->adv_reqp = NULL;
+        }
+        while ((sgp = boardp->adv_sgblkp) != NULL)
+        {
+            boardp->adv_sgblkp = sgp->next_sgblkp;
+            kfree(sgp);
+        }
+    }
+#ifdef CONFIG_PROC_FS
+    ASC_ASSERT(boardp->prtbuf != NULL);
+    kfree(boardp->prtbuf);
+#endif /* CONFIG_PROC_FS */
+    scsi_unregister(shp);
+    ASC_DBG(1, "advansys_release: end\n");
+    return 0;
+}
+
+/*
+ * advansys_info()
+ *
+ * Return suitable for printing on the console with the argument
+ * adapter's configuration information.
+ *
+ * Note: The information line should not exceed ASC_INFO_SIZE bytes,
+ * otherwise the static 'info' array will be overrun.
+ */
+const char *
+advansys_info(struct Scsi_Host *shp)
+{
+    static char     info[ASC_INFO_SIZE];
+    asc_board_t     *boardp;
+    ASC_DVC_VAR     *asc_dvc_varp;
+    ADV_DVC_VAR     *adv_dvc_varp;
+    char            *busname;
+    int             iolen;
+    char            *widename = NULL;
+
+    boardp = ASC_BOARDP(shp);
+    if (ASC_NARROW_BOARD(boardp)) {
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+        ASC_DBG(1, "advansys_info: begin\n");
+        if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+            if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+                busname = "ISA PnP";
+            } else {
+                busname = "ISA";
+            }
+            /* Don't reference 'shp->n_io_port'; It may be truncated. */
+            sprintf(info,
+"AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X, DMA 0x%X",
+                ASC_VERSION, busname,
+                (ulong) shp->io_port,
+                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
+                shp->irq, shp->dma_channel);
+        } else {
+            if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+                busname = "VL";
+            } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+                busname = "EISA";
+            } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+                if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+                    == ASC_IS_PCI_ULTRA) {
+                    busname = "PCI Ultra";
+                } else {
+                    busname = "PCI";
+                }
+            } else {
+                busname = "?";
+                ASC_PRINT2( "advansys_info: board %d: unknown bus type %d\n",
+                    boardp->id, asc_dvc_varp->bus_type);
+            }
+            /* Don't reference 'shp->n_io_port'; It may be truncated. */
+            sprintf(info,
+                "AdvanSys SCSI %s: %s: IO 0x%lX-0x%lX, IRQ 0x%X",
+                ASC_VERSION, busname,
+                (ulong) shp->io_port,
+                (ulong) shp->io_port + boardp->asc_n_io_port - 1,
+                shp->irq);
+        }
+    } else {
+        /*
+         * Wide Adapter Information
+         *
+         * Memory-mapped I/O is used instead of I/O space to access
+         * the adapter, but display the I/O Port range. The Memory
+         * I/O address is displayed through the driver /proc file.
+         */
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+        if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+        {
+            iolen = ADV_3550_IOLEN;
+            widename = "Ultra-Wide";
+        } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+        {
+            iolen = ADV_38C0800_IOLEN;
+            widename = "Ultra2-Wide";
+        } else
+        {
+            iolen = ADV_38C1600_IOLEN;
+            widename = "Ultra3-Wide";
+        }
+        sprintf(info, "AdvanSys SCSI %s: PCI %s: PCIMEM 0x%lX-0x%lX, IRQ 0x%X",
+            ASC_VERSION,
+            widename,
+            (ulong) adv_dvc_varp->iop_base,
+            (ulong) adv_dvc_varp->iop_base + iolen - 1,
+            shp->irq);
+    }
+    ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
+    ASC_DBG(1, "advansys_info: end\n");
+    return info;
+}
+
+/*
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
+ *
+ * This function always returns 0. Command return status is saved
+ * in the 'scp' result field.
+ */
+int
+advansys_queuecommand(struct scsi_cmnd *scp, void (*done)(struct scsi_cmnd *))
+{
+    struct Scsi_Host    *shp;
+    asc_board_t         *boardp;
+    ulong               flags;
+    struct scsi_cmnd           *done_scp;
+
+    shp = scp->device->host;
+    boardp = ASC_BOARDP(shp);
+    ASC_STATS(shp, queuecommand);
+
+    /* host_lock taken by mid-level prior to call but need to protect */
+    /* against own ISR */
+    spin_lock_irqsave(&boardp->lock, flags);
+
+    /*
+     * Block new commands while handling a reset or abort request.
+     */
+    if (boardp->flags & ASC_HOST_IN_RESET) {
+        ASC_DBG1(1,
+            "advansys_queuecommand: scp 0x%lx blocked for reset request\n",
+            (ulong) scp);
+        scp->result = HOST_BYTE(DID_RESET);
+
+        /*
+         * Add blocked requests to the board's 'done' queue. The queued
+         * requests will be completed at the end of the abort or reset
+         * handling.
+         */
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+	spin_unlock_irqrestore(&boardp->lock, flags);
+        return 0;
+    }
+
+    /*
+     * Attempt to execute any waiting commands for the board.
+     */
+    if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+        ASC_DBG(1,
+            "advansys_queuecommand: before asc_execute_queue() waiting\n");
+        asc_execute_queue(&boardp->waiting);
+    }
+
+    /*
+     * Save the function pointer to Linux mid-level 'done' function
+     * and attempt to execute the command.
+     *
+     * If ASC_NOERROR is returned the request has been added to the
+     * board's 'active' queue and will be completed by the interrupt
+     * handler.
+     *
+     * If ASC_BUSY is returned add the request to the board's per
+     * target waiting list. This is the first time the request has
+     * been tried. Add it to the back of the waiting list. It will be
+     * retried later.
+     *
+     * If an error occurred, the request will have been placed on the
+     * board's 'done' queue and must be completed before returning.
+     */
+    scp->scsi_done = done;
+    switch (asc_execute_scsi_cmnd(scp)) {
+    case ASC_NOERROR:
+        break;
+    case ASC_BUSY:
+        asc_enqueue(&boardp->waiting, scp, ASC_BACK);
+        break;
+    case ASC_ERROR:
+    default:
+        done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
+        /* Interrupts could be enabled here. */
+        asc_scsi_done_list(done_scp);
+        break;
+    }
+    spin_unlock_irqrestore(&boardp->lock, flags);
+
+    return 0;
+}
+
+/*
+ * advansys_reset()
+ *
+ * Reset the bus associated with the command 'scp'.
+ *
+ * This function runs its own thread. Interrupts must be blocked but
+ * sleeping is allowed and no locking other than for host structures is
+ * required. Returns SUCCESS or FAILED.
+ */
+int
+advansys_reset(struct scsi_cmnd *scp)
+{
+    struct Scsi_Host     *shp;
+    asc_board_t          *boardp;
+    ASC_DVC_VAR          *asc_dvc_varp;
+    ADV_DVC_VAR          *adv_dvc_varp;
+    ulong                flags;
+    struct scsi_cmnd            *done_scp = NULL, *last_scp = NULL;
+    struct scsi_cmnd            *tscp, *new_last_scp;
+    int                  status;
+    int                  ret = SUCCESS;
+
+    ASC_DBG1(1, "advansys_reset: 0x%lx\n", (ulong) scp);
+
+#ifdef ADVANSYS_STATS
+    if (scp->device->host != NULL) {
+        ASC_STATS(scp->device->host, reset);
+    }
+#endif /* ADVANSYS_STATS */
+
+    if ((shp = scp->device->host) == NULL) {
+        scp->result = HOST_BYTE(DID_ERROR);
+        return FAILED;
+    }
+
+    boardp = ASC_BOARDP(shp);
+
+    ASC_PRINT1("advansys_reset: board %d: SCSI bus reset started...\n",
+        boardp->id);
+    /*
+     * Check for re-entrancy.
+     */
+    spin_lock_irqsave(&boardp->lock, flags);
+    if (boardp->flags & ASC_HOST_IN_RESET) {
+	spin_unlock_irqrestore(&boardp->lock, flags);
+        return FAILED;
+    }
+    boardp->flags |= ASC_HOST_IN_RESET;
+    spin_unlock_irqrestore(&boardp->lock, flags);
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        /*
+         * Narrow Board
+         */
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+
+        /*
+         * Reset the chip and SCSI bus.
+         */
+        ASC_DBG(1, "advansys_reset: before AscInitAsc1000Driver()\n");
+        status = AscInitAsc1000Driver(asc_dvc_varp);
+
+        /* Refer to ASC_IERR_* defintions for meaning of 'err_code'. */
+        if (asc_dvc_varp->err_code) {
+            ASC_PRINT2(
+                "advansys_reset: board %d: SCSI bus reset error: 0x%x\n",
+                boardp->id, asc_dvc_varp->err_code);
+            ret = FAILED;
+        } else if (status) {
+            ASC_PRINT2(
+                "advansys_reset: board %d: SCSI bus reset warning: 0x%x\n",
+                boardp->id, status);
+        } else {
+            ASC_PRINT1(
+                "advansys_reset: board %d: SCSI bus reset successful.\n",
+                boardp->id);
+        }
+
+        ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
+	spin_lock_irqsave(&boardp->lock, flags);
+
+    } else {
+        /*
+         * Wide Board
+         *
+         * If the suggest reset bus flags are set, then reset the bus.
+         * Otherwise only reset the device.
+         */
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+
+        /*
+         * Reset the target's SCSI bus.
+         */
+        ASC_DBG(1, "advansys_reset: before AdvResetChipAndSB()\n");
+        switch (AdvResetChipAndSB(adv_dvc_varp)) {
+        case ASC_TRUE:
+            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset successful.\n",
+                boardp->id);
+            break;
+        case ASC_FALSE:
+        default:
+            ASC_PRINT1("advansys_reset: board %d: SCSI bus reset error.\n",
+                boardp->id);
+            ret = FAILED;
+            break;
+        }
+	spin_lock_irqsave(&boardp->lock, flags);
+        (void) AdvISR(adv_dvc_varp);
+    }
+    /* Board lock is held. */
+
+    /*
+     * Dequeue all board 'done' requests. A pointer to the last request
+     * is returned in 'last_scp'.
+     */
+    done_scp = asc_dequeue_list(&boardp->done, &last_scp, ASC_TID_ALL);
+
+    /*
+     * Dequeue all board 'active' requests for all devices and set
+     * the request status to DID_RESET. A pointer to the last request
+     * is returned in 'last_scp'.
+     */
+    if (done_scp == NULL) {
+        done_scp = asc_dequeue_list(&boardp->active, &last_scp, ASC_TID_ALL);
+        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+            tscp->result = HOST_BYTE(DID_RESET);
+        }
+    } else {
+        /* Append to 'done_scp' at the end with 'last_scp'. */
+        ASC_ASSERT(last_scp != NULL);
+        last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
+			&boardp->active, &new_last_scp, ASC_TID_ALL);
+        if (new_last_scp != NULL) {
+            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
+            }
+            last_scp = new_last_scp;
+        }
+    }
+
+    /*
+     * Dequeue all 'waiting' requests and set the request status
+     * to DID_RESET.
+     */
+    if (done_scp == NULL) {
+        done_scp = asc_dequeue_list(&boardp->waiting, &last_scp, ASC_TID_ALL);
+        for (tscp = done_scp; tscp; tscp = REQPNEXT(tscp)) {
+            tscp->result = HOST_BYTE(DID_RESET);
+        }
+    } else {
+        /* Append to 'done_scp' at the end with 'last_scp'. */
+        ASC_ASSERT(last_scp != NULL);
+        last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
+			&boardp->waiting, &new_last_scp, ASC_TID_ALL);
+        if (new_last_scp != NULL) {
+            ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+            for (tscp = REQPNEXT(last_scp); tscp; tscp = REQPNEXT(tscp)) {
+                tscp->result = HOST_BYTE(DID_RESET);
+            }
+            last_scp = new_last_scp;
+        }
+    }
+
+    /* Save the time of the most recently completed reset. */
+    boardp->last_reset = jiffies;
+
+    /* Clear reset flag. */
+    boardp->flags &= ~ASC_HOST_IN_RESET;
+    spin_unlock_irqrestore(&boardp->lock, flags);
+
+    /*
+     * Complete all the 'done_scp' requests.
+     */
+    if (done_scp != NULL) {
+        asc_scsi_done_list(done_scp);
+    }
+
+    ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
+
+    return ret;
+}
+
+/*
+ * advansys_biosparam()
+ *
+ * Translate disk drive geometry if the "BIOS greater than 1 GB"
+ * support is enabled for a drive.
+ *
+ * ip (information pointer) is an int array with the following definition:
+ * ip[0]: heads
+ * ip[1]: sectors
+ * ip[2]: cylinders
+ */
+int
+advansys_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int ip[])
+{
+    asc_board_t     *boardp;
+
+    ASC_DBG(1, "advansys_biosparam: begin\n");
+    ASC_STATS(sdev->host, biosparam);
+    boardp = ASC_BOARDP(sdev->host);
+    if (ASC_NARROW_BOARD(boardp)) {
+        if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+             ASC_CNTL_BIOS_GT_1GB) && capacity > 0x200000) {
+                ip[0] = 255;
+                ip[1] = 63;
+        } else {
+                ip[0] = 64;
+                ip[1] = 32;
+        }
+    } else {
+        if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+             BIOS_CTRL_EXTENDED_XLAT) && capacity > 0x200000) {
+                ip[0] = 255;
+                ip[1] = 63;
+        } else {
+                ip[0] = 64;
+                ip[1] = 32;
+        }
+    }
+    ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+    ASC_DBG(1, "advansys_biosparam: end\n");
+    return 0;
+}
+
+/*
+ * advansys_setup()
+ *
+ * This function is called from init/main.c at boot time.
+ * It it passed LILO parameters that can be set from the
+ * LILO command line or in /etc/lilo.conf.
+ *
+ * It is used by the AdvanSys driver to either disable I/O
+ * port scanning or to limit scanning to 1 - 4 I/O ports.
+ * Regardless of the option setting EISA and PCI boards
+ * will still be searched for and detected. This option
+ * only affects searching for ISA and VL boards.
+ *
+ * If ADVANSYS_DEBUG is defined the driver debug level may
+ * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
+ *
+ * Examples:
+ * 1. Eliminate I/O port scanning:
+ *         boot: linux advansys=
+ *       or
+ *         boot: linux advansys=0x0
+ * 2. Limit I/O port scanning to one I/O port:
+ *        boot: linux advansys=0x110
+ * 3. Limit I/O port scanning to four I/O ports:
+ *        boot: linux advansys=0x110,0x210,0x230,0x330
+ * 4. If ADVANSYS_DEBUG, limit I/O port scanning to four I/O ports and
+ *    set the driver debug level to 2.
+ *        boot: linux advansys=0x110,0x210,0x230,0x330,0xdeb2
+ *
+ * ints[0] - number of arguments
+ * ints[1] - first argument
+ * ints[2] - second argument
+ * ...
+ */
+void __init
+advansys_setup(char *str, int *ints)
+{
+    int    i;
+
+    if (asc_iopflag == ASC_TRUE) {
+        printk("AdvanSys SCSI: 'advansys' LILO option may appear only once\n");
+        return;
+    }
+
+    asc_iopflag = ASC_TRUE;
+
+    if (ints[0] > ASC_NUM_IOPORT_PROBE) {
+#ifdef ADVANSYS_DEBUG
+        if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
+            (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
+            asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
+        } else {
+#endif /* ADVANSYS_DEBUG */
+            printk("AdvanSys SCSI: only %d I/O ports accepted\n",
+                ASC_NUM_IOPORT_PROBE);
+#ifdef ADVANSYS_DEBUG
+        }
+#endif /* ADVANSYS_DEBUG */
+    }
+
+#ifdef ADVANSYS_DEBUG
+    ASC_DBG1(1, "advansys_setup: ints[0] %d\n", ints[0]);
+    for (i = 1; i < ints[0]; i++) {
+        ASC_DBG2(1, " ints[%d] 0x%x", i, ints[i]);
+    }
+    ASC_DBG(1, "\n");
+#endif /* ADVANSYS_DEBUG */
+
+    for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
+        asc_ioport[i-1] = ints[i];
+        ASC_DBG2(1, "advansys_setup: asc_ioport[%d] 0x%x\n",
+            i - 1, asc_ioport[i-1]);
+    }
+}
+
+
+/*
+ * --- Loadable Driver Support
+ */
+
+static struct scsi_host_template driver_template = {
+    .proc_name                  = "advansys",
+#ifdef CONFIG_PROC_FS
+    .proc_info                  = advansys_proc_info,
+#endif
+    .name                       = "advansys",
+    .detect                     = advansys_detect, 
+    .release                    = advansys_release,
+    .info                       = advansys_info,
+    .queuecommand               = advansys_queuecommand,
+    .eh_bus_reset_handler	= advansys_reset,
+    .bios_param                 = advansys_biosparam,
+    .slave_configure		= advansys_slave_configure,
+    /*
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+     * must be set. The flag will be cleared in advansys_detect for non-ISA
+     * adapters. Refer to the comment in scsi_module.c for more information.
+     */
+    .unchecked_isa_dma          = 1,
+    /*
+     * All adapters controlled by this driver are capable of large
+     * scatter-gather lists. According to the mid-level SCSI documentation
+     * this obviates any performance gain provided by setting
+     * 'use_clustering'. But empirically while CPU utilization is increased
+     * by enabling clustering, I/O throughput increases as well.
+     */
+    .use_clustering             = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+
+
+/*
+ * --- Miscellaneous Driver Functions
+ */
+
+/*
+ * First-level interrupt handler.
+ *
+ * 'dev_id' is a pointer to the interrupting adapter's asc_board_t. Because
+ * all boards are currently checked for interrupts on each interrupt, 'dev_id'
+ * is not referenced. 'dev_id' could be used to identify an interrupt passed
+ * to the AdvanSys driver which is for a device sharing an interrupt with
+ * an AdvanSys adapter.
+ */
+STATIC irqreturn_t
+advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    ulong           flags;
+    int             i;
+    asc_board_t     *boardp;
+    struct scsi_cmnd       *done_scp = NULL, *last_scp = NULL;
+    struct scsi_cmnd       *new_last_scp;
+    struct Scsi_Host *shp;
+
+    ASC_DBG(1, "advansys_interrupt: begin\n");
+
+    /*
+     * Check for interrupts on all boards.
+     * AscISR() will call asc_isr_callback().
+     */
+    for (i = 0; i < asc_board_count; i++) {
+	shp = asc_host[i];
+        boardp = ASC_BOARDP(shp);
+        ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
+            i, (ulong) boardp);
+        spin_lock_irqsave(&boardp->lock, flags);
+        if (ASC_NARROW_BOARD(boardp)) {
+            /*
+             * Narrow Board
+             */
+            if (AscIsIntPending(shp->io_port)) {
+                ASC_STATS(shp, interrupt);
+                ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
+                AscISR(&boardp->dvc_var.asc_dvc_var);
+            }
+        } else {
+            /*
+             * Wide Board
+             */
+            ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
+            if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+                ASC_STATS(shp, interrupt);
+            }
+        }
+
+        /*
+         * Start waiting requests and create a list of completed requests.
+         *
+         * If a reset request is being performed for the board, the reset
+         * handler will complete pending requests after it has completed.
+         */
+        if ((boardp->flags & ASC_HOST_IN_RESET) == 0) {
+            ASC_DBG2(1, "advansys_interrupt: done_scp 0x%lx, last_scp 0x%lx\n",
+                (ulong) done_scp, (ulong) last_scp);
+
+            /* Start any waiting commands for the board. */
+            if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
+                ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
+                asc_execute_queue(&boardp->waiting);
+            }
+
+             /*
+              * Add to the list of requests that must be completed.
+              *
+              * 'done_scp' will always be NULL on the first iteration
+              * of this loop. 'last_scp' is set at the same time as
+              * 'done_scp'.
+              */
+            if (done_scp == NULL) {
+                done_scp = asc_dequeue_list(&boardp->done, &last_scp,
+                    ASC_TID_ALL);
+            } else {
+                ASC_ASSERT(last_scp != NULL);
+                last_scp->host_scribble = (unsigned char *)asc_dequeue_list(
+			&boardp->done, &new_last_scp, ASC_TID_ALL);
+                if (new_last_scp != NULL) {
+                    ASC_ASSERT(REQPNEXT(last_scp) != NULL);
+                    last_scp = new_last_scp;
+                }
+            }
+        }
+        spin_unlock_irqrestore(&boardp->lock, flags);
+    }
+
+    /*
+     * If interrupts were enabled on entry, then they
+     * are now enabled here.
+     *
+     * Complete all requests on the done list.
+     */
+
+    asc_scsi_done_list(done_scp);
+
+    ASC_DBG(1, "advansys_interrupt: end\n");
+    return IRQ_HANDLED;
+}
+
+/*
+ * Set the number of commands to queue per device for the
+ * specified host adapter.
+ */
+STATIC int
+advansys_slave_configure(struct scsi_device *device)
+{
+    asc_board_t        *boardp;
+
+    boardp = ASC_BOARDP(device->host);
+    boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
+    /*
+     * Save a pointer to the device and set its initial/maximum
+     * queue depth.  Only save the pointer for a lun0 dev though.
+     */
+    if(device->lun == 0)
+        boardp->device[device->id] = device;
+    if(device->tagged_supported) {
+        if (ASC_NARROW_BOARD(boardp)) {
+	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+                boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id]);
+        } else {
+	    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+                boardp->dvc_var.adv_dvc_var.max_dvc_qng);
+        }
+    } else {
+	scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
+    }
+    ASC_DBG4(1, "advansys_slave_configure: device 0x%lx, boardp 0x%lx, id %d, depth %d\n",
+            (ulong) device, (ulong) boardp, device->id, device->queue_depth);
+    return 0;
+}
+
+/*
+ * Complete all requests on the singly linked list pointed
+ * to by 'scp'.
+ *
+ * Interrupts can be enabled on entry.
+ */
+STATIC void
+asc_scsi_done_list(struct scsi_cmnd *scp)
+{
+    struct scsi_cmnd    *tscp;
+
+    ASC_DBG(2, "asc_scsi_done_list: begin\n");
+    while (scp != NULL) {
+	asc_board_t *boardp;
+	struct device *dev;
+
+        ASC_DBG1(3, "asc_scsi_done_list: scp 0x%lx\n", (ulong) scp);
+        tscp = REQPNEXT(scp);
+        scp->host_scribble = NULL;
+
+	boardp = ASC_BOARDP(scp->device->host);
+
+	if (ASC_NARROW_BOARD(boardp))
+	    dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+	else
+	    dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+
+	if (scp->use_sg)
+	    dma_unmap_sg(dev, (struct scatterlist *)scp->request_buffer,
+			 scp->use_sg, scp->sc_data_direction);
+	else if (scp->request_bufflen)
+	    dma_unmap_single(dev, scp->SCp.dma_handle,
+			     scp->request_bufflen, scp->sc_data_direction);
+
+        ASC_STATS(scp->device->host, done);
+        ASC_ASSERT(scp->scsi_done != NULL);
+
+        scp->scsi_done(scp);
+
+        scp = tscp;
+    }
+    ASC_DBG(2, "asc_scsi_done_list: done\n");
+    return;
+}
+
+/*
+ * Execute a single 'Scsi_Cmnd'.
+ *
+ * The function 'done' is called when the request has been completed.
+ *
+ * Scsi_Cmnd:
+ *
+ *  host - board controlling device
+ *  device - device to send command
+ *  target - target of device
+ *  lun - lun of device
+ *  cmd_len - length of SCSI CDB
+ *  cmnd - buffer for SCSI 8, 10, or 12 byte CDB
+ *  use_sg - if non-zero indicates scatter-gather request with use_sg elements
+ *
+ *  if (use_sg == 0) {
+ *    request_buffer - buffer address for request
+ *    request_bufflen - length of request buffer
+ *  } else {
+ *    request_buffer - pointer to scatterlist structure
+ *  }
+ *
+ *  sense_buffer - sense command buffer
+ *
+ *  result (4 bytes of an int):
+ *    Byte Meaning
+ *    0 SCSI Status Byte Code
+ *    1 SCSI One Byte Message Code
+ *    2 Host Error Code
+ *    3 Mid-Level Error Code
+ *
+ *  host driver fields:
+ *    SCp - Scsi_Pointer used for command processing status
+ *    scsi_done - used to save caller's done function
+ *    host_scribble - used for pointer to another struct scsi_cmnd
+ *
+ * If this function returns ASC_NOERROR the request has been enqueued
+ * on the board's 'active' queue and will be completed from the
+ * interrupt handler.
+ *
+ * If this function returns ASC_NOERROR the request has been enqueued
+ * on the board's 'done' queue and must be completed by the caller.
+ *
+ * If ASC_BUSY is returned the request will be enqueued by the
+ * caller on the target's waiting queue and re-tried later.
+ */
+STATIC int
+asc_execute_scsi_cmnd(struct scsi_cmnd *scp)
+{
+    asc_board_t        *boardp;
+    ASC_DVC_VAR        *asc_dvc_varp;
+    ADV_DVC_VAR        *adv_dvc_varp;
+    ADV_SCSI_REQ_Q     *adv_scsiqp;
+    struct scsi_device *device;
+    int                ret;
+
+    ASC_DBG2(1, "asc_execute_scsi_cmnd: scp 0x%lx, done 0x%lx\n",
+        (ulong) scp, (ulong) scp->scsi_done);
+
+    boardp = ASC_BOARDP(scp->device->host);
+    device = boardp->device[scp->device->id];
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        /*
+         * Build and execute Narrow Board request.
+         */
+
+        asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+
+        /*
+         * Build Asc Library request structure using the
+         * global structures 'asc_scsi_req' and 'asc_sg_head'.
+         *
+         * If an error is returned, then the request has been
+         * queued on the board done queue. It will be completed
+         * by the caller.
+         *
+         * asc_build_req() can not return ASC_BUSY.
+         */
+        if (asc_build_req(boardp, scp) == ASC_ERROR) {
+            ASC_STATS(scp->device->host, build_error);
+            return ASC_ERROR;
+        }
+
+        /*
+         * Execute the command. If there is no error, add the command
+         * to the active queue.
+         */
+        switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
+        case ASC_NOERROR:
+            ASC_STATS(scp->device->host, exe_noerror);
+            /*
+             * Increment monotonically increasing per device successful
+             * request counter. Wrapping doesn't matter.
+             */
+            boardp->reqcnt[scp->device->id]++;
+            asc_enqueue(&boardp->active, scp, ASC_BACK);
+            ASC_DBG(1,
+                "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            /*
+             * Caller will enqueue request on the target's waiting queue
+             * and retry later.
+             */
+            ASC_STATS(scp->device->host, exe_busy);
+            break;
+        case ASC_ERROR:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+                boardp->id, asc_dvc_varp->err_code);
+            ASC_STATS(scp->device->host, exe_error);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        default:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code 0x%x\n",
+                boardp->id, asc_dvc_varp->err_code);
+            ASC_STATS(scp->device->host, exe_unknown);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        }
+    } else {
+        /*
+         * Build and execute Wide Board request.
+         */
+        adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+
+        /*
+         * Build and get a pointer to an Adv Library request structure.
+         *
+         * If the request is successfully built then send it below,
+         * otherwise return with an error.
+         */
+        switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+        case ASC_NOERROR:
+            ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+            /*
+             * If busy is returned the request has not been enqueued.
+             * It will be enqueued by the caller on the target's waiting
+             * queue and retried later.
+             *
+             * The asc_stats fields 'adv_build_noreq' and 'adv_build_nosg'
+             * count wide board busy conditions. They are updated in
+             * adv_build_req and adv_get_sglist, respectively.
+             */
+            return ASC_BUSY;
+        case ASC_ERROR:
+             /* 
+              * If an error is returned, then the request has been
+              * queued on the board done queue. It will be completed
+              * by the caller.
+              */
+        default:
+            ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
+            ASC_STATS(scp->device->host, build_error);
+            return ASC_ERROR;
+        }
+
+        /*
+         * Execute the command. If there is no error, add the command
+         * to the active queue.
+         */
+        switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
+        case ASC_NOERROR:
+            ASC_STATS(scp->device->host, exe_noerror);
+            /*
+             * Increment monotonically increasing per device successful
+             * request counter. Wrapping doesn't matter.
+             */
+            boardp->reqcnt[scp->device->id]++;
+            asc_enqueue(&boardp->active, scp, ASC_BACK);
+            ASC_DBG(1,
+                "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
+            break;
+        case ASC_BUSY:
+            /*
+             * Caller will enqueue request on the target's waiting queue
+             * and retry later.
+             */
+            ASC_STATS(scp->device->host, exe_busy);
+            break;
+        case ASC_ERROR:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code 0x%x\n",
+                boardp->id, adv_dvc_varp->err_code);
+            ASC_STATS(scp->device->host, exe_error);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        default:
+            ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code 0x%x\n",
+                boardp->id, adv_dvc_varp->err_code);
+            ASC_STATS(scp->device->host, exe_unknown);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            break;
+        }
+    }
+
+    ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+    return ret;
+}
+
+/*
+ * Build a request structure for the Asc Library (Narrow Board).
+ *
+ * The global structures 'asc_scsi_q' and 'asc_sg_head' are
+ * used to build the request.
+ *
+ * If an error occurs, then queue the request on the board done
+ * queue and return ASC_ERROR.
+ */
+STATIC int
+asc_build_req(asc_board_t *boardp, struct scsi_cmnd *scp)
+{
+    struct device *dev = boardp->dvc_cfg.asc_dvc_cfg.dev;
+
+    /*
+     * Mutually exclusive access is required to 'asc_scsi_q' and
+     * 'asc_sg_head' until after the request is started.
+     */
+    memset(&asc_scsi_q, 0, sizeof(ASC_SCSI_Q));
+
+    /*
+     * Point the ASC_SCSI_Q to the 'struct scsi_cmnd'.
+     */
+    asc_scsi_q.q2.srb_ptr = ASC_VADDR_TO_U32(scp);
+
+    /*
+     * Build the ASC_SCSI_Q request.
+     *
+     * For narrow boards a CDB length maximum of 12 bytes
+     * is supported.
+     */
+    if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+        ASC_PRINT3(
+"asc_build_req: board %d: cmd_len %d > ASC_MAX_CDB_LEN  %d\n",
+            boardp->id, scp->cmd_len, ASC_MAX_CDB_LEN);
+        scp->result = HOST_BYTE(DID_ERROR);
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+        return ASC_ERROR;
+    }
+    asc_scsi_q.cdbptr = &scp->cmnd[0];
+    asc_scsi_q.q2.cdb_len = scp->cmd_len;
+    asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->device->id);
+    asc_scsi_q.q1.target_lun = scp->device->lun;
+    asc_scsi_q.q2.target_ix = ASC_TIDLUN_TO_IX(scp->device->id, scp->device->lun);
+    asc_scsi_q.q1.sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+    asc_scsi_q.q1.sense_len = sizeof(scp->sense_buffer);
+
+    /*
+     * If there are any outstanding requests for the current target,
+     * then every 255th request send an ORDERED request. This heuristic
+     * tries to retain the benefit of request sorting while preventing
+     * request starvation. 255 is the max number of tags or pending commands
+     * a device may have outstanding.
+     *
+     * The request count is incremented below for every successfully
+     * started request.
+     *
+     */
+    if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->device->id] > 0) &&
+        (boardp->reqcnt[scp->device->id] % 255) == 0) {
+        asc_scsi_q.q2.tag_code = MSG_ORDERED_TAG;
+    } else {
+        asc_scsi_q.q2.tag_code = MSG_SIMPLE_TAG;
+    }
+
+    /*
+     * Build ASC_SCSI_Q for a contiguous buffer or a scatter-gather
+     * buffer command.
+     */
+    if (scp->use_sg == 0) {
+        /*
+         * CDB request of single contiguous buffer.
+         */
+        ASC_STATS(scp->device->host, cont_cnt);
+	scp->SCp.dma_handle = scp->request_bufflen ?
+	    dma_map_single(dev, scp->request_buffer,
+			   scp->request_bufflen, scp->sc_data_direction) : 0;
+	asc_scsi_q.q1.data_addr = cpu_to_le32(scp->SCp.dma_handle);
+        asc_scsi_q.q1.data_cnt = cpu_to_le32(scp->request_bufflen);
+        ASC_STATS_ADD(scp->device->host, cont_xfer,
+                      ASC_CEILING(scp->request_bufflen, 512));
+        asc_scsi_q.q1.sg_queue_cnt = 0;
+        asc_scsi_q.sg_head = NULL;
+    } else {
+        /*
+         * CDB scatter-gather request list.
+         */
+        int                     sgcnt;
+	int			use_sg;
+        struct scatterlist      *slp;
+
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+	if (use_sg > scp->device->host->sg_tablesize) {
+            ASC_PRINT3(
+"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+            return ASC_ERROR;
+        }
+
+        ASC_STATS(scp->device->host, sg_cnt);
+
+        /*
+         * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
+         * structure to point to it.
+         */
+        memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
+
+        asc_scsi_q.q1.cntl |= QC_SG_HEAD;
+        asc_scsi_q.sg_head = &asc_sg_head;
+        asc_scsi_q.q1.data_cnt = 0;
+        asc_scsi_q.q1.data_addr = 0;
+        /* This is a byte value, otherwise it would need to be swapped. */
+	asc_sg_head.entry_cnt = asc_scsi_q.q1.sg_queue_cnt = use_sg;
+        ASC_STATS_ADD(scp->device->host, sg_elem, asc_sg_head.entry_cnt);
+
+        /*
+         * Convert scatter-gather list into ASC_SG_HEAD list.
+         */
+	for (sgcnt = 0; sgcnt < use_sg; sgcnt++, slp++) {
+	    asc_sg_head.sg_list[sgcnt].addr = cpu_to_le32(sg_dma_address(slp));
+	    asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
+        }
+    }
+
+    ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
+    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+    return ASC_NOERROR;
+}
+
+/*
+ * Build a request structure for the Adv Library (Wide Board).
+ *
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the
+ * microcode for DMA addresses or math operations are byte swapped
+ * to little-endian order.
+ */
+STATIC int
+adv_build_req(asc_board_t *boardp, struct scsi_cmnd *scp,
+    ADV_SCSI_REQ_Q **adv_scsiqpp)
+{
+    adv_req_t           *reqp;
+    ADV_SCSI_REQ_Q      *scsiqp;
+    int                 i;
+    int                 ret;
+    struct device	*dev = boardp->dvc_cfg.adv_dvc_cfg.dev;
+
+    /*
+     * Allocate an adv_req_t structure from the board to execute
+     * the command.
+     */
+    if (boardp->adv_reqp == NULL) {
+        ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
+        ASC_STATS(scp->device->host, adv_build_noreq);
+        return ASC_BUSY;
+    } else {
+        reqp = boardp->adv_reqp;
+        boardp->adv_reqp = reqp->next_reqp;
+        reqp->next_reqp = NULL;
+    }
+
+    /*
+     * Get 32-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+     */
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
+
+    /*
+     * Initialize the structure.
+     */
+    scsiqp->cntl = scsiqp->scsi_cntl = scsiqp->done_status = 0;
+
+    /*
+     * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+     */
+    scsiqp->srb_ptr = ASC_VADDR_TO_U32(reqp);
+
+    /*
+     * Set the adv_req_t 'cmndp' to point to the struct scsi_cmnd structure.
+     */
+    reqp->cmndp = scp;
+
+    /*
+     * Build the ADV_SCSI_REQ_Q request.
+     */
+
+    /*
+     * Set CDB length and copy it to the request structure.
+     * For wide  boards a CDB length maximum of 16 bytes
+     * is supported.
+     */
+    if (scp->cmd_len > ADV_MAX_CDB_LEN) {
+        ASC_PRINT3(
+"adv_build_req: board %d: cmd_len %d > ADV_MAX_CDB_LEN  %d\n",
+            boardp->id, scp->cmd_len, ADV_MAX_CDB_LEN);
+        scp->result = HOST_BYTE(DID_ERROR);
+        asc_enqueue(&boardp->done, scp, ASC_BACK);
+        return ASC_ERROR;
+    }
+    scsiqp->cdb_len = scp->cmd_len;
+    /* Copy first 12 CDB bytes to cdb[]. */
+    for (i = 0; i < scp->cmd_len && i < 12; i++) {
+        scsiqp->cdb[i] = scp->cmnd[i];
+    }
+    /* Copy last 4 CDB bytes, if present, to cdb16[]. */
+    for (; i < scp->cmd_len; i++) {
+        scsiqp->cdb16[i - 12] = scp->cmnd[i];
+    }
+
+    scsiqp->target_id = scp->device->id;
+    scsiqp->target_lun = scp->device->lun;
+
+    scsiqp->sense_addr = cpu_to_le32(virt_to_bus(&scp->sense_buffer[0]));
+    scsiqp->sense_len = sizeof(scp->sense_buffer);
+
+    /*
+     * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
+     * buffer command.
+     */
+
+    scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+    scsiqp->vdata_addr = scp->request_buffer;
+    scsiqp->data_addr = cpu_to_le32(virt_to_bus(scp->request_buffer));
+
+    if (scp->use_sg == 0) {
+        /*
+         * CDB request of single contiguous buffer.
+         */
+        reqp->sgblkp = NULL;
+	scsiqp->data_cnt = cpu_to_le32(scp->request_bufflen);
+	if (scp->request_bufflen) {
+	    scsiqp->vdata_addr = scp->request_buffer;
+	    scp->SCp.dma_handle =
+	        dma_map_single(dev, scp->request_buffer,
+			       scp->request_bufflen, scp->sc_data_direction);
+	} else {
+	    scsiqp->vdata_addr = 0;
+	    scp->SCp.dma_handle = 0;
+	}
+	scsiqp->data_addr = cpu_to_le32(scp->SCp.dma_handle);
+        scsiqp->sg_list_ptr = NULL;
+        scsiqp->sg_real_addr = 0;
+        ASC_STATS(scp->device->host, cont_cnt);
+        ASC_STATS_ADD(scp->device->host, cont_xfer,
+                      ASC_CEILING(scp->request_bufflen, 512));
+    } else {
+        /*
+         * CDB scatter-gather request list.
+         */
+	struct scatterlist *slp;
+	int use_sg;
+
+	slp = (struct scatterlist *)scp->request_buffer;
+	use_sg = dma_map_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+
+	if (use_sg > ADV_MAX_SG_LIST) {
+            ASC_PRINT3(
+"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
+		boardp->id, use_sg, scp->device->host->sg_tablesize);
+	    dma_unmap_sg(dev, slp, scp->use_sg, scp->sc_data_direction);
+            scp->result = HOST_BYTE(DID_ERROR);
+            asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+            /*
+             * Free the 'adv_req_t' structure by adding it back to the
+             * board free list.
+             */
+            reqp->next_reqp = boardp->adv_reqp;
+            boardp->adv_reqp = reqp;
+
+            return ASC_ERROR;
+        }
+
+	if ((ret = adv_get_sglist(boardp, reqp, scp, use_sg)) != ADV_SUCCESS) {
+            /*
+             * Free the adv_req_t structure by adding it back to the
+             * board free list.
+             */
+            reqp->next_reqp = boardp->adv_reqp;
+            boardp->adv_reqp = reqp;
+
+            return ret;
+        }
+
+        ASC_STATS(scp->device->host, sg_cnt);
+	ASC_STATS_ADD(scp->device->host, sg_elem, use_sg);
+    }
+
+    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+    ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+    *adv_scsiqpp = scsiqp;
+
+    return ASC_NOERROR;
+}
+
+/*
+ * Build scatter-gather list for Adv Library (Wide Board).
+ *
+ * Additional ADV_SG_BLOCK structures will need to be allocated
+ * if the total number of scatter-gather elements exceeds
+ * NO_OF_SG_PER_BLOCK (15). The ADV_SG_BLOCK structures are
+ * assumed to be physically contiguous.
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - SG List successfully created
+ *      ADV_ERROR(-1) - SG List creation failed
+ */
+STATIC int
+adv_get_sglist(asc_board_t *boardp, adv_req_t *reqp, struct scsi_cmnd *scp, int use_sg)
+{
+    adv_sgblk_t         *sgblkp;
+    ADV_SCSI_REQ_Q      *scsiqp;
+    struct scatterlist  *slp;
+    int                 sg_elem_cnt;
+    ADV_SG_BLOCK        *sg_block, *prev_sg_block;
+    ADV_PADDR           sg_block_paddr;
+    int                 i;
+
+    scsiqp = (ADV_SCSI_REQ_Q *) ADV_32BALIGN(&reqp->scsi_req_q);
+    slp = (struct scatterlist *) scp->request_buffer;
+    sg_elem_cnt = use_sg;
+    prev_sg_block = NULL;
+    reqp->sgblkp = NULL;
+
+    do
+    {
+        /*
+         * Allocate a 'adv_sgblk_t' structure from the board free
+         * list. One 'adv_sgblk_t' structure holds NO_OF_SG_PER_BLOCK
+         * (15) scatter-gather elements.
+         */
+        if ((sgblkp = boardp->adv_sgblkp) == NULL) {
+            ASC_DBG(1, "adv_get_sglist: no free adv_sgblk_t\n");
+            ASC_STATS(scp->device->host, adv_build_nosg);
+
+            /*
+             * Allocation failed. Free 'adv_sgblk_t' structures already
+             * allocated for the request.
+             */
+            while ((sgblkp = reqp->sgblkp) != NULL)
+            {
+                /* Remove 'sgblkp' from the request list. */
+                reqp->sgblkp = sgblkp->next_sgblkp;
+
+                /* Add 'sgblkp' to the board free list. */
+                sgblkp->next_sgblkp = boardp->adv_sgblkp;
+                boardp->adv_sgblkp = sgblkp;
+            }
+            return ASC_BUSY;
+        } else {
+            /* Complete 'adv_sgblk_t' board allocation. */
+            boardp->adv_sgblkp = sgblkp->next_sgblkp;
+            sgblkp->next_sgblkp = NULL;
+
+            /*
+             * Get 8 byte aligned virtual and physical addresses for
+             * the allocated ADV_SG_BLOCK structure.
+             */
+            sg_block = (ADV_SG_BLOCK *) ADV_8BALIGN(&sgblkp->sg_block);
+            sg_block_paddr = virt_to_bus(sg_block);
+
+            /*
+             * Check if this is the first 'adv_sgblk_t' for the request.
+             */
+            if (reqp->sgblkp == NULL)
+            {
+                /* Request's first scatter-gather block. */
+                reqp->sgblkp = sgblkp;
+
+                /*
+                 * Set ADV_SCSI_REQ_T ADV_SG_BLOCK virtual and physical
+                 * address pointers.
+                 */
+                scsiqp->sg_list_ptr = sg_block;
+                scsiqp->sg_real_addr = cpu_to_le32(sg_block_paddr);
+            } else
+            {
+                /* Request's second or later scatter-gather block. */
+                sgblkp->next_sgblkp = reqp->sgblkp;
+                reqp->sgblkp = sgblkp;
+
+                /*
+                 * Point the previous ADV_SG_BLOCK structure to
+                 * the newly allocated ADV_SG_BLOCK structure.
+                 */
+                ASC_ASSERT(prev_sg_block != NULL);
+                prev_sg_block->sg_ptr = cpu_to_le32(sg_block_paddr);
+            }
+        }
+
+        for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
+        {
+	    sg_block->sg_list[i].sg_addr = cpu_to_le32(sg_dma_address(slp));
+	    sg_block->sg_list[i].sg_count = cpu_to_le32(sg_dma_len(slp));
+	    ASC_STATS_ADD(scp->device->host, sg_xfer, ASC_CEILING(sg_dma_len(slp), 512));
+
+            if (--sg_elem_cnt == 0)
+            {   /* Last ADV_SG_BLOCK and scatter-gather entry. */
+                sg_block->sg_cnt = i + 1;
+                sg_block->sg_ptr = 0L;    /* Last ADV_SG_BLOCK in list. */
+                return ADV_SUCCESS;
+            }
+            slp++;
+        }
+        sg_block->sg_cnt = NO_OF_SG_PER_BLOCK;
+        prev_sg_block = sg_block;
+    }
+    while (1);
+    /* NOTREACHED */
+}
+
+/*
+ * asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
+ */
+STATIC void
+asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
+{
+    asc_board_t         *boardp;
+    struct scsi_cmnd           *scp;
+    struct Scsi_Host    *shp;
+    int                 i;
+
+    ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp 0x%lx, qdonep 0x%lx\n",
+        (ulong) asc_dvc_varp, (ulong) qdonep);
+    ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
+
+    /*
+     * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+     * command that has been completed.
+     */
+    scp = (struct scsi_cmnd *) ASC_U32_TO_VADDR(qdonep->d2.srb_ptr);
+    ASC_DBG1(1, "asc_isr_callback: scp 0x%lx\n", (ulong) scp);
+
+    if (scp == NULL) {
+        ASC_PRINT("asc_isr_callback: scp is NULL\n");
+        return;
+    }
+    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+    /*
+     * If the request's host pointer is not valid, display a
+     * message and return.
+     */
+    shp = scp->device->host;
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i] == shp) {
+            break;
+        }
+    }
+    if (i == asc_board_count) {
+        ASC_PRINT2(
+            "asc_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+            (ulong) scp, (ulong) shp);
+        return;
+    }
+
+    ASC_STATS(shp, callback);
+    ASC_DBG1(1, "asc_isr_callback: shp 0x%lx\n", (ulong) shp);
+
+    /*
+     * If the request isn't found on the active queue, it may
+     * have been removed to handle a reset request.
+     * Display a message and return.
+     */
+    boardp = ASC_BOARDP(shp);
+    ASC_ASSERT(asc_dvc_varp == &boardp->dvc_var.asc_dvc_var);
+    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+        ASC_PRINT2(
+            "asc_isr_callback: board %d: scp 0x%lx not on active queue\n",
+            boardp->id, (ulong) scp);
+        return;
+    }
+
+    /*
+     * 'qdonep' contains the command's ending status.
+     */
+    switch (qdonep->d3.done_stat) {
+    case QD_NO_ERROR:
+        ASC_DBG(2, "asc_isr_callback: QD_NO_ERROR\n");
+        scp->result = 0;
+
+        /*
+         * If an INQUIRY command completed successfully, then call
+         * the AscInquiryHandling() function to set-up the device.
+         */
+        if (scp->cmnd[0] == INQUIRY && scp->device->lun == 0 &&
+            (scp->request_bufflen - qdonep->remain_bytes) >= 8)
+        {
+            AscInquiryHandling(asc_dvc_varp, scp->device->id & 0x7,
+                (ASC_SCSI_INQUIRY *) scp->request_buffer);
+        }
+
+        /*
+         * Check for an underrun condition.
+         *
+         * If there was no error and an underrun condition, then
+         * then return the number of underrun bytes.
+         */
+        if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
+            qdonep->remain_bytes <= scp->request_bufflen) {
+            ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
+            (unsigned) qdonep->remain_bytes);
+            scp->resid = qdonep->remain_bytes;
+        }
+        break;
+
+    case QD_WITH_ERROR:
+        ASC_DBG(2, "asc_isr_callback: QD_WITH_ERROR\n");
+        switch (qdonep->d3.host_stat) {
+        case QHSTA_NO_ERROR:
+            if (qdonep->d3.scsi_stat == SAM_STAT_CHECK_CONDITION) {
+                ASC_DBG(2, "asc_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                    sizeof(scp->sense_buffer));
+                /*
+                 * Note: The 'status_byte()' macro used by target drivers
+                 * defined in scsi.h shifts the status byte returned by
+                 * host drivers right by 1 bit. This is why target drivers
+                 * also use right shifted status byte definitions. For
+                 * instance target drivers use CHECK_CONDITION, defined to
+                 * 0x1, instead of the SCSI defined check condition value
+                 * of 0x2. Host drivers are supposed to return the status
+                 * byte as it is defined by SCSI.
+                 */
+                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                    STATUS_BYTE(qdonep->d3.scsi_stat);
+            } else {
+                scp->result = STATUS_BYTE(qdonep->d3.scsi_stat);
+            }
+            break;
+
+        default:
+            /* QHSTA error occurred */
+            ASC_DBG1(1, "asc_isr_callback: host_stat 0x%x\n",
+                qdonep->d3.host_stat);
+            scp->result = HOST_BYTE(DID_BAD_TARGET);
+            break;
+        }
+        break;
+
+    case QD_ABORTED_BY_HOST:
+        ASC_DBG(1, "asc_isr_callback: QD_ABORTED_BY_HOST\n");
+        scp->result = HOST_BYTE(DID_ABORT) | MSG_BYTE(qdonep->d3.scsi_msg) |
+                STATUS_BYTE(qdonep->d3.scsi_stat);
+        break;
+
+    default:
+        ASC_DBG1(1, "asc_isr_callback: done_stat 0x%x\n", qdonep->d3.done_stat);
+        scp->result = HOST_BYTE(DID_ERROR) | MSG_BYTE(qdonep->d3.scsi_msg) |
+                STATUS_BYTE(qdonep->d3.scsi_stat);
+        break;
+    }
+
+    /*
+     * If the 'init_tidmask' bit isn't already set for the target and the
+     * current request finished normally, then set the bit for the target
+     * to indicate that a device is present.
+     */
+    if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+        qdonep->d3.done_stat == QD_NO_ERROR &&
+        qdonep->d3.host_stat == QHSTA_NO_ERROR) {
+        boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+    }
+
+    /*
+     * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+     * function, add the command to the end of the board's done queue.
+     * The done function for the command will be called from
+     * advansys_interrupt().
+     */
+    asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+    return;
+}
+
+/*
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
+ *
+ * Callback function for the Wide SCSI Adv Library.
+ */
+STATIC void
+adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+{
+    asc_board_t         *boardp;
+    adv_req_t           *reqp;
+    adv_sgblk_t         *sgblkp;
+    struct scsi_cmnd           *scp;
+    struct Scsi_Host    *shp;
+    int                 i;
+    ADV_DCNT            resid_cnt;
+
+
+    ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp 0x%lx, scsiqp 0x%lx\n",
+        (ulong) adv_dvc_varp, (ulong) scsiqp);
+    ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+
+    /*
+     * Get the adv_req_t structure for the command that has been
+     * completed. The adv_req_t structure actually contains the
+     * completed ADV_SCSI_REQ_Q structure.
+     */
+    reqp = (adv_req_t *) ADV_U32_TO_VADDR(scsiqp->srb_ptr);
+    ASC_DBG1(1, "adv_isr_callback: reqp 0x%lx\n", (ulong) reqp);
+    if (reqp == NULL) {
+        ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+        return;
+    }
+
+    /*
+     * Get the struct scsi_cmnd structure and Scsi_Host structure for the
+     * command that has been completed.
+     *
+     * Note: The adv_req_t request structure and adv_sgblk_t structure,
+     * if any, are dropped, because a board structure pointer can not be
+     * determined.
+     */
+    scp = reqp->cmndp;
+    ASC_DBG1(1, "adv_isr_callback: scp 0x%lx\n", (ulong) scp);
+    if (scp == NULL) {
+        ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+        return;
+    }
+    ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+    /*
+     * If the request's host pointer is not valid, display a message
+     * and return.
+     */
+    shp = scp->device->host;
+    for (i = 0; i < asc_board_count; i++) {
+        if (asc_host[i] == shp) {
+            break;
+        }
+    }
+    /*
+     * Note: If the host structure is not found, the adv_req_t request
+     * structure and adv_sgblk_t structure, if any, is dropped.
+     */
+    if (i == asc_board_count) {
+        ASC_PRINT2(
+            "adv_isr_callback: scp 0x%lx has bad host pointer, host 0x%lx\n",
+            (ulong) scp, (ulong) shp);
+        return;
+    }
+
+    ASC_STATS(shp, callback);
+    ASC_DBG1(1, "adv_isr_callback: shp 0x%lx\n", (ulong) shp);
+
+    /*
+     * If the request isn't found on the active queue, it may have been
+     * removed to handle a reset request. Display a message and return.
+     *
+     * Note: Because the structure may still be in use don't attempt
+     * to free the adv_req_t and adv_sgblk_t, if any, structures.
+     */
+    boardp = ASC_BOARDP(shp);
+    ASC_ASSERT(adv_dvc_varp == &boardp->dvc_var.adv_dvc_var);
+    if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+        ASC_PRINT2(
+            "adv_isr_callback: board %d: scp 0x%lx not on active queue\n",
+            boardp->id, (ulong) scp);
+        return;
+    }
+
+    /*
+     * 'done_status' contains the command's ending status.
+     */
+    switch (scsiqp->done_status) {
+    case QD_NO_ERROR:
+        ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
+        scp->result = 0;
+
+        /*
+         * Check for an underrun condition.
+         *
+         * If there was no error and an underrun condition, then
+         * then return the number of underrun bytes.
+         */
+        resid_cnt = le32_to_cpu(scsiqp->data_cnt);
+        if (scp->request_bufflen != 0 && resid_cnt != 0 &&
+            resid_cnt <= scp->request_bufflen) {
+            ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
+                (ulong) resid_cnt);
+            scp->resid = resid_cnt;
+        }
+        break;
+
+    case QD_WITH_ERROR:
+        ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
+        switch (scsiqp->host_status) {
+        case QHSTA_NO_ERROR:
+            if (scsiqp->scsi_status == SAM_STAT_CHECK_CONDITION) {
+                ASC_DBG(2, "adv_isr_callback: SAM_STAT_CHECK_CONDITION\n");
+                ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+                    sizeof(scp->sense_buffer));
+                /*
+                 * Note: The 'status_byte()' macro used by target drivers
+                 * defined in scsi.h shifts the status byte returned by
+                 * host drivers right by 1 bit. This is why target drivers
+                 * also use right shifted status byte definitions. For
+                 * instance target drivers use CHECK_CONDITION, defined to
+                 * 0x1, instead of the SCSI defined check condition value
+                 * of 0x2. Host drivers are supposed to return the status
+                 * byte as it is defined by SCSI.
+                 */
+                scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+                    STATUS_BYTE(scsiqp->scsi_status);
+            } else {
+                scp->result = STATUS_BYTE(scsiqp->scsi_status);
+            }
+            break;
+
+        default:
+            /* Some other QHSTA error occurred. */
+            ASC_DBG1(1, "adv_isr_callback: host_status 0x%x\n",
+                scsiqp->host_status);
+            scp->result = HOST_BYTE(DID_BAD_TARGET);
+            break;
+        }
+        break;
+
+    case QD_ABORTED_BY_HOST:
+        ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
+        scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+        break;
+
+    default:
+        ASC_DBG1(1, "adv_isr_callback: done_status 0x%x\n", scsiqp->done_status);
+        scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+        break;
+    }
+
+    /*
+     * If the 'init_tidmask' bit isn't already set for the target and the
+     * current request finished normally, then set the bit for the target
+     * to indicate that a device is present.
+     */
+    if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->device->id)) == 0 &&
+        scsiqp->done_status == QD_NO_ERROR &&
+        scsiqp->host_status == QHSTA_NO_ERROR) {
+        boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->device->id);
+    }
+
+    /*
+     * Because interrupts may be enabled by the 'struct scsi_cmnd' done
+     * function, add the command to the end of the board's done queue.
+     * The done function for the command will be called from
+     * advansys_interrupt().
+     */
+    asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+    /*
+     * Free all 'adv_sgblk_t' structures allocated for the request.
+     */
+    while ((sgblkp = reqp->sgblkp) != NULL)
+    {
+        /* Remove 'sgblkp' from the request list. */
+        reqp->sgblkp = sgblkp->next_sgblkp;
+
+        /* Add 'sgblkp' to the board free list. */
+        sgblkp->next_sgblkp = boardp->adv_sgblkp;
+        boardp->adv_sgblkp = sgblkp;
+    }
+
+    /*
+     * Free the adv_req_t structure used with the command by adding
+     * it back to the board free list.
+     */
+    reqp->next_reqp = boardp->adv_reqp;
+    boardp->adv_reqp = reqp;
+
+    ASC_DBG(1, "adv_isr_callback: done\n");
+
+    return;
+}
+
+/*
+ * adv_async_callback() - Adv Library asynchronous event callback function.
+ */
+STATIC void
+adv_async_callback(ADV_DVC_VAR *adv_dvc_varp, uchar code)
+{
+    switch (code)
+    {
+    case ADV_ASYNC_SCSI_BUS_RESET_DET:
+        /*
+         * The firmware detected a SCSI Bus reset.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_SCSI_BUS_RESET_DET\n");
+        break;
+
+    case ADV_ASYNC_RDMA_FAILURE:
+        /*
+         * Handle RDMA failure by resetting the SCSI Bus and
+         * possibly the chip if it is unresponsive. Log the error
+         * with a unique code.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_ASYNC_RDMA_FAILURE\n");
+        AdvResetChipAndSB(adv_dvc_varp);
+        break;
+
+    case ADV_HOST_SCSI_BUS_RESET:
+        /*
+         * Host generated SCSI bus reset occurred.
+         */
+        ASC_DBG(0, "adv_async_callback: ADV_HOST_SCSI_BUS_RESET\n");
+        break;
+
+    default:
+        ASC_DBG1(0, "DvcAsyncCallBack: unknown code 0x%x\n", code);
+        break;
+    }
+}
+
+/*
+ * Add a 'REQP' to the end of specified queue. Set 'tidmask'
+ * to indicate a command is queued for the device.
+ *
+ * 'flag' may be either ASC_FRONT or ASC_BACK.
+ *
+ * 'REQPNEXT(reqp)' returns reqp's next pointer.
+ */
+STATIC void
+asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
+{
+    int        tid;
+
+    ASC_DBG3(3, "asc_enqueue: ascq 0x%lx, reqp 0x%lx, flag %d\n",
+        (ulong) ascq, (ulong) reqp, flag);
+    ASC_ASSERT(reqp != NULL);
+    ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
+    tid = REQPTID(reqp);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+    if (flag == ASC_FRONT) {
+        reqp->host_scribble = (unsigned char *)ascq->q_first[tid];
+        ascq->q_first[tid] = reqp;
+        /* If the queue was empty, set the last pointer. */
+        if (ascq->q_last[tid] == NULL) {
+            ascq->q_last[tid] = reqp;
+        }
+    } else { /* ASC_BACK */
+        if (ascq->q_last[tid] != NULL) {
+            ascq->q_last[tid]->host_scribble = (unsigned char *)reqp;
+        }
+        ascq->q_last[tid] = reqp;
+        reqp->host_scribble = NULL;
+        /* If the queue was empty, set the first pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_first[tid] = reqp;
+        }
+    }
+    /* The queue has at least one entry, set its bit. */
+    ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
+#ifdef ADVANSYS_STATS
+    /* Maintain request queue statistics. */
+    ascq->q_tot_cnt[tid]++;
+    ascq->q_cur_cnt[tid]++;
+    if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
+        ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
+        ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
+            tid, ascq->q_max_cnt[tid]);
+    }
+    REQPTIME(reqp) = REQTIMESTAMP();
+#endif /* ADVANSYS_STATS */
+    ASC_DBG1(3, "asc_enqueue: reqp 0x%lx\n", (ulong) reqp);
+    return;
+}
+
+/*
+ * Return first queued 'REQP' on the specified queue for
+ * the specified target device. Clear the 'tidmask' bit for
+ * the device if no more commands are left queued for it.
+ *
+ * 'REQPNEXT(reqp)' returns reqp's next pointer.
+ */
+STATIC REQP
+asc_dequeue(asc_queue_t *ascq, int tid)
+{
+    REQP    reqp;
+
+    ASC_DBG2(3, "asc_dequeue: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+    if ((reqp = ascq->q_first[tid]) != NULL) {
+        ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
+        ascq->q_first[tid] = REQPNEXT(reqp);
+        /* If the queue is empty, clear its bit and the last pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+            ASC_ASSERT(ascq->q_last[tid] == reqp);
+            ascq->q_last[tid] = NULL;
+        }
+#ifdef ADVANSYS_STATS
+        /* Maintain request queue statistics. */
+        ascq->q_cur_cnt[tid]--;
+        ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+        REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
+#endif /* ADVANSYS_STATS */
+    }
+    ASC_DBG1(3, "asc_dequeue: reqp 0x%lx\n", (ulong) reqp);
+    return reqp;
+}
+
+/*
+ * Return a pointer to a singly linked list of all the requests queued
+ * for 'tid' on the 'asc_queue_t' pointed to by 'ascq'.
+ *
+ * If 'lastpp' is not NULL, '*lastpp' will be set to point to the
+ * the last request returned in the singly linked list.
+ *
+ * 'tid' should either be a valid target id or if it is ASC_TID_ALL,
+ * then all queued requests are concatenated into one list and
+ * returned.
+ *
+ * Note: If 'lastpp' is used to append a new list to the end of
+ * an old list, only change the old list last pointer if '*lastpp'
+ * (or the function return value) is not NULL, i.e. use a temporary
+ * variable for 'lastpp' and check its value after the function return
+ * before assigning it to the list last pointer.
+ *
+ * Unfortunately collecting queuing time statistics adds overhead to
+ * the function that isn't inherent to the function's algorithm.
+ */
+STATIC REQP
+asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
+{
+    REQP    firstp, lastp;
+    int     i;
+
+    ASC_DBG2(3, "asc_dequeue_list: ascq 0x%lx, tid %d\n", (ulong) ascq, tid);
+    ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
+
+    /*
+     * If 'tid' is not ASC_TID_ALL, return requests only for
+     * the specified 'tid'. If 'tid' is ASC_TID_ALL, return all
+     * requests for all tids.
+     */
+    if (tid != ASC_TID_ALL) {
+        /* Return all requests for the specified 'tid'. */
+        if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
+            /* List is empty; Set first and last return pointers to NULL. */
+            firstp = lastp = NULL;
+        } else {
+            firstp = ascq->q_first[tid];
+            lastp = ascq->q_last[tid];
+            ascq->q_first[tid] = ascq->q_last[tid] = NULL;
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+#ifdef ADVANSYS_STATS
+            {
+                REQP reqp;
+                ascq->q_cur_cnt[tid] = 0;
+                for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+                    REQTIMESTAT("asc_dequeue_list", ascq, reqp, tid);
+                }
+            }
+#endif /* ADVANSYS_STATS */
+        }
+    } else {
+        /* Return all requests for all tids. */
+        firstp = lastp = NULL;
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
+                if (firstp == NULL) {
+                    firstp = ascq->q_first[i];
+                    lastp = ascq->q_last[i];
+                } else {
+                    ASC_ASSERT(lastp != NULL);
+                    lastp->host_scribble = (unsigned char *)ascq->q_first[i];
+                    lastp = ascq->q_last[i];
+                }
+                ascq->q_first[i] = ascq->q_last[i] = NULL;
+                ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+#ifdef ADVANSYS_STATS
+                ascq->q_cur_cnt[i] = 0;
+#endif /* ADVANSYS_STATS */
+            }
+        }
+#ifdef ADVANSYS_STATS
+        {
+            REQP reqp;
+            for (reqp = firstp; reqp; reqp = REQPNEXT(reqp)) {
+                REQTIMESTAT("asc_dequeue_list", ascq, reqp, reqp->device->id);
+            }
+        }
+#endif /* ADVANSYS_STATS */
+    }
+    if (lastpp) {
+        *lastpp = lastp;
+    }
+    ASC_DBG1(3, "asc_dequeue_list: firstp 0x%lx\n", (ulong) firstp);
+    return firstp;
+}
+
+/*
+ * Remove the specified 'REQP' from the specified queue for
+ * the specified target device. Clear the 'tidmask' bit for the
+ * device if no more commands are left queued for it.
+ *
+ * 'REQPNEXT(reqp)' returns reqp's the next pointer.
+ *
+ * Return ASC_TRUE if the command was found and removed,
+ * otherwise return ASC_FALSE.
+ */
+STATIC int
+asc_rmqueue(asc_queue_t *ascq, REQP reqp)
+{
+    REQP        currp, prevp;
+    int         tid;
+    int         ret = ASC_FALSE;
+
+    ASC_DBG2(3, "asc_rmqueue: ascq 0x%lx, reqp 0x%lx\n",
+        (ulong) ascq, (ulong) reqp);
+    ASC_ASSERT(reqp != NULL);
+
+    tid = REQPTID(reqp);
+    ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
+
+    /*
+     * Handle the common case of 'reqp' being the first
+     * entry on the queue.
+     */
+    if (reqp == ascq->q_first[tid]) {
+        ret = ASC_TRUE;
+        ascq->q_first[tid] = REQPNEXT(reqp);
+        /* If the queue is now empty, clear its bit and the last pointer. */
+        if (ascq->q_first[tid] == NULL) {
+            ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
+            ASC_ASSERT(ascq->q_last[tid] == reqp);
+            ascq->q_last[tid] = NULL;
+        }
+    } else if (ascq->q_first[tid] != NULL) {
+        ASC_ASSERT(ascq->q_last[tid] != NULL);
+        /*
+         * Because the case of 'reqp' being the first entry has been
+         * handled above and it is known the queue is not empty, if
+         * 'reqp' is found on the queue it is guaranteed the queue will
+         * not become empty and that 'q_first[tid]' will not be changed.
+         *
+         * Set 'prevp' to the first entry, 'currp' to the second entry,
+         * and search for 'reqp'.
+         */
+        for (prevp = ascq->q_first[tid], currp = REQPNEXT(prevp);
+             currp; prevp = currp, currp = REQPNEXT(currp)) {
+            if (currp == reqp) {
+                ret = ASC_TRUE;
+                prevp->host_scribble = (unsigned char *)REQPNEXT(currp);
+                reqp->host_scribble = NULL;
+                if (ascq->q_last[tid] == reqp) {
+                    ascq->q_last[tid] = prevp;
+                }
+                break;
+            }
+        }
+    }
+#ifdef ADVANSYS_STATS
+    /* Maintain request queue statistics. */
+    if (ret == ASC_TRUE) {
+        ascq->q_cur_cnt[tid]--;
+        REQTIMESTAT("asc_rmqueue", ascq, reqp, tid);
+    }
+    ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
+#endif /* ADVANSYS_STATS */
+    ASC_DBG2(3, "asc_rmqueue: reqp 0x%lx, ret %d\n", (ulong) reqp, ret);
+    return ret;
+}
+
+/*
+ * Execute as many queued requests as possible for the specified queue.
+ *
+ * Calls asc_execute_scsi_cmnd() to execute a REQP/struct scsi_cmnd.
+ */
+STATIC void
+asc_execute_queue(asc_queue_t *ascq)
+{
+    ADV_SCSI_BIT_ID_TYPE    scan_tidmask;
+    REQP                    reqp;
+    int                     i;
+
+    ASC_DBG1(1, "asc_execute_queue: ascq 0x%lx\n", (ulong) ascq);
+    /*
+     * Execute queued commands for devices attached to
+     * the current board in round-robin fashion.
+     */
+    scan_tidmask = ascq->q_tidmask;
+    do {
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
+                if ((reqp = asc_dequeue(ascq, i)) == NULL) {
+                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+                } else if (asc_execute_scsi_cmnd((struct scsi_cmnd *) reqp)
+                            == ASC_BUSY) {
+                    scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
+                    /*
+                     * The request returned ASC_BUSY. Enqueue at the front of
+                     * target's waiting list to maintain correct ordering.
+                     */
+                    asc_enqueue(ascq, reqp, ASC_FRONT);
+                }
+            }
+        }
+    } while (scan_tidmask);
+    return;
+}
+
+#ifdef CONFIG_PROC_FS
+/*
+ * asc_prt_board_devices()
+ *
+ * Print driver information for devices attached to the board.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t        *boardp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    int                chip_scsi_id;
+    int                i;
+
+    boardp = ASC_BOARDP(shp);
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no);
+    ASC_PRT_NEXT();
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+    len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+            len = asc_prt_line(cp, leftlen, " %X,", i);
+            ASC_PRT_NEXT();
+        }
+    }
+    len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
+    ASC_PRT_NEXT();
+
+    return totlen;
+}
+
+/*
+ * Display Wide Board BIOS Information.
+ */
+STATIC int
+asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t        *boardp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    ushort             major, minor, letter;
+
+    boardp = ASC_BOARDP(shp);
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+    ASC_PRT_NEXT();
+
+    /*
+     * If the BIOS saved a valid signature, then fill in
+     * the BIOS code segment base address.
+     */
+    if (boardp->bios_signature != 0x55AA) {
+        len = asc_prt_line(cp, leftlen, "Disabled or Pre-3.1\n");
+        ASC_PRT_NEXT();
+        len = asc_prt_line(cp, leftlen,
+"BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
+        ASC_PRT_NEXT();
+        len = asc_prt_line(cp, leftlen,
+"can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+        ASC_PRT_NEXT();
+    } else {
+        major = (boardp->bios_version >> 12) & 0xF;
+        minor = (boardp->bios_version >> 8) & 0xF;
+        letter = (boardp->bios_version & 0xFF);
+
+        len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+            major, minor, letter >= 26 ? '?' : letter + 'A');
+        ASC_PRT_NEXT();
+
+        /*
+         * Current available ROM BIOS release is 3.1I for UW
+         * and 3.2I for U2W. This code doesn't differentiate
+         * UW and U2W boards.
+         */
+        if (major < 3 || (major <= 3 && minor < 1) ||
+            (major <= 3 && minor <= 1 && letter < ('I'- 'A'))) {
+            len = asc_prt_line(cp, leftlen,
+"Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
+            ASC_PRT_NEXT();
+            len = asc_prt_line(cp, leftlen,
+"ftp://ftp.connectcom.net/pub\n");
+            ASC_PRT_NEXT();
+        }
+    }
+
+    return totlen;
+}
+
+/*
+ * Add serial number to information bar if signature AAh
+ * is found in at bit 15-9 (7 bits) of word 1.
+ *
+ * Serial Number consists fo 12 alpha-numeric digits.
+ *
+ *       1 - Product type (A,B,C,D..)  Word0: 15-13 (3 bits)
+ *       2 - MFG Location (A,B,C,D..)  Word0: 12-10 (3 bits)
+ *     3-4 - Product ID (0-99)         Word0: 9-0 (10 bits)
+ *       5 - Product revision (A-J)    Word0:  "         "
+ *
+ *           Signature                 Word1: 15-9 (7 bits)
+ *       6 - Year (0-9)                Word1: 8-6 (3 bits) & Word2: 15 (1 bit)
+ *     7-8 - Week of the year (1-52)   Word1: 5-0 (6 bits)
+ *
+ *    9-12 - Serial Number (A001-Z999) Word2: 14-0 (15 bits)
+ *
+ * Note 1: Only production cards will have a serial number.
+ *
+ * Note 2: Signature is most significant 7 bits (0xFE).
+ *
+ * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
+ */
+STATIC int
+asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+{
+    ushort      w, num;
+
+    if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
+        return ASC_FALSE;
+    } else {
+        /*
+         * First word - 6 digits.
+         */
+        w = serialnum[0];
+
+        /* Product type - 1st digit. */
+        if ((*cp = 'A' + ((w & 0xE000) >> 13)) == 'H') {
+            /* Product type is P=Prototype */
+            *cp += 0x8;
+        }
+        cp++;
+
+        /* Manufacturing location - 2nd digit. */
+        *cp++ = 'A' + ((w & 0x1C00) >> 10);
+
+        /* Product ID - 3rd, 4th digits. */
+        num = w & 0x3FF;
+        *cp++ = '0' + (num / 100);
+        num %= 100;
+        *cp++ = '0' + (num / 10);
+
+        /* Product revision - 5th digit. */
+        *cp++ = 'A' + (num % 10);
+
+        /*
+         * Second word
+         */
+        w = serialnum[1];
+
+        /*
+         * Year - 6th digit.
+         *
+         * If bit 15 of third word is set, then the
+         * last digit of the year is greater than 7.
+         */
+        if (serialnum[2] & 0x8000) {
+            *cp++ = '8' + ((w & 0x1C0) >> 6);
+        } else {
+            *cp++ = '0' + ((w & 0x1C0) >> 6);
+        }
+
+        /* Week of year - 7th, 8th digits. */
+        num = w & 0x003F;
+        *cp++ = '0' + num / 10;
+        num %= 10;
+        *cp++ = '0' + num;
+
+        /*
+         * Third word
+         */
+        w = serialnum[2] & 0x7FFF;
+
+        /* Serial number - 9th digit. */
+        *cp++ = 'A' + (w / 1000);
+
+        /* 10th, 11th, 12th digits. */
+        num = w % 1000;
+        *cp++ = '0' + num / 100;
+        num %= 100;
+        *cp++ = '0' + num / 10;
+        num %= 10;
+        *cp++ = '0' + num;
+
+        *cp = '\0';     /* Null Terminate the string. */
+        return ASC_TRUE;
+    }
+}
+
+/*
+ * asc_prt_asc_board_eeprom()
+ *
+ * Print board EEPROM configuration.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t        *boardp;
+    ASC_DVC_VAR        *asc_dvc_varp;
+    int                leftlen;
+    int                totlen;
+    int                len;
+    ASCEEP_CONFIG      *ep;
+    int                i;
+#ifdef CONFIG_ISA
+    int                isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+#endif /* CONFIG_ISA */
+    uchar              serialstr[13];
+
+    boardp = ASC_BOARDP(shp);
+    asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+    ep = &boardp->eep_config.asc_eep;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
+    ASC_PRT_NEXT();
+
+    if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
+        ASC_TRUE) {
+        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+        ASC_PRT_NEXT();
+    } else {
+        if (ep->adapter_info[5] == 0xBB) {
+            len = asc_prt_line(cp, leftlen,
+                " Default Settings Used for EEPROM-less Adapter.\n");
+            ASC_PRT_NEXT();
+        } else {
+            len = asc_prt_line(cp, leftlen,
+                " Serial Number Signature Not Present.\n");
+            ASC_PRT_NEXT();
+        }
+    }
+
+    len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+        ASC_EEP_GET_CHIP_ID(ep), ep->max_total_qng, ep->max_tag_qng);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" cntl 0x%x, no_scam 0x%x\n",
+        ep->cntl, ep->no_scam);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Target ID:           ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %d", i);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Disconnects:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Command Queuing:     ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Start Motor:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+#ifdef CONFIG_ISA
+    if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+        len = asc_prt_line(cp, leftlen,
+" Host ISA DMA speed:   %d MB/S\n",
+            isa_dma_speed[ASC_EEP_GET_DMA_SPD(ep)]);
+        ASC_PRT_NEXT();
+    }
+#endif /* CONFIG_ISA */
+
+     return totlen;
+}
+
+/*
+ * asc_prt_adv_board_eeprom()
+ *
+ * Print board EEPROM configuration.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t                 *boardp;
+    ADV_DVC_VAR                 *adv_dvc_varp;
+    int                         leftlen;
+    int                         totlen;
+    int                         len;
+    int                         i;
+    char                        *termstr;
+    uchar                       serialstr[13];
+    ADVEEP_3550_CONFIG          *ep_3550 = NULL;
+    ADVEEP_38C0800_CONFIG       *ep_38C0800 = NULL;
+    ADVEEP_38C1600_CONFIG       *ep_38C1600 = NULL;
+    ushort                      word;
+    ushort                      *wordp;
+    ushort                      sdtr_speed = 0;
+
+    boardp = ASC_BOARDP(shp);
+    adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        ep_3550 = &boardp->eep_config.adv_3550_eep;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        ep_38C0800 = &boardp->eep_config.adv_38C0800_eep;
+    } else
+    {
+        ep_38C1600 = &boardp->eep_config.adv_38C1600_eep;
+    }
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        wordp = &ep_3550->serial_number_word1;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        wordp = &ep_38C0800->serial_number_word1;
+    } else
+    {
+        wordp = &ep_38C1600->serial_number_word1;
+    }
+
+    if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE) {
+        len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+        ASC_PRT_NEXT();
+    } else {
+        len = asc_prt_line(cp, leftlen,
+            " Serial Number Signature Not Present.\n");
+        ASC_PRT_NEXT();
+    }
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_3550->adapter_scsi_id, ep_3550->max_host_qng,
+            ep_3550->max_dvc_qng);
+        ASC_PRT_NEXT();
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_38C0800->adapter_scsi_id, ep_38C0800->max_host_qng,
+            ep_38C0800->max_dvc_qng);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+            ep_38C1600->adapter_scsi_id, ep_38C1600->max_host_qng,
+            ep_38C1600->max_dvc_qng);
+        ASC_PRT_NEXT();
+    }
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->termination;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        word = ep_38C0800->termination_lvd;
+    } else
+    {
+        word = ep_38C1600->termination_lvd;
+    }
+    switch (word) {
+        case 1:
+            termstr = "Low Off/High Off";
+            break;
+        case 2:
+            termstr = "Low Off/High On";
+            break;
+        case 3:
+            termstr = "Low On/High On";
+            break;
+        default:
+        case 0:
+            termstr = "Automatic";
+            break;
+    }
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: 0x%x\n",
+            ep_3550->termination, termstr, ep_3550->bios_ctrl);
+        ASC_PRT_NEXT();
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: 0x%x\n",
+            ep_38C0800->termination_lvd, termstr, ep_38C0800->bios_ctrl);
+        ASC_PRT_NEXT();
+    } else
+    {
+        len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: 0x%x\n",
+            ep_38C1600->termination_lvd, termstr, ep_38C1600->bios_ctrl);
+        ASC_PRT_NEXT();
+    }
+
+    len = asc_prt_line(cp, leftlen,
+" Target ID:           ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %X", i);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->disc_enable;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        word = ep_38C0800->disc_enable;
+    } else
+    {
+        word = ep_38C1600->disc_enable;
+    }
+    len = asc_prt_line(cp, leftlen,
+" Disconnects:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->tagqng_able;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        word = ep_38C0800->tagqng_able;
+    } else
+    {
+        word = ep_38C1600->tagqng_able;
+    }
+    len = asc_prt_line(cp, leftlen,
+" Command Queuing:     ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->start_motor;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        word = ep_38C0800->start_motor;
+    } else
+    {
+        word = ep_38C1600->start_motor;
+    }
+    len = asc_prt_line(cp, leftlen,
+" Start Motor:         ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Ultra Transfer:      ");
+    ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            len = asc_prt_line(cp, leftlen, " %c",
+                (ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+            ASC_PRT_NEXT();
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
+    {
+        word = ep_3550->wdtr_able;
+    } else if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        word = ep_38C0800->wdtr_able;
+    } else
+    {
+        word = ep_38C1600->wdtr_able;
+    }
+    len = asc_prt_line(cp, leftlen,
+" Wide Transfer:       ");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        len = asc_prt_line(cp, leftlen, " %c",
+            (word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
+        adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer Speed (Mhz):\n  ");
+        ASC_PRT_NEXT();
+        for (i = 0; i <= ADV_MAX_TID; i++) {
+            char *speed_str;
+
+            if (i == 0)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed1;
+            } else if (i == 4)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed2;
+            } else if (i == 8)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed3;
+            } else if (i == 12)
+            {
+                sdtr_speed = adv_dvc_varp->sdtr_speed4;
+            }
+            switch (sdtr_speed & ADV_MAX_TID)
+            {
+                case 0:  speed_str = "Off"; break;
+                case 1:  speed_str = "  5"; break;
+                case 2:  speed_str = " 10"; break;
+                case 3:  speed_str = " 20"; break;
+                case 4:  speed_str = " 40"; break;
+                case 5:  speed_str = " 80"; break;
+                default: speed_str = "Unk"; break;
+            }
+            len = asc_prt_line(cp, leftlen, "%X:%s ", i, speed_str);
+            ASC_PRT_NEXT();
+            if (i == 7)
+            {
+                len = asc_prt_line(cp, leftlen, "\n  ");
+                ASC_PRT_NEXT();
+            }
+            sdtr_speed >>= 4;
+        }
+        len = asc_prt_line(cp, leftlen, "\n");
+        ASC_PRT_NEXT();
+    }
+
+    return totlen;
+}
+
+/*
+ * asc_prt_driver_conf()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t            *boardp;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    int                    chip_scsi_id;
+
+    boardp = ASC_BOARDP(shp);
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Configuration and Information for AdvanSys SCSI Host %d:\n",
+        shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" host_busy %u, last_reset %u, max_id %u, max_lun %u, max_channel %u\n",
+        shp->host_busy, shp->last_reset, shp->max_id, shp->max_lun,
+        shp->max_channel);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" unique_id %d, can_queue %d, this_id %d, sg_tablesize %u, cmd_per_lun %u\n",
+        shp->unique_id, shp->can_queue, shp->this_id, shp->sg_tablesize,
+        shp->cmd_per_lun);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" unchecked_isa_dma %d, use_clustering %d\n",
+        shp->unchecked_isa_dma, shp->use_clustering);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" flags 0x%x, last_reset 0x%x, jiffies 0x%x, asc_n_io_port 0x%x\n",
+        boardp->flags, boardp->last_reset, jiffies, boardp->asc_n_io_port);
+    ASC_PRT_NEXT();
+
+     /* 'shp->n_io_port' may be truncated because it is only one byte. */
+    len = asc_prt_line(cp, leftlen,
+" io_port 0x%x, n_io_port 0x%x\n",
+        shp->io_port, shp->n_io_port);
+    ASC_PRT_NEXT();
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+    return totlen;
+}
+
+/*
+ * asc_prt_asc_board_info()
+ *
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t            *boardp;
+    int                    chip_scsi_id;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    ASC_DVC_VAR            *v;
+    ASC_DVC_CFG            *c;
+    int                    i;
+    int                    renegotiate = 0;
+
+    boardp = ASC_BOARDP(shp);
+    v = &boardp->dvc_var.asc_dvc_var;
+    c = &boardp->dvc_cfg.asc_dvc_cfg;
+    chip_scsi_id = c->chip_scsi_id;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nAsc Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+    shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" chip_version %u, lib_version 0x%x, lib_serial_no %u, mcode_date 0x%x\n",
+        c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" mcode_version 0x%x, err_code %u\n",
+         c->mcode_version, v->err_code);
+    ASC_PRT_NEXT();
+
+    /* Current number of commands waiting for the host. */
+    len = asc_prt_line(cp, leftlen,
+" Total Command Pending: %d\n", v->cur_total_qng);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Command Queuing:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    /* Current number of commands waiting for a device. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Pending:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->cur_dvc_qng[i]);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    /* Current limit on number of commands that can be sent to a device. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Limit:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %X:%u", i, v->max_dvc_qng[i]);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    /* Indicate whether the device has returned queue full status. */
+    len = asc_prt_line(cp, leftlen,
+" Command Queue Full:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
+            len = asc_prt_line(cp, leftlen, " %X:Y-%d",
+                i, boardp->queue_full_cnt[i]);
+        } else {
+            len = asc_prt_line(cp, leftlen, " %X:N", i);
+        }
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        uchar syn_period_ix;
+
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((v->init_sdtr & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, "  %X:", i);
+        ASC_PRT_NEXT();
+
+        if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0)
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            syn_period_ix =
+                (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
+
+            len = asc_prt_line(cp, leftlen,
+                " Transfer Period Factor: %d (%d.%d Mhz),",
+                v->sdtr_period_tbl[syn_period_ix],
+                250 / v->sdtr_period_tbl[syn_period_ix],
+                ASC_TENTHS(250, v->sdtr_period_tbl[syn_period_ix]));
+            ASC_PRT_NEXT();
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET);
+            ASC_PRT_NEXT();
+        }
+
+        if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
+        }
+        ASC_PRT_NEXT();
+    }
+
+    if (renegotiate)
+    {
+        len = asc_prt_line(cp, leftlen,
+            " * = Re-negotiation pending before next command.\n");
+        ASC_PRT_NEXT();
+    }
+
+    return totlen;
+}
+
+/*
+ * asc_prt_adv_board_info()
+ *
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    asc_board_t            *boardp;
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    int                    i;
+    ADV_DVC_VAR            *v;
+    ADV_DVC_CFG            *c;
+    AdvPortAddr            iop_base;
+    ushort                 chip_scsi_id;
+    ushort                 lramword;
+    uchar                  lrambyte;
+    ushort                 tagqng_able;
+    ushort                 sdtr_able, wdtr_able;
+    ushort                 wdtr_done, sdtr_done;
+    ushort                 period = 0;
+    int                    renegotiate = 0;
+
+    boardp = ASC_BOARDP(shp);
+    v = &boardp->dvc_var.adv_dvc_var;
+    c = &boardp->dvc_cfg.adv_dvc_cfg;
+    iop_base = v->iop_base;
+    chip_scsi_id = v->chip_scsi_id;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    len = asc_prt_line(cp, leftlen,
+"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+    shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" iop_base 0x%lx, cable_detect: %X, err_code %u\n",
+         v->iop_base,
+         AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
+         v->err_code);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" chip_version %u, lib_version 0x%x, mcode_date 0x%x, mcode_version 0x%x\n",
+        c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    len = asc_prt_line(cp, leftlen,
+" Queuing Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Queue Limit:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
+
+        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" Command Pending:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
+
+        len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    len = asc_prt_line(cp, leftlen,
+" Wide Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
+    len = asc_prt_line(cp, leftlen,
+" Transfer Bit Width:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+            lramword);
+
+        len = asc_prt_line(cp, leftlen, " %X:%d",
+            i, (lramword & 0x8000) ? 16 : 8);
+        ASC_PRT_NEXT();
+
+        if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
+            (wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*");
+            ASC_PRT_NEXT();
+            renegotiate = 1;
+        }
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    len = asc_prt_line(cp, leftlen,
+" Synchronous Enabled:");
+    ASC_PRT_NEXT();
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, " %X:%c",
+            i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+        ASC_PRT_NEXT();
+    }
+    len = asc_prt_line(cp, leftlen, "\n");
+    ASC_PRT_NEXT();
+
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
+    for (i = 0; i <= ADV_MAX_TID; i++) {
+
+        AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+            lramword);
+        lramword &= ~0x8000;
+
+        if ((chip_scsi_id == i) ||
+            ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0) ||
+            ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0)) {
+            continue;
+        }
+
+        len = asc_prt_line(cp, leftlen, "  %X:", i);
+        ASC_PRT_NEXT();
+
+        if ((lramword & 0x1F) == 0) /* Check for REQ/ACK Offset 0. */
+        {
+            len = asc_prt_line(cp, leftlen, " Asynchronous");
+            ASC_PRT_NEXT();
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, " Transfer Period Factor: ");
+            ASC_PRT_NEXT();
+
+            if ((lramword & 0x1F00) == 0x1100) /* 80 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "9 (80.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else if ((lramword & 0x1F00) == 0x1000) /* 40 Mhz */
+            {
+                len = asc_prt_line(cp, leftlen, "10 (40.0 Mhz),");
+                ASC_PRT_NEXT();
+            } else /* 20 Mhz or below. */
+            {
+                period = (((lramword >> 8) * 25) + 50)/4;
+
+                if (period == 0) /* Should never happen. */
+                {
+                    len = asc_prt_line(cp, leftlen, "%d (? Mhz), ");
+                    ASC_PRT_NEXT();
+                } else
+                {
+                    len = asc_prt_line(cp, leftlen,
+                        "%d (%d.%d Mhz),",
+                        period, 250/period, ASC_TENTHS(250, period));
+                    ASC_PRT_NEXT();
+                }
+            }
+
+            len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d",
+                lramword & 0x1F);
+            ASC_PRT_NEXT();
+        }
+
+        if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
+            len = asc_prt_line(cp, leftlen, "*\n");
+            renegotiate = 1;
+        } else
+        {
+            len = asc_prt_line(cp, leftlen, "\n");
+        }
+        ASC_PRT_NEXT();
+    }
+
+    if (renegotiate)
+    {
+        len = asc_prt_line(cp, leftlen,
+            " * = Re-negotiation pending before next command.\n");
+        ASC_PRT_NEXT();
+    }
+
+    return totlen;
+}
+
+/*
+ * asc_proc_copy()
+ *
+ * Copy proc information to a read buffer taking into account the current
+ * read offset in the file and the remaining space in the read buffer.
+ */
+STATIC int
+asc_proc_copy(off_t advoffset, off_t offset, char *curbuf, int leftlen,
+              char *cp, int cplen)
+{
+    int cnt = 0;
+
+    ASC_DBG3(2, "asc_proc_copy: offset %d, advoffset %d, cplen %d\n",
+            (unsigned) offset, (unsigned) advoffset, cplen);
+    if (offset <= advoffset) {
+        /* Read offset below current offset, copy everything. */
+        cnt = min(cplen, leftlen);
+        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+                (ulong) curbuf, (ulong) cp, cnt);
+        memcpy(curbuf, cp, cnt);
+    } else if (offset < advoffset + cplen) {
+        /* Read offset within current range, partial copy. */
+        cnt = (advoffset + cplen) - offset;
+        cp = (cp + cplen) - cnt;
+        cnt = min(cnt, leftlen);
+        ASC_DBG3(2, "asc_proc_copy: curbuf 0x%lx, cp 0x%lx, cnt %d\n",
+                (ulong) curbuf, (ulong) cp, cnt);
+        memcpy(curbuf, cp, cnt);
+    }
+    return cnt;
+}
+
+/*
+ * asc_prt_line()
+ *
+ * If 'cp' is NULL print to the console, otherwise print to a buffer.
+ *
+ * Return 0 if printing to the console, otherwise return the number of
+ * bytes written to the buffer.
+ *
+ * Note: If any single line is greater than ASC_PRTLINE_SIZE bytes the stack
+ * will be corrupted. 's[]' is defined to be ASC_PRTLINE_SIZE bytes.
+ */
+STATIC int
+asc_prt_line(char *buf, int buflen, char *fmt, ...)
+{
+    va_list        args;
+    int            ret;
+    char           s[ASC_PRTLINE_SIZE];
+
+    va_start(args, fmt);
+    ret = vsprintf(s, fmt, args);
+    ASC_ASSERT(ret < ASC_PRTLINE_SIZE);
+    if (buf == NULL) {
+        (void) printk(s);
+        ret = 0;
+    } else {
+        ret = min(buflen, ret);
+        memcpy(buf, s, ret);
+    }
+    va_end(args);
+    return ret;
+}
+#endif /* CONFIG_PROC_FS */
+
+
+/*
+ * --- Functions Required by the Asc Library
+ */
+
+/*
+ * Delay for 'n' milliseconds. Don't use the 'jiffies'
+ * global variable which is incremented once every 5 ms
+ * from a timer interrupt, because this function may be
+ * called when interrupts are disabled.
+ */
+STATIC void
+DvcSleepMilliSecond(ADV_DCNT n)
+{
+    ASC_DBG1(4, "DvcSleepMilliSecond: %lu\n", (ulong) n);
+    mdelay(n);
+}
+
+/*
+ * Currently and inline noop but leave as a placeholder.
+ * Leave DvcEnterCritical() as a noop placeholder.
+ */
+STATIC inline ulong
+DvcEnterCritical(void)
+{
+    return 0;
+}
+
+/*
+ * Critical sections are all protected by the board spinlock.
+ * Leave DvcLeaveCritical() as a noop placeholder.
+ */
+STATIC inline void
+DvcLeaveCritical(ulong flags)
+{
+    return;
+}
+
+/*
+ * void
+ * DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+ *
+ * Calling/Exit State:
+ *    none
+ *
+ * Description:
+ *     Output an ASC_SCSI_Q structure to the chip
+ */
+STATIC void
+DvcPutScsiQ(PortAddr iop_base, ushort s_addr, uchar *outbuf, int words)
+{
+    int    i;
+
+    ASC_DBG_PRT_HEX(2, "DvcPutScsiQ", outbuf, 2 * words);
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < 2 * words; i += 2) {
+        if (i == 4 || i == 20) {
+            continue;
+        }
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) outbuf[i + 1] << 8) | outbuf[i]);
+    }
+}
+
+/*
+ * void
+ * DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+ *
+ * Calling/Exit State:
+ *    none
+ *
+ * Description:
+ *     Input an ASC_QDONE_INFO structure from the chip
+ */
+STATIC void
+DvcGetQinfo(PortAddr iop_base, ushort s_addr, uchar *inbuf, int words)
+{
+    int    i;
+    ushort word;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < 2 * words; i += 2) {
+        if (i == 10) {
+            continue;
+        }
+        word = inpw(iop_base + IOP_RAM_DATA);
+        inbuf[i] = word & 0xff;
+        inbuf[i + 1] = (word >> 8) & 0xff;
+    }
+    ASC_DBG_PRT_HEX(2, "DvcGetQinfo", inbuf, 2 * words);
+}
+
+/*
+ * Read a PCI configuration byte.
+ */
+STATIC uchar __init
+DvcReadPCIConfigByte(
+        ASC_DVC_VAR *asc_dvc,
+        ushort offset)
+{
+#ifdef CONFIG_PCI
+    uchar byte_data;
+    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+    return byte_data;
+#else /* !defined(CONFIG_PCI) */
+    return 0;
+#endif /* !defined(CONFIG_PCI) */
+}
+
+/*
+ * Write a PCI configuration byte.
+ */
+STATIC void __init
+DvcWritePCIConfigByte(
+        ASC_DVC_VAR *asc_dvc,
+        ushort offset,
+        uchar  byte_data)
+{
+#ifdef CONFIG_PCI
+    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+#endif /* CONFIG_PCI */
+}
+
+/*
+ * Return the BIOS address of the adapter at the specified
+ * I/O port and with the specified bus type.
+ */
+STATIC ushort __init
+AscGetChipBiosAddress(
+        PortAddr iop_base,
+        ushort bus_type)
+{
+    ushort  cfg_lsw;
+    ushort  bios_addr;
+
+    /*
+     * The PCI BIOS is re-located by the motherboard BIOS. Because
+     * of this the driver can not determine where a PCI BIOS is
+     * loaded and executes.
+     */
+    if (bus_type & ASC_IS_PCI)
+    {
+        return(0);
+    }
+
+#ifdef CONFIG_ISA
+    if((bus_type & ASC_IS_EISA) != 0)
+    {
+        cfg_lsw = AscGetEisaChipCfg(iop_base);
+        cfg_lsw &= 0x000F;
+        bios_addr = (ushort)(ASC_BIOS_MIN_ADDR  +
+                                (cfg_lsw * ASC_BIOS_BANK_SIZE));
+        return(bios_addr);
+    }/* if */
+#endif /* CONFIG_ISA */
+
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+
+    /*
+    *  ISA PnP uses the top bit as the 32K BIOS flag
+    */
+    if (bus_type == ASC_IS_ISAPNP)
+    {
+        cfg_lsw &= 0x7FFF;
+    }/* if */
+
+    bios_addr = (ushort)(((cfg_lsw >> 12) * ASC_BIOS_BANK_SIZE) +
+            ASC_BIOS_MIN_ADDR);
+    return(bios_addr);
+}
+
+
+/*
+ * --- Functions Required by the Adv Library
+ */
+
+/*
+ * DvcGetPhyAddr()
+ *
+ * Return the physical address of 'vaddr' and set '*lenp' to the
+ * number of physically contiguous bytes that follow 'vaddr'.
+ * 'flag' indicates the type of structure whose physical address
+ * is being translated.
+ *
+ * Note: Because Linux currently doesn't page the kernel and all
+ * kernel buffers are physically contiguous, leave '*lenp' unchanged.
+ */
+ADV_PADDR
+DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
+        uchar *vaddr, ADV_SDCNT *lenp, int flag)
+{
+    ADV_PADDR           paddr;
+
+    paddr = virt_to_bus(vaddr);
+
+    ASC_DBG4(4,
+        "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
+        (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), (ulong) paddr);
+
+    return paddr;
+}
+
+/*
+ * Read a PCI configuration byte.
+ */
+STATIC uchar __init
+DvcAdvReadPCIConfigByte(
+        ADV_DVC_VAR *asc_dvc,
+        ushort offset)
+{
+#ifdef CONFIG_PCI
+    uchar byte_data;
+    pci_read_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, &byte_data);
+    return byte_data;
+#else /* CONFIG_PCI */
+    return 0;
+#endif /* CONFIG_PCI */
+}
+
+/*
+ * Write a PCI configuration byte.
+ */
+STATIC void __init
+DvcAdvWritePCIConfigByte(
+        ADV_DVC_VAR *asc_dvc,
+        ushort offset,
+        uchar  byte_data)
+{
+#ifdef CONFIG_PCI
+    pci_write_config_byte(to_pci_dev(asc_dvc->cfg->dev), offset, byte_data);
+#else /* CONFIG_PCI */
+    return;
+#endif /* CONFIG_PCI */
+}
+
+/*
+ * --- Tracing and Debugging Functions
+ */
+
+#ifdef ADVANSYS_STATS
+#ifdef CONFIG_PROC_FS
+/*
+ * asc_prt_board_stats()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
+{
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    struct asc_stats       *s;
+    asc_board_t            *boardp;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    boardp = ASC_BOARDP(shp);
+    s = &boardp->asc_stats;
+
+    len = asc_prt_line(cp, leftlen,
+"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" queuecommand %lu, reset %lu, biosparam %lu, interrupt %lu\n",
+        s->queuecommand, s->reset, s->biosparam, s->interrupt);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" callback %lu, done %lu, build_error %lu, build_noreq %lu, build_nosg %lu\n",
+        s->callback, s->done, s->build_error, s->adv_build_noreq,
+        s->adv_build_nosg);
+    ASC_PRT_NEXT();
+
+    len = asc_prt_line(cp, leftlen,
+" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+        s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
+    ASC_PRT_NEXT();
+
+    /*
+     * Display data transfer statistics.
+     */
+    if (s->cont_cnt > 0) {
+        len = asc_prt_line(cp, leftlen, " cont_cnt %lu, ", s->cont_cnt);
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "cont_xfer %lu.%01lu kb ",
+                    s->cont_xfer/2,
+                    ASC_TENTHS(s->cont_xfer, 2));
+        ASC_PRT_NEXT();
+
+        /* Contiguous transfer average size */
+        len = asc_prt_line(cp, leftlen, "avg_xfer %lu.%01lu kb\n",
+                    (s->cont_xfer/2)/s->cont_cnt,
+                    ASC_TENTHS((s->cont_xfer/2), s->cont_cnt));
+        ASC_PRT_NEXT();
+    }
+
+    if (s->sg_cnt > 0) {
+
+        len = asc_prt_line(cp, leftlen, " sg_cnt %lu, sg_elem %lu, ",
+                    s->sg_cnt, s->sg_elem);
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "sg_xfer %lu.%01lu kb\n",
+                    s->sg_xfer/2,
+                    ASC_TENTHS(s->sg_xfer, 2));
+        ASC_PRT_NEXT();
+
+        /* Scatter gather transfer statistics */
+        len = asc_prt_line(cp, leftlen, " avg_num_elem %lu.%01lu, ",
+                    s->sg_elem/s->sg_cnt,
+                    ASC_TENTHS(s->sg_elem, s->sg_cnt));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "avg_elem_size %lu.%01lu kb, ",
+                    (s->sg_xfer/2)/s->sg_elem,
+                    ASC_TENTHS((s->sg_xfer/2), s->sg_elem));
+        ASC_PRT_NEXT();
+
+        len = asc_prt_line(cp, leftlen, "avg_xfer_size %lu.%01lu kb\n",
+                    (s->sg_xfer/2)/s->sg_cnt,
+                    ASC_TENTHS((s->sg_xfer/2), s->sg_cnt));
+        ASC_PRT_NEXT();
+    }
+
+    /*
+     * Display request queuing statistics.
+     */
+    len = asc_prt_line(cp, leftlen,
+" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
+    ASC_PRT_NEXT();
+
+
+     return totlen;
+}
+
+/*
+ * asc_prt_target_stats()
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * This is separated from asc_prt_board_stats because a full set
+ * of targets will overflow ASC_PRTBUF_SIZE.
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_target_stats(struct Scsi_Host *shp, int tgt_id, char *cp, int cplen)
+{
+    int                    leftlen;
+    int                    totlen;
+    int                    len;
+    struct asc_stats       *s;
+    ushort                 chip_scsi_id;
+    asc_board_t            *boardp;
+    asc_queue_t            *active;
+    asc_queue_t            *waiting;
+
+    leftlen = cplen;
+    totlen = len = 0;
+
+    boardp = ASC_BOARDP(shp);
+    s = &boardp->asc_stats;
+
+    active = &ASC_BOARDP(shp)->active;
+    waiting = &ASC_BOARDP(shp)->waiting;
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+    } else {
+        chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+    }
+
+    if ((chip_scsi_id == tgt_id) ||
+        ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(tgt_id)) == 0)) {
+        return 0;
+    }
+
+    do {
+        if (active->q_tot_cnt[tgt_id] > 0 || waiting->q_tot_cnt[tgt_id] > 0) {
+            len = asc_prt_line(cp, leftlen, " target %d\n", tgt_id);
+            ASC_PRT_NEXT();
+
+            len = asc_prt_line(cp, leftlen,
+"   active: cnt [cur %d, max %d, tot %u], time [min %d, max %d, avg %lu.%01lu]\n",
+                active->q_cur_cnt[tgt_id], active->q_max_cnt[tgt_id],
+                active->q_tot_cnt[tgt_id],
+                active->q_min_tim[tgt_id], active->q_max_tim[tgt_id],
+                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
+                (active->q_tot_tim[tgt_id]/active->q_tot_cnt[tgt_id]),
+                (active->q_tot_cnt[tgt_id] == 0) ? 0 :
+                ASC_TENTHS(active->q_tot_tim[tgt_id],
+                active->q_tot_cnt[tgt_id]));
+             ASC_PRT_NEXT();
+
+             len = asc_prt_line(cp, leftlen,
+"   waiting: cnt [cur %d, max %d, tot %u], time [min %u, max %u, avg %lu.%01lu]\n",
+                waiting->q_cur_cnt[tgt_id], waiting->q_max_cnt[tgt_id],
+                waiting->q_tot_cnt[tgt_id],
+                waiting->q_min_tim[tgt_id], waiting->q_max_tim[tgt_id],
+                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
+                (waiting->q_tot_tim[tgt_id]/waiting->q_tot_cnt[tgt_id]),
+                (waiting->q_tot_cnt[tgt_id] == 0) ? 0 :
+                ASC_TENTHS(waiting->q_tot_tim[tgt_id],
+                waiting->q_tot_cnt[tgt_id]));
+             ASC_PRT_NEXT();
+        }
+    } while (0);
+
+     return totlen;
+}
+#endif /* CONFIG_PROC_FS */
+#endif /* ADVANSYS_STATS */
+
+#ifdef ADVANSYS_DEBUG
+/*
+ * asc_prt_scsi_host()
+ */
+STATIC void
+asc_prt_scsi_host(struct Scsi_Host *s)
+{
+    asc_board_t         *boardp;
+
+    boardp = ASC_BOARDP(s);
+
+    printk("Scsi_Host at addr 0x%lx\n", (ulong) s);
+    printk(
+" host_busy %u, host_no %d, last_reset %d,\n",
+        s->host_busy, s->host_no,
+        (unsigned) s->last_reset);
+
+    printk(
+" base 0x%lx, io_port 0x%lx, n_io_port %u, irq 0x%x,\n",
+        (ulong) s->base, (ulong) s->io_port, s->n_io_port, s->irq);
+
+    printk(
+" dma_channel %d, this_id %d, can_queue %d,\n",
+        s->dma_channel, s->this_id, s->can_queue);
+
+    printk(
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
+        s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+
+    if (ASC_NARROW_BOARD(boardp)) {
+        asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
+        asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
+    } else {
+        asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
+        asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+    }
+}
+
+/*
+ * asc_prt_scsi_cmnd()
+ */
+STATIC void
+asc_prt_scsi_cmnd(struct scsi_cmnd *s)
+{
+    printk("struct scsi_cmnd at addr 0x%lx\n", (ulong) s);
+
+    printk(
+" host 0x%lx, device 0x%lx, target %u, lun %u, channel %u,\n",
+        (ulong) s->device->host, (ulong) s->device, s->device->id, s->device->lun,
+        s->device->channel);
+
+    asc_prt_hex(" CDB", s->cmnd, s->cmd_len);
+
+    printk (
+"sc_data_direction %u, resid %d\n",
+        s->sc_data_direction, s->resid);
+
+    printk(
+" use_sg %u, sglist_len %u, abort_reason 0x%x\n",
+        s->use_sg, s->sglist_len, s->abort_reason);
+
+    printk(
+" serial_number 0x%x, serial_number_at_timeout 0x%x, retries %d, allowed %d\n",
+        (unsigned) s->serial_number, (unsigned) s->serial_number_at_timeout,
+         s->retries, s->allowed);
+
+    printk(
+" timeout_per_command %d, timeout_total %d, timeout %d\n",
+        s->timeout_per_command, s->timeout_total, s->timeout);
+
+    printk(" internal_timeout %u\n", s->internal_timeout);
+
+    printk(
+" scsi_done 0x%lx, done 0x%lx, host_scribble 0x%lx, result 0x%x\n",
+        (ulong) s->scsi_done, (ulong) s->done,
+        (ulong) s->host_scribble, s->result);
+
+    printk(
+" tag %u, pid %u\n",
+        (unsigned) s->tag, (unsigned) s->pid);
+}
+
+/*
+ * asc_prt_asc_dvc_var()
+ */
+STATIC void
+asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
+{
+    printk("ASC_DVC_VAR at addr 0x%lx\n", (ulong) h);
+
+    printk(
+" iop_base 0x%x, err_code 0x%x, dvc_cntl 0x%x, bug_fix_cntl %d,\n",
+        h->iop_base, h->err_code, h->dvc_cntl, h->bug_fix_cntl);
+
+    printk(
+" bus_type %d, isr_callback 0x%lx, exe_callback 0x%lx, init_sdtr 0x%x,\n",
+        h->bus_type, (ulong) h->isr_callback, (ulong) h->exe_callback,
+        (unsigned) h->init_sdtr);
+
+    printk(
+" sdtr_done 0x%x, use_tagged_qng 0x%x, unit_not_ready 0x%x, chip_no 0x%x,\n",
+        (unsigned) h->sdtr_done, (unsigned) h->use_tagged_qng,
+        (unsigned) h->unit_not_ready, (unsigned) h->chip_no);
+
+    printk(
+" queue_full_or_busy 0x%x, start_motor 0x%x, scsi_reset_wait %u,\n",
+        (unsigned) h->queue_full_or_busy, (unsigned) h->start_motor,
+        (unsigned) h->scsi_reset_wait);
+
+    printk(
+" is_in_int %u, max_total_qng %u, cur_total_qng %u, in_critical_cnt %u,\n",
+        (unsigned) h->is_in_int, (unsigned) h->max_total_qng,
+        (unsigned) h->cur_total_qng, (unsigned) h->in_critical_cnt);
+
+    printk(
+" last_q_shortage %u, init_state 0x%x, no_scam 0x%x, pci_fix_asyn_xfer 0x%x,\n",
+        (unsigned) h->last_q_shortage, (unsigned) h->init_state,
+        (unsigned) h->no_scam, (unsigned) h->pci_fix_asyn_xfer);
+
+    printk(
+" cfg 0x%lx, irq_no 0x%x\n",
+        (ulong) h->cfg, (unsigned) h->irq_no);
+}
+
+/*
+ * asc_prt_asc_dvc_cfg()
+ */
+STATIC void
+asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
+{
+    printk("ASC_DVC_CFG at addr 0x%lx\n", (ulong) h);
+
+    printk(
+" can_tagged_qng 0x%x, cmd_qng_enabled 0x%x,\n",
+            h->can_tagged_qng, h->cmd_qng_enabled);
+    printk(
+" disc_enable 0x%x, sdtr_enable 0x%x,\n",
+            h->disc_enable, h->sdtr_enable);
+
+    printk(
+" chip_scsi_id %d, isa_dma_speed %d, isa_dma_channel %d, chip_version %d,\n",
+             h->chip_scsi_id, h->isa_dma_speed, h->isa_dma_channel,
+             h->chip_version);
+
+    printk(
+" pci_device_id %d, lib_serial_no %u, lib_version %u, mcode_date 0x%x,\n",
+	   to_pci_dev(h->dev)->device, h->lib_serial_no, h->lib_version,
+	   h->mcode_date);
+
+    printk(
+" mcode_version %d, overrun_buf 0x%lx\n",
+            h->mcode_version, (ulong) h->overrun_buf);
+}
+
+/*
+ * asc_prt_asc_scsi_q()
+ */
+STATIC void
+asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
+{
+    ASC_SG_HEAD    *sgp;
+    int i;
+
+    printk("ASC_SCSI_Q at addr 0x%lx\n", (ulong) q);
+
+    printk(
+" target_ix 0x%x, target_lun %u, srb_ptr 0x%lx, tag_code 0x%x,\n",
+            q->q2.target_ix, q->q1.target_lun,
+            (ulong) q->q2.srb_ptr, q->q2.tag_code);
+
+    printk(
+" data_addr 0x%lx, data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+            (ulong) le32_to_cpu(q->q1.data_addr),
+            (ulong) le32_to_cpu(q->q1.data_cnt),
+            (ulong) le32_to_cpu(q->q1.sense_addr), q->q1.sense_len);
+
+    printk(
+" cdbptr 0x%lx, cdb_len %u, sg_head 0x%lx, sg_queue_cnt %u\n",
+            (ulong) q->cdbptr, q->q2.cdb_len,
+            (ulong) q->sg_head, q->q1.sg_queue_cnt);
+
+    if (q->sg_head) {
+        sgp = q->sg_head;
+        printk("ASC_SG_HEAD at addr 0x%lx\n", (ulong) sgp);
+        printk(" entry_cnt %u, queue_cnt %u\n", sgp->entry_cnt, sgp->queue_cnt);
+        for (i = 0; i < sgp->entry_cnt; i++) {
+            printk(" [%u]: addr 0x%lx, bytes %lu\n",
+                i, (ulong) le32_to_cpu(sgp->sg_list[i].addr),
+                (ulong) le32_to_cpu(sgp->sg_list[i].bytes));
+        }
+
+    }
+}
+
+/*
+ * asc_prt_asc_qdone_info()
+ */
+STATIC void
+asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
+{
+    printk("ASC_QDONE_INFO at addr 0x%lx\n", (ulong) q);
+    printk(
+" srb_ptr 0x%lx, target_ix %u, cdb_len %u, tag_code %u,\n",
+            (ulong) q->d2.srb_ptr, q->d2.target_ix, q->d2.cdb_len,
+            q->d2.tag_code);
+    printk(
+" done_stat 0x%x, host_stat 0x%x, scsi_stat 0x%x, scsi_msg 0x%x\n",
+            q->d3.done_stat, q->d3.host_stat, q->d3.scsi_stat, q->d3.scsi_msg);
+}
+
+/*
+ * asc_prt_adv_dvc_var()
+ *
+ * Display an ADV_DVC_VAR structure.
+ */
+STATIC void
+asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
+{
+    printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
+
+    printk(
+"  iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+        (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
+
+    printk(
+"  isr_callback 0x%lx, sdtr_able 0x%x, wdtr_able 0x%x\n",
+        (ulong) h->isr_callback, (unsigned) h->sdtr_able,
+        (unsigned) h->wdtr_able);
+
+    printk(
+"  start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
+        (unsigned) h->start_motor,
+        (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+
+    printk(
+"  max_host_qng %u, max_dvc_qng %u, carr_freelist 0x%lxn\n",
+        (unsigned) h->max_host_qng, (unsigned) h->max_dvc_qng,
+        (ulong) h->carr_freelist);
+
+    printk(
+"  icq_sp 0x%lx, irq_sp 0x%lx\n",
+        (ulong) h->icq_sp, (ulong) h->irq_sp);
+
+    printk(
+"  no_scam 0x%x, tagqng_able 0x%x\n",
+        (unsigned) h->no_scam, (unsigned) h->tagqng_able);
+
+    printk(
+"  chip_scsi_id 0x%x, cfg 0x%lx\n",
+        (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+}
+
+/*
+ * asc_prt_adv_dvc_cfg()
+ *
+ * Display an ADV_DVC_CFG structure.
+ */
+STATIC void
+asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
+{
+    printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
+
+    printk(
+"  disc_enable 0x%x, termination 0x%x\n",
+        h->disc_enable, h->termination);
+
+    printk(
+"  chip_version 0x%x, mcode_date 0x%x\n",
+        h->chip_version, h->mcode_date);
+
+    printk(
+"  mcode_version 0x%x, pci_device_id 0x%x, lib_version %u\n",
+       h->mcode_version, to_pci_dev(h->dev)->device, h->lib_version);
+
+    printk(
+"  control_flag 0x%x, pci_slot_info 0x%x\n",
+       h->control_flag, h->pci_slot_info);
+}
+
+/*
+ * asc_prt_adv_scsi_req_q()
+ *
+ * Display an ADV_SCSI_REQ_Q structure.
+ */
+STATIC void
+asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
+{
+    int                 sg_blk_cnt;
+    struct asc_sg_block *sg_ptr;
+
+    printk("ADV_SCSI_REQ_Q at addr 0x%lx\n", (ulong) q);
+
+    printk(
+"  target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+            q->target_id, q->target_lun, (ulong) q->srb_ptr, q->a_flag);
+
+    printk("  cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+            q->cntl, (ulong) le32_to_cpu(q->data_addr), (ulong) q->vdata_addr);
+
+    printk(
+"  data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+            (ulong) le32_to_cpu(q->data_cnt),
+            (ulong) le32_to_cpu(q->sense_addr), q->sense_len);
+
+    printk(
+"  cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+            q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+
+    printk(
+"  sg_working_ix 0x%x, target_cmd %u\n",
+            q->sg_working_ix, q->target_cmd);
+
+    printk(
+"  scsiq_rptr 0x%lx, sg_real_addr 0x%lx, sg_list_ptr 0x%lx\n",
+            (ulong) le32_to_cpu(q->scsiq_rptr),
+            (ulong) le32_to_cpu(q->sg_real_addr), (ulong) q->sg_list_ptr);
+
+    /* Display the request's ADV_SG_BLOCK structures. */
+    if (q->sg_list_ptr != NULL)
+    {
+        sg_blk_cnt = 0;
+        while (1) {
+            /*
+             * 'sg_ptr' is a physical address. Convert it to a virtual
+             * address by indexing 'sg_blk_cnt' into the virtual address
+             * array 'sg_list_ptr'.
+             *
+             * XXX - Assumes all SG physical blocks are virtually contiguous.
+             */
+            sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[sg_blk_cnt]);
+            asc_prt_adv_sgblock(sg_blk_cnt, sg_ptr);
+            if (sg_ptr->sg_ptr == 0)
+            {
+                break;
+            }
+            sg_blk_cnt++;
+        }
+    }
+}
+
+/*
+ * asc_prt_adv_sgblock()
+ *
+ * Display an ADV_SG_BLOCK structure.
+ */
+STATIC void
+asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+{
+    int i;
+
+    printk(" ASC_SG_BLOCK at addr 0x%lx (sgblockno %d)\n",
+        (ulong) b, sgblockno);
+    printk("  sg_cnt %u, sg_ptr 0x%lx\n",
+        b->sg_cnt, (ulong) le32_to_cpu(b->sg_ptr));
+    ASC_ASSERT(b->sg_cnt <= NO_OF_SG_PER_BLOCK);
+    if (b->sg_ptr != 0)
+    {
+        ASC_ASSERT(b->sg_cnt == NO_OF_SG_PER_BLOCK);
+    }
+    for (i = 0; i < b->sg_cnt; i++) {
+        printk("  [%u]: sg_addr 0x%lx, sg_count 0x%lx\n",
+            i, (ulong) b->sg_list[i].sg_addr, (ulong) b->sg_list[i].sg_count);
+    }
+}
+
+/*
+ * asc_prt_hex()
+ *
+ * Print hexadecimal output in 4 byte groupings 32 bytes
+ * or 8 double-words per line.
+ */
+STATIC void
+asc_prt_hex(char *f, uchar *s, int l)
+{
+    int            i;
+    int            j;
+    int            k;
+    int            m;
+
+    printk("%s: (%d bytes)\n", f, l);
+
+    for (i = 0; i < l; i += 32) {
+
+        /* Display a maximum of 8 double-words per line. */
+        if ((k = (l - i) / 4) >= 8) {
+            k = 8;
+            m = 0;
+        } else {
+            m = (l - i) % 4;
+        }
+
+        for (j = 0; j < k; j++) {
+            printk(" %2.2X%2.2X%2.2X%2.2X",
+                (unsigned) s[i+(j*4)], (unsigned) s[i+(j*4)+1],
+                (unsigned) s[i+(j*4)+2], (unsigned) s[i+(j*4)+3]);
+        }
+
+        switch (m) {
+        case 0:
+        default:
+            break;
+        case 1:
+            printk(" %2.2X",
+                (unsigned) s[i+(j*4)]);
+            break;
+        case 2:
+            printk(" %2.2X%2.2X",
+                (unsigned) s[i+(j*4)],
+                (unsigned) s[i+(j*4)+1]);
+            break;
+        case 3:
+            printk(" %2.2X%2.2X%2.2X",
+                (unsigned) s[i+(j*4)+1],
+                (unsigned) s[i+(j*4)+2],
+                (unsigned) s[i+(j*4)+3]);
+            break;
+        }
+
+        printk("\n");
+    }
+}
+#endif /* ADVANSYS_DEBUG */
+
+/*
+ * --- Asc Library Functions
+ */
+
+STATIC ushort __init
+AscGetEisaChipCfg(
+                     PortAddr iop_base)
+{
+    PortAddr            eisa_cfg_iop;
+
+    eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+      (PortAddr) (ASC_EISA_CFG_IOP_MASK);
+    return (inpw(eisa_cfg_iop));
+}
+
+STATIC uchar __init
+AscSetChipScsiID(
+                    PortAddr iop_base,
+                    uchar new_host_id
+)
+{
+    ushort              cfg_lsw;
+
+    if (AscGetChipScsiID(iop_base) == new_host_id) {
+        return (new_host_id);
+    }
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    cfg_lsw &= 0xF8FF;
+    cfg_lsw |= (ushort) ((new_host_id & ASC_MAX_TID) << 8);
+    AscSetChipCfgLsw(iop_base, cfg_lsw);
+    return (AscGetChipScsiID(iop_base));
+}
+
+STATIC uchar __init
+AscGetChipScsiCtrl(
+		PortAddr iop_base)
+{
+    uchar               sc;
+
+    AscSetBank(iop_base, 1);
+    sc = inp(iop_base + IOP_REG_SC);
+    AscSetBank(iop_base, 0);
+    return (sc);
+}
+
+STATIC uchar __init
+AscGetChipVersion(
+                     PortAddr iop_base,
+                     ushort bus_type
+)
+{
+    if ((bus_type & ASC_IS_EISA) != 0) {
+        PortAddr            eisa_iop;
+        uchar               revision;
+        eisa_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
+          (PortAddr) ASC_EISA_REV_IOP_MASK;
+        revision = inp(eisa_iop);
+        return ((uchar) ((ASC_CHIP_MIN_VER_EISA - 1) + revision));
+    }
+    return (AscGetChipVerNo(iop_base));
+}
+
+STATIC ushort __init
+AscGetChipBusType(
+                     PortAddr iop_base)
+{
+    ushort              chip_ver;
+
+    chip_ver = AscGetChipVerNo(iop_base);
+    if (
+           (chip_ver >= ASC_CHIP_MIN_VER_VL)
+           && (chip_ver <= ASC_CHIP_MAX_VER_VL)
+) {
+        if (
+               ((iop_base & 0x0C30) == 0x0C30)
+               || ((iop_base & 0x0C50) == 0x0C50)
+) {
+            return (ASC_IS_EISA);
+        }
+        return (ASC_IS_VL);
+    }
+    if ((chip_ver >= ASC_CHIP_MIN_VER_ISA) &&
+        (chip_ver <= ASC_CHIP_MAX_VER_ISA)) {
+        if (chip_ver >= ASC_CHIP_MIN_VER_ISA_PNP) {
+            return (ASC_IS_ISAPNP);
+        }
+        return (ASC_IS_ISA);
+    } else if ((chip_ver >= ASC_CHIP_MIN_VER_PCI) &&
+               (chip_ver <= ASC_CHIP_MAX_VER_PCI)) {
+        return (ASC_IS_PCI);
+    }
+    return (0);
+}
+
+STATIC ASC_DCNT
+AscLoadMicroCode(
+                    PortAddr iop_base,
+                    ushort s_addr,
+                    uchar *mcode_buf,
+                    ushort mcode_size
+)
+{
+    ASC_DCNT            chksum;
+    ushort              mcode_word_size;
+    ushort              mcode_chksum;
+
+    /* Write the microcode buffer starting at LRAM address 0. */
+    mcode_word_size = (ushort) (mcode_size >> 1);
+    AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
+    AscMemWordCopyPtrToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
+
+    chksum = AscMemSumLramWord(iop_base, s_addr, mcode_word_size);
+    ASC_DBG1(1, "AscLoadMicroCode: chksum 0x%lx\n", (ulong) chksum);
+    mcode_chksum = (ushort) AscMemSumLramWord(iop_base,
+          (ushort) ASC_CODE_SEC_BEG,
+          (ushort) ((mcode_size - s_addr - (ushort) ASC_CODE_SEC_BEG) / 2));
+    ASC_DBG1(1, "AscLoadMicroCode: mcode_chksum 0x%lx\n",
+        (ulong) mcode_chksum);
+    AscWriteLramWord(iop_base, ASCV_MCODE_CHKSUM_W, mcode_chksum);
+    AscWriteLramWord(iop_base, ASCV_MCODE_SIZE_W, mcode_size);
+    return (chksum);
+}
+
+STATIC int
+AscFindSignature(
+                    PortAddr iop_base
+)
+{
+    ushort              sig_word;
+
+    ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureByte(0x%x) 0x%x\n",
+        iop_base, AscGetChipSignatureByte(iop_base));
+    if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
+        ASC_DBG2(1, "AscFindSignature: AscGetChipSignatureWord(0x%x) 0x%x\n",
+            iop_base, AscGetChipSignatureWord(iop_base));
+        sig_word = AscGetChipSignatureWord(iop_base);
+        if ((sig_word == (ushort) ASC_1000_ID0W) ||
+            (sig_word == (ushort) ASC_1000_ID0W_FIX)) {
+            return (1);
+        }
+    }
+    return (0);
+}
+
+STATIC PortAddr _asc_def_iop_base[ASC_IOADR_TABLE_MAX_IX] __initdata =
+{
+    0x100, ASC_IOADR_1, 0x120, ASC_IOADR_2, 0x140, ASC_IOADR_3, ASC_IOADR_4,
+    ASC_IOADR_5, ASC_IOADR_6, ASC_IOADR_7, ASC_IOADR_8
+};
+
+#ifdef CONFIG_ISA
+STATIC uchar _isa_pnp_inited __initdata = 0;
+
+STATIC PortAddr __init
+AscSearchIOPortAddr(
+                       PortAddr iop_beg,
+                       ushort bus_type)
+{
+    if (bus_type & ASC_IS_VL) {
+        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+            if (AscGetChipVersion(iop_beg, bus_type) <= ASC_CHIP_MAX_VER_VL) {
+                return (iop_beg);
+            }
+        }
+        return (0);
+    }
+    if (bus_type & ASC_IS_ISA) {
+        if (_isa_pnp_inited == 0) {
+            AscSetISAPNPWaitForKey();
+            _isa_pnp_inited++;
+        }
+        while ((iop_beg = AscSearchIOPortAddr11(iop_beg)) != 0) {
+            if ((AscGetChipVersion(iop_beg, bus_type) & ASC_CHIP_VER_ISA_BIT) != 0) {
+                return (iop_beg);
+            }
+        }
+        return (0);
+    }
+    if (bus_type & ASC_IS_EISA) {
+        if ((iop_beg = AscSearchIOPortAddrEISA(iop_beg)) != 0) {
+            return (iop_beg);
+        }
+        return (0);
+    }
+    return (0);
+}
+
+STATIC PortAddr __init
+AscSearchIOPortAddr11(
+                         PortAddr s_addr
+)
+{
+    int                 i;
+    PortAddr            iop_base;
+
+    for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+        if (_asc_def_iop_base[i] > s_addr) {
+            break;
+        }
+    }
+    for (; i < ASC_IOADR_TABLE_MAX_IX; i++) {
+        iop_base = _asc_def_iop_base[i];
+        if (check_region(iop_base, ASC_IOADR_GAP) != 0) {
+            ASC_DBG1(1,
+               "AscSearchIOPortAddr11: check_region() failed I/O port 0x%x\n",
+                     iop_base);
+            continue;
+        }
+        ASC_DBG1(1, "AscSearchIOPortAddr11: probing I/O port 0x%x\n", iop_base);
+        if (AscFindSignature(iop_base)) {
+            return (iop_base);
+        }
+    }
+    return (0);
+}
+
+STATIC void __init
+AscSetISAPNPWaitForKey(void)
+{
+    outp(ASC_ISA_PNP_PORT_ADDR, 0x02);
+    outp(ASC_ISA_PNP_PORT_WRITE, 0x02);
+    return;
+}
+#endif /* CONFIG_ISA */
+
+STATIC void __init
+AscToggleIRQAct(
+                   PortAddr iop_base
+)
+{
+    AscSetChipStatus(iop_base, CIW_IRQ_ACT);
+    AscSetChipStatus(iop_base, 0);
+    return;
+}
+
+STATIC uchar __init
+AscGetChipIRQ(
+                 PortAddr iop_base,
+                 ushort bus_type)
+{
+    ushort              cfg_lsw;
+    uchar               chip_irq;
+
+    if ((bus_type & ASC_IS_EISA) != 0) {
+        cfg_lsw = AscGetEisaChipCfg(iop_base);
+        chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
+        if ((chip_irq == 13) || (chip_irq > 15)) {
+            return (0);
+        }
+        return (chip_irq);
+    }
+    if ((bus_type & ASC_IS_VL) != 0) {
+        cfg_lsw = AscGetChipCfgLsw(iop_base);
+        chip_irq = (uchar) (((cfg_lsw >> 2) & 0x07));
+        if ((chip_irq == 0) ||
+            (chip_irq == 4) ||
+            (chip_irq == 7)) {
+            return (0);
+        }
+        return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
+    }
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    chip_irq = (uchar) (((cfg_lsw >> 2) & 0x03));
+    if (chip_irq == 3)
+        chip_irq += (uchar) 2;
+    return ((uchar) (chip_irq + ASC_MIN_IRQ_NO));
+}
+
+STATIC uchar __init
+AscSetChipIRQ(
+                 PortAddr iop_base,
+                 uchar irq_no,
+                 ushort bus_type)
+{
+    ushort              cfg_lsw;
+
+    if ((bus_type & ASC_IS_VL) != 0) {
+        if (irq_no != 0) {
+            if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
+                irq_no = 0;
+            } else {
+                irq_no -= (uchar) ((ASC_MIN_IRQ_NO - 1));
+            }
+        }
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE3);
+        cfg_lsw |= (ushort) 0x0010;
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        AscToggleIRQAct(iop_base);
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFE0);
+        cfg_lsw |= (ushort) ((irq_no & 0x07) << 2);
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        AscToggleIRQAct(iop_base);
+        return (AscGetChipIRQ(iop_base, bus_type));
+    }
+    if ((bus_type & (ASC_IS_ISA)) != 0) {
+        if (irq_no == 15)
+            irq_no -= (uchar) 2;
+        irq_no -= (uchar) ASC_MIN_IRQ_NO;
+        cfg_lsw = (ushort) (AscGetChipCfgLsw(iop_base) & 0xFFF3);
+        cfg_lsw |= (ushort) ((irq_no & 0x03) << 2);
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        return (AscGetChipIRQ(iop_base, bus_type));
+    }
+    return (0);
+}
+
+#ifdef CONFIG_ISA
+STATIC void __init
+AscEnableIsaDma(
+                   uchar dma_channel)
+{
+    if (dma_channel < 4) {
+        outp(0x000B, (ushort) (0xC0 | dma_channel));
+        outp(0x000A, dma_channel);
+    } else if (dma_channel < 8) {
+        outp(0x00D6, (ushort) (0xC0 | (dma_channel - 4)));
+        outp(0x00D4, (ushort) (dma_channel - 4));
+    }
+    return;
+}
+#endif /* CONFIG_ISA */
+
+STATIC int
+AscIsrChipHalted(
+                    ASC_DVC_VAR *asc_dvc
+)
+{
+    EXT_MSG             ext_msg;
+    EXT_MSG             out_msg;
+    ushort              halt_q_addr;
+    int                 sdtr_accept;
+    ushort              int_halt_code;
+    ASC_SCSI_BIT_ID_TYPE scsi_busy;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    PortAddr            iop_base;
+    uchar               tag_code;
+    uchar               q_status;
+    uchar               halt_qp;
+    uchar               sdtr_data;
+    uchar               target_ix;
+    uchar               q_cntl, tid_no;
+    uchar               cur_dvc_qng;
+    uchar               asyn_sdtr;
+    uchar               scsi_status;
+    asc_board_t         *boardp;
+
+    ASC_ASSERT(asc_dvc->drv_ptr != NULL);
+    boardp = asc_dvc->drv_ptr;
+
+    iop_base = asc_dvc->iop_base;
+    int_halt_code = AscReadLramWord(iop_base, ASCV_HALTCODE_W);
+
+    halt_qp = AscReadLramByte(iop_base, ASCV_CURCDB_B);
+    halt_q_addr = ASC_QNO_TO_QADDR(halt_qp);
+    target_ix = AscReadLramByte(iop_base,
+                   (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TARGET_IX));
+    q_cntl = AscReadLramByte(iop_base,
+                        (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    target_id = (uchar) ASC_TID_TO_TARGET_ID(tid_no);
+    if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+        asyn_sdtr = ASYN_SDTR_DATA_FIX_PCI_REV_AB;
+    } else {
+        asyn_sdtr = 0;
+    }
+    if (int_halt_code == ASC_HALT_DISABLE_ASYN_USE_SYN_FIX) {
+        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+            AscSetChipSDTR(iop_base, 0, tid_no);
+            boardp->sdtr_data[tid_no] = 0;
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_ENABLE_ASYN_USE_SYN_FIX) {
+        if (asc_dvc->pci_fix_asyn_xfer & target_id) {
+            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            boardp->sdtr_data[tid_no] = asyn_sdtr;
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_EXTMSG_IN) {
+
+        AscMemWordCopyPtrFromLram(iop_base,
+                               ASCV_MSGIN_BEG,
+                               (uchar *) &ext_msg,
+                               sizeof(EXT_MSG) >> 1);
+
+        if (ext_msg.msg_type == MS_EXTEND &&
+            ext_msg.msg_req == MS_SDTR_CODE &&
+            ext_msg.msg_len == MS_SDTR_LEN) {
+            sdtr_accept = TRUE;
+            if ((ext_msg.req_ack_offset > ASC_SYN_MAX_OFFSET)) {
+
+                sdtr_accept = FALSE;
+                ext_msg.req_ack_offset = ASC_SYN_MAX_OFFSET;
+            }
+            if ((ext_msg.xfer_period <
+                 asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index]) ||
+                (ext_msg.xfer_period >
+                 asc_dvc->sdtr_period_tbl[asc_dvc->max_sdtr_index])) {
+                sdtr_accept = FALSE;
+                ext_msg.xfer_period =
+                    asc_dvc->sdtr_period_tbl[asc_dvc->host_init_sdtr_index];
+            }
+            if (sdtr_accept) {
+                sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                           ext_msg.req_ack_offset);
+                if ((sdtr_data == 0xFF)) {
+
+                    q_cntl |= QC_MSG_OUT;
+                    asc_dvc->init_sdtr &= ~target_id;
+                    asc_dvc->sdtr_done &= ~target_id;
+                    AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+                    boardp->sdtr_data[tid_no] = asyn_sdtr;
+                }
+            }
+            if (ext_msg.req_ack_offset == 0) {
+
+                q_cntl &= ~QC_MSG_OUT;
+                asc_dvc->init_sdtr &= ~target_id;
+                asc_dvc->sdtr_done &= ~target_id;
+                AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            } else {
+                if (sdtr_accept && (q_cntl & QC_MSG_OUT)) {
+
+                    q_cntl &= ~QC_MSG_OUT;
+                    asc_dvc->sdtr_done |= target_id;
+                    asc_dvc->init_sdtr |= target_id;
+                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                               ext_msg.req_ack_offset);
+                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+                    boardp->sdtr_data[tid_no] = sdtr_data;
+                } else {
+
+                    q_cntl |= QC_MSG_OUT;
+                    AscMsgOutSDTR(asc_dvc,
+                                  ext_msg.xfer_period,
+                                  ext_msg.req_ack_offset);
+                    asc_dvc->pci_fix_asyn_xfer &= ~target_id;
+                    sdtr_data = AscCalSDTRData(asc_dvc, ext_msg.xfer_period,
+                                               ext_msg.req_ack_offset);
+                    AscSetChipSDTR(iop_base, sdtr_data, tid_no);
+                    boardp->sdtr_data[tid_no] = sdtr_data;
+                    asc_dvc->sdtr_done |= target_id;
+                    asc_dvc->init_sdtr |= target_id;
+                }
+            }
+
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        } else if (ext_msg.msg_type == MS_EXTEND &&
+                   ext_msg.msg_req == MS_WDTR_CODE &&
+                   ext_msg.msg_len == MS_WDTR_LEN) {
+
+            ext_msg.wdtr_width = 0;
+            AscMemWordCopyPtrToLram(iop_base,
+                                 ASCV_MSGOUT_BEG,
+                                 (uchar *) &ext_msg,
+                                 sizeof(EXT_MSG) >> 1);
+            q_cntl |= QC_MSG_OUT;
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        } else {
+
+            ext_msg.msg_type = MESSAGE_REJECT;
+            AscMemWordCopyPtrToLram(iop_base,
+                                 ASCV_MSGOUT_BEG,
+                                 (uchar *) &ext_msg,
+                                 sizeof(EXT_MSG) >> 1);
+            q_cntl |= QC_MSG_OUT;
+            AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                             q_cntl);
+            AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+            return (0);
+        }
+    } else if (int_halt_code == ASC_HALT_CHK_CONDITION) {
+
+        q_cntl |= QC_REQ_SENSE;
+
+        if ((asc_dvc->init_sdtr & target_id) != 0) {
+
+            asc_dvc->sdtr_done &= ~target_id;
+
+            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+            q_cntl |= QC_MSG_OUT;
+            AscMsgOutSDTR(asc_dvc,
+                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
+                           (uchar) (asc_dvc->max_sdtr_index - 1)],
+                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+        }
+
+        AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                         q_cntl);
+
+        tag_code = AscReadLramByte(iop_base,
+                    (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE));
+        tag_code &= 0xDC;
+        if (
+               (asc_dvc->pci_fix_asyn_xfer & target_id)
+               && !(asc_dvc->pci_fix_asyn_xfer_always & target_id)
+) {
+
+            tag_code |= (ASC_TAG_FLAG_DISABLE_DISCONNECT
+                         | ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX);
+
+        }
+        AscWriteLramByte(iop_base,
+                     (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_TAG_CODE),
+                         tag_code);
+
+        q_status = AscReadLramByte(iop_base,
+                      (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+        q_status |= (QS_READY | QS_BUSY);
+        AscWriteLramByte(iop_base,
+                       (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                         q_status);
+
+        scsi_busy = AscReadLramByte(iop_base,
+                                    (ushort) ASCV_SCSIBUSY_B);
+        scsi_busy &= ~target_id;
+        AscWriteLramByte(iop_base, (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_SDTR_REJECTED) {
+
+        AscMemWordCopyPtrFromLram(iop_base,
+                               ASCV_MSGOUT_BEG,
+                               (uchar *) &out_msg,
+                               sizeof(EXT_MSG) >> 1);
+
+        if ((out_msg.msg_type == MS_EXTEND) &&
+            (out_msg.msg_len == MS_SDTR_LEN) &&
+            (out_msg.msg_req == MS_SDTR_CODE)) {
+
+            asc_dvc->init_sdtr &= ~target_id;
+            asc_dvc->sdtr_done &= ~target_id;
+            AscSetChipSDTR(iop_base, asyn_sdtr, tid_no);
+            boardp->sdtr_data[tid_no] = asyn_sdtr;
+        }
+        q_cntl &= ~QC_MSG_OUT;
+        AscWriteLramByte(iop_base,
+                         (ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
+                         q_cntl);
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    } else if (int_halt_code == ASC_HALT_SS_QUEUE_FULL) {
+
+        scsi_status = AscReadLramByte(iop_base,
+          (ushort) ((ushort) halt_q_addr + (ushort) ASC_SCSIQ_SCSI_STATUS));
+        cur_dvc_qng = AscReadLramByte(iop_base,
+                     (ushort) ((ushort) ASC_QADR_BEG + (ushort) target_ix));
+        if ((cur_dvc_qng > 0) &&
+            (asc_dvc->cur_dvc_qng[tid_no] > 0)) {
+
+            scsi_busy = AscReadLramByte(iop_base,
+                                        (ushort) ASCV_SCSIBUSY_B);
+            scsi_busy |= target_id;
+            AscWriteLramByte(iop_base,
+                             (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+            asc_dvc->queue_full_or_busy |= target_id;
+
+            if (scsi_status == SAM_STAT_TASK_SET_FULL) {
+                if (cur_dvc_qng > ASC_MIN_TAGGED_CMD) {
+                    cur_dvc_qng -= 1;
+                    asc_dvc->max_dvc_qng[tid_no] = cur_dvc_qng;
+
+                    AscWriteLramByte(iop_base,
+                          (ushort) ((ushort) ASCV_MAX_DVC_QNG_BEG +
+                           (ushort) tid_no),
+                          cur_dvc_qng);
+
+                    /*
+                     * Set the device queue depth to the number of
+                     * active requests when the QUEUE FULL condition
+                     * was encountered.
+                     */
+                    boardp->queue_full |= target_id;
+                    boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
+                }
+            }
+        }
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return (0);
+    }
+#if CC_VERY_LONG_SG_LIST
+    else if (int_halt_code == ASC_HALT_HOST_COPY_SG_LIST_TO_RISC)
+    {
+        uchar              q_no;
+        ushort             q_addr;
+        uchar              sg_wk_q_no;
+        uchar              first_sg_wk_q_no;
+        ASC_SCSI_Q         *scsiq; /* Ptr to driver request. */
+        ASC_SG_HEAD        *sg_head; /* Ptr to driver SG request. */
+        ASC_SG_LIST_Q      scsi_sg_q; /* Structure written to queue. */
+        ushort             sg_list_dwords;
+        ushort             sg_entry_cnt;
+        uchar              next_qp;
+        int                i;
+
+        q_no = AscReadLramByte(iop_base, (ushort) ASCV_REQ_SG_LIST_QP);
+        if (q_no == ASC_QLINK_END)
+        {
+            return(0);
+        }
+
+        q_addr = ASC_QNO_TO_QADDR(q_no);
+
+        /*
+         * Convert the request's SRB pointer to a host ASC_SCSI_REQ
+         * structure pointer using a macro provided by the driver.
+         * The ASC_SCSI_REQ pointer provides a pointer to the
+         * host ASC_SG_HEAD structure.
+         */
+        /* Read request's SRB pointer. */
+        scsiq = (ASC_SCSI_Q *)
+           ASC_SRB2SCSIQ(
+               ASC_U32_TO_VADDR(AscReadLramDWord(iop_base,
+               (ushort) (q_addr + ASC_SCSIQ_D_SRBPTR))));
+
+        /*
+         * Get request's first and working SG queue.
+         */
+        sg_wk_q_no = AscReadLramByte(iop_base,
+            (ushort) (q_addr + ASC_SCSIQ_B_SG_WK_QP));
+
+        first_sg_wk_q_no = AscReadLramByte(iop_base,
+            (ushort) (q_addr + ASC_SCSIQ_B_FIRST_SG_WK_QP));
+
+        /*
+         * Reset request's working SG queue back to the
+         * first SG queue.
+         */
+        AscWriteLramByte(iop_base,
+            (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SG_WK_QP),
+            first_sg_wk_q_no);
+
+        sg_head = scsiq->sg_head;
+
+        /*
+         * Set sg_entry_cnt to the number of SG elements
+         * that will be completed on this interrupt.
+         *
+         * Note: The allocated SG queues contain ASC_MAX_SG_LIST - 1
+         * SG elements. The data_cnt and data_addr fields which
+         * add 1 to the SG element capacity are not used when
+         * restarting SG handling after a halt.
+         */
+        if (scsiq->remain_sg_entry_cnt > (ASC_MAX_SG_LIST - 1))
+        {
+             sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+             /*
+              * Keep track of remaining number of SG elements that will
+              * need to be handled on the next interrupt.
+              */
+             scsiq->remain_sg_entry_cnt -= (ASC_MAX_SG_LIST - 1);
+        } else
+        {
+             sg_entry_cnt = scsiq->remain_sg_entry_cnt;
+             scsiq->remain_sg_entry_cnt = 0;
+        }
+
+        /*
+         * Copy SG elements into the list of allocated SG queues.
+         *
+         * Last index completed is saved in scsiq->next_sg_index.
+         */
+        next_qp = first_sg_wk_q_no;
+        q_addr = ASC_QNO_TO_QADDR(next_qp);
+        scsi_sg_q.sg_head_qp = q_no;
+        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+        for( i = 0; i < sg_head->queue_cnt; i++)
+        {
+             scsi_sg_q.seq_no = i + 1;
+             if (sg_entry_cnt > ASC_SG_LIST_PER_Q)
+             {
+                 sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                 sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                 /*
+                  * After very first SG queue RISC FW uses next
+                  * SG queue first element then checks sg_list_cnt
+                  * against zero and then decrements, so set
+                  * sg_list_cnt 1 less than number of SG elements
+                  * in each SG queue.
+                  */
+                 scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                 scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+             } else {
+                 /*
+                  * This is the last SG queue in the list of
+                  * allocated SG queues. If there are more
+                  * SG elements than will fit in the allocated
+                  * queues, then set the QCSG_SG_XFER_MORE flag.
+                  */
+                 if (scsiq->remain_sg_entry_cnt != 0)
+                 {
+                     scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                 } else
+                 {
+                     scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+                 }
+                 /* equals sg_entry_cnt * 2 */
+                 sg_list_dwords = sg_entry_cnt << 1;
+                 scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                 scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                 sg_entry_cnt = 0;
+             }
+
+             scsi_sg_q.q_no = next_qp;
+             AscMemWordCopyPtrToLram(iop_base,
+                          q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                          (uchar *) &scsi_sg_q,
+                          sizeof(ASC_SG_LIST_Q) >> 1);
+
+             AscMemDWordCopyPtrToLram(iop_base,
+                          q_addr + ASC_SGQ_LIST_BEG,
+                          (uchar *) &sg_head->sg_list[scsiq->next_sg_index],
+                          sg_list_dwords);
+
+             scsiq->next_sg_index += ASC_SG_LIST_PER_Q;
+
+             /*
+              * If the just completed SG queue contained the
+              * last SG element, then no more SG queues need
+              * to be written.
+              */
+             if (scsi_sg_q.cntl & QCSG_SG_XFER_END)
+             {
+                 break;
+             }
+
+             next_qp = AscReadLramByte( iop_base,
+                          ( ushort )( q_addr+ASC_SCSIQ_B_FWD ) );
+             q_addr = ASC_QNO_TO_QADDR( next_qp );
+        }
+
+        /*
+         * Clear the halt condition so the RISC will be restarted
+         * after the return.
+         */
+        AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+        return(0);
+    }
+#endif /* CC_VERY_LONG_SG_LIST */
+    return (0);
+}
+
+STATIC uchar
+_AscCopyLramScsiDoneQ(
+                         PortAddr iop_base,
+                         ushort q_addr,
+                         ASC_QDONE_INFO * scsiq,
+                         ASC_DCNT max_dma_count
+)
+{
+    ushort              _val;
+    uchar               sg_queue_cnt;
+
+    DvcGetQinfo(iop_base,
+                q_addr + ASC_SCSIQ_DONE_INFO_BEG,
+                (uchar *) scsiq,
+                (sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2);
+
+    _val = AscReadLramWord(iop_base,
+                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
+    scsiq->q_status = (uchar) _val;
+    scsiq->q_no = (uchar) (_val >> 8);
+    _val = AscReadLramWord(iop_base,
+                           (ushort) (q_addr + (ushort) ASC_SCSIQ_B_CNTL));
+    scsiq->cntl = (uchar) _val;
+    sg_queue_cnt = (uchar) (_val >> 8);
+    _val = AscReadLramWord(iop_base,
+                        (ushort) (q_addr + (ushort) ASC_SCSIQ_B_SENSE_LEN));
+    scsiq->sense_len = (uchar) _val;
+    scsiq->extra_bytes = (uchar) (_val >> 8);
+
+    /*
+     * Read high word of remain bytes from alternate location.
+     */
+    scsiq->remain_bytes = (((ADV_DCNT) AscReadLramWord( iop_base,
+                      (ushort) (q_addr+ (ushort) ASC_SCSIQ_W_ALT_DC1))) << 16);
+    /*
+     * Read low word of remain bytes from original location.
+     */
+    scsiq->remain_bytes += AscReadLramWord(iop_base,
+        (ushort) (q_addr+ (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT));
+
+    scsiq->remain_bytes &= max_dma_count;
+    return (sg_queue_cnt);
+}
+
+STATIC int
+AscIsrQDone(
+               ASC_DVC_VAR *asc_dvc
+)
+{
+    uchar               next_qp;
+    uchar               n_q_used;
+    uchar               sg_list_qp;
+    uchar               sg_queue_cnt;
+    uchar               q_cnt;
+    uchar               done_q_tail;
+    uchar               tid_no;
+    ASC_SCSI_BIT_ID_TYPE scsi_busy;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    PortAddr            iop_base;
+    ushort              q_addr;
+    ushort              sg_q_addr;
+    uchar               cur_target_qng;
+    ASC_QDONE_INFO      scsiq_buf;
+    ASC_QDONE_INFO *scsiq;
+    int                 false_overrun;
+    ASC_ISR_CALLBACK    asc_isr_callback;
+
+    iop_base = asc_dvc->iop_base;
+    asc_isr_callback = asc_dvc->isr_callback;
+    n_q_used = 1;
+    scsiq = (ASC_QDONE_INFO *) & scsiq_buf;
+    done_q_tail = (uchar) AscGetVarDoneQTail(iop_base);
+    q_addr = ASC_QNO_TO_QADDR(done_q_tail);
+    next_qp = AscReadLramByte(iop_base,
+                              (ushort) (q_addr + (ushort) ASC_SCSIQ_B_FWD));
+    if (next_qp != ASC_QLINK_END) {
+        AscPutVarDoneQTail(iop_base, next_qp);
+        q_addr = ASC_QNO_TO_QADDR(next_qp);
+        sg_queue_cnt = _AscCopyLramScsiDoneQ(iop_base, q_addr, scsiq,
+            asc_dvc->max_dma_count);
+        AscWriteLramByte(iop_base,
+                         (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+             (uchar) (scsiq->q_status & (uchar) ~ (QS_READY | QS_ABORTED)));
+        tid_no = ASC_TIX_TO_TID(scsiq->d2.target_ix);
+        target_id = ASC_TIX_TO_TARGET_ID(scsiq->d2.target_ix);
+        if ((scsiq->cntl & QC_SG_HEAD) != 0) {
+            sg_q_addr = q_addr;
+            sg_list_qp = next_qp;
+            for (q_cnt = 0; q_cnt < sg_queue_cnt; q_cnt++) {
+                sg_list_qp = AscReadLramByte(iop_base,
+                           (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_FWD));
+                sg_q_addr = ASC_QNO_TO_QADDR(sg_list_qp);
+                if (sg_list_qp == ASC_QLINK_END) {
+                    AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_Q_LINKS);
+                    scsiq->d3.done_stat = QD_WITH_ERROR;
+                    scsiq->d3.host_stat = QHSTA_D_QDONE_SG_LIST_CORRUPTED;
+                    goto FATAL_ERR_QDONE;
+                }
+                AscWriteLramByte(iop_base,
+                         (ushort) (sg_q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+                                 QS_FREE);
+            }
+            n_q_used = sg_queue_cnt + 1;
+            AscPutVarDoneQTail(iop_base, sg_list_qp);
+        }
+        if (asc_dvc->queue_full_or_busy & target_id) {
+            cur_target_qng = AscReadLramByte(iop_base,
+            (ushort) ((ushort) ASC_QADR_BEG + (ushort) scsiq->d2.target_ix));
+            if (cur_target_qng < asc_dvc->max_dvc_qng[tid_no]) {
+                scsi_busy = AscReadLramByte(iop_base,
+                                            (ushort) ASCV_SCSIBUSY_B);
+                scsi_busy &= ~target_id;
+                AscWriteLramByte(iop_base,
+                                 (ushort) ASCV_SCSIBUSY_B, scsi_busy);
+                asc_dvc->queue_full_or_busy &= ~target_id;
+            }
+        }
+        if (asc_dvc->cur_total_qng >= n_q_used) {
+            asc_dvc->cur_total_qng -= n_q_used;
+            if (asc_dvc->cur_dvc_qng[tid_no] != 0) {
+                asc_dvc->cur_dvc_qng[tid_no]--;
+            }
+        } else {
+            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CUR_QNG);
+            scsiq->d3.done_stat = QD_WITH_ERROR;
+            goto FATAL_ERR_QDONE;
+        }
+        if ((scsiq->d2.srb_ptr == 0UL) ||
+            ((scsiq->q_status & QS_ABORTED) != 0)) {
+            return (0x11);
+        } else if (scsiq->q_status == QS_DONE) {
+            false_overrun = FALSE;
+            if (scsiq->extra_bytes != 0) {
+                scsiq->remain_bytes += (ADV_DCNT) scsiq->extra_bytes;
+            }
+            if (scsiq->d3.done_stat == QD_WITH_ERROR) {
+                if (scsiq->d3.host_stat == QHSTA_M_DATA_OVER_RUN) {
+                    if ((scsiq->cntl & (QC_DATA_IN | QC_DATA_OUT)) == 0) {
+                        scsiq->d3.done_stat = QD_NO_ERROR;
+                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
+                    } else if (false_overrun) {
+                        scsiq->d3.done_stat = QD_NO_ERROR;
+                        scsiq->d3.host_stat = QHSTA_NO_ERROR;
+                    }
+                } else if (scsiq->d3.host_stat ==
+                           QHSTA_M_HUNG_REQ_SCSI_BUS_RESET) {
+                    AscStopChip(iop_base);
+                    AscSetChipControl(iop_base,
+                        (uchar) (CC_SCSI_RESET | CC_HALT));
+                    DvcDelayNanoSecond(asc_dvc, 60000);
+                    AscSetChipControl(iop_base, CC_HALT);
+                    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+                    AscSetChipStatus(iop_base, 0);
+                    AscSetChipControl(iop_base, 0);
+                }
+            }
+            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                (*asc_isr_callback) (asc_dvc, scsiq);
+            } else {
+                if ((AscReadLramByte(iop_base,
+                          (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG)) ==
+                     START_STOP)) {
+                    asc_dvc->unit_not_ready &= ~target_id;
+                    if (scsiq->d3.done_stat != QD_NO_ERROR) {
+                        asc_dvc->start_motor &= ~target_id;
+                    }
+                }
+            }
+            return (1);
+        } else {
+            AscSetLibErrorCode(asc_dvc, ASCQ_ERR_Q_STATUS);
+          FATAL_ERR_QDONE:
+            if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
+                (*asc_isr_callback) (asc_dvc, scsiq);
+            }
+            return (0x80);
+        }
+    }
+    return (0);
+}
+
+STATIC int
+AscISR(
+          ASC_DVC_VAR *asc_dvc
+)
+{
+    ASC_CS_TYPE         chipstat;
+    PortAddr            iop_base;
+    ushort              saved_ram_addr;
+    uchar               ctrl_reg;
+    uchar               saved_ctrl_reg;
+    int                 int_pending;
+    int                 status;
+    uchar               host_flag;
+
+    iop_base = asc_dvc->iop_base;
+    int_pending = FALSE;
+
+    if (AscIsIntPending(iop_base) == 0)
+    {
+        return int_pending;
+    }
+
+    if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
+        || (asc_dvc->isr_callback == 0)
+) {
+        return (ERR);
+    }
+    if (asc_dvc->in_critical_cnt != 0) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_ON_CRITICAL);
+        return (ERR);
+    }
+    if (asc_dvc->is_in_int) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_ISR_RE_ENTRY);
+        return (ERR);
+    }
+    asc_dvc->is_in_int = TRUE;
+    ctrl_reg = AscGetChipControl(iop_base);
+    saved_ctrl_reg = ctrl_reg & (~(CC_SCSI_RESET | CC_CHIP_RESET |
+                                   CC_SINGLE_STEP | CC_DIAG | CC_TEST));
+    chipstat = AscGetChipStatus(iop_base);
+    if (chipstat & CSW_SCSI_RESET_LATCH) {
+        if (!(asc_dvc->bus_type & (ASC_IS_VL | ASC_IS_EISA))) {
+            int i = 10;
+            int_pending = TRUE;
+            asc_dvc->sdtr_done = 0;
+            saved_ctrl_reg &= (uchar) (~CC_HALT);
+            while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) &&
+                   (i-- > 0))
+            {
+                  DvcSleepMilliSecond(100);
+            }
+            AscSetChipControl(iop_base, (CC_CHIP_RESET | CC_HALT));
+            AscSetChipControl(iop_base, CC_HALT);
+            AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+            AscSetChipStatus(iop_base, 0);
+            chipstat = AscGetChipStatus(iop_base);
+        }
+    }
+    saved_ram_addr = AscGetChipLramAddr(iop_base);
+    host_flag = AscReadLramByte(iop_base,
+        ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                     (uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
+    if ((chipstat & CSW_INT_PENDING)
+        || (int_pending)
+) {
+        AscAckInterrupt(iop_base);
+        int_pending = TRUE;
+        if ((chipstat & CSW_HALTED) &&
+            (ctrl_reg & CC_SINGLE_STEP)) {
+            if (AscIsrChipHalted(asc_dvc) == ERR) {
+                goto ISR_REPORT_QDONE_FATAL_ERROR;
+            } else {
+                saved_ctrl_reg &= (uchar) (~CC_HALT);
+            }
+        } else {
+          ISR_REPORT_QDONE_FATAL_ERROR:
+            if ((asc_dvc->dvc_cntl & ASC_CNTL_INT_MULTI_Q) != 0) {
+                while (((status = AscIsrQDone(asc_dvc)) & 0x01) != 0) {
+                }
+            } else {
+                do {
+                    if ((status = AscIsrQDone(asc_dvc)) == 1) {
+                        break;
+                    }
+                } while (status == 0x11);
+            }
+            if ((status & 0x80) != 0)
+                int_pending = ERR;
+        }
+    }
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+    AscSetChipLramAddr(iop_base, saved_ram_addr);
+    AscSetChipControl(iop_base, saved_ctrl_reg);
+    asc_dvc->is_in_int = FALSE;
+    return (int_pending);
+}
+
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC uchar _asc_mcode_buf[] =
+{
+  0x01,  0x03,  0x01,  0x19,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x0F,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xC3,  0x12,  0x0D,  0x05,  0x01,  0x00,  0x00,  0x00,  0x00,  0xFF,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x00,  0xFF,  0x80,  0xFF,  0xFF,  0x01,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+  0x00,  0x00,  0x00,  0x23,  0x00,  0x00,  0x00,  0x00,  0x00,  0x07,  0x00,  0xFF,  0x00,  0x00,  0x00,  0x00,
+  0xFF,  0xFF,  0xFF,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0xE4,  0x88,  0x00,  0x00,  0x00,  0x00,
+  0x80,  0x73,  0x48,  0x04,  0x36,  0x00,  0x00,  0xA2,  0xC2,  0x00,  0x80,  0x73,  0x03,  0x23,  0x36,  0x40,
+  0xB6,  0x00,  0x36,  0x00,  0x05,  0xD6,  0x0C,  0xD2,  0x12,  0xDA,  0x00,  0xA2,  0xC2,  0x00,  0x92,  0x80,
+  0x1E,  0x98,  0x50,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xDF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,
+  0x4F,  0x00,  0xF5,  0x00,  0x48,  0x98,  0xEF,  0x23,  0x36,  0x60,  0xB6,  0x00,  0x92,  0x80,  0x80,  0x62,
+  0x92,  0x80,  0x00,  0x46,  0x15,  0xEE,  0x13,  0xEA,  0x02,  0x01,  0x09,  0xD8,  0xCD,  0x04,  0x4D,  0x00,
+  0x00,  0xA3,  0xD6,  0x00,  0xA6,  0x97,  0x7F,  0x23,  0x04,  0x61,  0x84,  0x01,  0xE6,  0x84,  0xD2,  0xC1,
+  0x80,  0x73,  0xCD,  0x04,  0x4D,  0x00,  0x00,  0xA3,  0xDA,  0x01,  0xA6,  0x97,  0xC6,  0x81,  0xC2,  0x88,
+  0x80,  0x73,  0x80,  0x77,  0x00,  0x01,  0x01,  0xA1,  0xFE,  0x00,  0x4F,  0x00,  0x84,  0x97,  0x07,  0xA6,
+  0x08,  0x01,  0x00,  0x33,  0x03,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x01,  0xDE,  0xC2,  0x88,  0xCE,  0x00,
+  0x69,  0x60,  0xCE,  0x00,  0x02,  0x03,  0x4A,  0x60,  0x00,  0xA2,  0x78,  0x01,  0x80,  0x63,  0x07,  0xA6,
+  0x24,  0x01,  0x78,  0x81,  0x03,  0x03,  0x80,  0x63,  0xE2,  0x00,  0x07,  0xA6,  0x34,  0x01,  0x00,  0x33,
+  0x04,  0x00,  0xC2,  0x88,  0x03,  0x07,  0x02,  0x01,  0x04,  0xCA,  0x0D,  0x23,  0x68,  0x98,  0x4D,  0x04,
+  0x04,  0x85,  0x05,  0xD8,  0x0D,  0x23,  0x68,  0x98,  0xCD,  0x04,  0x15,  0x23,  0xF8,  0x88,  0xFB,  0x23,
+  0x02,  0x61,  0x82,  0x01,  0x80,  0x63,  0x02,  0x03,  0x06,  0xA3,  0x62,  0x01,  0x00,  0x33,  0x0A,  0x00,
+  0xC2,  0x88,  0x4E,  0x00,  0x07,  0xA3,  0x6E,  0x01,  0x00,  0x33,  0x0B,  0x00,  0xC2,  0x88,  0xCD,  0x04,
+  0x36,  0x2D,  0x00,  0x33,  0x1A,  0x00,  0xC2,  0x88,  0x50,  0x04,  0x88,  0x81,  0x06,  0xAB,  0x82,  0x01,
+  0x88,  0x81,  0x4E,  0x00,  0x07,  0xA3,  0x92,  0x01,  0x50,  0x00,  0x00,  0xA3,  0x3C,  0x01,  0x00,  0x05,
+  0x7C,  0x81,  0x46,  0x97,  0x02,  0x01,  0x05,  0xC6,  0x04,  0x23,  0xA0,  0x01,  0x15,  0x23,  0xA1,  0x01,
+  0xBE,  0x81,  0xFD,  0x23,  0x02,  0x61,  0x82,  0x01,  0x0A,  0xDA,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,
+  0xB4,  0x01,  0x80,  0x63,  0xCD,  0x04,  0x36,  0x2D,  0x00,  0x33,  0x1B,  0x00,  0xC2,  0x88,  0x06,  0x23,
+  0x68,  0x98,  0xCD,  0x04,  0xE6,  0x84,  0x06,  0x01,  0x00,  0xA2,  0xD4,  0x01,  0x57,  0x60,  0x00,  0xA0,
+  0xDA,  0x01,  0xE6,  0x84,  0x80,  0x23,  0xA0,  0x01,  0xE6,  0x84,  0x80,  0x73,  0x4B,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x00,  0x02,  0x04,  0x01,  0x0C,  0xDE,  0x02,  0x01,  0x03,  0xCC,  0x4F,  0x00,  0x84,  0x97,
+  0xFC,  0x81,  0x08,  0x23,  0x02,  0x41,  0x82,  0x01,  0x4F,  0x00,  0x62,  0x97,  0x48,  0x04,  0x84,  0x80,
+  0xF0,  0x97,  0x00,  0x46,  0x56,  0x00,  0x03,  0xC0,  0x01,  0x23,  0xE8,  0x00,  0x81,  0x73,  0x06,  0x29,
+  0x03,  0x42,  0x06,  0xE2,  0x03,  0xEE,  0x6B,  0xEB,  0x11,  0x23,  0xF8,  0x88,  0x04,  0x98,  0xF0,  0x80,
+  0x80,  0x73,  0x80,  0x77,  0x07,  0xA4,  0x2A,  0x02,  0x7C,  0x95,  0x06,  0xA6,  0x34,  0x02,  0x03,  0xA6,
+  0x4C,  0x04,  0x46,  0x82,  0x04,  0x01,  0x03,  0xD8,  0xB4,  0x98,  0x6A,  0x96,  0x46,  0x82,  0xFE,  0x95,
+  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0xB6,  0x2D,  0x02,  0xA6,  0x6C,  0x02,  0x07,  0xA6,  0x5A,  0x02,
+  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x62,  0x02,  0xC2,  0x88,  0x7C,  0x95,  0x48,  0x82,  0x60,  0x96,
+  0x48,  0x82,  0x04,  0x23,  0xA0,  0x01,  0x14,  0x23,  0xA1,  0x01,  0x3C,  0x84,  0x04,  0x01,  0x0C,  0xDC,
+  0xE0,  0x23,  0x25,  0x61,  0xEF,  0x00,  0x14,  0x01,  0x4F,  0x04,  0xA8,  0x01,  0x6F,  0x00,  0xA5,  0x01,
+  0x03,  0x23,  0xA4,  0x01,  0x06,  0x23,  0x9C,  0x01,  0x24,  0x2B,  0x1C,  0x01,  0x02,  0xA6,  0xAA,  0x02,
+  0x07,  0xA6,  0x5A,  0x02,  0x06,  0xA6,  0x5E,  0x02,  0x03,  0xA6,  0x20,  0x04,  0x01,  0xA6,  0xB4,  0x02,
+  0x00,  0xA6,  0xB4,  0x02,  0x00,  0x33,  0x12,  0x00,  0xC2,  0x88,  0x00,  0x0E,  0x80,  0x63,  0x00,  0x43,
+  0x00,  0xA0,  0x8C,  0x02,  0x4D,  0x04,  0x04,  0x01,  0x0B,  0xDC,  0xE7,  0x23,  0x04,  0x61,  0x84,  0x01,
+  0x10,  0x31,  0x12,  0x35,  0x14,  0x01,  0xEC,  0x00,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0xEA,  0x82,
+  0x18,  0x23,  0x04,  0x61,  0x18,  0xA0,  0xE2,  0x02,  0x04,  0x01,  0xA2,  0xC8,  0x00,  0x33,  0x1F,  0x00,
+  0xC2,  0x88,  0x08,  0x31,  0x0A,  0x35,  0x0C,  0x39,  0x0E,  0x3D,  0x7E,  0x98,  0xB6,  0x2D,  0x01,  0xA6,
+  0x14,  0x03,  0x00,  0xA6,  0x14,  0x03,  0x07,  0xA6,  0x0C,  0x03,  0x06,  0xA6,  0x10,  0x03,  0x03,  0xA6,
+  0x20,  0x04,  0x02,  0xA6,  0x6C,  0x02,  0x00,  0x33,  0x33,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xEE,  0x82,
+  0x60,  0x96,  0xEE,  0x82,  0x82,  0x98,  0x80,  0x42,  0x7E,  0x98,  0x64,  0xE4,  0x04,  0x01,  0x2D,  0xC8,
+  0x31,  0x05,  0x07,  0x01,  0x00,  0xA2,  0x54,  0x03,  0x00,  0x43,  0x87,  0x01,  0x05,  0x05,  0x86,  0x98,
+  0x7E,  0x98,  0x00,  0xA6,  0x16,  0x03,  0x07,  0xA6,  0x4C,  0x03,  0x03,  0xA6,  0x3C,  0x04,  0x06,  0xA6,
+  0x50,  0x03,  0x01,  0xA6,  0x16,  0x03,  0x00,  0x33,  0x25,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x32,  0x83,
+  0x60,  0x96,  0x32,  0x83,  0x04,  0x01,  0x10,  0xCE,  0x07,  0xC8,  0x05,  0x05,  0xEB,  0x04,  0x00,  0x33,
+  0x00,  0x20,  0xC0,  0x20,  0x81,  0x62,  0x72,  0x83,  0x00,  0x01,  0x05,  0x05,  0xFF,  0xA2,  0x7A,  0x03,
+  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x2E,  0x83,  0x05,  0x05,  0x15,  0x01,  0x00,  0xA2,  0x9A,  0x03,
+  0xEC,  0x00,  0x6E,  0x00,  0x95,  0x01,  0x6C,  0x38,  0x00,  0x3F,  0x00,  0x00,  0x01,  0xA6,  0x96,  0x03,
+  0x00,  0xA6,  0x96,  0x03,  0x10,  0x84,  0x80,  0x42,  0x7E,  0x98,  0x01,  0xA6,  0xA4,  0x03,  0x00,  0xA6,
+  0xBC,  0x03,  0x10,  0x84,  0xA8,  0x98,  0x80,  0x42,  0x01,  0xA6,  0xA4,  0x03,  0x07,  0xA6,  0xB2,  0x03,
+  0xD4,  0x83,  0x7C,  0x95,  0xA8,  0x83,  0x00,  0x33,  0x2F,  0x00,  0xC2,  0x88,  0xA8,  0x98,  0x80,  0x42,
+  0x00,  0xA6,  0xBC,  0x03,  0x07,  0xA6,  0xCA,  0x03,  0xD4,  0x83,  0x7C,  0x95,  0xC0,  0x83,  0x00,  0x33,
+  0x26,  0x00,  0xC2,  0x88,  0x38,  0x2B,  0x80,  0x32,  0x80,  0x36,  0x04,  0x23,  0xA0,  0x01,  0x12,  0x23,
+  0xA1,  0x01,  0x10,  0x84,  0x07,  0xF0,  0x06,  0xA4,  0xF4,  0x03,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,
+  0x83,  0x03,  0x80,  0x63,  0x03,  0xA6,  0x0E,  0x04,  0x07,  0xA6,  0x06,  0x04,  0x06,  0xA6,  0x0A,  0x04,
+  0x00,  0x33,  0x17,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0xF4,  0x83,  0x60,  0x96,  0xF4,  0x83,  0x20,  0x84,
+  0x07,  0xF0,  0x06,  0xA4,  0x20,  0x04,  0x80,  0x6B,  0x80,  0x67,  0x05,  0x23,  0x83,  0x03,  0x80,  0x63,
+  0xB6,  0x2D,  0x03,  0xA6,  0x3C,  0x04,  0x07,  0xA6,  0x34,  0x04,  0x06,  0xA6,  0x38,  0x04,  0x00,  0x33,
+  0x30,  0x00,  0xC2,  0x88,  0x7C,  0x95,  0x20,  0x84,  0x60,  0x96,  0x20,  0x84,  0x1D,  0x01,  0x06,  0xCC,
+  0x00,  0x33,  0x00,  0x84,  0xC0,  0x20,  0x00,  0x23,  0xEA,  0x00,  0x81,  0x62,  0xA2,  0x0D,  0x80,  0x63,
+  0x07,  0xA6,  0x5A,  0x04,  0x00,  0x33,  0x18,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0xA3,  0x01,
+  0x07,  0xA4,  0x64,  0x04,  0x23,  0x01,  0x00,  0xA2,  0x86,  0x04,  0x0A,  0xA0,  0x76,  0x04,  0xE0,  0x00,
+  0x00,  0x33,  0x1D,  0x00,  0xC2,  0x88,  0x0B,  0xA0,  0x82,  0x04,  0xE0,  0x00,  0x00,  0x33,  0x1E,  0x00,
+  0xC2,  0x88,  0x42,  0x23,  0xF8,  0x88,  0x00,  0x23,  0x22,  0xA3,  0xE6,  0x04,  0x08,  0x23,  0x22,  0xA3,
+  0xA2,  0x04,  0x28,  0x23,  0x22,  0xA3,  0xAE,  0x04,  0x02,  0x23,  0x22,  0xA3,  0xC4,  0x04,  0x42,  0x23,
+  0xF8,  0x88,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA0,  0xAE,  0x04,  0x45,  0x23,  0xF8,  0x88,  0x04,  0x98,
+  0x00,  0xA2,  0xC0,  0x04,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x82,  0xC0,  0x20,  0x81,  0x62,  0xE8,  0x81,
+  0x47,  0x23,  0xF8,  0x88,  0x04,  0x01,  0x0B,  0xDE,  0x04,  0x98,  0xB4,  0x98,  0x00,  0x33,  0x00,  0x81,
+  0xC0,  0x20,  0x81,  0x62,  0x14,  0x01,  0x00,  0xA0,  0x00,  0x02,  0x43,  0x23,  0xF8,  0x88,  0x04,  0x23,
+  0xA0,  0x01,  0x44,  0x23,  0xA1,  0x01,  0x80,  0x73,  0x4D,  0x00,  0x03,  0xA3,  0xF4,  0x04,  0x00,  0x33,
+  0x27,  0x00,  0xC2,  0x88,  0x04,  0x01,  0x04,  0xDC,  0x02,  0x23,  0xA2,  0x01,  0x04,  0x23,  0xA0,  0x01,
+  0x04,  0x98,  0x26,  0x95,  0x4B,  0x00,  0xF6,  0x00,  0x4F,  0x04,  0x4F,  0x00,  0x00,  0xA3,  0x22,  0x05,
+  0x00,  0x05,  0x76,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x1C,  0x05,  0x0A,  0x85,  0x46,  0x97,  0xCD,  0x04,
+  0x24,  0x85,  0x48,  0x04,  0x84,  0x80,  0x02,  0x01,  0x03,  0xDA,  0x80,  0x23,  0x82,  0x01,  0x34,  0x85,
+  0x02,  0x23,  0xA0,  0x01,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0x40,  0x05,  0x1D,  0x01,  0x04,  0xD6,
+  0xFF,  0x23,  0x86,  0x41,  0x4B,  0x60,  0xCB,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x49,  0x00,  0x81,  0x01,
+  0x04,  0x01,  0x02,  0xC8,  0x30,  0x01,  0x80,  0x01,  0xF7,  0x04,  0x03,  0x01,  0x49,  0x04,  0x80,  0x01,
+  0xC9,  0x00,  0x00,  0x05,  0x00,  0x01,  0xFF,  0xA0,  0x60,  0x05,  0x77,  0x04,  0x01,  0x23,  0xEA,  0x00,
+  0x5D,  0x00,  0xFE,  0xC7,  0x00,  0x62,  0x00,  0x23,  0xEA,  0x00,  0x00,  0x63,  0x07,  0xA4,  0xF8,  0x05,
+  0x03,  0x03,  0x02,  0xA0,  0x8E,  0x05,  0xF4,  0x85,  0x00,  0x33,  0x2D,  0x00,  0xC2,  0x88,  0x04,  0xA0,
+  0xB8,  0x05,  0x80,  0x63,  0x00,  0x23,  0xDF,  0x00,  0x4A,  0x00,  0x06,  0x61,  0x00,  0xA2,  0xA4,  0x05,
+  0x1D,  0x01,  0x06,  0xD6,  0x02,  0x23,  0x02,  0x41,  0x82,  0x01,  0x50,  0x00,  0x62,  0x97,  0x04,  0x85,
+  0x04,  0x23,  0x02,  0x41,  0x82,  0x01,  0x04,  0x85,  0x08,  0xA0,  0xBE,  0x05,  0xF4,  0x85,  0x03,  0xA0,
+  0xC4,  0x05,  0xF4,  0x85,  0x01,  0xA0,  0xCE,  0x05,  0x88,  0x00,  0x80,  0x63,  0xCC,  0x86,  0x07,  0xA0,
+  0xEE,  0x05,  0x5F,  0x00,  0x00,  0x2B,  0xDF,  0x08,  0x00,  0xA2,  0xE6,  0x05,  0x80,  0x67,  0x80,  0x63,
+  0x01,  0xA2,  0x7A,  0x06,  0x7C,  0x85,  0x06,  0x23,  0x68,  0x98,  0x48,  0x23,  0xF8,  0x88,  0x07,  0x23,
+  0x80,  0x00,  0x06,  0x87,  0x80,  0x63,  0x7C,  0x85,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x4A,  0x00,
+  0x06,  0x61,  0x00,  0xA2,  0x36,  0x06,  0x1D,  0x01,  0x16,  0xD4,  0xC0,  0x23,  0x07,  0x41,  0x83,  0x03,
+  0x80,  0x63,  0x06,  0xA6,  0x1C,  0x06,  0x00,  0x33,  0x37,  0x00,  0xC2,  0x88,  0x1D,  0x01,  0x01,  0xD6,
+  0x20,  0x23,  0x63,  0x60,  0x83,  0x03,  0x80,  0x63,  0x02,  0x23,  0xDF,  0x00,  0x07,  0xA6,  0x7C,  0x05,
+  0xEF,  0x04,  0x6F,  0x00,  0x00,  0x63,  0x4B,  0x00,  0x06,  0x41,  0xCB,  0x00,  0x52,  0x00,  0x06,  0x61,
+  0x00,  0xA2,  0x4E,  0x06,  0x1D,  0x01,  0x03,  0xCA,  0xC0,  0x23,  0x07,  0x41,  0x00,  0x63,  0x1D,  0x01,
+  0x04,  0xCC,  0x00,  0x33,  0x00,  0x83,  0xC0,  0x20,  0x81,  0x62,  0x80,  0x23,  0x07,  0x41,  0x00,  0x63,
+  0x80,  0x67,  0x08,  0x23,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x01,  0x23,  0xDF,  0x00,  0x06,  0xA6,
+  0x84,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x80,  0x63,  0x00,  0x33,  0x00,  0x40,  0xC0,  0x20,
+  0x81,  0x62,  0x00,  0x63,  0x00,  0x00,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,  0x94,  0x06,
+  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x00,  0x01,  0xA0,  0x14,  0x07,  0x00,  0x2B,  0x40,  0x0E,  0x80,  0x63,
+  0x01,  0x00,  0x06,  0xA6,  0xAA,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x40,  0x0E,  0x80,  0x63,  0x00,  0x43,
+  0x00,  0xA0,  0xA2,  0x06,  0x06,  0xA6,  0xBC,  0x06,  0x07,  0xA6,  0x7C,  0x05,  0x80,  0x67,  0x40,  0x0E,
+  0x80,  0x63,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x23,  0xDF,  0x00,  0x00,  0x63,  0x07,  0xA6,  0xD6,  0x06,
+  0x00,  0x33,  0x2A,  0x00,  0xC2,  0x88,  0x03,  0x03,  0x80,  0x63,  0x89,  0x00,  0x0A,  0x2B,  0x07,  0xA6,
+  0xE8,  0x06,  0x00,  0x33,  0x29,  0x00,  0xC2,  0x88,  0x00,  0x43,  0x00,  0xA2,  0xF4,  0x06,  0xC0,  0x0E,
+  0x80,  0x63,  0xDE,  0x86,  0xC0,  0x0E,  0x00,  0x33,  0x00,  0x80,  0xC0,  0x20,  0x81,  0x62,  0x04,  0x01,
+  0x02,  0xDA,  0x80,  0x63,  0x7C,  0x85,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x8C,  0x06,  0x00,  0x33,
+  0x2C,  0x00,  0xC2,  0x88,  0x0C,  0xA2,  0x2E,  0x07,  0xFE,  0x95,  0x83,  0x03,  0x80,  0x63,  0x06,  0xA6,
+  0x2C,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0x00,  0x33,  0x3D,  0x00,  0xC2,  0x88,  0x00,  0x00,  0x80,  0x67,
+  0x83,  0x03,  0x80,  0x63,  0x0C,  0xA0,  0x44,  0x07,  0x07,  0xA6,  0x7C,  0x05,  0xBF,  0x23,  0x04,  0x61,
+  0x84,  0x01,  0xE6,  0x84,  0x00,  0x63,  0xF0,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x00,  0x01,  0xF2,  0x00,
+  0x01,  0x05,  0x80,  0x01,  0x72,  0x04,  0x71,  0x00,  0x81,  0x01,  0x70,  0x04,  0x80,  0x05,  0x81,  0x05,
+  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x01,  0x01,  0xF1,  0x00,  0x70,  0x00,  0x81,  0x01,
+  0x70,  0x04,  0x71,  0x00,  0x81,  0x01,  0x72,  0x00,  0x80,  0x01,  0x71,  0x04,  0x70,  0x00,  0x80,  0x01,
+  0x70,  0x04,  0x00,  0x63,  0xF0,  0x04,  0xF2,  0x00,  0x72,  0x04,  0x00,  0x01,  0xF1,  0x00,  0x70,  0x00,
+  0x80,  0x01,  0x70,  0x04,  0x71,  0x00,  0x80,  0x01,  0x72,  0x00,  0x81,  0x01,  0x71,  0x04,  0x70,  0x00,
+  0x81,  0x01,  0x70,  0x04,  0x00,  0x63,  0x00,  0x23,  0xB3,  0x01,  0x83,  0x05,  0xA3,  0x01,  0xA2,  0x01,
+  0xA1,  0x01,  0x01,  0x23,  0xA0,  0x01,  0x00,  0x01,  0xC8,  0x00,  0x03,  0xA1,  0xC4,  0x07,  0x00,  0x33,
+  0x07,  0x00,  0xC2,  0x88,  0x80,  0x05,  0x81,  0x05,  0x04,  0x01,  0x11,  0xC8,  0x48,  0x00,  0xB0,  0x01,
+  0xB1,  0x01,  0x08,  0x23,  0xB2,  0x01,  0x05,  0x01,  0x48,  0x04,  0x00,  0x43,  0x00,  0xA2,  0xE4,  0x07,
+  0x00,  0x05,  0xDA,  0x87,  0x00,  0x01,  0xC8,  0x00,  0xFF,  0x23,  0x80,  0x01,  0x05,  0x05,  0x00,  0x63,
+  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x80,  0x43,  0x76,  0x08,  0x80,  0x02,
+  0x77,  0x04,  0x00,  0x63,  0xF7,  0x04,  0x1A,  0x09,  0xF6,  0x08,  0x6E,  0x04,  0x00,  0x02,  0x00,  0xA0,
+  0x14,  0x08,  0x16,  0x88,  0x00,  0x43,  0x76,  0x08,  0x80,  0x02,  0x77,  0x04,  0x00,  0x63,  0xF3,  0x04,
+  0x00,  0x23,  0xF4,  0x00,  0x74,  0x00,  0x80,  0x43,  0xF4,  0x00,  0xCF,  0x40,  0x00,  0xA2,  0x44,  0x08,
+  0x74,  0x04,  0x02,  0x01,  0xF7,  0xC9,  0xF6,  0xD9,  0x00,  0x01,  0x01,  0xA1,  0x24,  0x08,  0x04,  0x98,
+  0x26,  0x95,  0x24,  0x88,  0x73,  0x04,  0x00,  0x63,  0xF3,  0x04,  0x75,  0x04,  0x5A,  0x88,  0x02,  0x01,
+  0x04,  0xD8,  0x46,  0x97,  0x04,  0x98,  0x26,  0x95,  0x4A,  0x88,  0x75,  0x00,  0x00,  0xA3,  0x64,  0x08,
+  0x00,  0x05,  0x4E,  0x88,  0x73,  0x04,  0x00,  0x63,  0x80,  0x7B,  0x80,  0x63,  0x06,  0xA6,  0x76,  0x08,
+  0x00,  0x33,  0x3E,  0x00,  0xC2,  0x88,  0x80,  0x67,  0x83,  0x03,  0x80,  0x63,  0x00,  0x63,  0x38,  0x2B,
+  0x9C,  0x88,  0x38,  0x2B,  0x92,  0x88,  0x32,  0x09,  0x31,  0x05,  0x92,  0x98,  0x05,  0x05,  0xB2,  0x09,
+  0x00,  0x63,  0x00,  0x32,  0x00,  0x36,  0x00,  0x3A,  0x00,  0x3E,  0x00,  0x63,  0x80,  0x32,  0x80,  0x36,
+  0x80,  0x3A,  0x80,  0x3E,  0xB4,  0x3D,  0x00,  0x63,  0x38,  0x2B,  0x40,  0x32,  0x40,  0x36,  0x40,  0x3A,
+  0x40,  0x3E,  0x00,  0x63,  0x5A,  0x20,  0xC9,  0x40,  0x00,  0xA0,  0xB4,  0x08,  0x5D,  0x00,  0xFE,  0xC3,
+  0x00,  0x63,  0x80,  0x73,  0xE6,  0x20,  0x02,  0x23,  0xE8,  0x00,  0x82,  0x73,  0xFF,  0xFD,  0x80,  0x73,
+  0x13,  0x23,  0xF8,  0x88,  0x66,  0x20,  0xC0,  0x20,  0x04,  0x23,  0xA0,  0x01,  0xA1,  0x23,  0xA1,  0x01,
+  0x81,  0x62,  0xE2,  0x88,  0x80,  0x73,  0x80,  0x77,  0x68,  0x00,  0x00,  0xA2,  0x80,  0x00,  0x03,  0xC2,
+  0xF1,  0xC7,  0x41,  0x23,  0xF8,  0x88,  0x11,  0x23,  0xA1,  0x01,  0x04,  0x23,  0xA0,  0x01,  0xE6,  0x84,
+};
+
+STATIC ushort _asc_mcode_size = sizeof(_asc_mcode_buf);
+STATIC ADV_DCNT _asc_mcode_chksum = 0x012C453FUL;
+
+#define ASC_SYN_OFFSET_ONE_DISABLE_LIST  16
+STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
+{
+    INQUIRY,
+    REQUEST_SENSE,
+    READ_CAPACITY,
+    READ_TOC,
+    MODE_SELECT,
+    MODE_SENSE,
+    MODE_SELECT_10,
+    MODE_SENSE_10,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF,
+    0xFF
+};
+
+STATIC int
+AscExeScsiQueue(
+                   ASC_DVC_VAR *asc_dvc,
+                   ASC_SCSI_Q *scsiq
+)
+{
+    PortAddr            iop_base;
+    ulong               last_int_level;
+    int                 sta;
+    int                 n_q_required;
+    int                 disable_syn_offset_one_fix;
+    int                 i;
+    ASC_PADDR           addr;
+    ASC_EXE_CALLBACK    asc_exe_callback;
+    ushort              sg_entry_cnt = 0;
+    ushort              sg_entry_cnt_minus_one = 0;
+    uchar               target_ix;
+    uchar               tid_no;
+    uchar               sdtr_data;
+    uchar               extra_bytes;
+    uchar               scsi_cmd;
+    uchar               disable_cmd;
+    ASC_SG_HEAD         *sg_head;
+    ASC_DCNT            data_cnt;
+
+    iop_base = asc_dvc->iop_base;
+    sg_head = scsiq->sg_head;
+    asc_exe_callback = asc_dvc->exe_callback;
+    if (asc_dvc->err_code != 0)
+        return (ERR);
+    if (scsiq == (ASC_SCSI_Q *) 0L) {
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SCSIQ_NULL_PTR);
+        return (ERR);
+    }
+    scsiq->q1.q_no = 0;
+    if ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES) == 0) {
+        scsiq->q1.extra_bytes = 0;
+    }
+    sta = 0;
+    target_ix = scsiq->q2.target_ix;
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    n_q_required = 1;
+    if (scsiq->cdbptr[0] == REQUEST_SENSE) {
+        if ((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) {
+            asc_dvc->sdtr_done &= ~scsiq->q1.target_id;
+            sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+            AscMsgOutSDTR(asc_dvc,
+                          asc_dvc->sdtr_period_tbl[(sdtr_data >> 4) &
+                          (uchar) (asc_dvc->max_sdtr_index - 1)],
+                          (uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
+            scsiq->q1.cntl |= (QC_MSG_OUT | QC_URGENT);
+        }
+    }
+    last_int_level = DvcEnterCritical();
+    if (asc_dvc->in_critical_cnt != 0) {
+        DvcLeaveCritical(last_int_level);
+        AscSetLibErrorCode(asc_dvc, ASCQ_ERR_CRITICAL_RE_ENTRY);
+        return (ERR);
+    }
+    asc_dvc->in_critical_cnt++;
+    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+        if ((sg_entry_cnt = sg_head->entry_cnt) == 0) {
+            asc_dvc->in_critical_cnt--;
+            DvcLeaveCritical(last_int_level);
+            return (ERR);
+        }
+#if !CC_VERY_LONG_SG_LIST
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+            asc_dvc->in_critical_cnt--;
+            DvcLeaveCritical(last_int_level);
+            return(ERR);
+        }
+#endif /* !CC_VERY_LONG_SG_LIST */
+        if (sg_entry_cnt == 1) {
+            scsiq->q1.data_addr = (ADV_PADDR) sg_head->sg_list[0].addr;
+            scsiq->q1.data_cnt = (ADV_DCNT) sg_head->sg_list[0].bytes;
+            scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
+        }
+        sg_entry_cnt_minus_one = sg_entry_cnt - 1;
+    }
+    scsi_cmd = scsiq->cdbptr[0];
+    disable_syn_offset_one_fix = FALSE;
+    if ((asc_dvc->pci_fix_asyn_xfer & scsiq->q1.target_id) &&
+        !(asc_dvc->pci_fix_asyn_xfer_always & scsiq->q1.target_id)) {
+        if (scsiq->q1.cntl & QC_SG_HEAD) {
+            data_cnt = 0;
+            for (i = 0; i < sg_entry_cnt; i++) {
+                data_cnt += (ADV_DCNT) le32_to_cpu(sg_head->sg_list[i].bytes);
+            }
+        } else {
+            data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+        }
+        if (data_cnt != 0UL) {
+            if (data_cnt < 512UL) {
+                disable_syn_offset_one_fix = TRUE;
+            } else {
+                for (i = 0; i < ASC_SYN_OFFSET_ONE_DISABLE_LIST; i++) {
+                    disable_cmd = _syn_offset_one_disable_cmd[i];
+                    if (disable_cmd == 0xFF) {
+                        break;
+                    }
+                    if (scsi_cmd == disable_cmd) {
+                        disable_syn_offset_one_fix = TRUE;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    if (disable_syn_offset_one_fix) {
+        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG;
+        scsiq->q2.tag_code |= (ASC_TAG_FLAG_DISABLE_ASYN_USE_SYN_FIX |
+                               ASC_TAG_FLAG_DISABLE_DISCONNECT);
+    } else {
+        scsiq->q2.tag_code &= 0x27;
+    }
+    if ((scsiq->q1.cntl & QC_SG_HEAD) != 0) {
+        if (asc_dvc->bug_fix_cntl) {
+            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                if ((scsi_cmd == READ_6) ||
+                    (scsi_cmd == READ_10)) {
+                    addr =
+                        (ADV_PADDR) le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].addr) +
+                        (ADV_DCNT) le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
+                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
+                    if ((extra_bytes != 0) &&
+                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
+                         == 0)) {
+                        scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
+                        scsiq->q1.extra_bytes = extra_bytes;
+                        data_cnt = le32_to_cpu(
+                            sg_head->sg_list[sg_entry_cnt_minus_one].bytes);
+                        data_cnt -= (ASC_DCNT) extra_bytes;
+                        sg_head->sg_list[sg_entry_cnt_minus_one].bytes =
+                            cpu_to_le32(data_cnt);
+                    }
+                }
+            }
+        }
+        sg_head->entry_to_copy = sg_head->entry_cnt;
+#if CC_VERY_LONG_SG_LIST
+        /*
+         * Set the sg_entry_cnt to the maximum possible. The rest of
+         * the SG elements will be copied when the RISC completes the
+         * SG elements that fit and halts.
+         */
+        if (sg_entry_cnt > ASC_MAX_SG_LIST)
+        {
+             sg_entry_cnt = ASC_MAX_SG_LIST;
+        }
+#endif /* CC_VERY_LONG_SG_LIST */
+        n_q_required = AscSgListToQueue(sg_entry_cnt);
+        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, n_q_required) >=
+            (uint) n_q_required) || ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+                                        n_q_required)) == 1) {
+                asc_dvc->in_critical_cnt--;
+                if (asc_exe_callback != 0) {
+                    (*asc_exe_callback) (asc_dvc, scsiq);
+                }
+                DvcLeaveCritical(last_int_level);
+                return (sta);
+            }
+        }
+    } else {
+        if (asc_dvc->bug_fix_cntl) {
+            if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_IF_NOT_DWB) {
+                if ((scsi_cmd == READ_6) ||
+                    (scsi_cmd == READ_10)) {
+                    addr = le32_to_cpu(scsiq->q1.data_addr) +
+                        le32_to_cpu(scsiq->q1.data_cnt);
+                    extra_bytes = (uchar) ((ushort) addr & 0x0003);
+                    if ((extra_bytes != 0) &&
+                        ((scsiq->q2.tag_code & ASC_TAG_FLAG_EXTRA_BYTES)
+                          == 0)) {
+                        data_cnt = le32_to_cpu(scsiq->q1.data_cnt);
+                        if (((ushort) data_cnt & 0x01FF) == 0) {
+                            scsiq->q2.tag_code |= ASC_TAG_FLAG_EXTRA_BYTES;
+                            data_cnt -= (ASC_DCNT) extra_bytes;
+                            scsiq->q1.data_cnt = cpu_to_le32(data_cnt);
+                            scsiq->q1.extra_bytes = extra_bytes;
+                        }
+                    }
+                }
+            }
+        }
+        n_q_required = 1;
+        if ((AscGetNumOfFreeQueue(asc_dvc, target_ix, 1) >= 1) ||
+            ((scsiq->q1.cntl & QC_URGENT) != 0)) {
+            if ((sta = AscSendScsiQueue(asc_dvc, scsiq,
+                                        n_q_required)) == 1) {
+                asc_dvc->in_critical_cnt--;
+                if (asc_exe_callback != 0) {
+                    (*asc_exe_callback) (asc_dvc, scsiq);
+                }
+                DvcLeaveCritical(last_int_level);
+                return (sta);
+            }
+        }
+    }
+    asc_dvc->in_critical_cnt--;
+    DvcLeaveCritical(last_int_level);
+    return (sta);
+}
+
+STATIC int
+AscSendScsiQueue(
+                    ASC_DVC_VAR *asc_dvc,
+                    ASC_SCSI_Q *scsiq,
+                    uchar n_q_required
+)
+{
+    PortAddr            iop_base;
+    uchar               free_q_head;
+    uchar               next_qp;
+    uchar               tid_no;
+    uchar               target_ix;
+    int                 sta;
+
+    iop_base = asc_dvc->iop_base;
+    target_ix = scsiq->q2.target_ix;
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    sta = 0;
+    free_q_head = (uchar) AscGetVarFreeQHead(iop_base);
+    if (n_q_required > 1) {
+        if ((next_qp = AscAllocMultipleFreeQueue(iop_base,
+                                       free_q_head, (uchar) (n_q_required)))
+            != (uchar) ASC_QLINK_END) {
+            asc_dvc->last_q_shortage = 0;
+            scsiq->sg_head->queue_cnt = n_q_required - 1;
+            scsiq->q1.q_no = free_q_head;
+            if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
+                                              free_q_head)) == 1) {
+                AscPutVarFreeQHead(iop_base, next_qp);
+                asc_dvc->cur_total_qng += (uchar) (n_q_required);
+                asc_dvc->cur_dvc_qng[tid_no]++;
+            }
+            return (sta);
+        }
+    } else if (n_q_required == 1) {
+        if ((next_qp = AscAllocFreeQueue(iop_base,
+                                         free_q_head)) != ASC_QLINK_END) {
+            scsiq->q1.q_no = free_q_head;
+            if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
+                                        free_q_head)) == 1) {
+                AscPutVarFreeQHead(iop_base, next_qp);
+                asc_dvc->cur_total_qng++;
+                asc_dvc->cur_dvc_qng[tid_no]++;
+            }
+            return (sta);
+        }
+    }
+    return (sta);
+}
+
+STATIC int
+AscSgListToQueue(
+                    int sg_list
+)
+{
+    int                 n_sg_list_qs;
+
+    n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
+    if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
+        n_sg_list_qs++;
+    return (n_sg_list_qs + 1);
+}
+
+
+STATIC uint
+AscGetNumOfFreeQueue(
+                        ASC_DVC_VAR *asc_dvc,
+                        uchar target_ix,
+                        uchar n_qs
+)
+{
+    uint                cur_used_qs;
+    uint                cur_free_qs;
+    ASC_SCSI_BIT_ID_TYPE target_id;
+    uchar               tid_no;
+
+    target_id = ASC_TIX_TO_TARGET_ID(target_ix);
+    tid_no = ASC_TIX_TO_TID(target_ix);
+    if ((asc_dvc->unit_not_ready & target_id) ||
+        (asc_dvc->queue_full_or_busy & target_id)) {
+        return (0);
+    }
+    if (n_qs == 1) {
+        cur_used_qs = (uint) asc_dvc->cur_total_qng +
+          (uint) asc_dvc->last_q_shortage +
+          (uint) ASC_MIN_FREE_Q;
+    } else {
+        cur_used_qs = (uint) asc_dvc->cur_total_qng +
+          (uint) ASC_MIN_FREE_Q;
+    }
+    if ((uint) (cur_used_qs + n_qs) <= (uint) asc_dvc->max_total_qng) {
+        cur_free_qs = (uint) asc_dvc->max_total_qng - cur_used_qs;
+        if (asc_dvc->cur_dvc_qng[tid_no] >=
+            asc_dvc->max_dvc_qng[tid_no]) {
+            return (0);
+        }
+        return (cur_free_qs);
+    }
+    if (n_qs > 1) {
+        if ((n_qs > asc_dvc->last_q_shortage) && (n_qs <= (asc_dvc->max_total_qng - ASC_MIN_FREE_Q))) {
+            asc_dvc->last_q_shortage = n_qs;
+        }
+    }
+    return (0);
+}
+
+STATIC int
+AscPutReadyQueue(
+                    ASC_DVC_VAR *asc_dvc,
+                    ASC_SCSI_Q *scsiq,
+                    uchar q_no
+)
+{
+    ushort              q_addr;
+    uchar               tid_no;
+    uchar               sdtr_data;
+    uchar               syn_period_ix;
+    uchar               syn_offset;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
+        ((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
+        tid_no = ASC_TIX_TO_TID(scsiq->q2.target_ix);
+        sdtr_data = AscGetMCodeInitSDTRAtID(iop_base, tid_no);
+        syn_period_ix = (sdtr_data >> 4) & (asc_dvc->max_sdtr_index - 1);
+        syn_offset = sdtr_data & ASC_SYN_MAX_OFFSET;
+        AscMsgOutSDTR(asc_dvc,
+                      asc_dvc->sdtr_period_tbl[syn_period_ix],
+                      syn_offset);
+        scsiq->q1.cntl |= QC_MSG_OUT;
+    }
+    q_addr = ASC_QNO_TO_QADDR(q_no);
+    if ((scsiq->q1.target_id & asc_dvc->use_tagged_qng) == 0) {
+        scsiq->q2.tag_code &= ~MSG_SIMPLE_TAG ;
+    }
+    scsiq->q1.status = QS_FREE;
+    AscMemWordCopyPtrToLram(iop_base,
+                         q_addr + ASC_SCSIQ_CDB_BEG,
+                         (uchar *) scsiq->cdbptr,
+                         scsiq->q2.cdb_len >> 1);
+
+    DvcPutScsiQ(iop_base,
+                q_addr + ASC_SCSIQ_CPY_BEG,
+                (uchar *) &scsiq->q1.cntl,
+                ((sizeof(ASC_SCSIQ_1) + sizeof(ASC_SCSIQ_2)) / 2) - 1);
+    AscWriteLramWord(iop_base,
+                     (ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
+             (ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
+    return (1);
+}
+
+STATIC int
+AscPutReadySgListQueue(
+                          ASC_DVC_VAR *asc_dvc,
+                          ASC_SCSI_Q *scsiq,
+                          uchar q_no
+)
+{
+    int                 sta;
+    int                 i;
+    ASC_SG_HEAD *sg_head;
+    ASC_SG_LIST_Q       scsi_sg_q;
+    ASC_DCNT            saved_data_addr;
+    ASC_DCNT            saved_data_cnt;
+    PortAddr            iop_base;
+    ushort              sg_list_dwords;
+    ushort              sg_index;
+    ushort              sg_entry_cnt;
+    ushort              q_addr;
+    uchar               next_qp;
+
+    iop_base = asc_dvc->iop_base;
+    sg_head = scsiq->sg_head;
+    saved_data_addr = scsiq->q1.data_addr;
+    saved_data_cnt = scsiq->q1.data_cnt;
+    scsiq->q1.data_addr = (ASC_PADDR) sg_head->sg_list[0].addr;
+    scsiq->q1.data_cnt = (ASC_DCNT) sg_head->sg_list[0].bytes;
+#if CC_VERY_LONG_SG_LIST
+    /*
+     * If sg_head->entry_cnt is greater than ASC_MAX_SG_LIST
+     * then not all SG elements will fit in the allocated queues.
+     * The rest of the SG elements will be copied when the RISC
+     * completes the SG elements that fit and halts.
+     */
+    if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+    {
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. It is minus 1, because
+          * the first SG element is handled above. ASC_MAX_SG_LIST is
+          * already inflated by 1 to account for this. For example it
+          * may be 50 which is 1 + 7 queues * 7 SG elements.
+          */
+         sg_entry_cnt = ASC_MAX_SG_LIST - 1;
+
+         /*
+          * Keep track of remaining number of SG elements that will
+          * need to be handled from a_isr.c.
+          */
+         scsiq->remain_sg_entry_cnt = sg_head->entry_cnt - ASC_MAX_SG_LIST;
+    } else
+    {
+#endif /* CC_VERY_LONG_SG_LIST */
+         /*
+          * Set sg_entry_cnt to be the number of SG elements that
+          * will fit in the allocated SG queues. It is minus 1, because
+          * the first SG element is handled above.
+          */
+         sg_entry_cnt = sg_head->entry_cnt - 1;
+#if CC_VERY_LONG_SG_LIST
+    }
+#endif /* CC_VERY_LONG_SG_LIST */
+    if (sg_entry_cnt != 0) {
+        scsiq->q1.cntl |= QC_SG_HEAD;
+        q_addr = ASC_QNO_TO_QADDR(q_no);
+        sg_index = 1;
+        scsiq->q1.sg_queue_cnt = sg_head->queue_cnt;
+        scsi_sg_q.sg_head_qp = q_no;
+        scsi_sg_q.cntl = QCSG_SG_XFER_LIST;
+        for (i = 0; i < sg_head->queue_cnt; i++) {
+            scsi_sg_q.seq_no = i + 1;
+            if (sg_entry_cnt > ASC_SG_LIST_PER_Q) {
+                sg_list_dwords = (uchar) (ASC_SG_LIST_PER_Q * 2);
+                sg_entry_cnt -= ASC_SG_LIST_PER_Q;
+                if (i == 0) {
+                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q;
+                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q;
+                } else {
+                    scsi_sg_q.sg_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                    scsi_sg_q.sg_cur_list_cnt = ASC_SG_LIST_PER_Q - 1;
+                }
+            } else {
+#if CC_VERY_LONG_SG_LIST
+                /*
+                 * This is the last SG queue in the list of
+                 * allocated SG queues. If there are more
+                 * SG elements than will fit in the allocated
+                 * queues, then set the QCSG_SG_XFER_MORE flag.
+                 */
+                if (sg_head->entry_cnt > ASC_MAX_SG_LIST)
+                {
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_MORE;
+                } else
+                {
+#endif /* CC_VERY_LONG_SG_LIST */
+                    scsi_sg_q.cntl |= QCSG_SG_XFER_END;
+#if CC_VERY_LONG_SG_LIST
+                }
+#endif /* CC_VERY_LONG_SG_LIST */
+                sg_list_dwords = sg_entry_cnt << 1;
+                if (i == 0) {
+                    scsi_sg_q.sg_list_cnt = sg_entry_cnt;
+                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt;
+                } else {
+                    scsi_sg_q.sg_list_cnt = sg_entry_cnt - 1;
+                    scsi_sg_q.sg_cur_list_cnt = sg_entry_cnt - 1;
+                }
+                sg_entry_cnt = 0;
+            }
+            next_qp = AscReadLramByte(iop_base,
+                                      (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+            scsi_sg_q.q_no = next_qp;
+            q_addr = ASC_QNO_TO_QADDR(next_qp);
+            AscMemWordCopyPtrToLram(iop_base,
+                                q_addr + ASC_SCSIQ_SGHD_CPY_BEG,
+                                (uchar *) &scsi_sg_q,
+                                sizeof(ASC_SG_LIST_Q) >> 1);
+            AscMemDWordCopyPtrToLram(iop_base,
+                                q_addr + ASC_SGQ_LIST_BEG,
+                                (uchar *) &sg_head->sg_list[sg_index],
+                                sg_list_dwords);
+            sg_index += ASC_SG_LIST_PER_Q;
+            scsiq->next_sg_index = sg_index;
+        }
+    } else {
+        scsiq->q1.cntl &= ~QC_SG_HEAD;
+    }
+    sta = AscPutReadyQueue(asc_dvc, scsiq, q_no);
+    scsiq->q1.data_addr = saved_data_addr;
+    scsiq->q1.data_cnt = saved_data_cnt;
+    return (sta);
+}
+
+STATIC int
+AscSetRunChipSynRegAtID(
+                           PortAddr iop_base,
+                           uchar tid_no,
+                           uchar sdtr_data
+)
+{
+    int                 sta = FALSE;
+
+    if (AscHostReqRiscHalt(iop_base)) {
+        sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+        AscStartChip(iop_base);
+        return (sta);
+    }
+    return (sta);
+}
+
+STATIC int
+AscSetChipSynRegAtID(
+                        PortAddr iop_base,
+                        uchar id,
+                        uchar sdtr_data
+)
+{
+    ASC_SCSI_BIT_ID_TYPE org_id;
+    int                 i;
+    int                 sta = TRUE;
+
+    AscSetBank(iop_base, 1);
+    org_id = AscReadChipDvcID(iop_base);
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        if (org_id == (0x01 << i))
+            break;
+    }
+    org_id = (ASC_SCSI_BIT_ID_TYPE) i;
+    AscWriteChipDvcID(iop_base, id);
+    if (AscReadChipDvcID(iop_base) == (0x01 << id)) {
+        AscSetBank(iop_base, 0);
+        AscSetChipSyn(iop_base, sdtr_data);
+        if (AscGetChipSyn(iop_base) != sdtr_data) {
+            sta = FALSE;
+        }
+    } else {
+        sta = FALSE;
+    }
+    AscSetBank(iop_base, 1);
+    AscWriteChipDvcID(iop_base, org_id);
+    AscSetBank(iop_base, 0);
+    return (sta);
+}
+
+STATIC ushort
+AscInitLram(
+               ASC_DVC_VAR *asc_dvc
+)
+{
+    uchar               i;
+    ushort              s_addr;
+    PortAddr            iop_base;
+    ushort              warn_code;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
+               (ushort) (((int) (asc_dvc->max_total_qng + 2 + 1) * 64) >> 1)
+);
+    i = ASC_MIN_ACTIVE_QNO;
+    s_addr = ASC_QADR_BEG + ASC_QBLK_SIZE;
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                     (uchar) (i + 1));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                     (uchar) (asc_dvc->max_total_qng));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                     (uchar) i);
+    i++;
+    s_addr += ASC_QBLK_SIZE;
+    for (; i < asc_dvc->max_total_qng; i++, s_addr += ASC_QBLK_SIZE) {
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                         (uchar) (i + 1));
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                         (uchar) (i - 1));
+        AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                         (uchar) i);
+    }
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_FWD),
+                     (uchar) ASC_QLINK_END);
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_BWD),
+                     (uchar) (asc_dvc->max_total_qng - 1));
+    AscWriteLramByte(iop_base, (ushort) (s_addr + ASC_SCSIQ_B_QNO),
+                     (uchar) asc_dvc->max_total_qng);
+    i++;
+    s_addr += ASC_QBLK_SIZE;
+    for (; i <= (uchar) (asc_dvc->max_total_qng + 3);
+         i++, s_addr += ASC_QBLK_SIZE) {
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_FWD), i);
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_BWD), i);
+        AscWriteLramByte(iop_base,
+                         (ushort) (s_addr + (ushort) ASC_SCSIQ_B_QNO), i);
+    }
+    return (warn_code);
+}
+
+STATIC ushort
+AscInitQLinkVar(
+                   ASC_DVC_VAR *asc_dvc
+)
+{
+    PortAddr            iop_base;
+    int                 i;
+    ushort              lram_addr;
+
+    iop_base = asc_dvc->iop_base;
+    AscPutRiscVarFreeQHead(iop_base, 1);
+    AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+    AscPutVarFreeQHead(iop_base, 1);
+    AscPutVarDoneQTail(iop_base, asc_dvc->max_total_qng);
+    AscWriteLramByte(iop_base, ASCV_BUSY_QHEAD_B,
+                     (uchar) ((int) asc_dvc->max_total_qng + 1));
+    AscWriteLramByte(iop_base, ASCV_DISC1_QHEAD_B,
+                     (uchar) ((int) asc_dvc->max_total_qng + 2));
+    AscWriteLramByte(iop_base, (ushort) ASCV_TOTAL_READY_Q_B,
+                     asc_dvc->max_total_qng);
+    AscWriteLramWord(iop_base, ASCV_ASCDVC_ERR_CODE_W, 0);
+    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, 0);
+    AscWriteLramByte(iop_base, ASCV_SCSIBUSY_B, 0);
+    AscWriteLramByte(iop_base, ASCV_WTM_FLAG_B, 0);
+    AscPutQDoneInProgress(iop_base, 0);
+    lram_addr = ASC_QADR_BEG;
+    for (i = 0; i < 32; i++, lram_addr += 2) {
+        AscWriteLramWord(iop_base, lram_addr, 0);
+    }
+    return (0);
+}
+
+STATIC int
+AscSetLibErrorCode(
+                      ASC_DVC_VAR *asc_dvc,
+                      ushort err_code
+)
+{
+    if (asc_dvc->err_code == 0) {
+        asc_dvc->err_code = err_code;
+        AscWriteLramWord(asc_dvc->iop_base, ASCV_ASCDVC_ERR_CODE_W,
+                         err_code);
+    }
+    return (err_code);
+}
+
+
+STATIC uchar
+AscMsgOutSDTR(
+                 ASC_DVC_VAR *asc_dvc,
+                 uchar sdtr_period,
+                 uchar sdtr_offset
+)
+{
+    EXT_MSG             sdtr_buf;
+    uchar               sdtr_period_index;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    sdtr_buf.msg_type = MS_EXTEND;
+    sdtr_buf.msg_len = MS_SDTR_LEN;
+    sdtr_buf.msg_req = MS_SDTR_CODE;
+    sdtr_buf.xfer_period = sdtr_period;
+    sdtr_offset &= ASC_SYN_MAX_OFFSET;
+    sdtr_buf.req_ack_offset = sdtr_offset;
+    if ((sdtr_period_index =
+         AscGetSynPeriodIndex(asc_dvc, sdtr_period)) <=
+        asc_dvc->max_sdtr_index) {
+        AscMemWordCopyPtrToLram(iop_base,
+                             ASCV_MSGOUT_BEG,
+                             (uchar *) &sdtr_buf,
+                             sizeof (EXT_MSG) >> 1);
+        return ((sdtr_period_index << 4) | sdtr_offset);
+    } else {
+
+        sdtr_buf.req_ack_offset = 0;
+        AscMemWordCopyPtrToLram(iop_base,
+                             ASCV_MSGOUT_BEG,
+                             (uchar *) &sdtr_buf,
+                             sizeof (EXT_MSG) >> 1);
+        return (0);
+    }
+}
+
+STATIC uchar
+AscCalSDTRData(
+                  ASC_DVC_VAR *asc_dvc,
+                  uchar sdtr_period,
+                  uchar syn_offset
+)
+{
+    uchar               byte;
+    uchar               sdtr_period_ix;
+
+    sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
+    if (
+           (sdtr_period_ix > asc_dvc->max_sdtr_index)
+) {
+        return (0xFF);
+    }
+    byte = (sdtr_period_ix << 4) | (syn_offset & ASC_SYN_MAX_OFFSET);
+    return (byte);
+}
+
+STATIC void
+AscSetChipSDTR(
+                  PortAddr iop_base,
+                  uchar sdtr_data,
+                  uchar tid_no
+)
+{
+    AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
+    AscPutMCodeSDTRDoneAtID(iop_base, tid_no, sdtr_data);
+    return;
+}
+
+STATIC uchar
+AscGetSynPeriodIndex(
+                        ASC_DVC_VAR *asc_dvc,
+                        uchar syn_time
+)
+{
+    uchar             *period_table;
+    int                 max_index;
+    int                 min_index;
+    int                 i;
+
+    period_table = asc_dvc->sdtr_period_tbl;
+    max_index = (int) asc_dvc->max_sdtr_index;
+    min_index = (int)asc_dvc->host_init_sdtr_index;
+    if ((syn_time <= period_table[max_index])) {
+        for (i = min_index; i < (max_index - 1); i++) {
+            if (syn_time <= period_table[i]) {
+                return ((uchar) i);
+            }
+        }
+        return ((uchar) max_index);
+    } else {
+        return ((uchar) (max_index + 1));
+    }
+}
+
+STATIC uchar
+AscAllocFreeQueue(
+                     PortAddr iop_base,
+                     uchar free_q_head
+)
+{
+    ushort              q_addr;
+    uchar               next_qp;
+    uchar               q_status;
+
+    q_addr = ASC_QNO_TO_QADDR(free_q_head);
+    q_status = (uchar) AscReadLramByte(iop_base,
+                                    (ushort) (q_addr + ASC_SCSIQ_B_STATUS));
+    next_qp = AscReadLramByte(iop_base,
+                              (ushort) (q_addr + ASC_SCSIQ_B_FWD));
+    if (((q_status & QS_READY) == 0) && (next_qp != ASC_QLINK_END)) {
+        return (next_qp);
+    }
+    return (ASC_QLINK_END);
+}
+
+STATIC uchar
+AscAllocMultipleFreeQueue(
+                             PortAddr iop_base,
+                             uchar free_q_head,
+                             uchar n_free_q
+)
+{
+    uchar               i;
+
+    for (i = 0; i < n_free_q; i++) {
+        if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
+            == ASC_QLINK_END) {
+            return (ASC_QLINK_END);
+        }
+    }
+    return (free_q_head);
+}
+
+STATIC int
+AscHostReqRiscHalt(
+                      PortAddr iop_base
+)
+{
+    int                 count = 0;
+    int                 sta = 0;
+    uchar               saved_stop_code;
+
+    if (AscIsChipHalted(iop_base))
+        return (1);
+    saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                     ASC_STOP_HOST_REQ_RISC_HALT | ASC_STOP_REQ_RISC_STOP
+);
+    do {
+        if (AscIsChipHalted(iop_base)) {
+            sta = 1;
+            break;
+        }
+        DvcSleepMilliSecond(100);
+    } while (count++ < 20);
+    AscWriteLramByte(iop_base, ASCV_STOP_CODE_B, saved_stop_code);
+    return (sta);
+}
+
+STATIC int
+AscStopQueueExe(
+                   PortAddr iop_base
+)
+{
+    int                 count = 0;
+
+    if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
+        AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
+                         ASC_STOP_REQ_RISC_STOP);
+        do {
+            if (
+                   AscReadLramByte(iop_base, ASCV_STOP_CODE_B) &
+                   ASC_STOP_ACK_RISC_STOP) {
+                return (1);
+            }
+            DvcSleepMilliSecond(100);
+        } while (count++ < 20);
+    }
+    return (0);
+}
+
+STATIC void
+DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
+{
+    udelay(micro_sec);
+}
+
+STATIC void
+DvcDelayNanoSecond(ASC_DVC_VAR *asc_dvc, ASC_DCNT nano_sec)
+{
+    udelay((nano_sec + 999)/1000);
+}
+
+#ifdef CONFIG_ISA
+STATIC ASC_DCNT __init
+AscGetEisaProductID(
+                       PortAddr iop_base)
+{
+    PortAddr            eisa_iop;
+    ushort              product_id_high, product_id_low;
+    ASC_DCNT            product_id;
+
+    eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
+    product_id_low = inpw(eisa_iop);
+    product_id_high = inpw(eisa_iop + 2);
+    product_id = ((ASC_DCNT) product_id_high << 16) |
+        (ASC_DCNT) product_id_low;
+    return (product_id);
+}
+
+STATIC PortAddr __init
+AscSearchIOPortAddrEISA(
+                           PortAddr iop_base)
+{
+    ASC_DCNT            eisa_product_id;
+
+    if (iop_base == 0) {
+        iop_base = ASC_EISA_MIN_IOP_ADDR;
+    } else {
+        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+            return (0);
+        if ((iop_base & 0x0050) == 0x0050) {
+            iop_base += ASC_EISA_BIG_IOP_GAP;
+        } else {
+            iop_base += ASC_EISA_SMALL_IOP_GAP;
+        }
+    }
+    while (iop_base <= ASC_EISA_MAX_IOP_ADDR) {
+        eisa_product_id = AscGetEisaProductID(iop_base);
+        if ((eisa_product_id == ASC_EISA_ID_740) ||
+            (eisa_product_id == ASC_EISA_ID_750)) {
+            if (AscFindSignature(iop_base)) {
+                inpw(iop_base + 4);
+                return (iop_base);
+            }
+        }
+        if (iop_base == ASC_EISA_MAX_IOP_ADDR)
+            return (0);
+        if ((iop_base & 0x0050) == 0x0050) {
+            iop_base += ASC_EISA_BIG_IOP_GAP;
+        } else {
+            iop_base += ASC_EISA_SMALL_IOP_GAP;
+        }
+    }
+    return (0);
+}
+#endif /* CONFIG_ISA */
+
+STATIC int
+AscStartChip(
+                PortAddr iop_base
+)
+{
+    AscSetChipControl(iop_base, 0);
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+        return (0);
+    }
+    return (1);
+}
+
+STATIC int
+AscStopChip(
+               PortAddr iop_base
+)
+{
+    uchar               cc_val;
+
+    cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
+    AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
+    AscSetChipIH(iop_base, INS_HALT);
+    AscSetChipIH(iop_base, INS_RFLAG_WTM);
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) == 0) {
+        return (0);
+    }
+    return (1);
+}
+
+STATIC int
+AscIsChipHalted(
+                   PortAddr iop_base
+)
+{
+    if ((AscGetChipStatus(iop_base) & CSW_HALTED) != 0) {
+        if ((AscGetChipControl(iop_base) & CC_HALT) != 0) {
+            return (1);
+        }
+    }
+    return (0);
+}
+
+STATIC void
+AscSetChipIH(
+                PortAddr iop_base,
+                ushort ins_code
+)
+{
+    AscSetBank(iop_base, 1);
+    AscWriteChipIH(iop_base, ins_code);
+    AscSetBank(iop_base, 0);
+    return;
+}
+
+STATIC void
+AscAckInterrupt(
+                   PortAddr iop_base
+)
+{
+    uchar               host_flag;
+    uchar               risc_flag;
+    ushort              loop;
+
+    loop = 0;
+    do {
+        risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
+        if (loop++ > 0x7FFF) {
+            break;
+        }
+    } while ((risc_flag & ASC_RISC_FLAG_GEN_INT) != 0);
+    host_flag = AscReadLramByte(iop_base, ASCV_HOST_FLAG_B) & (~ASC_HOST_FLAG_ACK_INT);
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
+                     (uchar) (host_flag | ASC_HOST_FLAG_ACK_INT));
+    AscSetChipStatus(iop_base, CIW_INT_ACK);
+    loop = 0;
+    while (AscGetChipStatus(iop_base) & CSW_INT_PENDING) {
+        AscSetChipStatus(iop_base, CIW_INT_ACK);
+        if (loop++ > 3) {
+            break;
+        }
+    }
+    AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
+    return;
+}
+
+STATIC void
+AscDisableInterrupt(
+                       PortAddr iop_base
+)
+{
+    ushort              cfg;
+
+    cfg = AscGetChipCfgLsw(iop_base);
+    AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
+    return;
+}
+
+STATIC void
+AscEnableInterrupt(
+                      PortAddr iop_base
+)
+{
+    ushort              cfg;
+
+    cfg = AscGetChipCfgLsw(iop_base);
+    AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
+    return;
+}
+
+
+
+STATIC void
+AscSetBank(
+              PortAddr iop_base,
+              uchar bank
+)
+{
+    uchar               val;
+
+    val = AscGetChipControl(iop_base) &
+      (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
+    if (bank == 1) {
+        val |= CC_BANK_ONE;
+    } else if (bank == 2) {
+        val |= CC_DIAG | CC_BANK_ONE;
+    } else {
+        val &= ~CC_BANK_ONE;
+    }
+    AscSetChipControl(iop_base, val);
+    return;
+}
+
+STATIC int
+AscResetChipAndScsiBus(
+                          ASC_DVC_VAR *asc_dvc
+)
+{
+    PortAddr    iop_base;
+    int         i = 10;
+
+    iop_base = asc_dvc->iop_base;
+    while ((AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) && (i-- > 0))
+    {
+          DvcSleepMilliSecond(100);
+    }
+    AscStopChip(iop_base);
+    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
+    DvcDelayNanoSecond(asc_dvc, 60000);
+    AscSetChipIH(iop_base, INS_RFLAG_WTM);
+    AscSetChipIH(iop_base, INS_HALT);
+    AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
+    AscSetChipControl(iop_base, CC_HALT);
+    DvcSleepMilliSecond(200);
+    AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
+    AscSetChipStatus(iop_base, 0);
+    return (AscIsChipHalted(iop_base));
+}
+
+STATIC ASC_DCNT __init
+AscGetMaxDmaCount(
+                     ushort bus_type)
+{
+    if (bus_type & ASC_IS_ISA)
+        return (ASC_MAX_ISA_DMA_COUNT);
+    else if (bus_type & (ASC_IS_EISA | ASC_IS_VL))
+        return (ASC_MAX_VL_DMA_COUNT);
+    return (ASC_MAX_PCI_DMA_COUNT);
+}
+
+#ifdef CONFIG_ISA
+STATIC ushort __init
+AscGetIsaDmaChannel(
+                       PortAddr iop_base)
+{
+    ushort              channel;
+
+    channel = AscGetChipCfgLsw(iop_base) & 0x0003;
+    if (channel == 0x03)
+        return (0);
+    else if (channel == 0x00)
+        return (7);
+    return (channel + 4);
+}
+
+STATIC ushort __init
+AscSetIsaDmaChannel(
+                       PortAddr iop_base,
+                       ushort dma_channel)
+{
+    ushort              cfg_lsw;
+    uchar               value;
+
+    if ((dma_channel >= 5) && (dma_channel <= 7)) {
+        if (dma_channel == 7)
+            value = 0x00;
+        else
+            value = dma_channel - 4;
+        cfg_lsw = AscGetChipCfgLsw(iop_base) & 0xFFFC;
+        cfg_lsw |= value;
+        AscSetChipCfgLsw(iop_base, cfg_lsw);
+        return (AscGetIsaDmaChannel(iop_base));
+    }
+    return (0);
+}
+
+STATIC uchar __init
+AscSetIsaDmaSpeed(
+                     PortAddr iop_base,
+                     uchar speed_value)
+{
+    speed_value &= 0x07;
+    AscSetBank(iop_base, 1);
+    AscWriteChipDmaSpeed(iop_base, speed_value);
+    AscSetBank(iop_base, 0);
+    return (AscGetIsaDmaSpeed(iop_base));
+}
+
+STATIC uchar __init
+AscGetIsaDmaSpeed(
+                     PortAddr iop_base
+)
+{
+    uchar               speed_value;
+
+    AscSetBank(iop_base, 1);
+    speed_value = AscReadChipDmaSpeed(iop_base);
+    speed_value &= 0x07;
+    AscSetBank(iop_base, 0);
+    return (speed_value);
+}
+#endif /* CONFIG_ISA */
+
+STATIC ushort __init
+AscReadPCIConfigWord(
+    ASC_DVC_VAR *asc_dvc,
+    ushort pci_config_offset)
+{
+    uchar       lsb, msb;
+
+    lsb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset);
+    msb = DvcReadPCIConfigByte(asc_dvc, pci_config_offset + 1);
+    return ((ushort) ((msb << 8) | lsb));
+}
+
+STATIC ushort __init
+AscInitGetConfig(
+        ASC_DVC_VAR *asc_dvc
+)
+{
+    ushort              warn_code;
+    PortAddr            iop_base;
+    ushort              PCIDeviceID;
+    ushort              PCIVendorID;
+    uchar               PCIRevisionID;
+    uchar               prevCmdRegBits;
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+    asc_dvc->init_state = ASC_INIT_STATE_BEG_GET_CFG;
+    if (asc_dvc->err_code != 0) {
+        return (UW_ERR);
+    }
+    if (asc_dvc->bus_type == ASC_IS_PCI) {
+        PCIVendorID = AscReadPCIConfigWord(asc_dvc,
+                                    AscPCIConfigVendorIDRegister);
+
+        PCIDeviceID = AscReadPCIConfigWord(asc_dvc,
+                                    AscPCIConfigDeviceIDRegister);
+
+        PCIRevisionID = DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigRevisionIDRegister);
+
+        if (PCIVendorID != ASC_PCI_VENDORID) {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+        prevCmdRegBits = DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigCommandRegister);
+
+        if ((prevCmdRegBits & AscPCICmdRegBits_IOMemBusMaster) !=
+            AscPCICmdRegBits_IOMemBusMaster) {
+            DvcWritePCIConfigByte(asc_dvc,
+                            AscPCIConfigCommandRegister,
+                            (prevCmdRegBits |
+                             AscPCICmdRegBits_IOMemBusMaster));
+
+            if ((DvcReadPCIConfigByte(asc_dvc,
+                                AscPCIConfigCommandRegister)
+                 & AscPCICmdRegBits_IOMemBusMaster)
+                != AscPCICmdRegBits_IOMemBusMaster) {
+                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+            }
+        }
+        if ((PCIDeviceID == ASC_PCI_DEVICEID_1200A) ||
+            (PCIDeviceID == ASC_PCI_DEVICEID_1200B)) {
+            DvcWritePCIConfigByte(asc_dvc,
+                            AscPCIConfigLatencyTimer, 0x00);
+            if (DvcReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer)
+                != 0x00) {
+                warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+            }
+        } else if (PCIDeviceID == ASC_PCI_DEVICEID_ULTRA) {
+            if (DvcReadPCIConfigByte(asc_dvc,
+                                AscPCIConfigLatencyTimer) < 0x20) {
+                DvcWritePCIConfigByte(asc_dvc,
+                                    AscPCIConfigLatencyTimer, 0x20);
+
+                if (DvcReadPCIConfigByte(asc_dvc,
+                                    AscPCIConfigLatencyTimer) < 0x20) {
+                    warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+                }
+            }
+        }
+    }
+
+    if (AscFindSignature(iop_base)) {
+        warn_code |= AscInitAscDvcVar(asc_dvc);
+        warn_code |= AscInitFromEEP(asc_dvc);
+        asc_dvc->init_state |= ASC_INIT_STATE_END_GET_CFG;
+        if (asc_dvc->scsi_reset_wait > ASC_MAX_SCSI_RESET_WAIT) {
+            asc_dvc->scsi_reset_wait = ASC_MAX_SCSI_RESET_WAIT;
+        }
+    } else {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+    }
+    return(warn_code);
+}
+
+STATIC ushort __init
+AscInitSetConfig(
+                    ASC_DVC_VAR *asc_dvc
+)
+{
+    ushort              warn_code = 0;
+
+    asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    if (AscFindSignature(asc_dvc->iop_base)) {
+        warn_code |= AscInitFromAscDvcVar(asc_dvc);
+        asc_dvc->init_state |= ASC_INIT_STATE_END_SET_CFG;
+    } else {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+    }
+    return (warn_code);
+}
+
+STATIC ushort __init
+AscInitFromAscDvcVar(
+                        ASC_DVC_VAR *asc_dvc
+)
+{
+    PortAddr            iop_base;
+    ushort              cfg_msw;
+    ushort              warn_code;
+    ushort              pci_device_id = 0;
+
+    iop_base = asc_dvc->iop_base;
+#ifdef CONFIG_PCI
+    if (asc_dvc->cfg->dev)
+        pci_device_id = to_pci_dev(asc_dvc->cfg->dev)->device;
+#endif
+    warn_code = 0;
+    cfg_msw = AscGetChipCfgMsw(iop_base);
+    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+    }
+    if ((asc_dvc->cfg->cmd_qng_enabled & asc_dvc->cfg->disc_enable) !=
+        asc_dvc->cfg->cmd_qng_enabled) {
+        asc_dvc->cfg->disc_enable = asc_dvc->cfg->cmd_qng_enabled;
+        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+    }
+    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+        warn_code |= ASC_WARN_AUTO_CONFIG;
+    }
+    if ((asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL)) != 0) {
+        if (AscSetChipIRQ(iop_base, asc_dvc->irq_no, asc_dvc->bus_type)
+            != asc_dvc->irq_no) {
+            asc_dvc->err_code |= ASC_IERR_SET_IRQ_NO;
+        }
+    }
+    if (asc_dvc->bus_type & ASC_IS_PCI) {
+        cfg_msw &= 0xFFC0;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+        if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
+        } else {
+            if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
+                (pci_device_id == ASC_PCI_DEVICE_ID_REV_B)) {
+                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_IF_NOT_DWB;
+                asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+            }
+        }
+    } else if (asc_dvc->bus_type == ASC_IS_ISAPNP) {
+        if (AscGetChipVersion(iop_base, asc_dvc->bus_type)
+            == ASC_CHIP_VER_ASYN_BUG) {
+            asc_dvc->bug_fix_cntl |= ASC_BUG_FIX_ASYN_USE_SYN;
+        }
+    }
+    if (AscSetChipScsiID(iop_base, asc_dvc->cfg->chip_scsi_id) !=
+        asc_dvc->cfg->chip_scsi_id) {
+        asc_dvc->err_code |= ASC_IERR_SET_SCSI_ID;
+    }
+#ifdef CONFIG_ISA
+    if (asc_dvc->bus_type & ASC_IS_ISA) {
+        AscSetIsaDmaChannel(iop_base, asc_dvc->cfg->isa_dma_channel);
+        AscSetIsaDmaSpeed(iop_base, asc_dvc->cfg->isa_dma_speed);
+    }
+#endif /* CONFIG_ISA */
+    return (warn_code);
+}
+
+STATIC ushort
+AscInitAsc1000Driver(
+                        ASC_DVC_VAR *asc_dvc
+)
+{
+    ushort              warn_code;
+    PortAddr            iop_base;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
+        !(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
+        AscResetChipAndScsiBus(asc_dvc);
+        DvcSleepMilliSecond((ASC_DCNT)
+            ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    }
+    asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    if (!AscFindSignature(asc_dvc->iop_base)) {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+        return (warn_code);
+    }
+    AscDisableInterrupt(iop_base);
+    warn_code |= AscInitLram(asc_dvc);
+    if (asc_dvc->err_code != 0)
+        return (UW_ERR);
+    ASC_DBG1(1, "AscInitAsc1000Driver: _asc_mcode_chksum 0x%lx\n",
+        (ulong) _asc_mcode_chksum);
+    if (AscLoadMicroCode(iop_base, 0, _asc_mcode_buf,
+                         _asc_mcode_size) != _asc_mcode_chksum) {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return (warn_code);
+    }
+    warn_code |= AscInitMicroCodeVar(asc_dvc);
+    asc_dvc->init_state |= ASC_INIT_STATE_END_LOAD_MC;
+    AscEnableInterrupt(iop_base);
+    return (warn_code);
+}
+
+STATIC ushort __init
+AscInitAscDvcVar(
+                    ASC_DVC_VAR *asc_dvc)
+{
+    int                 i;
+    PortAddr            iop_base;
+    ushort              warn_code;
+    uchar               chip_version;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    asc_dvc->err_code = 0;
+    if ((asc_dvc->bus_type &
+         (ASC_IS_ISA | ASC_IS_PCI | ASC_IS_EISA | ASC_IS_VL)) == 0) {
+        asc_dvc->err_code |= ASC_IERR_NO_BUS_TYPE;
+    }
+    AscSetChipControl(iop_base, CC_HALT);
+    AscSetChipStatus(iop_base, 0);
+    asc_dvc->bug_fix_cntl = 0;
+    asc_dvc->pci_fix_asyn_xfer = 0;
+    asc_dvc->pci_fix_asyn_xfer_always = 0;
+    /* asc_dvc->init_state initalized in AscInitGetConfig(). */
+    asc_dvc->sdtr_done = 0;
+    asc_dvc->cur_total_qng = 0;
+    asc_dvc->is_in_int = 0;
+    asc_dvc->in_critical_cnt = 0;
+    asc_dvc->last_q_shortage = 0;
+    asc_dvc->use_tagged_qng = 0;
+    asc_dvc->no_scam = 0;
+    asc_dvc->unit_not_ready = 0;
+    asc_dvc->queue_full_or_busy = 0;
+    asc_dvc->redo_scam = 0;
+    asc_dvc->res2 = 0;
+    asc_dvc->host_init_sdtr_index = 0;
+    asc_dvc->cfg->can_tagged_qng = 0;
+    asc_dvc->cfg->cmd_qng_enabled = 0;
+    asc_dvc->dvc_cntl = ASC_DEF_DVC_CNTL;
+    asc_dvc->init_sdtr = 0;
+    asc_dvc->max_total_qng = ASC_DEF_MAX_TOTAL_QNG;
+    asc_dvc->scsi_reset_wait = 3;
+    asc_dvc->start_motor = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->max_dma_count = AscGetMaxDmaCount(asc_dvc->bus_type);
+    asc_dvc->cfg->sdtr_enable = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->cfg->disc_enable = ASC_SCSI_WIDTH_BIT_SET;
+    asc_dvc->cfg->chip_scsi_id = ASC_DEF_CHIP_SCSI_ID;
+    asc_dvc->cfg->lib_serial_no = ASC_LIB_SERIAL_NUMBER;
+    asc_dvc->cfg->lib_version = (ASC_LIB_VERSION_MAJOR << 8) |
+      ASC_LIB_VERSION_MINOR;
+    chip_version = AscGetChipVersion(iop_base, asc_dvc->bus_type);
+    asc_dvc->cfg->chip_version = chip_version;
+    asc_dvc->sdtr_period_tbl[0] = SYN_XFER_NS_0;
+    asc_dvc->sdtr_period_tbl[1] = SYN_XFER_NS_1;
+    asc_dvc->sdtr_period_tbl[2] = SYN_XFER_NS_2;
+    asc_dvc->sdtr_period_tbl[3] = SYN_XFER_NS_3;
+    asc_dvc->sdtr_period_tbl[4] = SYN_XFER_NS_4;
+    asc_dvc->sdtr_period_tbl[5] = SYN_XFER_NS_5;
+    asc_dvc->sdtr_period_tbl[6] = SYN_XFER_NS_6;
+    asc_dvc->sdtr_period_tbl[7] = SYN_XFER_NS_7;
+    asc_dvc->max_sdtr_index = 7;
+    if ((asc_dvc->bus_type & ASC_IS_PCI) &&
+        (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3150)) {
+        asc_dvc->bus_type = ASC_IS_PCI_ULTRA;
+        asc_dvc->sdtr_period_tbl[0] = SYN_ULTRA_XFER_NS_0;
+        asc_dvc->sdtr_period_tbl[1] = SYN_ULTRA_XFER_NS_1;
+        asc_dvc->sdtr_period_tbl[2] = SYN_ULTRA_XFER_NS_2;
+        asc_dvc->sdtr_period_tbl[3] = SYN_ULTRA_XFER_NS_3;
+        asc_dvc->sdtr_period_tbl[4] = SYN_ULTRA_XFER_NS_4;
+        asc_dvc->sdtr_period_tbl[5] = SYN_ULTRA_XFER_NS_5;
+        asc_dvc->sdtr_period_tbl[6] = SYN_ULTRA_XFER_NS_6;
+        asc_dvc->sdtr_period_tbl[7] = SYN_ULTRA_XFER_NS_7;
+        asc_dvc->sdtr_period_tbl[8] = SYN_ULTRA_XFER_NS_8;
+        asc_dvc->sdtr_period_tbl[9] = SYN_ULTRA_XFER_NS_9;
+        asc_dvc->sdtr_period_tbl[10] = SYN_ULTRA_XFER_NS_10;
+        asc_dvc->sdtr_period_tbl[11] = SYN_ULTRA_XFER_NS_11;
+        asc_dvc->sdtr_period_tbl[12] = SYN_ULTRA_XFER_NS_12;
+        asc_dvc->sdtr_period_tbl[13] = SYN_ULTRA_XFER_NS_13;
+        asc_dvc->sdtr_period_tbl[14] = SYN_ULTRA_XFER_NS_14;
+        asc_dvc->sdtr_period_tbl[15] = SYN_ULTRA_XFER_NS_15;
+        asc_dvc->max_sdtr_index = 15;
+        if (chip_version == ASC_CHIP_VER_PCI_ULTRA_3150)
+        {
+            AscSetExtraControl(iop_base,
+                (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+        } else if (chip_version >= ASC_CHIP_VER_PCI_ULTRA_3050) {
+            AscSetExtraControl(iop_base,
+                (SEC_ACTIVE_NEGATE | SEC_ENABLE_FILTER));
+        }
+    }
+    if (asc_dvc->bus_type == ASC_IS_PCI) {
+           AscSetExtraControl(iop_base, (SEC_ACTIVE_NEGATE | SEC_SLEW_RATE));
+    }
+
+    asc_dvc->cfg->isa_dma_speed = ASC_DEF_ISA_DMA_SPEED;
+    if (AscGetChipBusType(iop_base) == ASC_IS_ISAPNP) {
+        AscSetChipIFC(iop_base, IFC_INIT_DEFAULT);
+        asc_dvc->bus_type = ASC_IS_ISAPNP;
+    }
+#ifdef CONFIG_ISA
+    if ((asc_dvc->bus_type & ASC_IS_ISA) != 0) {
+        asc_dvc->cfg->isa_dma_channel = (uchar) AscGetIsaDmaChannel(iop_base);
+    }
+#endif /* CONFIG_ISA */
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        asc_dvc->cur_dvc_qng[i] = 0;
+        asc_dvc->max_dvc_qng[i] = ASC_MAX_SCSI1_QNG;
+        asc_dvc->scsiq_busy_head[i] = (ASC_SCSI_Q *) 0L;
+        asc_dvc->scsiq_busy_tail[i] = (ASC_SCSI_Q *) 0L;
+        asc_dvc->cfg->max_tag_qng[i] = ASC_MAX_INRAM_TAG_QNG;
+    }
+    return (warn_code);
+}
+
+STATIC ushort __init
+AscInitFromEEP(ASC_DVC_VAR *asc_dvc)
+{
+    ASCEEP_CONFIG       eep_config_buf;
+    ASCEEP_CONFIG       *eep_config;
+    PortAddr            iop_base;
+    ushort              chksum;
+    ushort              warn_code;
+    ushort              cfg_msw, cfg_lsw;
+    int                 i;
+    int                 write_eep = 0;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
+    AscStopQueueExe(iop_base);
+    if ((AscStopChip(iop_base) == FALSE) ||
+        (AscGetChipScsiCtrl(iop_base) != 0)) {
+        asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
+        AscResetChipAndScsiBus(asc_dvc);
+        DvcSleepMilliSecond((ASC_DCNT)
+            ((ushort) asc_dvc->scsi_reset_wait * 1000));
+    }
+    if (AscIsChipHalted(iop_base) == FALSE) {
+        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+        return (warn_code);
+    }
+    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+        return (warn_code);
+    }
+    eep_config = (ASCEEP_CONFIG *) &eep_config_buf;
+    cfg_msw = AscGetChipCfgMsw(iop_base);
+    cfg_lsw = AscGetChipCfgLsw(iop_base);
+    if ((cfg_msw & ASC_CFG_MSW_CLR_MASK) != 0) {
+        cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+        warn_code |= ASC_WARN_CFG_MSW_RECOVER;
+        AscSetChipCfgMsw(iop_base, cfg_msw);
+    }
+    chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
+    ASC_DBG1(1, "AscInitFromEEP: chksum 0x%x\n", chksum);
+    if (chksum == 0) {
+        chksum = 0xaa55;
+    }
+    if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
+        warn_code |= ASC_WARN_AUTO_CONFIG;
+        if (asc_dvc->cfg->chip_version == 3) {
+            if (eep_config->cfg_lsw != cfg_lsw) {
+                warn_code |= ASC_WARN_EEPROM_RECOVER;
+                eep_config->cfg_lsw = AscGetChipCfgLsw(iop_base);
+            }
+            if (eep_config->cfg_msw != cfg_msw) {
+                warn_code |= ASC_WARN_EEPROM_RECOVER;
+                eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+            }
+        }
+    }
+    eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
+    eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
+    ASC_DBG1(1, "AscInitFromEEP: eep_config->chksum 0x%x\n",
+        eep_config->chksum);
+    if (chksum != eep_config->chksum) {
+            if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+                    ASC_CHIP_VER_PCI_ULTRA_3050 )
+            {
+                ASC_DBG(1,
+"AscInitFromEEP: chksum error ignored; EEPROM-less board\n");
+                eep_config->init_sdtr = 0xFF;
+                eep_config->disc_enable = 0xFF;
+                eep_config->start_motor = 0xFF;
+                eep_config->use_cmd_qng = 0;
+                eep_config->max_total_qng = 0xF0;
+                eep_config->max_tag_qng = 0x20;
+                eep_config->cntl = 0xBFFF;
+                ASC_EEP_SET_CHIP_ID(eep_config, 7);
+                eep_config->no_scam = 0;
+                eep_config->adapter_info[0] = 0;
+                eep_config->adapter_info[1] = 0;
+                eep_config->adapter_info[2] = 0;
+                eep_config->adapter_info[3] = 0;
+                eep_config->adapter_info[4] = 0;
+                /* Indicate EEPROM-less board. */
+                eep_config->adapter_info[5] = 0xBB;
+            } else {
+                ASC_PRINT(
+"AscInitFromEEP: EEPROM checksum error; Will try to re-write EEPROM.\n");
+                write_eep = 1;
+                warn_code |= ASC_WARN_EEPROM_CHKSUM;
+            }
+    }
+    asc_dvc->cfg->sdtr_enable = eep_config->init_sdtr;
+    asc_dvc->cfg->disc_enable = eep_config->disc_enable;
+    asc_dvc->cfg->cmd_qng_enabled = eep_config->use_cmd_qng;
+    asc_dvc->cfg->isa_dma_speed = ASC_EEP_GET_DMA_SPD(eep_config);
+    asc_dvc->start_motor = eep_config->start_motor;
+    asc_dvc->dvc_cntl = eep_config->cntl;
+    asc_dvc->no_scam = eep_config->no_scam;
+    asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+    asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+    asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+    asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+    asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+    asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
+    if (!AscTestExternalLram(asc_dvc)) {
+        if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
+            eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
+            eep_config->max_tag_qng = ASC_MAX_PCI_ULTRA_INRAM_TAG_QNG;
+        } else {
+            eep_config->cfg_msw |= 0x0800;
+            cfg_msw |= 0x0800;
+            AscSetChipCfgMsw(iop_base, cfg_msw);
+            eep_config->max_total_qng = ASC_MAX_PCI_INRAM_TOTAL_QNG;
+            eep_config->max_tag_qng = ASC_MAX_INRAM_TAG_QNG;
+        }
+    } else {
+    }
+    if (eep_config->max_total_qng < ASC_MIN_TOTAL_QNG) {
+        eep_config->max_total_qng = ASC_MIN_TOTAL_QNG;
+    }
+    if (eep_config->max_total_qng > ASC_MAX_TOTAL_QNG) {
+        eep_config->max_total_qng = ASC_MAX_TOTAL_QNG;
+    }
+    if (eep_config->max_tag_qng > eep_config->max_total_qng) {
+        eep_config->max_tag_qng = eep_config->max_total_qng;
+    }
+    if (eep_config->max_tag_qng < ASC_MIN_TAG_Q_PER_DVC) {
+        eep_config->max_tag_qng = ASC_MIN_TAG_Q_PER_DVC;
+    }
+    asc_dvc->max_total_qng = eep_config->max_total_qng;
+    if ((eep_config->use_cmd_qng & eep_config->disc_enable) !=
+        eep_config->use_cmd_qng) {
+        eep_config->disc_enable = eep_config->use_cmd_qng;
+        warn_code |= ASC_WARN_CMD_QNG_CONFLICT;
+    }
+    if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
+        asc_dvc->irq_no = AscGetChipIRQ(iop_base, asc_dvc->bus_type);
+    }
+    ASC_EEP_SET_CHIP_ID(eep_config, ASC_EEP_GET_CHIP_ID(eep_config) & ASC_MAX_TID);
+    asc_dvc->cfg->chip_scsi_id = ASC_EEP_GET_CHIP_ID(eep_config);
+    if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) &&
+        !(asc_dvc->dvc_cntl & ASC_CNTL_SDTR_ENABLE_ULTRA)) {
+        asc_dvc->host_init_sdtr_index = ASC_SDTR_ULTRA_PCI_10MB_INDEX;
+    }
+
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
+        asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
+        asc_dvc->cfg->sdtr_period_offset[i] =
+            (uchar) (ASC_DEF_SDTR_OFFSET |
+                     (asc_dvc->host_init_sdtr_index << 4));
+    }
+    eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
+    if (write_eep) {
+        if ((i = AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type)) !=
+             0) {
+                ASC_PRINT1(
+"AscInitFromEEP: Failed to re-write EEPROM with %d errors.\n", i);
+        } else {
+                ASC_PRINT("AscInitFromEEP: Succesfully re-wrote EEPROM.");
+        }
+    }
+    return (warn_code);
+}
+
+STATIC ushort
+AscInitMicroCodeVar(
+                       ASC_DVC_VAR *asc_dvc
+)
+{
+    int                 i;
+    ushort              warn_code;
+    PortAddr            iop_base;
+    ASC_PADDR           phy_addr;
+    ASC_DCNT            phy_size;
+
+    iop_base = asc_dvc->iop_base;
+    warn_code = 0;
+    for (i = 0; i <= ASC_MAX_TID; i++) {
+        AscPutMCodeInitSDTRAtID(iop_base, i,
+                                asc_dvc->cfg->sdtr_period_offset[i]
+);
+    }
+
+    AscInitQLinkVar(asc_dvc);
+    AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
+                     asc_dvc->cfg->disc_enable);
+    AscWriteLramByte(iop_base, ASCV_HOSTSCSI_ID_B,
+                     ASC_TID_TO_TARGET_ID(asc_dvc->cfg->chip_scsi_id));
+
+    /* Align overrun buffer on an 8 byte boundary. */
+    phy_addr = virt_to_bus(asc_dvc->cfg->overrun_buf);
+    phy_addr = cpu_to_le32((phy_addr + 7) & ~0x7);
+    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_PADDR_D,
+        (uchar *) &phy_addr, 1);
+    phy_size = cpu_to_le32(ASC_OVERRUN_BSIZE - 8);
+    AscMemDWordCopyPtrToLram(iop_base, ASCV_OVERRUN_BSIZE_D,
+        (uchar *) &phy_size, 1);
+
+    asc_dvc->cfg->mcode_date =
+        AscReadLramWord(iop_base, (ushort) ASCV_MC_DATE_W);
+    asc_dvc->cfg->mcode_version =
+        AscReadLramWord(iop_base, (ushort) ASCV_MC_VER_W);
+
+    AscSetPCAddr(iop_base, ASC_MCODE_START_ADDR);
+    if (AscGetPCAddr(iop_base) != ASC_MCODE_START_ADDR) {
+        asc_dvc->err_code |= ASC_IERR_SET_PC_ADDR;
+        return (warn_code);
+    }
+    if (AscStartChip(iop_base) != 1) {
+        asc_dvc->err_code |= ASC_IERR_START_STOP_CHIP;
+        return (warn_code);
+    }
+
+    return (warn_code);
+}
+
+STATIC int __init
+AscTestExternalLram(
+                       ASC_DVC_VAR *asc_dvc)
+{
+    PortAddr            iop_base;
+    ushort              q_addr;
+    ushort              saved_word;
+    int                 sta;
+
+    iop_base = asc_dvc->iop_base;
+    sta = 0;
+    q_addr = ASC_QNO_TO_QADDR(241);
+    saved_word = AscReadLramWord(iop_base, q_addr);
+    AscSetChipLramAddr(iop_base, q_addr);
+    AscSetChipLramData(iop_base, 0x55AA);
+    DvcSleepMilliSecond(10);
+    AscSetChipLramAddr(iop_base, q_addr);
+    if (AscGetChipLramData(iop_base) == 0x55AA) {
+        sta = 1;
+        AscWriteLramWord(iop_base, q_addr, saved_word);
+    }
+    return (sta);
+}
+
+STATIC int __init
+AscWriteEEPCmdReg(
+                     PortAddr iop_base,
+                     uchar cmd_reg
+)
+{
+    uchar               read_back;
+    int                 retry;
+
+    retry = 0;
+    while (TRUE) {
+        AscSetChipEEPCmd(iop_base, cmd_reg);
+        DvcSleepMilliSecond(1);
+        read_back = AscGetChipEEPCmd(iop_base);
+        if (read_back == cmd_reg) {
+            return (1);
+        }
+        if (retry++ > ASC_EEP_MAX_RETRY) {
+            return (0);
+        }
+    }
+}
+
+STATIC int __init
+AscWriteEEPDataReg(
+                      PortAddr iop_base,
+                      ushort data_reg
+)
+{
+    ushort              read_back;
+    int                 retry;
+
+    retry = 0;
+    while (TRUE) {
+        AscSetChipEEPData(iop_base, data_reg);
+        DvcSleepMilliSecond(1);
+        read_back = AscGetChipEEPData(iop_base);
+        if (read_back == data_reg) {
+            return (1);
+        }
+        if (retry++ > ASC_EEP_MAX_RETRY) {
+            return (0);
+        }
+    }
+}
+
+STATIC void __init
+AscWaitEEPRead(void)
+{
+    DvcSleepMilliSecond(1);
+    return;
+}
+
+STATIC void __init
+AscWaitEEPWrite(void)
+{
+    DvcSleepMilliSecond(20);
+    return;
+}
+
+STATIC ushort __init
+AscReadEEPWord(
+                  PortAddr iop_base,
+                  uchar addr)
+{
+    ushort              read_wval;
+    uchar               cmd_reg;
+
+    AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+    AscWaitEEPRead();
+    cmd_reg = addr | ASC_EEP_CMD_READ;
+    AscWriteEEPCmdReg(iop_base, cmd_reg);
+    AscWaitEEPRead();
+    read_wval = AscGetChipEEPData(iop_base);
+    AscWaitEEPRead();
+    return (read_wval);
+}
+
+STATIC ushort __init
+AscWriteEEPWord(
+                   PortAddr iop_base,
+                   uchar addr,
+                   ushort word_val)
+{
+    ushort              read_wval;
+
+    read_wval = AscReadEEPWord(iop_base, addr);
+    if (read_wval != word_val) {
+        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
+        AscWaitEEPRead();
+        AscWriteEEPDataReg(iop_base, word_val);
+        AscWaitEEPRead();
+        AscWriteEEPCmdReg(iop_base,
+                          (uchar) ((uchar) ASC_EEP_CMD_WRITE | addr));
+        AscWaitEEPWrite();
+        AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
+        AscWaitEEPRead();
+        return (AscReadEEPWord(iop_base, addr));
+    }
+    return (read_wval);
+}
+
+STATIC ushort __init
+AscGetEEPConfig(
+                   PortAddr iop_base,
+                   ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+{
+    ushort              wval;
+    ushort              sum;
+    ushort              *wbuf;
+    int                 cfg_beg;
+    int                 cfg_end;
+    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+    int                 s_addr;
+
+    wbuf = (ushort *) cfg_buf;
+    sum = 0;
+    /* Read two config words; Byte-swapping done by AscReadEEPWord(). */
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
+        sum += *wbuf;
+    }
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        wval = AscReadEEPWord( iop_base, ( uchar )s_addr ) ;
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * Swap all char fields - must unswap bytes already swapped
+             * by AscReadEEPWord().
+             */
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            *wbuf = wval;
+        }
+        sum += wval; /* Checksum treats all EEPROM data as words. */
+    }
+    /*
+     * Read the checksum word which will be compared against 'sum'
+     * by the caller. Word field already swapped.
+     */
+    *wbuf = AscReadEEPWord(iop_base, (uchar) s_addr);
+    return (sum);
+}
+
+STATIC int __init
+AscSetEEPConfigOnce(
+                       PortAddr iop_base,
+                       ASCEEP_CONFIG * cfg_buf, ushort bus_type)
+{
+    int                 n_error;
+    ushort              *wbuf;
+    ushort              word;
+    ushort              sum;
+    int                 s_addr;
+    int                 cfg_beg;
+    int                 cfg_end;
+    int                 uchar_end_in_config = ASC_EEP_MAX_DVC_ADDR - 2;
+
+
+    wbuf = (ushort *) cfg_buf;
+    n_error = 0;
+    sum = 0;
+    /* Write two config words; AscWriteEEPWord() will swap bytes. */
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        sum += *wbuf;
+        if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+            n_error++;
+        }
+    }
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * This is a char field. Swap char fields before they are
+             * swapped again by AscWriteEEPWord().
+             */
+            word = cpu_to_le16(*wbuf);
+            if (word != AscWriteEEPWord( iop_base, (uchar) s_addr, word)) {
+                n_error++;
+            }
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            if (*wbuf != AscWriteEEPWord(iop_base, (uchar) s_addr, *wbuf)) {
+                n_error++;
+            }
+        }
+        sum += *wbuf; /* Checksum calculated from word values. */
+    }
+    /* Write checksum word. It will be swapped by AscWriteEEPWord(). */
+    *wbuf = sum;
+    if (sum != AscWriteEEPWord(iop_base, (uchar) s_addr, sum)) {
+        n_error++;
+    }
+
+    /* Read EEPROM back again. */
+    wbuf = (ushort *) cfg_buf;
+    /*
+     * Read two config words; Byte-swapping done by AscReadEEPWord().
+     */
+    for (s_addr = 0; s_addr < 2; s_addr++, wbuf++) {
+        if (*wbuf != AscReadEEPWord(iop_base, (uchar) s_addr)) {
+            n_error++;
+        }
+    }
+    if (bus_type & ASC_IS_VL) {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG_VL;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR_VL;
+    } else {
+        cfg_beg = ASC_EEP_DVC_CFG_BEG;
+        cfg_end = ASC_EEP_MAX_DVC_ADDR;
+    }
+    for (s_addr = cfg_beg; s_addr <= (cfg_end - 1); s_addr++, wbuf++) {
+        if (s_addr <= uchar_end_in_config) {
+            /*
+             * Swap all char fields. Must unswap bytes already swapped
+             * by AscReadEEPWord().
+             */
+            word = le16_to_cpu(AscReadEEPWord(iop_base, (uchar) s_addr));
+        } else {
+            /* Don't swap word field at the end - cntl field. */
+            word = AscReadEEPWord(iop_base, (uchar) s_addr);
+        }
+        if (*wbuf != word) {
+            n_error++;
+        }
+    }
+    /* Read checksum; Byte swapping not needed. */
+    if (AscReadEEPWord(iop_base, (uchar) s_addr) != sum) {
+        n_error++;
+    }
+    return (n_error);
+}
+
+STATIC int __init
+AscSetEEPConfig(
+                   PortAddr iop_base,
+                   ASCEEP_CONFIG * cfg_buf, ushort bus_type
+)
+{
+    int            retry;
+    int            n_error;
+
+    retry = 0;
+    while (TRUE) {
+        if ((n_error = AscSetEEPConfigOnce(iop_base, cfg_buf,
+                                           bus_type)) == 0) {
+            break;
+        }
+        if (++retry > ASC_EEP_MAX_RETRY) {
+            break;
+        }
+    }
+    return (n_error);
+}
+
+STATIC void
+AscAsyncFix(
+               ASC_DVC_VAR *asc_dvc,
+               uchar tid_no,
+               ASC_SCSI_INQUIRY *inq)
+{
+    uchar                       dvc_type;
+    ASC_SCSI_BIT_ID_TYPE        tid_bits;
+
+    dvc_type = ASC_INQ_DVC_TYPE(inq);
+    tid_bits = ASC_TIX_TO_TARGET_ID(tid_no);
+
+    if (asc_dvc->bug_fix_cntl & ASC_BUG_FIX_ASYN_USE_SYN)
+    {
+        if (!(asc_dvc->init_sdtr & tid_bits))
+        {
+            if ((dvc_type == TYPE_ROM) &&
+                (AscCompareString((uchar *) inq->vendor_id,
+                    (uchar *) "HP ", 3) == 0))
+            {
+                asc_dvc->pci_fix_asyn_xfer_always |= tid_bits;
+            }
+            asc_dvc->pci_fix_asyn_xfer |= tid_bits;
+            if ((dvc_type == TYPE_PROCESSOR) ||
+                (dvc_type == TYPE_SCANNER) ||
+                (dvc_type == TYPE_ROM) ||
+                (dvc_type == TYPE_TAPE))
+            {
+                asc_dvc->pci_fix_asyn_xfer &= ~tid_bits;
+            }
+
+            if (asc_dvc->pci_fix_asyn_xfer & tid_bits)
+            {
+                AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
+                    ASYN_SDTR_DATA_FIX_PCI_REV_AB);
+            }
+        }
+    }
+    return;
+}
+
+STATIC int
+AscTagQueuingSafe(ASC_SCSI_INQUIRY *inq)
+{
+    if ((inq->add_len >= 32) &&
+        (AscCompareString((uchar *) inq->vendor_id,
+            (uchar *) "QUANTUM XP34301", 15) == 0) &&
+        (AscCompareString((uchar *) inq->product_rev_level,
+            (uchar *) "1071", 4) == 0))
+    {
+        return 0;
+    }
+    return 1;
+}
+
+STATIC void
+AscInquiryHandling(ASC_DVC_VAR *asc_dvc,
+                   uchar tid_no, ASC_SCSI_INQUIRY *inq)
+{
+    ASC_SCSI_BIT_ID_TYPE tid_bit = ASC_TIX_TO_TARGET_ID(tid_no);
+    ASC_SCSI_BIT_ID_TYPE orig_init_sdtr, orig_use_tagged_qng;
+
+    orig_init_sdtr = asc_dvc->init_sdtr;
+    orig_use_tagged_qng = asc_dvc->use_tagged_qng;
+
+    asc_dvc->init_sdtr &= ~tid_bit;
+    asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
+    asc_dvc->use_tagged_qng &= ~tid_bit;
+
+    if (ASC_INQ_RESPONSE_FMT(inq) >= 2 || ASC_INQ_ANSI_VER(inq) >= 2) {
+        if ((asc_dvc->cfg->sdtr_enable & tid_bit) && ASC_INQ_SYNC(inq)) {
+            asc_dvc->init_sdtr |= tid_bit;
+        }
+        if ((asc_dvc->cfg->cmd_qng_enabled & tid_bit) &&
+             ASC_INQ_CMD_QUEUE(inq)) {
+            if (AscTagQueuingSafe(inq)) {
+                asc_dvc->use_tagged_qng |= tid_bit;
+                asc_dvc->cfg->can_tagged_qng |= tid_bit;
+            }
+        }
+    }
+    if (orig_use_tagged_qng != asc_dvc->use_tagged_qng) {
+        AscWriteLramByte(asc_dvc->iop_base, ASCV_DISC_ENABLE_B,
+                         asc_dvc->cfg->disc_enable);
+        AscWriteLramByte(asc_dvc->iop_base, ASCV_USE_TAGGED_QNG_B,
+                         asc_dvc->use_tagged_qng);
+        AscWriteLramByte(asc_dvc->iop_base, ASCV_CAN_TAGGED_QNG_B,
+                         asc_dvc->cfg->can_tagged_qng);
+
+        asc_dvc->max_dvc_qng[tid_no] =
+          asc_dvc->cfg->max_tag_qng[tid_no];
+        AscWriteLramByte(asc_dvc->iop_base,
+                         (ushort) (ASCV_MAX_DVC_QNG_BEG + tid_no),
+                         asc_dvc->max_dvc_qng[tid_no]);
+    }
+    if (orig_init_sdtr != asc_dvc->init_sdtr) {
+        AscAsyncFix(asc_dvc, tid_no, inq);
+    }
+    return;
+}
+
+STATIC int
+AscCompareString(
+                    uchar *str1,
+                    uchar *str2,
+                    int len
+)
+{
+    int                 i;
+    int                 diff;
+
+    for (i = 0; i < len; i++) {
+        diff = (int) (str1[i] - str2[i]);
+        if (diff != 0)
+            return (diff);
+    }
+    return (0);
+}
+
+STATIC uchar
+AscReadLramByte(
+                   PortAddr iop_base,
+                   ushort addr
+)
+{
+    uchar               byte_data;
+    ushort              word_data;
+
+    if (isodd_word(addr)) {
+        AscSetChipLramAddr(iop_base, addr - 1);
+        word_data = AscGetChipLramData(iop_base);
+        byte_data = (uchar) ((word_data >> 8) & 0xFF);
+    } else {
+        AscSetChipLramAddr(iop_base, addr);
+        word_data = AscGetChipLramData(iop_base);
+        byte_data = (uchar) (word_data & 0xFF);
+    }
+    return (byte_data);
+}
+STATIC ushort
+AscReadLramWord(
+                   PortAddr iop_base,
+                   ushort addr
+)
+{
+    ushort              word_data;
+
+    AscSetChipLramAddr(iop_base, addr);
+    word_data = AscGetChipLramData(iop_base);
+    return (word_data);
+}
+
+#if CC_VERY_LONG_SG_LIST
+STATIC ASC_DCNT
+AscReadLramDWord(
+                    PortAddr iop_base,
+                    ushort addr
+)
+{
+    ushort              val_low, val_high;
+    ASC_DCNT            dword_data;
+
+    AscSetChipLramAddr(iop_base, addr);
+    val_low = AscGetChipLramData(iop_base);
+    val_high = AscGetChipLramData(iop_base);
+    dword_data = ((ASC_DCNT) val_high << 16) | (ASC_DCNT) val_low;
+    return (dword_data);
+}
+#endif /* CC_VERY_LONG_SG_LIST */
+
+STATIC void
+AscWriteLramWord(
+                    PortAddr iop_base,
+                    ushort addr,
+                    ushort word_val
+)
+{
+    AscSetChipLramAddr(iop_base, addr);
+    AscSetChipLramData(iop_base, word_val);
+    return;
+}
+
+STATIC void
+AscWriteLramByte(
+                    PortAddr iop_base,
+                    ushort addr,
+                    uchar byte_val
+)
+{
+    ushort              word_data;
+
+    if (isodd_word(addr)) {
+        addr--;
+        word_data = AscReadLramWord(iop_base, addr);
+        word_data &= 0x00FF;
+        word_data |= (((ushort) byte_val << 8) & 0xFF00);
+    } else {
+        word_data = AscReadLramWord(iop_base, addr);
+        word_data &= 0xFF00;
+        word_data |= ((ushort) byte_val & 0x00FF);
+    }
+    AscWriteLramWord(iop_base, addr, word_data);
+    return;
+}
+
+/*
+ * Copy 2 bytes to LRAM.
+ *
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when written to LRAM.
+ */
+STATIC void
+AscMemWordCopyPtrToLram(
+                        PortAddr iop_base,
+                        ushort s_addr,
+                        uchar *s_buffer,
+                        int words
+)
+{
+    int    i;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < 2 * words; i += 2) {
+        /*
+         * On a little-endian system the second argument below
+         * produces a little-endian ushort which is written to
+         * LRAM in little-endian order. On a big-endian system
+         * the second argument produces a big-endian ushort which
+         * is "transparently" byte-swapped by outpw() and written
+         * in little-endian order to LRAM.
+         */
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]);
+    }
+    return;
+}
+
+/*
+ * Copy 4 bytes to LRAM.
+ *
+ * The source data is assumed to be in little-endian order in memory
+ * and is maintained in little-endian order when writen to LRAM.
+ */
+STATIC void
+AscMemDWordCopyPtrToLram(
+                         PortAddr iop_base,
+                         ushort s_addr,
+                         uchar *s_buffer,
+                         int dwords
+)
+{
+    int       i;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < 4 * dwords; i += 4) {
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 1] << 8) | s_buffer[i]); /* LSW */
+        outpw(iop_base + IOP_RAM_DATA,
+            ((ushort) s_buffer[i + 3] << 8) | s_buffer[i + 2]); /* MSW */
+    }
+    return;
+}
+
+/*
+ * Copy 2 bytes from LRAM.
+ *
+ * The source data is assumed to be in little-endian order in LRAM
+ * and is maintained in little-endian order when written to memory.
+ */
+STATIC void
+AscMemWordCopyPtrFromLram(
+                          PortAddr iop_base,
+                          ushort s_addr,
+                          uchar *d_buffer,
+                          int words
+)
+{
+    int i;
+    ushort word;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < 2 * words; i += 2) {
+        word = inpw(iop_base + IOP_RAM_DATA);
+        d_buffer[i] = word & 0xff;
+        d_buffer[i + 1] = (word >> 8) & 0xff;
+    }
+    return;
+}
+
+STATIC ASC_DCNT
+AscMemSumLramWord(
+                     PortAddr iop_base,
+                     ushort s_addr,
+                     int words
+)
+{
+    ASC_DCNT         sum;
+    int              i;
+
+    sum = 0L;
+    for (i = 0; i < words; i++, s_addr += 2) {
+        sum += AscReadLramWord(iop_base, s_addr);
+    }
+    return (sum);
+}
+
+STATIC void
+AscMemWordSetLram(
+                     PortAddr iop_base,
+                     ushort s_addr,
+                     ushort set_wval,
+                     int words
+)
+{
+    int             i;
+
+    AscSetChipLramAddr(iop_base, s_addr);
+    for (i = 0; i < words; i++) {
+        AscSetChipLramData(iop_base, set_wval);
+    }
+    return;
+}
+
+
+/*
+ * --- Adv Library Functions
+ */
+
+/* a_mcode.h */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC unsigned char _adv_asc3550_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0x16,  0x18,  0xe4,  0x00,  0xfc,  0x01,  0x00,  0x48,  0xe4,
+  0xbe,  0x18,  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0x00,  0xfa,  0xff,  0xff,  0x28,  0x0e,  0x9e,  0xe7,
+  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x00,  0xf6,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,  0x01,  0xf6,
+  0x01,  0xfa,  0x08,  0x00,  0x03,  0x00,  0x04,  0x00,  0x18,  0xf4,  0x10,  0x00,  0x00,  0xec,  0x85,  0xf0,
+  0xbc,  0x00,  0xd5,  0xf0,  0x8e,  0x0c,  0x38,  0x54,  0x00,  0xe6,  0x1e,  0xf0,  0x86,  0xf0,  0xb4,  0x00,
+  0x98,  0x57,  0xd0,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x0c,  0x00,  0xbb,  0x00,  0xaa,  0x18,  0x02,  0x80,
+  0x32,  0xf0,  0x01,  0xfc,  0x88,  0x0c,  0xc6,  0x12,  0x02,  0x13,  0x18,  0x40,  0x00,  0x57,  0x01,  0xea,
+  0x3c,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,
+  0xc0,  0x00,  0x01,  0x01,  0x3e,  0x01,  0xda,  0x0f,  0x22,  0x10,  0x08,  0x12,  0x02,  0x4a,  0xb9,  0x54,
+  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x20,  0x00,  0x32,  0x00,  0x3e,  0x00,  0x80,  0x00,
+  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,
+  0x78,  0x01,  0x62,  0x0a,  0x92,  0x0c,  0x2c,  0x10,  0x2e,  0x10,  0x06,  0x13,  0x4c,  0x1c,  0xbb,  0x55,
+  0x3c,  0x56,  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0xb1,  0xf0,  0x03,  0xf7,  0x06,  0xf7,
+  0x03,  0xfc,  0x0f,  0x00,  0x40,  0x00,  0xbe,  0x00,  0x00,  0x01,  0xb0,  0x08,  0x30,  0x13,  0x64,  0x15,
+  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,  0x02,  0x48,  0x00,  0x4c,  0x04,  0xea,  0x5d,  0xf0,
+  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x34,  0x00,  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,
+  0x4e,  0x01,  0x4e,  0x0b,  0x1e,  0x0e,  0x0c,  0x10,  0x0a,  0x12,  0x04,  0x13,  0x40,  0x13,  0x30,  0x1c,
+  0x00,  0x4e,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xa7,  0xf0,
+  0xb8,  0xf0,  0x0e,  0xf7,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,
+  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xde,  0x03,  0x56,  0x0a,  0x14,  0x0e,  0x02,  0x10,
+  0x04,  0x10,  0x0a,  0x10,  0x36,  0x10,  0x0a,  0x13,  0x12,  0x13,  0x52,  0x13,  0x10,  0x15,  0x14,  0x15,
+  0xac,  0x16,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,
+  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x83,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,
+  0x0b,  0xf0,  0x0c,  0xf0,  0x5c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,
+  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0x0a,  0x00,  0x0d,  0x00,  0x1c,  0x00,  0x9e,  0x00,  0xa8,  0x00,
+  0xaa,  0x00,  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7a,  0x01,  0xc0,  0x01,
+  0xc2,  0x01,  0x7c,  0x02,  0x5a,  0x03,  0xea,  0x04,  0xe8,  0x07,  0x68,  0x08,  0x69,  0x08,  0xba,  0x08,
+  0xe9,  0x09,  0x06,  0x0b,  0x3a,  0x0e,  0x00,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,  0x06,  0x12,
+  0x0c,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x82,  0x13,  0x42,  0x14,  0xd6,  0x14,  0x8a,  0x15,  0xc6,  0x17,
+  0xd2,  0x17,  0x6b,  0x18,  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0x48,  0x47,
+  0x41,  0x48,  0x89,  0x48,  0x80,  0x4c,  0x00,  0x54,  0x44,  0x55,  0xe5,  0x55,  0x14,  0x56,  0x77,  0x57,
+  0xbf,  0x57,  0x40,  0x5c,  0x06,  0x80,  0x08,  0x90,  0x03,  0xa1,  0xfe,  0x9c,  0xf0,  0x29,  0x02,  0xfe,
+  0xb8,  0x0c,  0xff,  0x10,  0x00,  0x00,  0xd0,  0xfe,  0xcc,  0x18,  0x00,  0xcf,  0xfe,  0x80,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x48,  0x00,  0x4f,  0xff,  0x04,  0x00,  0x00,  0x10,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x0f,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xcf,
+  0x2a,  0x67,  0x0b,  0x01,  0xfe,  0xce,  0x0e,  0xfe,  0x04,  0xf7,  0xcf,  0x67,  0x0b,  0x3c,  0x2a,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x91,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf0,  0x01,  0xfe,  0x8f,  0xf0,  0x9c,  0x05,  0x51,  0x3b,  0x02,  0xfe,  0xd4,  0x0c,
+  0x01,  0xfe,  0x44,  0x0d,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x05,  0xfe,  0xa6,
+  0x00,  0xfe,  0xd3,  0x12,  0x47,  0x18,  0xfe,  0xa6,  0x00,  0xb5,  0xfe,  0x48,  0xf0,  0xfe,  0x86,  0x02,
+  0xfe,  0x49,  0xf0,  0xfe,  0xa0,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xbe,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
+  0x50,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x56,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x44,  0x02,  0xfe,  0x44,
+  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x4c,  0x02,  0x17,  0x0b,  0xa0,  0x17,  0x06,  0x18,
+  0x96,  0x02,  0x29,  0xfe,  0x00,  0x1c,  0xde,  0xfe,  0x02,  0x1c,  0xdd,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
+  0x10,  0x01,  0xfe,  0x20,  0x17,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xc7,  0x0a,  0x6b,  0x01,  0x9e,
+  0x02,  0x29,  0x14,  0x4d,  0x37,  0x97,  0x01,  0xfe,  0x64,  0x0f,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xbd,
+  0x10,  0x0a,  0x6b,  0x01,  0x82,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x17,  0x06,
+  0x18,  0x96,  0x2a,  0x25,  0x29,  0xfe,  0x3d,  0xf0,  0xfe,  0x02,  0x02,  0x21,  0xfe,  0x94,  0x02,  0xfe,
+  0x5a,  0x1c,  0xea,  0xfe,  0x14,  0x1c,  0x14,  0xfe,  0x30,  0x00,  0x37,  0x97,  0x01,  0xfe,  0x54,  0x0f,
+  0x17,  0x06,  0x18,  0x96,  0x02,  0xd0,  0x1e,  0x20,  0x07,  0x10,  0x34,  0xfe,  0x69,  0x10,  0x17,  0x06,
+  0x18,  0x96,  0xfe,  0x04,  0xec,  0x20,  0x46,  0x3d,  0x12,  0x20,  0xfe,  0x05,  0xf6,  0xc7,  0x01,  0xfe,
+  0x52,  0x16,  0x09,  0x4a,  0x4c,  0x35,  0x11,  0x2d,  0x3c,  0x8a,  0x01,  0xe6,  0x02,  0x29,  0x0a,  0x40,
+  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x01,  0x6f,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,
+  0x0e,  0xfe,  0xc8,  0x54,  0x64,  0xfe,  0x0c,  0x03,  0x01,  0xe6,  0x02,  0x29,  0x2a,  0x46,  0xfe,  0x02,
+  0xe8,  0x27,  0xf8,  0xfe,  0x9e,  0x43,  0xf7,  0xfe,  0x27,  0xf0,  0xfe,  0xdc,  0x01,  0xfe,  0x07,  0x4b,
+  0xfe,  0x20,  0xf0,  0x9c,  0xfe,  0x40,  0x1c,  0x25,  0xd2,  0xfe,  0x26,  0xf0,  0xfe,  0x56,  0x03,  0xfe,
+  0xa0,  0xf0,  0xfe,  0x44,  0x03,  0xfe,  0x11,  0xf0,  0x9c,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,
+  0x64,  0x03,  0xeb,  0x0f,  0xfe,  0x11,  0x00,  0x02,  0x5a,  0x2a,  0xfe,  0x48,  0x1c,  0xeb,  0x09,  0x04,
+  0x1d,  0xfe,  0x18,  0x13,  0x23,  0x1e,  0x98,  0xac,  0x12,  0x98,  0x0a,  0x40,  0x01,  0x0e,  0xac,  0x75,
+  0x01,  0xfe,  0xbc,  0x15,  0x11,  0xca,  0x25,  0xd2,  0xfe,  0x01,  0xf0,  0xd2,  0xfe,  0x82,  0xf0,  0xfe,
+  0x92,  0x03,  0xec,  0x11,  0xfe,  0xe4,  0x00,  0x65,  0xfe,  0xa4,  0x03,  0x25,  0x32,  0x1f,  0xfe,  0xb4,
+  0x03,  0x01,  0x43,  0xfe,  0x06,  0xf0,  0xfe,  0xc4,  0x03,  0x8d,  0x81,  0xfe,  0x0a,  0xf0,  0xfe,  0x7a,
+  0x06,  0x02,  0x22,  0x05,  0x6b,  0x28,  0x16,  0xfe,  0xf6,  0x04,  0x14,  0x2c,  0x01,  0x33,  0x8f,  0xfe,
+  0x66,  0x02,  0x02,  0xd1,  0xeb,  0x2a,  0x67,  0x1a,  0xfe,  0x67,  0x1b,  0xf8,  0xf7,  0xfe,  0x48,  0x1c,
+  0x70,  0x01,  0x6e,  0x87,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x16,  0xd3,  0x0a,  0xca,  0x01,  0x0e,
+  0x74,  0x60,  0x59,  0x76,  0x27,  0x05,  0x6b,  0x28,  0xfe,  0x10,  0x12,  0x14,  0x2c,  0x01,  0x33,  0x8f,
+  0xfe,  0x66,  0x02,  0x02,  0xd1,  0xbc,  0x7d,  0xbd,  0x7f,  0x25,  0x22,  0x65,  0xfe,  0x3c,  0x04,  0x1f,
+  0xfe,  0x38,  0x04,  0x68,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2b,  0xff,  0x02,
+  0x00,  0x10,  0x01,  0x08,  0x1f,  0xfe,  0xe0,  0x04,  0x2b,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd5,
+  0xfe,  0x4c,  0x44,  0xfe,  0x4c,  0x12,  0x60,  0xfe,  0x44,  0x48,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,
+  0xd3,  0x46,  0x76,  0x27,  0xfa,  0xef,  0xfe,  0x62,  0x13,  0x09,  0x04,  0x1d,  0xfe,  0x2a,  0x13,  0x2f,
+  0x07,  0x7e,  0xa5,  0xfe,  0x20,  0x10,  0x13,  0x2c,  0xfe,  0x4c,  0x54,  0x64,  0xd3,  0xfa,  0xef,  0x86,
+  0x09,  0x04,  0x1d,  0xfe,  0x08,  0x13,  0x2f,  0x07,  0x7e,  0x6e,  0x09,  0x04,  0x1d,  0xfe,  0x1c,  0x12,
+  0x14,  0x92,  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,
+  0x2b,  0x11,  0xfe,  0xe6,  0x00,  0xfe,  0x1c,  0x90,  0xf9,  0x03,  0x14,  0x92,  0x01,  0x33,  0x02,  0x29,
+  0xfe,  0x42,  0x5b,  0x67,  0x1a,  0xfe,  0x46,  0x59,  0xf8,  0xf7,  0xfe,  0x87,  0x80,  0xfe,  0x31,  0xe4,
+  0x4f,  0x09,  0x04,  0x0b,  0xfe,  0x78,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x1a,  0xfe,  0x70,  0x12,  0x49,
+  0x04,  0x06,  0xfe,  0x60,  0x13,  0x05,  0xfe,  0xa2,  0x00,  0x28,  0x16,  0xfe,  0x80,  0x05,  0xfe,  0x31,
+  0xe4,  0x6a,  0x49,  0x04,  0x0b,  0xfe,  0x4a,  0x13,  0x05,  0xfe,  0xa0,  0x00,  0x28,  0xfe,  0x42,  0x12,
+  0x5e,  0x01,  0x08,  0x25,  0x32,  0xf1,  0x01,  0x08,  0x26,  0xfe,  0x98,  0x05,  0x11,  0xfe,  0xe3,  0x00,
+  0x23,  0x49,  0xfe,  0x4a,  0xf0,  0xfe,  0x6a,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x64,  0x05,  0x83,  0x24,
+  0xfe,  0x21,  0x00,  0xa1,  0x24,  0xfe,  0x22,  0x00,  0xa0,  0x24,  0x4c,  0xfe,  0x09,  0x48,  0x01,  0x08,
+  0x26,  0xfe,  0x98,  0x05,  0xfe,  0xe2,  0x08,  0x49,  0x04,  0xc5,  0x3b,  0x01,  0x86,  0x24,  0x06,  0x12,
+  0xcc,  0x37,  0xfe,  0x27,  0x01,  0x09,  0x04,  0x1d,  0xfe,  0x22,  0x12,  0x47,  0x01,  0xa7,  0x14,  0x92,
+  0x09,  0x04,  0x06,  0x3b,  0x14,  0xc4,  0x01,  0x33,  0x8f,  0xfe,  0x70,  0x0c,  0x02,  0x22,  0x05,  0xfe,
+  0x9c,  0x00,  0x28,  0xfe,  0x3e,  0x12,  0x05,  0x50,  0x28,  0xfe,  0x36,  0x13,  0x47,  0x01,  0xa7,  0x26,
+  0xfe,  0x08,  0x06,  0x0a,  0x06,  0x49,  0x04,  0x19,  0xfe,  0x02,  0x12,  0x5f,  0x01,  0xfe,  0xaa,  0x14,
+  0x1f,  0xfe,  0xfe,  0x05,  0x11,  0x9a,  0x01,  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x50,  0xb4,  0x0c,
+  0x50,  0x05,  0xc6,  0x28,  0xfe,  0x62,  0x12,  0x05,  0x3f,  0x28,  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x14,
+  0x18,  0x01,  0xfe,  0x66,  0x18,  0xfe,  0x43,  0x48,  0xb7,  0x19,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,
+  0x48,  0x8b,  0x1c,  0x3d,  0x85,  0xb7,  0x69,  0x47,  0x01,  0xa7,  0x26,  0xfe,  0x72,  0x06,  0x49,  0x04,
+  0x1b,  0xdf,  0x89,  0x0a,  0x4d,  0x01,  0xfe,  0xd8,  0x14,  0x1f,  0xfe,  0x68,  0x06,  0x11,  0x9a,  0x01,
+  0x43,  0x11,  0xfe,  0xe5,  0x00,  0x05,  0x3f,  0xb4,  0x0c,  0x3f,  0x17,  0x06,  0x01,  0xa7,  0xec,  0x72,
+  0x70,  0x01,  0x6e,  0x87,  0x11,  0xfe,  0xe2,  0x00,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,
+  0xa6,  0x06,  0x8c,  0xfe,  0x5c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,  0x64,  0x07,  0x8d,  0x81,  0x02,  0x22,
+  0x09,  0x04,  0x0b,  0xfe,  0x2e,  0x12,  0x15,  0x1a,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,
+  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x15,  0x00,  0x02,  0xfe,  0x32,
+  0x08,  0x61,  0x04,  0x1b,  0xfe,  0x38,  0x12,  0x09,  0x04,  0x1b,  0x6e,  0x15,  0xfe,  0x1b,  0x00,  0x01,
+  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x00,  0x01,  0x08,  0x15,  0x06,  0x01,
+  0x08,  0x15,  0x00,  0x02,  0xd9,  0x66,  0x4c,  0xfe,  0x3a,  0x55,  0x5f,  0xfe,  0x9a,  0x81,  0x4b,  0x1d,
+  0xba,  0xfe,  0x32,  0x07,  0x0a,  0x1d,  0xfe,  0x09,  0x6f,  0xaf,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,
+  0x62,  0x2c,  0x85,  0x66,  0x7b,  0x01,  0x08,  0x25,  0x32,  0xfe,  0x0a,  0xf0,  0xfe,  0x32,  0x07,  0x8d,
+  0x81,  0x8c,  0xfe,  0x5c,  0x07,  0x02,  0x22,  0x01,  0x43,  0x02,  0xfe,  0x8a,  0x06,  0x15,  0x19,  0x02,
+  0xfe,  0x8a,  0x06,  0xfe,  0x9c,  0xf7,  0xd4,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x77,  0xfe,  0xca,
+  0x07,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x4a,  0x6a,  0x35,  0x1e,  0x20,  0x07,  0x10,  0xfe,  0x0e,  0x12,
+  0x74,  0xfe,  0x80,  0x80,  0x37,  0x20,  0x63,  0x27,  0xfe,  0x06,  0x10,  0xfe,  0x83,  0xe7,  0xc4,  0xa1,
+  0xfe,  0x03,  0x40,  0x09,  0x4a,  0x4f,  0x35,  0x01,  0xa8,  0xad,  0xfe,  0x1f,  0x40,  0x12,  0x58,  0x01,
+  0xa5,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0x83,  0xfb,  0xfe,
+  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x0c,  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,
+  0xc2,  0x50,  0x0c,  0x39,  0x18,  0x3a,  0xfe,  0x4a,  0x10,  0x09,  0x04,  0x6a,  0xfe,  0x2a,  0x12,  0xfe,
+  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x54,  0x18,  0x55,  0x09,  0x04,  0x4f,  0x85,  0x01,  0xa8,  0xfe,
+  0x1f,  0x80,  0x12,  0x58,  0xfe,  0x44,  0x90,  0xfe,  0xc6,  0x90,  0x0c,  0x56,  0x18,  0x57,  0xfb,  0xfe,
+  0x8a,  0x90,  0x0c,  0x52,  0x18,  0x53,  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x39,  0x18,  0x3a,
+  0x0c,  0x38,  0x18,  0x4e,  0x09,  0x4a,  0x19,  0x35,  0x2a,  0x13,  0xfe,  0x4e,  0x11,  0x65,  0xfe,  0x48,
+  0x08,  0xfe,  0x9e,  0xf0,  0xfe,  0x5c,  0x08,  0xb1,  0x16,  0x32,  0x2a,  0x73,  0xdd,  0xb8,  0xfe,  0x80,
+  0x08,  0xb9,  0xfe,  0x9e,  0x08,  0x8c,  0xfe,  0x74,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x7a,  0x08,  0x8d,
+  0x81,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xc9,  0x10,  0x15,  0x19,  0xfe,  0xc9,  0x10,  0x61,  0x04,  0x06,
+  0xfe,  0x10,  0x12,  0x61,  0x04,  0x0b,  0x45,  0x09,  0x04,  0x0b,  0xfe,  0x68,  0x12,  0xfe,  0x2e,  0x1c,
+  0x02,  0xfe,  0x24,  0x0a,  0x61,  0x04,  0x06,  0x45,  0x61,  0x04,  0x0b,  0xfe,  0x52,  0x12,  0xfe,  0x2c,
+  0x1c,  0xfe,  0xaa,  0xf0,  0xfe,  0x1e,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0xbe,  0x08,  0xfe,  0x8a,  0x10,
+  0xaa,  0xfe,  0xf3,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0xca,  0x08,  0x02,  0xfe,  0x24,  0x0a,  0xab,  0xfe,
+  0xe7,  0x10,  0xfe,  0x2b,  0xf0,  0x9d,  0xe9,  0x1c,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xb5,  0xfe,
+  0xd2,  0xf0,  0x9d,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x16,  0x9d,  0x05,  0xcb,  0x1c,  0x06,  0x16,  0x9d,
+  0xb8,  0x6d,  0xb9,  0x6d,  0xaa,  0xab,  0xfe,  0xb1,  0x10,  0x70,  0x5e,  0x2b,  0x14,  0x92,  0x01,  0x33,
+  0x0f,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x5a,  0x0f,  0x7c,  0x02,  0x5a,  0xfe,  0x74,  0x18,  0x1c,
+  0xfe,  0x00,  0xf8,  0x16,  0x6d,  0x67,  0x1b,  0x01,  0xfe,  0x44,  0x0d,  0x3b,  0x01,  0xe6,  0x1e,  0x27,
+  0x74,  0x67,  0x1a,  0x02,  0x6d,  0x09,  0x04,  0x0b,  0x21,  0xfe,  0x06,  0x0a,  0x09,  0x04,  0x6a,  0xfe,
+  0x82,  0x12,  0x09,  0x04,  0x19,  0xfe,  0x66,  0x13,  0x1e,  0x58,  0xac,  0xfc,  0xfe,  0x83,  0x80,  0xfe,
+  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x63,  0x27,  0xfe,  0x40,  0x59,
+  0xfe,  0xc1,  0x59,  0x77,  0xd7,  0x05,  0x54,  0x31,  0x55,  0x0c,  0x7b,  0x18,  0x7c,  0xbe,  0x54,  0xbf,
+  0x55,  0x01,  0xa8,  0xad,  0x63,  0x27,  0x12,  0x58,  0xc0,  0x38,  0xc1,  0x4e,  0x79,  0x56,  0x68,  0x57,
+  0xf4,  0xf5,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0x01,  0xa5,  0xa2,  0x23,  0x0c,  0x7b,
+  0x0c,  0x7c,  0x79,  0x56,  0x68,  0x57,  0xfe,  0x12,  0x10,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x79,  0x39,
+  0x68,  0x3a,  0x09,  0x04,  0xfe,  0xf7,  0x00,  0x35,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x10,  0x58,  0xfe,
+  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x02,  0x6d,  0x09,  0x04,  0x19,  0x16,  0xd7,  0x09,
+  0x04,  0xfe,  0xf7,  0x00,  0x35,  0xfe,  0x3a,  0x55,  0xfe,  0x19,  0x81,  0x5f,  0xfe,  0x10,  0x90,  0xfe,
+  0x92,  0x90,  0xfe,  0xd7,  0x10,  0x2f,  0x07,  0x9b,  0x16,  0xfe,  0xc6,  0x08,  0x11,  0x9b,  0x09,  0x04,
+  0x0b,  0xfe,  0x14,  0x13,  0x05,  0x39,  0x31,  0x3a,  0x77,  0xfe,  0xc6,  0x08,  0xfe,  0x0c,  0x58,  0xfe,
+  0x8d,  0x58,  0x02,  0x6d,  0x23,  0x47,  0xfe,  0x19,  0x80,  0xde,  0x09,  0x04,  0x0b,  0xfe,  0x1a,  0x12,
+  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xe9,  0xb5,  0xfe,  0xd1,  0xf0,  0xd9,  0x14,  0x7a,  0x01,  0x33,
+  0x0f,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0xbe,  0x39,  0xfe,  0xed,  0x19,  0xbf,
+  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xe9,  0x1c,  0xfe,  0x00,  0xff,  0x34,  0xfe,  0x74,  0x10,
+  0xb5,  0xfe,  0xd2,  0xf0,  0xfe,  0xb2,  0x0a,  0xfe,  0x76,  0x18,  0x1c,  0x1a,  0x84,  0x05,  0xcb,  0x1c,
+  0x06,  0xfe,  0x08,  0x13,  0x0f,  0xfe,  0x16,  0x00,  0x02,  0x5a,  0xfe,  0xd1,  0xf0,  0xfe,  0xc4,  0x0a,
+  0x14,  0x7a,  0x01,  0x33,  0x0f,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,  0xfe,  0xca,
+  0x0a,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xd6,  0x0a,  0x0f,  0xfe,  0x22,  0x00,  0x02,  0x5a,
+  0xfe,  0xcb,  0xf0,  0xfe,  0xe2,  0x0a,  0x0f,  0xfe,  0x24,  0x00,  0x02,  0x5a,  0xfe,  0xd0,  0xf0,  0xfe,
+  0xec,  0x0a,  0x0f,  0x93,  0xdc,  0xfe,  0xcf,  0xf0,  0xfe,  0xf6,  0x0a,  0x0f,  0x4c,  0xfe,  0x10,  0x10,
+  0xfe,  0xcc,  0xf0,  0xd9,  0x61,  0x04,  0x19,  0x3b,  0x0f,  0xfe,  0x12,  0x00,  0x2a,  0x13,  0xfe,  0x4e,
+  0x11,  0x65,  0xfe,  0x0c,  0x0b,  0xfe,  0x9e,  0xf0,  0xfe,  0x20,  0x0b,  0xb1,  0x16,  0x32,  0x2a,  0x73,
+  0xdd,  0xb8,  0x22,  0xb9,  0x22,  0x2a,  0xec,  0x65,  0xfe,  0x2c,  0x0b,  0x25,  0x32,  0x8c,  0xfe,  0x48,
+  0x0b,  0x8d,  0x81,  0xb8,  0xd4,  0xb9,  0xd4,  0x02,  0x22,  0x01,  0x43,  0xfe,  0xdb,  0x10,  0x11,  0xfe,
+  0xe8,  0x00,  0xaa,  0xab,  0x70,  0xbc,  0x7d,  0xbd,  0x7f,  0xfe,  0x89,  0xf0,  0x22,  0x30,  0x2e,  0xd8,
+  0xbc,  0x7d,  0xbd,  0x7f,  0x01,  0x08,  0x1f,  0x22,  0x30,  0x2e,  0xd6,  0xb1,  0x45,  0x0f,  0xfe,  0x42,
+  0x00,  0x02,  0x5a,  0x78,  0x06,  0xfe,  0x81,  0x49,  0x16,  0xfe,  0x38,  0x0c,  0x09,  0x04,  0x0b,  0xfe,
+  0x44,  0x13,  0x0f,  0x00,  0x4b,  0x0b,  0xfe,  0x54,  0x12,  0x4b,  0xfe,  0x28,  0x00,  0x21,  0xfe,  0xa6,
+  0x0c,  0x0a,  0x40,  0x01,  0x0e,  0x07,  0x00,  0x5d,  0x3e,  0xfe,  0x28,  0x00,  0xfe,  0xe2,  0x10,  0x01,
+  0xe7,  0x01,  0xe8,  0x0a,  0x99,  0x01,  0xfe,  0x32,  0x0e,  0x59,  0x11,  0x2d,  0x01,  0x6f,  0x02,  0x29,
+  0x0f,  0xfe,  0x44,  0x00,  0x4b,  0x0b,  0xdf,  0x3e,  0x0b,  0xfe,  0xb4,  0x10,  0x01,  0x86,  0x3e,  0x0b,
+  0xfe,  0xaa,  0x10,  0x01,  0x86,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xa3,  0x3e,  0x0b,  0x0f,  0xfe,
+  0x43,  0x00,  0xfe,  0x96,  0x10,  0x09,  0x4a,  0x0b,  0x35,  0x01,  0xe7,  0x01,  0xe8,  0x59,  0x11,  0x2d,
+  0x01,  0x6f,  0x67,  0x0b,  0x59,  0x3c,  0x8a,  0x02,  0xfe,  0x2a,  0x03,  0x09,  0x04,  0x0b,  0x84,  0x3e,
+  0x0b,  0x0f,  0x00,  0xfe,  0x5c,  0x10,  0x61,  0x04,  0x1b,  0xfe,  0x58,  0x12,  0x09,  0x04,  0x1b,  0xfe,
+  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x5c,  0x0c,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,
+  0xf0,  0xfe,  0x62,  0x0c,  0x09,  0x4a,  0x1b,  0x35,  0xfe,  0xa9,  0x10,  0x0f,  0xfe,  0x15,  0x00,  0xfe,
+  0x04,  0xe6,  0x0b,  0x5f,  0x5c,  0x0f,  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x0f,  0xfe,  0x47,  0x00,
+  0xa1,  0x0f,  0xfe,  0x41,  0x00,  0xa0,  0x0f,  0xfe,  0x24,  0x00,  0x87,  0xaa,  0xab,  0x70,  0x05,  0x6b,
+  0x28,  0x21,  0xd1,  0x5f,  0xfe,  0x04,  0xe6,  0x1b,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x59,  0x01,
+  0xda,  0x02,  0x29,  0xea,  0x14,  0x0b,  0x37,  0x95,  0xa9,  0x14,  0xfe,  0x31,  0x00,  0x37,  0x97,  0x01,
+  0xfe,  0x54,  0x0f,  0x02,  0xd0,  0x3c,  0xfe,  0x06,  0xec,  0xc9,  0xee,  0x3e,  0x1d,  0xfe,  0xce,  0x45,
+  0x34,  0x3c,  0xfe,  0x06,  0xea,  0xc9,  0xfe,  0x47,  0x4b,  0x89,  0xfe,  0x75,  0x57,  0x05,  0x51,  0xfe,
+  0x98,  0x56,  0xfe,  0x38,  0x12,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x44,  0x48,  0x46,  0x09,  0x04,  0x1d,
+  0xfe,  0x1a,  0x13,  0x0a,  0x40,  0x01,  0x0e,  0x47,  0xfe,  0x41,  0x58,  0x0a,  0x99,  0x01,  0x0e,  0xfe,
+  0x49,  0x54,  0x8e,  0xfe,  0x2a,  0x0d,  0x02,  0xfe,  0x2a,  0x03,  0x0a,  0x51,  0xfe,  0xee,  0x14,  0xee,
+  0x3e,  0x1d,  0xfe,  0xce,  0x45,  0x34,  0x3c,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x02,  0x29,  0x1e,
+  0x20,  0x07,  0x10,  0xfe,  0x9e,  0x12,  0x23,  0x12,  0x4d,  0x12,  0x94,  0x12,  0xce,  0x1e,  0x2d,  0x47,
+  0x37,  0x2d,  0xb1,  0xe0,  0xfe,  0xbc,  0xf0,  0xfe,  0xec,  0x0d,  0x13,  0x06,  0x12,  0x4d,  0x01,  0xfe,
+  0xe2,  0x15,  0x05,  0xfe,  0x38,  0x01,  0x31,  0xfe,  0x3a,  0x01,  0x77,  0xfe,  0xf0,  0x0d,  0xfe,  0x02,
+  0xec,  0xce,  0x62,  0x00,  0x5d,  0xfe,  0x04,  0xec,  0x20,  0x46,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,
+  0x01,  0xfe,  0x52,  0x16,  0xfb,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,  0x18,  0x13,  0xaf,  0xfe,  0x02,  0xea,
+  0xce,  0x62,  0x7a,  0xfe,  0xc5,  0x13,  0x14,  0x1b,  0x37,  0x95,  0xa9,  0x5c,  0x05,  0xfe,  0x38,  0x01,
+  0x1c,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,  0x05,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,
+  0x3d,  0x12,  0x20,  0x24,  0x06,  0x12,  0x2d,  0x11,  0x2d,  0x8a,  0x13,  0x06,  0x03,  0x23,  0x03,  0x1e,
+  0x4d,  0xfe,  0xf7,  0x12,  0x1e,  0x94,  0xac,  0x12,  0x94,  0x07,  0x7a,  0xfe,  0x71,  0x13,  0xfe,  0x24,
+  0x1c,  0x14,  0x1a,  0x37,  0x95,  0xa9,  0xfe,  0xd9,  0x10,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,
+  0xfe,  0x80,  0x5d,  0x03,  0xb6,  0xfe,  0x03,  0xdc,  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x03,  0xfe,
+  0x03,  0x57,  0xb6,  0x23,  0xfe,  0x00,  0xcc,  0x03,  0xfe,  0x03,  0x57,  0xb6,  0x75,  0x03,  0x09,  0x04,
+  0x4c,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xe1,
+  0xfe,  0x1d,  0x80,  0xa4,  0xfe,  0x0c,  0x90,  0xfe,  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xa3,  0xfe,  0x3c,
+  0x90,  0xfe,  0x30,  0xf4,  0x0b,  0xfe,  0x3c,  0x50,  0xa0,  0x01,  0xfe,  0x82,  0x16,  0x2f,  0x07,  0x2d,
+  0xe0,  0x01,  0xfe,  0xbc,  0x15,  0x09,  0x04,  0x1d,  0x45,  0x01,  0xe7,  0x01,  0xe8,  0x11,  0xfe,  0xe9,
+  0x00,  0x09,  0x04,  0x4c,  0xfe,  0x2c,  0x13,  0x01,  0xfe,  0x14,  0x16,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,
+  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,  0x18,  0xfe,  0x66,  0x01,  0x09,  0x04,  0x4f,  0xfe,
+  0x12,  0x12,  0xfe,  0x03,  0x80,  0x74,  0xfe,  0x01,  0xec,  0x20,  0xfe,  0x80,  0x40,  0x12,  0x20,  0x63,
+  0x27,  0x11,  0xc8,  0x59,  0x1e,  0x20,  0xed,  0x76,  0x20,  0x03,  0xfe,  0x08,  0x1c,  0x05,  0xfe,  0xac,
+  0x00,  0xfe,  0x06,  0x58,  0x05,  0xfe,  0xae,  0x00,  0xfe,  0x07,  0x58,  0x05,  0xfe,  0xb0,  0x00,  0xfe,
+  0x08,  0x58,  0x05,  0xfe,  0xb2,  0x00,  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x24,  0x69,  0x12,  0xc9,
+  0x23,  0x0c,  0x50,  0x0c,  0x3f,  0x13,  0x40,  0x48,  0x5f,  0x17,  0x1d,  0xfe,  0x90,  0x4d,  0xfe,  0x91,
+  0x54,  0x21,  0xfe,  0x08,  0x0f,  0x3e,  0x10,  0x13,  0x42,  0x48,  0x17,  0x4c,  0xfe,  0x90,  0x4d,  0xfe,
+  0x91,  0x54,  0x21,  0xfe,  0x1e,  0x0f,  0x24,  0x10,  0x12,  0x20,  0x78,  0x2c,  0x46,  0x1e,  0x20,  0xed,
+  0x76,  0x20,  0x11,  0xc8,  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x32,  0x0f,  0xea,  0x70,  0xfe,  0x14,  0x1c,
+  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x03,  0x3c,  0xfe,  0x0c,  0x14,  0xee,  0xfe,  0x07,  0xe6,  0x1d,
+  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x03,  0x01,  0x86,  0x78,  0x2c,  0x46,  0xfa,  0xef,  0xfe,  0x42,
+  0x13,  0x2f,  0x07,  0x2d,  0xfe,  0x34,  0x13,  0x0a,  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x36,  0x12,  0xf0,
+  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,
+  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x6f,  0xfe,  0x0e,  0x10,  0x07,  0x7e,  0x45,
+  0xf6,  0xfe,  0xd6,  0xf0,  0xfe,  0x6c,  0x0f,  0x03,  0xfe,  0x44,  0x58,  0x74,  0xfe,  0x01,  0xec,  0x97,
+  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1b,  0x76,  0x27,  0x01,  0xda,  0xfe,
+  0xdd,  0x10,  0x2a,  0xbc,  0x7d,  0xbd,  0x7f,  0x30,  0x2e,  0xd5,  0x07,  0x1b,  0xfe,  0x48,  0x12,  0x07,
+  0x0b,  0xfe,  0x56,  0x12,  0x07,  0x1a,  0xfe,  0x30,  0x12,  0x07,  0xc2,  0x16,  0xfe,  0x3e,  0x11,  0x07,
+  0xfe,  0x23,  0x00,  0x16,  0xfe,  0x4a,  0x11,  0x07,  0x06,  0x16,  0xfe,  0xa8,  0x11,  0x07,  0x19,  0xfe,
+  0x12,  0x12,  0x07,  0x00,  0x16,  0x22,  0x14,  0xc2,  0x01,  0x33,  0x9f,  0x2b,  0x01,  0x08,  0x8c,  0x43,
+  0x03,  0x2b,  0xfe,  0x62,  0x08,  0x0a,  0xca,  0x01,  0xfe,  0x32,  0x0e,  0x11,  0x7e,  0x02,  0x29,  0x2b,
+  0x2f,  0x07,  0x9b,  0xfe,  0xd9,  0x13,  0x79,  0x39,  0x68,  0x3a,  0x77,  0xfe,  0xfc,  0x10,  0x09,  0x04,
+  0x6a,  0xfe,  0x72,  0x12,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x8e,  0xfe,  0xc6,  0x10,  0x1e,  0x58,
+  0xfe,  0x26,  0x13,  0x05,  0x7b,  0x31,  0x7c,  0x77,  0xfe,  0x82,  0x0c,  0x0c,  0x54,  0x18,  0x55,  0x23,
+  0x0c,  0x7b,  0x0c,  0x7c,  0x01,  0xa8,  0x24,  0x69,  0x73,  0x12,  0x58,  0x01,  0xa5,  0xc0,  0x38,  0xc1,
+  0x4e,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x38,  0xfe,  0x05,  0xfa,  0x4e,  0xfe,
+  0x91,  0x10,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x56,  0x18,  0x57,
+  0x83,  0xc0,  0x38,  0xc1,  0x4e,  0xf4,  0xf5,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x00,  0x56,  0xfe,  0xa1,
+  0x56,  0x0c,  0x52,  0x18,  0x53,  0x09,  0x04,  0x6a,  0xfe,  0x1e,  0x12,  0x1e,  0x58,  0xfe,  0x1f,  0x40,
+  0x05,  0x54,  0x31,  0x55,  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x05,  0x56,  0x31,  0x57,  0xfe,  0x44,
+  0x50,  0xfe,  0xc6,  0x50,  0x05,  0x52,  0x31,  0x53,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x05,  0x39,
+  0x31,  0x3a,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x5c,  0x24,  0x06,  0x12,  0xcd,  0x02,  0x5b,
+  0x2b,  0x01,  0x08,  0x1f,  0x44,  0x30,  0x2e,  0xd5,  0x07,  0x06,  0x21,  0x44,  0x2f,  0x07,  0x9b,  0x21,
+  0x5b,  0x01,  0x6e,  0x1c,  0x3d,  0x16,  0x44,  0x09,  0x04,  0x0b,  0xe2,  0x79,  0x39,  0x68,  0x3a,  0xfe,
+  0x0a,  0x55,  0x34,  0xfe,  0x8b,  0x55,  0xbe,  0x39,  0xbf,  0x3a,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,
+  0x02,  0x5b,  0xfe,  0x19,  0x81,  0xaf,  0xfe,  0x19,  0x41,  0x02,  0x5b,  0x2b,  0x01,  0x08,  0x25,  0x32,
+  0x1f,  0xa2,  0x30,  0x2e,  0xd8,  0x4b,  0x1a,  0xfe,  0xa6,  0x12,  0x4b,  0x0b,  0x3b,  0x02,  0x44,  0x01,
+  0x08,  0x25,  0x32,  0x1f,  0xa2,  0x30,  0x2e,  0xd6,  0x07,  0x1a,  0x21,  0x44,  0x01,  0x08,  0x1f,  0xa2,
+  0x30,  0x2e,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x60,  0x05,  0xfe,  0x9c,  0x00,  0x28,  0x84,  0x49,
+  0x04,  0x19,  0x34,  0x9f,  0xfe,  0xbb,  0x45,  0x4b,  0x00,  0x45,  0x3e,  0x06,  0x78,  0x3d,  0xfe,  0xda,
+  0x14,  0x01,  0x6e,  0x87,  0xfe,  0x4b,  0x45,  0xe2,  0x2f,  0x07,  0x9a,  0xe1,  0x05,  0xc6,  0x28,  0x84,
+  0x05,  0x3f,  0x28,  0x34,  0x5e,  0x02,  0x5b,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,
+  0x05,  0x50,  0xb4,  0x0c,  0x50,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xaa,  0x14,  0x02,
+  0x5c,  0x01,  0x08,  0x25,  0x32,  0x1f,  0x44,  0x30,  0x2e,  0xd6,  0x07,  0x06,  0x21,  0x44,  0x01,  0xfe,
+  0x8e,  0x13,  0xfe,  0x42,  0x58,  0xfe,  0x82,  0x14,  0xfe,  0xa4,  0x14,  0x87,  0xfe,  0x4a,  0xf4,  0x0b,
+  0x16,  0x44,  0xfe,  0x4a,  0xf4,  0x06,  0xfe,  0x0c,  0x12,  0x2f,  0x07,  0x9a,  0x85,  0x02,  0x5b,  0x05,
+  0x3f,  0xb4,  0x0c,  0x3f,  0x5e,  0x2b,  0x01,  0x08,  0x26,  0x5c,  0x01,  0xfe,  0xd8,  0x14,  0x02,  0x5c,
+  0x13,  0x06,  0x65,  0xfe,  0xca,  0x12,  0x26,  0xfe,  0xe0,  0x12,  0x72,  0xf1,  0x01,  0x08,  0x23,  0x72,
+  0x03,  0x8f,  0xfe,  0xdc,  0x12,  0x25,  0xfe,  0xdc,  0x12,  0x1f,  0xfe,  0xca,  0x12,  0x5e,  0x2b,  0x01,
+  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,  0xfe,  0xff,  0x7f,
+  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0x1c,
+  0x3d,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,
+  0x03,  0x13,  0x6c,  0xff,  0x02,  0x00,  0x57,  0x48,  0x8b,  0xfe,  0x0b,  0x58,  0x03,  0x0a,  0x50,  0x01,
+  0x82,  0x0a,  0x3f,  0x01,  0x82,  0x03,  0xfc,  0x1c,  0x10,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,
+  0x19,  0x48,  0xfe,  0x00,  0x7d,  0xfe,  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x63,  0x27,
+  0x0c,  0x52,  0x18,  0x53,  0xbe,  0x56,  0xbf,  0x57,  0x03,  0xfe,  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,
+  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x74,  0x03,  0x01,  0xfe,  0x14,  0x18,  0xfe,  0x42,  0x48,  0x5f,  0x60,
+  0x89,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,  0x30,  0x2e,  0xd8,  0x01,  0x08,  0x1f,  0xfe,  0xa2,  0x14,
+  0x30,  0x2e,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x05,  0xc6,  0x28,  0xfe,  0xcc,  0x12,  0x49,  0x04,
+  0x1b,  0xfe,  0xc4,  0x13,  0x23,  0x62,  0x1b,  0xe2,  0x4b,  0xc3,  0x64,  0xfe,  0xe8,  0x13,  0x3b,  0x13,
+  0x06,  0x17,  0xc3,  0x78,  0xdb,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xa1,  0xff,  0x02,  0x83,
+  0x55,  0x62,  0x1a,  0xa4,  0xbb,  0xfe,  0x30,  0x00,  0x8e,  0xe4,  0x17,  0x2c,  0x13,  0x06,  0xfe,  0x56,
+  0x10,  0x62,  0x0b,  0xe1,  0xbb,  0xfe,  0x64,  0x00,  0x8e,  0xe4,  0x0a,  0xfe,  0x64,  0x00,  0x17,  0x93,
+  0x13,  0x06,  0xfe,  0x28,  0x10,  0x62,  0x06,  0xfe,  0x60,  0x13,  0xbb,  0xfe,  0xc8,  0x00,  0x8e,  0xe4,
+  0x0a,  0xfe,  0xc8,  0x00,  0x17,  0x4d,  0x13,  0x06,  0x83,  0xbb,  0xfe,  0x90,  0x01,  0xba,  0xfe,  0x4e,
+  0x14,  0x89,  0xfe,  0x12,  0x10,  0xfe,  0x43,  0xf4,  0x94,  0xfe,  0x56,  0xf0,  0xfe,  0x60,  0x14,  0xfe,
+  0x04,  0xf4,  0x6c,  0xfe,  0x43,  0xf4,  0x93,  0xfe,  0xf3,  0x10,  0xf9,  0x01,  0xfe,  0x22,  0x13,  0x1c,
+  0x3d,  0xfe,  0x10,  0x13,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x69,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
+  0x69,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,  0x19,  0xba,  0xfe,  0x9c,  0x14,  0xb7,
+  0x19,  0x83,  0x60,  0x23,  0xfe,  0x4d,  0xf4,  0x00,  0xdf,  0x89,  0x13,  0x06,  0xfe,  0xb4,  0x56,  0xfe,
+  0xc3,  0x58,  0x03,  0x60,  0x13,  0x0b,  0x03,  0x15,  0x06,  0x01,  0x08,  0x26,  0xe5,  0x15,  0x0b,  0x01,
+  0x08,  0x26,  0xe5,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xe5,  0x72,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x03,
+  0x15,  0x06,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x1a,  0x01,  0x08,  0x26,  0xa6,  0x15,  0x06,  0x01,  0x08,
+  0x26,  0xa6,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x26,  0xa6,  0x72,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x03,
+  0x60,  0x03,  0x1e,  0xcc,  0x07,  0x06,  0xfe,  0x44,  0x13,  0xad,  0x12,  0xcc,  0xfe,  0x49,  0xf4,  0x00,
+  0x3b,  0x72,  0x9f,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xf1,  0x01,  0x08,  0x2f,  0x07,  0xfe,
+  0xe3,  0x00,  0xfe,  0x20,  0x13,  0x1f,  0xfe,  0x5a,  0x15,  0x23,  0x12,  0xcd,  0x01,  0x43,  0x1e,  0xcd,
+  0x07,  0x06,  0x45,  0x09,  0x4a,  0x06,  0x35,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xed,  0x88,  0x07,  0x10,
+  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x80,  0x01,  0x0e,  0x88,
+  0xfe,  0x80,  0xe7,  0x10,  0x07,  0x10,  0x84,  0xfe,  0x45,  0x58,  0x01,  0xe3,  0x88,  0x03,  0x0a,  0x42,
+  0x01,  0x0e,  0x88,  0x0a,  0x51,  0x01,  0x9e,  0x03,  0x0a,  0x42,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xf2,
+  0xfe,  0x49,  0xe4,  0x10,  0xa4,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x0a,  0x51,  0x01,  0x82,  0x03,  0x17,
+  0x10,  0x71,  0x66,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,  0x1c,  0xfe,
+  0x1d,  0xf7,  0x1d,  0x90,  0xfe,  0xf6,  0x15,  0x01,  0xfe,  0xfc,  0x16,  0xe0,  0x91,  0x1d,  0x66,  0xfe,
+  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x03,  0xae,  0x21,  0xfe,  0xe6,  0x15,  0xfe,  0xda,  0x10,  0x17,  0x10,
+  0x71,  0x05,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x19,  0xfe,  0x18,  0x58,  0x05,  0xfe,  0x66,  0x01,
+  0xfe,  0x19,  0x58,  0x91,  0x19,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,  0x50,  0x66,
+  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x19,  0x90,  0xfe,  0x40,  0x16,  0xfe,  0xb6,
+  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x18,  0x16,  0xfe,  0x9c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x83,
+  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x38,  0x90,  0xfe,  0x62,  0x16,  0xfe,
+  0x94,  0x14,  0xfe,  0x10,  0x13,  0x91,  0x38,  0x66,  0x1b,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
+  0x03,  0xae,  0x21,  0xfe,  0x56,  0x16,  0xfe,  0x6c,  0x10,  0x17,  0x10,  0x71,  0xfe,  0x30,  0xbc,  0xfe,
+  0xb2,  0xbc,  0x91,  0xc5,  0x66,  0x1b,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xc5,  0x90,  0xfe,  0x9a,
+  0x16,  0xfe,  0x5c,  0x14,  0x34,  0x03,  0xae,  0x21,  0xfe,  0x86,  0x16,  0xfe,  0x42,  0x10,  0xfe,  0x02,
+  0xf6,  0x10,  0x71,  0xfe,  0x18,  0xfe,  0x54,  0xfe,  0x19,  0xfe,  0x55,  0xfc,  0xfe,  0x1d,  0xf7,  0x4f,
+  0x90,  0xfe,  0xc0,  0x16,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x91,  0x4f,  0x47,  0xfe,  0x83,  0x58,
+  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x10,  0xfe,  0x81,  0xe7,  0x10,  0x11,  0xfe,  0xdd,  0x00,  0x63,
+  0x27,  0x03,  0x63,  0x27,  0xfe,  0x12,  0x45,  0x21,  0xfe,  0xb0,  0x16,  0x14,  0x06,  0x37,  0x95,  0xa9,
+  0x02,  0x29,  0xfe,  0x39,  0xf0,  0xfe,  0x04,  0x17,  0x23,  0x03,  0xfe,  0x7e,  0x18,  0x1c,  0x1a,  0x5d,
+  0x13,  0x0d,  0x03,  0x71,  0x05,  0xcb,  0x1c,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x78,  0x2c,
+  0x46,  0x2f,  0x07,  0x2d,  0xfe,  0x3c,  0x13,  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x3c,  0x8a,  0x0a,
+  0x42,  0x01,  0x0e,  0xb0,  0xfe,  0x3e,  0x12,  0xf0,  0xfe,  0x45,  0x48,  0x01,  0xe3,  0xfe,  0x00,  0xcc,
+  0xb0,  0xfe,  0xf3,  0x13,  0x3d,  0x75,  0x07,  0x10,  0xa3,  0x0a,  0x80,  0x01,  0x0e,  0xf2,  0x01,  0x6f,
+  0xfe,  0x16,  0x10,  0x07,  0x7e,  0x85,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xf6,  0xfe,  0xd6,  0xf0,
+  0xfe,  0x24,  0x17,  0x17,  0x0b,  0x03,  0xfe,  0x9c,  0xe7,  0x0b,  0x0f,  0xfe,  0x15,  0x00,  0x59,  0x76,
+  0x27,  0x01,  0xda,  0x17,  0x06,  0x03,  0x3c,  0x8a,  0x09,  0x4a,  0x1d,  0x35,  0x11,  0x2d,  0x01,  0x6f,
+  0x17,  0x06,  0x03,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x79,  0xc7,  0x68,  0xc8,  0xfe,  0x48,  0x55,
+  0x34,  0xfe,  0xc9,  0x55,  0x03,  0x1e,  0x98,  0x73,  0x12,  0x98,  0x03,  0x0a,  0x99,  0x01,  0x0e,  0xf0,
+  0x0a,  0x40,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x16,  0xfe,  0xf0,  0x17,  0x73,  0x75,  0x03,  0x0a,  0x42,
+  0x01,  0x0e,  0x07,  0x10,  0x45,  0x0a,  0x51,  0x01,  0x9e,  0x0a,  0x40,  0x01,  0x0e,  0x73,  0x75,  0x03,
+  0xfe,  0x4e,  0xe4,  0x1a,  0x64,  0xfe,  0x24,  0x18,  0x05,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0x5b,
+  0xfe,  0x4e,  0xe4,  0xc2,  0x64,  0xfe,  0x36,  0x18,  0x05,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1b,
+  0xdc,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x64,  0xfe,  0x48,  0x18,  0x05,  0xfe,  0x94,  0x00,  0xfe,
+  0x02,  0xe6,  0x19,  0xfe,  0x08,  0x10,  0x05,  0xfe,  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x2c,  0xfe,  0x4e,
+  0x45,  0xfe,  0x0c,  0x12,  0xaf,  0xff,  0x04,  0x68,  0x54,  0xde,  0x1c,  0x69,  0x03,  0x07,  0x7a,  0xfe,
+  0x5a,  0xf0,  0xfe,  0x74,  0x18,  0x24,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1b,  0xfe,  0x5a,
+  0xf0,  0xfe,  0x82,  0x18,  0x24,  0xc3,  0xfe,  0x26,  0x10,  0x07,  0x1a,  0x5d,  0x24,  0x2c,  0xdc,  0x07,
+  0x0b,  0x5d,  0x24,  0x93,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x5d,  0x24,  0x4d,  0x9f,  0xad,  0x03,  0x14,
+  0xfe,  0x09,  0x00,  0x01,  0x33,  0xfe,  0x04,  0xfe,  0x7d,  0x05,  0x7f,  0xf9,  0x03,  0x25,  0xfe,  0xca,
+  0x18,  0xfe,  0x14,  0xf0,  0x08,  0x65,  0xfe,  0xc6,  0x18,  0x03,  0xff,  0x1a,  0x00,  0x00,
+};
+
+STATIC unsigned short _adv_asc3550_size =
+        sizeof(_adv_asc3550_buf); /* 0x13AD */
+STATIC ADV_DCNT _adv_asc3550_chksum =
+        0x04D52DDDUL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC unsigned char _adv_asc38C0800_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0xf0,  0x00,  0xfc,  0x00,  0x16,  0x18,  0xe4,  0x01,  0x00,  0x48,  0xe4,
+  0x18,  0x80,  0x03,  0xf6,  0x02,  0x00,  0xce,  0x19,  0x00,  0xfa,  0xff,  0xff,  0x1c,  0x0f,  0x00,  0xf6,
+  0x9e,  0xe7,  0xff,  0x00,  0x82,  0xe7,  0x00,  0xea,  0x01,  0xfa,  0x01,  0xe6,  0x09,  0xe7,  0x55,  0xf0,
+  0x01,  0xf6,  0x03,  0x00,  0x04,  0x00,  0x10,  0x00,  0x1e,  0xf0,  0x85,  0xf0,  0x18,  0xf4,  0x08,  0x00,
+  0xbc,  0x00,  0x38,  0x54,  0x00,  0xec,  0xd5,  0xf0,  0x82,  0x0d,  0x00,  0xe6,  0x86,  0xf0,  0xb1,  0xf0,
+  0x98,  0x57,  0x01,  0xfc,  0xb4,  0x00,  0xd4,  0x01,  0x0c,  0x1c,  0x3e,  0x1c,  0x3c,  0x00,  0xbb,  0x00,
+  0x00,  0x10,  0xba,  0x19,  0x02,  0x80,  0x32,  0xf0,  0x7c,  0x0d,  0x02,  0x13,  0xba,  0x13,  0x18,  0x40,
+  0x00,  0x57,  0x01,  0xea,  0x02,  0xfc,  0x03,  0xfc,  0x3e,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x74,  0x01,
+  0x76,  0x01,  0xb9,  0x54,  0x3e,  0x57,  0x00,  0x80,  0x03,  0xe6,  0xb6,  0x00,  0xc0,  0x00,  0x01,  0x01,
+  0x3e,  0x01,  0x7a,  0x01,  0xca,  0x08,  0xce,  0x10,  0x16,  0x11,  0x04,  0x12,  0x08,  0x12,  0x02,  0x4a,
+  0xbb,  0x55,  0x3c,  0x56,  0x03,  0x58,  0x1b,  0x80,  0x30,  0xe4,  0x4b,  0xe4,  0x5d,  0xf0,  0x02,  0xfa,
+  0x20,  0x00,  0x32,  0x00,  0x40,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,  0x68,  0x01,  0x6a,  0x01,
+  0x70,  0x01,  0x72,  0x01,  0x78,  0x01,  0x7c,  0x01,  0x62,  0x0a,  0x86,  0x0d,  0x06,  0x13,  0x4c,  0x1c,
+  0x04,  0x80,  0x4a,  0xe4,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x0c,  0x00,  0x0f,  0x00,  0x47,  0x00,
+  0xbe,  0x00,  0x00,  0x01,  0x20,  0x11,  0x5c,  0x16,  0x32,  0x1c,  0x38,  0x1c,  0x4e,  0x1c,  0x10,  0x44,
+  0x00,  0x4c,  0x04,  0xea,  0x5c,  0xf0,  0xa7,  0xf0,  0x04,  0xf6,  0x03,  0xfa,  0x05,  0x00,  0x34,  0x00,
+  0x36,  0x00,  0x98,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x4a,  0x0b,  0x42,  0x0c,  0x12,  0x0f,
+  0x0c,  0x10,  0x22,  0x11,  0x0a,  0x12,  0x04,  0x13,  0x30,  0x1c,  0x02,  0x48,  0x00,  0x4e,  0x42,  0x54,
+  0x44,  0x55,  0xbd,  0x56,  0x06,  0x83,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,  0x59,  0xf0,  0xb8,  0xf0,
+  0x4b,  0xf4,  0x06,  0xf7,  0x0e,  0xf7,  0x04,  0xfc,  0x05,  0xfc,  0x06,  0x00,  0x19,  0x00,  0x33,  0x00,
+  0x9b,  0x00,  0xa4,  0x00,  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe1,  0x00,  0xe7,  0x00,  0xe2,  0x03,
+  0x08,  0x0f,  0x02,  0x10,  0x04,  0x10,  0x0a,  0x10,  0x0a,  0x13,  0x0c,  0x13,  0x12,  0x13,  0x24,  0x14,
+  0x34,  0x14,  0x04,  0x16,  0x08,  0x16,  0xa4,  0x17,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x08,  0x44,
+  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x01,  0x48,  0x68,  0x54,  0x3a,  0x55,  0x83,  0x55,
+  0xe5,  0x55,  0xb0,  0x57,  0x01,  0x58,  0x83,  0x59,  0x05,  0xe6,  0x0b,  0xf0,  0x0c,  0xf0,  0x04,  0xf8,
+  0x05,  0xf8,  0x07,  0x00,  0x0a,  0x00,  0x1c,  0x00,  0x1e,  0x00,  0x9e,  0x00,  0xa8,  0x00,  0xaa,  0x00,
+  0xb9,  0x00,  0xe0,  0x00,  0x22,  0x01,  0x26,  0x01,  0x79,  0x01,  0x7e,  0x01,  0xc4,  0x01,  0xc6,  0x01,
+  0x80,  0x02,  0x5e,  0x03,  0xee,  0x04,  0x9a,  0x06,  0xf8,  0x07,  0x62,  0x08,  0x68,  0x08,  0x69,  0x08,
+  0xd6,  0x08,  0xe9,  0x09,  0xfa,  0x0b,  0x2e,  0x0f,  0x12,  0x10,  0x1a,  0x10,  0xed,  0x10,  0xf1,  0x10,
+  0x2a,  0x11,  0x06,  0x12,  0x0c,  0x12,  0x3e,  0x12,  0x10,  0x13,  0x16,  0x13,  0x1e,  0x13,  0x46,  0x14,
+  0x76,  0x14,  0x82,  0x14,  0x36,  0x15,  0xca,  0x15,  0x6b,  0x18,  0xbe,  0x18,  0xca,  0x18,  0xe6,  0x19,
+  0x12,  0x1c,  0x46,  0x1c,  0x9c,  0x32,  0x00,  0x40,  0x0e,  0x47,  0xfe,  0x9c,  0xf0,  0x2b,  0x02,  0xfe,
+  0xac,  0x0d,  0xff,  0x10,  0x00,  0x00,  0xd7,  0xfe,  0xe8,  0x19,  0x00,  0xd6,  0xfe,  0x84,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x4c,  0x00,  0x5b,  0xff,  0x04,  0x00,  0x00,  0x11,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x11,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xd6,
+  0x2c,  0x99,  0x0a,  0x01,  0xfe,  0xc2,  0x0f,  0xfe,  0x04,  0xf7,  0xd6,  0x99,  0x0a,  0x42,  0x2c,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x91,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf4,  0x01,  0xfe,  0x8f,  0xf0,  0xa7,  0x03,  0x5d,  0x4d,  0x02,  0xfe,  0xc8,  0x0d,
+  0x01,  0xfe,  0x38,  0x0e,  0xfe,  0xdd,  0x12,  0xfe,  0xfc,  0x10,  0xfe,  0x28,  0x1c,  0x03,  0xfe,  0xa6,
+  0x00,  0xfe,  0xd3,  0x12,  0x41,  0x14,  0xfe,  0xa6,  0x00,  0xc2,  0xfe,  0x48,  0xf0,  0xfe,  0x8a,  0x02,
+  0xfe,  0x49,  0xf0,  0xfe,  0xa4,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc2,  0x02,  0xfe,  0x46,  0xf0,  0xfe,
+  0x54,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x5a,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x48,  0x02,  0xfe,  0x44,
+  0xf0,  0xfe,  0x4c,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x50,  0x02,  0x18,  0x0a,  0xaa,  0x18,  0x06,  0x14,
+  0xa1,  0x02,  0x2b,  0xfe,  0x00,  0x1c,  0xe7,  0xfe,  0x02,  0x1c,  0xe6,  0xfe,  0x1e,  0x1c,  0xfe,  0xe9,
+  0x10,  0x01,  0xfe,  0x18,  0x18,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xce,  0x09,  0x70,  0x01,  0xa8,
+  0x02,  0x2b,  0x15,  0x59,  0x39,  0xa2,  0x01,  0xfe,  0x58,  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xbd,
+  0x10,  0x09,  0x70,  0x01,  0x87,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x18,  0x06,
+  0x14,  0xa1,  0x2c,  0x1c,  0x2b,  0xfe,  0x3d,  0xf0,  0xfe,  0x06,  0x02,  0x23,  0xfe,  0x98,  0x02,  0xfe,
+  0x5a,  0x1c,  0xf8,  0xfe,  0x14,  0x1c,  0x15,  0xfe,  0x30,  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,
+  0x18,  0x06,  0x14,  0xa1,  0x02,  0xd7,  0x22,  0x20,  0x07,  0x11,  0x35,  0xfe,  0x69,  0x10,  0x18,  0x06,
+  0x14,  0xa1,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0x43,  0x13,  0x20,  0xfe,  0x05,  0xf6,  0xce,  0x01,  0xfe,
+  0x4a,  0x17,  0x08,  0x54,  0x58,  0x37,  0x12,  0x2f,  0x42,  0x92,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
+  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x01,  0x73,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0xc8,  0x54,  0x6b,  0xfe,  0x10,  0x03,  0x01,  0xfe,  0x82,  0x16,  0x02,  0x2b,
+  0x2c,  0x4f,  0xfe,  0x02,  0xe8,  0x2a,  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,
+  0x27,  0xf0,  0xfe,  0xe0,  0x01,  0xfe,  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xa7,  0xfe,  0x40,  0x1c,  0x1c,
+  0xd9,  0xfe,  0x26,  0xf0,  0xfe,  0x5a,  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x48,  0x03,  0xfe,  0x11,  0xf0,
+  0xa7,  0xfe,  0xef,  0x10,  0xfe,  0x9f,  0xf0,  0xfe,  0x68,  0x03,  0xf9,  0x10,  0xfe,  0x11,  0x00,  0x02,
+  0x65,  0x2c,  0xfe,  0x48,  0x1c,  0xf9,  0x08,  0x05,  0x1b,  0xfe,  0x18,  0x13,  0x21,  0x22,  0xa3,  0xb7,
+  0x13,  0xa3,  0x09,  0x46,  0x01,  0x0e,  0xb7,  0x78,  0x01,  0xfe,  0xb4,  0x16,  0x12,  0xd1,  0x1c,  0xd9,
+  0xfe,  0x01,  0xf0,  0xd9,  0xfe,  0x82,  0xf0,  0xfe,  0x96,  0x03,  0xfa,  0x12,  0xfe,  0xe4,  0x00,  0x27,
+  0xfe,  0xa8,  0x03,  0x1c,  0x34,  0x1d,  0xfe,  0xb8,  0x03,  0x01,  0x4b,  0xfe,  0x06,  0xf0,  0xfe,  0xc8,
+  0x03,  0x95,  0x86,  0xfe,  0x0a,  0xf0,  0xfe,  0x8a,  0x06,  0x02,  0x24,  0x03,  0x70,  0x28,  0x17,  0xfe,
+  0xfa,  0x04,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,  0xd8,  0xf9,  0x2c,  0x99,  0x19,
+  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x74,  0x01,  0xaf,  0x8c,
+  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x17,  0xda,  0x09,  0xd1,  0x01,  0x0e,  0x8d,  0x51,  0x64,  0x79,
+  0x2a,  0x03,  0x70,  0x28,  0xfe,  0x10,  0x12,  0x15,  0x6d,  0x01,  0x36,  0x7b,  0xfe,  0x6a,  0x02,  0x02,
+  0xd8,  0xc7,  0x81,  0xc8,  0x83,  0x1c,  0x24,  0x27,  0xfe,  0x40,  0x04,  0x1d,  0xfe,  0x3c,  0x04,  0x3b,
+  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x4e,  0x12,  0x2d,  0xff,  0x02,  0x00,  0x10,  0x01,  0x0b,
+  0x1d,  0xfe,  0xe4,  0x04,  0x2d,  0x01,  0x0b,  0x1d,  0x24,  0x33,  0x31,  0xde,  0xfe,  0x4c,  0x44,  0xfe,
+  0x4c,  0x12,  0x51,  0xfe,  0x44,  0x48,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0x4f,  0x79,  0x2a,
+  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x62,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x2a,  0x13,  0x32,
+  0x07,  0x82,  0xfe,  0x52,  0x13,  0xfe,  0x20,  0x10,  0x0f,  0x6f,  0xfe,  0x4c,  0x54,  0x6b,  0xda,  0xfe,
+  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x40,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x08,  0x13,  0x32,  0x07,
+  0x82,  0xfe,  0x30,  0x13,  0x08,  0x05,  0x1b,  0xfe,  0x1c,  0x12,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,
+  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x2d,  0x12,  0xfe,  0xe6,
+  0x00,  0xfe,  0x1c,  0x90,  0xfe,  0x40,  0x5c,  0x04,  0x15,  0x9d,  0x01,  0x36,  0x02,  0x2b,  0xfe,  0x42,
+  0x5b,  0x99,  0x19,  0xfe,  0x46,  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x87,  0x80,  0xfe,
+  0x31,  0xe4,  0x5b,  0x08,  0x05,  0x0a,  0xfe,  0x84,  0x13,  0xfe,  0x20,  0x80,  0x07,  0x19,  0xfe,  0x7c,
+  0x12,  0x53,  0x05,  0x06,  0xfe,  0x6c,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x28,  0x17,  0xfe,  0x90,  0x05,
+  0xfe,  0x31,  0xe4,  0x5a,  0x53,  0x05,  0x0a,  0xfe,  0x56,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x28,  0xfe,
+  0x4e,  0x12,  0x67,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x48,  0x05,  0x1c,  0x34,  0xfe,  0x89,  0x48,
+  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x56,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0x12,  0xfe,  0xe3,  0x00,
+  0x21,  0x53,  0xfe,  0x4a,  0xf0,  0xfe,  0x76,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0x70,  0x05,  0x88,  0x25,
+  0xfe,  0x21,  0x00,  0xab,  0x25,  0xfe,  0x22,  0x00,  0xaa,  0x25,  0x58,  0xfe,  0x09,  0x48,  0xff,  0x02,
+  0x00,  0x10,  0x27,  0xfe,  0x86,  0x05,  0x26,  0xfe,  0xa8,  0x05,  0xfe,  0xe2,  0x08,  0x53,  0x05,  0xcb,
+  0x4d,  0x01,  0xb0,  0x25,  0x06,  0x13,  0xd3,  0x39,  0xfe,  0x27,  0x01,  0x08,  0x05,  0x1b,  0xfe,  0x22,
+  0x12,  0x41,  0x01,  0xb2,  0x15,  0x9d,  0x08,  0x05,  0x06,  0x4d,  0x15,  0xfe,  0x0d,  0x00,  0x01,  0x36,
+  0x7b,  0xfe,  0x64,  0x0d,  0x02,  0x24,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0xeb,  0x03,  0x5c,  0x28,  0xfe,
+  0x36,  0x13,  0x41,  0x01,  0xb2,  0x26,  0xfe,  0x18,  0x06,  0x09,  0x06,  0x53,  0x05,  0x1f,  0xfe,  0x02,
+  0x12,  0x50,  0x01,  0xfe,  0x9e,  0x15,  0x1d,  0xfe,  0x0e,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,
+  0xe5,  0x00,  0x03,  0x5c,  0xc1,  0x0c,  0x5c,  0x03,  0xcd,  0x28,  0xfe,  0x62,  0x12,  0x03,  0x45,  0x28,
+  0xfe,  0x5a,  0x13,  0x01,  0xfe,  0x0c,  0x19,  0x01,  0xfe,  0x76,  0x19,  0xfe,  0x43,  0x48,  0xc4,  0xcc,
+  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0x8b,  0xc4,  0x6e,  0x41,  0x01,  0xb2,
+  0x26,  0xfe,  0x82,  0x06,  0x53,  0x05,  0x1a,  0xe9,  0x91,  0x09,  0x59,  0x01,  0xfe,  0xcc,  0x15,  0x1d,
+  0xfe,  0x78,  0x06,  0x12,  0xa5,  0x01,  0x4b,  0x12,  0xfe,  0xe5,  0x00,  0x03,  0x45,  0xc1,  0x0c,  0x45,
+  0x18,  0x06,  0x01,  0xb2,  0xfa,  0x76,  0x74,  0x01,  0xaf,  0x8c,  0x12,  0xfe,  0xe2,  0x00,  0x27,  0xdb,
+  0x1c,  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0xb6,  0x06,  0x94,  0xfe,  0x6c,  0x07,  0xfe,  0x06,  0xf0,  0xfe,
+  0x74,  0x07,  0x95,  0x86,  0x02,  0x24,  0x08,  0x05,  0x0a,  0xfe,  0x2e,  0x12,  0x16,  0x19,  0x01,  0x0b,
+  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0xfe,  0x99,  0xa4,  0x01,
+  0x0b,  0x16,  0x00,  0x02,  0xfe,  0x42,  0x08,  0x68,  0x05,  0x1a,  0xfe,  0x38,  0x12,  0x08,  0x05,  0x1a,
+  0xfe,  0x30,  0x13,  0x16,  0xfe,  0x1b,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x00,  0x01,
+  0x0b,  0x16,  0x00,  0x01,  0x0b,  0x16,  0x06,  0x01,  0x0b,  0x16,  0x00,  0x02,  0xe2,  0x6c,  0x58,  0xbe,
+  0x50,  0xfe,  0x9a,  0x81,  0x55,  0x1b,  0x7a,  0xfe,  0x42,  0x07,  0x09,  0x1b,  0xfe,  0x09,  0x6f,  0xba,
+  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x69,  0x6d,  0x8b,  0x6c,  0x7f,  0x27,  0xfe,  0x54,  0x07,  0x1c,
+  0x34,  0xfe,  0x0a,  0xf0,  0xfe,  0x42,  0x07,  0x95,  0x86,  0x94,  0xfe,  0x6c,  0x07,  0x02,  0x24,  0x01,
+  0x4b,  0x02,  0xdb,  0x16,  0x1f,  0x02,  0xdb,  0xfe,  0x9c,  0xf7,  0xdc,  0xfe,  0x2c,  0x90,  0xfe,  0xae,
+  0x90,  0x56,  0xfe,  0xda,  0x07,  0x0c,  0x60,  0x14,  0x61,  0x08,  0x54,  0x5a,  0x37,  0x22,  0x20,  0x07,
+  0x11,  0xfe,  0x0e,  0x12,  0x8d,  0xfe,  0x80,  0x80,  0x39,  0x20,  0x6a,  0x2a,  0xfe,  0x06,  0x10,  0xfe,
+  0x83,  0xe7,  0xfe,  0x48,  0x00,  0xab,  0xfe,  0x03,  0x40,  0x08,  0x54,  0x5b,  0x37,  0x01,  0xb3,  0xb8,
+  0xfe,  0x1f,  0x40,  0x13,  0x62,  0x01,  0xef,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,
+  0xfe,  0xc6,  0x51,  0x88,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,  0xfe,  0x0c,
+  0x90,  0xfe,  0x8e,  0x90,  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x0c,  0x3d,  0x14,  0x3e,  0xfe,  0x4a,
+  0x10,  0x08,  0x05,  0x5a,  0xfe,  0x2a,  0x12,  0xfe,  0x2c,  0x90,  0xfe,  0xae,  0x90,  0x0c,  0x60,  0x14,
+  0x61,  0x08,  0x05,  0x5b,  0x8b,  0x01,  0xb3,  0xfe,  0x1f,  0x80,  0x13,  0x62,  0xfe,  0x44,  0x90,  0xfe,
+  0xc6,  0x90,  0x0c,  0x3f,  0x14,  0x40,  0xfe,  0x08,  0x90,  0xfe,  0x8a,  0x90,  0x0c,  0x5e,  0x14,  0x5f,
+  0xfe,  0x40,  0x90,  0xfe,  0xc2,  0x90,  0x0c,  0x3d,  0x14,  0x3e,  0x0c,  0x2e,  0x14,  0x3c,  0x21,  0x0c,
+  0x49,  0x0c,  0x63,  0x08,  0x54,  0x1f,  0x37,  0x2c,  0x0f,  0xfe,  0x4e,  0x11,  0x27,  0xdd,  0xfe,  0x9e,
+  0xf0,  0xfe,  0x76,  0x08,  0xbc,  0x17,  0x34,  0x2c,  0x77,  0xe6,  0xc5,  0xfe,  0x9a,  0x08,  0xc6,  0xfe,
+  0xb8,  0x08,  0x94,  0xfe,  0x8e,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x94,  0x08,  0x95,  0x86,  0x02,  0x24,
+  0x01,  0x4b,  0xfe,  0xc9,  0x10,  0x16,  0x1f,  0xfe,  0xc9,  0x10,  0x68,  0x05,  0x06,  0xfe,  0x10,  0x12,
+  0x68,  0x05,  0x0a,  0x4e,  0x08,  0x05,  0x0a,  0xfe,  0x90,  0x12,  0xfe,  0x2e,  0x1c,  0x02,  0xfe,  0x18,
+  0x0b,  0x68,  0x05,  0x06,  0x4e,  0x68,  0x05,  0x0a,  0xfe,  0x7a,  0x12,  0xfe,  0x2c,  0x1c,  0xfe,  0xaa,
+  0xf0,  0xfe,  0xd2,  0x09,  0xfe,  0xac,  0xf0,  0xfe,  0x00,  0x09,  0x02,  0xfe,  0xde,  0x09,  0xfe,  0xb7,
+  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0x02,  0xf6,  0x1a,  0x50,  0xfe,  0x70,  0x18,  0xfe,  0xf1,  0x18,  0xfe,
+  0x40,  0x55,  0xfe,  0xe1,  0x55,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0xfe,  0x14,  0x59,  0xfe,  0x95,
+  0x59,  0x1c,  0x85,  0xfe,  0x8c,  0xf0,  0xfe,  0xfc,  0x08,  0xfe,  0xac,  0xf0,  0xfe,  0xf0,  0x08,  0xb5,
+  0xfe,  0xcb,  0x10,  0xfe,  0xad,  0xf0,  0xfe,  0x0c,  0x09,  0x02,  0xfe,  0x18,  0x0b,  0xb6,  0xfe,  0xbf,
+  0x10,  0xfe,  0x2b,  0xf0,  0x85,  0xf4,  0x1e,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xc2,  0xfe,  0xd2,
+  0xf0,  0x85,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x17,  0x85,  0x03,  0xd2,  0x1e,  0x06,  0x17,  0x85,  0xc5,
+  0x4a,  0xc6,  0x4a,  0xb5,  0xb6,  0xfe,  0x89,  0x10,  0x74,  0x67,  0x2d,  0x15,  0x9d,  0x01,  0x36,  0x10,
+  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x65,  0x10,  0x80,  0x02,  0x65,  0xfe,  0x98,  0x80,  0xfe,  0x19,
+  0xe4,  0x0a,  0xfe,  0x1a,  0x12,  0x51,  0xfe,  0x19,  0x82,  0xfe,  0x6c,  0x18,  0xfe,  0x44,  0x54,  0xbe,
+  0xfe,  0x19,  0x81,  0xfe,  0x74,  0x18,  0x8f,  0x90,  0x17,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0x08,  0x05,
+  0x5a,  0xec,  0x03,  0x2e,  0x29,  0x3c,  0x0c,  0x3f,  0x14,  0x40,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x6c,
+  0x18,  0xfe,  0xed,  0x18,  0xfe,  0x44,  0x54,  0xfe,  0xe5,  0x54,  0x3a,  0x3f,  0x3b,  0x40,  0x03,  0x49,
+  0x29,  0x63,  0x8f,  0xfe,  0xe3,  0x54,  0xfe,  0x74,  0x18,  0xfe,  0xf5,  0x18,  0x8f,  0xfe,  0xe3,  0x54,
+  0x90,  0xc0,  0x56,  0xfe,  0xce,  0x08,  0x02,  0x4a,  0xfe,  0x37,  0xf0,  0xfe,  0xda,  0x09,  0xfe,  0x8b,
+  0xf0,  0xfe,  0x60,  0x09,  0x02,  0x4a,  0x08,  0x05,  0x0a,  0x23,  0xfe,  0xfa,  0x0a,  0x3a,  0x49,  0x3b,
+  0x63,  0x56,  0xfe,  0x3e,  0x0a,  0x0f,  0xfe,  0xc0,  0x07,  0x41,  0x98,  0x00,  0xad,  0xfe,  0x01,  0x59,
+  0xfe,  0x52,  0xf0,  0xfe,  0x0c,  0x0a,  0x8f,  0x7a,  0xfe,  0x24,  0x0a,  0x3a,  0x49,  0x8f,  0xfe,  0xe3,
+  0x54,  0x57,  0x49,  0x7d,  0x63,  0xfe,  0x14,  0x58,  0xfe,  0x95,  0x58,  0x02,  0x4a,  0x3a,  0x49,  0x3b,
+  0x63,  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0xbe,  0x57,  0x49,  0x57,  0x63,  0x02,  0x4a,  0x08,  0x05,
+  0x5a,  0xfe,  0x82,  0x12,  0x08,  0x05,  0x1f,  0xfe,  0x66,  0x13,  0x22,  0x62,  0xb7,  0xfe,  0x03,  0xa1,
+  0xfe,  0x83,  0x80,  0xfe,  0xc8,  0x44,  0xfe,  0x2e,  0x13,  0xfe,  0x04,  0x91,  0xfe,  0x86,  0x91,  0x6a,
+  0x2a,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x56,  0xe0,  0x03,  0x60,  0x29,  0x61,  0x0c,  0x7f,  0x14,
+  0x80,  0x57,  0x60,  0x7d,  0x61,  0x01,  0xb3,  0xb8,  0x6a,  0x2a,  0x13,  0x62,  0x9b,  0x2e,  0x9c,  0x3c,
+  0x3a,  0x3f,  0x3b,  0x40,  0x90,  0xc0,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0x01,  0xef,
+  0xfe,  0x36,  0x10,  0x21,  0x0c,  0x7f,  0x0c,  0x80,  0x3a,  0x3f,  0x3b,  0x40,  0xe4,  0x08,  0x05,  0x1f,
+  0x17,  0xe0,  0x3a,  0x3d,  0x3b,  0x3e,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0x03,  0x5e,  0x29,  0x5f,
+  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,  0x57,  0x49,  0x7d,  0x63,  0x02,  0xfe,  0xf4,  0x09,  0x08,  0x05,
+  0x1f,  0x17,  0xe0,  0x08,  0x05,  0xfe,  0xf7,  0x00,  0x37,  0xbe,  0xfe,  0x19,  0x81,  0x50,  0xfe,  0x10,
+  0x90,  0xfe,  0x92,  0x90,  0xfe,  0xd3,  0x10,  0x32,  0x07,  0xa6,  0x17,  0xfe,  0x08,  0x09,  0x12,  0xa6,
+  0x08,  0x05,  0x0a,  0xfe,  0x14,  0x13,  0x03,  0x3d,  0x29,  0x3e,  0x56,  0xfe,  0x08,  0x09,  0xfe,  0x0c,
+  0x58,  0xfe,  0x8d,  0x58,  0x02,  0x4a,  0x21,  0x41,  0xfe,  0x19,  0x80,  0xe7,  0x08,  0x05,  0x0a,  0xfe,
+  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,  0xf4,  0xc2,  0xfe,  0xd1,  0xf0,  0xe2,  0x15,  0x7e,
+  0x01,  0x36,  0x10,  0xfe,  0x44,  0x00,  0xfe,  0x8e,  0x10,  0xfe,  0x6c,  0x19,  0x57,  0x3d,  0xfe,  0xed,
+  0x19,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0xf4,  0x1e,  0xfe,  0x00,  0xff,  0x35,  0xfe,
+  0x74,  0x10,  0xc2,  0xfe,  0xd2,  0xf0,  0xfe,  0xa6,  0x0b,  0xfe,  0x76,  0x18,  0x1e,  0x19,  0x8a,  0x03,
+  0xd2,  0x1e,  0x06,  0xfe,  0x08,  0x13,  0x10,  0xfe,  0x16,  0x00,  0x02,  0x65,  0xfe,  0xd1,  0xf0,  0xfe,
+  0xb8,  0x0b,  0x15,  0x7e,  0x01,  0x36,  0x10,  0xfe,  0x17,  0x00,  0xfe,  0x42,  0x10,  0xfe,  0xce,  0xf0,
+  0xfe,  0xbe,  0x0b,  0xfe,  0x3c,  0x10,  0xfe,  0xcd,  0xf0,  0xfe,  0xca,  0x0b,  0x10,  0xfe,  0x22,  0x00,
+  0x02,  0x65,  0xfe,  0xcb,  0xf0,  0xfe,  0xd6,  0x0b,  0x10,  0xfe,  0x24,  0x00,  0x02,  0x65,  0xfe,  0xd0,
+  0xf0,  0xfe,  0xe0,  0x0b,  0x10,  0x9e,  0xe5,  0xfe,  0xcf,  0xf0,  0xfe,  0xea,  0x0b,  0x10,  0x58,  0xfe,
+  0x10,  0x10,  0xfe,  0xcc,  0xf0,  0xe2,  0x68,  0x05,  0x1f,  0x4d,  0x10,  0xfe,  0x12,  0x00,  0x2c,  0x0f,
+  0xfe,  0x4e,  0x11,  0x27,  0xfe,  0x00,  0x0c,  0xfe,  0x9e,  0xf0,  0xfe,  0x14,  0x0c,  0xbc,  0x17,  0x34,
+  0x2c,  0x77,  0xe6,  0xc5,  0x24,  0xc6,  0x24,  0x2c,  0xfa,  0x27,  0xfe,  0x20,  0x0c,  0x1c,  0x34,  0x94,
+  0xfe,  0x3c,  0x0c,  0x95,  0x86,  0xc5,  0xdc,  0xc6,  0xdc,  0x02,  0x24,  0x01,  0x4b,  0xfe,  0xdb,  0x10,
+  0x12,  0xfe,  0xe8,  0x00,  0xb5,  0xb6,  0x74,  0xc7,  0x81,  0xc8,  0x83,  0xfe,  0x89,  0xf0,  0x24,  0x33,
+  0x31,  0xe1,  0xc7,  0x81,  0xc8,  0x83,  0x27,  0xfe,  0x66,  0x0c,  0x1d,  0x24,  0x33,  0x31,  0xdf,  0xbc,
+  0x4e,  0x10,  0xfe,  0x42,  0x00,  0x02,  0x65,  0x7c,  0x06,  0xfe,  0x81,  0x49,  0x17,  0xfe,  0x2c,  0x0d,
+  0x08,  0x05,  0x0a,  0xfe,  0x44,  0x13,  0x10,  0x00,  0x55,  0x0a,  0xfe,  0x54,  0x12,  0x55,  0xfe,  0x28,
+  0x00,  0x23,  0xfe,  0x9a,  0x0d,  0x09,  0x46,  0x01,  0x0e,  0x07,  0x00,  0x66,  0x44,  0xfe,  0x28,  0x00,
+  0xfe,  0xe2,  0x10,  0x01,  0xf5,  0x01,  0xf6,  0x09,  0xa4,  0x01,  0xfe,  0x26,  0x0f,  0x64,  0x12,  0x2f,
+  0x01,  0x73,  0x02,  0x2b,  0x10,  0xfe,  0x44,  0x00,  0x55,  0x0a,  0xe9,  0x44,  0x0a,  0xfe,  0xb4,  0x10,
+  0x01,  0xb0,  0x44,  0x0a,  0xfe,  0xaa,  0x10,  0x01,  0xb0,  0xfe,  0x19,  0x82,  0xfe,  0x34,  0x46,  0xac,
+  0x44,  0x0a,  0x10,  0xfe,  0x43,  0x00,  0xfe,  0x96,  0x10,  0x08,  0x54,  0x0a,  0x37,  0x01,  0xf5,  0x01,
+  0xf6,  0x64,  0x12,  0x2f,  0x01,  0x73,  0x99,  0x0a,  0x64,  0x42,  0x92,  0x02,  0xfe,  0x2e,  0x03,  0x08,
+  0x05,  0x0a,  0x8a,  0x44,  0x0a,  0x10,  0x00,  0xfe,  0x5c,  0x10,  0x68,  0x05,  0x1a,  0xfe,  0x58,  0x12,
+  0x08,  0x05,  0x1a,  0xfe,  0x50,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x50,  0x0d,  0xfe,
+  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x56,  0x0d,  0x08,  0x54,  0x1a,  0x37,  0xfe,  0xa9,  0x10,  0x10,
+  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0a,  0x50,  0xfe,  0x2e,  0x10,  0x10,  0xfe,  0x13,  0x00,  0xfe,
+  0x10,  0x10,  0x10,  0x6f,  0xab,  0x10,  0xfe,  0x41,  0x00,  0xaa,  0x10,  0xfe,  0x24,  0x00,  0x8c,  0xb5,
+  0xb6,  0x74,  0x03,  0x70,  0x28,  0x23,  0xd8,  0x50,  0xfe,  0x04,  0xe6,  0x1a,  0xfe,  0x9d,  0x41,  0xfe,
+  0x1c,  0x42,  0x64,  0x01,  0xe3,  0x02,  0x2b,  0xf8,  0x15,  0x0a,  0x39,  0xa0,  0xb4,  0x15,  0xfe,  0x31,
+  0x00,  0x39,  0xa2,  0x01,  0xfe,  0x48,  0x10,  0x02,  0xd7,  0x42,  0xfe,  0x06,  0xec,  0xd0,  0xfc,  0x44,
+  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0x06,  0xea,  0xd0,  0xfe,  0x47,  0x4b,  0x91,  0xfe,  0x75,
+  0x57,  0x03,  0x5d,  0xfe,  0x98,  0x56,  0xfe,  0x38,  0x12,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x44,  0x48,
+  0x4f,  0x08,  0x05,  0x1b,  0xfe,  0x1a,  0x13,  0x09,  0x46,  0x01,  0x0e,  0x41,  0xfe,  0x41,  0x58,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0x49,  0x54,  0x96,  0xfe,  0x1e,  0x0e,  0x02,  0xfe,  0x2e,  0x03,  0x09,  0x5d,
+  0xfe,  0xee,  0x14,  0xfc,  0x44,  0x1b,  0xfe,  0xce,  0x45,  0x35,  0x42,  0xfe,  0xce,  0x47,  0xfe,  0xad,
+  0x13,  0x02,  0x2b,  0x22,  0x20,  0x07,  0x11,  0xfe,  0x9e,  0x12,  0x21,  0x13,  0x59,  0x13,  0x9f,  0x13,
+  0xd5,  0x22,  0x2f,  0x41,  0x39,  0x2f,  0xbc,  0xad,  0xfe,  0xbc,  0xf0,  0xfe,  0xe0,  0x0e,  0x0f,  0x06,
+  0x13,  0x59,  0x01,  0xfe,  0xda,  0x16,  0x03,  0xfe,  0x38,  0x01,  0x29,  0xfe,  0x3a,  0x01,  0x56,  0xfe,
+  0xe4,  0x0e,  0xfe,  0x02,  0xec,  0xd5,  0x69,  0x00,  0x66,  0xfe,  0x04,  0xec,  0x20,  0x4f,  0xfe,  0x05,
+  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x4a,  0x17,  0xfe,  0x08,  0x90,  0xfe,  0x48,  0xf4,  0x0d,  0xfe,
+  0x18,  0x13,  0xba,  0xfe,  0x02,  0xea,  0xd5,  0x69,  0x7e,  0xfe,  0xc5,  0x13,  0x15,  0x1a,  0x39,  0xa0,
+  0xb4,  0xfe,  0x2e,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x1e,  0xfe,  0xf0,  0xff,  0x0c,  0xfe,  0x60,  0x01,
+  0x03,  0xfe,  0x3a,  0x01,  0x0c,  0xfe,  0x62,  0x01,  0x43,  0x13,  0x20,  0x25,  0x06,  0x13,  0x2f,  0x12,
+  0x2f,  0x92,  0x0f,  0x06,  0x04,  0x21,  0x04,  0x22,  0x59,  0xfe,  0xf7,  0x12,  0x22,  0x9f,  0xb7,  0x13,
+  0x9f,  0x07,  0x7e,  0xfe,  0x71,  0x13,  0xfe,  0x24,  0x1c,  0x15,  0x19,  0x39,  0xa0,  0xb4,  0xfe,  0xd9,
+  0x10,  0xc3,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xc3,  0xfe,  0x03,  0xdc,
+  0xfe,  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x04,  0xfe,  0x03,  0x57,  0xc3,  0x21,  0xfe,  0x00,  0xcc,  0x04,
+  0xfe,  0x03,  0x57,  0xc3,  0x78,  0x04,  0x08,  0x05,  0x58,  0xfe,  0x22,  0x13,  0xfe,  0x1c,  0x80,  0x07,
+  0x06,  0xfe,  0x1a,  0x13,  0xfe,  0x1e,  0x80,  0xed,  0xfe,  0x1d,  0x80,  0xae,  0xfe,  0x0c,  0x90,  0xfe,
+  0x0e,  0x13,  0xfe,  0x0e,  0x90,  0xac,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x0a,  0xfe,  0x3c,  0x50,
+  0xaa,  0x01,  0xfe,  0x7a,  0x17,  0x32,  0x07,  0x2f,  0xad,  0x01,  0xfe,  0xb4,  0x16,  0x08,  0x05,  0x1b,
+  0x4e,  0x01,  0xf5,  0x01,  0xf6,  0x12,  0xfe,  0xe9,  0x00,  0x08,  0x05,  0x58,  0xfe,  0x2c,  0x13,  0x01,
+  0xfe,  0x0c,  0x17,  0xfe,  0x1e,  0x1c,  0xfe,  0x14,  0x90,  0xfe,  0x96,  0x90,  0x0c,  0xfe,  0x64,  0x01,
+  0x14,  0xfe,  0x66,  0x01,  0x08,  0x05,  0x5b,  0xfe,  0x12,  0x12,  0xfe,  0x03,  0x80,  0x8d,  0xfe,  0x01,
+  0xec,  0x20,  0xfe,  0x80,  0x40,  0x13,  0x20,  0x6a,  0x2a,  0x12,  0xcf,  0x64,  0x22,  0x20,  0xfb,  0x79,
+  0x20,  0x04,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,  0xae,  0x00,
+
+  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,  0xfe,  0x09,
+  0x58,  0xfe,  0x0a,  0x1c,  0x25,  0x6e,  0x13,  0xd0,  0x21,  0x0c,  0x5c,  0x0c,  0x45,  0x0f,  0x46,  0x52,
+  0x50,  0x18,  0x1b,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xfe,  0xfc,  0x0f,  0x44,  0x11,  0x0f,
+  0x48,  0x52,  0x18,  0x58,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x23,  0xe4,  0x25,  0x11,  0x13,  0x20,
+  0x7c,  0x6f,  0x4f,  0x22,  0x20,  0xfb,  0x79,  0x20,  0x12,  0xcf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,
+  0xfe,  0x26,  0x10,  0xf8,  0x74,  0xfe,  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x04,  0x42,
+  0xfe,  0x0c,  0x14,  0xfc,  0xfe,  0x07,  0xe6,  0x1b,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x04,  0x01,
+  0xb0,  0x7c,  0x6f,  0x4f,  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0x32,  0x07,  0x2f,
+  0xfe,  0x34,  0x13,  0x09,  0x48,  0x01,  0x0e,  0xbb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,
+  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,
+  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x5c,  0x01,  0x73,  0xfe,  0x0e,  0x10,  0x07,  0x82,  0x4e,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x60,  0x10,  0x04,  0xfe,  0x44,  0x58,  0x8d,  0xfe,  0x01,  0xec,  0xa2,
+  0xfe,  0x9e,  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x1a,  0x79,  0x2a,  0x01,  0xe3,  0xfe,
+  0xdd,  0x10,  0x2c,  0xc7,  0x81,  0xc8,  0x83,  0x33,  0x31,  0xde,  0x07,  0x1a,  0xfe,  0x48,  0x12,  0x07,
+  0x0a,  0xfe,  0x56,  0x12,  0x07,  0x19,  0xfe,  0x30,  0x12,  0x07,  0xc9,  0x17,  0xfe,  0x32,  0x12,  0x07,
+  0xfe,  0x23,  0x00,  0x17,  0xeb,  0x07,  0x06,  0x17,  0xfe,  0x9c,  0x12,  0x07,  0x1f,  0xfe,  0x12,  0x12,
+  0x07,  0x00,  0x17,  0x24,  0x15,  0xc9,  0x01,  0x36,  0xa9,  0x2d,  0x01,  0x0b,  0x94,  0x4b,  0x04,  0x2d,
+  0xdd,  0x09,  0xd1,  0x01,  0xfe,  0x26,  0x0f,  0x12,  0x82,  0x02,  0x2b,  0x2d,  0x32,  0x07,  0xa6,  0xfe,
+  0xd9,  0x13,  0x3a,  0x3d,  0x3b,  0x3e,  0x56,  0xfe,  0xf0,  0x11,  0x08,  0x05,  0x5a,  0xfe,  0x72,  0x12,
+  0x9b,  0x2e,  0x9c,  0x3c,  0x90,  0xc0,  0x96,  0xfe,  0xba,  0x11,  0x22,  0x62,  0xfe,  0x26,  0x13,  0x03,
+  0x7f,  0x29,  0x80,  0x56,  0xfe,  0x76,  0x0d,  0x0c,  0x60,  0x14,  0x61,  0x21,  0x0c,  0x7f,  0x0c,  0x80,
+  0x01,  0xb3,  0x25,  0x6e,  0x77,  0x13,  0x62,  0x01,  0xef,  0x9b,  0x2e,  0x9c,  0x3c,  0xfe,  0x04,  0x55,
+  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,  0x2e,  0xfe,  0x05,  0xfa,  0x3c,  0xfe,  0x91,  0x10,  0x03,  0x3f,
+  0x29,  0x40,  0xfe,  0x40,  0x56,  0xfe,  0xe1,  0x56,  0x0c,  0x3f,  0x14,  0x40,  0x88,  0x9b,  0x2e,  0x9c,
+  0x3c,  0x90,  0xc0,  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x0c,  0x5e,  0x14,
+  0x5f,  0x08,  0x05,  0x5a,  0xfe,  0x1e,  0x12,  0x22,  0x62,  0xfe,  0x1f,  0x40,  0x03,  0x60,  0x29,  0x61,
+  0xfe,  0x2c,  0x50,  0xfe,  0xae,  0x50,  0x03,  0x3f,  0x29,  0x40,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,
+  0x03,  0x5e,  0x29,  0x5f,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x3d,  0x29,  0x3e,  0xfe,  0x40,
+  0x50,  0xfe,  0xc2,  0x50,  0x02,  0x89,  0x25,  0x06,  0x13,  0xd4,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1d,
+  0x4c,  0x33,  0x31,  0xde,  0x07,  0x06,  0x23,  0x4c,  0x32,  0x07,  0xa6,  0x23,  0x72,  0x01,  0xaf,  0x1e,
+  0x43,  0x17,  0x4c,  0x08,  0x05,  0x0a,  0xee,  0x3a,  0x3d,  0x3b,  0x3e,  0xfe,  0x0a,  0x55,  0x35,  0xfe,
+  0x8b,  0x55,  0x57,  0x3d,  0x7d,  0x3e,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x02,  0x72,  0xfe,  0x19,
+  0x81,  0xba,  0xfe,  0x19,  0x41,  0x02,  0x72,  0x2d,  0x01,  0x0b,  0x1c,  0x34,  0x1d,  0xe8,  0x33,  0x31,
+  0xe1,  0x55,  0x19,  0xfe,  0xa6,  0x12,  0x55,  0x0a,  0x4d,  0x02,  0x4c,  0x01,  0x0b,  0x1c,  0x34,  0x1d,
+  0xe8,  0x33,  0x31,  0xdf,  0x07,  0x19,  0x23,  0x4c,  0x01,  0x0b,  0x1d,  0xe8,  0x33,  0x31,  0xfe,  0xe8,
+  0x09,  0xfe,  0xc2,  0x49,  0x51,  0x03,  0xfe,  0x9c,  0x00,  0x28,  0x8a,  0x53,  0x05,  0x1f,  0x35,  0xa9,
+  0xfe,  0xbb,  0x45,  0x55,  0x00,  0x4e,  0x44,  0x06,  0x7c,  0x43,  0xfe,  0xda,  0x14,  0x01,  0xaf,  0x8c,
+  0xfe,  0x4b,  0x45,  0xee,  0x32,  0x07,  0xa5,  0xed,  0x03,  0xcd,  0x28,  0x8a,  0x03,  0x45,  0x28,  0x35,
+  0x67,  0x02,  0x72,  0xfe,  0xc0,  0x5d,  0xfe,  0xf8,  0x14,  0xfe,  0x03,  0x17,  0x03,  0x5c,  0xc1,  0x0c,
+  0x5c,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,  0x01,  0xfe,  0x9e,  0x15,  0x02,  0x89,  0x01,  0x0b,  0x1c,
+  0x34,  0x1d,  0x4c,  0x33,  0x31,  0xdf,  0x07,  0x06,  0x23,  0x4c,  0x01,  0xf1,  0xfe,  0x42,  0x58,  0xf1,
+  0xfe,  0xa4,  0x14,  0x8c,  0xfe,  0x4a,  0xf4,  0x0a,  0x17,  0x4c,  0xfe,  0x4a,  0xf4,  0x06,  0xea,  0x32,
+  0x07,  0xa5,  0x8b,  0x02,  0x72,  0x03,  0x45,  0xc1,  0x0c,  0x45,  0x67,  0x2d,  0x01,  0x0b,  0x26,  0x89,
+  0x01,  0xfe,  0xcc,  0x15,  0x02,  0x89,  0x0f,  0x06,  0x27,  0xfe,  0xbe,  0x13,  0x26,  0xfe,  0xd4,  0x13,
+  0x76,  0xfe,  0x89,  0x48,  0x01,  0x0b,  0x21,  0x76,  0x04,  0x7b,  0xfe,  0xd0,  0x13,  0x1c,  0xfe,  0xd0,
+  0x13,  0x1d,  0xfe,  0xbe,  0x13,  0x67,  0x2d,  0x01,  0x0b,  0xfe,  0xd5,  0x10,  0x0f,  0x71,  0xff,  0x02,
+  0x00,  0x57,  0x52,  0x93,  0x1e,  0xfe,  0xff,  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,  0x0f,
+  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x1e,  0x43,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x04,
+  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,  0x93,  0x04,  0x0f,  0x71,  0xff,  0x02,  0x00,  0x57,  0x52,
+  0x93,  0xfe,  0x0b,  0x58,  0x04,  0x09,  0x5c,  0x01,  0x87,  0x09,  0x45,  0x01,  0x87,  0x04,  0xfe,  0x03,
+  0xa1,  0x1e,  0x11,  0xff,  0x03,  0x00,  0x54,  0xfe,  0x00,  0xf4,  0x1f,  0x52,  0xfe,  0x00,  0x7d,  0xfe,
+  0x01,  0x7d,  0xfe,  0x02,  0x7d,  0xfe,  0x03,  0x7c,  0x6a,  0x2a,  0x0c,  0x5e,  0x14,  0x5f,  0x57,  0x3f,
+  0x7d,  0x40,  0x04,  0xdd,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x8d,  0x04,  0x01,
+  0xfe,  0x0c,  0x19,  0xfe,  0x42,  0x48,  0x50,  0x51,  0x91,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,
+  0x31,  0xe1,  0x01,  0x0b,  0x1d,  0xfe,  0x96,  0x15,  0x33,  0x31,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,
+  0x03,  0xcd,  0x28,  0xfe,  0xcc,  0x12,  0x53,  0x05,  0x1a,  0xfe,  0xc4,  0x13,  0x21,  0x69,  0x1a,  0xee,
+  0x55,  0xca,  0x6b,  0xfe,  0xdc,  0x14,  0x4d,  0x0f,  0x06,  0x18,  0xca,  0x7c,  0x30,  0xfe,  0x78,  0x10,
+  0xff,  0x02,  0x83,  0x55,  0xab,  0xff,  0x02,  0x83,  0x55,  0x69,  0x19,  0xae,  0x98,  0xfe,  0x30,  0x00,
+  0x96,  0xf2,  0x18,  0x6d,  0x0f,  0x06,  0xfe,  0x56,  0x10,  0x69,  0x0a,  0xed,  0x98,  0xfe,  0x64,  0x00,
+  0x96,  0xf2,  0x09,  0xfe,  0x64,  0x00,  0x18,  0x9e,  0x0f,  0x06,  0xfe,  0x28,  0x10,  0x69,  0x06,  0xfe,
+  0x60,  0x13,  0x98,  0xfe,  0xc8,  0x00,  0x96,  0xf2,  0x09,  0xfe,  0xc8,  0x00,  0x18,  0x59,  0x0f,  0x06,
+  0x88,  0x98,  0xfe,  0x90,  0x01,  0x7a,  0xfe,  0x42,  0x15,  0x91,  0xe4,  0xfe,  0x43,  0xf4,  0x9f,  0xfe,
+  0x56,  0xf0,  0xfe,  0x54,  0x15,  0xfe,  0x04,  0xf4,  0x71,  0xfe,  0x43,  0xf4,  0x9e,  0xfe,  0xf3,  0x10,
+  0xfe,  0x40,  0x5c,  0x01,  0xfe,  0x16,  0x14,  0x1e,  0x43,  0xec,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
+  0x6e,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0x6e,  0xfe,  0x1c,  0x10,  0xfe,  0x00,  0x17,  0xfe,  0x4d,  0xe4,
+  0xcc,  0x7a,  0xfe,  0x90,  0x15,  0xc4,  0xcc,  0x88,  0x51,  0x21,  0xfe,  0x4d,  0xf4,  0x00,  0xe9,  0x91,
+  0x0f,  0x06,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x04,  0x51,  0x0f,  0x0a,  0x04,  0x16,  0x06,  0x01,
+  0x0b,  0x26,  0xf3,  0x16,  0x0a,  0x01,  0x0b,  0x26,  0xf3,  0x16,  0x19,  0x01,  0x0b,  0x26,  0xf3,  0x76,
+  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x04,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0x16,  0x19,  0x01,  0x0b,
+  0x26,  0xb1,  0x16,  0x06,  0x01,  0x0b,  0x26,  0xb1,  0xfe,  0x89,  0x49,  0x01,  0x0b,  0x26,  0xb1,  0x76,
+  0xfe,  0x89,  0x4a,  0x01,  0x0b,  0x04,  0x51,  0x04,  0x22,  0xd3,  0x07,  0x06,  0xfe,  0x48,  0x13,  0xb8,
+  0x13,  0xd3,  0xfe,  0x49,  0xf4,  0x00,  0x4d,  0x76,  0xa9,  0x67,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,
+  0xfe,  0x89,  0x48,  0xff,  0x02,  0x00,  0x10,  0x27,  0xfe,  0x2e,  0x16,  0x32,  0x07,  0xfe,  0xe3,  0x00,
+  0xfe,  0x20,  0x13,  0x1d,  0xfe,  0x52,  0x16,  0x21,  0x13,  0xd4,  0x01,  0x4b,  0x22,  0xd4,  0x07,  0x06,
+  0x4e,  0x08,  0x54,  0x06,  0x37,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfb,  0x8e,  0x07,  0x11,  0xae,  0x09,
+  0x84,  0x01,  0x0e,  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x84,  0x01,  0x0e,  0x8e,  0xfe,  0x80,
+  0xe7,  0x11,  0x07,  0x11,  0x8a,  0xfe,  0x45,  0x58,  0x01,  0xf0,  0x8e,  0x04,  0x09,  0x48,  0x01,  0x0e,
+  0x8e,  0x09,  0x5d,  0x01,  0xa8,  0x04,  0x09,  0x48,  0x01,  0x0e,  0xfe,  0x80,  0x80,  0xfe,  0x80,  0x4c,
+  0xfe,  0x49,  0xe4,  0x11,  0xae,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,  0x09,  0x5d,  0x01,  0x87,
+  0x04,  0x18,  0x11,  0x75,  0x6c,  0xfe,  0x60,  0x01,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x24,
+  0x1c,  0xfe,  0x1d,  0xf7,  0x1b,  0x97,  0xfe,  0xee,  0x16,  0x01,  0xfe,  0xf4,  0x17,  0xad,  0x9a,  0x1b,
+  0x6c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x04,  0xb9,  0x23,  0xfe,  0xde,  0x16,  0xfe,  0xda,  0x10,
+  0x18,  0x11,  0x75,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x1f,  0xfe,  0x18,  0x58,  0x03,  0xfe,
+  0x66,  0x01,  0xfe,  0x19,  0x58,  0x9a,  0x1f,  0xfe,  0x3c,  0x90,  0xfe,  0x30,  0xf4,  0x06,  0xfe,  0x3c,
+  0x50,  0x6c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x1f,  0x97,  0xfe,  0x38,  0x17,
+  0xfe,  0xb6,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x10,  0x17,  0xfe,  0x9c,  0x10,  0x18,  0x11,  0x75,
+  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x2e,  0x97,  0xfe,  0x5a,
+  0x17,  0xfe,  0x94,  0x14,  0xec,  0x9a,  0x2e,  0x6c,  0x1a,  0xfe,  0xaf,  0x19,  0xfe,  0x98,  0xe7,  0x00,
+  0x04,  0xb9,  0x23,  0xfe,  0x4e,  0x17,  0xfe,  0x6c,  0x10,  0x18,  0x11,  0x75,  0xfe,  0x30,  0xbc,  0xfe,
+  0xb2,  0xbc,  0x9a,  0xcb,  0x6c,  0x1a,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0xcb,  0x97,  0xfe,  0x92,
+  0x17,  0xfe,  0x5c,  0x14,  0x35,  0x04,  0xb9,  0x23,  0xfe,  0x7e,  0x17,  0xfe,  0x42,  0x10,  0xfe,  0x02,
+  0xf6,  0x11,  0x75,  0xfe,  0x18,  0xfe,  0x60,  0xfe,  0x19,  0xfe,  0x61,  0xfe,  0x03,  0xa1,  0xfe,  0x1d,
+  0xf7,  0x5b,  0x97,  0xfe,  0xb8,  0x17,  0xfe,  0x36,  0x14,  0xfe,  0x1c,  0x13,  0x9a,  0x5b,  0x41,  0xfe,
+  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x11,  0xfe,  0x81,  0xe7,  0x11,  0x12,  0xfe,  0xdd,
+  0x00,  0x6a,  0x2a,  0x04,  0x6a,  0x2a,  0xfe,  0x12,  0x45,  0x23,  0xfe,  0xa8,  0x17,  0x15,  0x06,  0x39,
+  0xa0,  0xb4,  0x02,  0x2b,  0xfe,  0x39,  0xf0,  0xfe,  0xfc,  0x17,  0x21,  0x04,  0xfe,  0x7e,  0x18,  0x1e,
+  0x19,  0x66,  0x0f,  0x0d,  0x04,  0x75,  0x03,  0xd2,  0x1e,  0x06,  0xfe,  0xef,  0x12,  0xfe,  0xe1,  0x10,
+  0x7c,  0x6f,  0x4f,  0x32,  0x07,  0x2f,  0xfe,  0x3c,  0x13,  0xf1,  0xfe,  0x42,  0x13,  0x42,  0x92,  0x09,
+  0x48,  0x01,  0x0e,  0xbb,  0xeb,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xf0,  0xfe,  0x00,  0xcc,
+  0xbb,  0xfe,  0xf3,  0x13,  0x43,  0x78,  0x07,  0x11,  0xac,  0x09,  0x84,  0x01,  0x0e,  0xfe,  0x80,  0x4c,
+  0x01,  0x73,  0xfe,  0x16,  0x10,  0x07,  0x82,  0x8b,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,
+  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0x1c,  0x18,  0x18,  0x0a,  0x04,  0xfe,  0x9c,  0xe7,  0x0a,  0x10,  0xfe,
+  0x15,  0x00,  0x64,  0x79,  0x2a,  0x01,  0xe3,  0x18,  0x06,  0x04,  0x42,  0x92,  0x08,  0x54,  0x1b,  0x37,
+  0x12,  0x2f,  0x01,  0x73,  0x18,  0x06,  0x04,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,  0x3a,  0xce,  0x3b,
+  0xcf,  0xfe,  0x48,  0x55,  0x35,  0xfe,  0xc9,  0x55,  0x04,  0x22,  0xa3,  0x77,  0x13,  0xa3,  0x04,  0x09,
+  0xa4,  0x01,  0x0e,  0xfe,  0x41,  0x48,  0x09,  0x46,  0x01,  0x0e,  0xfe,  0x49,  0x44,  0x17,  0xfe,  0xe8,
+  0x18,  0x77,  0x78,  0x04,  0x09,  0x48,  0x01,  0x0e,  0x07,  0x11,  0x4e,  0x09,  0x5d,  0x01,  0xa8,  0x09,
+  0x46,  0x01,  0x0e,  0x77,  0x78,  0x04,  0xfe,  0x4e,  0xe4,  0x19,  0x6b,  0xfe,  0x1c,  0x19,  0x03,  0xfe,
+  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xc9,  0x6b,  0xfe,  0x2e,  0x19,
+  0x03,  0xfe,  0x92,  0x00,  0xfe,  0x02,  0xe6,  0x1a,  0xe5,  0xfe,  0x4e,  0xe4,  0xfe,  0x0b,  0x00,  0x6b,
+  0xfe,  0x40,  0x19,  0x03,  0xfe,  0x94,  0x00,  0xfe,  0x02,  0xe6,  0x1f,  0xfe,  0x08,  0x10,  0x03,  0xfe,
+  0x96,  0x00,  0xfe,  0x02,  0xe6,  0x6d,  0xfe,  0x4e,  0x45,  0xea,  0xba,  0xff,  0x04,  0x68,  0x54,  0xe7,
+  0x1e,  0x6e,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,  0x00,
+  0x04,  0xea,  0xfe,  0x48,  0xf4,  0x19,  0x7a,  0xfe,  0x74,  0x19,  0x0f,  0x19,  0x04,  0x07,  0x7e,  0xfe,
+  0x5a,  0xf0,  0xfe,  0x84,  0x19,  0x25,  0xfe,  0x09,  0x00,  0xfe,  0x34,  0x10,  0x07,  0x1a,  0xfe,  0x5a,
+  0xf0,  0xfe,  0x92,  0x19,  0x25,  0xca,  0xfe,  0x26,  0x10,  0x07,  0x19,  0x66,  0x25,  0x6d,  0xe5,  0x07,
+  0x0a,  0x66,  0x25,  0x9e,  0xfe,  0x0e,  0x10,  0x07,  0x06,  0x66,  0x25,  0x59,  0xa9,  0xb8,  0x04,  0x15,
+  0xfe,  0x09,  0x00,  0x01,  0x36,  0xfe,  0x04,  0xfe,  0x81,  0x03,  0x83,  0xfe,  0x40,  0x5c,  0x04,  0x1c,
+  0xf7,  0xfe,  0x14,  0xf0,  0x0b,  0x27,  0xfe,  0xd6,  0x19,  0x1c,  0xf7,  0x7b,  0xf7,  0xfe,  0x82,  0xf0,
+  0xfe,  0xda,  0x19,  0x04,  0xff,  0xcc,  0x00,  0x00,
+};
+
+STATIC unsigned short _adv_asc38C0800_size =
+        sizeof(_adv_asc38C0800_buf); /* 0x14E1 */
+STATIC ADV_DCNT _adv_asc38C0800_chksum =
+        0x050D3FD8UL; /* Expanded little-endian checksum. */
+
+/* Microcode buffer is kept after initialization for error recovery. */
+STATIC unsigned char _adv_asc38C1600_buf[] = {
+  0x00,  0x00,  0x00,  0xf2,  0x00,  0x16,  0x00,  0xfc,  0x00,  0x10,  0x00,  0xf0,  0x18,  0xe4,  0x01,  0x00,
+  0x04,  0x1e,  0x48,  0xe4,  0x03,  0xf6,  0xf7,  0x13,  0x2e,  0x1e,  0x02,  0x00,  0x07,  0x17,  0xc0,  0x5f,
+  0x00,  0xfa,  0xff,  0xff,  0x04,  0x00,  0x00,  0xf6,  0x09,  0xe7,  0x82,  0xe7,  0x85,  0xf0,  0x86,  0xf0,
+  0x4e,  0x10,  0x9e,  0xe7,  0xff,  0x00,  0x55,  0xf0,  0x01,  0xf6,  0x03,  0x00,  0x98,  0x57,  0x01,  0xe6,
+  0x00,  0xea,  0x00,  0xec,  0x01,  0xfa,  0x18,  0xf4,  0x08,  0x00,  0xf0,  0x1d,  0x38,  0x54,  0x32,  0xf0,
+  0x10,  0x00,  0xc2,  0x0e,  0x1e,  0xf0,  0xd5,  0xf0,  0xbc,  0x00,  0x4b,  0xe4,  0x00,  0xe6,  0xb1,  0xf0,
+  0xb4,  0x00,  0x02,  0x13,  0x3e,  0x1c,  0xc8,  0x47,  0x3e,  0x00,  0xd8,  0x01,  0x06,  0x13,  0x0c,  0x1c,
+  0x5e,  0x1e,  0x00,  0x57,  0xc8,  0x57,  0x01,  0xfc,  0xbc,  0x0e,  0xa2,  0x12,  0xb9,  0x54,  0x00,  0x80,
+  0x62,  0x0a,  0x5a,  0x12,  0xc8,  0x15,  0x3e,  0x1e,  0x18,  0x40,  0xbd,  0x56,  0x03,  0xe6,  0x01,  0xea,
+  0x5c,  0xf0,  0x0f,  0x00,  0x20,  0x00,  0x6c,  0x01,  0x6e,  0x01,  0x04,  0x12,  0x04,  0x13,  0xbb,  0x55,
+  0x3c,  0x56,  0x3e,  0x57,  0x03,  0x58,  0x4a,  0xe4,  0x40,  0x00,  0xb6,  0x00,  0xbb,  0x00,  0xc0,  0x00,
+  0x00,  0x01,  0x01,  0x01,  0x3e,  0x01,  0x58,  0x0a,  0x44,  0x10,  0x0a,  0x12,  0x4c,  0x1c,  0x4e,  0x1c,
+  0x02,  0x4a,  0x30,  0xe4,  0x05,  0xe6,  0x0c,  0x00,  0x3c,  0x00,  0x80,  0x00,  0x24,  0x01,  0x3c,  0x01,
+  0x68,  0x01,  0x6a,  0x01,  0x70,  0x01,  0x72,  0x01,  0x74,  0x01,  0x76,  0x01,  0x78,  0x01,  0x7c,  0x01,
+  0xc6,  0x0e,  0x0c,  0x10,  0xac,  0x12,  0xae,  0x12,  0x16,  0x1a,  0x32,  0x1c,  0x6e,  0x1e,  0x02,  0x48,
+  0x3a,  0x55,  0xc9,  0x57,  0x02,  0xee,  0x5b,  0xf0,  0x03,  0xf7,  0x06,  0xf7,  0x03,  0xfc,  0x06,  0x00,
+  0x1e,  0x00,  0xbe,  0x00,  0xe1,  0x00,  0x0c,  0x12,  0x18,  0x1a,  0x70,  0x1a,  0x30,  0x1c,  0x38,  0x1c,
+  0x10,  0x44,  0x00,  0x4c,  0xb0,  0x57,  0x40,  0x5c,  0x4d,  0xe4,  0x04,  0xea,  0x5d,  0xf0,  0xa7,  0xf0,
+  0x04,  0xf6,  0x02,  0xfc,  0x05,  0x00,  0x09,  0x00,  0x19,  0x00,  0x32,  0x00,  0x33,  0x00,  0x34,  0x00,
+  0x36,  0x00,  0x98,  0x00,  0x9e,  0x00,  0xcc,  0x00,  0x20,  0x01,  0x4e,  0x01,  0x79,  0x01,  0x3c,  0x09,
+  0x68,  0x0d,  0x02,  0x10,  0x04,  0x10,  0x3a,  0x10,  0x08,  0x12,  0x0a,  0x13,  0x40,  0x16,  0x50,  0x16,
+  0x00,  0x17,  0x4a,  0x19,  0x00,  0x4e,  0x00,  0x54,  0x01,  0x58,  0x00,  0xdc,  0x05,  0xf0,  0x09,  0xf0,
+  0x59,  0xf0,  0xb8,  0xf0,  0x48,  0xf4,  0x0e,  0xf7,  0x0a,  0x00,  0x9b,  0x00,  0x9c,  0x00,  0xa4,  0x00,
+  0xb5,  0x00,  0xba,  0x00,  0xd0,  0x00,  0xe7,  0x00,  0xf0,  0x03,  0x69,  0x08,  0xe9,  0x09,  0x5c,  0x0c,
+  0xb6,  0x12,  0xbc,  0x19,  0xd8,  0x1b,  0x20,  0x1c,  0x34,  0x1c,  0x36,  0x1c,  0x42,  0x1d,  0x08,  0x44,
+  0x38,  0x44,  0x91,  0x44,  0x0a,  0x45,  0x48,  0x46,  0x89,  0x48,  0x68,  0x54,  0x83,  0x55,  0x83,  0x59,
+  0x31,  0xe4,  0x02,  0xe6,  0x07,  0xf0,  0x08,  0xf0,  0x0b,  0xf0,  0x0c,  0xf0,  0x4b,  0xf4,  0x04,  0xf8,
+  0x05,  0xf8,  0x02,  0xfa,  0x03,  0xfa,  0x04,  0xfc,  0x05,  0xfc,  0x07,  0x00,  0xa8,  0x00,  0xaa,  0x00,
+  0xb9,  0x00,  0xe0,  0x00,  0xe5,  0x00,  0x22,  0x01,  0x26,  0x01,  0x60,  0x01,  0x7a,  0x01,  0x82,  0x01,
+  0xc8,  0x01,  0xca,  0x01,  0x86,  0x02,  0x6a,  0x03,  0x18,  0x05,  0xb2,  0x07,  0x68,  0x08,  0x10,  0x0d,
+  0x06,  0x10,  0x0a,  0x10,  0x0e,  0x10,  0x12,  0x10,  0x60,  0x10,  0xed,  0x10,  0xf3,  0x10,  0x06,  0x12,
+  0x10,  0x12,  0x1e,  0x12,  0x0c,  0x13,  0x0e,  0x13,  0x10,  0x13,  0xfe,  0x9c,  0xf0,  0x35,  0x05,  0xfe,
+  0xec,  0x0e,  0xff,  0x10,  0x00,  0x00,  0xe9,  0xfe,  0x34,  0x1f,  0x00,  0xe8,  0xfe,  0x88,  0x01,  0xff,
+  0x03,  0x00,  0x00,  0xfe,  0x93,  0x15,  0xfe,  0x0f,  0x05,  0xff,  0x38,  0x00,  0x00,  0xfe,  0x57,  0x24,
+  0x00,  0xfe,  0x4c,  0x00,  0x65,  0xff,  0x04,  0x00,  0x00,  0x1a,  0xff,  0x09,  0x00,  0x00,  0xff,  0x08,
+  0x01,  0x01,  0xff,  0x08,  0xff,  0xff,  0xff,  0x27,  0x00,  0x00,  0xff,  0x10,  0xff,  0xff,  0xff,  0x13,
+  0x00,  0x00,  0xfe,  0x78,  0x56,  0xfe,  0x34,  0x12,  0xff,  0x21,  0x00,  0x00,  0xfe,  0x04,  0xf7,  0xe8,
+  0x37,  0x7d,  0x0d,  0x01,  0xfe,  0x4a,  0x11,  0xfe,  0x04,  0xf7,  0xe8,  0x7d,  0x0d,  0x51,  0x37,  0xfe,
+  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x91,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,
+  0x90,  0xf0,  0xfe,  0xf8,  0x01,  0xfe,  0x8f,  0xf0,  0xbc,  0x03,  0x67,  0x4d,  0x05,  0xfe,  0x08,  0x0f,
+  0x01,  0xfe,  0x78,  0x0f,  0xfe,  0xdd,  0x12,  0x05,  0xfe,  0x0e,  0x03,  0xfe,  0x28,  0x1c,  0x03,  0xfe,
+  0xa6,  0x00,  0xfe,  0xd1,  0x12,  0x3e,  0x22,  0xfe,  0xa6,  0x00,  0xac,  0xfe,  0x48,  0xf0,  0xfe,  0x90,
+  0x02,  0xfe,  0x49,  0xf0,  0xfe,  0xaa,  0x02,  0xfe,  0x4a,  0xf0,  0xfe,  0xc8,  0x02,  0xfe,  0x46,  0xf0,
+  0xfe,  0x5a,  0x02,  0xfe,  0x47,  0xf0,  0xfe,  0x60,  0x02,  0xfe,  0x43,  0xf0,  0xfe,  0x4e,  0x02,  0xfe,
+  0x44,  0xf0,  0xfe,  0x52,  0x02,  0xfe,  0x45,  0xf0,  0xfe,  0x56,  0x02,  0x1c,  0x0d,  0xa2,  0x1c,  0x07,
+  0x22,  0xb7,  0x05,  0x35,  0xfe,  0x00,  0x1c,  0xfe,  0xf1,  0x10,  0xfe,  0x02,  0x1c,  0xf5,  0xfe,  0x1e,
+  0x1c,  0xfe,  0xe9,  0x10,  0x01,  0x5f,  0xfe,  0xe7,  0x10,  0xfe,  0x06,  0xfc,  0xde,  0x0a,  0x81,  0x01,
+  0xa3,  0x05,  0x35,  0x1f,  0x95,  0x47,  0xb8,  0x01,  0xfe,  0xe4,  0x11,  0x0a,  0x81,  0x01,  0x5c,  0xfe,
+  0xbd,  0x10,  0x0a,  0x81,  0x01,  0x5c,  0xfe,  0xad,  0x10,  0xfe,  0x16,  0x1c,  0xfe,  0x58,  0x1c,  0x1c,
+  0x07,  0x22,  0xb7,  0x37,  0x2a,  0x35,  0xfe,  0x3d,  0xf0,  0xfe,  0x0c,  0x02,  0x2b,  0xfe,  0x9e,  0x02,
+  0xfe,  0x5a,  0x1c,  0xfe,  0x12,  0x1c,  0xfe,  0x14,  0x1c,  0x1f,  0xfe,  0x30,  0x00,  0x47,  0xb8,  0x01,
+  0xfe,  0xd4,  0x11,  0x1c,  0x07,  0x22,  0xb7,  0x05,  0xe9,  0x21,  0x2c,  0x09,  0x1a,  0x31,  0xfe,  0x69,
+  0x10,  0x1c,  0x07,  0x22,  0xb7,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0x01,  0xfe,  0x1e,  0x1e,  0x20,  0x2c,
+  0xfe,  0x05,  0xf6,  0xde,  0x01,  0xfe,  0x62,  0x1b,  0x01,  0x0c,  0x61,  0x4a,  0x44,  0x15,  0x56,  0x51,
+  0x01,  0xfe,  0x9e,  0x1e,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,
+  0x36,  0x01,  0x85,  0xfe,  0x18,  0x10,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0xc8,  0x54,
+  0x7b,  0xfe,  0x1c,  0x03,  0x01,  0xfe,  0x96,  0x1a,  0x05,  0x35,  0x37,  0x60,  0xfe,  0x02,  0xe8,  0x30,
+  0xfe,  0xbf,  0x57,  0xfe,  0x9e,  0x43,  0xfe,  0x77,  0x57,  0xfe,  0x27,  0xf0,  0xfe,  0xe4,  0x01,  0xfe,
+  0x07,  0x4b,  0xfe,  0x20,  0xf0,  0xbc,  0xfe,  0x40,  0x1c,  0x2a,  0xeb,  0xfe,  0x26,  0xf0,  0xfe,  0x66,
+  0x03,  0xfe,  0xa0,  0xf0,  0xfe,  0x54,  0x03,  0xfe,  0x11,  0xf0,  0xbc,  0xfe,  0xef,  0x10,  0xfe,  0x9f,
+  0xf0,  0xfe,  0x74,  0x03,  0xfe,  0x46,  0x1c,  0x19,  0xfe,  0x11,  0x00,  0x05,  0x70,  0x37,  0xfe,  0x48,
+  0x1c,  0xfe,  0x46,  0x1c,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x18,  0x13,  0x26,  0x21,  0xb9,  0xc7,  0x20,
+  0xb9,  0x0a,  0x57,  0x01,  0x18,  0xc7,  0x89,  0x01,  0xfe,  0xc8,  0x1a,  0x15,  0xe1,  0x2a,  0xeb,  0xfe,
+  0x01,  0xf0,  0xeb,  0xfe,  0x82,  0xf0,  0xfe,  0xa4,  0x03,  0xfe,  0x9c,  0x32,  0x15,  0xfe,  0xe4,  0x00,
+  0x2f,  0xfe,  0xb6,  0x03,  0x2a,  0x3c,  0x16,  0xfe,  0xc6,  0x03,  0x01,  0x41,  0xfe,  0x06,  0xf0,  0xfe,
+  0xd6,  0x03,  0xaf,  0xa0,  0xfe,  0x0a,  0xf0,  0xfe,  0xa2,  0x07,  0x05,  0x29,  0x03,  0x81,  0x1e,  0x1b,
+  0xfe,  0x24,  0x05,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,  0x05,  0xea,  0xfe,  0x46,  0x1c,
+  0x37,  0x7d,  0x1d,  0xfe,  0x67,  0x1b,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0xfe,  0x48,  0x1c,  0x75,
+  0x01,  0xa6,  0x86,  0x0a,  0x57,  0x01,  0x18,  0x09,  0x00,  0x1b,  0xec,  0x0a,  0xe1,  0x01,  0x18,  0x77,
+  0x50,  0x40,  0x8d,  0x30,  0x03,  0x81,  0x1e,  0xf8,  0x1f,  0x63,  0x01,  0x42,  0x8f,  0xfe,  0x70,  0x02,
+  0x05,  0xea,  0xd7,  0x99,  0xd8,  0x9c,  0x2a,  0x29,  0x2f,  0xfe,  0x4e,  0x04,  0x16,  0xfe,  0x4a,  0x04,
+  0x7e,  0xfe,  0xa0,  0x00,  0xfe,  0x9b,  0x57,  0xfe,  0x54,  0x12,  0x32,  0xff,  0x02,  0x00,  0x10,  0x01,
+  0x08,  0x16,  0xfe,  0x02,  0x05,  0x32,  0x01,  0x08,  0x16,  0x29,  0x27,  0x25,  0xee,  0xfe,  0x4c,  0x44,
+  0xfe,  0x58,  0x12,  0x50,  0xfe,  0x44,  0x48,  0x13,  0x34,  0xfe,  0x4c,  0x54,  0x7b,  0xec,  0x60,  0x8d,
+  0x30,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x7c,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xfe,
+  0x32,  0x13,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x68,  0x13,  0xfe,  0x26,  0x10,  0x13,  0x34,  0xfe,  0x4c,
+  0x54,  0x7b,  0xec,  0x01,  0xfe,  0x4e,  0x1e,  0xfe,  0x48,  0x47,  0xfe,  0x54,  0x13,  0x01,  0x0c,  0x06,
+  0x28,  0xa5,  0x01,  0x43,  0x09,  0x9b,  0xfe,  0x40,  0x13,  0x01,  0x0c,  0x06,  0x28,  0xf9,  0x1f,  0x7f,
+  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,  0x8f,  0xfe,  0xa4,  0x0e,  0x05,
+  0x29,  0x32,  0x15,  0xfe,  0xe6,  0x00,  0x0f,  0xfe,  0x1c,  0x90,  0x04,  0xfe,  0x9c,  0x93,  0x3a,  0x0b,
+  0x0e,  0x8b,  0x02,  0x1f,  0x7f,  0x01,  0x42,  0x05,  0x35,  0xfe,  0x42,  0x5b,  0x7d,  0x1d,  0xfe,  0x46,
+  0x59,  0xfe,  0xbf,  0x57,  0xfe,  0x77,  0x57,  0x0f,  0xfe,  0x87,  0x80,  0x04,  0xfe,  0x87,  0x83,  0xfe,
+  0xc9,  0x47,  0x0b,  0x0e,  0xd0,  0x65,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x98,  0x13,  0x0f,  0xfe,  0x20,
+  0x80,  0x04,  0xfe,  0xa0,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x1d,  0xfe,  0x84,  0x12,  0x01,  0x38,  0x06,
+  0x07,  0xfe,  0x70,  0x13,  0x03,  0xfe,  0xa2,  0x00,  0x1e,  0x1b,  0xfe,  0xda,  0x05,  0xd0,  0x54,  0x01,
+  0x38,  0x06,  0x0d,  0xfe,  0x58,  0x13,  0x03,  0xfe,  0xa0,  0x00,  0x1e,  0xfe,  0x50,  0x12,  0x5e,  0xff,
+  0x02,  0x00,  0x10,  0x2f,  0xfe,  0x90,  0x05,  0x2a,  0x3c,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,
+  0x9e,  0x05,  0x17,  0xfe,  0xf4,  0x05,  0x15,  0xfe,  0xe3,  0x00,  0x26,  0x01,  0x38,  0xfe,  0x4a,  0xf0,
+  0xfe,  0xc0,  0x05,  0xfe,  0x49,  0xf0,  0xfe,  0xba,  0x05,  0x71,  0x2e,  0xfe,  0x21,  0x00,  0xf1,  0x2e,
+  0xfe,  0x22,  0x00,  0xa2,  0x2e,  0x4a,  0xfe,  0x09,  0x48,  0xff,  0x02,  0x00,  0x10,  0x2f,  0xfe,  0xd0,
+  0x05,  0x17,  0xfe,  0xf4,  0x05,  0xfe,  0xe2,  0x08,  0x01,  0x38,  0x06,  0xfe,  0x1c,  0x00,  0x4d,  0x01,
+  0xa7,  0x2e,  0x07,  0x20,  0xe4,  0x47,  0xfe,  0x27,  0x01,  0x01,  0x0c,  0x06,  0x28,  0xfe,  0x24,  0x12,
+  0x3e,  0x01,  0x84,  0x1f,  0x7f,  0x01,  0x0c,  0x06,  0x07,  0x4d,  0x1f,  0xfe,  0x0d,  0x00,  0x01,  0x42,
+  0x8f,  0xfe,  0xa4,  0x0e,  0x05,  0x29,  0x03,  0xe6,  0x1e,  0xfe,  0xca,  0x13,  0x03,  0xb6,  0x1e,  0xfe,
+  0x40,  0x12,  0x03,  0x66,  0x1e,  0xfe,  0x38,  0x13,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0x72,  0x06,  0x0a,
+  0x07,  0x01,  0x38,  0x06,  0x24,  0xfe,  0x02,  0x12,  0x4f,  0x01,  0xfe,  0x56,  0x19,  0x16,  0xfe,  0x68,
+  0x06,  0x15,  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x03,  0x9a,  0x1e,  0xfe,
+  0x70,  0x12,  0x03,  0x55,  0x1e,  0xfe,  0x68,  0x13,  0x01,  0xc6,  0x09,  0x12,  0x48,  0xfe,  0x92,  0x06,
+  0x2e,  0x12,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,  0x13,  0x58,  0xff,  0x02,  0x00,
+  0x57,  0x52,  0xad,  0x23,  0x3f,  0x4e,  0x62,  0x49,  0x3e,  0x01,  0x84,  0x17,  0xfe,  0xea,  0x06,  0x01,
+  0x38,  0x06,  0x12,  0xf7,  0x45,  0x0a,  0x95,  0x01,  0xfe,  0x84,  0x19,  0x16,  0xfe,  0xe0,  0x06,  0x15,
+  0x82,  0x01,  0x41,  0x15,  0xe2,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0xae,
+  0x10,  0x03,  0x6f,  0x1e,  0xfe,  0x9e,  0x13,  0x3e,  0x01,  0x84,  0x03,  0x9a,  0x1e,  0xfe,  0x1a,  0x12,
+  0x01,  0x38,  0x06,  0x12,  0xfc,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,  0x43,  0x48,  0x62,  0x80,
+  0xf0,  0x45,  0x0a,  0x95,  0x03,  0xb6,  0x1e,  0xf8,  0x01,  0x38,  0x06,  0x24,  0x36,  0xfe,  0x02,  0xf6,
+  0x07,  0x71,  0x78,  0x8c,  0x00,  0x4d,  0x62,  0x49,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x17,  0xfe,
+  0x9a,  0x07,  0x01,  0xfe,  0xc0,  0x19,  0x16,  0xfe,  0x90,  0x07,  0x26,  0x20,  0x9e,  0x15,  0x82,  0x01,
+  0x41,  0x15,  0xe2,  0x21,  0x9e,  0x09,  0x07,  0xfb,  0x03,  0xe6,  0xfe,  0x58,  0x57,  0x10,  0xe6,  0x05,
+  0xfe,  0x2a,  0x06,  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x1c,  0x07,  0x01,  0x84,  0xfe,  0x9c,  0x32,  0x5f,
+  0x75,  0x01,  0xa6,  0x86,  0x15,  0xfe,  0xe2,  0x00,  0x2f,  0xed,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,
+  0xce,  0x07,  0xae,  0xfe,  0x96,  0x08,  0xfe,  0x06,  0xf0,  0xfe,  0x9e,  0x08,  0xaf,  0xa0,  0x05,  0x29,
+  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x2e,  0x12,  0x14,  0x1d,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,
+  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0xfe,  0x99,  0xa4,  0x01,  0x08,  0x14,  0x00,  0x05,  0xfe,
+  0xc6,  0x09,  0x01,  0x76,  0x06,  0x12,  0xfe,  0x3a,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x30,  0x13,
+  0x14,  0xfe,  0x1b,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,  0x01,  0x08,  0x14,  0x00,
+  0x01,  0x08,  0x14,  0x07,  0x01,  0x08,  0x14,  0x00,  0x05,  0xef,  0x7c,  0x4a,  0x78,  0x4f,  0x0f,  0xfe,
+  0x9a,  0x81,  0x04,  0xfe,  0x9a,  0x83,  0xfe,  0xcb,  0x47,  0x0b,  0x0e,  0x2d,  0x28,  0x48,  0xfe,  0x6c,
+  0x08,  0x0a,  0x28,  0xfe,  0x09,  0x6f,  0xca,  0xfe,  0xca,  0x45,  0xfe,  0x32,  0x12,  0x53,  0x63,  0x4e,
+  0x7c,  0x97,  0x2f,  0xfe,  0x7e,  0x08,  0x2a,  0x3c,  0xfe,  0x0a,  0xf0,  0xfe,  0x6c,  0x08,  0xaf,  0xa0,
+  0xae,  0xfe,  0x96,  0x08,  0x05,  0x29,  0x01,  0x41,  0x05,  0xed,  0x14,  0x24,  0x05,  0xed,  0xfe,  0x9c,
+  0xf7,  0x9f,  0x01,  0xfe,  0xae,  0x1e,  0xfe,  0x18,  0x58,  0x01,  0xfe,  0xbe,  0x1e,  0xfe,  0x99,  0x58,
+  0xfe,  0x78,  0x18,  0xfe,  0xf9,  0x18,  0x8e,  0xfe,  0x16,  0x09,  0x10,  0x6a,  0x22,  0x6b,  0x01,  0x0c,
+  0x61,  0x54,  0x44,  0x21,  0x2c,  0x09,  0x1a,  0xf8,  0x77,  0x01,  0xfe,  0x7e,  0x1e,  0x47,  0x2c,  0x7a,
+  0x30,  0xf0,  0xfe,  0x83,  0xe7,  0xfe,  0x3f,  0x00,  0x71,  0xfe,  0x03,  0x40,  0x01,  0x0c,  0x61,  0x65,
+  0x44,  0x01,  0xc2,  0xc8,  0xfe,  0x1f,  0x40,  0x20,  0x6e,  0x01,  0xfe,  0x6a,  0x16,  0xfe,  0x08,  0x50,
+  0xfe,  0x8a,  0x50,  0xfe,  0x44,  0x51,  0xfe,  0xc6,  0x51,  0xfe,  0x10,  0x10,  0x01,  0xfe,  0xce,  0x1e,
+  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x01,  0xfe,  0xee,  0x1e,  0x01,  0xfe,  0xfe,  0x1e,
+  0xfe,  0x40,  0x50,  0xfe,  0xc2,  0x50,  0x10,  0x4b,  0x22,  0x4c,  0xfe,  0x8a,  0x10,  0x01,  0x0c,  0x06,
+  0x54,  0xfe,  0x50,  0x12,  0x01,  0xfe,  0xae,  0x1e,  0x01,  0xfe,  0xbe,  0x1e,  0x10,  0x6a,  0x22,  0x6b,
+  0x01,  0x0c,  0x06,  0x65,  0x4e,  0x01,  0xc2,  0x0f,  0xfe,  0x1f,  0x80,  0x04,  0xfe,  0x9f,  0x83,  0x33,
+  0x0b,  0x0e,  0x20,  0x6e,  0x0f,  0xfe,  0x44,  0x90,  0x04,  0xfe,  0xc4,  0x93,  0x3a,  0x0b,  0xfe,  0xc6,
+  0x90,  0x04,  0xfe,  0xc6,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x6c,  0x22,  0x6d,  0x01,  0xfe,  0xce,  0x1e,
+  0x01,  0xfe,  0xde,  0x1e,  0x10,  0x68,  0x22,  0x69,  0x0f,  0xfe,  0x40,  0x90,  0x04,  0xfe,  0xc0,  0x93,
+  0x3a,  0x0b,  0xfe,  0xc2,  0x90,  0x04,  0xfe,  0xc2,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0x4b,  0x22,  0x4c,
+  0x10,  0x64,  0x22,  0x34,  0x01,  0x0c,  0x61,  0x24,  0x44,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
+  0xde,  0x09,  0xfe,  0x9e,  0xf0,  0xfe,  0xf2,  0x09,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
+  0xd4,  0xfe,  0x1e,  0x0a,  0xd5,  0xfe,  0x42,  0x0a,  0xd2,  0xfe,  0x1e,  0x0a,  0xd3,  0xfe,  0x42,  0x0a,
+  0xae,  0xfe,  0x12,  0x0a,  0xfe,  0x06,  0xf0,  0xfe,  0x18,  0x0a,  0xaf,  0xa0,  0x05,  0x29,  0x01,  0x41,
+  0xfe,  0xc1,  0x10,  0x14,  0x24,  0xfe,  0xc1,  0x10,  0x01,  0x76,  0x06,  0x07,  0xfe,  0x14,  0x12,  0x01,
+  0x76,  0x06,  0x0d,  0x5d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x74,  0x12,  0xfe,  0x2e,  0x1c,  0x05,  0xfe,
+  0x1a,  0x0c,  0x01,  0x76,  0x06,  0x07,  0x5d,  0x01,  0x76,  0x06,  0x0d,  0x41,  0xfe,  0x2c,  0x1c,  0xfe,
+  0xaa,  0xf0,  0xfe,  0xce,  0x0a,  0xfe,  0xac,  0xf0,  0xfe,  0x66,  0x0a,  0xfe,  0x92,  0x10,  0xc4,  0xf6,
+  0xfe,  0xad,  0xf0,  0xfe,  0x72,  0x0a,  0x05,  0xfe,  0x1a,  0x0c,  0xc5,  0xfe,  0xe7,  0x10,  0xfe,  0x2b,
+  0xf0,  0xbf,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xfe,  0xfe,  0x1c,  0x12,  0xac,  0xfe,  0xd2,  0xf0,
+  0xbf,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x1b,  0xbf,  0x03,  0xe3,  0x23,  0x07,  0x1b,  0xbf,  0xd4,  0x5b,
+  0xd5,  0x5b,  0xd2,  0x5b,  0xd3,  0x5b,  0xc4,  0xc5,  0xfe,  0xa9,  0x10,  0x75,  0x5e,  0x32,  0x1f,  0x7f,
+  0x01,  0x42,  0x19,  0xfe,  0x35,  0x00,  0xfe,  0x01,  0xf0,  0x70,  0x19,  0x98,  0x05,  0x70,  0xfe,  0x74,
+  0x18,  0x23,  0xfe,  0x00,  0xf8,  0x1b,  0x5b,  0x7d,  0x12,  0x01,  0xfe,  0x78,  0x0f,  0x4d,  0x01,  0xfe,
+  0x96,  0x1a,  0x21,  0x30,  0x77,  0x7d,  0x1d,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x0d,  0x2b,  0xfe,  0xe2,
+  0x0b,  0x01,  0x0c,  0x06,  0x54,  0xfe,  0xa6,  0x12,  0x01,  0x0c,  0x06,  0x24,  0xfe,  0x88,  0x13,  0x21,
+  0x6e,  0xc7,  0x01,  0xfe,  0x1e,  0x1f,  0x0f,  0xfe,  0x83,  0x80,  0x04,  0xfe,  0x83,  0x83,  0xfe,  0xc9,
+  0x47,  0x0b,  0x0e,  0xfe,  0xc8,  0x44,  0xfe,  0x42,  0x13,  0x0f,  0xfe,  0x04,  0x91,  0x04,  0xfe,  0x84,
+  0x93,  0xfe,  0xca,  0x57,  0x0b,  0xfe,  0x86,  0x91,  0x04,  0xfe,  0x86,  0x93,  0xfe,  0xcb,  0x57,  0x0b,
+  0x0e,  0x7a,  0x30,  0xfe,  0x40,  0x59,  0xfe,  0xc1,  0x59,  0x8e,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0x10,
+  0x97,  0x22,  0x98,  0xd9,  0x6a,  0xda,  0x6b,  0x01,  0xc2,  0xc8,  0x7a,  0x30,  0x20,  0x6e,  0xdb,  0x64,
+  0xdc,  0x34,  0x91,  0x6c,  0x7e,  0x6d,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xfe,  0x04,  0xfa,  0x64,
+  0xfe,  0x05,  0xfa,  0x34,  0x01,  0xfe,  0x6a,  0x16,  0xa3,  0x26,  0x10,  0x97,  0x10,  0x98,  0x91,  0x6c,
+  0x7e,  0x6d,  0xfe,  0x14,  0x10,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x91,  0x4b,  0x7e,  0x4c,  0x01,
+  0x0c,  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x10,  0x58,  0xfe,  0x91,  0x58,
+  0xfe,  0x14,  0x59,  0xfe,  0x95,  0x59,  0x05,  0x5b,  0x01,  0x0c,  0x06,  0x24,  0x1b,  0x40,  0x01,  0x0c,
+  0x06,  0xfe,  0xf7,  0x00,  0x44,  0x78,  0x01,  0xfe,  0x8e,  0x1e,  0x4f,  0x0f,  0xfe,  0x10,  0x90,  0x04,
+  0xfe,  0x90,  0x93,  0x3a,  0x0b,  0xfe,  0x92,  0x90,  0x04,  0xfe,  0x92,  0x93,  0x79,  0x0b,  0x0e,  0xfe,
+  0xbd,  0x10,  0x01,  0x43,  0x09,  0xbb,  0x1b,  0xfe,  0x6e,  0x0a,  0x15,  0xbb,  0x01,  0x0c,  0x06,  0x0d,
+  0xfe,  0x14,  0x13,  0x03,  0x4b,  0x3b,  0x4c,  0x8e,  0xfe,  0x6e,  0x0a,  0xfe,  0x0c,  0x58,  0xfe,  0x8d,
+  0x58,  0x05,  0x5b,  0x26,  0x3e,  0x0f,  0xfe,  0x19,  0x80,  0x04,  0xfe,  0x99,  0x83,  0x33,  0x0b,  0x0e,
+  0xfe,  0xe5,  0x10,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1a,  0x12,  0xfe,  0x6c,  0x19,  0xfe,  0x19,  0x41,
+  0xfe,  0x6b,  0x18,  0xac,  0xfe,  0xd1,  0xf0,  0xef,  0x1f,  0x92,  0x01,  0x42,  0x19,  0xfe,  0x44,  0x00,
+  0xfe,  0x90,  0x10,  0xfe,  0x6c,  0x19,  0xd9,  0x4b,  0xfe,  0xed,  0x19,  0xda,  0x4c,  0xfe,  0x0c,  0x51,
+  0xfe,  0x8e,  0x51,  0xfe,  0x6b,  0x18,  0x23,  0xfe,  0x00,  0xff,  0x31,  0xfe,  0x76,  0x10,  0xac,  0xfe,
+  0xd2,  0xf0,  0xfe,  0xba,  0x0c,  0xfe,  0x76,  0x18,  0x23,  0x1d,  0x5d,  0x03,  0xe3,  0x23,  0x07,  0xfe,
+  0x08,  0x13,  0x19,  0xfe,  0x16,  0x00,  0x05,  0x70,  0xfe,  0xd1,  0xf0,  0xfe,  0xcc,  0x0c,  0x1f,  0x92,
+  0x01,  0x42,  0x19,  0xfe,  0x17,  0x00,  0x5c,  0xfe,  0xce,  0xf0,  0xfe,  0xd2,  0x0c,  0xfe,  0x3e,  0x10,
+  0xfe,  0xcd,  0xf0,  0xfe,  0xde,  0x0c,  0x19,  0xfe,  0x22,  0x00,  0x05,  0x70,  0xfe,  0xcb,  0xf0,  0xfe,
+  0xea,  0x0c,  0x19,  0xfe,  0x24,  0x00,  0x05,  0x70,  0xfe,  0xd0,  0xf0,  0xfe,  0xf4,  0x0c,  0x19,  0x94,
+  0xfe,  0x1c,  0x10,  0xfe,  0xcf,  0xf0,  0xfe,  0xfe,  0x0c,  0x19,  0x4a,  0xf3,  0xfe,  0xcc,  0xf0,  0xef,
+  0x01,  0x76,  0x06,  0x24,  0x4d,  0x19,  0xfe,  0x12,  0x00,  0x37,  0x13,  0xfe,  0x4e,  0x11,  0x2f,  0xfe,
+  0x16,  0x0d,  0xfe,  0x9e,  0xf0,  0xfe,  0x2a,  0x0d,  0xfe,  0x01,  0x48,  0x1b,  0x3c,  0x37,  0x88,  0xf5,
+  0xd4,  0x29,  0xd5,  0x29,  0xd2,  0x29,  0xd3,  0x29,  0x37,  0xfe,  0x9c,  0x32,  0x2f,  0xfe,  0x3e,  0x0d,
+  0x2a,  0x3c,  0xae,  0xfe,  0x62,  0x0d,  0xaf,  0xa0,  0xd4,  0x9f,  0xd5,  0x9f,  0xd2,  0x9f,  0xd3,  0x9f,
+  0x05,  0x29,  0x01,  0x41,  0xfe,  0xd3,  0x10,  0x15,  0xfe,  0xe8,  0x00,  0xc4,  0xc5,  0x75,  0xd7,  0x99,
+  0xd8,  0x9c,  0xfe,  0x89,  0xf0,  0x29,  0x27,  0x25,  0xbe,  0xd7,  0x99,  0xd8,  0x9c,  0x2f,  0xfe,  0x8c,
+  0x0d,  0x16,  0x29,  0x27,  0x25,  0xbd,  0xfe,  0x01,  0x48,  0xa4,  0x19,  0xfe,  0x42,  0x00,  0x05,  0x70,
+  0x90,  0x07,  0xfe,  0x81,  0x49,  0x1b,  0xfe,  0x64,  0x0e,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x44,  0x13,
+  0x19,  0x00,  0x2d,  0x0d,  0xfe,  0x54,  0x12,  0x2d,  0xfe,  0x28,  0x00,  0x2b,  0xfe,  0xda,  0x0e,  0x0a,
+  0x57,  0x01,  0x18,  0x09,  0x00,  0x36,  0x46,  0xfe,  0x28,  0x00,  0xfe,  0xfa,  0x10,  0x01,  0xfe,  0xf4,
+  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x0a,  0xba,  0x01,  0xfe,  0x58,  0x10,  0x40,  0x15,  0x56,  0x01,  0x85,
+  0x05,  0x35,  0x19,  0xfe,  0x44,  0x00,  0x2d,  0x0d,  0xf7,  0x46,  0x0d,  0xfe,  0xcc,  0x10,  0x01,  0xa7,
+  0x46,  0x0d,  0xfe,  0xc2,  0x10,  0x01,  0xa7,  0x0f,  0xfe,  0x19,  0x82,  0x04,  0xfe,  0x99,  0x83,  0xfe,
+  0xcc,  0x47,  0x0b,  0x0e,  0xfe,  0x34,  0x46,  0xa5,  0x46,  0x0d,  0x19,  0xfe,  0x43,  0x00,  0xfe,  0xa2,
+  0x10,  0x01,  0x0c,  0x61,  0x0d,  0x44,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x40,  0x15,
+  0x56,  0x01,  0x85,  0x7d,  0x0d,  0x40,  0x51,  0x01,  0xfe,  0x9e,  0x1e,  0x05,  0xfe,  0x3a,  0x03,  0x01,
+  0x0c,  0x06,  0x0d,  0x5d,  0x46,  0x0d,  0x19,  0x00,  0xfe,  0x62,  0x10,  0x01,  0x76,  0x06,  0x12,  0xfe,
+  0x5c,  0x12,  0x01,  0x0c,  0x06,  0x12,  0xfe,  0x52,  0x13,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,
+  0x8e,  0x0e,  0xfe,  0x1c,  0x1c,  0xfe,  0x9d,  0xf0,  0xfe,  0x94,  0x0e,  0x01,  0x0c,  0x61,  0x12,  0x44,
+  0xfe,  0x9f,  0x10,  0x19,  0xfe,  0x15,  0x00,  0xfe,  0x04,  0xe6,  0x0d,  0x4f,  0xfe,  0x2e,  0x10,  0x19,
+  0xfe,  0x13,  0x00,  0xfe,  0x10,  0x10,  0x19,  0xfe,  0x47,  0x00,  0xf1,  0x19,  0xfe,  0x41,  0x00,  0xa2,
+  0x19,  0xfe,  0x24,  0x00,  0x86,  0xc4,  0xc5,  0x75,  0x03,  0x81,  0x1e,  0x2b,  0xea,  0x4f,  0xfe,  0x04,
+  0xe6,  0x12,  0xfe,  0x9d,  0x41,  0xfe,  0x1c,  0x42,  0x40,  0x01,  0xf4,  0x05,  0x35,  0xfe,  0x12,  0x1c,
+  0x1f,  0x0d,  0x47,  0xb5,  0xc3,  0x1f,  0xfe,  0x31,  0x00,  0x47,  0xb8,  0x01,  0xfe,  0xd4,  0x11,  0x05,
+  0xe9,  0x51,  0xfe,  0x06,  0xec,  0xe0,  0xfe,  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,
+  0xfe,  0x06,  0xea,  0xe0,  0xfe,  0x47,  0x4b,  0x45,  0xfe,  0x75,  0x57,  0x03,  0x67,  0xfe,  0x98,  0x56,
+  0xfe,  0x38,  0x12,  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x44,  0x48,  0x60,  0x01,  0x0c,  0x06,  0x28,  0xfe,
+  0x18,  0x13,  0x0a,  0x57,  0x01,  0x18,  0x3e,  0xfe,  0x41,  0x58,  0x0a,  0xba,  0xfe,  0xfa,  0x14,  0xfe,
+  0x49,  0x54,  0xb0,  0xfe,  0x5e,  0x0f,  0x05,  0xfe,  0x3a,  0x03,  0x0a,  0x67,  0xfe,  0xe0,  0x14,  0xfe,
+  0x0e,  0x47,  0x46,  0x28,  0xfe,  0xce,  0x45,  0x31,  0x51,  0xfe,  0xce,  0x47,  0xfe,  0xad,  0x13,  0x05,
+  0x35,  0x21,  0x2c,  0x09,  0x1a,  0xfe,  0x98,  0x12,  0x26,  0x20,  0x96,  0x20,  0xe7,  0xfe,  0x08,  0x1c,
+  0xfe,  0x7c,  0x19,  0xfe,  0xfd,  0x19,  0xfe,  0x0a,  0x1c,  0x03,  0xe5,  0xfe,  0x48,  0x55,  0xa5,  0x3b,
+  0xfe,  0x62,  0x01,  0xfe,  0xc9,  0x55,  0x31,  0xfe,  0x74,  0x10,  0x01,  0xfe,  0xf0,  0x1a,  0x03,  0xfe,
+  0x38,  0x01,  0x3b,  0xfe,  0x3a,  0x01,  0x8e,  0xfe,  0x1e,  0x10,  0xfe,  0x02,  0xec,  0xe7,  0x53,  0x00,
+  0x36,  0xfe,  0x04,  0xec,  0x2c,  0x60,  0xfe,  0x05,  0xf6,  0xfe,  0x34,  0x01,  0x01,  0xfe,  0x62,  0x1b,
+  0x01,  0xfe,  0xce,  0x1e,  0xb2,  0x11,  0xfe,  0x18,  0x13,  0xca,  0xfe,  0x02,  0xea,  0xe7,  0x53,  0x92,
+  0xfe,  0xc3,  0x13,  0x1f,  0x12,  0x47,  0xb5,  0xc3,  0xfe,  0x2a,  0x10,  0x03,  0xfe,  0x38,  0x01,  0x23,
+  0xfe,  0xf0,  0xff,  0x10,  0xe5,  0x03,  0xfe,  0x3a,  0x01,  0x10,  0xfe,  0x62,  0x01,  0x01,  0xfe,  0x1e,
+  0x1e,  0x20,  0x2c,  0x15,  0x56,  0x01,  0xfe,  0x9e,  0x1e,  0x13,  0x07,  0x02,  0x26,  0x02,  0x21,  0x96,
+  0xc7,  0x20,  0x96,  0x09,  0x92,  0xfe,  0x79,  0x13,  0x1f,  0x1d,  0x47,  0xb5,  0xc3,  0xfe,  0xe1,  0x10,
+  0xcf,  0xfe,  0x03,  0xdc,  0xfe,  0x73,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xcf,  0xfe,  0x03,  0xdc,  0xfe,
+  0x5b,  0x57,  0xfe,  0x80,  0x5d,  0x02,  0xfe,  0x03,  0x57,  0xcf,  0x26,  0xfe,  0x00,  0xcc,  0x02,  0xfe,
+  0x03,  0x57,  0xcf,  0x89,  0x02,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x0f,  0xfe,  0x1c,  0x80,
+  0x04,  0xfe,  0x9c,  0x83,  0x33,  0x0b,  0x0e,  0x09,  0x07,  0xfe,  0x3a,  0x13,  0x0f,  0xfe,  0x1e,  0x80,
+  0x04,  0xfe,  0x9e,  0x83,  0x33,  0x0b,  0x0e,  0xfe,  0x2a,  0x13,  0x0f,  0xfe,  0x1d,  0x80,  0x04,  0xfe,
+  0x9d,  0x83,  0xfe,  0xf9,  0x13,  0x0e,  0xfe,  0x1c,  0x13,  0x01,  0xfe,  0xee,  0x1e,  0xac,  0xfe,  0x14,
+  0x13,  0x01,  0xfe,  0xfe,  0x1e,  0xfe,  0x81,  0x58,  0xfa,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,
+  0x0d,  0xfe,  0x3c,  0x50,  0xa2,  0x01,  0xfe,  0x92,  0x1b,  0x01,  0x43,  0x09,  0x56,  0xfb,  0x01,  0xfe,
+  0xc8,  0x1a,  0x01,  0x0c,  0x06,  0x28,  0xa4,  0x01,  0xfe,  0xf4,  0x1c,  0x01,  0xfe,  0x00,  0x1d,  0x15,
+  0xfe,  0xe9,  0x00,  0x01,  0x0c,  0x06,  0x4a,  0xfe,  0x4e,  0x13,  0x01,  0xfe,  0x22,  0x1b,  0xfe,  0x1e,
+  0x1c,  0x0f,  0xfe,  0x14,  0x90,  0x04,  0xfe,  0x94,  0x93,  0x3a,  0x0b,  0xfe,  0x96,  0x90,  0x04,  0xfe,
+  0x96,  0x93,  0x79,  0x0b,  0x0e,  0x10,  0xfe,  0x64,  0x01,  0x22,  0xfe,  0x66,  0x01,  0x01,  0x0c,  0x06,
+  0x65,  0xf9,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,  0x33,  0x0b,  0x0e,  0x77,  0xfe,  0x01,
+  0xec,  0x2c,  0xfe,  0x80,  0x40,  0x20,  0x2c,  0x7a,  0x30,  0x15,  0xdf,  0x40,  0x21,  0x2c,  0xfe,  0x00,
+  0x40,  0x8d,  0x2c,  0x02,  0xfe,  0x08,  0x1c,  0x03,  0xfe,  0xac,  0x00,  0xfe,  0x06,  0x58,  0x03,  0xfe,
+  0xae,  0x00,  0xfe,  0x07,  0x58,  0x03,  0xfe,  0xb0,  0x00,  0xfe,  0x08,  0x58,  0x03,  0xfe,  0xb2,  0x00,
+  0xfe,  0x09,  0x58,  0xfe,  0x0a,  0x1c,  0x2e,  0x49,  0x20,  0xe0,  0x26,  0x10,  0x66,  0x10,  0x55,  0x10,
+  0x6f,  0x13,  0x57,  0x52,  0x4f,  0x1c,  0x28,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,  0x88,
+  0x11,  0x46,  0x1a,  0x13,  0x5a,  0x52,  0x1c,  0x4a,  0xfe,  0x90,  0x4d,  0xfe,  0x91,  0x54,  0x2b,  0xfe,
+  0x9e,  0x11,  0x2e,  0x1a,  0x20,  0x2c,  0x90,  0x34,  0x60,  0x21,  0x2c,  0xfe,  0x00,  0x40,  0x8d,  0x2c,
+  0x15,  0xdf,  0xfe,  0x14,  0x56,  0xfe,  0xd6,  0xf0,  0xfe,  0xb2,  0x11,  0xfe,  0x12,  0x1c,  0x75,  0xfe,
+  0x14,  0x1c,  0xfe,  0x10,  0x1c,  0xfe,  0x18,  0x1c,  0x02,  0x51,  0xfe,  0x0c,  0x14,  0xfe,  0x0e,  0x47,
+  0xfe,  0x07,  0xe6,  0x28,  0xfe,  0xce,  0x47,  0xfe,  0xf5,  0x13,  0x02,  0x01,  0xa7,  0x90,  0x34,  0x60,
+  0xfe,  0x06,  0x80,  0xfe,  0x48,  0x47,  0xfe,  0x42,  0x13,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x34,
+  0x13,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,  0x36,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,
+  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,
+  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x5c,  0x01,  0x85,  0xf2,  0x09,  0x9b,  0xa4,  0xfe,  0x14,  0x56,  0xfe,
+  0xd6,  0xf0,  0xfe,  0xec,  0x11,  0x02,  0xfe,  0x44,  0x58,  0x77,  0xfe,  0x01,  0xec,  0xb8,  0xfe,  0x9e,
+  0x40,  0xfe,  0x9d,  0xe7,  0x00,  0xfe,  0x9c,  0xe7,  0x12,  0x8d,  0x30,  0x01,  0xf4,  0xfe,  0xdd,  0x10,
+  0x37,  0xd7,  0x99,  0xd8,  0x9c,  0x27,  0x25,  0xee,  0x09,  0x12,  0xfe,  0x48,  0x12,  0x09,  0x0d,  0xfe,
+  0x56,  0x12,  0x09,  0x1d,  0xfe,  0x30,  0x12,  0x09,  0xdd,  0x1b,  0xfe,  0xc4,  0x13,  0x09,  0xfe,  0x23,
+  0x00,  0x1b,  0xfe,  0xd0,  0x13,  0x09,  0x07,  0x1b,  0xfe,  0x34,  0x14,  0x09,  0x24,  0xfe,  0x12,  0x12,
+  0x09,  0x00,  0x1b,  0x29,  0x1f,  0xdd,  0x01,  0x42,  0xa1,  0x32,  0x01,  0x08,  0xae,  0x41,  0x02,  0x32,
+  0xfe,  0x62,  0x08,  0x0a,  0xe1,  0x01,  0xfe,  0x58,  0x10,  0x15,  0x9b,  0x05,  0x35,  0x32,  0x01,  0x43,
+  0x09,  0xbb,  0xfe,  0xd7,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0x8e,  0xfe,  0x80,  0x13,  0x01,  0x0c,  0x06,
+  0x54,  0xfe,  0x72,  0x12,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,  0x55,  0xb0,  0xfe,
+  0x4a,  0x13,  0x21,  0x6e,  0xfe,  0x26,  0x13,  0x03,  0x97,  0x3b,  0x98,  0x8e,  0xfe,  0xb6,  0x0e,  0x10,
+  0x6a,  0x22,  0x6b,  0x26,  0x10,  0x97,  0x10,  0x98,  0x01,  0xc2,  0x2e,  0x49,  0x88,  0x20,  0x6e,  0x01,
+  0xfe,  0x6a,  0x16,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x04,  0x55,  0xfe,  0xa5,  0x55,  0xfe,  0x04,  0xfa,
+  0x64,  0xfe,  0x05,  0xfa,  0x34,  0xfe,  0x8f,  0x10,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x40,  0x56,  0xfe,
+  0xe1,  0x56,  0x10,  0x6c,  0x22,  0x6d,  0x71,  0xdb,  0x64,  0xdc,  0x34,  0xfe,  0x44,  0x55,  0xfe,  0xe5,
+  0x55,  0x03,  0x68,  0x3b,  0x69,  0xfe,  0x00,  0x56,  0xfe,  0xa1,  0x56,  0x10,  0x68,  0x22,  0x69,  0x01,
+  0x0c,  0x06,  0x54,  0xf9,  0x21,  0x6e,  0xfe,  0x1f,  0x40,  0x03,  0x6a,  0x3b,  0x6b,  0xfe,  0x2c,  0x50,
+  0xfe,  0xae,  0x50,  0x03,  0x6c,  0x3b,  0x6d,  0xfe,  0x44,  0x50,  0xfe,  0xc6,  0x50,  0x03,  0x68,  0x3b,
+  0x69,  0xfe,  0x08,  0x50,  0xfe,  0x8a,  0x50,  0x03,  0x4b,  0x3b,  0x4c,  0xfe,  0x40,  0x50,  0xfe,  0xc2,
+  0x50,  0x05,  0x73,  0x2e,  0x07,  0x20,  0x9e,  0x05,  0x72,  0x32,  0x01,  0x08,  0x16,  0x3d,  0x27,  0x25,
+  0xee,  0x09,  0x07,  0x2b,  0x3d,  0x01,  0x43,  0x09,  0xbb,  0x2b,  0x72,  0x01,  0xa6,  0x23,  0x3f,  0x1b,
+  0x3d,  0x01,  0x0c,  0x06,  0x0d,  0xfe,  0x1e,  0x13,  0x91,  0x4b,  0x7e,  0x4c,  0xfe,  0x0a,  0x55,  0x31,
+  0xfe,  0x8b,  0x55,  0xd9,  0x4b,  0xda,  0x4c,  0xfe,  0x0c,  0x51,  0xfe,  0x8e,  0x51,  0x05,  0x72,  0x01,
+  0xfe,  0x8e,  0x1e,  0xca,  0xfe,  0x19,  0x41,  0x05,  0x72,  0x32,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,
+  0x27,  0x25,  0xbe,  0x2d,  0x1d,  0xc0,  0x2d,  0x0d,  0x83,  0x2d,  0x7f,  0x1b,  0xfe,  0x66,  0x15,  0x05,
+  0x3d,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0xc0,  0x27,  0x25,  0xbd,  0x09,  0x1d,  0x2b,  0x3d,  0x01,  0x08,
+  0x16,  0xc0,  0x27,  0x25,  0xfe,  0xe8,  0x09,  0xfe,  0xc2,  0x49,  0x50,  0x03,  0xb6,  0x1e,  0x83,  0x01,
+  0x38,  0x06,  0x24,  0x31,  0xa1,  0xfe,  0xbb,  0x45,  0x2d,  0x00,  0xa4,  0x46,  0x07,  0x90,  0x3f,  0x01,
+  0xfe,  0xf8,  0x15,  0x01,  0xa6,  0x86,  0xfe,  0x4b,  0x45,  0xfe,  0x20,  0x13,  0x01,  0x43,  0x09,  0x82,
+  0xfe,  0x16,  0x13,  0x03,  0x9a,  0x1e,  0x5d,  0x03,  0x55,  0x1e,  0x31,  0x5e,  0x05,  0x72,  0xfe,  0xc0,
+  0x5d,  0x01,  0xa7,  0xfe,  0x03,  0x17,  0x03,  0x66,  0x8a,  0x10,  0x66,  0x5e,  0x32,  0x01,  0x08,  0x17,
+  0x73,  0x01,  0xfe,  0x56,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,
+  0x09,  0x07,  0x2b,  0x3d,  0x01,  0xfe,  0xbe,  0x16,  0xfe,  0x42,  0x58,  0xfe,  0xe8,  0x14,  0x01,  0xa6,
+  0x86,  0xfe,  0x4a,  0xf4,  0x0d,  0x1b,  0x3d,  0xfe,  0x4a,  0xf4,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,
+  0x09,  0x82,  0x4e,  0x05,  0x72,  0x03,  0x55,  0x8a,  0x10,  0x55,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,
+  0x01,  0xfe,  0x84,  0x19,  0x05,  0x73,  0x01,  0x08,  0x2a,  0x3c,  0x16,  0x3d,  0x27,  0x25,  0xbd,  0x09,
+  0x12,  0x2b,  0x3d,  0x01,  0xfe,  0xe8,  0x17,  0x8b,  0xfe,  0xaa,  0x14,  0xfe,  0xb6,  0x14,  0x86,  0xa8,
+  0xb2,  0x0d,  0x1b,  0x3d,  0xb2,  0x07,  0xfe,  0x0e,  0x12,  0x01,  0x43,  0x09,  0x82,  0x4e,  0x05,  0x72,
+  0x03,  0x6f,  0x8a,  0x10,  0x6f,  0x5e,  0x32,  0x01,  0x08,  0x17,  0x73,  0x01,  0xfe,  0xc0,  0x19,  0x05,
+  0x73,  0x13,  0x07,  0x2f,  0xfe,  0xcc,  0x15,  0x17,  0xfe,  0xe2,  0x15,  0x5f,  0xcc,  0x01,  0x08,  0x26,
+  0x5f,  0x02,  0x8f,  0xfe,  0xde,  0x15,  0x2a,  0xfe,  0xde,  0x15,  0x16,  0xfe,  0xcc,  0x15,  0x5e,  0x32,
+  0x01,  0x08,  0xfe,  0xd5,  0x10,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,  0x23,  0xfe,  0xff,
+  0x7f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xad,
+  0x23,  0x3f,  0xfe,  0x30,  0x56,  0xfe,  0x00,  0x5c,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,
+  0xad,  0x02,  0x13,  0x58,  0xff,  0x02,  0x00,  0x57,  0x52,  0xfe,  0x00,  0x5e,  0x02,  0x13,  0x58,  0xff,
+  0x02,  0x00,  0x57,  0x52,  0xad,  0xfe,  0x0b,  0x58,  0x02,  0x0a,  0x66,  0x01,  0x5c,  0x0a,  0x55,  0x01,
+  0x5c,  0x0a,  0x6f,  0x01,  0x5c,  0x02,  0x01,  0xfe,  0x1e,  0x1f,  0x23,  0x1a,  0xff,  0x03,  0x00,  0x54,
+  0xfe,  0x00,  0xf4,  0x24,  0x52,  0x0f,  0xfe,  0x00,  0x7c,  0x04,  0xfe,  0x07,  0x7c,  0x3a,  0x0b,  0x0e,
+  0xfe,  0x00,  0x71,  0xfe,  0xf9,  0x18,  0xfe,  0x7a,  0x19,  0xfe,  0xfb,  0x19,  0xfe,  0x1a,  0xf7,  0x00,
+  0xfe,  0x1b,  0xf7,  0x00,  0x7a,  0x30,  0x10,  0x68,  0x22,  0x69,  0xd9,  0x6c,  0xda,  0x6d,  0x02,  0xfe,
+  0x62,  0x08,  0xfe,  0x82,  0x4a,  0xfe,  0xe1,  0x1a,  0xfe,  0x83,  0x5a,  0x77,  0x02,  0x01,  0xc6,  0xfe,
+  0x42,  0x48,  0x4f,  0x50,  0x45,  0x01,  0x08,  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xbe,  0x01,  0x08,
+  0x16,  0xfe,  0xe0,  0x17,  0x27,  0x25,  0xfe,  0xe8,  0x0a,  0xfe,  0xc1,  0x59,  0x03,  0x9a,  0x1e,  0xfe,
+  0xda,  0x12,  0x01,  0x38,  0x06,  0x12,  0xfe,  0xd0,  0x13,  0x26,  0x53,  0x12,  0x48,  0xfe,  0x08,  0x17,
+  0xd1,  0x12,  0x53,  0x12,  0xfe,  0x1e,  0x13,  0x2d,  0xb4,  0x7b,  0xfe,  0x26,  0x17,  0x4d,  0x13,  0x07,
+  0x1c,  0xb4,  0x90,  0x04,  0xfe,  0x78,  0x10,  0xff,  0x02,  0x83,  0x55,  0xf1,  0xff,  0x02,  0x83,  0x55,
+  0x53,  0x1d,  0xfe,  0x12,  0x13,  0xd6,  0xfe,  0x30,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x1c,  0x63,  0x13,
+  0x07,  0xfe,  0x56,  0x10,  0x53,  0x0d,  0xfe,  0x16,  0x13,  0xd6,  0xfe,  0x64,  0x00,  0xb0,  0xfe,  0x80,
+  0x17,  0x0a,  0xfe,  0x64,  0x00,  0x1c,  0x94,  0x13,  0x07,  0xfe,  0x28,  0x10,  0x53,  0x07,  0xfe,  0x60,
+  0x13,  0xd6,  0xfe,  0xc8,  0x00,  0xb0,  0xfe,  0x80,  0x17,  0x0a,  0xfe,  0xc8,  0x00,  0x1c,  0x95,  0x13,
+  0x07,  0x71,  0xd6,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0x8c,  0x17,  0x45,  0xf3,  0xfe,  0x43,  0xf4,  0x96,
+  0xfe,  0x56,  0xf0,  0xfe,  0x9e,  0x17,  0xfe,  0x04,  0xf4,  0x58,  0xfe,  0x43,  0xf4,  0x94,  0xf6,  0x8b,
+  0x01,  0xfe,  0x24,  0x16,  0x23,  0x3f,  0xfc,  0xa8,  0x8c,  0x49,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x49,
+  0xfe,  0x1c,  0x10,  0xa8,  0x8c,  0x80,  0x48,  0xfe,  0xda,  0x17,  0x62,  0x80,  0x71,  0x50,  0x26,  0xfe,
+  0x4d,  0xf4,  0x00,  0xf7,  0x45,  0x13,  0x07,  0xfe,  0xb4,  0x56,  0xfe,  0xc3,  0x58,  0x02,  0x50,  0x13,
+  0x0d,  0x02,  0x50,  0x3e,  0x78,  0x4f,  0x45,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xbe,  0xfe,  0x03,
+  0xea,  0xfe,  0x7e,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0x01,  0x08,  0x16,
+  0xa9,  0x27,  0x25,  0xfe,  0xe9,  0x0a,  0xfe,  0x05,  0xea,  0xfe,  0x7f,  0x01,  0x01,  0x08,  0x16,  0xa9,
+  0x27,  0x25,  0xfe,  0x69,  0x09,  0xfe,  0x02,  0xea,  0xfe,  0x80,  0x01,  0x01,  0x08,  0x16,  0xa9,  0x27,
+  0x25,  0xfe,  0xe8,  0x08,  0x47,  0xfe,  0x81,  0x01,  0x03,  0xb6,  0x1e,  0x83,  0x01,  0x38,  0x06,  0x24,
+  0x31,  0xa2,  0x78,  0xf2,  0x53,  0x07,  0x36,  0xfe,  0x34,  0xf4,  0x3f,  0xa1,  0x78,  0x03,  0x9a,  0x1e,
+  0x83,  0x01,  0x38,  0x06,  0x12,  0x31,  0xf0,  0x4f,  0x45,  0xfe,  0x90,  0x10,  0xfe,  0x40,  0x5a,  0x23,
+  0x3f,  0xfb,  0x8c,  0x49,  0x48,  0xfe,  0xaa,  0x18,  0x62,  0x49,  0x71,  0x8c,  0x80,  0x48,  0xfe,  0xaa,
+  0x18,  0x62,  0x80,  0xfe,  0xb4,  0x56,  0xfe,  0x40,  0x5d,  0x01,  0xc6,  0x01,  0xfe,  0xac,  0x1d,  0xfe,
+  0x02,  0x17,  0xfe,  0xc8,  0x45,  0xfe,  0x5a,  0xf0,  0xfe,  0xc0,  0x18,  0xfe,  0x43,  0x48,  0x2d,  0x93,
+  0x36,  0xfe,  0x34,  0xf4,  0xfe,  0x00,  0x11,  0xfe,  0x40,  0x10,  0x2d,  0xb4,  0x36,  0xfe,  0x34,  0xf4,
+  0x04,  0xfe,  0x34,  0x10,  0x2d,  0xfe,  0x0b,  0x00,  0x36,  0x46,  0x63,  0xfe,  0x28,  0x10,  0xfe,  0xc0,
+  0x49,  0xff,  0x02,  0x00,  0x54,  0xb2,  0xfe,  0x90,  0x01,  0x48,  0xfe,  0xfa,  0x18,  0x45,  0xfe,  0x1c,
+  0xf4,  0x3f,  0xf3,  0xfe,  0x40,  0xf4,  0x96,  0xfe,  0x56,  0xf0,  0xfe,  0x0c,  0x19,  0xfe,  0x04,  0xf4,
+  0x58,  0xfe,  0x40,  0xf4,  0x94,  0xf6,  0x3e,  0x2d,  0x93,  0x4e,  0xd0,  0x0d,  0x21,  0xfe,  0x7f,  0x01,
+  0xfe,  0xc8,  0x46,  0xfe,  0x24,  0x13,  0x8c,  0x00,  0x5d,  0x26,  0x21,  0xfe,  0x7e,  0x01,  0xfe,  0xc8,
+  0x45,  0xfe,  0x14,  0x13,  0x21,  0xfe,  0x80,  0x01,  0xfe,  0x48,  0x45,  0xfa,  0x21,  0xfe,  0x81,  0x01,
+  0xfe,  0xc8,  0x44,  0x4e,  0x26,  0x02,  0x13,  0x07,  0x02,  0x78,  0x45,  0x50,  0x13,  0x0d,  0x02,  0x14,
+  0x07,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,  0x0d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x14,
+  0x1d,  0x01,  0x08,  0x17,  0xfe,  0x82,  0x19,  0x5f,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x02,  0x14,  0x07,
+  0x01,  0x08,  0x17,  0xc1,  0x14,  0x1d,  0x01,  0x08,  0x17,  0xc1,  0x14,  0x07,  0x01,  0x08,  0x17,  0xc1,
+  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0xc1,  0x5f,  0xfe,  0x89,  0x4a,  0x01,  0x08,  0x02,  0x50,  0x02,
+  0x14,  0x07,  0x01,  0x08,  0x17,  0x74,  0x14,  0x7f,  0x01,  0x08,  0x17,  0x74,  0x14,  0x12,  0x01,  0x08,
+  0x17,  0x74,  0xfe,  0x89,  0x49,  0x01,  0x08,  0x17,  0x74,  0x14,  0x00,  0x01,  0x08,  0x17,  0x74,  0xfe,
+  0x89,  0x4a,  0x01,  0x08,  0x17,  0x74,  0xfe,  0x09,  0x49,  0x01,  0x08,  0x17,  0x74,  0x5f,  0xcc,  0x01,
+  0x08,  0x02,  0x21,  0xe4,  0x09,  0x07,  0xfe,  0x4c,  0x13,  0xc8,  0x20,  0xe4,  0xfe,  0x49,  0xf4,  0x00,
+  0x4d,  0x5f,  0xa1,  0x5e,  0xfe,  0x01,  0xec,  0xfe,  0x27,  0x01,  0xcc,  0xff,  0x02,  0x00,  0x10,  0x2f,
+  0xfe,  0x3e,  0x1a,  0x01,  0x43,  0x09,  0xfe,  0xe3,  0x00,  0xfe,  0x22,  0x13,  0x16,  0xfe,  0x64,  0x1a,
+  0x26,  0x20,  0x9e,  0x01,  0x41,  0x21,  0x9e,  0x09,  0x07,  0x5d,  0x01,  0x0c,  0x61,  0x07,  0x44,  0x02,
+  0x0a,  0x5a,  0x01,  0x18,  0xfe,  0x00,  0x40,  0xaa,  0x09,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,
+  0x18,  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x9d,  0x01,  0x18,  0xaa,  0xfe,  0x80,  0xe7,  0x1a,
+  0x09,  0x1a,  0x5d,  0xfe,  0x45,  0x58,  0x01,  0xfe,  0xb2,  0x16,  0xaa,  0x02,  0x0a,  0x5a,  0x01,  0x18,
+  0xaa,  0x0a,  0x67,  0x01,  0xa3,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x01,  0xfe,  0x7e,  0x1e,  0xfe,  0x80,
+  0x4c,  0xfe,  0x49,  0xe4,  0x1a,  0xfe,  0x12,  0x13,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x0a,
+  0x67,  0x01,  0x5c,  0x02,  0x1c,  0x1a,  0x87,  0x7c,  0xe5,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,
+  0x24,  0x1c,  0xfe,  0x1d,  0xf7,  0x28,  0xb1,  0xfe,  0x04,  0x1b,  0x01,  0xfe,  0x2a,  0x1c,  0xfa,  0xb3,
+  0x28,  0x7c,  0xfe,  0x2c,  0x01,  0xfe,  0x2f,  0x19,  0x02,  0xc9,  0x2b,  0xfe,  0xf4,  0x1a,  0xfe,  0xfa,
+  0x10,  0x1c,  0x1a,  0x87,  0x03,  0xfe,  0x64,  0x01,  0xfe,  0x00,  0xf4,  0x24,  0xfe,  0x18,  0x58,  0x03,
+  0xfe,  0x66,  0x01,  0xfe,  0x19,  0x58,  0xb3,  0x24,  0x01,  0xfe,  0x0e,  0x1f,  0xfe,  0x30,  0xf4,  0x07,
+  0xfe,  0x3c,  0x50,  0x7c,  0xfe,  0x38,  0x00,  0xfe,  0x0f,  0x79,  0xfe,  0x1c,  0xf7,  0x24,  0xb1,  0xfe,
+  0x50,  0x1b,  0xfe,  0xd4,  0x14,  0x31,  0x02,  0xc9,  0x2b,  0xfe,  0x26,  0x1b,  0xfe,  0xba,  0x10,  0x1c,
+  0x1a,  0x87,  0xfe,  0x83,  0x5a,  0xfe,  0x18,  0xdf,  0xfe,  0x19,  0xde,  0xfe,  0x1d,  0xf7,  0x54,  0xb1,
+  0xfe,  0x72,  0x1b,  0xfe,  0xb2,  0x14,  0xfc,  0xb3,  0x54,  0x7c,  0x12,  0xfe,  0xaf,  0x19,  0xfe,  0x98,
+  0xe7,  0x00,  0x02,  0xc9,  0x2b,  0xfe,  0x66,  0x1b,  0xfe,  0x8a,  0x10,  0x1c,  0x1a,  0x87,  0x8b,  0x0f,
+  0xfe,  0x30,  0x90,  0x04,  0xfe,  0xb0,  0x93,  0x3a,  0x0b,  0xfe,  0x18,  0x58,  0xfe,  0x32,  0x90,  0x04,
+  0xfe,  0xb2,  0x93,  0x3a,  0x0b,  0xfe,  0x19,  0x58,  0x0e,  0xa8,  0xb3,  0x4a,  0x7c,  0x12,  0xfe,  0x0f,
+  0x79,  0xfe,  0x1c,  0xf7,  0x4a,  0xb1,  0xfe,  0xc6,  0x1b,  0xfe,  0x5e,  0x14,  0x31,  0x02,  0xc9,  0x2b,
+  0xfe,  0x96,  0x1b,  0x5c,  0xfe,  0x02,  0xf6,  0x1a,  0x87,  0xfe,  0x18,  0xfe,  0x6a,  0xfe,  0x19,  0xfe,
+  0x6b,  0x01,  0xfe,  0x1e,  0x1f,  0xfe,  0x1d,  0xf7,  0x65,  0xb1,  0xfe,  0xee,  0x1b,  0xfe,  0x36,  0x14,
+  0xfe,  0x1c,  0x13,  0xb3,  0x65,  0x3e,  0xfe,  0x83,  0x58,  0xfe,  0xaf,  0x19,  0xfe,  0x80,  0xe7,  0x1a,
+  0xfe,  0x81,  0xe7,  0x1a,  0x15,  0xfe,  0xdd,  0x00,  0x7a,  0x30,  0x02,  0x7a,  0x30,  0xfe,  0x12,  0x45,
+  0x2b,  0xfe,  0xdc,  0x1b,  0x1f,  0x07,  0x47,  0xb5,  0xc3,  0x05,  0x35,  0xfe,  0x39,  0xf0,  0x75,  0x26,
+  0x02,  0xfe,  0x7e,  0x18,  0x23,  0x1d,  0x36,  0x13,  0x11,  0x02,  0x87,  0x03,  0xe3,  0x23,  0x07,  0xfe,
+  0xef,  0x12,  0xfe,  0xe1,  0x10,  0x90,  0x34,  0x60,  0xfe,  0x02,  0x80,  0x09,  0x56,  0xfe,  0x3c,  0x13,
+  0xfe,  0x82,  0x14,  0xfe,  0x42,  0x13,  0x51,  0xfe,  0x06,  0x83,  0x0a,  0x5a,  0x01,  0x18,  0xcb,  0xfe,
+  0x3e,  0x12,  0xfe,  0x41,  0x48,  0xfe,  0x45,  0x48,  0x01,  0xfe,  0xb2,  0x16,  0xfe,  0x00,  0xcc,  0xcb,
+  0xfe,  0xf3,  0x13,  0x3f,  0x89,  0x09,  0x1a,  0xa5,  0x0a,  0x9d,  0x01,  0x18,  0xfe,  0x80,  0x4c,  0x01,
+  0x85,  0xfe,  0x16,  0x10,  0x09,  0x9b,  0x4e,  0xfe,  0x40,  0x14,  0xfe,  0x24,  0x12,  0xfe,  0x14,  0x56,
+  0xfe,  0xd6,  0xf0,  0xfe,  0x52,  0x1c,  0x1c,  0x0d,  0x02,  0xfe,  0x9c,  0xe7,  0x0d,  0x19,  0xfe,  0x15,
+  0x00,  0x40,  0x8d,  0x30,  0x01,  0xf4,  0x1c,  0x07,  0x02,  0x51,  0xfe,  0x06,  0x83,  0xfe,  0x18,  0x80,
+  0x61,  0x28,  0x44,  0x15,  0x56,  0x01,  0x85,  0x1c,  0x07,  0x02,  0xfe,  0x38,  0x90,  0xfe,  0xba,  0x90,
+  0x91,  0xde,  0x7e,  0xdf,  0xfe,  0x48,  0x55,  0x31,  0xfe,  0xc9,  0x55,  0x02,  0x21,  0xb9,  0x88,  0x20,
+  0xb9,  0x02,  0x0a,  0xba,  0x01,  0x18,  0xfe,  0x41,  0x48,  0x0a,  0x57,  0x01,  0x18,  0xfe,  0x49,  0x44,
+  0x1b,  0xfe,  0x1e,  0x1d,  0x88,  0x89,  0x02,  0x0a,  0x5a,  0x01,  0x18,  0x09,  0x1a,  0xa4,  0x0a,  0x67,
+  0x01,  0xa3,  0x0a,  0x57,  0x01,  0x18,  0x88,  0x89,  0x02,  0xfe,  0x4e,  0xe4,  0x1d,  0x7b,  0xfe,  0x52,
+  0x1d,  0x03,  0xfe,  0x90,  0x00,  0xfe,  0x3a,  0x45,  0xfe,  0x2c,  0x10,  0xfe,  0x4e,  0xe4,  0xdd,  0x7b,
+  0xfe,  0x64,  0x1d,  0x03,  0xfe,  0x92,  0x00,  0xd1,  0x12,  0xfe,  0x1a,  0x10,  0xfe,  0x4e,  0xe4,  0xfe,
+  0x0b,  0x00,  0x7b,  0xfe,  0x76,  0x1d,  0x03,  0xfe,  0x94,  0x00,  0xd1,  0x24,  0xfe,  0x08,  0x10,  0x03,
+  0xfe,  0x96,  0x00,  0xd1,  0x63,  0xfe,  0x4e,  0x45,  0x83,  0xca,  0xff,  0x04,  0x68,  0x54,  0xfe,  0xf1,
+  0x10,  0x23,  0x49,  0xfe,  0x08,  0x1c,  0xfe,  0x67,  0x19,  0xfe,  0x0a,  0x1c,  0xfe,  0x1a,  0xf4,  0xfe,
+  0x00,  0x04,  0x83,  0xb2,  0x1d,  0x48,  0xfe,  0xaa,  0x1d,  0x13,  0x1d,  0x02,  0x09,  0x92,  0xfe,  0x5a,
+  0xf0,  0xfe,  0xba,  0x1d,  0x2e,  0x93,  0xfe,  0x34,  0x10,  0x09,  0x12,  0xfe,  0x5a,  0xf0,  0xfe,  0xc8,
+  0x1d,  0x2e,  0xb4,  0xfe,  0x26,  0x10,  0x09,  0x1d,  0x36,  0x2e,  0x63,  0xfe,  0x1a,  0x10,  0x09,  0x0d,
+  0x36,  0x2e,  0x94,  0xf2,  0x09,  0x07,  0x36,  0x2e,  0x95,  0xa1,  0xc8,  0x02,  0x1f,  0x93,  0x01,  0x42,
+  0xfe,  0x04,  0xfe,  0x99,  0x03,  0x9c,  0x8b,  0x02,  0x2a,  0xfe,  0x1c,  0x1e,  0xfe,  0x14,  0xf0,  0x08,
+  0x2f,  0xfe,  0x0c,  0x1e,  0x2a,  0xfe,  0x1c,  0x1e,  0x8f,  0xfe,  0x1c,  0x1e,  0xfe,  0x82,  0xf0,  0xfe,
+  0x10,  0x1e,  0x02,  0x0f,  0x3f,  0x04,  0xfe,  0x80,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x18,
+  0x80,  0x04,  0xfe,  0x98,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x02,  0x80,  0x04,  0xfe,  0x82,
+  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x80,  0x04,  0xfe,  0x86,  0x83,  0x33,  0x0b,  0x0e,
+  0x02,  0x0f,  0xfe,  0x1b,  0x80,  0x04,  0xfe,  0x9b,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x04,
+  0x80,  0x04,  0xfe,  0x84,  0x83,  0x33,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x80,  0x80,  0x04,  0xfe,  0x80,
+  0x83,  0xfe,  0xc9,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x19,  0x81,  0x04,  0xfe,  0x99,  0x83,  0xfe,
+  0xca,  0x47,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x06,  0x83,  0x04,  0xfe,  0x86,  0x83,  0xfe,  0xce,  0x47,
+  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x2c,  0x90,  0x04,  0xfe,  0xac,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
+  0xfe,  0xae,  0x90,  0x04,  0xfe,  0xae,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x08,  0x90,  0x04,
+  0xfe,  0x88,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x8a,  0x90,  0x04,  0xfe,  0x8a,  0x93,  0x79,
+  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x0c,  0x90,  0x04,  0xfe,  0x8c,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x0f,
+  0xfe,  0x8e,  0x90,  0x04,  0xfe,  0x8e,  0x93,  0x79,  0x0b,  0x0e,  0x02,  0x0f,  0xfe,  0x3c,  0x90,  0x04,
+  0xfe,  0xbc,  0x93,  0x3a,  0x0b,  0x0e,  0x02,  0x8b,  0x0f,  0xfe,  0x03,  0x80,  0x04,  0xfe,  0x83,  0x83,
+  0x33,  0x0b,  0x77,  0x0e,  0xa8,  0x02,  0xff,  0x66,  0x00,  0x00,
+};
+
+STATIC unsigned short _adv_asc38C1600_size =
+        sizeof(_adv_asc38C1600_buf); /* 0x1673 */
+STATIC ADV_DCNT _adv_asc38C1600_chksum =
+        0x0604EF77UL; /* Expanded little-endian checksum. */
+
+/* a_init.c */
+/*
+ * EEPROM Configuration.
+ *
+ * All drivers should use this structure to set the default EEPROM
+ * configuration. The BIOS now uses this structure when it is built.
+ * Additional structure information can be found in a_condor.h where
+ * the structure is defined.
+ *
+ * The *_Field_IsChar structs are needed to correct for endianness.
+ * These values are read from the board 16 bits at a time directly
+ * into the structs. Because some fields are char, the values will be
+ * in the wrong order. The *_Field_IsChar tells when to flip the
+ * bytes. Data read and written to PCI memory is automatically swapped
+ * on big-endian platforms so char fields read as words are actually being
+ * unswapped on big-endian platforms.
+ */
+STATIC ADVEEP_3550_CONFIG
+Default_3550_EEPROM_Config __initdata = {
+    ADV_EEPROM_BIOS_ENABLE,     /* cfg_lsw */
+    0x0000,                     /* cfg_msw */
+    0xFFFF,                     /* disc_enable */
+    0xFFFF,                     /* wdtr_able */
+    0xFFFF,                     /* sdtr_able */
+    0xFFFF,                     /* start_motor */
+    0xFFFF,                     /* tagqng_able */
+    0xFFFF,                     /* bios_scan */
+    0,                          /* scam_tolerant */
+    7,                          /* adapter_scsi_id */
+    0,                          /* bios_boot_delay */
+    3,                          /* scsi_reset_delay */
+    0,                          /* bios_id_lun */
+    0,                          /* termination */
+    0,                          /* reserved1 */
+    0xFFE7,                     /* bios_ctrl */
+    0xFFFF,                     /* ultra_able */
+    0,                          /* reserved2 */
+    ASC_DEF_MAX_HOST_QNG,       /* max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /* max_dvc_qng */
+    0,                          /* dvc_cntl */
+    0,                          /* bug_fix */
+    0,                          /* serial_number_word1 */
+    0,                          /* serial_number_word2 */
+    0,                          /* serial_number_word3 */
+    0,                          /* check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */
+    0,                          /* dvc_err_code */
+    0,                          /* adv_err_code */
+    0,                          /* adv_err_addr */
+    0,                          /* saved_dvc_err_code */
+    0,                          /* saved_adv_err_code */
+    0,                          /* saved_adv_err_addr */
+    0                           /* num_of_err */
+};
+
+STATIC ADVEEP_3550_CONFIG
+ADVEEP_3550_Config_Field_IsChar __initdata = {
+    0,                          /* cfg_lsw */
+    0,                          /* cfg_msw */
+    0,                          /* -disc_enable */
+    0,                          /* wdtr_able */
+    0,                          /* sdtr_able */
+    0,                          /* start_motor */
+    0,                          /* tagqng_able */
+    0,                          /* bios_scan */
+    0,                          /* scam_tolerant */
+    1,                          /* adapter_scsi_id */
+    1,                          /* bios_boot_delay */
+    1,                          /* scsi_reset_delay */
+    1,                          /* bios_id_lun */
+    1,                          /* termination */
+    1,                          /* reserved1 */
+    0,                          /* bios_ctrl */
+    0,                          /* ultra_able */
+    0,                          /* reserved2 */
+    1,                          /* max_host_qng */
+    1,                          /* max_dvc_qng */
+    0,                          /* dvc_cntl */
+    0,                          /* bug_fix */
+    0,                          /* serial_number_word1 */
+    0,                          /* serial_number_word2 */
+    0,                          /* serial_number_word3 */
+    0,                          /* check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* oem_name[16] */
+    0,                          /* dvc_err_code */
+    0,                          /* adv_err_code */
+    0,                          /* adv_err_addr */
+    0,                          /* saved_dvc_err_code */
+    0,                          /* saved_adv_err_code */
+    0,                          /* saved_adv_err_addr */
+    0                           /* num_of_err */
+};
+
+STATIC ADVEEP_38C0800_CONFIG
+Default_38C0800_EEPROM_Config __initdata = {
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
+    0x0000,                     /* 01 cfg_msw */
+    0xFFFF,                     /* 02 disc_enable */
+    0xFFFF,                     /* 03 wdtr_able */
+    0x4444,                     /* 04 sdtr_speed1 */
+    0xFFFF,                     /* 05 start_motor */
+    0xFFFF,                     /* 06 tagqng_able */
+    0xFFFF,                     /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    7,                          /* 09 adapter_scsi_id */
+    0,                          /*    bios_boot_delay */
+    3,                          /* 10 scsi_reset_delay */
+    0,                          /*    bios_id_lun */
+    0,                          /* 11 termination_se */
+    0,                          /*    termination_lvd */
+    0xFFE7,                     /* 12 bios_ctrl */
+    0x4444,                     /* 13 sdtr_speed2 */
+    0x4444,                     /* 14 sdtr_speed3 */
+    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0x4444,                     /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    ADV_PCI_VENDOR_ID,          /* 58 subsysvid */
+    ADV_PCI_DEVID_38C0800_REV1, /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+STATIC ADVEEP_38C0800_CONFIG
+ADVEEP_38C0800_Config_Field_IsChar __initdata = {
+    0,                          /* 00 cfg_lsw */
+    0,                          /* 01 cfg_msw */
+    0,                          /* 02 disc_enable */
+    0,                          /* 03 wdtr_able */
+    0,                          /* 04 sdtr_speed1 */
+    0,                          /* 05 start_motor */
+    0,                          /* 06 tagqng_able */
+    0,                          /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    1,                          /* 09 adapter_scsi_id */
+    1,                          /*    bios_boot_delay */
+    1,                          /* 10 scsi_reset_delay */
+    1,                          /*    bios_id_lun */
+    1,                          /* 11 termination_se */
+    1,                          /*    termination_lvd */
+    0,                          /* 12 bios_ctrl */
+    0,                          /* 13 sdtr_speed2 */
+    0,                          /* 14 sdtr_speed3 */
+    1,                          /* 15 max_host_qng */
+    1,                          /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0,                          /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    0,                          /* 58 subsysvid */
+    0,                          /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+STATIC ADVEEP_38C1600_CONFIG
+Default_38C1600_EEPROM_Config __initdata = {
+    ADV_EEPROM_BIOS_ENABLE,     /* 00 cfg_lsw */
+    0x0000,                     /* 01 cfg_msw */
+    0xFFFF,                     /* 02 disc_enable */
+    0xFFFF,                     /* 03 wdtr_able */
+    0x5555,                     /* 04 sdtr_speed1 */
+    0xFFFF,                     /* 05 start_motor */
+    0xFFFF,                     /* 06 tagqng_able */
+    0xFFFF,                     /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    7,                          /* 09 adapter_scsi_id */
+    0,                          /*    bios_boot_delay */
+    3,                          /* 10 scsi_reset_delay */
+    0,                          /*    bios_id_lun */
+    0,                          /* 11 termination_se */
+    0,                          /*    termination_lvd */
+    0xFFE7,                     /* 12 bios_ctrl */
+    0x5555,                     /* 13 sdtr_speed2 */
+    0x5555,                     /* 14 sdtr_speed3 */
+    ASC_DEF_MAX_HOST_QNG,       /* 15 max_host_qng */
+    ASC_DEF_MAX_DVC_QNG,        /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0x5555,                     /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    ADV_PCI_VENDOR_ID,          /* 58 subsysvid */
+    ADV_PCI_DEVID_38C1600_REV1, /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+STATIC ADVEEP_38C1600_CONFIG
+ADVEEP_38C1600_Config_Field_IsChar __initdata = {
+    0,                          /* 00 cfg_lsw */
+    0,                          /* 01 cfg_msw */
+    0,                          /* 02 disc_enable */
+    0,                          /* 03 wdtr_able */
+    0,                          /* 04 sdtr_speed1 */
+    0,                          /* 05 start_motor */
+    0,                          /* 06 tagqng_able */
+    0,                          /* 07 bios_scan */
+    0,                          /* 08 scam_tolerant */
+    1,                          /* 09 adapter_scsi_id */
+    1,                          /*    bios_boot_delay */
+    1,                          /* 10 scsi_reset_delay */
+    1,                          /*    bios_id_lun */
+    1,                          /* 11 termination_se */
+    1,                          /*    termination_lvd */
+    0,                          /* 12 bios_ctrl */
+    0,                          /* 13 sdtr_speed2 */
+    0,                          /* 14 sdtr_speed3 */
+    1,                          /* 15 max_host_qng */
+    1,                          /*    max_dvc_qng */
+    0,                          /* 16 dvc_cntl */
+    0,                          /* 17 sdtr_speed4 */
+    0,                          /* 18 serial_number_word1 */
+    0,                          /* 19 serial_number_word2 */
+    0,                          /* 20 serial_number_word3 */
+    0,                          /* 21 check_sum */
+    { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, /* 22-29 oem_name[16] */
+    0,                          /* 30 dvc_err_code */
+    0,                          /* 31 adv_err_code */
+    0,                          /* 32 adv_err_addr */
+    0,                          /* 33 saved_dvc_err_code */
+    0,                          /* 34 saved_adv_err_code */
+    0,                          /* 35 saved_adv_err_addr */
+    0,                          /* 36 reserved */
+    0,                          /* 37 reserved */
+    0,                          /* 38 reserved */
+    0,                          /* 39 reserved */
+    0,                          /* 40 reserved */
+    0,                          /* 41 reserved */
+    0,                          /* 42 reserved */
+    0,                          /* 43 reserved */
+    0,                          /* 44 reserved */
+    0,                          /* 45 reserved */
+    0,                          /* 46 reserved */
+    0,                          /* 47 reserved */
+    0,                          /* 48 reserved */
+    0,                          /* 49 reserved */
+    0,                          /* 50 reserved */
+    0,                          /* 51 reserved */
+    0,                          /* 52 reserved */
+    0,                          /* 53 reserved */
+    0,                          /* 54 reserved */
+    0,                          /* 55 reserved */
+    0,                          /* 56 cisptr_lsw */
+    0,                          /* 57 cisprt_msw */
+    0,                          /* 58 subsysvid */
+    0,                          /* 59 subsysid */
+    0,                          /* 60 reserved */
+    0,                          /* 61 reserved */
+    0,                          /* 62 reserved */
+    0                           /* 63 reserved */
+};
+
+/*
+ * Initialize the ADV_DVC_VAR structure.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+STATIC int __init
+AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+{
+    ushort      warn_code;
+    AdvPortAddr iop_base;
+    uchar       pci_cmd_reg;
+    int         status;
+
+    warn_code = 0;
+    asc_dvc->err_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * PCI Command Register
+     *
+     * Note: AscPCICmdRegBits_BusMastering definition (0x0007) includes
+     * I/O Space Control, Memory Space Control and Bus Master Control bits.
+     */
+
+    if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
+                            AscPCIConfigCommandRegister))
+         & AscPCICmdRegBits_BusMastering)
+        != AscPCICmdRegBits_BusMastering)
+    {
+        pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
+
+        DvcAdvWritePCIConfigByte(asc_dvc,
+                AscPCIConfigCommandRegister, pci_cmd_reg);
+
+        if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister))
+             & AscPCICmdRegBits_BusMastering)
+            != AscPCICmdRegBits_BusMastering)
+        {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+    }
+
+    /*
+     * PCI Latency Timer
+     *
+     * If the "latency timer" register is 0x20 or above, then we don't need
+     * to change it.  Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
+     * comes up less than 0x20).
+     */
+    if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
+        DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20);
+        if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20)
+        {
+            warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+        }
+    }
+
+    /*
+     * Save the state of the PCI Configuration Command Register
+     * "Parity Error Response Control" Bit. If the bit is clear (0),
+     * in AdvInitAsc3550/38C0800Driver() tell the microcode to ignore
+     * DMA parity errors.
+     */
+    asc_dvc->cfg->control_flag = 0;
+    if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
+         & AscPCICmdRegBits_ParErrRespCtrl)) == 0)
+    {
+        asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
+    }
+
+    asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
+      ADV_LIB_VERSION_MINOR;
+    asc_dvc->cfg->chip_version =
+      AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+
+    ASC_DBG2(1, "AdvInitGetConfig: iopb_chip_id_1: 0x%x 0x%x\n",
+        (ushort) AdvReadByteRegister(iop_base, IOPB_CHIP_ID_1),
+        (ushort) ADV_CHIP_ID_BYTE);
+
+    ASC_DBG2(1, "AdvInitGetConfig: iopw_chip_id_0: 0x%x 0x%x\n",
+        (ushort) AdvReadWordRegister(iop_base, IOPW_CHIP_ID_0),
+        (ushort) ADV_CHIP_ID_WORD);
+
+    /*
+     * Reset the chip to start and allow register writes.
+     */
+    if (AdvFindSignature(iop_base) == 0)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+        return ADV_ERROR;
+    }
+    else {
+        /*
+         * The caller must set 'chip_type' to a valid setting.
+         */
+        if (asc_dvc->chip_type != ADV_CHIP_ASC3550 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C0800 &&
+            asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
+        {
+            asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+            return ADV_ERROR;
+        }
+
+        /*
+         * Reset Chip.
+         */
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_RESET);
+        DvcSleepMilliSecond(100);
+        AdvWriteWordRegister(iop_base, IOPW_CTRL_REG,
+            ADV_CTRL_REG_CMD_WR_IO_REG);
+
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+        {
+            if ((status = AdvInitFrom38C1600EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+        {
+            if ((status = AdvInitFrom38C0800EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        } else
+        {
+            if ((status = AdvInitFrom3550EEP(asc_dvc)) == ADV_ERROR)
+            {
+                return ADV_ERROR;
+            }
+        }
+        warn_code |= status;
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-3550.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+STATIC int
+AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ADV_DCNT    sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    int         word;
+    int         j;
+    int         adv_asc3550_expanded_size;
+    ADV_CARR_T  *carrp;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able = 0, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC3550.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC3550)
+    {
+        asc_dvc->err_code |= ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+    {
+        ushort  bios_version, major, minor;
+
+        bios_version = bios_mem[(ASC_MC_BIOS_VERSION - ASC_MC_BIOSMEM)/2];
+        major = (bios_version  >> 12) & 0xF;
+        minor = (bios_version  >> 8) & 0xF;
+        if (major < 3 || (major == 3 && minor == 1))
+        {
+            /* BIOS 3.1 and earlier location of 'wdtr_able' variable. */
+            AdvReadWordLram(iop_base, 0x120, wdtr_able);
+        } else
+        {
+            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+        }
+    }
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc3550_size; i++)
+    {
+        if (_adv_asc3550_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc3550_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                    _adv_asc3550_buf[i + 3] << 8) |
+                _adv_asc3550_buf[i + 2]));
+                word++;
+            }
+            i += 3;
+        } else if (_adv_asc3550_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc3550_buf[i + 2] << 8) |
+                _adv_asc3550_buf[i + 1]));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc3550_buf[(_adv_asc3550_buf[i] * 2) + 1] << 8) |
+                _adv_asc3550_buf[_adv_asc3550_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc3550_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-3550 Internal RAM (8KB).
+     */
+    for (; word < ADV_3550_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc3550_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_asc3550_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read and save microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC3550.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC3550);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-3550, setting the START_CTL_EMFU [3:2] bits sets a FIFO
+     * threshold of 128 bytes. This register is only accessible to the host.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        START_CTL_EMFU | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 based on the ULTRA EEPROM per TID
+     * bitmask. These values determine the maximum SDTR speed negotiated
+     * with a device.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     *
+     * 4-bit speed  SDTR speed name
+     * ===========  ===============
+     * 0000b (0x0)  SDTR disabled
+     * 0001b (0x1)  5 Mhz
+     * 0010b (0x2)  10 Mhz
+     * 0011b (0x3)  20 Mhz (Ultra)
+     * 0100b (0x4)  40 Mhz (LVD/Ultra2)
+     * 0101b (0x5)  80 Mhz (LVD2/Ultra3)
+     * 0110b (0x6)  Undefined
+     * .
+     * 1111b (0xF)  Undefined
+     */
+    word = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (ADV_TID_TO_TIDMASK(tid) & asc_dvc->ultra_able)
+        {
+            /* Set Ultra speed for TID 'tid'. */
+            word |= (0x3 << (4 * (tid % 4)));
+        } else
+        {
+            /* Set Fast speed for TID 'tid'. */
+            word |= (0x2 << (4 * (tid % 4)));
+        }
+        if (tid == 3) /* Check if done with sdtr_speed1. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, word);
+            word = 0;
+        } else if (tid == 7) /* Check if done with sdtr_speed2. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, word);
+            word = 0;
+        } else if (tid == 11) /* Check if done with sdtr_speed3. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, word);
+            word = 0;
+        } else if (tid == 15) /* Check if done with sdtr_speed4. */
+        {
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, word);
+            /* End of loop. */
+        }
+    }
+
+    /*
+     * Set microcode operating variable for the disconnect per TID bitmask.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
+
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If all three connectors are in use, return an error.
+     */
+    if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+        (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
+    {
+            asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+            return ADV_ERROR;
+    }
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If this is a differential board and a single-ended device
+     * is attached to one of the connectors, return an error.
+     */
+    if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
+    {
+        asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If automatic termination control is enabled, then set the
+     * termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting
+     * then 'termination' was set-up in AdvInitFrom3550EEPROM() and
+     * is ready to be 'ored' into SCSI_CFG1.
+     */
+    if (asc_dvc->cfg->termination == 0)
+    {
+        /*
+         * The software always controls termination by setting TERM_CTL_SEL.
+         * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+         */
+        asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+        switch(scsi_cfg1 & CABLE_DETECT)
+        {
+            /* TERM_CTL_H: on, TERM_CTL_L: on */
+            case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
+                asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+                break;
+
+            /* TERM_CTL_H: on, TERM_CTL_L: off */
+            case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
+                asc_dvc->cfg->termination |= TERM_CTL_H;
+                break;
+
+            /* TERM_CTL_H: off, TERM_CTL_L: off */
+            case 0x2: case 0x6:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+     */
+    scsi_cfg1 &= ~TERM_CTL;
+
+    /*
+     * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+     * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+     * referenced, because the hardware internally inverts
+     * the Termination High and Low bits if TERM_POL is set.
+     */
+    scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set filter value and possibly modified termination control
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+        FLTR_DISABLE | scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-3550 has 8KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_8KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address of the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC ICQ physical address start value.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+         ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C0800.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+STATIC int
+AdvInitAsc38C0800Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ADV_DCNT    sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    int         word;
+    int         j;
+    int         adv_asc38C0800_expanded_size;
+    ADV_CARR_T  *carrp;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       byte;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    uchar       max_cmd[ADV_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C0800.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C0800)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * RAM BIST (RAM Built-In Self Test)
+     *
+     * Address : I/O base + offset 0x38h register (byte).
+     * Function: Bit 7-6(RW) : RAM mode
+     *                          Normal Mode   : 0x00
+     *                          Pre-test Mode : 0x40
+     *                          RAM Test Mode : 0x80
+     *           Bit 5       : unused
+     *           Bit 4(RO)   : Done bit
+     *           Bit 3-0(RO) : Status
+     *                          Host Error    : 0x08
+     *                          Int_RAM Error : 0x04
+     *                          RISC Error    : 0x02
+     *                          SCSI Error    : 0x01
+     *                          No Error      : 0x00
+     *
+     * Note: RAM BIST code should be put right here, before loading the
+     * microcode and after saving the RISC memory BIOS region.
+     */
+
+    /*
+     * LRAM Pre-test
+     *
+     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+     * to NORMAL_MODE, return an error too.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+            != NORMAL_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+    }
+
+    /*
+     * LRAM Test - It takes about 1.5 ms to run through the test.
+     *
+     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+     * If Done bit not set or Status not 0, save register byte, set the
+     * err_code, and return an error.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+
+    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+    {
+        /* Get here if Done bit not set or Status not 0. */
+        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+        return ADV_ERROR;
+    }
+
+    /* We need to reset back to normal mode after LRAM test passes. */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     *
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    /* Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc38C0800_size; i++)
+    {
+        if (_adv_asc38C0800_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc38C0800_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                    _adv_asc38C0800_buf[i + 3] << 8) |
+                    _adv_asc38C0800_buf[i + 2]));
+                word++;
+            }
+            i += 3;
+        } else if (_adv_asc38C0800_buf[i] == 0xfe)
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc38C0800_buf[i + 2] << 8) |
+                _adv_asc38C0800_buf[i + 1]));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                _adv_asc38C0800_buf[(_adv_asc38C0800_buf[i] * 2) + 1] << 8) |
+                _adv_asc38C0800_buf[_adv_asc38C0800_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc38C0800_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-38C0800 Internal RAM (16KB).
+     */
+    for (; word < ADV_38C0800_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc38C0800_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    ASC_DBG2(1, "AdvInitAsc38C0800Driver: word %d, i %d\n", word, i);
+
+    ASC_DBG2(1,
+        "AdvInitAsc38C0800Driver: sum 0x%lx, _adv_asc38C0800_chksum 0x%lx\n",
+        (ulong) sum, (ulong) _adv_asc38C0800_chksum);
+
+    if (sum != _adv_asc38C0800_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC38C0800.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C0800);
+
+    /*
+     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+     * cable detection and then we are able to read C_DET[3:0].
+     *
+     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+     * Microcode Default Value' section below.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-38C0800, set FIFO_THRESH_80B [6:4] bits and START_CTL_TH [3:2]
+     * bits for the default FIFO threshold.
+     *
+     * Note: ASC-38C0800 FIFO threshold has been changed to 256 bytes.
+     *
+     * For DMA Errata #4 set the BC_THRESH_ENB bit.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        BC_THRESH_ENB | FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for DISC and SDTR_SPEED1,
+     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+     * configuration values.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
+
+    /*
+     * Determine SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+
+    /* Read current SCSI_CFG1 Register value. */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If the internal narrow cable is reversed all of the SCSI_CTRL
+     * register signals will be set. Check for and return an error if
+     * this condition is found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * All kind of combinations of devices attached to one of four connectors
+     * are acceptable except HVD device attached. For example, LVD device can
+     * be attached to SE connector while SE device attached to LVD connector.
+     * If LVD device attached to SE connector, it only runs up to Ultra speed.
+     *
+     * If an HVD device is attached to one of LVD connectors, return an error.
+     * However, there is no way to detect HVD device attached to SE connectors.
+     */
+    if (scsi_cfg1 & HVD)
+    {
+        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * If either SE or LVD automatic termination control is enabled, then
+     * set the termination value based on a table listed in a_condor.h.
+     *
+     * If manual termination was specified with an EEPROM setting then
+     * 'termination' was set-up in AdvInitFrom38C0800EEPROM() and is ready to
+     * be 'ored' into SCSI_CFG1.
+     */
+    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
+    {
+        /* SE automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_SE)
+        {
+            /* TERM_SE_HI: on, TERM_SE_LO: on */
+            case 0x1: case 0x2: case 0x3:
+                asc_dvc->cfg->termination |= TERM_SE;
+                break;
+
+            /* TERM_SE_HI: on, TERM_SE_LO: off */
+            case 0x0:
+                asc_dvc->cfg->termination |= TERM_SE_HI;
+                break;
+        }
+    }
+
+    if ((asc_dvc->cfg->termination & TERM_LVD) == 0)
+    {
+        /* LVD automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_LVD)
+        {
+            /* TERM_LVD_HI: on, TERM_LVD_LO: on */
+            case 0x4: case 0x8: case 0xC:
+                asc_dvc->cfg->termination |= TERM_LVD;
+                break;
+
+            /* TERM_LVD_HI: off, TERM_LVD_LO: off */
+            case 0x0:
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_SE and TERM_LVD bits.
+     */
+    scsi_cfg1 &= (~TERM_SE & ~TERM_LVD);
+
+    /*
+     * Invert the TERM_SE and TERM_LVD bits and then set 'scsi_cfg1'.
+     */
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & 0xF0);
+
+    /*
+     * Clear BIG_ENDIAN, DIS_TERM_DRV, Terminator Polarity and HVD/LVD/SE bits
+     * and set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
+     */
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL & ~HVD_LVD_SE);
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set possibly modified termination control and reset DIS_TERM_DRV
+     * bits in the Microcode SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-38C0800 has 16KB internal memory.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+        BIOS_EN | RAM_SZ_16KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build the carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address for the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC ICQ physical address start value.
+     * carr_pa is LE, must be native before write
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC IRQ physical address start value.
+     *
+     * carr_pa is LE, must be native before write *
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * BIOS Handshake Configuration Table and do not perform
+         * a SCSI Bus Reset.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ADV_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Initialize the ASC-38C1600.
+ *
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Needed after initialization for error recovery.
+ */
+STATIC int
+AdvInitAsc38C1600Driver(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr iop_base;
+    ushort      warn_code;
+    ADV_DCNT    sum;
+    int         begin_addr;
+    int         end_addr;
+    ushort      code_sum;
+    long        word;
+    int         j;
+    int         adv_asc38C1600_expanded_size;
+    ADV_CARR_T  *carrp;
+    ADV_DCNT    contig_len;
+    ADV_SDCNT   buf_size;
+    ADV_PADDR   carr_paddr;
+    int         i;
+    ushort      scsi_cfg1;
+    uchar       byte;
+    uchar       tid;
+    ushort      bios_mem[ASC_MC_BIOSLEN/2]; /* BIOS RISC Memory 0x40-0x8F. */
+    ushort      wdtr_able, sdtr_able, ppr_able, tagqng_able;
+    uchar       max_cmd[ASC_MAX_TID + 1];
+
+    /* If there is already an error, don't continue. */
+    if (asc_dvc->err_code != 0)
+    {
+        return ADV_ERROR;
+    }
+
+    /*
+     * The caller must set 'chip_type' to ADV_CHIP_ASC38C1600.
+     */
+    if (asc_dvc->chip_type != ADV_CHIP_ASC38C1600)
+    {
+        asc_dvc->err_code = ASC_IERR_BAD_CHIPTYPE;
+        return ADV_ERROR;
+    }
+
+    warn_code = 0;
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save the RISC memory BIOS region before writing the microcode.
+     * The BIOS may already be loaded and using its RISC LRAM region
+     * so its region must be saved and restored.
+     *
+     * Note: This code makes the assumption, which is currently true,
+     * that a chip reset does not clear RISC LRAM.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ASC_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * RAM BIST (Built-In Self Test)
+     *
+     * Address : I/O base + offset 0x38h register (byte).
+     * Function: Bit 7-6(RW) : RAM mode
+     *                          Normal Mode   : 0x00
+     *                          Pre-test Mode : 0x40
+     *                          RAM Test Mode : 0x80
+     *           Bit 5       : unused
+     *           Bit 4(RO)   : Done bit
+     *           Bit 3-0(RO) : Status
+     *                          Host Error    : 0x08
+     *                          Int_RAM Error : 0x04
+     *                          RISC Error    : 0x02
+     *                          SCSI Error    : 0x01
+     *                          No Error      : 0x00
+     *
+     * Note: RAM BIST code should be put right here, before loading the
+     * microcode and after saving the RISC memory BIOS region.
+     */
+
+    /*
+     * LRAM Pre-test
+     *
+     * Write PRE_TEST_MODE (0x40) to register and wait for 10 milliseconds.
+     * If Done bit not set or low nibble not PRE_TEST_VALUE (0x05), return
+     * an error. Reset to NORMAL_MODE (0x00) and do again. If cannot reset
+     * to NORMAL_MODE, return an error too.
+     */
+    for (i = 0; i < 2; i++)
+    {
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, PRE_TEST_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+        if ((byte & RAM_TEST_DONE) == 0 || (byte & 0x0F) != PRE_TEST_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+
+        AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+        DvcSleepMilliSecond(10);  /* Wait for 10ms before reading back. */
+        if (AdvReadByteRegister(iop_base, IOPB_RAM_BIST)
+            != NORMAL_VALUE)
+        {
+            asc_dvc->err_code |= ASC_IERR_BIST_PRE_TEST;
+            return ADV_ERROR;
+        }
+    }
+
+    /*
+     * LRAM Test - It takes about 1.5 ms to run through the test.
+     *
+     * Write RAM_TEST_MODE (0x80) to register and wait for 10 milliseconds.
+     * If Done bit not set or Status not 0, save register byte, set the
+     * err_code, and return an error.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, RAM_TEST_MODE);
+    DvcSleepMilliSecond(10);  /* Wait for 10ms before checking status. */
+
+    byte = AdvReadByteRegister(iop_base, IOPB_RAM_BIST);
+    if ((byte & RAM_TEST_DONE) == 0 || (byte & RAM_TEST_STATUS) != 0)
+    {
+        /* Get here if Done bit not set or Status not 0. */
+        asc_dvc->bist_err_code = byte;  /* for BIOS display message */
+        asc_dvc->err_code |= ASC_IERR_BIST_RAM_TEST;
+        return ADV_ERROR;
+    }
+
+    /* We need to reset back to normal mode after LRAM test passes. */
+    AdvWriteByteRegister(iop_base, IOPB_RAM_BIST, NORMAL_MODE);
+
+    /*
+     * Load the Microcode
+     *
+     * Write the microcode image to RISC memory starting at address 0.
+     *
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    /*
+     * Assume the following compressed format of the microcode buffer:
+     *
+     *  254 word (508 byte) table indexed by byte code followed
+     *  by the following byte codes:
+     *
+     *    1-Byte Code:
+     *      00: Emit word 0 in table.
+     *      01: Emit word 1 in table.
+     *      .
+     *      FD: Emit word 253 in table.
+     *
+     *    Multi-Byte Code:
+     *      FE WW WW: (3 byte code) Word to emit is the next word WW WW.
+     *      FF BB WW WW: (4 byte code) Emit BB count times next word WW WW.
+     */
+    word = 0;
+    for (i = 253 * 2; i < _adv_asc38C1600_size; i++)
+    {
+        if (_adv_asc38C1600_buf[i] == 0xff)
+        {
+            for (j = 0; j < _adv_asc38C1600_buf[i + 1]; j++)
+            {
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                     _adv_asc38C1600_buf[i + 3] << 8) |
+                     _adv_asc38C1600_buf[i + 2]));
+                word++;
+            }
+           i += 3;
+        } else if (_adv_asc38C1600_buf[i] == 0xfe)
+        {
+                AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                     _adv_asc38C1600_buf[i + 2] << 8) |
+                     _adv_asc38C1600_buf[i + 1]));
+            i += 2;
+            word++;
+        } else
+        {
+            AdvWriteWordAutoIncLram(iop_base, (((ushort)
+                 _adv_asc38C1600_buf[(_adv_asc38C1600_buf[i] * 2) + 1] << 8) |
+                 _adv_asc38C1600_buf[_adv_asc38C1600_buf[i] * 2]));
+            word++;
+        }
+    }
+
+    /*
+     * Set 'word' for later use to clear the rest of memory and save
+     * the expanded mcode size.
+     */
+    word *= 2;
+    adv_asc38C1600_expanded_size = word;
+
+    /*
+     * Clear the rest of ASC-38C1600 Internal RAM (32KB).
+     */
+    for (; word < ADV_38C1600_MEMSIZE; word += 2)
+    {
+        AdvWriteWordAutoIncLram(iop_base, 0);
+    }
+
+    /*
+     * Verify the microcode checksum.
+     */
+    sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+
+    for (word = 0; word < adv_asc38C1600_expanded_size; word += 2)
+    {
+        sum += AdvReadWordAutoIncLram(iop_base);
+    }
+
+    if (sum != _adv_asc38C1600_chksum)
+    {
+        asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Restore the RISC memory BIOS region.
+     */
+    for (i = 0; i < ASC_MC_BIOSLEN/2; i++)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_BIOSMEM + (2 * i), bios_mem[i]);
+    }
+
+    /*
+     * Calculate and write the microcode code checksum to the microcode
+     * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+     */
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+    AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+    code_sum = 0;
+    AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, begin_addr);
+    for (word = begin_addr; word < end_addr; word += 2)
+    {
+        code_sum += AdvReadWordAutoIncLram(iop_base);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+    /*
+     * Read microcode version and date.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+    AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+    /*
+     * Set the chip type to indicate the ASC38C1600.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_CHIP_TYPE, ADV_CHIP_ASC38C1600);
+
+    /*
+     * Write 1 to bit 14 'DIS_TERM_DRV' in the SCSI_CFG1 register.
+     * When DIS_TERM_DRV set to 1, C_DET[3:0] will reflect current
+     * cable detection and then we are able to read C_DET[3:0].
+     *
+     * Note: We will reset DIS_TERM_DRV to 0 in the 'Set SCSI_CFG1
+     * Microcode Default Value' section below.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+    AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, scsi_cfg1 | DIS_TERM_DRV);
+
+    /*
+     * If the PCI Configuration Command Register "Parity Error Response
+     * Control" Bit was clear (0), then set the microcode variable
+     * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+     * to ignore DMA parity errors.
+     */
+    if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_IGNORE_PERR;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * If the BIOS control flag AIPP (Asynchronous Information
+     * Phase Protection) disable bit is not set, then set the firmware
+     * 'control_flag' CONTROL_FLAG_ENABLE_AIPP bit to enable
+     * AIPP checking and encoding.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_AIPP_DIS) == 0)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+        word |= CONTROL_FLAG_ENABLE_AIPP;
+        AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+    }
+
+    /*
+     * For ASC-38C1600 use DMA_CFG0 default values: FIFO_THRESH_80B [6:4],
+     * and START_CTL_TH [3:2].
+     */
+    AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+        FIFO_THRESH_80B | START_CTL_TH | READ_CMD_MRM);
+
+    /*
+     * Microcode operating variables for WDTR, SDTR, and command tag
+     * queuing will be set in AdvInquiryHandling() based on what a
+     * device reports it is capable of in Inquiry byte 7.
+     *
+     * If SCSI Bus Resets have been disabled, then directly set
+     * SDTR and WDTR from the EEPROM configuration. This will allow
+     * the BIOS and warm boot to work without a SCSI bus hang on
+     * the Inquiry caused by host and target mismatched DTR values.
+     * Without the SCSI Bus Reset, before an Inquiry a device can't
+     * be assumed to be in Asynchronous, Narrow mode.
+     */
+    if ((asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS) == 0)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, asc_dvc->wdtr_able);
+        AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, asc_dvc->sdtr_able);
+    }
+
+    /*
+     * Set microcode operating variables for DISC and SDTR_SPEED1,
+     * SDTR_SPEED2, SDTR_SPEED3, and SDTR_SPEED4 based on the EEPROM
+     * configuration values.
+     *
+     * The SDTR per TID bitmask overrides the SDTR_SPEED1, SDTR_SPEED2,
+     * SDTR_SPEED3, and SDTR_SPEED4 values so it is safe to set them
+     * without determining here whether the device supports SDTR.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED1, asc_dvc->sdtr_speed1);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED2, asc_dvc->sdtr_speed2);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED3, asc_dvc->sdtr_speed3);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_SPEED4, asc_dvc->sdtr_speed4);
+
+    /*
+     * Set SCSI_CFG0 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG0 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+        PARITY_EN | QUEUE_128 | SEL_TMO_LONG | OUR_ID_EN |
+        asc_dvc->chip_scsi_id);
+
+    /*
+     * Calculate SCSI_CFG1 Microcode Default Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     *
+     * Each ASC-38C1600 function has only two cable detect bits.
+     * The bus mode override bits are in IOPB_SOFT_OVER_WR.
+     */
+    scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+    /*
+     * If the cable is reversed all of the SCSI_CTRL register signals
+     * will be set. Check for and return an error if this condition is
+     * found.
+     */
+    if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+    {
+        asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Each ASC-38C1600 function has two connectors. Only an HVD device
+     * can not be connected to either connector. An LVD device or SE device
+     * may be connected to either connecor. If an SE device is connected,
+     * then at most Ultra speed (20 Mhz) can be used on both connectors.
+     *
+     * If an HVD device is attached, return an error.
+     */
+    if (scsi_cfg1 & HVD)
+    {
+        asc_dvc->err_code |= ASC_IERR_HVD_DEVICE;
+        return ADV_ERROR;
+    }
+
+    /*
+     * Each function in the ASC-38C1600 uses only the SE cable detect and
+     * termination because there are two connectors for each function. Each
+     * function may use either LVD or SE mode. Corresponding the SE automatic
+     * termination control EEPROM bits are used for each function. Each
+     * function has its own EEPROM. If SE automatic control is enabled for
+     * the function, then set the termination value based on a table listed
+     * in a_condor.h.
+     *
+     * If manual termination is specified in the EEPROM for the function,
+     * then 'termination' was set-up in AscInitFrom38C1600EEPROM() and is
+     * ready to be 'ored' into SCSI_CFG1.
+     */
+    if ((asc_dvc->cfg->termination & TERM_SE) == 0)
+    {
+        /* SE automatic termination control is enabled. */
+        switch(scsi_cfg1 & C_DET_SE)
+        {
+            /* TERM_SE_HI: on, TERM_SE_LO: on */
+            case 0x1: case 0x2: case 0x3:
+                asc_dvc->cfg->termination |= TERM_SE;
+                break;
+
+            case 0x0:
+                if (ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) == 0)
+                {
+                    /* Function 0 - TERM_SE_HI: off, TERM_SE_LO: off */
+                }
+                else
+                {
+                    /* Function 1 - TERM_SE_HI: on, TERM_SE_LO: off */
+                    asc_dvc->cfg->termination |= TERM_SE_HI;
+                }
+                break;
+        }
+    }
+
+    /*
+     * Clear any set TERM_SE bits.
+     */
+    scsi_cfg1 &= ~TERM_SE;
+
+    /*
+     * Invert the TERM_SE bits and then set 'scsi_cfg1'.
+     */
+    scsi_cfg1 |= (~asc_dvc->cfg->termination & TERM_SE);
+
+    /*
+     * Clear Big Endian and Terminator Polarity bits and set possibly
+     * modified termination control bits in the Microcode SCSI_CFG1
+     * Register Value.
+     *
+     * Big Endian bit is not used even on big endian machines.
+     */
+    scsi_cfg1 &= (~BIG_ENDIAN & ~DIS_TERM_DRV & ~TERM_POL);
+
+    /*
+     * Set SCSI_CFG1 Microcode Default Value
+     *
+     * Set possibly modified termination control bits in the Microcode
+     * SCSI_CFG1 Register Value.
+     *
+     * The microcode will set the SCSI_CFG1 register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1, scsi_cfg1);
+
+    /*
+     * Set MEM_CFG Microcode Default Value
+     *
+     * The microcode will set the MEM_CFG register using this value
+     * after it is started below.
+     *
+     * MEM_CFG may be accessed as a word or byte, but only bits 0-7
+     * are defined.
+     *
+     * ASC-38C1600 has 32KB internal memory.
+     *
+     * XXX - Since ASC38C1600 Rev.3 has a Local RAM failure issue, we come
+     * out a special 16K Adv Library and Microcode version. After the issue
+     * resolved, we should turn back to the 32K support. Both a_condor.h and
+     * mcode.sas files also need to be updated.
+     *
+     * AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG,
+     *  BIOS_EN | RAM_SZ_32KB);
+     */
+     AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_MEM_CFG, BIOS_EN | RAM_SZ_16KB);
+
+    /*
+     * Set SEL_MASK Microcode Default Value
+     *
+     * The microcode will set the SEL_MASK register using this value
+     * after it is started below.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+        ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+    /*
+     * Build the carrier freelist.
+     *
+     * Driver must have already allocated memory and set 'carrier_buf'.
+     */
+
+    ASC_ASSERT(asc_dvc->carrier_buf != NULL);
+
+    carrp = (ADV_CARR_T *) ADV_16BALIGN(asc_dvc->carrier_buf);
+    asc_dvc->carr_freelist = NULL;
+    if (carrp == (ADV_CARR_T *) asc_dvc->carrier_buf)
+    {
+        buf_size = ADV_CARRIER_BUFSIZE;
+    } else
+    {
+        buf_size = ADV_CARRIER_BUFSIZE - sizeof(ADV_CARR_T);
+    }
+
+    do {
+        /*
+         * Get physical address for the carrier 'carrp'.
+         */
+        contig_len = sizeof(ADV_CARR_T);
+        carr_paddr = cpu_to_le32(DvcGetPhyAddr(asc_dvc, NULL, (uchar *) carrp,
+            (ADV_SDCNT *) &contig_len, ADV_IS_CARRIER_FLAG));
+
+        buf_size -= sizeof(ADV_CARR_T);
+
+        /*
+         * If the current carrier is not physically contiguous, then
+         * maybe there was a page crossing. Try the next carrier aligned
+         * start address.
+         */
+        if (contig_len < sizeof(ADV_CARR_T))
+        {
+            carrp++;
+            continue;
+        }
+
+        carrp->carr_pa = carr_paddr;
+        carrp->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(carrp));
+
+        /*
+         * Insert the carrier at the beginning of the freelist.
+         */
+        carrp->next_vpa = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+        asc_dvc->carr_freelist = carrp;
+
+        carrp++;
+    }
+    while (buf_size > 0);
+
+    /*
+     * Set-up the Host->RISC Initiator Command Queue (ICQ).
+     */
+    if ((asc_dvc->icq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->icq_sp->next_vpa));
+
+    /*
+     * The first command issued will be placed in the stopper carrier.
+     */
+    asc_dvc->icq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC ICQ physical address start value. Initialize the
+     * COMMA register to the same value otherwise the RISC will
+     * prematurely detect a command is available.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_ICQ, asc_dvc->icq_sp->carr_pa);
+    AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+        le32_to_cpu(asc_dvc->icq_sp->carr_pa));
+
+    /*
+     * Set-up the RISC->Host Initiator Response Queue (IRQ).
+     */
+    if ((asc_dvc->irq_sp = asc_dvc->carr_freelist) == NULL)
+    {
+        asc_dvc->err_code |= ASC_IERR_NO_CARRIER;
+        return ADV_ERROR;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->next_vpa));
+
+    /*
+     * The first command completed by the RISC will be placed in
+     * the stopper.
+     *
+     * Note: Set 'next_vpa' to ASC_CQ_STOPPER. When the request is
+     * completed the RISC will set the ASC_RQ_STOPPER bit.
+     */
+    asc_dvc->irq_sp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Set RISC IRQ physical address start value.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IRQ, asc_dvc->irq_sp->carr_pa);
+    asc_dvc->carr_pending_cnt = 0;
+
+    AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+        (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+    AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+    AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+    /* finally, finally, gentlemen, start your engine */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+    /*
+     * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+     * Resets should be performed. The RISC has to be running
+     * to issue a SCSI Bus Reset.
+     */
+    if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+    {
+        /*
+         * If the BIOS Signature is present in memory, restore the
+         * per TID microcode operating variables.
+         */
+        if (bios_mem[(ASC_MC_BIOS_SIGNATURE - ASC_MC_BIOSMEM)/2] == 0x55AA)
+        {
+            /*
+             * Restore per TID negotiated values.
+             */
+            AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+            for (tid = 0; tid <= ASC_MAX_TID; tid++)
+            {
+                AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                    max_cmd[tid]);
+            }
+        } else
+        {
+            if (AdvResetSB(asc_dvc) != ADV_TRUE)
+            {
+                warn_code = ASC_WARN_BUSRESET_ERROR;
+            }
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+STATIC int __init
+AdvInitFrom3550EEP(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr         iop_base;
+    ushort              warn_code;
+    ADVEEP_3550_CONFIG  eep_config;
+    int                 i;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet3550EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_3550_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_3550_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+        AdvSet3550EEPConfig(iop_base, &eep_config);
+    }
+    /*
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_able = eep_config.sdtr_able;
+    asc_dvc->ultra_able = eep_config.ultra_able;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination == 0)
+    {
+        asc_dvc->cfg->termination = 0;    /* auto termination */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination == 1)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination == 2)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination == 3)
+        {
+            asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+        } else
+        {
+            /*
+             * The EEPROM 'termination' field contains a bad value. Use
+             * automatic termination instead.
+             */
+            asc_dvc->cfg->termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+STATIC int __init
+AdvInitFrom38C0800EEP(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C0800_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet38C0800EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_38C0800_CONFIG); i++)
+        {
+            *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C0800_EEPROM_Config + i);
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+        AdvSet38C0800EEPConfig(iop_base, &eep_config);
+    }
+    /*
+     * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+    asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+    asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+    asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+    /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ADV_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ADV_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ADV_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination_se == 0)
+    {
+        termination = 0;                         /* auto termination for SE */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_se == 1)
+        {
+            termination = 0;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_se == 2)
+        {
+            termination = TERM_SE_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_se == 3)
+        {
+            termination = TERM_SE;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ASC_DVC_VAR and
+ * ASC_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ASC_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+STATIC int __init
+AdvInitFrom38C1600EEP(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr              iop_base;
+    ushort                   warn_code;
+    ADVEEP_38C1600_CONFIG    eep_config;
+    int                      i;
+    uchar                    tid, termination;
+    ushort                   sdtr_speed = 0;
+
+    iop_base = asc_dvc->iop_base;
+
+    warn_code = 0;
+
+    /*
+     * Read the board's EEPROM configuration.
+     *
+     * Set default values if a bad checksum is found.
+     */
+    if (AdvGet38C1600EEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+    {
+        warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+        /*
+         * Set EEPROM default values.
+         */
+        for (i = 0; i < sizeof(ADVEEP_38C1600_CONFIG); i++)
+        {
+            if (i == 1 && ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info) != 0)
+            {
+                /*
+                 * Set Function 1 EEPROM Word 0 MSB
+                 *
+                 * Clear the BIOS_ENABLE (bit 14) and INTAB (bit 11)
+                 * EEPROM bits.
+                 *
+                 * Disable Bit 14 (BIOS_ENABLE) to fix SPARC Ultra 60 and
+                 * old Mac system booting problem. The Expansion ROM must
+                 * be disabled in Function 1 for these systems.
+                 *
+                 */
+                *((uchar *) &eep_config + i) =
+                ((*((uchar *) &Default_38C1600_EEPROM_Config + i)) &
+                    (~(((ADV_EEPROM_BIOS_ENABLE | ADV_EEPROM_INTAB) >> 8) &
+                     0xFF)));
+
+                /*
+                 * Set the INTAB (bit 11) if the GPIO 0 input indicates
+                 * the Function 1 interrupt line is wired to INTA.
+                 *
+                 * Set/Clear Bit 11 (INTAB) from the GPIO bit 0 input:
+                 *   1 - Function 1 interrupt line wired to INT A.
+                 *   0 - Function 1 interrupt line wired to INT B.
+                 *
+                 * Note: Adapter boards always have Function 0 wired to INTA.
+                 * Put all 5 GPIO bits in input mode and then read
+                 * their input values.
+                 */
+                AdvWriteByteRegister(iop_base, IOPB_GPIO_CNTL, 0);
+                if (AdvReadByteRegister(iop_base, IOPB_GPIO_DATA) & 0x01)
+                {
+                    /* Function 1 interrupt wired to INTA; Set EEPROM bit. */
+                *((uchar *) &eep_config + i) |=
+                    ((ADV_EEPROM_INTAB >> 8) & 0xFF);
+                }
+            }
+            else
+            {
+                *((uchar *) &eep_config + i) =
+                *((uchar *) &Default_38C1600_EEPROM_Config + i);
+            }
+        }
+
+        /*
+         * Assume the 6 byte board serial number that was read
+         * from EEPROM is correct even if the EEPROM checksum
+         * failed.
+         */
+        eep_config.serial_number_word3 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 1);
+
+        eep_config.serial_number_word2 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 2);
+
+        eep_config.serial_number_word1 =
+            AdvReadEEPWord(iop_base, ADV_EEP_DVC_CFG_END - 3);
+
+        AdvSet38C1600EEPConfig(iop_base, &eep_config);
+    }
+
+    /*
+     * Set ASC_DVC_VAR and ASC_DVC_CFG variables from the
+     * EEPROM configuration that was read.
+     *
+     * This is the mapping of EEPROM fields to Adv Library fields.
+     */
+    asc_dvc->wdtr_able = eep_config.wdtr_able;
+    asc_dvc->sdtr_speed1 = eep_config.sdtr_speed1;
+    asc_dvc->sdtr_speed2 = eep_config.sdtr_speed2;
+    asc_dvc->sdtr_speed3 = eep_config.sdtr_speed3;
+    asc_dvc->sdtr_speed4 = eep_config.sdtr_speed4;
+    asc_dvc->ppr_able = 0;
+    asc_dvc->tagqng_able = eep_config.tagqng_able;
+    asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+    asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ASC_MAX_TID);
+    asc_dvc->start_motor = eep_config.start_motor;
+    asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+    asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+    asc_dvc->no_scam = eep_config.scam_tolerant;
+
+    /*
+     * For every Target ID if any of its 'sdtr_speed[1234]' bits
+     * are set, then set an 'sdtr_able' bit for it.
+     */
+    asc_dvc->sdtr_able = 0;
+    for (tid = 0; tid <= ASC_MAX_TID; tid++)
+    {
+        if (tid == 0)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed1;
+        } else if (tid == 4)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed2;
+        } else if (tid == 8)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed3;
+        } else if (tid == 12)
+        {
+            sdtr_speed = asc_dvc->sdtr_speed4;
+        }
+        if (sdtr_speed & ASC_MAX_TID)
+        {
+            asc_dvc->sdtr_able |= (1 << tid);
+        }
+        sdtr_speed >>= 4;
+    }
+
+    /*
+     * Set the host maximum queuing (max. 253, min. 16) and the per device
+     * maximum queuing (max. 63, min. 4).
+     */
+    if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+    {
+        eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+    } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_host_qng == 0)
+        {
+            eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+        } else
+        {
+            eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+        }
+    }
+
+    if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+    {
+        eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+    } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+    {
+        /* If the value is zero, assume it is uninitialized. */
+        if (eep_config.max_dvc_qng == 0)
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+        } else
+        {
+            eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+        }
+    }
+
+    /*
+     * If 'max_dvc_qng' is greater than 'max_host_qng', then
+     * set 'max_dvc_qng' to 'max_host_qng'.
+     */
+    if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+    {
+        eep_config.max_dvc_qng = eep_config.max_host_qng;
+    }
+
+    /*
+     * Set ASC_DVC_VAR 'max_host_qng' and ASC_DVC_VAR 'max_dvc_qng'
+     * values based on possibly adjusted EEPROM values.
+     */
+    asc_dvc->max_host_qng = eep_config.max_host_qng;
+    asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+    /*
+     * If the EEPROM 'termination' field is set to automatic (0), then set
+     * the ASC_DVC_CFG 'termination' field to automatic also.
+     *
+     * If the termination is specified with a non-zero 'termination'
+     * value check that a legal value is set and set the ASC_DVC_CFG
+     * 'termination' field appropriately.
+     */
+    if (eep_config.termination_se == 0)
+    {
+        termination = 0;                         /* auto termination for SE */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_se == 1)
+        {
+            termination = 0;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_se == 2)
+        {
+            termination = TERM_SE_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_se == 3)
+        {
+            termination = TERM_SE;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_se' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            termination = 0;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    if (eep_config.termination_lvd == 0)
+    {
+        asc_dvc->cfg->termination = termination; /* auto termination for LVD */
+    } else
+    {
+        /* Enable manual control with low off / high off. */
+        if (eep_config.termination_lvd == 1)
+        {
+            asc_dvc->cfg->termination = termination;
+
+        /* Enable manual control with low off / high on. */
+        } else if (eep_config.termination_lvd == 2)
+        {
+            asc_dvc->cfg->termination = termination | TERM_LVD_HI;
+
+        /* Enable manual control with low on / high on. */
+        } else if (eep_config.termination_lvd == 3)
+        {
+            asc_dvc->cfg->termination =
+                termination | TERM_LVD;
+        } else
+        {
+            /*
+             * The EEPROM 'termination_lvd' field contains a bad value.
+             * Use automatic termination instead.
+             */
+            asc_dvc->cfg->termination = termination;
+            warn_code |= ASC_WARN_EEPROM_TERMINATION;
+        }
+    }
+
+    return warn_code;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+STATIC ushort __init
+AdvGet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+    ushort              *charfields;
+
+    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
+    }
+    /* Read checksum word. */
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
+    }
+    return chksum;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+STATIC ushort __init
+AdvGet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+    ushort              *charfields;
+
+    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
+    }
+    /* Read checksum word. */
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
+    }
+    return chksum;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+STATIC ushort __init
+AdvGet38C1600EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+    ushort              wval, chksum;
+    ushort              *wbuf;
+    int                 eep_addr;
+    ushort              *charfields;
+
+    charfields = (ushort*) &ADVEEP_38C1600_Config_Field_IsChar;
+    wbuf = (ushort *) cfg_buf;
+    chksum = 0;
+
+    for (eep_addr = ADV_EEP_DVC_CFG_BEGIN;
+         eep_addr < ADV_EEP_DVC_CFG_END;
+         eep_addr++, wbuf++)
+    {
+        wval = AdvReadEEPWord(iop_base, eep_addr);
+        chksum += wval; /* Checksum is calculated from word values. */
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(wval);
+        } else {
+            *wbuf = wval;
+        }
+    }
+    /* Read checksum word. */
+    *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+    wbuf++; charfields++;
+
+    /* Read rest of EEPROM not covered by the checksum. */
+    for (eep_addr = ADV_EEP_DVC_CTL_BEGIN;
+         eep_addr < ADV_EEP_MAX_WORD_ADDR;
+         eep_addr++, wbuf++)
+    {
+        *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+        if (*charfields++) {
+            *wbuf = le16_to_cpu(*wbuf);
+        }
+    }
+    return chksum;
+}
+
+/*
+ * Read the EEPROM from specified location
+ */
+STATIC ushort __init
+AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+{
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+        ASC_EEP_CMD_READ | eep_word_addr);
+    AdvWaitEEPCmd(iop_base);
+    return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+}
+
+/*
+ * Wait for EEPROM command to complete
+ */
+STATIC void __init
+AdvWaitEEPCmd(AdvPortAddr iop_base)
+{
+    int eep_delay_ms;
+
+    for (eep_delay_ms = 0; eep_delay_ms < ADV_EEP_DELAY_MS; eep_delay_ms++)
+    {
+        if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
+        {
+            break;
+        }
+        DvcSleepMilliSecond(1);
+    }
+    if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
+    {
+        ASC_ASSERT(0);
+    }
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet3550EEPConfig(AdvPortAddr iop_base, ADVEEP_3550_CONFIG *cfg_buf)
+{
+    ushort *wbuf;
+    ushort addr, chksum;
+    ushort *charfields;
+
+    wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_3550_Config_Field_IsChar;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20.
+     */
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++; charfields++;
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29.
+     */
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C0800EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C0800_CONFIG *cfg_buf)
+{
+    ushort *wbuf;
+    ushort *charfields;
+    ushort addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_38C0800_Config_Field_IsChar;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20.
+     */
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++; charfields++;
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29.
+     */
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+void
+AdvSet38C1600EEPConfig(AdvPortAddr iop_base,
+                       ADVEEP_38C1600_CONFIG *cfg_buf)
+{
+    ushort              *wbuf;
+    ushort              *charfields;
+    ushort              addr, chksum;
+
+    wbuf = (ushort *) cfg_buf;
+    charfields = (ushort *) &ADVEEP_38C1600_Config_Field_IsChar;
+    chksum = 0;
+
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+    AdvWaitEEPCmd(iop_base);
+
+    /*
+     * Write EEPROM from word 0 to word 20.
+     */
+    for (addr = ADV_EEP_DVC_CFG_BEGIN;
+         addr < ADV_EEP_DVC_CFG_END; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        chksum += *wbuf; /* Checksum is calculated from word values. */
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+        DvcSleepMilliSecond(ADV_EEP_DELAY_MS);
+    }
+
+    /*
+     * Write EEPROM checksum at word 21.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+    AdvWaitEEPCmd(iop_base);
+    wbuf++; charfields++;
+
+    /*
+     * Write EEPROM OEM name at words 22 to 29.
+     */
+    for (addr = ADV_EEP_DVC_CTL_BEGIN;
+         addr < ADV_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+    {
+        ushort word;
+
+        if (*charfields++) {
+            word = cpu_to_le16(*wbuf);
+        } else {
+            word = *wbuf;
+        }
+        AdvWriteWordRegister(iop_base, IOPW_EE_DATA, word);
+        AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+        AdvWaitEEPCmd(iop_base);
+    }
+    AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+    AdvWaitEEPCmd(iop_base);
+    return;
+}
+
+/* a_advlib.c */
+/*
+ * AdvExeScsiQueue() - Send a request to the RISC microcode program.
+ *
+ *   Allocate a carrier structure, point the carrier to the ADV_SCSI_REQ_Q,
+ *   add the carrier to the ICQ (Initiator Command Queue), and tickle the
+ *   RISC to notify it a new command is ready to be executed.
+ *
+ * If 'done_status' is not set to QD_DO_RETRY, then 'error_retry' will be
+ * set to SCSI_MAX_RETRY.
+ *
+ * Multi-byte fields in the ASC_SCSI_REQ_Q that are used by the microcode
+ * for DMA addresses or math operations are byte swapped to little-endian
+ * order.
+ *
+ * Return:
+ *      ADV_SUCCESS(1) - The request was successfully queued.
+ *      ADV_BUSY(0) -    Resource unavailable; Retry again after pending
+ *                       request completes.
+ *      ADV_ERROR(-1) -  Invalid ADV_SCSI_REQ_Q request structure
+ *                       host IC error.
+ */
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+                ADV_SCSI_REQ_Q *scsiq)
+{
+    ulong                  last_int_level;
+    AdvPortAddr            iop_base;
+    ADV_DCNT               req_size;
+    ADV_PADDR              req_paddr;
+    ADV_CARR_T             *new_carrp;
+
+    ASC_ASSERT(scsiq != NULL); /* 'scsiq' should never be NULL. */
+
+    /*
+     * The ADV_SCSI_REQ_Q 'target_id' field should never exceed ADV_MAX_TID.
+     */
+    if (scsiq->target_id > ADV_MAX_TID)
+    {
+        scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+        scsiq->done_status = QD_WITH_ERROR;
+        return ADV_ERROR;
+    }
+
+    iop_base = asc_dvc->iop_base;
+
+    last_int_level = DvcEnterCritical();
+
+    /*
+     * Allocate a carrier ensuring at least one carrier always
+     * remains on the freelist and initialize fields.
+     */
+    if ((new_carrp = asc_dvc->carr_freelist) == NULL)
+    {
+       DvcLeaveCritical(last_int_level);
+       return ADV_BUSY;
+    }
+    asc_dvc->carr_freelist = (ADV_CARR_T *)
+        ADV_U32_TO_VADDR(le32_to_cpu(new_carrp->next_vpa));
+    asc_dvc->carr_pending_cnt++;
+
+    /*
+     * Set the carrier to be a stopper by setting 'next_vpa'
+     * to the stopper value. The current stopper will be changed
+     * below to point to the new stopper.
+     */
+    new_carrp->next_vpa = cpu_to_le32(ASC_CQ_STOPPER);
+
+    /*
+     * Clear the ADV_SCSI_REQ_Q done flag.
+     */
+    scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+    req_size = sizeof(ADV_SCSI_REQ_Q);
+    req_paddr = DvcGetPhyAddr(asc_dvc, scsiq, (uchar *) scsiq,
+        (ADV_SDCNT *) &req_size, ADV_IS_SCSIQ_FLAG);
+
+    ASC_ASSERT(ADV_32BALIGN(req_paddr) == req_paddr);
+    ASC_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+    /* Wait for assertion before making little-endian */
+    req_paddr = cpu_to_le32(req_paddr);
+
+    /* Save virtual and physical address of ADV_SCSI_REQ_Q and carrier. */
+    scsiq->scsiq_ptr = cpu_to_le32(ADV_VADDR_TO_U32(scsiq));
+    scsiq->scsiq_rptr = req_paddr;
+
+    scsiq->carr_va = cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->icq_sp));
+    /*
+     * Every ADV_CARR_T.carr_pa is byte swapped to little-endian
+     * order during initialization.
+     */
+    scsiq->carr_pa = asc_dvc->icq_sp->carr_pa;
+
+   /*
+    * Use the current stopper to send the ADV_SCSI_REQ_Q command to
+    * the microcode. The newly allocated stopper will become the new
+    * stopper.
+    */
+    asc_dvc->icq_sp->areq_vpa = req_paddr;
+
+    /*
+     * Set the 'next_vpa' pointer for the old stopper to be the
+     * physical address of the new stopper. The RISC can only
+     * follow physical addresses.
+     */
+    asc_dvc->icq_sp->next_vpa = new_carrp->carr_pa;
+
+    /*
+     * Set the host adapter stopper pointer to point to the new carrier.
+     */
+    asc_dvc->icq_sp = new_carrp;
+
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+        asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        /*
+         * Tickle the RISC to tell it to read its Command Queue Head pointer.
+         */
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+        if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+        {
+            /*
+             * Clear the tickle value. In the ASC-3550 the RISC flag
+             * command 'clr_tickle_a' does not work unless the host
+             * value is cleared.
+             */
+            AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+        }
+    } else if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        /*
+         * Notify the RISC a carrier is ready by writing the physical
+         * address of the new carrier stopper to the COMMA register.
+         */
+        AdvWriteDWordRegister(iop_base, IOPDW_COMMA,
+                le32_to_cpu(new_carrp->carr_pa));
+    }
+
+    DvcLeaveCritical(last_int_level);
+
+    return ADV_SUCCESS;
+}
+
+/*
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   All requests are purged and SCSI Bus is reset.
+ *      ADV_FALSE(0) -  Microcode command failed.
+ *      ADV_ERROR(-1) - Microcode command timed-out. Microcode or IC
+ *                      may be hung which requires driver recovery.
+ */
+STATIC int
+AdvResetSB(ADV_DVC_VAR *asc_dvc)
+{
+    int         status;
+
+    /*
+     * Send the SCSI Bus Reset idle start idle command which asserts
+     * the SCSI Bus Reset signal.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_START, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
+
+    /*
+     * Delay for the specified SCSI Bus Reset hold time.
+     *
+     * The hold time delay is done on the host because the RISC has no
+     * microsecond accurate timer.
+     */
+    DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+
+    /*
+     * Send the SCSI Bus Reset end idle command which de-asserts
+     * the SCSI Bus Reset signal and purges any pending requests.
+     */
+    status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET_END, 0L);
+    if (status != ADV_TRUE)
+    {
+        return status;
+    }
+
+    DvcSleepMilliSecond((ADV_DCNT) asc_dvc->scsi_reset_wait * 1000);
+
+    return status;
+}
+
+/*
+ * Reset chip and SCSI Bus.
+ *
+ * Return Value:
+ *      ADV_TRUE(1) -   Chip re-initialization and SCSI Bus Reset successful.
+ *      ADV_FALSE(0) -  Chip re-initialization and SCSI Bus Reset failure.
+ */
+STATIC int
+AdvResetChipAndSB(ADV_DVC_VAR *asc_dvc)
+{
+    int         status;
+    ushort      wdtr_able, sdtr_able, tagqng_able;
+    ushort      ppr_able = 0;
+    uchar       tid, max_cmd[ADV_MAX_TID + 1];
+    AdvPortAddr iop_base;
+    ushort      bios_sig;
+
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Save current per TID negotiated values.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+    }
+    AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    /*
+     * Force the AdvInitAsc3550/38C0800Driver() function to
+     * perform a SCSI Bus Reset by clearing the BIOS signature word.
+     * The initialization functions assumes a SCSI Bus Reset is not
+     * needed if the BIOS signature word is present.
+     */
+    AdvReadWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, 0);
+
+    /*
+     * Stop chip and reset it.
+     */
+    AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_STOP);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+    DvcSleepMilliSecond(100);
+    AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+    /*
+     * Reset Adv Library error code, if any, and try
+     * re-initializing the chip.
+     */
+    asc_dvc->err_code = 0;
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        status = AdvInitAsc38C1600Driver(asc_dvc);
+    }
+    else if (asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+    {
+        status = AdvInitAsc38C0800Driver(asc_dvc);
+    } else
+    {
+        status = AdvInitAsc3550Driver(asc_dvc);
+    }
+
+    /* Translate initialization return value to status value. */
+    if (status == 0)
+    {
+        status = ADV_TRUE;
+    } else
+    {
+        status = ADV_FALSE;
+    }
+
+    /*
+     * Restore the BIOS signature word.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_BIOS_SIGNATURE, bios_sig);
+
+    /*
+     * Restore per TID negotiated values.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
+    AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600)
+    {
+        AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, ppr_able);
+    }
+    AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
+    for (tid = 0; tid <= ADV_MAX_TID; tid++)
+    {
+        AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+            max_cmd[tid]);
+    }
+
+    return status;
+}
+
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ *  This function is called by a driver's interrupt service routine.
+ *  The function disables and re-enables interrupts.
+ *
+ *  When a microcode idle command is completed, the ADV_DVC_VAR
+ *  'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ *  Note: AdvISR() can be called when interrupts are disabled or even
+ *  when there is no hardware interrupt condition present. It will
+ *  always check for completed idle commands and microcode requests.
+ *  This is an important feature that shouldn't be changed because it
+ *  allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ *   ADV_TRUE(1) - interrupt was pending
+ *   ADV_FALSE(0) - no interrupt was pending
+ */
+STATIC int
+AdvISR(ADV_DVC_VAR *asc_dvc)
+{
+    AdvPortAddr                 iop_base;
+    uchar                       int_stat;
+    ushort                      target_bit;
+    ADV_CARR_T                  *free_carrp;
+    ADV_VADDR                   irq_next_vpa;
+    int                         flags;
+    ADV_SCSI_REQ_Q              *scsiq;
+
+    flags = DvcEnterCritical();
+
+    iop_base = asc_dvc->iop_base;
+
+    /* Reading the register clears the interrupt. */
+    int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+    if ((int_stat & (ADV_INTR_STATUS_INTRA | ADV_INTR_STATUS_INTRB |
+         ADV_INTR_STATUS_INTRC)) == 0)
+    {
+        DvcLeaveCritical(flags);
+        return ADV_FALSE;
+    }
+
+    /*
+     * Notify the driver of an asynchronous microcode condition by
+     * calling the ADV_DVC_VAR.async_callback function. The function
+     * is passed the microcode ASC_MC_INTRB_CODE byte value.
+     */
+    if (int_stat & ADV_INTR_STATUS_INTRB)
+    {
+        uchar intrb_code;
+
+        AdvReadByteLram(iop_base, ASC_MC_INTRB_CODE, intrb_code);
+
+        if (asc_dvc->chip_type == ADV_CHIP_ASC3550 ||
+            asc_dvc->chip_type == ADV_CHIP_ASC38C0800)
+        {
+            if (intrb_code == ADV_ASYNC_CARRIER_READY_FAILURE &&
+                asc_dvc->carr_pending_cnt != 0)
+            {
+                AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_A);
+                if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+                {
+                    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+                }
+            }
+        }
+
+        if (asc_dvc->async_callback != 0)
+        {
+            (*asc_dvc->async_callback)(asc_dvc, intrb_code);
+        }
+    }
+
+    /*
+     * Check if the IRQ stopper carrier contains a completed request.
+     */
+    while (((irq_next_vpa =
+             le32_to_cpu(asc_dvc->irq_sp->next_vpa)) & ASC_RQ_DONE) != 0)
+    {
+        /*
+         * Get a pointer to the newly completed ADV_SCSI_REQ_Q structure.
+         * The RISC will have set 'areq_vpa' to a virtual address.
+         *
+         * The firmware will have copied the ASC_SCSI_REQ_Q.scsiq_ptr
+         * field to the carrier ADV_CARR_T.areq_vpa field. The conversion
+         * below complements the conversion of ASC_SCSI_REQ_Q.scsiq_ptr'
+         * in AdvExeScsiQueue().
+         */
+        scsiq = (ADV_SCSI_REQ_Q *)
+            ADV_U32_TO_VADDR(le32_to_cpu(asc_dvc->irq_sp->areq_vpa));
+
+        /*
+         * Request finished with good status and the queue was not
+         * DMAed to host memory by the firmware. Set all status fields
+         * to indicate good status.
+         */
+        if ((irq_next_vpa & ASC_RQ_GOOD) != 0)
+        {
+            scsiq->done_status = QD_NO_ERROR;
+            scsiq->host_status = scsiq->scsi_status = 0;
+            scsiq->data_cnt = 0L;
+        }
+
+        /*
+         * Advance the stopper pointer to the next carrier
+         * ignoring the lower four bits. Free the previous
+         * stopper carrier.
+         */
+        free_carrp = asc_dvc->irq_sp;
+        asc_dvc->irq_sp = (ADV_CARR_T *)
+            ADV_U32_TO_VADDR(ASC_GET_CARRP(irq_next_vpa));
+
+        free_carrp->next_vpa =
+                cpu_to_le32(ADV_VADDR_TO_U32(asc_dvc->carr_freelist));
+        asc_dvc->carr_freelist = free_carrp;
+        asc_dvc->carr_pending_cnt--;
+
+        ASC_ASSERT(scsiq != NULL);
+        target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+        /*
+         * Clear request microcode control flag.
+         */
+        scsiq->cntl = 0;
+
+        /*
+         * If the command that completed was a SCSI INQUIRY and
+         * LUN 0 was sent the command, then process the INQUIRY
+         * command information for the device.
+         *
+         * Note: If data returned were either VPD or CmdDt data,
+         * don't process the INQUIRY command information for
+         * the device, otherwise may erroneously set *_able bits.
+         */
+        if (scsiq->done_status == QD_NO_ERROR &&
+            scsiq->cdb[0] == INQUIRY &&
+            scsiq->target_lun == 0 &&
+            (scsiq->cdb[1] & ADV_INQ_RTN_VPD_AND_CMDDT)
+                == ADV_INQ_RTN_STD_INQUIRY_DATA)
+        {
+            AdvInquiryHandling(asc_dvc, scsiq);
+        }
+
+        /*
+         * Notify the driver of the completed request by passing
+         * the ADV_SCSI_REQ_Q pointer to its callback function.
+         */
+        scsiq->a_flag |= ADV_SCSIQ_DONE;
+        (*asc_dvc->isr_callback)(asc_dvc, scsiq);
+        /*
+         * Note: After the driver callback function is called, 'scsiq'
+         * can no longer be referenced.
+         *
+         * Fall through and continue processing other completed
+         * requests...
+         */
+
+        /*
+         * Disable interrupts again in case the driver inadvertently
+         * enabled interrupts in its callback function.
+         *
+         * The DvcEnterCritical() return value is ignored, because
+         * the 'flags' saved when AdvISR() was first entered will be
+         * used to restore the interrupt flag on exit.
+         */
+        (void) DvcEnterCritical();
+    }
+    DvcLeaveCritical(flags);
+    return ADV_TRUE;
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Command completion is polled for once per microsecond.
+ *
+ * The function can be called from anywhere including an interrupt handler.
+ * But the function is not re-entrant, so it uses the DvcEnter/LeaveCritical()
+ * functions to prevent reentrancy.
+ *
+ * Return Values:
+ *   ADV_TRUE - command completed successfully
+ *   ADV_FALSE - command failed
+ *   ADV_ERROR - command timed out
+ */
+STATIC int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+               ushort idle_cmd,
+               ADV_DCNT idle_cmd_parameter)
+{
+    ulong       last_int_level;
+    int         result;
+    ADV_DCNT    i, j;
+    AdvPortAddr iop_base;
+
+    last_int_level = DvcEnterCritical();
+
+    iop_base = asc_dvc->iop_base;
+
+    /*
+     * Clear the idle command status which is set by the microcode
+     * to a non-zero value to indicate when the command is completed.
+     * The non-zero result is one of the IDLE_CMD_STATUS_* values
+     * defined in a_advlib.h.
+     */
+    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, (ushort) 0);
+
+    /*
+     * Write the idle command value after the idle command parameter
+     * has been written to avoid a race condition. If the order is not
+     * followed, the microcode may process the idle command before the
+     * parameters have been written to LRAM.
+     */
+    AdvWriteDWordLramNoSwap(iop_base, ASC_MC_IDLE_CMD_PARAMETER,
+        cpu_to_le32(idle_cmd_parameter));
+    AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+
+    /*
+     * Tickle the RISC to tell it to process the idle command.
+     */
+    AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_B);
+    if (asc_dvc->chip_type == ADV_CHIP_ASC3550)
+    {
+        /*
+         * Clear the tickle value. In the ASC-3550 the RISC flag
+         * command 'clr_tickle_b' does not work unless the host
+         * value is cleared.
+         */
+        AdvWriteByteRegister(iop_base, IOPB_TICKLE, ADV_TICKLE_NOP);
+    }
+
+    /* Wait for up to 100 millisecond for the idle command to timeout. */
+    for (i = 0; i < SCSI_WAIT_100_MSEC; i++)
+    {
+        /* Poll once each microsecond for command completion. */
+        for (j = 0; j < SCSI_US_PER_MSEC; j++)
+        {
+            AdvReadWordLram(iop_base, ASC_MC_IDLE_CMD_STATUS, result);
+            if (result != 0)
+            {
+                DvcLeaveCritical(last_int_level);
+                return result;
+            }
+            DvcDelayMicroSecond(asc_dvc, (ushort) 1);
+        }
+    }
+
+    ASC_ASSERT(0); /* The idle command should never timeout. */
+    DvcLeaveCritical(last_int_level);
+    return ADV_ERROR;
+}
+
+/*
+ * Inquiry Information Byte 7 Handling
+ *
+ * Handle SCSI Inquiry Command information for a device by setting
+ * microcode operating variables that affect WDTR, SDTR, and Tag
+ * Queuing.
+ */
+STATIC void
+AdvInquiryHandling(
+    ADV_DVC_VAR                 *asc_dvc,
+    ADV_SCSI_REQ_Q              *scsiq)
+{
+    AdvPortAddr                 iop_base;
+    uchar                       tid;
+    ADV_SCSI_INQUIRY            *inq;
+    ushort                      tidmask;
+    ushort                      cfg_word;
+
+    /*
+     * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+     * to be available.
+     *
+     * If less than 8 bytes of INQUIRY information were requested or less
+     * than 8 bytes were transferred, then return. cdb[4] is the request
+     * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
+     * microcode to the transfer residual count.
+     */
+
+    if (scsiq->cdb[4] < 8 ||
+        (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) < 8)
+    {
+        return;
+    }
+
+    iop_base = asc_dvc->iop_base;
+    tid = scsiq->target_id;
+
+    inq = (ADV_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+    /*
+     * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+     */
+    if (ADV_INQ_RESPONSE_FMT(inq) < 2 && ADV_INQ_ANSI_VER(inq) < 2)
+    {
+        return;
+    } else
+    {
+        /*
+         * INQUIRY Byte 7 Handling
+         *
+         * Use a device's INQUIRY byte 7 to determine whether it
+         * supports WDTR, SDTR, and Tag Queuing. If the feature
+         * is enabled in the EEPROM and the device supports the
+         * feature, then enable it in the microcode.
+         */
+
+        tidmask = ADV_TID_TO_TIDMASK(tid);
+
+        /*
+         * Wide Transfers
+         *
+         * If the EEPROM enabled WDTR for the device and the device
+         * supports wide bus (16 bit) transfers, then turn on the
+         * device's 'wdtr_able' bit and write the new value to the
+         * microcode.
+         */
+        if ((asc_dvc->wdtr_able & tidmask) && ADV_INQ_WIDE16(inq))
+        {
+            AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+            if ((cfg_word & tidmask) == 0)
+            {
+                cfg_word |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+
+                /*
+                 * Clear the microcode "SDTR negotiation" and "WDTR
+                 * negotiation" done indicators for the target to cause
+                 * it to negotiate with the new setting set above.
+                 * WDTR when accepted causes the target to enter
+                 * asynchronous mode, so SDTR must be negotiated.
+                 */
+                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+            }
+        }
+
+        /*
+         * Synchronous Transfers
+         *
+         * If the EEPROM enabled SDTR for the device and the device
+         * supports synchronous transfers, then turn on the device's
+         * 'sdtr_able' bit. Write the new value to the microcode.
+         */
+        if ((asc_dvc->sdtr_able & tidmask) && ADV_INQ_SYNC(inq))
+        {
+            AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+            if ((cfg_word & tidmask) == 0)
+            {
+                cfg_word |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+
+                /*
+                 * Clear the microcode "SDTR negotiation" done indicator
+                 * for the target to cause it to negotiate with the new
+                 * setting set above.
+                 */
+                AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+                cfg_word &= ~tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+            }
+        }
+        /*
+         * If the Inquiry data included enough space for the SPI-3
+         * Clocking field, then check if DT mode is supported.
+         */
+        if (asc_dvc->chip_type == ADV_CHIP_ASC38C1600 &&
+            (scsiq->cdb[4] >= 57 ||
+            (scsiq->cdb[4] - le32_to_cpu(scsiq->data_cnt)) >= 57))
+        {
+            /*
+             * PPR (Parallel Protocol Request) Capable
+             *
+             * If the device supports DT mode, then it must be PPR capable.
+             * The PPR message will be used in place of the SDTR and WDTR
+             * messages to negotiate synchronous speed and offset, transfer
+             * width, and protocol options.
+             */
+            if (ADV_INQ_CLOCKING(inq) & ADV_INQ_CLOCKING_DT_ONLY)
+            {
+                AdvReadWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
+                asc_dvc->ppr_able |= tidmask;
+                AdvWriteWordLram(iop_base, ASC_MC_PPR_ABLE, asc_dvc->ppr_able);
+            }
+        }
+
+        /*
+         * If the EEPROM enabled Tag Queuing for the device and the
+         * device supports Tag Queueing, then turn on the device's
+         * 'tagqng_enable' bit in the microcode and set the microcode
+         * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
+         * value.
+         *
+         * Tag Queuing is disabled for the BIOS which runs in polled
+         * mode and would see no benefit from Tag Queuing. Also by
+         * disabling Tag Queuing in the BIOS devices with Tag Queuing
+         * bugs will at least work with the BIOS.
+         */
+        if ((asc_dvc->tagqng_able & tidmask) && ADV_INQ_CMD_QUEUE(inq))
+        {
+            AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+            cfg_word |= tidmask;
+            AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+
+            AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+                asc_dvc->max_dvc_qng);
+        }
+    }
+}
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
new file mode 100644
index 0000000..3f4bde0
--- /dev/null
+++ b/drivers/scsi/advansys.h
@@ -0,0 +1,36 @@
+/*
+ * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
+ * 
+ * Copyright (c) 1995-2000 Advanced System Products, Inc.
+ * Copyright (c) 2000-2001 ConnectCom Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * As of March 8, 2000 Advanced System Products, Inc. (AdvanSys)
+ * changed its name to ConnectCom Solutions, Inc.
+ *
+ */
+
+#ifndef _ADVANSYS_H
+#define _ADVANSYS_H
+
+/*
+ * Scsi_Host_Template function prototypes.
+ */
+int advansys_detect(struct scsi_host_template *);
+int advansys_release(struct Scsi_Host *);
+const char *advansys_info(struct Scsi_Host *);
+int advansys_queuecommand(struct scsi_cmnd *, void (* done)(struct scsi_cmnd *));
+int advansys_reset(struct scsi_cmnd *);
+int advansys_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int[]);
+static int advansys_slave_configure(struct scsi_device *);
+
+/* init/main.c setup function */
+void advansys_setup(char *, int *);
+
+#endif /* _ADVANSYS_H */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
new file mode 100644
index 0000000..d7b8efe
--- /dev/null
+++ b/drivers/scsi/aha152x.c
@@ -0,0 +1,3982 @@
+/* aha152x.c -- Adaptec AHA-152x driver
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-2004 Jürgen E. Fischer
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *
+ * $Id: aha152x.c,v 2.7 2004/01/24 11:42:59 fischer Exp $
+ *
+ * $Log: aha152x.c,v $
+ * Revision 2.7  2004/01/24 11:42:59  fischer
+ * - gather code that is not used by PCMCIA at the end
+ * - move request_region for !PCMCIA case to detection
+ * - migration to new scsi host api (remove legacy code)
+ * - free host scribble before scsi_done
+ * - fix error handling
+ * - one isapnp device added to id_table
+ *
+ * Revision 2.6  2003/10/30 20:52:47  fischer
+ * - interfaces changes for kernel 2.6
+ * - aha152x_probe_one introduced for pcmcia stub
+ * - fixed pnpdev handling
+ * - instead of allocation a new one, reuse command for request sense after check condition and reset
+ * - fixes race in is_complete
+ *
+ * Revision 2.5  2002/04/14 11:24:53  fischer
+ * - isapnp support
+ * - abort fixed
+ * - 2.5 support
+ *
+ * Revision 2.4  2000/12/16 12:53:56  fischer
+ * - allow REQUEST SENSE to be queued
+ * - handle shared PCI interrupts
+ *
+ * Revision 2.3  2000/11/04 16:40:26  fischer
+ * - handle data overruns
+ * - extend timeout for data phases
+ *
+ * Revision 2.2  2000/08/08 19:54:53  fischer
+ * - minor changes
+ *
+ * Revision 2.1  2000/05/17 16:23:17  fischer
+ * - signature update
+ * - fix for data out w/o scatter gather
+ *
+ * Revision 2.0  1999/12/25 15:07:32  fischer
+ * - interrupt routine completly reworked
+ * - basic support for new eh code
+ *
+ * Revision 1.21  1999/11/10 23:46:36  fischer
+ * - default to synchronous operation
+ * - synchronous negotiation fixed
+ * - added timeout to loops
+ * - debugging output can be controlled through procfs
+ *
+ * Revision 1.20  1999/11/07 18:37:31  fischer
+ * - synchronous operation works
+ * - resid support for sg driver
+ *
+ * Revision 1.19  1999/11/02 22:39:59  fischer
+ * - moved leading comments to README.aha152x
+ * - new additional module parameters
+ * - updates for 2.3
+ * - support for the Tripace TC1550 controller
+ * - interrupt handling changed
+ *
+ * Revision 1.18  1996/09/07 20:10:40  fischer
+ * - fixed can_queue handling (multiple outstanding commands working again)
+ *
+ * Revision 1.17  1996/08/17 16:05:14  fischer
+ * - biosparam improved
+ * - interrupt verification
+ * - updated documentation
+ * - cleanups
+ *
+ * Revision 1.16  1996/06/09 00:04:56  root
+ * - added configuration symbols for insmod (aha152x/aha152x1)
+ *
+ * Revision 1.15  1996/04/30 14:52:06  fischer
+ * - proc info fixed
+ * - support for extended translation for >1GB disks
+ *
+ * Revision 1.14  1996/01/17  15:11:20  fischer
+ * - fixed lockup in MESSAGE IN phase after reconnection
+ *
+ * Revision 1.13  1996/01/09  02:15:53  fischer
+ * - some cleanups
+ * - moved request_irq behind controller initialization
+ *   (to avoid spurious interrupts)
+ *
+ * Revision 1.12  1995/12/16  12:26:07  fischer
+ * - barrier()s added
+ * - configurable RESET delay added
+ *
+ * Revision 1.11  1995/12/06  21:18:35  fischer
+ * - some minor updates
+ *
+ * Revision 1.10  1995/07/22  19:18:45  fischer
+ * - support for 2 controllers
+ * - started synchronous data transfers (not working yet)
+ *
+ * Revision 1.9  1995/03/18  09:20:24  root
+ * - patches for PCMCIA and modules
+ *
+ * Revision 1.8  1995/01/21  22:07:19  root
+ * - snarf_region => request_region
+ * - aha152x_intr interface change
+ *
+ * Revision 1.7  1995/01/02  23:19:36  root
+ * - updated COMMAND_SIZE to cmd_len
+ * - changed sti() to restore_flags()
+ * - fixed some #ifdef which generated warnings
+ *
+ * Revision 1.6  1994/11/24  20:35:27  root
+ * - problem with odd number of bytes in fifo fixed
+ *
+ * Revision 1.5  1994/10/30  14:39:56  root
+ * - abort code fixed
+ * - debugging improved
+ *
+ * Revision 1.4  1994/09/12  11:33:01  root
+ * - irqaction to request_irq
+ * - abortion updated
+ *
+ * Revision 1.3  1994/08/04  13:53:05  root
+ * - updates for mid-level-driver changes
+ * - accept unexpected BUSFREE phase as error condition
+ * - parity check now configurable
+ *
+ * Revision 1.2  1994/07/03  12:56:36  root
+ * - cleaned up debugging code
+ * - more tweaking on reset delays
+ * - updated abort/reset code (pretty untested...)
+ *
+ * Revision 1.1  1994/05/28  21:18:49  root
+ * - update for mid-level interface change (abort-reset)
+ * - delays after resets adjusted for some slow devices
+ *
+ * Revision 1.0  1994/03/25  12:52:00  root
+ * - Fixed "more data than expected" problem
+ * - added new BIOS signatures
+ *
+ * Revision 0.102  1994/01/31  20:44:12  root
+ * - minor changes in insw/outsw handling
+ *
+ * Revision 0.101  1993/12/13  01:16:27  root
+ * - fixed STATUS phase (non-GOOD stati were dropped sometimes;
+ *   fixes problems with CD-ROM sector size detection & media change)
+ *
+ * Revision 0.100  1993/12/10  16:58:47  root
+ * - fix for unsuccessful selections in case of non-continuous id assignments
+ *   on the scsi bus.
+ *
+ * Revision 0.99  1993/10/24  16:19:59  root
+ * - fixed DATA IN (rare read errors gone)
+ *
+ * Revision 0.98  1993/10/17  12:54:44  root
+ * - fixed some recent fixes (shame on me)
+ * - moved initialization of scratch area to aha152x_queue
+ *
+ * Revision 0.97  1993/10/09  18:53:53  root
+ * - DATA IN fixed. Rarely left data in the fifo.
+ *
+ * Revision 0.96  1993/10/03  00:53:59  root
+ * - minor changes on DATA IN
+ *
+ * Revision 0.95  1993/09/24  10:36:01  root
+ * - change handling of MSGI after reselection
+ * - fixed sti/cli
+ * - minor changes
+ *
+ * Revision 0.94  1993/09/18  14:08:22  root
+ * - fixed bug in multiple outstanding command code
+ * - changed detection
+ * - support for kernel command line configuration
+ * - reset corrected
+ * - changed message handling
+ *
+ * Revision 0.93  1993/09/15  20:41:19  root
+ * - fixed bugs with multiple outstanding commands
+ *
+ * Revision 0.92  1993/09/13  02:46:33  root
+ * - multiple outstanding commands work (no problems with IBM drive)
+ *
+ * Revision 0.91  1993/09/12  20:51:46  root
+ * added multiple outstanding commands
+ * (some problem with this $%&? IBM device remain)
+ *
+ * Revision 0.9  1993/09/12  11:11:22  root
+ * - corrected auto-configuration
+ * - changed the auto-configuration (added some '#define's)
+ * - added support for dis-/reconnection
+ *
+ * Revision 0.8  1993/09/06  23:09:39  root
+ * - added support for the drive activity light
+ * - minor changes
+ *
+ * Revision 0.7  1993/09/05  14:30:15  root
+ * - improved phase detection
+ * - now using the new snarf_region code of 0.99pl13
+ *
+ * Revision 0.6  1993/09/02  11:01:38  root
+ * first public release; added some signatures and biosparam()
+ *
+ * Revision 0.5  1993/08/30  10:23:30  root
+ * fixed timing problems with my IBM drive
+ *
+ * Revision 0.4  1993/08/29  14:06:52  root
+ * fixed some problems with timeouts due incomplete commands
+ *
+ * Revision 0.3  1993/08/28  15:55:03  root
+ * writing data works too.  mounted and worked on a dos partition
+ *
+ * Revision 0.2  1993/08/27  22:42:07  root
+ * reading data works.  Mounted a msdos partition.
+ *
+ * Revision 0.1  1993/08/25  13:38:30  root
+ * first "damn thing doesn't work" version
+ *
+ * Revision 0.0  1993/08/14  19:54:25  root
+ * empty function bodies; detect() works.
+ *
+ *
+ **************************************************************************
+ 
+ see Documentation/scsi/aha152x.txt for configuration details
+
+ **************************************************************************/
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <linux/blkdev.h>
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/isapnp.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <asm/semaphore.h>
+#include <scsi/scsicam.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha152x.h"
+
+
+/* DEFINES */
+
+/* For PCMCIA cards, always use AUTOCONF */
+#if defined(PCMCIA) || defined(MODULE)
+#if !defined(AUTOCONF)
+#define AUTOCONF
+#endif
+#endif
+
+#if !defined(AUTOCONF) && !defined(SETUP0)
+#error define AUTOCONF or SETUP0
+#endif
+
+#if defined(AHA152X_DEBUG)
+#define DEBUG_DEFAULT debug_eh
+
+#define DPRINTK(when,msgs...) \
+	do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
+
+#define DO_LOCK(flags)	\
+	do { \
+		if(spin_is_locked(&QLOCK)) { \
+			DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		} \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		spin_lock_irqsave(&QLOCK,flags); \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		QLOCKER=__FUNCTION__; \
+		QLOCKERL=__LINE__; \
+	} while(0)
+
+#define DO_UNLOCK(flags)	\
+	do { \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+		spin_unlock_irqrestore(&QLOCK,flags); \
+		DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+		QLOCKER="(not locked)"; \
+		QLOCKERL=0; \
+	} while(0)
+
+#else
+#define DPRINTK(when,msgs...)
+#define	DO_LOCK(flags)		spin_lock_irqsave(&QLOCK,flags)
+#define	DO_UNLOCK(flags)	spin_unlock_irqrestore(&QLOCK,flags)
+#endif
+
+#define LEAD		"(scsi%d:%d:%d) "
+#define WARN_LEAD	KERN_WARNING	LEAD
+#define INFO_LEAD	KERN_INFO	LEAD
+#define NOTE_LEAD	KERN_NOTICE	LEAD
+#define ERR_LEAD	KERN_ERR	LEAD
+#define DEBUG_LEAD	KERN_DEBUG	LEAD
+#define CMDINFO(cmd) \
+			(cmd) ? ((cmd)->device->host->host_no) : -1, \
+                        (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
+			(cmd) ? ((cmd)->device->lun & 0x07) : -1
+
+#define DELAY_DEFAULT 1000
+
+#if defined(PCMCIA)
+#define IRQ_MIN 0
+#define IRQ_MAX 16
+#else
+#define IRQ_MIN 9
+#if defined(__PPC)
+#define IRQ_MAX (NR_IRQS-1)
+#else
+#define IRQ_MAX 12
+#endif
+#endif
+
+enum {
+	not_issued	= 0x0001,	/* command not yet issued */
+	selecting	= 0x0002, 	/* target is beeing selected */
+	identified	= 0x0004,	/* IDENTIFY was sent */
+	disconnected	= 0x0008,	/* target disconnected */
+	completed	= 0x0010,	/* target sent COMMAND COMPLETE */ 
+	aborted		= 0x0020,	/* ABORT was sent */
+	resetted	= 0x0040,	/* BUS DEVICE RESET was sent */
+	spiordy		= 0x0080,	/* waiting for SPIORDY to raise */
+	syncneg		= 0x0100,	/* synchronous negotiation in progress */
+	aborting	= 0x0200,	/* ABORT is pending */
+	resetting	= 0x0400,	/* BUS DEVICE RESET is pending */
+	check_condition = 0x0800,	/* requesting sense after CHECK CONDITION */
+};
+
+MODULE_AUTHOR("Jürgen Fischer");
+MODULE_DESCRIPTION(AHA152X_REVID);
+MODULE_LICENSE("GPL");
+
+#if !defined(PCMCIA)
+#if defined(MODULE)
+static int io[] = {0, 0};
+module_param_array(io, int, NULL, 0);
+MODULE_PARM_DESC(io,"base io address of controller");
+
+static int irq[] = {0, 0};
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(irq,"interrupt for controller");
+
+static int scsiid[] = {7, 7};
+module_param_array(scsiid, int, NULL, 0);
+MODULE_PARM_DESC(scsiid,"scsi id of controller");
+
+static int reconnect[] = {1, 1};
+module_param_array(reconnect, int, NULL, 0);
+MODULE_PARM_DESC(reconnect,"allow targets to disconnect");
+
+static int parity[] = {1, 1};
+module_param_array(parity, int, NULL, 0);
+MODULE_PARM_DESC(parity,"use scsi parity");
+
+static int sync[] = {1, 1};
+module_param_array(sync, int, NULL, 0);
+MODULE_PARM_DESC(sync,"use synchronous transfers");
+
+static int delay[] = {DELAY_DEFAULT, DELAY_DEFAULT};
+module_param_array(delay, int, NULL, 0);
+MODULE_PARM_DESC(delay,"scsi reset delay");
+
+static int exttrans[] = {0, 0};
+module_param_array(exttrans, int, NULL, 0);
+MODULE_PARM_DESC(exttrans,"use extended translation");
+
+#if !defined(AHA152X_DEBUG)
+static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+module_param_array(aha152x, int, NULL, 0);
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+
+static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
+module_param_array(aha152x1, int, NULL, 0);
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+#else
+static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
+module_param_array(debug, int, NULL, 0);
+MODULE_PARM_DESC(debug, "flags for driver debugging");
+
+static int aha152x[]   = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+module_param_array(aha152x, int, NULL, 0);
+MODULE_PARM_DESC(aha152x, "parameters for first controller");
+
+static int aha152x1[]  = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
+module_param_array(aha152x1, int, NULL, 0);
+MODULE_PARM_DESC(aha152x1, "parameters for second controller");
+#endif /* !defined(AHA152X_DEBUG) */
+#endif /* MODULE */
+
+#ifdef __ISAPNP__
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1505), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A','D','P'), ISAPNP_FUNCTION(0x1530), 0 },
+	{ ISAPNP_DEVICE_SINGLE_END, }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+#endif /* ISAPNP */
+
+#endif /* !PCMCIA */
+
+static int registered_count=0;
+static struct Scsi_Host *aha152x_host[2];
+static Scsi_Host_Template aha152x_driver_template;
+
+/*
+ * internal states of the host
+ *
+ */ 
+enum aha152x_state {
+	idle=0,
+	unknown,
+	seldo,
+	seldi,
+	selto,
+	busfree,
+	msgo,
+	cmd,
+	msgi,
+	status,
+	datai,
+	datao,
+	parerr,
+	rsti,
+	maxstate
+};
+
+/*
+ * current state information of the host
+ *
+ */
+struct aha152x_hostdata {
+	Scsi_Cmnd *issue_SC;
+		/* pending commands to issue */
+
+	Scsi_Cmnd *current_SC;
+		/* current command on the bus */
+
+	Scsi_Cmnd *disconnected_SC;
+		/* commands that disconnected */
+
+	Scsi_Cmnd *done_SC;
+		/* command that was completed */
+
+	spinlock_t lock;
+		/* host lock */
+
+#if defined(AHA152X_DEBUG)
+	const char *locker;
+		/* which function has the lock */
+	int lockerl;	/* where did it get it */
+
+	int debug;	/* current debugging setting */
+#endif
+
+#if defined(AHA152X_STAT)
+	int           total_commands;
+	int	      disconnections;
+	int	      busfree_without_any_action;
+	int	      busfree_without_old_command;
+	int	      busfree_without_new_command;
+	int	      busfree_without_done_command;
+	int	      busfree_with_check_condition;
+	int           count[maxstate];
+	int           count_trans[maxstate];
+	unsigned long time[maxstate];
+#endif
+
+	int commands;		/* current number of commands */
+
+	int reconnect;		/* disconnection allowed */
+	int parity;		/* parity checking enabled */
+	int synchronous;	/* synchronous transferes enabled */
+	int delay;		/* reset out delay */
+	int ext_trans;		/* extended translation enabled */
+
+	int swint; 		/* software-interrupt was fired during detect() */
+	int service;		/* bh needs to be run */
+	int in_intr;		/* bh is running */
+
+	/* current state,
+	   previous state,
+	   last state different from current state */
+	enum aha152x_state state, prevstate, laststate;
+
+	int target;
+		/* reconnecting target */
+
+	unsigned char syncrate[8];
+		/* current synchronous transfer agreements */
+
+	unsigned char syncneg[8];
+		/* 0: no negotiation;
+		 * 1: negotiation in progress;
+		 * 2: negotiation completed
+		 */
+
+	int cmd_i;
+		/* number of sent bytes of current command */
+
+	int msgi_len;
+		/* number of received message bytes */
+	unsigned char msgi[256];
+		/* received message bytes */
+
+	int msgo_i, msgo_len;	
+		/* number of sent bytes and length of current messages */
+	unsigned char msgo[256];
+		/* pending messages */
+
+	int data_len;
+		/* number of sent/received bytes in dataphase */
+
+	unsigned long io_port0;
+	unsigned long io_port1;
+
+#ifdef __ISAPNP__
+	struct pnp_dev *pnpdev;
+#endif
+};
+
+
+/*
+ * host specific command extension
+ *
+ */
+struct aha152x_scdata {
+	Scsi_Cmnd *next;	/* next sc in queue */
+	struct semaphore *sem;	/* semaphore to block on */
+};
+
+
+/* access macros for hostdata */
+
+#define HOSTDATA(shpnt)		((struct aha152x_hostdata *) &shpnt->hostdata)
+
+#define HOSTNO			((shpnt)->host_no)
+
+#define CURRENT_SC		(HOSTDATA(shpnt)->current_SC)
+#define DONE_SC			(HOSTDATA(shpnt)->done_SC)
+#define ISSUE_SC		(HOSTDATA(shpnt)->issue_SC)
+#define DISCONNECTED_SC		(HOSTDATA(shpnt)->disconnected_SC)
+#define QLOCK			(HOSTDATA(shpnt)->lock)
+#define QLOCKER			(HOSTDATA(shpnt)->locker)
+#define QLOCKERL		(HOSTDATA(shpnt)->lockerl)
+
+#define STATE			(HOSTDATA(shpnt)->state)
+#define PREVSTATE		(HOSTDATA(shpnt)->prevstate)
+#define LASTSTATE		(HOSTDATA(shpnt)->laststate)
+
+#define RECONN_TARGET		(HOSTDATA(shpnt)->target)
+
+#define CMD_I			(HOSTDATA(shpnt)->cmd_i)
+
+#define MSGO(i)			(HOSTDATA(shpnt)->msgo[i])
+#define MSGO_I			(HOSTDATA(shpnt)->msgo_i)
+#define MSGOLEN			(HOSTDATA(shpnt)->msgo_len)
+#define ADDMSGO(x)		(MSGOLEN<256 ? (void)(MSGO(MSGOLEN++)=x) : aha152x_error(shpnt,"MSGO overflow"))
+
+#define MSGI(i)			(HOSTDATA(shpnt)->msgi[i])
+#define MSGILEN			(HOSTDATA(shpnt)->msgi_len)
+#define ADDMSGI(x)		(MSGILEN<256 ? (void)(MSGI(MSGILEN++)=x) : aha152x_error(shpnt,"MSGI overflow"))
+
+#define DATA_LEN		(HOSTDATA(shpnt)->data_len)
+
+#define SYNCRATE		(HOSTDATA(shpnt)->syncrate[CURRENT_SC->device->id])
+#define SYNCNEG			(HOSTDATA(shpnt)->syncneg[CURRENT_SC->device->id])
+
+#define DELAY			(HOSTDATA(shpnt)->delay)
+#define EXT_TRANS		(HOSTDATA(shpnt)->ext_trans)
+#define TC1550			(HOSTDATA(shpnt)->tc1550)
+#define RECONNECT		(HOSTDATA(shpnt)->reconnect)
+#define PARITY			(HOSTDATA(shpnt)->parity)
+#define SYNCHRONOUS		(HOSTDATA(shpnt)->synchronous)
+
+#define HOSTIOPORT0		(HOSTDATA(shpnt)->io_port0)
+#define HOSTIOPORT1		(HOSTDATA(shpnt)->io_port1)
+
+#define SCDATA(SCpnt)		((struct aha152x_scdata *) (SCpnt)->host_scribble)
+#define SCNEXT(SCpnt)		SCDATA(SCpnt)->next
+#define SCSEM(SCpnt)		SCDATA(SCpnt)->sem
+
+#define SG_ADDRESS(buffer)	((char *) (page_address((buffer)->page)+(buffer)->offset))
+
+/* state handling */
+static void seldi_run(struct Scsi_Host *shpnt);
+static void seldo_run(struct Scsi_Host *shpnt);
+static void selto_run(struct Scsi_Host *shpnt);
+static void busfree_run(struct Scsi_Host *shpnt);
+
+static void msgo_init(struct Scsi_Host *shpnt);
+static void msgo_run(struct Scsi_Host *shpnt);
+static void msgo_end(struct Scsi_Host *shpnt);
+
+static void cmd_init(struct Scsi_Host *shpnt);
+static void cmd_run(struct Scsi_Host *shpnt);
+static void cmd_end(struct Scsi_Host *shpnt);
+
+static void datai_init(struct Scsi_Host *shpnt);
+static void datai_run(struct Scsi_Host *shpnt);
+static void datai_end(struct Scsi_Host *shpnt);
+
+static void datao_init(struct Scsi_Host *shpnt);
+static void datao_run(struct Scsi_Host *shpnt);
+static void datao_end(struct Scsi_Host *shpnt);
+
+static void status_run(struct Scsi_Host *shpnt);
+
+static void msgi_run(struct Scsi_Host *shpnt);
+static void msgi_end(struct Scsi_Host *shpnt);
+
+static void parerr_run(struct Scsi_Host *shpnt);
+static void rsti_run(struct Scsi_Host *shpnt);
+
+static void is_complete(struct Scsi_Host *shpnt);
+
+/*
+ * driver states
+ *
+ */
+static struct {
+	char		*name;
+	void		(*init)(struct Scsi_Host *);
+	void		(*run)(struct Scsi_Host *);
+	void		(*end)(struct Scsi_Host *);
+	int		spio;
+} states[] = {
+	{ "idle",	NULL,		NULL,		NULL,		0},
+	{ "unknown",	NULL,		NULL,		NULL,		0},
+	{ "seldo",	NULL,		seldo_run,	NULL,		0},
+	{ "seldi",	NULL,		seldi_run,	NULL,		0},
+	{ "selto",	NULL,		selto_run,	NULL,		0},
+	{ "busfree",	NULL,		busfree_run,	NULL,		0},
+	{ "msgo",	msgo_init,	msgo_run,	msgo_end,	1},
+	{ "cmd",	cmd_init,	cmd_run,	cmd_end,	1},
+	{ "msgi",	NULL,		msgi_run,	msgi_end,	1},
+	{ "status",	NULL,		status_run,	NULL,		1},
+	{ "datai",	datai_init,	datai_run,	datai_end,	0},
+	{ "datao",	datao_init,	datao_run,	datao_end,	0},
+	{ "parerr",	NULL,		parerr_run,	NULL,		0},
+	{ "rsti",	NULL,		rsti_run,	NULL,		0},
+};
+
+/* setup & interrupt */
+static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
+static void reset_ports(struct Scsi_Host *shpnt);
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
+static void done(struct Scsi_Host *shpnt, int error);
+
+/* diagnostics */
+static void disp_ports(struct Scsi_Host *shpnt);
+static void show_command(Scsi_Cmnd * ptr);
+static void show_queues(struct Scsi_Host *shpnt);
+static void disp_enintr(struct Scsi_Host *shpnt);
+
+
+/*
+ *  queue services:
+ *
+ */
+static inline void append_SC(Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+	Scsi_Cmnd *end;
+
+	SCNEXT(new_SC) = NULL;
+	if (!*SC)
+		*SC = new_SC;
+	else {
+		for (end = *SC; SCNEXT(end); end = SCNEXT(end))
+			;
+		SCNEXT(end) = new_SC;
+	}
+}
+
+static inline Scsi_Cmnd *remove_first_SC(Scsi_Cmnd ** SC)
+{
+	Scsi_Cmnd *ptr;
+
+	ptr = *SC;
+	if (ptr) {
+		*SC = SCNEXT(*SC);
+		SCNEXT(ptr)=NULL;
+	}
+	return ptr;
+}
+
+static inline Scsi_Cmnd *remove_lun_SC(Scsi_Cmnd ** SC, int target, int lun)
+{
+	Scsi_Cmnd *ptr, *prev;
+
+	for (ptr = *SC, prev = NULL;
+	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
+
+	if (ptr) {
+		if (prev)
+			SCNEXT(prev) = SCNEXT(ptr);
+		else
+			*SC = SCNEXT(ptr);
+
+		SCNEXT(ptr)=NULL;
+	}
+
+	return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
+{
+	Scsi_Cmnd *ptr, *prev;
+
+	for (ptr = *SC, prev = NULL;
+	     ptr && SCp!=ptr;
+	     prev = ptr, ptr = SCNEXT(ptr))
+	     ;
+
+	if (ptr) {
+		if (prev)
+			SCNEXT(prev) = SCNEXT(ptr);
+		else
+			*SC = SCNEXT(ptr);
+
+		SCNEXT(ptr)=NULL;
+	}
+
+	return ptr;
+}
+
+static inline struct Scsi_Host *lookup_irq(int irqno)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
+		if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
+			return aha152x_host[i];
+
+	return NULL;
+}
+
+static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
+
+	if (!shpnt) {
+        	printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
+		return IRQ_NONE;
+	}
+
+	HOSTDATA(shpnt)->swint++;
+
+	SETPORT(DMACNTRL0, INTEN);
+	return IRQ_HANDLED;
+}
+
+struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
+{
+	struct Scsi_Host *shpnt;
+
+	shpnt = scsi_host_alloc(&aha152x_driver_template, sizeof(struct aha152x_hostdata));
+	if (!shpnt) {
+		printk(KERN_ERR "aha152x: scsi_host_alloc failed\n");
+		return NULL;
+	}
+
+	/* need to have host registered before triggering any interrupt */
+	aha152x_host[registered_count] = shpnt;
+
+	memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
+
+	shpnt->io_port   = setup->io_port;
+	shpnt->n_io_port = IO_RANGE;
+	shpnt->irq       = setup->irq;
+
+	if (!setup->tc1550) {
+		HOSTIOPORT0 = setup->io_port;
+		HOSTIOPORT1 = setup->io_port;
+	} else {
+		HOSTIOPORT0 = setup->io_port+0x10;
+		HOSTIOPORT1 = setup->io_port-0x10;
+	}
+
+	spin_lock_init(&QLOCK);
+	RECONNECT   = setup->reconnect;
+	SYNCHRONOUS = setup->synchronous;
+	PARITY      = setup->parity;
+	DELAY       = setup->delay;
+	EXT_TRANS   = setup->ext_trans;
+
+#if defined(AHA152X_DEBUG)
+	HOSTDATA(shpnt)->debug = setup->debug;
+#endif
+
+	SETPORT(SCSIID, setup->scsiid << 4);
+	shpnt->this_id = setup->scsiid;
+
+	if (setup->reconnect)
+		shpnt->can_queue = AHA152X_MAXQUEUE;
+
+	/* RESET OUT */
+	printk("aha152x: resetting bus...\n");
+	SETPORT(SCSISEQ, SCSIRSTO);
+	mdelay(256);
+	SETPORT(SCSISEQ, 0);
+	mdelay(DELAY);
+
+	reset_ports(shpnt);
+
+	printk(KERN_INFO
+	       "aha152x%d%s: "
+	       "vital data: rev=%x, "
+	       "io=0x%03lx (0x%03lx/0x%03lx), "
+	       "irq=%d, "
+	       "scsiid=%d, "
+	       "reconnect=%s, "
+	       "parity=%s, "
+	       "synchronous=%s, "
+	       "delay=%d, "
+	       "extended translation=%s\n",
+	       shpnt->host_no, setup->tc1550 ? " (tc1550 mode)" : "",
+	       GETPORT(REV) & 0x7,
+	       shpnt->io_port, HOSTIOPORT0, HOSTIOPORT1,
+	       shpnt->irq,
+	       shpnt->this_id,
+	       RECONNECT ? "enabled" : "disabled",
+	       PARITY ? "enabled" : "disabled",
+	       SYNCHRONOUS ? "enabled" : "disabled",
+	       DELAY,
+	       EXT_TRANS ? "enabled" : "disabled");
+
+	/* not expecting any interrupts */
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, 0);
+
+	if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+		printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+
+	HOSTDATA(shpnt)->swint = 0;
+
+	printk(KERN_INFO "aha152x%d: trying software interrupt, ", shpnt->host_no);
+
+	mb();
+	SETPORT(DMACNTRL0, SWINT|INTEN);
+	mdelay(1000);
+	free_irq(shpnt->irq, shpnt);
+
+	if (!HOSTDATA(shpnt)->swint) {
+		if (TESTHI(DMASTAT, INTSTAT)) {
+			printk("lost.\n");
+		} else {
+			printk("failed.\n");
+		}
+
+		SETPORT(DMACNTRL0, INTEN);
+
+		printk(KERN_ERR "aha152x%d: irq %d possibly wrong.  "
+				"Please verify.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+	printk("ok.\n");
+
+
+	/* clear interrupts */
+	SETPORT(SSTAT0, 0x7f);
+	SETPORT(SSTAT1, 0xef);
+
+	if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+		printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
+		goto out_host_put;
+	}
+
+	if( scsi_add_host(shpnt, NULL) ) {
+		free_irq(shpnt->irq, shpnt);
+		printk(KERN_ERR "aha152x%d: failed to add host.\n", shpnt->host_no);
+		goto out_host_put;
+	}
+
+	scsi_scan_host(shpnt);
+
+	registered_count++;
+
+	return shpnt;
+
+out_host_put:
+	aha152x_host[registered_count]=NULL;
+	scsi_host_put(shpnt);
+
+	return NULL;
+}
+
+void aha152x_release(struct Scsi_Host *shpnt)
+{
+	if(!shpnt)
+		return;
+
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+
+#if !defined(PCMCIA)
+	if (shpnt->io_port)
+		release_region(shpnt->io_port, IO_RANGE);
+#endif
+
+#ifdef __ISAPNP__
+	if (HOSTDATA(shpnt)->pnpdev)
+		pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
+#endif
+
+	scsi_remove_host(shpnt);
+	scsi_host_put(shpnt);
+}
+
+
+/*
+ * setup controller to generate interrupts depending
+ * on current state (lock has to be acquired)
+ *
+ */ 
+static int setup_expected_interrupts(struct Scsi_Host *shpnt)
+{
+	if(CURRENT_SC) {
+		CURRENT_SC->SCp.phase |= 1 << 16;
+	
+		if(CURRENT_SC->SCp.phase & selecting) {
+			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
+			SETPORT(SSTAT1, SELTO);
+			SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
+			SETPORT(SIMODE1, ENSELTIMO);
+		} else {
+			DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
+			SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
+			SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+		}
+	} else if(STATE==seldi) {
+		DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
+		SETPORT(SIMODE0, 0);
+		SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE); 
+	} else {
+		DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
+			CMDINFO(CURRENT_SC),
+			DISCONNECTED_SC ? "(reselection)" : "",
+			ISSUE_SC ? "(busfree)" : "");
+		SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
+		SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
+	}
+
+	if(!HOSTDATA(shpnt)->in_intr)
+		SETBITS(DMACNTRL0, INTEN);
+
+	return TESTHI(DMASTAT, INTSTAT);
+}
+
+
+/* 
+ *  Queue a command and setup interrupts for a free bus.
+ */
+static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *))
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_queue) {
+		printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
+		       CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+		print_command(SCpnt->cmnd);
+	}
+#endif
+
+	SCpnt->scsi_done	= done;
+	SCpnt->resid 		= SCpnt->request_bufflen;
+	SCpnt->SCp.phase	= not_issued | phase;
+	SCpnt->SCp.Status	= CHECK_CONDITION;
+	SCpnt->SCp.Message	= 0;
+	SCpnt->SCp.have_data_in	= 0;
+	SCpnt->SCp.sent_command	= 0;
+
+	if(SCpnt->SCp.phase & (resetting|check_condition)) {
+		if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
+			printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));
+			return FAILED;
+		}
+	} else {
+		SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
+		if(SCpnt->host_scribble==0) {
+			printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+			return FAILED;
+		}
+	}
+
+	SCNEXT(SCpnt)		= NULL;
+	SCSEM(SCpnt)		= sem;
+
+	/* setup scratch area
+	   SCp.ptr              : buffer pointer
+	   SCp.this_residual    : buffer length
+	   SCp.buffer           : next buffer
+	   SCp.buffers_residual : left buffers in list
+	   SCp.phase            : current state of the command */
+	if (SCpnt->use_sg) {
+		SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+	} else {
+		SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer           = NULL;
+		SCpnt->SCp.buffers_residual = 0;
+	}
+
+	DO_LOCK(flags);
+
+#if defined(AHA152X_STAT)
+	HOSTDATA(shpnt)->total_commands++;
+#endif
+
+	/* Turn led on, when this is the first command. */
+	HOSTDATA(shpnt)->commands++;
+	if (HOSTDATA(shpnt)->commands==1)
+		SETPORT(PORTA, 1);
+
+	append_SC(&ISSUE_SC, SCpnt);
+
+	if(!HOSTDATA(shpnt)->in_intr)
+		setup_expected_interrupts(shpnt);
+
+	DO_UNLOCK(flags);
+
+	return 0;
+}
+
+/*
+ *  queue a command
+ *
+ */
+static int aha152x_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+#if 0
+	if(*SCpnt->cmnd == REQUEST_SENSE) {
+		SCpnt->result = 0;
+		done(SCpnt);
+
+		return 0;
+	}
+#endif
+
+	return aha152x_internal_queue(SCpnt, NULL, 0, done);
+}
+
+
+/*
+ *  
+ *
+ */
+static void reset_done(Scsi_Cmnd *SCpnt)
+{
+#if 0
+	struct Scsi_Host *shpnt = SCpnt->host;
+	DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
+#endif
+	if(SCSEM(SCpnt)) {
+		up(SCSEM(SCpnt));
+	} else {
+		printk(KERN_ERR "aha152x: reset_done w/o semaphore\n");
+	}
+}
+
+/*
+ *  Abort a command
+ *
+ */
+static int aha152x_abort(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	DO_LOCK(flags);
+
+	ptr=remove_SC(&ISSUE_SC, SCpnt);
+
+	if(ptr) {
+		DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt));
+
+		HOSTDATA(shpnt)->commands--;
+		if (!HOSTDATA(shpnt)->commands)
+			SETPORT(PORTA, 0);
+		DO_UNLOCK(flags);
+
+		kfree(SCpnt->host_scribble);
+		SCpnt->host_scribble=NULL;
+
+		return SUCCESS;
+	} 
+
+	DO_UNLOCK(flags);
+
+	/*
+	 * FIXME:
+	 * for current command: queue ABORT for message out and raise ATN
+	 * for disconnected command: pseudo SC with ABORT message or ABORT on reselection?
+	 *
+	 */
+
+	printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
+
+	return FAILED;
+}
+
+static void timer_expired(unsigned long p)
+{
+	Scsi_Cmnd	 *SCp   = (Scsi_Cmnd *)p;
+	struct semaphore *sem   = SCSEM(SCp);
+	struct Scsi_Host *shpnt = SCp->device->host;
+	unsigned long flags;
+
+	/* remove command from issue queue */
+	DO_LOCK(flags);
+	remove_SC(&ISSUE_SC, SCp);
+	DO_UNLOCK(flags);
+
+	up(sem);
+}
+
+/*
+ * Reset a device
+ *
+ */
+static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	DECLARE_MUTEX_LOCKED(sem);
+	struct timer_list timer;
+	int ret, issued, disconnected;
+	unsigned long flags;
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	if(CURRENT_SC==SCpnt) {
+		printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+		return FAILED;
+	}
+
+	DO_LOCK(flags);
+	issued       = remove_SC(&ISSUE_SC, SCpnt)==0;
+	disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
+	DO_UNLOCK(flags);
+
+	SCpnt->cmd_len         = 0;
+	SCpnt->use_sg          = 0;
+	SCpnt->request_buffer  = NULL;
+	SCpnt->request_bufflen = 0;
+
+	init_timer(&timer);
+	timer.data     = (unsigned long) SCpnt;
+	timer.expires  = jiffies + 100*HZ;   /* 10s */
+	timer.function = (void (*)(unsigned long)) timer_expired;
+
+	aha152x_internal_queue(SCpnt, &sem, resetting, reset_done);
+	add_timer(&timer);
+	down(&sem);
+	del_timer(&timer);
+	
+	SCpnt->cmd_len         = SCpnt->old_cmd_len;
+	SCpnt->use_sg          = SCpnt->old_use_sg;
+  	SCpnt->request_buffer  = SCpnt->buffer;
+       	SCpnt->request_bufflen = SCpnt->bufflen;
+
+	DO_LOCK(flags);
+
+	if(SCpnt->SCp.phase & resetted) {
+		HOSTDATA(shpnt)->commands--;
+		if (!HOSTDATA(shpnt)->commands)
+			SETPORT(PORTA, 0);
+		kfree(SCpnt->host_scribble);
+		SCpnt->host_scribble=NULL;
+
+		ret = SUCCESS;
+	} else {
+		/* requeue */
+		if(!issued) {
+			append_SC(&ISSUE_SC, SCpnt);
+		} else if(disconnected) {
+			append_SC(&DISCONNECTED_SC, SCpnt);
+		}
+	
+		ret = FAILED;
+	}
+
+	DO_UNLOCK(flags);
+
+	spin_lock_irq(shpnt->host_lock);
+	return ret;
+}
+
+static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
+{
+	Scsi_Cmnd *ptr;
+
+	ptr=*SCs;
+	while(ptr) {
+		Scsi_Cmnd *next;
+
+		if(SCDATA(ptr)) {
+			next = SCNEXT(ptr);
+		} else {
+			printk(DEBUG_LEAD "queue corrupted at %p\n", CMDINFO(ptr), ptr);
+			next = NULL;
+		}
+
+		if (!ptr->device->soft_reset) {
+			DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr);
+			remove_SC(SCs, ptr);
+			HOSTDATA(shpnt)->commands--;
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=NULL;
+		}
+
+		ptr = next;
+	}
+}
+
+/*
+ * Reset the bus
+ *
+ */
+static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+	unsigned long flags;
+
+	DO_LOCK(flags);
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_eh) {
+		printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+		show_queues(shpnt);
+	}
+#endif
+
+	free_hard_reset_SCs(shpnt, &ISSUE_SC);
+	free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+
+	SETPORT(SCSISEQ, SCSIRSTO);
+	mdelay(256);
+	SETPORT(SCSISEQ, 0);
+	mdelay(DELAY);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "bus resetted\n", CMDINFO(SCpnt));
+
+	setup_expected_interrupts(shpnt);
+	if(HOSTDATA(shpnt)->commands==0)
+		SETPORT(PORTA, 0);
+
+	DO_UNLOCK(flags);
+
+	return SUCCESS;
+}
+
+
+/*
+ *  Restore default values to the AIC-6260 registers and reset the fifos
+ *
+ */
+static void reset_ports(struct Scsi_Host *shpnt)
+{
+	unsigned long flags;
+
+	/* disable interrupts */
+	SETPORT(DMACNTRL0, RSTFIFO);
+
+	SETPORT(SCSISEQ, 0);
+
+	SETPORT(SXFRCTL1, 0);
+	SETPORT(SCSISIG, 0);
+	SETRATE(0);
+
+	/* clear all interrupt conditions */
+	SETPORT(SSTAT0, 0x7f);
+	SETPORT(SSTAT1, 0xef);
+
+	SETPORT(SSTAT4, SYNCERR | FWERR | FRERR);
+
+	SETPORT(DMACNTRL0, 0);
+	SETPORT(DMACNTRL1, 0);
+
+	SETPORT(BRSTCNTRL, 0xf1);
+
+	/* clear SCSI fifos and transfer count */
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	DO_LOCK(flags);
+	setup_expected_interrupts(shpnt);
+	DO_UNLOCK(flags);
+}
+
+/*
+ * Reset the host (bus and controller)
+ *
+ */
+int aha152x_host_reset(Scsi_Cmnd * SCpnt)
+{
+#if defined(AHA152X_DEBUG)
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+#endif
+
+	DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
+
+	aha152x_bus_reset(SCpnt);
+
+	DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
+	reset_ports(SCpnt->device->host);
+
+	return SUCCESS;
+}
+
+/*
+ * Return the "logical geometry"
+ *
+ */
+static int aha152x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int *info_array)
+{
+	struct Scsi_Host *shpnt = sdev->host;
+
+	/* try default translation */
+	info_array[0] = 64;
+	info_array[1] = 32;
+	info_array[2] = (unsigned long)capacity / (64 * 32);
+
+	/* for disks >1GB do some guessing */
+	if (info_array[2] >= 1024) {
+		int info[3];
+
+		/* try to figure out the geometry from the partition table */
+		if (scsicam_bios_param(bdev, capacity, info) < 0 ||
+		    !((info[0] == 64 && info[1] == 32) || (info[0] == 255 && info[1] == 63))) {
+			if (EXT_TRANS) {
+				printk(KERN_NOTICE
+				       "aha152x: unable to verify geometry for disk with >1GB.\n"
+				       "         using extended translation.\n");
+				info_array[0] = 255;
+				info_array[1] = 63;
+				info_array[2] = (unsigned long)capacity / (255 * 63);
+			} else {
+				printk(KERN_NOTICE
+				       "aha152x: unable to verify geometry for disk with >1GB.\n"
+				       "         Using default translation. Please verify yourself.\n"
+				       "         Perhaps you need to enable extended translation in the driver.\n"
+				       "         See Documentation/scsi/aha152x.txt for details.\n");
+			}
+		} else {
+			info_array[0] = info[0];
+			info_array[1] = info[1];
+			info_array[2] = info[2];
+
+			if (info[0] == 255 && !EXT_TRANS) {
+				printk(KERN_NOTICE
+				       "aha152x: current partition table is using extended translation.\n"
+				       "         using it also, although it's not explicitly enabled.\n");
+			}
+		}
+	}
+
+	return 0;
+}
+
+/*
+ *  Internal done function
+ *
+ */
+static void done(struct Scsi_Host *shpnt, int error)
+{
+	if (CURRENT_SC) {
+		if(DONE_SC)
+			printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
+
+		DONE_SC = CURRENT_SC;
+		CURRENT_SC = NULL;
+		DONE_SC->result = error;
+	} else
+		printk(KERN_ERR "aha152x: done() called outside of command\n");
+}
+
+static struct work_struct aha152x_tq;
+
+/*
+ * Run service completions on the card with interrupts enabled.
+ *
+ */
+static void run(void)
+{
+	int i;
+	for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
+		struct Scsi_Host *shpnt = aha152x_host[i];
+		if (shpnt && HOSTDATA(shpnt)->service) {
+			HOSTDATA(shpnt)->service=0;
+			is_complete(shpnt);
+		}
+	}
+}
+
+/*
+ *    Interrupts handler
+ *
+ */
+
+static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *shpnt = lookup_irq(irqno);
+	unsigned char rev, dmacntrl0;
+
+	if (!shpnt) {
+		printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
+		return IRQ_NONE;
+	}
+
+	/*
+	 * Read a couple of registers that are known to not be all 1's. If
+	 * we read all 1's (-1), that means that either:
+	 *
+	 * a. The host adapter chip has gone bad, and we cannot control it,
+	 *	OR
+	 * b. The host adapter is a PCMCIA card that has been ejected
+	 *
+	 * In either case, we cannot do anything with the host adapter at
+	 * this point in time. So just ignore the interrupt and return.
+	 * In the latter case, the interrupt might actually be meant for
+	 * someone else sharing this IRQ, and that driver will handle it.
+	 */
+	rev = GETPORT(REV);
+	dmacntrl0 = GETPORT(DMACNTRL0);
+	if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
+		return IRQ_NONE;
+
+	/* no more interrupts from the controller, while we're busy.
+	   INTEN is restored by the BH handler */
+	CLRBITS(DMACNTRL0, INTEN);
+
+#if 0
+	/* check if there is already something to be
+           serviced; should not happen */
+	if(HOSTDATA(shpnt)->service) {
+		printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
+	        show_queues(shpnt);
+	}
+#endif
+	
+	/* Poke the BH handler */
+	HOSTDATA(shpnt)->service++;
+	INIT_WORK(&aha152x_tq, (void *) run, NULL);
+	schedule_work(&aha152x_tq);
+	return IRQ_HANDLED;
+}
+
+/*
+ * busfree phase
+ * - handle completition/disconnection/error of current command
+ * - start selection for next command (if any)
+ */
+static void busfree_run(struct Scsi_Host *shpnt)
+{
+	unsigned long flags;
+#if defined(AHA152X_STAT)
+	int action=0;
+#endif
+
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	SETPORT(SSTAT1, CLRBUSFREE);
+	
+	if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+		CURRENT_SC->SCp.phase &= ~syncneg;
+
+		if(CURRENT_SC->SCp.phase & completed) {
+			/* target sent COMMAND COMPLETE */
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+
+		} else if(CURRENT_SC->SCp.phase & aborted) {
+			DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC));
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
+
+		} else if(CURRENT_SC->SCp.phase & resetted) {
+			DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC));
+			done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
+
+		} else if(CURRENT_SC->SCp.phase & disconnected) {
+			/* target sent DISCONNECT */
+			DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
+				CMDINFO(CURRENT_SC),
+				CURRENT_SC->resid,
+				CURRENT_SC->request_bufflen);
+#if defined(AHA152X_STAT)
+			HOSTDATA(shpnt)->disconnections++;
+#endif
+			append_SC(&DISCONNECTED_SC, CURRENT_SC);
+			CURRENT_SC->SCp.phase |= 1 << 16;
+			CURRENT_SC = NULL;
+
+		} else {
+			done(shpnt, DID_ERROR << 16);
+		}
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_old_command++;
+#endif
+	}
+
+	DO_LOCK(flags);
+
+	if(DONE_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+
+		if(DONE_SC->SCp.phase & check_condition) {
+#if 0
+			if(HOSTDATA(shpnt)->debug & debug_eh) {
+				printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
+				print_sense("bh", DONE_SC);
+			}
+#endif
+
+			/* restore old command */
+			memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
+			DONE_SC->request_buffer  = DONE_SC->buffer;
+			DONE_SC->request_bufflen = DONE_SC->bufflen;
+			DONE_SC->use_sg          = DONE_SC->old_use_sg;
+			DONE_SC->cmd_len         = DONE_SC->old_cmd_len;
+
+			DONE_SC->SCp.Status = 0x02;
+
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+		} else if(DONE_SC->SCp.Status==0x02) {
+#if defined(AHA152X_STAT)
+			HOSTDATA(shpnt)->busfree_with_check_condition++;
+#endif
+#if 0
+			DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
+#endif
+
+			if(!(DONE_SC->SCp.Status & not_issued)) {
+				Scsi_Cmnd *ptr = DONE_SC;
+				DONE_SC=NULL;
+#if 0
+				DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
+#endif
+
+				ptr->cmnd[0]         = REQUEST_SENSE;
+				ptr->cmnd[1]         = 0;
+				ptr->cmnd[2]         = 0;
+				ptr->cmnd[3]         = 0;
+				ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
+				ptr->cmnd[5]         = 0;
+				ptr->cmd_len         = 6;
+				ptr->use_sg          = 0; 
+				ptr->request_buffer  = ptr->sense_buffer;
+				ptr->request_bufflen = sizeof(ptr->sense_buffer);
+			
+				DO_UNLOCK(flags);
+				aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
+				DO_LOCK(flags);
+#if 0
+			} else {
+				DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
+#endif
+			}
+		}
+
+		if(DONE_SC && DONE_SC->scsi_done) {
+#if defined(AHA152X_DEBUG)
+			int hostno=DONE_SC->device->host->host_no;
+			int id=DONE_SC->device->id & 0xf;
+			int lun=DONE_SC->device->lun & 0x7;
+#endif
+			Scsi_Cmnd *ptr = DONE_SC;
+			DONE_SC=NULL;
+
+			/* turn led off, when no commands are in the driver */
+			HOSTDATA(shpnt)->commands--;
+			if (!HOSTDATA(shpnt)->commands)
+				SETPORT(PORTA, 0);	/* turn led off */
+
+			if(ptr->scsi_done != reset_done) {
+				kfree(ptr->host_scribble);
+				ptr->host_scribble=NULL;
+			}
+
+			DO_UNLOCK(flags);
+			DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", hostno, id, lun, ptr);
+                	ptr->scsi_done(ptr);
+			DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", hostno, id, lun, ptr);
+			DO_LOCK(flags);
+		}
+
+		DONE_SC=NULL;
+#if defined(AHA152X_STAT)
+	} else {
+		HOSTDATA(shpnt)->busfree_without_done_command++;
+#endif
+	}
+
+	if(ISSUE_SC)
+		CURRENT_SC = remove_first_SC(&ISSUE_SC);
+
+	DO_UNLOCK(flags);
+
+	if(CURRENT_SC) {
+#if defined(AHA152X_STAT)
+		action++;
+#endif
+	    	CURRENT_SC->SCp.phase |= selecting;
+
+		DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
+
+		/* clear selection timeout */
+		SETPORT(SSTAT1, SELTO);
+
+		SETPORT(SCSIID, (shpnt->this_id << OID_) | CURRENT_SC->device->id);
+		SETPORT(SXFRCTL1, (PARITY ? ENSPCHK : 0 ) | ENSTIMER);
+		SETPORT(SCSISEQ, ENSELO | ENAUTOATNO | (DISCONNECTED_SC ? ENRESELI : 0));
+	} else {
+#if defined(AHA152X_STAT)
+		HOSTDATA(shpnt)->busfree_without_new_command++;
+#endif
+		SETPORT(SCSISEQ, DISCONNECTED_SC ? ENRESELI : 0);
+	}
+
+#if defined(AHA152X_STAT)
+	if(!action)
+		HOSTDATA(shpnt)->busfree_without_any_action++;
+#endif
+}
+
+/*
+ * Selection done (OUT)
+ * - queue IDENTIFY message and SDTR to selected target for message out
+ *   (ATN asserted automagically via ENAUTOATNO in busfree())
+ */
+static void seldo_run(struct Scsi_Host *shpnt)
+{
+	SETPORT(SCSISIG, 0);
+	SETPORT(SSTAT1, CLRBUSFREE);
+	SETPORT(SSTAT1, CLRPHASECHG);
+
+    	CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
+
+	SETPORT(SCSISEQ, 0);
+
+	if (TESTLO(SSTAT0, SELDO)) {
+		printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_NO_CONNECT << 16);
+		return;
+	}
+
+	SETPORT(SSTAT0, CLRSELDO);
+	
+	ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
+
+	if (CURRENT_SC->SCp.phase & aborting) {
+		ADDMSGO(ABORT);
+	} else if (CURRENT_SC->SCp.phase & resetting) {
+		ADDMSGO(BUS_DEVICE_RESET);
+	} else if (SYNCNEG==0 && SYNCHRONOUS) {
+    		CURRENT_SC->SCp.phase |= syncneg;
+		ADDMSGO(EXTENDED_MESSAGE);
+		ADDMSGO(3);
+		ADDMSGO(EXTENDED_SDTR);
+		ADDMSGO(50);		/* 200ns */
+		ADDMSGO(8);		/* 8 byte req/ack offset */
+
+		SYNCNEG=1;		/* negotiation in progress */
+	}
+
+	SETRATE(SYNCRATE);
+}
+
+/*
+ * Selection timeout
+ * - return command to mid-level with failure cause
+ *
+ */
+static void selto_run(struct Scsi_Host *shpnt)
+{
+	SETPORT(SCSISEQ, 0);		
+	SETPORT(SSTAT1, CLRSELTIMO);
+
+	DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
+
+	if(!CURRENT_SC) {
+		DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+    	CURRENT_SC->SCp.phase &= ~selecting;
+
+	if (CURRENT_SC->SCp.phase & aborted) {
+		DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_ABORT << 16);
+	} else if (TESTLO(SSTAT0, SELINGO)) {
+		DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_BUS_BUSY << 16);
+	} else {
+		/* ARBITRATION won, but SELECTION failed */
+		DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_NO_CONNECT << 16);
+	}
+}
+
+/*
+ * Selection in done
+ * - put current command back to issue queue
+ *   (reconnection of a disconnected nexus instead
+ *    of successful selection out)
+ *
+ */
+static void seldi_run(struct Scsi_Host *shpnt)
+{
+	int selid;
+	int target;
+	unsigned long flags;
+
+	SETPORT(SCSISIG, 0);
+	SETPORT(SSTAT0, CLRSELDI);
+	SETPORT(SSTAT1, CLRBUSFREE);
+	SETPORT(SSTAT1, CLRPHASECHG);
+
+	if(CURRENT_SC) {
+		if(!(CURRENT_SC->SCp.phase & not_issued))
+			printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
+
+		DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
+
+		DO_LOCK(flags);
+		append_SC(&ISSUE_SC, CURRENT_SC);
+		DO_UNLOCK(flags);
+
+		CURRENT_SC = NULL;
+	}
+
+	if(!DISCONNECTED_SC) {
+		DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+	RECONN_TARGET=-1;
+
+	selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
+
+	if (selid==0) {
+		printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+		return;
+	}
+
+	for(target=7; !(selid & (1 << target)); target--)
+		;
+
+	if(selid & ~(1 << target)) {
+		printk("aha152x%d: multiple targets reconnected (%02x)\n",
+		       HOSTNO, selid);
+	}
+
+
+	SETPORT(SCSIID, (shpnt->this_id << OID_) | target);
+	SETPORT(SCSISEQ, 0);
+
+	SETRATE(HOSTDATA(shpnt)->syncrate[target]);
+
+	RECONN_TARGET=target;
+	DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid);
+}
+
+/*
+ * message in phase
+ * - handle initial message after reconnection to identify
+ *   reconnecting nexus
+ * - queue command on DISCONNECTED_SC on DISCONNECT message
+ * - set completed flag on COMMAND COMPLETE
+ *   (other completition code moved to busfree_run)
+ * - handle response to SDTR
+ * - clear synchronous transfer agreements on BUS RESET
+ *
+ * FIXME: what about SAVE POINTERS, RESTORE POINTERS?
+ *
+ */
+static void msgi_run(struct Scsi_Host *shpnt)
+{
+	for(;;) {
+		int sstat1 = GETPORT(SSTAT1);
+
+		if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
+			return;
+
+		if(TESTLO(SSTAT0,SPIORDY)) {
+			DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}	
+
+		ADDMSGI(GETPORT(SCSIDAT));
+
+#if defined(AHA152X_DEBUG)
+		if (HOSTDATA(shpnt)->debug & debug_msgi) {
+			printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
+			print_msg(&MSGI(0));
+			printk("\n");
+		}
+#endif
+
+		if(!CURRENT_SC) {
+			if(LASTSTATE!=seldi) {
+				printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
+			}
+
+			/*
+	 	 	 * Handle reselection
+	 		 */
+			if(!(MSGI(0) & IDENTIFY_BASE)) {
+				printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+				continue;
+			}
+
+			CURRENT_SC = remove_lun_SC(&DISCONNECTED_SC, RECONN_TARGET, MSGI(0) & 0x3f);
+
+			if (!CURRENT_SC) {
+				show_queues(shpnt);
+				printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f);
+				continue;
+			}
+
+			DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.Message = MSGI(0);
+			CURRENT_SC->SCp.phase &= ~disconnected;
+
+			MSGILEN=0;
+
+			/* next message if any */
+			continue;
+		} 
+
+		CURRENT_SC->SCp.Message = MSGI(0);
+
+		switch (MSGI(0)) {
+		case DISCONNECT:
+			if (!RECONNECT)
+				printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.phase |= disconnected;
+			break;
+
+		case COMMAND_COMPLETE:
+			if(CURRENT_SC->SCp.phase & completed)
+				DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
+
+			CURRENT_SC->SCp.phase |= completed;
+			break;
+
+		case MESSAGE_REJECT:
+			if (SYNCNEG==1) {
+				printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+				SYNCNEG=2;	/* negotiation completed */
+			} else
+				printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC));
+			break;
+
+		case SAVE_POINTERS:
+			break;
+
+		case RESTORE_POINTERS:
+			break;
+
+		case EXTENDED_MESSAGE:
+			if(MSGILEN<2 || MSGILEN<MSGI(1)+2) {
+				/* not yet completed */
+				continue;
+			}
+
+			switch (MSGI(2)) {
+			case EXTENDED_SDTR:
+				{
+					long ticks;
+
+					if (MSGI(1) != 3) {
+						printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+						break;
+					}
+
+					if (!HOSTDATA(shpnt)->synchronous)
+						break;
+
+					printk(INFO_LEAD, CMDINFO(CURRENT_SC));
+					print_msg(&MSGI(0));
+					printk("\n");
+
+					ticks = (MSGI(3) * 4 + 49) / 50;
+
+					if (syncneg) {
+						/* negotiation in progress */
+						if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
+							ADDMSGO(MESSAGE_REJECT);
+							printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC));
+							break;
+						}
+						
+						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+					} else if (ticks <= 9 && MSGI(4) >= 1) {
+						ADDMSGO(EXTENDED_MESSAGE);
+						ADDMSGO(3);
+						ADDMSGO(EXTENDED_SDTR);
+						if (ticks < 4) {
+							ticks = 4;
+							ADDMSGO(50);
+						} else
+							ADDMSGO(MSGI(3));
+
+						if (MSGI(4) > 8)
+							MSGI(4) = 8;
+
+						ADDMSGO(MSGI(4));
+
+						SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
+					} else {
+						/* requested SDTR is too slow, do it asynchronously */
+						printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC));
+						ADDMSGO(MESSAGE_REJECT);
+					}
+
+					SYNCNEG=2;		/* negotiation completed */
+					SETRATE(SYNCRATE);
+				}
+				break;
+
+			case BUS_DEVICE_RESET:
+				{
+					int i;
+
+					for(i=0; i<8; i++) {
+						HOSTDATA(shpnt)->syncrate[i]=0;
+						HOSTDATA(shpnt)->syncneg[i]=0;
+					}
+
+				}
+				break;
+
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			case EXTENDED_WDTR:
+			default:
+				ADDMSGO(MESSAGE_REJECT);
+				break;
+			}
+			break;
+		}
+
+		MSGILEN=0;
+	}
+}
+
+static void msgi_end(struct Scsi_Host *shpnt)
+{
+	if(MSGILEN>0)
+		printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN);
+
+	if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
+		DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+		SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
+	} 
+}
+
+/*
+ * message out phase
+ *
+ */
+static void msgo_init(struct Scsi_Host *shpnt)
+{
+	if(MSGOLEN==0) {
+		if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
+			ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
+		} else {
+			printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+			ADDMSGO(MESSAGE_REJECT);
+		}
+	}
+
+#if defined(AHA152X_DEBUG)
+	if(HOSTDATA(shpnt)->debug & debug_msgo) {
+		int i;
+
+		printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
+		for (i=0; i<MSGOLEN; i+=print_msg(&MSGO(i)), printk(" "))
+			;
+		printk(")\n");
+	}
+#endif
+}
+
+/*
+ * message out phase
+ *
+ */
+static void msgo_run(struct Scsi_Host *shpnt)
+{
+	if(MSGO_I==MSGOLEN)
+		DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+
+	while(MSGO_I<MSGOLEN) {
+		DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
+
+		if(TESTLO(SSTAT0, SPIORDY)) {
+			DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}
+
+		if (MSGO_I==MSGOLEN-1) {
+			/* Leave MESSAGE OUT after transfer */
+			SETPORT(SSTAT1, CLRATNO);
+		}
+
+
+		if (MSGO(MSGO_I) & IDENTIFY_BASE)
+			CURRENT_SC->SCp.phase |= identified;
+
+		if (MSGO(MSGO_I)==ABORT)
+			CURRENT_SC->SCp.phase |= aborted;
+
+		if (MSGO(MSGO_I)==BUS_DEVICE_RESET)
+			CURRENT_SC->SCp.phase |= resetted;
+
+		SETPORT(SCSIDAT, MSGO(MSGO_I++));
+	}
+}
+
+static void msgo_end(struct Scsi_Host *shpnt)
+{
+	if(MSGO_I<MSGOLEN) {
+		printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+		if(SYNCNEG==1) {
+			printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+			SYNCNEG=2;
+		}
+	}
+		
+	MSGO_I  = 0;
+	MSGOLEN = 0;
+}
+
+/* 
+ * command phase
+ *
+ */
+static void cmd_init(struct Scsi_Host *shpnt)
+{
+	if (CURRENT_SC->SCp.sent_command) {
+		printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC));
+		done(shpnt, DID_ERROR << 16);
+		return;
+	}
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_cmd) {
+		printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
+		print_command(CURRENT_SC->cmnd);
+	}
+#endif
+
+	CMD_I=0;
+}
+
+/*
+ * command phase
+ *
+ */
+static void cmd_run(struct Scsi_Host *shpnt)
+{
+	if(CMD_I==CURRENT_SC->cmd_len) {
+		DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+		disp_ports(shpnt);
+	}
+
+	while(CMD_I<CURRENT_SC->cmd_len) {
+		DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len);
+
+		if(TESTLO(SSTAT0, SPIORDY)) {
+			DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+			return;
+		}
+
+		SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
+	}
+}
+
+static void cmd_end(struct Scsi_Host *shpnt)
+{
+	if(CMD_I<CURRENT_SC->cmd_len)
+		printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+	else
+		CURRENT_SC->SCp.sent_command++;
+}
+
+/*
+ * status phase
+ *
+ */
+static void status_run(struct Scsi_Host *shpnt)
+{
+	if(TESTLO(SSTAT0,SPIORDY)) {
+		DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+		return;
+	}
+
+	CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
+
+#if defined(AHA152X_DEBUG)
+	if (HOSTDATA(shpnt)->debug & debug_status) {
+		printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
+		print_status(CURRENT_SC->SCp.Status);
+		printk("\n");
+	}
+#endif
+}
+
+/*
+ * data in phase
+ *
+ */
+static void datai_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, RSTFIFO);
+	SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
+
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
+
+	DATA_LEN=0;
+	DPRINTK(debug_datai,
+		DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
+
+static void datai_run(struct Scsi_Host *shpnt)
+{
+	unsigned long the_time;
+	int fifodata, data_count;
+
+	/*
+	 * loop while the phase persists or the fifos are not empty
+	 *
+	 */
+	while(TESTLO(DMASTAT, INTSTAT) || TESTLO(DMASTAT, DFIFOEMP) || TESTLO(SSTAT2, SEMPTY)) {
+		/* FIXME: maybe this should be done by setting up
+		 * STCNT to trigger ENSWRAP interrupt, instead of
+		 * polling for DFIFOFULL
+		 */
+		the_time=jiffies + 100*HZ;
+		while(TESTLO(DMASTAT, DFIFOFULL|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
+
+		if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
+			printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
+		}
+
+		if(TESTHI(DMASTAT, DFIFOFULL)) {
+			fifodata = 128;
+		} else {
+			the_time=jiffies + 100*HZ;
+			while(TESTLO(SSTAT2, SEMPTY) && time_before(jiffies,the_time))
+				barrier();
+
+			if(TESTLO(SSTAT2, SEMPTY)) {
+				printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
+				disp_ports(shpnt);
+				break;
+			}
+
+			fifodata = GETPORT(FIFOSTAT);
+		}
+
+		if(CURRENT_SC->SCp.this_residual>0) {
+			while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
+                        	data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+						CURRENT_SC->SCp.this_residual :
+						fifodata;
+				fifodata -= data_count;
+
+                        	if(data_count & 1) {
+					DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
+                                	SETPORT(DMACNTRL0, ENDMA|_8BIT);
+                                	*CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+                                	CURRENT_SC->SCp.this_residual--;
+                                	DATA_LEN++;
+                                	SETPORT(DMACNTRL0, ENDMA);
+                        	}
+	
+                        	if(data_count > 1) {
+					DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
+                                	data_count >>= 1;
+                                	insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+                                	CURRENT_SC->SCp.ptr           += 2 * data_count;
+                                	CURRENT_SC->SCp.this_residual -= 2 * data_count;
+                                	DATA_LEN                      += 2 * data_count;
+                        	}
+	
+                        	if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+                               		/* advance to next buffer */
+                               		CURRENT_SC->SCp.buffers_residual--;
+                               		CURRENT_SC->SCp.buffer++;
+                               		CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+                               		CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+				} 
+                	}
+		} else if(fifodata>0) { 
+			printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
+                        SETPORT(DMACNTRL0, ENDMA|_8BIT);
+			while(fifodata>0) {
+				int data;
+				data=GETPORT(DATAPORT);
+				DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data);
+				fifodata--;
+				DATA_LEN++;
+			}
+                        SETPORT(DMACNTRL0, ENDMA|_8BIT);
+		}
+	}
+
+	if(TESTLO(DMASTAT, INTSTAT) ||
+	   TESTLO(DMASTAT, DFIFOEMP) ||
+	   TESTLO(SSTAT2, SEMPTY) ||
+	   GETPORT(FIFOSTAT)>0) {
+	   	/*
+		 * something went wrong, if there's something left in the fifos
+		 * or the phase didn't change
+		 */
+		printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC));
+		disp_ports(shpnt);
+	}
+
+	if(DATA_LEN!=GETSTCNT()) {
+		printk(ERR_LEAD
+		       "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)",
+		       CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT));
+		disp_ports(shpnt);
+		mdelay(10000);
+	}
+}
+
+static void datai_end(struct Scsi_Host *shpnt)
+{
+	CURRENT_SC->resid -= GETSTCNT();
+
+	DPRINTK(debug_datai,
+		DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(DMACNTRL0, 0);
+}
+
+/*
+ * data out phase
+ *
+ */
+static void datao_init(struct Scsi_Host *shpnt)
+{
+	SETPORT(DMACNTRL0, WRITE_READ | RSTFIFO);
+	SETPORT(DMACNTRL0, WRITE_READ | ENDMA);
+
+	SETPORT(SXFRCTL0, CH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN);
+
+	SETPORT(SIMODE0, 0);
+	SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
+
+	DATA_LEN = CURRENT_SC->resid;
+
+	DPRINTK(debug_datao,
+		DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
+		CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+}
+
+static void datao_run(struct Scsi_Host *shpnt)
+{
+	unsigned long the_time;
+	int data_count;
+
+	/* until phase changes or all data sent */
+	while(TESTLO(DMASTAT, INTSTAT) && CURRENT_SC->SCp.this_residual>0) {
+		data_count = 128;
+		if(data_count > CURRENT_SC->SCp.this_residual)
+			data_count=CURRENT_SC->SCp.this_residual;
+
+		if(TESTLO(DMASTAT, DFIFOEMP)) {
+			printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
+			disp_ports(shpnt);
+			break;
+		}
+
+		if(data_count & 1) {
+			SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
+			SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
+			CURRENT_SC->SCp.this_residual--;
+			CURRENT_SC->resid--;
+			SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
+		}
+
+		if(data_count > 1) {
+			data_count >>= 1;
+			outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+			CURRENT_SC->SCp.ptr           += 2 * data_count;
+			CURRENT_SC->SCp.this_residual -= 2 * data_count;
+			CURRENT_SC->resid             -= 2 * data_count;
+	  	}
+
+		if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
+			/* advance to next buffer */
+			CURRENT_SC->SCp.buffers_residual--;
+			CURRENT_SC->SCp.buffer++;
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+		}
+
+		the_time=jiffies + 100*HZ;
+		while(TESTLO(DMASTAT, DFIFOEMP|INTSTAT) && time_before(jiffies,the_time))
+			barrier();
+
+		if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
+			printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
+			disp_ports(shpnt);
+			break;
+		}
+	}
+}
+
+static void datao_end(struct Scsi_Host *shpnt)
+{
+	if(TESTLO(DMASTAT, DFIFOEMP)) {
+		int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+
+		DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
+			CMDINFO(CURRENT_SC),
+			data_count,
+			DATA_LEN-CURRENT_SC->resid,
+			GETSTCNT());
+
+		CURRENT_SC->resid += data_count;
+
+		if(CURRENT_SC->use_sg) {
+			data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
+			while(data_count>0) {
+				CURRENT_SC->SCp.buffer--;
+				CURRENT_SC->SCp.buffers_residual++;
+				data_count -= CURRENT_SC->SCp.buffer->length;
+			}
+			CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
+			CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
+		} else {
+			CURRENT_SC->SCp.ptr           -= data_count;
+			CURRENT_SC->SCp.this_residual += data_count;
+		}
+	}
+
+	DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
+		CMDINFO(CURRENT_SC),
+		CURRENT_SC->request_bufflen,
+		CURRENT_SC->resid,
+		GETSTCNT());
+
+	SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+	SETPORT(SXFRCTL0, CH1);
+
+	SETPORT(DMACNTRL0, 0);
+}
+
+/*
+ * figure out what state we're in
+ *
+ */
+static int update_state(struct Scsi_Host *shpnt)
+{
+	int dataphase=0;
+	unsigned int stat0 = GETPORT(SSTAT0);
+	unsigned int stat1 = GETPORT(SSTAT1);
+
+	PREVSTATE = STATE;
+	STATE=unknown;
+
+	if(stat1 & SCSIRSTI) {
+		STATE=rsti;
+		SETPORT(SCSISEQ,0);
+		SETPORT(SSTAT1,SCSIRSTI);
+  	} else if(stat0 & SELDI && PREVSTATE==busfree) {
+		STATE=seldi;
+	} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
+		STATE=seldo;
+	} else if(stat1 & SELTO) {
+		STATE=selto;
+	} else if(stat1 & BUSFREE) {
+		STATE=busfree;
+		SETPORT(SSTAT1,BUSFREE);
+	} else if(stat1 & SCSIPERR) {
+		STATE=parerr;
+		SETPORT(SSTAT1,SCSIPERR);
+	} else if(stat1 & REQINIT) {
+		switch(GETPORT(SCSISIG) & P_MASK) {
+		case P_MSGI:	STATE=msgi;	break;
+		case P_MSGO:	STATE=msgo;	break;
+		case P_DATAO:	STATE=datao;	break;
+		case P_DATAI:	STATE=datai;	break;
+		case P_STATUS:	STATE=status;	break;
+		case P_CMD:	STATE=cmd;	break;
+		}
+		dataphase=1;
+	}
+
+	if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
+		printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
+		disp_ports(shpnt);
+	}
+
+	if(STATE!=PREVSTATE) {
+		LASTSTATE=PREVSTATE;
+	}
+
+	return dataphase;
+}
+
+/*
+ * handle parity error
+ *
+ * FIXME: in which phase?
+ *
+ */
+static void parerr_run(struct Scsi_Host *shpnt)
+{
+	printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC));
+	done(shpnt, DID_PARITY << 16);
+}
+
+/*
+ * handle reset in
+ *
+ */
+static void rsti_run(struct Scsi_Host *shpnt)
+{
+	Scsi_Cmnd *ptr;
+
+	printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
+	
+	ptr=DISCONNECTED_SC;
+	while(ptr) {
+		Scsi_Cmnd *next = SCNEXT(ptr);
+
+		if (!ptr->device->soft_reset) {
+			remove_SC(&DISCONNECTED_SC, ptr);
+
+			kfree(ptr->host_scribble);
+			ptr->host_scribble=NULL;
+
+			ptr->result =  DID_RESET << 16;
+			ptr->scsi_done(ptr);
+		}
+
+		ptr = next;
+	}
+
+	if(CURRENT_SC && !CURRENT_SC->device->soft_reset)
+		done(shpnt, DID_RESET << 16 );
+}
+
+
+/*
+ * bottom-half handler
+ *
+ */
+static void is_complete(struct Scsi_Host *shpnt)
+{
+	int dataphase;
+	unsigned long flags;
+	int pending;
+
+	DO_LOCK(flags);
+	if(HOSTDATA(shpnt)->in_intr) {
+		DO_UNLOCK(flags);
+		/* aha152x_error never returns.. */
+		aha152x_error(shpnt, "bottom-half already running!?");
+	}
+	HOSTDATA(shpnt)->in_intr++;
+
+	/*
+	 * loop while there are interrupt conditions pending
+	 *
+	 */
+	do {
+		unsigned long start = jiffies;
+		DO_UNLOCK(flags);
+
+		dataphase=update_state(shpnt);
+
+		DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+
+		/*
+		 * end previous state
+		 *
+		 */
+		if(PREVSTATE!=STATE && states[PREVSTATE].end)
+			states[PREVSTATE].end(shpnt);
+
+		/*
+		 * disable SPIO mode if previous phase used it
+		 * and this one doesn't
+		 *
+		 */
+		if(states[PREVSTATE].spio && !states[STATE].spio) {
+			SETPORT(SXFRCTL0, CH1);
+			SETPORT(DMACNTRL0, 0);
+			if(CURRENT_SC)
+				CURRENT_SC->SCp.phase &= ~spiordy;
+		}
+
+		/*
+		 * accept current dataphase phase
+		 *
+		 */
+		if(dataphase) {
+			SETPORT(SSTAT0, REQINIT);
+			SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
+			SETPORT(SSTAT1, PHASECHG);  
+		}
+		
+		/*
+		 * enable SPIO mode if previous didn't use it
+		 * and this one does
+		 *
+		 */
+		if(!states[PREVSTATE].spio && states[STATE].spio) {
+			SETPORT(DMACNTRL0, 0);
+			SETPORT(SXFRCTL0, CH1|SPIOEN);
+			if(CURRENT_SC)
+				CURRENT_SC->SCp.phase |= spiordy;
+		}
+		
+		/*
+		 * initialize for new state
+		 *
+		 */
+		if(PREVSTATE!=STATE && states[STATE].init)
+			states[STATE].init(shpnt);
+		
+		/*
+		 * handle current state
+		 *
+		 */
+		if(states[STATE].run)
+			states[STATE].run(shpnt);
+		else
+			printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE);
+		
+		/*
+		 * setup controller to interrupt on
+		 * the next expected condition and
+		 * loop if it's already there
+		 *
+		 */
+		DO_LOCK(flags);
+		pending=setup_expected_interrupts(shpnt);
+#if defined(AHA152X_STAT)
+		HOSTDATA(shpnt)->count[STATE]++;
+		if(PREVSTATE!=STATE)
+			HOSTDATA(shpnt)->count_trans[STATE]++;
+		HOSTDATA(shpnt)->time[STATE] += jiffies-start;
+#endif
+
+		DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
+	} while(pending);
+
+	/*
+	 * enable interrupts and leave bottom-half
+	 *
+	 */
+	HOSTDATA(shpnt)->in_intr--;
+	SETBITS(DMACNTRL0, INTEN);
+	DO_UNLOCK(flags);
+}
+
+
+/* 
+ * Dump the current driver status and panic
+ */
+static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
+{
+	printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
+	show_queues(shpnt);
+	panic("aha152x panic\n");
+}
+
+/*
+ * Display registers of AIC-6260
+ */
+static void disp_ports(struct Scsi_Host *shpnt)
+{
+#if defined(AHA152X_DEBUG)
+	int s;
+
+	printk("\n%s: %s(%s) ",
+		CURRENT_SC ? "busy" : "waiting",
+		states[STATE].name,
+		states[PREVSTATE].name);
+
+	s = GETPORT(SCSISEQ);
+	printk("SCSISEQ( ");
+	if (s & TEMODEO)
+		printk("TARGET MODE ");
+	if (s & ENSELO)
+		printk("SELO ");
+	if (s & ENSELI)
+		printk("SELI ");
+	if (s & ENRESELI)
+		printk("RESELI ");
+	if (s & ENAUTOATNO)
+		printk("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		printk("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		printk("AUTOATNP ");
+	if (s & SCSIRSTO)
+		printk("SCSIRSTO ");
+	printk(");");
+
+	printk(" SCSISIG(");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		printk("DATA OUT");
+		break;
+	case P_DATAI:
+		printk("DATA IN");
+		break;
+	case P_CMD:
+		printk("COMMAND");
+		break;
+	case P_STATUS:
+		printk("STATUS");
+		break;
+	case P_MSGO:
+		printk("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		printk("MESSAGE IN");
+		break;
+	default:
+		printk("*invalid*");
+		break;
+	}
+
+	printk("); ");
+
+	printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+
+	printk("SSTAT( ");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+
+	printk("SSTAT( ");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		printk("TARGET ");
+	if (s & SELDO)
+		printk("SELDO ");
+	if (s & SELDI)
+		printk("SELDI ");
+	if (s & SELINGO)
+		printk("SELINGO ");
+	if (s & SWRAP)
+		printk("SWRAP ");
+	if (s & SDONE)
+		printk("SDONE ");
+	if (s & SPIORDY)
+		printk("SPIORDY ");
+	if (s & DMADONE)
+		printk("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		printk("SELTO ");
+	if (s & ATNTARG)
+		printk("ATNTARG ");
+	if (s & SCSIRSTI)
+		printk("SCSIRSTI ");
+	if (s & PHASEMIS)
+		printk("PHASEMIS ");
+	if (s & BUSFREE)
+		printk("BUSFREE ");
+	if (s & SCSIPERR)
+		printk("SCSIPERR ");
+	if (s & PHASECHG)
+		printk("PHASECHG ");
+	if (s & REQINIT)
+		printk("REQINIT ");
+	printk("); ");
+
+	printk("SXFRCTL0( ");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		printk("SCSIEN ");
+	if (s & DMAEN)
+		printk("DMAEN ");
+	if (s & CH1)
+		printk("CH1 ");
+	if (s & CLRSTCNT)
+		printk("CLRSTCNT ");
+	if (s & SPIOEN)
+		printk("SPIOEN ");
+	if (s & CLRCH1)
+		printk("CLRCH1 ");
+	printk("); ");
+
+	printk("SIGNAL( ");
+
+	s = GETPORT(SCSISIG);
+	if (s & SIG_ATNI)
+		printk("ATNI ");
+	if (s & SIG_SELI)
+		printk("SELI ");
+	if (s & SIG_BSYI)
+		printk("BSYI ");
+	if (s & SIG_REQI)
+		printk("REQI ");
+	if (s & SIG_ACKI)
+		printk("ACKI ");
+	printk("); ");
+
+	printk("SELID (%02x), ", GETPORT(SELID));
+
+	printk("STCNT (%d), ", GETSTCNT());
+	
+	printk("SSTAT2( ");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		printk("SOFFSET ");
+	if (s & SEMPTY)
+		printk("SEMPTY ");
+	if (s & SFULL)
+		printk("SFULL ");
+	printk("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	printk("SSTAT4( ");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		printk("SYNCERR ");
+	if (s & FWERR)
+		printk("FWERR ");
+	if (s & FRERR)
+		printk("FRERR ");
+	printk("); ");
+
+	printk("DMACNTRL0( ");
+	s = GETPORT(DMACNTRL0);
+	printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	printk("%s ", s & DMA ? "DMA" : "PIO");
+	printk("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		printk("ENDMA ");
+	if (s & INTEN)
+		printk("INTEN ");
+	if (s & RSTFIFO)
+		printk("RSTFIFO ");
+	if (s & SWINT)
+		printk("SWINT ");
+	printk("); ");
+
+	printk("DMASTAT( ");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		printk("ATDONE ");
+	if (s & WORDRDY)
+		printk("WORDRDY ");
+	if (s & DFIFOFULL)
+		printk("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		printk("DFIFOEMP ");
+	printk(")\n");
+#endif
+}
+
+/*
+ * display enabled interrupts
+ */
+static void disp_enintr(struct Scsi_Host *shpnt)
+{
+	int s;
+
+	printk(KERN_DEBUG "enabled interrupts ( ");
+
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		printk("ENSELDO ");
+	if (s & ENSELDI)
+		printk("ENSELDI ");
+	if (s & ENSELINGO)
+		printk("ENSELINGO ");
+	if (s & ENSWRAP)
+		printk("ENSWRAP ");
+	if (s & ENSDONE)
+		printk("ENSDONE ");
+	if (s & ENSPIORDY)
+		printk("ENSPIORDY ");
+	if (s & ENDMADONE)
+		printk("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		printk("ENSELTIMO ");
+	if (s & ENATNTARG)
+		printk("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		printk("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		printk("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		printk("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		printk("ENPHASECHG ");
+	if (s & ENREQINIT)
+		printk("ENREQINIT ");
+	printk(")\n");
+}
+
+/*
+ * Show the command data of a command
+ */
+static void show_command(Scsi_Cmnd *ptr)
+{
+	printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
+	       (unsigned int) ptr, ptr->device->id, ptr->device->lun);
+
+	print_command(ptr->cmnd);
+
+	printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
+	       ptr->request_bufflen, ptr->resid);
+
+	if (ptr->SCp.phase & not_issued)
+		printk("not issued|");
+	if (ptr->SCp.phase & selecting)
+		printk("selecting|");
+	if (ptr->SCp.phase & identified)
+		printk("identified|");
+	if (ptr->SCp.phase & disconnected)
+		printk("disconnected|");
+	if (ptr->SCp.phase & completed)
+		printk("completed|");
+	if (ptr->SCp.phase & spiordy)
+		printk("spiordy|");
+	if (ptr->SCp.phase & syncneg)
+		printk("syncneg|");
+	if (ptr->SCp.phase & aborted)
+		printk("aborted|");
+	if (ptr->SCp.phase & resetted)
+		printk("resetted|");
+	if( SCDATA(ptr) ) {
+		printk("; next=0x%p\n", SCNEXT(ptr));
+	} else {
+		printk("; next=(host scribble NULL)\n");
+	}
+}
+
+/*
+ * Dump the queued data
+ */
+static void show_queues(struct Scsi_Host *shpnt)
+{
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+
+	DO_LOCK(flags);
+	printk(KERN_DEBUG "\nqueue status:\nissue_SC:\n");
+	for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
+		show_command(ptr);
+	DO_UNLOCK(flags);
+
+	printk(KERN_DEBUG "current_SC:\n");
+	if (CURRENT_SC)
+		show_command(CURRENT_SC);
+	else
+		printk(KERN_DEBUG "none\n");
+
+	printk(KERN_DEBUG "disconnected_SC:\n");
+	for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
+		show_command(ptr);
+
+	disp_ports(shpnt);
+	disp_enintr(shpnt);
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, ## args)
+
+static int get_command(char *pos, Scsi_Cmnd * ptr)
+{
+	char *start = pos;
+	int i;
+
+	SPRINTF("0x%08x: target=%d; lun=%d; cmnd=( ",
+		(unsigned int) ptr, ptr->device->id, ptr->device->lun);
+
+	for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
+		SPRINTF("0x%02x ", ptr->cmnd[i]);
+
+	SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
+		ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+	if (ptr->SCp.phase & not_issued)
+		SPRINTF("not issued|");
+	if (ptr->SCp.phase & selecting)
+		SPRINTF("selecting|");
+	if (ptr->SCp.phase & disconnected)
+		SPRINTF("disconnected|");
+	if (ptr->SCp.phase & aborted)
+		SPRINTF("aborted|");
+	if (ptr->SCp.phase & identified)
+		SPRINTF("identified|");
+	if (ptr->SCp.phase & completed)
+		SPRINTF("completed|");
+	if (ptr->SCp.phase & spiordy)
+		SPRINTF("spiordy|");
+	if (ptr->SCp.phase & syncneg)
+		SPRINTF("syncneg|");
+	SPRINTF("; next=0x%p\n", SCNEXT(ptr));
+
+	return (pos - start);
+}
+
+static int get_ports(struct Scsi_Host *shpnt, char *pos)
+{
+	char *start = pos;
+	int s;
+
+	SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
+
+	s = GETPORT(SCSISEQ);
+	SPRINTF("SCSISEQ( ");
+	if (s & TEMODEO)
+		SPRINTF("TARGET MODE ");
+	if (s & ENSELO)
+		SPRINTF("SELO ");
+	if (s & ENSELI)
+		SPRINTF("SELI ");
+	if (s & ENRESELI)
+		SPRINTF("RESELI ");
+	if (s & ENAUTOATNO)
+		SPRINTF("AUTOATNO ");
+	if (s & ENAUTOATNI)
+		SPRINTF("AUTOATNI ");
+	if (s & ENAUTOATNP)
+		SPRINTF("AUTOATNP ");
+	if (s & SCSIRSTO)
+		SPRINTF("SCSIRSTO ");
+	SPRINTF(");");
+
+	SPRINTF(" SCSISIG(");
+	s = GETPORT(SCSISIG);
+	switch (s & P_MASK) {
+	case P_DATAO:
+		SPRINTF("DATA OUT");
+		break;
+	case P_DATAI:
+		SPRINTF("DATA IN");
+		break;
+	case P_CMD:
+		SPRINTF("COMMAND");
+		break;
+	case P_STATUS:
+		SPRINTF("STATUS");
+		break;
+	case P_MSGO:
+		SPRINTF("MESSAGE OUT");
+		break;
+	case P_MSGI:
+		SPRINTF("MESSAGE IN");
+		break;
+	default:
+		SPRINTF("*invalid*");
+		break;
+	}
+
+	SPRINTF("); ");
+
+	SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+
+	SPRINTF("SSTAT( ");
+	s = GETPORT(SSTAT0);
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1);
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+
+	SPRINTF("SSTAT( ");
+
+	s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+	if (s & TARGET)
+		SPRINTF("TARGET ");
+	if (s & SELDO)
+		SPRINTF("SELDO ");
+	if (s & SELDI)
+		SPRINTF("SELDI ");
+	if (s & SELINGO)
+		SPRINTF("SELINGO ");
+	if (s & SWRAP)
+		SPRINTF("SWRAP ");
+	if (s & SDONE)
+		SPRINTF("SDONE ");
+	if (s & SPIORDY)
+		SPRINTF("SPIORDY ");
+	if (s & DMADONE)
+		SPRINTF("DMADONE ");
+
+	s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+	if (s & SELTO)
+		SPRINTF("SELTO ");
+	if (s & ATNTARG)
+		SPRINTF("ATNTARG ");
+	if (s & SCSIRSTI)
+		SPRINTF("SCSIRSTI ");
+	if (s & PHASEMIS)
+		SPRINTF("PHASEMIS ");
+	if (s & BUSFREE)
+		SPRINTF("BUSFREE ");
+	if (s & SCSIPERR)
+		SPRINTF("SCSIPERR ");
+	if (s & PHASECHG)
+		SPRINTF("PHASECHG ");
+	if (s & REQINIT)
+		SPRINTF("REQINIT ");
+	SPRINTF("); ");
+
+	SPRINTF("SXFRCTL0( ");
+
+	s = GETPORT(SXFRCTL0);
+	if (s & SCSIEN)
+		SPRINTF("SCSIEN ");
+	if (s & DMAEN)
+		SPRINTF("DMAEN ");
+	if (s & CH1)
+		SPRINTF("CH1 ");
+	if (s & CLRSTCNT)
+		SPRINTF("CLRSTCNT ");
+	if (s & SPIOEN)
+		SPRINTF("SPIOEN ");
+	if (s & CLRCH1)
+		SPRINTF("CLRCH1 ");
+	SPRINTF("); ");
+
+	SPRINTF("SIGNAL( ");
+
+	s = GETPORT(SCSISIG);
+	if (s & SIG_ATNI)
+		SPRINTF("ATNI ");
+	if (s & SIG_SELI)
+		SPRINTF("SELI ");
+	if (s & SIG_BSYI)
+		SPRINTF("BSYI ");
+	if (s & SIG_REQI)
+		SPRINTF("REQI ");
+	if (s & SIG_ACKI)
+		SPRINTF("ACKI ");
+	SPRINTF("); ");
+
+	SPRINTF("SELID(%02x), ", GETPORT(SELID));
+
+	SPRINTF("STCNT(%d), ", GETSTCNT());
+
+	SPRINTF("SSTAT2( ");
+
+	s = GETPORT(SSTAT2);
+	if (s & SOFFSET)
+		SPRINTF("SOFFSET ");
+	if (s & SEMPTY)
+		SPRINTF("SEMPTY ");
+	if (s & SFULL)
+		SPRINTF("SFULL ");
+	SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT));
+
+	s = GETPORT(SSTAT3);
+	SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+
+	SPRINTF("SSTAT4( ");
+	s = GETPORT(SSTAT4);
+	if (s & SYNCERR)
+		SPRINTF("SYNCERR ");
+	if (s & FWERR)
+		SPRINTF("FWERR ");
+	if (s & FRERR)
+		SPRINTF("FRERR ");
+	SPRINTF("); ");
+
+	SPRINTF("DMACNTRL0( ");
+	s = GETPORT(DMACNTRL0);
+	SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
+	SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
+	SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ");
+	if (s & ENDMA)
+		SPRINTF("ENDMA ");
+	if (s & INTEN)
+		SPRINTF("INTEN ");
+	if (s & RSTFIFO)
+		SPRINTF("RSTFIFO ");
+	if (s & SWINT)
+		SPRINTF("SWINT ");
+	SPRINTF("); ");
+
+	SPRINTF("DMASTAT( ");
+	s = GETPORT(DMASTAT);
+	if (s & ATDONE)
+		SPRINTF("ATDONE ");
+	if (s & WORDRDY)
+		SPRINTF("WORDRDY ");
+	if (s & DFIFOFULL)
+		SPRINTF("DFIFOFULL ");
+	if (s & DFIFOEMP)
+		SPRINTF("DFIFOEMP ");
+	SPRINTF(")\n");
+
+	SPRINTF("enabled interrupts( ");
+
+	s = GETPORT(SIMODE0);
+	if (s & ENSELDO)
+		SPRINTF("ENSELDO ");
+	if (s & ENSELDI)
+		SPRINTF("ENSELDI ");
+	if (s & ENSELINGO)
+		SPRINTF("ENSELINGO ");
+	if (s & ENSWRAP)
+		SPRINTF("ENSWRAP ");
+	if (s & ENSDONE)
+		SPRINTF("ENSDONE ");
+	if (s & ENSPIORDY)
+		SPRINTF("ENSPIORDY ");
+	if (s & ENDMADONE)
+		SPRINTF("ENDMADONE ");
+
+	s = GETPORT(SIMODE1);
+	if (s & ENSELTIMO)
+		SPRINTF("ENSELTIMO ");
+	if (s & ENATNTARG)
+		SPRINTF("ENATNTARG ");
+	if (s & ENPHASEMIS)
+		SPRINTF("ENPHASEMIS ");
+	if (s & ENBUSFREE)
+		SPRINTF("ENBUSFREE ");
+	if (s & ENSCSIPERR)
+		SPRINTF("ENSCSIPERR ");
+	if (s & ENPHASECHG)
+		SPRINTF("ENPHASECHG ");
+	if (s & ENREQINIT)
+		SPRINTF("ENREQINIT ");
+	SPRINTF(")\n");
+
+	return (pos - start);
+}
+
+static int aha152x_set_info(char *buffer, int length, struct Scsi_Host *shpnt)
+{
+	if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
+		return -EINVAL;
+
+#if defined(AHA152X_DEBUG)
+	if(length>14 && strncmp("debug ", buffer+8, 6)==0) {
+		int debug = HOSTDATA(shpnt)->debug;
+
+		HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0);
+
+		printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug);
+	} else
+#endif
+#if defined(AHA152X_STAT)
+	if(length>13 && strncmp("reset", buffer+8, 5)==0) {
+		int i;
+
+		HOSTDATA(shpnt)->total_commands=0;
+		HOSTDATA(shpnt)->disconnections=0;
+		HOSTDATA(shpnt)->busfree_without_any_action=0;
+		HOSTDATA(shpnt)->busfree_without_old_command=0;
+		HOSTDATA(shpnt)->busfree_without_new_command=0;
+		HOSTDATA(shpnt)->busfree_without_done_command=0;
+		HOSTDATA(shpnt)->busfree_with_check_condition=0;
+		for (i = idle; i<maxstate; i++) {
+			HOSTDATA(shpnt)->count[i]=0;
+			HOSTDATA(shpnt)->count_trans[i]=0;
+			HOSTDATA(shpnt)->time[i]=0;
+		}
+
+		printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO);
+
+	} else
+#endif
+	{
+		return -EINVAL;
+	}
+
+
+	return length;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+	do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0)
+
+static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start,
+		      off_t offset, int length, int inout)
+{
+	int i;
+	char *pos = buffer;
+	Scsi_Cmnd *ptr;
+	unsigned long flags;
+	int thislength;
+
+	DPRINTK(debug_procinfo, 
+	       KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n",
+	       buffer, offset, length, shpnt->host_no, inout);
+
+
+	if (inout)
+		return aha152x_set_info(buffer, length, shpnt);
+
+	SPRINTF(AHA152X_REVID "\n");
+
+	SPRINTF("ioports 0x%04lx to 0x%04lx\n",
+		shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
+	SPRINTF("interrupt 0x%02x\n", shpnt->irq);
+	SPRINTF("disconnection/reconnection %s\n",
+		RECONNECT ? "enabled" : "disabled");
+	SPRINTF("parity checking %s\n",
+		PARITY ? "enabled" : "disabled");
+	SPRINTF("synchronous transfers %s\n",
+		SYNCHRONOUS ? "enabled" : "disabled");
+	SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
+
+	if(SYNCHRONOUS) {
+		SPRINTF("synchronously operating targets (tick=50 ns):\n");
+		for (i = 0; i < 8; i++)
+			if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
+				SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
+					i,
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
+					(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
+				    HOSTDATA(shpnt)->syncrate[i] & 0x0f);
+	}
+#if defined(AHA152X_DEBUG)
+#define PDEBUG(flags,txt) \
+	if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
+
+	SPRINTF("enabled debugging options: ");
+
+	PDEBUG(debug_procinfo, "procinfo");
+	PDEBUG(debug_queue, "queue");
+	PDEBUG(debug_intr, "interrupt");
+	PDEBUG(debug_selection, "selection");
+	PDEBUG(debug_msgo, "message out");
+	PDEBUG(debug_msgi, "message in");
+	PDEBUG(debug_status, "status");
+	PDEBUG(debug_cmd, "command");
+	PDEBUG(debug_datai, "data in");
+	PDEBUG(debug_datao, "data out");
+	PDEBUG(debug_eh, "eh");
+	PDEBUG(debug_locks, "locks");
+	PDEBUG(debug_phases, "phases");
+
+	SPRINTF("\n");
+#endif
+
+	SPRINTF("\nqueue status:\n");
+	DO_LOCK(flags);
+	if (ISSUE_SC) {
+		SPRINTF("not yet issued commands:\n");
+		for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no not yet issued commands\n");
+	DO_UNLOCK(flags);
+
+	if (CURRENT_SC) {
+		SPRINTF("current command:\n");
+		pos += get_command(pos, CURRENT_SC);
+	} else
+		SPRINTF("no current command\n");
+
+	if (DISCONNECTED_SC) {
+		SPRINTF("disconnected commands:\n");
+		for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
+			pos += get_command(pos, ptr);
+	} else
+		SPRINTF("no disconnected commands\n");
+
+	pos += get_ports(shpnt, pos);
+
+#if defined(AHA152X_STAT)
+	SPRINTF("statistics:\n"
+	        "total commands:               %d\n"
+	        "disconnections:               %d\n"
+		"busfree with check condition: %d\n"
+		"busfree without old command:  %d\n"
+		"busfree without new command:  %d\n"
+		"busfree without done command: %d\n"
+		"busfree without any action:   %d\n"
+		"state      "
+		"transitions  "
+		"count        "
+		"time\n",
+		HOSTDATA(shpnt)->total_commands,
+		HOSTDATA(shpnt)->disconnections,
+		HOSTDATA(shpnt)->busfree_with_check_condition,
+		HOSTDATA(shpnt)->busfree_without_old_command,
+		HOSTDATA(shpnt)->busfree_without_new_command,
+		HOSTDATA(shpnt)->busfree_without_done_command,
+		HOSTDATA(shpnt)->busfree_without_any_action);
+	for(i=0; i<maxstate; i++) {
+		SPRINTF("%-10s %-12d %-12d %-12ld\n",
+		        states[i].name,
+			HOSTDATA(shpnt)->count_trans[i],
+			HOSTDATA(shpnt)->count[i],
+			HOSTDATA(shpnt)->time[i]);
+	}
+#endif
+
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: pos=%p\n", pos);
+
+	thislength = pos - (buffer + offset);
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: length=%d thislength=%d\n", length, thislength);
+
+	if(thislength<0) {
+		DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: output too short\n");
+		*start = NULL;
+		return 0;
+	}
+
+	thislength = thislength<length ? thislength : length;
+
+	DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: return %d\n", thislength);
+
+	*start = buffer + offset;
+	return thislength < length ? thislength : length;
+}
+
+static Scsi_Host_Template aha152x_driver_template = {
+	.module				= THIS_MODULE,
+	.name				= AHA152X_REVID,
+	.proc_name			= "aha152x",
+	.proc_info			= aha152x_proc_info,
+	.queuecommand			= aha152x_queue,
+	.eh_abort_handler		= aha152x_abort,
+	.eh_device_reset_handler	= aha152x_device_reset,
+	.eh_bus_reset_handler		= aha152x_bus_reset,
+	.eh_host_reset_handler		= aha152x_host_reset,
+	.bios_param			= aha152x_biosparam,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+};
+
+#if !defined(PCMCIA)
+static int setup_count;
+static struct aha152x_setup setup[2];
+
+/* possible i/o addresses for the AIC-6260; default first */
+static unsigned short ports[] = { 0x340, 0x140 };
+
+#if !defined(SKIP_BIOSTEST)
+/* possible locations for the Adaptec BIOS; defaults first */
+static unsigned int addresses[] =
+{
+	0xdc000,		/* default first */
+	0xc8000,
+	0xcc000,
+	0xd0000,
+	0xd4000,
+	0xd8000,
+	0xe0000,
+	0xeb800,		/* VTech Platinum SMP */
+	0xf0000,
+};
+
+/* signatures for various AIC-6[23]60 based controllers.
+   The point in detecting signatures is to avoid useless and maybe
+   harmful probes on ports. I'm not sure that all listed boards pass
+   auto-configuration. For those which fail the BIOS signature is
+   obsolete, because user intervention to supply the configuration is
+   needed anyway.  May be an information whether or not the BIOS supports
+   extended translation could be also useful here. */
+static struct signature {
+	unsigned char *signature;
+	int sig_offset;
+	int sig_length;
+} signatures[] =
+{
+	{ "Adaptec AHA-1520 BIOS",	0x102e, 21 },
+		/* Adaptec 152x */
+	{ "Adaptec AHA-1520B",		0x000b, 17 },
+		/* Adaptec 152x rev B */
+	{ "Adaptec AHA-1520B",		0x0026, 17 },
+		/* Iomega Jaz Jet ISA (AIC6370Q) */
+	{ "Adaptec ASW-B626 BIOS",	0x1029, 21 },
+		/* on-board controller */
+	{ "Adaptec BIOS: ASW-B626",	0x000f, 22 },
+		/* on-board controller */
+	{ "Adaptec ASW-B626 S2",	0x2e6c, 19 },
+		/* on-board controller */
+	{ "Adaptec BIOS:AIC-6360",	0x000c, 21 },
+		/* on-board controller */
+	{ "ScsiPro SP-360 BIOS",	0x2873, 19 },
+		/* ScsiPro-Controller  */
+	{ "GA-400 LOCAL BUS SCSI BIOS", 0x102e, 26 },
+		/* Gigabyte Local-Bus-SCSI */
+	{ "Adaptec BIOS:AVA-282X",	0x000c, 21 },
+		/* Adaptec 282x */
+	{ "Adaptec IBM Dock II SCSI",   0x2edd, 24 },
+		/* IBM Thinkpad Dock II */
+	{ "Adaptec BIOS:AHA-1532P",     0x001c, 22 },
+		/* IBM Thinkpad Dock II SCSI */
+	{ "DTC3520A Host Adapter BIOS", 0x318a, 26 },
+		/* DTC 3520A ISA SCSI */
+};
+#endif /* !SKIP_BIOSTEST */
+
+/*
+ * Test, if port_base is valid.
+ *
+ */
+static int aha152x_porttest(int io_port)
+{
+	int i;
+
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16; i++)
+		SETPORT(io_port + O_STACK, i);
+
+	SETPORT(io_port + O_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16 && GETPORT(io_port + O_STACK) == i; i++)
+		;
+
+	return (i == 16);
+}
+
+static int tc1550_porttest(int io_port)
+{
+	int i;
+
+	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16; i++)
+		SETPORT(io_port + O_STACK, i);
+
+	SETPORT(io_port + O_TC_DMACNTRL1, 0);	/* reset stack pointer */
+	for (i = 0; i < 16 && GETPORT(io_port + O_TC_STACK) == i; i++)
+		;
+
+	return (i == 16);
+}
+
+
+static int checksetup(struct aha152x_setup *setup)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(ports) && (setup->io_port != ports[i]); i++)
+		;
+
+	if (i == ARRAY_SIZE(ports))
+		return 0;
+
+	if ( request_region(setup->io_port, IO_RANGE, "aha152x")==0 ) {
+		printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
+		return 0;
+	}
+
+	if( aha152x_porttest(setup->io_port) ) {
+		setup->tc1550=0;
+	} else if( tc1550_porttest(setup->io_port) ) {
+		setup->tc1550=1;
+	} else {
+		release_region(setup->io_port, IO_RANGE);
+		return 0;
+	}
+
+	release_region(setup->io_port, IO_RANGE);
+
+	if ((setup->irq < IRQ_MIN) || (setup->irq > IRQ_MAX))
+		return 0;
+
+	if ((setup->scsiid < 0) || (setup->scsiid > 7))
+		return 0;
+
+	if ((setup->reconnect < 0) || (setup->reconnect > 1))
+		return 0;
+
+	if ((setup->parity < 0) || (setup->parity > 1))
+		return 0;
+
+	if ((setup->synchronous < 0) || (setup->synchronous > 1))
+		return 0;
+
+	if ((setup->ext_trans < 0) || (setup->ext_trans > 1))
+		return 0;
+
+
+	return 1;
+}
+
+
+static int __init aha152x_init(void)
+{
+	int i, j, ok;
+#if defined(AUTOCONF)
+	aha152x_config conf;
+#endif
+#ifdef __ISAPNP__
+	struct pnp_dev *dev=NULL, *pnpdev[2] = {NULL, NULL};
+#endif
+
+	if ( setup_count ) {
+		printk(KERN_INFO "aha152x: processing commandline: ");
+
+		for (i = 0; i<setup_count; i++) {
+			if (!checksetup(&setup[i])) {
+				printk(KERN_ERR "\naha152x: %s\n", setup[i].conf);
+				printk(KERN_ERR "aha152x: invalid line\n");
+			}
+		}
+		printk("ok\n");
+	}
+
+#if defined(SETUP0)
+	if (setup_count < ARRAY_SIZE(setup)) {
+		struct aha152x_setup override = SETUP0;
+
+		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
+			if (!checksetup(&override)) {
+				printk(KERN_ERR "\naha152x: invalid override SETUP0={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+		}
+	}
+#endif
+
+#if defined(SETUP1)
+	if (setup_count < ARRAY_SIZE(setup)) {
+		struct aha152x_setup override = SETUP1;
+
+		if (setup_count == 0 || (override.io_port != setup[0].io_port)) {
+			if (!checksetup(&override)) {
+				printk(KERN_ERR "\naha152x: invalid override SETUP1={0x%x,%d,%d,%d,%d,%d,%d,%d}\n",
+				       override.io_port,
+				       override.irq,
+				       override.scsiid,
+				       override.reconnect,
+				       override.parity,
+				       override.synchronous,
+				       override.delay,
+				       override.ext_trans);
+			} else
+				setup[setup_count++] = override;
+		}
+	}
+#endif
+
+#if defined(MODULE)
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x[0]!=0 || io[0]!=0 || irq[0]!=0)) {
+		if(aha152x[0]!=0) {
+			setup[setup_count].conf        = "";
+			setup[setup_count].io_port     = aha152x[0];
+			setup[setup_count].irq         = aha152x[1];
+			setup[setup_count].scsiid      = aha152x[2];
+			setup[setup_count].reconnect   = aha152x[3];
+			setup[setup_count].parity      = aha152x[4];
+			setup[setup_count].synchronous = aha152x[5];
+			setup[setup_count].delay       = aha152x[6];
+			setup[setup_count].ext_trans   = aha152x[7];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = aha152x[8];
+#endif
+	  	} else if(io[0]!=0 || irq[0]!=0) {
+			if(io[0]!=0)  setup[setup_count].io_port = io[0];
+			if(irq[0]!=0) setup[setup_count].irq     = irq[0];
+
+	    		setup[setup_count].scsiid      = scsiid[0];
+	    		setup[setup_count].reconnect   = reconnect[0];
+	    		setup[setup_count].parity      = parity[0];
+	    		setup[setup_count].synchronous = sync[0];
+	    		setup[setup_count].delay       = delay[0];
+	    		setup[setup_count].ext_trans   = exttrans[0];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = debug[0];
+#endif
+		}
+
+          	if (checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
+
+	if (setup_count<ARRAY_SIZE(setup) && (aha152x1[0]!=0 || io[1]!=0 || irq[1]!=0)) {
+		if(aha152x1[0]!=0) {
+			setup[setup_count].conf        = "";
+			setup[setup_count].io_port     = aha152x1[0];
+			setup[setup_count].irq         = aha152x1[1];
+			setup[setup_count].scsiid      = aha152x1[2];
+			setup[setup_count].reconnect   = aha152x1[3];
+			setup[setup_count].parity      = aha152x1[4];
+			setup[setup_count].synchronous = aha152x1[5];
+			setup[setup_count].delay       = aha152x1[6];
+			setup[setup_count].ext_trans   = aha152x1[7];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = aha152x1[8];
+#endif
+	  	} else if(io[1]!=0 || irq[1]!=0) {
+			if(io[1]!=0)  setup[setup_count].io_port = io[1];
+			if(irq[1]!=0) setup[setup_count].irq     = irq[1];
+
+	    		setup[setup_count].scsiid      = scsiid[1];
+	    		setup[setup_count].reconnect   = reconnect[1];
+	    		setup[setup_count].parity      = parity[1];
+	    		setup[setup_count].synchronous = sync[1];
+	    		setup[setup_count].delay       = delay[1];
+	    		setup[setup_count].ext_trans   = exttrans[1];
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = debug[1];
+#endif
+		}
+		if (checksetup(&setup[setup_count]))
+			setup_count++;
+		else
+			printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
+			       setup[setup_count].io_port,
+			       setup[setup_count].irq,
+			       setup[setup_count].scsiid,
+			       setup[setup_count].reconnect,
+			       setup[setup_count].parity,
+			       setup[setup_count].synchronous,
+			       setup[setup_count].delay,
+			       setup[setup_count].ext_trans);
+	}
+#endif
+
+#ifdef __ISAPNP__
+	for(i=0; setup_count<ARRAY_SIZE(setup) && id_table[i].vendor; i++) {
+		while ( setup_count<ARRAY_SIZE(setup) &&
+			(dev=pnp_find_dev(NULL, id_table[i].vendor, id_table[i].function, dev)) ) {
+			if (pnp_device_attach(dev) < 0)
+				continue;
+
+			if (pnp_activate_dev(dev) < 0) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			if (!pnp_port_valid(dev, 0)) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			if (setup_count==1 && pnp_port_start(dev, 0)==setup[0].io_port) {
+				pnp_device_detach(dev);
+				continue;
+			}
+
+			setup[setup_count].io_port     = pnp_port_start(dev, 0);
+			setup[setup_count].irq         = pnp_irq(dev, 0);
+			setup[setup_count].scsiid      = 7;
+			setup[setup_count].reconnect   = 1;
+			setup[setup_count].parity      = 1;
+			setup[setup_count].synchronous = 1;
+			setup[setup_count].delay       = DELAY_DEFAULT;
+			setup[setup_count].ext_trans   = 0;
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug       = DEBUG_DEFAULT;
+#endif
+#if defined(__ISAPNP__)
+			pnpdev[setup_count]            = dev;
+#endif
+			printk (KERN_INFO
+				"aha152x: found ISAPnP adapter at io=0x%03x, irq=%d\n",
+				setup[setup_count].io_port, setup[setup_count].irq);
+			setup_count++;
+		}
+	}
+#endif
+
+#if defined(AUTOCONF)
+	if (setup_count<ARRAY_SIZE(setup)) {
+#if !defined(SKIP_BIOSTEST)
+		ok = 0;
+		for (i = 0; i < ARRAY_SIZE(addresses) && !ok; i++) {
+			void __iomem *p = ioremap(addresses[i], 0x4000);
+			if (!p)
+				continue;
+			for (j = 0; j<ARRAY_SIZE(signatures) && !ok; j++)
+				ok = check_signature(p + signatures[j].sig_offset,
+								signatures[j].signature, signatures[j].sig_length);
+			iounmap(p);
+		}
+		if (!ok && setup_count == 0)
+			return 0;
+
+		printk(KERN_INFO "aha152x: BIOS test: passed, ");
+#else
+		printk(KERN_INFO "aha152x: ");
+#endif				/* !SKIP_BIOSTEST */
+
+		ok = 0;
+		for (i = 0; i < ARRAY_SIZE(ports) && setup_count < 2; i++) {
+			if ((setup_count == 1) && (setup[0].io_port == ports[i]))
+				continue;
+
+			if ( request_region(ports[i], IO_RANGE, "aha152x")==0 ) {
+				printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
+				continue;
+			}
+
+			if (aha152x_porttest(ports[i])) {
+				setup[setup_count].tc1550  = 0;
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_PORTA) << 8) + GETPORT(ports[i] + O_PORTB);
+			} else if (tc1550_porttest(ports[i])) {
+				setup[setup_count].tc1550  = 1;
+
+				conf.cf_port =
+				    (GETPORT(ports[i] + O_TC_PORTA) << 8) + GETPORT(ports[i] + O_TC_PORTB);
+			} else {
+				release_region(ports[i], IO_RANGE);
+				continue;
+			}
+
+			release_region(ports[i], IO_RANGE);
+
+			ok++;
+			setup[setup_count].io_port = ports[i];
+			setup[setup_count].irq = IRQ_MIN + conf.cf_irq;
+			setup[setup_count].scsiid = conf.cf_id;
+			setup[setup_count].reconnect = conf.cf_tardisc;
+			setup[setup_count].parity = !conf.cf_parity;
+			setup[setup_count].synchronous = conf.cf_syncneg;
+			setup[setup_count].delay = DELAY_DEFAULT;
+			setup[setup_count].ext_trans = 0;
+#if defined(AHA152X_DEBUG)
+			setup[setup_count].debug = DEBUG_DEFAULT;
+#endif
+			setup_count++;
+
+		}
+
+		if (ok)
+			printk("auto configuration: ok, ");
+	}
+#endif
+
+	printk("%d controller(s) configured\n", setup_count);
+
+	for (i=0; i<setup_count; i++) {
+		if ( request_region(setup[i].io_port, IO_RANGE, "aha152x") ) {
+			struct Scsi_Host *shpnt = aha152x_probe_one(&setup[i]);
+
+			if( !shpnt ) {
+				release_region(setup[i].io_port, IO_RANGE);
+#if defined(__ISAPNP__)
+			} else if( pnpdev[i] ) {
+				HOSTDATA(shpnt)->pnpdev=pnpdev[i];
+				pnpdev[i]=NULL;
+#endif
+			}
+		} else {
+			printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup[i].io_port);
+		}
+
+#if defined(__ISAPNP__)
+		if( pnpdev[i] )
+			pnp_device_detach(pnpdev[i]);
+#endif
+	}
+
+	return registered_count>0;
+}
+
+static void __exit aha152x_exit(void)
+{
+	int i;
+
+	for(i=0; i<ARRAY_SIZE(setup); i++) {
+		aha152x_release(aha152x_host[i]);
+		aha152x_host[i]=NULL;
+	}
+}
+
+module_init(aha152x_init);
+module_exit(aha152x_exit);
+
+#if !defined(MODULE)
+static int __init aha152x_setup(char *str)
+{
+#if defined(AHA152X_DEBUG)
+	int ints[11];
+#else
+	int ints[10];
+#endif
+	get_options(str, ARRAY_SIZE(ints), ints);
+
+	if(setup_count>=ARRAY_SIZE(setup)) {
+		printk(KERN_ERR "aha152x: you can only configure up to two controllers\n");
+		return 1;
+	}
+
+	setup[setup_count].conf        = str;
+	setup[setup_count].io_port     = ints[0] >= 1 ? ints[1] : 0x340;
+	setup[setup_count].irq         = ints[0] >= 2 ? ints[2] : 11;
+	setup[setup_count].scsiid      = ints[0] >= 3 ? ints[3] : 7;
+	setup[setup_count].reconnect   = ints[0] >= 4 ? ints[4] : 1;
+	setup[setup_count].parity      = ints[0] >= 5 ? ints[5] : 1;
+	setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
+	setup[setup_count].delay       = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
+	setup[setup_count].ext_trans   = ints[0] >= 8 ? ints[8] : 0;
+#if defined(AHA152X_DEBUG)
+	setup[setup_count].debug       = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
+	if (ints[0] > 9) {
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
+#else
+	if (ints[0] > 8) {                                                /*}*/
+		printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
+		       "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
+#endif
+	} else {
+		setup_count++;
+		return 0;
+	}
+
+	return 1;
+}
+__setup("aha152x=", aha152x_setup);
+#endif
+
+#endif /* !PCMCIA */
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
new file mode 100644
index 0000000..d277613
--- /dev/null
+++ b/drivers/scsi/aha152x.h
@@ -0,0 +1,337 @@
+#ifndef _AHA152X_H
+#define _AHA152X_H
+
+/*
+ * $Id: aha152x.h,v 2.7 2004/01/24 11:39:03 fischer Exp $
+ */
+
+/* number of queueable commands
+   (unless we support more than 1 cmd_per_lun this should do) */
+#define AHA152X_MAXQUEUE 7
+
+#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 2.7 $"
+
+/* port addresses */
+#define SCSISEQ      (HOSTIOPORT0+0x00)    /* SCSI sequence control */
+#define SXFRCTL0     (HOSTIOPORT0+0x01)    /* SCSI transfer control 0 */
+#define SXFRCTL1     (HOSTIOPORT0+0x02)    /* SCSI transfer control 1 */
+#define SCSISIG      (HOSTIOPORT0+0x03)    /* SCSI signal in/out */
+#define SCSIRATE     (HOSTIOPORT0+0x04)    /* SCSI rate control */
+#define SELID        (HOSTIOPORT0+0x05)    /* selection/reselection ID */
+#define SCSIID       SELID                 /* SCSI ID */
+#define SCSIDAT      (HOSTIOPORT0+0x06)    /* SCSI latched data */
+#define SCSIBUS      (HOSTIOPORT0+0x07)    /* SCSI data bus */
+#define STCNT0       (HOSTIOPORT0+0x08)    /* SCSI transfer count 0 */
+#define STCNT1       (HOSTIOPORT0+0x09)    /* SCSI transfer count 1 */
+#define STCNT2       (HOSTIOPORT0+0x0a)    /* SCSI transfer count 2 */
+#define SSTAT0       (HOSTIOPORT0+0x0b)    /* SCSI interrupt status 0 */
+#define SSTAT1       (HOSTIOPORT0+0x0c)    /* SCSI interrupt status 1 */
+#define SSTAT2       (HOSTIOPORT0+0x0d)    /* SCSI interrupt status 2 */
+#define SCSITEST     (HOSTIOPORT0+0x0e)    /* SCSI test control */
+#define SSTAT3       SCSITEST              /* SCSI interrupt status 3 */
+#define SSTAT4       (HOSTIOPORT0+0x0f)    /* SCSI status 4 */
+#define SIMODE0      (HOSTIOPORT1+0x10)    /* SCSI interrupt mode 0 */
+#define SIMODE1      (HOSTIOPORT1+0x11)    /* SCSI interrupt mode 1 */
+#define DMACNTRL0    (HOSTIOPORT1+0x12)    /* DMA control 0 */
+#define DMACNTRL1    (HOSTIOPORT1+0x13)    /* DMA control 1 */
+#define DMASTAT      (HOSTIOPORT1+0x14)    /* DMA status */
+#define FIFOSTAT     (HOSTIOPORT1+0x15)    /* FIFO status */
+#define DATAPORT     (HOSTIOPORT1+0x16)    /* DATA port */
+#define BRSTCNTRL    (HOSTIOPORT1+0x18)    /* burst control */
+#define PORTA        (HOSTIOPORT1+0x1a)    /* PORT A */
+#define PORTB        (HOSTIOPORT1+0x1b)    /* PORT B */
+#define REV          (HOSTIOPORT1+0x1c)    /* revision */
+#define STACK        (HOSTIOPORT1+0x1d)    /* stack */
+#define TEST         (HOSTIOPORT1+0x1e)    /* test register */
+
+#define IO_RANGE        0x20
+
+/* used in aha152x_porttest */
+#define O_PORTA         0x1a               /* PORT A */
+#define O_PORTB         0x1b               /* PORT B */
+#define O_DMACNTRL1     0x13               /* DMA control 1 */
+#define O_STACK         0x1d               /* stack */
+
+/* used in tc1550_porttest */
+#define O_TC_PORTA      0x0a               /* PORT A */
+#define O_TC_PORTB      0x0b               /* PORT B */
+#define O_TC_DMACNTRL1  0x03               /* DMA control 1 */
+#define O_TC_STACK      0x0d               /* stack */
+
+/* bits and bitmasks to ports */
+
+/* SCSI sequence control */
+#define TEMODEO      0x80
+#define ENSELO       0x40
+#define ENSELI       0x20
+#define ENRESELI     0x10
+#define ENAUTOATNO   0x08
+#define ENAUTOATNI   0x04
+#define ENAUTOATNP   0x02
+#define SCSIRSTO     0x01
+
+/* SCSI transfer control 0 */
+#define SCSIEN       0x80
+#define DMAEN        0x40
+#define CH1          0x20
+#define CLRSTCNT     0x10
+#define SPIOEN       0x08
+#define CLRCH1       0x02
+
+/* SCSI transfer control 1 */
+#define BITBUCKET    0x80
+#define SWRAPEN      0x40
+#define ENSPCHK      0x20
+#define STIMESEL     0x18    /* mask */
+#define STIMESEL_    3
+#define ENSTIMER     0x04
+#define BYTEALIGN    0x02
+
+/* SCSI signal IN */
+#define SIG_CDI          0x80
+#define SIG_IOI          0x40
+#define SIG_MSGI         0x20
+#define SIG_ATNI         0x10
+#define SIG_SELI         0x08
+#define SIG_BSYI         0x04
+#define SIG_REQI         0x02
+#define SIG_ACKI         0x01
+
+/* SCSI Phases */
+#define P_MASK       (SIG_MSGI|SIG_CDI|SIG_IOI)
+#define P_DATAO      (0)
+#define P_DATAI      (SIG_IOI)
+#define P_CMD        (SIG_CDI)
+#define P_STATUS     (SIG_CDI|SIG_IOI)
+#define P_MSGO       (SIG_MSGI|SIG_CDI)
+#define P_MSGI       (SIG_MSGI|SIG_CDI|SIG_IOI)
+
+/* SCSI signal OUT */
+#define SIG_CDO          0x80
+#define SIG_IOO          0x40
+#define SIG_MSGO         0x20
+#define SIG_ATNO         0x10
+#define SIG_SELO         0x08
+#define SIG_BSYO         0x04
+#define SIG_REQO         0x02
+#define SIG_ACKO         0x01
+
+/* SCSI rate control */
+#define SXFR         0x70    /* mask */
+#define SXFR_        4
+#define SOFS         0x0f    /* mask */
+
+/* SCSI ID */
+#define OID          0x70
+#define OID_         4
+#define TID          0x07
+
+/* SCSI transfer count */
+#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \
+                   + (GETPORT(STCNT1)<< 8) \
+                   + GETPORT(STCNT0) )
+
+#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \
+                      SETPORT(STCNT1, ((X) & 0x00FF00) >>  8); \
+                      SETPORT(STCNT0, ((X) & 0x0000FF) ); }
+
+/* SCSI interrupt status */
+#define TARGET       0x80
+#define SELDO        0x40
+#define SELDI        0x20
+#define SELINGO      0x10
+#define SWRAP        0x08
+#define SDONE        0x04
+#define SPIORDY      0x02
+#define DMADONE      0x01
+
+#define SETSDONE     0x80
+#define CLRSELDO     0x40
+#define CLRSELDI     0x20
+#define CLRSELINGO   0x10
+#define CLRSWRAP     0x08
+#define CLRSDONE     0x04
+#define CLRSPIORDY   0x02
+#define CLRDMADONE   0x01
+
+/* SCSI status 1 */
+#define SELTO        0x80
+#define ATNTARG      0x40
+#define SCSIRSTI     0x20
+#define PHASEMIS     0x10
+#define BUSFREE      0x08
+#define SCSIPERR     0x04
+#define PHASECHG     0x02
+#define REQINIT      0x01
+
+#define CLRSELTIMO   0x80
+#define CLRATNO      0x40
+#define CLRSCSIRSTI  0x20
+#define CLRBUSFREE   0x08
+#define CLRSCSIPERR  0x04
+#define CLRPHASECHG  0x02
+#define CLRREQINIT   0x01
+
+/* SCSI status 2 */
+#define SOFFSET      0x20
+#define SEMPTY       0x10
+#define SFULL        0x08
+#define SFCNT        0x07    /* mask */
+
+/* SCSI status 3 */
+#define SCSICNT      0xf0    /* mask */
+#define SCSICNT_     4
+#define OFFCNT       0x0f    /* mask */
+
+/* SCSI TEST control */
+#define SCTESTU      0x08
+#define SCTESTD      0x04
+#define STCTEST      0x01
+
+/* SCSI status 4 */
+#define SYNCERR      0x04
+#define FWERR        0x02
+#define FRERR        0x01
+
+#define CLRSYNCERR   0x04
+#define CLRFWERR     0x02
+#define CLRFRERR     0x01
+
+/* SCSI interrupt mode 0 */
+#define ENSELDO      0x40
+#define ENSELDI      0x20
+#define ENSELINGO    0x10
+#define ENSWRAP      0x08
+#define ENSDONE      0x04
+#define ENSPIORDY    0x02
+#define ENDMADONE    0x01
+
+/* SCSI interrupt mode 1 */
+#define ENSELTIMO    0x80
+#define ENATNTARG    0x40
+#define ENSCSIRST    0x20
+#define ENPHASEMIS   0x10
+#define ENBUSFREE    0x08
+#define ENSCSIPERR   0x04
+#define ENPHASECHG   0x02
+#define ENREQINIT    0x01
+
+/* DMA control 0 */
+#define ENDMA        0x80
+#define _8BIT        0x40
+#define DMA          0x20
+#define WRITE_READ   0x08
+#define INTEN        0x04
+#define RSTFIFO      0x02
+#define SWINT        0x01
+
+/* DMA control 1 */
+#define PWRDWN       0x80
+#define STK          0x07    /* mask */
+
+/* DMA status */
+#define ATDONE       0x80
+#define WORDRDY      0x40
+#define INTSTAT      0x20
+#define DFIFOFULL    0x10
+#define DFIFOEMP     0x08
+
+/* BURST control */
+#define BON          0xf0
+#define BOFF         0x0f
+
+/* TEST REGISTER */
+#define BOFFTMR      0x40
+#define BONTMR       0x20
+#define STCNTH       0x10
+#define STCNTM       0x08
+#define STCNTL       0x04
+#define SCSIBLK      0x02
+#define DMABLK       0x01
+
+/* On the AHA-152x board PORTA and PORTB contain
+   some information about the board's configuration. */
+typedef union {
+  struct {
+    unsigned reserved:2;    /* reserved */
+    unsigned tardisc:1;     /* Target disconnect: 0=disabled, 1=enabled */
+    unsigned syncneg:1;     /* Initial sync neg: 0=disabled, 1=enabled */
+    unsigned msgclasses:2;  /* Message classes
+                                 0=#4
+                                 1=#0, #1, #2, #3, #4
+                                 2=#0, #3, #4
+                                 3=#0, #4
+                             */
+    unsigned boot:1;        /* boot: 0=disabled, 1=enabled */
+    unsigned dma:1;         /* Transfer mode: 0=PIO; 1=DMA */
+    unsigned id:3;          /* SCSI-id */
+    unsigned irq:2;         /* IRQ-Channel: 0,3=12, 1=10, 2=11 */
+    unsigned dmachan:2;     /* DMA-Channel: 0=0, 1=5, 2=6, 3=7 */
+    unsigned parity:1;      /* SCSI-parity: 1=enabled 0=disabled */
+  } fields;
+  unsigned short port;
+} aha152x_config ;
+
+#define cf_parity     fields.parity
+#define cf_dmachan    fields.dmachan
+#define cf_irq        fields.irq
+#define cf_id         fields.id
+#define cf_dma        fields.dma
+#define cf_boot       fields.boot
+#define cf_msgclasses fields.msgclasses
+#define cf_syncneg    fields.syncneg
+#define cf_tardisc    fields.tardisc
+#define cf_port       port
+
+/* Some macros to manipulate ports and their bits */
+
+#define SETPORT(PORT, VAL)	outb( (VAL), (PORT) )
+#define GETPORT(PORT)		inb( PORT )
+#define SETBITS(PORT, BITS)	outb( (inb(PORT) | (BITS)), (PORT) )
+#define CLRBITS(PORT, BITS)	outb( (inb(PORT) & ~(BITS)), (PORT) )
+#define TESTHI(PORT, BITS)	((inb(PORT) & (BITS)) == (BITS))
+#define TESTLO(PORT, BITS)	((inb(PORT) & (BITS)) == 0)
+
+#define SETRATE(RATE)		SETPORT(SCSIRATE,(RATE) & 0x7f)
+
+#if defined(AHA152X_DEBUG)
+enum {
+  debug_procinfo  = 0x0001,
+  debug_queue     = 0x0002,
+  debug_locks     = 0x0004,
+  debug_intr      = 0x0008,
+  debug_selection = 0x0010,
+  debug_msgo      = 0x0020,
+  debug_msgi      = 0x0040,
+  debug_status    = 0x0080,
+  debug_cmd       = 0x0100,
+  debug_datai     = 0x0200,
+  debug_datao     = 0x0400,
+  debug_eh	  = 0x0800,
+  debug_done      = 0x1000,
+  debug_phases    = 0x2000,
+};
+#endif
+
+/* for the pcmcia stub */
+struct aha152x_setup {
+	int io_port;
+	int irq;
+	int scsiid;
+	int reconnect;
+	int parity;
+	int synchronous;
+	int delay;
+	int ext_trans;
+	int tc1550;
+#if defined(AHA152X_DEBUG)
+	int debug;
+#endif
+	char *conf;
+};
+
+struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *);
+void aha152x_release(struct Scsi_Host *);
+int aha152x_host_reset(Scsi_Cmnd *);
+
+#endif /* _AHA152X_H */
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
new file mode 100644
index 0000000..e9920a0
--- /dev/null
+++ b/drivers/scsi/aha1542.c
@@ -0,0 +1,1832 @@
+/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $
+ *  linux/kernel/aha1542.c
+ *
+ *  Copyright (C) 1992  Tommy Thorn
+ *  Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *
+ *  Modified by Eric Youngdale
+ *        Use request_irq and request_dma to help prevent unexpected conflicts
+ *        Set up on-board DMA controller, such that we do not have to
+ *        have the bios enabled to use the aha1542.
+ *  Modified by David Gentzel
+ *        Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus
+ *        controller).
+ *  Modified by Matti Aarnio
+ *        Accept parameters from LILO cmd-line. -- 1-Oct-94
+ *  Modified by Mike McLagan <mike.mclagan@linux.org>
+ *        Recognise extended mode on AHA1542CP, different bit than 1542CF
+ *        1-Jan-97
+ *  Modified by Bjorn L. Thordarson and Einar Thor Einarsson
+ *        Recognize that DMA0 is valid DMA channel -- 13-Jul-98
+ *  Modified by Chris Faulhaber <jedgar@fxp.org>
+ *        Added module command-line options
+ *        19-Jul-99
+ *  Modified by Adam Fritzler <mid@auk.cx>
+ *        Added proper detection of the AHA-1640 (MCA version of AHA-1540)
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/isapnp.h>
+#include <linux/blkdev.h>
+#include <linux/mca.h>
+#include <linux/mca-legacy.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha1542.h"
+
+#define SCSI_BUF_PA(address)	isa_virt_to_bus(address)
+#define SCSI_SG_PA(sgent)	(isa_page_to_bus((sgent)->page) + (sgent)->offset)
+
+static void BAD_DMA(void *address, unsigned int length)
+{
+	printk(KERN_CRIT "buf vaddress %p paddress 0x%lx length %d\n",
+	       address,
+	       SCSI_BUF_PA(address),
+	       length);
+	panic("Buffer at physical address > 16Mb used for aha1542");
+}
+
+static void BAD_SG_DMA(Scsi_Cmnd * SCpnt,
+		       struct scatterlist *sgpnt,
+		       int nseg,
+		       int badseg)
+{
+	printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%llx length %u\n",
+	       badseg, nseg,
+	       page_address(sgpnt[badseg].page) + sgpnt[badseg].offset,
+	       (unsigned long long)SCSI_SG_PA(&sgpnt[badseg]),
+	       sgpnt[badseg].length);
+
+	/*
+	 * Not safe to continue.
+	 */
+	panic("Buffer at physical address > 16Mb used for aha1542");
+}
+
+#include<linux/stat.h>
+
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+/*
+   static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
+ */
+
+/* The adaptec can be configured for quite a number of addresses, but
+   I generally do not want the card poking around at random.  We allow
+   two addresses - this allows people to use the Adaptec with a Midi
+   card, which also used 0x330 -- can be overridden with LILO! */
+
+#define MAXBOARDS 4		/* Increase this and the sizes of the
+				   arrays below, if you need more.. */
+
+/* Boards 3,4 slots are reserved for ISAPnP/MCA scans */
+
+static unsigned int bases[MAXBOARDS] __initdata = {0x330, 0x334, 0, 0};
+
+/* set by aha1542_setup according to the command line; they also may
+   be marked __initdata, but require zero initializers then */
+
+static int setup_called[MAXBOARDS];
+static int setup_buson[MAXBOARDS];
+static int setup_busoff[MAXBOARDS];
+static int setup_dmaspeed[MAXBOARDS] __initdata = { -1, -1, -1, -1 };
+
+/*
+ * LILO/Module params:  aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]
+ *
+ * Where:  <PORTBASE> is any of the valid AHA addresses:
+ *                      0x130, 0x134, 0x230, 0x234, 0x330, 0x334
+ *         <BUSON>  is the time (in microsecs) that AHA spends on the AT-bus
+ *                  when transferring data.  1542A power-on default is 11us,
+ *                  valid values are in range: 2..15 (decimal)
+ *         <BUSOFF> is the time that AHA spends OFF THE BUS after while
+ *                  it is transferring data (not to monopolize the bus).
+ *                  Power-on default is 4us, valid range: 1..64 microseconds.
+ *         <DMASPEED> Default is jumper selected (1542A: on the J1),
+ *                  but experimenter can alter it with this.
+ *                  Valid values: 5, 6, 7, 8, 10 (MB/s)
+ *                  Factory default is 5 MB/s.
+ */
+
+#if defined(MODULE)
+static int isapnp = 0;
+static int aha1542[] = {0x330, 11, 4, -1};
+module_param_array(aha1542, int, NULL, 0);
+module_param(isapnp, bool, 0);
+
+static struct isapnp_device_id id_table[] __initdata = {
+	{
+		ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('A', 'D', 'P'), ISAPNP_FUNCTION(0x1542),
+		0
+	},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+#else
+static int isapnp = 1;
+#endif
+
+#define BIOS_TRANSLATION_1632 0	/* Used by some old 1542A boards */
+#define BIOS_TRANSLATION_6432 1	/* Default case these days */
+#define BIOS_TRANSLATION_25563 2	/* Big disk case */
+
+struct aha1542_hostdata {
+	/* This will effectively start both of them at the first mailbox */
+	int bios_translation;	/* Mapping bios uses - for compatibility */
+	int aha1542_last_mbi_used;
+	int aha1542_last_mbo_used;
+	Scsi_Cmnd *SCint[AHA1542_MAILBOXES];
+	struct mailbox mb[2 * AHA1542_MAILBOXES];
+	struct ccb ccb[AHA1542_MAILBOXES];
+};
+
+#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
+
+static struct Scsi_Host *aha_host[7];	/* One for each IRQ level (9-15) */
+
+static DEFINE_SPINLOCK(aha1542_lock);
+
+
+
+#define WAITnexttimeout 3000000
+
+static void setup_mailboxes(int base_io, struct Scsi_Host *shpnt);
+static int aha1542_restart(struct Scsi_Host *shost);
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs);
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+					struct pt_regs *regs);
+
+#define aha1542_intr_reset(base)  outb(IRST, CONTROL(base))
+
+#define WAIT(port, mask, allof, noneof)					\
+ { register int WAITbits;						\
+   register int WAITtimeout = WAITnexttimeout;				\
+   while (1) {								\
+     WAITbits = inb(port) & (mask);					\
+     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+       break;                                                         	\
+     if (--WAITtimeout == 0) goto fail;					\
+   }									\
+ }
+
+/* Similar to WAIT, except we use the udelay call to regulate the
+   amount of time we wait.  */
+#define WAITd(port, mask, allof, noneof, timeout)			\
+ { register int WAITbits;						\
+   register int WAITtimeout = timeout;					\
+   while (1) {								\
+     WAITbits = inb(port) & (mask);					\
+     if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
+       break;                                                         	\
+     mdelay(1);							\
+     if (--WAITtimeout == 0) goto fail;					\
+   }									\
+ }
+
+static void aha1542_stat(void)
+{
+/*	int s = inb(STATUS), i = inb(INTRFLAGS);
+	printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
+}
+
+/* This is a bit complicated, but we need to make sure that an interrupt
+   routine does not send something out while we are in the middle of this.
+   Fortunately, it is only at boot time that multi-byte messages
+   are ever sent. */
+static int aha1542_out(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags = 0;
+	int got_lock;
+
+	if (len == 1) {
+		got_lock = 0;
+		while (1 == 1) {
+			WAIT(STATUS(base), CDF, 0, CDF);
+			spin_lock_irqsave(&aha1542_lock, flags);
+			if (inb(STATUS(base)) & CDF) {
+				spin_unlock_irqrestore(&aha1542_lock, flags);
+				continue;
+			}
+			outb(*cmdp, DATA(base));
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			return 0;
+		}
+	} else {
+		spin_lock_irqsave(&aha1542_lock, flags);
+		got_lock = 1;
+		while (len--) {
+			WAIT(STATUS(base), CDF, 0, CDF);
+			outb(*cmdp++, DATA(base));
+		}
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+	}
+	return 0;
+fail:
+	if (got_lock)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+	printk(KERN_ERR "aha1542_out failed(%d): ", len + 1);
+	aha1542_stat();
+	return 1;
+}
+
+/* Only used at boot time, so we do not need to worry about latency as much
+   here */
+
+static int __init aha1542_in(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	while (len--) {
+		WAIT(STATUS(base), DF, DF, 0);
+		*cmdp++ = inb(DATA(base));
+	}
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 0;
+fail:
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	printk(KERN_ERR "aha1542_in failed(%d): ", len + 1);
+	aha1542_stat();
+	return 1;
+}
+
+/* Similar to aha1542_in, except that we wait a very short period of time.
+   We use this if we know the board is alive and awake, but we are not sure
+   if the board will respond to the command we are about to send or not */
+static int __init aha1542_in1(unsigned int base, unchar * cmdp, int len)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	while (len--) {
+		WAITd(STATUS(base), DF, DF, 0, 100);
+		*cmdp++ = inb(DATA(base));
+	}
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 0;
+fail:
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+	return 1;
+}
+
+static int makecode(unsigned hosterr, unsigned scsierr)
+{
+	switch (hosterr) {
+	case 0x0:
+	case 0xa:		/* Linked command complete without error and linked normally */
+	case 0xb:		/* Linked command complete without error, interrupt generated */
+		hosterr = 0;
+		break;
+
+	case 0x11:		/* Selection time out-The initiator selection or target
+				   reselection was not complete within the SCSI Time out period */
+		hosterr = DID_TIME_OUT;
+		break;
+
+	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
+				   than was allocated by the Data Length field or the sum of the
+				   Scatter / Gather Data Length fields. */
+
+	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+
+	case 0x15:		/* MBO command was not 00, 01 or 02-The first byte of the CB was
+				   invalid. This usually indicates a software failure. */
+
+	case 0x16:		/* Invalid CCB Operation Code-The first byte of the CCB was invalid.
+				   This usually indicates a software failure. */
+
+	case 0x17:		/* Linked CCB does not have the same LUN-A subsequent CCB of a set
+				   of linked CCB's does not specify the same logical unit number as
+				   the first. */
+	case 0x18:		/* Invalid Target Direction received from Host-The direction of a
+				   Target Mode CCB was invalid. */
+
+	case 0x19:		/* Duplicate CCB Received in Target Mode-More than once CCB was
+				   received to service data transfer between the same target LUN
+				   and initiator SCSI ID in the same direction. */
+
+	case 0x1a:		/* Invalid CCB or Segment List Parameter-A segment list with a zero
+				   length segment or invalid segment list boundaries was received.
+				   A CCB parameter was invalid. */
+		DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
+		hosterr = DID_ERROR;	/* Couldn't find any better */
+		break;
+
+	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
+				   phase sequence was requested by the target. The host adapter
+				   will generate a SCSI Reset Condition, notifying the host with
+				   a SCRD interrupt */
+		hosterr = DID_RESET;
+		break;
+	default:
+		printk(KERN_ERR "aha1542: makecode: unknown hoststatus %x\n", hosterr);
+		break;
+	}
+	return scsierr | (hosterr << 16);
+}
+
+static int __init aha1542_test_port(int bse, struct Scsi_Host *shpnt)
+{
+	unchar inquiry_cmd[] = {CMD_INQUIRY};
+	unchar inquiry_result[4];
+	unchar *cmdp;
+	int len;
+	volatile int debug = 0;
+
+	/* Quick and dirty test for presence of the card. */
+	if (inb(STATUS(bse)) == 0xff)
+		return 0;
+
+	/* Reset the adapter. I ought to make a hard reset, but it's not really necessary */
+
+	/*  DEB(printk("aha1542_test_port called \n")); */
+
+	/* In case some other card was probing here, reset interrupts */
+	aha1542_intr_reset(bse);	/* reset interrupts, so they don't block */
+
+	outb(SRST | IRST /*|SCRST */ , CONTROL(bse));
+
+	mdelay(20);		/* Wait a little bit for things to settle down. */
+
+	debug = 1;
+	/* Expect INIT and IDLE, any of the others are bad */
+	WAIT(STATUS(bse), STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	debug = 2;
+	/* Shouldn't have generated any interrupts during reset */
+	if (inb(INTRFLAGS(bse)) & INTRMASK)
+		goto fail;
+
+
+	/* Perform a host adapter inquiry instead so we do not need to set
+	   up the mailboxes ahead of time */
+
+	aha1542_out(bse, inquiry_cmd, 1);
+
+	debug = 3;
+	len = 4;
+	cmdp = &inquiry_result[0];
+
+	while (len--) {
+		WAIT(STATUS(bse), DF, DF, 0);
+		*cmdp++ = inb(DATA(bse));
+	}
+
+	debug = 8;
+	/* Reading port should reset DF */
+	if (inb(STATUS(bse)) & DF)
+		goto fail;
+
+	debug = 9;
+	/* When HACC, command is completed, and we're though testing */
+	WAIT(INTRFLAGS(bse), HACC, HACC, 0);
+	/* now initialize adapter */
+
+	debug = 10;
+	/* Clear interrupts */
+	outb(IRST, CONTROL(bse));
+
+	debug = 11;
+
+	return debug;		/* 1 = ok */
+fail:
+	return 0;		/* 0 = not ok */
+}
+
+/* A quick wrapper for do_aha1542_intr_handle to grab the spin lock */
+static irqreturn_t do_aha1542_intr_handle(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *shost;
+
+	shost = aha_host[irq - 9];
+	if (!shost)
+		panic("Splunge!");
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	aha1542_intr_handle(shost, dev_id, regs);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/* A "high" level interrupt handler */
+static void aha1542_intr_handle(struct Scsi_Host *shost, void *dev_id, struct pt_regs *regs)
+{
+	void (*my_done) (Scsi_Cmnd *) = NULL;
+	int errstatus, mbi, mbo, mbistatus;
+	int number_serviced;
+	unsigned long flags;
+	Scsi_Cmnd *SCtmp;
+	int flag;
+	int needs_restart;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	mb = HOSTDATA(shost)->mb;
+	ccb = HOSTDATA(shost)->ccb;
+
+#ifdef DEBUG
+	{
+		flag = inb(INTRFLAGS(shost->io_port));
+		printk(KERN_DEBUG "aha1542_intr_handle: ");
+		if (!(flag & ANYINTR))
+			printk("no interrupt?");
+		if (flag & MBIF)
+			printk("MBIF ");
+		if (flag & MBOA)
+			printk("MBOF ");
+		if (flag & HACC)
+			printk("HACC ");
+		if (flag & SCRD)
+			printk("SCRD ");
+		printk("status %02x\n", inb(STATUS(shost->io_port)));
+	};
+#endif
+	number_serviced = 0;
+	needs_restart = 0;
+
+	while (1 == 1) {
+		flag = inb(INTRFLAGS(shost->io_port));
+
+		/* Check for unusual interrupts.  If any of these happen, we should
+		   probably do something special, but for now just printing a message
+		   is sufficient.  A SCSI reset detected is something that we really
+		   need to deal with in some way. */
+		if (flag & ~MBIF) {
+			if (flag & MBOA)
+				printk("MBOF ");
+			if (flag & HACC)
+				printk("HACC ");
+			if (flag & SCRD) {
+				needs_restart = 1;
+				printk("SCRD ");
+			}
+		}
+		aha1542_intr_reset(shost->io_port);
+
+		spin_lock_irqsave(&aha1542_lock, flags);
+		mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
+		if (mbi >= 2 * AHA1542_MAILBOXES)
+			mbi = AHA1542_MAILBOXES;
+
+		do {
+			if (mb[mbi].status != 0)
+				break;
+			mbi++;
+			if (mbi >= 2 * AHA1542_MAILBOXES)
+				mbi = AHA1542_MAILBOXES;
+		} while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
+
+		if (mb[mbi].status == 0) {
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			/* Hmm, no mail.  Must have read it the last time around */
+			if (!number_serviced && !needs_restart)
+				printk(KERN_WARNING "aha1542.c: interrupt received, but no mail.\n");
+			/* We detected a reset.  Restart all pending commands for
+			   devices that use the hard reset option */
+			if (needs_restart)
+				aha1542_restart(shost);
+			return;
+		};
+
+		mbo = (scsi2int(mb[mbi].ccbptr) - (SCSI_BUF_PA(&ccb[0]))) / sizeof(struct ccb);
+		mbistatus = mb[mbi].status;
+		mb[mbi].status = 0;
+		HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+
+#ifdef DEBUG
+		{
+			if (ccb[mbo].tarstat | ccb[mbo].hastat)
+				printk(KERN_DEBUG "aha1542_command: returning %x (status %d)\n",
+				       ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status);
+		};
+#endif
+
+		if (mbistatus == 3)
+			continue;	/* Aborted command not found */
+
+#ifdef DEBUG
+		printk(KERN_DEBUG "...done %d %d\n", mbo, mbi);
+#endif
+
+		SCtmp = HOSTDATA(shost)->SCint[mbo];
+
+		if (!SCtmp || !SCtmp->scsi_done) {
+			printk(KERN_WARNING "aha1542_intr_handle: Unexpected interrupt\n");
+			printk(KERN_WARNING "tarstat=%x, hastat=%x idlun=%x ccb#=%d \n", ccb[mbo].tarstat,
+			       ccb[mbo].hastat, ccb[mbo].idlun, mbo);
+			return;
+		}
+		my_done = SCtmp->scsi_done;
+		if (SCtmp->host_scribble) {
+			kfree(SCtmp->host_scribble);
+			SCtmp->host_scribble = NULL;
+		}
+		/* Fetch the sense data, and tuck it away, in the required slot.  The
+		   Adaptec automatically fetches it, and there is no guarantee that
+		   we will still have it in the cdb when we come back */
+		if (ccb[mbo].tarstat == 2)
+			memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen],
+			       sizeof(SCtmp->sense_buffer));
+
+
+		/* is there mail :-) */
+
+		/* more error checking left out here */
+		if (mbistatus != 1)
+			/* This is surely wrong, but I don't know what's right */
+			errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat);
+		else
+			errstatus = 0;
+
+#ifdef DEBUG
+		if (errstatus)
+			printk(KERN_DEBUG "(aha1542 error:%x %x %x) ", errstatus,
+			       ccb[mbo].hastat, ccb[mbo].tarstat);
+#endif
+
+		if (ccb[mbo].tarstat == 2) {
+#ifdef DEBUG
+			int i;
+#endif
+			DEB(printk("aha1542_intr_handle: sense:"));
+#ifdef DEBUG
+			for (i = 0; i < 12; i++)
+				printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen + i]);
+			printk("\n");
+#endif
+			/*
+			   DEB(printk("aha1542_intr_handle: buf:"));
+			   for (i = 0; i < bufflen; i++)
+			   printk("%02x ", ((unchar *)buff)[i]);
+			   printk("\n");
+			 */
+		}
+		DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
+		SCtmp->result = errstatus;
+		HOSTDATA(shost)->SCint[mbo] = NULL;	/* This effectively frees up the mailbox slot, as
+							   far as queuecommand is concerned */
+		my_done(SCtmp);
+		number_serviced++;
+	};
+}
+
+static int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	unchar ahacmd = CMD_START_SCSI;
+	unchar direction;
+	unchar *cmd = (unchar *) SCpnt->cmnd;
+	unchar target = SCpnt->device->id;
+	unchar lun = SCpnt->device->lun;
+	unsigned long flags;
+	void *buff = SCpnt->request_buffer;
+	int bufflen = SCpnt->request_bufflen;
+	int mbo;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	DEB(int i);
+
+	mb = HOSTDATA(SCpnt->device->host)->mb;
+	ccb = HOSTDATA(SCpnt->device->host)->ccb;
+
+	DEB(if (target > 1) {
+	    SCpnt->result = DID_TIME_OUT << 16;
+	    done(SCpnt); return 0;
+	    }
+	);
+
+	if (*cmd == REQUEST_SENSE) {
+		/* Don't do the command - we have the sense data already */
+#if 0
+		/* scsi_request_sense() provides a buffer of size 256,
+		   so there is no reason to expect equality */
+		if (bufflen != sizeof(SCpnt->sense_buffer))
+			printk(KERN_CRIT "aha1542: Wrong buffer length supplied "
+			       "for request sense (%d)\n", bufflen);
+#endif
+		SCpnt->result = 0;
+		done(SCpnt);
+		return 0;
+	}
+#ifdef DEBUG
+	if (*cmd == READ_10 || *cmd == WRITE_10)
+		i = xscsi2int(cmd + 2);
+	else if (*cmd == READ_6 || *cmd == WRITE_6)
+		i = scsi2int(cmd + 2);
+	else
+		i = -1;
+	if (done)
+		printk(KERN_DEBUG "aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+	else
+		printk(KERN_DEBUG "aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
+	aha1542_stat();
+	printk(KERN_DEBUG "aha1542_queuecommand: dumping scsi cmd:");
+	for (i = 0; i < SCpnt->cmd_len; i++)
+		printk("%02x ", cmd[i]);
+	printk("\n");
+	if (*cmd == WRITE_10 || *cmd == WRITE_6)
+		return 0;	/* we are still testing, so *don't* write */
+#endif
+	/* Use the outgoing mailboxes in a round-robin fashion, because this
+	   is how the host adapter will scan for them */
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1;
+	if (mbo >= AHA1542_MAILBOXES)
+		mbo = 0;
+
+	do {
+		if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL)
+			break;
+		mbo++;
+		if (mbo >= AHA1542_MAILBOXES)
+			mbo = 0;
+	} while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used);
+
+	if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo])
+		panic("Unable to find empty mailbox for aha1542.\n");
+
+	HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt;	/* This will effectively prevent someone else from
+							   screwing with this cdb. */
+
+	HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo;
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+#ifdef DEBUG
+	printk(KERN_DEBUG "Sending command (%d %x)...", mbo, done);
+#endif
+
+	any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo]));	/* This gets trashed for some reason */
+
+	memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+	ccb[mbo].cdblen = SCpnt->cmd_len;
+
+	direction = 0;
+	if (*cmd == READ_10 || *cmd == READ_6)
+		direction = 8;
+	else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+		direction = 16;
+
+	memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen);
+
+	if (SCpnt->use_sg) {
+		struct scatterlist *sgpnt;
+		struct chain *cptr;
+#ifdef DEBUG
+		unsigned char *ptr;
+#endif
+		int i;
+		ccb[mbo].op = 2;	/* SCSI Initiator Command  w/scatter-gather */
+		SCpnt->host_scribble = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+		sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+		cptr = (struct chain *) SCpnt->host_scribble;
+		if (cptr == NULL) {
+			/* free the claimed mailbox slot */
+			HOSTDATA(SCpnt->device->host)->SCint[mbo] = NULL;
+			return SCSI_MLQUEUE_HOST_BUSY;
+		}
+		for (i = 0; i < SCpnt->use_sg; i++) {
+			if (sgpnt[i].length == 0 || SCpnt->use_sg > 16 ||
+			    (((int) sgpnt[i].offset) & 1) || (sgpnt[i].length & 1)) {
+				unsigned char *ptr;
+				printk(KERN_CRIT "Bad segment list supplied to aha1542.c (%d, %d)\n", SCpnt->use_sg, i);
+				for (i = 0; i < SCpnt->use_sg; i++) {
+					printk(KERN_CRIT "%d: %p %d\n", i,
+					       (page_address(sgpnt[i].page) +
+						sgpnt[i].offset),
+					       sgpnt[i].length);
+				};
+				printk(KERN_CRIT "cptr %x: ", (unsigned int) cptr);
+				ptr = (unsigned char *) &cptr[i];
+				for (i = 0; i < 18; i++)
+					printk("%02x ", ptr[i]);
+				panic("Foooooooood fight!");
+			};
+			any2scsi(cptr[i].dataptr, SCSI_SG_PA(&sgpnt[i]));
+			if (SCSI_SG_PA(&sgpnt[i]) + sgpnt[i].length - 1 > ISA_DMA_THRESHOLD)
+				BAD_SG_DMA(SCpnt, sgpnt, SCpnt->use_sg, i);
+			any2scsi(cptr[i].datalen, sgpnt[i].length);
+		};
+		any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain));
+		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(cptr));
+#ifdef DEBUG
+		printk("cptr %x: ", cptr);
+		ptr = (unsigned char *) cptr;
+		for (i = 0; i < 18; i++)
+			printk("%02x ", ptr[i]);
+#endif
+	} else {
+		ccb[mbo].op = 0;	/* SCSI Initiator Command */
+		SCpnt->host_scribble = NULL;
+		any2scsi(ccb[mbo].datalen, bufflen);
+		if (buff && SCSI_BUF_PA(buff + bufflen - 1) > ISA_DMA_THRESHOLD)
+			BAD_DMA(buff, bufflen);
+		any2scsi(ccb[mbo].dataptr, SCSI_BUF_PA(buff));
+	};
+	ccb[mbo].idlun = (target & 7) << 5 | direction | (lun & 7);	/*SCSI Target Id */
+	ccb[mbo].rsalen = 16;
+	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+	ccb[mbo].commlinkid = 0;
+
+#ifdef DEBUG
+	{
+		int i;
+		printk(KERN_DEBUG "aha1542_command: sending.. ");
+		for (i = 0; i < sizeof(ccb[mbo]) - 10; i++)
+			printk("%02x ", ((unchar *) & ccb[mbo])[i]);
+	};
+#endif
+
+	if (done) {
+		DEB(printk("aha1542_queuecommand: now waiting for interrupt ");
+		    aha1542_stat());
+		SCpnt->scsi_done = done;
+		mb[mbo].status = 1;
+		aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1);	/* start scsi command */
+		DEB(aha1542_stat());
+	} else
+		printk("aha1542_queuecommand: done can't be NULL\n");
+
+	return 0;
+}
+
+/* Initialize mailboxes */
+static void setup_mailboxes(int bse, struct Scsi_Host *shpnt)
+{
+	int i;
+	struct mailbox *mb;
+	struct ccb *ccb;
+
+	unchar cmd[5] = { CMD_MBINIT, AHA1542_MAILBOXES, 0, 0, 0};
+
+	mb = HOSTDATA(shpnt)->mb;
+	ccb = HOSTDATA(shpnt)->ccb;
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		mb[i].status = mb[AHA1542_MAILBOXES + i].status = 0;
+		any2scsi(mb[i].ccbptr, SCSI_BUF_PA(&ccb[i]));
+	};
+	aha1542_intr_reset(bse);	/* reset interrupts, so they don't block */
+	any2scsi((cmd + 2), SCSI_BUF_PA(mb));
+	aha1542_out(bse, cmd, 5);
+	WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: failed setting up mailboxes\n");
+	}
+	aha1542_intr_reset(bse);
+}
+
+static int __init aha1542_getconfig(int base_io, unsigned char *irq_level, unsigned char *dma_chan, unsigned char *scsi_id)
+{
+	unchar inquiry_cmd[] = {CMD_RETCONF};
+	unchar inquiry_result[3];
+	int i;
+	i = inb(STATUS(base_io));
+	if (i & DF) {
+		i = inb(DATA(base_io));
+	};
+	aha1542_out(base_io, inquiry_cmd, 1);
+	aha1542_in(base_io, inquiry_result, 3);
+	WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: query board settings\n");
+	}
+	aha1542_intr_reset(base_io);
+	switch (inquiry_result[0]) {
+	case 0x80:
+		*dma_chan = 7;
+		break;
+	case 0x40:
+		*dma_chan = 6;
+		break;
+	case 0x20:
+		*dma_chan = 5;
+		break;
+	case 0x01:
+		*dma_chan = 0;
+		break;
+	case 0:
+		/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
+		   Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
+		*dma_chan = 0xFF;
+		break;
+	default:
+		printk(KERN_ERR "Unable to determine Adaptec DMA priority.  Disabling board\n");
+		return -1;
+	};
+	switch (inquiry_result[1]) {
+	case 0x40:
+		*irq_level = 15;
+		break;
+	case 0x20:
+		*irq_level = 14;
+		break;
+	case 0x8:
+		*irq_level = 12;
+		break;
+	case 0x4:
+		*irq_level = 11;
+		break;
+	case 0x2:
+		*irq_level = 10;
+		break;
+	case 0x1:
+		*irq_level = 9;
+		break;
+	default:
+		printk(KERN_ERR "Unable to determine Adaptec IRQ level.  Disabling board\n");
+		return -1;
+	};
+	*scsi_id = inquiry_result[2] & 7;
+	return 0;
+}
+
+/* This function should only be called for 1542C boards - we can detect
+   the special firmware settings and unlock the board */
+
+static int __init aha1542_mbenable(int base)
+{
+	static unchar mbenable_cmd[3];
+	static unchar mbenable_result[2];
+	int retval;
+
+	retval = BIOS_TRANSLATION_6432;
+
+	mbenable_cmd[0] = CMD_EXTBIOS;
+	aha1542_out(base, mbenable_cmd, 1);
+	if (aha1542_in1(base, mbenable_result, 2))
+		return retval;
+	WAITd(INTRFLAGS(base), INTRMASK, HACC, 0, 100);
+	aha1542_intr_reset(base);
+
+	if ((mbenable_result[0] & 0x08) || mbenable_result[1]) {
+		mbenable_cmd[0] = CMD_MBENABLE;
+		mbenable_cmd[1] = 0;
+		mbenable_cmd[2] = mbenable_result[1];
+
+		if ((mbenable_result[0] & 0x08) && (mbenable_result[1] & 0x03))
+			retval = BIOS_TRANSLATION_25563;
+
+		aha1542_out(base, mbenable_cmd, 3);
+		WAIT(INTRFLAGS(base), INTRMASK, HACC, 0);
+	};
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_mbenable: Mailbox init failed\n");
+	}
+	aha1542_intr_reset(base);
+	return retval;
+}
+
+/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
+static int __init aha1542_query(int base_io, int *transl)
+{
+	unchar inquiry_cmd[] = {CMD_INQUIRY};
+	unchar inquiry_result[4];
+	int i;
+	i = inb(STATUS(base_io));
+	if (i & DF) {
+		i = inb(DATA(base_io));
+	};
+	aha1542_out(base_io, inquiry_cmd, 1);
+	aha1542_in(base_io, inquiry_result, 4);
+	WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+	while (0) {
+fail:
+		printk(KERN_ERR "aha1542_detect: query card type\n");
+	}
+	aha1542_intr_reset(base_io);
+
+	*transl = BIOS_TRANSLATION_6432;	/* Default case */
+
+	/* For an AHA1740 series board, we ignore the board since there is a
+	   hardware bug which can lead to wrong blocks being returned if the board
+	   is operating in the 1542 emulation mode.  Since there is an extended mode
+	   driver, we simply ignore the board and let the 1740 driver pick it up.
+	 */
+
+	if (inquiry_result[0] == 0x43) {
+		printk(KERN_INFO "aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
+		return 1;
+	};
+
+	/* Always call this - boards that do not support extended bios translation
+	   will ignore the command, and we will set the proper default */
+
+	*transl = aha1542_mbenable(base_io);
+
+	return 0;
+}
+
+#ifndef MODULE
+static char *setup_str[MAXBOARDS] __initdata;
+static int setup_idx = 0;
+
+static void __init aha1542_setup(char *str, int *ints)
+{
+	const char *ahausage = "aha1542: usage: aha1542=<PORTBASE>[,<BUSON>,<BUSOFF>[,<DMASPEED>]]\n";
+	int setup_portbase;
+
+	if (setup_idx >= MAXBOARDS) {
+		printk(KERN_ERR "aha1542: aha1542_setup called too many times! Bad LILO params ?\n");
+		printk(KERN_ERR "   Entryline 1: %s\n", setup_str[0]);
+		printk(KERN_ERR "   Entryline 2: %s\n", setup_str[1]);
+		printk(KERN_ERR "   This line:   %s\n", str);
+		return;
+	}
+	if (ints[0] < 1 || ints[0] > 4) {
+		printk(KERN_ERR "aha1542: %s\n", str);
+		printk(ahausage);
+		printk(KERN_ERR "aha1542: Wrong parameters may cause system malfunction.. We try anyway..\n");
+	}
+	setup_called[setup_idx] = ints[0];
+	setup_str[setup_idx] = str;
+
+	setup_portbase = ints[0] >= 1 ? ints[1] : 0;	/* Preserve the default value.. */
+	setup_buson[setup_idx] = ints[0] >= 2 ? ints[2] : 7;
+	setup_busoff[setup_idx] = ints[0] >= 3 ? ints[3] : 5;
+	if (ints[0] >= 4) 
+	{
+		int atbt = -1;
+		switch (ints[4]) {
+		case 5:
+			atbt = 0x00;
+			break;
+		case 6:
+			atbt = 0x04;
+			break;
+		case 7:
+			atbt = 0x01;
+			break;
+		case 8:
+			atbt = 0x02;
+			break;
+		case 10:
+			atbt = 0x03;
+			break;
+		default:
+			printk(KERN_ERR "aha1542: %s\n", str);
+			printk(ahausage);
+			printk(KERN_ERR "aha1542: Valid values for DMASPEED are 5-8, 10 MB/s.  Using jumper defaults.\n");
+			break;
+		}
+		setup_dmaspeed[setup_idx] = atbt;
+	}
+	if (setup_portbase != 0)
+		bases[setup_idx] = setup_portbase;
+
+	++setup_idx;
+}
+
+static int __init do_setup(char *str)
+{
+	int ints[5];
+
+	int count=setup_idx;
+
+	get_options(str, sizeof(ints)/sizeof(int), ints);
+	aha1542_setup(str,ints);
+
+	return count<setup_idx;
+}
+
+__setup("aha1542=",do_setup);
+#endif
+
+/* return non-zero on detection */
+static int __init aha1542_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned char dma_chan;
+	unsigned char irq_level;
+	unsigned char scsi_id;
+	unsigned long flags;
+	unsigned int base_io;
+	int trans;
+	struct Scsi_Host *shpnt = NULL;
+	int count = 0;
+	int indx;
+
+	DEB(printk("aha1542_detect: \n"));
+
+	tpnt->proc_name = "aha1542";
+
+#ifdef MODULE
+	bases[0] = aha1542[0];
+	setup_buson[0] = aha1542[1];
+	setup_busoff[0] = aha1542[2];
+	{
+		int atbt = -1;
+		switch (aha1542[3]) {
+		case 5:
+			atbt = 0x00;
+			break;
+		case 6:
+			atbt = 0x04;
+			break;
+		case 7:
+			atbt = 0x01;
+			break;
+		case 8:
+			atbt = 0x02;
+			break;
+		case 10:
+			atbt = 0x03;
+			break;
+		};
+		setup_dmaspeed[0] = atbt;
+	}
+#endif
+
+	/*
+	 *	Find MicroChannel cards (AHA1640)
+	 */
+#ifdef CONFIG_MCA_LEGACY
+	if(MCA_bus) {
+		int slot = 0;
+		int pos = 0;
+
+		for (indx = 0; (slot !=  MCA_NOTFOUND) && 
+			     (indx < sizeof(bases)/sizeof(bases[0])); indx++) {
+
+			if (bases[indx])
+				continue;
+
+			/* Detect only AHA-1640 cards -- MCA ID 0F1F */
+			slot = mca_find_unused_adapter(0x0f1f, slot);
+			if (slot == MCA_NOTFOUND)
+				break;
+
+			
+			/* Found one */
+			pos = mca_read_stored_pos(slot, 3);
+			
+			/* Decode address */
+			if (pos & 0x80) {
+				if (pos & 0x02) {
+					if (pos & 0x01)
+						bases[indx] = 0x334;
+					else
+						bases[indx] = 0x234;
+				} else {
+					if (pos & 0x01)
+						bases[indx] = 0x134;
+				}
+			} else {
+				if (pos & 0x02) {
+					if (pos & 0x01)
+						bases[indx] = 0x330;
+					else
+						bases[indx] = 0x230;
+				} else {
+					if (pos & 0x01)
+						bases[indx] = 0x130;
+				}
+			}
+
+			/* No need to decode IRQ and Arb level -- those are
+			 * read off the card later.
+			 */
+			printk(KERN_INFO "Found an AHA-1640 in MCA slot %d, I/O 0x%04x\n", slot, bases[indx]);
+
+			mca_set_adapter_name(slot, "Adapter AHA-1640");
+			mca_set_adapter_procfn(slot, NULL, NULL);
+			mca_mark_as_used(slot);
+			
+			/* Go on */
+			slot++;
+		}
+		
+	}
+#endif
+
+	/*
+	 *	Hunt for ISA Plug'n'Pray Adaptecs (AHA1535)
+	 */
+	 
+	if(isapnp)
+	{
+		struct pnp_dev *pdev = NULL;
+		for(indx = 0; indx <sizeof(bases)/sizeof(bases[0]);indx++)
+		{
+			if(bases[indx])
+				continue;
+			pdev = pnp_find_dev(NULL, ISAPNP_VENDOR('A', 'D', 'P'), 
+				ISAPNP_FUNCTION(0x1542), pdev);
+			if(pdev==NULL)
+				break;
+			/*
+			 *	Activate the PnP card
+			 */
+			 
+			if(pnp_device_attach(pdev)<0)
+				continue;
+			
+			if(pnp_activate_dev(pdev)<0) {
+				pnp_device_detach(pdev);
+				continue;
+			}
+			
+			if(!pnp_port_valid(pdev, 0)) {
+				pnp_device_detach(pdev);
+				continue;
+			}
+				
+			bases[indx] = pnp_port_start(pdev, 0);
+			
+			/* The card can be queried for its DMA, we have 
+			   the DMA set up that is enough */
+			   
+			printk(KERN_INFO "ISAPnP found an AHA1535 at I/O 0x%03X\n", bases[indx]);
+		}
+	}
+	for (indx = 0; indx < sizeof(bases) / sizeof(bases[0]); indx++)
+		if (bases[indx] != 0 && request_region(bases[indx], 4, "aha1542")) {
+			shpnt = scsi_register(tpnt,
+					sizeof(struct aha1542_hostdata));
+
+			if(shpnt==NULL) {
+				release_region(bases[indx], 4);
+				continue;
+			}
+			/* For now we do this - until kmalloc is more intelligent
+			   we are resigned to stupid hacks like this */
+			if (SCSI_BUF_PA(shpnt) >= ISA_DMA_THRESHOLD) {
+				printk(KERN_ERR "Invalid address for shpnt with 1542.\n");
+				goto unregister;
+			}
+			if (!aha1542_test_port(bases[indx], shpnt))
+				goto unregister;
+
+
+			base_io = bases[indx];
+
+			/* Set the Bus on/off-times as not to ruin floppy performance */
+			{
+				unchar oncmd[] = {CMD_BUSON_TIME, 7};
+				unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+				if (setup_called[indx]) {
+					oncmd[1] = setup_buson[indx];
+					offcmd[1] = setup_busoff[indx];
+				}
+				aha1542_intr_reset(base_io);
+				aha1542_out(base_io, oncmd, 2);
+				WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				aha1542_intr_reset(base_io);
+				aha1542_out(base_io, offcmd, 2);
+				WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				if (setup_dmaspeed[indx] >= 0) {
+					unchar dmacmd[] = {CMD_DMASPEED, 0};
+					dmacmd[1] = setup_dmaspeed[indx];
+					aha1542_intr_reset(base_io);
+					aha1542_out(base_io, dmacmd, 2);
+					WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+				}
+				while (0) {
+fail:
+					printk(KERN_ERR "aha1542_detect: setting bus on/off-time failed\n");
+				}
+				aha1542_intr_reset(base_io);
+			}
+			if (aha1542_query(base_io, &trans))
+				goto unregister;
+
+			if (aha1542_getconfig(base_io, &irq_level, &dma_chan, &scsi_id) == -1)
+				goto unregister;
+
+			printk(KERN_INFO "Configuring Adaptec (SCSI-ID %d) at IO:%x, IRQ %d", scsi_id, base_io, irq_level);
+			if (dma_chan != 0xFF)
+				printk(", DMA priority %d", dma_chan);
+			printk("\n");
+
+			DEB(aha1542_stat());
+			setup_mailboxes(base_io, shpnt);
+
+			DEB(aha1542_stat());
+
+			DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
+			spin_lock_irqsave(&aha1542_lock, flags);
+			if (request_irq(irq_level, do_aha1542_intr_handle, 0, "aha1542", NULL)) {
+				printk(KERN_ERR "Unable to allocate IRQ for adaptec controller.\n");
+				spin_unlock_irqrestore(&aha1542_lock, flags);
+				goto unregister;
+			}
+			if (dma_chan != 0xFF) {
+				if (request_dma(dma_chan, "aha1542")) {
+					printk(KERN_ERR "Unable to allocate DMA channel for Adaptec.\n");
+					free_irq(irq_level, NULL);
+					spin_unlock_irqrestore(&aha1542_lock, flags);
+					goto unregister;
+				}
+				if (dma_chan == 0 || dma_chan >= 5) {
+					set_dma_mode(dma_chan, DMA_MODE_CASCADE);
+					enable_dma(dma_chan);
+				}
+			}
+			aha_host[irq_level - 9] = shpnt;
+			shpnt->this_id = scsi_id;
+			shpnt->unique_id = base_io;
+			shpnt->io_port = base_io;
+			shpnt->n_io_port = 4;	/* Number of bytes of I/O space used */
+			shpnt->dma_channel = dma_chan;
+			shpnt->irq = irq_level;
+			HOSTDATA(shpnt)->bios_translation = trans;
+			if (trans == BIOS_TRANSLATION_25563)
+				printk(KERN_INFO "aha1542.c: Using extended bios translation\n");
+			HOSTDATA(shpnt)->aha1542_last_mbi_used = (2 * AHA1542_MAILBOXES - 1);
+			HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
+			memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+#if 0
+			DEB(printk(" *** READ CAPACITY ***\n"));
+
+			{
+				unchar buf[8];
+				static unchar cmd[] = { READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+				int i;
+
+				for (i = 0; i < sizeof(buf); ++i)
+					buf[i] = 0x87;
+				for (i = 0; i < 2; ++i)
+					if (!aha1542_command(i, cmd, buf, sizeof(buf))) {
+						printk(KERN_DEBUG "aha_detect: LU %d sector_size %d device_size %d\n",
+						       i, xscsi2int(buf + 4), xscsi2int(buf));
+					}
+			}
+
+			DEB(printk(" *** NOW RUNNING MY OWN TEST *** \n"));
+
+			for (i = 0; i < 4; ++i) {
+				unsigned char cmd[10];
+				static buffer[512];
+
+				cmd[0] = READ_10;
+				cmd[1] = 0;
+				xany2scsi(cmd + 2, i);
+				cmd[6] = 0;
+				cmd[7] = 0;
+				cmd[8] = 1;
+				cmd[9] = 0;
+				aha1542_command(0, cmd, buffer, 512);
+			}
+#endif
+			count++;
+			continue;
+unregister:
+			release_region(bases[indx], 4);
+			scsi_unregister(shpnt);
+			continue;
+
+		};
+
+	return count;
+}
+
+static int aha1542_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static int aha1542_restart(struct Scsi_Host *shost)
+{
+	int i;
+	int count = 0;
+#if 0
+	unchar ahacmd = CMD_START_SCSI;
+#endif
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++)
+		if (HOSTDATA(shost)->SCint[i] &&
+		    !(HOSTDATA(shost)->SCint[i]->device->soft_reset)) {
+#if 0
+			HOSTDATA(shost)->mb[i].status = 1;	/* Indicate ready to restart... */
+#endif
+			count++;
+		}
+	printk(KERN_DEBUG "Potential to restart %d stalled commands...\n", count);
+#if 0
+	/* start scsi command */
+	if (count)
+		aha1542_out(shost->io_port, &ahacmd, 1);
+#endif
+	return 0;
+}
+
+static int aha1542_abort(Scsi_Cmnd * SCpnt)
+{
+
+	/*
+	 * The abort command does not leave the device in a clean state where
+	 *  it is available to be used again.  Until this gets worked out, we
+	 * will leave it commented out.  
+	 */
+
+	printk(KERN_ERR "aha1542.c: Unable to abort command for target %d\n",
+	       SCpnt->device->id);
+	return FAILED;
+}
+
+/*
+ * This is a device reset.  This is handled by sending a special command
+ * to the device.
+ */
+static int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+{
+	unsigned long flags;
+	struct mailbox *mb;
+	unchar target = SCpnt->device->id;
+	unchar lun = SCpnt->device->lun;
+	int mbo;
+	struct ccb *ccb;
+	unchar ahacmd = CMD_START_SCSI;
+
+	ccb = HOSTDATA(SCpnt->device->host)->ccb;
+	mb = HOSTDATA(SCpnt->device->host)->mb;
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mbo = HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used + 1;
+	if (mbo >= AHA1542_MAILBOXES)
+		mbo = 0;
+
+	do {
+		if (mb[mbo].status == 0 && HOSTDATA(SCpnt->device->host)->SCint[mbo] == NULL)
+			break;
+		mbo++;
+		if (mbo >= AHA1542_MAILBOXES)
+			mbo = 0;
+	} while (mbo != HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used);
+
+	if (mb[mbo].status || HOSTDATA(SCpnt->device->host)->SCint[mbo])
+		panic("Unable to find empty mailbox for aha1542.\n");
+
+	HOSTDATA(SCpnt->device->host)->SCint[mbo] = SCpnt;	/* This will effectively
+							   prevent someone else from
+							   screwing with this cdb. */
+
+	HOSTDATA(SCpnt->device->host)->aha1542_last_mbo_used = mbo;
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+	any2scsi(mb[mbo].ccbptr, SCSI_BUF_PA(&ccb[mbo]));	/* This gets trashed for some reason */
+
+	memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+	ccb[mbo].op = 0x81;	/* BUS DEVICE RESET */
+
+	ccb[mbo].idlun = (target & 7) << 5 | (lun & 7);		/*SCSI Target Id */
+
+	ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+	ccb[mbo].commlinkid = 0;
+
+	/* 
+	 * Now tell the 1542 to flush all pending commands for this 
+	 * target 
+	 */
+	aha1542_out(SCpnt->device->host->io_port, &ahacmd, 1);
+
+	printk(KERN_WARNING "aha1542.c: Trying device reset for target %d\n", SCpnt->device->id);
+
+	return SUCCESS;
+
+
+#ifdef ERIC_neverdef
+	/* 
+	 * With the 1542 we apparently never get an interrupt to
+	 * acknowledge a device reset being sent.  Then again, Leonard
+	 * says we are doing this wrong in the first place...
+	 *
+	 * Take a wait and see attitude.  If we get spurious interrupts,
+	 * then the device reset is doing something sane and useful, and
+	 * we will wait for the interrupt to post completion.
+	 */
+	printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+	/*
+	 * Free the command block for all commands running on this 
+	 * target... 
+	 */
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->host)->SCint[i] &&
+		    HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->host)->mb[i].status = 0;
+		}
+	}
+	return SUCCESS;
+
+	return FAILED;
+#endif				/* ERIC_neverdef */
+}
+
+static int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	int i;
+
+	/* 
+	 * This does a scsi reset for all devices on the bus.
+	 * In principle, we could also reset the 1542 - should
+	 * we do this?  Try this first, and we can add that later
+	 * if it turns out to be useful.
+	 */
+	outb(SCRST, CONTROL(SCpnt->device->host->io_port));
+
+	/*
+	 * Wait for the thing to settle down a bit.  Unfortunately
+	 * this is going to basically lock up the machine while we
+	 * wait for this to complete.  To be 100% correct, we need to
+	 * check for timeout, and if we are doing something like this
+	 * we are pretty desperate anyways.
+	 */
+	spin_unlock_irq(SCpnt->device->host->host_lock);
+	ssleep(4);
+	spin_lock_irq(SCpnt->device->host->host_lock);
+
+	WAIT(STATUS(SCpnt->device->host->io_port),
+	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	/*
+	 * Now try to pick up the pieces.  For all pending commands,
+	 * free any internal data structures, and basically clear things
+	 * out.  We do not try and restart any commands or anything - 
+	 * the strategy handler takes care of that crap.
+	 */
+	printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no);
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i];
+
+
+			if (SCtmp->device->soft_reset) {
+				/*
+				 * If this device implements the soft reset option,
+				 * then it is still holding onto the command, and
+				 * may yet complete it.  In this case, we don't
+				 * flush the data.
+				 */
+				continue;
+			}
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->device->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->device->host)->mb[i].status = 0;
+		}
+	}
+
+	return SUCCESS;
+
+fail:
+	return FAILED;
+}
+
+static int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+{
+	int i;
+
+	/* 
+	 * This does a scsi reset for all devices on the bus.
+	 * In principle, we could also reset the 1542 - should
+	 * we do this?  Try this first, and we can add that later
+	 * if it turns out to be useful.
+	 */
+	outb(HRST | SCRST, CONTROL(SCpnt->device->host->io_port));
+
+	/*
+	 * Wait for the thing to settle down a bit.  Unfortunately
+	 * this is going to basically lock up the machine while we
+	 * wait for this to complete.  To be 100% correct, we need to
+	 * check for timeout, and if we are doing something like this
+	 * we are pretty desperate anyways.
+	 */
+	spin_unlock_irq(SCpnt->device->host->host_lock);
+	ssleep(4);
+	spin_lock_irq(SCpnt->device->host->host_lock);
+
+	WAIT(STATUS(SCpnt->device->host->io_port),
+	     STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+	/*
+	 * We need to do this too before the 1542 can interact with
+	 * us again.
+	 */
+	setup_mailboxes(SCpnt->device->host->io_port, SCpnt->device->host);
+
+	/*
+	 * Now try to pick up the pieces.  For all pending commands,
+	 * free any internal data structures, and basically clear things
+	 * out.  We do not try and restart any commands or anything - 
+	 * the strategy handler takes care of that crap.
+	 */
+	printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->device->host->host_no);
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++) {
+		if (HOSTDATA(SCpnt->device->host)->SCint[i] != NULL) {
+			Scsi_Cmnd *SCtmp;
+			SCtmp = HOSTDATA(SCpnt->device->host)->SCint[i];
+
+			if (SCtmp->device->soft_reset) {
+				/*
+				 * If this device implements the soft reset option,
+				 * then it is still holding onto the command, and
+				 * may yet complete it.  In this case, we don't
+				 * flush the data.
+				 */
+				continue;
+			}
+			if (SCtmp->host_scribble) {
+				kfree(SCtmp->host_scribble);
+				SCtmp->host_scribble = NULL;
+			}
+			HOSTDATA(SCpnt->device->host)->SCint[i] = NULL;
+			HOSTDATA(SCpnt->device->host)->mb[i].status = 0;
+		}
+	}
+
+	return SUCCESS;
+
+fail:
+	return FAILED;
+}
+
+#if 0
+/*
+ * These are the old error handling routines.  They are only temporarily
+ * here while we play with the new error handling code.
+ */
+static int aha1542_old_abort(Scsi_Cmnd * SCpnt)
+{
+#if 0
+	unchar ahacmd = CMD_START_SCSI;
+	unsigned long flags;
+	struct mailbox *mb;
+	int mbi, mbo, i;
+
+	printk(KERN_DEBUG "In aha1542_abort: %x %x\n",
+	       inb(STATUS(SCpnt->host->io_port)),
+	       inb(INTRFLAGS(SCpnt->host->io_port)));
+
+	spin_lock_irqsave(&aha1542_lock, flags);
+	mb = HOSTDATA(SCpnt->host)->mb;
+	mbi = HOSTDATA(SCpnt->host)->aha1542_last_mbi_used + 1;
+	if (mbi >= 2 * AHA1542_MAILBOXES)
+		mbi = AHA1542_MAILBOXES;
+
+	do {
+		if (mb[mbi].status != 0)
+			break;
+		mbi++;
+		if (mbi >= 2 * AHA1542_MAILBOXES)
+			mbi = AHA1542_MAILBOXES;
+	} while (mbi != HOSTDATA(SCpnt->host)->aha1542_last_mbi_used);
+	spin_unlock_irqrestore(&aha1542_lock, flags);
+
+	if (mb[mbi].status) {
+		printk(KERN_ERR "Lost interrupt discovered on irq %d - attempting to recover\n",
+		       SCpnt->host->irq);
+		aha1542_intr_handle(SCpnt->host, NULL);
+		return 0;
+	}
+	/* OK, no lost interrupt.  Try looking to see how many pending commands
+	   we think we have. */
+
+	for (i = 0; i < AHA1542_MAILBOXES; i++)
+		if (HOSTDATA(SCpnt->host)->SCint[i]) {
+			if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+				printk(KERN_ERR "Timed out command pending for %s\n",
+				       SCpnt->request->rq_disk ?
+				       SCpnt->request->rq_disk->disk_name : "?"
+				       );
+				if (HOSTDATA(SCpnt->host)->mb[i].status) {
+					printk(KERN_ERR "OGMB still full - restarting\n");
+					aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+				};
+			} else
+				printk(KERN_ERR "Other pending command %s\n",
+				       SCpnt->request->rq_disk ?
+				       SCpnt->request->rq_disk->disk_name : "?"
+				       );
+		}
+#endif
+
+	DEB(printk("aha1542_abort\n"));
+#if 0
+	spin_lock_irqsave(&aha1542_lock, flags);
+	for (mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) {
+		if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]) {
+			mb[mbo].status = 2;	/* Abort command */
+			aha1542_out(SCpnt->host->io_port, &ahacmd, 1);	/* start scsi command */
+			spin_unlock_irqrestore(&aha1542_lock, flags);
+			break;
+		}
+	}
+	if (AHA1542_MAILBOXES == mbo)
+		spin_unlock_irqrestore(&aha1542_lock, flags);
+#endif
+	return SCSI_ABORT_SNOOZE;
+}
+
+/* We do not implement a reset function here, but the upper level code
+   assumes that it will get some kind of response for the command in
+   SCpnt.  We must oblige, or the command will hang the scsi system.
+   For a first go, we assume that the 1542 notifies us with all of the
+   pending commands (it does implement soft reset, after all). */
+
+static int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+	unchar ahacmd = CMD_START_SCSI;
+	int i;
+
+	/*
+	 * See if a bus reset was suggested.
+	 */
+	if (reset_flags & SCSI_RESET_SUGGEST_BUS_RESET) {
+		/* 
+		 * This does a scsi reset for all devices on the bus.
+		 * In principle, we could also reset the 1542 - should
+		 * we do this?  Try this first, and we can add that later
+		 * if it turns out to be useful.
+		 */
+		outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+
+		/*
+		 * Wait for the thing to settle down a bit.  Unfortunately
+		 * this is going to basically lock up the machine while we
+		 * wait for this to complete.  To be 100% correct, we need to
+		 * check for timeout, and if we are doing something like this
+		 * we are pretty desperate anyways.
+		 */
+		WAIT(STATUS(SCpnt->host->io_port),
+		STATMASK, INIT | IDLE, STST | DIAGF | INVDCMD | DF | CDF);
+
+		/*
+		 * We need to do this too before the 1542 can interact with
+		 * us again.
+		 */
+		setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+		/*
+		 * Now try to pick up the pieces.  Restart all commands
+		 * that are currently active on the bus, and reset all of
+		 * the datastructures.  We have some time to kill while
+		 * things settle down, so print a nice message.
+		 */
+		printk(KERN_WARNING "Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+		for (i = 0; i < AHA1542_MAILBOXES; i++)
+			if (HOSTDATA(SCpnt->host)->SCint[i] != NULL) {
+				Scsi_Cmnd *SCtmp;
+				SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+				SCtmp->result = DID_RESET << 16;
+				if (SCtmp->host_scribble) {
+					kfree(SCtmp->host_scribble);
+					SCtmp->host_scribble = NULL;
+				}
+				printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+				SCtmp->scsi_done(SCpnt);
+
+				HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+				HOSTDATA(SCpnt->host)->mb[i].status = 0;
+			}
+		/*
+		 * Now tell the mid-level code what we did here.  Since
+		 * we have restarted all of the outstanding commands,
+		 * then report SUCCESS.
+		 */
+		return (SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET);
+fail:
+		printk(KERN_CRIT "aha1542.c: Unable to perform hard reset.\n");
+		printk(KERN_CRIT "Power cycle machine to reset\n");
+		return (SCSI_RESET_ERROR | SCSI_RESET_BUS_RESET);
+
+
+	} else {
+		/* This does a selective reset of just the one device */
+		/* First locate the ccb for this command */
+		for (i = 0; i < AHA1542_MAILBOXES; i++)
+			if (HOSTDATA(SCpnt->host)->SCint[i] == SCpnt) {
+				HOSTDATA(SCpnt->host)->ccb[i].op = 0x81;	/* BUS DEVICE RESET */
+				/* Now tell the 1542 to flush all pending commands for this target */
+				aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+				/* Here is the tricky part.  What to do next.  Do we get an interrupt
+				   for the commands that we aborted with the specified target, or
+				   do we generate this on our own?  Try it without first and see
+				   what happens */
+				printk(KERN_WARNING "Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+				/* If the first does not work, then try the second.  I think the
+				   first option is more likely to be correct. Free the command
+				   block for all commands running on this target... */
+				for (i = 0; i < AHA1542_MAILBOXES; i++)
+					if (HOSTDATA(SCpnt->host)->SCint[i] &&
+					    HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target) {
+						Scsi_Cmnd *SCtmp;
+						SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+						SCtmp->result = DID_RESET << 16;
+						if (SCtmp->host_scribble) {
+							kfree(SCtmp->host_scribble);
+							SCtmp->host_scribble = NULL;
+						}
+						printk(KERN_WARNING "Sending DID_RESET for target %d\n", SCpnt->target);
+						SCtmp->scsi_done(SCpnt);
+
+						HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+						HOSTDATA(SCpnt->host)->mb[i].status = 0;
+					}
+				return SCSI_RESET_SUCCESS;
+			}
+	}
+	/* No active command at this time, so this means that each time we got
+	   some kind of response the last time through.  Tell the mid-level code
+	   to request sense information in order to decide what to do next. */
+	return SCSI_RESET_PUNT;
+}
+#endif    /* end of big comment block around old_abort + old_reset */
+
+static int aha1542_biosparam(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int *ip)
+{
+	int translation_algorithm;
+	int size = capacity;
+
+	translation_algorithm = HOSTDATA(sdev->host)->bios_translation;
+
+	if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) {
+		/* Please verify that this is the same as what DOS returns */
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / 255 / 63;
+	} else {
+		ip[0] = 64;
+		ip[1] = 32;
+		ip[2] = size >> 11;
+	}
+
+	return 0;
+}
+MODULE_LICENSE("GPL");
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "aha1542",
+	.name			= "Adaptec 1542",
+	.detect			= aha1542_detect,
+	.release		= aha1542_release,
+	.queuecommand		= aha1542_queuecommand,
+	.eh_abort_handler	= aha1542_abort,
+	.eh_device_reset_handler= aha1542_dev_reset,
+	.eh_bus_reset_handler	= aha1542_bus_reset,
+	.eh_host_reset_handler	= aha1542_host_reset,
+	.bios_param		= aha1542_biosparam,
+	.can_queue		= AHA1542_MAILBOXES, 
+	.this_id		= 7,
+	.sg_tablesize		= AHA1542_SCATTER,
+	.cmd_per_lun		= AHA1542_CMDLUN,
+	.unchecked_isa_dma	= 1, 
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
new file mode 100644
index 0000000..c402351
--- /dev/null
+++ b/drivers/scsi/aha1542.h
@@ -0,0 +1,151 @@
+#ifndef _AHA1542_H
+
+/* $Id: aha1542.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ *
+ * Header file for the adaptec 1542 driver for Linux
+ *
+ * $Log: aha1542.h,v $
+ * Revision 1.1  1992/07/24  06:27:38  root
+ * Initial revision
+ *
+ * Revision 1.2  1992/07/04  18:41:49  root
+ * Replaced distribution with current drivers
+ *
+ * Revision 1.3  1992/06/23  23:58:20  root
+ * Fixes.
+ *
+ * Revision 1.2  1992/05/26  22:13:23  root
+ * Changed bug that prevented DMA above first 2 mbytes.
+ *
+ * Revision 1.1  1992/05/22  21:00:29  root
+ * Initial revision
+ *
+ * Revision 1.1  1992/04/24  18:01:50  root
+ * Initial revision
+ *
+ * Revision 1.1  1992/04/02  03:23:13  drew
+ * Initial revision
+ *
+ * Revision 1.3  1992/01/27  14:46:29  tthorn
+ * *** empty log message ***
+ *
+ */
+
+#include <linux/types.h>
+
+/* I/O Port interface 4.2 */
+/* READ */
+#define STATUS(base) base
+#define STST	0x80		/* Self Test in Progress */
+#define DIAGF	0x40		/* Internal Diagnostic Failure */
+#define INIT	0x20		/* Mailbox Initialization Required */
+#define IDLE	0x10		/* SCSI Host Adapter Idle */
+#define CDF	0x08		/* Command/Data Out Port Full */
+#define DF	0x04		/* Data In Port Full */
+#define INVDCMD	0x01		/* Invalid H A Command */
+#define STATMASK 0xfd		/* 0x02 is reserved */
+
+#define INTRFLAGS(base) (STATUS(base)+2)
+#define ANYINTR	0x80		/* Any Interrupt */
+#define SCRD	0x08		/* SCSI Reset Detected */
+#define HACC	0x04		/* HA Command Complete */
+#define MBOA	0x02		/* MBO Empty */
+#define MBIF	0x01		/* MBI Full */
+#define INTRMASK 0x8f
+
+/* WRITE */
+#define CONTROL(base) STATUS(base)
+#define HRST	0x80		/* Hard Reset */
+#define SRST	0x40		/* Soft Reset */
+#define IRST	0x20		/* Interrupt Reset */
+#define SCRST	0x10		/* SCSI Bus Reset */
+
+/* READ/WRITE */
+#define DATA(base) (STATUS(base)+1)
+#define CMD_NOP		0x00	/* No Operation */
+#define CMD_MBINIT	0x01	/* Mailbox Initialization */
+#define CMD_START_SCSI	0x02	/* Start SCSI Command */
+#define CMD_INQUIRY	0x04	/* Adapter Inquiry */
+#define CMD_EMBOI	0x05	/* Enable MailBox Out Interrupt */
+#define CMD_BUSON_TIME	0x07	/* Set Bus-On Time */
+#define CMD_BUSOFF_TIME	0x08	/* Set Bus-Off Time */
+#define CMD_DMASPEED	0x09	/* Set AT Bus Transfer Speed */
+#define CMD_RETDEVS	0x0a	/* Return Installed Devices */
+#define CMD_RETCONF	0x0b	/* Return Configuration Data */
+#define CMD_RETSETUP	0x0d	/* Return Setup Data */
+#define CMD_ECHO	0x1f	/* ECHO Command Data */
+
+#define CMD_EXTBIOS     0x28    /* Return extend bios information only 1542C */
+#define CMD_MBENABLE    0x29    /* Set Mailbox Interface enable only 1542C */
+
+/* Mailbox Definition 5.2.1 and 5.2.2 */
+struct mailbox {
+  unchar status;		/* Command/Status */
+  unchar ccbptr[3];		/* msb, .., lsb */
+};
+
+/* This is used with scatter-gather */
+struct chain {
+  unchar datalen[3];		/* Size of this part of chain */
+  unchar dataptr[3];		/* Location of data */
+};
+
+/* These belong in scsi.h also */
+static inline void any2scsi(u8 *p, u32 v)
+{
+	p[0] = v >> 16;
+	p[1] = v >> 8;
+	p[2] = v;
+}
+
+#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
+
+#define xany2scsi(up, p)	\
+(up)[0] = ((long)(p)) >> 24;	\
+(up)[1] = ((long)(p)) >> 16;	\
+(up)[2] = ((long)(p)) >> 8;	\
+(up)[3] = ((long)(p));
+
+#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+		      + (((long)(up)[2]) <<  8) +  ((long)(up)[3]) )
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+
+struct ccb {			/* Command Control Block 5.3 */
+  unchar op;			/* Command Control Block Operation Code */
+  unchar idlun;			/* op=0,2:Target Id, op=1:Initiator Id */
+				/* Outbound data transfer, length is checked*/
+				/* Inbound data transfer, length is checked */
+				/* Logical Unit Number */
+  unchar cdblen;		/* SCSI Command Length */
+  unchar rsalen;		/* Request Sense Allocation Length/Disable */
+  unchar datalen[3];		/* Data Length (msb, .., lsb) */
+  unchar dataptr[3];		/* Data Pointer */
+  unchar linkptr[3];		/* Link Pointer */
+  unchar commlinkid;		/* Command Linking Identifier */
+  unchar hastat;		/* Host Adapter Status (HASTAT) */
+  unchar tarstat;		/* Target Device Status */
+  unchar reserved[2];
+  unchar cdb[MAX_CDB+MAX_SENSE];/* SCSI Command Descriptor Block */
+				/* REQUEST SENSE */
+};
+
+static int aha1542_detect(Scsi_Host_Template *);
+static int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int aha1542_abort(Scsi_Cmnd * SCpnt);
+static int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
+static int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
+static int aha1542_host_reset(Scsi_Cmnd * SCpnt);
+#if 0
+static int aha1542_old_abort(Scsi_Cmnd * SCpnt);
+static int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
+#endif
+static int aha1542_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int *);
+
+#define AHA1542_MAILBOXES 8
+#define AHA1542_SCATTER 16
+#define AHA1542_CMDLUN 1
+
+#endif
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
new file mode 100644
index 0000000..73f33e7
--- /dev/null
+++ b/drivers/scsi/aha1740.c
@@ -0,0 +1,707 @@
+/*  $Id$
+ *  1993/03/31
+ *  linux/kernel/aha1740.c
+ *
+ *  Based loosely on aha1542.c which is
+ *  Copyright (C) 1992  Tommy Thorn and
+ *  Modified by Eric Youngdale
+ *
+ *  This file is aha1740.c, written and
+ *  Copyright (C) 1992,1993  Brad McLean
+ *  brad@saturn.gaylord.com or brad@bradpc.gaylord.com.
+ *  
+ *  Modifications to makecode and queuecommand
+ *  for proper handling of multiple devices courteously
+ *  provided by Michael Weller, March, 1993
+ *
+ *  Multiple adapter support, extended translation detection,
+ *  update to current scsi subsystem changes, proc fs support,
+ *  working (!) module support based on patches from Andreas Arens,
+ *  by Andreas Degert <ad@papyrus.hamburg.com>, 2/1997
+ *
+ * aha1740_makecode may still need even more work
+ * if it doesn't work for your devices, take a look.
+ *
+ * Reworked for new_eh and new locking by Alan Cox <alan@redhat.com>
+ *
+ * Converted to EISA and generic DMA APIs by Marc Zyngier
+ * <maz@wild-wind.fr.eu.org>, 4/2003.
+ *
+ * Shared interrupt support added by Rask Ingemann Lambertsen
+ * <rask@sygehus.dk>, 10/2003
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/eisa.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha1740.h"
+
+/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH
+   IT WORK, THEN:
+#define DEBUG
+*/
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+struct aha1740_hostdata {
+	struct eisa_device *edev;
+	unsigned int translation;
+	unsigned int last_ecb_used;
+	dma_addr_t ecb_dma_addr;
+	struct ecb ecb[AHA1740_ECBS];
+};
+
+struct aha1740_sg {
+	struct aha1740_chain sg_chain[AHA1740_SCATTER];
+	dma_addr_t sg_dma_addr;
+	dma_addr_t buf_dma_addr;
+};
+
+#define HOSTDATA(host) ((struct aha1740_hostdata *) &host->hostdata)
+
+static inline struct ecb *ecb_dma_to_cpu (struct Scsi_Host *host,
+					  dma_addr_t dma)
+{
+	struct aha1740_hostdata *hdata = HOSTDATA (host);
+	dma_addr_t offset;
+
+	offset = dma - hdata->ecb_dma_addr;
+
+	return (struct ecb *)(((char *) hdata->ecb) + (unsigned int) offset);
+}
+
+static inline dma_addr_t ecb_cpu_to_dma (struct Scsi_Host *host, void *cpu)
+{
+	struct aha1740_hostdata *hdata = HOSTDATA (host);
+	dma_addr_t offset;
+    
+	offset = (char *) cpu - (char *) hdata->ecb;
+
+	return hdata->ecb_dma_addr + offset;
+}
+
+static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer,
+			     char **start, off_t offset,
+			     int length, int inout)
+{
+	int len;
+	struct aha1740_hostdata *host;
+
+	if (inout)
+		return-ENOSYS;
+
+	host = HOSTDATA(shpnt);
+
+	len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n"
+		      "Extended translation %sabled.\n",
+		      shpnt->io_port, shpnt->irq, host->edev->slot,
+		      host->translation ? "en" : "dis");
+
+	if (offset > len) {
+		*start = buffer;
+		return 0;
+	}
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	return len;
+}
+
+static int aha1740_makecode(unchar *sense, unchar *status)
+{
+	struct statusword
+	{
+		ushort	don:1,	/* Command Done - No Error */
+			du:1,	/* Data underrun */
+		    :1,	qf:1,	/* Queue full */
+		        sc:1,	/* Specification Check */
+		        dor:1,	/* Data overrun */
+		        ch:1,	/* Chaining Halted */
+		        intr:1,	/* Interrupt issued */
+		        asa:1,	/* Additional Status Available */
+		        sns:1,	/* Sense information Stored */
+		    :1,	ini:1,	/* Initialization Required */
+			me:1,	/* Major error or exception */
+		    :1,	eca:1,  /* Extended Contingent alliance */
+		    :1;
+	} status_word;
+	int retval = DID_OK;
+
+	status_word = * (struct statusword *) status;
+#ifdef DEBUG
+	printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",
+	       status[0], status[1], status[2], status[3],
+	       sense[0], sense[1], sense[2], sense[3]);
+#endif
+	if (!status_word.don) { /* Anything abnormal was detected */
+		if ( (status[1]&0x18) || status_word.sc ) {
+			/*Additional info available*/
+			/* Use the supplied info for further diagnostics */
+			switch ( status[2] ) {
+			case 0x12:
+				if ( status_word.dor )
+					retval=DID_ERROR; /* It's an Overrun */
+				/* If not overrun, assume underrun and
+				 * ignore it! */
+			case 0x00: /* No info, assume no error, should
+				    * not occur */
+				break;
+			case 0x11:
+			case 0x21:
+				retval=DID_TIME_OUT;
+				break;
+			case 0x0a:
+				retval=DID_BAD_TARGET;
+				break;
+			case 0x04:
+			case 0x05:
+				retval=DID_ABORT;
+				/* Either by this driver or the
+				 * AHA1740 itself */
+				break;
+			default:
+				retval=DID_ERROR; /* No further
+						   * diagnostics
+						   * possible */
+			}
+		} else {
+			/* Michael suggests, and Brad concurs: */
+			if ( status_word.qf ) {
+				retval = DID_TIME_OUT; /* forces a redo */
+				/* I think this specific one should
+				 * not happen -Brad */
+				printk("aha1740.c: WARNING: AHA1740 queue overflow!\n");
+			} else
+				if ( status[0]&0x60 ) {
+					 /* Didn't find a better error */
+					retval = DID_ERROR;
+				}
+			/* In any other case return DID_OK so for example
+			   CONDITION_CHECKS make it through to the appropriate
+			   device driver */
+		}
+	}
+	/* Under all circumstances supply the target status -Michael */
+	return status[3] | retval << 16;
+}
+
+static int aha1740_test_port(unsigned int base)
+{
+	if ( inb(PORTADR(base)) & PORTADDR_ENH )
+		return 1;   /* Okay, we're all set */
+	
+	printk("aha174x: Board detected, but not in enhanced mode, so disabled it.\n");
+	return 0;
+}
+
+/* A "high" level interrupt handler */
+static irqreturn_t aha1740_intr_handle(int irq, void *dev_id,
+				       struct pt_regs *regs)
+{
+	struct Scsi_Host *host = (struct Scsi_Host *) dev_id;
+        void (*my_done)(Scsi_Cmnd *);
+	int errstatus, adapstat;
+	int number_serviced;
+	struct ecb *ecbptr;
+	Scsi_Cmnd *SCtmp;
+	unsigned int base;
+	unsigned long flags;
+	int handled = 0;
+	struct aha1740_sg *sgptr;
+	struct eisa_device *edev;
+	
+	if (!host)
+		panic("aha1740.c: Irq from unknown host!\n");
+	spin_lock_irqsave(host->host_lock, flags);
+	base = host->io_port;
+	number_serviced = 0;
+	edev = HOSTDATA(host)->edev;
+
+	while(inb(G2STAT(base)) & G2STAT_INTPEND) {
+		handled = 1;
+		DEB(printk("aha1740_intr top of loop.\n"));
+		adapstat = inb(G2INTST(base));
+		ecbptr = ecb_dma_to_cpu (host, inl(MBOXIN0(base)));
+		outb(G2CNTRL_IRST,G2CNTRL(base)); /* interrupt reset */
+      
+		switch ( adapstat & G2INTST_MASK ) {
+		case	G2INTST_CCBRETRY:
+		case	G2INTST_CCBERROR:
+		case	G2INTST_CCBGOOD:
+			/* Host Ready -> Mailbox in complete */
+			outb(G2CNTRL_HRDY,G2CNTRL(base));
+			if (!ecbptr) {
+				printk("Aha1740 null ecbptr in interrupt (%x,%x,%x,%d)\n",
+				       inb(G2STAT(base)),adapstat,
+				       inb(G2INTST(base)), number_serviced++);
+				continue;
+			}
+			SCtmp = ecbptr->SCpnt;
+			if (!SCtmp) {
+				printk("Aha1740 null SCtmp in interrupt (%x,%x,%x,%d)\n",
+				       inb(G2STAT(base)),adapstat,
+				       inb(G2INTST(base)), number_serviced++);
+				continue;
+			}
+			sgptr = (struct aha1740_sg *) SCtmp->host_scribble;
+			if (SCtmp->use_sg) {
+				/* We used scatter-gather.
+				   Do the unmapping dance. */
+				dma_unmap_sg (&edev->dev,
+					      (struct scatterlist *) SCtmp->request_buffer,
+					      SCtmp->use_sg,
+					      SCtmp->sc_data_direction);
+			} else {
+				dma_unmap_single (&edev->dev,
+						  sgptr->buf_dma_addr,
+						  SCtmp->request_bufflen,
+						  DMA_BIDIRECTIONAL);
+			}
+	    
+			/* Free the sg block */
+			dma_free_coherent (&edev->dev,
+					   sizeof (struct aha1740_sg),
+					   SCtmp->host_scribble,
+					   sgptr->sg_dma_addr);
+	    
+			/* Fetch the sense data, and tuck it away, in
+			   the required slot.  The Adaptec
+			   automatically fetches it, and there is no
+			   guarantee that we will still have it in the
+			   cdb when we come back */
+			if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) {
+				memcpy(SCtmp->sense_buffer, ecbptr->sense, 
+				       sizeof(SCtmp->sense_buffer));
+				errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status);
+			} else
+				errstatus = 0;
+			DEB(if (errstatus)
+			    printk("aha1740_intr_handle: returning %6x\n",
+				   errstatus));
+			SCtmp->result = errstatus;
+			my_done = ecbptr->done;
+			memset(ecbptr,0,sizeof(struct ecb)); 
+			if ( my_done )
+				my_done(SCtmp);
+			break;
+			
+		case	G2INTST_HARDFAIL:
+			printk(KERN_ALERT "aha1740 hardware failure!\n");
+			panic("aha1740.c");	/* Goodbye */
+			
+		case	G2INTST_ASNEVENT:
+			printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",
+			       adapstat,
+			       inb(MBOXIN0(base)),
+			       inb(MBOXIN1(base)),
+			       inb(MBOXIN2(base)),
+			       inb(MBOXIN3(base))); /* Say What? */
+			/* Host Ready -> Mailbox in complete */
+			outb(G2CNTRL_HRDY,G2CNTRL(base));
+			break;
+			
+		case	G2INTST_CMDGOOD:
+			/* set immediate command success flag here: */
+			break;
+			
+		case	G2INTST_CMDERROR:
+			/* Set immediate command failure flag here: */
+			break;
+		}
+		number_serviced++;
+	}
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return IRQ_RETVAL(handled);
+}
+
+static int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	unchar direction;
+	unchar *cmd = (unchar *) SCpnt->cmnd;
+	unchar target = SCpnt->device->id;
+	struct aha1740_hostdata *host = HOSTDATA(SCpnt->device->host);
+	unsigned long flags;
+	void *buff = SCpnt->request_buffer;
+	int bufflen = SCpnt->request_bufflen;
+	dma_addr_t sg_dma;
+	struct aha1740_sg *sgptr;
+	int ecbno;
+	DEB(int i);
+
+	if(*cmd == REQUEST_SENSE) {
+		SCpnt->result = 0;
+		done(SCpnt); 
+		return 0;
+	}
+
+#ifdef DEBUG
+	if (*cmd == READ_10 || *cmd == WRITE_10)
+		i = xscsi2int(cmd+2);
+	else if (*cmd == READ_6 || *cmd == WRITE_6)
+		i = scsi2int(cmd+2);
+	else
+		i = -1;
+	printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ",
+	       target, *cmd, i, bufflen);
+	printk("scsi cmd:");
+	for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
+	printk("\n");
+#endif
+
+	/* locate an available ecb */
+	spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
+	ecbno = host->last_ecb_used + 1; /* An optimization */
+	if (ecbno >= AHA1740_ECBS)
+		ecbno = 0;
+	do {
+		if (!host->ecb[ecbno].cmdw)
+			break;
+		ecbno++;
+		if (ecbno >= AHA1740_ECBS)
+			ecbno = 0;
+	} while (ecbno != host->last_ecb_used);
+
+	if (host->ecb[ecbno].cmdw)
+		panic("Unable to find empty ecb for aha1740.\n");
+
+	host->ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command
+						    doubles as reserved flag */
+
+	host->last_ecb_used = ecbno;    
+	spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
+
+#ifdef DEBUG
+	printk("Sending command (%d %x)...", ecbno, done);
+#endif
+
+	host->ecb[ecbno].cdblen = SCpnt->cmd_len; /* SCSI Command
+						   * Descriptor Block
+						   * Length */
+
+	direction = 0;
+	if (*cmd == READ_10 || *cmd == READ_6)
+		direction = 1;
+	else if (*cmd == WRITE_10 || *cmd == WRITE_6)
+		direction = 0;
+
+	memcpy(host->ecb[ecbno].cdb, cmd, SCpnt->cmd_len);
+
+	SCpnt->host_scribble = dma_alloc_coherent (&host->edev->dev,
+						   sizeof (struct aha1740_sg),
+						   &sg_dma, GFP_ATOMIC);
+	if(SCpnt->host_scribble == NULL) {
+		printk(KERN_WARNING "aha1740: out of memory in queuecommand!\n");
+		return 1;
+	}
+	sgptr = (struct aha1740_sg *) SCpnt->host_scribble;
+	sgptr->sg_dma_addr = sg_dma;
+    
+	if (SCpnt->use_sg) {
+		struct scatterlist * sgpnt;
+		struct aha1740_chain * cptr;
+		int i, count;
+		DEB(unsigned char * ptr);
+
+		host->ecb[ecbno].sg = 1;  /* SCSI Initiator Command
+					   * w/scatter-gather*/
+		sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+		cptr = sgptr->sg_chain;
+		count = dma_map_sg (&host->edev->dev, sgpnt, SCpnt->use_sg,
+				    SCpnt->sc_data_direction);
+		for(i=0; i < count; i++) {
+			cptr[i].datalen = sg_dma_len (sgpnt + i);
+			cptr[i].dataptr = sg_dma_address (sgpnt + i);
+		}
+		host->ecb[ecbno].datalen = count*sizeof(struct aha1740_chain);
+		host->ecb[ecbno].dataptr = sg_dma;
+#ifdef DEBUG
+		printk("cptr %x: ",cptr);
+		ptr = (unsigned char *) cptr;
+		for(i=0;i<24;i++) printk("%02x ", ptr[i]);
+#endif
+	} else {
+		host->ecb[ecbno].datalen = bufflen;
+		sgptr->buf_dma_addr =  dma_map_single (&host->edev->dev,
+						       buff, bufflen,
+						       DMA_BIDIRECTIONAL);
+		host->ecb[ecbno].dataptr = sgptr->buf_dma_addr;
+	}
+	host->ecb[ecbno].lun = SCpnt->device->lun;
+	host->ecb[ecbno].ses = 1; /* Suppress underrun errors */
+	host->ecb[ecbno].dir = direction;
+	host->ecb[ecbno].ars = 1; /* Yes, get the sense on an error */
+	host->ecb[ecbno].senselen = 12;
+	host->ecb[ecbno].senseptr = ecb_cpu_to_dma (SCpnt->device->host,
+						    host->ecb[ecbno].sense);
+	host->ecb[ecbno].statusptr = ecb_cpu_to_dma (SCpnt->device->host,
+						     host->ecb[ecbno].status);
+	host->ecb[ecbno].done = done;
+	host->ecb[ecbno].SCpnt = SCpnt;
+#ifdef DEBUG
+	{
+		int i;
+		printk("aha1740_command: sending.. ");
+		for (i = 0; i < sizeof(host->ecb[ecbno]) - 10; i++)
+			printk("%02x ", ((unchar *)&host->ecb[ecbno])[i]);
+	}
+	printk("\n");
+#endif
+	if (done) {
+	/* The Adaptec Spec says the card is so fast that the loops
+           will only be executed once in the code below. Even if this
+           was true with the fastest processors when the spec was
+           written, it doesn't seem to be true with todays fast
+           processors. We print a warning if the code is executed more
+           often than LOOPCNT_WARN. If this happens, it should be
+           investigated. If the count reaches LOOPCNT_MAX, we assume
+           something is broken; since there is no way to return an
+           error (the return value is ignored by the mid-level scsi
+           layer) we have to panic (and maybe that's the best thing we
+           can do then anyhow). */
+
+#define LOOPCNT_WARN 10		/* excessive mbxout wait -> syslog-msg */
+#define LOOPCNT_MAX 1000000	/* mbxout deadlock -> panic() after ~ 2 sec. */
+		int loopcnt;
+		unsigned int base = SCpnt->device->host->io_port;
+		DEB(printk("aha1740[%d] critical section\n",ecbno));
+
+		spin_lock_irqsave(SCpnt->device->host->host_lock, flags);
+		for (loopcnt = 0; ; loopcnt++) {
+			if (inb(G2STAT(base)) & G2STAT_MBXOUT) break;
+			if (loopcnt == LOOPCNT_WARN) {
+				printk("aha1740[%d]_mbxout wait!\n",ecbno);
+			}
+			if (loopcnt == LOOPCNT_MAX)
+				panic("aha1740.c: mbxout busy!\n");
+		}
+		outl (ecb_cpu_to_dma (SCpnt->device->host, host->ecb + ecbno),
+		      MBOXOUT0(base));
+		for (loopcnt = 0; ; loopcnt++) {
+			if (! (inb(G2STAT(base)) & G2STAT_BUSY)) break;
+			if (loopcnt == LOOPCNT_WARN) {
+				printk("aha1740[%d]_attn wait!\n",ecbno);
+			}
+			if (loopcnt == LOOPCNT_MAX)
+				panic("aha1740.c: attn wait failed!\n");
+		}
+		outb(ATTN_START | (target & 7), ATTN(base)); /* Start it up */
+		spin_unlock_irqrestore(SCpnt->device->host->host_lock, flags);
+		DEB(printk("aha1740[%d] request queued.\n",ecbno));
+	} else
+		printk(KERN_ALERT "aha1740_queuecommand: done can't be NULL\n");
+	return 0;
+}
+
+/* Query the board for its irq_level and irq_type.  Nothing else matters
+   in enhanced mode on an EISA bus. */
+
+static void aha1740_getconfig(unsigned int base, unsigned int *irq_level,
+			      unsigned int *irq_type,
+			      unsigned int *translation)
+{
+	static int intab[] = { 9, 10, 11, 12, 0, 14, 15, 0 };
+
+	*irq_level = intab[inb(INTDEF(base)) & 0x7];
+	*irq_type  = (inb(INTDEF(base)) & 0x8) >> 3;
+	*translation = inb(RESV1(base)) & 0x1;
+	outb(inb(INTDEF(base)) | 0x10, INTDEF(base));
+}
+
+static int aha1740_biosparam(struct scsi_device *sdev,
+			     struct block_device *dev,
+			     sector_t capacity, int* ip)
+{
+	int size = capacity;
+	int extended = HOSTDATA(sdev->host)->translation;
+
+	DEB(printk("aha1740_biosparam\n"));
+	if (extended && (ip[2] > 1024))	{
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (255 * 63);
+	} else {
+		ip[0] = 64;
+		ip[1] = 32;
+		ip[2] = size >> 11;
+	}
+	return 0;
+}
+
+static int aha1740_eh_abort_handler (Scsi_Cmnd *dummy)
+{
+/*
+ * From Alan Cox :
+ * The AHA1740 has firmware handled abort/reset handling. The "head in
+ * sand" kernel code is correct for once 8)
+ *
+ * So we define a dummy handler just to keep the kernel SCSI code as
+ * quiet as possible...
+ */
+
+	return 0;
+}
+
+static Scsi_Host_Template aha1740_template = {
+	.module           = THIS_MODULE,
+	.proc_name        = "aha1740",
+	.proc_info        = aha1740_proc_info,
+	.name             = "Adaptec 174x (EISA)",
+	.queuecommand     = aha1740_queuecommand,
+	.bios_param       = aha1740_biosparam,
+	.can_queue        = AHA1740_ECBS,
+	.this_id          = 7,
+	.sg_tablesize     = AHA1740_SCATTER,
+	.cmd_per_lun      = AHA1740_CMDLUN,
+	.use_clustering   = ENABLE_CLUSTERING,
+	.eh_abort_handler = aha1740_eh_abort_handler,
+};
+
+static int aha1740_probe (struct device *dev)
+{
+	int slotbase;
+	unsigned int irq_level, irq_type, translation;
+	struct Scsi_Host *shpnt;
+	struct aha1740_hostdata *host;
+	struct eisa_device *edev = to_eisa_device (dev);
+
+	DEB(printk("aha1740_probe: \n"));
+	
+	slotbase = edev->base_addr + EISA_VENDOR_ID_OFFSET;
+	if (!request_region(slotbase, SLOTSIZE, "aha1740")) /* See if in use */
+		return -EBUSY;
+	if (!aha1740_test_port(slotbase))
+		goto err_release_region;
+	aha1740_getconfig(slotbase,&irq_level,&irq_type,&translation);
+	if ((inb(G2STAT(slotbase)) &
+	     (G2STAT_MBXOUT|G2STAT_BUSY)) != G2STAT_MBXOUT) {
+		/* If the card isn't ready, hard reset it */
+		outb(G2CNTRL_HRST, G2CNTRL(slotbase));
+		outb(0, G2CNTRL(slotbase));
+	}
+	printk(KERN_INFO "Configuring slot %d at IO:%x, IRQ %u (%s)\n",
+	       edev->slot, slotbase, irq_level, irq_type ? "edge" : "level");
+	printk(KERN_INFO "aha174x: Extended translation %sabled.\n",
+	       translation ? "en" : "dis");
+	shpnt = scsi_host_alloc(&aha1740_template,
+			      sizeof(struct aha1740_hostdata));
+	if(shpnt == NULL)
+		goto err_release_region;
+
+	shpnt->base = 0;
+	shpnt->io_port = slotbase;
+	shpnt->n_io_port = SLOTSIZE;
+	shpnt->irq = irq_level;
+	shpnt->dma_channel = 0xff;
+	host = HOSTDATA(shpnt);
+	host->edev = edev;
+	host->translation = translation;
+	host->ecb_dma_addr = dma_map_single (&edev->dev, host->ecb,
+					     sizeof (host->ecb),
+					     DMA_BIDIRECTIONAL);
+	if (!host->ecb_dma_addr) {
+		printk (KERN_ERR "aha1740_probe: Couldn't map ECB, giving up\n");
+		scsi_unregister (shpnt);
+		goto err_host_put;
+	}
+	
+	DEB(printk("aha1740_probe: enable interrupt channel %d\n",irq_level));
+	if (request_irq(irq_level,aha1740_intr_handle,irq_type ? 0 : SA_SHIRQ,
+			"aha1740",shpnt)) {
+		printk(KERN_ERR "aha1740_probe: Unable to allocate IRQ %d.\n",
+		       irq_level);
+		goto err_unmap;
+	}
+
+	eisa_set_drvdata (edev, shpnt);
+	scsi_add_host (shpnt, dev); /* XXX handle failure */
+	scsi_scan_host (shpnt);
+	return 0;
+
+ err_unmap:
+	dma_unmap_single (&edev->dev, host->ecb_dma_addr,
+			  sizeof (host->ecb), DMA_BIDIRECTIONAL);
+ err_host_put:
+	scsi_host_put (shpnt);
+ err_release_region:
+	release_region(slotbase, SLOTSIZE);
+
+	return -ENODEV;
+}
+
+static __devexit int aha1740_remove (struct device *dev)
+{
+	struct Scsi_Host *shpnt = dev->driver_data;
+	struct aha1740_hostdata *host = HOSTDATA (shpnt);
+
+	scsi_remove_host(shpnt);
+	
+	free_irq (shpnt->irq, shpnt);
+	dma_unmap_single (dev, host->ecb_dma_addr,
+			  sizeof (host->ecb), DMA_BIDIRECTIONAL);
+	release_region (shpnt->io_port, SLOTSIZE);
+
+	scsi_host_put (shpnt);
+	
+	return 0;
+}
+
+static struct eisa_device_id aha1740_ids[] = {
+	{ "ADP0000" },		/* 1740  */
+	{ "ADP0001" },		/* 1740A */
+	{ "ADP0002" },		/* 1742A */
+	{ "ADP0400" },		/* 1744  */
+	{ "" }
+};
+
+static struct eisa_driver aha1740_driver = {
+	.id_table = aha1740_ids,
+	.driver   = {
+		.name    = "aha1740",
+		.probe   = aha1740_probe,
+		.remove  = __devexit_p (aha1740_remove),
+	},
+};
+
+static __init int aha1740_init (void)
+{
+	return eisa_driver_register (&aha1740_driver);
+}
+
+static __exit void aha1740_exit (void)
+{
+	eisa_driver_unregister (&aha1740_driver);
+}
+
+module_init (aha1740_init);
+module_exit (aha1740_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
new file mode 100644
index 0000000..af23fd6
--- /dev/null
+++ b/drivers/scsi/aha1740.h
@@ -0,0 +1,154 @@
+#ifndef _AHA1740_H
+
+/* $Id$
+ *
+ * Header file for the adaptec 1740 driver for Linux
+ *
+ * With minor revisions 3/31/93
+ * Written and (C) 1992,1993 Brad McLean.  See aha1740.c
+ * for more info
+ *
+ */
+
+#include <linux/types.h>
+
+#define SLOTSIZE	0x5c
+
+/* EISA configuration registers & values */
+#define	HID0(base)	(base + 0x0)
+#define	HID1(base)	(base + 0x1)
+#define HID2(base)	(base + 0x2)
+#define	HID3(base)	(base + 0x3)
+#define	EBCNTRL(base)	(base + 0x4)
+#define	PORTADR(base)	(base + 0x40)
+#define BIOSADR(base)	(base + 0x41)
+#define INTDEF(base)	(base + 0x42)
+#define SCSIDEF(base)	(base + 0x43)
+#define BUSDEF(base)	(base + 0x44)
+#define	RESV0(base)	(base + 0x45)
+#define RESV1(base)	(base + 0x46)
+#define	RESV2(base)	(base + 0x47)
+
+#define	HID_MFG	"ADP"
+#define	HID_PRD 0
+#define HID_REV 2
+#define EBCNTRL_VALUE 1
+#define PORTADDR_ENH 0x80
+/* READ */
+#define	G2INTST(base)	(base + 0x56)
+#define G2STAT(base)	(base + 0x57)
+#define	MBOXIN0(base)	(base + 0x58)
+#define	MBOXIN1(base)	(base + 0x59)
+#define	MBOXIN2(base)	(base + 0x5a)
+#define	MBOXIN3(base)	(base + 0x5b)
+#define G2STAT2(base)	(base + 0x5c)
+
+#define G2INTST_MASK		0xf0	/* isolate the status */
+#define	G2INTST_CCBGOOD		0x10	/* CCB Completed */
+#define	G2INTST_CCBRETRY	0x50	/* CCB Completed with a retry */
+#define	G2INTST_HARDFAIL	0x70	/* Adapter Hardware Failure */
+#define	G2INTST_CMDGOOD		0xa0	/* Immediate command success */
+#define G2INTST_CCBERROR	0xc0	/* CCB Completed with error */
+#define	G2INTST_ASNEVENT	0xd0	/* Asynchronous Event Notification */
+#define	G2INTST_CMDERROR	0xe0	/* Immediate command error */
+
+#define G2STAT_MBXOUT	4	/* Mailbox Out Empty Bit */
+#define	G2STAT_INTPEND	2	/* Interrupt Pending Bit */
+#define	G2STAT_BUSY	1	/* Busy Bit (attention pending) */
+
+#define G2STAT2_READY	0	/* Host Ready Bit */
+
+/* WRITE (and ReadBack) */
+#define	MBOXOUT0(base)	(base + 0x50)
+#define	MBOXOUT1(base)	(base + 0x51)
+#define	MBOXOUT2(base)	(base + 0x52)
+#define	MBOXOUT3(base)	(base + 0x53)
+#define	ATTN(base)	(base + 0x54)
+#define G2CNTRL(base)	(base + 0x55)
+
+#define	ATTN_IMMED	0x10	/* Immediate Command */
+#define	ATTN_START	0x40	/* Start CCB */
+#define	ATTN_ABORT	0x50	/* Abort CCB */
+
+#define G2CNTRL_HRST	0x80	/* Hard Reset */
+#define G2CNTRL_IRST	0x40	/* Clear EISA Interrupt */
+#define G2CNTRL_HRDY	0x20	/* Sets HOST ready */
+
+/* This is used with scatter-gather */
+struct aha1740_chain {
+	u32 dataptr;		/* Location of data */
+	u32 datalen;		/* Size of this part of chain */
+};
+
+/* These belong in scsi.h */
+#define any2scsi(up, p)				\
+(up)[0] = (((unsigned long)(p)) >> 16)  ;	\
+(up)[1] = (((unsigned long)(p)) >> 8);		\
+(up)[2] = ((unsigned long)(p));
+
+#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) )
+
+#define xany2scsi(up, p)	\
+(up)[0] = ((long)(p)) >> 24;	\
+(up)[1] = ((long)(p)) >> 16;	\
+(up)[2] = ((long)(p)) >> 8;	\
+(up)[3] = ((long)(p));
+
+#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \
+		      + (((long)(up)[2]) <<  8) +  ((long)(up)[3]) )
+
+#define MAX_CDB 12
+#define MAX_SENSE 14
+#define MAX_STATUS 32
+
+struct ecb {			/* Enhanced Control Block 6.1 */
+	u16 cmdw;		/* Command Word */
+	/* Flag Word 1 */
+	u16 cne:1,		/* Control Block Chaining */
+	:6, di:1,		/* Disable Interrupt */
+	:2, ses:1,		/* Suppress Underrun error */
+	:1, sg:1,		/* Scatter/Gather */
+	:1, dsb:1,		/* Disable Status Block */
+	 ars:1;			/* Automatic Request Sense */
+	/* Flag Word 2 */
+	u16 lun:3,		/* Logical Unit */
+	 tag:1,			/* Tagged Queuing */
+	 tt:2,			/* Tag Type */
+	 nd:1,			/* No Disconnect */
+	:1, dat:1,		/* Data transfer - check direction */
+	 dir:1,			/* Direction of transfer 1 = datain */
+	 st:1,			/* Suppress Transfer */
+	 chk:1,			/* Calculate Checksum */
+	:2, rec:1,:1;		/* Error Recovery */
+	u16 nil0;		/* nothing */
+	u32 dataptr;		/* Data or Scatter List ptr */
+	u32 datalen;		/* Data or Scatter List len */
+	u32 statusptr;		/* Status Block ptr */
+	u32 linkptr;		/* Chain Address */
+	u32 nil1;		/* nothing */
+	u32 senseptr;		/* Sense Info Pointer */
+	u8 senselen;		/* Sense Length */
+	u8 cdblen;		/* CDB Length */
+	u16 datacheck;		/* Data checksum */
+	u8 cdb[MAX_CDB];	/* CDB area */
+/* Hardware defined portion ends here, rest is driver defined */
+	u8 sense[MAX_SENSE];	/* Sense area */
+	u8 status[MAX_STATUS];	/* Status area */
+	Scsi_Cmnd *SCpnt;	/* Link to the SCSI Command Block */
+	void (*done) (Scsi_Cmnd *);	/* Completion Function */
+};
+
+#define	AHA1740CMD_NOP	 0x00	/* No OP */
+#define AHA1740CMD_INIT	 0x01	/* Initiator SCSI Command */
+#define AHA1740CMD_DIAG	 0x05	/* Run Diagnostic Command */
+#define AHA1740CMD_SCSI	 0x06	/* Initialize SCSI */
+#define AHA1740CMD_SENSE 0x08	/* Read Sense Information */
+#define AHA1740CMD_DOWN  0x09	/* Download Firmware (yeah, I bet!) */
+#define AHA1740CMD_RINQ  0x0a	/* Read Host Adapter Inquiry Data */
+#define AHA1740CMD_TARG  0x10	/* Target SCSI Command */
+
+#define AHA1740_ECBS 32
+#define AHA1740_SCATTER 16
+#define AHA1740_CMDLUN 1
+
+#endif
diff --git a/drivers/scsi/ahci.c b/drivers/scsi/ahci.c
new file mode 100644
index 0000000..3a15b13
--- /dev/null
+++ b/drivers/scsi/ahci.c
@@ -0,0 +1,1065 @@
+/*
+ *  ahci.c - AHCI SATA support
+ *
+ *  Copyright 2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ * Version 1.0 of the AHCI specification:
+ * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME	"ahci"
+#define DRV_VERSION	"1.00"
+
+
+enum {
+	AHCI_PCI_BAR		= 5,
+	AHCI_MAX_SG		= 168, /* hardware max is 64K */
+	AHCI_DMA_BOUNDARY	= 0xffffffff,
+	AHCI_USE_CLUSTERING	= 0,
+	AHCI_CMD_SLOT_SZ	= 32 * 32,
+	AHCI_RX_FIS_SZ		= 256,
+	AHCI_CMD_TBL_HDR	= 0x80,
+	AHCI_CMD_TBL_SZ		= AHCI_CMD_TBL_HDR + (AHCI_MAX_SG * 16),
+	AHCI_PORT_PRIV_DMA_SZ	= AHCI_CMD_SLOT_SZ + AHCI_CMD_TBL_SZ +
+				  AHCI_RX_FIS_SZ,
+	AHCI_IRQ_ON_SG		= (1 << 31),
+	AHCI_CMD_ATAPI		= (1 << 5),
+	AHCI_CMD_WRITE		= (1 << 6),
+
+	RX_FIS_D2H_REG		= 0x40,	/* offset of D2H Register FIS data */
+
+	board_ahci		= 0,
+
+	/* global controller registers */
+	HOST_CAP		= 0x00, /* host capabilities */
+	HOST_CTL		= 0x04, /* global host control */
+	HOST_IRQ_STAT		= 0x08, /* interrupt status */
+	HOST_PORTS_IMPL		= 0x0c, /* bitmap of implemented ports */
+	HOST_VERSION		= 0x10, /* AHCI spec. version compliancy */
+
+	/* HOST_CTL bits */
+	HOST_RESET		= (1 << 0),  /* reset controller; self-clear */
+	HOST_IRQ_EN		= (1 << 1),  /* global IRQ enable */
+	HOST_AHCI_EN		= (1 << 31), /* AHCI enabled */
+
+	/* HOST_CAP bits */
+	HOST_CAP_64		= (1 << 31), /* PCI DAC (64-bit DMA) support */
+
+	/* registers for each SATA port */
+	PORT_LST_ADDR		= 0x00, /* command list DMA addr */
+	PORT_LST_ADDR_HI	= 0x04, /* command list DMA addr hi */
+	PORT_FIS_ADDR		= 0x08, /* FIS rx buf addr */
+	PORT_FIS_ADDR_HI	= 0x0c, /* FIS rx buf addr hi */
+	PORT_IRQ_STAT		= 0x10, /* interrupt status */
+	PORT_IRQ_MASK		= 0x14, /* interrupt enable/disable mask */
+	PORT_CMD		= 0x18, /* port command */
+	PORT_TFDATA		= 0x20,	/* taskfile data */
+	PORT_SIG		= 0x24,	/* device TF signature */
+	PORT_CMD_ISSUE		= 0x38, /* command issue */
+	PORT_SCR		= 0x28, /* SATA phy register block */
+	PORT_SCR_STAT		= 0x28, /* SATA phy register: SStatus */
+	PORT_SCR_CTL		= 0x2c, /* SATA phy register: SControl */
+	PORT_SCR_ERR		= 0x30, /* SATA phy register: SError */
+	PORT_SCR_ACT		= 0x34, /* SATA phy register: SActive */
+
+	/* PORT_IRQ_{STAT,MASK} bits */
+	PORT_IRQ_COLD_PRES	= (1 << 31), /* cold presence detect */
+	PORT_IRQ_TF_ERR		= (1 << 30), /* task file error */
+	PORT_IRQ_HBUS_ERR	= (1 << 29), /* host bus fatal error */
+	PORT_IRQ_HBUS_DATA_ERR	= (1 << 28), /* host bus data error */
+	PORT_IRQ_IF_ERR		= (1 << 27), /* interface fatal error */
+	PORT_IRQ_IF_NONFATAL	= (1 << 26), /* interface non-fatal error */
+	PORT_IRQ_OVERFLOW	= (1 << 24), /* xfer exhausted available S/G */
+	PORT_IRQ_BAD_PMP	= (1 << 23), /* incorrect port multiplier */
+
+	PORT_IRQ_PHYRDY		= (1 << 22), /* PhyRdy changed */
+	PORT_IRQ_DEV_ILCK	= (1 << 7), /* device interlock */
+	PORT_IRQ_CONNECT	= (1 << 6), /* port connect change status */
+	PORT_IRQ_SG_DONE	= (1 << 5), /* descriptor processed */
+	PORT_IRQ_UNK_FIS	= (1 << 4), /* unknown FIS rx'd */
+	PORT_IRQ_SDB_FIS	= (1 << 3), /* Set Device Bits FIS rx'd */
+	PORT_IRQ_DMAS_FIS	= (1 << 2), /* DMA Setup FIS rx'd */
+	PORT_IRQ_PIOS_FIS	= (1 << 1), /* PIO Setup FIS rx'd */
+	PORT_IRQ_D2H_REG_FIS	= (1 << 0), /* D2H Register FIS rx'd */
+
+	PORT_IRQ_FATAL		= PORT_IRQ_TF_ERR |
+				  PORT_IRQ_HBUS_ERR |
+				  PORT_IRQ_HBUS_DATA_ERR |
+				  PORT_IRQ_IF_ERR,
+	DEF_PORT_IRQ		= PORT_IRQ_FATAL | PORT_IRQ_PHYRDY |
+				  PORT_IRQ_CONNECT | PORT_IRQ_SG_DONE |
+				  PORT_IRQ_UNK_FIS | PORT_IRQ_SDB_FIS |
+				  PORT_IRQ_DMAS_FIS | PORT_IRQ_PIOS_FIS |
+				  PORT_IRQ_D2H_REG_FIS,
+
+	/* PORT_CMD bits */
+	PORT_CMD_LIST_ON	= (1 << 15), /* cmd list DMA engine running */
+	PORT_CMD_FIS_ON		= (1 << 14), /* FIS DMA engine running */
+	PORT_CMD_FIS_RX		= (1 << 4), /* Enable FIS receive DMA engine */
+	PORT_CMD_POWER_ON	= (1 << 2), /* Power up device */
+	PORT_CMD_SPIN_UP	= (1 << 1), /* Spin up device */
+	PORT_CMD_START		= (1 << 0), /* Enable port DMA engine */
+
+	PORT_CMD_ICC_ACTIVE	= (0x1 << 28), /* Put i/f in active state */
+	PORT_CMD_ICC_PARTIAL	= (0x2 << 28), /* Put i/f in partial state */
+	PORT_CMD_ICC_SLUMBER	= (0x6 << 28), /* Put i/f in slumber state */
+};
+
+struct ahci_cmd_hdr {
+	u32			opts;
+	u32			status;
+	u32			tbl_addr;
+	u32			tbl_addr_hi;
+	u32			reserved[4];
+};
+
+struct ahci_sg {
+	u32			addr;
+	u32			addr_hi;
+	u32			reserved;
+	u32			flags_size;
+};
+
+struct ahci_host_priv {
+	unsigned long		flags;
+	u32			cap;	/* cache of HOST_CAP register */
+	u32			port_map; /* cache of HOST_PORTS_IMPL reg */
+};
+
+struct ahci_port_priv {
+	struct ahci_cmd_hdr	*cmd_slot;
+	dma_addr_t		cmd_slot_dma;
+	void			*cmd_tbl;
+	dma_addr_t		cmd_tbl_dma;
+	struct ahci_sg		*cmd_tbl_sg;
+	void			*rx_fis;
+	dma_addr_t		rx_fis_dma;
+};
+
+static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static int ahci_qc_issue(struct ata_queued_cmd *qc);
+static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void ahci_phy_reset(struct ata_port *ap);
+static void ahci_irq_clear(struct ata_port *ap);
+static void ahci_eng_timeout(struct ata_port *ap);
+static int ahci_port_start(struct ata_port *ap);
+static void ahci_port_stop(struct ata_port *ap);
+static void ahci_host_stop(struct ata_host_set *host_set);
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf);
+static void ahci_qc_prep(struct ata_queued_cmd *qc);
+static u8 ahci_check_status(struct ata_port *ap);
+static u8 ahci_check_err(struct ata_port *ap);
+static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
+
+static Scsi_Host_Template ahci_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= AHCI_MAX_SG,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= AHCI_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= AHCI_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations ahci_ops = {
+	.port_disable		= ata_port_disable,
+
+	.check_status		= ahci_check_status,
+	.check_altstatus	= ahci_check_status,
+	.check_err		= ahci_check_err,
+	.dev_select		= ata_noop_dev_select,
+
+	.tf_read		= ahci_tf_read,
+
+	.phy_reset		= ahci_phy_reset,
+
+	.qc_prep		= ahci_qc_prep,
+	.qc_issue		= ahci_qc_issue,
+
+	.eng_timeout		= ahci_eng_timeout,
+
+	.irq_handler		= ahci_interrupt,
+	.irq_clear		= ahci_irq_clear,
+
+	.scr_read		= ahci_scr_read,
+	.scr_write		= ahci_scr_write,
+
+	.port_start		= ahci_port_start,
+	.port_stop		= ahci_port_stop,
+	.host_stop		= ahci_host_stop,
+};
+
+static struct ata_port_info ahci_port_info[] = {
+	/* board_ahci */
+	{
+		.sht		= &ahci_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO |
+				  ATA_FLAG_PIO_DMA,
+		.pio_mask	= 0x03, /* pio3-4 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &ahci_ops,
+	},
+};
+
+static struct pci_device_id ahci_pci_tbl[] = {
+	{ PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH6 */
+	{ PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH6M */
+	{ PCI_VENDOR_ID_INTEL, 0x27c1, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7 */
+	{ PCI_VENDOR_ID_INTEL, 0x27c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7M */
+	{ PCI_VENDOR_ID_INTEL, 0x27c3, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ICH7R */
+	{ PCI_VENDOR_ID_AL, 0x5288, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_ahci }, /* ULi M5288 */
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver ahci_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= ahci_pci_tbl,
+	.probe			= ahci_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static inline unsigned long ahci_port_base_ul (unsigned long base, unsigned int port)
+{
+	return base + 0x100 + (port * 0x80);
+}
+
+static inline void *ahci_port_base (void *base, unsigned int port)
+{
+	return (void *) ahci_port_base_ul((unsigned long)base, port);
+}
+
+static void ahci_host_stop(struct ata_host_set *host_set)
+{
+	struct ahci_host_priv *hpriv = host_set->private_data;
+	kfree(hpriv);
+}
+
+static int ahci_port_start(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct ahci_host_priv *hpriv = ap->host_set->private_data;
+	struct ahci_port_priv *pp;
+	int rc;
+	void *mem, *mmio = ap->host_set->mmio_base;
+	void *port_mmio = ahci_port_base(mmio, ap->port_no);
+	dma_addr_t mem_dma;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL);
+	if (!mem) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+	memset(mem, 0, AHCI_PORT_PRIV_DMA_SZ);
+
+	/*
+	 * First item in chunk of DMA memory: 32-slot command table,
+	 * 32 bytes each in size
+	 */
+	pp->cmd_slot = mem;
+	pp->cmd_slot_dma = mem_dma;
+
+	mem += AHCI_CMD_SLOT_SZ;
+	mem_dma += AHCI_CMD_SLOT_SZ;
+
+	/*
+	 * Second item: Received-FIS area
+	 */
+	pp->rx_fis = mem;
+	pp->rx_fis_dma = mem_dma;
+
+	mem += AHCI_RX_FIS_SZ;
+	mem_dma += AHCI_RX_FIS_SZ;
+
+	/*
+	 * Third item: data area for storing a single command
+	 * and its scatter-gather table
+	 */
+	pp->cmd_tbl = mem;
+	pp->cmd_tbl_dma = mem_dma;
+
+	pp->cmd_tbl_sg = mem + AHCI_CMD_TBL_HDR;
+
+	ap->private_data = pp;
+
+	if (hpriv->cap & HOST_CAP_64)
+		writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI);
+	writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR);
+	readl(port_mmio + PORT_LST_ADDR); /* flush */
+
+	if (hpriv->cap & HOST_CAP_64)
+		writel((pp->rx_fis_dma >> 16) >> 16, port_mmio + PORT_FIS_ADDR_HI);
+	writel(pp->rx_fis_dma & 0xffffffff, port_mmio + PORT_FIS_ADDR);
+	readl(port_mmio + PORT_FIS_ADDR); /* flush */
+
+	writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX |
+	       PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP |
+	       PORT_CMD_START, port_mmio + PORT_CMD);
+	readl(port_mmio + PORT_CMD); /* flush */
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void ahci_port_stop(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct ahci_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	void *port_mmio = ahci_port_base(mmio, ap->port_no);
+	u32 tmp;
+
+	tmp = readl(port_mmio + PORT_CMD);
+	tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX);
+	writel(tmp, port_mmio + PORT_CMD);
+	readl(port_mmio + PORT_CMD); /* flush */
+
+	/* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
+	 * this is slightly incorrect.
+	 */
+	msleep(500);
+
+	ap->private_data = NULL;
+	dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ,
+			  pp->cmd_slot, pp->cmd_slot_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+static u32 ahci_scr_read (struct ata_port *ap, unsigned int sc_reg_in)
+{
+	unsigned int sc_reg;
+
+	switch (sc_reg_in) {
+	case SCR_STATUS:	sc_reg = 0; break;
+	case SCR_CONTROL:	sc_reg = 1; break;
+	case SCR_ERROR:		sc_reg = 2; break;
+	case SCR_ACTIVE:	sc_reg = 3; break;
+	default:
+		return 0xffffffffU;
+	}
+
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void ahci_scr_write (struct ata_port *ap, unsigned int sc_reg_in,
+			       u32 val)
+{
+	unsigned int sc_reg;
+
+	switch (sc_reg_in) {
+	case SCR_STATUS:	sc_reg = 0; break;
+	case SCR_CONTROL:	sc_reg = 1; break;
+	case SCR_ERROR:		sc_reg = 2; break;
+	case SCR_ACTIVE:	sc_reg = 3; break;
+	default:
+		return;
+	}
+
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void ahci_phy_reset(struct ata_port *ap)
+{
+	void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr;
+	struct ata_taskfile tf;
+	struct ata_device *dev = &ap->device[0];
+	u32 tmp;
+
+	__sata_phy_reset(ap);
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	tmp = readl(port_mmio + PORT_SIG);
+	tf.lbah		= (tmp >> 24)	& 0xff;
+	tf.lbam		= (tmp >> 16)	& 0xff;
+	tf.lbal		= (tmp >> 8)	& 0xff;
+	tf.nsect	= (tmp)		& 0xff;
+
+	dev->class = ata_dev_classify(&tf);
+	if (!ata_dev_present(dev))
+		ata_port_disable(ap);
+}
+
+static u8 ahci_check_status(struct ata_port *ap)
+{
+	void *mmio = (void *) ap->ioaddr.cmd_addr;
+
+	return readl(mmio + PORT_TFDATA) & 0xFF;
+}
+
+static u8 ahci_check_err(struct ata_port *ap)
+{
+	void *mmio = (void *) ap->ioaddr.cmd_addr;
+
+	return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF;
+}
+
+static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ahci_port_priv *pp = ap->private_data;
+	u8 *d2h_fis = pp->rx_fis + RX_FIS_D2H_REG;
+
+	ata_tf_from_fis(d2h_fis, tf);
+}
+
+static void ahci_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct ahci_port_priv *pp = qc->ap->private_data;
+	unsigned int i;
+
+	VPRINTK("ENTER\n");
+
+	/*
+	 * Next, the S/G list.
+	 */
+	for (i = 0; i < qc->n_elem; i++) {
+		u32 sg_len;
+		dma_addr_t addr;
+
+		addr = sg_dma_address(&qc->sg[i]);
+		sg_len = sg_dma_len(&qc->sg[i]);
+
+		pp->cmd_tbl_sg[i].addr = cpu_to_le32(addr & 0xffffffff);
+		pp->cmd_tbl_sg[i].addr_hi = cpu_to_le32((addr >> 16) >> 16);
+		pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len - 1);
+	}
+}
+
+static void ahci_qc_prep(struct ata_queued_cmd *qc)
+{
+	struct ahci_port_priv *pp = qc->ap->private_data;
+	u32 opts;
+	const u32 cmd_fis_len = 5; /* five dwords */
+
+	/*
+	 * Fill in command slot information (currently only one slot,
+	 * slot 0, is currently since we don't do queueing)
+	 */
+
+	opts = (qc->n_elem << 16) | cmd_fis_len;
+	if (qc->tf.flags & ATA_TFLAG_WRITE)
+		opts |= AHCI_CMD_WRITE;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_ATAPI:
+	case ATA_PROT_ATAPI_NODATA:
+	case ATA_PROT_ATAPI_DMA:
+		opts |= AHCI_CMD_ATAPI;
+		break;
+
+	default:
+		/* do nothing */
+		break;
+	}
+
+	pp->cmd_slot[0].opts = cpu_to_le32(opts);
+	pp->cmd_slot[0].status = 0;
+	pp->cmd_slot[0].tbl_addr = cpu_to_le32(pp->cmd_tbl_dma & 0xffffffff);
+	pp->cmd_slot[0].tbl_addr_hi = cpu_to_le32((pp->cmd_tbl_dma >> 16) >> 16);
+
+	/*
+	 * Fill in command table information.  First, the header,
+	 * a SATA Register - Host to Device command FIS.
+	 */
+	ata_tf_to_fis(&qc->tf, pp->cmd_tbl, 0);
+
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+		return;
+
+	ahci_fill_sg(qc);
+}
+
+static void ahci_intr_error(struct ata_port *ap, u32 irq_stat)
+{
+	void *mmio = ap->host_set->mmio_base;
+	void *port_mmio = ahci_port_base(mmio, ap->port_no);
+	u32 tmp;
+	int work;
+
+	/* stop DMA */
+	tmp = readl(port_mmio + PORT_CMD);
+	tmp &= ~PORT_CMD_START;
+	writel(tmp, port_mmio + PORT_CMD);
+
+	/* wait for engine to stop.  TODO: this could be
+	 * as long as 500 msec
+	 */
+	work = 1000;
+	while (work-- > 0) {
+		tmp = readl(port_mmio + PORT_CMD);
+		if ((tmp & PORT_CMD_LIST_ON) == 0)
+			break;
+		udelay(10);
+	}
+
+	/* clear SATA phy error, if any */
+	tmp = readl(port_mmio + PORT_SCR_ERR);
+	writel(tmp, port_mmio + PORT_SCR_ERR);
+
+	/* if DRQ/BSY is set, device needs to be reset.
+	 * if so, issue COMRESET
+	 */
+	tmp = readl(port_mmio + PORT_TFDATA);
+	if (tmp & (ATA_BUSY | ATA_DRQ)) {
+		writel(0x301, port_mmio + PORT_SCR_CTL);
+		readl(port_mmio + PORT_SCR_CTL); /* flush */
+		udelay(10);
+		writel(0x300, port_mmio + PORT_SCR_CTL);
+		readl(port_mmio + PORT_SCR_CTL); /* flush */
+	}
+
+	/* re-start DMA */
+	tmp = readl(port_mmio + PORT_CMD);
+	tmp |= PORT_CMD_START;
+	writel(tmp, port_mmio + PORT_CMD);
+	readl(port_mmio + PORT_CMD); /* flush */
+
+	printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id);
+}
+
+static void ahci_eng_timeout(struct ata_port *ap)
+{
+	void *mmio = ap->host_set->mmio_base;
+	void *port_mmio = ahci_port_base(mmio, ap->port_no);
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT));
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+	} else {
+		/* hack alert!  We cannot use the supplied completion
+	 	 * function from inside the ->eh_strategy_handler() thread.
+	 	 * libata is the only user of ->eh_strategy_handler() in
+	 	 * any kernel, so the default scsi_done() assumes it is
+	 	 * not being called from the SCSI EH.
+	 	 */
+		qc->scsidone = scsi_finish_command;
+		ata_qc_complete(qc, ATA_ERR);
+	}
+
+}
+
+static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc)
+{
+	void *mmio = ap->host_set->mmio_base;
+	void *port_mmio = ahci_port_base(mmio, ap->port_no);
+	u32 status, serr, ci;
+
+	serr = readl(port_mmio + PORT_SCR_ERR);
+	writel(serr, port_mmio + PORT_SCR_ERR);
+
+	status = readl(port_mmio + PORT_IRQ_STAT);
+	writel(status, port_mmio + PORT_IRQ_STAT);
+
+	ci = readl(port_mmio + PORT_CMD_ISSUE);
+	if (likely((ci & 0x1) == 0)) {
+		if (qc) {
+			ata_qc_complete(qc, 0);
+			qc = NULL;
+		}
+	}
+
+	if (status & PORT_IRQ_FATAL) {
+		ahci_intr_error(ap, status);
+		if (qc)
+			ata_qc_complete(qc, ATA_ERR);
+	}
+
+	return 1;
+}
+
+static void ahci_irq_clear(struct ata_port *ap)
+{
+	/* TODO */
+}
+
+static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ahci_host_priv *hpriv;
+	unsigned int i, handled = 0;
+	void *mmio;
+	u32 irq_stat, irq_ack = 0;
+
+	VPRINTK("ENTER\n");
+
+	hpriv = host_set->private_data;
+	mmio = host_set->mmio_base;
+
+	/* sigh.  0xffffffff is a valid return from h/w */
+	irq_stat = readl(mmio + HOST_IRQ_STAT);
+	irq_stat &= hpriv->port_map;
+	if (!irq_stat)
+		return IRQ_NONE;
+
+        spin_lock(&host_set->lock);
+
+        for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+		u32 tmp;
+
+		VPRINTK("port %u\n", i);
+		ap = host_set->ports[i];
+		tmp = irq_stat & (1 << i);
+		if (tmp && ap) {
+			struct ata_queued_cmd *qc;
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (ahci_host_intr(ap, qc))
+				irq_ack |= (1 << i);
+		}
+	}
+
+	if (irq_ack) {
+		writel(irq_ack, mmio + HOST_IRQ_STAT);
+		handled = 1;
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static int ahci_qc_issue(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	void *port_mmio = (void *) ap->ioaddr.cmd_addr;
+
+	writel(1, port_mmio + PORT_SCR_ACT);
+	readl(port_mmio + PORT_SCR_ACT);	/* flush */
+
+	writel(1, port_mmio + PORT_CMD_ISSUE);
+	readl(port_mmio + PORT_CMD_ISSUE);	/* flush */
+
+	return 0;
+}
+
+static void ahci_setup_port(struct ata_ioports *port, unsigned long base,
+			    unsigned int port_idx)
+{
+	VPRINTK("ENTER, base==0x%lx, port_idx %u\n", base, port_idx);
+	base = ahci_port_base_ul(base, port_idx);
+	VPRINTK("base now==0x%lx\n", base);
+
+	port->cmd_addr		= base;
+	port->scr_addr		= base + PORT_SCR;
+
+	VPRINTK("EXIT\n");
+}
+
+static int ahci_host_init(struct ata_probe_ent *probe_ent)
+{
+	struct ahci_host_priv *hpriv = probe_ent->private_data;
+	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	void __iomem *mmio = probe_ent->mmio_base;
+	u32 tmp, cap_save;
+	u16 tmp16;
+	unsigned int i, j, using_dac;
+	int rc;
+	void __iomem *port_mmio;
+
+	cap_save = readl(mmio + HOST_CAP);
+	cap_save &= ( (1<<28) | (1<<17) );
+	cap_save |= (1 << 27);
+
+	/* global controller reset */
+	tmp = readl(mmio + HOST_CTL);
+	if ((tmp & HOST_RESET) == 0) {
+		writel(tmp | HOST_RESET, mmio + HOST_CTL);
+		readl(mmio + HOST_CTL); /* flush */
+	}
+
+	/* reset must complete within 1 second, or
+	 * the hardware should be considered fried.
+	 */
+	ssleep(1);
+
+	tmp = readl(mmio + HOST_CTL);
+	if (tmp & HOST_RESET) {
+		printk(KERN_ERR DRV_NAME "(%s): controller reset failed (0x%x)\n",
+			pci_name(pdev), tmp);
+		return -EIO;
+	}
+
+	writel(HOST_AHCI_EN, mmio + HOST_CTL);
+	(void) readl(mmio + HOST_CTL);	/* flush */
+	writel(cap_save, mmio + HOST_CAP);
+	writel(0xf, mmio + HOST_PORTS_IMPL);
+	(void) readl(mmio + HOST_PORTS_IMPL);	/* flush */
+
+	pci_read_config_word(pdev, 0x92, &tmp16);
+	tmp16 |= 0xf;
+	pci_write_config_word(pdev, 0x92, tmp16);
+
+	hpriv->cap = readl(mmio + HOST_CAP);
+	hpriv->port_map = readl(mmio + HOST_PORTS_IMPL);
+	probe_ent->n_ports = (hpriv->cap & 0x1f) + 1;
+
+	VPRINTK("cap 0x%x  port_map 0x%x  n_ports %d\n",
+		hpriv->cap, hpriv->port_map, probe_ent->n_ports);
+
+	using_dac = hpriv->cap & HOST_CAP_64;
+	if (using_dac &&
+	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (rc) {
+			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+			if (rc) {
+				printk(KERN_ERR DRV_NAME "(%s): 64-bit DMA enable failed\n",
+					pci_name(pdev));
+				return rc;
+			}
+		}
+
+		hpriv->flags |= HOST_CAP_64;
+	} else {
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n",
+				pci_name(pdev));
+			return rc;
+		}
+		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME "(%s): 32-bit consistent DMA enable failed\n",
+				pci_name(pdev));
+			return rc;
+		}
+	}
+
+	for (i = 0; i < probe_ent->n_ports; i++) {
+#if 0 /* BIOSen initialize this incorrectly */
+		if (!(hpriv->port_map & (1 << i)))
+			continue;
+#endif
+
+		port_mmio = ahci_port_base(mmio, i);
+		VPRINTK("mmio %p  port_mmio %p\n", mmio, port_mmio);
+
+		ahci_setup_port(&probe_ent->port[i],
+				(unsigned long) mmio, i);
+
+		/* make sure port is not active */
+		tmp = readl(port_mmio + PORT_CMD);
+		VPRINTK("PORT_CMD 0x%x\n", tmp);
+		if (tmp & (PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+			   PORT_CMD_FIS_RX | PORT_CMD_START)) {
+			tmp &= ~(PORT_CMD_LIST_ON | PORT_CMD_FIS_ON |
+				 PORT_CMD_FIS_RX | PORT_CMD_START);
+			writel(tmp, port_mmio + PORT_CMD);
+			readl(port_mmio + PORT_CMD); /* flush */
+
+			/* spec says 500 msecs for each bit, so
+			 * this is slightly incorrect.
+			 */
+			msleep(500);
+		}
+
+		writel(PORT_CMD_SPIN_UP, port_mmio + PORT_CMD);
+
+		j = 0;
+		while (j < 100) {
+			msleep(10);
+			tmp = readl(port_mmio + PORT_SCR_STAT);
+			if ((tmp & 0xf) == 0x3)
+				break;
+			j++;
+		}
+
+		tmp = readl(port_mmio + PORT_SCR_ERR);
+		VPRINTK("PORT_SCR_ERR 0x%x\n", tmp);
+		writel(tmp, port_mmio + PORT_SCR_ERR);
+
+		/* ack any pending irq events for this port */
+		tmp = readl(port_mmio + PORT_IRQ_STAT);
+		VPRINTK("PORT_IRQ_STAT 0x%x\n", tmp);
+		if (tmp)
+			writel(tmp, port_mmio + PORT_IRQ_STAT);
+
+		writel(1 << i, mmio + HOST_IRQ_STAT);
+
+		/* set irq mask (enables interrupts) */
+		writel(DEF_PORT_IRQ, port_mmio + PORT_IRQ_MASK);
+	}
+
+	tmp = readl(mmio + HOST_CTL);
+	VPRINTK("HOST_CTL 0x%x\n", tmp);
+	writel(tmp | HOST_IRQ_EN, mmio + HOST_CTL);
+	tmp = readl(mmio + HOST_CTL);
+	VPRINTK("HOST_CTL 0x%x\n", tmp);
+
+	pci_set_master(pdev);
+
+	return 0;
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+static void ahci_print_info(struct ata_probe_ent *probe_ent)
+{
+	struct ahci_host_priv *hpriv = probe_ent->private_data;
+	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	void *mmio = probe_ent->mmio_base;
+	u32 vers, cap, impl, speed;
+	const char *speed_s;
+	u16 cc;
+	const char *scc_s;
+
+	vers = readl(mmio + HOST_VERSION);
+	cap = hpriv->cap;
+	impl = hpriv->port_map;
+
+	speed = (cap >> 20) & 0xf;
+	if (speed == 1)
+		speed_s = "1.5";
+	else if (speed == 2)
+		speed_s = "3";
+	else
+		speed_s = "?";
+
+	pci_read_config_word(pdev, 0x0a, &cc);
+	if (cc == 0x0101)
+		scc_s = "IDE";
+	else if (cc == 0x0106)
+		scc_s = "SATA";
+	else if (cc == 0x0104)
+		scc_s = "RAID";
+	else
+		scc_s = "unknown";
+
+	printk(KERN_INFO DRV_NAME "(%s) AHCI %02x%02x.%02x%02x "
+		"%u slots %u ports %s Gbps 0x%x impl %s mode\n"
+	       	,
+	       	pci_name(pdev),
+
+	       	(vers >> 24) & 0xff,
+	       	(vers >> 16) & 0xff,
+	       	(vers >> 8) & 0xff,
+	       	vers & 0xff,
+
+		((cap >> 8) & 0x1f) + 1,
+		(cap & 0x1f) + 1,
+		speed_s,
+		impl,
+		scc_s);
+
+	printk(KERN_INFO DRV_NAME "(%s) flags: "
+	       	"%s%s%s%s%s%s"
+	       	"%s%s%s%s%s%s%s\n"
+	       	,
+	       	pci_name(pdev),
+
+		cap & (1 << 31) ? "64bit " : "",
+		cap & (1 << 30) ? "ncq " : "",
+		cap & (1 << 28) ? "ilck " : "",
+		cap & (1 << 27) ? "stag " : "",
+		cap & (1 << 26) ? "pm " : "",
+		cap & (1 << 25) ? "led " : "",
+
+		cap & (1 << 24) ? "clo " : "",
+		cap & (1 << 19) ? "nz " : "",
+		cap & (1 << 18) ? "only " : "",
+		cap & (1 << 17) ? "pmp " : "",
+		cap & (1 << 15) ? "pio " : "",
+		cap & (1 << 14) ? "slum " : "",
+		cap & (1 << 13) ? "part " : ""
+		);
+}
+
+static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	struct ahci_host_priv *hpriv;
+	unsigned long base;
+	void *mmio_base;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int pci_dev_busy = 0;
+	int rc;
+
+	VPRINTK("ENTER\n");
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	pci_enable_intx(pdev);
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR),
+		            pci_resource_len(pdev, AHCI_PCI_BAR));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+	if (!hpriv) {
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+	memset(hpriv, 0, sizeof(*hpriv));
+
+	probe_ent->sht		= ahci_port_info[board_idx].sht;
+	probe_ent->host_flags	= ahci_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= ahci_port_info[board_idx].pio_mask;
+	probe_ent->udma_mask	= ahci_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= ahci_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+	probe_ent->private_data = hpriv;
+
+	/* initialize adapter */
+	rc = ahci_host_init(probe_ent);
+	if (rc)
+		goto err_out_hpriv;
+
+	ahci_print_info(probe_ent);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_hpriv:
+	kfree(hpriv);
+err_out_iounmap:
+	iounmap(mmio_base);
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init ahci_init(void)
+{
+	return pci_module_init(&ahci_pci_driver);
+}
+
+
+static void __exit ahci_exit(void)
+{
+	pci_unregister_driver(&ahci_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("AHCI SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, ahci_pci_tbl);
+
+module_init(ahci_init);
+module_exit(ahci_exit);
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic79xx b/drivers/scsi/aic7xxx/Kconfig.aic79xx
new file mode 100644
index 0000000..c2523a3
--- /dev/null
+++ b/drivers/scsi/aic7xxx/Kconfig.aic79xx
@@ -0,0 +1,97 @@
+#
+# AIC79XX 2.5.X Kernel configuration File.
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic79xx#4 $
+#
+config SCSI_AIC79XX
+	tristate "Adaptec AIC79xx U320 support"
+	depends on PCI && SCSI
+	help
+	This driver supports all of Adaptec's Ultra 320 PCI-X
+	based SCSI controllers.
+
+config AIC79XX_CMDS_PER_DEVICE
+	int "Maximum number of TCQ commands per device"
+	depends on SCSI_AIC79XX
+	default "32"
+	---help---
+	Specify the number of commands you would like to allocate per SCSI
+	device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+	This is an upper bound value for the number of tagged transactions
+	to be used for any device.  The aic7xxx driver will automatically
+	vary this number based on device behavior.  For devices with a
+	fixed maximum, the driver will eventually lock to this maximum
+	and display a console message inidicating this value.
+
+	Due to resource allocation issues in the Linux SCSI mid-layer, using
+	a high number of commands per device may result in memory allocation
+	failures when many devices are attached to the system.  For this reason,
+	the default is set to 32.  Higher values may result in higer performance
+	on some devices.  The upper bound is 253.  0 disables tagged queueing.
+
+	Per device tag depth can be controlled via the kernel command line
+	"tag_info" option.  See drivers/scsi/aic7xxx/README.aic79xx
+	for details.
+
+config AIC79XX_RESET_DELAY_MS
+	int "Initial bus reset delay in milli-seconds"
+	depends on SCSI_AIC79XX
+	default "15000"
+	---help---
+	The number of milliseconds to delay after an initial bus reset.
+	The bus settle delay following all error recovery actions is
+	dictated by the SCSI layer and is not affected by this value.
+
+	Default: 15000 (15 seconds)
+
+config AIC79XX_BUILD_FIRMWARE
+	bool "Build Adapter Firmware with Kernel Build"
+	depends on SCSI_AIC79XX && !PREVENT_FIRMWARE_BUILD
+	help
+	This option should only be enabled if you are modifying the firmware
+	source to the aic79xx driver and wish to have the generated firmware
+	include files updated during a normal kernel build.  The assembler
+	for the firmware requires lex and yacc or their equivalents, as well
+	as the db v1 library.  You may have to install additional packages
+	or modify the assembler Makefile or the files it includes if your
+	build environment is different than that of the author.
+
+config AIC79XX_ENABLE_RD_STRM
+	bool "Enable Read Streaming for All Targets"
+	depends on SCSI_AIC79XX
+	default n
+	help
+	Read Streaming is a U320 protocol option that should enhance
+	performance.  Early U320 drive firmware actually performs slower
+	with read streaming enabled so it is disabled by default.  Read
+	Streaming can be configured in much the same way as tagged queueing
+	using the "rd_strm" command line option.  See
+	drivers/scsi/aic7xxx/README.aic79xx for details.
+
+config AIC79XX_DEBUG_ENABLE
+	bool "Compile in Debugging Code"
+	depends on SCSI_AIC79XX
+	default y
+	help
+	Compile in aic79xx debugging code that can be useful in diagnosing
+	driver errors.
+
+config AIC79XX_DEBUG_MASK
+	int "Debug code enable mask (16383 for all debugging)"
+	depends on SCSI_AIC79XX
+	default "0"
+	help
+	Bit mask of debug options that is only valid if the
+	CONFIG_AIC79XX_DEBUG_ENBLE option is enabled.  The bits in this mask
+	are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the
+	variable ahd_debug in that file to find them.
+
+config AIC79XX_REG_PRETTY_PRINT
+	bool "Decode registers during diagnostics"
+	depends on SCSI_AIC79XX
+	default y
+	help
+	Compile in register value tables for the output of expanded register
+	contents in diagnostics.  This make it much easier to understand debug
+	output without having to refer to a data book and/or the aic7xxx.reg
+	file.
diff --git a/drivers/scsi/aic7xxx/Kconfig.aic7xxx b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
new file mode 100644
index 0000000..8398e0d
--- /dev/null
+++ b/drivers/scsi/aic7xxx/Kconfig.aic7xxx
@@ -0,0 +1,100 @@
+#
+# AIC7XXX and AIC79XX 2.5.X Kernel configuration File.
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Kconfig.aic7xxx#7 $
+#
+config SCSI_AIC7XXX
+	tristate "Adaptec AIC7xxx Fast -> U160 support (New Driver)"
+	depends on (PCI || EISA) && SCSI
+	---help---
+	This driver supports all of Adaptec's Fast through Ultra 160 PCI
+	based SCSI controllers as well as the aic7770 based EISA and VLB
+	SCSI controllers (the 274x and 284x series).  For AAA and ARO based
+	configurations, only SCSI functionality is provided.
+
+	To compile this driver as a module, choose M here: the
+	module will be called aic7xxx.
+
+config AIC7XXX_CMDS_PER_DEVICE
+	int "Maximum number of TCQ commands per device"
+	depends on SCSI_AIC7XXX
+	default "32"
+	---help---
+	Specify the number of commands you would like to allocate per SCSI
+	device when Tagged Command Queueing (TCQ) is enabled on that device.
+
+	This is an upper bound value for the number of tagged transactions
+	to be used for any device.  The aic7xxx driver will automatically
+	vary this number based on device behavior.  For devices with a
+	fixed maximum, the driver will eventually lock to this maximum
+	and display a console message inidicating this value.
+
+	Due to resource allocation issues in the Linux SCSI mid-layer, using
+	a high number of commands per device may result in memory allocation
+	failures when many devices are attached to the system.  For this reason,
+	the default is set to 32.  Higher values may result in higer performance
+	on some devices.  The upper bound is 253.  0 disables tagged queueing.
+
+	Per device tag depth can be controlled via the kernel command line
+	"tag_info" option.  See drivers/scsi/aic7xxx/README.aic7xxx
+	for details.
+
+config AIC7XXX_RESET_DELAY_MS
+	int "Initial bus reset delay in milli-seconds"
+	depends on SCSI_AIC7XXX
+	default "15000"
+	---help---
+	The number of milliseconds to delay after an initial bus reset.
+	The bus settle delay following all error recovery actions is
+	dictated by the SCSI layer and is not affected by this value.
+
+	Default: 15000 (15 seconds)
+
+config AIC7XXX_PROBE_EISA_VL
+	bool "Probe for EISA and VL AIC7XXX Adapters"
+	depends on SCSI_AIC7XXX && EISA
+	help
+	Probe for EISA and VLB Aic7xxx controllers.  In many newer systems,
+	the invasive probes necessary to detect these controllers can cause
+	other devices to fail.  For this reason, the non-PCI probe code is
+	disabled by default.  The current value of this option can be "toggled"
+	via the no_probe kernel command line option.
+
+config AIC7XXX_BUILD_FIRMWARE
+	bool "Build Adapter Firmware with Kernel Build"
+	depends on SCSI_AIC7XXX && !PREVENT_FIRMWARE_BUILD
+	help
+	This option should only be enabled if you are modifying the firmware
+	source to the aic7xxx driver and wish to have the generated firmware
+	include files updated during a normal kernel build.  The assembler
+	for the firmware requires lex and yacc or their equivalents, as well
+	as the db v1 library.  You may have to install additional packages
+	or modify the assembler Makefile or the files it includes if your
+	build environment is different than that of the author.
+
+config AIC7XXX_DEBUG_ENABLE
+	bool "Compile in Debugging Code"
+	depends on SCSI_AIC7XXX
+	default y
+	help
+	Compile in aic7xxx debugging code that can be useful in diagnosing
+	driver errors.
+
+config AIC7XXX_DEBUG_MASK
+        int "Debug code enable mask (2047 for all debugging)"
+        depends on SCSI_AIC7XXX
+        default "0"
+        help
+	Bit mask of debug options that is only valid if the
+	CONFIG_AIC7XXX_DEBUG_ENBLE option is enabled.  The bits in this mask
+	are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the
+	variable ahc_debug in that file to find them.
+
+config AIC7XXX_REG_PRETTY_PRINT
+        bool "Decode registers during diagnostics"
+        depends on SCSI_AIC7XXX
+	default y
+        help
+	Compile in register value tables for the output of expanded register
+	contents in diagnostics.  This make it much easier to understand debug
+	output without having to refer to a data book and/or the aic7xxx.reg
+	file.
diff --git a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
new file mode 100644
index 0000000..9a6ce19
--- /dev/null
+++ b/drivers/scsi/aic7xxx/Makefile
@@ -0,0 +1,99 @@
+#
+# Makefile for the Linux aic7xxx SCSI driver.
+#
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#8 $
+#
+
+# Let kbuild descend into aicasm when cleaning
+subdir-				+= aicasm
+
+obj-$(CONFIG_SCSI_AIC7XXX)	+= aic7xxx.o
+obj-$(CONFIG_SCSI_AIC79XX)	+= aic79xx.o
+
+# Core Fast -> U160 files
+aic7xxx-y					+= aic7xxx_core.o	\
+						   aic7xxx_93cx6.o
+aic7xxx-$(CONFIG_EISA)				+= aic7770.o
+aic7xxx-$(CONFIG_PCI)				+= aic7xxx_pci.o
+aic7xxx-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT)	+= aic7xxx_reg_print.o
+
+# Platform Specific Fast -> U160 Files
+aic7xxx-y					+= aic7xxx_osm.o	\
+						   aic7xxx_proc.o
+aic7xxx-$(CONFIG_EISA)				+= aic7770_osm.o
+aic7xxx-$(CONFIG_PCI)				+= aic7xxx_osm_pci.o
+
+# Core U320 files
+aic79xx-y					+= aic79xx_core.o	\
+						   aic79xx_pci.o
+aic79xx-$(CONFIG_AIC79XX_REG_PRETTY_PRINT)	+= aic79xx_reg_print.o
+
+# Platform Specific U320 Files
+aic79xx-y					+= aic79xx_osm.o	\
+						   aic79xx_proc.o	\
+						   aic79xx_osm_pci.o
+
+EXTRA_CFLAGS += -Idrivers/scsi
+ifdef WARNINGS_BECOME_ERRORS
+EXTRA_CFLAGS += -Werror
+endif
+#EXTRA_CFLAGS += -g
+
+# Files generated that shall be removed upon make clean
+clean-files := aic7xxx_seq.h aic7xxx_reg.h aic7xxx_reg_print.c
+clean-files += aic79xx_seq.h aic79xx_reg.h aic79xx_reg_print.c
+
+# Dependencies for generated files need to be listed explicitly
+
+$(obj)/aic7xxx_core.o: $(obj)/aic7xxx_seq.h
+$(obj)/aic79xx_core.o: $(obj)/aic79xx_seq.h
+$(obj)/aic79xx_reg_print.c: $(src)/aic79xx_reg_print.c_shipped
+$(obj)/aic7xxx_reg_print.c: $(src)/aic7xxx_reg_print.c_shipped
+
+$(addprefix $(obj)/,$(aic7xxx-y)): $(obj)/aic7xxx_reg.h
+$(addprefix $(obj)/,$(aic79xx-y)): $(obj)/aic79xx_reg.h
+
+aic7xxx-gen-$(CONFIG_AIC7XXX_BUILD_FIRMWARE)	:= $(obj)/aic7xxx_seq.h \
+						   $(obj)/aic7xxx_reg.h
+aic7xxx-gen-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT)	+= $(obj)/aic7xxx_reg_print.c
+
+aicasm-7xxx-opts-$(CONFIG_AIC7XXX_REG_PRETTY_PRINT) := \
+	-p $(obj)/aic7xxx_reg_print.c -i aic7xxx_osm.h
+
+ifeq ($(CONFIG_AIC7XXX_BUILD_FIRMWARE),y)
+# Create a dependency chain in generated files
+# to avoid concurrent invocations of the single
+# rule that builds them all.
+aic7xxx_seq.h: aic7xxx_reg.h
+ifeq ($(CONFIG_AIC7XXX_REG_PRETTY_PRINT),y)
+aic7xxx_reg.h: aic7xxx_reg_print.c
+endif
+$(aic7xxx-gen-y): $(src)/aic7xxx.seq $(src)/aic7xxx.reg $(obj)/aicasm/aicasm
+	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic7xxx_reg.h \
+			      $(aicasm-7xxx-opts-y) -o $(obj)/aic7xxx_seq.h \
+			      $(src)/aic7xxx.seq
+endif
+
+aic79xx-gen-$(CONFIG_AIC79XX_BUILD_FIRMWARE)	:= $(obj)/aic79xx_seq.h \
+						   $(obj)/aic79xx_reg.h
+aic79xx-gen-$(CONFIG_AIC79XX_REG_PRETTY_PRINT)	+= $(obj)/aic79xx_reg_print.c
+
+aicasm-79xx-opts-$(CONFIG_AIC79XX_REG_PRETTY_PRINT) := \
+	-p $(obj)/aic79xx_reg_print.c -i aic79xx_osm.h
+
+ifeq ($(CONFIG_AIC79XX_BUILD_FIRMWARE),y)
+# Create a dependency chain in generated files
+# to avoid concurrent invocations of the single
+# rule that builds them all.
+aic79xx_seq.h: aic79xx_reg.h
+ifeq ($(CONFIG_AIC79XX_REG_PRETTY_PRINT),y)
+aic79xx_reg.h: aic79xx_reg_print.c
+endif
+$(aic79xx-gen-y): $(src)/aic79xx.seq $(src)/aic79xx.reg $(obj)/aicasm/aicasm
+	$(obj)/aicasm/aicasm -I$(src) -r $(obj)/aic79xx_reg.h \
+			      $(aicasm-79xx-opts-y) -o $(obj)/aic79xx_seq.h \
+			      $(src)/aic79xx.seq
+endif
+
+$(obj)/aicasm/aicasm: $(src)/aicasm/*.[chyl]
+	$(MAKE) -C $(src)/aicasm
diff --git a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
new file mode 100644
index 0000000..92703bb
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7770.c
@@ -0,0 +1,415 @@
+/*
+ * Product specific probe and attach routines for:
+ * 	27/284X and aic7770 motherboard SCSI controllers
+ *
+ * Copyright (c) 1994-1998, 2000, 2001 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#32 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+#else
+#include <dev/aic7xxx/aic7xxx_osm.h>
+#include <dev/aic7xxx/aic7xxx_inline.h>
+#include <dev/aic7xxx/aic7xxx_93cx6.h>
+#endif
+
+#define ID_AIC7770	0x04907770
+#define ID_AHA_274x	0x04907771
+#define ID_AHA_284xB	0x04907756 /* BIOS enabled */
+#define ID_AHA_284x	0x04907757 /* BIOS disabled*/
+#define	ID_OLV_274x	0x04907782 /* Olivetti OEM */
+#define	ID_OLV_274xD	0x04907783 /* Olivetti OEM (Differential) */
+
+static int aic7770_chip_init(struct ahc_softc *ahc);
+static int aic7770_suspend(struct ahc_softc *ahc);
+static int aic7770_resume(struct ahc_softc *ahc);
+static int aha2840_load_seeprom(struct ahc_softc *ahc);
+static ahc_device_setup_t ahc_aic7770_VL_setup;
+static ahc_device_setup_t ahc_aic7770_EISA_setup;
+static ahc_device_setup_t ahc_aic7770_setup;
+
+struct aic7770_identity aic7770_ident_table[] =
+{
+	{
+		ID_AHA_274x,
+		0xFFFFFFFF,
+		"Adaptec 274X SCSI adapter",
+		ahc_aic7770_EISA_setup
+	},
+	{
+		ID_AHA_284xB,
+		0xFFFFFFFE,
+		"Adaptec 284X SCSI adapter",
+		ahc_aic7770_VL_setup
+	},
+	{
+		ID_AHA_284x,
+		0xFFFFFFFE,
+		"Adaptec 284X SCSI adapter (BIOS Disabled)",
+		ahc_aic7770_VL_setup
+	},
+	{
+		ID_OLV_274x,
+		0xFFFFFFFF,
+		"Adaptec (Olivetti OEM) 274X SCSI adapter",
+		ahc_aic7770_EISA_setup
+	},
+	{
+		ID_OLV_274xD,
+		0xFFFFFFFF,
+		"Adaptec (Olivetti OEM) 274X Differential SCSI adapter",
+		ahc_aic7770_EISA_setup
+	},
+	/* Generic chip probes for devices we don't know 'exactly' */
+	{
+		ID_AIC7770,
+		0xFFFFFFFF,
+		"Adaptec aic7770 SCSI adapter",
+		ahc_aic7770_EISA_setup
+	}
+};
+const int ahc_num_aic7770_devs = NUM_ELEMENTS(aic7770_ident_table);
+
+struct aic7770_identity *
+aic7770_find_device(uint32_t id)
+{
+	struct	aic7770_identity *entry;
+	int	i;
+
+	for (i = 0; i < ahc_num_aic7770_devs; i++) {
+		entry = &aic7770_ident_table[i];
+		if (entry->full_id == (id & entry->id_mask))
+			return (entry);
+	}
+	return (NULL);
+}
+
+int
+aic7770_config(struct ahc_softc *ahc, struct aic7770_identity *entry, u_int io)
+{
+	u_long	l;
+	int	error;
+	int	have_seeprom;
+	u_int	hostconf;
+	u_int   irq;
+	u_int	intdef;
+
+	error = entry->setup(ahc);
+	have_seeprom = 0;
+	if (error != 0)
+		return (error);
+
+	error = aic7770_map_registers(ahc, io);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Before we continue probing the card, ensure that
+	 * its interrupts are *disabled*.  We don't want
+	 * a misstep to hang the machine in an interrupt
+	 * storm.
+	 */
+	ahc_intr_enable(ahc, FALSE);
+
+	ahc->description = entry->name;
+	error = ahc_softc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	ahc->bus_chip_init = aic7770_chip_init;
+	ahc->bus_suspend = aic7770_suspend;
+	ahc->bus_resume = aic7770_resume;
+
+	error = ahc_reset(ahc, /*reinit*/FALSE);
+	if (error != 0)
+		return (error);
+
+	/* Make sure we have a valid interrupt vector */
+	intdef = ahc_inb(ahc, INTDEF);
+	irq = intdef & VECTOR;
+	switch (irq) {
+	case 9:
+	case 10:
+	case 11:
+	case 12:
+	case 14:
+	case 15:
+		break;
+	default:
+		printf("aic7770_config: invalid irq setting %d\n", intdef);
+		return (ENXIO);
+	}
+
+	if ((intdef & EDGE_TRIG) != 0)
+		ahc->flags |= AHC_EDGE_INTERRUPT;
+
+	switch (ahc->chip & (AHC_EISA|AHC_VL)) {
+	case AHC_EISA:
+	{
+		u_int biosctrl;
+		u_int scsiconf;
+		u_int scsiconf1;
+
+		biosctrl = ahc_inb(ahc, HA_274_BIOSCTRL);
+		scsiconf = ahc_inb(ahc, SCSICONF);
+		scsiconf1 = ahc_inb(ahc, SCSICONF + 1);
+
+		/* Get the primary channel information */
+		if ((biosctrl & CHANNEL_B_PRIMARY) != 0)
+			ahc->flags |= 1;
+
+		if ((biosctrl & BIOSMODE) == BIOSDISABLED) {
+			ahc->flags |= AHC_USEDEFAULTS;
+		} else {
+			if ((ahc->features & AHC_WIDE) != 0) {
+				ahc->our_id = scsiconf1 & HWSCSIID;
+				if (scsiconf & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_A;
+			} else {
+				ahc->our_id = scsiconf & HSCSIID;
+				ahc->our_id_b = scsiconf1 & HSCSIID;
+				if (scsiconf & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_A;
+				if (scsiconf1 & TERM_ENB)
+					ahc->flags |= AHC_TERM_ENB_B;
+			}
+		}
+		if ((ahc_inb(ahc, HA_274_BIOSGLOBAL) & HA_274_EXTENDED_TRANS))
+			ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B;
+		break;
+	}
+	case AHC_VL:
+	{
+		have_seeprom = aha2840_load_seeprom(ahc);
+		break;
+	}
+	default:
+		break;
+	}
+	if (have_seeprom == 0) {
+		free(ahc->seep_config, M_DEVBUF);
+		ahc->seep_config = NULL;
+	}
+
+	/*
+	 * Ensure autoflush is enabled
+	 */
+	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
+
+	/* Setup the FIFO threshold and the bus off time */
+	hostconf = ahc_inb(ahc, HOSTCONF);
+	ahc_outb(ahc, BUSSPD, hostconf & DFTHRSH);
+	ahc_outb(ahc, BUSTIME, (hostconf << 2) & BOFF);
+
+	ahc->bus_softc.aic7770_softc.busspd = hostconf & DFTHRSH;
+	ahc->bus_softc.aic7770_softc.bustime = (hostconf << 2) & BOFF;
+
+	/*
+	 * Generic aic7xxx initialization.
+	 */
+	error = ahc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	error = aic7770_map_int(ahc, irq);
+	if (error != 0)
+		return (error);
+
+	ahc_list_lock(&l);
+	/*
+	 * Link this softc in with all other ahc instances.
+	 */
+	ahc_softc_insert(ahc);
+
+	/*
+	 * Enable the board's BUS drivers
+	 */
+	ahc_outb(ahc, BCTL, ENABLE);
+
+	ahc_list_unlock(&l);
+
+	return (0);
+}
+
+static int
+aic7770_chip_init(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, BUSSPD, ahc->bus_softc.aic7770_softc.busspd);
+	ahc_outb(ahc, BUSTIME, ahc->bus_softc.aic7770_softc.bustime);
+	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~AUTOFLUSHDIS);
+	ahc_outb(ahc, BCTL, ENABLE);
+	return (ahc_chip_init(ahc));
+}
+
+static int
+aic7770_suspend(struct ahc_softc *ahc)
+{
+	return (ahc_suspend(ahc));
+}
+
+static int
+aic7770_resume(struct ahc_softc *ahc)
+{
+	return (ahc_resume(ahc));
+}
+
+/*
+ * Read the 284x SEEPROM.
+ */
+static int
+aha2840_load_seeprom(struct ahc_softc *ahc)
+{
+	struct	seeprom_descriptor sd;
+	struct	seeprom_config *sc;
+	int	have_seeprom;
+	uint8_t scsi_conf;
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL_2840;
+	sd.sd_status_offset = STATUS_2840;
+	sd.sd_dataout_offset = STATUS_2840;		
+	sd.sd_chip = C46;
+	sd.sd_MS = 0;
+	sd.sd_RDY = EEPROM_TF;
+	sd.sd_CS = CS_2840;
+	sd.sd_CK = CK_2840;
+	sd.sd_DO = DO_2840;
+	sd.sd_DI = DI_2840;
+	sc = ahc->seep_config;
+
+	if (bootverbose)
+		printf("%s: Reading SEEPROM...", ahc_name(ahc));
+	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
+					/*start_addr*/0, sizeof(*sc)/2);
+
+	if (have_seeprom) {
+
+		if (ahc_verify_cksum(sc) == 0) {
+			if(bootverbose)
+				printf ("checksum error\n");
+			have_seeprom = 0;
+		} else if (bootverbose) {
+			printf("done.\n");
+		}
+	}
+
+	if (!have_seeprom) {
+		if (bootverbose)
+			printf("%s: No SEEPROM available\n", ahc_name(ahc));
+		ahc->flags |= AHC_USEDEFAULTS;
+	} else {
+		/*
+		 * Put the data we've collected down into SRAM
+		 * where ahc_init will find it.
+		 */
+		int	 i;
+		int	 max_targ;
+		uint16_t discenable;
+
+		max_targ = (ahc->features & AHC_WIDE) != 0 ? 16 : 8;
+		discenable = 0;
+		for (i = 0; i < max_targ; i++){
+			uint8_t target_settings;
+
+			target_settings = (sc->device_flags[i] & CFXFER) << 4;
+			if (sc->device_flags[i] & CFSYNCH)
+				target_settings |= SOFS;
+			if (sc->device_flags[i] & CFWIDEB)
+				target_settings |= WIDEXFER;
+			if (sc->device_flags[i] & CFDISC)
+				discenable |= (0x01 << i);
+			ahc_outb(ahc, TARG_SCSIRATE + i, target_settings);
+		}
+		ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+		ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+
+		ahc->our_id = sc->brtime_id & CFSCSIID;
+
+		scsi_conf = (ahc->our_id & 0x7);
+		if (sc->adapter_control & CFSPARITY)
+			scsi_conf |= ENSPCHK;
+		if (sc->adapter_control & CFRESETB)
+			scsi_conf |= RESET_SCSI;
+
+		if (sc->bios_control & CF284XEXTEND)		
+			ahc->flags |= AHC_EXTENDED_TRANS_A;
+		/* Set SCSICONF info */
+		ahc_outb(ahc, SCSICONF, scsi_conf);
+
+		if (sc->adapter_control & CF284XSTERM)
+			ahc->flags |= AHC_TERM_ENB_A;
+	}
+	return (have_seeprom);
+}
+
+static int
+ahc_aic7770_VL_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7770_setup(ahc);
+	ahc->chip |= AHC_VL;
+	return (error);
+}
+
+static int
+ahc_aic7770_EISA_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7770_setup(ahc);
+	ahc->chip |= AHC_EISA;
+	return (error);
+}
+
+static int
+ahc_aic7770_setup(struct ahc_softc *ahc)
+{
+	ahc->channel = 'A';
+	ahc->channel_b = 'B';
+	ahc->chip = AHC_AIC7770;
+	ahc->features = AHC_AIC7770_FE;
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
+	ahc->flags |= AHC_PAGESCBS;
+	ahc->instruction_ram_size = 448;
+	return (0);
+}
diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c
new file mode 100644
index 0000000..c2b47f2
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7770_osm.c
@@ -0,0 +1,264 @@
+/*
+ * Linux driver attachment glue for aic7770 based controllers.
+ *
+ * Copyright (c) 2000-2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7770_osm.c#14 $
+ */
+
+#include "aic7xxx_osm.h"
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#include <linux/device.h>
+#include <linux/eisa.h>
+
+#define EISA_MFCTR_CHAR0(ID) (char)(((ID>>26) & 0x1F) | '@')  /* Bits 26-30 */
+#define EISA_MFCTR_CHAR1(ID) (char)(((ID>>21) & 0x1F) | '@')  /* Bits 21-25 */
+#define EISA_MFCTR_CHAR2(ID) (char)(((ID>>16) & 0x1F) | '@')  /* Bits 16-20 */
+#define EISA_PRODUCT_ID(ID)  (short)((ID>>4)  & 0xFFF)        /* Bits  4-15 */
+#define EISA_REVISION_ID(ID) (uint8_t)(ID & 0x0F)             /* Bits  0-3  */
+
+static int aic7770_eisa_dev_probe(struct device *dev);
+static int aic7770_eisa_dev_remove(struct device *dev);
+static struct eisa_driver aic7770_driver = {
+	.driver = {
+		.name   = "aic7xxx",
+		.probe  = aic7770_eisa_dev_probe,
+		.remove = aic7770_eisa_dev_remove,
+	}
+};
+
+typedef  struct device *aic7770_dev_t;
+#else
+#define MINSLOT			1
+#define NUMSLOTS		16
+#define IDOFFSET		0x80
+
+typedef void *aic7770_dev_t;
+#endif
+
+static int aic7770_linux_config(struct aic7770_identity *entry,
+				aic7770_dev_t dev, u_int eisaBase);
+
+int
+ahc_linux_eisa_init(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	struct eisa_device_id *eid;
+	struct aic7770_identity *id;
+	int i;
+
+	if (aic7xxx_probe_eisa_vl == 0)
+		return -ENODEV;
+
+	/*
+	 * Linux requires the EISA IDs to be specified in
+	 * the EISA ID string format.  Perform the conversion
+	 * and setup a table with a NUL terminal entry.
+	 */
+	aic7770_driver.id_table = malloc(sizeof(struct eisa_device_id) *
+					 (ahc_num_aic7770_devs + 1),
+					 M_DEVBUF, M_NOWAIT);
+	if (aic7770_driver.id_table == NULL)
+		return -ENOMEM;
+
+	for (eid = (struct eisa_device_id *)aic7770_driver.id_table,
+	     id = aic7770_ident_table, i = 0;
+	     i < ahc_num_aic7770_devs; eid++, id++, i++) {
+
+		sprintf(eid->sig, "%c%c%c%03X%01X",
+			EISA_MFCTR_CHAR0(id->full_id),
+			EISA_MFCTR_CHAR1(id->full_id),
+			EISA_MFCTR_CHAR2(id->full_id),
+			EISA_PRODUCT_ID(id->full_id),
+			EISA_REVISION_ID(id->full_id));
+		eid->driver_data = i;
+	}
+	eid->sig[0] = 0;
+
+	return eisa_driver_register(&aic7770_driver);
+#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) */
+	struct aic7770_identity *entry;
+	u_int  slot;
+	u_int  eisaBase;
+	u_int  i;
+	int ret = -ENODEV;
+
+	if (aic7xxx_probe_eisa_vl == 0)
+		return ret;
+
+	eisaBase = 0x1000 + AHC_EISA_SLOT_OFFSET;
+	for (slot = 1; slot < NUMSLOTS; eisaBase+=0x1000, slot++) {
+		uint32_t eisa_id;
+		size_t	 id_size;
+
+		if (request_region(eisaBase, AHC_EISA_IOSIZE, "aic7xxx") == 0)
+			continue;
+
+		eisa_id = 0;
+		id_size = sizeof(eisa_id);
+		for (i = 0; i < 4; i++) {
+			/* VLcards require priming*/
+			outb(0x80 + i, eisaBase + IDOFFSET);
+			eisa_id |= inb(eisaBase + IDOFFSET + i)
+				   << ((id_size-i-1) * 8);
+		}
+		release_region(eisaBase, AHC_EISA_IOSIZE);
+		if (eisa_id & 0x80000000)
+			continue;  /* no EISA card in slot */
+
+		entry = aic7770_find_device(eisa_id);
+		if (entry != NULL) {
+			aic7770_linux_config(entry, NULL, eisaBase);
+			ret = 0;
+		}
+	}
+	return ret;
+#endif
+}
+
+void
+ahc_linux_eisa_exit(void)
+{
+	if(aic7xxx_probe_eisa_vl != 0 && aic7770_driver.id_table != NULL) {
+		eisa_driver_unregister(&aic7770_driver);
+		free(aic7770_driver.id_table, M_DEVBUF);
+	}
+}
+
+static int
+aic7770_linux_config(struct aic7770_identity *entry, aic7770_dev_t dev,
+		     u_int eisaBase)
+{
+	struct	ahc_softc *ahc;
+	char	buf[80];
+	char   *name;
+	int	error;
+
+	/*
+	 * Allocate a softc for this card and
+	 * set it up for attachment by our
+	 * common detect routine.
+	 */
+	sprintf(buf, "ahc_eisa:%d", eisaBase >> 12);
+	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (name == NULL)
+		return (ENOMEM);
+	strcpy(name, buf);
+	ahc = ahc_alloc(&aic7xxx_driver_template, name);
+	if (ahc == NULL)
+		return (ENOMEM);
+	error = aic7770_config(ahc, entry, eisaBase);
+	if (error != 0) {
+		ahc->bsh.ioport = 0;
+		ahc_free(ahc);
+		return (error);
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	dev->driver_data = (void *)ahc;
+	if (aic7xxx_detect_complete)
+		error = ahc_linux_register_host(ahc, &aic7xxx_driver_template);
+#endif
+	return (error);
+}
+
+int
+aic7770_map_registers(struct ahc_softc *ahc, u_int port)
+{
+	/*
+	 * Lock out other contenders for our i/o space.
+	 */
+	if (request_region(port, AHC_EISA_IOSIZE, "aic7xxx") == 0)
+		return (ENOMEM);
+	ahc->tag = BUS_SPACE_PIO;
+	ahc->bsh.ioport = port;
+	return (0);
+}
+
+int
+aic7770_map_int(struct ahc_softc *ahc, u_int irq)
+{
+	int error;
+	int shared;
+
+	shared = 0;
+	if ((ahc->flags & AHC_EDGE_INTERRUPT) == 0)
+		shared = SA_SHIRQ;
+
+	error = request_irq(irq, ahc_linux_isr, shared, "aic7xxx", ahc);
+	if (error == 0)
+		ahc->platform_data->irq = irq;
+	
+	return (-error);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int
+aic7770_eisa_dev_probe(struct device *dev)
+{
+	struct eisa_device *edev;
+
+	edev = to_eisa_device(dev);
+	return (aic7770_linux_config(aic7770_ident_table + edev->id.driver_data,
+				    dev, edev->base_addr+AHC_EISA_SLOT_OFFSET));
+}
+
+static int
+aic7770_eisa_dev_remove(struct device *dev)
+{
+	struct ahc_softc *ahc;
+	u_long l;
+
+	/*
+	 * We should be able to just perform
+	 * the free directly, but check our
+	 * list for extra sanity.
+	 */
+	ahc_list_lock(&l);
+	ahc = ahc_find_softc((struct ahc_softc *)dev->driver_data);
+	if (ahc != NULL) {
+		u_long s;
+
+		ahc_lock(ahc, &s);
+		ahc_intr_enable(ahc, FALSE);
+		ahc_unlock(ahc, &s);
+		ahc_free(ahc);
+	}
+	ahc_list_unlock(&l);
+
+	return (0);
+}
+#endif
diff --git a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
new file mode 100644
index 0000000..fd4b2f3
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx.h
@@ -0,0 +1,1537 @@
+/*
+ * Core definitions and data structures shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2002 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#95 $
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AIC79XX_H_
+#define _AIC79XX_H_
+
+/* Register Definitions */
+#include "aic79xx_reg.h"
+
+/************************* Forward Declarations *******************************/
+struct ahd_platform_data;
+struct scb_platform_data;
+
+/****************************** Useful Macros *********************************/
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))
+
+#define ALL_CHANNELS '\0'
+#define ALL_TARGETS_MASK 0xFFFF
+#define INITIATOR_WILDCARD	(~0)
+#define	SCB_LIST_NULL		0xFF00
+#define	SCB_LIST_NULL_LE	(ahd_htole16(SCB_LIST_NULL))
+#define QOUTFIFO_ENTRY_VALID 0x8000
+#define QOUTFIFO_ENTRY_VALID_LE (ahd_htole16(0x8000))
+#define SCBID_IS_NULL(scbid) (((scbid) & 0xFF00 ) == SCB_LIST_NULL)
+
+#define SCSIID_TARGET(ahd, scsiid)	\
+	(((scsiid) & TID) >> TID_SHIFT)
+#define SCSIID_OUR_ID(scsiid)		\
+	((scsiid) & OID)
+#define SCSIID_CHANNEL(ahd, scsiid) ('A')
+#define	SCB_IS_SCSIBUS_B(ahd, scb) (0)
+#define	SCB_GET_OUR_ID(scb) \
+	SCSIID_OUR_ID((scb)->hscb->scsiid)
+#define	SCB_GET_TARGET(ahd, scb) \
+	SCSIID_TARGET((ahd), (scb)->hscb->scsiid)
+#define	SCB_GET_CHANNEL(ahd, scb) \
+	SCSIID_CHANNEL(ahd, (scb)->hscb->scsiid)
+#define	SCB_GET_LUN(scb) \
+	((scb)->hscb->lun)
+#define SCB_GET_TARGET_OFFSET(ahd, scb)	\
+	SCB_GET_TARGET(ahd, scb)
+#define SCB_GET_TARGET_MASK(ahd, scb) \
+	(0x01 << (SCB_GET_TARGET_OFFSET(ahd, scb)))
+#ifdef AHD_DEBUG
+#define SCB_IS_SILENT(scb)					\
+	((ahd_debug & AHD_SHOW_MASKED_ERRORS) == 0		\
+      && (((scb)->flags & SCB_SILENT) != 0))
+#else
+#define SCB_IS_SILENT(scb)					\
+	(((scb)->flags & SCB_SILENT) != 0)
+#endif
+/*
+ * TCLs have the following format: TTTTLLLLLLLL
+ */
+#define TCL_TARGET_OFFSET(tcl) \
+	((((tcl) >> 4) & TID) >> 4)
+#define TCL_LUN(tcl) \
+	(tcl & (AHD_NUM_LUNS - 1))
+#define BUILD_TCL(scsiid, lun) \
+	((lun) | (((scsiid) & TID) << 4))
+#define BUILD_TCL_RAW(target, channel, lun) \
+	((lun) | ((target) << 8))
+
+#define SCB_GET_TAG(scb) \
+	ahd_le16toh(scb->hscb->tag)
+
+#ifndef	AHD_TARGET_MODE
+#undef	AHD_TMODE_ENABLE
+#define	AHD_TMODE_ENABLE 0
+#endif
+
+#define AHD_BUILD_COL_IDX(target, lun)				\
+	(((lun) << 4) | target)
+
+#define AHD_GET_SCB_COL_IDX(ahd, scb)				\
+	((SCB_GET_LUN(scb) << 4) | SCB_GET_TARGET(ahd, scb))
+
+#define AHD_SET_SCB_COL_IDX(scb, col_idx)				\
+do {									\
+	(scb)->hscb->scsiid = ((col_idx) << TID_SHIFT) & TID;		\
+	(scb)->hscb->lun = ((col_idx) >> 4) & (AHD_NUM_LUNS_NONPKT-1);	\
+} while (0)
+
+#define AHD_COPY_SCB_COL_IDX(dst, src)				\
+do {								\
+	dst->hscb->scsiid = src->hscb->scsiid;			\
+	dst->hscb->lun = src->hscb->lun;			\
+} while (0)
+
+#define	AHD_NEVER_COL_IDX 0xFFFF
+
+/**************************** Driver Constants ********************************/
+/*
+ * The maximum number of supported targets.
+ */
+#define AHD_NUM_TARGETS 16
+
+/*
+ * The maximum number of supported luns.
+ * The identify message only supports 64 luns in non-packetized transfers.
+ * You can have 2^64 luns when information unit transfers are enabled,
+ * but until we see a need to support that many, we support 256.
+ */
+#define AHD_NUM_LUNS_NONPKT 64
+#define AHD_NUM_LUNS 256
+
+/*
+ * The maximum transfer per S/G segment.
+ */
+#define AHD_MAXTRANSFER_SIZE	 0x00ffffff	/* limited by 24bit counter */
+
+/*
+ * The maximum amount of SCB storage in hardware on a controller.
+ * This value represents an upper bound.  Due to software design,
+ * we may not be able to use this number.
+ */
+#define AHD_SCB_MAX	512
+
+/*
+ * The maximum number of concurrent transactions supported per driver instance.
+ * Sequencer Control Blocks (SCBs) store per-transaction information.
+ */
+#define AHD_MAX_QUEUE	AHD_SCB_MAX
+
+/*
+ * Define the size of our QIN and QOUT FIFOs.  They must be a power of 2
+ * in size and accommodate as many transactions as can be queued concurrently.
+ */
+#define	AHD_QIN_SIZE	AHD_MAX_QUEUE
+#define	AHD_QOUT_SIZE	AHD_MAX_QUEUE
+
+#define AHD_QIN_WRAP(x) ((x) & (AHD_QIN_SIZE-1))
+/*
+ * The maximum amount of SCB storage we allocate in host memory.
+ */
+#define AHD_SCB_MAX_ALLOC AHD_MAX_QUEUE
+
+/*
+ * Ring Buffer of incoming target commands.
+ * We allocate 256 to simplify the logic in the sequencer
+ * by using the natural wrap point of an 8bit counter.
+ */
+#define AHD_TMODE_CMDS	256
+
+/* Reset line assertion time in us */
+#define AHD_BUSRESET_DELAY	25
+
+/******************* Chip Characteristics/Operating Settings  *****************/
+/*
+ * Chip Type
+ * The chip order is from least sophisticated to most sophisticated.
+ */
+typedef enum {
+	AHD_NONE	= 0x0000,
+	AHD_CHIPID_MASK	= 0x00FF,
+	AHD_AIC7901	= 0x0001,
+	AHD_AIC7902	= 0x0002,
+	AHD_AIC7901A	= 0x0003,
+	AHD_PCI		= 0x0100,	/* Bus type PCI */
+	AHD_PCIX	= 0x0200,	/* Bus type PCIX */
+	AHD_BUS_MASK	= 0x0F00
+} ahd_chip;
+
+/*
+ * Features available in each chip type.
+ */
+typedef enum {
+	AHD_FENONE		= 0x00000,
+	AHD_WIDE  		= 0x00001,/* Wide Channel */
+	AHD_MULTI_FUNC		= 0x00100,/* Multi-Function/Channel Device */
+	AHD_TARGETMODE		= 0x01000,/* Has tested target mode support */
+	AHD_MULTIROLE		= 0x02000,/* Space for two roles at a time */
+	AHD_RTI			= 0x04000,/* Retained Training Support */
+	AHD_NEW_IOCELL_OPTS	= 0x08000,/* More Signal knobs in the IOCELL */
+	AHD_NEW_DFCNTRL_OPTS	= 0x10000,/* SCSIENWRDIS bit */
+	AHD_FAST_CDB_DELIVERY	= 0x20000,/* CDB acks released to Output Sync */
+	AHD_REMOVABLE		= 0x00000,/* Hot-Swap supported - None so far*/
+	AHD_AIC7901_FE		= AHD_FENONE,
+	AHD_AIC7901A_FE		= AHD_FENONE,
+	AHD_AIC7902_FE		= AHD_MULTI_FUNC
+} ahd_feature;
+
+/*
+ * Bugs in the silicon that we work around in software.
+ */
+typedef enum {
+	AHD_BUGNONE		= 0x0000,
+	/*
+	 * Rev A hardware fails to update LAST/CURR/NEXTSCB
+	 * correctly in certain packetized selection cases.
+	 */
+	AHD_SENT_SCB_UPDATE_BUG	= 0x0001,
+	/* The wrong SCB is accessed to check the abort pending bit. */
+	AHD_ABORT_LQI_BUG	= 0x0002,
+	/* Packetized bitbucket crosses packet boundaries. */
+	AHD_PKT_BITBUCKET_BUG	= 0x0004,
+	/* The selection timer runs twice as long as its setting. */
+	AHD_LONG_SETIMO_BUG	= 0x0008,
+	/* The Non-LQ CRC error status is delayed until phase change. */
+	AHD_NLQICRC_DELAYED_BUG	= 0x0010,
+	/* The chip must be reset for all outgoing bus resets.  */
+	AHD_SCSIRST_BUG		= 0x0020,
+	/* Some PCIX fields must be saved and restored across chip reset. */
+	AHD_PCIX_CHIPRST_BUG	= 0x0040,
+	/* MMAPIO is not functional in PCI-X mode.  */
+	AHD_PCIX_MMAPIO_BUG	= 0x0080,
+	/* Reads to SCBRAM fail to reset the discard timer. */
+	AHD_PCIX_SCBRAM_RD_BUG  = 0x0100,
+	/* Bug workarounds that can be disabled on non-PCIX busses. */
+	AHD_PCIX_BUG_MASK	= AHD_PCIX_CHIPRST_BUG
+				| AHD_PCIX_MMAPIO_BUG
+				| AHD_PCIX_SCBRAM_RD_BUG,
+	/*
+	 * LQOSTOP0 status set even for forced selections with ATN
+	 * to perform non-packetized message delivery.
+	 */
+	AHD_LQO_ATNO_BUG	= 0x0200,
+	/* FIFO auto-flush does not always trigger.  */
+	AHD_AUTOFLUSH_BUG	= 0x0400,
+	/* The CLRLQO registers are not self-clearing. */
+	AHD_CLRLQO_AUTOCLR_BUG	= 0x0800,
+	/* The PACKETIZED status bit refers to the previous connection. */
+	AHD_PKTIZED_STATUS_BUG  = 0x1000,
+	/* "Short Luns" are not placed into outgoing LQ packets correctly. */
+	AHD_PKT_LUN_BUG		= 0x2000,
+	/*
+	 * Only the FIFO allocated to the non-packetized connection may
+	 * be in use during a non-packetzied connection.
+	 */
+	AHD_NONPACKFIFO_BUG	= 0x4000,
+	/*
+	 * Writing to a DFF SCBPTR register may fail if concurent with
+	 * a hardware write to the other DFF SCBPTR register.  This is
+	 * not currently a concern in our sequencer since all chips with
+	 * this bug have the AHD_NONPACKFIFO_BUG and all writes of concern
+	 * occur in non-packetized connections.
+	 */
+	AHD_MDFF_WSCBPTR_BUG	= 0x8000,
+	/* SGHADDR updates are slow. */
+	AHD_REG_SLOW_SETTLE_BUG	= 0x10000,
+	/*
+	 * Changing the MODE_PTR coincident with an interrupt that
+	 * switches to a different mode will cause the interrupt to
+	 * be in the mode written outside of interrupt context.
+	 */
+	AHD_SET_MODE_BUG	= 0x20000,
+	/* Non-packetized busfree revision does not work. */
+	AHD_BUSFREEREV_BUG	= 0x40000,
+	/*
+	 * Paced transfers are indicated with a non-standard PPR
+	 * option bit in the neg table, 160MHz is indicated by
+	 * sync factor 0x7, and the offset if off by a factor of 2.
+	 */
+	AHD_PACED_NEGTABLE_BUG	= 0x80000,
+	/* LQOOVERRUN false positives. */
+	AHD_LQOOVERRUN_BUG	= 0x100000,
+	/*
+	 * Controller write to INTSTAT will lose to a host
+	 * write to CLRINT.
+	 */
+	AHD_INTCOLLISION_BUG	= 0x200000,
+	/*
+	 * The GEM318 violates the SCSI spec by not waiting
+	 * the mandated bus settle delay between phase changes
+	 * in some situations.  Some aic79xx chip revs. are more
+	 * strict in this regard and will treat REQ assertions
+	 * that fall within the bus settle delay window as
+	 * glitches.  This flag tells the firmware to tolerate
+	 * early REQ assertions.
+	 */
+	AHD_EARLY_REQ_BUG	= 0x400000,
+	/*
+	 * The LED does not stay on long enough in packetized modes.
+	 */
+	AHD_FAINT_LED_BUG	= 0x800000
+} ahd_bug;
+
+/*
+ * Configuration specific settings.
+ * The driver determines these settings by probing the
+ * chip/controller's configuration.
+ */
+typedef enum {
+	AHD_FNONE	      = 0x00000,
+	AHD_BOOT_CHANNEL      = 0x00001,/* We were set as the boot channel. */
+	AHD_USEDEFAULTS	      = 0x00004,/*
+					 * For cards without an seeprom
+					 * or a BIOS to initialize the chip's
+					 * SRAM, we use the default target
+					 * settings.
+					 */
+	AHD_SEQUENCER_DEBUG   = 0x00008,
+	AHD_RESET_BUS_A	      = 0x00010,
+	AHD_EXTENDED_TRANS_A  = 0x00020,
+	AHD_TERM_ENB_A	      = 0x00040,
+	AHD_SPCHK_ENB_A	      = 0x00080,
+	AHD_STPWLEVEL_A	      = 0x00100,
+	AHD_INITIATORROLE     = 0x00200,/*
+					 * Allow initiator operations on
+					 * this controller.
+					 */
+	AHD_TARGETROLE	      = 0x00400,/*
+					 * Allow target operations on this
+					 * controller.
+					 */
+	AHD_RESOURCE_SHORTAGE = 0x00800,
+	AHD_TQINFIFO_BLOCKED  = 0x01000,/* Blocked waiting for ATIOs */
+	AHD_INT50_SPEEDFLEX   = 0x02000,/*
+					 * Internal 50pin connector
+					 * sits behind an aic3860
+					 */
+	AHD_BIOS_ENABLED      = 0x04000,
+	AHD_ALL_INTERRUPTS    = 0x08000,
+	AHD_39BIT_ADDRESSING  = 0x10000,/* Use 39 bit addressing scheme. */
+	AHD_64BIT_ADDRESSING  = 0x20000,/* Use 64 bit addressing scheme. */
+	AHD_CURRENT_SENSING   = 0x40000,
+	AHD_SCB_CONFIG_USED   = 0x80000,/* No SEEPROM but SCB had info. */
+	AHD_HP_BOARD	      = 0x100000,
+	AHD_RESET_POLL_ACTIVE = 0x200000,
+	AHD_UPDATE_PEND_CMDS  = 0x400000,
+	AHD_RUNNING_QOUTFIFO  = 0x800000,
+	AHD_HAD_FIRST_SEL     = 0x1000000
+} ahd_flag;
+
+/************************* Hardware  SCB Definition ***************************/
+
+/*
+ * The driver keeps up to MAX_SCB scb structures per card in memory.  The SCB
+ * consists of a "hardware SCB" mirroring the fields available on the card
+ * and additional information the kernel stores for each transaction.
+ *
+ * To minimize space utilization, a portion of the hardware scb stores
+ * different data during different portions of a SCSI transaction.
+ * As initialized by the host driver for the initiator role, this area
+ * contains the SCSI cdb (or a pointer to the  cdb) to be executed.  After
+ * the cdb has been presented to the target, this area serves to store
+ * residual transfer information and the SCSI status byte.
+ * For the target role, the contents of this area do not change, but
+ * still serve a different purpose than for the initiator role.  See
+ * struct target_data for details.
+ */
+
+/*
+ * Status information embedded in the shared poriton of
+ * an SCB after passing the cdb to the target.  The kernel
+ * driver will only read this data for transactions that
+ * complete abnormally.
+ */
+struct initiator_status {
+	uint32_t residual_datacnt;	/* Residual in the current S/G seg */
+	uint32_t residual_sgptr;	/* The next S/G for this transfer */
+	uint8_t	 scsi_status;		/* Standard SCSI status byte */
+};
+
+struct target_status {
+	uint32_t residual_datacnt;	/* Residual in the current S/G seg */
+	uint32_t residual_sgptr;	/* The next S/G for this transfer */
+	uint8_t  scsi_status;		/* SCSI status to give to initiator */
+	uint8_t  target_phases;		/* Bitmap of phases to execute */
+	uint8_t  data_phase;		/* Data-In or Data-Out */
+	uint8_t  initiator_tag;		/* Initiator's transaction tag */
+};
+
+/*
+ * Initiator mode SCB shared data area.
+ * If the embedded CDB is 12 bytes or less, we embed
+ * the sense buffer address in the SCB.  This allows
+ * us to retrieve sense information without interrupting
+ * the host in packetized mode.
+ */
+typedef uint32_t sense_addr_t;
+#define MAX_CDB_LEN 16
+#define MAX_CDB_LEN_WITH_SENSE_ADDR (MAX_CDB_LEN - sizeof(sense_addr_t))
+union initiator_data {
+	struct {
+		uint64_t cdbptr;
+		uint8_t  cdblen;
+	} cdb_from_host;
+	uint8_t	 cdb[MAX_CDB_LEN];
+	struct {
+		uint8_t	 cdb[MAX_CDB_LEN_WITH_SENSE_ADDR];
+		sense_addr_t sense_addr;
+	} cdb_plus_saddr;
+};
+
+/*
+ * Target mode version of the shared data SCB segment.
+ */
+struct target_data {
+	uint32_t spare[2];	
+	uint8_t  scsi_status;		/* SCSI status to give to initiator */
+	uint8_t  target_phases;		/* Bitmap of phases to execute */
+	uint8_t  data_phase;		/* Data-In or Data-Out */
+	uint8_t  initiator_tag;		/* Initiator's transaction tag */
+};
+
+struct hardware_scb {
+/*0*/	union {
+		union	initiator_data idata;
+		struct	target_data tdata;
+		struct	initiator_status istatus;
+		struct	target_status tstatus;
+	} shared_data;
+/*
+ * A word about residuals.
+ * The scb is presented to the sequencer with the dataptr and datacnt
+ * fields initialized to the contents of the first S/G element to
+ * transfer.  The sgptr field is initialized to the bus address for
+ * the S/G element that follows the first in the in core S/G array
+ * or'ed with the SG_FULL_RESID flag.  Sgptr may point to an invalid
+ * S/G entry for this transfer (single S/G element transfer with the
+ * first elements address and length preloaded in the dataptr/datacnt
+ * fields).  If no transfer is to occur, sgptr is set to SG_LIST_NULL.
+ * The SG_FULL_RESID flag ensures that the residual will be correctly
+ * noted even if no data transfers occur.  Once the data phase is entered,
+ * the residual sgptr and datacnt are loaded from the sgptr and the
+ * datacnt fields.  After each S/G element's dataptr and length are
+ * loaded into the hardware, the residual sgptr is advanced.  After
+ * each S/G element is expired, its datacnt field is checked to see
+ * if the LAST_SEG flag is set.  If so, SG_LIST_NULL is set in the
+ * residual sg ptr and the transfer is considered complete.  If the
+ * sequencer determines that there is a residual in the tranfer, or
+ * there is non-zero status, it will set the SG_STATUS_VALID flag in
+ * sgptr and dma the scb back into host memory.  To sumarize:
+ *
+ * Sequencer:
+ *	o A residual has occurred if SG_FULL_RESID is set in sgptr,
+ *	  or residual_sgptr does not have SG_LIST_NULL set.
+ *
+ *	o We are transfering the last segment if residual_datacnt has
+ *	  the SG_LAST_SEG flag set.
+ *
+ * Host:
+ *	o A residual can only have occurred if a completed scb has the
+ *	  SG_STATUS_VALID flag set.  Inspection of the SCSI status field,
+ *	  the residual_datacnt, and the residual_sgptr field will tell
+ *	  for sure.
+ *
+ *	o residual_sgptr and sgptr refer to the "next" sg entry
+ *	  and so may point beyond the last valid sg entry for the
+ *	  transfer.
+ */ 
+#define SG_PTR_MASK	0xFFFFFFF8
+/*16*/	uint16_t tag;		/* Reused by Sequencer. */
+/*18*/	uint8_t  control;	/* See SCB_CONTROL in aic79xx.reg for details */
+/*19*/	uint8_t	 scsiid;	/*
+				 * Selection out Id
+				 * Our Id (bits 0-3) Their ID (bits 4-7)
+				 */
+/*20*/	uint8_t  lun;
+/*21*/	uint8_t  task_attribute;
+/*22*/	uint8_t  cdb_len;
+/*23*/	uint8_t  task_management;
+/*24*/	uint64_t dataptr;
+/*32*/	uint32_t datacnt;	/* Byte 3 is spare. */
+/*36*/	uint32_t sgptr;
+/*40*/	uint32_t hscb_busaddr;
+/*44*/	uint32_t next_hscb_busaddr;
+/********** Long lun field only downloaded for full 8 byte lun support ********/
+/*48*/  uint8_t	 pkt_long_lun[8];
+/******* Fields below are not Downloaded (Sequencer may use for scratch) ******/
+/*56*/  uint8_t	 spare[8];
+};
+
+/************************ Kernel SCB Definitions ******************************/
+/*
+ * Some fields of the SCB are OS dependent.  Here we collect the
+ * definitions for elements that all OS platforms need to include
+ * in there SCB definition.
+ */
+
+/*
+ * Definition of a scatter/gather element as transfered to the controller.
+ * The aic7xxx chips only support a 24bit length.  We use the top byte of
+ * the length to store additional address bits and a flag to indicate
+ * that a given segment terminates the transfer.  This gives us an
+ * addressable range of 512GB on machines with 64bit PCI or with chips
+ * that can support dual address cycles on 32bit PCI busses.
+ */
+struct ahd_dma_seg {
+	uint32_t	addr;
+	uint32_t	len;
+#define	AHD_DMA_LAST_SEG	0x80000000
+#define	AHD_SG_HIGH_ADDR_MASK	0x7F000000
+#define	AHD_SG_LEN_MASK		0x00FFFFFF
+};
+
+struct ahd_dma64_seg {
+	uint64_t	addr;
+	uint32_t	len;
+	uint32_t	pad;
+};
+
+struct map_node {
+	bus_dmamap_t		 dmamap;
+	dma_addr_t		 physaddr;
+	uint8_t			*vaddr;
+	SLIST_ENTRY(map_node)	 links;
+};
+
+/*
+ * The current state of this SCB.
+ */
+typedef enum {
+	SCB_FLAG_NONE		= 0x00000,
+	SCB_TRANSMISSION_ERROR	= 0x00001,/*
+					   * We detected a parity or CRC
+					   * error that has effected the
+					   * payload of the command.  This
+					   * flag is checked when normal
+					   * status is returned to catch
+					   * the case of a target not
+					   * responding to our attempt
+					   * to report the error.
+					   */
+	SCB_OTHERTCL_TIMEOUT	= 0x00002,/*
+					   * Another device was active
+					   * during the first timeout for
+					   * this SCB so we gave ourselves
+					   * an additional timeout period
+					   * in case it was hogging the
+					   * bus.
+				           */
+	SCB_DEVICE_RESET	= 0x00004,
+	SCB_SENSE		= 0x00008,
+	SCB_CDB32_PTR		= 0x00010,
+	SCB_RECOVERY_SCB	= 0x00020,
+	SCB_AUTO_NEGOTIATE	= 0x00040,/* Negotiate to achieve goal. */
+	SCB_NEGOTIATE		= 0x00080,/* Negotiation forced for command. */
+	SCB_ABORT		= 0x00100,
+	SCB_ACTIVE		= 0x00200,
+	SCB_TARGET_IMMEDIATE	= 0x00400,
+	SCB_PACKETIZED		= 0x00800,
+	SCB_EXPECT_PPR_BUSFREE	= 0x01000,
+	SCB_PKT_SENSE		= 0x02000,
+	SCB_CMDPHASE_ABORT	= 0x04000,
+	SCB_ON_COL_LIST		= 0x08000,
+	SCB_SILENT		= 0x10000 /*
+					   * Be quiet about transmission type
+					   * errors.  They are expected and we
+					   * don't want to upset the user.  This
+					   * flag is typically used during DV.
+					   */
+} scb_flag;
+
+struct scb {
+	struct	hardware_scb	 *hscb;
+	union {
+		SLIST_ENTRY(scb)  sle;
+		LIST_ENTRY(scb)	  le;
+		TAILQ_ENTRY(scb)  tqe;
+	} links;
+	union {
+		SLIST_ENTRY(scb)  sle;
+		LIST_ENTRY(scb)	  le;
+		TAILQ_ENTRY(scb)  tqe;
+	} links2;
+#define pending_links links2.le
+#define collision_links links2.le
+	struct scb		 *col_scb;
+	ahd_io_ctx_t		  io_ctx;
+	struct ahd_softc	 *ahd_softc;
+	scb_flag		  flags;
+#ifndef __linux__
+	bus_dmamap_t		  dmamap;
+#endif
+	struct scb_platform_data *platform_data;
+	struct map_node	 	 *hscb_map;
+	struct map_node	 	 *sg_map;
+	struct map_node	 	 *sense_map;
+	void			 *sg_list;
+	uint8_t			 *sense_data;
+	dma_addr_t		  sg_list_busaddr;
+	dma_addr_t		  sense_busaddr;
+	u_int			  sg_count;/* How full ahd_dma_seg is */
+#define	AHD_MAX_LQ_CRC_ERRORS 5
+	u_int			  crc_retry_count;
+};
+
+TAILQ_HEAD(scb_tailq, scb);
+LIST_HEAD(scb_list, scb);
+
+struct scb_data {
+	/*
+	 * TAILQ of lists of free SCBs grouped by device
+	 * collision domains.
+	 */
+	struct scb_tailq free_scbs;
+
+	/*
+	 * Per-device lists of SCBs whose tag ID would collide
+	 * with an already active tag on the device.
+	 */
+	struct scb_list free_scb_lists[AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT];
+
+	/*
+	 * SCBs that will not collide with any active device.
+	 */
+	struct scb_list any_dev_free_scb_list;
+
+	/*
+	 * Mapping from tag to SCB.
+	 */
+	struct	scb *scbindex[AHD_SCB_MAX];
+
+	/*
+	 * "Bus" addresses of our data structures.
+	 */
+	bus_dma_tag_t	 hscb_dmat;	/* dmat for our hardware SCB array */
+	bus_dma_tag_t	 sg_dmat;	/* dmat for our sg segments */
+	bus_dma_tag_t	 sense_dmat;	/* dmat for our sense buffers */
+	SLIST_HEAD(, map_node) hscb_maps;
+	SLIST_HEAD(, map_node) sg_maps;
+	SLIST_HEAD(, map_node) sense_maps;
+	int		 scbs_left;	/* unallocated scbs in head map_node */
+	int		 sgs_left;	/* unallocated sgs in head map_node */
+	int		 sense_left;	/* unallocated sense in head map_node */
+	uint16_t	 numscbs;
+	uint16_t	 maxhscbs;	/* Number of SCBs on the card */
+	uint8_t		 init_level;	/*
+					 * How far we've initialized
+					 * this structure.
+					 */
+};
+
+/************************ Target Mode Definitions *****************************/
+
+/*
+ * Connection desciptor for select-in requests in target mode.
+ */
+struct target_cmd {
+	uint8_t scsiid;		/* Our ID and the initiator's ID */
+	uint8_t identify;	/* Identify message */
+	uint8_t bytes[22];	/* 
+				 * Bytes contains any additional message
+				 * bytes terminated by 0xFF.  The remainder
+				 * is the cdb to execute.
+				 */
+	uint8_t cmd_valid;	/*
+				 * When a command is complete, the firmware
+				 * will set cmd_valid to all bits set.
+				 * After the host has seen the command,
+				 * the bits are cleared.  This allows us
+				 * to just peek at host memory to determine
+				 * if more work is complete. cmd_valid is on
+				 * an 8 byte boundary to simplify setting
+				 * it on aic7880 hardware which only has
+				 * limited direct access to the DMA FIFO.
+				 */
+	uint8_t pad[7];
+};
+
+/*
+ * Number of events we can buffer up if we run out
+ * of immediate notify ccbs.
+ */
+#define AHD_TMODE_EVENT_BUFFER_SIZE 8
+struct ahd_tmode_event {
+	uint8_t initiator_id;
+	uint8_t event_type;	/* MSG type or EVENT_TYPE_BUS_RESET */
+#define	EVENT_TYPE_BUS_RESET 0xFF
+	uint8_t event_arg;
+};
+
+/*
+ * Per enabled lun target mode state.
+ * As this state is directly influenced by the host OS'es target mode
+ * environment, we let the OS module define it.  Forward declare the
+ * structure here so we can store arrays of them, etc. in OS neutral
+ * data structures.
+ */
+#ifdef AHD_TARGET_MODE 
+struct ahd_tmode_lstate {
+	struct cam_path *path;
+	struct ccb_hdr_slist accept_tios;
+	struct ccb_hdr_slist immed_notifies;
+	struct ahd_tmode_event event_buffer[AHD_TMODE_EVENT_BUFFER_SIZE];
+	uint8_t event_r_idx;
+	uint8_t event_w_idx;
+};
+#else
+struct ahd_tmode_lstate;
+#endif
+
+/******************** Transfer Negotiation Datastructures *********************/
+#define AHD_TRANS_CUR		0x01	/* Modify current neogtiation status */
+#define AHD_TRANS_ACTIVE	0x03	/* Assume this target is on the bus */
+#define AHD_TRANS_GOAL		0x04	/* Modify negotiation goal */
+#define AHD_TRANS_USER		0x08	/* Modify user negotiation settings */
+#define AHD_PERIOD_10MHz	0x19
+
+#define AHD_WIDTH_UNKNOWN	0xFF
+#define AHD_PERIOD_UNKNOWN	0xFF
+#define AHD_OFFSET_UNKNOWN	0xFF
+#define AHD_PPR_OPTS_UNKNOWN	0xFF
+
+/*
+ * Transfer Negotiation Information.
+ */
+struct ahd_transinfo {
+	uint8_t protocol_version;	/* SCSI Revision level */
+	uint8_t transport_version;	/* SPI Revision level */
+	uint8_t width;			/* Bus width */
+	uint8_t period;			/* Sync rate factor */
+	uint8_t offset;			/* Sync offset */
+	uint8_t ppr_options;		/* Parallel Protocol Request options */
+};
+
+/*
+ * Per-initiator current, goal and user transfer negotiation information. */
+struct ahd_initiator_tinfo {
+	struct ahd_transinfo curr;
+	struct ahd_transinfo goal;
+	struct ahd_transinfo user;
+};
+
+/*
+ * Per enabled target ID state.
+ * Pointers to lun target state as well as sync/wide negotiation information
+ * for each initiator<->target mapping.  For the initiator role we pretend
+ * that we are the target and the targets are the initiators since the
+ * negotiation is the same regardless of role.
+ */
+struct ahd_tmode_tstate {
+	struct ahd_tmode_lstate*	enabled_luns[AHD_NUM_LUNS];
+	struct ahd_initiator_tinfo	transinfo[AHD_NUM_TARGETS];
+
+	/*
+	 * Per initiator state bitmasks.
+	 */
+	uint16_t	 auto_negotiate;/* Auto Negotiation Required */
+	uint16_t	 discenable;	/* Disconnection allowed  */
+	uint16_t	 tagenable;	/* Tagged Queuing allowed */
+};
+
+/*
+ * Points of interest along the negotiated transfer scale.
+ */
+#define AHD_SYNCRATE_160	0x8
+#define AHD_SYNCRATE_PACED	0x8
+#define AHD_SYNCRATE_DT		0x9
+#define AHD_SYNCRATE_ULTRA2	0xa
+#define AHD_SYNCRATE_ULTRA	0xc
+#define AHD_SYNCRATE_FAST	0x19
+#define AHD_SYNCRATE_MIN_DT	AHD_SYNCRATE_FAST
+#define AHD_SYNCRATE_SYNC	0x32
+#define AHD_SYNCRATE_MIN	0x60
+#define	AHD_SYNCRATE_ASYNC	0xFF
+#define AHD_SYNCRATE_MAX	AHD_SYNCRATE_160
+
+/* Safe and valid period for async negotiations. */
+#define	AHD_ASYNC_XFER_PERIOD	0x44
+
+/*
+ * In RevA, the synctable uses a 120MHz rate for the period
+ * factor 8 and 160MHz for the period factor 7.  The 120MHz
+ * rate never made it into the official SCSI spec, so we must
+ * compensate when setting the negotiation table for Rev A
+ * parts.
+ */
+#define AHD_SYNCRATE_REVA_120	0x8
+#define AHD_SYNCRATE_REVA_160	0x7
+
+/***************************** Lookup Tables **********************************/
+/*
+ * Phase -> name and message out response
+ * to parity errors in each phase table. 
+ */
+struct ahd_phase_table_entry {
+        uint8_t phase;
+        uint8_t mesg_out; /* Message response to parity errors */
+	char *phasemsg;
+};
+
+/************************** Serial EEPROM Format ******************************/
+
+struct seeprom_config {
+/*
+ * Per SCSI ID Configuration Flags
+ */
+	uint16_t device_flags[16];	/* words 0-15 */
+#define		CFXFER		0x003F	/* synchronous transfer rate */
+#define			CFXFER_ASYNC	0x3F
+#define		CFQAS		0x0040	/* Negotiate QAS */
+#define		CFPACKETIZED	0x0080	/* Negotiate Packetized Transfers */
+#define		CFSTART		0x0100	/* send start unit SCSI command */
+#define		CFINCBIOS	0x0200	/* include in BIOS scan */
+#define		CFDISC		0x0400	/* enable disconnection */
+#define		CFMULTILUNDEV	0x0800	/* Probe multiple luns in BIOS scan */
+#define		CFWIDEB		0x1000	/* wide bus device */
+#define		CFHOSTMANAGED	0x8000	/* Managed by a RAID controller */
+
+/*
+ * BIOS Control Bits
+ */
+	uint16_t bios_control;		/* word 16 */
+#define		CFSUPREM	0x0001	/* support all removeable drives */
+#define		CFSUPREMB	0x0002	/* support removeable boot drives */
+#define		CFBIOSSTATE	0x000C	/* BIOS Action State */
+#define		    CFBS_DISABLED	0x00
+#define		    CFBS_ENABLED	0x04
+#define		    CFBS_DISABLED_SCAN	0x08
+#define		CFENABLEDV	0x0010	/* Perform Domain Validation */
+#define		CFCTRL_A	0x0020	/* BIOS displays Ctrl-A message */	
+#define		CFSPARITY	0x0040	/* SCSI parity */
+#define		CFEXTEND	0x0080	/* extended translation enabled */
+#define		CFBOOTCD	0x0100  /* Support Bootable CD-ROM */
+#define		CFMSG_LEVEL	0x0600	/* BIOS Message Level */
+#define			CFMSG_VERBOSE	0x0000
+#define			CFMSG_SILENT	0x0200
+#define			CFMSG_DIAG	0x0400
+#define		CFRESETB	0x0800	/* reset SCSI bus at boot */
+/*		UNUSED		0xf000	*/
+
+/*
+ * Host Adapter Control Bits
+ */
+	uint16_t adapter_control;	/* word 17 */	
+#define		CFAUTOTERM	0x0001	/* Perform Auto termination */
+#define		CFSTERM		0x0002	/* SCSI low byte termination */
+#define		CFWSTERM	0x0004	/* SCSI high byte termination */
+#define		CFSEAUTOTERM	0x0008	/* Ultra2 Perform secondary Auto Term*/
+#define		CFSELOWTERM	0x0010	/* Ultra2 secondary low term */
+#define		CFSEHIGHTERM	0x0020	/* Ultra2 secondary high term */
+#define		CFSTPWLEVEL	0x0040	/* Termination level control */
+#define		CFBIOSAUTOTERM	0x0080	/* Perform Auto termination */
+#define		CFTERM_MENU	0x0100	/* BIOS displays termination menu */	
+#define		CFCLUSTERENB	0x8000	/* Cluster Enable */
+
+/*
+ * Bus Release Time, Host Adapter ID
+ */
+	uint16_t brtime_id;		/* word 18 */
+#define		CFSCSIID	0x000f	/* host adapter SCSI ID */
+/*		UNUSED		0x00f0	*/
+#define		CFBRTIME	0xff00	/* bus release time/PCI Latency Time */
+
+/*
+ * Maximum targets
+ */
+	uint16_t max_targets;		/* word 19 */	
+#define		CFMAXTARG	0x00ff	/* maximum targets */
+#define		CFBOOTLUN	0x0f00	/* Lun to boot from */
+#define		CFBOOTID	0xf000	/* Target to boot from */
+	uint16_t res_1[10];		/* words 20-29 */
+	uint16_t signature;		/* BIOS Signature */
+#define		CFSIGNATURE	0x400
+	uint16_t checksum;		/* word 31 */
+};
+
+/*
+ * Vital Product Data used during POST and by the BIOS.
+ */
+struct vpd_config {
+	uint8_t  bios_flags;
+#define		VPDMASTERBIOS	0x0001
+#define		VPDBOOTHOST	0x0002
+	uint8_t  reserved_1[21];
+	uint8_t  resource_type;
+	uint8_t  resource_len[2];
+	uint8_t  resource_data[8];
+	uint8_t  vpd_tag;
+	uint16_t vpd_len;
+	uint8_t  vpd_keyword[2];
+	uint8_t  length;
+	uint8_t  revision;
+	uint8_t  device_flags;
+	uint8_t  termnation_menus[2];
+	uint8_t  fifo_threshold;
+	uint8_t  end_tag;
+	uint8_t  vpd_checksum;
+	uint16_t default_target_flags;
+	uint16_t default_bios_flags;
+	uint16_t default_ctrl_flags;
+	uint8_t  default_irq;
+	uint8_t  pci_lattime;
+	uint8_t  max_target;
+	uint8_t  boot_lun;
+	uint16_t signature;
+	uint8_t  reserved_2;
+	uint8_t  checksum;
+	uint8_t	 reserved_3[4];
+};
+
+/****************************** Flexport Logic ********************************/
+#define FLXADDR_TERMCTL			0x0
+#define		FLX_TERMCTL_ENSECHIGH	0x8
+#define		FLX_TERMCTL_ENSECLOW	0x4
+#define		FLX_TERMCTL_ENPRIHIGH	0x2
+#define		FLX_TERMCTL_ENPRILOW	0x1
+#define FLXADDR_ROMSTAT_CURSENSECTL	0x1
+#define		FLX_ROMSTAT_SEECFG	0xF0
+#define		FLX_ROMSTAT_EECFG	0x0F
+#define		FLX_ROMSTAT_SEE_93C66	0x00
+#define		FLX_ROMSTAT_SEE_NONE	0xF0
+#define		FLX_ROMSTAT_EE_512x8	0x0
+#define		FLX_ROMSTAT_EE_1MBx8	0x1
+#define		FLX_ROMSTAT_EE_2MBx8	0x2
+#define		FLX_ROMSTAT_EE_4MBx8	0x3
+#define		FLX_ROMSTAT_EE_16MBx8	0x4
+#define 		CURSENSE_ENB	0x1
+#define	FLXADDR_FLEXSTAT		0x2
+#define		FLX_FSTAT_BUSY		0x1
+#define FLXADDR_CURRENT_STAT		0x4
+#define		FLX_CSTAT_SEC_HIGH	0xC0
+#define		FLX_CSTAT_SEC_LOW	0x30
+#define		FLX_CSTAT_PRI_HIGH	0x0C
+#define		FLX_CSTAT_PRI_LOW	0x03
+#define		FLX_CSTAT_MASK		0x03
+#define		FLX_CSTAT_SHIFT		2
+#define		FLX_CSTAT_OKAY		0x0
+#define		FLX_CSTAT_OVER		0x1
+#define		FLX_CSTAT_UNDER		0x2
+#define		FLX_CSTAT_INVALID	0x3
+
+int		ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
+				 u_int start_addr, u_int count, int bstream);
+
+int		ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
+				  u_int start_addr, u_int count);
+int		ahd_wait_seeprom(struct ahd_softc *ahd);
+int		ahd_verify_vpd_cksum(struct vpd_config *vpd);
+int		ahd_verify_cksum(struct seeprom_config *sc);
+int		ahd_acquire_seeprom(struct ahd_softc *ahd);
+void		ahd_release_seeprom(struct ahd_softc *ahd);
+
+/****************************  Message Buffer *********************************/
+typedef enum {
+	MSG_FLAG_NONE			= 0x00,
+	MSG_FLAG_EXPECT_PPR_BUSFREE	= 0x01,
+	MSG_FLAG_IU_REQ_CHANGED		= 0x02,
+	MSG_FLAG_EXPECT_IDE_BUSFREE	= 0x04,
+	MSG_FLAG_EXPECT_QASREJ_BUSFREE	= 0x08,
+	MSG_FLAG_PACKETIZED		= 0x10
+} ahd_msg_flags;
+
+typedef enum {
+	MSG_TYPE_NONE			= 0x00,
+	MSG_TYPE_INITIATOR_MSGOUT	= 0x01,
+	MSG_TYPE_INITIATOR_MSGIN	= 0x02,
+	MSG_TYPE_TARGET_MSGOUT		= 0x03,
+	MSG_TYPE_TARGET_MSGIN		= 0x04
+} ahd_msg_type;
+
+typedef enum {
+	MSGLOOP_IN_PROG,
+	MSGLOOP_MSGCOMPLETE,
+	MSGLOOP_TERMINATED
+} msg_loop_stat;
+
+/*********************** Software Configuration Structure *********************/
+struct ahd_suspend_channel_state {
+	uint8_t	scsiseq;
+	uint8_t	sxfrctl0;
+	uint8_t	sxfrctl1;
+	uint8_t	simode0;
+	uint8_t	simode1;
+	uint8_t	seltimer;
+	uint8_t	seqctl;
+};
+
+struct ahd_suspend_state {
+	struct	ahd_suspend_channel_state channel[2];
+	uint8_t	optionmode;
+	uint8_t	dscommand0;
+	uint8_t	dspcistatus;
+	/* hsmailbox */
+	uint8_t	crccontrol1;
+	uint8_t	scbbaddr;
+	/* Host and sequencer SCB counts */
+	uint8_t	dff_thrsh;
+	uint8_t	*scratch_ram;
+	uint8_t	*btt;
+};
+
+typedef void (*ahd_bus_intr_t)(struct ahd_softc *);
+
+typedef enum {
+	AHD_MODE_DFF0,
+	AHD_MODE_DFF1,
+	AHD_MODE_CCHAN,
+	AHD_MODE_SCSI,
+	AHD_MODE_CFG,
+	AHD_MODE_UNKNOWN
+} ahd_mode;
+
+#define AHD_MK_MSK(x) (0x01 << (x))
+#define AHD_MODE_DFF0_MSK	AHD_MK_MSK(AHD_MODE_DFF0)
+#define AHD_MODE_DFF1_MSK	AHD_MK_MSK(AHD_MODE_DFF1)
+#define AHD_MODE_CCHAN_MSK	AHD_MK_MSK(AHD_MODE_CCHAN)
+#define AHD_MODE_SCSI_MSK	AHD_MK_MSK(AHD_MODE_SCSI)
+#define AHD_MODE_CFG_MSK	AHD_MK_MSK(AHD_MODE_CFG)
+#define AHD_MODE_UNKNOWN_MSK	AHD_MK_MSK(AHD_MODE_UNKNOWN)
+#define AHD_MODE_ANY_MSK (~0)
+
+typedef uint8_t ahd_mode_state;
+
+typedef void ahd_callback_t (void *);
+
+struct ahd_softc {
+	bus_space_tag_t           tags[2];
+	bus_space_handle_t        bshs[2];
+#ifndef __linux__
+	bus_dma_tag_t		  buffer_dmat;   /* dmat for buffer I/O */
+#endif
+	struct scb_data		  scb_data;
+
+	struct hardware_scb	 *next_queued_hscb;
+
+	/*
+	 * SCBs that have been sent to the controller
+	 */
+	LIST_HEAD(, scb)	  pending_scbs;
+
+	/*
+	 * Current register window mode information.
+	 */
+	ahd_mode		  dst_mode;
+	ahd_mode		  src_mode;
+
+	/*
+	 * Saved register window mode information
+	 * used for restore on next unpause.
+	 */
+	ahd_mode		  saved_dst_mode;
+	ahd_mode		  saved_src_mode;
+
+	/*
+	 * Platform specific data.
+	 */
+	struct ahd_platform_data *platform_data;
+
+	/*
+	 * Platform specific device information.
+	 */
+	ahd_dev_softc_t		  dev_softc;
+
+	/*
+	 * Bus specific device information.
+	 */
+	ahd_bus_intr_t		  bus_intr;
+
+	/*
+	 * Target mode related state kept on a per enabled lun basis.
+	 * Targets that are not enabled will have null entries.
+	 * As an initiator, we keep one target entry for our initiator
+	 * ID to store our sync/wide transfer settings.
+	 */
+	struct ahd_tmode_tstate  *enabled_targets[AHD_NUM_TARGETS];
+
+	/*
+	 * The black hole device responsible for handling requests for
+	 * disabled luns on enabled targets.
+	 */
+	struct ahd_tmode_lstate  *black_hole;
+
+	/*
+	 * Device instance currently on the bus awaiting a continue TIO
+	 * for a command that was not given the disconnect priveledge.
+	 */
+	struct ahd_tmode_lstate  *pending_device;
+
+	/*
+	 * Timer handles for timer driven callbacks.
+	 */
+	ahd_timer_t		  reset_timer;
+	ahd_timer_t		  stat_timer;
+
+	/*
+	 * Statistics.
+	 */
+#define	AHD_STAT_UPDATE_US	250000 /* 250ms */
+#define	AHD_STAT_BUCKETS	4
+	u_int			  cmdcmplt_bucket;
+	uint32_t		  cmdcmplt_counts[AHD_STAT_BUCKETS];
+	uint32_t		  cmdcmplt_total;
+
+	/*
+	 * Card characteristics
+	 */
+	ahd_chip		  chip;
+	ahd_feature		  features;
+	ahd_bug			  bugs;
+	ahd_flag		  flags;
+	struct seeprom_config	 *seep_config;
+
+	/* Values to store in the SEQCTL register for pause and unpause */
+	uint8_t			  unpause;
+	uint8_t			  pause;
+
+	/* Command Queues */
+	uint16_t		  qoutfifonext;
+	uint16_t		  qoutfifonext_valid_tag;
+	uint16_t		  qinfifonext;
+	uint16_t		  qinfifo[AHD_SCB_MAX];
+	uint16_t		 *qoutfifo;
+
+	/* Critical Section Data */
+	struct cs		 *critical_sections;
+	u_int			  num_critical_sections;
+
+	/* Buffer for handling packetized bitbucket. */
+	uint8_t			 *overrun_buf;
+
+	/* Links for chaining softcs */
+	TAILQ_ENTRY(ahd_softc)	  links;
+
+	/* Channel Names ('A', 'B', etc.) */
+	char			  channel;
+
+	/* Initiator Bus ID */
+	uint8_t			  our_id;
+
+	/*
+	 * Target incoming command FIFO.
+	 */
+	struct target_cmd	 *targetcmds;
+	uint8_t			  tqinfifonext;
+
+	/*
+	 * Cached verson of the hs_mailbox so we can avoid
+	 * pausing the sequencer during mailbox updates.
+	 */
+	uint8_t			  hs_mailbox;
+
+	/*
+	 * Incoming and outgoing message handling.
+	 */
+	uint8_t			  send_msg_perror;
+	ahd_msg_flags		  msg_flags;
+	ahd_msg_type		  msg_type;
+	uint8_t			  msgout_buf[12];/* Message we are sending */
+	uint8_t			  msgin_buf[12];/* Message we are receiving */
+	u_int			  msgout_len;	/* Length of message to send */
+	u_int			  msgout_index;	/* Current index in msgout */
+	u_int			  msgin_index;	/* Current index in msgin */
+
+	/*
+	 * Mapping information for data structures shared
+	 * between the sequencer and kernel.
+	 */
+	bus_dma_tag_t		  parent_dmat;
+	bus_dma_tag_t		  shared_data_dmat;
+	bus_dmamap_t		  shared_data_dmamap;
+	dma_addr_t		  shared_data_busaddr;
+
+	/* Information saved through suspend/resume cycles */
+	struct ahd_suspend_state  suspend_state;
+
+	/* Number of enabled target mode device on this card */
+	u_int			  enabled_luns;
+
+	/* Initialization level of this data structure */
+	u_int			  init_level;
+
+	/* PCI cacheline size. */
+	u_int			  pci_cachesize;
+
+	/* IO Cell Parameters */
+	uint8_t			  iocell_opts[AHD_NUM_PER_DEV_ANNEXCOLS];
+
+	u_int			  stack_size;
+	uint16_t		 *saved_stack;
+
+	/* Per-Unit descriptive information */
+	const char		 *description;
+	const char		 *bus_description;
+	char			 *name;
+	int			  unit;
+
+	/* Selection Timer settings */
+	int			  seltime;
+
+	/*
+	 * Interrupt coalescing settings.
+	 */
+#define	AHD_INT_COALESCING_TIMER_DEFAULT		250 /*us*/
+#define	AHD_INT_COALESCING_MAXCMDS_DEFAULT		10
+#define	AHD_INT_COALESCING_MAXCMDS_MAX			127
+#define	AHD_INT_COALESCING_MINCMDS_DEFAULT		5
+#define	AHD_INT_COALESCING_MINCMDS_MAX			127
+#define	AHD_INT_COALESCING_THRESHOLD_DEFAULT		2000
+#define	AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT	1000
+	u_int			  int_coalescing_timer;
+	u_int			  int_coalescing_maxcmds;
+	u_int			  int_coalescing_mincmds;
+	u_int			  int_coalescing_threshold;
+	u_int			  int_coalescing_stop_threshold;
+
+	uint16_t	 	  user_discenable;/* Disconnection allowed  */
+	uint16_t		  user_tagenable;/* Tagged Queuing allowed */
+};
+
+TAILQ_HEAD(ahd_softc_tailq, ahd_softc);
+extern struct ahd_softc_tailq ahd_tailq;
+
+/*************************** IO Cell Configuration ****************************/
+#define	AHD_PRECOMP_SLEW_INDEX						\
+    (AHD_ANNEXCOL_PRECOMP_SLEW - AHD_ANNEXCOL_PER_DEV0)
+
+#define	AHD_AMPLITUDE_INDEX						\
+    (AHD_ANNEXCOL_AMPLITUDE - AHD_ANNEXCOL_PER_DEV0)
+
+#define AHD_SET_SLEWRATE(ahd, new_slew)					\
+do {									\
+    (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_SLEWRATE_MASK;	\
+    (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |=			\
+	(((new_slew) << AHD_SLEWRATE_SHIFT) & AHD_SLEWRATE_MASK);	\
+} while (0)
+
+#define AHD_SET_PRECOMP(ahd, new_pcomp)					\
+do {									\
+    (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK;	\
+    (ahd)->iocell_opts[AHD_PRECOMP_SLEW_INDEX] |=			\
+	(((new_pcomp) << AHD_PRECOMP_SHIFT) & AHD_PRECOMP_MASK);	\
+} while (0)
+
+#define AHD_SET_AMPLITUDE(ahd, new_amp)					\
+do {									\
+    (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] &= ~AHD_AMPLITUDE_MASK;	\
+    (ahd)->iocell_opts[AHD_AMPLITUDE_INDEX] |=				\
+	(((new_amp) << AHD_AMPLITUDE_SHIFT) & AHD_AMPLITUDE_MASK);	\
+} while (0)
+
+/************************ Active Device Information ***************************/
+typedef enum {
+	ROLE_UNKNOWN,
+	ROLE_INITIATOR,
+	ROLE_TARGET
+} role_t;
+
+struct ahd_devinfo {
+	int	 our_scsiid;
+	int	 target_offset;
+	uint16_t target_mask;
+	u_int	 target;
+	u_int	 lun;
+	char	 channel;
+	role_t	 role;		/*
+				 * Only guaranteed to be correct if not
+				 * in the busfree state.
+				 */
+};
+
+/****************************** PCI Structures ********************************/
+#define AHD_PCI_IOADDR0	PCIR_MAPS	/* I/O BAR*/
+#define AHD_PCI_MEMADDR	(PCIR_MAPS + 4)	/* Memory BAR */
+#define AHD_PCI_IOADDR1	(PCIR_MAPS + 12)/* Second I/O BAR */
+
+typedef int (ahd_device_setup_t)(struct ahd_softc *);
+
+struct ahd_pci_identity {
+	uint64_t		 full_id;
+	uint64_t		 id_mask;
+	char			*name;
+	ahd_device_setup_t	*setup;
+};
+extern struct ahd_pci_identity ahd_pci_ident_table [];
+extern const u_int ahd_num_pci_devs;
+
+/***************************** VL/EISA Declarations ***************************/
+struct aic7770_identity {
+	uint32_t		 full_id;
+	uint32_t		 id_mask;
+	char			*name;
+	ahd_device_setup_t	*setup;
+};
+extern struct aic7770_identity aic7770_ident_table [];
+extern const int ahd_num_aic7770_devs;
+
+#define AHD_EISA_SLOT_OFFSET	0xc00
+#define AHD_EISA_IOSIZE		0x100
+
+/*************************** Function Declarations ****************************/
+/******************************************************************************/
+void			ahd_reset_cmds_pending(struct ahd_softc *ahd);
+u_int			ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl);
+void			ahd_busy_tcl(struct ahd_softc *ahd,
+				     u_int tcl, u_int busyid);
+static __inline void	ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl);
+static __inline void
+ahd_unbusy_tcl(struct ahd_softc *ahd, u_int tcl)
+{
+	ahd_busy_tcl(ahd, tcl, SCB_LIST_NULL);
+}
+
+/***************************** PCI Front End *********************************/
+struct	ahd_pci_identity *ahd_find_pci_device(ahd_dev_softc_t);
+int			  ahd_pci_config(struct ahd_softc *,
+					 struct ahd_pci_identity *);
+int	ahd_pci_test_register_access(struct ahd_softc *);
+
+/************************** SCB and SCB queue management **********************/
+int		ahd_probe_scbs(struct ahd_softc *);
+void		ahd_qinfifo_requeue_tail(struct ahd_softc *ahd,
+					 struct scb *scb);
+int		ahd_match_scb(struct ahd_softc *ahd, struct scb *scb,
+			      int target, char channel, int lun,
+			      u_int tag, role_t role);
+
+/****************************** Initialization ********************************/
+struct ahd_softc	*ahd_alloc(void *platform_arg, char *name);
+int			 ahd_softc_init(struct ahd_softc *);
+void			 ahd_controller_info(struct ahd_softc *ahd, char *buf);
+int			 ahd_init(struct ahd_softc *ahd);
+int			 ahd_default_config(struct ahd_softc *ahd);
+int			 ahd_parse_vpddata(struct ahd_softc *ahd,
+					   struct vpd_config *vpd);
+int			 ahd_parse_cfgdata(struct ahd_softc *ahd,
+					   struct seeprom_config *sc);
+void			 ahd_intr_enable(struct ahd_softc *ahd, int enable);
+void			 ahd_update_coalescing_values(struct ahd_softc *ahd,
+						      u_int timer,
+						      u_int maxcmds,
+						      u_int mincmds);
+void			 ahd_enable_coalescing(struct ahd_softc *ahd,
+					       int enable);
+void			 ahd_pause_and_flushwork(struct ahd_softc *ahd);
+int			 ahd_suspend(struct ahd_softc *ahd); 
+int			 ahd_resume(struct ahd_softc *ahd);
+void			 ahd_softc_insert(struct ahd_softc *);
+struct ahd_softc	*ahd_find_softc(struct ahd_softc *ahd);
+void			 ahd_set_unit(struct ahd_softc *, int);
+void			 ahd_set_name(struct ahd_softc *, char *);
+struct scb		*ahd_get_scb(struct ahd_softc *ahd, u_int col_idx);
+void			 ahd_free_scb(struct ahd_softc *ahd, struct scb *scb);
+void			 ahd_alloc_scbs(struct ahd_softc *ahd);
+void			 ahd_free(struct ahd_softc *ahd);
+int			 ahd_reset(struct ahd_softc *ahd, int reinit);
+void			 ahd_shutdown(void *arg);
+int			 ahd_write_flexport(struct ahd_softc *ahd,
+					    u_int addr, u_int value);
+int			 ahd_read_flexport(struct ahd_softc *ahd, u_int addr,
+					   uint8_t *value);
+int			 ahd_wait_flexport(struct ahd_softc *ahd);
+
+/*************************** Interrupt Services *******************************/
+void			ahd_pci_intr(struct ahd_softc *ahd);
+void			ahd_clear_intstat(struct ahd_softc *ahd);
+void			ahd_flush_qoutfifo(struct ahd_softc *ahd);
+void			ahd_run_qoutfifo(struct ahd_softc *ahd);
+#ifdef AHD_TARGET_MODE
+void			ahd_run_tqinfifo(struct ahd_softc *ahd, int paused);
+#endif
+void			ahd_handle_hwerrint(struct ahd_softc *ahd);
+void			ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat);
+void			ahd_handle_scsiint(struct ahd_softc *ahd,
+					   u_int intstat);
+void			ahd_clear_critical_section(struct ahd_softc *ahd);
+
+/***************************** Error Recovery *********************************/
+typedef enum {
+	SEARCH_COMPLETE,
+	SEARCH_COUNT,
+	SEARCH_REMOVE,
+	SEARCH_PRINT
+} ahd_search_action;
+int			ahd_search_qinfifo(struct ahd_softc *ahd, int target,
+					   char channel, int lun, u_int tag,
+					   role_t role, uint32_t status,
+					   ahd_search_action action);
+int			ahd_search_disc_list(struct ahd_softc *ahd, int target,
+					     char channel, int lun, u_int tag,
+					     int stop_on_first, int remove,
+					     int save_state);
+void			ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
+int			ahd_reset_channel(struct ahd_softc *ahd, char channel,
+					  int initiate_reset);
+int			ahd_abort_scbs(struct ahd_softc *ahd, int target,
+				       char channel, int lun, u_int tag,
+				       role_t role, uint32_t status);
+void			ahd_restart(struct ahd_softc *ahd);
+void			ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo);
+void			ahd_handle_scb_status(struct ahd_softc *ahd,
+					      struct scb *scb);
+void			ahd_handle_scsi_status(struct ahd_softc *ahd,
+					       struct scb *scb);
+void			ahd_calc_residual(struct ahd_softc *ahd,
+					  struct scb *scb);
+/*************************** Utility Functions ********************************/
+struct ahd_phase_table_entry*
+			ahd_lookup_phase_entry(int phase);
+void			ahd_compile_devinfo(struct ahd_devinfo *devinfo,
+					    u_int our_id, u_int target,
+					    u_int lun, char channel,
+					    role_t role);
+/************************** Transfer Negotiation ******************************/
+void			ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
+					  u_int *ppr_options, u_int maxsync);
+void			ahd_validate_offset(struct ahd_softc *ahd,
+					    struct ahd_initiator_tinfo *tinfo,
+					    u_int period, u_int *offset,
+					    int wide, role_t role);
+void			ahd_validate_width(struct ahd_softc *ahd,
+					   struct ahd_initiator_tinfo *tinfo,
+					   u_int *bus_width,
+					   role_t role);
+/*
+ * Negotiation types.  These are used to qualify if we should renegotiate
+ * even if our goal and current transport parameters are identical.
+ */
+typedef enum {
+	AHD_NEG_TO_GOAL,	/* Renegotiate only if goal and curr differ. */
+	AHD_NEG_IF_NON_ASYNC,	/* Renegotiate so long as goal is non-async. */
+	AHD_NEG_ALWAYS		/* Renegotiat even if goal is async. */
+} ahd_neg_type;
+int			ahd_update_neg_request(struct ahd_softc*,
+					       struct ahd_devinfo*,
+					       struct ahd_tmode_tstate*,
+					       struct ahd_initiator_tinfo*,
+					       ahd_neg_type);
+void			ahd_set_width(struct ahd_softc *ahd,
+				      struct ahd_devinfo *devinfo,
+				      u_int width, u_int type, int paused);
+void			ahd_set_syncrate(struct ahd_softc *ahd,
+					 struct ahd_devinfo *devinfo,
+					 u_int period, u_int offset,
+					 u_int ppr_options,
+					 u_int type, int paused);
+typedef enum {
+	AHD_QUEUE_NONE,
+	AHD_QUEUE_BASIC,
+	AHD_QUEUE_TAGGED
+} ahd_queue_alg;
+
+void			ahd_set_tags(struct ahd_softc *ahd,
+				     struct ahd_devinfo *devinfo,
+				     ahd_queue_alg alg);
+
+/**************************** Target Mode *************************************/
+#ifdef AHD_TARGET_MODE
+void		ahd_send_lstate_events(struct ahd_softc *,
+				       struct ahd_tmode_lstate *);
+void		ahd_handle_en_lun(struct ahd_softc *ahd,
+				  struct cam_sim *sim, union ccb *ccb);
+cam_status	ahd_find_tmode_devs(struct ahd_softc *ahd,
+				    struct cam_sim *sim, union ccb *ccb,
+				    struct ahd_tmode_tstate **tstate,
+				    struct ahd_tmode_lstate **lstate,
+				    int notfound_failure);
+#ifndef AHD_TMODE_ENABLE
+#define AHD_TMODE_ENABLE 0
+#endif
+#endif
+/******************************* Debug ***************************************/
+#ifdef AHD_DEBUG
+extern uint32_t ahd_debug;
+#define AHD_SHOW_MISC		0x00001
+#define AHD_SHOW_SENSE		0x00002
+#define AHD_SHOW_RECOVERY	0x00004
+#define AHD_DUMP_SEEPROM	0x00008
+#define AHD_SHOW_TERMCTL	0x00010
+#define AHD_SHOW_MEMORY		0x00020
+#define AHD_SHOW_MESSAGES	0x00040
+#define AHD_SHOW_MODEPTR	0x00080
+#define AHD_SHOW_SELTO		0x00100
+#define AHD_SHOW_FIFOS		0x00200
+#define AHD_SHOW_QFULL		0x00400
+#define	AHD_SHOW_DV		0x00800
+#define AHD_SHOW_MASKED_ERRORS	0x01000
+#define AHD_SHOW_QUEUE		0x02000
+#define AHD_SHOW_TQIN		0x04000
+#define AHD_SHOW_SG		0x08000
+#define AHD_SHOW_INT_COALESCING	0x10000
+#define AHD_DEBUG_SEQUENCER	0x20000
+#endif
+void			ahd_print_scb(struct scb *scb);
+void			ahd_print_devinfo(struct ahd_softc *ahd,
+					  struct ahd_devinfo *devinfo);
+void			ahd_dump_sglist(struct scb *scb);
+void			ahd_dump_all_cards_state(void);
+void			ahd_dump_card_state(struct ahd_softc *ahd);
+int			ahd_print_register(ahd_reg_parse_entry_t *table,
+					   u_int num_entries,
+					   const char *name,
+					   u_int address,
+					   u_int value,
+					   u_int *cur_column,
+					   u_int wrap_point);
+void			ahd_dump_scbs(struct ahd_softc *ahd);
+#endif /* _AIC79XX_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
new file mode 100644
index 0000000..cca58ed
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx.reg
@@ -0,0 +1,3958 @@
+/*
+ * Aic79xx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $"
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic79xx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic79xx driver.
+ */
+
+/* Register window Modes */
+#define M_DFF0		0
+#define M_DFF1		1
+#define M_CCHAN		2
+#define M_SCSI		3
+#define M_CFG		4
+#define M_DST_SHIFT	4
+
+#define MK_MODE(src, dst) ((src) | ((dst) << M_DST_SHIFT))
+#define SET_MODE(src, dst)						\
+	SET_SRC_MODE	src;						\
+	SET_DST_MODE	dst;						\
+	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {			\
+		mvi	MK_MODE(src, dst) call set_mode_work_around;	\
+	} else {							\
+		mvi	MODE_PTR, MK_MODE(src, dst);			\
+	}
+
+#define TOGGLE_DFF_MODE							\
+	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {			\
+		call	toggle_dff_mode_work_around;			\
+	} else {							\
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);		\
+	}
+	
+#define RESTORE_MODE(mode)						\
+	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {			\
+		mov	mode call set_mode_work_around;			\
+	} else {							\
+		mov	MODE_PTR, mode;					\
+	}
+
+#define SET_SEQINTCODE(code)						\
+	if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {			\
+		mvi	code call set_seqint_work_around;		\
+	} else {							\
+		mvi	SEQINTCODE, code;				\
+	}
+
+/*
+ * Mode Pointer
+ * Controls which of the 5, 512byte, address spaces should be used
+ * as the source and destination of any register accesses in our
+ * register window.
+ */
+register MODE_PTR {
+	address			0x000
+	access_mode	RW
+	field	DST_MODE	0x70
+	field	SRC_MODE	0x07
+	mode_pointer
+}
+
+const SRC_MODE_SHIFT	0
+const DST_MODE_SHIFT	4
+
+/*
+ * Host Interrupt Status
+ */
+register INTSTAT {
+	address			0x001
+	access_mode	RW
+	field	HWERRINT	0x80
+	field	BRKADRINT	0x40
+	field	SWTMINT		0x20
+	field	PCIINT		0x10
+	field	SCSIINT		0x08
+	field	SEQINT		0x04
+	field	CMDCMPLT	0x02
+	field	SPLTINT		0x01
+	mask	INT_PEND 0xFF
+}
+
+/*
+ * Sequencer Interrupt Code
+ */
+register SEQINTCODE {
+	address			0x002
+	access_mode	RW
+	field {
+		NO_SEQINT,			/* No seqint pending. */
+		BAD_PHASE,			/* unknown scsi bus phase */
+		SEND_REJECT,			/* sending a message reject */
+		PROTO_VIOLATION, 		/* Protocol Violation */
+		NO_MATCH,			/* no cmd match for reconnect */
+		IGN_WIDE_RES,			/* Complex IGN Wide Res Msg */
+		PDATA_REINIT,			/*
+						 * Returned to data phase
+						 * that requires data
+						 * transfer pointers to be
+						 * recalculated from the
+						 * transfer residual.
+						 */
+		HOST_MSG_LOOP,			/*
+						 * The bus is ready for the
+						 * host to perform another
+						 * message transaction.  This
+						 * mechanism is used for things
+						 * like sync/wide negotiation
+						 * that require a kernel based
+						 * message state engine.
+						 */
+		BAD_STATUS,			/* Bad status from target */
+		DATA_OVERRUN,			/*
+						 * Target attempted to write
+						 * beyond the bounds of its
+						 * command.
+						 */
+		MKMSG_FAILED,			/*
+						 * Target completed command
+						 * without honoring our ATN
+						 * request to issue a message. 
+						 */
+		MISSED_BUSFREE,			/*
+						 * The sequencer never saw
+						 * the bus go free after
+						 * either a command complete
+						 * or disconnect message.
+						 */
+		DUMP_CARD_STATE,
+		ILLEGAL_PHASE,
+		INVALID_SEQINT,
+		CFG4ISTAT_INTR,
+		STATUS_OVERRUN,
+		CFG4OVERRUN,
+		ENTERING_NONPACK,
+		TASKMGMT_FUNC_COMPLETE,		/*
+						 * Task management function
+						 * request completed with
+						 * an expected busfree.
+						 */
+		TASKMGMT_CMD_CMPLT_OKAY,	/*
+						 * A command with a non-zero
+						 * task management function
+						 * has completed via the normal
+						 * command completion method
+						 * for commands with a zero
+						 * task management function.
+						 * This happens when an attempt
+						 * to abort a command loses
+						 * the race for the command to
+						 * complete normally.
+						 */
+		TRACEPOINT0,
+		TRACEPOINT1,
+		TRACEPOINT2,
+		TRACEPOINT3,
+		SAW_HWERR,
+		BAD_SCB_STATUS
+	}
+}
+
+/*
+ * Clear Host Interrupt
+ */
+register CLRINT {
+	address			0x003
+	access_mode	WO
+	field	CLRHWERRINT	0x80 /* Rev B or greater */
+	field	CLRBRKADRINT	0x40
+	field	CLRSWTMINT	0x20
+	field	CLRPCIINT	0x10
+	field	CLRSCSIINT	0x08
+	field	CLRSEQINT	0x04
+	field	CLRCMDINT	0x02
+	field	CLRSPLTINT	0x01
+}
+
+/*
+ * Error Register
+ */
+register ERROR {
+	address			0x004
+	access_mode	RO
+	field	CIOPARERR	0x80
+	field	CIOACCESFAIL	0x40 /* Rev B or greater */
+	field	MPARERR		0x20
+	field	DPARERR		0x10
+	field	SQPARERR	0x08
+	field	ILLOPCODE	0x04
+	field	DSCTMOUT	0x02
+}
+
+/*
+ * Clear Error
+ */
+register CLRERR {
+	address			0x004
+	access_mode 	WO
+	field	CLRCIOPARERR	0x80
+	field	CLRCIOACCESFAIL	0x40 /* Rev B or greater */
+	field	CLRMPARERR	0x20
+	field	CLRDPARERR	0x10
+	field	CLRSQPARERR	0x08
+	field	CLRILLOPCODE	0x04
+	field	CLRDSCTMOUT	0x02
+}
+
+/*
+ * Host Control Register
+ * Overall host control of the device.
+ */
+register HCNTRL {
+	address			0x005
+	access_mode	RW
+	field	SEQ_RESET	0x80 /* Rev B or greater */
+	field	POWRDN		0x40
+	field	SWINT		0x10
+	field	SWTIMER_START_B	0x08 /* Rev B or greater */
+	field	PAUSE		0x04
+	field	INTEN		0x02
+	field	CHIPRST		0x01
+	field	CHIPRSTACK	0x01
+}
+
+/*
+ * Host New SCB Queue Offset
+ */
+register HNSCB_QOFF {
+	address			0x006
+	access_mode	RW
+	size		2
+}
+
+/*
+ * Host Empty SCB Queue Offset
+ */
+register HESCB_QOFF {
+	address			0x008
+	access_mode	RW
+}
+
+/*
+ * Host Mailbox
+ */
+register HS_MAILBOX {
+	address			0x00B
+	access_mode	RW
+	mask	HOST_TQINPOS	0x80	/* Boundary at either 0 or 128 */
+	mask	ENINT_COALESCE	0x40	/* Perform interrupt coalescing */
+}
+
+/*
+ * Sequencer Interupt Status
+ */
+register SEQINTSTAT {
+	address			0x00C
+	access_mode	RO
+	field	SEQ_SWTMRTO	0x10
+	field	SEQ_SEQINT	0x08
+	field	SEQ_SCSIINT	0x04
+	field	SEQ_PCIINT	0x02
+	field	SEQ_SPLTINT	0x01
+}
+
+/*
+ * Clear SEQ Interrupt
+ */
+register CLRSEQINTSTAT {
+	address			0x00C
+	access_mode	WO
+	field	CLRSEQ_SWTMRTO	0x10
+	field	CLRSEQ_SEQINT	0x08
+	field	CLRSEQ_SCSIINT	0x04
+	field	CLRSEQ_PCIINT	0x02
+	field	CLRSEQ_SPLTINT	0x01
+}
+
+/*
+ * Software Timer
+ */
+register SWTIMER {
+	address			0x00E
+	access_mode	RW
+	size		2
+}
+
+/*
+ * SEQ New SCB Queue Offset
+ */
+register SNSCB_QOFF {
+	address			0x010
+	access_mode	RW
+	size		2
+	modes		M_CCHAN
+}
+
+/*
+ * SEQ Empty SCB Queue Offset
+ */
+register SESCB_QOFF {
+	address			0x012
+	access_mode	RW
+	modes		M_CCHAN
+}
+
+/*
+ * SEQ Done SCB Queue Offset
+ */
+register SDSCB_QOFF {
+	address			0x014
+	access_mode	RW
+	modes		M_CCHAN
+	size		2
+}
+
+/*
+ * Queue Offset Control & Status
+ */
+register QOFF_CTLSTA {
+	address			0x016
+	access_mode	RW
+	modes		M_CCHAN
+	field	EMPTY_SCB_AVAIL	0x80
+	field	NEW_SCB_AVAIL	0x40
+	field	SDSCB_ROLLOVR	0x20
+	field	HS_MAILBOX_ACT	0x10
+	field	SCB_QSIZE	0x0F {
+		SCB_QSIZE_4,
+		SCB_QSIZE_8,
+		SCB_QSIZE_16,
+		SCB_QSIZE_32,
+		SCB_QSIZE_64,
+		SCB_QSIZE_128,
+		SCB_QSIZE_256,
+		SCB_QSIZE_512,
+		SCB_QSIZE_1024,
+		SCB_QSIZE_2048,
+		SCB_QSIZE_4096,
+		SCB_QSIZE_8192,
+		SCB_QSIZE_16384
+	}
+}
+
+/*
+ * Interrupt Control
+ */
+register INTCTL {
+	address			0x018
+	access_mode	RW
+	field	SWTMINTMASK	0x80
+	field	SWTMINTEN	0x40
+	field	SWTIMER_START	0x20
+	field	AUTOCLRCMDINT	0x10
+	field	PCIINTEN	0x08
+	field	SCSIINTEN	0x04
+	field	SEQINTEN	0x02
+	field	SPLTINTEN	0x01
+}
+
+/*
+ * Data FIFO Control
+ */
+register DFCNTRL {
+	address			0x019
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	PRELOADEN	0x80
+	field	SCSIENWRDIS	0x40	/* Rev B only. */
+	field	SCSIEN		0x20
+	field	SCSIENACK	0x20
+	field	HDMAEN		0x08
+	field	HDMAENACK	0x08
+	field	DIRECTION	0x04
+	field	DIRECTIONACK	0x04
+	field	FIFOFLUSH	0x02
+	field	FIFOFLUSHACK	0x02
+	field	DIRECTIONEN	0x01
+}
+
+/*
+ * Device Space Command 0
+ */
+register DSCOMMAND0 {
+	address			0x019
+	access_mode	RW
+	modes		M_CFG
+	field	CACHETHEN	0x80	/* Cache Threshold enable */
+	field	DPARCKEN	0x40	/* Data Parity Check Enable */
+	field	MPARCKEN	0x20	/* Memory Parity Check Enable */
+	field	EXTREQLCK	0x10	/* External Request Lock */
+	field	DISABLE_TWATE	0x02	/* Rev B or greater */
+	field	CIOPARCKEN	0x01	/* Internal bus parity error enable */
+}
+
+/*
+ * Data FIFO Status
+ */
+register DFSTATUS {
+	address			0x01A
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	PRELOAD_AVAIL		0x80
+	field	PKT_PRELOAD_AVAIL	0x40
+	field	MREQPEND		0x10
+	field	HDONE			0x08
+	field	DFTHRESH		0x04
+	field	FIFOFULL		0x02
+	field	FIFOEMP			0x01
+}
+
+/*
+ * S/G Cache Pointer
+ */
+register SG_CACHE_PRE {
+	address			0x01B
+	access_mode	WO
+	modes		M_DFF0, M_DFF1
+	field	SG_ADDR_MASK	0xf8
+	field	ODD_SEG		0x04
+	field	LAST_SEG	0x02
+}
+
+register SG_CACHE_SHADOW {
+	address			0x01B
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	SG_ADDR_MASK	0xf8
+	field	ODD_SEG		0x04
+	field	LAST_SEG	0x02
+	field	LAST_SEG_DONE	0x01
+}
+
+/*
+ * Arbiter Control
+ */
+register ARBCTL {
+	address			0x01B
+	access_mode	RW
+	modes		M_CFG
+	field	RESET_HARB	0x80
+	field	RETRY_SWEN	0x08
+	field	USE_TIME	0x07
+}
+
+/*
+ * Data Channel Host Address
+ */
+register HADDR {
+	address			0x070
+	access_mode	RW
+	size		8
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Host Overlay DMA Address
+ */
+register HODMAADR {
+	address			0x070
+	access_mode	RW
+	size		8
+	modes		M_SCSI
+}
+
+/*
+ * PCI PLL Delay.
+ */
+register PLLDELAY {
+	address			0x070
+	access_mode	RW
+	size		1
+	modes		M_CFG
+	field	SPLIT_DROP_REQ	0x80
+}
+
+/*
+ * Data Channel Host Count
+ */
+register HCNT {
+	address			0x078
+	access_mode	RW
+	size		3
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Host Overlay DMA Count
+ */
+register HODMACNT {
+	address			0x078
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * Host Overlay DMA Enable
+ */
+register HODMAEN {
+	address			0x07A
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Scatter/Gather Host Address
+ */
+register SGHADDR {
+	address			0x07C
+	access_mode	RW
+	size		8
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * SCB Host Address
+ */
+register SCBHADDR {
+	address			0x07C
+	access_mode	RW
+	size		8
+	modes		M_CCHAN
+}
+
+/*
+ * Scatter/Gather Host Count
+ */
+register SGHCNT {
+	address			0x084
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * SCB Host Count
+ */
+register SCBHCNT {
+	address			0x084
+	access_mode	RW
+	modes		M_CCHAN
+}
+
+/*
+ * Data FIFO Threshold
+ */
+register DFF_THRSH {
+	address			0x088
+	access_mode	RW
+	modes		M_CFG
+	field	WR_DFTHRSH	0x70 {
+		WR_DFTHRSH_MIN,
+		WR_DFTHRSH_25,
+		WR_DFTHRSH_50,
+		WR_DFTHRSH_63,
+		WR_DFTHRSH_75,
+		WR_DFTHRSH_85,
+		WR_DFTHRSH_90,
+		WR_DFTHRSH_MAX
+	}
+	field	RD_DFTHRSH	0x07 {
+		RD_DFTHRSH_MIN,
+		RD_DFTHRSH_25,
+		RD_DFTHRSH_50,
+		RD_DFTHRSH_63,
+		RD_DFTHRSH_75,
+		RD_DFTHRSH_85,
+		RD_DFTHRSH_90,
+		RD_DFTHRSH_MAX
+	}
+}
+
+/*
+ * ROM Address
+ */
+register ROMADDR {
+	address			0x08A
+	access_mode	RW
+	size		3
+}
+
+/*
+ * ROM Control
+ */
+register ROMCNTRL {
+	address			0x08D
+	access_mode	RW
+	field	ROMOP		0xE0
+	field	ROMSPD		0x18
+	field	REPEAT		0x02
+	field	RDY		0x01
+}
+
+/*
+ * ROM Data
+ */
+register ROMDATA {
+	address			0x08E
+	access_mode	RW
+}
+
+/*
+ * Data Channel Receive Message 0
+ */
+register DCHRXMSG0 {
+	address			0x090
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field		CDNUM	0xF8
+	field		CFNUM	0x07
+}
+
+/*
+ * CMC Recieve Message 0
+ */
+register CMCRXMSG0 {
+	address			0x090
+	access_mode	RO
+	modes		M_CCHAN
+	field		CDNUM	0xF8
+	field		CFNUM	0x07
+}
+
+/*
+ * Overlay Recieve Message 0
+ */
+register OVLYRXMSG0 {
+	address			0x090
+	access_mode	RO
+	modes		M_SCSI
+	field		CDNUM	0xF8
+	field		CFNUM	0x07
+}
+
+/*
+ * Relaxed Order Enable
+ */
+register ROENABLE {
+	address			0x090
+	access_mode	RW
+	modes		M_CFG
+	field	MSIROEN		0x20
+	field	OVLYROEN	0x10
+	field	CMCROEN		0x08
+	field	SGROEN		0x04
+	field	DCH1ROEN	0x02
+	field	DCH0ROEN	0x01
+}
+
+/*
+ * Data Channel Receive Message 1
+ */
+register DCHRXMSG1 {
+	address			0x091
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	CBNUM		0xFF
+}
+
+/*
+ * CMC Recieve Message 1
+ */
+register CMCRXMSG1 {
+	address			0x091
+	access_mode	RO
+	modes		M_CCHAN
+	field	CBNUM		0xFF
+}
+
+/*
+ * Overlay Recieve Message 1
+ */
+register OVLYRXMSG1 {
+	address			0x091
+	access_mode	RO
+	modes		M_SCSI
+	field	CBNUM		0xFF
+}
+
+/*
+ * No Snoop Enable
+ */
+register NSENABLE {
+	address			0x091
+	access_mode	RW
+	modes		M_CFG
+	field	MSINSEN		0x20
+	field	OVLYNSEN	0x10
+	field	CMCNSEN		0x08
+	field	SGNSEN		0x04
+	field	DCH1NSEN	0x02
+	field	DCH0NSEN	0x01
+}
+
+/*
+ * Data Channel Receive Message 2
+ */
+register DCHRXMSG2 {
+	address			0x092
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	MINDEX		0xFF
+}
+
+/*
+ * CMC Recieve Message 2
+ */
+register CMCRXMSG2 {
+	address			0x092
+	access_mode	RO
+	modes		M_CCHAN
+	field	MINDEX		0xFF
+}
+
+/*
+ * Overlay Recieve Message 2
+ */
+register OVLYRXMSG2 {
+	address			0x092
+	access_mode	RO
+	modes		M_SCSI
+	field	MINDEX		0xFF
+}
+
+/*
+ * Outstanding Split Transactions
+ */
+register OST {
+	address			0x092
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Data Channel Receive Message 3
+ */
+register DCHRXMSG3 {
+	address			0x093
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	MCLASS		0x0F
+}
+
+/*
+ * CMC Recieve Message 3
+ */
+register CMCRXMSG3 {
+	address			0x093
+	access_mode	RO
+	modes		M_CCHAN
+	field	MCLASS		0x0F
+}
+
+/*
+ * Overlay Recieve Message 3
+ */
+register OVLYRXMSG3 {
+	address			0x093
+	access_mode	RO
+	modes		M_SCSI
+	field	MCLASS		0x0F
+}
+
+/*
+ * PCI-X Control
+ */
+register PCIXCTL {
+	address			0x093
+	access_mode	RW
+	modes		M_CFG
+	field	SERRPULSE	0x80
+	field	UNEXPSCIEN	0x20
+	field	SPLTSMADIS	0x10
+	field	SPLTSTADIS	0x08
+	field	SRSPDPEEN	0x04
+	field	TSCSERREN	0x02
+	field	CMPABCDIS	0x01
+}
+
+/*
+ * CMC Sequencer Byte Count
+ */
+register CMCSEQBCNT {
+	address			0x094
+	access_mode	RO
+	modes		M_CCHAN
+}
+
+/*
+ * Overlay Sequencer Byte Count
+ */
+register OVLYSEQBCNT {
+	address			0x094
+	access_mode	RO
+	modes		M_SCSI
+}
+
+/*
+ * Data Channel Sequencer Byte Count
+ */
+register DCHSEQBCNT {
+	address			0x094
+	access_mode	RO
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Data Channel Split Status 0
+ */
+register DCHSPLTSTAT0 {
+	address			0x096
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	STAETERM	0x80
+	field	SCBCERR		0x40
+	field	SCADERR		0x20
+	field	SCDATBUCKET	0x10
+	field	CNTNOTCMPLT	0x08
+	field	RXOVRUN		0x04
+	field	RXSCEMSG	0x02
+	field	RXSPLTRSP	0x01
+}
+
+/*
+ * CMC Split Status 0
+ */
+register CMCSPLTSTAT0 {
+	address			0x096
+	access_mode	RW
+	modes		M_CCHAN
+	field	STAETERM	0x80
+	field	SCBCERR		0x40
+	field	SCADERR		0x20
+	field	SCDATBUCKET	0x10
+	field	CNTNOTCMPLT	0x08
+	field	RXOVRUN		0x04
+	field	RXSCEMSG	0x02
+	field	RXSPLTRSP	0x01
+}
+
+/*
+ * Overlay Split Status 0
+ */
+register OVLYSPLTSTAT0 {
+	address			0x096
+	access_mode	RW
+	modes		M_SCSI
+	field	STAETERM	0x80
+	field	SCBCERR		0x40
+	field	SCADERR		0x20
+	field	SCDATBUCKET	0x10
+	field	CNTNOTCMPLT	0x08
+	field	RXOVRUN		0x04
+	field	RXSCEMSG	0x02
+	field	RXSPLTRSP	0x01
+}
+
+/*
+ * Data Channel Split Status 1
+ */
+register DCHSPLTSTAT1 {
+	address			0x097
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	RXDATABUCKET	0x01
+}
+
+/*
+ * CMC Split Status 1
+ */
+register CMCSPLTSTAT1 {
+	address			0x097
+	access_mode	RW
+	modes		M_CCHAN
+	field	RXDATABUCKET	0x01
+}
+
+/*
+ * Overlay Split Status 1
+ */
+register OVLYSPLTSTAT1 {
+	address			0x097
+	access_mode	RW
+	modes		M_SCSI
+	field	RXDATABUCKET	0x01
+}
+
+/*
+ * S/G Receive Message 0
+ */
+register SGRXMSG0 {
+	address			0x098
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field		CDNUM	0xF8
+	field		CFNUM	0x07
+}
+
+/*
+ * S/G Receive Message 1
+ */
+register SGRXMSG1 {
+	address			0x099
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	CBNUM		0xFF
+}
+
+/*
+ * S/G Receive Message 2
+ */
+register SGRXMSG2 {
+	address			0x09A
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	MINDEX		0xFF
+}
+
+/*
+ * S/G Receive Message 3
+ */
+register SGRXMSG3 {
+	address			0x09B
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	MCLASS		0x0F
+}
+
+/*
+ * Slave Split Out Address 0
+ */
+register SLVSPLTOUTADR0 {
+	address			0x098
+	access_mode	RO
+	modes		M_SCSI
+	field	LOWER_ADDR	0x7F
+}
+
+/*
+ * Slave Split Out Address 1
+ */
+register SLVSPLTOUTADR1 {
+	address			0x099
+	access_mode	RO
+	modes		M_SCSI
+	field	REQ_DNUM	0xF8
+	field	REQ_FNUM	0x07
+}
+
+/*
+ * Slave Split Out Address 2
+ */
+register SLVSPLTOUTADR2 {
+	address			0x09A
+	access_mode	RO
+	modes		M_SCSI
+	field	REQ_BNUM	0xFF
+}
+
+/*
+ * Slave Split Out Address 3
+ */
+register SLVSPLTOUTADR3 {
+	address			0x09B
+	access_mode	RO
+	modes		M_SCSI
+	field	RLXORD		020
+	field	TAG_NUM		0x1F
+}
+
+/*
+ * SG Sequencer Byte Count
+ */
+register SGSEQBCNT {
+	address			0x09C
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Slave Split Out Attribute 0
+ */
+register SLVSPLTOUTATTR0 {
+	address			0x09C
+	access_mode	RO
+	modes		M_SCSI
+	field	LOWER_BCNT	0xFF
+}
+
+/*
+ * Slave Split Out Attribute 1
+ */
+register SLVSPLTOUTATTR1 {
+	address			0x09D
+	access_mode	RO
+	modes		M_SCSI
+	field	CMPLT_DNUM	0xF8
+	field	CMPLT_FNUM	0x07
+}
+
+/*
+ * Slave Split Out Attribute 2
+ */
+register SLVSPLTOUTATTR2 {
+	address			0x09E
+	access_mode	RO
+	size		2
+	modes		M_SCSI
+	field	CMPLT_BNUM	0xFF
+}
+/*
+ * S/G Split Status 0
+ */
+register SGSPLTSTAT0 {
+	address			0x09E
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	STAETERM	0x80
+	field	SCBCERR		0x40
+	field	SCADERR		0x20
+	field	SCDATBUCKET	0x10
+	field	CNTNOTCMPLT	0x08
+	field	RXOVRUN		0x04
+	field	RXSCEMSG	0x02
+	field	RXSPLTRSP	0x01
+}
+
+/*
+ * S/G Split Status 1
+ */
+register SGSPLTSTAT1 {
+	address			0x09F
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	RXDATABUCKET	0x01
+}
+
+/*
+ * Special Function
+ */
+register SFUNCT {
+	address			0x09f
+	access_mode	RW
+	modes		M_CFG
+	field	TEST_GROUP	0xF0
+	field	TEST_NUM	0x0F
+}
+
+/*
+ * Data FIFO 0 PCI Status 
+ */
+register DF0PCISTAT {
+	address			0x0A0
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	SCAAPERR	0x08
+	field	RDPERR		0x04
+	field	TWATERR		0x02
+	field	DPR		0x01
+}
+
+/*
+ * Data FIFO 1 PCI Status 
+ */
+register DF1PCISTAT {
+	address			0x0A1
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	SCAAPERR	0x08
+	field	RDPERR		0x04
+	field	TWATERR		0x02
+	field	DPR		0x01
+}
+
+/*
+ * S/G PCI Status 
+ */
+register SGPCISTAT {
+	address			0x0A2
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	SCAAPERR	0x08
+	field	RDPERR		0x04
+	field	DPR		0x01
+}
+
+/*
+ * CMC PCI Status 
+ */
+register CMCPCISTAT {
+	address			0x0A3
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	SCAAPERR	0x08
+	field	RDPERR		0x04
+	field	TWATERR		0x02
+	field	DPR		0x01
+}
+
+/*
+ * Overlay PCI Status 
+ */
+register OVLYPCISTAT {
+	address			0x0A4
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	SCAAPERR	0x08
+	field	RDPERR		0x04
+	field	DPR		0x01
+}
+
+/*
+ * PCI Status for MSI Master DMA Transfer
+ */
+register MSIPCISTAT {
+	address			0x0A6
+	access_mode	RW
+	modes		M_CFG
+	field	SSE		0x40
+	field	RMA		0x20
+	field	RTA		0x10
+	field	CLRPENDMSI	0x08
+	field	TWATERR		0x02
+	field	DPR		0x01
+}
+
+/*
+ * PCI Status for Target
+ */
+register TARGPCISTAT {
+	address			0x0A7
+	access_mode	RW
+	modes		M_CFG
+	field	DPE		0x80
+	field	SSE		0x40
+	field	STA		0x08
+	field	TWATERR		0x02
+}
+
+/*
+ * LQ Packet In
+ * The last LQ Packet received
+ */
+register LQIN {
+	address			0x020
+	access_mode	RW
+	size		20
+	modes		M_DFF0, M_DFF1, M_SCSI
+}
+
+/*
+ * SCB Type Pointer
+ * SCB offset for Target Mode SCB type information
+ */
+register TYPEPTR {
+	address			0x020
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Queue Tag Pointer
+ * SCB offset to the Two Byte tag identifier used for target mode.
+ */
+register TAGPTR {
+	address			0x021
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Logical Unit Number Pointer
+ * SCB offset to the LSB (little endian) of the lun field.
+ */
+register LUNPTR {
+	address			0x022
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Data Length Pointer
+ * SCB offset for the 4 byte data length field in target mode.
+ */
+register DATALENPTR {
+	address			0x023
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Status Length Pointer
+ * SCB offset to the two byte status field in target SCBs.
+ */
+register STATLENPTR {
+	address			0x024
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Command Length Pointer
+ * Scb offset for the CDB length field in initiator SCBs.
+ */
+register CMDLENPTR {
+	address			0x025
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Task Attribute Pointer
+ * Scb offset for the byte field specifying the attribute byte
+ * to be used in command packets.
+ */ 
+register ATTRPTR {
+	address			0x026
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Task Management Flags Pointer
+ * Scb offset for the byte field specifying the attribute flags
+ * byte to be used in command packets.
+ */ 
+register FLAGPTR {
+	address			0x027
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Command Pointer
+ * Scb offset for the first byte in the CDB for initiator SCBs.
+ */
+register CMDPTR {
+	address			0x028
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Queue Next Pointer
+ * Scb offset for the 2 byte "next scb link".
+ */
+register QNEXTPTR {
+	address			0x029
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * SCSI ID Pointer
+ * Scb offset to the value to place in the SCSIID register
+ * during target mode connections.
+ */
+register IDPTR {
+	address			0x02A
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Command Aborted Byte Pointer
+ * Offset to the SCB flags field that includes the
+ * "SCB aborted" status bit.
+ */
+register ABRTBYTEPTR {
+	address			0x02B
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Command Aborted Bit Pointer
+ * Bit offset in the SCB flags field for "SCB aborted" status.
+ */
+register ABRTBITPTR {
+	address			0x02C
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Rev B or greater.
+ */
+register MAXCMDBYTES {
+	address			0x02D
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Rev B or greater.
+ */
+register MAXCMD2RCV {
+	address			0x02E
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Rev B or greater.
+ */
+register SHORTTHRESH {
+	address			0x02F
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Logical Unit Number Length
+ * The length, in bytes, of the SCB lun field.
+ */
+register LUNLEN {
+	address			0x030
+	access_mode	RW
+	modes		M_CFG
+	mask		ILUNLEN	0x0F
+	mask		TLUNLEN	0xF0
+}
+const LUNLEN_SINGLE_LEVEL_LUN 0xF
+
+/*
+ * CDB Limit
+ * The size, in bytes, of the embedded CDB field in initator SCBs.
+ */
+register CDBLIMIT {
+	address			0x031
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Maximum Commands
+ * The maximum number of commands to issue during a
+ * single packetized connection.
+ */
+register MAXCMD {
+	address			0x032
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * Maximum Command Counter
+ * The number of commands already sent during this connection
+ */
+register MAXCMDCNT {
+	address			0x033
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * LQ Packet Reserved Bytes
+ * The bytes to be sent in the currently reserved fileds
+ * of all LQ packets.
+ */
+register LQRSVD01 {
+	address			0x034
+	access_mode	RW
+	modes		M_SCSI
+}
+register LQRSVD16 {
+	address			0x035
+	access_mode	RW
+	modes		M_SCSI
+}
+register LQRSVD17 {
+	address			0x036
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Command Reserved 0
+ * The byte to be sent for the reserved byte 0 of
+ * outgoing command packets.
+ */
+register CMDRSVD0 {
+	address			0x037
+	access_mode	RW
+	modes		M_CFG
+}
+
+/*
+ * LQ Manager Control 0
+ */
+register LQCTL0 {
+	address			0x038
+	access_mode	RW
+	modes		M_CFG
+	field	LQITARGCLT	0xC0
+	field	LQIINITGCLT	0x30
+	field	LQ0TARGCLT	0x0C
+	field	LQ0INITGCLT	0x03
+}
+
+/*
+ * LQ Manager Control 1
+ */
+register LQCTL1 {
+	address			0x038
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	PCI2PCI		0x04
+	field	SINGLECMD	0x02
+	field	ABORTPENDING	0x01
+}
+
+/*
+ * LQ Manager Control 2
+ */
+register LQCTL2 {
+	address			0x039
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQIRETRY	0x80
+	field	LQICONTINUE	0x40
+	field	LQITOIDLE	0x20
+	field	LQIPAUSE	0x10
+	field	LQORETRY	0x08
+	field	LQOCONTINUE	0x04
+	field	LQOTOIDLE	0x02
+	field	LQOPAUSE	0x01
+}
+
+/*
+ * SCSI RAM BIST0
+ */
+register SCSBIST0 {
+	address			0x039
+	access_mode	RW
+	modes		M_CFG
+	field	GSBISTERR	0x40
+	field	GSBISTDONE	0x20
+	field	GSBISTRUN	0x10
+	field	OSBISTERR	0x04
+	field	OSBISTDONE	0x02
+	field	OSBISTRUN	0x01
+}
+
+/*
+ * SCSI Sequence Control0
+ */
+register SCSISEQ0 {
+	address			0x03A
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	TEMODEO		0x80
+	field	ENSELO		0x40
+	field	ENARBO		0x20
+	field	FORCEBUSFREE	0x10
+	field	SCSIRSTO	0x01
+}
+
+/*
+ * SCSI RAM BIST 1
+ */
+register SCSBIST1 {
+	address			0x03A
+	access_mode	RW
+	modes		M_CFG
+	field	NTBISTERR	0x04
+	field	NTBISTDONE	0x02
+	field	NTBISTRUN	0x01
+}
+
+/*
+ * SCSI Sequence Control 1
+ */
+register SCSISEQ1 {
+	address			0x03B
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	MANUALCTL	0x40
+	field	ENSELI		0x20
+	field	ENRSELI		0x10
+	field	MANUALP		0x0C
+	field	ENAUTOATNP	0x02
+	field	ALTSTIM		0x01
+}
+
+/*
+ * SCSI Transfer Control 0
+ */
+register SXFRCTL0 {
+	address			0x03C
+	access_mode	RW
+	modes		M_SCSI
+	field	DFON		0x80
+	field	DFPEXP		0x40
+	field	BIOSCANCELEN	0x10
+	field	SPIOEN		0x08
+}
+
+/*
+ * SCSI Transfer Control 1
+ */
+register SXFRCTL1 {
+	address			0x03D
+	access_mode	RW
+	modes		M_SCSI
+	field	BITBUCKET	0x80
+	field	ENSACHK		0x40
+	field	ENSPCHK		0x20
+	field	STIMESEL	0x18
+	field	ENSTIMER	0x04
+	field	ACTNEGEN	0x02
+	field	STPWEN		0x01
+}
+
+/*
+ * SCSI Transfer Control 2
+ */
+register SXFRCTL2 {
+	address			0x03E
+	access_mode	RW
+	modes		M_SCSI
+	field	AUTORSTDIS	0x10
+	field	CMDDMAEN	0x08
+	field	ASU		0x07
+}
+
+/*
+ * SCSI Bus Initiator IDs
+ * Bitmask of observed initiators on the bus.
+ */
+register BUSINITID {
+	address			0x03C
+	access_mode	RW
+	modes		M_CFG
+	size		2
+}
+
+/*
+ * Data Length Counters
+ * Packet byte counter.
+ */
+register DLCOUNT {
+	address			0x03C
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	size		3
+}
+
+/*
+ * Data FIFO Status
+ */
+register DFFSTAT {
+	address			0x03F
+	access_mode	RW
+	modes		M_SCSI
+	field	FIFO1FREE	0x20
+	field	FIFO0FREE	0x10
+	/*
+	 * On the B, this enum only works
+	 * in the read direction.  For writes,
+	 * you must use the B version of the
+	 * CURRFIFO_0 definition which is defined
+	 * as a constant outside of this register
+	 * definition to avoid confusing the
+	 * register pretty printing code.
+	 */
+	enum	CURRFIFO	0x03 {
+		CURRFIFO_0,
+		CURRFIFO_1,
+		CURRFIFO_NONE	0x3
+	}
+}
+
+const B_CURRFIFO_0 0x2
+
+/*
+ * SCSI Bus Target IDs
+ * Bitmask of observed targets on the bus.
+ */
+register BUSTARGID {
+	address			0x03E
+	access_mode	RW
+	modes		M_CFG
+	size		2
+}
+
+/*
+ * SCSI Control Signal Out
+ */
+register SCSISIGO {
+	address			0x040
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CDO		0x80
+	field	IOO		0x40
+	field	MSGO		0x20
+	field	ATNO		0x10
+	field	SELO		0x08
+	field	BSYO		0x04
+	field	REQO		0x02
+	field	ACKO		0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+	enum	PHASE_MASK  CDO|IOO|MSGO {
+		P_DATAOUT	0x0,
+		P_DATAIN	IOO,
+		P_DATAOUT_DT	P_DATAOUT|MSGO,
+		P_DATAIN_DT	P_DATAIN|MSGO,
+		P_COMMAND	CDO,
+		P_MESGOUT	CDO|MSGO,
+		P_STATUS	CDO|IOO,
+		P_MESGIN	CDO|IOO|MSGO
+	}
+}
+
+register SCSISIGI {
+	address			0x041
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CDI		0x80
+	field	IOI		0x40
+	field	MSGI		0x20
+	field	ATNI		0x10
+	field	SELI		0x08
+	field	BSYI		0x04
+	field	REQI		0x02
+	field	ACKI		0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+	enum	PHASE_MASK  CDO|IOO|MSGO {
+		P_DATAOUT	0x0,
+		P_DATAIN	IOO,
+		P_DATAOUT_DT	P_DATAOUT|MSGO,
+		P_DATAIN_DT	P_DATAIN|MSGO,
+		P_COMMAND	CDO,
+		P_MESGOUT	CDO|MSGO,
+		P_STATUS	CDO|IOO,
+		P_MESGIN	CDO|IOO|MSGO
+	}
+}
+
+/*
+ * Multiple Target IDs
+ * Bitmask of ids to respond as a target.
+ */
+register MULTARGID {
+	address			0x040
+	access_mode	RW
+	modes		M_CFG
+	size		2
+}
+
+/*
+ * SCSI Phase
+ */
+register SCSIPHASE {
+	address			0x042
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	STATUS_PHASE	0x20
+	field	COMMAND_PHASE	0x10
+	field	MSG_IN_PHASE	0x08
+	field	MSG_OUT_PHASE	0x04
+	field	DATA_PHASE_MASK	0x03 {
+		DATA_OUT_PHASE	0x01,
+		DATA_IN_PHASE	0x02
+	}
+}
+
+/*
+ * SCSI Data 0 Image
+ */
+register SCSIDAT0_IMG {
+	address			0x043
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+}
+
+/*
+ * SCSI Latched Data
+ */
+register SCSIDAT {
+	address			0x044
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	size		2
+}
+
+/*
+ * SCSI Data Bus
+ */
+register SCSIBUS {
+	address			0x046
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	size		2
+}
+
+/*
+ * Target ID In
+ */
+register TARGIDIN {
+	address			0x048
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLKOUT		0x80
+	field	TARGID		0x0F
+}
+
+/*
+ * Selection/Reselection ID
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+	address			0x049
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	SELID_MASK	0xf0
+	field	ONEBIT		0x08
+}
+
+/*
+ * SCSI Block Control
+ * Controls Bus type and channel selection.  SELWIDE allows for the
+ * coexistence of 8bit and 16bit devices on a wide bus.
+ */
+register SBLKCTL {
+	address			0x04A
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	DIAGLEDEN	0x80
+	field	DIAGLEDON	0x40
+	field	ENAB40		0x08	/* LVD transceiver active */
+	field	ENAB20		0x04	/* SE/HVD transceiver active */
+	field	SELWIDE		0x02
+}
+
+/*
+ * Option Mode
+ */
+register OPTIONMODE {
+	address			0x04A
+	access_mode	RW
+	modes		M_CFG
+	field	BIOSCANCTL		0x80
+	field	AUTOACKEN		0x40
+	field	BIASCANCTL		0x20
+	field	BUSFREEREV		0x10
+	field	ENDGFORMCHK		0x04
+	field	AUTO_MSGOUT_DE		0x02
+	mask	OPTIONMODE_DEFAULTS	AUTO_MSGOUT_DE
+}
+
+/*
+ * SCSI Status 0
+ */
+register SSTAT0	{
+	address			0x04B
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	TARGET		0x80	/* Board acting as target */
+	field	SELDO		0x40	/* Selection Done */
+	field	SELDI		0x20	/* Board has been selected */
+	field	SELINGO		0x10	/* Selection In Progress */
+	field	IOERR		0x08	/* LVD Tranceiver mode changed */
+	field	OVERRUN		0x04	/* SCSI Offset overrun detected */
+	field	SPIORDY		0x02	/* SCSI PIO Ready */
+	field	ARBDO		0x01	/* Arbitration Done Out */
+}
+
+/*
+ * Clear SCSI Interrupt 0
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+	address			0x04B
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRSELDO	0x40
+	field	CLRSELDI	0x20
+	field	CLRSELINGO	0x10
+	field	CLRIOERR	0x08
+	field	CLROVERRUN	0x04
+	field	CLRSPIORDY	0x02
+	field	CLRARBDO	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 0
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+	address			0x04B
+	access_mode	RW
+	modes		M_CFG
+	field	ENSELDO		0x40
+	field	ENSELDI		0x20
+	field	ENSELINGO	0x10
+	field	ENIOERR		0x08
+	field	ENOVERRUN	0x04
+	field	ENSPIORDY	0x02
+	field	ENARBDO		0x01
+}
+
+/*
+ * SCSI Status 1
+ */
+register SSTAT1 {
+	address			0x04C
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	SELTO		0x80
+	field	ATNTARG 	0x40
+	field	SCSIRSTI	0x20
+	field	PHASEMIS	0x10
+	field	BUSFREE		0x08
+	field	SCSIPERR	0x04
+	field	STRB2FAST	0x02
+	field	REQINIT		0x01
+}
+
+/*
+ * Clear SCSI Interrupt 1
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+	address			0x04C
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRSELTIMEO	0x80
+	field	CLRATNO		0x40
+	field	CLRSCSIRSTI	0x20
+	field	CLRBUSFREE	0x08
+	field	CLRSCSIPERR	0x04
+	field	CLRSTRB2FAST	0x02
+	field	CLRREQINIT	0x01
+}
+
+/*
+ * SCSI Status 2
+ */
+register SSTAT2 {
+	address			0x04d
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	BUSFREETIME	0xc0 {
+		BUSFREE_LQO	0x40,
+		BUSFREE_DFF0	0x80,
+		BUSFREE_DFF1	0xC0
+	}
+	field	NONPACKREQ	0x20
+	field	EXP_ACTIVE	0x10	/* SCSI Expander Active */
+	field	BSYX		0x08	/* Busy Expander */
+	field	WIDE_RES	0x04	/* Modes 0 and 1 only */
+	field	SDONE		0x02	/* Modes 0 and 1 only */
+	field	DMADONE		0x01	/* Modes 0 and 1 only */
+}
+
+/*
+ * Clear SCSI Interrupt 2
+ */
+register CLRSINT2 {
+	address			0x04D
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRNONPACKREQ	0x20
+	field	CLRWIDE_RES	0x04	/* Modes 0 and 1 only */
+	field	CLRSDONE	0x02	/* Modes 0 and 1 only */
+	field	CLRDMADONE	0x01	/* Modes 0 and 1 only */
+}
+
+/*
+ * SCSI Interrupt Mode 2
+ */
+register SIMODE2 {
+	address			0x04D
+	access_mode	RW
+	modes		M_CFG
+	field	ENWIDE_RES	0x04
+	field	ENSDONE		0x02
+	field	ENDMADONE	0x01
+}
+
+/*
+ * Physical Error Diagnosis
+ */
+register PERRDIAG {
+	address			0x04E
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	HIZERO		0x80
+	field	HIPERR		0x40
+	field	PREVPHASE	0x20
+	field	PARITYERR	0x10
+	field	AIPERR		0x08
+	field	CRCERR		0x04
+	field	DGFORMERR	0x02
+	field	DTERR		0x01
+}
+
+/*
+ * LQI Manager Current State
+ */
+register LQISTATE {
+	address			0x04E
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * SCSI Offset Count
+ */
+register SOFFCNT {
+	address			0x04F
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+}
+
+/*
+ * LQO Manager Current State
+ */
+register LQOSTATE {
+	address			0x04F
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * LQI Manager Status
+ */
+register LQISTAT0 {
+	address			0x050
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQIATNQAS	0x20
+	field	LQICRCT1	0x10
+	field	LQICRCT2	0x08
+	field	LQIBADLQT	0x04
+	field	LQIATNLQ	0x02
+	field	LQIATNCMD	0x01
+}
+
+/*
+ * Clear LQI Interrupts 0
+ */
+register CLRLQIINT0 {
+	address			0x050
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRLQIATNQAS	0x20
+	field	CLRLQICRCT1	0x10
+	field	CLRLQICRCT2	0x08
+	field	CLRLQIBADLQT	0x04
+	field	CLRLQIATNLQ	0x02
+	field	CLRLQIATNCMD	0x01
+}
+
+/*
+ * LQI Manager Interrupt Mode 0
+ */
+register LQIMODE0 {
+	address			0x050
+	access_mode	RW
+	modes		M_CFG
+	field	ENLQIATNQASK	0x20
+	field	ENLQICRCT1	0x10
+	field	ENLQICRCT2	0x08
+	field	ENLQIBADLQT	0x04
+	field	ENLQIATNLQ	0x02
+	field	ENLQIATNCMD	0x01
+}
+
+/*
+ * LQI Manager Status 1
+ */
+register LQISTAT1 {
+	address			0x051
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQIPHASE_LQ	0x80
+	field	LQIPHASE_NLQ	0x40
+	field	LQIABORT	0x20
+	field	LQICRCI_LQ	0x10
+	field	LQICRCI_NLQ	0x08
+	field	LQIBADLQI	0x04
+	field	LQIOVERI_LQ	0x02
+	field	LQIOVERI_NLQ	0x01
+}
+
+/*
+ * Clear LQI Manager Interrupts1
+ */
+register CLRLQIINT1 {
+	address			0x051
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRLQIPHASE_LQ	0x80
+	field	CLRLQIPHASE_NLQ	0x40
+	field	CLRLIQABORT	0x20
+	field	CLRLQICRCI_LQ	0x10
+	field	CLRLQICRCI_NLQ	0x08
+	field	CLRLQIBADLQI	0x04
+	field	CLRLQIOVERI_LQ	0x02
+	field	CLRLQIOVERI_NLQ	0x01
+}
+
+/*
+ * LQI Manager Interrupt Mode 1
+ */
+register LQIMODE1 {
+	address			0x051
+	access_mode	RW
+	modes		M_CFG
+	field	ENLQIPHASE_LQ	0x80	/* LQIPHASE1 */
+	field	ENLQIPHASE_NLQ	0x40	/* LQIPHASE2 */
+	field	ENLIQABORT	0x20
+	field	ENLQICRCI_LQ	0x10	/* LQICRCI1 */
+	field	ENLQICRCI_NLQ	0x08	/* LQICRCI2 */
+	field	ENLQIBADLQI	0x04
+	field	ENLQIOVERI_LQ	0x02	/* LQIOVERI1 */
+	field	ENLQIOVERI_NLQ	0x01	/* LQIOVERI2 */
+}
+
+/*
+ * LQI Manager Status 2
+ */
+register LQISTAT2 {
+	address			0x052
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	PACKETIZED	0x80
+	field	LQIPHASE_OUTPKT	0x40
+	field	LQIWORKONLQ	0x20
+	field	LQIWAITFIFO	0x10
+	field	LQISTOPPKT	0x08
+	field	LQISTOPLQ	0x04
+	field	LQISTOPCMD	0x02
+	field	LQIGSAVAIL	0x01
+}
+
+/*
+ * SCSI Status 3
+ */
+register SSTAT3 {
+	address			0x053
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	NTRAMPERR	0x02
+	field	OSRAMPERR	0x01
+}
+
+/*
+ * Clear SCSI Status 3
+ */
+register CLRSINT3 {
+	address			0x053
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRNTRAMPERR	0x02
+	field	CLROSRAMPERR	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 3
+ */
+register SIMODE3 {
+	address			0x053
+	access_mode	RW
+	modes		M_CFG
+	field	ENNTRAMPERR	0x02
+	field	ENOSRAMPERR	0x01
+}
+
+/*
+ * LQO Manager Status 0
+ */
+register LQOSTAT0 {
+	address			0x054
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQOTARGSCBPERR	0x10
+	field	LQOSTOPT2	0x08
+	field	LQOATNLQ	0x04
+	field	LQOATNPKT	0x02
+	field	LQOTCRC		0x01
+}
+
+/*
+ * Clear LQO Manager interrupt 0
+ */
+register CLRLQOINT0 {
+	address			0x054
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRLQOTARGSCBPERR	0x10
+	field	CLRLQOSTOPT2		0x08
+	field	CLRLQOATNLQ		0x04
+	field	CLRLQOATNPKT		0x02
+	field	CLRLQOTCRC		0x01
+}
+
+/*
+ * LQO Manager Interrupt Mode 0
+ */
+register LQOMODE0 {
+	address			0x054
+	access_mode	RW
+	modes		M_CFG
+	field	ENLQOTARGSCBPERR	0x10
+	field	ENLQOSTOPT2		0x08
+	field	ENLQOATNLQ		0x04
+	field	ENLQOATNPKT		0x02
+	field	ENLQOTCRC		0x01
+}
+
+/*
+ * LQO Manager Status 1
+ */
+register LQOSTAT1 {
+	address			0x055
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQOINITSCBPERR	0x10
+	field	LQOSTOPI2	0x08
+	field	LQOBADQAS	0x04
+	field	LQOBUSFREE	0x02
+	field	LQOPHACHGINPKT	0x01
+}
+
+/*
+ * Clear LOQ Interrupt 1
+ */
+register CLRLQOINT1 {
+	address			0x055
+	access_mode	WO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	CLRLQOINITSCBPERR	0x10
+	field	CLRLQOSTOPI2		0x08
+	field	CLRLQOBADQAS		0x04
+	field	CLRLQOBUSFREE		0x02
+	field	CLRLQOPHACHGINPKT	0x01
+}
+
+/*
+ * LQO Manager Interrupt Mode 1
+ */
+register LQOMODE1 {
+	address			0x055
+	access_mode	RW
+	modes		M_CFG
+	field	ENLQOINITSCBPERR	0x10
+	field	ENLQOSTOPI2		0x08
+	field	ENLQOBADQAS		0x04
+	field	ENLQOBUSFREE		0x02
+	field	ENLQOPHACHGINPKT	0x01
+}
+
+/*
+ * LQO Manager Status 2
+ */
+register LQOSTAT2 {
+	address			0x056
+	access_mode	RO
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	LQOPKT		0xE0
+	field	LQOWAITFIFO	0x10
+	field	LQOPHACHGOUTPKT	0x02	/* outside of packet boundaries. */
+	field	LQOSTOP0	0x01	/* Stopped after sending all packets */
+}
+
+/*
+ * Output Synchronizer Space Count
+ */
+register OS_SPACE_CNT {
+	address			0x056
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * SCSI Interrupt Mode 1
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+	address			0x057
+	access_mode	RW
+	modes		M_DFF0, M_DFF1, M_SCSI
+	field	ENSELTIMO	0x80
+	field	ENATNTARG	0x40
+	field	ENSCSIRST	0x20
+	field	ENPHASEMIS	0x10
+	field	ENBUSFREE	0x08
+	field	ENSCSIPERR	0x04
+	field	ENSTRB2FAST	0x02
+	field	ENREQINIT	0x01
+}
+
+/*
+ * Good Status FIFO
+ */
+register GSFIFO {
+	address			0x058
+	access_mode	RO
+	size		2
+	modes		M_DFF0, M_DFF1, M_SCSI
+}
+
+/*
+ * Data FIFO SCSI Transfer Control
+ */
+register DFFSXFRCTL {
+	address			0x05A
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	DFFBITBUCKET	0x08
+	field	CLRSHCNT	0x04
+	field	CLRCHN		0x02
+	field	RSTCHN		0x01
+}
+
+/*
+ * Next SCSI Control Block
+ */
+register NEXTSCB {
+	address			0x05A
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/* Rev B only. */
+register LQOSCSCTL {
+	address			0x05A
+	access_mode	RW
+	size		1
+	modes		M_CFG
+	field		LQOH2A_VERSION	0x80
+	field		LQONOCHKOVER	0x01
+}
+
+/*
+ * SEQ Interrupts
+ */
+register SEQINTSRC {
+	address			0x05B
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	CTXTDONE	0x40
+	field	SAVEPTRS	0x20
+	field	CFG4DATA	0x10
+	field	CFG4ISTAT	0x08
+	field	CFG4TSTAT	0x04
+	field	CFG4ICMD	0x02
+	field	CFG4TCMD	0x01
+}
+
+/*
+ * Clear Arp Interrupts
+ */
+register CLRSEQINTSRC {
+	address			0x05B
+	access_mode	WO
+	modes		M_DFF0, M_DFF1
+	field	CLRCTXTDONE	0x40
+	field	CLRSAVEPTRS	0x20
+	field	CLRCFG4DATA	0x10
+	field	CLRCFG4ISTAT	0x08
+	field	CLRCFG4TSTAT	0x04
+	field	CLRCFG4ICMD	0x02
+	field	CLRCFG4TCMD	0x01
+}
+
+/*
+ * SEQ Interrupt Enabled (Shared)
+ */
+register SEQIMODE {
+	address			0x05C
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	ENCTXTDONE	0x40
+	field	ENSAVEPTRS	0x20
+	field	ENCFG4DATA	0x10
+	field	ENCFG4ISTAT	0x08
+	field	ENCFG4TSTAT	0x04
+	field	ENCFG4ICMD	0x02
+	field	ENCFG4TCMD	0x01
+}
+
+/*
+ * Current SCSI Control Block
+ */
+register CURRSCB {
+	address			0x05C
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * Data FIFO Status
+ */
+register MDFFSTAT {
+	address			0x05D
+	access_mode	RO
+	modes		M_DFF0, M_DFF1
+	field	SHCNTNEGATIVE	0x40 /* Rev B or higher */
+	field	SHCNTMINUS1	0x20 /* Rev B or higher */
+	field	LASTSDONE	0x10
+	field	SHVALID		0x08
+	field	DLZERO		0x04 /* FIFO data ends on packet boundary. */
+	field	DATAINFIFO	0x02
+	field	FIFOFREE	0x01
+}
+
+/*
+ * CRC Control
+ */
+register CRCCONTROL {
+	address			0x05d
+	access_mode	RW
+	modes		M_CFG
+	field	CRCVALCHKEN		0x40
+}
+
+/*
+ * SCSI Test Control
+ */
+register SCSITEST {
+	address			0x05E
+	access_mode	RW
+	modes		M_CFG
+	field	CNTRTEST	0x08
+	field	SEL_TXPLL_DEBUG	0x04
+}
+
+/*
+ * Data FIFO Queue Tag
+ */
+register DFFTAG {
+	address			0x05E
+	access_mode	RW
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Last SCSI Control Block
+ */
+register LASTSCB {
+	address			0x05E
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * SCSI I/O Cell Power-down Control
+ */
+register IOPDNCTL {
+	address			0x05F
+	access_mode	RW
+	modes		M_CFG
+	field	DISABLE_OE	0x80
+	field	PDN_IDIST	0x04
+	field	PDN_DIFFSENSE	0x01
+}
+
+/*
+ * Shaddow Host Address.
+ */
+register SHADDR {
+	address			0x060
+	access_mode	RO
+	size		8
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Data Group CRC Interval.
+ */
+register DGRPCRCI {
+	address			0x060
+	access_mode	RW
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * Data Transfer Negotiation Address
+ */
+register NEGOADDR {
+	address			0x060
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Data Transfer Negotiation Data - Period Byte
+ */
+register NEGPERIOD {
+	address			0x061
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Packetized CRC Interval
+ */
+register PACKCRCI {
+	address			0x062
+	access_mode	RW
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * Data Transfer Negotiation Data - Offset Byte
+ */
+register NEGOFFSET {
+	address			0x062
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Data Transfer Negotiation Data - PPR Options
+ */
+register NEGPPROPTS {
+	address			0x063
+	access_mode	RW
+	modes		M_SCSI
+	field	PPROPT_PACE	0x08
+	field	PPROPT_QAS	0x04
+	field	PPROPT_DT	0x02
+	field	PPROPT_IUT	0x01
+}
+
+/*
+ * Data Transfer Negotiation Data -  Connection Options
+ */
+register NEGCONOPTS {
+	address			0x064
+	access_mode	RW
+	modes		M_SCSI
+	field	ENSNAPSHOT	0x40
+	field	RTI_WRTDIS	0x20
+	field	RTI_OVRDTRN	0x10
+	field	ENSLOWCRC	0x08
+	field	ENAUTOATNI	0x04
+	field	ENAUTOATNO	0x02
+	field	WIDEXFER	0x01
+}
+
+/*
+ * Negotiation Table Annex Column Index.
+ */
+register ANNEXCOL {
+	address			0x065
+	access_mode	RW
+	modes		M_SCSI
+}
+
+register SCSCHKN {
+	address			0x066
+	access_mode	RW
+	modes		M_CFG
+	field	STSELSKIDDIS	0x40
+	field	CURRFIFODEF	0x20
+	field	WIDERESEN	0x10
+	field	SDONEMSKDIS	0x08
+	field	DFFACTCLR	0x04
+	field	SHVALIDSTDIS	0x02
+	field	LSTSGCLRDIS	0x01
+}
+
+const AHD_ANNEXCOL_PER_DEV0	4
+const AHD_NUM_PER_DEV_ANNEXCOLS	4
+const AHD_ANNEXCOL_PRECOMP_SLEW	4
+const	AHD_PRECOMP_MASK	0x07
+const	AHD_PRECOMP_SHIFT	0
+const	AHD_PRECOMP_CUTBACK_17	0x04
+const	AHD_PRECOMP_CUTBACK_29	0x06
+const	AHD_PRECOMP_CUTBACK_37	0x07
+const	AHD_SLEWRATE_MASK	0x78
+const	AHD_SLEWRATE_SHIFT	3
+/*
+ * Rev A has only a single bit (high bit of field) of slew adjustment.
+ * Rev B has 4 bits.  The current default happens to be the same for both.
+ */
+const	AHD_SLEWRATE_DEF_REVA	0x08
+const	AHD_SLEWRATE_DEF_REVB	0x08
+
+/* Rev A does not have any amplitude setting. */
+const AHD_ANNEXCOL_AMPLITUDE	6
+const	AHD_AMPLITUDE_MASK	0x7
+const	AHD_AMPLITUDE_SHIFT	0
+const	AHD_AMPLITUDE_DEF	0x7
+
+/*
+ * Negotiation Table Annex Data Port.
+ */
+register ANNEXDAT {
+	address			0x066
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Initiator's Own Id.
+ * The SCSI ID to use for Selection Out and seen during a reselection..
+ */
+register IOWNID {
+	address			0x067
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * 960MHz Phase-Locked Loop Control 0
+ */
+register PLL960CTL0 {
+	address			0x068
+	access_mode	RW
+	modes		M_CFG
+	field	PLL_VCOSEL	0x80
+	field	PLL_PWDN	0x40
+	field	PLL_NS		0x30
+	field	PLL_ENLUD	0x08
+	field	PLL_ENLPF	0x04
+	field	PLL_DLPF	0x02
+	field	PLL_ENFBM	0x01
+}
+
+/*
+ * Target Own Id
+ */
+register TOWNID {
+	address			0x069
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * 960MHz Phase-Locked Loop Control 1
+ */
+register PLL960CTL1 {
+	address			0x069
+	access_mode	RW
+	modes		M_CFG
+	field	PLL_CNTEN	0x80
+	field	PLL_CNTCLR	0x40
+	field	PLL_RST		0x01
+}
+
+/*
+ * Expander Signature
+ */
+register XSIG {
+	address			0x06A
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Shadow Byte Count
+ */
+register SHCNT {
+	address			0x068
+	access_mode	RW
+	size		3
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Selection Out ID
+ */
+register SELOID {
+	address			0x06B
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * 960-MHz Phase-Locked Loop Test Count
+ */
+register PLL960CNT0 {
+	address			0x06A
+	access_mode	RO
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * 400-MHz Phase-Locked Loop Control 0
+ */
+register PLL400CTL0 {
+	address			0x06C
+	access_mode	RW
+	modes		M_CFG
+	field	PLL_VCOSEL	0x80
+	field	PLL_PWDN	0x40
+	field	PLL_NS		0x30
+	field	PLL_ENLUD	0x08
+	field	PLL_ENLPF	0x04
+	field	PLL_DLPF	0x02
+	field	PLL_ENFBM	0x01
+}
+
+/*
+ * Arbitration Fairness
+ */
+register FAIRNESS {
+	address			0x06C
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * 400-MHz Phase-Locked Loop Control 1
+ */
+register PLL400CTL1 {
+	address			0x06D
+	access_mode	RW
+	modes		M_CFG
+	field	PLL_CNTEN	0x80
+	field	PLL_CNTCLR	0x40
+	field	PLL_RST		0x01
+}
+
+/*
+ * Arbitration Unfairness
+ */
+register UNFAIRNESS {
+	address			0x06E
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * 400-MHz Phase-Locked Loop Test Count
+ */
+register PLL400CNT0 {
+	address			0x06E
+	access_mode	RO
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * SCB Page Pointer
+ */
+register SCBPTR {
+	address			0x0A8
+	access_mode	RW
+	size		2
+	modes		M_DFF0, M_DFF1, M_CCHAN, M_SCSI
+}
+
+/*
+ * CMC SCB Array Count
+ * Number of bytes to transfer between CMC SCB memory and SCBRAM.
+ * Transfers must be 8byte aligned and sized.
+ */
+register CCSCBACNT {
+	address			0x0AB
+	access_mode	RW
+	modes		M_CCHAN
+}
+
+/*
+ * SCB Autopointer
+ * SCB-Next Address Snooping logic.  When an SCB is transferred to
+ * the card, the next SCB address to be used by the CMC array can
+ * be autoloaded from that transfer.
+ */
+register SCBAUTOPTR {
+	address			0x0AB
+	access_mode	RW
+	modes		M_CFG
+	field	AUSCBPTR_EN	0x80
+	field	SCBPTR_ADDR	0x38
+	field	SCBPTR_OFF	0x07
+}
+
+/*
+ * CMC SG Ram Address Pointer
+ */
+register CCSGADDR {
+	address			0x0AC
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * CMC SCB RAM Address Pointer
+ */
+register CCSCBADDR {
+	address			0x0AC
+	access_mode	RW
+	modes		M_CCHAN
+}
+
+/*
+ * CMC SCB Ram Back-up Address Pointer
+ * Indicates the true stop location of transfers halted prior
+ * to SCBHCNT going to 0.
+ */
+register CCSCBADR_BK {
+	address			0x0AC
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * CMC SG Control
+ */
+register CCSGCTL {
+	address			0x0AD
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	CCSGDONE	0x80
+	field	SG_CACHE_AVAIL	0x10
+	field	CCSGENACK	0x08
+	mask	CCSGEN		0x0C
+	field	SG_FETCH_REQ	0x02
+	field	CCSGRESET	0x01
+}
+
+/*
+ * CMD SCB Control
+ */
+register CCSCBCTL {
+	address			0x0AD
+	access_mode	RW
+	modes		M_CCHAN
+	field	CCSCBDONE	0x80
+	field	ARRDONE		0x40
+	field	CCARREN		0x10
+	field	CCSCBEN		0x08
+	field	CCSCBDIR	0x04
+	field	CCSCBRESET	0x01
+}
+
+/*
+ * CMC Ram BIST
+ */
+register CMC_RAMBIST {
+	address			0x0AD
+	access_mode	RW
+	modes		M_CFG
+	field	SG_ELEMENT_SIZE		0x80
+	field	SCBRAMBIST_FAIL		0x40
+	field	SG_BIST_FAIL		0x20
+	field	SG_BIST_EN		0x10
+	field	CMC_BUFFER_BIST_FAIL	0x02
+	field	CMC_BUFFER_BIST_EN	0x01
+}
+
+/*
+ * CMC SG RAM Data Port
+ */
+register CCSGRAM {
+	address			0x0B0
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * CMC SCB RAM Data Port
+ */
+register CCSCBRAM {
+	address			0x0B0
+	access_mode	RW
+	modes		M_CCHAN
+}
+
+/*
+ * Flex DMA Address.
+ */
+register FLEXADR {
+	address			0x0B0
+	access_mode	RW
+	size		3
+	modes		M_SCSI
+}
+
+/*
+ * Flex DMA Byte Count
+ */
+register FLEXCNT {
+	address			0x0B3
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * Flex DMA Status
+ */
+register FLEXDMASTAT {
+	address			0x0B5
+	access_mode	RW
+	modes		M_SCSI
+	field	FLEXDMAERR	0x02
+	field	FLEXDMADONE	0x01
+}
+
+/*
+ * Flex DMA Data Port
+ */
+register FLEXDATA {
+	address			0x0B6
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Board Data
+ */
+register BRDDAT {
+	address			0x0B8
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Board Control
+ */
+register BRDCTL {
+	address			0x0B9
+	access_mode	RW
+	modes		M_SCSI
+	field	FLXARBACK	0x80
+	field	FLXARBREQ	0x40
+	field	BRDADDR		0x38
+	field	BRDEN		0x04
+	field	BRDRW		0x02
+	field	BRDSTB		0x01
+}
+
+/*
+ * Serial EEPROM Address
+ */
+register SEEADR {
+	address			0x0BA
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Serial EEPROM Data
+ */
+register SEEDAT {
+	address			0x0BC
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * Serial EEPROM Status
+ */
+register SEESTAT {
+	address			0x0BE
+	access_mode	RO
+	modes		M_SCSI
+	field	INIT_DONE	0x80
+	field	SEEOPCODE	0x70
+	field	LDALTID_L	0x08
+	field	SEEARBACK	0x04
+	field	SEEBUSY		0x02
+	field	SEESTART	0x01
+}
+
+/*
+ * Serial EEPROM Control
+ */
+register SEECTL {
+	address			0x0BE
+	access_mode	RW
+	modes		M_SCSI
+	field	SEEOPCODE	0x70 {
+		SEEOP_ERASE	0x70,
+		SEEOP_READ	0x60,
+		SEEOP_WRITE	0x50,
+	/*
+	 * The following four commands use special
+	 * addresses for differentiation.
+	 */
+		SEEOP_ERAL	0x40
+	}
+	mask	SEEOP_EWEN	0x40
+	mask	SEEOP_WALL	0x40
+	mask	SEEOP_EWDS	0x40
+	field	SEERST		0x02
+	field	SEESTART	0x01
+}
+
+const SEEOP_ERAL_ADDR	0x80
+const SEEOP_EWEN_ADDR	0xC0
+const SEEOP_WRAL_ADDR	0x40
+const SEEOP_EWDS_ADDR	0x00
+
+/*
+ * SCB Counter
+ */
+register SCBCNT {
+	address			0x0BF
+	access_mode	RW
+	modes		M_SCSI
+}
+
+/*
+ * Data FIFO Write Address
+ * Pointer to the next QWD location to be written to the data FIFO.
+ */
+register DFWADDR {
+	address			0x0C0
+	access_mode	RW
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * DSP Filter Control
+ */
+register DSPFLTRCTL {
+	address			0x0C0
+	access_mode	RW
+	modes		M_CFG
+	field	FLTRDISABLE	0x20
+	field	EDGESENSE	0x10
+	field	DSPFCNTSEL	0x0F
+}
+
+/*
+ * DSP Data Channel Control
+ */
+register DSPDATACTL {
+	address			0x0C1
+	access_mode	RW
+	modes		M_CFG
+	field	BYPASSENAB	0x80
+	field	DESQDIS		0x10
+	field	RCVROFFSTDIS	0x04
+	field	XMITOFFSTDIS	0x02
+}
+
+/*
+ * Data FIFO Read Address
+ * Pointer to the next QWD location to be read from the data FIFO.
+ */
+register DFRADDR {
+	address			0x0C2
+	access_mode	RW
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * DSP REQ Control
+ */
+register DSPREQCTL {
+	address			0x0C2
+	access_mode	RW
+	modes		M_CFG
+	field	MANREQCTL	0xC0
+	field	MANREQDLY	0x3F
+}
+
+/*
+ * DSP ACK Control
+ */
+register DSPACKCTL {
+	address			0x0C3
+	access_mode	RW
+	modes		M_CFG
+	field	MANACKCTL	0xC0
+	field	MANACKDLY	0x3F
+}
+
+/*
+ * Data FIFO Data
+ * Read/Write byte port into the data FIFO.  The read and write
+ * FIFO pointers increment with each read and write respectively
+ * to this port.
+ */
+register DFDAT {
+	address			0x0C4
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * DSP Channel Select
+ */
+register DSPSELECT {
+	address			0x0C4
+	access_mode	RW
+	modes		M_CFG
+	field	AUTOINCEN	0x80
+	field	DSPSEL		0x1F
+}
+
+const NUMDSPS 0x14
+
+/*
+ * Write Bias Control
+ */
+register WRTBIASCTL {
+	address			0x0C5
+	access_mode	WO
+	modes		M_CFG
+	field	AUTOXBCDIS	0x80
+	field	XMITMANVAL	0x3F
+}
+
+/*
+ * Currently the WRTBIASCTL is the same as the default.
+ */
+const WRTBIASCTL_HP_DEFAULT 0x0
+
+/*
+ * Receiver Bias Control
+ */
+register RCVRBIOSCTL {
+	address			0x0C6
+	access_mode	WO
+	modes		M_CFG
+	field	AUTORBCDIS	0x80
+	field	RCVRMANVAL	0x3F
+}
+
+/*
+ * Write Bias Calculator
+ */
+register WRTBIASCALC {
+	address			0x0C7
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * Data FIFO Pointers
+ * Contains the byte offset from DFWADDR and DWRADDR to the current
+ * FIFO write/read locations.
+ */
+register DFPTRS {
+	address			0x0C8
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Receiver Bias Calculator
+ */
+register RCVRBIASCALC {
+	address			0x0C8
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * Data FIFO Backup Read Pointer
+ * Contains the data FIFO address to be restored if the last
+ * data accessed from the data FIFO was not transferred successfully.
+ */
+register DFBKPTR {
+	address			0x0C9
+	access_mode	RW
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Skew Calculator
+ */
+register SKEWCALC {
+	address			0x0C9
+	access_mode	RO
+	modes		M_CFG
+}
+
+/*
+ * Data FIFO Debug Control
+ */
+register DFDBCTL {
+	address				0x0CB
+	access_mode	RW
+	modes		M_DFF0, M_DFF1
+	field	DFF_CIO_WR_RDY		0x20
+	field	DFF_CIO_RD_RDY		0x10
+	field	DFF_DIR_ERR		0x08
+	field	DFF_RAMBIST_FAIL	0x04
+	field	DFF_RAMBIST_DONE	0x02
+	field	DFF_RAMBIST_EN		0x01
+}
+
+/*
+ * Data FIFO Space Count
+ * Number of FIFO locations that are free.
+ */
+register DFSCNT {
+	address			0x0CC
+	access_mode	RO
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Data FIFO Byte Count
+ * Number of filled FIFO locations.
+ */
+register DFBCNT {
+	address			0x0CE
+	access_mode	RO
+	size		2
+	modes		M_DFF0, M_DFF1
+}
+
+/*
+ * Sequencer Program Overlay Address.
+ * Low address must be written prior to high address.
+ */
+register OVLYADDR {
+	address			0x0D4
+	modes		M_SCSI
+	size		2
+	access_mode	RW
+}
+
+/*
+ * Sequencer Control 0
+ * Error detection mode, speed configuration,
+ * single step, breakpoints and program load.
+ */
+register SEQCTL0 {
+	address			0x0D6
+	access_mode RW
+	field	PERRORDIS	0x80
+	field	PAUSEDIS	0x40
+	field	FAILDIS		0x20
+	field	FASTMODE	0x10
+	field	BRKADRINTEN	0x08
+	field	STEP		0x04
+	field	SEQRESET	0x02
+	field	LOADRAM		0x01
+}
+
+/*
+ * Sequencer Control 1
+ * Instruction RAM Diagnostics
+ */
+register SEQCTL1 {
+	address			0x0D7
+	access_mode RW
+	field	OVRLAY_DATA_CHK	0x08
+	field	RAMBIST_DONE	0x04
+	field	RAMBIST_FAIL	0x02
+	field	RAMBIST_EN	0x01
+}
+
+/*
+ * Sequencer Flags
+ * Zero and Carry state of the ALU.
+ */
+register FLAGS {
+	address			0x0D8
+	access_mode RO
+	field	ZERO		0x02
+	field	CARRY		0x01
+}
+
+/*
+ * Sequencer Interrupt Control
+ */ 
+register SEQINTCTL {
+	address			0x0D9
+	access_mode RW
+	field	INTVEC1DSL	0x80
+	field	INT1_CONTEXT	0x20
+	field	SCS_SEQ_INT1M1	0x10
+	field	SCS_SEQ_INT1M0	0x08
+	field	INTMASK2	0x04
+	field	INTMASK1	0x02
+	field	IRET		0x01
+}
+
+/*
+ * Sequencer RAM Data Port
+ * Single byte window into the Sequencer Instruction Ram area starting
+ * at the address specified by OVLYADDR.  To write a full instruction word,
+ * simply write four bytes in succession.  OVLYADDR will increment after the
+ * most significant instrution byte (the byte with the parity bit) is written.
+ */
+register SEQRAM {
+	address			0x0DA
+	access_mode RW
+}
+
+/*
+ * Sequencer Program Counter
+ * Low byte must be written prior to high byte.
+ */
+register PRGMCNT {
+	address			0x0DE
+	access_mode	RW
+	size		2
+}
+
+/*
+ * Accumulator
+ */
+register ACCUM {
+	address			0x0E0
+	access_mode RW
+	accumulator
+}
+
+/*
+ * Source Index Register
+ * Incrementing index for reads of SINDIR and the destination (low byte only)
+ * for any immediate operands passed in jmp, jc, jnc, call instructions.
+ * Example:
+ *		mvi	0xFF	call some_routine;
+ *
+ *  Will set SINDEX[0] to 0xFF and call the routine "some_routine.
+ */
+register SINDEX	{
+	address			0x0E2
+	access_mode	RW
+	size		2
+	sindex
+}
+
+/*
+ * Destination Index Register
+ * Incrementing index for writes to DINDIR.  Can be used as a scratch register.
+ */
+register DINDEX {
+	address			0x0E4
+	access_mode	RW
+	size		2
+}
+
+/*
+ * Break Address
+ * Sequencer instruction breakpoint address address.
+ */
+register BRKADDR0 {
+	address			0x0E6
+	access_mode	RW
+}
+
+register BRKADDR1 {
+	address			0x0E6
+	access_mode	RW
+	field	BRKDIS		0x80	/* Disable Breakpoint */
+}
+
+/*
+ * All Ones
+ * All reads to this register return the value 0xFF.
+ */
+register ALLONES {
+	address			0x0E8
+	access_mode RO
+	allones
+}
+
+/*
+ * All Zeros
+ * All reads to this register return the value 0.
+ */
+register ALLZEROS {
+	address			0x0EA
+	access_mode RO
+	allzeros
+}
+
+/*
+ * No Destination
+ * Writes to this register have no effect.
+ */
+register NONE {
+	address			0x0EA
+	access_mode WO
+	none
+}
+
+/*
+ * Source Index Indirect
+ * Reading this register is equivalent to reading (register_base + SINDEX) and
+ * incrementing SINDEX by 1.
+ */
+register SINDIR	{
+	address			0x0EC
+	access_mode RO
+}
+
+/*
+ * Destination Index Indirect
+ * Writing this register is equivalent to writing to (register_base + DINDEX)
+ * and incrementing DINDEX by 1.
+ */
+register DINDIR	 {
+	address			0x0ED
+	access_mode WO
+}
+
+/*
+ * Function One
+ * 2's complement to bit value conversion.  Write the 2's complement value
+ * (0-7 only) to the top nibble and retrieve the bit indexed by that value
+ * on the next read of this register. 
+ * Example:
+ *	Write	0x60
+ *	Read	0x40
+ */
+register FUNCTION1 {
+	address			0x0F0
+	access_mode RW
+}
+
+/*
+ * Stack
+ * Window into the stack.  Each stack location is 10 bits wide reported
+ * low byte followed by high byte.  There are 8 stack locations.
+ */
+register STACK {
+	address			0x0F2
+	access_mode RW
+}
+
+/*
+ * Interrupt Vector 1 Address
+ * Interrupt branch address for SCS SEQ_INT1 mode 0 and 1 interrupts.
+ */
+register INTVEC1_ADDR {
+	address			0x0F4
+	access_mode	RW
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * Current Address
+ * Address of the SEQRAM instruction currently executing instruction.
+ */
+register CURADDR {
+	address			0x0F4
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+/*
+ * Interrupt Vector 2 Address
+ * Interrupt branch address for HST_SEQ_INT2 interrupts.
+ */
+register INTVEC2_ADDR {
+	address			0x0F6
+	access_mode	RW
+	size		2
+	modes		M_CFG
+}
+
+/*
+ * Last Address
+ * Address of the SEQRAM instruction executed prior to the current instruction.
+ */
+register LASTADDR {
+	address			0x0F6
+	access_mode	RW
+	size		2
+	modes		M_SCSI
+}
+
+register AHD_PCI_CONFIG_BASE {
+	address			0x100
+	access_mode	RW
+	size		256
+	modes		M_CFG
+}
+
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+scratch_ram {
+	/* Mode Specific */
+	address			0x0A0
+	size	8
+	modes	0, 1, 2, 3
+	REG0 {
+		size		2
+	}
+	REG1 {
+		size		2
+	}
+	REG_ISR {
+		size		2
+	}
+	SG_STATE {
+		size		1
+		field	SEGS_AVAIL	0x01
+		field	LOADING_NEEDED	0x02
+		field	FETCH_INPROG	0x04
+	}
+	/*
+	 * Track whether the transfer byte count for
+	 * the current data phase is odd.
+	 */
+	DATA_COUNT_ODD {
+		size		1
+	}
+}
+
+scratch_ram {
+	/* Mode Specific */
+	address			0x0F8
+	size	8
+	modes	0, 1, 2, 3
+	LONGJMP_ADDR {
+		size		2
+	}
+	ACCUM_SAVE {
+		size		1
+	}
+}
+
+
+scratch_ram {
+	address			0x100
+	size	128
+	modes	0, 1, 2, 3
+	/*
+	 * Per "other-id" execution queues.  We use an array of
+	 * tail pointers into lists of SCBs sorted by "other-id".
+	 * The execution head pointer threads the head SCBs for
+	 * each list.
+	 */
+	WAITING_SCB_TAILS {
+		size		32
+	}
+	WAITING_TID_HEAD {
+		size		2
+	}
+	WAITING_TID_TAIL {
+		size		2
+	}
+	/*
+	 * SCBID of the next SCB in the new SCB queue.
+	 */
+	NEXT_QUEUED_SCB_ADDR {
+		size		4
+	}
+	/*
+	 * head of list of SCBs that have
+	 * completed but have not been
+	 * put into the qoutfifo.
+	 */
+	COMPLETE_SCB_HEAD {
+		size		2
+	}
+	/*
+	 * The list of completed SCBs in
+	 * the active DMA.
+	 */
+	COMPLETE_SCB_DMAINPROG_HEAD {
+		size		2
+	}
+	/*
+	 * head of list of SCBs that have
+	 * completed but need to be uploaded
+	 * to the host prior to being completed.
+	 */
+	COMPLETE_DMA_SCB_HEAD {
+		size		2
+	}
+	/* Counting semaphore to prevent new select-outs */
+	QFREEZE_COUNT {
+		size		2
+	}
+	/*
+	 * Mode to restore on legacy idle loop exit.
+	 */
+	SAVED_MODE {
+		size		1
+	}
+	/*
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
+	 */
+	MSG_OUT {
+		size		1
+	}
+	/* Parameters for DMA Logic */
+	DMAPARAMS {
+		size		1
+		field	PRELOADEN	0x80
+		field	WIDEODD		0x40
+		field	SCSIEN		0x20
+		field	SDMAEN		0x10
+		field	SDMAENACK	0x10
+		field	HDMAEN		0x08
+		field	HDMAENACK	0x08
+		field	DIRECTION	0x04	/* Set indicates PCI->SCSI */
+		field	FIFOFLUSH	0x02
+		field	FIFORESET	0x01
+	}
+	SEQ_FLAGS {
+		size		1
+		field	NOT_IDENTIFIED		0x80
+		field	NO_CDB_SENT		0x40
+		field	TARGET_CMD_IS_TAGGED	0x40
+		field	DPHASE			0x20
+		/* Target flags */
+		field	TARG_CMD_PENDING	0x10
+		field	CMDPHASE_PENDING	0x08
+		field	DPHASE_PENDING		0x04
+		field	SPHASE_PENDING		0x02
+		field	NO_DISCONNECT		0x01
+	}
+	/*
+	 * Temporary storage for the
+	 * target/channel/lun of a
+	 * reconnecting target
+	 */
+	SAVED_SCSIID {
+		size		1
+	}
+	SAVED_LUN {
+		size		1
+	}
+	/*
+	 * The last bus phase as seen by the sequencer. 
+	 */
+	LASTPHASE {
+		size		1
+		field	CDI		0x80
+		field	IOI		0x40
+		field	MSGI		0x20
+		field	P_BUSFREE	0x01
+		enum	PHASE_MASK  CDO|IOO|MSGO {
+			P_DATAOUT	0x0,
+			P_DATAIN	IOO,
+			P_DATAOUT_DT	P_DATAOUT|MSGO,
+			P_DATAIN_DT	P_DATAIN|MSGO,
+			P_COMMAND	CDO,
+			P_MESGOUT	CDO|MSGO,
+			P_STATUS	CDO|IOO,
+			P_MESGIN	CDO|IOO|MSGO
+		}
+	}
+	/*
+	 * Value to "or" into the SCBPTR[1] value to
+	 * indicate that an entry in the QINFIFO is valid.
+	 */
+	QOUTFIFO_ENTRY_VALID_TAG {
+		size		1
+	}
+	/*
+	 * Base address of our shared data with the kernel driver in host
+	 * memory.  This includes the qoutfifo and target mode
+	 * incoming command queue.
+	 */
+	SHARED_DATA_ADDR {
+		size		4
+	}
+	/*
+	 * Pointer to location in host memory for next
+	 * position in the qoutfifo.
+	 */
+	QOUTFIFO_NEXT_ADDR {
+		size		4
+	}
+	/*
+	 * Kernel and sequencer offsets into the queue of
+	 * incoming target mode command descriptors.  The
+	 * queue is full when the KERNEL_TQINPOS == TQINPOS.
+	 */
+	KERNEL_TQINPOS {
+		size		1
+	}
+	TQINPOS {                
+		size		1
+	}
+	ARG_1 {
+		size		1
+		mask	SEND_MSG		0x80
+		mask	SEND_SENSE		0x40
+		mask	SEND_REJ		0x20
+		mask	MSGOUT_PHASEMIS		0x10
+		mask	EXIT_MSG_LOOP		0x08
+		mask	CONT_MSG_LOOP_WRITE	0x04
+		mask	CONT_MSG_LOOP_READ	0x03
+		mask	CONT_MSG_LOOP_TARG	0x02
+		alias	RETURN_1
+	}
+	ARG_2 {
+		size		1
+		alias	RETURN_2
+	}
+
+	/*
+	 * Snapshot of MSG_OUT taken after each message is sent.
+	 */
+	LAST_MSG {
+		size		1
+	}
+
+	/*
+	 * Sequences the kernel driver has okayed for us.  This allows
+	 * the driver to do things like prevent initiator or target
+	 * operations.
+	 */
+	SCSISEQ_TEMPLATE {
+		size		1
+		field	MANUALCTL	0x40
+		field	ENSELI		0x20
+		field	ENRSELI		0x10
+		field	MANUALP		0x0C
+		field	ENAUTOATNP	0x02
+		field	ALTSTIM		0x01
+	}
+
+	/*
+	 * The initiator specified tag for this target mode transaction.
+	 */
+	INITIATOR_TAG {
+		size		1
+	}
+
+	SEQ_FLAGS2 {
+		size		1
+		field	TARGET_MSG_PENDING	  0x02
+		field	SELECTOUT_QFROZEN	  0x04
+	}
+
+	ALLOCFIFO_SCBPTR {
+		size		2
+	}
+
+	/*
+	 * The maximum amount of time to wait, when interrupt coalescing
+	 * is enabled, before issueing a CMDCMPLT interrupt for a completed
+	 * command.
+	 */
+	INT_COALESCING_TIMER {
+		size		2
+	}
+
+	/*
+	 * The maximum number of commands to coalesce into a single interrupt.
+	 * Actually the 2's complement of that value to simplify sequencer
+	 * code.
+	 */
+	INT_COALESCING_MAXCMDS {
+		size		1
+	}
+
+	/*
+	 * The minimum number of commands still outstanding required
+	 * to continue coalescing (2's complement of value).
+	 */
+	INT_COALESCING_MINCMDS {
+		size		1
+	}
+
+	/*
+	 * Number of commands "in-flight".
+	 */
+	CMDS_PENDING {
+		size		2
+	}
+
+	/*
+	 * The count of commands that have been coalesced.
+	 */
+	INT_COALESCING_CMDCOUNT {
+		size		1
+	}
+
+	/*
+	 * Since the HS_MAIBOX is self clearing, copy its contents to
+	 * this position in scratch ram every time it changes.
+	 */
+	LOCAL_HS_MAILBOX {
+		size		1
+	}
+	/*
+	 * Target-mode CDB type to CDB length table used
+	 * in non-packetized operation.
+	 */
+	CMDSIZE_TABLE {
+		size		8
+	}
+}
+
+/************************* Hardware SCB Definition ****************************/
+scb {
+	address			0x180
+	size	64
+	modes	0, 1, 2, 3
+	SCB_RESIDUAL_DATACNT {
+		size	4
+		alias	SCB_CDB_STORE
+		alias	SCB_HOST_CDB_PTR
+	}
+	SCB_RESIDUAL_SGPTR {
+		size	4
+		field	SG_ADDR_MASK		0xf8	/* In the last byte */
+		field	SG_OVERRUN_RESID	0x02	/* In the first byte */
+		field	SG_LIST_NULL		0x01	/* In the first byte */
+	}
+	SCB_SCSI_STATUS {
+		size	1
+		alias	SCB_HOST_CDB_LEN
+	}
+	SCB_TARGET_PHASES {
+		size	1
+	}
+	SCB_TARGET_DATA_DIR {
+		size	1
+	}
+	SCB_TARGET_ITAG {
+		size	1
+	}
+	SCB_SENSE_BUSADDR {
+		/*
+		 * Only valid if CDB length is less than 13 bytes or
+		 * we are using a CDB pointer.  Otherwise contains
+		 * the last 4 bytes of embedded cdb information.
+		 */
+		size	4
+		alias	SCB_NEXT_COMPLETE
+	}
+	SCB_TAG {
+		alias	SCB_FIFO_USE_COUNT
+		size	2
+	}
+	SCB_CONTROL {
+		size	1
+		field	TARGET_SCB	0x80
+		field	DISCENB		0x40
+		field	TAG_ENB		0x20
+		field	MK_MESSAGE	0x10
+		field	STATUS_RCVD	0x08
+		field	DISCONNECTED	0x04
+		field	SCB_TAG_TYPE	0x03
+	}
+	SCB_SCSIID {
+		size	1
+		field	TID	0xF0
+		field	OID	0x0F
+	}
+	SCB_LUN {
+		size	1
+		field	LID	0xff
+	}
+	SCB_TASK_ATTRIBUTE {
+		size	1
+		/*
+		 * Overloaded field for non-packetized 
+		 * ignore wide residue message handling.
+		 */
+		field	SCB_XFERLEN_ODD	0x01
+	}
+	SCB_CDB_LEN {
+		size	1
+		field	SCB_CDB_LEN_PTR	0x80	/* CDB in host memory */
+	}
+	SCB_TASK_MANAGEMENT {
+		size	1
+	}
+	SCB_DATAPTR {
+		size	8
+	}
+	SCB_DATACNT {
+		/*
+		 * The last byte is really the high address bits for
+		 * the data address.
+		 */
+		size	4
+		field	SG_LAST_SEG		0x80	/* In the fourth byte */
+		field	SG_HIGH_ADDR_BITS	0x7F	/* In the fourth byte */
+	}
+	SCB_SGPTR {
+		size	4
+		field	SG_STATUS_VALID	0x04	/* In the first byte */
+		field	SG_FULL_RESID	0x02	/* In the first byte */
+		field	SG_LIST_NULL	0x01	/* In the first byte */
+	}
+	SCB_BUSADDR {
+		size	4
+	}
+	SCB_NEXT {
+		alias	SCB_NEXT_SCB_BUSADDR
+		size	2
+	}
+	SCB_NEXT2 {
+		size	2
+	}
+	SCB_SPARE {
+		size	8
+		alias	SCB_PKT_LUN
+	}
+	SCB_DISCONNECTED_LISTS {
+		size	8
+	}
+}
+
+/*********************************** Constants ********************************/
+const MK_MESSAGE_BIT_OFFSET	4
+const TID_SHIFT		4
+const TARGET_CMD_CMPLT	0xfe
+const INVALID_ADDR	0x80
+#define SCB_LIST_NULL	0xff
+#define QOUTFIFO_ENTRY_VALID_TOGGLE	0x80
+
+const CCSGADDR_MAX	0x80
+const CCSCBADDR_MAX	0x80
+const CCSGRAM_MAXSEGS	16
+
+/* Selection Timeout Timer Constants */
+const STIMESEL_SHIFT	3
+const STIMESEL_MIN	0x18
+const STIMESEL_BUG_ADJ	0x8
+
+/* WDTR Message values */
+const BUS_8_BIT			0x00
+const BUS_16_BIT		0x01
+const BUS_32_BIT		0x02
+
+/* Offset maximums */
+const MAX_OFFSET		0xfe
+const MAX_OFFSET_PACED		0xfe
+const MAX_OFFSET_PACED_BUG	0x7f
+/*
+ * Some 160 devices incorrectly accept 0xfe as a
+ * sync offset, but will overrun this value.  Limit
+ * to 0x7f for speed lower than U320 which will
+ * avoid the persistent sync offset overruns.
+ */
+const MAX_OFFSET_NON_PACED	0x7f
+const HOST_MSG			0xff
+
+/*
+ * The size of our sense buffers.
+ * Sense buffer mapping can be handled in either of two ways.
+ * The first is to allocate a dmamap for each transaction.
+ * Depending on the architecture, dmamaps can be costly. The
+ * alternative is to statically map the buffers in much the same
+ * way we handle our scatter gather lists.  The driver implements
+ * the later.
+ */
+const AHD_SENSE_BUFSIZE		256
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+
+const STATUS_BUSY		0x08
+const STATUS_QUEUE_FULL		0x28
+const STATUS_PKT_SENSE		0xFF
+const TARGET_DATA_IN		1
+
+const SCB_TRANSFER_SIZE_FULL_LUN	56
+const SCB_TRANSFER_SIZE_1BYTE_LUN	48
+/* PKT_OVERRUN_BUFSIZE must be a multiple of 256 less than 64K */
+const PKT_OVERRUN_BUFSIZE	512
+
+/*
+ * Timer parameters.
+ */
+const AHD_TIMER_US_PER_TICK	25
+const AHD_TIMER_MAX_TICKS	0xFFFF
+const AHD_TIMER_MAX_US		(AHD_TIMER_MAX_TICKS * AHD_TIMER_US_PER_TICK)
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+const SG_PREFETCH_CNT download
+const SG_PREFETCH_CNT_LIMIT download
+const SG_PREFETCH_ALIGN_MASK download
+const SG_PREFETCH_ADDR_MASK download
+const SG_SIZEOF download
+const PKT_OVERRUN_BUFOFFSET download
+const SCB_TRANSFER_SIZE	download
+
+/*
+ * BIOS SCB offsets
+ */
+const NVRAM_SCB_OFFSET	0x2C
diff --git a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
new file mode 100644
index 0000000..65339bc
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx.seq
@@ -0,0 +1,2058 @@
+/*
+ * Adaptec U320 device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#99 $"
+PATCH_ARG_LIST = "struct ahd_softc *ahd"
+PREFIX = "ahd_"
+
+#include "aic79xx.reg"
+#include "scsi_message.h"
+
+restart:
+if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+	test	SEQINTCODE, 0xFF jz idle_loop;
+	SET_SEQINTCODE(NO_SEQINT)
+}
+
+idle_loop:
+
+	if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+		/*
+		 * Convert ERROR status into a sequencer
+		 * interrupt to handle the case of an
+		 * interrupt collision on the hardware
+		 * setting of HWERR.
+		 */
+		test	ERROR, 0xFF jz no_error_set;
+		SET_SEQINTCODE(SAW_HWERR)
+no_error_set:
+	}
+	SET_MODE(M_SCSI, M_SCSI)
+	test	SCSISEQ0, ENSELO|ENARBO jnz idle_loop_checkbus;
+	test	SEQ_FLAGS2, SELECTOUT_QFROZEN jnz idle_loop_checkbus;
+	cmp	WAITING_TID_HEAD[1], SCB_LIST_NULL je idle_loop_checkbus;
+	/*
+	 * ENSELO is cleared by a SELDO, so we must test for SELDO
+	 * one last time.
+	 */
+BEGIN_CRITICAL;
+	test	SSTAT0, SELDO jnz select_out;
+END_CRITICAL;
+	call	start_selection;
+idle_loop_checkbus:
+BEGIN_CRITICAL;
+	test	SSTAT0, SELDO jnz select_out;
+END_CRITICAL;
+	test	SSTAT0, SELDI jnz select_in;
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz idle_loop_check_nonpackreq;
+	test	SCSISIGO, ATNO jz idle_loop_check_nonpackreq;
+	call	unexpected_nonpkt_phase_find_ctxt;
+idle_loop_check_nonpackreq:
+	test	SSTAT2, NONPACKREQ jz . + 2;
+	call	unexpected_nonpkt_phase_find_ctxt;
+	if ((ahd->bugs & AHD_FAINT_LED_BUG) != 0) {
+		and	A, FIFO0FREE|FIFO1FREE, DFFSTAT;
+		cmp	A, FIFO0FREE|FIFO1FREE jne . + 3;
+		and	SBLKCTL, ~DIAGLEDEN|DIAGLEDON;
+		jmp	. + 2;
+		or	SBLKCTL, DIAGLEDEN|DIAGLEDON;
+	}
+	call	idle_loop_gsfifo_in_scsi_mode;
+	call	idle_loop_service_fifos;
+	call	idle_loop_cchan;
+	jmp	idle_loop;
+
+BEGIN_CRITICAL;
+idle_loop_gsfifo:
+	SET_MODE(M_SCSI, M_SCSI)
+idle_loop_gsfifo_in_scsi_mode:
+	test	LQISTAT2, LQIGSAVAIL jz return;
+	/*
+	 * We have received good status for this transaction.  There may
+	 * still be data in our FIFOs draining to the host.  Complete
+	 * the SCB only if all data has transferred to the host.
+	 */
+good_status_IU_done:
+	bmov	SCBPTR, GSFIFO, 2;
+	clr	SCB_SCSI_STATUS;
+	/*
+	 * If a command completed before an attempted task management
+	 * function completed, notify the host after disabling any
+	 * pending select-outs.
+	 */
+	test	SCB_TASK_MANAGEMENT, 0xFF jz gsfifo_complete_normally;
+	test	SSTAT0, SELDO|SELINGO jnz . + 2;
+	and	SCSISEQ0, ~ENSELO;
+	SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)
+gsfifo_complete_normally:
+	or	SCB_CONTROL, STATUS_RCVD;
+
+	/*
+	 * Since this status did not consume a FIFO, we have to
+	 * be a bit more dilligent in how we check for FIFOs pertaining
+	 * to this transaction.  There are two states that a FIFO still
+	 * transferring data may be in.
+	 *
+	 * 1) Configured and draining to the host, with a FIFO handler.
+	 * 2) Pending cfg4data, fifo not empty.
+	 *
+	 * Case 1 can be detected by noticing a non-zero FIFO active
+	 * count in the SCB.  In this case, we allow the routine servicing
+	 * the FIFO to complete the SCB.
+	 * 
+	 * Case 2 implies either a pending or yet to occur save data
+	 * pointers for this same context in the other FIFO.  So, if
+	 * we detect case 1, we will properly defer the post of the SCB
+	 * and achieve the desired result.  The pending cfg4data will
+	 * notice that status has been received and complete the SCB.
+	 */
+	test	SCB_FIFO_USE_COUNT, 0xFF jnz idle_loop_gsfifo_in_scsi_mode;
+	call	complete;
+END_CRITICAL;
+	jmp	idle_loop_gsfifo_in_scsi_mode;
+
+idle_loop_service_fifos:
+	SET_MODE(M_DFF0, M_DFF0)
+	test	LONGJMP_ADDR[1], INVALID_ADDR jnz idle_loop_next_fifo;
+	call	longjmp;
+idle_loop_next_fifo:
+	SET_MODE(M_DFF1, M_DFF1)
+	test	LONGJMP_ADDR[1], INVALID_ADDR jz longjmp;
+return:
+	ret;
+
+idle_loop_cchan:
+	SET_MODE(M_CCHAN, M_CCHAN)
+	test	QOFF_CTLSTA, HS_MAILBOX_ACT jz	hs_mailbox_empty;
+	or	QOFF_CTLSTA, HS_MAILBOX_ACT;
+	mov	LOCAL_HS_MAILBOX, HS_MAILBOX;
+hs_mailbox_empty:
+BEGIN_CRITICAL;
+	test	CCSCBCTL, CCARREN|CCSCBEN jz scbdma_idle;
+	test	CCSCBCTL, CCSCBDIR jnz fetch_new_scb_inprog;
+	test	CCSCBCTL, CCSCBDONE jz return;
+END_CRITICAL;
+	/* FALLTHROUGH */
+scbdma_tohost_done:
+	test	CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
+	/*
+	 * An SCB has been succesfully uploaded to the host.
+	 * If the SCB was uploaded for some reason other than
+	 * bad SCSI status (currently only for underruns), we
+	 * queue the SCB for normal completion.  Otherwise, we
+	 * wait until any select-out activity has halted, and
+	 * then notify the host so that the transaction can be
+	 * dealt with.
+	 */
+	test	SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host;
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
+	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+scbdma_notify_host:
+	SET_MODE(M_SCSI, M_SCSI)
+	test	SCSISEQ0, ENSELO jnz return;
+	test	SSTAT0, (SELDO|SELINGO) jnz return;
+	SET_MODE(M_CCHAN, M_CCHAN)
+	/*
+	 * Remove SCB and notify host.
+	 */
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	SET_SEQINTCODE(BAD_SCB_STATUS)
+	ret;
+fill_qoutfifo_dmadone:
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	call	qoutfifo_updated;
+	mvi	COMPLETE_SCB_DMAINPROG_HEAD[1], SCB_LIST_NULL;
+	bmov	QOUTFIFO_NEXT_ADDR, SCBHADDR, 4;
+	test	QOFF_CTLSTA, SDSCB_ROLLOVR jz return;
+	bmov	QOUTFIFO_NEXT_ADDR, SHARED_DATA_ADDR, 4;
+	xor	QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID_TOGGLE ret;
+
+qoutfifo_updated:
+	/*
+	 * If there are more commands waiting to be dma'ed
+	 * to the host, always coalesce.  Otherwise honor the
+	 * host's wishes.
+	 */
+	cmp	COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count;
+	cmp	COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count;
+	test	LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt;
+
+	/*
+	 * If we have relatively few commands outstanding, don't
+	 * bother waiting for another command to complete.
+	 */
+	test	CMDS_PENDING[1], 0xFF jnz coalesce_by_count;
+	/* Add -1 so that jnc means <= not just < */
+	add	A, -1, INT_COALESCING_MINCMDS;
+	add	NONE, A, CMDS_PENDING;
+	jnc	issue_cmdcmplt;
+	
+	/*
+	 * If coalescing, only coalesce up to the limit
+	 * provided by the host driver.
+	 */
+coalesce_by_count:
+	mov	A, INT_COALESCING_MAXCMDS;
+	add	NONE, A, INT_COALESCING_CMDCOUNT;
+	jc	issue_cmdcmplt;
+	/*
+	 * If the timer is not currently active,
+	 * fire it up.
+	 */
+	test	INTCTL, SWTMINTMASK jz return;
+	bmov	SWTIMER, INT_COALESCING_TIMER, 2;
+	mvi	CLRSEQINTSTAT, CLRSEQ_SWTMRTO;
+	or	INTCTL, SWTMINTEN|SWTIMER_START;
+	and	INTCTL, ~SWTMINTMASK ret;
+
+issue_cmdcmplt:
+	mvi	INTSTAT, CMDCMPLT;
+	clr	INT_COALESCING_CMDCOUNT;
+	or	INTCTL, SWTMINTMASK ret;
+
+BEGIN_CRITICAL;
+fetch_new_scb_inprog:
+	test	CCSCBCTL, ARRDONE jz return;
+fetch_new_scb_done:
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	bmov	REG0, SCBPTR, 2;
+	clr	A;
+	add	CMDS_PENDING, 1;
+	adc	CMDS_PENDING[1], A;
+	if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) {
+		/*
+		 * "Short Luns" are not placed into outgoing LQ
+		 * packets in the correct byte order.  Use a full
+		 * sized lun field instead and fill it with the
+		 * one byte of lun information we support.
+		 */
+		mov	SCB_PKT_LUN[6], SCB_LUN;
+	}
+	/*
+	 * The FIFO use count field is shared with the
+	 * tag set by the host so that our SCB dma engine
+	 * knows the correct location to store the SCB.
+	 * Set it to zero before processing the SCB.
+	 */
+	clr	SCB_FIFO_USE_COUNT;
+	/* Update the next SCB address to download. */
+	bmov	NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4;
+	mvi	SCB_NEXT[1], SCB_LIST_NULL;
+	mvi	SCB_NEXT2[1], SCB_LIST_NULL;
+	/* Increment our position in the QINFIFO. */
+	mov	NONE, SNSCB_QOFF;
+	/*
+	 * SCBs that want to send messages are always
+	 * queued independently.  This ensures that they
+	 * are at the head of the SCB list to select out
+	 * to a target and we will see the MK_MESSAGE flag.
+	 */
+	test	SCB_CONTROL, MK_MESSAGE jnz first_new_target_scb;
+	shr	SINDEX, 3, SCB_SCSIID;
+	and	SINDEX, ~0x1;
+	mvi	SINDEX[1], (WAITING_SCB_TAILS >> 8);
+	bmov	DINDEX, SINDEX, 2;
+	bmov	SCBPTR, SINDIR, 2;
+	bmov	DINDIR, REG0, 2;
+	cmp	SCBPTR[1], SCB_LIST_NULL je first_new_target_scb;
+	bmov	SCB_NEXT, REG0, 2 ret;
+first_new_target_scb:
+	cmp	WAITING_TID_HEAD[1], SCB_LIST_NULL je first_new_scb;
+	bmov	SCBPTR, WAITING_TID_TAIL, 2;
+	bmov	SCB_NEXT2, REG0, 2;
+	bmov	WAITING_TID_TAIL, REG0, 2 ret;
+first_new_scb:
+	bmov	WAITING_TID_HEAD, REG0, 2;
+	bmov	WAITING_TID_TAIL, REG0, 2 ret;
+END_CRITICAL;
+
+scbdma_idle:
+	/*
+	 * Give precedence to downloading new SCBs to execute
+	 * unless select-outs are currently frozen.
+	 */
+	test	SEQ_FLAGS2, SELECTOUT_QFROZEN jnz . + 2;
+BEGIN_CRITICAL;
+	test	QOFF_CTLSTA, NEW_SCB_AVAIL jnz fetch_new_scb;
+	cmp	COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne dma_complete_scb;
+	cmp	COMPLETE_SCB_HEAD[1], SCB_LIST_NULL je return;
+	/* FALLTHROUGH */
+fill_qoutfifo:
+	/*
+	 * Keep track of the SCBs we are dmaing just
+	 * in case the DMA fails or is aborted.
+	 */
+	mov	A, QOUTFIFO_ENTRY_VALID_TAG;
+	bmov	COMPLETE_SCB_DMAINPROG_HEAD, COMPLETE_SCB_HEAD, 2;
+	mvi	CCSCBCTL, CCSCBRESET;
+	bmov	SCBHADDR, QOUTFIFO_NEXT_ADDR, 4;
+	bmov	SCBPTR, COMPLETE_SCB_HEAD, 2;
+fill_qoutfifo_loop:
+	mov	CCSCBRAM, SCBPTR;
+	or	CCSCBRAM, A, SCBPTR[1];
+	mov	NONE, SDSCB_QOFF;
+	inc	INT_COALESCING_CMDCOUNT;
+	add	CMDS_PENDING, -1;
+	adc	CMDS_PENDING[1], -1;
+	cmp	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done;
+	cmp	CCSCBADDR, CCSCBADDR_MAX je fill_qoutfifo_done;
+	test	QOFF_CTLSTA, SDSCB_ROLLOVR jnz fill_qoutfifo_done;
+	bmov	SCBPTR, SCB_NEXT_COMPLETE, 2;
+	jmp	fill_qoutfifo_loop;
+fill_qoutfifo_done:
+	mov	SCBHCNT, CCSCBADDR;
+	mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
+	bmov	COMPLETE_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	mvi	SCB_NEXT_COMPLETE[1], SCB_LIST_NULL ret;
+
+fetch_new_scb:
+	bmov	SCBHADDR, NEXT_QUEUED_SCB_ADDR, 4;
+	mvi	CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET jmp dma_scb;
+dma_complete_scb:
+	bmov	SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
+	bmov	SCBHADDR, SCB_BUSADDR, 4;
+	mvi	CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;
+END_CRITICAL;
+
+/*
+ * Either post or fetch an SCB from host memory.  The caller
+ * is responsible for polling for transfer completion.
+ *
+ * Prerequisits: Mode == M_CCHAN
+ *		 SINDEX contains CCSCBCTL flags
+ *		 SCBHADDR set to Host SCB address
+ *		 SCBPTR set to SCB src location on "push" operations
+ */
+SET_SRC_MODE	M_CCHAN;
+SET_DST_MODE	M_CCHAN;
+dma_scb:
+	mvi	SCBHCNT, SCB_TRANSFER_SIZE;
+	mov	CCSCBCTL, SINDEX ret;
+
+BEGIN_CRITICAL;
+setjmp:
+	bmov	LONGJMP_ADDR, STACK, 2 ret;
+setjmp_inline:
+	bmov	LONGJMP_ADDR, STACK, 2;
+longjmp:
+	bmov	STACK, LONGJMP_ADDR, 2 ret;
+END_CRITICAL;
+
+/*************************** Chip Bug Work Arounds ****************************/
+/*
+ * Must disable interrupts when setting the mode pointer
+ * register as an interrupt occurring mid update will
+ * fail to store the new mode value for restoration on
+ * an iret.
+ */
+if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {
+set_mode_work_around:
+	mvi	SEQINTCTL, INTVEC1DSL;
+	mov	MODE_PTR, SINDEX;
+	clr	SEQINTCTL ret;
+
+toggle_dff_mode_work_around:
+	mvi	SEQINTCTL, INTVEC1DSL;
+	xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+	clr	SEQINTCTL ret;
+}
+
+
+if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+set_seqint_work_around:
+	mov	SEQINTCODE, SINDEX;
+	mvi	SEQINTCODE, NO_SEQINT ret;
+}
+
+/************************ Packetized LongJmp Routines *************************/
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+start_selection:
+BEGIN_CRITICAL;
+	if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) {
+		/*
+		 * Razor #494
+		 * Rev A hardware fails to update LAST/CURR/NEXTSCB
+		 * correctly after a packetized selection in several
+		 * situations:
+		 *
+		 * 1) If only one command existed in the queue, the
+		 *    LAST/CURR/NEXTSCB are unchanged.
+		 *
+		 * 2) In a non QAS, protocol allowed phase change,
+		 *    the queue is shifted 1 too far.  LASTSCB is
+		 *    the last SCB that was correctly processed.
+		 * 
+		 * 3) In the QAS case, if the full list of commands
+		 *    was successfully sent, NEXTSCB is NULL and neither
+		 *    CURRSCB nor LASTSCB can be trusted.  We must
+		 *    manually walk the list counting MAXCMDCNT elements
+		 *    to find the last SCB that was sent correctly.
+		 *
+		 * To simplify the workaround for this bug in SELDO
+		 * handling, we initialize LASTSCB prior to enabling
+		 * selection so we can rely on it even for case #1 above.
+		 */
+		bmov	LASTSCB, WAITING_TID_HEAD, 2;
+	}
+	bmov	CURRSCB, WAITING_TID_HEAD, 2;
+	bmov	SCBPTR, WAITING_TID_HEAD, 2;
+	shr	SELOID, 4, SCB_SCSIID;
+	/*
+	 * If we want to send a message to the device, ensure
+	 * we are selecting with atn irregardless of our packetized
+	 * agreement.  Since SPI4 only allows target reset or PPR
+	 * messages if this is a packetized connection, the change
+	 * to our negotiation table entry for this selection will
+	 * be cleared when the message is acted on.
+	 */
+	test	SCB_CONTROL, MK_MESSAGE jz . + 3;
+	mov	NEGOADDR, SELOID;
+	or	NEGCONOPTS, ENAUTOATNO;
+	or	SCSISEQ0, ENSELO ret;
+END_CRITICAL;
+
+/*
+ * Allocate a FIFO for a non-packetized transaction.
+ * In RevA hardware, both FIFOs must be free before we
+ * can allocate a FIFO for a non-packetized transaction.
+ */
+allocate_fifo_loop:
+	/*
+	 * Do whatever work is required to free a FIFO.
+	 */
+	call	idle_loop_service_fifos;
+	SET_MODE(M_SCSI, M_SCSI)
+allocate_fifo:
+	if ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0) {
+		and	A, FIFO0FREE|FIFO1FREE, DFFSTAT;
+		cmp	A, FIFO0FREE|FIFO1FREE jne allocate_fifo_loop;
+	} else {
+		test	DFFSTAT, FIFO1FREE jnz allocate_fifo1;
+		test	DFFSTAT, FIFO0FREE jz allocate_fifo_loop;
+		mvi	DFFSTAT, B_CURRFIFO_0;
+		SET_MODE(M_DFF0, M_DFF0)
+		bmov	SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;
+	}
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+allocate_fifo1:
+	mvi	DFFSTAT, CURRFIFO_1;
+	SET_MODE(M_DFF1, M_DFF1)
+	bmov	SCBPTR, ALLOCFIFO_SCBPTR, 2 ret;
+
+/*
+ * We have been reselected as an initiator
+ * or selected as a target.
+ */
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+select_in:
+	if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
+		/*
+		 * Test to ensure that the bus has not
+		 * already gone free prior to clearing
+		 * any stale busfree status.  This avoids
+		 * a window whereby a busfree just after
+		 * a selection could be missed.
+		 */
+		test	SCSISIGI, BSYI jz . + 2;
+		mvi	CLRSINT1,CLRBUSFREE;
+		or	SIMODE1, ENBUSFREE;
+	}
+	or	SXFRCTL0, SPIOEN;
+	and	SAVED_SCSIID, SELID_MASK, SELID;
+	and	A, OID, IOWNID;
+	or	SAVED_SCSIID, A;
+	mvi	CLRSINT0, CLRSELDI;
+	jmp	ITloop;
+
+/*
+ * We have successfully selected out.
+ *
+ * Clear SELDO.
+ * Dequeue all SCBs sent from the waiting queue
+ * Requeue all SCBs *not* sent to the tail of the waiting queue
+ * Take Razor #494 into account for above.
+ *
+ * In Packetized Mode:
+ *	Return to the idle loop.  Our interrupt handler will take
+ *	care of any incoming L_Qs.
+ *
+ * In Non-Packetize Mode:
+ *	Continue to our normal state machine.
+ */
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+select_out:
+BEGIN_CRITICAL;
+	/* Clear out all SCBs that have been successfully sent. */
+	if ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0) {
+		/*
+		 * For packetized, the LQO manager clears ENSELO on
+		 * the assertion of SELDO.  If we are non-packetized,
+		 * LASTSCB and CURRSCB are accurate.
+		 */
+		test	SCSISEQ0, ENSELO jnz use_lastscb;
+
+		/*
+		 * The update is correct for LQOSTAT1 errors.  All
+		 * but LQOBUSFREE are handled by kernel interrupts.
+		 * If we see LQOBUSFREE, return to the idle loop.
+		 * Once we are out of the select_out critical section,
+		 * the kernel will cleanup the LQOBUSFREE and we will
+		 * eventually restart the selection if appropriate.
+		 */
+		test	LQOSTAT1, LQOBUSFREE jnz idle_loop;
+
+		/*
+		 * On a phase change oustside of packet boundaries,
+		 * LASTSCB points to the currently active SCB context
+		 * on the bus.
+		 */
+		test	LQOSTAT2, LQOPHACHGOUTPKT jnz use_lastscb;
+
+		/*
+		 * If the hardware has traversed the whole list, NEXTSCB
+		 * will be NULL, CURRSCB and LASTSCB cannot be trusted,
+		 * but MAXCMDCNT is accurate.  If we stop part way through
+		 * the list or only had one command to issue, NEXTSCB[1] is
+		 * not NULL and LASTSCB is the last command to go out.
+		 */
+		cmp	NEXTSCB[1], SCB_LIST_NULL jne use_lastscb;
+
+		/*
+		 * Brute force walk.
+		 */
+		bmov	SCBPTR, WAITING_TID_HEAD, 2;
+		mvi	SEQINTCTL, INTVEC1DSL;
+		mvi	MODE_PTR, MK_MODE(M_CFG, M_CFG);
+		mov	A, MAXCMDCNT;
+		mvi	MODE_PTR, MK_MODE(M_SCSI, M_SCSI);
+		clr	SEQINTCTL;
+find_lastscb_loop:
+		dec	A;
+		test	A, 0xFF jz found_last_sent_scb;
+		bmov	SCBPTR, SCB_NEXT, 2;
+		jmp	find_lastscb_loop;
+use_lastscb:
+		bmov	SCBPTR, LASTSCB, 2;
+found_last_sent_scb:
+		bmov	CURRSCB, SCBPTR, 2;
+curscb_ww_done:
+	} else {
+		bmov	SCBPTR, CURRSCB, 2;
+	}
+
+	/*
+	 * Requeue any SCBs not sent, to the tail of the waiting Q.
+	 */
+	cmp	SCB_NEXT[1], SCB_LIST_NULL je select_out_list_done;
+
+	/*
+	 * We know that neither the per-TID list nor the list of
+	 * TIDs is empty.  Use this knowledge to our advantage.
+	 */
+	bmov	REG0, SCB_NEXT, 2;
+	bmov	SCBPTR, WAITING_TID_TAIL, 2;
+	bmov	SCB_NEXT2, REG0, 2;
+	bmov	WAITING_TID_TAIL, REG0, 2;
+	jmp	select_out_inc_tid_q;
+
+select_out_list_done:
+	/*
+	 * The whole list made it.  Just clear our TID's tail pointer
+	 * unless we were queued independently due to our need to
+	 * send a message.
+	 */
+	test	SCB_CONTROL, MK_MESSAGE jnz select_out_inc_tid_q;
+	shr	DINDEX, 3, SCB_SCSIID;
+	or	DINDEX, 1;	/* Want only the second byte */
+	mvi	DINDEX[1], ((WAITING_SCB_TAILS) >> 8);
+	mvi	DINDIR, SCB_LIST_NULL;
+select_out_inc_tid_q:
+	bmov	SCBPTR, WAITING_TID_HEAD, 2;
+	bmov	WAITING_TID_HEAD, SCB_NEXT2, 2;
+	cmp	WAITING_TID_HEAD[1], SCB_LIST_NULL jne . + 2;
+	mvi	WAITING_TID_TAIL[1], SCB_LIST_NULL;
+	bmov	SCBPTR, CURRSCB, 2;
+	mvi	CLRSINT0, CLRSELDO;
+	test	LQOSTAT2, LQOPHACHGOUTPKT jnz unexpected_nonpkt_phase;
+	test	LQOSTAT1, LQOPHACHGINPKT jnz unexpected_nonpkt_phase;
+
+	/*
+	 * If this is a packetized connection, return to our
+	 * idle_loop and let our interrupt handler deal with
+	 * any connection setup/teardown issues.  The only
+	 * exceptions are the case of MK_MESSAGE and task management
+	 * SCBs.
+	 */
+	if ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0) {
+		/*
+		 * In the A, the LQO manager transitions to LQOSTOP0 even if
+		 * we have selected out with ATN asserted and the target
+		 * REQs in a non-packet phase.
+		 */
+		test 	SCB_CONTROL, MK_MESSAGE jz select_out_no_message;
+		test	SCSISIGO, ATNO jnz select_out_non_packetized;
+select_out_no_message:
+	}
+	test	LQOSTAT2, LQOSTOP0 jz select_out_non_packetized;
+	test	SCB_TASK_MANAGEMENT, 0xFF jz idle_loop;
+	SET_SEQINTCODE(TASKMGMT_FUNC_COMPLETE)
+	jmp	idle_loop;
+
+select_out_non_packetized:
+	/* Non packetized request. */
+	and     SCSISEQ0, ~ENSELO;
+	if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
+		/*
+		 * Test to ensure that the bus has not
+		 * already gone free prior to clearing
+		 * any stale busfree status.  This avoids
+		 * a window whereby a busfree just after
+		 * a selection could be missed.
+		 */
+		test	SCSISIGI, BSYI jz . + 2;
+		mvi	CLRSINT1,CLRBUSFREE;
+		or	SIMODE1, ENBUSFREE;
+	}
+	mov	SAVED_SCSIID, SCB_SCSIID;
+	mov	SAVED_LUN, SCB_LUN;
+	mvi	SEQ_FLAGS, NO_CDB_SENT;
+END_CRITICAL;
+	or	SXFRCTL0, SPIOEN;
+
+	/*
+	 * As soon as we get a successful selection, the target
+	 * should go into the message out phase since we have ATN
+	 * asserted.
+	 */
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+
+	/*
+	 * Main loop for information transfer phases.  Wait for the
+	 * target to assert REQ before checking MSG, C/D and I/O for
+	 * the bus phase.
+	 */
+mesgin_phasemis:
+ITloop:
+	call	phase_lock;
+
+	mov	A, LASTPHASE;
+
+	test	A, ~P_DATAIN_DT	jz p_data;
+	cmp	A,P_COMMAND	je p_command;
+	cmp	A,P_MESGOUT	je p_mesgout;
+	cmp	A,P_STATUS	je p_status;
+	cmp	A,P_MESGIN	je p_mesgin;
+
+	SET_SEQINTCODE(BAD_PHASE)
+	jmp	ITloop;			/* Try reading the bus again. */
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+	test	SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay;
+	SET_SEQINTCODE(PROTO_VIOLATION)
+p_command_okay:
+	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
+		jnz p_command_allocate_fifo;
+	/*
+	 * Command retry.  Free our current FIFO and
+	 * re-allocate a FIFO so transfer state is
+	 * reset.
+	 */
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+	mvi	DFFSXFRCTL, RSTCHN|CLRSHCNT;
+	SET_MODE(M_SCSI, M_SCSI)
+p_command_allocate_fifo:
+	bmov	ALLOCFIFO_SCBPTR, SCBPTR, 2;
+	call	allocate_fifo;
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+	add	NONE, -17, SCB_CDB_LEN;
+	jnc	p_command_embedded;
+p_command_from_host:
+	bmov	HADDR[0], SCB_HOST_CDB_PTR, 9;
+	mvi	SG_CACHE_PRE, LAST_SEG;
+	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
+	jmp	p_command_xfer;
+p_command_embedded:
+	bmov	SHCNT[0], SCB_CDB_LEN,  1;
+	bmov	DFDAT, SCB_CDB_STORE, 16; 
+	mvi	DFCNTRL, SCSIEN;
+p_command_xfer:
+	and	SEQ_FLAGS, ~NO_CDB_SENT;
+	if ((ahd->features & AHD_FAST_CDB_DELIVERY) != 0) {
+		/*
+		 * To speed up CDB delivery in Rev B, all CDB acks
+		 * are "released" to the output sync as soon as the
+		 * command phase starts.  There is only one problem
+		 * with this approach.  If the target changes phase
+		 * before all data are sent, we have left over acks
+		 * that can go out on the bus in a data phase.  Due
+		 * to other chip contraints, this only happens if
+		 * the target goes to data-in, but if the acks go
+		 * out before we can test SDONE, we'll think that
+		 * the transfer has completed successfully.  Work
+		 * around this by taking advantage of the 400ns or
+		 * 800ns dead time between command phase and the REQ
+		 * of the new phase.  If the transfer has completed
+		 * successfully, SCSIEN should fall *long* before we
+		 * see a phase change.  We thus treat any phasemiss
+		 * that occurs before SCSIEN falls as an incomplete
+		 * transfer.
+		 */
+		test	SSTAT1, PHASEMIS jnz p_command_xfer_failed;
+		test	DFCNTRL, SCSIEN jnz . - 1;
+	} else {
+		test	DFCNTRL, SCSIEN jnz .;
+	}
+	/*
+	 * DMA Channel automatically disabled.
+	 * Don't allow a data phase if the command
+	 * was not fully transferred.
+	 */
+	test	SSTAT2, SDONE jnz ITloop;
+p_command_xfer_failed:
+	or	SEQ_FLAGS, NO_CDB_SENT;
+	jmp	ITloop;
+
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+p_status:
+	test	SEQ_FLAGS,NOT_IDENTIFIED jnz mesgin_proto_violation;
+p_status_okay:
+	mov	SCB_SCSI_STATUS, SCSIDAT;
+	or	SCB_CONTROL, STATUS_RCVD;
+	jmp	ITloop;
+
+/*
+ * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
+ * indentify message sequence and send it to the target.  The host may
+ * override this behavior by setting the MK_MESSAGE bit in the SCB
+ * control byte.  This will cause us to interrupt the host and allow
+ * it to handle the message phase completely on its own.  If the bit
+ * associated with this target is set, we will also interrupt the host,
+ * thereby allowing it to send a message on the next selection regardless
+ * of the transaction being sent.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the host to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+ *
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
+ */
+p_mesgout_retry:
+	/* Turn on ATN for the retry */
+	mvi	SCSISIGO, ATNO;
+p_mesgout:
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
+p_mesgout_identify:
+	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN;
+	test	SCB_CONTROL, DISCENB jnz . + 2;
+	and	SINDEX, ~DISCENB;
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_NONPACKET_TAG as the tag value.
+ */
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDAT, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDAT,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCBPTR jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to handle this message
+ * phase and any required retries.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	jmp	host_message_loop;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDAT, SINDEX;
+
+/*
+ * If the next bus phase after ATN drops is message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
+
+p_mesgout_done:
+	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
+	mov	LAST_MSG, MSG_OUT;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
+	jmp	ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+	/* read the 1st message byte */
+	mvi	ACCUM		call inb_first;
+
+	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
+	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
+	cmp	ALLZEROS,A		je mesgin_complete;
+	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
+	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
+	cmp	A,MSG_NOOP		je mesgin_done;
+
+/*
+ * Pushed message loop to allow the kernel to
+ * run it's own message state engine.  To avoid an
+ * extra nop instruction after signaling the kernel,
+ * we perform the phase_lock before checking to see
+ * if we should exit the loop and skip the phase_lock
+ * in the ITloop.  Performing back to back phase_locks
+ * shouldn't hurt, but why do it twice...
+ */
+host_message_loop:
+	call	phase_lock;	/* Benign the first time through. */
+	SET_SEQINTCODE(HOST_MSG_LOOP)
+	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop;
+	cmp	RETURN_1, CONT_MSG_LOOP_WRITE	jne . + 3;
+	mov	SCSIDAT, RETURN_2;
+	jmp	host_message_loop;
+	/* Must be CONT_MSG_LOOP_READ */
+	mov	NONE, SCSIDAT;	/* ACK Byte */
+	jmp	host_message_loop;
+
+mesgin_ign_wide_residue:
+	mov	SAVED_MODE, MODE_PTR;
+	SET_MODE(M_SCSI, M_SCSI)
+	shr	NEGOADDR, 4, SAVED_SCSIID;
+	mov	A, NEGCONOPTS;
+	RESTORE_MODE(SAVED_MODE)
+	test	A, WIDEXFER jz mesgin_reject;
+	/* Pull the residue byte */
+	mvi	REG0	call inb_next;
+	cmp	REG0, 0x01 jne mesgin_reject;
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
+	test	SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done;
+	SET_SEQINTCODE(IGN_WIDE_RES)
+	jmp	mesgin_done;
+
+mesgin_proto_violation:
+	SET_SEQINTCODE(PROTO_VIOLATION)
+	jmp	mesgin_done;
+mesgin_reject:
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+mesgin_done:
+	mov	NONE,SCSIDAT;		/*dummy read from latch to ACK*/
+	jmp	ITloop;
+
+#define INDEX_DISC_LIST(scsiid, lun)					\
+	and	A, 0xC0, scsiid;					\
+	or	SCBPTR, A, lun;						\
+	clr	SCBPTR[1];						\
+	and	SINDEX, 0x30, scsiid;					\
+	shr	SINDEX, 3;	/* Multiply by 2 */			\
+	add	SINDEX, (SCB_DISCONNECTED_LISTS & 0xFF);		\
+	mvi	SINDEX[1], ((SCB_DISCONNECTED_LISTS >> 8) & 0xFF)
+
+mesgin_identify:
+	/*
+	 * Determine whether a target is using tagged or non-tagged
+	 * transactions by first looking at the transaction stored in
+	 * the per-device, disconnected array.  If there is no untagged
+	 * transaction for this target, this must be a tagged transaction.
+	 */
+	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
+	INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN);
+	bmov	DINDEX, SINDEX, 2;
+	bmov	REG0, SINDIR, 2;
+	cmp	REG0[1], SCB_LIST_NULL je snoop_tag;
+	/* Untagged.  Clear the busy table entry and setup the SCB. */
+	bmov	DINDIR, ALLONES, 2;
+	bmov	SCBPTR, REG0, 2;
+	jmp	setup_SCB;
+
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB.  After receiving the tag, look for the SCB at SCB locations tag and
+ * tag + 256.
+ */
+snoop_tag:
+	if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x80;
+	}
+	mov	NONE, SCSIDAT;		/* ACK Identify MSG */
+	call	phase_lock;
+	if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x1;
+	}
+	cmp	LASTPHASE, P_MESGIN	jne not_found_ITloop;
+	if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x2;
+	}
+	cmp	SCSIBUS, MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+	clr	SCBPTR[1];
+	mvi	SCBPTR	call inb_next;	/* tag value */
+verify_scb:
+	test	SCB_CONTROL,DISCONNECTED jz verify_other_scb;
+	mov	A, SAVED_SCSIID;
+	cmp	SCB_SCSIID, A jne verify_other_scb;
+	mov	A, SAVED_LUN;
+	cmp	SCB_LUN, A je setup_SCB_disconnected;
+verify_other_scb:
+	xor	SCBPTR[1], 1;
+	test	SCBPTR[1], 0xFF jnz verify_scb;
+	jmp	not_found;
+
+/*
+ * Ensure that the SCB the tag points to is for
+ * an SCB transaction to the reconnecting target.
+ */
+setup_SCB:
+	if ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x10;
+	}
+	test	SCB_CONTROL,DISCONNECTED jz not_found;
+setup_SCB_disconnected:
+	and	SCB_CONTROL,~DISCONNECTED;
+	clr	SEQ_FLAGS;	/* make note of IDENTIFY */
+	test	SCB_SGPTR, SG_LIST_NULL jnz . + 3;
+	bmov	ALLOCFIFO_SCBPTR, SCBPTR, 2;
+	call	allocate_fifo;
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	mvi	HOST_MSG	call mk_mesg;
+	jmp	mesgin_done;
+
+not_found:
+	SET_SEQINTCODE(NO_MATCH)
+	jmp	mesgin_done;
+
+not_found_ITloop:
+	SET_SEQINTCODE(NO_MATCH)
+	jmp	ITloop;
+
+/*
+ * We received a "command complete" message.  Put the SCB on the complete
+ * queue and trigger a completion interrupt via the idle loop.  Before doing
+ * so, check to see if there
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
+ * process this information.  In the case of a non zero status byte, we 
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved.  If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command, requeue
+ * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
+ * RETURN_1 to SEND_SENSE.
+ */
+mesgin_complete:
+
+	/*
+	 * If ATN is raised, we still want to give the target a message.
+	 * Perhaps there was a parity error on this last message byte.
+	 * Either way, the target should take us to message out phase
+	 * and then attempt to complete the command again.  We should use a
+	 * critical section here to guard against a timeout triggering
+	 * for this command and setting ATN while we are still processing
+	 * the completion.
+	test	SCSISIGI, ATNI jnz mesgin_done;
+	 */
+
+	/*
+	 * If we are identified and have successfully sent the CDB,
+	 * any status will do.  Optimize this fast path.
+	 */
+	test	SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation;
+	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted;
+
+	/*
+	 * If the target never sent an identify message but instead went
+	 * to mesgin to give an invalid message, let the host abort us.
+	 */
+	test	SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
+
+	/*
+	 * If we recevied good status but never successfully sent the
+	 * cdb, abort the command.
+	 */
+	test	SCB_SCSI_STATUS,0xff	jnz complete_accepted;
+	test	SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation;
+complete_accepted:
+
+	/*
+	 * See if we attempted to deliver a message but the target ingnored us.
+	 */
+	test	SCB_CONTROL, MK_MESSAGE jz complete_nomsg;
+	SET_SEQINTCODE(MKMSG_FAILED)
+complete_nomsg:
+	call	queue_scb_completion;
+	jmp	await_busfree;
+
+freeze_queue:
+	/* Cancel any pending select-out. */
+	test	SSTAT0, SELDO|SELINGO jnz . + 2;
+	and	SCSISEQ0, ~ENSELO;
+	mov	ACCUM_SAVE, A;
+	clr	A;
+	add	QFREEZE_COUNT, 1;
+	adc	QFREEZE_COUNT[1], A;
+	or	SEQ_FLAGS2, SELECTOUT_QFROZEN;
+	mov	A, ACCUM_SAVE ret;
+
+/*
+ * Complete the current FIFO's SCB if data for this same
+ * SCB is not transferring in the other FIFO.
+ */
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+pkt_complete_scb_if_fifos_idle:
+	bmov	ARG_1, SCBPTR, 2;
+	mvi	DFFSXFRCTL, CLRCHN;
+	SET_MODE(M_SCSI, M_SCSI)
+	bmov	SCBPTR, ARG_1, 2;
+	test	SCB_FIFO_USE_COUNT, 0xFF jnz return;
+queue_scb_completion:
+	test	SCB_SCSI_STATUS,0xff	jnz bad_status;
+	/*
+	 * Check for residuals
+	 */
+	test	SCB_SGPTR, SG_LIST_NULL jnz complete;	/* No xfer */
+	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
+	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
+complete:
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
+	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+bad_status:
+	cmp	SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb;
+	call	freeze_queue;
+upload_scb:
+	/*
+	 * Restore SCB TAG since we reuse this field
+	 * in the sequencer.  We don't want to corrupt
+	 * it on the host.
+	 */
+	bmov	SCB_TAG, SCBPTR, 2;
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2;
+	bmov	COMPLETE_DMA_SCB_HEAD, SCBPTR, 2;
+	or	SCB_SGPTR, SG_STATUS_VALID ret;
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.  If this is an untagged transaction
+ * store the SCB id for it in our untagged target table for lookup on
+ * a reselction.
+ */
+mesgin_disconnect:
+	/*
+	 * If ATN is raised, we still want to give the target a message.
+	 * Perhaps there was a parity error on this last message byte
+	 * or we want to abort this command.  Either way, the target
+	 * should take us to message out phase and then attempt to
+	 * disconnect again.
+	 * XXX - Wait for more testing.
+	test	SCSISIGI, ATNI jnz mesgin_done;
+	 */
+	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT
+		jnz mesgin_proto_violation;
+	or	SCB_CONTROL,DISCONNECTED;
+	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
+queue_disc_scb:
+	bmov	REG0, SCBPTR, 2;
+	INDEX_DISC_LIST(SAVED_SCSIID, SAVED_LUN);
+	bmov	DINDEX, SINDEX, 2;
+	bmov	DINDIR, REG0, 2;
+	bmov	SCBPTR, REG0, 2;
+	/* FALLTHROUGH */
+await_busfree:
+	and	SIMODE1, ~ENBUSFREE;
+	if ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0) {
+		/*
+		 * In the BUSFREEREV_BUG case, the
+		 * busfree status was cleared at the
+		 * beginning of the connection.
+		 */
+		mvi	CLRSINT1,CLRBUSFREE;
+	}
+	mov	NONE, SCSIDAT;		/* Ack the last byte */
+	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
+		jnz await_busfree_not_m_dff;
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+await_busfree_clrchn:
+	mvi	DFFSXFRCTL, CLRCHN;
+await_busfree_not_m_dff:
+	call	clear_target_state;
+	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	test	SSTAT1, BUSFREE jnz idle_loop;
+	SET_SEQINTCODE(MISSED_BUSFREE)
+
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ * Ack the message as soon as possible.
+ */
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+mesgin_sdptrs:
+	mov	NONE,SCSIDAT;		/*dummy read from latch to ACK*/
+	test	SEQ_FLAGS, DPHASE	jz ITloop;
+	call	save_pointers;
+	jmp	ITloop;
+
+save_pointers:
+	/*
+	 * If we are asked to save our position at the end of the
+	 * transfer, just mark us at the end rather than perform a
+	 * full save.
+	 */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz save_pointers_full;
+	or	SCB_SGPTR, SG_LIST_NULL ret;
+
+save_pointers_full:
+	/*
+	 * The SCB_DATAPTR becomes the current SHADDR.
+	 * All other information comes directly from our residual
+	 * state.
+	 */
+	bmov	SCB_DATAPTR, SHADDR, 8;
+	bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8 ret;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.  We also reset/reallocate the FIFO to make
+ * sure we have a clean start for the next data or command phase.
+ */
+mesgin_rdptrs:
+	and	SEQ_FLAGS, ~DPHASE;
+	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1)) jnz msgin_rdptrs_get_fifo;
+	mvi	DFFSXFRCTL, RSTCHN|CLRSHCNT;
+	SET_MODE(M_SCSI, M_SCSI)
+msgin_rdptrs_get_fifo:
+	call	allocate_fifo;
+	jmp	mesgin_done;
+
+clear_target_state:
+	mvi	LASTPHASE, P_BUSFREE;
+	/* clear target specific flags */
+	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
+
+phase_lock:     
+	if ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0) {
+		/*
+		 * Don't ignore persistent REQ assertions just because
+		 * they were asserted within the bus settle delay window.
+		 * This allows us to tolerate devices like the GEM318
+		 * that violate the SCSI spec.  We are careful not to
+		 * count REQ while we are waiting for it to fall during
+		 * an async phase due to our asserted ACK.  Each
+		 * sequencer instruction takes ~25ns, so the REQ must
+		 * last at least 100ns in order to be counted as a true
+		 * REQ.
+		 */
+		test	SCSIPHASE, 0xFF jnz phase_locked;
+		test	SCSISIGI, ACKI jnz phase_lock;
+		test	SCSISIGI, REQI jz phase_lock;
+		test	SCSIPHASE, 0xFF jnz phase_locked;
+		test	SCSISIGI, ACKI jnz phase_lock;
+		test	SCSISIGI, REQI jz phase_lock;
+phase_locked:
+	} else {
+		test	SCSIPHASE, 0xFF jz .;
+	}
+	test	SSTAT1, SCSIPERR jnz phase_lock;
+phase_lock_latch_phase:
+	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * An ACK is not sent on input from the target until SCSIDATL is read from.
+ * So we wait until SCSIDATL is latched (the usual way), then read the data
+ * byte directly off the bus using SCSIBUSL.  When we have pulled the ATN
+ * line, or we just want to acknowledge the byte, then we do a dummy read
+ * from SCISDATL.  The SCSI spec guarantees that the target will hold the
+ * data byte on the bus until we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+inb_next:
+	mov	NONE,SCSIDAT;		/*dummy read from latch to ACK*/
+inb_next_wait:
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SCSIPHASE, 0xFF jz .;
+	test	SSTAT1, SCSIPERR jnz inb_next_wait;
+inb_next_check_phase:
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+	clr	DINDEX[1];
+	mov	DINDEX,SINDEX;
+	mov	DINDIR,SCSIBUS	ret;		/*read byte directly from bus*/
+inb_last:
+	mov	NONE,SCSIDAT ret;		/*dummy read from latch to ACK*/
+
+mk_mesg:
+	mvi	SCSISIGO, ATNO;
+	mov	MSG_OUT,SINDEX ret;
+
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+disable_ccsgen:
+	test	SG_STATE, FETCH_INPROG jz disable_ccsgen_fetch_done;
+	clr	CCSGCTL;
+disable_ccsgen_fetch_done:
+	clr	SG_STATE ret;
+
+service_fifo:
+	/*
+	 * Do we have any prefetch left???
+	 */
+	test	SG_STATE, SEGS_AVAIL jnz idle_sg_avail;
+
+	/*
+	 * Can this FIFO have access to the S/G cache yet?
+	 */
+	test	CCSGCTL, SG_CACHE_AVAIL jz return;
+
+	/* Did we just finish fetching segs? */
+	test	CCSGCTL, CCSGDONE jnz idle_sgfetch_complete;
+
+	/* Are we actively fetching segments? */
+	test	CCSGCTL, CCSGENACK jnz return;
+
+	/*
+	 * We fetch a "cacheline aligned" and sized amount of data
+	 * so we don't end up referencing a non-existant page.
+	 * Cacheline aligned is in quotes because the kernel will
+	 * set the prefetch amount to a reasonable level if the
+	 * cacheline size is unknown.
+	 */
+	bmov	SGHADDR, SCB_RESIDUAL_SGPTR, 4;
+	mvi	SGHCNT, SG_PREFETCH_CNT;
+	if ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0) {
+		/*
+		 * Need two instruction between "touches" of SGHADDR.
+		 */
+		nop;
+	}
+	and	SGHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
+	mvi	CCSGCTL, CCSGEN|CCSGRESET;
+	or	SG_STATE, FETCH_INPROG ret;
+idle_sgfetch_complete:
+	/*
+	 * Guard against SG_CACHE_AVAIL activating during sg fetch
+	 * request in the other FIFO.
+	 */
+	test	SG_STATE, FETCH_INPROG jz return;
+	clr	CCSGCTL;
+	and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
+	mvi	SG_STATE, SEGS_AVAIL|LOADING_NEEDED;
+idle_sg_avail:
+	/* Does the hardware have space for another SG entry? */
+	test	DFSTATUS, PRELOAD_AVAIL jz return;
+	/*
+	 * On the A, preloading a segment before HDMAENACK
+	 * comes true can clobber the shaddow address of the
+	 * first segment in the S/G FIFO.  Wait until it is
+	 * safe to proceed.
+	 */
+	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0) {
+		test	DFCNTRL, HDMAENACK jz return;
+	}
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+		bmov	HADDR, CCSGRAM, 8;
+	} else {
+		bmov 	HADDR, CCSGRAM, 4;
+	}
+	bmov	HCNT, CCSGRAM, 3;
+	bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+	if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
+		and	HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3];
+	}
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+		/* Skip 4 bytes of pad. */
+		add	CCSGADDR, 4;
+	}
+sg_advance:
+	clr	A;			/* add sizeof(struct scatter) */
+	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
+	adc	SCB_RESIDUAL_SGPTR[1],A;
+	adc	SCB_RESIDUAL_SGPTR[2],A;
+	adc	SCB_RESIDUAL_SGPTR[3],A;
+	mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
+	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3;
+	or	SINDEX, LAST_SEG;
+	clr	SG_STATE;
+	mov	SG_CACHE_PRE, SINDEX;
+	if ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0) {
+		/*
+		 * Use SCSIENWRDIS so that SCSIEN is never
+		 * modified by this operation.
+		 */
+		or	DFCNTRL, PRELOADEN|HDMAEN|SCSIENWRDIS;
+	} else {
+		or	DFCNTRL, PRELOADEN|HDMAEN;
+	}
+	/*
+	 * Do we have another segment in the cache?
+	 */
+	add	NONE, SG_PREFETCH_CNT_LIMIT, CCSGADDR;
+	jnc	return;
+	and	SG_STATE, ~SEGS_AVAIL ret;
+
+/*
+ * Initialize the DMA address and counter from the SCB.
+ */
+load_first_seg:
+	bmov	HADDR, SCB_DATAPTR, 11;
+	and	REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0];
+	test	SCB_DATACNT[3], SG_LAST_SEG jz . + 2;
+	or	REG_ISR, LAST_SEG;
+	mov	SG_CACHE_PRE, REG_ISR;
+	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
+	/*
+	 * Since we've are entering a data phase, we will
+	 * rely on the SCB_RESID* fields.  Initialize the
+	 * residual and clear the full residual flag.
+	 */
+	and	SCB_SGPTR[0], ~SG_FULL_RESID;
+	bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
+	/* If we need more S/G elements, tell the idle loop */
+	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz . + 2;
+	mvi	SG_STATE, LOADING_NEEDED ret;
+	clr	SG_STATE ret;
+
+p_data_handle_xfer:
+	call	setjmp;
+	test	SG_STATE, LOADING_NEEDED jnz service_fifo;
+p_data_clear_handler:
+	or	LONGJMP_ADDR[1], INVALID_ADDR ret;
+
+p_data:
+	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT	jz p_data_allowed;
+	SET_SEQINTCODE(PROTO_VIOLATION)
+p_data_allowed:
+ 
+	test	SEQ_FLAGS, DPHASE	jz data_phase_initialize;
+
+	/*
+	 * If we re-enter the data phase after going through another
+	 * phase, our transfer location has almost certainly been
+	 * corrupted by the interveining, non-data, transfers.  Ask
+	 * the host driver to fix us up based on the transfer residual
+	 * unless we already know that we should be bitbucketing.
+	 */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;
+	SET_SEQINTCODE(PDATA_REINIT)
+	jmp	data_phase_inbounds;
+
+p_data_bitbucket:
+	/*
+	 * Turn on `Bit Bucket' mode, wait until the target takes
+	 * us to another phase, and then notify the host.
+	 */
+	mov	SAVED_MODE, MODE_PTR;
+	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
+		jnz bitbucket_not_m_dff;
+	/*
+	 * Ensure that any FIFO contents are cleared out and the
+	 * FIFO free'd prior to starting the BITBUCKET.  BITBUCKET
+	 * doesn't discard data already in the FIFO.
+	 */
+	mvi	DFFSXFRCTL, RSTCHN|CLRSHCNT;
+	SET_MODE(M_SCSI, M_SCSI)
+bitbucket_not_m_dff:
+	or	SXFRCTL1,BITBUCKET;
+	/* Wait for non-data phase. */
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz .;
+	and	SXFRCTL1, ~BITBUCKET;
+	RESTORE_MODE(SAVED_MODE)
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+	SET_SEQINTCODE(DATA_OVERRUN)
+	jmp	ITloop;
+
+data_phase_initialize:
+	test	SCB_SGPTR[0], SG_LIST_NULL jnz p_data_bitbucket;
+	call	load_first_seg;
+data_phase_inbounds:
+	/* We have seen a data phase at least once. */
+	or	SEQ_FLAGS, DPHASE;
+	mov	SAVED_MODE, MODE_PTR;
+	test	SG_STATE, LOADING_NEEDED jz data_group_dma_loop;
+	call	p_data_handle_xfer;
+data_group_dma_loop:
+	/*
+	 * The transfer is complete if either the last segment
+	 * completes or the target changes phase.  Both conditions
+	 * will clear SCSIEN.
+	 */
+	call	idle_loop_service_fifos;
+	call	idle_loop_cchan;
+	call	idle_loop_gsfifo;
+	RESTORE_MODE(SAVED_MODE)
+	test	DFCNTRL, SCSIEN jnz data_group_dma_loop;
+
+data_group_dmafinish:
+	/*
+	 * The transfer has terminated either due to a phase
+	 * change, and/or the completion of the last segment.
+	 * We have two goals here.  Do as much other work
+	 * as possible while the data fifo drains on a read
+	 * and respond as quickly as possible to the standard
+	 * messages (save data pointers/disconnect and command
+	 * complete) that usually follow a data phase.
+	 */
+	call	calc_residual;
+
+	/*
+	 * Go ahead and shut down the DMA engine now.
+	 */
+	test	DFCNTRL, DIRECTION jnz data_phase_finish;
+data_group_fifoflush:
+	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
+		or	DFCNTRL, FIFOFLUSH;
+	}
+	/*
+	 * We have enabled the auto-ack feature.  This means
+	 * that the controller may have already transferred
+	 * some overrun bytes into the data FIFO and acked them
+	 * on the bus.  The only way to detect this situation is
+	 * to wait for LAST_SEG_DONE to come true on a completed
+	 * transfer and then test to see if the data FIFO is
+	 * non-empty.  We know there is more data yet to transfer
+	 * if SG_LIST_NULL is not yet set, thus there cannot be
+	 * an overrun.
+	 */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_finish;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
+	test	DFSTATUS, FIFOEMP jnz data_phase_finish;
+	/* Overrun */
+	jmp	p_data;
+data_phase_finish:
+	/*
+	 * If the target has left us in data phase, loop through
+	 * the dma code again.  We will only loop if there is a
+	 * data overrun.  
+	 */
+	if ((ahd->flags & AHD_TARGETROLE) != 0) {
+		test	SSTAT0, TARGET jnz data_phase_done;
+	}
+	if ((ahd->flags & AHD_INITIATORROLE) != 0) {
+		test	SSTAT1, REQINIT jz .;
+		test	SCSIPHASE, DATA_PHASE_MASK jnz p_data;
+	}
+
+data_phase_done:
+	/* Kill off any pending prefetch */
+	call	disable_ccsgen;
+	or 	LONGJMP_ADDR[1], INVALID_ADDR;
+
+	if ((ahd->flags & AHD_TARGETROLE) != 0) {
+		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
+		/*
+		and	SEQ_FLAGS, ~DPHASE_PENDING;
+		 * For data-in phases, wait for any pending acks from the
+		 * initiator before changing phase.  We only need to
+		 * send Ignore Wide Residue messages for data-in phases.
+		test	DFCNTRL, DIRECTION jz target_ITloop;
+		test	SSTAT1, REQINIT	jnz .;
+		test	SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop;
+		SET_MODE(M_SCSI, M_SCSI)
+		test	NEGCONOPTS, WIDEXFER jz target_ITloop;
+		 */
+		/*
+		 * Issue an Ignore Wide Residue Message.
+		mvi	P_MESGIN|BSYO call change_phase;
+		mvi	MSG_IGN_WIDE_RESIDUE call target_outb;
+		mvi	1 call target_outb;
+		jmp	target_ITloop;
+		 */
+	} else {
+		jmp	ITloop;
+	}
+
+/*
+ * We assume that, even though data may still be
+ * transferring to the host, that the SCSI side of
+ * the DMA engine is now in a static state.  This
+ * allows us to update our notion of where we are
+ * in this transfer.
+ *
+ * If, by chance, we stopped before being able
+ * to fetch additional segments for this transfer,
+ * yet the last S/G was completely exhausted,
+ * call our idle loop until it is able to load
+ * another segment.  This will allow us to immediately
+ * pickup on the next segment on the next data phase.
+ *
+ * If we happened to stop on the last segment, then
+ * our residual information is still correct from
+ * the idle loop and there is no need to perform
+ * any fixups.
+ */
+residual_before_last_seg:
+	test    MDFFSTAT, SHVALID	jnz sgptr_fixup;
+	/*
+	 * Can never happen from an interrupt as the packetized
+	 * hardware will only interrupt us once SHVALID or
+	 * LAST_SEG_DONE.
+	 */
+	call	idle_loop_service_fifos;
+	RESTORE_MODE(SAVED_MODE)
+	/* FALLTHROUGH */
+calc_residual:
+	test	SG_CACHE_SHADOW, LAST_SEG jz residual_before_last_seg;
+	/* Record if we've consumed all S/G entries */
+	test	MDFFSTAT, SHVALID	jz . + 2;
+	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
+	or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL ret;
+
+sgptr_fixup:
+	/*
+	 * Fixup the residual next S/G pointer.  The S/G preload
+	 * feature of the chip allows us to load two elements
+	 * in addition to the currently active element.  We
+	 * store the bottom byte of the next S/G pointer in
+	 * the SG_CACHE_PTR register so we can restore the
+	 * correct value when the DMA completes.  If the next
+	 * sg ptr value has advanced to the point where higher
+	 * bytes in the address have been affected, fix them
+	 * too.
+	 */
+	test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
+	test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
+	add	SCB_RESIDUAL_SGPTR[1], -1;
+	adc	SCB_RESIDUAL_SGPTR[2], -1; 
+	adc	SCB_RESIDUAL_SGPTR[3], -1;
+sgptr_fixup_done:
+	and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
+	clr	SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */
+	bmov	SCB_RESIDUAL_DATACNT, SHCNT, 3 ret;
+
+export timer_isr:
+	call	issue_cmdcmplt;
+	mvi	CLRSEQINTSTAT, CLRSEQ_SWTMRTO;
+	if ((ahd->bugs & AHD_SET_MODE_BUG) != 0) {
+		/*
+		 * In H2A4, the mode pointer is not saved
+		 * for intvec2, but is restored on iret.
+		 * This can lead to the restoration of a
+		 * bogus mode ptr.  Manually clear the
+		 * intmask bits and do a normal return
+		 * to compensate.
+		 */
+		and	SEQINTCTL, ~(INTMASK2|INTMASK1) ret;
+	} else {
+		or	SEQINTCTL, IRET ret;
+	}
+
+export seq_isr:
+	if ((ahd->features & AHD_RTI) == 0) {
+		/*
+		 * On RevA Silicon, if the target returns us to data-out
+		 * after we have already trained for data-out, it is
+		 * possible for us to transition the free running clock to
+		 * data-valid before the required 100ns P1 setup time (8 P1
+		 * assertions in fast-160 mode).  This will only happen if
+		 * this L-Q is a continuation of a data transfer for which
+		 * we have already prefetched data into our FIFO (LQ/Data
+		 * followed by LQ/Data for the same write transaction).
+		 * This can cause some target implementations to miss the
+		 * first few data transfers on the bus.  We detect this
+		 * situation by noticing that this is the first data transfer
+		 * after an LQ (LQIWORKONLQ true), that the data transfer is
+		 * a continuation of a transfer already setup in our FIFO
+		 * (SAVEPTRS interrupt), and that the transaction is a write
+		 * (DIRECTION set in DFCNTRL). The delay is performed by
+		 * disabling SCSIEN until we see the first REQ from the
+		 * target.
+		 * 
+		 * First instruction in an ISR cannot be a branch on
+		 * Rev A.  Snapshot LQISTAT2 so the status is not missed
+		 * and deffer the test by one instruction.
+		 */
+		mov	REG_ISR, LQISTAT2;
+		test	REG_ISR, LQIWORKONLQ jz main_isr;
+		test	SEQINTSRC, SAVEPTRS  jz main_isr;
+		test	LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo;
+		/*
+		 * Switch to the active FIFO after clearing the snapshot
+		 * savepointer in the current FIFO.  We do this so that
+		 * a pending CTXTDONE or SAVEPTR is visible in the active
+		 * FIFO.  This status is the only way we can detect if we
+		 * have lost the race (e.g. host paused us) and our attepts
+		 * to disable the channel occurred after all REQs were
+		 * already seen and acked (REQINIT never comes true).
+		 */
+		mvi	DFFSXFRCTL, CLRCHN;
+		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
+		test	DFCNTRL, DIRECTION jz interrupt_return;
+		and	DFCNTRL, ~SCSIEN;
+snapshot_wait_data_valid:
+		test	SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid;
+		test	SSTAT1, REQINIT	jz snapshot_wait_data_valid;
+snapshot_data_valid:
+		or	DFCNTRL, SCSIEN;
+		or	SEQINTCTL, IRET ret;
+snapshot_saveptr:
+		mvi	DFFSXFRCTL, CLRCHN;
+		or	SEQINTCTL, IRET ret;
+main_isr:
+	}
+	test	SEQINTSRC, CFG4DATA	jnz cfg4data_intr;
+	test	SEQINTSRC, CFG4ISTAT	jnz cfg4istat_intr;
+	test	SEQINTSRC, SAVEPTRS	jnz saveptr_intr;
+	test	SEQINTSRC, CFG4ICMD	jnz cfg4icmd_intr;
+	SET_SEQINTCODE(INVALID_SEQINT)
+
+/*
+ * There are two types of save pointers interrupts:
+ * The first is a snapshot save pointers where the current FIFO is not
+ * active and contains a snapshot of the current poniter information.
+ * This happens between packets in a stream for a single L_Q.  Since we
+ * are not performing a pointer save, we can safely clear the channel
+ * so it can be used for other transactions.  On RTI capable controllers,
+ * where snapshots can, and are, disabled, the code to handle this type
+ * of snapshot is not active.
+ *
+ * The second case is a save pointers on an active FIFO which occurs
+ * if the target changes to a new L_Q or busfrees/QASes and the transfer
+ * has a residual.  This should occur coincident with a ctxtdone.  We
+ * disable the interrupt and allow our active routine to handle the
+ * save.
+ */
+saveptr_intr:
+	if ((ahd->features & AHD_RTI) == 0) {
+		test	LONGJMP_ADDR[1], INVALID_ADDR jnz snapshot_saveptr;
+	}
+saveptr_active_fifo:
+	and	SEQIMODE, ~ENSAVEPTRS;
+	or	SEQINTCTL, IRET ret;
+
+cfg4data_intr:
+	test	SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count;
+	call	load_first_seg;
+	call	pkt_handle_xfer;
+	inc	SCB_FIFO_USE_COUNT;
+interrupt_return:
+	or	SEQINTCTL, IRET ret;
+
+cfg4istat_intr:
+	call	freeze_queue;
+	add	NONE, -13, SCB_CDB_LEN;
+	jnc	cfg4istat_have_sense_addr;
+	test	SCB_CDB_LEN, SCB_CDB_LEN_PTR jnz cfg4istat_have_sense_addr;
+	/*
+	 * Host sets up address/count and enables transfer.
+	 */
+	SET_SEQINTCODE(CFG4ISTAT_INTR)
+	jmp	cfg4istat_setup_handler;
+cfg4istat_have_sense_addr:
+	bmov	HADDR, SCB_SENSE_BUSADDR, 4;
+	mvi	HCNT[1], (AHD_SENSE_BUFSIZE >> 8);
+	mvi	SG_CACHE_PRE, LAST_SEG;
+	mvi	DFCNTRL, PRELOADEN|SCSIEN|HDMAEN;
+cfg4istat_setup_handler:
+	/*
+	 * Status pkt is transferring to host.
+	 * Wait in idle loop for transfer to complete.
+	 * If a command completed before an attempted
+	 * task management function completed, notify the host.
+	 */
+	test	SCB_TASK_MANAGEMENT, 0xFF jz cfg4istat_no_taskmgmt_func;
+	SET_SEQINTCODE(TASKMGMT_CMD_CMPLT_OKAY)
+cfg4istat_no_taskmgmt_func:
+	call	pkt_handle_status;
+	or	SEQINTCTL, IRET ret;
+
+cfg4icmd_intr:
+	/*
+	 * In the case of DMAing a CDB from the host, the normal
+	 * CDB buffer is formatted with an 8 byte address followed
+	 * by a 1 byte count.
+	 */
+	bmov	HADDR[0], SCB_HOST_CDB_PTR, 9;
+	mvi	SG_CACHE_PRE, LAST_SEG;
+	mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN);
+	call	pkt_handle_cdb;
+	or	SEQINTCTL, IRET ret;
+
+/*
+ * See if the target has gone on in this context creating an
+ * overrun condition.  For the write case, the hardware cannot
+ * ack bytes until data are provided.  So, if the target begins
+ * another  packet without changing contexts, implying we are
+ * not sitting on a packet boundary, we are in an overrun
+ * situation.  For the read case, the hardware will continue to
+ * ack bytes into the FIFO, and may even ack the last overrun packet
+ * into the FIFO.   If the FIFO should become non-empty, we are in
+ * a read overrun case.
+ */
+#define check_overrun							\
+	/* Not on a packet boundary. */					\
+	test 	MDFFSTAT, DLZERO jz pkt_handle_overrun;			\
+	test	DFSTATUS, FIFOEMP jz pkt_handle_overrun
+
+pkt_handle_xfer:
+	test	SG_STATE, LOADING_NEEDED jz pkt_last_seg;
+	call	setjmp;
+	test	SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
+	test	SCSISIGO, ATNO jnz . + 2;
+	test	SSTAT2, NONPACKREQ jz pkt_service_fifo;
+	/*
+	 * Defer handling of this NONPACKREQ until we
+	 * can be sure it pertains to this FIFO.  SAVEPTRS
+	 * will not be asserted if the NONPACKREQ is for us,
+	 * so we must simulate it if shaddow is valid.  If
+	 * shaddow is not valid, keep running this FIFO until we
+	 * have satisfied the transfer by loading segments and
+	 * waiting for either shaddow valid or last_seg_done.
+	 */
+	test	MDFFSTAT, SHVALID jnz pkt_saveptrs;
+pkt_service_fifo:
+	test	SG_STATE, LOADING_NEEDED jnz service_fifo;
+pkt_last_seg:
+	call	setjmp;
+	test	SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_last_seg_done;
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
+	test	SCSISIGO, ATNO jnz . + 2;
+	test	SSTAT2, NONPACKREQ jz return;
+	test	MDFFSTAT, SHVALID jz return;
+	/* FALLTHROUGH */
+
+/*
+ * Either a SAVEPTRS interrupt condition is pending for this FIFO
+ * or we have a pending NONPACKREQ for this FIFO.  We differentiate
+ * between the two by capturing the state of the SAVEPTRS interrupt
+ * prior to clearing this status and executing the common code for
+ * these two cases.
+ */
+pkt_saveptrs:
+BEGIN_CRITICAL;
+	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
+		or	DFCNTRL, FIFOFLUSH;
+	}
+	mov	REG0, SEQINTSRC;
+	call	calc_residual;
+	call	save_pointers;
+	mvi	CLRSEQINTSRC, CLRSAVEPTRS;
+	call	disable_ccsgen;
+	or	SEQIMODE, ENSAVEPTRS;
+	test	DFCNTRL, DIRECTION jnz pkt_saveptrs_check_status;
+	test	DFSTATUS, FIFOEMP jnz pkt_saveptrs_check_status;
+	/*
+	 * Keep a handler around for this FIFO until it drains
+	 * to the host to guarantee that we don't complete the
+	 * command to the host before the data arrives.
+	 */
+pkt_saveptrs_wait_fifoemp:
+	call	setjmp;
+	test	DFSTATUS, FIFOEMP jz return;
+pkt_saveptrs_check_status:
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	test	REG0, SAVEPTRS jz unexpected_nonpkt_phase;
+	dec	SCB_FIFO_USE_COUNT;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+END_CRITICAL;
+
+/*
+ * LAST_SEG_DONE status has been seen in the current FIFO.
+ * This indicates that all of the allowed data for this
+ * command has transferred across the SCSI and host buses.
+ * Check for overrun and see if we can complete this command.
+ */
+pkt_last_seg_done:
+BEGIN_CRITICAL;
+	/*
+	 * Mark transfer as completed.
+	 */
+	or	SCB_SGPTR, SG_LIST_NULL;
+
+	/*
+	 * Wait for the current context to finish to verify that
+	 * no overrun condition has occurred.
+	 */
+	test	SEQINTSRC, CTXTDONE jnz pkt_ctxt_done;
+	call	setjmp;
+pkt_wait_ctxt_done_loop:
+	test	SEQINTSRC, CTXTDONE jnz pkt_ctxt_done;
+	/*
+	 * A sufficiently large overrun or a NONPACKREQ may
+	 * prevent CTXTDONE from ever asserting, so we must
+	 * poll for these statuses too.
+	 */
+	check_overrun;
+	test	SSTAT2, NONPACKREQ jz return;
+	test	SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
+	/* FALLTHROUGH */
+
+pkt_ctxt_done:
+	check_overrun;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	/*
+	 * If status has been received, it is safe to skip
+	 * the check to see if another FIFO is active because
+	 * LAST_SEG_DONE has been observed.  However, we check
+	 * the FIFO anyway since it costs us only one extra
+	 * instruction to leverage common code to perform the
+	 * SCB completion.
+	 */
+	dec	SCB_FIFO_USE_COUNT;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+END_CRITICAL;
+
+/*
+ * Must wait until CDB xfer is over before issuing the
+ * clear channel.
+ */
+pkt_handle_cdb:
+	call	setjmp;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz return;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+
+/*
+ * Watch over the status transfer.  Our host sense buffer is
+ * large enough to take the maximum allowed status packet.
+ * None-the-less, we must still catch and report overruns to
+ * the host.  Additionally, properly catch unexpected non-packet
+ * phases that are typically caused by CRC errors in status packet
+ * transmission.
+ */
+pkt_handle_status:
+	call	setjmp;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun;
+	test	SEQINTSRC, CTXTDONE jz pkt_status_check_nonpackreq;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun;
+pkt_status_IU_done:
+	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
+		or	DFCNTRL, FIFOFLUSH;
+	}
+	test	DFSTATUS, FIFOEMP jz return;
+BEGIN_CRITICAL;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	mvi	SCB_SCSI_STATUS, STATUS_PKT_SENSE;
+	or	SCB_CONTROL, STATUS_RCVD;
+	jmp	pkt_complete_scb_if_fifos_idle;
+END_CRITICAL;
+pkt_status_check_overrun:
+	/*
+	 * Status PKT overruns are uncerimoniously recovered with a
+	 * bus reset.  If we've overrun, let the host know so that
+	 * recovery can be performed.
+	 *
+	 * LAST_SEG_DONE has been observed.  If either CTXTDONE or
+	 * a NONPACKREQ phase change have occurred and the FIFO is
+	 * empty, there is no overrun.
+	 */
+	test	DFSTATUS, FIFOEMP jz pkt_status_report_overrun;
+	test	SEQINTSRC, CTXTDONE jz . + 2;
+	test	DFSTATUS, FIFOEMP jnz pkt_status_IU_done;
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz return;
+	test	DFSTATUS, FIFOEMP jnz pkt_status_check_nonpackreq;
+pkt_status_report_overrun:
+	SET_SEQINTCODE(STATUS_OVERRUN)
+	/* SEQUENCER RESTARTED */
+pkt_status_check_nonpackreq:
+	/*
+	 * CTXTDONE may be held off if a NONPACKREQ is associated with
+	 * the current context.  If a NONPACKREQ is observed, decide
+	 * if it is for the current context.  If it is for the current
+	 * context, we must defer NONPACKREQ processing until all data
+	 * has transferred to the host.
+	 */
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz return;
+	test	SCSISIGO, ATNO jnz . + 2;
+	test	SSTAT2, NONPACKREQ jz return;
+	test	SEQINTSRC, CTXTDONE jnz pkt_status_IU_done;
+	test	DFSTATUS, FIFOEMP jz return;
+	/*
+	 * The unexpected nonpkt phase handler assumes that any
+	 * data channel use will have a FIFO reference count.  It
+	 * turns out that the status handler doesn't need a refernce
+	 * count since the status received flag, and thus completion
+	 * processing, cannot be set until the handler is finished.
+	 * We increment the count here to make the nonpkt handler
+	 * happy.
+	 */
+	inc	SCB_FIFO_USE_COUNT;
+	/* FALLTHROUGH */
+
+/*
+ * Nonpackreq is a polled status.  It can come true in three situations:
+ * we have received an L_Q, we have sent one or more L_Qs, or there is no
+ * L_Q context associated with this REQ (REQ occurs immediately after a
+ * (re)selection).  Routines that know that the context responsible for this
+ * nonpackreq call directly into unexpected_nonpkt_phase.  In the case of the
+ * top level idle loop, we exhaust all active contexts prior to determining that
+ * we simply do not have the full I_T_L_Q for this phase.
+ */
+unexpected_nonpkt_phase_find_ctxt:
+	/*
+	 * This nonpackreq is most likely associated with one of the tags
+	 * in a FIFO or an outgoing LQ.  Only treat it as an I_T only
+	 * nonpackreq if we've cleared out the FIFOs and handled any
+	 * pending SELDO.
+	 */
+SET_SRC_MODE	M_SCSI;
+SET_DST_MODE	M_SCSI;
+	and	A, FIFO1FREE|FIFO0FREE, DFFSTAT;
+	cmp	A, FIFO1FREE|FIFO0FREE jne return;
+	test	SSTAT0, SELDO jnz return;
+	mvi	SCBPTR[1], SCB_LIST_NULL;
+unexpected_nonpkt_phase:
+	test	MODE_PTR, ~(MK_MODE(M_DFF1, M_DFF1))
+		jnz unexpected_nonpkt_mode_cleared;
+SET_SRC_MODE	M_DFF0;
+SET_DST_MODE	M_DFF0;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	dec	SCB_FIFO_USE_COUNT;
+	mvi	DFFSXFRCTL, CLRCHN;
+unexpected_nonpkt_mode_cleared:
+	mvi	CLRSINT2, CLRNONPACKREQ;
+	test	SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase;
+	SET_SEQINTCODE(ENTERING_NONPACK)
+	jmp	ITloop;
+
+illegal_phase:
+	SET_SEQINTCODE(ILLEGAL_PHASE)
+	jmp	ITloop;
+
+/*
+ * We have entered an overrun situation.  If we have working
+ * BITBUCKET, flip that on and let the hardware eat any overrun
+ * data.  Otherwise use an overrun buffer in the host to simulate
+ * BITBUCKET.
+ */
+pkt_handle_overrun_inc_use_count:
+	inc	SCB_FIFO_USE_COUNT;
+pkt_handle_overrun:
+	SET_SEQINTCODE(CFG4OVERRUN)
+	call	freeze_queue;
+	if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0) {
+		or	DFFSXFRCTL, DFFBITBUCKET;
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+	} else {
+		call	load_overrun_buf;
+		mvi	DFCNTRL, (HDMAEN|SCSIEN|PRELOADEN);
+	}
+	call	setjmp;
+	if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
+		test	DFSTATUS, PRELOAD_AVAIL jz overrun_load_done;
+		call	load_overrun_buf;
+		or	DFCNTRL, PRELOADEN;
+overrun_load_done:
+		test	SEQINTSRC, CTXTDONE jnz pkt_overrun_end;
+	} else {
+		test	DFFSXFRCTL, DFFBITBUCKET jz pkt_overrun_end;
+	}
+	test	SSTAT2, NONPACKREQ jz return;
+pkt_overrun_end:
+	or	SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
+	test	SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
+	dec	SCB_FIFO_USE_COUNT;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+
+if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
+load_overrun_buf:
+	/*
+	 * Load a dummy segment if preload space is available.
+	 */
+	mov 	HADDR[0], SHARED_DATA_ADDR;
+	add	HADDR[1], PKT_OVERRUN_BUFOFFSET, SHARED_DATA_ADDR[1];
+	mov	ACCUM_SAVE, A;
+	clr	A;
+	adc	HADDR[2], A, SHARED_DATA_ADDR[2];
+	adc	HADDR[3], A, SHARED_DATA_ADDR[3];
+	mov	A, ACCUM_SAVE;
+	bmov	HADDR[4], ALLZEROS, 4;
+	/* PKT_OVERRUN_BUFSIZE is a multiple of 256 */
+	clr	HCNT[0];
+	mvi	HCNT[1], ((PKT_OVERRUN_BUFSIZE >> 8) & 0xFF);
+	clr	HCNT[2] ret;
+}
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
new file mode 100644
index 0000000..137fb1a
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -0,0 +1,9888 @@
+/*
+ * Core routines and tables shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2002 Justin T. Gibbs.
+ * Copyright (c) 2000-2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#202 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "aic79xx_osm.h"
+#include "aic79xx_inline.h"
+#include "aicasm/aicasm_insformat.h"
+#else
+#include <dev/aic7xxx/aic79xx_osm.h>
+#include <dev/aic7xxx/aic79xx_inline.h>
+#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
+#endif
+
+/******************************** Globals *************************************/
+struct ahd_softc_tailq ahd_tailq = TAILQ_HEAD_INITIALIZER(ahd_tailq);
+
+/***************************** Lookup Tables **********************************/
+char *ahd_chip_names[] =
+{
+	"NONE",
+	"aic7901",
+	"aic7902",
+	"aic7901A"
+};
+static const u_int num_chip_names = NUM_ELEMENTS(ahd_chip_names);
+
+/*
+ * Hardware error codes.
+ */
+struct ahd_hard_error_entry {
+        uint8_t errno;
+	char *errmesg;
+};
+
+static struct ahd_hard_error_entry ahd_hard_errors[] = {
+	{ DSCTMOUT,	"Discard Timer has timed out" },
+	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },
+	{ SQPARERR,	"Sequencer Parity Error" },
+	{ DPARERR,	"Data-path Parity Error" },
+	{ MPARERR,	"Scratch or SCB Memory Parity Error" },
+	{ CIOPARERR,	"CIOBUS Parity Error" },
+};
+static const u_int num_errors = NUM_ELEMENTS(ahd_hard_errors);
+
+static struct ahd_phase_table_entry ahd_phase_table[] =
+{
+	{ P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	},
+	{ P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	},
+	{ P_DATAOUT_DT,	MSG_NOOP,		"in DT Data-out phase"	},
+	{ P_DATAIN_DT,	MSG_INITIATOR_DET_ERR,	"in DT Data-in phase"	},
+	{ P_COMMAND,	MSG_NOOP,		"in Command phase"	},
+	{ P_MESGOUT,	MSG_NOOP,		"in Message-out phase"	},
+	{ P_STATUS,	MSG_INITIATOR_DET_ERR,	"in Status phase"	},
+	{ P_MESGIN,	MSG_PARITY_ERROR,	"in Message-in phase"	},
+	{ P_BUSFREE,	MSG_NOOP,		"while idle"		},
+	{ 0,		MSG_NOOP,		"in unknown phase"	}
+};
+
+/*
+ * In most cases we only wish to itterate over real phases, so
+ * exclude the last element from the count.
+ */
+static const u_int num_phases = NUM_ELEMENTS(ahd_phase_table) - 1;
+
+/* Our Sequencer Program */
+#include "aic79xx_seq.h"
+
+/**************************** Function Declarations ***************************/
+static void		ahd_handle_transmission_error(struct ahd_softc *ahd);
+static void		ahd_handle_lqiphase_error(struct ahd_softc *ahd,
+						  u_int lqistat1);
+static int		ahd_handle_pkt_busfree(struct ahd_softc *ahd,
+					       u_int busfreetime);
+static int		ahd_handle_nonpkt_busfree(struct ahd_softc *ahd);
+static void		ahd_handle_proto_violation(struct ahd_softc *ahd);
+static void		ahd_force_renegotiation(struct ahd_softc *ahd,
+						struct ahd_devinfo *devinfo);
+
+static struct ahd_tmode_tstate*
+			ahd_alloc_tstate(struct ahd_softc *ahd,
+					 u_int scsi_id, char channel);
+#ifdef AHD_TARGET_MODE
+static void		ahd_free_tstate(struct ahd_softc *ahd,
+					u_int scsi_id, char channel, int force);
+#endif
+static void		ahd_devlimited_syncrate(struct ahd_softc *ahd,
+					        struct ahd_initiator_tinfo *,
+						u_int *period,
+						u_int *ppr_options,
+						role_t role);
+static void		ahd_update_neg_table(struct ahd_softc *ahd,
+					     struct ahd_devinfo *devinfo,
+					     struct ahd_transinfo *tinfo);
+static void		ahd_update_pending_scbs(struct ahd_softc *ahd);
+static void		ahd_fetch_devinfo(struct ahd_softc *ahd,
+					  struct ahd_devinfo *devinfo);
+static void		ahd_scb_devinfo(struct ahd_softc *ahd,
+					struct ahd_devinfo *devinfo,
+					struct scb *scb);
+static void		ahd_setup_initiator_msgout(struct ahd_softc *ahd,
+						   struct ahd_devinfo *devinfo,
+						   struct scb *scb);
+static void		ahd_build_transfer_msg(struct ahd_softc *ahd,
+					       struct ahd_devinfo *devinfo);
+static void		ahd_construct_sdtr(struct ahd_softc *ahd,
+					   struct ahd_devinfo *devinfo,
+					   u_int period, u_int offset);
+static void		ahd_construct_wdtr(struct ahd_softc *ahd,
+					   struct ahd_devinfo *devinfo,
+					   u_int bus_width);
+static void		ahd_construct_ppr(struct ahd_softc *ahd,
+					  struct ahd_devinfo *devinfo,
+					  u_int period, u_int offset,
+					  u_int bus_width, u_int ppr_options);
+static void		ahd_clear_msg_state(struct ahd_softc *ahd);
+static void		ahd_handle_message_phase(struct ahd_softc *ahd);
+typedef enum {
+	AHDMSG_1B,
+	AHDMSG_2B,
+	AHDMSG_EXT
+} ahd_msgtype;
+static int		ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type,
+				     u_int msgval, int full);
+static int		ahd_parse_msg(struct ahd_softc *ahd,
+				      struct ahd_devinfo *devinfo);
+static int		ahd_handle_msg_reject(struct ahd_softc *ahd,
+					      struct ahd_devinfo *devinfo);
+static void		ahd_handle_ign_wide_residue(struct ahd_softc *ahd,
+						struct ahd_devinfo *devinfo);
+static void		ahd_reinitialize_dataptrs(struct ahd_softc *ahd);
+static void		ahd_handle_devreset(struct ahd_softc *ahd,
+					    struct ahd_devinfo *devinfo,
+					    u_int lun, cam_status status,
+					    char *message, int verbose_level);
+#ifdef AHD_TARGET_MODE
+static void		ahd_setup_target_msgin(struct ahd_softc *ahd,
+					       struct ahd_devinfo *devinfo,
+					       struct scb *scb);
+#endif
+
+static u_int		ahd_sglist_size(struct ahd_softc *ahd);
+static u_int		ahd_sglist_allocsize(struct ahd_softc *ahd);
+static bus_dmamap_callback_t
+			ahd_dmamap_cb; 
+static void		ahd_initialize_hscbs(struct ahd_softc *ahd);
+static int		ahd_init_scbdata(struct ahd_softc *ahd);
+static void		ahd_fini_scbdata(struct ahd_softc *ahd);
+static void		ahd_setup_iocell_workaround(struct ahd_softc *ahd);
+static void		ahd_iocell_first_selection(struct ahd_softc *ahd);
+static void		ahd_add_col_list(struct ahd_softc *ahd,
+					 struct scb *scb, u_int col_idx);
+static void		ahd_rem_col_list(struct ahd_softc *ahd,
+					 struct scb *scb);
+static void		ahd_chip_init(struct ahd_softc *ahd);
+static void		ahd_qinfifo_requeue(struct ahd_softc *ahd,
+					    struct scb *prev_scb,
+					    struct scb *scb);
+static int		ahd_qinfifo_count(struct ahd_softc *ahd);
+static int		ahd_search_scb_list(struct ahd_softc *ahd, int target,
+					    char channel, int lun, u_int tag,
+					    role_t role, uint32_t status,
+					    ahd_search_action action,
+					    u_int *list_head, u_int tid);
+static void		ahd_stitch_tid_list(struct ahd_softc *ahd,
+					    u_int tid_prev, u_int tid_cur,
+					    u_int tid_next);
+static void		ahd_add_scb_to_free_list(struct ahd_softc *ahd,
+						 u_int scbid);
+static u_int		ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
+				     u_int prev, u_int next, u_int tid);
+static void		ahd_reset_current_bus(struct ahd_softc *ahd);
+static ahd_callback_t	ahd_reset_poll;
+static ahd_callback_t	ahd_stat_timer;
+#ifdef AHD_DUMP_SEQ
+static void		ahd_dumpseq(struct ahd_softc *ahd);
+#endif
+static void		ahd_loadseq(struct ahd_softc *ahd);
+static int		ahd_check_patch(struct ahd_softc *ahd,
+					struct patch **start_patch,
+					u_int start_instr, u_int *skip_addr);
+static u_int		ahd_resolve_seqaddr(struct ahd_softc *ahd,
+					    u_int address);
+static void		ahd_download_instr(struct ahd_softc *ahd,
+					   u_int instrptr, uint8_t *dconsts);
+static int		ahd_probe_stack_size(struct ahd_softc *ahd);
+static int		ahd_scb_active_in_fifo(struct ahd_softc *ahd,
+					       struct scb *scb);
+static void		ahd_run_data_fifo(struct ahd_softc *ahd,
+					  struct scb *scb);
+
+#ifdef AHD_TARGET_MODE
+static void		ahd_queue_lstate_event(struct ahd_softc *ahd,
+					       struct ahd_tmode_lstate *lstate,
+					       u_int initiator_id,
+					       u_int event_type,
+					       u_int event_arg);
+static void		ahd_update_scsiid(struct ahd_softc *ahd,
+					  u_int targid_mask);
+static int		ahd_handle_target_cmd(struct ahd_softc *ahd,
+					      struct target_cmd *cmd);
+#endif
+
+/******************************** Private Inlines *****************************/
+static __inline void	ahd_assert_atn(struct ahd_softc *ahd);
+static __inline int	ahd_currently_packetized(struct ahd_softc *ahd);
+static __inline int	ahd_set_active_fifo(struct ahd_softc *ahd);
+
+static __inline void
+ahd_assert_atn(struct ahd_softc *ahd)
+{
+	ahd_outb(ahd, SCSISIGO, ATNO);
+}
+
+/*
+ * Determine if the current connection has a packetized
+ * agreement.  This does not necessarily mean that we
+ * are currently in a packetized transfer.  We could
+ * just as easily be sending or receiving a message.
+ */
+static __inline int
+ahd_currently_packetized(struct ahd_softc *ahd)
+{
+	ahd_mode_state	 saved_modes;
+	int		 packetized;
+
+	saved_modes = ahd_save_modes(ahd);
+	if ((ahd->bugs & AHD_PKTIZED_STATUS_BUG) != 0) {
+		/*
+		 * The packetized bit refers to the last
+		 * connection, not the current one.  Check
+		 * for non-zero LQISTATE instead.
+		 */
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		packetized = ahd_inb(ahd, LQISTATE) != 0;
+	} else {
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		packetized = ahd_inb(ahd, LQISTAT2) & PACKETIZED;
+	}
+	ahd_restore_modes(ahd, saved_modes);
+	return (packetized);
+}
+
+static __inline int
+ahd_set_active_fifo(struct ahd_softc *ahd)
+{
+	u_int active_fifo;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	active_fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO;
+	switch (active_fifo) {
+	case 0:
+	case 1:
+		ahd_set_modes(ahd, active_fifo, active_fifo);
+		return (1);
+	default:
+		return (0);
+	}
+}
+
+/************************* Sequencer Execution Control ************************/
+/*
+ * Restart the sequencer program from address zero
+ */
+void
+ahd_restart(struct ahd_softc *ahd)
+{
+
+	ahd_pause(ahd);
+
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	/* No more pending messages */
+	ahd_clear_msg_state(ahd);
+	ahd_outb(ahd, SCSISIGO, 0);		/* De-assert BSY */
+	ahd_outb(ahd, MSG_OUT, MSG_NOOP);	/* No message to send */
+	ahd_outb(ahd, SXFRCTL1, ahd_inb(ahd, SXFRCTL1) & ~BITBUCKET);
+	ahd_outb(ahd, SEQINTCTL, 0);
+	ahd_outb(ahd, LASTPHASE, P_BUSFREE);
+	ahd_outb(ahd, SEQ_FLAGS, 0);
+	ahd_outb(ahd, SAVED_SCSIID, 0xFF);
+	ahd_outb(ahd, SAVED_LUN, 0xFF);
+
+	/*
+	 * Ensure that the sequencer's idea of TQINPOS
+	 * matches our own.  The sequencer increments TQINPOS
+	 * only after it sees a DMA complete and a reset could
+	 * occur before the increment leaving the kernel to believe
+	 * the command arrived but the sequencer to not.
+	 */
+	ahd_outb(ahd, TQINPOS, ahd->tqinfifonext);
+
+	/* Always allow reselection */
+	ahd_outb(ahd, SCSISEQ1,
+		 ahd_inb(ahd, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+	ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);
+	ahd_unpause(ahd);
+}
+
+void
+ahd_clear_fifo(struct ahd_softc *ahd, u_int fifo)
+{
+	ahd_mode_state	 saved_modes;
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_FIFOS) != 0)
+		printf("%s: Clearing FIFO %d\n", ahd_name(ahd), fifo);
+#endif
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, fifo, fifo);
+	ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT);
+	if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
+		ahd_outb(ahd, CCSGCTL, CCSGRESET);
+	ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
+	ahd_outb(ahd, SG_STATE, 0);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+/************************* Input/Output Queues ********************************/
+/*
+ * Flush and completed commands that are sitting in the command
+ * complete queues down on the chip but have yet to be dma'ed back up.
+ */
+void
+ahd_flush_qoutfifo(struct ahd_softc *ahd)
+{
+	struct		scb *scb;
+	ahd_mode_state	saved_modes;
+	u_int		saved_scbptr;
+	u_int		ccscbctl;
+	u_int		scbid;
+	u_int		next_scbid;
+
+	saved_modes = ahd_save_modes(ahd);
+
+	/*
+	 * Complete any SCBs that just finished being
+	 * DMA'ed into the qoutfifo.
+	 */
+	ahd_run_qoutfifo(ahd);
+
+	/*
+	 * Flush the good status FIFO for compelted packetized commands.
+	 */
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	saved_scbptr = ahd_get_scbptr(ahd);
+	while ((ahd_inb(ahd, LQISTAT2) & LQIGSAVAIL) != 0) {
+		u_int fifo_mode;
+		u_int i;
+		
+		scbid = (ahd_inb(ahd, GSFIFO+1) << 8)
+		      | ahd_inb(ahd, GSFIFO);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: Warning - GSFIFO SCB %d invalid\n",
+			       ahd_name(ahd), scbid);
+			continue;
+		}
+		/*
+		 * Determine if this transaction is still active in
+		 * any FIFO.  If it is, we must flush that FIFO to
+		 * the host before completing the  command.
+		 */
+		fifo_mode = 0;
+		for (i = 0; i < 2; i++) {
+			/* Toggle to the other mode. */
+			fifo_mode ^= 1;
+			ahd_set_modes(ahd, fifo_mode, fifo_mode);
+			if (ahd_scb_active_in_fifo(ahd, scb) == 0)
+				continue;
+
+			ahd_run_data_fifo(ahd, scb);
+
+			/*
+			 * Clearing this transaction in this FIFO may
+			 * cause a CFG4DATA for this same transaction
+			 * to assert in the other FIFO.  Make sure we
+			 * loop one more time and check the other FIFO.
+			 */
+			i = 0;
+		}
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		ahd_set_scbptr(ahd, scbid);
+		if ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_LIST_NULL) == 0
+		 && ((ahd_inb_scbram(ahd, SCB_SGPTR) & SG_FULL_RESID) != 0
+		  || (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR)
+		      & SG_LIST_NULL) != 0)) {
+			u_int comp_head;
+
+			/*
+			 * The transfer completed with a residual.
+			 * Place this SCB on the complete DMA list
+			 * so that we Update our in-core copy of the
+			 * SCB before completing the command.
+			 */
+			ahd_outb(ahd, SCB_SCSI_STATUS, 0);
+			ahd_outb(ahd, SCB_SGPTR,
+				 ahd_inb_scbram(ahd, SCB_SGPTR)
+				 | SG_STATUS_VALID);
+			ahd_outw(ahd, SCB_TAG, SCB_GET_TAG(scb));
+			comp_head = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
+			ahd_outw(ahd, SCB_NEXT_COMPLETE, comp_head);
+			if (SCBID_IS_NULL(comp_head))
+				ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD,
+					 SCB_GET_TAG(scb));
+		} else
+			ahd_complete_scb(ahd, scb);
+	}
+	ahd_set_scbptr(ahd, saved_scbptr);
+
+	/*
+	 * Setup for command channel portion of flush.
+	 */
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+	/*
+	 * Wait for any inprogress DMA to complete and clear DMA state
+	 * if this if for an SCB in the qinfifo.
+	 */
+	while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) {
+
+		if ((ccscbctl & (CCSCBDIR|CCARREN)) == (CCSCBDIR|CCARREN)) {
+			if ((ccscbctl & ARRDONE) != 0)
+				break;
+		} else if ((ccscbctl & CCSCBDONE) != 0)
+			break;
+		ahd_delay(200);
+	}
+	if ((ccscbctl & CCSCBDIR) != 0)
+		ahd_outb(ahd, CCSCBCTL, ccscbctl & ~(CCARREN|CCSCBEN));
+
+	saved_scbptr = ahd_get_scbptr(ahd);
+	/*
+	 * Manually update/complete any completed SCBs that are waiting to be
+	 * DMA'ed back up to the host.
+	 */
+	scbid = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
+	while (!SCBID_IS_NULL(scbid)) {
+		uint8_t *hscb_ptr;
+		u_int	 i;
+		
+		ahd_set_scbptr(ahd, scbid);
+		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: Warning - DMA-up and complete "
+			       "SCB %d invalid\n", ahd_name(ahd), scbid);
+			continue;
+		}
+		hscb_ptr = (uint8_t *)scb->hscb;
+		for (i = 0; i < sizeof(struct hardware_scb); i++)
+			*hscb_ptr++ = ahd_inb_scbram(ahd, SCB_BASE + i);
+
+		ahd_complete_scb(ahd, scb);
+		scbid = next_scbid;
+	}
+	ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+
+	scbid = ahd_inw(ahd, COMPLETE_SCB_HEAD);
+	while (!SCBID_IS_NULL(scbid)) {
+
+		ahd_set_scbptr(ahd, scbid);
+		next_scbid = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: Warning - Complete SCB %d invalid\n",
+			       ahd_name(ahd), scbid);
+			continue;
+		}
+
+		ahd_complete_scb(ahd, scb);
+		scbid = next_scbid;
+	}
+	ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL);
+
+	/*
+	 * Restore state.
+	 */
+	ahd_set_scbptr(ahd, saved_scbptr);
+	ahd_restore_modes(ahd, saved_modes);
+	ahd->flags |= AHD_UPDATE_PEND_CMDS;
+}
+
+/*
+ * Determine if an SCB for a packetized transaction
+ * is active in a FIFO.
+ */
+static int
+ahd_scb_active_in_fifo(struct ahd_softc *ahd, struct scb *scb)
+{
+
+	/*
+	 * The FIFO is only active for our transaction if
+	 * the SCBPTR matches the SCB's ID and the firmware
+	 * has installed a handler for the FIFO or we have
+	 * a pending SAVEPTRS or CFG4DATA interrupt.
+	 */
+	if (ahd_get_scbptr(ahd) != SCB_GET_TAG(scb)
+	 || ((ahd_inb(ahd, LONGJMP_ADDR+1) & INVALID_ADDR) != 0
+	  && (ahd_inb(ahd, SEQINTSRC) & (CFG4DATA|SAVEPTRS)) == 0))
+		return (0);
+
+	return (1);
+}
+
+/*
+ * Run a data fifo to completion for a transaction we know
+ * has completed across the SCSI bus (good status has been
+ * received).  We are already set to the correct FIFO mode
+ * on entry to this routine.
+ *
+ * This function attempts to operate exactly as the firmware
+ * would when running this FIFO.  Care must be taken to update
+ * this routine any time the firmware's FIFO algorithm is
+ * changed.
+ */
+static void
+ahd_run_data_fifo(struct ahd_softc *ahd, struct scb *scb)
+{
+	u_int seqintsrc;
+
+	while (1) {
+		seqintsrc = ahd_inb(ahd, SEQINTSRC);
+		if ((seqintsrc & CFG4DATA) != 0) {
+			uint32_t datacnt;
+			uint32_t sgptr;
+
+			/*
+			 * Clear full residual flag.
+			 */
+			sgptr = ahd_inl_scbram(ahd, SCB_SGPTR) & ~SG_FULL_RESID;
+			ahd_outb(ahd, SCB_SGPTR, sgptr);
+
+			/*
+			 * Load datacnt and address.
+			 */
+			datacnt = ahd_inl_scbram(ahd, SCB_DATACNT);
+			if ((datacnt & AHD_DMA_LAST_SEG) != 0) {
+				sgptr |= LAST_SEG;
+				ahd_outb(ahd, SG_STATE, 0);
+			} else
+				ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+			ahd_outq(ahd, HADDR, ahd_inq_scbram(ahd, SCB_DATAPTR));
+			ahd_outl(ahd, HCNT, datacnt & AHD_SG_LEN_MASK);
+			ahd_outb(ahd, SG_CACHE_PRE, sgptr);
+			ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
+
+			/*
+			 * Initialize Residual Fields.
+			 */
+			ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, datacnt >> 24);
+			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr & SG_PTR_MASK);
+
+			/*
+			 * Mark the SCB as having a FIFO in use.
+			 */
+			ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+				 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) + 1);
+
+			/*
+			 * Install a "fake" handler for this FIFO.
+			 */
+			ahd_outw(ahd, LONGJMP_ADDR, 0);
+
+			/*
+			 * Notify the hardware that we have satisfied
+			 * this sequencer interrupt.
+			 */
+			ahd_outb(ahd, CLRSEQINTSRC, CLRCFG4DATA);
+		} else if ((seqintsrc & SAVEPTRS) != 0) {
+			uint32_t sgptr;
+			uint32_t resid;
+
+			if ((ahd_inb(ahd, LONGJMP_ADDR+1)&INVALID_ADDR) != 0) {
+				/*
+				 * Snapshot Save Pointers.  Clear
+				 * the snapshot and continue.
+				 */
+				ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
+				continue;
+			}
+
+			/*
+			 * Disable S/G fetch so the DMA engine
+			 * is available to future users.
+			 */
+			if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0)
+				ahd_outb(ahd, CCSGCTL, 0);
+			ahd_outb(ahd, SG_STATE, 0);
+
+			/*
+			 * Flush the data FIFO.  Strickly only
+			 * necessary for Rev A parts.
+			 */
+			ahd_outb(ahd, DFCNTRL,
+				 ahd_inb(ahd, DFCNTRL) | FIFOFLUSH);
+
+			/*
+			 * Calculate residual.
+			 */
+			sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+			resid = ahd_inl(ahd, SHCNT);
+			resid |=
+			    ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24;
+			ahd_outl(ahd, SCB_RESIDUAL_DATACNT, resid);
+			if ((ahd_inb(ahd, SG_CACHE_SHADOW) & LAST_SEG) == 0) {
+				/*
+				 * Must back up to the correct S/G element.
+				 * Typically this just means resetting our
+				 * low byte to the offset in the SG_CACHE,
+				 * but if we wrapped, we have to correct
+				 * the other bytes of the sgptr too.
+				 */
+				if ((ahd_inb(ahd, SG_CACHE_SHADOW) & 0x80) != 0
+				 && (sgptr & 0x80) == 0)
+					sgptr -= 0x100;
+				sgptr &= ~0xFF;
+				sgptr |= ahd_inb(ahd, SG_CACHE_SHADOW)
+				       & SG_ADDR_MASK;
+				ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+				ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, 0);
+			} else if ((resid & AHD_SG_LEN_MASK) == 0) {
+				ahd_outb(ahd, SCB_RESIDUAL_SGPTR,
+					 sgptr | SG_LIST_NULL);
+			}
+			/*
+			 * Save Pointers.
+			 */
+			ahd_outq(ahd, SCB_DATAPTR, ahd_inq(ahd, SHADDR));
+			ahd_outl(ahd, SCB_DATACNT, resid);
+			ahd_outl(ahd, SCB_SGPTR, sgptr);
+			ahd_outb(ahd, CLRSEQINTSRC, CLRSAVEPTRS);
+			ahd_outb(ahd, SEQIMODE,
+				 ahd_inb(ahd, SEQIMODE) | ENSAVEPTRS);
+			/*
+			 * If the data is to the SCSI bus, we are
+			 * done, otherwise wait for FIFOEMP.
+			 */
+			if ((ahd_inb(ahd, DFCNTRL) & DIRECTION) != 0)
+				break;
+		} else if ((ahd_inb(ahd, SG_STATE) & LOADING_NEEDED) != 0) {
+			uint32_t sgptr;
+			uint64_t data_addr;
+			uint32_t data_len;
+			u_int	 dfcntrl;
+
+			/*
+			 * Disable S/G fetch so the DMA engine
+			 * is available to future users.
+			 */
+			if ((ahd_inb(ahd, SG_STATE) & FETCH_INPROG) != 0) {
+				ahd_outb(ahd, CCSGCTL, 0);
+				ahd_outb(ahd, SG_STATE, LOADING_NEEDED);
+			}
+
+			/*
+			 * Wait for the DMA engine to notice that the
+			 * host transfer is enabled and that there is
+			 * space in the S/G FIFO for new segments before
+			 * loading more segments.
+			 */
+			if ((ahd_inb(ahd, DFSTATUS) & PRELOAD_AVAIL) == 0)
+				continue;
+			if ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) == 0)
+				continue;
+
+			/*
+			 * Determine the offset of the next S/G
+			 * element to load.
+			 */
+			sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+			sgptr &= SG_PTR_MASK;
+			if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+				struct ahd_dma64_seg *sg;
+
+				sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+				data_addr = sg->addr;
+				data_len = sg->len;
+				sgptr += sizeof(*sg);
+			} else {
+				struct	ahd_dma_seg *sg;
+
+				sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+				data_addr = sg->len & AHD_SG_HIGH_ADDR_MASK;
+				data_addr <<= 8;
+				data_addr |= sg->addr;
+				data_len = sg->len;
+				sgptr += sizeof(*sg);
+			}
+
+			/*
+			 * Update residual information.
+			 */
+			ahd_outb(ahd, SCB_RESIDUAL_DATACNT+3, data_len >> 24);
+			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+
+			/*
+			 * Load the S/G.
+			 */
+			if (data_len & AHD_DMA_LAST_SEG) {
+				sgptr |= LAST_SEG;
+				ahd_outb(ahd, SG_STATE, 0);
+			}
+			ahd_outq(ahd, HADDR, data_addr);
+			ahd_outl(ahd, HCNT, data_len & AHD_SG_LEN_MASK);
+			ahd_outb(ahd, SG_CACHE_PRE, sgptr & 0xFF);
+
+			/*
+			 * Advertise the segment to the hardware.
+			 */
+			dfcntrl = ahd_inb(ahd, DFCNTRL)|PRELOADEN|HDMAEN;
+			if ((ahd->features & AHD_NEW_DFCNTRL_OPTS)!=0) {
+				/*
+				 * Use SCSIENWRDIS so that SCSIEN
+				 * is never modified by this
+				 * operation.
+				 */
+				dfcntrl |= SCSIENWRDIS;
+			}
+			ahd_outb(ahd, DFCNTRL, dfcntrl);
+		} else if ((ahd_inb(ahd, SG_CACHE_SHADOW)
+			 & LAST_SEG_DONE) != 0) {
+
+			/*
+			 * Transfer completed to the end of SG list
+			 * and has flushed to the host.
+			 */
+			ahd_outb(ahd, SCB_SGPTR,
+				 ahd_inb_scbram(ahd, SCB_SGPTR) | SG_LIST_NULL);
+			break;
+		} else if ((ahd_inb(ahd, DFSTATUS) & FIFOEMP) != 0) {
+			break;
+		}
+		ahd_delay(200);
+	}
+	/*
+	 * Clear any handler for this FIFO, decrement
+	 * the FIFO use count for the SCB, and release
+	 * the FIFO.
+	 */
+	ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
+	ahd_outb(ahd, SCB_FIFO_USE_COUNT,
+		 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT) - 1);
+	ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
+}
+
+void
+ahd_run_qoutfifo(struct ahd_softc *ahd)
+{
+	struct scb *scb;
+	u_int  scb_index;
+
+	if ((ahd->flags & AHD_RUNNING_QOUTFIFO) != 0)
+		panic("ahd_run_qoutfifo recursion");
+	ahd->flags |= AHD_RUNNING_QOUTFIFO;
+	ahd_sync_qoutfifo(ahd, BUS_DMASYNC_POSTREAD);
+	while ((ahd->qoutfifo[ahd->qoutfifonext]
+	     & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag) {
+
+		scb_index = ahd_le16toh(ahd->qoutfifo[ahd->qoutfifonext]
+				      & ~QOUTFIFO_ENTRY_VALID_LE);
+		scb = ahd_lookup_scb(ahd, scb_index);
+		if (scb == NULL) {
+			printf("%s: WARNING no command for scb %d "
+			       "(cmdcmplt)\nQOUTPOS = %d\n",
+			       ahd_name(ahd), scb_index,
+			       ahd->qoutfifonext);
+			ahd_dump_card_state(ahd);
+		} else
+			ahd_complete_scb(ahd, scb);
+
+		ahd->qoutfifonext = (ahd->qoutfifonext+1) & (AHD_QOUT_SIZE-1);
+		if (ahd->qoutfifonext == 0)
+			ahd->qoutfifonext_valid_tag ^= QOUTFIFO_ENTRY_VALID_LE;
+	}
+	ahd->flags &= ~AHD_RUNNING_QOUTFIFO;
+}
+
+/************************* Interrupt Handling *********************************/
+void
+ahd_handle_hwerrint(struct ahd_softc *ahd)
+{
+	/*
+	 * Some catastrophic hardware error has occurred.
+	 * Print it for the user and disable the controller.
+	 */
+	int i;
+	int error;
+
+	error = ahd_inb(ahd, ERROR);
+	for (i = 0; i < num_errors; i++) {
+		if ((error & ahd_hard_errors[i].errno) != 0)
+			printf("%s: hwerrint, %s\n",
+			       ahd_name(ahd), ahd_hard_errors[i].errmesg);
+	}
+
+	ahd_dump_card_state(ahd);
+	panic("BRKADRINT");
+
+	/* Tell everyone that this HBA is no longer available */
+	ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+		       CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
+		       CAM_NO_HBA);
+
+	/* Tell the system that this controller has gone away. */
+	ahd_free(ahd);
+}
+
+void
+ahd_handle_seqint(struct ahd_softc *ahd, u_int intstat)
+{
+	u_int seqintcode;
+
+	/*
+	 * Save the sequencer interrupt code and clear the SEQINT
+	 * bit. We will unpause the sequencer, if appropriate,
+	 * after servicing the request.
+	 */
+	seqintcode = ahd_inb(ahd, SEQINTCODE);
+	ahd_outb(ahd, CLRINT, CLRSEQINT);
+	if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+		/*
+		 * Unpause the sequencer and let it clear
+		 * SEQINT by writing NO_SEQINT to it.  This
+		 * will cause the sequencer to be paused again,
+		 * which is the expected state of this routine.
+		 */
+		ahd_unpause(ahd);
+		while (!ahd_is_paused(ahd))
+			;
+		ahd_outb(ahd, CLRINT, CLRSEQINT);
+	}
+	ahd_update_modes(ahd);
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MISC) != 0)
+		printf("%s: Handle Seqint Called for code %d\n",
+		       ahd_name(ahd), seqintcode);
+#endif
+	switch (seqintcode) {
+	case BAD_SCB_STATUS:
+	{
+		struct	scb *scb;
+		u_int	scbid;
+		int	cmds_pending;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL) {
+			ahd_complete_scb(ahd, scb);
+		} else {
+			printf("%s: WARNING no command for scb %d "
+			       "(bad status)\n", ahd_name(ahd), scbid);
+			ahd_dump_card_state(ahd);
+		}
+		cmds_pending = ahd_inw(ahd, CMDS_PENDING);
+		if (cmds_pending > 0)
+			ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1);
+		break;
+	}
+	case ENTERING_NONPACK:
+	{
+		struct	scb *scb;
+		u_int	scbid;
+
+		AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+				 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			/*
+			 * Somehow need to know if this
+			 * is from a selection or reselection.
+			 * From that, we can determine target
+			 * ID so we at least have an I_T nexus.
+			 */
+		} else {
+			ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid);
+			ahd_outb(ahd, SAVED_LUN, scb->hscb->lun);
+			ahd_outb(ahd, SEQ_FLAGS, 0x0);
+		}
+		if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0
+		 && (ahd_inb(ahd, SCSISIGO) & ATNO) != 0) {
+			/*
+			 * Phase change after read stream with
+			 * CRC error with P0 asserted on last
+			 * packet.
+			 */
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+				printf("%s: Assuming LQIPHASE_NLQ with "
+				       "P0 assertion\n", ahd_name(ahd));
+#endif
+		}
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+			printf("%s: Entering NONPACK\n", ahd_name(ahd));
+#endif
+		break;
+	}
+	case INVALID_SEQINT:
+		printf("%s: Invalid Sequencer interrupt occurred.\n",
+		       ahd_name(ahd));
+		ahd_dump_card_state(ahd);
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+		break;
+	case STATUS_OVERRUN:
+	{
+		struct	scb *scb;
+		u_int	scbid;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL)
+			ahd_print_path(ahd, scb);
+		else
+			printf("%s: ", ahd_name(ahd));
+		printf("SCB %d Packetized Status Overrun", scbid);
+		ahd_dump_card_state(ahd);
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+		break;
+	}
+	case CFG4ISTAT_INTR:
+	{
+		struct	scb *scb;
+		u_int	scbid;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			ahd_dump_card_state(ahd);
+			printf("CFG4ISTAT: Free SCB %d referenced", scbid);
+			panic("For safety");
+		}
+		ahd_outq(ahd, HADDR, scb->sense_busaddr);
+		ahd_outw(ahd, HCNT, AHD_SENSE_BUFSIZE);
+		ahd_outb(ahd, HCNT + 2, 0);
+		ahd_outb(ahd, SG_CACHE_PRE, SG_LAST_SEG);
+		ahd_outb(ahd, DFCNTRL, PRELOADEN|SCSIEN|HDMAEN);
+		break;
+	}
+	case ILLEGAL_PHASE:
+	{
+		u_int bus_phase;
+
+		bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
+		printf("%s: ILLEGAL_PHASE 0x%x\n",
+		       ahd_name(ahd), bus_phase);
+
+		switch (bus_phase) {
+		case P_DATAOUT:
+		case P_DATAIN:
+		case P_DATAOUT_DT:
+		case P_DATAIN_DT:
+		case P_MESGOUT:
+		case P_STATUS:
+		case P_MESGIN:
+			ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+			printf("%s: Issued Bus Reset.\n", ahd_name(ahd));
+			break;
+		case P_COMMAND:
+		{
+			struct	ahd_devinfo devinfo;
+			struct	scb *scb;
+			struct	ahd_initiator_tinfo *targ_info;
+			struct	ahd_tmode_tstate *tstate;
+			struct	ahd_transinfo *tinfo;
+			u_int	scbid;
+
+			/*
+			 * If a target takes us into the command phase
+			 * assume that it has been externally reset and
+			 * has thus lost our previous packetized negotiation
+			 * agreement.  Since we have not sent an identify
+			 * message and may not have fully qualified the
+			 * connection, we change our command to TUR, assert
+			 * ATN and ABORT the task when we go to message in
+			 * phase.  The OSM will see the REQUEUE_REQUEST
+			 * status and retry the command.
+			 */
+			scbid = ahd_get_scbptr(ahd);
+			scb = ahd_lookup_scb(ahd, scbid);
+			if (scb == NULL) {
+				printf("Invalid phase with no valid SCB.  "
+				       "Resetting bus.\n");
+				ahd_reset_channel(ahd, 'A',
+						  /*Initiate Reset*/TRUE);
+				break;
+			}
+			ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb),
+					    SCB_GET_TARGET(ahd, scb),
+					    SCB_GET_LUN(scb),
+					    SCB_GET_CHANNEL(ahd, scb),
+					    ROLE_INITIATOR);
+			targ_info = ahd_fetch_transinfo(ahd,
+							devinfo.channel,
+							devinfo.our_scsiid,
+							devinfo.target,
+							&tstate);
+			tinfo = &targ_info->curr;
+			ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHD_TRANS_ACTIVE, /*paused*/TRUE);
+			ahd_set_syncrate(ahd, &devinfo, /*period*/0,
+					 /*offset*/0, /*ppr_options*/0,
+					 AHD_TRANS_ACTIVE, /*paused*/TRUE);
+			ahd_outb(ahd, SCB_CDB_STORE, 0);
+			ahd_outb(ahd, SCB_CDB_STORE+1, 0);
+			ahd_outb(ahd, SCB_CDB_STORE+2, 0);
+			ahd_outb(ahd, SCB_CDB_STORE+3, 0);
+			ahd_outb(ahd, SCB_CDB_STORE+4, 0);
+			ahd_outb(ahd, SCB_CDB_STORE+5, 0);
+			ahd_outb(ahd, SCB_CDB_LEN, 6);
+			scb->hscb->control &= ~(TAG_ENB|SCB_TAG_TYPE);
+			scb->hscb->control |= MK_MESSAGE;
+			ahd_outb(ahd, SCB_CONTROL, scb->hscb->control);
+			ahd_outb(ahd, MSG_OUT, HOST_MSG);
+			ahd_outb(ahd, SAVED_SCSIID, scb->hscb->scsiid);
+			/*
+			 * The lun is 0, regardless of the SCB's lun
+			 * as we have not sent an identify message.
+			 */
+			ahd_outb(ahd, SAVED_LUN, 0);
+			ahd_outb(ahd, SEQ_FLAGS, 0);
+			ahd_assert_atn(ahd);
+			scb->flags &= ~(SCB_PACKETIZED);
+			scb->flags |= SCB_ABORT|SCB_CMDPHASE_ABORT;
+			ahd_freeze_devq(ahd, scb);
+			ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
+			ahd_freeze_scb(scb);
+
+			/*
+			 * Allow the sequencer to continue with
+			 * non-pack processing.
+			 */
+			ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+			ahd_outb(ahd, CLRLQOINT1, CLRLQOPHACHGINPKT);
+			if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+				ahd_outb(ahd, CLRLQOINT1, 0);
+			}
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+				ahd_print_path(ahd, scb);
+				printf("Unexpected command phase from "
+				       "packetized target\n");
+			}
+#endif
+			break;
+		}
+		}
+		break;
+	}
+	case CFG4OVERRUN:
+	{
+		struct	scb *scb;
+		u_int	scb_index;
+		
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+			printf("%s: CFG4OVERRUN mode = %x\n", ahd_name(ahd),
+			       ahd_inb(ahd, MODE_PTR));
+		}
+#endif
+		scb_index = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scb_index);
+		if (scb == NULL) {
+			/*
+			 * Attempt to transfer to an SCB that is
+			 * not outstanding.
+			 */
+			ahd_assert_atn(ahd);
+			ahd_outb(ahd, MSG_OUT, HOST_MSG);
+			ahd->msgout_buf[0] = MSG_ABORT_TASK;
+			ahd->msgout_len = 1;
+			ahd->msgout_index = 0;
+			ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+			/*
+			 * Clear status received flag to prevent any
+			 * attempt to complete this bogus SCB.
+			 */
+			ahd_outb(ahd, SCB_CONTROL,
+				 ahd_inb_scbram(ahd, SCB_CONTROL)
+				 & ~STATUS_RCVD);
+		}
+		break;
+	}
+	case DUMP_CARD_STATE:
+	{
+		ahd_dump_card_state(ahd);
+		break;
+	}
+	case PDATA_REINIT:
+	{
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+			printf("%s: PDATA_REINIT - DFCNTRL = 0x%x "
+			       "SG_CACHE_SHADOW = 0x%x\n",
+			       ahd_name(ahd), ahd_inb(ahd, DFCNTRL),
+			       ahd_inb(ahd, SG_CACHE_SHADOW));
+		}
+#endif
+		ahd_reinitialize_dataptrs(ahd);
+		break;
+	}
+	case HOST_MSG_LOOP:
+	{
+		struct ahd_devinfo devinfo;
+
+		/*
+		 * The sequencer has encountered a message phase
+		 * that requires host assistance for completion.
+		 * While handling the message phase(s), we will be
+		 * notified by the sequencer after each byte is
+		 * transfered so we can track bus phase changes.
+		 *
+		 * If this is the first time we've seen a HOST_MSG_LOOP
+		 * interrupt, initialize the state of the host message
+		 * loop.
+		 */
+		ahd_fetch_devinfo(ahd, &devinfo);
+		if (ahd->msg_type == MSG_TYPE_NONE) {
+			struct scb *scb;
+			u_int scb_index;
+			u_int bus_phase;
+
+			bus_phase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
+			if (bus_phase != P_MESGIN
+			 && bus_phase != P_MESGOUT) {
+				printf("ahd_intr: HOST_MSG_LOOP bad "
+				       "phase 0x%x\n", bus_phase);
+				/*
+				 * Probably transitioned to bus free before
+				 * we got here.  Just punt the message.
+				 */
+				ahd_dump_card_state(ahd);
+				ahd_clear_intstat(ahd);
+				ahd_restart(ahd);
+				return;
+			}
+
+			scb_index = ahd_get_scbptr(ahd);
+			scb = ahd_lookup_scb(ahd, scb_index);
+			if (devinfo.role == ROLE_INITIATOR) {
+				if (bus_phase == P_MESGOUT)
+					ahd_setup_initiator_msgout(ahd,
+								   &devinfo,
+								   scb);
+				else {
+					ahd->msg_type =
+					    MSG_TYPE_INITIATOR_MSGIN;
+					ahd->msgin_index = 0;
+				}
+			}
+#ifdef AHD_TARGET_MODE
+			else {
+				if (bus_phase == P_MESGOUT) {
+					ahd->msg_type =
+					    MSG_TYPE_TARGET_MSGOUT;
+					ahd->msgin_index = 0;
+				}
+				else 
+					ahd_setup_target_msgin(ahd,
+							       &devinfo,
+							       scb);
+			}
+#endif
+		}
+
+		ahd_handle_message_phase(ahd);
+		break;
+	}
+	case NO_MATCH:
+	{
+		/* Ensure we don't leave the selection hardware on */
+		AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+
+		printf("%s:%c:%d: no active SCB for reconnecting "
+		       "target - issuing BUS DEVICE RESET\n",
+		       ahd_name(ahd), 'A', ahd_inb(ahd, SELID) >> 4);
+		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		       "REG0 == 0x%x ACCUM = 0x%x\n",
+		       ahd_inb(ahd, SAVED_SCSIID), ahd_inb(ahd, SAVED_LUN),
+		       ahd_inw(ahd, REG0), ahd_inb(ahd, ACCUM));
+		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		       "SINDEX == 0x%x\n",
+		       ahd_inb(ahd, SEQ_FLAGS), ahd_get_scbptr(ahd),
+		       ahd_find_busy_tcl(ahd,
+					 BUILD_TCL(ahd_inb(ahd, SAVED_SCSIID),
+						   ahd_inb(ahd, SAVED_LUN))),
+		       ahd_inw(ahd, SINDEX));
+		printf("SELID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		       "SCB_CONTROL == 0x%x\n",
+		       ahd_inb(ahd, SELID), ahd_inb_scbram(ahd, SCB_SCSIID),
+		       ahd_inb_scbram(ahd, SCB_LUN),
+		       ahd_inb_scbram(ahd, SCB_CONTROL));
+		printf("SCSIBUS[0] == 0x%x, SCSISIGI == 0x%x\n",
+		       ahd_inb(ahd, SCSIBUS), ahd_inb(ahd, SCSISIGI));
+		printf("SXFRCTL0 == 0x%x\n", ahd_inb(ahd, SXFRCTL0));
+		printf("SEQCTL0 == 0x%x\n", ahd_inb(ahd, SEQCTL0));
+		ahd_dump_card_state(ahd);
+		ahd->msgout_buf[0] = MSG_BUS_DEV_RESET;
+		ahd->msgout_len = 1;
+		ahd->msgout_index = 0;
+		ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		ahd_outb(ahd, MSG_OUT, HOST_MSG);
+		ahd_assert_atn(ahd);
+		break;
+	}
+	case PROTO_VIOLATION:
+	{
+		ahd_handle_proto_violation(ahd);
+		break;
+	}
+	case IGN_WIDE_RES:
+	{
+		struct ahd_devinfo devinfo;
+
+		ahd_fetch_devinfo(ahd, &devinfo);
+		ahd_handle_ign_wide_residue(ahd, &devinfo);
+		break;
+	}
+	case BAD_PHASE:
+	{
+		u_int lastphase;
+
+		lastphase = ahd_inb(ahd, LASTPHASE);
+		printf("%s:%c:%d: unknown scsi bus phase %x, "
+		       "lastphase = 0x%x.  Attempting to continue\n",
+		       ahd_name(ahd), 'A',
+		       SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
+		       lastphase, ahd_inb(ahd, SCSISIGI));
+		break;
+	}
+	case MISSED_BUSFREE:
+	{
+		u_int lastphase;
+
+		lastphase = ahd_inb(ahd, LASTPHASE);
+		printf("%s:%c:%d: Missed busfree. "
+		       "Lastphase = 0x%x, Curphase = 0x%x\n",
+		       ahd_name(ahd), 'A',
+		       SCSIID_TARGET(ahd, ahd_inb(ahd, SAVED_SCSIID)),
+		       lastphase, ahd_inb(ahd, SCSISIGI));
+		ahd_restart(ahd);
+		return;
+	}
+	case DATA_OVERRUN:
+	{
+		/*
+		 * When the sequencer detects an overrun, it
+		 * places the controller in "BITBUCKET" mode
+		 * and allows the target to complete its transfer.
+		 * Unfortunately, none of the counters get updated
+		 * when the controller is in this mode, so we have
+		 * no way of knowing how large the overrun was.
+		 */
+		struct	scb *scb;
+		u_int	scbindex;
+#ifdef AHD_DEBUG
+		u_int	lastphase;
+#endif
+
+		scbindex = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbindex);
+#ifdef AHD_DEBUG
+		lastphase = ahd_inb(ahd, LASTPHASE);
+		if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+			ahd_print_path(ahd, scb);
+			printf("data overrun detected %s.  Tag == 0x%x.\n",
+			       ahd_lookup_phase_entry(lastphase)->phasemsg,
+			       SCB_GET_TAG(scb));
+			ahd_print_path(ahd, scb);
+			printf("%s seen Data Phase.  Length = %ld.  "
+			       "NumSGs = %d.\n",
+			       ahd_inb(ahd, SEQ_FLAGS) & DPHASE
+			       ? "Have" : "Haven't",
+			       ahd_get_transfer_length(scb), scb->sg_count);
+			ahd_dump_sglist(scb);
+		}
+#endif
+
+		/*
+		 * Set this and it will take effect when the
+		 * target does a command complete.
+		 */
+		ahd_freeze_devq(ahd, scb);
+		ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		ahd_freeze_scb(scb);
+		break;
+	}
+	case MKMSG_FAILED:
+	{
+		struct ahd_devinfo devinfo;
+		struct scb *scb;
+		u_int scbid;
+
+		ahd_fetch_devinfo(ahd, &devinfo);
+		printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+		       ahd_name(ahd), devinfo.channel, devinfo.target,
+		       devinfo.lun);
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL
+		 && (scb->flags & SCB_RECOVERY_SCB) != 0)
+			/*
+			 * Ensure that we didn't put a second instance of this
+			 * SCB into the QINFIFO.
+			 */
+			ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),
+					   SCB_GET_CHANNEL(ahd, scb),
+					   SCB_GET_LUN(scb), SCB_GET_TAG(scb),
+					   ROLE_INITIATOR, /*status*/0,
+					   SEARCH_REMOVE);
+		ahd_outb(ahd, SCB_CONTROL,
+			 ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE);
+		break;
+	}
+	case TASKMGMT_FUNC_COMPLETE:
+	{
+		u_int	scbid;
+		struct	scb *scb;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL) {
+			u_int	   lun;
+			u_int	   tag;
+			cam_status error;
+
+			ahd_print_path(ahd, scb);
+			printf("Task Management Func 0x%x Complete\n",
+			       scb->hscb->task_management);
+			lun = CAM_LUN_WILDCARD;
+			tag = SCB_LIST_NULL;
+
+			switch (scb->hscb->task_management) {
+			case SIU_TASKMGMT_ABORT_TASK:
+				tag = SCB_GET_TAG(scb);
+			case SIU_TASKMGMT_ABORT_TASK_SET:
+			case SIU_TASKMGMT_CLEAR_TASK_SET:
+				lun = scb->hscb->lun;
+				error = CAM_REQ_ABORTED;
+				ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
+					       'A', lun, tag, ROLE_INITIATOR,
+					       error);
+				break;
+			case SIU_TASKMGMT_LUN_RESET:
+				lun = scb->hscb->lun;
+			case SIU_TASKMGMT_TARGET_RESET:
+			{
+				struct ahd_devinfo devinfo;
+
+				ahd_scb_devinfo(ahd, &devinfo, scb);
+				error = CAM_BDR_SENT;
+				ahd_handle_devreset(ahd, &devinfo, lun,
+						    CAM_BDR_SENT,
+						    lun != CAM_LUN_WILDCARD
+						    ? "Lun Reset"
+						    : "Target Reset",
+						    /*verbose_level*/0);
+				break;
+			}
+			default:
+				panic("Unexpected TaskMgmt Func\n");
+				break;
+			}
+		}
+		break;
+	}
+	case TASKMGMT_CMD_CMPLT_OKAY:
+	{
+		u_int	scbid;
+		struct	scb *scb;
+
+		/*
+		 * An ABORT TASK TMF failed to be delivered before
+		 * the targeted command completed normally.
+		 */
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL) {
+			/*
+			 * Remove the second instance of this SCB from
+			 * the QINFIFO if it is still there.
+                         */
+			ahd_print_path(ahd, scb);
+			printf("SCB completes before TMF\n");
+			/*
+			 * Handle losing the race.  Wait until any
+			 * current selection completes.  We will then
+			 * set the TMF back to zero in this SCB so that
+			 * the sequencer doesn't bother to issue another
+			 * sequencer interrupt for its completion.
+			 */
+			while ((ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0
+			    && (ahd_inb(ahd, SSTAT0) & SELDO) == 0
+			    && (ahd_inb(ahd, SSTAT1) & SELTO) == 0)
+				;
+			ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0);
+			ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),
+					   SCB_GET_CHANNEL(ahd, scb),  
+					   SCB_GET_LUN(scb), SCB_GET_TAG(scb), 
+					   ROLE_INITIATOR, /*status*/0,   
+					   SEARCH_REMOVE);
+		}
+		break;
+	}
+	case TRACEPOINT0:
+	case TRACEPOINT1:
+	case TRACEPOINT2:
+	case TRACEPOINT3:
+		printf("%s: Tracepoint %d\n", ahd_name(ahd),
+		       seqintcode - TRACEPOINT0);
+		break;
+	case NO_SEQINT:
+		break;
+	case SAW_HWERR:
+		ahd_handle_hwerrint(ahd);
+		break;
+	default:
+		printf("%s: Unexpected SEQINTCODE %d\n", ahd_name(ahd),
+		       seqintcode);
+		break;
+	}
+	/*
+	 *  The sequencer is paused immediately on
+	 *  a SEQINT, so we should restart it when
+	 *  we're done.
+	 */
+	ahd_unpause(ahd);
+}
+
+void
+ahd_handle_scsiint(struct ahd_softc *ahd, u_int intstat)
+{
+	struct scb	*scb;
+	u_int		 status0;
+	u_int		 status3;
+	u_int		 status;
+	u_int		 lqistat1;
+	u_int		 lqostat0;
+	u_int		 scbid;
+	u_int		 busfreetime;
+
+	ahd_update_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	status3 = ahd_inb(ahd, SSTAT3) & (NTRAMPERR|OSRAMPERR);
+	status0 = ahd_inb(ahd, SSTAT0) & (IOERR|OVERRUN|SELDI|SELDO);
+	status = ahd_inb(ahd, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
+	lqistat1 = ahd_inb(ahd, LQISTAT1);
+	lqostat0 = ahd_inb(ahd, LQOSTAT0);
+	busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
+	if ((status0 & (SELDI|SELDO)) != 0) {
+		u_int simode0;
+
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		simode0 = ahd_inb(ahd, SIMODE0);
+		status0 &= simode0 & (IOERR|OVERRUN|SELDI|SELDO);
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	}
+	scbid = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scbid);
+	if (scb != NULL
+	 && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
+		scb = NULL;
+
+	/* Make sure the sequencer is in a safe location. */
+	ahd_clear_critical_section(ahd);
+
+	if ((status0 & IOERR) != 0) {
+		u_int now_lvd;
+
+		now_lvd = ahd_inb(ahd, SBLKCTL) & ENAB40;
+		printf("%s: Transceiver State Has Changed to %s mode\n",
+		       ahd_name(ahd), now_lvd ? "LVD" : "SE");
+		ahd_outb(ahd, CLRSINT0, CLRIOERR);
+		/*
+		 * A change in I/O mode is equivalent to a bus reset.
+		 */
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+		ahd_pause(ahd);
+		ahd_setup_iocell_workaround(ahd);
+		ahd_unpause(ahd);
+	} else if ((status0 & OVERRUN) != 0) {
+		printf("%s: SCSI offset overrun detected.  Resetting bus.\n",
+		       ahd_name(ahd));
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+	} else if ((status & SCSIRSTI) != 0) {
+		printf("%s: Someone reset channel A\n", ahd_name(ahd));
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
+	} else if ((status & SCSIPERR) != 0) {
+		ahd_handle_transmission_error(ahd);
+	} else if (lqostat0 != 0) {
+		printf("%s: lqostat0 == 0x%x!\n", ahd_name(ahd), lqostat0);
+		ahd_outb(ahd, CLRLQOINT0, lqostat0);
+		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+			ahd_outb(ahd, CLRLQOINT1, 0);
+		}
+	} else if ((status & SELTO) != 0) {
+		u_int  scbid;
+
+		/* Stop the selection */
+		ahd_outb(ahd, SCSISEQ0, 0);
+
+		/* No more pending messages */
+		ahd_clear_msg_state(ahd);
+
+		/* Clear interrupt state */
+		ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Although the driver does not care about the
+		 * 'Selection in Progress' status bit, the busy
+		 * LED does.  SELINGO is only cleared by a sucessfull
+		 * selection, so we must manually clear it to insure
+		 * the LED turns off just incase no future successful
+		 * selections occur (e.g. no devices on the bus).
+		 */
+		ahd_outb(ahd, CLRSINT0, CLRSELINGO);
+
+		scbid = ahd_inw(ahd, WAITING_TID_HEAD);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: ahd_intr - referenced scb not "
+			       "valid during SELTO scb(0x%x)\n",
+			       ahd_name(ahd), scbid);
+			ahd_dump_card_state(ahd);
+		} else {
+			struct ahd_devinfo devinfo;
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_SELTO) != 0) {
+				ahd_print_path(ahd, scb);
+				printf("Saw Selection Timeout for SCB 0x%x\n",
+				       scbid);
+			}
+#endif
+			/*
+			 * Force a renegotiation with this target just in
+			 * case the cable was pulled and will later be
+			 * re-attached.  The target may forget its negotiation
+			 * settings with us should it attempt to reselect
+			 * during the interruption.  The target will not issue
+			 * a unit attention in this case, so we must always
+			 * renegotiate.
+			 */
+			ahd_scb_devinfo(ahd, &devinfo, scb);
+			ahd_force_renegotiation(ahd, &devinfo);
+			ahd_set_transaction_status(scb, CAM_SEL_TIMEOUT);
+			ahd_freeze_devq(ahd, scb);
+		}
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
+		ahd_iocell_first_selection(ahd);
+		ahd_unpause(ahd);
+	} else if ((status0 & (SELDI|SELDO)) != 0) {
+		ahd_iocell_first_selection(ahd);
+		ahd_unpause(ahd);
+	} else if (status3 != 0) {
+		printf("%s: SCSI Cell parity error SSTAT3 == 0x%x\n",
+		       ahd_name(ahd), status3);
+		ahd_outb(ahd, CLRSINT3, status3);
+	} else if ((lqistat1 & (LQIPHASE_LQ|LQIPHASE_NLQ)) != 0) {
+		ahd_handle_lqiphase_error(ahd, lqistat1);
+	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
+		/*
+		 * This status can be delayed during some
+		 * streaming operations.  The SCSIPHASE
+		 * handler has already dealt with this case
+		 * so just clear the error.
+		 */
+		ahd_outb(ahd, CLRLQIINT1, CLRLQICRCI_NLQ);
+	} else if ((status & BUSFREE) != 0) {
+		u_int lqostat1;
+		int   restart;
+		int   clear_fifo;
+		int   packetized;
+		u_int mode;
+
+		/*
+		 * Clear our selection hardware as soon as possible.
+		 * We may have an entry in the waiting Q for this target,
+		 * that is affected by this busfree and we don't want to
+		 * go about selecting the target while we handle the event.
+		 */
+		ahd_outb(ahd, SCSISEQ0, 0);
+
+		/*
+		 * Determine what we were up to at the time of
+		 * the busfree.
+		 */
+		mode = AHD_MODE_SCSI;
+		busfreetime = ahd_inb(ahd, SSTAT2) & BUSFREETIME;
+		lqostat1 = ahd_inb(ahd, LQOSTAT1);
+		switch (busfreetime) {
+		case BUSFREE_DFF0:
+		case BUSFREE_DFF1:
+		{
+			u_int	scbid;
+			struct	scb *scb;
+
+			mode = busfreetime == BUSFREE_DFF0
+			     ? AHD_MODE_DFF0 : AHD_MODE_DFF1;
+			ahd_set_modes(ahd, mode, mode);
+			scbid = ahd_get_scbptr(ahd);
+			scb = ahd_lookup_scb(ahd, scbid);
+			if (scb == NULL) {
+				printf("%s: Invalid SCB %d in DFF%d "
+				       "during unexpected busfree\n",
+				       ahd_name(ahd), scbid, mode);
+				packetized = 0;
+			} else
+				packetized = (scb->flags & SCB_PACKETIZED) != 0;
+			clear_fifo = 1;
+			break;
+		}
+		case BUSFREE_LQO:
+			clear_fifo = 0;
+			packetized = 1;
+			break;
+		default:
+			clear_fifo = 0;
+			packetized =  (lqostat1 & LQOBUSFREE) != 0;
+			if (!packetized
+			 && ahd_inb(ahd, LASTPHASE) == P_BUSFREE)
+				packetized = 1;
+			break;
+		}
+
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MISC) != 0)
+			printf("Saw Busfree.  Busfreetime = 0x%x.\n",
+			       busfreetime);
+#endif
+		/*
+		 * Busfrees that occur in non-packetized phases are
+		 * handled by the nonpkt_busfree handler.
+		 */
+		if (packetized && ahd_inb(ahd, LASTPHASE) == P_BUSFREE) {
+			restart = ahd_handle_pkt_busfree(ahd, busfreetime);
+		} else {
+			packetized = 0;
+			restart = ahd_handle_nonpkt_busfree(ahd);
+		}
+		/*
+		 * Clear the busfree interrupt status.  The setting of
+		 * the interrupt is a pulse, so in a perfect world, we
+		 * would not need to muck with the ENBUSFREE logic.  This
+		 * would ensure that if the bus moves on to another
+		 * connection, busfree protection is still in force.  If
+		 * BUSFREEREV is broken, however, we must manually clear
+		 * the ENBUSFREE if the busfree occurred during a non-pack
+		 * connection so that we don't get false positives during
+		 * future, packetized, connections.
+		 */
+		ahd_outb(ahd, CLRSINT1, CLRBUSFREE);
+		if (packetized == 0
+		 && (ahd->bugs & AHD_BUSFREEREV_BUG) != 0)
+			ahd_outb(ahd, SIMODE1,
+				 ahd_inb(ahd, SIMODE1) & ~ENBUSFREE);
+
+		if (clear_fifo)
+			ahd_clear_fifo(ahd, mode);
+
+		ahd_clear_msg_state(ahd);
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
+		if (restart) {
+			ahd_restart(ahd);
+		} else {
+			ahd_unpause(ahd);
+		}
+	} else {
+		printf("%s: Missing case in ahd_handle_scsiint. status = %x\n",
+		       ahd_name(ahd), status);
+		ahd_dump_card_state(ahd);
+		ahd_clear_intstat(ahd);
+		ahd_unpause(ahd);
+	}
+}
+
+static void
+ahd_handle_transmission_error(struct ahd_softc *ahd)
+{
+	struct	scb *scb;
+	u_int	scbid;
+	u_int	lqistat1;
+	u_int	lqistat2;
+	u_int	msg_out;
+	u_int	curphase;
+	u_int	lastphase;
+	u_int	perrdiag;
+	u_int	cur_col;
+	int	silent;
+
+	scb = NULL;
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	lqistat1 = ahd_inb(ahd, LQISTAT1) & ~(LQIPHASE_LQ|LQIPHASE_NLQ);
+	lqistat2 = ahd_inb(ahd, LQISTAT2);
+	if ((lqistat1 & (LQICRCI_NLQ|LQICRCI_LQ)) == 0
+	 && (ahd->bugs & AHD_NLQICRC_DELAYED_BUG) != 0) {
+		u_int lqistate;
+
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		lqistate = ahd_inb(ahd, LQISTATE);
+		if ((lqistate >= 0x1E && lqistate <= 0x24)
+		 || (lqistate == 0x29)) {
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_RECOVERY) != 0) {
+				printf("%s: NLQCRC found via LQISTATE\n",
+				       ahd_name(ahd));
+			}
+#endif
+			lqistat1 |= LQICRCI_NLQ;
+		}
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	}
+
+	ahd_outb(ahd, CLRLQIINT1, lqistat1);
+	lastphase = ahd_inb(ahd, LASTPHASE);
+	curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
+	perrdiag = ahd_inb(ahd, PERRDIAG);
+	msg_out = MSG_INITIATOR_DET_ERR;
+	ahd_outb(ahd, CLRSINT1, CLRSCSIPERR);
+	
+	/*
+	 * Try to find the SCB associated with this error.
+	 */
+	silent = FALSE;
+	if (lqistat1 == 0
+	 || (lqistat1 & LQICRCI_NLQ) != 0) {
+	 	if ((lqistat1 & (LQICRCI_NLQ|LQIOVERI_NLQ)) != 0)
+			ahd_set_active_fifo(ahd);
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL && SCB_IS_SILENT(scb))
+			silent = TRUE;
+	}
+
+	cur_col = 0;
+	if (silent == FALSE) {
+		printf("%s: Transmission error detected\n", ahd_name(ahd));
+		ahd_lqistat1_print(lqistat1, &cur_col, 50);
+		ahd_lastphase_print(lastphase, &cur_col, 50);
+		ahd_scsisigi_print(curphase, &cur_col, 50);
+		ahd_perrdiag_print(perrdiag, &cur_col, 50);
+		printf("\n");
+		ahd_dump_card_state(ahd);
+	}
+
+	if ((lqistat1 & (LQIOVERI_LQ|LQIOVERI_NLQ)) != 0) {
+		if (silent == FALSE) {
+			printf("%s: Gross protocol error during incoming "
+			       "packet.  lqistat1 == 0x%x.  Resetting bus.\n",
+			       ahd_name(ahd), lqistat1);
+		}
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+		return;
+	} else if ((lqistat1 & LQICRCI_LQ) != 0) {
+		/*
+		 * A CRC error has been detected on an incoming LQ.
+		 * The bus is currently hung on the last ACK.
+		 * Hit LQIRETRY to release the last ack, and
+		 * wait for the sequencer to determine that ATNO
+		 * is asserted while in message out to take us
+		 * to our host message loop.  No NONPACKREQ or
+		 * LQIPHASE type errors will occur in this
+		 * scenario.  After this first LQIRETRY, the LQI
+		 * manager will be in ISELO where it will
+		 * happily sit until another packet phase begins.
+		 * Unexpected bus free detection is enabled
+		 * through any phases that occur after we release
+		 * this last ack until the LQI manager sees a
+		 * packet phase.  This implies we may have to
+		 * ignore a perfectly valid "unexected busfree"
+		 * after our "initiator detected error" message is
+		 * sent.  A busfree is the expected response after
+		 * we tell the target that it's L_Q was corrupted.
+		 * (SPI4R09 10.7.3.3.3)
+		 */
+		ahd_outb(ahd, LQCTL2, LQIRETRY);
+		printf("LQIRetry for LQICRCI_LQ to release ACK\n");
+	} else if ((lqistat1 & LQICRCI_NLQ) != 0) {
+		/*
+		 * We detected a CRC error in a NON-LQ packet.
+		 * The hardware has varying behavior in this situation
+		 * depending on whether this packet was part of a
+		 * stream or not.
+		 *
+		 * PKT by PKT mode:
+		 * The hardware has already acked the complete packet.
+		 * If the target honors our outstanding ATN condition,
+		 * we should be (or soon will be) in MSGOUT phase.
+		 * This will trigger the LQIPHASE_LQ status bit as the
+		 * hardware was expecting another LQ.  Unexpected
+		 * busfree detection is enabled.  Once LQIPHASE_LQ is
+		 * true (first entry into host message loop is much
+		 * the same), we must clear LQIPHASE_LQ and hit
+		 * LQIRETRY so the hardware is ready to handle
+		 * a future LQ.  NONPACKREQ will not be asserted again
+		 * once we hit LQIRETRY until another packet is
+		 * processed.  The target may either go busfree
+		 * or start another packet in response to our message.
+		 *
+		 * Read Streaming P0 asserted:
+		 * If we raise ATN and the target completes the entire
+		 * stream (P0 asserted during the last packet), the
+		 * hardware will ack all data and return to the ISTART
+		 * state.  When the target reponds to our ATN condition,
+		 * LQIPHASE_LQ will be asserted.  We should respond to
+		 * this with an LQIRETRY to prepare for any future
+		 * packets.  NONPACKREQ will not be asserted again
+		 * once we hit LQIRETRY until another packet is
+		 * processed.  The target may either go busfree or
+		 * start another packet in response to our message.
+		 * Busfree detection is enabled.
+		 *
+		 * Read Streaming P0 not asserted:
+		 * If we raise ATN and the target transitions to
+		 * MSGOUT in or after a packet where P0 is not
+		 * asserted, the hardware will assert LQIPHASE_NLQ.
+		 * We should respond to the LQIPHASE_NLQ with an
+		 * LQIRETRY.  Should the target stay in a non-pkt
+		 * phase after we send our message, the hardware
+		 * will assert LQIPHASE_LQ.  Recovery is then just as
+		 * listed above for the read streaming with P0 asserted.
+		 * Busfree detection is enabled.
+		 */
+		if (silent == FALSE)
+			printf("LQICRC_NLQ\n");
+		if (scb == NULL) {
+			printf("%s: No SCB valid for LQICRC_NLQ.  "
+			       "Resetting bus\n", ahd_name(ahd));
+			ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+			return;
+		}
+	} else if ((lqistat1 & LQIBADLQI) != 0) {
+		printf("Need to handle BADLQI!\n");
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+		return;
+	} else if ((perrdiag & (PARITYERR|PREVPHASE)) == PARITYERR) {
+		if ((curphase & ~P_DATAIN_DT) != 0) {
+			/* Ack the byte.  So we can continue. */
+			if (silent == FALSE)
+				printf("Acking %s to clear perror\n",
+				    ahd_lookup_phase_entry(curphase)->phasemsg);
+			ahd_inb(ahd, SCSIDAT);
+		}
+	
+		if (curphase == P_MESGIN)
+			msg_out = MSG_PARITY_ERROR;
+	}
+
+	/*
+	 * We've set the hardware to assert ATN if we 
+	 * get a parity error on "in" phases, so all we
+	 * need to do is stuff the message buffer with
+	 * the appropriate message.  "In" phases have set
+	 * mesg_out to something other than MSG_NOP.
+	 */
+	ahd->send_msg_perror = msg_out;
+	if (scb != NULL && msg_out == MSG_INITIATOR_DET_ERR)
+		scb->flags |= SCB_TRANSMISSION_ERROR;
+	ahd_outb(ahd, MSG_OUT, HOST_MSG);
+	ahd_outb(ahd, CLRINT, CLRSCSIINT);
+	ahd_unpause(ahd);
+}
+
+static void
+ahd_handle_lqiphase_error(struct ahd_softc *ahd, u_int lqistat1)
+{
+	/*
+	 * Clear the sources of the interrupts.
+	 */
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, CLRLQIINT1, lqistat1);
+
+	/*
+	 * If the "illegal" phase changes were in response
+	 * to our ATN to flag a CRC error, AND we ended up
+	 * on packet boundaries, clear the error, restart the
+	 * LQI manager as appropriate, and go on our merry
+	 * way toward sending the message.  Otherwise, reset
+	 * the bus to clear the error.
+	 */
+	ahd_set_active_fifo(ahd);
+	if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0
+	 && (ahd_inb(ahd, MDFFSTAT) & DLZERO) != 0) {
+		if ((lqistat1 & LQIPHASE_LQ) != 0) {
+			printf("LQIRETRY for LQIPHASE_LQ\n");
+			ahd_outb(ahd, LQCTL2, LQIRETRY);
+		} else if ((lqistat1 & LQIPHASE_NLQ) != 0) {
+			printf("LQIRETRY for LQIPHASE_NLQ\n");
+			ahd_outb(ahd, LQCTL2, LQIRETRY);
+		} else
+			panic("ahd_handle_lqiphase_error: No phase errors\n");
+		ahd_dump_card_state(ahd);
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
+		ahd_unpause(ahd);
+	} else {
+		printf("Reseting Channel for LQI Phase error\n");
+		ahd_dump_card_state(ahd);
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
+	}
+}
+
+/*
+ * Packetized unexpected or expected busfree.
+ * Entered in mode based on busfreetime.
+ */
+static int
+ahd_handle_pkt_busfree(struct ahd_softc *ahd, u_int busfreetime)
+{
+	u_int lqostat1;
+
+	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+	lqostat1 = ahd_inb(ahd, LQOSTAT1);
+	if ((lqostat1 & LQOBUSFREE) != 0) {
+		struct scb *scb;
+		u_int scbid;
+		u_int saved_scbptr;
+		u_int waiting_h;
+		u_int waiting_t;
+		u_int next;
+
+		if ((busfreetime & BUSFREE_LQO) == 0)
+			printf("%s: Warning, BUSFREE time is 0x%x.  "
+			       "Expected BUSFREE_LQO.\n",
+			       ahd_name(ahd), busfreetime);
+		/*
+		 * The LQO manager detected an unexpected busfree
+		 * either:
+		 *
+		 * 1) During an outgoing LQ.
+		 * 2) After an outgoing LQ but before the first
+		 *    REQ of the command packet.
+		 * 3) During an outgoing command packet.
+		 *
+		 * In all cases, CURRSCB is pointing to the
+		 * SCB that encountered the failure.  Clean
+		 * up the queue, clear SELDO and LQOBUSFREE,
+		 * and allow the sequencer to restart the select
+		 * out at its lesure.
+		 */
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		scbid = ahd_inw(ahd, CURRSCB);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL)
+		       panic("SCB not valid during LQOBUSFREE");
+		/*
+		 * Clear the status.
+		 */
+		ahd_outb(ahd, CLRLQOINT1, CLRLQOBUSFREE);
+		if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0)
+			ahd_outb(ahd, CLRLQOINT1, 0);
+		ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+		ahd_flush_device_writes(ahd);
+		ahd_outb(ahd, CLRSINT0, CLRSELDO);
+
+		/*
+		 * Return the LQO manager to its idle loop.  It will
+		 * not do this automatically if the busfree occurs
+		 * after the first REQ of either the LQ or command
+		 * packet or between the LQ and command packet.
+		 */
+		ahd_outb(ahd, LQCTL2, ahd_inb(ahd, LQCTL2) | LQOTOIDLE);
+
+		/*
+		 * Update the waiting for selection queue so
+		 * we restart on the correct SCB.
+		 */
+		waiting_h = ahd_inw(ahd, WAITING_TID_HEAD);
+		saved_scbptr = ahd_get_scbptr(ahd);
+		if (waiting_h != scbid) {
+
+			ahd_outw(ahd, WAITING_TID_HEAD, scbid);
+			waiting_t = ahd_inw(ahd, WAITING_TID_TAIL);
+			if (waiting_t == waiting_h) {
+				ahd_outw(ahd, WAITING_TID_TAIL, scbid);
+				next = SCB_LIST_NULL;
+			} else {
+				ahd_set_scbptr(ahd, waiting_h);
+				next = ahd_inw_scbram(ahd, SCB_NEXT2);
+			}
+			ahd_set_scbptr(ahd, scbid);
+			ahd_outw(ahd, SCB_NEXT2, next);
+		}
+		ahd_set_scbptr(ahd, saved_scbptr);
+		if (scb->crc_retry_count < AHD_MAX_LQ_CRC_ERRORS) {
+			if (SCB_IS_SILENT(scb) == FALSE) {
+				ahd_print_path(ahd, scb);
+				printf("Probable outgoing LQ CRC error.  "
+				       "Retrying command\n");
+			}
+			scb->crc_retry_count++;
+		} else {
+			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
+			ahd_freeze_scb(scb);
+			ahd_freeze_devq(ahd, scb);
+		}
+		/* Return unpausing the sequencer. */
+		return (0);
+	} else if ((ahd_inb(ahd, PERRDIAG) & PARITYERR) != 0) {
+		/*
+		 * Ignore what are really parity errors that
+		 * occur on the last REQ of a free running
+		 * clock prior to going busfree.  Some drives
+		 * do not properly active negate just before
+		 * going busfree resulting in a parity glitch.
+		 */
+		ahd_outb(ahd, CLRSINT1, CLRSCSIPERR|CLRBUSFREE);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MASKED_ERRORS) != 0)
+			printf("%s: Parity on last REQ detected "
+			       "during busfree phase.\n",
+			       ahd_name(ahd));
+#endif
+		/* Return unpausing the sequencer. */
+		return (0);
+	}
+	if (ahd->src_mode != AHD_MODE_SCSI) {
+		u_int	scbid;
+		struct	scb *scb;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		ahd_print_path(ahd, scb);
+		printf("Unexpected PKT busfree condition\n");
+		ahd_dump_card_state(ahd);
+		ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb), 'A',
+			       SCB_GET_LUN(scb), SCB_GET_TAG(scb),
+			       ROLE_INITIATOR, CAM_UNEXP_BUSFREE);
+
+		/* Return restarting the sequencer. */
+		return (1);
+	}
+	printf("%s: Unexpected PKT busfree condition\n", ahd_name(ahd));
+	ahd_dump_card_state(ahd);
+	/* Restart the sequencer. */
+	return (1);
+}
+
+/*
+ * Non-packetized unexpected or expected busfree.
+ */
+static int
+ahd_handle_nonpkt_busfree(struct ahd_softc *ahd)
+{
+	struct	ahd_devinfo devinfo;
+	struct	scb *scb;
+	u_int	lastphase;
+	u_int	saved_scsiid;
+	u_int	saved_lun;
+	u_int	target;
+	u_int	initiator_role_id;
+	u_int	scbid;
+	u_int	ppr_busfree;
+	int	printerror;
+
+	/*
+	 * Look at what phase we were last in.  If its message out,
+	 * chances are pretty good that the busfree was in response
+	 * to one of our abort requests.
+	 */
+	lastphase = ahd_inb(ahd, LASTPHASE);
+	saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
+	saved_lun = ahd_inb(ahd, SAVED_LUN);
+	target = SCSIID_TARGET(ahd, saved_scsiid);
+	initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
+	ahd_compile_devinfo(&devinfo, initiator_role_id,
+			    target, saved_lun, 'A', ROLE_INITIATOR);
+	printerror = 1;
+
+	scbid = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scbid);
+	if (scb != NULL
+	 && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
+		scb = NULL;
+
+	ppr_busfree = (ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0;
+	if (lastphase == P_MESGOUT) {
+		u_int tag;
+
+		tag = SCB_LIST_NULL;
+		if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT_TAG, TRUE)
+		 || ahd_sent_msg(ahd, AHDMSG_1B, MSG_ABORT, TRUE)) {
+			int found;
+			int sent_msg;
+
+			if (scb == NULL) {
+				ahd_print_devinfo(ahd, &devinfo);
+				printf("Abort for unidentified "
+				       "connection completed.\n");
+				/* restart the sequencer. */
+				return (1);
+			}
+			sent_msg = ahd->msgout_buf[ahd->msgout_index - 1];
+			ahd_print_path(ahd, scb);
+			printf("SCB %d - Abort%s Completed.\n",
+			       SCB_GET_TAG(scb),
+			       sent_msg == MSG_ABORT_TAG ? "" : " Tag");
+
+			if (sent_msg == MSG_ABORT_TAG)
+				tag = SCB_GET_TAG(scb);
+
+			if ((scb->flags & SCB_CMDPHASE_ABORT) != 0) {
+				/*
+				 * This abort is in response to an
+				 * unexpected switch to command phase
+				 * for a packetized connection.  Since
+				 * the identify message was never sent,
+				 * "saved lun" is 0.  We really want to
+				 * abort only the SCB that encountered
+				 * this error, which could have a different
+				 * lun.  The SCB will be retried so the OS
+				 * will see the UA after renegotiating to
+				 * packetized.
+				 */
+				tag = SCB_GET_TAG(scb);
+				saved_lun = scb->hscb->lun;
+			}
+			found = ahd_abort_scbs(ahd, target, 'A', saved_lun,
+					       tag, ROLE_INITIATOR,
+					       CAM_REQ_ABORTED);
+			printf("found == 0x%x\n", found);
+			printerror = 0;
+		} else if (ahd_sent_msg(ahd, AHDMSG_1B,
+					MSG_BUS_DEV_RESET, TRUE)) {
+#ifdef __FreeBSD__
+			/*
+			 * Don't mark the user's request for this BDR
+			 * as completing with CAM_BDR_SENT.  CAM3
+			 * specifies CAM_REQ_CMP.
+			 */
+			if (scb != NULL
+			 && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV
+			 && ahd_match_scb(ahd, scb, target, 'A',
+					  CAM_LUN_WILDCARD, SCB_LIST_NULL,
+					  ROLE_INITIATOR))
+				ahd_set_transaction_status(scb, CAM_REQ_CMP);
+#endif
+			ahd_handle_devreset(ahd, &devinfo, CAM_LUN_WILDCARD,
+					    CAM_BDR_SENT, "Bus Device Reset",
+					    /*verbose_level*/0);
+			printerror = 0;
+		} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, FALSE)
+			&& ppr_busfree == 0) {
+			struct ahd_initiator_tinfo *tinfo;
+			struct ahd_tmode_tstate *tstate;
+
+			/*
+			 * PPR Rejected.  Try non-ppr negotiation
+			 * and retry command.
+			 */
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("PPR negotiation rejected busfree.\n");
+#endif
+			tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
+						    devinfo.our_scsiid,
+						    devinfo.target, &tstate);
+			tinfo->curr.transport_version = 2;
+			tinfo->goal.transport_version = 2;
+			tinfo->goal.ppr_options = 0;
+			ahd_qinfifo_requeue_tail(ahd, scb);
+			printerror = 0;
+		} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, FALSE)
+			&& ppr_busfree == 0) {
+			/*
+			 * Negotiation Rejected.  Go-narrow and
+			 * retry command.
+			 */
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("WDTR negotiation rejected busfree.\n");
+#endif
+			ahd_set_width(ahd, &devinfo,
+				      MSG_EXT_WDTR_BUS_8_BIT,
+				      AHD_TRANS_CUR|AHD_TRANS_GOAL,
+				      /*paused*/TRUE);
+			ahd_qinfifo_requeue_tail(ahd, scb);
+			printerror = 0;
+		} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, FALSE)
+			&& ppr_busfree == 0) {
+			/*
+			 * Negotiation Rejected.  Go-async and
+			 * retry command.
+			 */
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("SDTR negotiation rejected busfree.\n");
+#endif
+			ahd_set_syncrate(ahd, &devinfo,
+					/*period*/0, /*offset*/0,
+					/*ppr_options*/0,
+					AHD_TRANS_CUR|AHD_TRANS_GOAL,
+					/*paused*/TRUE);
+			ahd_qinfifo_requeue_tail(ahd, scb);
+			printerror = 0;
+		} else if ((ahd->msg_flags & MSG_FLAG_EXPECT_IDE_BUSFREE) != 0
+			&& ahd_sent_msg(ahd, AHDMSG_1B,
+					 MSG_INITIATOR_DET_ERR, TRUE)) {
+
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("Expected IDE Busfree\n");
+#endif
+			printerror = 0;
+		} else if ((ahd->msg_flags & MSG_FLAG_EXPECT_QASREJ_BUSFREE)
+			&& ahd_sent_msg(ahd, AHDMSG_1B,
+					MSG_MESSAGE_REJECT, TRUE)) {
+
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("Expected QAS Reject Busfree\n");
+#endif
+			printerror = 0;
+		}
+	}
+
+	/*
+	 * The busfree required flag is honored at the end of
+	 * the message phases.  We check it last in case we
+	 * had to send some other message that caused a busfree.
+	 */
+	if (printerror != 0
+	 && (lastphase == P_MESGIN || lastphase == P_MESGOUT)
+	 && ((ahd->msg_flags & MSG_FLAG_EXPECT_PPR_BUSFREE) != 0)) {
+
+		ahd_freeze_devq(ahd, scb);
+		ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
+		ahd_freeze_scb(scb);
+		if ((ahd->msg_flags & MSG_FLAG_IU_REQ_CHANGED) != 0) {
+			ahd_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
+				       SCB_GET_CHANNEL(ahd, scb),
+				       SCB_GET_LUN(scb), SCB_LIST_NULL,
+				       ROLE_INITIATOR, CAM_REQ_ABORTED);
+		} else {
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf("PPR Negotiation Busfree.\n");
+#endif
+			ahd_done(ahd, scb);
+		}
+		printerror = 0;
+	}
+	if (printerror != 0) {
+		int aborted;
+
+		aborted = 0;
+		if (scb != NULL) {
+			u_int tag;
+
+			if ((scb->hscb->control & TAG_ENB) != 0)
+				tag = SCB_GET_TAG(scb);
+			else
+				tag = SCB_LIST_NULL;
+			ahd_print_path(ahd, scb);
+			aborted = ahd_abort_scbs(ahd, target, 'A',
+				       SCB_GET_LUN(scb), tag,
+				       ROLE_INITIATOR,
+				       CAM_UNEXP_BUSFREE);
+		} else {
+			/*
+			 * We had not fully identified this connection,
+			 * so we cannot abort anything.
+			 */
+			printf("%s: ", ahd_name(ahd));
+		}
+		if (lastphase != P_BUSFREE)
+			ahd_force_renegotiation(ahd, &devinfo);
+		printf("Unexpected busfree %s, %d SCBs aborted, "
+		       "PRGMCNT == 0x%x\n",
+		       ahd_lookup_phase_entry(lastphase)->phasemsg,
+		       aborted,
+		       ahd_inb(ahd, PRGMCNT)
+			| (ahd_inb(ahd, PRGMCNT+1) << 8));
+		ahd_dump_card_state(ahd);
+	}
+	/* Always restart the sequencer. */
+	return (1);
+}
+
+static void
+ahd_handle_proto_violation(struct ahd_softc *ahd)
+{
+	struct	ahd_devinfo devinfo;
+	struct	scb *scb;
+	u_int	scbid;
+	u_int	seq_flags;
+	u_int	curphase;
+	u_int	lastphase;
+	int	found;
+
+	ahd_fetch_devinfo(ahd, &devinfo);
+	scbid = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scbid);
+	seq_flags = ahd_inb(ahd, SEQ_FLAGS);
+	curphase = ahd_inb(ahd, SCSISIGI) & PHASE_MASK;
+	lastphase = ahd_inb(ahd, LASTPHASE);
+	if ((seq_flags & NOT_IDENTIFIED) != 0) {
+
+		/*
+		 * The reconnecting target either did not send an
+		 * identify message, or did, but we didn't find an SCB
+		 * to match.
+		 */
+		ahd_print_devinfo(ahd, &devinfo);
+		printf("Target did not send an IDENTIFY message. "
+		       "LASTPHASE = 0x%x.\n", lastphase);
+		scb = NULL;
+	} else if (scb == NULL) {
+		/*
+		 * We don't seem to have an SCB active for this
+		 * transaction.  Print an error and reset the bus.
+		 */
+		ahd_print_devinfo(ahd, &devinfo);
+		printf("No SCB found during protocol violation\n");
+		goto proto_violation_reset;
+	} else {
+		ahd_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
+		if ((seq_flags & NO_CDB_SENT) != 0) {
+			ahd_print_path(ahd, scb);
+			printf("No or incomplete CDB sent to device.\n");
+		} else if ((ahd_inb_scbram(ahd, SCB_CONTROL)
+			  & STATUS_RCVD) == 0) {
+			/*
+			 * The target never bothered to provide status to
+			 * us prior to completing the command.  Since we don't
+			 * know the disposition of this command, we must attempt
+			 * to abort it.  Assert ATN and prepare to send an abort
+			 * message.
+			 */
+			ahd_print_path(ahd, scb);
+			printf("Completed command without status.\n");
+		} else {
+			ahd_print_path(ahd, scb);
+			printf("Unknown protocol violation.\n");
+			ahd_dump_card_state(ahd);
+		}
+	}
+	if ((lastphase & ~P_DATAIN_DT) == 0
+	 || lastphase == P_COMMAND) {
+proto_violation_reset:
+		/*
+		 * Target either went directly to data
+		 * phase or didn't respond to our ATN.
+		 * The only safe thing to do is to blow
+		 * it away with a bus reset.
+		 */
+		found = ahd_reset_channel(ahd, 'A', TRUE);
+		printf("%s: Issued Channel %c Bus Reset. "
+		       "%d SCBs aborted\n", ahd_name(ahd), 'A', found);
+	} else {
+		/*
+		 * Leave the selection hardware off in case
+		 * this abort attempt will affect yet to
+		 * be sent commands.
+		 */
+		ahd_outb(ahd, SCSISEQ0,
+			 ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+		ahd_assert_atn(ahd);
+		ahd_outb(ahd, MSG_OUT, HOST_MSG);
+		if (scb == NULL) {
+			ahd_print_devinfo(ahd, &devinfo);
+			ahd->msgout_buf[0] = MSG_ABORT_TASK;
+			ahd->msgout_len = 1;
+			ahd->msgout_index = 0;
+			ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		} else {
+			ahd_print_path(ahd, scb);
+			scb->flags |= SCB_ABORT;
+		}
+		printf("Protocol violation %s.  Attempting to abort.\n",
+		       ahd_lookup_phase_entry(curphase)->phasemsg);
+	}
+}
+
+/*
+ * Force renegotiation to occur the next time we initiate
+ * a command to the current device.
+ */
+static void
+ahd_force_renegotiation(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	struct	ahd_initiator_tinfo *targ_info;
+	struct	ahd_tmode_tstate *tstate;
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Forcing renegotiation\n");
+	}
+#endif
+	targ_info = ahd_fetch_transinfo(ahd,
+					devinfo->channel,
+					devinfo->our_scsiid,
+					devinfo->target,
+					&tstate);
+	ahd_update_neg_request(ahd, devinfo, tstate,
+			       targ_info, AHD_NEG_IF_NON_ASYNC);
+}
+
+#define AHD_MAX_STEPS 2000
+void
+ahd_clear_critical_section(struct ahd_softc *ahd)
+{
+	ahd_mode_state	saved_modes;
+	int		stepping;
+	int		steps;
+	int		first_instr;
+	u_int		simode0;
+	u_int		simode1;
+	u_int		simode3;
+	u_int		lqimode0;
+	u_int		lqimode1;
+	u_int		lqomode0;
+	u_int		lqomode1;
+
+	if (ahd->num_critical_sections == 0)
+		return;
+
+	stepping = FALSE;
+	steps = 0;
+	first_instr = 0;
+	simode0 = 0;
+	simode1 = 0;
+	simode3 = 0;
+	lqimode0 = 0;
+	lqimode1 = 0;
+	lqomode0 = 0;
+	lqomode1 = 0;
+	saved_modes = ahd_save_modes(ahd);
+	for (;;) {
+		struct	cs *cs;
+		u_int	seqaddr;
+		u_int	i;
+
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		seqaddr = ahd_inb(ahd, CURADDR)
+			| (ahd_inb(ahd, CURADDR+1) << 8);
+
+		cs = ahd->critical_sections;
+		for (i = 0; i < ahd->num_critical_sections; i++, cs++) {
+			
+			if (cs->begin < seqaddr && cs->end >= seqaddr)
+				break;
+		}
+
+		if (i == ahd->num_critical_sections)
+			break;
+
+		if (steps > AHD_MAX_STEPS) {
+			printf("%s: Infinite loop in critical section\n"
+			       "%s: First Instruction 0x%x now 0x%x\n",
+			       ahd_name(ahd), ahd_name(ahd), first_instr,
+			       seqaddr);
+			ahd_dump_card_state(ahd);
+			panic("critical section loop");
+		}
+
+		steps++;
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MISC) != 0)
+			printf("%s: Single stepping at 0x%x\n", ahd_name(ahd),
+			       seqaddr);
+#endif
+		if (stepping == FALSE) {
+
+			first_instr = seqaddr;
+  			ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+  			simode0 = ahd_inb(ahd, SIMODE0);
+			simode3 = ahd_inb(ahd, SIMODE3);
+			lqimode0 = ahd_inb(ahd, LQIMODE0);
+			lqimode1 = ahd_inb(ahd, LQIMODE1);
+			lqomode0 = ahd_inb(ahd, LQOMODE0);
+			lqomode1 = ahd_inb(ahd, LQOMODE1);
+			ahd_outb(ahd, SIMODE0, 0);
+			ahd_outb(ahd, SIMODE3, 0);
+			ahd_outb(ahd, LQIMODE0, 0);
+			ahd_outb(ahd, LQIMODE1, 0);
+			ahd_outb(ahd, LQOMODE0, 0);
+			ahd_outb(ahd, LQOMODE1, 0);
+			ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+			simode1 = ahd_inb(ahd, SIMODE1);
+			/*
+			 * We don't clear ENBUSFREE.  Unfortunately
+			 * we cannot re-enable busfree detection within
+			 * the current connection, so we must leave it
+			 * on while single stepping.
+			 */
+			ahd_outb(ahd, SIMODE1, simode1 & ENBUSFREE);
+			ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) | STEP);
+			stepping = TRUE;
+		}
+		ahd_outb(ahd, CLRSINT1, CLRBUSFREE);
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
+		ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
+		ahd_outb(ahd, HCNTRL, ahd->unpause);
+		while (!ahd_is_paused(ahd))
+			ahd_delay(200);
+		ahd_update_modes(ahd);
+	}
+	if (stepping) {
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		ahd_outb(ahd, SIMODE0, simode0);
+		ahd_outb(ahd, SIMODE3, simode3);
+		ahd_outb(ahd, LQIMODE0, lqimode0);
+		ahd_outb(ahd, LQIMODE1, lqimode1);
+		ahd_outb(ahd, LQOMODE0, lqomode0);
+		ahd_outb(ahd, LQOMODE1, lqomode1);
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP);
+  		ahd_outb(ahd, SIMODE1, simode1);
+		/*
+		 * SCSIINT seems to glitch occassionally when
+		 * the interrupt masks are restored.  Clear SCSIINT
+		 * one more time so that only persistent errors
+		 * are seen as a real interrupt.
+		 */
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
+	}
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+/*
+ * Clear any pending interrupt status.
+ */
+void
+ahd_clear_intstat(struct ahd_softc *ahd)
+{
+	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+	/* Clear any interrupt conditions this may have caused */
+	ahd_outb(ahd, CLRLQIINT0, CLRLQIATNQAS|CLRLQICRCT1|CLRLQICRCT2
+				 |CLRLQIBADLQT|CLRLQIATNLQ|CLRLQIATNCMD);
+	ahd_outb(ahd, CLRLQIINT1, CLRLQIPHASE_LQ|CLRLQIPHASE_NLQ|CLRLIQABORT
+				 |CLRLQICRCI_LQ|CLRLQICRCI_NLQ|CLRLQIBADLQI
+				 |CLRLQIOVERI_LQ|CLRLQIOVERI_NLQ|CLRNONPACKREQ);
+	ahd_outb(ahd, CLRLQOINT0, CLRLQOTARGSCBPERR|CLRLQOSTOPT2|CLRLQOATNLQ
+				 |CLRLQOATNPKT|CLRLQOTCRC);
+	ahd_outb(ahd, CLRLQOINT1, CLRLQOINITSCBPERR|CLRLQOSTOPI2|CLRLQOBADQAS
+				 |CLRLQOBUSFREE|CLRLQOPHACHGINPKT);
+	if ((ahd->bugs & AHD_CLRLQO_AUTOCLR_BUG) != 0) {
+		ahd_outb(ahd, CLRLQOINT0, 0);
+		ahd_outb(ahd, CLRLQOINT1, 0);
+	}
+	ahd_outb(ahd, CLRSINT3, CLRNTRAMPERR|CLROSRAMPERR);
+	ahd_outb(ahd, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
+				|CLRBUSFREE|CLRSCSIPERR|CLRREQINIT);
+	ahd_outb(ahd, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO
+			        |CLRIOERR|CLROVERRUN);
+	ahd_outb(ahd, CLRINT, CLRSCSIINT);
+}
+
+/**************************** Debugging Routines ******************************/
+#ifdef AHD_DEBUG
+uint32_t ahd_debug = AHD_DEBUG_OPTS;
+#endif
+void
+ahd_print_scb(struct scb *scb)
+{
+	struct hardware_scb *hscb;
+	int i;
+
+	hscb = scb->hscb;
+	printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+	       (void *)scb,
+	       hscb->control,
+	       hscb->scsiid,
+	       hscb->lun,
+	       hscb->cdb_len);
+	printf("Shared Data: ");
+	for (i = 0; i < sizeof(hscb->shared_data.idata.cdb); i++)
+		printf("%#02x", hscb->shared_data.idata.cdb[i]);
+	printf("        dataptr:%#x%x datacnt:%#x sgptr:%#x tag:%#x\n",
+	       (uint32_t)((ahd_le64toh(hscb->dataptr) >> 32) & 0xFFFFFFFF),
+	       (uint32_t)(ahd_le64toh(hscb->dataptr) & 0xFFFFFFFF),
+	       ahd_le32toh(hscb->datacnt),
+	       ahd_le32toh(hscb->sgptr),
+	       SCB_GET_TAG(scb));
+	ahd_dump_sglist(scb);
+}
+
+void
+ahd_dump_sglist(struct scb *scb)
+{
+	int i;
+
+	if (scb->sg_count > 0) {
+		if ((scb->ahd_softc->flags & AHD_64BIT_ADDRESSING) != 0) {
+			struct ahd_dma64_seg *sg_list;
+
+			sg_list = (struct ahd_dma64_seg*)scb->sg_list;
+			for (i = 0; i < scb->sg_count; i++) {
+				uint64_t addr;
+				uint32_t len;
+
+				addr = ahd_le64toh(sg_list[i].addr);
+				len = ahd_le32toh(sg_list[i].len);
+				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				       i,
+				       (uint32_t)((addr >> 32) & 0xFFFFFFFF),
+				       (uint32_t)(addr & 0xFFFFFFFF),
+				       sg_list[i].len & AHD_SG_LEN_MASK,
+				       (sg_list[i].len & AHD_DMA_LAST_SEG)
+				     ? " Last" : "");
+			}
+		} else {
+			struct ahd_dma_seg *sg_list;
+
+			sg_list = (struct ahd_dma_seg*)scb->sg_list;
+			for (i = 0; i < scb->sg_count; i++) {
+				uint32_t len;
+
+				len = ahd_le32toh(sg_list[i].len);
+				printf("sg[%d] - Addr 0x%x%x : Length %d%s\n",
+				       i,
+				       (len & AHD_SG_HIGH_ADDR_MASK) >> 24,
+				       ahd_le32toh(sg_list[i].addr),
+				       len & AHD_SG_LEN_MASK,
+				       len & AHD_DMA_LAST_SEG ? " Last" : "");
+			}
+		}
+	}
+}
+
+/************************* Transfer Negotiation *******************************/
+/*
+ * Allocate per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static struct ahd_tmode_tstate *
+ahd_alloc_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel)
+{
+	struct ahd_tmode_tstate *master_tstate;
+	struct ahd_tmode_tstate *tstate;
+	int i;
+
+	master_tstate = ahd->enabled_targets[ahd->our_id];
+	if (ahd->enabled_targets[scsi_id] != NULL
+	 && ahd->enabled_targets[scsi_id] != master_tstate)
+		panic("%s: ahd_alloc_tstate - Target already allocated",
+		      ahd_name(ahd));
+	tstate = malloc(sizeof(*tstate), M_DEVBUF, M_NOWAIT);
+	if (tstate == NULL)
+		return (NULL);
+
+	/*
+	 * If we have allocated a master tstate, copy user settings from
+	 * the master tstate (taken from SRAM or the EEPROM) for this
+	 * channel, but reset our current and goal settings to async/narrow
+	 * until an initiator talks to us.
+	 */
+	if (master_tstate != NULL) {
+		memcpy(tstate, master_tstate, sizeof(*tstate));
+		memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
+		for (i = 0; i < 16; i++) {
+			memset(&tstate->transinfo[i].curr, 0,
+			      sizeof(tstate->transinfo[i].curr));
+			memset(&tstate->transinfo[i].goal, 0,
+			      sizeof(tstate->transinfo[i].goal));
+		}
+	} else
+		memset(tstate, 0, sizeof(*tstate));
+	ahd->enabled_targets[scsi_id] = tstate;
+	return (tstate);
+}
+
+#ifdef AHD_TARGET_MODE
+/*
+ * Free per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static void
+ahd_free_tstate(struct ahd_softc *ahd, u_int scsi_id, char channel, int force)
+{
+	struct ahd_tmode_tstate *tstate;
+
+	/*
+	 * Don't clean up our "master" tstate.
+	 * It has our default user settings.
+	 */
+	if (scsi_id == ahd->our_id
+	 && force == FALSE)
+		return;
+
+	tstate = ahd->enabled_targets[scsi_id];
+	if (tstate != NULL)
+		free(tstate, M_DEVBUF);
+	ahd->enabled_targets[scsi_id] = NULL;
+}
+#endif
+
+/*
+ * Called when we have an active connection to a target on the bus,
+ * this function finds the nearest period to the input period limited
+ * by the capabilities of the bus connectivity of and sync settings for
+ * the target.
+ */
+void
+ahd_devlimited_syncrate(struct ahd_softc *ahd,
+			struct ahd_initiator_tinfo *tinfo,
+			u_int *period, u_int *ppr_options, role_t role)
+{
+	struct	ahd_transinfo *transinfo;
+	u_int	maxsync;
+
+	if ((ahd_inb(ahd, SBLKCTL) & ENAB40) != 0
+	 && (ahd_inb(ahd, SSTAT2) & EXP_ACTIVE) == 0) {
+		maxsync = AHD_SYNCRATE_PACED;
+	} else {
+		maxsync = AHD_SYNCRATE_ULTRA;
+		/* Can't do DT related options on an SE bus */
+		*ppr_options &= MSG_EXT_PPR_QAS_REQ;
+	}
+	/*
+	 * Never allow a value higher than our current goal
+	 * period otherwise we may allow a target initiated
+	 * negotiation to go above the limit as set by the
+	 * user.  In the case of an initiator initiated
+	 * sync negotiation, we limit based on the user
+	 * setting.  This allows the system to still accept
+	 * incoming negotiations even if target initiated
+	 * negotiation is not performed.
+	 */
+	if (role == ROLE_TARGET)
+		transinfo = &tinfo->user;
+	else 
+		transinfo = &tinfo->goal;
+	*ppr_options &= (transinfo->ppr_options|MSG_EXT_PPR_PCOMP_EN);
+	if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
+		maxsync = MAX(maxsync, AHD_SYNCRATE_ULTRA2);
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	}
+	if (transinfo->period == 0) {
+		*period = 0;
+		*ppr_options = 0;
+	} else {
+		*period = MAX(*period, transinfo->period);
+		ahd_find_syncrate(ahd, period, ppr_options, maxsync);
+	}
+}
+
+/*
+ * Look up the valid period to SCSIRATE conversion in our table.
+ * Return the period and offset that should be sent to the target
+ * if this was the beginning of an SDTR.
+ */
+void
+ahd_find_syncrate(struct ahd_softc *ahd, u_int *period,
+		  u_int *ppr_options, u_int maxsync)
+{
+	if (*period < maxsync)
+		*period = maxsync;
+
+	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) != 0
+	 && *period > AHD_SYNCRATE_MIN_DT)
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+		
+	if (*period > AHD_SYNCRATE_MIN)
+		*period = 0;
+
+	/* Honor PPR option conformance rules. */
+	if (*period > AHD_SYNCRATE_PACED)
+		*ppr_options &= ~MSG_EXT_PPR_RTI;
+
+	if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0)
+		*ppr_options &= (MSG_EXT_PPR_DT_REQ|MSG_EXT_PPR_QAS_REQ);
+
+	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0)
+		*ppr_options &= MSG_EXT_PPR_QAS_REQ;
+
+	/* Skip all PACED only entries if IU is not available */
+	if ((*ppr_options & MSG_EXT_PPR_IU_REQ) == 0
+	 && *period < AHD_SYNCRATE_DT)
+		*period = AHD_SYNCRATE_DT;
+
+	/* Skip all DT only entries if DT is not available */
+	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+	 && *period < AHD_SYNCRATE_ULTRA2)
+		*period = AHD_SYNCRATE_ULTRA2;
+}
+
+/*
+ * Truncate the given synchronous offset to a value the
+ * current adapter type and syncrate are capable of.
+ */
+void
+ahd_validate_offset(struct ahd_softc *ahd,
+		    struct ahd_initiator_tinfo *tinfo,
+		    u_int period, u_int *offset, int wide,
+		    role_t role)
+{
+	u_int maxoffset;
+
+	/* Limit offset to what we can do */
+	if (period == 0)
+		maxoffset = 0;
+	else if (period <= AHD_SYNCRATE_PACED) {
+		if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0)
+			maxoffset = MAX_OFFSET_PACED_BUG;
+		else
+			maxoffset = MAX_OFFSET_PACED;
+	} else
+		maxoffset = MAX_OFFSET_NON_PACED;
+	*offset = MIN(*offset, maxoffset);
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*offset = MIN(*offset, tinfo->user.offset);
+		else
+			*offset = MIN(*offset, tinfo->goal.offset);
+	}
+}
+
+/*
+ * Truncate the given transfer width parameter to a value the
+ * current adapter type is capable of.
+ */
+void
+ahd_validate_width(struct ahd_softc *ahd, struct ahd_initiator_tinfo *tinfo,
+		   u_int *bus_width, role_t role)
+{
+	switch (*bus_width) {
+	default:
+		if (ahd->features & AHD_WIDE) {
+			/* Respond Wide */
+			*bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+			break;
+		}
+		/* FALLTHROUGH */
+	case MSG_EXT_WDTR_BUS_8_BIT:
+		*bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+		break;
+	}
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*bus_width = MIN(tinfo->user.width, *bus_width);
+		else
+			*bus_width = MIN(tinfo->goal.width, *bus_width);
+	}
+}
+
+/*
+ * Update the bitmask of targets for which the controller should
+ * negotiate with at the next convenient oportunity.  This currently
+ * means the next time we send the initial identify messages for
+ * a new transaction.
+ */
+int
+ahd_update_neg_request(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		       struct ahd_tmode_tstate *tstate,
+		       struct ahd_initiator_tinfo *tinfo, ahd_neg_type neg_type)
+{
+	u_int auto_negotiate_orig;
+
+	auto_negotiate_orig = tstate->auto_negotiate;
+	if (neg_type == AHD_NEG_ALWAYS) {
+		/*
+		 * Force our "current" settings to be
+		 * unknown so that unless a bus reset
+		 * occurs the need to renegotiate is
+		 * recorded persistently.
+		 */
+		if ((ahd->features & AHD_WIDE) != 0)
+			tinfo->curr.width = AHD_WIDTH_UNKNOWN;
+		tinfo->curr.period = AHD_PERIOD_UNKNOWN;
+		tinfo->curr.offset = AHD_OFFSET_UNKNOWN;
+	}
+	if (tinfo->curr.period != tinfo->goal.period
+	 || tinfo->curr.width != tinfo->goal.width
+	 || tinfo->curr.offset != tinfo->goal.offset
+	 || tinfo->curr.ppr_options != tinfo->goal.ppr_options
+	 || (neg_type == AHD_NEG_IF_NON_ASYNC
+	  && (tinfo->goal.offset != 0
+	   || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
+	   || tinfo->goal.ppr_options != 0)))
+		tstate->auto_negotiate |= devinfo->target_mask;
+	else
+		tstate->auto_negotiate &= ~devinfo->target_mask;
+
+	return (auto_negotiate_orig != tstate->auto_negotiate);
+}
+
+/*
+ * Update the user/goal/curr tables of synchronous negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahd_set_syncrate(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		 u_int period, u_int offset, u_int ppr_options,
+		 u_int type, int paused)
+{
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	u_int	old_period;
+	u_int	old_offset;
+	u_int	old_ppr;
+	int	active;
+	int	update_needed;
+
+	active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE;
+	update_needed = 0;
+
+	if (period == 0 || offset == 0) {
+		period = 0;
+		offset = 0;
+	}
+
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHD_TRANS_USER) != 0) {
+		tinfo->user.period = period;
+		tinfo->user.offset = offset;
+		tinfo->user.ppr_options = ppr_options;
+	}
+
+	if ((type & AHD_TRANS_GOAL) != 0) {
+		tinfo->goal.period = period;
+		tinfo->goal.offset = offset;
+		tinfo->goal.ppr_options = ppr_options;
+	}
+
+	old_period = tinfo->curr.period;
+	old_offset = tinfo->curr.offset;
+	old_ppr	   = tinfo->curr.ppr_options;
+
+	if ((type & AHD_TRANS_CUR) != 0
+	 && (old_period != period
+	  || old_offset != offset
+	  || old_ppr != ppr_options)) {
+
+		update_needed++;
+
+		tinfo->curr.period = period;
+		tinfo->curr.offset = offset;
+		tinfo->curr.ppr_options = ppr_options;
+
+		ahd_send_async(ahd, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+		if (bootverbose) {
+			if (offset != 0) {
+				int options;
+
+				printf("%s: target %d synchronous with "
+				       "period = 0x%x, offset = 0x%x",
+				       ahd_name(ahd), devinfo->target,
+				       period, offset);
+				options = 0;
+				if ((ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
+					printf("(RDSTRM");
+					options++;
+				}
+				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
+					printf("%s", options ? "|DT" : "(DT");
+					options++;
+				}
+				if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+					printf("%s", options ? "|IU" : "(IU");
+					options++;
+				}
+				if ((ppr_options & MSG_EXT_PPR_RTI) != 0) {
+					printf("%s", options ? "|RTI" : "(RTI");
+					options++;
+				}
+				if ((ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
+					printf("%s", options ? "|QAS" : "(QAS");
+					options++;
+				}
+				if (options != 0)
+					printf(")\n");
+				else
+					printf("\n");
+			} else {
+				printf("%s: target %d using "
+				       "asynchronous transfers%s\n",
+				       ahd_name(ahd), devinfo->target,
+				       (ppr_options & MSG_EXT_PPR_QAS_REQ) != 0
+				     ?  "(QAS)" : "");
+			}
+		}
+	}
+	/*
+	 * Always refresh the neg-table to handle the case of the
+	 * sequencer setting the ENATNO bit for a MK_MESSAGE request.
+	 * We will always renegotiate in that case if this is a
+	 * packetized request.  Also manage the busfree expected flag
+	 * from this common routine so that we catch changes due to
+	 * WDTR or SDTR messages.
+	 */
+	if ((type & AHD_TRANS_CUR) != 0) {
+		if (!paused)
+			ahd_pause(ahd);
+		ahd_update_neg_table(ahd, devinfo, &tinfo->curr);
+		if (!paused)
+			ahd_unpause(ahd);
+		if (ahd->msg_type != MSG_TYPE_NONE) {
+			if ((old_ppr & MSG_EXT_PPR_IU_REQ)
+			 != (ppr_options & MSG_EXT_PPR_IU_REQ)) {
+#ifdef AHD_DEBUG
+				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+					ahd_print_devinfo(ahd, devinfo);
+					printf("Expecting IU Change busfree\n");
+				}
+#endif
+				ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE
+					       |  MSG_FLAG_IU_REQ_CHANGED;
+			}
+			if ((old_ppr & MSG_EXT_PPR_IU_REQ) != 0) {
+#ifdef AHD_DEBUG
+				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+					printf("PPR with IU_REQ outstanding\n");
+#endif
+				ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE;
+			}
+		}
+	}
+
+	update_needed += ahd_update_neg_request(ahd, devinfo, tstate,
+						tinfo, AHD_NEG_TO_GOAL);
+
+	if (update_needed && active)
+		ahd_update_pending_scbs(ahd);
+}
+
+/*
+ * Update the user/goal/curr tables of wide negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahd_set_width(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+	      u_int width, u_int type, int paused)
+{
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	u_int	oldwidth;
+	int	active;
+	int	update_needed;
+
+	active = (type & AHD_TRANS_ACTIVE) == AHD_TRANS_ACTIVE;
+	update_needed = 0;
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHD_TRANS_USER) != 0)
+		tinfo->user.width = width;
+
+	if ((type & AHD_TRANS_GOAL) != 0)
+		tinfo->goal.width = width;
+
+	oldwidth = tinfo->curr.width;
+	if ((type & AHD_TRANS_CUR) != 0 && oldwidth != width) {
+
+		update_needed++;
+
+		tinfo->curr.width = width;
+		ahd_send_async(ahd, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+		if (bootverbose) {
+			printf("%s: target %d using %dbit transfers\n",
+			       ahd_name(ahd), devinfo->target,
+			       8 * (0x01 << width));
+		}
+	}
+
+	if ((type & AHD_TRANS_CUR) != 0) {
+		if (!paused)
+			ahd_pause(ahd);
+		ahd_update_neg_table(ahd, devinfo, &tinfo->curr);
+		if (!paused)
+			ahd_unpause(ahd);
+	}
+
+	update_needed += ahd_update_neg_request(ahd, devinfo, tstate,
+						tinfo, AHD_NEG_TO_GOAL);
+	if (update_needed && active)
+		ahd_update_pending_scbs(ahd);
+
+}
+
+/*
+ * Update the current state of tagged queuing for a given target.
+ */
+void
+ahd_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+	     ahd_queue_alg alg)
+{
+	ahd_platform_set_tags(ahd, devinfo, alg);
+	ahd_send_async(ahd, devinfo->channel, devinfo->target,
+		       devinfo->lun, AC_TRANSFER_NEG, &alg);
+}
+
+static void
+ahd_update_neg_table(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		     struct ahd_transinfo *tinfo)
+{
+	ahd_mode_state	saved_modes;
+	u_int		period;
+	u_int		ppr_opts;
+	u_int		con_opts;
+	u_int		offset;
+	u_int		saved_negoaddr;
+	uint8_t		iocell_opts[sizeof(ahd->iocell_opts)];
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	saved_negoaddr = ahd_inb(ahd, NEGOADDR);
+	ahd_outb(ahd, NEGOADDR, devinfo->target);
+	period = tinfo->period;
+	offset = tinfo->offset;
+	memcpy(iocell_opts, ahd->iocell_opts, sizeof(ahd->iocell_opts)); 
+	ppr_opts = tinfo->ppr_options & (MSG_EXT_PPR_QAS_REQ|MSG_EXT_PPR_DT_REQ
+					|MSG_EXT_PPR_IU_REQ|MSG_EXT_PPR_RTI);
+	con_opts = 0;
+	if (period == 0)
+		period = AHD_SYNCRATE_ASYNC;
+	if (period == AHD_SYNCRATE_160) {
+
+		if ((ahd->bugs & AHD_PACED_NEGTABLE_BUG) != 0) {
+			/*
+			 * When the SPI4 spec was finalized, PACE transfers
+			 * was not made a configurable option in the PPR
+			 * message.  Instead it is assumed to be enabled for
+			 * any syncrate faster than 80MHz.  Nevertheless,
+			 * Harpoon2A4 allows this to be configurable.
+			 *
+			 * Harpoon2A4 also assumes at most 2 data bytes per
+			 * negotiated REQ/ACK offset.  Paced transfers take
+			 * 4, so we must adjust our offset.
+			 */
+			ppr_opts |= PPROPT_PACE;
+			offset *= 2;
+
+			/*
+			 * Harpoon2A assumed that there would be a
+			 * fallback rate between 160MHz and 80Mhz,
+			 * so 7 is used as the period factor rather
+			 * than 8 for 160MHz.
+			 */
+			period = AHD_SYNCRATE_REVA_160;
+		}
+		if ((tinfo->ppr_options & MSG_EXT_PPR_PCOMP_EN) == 0)
+			iocell_opts[AHD_PRECOMP_SLEW_INDEX] &=
+			    ~AHD_PRECOMP_MASK;
+	} else {
+		/*
+		 * Precomp should be disabled for non-paced transfers.
+		 */
+		iocell_opts[AHD_PRECOMP_SLEW_INDEX] &= ~AHD_PRECOMP_MASK;
+
+		if ((ahd->features & AHD_NEW_IOCELL_OPTS) != 0
+		 && (ppr_opts & MSG_EXT_PPR_DT_REQ) != 0) {
+			/*
+			 * Slow down our CRC interval to be
+			 * compatible with devices that can't
+			 * handle a CRC at full speed.
+			 */
+			con_opts |= ENSLOWCRC;
+		}
+	}
+
+	ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PRECOMP_SLEW);
+	ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_PRECOMP_SLEW_INDEX]);
+	ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_AMPLITUDE);
+	ahd_outb(ahd, ANNEXDAT, iocell_opts[AHD_AMPLITUDE_INDEX]);
+
+	ahd_outb(ahd, NEGPERIOD, period);
+	ahd_outb(ahd, NEGPPROPTS, ppr_opts);
+	ahd_outb(ahd, NEGOFFSET, offset);
+
+	if (tinfo->width == MSG_EXT_WDTR_BUS_16_BIT)
+		con_opts |= WIDEXFER;
+
+	/*
+	 * During packetized transfers, the target will
+	 * give us the oportunity to send command packets
+	 * without us asserting attention.
+	 */
+	if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) == 0)
+		con_opts |= ENAUTOATNO;
+	ahd_outb(ahd, NEGCONOPTS, con_opts);
+	ahd_outb(ahd, NEGOADDR, saved_negoaddr);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+/*
+ * When the transfer settings for a connection change, setup for
+ * negotiation in pending SCBs to effect the change as quickly as
+ * possible.  We also cancel any negotiations that are scheduled
+ * for inflight SCBs that have not been started yet.
+ */
+static void
+ahd_update_pending_scbs(struct ahd_softc *ahd)
+{
+	struct		scb *pending_scb;
+	int		pending_scb_count;
+	u_int		scb_tag;
+	int		paused;
+	u_int		saved_scbptr;
+	ahd_mode_state	saved_modes;
+
+	/*
+	 * Traverse the pending SCB list and ensure that all of the
+	 * SCBs there have the proper settings.  We can only safely
+	 * clear the negotiation required flag (setting requires the
+	 * execution queue to be modified) and this is only possible
+	 * if we are not already attempting to select out for this
+	 * SCB.  For this reason, all callers only call this routine
+	 * if we are changing the negotiation settings for the currently
+	 * active transaction on the bus.
+	 */
+	pending_scb_count = 0;
+	LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+		struct ahd_devinfo devinfo;
+		struct hardware_scb *pending_hscb;
+		struct ahd_initiator_tinfo *tinfo;
+		struct ahd_tmode_tstate *tstate;
+
+		ahd_scb_devinfo(ahd, &devinfo, pending_scb);
+		tinfo = ahd_fetch_transinfo(ahd, devinfo.channel,
+					    devinfo.our_scsiid,
+					    devinfo.target, &tstate);
+		pending_hscb = pending_scb->hscb;
+		if ((tstate->auto_negotiate & devinfo.target_mask) == 0
+		 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {
+			pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
+			pending_hscb->control &= ~MK_MESSAGE;
+		}
+		ahd_sync_scb(ahd, pending_scb,
+			     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		pending_scb_count++;
+	}
+
+	if (pending_scb_count == 0)
+		return;
+
+	if (ahd_is_paused(ahd)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahd_pause(ahd);
+	}
+
+	/*
+	 * Force the sequencer to reinitialize the selection for
+	 * the command at the head of the execution queue if it
+	 * has already been setup.  The negotiation changes may
+	 * effect whether we select-out with ATN.
+	 */
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, SCSISEQ0, ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+	saved_scbptr = ahd_get_scbptr(ahd);
+	/* Ensure that the hscbs down on the card match the new information */
+	for (scb_tag = 0; scb_tag < ahd->scb_data.maxhscbs; scb_tag++) {
+		struct	hardware_scb *pending_hscb;
+		u_int	control;
+
+		pending_scb = ahd_lookup_scb(ahd, scb_tag);
+		if (pending_scb == NULL)
+			continue;
+		ahd_set_scbptr(ahd, scb_tag);
+		pending_hscb = pending_scb->hscb;
+		control = ahd_inb_scbram(ahd, SCB_CONTROL);
+		control &= ~MK_MESSAGE;
+		control |= pending_hscb->control & MK_MESSAGE;
+		ahd_outb(ahd, SCB_CONTROL, control);
+	}
+	ahd_set_scbptr(ahd, saved_scbptr);
+	ahd_restore_modes(ahd, saved_modes);
+
+	if (paused == 0)
+		ahd_unpause(ahd);
+}
+
+/**************************** Pathing Information *****************************/
+static void
+ahd_fetch_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	ahd_mode_state	saved_modes;
+	u_int		saved_scsiid;
+	role_t		role;
+	int		our_id;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	if (ahd_inb(ahd, SSTAT0) & TARGET)
+		role = ROLE_TARGET;
+	else
+		role = ROLE_INITIATOR;
+
+	if (role == ROLE_TARGET
+	 && (ahd_inb(ahd, SEQ_FLAGS) & CMDPHASE_PENDING) != 0) {
+		/* We were selected, so pull our id from TARGIDIN */
+		our_id = ahd_inb(ahd, TARGIDIN) & OID;
+	} else if (role == ROLE_TARGET)
+		our_id = ahd_inb(ahd, TOWNID);
+	else
+		our_id = ahd_inb(ahd, IOWNID);
+
+	saved_scsiid = ahd_inb(ahd, SAVED_SCSIID);
+	ahd_compile_devinfo(devinfo,
+			    our_id,
+			    SCSIID_TARGET(ahd, saved_scsiid),
+			    ahd_inb(ahd, SAVED_LUN),
+			    SCSIID_CHANNEL(ahd, saved_scsiid),
+			    role);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+void
+ahd_print_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	printf("%s:%c:%d:%d: ", ahd_name(ahd), 'A',
+	       devinfo->target, devinfo->lun);
+}
+
+struct ahd_phase_table_entry*
+ahd_lookup_phase_entry(int phase)
+{
+	struct ahd_phase_table_entry *entry;
+	struct ahd_phase_table_entry *last_entry;
+
+	/*
+	 * num_phases doesn't include the default entry which
+	 * will be returned if the phase doesn't match.
+	 */
+	last_entry = &ahd_phase_table[num_phases];
+	for (entry = ahd_phase_table; entry < last_entry; entry++) {
+		if (phase == entry->phase)
+			break;
+	}
+	return (entry);
+}
+
+void
+ahd_compile_devinfo(struct ahd_devinfo *devinfo, u_int our_id, u_int target,
+		    u_int lun, char channel, role_t role)
+{
+	devinfo->our_scsiid = our_id;
+	devinfo->target = target;
+	devinfo->lun = lun;
+	devinfo->target_offset = target;
+	devinfo->channel = channel;
+	devinfo->role = role;
+	if (channel == 'B')
+		devinfo->target_offset += 8;
+	devinfo->target_mask = (0x01 << devinfo->target_offset);
+}
+
+static void
+ahd_scb_devinfo(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		struct scb *scb)
+{
+	role_t	role;
+	int	our_id;
+
+	our_id = SCSIID_OUR_ID(scb->hscb->scsiid);
+	role = ROLE_INITIATOR;
+	if ((scb->hscb->control & TARGET_SCB) != 0)
+		role = ROLE_TARGET;
+	ahd_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahd, scb),
+			    SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahd, scb), role);
+}
+
+
+/************************ Message Phase Processing ****************************/
+/*
+ * When an initiator transaction with the MK_MESSAGE flag either reconnects
+ * or enters the initial message out phase, we are interrupted.  Fill our
+ * outgoing message buffer with the appropriate message and beging handing
+ * the message phase(s) manually.
+ */
+static void
+ahd_setup_initiator_msgout(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+			   struct scb *scb)
+{
+	/*
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */
+	ahd->msgout_index = 0;
+	ahd->msgout_len = 0;
+
+	if (ahd_currently_packetized(ahd))
+		ahd->msg_flags |= MSG_FLAG_PACKETIZED;
+
+	if (ahd->send_msg_perror
+	 && ahd_inb(ahd, MSG_OUT) == HOST_MSG) {
+		ahd->msgout_buf[ahd->msgout_index++] = ahd->send_msg_perror;
+		ahd->msgout_len++;
+		ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+			printf("Setting up for Parity Error delivery\n");
+#endif
+		return;
+	} else if (scb == NULL) {
+		printf("%s: WARNING. No pending message for "
+		       "I_T msgin.  Issuing NO-OP\n", ahd_name(ahd));
+		ahd->msgout_buf[ahd->msgout_index++] = MSG_NOOP;
+		ahd->msgout_len++;
+		ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		return;
+	}
+
+	if ((scb->flags & SCB_DEVICE_RESET) == 0
+	 && (scb->flags & SCB_PACKETIZED) == 0
+	 && ahd_inb(ahd, MSG_OUT) == MSG_IDENTIFYFLAG) {
+		u_int identify_msg;
+
+		identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb);
+		if ((scb->hscb->control & DISCENB) != 0)
+			identify_msg |= MSG_IDENTIFY_DISCFLAG;
+		ahd->msgout_buf[ahd->msgout_index++] = identify_msg;
+		ahd->msgout_len++;
+
+		if ((scb->hscb->control & TAG_ENB) != 0) {
+			ahd->msgout_buf[ahd->msgout_index++] =
+			    scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE);
+			ahd->msgout_buf[ahd->msgout_index++] = SCB_GET_TAG(scb);
+			ahd->msgout_len += 2;
+		}
+	}
+
+	if (scb->flags & SCB_DEVICE_RESET) {
+		ahd->msgout_buf[ahd->msgout_index++] = MSG_BUS_DEV_RESET;
+		ahd->msgout_len++;
+		ahd_print_path(ahd, scb);
+		printf("Bus Device Reset Message Sent\n");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahd_outb(ahd, SCSISEQ0, 0);
+	} else if ((scb->flags & SCB_ABORT) != 0) {
+
+		if ((scb->hscb->control & TAG_ENB) != 0) {
+			ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT_TAG;
+		} else {
+			ahd->msgout_buf[ahd->msgout_index++] = MSG_ABORT;
+		}
+		ahd->msgout_len++;
+		ahd_print_path(ahd, scb);
+		printf("Abort%s Message Sent\n",
+		       (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahd_outb(ahd, SCSISEQ0, 0);
+	} else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) {
+		ahd_build_transfer_msg(ahd, devinfo);
+		/*
+		 * Clear our selection hardware in advance of potential
+		 * PPR IU status change busfree.  We may have an entry in
+		 * the waiting Q for this target, and we don't want to go
+		 * about selecting while we handle the busfree and blow
+		 * it away.
+		 */
+		ahd_outb(ahd, SCSISEQ0, 0);
+	} else {
+		printf("ahd_intr: AWAITING_MSG for an SCB that "
+		       "does not have a waiting message\n");
+		printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+		       devinfo->target_mask);
+		panic("SCB = %d, SCB Control = %x:%x, MSG_OUT = %x "
+		      "SCB flags = %x", SCB_GET_TAG(scb), scb->hscb->control,
+		      ahd_inb_scbram(ahd, SCB_CONTROL), ahd_inb(ahd, MSG_OUT),
+		      scb->flags);
+	}
+
+	/*
+	 * Clear the MK_MESSAGE flag from the SCB so we aren't
+	 * asked to send this message again.
+	 */
+	ahd_outb(ahd, SCB_CONTROL,
+		 ahd_inb_scbram(ahd, SCB_CONTROL) & ~MK_MESSAGE);
+	scb->hscb->control &= ~MK_MESSAGE;
+	ahd->msgout_index = 0;
+	ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+}
+
+/*
+ * Build an appropriate transfer negotiation message for the
+ * currently active target.
+ */
+static void
+ahd_build_transfer_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	/*
+	 * We need to initiate transfer negotiations.
+	 * If our current and goal settings are identical,
+	 * we want to renegotiate due to a check condition.
+	 */
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	int	dowide;
+	int	dosync;
+	int	doppr;
+	u_int	period;
+	u_int	ppr_options;
+	u_int	offset;
+
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	/*
+	 * Filter our period based on the current connection.
+	 * If we can't perform DT transfers on this segment (not in LVD
+	 * mode for instance), then our decision to issue a PPR message
+	 * may change.
+	 */
+	period = tinfo->goal.period;
+	offset = tinfo->goal.offset;
+	ppr_options = tinfo->goal.ppr_options;
+	/* Target initiated PPR is not allowed in the SCSI spec */
+	if (devinfo->role == ROLE_TARGET)
+		ppr_options = 0;
+	ahd_devlimited_syncrate(ahd, tinfo, &period,
+				&ppr_options, devinfo->role);
+	dowide = tinfo->curr.width != tinfo->goal.width;
+	dosync = tinfo->curr.offset != offset || tinfo->curr.period != period;
+	/*
+	 * Only use PPR if we have options that need it, even if the device
+	 * claims to support it.  There might be an expander in the way
+	 * that doesn't.
+	 */
+	doppr = ppr_options != 0;
+
+	if (!dowide && !dosync && !doppr) {
+		dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
+		dosync = tinfo->goal.offset != 0;
+	}
+
+	if (!dowide && !dosync && !doppr) {
+		/*
+		 * Force async with a WDTR message if we have a wide bus,
+		 * or just issue an SDTR with a 0 offset.
+		 */
+		if ((ahd->features & AHD_WIDE) != 0)
+			dowide = 1;
+		else
+			dosync = 1;
+
+		if (bootverbose) {
+			ahd_print_devinfo(ahd, devinfo);
+			printf("Ensuring async\n");
+		}
+	}
+	/* Target initiated PPR is not allowed in the SCSI spec */
+	if (devinfo->role == ROLE_TARGET)
+		doppr = 0;
+
+	/*
+	 * Both the PPR message and SDTR message require the
+	 * goal syncrate to be limited to what the target device
+	 * is capable of handling (based on whether an LVD->SE
+	 * expander is on the bus), so combine these two cases.
+	 * Regardless, guarantee that if we are using WDTR and SDTR
+	 * messages that WDTR comes first.
+	 */
+	if (doppr || (dosync && !dowide)) {
+
+		offset = tinfo->goal.offset;
+		ahd_validate_offset(ahd, tinfo, period, &offset,
+				    doppr ? tinfo->goal.width
+					  : tinfo->curr.width,
+				    devinfo->role);
+		if (doppr) {
+			ahd_construct_ppr(ahd, devinfo, period, offset,
+					  tinfo->goal.width, ppr_options);
+		} else {
+			ahd_construct_sdtr(ahd, devinfo, period, offset);
+		}
+	} else {
+		ahd_construct_wdtr(ahd, devinfo, tinfo->goal.width);
+	}
+}
+
+/*
+ * Build a synchronous negotiation message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahd_construct_sdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		   u_int period, u_int offset)
+{
+	if (offset == 0)
+		period = AHD_ASYNC_XFER_PERIOD;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR_LEN;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_SDTR;
+	ahd->msgout_buf[ahd->msgout_index++] = period;
+	ahd->msgout_buf[ahd->msgout_index++] = offset;
+	ahd->msgout_len += 5;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+		       ahd_name(ahd), devinfo->channel, devinfo->target,
+		       devinfo->lun, period, offset);
+	}
+}
+
+/*
+ * Build a wide negotiateion message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahd_construct_wdtr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		   u_int bus_width)
+{
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR_LEN;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_WDTR;
+	ahd->msgout_buf[ahd->msgout_index++] = bus_width;
+	ahd->msgout_len += 4;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+		       ahd_name(ahd), devinfo->channel, devinfo->target,
+		       devinfo->lun, bus_width);
+	}
+}
+
+/*
+ * Build a parallel protocol request message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahd_construct_ppr(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		  u_int period, u_int offset, u_int bus_width,
+		  u_int ppr_options)
+{
+	/*
+	 * Always request precompensation from
+	 * the other target if we are running
+	 * at paced syncrates.
+	 */
+	if (period <= AHD_SYNCRATE_PACED)
+		ppr_options |= MSG_EXT_PPR_PCOMP_EN;
+	if (offset == 0)
+		period = AHD_ASYNC_XFER_PERIOD;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXTENDED;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR_LEN;
+	ahd->msgout_buf[ahd->msgout_index++] = MSG_EXT_PPR;
+	ahd->msgout_buf[ahd->msgout_index++] = period;
+	ahd->msgout_buf[ahd->msgout_index++] = 0;
+	ahd->msgout_buf[ahd->msgout_index++] = offset;
+	ahd->msgout_buf[ahd->msgout_index++] = bus_width;
+	ahd->msgout_buf[ahd->msgout_index++] = ppr_options;
+	ahd->msgout_len += 8;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+		       "offset %x, ppr_options %x\n", ahd_name(ahd),
+		       devinfo->channel, devinfo->target, devinfo->lun,
+		       bus_width, period, offset, ppr_options);
+	}
+}
+
+/*
+ * Clear any active message state.
+ */
+static void
+ahd_clear_msg_state(struct ahd_softc *ahd)
+{
+	ahd_mode_state saved_modes;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd->send_msg_perror = 0;
+	ahd->msg_flags = MSG_FLAG_NONE;
+	ahd->msgout_len = 0;
+	ahd->msgin_index = 0;
+	ahd->msg_type = MSG_TYPE_NONE;
+	if ((ahd_inb(ahd, SCSISIGO) & ATNO) != 0) {
+		/*
+		 * The target didn't care to respond to our
+		 * message request, so clear ATN.
+		 */
+		ahd_outb(ahd, CLRSINT1, CLRATNO);
+	}
+	ahd_outb(ahd, MSG_OUT, MSG_NOOP);
+	ahd_outb(ahd, SEQ_FLAGS2,
+		 ahd_inb(ahd, SEQ_FLAGS2) & ~TARGET_MSG_PENDING);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+/*
+ * Manual message loop handler.
+ */
+static void
+ahd_handle_message_phase(struct ahd_softc *ahd)
+{ 
+	struct	ahd_devinfo devinfo;
+	u_int	bus_phase;
+	int	end_session;
+
+	ahd_fetch_devinfo(ahd, &devinfo);
+	end_session = FALSE;
+	bus_phase = ahd_inb(ahd, LASTPHASE);
+
+	if ((ahd_inb(ahd, LQISTAT2) & LQIPHASE_OUTPKT) != 0) {
+		printf("LQIRETRY for LQIPHASE_OUTPKT\n");
+		ahd_outb(ahd, LQCTL2, LQIRETRY);
+	}
+reswitch:
+	switch (ahd->msg_type) {
+	case MSG_TYPE_INITIATOR_MSGOUT:
+	{
+		int lastbyte;
+		int phasemis;
+		int msgdone;
+
+		if (ahd->msgout_len == 0 && ahd->send_msg_perror == 0)
+			panic("HOST_MSG_LOOP interrupt with no active message");
+
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+			ahd_print_devinfo(ahd, &devinfo);
+			printf("INITIATOR_MSG_OUT");
+		}
+#endif
+		phasemis = bus_phase != P_MESGOUT;
+		if (phasemis) {
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+				printf(" PHASEMIS %s\n",
+				       ahd_lookup_phase_entry(bus_phase)
+							     ->phasemsg);
+			}
+#endif
+			if (bus_phase == P_MESGIN) {
+				/*
+				 * Change gears and see if
+				 * this messages is of interest to
+				 * us or should be passed back to
+				 * the sequencer.
+				 */
+				ahd_outb(ahd, CLRSINT1, CLRATNO);
+				ahd->send_msg_perror = 0;
+				ahd->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+				ahd->msgin_index = 0;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		if (ahd->send_msg_perror) {
+			ahd_outb(ahd, CLRSINT1, CLRATNO);
+			ahd_outb(ahd, CLRSINT1, CLRREQINIT);
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+				printf(" byte 0x%x\n", ahd->send_msg_perror);
+#endif
+			/*
+			 * If we are notifying the target of a CRC error
+			 * during packetized operations, the target is
+			 * within its rights to acknowledge our message
+			 * with a busfree.
+			 */
+			if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0
+			 && ahd->send_msg_perror == MSG_INITIATOR_DET_ERR)
+				ahd->msg_flags |= MSG_FLAG_EXPECT_IDE_BUSFREE;
+
+			ahd_outb(ahd, RETURN_2, ahd->send_msg_perror);
+			ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE);
+			break;
+		}
+
+		msgdone	= ahd->msgout_index == ahd->msgout_len;
+		if (msgdone) {
+			/*
+			 * The target has requested a retry.
+			 * Re-assert ATN, reset our message index to
+			 * 0, and try again.
+			 */
+			ahd->msgout_index = 0;
+			ahd_assert_atn(ahd);
+		}
+
+		lastbyte = ahd->msgout_index == (ahd->msgout_len - 1);
+		if (lastbyte) {
+			/* Last byte is signified by dropping ATN */
+			ahd_outb(ahd, CLRSINT1, CLRATNO);
+		}
+
+		/*
+		 * Clear our interrupt status and present
+		 * the next byte on the bus.
+		 */
+		ahd_outb(ahd, CLRSINT1, CLRREQINIT);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+			printf(" byte 0x%x\n",
+			       ahd->msgout_buf[ahd->msgout_index]);
+#endif
+		ahd_outb(ahd, RETURN_2, ahd->msgout_buf[ahd->msgout_index++]);
+		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_WRITE);
+		break;
+	}
+	case MSG_TYPE_INITIATOR_MSGIN:
+	{
+		int phasemis;
+		int message_done;
+
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+			ahd_print_devinfo(ahd, &devinfo);
+			printf("INITIATOR_MSG_IN");
+		}
+#endif
+		phasemis = bus_phase != P_MESGIN;
+		if (phasemis) {
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+				printf(" PHASEMIS %s\n",
+				       ahd_lookup_phase_entry(bus_phase)
+							     ->phasemsg);
+			}
+#endif
+			ahd->msgin_index = 0;
+			if (bus_phase == P_MESGOUT
+			 && (ahd->send_msg_perror != 0
+			  || (ahd->msgout_len != 0
+			   && ahd->msgout_index == 0))) {
+				ahd->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		/* Pull the byte in without acking it */
+		ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIBUS);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+			printf(" byte 0x%x\n",
+			       ahd->msgin_buf[ahd->msgin_index]);
+#endif
+
+		message_done = ahd_parse_msg(ahd, &devinfo);
+
+		if (message_done) {
+			/*
+			 * Clear our incoming message buffer in case there
+			 * is another message following this one.
+			 */
+			ahd->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response,
+			 * assert ATN so the target takes us to the
+			 * message out phase.
+			 */
+			if (ahd->msgout_len != 0) {
+#ifdef AHD_DEBUG
+				if ((ahd_debug & AHD_SHOW_MESSAGES) != 0) {
+					ahd_print_devinfo(ahd, &devinfo);
+					printf("Asserting ATN for response\n");
+				}
+#endif
+				ahd_assert_atn(ahd);
+			}
+		} else 
+			ahd->msgin_index++;
+
+		if (message_done == MSGLOOP_TERMINATED) {
+			end_session = TRUE;
+		} else {
+			/* Ack the byte */
+			ahd_outb(ahd, CLRSINT1, CLRREQINIT);
+			ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_READ);
+		}
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGIN:
+	{
+		int msgdone;
+		int msgout_request;
+
+		/*
+		 * By default, the message loop will continue.
+		 */
+		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
+
+		if (ahd->msgout_len == 0)
+			panic("Target MSGIN with no active message");
+
+		/*
+		 * If we interrupted a mesgout session, the initiator
+		 * will not know this until our first REQ.  So, we
+		 * only honor mesgout requests after we've sent our
+		 * first byte.
+		 */
+		if ((ahd_inb(ahd, SCSISIGI) & ATNI) != 0
+		 && ahd->msgout_index > 0)
+			msgout_request = TRUE;
+		else
+			msgout_request = FALSE;
+
+		if (msgout_request) {
+
+			/*
+			 * Change gears and see if
+			 * this messages is of interest to
+			 * us or should be passed back to
+			 * the sequencer.
+			 */
+			ahd->msg_type = MSG_TYPE_TARGET_MSGOUT;
+			ahd_outb(ahd, SCSISIGO, P_MESGOUT | BSYO);
+			ahd->msgin_index = 0;
+			/* Dummy read to REQ for first byte */
+			ahd_inb(ahd, SCSIDAT);
+			ahd_outb(ahd, SXFRCTL0,
+				 ahd_inb(ahd, SXFRCTL0) | SPIOEN);
+			break;
+		}
+
+		msgdone = ahd->msgout_index == ahd->msgout_len;
+		if (msgdone) {
+			ahd_outb(ahd, SXFRCTL0,
+				 ahd_inb(ahd, SXFRCTL0) & ~SPIOEN);
+			end_session = TRUE;
+			break;
+		}
+
+		/*
+		 * Present the next byte on the bus.
+		 */
+		ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) | SPIOEN);
+		ahd_outb(ahd, SCSIDAT, ahd->msgout_buf[ahd->msgout_index++]);
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGOUT:
+	{
+		int lastbyte;
+		int msgdone;
+
+		/*
+		 * By default, the message loop will continue.
+		 */
+		ahd_outb(ahd, RETURN_1, CONT_MSG_LOOP_TARG);
+
+		/*
+		 * The initiator signals that this is
+		 * the last byte by dropping ATN.
+		 */
+		lastbyte = (ahd_inb(ahd, SCSISIGI) & ATNI) == 0;
+
+		/*
+		 * Read the latched byte, but turn off SPIOEN first
+		 * so that we don't inadvertently cause a REQ for the
+		 * next byte.
+		 */
+		ahd_outb(ahd, SXFRCTL0, ahd_inb(ahd, SXFRCTL0) & ~SPIOEN);
+		ahd->msgin_buf[ahd->msgin_index] = ahd_inb(ahd, SCSIDAT);
+		msgdone = ahd_parse_msg(ahd, &devinfo);
+		if (msgdone == MSGLOOP_TERMINATED) {
+			/*
+			 * The message is *really* done in that it caused
+			 * us to go to bus free.  The sequencer has already
+			 * been reset at this point, so pull the ejection
+			 * handle.
+			 */
+			return;
+		}
+		
+		ahd->msgin_index++;
+
+		/*
+		 * XXX Read spec about initiator dropping ATN too soon
+		 *     and use msgdone to detect it.
+		 */
+		if (msgdone == MSGLOOP_MSGCOMPLETE) {
+			ahd->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response, transition
+			 * to the Message in phase and send it.
+			 */
+			if (ahd->msgout_len != 0) {
+				ahd_outb(ahd, SCSISIGO, P_MESGIN | BSYO);
+				ahd_outb(ahd, SXFRCTL0,
+					 ahd_inb(ahd, SXFRCTL0) | SPIOEN);
+				ahd->msg_type = MSG_TYPE_TARGET_MSGIN;
+				ahd->msgin_index = 0;
+				break;
+			}
+		}
+
+		if (lastbyte)
+			end_session = TRUE;
+		else {
+			/* Ask for the next byte. */
+			ahd_outb(ahd, SXFRCTL0,
+				 ahd_inb(ahd, SXFRCTL0) | SPIOEN);
+		}
+
+		break;
+	}
+	default:
+		panic("Unknown REQINIT message type");
+	}
+
+	if (end_session) {
+		if ((ahd->msg_flags & MSG_FLAG_PACKETIZED) != 0) {
+			printf("%s: Returning to Idle Loop\n",
+			       ahd_name(ahd));
+			ahd_clear_msg_state(ahd);
+
+			/*
+			 * Perform the equivalent of a clear_target_state.
+			 */
+			ahd_outb(ahd, LASTPHASE, P_BUSFREE);
+			ahd_outb(ahd, SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT);
+			ahd_outb(ahd, SEQCTL0, FASTMODE|SEQRESET);
+		} else {
+			ahd_clear_msg_state(ahd);
+			ahd_outb(ahd, RETURN_1, EXIT_MSG_LOOP);
+		}
+	}
+}
+
+/*
+ * See if we sent a particular extended message to the target.
+ * If "full" is true, return true only if the target saw the full
+ * message.  If "full" is false, return true if the target saw at
+ * least the first byte of the message.
+ */
+static int
+ahd_sent_msg(struct ahd_softc *ahd, ahd_msgtype type, u_int msgval, int full)
+{
+	int found;
+	u_int index;
+
+	found = FALSE;
+	index = 0;
+
+	while (index < ahd->msgout_len) {
+		if (ahd->msgout_buf[index] == MSG_EXTENDED) {
+			u_int end_index;
+
+			end_index = index + 1 + ahd->msgout_buf[index + 1];
+			if (ahd->msgout_buf[index+2] == msgval
+			 && type == AHDMSG_EXT) {
+
+				if (full) {
+					if (ahd->msgout_index > end_index)
+						found = TRUE;
+				} else if (ahd->msgout_index > index)
+					found = TRUE;
+			}
+			index = end_index;
+		} else if (ahd->msgout_buf[index] >= MSG_SIMPLE_TASK
+			&& ahd->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
+
+			/* Skip tag type and tag id or residue param*/
+			index += 2;
+		} else {
+			/* Single byte message */
+			if (type == AHDMSG_1B
+			 && ahd->msgout_index > index
+			 && (ahd->msgout_buf[index] == msgval
+			  || ((ahd->msgout_buf[index] & MSG_IDENTIFYFLAG) != 0
+			   && msgval == MSG_IDENTIFYFLAG)))
+				found = TRUE;
+			index++;
+		}
+
+		if (found)
+			break;
+	}
+	return (found);
+}
+
+/*
+ * Wait for a complete incoming message, parse it, and respond accordingly.
+ */
+static int
+ahd_parse_msg(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	int	reject;
+	int	done;
+	int	response;
+
+	done = MSGLOOP_IN_PROG;
+	response = FALSE;
+	reject = FALSE;
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	/*
+	 * Parse as much of the message as is available,
+	 * rejecting it if we don't support it.  When
+	 * the entire message is available and has been
+	 * handled, return MSGLOOP_MSGCOMPLETE, indicating
+	 * that we have parsed an entire message.
+	 *
+	 * In the case of extended messages, we accept the length
+	 * byte outright and perform more checking once we know the
+	 * extended message type.
+	 */
+	switch (ahd->msgin_buf[0]) {
+	case MSG_DISCONNECT:
+	case MSG_SAVEDATAPOINTER:
+	case MSG_CMDCOMPLETE:
+	case MSG_RESTOREPOINTERS:
+	case MSG_IGN_WIDE_RESIDUE:
+		/*
+		 * End our message loop as these are messages
+		 * the sequencer handles on its own.
+		 */
+		done = MSGLOOP_TERMINATED;
+		break;
+	case MSG_MESSAGE_REJECT:
+		response = ahd_handle_msg_reject(ahd, devinfo);
+		/* FALLTHROUGH */
+	case MSG_NOOP:
+		done = MSGLOOP_MSGCOMPLETE;
+		break;
+	case MSG_EXTENDED:
+	{
+		/* Wait for enough of the message to begin validation */
+		if (ahd->msgin_index < 2)
+			break;
+		switch (ahd->msgin_buf[2]) {
+		case MSG_EXT_SDTR:
+		{
+			u_int	 period;
+			u_int	 ppr_options;
+			u_int	 offset;
+			u_int	 saved_offset;
+			
+			if (ahd->msgin_buf[1] != MSG_EXT_SDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have both args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_SDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahd->msgin_index < (MSG_EXT_SDTR_LEN + 1))
+				break;
+
+			period = ahd->msgin_buf[3];
+			ppr_options = 0;
+			saved_offset = offset = ahd->msgin_buf[4];
+			ahd_devlimited_syncrate(ahd, tinfo, &period,
+						&ppr_options, devinfo->role);
+			ahd_validate_offset(ahd, tinfo, period, &offset,
+					    tinfo->curr.width, devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received "
+				       "SDTR period %x, offset %x\n\t"
+				       "Filtered to period %x, offset %x\n",
+				       ahd_name(ahd), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       ahd->msgin_buf[3], saved_offset,
+				       period, offset);
+			}
+			ahd_set_syncrate(ahd, devinfo, period,
+					 offset, ppr_options,
+					 AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+					 /*paused*/TRUE);
+
+			/*
+			 * See if we initiated Sync Negotiation
+			 * and didn't have to fall down to async
+			 * transfers.
+			 */
+			if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, TRUE)) {
+				/* We started it */
+				if (saved_offset != offset) {
+					/* Went too low - force async */
+					reject = TRUE;
+				}
+			} else {
+				/*
+				 * Send our own SDTR in reply
+				 */
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated SDTR\n",
+					       ahd_name(ahd), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahd->msgout_index = 0;
+				ahd->msgout_len = 0;
+				ahd_construct_sdtr(ahd, devinfo,
+						   period, offset);
+				ahd->msgout_index = 0;
+				response = TRUE;
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_WDTR:
+		{
+			u_int bus_width;
+			u_int saved_width;
+			u_int sending_reply;
+
+			sending_reply = FALSE;
+			if (ahd->msgin_buf[1] != MSG_EXT_WDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have our arg before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_WDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahd->msgin_index < (MSG_EXT_WDTR_LEN + 1))
+				break;
+
+			bus_width = ahd->msgin_buf[3];
+			saved_width = bus_width;
+			ahd_validate_width(ahd, tinfo, &bus_width,
+					   devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received WDTR "
+				       "%x filtered to %x\n",
+				       ahd_name(ahd), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       saved_width, bus_width);
+			}
+
+			if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, TRUE)) {
+				/*
+				 * Don't send a WDTR back to the
+				 * target, since we asked first.
+				 * If the width went higher than our
+				 * request, reject it.
+				 */
+				if (saved_width > bus_width) {
+					reject = TRUE;
+					printf("(%s:%c:%d:%d): requested %dBit "
+					       "transfers.  Rejecting...\n",
+					       ahd_name(ahd), devinfo->channel,
+					       devinfo->target, devinfo->lun,
+					       8 * (0x01 << bus_width));
+					bus_width = 0;
+				}
+			} else {
+				/*
+				 * Send our own WDTR in reply
+				 */
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated WDTR\n",
+					       ahd_name(ahd), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahd->msgout_index = 0;
+				ahd->msgout_len = 0;
+				ahd_construct_wdtr(ahd, devinfo, bus_width);
+				ahd->msgout_index = 0;
+				response = TRUE;
+				sending_reply = TRUE;
+			}
+			/*
+			 * After a wide message, we are async, but
+			 * some devices don't seem to honor this portion
+			 * of the spec.  Force a renegotiation of the
+			 * sync component of our transfer agreement even
+			 * if our goal is async.  By updating our width
+			 * after forcing the negotiation, we avoid
+			 * renegotiating for width.
+			 */
+			ahd_update_neg_request(ahd, devinfo, tstate,
+					       tinfo, AHD_NEG_ALWAYS);
+			ahd_set_width(ahd, devinfo, bus_width,
+				      AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+				      /*paused*/TRUE);
+			if (sending_reply == FALSE && reject == FALSE) {
+
+				/*
+				 * We will always have an SDTR to send.
+				 */
+				ahd->msgout_index = 0;
+				ahd->msgout_len = 0;
+				ahd_build_transfer_msg(ahd, devinfo);
+				ahd->msgout_index = 0;
+				response = TRUE;
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_PPR:
+		{
+			u_int	period;
+			u_int	offset;
+			u_int	bus_width;
+			u_int	ppr_options;
+			u_int	saved_width;
+			u_int	saved_offset;
+			u_int	saved_ppr_options;
+
+			if (ahd->msgin_buf[1] != MSG_EXT_PPR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have all args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_PPR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahd->msgin_index < (MSG_EXT_PPR_LEN + 1))
+				break;
+
+			period = ahd->msgin_buf[3];
+			offset = ahd->msgin_buf[5];
+			bus_width = ahd->msgin_buf[6];
+			saved_width = bus_width;
+			ppr_options = ahd->msgin_buf[7];
+			/*
+			 * According to the spec, a DT only
+			 * period factor with no DT option
+			 * set implies async.
+			 */
+			if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+			 && period <= 9)
+				offset = 0;
+			saved_ppr_options = ppr_options;
+			saved_offset = offset;
+
+			/*
+			 * Transfer options are only available if we
+			 * are negotiating wide.
+			 */
+			if (bus_width == 0)
+				ppr_options &= MSG_EXT_PPR_QAS_REQ;
+
+			ahd_validate_width(ahd, tinfo, &bus_width,
+					   devinfo->role);
+			ahd_devlimited_syncrate(ahd, tinfo, &period,
+						&ppr_options, devinfo->role);
+			ahd_validate_offset(ahd, tinfo, period, &offset,
+					    bus_width, devinfo->role);
+
+			if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, TRUE)) {
+				/*
+				 * If we are unable to do any of the
+				 * requested options (we went too low),
+				 * then we'll have to reject the message.
+				 */
+				if (saved_width > bus_width
+				 || saved_offset != offset
+				 || saved_ppr_options != ppr_options) {
+					reject = TRUE;
+					period = 0;
+					offset = 0;
+					bus_width = 0;
+					ppr_options = 0;
+				}
+			} else {
+				if (devinfo->role != ROLE_TARGET)
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated PPR\n",
+					       ahd_name(ahd), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				else
+					printf("(%s:%c:%d:%d): Initiator "
+					       "Initiated PPR\n",
+					       ahd_name(ahd), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				ahd->msgout_index = 0;
+				ahd->msgout_len = 0;
+				ahd_construct_ppr(ahd, devinfo, period, offset,
+						  bus_width, ppr_options);
+				ahd->msgout_index = 0;
+				response = TRUE;
+			}
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received PPR width %x, "
+				       "period %x, offset %x,options %x\n"
+				       "\tFiltered to width %x, period %x, "
+				       "offset %x, options %x\n",
+				       ahd_name(ahd), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       saved_width, ahd->msgin_buf[3],
+				       saved_offset, saved_ppr_options,
+				       bus_width, period, offset, ppr_options);
+			}
+			ahd_set_width(ahd, devinfo, bus_width,
+				      AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+				      /*paused*/TRUE);
+			ahd_set_syncrate(ahd, devinfo, period,
+					 offset, ppr_options,
+					 AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+					 /*paused*/TRUE);
+
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		default:
+			/* Unknown extended message.  Reject it. */
+			reject = TRUE;
+			break;
+		}
+		break;
+	}
+#ifdef AHD_TARGET_MODE
+	case MSG_BUS_DEV_RESET:
+		ahd_handle_devreset(ahd, devinfo, CAM_LUN_WILDCARD,
+				    CAM_BDR_SENT,
+				    "Bus Device Reset Received",
+				    /*verbose_level*/0);
+		ahd_restart(ahd);
+		done = MSGLOOP_TERMINATED;
+		break;
+	case MSG_ABORT_TAG:
+	case MSG_ABORT:
+	case MSG_CLEAR_QUEUE:
+	{
+		int tag;
+
+		/* Target mode messages */
+		if (devinfo->role != ROLE_TARGET) {
+			reject = TRUE;
+			break;
+		}
+		tag = SCB_LIST_NULL;
+		if (ahd->msgin_buf[0] == MSG_ABORT_TAG)
+			tag = ahd_inb(ahd, INITIATOR_TAG);
+		ahd_abort_scbs(ahd, devinfo->target, devinfo->channel,
+			       devinfo->lun, tag, ROLE_TARGET,
+			       CAM_REQ_ABORTED);
+
+		tstate = ahd->enabled_targets[devinfo->our_scsiid];
+		if (tstate != NULL) {
+			struct ahd_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[devinfo->lun];
+			if (lstate != NULL) {
+				ahd_queue_lstate_event(ahd, lstate,
+						       devinfo->our_scsiid,
+						       ahd->msgin_buf[0],
+						       /*arg*/tag);
+				ahd_send_lstate_events(ahd, lstate);
+			}
+		}
+		ahd_restart(ahd);
+		done = MSGLOOP_TERMINATED;
+		break;
+	}
+#endif
+	case MSG_QAS_REQUEST:
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+			printf("%s: QAS request.  SCSISIGI == 0x%x\n",
+			       ahd_name(ahd), ahd_inb(ahd, SCSISIGI));
+#endif
+		ahd->msg_flags |= MSG_FLAG_EXPECT_QASREJ_BUSFREE;
+		/* FALLTHROUGH */
+	case MSG_TERM_IO_PROC:
+	default:
+		reject = TRUE;
+		break;
+	}
+
+	if (reject) {
+		/*
+		 * Setup to reject the message.
+		 */
+		ahd->msgout_index = 0;
+		ahd->msgout_len = 1;
+		ahd->msgout_buf[0] = MSG_MESSAGE_REJECT;
+		done = MSGLOOP_MSGCOMPLETE;
+		response = TRUE;
+	}
+
+	if (done != MSGLOOP_IN_PROG && !response)
+		/* Clear the outgoing message buffer */
+		ahd->msgout_len = 0;
+
+	return (done);
+}
+
+/*
+ * Process a message reject message.
+ */
+static int
+ahd_handle_msg_reject(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	/*
+	 * What we care about here is if we had an
+	 * outstanding SDTR or WDTR message for this
+	 * target.  If we did, this is a signal that
+	 * the target is refusing negotiation.
+	 */
+	struct scb *scb;
+	struct ahd_initiator_tinfo *tinfo;
+	struct ahd_tmode_tstate *tstate;
+	u_int scb_index;
+	u_int last_msg;
+	int   response = 0;
+
+	scb_index = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scb_index);
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	/* Might be necessary */
+	last_msg = ahd_inb(ahd, LAST_MSG);
+
+	if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) {
+		if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_PPR, /*full*/TRUE)
+		 && tinfo->goal.period <= AHD_SYNCRATE_PACED) {
+			/*
+			 * Target may not like our SPI-4 PPR Options.
+			 * Attempt to negotiate 80MHz which will turn
+			 * off these options.
+			 */
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): PPR Rejected. "
+				       "Trying simple U160 PPR\n",
+				       ahd_name(ahd), devinfo->channel,
+				       devinfo->target, devinfo->lun);
+			}
+			tinfo->goal.period = AHD_SYNCRATE_DT;
+			tinfo->goal.ppr_options &= MSG_EXT_PPR_IU_REQ
+						|  MSG_EXT_PPR_QAS_REQ
+						|  MSG_EXT_PPR_DT_REQ;
+		} else {
+			/*
+			 * Target does not support the PPR message.
+			 * Attempt to negotiate SPI-2 style.
+			 */
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): PPR Rejected. "
+				       "Trying WDTR/SDTR\n",
+				       ahd_name(ahd), devinfo->channel,
+				       devinfo->target, devinfo->lun);
+			}
+			tinfo->goal.ppr_options = 0;
+			tinfo->curr.transport_version = 2;
+			tinfo->goal.transport_version = 2;
+		}
+		ahd->msgout_index = 0;
+		ahd->msgout_len = 0;
+		ahd_build_transfer_msg(ahd, devinfo);
+		ahd->msgout_index = 0;
+		response = 1;
+	} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
+
+		/* note 8bit xfers */
+		printf("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
+		       "8bit transfers\n", ahd_name(ahd),
+		       devinfo->channel, devinfo->target, devinfo->lun);
+		ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+			      AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+			      /*paused*/TRUE);
+		/*
+		 * No need to clear the sync rate.  If the target
+		 * did not accept the command, our syncrate is
+		 * unaffected.  If the target started the negotiation,
+		 * but rejected our response, we already cleared the
+		 * sync rate before sending our WDTR.
+		 */
+		if (tinfo->goal.offset != tinfo->curr.offset) {
+
+			/* Start the sync negotiation */
+			ahd->msgout_index = 0;
+			ahd->msgout_len = 0;
+			ahd_build_transfer_msg(ahd, devinfo);
+			ahd->msgout_index = 0;
+			response = 1;
+		}
+	} else if (ahd_sent_msg(ahd, AHDMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) {
+		/* note asynch xfers and clear flag */
+		ahd_set_syncrate(ahd, devinfo, /*period*/0,
+				 /*offset*/0, /*ppr_options*/0,
+				 AHD_TRANS_ACTIVE|AHD_TRANS_GOAL,
+				 /*paused*/TRUE);
+		printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+		       "Using asynchronous transfers\n",
+		       ahd_name(ahd), devinfo->channel,
+		       devinfo->target, devinfo->lun);
+	} else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) {
+		int tag_type;
+		int mask;
+
+		tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
+
+		if (tag_type == MSG_SIMPLE_TASK) {
+			printf("(%s:%c:%d:%d): refuses tagged commands.  "
+			       "Performing non-tagged I/O\n", ahd_name(ahd),
+			       devinfo->channel, devinfo->target, devinfo->lun);
+			ahd_set_tags(ahd, devinfo, AHD_QUEUE_NONE);
+			mask = ~0x23;
+		} else {
+			printf("(%s:%c:%d:%d): refuses %s tagged commands.  "
+			       "Performing simple queue tagged I/O only\n",
+			       ahd_name(ahd), devinfo->channel, devinfo->target,
+			       devinfo->lun, tag_type == MSG_ORDERED_TASK
+			       ? "ordered" : "head of queue");
+			ahd_set_tags(ahd, devinfo, AHD_QUEUE_BASIC);
+			mask = ~0x03;
+		}
+
+		/*
+		 * Resend the identify for this CCB as the target
+		 * may believe that the selection is invalid otherwise.
+		 */
+		ahd_outb(ahd, SCB_CONTROL,
+			 ahd_inb_scbram(ahd, SCB_CONTROL) & mask);
+	 	scb->hscb->control &= mask;
+		ahd_set_transaction_tag(scb, /*enabled*/FALSE,
+					/*type*/MSG_SIMPLE_TASK);
+		ahd_outb(ahd, MSG_OUT, MSG_IDENTIFYFLAG);
+		ahd_assert_atn(ahd);
+		ahd_busy_tcl(ahd, BUILD_TCL(scb->hscb->scsiid, devinfo->lun),
+			     SCB_GET_TAG(scb));
+
+		/*
+		 * Requeue all tagged commands for this target
+		 * currently in our posession so they can be
+		 * converted to untagged commands.
+		 */
+		ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),
+				   SCB_GET_CHANNEL(ahd, scb),
+				   SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL,
+				   ROLE_INITIATOR, CAM_REQUEUE_REQ,
+				   SEARCH_COMPLETE);
+	} else if (ahd_sent_msg(ahd, AHDMSG_1B, MSG_IDENTIFYFLAG, TRUE)) {
+		/*
+		 * Most likely the device believes that we had
+		 * previously negotiated packetized.
+		 */
+		ahd->msg_flags |= MSG_FLAG_EXPECT_PPR_BUSFREE
+			       |  MSG_FLAG_IU_REQ_CHANGED;
+
+		ahd_force_renegotiation(ahd, devinfo);
+		ahd->msgout_index = 0;
+		ahd->msgout_len = 0;
+		ahd_build_transfer_msg(ahd, devinfo);
+		ahd->msgout_index = 0;
+		response = 1;
+	} else {
+		/*
+		 * Otherwise, we ignore it.
+		 */
+		printf("%s:%c:%d: Message reject for %x -- ignored\n",
+		       ahd_name(ahd), devinfo->channel, devinfo->target,
+		       last_msg);
+	}
+	return (response);
+}
+
+/*
+ * Process an ingnore wide residue message.
+ */
+static void
+ahd_handle_ign_wide_residue(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	u_int scb_index;
+	struct scb *scb;
+
+	scb_index = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scb_index);
+	/*
+	 * XXX Actually check data direction in the sequencer?
+	 * Perhaps add datadir to some spare bits in the hscb?
+	 */
+	if ((ahd_inb(ahd, SEQ_FLAGS) & DPHASE) == 0
+	 || ahd_get_transfer_dir(scb) != CAM_DIR_IN) {
+		/*
+		 * Ignore the message if we haven't
+		 * seen an appropriate data phase yet.
+		 */
+	} else {
+		/*
+		 * If the residual occurred on the last
+		 * transfer and the transfer request was
+		 * expected to end on an odd count, do
+		 * nothing.  Otherwise, subtract a byte
+		 * and update the residual count accordingly.
+		 */
+		uint32_t sgptr;
+
+		sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR);
+		if ((sgptr & SG_LIST_NULL) != 0
+		 && (ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE)
+		     & SCB_XFERLEN_ODD) != 0) {
+			/*
+			 * If the residual occurred on the last
+			 * transfer and the transfer request was
+			 * expected to end on an odd count, do
+			 * nothing.
+			 */
+		} else {
+			uint32_t data_cnt;
+			uint64_t data_addr;
+			uint32_t sglen;
+
+			/* Pull in the rest of the sgptr */
+			sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR);
+			data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT);
+			if ((sgptr & SG_LIST_NULL) != 0) {
+				/*
+				 * The residual data count is not updated
+				 * for the command run to completion case.
+				 * Explicitly zero the count.
+				 */
+				data_cnt &= ~AHD_SG_LEN_MASK;
+			}
+			data_addr = ahd_inq(ahd, SHADDR);
+			data_cnt += 1;
+			data_addr -= 1;
+			sgptr &= SG_PTR_MASK;
+			if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+				struct ahd_dma64_seg *sg;
+
+				sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+
+				/*
+				 * The residual sg ptr points to the next S/G
+				 * to load so we must go back one.
+				 */
+				sg--;
+				sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK;
+				if (sg != scb->sg_list
+				 && sglen < (data_cnt & AHD_SG_LEN_MASK)) {
+
+					sg--;
+					sglen = ahd_le32toh(sg->len);
+					/*
+					 * Preserve High Address and SG_LIST
+					 * bits while setting the count to 1.
+					 */
+					data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK));
+					data_addr = ahd_le64toh(sg->addr)
+						  + (sglen & AHD_SG_LEN_MASK)
+						  - 1;
+
+					/*
+					 * Increment sg so it points to the
+					 * "next" sg.
+					 */
+					sg++;
+					sgptr = ahd_sg_virt_to_bus(ahd, scb,
+								   sg);
+				}
+			} else {
+				struct ahd_dma_seg *sg;
+
+				sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+
+				/*
+				 * The residual sg ptr points to the next S/G
+				 * to load so we must go back one.
+				 */
+				sg--;
+				sglen = ahd_le32toh(sg->len) & AHD_SG_LEN_MASK;
+				if (sg != scb->sg_list
+				 && sglen < (data_cnt & AHD_SG_LEN_MASK)) {
+
+					sg--;
+					sglen = ahd_le32toh(sg->len);
+					/*
+					 * Preserve High Address and SG_LIST
+					 * bits while setting the count to 1.
+					 */
+					data_cnt = 1|(sglen&(~AHD_SG_LEN_MASK));
+					data_addr = ahd_le32toh(sg->addr)
+						  + (sglen & AHD_SG_LEN_MASK)
+						  - 1;
+
+					/*
+					 * Increment sg so it points to the
+					 * "next" sg.
+					 */
+					sg++;
+					sgptr = ahd_sg_virt_to_bus(ahd, scb,
+								  sg);
+				}
+			}
+			/*
+			 * Toggle the "oddness" of the transfer length
+			 * to handle this mid-transfer ignore wide
+			 * residue.  This ensures that the oddness is
+			 * correct for subsequent data transfers.
+			 */
+			ahd_outb(ahd, SCB_TASK_ATTRIBUTE,
+			    ahd_inb_scbram(ahd, SCB_TASK_ATTRIBUTE)
+			    ^ SCB_XFERLEN_ODD);
+
+			ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr);
+			ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt);
+			/*
+			 * The FIFO's pointers will be updated if/when the
+			 * sequencer re-enters a data phase.
+			 */
+		}
+	}
+}
+
+
+/*
+ * Reinitialize the data pointers for the active transfer
+ * based on its current residual.
+ */
+static void
+ahd_reinitialize_dataptrs(struct ahd_softc *ahd)
+{
+	struct		 scb *scb;
+	ahd_mode_state	 saved_modes;
+	u_int		 scb_index;
+	u_int		 wait;
+	uint32_t	 sgptr;
+	uint32_t	 resid;
+	uint64_t	 dataptr;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK,
+			 AHD_MODE_DFF0_MSK|AHD_MODE_DFF1_MSK);
+			 
+	scb_index = ahd_get_scbptr(ahd);
+	scb = ahd_lookup_scb(ahd, scb_index);
+
+	/*
+	 * Release and reacquire the FIFO so we
+	 * have a clean slate.
+	 */
+	ahd_outb(ahd, DFFSXFRCTL, CLRCHN);
+	wait = 1000;
+	while (--wait && !(ahd_inb(ahd, MDFFSTAT) & FIFOFREE))
+		ahd_delay(100);
+	if (wait == 0) {
+		ahd_print_path(ahd, scb);
+		printf("ahd_reinitialize_dataptrs: Forcing FIFO free.\n");
+		ahd_outb(ahd, DFFSXFRCTL, RSTCHN|CLRSHCNT);
+	}
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, DFFSTAT,
+		 ahd_inb(ahd, DFFSTAT)
+		| (saved_modes == 0x11 ? CURRFIFO_1 : CURRFIFO_0));
+
+	/*
+	 * Determine initial values for data_addr and data_cnt
+	 * for resuming the data phase.
+	 */
+	sgptr = (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24)
+	      | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16)
+	      | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8)
+	      |	ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR);
+	sgptr &= SG_PTR_MASK;
+
+	resid = (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 2) << 16)
+	      | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT + 1) << 8)
+	      | ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT);
+
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+		struct ahd_dma64_seg *sg;
+
+		sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+
+		/* The residual sg_ptr always points to the next sg */
+		sg--;
+
+		dataptr = ahd_le64toh(sg->addr)
+			+ (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK)
+			- resid;
+		ahd_outb(ahd, HADDR + 7, dataptr >> 56);
+		ahd_outb(ahd, HADDR + 6, dataptr >> 48);
+		ahd_outb(ahd, HADDR + 5, dataptr >> 40);
+		ahd_outb(ahd, HADDR + 4, dataptr >> 32);
+	} else {
+		struct	 ahd_dma_seg *sg;
+
+		sg = ahd_sg_bus_to_virt(ahd, scb, sgptr);
+
+		/* The residual sg_ptr always points to the next sg */
+		sg--;
+
+		dataptr = ahd_le32toh(sg->addr)
+			+ (ahd_le32toh(sg->len) & AHD_SG_LEN_MASK)
+			- resid;
+		ahd_outb(ahd, HADDR + 4,
+			 (ahd_le32toh(sg->len) & ~AHD_SG_LEN_MASK) >> 24);
+	}
+	ahd_outb(ahd, HADDR + 3, dataptr >> 24);
+	ahd_outb(ahd, HADDR + 2, dataptr >> 16);
+	ahd_outb(ahd, HADDR + 1, dataptr >> 8);
+	ahd_outb(ahd, HADDR, dataptr);
+	ahd_outb(ahd, HCNT + 2, resid >> 16);
+	ahd_outb(ahd, HCNT + 1, resid >> 8);
+	ahd_outb(ahd, HCNT, resid);
+}
+
+/*
+ * Handle the effects of issuing a bus device reset message.
+ */
+static void
+ahd_handle_devreset(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		    u_int lun, cam_status status, char *message,
+		    int verbose_level)
+{
+#ifdef AHD_TARGET_MODE
+	struct ahd_tmode_tstate* tstate;
+#endif
+	int found;
+
+	found = ahd_abort_scbs(ahd, devinfo->target, devinfo->channel,
+			       lun, SCB_LIST_NULL, devinfo->role,
+			       status);
+
+#ifdef AHD_TARGET_MODE
+	/*
+	 * Send an immediate notify ccb to all target mord peripheral
+	 * drivers affected by this action.
+	 */
+	tstate = ahd->enabled_targets[devinfo->our_scsiid];
+	if (tstate != NULL) {
+		u_int cur_lun;
+		u_int max_lun;
+
+		if (lun != CAM_LUN_WILDCARD) {
+			cur_lun = 0;
+			max_lun = AHD_NUM_LUNS - 1;
+		} else {
+			cur_lun = lun;
+			max_lun = lun;
+		}
+		for (cur_lun <= max_lun; cur_lun++) {
+			struct ahd_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[cur_lun];
+			if (lstate == NULL)
+				continue;
+
+			ahd_queue_lstate_event(ahd, lstate, devinfo->our_scsiid,
+					       MSG_BUS_DEV_RESET, /*arg*/0);
+			ahd_send_lstate_events(ahd, lstate);
+		}
+	}
+#endif
+
+	/*
+	 * Go back to async/narrow transfers and renegotiate.
+	 */
+	ahd_set_width(ahd, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+		      AHD_TRANS_CUR, /*paused*/TRUE);
+	ahd_set_syncrate(ahd, devinfo, /*period*/0, /*offset*/0,
+			 /*ppr_options*/0, AHD_TRANS_CUR, /*paused*/TRUE);
+	
+	ahd_send_async(ahd, devinfo->channel, devinfo->target,
+		       lun, AC_SENT_BDR, NULL);
+
+	if (message != NULL
+	 && (verbose_level <= bootverbose))
+		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahd_name(ahd),
+		       message, devinfo->channel, devinfo->target, found);
+}
+
+#ifdef AHD_TARGET_MODE
+static void
+ahd_setup_target_msgin(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		       struct scb *scb)
+{
+
+	/*              
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */             
+	ahd->msgout_index = 0;
+	ahd->msgout_len = 0;
+
+	if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0)
+		ahd_build_transfer_msg(ahd, devinfo);
+	else
+		panic("ahd_intr: AWAITING target message with no message");
+
+	ahd->msgout_index = 0;
+	ahd->msg_type = MSG_TYPE_TARGET_MSGIN;
+}
+#endif
+/**************************** Initialization **********************************/
+static u_int
+ahd_sglist_size(struct ahd_softc *ahd)
+{
+	bus_size_t list_size;
+
+	list_size = sizeof(struct ahd_dma_seg) * AHD_NSEG;
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
+		list_size = sizeof(struct ahd_dma64_seg) * AHD_NSEG;
+	return (list_size);
+}
+
+/*
+ * Calculate the optimum S/G List allocation size.  S/G elements used
+ * for a given transaction must be physically contiguous.  Assume the
+ * OS will allocate full pages to us, so it doesn't make sense to request
+ * less than a page.
+ */
+static u_int
+ahd_sglist_allocsize(struct ahd_softc *ahd)
+{
+	bus_size_t sg_list_increment;
+	bus_size_t sg_list_size;
+	bus_size_t max_list_size;
+	bus_size_t best_list_size;
+
+	/* Start out with the minimum required for AHD_NSEG. */
+	sg_list_increment = ahd_sglist_size(ahd);
+	sg_list_size = sg_list_increment;
+
+	/* Get us as close as possible to a page in size. */
+	while ((sg_list_size + sg_list_increment) <= PAGE_SIZE)
+		sg_list_size += sg_list_increment;
+
+	/*
+	 * Try to reduce the amount of wastage by allocating
+	 * multiple pages.
+	 */
+	best_list_size = sg_list_size;
+	max_list_size = roundup(sg_list_increment, PAGE_SIZE);
+	if (max_list_size < 4 * PAGE_SIZE)
+		max_list_size = 4 * PAGE_SIZE;
+	if (max_list_size > (AHD_SCB_MAX_ALLOC * sg_list_increment))
+		max_list_size = (AHD_SCB_MAX_ALLOC * sg_list_increment);
+	while ((sg_list_size + sg_list_increment) <= max_list_size
+	   &&  (sg_list_size % PAGE_SIZE) != 0) {
+		bus_size_t new_mod;
+		bus_size_t best_mod;
+
+		sg_list_size += sg_list_increment;
+		new_mod = sg_list_size % PAGE_SIZE;
+		best_mod = best_list_size % PAGE_SIZE;
+		if (new_mod > best_mod || new_mod == 0) {
+			best_list_size = sg_list_size;
+		}
+	}
+	return (best_list_size);
+}
+
+/*
+ * Allocate a controller structure for a new device
+ * and perform initial initializion.
+ */
+struct ahd_softc *
+ahd_alloc(void *platform_arg, char *name)
+{
+	struct  ahd_softc *ahd;
+
+#ifndef	__FreeBSD__
+	ahd = malloc(sizeof(*ahd), M_DEVBUF, M_NOWAIT);
+	if (!ahd) {
+		printf("aic7xxx: cannot malloc softc!\n");
+		free(name, M_DEVBUF);
+		return NULL;
+	}
+#else
+	ahd = device_get_softc((device_t)platform_arg);
+#endif
+	memset(ahd, 0, sizeof(*ahd));
+	ahd->seep_config = malloc(sizeof(*ahd->seep_config),
+				  M_DEVBUF, M_NOWAIT);
+	if (ahd->seep_config == NULL) {
+#ifndef	__FreeBSD__
+		free(ahd, M_DEVBUF);
+#endif
+		free(name, M_DEVBUF);
+		return (NULL);
+	}
+	LIST_INIT(&ahd->pending_scbs);
+	/* We don't know our unit number until the OSM sets it */
+	ahd->name = name;
+	ahd->unit = -1;
+	ahd->description = NULL;
+	ahd->bus_description = NULL;
+	ahd->channel = 'A';
+	ahd->chip = AHD_NONE;
+	ahd->features = AHD_FENONE;
+	ahd->bugs = AHD_BUGNONE;
+	ahd->flags = AHD_SPCHK_ENB_A|AHD_RESET_BUS_A|AHD_TERM_ENB_A
+		   | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A;
+	ahd_timer_init(&ahd->reset_timer);
+	ahd_timer_init(&ahd->stat_timer);
+	ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT;
+	ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT;
+	ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT;
+	ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT;
+	ahd->int_coalescing_stop_threshold =
+	    AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT;
+
+	if (ahd_platform_alloc(ahd, platform_arg) != 0) {
+		ahd_free(ahd);
+		ahd = NULL;
+	}
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MEMORY) != 0) {
+		printf("%s: scb size = 0x%x, hscb size = 0x%x\n",
+		       ahd_name(ahd), (u_int)sizeof(struct scb),
+		       (u_int)sizeof(struct hardware_scb));
+	}
+#endif
+	return (ahd);
+}
+
+int
+ahd_softc_init(struct ahd_softc *ahd)
+{
+
+	ahd->unpause = 0;
+	ahd->pause = PAUSE; 
+	return (0);
+}
+
+void
+ahd_softc_insert(struct ahd_softc *ahd)
+{
+	struct ahd_softc *list_ahd;
+
+#if AHD_PCI_CONFIG > 0
+	/*
+	 * Second Function PCI devices need to inherit some
+	 * settings from function 0.
+	 */
+	if ((ahd->features & AHD_MULTI_FUNC) != 0) {
+		TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
+			ahd_dev_softc_t list_pci;
+			ahd_dev_softc_t pci;
+
+			list_pci = list_ahd->dev_softc;
+			pci = ahd->dev_softc;
+			if (ahd_get_pci_slot(list_pci) == ahd_get_pci_slot(pci)
+			 && ahd_get_pci_bus(list_pci) == ahd_get_pci_bus(pci)) {
+				struct ahd_softc *master;
+				struct ahd_softc *slave;
+
+				if (ahd_get_pci_function(list_pci) == 0) {
+					master = list_ahd;
+					slave = ahd;
+				} else {
+					master = ahd;
+					slave = list_ahd;
+				}
+				slave->flags &= ~AHD_BIOS_ENABLED; 
+				slave->flags |=
+				    master->flags & AHD_BIOS_ENABLED;
+				break;
+			}
+		}
+	}
+#endif
+
+	/*
+	 * Insertion sort into our list of softcs.
+	 */
+	list_ahd = TAILQ_FIRST(&ahd_tailq);
+	while (list_ahd != NULL
+	    && ahd_softc_comp(ahd, list_ahd) <= 0)
+		list_ahd = TAILQ_NEXT(list_ahd, links);
+	if (list_ahd != NULL)
+		TAILQ_INSERT_BEFORE(list_ahd, ahd, links);
+	else
+		TAILQ_INSERT_TAIL(&ahd_tailq, ahd, links);
+	ahd->init_level++;
+}
+
+/*
+ * Verify that the passed in softc pointer is for a
+ * controller that is still configured.
+ */
+struct ahd_softc *
+ahd_find_softc(struct ahd_softc *ahd)
+{
+	struct ahd_softc *list_ahd;
+
+	TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
+		if (list_ahd == ahd)
+			return (ahd);
+	}
+	return (NULL);
+}
+
+void
+ahd_set_unit(struct ahd_softc *ahd, int unit)
+{
+	ahd->unit = unit;
+}
+
+void
+ahd_set_name(struct ahd_softc *ahd, char *name)
+{
+	if (ahd->name != NULL)
+		free(ahd->name, M_DEVBUF);
+	ahd->name = name;
+}
+
+void
+ahd_free(struct ahd_softc *ahd)
+{
+	int i;
+
+	switch (ahd->init_level) {
+	default:
+	case 5:
+		ahd_shutdown(ahd);
+		/* FALLTHROUGH */
+	case 4:
+		ahd_dmamap_unload(ahd, ahd->shared_data_dmat,
+				  ahd->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 3:
+		ahd_dmamem_free(ahd, ahd->shared_data_dmat, ahd->qoutfifo,
+				ahd->shared_data_dmamap);
+		ahd_dmamap_destroy(ahd, ahd->shared_data_dmat,
+				   ahd->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 2:
+		ahd_dma_tag_destroy(ahd, ahd->shared_data_dmat);
+	case 1:
+#ifndef __linux__
+		ahd_dma_tag_destroy(ahd, ahd->buffer_dmat);
+#endif
+		break;
+	case 0:
+		break;
+	}
+
+#ifndef __linux__
+	ahd_dma_tag_destroy(ahd, ahd->parent_dmat);
+#endif
+	ahd_platform_free(ahd);
+	ahd_fini_scbdata(ahd);
+	for (i = 0; i < AHD_NUM_TARGETS; i++) {
+		struct ahd_tmode_tstate *tstate;
+
+		tstate = ahd->enabled_targets[i];
+		if (tstate != NULL) {
+#ifdef AHD_TARGET_MODE
+			int j;
+
+			for (j = 0; j < AHD_NUM_LUNS; j++) {
+				struct ahd_tmode_lstate *lstate;
+
+				lstate = tstate->enabled_luns[j];
+				if (lstate != NULL) {
+					xpt_free_path(lstate->path);
+					free(lstate, M_DEVBUF);
+				}
+			}
+#endif
+			free(tstate, M_DEVBUF);
+		}
+	}
+#ifdef AHD_TARGET_MODE
+	if (ahd->black_hole != NULL) {
+		xpt_free_path(ahd->black_hole->path);
+		free(ahd->black_hole, M_DEVBUF);
+	}
+#endif
+	if (ahd->name != NULL)
+		free(ahd->name, M_DEVBUF);
+	if (ahd->seep_config != NULL)
+		free(ahd->seep_config, M_DEVBUF);
+	if (ahd->saved_stack != NULL)
+		free(ahd->saved_stack, M_DEVBUF);
+#ifndef __FreeBSD__
+	free(ahd, M_DEVBUF);
+#endif
+	return;
+}
+
+void
+ahd_shutdown(void *arg)
+{
+	struct	ahd_softc *ahd;
+
+	ahd = (struct ahd_softc *)arg;
+
+	/*
+	 * Stop periodic timer callbacks.
+	 */
+	ahd_timer_stop(&ahd->reset_timer);
+	ahd_timer_stop(&ahd->stat_timer);
+
+	/* This will reset most registers to 0, but not all */
+	ahd_reset(ahd, /*reinit*/FALSE);
+}
+
+/*
+ * Reset the controller and record some information about it
+ * that is only available just after a reset.  If "reinit" is
+ * non-zero, this reset occured after initial configuration
+ * and the caller requests that the chip be fully reinitialized
+ * to a runable state.  Chip interrupts are *not* enabled after
+ * a reinitialization.  The caller must enable interrupts via
+ * ahd_intr_enable().
+ */
+int
+ahd_reset(struct ahd_softc *ahd, int reinit)
+{
+	u_int	 sxfrctl1;
+	int	 wait;
+	uint32_t cmd;
+	
+	/*
+	 * Preserve the value of the SXFRCTL1 register for all channels.
+	 * It contains settings that affect termination and we don't want
+	 * to disturb the integrity of the bus.
+	 */
+	ahd_pause(ahd);
+	ahd_update_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	sxfrctl1 = ahd_inb(ahd, SXFRCTL1);
+
+	cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
+	if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) {
+		uint32_t mod_cmd;
+
+		/*
+		 * A4 Razor #632
+		 * During the assertion of CHIPRST, the chip
+		 * does not disable its parity logic prior to
+		 * the start of the reset.  This may cause a
+		 * parity error to be detected and thus a
+		 * spurious SERR or PERR assertion.  Disble
+		 * PERR and SERR responses during the CHIPRST.
+		 */
+		mod_cmd = cmd & ~(PCIM_CMD_PERRESPEN|PCIM_CMD_SERRESPEN);
+		ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
+				     mod_cmd, /*bytes*/2);
+	}
+	ahd_outb(ahd, HCNTRL, CHIPRST | ahd->pause);
+
+	/*
+	 * Ensure that the reset has finished.  We delay 1000us
+	 * prior to reading the register to make sure the chip
+	 * has sufficiently completed its reset to handle register
+	 * accesses.
+	 */
+	wait = 1000;
+	do {
+		ahd_delay(1000);
+	} while (--wait && !(ahd_inb(ahd, HCNTRL) & CHIPRSTACK));
+
+	if (wait == 0) {
+		printf("%s: WARNING - Failed chip reset!  "
+		       "Trying to initialize anyway.\n", ahd_name(ahd));
+	}
+	ahd_outb(ahd, HCNTRL, ahd->pause);
+
+	if ((ahd->bugs & AHD_PCIX_CHIPRST_BUG) != 0) {
+		/*
+		 * Clear any latched PCI error status and restore
+		 * previous SERR and PERR response enables.
+		 */
+		ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
+				     0xFF, /*bytes*/1);
+		ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
+				     cmd, /*bytes*/2);
+	}
+
+	/*
+	 * Mode should be SCSI after a chip reset, but lets
+	 * set it just to be safe.  We touch the MODE_PTR
+	 * register directly so as to bypass the lazy update
+	 * code in ahd_set_modes().
+	 */
+	ahd_known_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, MODE_PTR,
+		 ahd_build_mode_state(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI));
+
+	/*
+	 * Restore SXFRCTL1.
+	 *
+	 * We must always initialize STPWEN to 1 before we
+	 * restore the saved values.  STPWEN is initialized
+	 * to a tri-state condition which can only be cleared
+	 * by turning it on.
+	 */
+	ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
+	ahd_outb(ahd, SXFRCTL1, sxfrctl1);
+
+	/* Determine chip configuration */
+	ahd->features &= ~AHD_WIDE;
+	if ((ahd_inb(ahd, SBLKCTL) & SELWIDE) != 0)
+		ahd->features |= AHD_WIDE;
+
+	/*
+	 * If a recovery action has forced a chip reset,
+	 * re-initialize the chip to our liking.
+	 */
+	if (reinit != 0)
+		ahd_chip_init(ahd);
+
+	return (0);
+}
+
+/*
+ * Determine the number of SCBs available on the controller
+ */
+int
+ahd_probe_scbs(struct ahd_softc *ahd) {
+	int i;
+
+	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+	for (i = 0; i < AHD_SCB_MAX; i++) {
+		int j;
+
+		ahd_set_scbptr(ahd, i);
+		ahd_outw(ahd, SCB_BASE, i);
+		for (j = 2; j < 64; j++)
+			ahd_outb(ahd, SCB_BASE+j, 0);
+		/* Start out life as unallocated (needing an abort) */
+		ahd_outb(ahd, SCB_CONTROL, MK_MESSAGE);
+		if (ahd_inw_scbram(ahd, SCB_BASE) != i)
+			break;
+		ahd_set_scbptr(ahd, 0);
+		if (ahd_inw_scbram(ahd, SCB_BASE) != 0)
+			break;
+	}
+	return (i);
+}
+
+static void
+ahd_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 
+{
+	dma_addr_t *baddr;
+
+	baddr = (dma_addr_t *)arg;
+	*baddr = segs->ds_addr;
+}
+
+static void
+ahd_initialize_hscbs(struct ahd_softc *ahd)
+{
+	int i;
+
+	for (i = 0; i < ahd->scb_data.maxhscbs; i++) {
+		ahd_set_scbptr(ahd, i);
+
+		/* Clear the control byte. */
+		ahd_outb(ahd, SCB_CONTROL, 0);
+
+		/* Set the next pointer */
+		ahd_outw(ahd, SCB_NEXT, SCB_LIST_NULL);
+	}
+}
+
+static int
+ahd_init_scbdata(struct ahd_softc *ahd)
+{
+	struct	scb_data *scb_data;
+	int	i;
+
+	scb_data = &ahd->scb_data;
+	TAILQ_INIT(&scb_data->free_scbs);
+	for (i = 0; i < AHD_NUM_TARGETS * AHD_NUM_LUNS_NONPKT; i++)
+		LIST_INIT(&scb_data->free_scb_lists[i]);
+	LIST_INIT(&scb_data->any_dev_free_scb_list);
+	SLIST_INIT(&scb_data->hscb_maps);
+	SLIST_INIT(&scb_data->sg_maps);
+	SLIST_INIT(&scb_data->sense_maps);
+
+	/* Determine the number of hardware SCBs and initialize them */
+	scb_data->maxhscbs = ahd_probe_scbs(ahd);
+	if (scb_data->maxhscbs == 0) {
+		printf("%s: No SCB space found\n", ahd_name(ahd));
+		return (ENXIO);
+	}
+
+	ahd_initialize_hscbs(ahd);
+
+	/*
+	 * Create our DMA tags.  These tags define the kinds of device
+	 * accessible memory allocations and memory mappings we will
+	 * need to perform during normal operation.
+	 *
+	 * Unless we need to further restrict the allocation, we rely
+	 * on the restrictions of the parent dmat, hence the common
+	 * use of MAXADDR and MAXSIZE.
+	 */
+
+	/* DMA tag for our hardware scb structures */
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       PAGE_SIZE, /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->hscb_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* DMA tag for our S/G structures. */
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/8,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       ahd_sglist_allocsize(ahd), /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sg_dmat) != 0) {
+		goto error_exit;
+	}
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MEMORY) != 0)
+		printf("%s: ahd_sglist_allocsize = 0x%x\n", ahd_name(ahd),
+		       ahd_sglist_allocsize(ahd));
+#endif
+
+	scb_data->init_level++;
+
+	/* DMA tag for our sense buffers.  We allocate in page sized chunks */
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       PAGE_SIZE, /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sense_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Perform initial CCB allocation */
+	ahd_alloc_scbs(ahd);
+
+	if (scb_data->numscbs == 0) {
+		printf("%s: ahd_init_scbdata - "
+		       "Unable to allocate initial scbs\n",
+		       ahd_name(ahd));
+		goto error_exit;
+	}
+
+	/*
+	 * Note that we were successfull
+	 */
+	return (0); 
+
+error_exit:
+
+	return (ENOMEM);
+}
+
+static struct scb *
+ahd_find_scb_by_tag(struct ahd_softc *ahd, u_int tag)
+{
+	struct scb *scb;
+
+	/*
+	 * Look on the pending list.
+	 */
+	LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+		if (SCB_GET_TAG(scb) == tag)
+			return (scb);
+	}
+
+	/*
+	 * Then on all of the collision free lists.
+	 */
+	TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
+		struct scb *list_scb;
+
+		list_scb = scb;
+		do {
+			if (SCB_GET_TAG(list_scb) == tag)
+				return (list_scb);
+			list_scb = LIST_NEXT(list_scb, collision_links);
+		} while (list_scb);
+	}
+
+	/*
+	 * And finally on the generic free list.
+	 */
+	LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
+		if (SCB_GET_TAG(scb) == tag)
+			return (scb);
+	}
+
+	return (NULL);
+}
+
+static void
+ahd_fini_scbdata(struct ahd_softc *ahd)
+{
+	struct scb_data *scb_data;
+
+	scb_data = &ahd->scb_data;
+	if (scb_data == NULL)
+		return;
+
+	switch (scb_data->init_level) {
+	default:
+	case 7:
+	{
+		struct map_node *sns_map;
+
+		while ((sns_map = SLIST_FIRST(&scb_data->sense_maps)) != NULL) {
+			SLIST_REMOVE_HEAD(&scb_data->sense_maps, links);
+			ahd_dmamap_unload(ahd, scb_data->sense_dmat,
+					  sns_map->dmamap);
+			ahd_dmamem_free(ahd, scb_data->sense_dmat,
+					sns_map->vaddr, sns_map->dmamap);
+			free(sns_map, M_DEVBUF);
+		}
+		ahd_dma_tag_destroy(ahd, scb_data->sense_dmat);
+		/* FALLTHROUGH */
+	}
+	case 6:
+	{
+		struct map_node *sg_map;
+
+		while ((sg_map = SLIST_FIRST(&scb_data->sg_maps)) != NULL) {
+			SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
+			ahd_dmamap_unload(ahd, scb_data->sg_dmat,
+					  sg_map->dmamap);
+			ahd_dmamem_free(ahd, scb_data->sg_dmat,
+					sg_map->vaddr, sg_map->dmamap);
+			free(sg_map, M_DEVBUF);
+		}
+		ahd_dma_tag_destroy(ahd, scb_data->sg_dmat);
+		/* FALLTHROUGH */
+	}
+	case 5:
+	{
+		struct map_node *hscb_map;
+
+		while ((hscb_map = SLIST_FIRST(&scb_data->hscb_maps)) != NULL) {
+			SLIST_REMOVE_HEAD(&scb_data->hscb_maps, links);
+			ahd_dmamap_unload(ahd, scb_data->hscb_dmat,
+					  hscb_map->dmamap);
+			ahd_dmamem_free(ahd, scb_data->hscb_dmat,
+					hscb_map->vaddr, hscb_map->dmamap);
+			free(hscb_map, M_DEVBUF);
+		}
+		ahd_dma_tag_destroy(ahd, scb_data->hscb_dmat);
+		/* FALLTHROUGH */
+	}
+	case 4:
+	case 3:
+	case 2:
+	case 1:
+	case 0:
+		break;
+	}
+}
+
+/*
+ * DSP filter Bypass must be enabled until the first selection
+ * after a change in bus mode (Razor #491 and #493).
+ */
+static void
+ahd_setup_iocell_workaround(struct ahd_softc *ahd)
+{
+	ahd_mode_state saved_modes;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+	ahd_outb(ahd, DSPDATACTL, ahd_inb(ahd, DSPDATACTL)
+	       | BYPASSENAB | RCVROFFSTDIS | XMITOFFSTDIS);
+	ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) | (ENSELDO|ENSELDI));
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MISC) != 0)
+		printf("%s: Setting up iocell workaround\n", ahd_name(ahd));
+#endif
+	ahd_restore_modes(ahd, saved_modes);
+	ahd->flags &= ~AHD_HAD_FIRST_SEL;
+}
+
+static void
+ahd_iocell_first_selection(struct ahd_softc *ahd)
+{
+	ahd_mode_state	saved_modes;
+	u_int		sblkctl;
+
+	if ((ahd->flags & AHD_HAD_FIRST_SEL) != 0)
+		return;
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	sblkctl = ahd_inb(ahd, SBLKCTL);
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MISC) != 0)
+		printf("%s: iocell first selection\n", ahd_name(ahd));
+#endif
+	if ((sblkctl & ENAB40) != 0) {
+		ahd_outb(ahd, DSPDATACTL,
+			 ahd_inb(ahd, DSPDATACTL) & ~BYPASSENAB);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MISC) != 0)
+			printf("%s: BYPASS now disabled\n", ahd_name(ahd));
+#endif
+	}
+	ahd_outb(ahd, SIMODE0, ahd_inb(ahd, SIMODE0) & ~(ENSELDO|ENSELDI));
+	ahd_outb(ahd, CLRINT, CLRSCSIINT);
+	ahd_restore_modes(ahd, saved_modes);
+	ahd->flags |= AHD_HAD_FIRST_SEL;
+}
+
+/*************************** SCB Management ***********************************/
+static void
+ahd_add_col_list(struct ahd_softc *ahd, struct scb *scb, u_int col_idx)
+{
+	struct	scb_list *free_list;
+	struct	scb_tailq *free_tailq;
+	struct	scb *first_scb;
+
+	scb->flags |= SCB_ON_COL_LIST;
+	AHD_SET_SCB_COL_IDX(scb, col_idx);
+	free_list = &ahd->scb_data.free_scb_lists[col_idx];
+	free_tailq = &ahd->scb_data.free_scbs;
+	first_scb = LIST_FIRST(free_list);
+	if (first_scb != NULL) {
+		LIST_INSERT_AFTER(first_scb, scb, collision_links);
+	} else {
+		LIST_INSERT_HEAD(free_list, scb, collision_links);
+		TAILQ_INSERT_TAIL(free_tailq, scb, links.tqe);
+	}
+}
+
+static void
+ahd_rem_col_list(struct ahd_softc *ahd, struct scb *scb)
+{
+	struct	scb_list *free_list;
+	struct	scb_tailq *free_tailq;
+	struct	scb *first_scb;
+	u_int	col_idx;
+
+	scb->flags &= ~SCB_ON_COL_LIST;
+	col_idx = AHD_GET_SCB_COL_IDX(ahd, scb);
+	free_list = &ahd->scb_data.free_scb_lists[col_idx];
+	free_tailq = &ahd->scb_data.free_scbs;
+	first_scb = LIST_FIRST(free_list);
+	if (first_scb == scb) {
+		struct scb *next_scb;
+
+		/*
+		 * Maintain order in the collision free
+		 * lists for fairness if this device has
+		 * other colliding tags active.
+		 */
+		next_scb = LIST_NEXT(scb, collision_links);
+		if (next_scb != NULL) {
+			TAILQ_INSERT_AFTER(free_tailq, scb,
+					   next_scb, links.tqe);
+		}
+		TAILQ_REMOVE(free_tailq, scb, links.tqe);
+	}
+	LIST_REMOVE(scb, collision_links);
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
+ */
+struct scb *
+ahd_get_scb(struct ahd_softc *ahd, u_int col_idx)
+{
+	struct scb *scb;
+	int tries;
+
+	tries = 0;
+look_again:
+	TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
+		if (AHD_GET_SCB_COL_IDX(ahd, scb) != col_idx) {
+			ahd_rem_col_list(ahd, scb);
+			goto found;
+		}
+	}
+	if ((scb = LIST_FIRST(&ahd->scb_data.any_dev_free_scb_list)) == NULL) {
+
+		if (tries++ != 0)
+			return (NULL);
+		ahd_alloc_scbs(ahd);
+		goto look_again;
+	}
+	LIST_REMOVE(scb, links.le);
+	if (col_idx != AHD_NEVER_COL_IDX
+	 && (scb->col_scb != NULL)
+	 && (scb->col_scb->flags & SCB_ACTIVE) == 0) {
+		LIST_REMOVE(scb->col_scb, links.le);
+		ahd_add_col_list(ahd, scb->col_scb, col_idx);
+	}
+found:
+	scb->flags |= SCB_ACTIVE;
+	return (scb);
+}
+
+/*
+ * Return an SCB resource to the free list.
+ */
+void
+ahd_free_scb(struct ahd_softc *ahd, struct scb *scb)
+{       
+
+	/* Clean up for the next user */
+	scb->flags = SCB_FLAG_NONE;
+	scb->hscb->control = 0;
+	ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL;
+
+	if (scb->col_scb == NULL) {
+
+		/*
+		 * No collision possible.  Just free normally.
+		 */
+		LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
+				 scb, links.le);
+	} else if ((scb->col_scb->flags & SCB_ON_COL_LIST) != 0) {
+
+		/*
+		 * The SCB we might have collided with is on
+		 * a free collision list.  Put both SCBs on
+		 * the generic list.
+		 */
+		ahd_rem_col_list(ahd, scb->col_scb);
+		LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
+				 scb, links.le);
+		LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
+				 scb->col_scb, links.le);
+	} else if ((scb->col_scb->flags
+		  & (SCB_PACKETIZED|SCB_ACTIVE)) == SCB_ACTIVE
+		&& (scb->col_scb->hscb->control & TAG_ENB) != 0) {
+
+		/*
+		 * The SCB we might collide with on the next allocation
+		 * is still active in a non-packetized, tagged, context.
+		 * Put us on the SCB collision list.
+		 */
+		ahd_add_col_list(ahd, scb,
+				 AHD_GET_SCB_COL_IDX(ahd, scb->col_scb));
+	} else {
+		/*
+		 * The SCB we might collide with on the next allocation
+		 * is either active in a packetized context, or free.
+		 * Since we can't collide, put this SCB on the generic
+		 * free list.
+		 */
+		LIST_INSERT_HEAD(&ahd->scb_data.any_dev_free_scb_list,
+				 scb, links.le);
+	}
+
+	ahd_platform_scb_free(ahd, scb);
+}
+
+void
+ahd_alloc_scbs(struct ahd_softc *ahd)
+{
+	struct scb_data *scb_data;
+	struct scb	*next_scb;
+	struct hardware_scb *hscb;
+	struct map_node *hscb_map;
+	struct map_node *sg_map;
+	struct map_node *sense_map;
+	uint8_t		*segs;
+	uint8_t		*sense_data;
+	dma_addr_t	 hscb_busaddr;
+	dma_addr_t	 sg_busaddr;
+	dma_addr_t	 sense_busaddr;
+	int		 newcount;
+	int		 i;
+
+	scb_data = &ahd->scb_data;
+	if (scb_data->numscbs >= AHD_SCB_MAX_ALLOC)
+		/* Can't allocate any more */
+		return;
+
+	if (scb_data->scbs_left != 0) {
+		int offset;
+
+		offset = (PAGE_SIZE / sizeof(*hscb)) - scb_data->scbs_left;
+		hscb_map = SLIST_FIRST(&scb_data->hscb_maps);
+		hscb = &((struct hardware_scb *)hscb_map->vaddr)[offset];
+		hscb_busaddr = hscb_map->physaddr + (offset * sizeof(*hscb));
+	} else {
+		hscb_map = malloc(sizeof(*hscb_map), M_DEVBUF, M_NOWAIT);
+
+		if (hscb_map == NULL)
+			return;
+
+		/* Allocate the next batch of hardware SCBs */
+		if (ahd_dmamem_alloc(ahd, scb_data->hscb_dmat,
+				     (void **)&hscb_map->vaddr,
+				     BUS_DMA_NOWAIT, &hscb_map->dmamap) != 0) {
+			free(hscb_map, M_DEVBUF);
+			return;
+		}
+
+		SLIST_INSERT_HEAD(&scb_data->hscb_maps, hscb_map, links);
+
+		ahd_dmamap_load(ahd, scb_data->hscb_dmat, hscb_map->dmamap,
+				hscb_map->vaddr, PAGE_SIZE, ahd_dmamap_cb,
+				&hscb_map->physaddr, /*flags*/0);
+
+		hscb = (struct hardware_scb *)hscb_map->vaddr;
+		hscb_busaddr = hscb_map->physaddr;
+		scb_data->scbs_left = PAGE_SIZE / sizeof(*hscb);
+	}
+
+	if (scb_data->sgs_left != 0) {
+		int offset;
+
+		offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd))
+		       - scb_data->sgs_left) * ahd_sglist_size(ahd);
+		sg_map = SLIST_FIRST(&scb_data->sg_maps);
+		segs = sg_map->vaddr + offset;
+		sg_busaddr = sg_map->physaddr + offset;
+	} else {
+		sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+
+		if (sg_map == NULL)
+			return;
+
+		/* Allocate the next batch of S/G lists */
+		if (ahd_dmamem_alloc(ahd, scb_data->sg_dmat,
+				     (void **)&sg_map->vaddr,
+				     BUS_DMA_NOWAIT, &sg_map->dmamap) != 0) {
+			free(sg_map, M_DEVBUF);
+			return;
+		}
+
+		SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
+
+		ahd_dmamap_load(ahd, scb_data->sg_dmat, sg_map->dmamap,
+				sg_map->vaddr, ahd_sglist_allocsize(ahd),
+				ahd_dmamap_cb, &sg_map->physaddr, /*flags*/0);
+
+		segs = sg_map->vaddr;
+		sg_busaddr = sg_map->physaddr;
+		scb_data->sgs_left =
+		    ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd);
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_MEMORY)
+			printf("Mapped SG data\n");
+#endif
+	}
+
+	if (scb_data->sense_left != 0) {
+		int offset;
+
+		offset = PAGE_SIZE - (AHD_SENSE_BUFSIZE * scb_data->sense_left);
+		sense_map = SLIST_FIRST(&scb_data->sense_maps);
+		sense_data = sense_map->vaddr + offset;
+		sense_busaddr = sense_map->physaddr + offset;
+	} else {
+		sense_map = malloc(sizeof(*sense_map), M_DEVBUF, M_NOWAIT);
+
+		if (sense_map == NULL)
+			return;
+
+		/* Allocate the next batch of sense buffers */
+		if (ahd_dmamem_alloc(ahd, scb_data->sense_dmat,
+				     (void **)&sense_map->vaddr,
+				     BUS_DMA_NOWAIT, &sense_map->dmamap) != 0) {
+			free(sense_map, M_DEVBUF);
+			return;
+		}
+
+		SLIST_INSERT_HEAD(&scb_data->sense_maps, sense_map, links);
+
+		ahd_dmamap_load(ahd, scb_data->sense_dmat, sense_map->dmamap,
+				sense_map->vaddr, PAGE_SIZE, ahd_dmamap_cb,
+				&sense_map->physaddr, /*flags*/0);
+
+		sense_data = sense_map->vaddr;
+		sense_busaddr = sense_map->physaddr;
+		scb_data->sense_left = PAGE_SIZE / AHD_SENSE_BUFSIZE;
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_MEMORY)
+			printf("Mapped sense data\n");
+#endif
+	}
+
+	newcount = MIN(scb_data->sense_left, scb_data->scbs_left);
+	newcount = MIN(newcount, scb_data->sgs_left);
+	newcount = MIN(newcount, (AHD_SCB_MAX_ALLOC - scb_data->numscbs));
+	scb_data->sense_left -= newcount;
+	scb_data->scbs_left -= newcount;
+	scb_data->sgs_left -= newcount;
+	for (i = 0; i < newcount; i++) {
+		u_int col_tag;
+
+		struct scb_platform_data *pdata;
+#ifndef __linux__
+		int error;
+#endif
+		next_scb = (struct scb *)malloc(sizeof(*next_scb),
+						M_DEVBUF, M_NOWAIT);
+		if (next_scb == NULL)
+			break;
+
+		pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
+							   M_DEVBUF, M_NOWAIT);
+		if (pdata == NULL) {
+			free(next_scb, M_DEVBUF);
+			break;
+		}
+		next_scb->platform_data = pdata;
+		next_scb->hscb_map = hscb_map;
+		next_scb->sg_map = sg_map;
+		next_scb->sense_map = sense_map;
+		next_scb->sg_list = segs;
+		next_scb->sense_data = sense_data;
+		next_scb->sense_busaddr = sense_busaddr;
+		memset(hscb, 0, sizeof(*hscb));
+		next_scb->hscb = hscb;
+		hscb->hscb_busaddr = ahd_htole32(hscb_busaddr);
+
+		/*
+		 * The sequencer always starts with the second entry.
+		 * The first entry is embedded in the scb.
+		 */
+		next_scb->sg_list_busaddr = sg_busaddr;
+		if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
+			next_scb->sg_list_busaddr
+			    += sizeof(struct ahd_dma64_seg);
+		else
+			next_scb->sg_list_busaddr += sizeof(struct ahd_dma_seg);
+		next_scb->ahd_softc = ahd;
+		next_scb->flags = SCB_FLAG_NONE;
+#ifndef __linux__
+		error = ahd_dmamap_create(ahd, ahd->buffer_dmat, /*flags*/0,
+					  &next_scb->dmamap);
+		if (error != 0) {
+			free(next_scb, M_DEVBUF);
+			free(pdata, M_DEVBUF);
+			break;
+		}
+#endif
+		next_scb->hscb->tag = ahd_htole16(scb_data->numscbs);
+		col_tag = scb_data->numscbs ^ 0x100;
+		next_scb->col_scb = ahd_find_scb_by_tag(ahd, col_tag);
+		if (next_scb->col_scb != NULL)
+			next_scb->col_scb->col_scb = next_scb;
+		ahd_free_scb(ahd, next_scb);
+		hscb++;
+		hscb_busaddr += sizeof(*hscb);
+		segs += ahd_sglist_size(ahd);
+		sg_busaddr += ahd_sglist_size(ahd);
+		sense_data += AHD_SENSE_BUFSIZE;
+		sense_busaddr += AHD_SENSE_BUFSIZE;
+		scb_data->numscbs++;
+	}
+}
+
+void
+ahd_controller_info(struct ahd_softc *ahd, char *buf)
+{
+	const char *speed;
+	const char *type;
+	int len;
+
+	len = sprintf(buf, "%s: ", ahd_chip_names[ahd->chip & AHD_CHIPID_MASK]);
+	buf += len;
+
+	speed = "Ultra320 ";
+	if ((ahd->features & AHD_WIDE) != 0) {
+		type = "Wide ";
+	} else {
+		type = "Single ";
+	}
+	len = sprintf(buf, "%s%sChannel %c, SCSI Id=%d, ",
+		      speed, type, ahd->channel, ahd->our_id);
+	buf += len;
+
+	sprintf(buf, "%s, %d SCBs", ahd->bus_description,
+		ahd->scb_data.maxhscbs);
+}
+
+static const char *channel_strings[] = {
+	"Primary Low",
+	"Primary High",
+	"Secondary Low", 
+	"Secondary High"
+};
+
+static const char *termstat_strings[] = {
+	"Terminated Correctly",
+	"Over Terminated",
+	"Under Terminated",
+	"Not Configured"
+};
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+ahd_init(struct ahd_softc *ahd)
+{
+	uint8_t		*base_vaddr;
+	uint8_t		*next_vaddr;
+	dma_addr_t	 next_baddr;
+	size_t		 driver_data_size;
+	int		 i;
+	int		 error;
+	u_int		 warn_user;
+	uint8_t		 current_sensing;
+	uint8_t		 fstat;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+
+	ahd->stack_size = ahd_probe_stack_size(ahd);
+	ahd->saved_stack = malloc(ahd->stack_size * sizeof(uint16_t),
+				  M_DEVBUF, M_NOWAIT);
+	if (ahd->saved_stack == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Verify that the compiler hasn't over-agressively
+	 * padded important structures.
+	 */
+	if (sizeof(struct hardware_scb) != 64)
+		panic("Hardware SCB size is incorrect");
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_DEBUG_SEQUENCER) != 0)
+		ahd->flags |= AHD_SEQUENCER_DEBUG;
+#endif
+
+	/*
+	 * Default to allowing initiator operations.
+	 */
+	ahd->flags |= AHD_INITIATORROLE;
+
+	/*
+	 * Only allow target mode features if this unit has them enabled.
+	 */
+	if ((AHD_TMODE_ENABLE & (0x1 << ahd->unit)) == 0)
+		ahd->features &= ~AHD_TARGETMODE;
+
+#ifndef __linux__
+	/* DMA tag for mapping buffers into device visible space. */
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/ahd->flags & AHD_39BIT_ADDRESSING
+					? (dma_addr_t)0x7FFFFFFFFFULL
+					: BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       /*maxsize*/(AHD_NSEG - 1) * PAGE_SIZE,
+			       /*nsegments*/AHD_NSEG,
+			       /*maxsegsz*/AHD_MAXTRANSFER_SIZE,
+			       /*flags*/BUS_DMA_ALLOCNOW,
+			       &ahd->buffer_dmat) != 0) {
+		return (ENOMEM);
+	}
+#endif
+
+	ahd->init_level++;
+
+	/*
+	 * DMA tag for our command fifos and other data in system memory
+	 * the card's sequencer must be able to access.  For initiator
+	 * roles, we need to allocate space for the qoutfifo.  When providing
+	 * for the target mode role, we must additionally provide space for
+	 * the incoming target command fifo.
+	 */
+	driver_data_size = AHD_SCB_MAX * sizeof(uint16_t)
+			 + sizeof(struct hardware_scb);
+	if ((ahd->features & AHD_TARGETMODE) != 0)
+		driver_data_size += AHD_TMODE_CMDS * sizeof(struct target_cmd);
+	if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0)
+		driver_data_size += PKT_OVERRUN_BUFSIZE;
+	if (ahd_dma_tag_create(ahd, ahd->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       driver_data_size,
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &ahd->shared_data_dmat) != 0) {
+		return (ENOMEM);
+	}
+
+	ahd->init_level++;
+
+	/* Allocation of driver data */
+	if (ahd_dmamem_alloc(ahd, ahd->shared_data_dmat,
+			     (void **)&base_vaddr,
+			     BUS_DMA_NOWAIT, &ahd->shared_data_dmamap) != 0) {
+		return (ENOMEM);
+	}
+
+	ahd->init_level++;
+
+	/* And permanently map it in */
+	ahd_dmamap_load(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
+			base_vaddr, driver_data_size, ahd_dmamap_cb,
+			&ahd->shared_data_busaddr, /*flags*/0);
+	ahd->qoutfifo = (uint16_t *)base_vaddr;
+	next_vaddr = (uint8_t *)&ahd->qoutfifo[AHD_QOUT_SIZE];
+	next_baddr = ahd->shared_data_busaddr + AHD_QOUT_SIZE*sizeof(uint16_t);
+	if ((ahd->features & AHD_TARGETMODE) != 0) {
+		ahd->targetcmds = (struct target_cmd *)next_vaddr;
+		next_vaddr += AHD_TMODE_CMDS * sizeof(struct target_cmd);
+		next_baddr += AHD_TMODE_CMDS * sizeof(struct target_cmd);
+	}
+
+	if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
+		ahd->overrun_buf = next_vaddr;
+		next_vaddr += PKT_OVERRUN_BUFSIZE;
+		next_baddr += PKT_OVERRUN_BUFSIZE;
+	}
+
+	/*
+	 * We need one SCB to serve as the "next SCB".  Since the
+	 * tag identifier in this SCB will never be used, there is
+	 * no point in using a valid HSCB tag from an SCB pulled from
+	 * the standard free pool.  So, we allocate this "sentinel"
+	 * specially from the DMA safe memory chunk used for the QOUTFIFO.
+	 */
+	ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr;
+	ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr);
+
+	ahd->init_level++;
+
+	/* Allocate SCB data now that buffer_dmat is initialized */
+	if (ahd_init_scbdata(ahd) != 0)
+		return (ENOMEM);
+
+	if ((ahd->flags & AHD_INITIATORROLE) == 0)
+		ahd->flags &= ~AHD_RESET_BUS_A;
+
+	/*
+	 * Before committing these settings to the chip, give
+	 * the OSM one last chance to modify our configuration.
+	 */
+	ahd_platform_init(ahd);
+
+	/* Bring up the chip. */
+	ahd_chip_init(ahd);
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+
+	if ((ahd->flags & AHD_CURRENT_SENSING) == 0)
+		goto init_done;
+
+	/*
+	 * Verify termination based on current draw and
+	 * warn user if the bus is over/under terminated.
+	 */
+	error = ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL,
+				   CURSENSE_ENB);
+	if (error != 0) {
+		printf("%s: current sensing timeout 1\n", ahd_name(ahd));
+		goto init_done;
+	}
+	for (i = 20, fstat = FLX_FSTAT_BUSY;
+	     (fstat & FLX_FSTAT_BUSY) != 0 && i; i--) {
+		error = ahd_read_flexport(ahd, FLXADDR_FLEXSTAT, &fstat);
+		if (error != 0) {
+			printf("%s: current sensing timeout 2\n",
+			       ahd_name(ahd));
+			goto init_done;
+		}
+	}
+	if (i == 0) {
+		printf("%s: Timedout during current-sensing test\n",
+		       ahd_name(ahd));
+		goto init_done;
+	}
+
+	/* Latch Current Sensing status. */
+	error = ahd_read_flexport(ahd, FLXADDR_CURRENT_STAT, &current_sensing);
+	if (error != 0) {
+		printf("%s: current sensing timeout 3\n", ahd_name(ahd));
+		goto init_done;
+	}
+
+	/* Diable current sensing. */
+	ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0);
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_TERMCTL) != 0) {
+		printf("%s: current_sensing == 0x%x\n",
+		       ahd_name(ahd), current_sensing);
+	}
+#endif
+	warn_user = 0;
+	for (i = 0; i < 4; i++, current_sensing >>= FLX_CSTAT_SHIFT) {
+		u_int term_stat;
+
+		term_stat = (current_sensing & FLX_CSTAT_MASK);
+		switch (term_stat) {
+		case FLX_CSTAT_OVER:
+		case FLX_CSTAT_UNDER:
+			warn_user++;
+		case FLX_CSTAT_INVALID:
+		case FLX_CSTAT_OKAY:
+			if (warn_user == 0 && bootverbose == 0)
+				break;
+			printf("%s: %s Channel %s\n", ahd_name(ahd),
+			       channel_strings[i], termstat_strings[term_stat]);
+			break;
+		}
+	}
+	if (warn_user) {
+		printf("%s: WARNING. Termination is not configured correctly.\n"
+		       "%s: WARNING. SCSI bus operations may FAIL.\n",
+		       ahd_name(ahd), ahd_name(ahd));
+	}
+init_done:
+	ahd_restart(ahd);
+	ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
+			ahd_stat_timer, ahd);
+	return (0);
+}
+
+/*
+ * (Re)initialize chip state after a chip reset.
+ */
+static void
+ahd_chip_init(struct ahd_softc *ahd)
+{
+	uint32_t busaddr;
+	u_int	 sxfrctl1;
+	u_int	 scsiseq_template;
+	u_int	 wait;
+	u_int	 i;
+	u_int	 target;
+
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	/*
+	 * Take the LED out of diagnostic mode
+	 */
+	ahd_outb(ahd, SBLKCTL, ahd_inb(ahd, SBLKCTL) & ~(DIAGLEDEN|DIAGLEDON));
+
+	/*
+	 * Return HS_MAILBOX to its default value.
+	 */
+	ahd->hs_mailbox = 0;
+	ahd_outb(ahd, HS_MAILBOX, 0);
+
+	/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1. */
+	ahd_outb(ahd, IOWNID, ahd->our_id);
+	ahd_outb(ahd, TOWNID, ahd->our_id);
+	sxfrctl1 = (ahd->flags & AHD_TERM_ENB_A) != 0 ? STPWEN : 0;
+	sxfrctl1 |= (ahd->flags & AHD_SPCHK_ENB_A) != 0 ? ENSPCHK : 0;
+	if ((ahd->bugs & AHD_LONG_SETIMO_BUG)
+	 && (ahd->seltime != STIMESEL_MIN)) {
+		/*
+		 * The selection timer duration is twice as long
+		 * as it should be.  Halve it by adding "1" to
+		 * the user specified setting.
+		 */
+		sxfrctl1 |= ahd->seltime + STIMESEL_BUG_ADJ;
+	} else {
+		sxfrctl1 |= ahd->seltime;
+	}
+		
+	ahd_outb(ahd, SXFRCTL0, DFON);
+	ahd_outb(ahd, SXFRCTL1, sxfrctl1|ahd->seltime|ENSTIMER|ACTNEGEN);
+	ahd_outb(ahd, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+
+	/*
+	 * Now that termination is set, wait for up
+	 * to 500ms for our transceivers to settle.  If
+	 * the adapter does not have a cable attached,
+	 * the transceivers may never settle, so don't
+	 * complain if we fail here.
+	 */
+	for (wait = 10000;
+	     (ahd_inb(ahd, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+	     wait--)
+		ahd_delay(100);
+
+	/* Clear any false bus resets due to the transceivers settling */
+	ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
+	ahd_outb(ahd, CLRINT, CLRSCSIINT);
+
+	/* Initialize mode specific S/G state. */
+	for (i = 0; i < 2; i++) {
+		ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
+		ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
+		ahd_outb(ahd, SG_STATE, 0);
+		ahd_outb(ahd, CLRSEQINTSRC, 0xFF);
+		ahd_outb(ahd, SEQIMODE,
+			 ENSAVEPTRS|ENCFG4DATA|ENCFG4ISTAT
+			|ENCFG4TSTAT|ENCFG4ICMD|ENCFG4TCMD);
+	}
+
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+	ahd_outb(ahd, DSCOMMAND0, ahd_inb(ahd, DSCOMMAND0)|MPARCKEN|CACHETHEN);
+	ahd_outb(ahd, DFF_THRSH, RD_DFTHRSH_75|WR_DFTHRSH_75);
+	ahd_outb(ahd, SIMODE0, ENIOERR|ENOVERRUN);
+	ahd_outb(ahd, SIMODE3, ENNTRAMPERR|ENOSRAMPERR);
+	if ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0) {
+		ahd_outb(ahd, OPTIONMODE, AUTOACKEN|AUTO_MSGOUT_DE);
+	} else {
+		ahd_outb(ahd, OPTIONMODE, AUTOACKEN|BUSFREEREV|AUTO_MSGOUT_DE);
+	}
+	ahd_outb(ahd, SCSCHKN, CURRFIFODEF|WIDERESEN|SHVALIDSTDIS);
+	if ((ahd->chip & AHD_BUS_MASK) == AHD_PCIX)
+		/*
+		 * Do not issue a target abort when a split completion
+		 * error occurs.  Let our PCIX interrupt handler deal
+		 * with it instead. H2A4 Razor #625
+		 */
+		ahd_outb(ahd, PCIXCTL, ahd_inb(ahd, PCIXCTL) | SPLTSTADIS);
+
+	if ((ahd->bugs & AHD_LQOOVERRUN_BUG) != 0)
+		ahd_outb(ahd, LQOSCSCTL, LQONOCHKOVER);
+
+	/*
+	 * Tweak IOCELL settings.
+	 */
+	if ((ahd->flags & AHD_HP_BOARD) != 0) {
+		for (i = 0; i < NUMDSPS; i++) {
+			ahd_outb(ahd, DSPSELECT, i);
+			ahd_outb(ahd, WRTBIASCTL, WRTBIASCTL_HP_DEFAULT);
+		}
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MISC) != 0)
+			printf("%s: WRTBIASCTL now 0x%x\n", ahd_name(ahd),
+			       WRTBIASCTL_HP_DEFAULT);
+#endif
+	}
+	ahd_setup_iocell_workaround(ahd);
+
+	/*
+	 * Enable LQI Manager interrupts.
+	 */
+	ahd_outb(ahd, LQIMODE1, ENLQIPHASE_LQ|ENLQIPHASE_NLQ|ENLIQABORT
+			      | ENLQICRCI_LQ|ENLQICRCI_NLQ|ENLQIBADLQI
+			      | ENLQIOVERI_LQ|ENLQIOVERI_NLQ);
+	ahd_outb(ahd, LQOMODE0, ENLQOATNLQ|ENLQOATNPKT|ENLQOTCRC);
+	/*
+	 * An interrupt from LQOBUSFREE is made redundant by the
+	 * BUSFREE interrupt.  We choose to have the sequencer catch
+	 * LQOPHCHGINPKT errors manually for the command phase at the
+	 * start of a packetized selection case.
+	ahd_outb(ahd, LQOMODE1, ENLQOBUSFREE|ENLQOPHACHGINPKT);
+	 */
+	ahd_outb(ahd, LQOMODE1, 0);
+
+	/*
+	 * Setup sequencer interrupt handlers.
+	 */
+	ahd_outw(ahd, INTVEC1_ADDR, ahd_resolve_seqaddr(ahd, LABEL_seq_isr));
+	ahd_outw(ahd, INTVEC2_ADDR, ahd_resolve_seqaddr(ahd, LABEL_timer_isr));
+
+	/*
+	 * Setup SCB Offset registers.
+	 */
+	if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) {
+		ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb,
+			 pkt_long_lun));
+	} else {
+		ahd_outb(ahd, LUNPTR, offsetof(struct hardware_scb, lun));
+	}
+	ahd_outb(ahd, CMDLENPTR, offsetof(struct hardware_scb, cdb_len));
+	ahd_outb(ahd, ATTRPTR, offsetof(struct hardware_scb, task_attribute));
+	ahd_outb(ahd, FLAGPTR, offsetof(struct hardware_scb, task_management));
+	ahd_outb(ahd, CMDPTR, offsetof(struct hardware_scb,
+				       shared_data.idata.cdb));
+	ahd_outb(ahd, QNEXTPTR,
+		 offsetof(struct hardware_scb, next_hscb_busaddr));
+	ahd_outb(ahd, ABRTBITPTR, MK_MESSAGE_BIT_OFFSET);
+	ahd_outb(ahd, ABRTBYTEPTR, offsetof(struct hardware_scb, control));
+	if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) {
+		ahd_outb(ahd, LUNLEN,
+			 sizeof(ahd->next_queued_hscb->pkt_long_lun) - 1);
+	} else {
+		ahd_outb(ahd, LUNLEN, LUNLEN_SINGLE_LEVEL_LUN);
+	}
+	ahd_outb(ahd, CDBLIMIT, SCB_CDB_LEN_PTR - 1);
+	ahd_outb(ahd, MAXCMD, 0xFF);
+	ahd_outb(ahd, SCBAUTOPTR,
+		 AUSCBPTR_EN | offsetof(struct hardware_scb, tag));
+
+	/* We haven't been enabled for target mode yet. */
+	ahd_outb(ahd, MULTARGID, 0);
+	ahd_outb(ahd, MULTARGID + 1, 0);
+
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	/* Initialize the negotiation table. */
+	if ((ahd->features & AHD_NEW_IOCELL_OPTS) == 0) {
+		/*
+		 * Clear the spare bytes in the neg table to avoid
+		 * spurious parity errors.
+		 */
+		for (target = 0; target < AHD_NUM_TARGETS; target++) {
+			ahd_outb(ahd, NEGOADDR, target);
+			ahd_outb(ahd, ANNEXCOL, AHD_ANNEXCOL_PER_DEV0);
+			for (i = 0; i < AHD_NUM_PER_DEV_ANNEXCOLS; i++)
+				ahd_outb(ahd, ANNEXDAT, 0);
+		}
+	}
+	for (target = 0; target < AHD_NUM_TARGETS; target++) {
+		struct	 ahd_devinfo devinfo;
+		struct	 ahd_initiator_tinfo *tinfo;
+		struct	 ahd_tmode_tstate *tstate;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    target, &tstate);
+		ahd_compile_devinfo(&devinfo, ahd->our_id,
+				    target, CAM_LUN_WILDCARD,
+				    'A', ROLE_INITIATOR);
+		ahd_update_neg_table(ahd, &devinfo, &tinfo->curr);
+	}
+
+	ahd_outb(ahd, CLRSINT3, NTRAMPERR|OSRAMPERR);
+	ahd_outb(ahd, CLRINT, CLRSCSIINT);
+
+#ifdef NEEDS_MORE_TESTING
+	/*
+	 * Always enable abort on incoming L_Qs if this feature is
+	 * supported.  We use this to catch invalid SCB references.
+	 */
+	if ((ahd->bugs & AHD_ABORT_LQI_BUG) == 0)
+		ahd_outb(ahd, LQCTL1, ABORTPENDING);
+	else
+#endif
+		ahd_outb(ahd, LQCTL1, 0);
+
+	/* All of our queues are empty */
+	ahd->qoutfifonext = 0;
+	ahd->qoutfifonext_valid_tag = QOUTFIFO_ENTRY_VALID_LE;
+	ahd_outb(ahd, QOUTFIFO_ENTRY_VALID_TAG, QOUTFIFO_ENTRY_VALID >> 8);
+	for (i = 0; i < AHD_QOUT_SIZE; i++)
+		ahd->qoutfifo[i] = 0;
+	ahd_sync_qoutfifo(ahd, BUS_DMASYNC_PREREAD);
+
+	ahd->qinfifonext = 0;
+	for (i = 0; i < AHD_QIN_SIZE; i++)
+		ahd->qinfifo[i] = SCB_LIST_NULL;
+
+	if ((ahd->features & AHD_TARGETMODE) != 0) {
+		/* All target command blocks start out invalid. */
+		for (i = 0; i < AHD_TMODE_CMDS; i++)
+			ahd->targetcmds[i].cmd_valid = 0;
+		ahd_sync_tqinfifo(ahd, BUS_DMASYNC_PREREAD);
+		ahd->tqinfifonext = 1;
+		ahd_outb(ahd, KERNEL_TQINPOS, ahd->tqinfifonext - 1);
+		ahd_outb(ahd, TQINPOS, ahd->tqinfifonext);
+	}
+
+	/* Initialize Scratch Ram. */
+	ahd_outb(ahd, SEQ_FLAGS, 0);
+	ahd_outb(ahd, SEQ_FLAGS2, 0);
+
+	/* We don't have any waiting selections */
+	ahd_outw(ahd, WAITING_TID_HEAD, SCB_LIST_NULL);
+	ahd_outw(ahd, WAITING_TID_TAIL, SCB_LIST_NULL);
+	for (i = 0; i < AHD_NUM_TARGETS; i++)
+		ahd_outw(ahd, WAITING_SCB_TAILS + (2 * i), SCB_LIST_NULL);
+
+	/*
+	 * Nobody is waiting to be DMAed into the QOUTFIFO.
+	 */
+	ahd_outw(ahd, COMPLETE_SCB_HEAD, SCB_LIST_NULL);
+	ahd_outw(ahd, COMPLETE_SCB_DMAINPROG_HEAD, SCB_LIST_NULL);
+	ahd_outw(ahd, COMPLETE_DMA_SCB_HEAD, SCB_LIST_NULL);
+
+	/*
+	 * The Freeze Count is 0.
+	 */
+	ahd_outw(ahd, QFREEZE_COUNT, 0);
+
+	/*
+	 * Tell the sequencer where it can find our arrays in memory.
+	 */
+	busaddr = ahd->shared_data_busaddr;
+	ahd_outb(ahd, SHARED_DATA_ADDR, busaddr & 0xFF);
+	ahd_outb(ahd, SHARED_DATA_ADDR + 1, (busaddr >> 8) & 0xFF);
+	ahd_outb(ahd, SHARED_DATA_ADDR + 2, (busaddr >> 16) & 0xFF);
+	ahd_outb(ahd, SHARED_DATA_ADDR + 3, (busaddr >> 24) & 0xFF);
+	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR, busaddr & 0xFF);
+	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 1, (busaddr >> 8) & 0xFF);
+	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 2, (busaddr >> 16) & 0xFF);
+	ahd_outb(ahd, QOUTFIFO_NEXT_ADDR + 3, (busaddr >> 24) & 0xFF);
+
+	/*
+	 * Setup the allowed SCSI Sequences based on operational mode.
+	 * If we are a target, we'll enable select in operations once
+	 * we've had a lun enabled.
+	 */
+	scsiseq_template = ENAUTOATNP;
+	if ((ahd->flags & AHD_INITIATORROLE) != 0)
+		scsiseq_template |= ENRSELI;
+	ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq_template);
+
+	/* There are no busy SCBs yet. */
+	for (target = 0; target < AHD_NUM_TARGETS; target++) {
+		int lun;
+
+		for (lun = 0; lun < AHD_NUM_LUNS_NONPKT; lun++)
+			ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(target, 'A', lun));
+	}
+
+	/*
+	 * Initialize the group code to command length table.
+	 * Vendor Unique codes are set to 0 so we only capture
+	 * the first byte of the cdb.  These can be overridden
+	 * when target mode is enabled.
+	 */
+	ahd_outb(ahd, CMDSIZE_TABLE, 5);
+	ahd_outb(ahd, CMDSIZE_TABLE + 1, 9);
+	ahd_outb(ahd, CMDSIZE_TABLE + 2, 9);
+	ahd_outb(ahd, CMDSIZE_TABLE + 3, 0);
+	ahd_outb(ahd, CMDSIZE_TABLE + 4, 15);
+	ahd_outb(ahd, CMDSIZE_TABLE + 5, 11);
+	ahd_outb(ahd, CMDSIZE_TABLE + 6, 0);
+	ahd_outb(ahd, CMDSIZE_TABLE + 7, 0);
+		
+	/* Tell the sequencer of our initial queue positions */
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+	ahd_outb(ahd, QOFF_CTLSTA, SCB_QSIZE_512);
+	ahd->qinfifonext = 0;
+	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+	ahd_set_hescb_qoff(ahd, 0);
+	ahd_set_snscb_qoff(ahd, 0);
+	ahd_set_sescb_qoff(ahd, 0);
+	ahd_set_sdscb_qoff(ahd, 0);
+
+	/*
+	 * Tell the sequencer which SCB will be the next one it receives.
+	 */
+	busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+
+	/*
+	 * Default to coalescing disabled.
+	 */
+	ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0);
+	ahd_outw(ahd, CMDS_PENDING, 0);
+	ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer,
+				     ahd->int_coalescing_maxcmds,
+				     ahd->int_coalescing_mincmds);
+	ahd_enable_coalescing(ahd, FALSE);
+
+	ahd_loadseq(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+}
+
+/*
+ * Setup default device and controller settings.
+ * This should only be called if our probe has
+ * determined that no configuration data is available.
+ */
+int
+ahd_default_config(struct ahd_softc *ahd)
+{
+	int	targ;
+
+	ahd->our_id = 7;
+
+	/*
+	 * Allocate a tstate to house information for our
+	 * initiator presence on the bus as well as the user
+	 * data for any target mode initiator.
+	 */
+	if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
+		printf("%s: unable to allocate ahd_tmode_tstate.  "
+		       "Failing attach\n", ahd_name(ahd));
+		return (ENOMEM);
+	}
+
+	for (targ = 0; targ < AHD_NUM_TARGETS; targ++) {
+		struct	 ahd_devinfo devinfo;
+		struct	 ahd_initiator_tinfo *tinfo;
+		struct	 ahd_tmode_tstate *tstate;
+		uint16_t target_mask;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    targ, &tstate);
+		/*
+		 * We support SPC2 and SPI4.
+		 */
+		tinfo->user.protocol_version = 4;
+		tinfo->user.transport_version = 4;
+
+		target_mask = 0x01 << targ;
+		ahd->user_discenable |= target_mask;
+		tstate->discenable |= target_mask;
+		ahd->user_tagenable |= target_mask;
+#ifdef AHD_FORCE_160
+		tinfo->user.period = AHD_SYNCRATE_DT;
+#else
+		tinfo->user.period = AHD_SYNCRATE_160;
+#endif
+		tinfo->user.offset = MAX_OFFSET;
+		tinfo->user.ppr_options = MSG_EXT_PPR_RD_STRM
+					| MSG_EXT_PPR_WR_FLOW
+					| MSG_EXT_PPR_HOLD_MCS
+					| MSG_EXT_PPR_IU_REQ
+					| MSG_EXT_PPR_QAS_REQ
+					| MSG_EXT_PPR_DT_REQ;
+		if ((ahd->features & AHD_RTI) != 0)
+			tinfo->user.ppr_options |= MSG_EXT_PPR_RTI;
+
+		tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+
+		/*
+		 * Start out Async/Narrow/Untagged and with
+		 * conservative protocol support.
+		 */
+		tinfo->goal.protocol_version = 2;
+		tinfo->goal.transport_version = 2;
+		tinfo->curr.protocol_version = 2;
+		tinfo->curr.transport_version = 2;
+		ahd_compile_devinfo(&devinfo, ahd->our_id,
+				    targ, CAM_LUN_WILDCARD,
+				    'A', ROLE_INITIATOR);
+		tstate->tagenable &= ~target_mask;
+		ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+			      AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE);
+		ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
+				 /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL,
+				 /*paused*/TRUE);
+	}
+	return (0);
+}
+
+/*
+ * Parse device configuration information.
+ */
+int
+ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc)
+{
+	int targ;
+	int max_targ;
+
+	max_targ = sc->max_targets & CFMAXTARG;
+	ahd->our_id = sc->brtime_id & CFSCSIID;
+
+	/*
+	 * Allocate a tstate to house information for our
+	 * initiator presence on the bus as well as the user
+	 * data for any target mode initiator.
+	 */
+	if (ahd_alloc_tstate(ahd, ahd->our_id, 'A') == NULL) {
+		printf("%s: unable to allocate ahd_tmode_tstate.  "
+		       "Failing attach\n", ahd_name(ahd));
+		return (ENOMEM);
+	}
+
+	for (targ = 0; targ < max_targ; targ++) {
+		struct	 ahd_devinfo devinfo;
+		struct	 ahd_initiator_tinfo *tinfo;
+		struct	 ahd_transinfo *user_tinfo;
+		struct	 ahd_tmode_tstate *tstate;
+		uint16_t target_mask;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    targ, &tstate);
+		user_tinfo = &tinfo->user;
+
+		/*
+		 * We support SPC2 and SPI4.
+		 */
+		tinfo->user.protocol_version = 4;
+		tinfo->user.transport_version = 4;
+
+		target_mask = 0x01 << targ;
+		ahd->user_discenable &= ~target_mask;
+		tstate->discenable &= ~target_mask;
+		ahd->user_tagenable &= ~target_mask;
+		if (sc->device_flags[targ] & CFDISC) {
+			tstate->discenable |= target_mask;
+			ahd->user_discenable |= target_mask;
+			ahd->user_tagenable |= target_mask;
+		} else {
+			/*
+			 * Cannot be packetized without disconnection.
+			 */
+			sc->device_flags[targ] &= ~CFPACKETIZED;
+		}
+
+		user_tinfo->ppr_options = 0;
+		user_tinfo->period = (sc->device_flags[targ] & CFXFER);
+		if (user_tinfo->period < CFXFER_ASYNC) {
+			if (user_tinfo->period <= AHD_PERIOD_10MHz)
+				user_tinfo->ppr_options |= MSG_EXT_PPR_DT_REQ;
+			user_tinfo->offset = MAX_OFFSET;
+		} else  {
+			user_tinfo->offset = 0;
+			user_tinfo->period = AHD_ASYNC_XFER_PERIOD;
+		}
+#ifdef AHD_FORCE_160
+		if (user_tinfo->period <= AHD_SYNCRATE_160)
+			user_tinfo->period = AHD_SYNCRATE_DT;
+#endif
+
+		if ((sc->device_flags[targ] & CFPACKETIZED) != 0) {
+			user_tinfo->ppr_options |= MSG_EXT_PPR_RD_STRM
+						|  MSG_EXT_PPR_WR_FLOW
+						|  MSG_EXT_PPR_HOLD_MCS
+						|  MSG_EXT_PPR_IU_REQ;
+			if ((ahd->features & AHD_RTI) != 0)
+				user_tinfo->ppr_options |= MSG_EXT_PPR_RTI;
+		}
+
+		if ((sc->device_flags[targ] & CFQAS) != 0)
+			user_tinfo->ppr_options |= MSG_EXT_PPR_QAS_REQ;
+
+		if ((sc->device_flags[targ] & CFWIDEB) != 0)
+			user_tinfo->width = MSG_EXT_WDTR_BUS_16_BIT;
+		else
+			user_tinfo->width = MSG_EXT_WDTR_BUS_8_BIT;
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MISC) != 0)
+			printf("(%d): %x:%x:%x:%x\n", targ, user_tinfo->width,
+			       user_tinfo->period, user_tinfo->offset,
+			       user_tinfo->ppr_options);
+#endif
+		/*
+		 * Start out Async/Narrow/Untagged and with
+		 * conservative protocol support.
+		 */
+		tstate->tagenable &= ~target_mask;
+		tinfo->goal.protocol_version = 2;
+		tinfo->goal.transport_version = 2;
+		tinfo->curr.protocol_version = 2;
+		tinfo->curr.transport_version = 2;
+		ahd_compile_devinfo(&devinfo, ahd->our_id,
+				    targ, CAM_LUN_WILDCARD,
+				    'A', ROLE_INITIATOR);
+		ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+			      AHD_TRANS_CUR|AHD_TRANS_GOAL, /*paused*/TRUE);
+		ahd_set_syncrate(ahd, &devinfo, /*period*/0, /*offset*/0,
+				 /*ppr_options*/0, AHD_TRANS_CUR|AHD_TRANS_GOAL,
+				 /*paused*/TRUE);
+	}
+
+	ahd->flags &= ~AHD_SPCHK_ENB_A;
+	if (sc->bios_control & CFSPARITY)
+		ahd->flags |= AHD_SPCHK_ENB_A;
+
+	ahd->flags &= ~AHD_RESET_BUS_A;
+	if (sc->bios_control & CFRESETB)
+		ahd->flags |= AHD_RESET_BUS_A;
+
+	ahd->flags &= ~AHD_EXTENDED_TRANS_A;
+	if (sc->bios_control & CFEXTEND)
+		ahd->flags |= AHD_EXTENDED_TRANS_A;
+
+	ahd->flags &= ~AHD_BIOS_ENABLED;
+	if ((sc->bios_control & CFBIOSSTATE) == CFBS_ENABLED)
+		ahd->flags |= AHD_BIOS_ENABLED;
+
+	ahd->flags &= ~AHD_STPWLEVEL_A;
+	if ((sc->adapter_control & CFSTPWLEVEL) != 0)
+		ahd->flags |= AHD_STPWLEVEL_A;
+
+	return (0);
+}
+
+/*
+ * Parse device configuration information.
+ */
+int
+ahd_parse_vpddata(struct ahd_softc *ahd, struct vpd_config *vpd)
+{
+	int error;
+
+	error = ahd_verify_vpd_cksum(vpd);
+	if (error == 0)
+		return (EINVAL);
+	if ((vpd->bios_flags & VPDBOOTHOST) != 0)
+		ahd->flags |= AHD_BOOT_CHANNEL;
+	return (0);
+}
+
+void
+ahd_intr_enable(struct ahd_softc *ahd, int enable)
+{
+	u_int hcntrl;
+
+	hcntrl = ahd_inb(ahd, HCNTRL);
+	hcntrl &= ~INTEN;
+	ahd->pause &= ~INTEN;
+	ahd->unpause &= ~INTEN;
+	if (enable) {
+		hcntrl |= INTEN;
+		ahd->pause |= INTEN;
+		ahd->unpause |= INTEN;
+	}
+	ahd_outb(ahd, HCNTRL, hcntrl);
+}
+
+void
+ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds,
+			     u_int mincmds)
+{
+	if (timer > AHD_TIMER_MAX_US)
+		timer = AHD_TIMER_MAX_US;
+	ahd->int_coalescing_timer = timer;
+
+	if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX)
+		maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX;
+	if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX)
+		mincmds = AHD_INT_COALESCING_MINCMDS_MAX;
+	ahd->int_coalescing_maxcmds = maxcmds;
+	ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK);
+	ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds);
+	ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds);
+}
+
+void
+ahd_enable_coalescing(struct ahd_softc *ahd, int enable)
+{
+
+	ahd->hs_mailbox &= ~ENINT_COALESCE;
+	if (enable)
+		ahd->hs_mailbox |= ENINT_COALESCE;
+	ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox);
+	ahd_flush_device_writes(ahd);
+	ahd_run_qoutfifo(ahd);
+}
+
+/*
+ * Ensure that the card is paused in a location
+ * outside of all critical sections and that all
+ * pending work is completed prior to returning.
+ * This routine should only be called from outside
+ * an interrupt context.
+ */
+void
+ahd_pause_and_flushwork(struct ahd_softc *ahd)
+{
+	u_int intstat;
+	u_int maxloops;
+	u_int qfreeze_cnt;
+
+	maxloops = 1000;
+	ahd->flags |= AHD_ALL_INTERRUPTS;
+	ahd_pause(ahd);
+	/*
+	 * Increment the QFreeze Count so that the sequencer
+	 * will not start new selections.  We do this only
+	 * until we are safely paused without further selections
+	 * pending.
+	 */
+	ahd_outw(ahd, QFREEZE_COUNT, ahd_inw(ahd, QFREEZE_COUNT) + 1);
+	ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
+	do {
+		struct scb *waiting_scb;
+
+		ahd_unpause(ahd);
+		ahd_intr(ahd);
+		ahd_pause(ahd);
+		ahd_clear_critical_section(ahd);
+		intstat = ahd_inb(ahd, INTSTAT);
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
+			ahd_outb(ahd, SCSISEQ0,
+				 ahd_inb(ahd, SCSISEQ0) & ~ENSELO);
+		/*
+		 * In the non-packetized case, the sequencer (for Rev A),
+		 * relies on ENSELO remaining set after SELDO.  The hardware
+		 * auto-clears ENSELO in the packetized case.
+		 */
+		waiting_scb = ahd_lookup_scb(ahd,
+					     ahd_inw(ahd, WAITING_TID_HEAD));
+		if (waiting_scb != NULL
+		 && (waiting_scb->flags & SCB_PACKETIZED) == 0
+		 && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
+			ahd_outb(ahd, SCSISEQ0,
+				 ahd_inb(ahd, SCSISEQ0) | ENSELO);
+	} while (--maxloops
+	      && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
+	      && ((intstat & INT_PEND) != 0
+	       || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0
+	       || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0));
+
+	if (maxloops == 0) {
+		printf("Infinite interrupt loop, INTSTAT = %x",
+		      ahd_inb(ahd, INTSTAT));
+	}
+	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
+	if (qfreeze_cnt == 0) {
+		printf("%s: ahd_pause_and_flushwork with 0 qfreeze count!\n",
+		       ahd_name(ahd));
+	} else {
+		qfreeze_cnt--;
+	}
+	ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
+	if (qfreeze_cnt == 0)
+		ahd_outb(ahd, SEQ_FLAGS2,
+			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+
+	ahd_flush_qoutfifo(ahd);
+
+	ahd_platform_flushwork(ahd);
+	ahd->flags &= ~AHD_ALL_INTERRUPTS;
+}
+
+int
+ahd_suspend(struct ahd_softc *ahd)
+{
+
+	ahd_pause_and_flushwork(ahd);
+
+	if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+		ahd_unpause(ahd);
+		return (EBUSY);
+	}
+	ahd_shutdown(ahd);
+	return (0);
+}
+
+int
+ahd_resume(struct ahd_softc *ahd)
+{
+
+	ahd_reset(ahd, /*reinit*/TRUE);
+	ahd_intr_enable(ahd, TRUE); 
+	ahd_restart(ahd);
+	return (0);
+}
+
+/************************** Busy Target Table *********************************/
+/*
+ * Set SCBPTR to the SCB that contains the busy
+ * table entry for TCL.  Return the offset into
+ * the SCB that contains the entry for TCL.
+ * saved_scbid is dereferenced and set to the
+ * scbid that should be restored once manipualtion
+ * of the TCL entry is complete.
+ */
+static __inline u_int
+ahd_index_busy_tcl(struct ahd_softc *ahd, u_int *saved_scbid, u_int tcl)
+{
+	/*
+	 * Index to the SCB that contains the busy entry.
+	 */
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	*saved_scbid = ahd_get_scbptr(ahd);
+	ahd_set_scbptr(ahd, TCL_LUN(tcl)
+		     | ((TCL_TARGET_OFFSET(tcl) & 0xC) << 4));
+
+	/*
+	 * And now calculate the SCB offset to the entry.
+	 * Each entry is 2 bytes wide, hence the
+	 * multiplication by 2.
+	 */
+	return (((TCL_TARGET_OFFSET(tcl) & 0x3) << 1) + SCB_DISCONNECTED_LISTS);
+}
+
+/*
+ * Return the untagged transaction id for a given target/channel lun.
+ */
+u_int
+ahd_find_busy_tcl(struct ahd_softc *ahd, u_int tcl)
+{
+	u_int scbid;
+	u_int scb_offset;
+	u_int saved_scbptr;
+		
+	scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl);
+	scbid = ahd_inw_scbram(ahd, scb_offset);
+	ahd_set_scbptr(ahd, saved_scbptr);
+	return (scbid);
+}
+
+void
+ahd_busy_tcl(struct ahd_softc *ahd, u_int tcl, u_int scbid)
+{
+	u_int scb_offset;
+	u_int saved_scbptr;
+		
+	scb_offset = ahd_index_busy_tcl(ahd, &saved_scbptr, tcl);
+	ahd_outw(ahd, scb_offset, scbid);
+	ahd_set_scbptr(ahd, saved_scbptr);
+}
+
+/************************** SCB and SCB queue management **********************/
+int
+ahd_match_scb(struct ahd_softc *ahd, struct scb *scb, int target,
+	      char channel, int lun, u_int tag, role_t role)
+{
+	int targ = SCB_GET_TARGET(ahd, scb);
+	char chan = SCB_GET_CHANNEL(ahd, scb);
+	int slun = SCB_GET_LUN(scb);
+	int match;
+
+	match = ((chan == channel) || (channel == ALL_CHANNELS));
+	if (match != 0)
+		match = ((targ == target) || (target == CAM_TARGET_WILDCARD));
+	if (match != 0)
+		match = ((lun == slun) || (lun == CAM_LUN_WILDCARD));
+	if (match != 0) {
+#ifdef AHD_TARGET_MODE
+		int group;
+
+		group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code);
+		if (role == ROLE_INITIATOR) {
+			match = (group != XPT_FC_GROUP_TMODE)
+			      && ((tag == SCB_GET_TAG(scb))
+			       || (tag == SCB_LIST_NULL));
+		} else if (role == ROLE_TARGET) {
+			match = (group == XPT_FC_GROUP_TMODE)
+			      && ((tag == scb->io_ctx->csio.tag_id)
+			       || (tag == SCB_LIST_NULL));
+		}
+#else /* !AHD_TARGET_MODE */
+		match = ((tag == SCB_GET_TAG(scb)) || (tag == SCB_LIST_NULL));
+#endif /* AHD_TARGET_MODE */
+	}
+
+	return match;
+}
+
+void
+ahd_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
+{
+	int	target;
+	char	channel;
+	int	lun;
+
+	target = SCB_GET_TARGET(ahd, scb);
+	lun = SCB_GET_LUN(scb);
+	channel = SCB_GET_CHANNEL(ahd, scb);
+	
+	ahd_search_qinfifo(ahd, target, channel, lun,
+			   /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN,
+			   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	ahd_platform_freeze_devq(ahd, scb);
+}
+
+void
+ahd_qinfifo_requeue_tail(struct ahd_softc *ahd, struct scb *scb)
+{
+	struct scb	*prev_scb;
+	ahd_mode_state	 saved_modes;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+	prev_scb = NULL;
+	if (ahd_qinfifo_count(ahd) != 0) {
+		u_int prev_tag;
+		u_int prev_pos;
+
+		prev_pos = AHD_QIN_WRAP(ahd->qinfifonext - 1);
+		prev_tag = ahd->qinfifo[prev_pos];
+		prev_scb = ahd_lookup_scb(ahd, prev_tag);
+	}
+	ahd_qinfifo_requeue(ahd, prev_scb, scb);
+	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+static void
+ahd_qinfifo_requeue(struct ahd_softc *ahd, struct scb *prev_scb,
+		    struct scb *scb)
+{
+	if (prev_scb == NULL) {
+		uint32_t busaddr;
+
+		busaddr = ahd_le32toh(scb->hscb->hscb_busaddr);
+		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
+		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
+		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
+		ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+	} else {
+		prev_scb->hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
+		ahd_sync_scb(ahd, prev_scb, 
+			     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+	}
+	ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
+	ahd->qinfifonext++;
+	scb->hscb->next_hscb_busaddr = ahd->next_queued_hscb->hscb_busaddr;
+	ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+}
+
+static int
+ahd_qinfifo_count(struct ahd_softc *ahd)
+{
+	u_int qinpos;
+	u_int wrap_qinpos;
+	u_int wrap_qinfifonext;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	qinpos = ahd_get_snscb_qoff(ahd);
+	wrap_qinpos = AHD_QIN_WRAP(qinpos);
+	wrap_qinfifonext = AHD_QIN_WRAP(ahd->qinfifonext);
+	if (wrap_qinfifonext >= wrap_qinpos)
+		return (wrap_qinfifonext - wrap_qinpos);
+	else
+		return (wrap_qinfifonext
+		      + NUM_ELEMENTS(ahd->qinfifo) - wrap_qinpos);
+}
+
+void
+ahd_reset_cmds_pending(struct ahd_softc *ahd)
+{
+	struct		scb *scb;
+	ahd_mode_state	saved_modes;
+	u_int		pending_cmds;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+	/*
+	 * Don't count any commands as outstanding that the
+	 * sequencer has already marked for completion.
+	 */
+	ahd_flush_qoutfifo(ahd);
+
+	pending_cmds = 0;
+	LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+		pending_cmds++;
+	}
+	ahd_outw(ahd, CMDS_PENDING, pending_cmds - ahd_qinfifo_count(ahd));
+	ahd_restore_modes(ahd, saved_modes);
+	ahd->flags &= ~AHD_UPDATE_PEND_CMDS;
+}
+
+int
+ahd_search_qinfifo(struct ahd_softc *ahd, int target, char channel,
+		   int lun, u_int tag, role_t role, uint32_t status,
+		   ahd_search_action action)
+{
+	struct scb	*scb;
+	struct scb	*prev_scb;
+	ahd_mode_state	 saved_modes;
+	u_int		 qinstart;
+	u_int		 qinpos;
+	u_int		 qintail;
+	u_int		 tid_next;
+	u_int		 tid_prev;
+	u_int		 scbid;
+	u_int		 savedscbptr;
+	uint32_t	 busaddr;
+	int		 found;
+	int		 targets;
+
+	/* Must be in CCHAN mode */
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+
+	/*
+	 * Halt any pending SCB DMA.  The sequencer will reinitiate
+	 * this dma if the qinfifo is not empty once we unpause.
+	 */
+	if ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN|CCSCBDIR))
+	 == (CCARREN|CCSCBEN|CCSCBDIR)) {
+		ahd_outb(ahd, CCSCBCTL,
+			 ahd_inb(ahd, CCSCBCTL) & ~(CCARREN|CCSCBEN));
+		while ((ahd_inb(ahd, CCSCBCTL) & (CCARREN|CCSCBEN)) != 0)
+			;
+	}
+	/* Determine sequencer's position in the qinfifo. */
+	qintail = AHD_QIN_WRAP(ahd->qinfifonext);
+	qinstart = ahd_get_snscb_qoff(ahd);
+	qinpos = AHD_QIN_WRAP(qinstart);
+	found = 0;
+	prev_scb = NULL;
+
+	if (action == SEARCH_PRINT) {
+		printf("qinstart = %d qinfifonext = %d\nQINFIFO:",
+		       qinstart, ahd->qinfifonext);
+	}
+
+	/*
+	 * Start with an empty queue.  Entries that are not chosen
+	 * for removal will be re-added to the queue as we go.
+	 */
+	ahd->qinfifonext = qinstart;
+	busaddr = ahd_le32toh(ahd->next_queued_hscb->hscb_busaddr);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 0, busaddr & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 1, (busaddr >> 8) & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 2, (busaddr >> 16) & 0xFF);
+	ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF);
+
+	while (qinpos != qintail) {
+		scb = ahd_lookup_scb(ahd, ahd->qinfifo[qinpos]);
+		if (scb == NULL) {
+			printf("qinpos = %d, SCB index = %d\n",
+				qinpos, ahd->qinfifo[qinpos]);
+			panic("Loop 1\n");
+		}
+
+		if (ahd_match_scb(ahd, scb, target, channel, lun, tag, role)) {
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahd_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahd_set_transaction_status(scb,
+								   status);
+				cstat = ahd_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahd_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in qinfifo\n");
+				ahd_done(ahd, scb);
+
+				/* FALLTHROUGH */
+			}
+			case SEARCH_REMOVE:
+				break;
+			case SEARCH_PRINT:
+				printf(" 0x%x", ahd->qinfifo[qinpos]);
+				/* FALLTHROUGH */
+			case SEARCH_COUNT:
+				ahd_qinfifo_requeue(ahd, prev_scb, scb);
+				prev_scb = scb;
+				break;
+			}
+		} else {
+			ahd_qinfifo_requeue(ahd, prev_scb, scb);
+			prev_scb = scb;
+		}
+		qinpos = AHD_QIN_WRAP(qinpos+1);
+	}
+
+	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+
+	if (action == SEARCH_PRINT)
+		printf("\nWAITING_TID_QUEUES:\n");
+
+	/*
+	 * Search waiting for selection lists.  We traverse the
+	 * list of "their ids" waiting for selection and, if
+	 * appropriate, traverse the SCBs of each "their id"
+	 * looking for matches.
+	 */
+	savedscbptr = ahd_get_scbptr(ahd);
+	tid_next = ahd_inw(ahd, WAITING_TID_HEAD);
+	tid_prev = SCB_LIST_NULL;
+	targets = 0;
+	for (scbid = tid_next; !SCBID_IS_NULL(scbid); scbid = tid_next) {
+		u_int tid_head;
+
+		/*
+		 * We limit based on the number of SCBs since
+		 * MK_MESSAGE SCBs are not in the per-tid lists.
+		 */
+		targets++;
+		if (targets > AHD_SCB_MAX) {
+			panic("TID LIST LOOP");
+		}
+		if (scbid >= ahd->scb_data.numscbs) {
+			printf("%s: Waiting TID List inconsistency. "
+			       "SCB index == 0x%x, yet numscbs == 0x%x.",
+			       ahd_name(ahd), scbid, ahd->scb_data.numscbs);
+			ahd_dump_card_state(ahd);
+			panic("for safety");
+		}
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: SCB = 0x%x Not Active!\n",
+			       ahd_name(ahd), scbid);
+			panic("Waiting TID List traversal\n");
+		}
+		ahd_set_scbptr(ahd, scbid);
+		tid_next = ahd_inw_scbram(ahd, SCB_NEXT2);
+		if (ahd_match_scb(ahd, scb, target, channel, CAM_LUN_WILDCARD,
+				  SCB_LIST_NULL, ROLE_UNKNOWN) == 0) {
+			tid_prev = scbid;
+			continue;
+		}
+
+		/*
+		 * We found a list of scbs that needs to be searched.
+		 */
+		if (action == SEARCH_PRINT)
+			printf("       %d ( ", SCB_GET_TARGET(ahd, scb));
+		tid_head = scbid;
+		found += ahd_search_scb_list(ahd, target, channel,
+					     lun, tag, role, status,
+					     action, &tid_head,
+					     SCB_GET_TARGET(ahd, scb));
+		if (tid_head != scbid)
+			ahd_stitch_tid_list(ahd, tid_prev, tid_head, tid_next);
+		if (!SCBID_IS_NULL(tid_head))
+			tid_prev = tid_head;
+		if (action == SEARCH_PRINT)
+			printf(")\n");
+	}
+	ahd_set_scbptr(ahd, savedscbptr);
+	ahd_restore_modes(ahd, saved_modes);
+	return (found);
+}
+
+static int
+ahd_search_scb_list(struct ahd_softc *ahd, int target, char channel,
+		    int lun, u_int tag, role_t role, uint32_t status,
+		    ahd_search_action action, u_int *list_head, u_int tid)
+{
+	struct	scb *scb;
+	u_int	scbid;
+	u_int	next;
+	u_int	prev;
+	int	found;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	found = 0;
+	prev = SCB_LIST_NULL;
+	next = *list_head;
+	for (scbid = next; !SCBID_IS_NULL(scbid); scbid = next) {
+		if (scbid >= ahd->scb_data.numscbs) {
+			printf("%s:SCB List inconsistency. "
+			       "SCB == 0x%x, yet numscbs == 0x%x.",
+			       ahd_name(ahd), scbid, ahd->scb_data.numscbs);
+			ahd_dump_card_state(ahd);
+			panic("for safety");
+		}
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb == NULL) {
+			printf("%s: SCB = %d Not Active!\n",
+			       ahd_name(ahd), scbid);
+			panic("Waiting List traversal\n");
+		}
+		ahd_set_scbptr(ahd, scbid);
+		next = ahd_inw_scbram(ahd, SCB_NEXT);
+		if (ahd_match_scb(ahd, scb, target, channel,
+				  lun, SCB_LIST_NULL, role) == 0) {
+			prev = scbid;
+			continue;
+		}
+		found++;
+		switch (action) {
+		case SEARCH_COMPLETE:
+		{
+			cam_status ostat;
+			cam_status cstat;
+
+			ostat = ahd_get_transaction_status(scb);
+			if (ostat == CAM_REQ_INPROG)
+				ahd_set_transaction_status(scb, status);
+			cstat = ahd_get_transaction_status(scb);
+			if (cstat != CAM_REQ_CMP)
+				ahd_freeze_scb(scb);
+			if ((scb->flags & SCB_ACTIVE) == 0)
+				printf("Inactive SCB in Waiting List\n");
+			ahd_done(ahd, scb);
+			/* FALLTHROUGH */
+		}
+		case SEARCH_REMOVE:
+			ahd_rem_wscb(ahd, scbid, prev, next, tid);
+			if (prev == SCB_LIST_NULL)
+				*list_head = next;
+			break;
+		case SEARCH_PRINT:
+			printf("0x%x ", scbid);
+		case SEARCH_COUNT:
+			prev = scbid;
+			break;
+		}
+		if (found > AHD_SCB_MAX)
+			panic("SCB LIST LOOP");
+	}
+	if (action == SEARCH_COMPLETE
+	 || action == SEARCH_REMOVE)
+		ahd_outw(ahd, CMDS_PENDING, ahd_inw(ahd, CMDS_PENDING) - found);
+	return (found);
+}
+
+static void
+ahd_stitch_tid_list(struct ahd_softc *ahd, u_int tid_prev,
+		    u_int tid_cur, u_int tid_next)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+
+	if (SCBID_IS_NULL(tid_cur)) {
+
+		/* Bypass current TID list */
+		if (SCBID_IS_NULL(tid_prev)) {
+			ahd_outw(ahd, WAITING_TID_HEAD, tid_next);
+		} else {
+			ahd_set_scbptr(ahd, tid_prev);
+			ahd_outw(ahd, SCB_NEXT2, tid_next);
+		}
+		if (SCBID_IS_NULL(tid_next))
+			ahd_outw(ahd, WAITING_TID_TAIL, tid_prev);
+	} else {
+
+		/* Stitch through tid_cur */
+		if (SCBID_IS_NULL(tid_prev)) {
+			ahd_outw(ahd, WAITING_TID_HEAD, tid_cur);
+		} else {
+			ahd_set_scbptr(ahd, tid_prev);
+			ahd_outw(ahd, SCB_NEXT2, tid_cur);
+		}
+		ahd_set_scbptr(ahd, tid_cur);
+		ahd_outw(ahd, SCB_NEXT2, tid_next);
+
+		if (SCBID_IS_NULL(tid_next))
+			ahd_outw(ahd, WAITING_TID_TAIL, tid_cur);
+	}
+}
+
+/*
+ * Manipulate the waiting for selection list and return the
+ * scb that follows the one that we remove.
+ */
+static u_int
+ahd_rem_wscb(struct ahd_softc *ahd, u_int scbid,
+	     u_int prev, u_int next, u_int tid)
+{
+	u_int tail_offset;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	if (!SCBID_IS_NULL(prev)) {
+		ahd_set_scbptr(ahd, prev);
+		ahd_outw(ahd, SCB_NEXT, next);
+	}
+
+	/*
+	 * SCBs that had MK_MESSAGE set in them will not
+	 * be queued to the per-target lists, so don't
+	 * blindly clear the tail pointer.
+	 */
+	tail_offset = WAITING_SCB_TAILS + (2 * tid);
+	if (SCBID_IS_NULL(next)
+	 && ahd_inw(ahd, tail_offset) == scbid)
+		ahd_outw(ahd, tail_offset, prev);
+	ahd_add_scb_to_free_list(ahd, scbid);
+	return (next);
+}
+
+/*
+ * Add the SCB as selected by SCBPTR onto the on chip list of
+ * free hardware SCBs.  This list is empty/unused if we are not
+ * performing SCB paging.
+ */
+static void
+ahd_add_scb_to_free_list(struct ahd_softc *ahd, u_int scbid)
+{
+/* XXX Need some other mechanism to designate "free". */
+	/*
+	 * Invalidate the tag so that our abort
+	 * routines don't think it's active.
+	ahd_outb(ahd, SCB_TAG, SCB_LIST_NULL);
+	 */
+}
+
+/******************************** Error Handling ******************************/
+/*
+ * Abort all SCBs that match the given description (target/channel/lun/tag),
+ * setting their status to the passed in status if the status has not already
+ * been modified from CAM_REQ_INPROG.  This routine assumes that the sequencer
+ * is paused before it is called.
+ */
+int
+ahd_abort_scbs(struct ahd_softc *ahd, int target, char channel,
+	       int lun, u_int tag, role_t role, uint32_t status)
+{
+	struct		scb *scbp;
+	struct		scb *scbp_next;
+	u_int		i, j;
+	u_int		maxtarget;
+	u_int		minlun;
+	u_int		maxlun;
+	int		found;
+	ahd_mode_state	saved_modes;
+
+	/* restore this when we're done */
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	found = ahd_search_qinfifo(ahd, target, channel, lun, SCB_LIST_NULL,
+				   role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	/*
+	 * Clean out the busy target table for any untagged commands.
+	 */
+	i = 0;
+	maxtarget = 16;
+	if (target != CAM_TARGET_WILDCARD) {
+		i = target;
+		if (channel == 'B')
+			i += 8;
+		maxtarget = i + 1;
+	}
+
+	if (lun == CAM_LUN_WILDCARD) {
+		minlun = 0;
+		maxlun = AHD_NUM_LUNS_NONPKT;
+	} else if (lun >= AHD_NUM_LUNS_NONPKT) {
+		minlun = maxlun = 0;
+	} else {
+		minlun = lun;
+		maxlun = lun + 1;
+	}
+
+	if (role != ROLE_TARGET) {
+		for (;i < maxtarget; i++) {
+			for (j = minlun;j < maxlun; j++) {
+				u_int scbid;
+				u_int tcl;
+
+				tcl = BUILD_TCL_RAW(i, 'A', j);
+				scbid = ahd_find_busy_tcl(ahd, tcl);
+				scbp = ahd_lookup_scb(ahd, scbid);
+				if (scbp == NULL
+				 || ahd_match_scb(ahd, scbp, target, channel,
+						  lun, tag, role) == 0)
+					continue;
+				ahd_unbusy_tcl(ahd, BUILD_TCL_RAW(i, 'A', j));
+			}
+		}
+	}
+
+	/*
+	 * Don't abort commands that have already completed,
+	 * but haven't quite made it up to the host yet.
+	 */
+	ahd_flush_qoutfifo(ahd);
+
+	/*
+	 * Go through the pending CCB list and look for
+	 * commands for this target that are still active.
+	 * These are other tagged commands that were
+	 * disconnected when the reset occurred.
+	 */
+	scbp_next = LIST_FIRST(&ahd->pending_scbs);
+	while (scbp_next != NULL) {
+		scbp = scbp_next;
+		scbp_next = LIST_NEXT(scbp, pending_links);
+		if (ahd_match_scb(ahd, scbp, target, channel, lun, tag, role)) {
+			cam_status ostat;
+
+			ostat = ahd_get_transaction_status(scbp);
+			if (ostat == CAM_REQ_INPROG)
+				ahd_set_transaction_status(scbp, status);
+			if (ahd_get_transaction_status(scbp) != CAM_REQ_CMP)
+				ahd_freeze_scb(scbp);
+			if ((scbp->flags & SCB_ACTIVE) == 0)
+				printf("Inactive SCB on pending list\n");
+			ahd_done(ahd, scbp);
+			found++;
+		}
+	}
+	ahd_restore_modes(ahd, saved_modes);
+	ahd_platform_abort_scbs(ahd, target, channel, lun, tag, role, status);
+	ahd->flags |= AHD_UPDATE_PEND_CMDS;
+	return found;
+}
+
+static void
+ahd_reset_current_bus(struct ahd_softc *ahd)
+{
+	uint8_t scsiseq;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) & ~ENSCSIRST);
+	scsiseq = ahd_inb(ahd, SCSISEQ0) & ~(ENSELO|ENARBO|SCSIRSTO);
+	ahd_outb(ahd, SCSISEQ0, scsiseq | SCSIRSTO);
+	ahd_flush_device_writes(ahd);
+	ahd_delay(AHD_BUSRESET_DELAY);
+	/* Turn off the bus reset */
+	ahd_outb(ahd, SCSISEQ0, scsiseq);
+	ahd_flush_device_writes(ahd);
+	ahd_delay(AHD_BUSRESET_DELAY);
+	if ((ahd->bugs & AHD_SCSIRST_BUG) != 0) {
+		/*
+		 * 2A Razor #474
+		 * Certain chip state is not cleared for
+		 * SCSI bus resets that we initiate, so
+		 * we must reset the chip.
+		 */
+		ahd_reset(ahd, /*reinit*/TRUE);
+		ahd_intr_enable(ahd, /*enable*/TRUE);
+		AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	}
+
+	ahd_clear_intstat(ahd);
+}
+
+int
+ahd_reset_channel(struct ahd_softc *ahd, char channel, int initiate_reset)
+{
+	struct	ahd_devinfo devinfo;
+	u_int	initiator;
+	u_int	target;
+	u_int	max_scsiid;
+	int	found;
+	u_int	fifo;
+	u_int	next_fifo;
+
+	ahd->pending_device = NULL;
+
+	ahd_compile_devinfo(&devinfo,
+			    CAM_TARGET_WILDCARD,
+			    CAM_TARGET_WILDCARD,
+			    CAM_LUN_WILDCARD,
+			    channel, ROLE_UNKNOWN);
+	ahd_pause(ahd);
+
+	/* Make sure the sequencer is in a safe location. */
+	ahd_clear_critical_section(ahd);
+
+#ifdef AHD_TARGET_MODE
+	if ((ahd->flags & AHD_TARGETROLE) != 0) {
+		ahd_run_tqinfifo(ahd, /*paused*/TRUE);
+	}
+#endif
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+
+	/*
+	 * Disable selections so no automatic hardware
+	 * functions will modify chip state.
+	 */
+	ahd_outb(ahd, SCSISEQ0, 0);
+	ahd_outb(ahd, SCSISEQ1, 0);
+
+	/*
+	 * Safely shut down our DMA engines.  Always start with
+	 * the FIFO that is not currently active (if any are
+	 * actively connected).
+	 */
+	next_fifo = fifo = ahd_inb(ahd, DFFSTAT) & CURRFIFO;
+	if (next_fifo > CURRFIFO_1)
+		/* If disconneced, arbitrarily start with FIFO1. */
+		next_fifo = fifo = 0;
+	do {
+		next_fifo ^= CURRFIFO_1;
+		ahd_set_modes(ahd, next_fifo, next_fifo);
+		ahd_outb(ahd, DFCNTRL,
+			 ahd_inb(ahd, DFCNTRL) & ~(SCSIEN|HDMAEN));
+		while ((ahd_inb(ahd, DFCNTRL) & HDMAENACK) != 0)
+			ahd_delay(10);
+		/*
+		 * Set CURRFIFO to the now inactive channel.
+		 */
+		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+		ahd_outb(ahd, DFFSTAT, next_fifo);
+	} while (next_fifo != fifo);
+
+	/*
+	 * Reset the bus if we are initiating this reset
+	 */
+	ahd_clear_msg_state(ahd);
+	ahd_outb(ahd, SIMODE1,
+		 ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
+
+	if (initiate_reset)
+		ahd_reset_current_bus(ahd);
+
+	ahd_clear_intstat(ahd);
+
+	/*
+	 * Clean up all the state information for the
+	 * pending transactions on this bus.
+	 */
+	found = ahd_abort_scbs(ahd, CAM_TARGET_WILDCARD, channel,
+			       CAM_LUN_WILDCARD, SCB_LIST_NULL,
+			       ROLE_UNKNOWN, CAM_SCSI_BUS_RESET);
+
+	/*
+	 * Cleanup anything left in the FIFOs.
+	 */
+	ahd_clear_fifo(ahd, 0);
+	ahd_clear_fifo(ahd, 1);
+
+	/*
+	 * Revert to async/narrow transfers until we renegotiate.
+	 */
+	max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
+	for (target = 0; target <= max_scsiid; target++) {
+
+		if (ahd->enabled_targets[target] == NULL)
+			continue;
+		for (initiator = 0; initiator <= max_scsiid; initiator++) {
+			struct ahd_devinfo devinfo;
+
+			ahd_compile_devinfo(&devinfo, target, initiator,
+					    CAM_LUN_WILDCARD,
+					    'A', ROLE_UNKNOWN);
+			ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHD_TRANS_CUR, /*paused*/TRUE);
+			ahd_set_syncrate(ahd, &devinfo, /*period*/0,
+					 /*offset*/0, /*ppr_options*/0,
+					 AHD_TRANS_CUR, /*paused*/TRUE);
+		}
+	}
+
+#ifdef AHD_TARGET_MODE
+	max_scsiid = (ahd->features & AHD_WIDE) ? 15 : 7;
+
+	/*
+	 * Send an immediate notify ccb to all target more peripheral
+	 * drivers affected by this action.
+	 */
+	for (target = 0; target <= max_scsiid; target++) {
+		struct ahd_tmode_tstate* tstate;
+		u_int lun;
+
+		tstate = ahd->enabled_targets[target];
+		if (tstate == NULL)
+			continue;
+		for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
+			struct ahd_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[lun];
+			if (lstate == NULL)
+				continue;
+
+			ahd_queue_lstate_event(ahd, lstate, CAM_TARGET_WILDCARD,
+					       EVENT_TYPE_BUS_RESET, /*arg*/0);
+			ahd_send_lstate_events(ahd, lstate);
+		}
+	}
+#endif
+	/* Notify the XPT that a bus reset occurred */
+	ahd_send_async(ahd, devinfo.channel, CAM_TARGET_WILDCARD,
+		       CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
+	ahd_restart(ahd);
+	/*
+	 * Freeze the SIMQ until our poller can determine that
+	 * the bus reset has really gone away.  We set the initial
+	 * timer to 0 to have the check performed as soon as possible
+	 * from the timer context.
+	 */
+	if ((ahd->flags & AHD_RESET_POLL_ACTIVE) == 0) {
+		ahd->flags |= AHD_RESET_POLL_ACTIVE;
+		ahd_freeze_simq(ahd);
+		ahd_timer_reset(&ahd->reset_timer, 0, ahd_reset_poll, ahd);
+	}
+	return (found);
+}
+
+
+#define AHD_RESET_POLL_US 1000
+static void
+ahd_reset_poll(void *arg)
+{
+	struct	ahd_softc *ahd;
+	u_int	scsiseq1;
+	u_long	l;
+	u_long	s;
+	
+	ahd_list_lock(&l);
+	ahd = ahd_find_softc((struct ahd_softc *)arg);
+	if (ahd == NULL) {
+		printf("ahd_reset_poll: Instance %p no longer exists\n", arg);
+		ahd_list_unlock(&l);
+		return;
+	}
+	ahd_lock(ahd, &s);
+	ahd_pause(ahd);
+	ahd_update_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, CLRSINT1, CLRSCSIRSTI);
+	if ((ahd_inb(ahd, SSTAT1) & SCSIRSTI) != 0) {
+		ahd_timer_reset(&ahd->reset_timer, AHD_RESET_POLL_US,
+				ahd_reset_poll, ahd);
+		ahd_unpause(ahd);
+		ahd_unlock(ahd, &s);
+		ahd_list_unlock(&l);
+		return;
+	}
+
+	/* Reset is now low.  Complete chip reinitialization. */
+	ahd_outb(ahd, SIMODE1, ahd_inb(ahd, SIMODE1) | ENSCSIRST);
+	scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
+	ahd_outb(ahd, SCSISEQ1, scsiseq1 & (ENSELI|ENRSELI|ENAUTOATNP));
+	ahd_unpause(ahd);
+	ahd->flags &= ~AHD_RESET_POLL_ACTIVE;
+	ahd_unlock(ahd, &s);
+	ahd_release_simq(ahd);
+	ahd_list_unlock(&l);
+}
+
+/**************************** Statistics Processing ***************************/
+static void
+ahd_stat_timer(void *arg)
+{
+	struct	ahd_softc *ahd;
+	u_long	l;
+	u_long	s;
+	int	enint_coal;
+	
+	ahd_list_lock(&l);
+	ahd = ahd_find_softc((struct ahd_softc *)arg);
+	if (ahd == NULL) {
+		printf("ahd_stat_timer: Instance %p no longer exists\n", arg);
+		ahd_list_unlock(&l);
+		return;
+	}
+	ahd_lock(ahd, &s);
+
+	enint_coal = ahd->hs_mailbox & ENINT_COALESCE;
+	if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold)
+		enint_coal |= ENINT_COALESCE;
+	else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold)
+		enint_coal &= ~ENINT_COALESCE;
+
+	if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) {
+		ahd_enable_coalescing(ahd, enint_coal);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0)
+			printf("%s: Interrupt coalescing "
+			       "now %sabled. Cmds %d\n",
+			       ahd_name(ahd),
+			       (enint_coal & ENINT_COALESCE) ? "en" : "dis",
+			       ahd->cmdcmplt_total);
+#endif
+	}
+
+	ahd->cmdcmplt_bucket = (ahd->cmdcmplt_bucket+1) & (AHD_STAT_BUCKETS-1);
+	ahd->cmdcmplt_total -= ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket];
+	ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket] = 0;
+	ahd_timer_reset(&ahd->stat_timer, AHD_STAT_UPDATE_US,
+			ahd_stat_timer, ahd);
+	ahd_unlock(ahd, &s);
+	ahd_list_unlock(&l);
+}
+
+/****************************** Status Processing *****************************/
+void
+ahd_handle_scb_status(struct ahd_softc *ahd, struct scb *scb)
+{
+	if (scb->hscb->shared_data.istatus.scsi_status != 0) {
+		ahd_handle_scsi_status(ahd, scb);
+	} else {
+		ahd_calc_residual(ahd, scb);
+		ahd_done(ahd, scb);
+	}
+}
+
+void
+ahd_handle_scsi_status(struct ahd_softc *ahd, struct scb *scb)
+{
+	struct hardware_scb *hscb;
+	u_int  qfreeze_cnt;
+
+	/*
+	 * The sequencer freezes its select-out queue
+	 * anytime a SCSI status error occurs.  We must
+	 * handle the error and decrement the QFREEZE count
+	 * to allow the sequencer to continue.
+	 */
+	hscb = scb->hscb; 
+
+	/* Freeze the queue until the client sees the error. */
+	ahd_freeze_devq(ahd, scb);
+	ahd_freeze_scb(scb);
+	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
+	if (qfreeze_cnt == 0) {
+		printf("%s: Bad status with 0 qfreeze count!\n", ahd_name(ahd));
+	} else {
+		qfreeze_cnt--;
+		ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
+	}
+	if (qfreeze_cnt == 0)
+		ahd_outb(ahd, SEQ_FLAGS2,
+			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
+
+	/* Don't want to clobber the original sense code */
+	if ((scb->flags & SCB_SENSE) != 0) {
+		/*
+		 * Clear the SCB_SENSE Flag and perform
+		 * a normal command completion.
+		 */
+		scb->flags &= ~SCB_SENSE;
+		ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+		ahd_done(ahd, scb);
+		return;
+	}
+	ahd_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR);
+	ahd_set_scsi_status(scb, hscb->shared_data.istatus.scsi_status);
+	switch (hscb->shared_data.istatus.scsi_status) {
+	case STATUS_PKT_SENSE:
+	{
+		struct scsi_status_iu_header *siu;
+
+		ahd_sync_sense(ahd, scb, BUS_DMASYNC_POSTREAD);
+		siu = (struct scsi_status_iu_header *)scb->sense_data;
+		ahd_set_scsi_status(scb, siu->status);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_SENSE) != 0) {
+			ahd_print_path(ahd, scb);
+			printf("SCB 0x%x Received PKT Status of 0x%x\n",
+			       SCB_GET_TAG(scb), siu->status);
+			printf("\tflags = 0x%x, sense len = 0x%x, "
+			       "pktfail = 0x%x\n",
+			       siu->flags, scsi_4btoul(siu->sense_length),
+			       scsi_4btoul(siu->pkt_failures_length));
+		}
+#endif
+		if ((siu->flags & SIU_RSPVALID) != 0) {
+			ahd_print_path(ahd, scb);
+			if (scsi_4btoul(siu->pkt_failures_length) < 4) {
+				printf("Unable to parse pkt_failures\n");
+			} else {
+
+				switch (SIU_PKTFAIL_CODE(siu)) {
+				case SIU_PFC_NONE:
+					printf("No packet failure found\n");
+					break;
+				case SIU_PFC_CIU_FIELDS_INVALID:
+					printf("Invalid Command IU Field\n");
+					break;
+				case SIU_PFC_TMF_NOT_SUPPORTED:
+					printf("TMF not supportd\n");
+					break;
+				case SIU_PFC_TMF_FAILED:
+					printf("TMF failed\n");
+					break;
+				case SIU_PFC_INVALID_TYPE_CODE:
+					printf("Invalid L_Q Type code\n");
+					break;
+				case SIU_PFC_ILLEGAL_REQUEST:
+					printf("Illegal request\n");
+				default:
+					break;
+				}
+			}
+			if (siu->status == SCSI_STATUS_OK)
+				ahd_set_transaction_status(scb,
+							   CAM_REQ_CMP_ERR);
+		}
+		if ((siu->flags & SIU_SNSVALID) != 0) {
+			scb->flags |= SCB_PKT_SENSE;
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_SENSE) != 0)
+				printf("Sense data available\n");
+#endif
+		}
+		ahd_done(ahd, scb);
+		break;
+	}
+	case SCSI_STATUS_CMD_TERMINATED:
+	case SCSI_STATUS_CHECK_COND:
+	{
+		struct ahd_devinfo devinfo;
+		struct ahd_dma_seg *sg;
+		struct scsi_sense *sc;
+		struct ahd_initiator_tinfo *targ_info;
+		struct ahd_tmode_tstate *tstate;
+		struct ahd_transinfo *tinfo;
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_SENSE) {
+			ahd_print_path(ahd, scb);
+			printf("SCB %d: requests Check Status\n",
+			       SCB_GET_TAG(scb));
+		}
+#endif
+
+		if (ahd_perform_autosense(scb) == 0)
+			break;
+
+		ahd_compile_devinfo(&devinfo, SCB_GET_OUR_ID(scb),
+				    SCB_GET_TARGET(ahd, scb),
+				    SCB_GET_LUN(scb),
+				    SCB_GET_CHANNEL(ahd, scb),
+				    ROLE_INITIATOR);
+		targ_info = ahd_fetch_transinfo(ahd,
+						devinfo.channel,
+						devinfo.our_scsiid,
+						devinfo.target,
+						&tstate);
+		tinfo = &targ_info->curr;
+		sg = scb->sg_list;
+		sc = (struct scsi_sense *)hscb->shared_data.idata.cdb;
+		/*
+		 * Save off the residual if there is one.
+		 */
+		ahd_update_residual(ahd, scb);
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_SENSE) {
+			ahd_print_path(ahd, scb);
+			printf("Sending Sense\n");
+		}
+#endif
+		scb->sg_count = 0;
+		sg = ahd_sg_setup(ahd, scb, sg, ahd_get_sense_bufaddr(ahd, scb),
+				  ahd_get_sense_bufsize(ahd, scb),
+				  /*last*/TRUE);
+		sc->opcode = REQUEST_SENSE;
+		sc->byte2 = 0;
+		if (tinfo->protocol_version <= SCSI_REV_2
+		 && SCB_GET_LUN(scb) < 8)
+			sc->byte2 = SCB_GET_LUN(scb) << 5;
+		sc->unused[0] = 0;
+		sc->unused[1] = 0;
+		sc->length = ahd_get_sense_bufsize(ahd, scb);
+		sc->control = 0;
+
+		/*
+		 * We can't allow the target to disconnect.
+		 * This will be an untagged transaction and
+		 * having the target disconnect will make this
+		 * transaction indestinguishable from outstanding
+		 * tagged transactions.
+		 */
+		hscb->control = 0;
+
+		/*
+		 * This request sense could be because the
+		 * the device lost power or in some other
+		 * way has lost our transfer negotiations.
+		 * Renegotiate if appropriate.  Unit attention
+		 * errors will be reported before any data
+		 * phases occur.
+		 */
+		if (ahd_get_residual(scb) == ahd_get_transfer_length(scb)) {
+			ahd_update_neg_request(ahd, &devinfo,
+					       tstate, targ_info,
+					       AHD_NEG_IF_NON_ASYNC);
+		}
+		if (tstate->auto_negotiate & devinfo.target_mask) {
+			hscb->control |= MK_MESSAGE;
+			scb->flags &=
+			    ~(SCB_NEGOTIATE|SCB_ABORT|SCB_DEVICE_RESET);
+			scb->flags |= SCB_AUTO_NEGOTIATE;
+		}
+		hscb->cdb_len = sizeof(*sc);
+		ahd_setup_data_scb(ahd, scb);
+		scb->flags |= SCB_SENSE;
+		ahd_queue_scb(ahd, scb);
+		/*
+		 * Ensure we have enough time to actually
+		 * retrieve the sense.
+		 */
+		ahd_scb_timer_reset(scb, 5 * 1000000);
+		break;
+	}
+	case SCSI_STATUS_OK:
+		printf("%s: Interrupted for staus of 0???\n",
+		       ahd_name(ahd));
+		/* FALLTHROUGH */
+	default:
+		ahd_done(ahd, scb);
+		break;
+	}
+}
+
+/*
+ * Calculate the residual for a just completed SCB.
+ */
+void
+ahd_calc_residual(struct ahd_softc *ahd, struct scb *scb)
+{
+	struct hardware_scb *hscb;
+	struct initiator_status *spkt;
+	uint32_t sgptr;
+	uint32_t resid_sgptr;
+	uint32_t resid;
+
+	/*
+	 * 5 cases.
+	 * 1) No residual.
+	 *    SG_STATUS_VALID clear in sgptr.
+	 * 2) Transferless command
+	 * 3) Never performed any transfers.
+	 *    sgptr has SG_FULL_RESID set.
+	 * 4) No residual but target did not
+	 *    save data pointers after the
+	 *    last transfer, so sgptr was
+	 *    never updated.
+	 * 5) We have a partial residual.
+	 *    Use residual_sgptr to determine
+	 *    where we are.
+	 */
+
+	hscb = scb->hscb;
+	sgptr = ahd_le32toh(hscb->sgptr);
+	if ((sgptr & SG_STATUS_VALID) == 0)
+		/* Case 1 */
+		return;
+	sgptr &= ~SG_STATUS_VALID;
+
+	if ((sgptr & SG_LIST_NULL) != 0)
+		/* Case 2 */
+		return;
+
+	/*
+	 * Residual fields are the same in both
+	 * target and initiator status packets,
+	 * so we can always use the initiator fields
+	 * regardless of the role for this SCB.
+	 */
+	spkt = &hscb->shared_data.istatus;
+	resid_sgptr = ahd_le32toh(spkt->residual_sgptr);
+	if ((sgptr & SG_FULL_RESID) != 0) {
+		/* Case 3 */
+		resid = ahd_get_transfer_length(scb);
+	} else if ((resid_sgptr & SG_LIST_NULL) != 0) {
+		/* Case 4 */
+		return;
+	} else if ((resid_sgptr & SG_OVERRUN_RESID) != 0) {
+		ahd_print_path(ahd, scb);
+		printf("data overrun detected Tag == 0x%x.\n",
+		       SCB_GET_TAG(scb));
+		ahd_freeze_devq(ahd, scb);
+		ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		ahd_freeze_scb(scb);
+		return;
+	} else if ((resid_sgptr & ~SG_PTR_MASK) != 0) {
+		panic("Bogus resid sgptr value 0x%x\n", resid_sgptr);
+		/* NOTREACHED */
+	} else {
+		struct ahd_dma_seg *sg;
+
+		/*
+		 * Remainder of the SG where the transfer
+		 * stopped.  
+		 */
+		resid = ahd_le32toh(spkt->residual_datacnt) & AHD_SG_LEN_MASK;
+		sg = ahd_sg_bus_to_virt(ahd, scb, resid_sgptr & SG_PTR_MASK);
+
+		/* The residual sg_ptr always points to the next sg */
+		sg--;
+
+		/*
+		 * Add up the contents of all residual
+		 * SG segments that are after the SG where
+		 * the transfer stopped.
+		 */
+		while ((ahd_le32toh(sg->len) & AHD_DMA_LAST_SEG) == 0) {
+			sg++;
+			resid += ahd_le32toh(sg->len) & AHD_SG_LEN_MASK;
+		}
+	}
+	if ((scb->flags & SCB_SENSE) == 0)
+		ahd_set_residual(scb, resid);
+	else
+		ahd_set_sense_residual(scb, resid);
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MISC) != 0) {
+		ahd_print_path(ahd, scb);
+		printf("Handled %sResidual of %d bytes\n",
+		       (scb->flags & SCB_SENSE) ? "Sense " : "", resid);
+	}
+#endif
+}
+
+/******************************* Target Mode **********************************/
+#ifdef AHD_TARGET_MODE
+/*
+ * Add a target mode event to this lun's queue
+ */
+static void
+ahd_queue_lstate_event(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate,
+		       u_int initiator_id, u_int event_type, u_int event_arg)
+{
+	struct ahd_tmode_event *event;
+	int pending;
+
+	xpt_freeze_devq(lstate->path, /*count*/1);
+	if (lstate->event_w_idx >= lstate->event_r_idx)
+		pending = lstate->event_w_idx - lstate->event_r_idx;
+	else
+		pending = AHD_TMODE_EVENT_BUFFER_SIZE + 1
+			- (lstate->event_r_idx - lstate->event_w_idx);
+
+	if (event_type == EVENT_TYPE_BUS_RESET
+	 || event_type == MSG_BUS_DEV_RESET) {
+		/*
+		 * Any earlier events are irrelevant, so reset our buffer.
+		 * This has the effect of allowing us to deal with reset
+		 * floods (an external device holding down the reset line)
+		 * without losing the event that is really interesting.
+		 */
+		lstate->event_r_idx = 0;
+		lstate->event_w_idx = 0;
+		xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE);
+	}
+
+	if (pending == AHD_TMODE_EVENT_BUFFER_SIZE) {
+		xpt_print_path(lstate->path);
+		printf("immediate event %x:%x lost\n",
+		       lstate->event_buffer[lstate->event_r_idx].event_type,
+		       lstate->event_buffer[lstate->event_r_idx].event_arg);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+		xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE);
+	}
+
+	event = &lstate->event_buffer[lstate->event_w_idx];
+	event->initiator_id = initiator_id;
+	event->event_type = event_type;
+	event->event_arg = event_arg;
+	lstate->event_w_idx++;
+	if (lstate->event_w_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
+		lstate->event_w_idx = 0;
+}
+
+/*
+ * Send any target mode events queued up waiting
+ * for immediate notify resources.
+ */
+void
+ahd_send_lstate_events(struct ahd_softc *ahd, struct ahd_tmode_lstate *lstate)
+{
+	struct ccb_hdr *ccbh;
+	struct ccb_immed_notify *inot;
+
+	while (lstate->event_r_idx != lstate->event_w_idx
+	    && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) {
+		struct ahd_tmode_event *event;
+
+		event = &lstate->event_buffer[lstate->event_r_idx];
+		SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle);
+		inot = (struct ccb_immed_notify *)ccbh;
+		switch (event->event_type) {
+		case EVENT_TYPE_BUS_RESET:
+			ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN;
+			break;
+		default:
+			ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
+			inot->message_args[0] = event->event_type;
+			inot->message_args[1] = event->event_arg;
+			break;
+		}
+		inot->initiator_id = event->initiator_id;
+		inot->sense_len = 0;
+		xpt_done((union ccb *)inot);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHD_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+	}
+}
+#endif
+
+/******************** Sequencer Program Patching/Download *********************/
+
+#ifdef AHD_DUMP_SEQ
+void
+ahd_dumpseq(struct ahd_softc* ahd)
+{
+	int i;
+	int max_prog;
+
+	max_prog = 2048;
+
+	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahd_outb(ahd, PRGMCNT, 0);
+	ahd_outb(ahd, PRGMCNT+1, 0);
+	for (i = 0; i < max_prog; i++) {
+		uint8_t ins_bytes[4];
+
+		ahd_insb(ahd, SEQRAM, ins_bytes, 4);
+		printf("0x%08x\n", ins_bytes[0] << 24
+				 | ins_bytes[1] << 16
+				 | ins_bytes[2] << 8
+				 | ins_bytes[3]);
+	}
+}
+#endif
+
+static void
+ahd_loadseq(struct ahd_softc *ahd)
+{
+	struct	cs cs_table[num_critical_sections];
+	u_int	begin_set[num_critical_sections];
+	u_int	end_set[num_critical_sections];
+	struct	patch *cur_patch;
+	u_int	cs_count;
+	u_int	cur_cs;
+	u_int	i;
+	int	downloaded;
+	u_int	skip_addr;
+	u_int	sg_prefetch_cnt;
+	u_int	sg_prefetch_cnt_limit;
+	u_int	sg_prefetch_align;
+	u_int	sg_size;
+	uint8_t	download_consts[DOWNLOAD_CONST_COUNT];
+
+	if (bootverbose)
+		printf("%s: Downloading Sequencer Program...",
+		       ahd_name(ahd));
+
+#if DOWNLOAD_CONST_COUNT != 7
+#error "Download Const Mismatch"
+#endif
+	/*
+	 * Start out with 0 critical sections
+	 * that apply to this firmware load.
+	 */
+	cs_count = 0;
+	cur_cs = 0;
+	memset(begin_set, 0, sizeof(begin_set));
+	memset(end_set, 0, sizeof(end_set));
+
+	/*
+	 * Setup downloadable constant table.
+	 * 
+	 * The computation for the S/G prefetch variables is
+	 * a bit complicated.  We would like to always fetch
+	 * in terms of cachelined sized increments.  However,
+	 * if the cacheline is not an even multiple of the
+	 * SG element size or is larger than our SG RAM, using
+	 * just the cache size might leave us with only a portion
+	 * of an SG element at the tail of a prefetch.  If the
+	 * cacheline is larger than our S/G prefetch buffer less
+	 * the size of an SG element, we may round down to a cacheline
+	 * that doesn't contain any or all of the S/G of interest
+	 * within the bounds of our S/G ram.  Provide variables to
+	 * the sequencer that will allow it to handle these edge
+	 * cases.
+	 */
+	/* Start by aligning to the nearest cacheline. */
+	sg_prefetch_align = ahd->pci_cachesize;
+	if (sg_prefetch_align == 0)
+		sg_prefetch_align = 8;
+	/* Round down to the nearest power of 2. */
+	while (powerof2(sg_prefetch_align) == 0)
+		sg_prefetch_align--;
+	/*
+	 * If the cacheline boundary is greater than half our prefetch RAM
+	 * we risk not being able to fetch even a single complete S/G
+	 * segment if we align to that boundary.
+	 */
+	if (sg_prefetch_align > CCSGADDR_MAX/2)
+		sg_prefetch_align = CCSGADDR_MAX/2;
+	/* Start by fetching a single cacheline. */
+	sg_prefetch_cnt = sg_prefetch_align;
+	/*
+	 * Increment the prefetch count by cachelines until
+	 * at least one S/G element will fit.
+	 */
+	sg_size = sizeof(struct ahd_dma_seg);
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
+		sg_size = sizeof(struct ahd_dma64_seg);
+	while (sg_prefetch_cnt < sg_size)
+		sg_prefetch_cnt += sg_prefetch_align;
+	/*
+	 * If the cacheline is not an even multiple of
+	 * the S/G size, we may only get a partial S/G when
+	 * we align. Add a cacheline if this is the case.
+	 */
+	if ((sg_prefetch_align % sg_size) != 0
+	 && (sg_prefetch_cnt < CCSGADDR_MAX))
+		sg_prefetch_cnt += sg_prefetch_align;
+	/*
+	 * Lastly, compute a value that the sequencer can use
+	 * to determine if the remainder of the CCSGRAM buffer
+	 * has a full S/G element in it.
+	 */
+	sg_prefetch_cnt_limit = -(sg_prefetch_cnt - sg_size + 1);
+	download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt;
+	download_consts[SG_PREFETCH_CNT_LIMIT] = sg_prefetch_cnt_limit;
+	download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_align - 1);
+	download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_align - 1);
+	download_consts[SG_SIZEOF] = sg_size;
+	download_consts[PKT_OVERRUN_BUFOFFSET] =
+		(ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256;
+	download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN;
+	cur_patch = patches;
+	downloaded = 0;
+	skip_addr = 0;
+	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahd_outb(ahd, PRGMCNT, 0);
+	ahd_outb(ahd, PRGMCNT+1, 0);
+
+	for (i = 0; i < sizeof(seqprog)/4; i++) {
+		if (ahd_check_patch(ahd, &cur_patch, i, &skip_addr) == 0) {
+			/*
+			 * Don't download this instruction as it
+			 * is in a patch that was removed.
+			 */
+			continue;
+		}
+		/*
+		 * Move through the CS table until we find a CS
+		 * that might apply to this instruction.
+		 */
+		for (; cur_cs < num_critical_sections; cur_cs++) {
+			if (critical_sections[cur_cs].end <= i) {
+				if (begin_set[cs_count] == TRUE
+				 && end_set[cs_count] == FALSE) {
+					cs_table[cs_count].end = downloaded;
+				 	end_set[cs_count] = TRUE;
+					cs_count++;
+				}
+				continue;
+			}
+			if (critical_sections[cur_cs].begin <= i
+			 && begin_set[cs_count] == FALSE) {
+				cs_table[cs_count].begin = downloaded;
+				begin_set[cs_count] = TRUE;
+			}
+			break;
+		}
+		ahd_download_instr(ahd, i, download_consts);
+		downloaded++;
+	}
+
+	ahd->num_critical_sections = cs_count;
+	if (cs_count != 0) {
+
+		cs_count *= sizeof(struct cs);
+		ahd->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+		if (ahd->critical_sections == NULL)
+			panic("ahd_loadseq: Could not malloc");
+		memcpy(ahd->critical_sections, cs_table, cs_count);
+	}
+	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS|FASTMODE);
+
+	if (bootverbose) {
+		printf(" %d instructions downloaded\n", downloaded);
+		printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+		       ahd_name(ahd), ahd->features, ahd->bugs, ahd->flags);
+	}
+}
+
+static int
+ahd_check_patch(struct ahd_softc *ahd, struct patch **start_patch,
+		u_int start_instr, u_int *skip_addr)
+{
+	struct	patch *cur_patch;
+	struct	patch *last_patch;
+	u_int	num_patches;
+
+	num_patches = sizeof(patches)/sizeof(struct patch);
+	last_patch = &patches[num_patches];
+	cur_patch = *start_patch;
+
+	while (cur_patch < last_patch && start_instr == cur_patch->begin) {
+
+		if (cur_patch->patch_func(ahd) == 0) {
+
+			/* Start rejecting code */
+			*skip_addr = start_instr + cur_patch->skip_instr;
+			cur_patch += cur_patch->skip_patch;
+		} else {
+			/* Accepted this patch.  Advance to the next
+			 * one and wait for our intruction pointer to
+			 * hit this point.
+			 */
+			cur_patch++;
+		}
+	}
+
+	*start_patch = cur_patch;
+	if (start_instr < *skip_addr)
+		/* Still skipping */
+		return (0);
+
+	return (1);
+}
+
+static u_int
+ahd_resolve_seqaddr(struct ahd_softc *ahd, u_int address)
+{
+	struct patch *cur_patch;
+	int address_offset;
+	u_int skip_addr;
+	u_int i;
+
+	address_offset = 0;
+	cur_patch = patches;
+	skip_addr = 0;
+
+	for (i = 0; i < address;) {
+
+		ahd_check_patch(ahd, &cur_patch, i, &skip_addr);
+
+		if (skip_addr > i) {
+			int end_addr;
+
+			end_addr = MIN(address, skip_addr);
+			address_offset += end_addr - i;
+			i = skip_addr;
+		} else {
+			i++;
+		}
+	}
+	return (address - address_offset);
+}
+
+static void
+ahd_download_instr(struct ahd_softc *ahd, u_int instrptr, uint8_t *dconsts)
+{
+	union	ins_formats instr;
+	struct	ins_format1 *fmt1_ins;
+	struct	ins_format3 *fmt3_ins;
+	u_int	opcode;
+
+	/*
+	 * The firmware is always compiled into a little endian format.
+	 */
+	instr.integer = ahd_le32toh(*(uint32_t*)&seqprog[instrptr * 4]);
+
+	fmt1_ins = &instr.format1;
+	fmt3_ins = NULL;
+
+	/* Pull the opcode */
+	opcode = instr.format1.opcode;
+	switch (opcode) {
+	case AIC_OP_JMP:
+	case AIC_OP_JC:
+	case AIC_OP_JNC:
+	case AIC_OP_CALL:
+	case AIC_OP_JNE:
+	case AIC_OP_JNZ:
+	case AIC_OP_JE:
+	case AIC_OP_JZ:
+	{
+		fmt3_ins = &instr.format3;
+		fmt3_ins->address = ahd_resolve_seqaddr(ahd, fmt3_ins->address);
+		/* FALLTHROUGH */
+	}
+	case AIC_OP_OR:
+	case AIC_OP_AND:
+	case AIC_OP_XOR:
+	case AIC_OP_ADD:
+	case AIC_OP_ADC:
+	case AIC_OP_BMOV:
+		if (fmt1_ins->parity != 0) {
+			fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+		}
+		fmt1_ins->parity = 0;
+		/* FALLTHROUGH */
+	case AIC_OP_ROL:
+	{
+		int i, count;
+
+		/* Calculate odd parity for the instruction */
+		for (i = 0, count = 0; i < 31; i++) {
+			uint32_t mask;
+
+			mask = 0x01 << i;
+			if ((instr.integer & mask) != 0)
+				count++;
+		}
+		if ((count & 0x01) == 0)
+			instr.format1.parity = 1;
+
+		/* The sequencer is a little endian cpu */
+		instr.integer = ahd_htole32(instr.integer);
+		ahd_outsb(ahd, SEQRAM, instr.bytes, 4);
+		break;
+	}
+	default:
+		panic("Unknown opcode encountered in seq program");
+		break;
+	}
+}
+
+static int
+ahd_probe_stack_size(struct ahd_softc *ahd)
+{
+	int last_probe;
+
+	last_probe = 0;
+	while (1) {
+		int i;
+
+		/*
+		 * We avoid using 0 as a pattern to avoid
+		 * confusion if the stack implementation
+		 * "back-fills" with zeros when "poping'
+		 * entries.
+		 */
+		for (i = 1; i <= last_probe+1; i++) {
+		       ahd_outb(ahd, STACK, i & 0xFF);
+		       ahd_outb(ahd, STACK, (i >> 8) & 0xFF);
+		}
+
+		/* Verify */
+		for (i = last_probe+1; i > 0; i--) {
+			u_int stack_entry;
+
+			stack_entry = ahd_inb(ahd, STACK)
+				    |(ahd_inb(ahd, STACK) << 8);
+			if (stack_entry != i)
+				goto sized;
+		}
+		last_probe++;
+	}
+sized:
+	return (last_probe);
+}
+
+void
+ahd_dump_all_cards_state(void)
+{
+	struct ahd_softc *list_ahd;
+
+	TAILQ_FOREACH(list_ahd, &ahd_tailq, links) {
+		ahd_dump_card_state(list_ahd);
+	}
+}
+
+int
+ahd_print_register(ahd_reg_parse_entry_t *table, u_int num_entries,
+		   const char *name, u_int address, u_int value,
+		   u_int *cur_column, u_int wrap_point)
+{
+	int	printed;
+	u_int	printed_mask;
+
+	if (cur_column != NULL && *cur_column >= wrap_point) {
+		printf("\n");
+		*cur_column = 0;
+	}
+	printed = printf("%s[0x%x]", name, value);
+	if (table == NULL) {
+		printed += printf(" ");
+		*cur_column += printed;
+		return (printed);
+	}
+	printed_mask = 0;
+	while (printed_mask != 0xFF) {
+		int entry;
+
+		for (entry = 0; entry < num_entries; entry++) {
+			if (((value & table[entry].mask)
+			  != table[entry].value)
+			 || ((printed_mask & table[entry].mask)
+			  == table[entry].mask))
+				continue;
+
+			printed += printf("%s%s",
+					  printed_mask == 0 ? ":(" : "|",
+					  table[entry].name);
+			printed_mask |= table[entry].mask;
+			
+			break;
+		}
+		if (entry >= num_entries)
+			break;
+	}
+	if (printed_mask != 0)
+		printed += printf(") ");
+	else
+		printed += printf(" ");
+	if (cur_column != NULL)
+		*cur_column += printed;
+	return (printed);
+}
+
+void
+ahd_dump_card_state(struct ahd_softc *ahd)
+{
+	struct scb	*scb;
+	ahd_mode_state	 saved_modes;
+	u_int		 dffstat;
+	int		 paused;
+	u_int		 scb_index;
+	u_int		 saved_scb_index;
+	u_int		 cur_col;
+	int		 i;
+
+	if (ahd_is_paused(ahd)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahd_pause(ahd);
+	}
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+	       "%s: Dumping Card State at program address 0x%x Mode 0x%x\n",
+	       ahd_name(ahd), 
+	       ahd_inb(ahd, CURADDR) | (ahd_inb(ahd, CURADDR+1) << 8),
+	       ahd_build_mode_state(ahd, ahd->saved_src_mode,
+				    ahd->saved_dst_mode));
+	if (paused)
+		printf("Card was paused\n");
+
+	if (ahd_check_cmdcmpltqueues(ahd))
+		printf("Completions are pending\n");
+
+	/*
+	 * Mode independent registers.
+	 */
+	cur_col = 0;
+	ahd_hs_mailbox_print(ahd_inb(ahd, LOCAL_HS_MAILBOX), &cur_col, 50);
+	ahd_intctl_print(ahd_inb(ahd, INTCTL), &cur_col, 50);
+	ahd_seqintstat_print(ahd_inb(ahd, SEQINTSTAT), &cur_col, 50);
+	ahd_saved_mode_print(ahd_inb(ahd, SAVED_MODE), &cur_col, 50);
+	ahd_dffstat_print(ahd_inb(ahd, DFFSTAT), &cur_col, 50);
+	ahd_scsisigi_print(ahd_inb(ahd, SCSISIGI), &cur_col, 50);
+	ahd_scsiphase_print(ahd_inb(ahd, SCSIPHASE), &cur_col, 50);
+	ahd_scsibus_print(ahd_inb(ahd, SCSIBUS), &cur_col, 50);
+	ahd_lastphase_print(ahd_inb(ahd, LASTPHASE), &cur_col, 50);
+	ahd_scsiseq0_print(ahd_inb(ahd, SCSISEQ0), &cur_col, 50);
+	ahd_scsiseq1_print(ahd_inb(ahd, SCSISEQ1), &cur_col, 50);
+	ahd_seqctl0_print(ahd_inb(ahd, SEQCTL0), &cur_col, 50);
+	ahd_seqintctl_print(ahd_inb(ahd, SEQINTCTL), &cur_col, 50);
+	ahd_seq_flags_print(ahd_inb(ahd, SEQ_FLAGS), &cur_col, 50);
+	ahd_seq_flags2_print(ahd_inb(ahd, SEQ_FLAGS2), &cur_col, 50);
+	ahd_sstat0_print(ahd_inb(ahd, SSTAT0), &cur_col, 50);
+	ahd_sstat1_print(ahd_inb(ahd, SSTAT1), &cur_col, 50);
+	ahd_sstat2_print(ahd_inb(ahd, SSTAT2), &cur_col, 50);
+	ahd_sstat3_print(ahd_inb(ahd, SSTAT3), &cur_col, 50);
+	ahd_perrdiag_print(ahd_inb(ahd, PERRDIAG), &cur_col, 50);
+	ahd_simode1_print(ahd_inb(ahd, SIMODE1), &cur_col, 50);
+	ahd_lqistat0_print(ahd_inb(ahd, LQISTAT0), &cur_col, 50);
+	ahd_lqistat1_print(ahd_inb(ahd, LQISTAT1), &cur_col, 50);
+	ahd_lqistat2_print(ahd_inb(ahd, LQISTAT2), &cur_col, 50);
+	ahd_lqostat0_print(ahd_inb(ahd, LQOSTAT0), &cur_col, 50);
+	ahd_lqostat1_print(ahd_inb(ahd, LQOSTAT1), &cur_col, 50);
+	ahd_lqostat2_print(ahd_inb(ahd, LQOSTAT2), &cur_col, 50);
+	printf("\n");
+	printf("\nSCB Count = %d CMDS_PENDING = %d LASTSCB 0x%x "
+	       "CURRSCB 0x%x NEXTSCB 0x%x\n",
+	       ahd->scb_data.numscbs, ahd_inw(ahd, CMDS_PENDING),
+	       ahd_inw(ahd, LASTSCB), ahd_inw(ahd, CURRSCB),
+	       ahd_inw(ahd, NEXTSCB));
+	cur_col = 0;
+	/* QINFIFO */
+	ahd_search_qinfifo(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+			   CAM_LUN_WILDCARD, SCB_LIST_NULL,
+			   ROLE_UNKNOWN, /*status*/0, SEARCH_PRINT);
+	saved_scb_index = ahd_get_scbptr(ahd);
+	printf("Pending list:");
+	i = 0;
+	LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+		if (i++ > AHD_SCB_MAX)
+			break;
+		cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
+				 ahd_inb_scbram(ahd, SCB_FIFO_USE_COUNT));
+		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
+		ahd_scb_control_print(ahd_inb_scbram(ahd, SCB_CONTROL),
+				      &cur_col, 60);
+		ahd_scb_scsiid_print(ahd_inb_scbram(ahd, SCB_SCSIID),
+				     &cur_col, 60);
+	}
+	printf("\nTotal %d\n", i);
+
+	printf("Kernel Free SCB list: ");
+	i = 0;
+	TAILQ_FOREACH(scb, &ahd->scb_data.free_scbs, links.tqe) {
+		struct scb *list_scb;
+
+		list_scb = scb;
+		do {
+			printf("%d ", SCB_GET_TAG(list_scb));
+			list_scb = LIST_NEXT(list_scb, collision_links);
+		} while (list_scb && i++ < AHD_SCB_MAX);
+	}
+
+	LIST_FOREACH(scb, &ahd->scb_data.any_dev_free_scb_list, links.le) {
+		if (i++ > AHD_SCB_MAX)
+			break;
+		printf("%d ", SCB_GET_TAG(scb));
+	}
+	printf("\n");
+
+	printf("Sequencer Complete DMA-inprog list: ");
+	scb_index = ahd_inw(ahd, COMPLETE_SCB_DMAINPROG_HEAD);
+	i = 0;
+	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
+		ahd_set_scbptr(ahd, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+	}
+	printf("\n");
+
+	printf("Sequencer Complete list: ");
+	scb_index = ahd_inw(ahd, COMPLETE_SCB_HEAD);
+	i = 0;
+	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
+		ahd_set_scbptr(ahd, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+	}
+	printf("\n");
+
+	
+	printf("Sequencer DMA-Up and Complete list: ");
+	scb_index = ahd_inw(ahd, COMPLETE_DMA_SCB_HEAD);
+	i = 0;
+	while (!SCBID_IS_NULL(scb_index) && i++ < AHD_SCB_MAX) {
+		ahd_set_scbptr(ahd, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahd_inw_scbram(ahd, SCB_NEXT_COMPLETE);
+	}
+	printf("\n");
+	ahd_set_scbptr(ahd, saved_scb_index);
+	dffstat = ahd_inb(ahd, DFFSTAT);
+	for (i = 0; i < 2; i++) {
+#ifdef AHD_DEBUG
+		struct scb *fifo_scb;
+#endif
+		u_int	    fifo_scbptr;
+
+		ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
+		fifo_scbptr = ahd_get_scbptr(ahd);
+		printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
+		       ahd_name(ahd), i,
+		       (dffstat & (FIFO0FREE << i)) ? "Free" : "Active",
+		       ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr);
+		cur_col = 0;
+		ahd_seqimode_print(ahd_inb(ahd, SEQIMODE), &cur_col, 50);
+		ahd_seqintsrc_print(ahd_inb(ahd, SEQINTSRC), &cur_col, 50);
+		ahd_dfcntrl_print(ahd_inb(ahd, DFCNTRL), &cur_col, 50);
+		ahd_dfstatus_print(ahd_inb(ahd, DFSTATUS), &cur_col, 50);
+		ahd_sg_cache_shadow_print(ahd_inb(ahd, SG_CACHE_SHADOW),
+					  &cur_col, 50);
+		ahd_sg_state_print(ahd_inb(ahd, SG_STATE), &cur_col, 50);
+		ahd_dffsxfrctl_print(ahd_inb(ahd, DFFSXFRCTL), &cur_col, 50);
+		ahd_soffcnt_print(ahd_inb(ahd, SOFFCNT), &cur_col, 50);
+		ahd_mdffstat_print(ahd_inb(ahd, MDFFSTAT), &cur_col, 50);
+		if (cur_col > 50) {
+			printf("\n");
+			cur_col = 0;
+		}
+		cur_col += printf("SHADDR = 0x%x%x, SHCNT = 0x%x ",
+				  ahd_inl(ahd, SHADDR+4),
+				  ahd_inl(ahd, SHADDR),
+				  (ahd_inb(ahd, SHCNT)
+				| (ahd_inb(ahd, SHCNT + 1) << 8)
+				| (ahd_inb(ahd, SHCNT + 2) << 16)));
+		if (cur_col > 50) {
+			printf("\n");
+			cur_col = 0;
+		}
+		cur_col += printf("HADDR = 0x%x%x, HCNT = 0x%x ",
+				  ahd_inl(ahd, HADDR+4),
+				  ahd_inl(ahd, HADDR),
+				  (ahd_inb(ahd, HCNT)
+				| (ahd_inb(ahd, HCNT + 1) << 8)
+				| (ahd_inb(ahd, HCNT + 2) << 16)));
+		ahd_ccsgctl_print(ahd_inb(ahd, CCSGCTL), &cur_col, 50);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_SG) != 0) {
+			fifo_scb = ahd_lookup_scb(ahd, fifo_scbptr);
+			if (fifo_scb != NULL)
+				ahd_dump_sglist(fifo_scb);
+		}
+#endif
+	}
+	printf("\nLQIN: ");
+	for (i = 0; i < 20; i++)
+		printf("0x%x ", ahd_inb(ahd, LQIN + i));
+	printf("\n");
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+	printf("%s: LQISTATE = 0x%x, LQOSTATE = 0x%x, OPTIONMODE = 0x%x\n",
+	       ahd_name(ahd), ahd_inb(ahd, LQISTATE), ahd_inb(ahd, LQOSTATE),
+	       ahd_inb(ahd, OPTIONMODE));
+	printf("%s: OS_SPACE_CNT = 0x%x MAXCMDCNT = 0x%x\n",
+	       ahd_name(ahd), ahd_inb(ahd, OS_SPACE_CNT),
+	       ahd_inb(ahd, MAXCMDCNT));
+	ahd_simode0_print(ahd_inb(ahd, SIMODE0), &cur_col, 50);
+	printf("\n");
+	ahd_set_modes(ahd, AHD_MODE_CCHAN, AHD_MODE_CCHAN);
+	cur_col = 0;
+	ahd_ccscbctl_print(ahd_inb(ahd, CCSCBCTL), &cur_col, 50);
+	printf("\n");
+	ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
+	printf("%s: REG0 == 0x%x, SINDEX = 0x%x, DINDEX = 0x%x\n",
+	       ahd_name(ahd), ahd_inw(ahd, REG0), ahd_inw(ahd, SINDEX),
+	       ahd_inw(ahd, DINDEX));
+	printf("%s: SCBPTR == 0x%x, SCB_NEXT == 0x%x, SCB_NEXT2 == 0x%x\n",
+	       ahd_name(ahd), ahd_get_scbptr(ahd),
+	       ahd_inw_scbram(ahd, SCB_NEXT),
+	       ahd_inw_scbram(ahd, SCB_NEXT2));
+	printf("CDB %x %x %x %x %x %x\n",
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE),
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE+1),
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE+2),
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE+3),
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE+4),
+	       ahd_inb_scbram(ahd, SCB_CDB_STORE+5));
+	printf("STACK:");
+	for (i = 0; i < ahd->stack_size; i++) {
+		ahd->saved_stack[i] =
+		    ahd_inb(ahd, STACK)|(ahd_inb(ahd, STACK) << 8);
+		printf(" 0x%x", ahd->saved_stack[i]);
+	}
+	for (i = ahd->stack_size-1; i >= 0; i--) {
+		ahd_outb(ahd, STACK, ahd->saved_stack[i] & 0xFF);
+		ahd_outb(ahd, STACK, (ahd->saved_stack[i] >> 8) & 0xFF);
+	}
+	printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+	ahd_platform_dump_card_state(ahd);
+	ahd_restore_modes(ahd, saved_modes);
+	if (paused == 0)
+		ahd_unpause(ahd);
+}
+
+void
+ahd_dump_scbs(struct ahd_softc *ahd)
+{
+	ahd_mode_state saved_modes;
+	u_int	       saved_scb_index;
+	int	       i;
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	saved_scb_index = ahd_get_scbptr(ahd);
+	for (i = 0; i < AHD_SCB_MAX; i++) {
+		ahd_set_scbptr(ahd, i);
+		printf("%3d", i);
+		printf("(CTRL 0x%x ID 0x%x N 0x%x N2 0x%x SG 0x%x, RSG 0x%x)\n",
+		       ahd_inb_scbram(ahd, SCB_CONTROL),
+		       ahd_inb_scbram(ahd, SCB_SCSIID),
+		       ahd_inw_scbram(ahd, SCB_NEXT),
+		       ahd_inw_scbram(ahd, SCB_NEXT2),
+		       ahd_inl_scbram(ahd, SCB_SGPTR),
+		       ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR));
+	}
+	printf("\n");
+	ahd_set_scbptr(ahd, saved_scb_index);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+/**************************** Flexport Logic **********************************/
+/*
+ * Read count 16bit words from 16bit word address start_addr from the
+ * SEEPROM attached to the controller, into buf, using the controller's
+ * SEEPROM reading state machine.  Optionally treat the data as a byte
+ * stream in terms of byte order.
+ */
+int
+ahd_read_seeprom(struct ahd_softc *ahd, uint16_t *buf,
+		 u_int start_addr, u_int count, int bytestream)
+{
+	u_int cur_addr;
+	u_int end_addr;
+	int   error;
+
+	/*
+	 * If we never make it through the loop even once,
+	 * we were passed invalid arguments.
+	 */
+	error = EINVAL;
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	end_addr = start_addr + count;
+	for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) {
+
+		ahd_outb(ahd, SEEADR, cur_addr);
+		ahd_outb(ahd, SEECTL, SEEOP_READ | SEESTART);
+		
+		error = ahd_wait_seeprom(ahd);
+		if (error)
+			break;
+		if (bytestream != 0) {
+			uint8_t *bytestream_ptr;
+
+			bytestream_ptr = (uint8_t *)buf;
+			*bytestream_ptr++ = ahd_inb(ahd, SEEDAT);
+			*bytestream_ptr = ahd_inb(ahd, SEEDAT+1);
+		} else {
+			/*
+			 * ahd_inw() already handles machine byte order.
+			 */
+			*buf = ahd_inw(ahd, SEEDAT);
+		}
+		buf++;
+	}
+	return (error);
+}
+
+/*
+ * Write count 16bit words from buf, into SEEPROM attache to the
+ * controller starting at 16bit word address start_addr, using the
+ * controller's SEEPROM writing state machine.
+ */
+int
+ahd_write_seeprom(struct ahd_softc *ahd, uint16_t *buf,
+		  u_int start_addr, u_int count)
+{
+	u_int cur_addr;
+	u_int end_addr;
+	int   error;
+	int   retval;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	error = ENOENT;
+
+	/* Place the chip into write-enable mode */
+	ahd_outb(ahd, SEEADR, SEEOP_EWEN_ADDR);
+	ahd_outb(ahd, SEECTL, SEEOP_EWEN | SEESTART);
+	error = ahd_wait_seeprom(ahd);
+	if (error)
+		return (error);
+
+	/*
+	 * Write the data.  If we don't get throught the loop at
+	 * least once, the arguments were invalid.
+	 */
+	retval = EINVAL;
+	end_addr = start_addr + count;
+	for (cur_addr = start_addr; cur_addr < end_addr; cur_addr++) {
+		ahd_outw(ahd, SEEDAT, *buf++);
+		ahd_outb(ahd, SEEADR, cur_addr);
+		ahd_outb(ahd, SEECTL, SEEOP_WRITE | SEESTART);
+		
+		retval = ahd_wait_seeprom(ahd);
+		if (retval)
+			break;
+	}
+
+	/*
+	 * Disable writes.
+	 */
+	ahd_outb(ahd, SEEADR, SEEOP_EWDS_ADDR);
+	ahd_outb(ahd, SEECTL, SEEOP_EWDS | SEESTART);
+	error = ahd_wait_seeprom(ahd);
+	if (error)
+		return (error);
+	return (retval);
+}
+
+/*
+ * Wait ~100us for the serial eeprom to satisfy our request.
+ */
+int
+ahd_wait_seeprom(struct ahd_softc *ahd)
+{
+	int cnt;
+
+	cnt = 20;
+	while ((ahd_inb(ahd, SEESTAT) & (SEEARBACK|SEEBUSY)) != 0 && --cnt)
+		ahd_delay(5);
+
+	if (cnt == 0)
+		return (ETIMEDOUT);
+	return (0);
+}
+
+/*
+ * Validate the two checksums in the per_channel
+ * vital product data struct.
+ */
+int
+ahd_verify_vpd_cksum(struct vpd_config *vpd)
+{
+	int i;
+	int maxaddr;
+	uint32_t checksum;
+	uint8_t *vpdarray;
+
+	vpdarray = (uint8_t *)vpd;
+	maxaddr = offsetof(struct vpd_config, vpd_checksum);
+	checksum = 0;
+	for (i = offsetof(struct vpd_config, resource_type); i < maxaddr; i++)
+		checksum = checksum + vpdarray[i];
+	if (checksum == 0
+	 || (-checksum & 0xFF) != vpd->vpd_checksum)
+		return (0);
+
+	checksum = 0;
+	maxaddr = offsetof(struct vpd_config, checksum);
+	for (i = offsetof(struct vpd_config, default_target_flags);
+	     i < maxaddr; i++)
+		checksum = checksum + vpdarray[i];
+	if (checksum == 0
+	 || (-checksum & 0xFF) != vpd->checksum)
+		return (0);
+	return (1);
+}
+
+int
+ahd_verify_cksum(struct seeprom_config *sc)
+{
+	int i;
+	int maxaddr;
+	uint32_t checksum;
+	uint16_t *scarray;
+
+	maxaddr = (sizeof(*sc)/2) - 1;
+	checksum = 0;
+	scarray = (uint16_t *)sc;
+
+	for (i = 0; i < maxaddr; i++)
+		checksum = checksum + scarray[i];
+	if (checksum == 0
+	 || (checksum & 0xFFFF) != sc->checksum) {
+		return (0);
+	} else {
+		return (1);
+	}
+}
+
+int
+ahd_acquire_seeprom(struct ahd_softc *ahd)
+{
+	/*
+	 * We should be able to determine the SEEPROM type
+	 * from the flexport logic, but unfortunately not
+	 * all implementations have this logic and there is
+	 * no programatic method for determining if the logic
+	 * is present.
+	 */
+	return (1);
+#if 0
+	uint8_t	seetype;
+	int	error;
+
+	error = ahd_read_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, &seetype);
+	if (error != 0
+         || ((seetype & FLX_ROMSTAT_SEECFG) == FLX_ROMSTAT_SEE_NONE))
+		return (0);
+	return (1);
+#endif
+}
+
+void
+ahd_release_seeprom(struct ahd_softc *ahd)
+{
+	/* Currently a no-op */
+}
+
+int
+ahd_write_flexport(struct ahd_softc *ahd, u_int addr, u_int value)
+{
+	int error;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	if (addr > 7)
+		panic("ahd_write_flexport: address out of range");
+	ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3));
+	error = ahd_wait_flexport(ahd);
+	if (error != 0)
+		return (error);
+	ahd_outb(ahd, BRDDAT, value);
+	ahd_flush_device_writes(ahd);
+	ahd_outb(ahd, BRDCTL, BRDSTB|BRDEN|(addr << 3));
+	ahd_flush_device_writes(ahd);
+	ahd_outb(ahd, BRDCTL, BRDEN|(addr << 3));
+	ahd_flush_device_writes(ahd);
+	ahd_outb(ahd, BRDCTL, 0);
+	ahd_flush_device_writes(ahd);
+	return (0);
+}
+
+int
+ahd_read_flexport(struct ahd_softc *ahd, u_int addr, uint8_t *value)
+{
+	int	error;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	if (addr > 7)
+		panic("ahd_read_flexport: address out of range");
+	ahd_outb(ahd, BRDCTL, BRDRW|BRDEN|(addr << 3));
+	error = ahd_wait_flexport(ahd);
+	if (error != 0)
+		return (error);
+	*value = ahd_inb(ahd, BRDDAT);
+	ahd_outb(ahd, BRDCTL, 0);
+	ahd_flush_device_writes(ahd);
+	return (0);
+}
+
+/*
+ * Wait at most 2 seconds for flexport arbitration to succeed.
+ */
+int
+ahd_wait_flexport(struct ahd_softc *ahd)
+{
+	int cnt;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_SCSI_MSK, AHD_MODE_SCSI_MSK);
+	cnt = 1000000 * 2 / 5;
+	while ((ahd_inb(ahd, BRDCTL) & FLXARBACK) == 0 && --cnt)
+		ahd_delay(5);
+
+	if (cnt == 0)
+		return (ETIMEDOUT);
+	return (0);
+}
+
+/************************* Target Mode ****************************************/
+#ifdef AHD_TARGET_MODE
+cam_status
+ahd_find_tmode_devs(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb,
+		    struct ahd_tmode_tstate **tstate,
+		    struct ahd_tmode_lstate **lstate,
+		    int notfound_failure)
+{
+
+	if ((ahd->features & AHD_TARGETMODE) == 0)
+		return (CAM_REQ_INVALID);
+
+	/*
+	 * Handle the 'black hole' device that sucks up
+	 * requests to unattached luns on enabled targets.
+	 */
+	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD
+	 && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
+		*tstate = NULL;
+		*lstate = ahd->black_hole;
+	} else {
+		u_int max_id;
+
+		max_id = (ahd->features & AHD_WIDE) ? 15 : 7;
+		if (ccb->ccb_h.target_id > max_id)
+			return (CAM_TID_INVALID);
+
+		if (ccb->ccb_h.target_lun >= AHD_NUM_LUNS)
+			return (CAM_LUN_INVALID);
+
+		*tstate = ahd->enabled_targets[ccb->ccb_h.target_id];
+		*lstate = NULL;
+		if (*tstate != NULL)
+			*lstate =
+			    (*tstate)->enabled_luns[ccb->ccb_h.target_lun];
+	}
+
+	if (notfound_failure != 0 && *lstate == NULL)
+		return (CAM_PATH_INVALID);
+
+	return (CAM_REQ_CMP);
+}
+
+void
+ahd_handle_en_lun(struct ahd_softc *ahd, struct cam_sim *sim, union ccb *ccb)
+{
+#if NOT_YET
+	struct	   ahd_tmode_tstate *tstate;
+	struct	   ahd_tmode_lstate *lstate;
+	struct	   ccb_en_lun *cel;
+	cam_status status;
+	u_int	   target;
+	u_int	   lun;
+	u_int	   target_mask;
+	u_long	   s;
+	char	   channel;
+
+	status = ahd_find_tmode_devs(ahd, sim, ccb, &tstate, &lstate,
+				     /*notfound_failure*/FALSE);
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	if ((ahd->features & AHD_MULTIROLE) != 0) {
+		u_int	   our_id;
+
+		our_id = ahd->our_id;
+		if (ccb->ccb_h.target_id != our_id) {
+			if ((ahd->features & AHD_MULTI_TID) != 0
+		   	 && (ahd->flags & AHD_INITIATORROLE) != 0) {
+				/*
+				 * Only allow additional targets if
+				 * the initiator role is disabled.
+				 * The hardware cannot handle a re-select-in
+				 * on the initiator id during a re-select-out
+				 * on a different target id.
+				 */
+				status = CAM_TID_INVALID;
+			} else if ((ahd->flags & AHD_INITIATORROLE) != 0
+				|| ahd->enabled_luns > 0) {
+				/*
+				 * Only allow our target id to change
+				 * if the initiator role is not configured
+				 * and there are no enabled luns which
+				 * are attached to the currently registered
+				 * scsi id.
+				 */
+				status = CAM_TID_INVALID;
+			}
+		}
+	}
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	/*
+	 * We now have an id that is valid.
+	 * If we aren't in target mode, switch modes.
+	 */
+	if ((ahd->flags & AHD_TARGETROLE) == 0
+	 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
+		u_long	s;
+
+		printf("Configuring Target Mode\n");
+		ahd_lock(ahd, &s);
+		if (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+			ccb->ccb_h.status = CAM_BUSY;
+			ahd_unlock(ahd, &s);
+			return;
+		}
+		ahd->flags |= AHD_TARGETROLE;
+		if ((ahd->features & AHD_MULTIROLE) == 0)
+			ahd->flags &= ~AHD_INITIATORROLE;
+		ahd_pause(ahd);
+		ahd_loadseq(ahd);
+		ahd_restart(ahd);
+		ahd_unlock(ahd, &s);
+	}
+	cel = &ccb->cel;
+	target = ccb->ccb_h.target_id;
+	lun = ccb->ccb_h.target_lun;
+	channel = SIM_CHANNEL(ahd, sim);
+	target_mask = 0x01 << target;
+	if (channel == 'B')
+		target_mask <<= 8;
+
+	if (cel->enable != 0) {
+		u_int scsiseq1;
+
+		/* Are we already enabled?? */
+		if (lstate != NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Lun already enabled\n");
+			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
+			return;
+		}
+
+		if (cel->grp6_len != 0
+		 || cel->grp7_len != 0) {
+			/*
+			 * Don't (yet?) support vendor
+			 * specific commands.
+			 */
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+			printf("Non-zero Group Codes\n");
+			return;
+		}
+
+		/*
+		 * Seems to be okay.
+		 * Setup our data structures.
+		 */
+		if (target != CAM_TARGET_WILDCARD && tstate == NULL) {
+			tstate = ahd_alloc_tstate(ahd, target, channel);
+			if (tstate == NULL) {
+				xpt_print_path(ccb->ccb_h.path);
+				printf("Couldn't allocate tstate\n");
+				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+				return;
+			}
+		}
+		lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+		if (lstate == NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate lstate\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		memset(lstate, 0, sizeof(*lstate));
+		status = xpt_create_path(&lstate->path, /*periph*/NULL,
+					 xpt_path_path_id(ccb->ccb_h.path),
+					 xpt_path_target_id(ccb->ccb_h.path),
+					 xpt_path_lun_id(ccb->ccb_h.path));
+		if (status != CAM_REQ_CMP) {
+			free(lstate, M_DEVBUF);
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate path\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		SLIST_INIT(&lstate->accept_tios);
+		SLIST_INIT(&lstate->immed_notifies);
+		ahd_lock(ahd, &s);
+		ahd_pause(ahd);
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = lstate;
+			ahd->enabled_luns++;
+
+			if ((ahd->features & AHD_MULTI_TID) != 0) {
+				u_int targid_mask;
+
+				targid_mask = ahd_inb(ahd, TARGID)
+					    | (ahd_inb(ahd, TARGID + 1) << 8);
+
+				targid_mask |= target_mask;
+				ahd_outb(ahd, TARGID, targid_mask);
+				ahd_outb(ahd, TARGID+1, (targid_mask >> 8));
+				
+				ahd_update_scsiid(ahd, targid_mask);
+			} else {
+				u_int our_id;
+				char  channel;
+
+				channel = SIM_CHANNEL(ahd, sim);
+				our_id = SIM_SCSI_ID(ahd, sim);
+
+				/*
+				 * This can only happen if selections
+				 * are not enabled
+				 */
+				if (target != our_id) {
+					u_int sblkctl;
+					char  cur_channel;
+					int   swap;
+
+					sblkctl = ahd_inb(ahd, SBLKCTL);
+					cur_channel = (sblkctl & SELBUSB)
+						    ? 'B' : 'A';
+					if ((ahd->features & AHD_TWIN) == 0)
+						cur_channel = 'A';
+					swap = cur_channel != channel;
+					ahd->our_id = target;
+
+					if (swap)
+						ahd_outb(ahd, SBLKCTL,
+							 sblkctl ^ SELBUSB);
+
+					ahd_outb(ahd, SCSIID, target);
+
+					if (swap)
+						ahd_outb(ahd, SBLKCTL, sblkctl);
+				}
+			}
+		} else
+			ahd->black_hole = lstate;
+		/* Allow select-in operations */
+		if (ahd->black_hole != NULL && ahd->enabled_luns > 0) {
+			scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
+			scsiseq1 |= ENSELI;
+			ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1);
+			scsiseq1 = ahd_inb(ahd, SCSISEQ1);
+			scsiseq1 |= ENSELI;
+			ahd_outb(ahd, SCSISEQ1, scsiseq1);
+		}
+		ahd_unpause(ahd);
+		ahd_unlock(ahd, &s);
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Lun now enabled for target mode\n");
+	} else {
+		struct scb *scb;
+		int i, empty;
+
+		if (lstate == NULL) {
+			ccb->ccb_h.status = CAM_LUN_INVALID;
+			return;
+		}
+
+		ahd_lock(ahd, &s);
+		
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
+			struct ccb_hdr *ccbh;
+
+			ccbh = &scb->io_ctx->ccb_h;
+			if (ccbh->func_code == XPT_CONT_TARGET_IO
+			 && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
+				printf("CTIO pending\n");
+				ccb->ccb_h.status = CAM_REQ_INVALID;
+				ahd_unlock(ahd, &s);
+				return;
+			}
+		}
+
+		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
+			printf("ATIOs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
+			printf("INOTs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (ccb->ccb_h.status != CAM_REQ_CMP) {
+			ahd_unlock(ahd, &s);
+			return;
+		}
+
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Target mode disabled\n");
+		xpt_free_path(lstate->path);
+		free(lstate, M_DEVBUF);
+
+		ahd_pause(ahd);
+		/* Can we clean up the target too? */
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = NULL;
+			ahd->enabled_luns--;
+			for (empty = 1, i = 0; i < 8; i++)
+				if (tstate->enabled_luns[i] != NULL) {
+					empty = 0;
+					break;
+				}
+
+			if (empty) {
+				ahd_free_tstate(ahd, target, channel,
+						/*force*/FALSE);
+				if (ahd->features & AHD_MULTI_TID) {
+					u_int targid_mask;
+
+					targid_mask = ahd_inb(ahd, TARGID)
+						    | (ahd_inb(ahd, TARGID + 1)
+						       << 8);
+
+					targid_mask &= ~target_mask;
+					ahd_outb(ahd, TARGID, targid_mask);
+					ahd_outb(ahd, TARGID+1,
+					 	 (targid_mask >> 8));
+					ahd_update_scsiid(ahd, targid_mask);
+				}
+			}
+		} else {
+
+			ahd->black_hole = NULL;
+
+			/*
+			 * We can't allow selections without
+			 * our black hole device.
+			 */
+			empty = TRUE;
+		}
+		if (ahd->enabled_luns == 0) {
+			/* Disallow select-in */
+			u_int scsiseq1;
+
+			scsiseq1 = ahd_inb(ahd, SCSISEQ_TEMPLATE);
+			scsiseq1 &= ~ENSELI;
+			ahd_outb(ahd, SCSISEQ_TEMPLATE, scsiseq1);
+			scsiseq1 = ahd_inb(ahd, SCSISEQ1);
+			scsiseq1 &= ~ENSELI;
+			ahd_outb(ahd, SCSISEQ1, scsiseq1);
+
+			if ((ahd->features & AHD_MULTIROLE) == 0) {
+				printf("Configuring Initiator Mode\n");
+				ahd->flags &= ~AHD_TARGETROLE;
+				ahd->flags |= AHD_INITIATORROLE;
+				ahd_pause(ahd);
+				ahd_loadseq(ahd);
+				ahd_restart(ahd);
+				/*
+				 * Unpaused.  The extra unpause
+				 * that follows is harmless.
+				 */
+			}
+		}
+		ahd_unpause(ahd);
+		ahd_unlock(ahd, &s);
+	}
+#endif
+}
+
+static void
+ahd_update_scsiid(struct ahd_softc *ahd, u_int targid_mask)
+{
+#if NOT_YET
+	u_int scsiid_mask;
+	u_int scsiid;
+
+	if ((ahd->features & AHD_MULTI_TID) == 0)
+		panic("ahd_update_scsiid called on non-multitid unit\n");
+
+	/*
+	 * Since we will rely on the TARGID mask
+	 * for selection enables, ensure that OID
+	 * in SCSIID is not set to some other ID
+	 * that we don't want to allow selections on.
+	 */
+	if ((ahd->features & AHD_ULTRA2) != 0)
+		scsiid = ahd_inb(ahd, SCSIID_ULTRA2);
+	else
+		scsiid = ahd_inb(ahd, SCSIID);
+	scsiid_mask = 0x1 << (scsiid & OID);
+	if ((targid_mask & scsiid_mask) == 0) {
+		u_int our_id;
+
+		/* ffs counts from 1 */
+		our_id = ffs(targid_mask);
+		if (our_id == 0)
+			our_id = ahd->our_id;
+		else
+			our_id--;
+		scsiid &= TID;
+		scsiid |= our_id;
+	}
+	if ((ahd->features & AHD_ULTRA2) != 0)
+		ahd_outb(ahd, SCSIID_ULTRA2, scsiid);
+	else
+		ahd_outb(ahd, SCSIID, scsiid);
+#endif
+}
+
+void
+ahd_run_tqinfifo(struct ahd_softc *ahd, int paused)
+{
+	struct target_cmd *cmd;
+
+	ahd_sync_tqinfifo(ahd, BUS_DMASYNC_POSTREAD);
+	while ((cmd = &ahd->targetcmds[ahd->tqinfifonext])->cmd_valid != 0) {
+
+		/*
+		 * Only advance through the queue if we
+		 * have the resources to process the command.
+		 */
+		if (ahd_handle_target_cmd(ahd, cmd) != 0)
+			break;
+
+		cmd->cmd_valid = 0;
+		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+				ahd->shared_data_dmamap,
+				ahd_targetcmd_offset(ahd, ahd->tqinfifonext),
+				sizeof(struct target_cmd),
+				BUS_DMASYNC_PREREAD);
+		ahd->tqinfifonext++;
+
+		/*
+		 * Lazily update our position in the target mode incoming
+		 * command queue as seen by the sequencer.
+		 */
+		if ((ahd->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
+			u_int hs_mailbox;
+
+			hs_mailbox = ahd_inb(ahd, HS_MAILBOX);
+			hs_mailbox &= ~HOST_TQINPOS;
+			hs_mailbox |= ahd->tqinfifonext & HOST_TQINPOS;
+			ahd_outb(ahd, HS_MAILBOX, hs_mailbox);
+		}
+	}
+}
+
+static int
+ahd_handle_target_cmd(struct ahd_softc *ahd, struct target_cmd *cmd)
+{
+	struct	  ahd_tmode_tstate *tstate;
+	struct	  ahd_tmode_lstate *lstate;
+	struct	  ccb_accept_tio *atio;
+	uint8_t *byte;
+	int	  initiator;
+	int	  target;
+	int	  lun;
+
+	initiator = SCSIID_TARGET(ahd, cmd->scsiid);
+	target = SCSIID_OUR_ID(cmd->scsiid);
+	lun    = (cmd->identify & MSG_IDENTIFY_LUNMASK);
+
+	byte = cmd->bytes;
+	tstate = ahd->enabled_targets[target];
+	lstate = NULL;
+	if (tstate != NULL)
+		lstate = tstate->enabled_luns[lun];
+
+	/*
+	 * Commands for disabled luns go to the black hole driver.
+	 */
+	if (lstate == NULL)
+		lstate = ahd->black_hole;
+
+	atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
+	if (atio == NULL) {
+		ahd->flags |= AHD_TQINFIFO_BLOCKED;
+		/*
+		 * Wait for more ATIOs from the peripheral driver for this lun.
+		 */
+		return (1);
+	} else
+		ahd->flags &= ~AHD_TQINFIFO_BLOCKED;
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_TQIN) != 0)
+		printf("Incoming command from %d for %d:%d%s\n",
+		       initiator, target, lun,
+		       lstate == ahd->black_hole ? "(Black Holed)" : "");
+#endif
+	SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
+
+	if (lstate == ahd->black_hole) {
+		/* Fill in the wildcards */
+		atio->ccb_h.target_id = target;
+		atio->ccb_h.target_lun = lun;
+	}
+
+	/*
+	 * Package it up and send it off to
+	 * whomever has this lun enabled.
+	 */
+	atio->sense_len = 0;
+	atio->init_id = initiator;
+	if (byte[0] != 0xFF) {
+		/* Tag was included */
+		atio->tag_action = *byte++;
+		atio->tag_id = *byte++;
+		atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
+	} else {
+		atio->ccb_h.flags = 0;
+	}
+	byte++;
+
+	/* Okay.  Now determine the cdb size based on the command code */
+	switch (*byte >> CMD_GROUP_CODE_SHIFT) {
+	case 0:
+		atio->cdb_len = 6;
+		break;
+	case 1:
+	case 2:
+		atio->cdb_len = 10;
+		break;
+	case 4:
+		atio->cdb_len = 16;
+		break;
+	case 5:
+		atio->cdb_len = 12;
+		break;
+	case 3:
+	default:
+		/* Only copy the opcode. */
+		atio->cdb_len = 1;
+		printf("Reserved or VU command code type encountered\n");
+		break;
+	}
+	
+	memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len);
+
+	atio->ccb_h.status |= CAM_CDB_RECVD;
+
+	if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) {
+		/*
+		 * We weren't allowed to disconnect.
+		 * We're hanging on the bus until a
+		 * continue target I/O comes in response
+		 * to this accept tio.
+		 */
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_TQIN) != 0)
+			printf("Received Immediate Command %d:%d:%d - %p\n",
+			       initiator, target, lun, ahd->pending_device);
+#endif
+		ahd->pending_device = lstate;
+		ahd_freeze_ccb((union ccb *)atio);
+		atio->ccb_h.flags |= CAM_DIS_DISCONNECT;
+	}
+	xpt_done((union ccb*)atio);
+	return (0);
+}
+
+#endif
diff --git a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
new file mode 100644
index 0000000..d80bc51
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h
@@ -0,0 +1,965 @@
+/*
+ * Inline routines shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#51 $
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AIC79XX_INLINE_H_
+#define _AIC79XX_INLINE_H_
+
+/******************************** Debugging ***********************************/
+static __inline char *ahd_name(struct ahd_softc *ahd);
+
+static __inline char *
+ahd_name(struct ahd_softc *ahd)
+{
+	return (ahd->name);
+}
+
+/************************ Sequencer Execution Control *************************/
+static __inline void ahd_known_modes(struct ahd_softc *ahd,
+				     ahd_mode src, ahd_mode dst);
+static __inline ahd_mode_state ahd_build_mode_state(struct ahd_softc *ahd,
+						    ahd_mode src,
+						    ahd_mode dst);
+static __inline void ahd_extract_mode_state(struct ahd_softc *ahd,
+					    ahd_mode_state state,
+					    ahd_mode *src, ahd_mode *dst);
+static __inline void ahd_set_modes(struct ahd_softc *ahd, ahd_mode src,
+				   ahd_mode dst);
+static __inline void ahd_update_modes(struct ahd_softc *ahd);
+static __inline void ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
+				      ahd_mode dstmode, const char *file,
+				      int line);
+static __inline ahd_mode_state ahd_save_modes(struct ahd_softc *ahd);
+static __inline void ahd_restore_modes(struct ahd_softc *ahd,
+				       ahd_mode_state state);
+static __inline int  ahd_is_paused(struct ahd_softc *ahd);
+static __inline void ahd_pause(struct ahd_softc *ahd);
+static __inline void ahd_unpause(struct ahd_softc *ahd);
+
+static __inline void
+ahd_known_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
+{
+	ahd->src_mode = src;
+	ahd->dst_mode = dst;
+	ahd->saved_src_mode = src;
+	ahd->saved_dst_mode = dst;
+}
+
+static __inline ahd_mode_state
+ahd_build_mode_state(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
+{
+	return ((src << SRC_MODE_SHIFT) | (dst << DST_MODE_SHIFT));
+}
+
+static __inline void
+ahd_extract_mode_state(struct ahd_softc *ahd, ahd_mode_state state,
+		       ahd_mode *src, ahd_mode *dst)
+{
+	*src = (state & SRC_MODE) >> SRC_MODE_SHIFT;
+	*dst = (state & DST_MODE) >> DST_MODE_SHIFT;
+}
+
+static __inline void
+ahd_set_modes(struct ahd_softc *ahd, ahd_mode src, ahd_mode dst)
+{
+	if (ahd->src_mode == src && ahd->dst_mode == dst)
+		return;
+#ifdef AHD_DEBUG
+	if (ahd->src_mode == AHD_MODE_UNKNOWN
+	 || ahd->dst_mode == AHD_MODE_UNKNOWN)
+		panic("Setting mode prior to saving it.\n");
+	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+		printf("%s: Setting mode 0x%x\n", ahd_name(ahd),
+		       ahd_build_mode_state(ahd, src, dst));
+#endif
+	ahd_outb(ahd, MODE_PTR, ahd_build_mode_state(ahd, src, dst));
+	ahd->src_mode = src;
+	ahd->dst_mode = dst;
+}
+
+static __inline void
+ahd_update_modes(struct ahd_softc *ahd)
+{
+	ahd_mode_state mode_ptr;
+	ahd_mode src;
+	ahd_mode dst;
+
+	mode_ptr = ahd_inb(ahd, MODE_PTR);
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_MODEPTR) != 0)
+		printf("Reading mode 0x%x\n", mode_ptr);
+#endif
+	ahd_extract_mode_state(ahd, mode_ptr, &src, &dst);
+	ahd_known_modes(ahd, src, dst);
+}
+
+static __inline void
+ahd_assert_modes(struct ahd_softc *ahd, ahd_mode srcmode,
+		 ahd_mode dstmode, const char *file, int line)
+{
+#ifdef AHD_DEBUG
+	if ((srcmode & AHD_MK_MSK(ahd->src_mode)) == 0
+	 || (dstmode & AHD_MK_MSK(ahd->dst_mode)) == 0) {
+		panic("%s:%s:%d: Mode assertion failed.\n",
+		       ahd_name(ahd), file, line);
+	}
+#endif
+}
+
+static __inline ahd_mode_state
+ahd_save_modes(struct ahd_softc *ahd)
+{
+	if (ahd->src_mode == AHD_MODE_UNKNOWN
+	 || ahd->dst_mode == AHD_MODE_UNKNOWN)
+		ahd_update_modes(ahd);
+
+	return (ahd_build_mode_state(ahd, ahd->src_mode, ahd->dst_mode));
+}
+
+static __inline void
+ahd_restore_modes(struct ahd_softc *ahd, ahd_mode_state state)
+{
+	ahd_mode src;
+	ahd_mode dst;
+
+	ahd_extract_mode_state(ahd, state, &src, &dst);
+	ahd_set_modes(ahd, src, dst);
+}
+
+#define AHD_ASSERT_MODES(ahd, source, dest) \
+	ahd_assert_modes(ahd, source, dest, __FILE__, __LINE__);
+
+/*
+ * Determine whether the sequencer has halted code execution.
+ * Returns non-zero status if the sequencer is stopped.
+ */
+static __inline int
+ahd_is_paused(struct ahd_softc *ahd)
+{
+	return ((ahd_inb(ahd, HCNTRL) & PAUSE) != 0);
+}
+
+/*
+ * Request that the sequencer stop and wait, indefinitely, for it
+ * to stop.  The sequencer will only acknowledge that it is paused
+ * once it has reached an instruction boundary and PAUSEDIS is
+ * cleared in the SEQCTL register.  The sequencer may use PAUSEDIS
+ * for critical sections.
+ */
+static __inline void
+ahd_pause(struct ahd_softc *ahd)
+{
+	ahd_outb(ahd, HCNTRL, ahd->pause);
+
+	/*
+	 * Since the sequencer can disable pausing in a critical section, we
+	 * must loop until it actually stops.
+	 */
+	while (ahd_is_paused(ahd) == 0)
+		;
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted.  If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+static __inline void
+ahd_unpause(struct ahd_softc *ahd)
+{
+	/*
+	 * Automatically restore our modes to those saved
+	 * prior to the first change of the mode.
+	 */
+	if (ahd->saved_src_mode != AHD_MODE_UNKNOWN
+	 && ahd->saved_dst_mode != AHD_MODE_UNKNOWN) {
+		if ((ahd->flags & AHD_UPDATE_PEND_CMDS) != 0)
+			ahd_reset_cmds_pending(ahd);
+		ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
+	}
+
+	if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
+		ahd_outb(ahd, HCNTRL, ahd->unpause);
+
+	ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
+}
+
+/*********************** Scatter Gather List Handling *************************/
+static __inline void	*ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+				      void *sgptr, dma_addr_t addr,
+				      bus_size_t len, int last);
+static __inline void	 ahd_setup_scb_common(struct ahd_softc *ahd,
+					      struct scb *scb);
+static __inline void	 ahd_setup_data_scb(struct ahd_softc *ahd,
+					    struct scb *scb);
+static __inline void	 ahd_setup_noxfer_scb(struct ahd_softc *ahd,
+					      struct scb *scb);
+
+static __inline void *
+ahd_sg_setup(struct ahd_softc *ahd, struct scb *scb,
+	     void *sgptr, dma_addr_t addr, bus_size_t len, int last)
+{
+	scb->sg_count++;
+	if (sizeof(dma_addr_t) > 4
+	 && (ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+		struct ahd_dma64_seg *sg;
+
+		sg = (struct ahd_dma64_seg *)sgptr;
+		sg->addr = ahd_htole64(addr);
+		sg->len = ahd_htole32(len | (last ? AHD_DMA_LAST_SEG : 0));
+		return (sg + 1);
+	} else {
+		struct ahd_dma_seg *sg;
+
+		sg = (struct ahd_dma_seg *)sgptr;
+		sg->addr = ahd_htole32(addr & 0xFFFFFFFF);
+		sg->len = ahd_htole32(len | ((addr >> 8) & 0x7F000000)
+				    | (last ? AHD_DMA_LAST_SEG : 0));
+		return (sg + 1);
+	}
+}
+
+static __inline void
+ahd_setup_scb_common(struct ahd_softc *ahd, struct scb *scb)
+{
+	/* XXX Handle target mode SCBs. */
+	scb->crc_retry_count = 0;
+	if ((scb->flags & SCB_PACKETIZED) != 0) {
+		/* XXX what about ACA??  It is type 4, but TAG_TYPE == 0x3. */
+		scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE;
+	} else {
+		if (ahd_get_transfer_length(scb) & 0x01)
+			scb->hscb->task_attribute = SCB_XFERLEN_ODD;
+		else
+			scb->hscb->task_attribute = 0;
+	}
+
+	if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR
+	 || (scb->hscb->cdb_len & SCB_CDB_LEN_PTR) != 0)
+		scb->hscb->shared_data.idata.cdb_plus_saddr.sense_addr =
+		    ahd_htole32(scb->sense_busaddr);
+}
+
+static __inline void
+ahd_setup_data_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	/*
+	 * Copy the first SG into the "current" data ponter area.
+	 */
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) {
+		struct ahd_dma64_seg *sg;
+
+		sg = (struct ahd_dma64_seg *)scb->sg_list;
+		scb->hscb->dataptr = sg->addr;
+		scb->hscb->datacnt = sg->len;
+	} else {
+		struct ahd_dma_seg *sg;
+		uint32_t *dataptr_words;
+
+		sg = (struct ahd_dma_seg *)scb->sg_list;
+		dataptr_words = (uint32_t*)&scb->hscb->dataptr;
+		dataptr_words[0] = sg->addr;
+		dataptr_words[1] = 0;
+		if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
+			uint64_t high_addr;
+
+			high_addr = ahd_le32toh(sg->len) & 0x7F000000;
+			scb->hscb->dataptr |= ahd_htole64(high_addr << 8);
+		}
+		scb->hscb->datacnt = sg->len;
+	}
+	/*
+	 * Note where to find the SG entries in bus space.
+	 * We also set the full residual flag which the 
+	 * sequencer will clear as soon as a data transfer
+	 * occurs.
+	 */
+	scb->hscb->sgptr = ahd_htole32(scb->sg_list_busaddr|SG_FULL_RESID);
+}
+
+static __inline void
+ahd_setup_noxfer_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	scb->hscb->sgptr = ahd_htole32(SG_LIST_NULL);
+	scb->hscb->dataptr = 0;
+	scb->hscb->datacnt = 0;
+}
+
+/************************** Memory mapping routines ***************************/
+static __inline size_t	ahd_sg_size(struct ahd_softc *ahd);
+static __inline void *
+			ahd_sg_bus_to_virt(struct ahd_softc *ahd,
+					   struct scb *scb,
+					   uint32_t sg_busaddr);
+static __inline uint32_t
+			ahd_sg_virt_to_bus(struct ahd_softc *ahd,
+					   struct scb *scb,
+					   void *sg);
+static __inline void	ahd_sync_scb(struct ahd_softc *ahd,
+				     struct scb *scb, int op);
+static __inline void	ahd_sync_sglist(struct ahd_softc *ahd,
+					struct scb *scb, int op);
+static __inline void	ahd_sync_sense(struct ahd_softc *ahd,
+				       struct scb *scb, int op);
+static __inline uint32_t
+			ahd_targetcmd_offset(struct ahd_softc *ahd,
+					     u_int index);
+
+static __inline size_t
+ahd_sg_size(struct ahd_softc *ahd)
+{
+	if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0)
+		return (sizeof(struct ahd_dma64_seg));
+	return (sizeof(struct ahd_dma_seg));
+}
+
+static __inline void *
+ahd_sg_bus_to_virt(struct ahd_softc *ahd, struct scb *scb, uint32_t sg_busaddr)
+{
+	dma_addr_t sg_offset;
+
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_offset = sg_busaddr - (scb->sg_list_busaddr - ahd_sg_size(ahd));
+	return ((uint8_t *)scb->sg_list + sg_offset);
+}
+
+static __inline uint32_t
+ahd_sg_virt_to_bus(struct ahd_softc *ahd, struct scb *scb, void *sg)
+{
+	dma_addr_t sg_offset;
+
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_offset = ((uint8_t *)sg - (uint8_t *)scb->sg_list)
+		  - ahd_sg_size(ahd);
+
+	return (scb->sg_list_busaddr + sg_offset);
+}
+
+static __inline void
+ahd_sync_scb(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+	ahd_dmamap_sync(ahd, ahd->scb_data.hscb_dmat,
+			scb->hscb_map->dmamap,
+			/*offset*/(uint8_t*)scb->hscb - scb->hscb_map->vaddr,
+			/*len*/sizeof(*scb->hscb), op);
+}
+
+static __inline void
+ahd_sync_sglist(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+	if (scb->sg_count == 0)
+		return;
+
+	ahd_dmamap_sync(ahd, ahd->scb_data.sg_dmat,
+			scb->sg_map->dmamap,
+			/*offset*/scb->sg_list_busaddr - ahd_sg_size(ahd),
+			/*len*/ahd_sg_size(ahd) * scb->sg_count, op);
+}
+
+static __inline void
+ahd_sync_sense(struct ahd_softc *ahd, struct scb *scb, int op)
+{
+	ahd_dmamap_sync(ahd, ahd->scb_data.sense_dmat,
+			scb->sense_map->dmamap,
+			/*offset*/scb->sense_busaddr,
+			/*len*/AHD_SENSE_BUFSIZE, op);
+}
+
+static __inline uint32_t
+ahd_targetcmd_offset(struct ahd_softc *ahd, u_int index)
+{
+	return (((uint8_t *)&ahd->targetcmds[index])
+	       - (uint8_t *)ahd->qoutfifo);
+}
+
+/*********************** Miscelaneous Support Functions ***********************/
+static __inline void	ahd_complete_scb(struct ahd_softc *ahd,
+					 struct scb *scb);
+static __inline void	ahd_update_residual(struct ahd_softc *ahd,
+					    struct scb *scb);
+static __inline struct ahd_initiator_tinfo *
+			ahd_fetch_transinfo(struct ahd_softc *ahd,
+					    char channel, u_int our_id,
+					    u_int remote_id,
+					    struct ahd_tmode_tstate **tstate);
+static __inline uint16_t
+			ahd_inw(struct ahd_softc *ahd, u_int port);
+static __inline void	ahd_outw(struct ahd_softc *ahd, u_int port,
+				 u_int value);
+static __inline uint32_t
+			ahd_inl(struct ahd_softc *ahd, u_int port);
+static __inline void	ahd_outl(struct ahd_softc *ahd, u_int port,
+				 uint32_t value);
+static __inline uint64_t
+			ahd_inq(struct ahd_softc *ahd, u_int port);
+static __inline void	ahd_outq(struct ahd_softc *ahd, u_int port,
+				 uint64_t value);
+static __inline u_int	ahd_get_scbptr(struct ahd_softc *ahd);
+static __inline void	ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr);
+static __inline u_int	ahd_get_hnscb_qoff(struct ahd_softc *ahd);
+static __inline void	ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value);
+static __inline u_int	ahd_get_hescb_qoff(struct ahd_softc *ahd);
+static __inline void	ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value);
+static __inline u_int	ahd_get_snscb_qoff(struct ahd_softc *ahd);
+static __inline void	ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value);
+static __inline u_int	ahd_get_sescb_qoff(struct ahd_softc *ahd);
+static __inline void	ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value);
+static __inline u_int	ahd_get_sdscb_qoff(struct ahd_softc *ahd);
+static __inline void	ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value);
+static __inline u_int	ahd_inb_scbram(struct ahd_softc *ahd, u_int offset);
+static __inline u_int	ahd_inw_scbram(struct ahd_softc *ahd, u_int offset);
+static __inline uint32_t
+			ahd_inl_scbram(struct ahd_softc *ahd, u_int offset);
+static __inline uint64_t
+			ahd_inq_scbram(struct ahd_softc *ahd, u_int offset);
+static __inline void	ahd_swap_with_next_hscb(struct ahd_softc *ahd,
+						struct scb *scb);
+static __inline void	ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb);
+static __inline uint8_t *
+			ahd_get_sense_buf(struct ahd_softc *ahd,
+					  struct scb *scb);
+static __inline uint32_t
+			ahd_get_sense_bufaddr(struct ahd_softc *ahd,
+					      struct scb *scb);
+
+static __inline void
+ahd_complete_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	uint32_t sgptr;
+
+	sgptr = ahd_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_STATUS_VALID) != 0)
+		ahd_handle_scb_status(ahd, scb);
+	else
+		ahd_done(ahd, scb);
+}
+
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static __inline void
+ahd_update_residual(struct ahd_softc *ahd, struct scb *scb)
+{
+	uint32_t sgptr;
+
+	sgptr = ahd_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_STATUS_VALID) != 0)
+		ahd_calc_residual(ahd, scb);
+}
+
+/*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+ */
+static __inline struct ahd_initiator_tinfo *
+ahd_fetch_transinfo(struct ahd_softc *ahd, char channel, u_int our_id,
+		    u_int remote_id, struct ahd_tmode_tstate **tstate)
+{
+	/*
+	 * Transfer data structures are stored from the perspective
+	 * of the target role.  Since the parameters for a connection
+	 * in the initiator role to a given target are the same as
+	 * when the roles are reversed, we pretend we are the target.
+	 */
+	if (channel == 'B')
+		our_id += 8;
+	*tstate = ahd->enabled_targets[our_id];
+	return (&(*tstate)->transinfo[remote_id]);
+}
+
+#define AHD_COPY_COL_IDX(dst, src)				\
+do {								\
+	dst->hscb->scsiid = src->hscb->scsiid;			\
+	dst->hscb->lun = src->hscb->lun;			\
+} while (0)
+
+static __inline uint16_t
+ahd_inw(struct ahd_softc *ahd, u_int port)
+{
+	return ((ahd_inb(ahd, port+1) << 8) | ahd_inb(ahd, port));
+}
+
+static __inline void
+ahd_outw(struct ahd_softc *ahd, u_int port, u_int value)
+{
+	ahd_outb(ahd, port, value & 0xFF);
+	ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+}
+
+static __inline uint32_t
+ahd_inl(struct ahd_softc *ahd, u_int port)
+{
+	return ((ahd_inb(ahd, port))
+	      | (ahd_inb(ahd, port+1) << 8)
+	      | (ahd_inb(ahd, port+2) << 16)
+	      | (ahd_inb(ahd, port+3) << 24));
+}
+
+static __inline void
+ahd_outl(struct ahd_softc *ahd, u_int port, uint32_t value)
+{
+	ahd_outb(ahd, port, (value) & 0xFF);
+	ahd_outb(ahd, port+1, ((value) >> 8) & 0xFF);
+	ahd_outb(ahd, port+2, ((value) >> 16) & 0xFF);
+	ahd_outb(ahd, port+3, ((value) >> 24) & 0xFF);
+}
+
+static __inline uint64_t
+ahd_inq(struct ahd_softc *ahd, u_int port)
+{
+	return ((ahd_inb(ahd, port))
+	      | (ahd_inb(ahd, port+1) << 8)
+	      | (ahd_inb(ahd, port+2) << 16)
+	      | (ahd_inb(ahd, port+3) << 24)
+	      | (((uint64_t)ahd_inb(ahd, port+4)) << 32)
+	      | (((uint64_t)ahd_inb(ahd, port+5)) << 40)
+	      | (((uint64_t)ahd_inb(ahd, port+6)) << 48)
+	      | (((uint64_t)ahd_inb(ahd, port+7)) << 56));
+}
+
+static __inline void
+ahd_outq(struct ahd_softc *ahd, u_int port, uint64_t value)
+{
+	ahd_outb(ahd, port, value & 0xFF);
+	ahd_outb(ahd, port+1, (value >> 8) & 0xFF);
+	ahd_outb(ahd, port+2, (value >> 16) & 0xFF);
+	ahd_outb(ahd, port+3, (value >> 24) & 0xFF);
+	ahd_outb(ahd, port+4, (value >> 32) & 0xFF);
+	ahd_outb(ahd, port+5, (value >> 40) & 0xFF);
+	ahd_outb(ahd, port+6, (value >> 48) & 0xFF);
+	ahd_outb(ahd, port+7, (value >> 56) & 0xFF);
+}
+
+static __inline u_int
+ahd_get_scbptr(struct ahd_softc *ahd)
+{
+	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+	return (ahd_inb(ahd, SCBPTR) | (ahd_inb(ahd, SCBPTR + 1) << 8));
+}
+
+static __inline void
+ahd_set_scbptr(struct ahd_softc *ahd, u_int scbptr)
+{
+	AHD_ASSERT_MODES(ahd, ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK),
+			 ~(AHD_MODE_UNKNOWN_MSK|AHD_MODE_CFG_MSK));
+	ahd_outb(ahd, SCBPTR, scbptr & 0xFF);
+	ahd_outb(ahd, SCBPTR+1, (scbptr >> 8) & 0xFF);
+}
+
+static __inline u_int
+ahd_get_hnscb_qoff(struct ahd_softc *ahd)
+{
+	return (ahd_inw_atomic(ahd, HNSCB_QOFF));
+}
+
+static __inline void
+ahd_set_hnscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+	ahd_outw_atomic(ahd, HNSCB_QOFF, value);
+}
+
+static __inline u_int
+ahd_get_hescb_qoff(struct ahd_softc *ahd)
+{
+	return (ahd_inb(ahd, HESCB_QOFF));
+}
+
+static __inline void
+ahd_set_hescb_qoff(struct ahd_softc *ahd, u_int value)
+{
+	ahd_outb(ahd, HESCB_QOFF, value);
+}
+
+static __inline u_int
+ahd_get_snscb_qoff(struct ahd_softc *ahd)
+{
+	u_int oldvalue;
+
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	oldvalue = ahd_inw(ahd, SNSCB_QOFF);
+	ahd_outw(ahd, SNSCB_QOFF, oldvalue);
+	return (oldvalue);
+}
+
+static __inline void
+ahd_set_snscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	ahd_outw(ahd, SNSCB_QOFF, value);
+}
+
+static __inline u_int
+ahd_get_sescb_qoff(struct ahd_softc *ahd)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	return (ahd_inb(ahd, SESCB_QOFF));
+}
+
+static __inline void
+ahd_set_sescb_qoff(struct ahd_softc *ahd, u_int value)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	ahd_outb(ahd, SESCB_QOFF, value);
+}
+
+static __inline u_int
+ahd_get_sdscb_qoff(struct ahd_softc *ahd)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	return (ahd_inb(ahd, SDSCB_QOFF) | (ahd_inb(ahd, SDSCB_QOFF + 1) << 8));
+}
+
+static __inline void
+ahd_set_sdscb_qoff(struct ahd_softc *ahd, u_int value)
+{
+	AHD_ASSERT_MODES(ahd, AHD_MODE_CCHAN_MSK, AHD_MODE_CCHAN_MSK);
+	ahd_outb(ahd, SDSCB_QOFF, value & 0xFF);
+	ahd_outb(ahd, SDSCB_QOFF+1, (value >> 8) & 0xFF);
+}
+
+static __inline u_int
+ahd_inb_scbram(struct ahd_softc *ahd, u_int offset)
+{
+	u_int value;
+
+	/*
+	 * Workaround PCI-X Rev A. hardware bug.
+	 * After a host read of SCB memory, the chip
+	 * may become confused into thinking prefetch
+	 * was required.  This starts the discard timer
+	 * running and can cause an unexpected discard
+	 * timer interrupt.  The work around is to read
+	 * a normal register prior to the exhaustion of
+	 * the discard timer.  The mode pointer register
+	 * has no side effects and so serves well for
+	 * this purpose.
+	 *
+	 * Razor #528
+	 */
+	value = ahd_inb(ahd, offset);
+	if ((ahd->flags & AHD_PCIX_SCBRAM_RD_BUG) != 0)
+		ahd_inb(ahd, MODE_PTR);
+	return (value);
+}
+
+static __inline u_int
+ahd_inw_scbram(struct ahd_softc *ahd, u_int offset)
+{
+	return (ahd_inb_scbram(ahd, offset)
+	      | (ahd_inb_scbram(ahd, offset+1) << 8));
+}
+
+static __inline uint32_t
+ahd_inl_scbram(struct ahd_softc *ahd, u_int offset)
+{
+	return (ahd_inw_scbram(ahd, offset)
+	      | (ahd_inw_scbram(ahd, offset+2) << 16));
+}
+
+static __inline uint64_t
+ahd_inq_scbram(struct ahd_softc *ahd, u_int offset)
+{
+	return (ahd_inl_scbram(ahd, offset)
+	      | ((uint64_t)ahd_inl_scbram(ahd, offset+4)) << 32);
+}
+
+static __inline struct scb *
+ahd_lookup_scb(struct ahd_softc *ahd, u_int tag)
+{
+	struct scb* scb;
+
+	if (tag >= AHD_SCB_MAX)
+		return (NULL);
+	scb = ahd->scb_data.scbindex[tag];
+	if (scb != NULL)
+		ahd_sync_scb(ahd, scb,
+			     BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+	return (scb);
+}
+
+static __inline void
+ahd_swap_with_next_hscb(struct ahd_softc *ahd, struct scb *scb)
+{
+	struct hardware_scb *q_hscb;
+	uint32_t saved_hscb_busaddr;
+
+	/*
+	 * Our queuing method is a bit tricky.  The card
+	 * knows in advance which HSCB (by address) to download,
+	 * and we can't disappoint it.  To achieve this, the next
+	 * HSCB to download is saved off in ahd->next_queued_hscb.
+	 * When we are called to queue "an arbitrary scb",
+	 * we copy the contents of the incoming HSCB to the one
+	 * the sequencer knows about, swap HSCB pointers and
+	 * finally assign the SCB to the tag indexed location
+	 * in the scb_array.  This makes sure that we can still
+	 * locate the correct SCB by SCB_TAG.
+	 */
+	q_hscb = ahd->next_queued_hscb;
+	saved_hscb_busaddr = q_hscb->hscb_busaddr;
+	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+	q_hscb->hscb_busaddr = saved_hscb_busaddr;
+	q_hscb->next_hscb_busaddr = scb->hscb->hscb_busaddr;
+
+	/* Now swap HSCB pointers. */
+	ahd->next_queued_hscb = scb->hscb;
+	scb->hscb = q_hscb;
+
+	/* Now define the mapping from tag to SCB in the scbindex */
+	ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+static __inline void
+ahd_queue_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	ahd_swap_with_next_hscb(ahd, scb);
+
+	if (SCBID_IS_NULL(SCB_GET_TAG(scb)))
+		panic("Attempt to queue invalid SCB tag %x\n",
+		      SCB_GET_TAG(scb));
+
+	/*
+	 * Keep a history of SCBs we've downloaded in the qinfifo.
+	 */
+	ahd->qinfifo[AHD_QIN_WRAP(ahd->qinfifonext)] = SCB_GET_TAG(scb);
+	ahd->qinfifonext++;
+
+	if (scb->sg_count != 0)
+		ahd_setup_data_scb(ahd, scb);
+	else
+		ahd_setup_noxfer_scb(ahd, scb);
+	ahd_setup_scb_common(ahd, scb);
+
+	/*
+	 * Make sure our data is consistent from the
+	 * perspective of the adapter.
+	 */
+	ahd_sync_scb(ahd, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
+		uint64_t host_dataptr;
+
+		host_dataptr = ahd_le64toh(scb->hscb->dataptr);
+		printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
+		       ahd_name(ahd),
+		       SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr),
+		       (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
+		       (u_int)(host_dataptr & 0xFFFFFFFF),
+		       ahd_le32toh(scb->hscb->datacnt));
+	}
+#endif
+	/* Tell the adapter about the newly queued SCB */
+	ahd_set_hnscb_qoff(ahd, ahd->qinfifonext);
+}
+
+static __inline uint8_t *
+ahd_get_sense_buf(struct ahd_softc *ahd, struct scb *scb)
+{
+	return (scb->sense_data);
+}
+
+static __inline uint32_t
+ahd_get_sense_bufaddr(struct ahd_softc *ahd, struct scb *scb)
+{
+	return (scb->sense_busaddr);
+}
+
+/************************** Interrupt Processing ******************************/
+static __inline void	ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
+static __inline void	ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
+static __inline u_int	ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
+static __inline int	ahd_intr(struct ahd_softc *ahd);
+
+static __inline void
+ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
+{
+	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
+			/*offset*/0, /*len*/AHC_SCB_MAX * sizeof(uint16_t), op);
+}
+
+static __inline void
+ahd_sync_tqinfifo(struct ahd_softc *ahd, int op)
+{
+#ifdef AHD_TARGET_MODE
+	if ((ahd->flags & AHD_TARGETROLE) != 0) {
+		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+				ahd->shared_data_dmamap,
+				ahd_targetcmd_offset(ahd, 0),
+				sizeof(struct target_cmd) * AHD_TMODE_CMDS,
+				op);
+	}
+#endif
+}
+
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHD_RUN_QOUTFIFO 0x1
+#define AHD_RUN_TQINFIFO 0x2
+static __inline u_int
+ahd_check_cmdcmpltqueues(struct ahd_softc *ahd)
+{
+	u_int retval;
+
+	retval = 0;
+	ahd_dmamap_sync(ahd, ahd->shared_data_dmat, ahd->shared_data_dmamap,
+			/*offset*/ahd->qoutfifonext, /*len*/2,
+			BUS_DMASYNC_POSTREAD);
+	if ((ahd->qoutfifo[ahd->qoutfifonext]
+	     & QOUTFIFO_ENTRY_VALID_LE) == ahd->qoutfifonext_valid_tag)
+		retval |= AHD_RUN_QOUTFIFO;
+#ifdef AHD_TARGET_MODE
+	if ((ahd->flags & AHD_TARGETROLE) != 0
+	 && (ahd->flags & AHD_TQINFIFO_BLOCKED) == 0) {
+		ahd_dmamap_sync(ahd, ahd->shared_data_dmat,
+				ahd->shared_data_dmamap,
+				ahd_targetcmd_offset(ahd, ahd->tqinfifofnext),
+				/*len*/sizeof(struct target_cmd),
+				BUS_DMASYNC_POSTREAD);
+		if (ahd->targetcmds[ahd->tqinfifonext].cmd_valid != 0)
+			retval |= AHD_RUN_TQINFIFO;
+	}
+#endif
+	return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+static __inline int
+ahd_intr(struct ahd_softc *ahd)
+{
+	u_int	intstat;
+
+	if ((ahd->pause & INTEN) == 0) {
+		/*
+		 * Our interrupt is not enabled on the chip
+		 * and may be disabled for re-entrancy reasons,
+		 * so just return.  This is likely just a shared
+		 * interrupt.
+		 */
+		return (0);
+	}
+
+	/*
+	 * Instead of directly reading the interrupt status register,
+	 * infer the cause of the interrupt by checking our in-core
+	 * completion queues.  This avoids a costly PCI bus read in
+	 * most cases.
+	 */
+	if ((ahd->flags & AHD_ALL_INTERRUPTS) == 0
+	 && (ahd_check_cmdcmpltqueues(ahd) != 0))
+		intstat = CMDCMPLT;
+	else
+		intstat = ahd_inb(ahd, INTSTAT);
+
+	if ((intstat & INT_PEND) == 0)
+		return (0);
+
+	if (intstat & CMDCMPLT) {
+		ahd_outb(ahd, CLRINT, CLRCMDINT);
+
+		/*
+		 * Ensure that the chip sees that we've cleared
+		 * this interrupt before we walk the output fifo.
+		 * Otherwise, we may, due to posted bus writes,
+		 * clear the interrupt after we finish the scan,
+		 * and after the sequencer has added new entries
+		 * and asserted the interrupt again.
+		 */
+		if ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0) {
+			if (ahd_is_paused(ahd)) {
+				/*
+				 * Potentially lost SEQINT.
+				 * If SEQINTCODE is non-zero,
+				 * simulate the SEQINT.
+				 */
+				if (ahd_inb(ahd, SEQINTCODE) != NO_SEQINT)
+					intstat |= SEQINT;
+			}
+		} else {
+			ahd_flush_device_writes(ahd);
+		}
+		ahd_run_qoutfifo(ahd);
+		ahd->cmdcmplt_counts[ahd->cmdcmplt_bucket]++;
+		ahd->cmdcmplt_total++;
+#ifdef AHD_TARGET_MODE
+		if ((ahd->flags & AHD_TARGETROLE) != 0)
+			ahd_run_tqinfifo(ahd, /*paused*/FALSE);
+#endif
+	}
+
+	/*
+	 * Handle statuses that may invalidate our cached
+	 * copy of INTSTAT separately.
+	 */
+	if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
+		/* Hot eject.  Do nothing */
+	} else if (intstat & HWERRINT) {
+		ahd_handle_hwerrint(ahd);
+	} else if ((intstat & (PCIINT|SPLTINT)) != 0) {
+		ahd->bus_intr(ahd);
+	} else {
+
+		if ((intstat & SEQINT) != 0)
+			ahd_handle_seqint(ahd, intstat);
+
+		if ((intstat & SCSIINT) != 0)
+			ahd_handle_scsiint(ahd, intstat);
+	}
+	return (1);
+}
+
+#endif  /* _AIC79XX_INLINE_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
new file mode 100644
index 0000000..fb2877c
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -0,0 +1,5017 @@
+/*
+ * Adaptec AIC79xx device driver for Linux.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#171 $
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-2000 Justin T. Gibbs.
+ * Copyright (c) 1997-1999 Doug Ledford
+ * Copyright (c) 2000-2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include "aic79xx_osm.h"
+#include "aic79xx_inline.h"
+#include <scsi/scsicam.h>
+
+/*
+ * Include aiclib.c as part of our
+ * "module dependencies are hard" work around.
+ */
+#include "aiclib.c"
+
+#include <linux/init.h>		/* __setup */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "sd.h"			/* For geometry detection */
+#endif
+
+#include <linux/mm.h>		/* For fetching system memory size */
+#include <linux/delay.h>	/* For ssleep/msleep */
+
+/*
+ * Lock protecting manipulation of the ahd softc list.
+ */
+spinlock_t ahd_list_spinlock;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/* For dynamic sglist size calculation. */
+u_int ahd_linux_nseg;
+#endif
+
+/*
+ * Bucket size for counting good commands in between bad ones.
+ */
+#define AHD_LINUX_ERR_THRESH	1000
+
+/*
+ * Set this to the delay in seconds after SCSI bus reset.
+ * Note, we honor this only for the initial bus reset.
+ * The scsi error recovery code performs its own bus settle
+ * delay handling for error recovery actions.
+ */
+#ifdef CONFIG_AIC79XX_RESET_DELAY_MS
+#define AIC79XX_RESET_DELAY CONFIG_AIC79XX_RESET_DELAY_MS
+#else
+#define AIC79XX_RESET_DELAY 5000
+#endif
+
+/*
+ * To change the default number of tagged transactions allowed per-device,
+ * add a line to the lilo.conf file like:
+ * append="aic79xx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ * which will result in the first four devices on the first two
+ * controllers being set to a tagged queue depth of 32.
+ *
+ * The tag_commands is an array of 16 to allow for wide and twin adapters.
+ * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15
+ * for channel 1.
+ */
+typedef struct {
+	uint16_t tag_commands[16];	/* Allow for wide/twin adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Modify this as you see fit for your system.
+ *
+ * 0			tagged queuing disabled
+ * 1 <= n <= 253	n == max tags ever dispatched.
+ *
+ * The driver will throttle the number of commands dispatched to a
+ * device if it returns queue full.  For devices with a fixed maximum
+ * queue depth, the driver will eventually determine this depth and
+ * lock it in (a console message is printed to indicate that a lock
+ * has occurred).  On some devices, queue full is returned for a temporary
+ * resource shortage.  These devices will return queue full at varying
+ * depths.  The driver will throttle back when the queue fulls occur and
+ * attempt to slowly increase the depth over time as the device recovers
+ * from the resource shortage.
+ *
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic79xx adapter.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to attempt to use up to 64 tags for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+
+/*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is just below this comment block.
+adapter_tag_info_t aic79xx_tag_info[] =
+{
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}},
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+*/
+
+#ifdef CONFIG_AIC79XX_CMDS_PER_DEVICE
+#define AIC79XX_CMDS_PER_DEVICE CONFIG_AIC79XX_CMDS_PER_DEVICE
+#else
+#define AIC79XX_CMDS_PER_DEVICE AHD_MAX_QUEUE
+#endif
+
+#define AIC79XX_CONFIGED_TAG_COMMANDS {					\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE,		\
+	AIC79XX_CMDS_PER_DEVICE, AIC79XX_CMDS_PER_DEVICE		\
+}
+
+/*
+ * By default, use the number of commands specified by
+ * the users kernel configuration.
+ */
+static adapter_tag_info_t aic79xx_tag_info[] =
+{
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS},
+	{AIC79XX_CONFIGED_TAG_COMMANDS}
+};
+
+/*
+ * By default, read streaming is disabled.  In theory,
+ * read streaming should enhance performance, but early
+ * U320 drive firmware actually performs slower with
+ * read streaming enabled.
+ */
+#ifdef CONFIG_AIC79XX_ENABLE_RD_STRM
+#define AIC79XX_CONFIGED_RD_STRM 0xFFFF
+#else
+#define AIC79XX_CONFIGED_RD_STRM 0
+#endif
+
+static uint16_t aic79xx_rd_strm_info[] =
+{
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM,
+	AIC79XX_CONFIGED_RD_STRM
+};
+
+/*
+ * DV option:
+ *
+ * positive value = DV Enabled
+ * zero		  = DV Disabled
+ * negative value = DV Default for adapter type/seeprom
+ */
+#ifdef CONFIG_AIC79XX_DV_SETTING
+#define AIC79XX_CONFIGED_DV CONFIG_AIC79XX_DV_SETTING
+#else
+#define AIC79XX_CONFIGED_DV -1
+#endif
+
+static int8_t aic79xx_dv_settings[] =
+{
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV,
+	AIC79XX_CONFIGED_DV
+};
+
+/*
+ * The I/O cell on the chip is very configurable in respect to its analog
+ * characteristics.  Set the defaults here; they can be overriden with
+ * the proper insmod parameters.
+ */
+struct ahd_linux_iocell_opts
+{
+	uint8_t	precomp;
+	uint8_t	slewrate;
+	uint8_t amplitude;
+};
+#define AIC79XX_DEFAULT_PRECOMP		0xFF
+#define AIC79XX_DEFAULT_SLEWRATE	0xFF
+#define AIC79XX_DEFAULT_AMPLITUDE	0xFF
+#define AIC79XX_DEFAULT_IOOPTS			\
+{						\
+	AIC79XX_DEFAULT_PRECOMP,		\
+	AIC79XX_DEFAULT_SLEWRATE,		\
+	AIC79XX_DEFAULT_AMPLITUDE		\
+}
+#define AIC79XX_PRECOMP_INDEX	0
+#define AIC79XX_SLEWRATE_INDEX	1
+#define AIC79XX_AMPLITUDE_INDEX	2
+static struct ahd_linux_iocell_opts aic79xx_iocell_info[] =
+{
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS,
+	AIC79XX_DEFAULT_IOOPTS
+};
+
+/*
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW   DID_ERROR
+
+void
+ahd_print_path(struct ahd_softc *ahd, struct scb *scb)
+{
+	printk("(scsi%d:%c:%d:%d): ",
+	       ahd->platform_data->host->host_no,
+	       scb != NULL ? SCB_GET_CHANNEL(ahd, scb) : 'X',
+	       scb != NULL ? SCB_GET_TARGET(ahd, scb) : -1,
+	       scb != NULL ? SCB_GET_LUN(scb) : -1);
+}
+
+/*
+ * XXX - these options apply unilaterally to _all_ adapters
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
+ */
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static uint32_t aic79xx_no_reset;
+
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static uint32_t aic79xx_reverse_scan;
+
+/*
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
+ */
+static uint32_t aic79xx_extended;
+
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations, it can generate tons of false error messages.
+ * It's included in the driver for completeness.
+ *   0	   = Shut off PCI parity check
+ *   non-0 = Enable PCI parity check
+ *
+ * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
+ * variable to -1 you would actually want to simply pass the variable
+ * name without a number.  That will invert the 0 which will result in
+ * -1.
+ */
+static uint32_t aic79xx_pci_parity = ~0;
+
+/*
+ * There are lots of broken chipsets in the world.  Some of them will
+ * violate the PCI spec when we issue byte sized memory writes to our
+ * controller.  I/O mapped register access, if allowed by the given
+ * platform, will work in almost all cases.
+ */
+uint32_t aic79xx_allow_memio = ~0;
+
+/*
+ * aic79xx_detect() has been run, so register all device arrivals
+ * immediately with the system rather than deferring to the sorted
+ * attachment performed by aic79xx_detect().
+ */
+int aic79xx_detect_complete;
+
+/*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ *   0 - 256ms
+ *   1 - 128ms
+ *   2 - 64ms
+ *   3 - 32ms
+ * We default to 256ms because some older devices need a longer time
+ * to respond to initial selection.
+ */
+static uint32_t aic79xx_seltime;
+
+/*
+ * Certain devices do not perform any aging on commands.  Should the
+ * device be saturated by commands in one portion of the disk, it is
+ * possible for transactions on far away sectors to never be serviced.
+ * To handle these devices, we can periodically send an ordered tag to
+ * force all outstanding transactions to be serviced prior to a new
+ * transaction.
+ */
+uint32_t aic79xx_periodic_otag;
+
+/*
+ * Module information and settable options.
+ */
+static char *aic79xx = NULL;
+
+MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
+MODULE_DESCRIPTION("Adaptec Aic790X U320 SCSI Host Bus Adapter driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(AIC79XX_DRIVER_VERSION);
+module_param(aic79xx, charp, 0);
+MODULE_PARM_DESC(aic79xx,
+"period delimited, options string.\n"
+"	verbose			Enable verbose/diagnostic logging\n"
+"	allow_memio		Allow device registers to be memory mapped\n"
+"	debug			Bitmask of debug values to enable\n"
+"	no_reset		Supress initial bus resets\n"
+"	extended		Enable extended geometry on all controllers\n"
+"	periodic_otag		Send an ordered tagged transaction\n"
+"				periodically to prevent tag starvation.\n"
+"				This may be required by some older disk\n"
+"				or drives/RAID arrays.\n"
+"	reverse_scan		Sort PCI devices highest Bus/Slot to lowest\n"
+"	tag_info:<tag_str>	Set per-target tag depth\n"
+"	global_tag_depth:<int>	Global tag depth for all targets on all buses\n"
+"	rd_strm:<rd_strm_masks> Set per-target read streaming setting.\n"
+"	dv:<dv_settings>	Set per-controller Domain Validation Setting.\n"
+"	slewrate:<slewrate_list>Set the signal slew rate (0-15).\n"
+"	precomp:<pcomp_list>	Set the signal precompensation (0-7).\n"
+"	amplitude:<int>		Set the signal amplitude (0-7).\n"
+"	seltime:<int>		Selection Timeout:\n"
+"				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
+"\n"
+"	Sample /etc/modprobe.conf line:\n"
+"		Enable verbose logging\n"
+"		Set tag depth on Controller 2/Target 2 to 10 tags\n"
+"		Shorten the selection timeout to 128ms\n"
+"\n"
+"	options aic79xx 'aic79xx=verbose.tag_info:{{}.{}.{..10}}.seltime:1'\n"
+"\n"
+"	Sample /etc/modprobe.conf line:\n"
+"		Change Read Streaming for Controller's 2 and 3\n"
+"\n"
+"	options aic79xx 'aic79xx=rd_strm:{..0xFFF0.0xC0F0}'");
+
+static void ahd_linux_handle_scsi_status(struct ahd_softc *,
+					 struct ahd_linux_device *,
+					 struct scb *);
+static void ahd_linux_queue_cmd_complete(struct ahd_softc *ahd,
+					 Scsi_Cmnd *cmd);
+static void ahd_linux_filter_inquiry(struct ahd_softc *ahd,
+				     struct ahd_devinfo *devinfo);
+static void ahd_linux_dev_timed_unfreeze(u_long arg);
+static void ahd_linux_sem_timeout(u_long arg);
+static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
+static void ahd_linux_size_nseg(void);
+static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
+static void ahd_linux_start_dv(struct ahd_softc *ahd);
+static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);
+static int  ahd_linux_dv_thread(void *data);
+static void ahd_linux_kill_dv_thread(struct ahd_softc *ahd);
+static void ahd_linux_dv_target(struct ahd_softc *ahd, u_int target);
+static void ahd_linux_dv_transition(struct ahd_softc *ahd,
+				    struct scsi_cmnd *cmd,
+				    struct ahd_devinfo *devinfo,
+				    struct ahd_linux_target *targ);
+static void ahd_linux_dv_fill_cmd(struct ahd_softc *ahd,
+				  struct scsi_cmnd *cmd,
+				  struct ahd_devinfo *devinfo);
+static void ahd_linux_dv_inq(struct ahd_softc *ahd,
+			     struct scsi_cmnd *cmd,
+			     struct ahd_devinfo *devinfo,
+			     struct ahd_linux_target *targ,
+			     u_int request_length);
+static void ahd_linux_dv_tur(struct ahd_softc *ahd,
+			     struct scsi_cmnd *cmd,
+			     struct ahd_devinfo *devinfo);
+static void ahd_linux_dv_rebd(struct ahd_softc *ahd,
+			      struct scsi_cmnd *cmd,
+			      struct ahd_devinfo *devinfo,
+			      struct ahd_linux_target *targ);
+static void ahd_linux_dv_web(struct ahd_softc *ahd,
+			     struct scsi_cmnd *cmd,
+			     struct ahd_devinfo *devinfo,
+			     struct ahd_linux_target *targ);
+static void ahd_linux_dv_reb(struct ahd_softc *ahd,
+			     struct scsi_cmnd *cmd,
+			     struct ahd_devinfo *devinfo,
+			     struct ahd_linux_target *targ);
+static void ahd_linux_dv_su(struct ahd_softc *ahd,
+			    struct scsi_cmnd *cmd,
+			    struct ahd_devinfo *devinfo,
+			    struct ahd_linux_target *targ);
+static int ahd_linux_fallback(struct ahd_softc *ahd,
+			      struct ahd_devinfo *devinfo);
+static __inline int ahd_linux_dv_fallback(struct ahd_softc *ahd,
+					  struct ahd_devinfo *devinfo);
+static void ahd_linux_dv_complete(Scsi_Cmnd *cmd);
+static void ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ);
+static u_int ahd_linux_user_tagdepth(struct ahd_softc *ahd,
+				     struct ahd_devinfo *devinfo);
+static u_int ahd_linux_user_dv_setting(struct ahd_softc *ahd);
+static void ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd);
+static void ahd_linux_device_queue_depth(struct ahd_softc *ahd,
+					 struct ahd_linux_device *dev);
+static struct ahd_linux_target*	ahd_linux_alloc_target(struct ahd_softc*,
+						       u_int, u_int);
+static void			ahd_linux_free_target(struct ahd_softc*,
+						      struct ahd_linux_target*);
+static struct ahd_linux_device*	ahd_linux_alloc_device(struct ahd_softc*,
+						       struct ahd_linux_target*,
+						       u_int);
+static void			ahd_linux_free_device(struct ahd_softc*,
+						      struct ahd_linux_device*);
+static void ahd_linux_run_device_queue(struct ahd_softc*,
+				       struct ahd_linux_device*);
+static void ahd_linux_setup_tag_info_global(char *p);
+static aic_option_callback_t ahd_linux_setup_tag_info;
+static aic_option_callback_t ahd_linux_setup_rd_strm_info;
+static aic_option_callback_t ahd_linux_setup_dv;
+static aic_option_callback_t ahd_linux_setup_iocell_info;
+static int ahd_linux_next_unit(void);
+static void ahd_runq_tasklet(unsigned long data);
+static int aic79xx_setup(char *c);
+
+/****************************** Inlines ***************************************/
+static __inline void ahd_schedule_completeq(struct ahd_softc *ahd);
+static __inline void ahd_schedule_runq(struct ahd_softc *ahd);
+static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);
+static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);
+static __inline struct ahd_linux_device*
+		     ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,
+					  u_int target, u_int lun, int alloc);
+static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd);
+static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,
+						  struct ahd_linux_device *dev);
+static __inline struct ahd_linux_device *
+		     ahd_linux_next_device_to_run(struct ahd_softc *ahd);
+static __inline void ahd_linux_run_device_queues(struct ahd_softc *ahd);
+static __inline void ahd_linux_unmap_scb(struct ahd_softc*, struct scb*);
+
+static __inline void
+ahd_schedule_completeq(struct ahd_softc *ahd)
+{
+	if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {
+		ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;
+		ahd->platform_data->completeq_timer.expires = jiffies;
+		add_timer(&ahd->platform_data->completeq_timer);
+	}
+}
+
+/*
+ * Must be called with our lock held.
+ */
+static __inline void
+ahd_schedule_runq(struct ahd_softc *ahd)
+{
+	tasklet_schedule(&ahd->platform_data->runq_tasklet);
+}
+
+static __inline
+void ahd_setup_runq_tasklet(struct ahd_softc *ahd)
+{
+	tasklet_init(&ahd->platform_data->runq_tasklet, ahd_runq_tasklet,
+		     (unsigned long)ahd);
+}
+
+static __inline void
+ahd_teardown_runq_tasklet(struct ahd_softc *ahd)
+{
+	tasklet_kill(&ahd->platform_data->runq_tasklet);
+}
+
+static __inline struct ahd_linux_device*
+ahd_linux_get_device(struct ahd_softc *ahd, u_int channel, u_int target,
+		     u_int lun, int alloc)
+{
+	struct ahd_linux_target *targ;
+	struct ahd_linux_device *dev;
+	u_int target_offset;
+
+	target_offset = target;
+	if (channel != 0)
+		target_offset += 8;
+	targ = ahd->platform_data->targets[target_offset];
+	if (targ == NULL) {
+		if (alloc != 0) {
+			targ = ahd_linux_alloc_target(ahd, channel, target);
+			if (targ == NULL)
+				return (NULL);
+		} else
+			return (NULL);
+	}
+	dev = targ->devices[lun];
+	if (dev == NULL && alloc != 0)
+		dev = ahd_linux_alloc_device(ahd, targ, lun);
+	return (dev);
+}
+
+#define AHD_LINUX_MAX_RETURNED_ERRORS 4
+static struct ahd_cmd *
+ahd_linux_run_complete_queue(struct ahd_softc *ahd)
+{	
+	struct	ahd_cmd *acmd;
+	u_long	done_flags;
+	int	with_errors;
+
+	with_errors = 0;
+	ahd_done_lock(ahd, &done_flags);
+	while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) {
+		Scsi_Cmnd *cmd;
+
+		if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {
+			/*
+			 * Linux uses stack recursion to requeue
+			 * commands that need to be retried.  Avoid
+			 * blowing out the stack by "spoon feeding"
+			 * commands that completed with error back
+			 * the operating system in case they are going
+			 * to be retried. "ick"
+			 */
+			ahd_schedule_completeq(ahd);
+			break;
+		}
+		TAILQ_REMOVE(&ahd->platform_data->completeq,
+			     acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		cmd->host_scribble = NULL;
+		if (ahd_cmd_get_transaction_status(cmd) != DID_OK
+		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
+			with_errors++;
+
+		cmd->scsi_done(cmd);
+	}
+	ahd_done_unlock(ahd, &done_flags);
+	return (acmd);
+}
+
+static __inline void
+ahd_linux_check_device_queue(struct ahd_softc *ahd,
+			     struct ahd_linux_device *dev)
+{
+	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) != 0
+	 && dev->active == 0) {
+		dev->flags &= ~AHD_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen--;
+	}
+
+	if (TAILQ_FIRST(&dev->busyq) == NULL
+	 || dev->openings == 0 || dev->qfrozen != 0)
+		return;
+
+	ahd_linux_run_device_queue(ahd, dev);
+}
+
+static __inline struct ahd_linux_device *
+ahd_linux_next_device_to_run(struct ahd_softc *ahd)
+{
+	
+	if ((ahd->flags & AHD_RESOURCE_SHORTAGE) != 0
+	 || (ahd->platform_data->qfrozen != 0
+	  && AHD_DV_SIMQ_FROZEN(ahd) == 0))
+		return (NULL);
+	return (TAILQ_FIRST(&ahd->platform_data->device_runq));
+}
+
+static __inline void
+ahd_linux_run_device_queues(struct ahd_softc *ahd)
+{
+	struct ahd_linux_device *dev;
+
+	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
+		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
+		dev->flags &= ~AHD_DEV_ON_RUN_LIST;
+		ahd_linux_check_device_queue(ahd, dev);
+	}
+}
+
+static __inline void
+ahd_linux_unmap_scb(struct ahd_softc *ahd, struct scb *scb)
+{
+	Scsi_Cmnd *cmd;
+	int direction;
+
+	cmd = scb->io_ctx;
+	direction = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+	ahd_sync_sglist(ahd, scb, BUS_DMASYNC_POSTWRITE);
+	if (cmd->use_sg != 0) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *)cmd->request_buffer;
+		pci_unmap_sg(ahd->dev_softc, sg, cmd->use_sg, direction);
+	} else if (cmd->request_bufflen != 0) {
+		pci_unmap_single(ahd->dev_softc,
+				 scb->platform_data->buf_busaddr,
+				 cmd->request_bufflen, direction);
+	}
+}
+
+/******************************** Macros **************************************/
+#define BUILD_SCSIID(ahd, cmd)						\
+	((((cmd)->device->id << TID_SHIFT) & TID) | (ahd)->our_id)
+
+/************************  Host template entry points *************************/
+static int	   ahd_linux_detect(Scsi_Host_Template *);
+static const char *ahd_linux_info(struct Scsi_Host *);
+static int	   ahd_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int	   ahd_linux_slave_alloc(Scsi_Device *);
+static int	   ahd_linux_slave_configure(Scsi_Device *);
+static void	   ahd_linux_slave_destroy(Scsi_Device *);
+#if defined(__i386__)
+static int	   ahd_linux_biosparam(struct scsi_device*,
+				       struct block_device*, sector_t, int[]);
+#endif
+#else
+static int	   ahd_linux_release(struct Scsi_Host *);
+static void	   ahd_linux_select_queue_depth(struct Scsi_Host *host,
+						Scsi_Device *scsi_devs);
+#if defined(__i386__)
+static int	   ahd_linux_biosparam(Disk *, kdev_t, int[]);
+#endif
+#endif
+static int	   ahd_linux_bus_reset(Scsi_Cmnd *);
+static int	   ahd_linux_dev_reset(Scsi_Cmnd *);
+static int	   ahd_linux_abort(Scsi_Cmnd *);
+
+/*
+ * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
+ *
+ * In pre-2.5.X...
+ * The midlayer allocates an S/G array dynamically when a command is issued
+ * using SCSI malloc.  This array, which is in an OS dependent format that
+ * must later be copied to our private S/G list, is sized to house just the
+ * number of segments needed for the current transfer.  Since the code that
+ * sizes the SCSI malloc pool does not take into consideration fragmentation
+ * of the pool, executing transactions numbering just a fraction of our
+ * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will
+ * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
+ * mid-layer does not properly handle this scsi malloc failures for the S/G
+ * array and the result can be a lockup of the I/O subsystem.  We try to size
+ * our S/G list so that it satisfies our drivers allocation requirements in
+ * addition to avoiding fragmentation of the SCSI malloc pool.
+ */
+static void
+ahd_linux_size_nseg(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	u_int cur_size;
+	u_int best_size;
+
+	/*
+	 * The SCSI allocator rounds to the nearest 512 bytes
+	 * an cannot allocate across a page boundary.  Our algorithm
+	 * is to start at 1K of scsi malloc space per-command and
+	 * loop through all factors of the PAGE_SIZE and pick the best.
+	 */
+	best_size = 0;
+	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
+		u_int nseg;
+
+		nseg = cur_size / sizeof(struct scatterlist);
+		if (nseg < AHD_LINUX_MIN_NSEG)
+			continue;
+
+		if (best_size == 0) {
+			best_size = cur_size;
+			ahd_linux_nseg = nseg;
+		} else {
+			u_int best_rem;
+			u_int cur_rem;
+
+			/*
+			 * Compare the traits of the current "best_size"
+			 * with the current size to determine if the
+			 * current size is a better size.
+			 */
+			best_rem = best_size % sizeof(struct scatterlist);
+			cur_rem = cur_size % sizeof(struct scatterlist);
+			if (cur_rem < best_rem) {
+				best_size = cur_size;
+				ahd_linux_nseg = nseg;
+			}
+		}
+	}
+#endif
+}
+
+/*
+ * Try to detect an Adaptec 79XX controller.
+ */
+static int
+ahd_linux_detect(Scsi_Host_Template *template)
+{
+	struct	ahd_softc *ahd;
+	int     found;
+	int	error = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * It is a bug that the upper layer takes
+	 * this lock just prior to calling us.
+	 */
+	spin_unlock_irq(&io_request_lock);
+#endif
+
+	/*
+	 * Sanity checking of Linux SCSI data structures so
+	 * that some of our hacks^H^H^H^H^Hassumptions aren't
+	 * violated.
+	 */
+	if (offsetof(struct ahd_cmd_internal, end)
+	  > offsetof(struct scsi_cmnd, host_scribble)) {
+		printf("ahd_linux_detect: SCSI data structures changed.\n");
+		printf("ahd_linux_detect: Unable to attach\n");
+		return (0);
+	}
+	/*
+	 * Determine an appropriate size for our Scatter Gatther lists.
+	 */
+	ahd_linux_size_nseg();
+#ifdef MODULE
+	/*
+	 * If we've been passed any parameters, process them now.
+	 */
+	if (aic79xx)
+		aic79xx_setup(aic79xx);
+#endif
+
+	template->proc_name = "aic79xx";
+
+	/*
+	 * Initialize our softc list lock prior to
+	 * probing for any adapters.
+	 */
+	ahd_list_lockinit();
+
+#ifdef CONFIG_PCI
+	error = ahd_linux_pci_init();
+	if (error)
+		return error;
+#endif
+
+	/*
+	 * Register with the SCSI layer all
+	 * controllers we've found.
+	 */
+	found = 0;
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+
+		if (ahd_linux_register_host(ahd, template) == 0)
+			found++;
+	}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_lock_irq(&io_request_lock);
+#endif
+	aic79xx_detect_complete++;
+	return 0;
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * Free the passed in Scsi_Host memory structures prior to unloading the
+ * module.
+ */
+static int
+ahd_linux_release(struct Scsi_Host * host)
+{
+	struct ahd_softc *ahd;
+	u_long l;
+
+	ahd_list_lock(&l);
+	if (host != NULL) {
+
+		/*
+		 * We should be able to just perform
+		 * the free directly, but check our
+		 * list for extra sanity.
+		 */
+		ahd = ahd_find_softc(*(struct ahd_softc **)host->hostdata);
+		if (ahd != NULL) {
+			u_long s;
+
+			ahd_lock(ahd, &s);
+			ahd_intr_enable(ahd, FALSE);
+			ahd_unlock(ahd, &s);
+			ahd_free(ahd);
+		}
+	}
+	ahd_list_unlock(&l);
+	return (0);
+}
+#endif
+
+/*
+ * Return a string describing the driver.
+ */
+static const char *
+ahd_linux_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	char	ahd_info[256];
+	char   *bp;
+	struct ahd_softc *ahd;
+
+	bp = &buffer[0];
+	ahd = *(struct ahd_softc **)host->hostdata;
+	memset(bp, 0, sizeof(buffer));
+	strcpy(bp, "Adaptec AIC79XX PCI-X SCSI HBA DRIVER, Rev ");
+	strcat(bp, AIC79XX_DRIVER_VERSION);
+	strcat(bp, "\n");
+	strcat(bp, "        <");
+	strcat(bp, ahd->description);
+	strcat(bp, ">\n");
+	strcat(bp, "        ");
+	ahd_controller_info(ahd, ahd_info);
+	strcat(bp, ahd_info);
+	strcat(bp, "\n");
+
+	return (bp);
+}
+
+/*
+ * Queue an SCB to the controller.
+ */
+static int
+ahd_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+{
+	struct	 ahd_softc *ahd;
+	struct	 ahd_linux_device *dev;
+	u_long	 flags;
+
+	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
+
+	/*
+	 * Save the callback on completion function.
+	 */
+	cmd->scsi_done = scsi_done;
+
+	ahd_midlayer_entrypoint_lock(ahd, &flags);
+
+	/*
+	 * Close the race of a command that was in the process of
+	 * being queued to us just as our simq was frozen.  Let
+	 * DV commands through so long as we are only frozen to
+	 * perform DV.
+	 */
+	if (ahd->platform_data->qfrozen != 0
+	 && AHD_DV_CMD(cmd) == 0) {
+
+		ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
+		ahd_linux_queue_cmd_complete(ahd, cmd);
+		ahd_schedule_completeq(ahd);
+		ahd_midlayer_entrypoint_unlock(ahd, &flags);
+		return (0);
+	}
+	dev = ahd_linux_get_device(ahd, cmd->device->channel,
+				   cmd->device->id, cmd->device->lun,
+				   /*alloc*/TRUE);
+	if (dev == NULL) {
+		ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
+		ahd_linux_queue_cmd_complete(ahd, cmd);
+		ahd_schedule_completeq(ahd);
+		ahd_midlayer_entrypoint_unlock(ahd, &flags);
+		printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",
+		       ahd_name(ahd));
+		return (0);
+	}
+	if (cmd->cmd_len > MAX_CDB_LEN)
+		return (-EINVAL);
+	cmd->result = CAM_REQ_INPROG << 16;
+	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahd_cmd *)cmd, acmd_links.tqe);
+	if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
+		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
+		dev->flags |= AHD_DEV_ON_RUN_LIST;
+		ahd_linux_run_device_queues(ahd);
+	}
+	ahd_midlayer_entrypoint_unlock(ahd, &flags);
+	return (0);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int
+ahd_linux_slave_alloc(Scsi_Device *device)
+{
+	struct	ahd_softc *ahd;
+
+	ahd = *((struct ahd_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Alloc %d\n", ahd_name(ahd), device->id);
+	return (0);
+}
+
+static int
+ahd_linux_slave_configure(Scsi_Device *device)
+{
+	struct	ahd_softc *ahd;
+	struct	ahd_linux_device *dev;
+	u_long	flags;
+
+	ahd = *((struct ahd_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Configure %d\n", ahd_name(ahd), device->id);
+	ahd_midlayer_entrypoint_lock(ahd, &flags);
+	/*
+	 * Since Linux has attached to the device, configure
+	 * it so we don't free and allocate the device
+	 * structure on every command.
+	 */
+	dev = ahd_linux_get_device(ahd, device->channel,
+				   device->id, device->lun,
+				   /*alloc*/TRUE);
+	if (dev != NULL) {
+		dev->flags &= ~AHD_DEV_UNCONFIGURED;
+		dev->flags |= AHD_DEV_SLAVE_CONFIGURED;
+		dev->scsi_device = device;
+		ahd_linux_device_queue_depth(ahd, dev);
+	}
+	ahd_midlayer_entrypoint_unlock(ahd, &flags);
+	return (0);
+}
+
+static void
+ahd_linux_slave_destroy(Scsi_Device *device)
+{
+	struct	ahd_softc *ahd;
+	struct	ahd_linux_device *dev;
+	u_long	flags;
+
+	ahd = *((struct ahd_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Destroy %d\n", ahd_name(ahd), device->id);
+	ahd_midlayer_entrypoint_lock(ahd, &flags);
+	dev = ahd_linux_get_device(ahd, device->channel,
+				   device->id, device->lun,
+					   /*alloc*/FALSE);
+
+	/*
+	 * Filter out "silly" deletions of real devices by only
+	 * deleting devices that have had slave_configure()
+	 * called on them.  All other devices that have not
+	 * been configured will automatically be deleted by
+	 * the refcounting process.
+	 */
+	if (dev != NULL
+	 && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {
+		dev->flags |= AHD_DEV_UNCONFIGURED;
+		if (TAILQ_EMPTY(&dev->busyq)
+		 && dev->active == 0
+		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
+			ahd_linux_free_device(ahd, dev);
+	}
+	ahd_midlayer_entrypoint_unlock(ahd, &flags);
+}
+#else
+/*
+ * Sets the queue depth for each SCSI device hanging
+ * off the input host adapter.
+ */
+static void
+ahd_linux_select_queue_depth(struct Scsi_Host * host,
+			     Scsi_Device * scsi_devs)
+{
+	Scsi_Device *device;
+	Scsi_Device *ldev;
+	struct	ahd_softc *ahd;
+	u_long	flags;
+
+	ahd = *((struct ahd_softc **)host->hostdata);
+	ahd_lock(ahd, &flags);
+	for (device = scsi_devs; device != NULL; device = device->next) {
+
+		/*
+		 * Watch out for duplicate devices.  This works around
+		 * some quirks in how the SCSI scanning code does its
+		 * device management.
+		 */
+		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
+			if (ldev->host == device->host
+			 && ldev->channel == device->channel
+			 && ldev->id == device->id
+			 && ldev->lun == device->lun)
+				break;
+		}
+		/* Skip duplicate. */
+		if (ldev != device)
+			continue;
+
+		if (device->host == host) {
+			struct	 ahd_linux_device *dev;
+
+			/*
+			 * Since Linux has attached to the device, configure
+			 * it so we don't free and allocate the device
+			 * structure on every command.
+			 */
+			dev = ahd_linux_get_device(ahd, device->channel,
+						   device->id, device->lun,
+						   /*alloc*/TRUE);
+			if (dev != NULL) {
+				dev->flags &= ~AHD_DEV_UNCONFIGURED;
+				dev->scsi_device = device;
+				ahd_linux_device_queue_depth(ahd, dev);
+				device->queue_depth = dev->openings
+						    + dev->active;
+				if ((dev->flags & (AHD_DEV_Q_BASIC
+						| AHD_DEV_Q_TAGGED)) == 0) {
+					/*
+					 * We allow the OS to queue 2 untagged
+					 * transactions to us at any time even
+					 * though we can only execute them
+					 * serially on the controller/device.
+					 * This should remove some latency.
+					 */
+					device->queue_depth = 2;
+				}
+			}
+		}
+	}
+	ahd_unlock(ahd, &flags);
+}
+#endif
+
+#if defined(__i386__)
+/*
+ * Return the disk geometry for the given SCSI device.
+ */
+static int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ahd_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		    sector_t capacity, int geom[])
+{
+	uint8_t *bh;
+#else
+ahd_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+	struct	scsi_device *sdev = disk->device;
+	u_long	capacity = disk->capacity;
+	struct	buffer_head *bh;
+#endif
+	int	 heads;
+	int	 sectors;
+	int	 cylinders;
+	int	 ret;
+	int	 extended;
+	struct	 ahd_softc *ahd;
+
+	ahd = *((struct ahd_softc **)sdev->host->hostdata);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	bh = scsi_bios_ptable(bdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
+	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
+#else
+	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
+#endif
+
+	if (bh) {
+		ret = scsi_partsize(bh, capacity,
+				    &geom[2], &geom[0], &geom[1]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		kfree(bh);
+#else
+		brelse(bh);
+#endif
+		if (ret != -1)
+			return (ret);
+	}
+	heads = 64;
+	sectors = 32;
+	cylinders = aic_sector_div(capacity, heads, sectors);
+
+	if (aic79xx_extended != 0)
+		extended = 1;
+	else
+		extended = (ahd->flags & AHD_EXTENDED_TRANS_A) != 0;
+	if (extended && cylinders >= 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = aic_sector_div(capacity, heads, sectors);
+	}
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return (0);
+}
+#endif
+
+/*
+ * Abort the current SCSI command(s).
+ */
+static int
+ahd_linux_abort(Scsi_Cmnd *cmd)
+{
+	struct ahd_softc *ahd;
+	struct ahd_cmd *acmd;
+	struct ahd_cmd *list_acmd;
+	struct ahd_linux_device *dev;
+	struct scb *pending_scb;
+	u_long s;
+	u_int  saved_scbptr;
+	u_int  active_scbptr;
+	u_int  last_phase;
+	u_int  cdb_byte;
+	int    retval;
+	int    was_paused;
+	int    paused;
+	int    wait;
+	int    disconnected;
+	ahd_mode_state saved_modes;
+
+	pending_scb = NULL;
+	paused = FALSE;
+	wait = FALSE;
+	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
+	acmd = (struct ahd_cmd *)cmd;
+
+	printf("%s:%d:%d:%d: Attempting to abort cmd %p:",
+	       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+	       cmd->device->lun, cmd);
+	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
+		printf(" 0x%x", cmd->cmnd[cdb_byte]);
+	printf("\n");
+
+	/*
+	 * In all versions of Linux, we have to work around
+	 * a major flaw in how the mid-layer is locked down
+	 * if we are to sleep successfully in our error handler
+	 * while allowing our interrupt handler to run.  Since
+	 * the midlayer acquires either the io_request_lock or
+	 * our lock prior to calling us, we must use the
+	 * spin_unlock_irq() method for unlocking our lock.
+	 * This will force interrupts to be enabled on the
+	 * current CPU.  Since the EH thread should not have
+	 * been running with CPU interrupts disabled other than
+	 * by acquiring either the io_request_lock or our own
+	 * lock, this *should* be safe.
+	 */
+	ahd_midlayer_entrypoint_lock(ahd, &s);
+
+	/*
+	 * First determine if we currently own this command.
+	 * Start by searching the device queue.  If not found
+	 * there, check the pending_scb list.  If not found
+	 * at all, and the system wanted us to just abort the
+	 * command, return success.
+	 */
+	dev = ahd_linux_get_device(ahd, cmd->device->channel,
+				   cmd->device->id, cmd->device->lun,
+				   /*alloc*/FALSE);
+
+	if (dev == NULL) {
+		/*
+		 * No target device for this command exists,
+		 * so we must not still own the command.
+		 */
+		printf("%s:%d:%d:%d: Is not an active device\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		retval = SUCCESS;
+		goto no_cmd;
+	}
+
+	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
+		if (list_acmd == acmd)
+			break;
+	}
+
+	if (list_acmd != NULL) {
+		printf("%s:%d:%d:%d: Command found on device queue\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
+		cmd->result = DID_ABORT << 16;
+		ahd_linux_queue_cmd_complete(ahd, cmd);
+		retval = SUCCESS;
+		goto done;
+	}
+
+	/*
+	 * See if we can find a matching cmd in the pending list.
+	 */
+	LIST_FOREACH(pending_scb, &ahd->pending_scbs, pending_links) {
+		if (pending_scb->io_ctx == cmd)
+			break;
+	}
+
+	if (pending_scb == NULL) {
+		printf("%s:%d:%d:%d: Command not found\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		goto no_cmd;
+	}
+
+	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {
+		/*
+		 * We can't queue two recovery actions using the same SCB
+		 */
+		retval = FAILED;
+		goto  done;
+	}
+
+	/*
+	 * Ensure that the card doesn't do anything
+	 * behind our back.  Also make sure that we
+	 * didn't "just" miss an interrupt that would
+	 * affect this cmd.
+	 */
+	was_paused = ahd_is_paused(ahd);
+	ahd_pause_and_flushwork(ahd);
+	paused = TRUE;
+
+	if ((pending_scb->flags & SCB_ACTIVE) == 0) {
+		printf("%s:%d:%d:%d: Command already completed\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		goto no_cmd;
+	}
+
+	printf("%s: At time of recovery, card was %spaused\n",
+	       ahd_name(ahd), was_paused ? "" : "not ");
+	ahd_dump_card_state(ahd);
+
+	disconnected = TRUE;
+	if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A',
+			       cmd->device->lun, SCB_GET_TAG(pending_scb),
+			       ROLE_INITIATOR, CAM_REQ_ABORTED,
+			       SEARCH_COMPLETE) > 0) {
+		printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+				cmd->device->lun);
+		retval = SUCCESS;
+		goto done;
+	}
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	last_phase = ahd_inb(ahd, LASTPHASE);
+	saved_scbptr = ahd_get_scbptr(ahd);
+	active_scbptr = saved_scbptr;
+	if (disconnected && (ahd_inb(ahd, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
+		struct scb *bus_scb;
+
+		bus_scb = ahd_lookup_scb(ahd, active_scbptr);
+		if (bus_scb == pending_scb)
+			disconnected = FALSE;
+	}
+
+	/*
+	 * At this point, pending_scb is the scb associated with the
+	 * passed in command.  That command is currently active on the
+	 * bus or is in the disconnected state.
+	 */
+	if (last_phase != P_BUSFREE
+	 && SCB_GET_TAG(pending_scb) == active_scbptr) {
+
+		/*
+		 * We're active on the bus, so assert ATN
+		 * and hope that the target responds.
+		 */
+		pending_scb = ahd_lookup_scb(ahd, active_scbptr);
+		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
+		ahd_outb(ahd, MSG_OUT, HOST_MSG);
+		ahd_outb(ahd, SCSISIGO, last_phase|ATNO);
+		printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
+		       ahd_name(ahd), cmd->device->channel,
+		       cmd->device->id, cmd->device->lun);
+		wait = TRUE;
+	} else if (disconnected) {
+
+		/*
+		 * Actually re-queue this SCB in an attempt
+		 * to select the device before it reconnects.
+		 */
+		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
+		ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
+		pending_scb->hscb->cdb_len = 0;
+		pending_scb->hscb->task_attribute = 0;
+		pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK;
+
+		if ((pending_scb->flags & SCB_PACKETIZED) != 0) {
+			/*
+			 * Mark the SCB has having an outstanding
+			 * task management function.  Should the command
+			 * complete normally before the task management
+			 * function can be sent, the host will be notified
+			 * to abort our requeued SCB.
+			 */
+			ahd_outb(ahd, SCB_TASK_MANAGEMENT,
+				 pending_scb->hscb->task_management);
+		} else {
+			/*
+			 * If non-packetized, set the MK_MESSAGE control
+			 * bit indicating that we desire to send a message.
+			 * We also set the disconnected flag since there is
+			 * no guarantee that our SCB control byte matches
+			 * the version on the card.  We don't want the
+			 * sequencer to abort the command thinking an
+			 * unsolicited reselection occurred.
+			 */
+			pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
+
+			/*
+			 * The sequencer will never re-reference the
+			 * in-core SCB.  To make sure we are notified
+			 * during reslection, set the MK_MESSAGE flag in
+			 * the card's copy of the SCB.
+			 */
+			ahd_outb(ahd, SCB_CONTROL,
+				 ahd_inb(ahd, SCB_CONTROL)|MK_MESSAGE);
+		}
+
+		/*
+		 * Clear out any entries in the QINFIFO first
+		 * so we are the next SCB for this target
+		 * to run.
+		 */
+		ahd_search_qinfifo(ahd, cmd->device->id,
+				   cmd->device->channel + 'A', cmd->device->lun,
+				   SCB_LIST_NULL, ROLE_INITIATOR,
+				   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+		ahd_qinfifo_requeue_tail(ahd, pending_scb);
+		ahd_set_scbptr(ahd, saved_scbptr);
+		ahd_print_path(ahd, pending_scb);
+		printf("Device is disconnected, re-queuing SCB\n");
+		wait = TRUE;
+	} else {
+		printf("%s:%d:%d:%d: Unable to deliver message\n",
+		       ahd_name(ahd), cmd->device->channel,
+		       cmd->device->id, cmd->device->lun);
+		retval = FAILED;
+		goto done;
+	}
+
+no_cmd:
+	/*
+	 * Our assumption is that if we don't have the command, no
+	 * recovery action was required, so we return success.  Again,
+	 * the semantics of the mid-layer recovery engine are not
+	 * well defined, so this may change in time.
+	 */
+	retval = SUCCESS;
+done:
+	if (paused)
+		ahd_unpause(ahd);
+	if (wait) {
+		struct timer_list timer;
+		int ret;
+
+		pending_scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
+		spin_unlock_irq(&ahd->platform_data->spin_lock);
+		init_timer(&timer);
+		timer.data = (u_long)pending_scb;
+		timer.expires = jiffies + (5 * HZ);
+		timer.function = ahd_linux_sem_timeout;
+		add_timer(&timer);
+		printf("Recovery code sleeping\n");
+		down(&ahd->platform_data->eh_sem);
+		printf("Recovery code awake\n");
+        	ret = del_timer_sync(&timer);
+		if (ret == 0) {
+			printf("Timer Expired\n");
+			retval = FAILED;
+		}
+		spin_lock_irq(&ahd->platform_data->spin_lock);
+	}
+	ahd_schedule_runq(ahd);
+	ahd_linux_run_complete_queue(ahd);
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
+	return (retval);
+}
+
+
+static void
+ahd_linux_dev_reset_complete(Scsi_Cmnd *cmd)
+{
+	free(cmd, M_DEVBUF);
+}
+
+/*
+ * Attempt to send a target reset message to the device that timed out.
+ */
+static int
+ahd_linux_dev_reset(Scsi_Cmnd *cmd)
+{
+	struct	ahd_softc *ahd;
+	struct	scsi_cmnd *recovery_cmd;
+	struct	ahd_linux_device *dev;
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	struct	scb *scb;
+	struct	hardware_scb *hscb;
+	u_long	s;
+	struct	timer_list timer;
+	int	retval;
+
+	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
+	recovery_cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
+	if (!recovery_cmd)
+		return (FAILED);
+	memset(recovery_cmd, 0, sizeof(struct scsi_cmnd));
+	recovery_cmd->device = cmd->device;
+	recovery_cmd->scsi_done = ahd_linux_dev_reset_complete;
+#if AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+		printf("%s:%d:%d:%d: Device reset called for cmd %p\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun, cmd);
+#endif
+	ahd_midlayer_entrypoint_lock(ahd, &s);
+
+	dev = ahd_linux_get_device(ahd, cmd->device->channel, cmd->device->id,
+				   cmd->device->lun, /*alloc*/FALSE);
+	if (dev == NULL) {
+		ahd_midlayer_entrypoint_unlock(ahd, &s);
+		kfree(recovery_cmd);
+		return (FAILED);
+	}
+	if ((scb = ahd_get_scb(ahd, AHD_NEVER_COL_IDX)) == NULL) {
+		ahd_midlayer_entrypoint_unlock(ahd, &s);
+		kfree(recovery_cmd);
+		return (FAILED);
+	}
+	tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+				    cmd->device->id, &tstate);
+	recovery_cmd->result = CAM_REQ_INPROG << 16;
+	recovery_cmd->host_scribble = (char *)scb;
+	scb->io_ctx = recovery_cmd;
+	scb->platform_data->dev = dev;
+	scb->sg_count = 0;
+	ahd_set_residual(scb, 0);
+	ahd_set_sense_residual(scb, 0);
+	hscb = scb->hscb;
+	hscb->control = 0;
+	hscb->scsiid = BUILD_SCSIID(ahd, cmd);
+	hscb->lun = cmd->device->lun;
+	hscb->cdb_len = 0;
+	hscb->task_management = SIU_TASKMGMT_LUN_RESET;
+	scb->flags |= SCB_DEVICE_RESET|SCB_RECOVERY_SCB|SCB_ACTIVE;
+	if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+		scb->flags |= SCB_PACKETIZED;
+	} else {
+		hscb->control |= MK_MESSAGE;
+	}
+	dev->openings--;
+	dev->active++;
+	dev->commands_issued++;
+	LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
+	ahd_queue_scb(ahd, scb);
+
+	scb->platform_data->flags |= AHD_SCB_UP_EH_SEM;
+	spin_unlock_irq(&ahd->platform_data->spin_lock);
+	init_timer(&timer);
+	timer.data = (u_long)scb;
+	timer.expires = jiffies + (5 * HZ);
+	timer.function = ahd_linux_sem_timeout;
+	add_timer(&timer);
+	printf("Recovery code sleeping\n");
+	down(&ahd->platform_data->eh_sem);
+	printf("Recovery code awake\n");
+	retval = SUCCESS;
+	if (del_timer_sync(&timer) == 0) {
+		printf("Timer Expired\n");
+		retval = FAILED;
+	}
+	spin_lock_irq(&ahd->platform_data->spin_lock);
+	ahd_schedule_runq(ahd);
+	ahd_linux_run_complete_queue(ahd);
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
+	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
+	return (retval);
+}
+
+/*
+ * Reset the SCSI bus.
+ */
+static int
+ahd_linux_bus_reset(Scsi_Cmnd *cmd)
+{
+	struct ahd_softc *ahd;
+	u_long s;
+	int    found;
+
+	ahd = *(struct ahd_softc **)cmd->device->host->hostdata;
+#ifdef AHD_DEBUG
+	if ((ahd_debug & AHD_SHOW_RECOVERY) != 0)
+		printf("%s: Bus reset called for cmd %p\n",
+		       ahd_name(ahd), cmd);
+#endif
+	ahd_midlayer_entrypoint_lock(ahd, &s);
+	found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
+				  /*initiate reset*/TRUE);
+	ahd_linux_run_complete_queue(ahd);
+	ahd_midlayer_entrypoint_unlock(ahd, &s);
+
+	if (bootverbose)
+		printf("%s: SCSI bus reset delivered. "
+		       "%d SCBs aborted.\n", ahd_name(ahd), found);
+
+	return (SUCCESS);
+}
+
+Scsi_Host_Template aic79xx_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "aic79xx",
+	.proc_info		= ahd_linux_proc_info,
+	.info			= ahd_linux_info,
+	.queuecommand		= ahd_linux_queue,
+	.eh_abort_handler	= ahd_linux_abort,
+	.eh_device_reset_handler = ahd_linux_dev_reset,
+	.eh_bus_reset_handler	= ahd_linux_bus_reset,
+#if defined(__i386__)
+	.bios_param		= ahd_linux_biosparam,
+#endif
+	.can_queue		= AHD_MAX_QUEUE,
+	.this_id		= -1,
+	.cmd_per_lun		= 2,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.slave_alloc		= ahd_linux_slave_alloc,
+	.slave_configure	= ahd_linux_slave_configure,
+	.slave_destroy		= ahd_linux_slave_destroy,
+};
+
+/**************************** Tasklet Handler *********************************/
+
+/*
+ * In 2.4.X and above, this routine is called from a tasklet,
+ * so we must re-acquire our lock prior to executing this code.
+ * In all prior kernels, ahd_schedule_runq() calls this routine
+ * directly and ahd_schedule_runq() is called with our lock held.
+ */
+static void
+ahd_runq_tasklet(unsigned long data)
+{
+	struct ahd_softc* ahd;
+	struct ahd_linux_device *dev;
+	u_long flags;
+
+	ahd = (struct ahd_softc *)data;
+	ahd_lock(ahd, &flags);
+	while ((dev = ahd_linux_next_device_to_run(ahd)) != NULL) {
+	
+		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
+		dev->flags &= ~AHD_DEV_ON_RUN_LIST;
+		ahd_linux_check_device_queue(ahd, dev);
+		/* Yeild to our interrupt handler */
+		ahd_unlock(ahd, &flags);
+		ahd_lock(ahd, &flags);
+	}
+	ahd_unlock(ahd, &flags);
+}
+
+/******************************** Bus DMA *************************************/
+int
+ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
+		   bus_size_t alignment, bus_size_t boundary,
+		   dma_addr_t lowaddr, dma_addr_t highaddr,
+		   bus_dma_filter_t *filter, void *filterarg,
+		   bus_size_t maxsize, int nsegments,
+		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
+{
+	bus_dma_tag_t dmat;
+
+	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+	if (dmat == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Linux is very simplistic about DMA memory.  For now don't
+	 * maintain all specification information.  Once Linux supplies
+	 * better facilities for doing these operations, or the
+	 * needs of this particular driver change, we might need to do
+	 * more here.
+	 */
+	dmat->alignment = alignment;
+	dmat->boundary = boundary;
+	dmat->maxsize = maxsize;
+	*ret_tag = dmat;
+	return (0);
+}
+
+void
+ahd_dma_tag_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat)
+{
+	free(dmat, M_DEVBUF);
+}
+
+int
+ahd_dmamem_alloc(struct ahd_softc *ahd, bus_dma_tag_t dmat, void** vaddr,
+		 int flags, bus_dmamap_t *mapp)
+{
+	bus_dmamap_t map;
+
+	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
+	if (map == NULL)
+		return (ENOMEM);
+	/*
+	 * Although we can dma data above 4GB, our
+	 * "consistent" memory is below 4GB for
+	 * space efficiency reasons (only need a 4byte
+	 * address).  For this reason, we have to reset
+	 * our dma mask when doing allocations.
+	 */
+	if (ahd->dev_softc != NULL)
+		if (pci_set_dma_mask(ahd->dev_softc, 0xFFFFFFFF)) {
+			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
+			kfree(map);
+			return (ENODEV);
+		}
+	*vaddr = pci_alloc_consistent(ahd->dev_softc,
+				      dmat->maxsize, &map->bus_addr);
+	if (ahd->dev_softc != NULL)
+		if (pci_set_dma_mask(ahd->dev_softc,
+				     ahd->platform_data->hw_dma_mask)) {
+			printk(KERN_WARNING "aic79xx: No suitable DMA available.\n");
+			kfree(map);
+			return (ENODEV);
+		}
+	if (*vaddr == NULL)
+		return (ENOMEM);
+	*mapp = map;
+	return(0);
+}
+
+void
+ahd_dmamem_free(struct ahd_softc *ahd, bus_dma_tag_t dmat,
+		void* vaddr, bus_dmamap_t map)
+{
+	pci_free_consistent(ahd->dev_softc, dmat->maxsize,
+			    vaddr, map->bus_addr);
+}
+
+int
+ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map,
+		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
+		void *cb_arg, int flags)
+{
+	/*
+	 * Assume for now that this will only be used during
+	 * initialization and not for per-transaction buffer mapping.
+	 */
+	bus_dma_segment_t stack_sg;
+
+	stack_sg.ds_addr = map->bus_addr;
+	stack_sg.ds_len = dmat->maxsize;
+	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
+	return (0);
+}
+
+void
+ahd_dmamap_destroy(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/*
+	 * The map may is NULL in our < 2.3.X implementation.
+	 */
+	if (map != NULL)
+		free(map, M_DEVBUF);
+}
+
+int
+ahd_dmamap_unload(struct ahd_softc *ahd, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/* Nothing to do */
+	return (0);
+}
+
+/********************* Platform Dependent Functions ***************************/
+/*
+ * Compare "left hand" softc with "right hand" softc, returning:
+ * < 0 - lahd has a lower priority than rahd
+ *   0 - Softcs are equal
+ * > 0 - lahd has a higher priority than rahd
+ */
+int
+ahd_softc_comp(struct ahd_softc *lahd, struct ahd_softc *rahd)
+{
+	int	value;
+
+	/*
+	 * Under Linux, cards are ordered as follows:
+	 *	1) PCI devices that are marked as the boot controller.
+	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.
+	 *	3) All remaining PCI devices sorted by bus/slot/func.
+	 */
+#if 0
+	value = (lahd->flags & AHD_BOOT_CHANNEL)
+	      - (rahd->flags & AHD_BOOT_CHANNEL);
+	if (value != 0)
+		/* Controllers set for boot have a *higher* priority */
+		return (value);
+#endif
+
+	value = (lahd->flags & AHD_BIOS_ENABLED)
+	      - (rahd->flags & AHD_BIOS_ENABLED);
+	if (value != 0)
+		/* Controllers with BIOS enabled have a *higher* priority */
+		return (value);
+
+	/* Still equal.  Sort by bus/slot/func. */
+	if (aic79xx_reverse_scan != 0)
+		value = ahd_get_pci_bus(lahd->dev_softc)
+		      - ahd_get_pci_bus(rahd->dev_softc);
+	else
+		value = ahd_get_pci_bus(rahd->dev_softc)
+		      - ahd_get_pci_bus(lahd->dev_softc);
+	if (value != 0)
+		return (value);
+	if (aic79xx_reverse_scan != 0)
+		value = ahd_get_pci_slot(lahd->dev_softc)
+		      - ahd_get_pci_slot(rahd->dev_softc);
+	else
+		value = ahd_get_pci_slot(rahd->dev_softc)
+		      - ahd_get_pci_slot(lahd->dev_softc);
+	if (value != 0)
+		return (value);
+
+	value = rahd->channel - lahd->channel;
+	return (value);
+}
+
+static void
+ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
+{
+
+	if ((instance >= 0) && (targ >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_tag_info))
+	 && (targ < AHD_NUM_TARGETS)) {
+		aic79xx_tag_info[instance].tag_commands[targ] = value & 0x1FF;
+		if (bootverbose)
+			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+	}
+}
+
+static void
+ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value)
+{
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
+		aic79xx_rd_strm_info[instance] = value & 0xFFFF;
+		if (bootverbose)
+			printf("rd_strm[%d] = 0x%x\n", instance, value);
+	}
+}
+
+static void
+ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
+{
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
+		aic79xx_dv_settings[instance] = value;
+		if (bootverbose)
+			printf("dv[%d] = %d\n", instance, value);
+	}
+}
+
+static void
+ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
+{
+
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
+		uint8_t *iocell_info;
+
+		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
+		iocell_info[index] = value & 0xFFFF;
+		if (bootverbose)
+			printf("iocell[%d:%ld] = %d\n", instance, index, value);
+	}
+}
+
+static void
+ahd_linux_setup_tag_info_global(char *p)
+{
+	int tags, i, j;
+
+	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
+	printf("Setting Global Tags= %d\n", tags);
+
+	for (i = 0; i < NUM_ELEMENTS(aic79xx_tag_info); i++) {
+		for (j = 0; j < AHD_NUM_TARGETS; j++) {
+			aic79xx_tag_info[i].tag_commands[j] = tags;
+		}
+	}
+}
+
+/*
+ * Handle Linux boot parameters. This routine allows for assigning a value
+ * to a parameter with a ':' between the parameter and the value.
+ * ie. aic79xx=stpwlev:1,extended
+ */
+static int
+aic79xx_setup(char *s)
+{
+	int	i, n;
+	char   *p;
+	char   *end;
+
+	static struct {
+		const char *name;
+		uint32_t *flag;
+	} options[] = {
+		{ "extended", &aic79xx_extended },
+		{ "no_reset", &aic79xx_no_reset },
+		{ "verbose", &aic79xx_verbose },
+		{ "allow_memio", &aic79xx_allow_memio},
+#ifdef AHD_DEBUG
+		{ "debug", &ahd_debug },
+#endif
+		{ "reverse_scan", &aic79xx_reverse_scan },
+		{ "periodic_otag", &aic79xx_periodic_otag },
+		{ "pci_parity", &aic79xx_pci_parity },
+		{ "seltime", &aic79xx_seltime },
+		{ "tag_info", NULL },
+		{ "global_tag_depth", NULL},
+		{ "rd_strm", NULL },
+		{ "dv", NULL },
+		{ "slewrate", NULL },
+		{ "precomp", NULL },
+		{ "amplitude", NULL },
+	};
+
+	end = strchr(s, '\0');
+
+	/*
+	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
+	 * will never be 0 in this case.
+	 */      
+	n = 0;  
+
+	while ((p = strsep(&s, ",.")) != NULL) {
+		if (*p == '\0')
+			continue;
+		for (i = 0; i < NUM_ELEMENTS(options); i++) {
+
+			n = strlen(options[i].name);
+			if (strncmp(options[i].name, p, n) == 0)
+				break;
+		}
+		if (i == NUM_ELEMENTS(options))
+			continue;
+
+		if (strncmp(p, "global_tag_depth", n) == 0) {
+			ahd_linux_setup_tag_info_global(p + n);
+		} else if (strncmp(p, "tag_info", n) == 0) {
+			s = aic_parse_brace_option("tag_info", p + n, end,
+			    2, ahd_linux_setup_tag_info, 0);
+		} else if (strncmp(p, "rd_strm", n) == 0) {
+			s = aic_parse_brace_option("rd_strm", p + n, end,
+			    1, ahd_linux_setup_rd_strm_info, 0);
+		} else if (strncmp(p, "dv", n) == 0) {
+			s = aic_parse_brace_option("dv", p + n, end, 1,
+			    ahd_linux_setup_dv, 0);
+		} else if (strncmp(p, "slewrate", n) == 0) {
+			s = aic_parse_brace_option("slewrate",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    AIC79XX_SLEWRATE_INDEX);
+		} else if (strncmp(p, "precomp", n) == 0) {
+			s = aic_parse_brace_option("precomp",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    AIC79XX_PRECOMP_INDEX);
+		} else if (strncmp(p, "amplitude", n) == 0) {
+			s = aic_parse_brace_option("amplitude",
+			    p + n, end, 1, ahd_linux_setup_iocell_info,
+			    AIC79XX_AMPLITUDE_INDEX);
+		} else if (p[n] == ':') {
+			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+		} else if (!strncmp(p, "verbose", n)) {
+			*(options[i].flag) = 1;
+		} else {
+			*(options[i].flag) ^= 0xFFFFFFFF;
+		}
+	}
+	return 1;
+}
+
+__setup("aic79xx=", aic79xx_setup);
+
+uint32_t aic79xx_verbose;
+
+int
+ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
+{
+	char	buf[80];
+	struct	Scsi_Host *host;
+	char	*new_name;
+	u_long	s;
+	u_long	target;
+
+	template->name = ahd->description;
+	host = scsi_host_alloc(template, sizeof(struct ahd_softc *));
+	if (host == NULL)
+		return (ENOMEM);
+
+	*((struct ahd_softc **)host->hostdata) = ahd;
+	ahd_lock(ahd, &s);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	scsi_assign_lock(host, &ahd->platform_data->spin_lock);
+#elif AHD_SCSI_HAS_HOST_LOCK != 0
+	host->lock = &ahd->platform_data->spin_lock;
+#endif
+	ahd->platform_data->host = host;
+	host->can_queue = AHD_MAX_QUEUE;
+	host->cmd_per_lun = 2;
+	host->sg_tablesize = AHD_NSEG;
+	host->this_id = ahd->our_id;
+	host->irq = ahd->platform_data->irq;
+	host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
+	host->max_lun = AHD_NUM_LUNS;
+	host->max_channel = 0;
+	host->sg_tablesize = AHD_NSEG;
+	ahd_set_unit(ahd, ahd_linux_next_unit());
+	sprintf(buf, "scsi%d", host->host_no);
+	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (new_name != NULL) {
+		strcpy(new_name, buf);
+		ahd_set_name(ahd, new_name);
+	}
+	host->unique_id = ahd->unit;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	scsi_set_pci_device(host, ahd->dev_softc);
+#endif
+	ahd_linux_setup_user_rd_strm_settings(ahd);
+	ahd_linux_initialize_scsi_bus(ahd);
+	ahd_unlock(ahd, &s);
+	ahd->platform_data->dv_pid = kernel_thread(ahd_linux_dv_thread, ahd, 0);
+	ahd_lock(ahd, &s);
+	if (ahd->platform_data->dv_pid < 0) {
+		printf("%s: Failed to create DV thread, error= %d\n",
+		       ahd_name(ahd), ahd->platform_data->dv_pid);
+		return (-ahd->platform_data->dv_pid);
+	}
+	/*
+	 * Initially allocate *all* of our linux target objects
+	 * so that the DV thread will scan them all in parallel
+	 * just after driver initialization.  Any device that
+	 * does not exist will have its target object destroyed
+	 * by the selection timeout handler.  In the case of a
+	 * device that appears after the initial DV scan, async
+	 * negotiation will occur for the first command, and DV
+	 * will comence should that first command be successful.
+	 */
+	for (target = 0; target < host->max_id; target++) {
+
+		/*
+		 * Skip our own ID.  Some Compaq/HP storage devices
+		 * have enclosure management devices that respond to
+		 * single bit selection (i.e. selecting ourselves).
+		 * It is expected that either an external application
+		 * or a modified kernel will be used to probe this
+		 * ID if it is appropriate.  To accommodate these
+		 * installations, ahc_linux_alloc_target() will allocate
+		 * for our ID if asked to do so.
+		 */
+		if (target == ahd->our_id) 
+			continue;
+
+		ahd_linux_alloc_target(ahd, 0, target);
+	}
+	ahd_intr_enable(ahd, TRUE);
+	ahd_linux_start_dv(ahd);
+	ahd_unlock(ahd, &s);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	scsi_add_host(host, &ahd->dev_softc->dev); /* XXX handle failure */
+	scsi_scan_host(host);
+#endif
+	return (0);
+}
+
+uint64_t
+ahd_linux_get_memsize(void)
+{
+	struct sysinfo si;
+
+	si_meminfo(&si);
+	return ((uint64_t)si.totalram << PAGE_SHIFT);
+}
+
+/*
+ * Find the smallest available unit number to use
+ * for a new device.  We don't just use a static
+ * count to handle the "repeated hot-(un)plug"
+ * scenario.
+ */
+static int
+ahd_linux_next_unit(void)
+{
+	struct ahd_softc *ahd;
+	int unit;
+
+	unit = 0;
+retry:
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+		if (ahd->unit == unit) {
+			unit++;
+			goto retry;
+		}
+	}
+	return (unit);
+}
+
+/*
+ * Place the SCSI bus into a known state by either resetting it,
+ * or forcing transfer negotiations on the next command to any
+ * target.
+ */
+static void
+ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd)
+{
+	u_int target_id;
+	u_int numtarg;
+
+	target_id = 0;
+	numtarg = 0;
+
+	if (aic79xx_no_reset != 0)
+		ahd->flags &= ~AHD_RESET_BUS_A;
+
+	if ((ahd->flags & AHD_RESET_BUS_A) != 0)
+		ahd_reset_channel(ahd, 'A', /*initiate_reset*/TRUE);
+	else
+		numtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
+
+	/*
+	 * Force negotiation to async for all targets that
+	 * will not see an initial bus reset.
+	 */
+	for (; target_id < numtarg; target_id++) {
+		struct ahd_devinfo devinfo;
+		struct ahd_initiator_tinfo *tinfo;
+		struct ahd_tmode_tstate *tstate;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    target_id, &tstate);
+		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
+				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
+		ahd_update_neg_request(ahd, &devinfo, tstate,
+				       tinfo, AHD_NEG_ALWAYS);
+	}
+	/* Give the bus some time to recover */
+	if ((ahd->flags & AHD_RESET_BUS_A) != 0) {
+		ahd_freeze_simq(ahd);
+		init_timer(&ahd->platform_data->reset_timer);
+		ahd->platform_data->reset_timer.data = (u_long)ahd;
+		ahd->platform_data->reset_timer.expires =
+		    jiffies + (AIC79XX_RESET_DELAY * HZ)/1000;
+		ahd->platform_data->reset_timer.function =
+		    (ahd_linux_callback_t *)ahd_release_simq;
+		add_timer(&ahd->platform_data->reset_timer);
+	}
+}
+
+int
+ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg)
+{
+	ahd->platform_data =
+	    malloc(sizeof(struct ahd_platform_data), M_DEVBUF, M_NOWAIT);
+	if (ahd->platform_data == NULL)
+		return (ENOMEM);
+	memset(ahd->platform_data, 0, sizeof(struct ahd_platform_data));
+	TAILQ_INIT(&ahd->platform_data->completeq);
+	TAILQ_INIT(&ahd->platform_data->device_runq);
+	ahd->platform_data->irq = AHD_LINUX_NOIRQ;
+	ahd->platform_data->hw_dma_mask = 0xFFFFFFFF;
+	ahd_lockinit(ahd);
+	ahd_done_lockinit(ahd);
+	init_timer(&ahd->platform_data->completeq_timer);
+	ahd->platform_data->completeq_timer.data = (u_long)ahd;
+	ahd->platform_data->completeq_timer.function =
+	    (ahd_linux_callback_t *)ahd_linux_thread_run_complete_queue;
+	init_MUTEX_LOCKED(&ahd->platform_data->eh_sem);
+	init_MUTEX_LOCKED(&ahd->platform_data->dv_sem);
+	init_MUTEX_LOCKED(&ahd->platform_data->dv_cmd_sem);
+	ahd_setup_runq_tasklet(ahd);
+	ahd->seltime = (aic79xx_seltime & 0x3) << 4;
+	return (0);
+}
+
+void
+ahd_platform_free(struct ahd_softc *ahd)
+{
+	struct ahd_linux_target *targ;
+	struct ahd_linux_device *dev;
+	int i, j;
+
+	if (ahd->platform_data != NULL) {
+		del_timer_sync(&ahd->platform_data->completeq_timer);
+		ahd_linux_kill_dv_thread(ahd);
+		ahd_teardown_runq_tasklet(ahd);
+		if (ahd->platform_data->host != NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+			scsi_remove_host(ahd->platform_data->host);
+#endif
+			scsi_host_put(ahd->platform_data->host);
+		}
+
+		/* destroy all of the device and target objects */
+		for (i = 0; i < AHD_NUM_TARGETS; i++) {
+			targ = ahd->platform_data->targets[i];
+			if (targ != NULL) {
+				/* Keep target around through the loop. */
+				targ->refcount++;
+				for (j = 0; j < AHD_NUM_LUNS; j++) {
+
+					if (targ->devices[j] == NULL)
+						continue;
+					dev = targ->devices[j];
+					ahd_linux_free_device(ahd, dev);
+				}
+				/*
+				 * Forcibly free the target now that
+				 * all devices are gone.
+				 */
+				ahd_linux_free_target(ahd, targ);
+			}
+		}
+
+		if (ahd->platform_data->irq != AHD_LINUX_NOIRQ)
+			free_irq(ahd->platform_data->irq, ahd);
+		if (ahd->tags[0] == BUS_SPACE_PIO
+		 && ahd->bshs[0].ioport != 0)
+			release_region(ahd->bshs[0].ioport, 256);
+		if (ahd->tags[1] == BUS_SPACE_PIO
+		 && ahd->bshs[1].ioport != 0)
+			release_region(ahd->bshs[1].ioport, 256);
+		if (ahd->tags[0] == BUS_SPACE_MEMIO
+		 && ahd->bshs[0].maddr != NULL) {
+			iounmap(ahd->bshs[0].maddr);
+			release_mem_region(ahd->platform_data->mem_busaddr,
+					   0x1000);
+		}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+    		/*
+		 * In 2.4 we detach from the scsi midlayer before the PCI
+		 * layer invokes our remove callback.  No per-instance
+		 * detach is provided, so we must reach inside the PCI
+		 * subsystem's internals and detach our driver manually.
+		 */
+		if (ahd->dev_softc != NULL)
+			ahd->dev_softc->driver = NULL;
+#endif
+		free(ahd->platform_data, M_DEVBUF);
+	}
+}
+
+void
+ahd_platform_init(struct ahd_softc *ahd)
+{
+	/*
+	 * Lookup and commit any modified IO Cell options.
+	 */
+	if (ahd->unit < NUM_ELEMENTS(aic79xx_iocell_info)) {
+		struct ahd_linux_iocell_opts *iocell_opts;
+
+		iocell_opts = &aic79xx_iocell_info[ahd->unit];
+		if (iocell_opts->precomp != AIC79XX_DEFAULT_PRECOMP)
+			AHD_SET_PRECOMP(ahd, iocell_opts->precomp);
+		if (iocell_opts->slewrate != AIC79XX_DEFAULT_SLEWRATE)
+			AHD_SET_SLEWRATE(ahd, iocell_opts->slewrate);
+		if (iocell_opts->amplitude != AIC79XX_DEFAULT_AMPLITUDE)
+			AHD_SET_AMPLITUDE(ahd, iocell_opts->amplitude);
+	}
+
+}
+
+void
+ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb)
+{
+	ahd_platform_abort_scbs(ahd, SCB_GET_TARGET(ahd, scb),
+				SCB_GET_CHANNEL(ahd, scb),
+				SCB_GET_LUN(scb), SCB_LIST_NULL,
+				ROLE_UNKNOWN, CAM_REQUEUE_REQ);
+}
+
+void
+ahd_platform_set_tags(struct ahd_softc *ahd, struct ahd_devinfo *devinfo,
+		      ahd_queue_alg alg)
+{
+	struct ahd_linux_device *dev;
+	int was_queuing;
+	int now_queuing;
+
+	dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
+				   devinfo->target,
+				   devinfo->lun, /*alloc*/FALSE);
+	if (dev == NULL)
+		return;
+	was_queuing = dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED);
+	switch (alg) {
+	default:
+	case AHD_QUEUE_NONE:
+		now_queuing = 0;
+		break; 
+	case AHD_QUEUE_BASIC:
+		now_queuing = AHD_DEV_Q_BASIC;
+		break;
+	case AHD_QUEUE_TAGGED:
+		now_queuing = AHD_DEV_Q_TAGGED;
+		break;
+	}
+	if ((dev->flags & AHD_DEV_FREEZE_TIL_EMPTY) == 0
+	 && (was_queuing != now_queuing)
+	 && (dev->active != 0)) {
+		dev->flags |= AHD_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen++;
+	}
+
+	dev->flags &= ~(AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED|AHD_DEV_PERIODIC_OTAG);
+	if (now_queuing) {
+		u_int usertags;
+
+		usertags = ahd_linux_user_tagdepth(ahd, devinfo);
+		if (!was_queuing) {
+			/*
+			 * Start out agressively and allow our
+			 * dynamic queue depth algorithm to take
+			 * care of the rest.
+			 */
+			dev->maxtags = usertags;
+			dev->openings = dev->maxtags - dev->active;
+		}
+		if (dev->maxtags == 0) {
+			/*
+			 * Queueing is disabled by the user.
+			 */
+			dev->openings = 1;
+		} else if (alg == AHD_QUEUE_TAGGED) {
+			dev->flags |= AHD_DEV_Q_TAGGED;
+			if (aic79xx_periodic_otag != 0)
+				dev->flags |= AHD_DEV_PERIODIC_OTAG;
+		} else
+			dev->flags |= AHD_DEV_Q_BASIC;
+	} else {
+		/* We can only have one opening. */
+		dev->maxtags = 0;
+		dev->openings =  1 - dev->active;
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	if (dev->scsi_device != NULL) {
+		switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
+		case AHD_DEV_Q_BASIC:
+			scsi_adjust_queue_depth(dev->scsi_device,
+						MSG_SIMPLE_TASK,
+						dev->openings + dev->active);
+			break;
+		case AHD_DEV_Q_TAGGED:
+			scsi_adjust_queue_depth(dev->scsi_device,
+						MSG_ORDERED_TASK,
+						dev->openings + dev->active);
+			break;
+		default:
+			/*
+			 * We allow the OS to queue 2 untagged transactions to
+			 * us at any time even though we can only execute them
+			 * serially on the controller/device.  This should
+			 * remove some latency.
+			 */
+			scsi_adjust_queue_depth(dev->scsi_device,
+						/*NON-TAGGED*/0,
+						/*queue depth*/2);
+			break;
+		}
+	}
+#endif
+}
+
+int
+ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel,
+			int lun, u_int tag, role_t role, uint32_t status)
+{
+	int targ;
+	int maxtarg;
+	int maxlun;
+	int clun;
+	int count;
+
+	if (tag != SCB_LIST_NULL)
+		return (0);
+
+	targ = 0;
+	if (target != CAM_TARGET_WILDCARD) {
+		targ = target;
+		maxtarg = targ + 1;
+	} else {
+		maxtarg = (ahd->features & AHD_WIDE) ? 16 : 8;
+	}
+	clun = 0;
+	if (lun != CAM_LUN_WILDCARD) {
+		clun = lun;
+		maxlun = clun + 1;
+	} else {
+		maxlun = AHD_NUM_LUNS;
+	}
+
+	count = 0;
+	for (; targ < maxtarg; targ++) {
+
+		for (; clun < maxlun; clun++) {
+			struct ahd_linux_device *dev;
+			struct ahd_busyq *busyq;
+			struct ahd_cmd *acmd;
+
+			dev = ahd_linux_get_device(ahd, /*chan*/0, targ,
+						   clun, /*alloc*/FALSE);
+			if (dev == NULL)
+				continue;
+
+			busyq = &dev->busyq;
+			while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
+				Scsi_Cmnd *cmd;
+
+				cmd = &acmd_scsi_cmd(acmd);
+				TAILQ_REMOVE(busyq, acmd,
+					     acmd_links.tqe);
+				count++;
+				cmd->result = status << 16;
+				ahd_linux_queue_cmd_complete(ahd, cmd);
+			}
+		}
+	}
+
+	return (count);
+}
+
+static void
+ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd)
+{
+	u_long flags;
+
+	ahd_lock(ahd, &flags);
+	del_timer(&ahd->platform_data->completeq_timer);
+	ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER;
+	ahd_linux_run_complete_queue(ahd);
+	ahd_unlock(ahd, &flags);
+}
+
+static void
+ahd_linux_start_dv(struct ahd_softc *ahd)
+{
+
+	/*
+	 * Freeze the simq and signal ahd_linux_queue to not let any
+	 * more commands through
+	 */
+	if ((ahd->platform_data->flags & AHD_DV_ACTIVE) == 0) {
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_DV)
+			printf("%s: Starting DV\n", ahd_name(ahd));
+#endif
+
+		ahd->platform_data->flags |= AHD_DV_ACTIVE;
+		ahd_freeze_simq(ahd);
+
+		/* Wake up the DV kthread */
+		up(&ahd->platform_data->dv_sem);
+	}
+}
+
+static int
+ahd_linux_dv_thread(void *data)
+{
+	struct	ahd_softc *ahd;
+	int	target;
+	u_long	s;
+
+	ahd = (struct ahd_softc *)data;
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV)
+		printf("In DV Thread\n");
+#endif
+
+	/*
+	 * Complete thread creation.
+	 */
+	lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,60)
+	/*
+	 * Don't care about any signals.
+	 */
+	siginitsetinv(&current->blocked, 0);
+
+	daemonize();
+	sprintf(current->comm, "ahd_dv_%d", ahd->unit);
+#else
+	daemonize("ahd_dv_%d", ahd->unit);
+	current->flags |= PF_FREEZE;
+#endif
+	unlock_kernel();
+
+	while (1) {
+		/*
+		 * Use down_interruptible() rather than down() to
+		 * avoid inclusion in the load average.
+		 */
+		down_interruptible(&ahd->platform_data->dv_sem);
+
+		/* Check to see if we've been signaled to exit */
+		ahd_lock(ahd, &s);
+		if ((ahd->platform_data->flags & AHD_DV_SHUTDOWN) != 0) {
+			ahd_unlock(ahd, &s);
+			break;
+		}
+		ahd_unlock(ahd, &s);
+
+#ifdef AHD_DEBUG
+		if (ahd_debug & AHD_SHOW_DV)
+			printf("%s: Beginning Domain Validation\n",
+			       ahd_name(ahd));
+#endif
+
+		/*
+		 * Wait for any pending commands to drain before proceeding.
+		 */
+		ahd_lock(ahd, &s);
+		while (LIST_FIRST(&ahd->pending_scbs) != NULL) {
+			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_EMPTY;
+			ahd_unlock(ahd, &s);
+			down_interruptible(&ahd->platform_data->dv_sem);
+			ahd_lock(ahd, &s);
+		}
+
+		/*
+		 * Wait for the SIMQ to be released so that DV is the
+		 * only reason the queue is frozen.
+		 */
+		while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
+			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
+			ahd_unlock(ahd, &s);
+			down_interruptible(&ahd->platform_data->dv_sem);
+			ahd_lock(ahd, &s);
+		}
+		ahd_unlock(ahd, &s);
+
+		for (target = 0; target < AHD_NUM_TARGETS; target++)
+			ahd_linux_dv_target(ahd, target);
+
+		ahd_lock(ahd, &s);
+		ahd->platform_data->flags &= ~AHD_DV_ACTIVE;
+		ahd_unlock(ahd, &s);
+
+		/*
+		 * Release the SIMQ so that normal commands are
+		 * allowed to continue on the bus.
+		 */
+		ahd_release_simq(ahd);
+	}
+	up(&ahd->platform_data->eh_sem);
+	return (0);
+}
+
+static void
+ahd_linux_kill_dv_thread(struct ahd_softc *ahd)
+{
+	u_long s;
+
+	ahd_lock(ahd, &s);
+	if (ahd->platform_data->dv_pid != 0) {
+		ahd->platform_data->flags |= AHD_DV_SHUTDOWN;
+		ahd_unlock(ahd, &s);
+		up(&ahd->platform_data->dv_sem);
+
+		/*
+		 * Use the eh_sem as an indicator that the
+		 * dv thread is exiting.  Note that the dv
+		 * thread must still return after performing
+		 * the up on our semaphore before it has
+		 * completely exited this module.  Unfortunately,
+		 * there seems to be no easy way to wait for the
+		 * exit of a thread for which you are not the
+		 * parent (dv threads are parented by init).
+		 * Cross your fingers...
+		 */
+		down(&ahd->platform_data->eh_sem);
+
+		/*
+		 * Mark the dv thread as already dead.  This
+		 * avoids attempting to kill it a second time.
+		 * This is necessary because we must kill the
+		 * DV thread before calling ahd_free() in the
+		 * module shutdown case to avoid bogus locking
+		 * in the SCSI mid-layer, but we ahd_free() is
+		 * called without killing the DV thread in the
+		 * instance detach case, so ahd_platform_free()
+		 * calls us again to verify that the DV thread
+		 * is dead.
+		 */
+		ahd->platform_data->dv_pid = 0;
+	} else {
+		ahd_unlock(ahd, &s);
+	}
+}
+
+#define AHD_LINUX_DV_INQ_SHORT_LEN	36
+#define AHD_LINUX_DV_INQ_LEN		256
+#define AHD_LINUX_DV_TIMEOUT		(HZ / 4)
+
+#define AHD_SET_DV_STATE(ahd, targ, newstate) \
+	ahd_set_dv_state(ahd, targ, newstate, __LINE__)
+
+static __inline void
+ahd_set_dv_state(struct ahd_softc *ahd, struct ahd_linux_target *targ,
+		 ahd_dv_state newstate, u_int line)
+{
+	ahd_dv_state oldstate;
+
+	oldstate = targ->dv_state;
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV)
+		printf("%s:%d: Going from state %d to state %d\n",
+		       ahd_name(ahd), line, oldstate, newstate);
+#endif
+
+	if (oldstate == newstate)
+		targ->dv_state_retry++;
+	else
+		targ->dv_state_retry = 0;
+	targ->dv_state = newstate;
+}
+
+static void
+ahd_linux_dv_target(struct ahd_softc *ahd, u_int target_offset)
+{
+	struct	 ahd_devinfo devinfo;
+	struct	 ahd_linux_target *targ;
+	struct	 scsi_cmnd *cmd;
+	struct	 scsi_device *scsi_dev;
+	struct	 scsi_sense_data *sense;
+	uint8_t *buffer;
+	u_long	 s;
+	u_int	 timeout;
+	int	 echo_size;
+
+	sense = NULL;
+	buffer = NULL;
+	echo_size = 0;
+	ahd_lock(ahd, &s);
+	targ = ahd->platform_data->targets[target_offset];
+	if (targ == NULL || (targ->flags & AHD_DV_REQUIRED) == 0) {
+		ahd_unlock(ahd, &s);
+		return;
+	}
+	ahd_compile_devinfo(&devinfo, ahd->our_id, targ->target, /*lun*/0,
+			    targ->channel + 'A', ROLE_INITIATOR);
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, &devinfo);
+		printf("Performing DV\n");
+	}
+#endif
+
+	ahd_unlock(ahd, &s);
+
+	cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
+	scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK);
+	scsi_dev->host = ahd->platform_data->host;
+	scsi_dev->id = devinfo.target;
+	scsi_dev->lun = devinfo.lun;
+	scsi_dev->channel = devinfo.channel - 'A';
+	ahd->platform_data->dv_scsi_dev = scsi_dev;
+
+	AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_SHORT_ASYNC);
+
+	while (targ->dv_state != AHD_DV_STATE_EXIT) {
+		timeout = AHD_LINUX_DV_TIMEOUT;
+		switch (targ->dv_state) {
+		case AHD_DV_STATE_INQ_SHORT_ASYNC:
+		case AHD_DV_STATE_INQ_ASYNC:
+		case AHD_DV_STATE_INQ_ASYNC_VERIFY:
+			/*
+			 * Set things to async narrow to reduce the
+			 * chance that the INQ will fail.
+			 */
+			ahd_lock(ahd, &s);
+			ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
+					 AHD_TRANS_GOAL, /*paused*/FALSE);
+			ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHD_TRANS_GOAL, /*paused*/FALSE);
+			ahd_unlock(ahd, &s);
+			timeout = 10 * HZ;
+			targ->flags &= ~AHD_INQ_VALID;
+			/* FALLTHROUGH */
+		case AHD_DV_STATE_INQ_VERIFY:
+		{
+			u_int inq_len;
+
+			if (targ->dv_state == AHD_DV_STATE_INQ_SHORT_ASYNC)
+				inq_len = AHD_LINUX_DV_INQ_SHORT_LEN;
+			else
+				inq_len = targ->inq_data->additional_length + 5;
+			ahd_linux_dv_inq(ahd, cmd, &devinfo, targ, inq_len);
+			break;
+		}
+		case AHD_DV_STATE_TUR:
+		case AHD_DV_STATE_BUSY:
+			timeout = 5 * HZ;
+			ahd_linux_dv_tur(ahd, cmd, &devinfo);
+			break;
+		case AHD_DV_STATE_REBD:
+			ahd_linux_dv_rebd(ahd, cmd, &devinfo, targ);
+			break;
+		case AHD_DV_STATE_WEB:
+			ahd_linux_dv_web(ahd, cmd, &devinfo, targ);
+			break;
+
+		case AHD_DV_STATE_REB:
+			ahd_linux_dv_reb(ahd, cmd, &devinfo, targ);
+			break;
+
+		case AHD_DV_STATE_SU:
+			ahd_linux_dv_su(ahd, cmd, &devinfo, targ);
+			timeout = 50 * HZ;
+			break;
+
+		default:
+			ahd_print_devinfo(ahd, &devinfo);
+			printf("Unknown DV state %d\n", targ->dv_state);
+			goto out;
+		}
+
+		/* Queue the command and wait for it to complete */
+		/* Abuse eh_timeout in the scsi_cmnd struct for our purposes */
+		init_timer(&cmd->eh_timeout);
+#ifdef AHD_DEBUG
+		if ((ahd_debug & AHD_SHOW_MESSAGES) != 0)
+			/*
+			 * All of the printfs during negotiation
+			 * really slow down the negotiation.
+			 * Add a bit of time just to be safe.
+			 */
+			timeout += HZ;
+#endif
+		scsi_add_timer(cmd, timeout, ahd_linux_dv_timeout);
+		/*
+		 * In 2.5.X, it is assumed that all calls from the
+		 * "midlayer" (which we are emulating) will have the
+		 * ahd host lock held.  For other kernels, the
+		 * io_request_lock must be held.
+		 */
+#if AHD_SCSI_HAS_HOST_LOCK != 0
+		ahd_lock(ahd, &s);
+#else
+		spin_lock_irqsave(&io_request_lock, s);
+#endif
+		ahd_linux_queue(cmd, ahd_linux_dv_complete);
+#if AHD_SCSI_HAS_HOST_LOCK != 0
+		ahd_unlock(ahd, &s);
+#else
+		spin_unlock_irqrestore(&io_request_lock, s);
+#endif
+		down_interruptible(&ahd->platform_data->dv_cmd_sem);
+		/*
+		 * Wait for the SIMQ to be released so that DV is the
+		 * only reason the queue is frozen.
+		 */
+		ahd_lock(ahd, &s);
+		while (AHD_DV_SIMQ_FROZEN(ahd) == 0) {
+			ahd->platform_data->flags |= AHD_DV_WAIT_SIMQ_RELEASE;
+			ahd_unlock(ahd, &s);
+			down_interruptible(&ahd->platform_data->dv_sem);
+			ahd_lock(ahd, &s);
+		}
+		ahd_unlock(ahd, &s);
+
+		ahd_linux_dv_transition(ahd, cmd, &devinfo, targ);
+	}
+
+out:
+	if ((targ->flags & AHD_INQ_VALID) != 0
+	 && ahd_linux_get_device(ahd, devinfo.channel - 'A',
+				 devinfo.target, devinfo.lun,
+				 /*alloc*/FALSE) == NULL) {
+		/*
+		 * The DV state machine failed to configure this device.  
+		 * This is normal if DV is disabled.  Since we have inquiry
+		 * data, filter it and use the "optimistic" negotiation
+		 * parameters found in the inquiry string.
+		 */
+		ahd_linux_filter_inquiry(ahd, &devinfo);
+		if ((targ->flags & (AHD_BASIC_DV|AHD_ENHANCED_DV)) != 0) {
+			ahd_print_devinfo(ahd, &devinfo);
+			printf("DV failed to configure device.  "
+			       "Please file a bug report against "
+			       "this driver.\n");
+		}
+	}
+
+	if (cmd != NULL)
+		free(cmd, M_DEVBUF);
+
+	if (ahd->platform_data->dv_scsi_dev != NULL) {
+		free(ahd->platform_data->dv_scsi_dev, M_DEVBUF);
+		ahd->platform_data->dv_scsi_dev = NULL;
+	}
+
+	ahd_lock(ahd, &s);
+	if (targ->dv_buffer != NULL) {
+		free(targ->dv_buffer, M_DEVBUF);
+		targ->dv_buffer = NULL;
+	}
+	if (targ->dv_buffer1 != NULL) {
+		free(targ->dv_buffer1, M_DEVBUF);
+		targ->dv_buffer1 = NULL;
+	}
+	targ->flags &= ~AHD_DV_REQUIRED;
+	if (targ->refcount == 0)
+		ahd_linux_free_target(ahd, targ);
+	ahd_unlock(ahd, &s);
+}
+
+static __inline int
+ahd_linux_dv_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	u_long s;
+	int retval;
+
+	ahd_lock(ahd, &s);
+	retval = ahd_linux_fallback(ahd, devinfo);
+	ahd_unlock(ahd, &s);
+
+	return (retval);
+}
+
+static void
+ahd_linux_dv_transition(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+			struct ahd_devinfo *devinfo,
+			struct ahd_linux_target *targ)
+{
+	u_int32_t status;
+
+	status = aic_error_action(cmd, targ->inq_data,
+				  ahd_cmd_get_transaction_status(cmd),
+				  ahd_cmd_get_scsi_status(cmd));
+
+	
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Entering ahd_linux_dv_transition, state= %d, "
+		       "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state,
+		       status, cmd->result);
+	}
+#endif
+
+	switch (targ->dv_state) {
+	case AHD_DV_STATE_INQ_SHORT_ASYNC:
+	case AHD_DV_STATE_INQ_ASYNC:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+			if ((status & SS_ERRMASK) == EBUSY)
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+	case AHD_DV_STATE_INQ_ASYNC_VERIFY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			u_int xportflags;
+			u_int spi3data;
+
+			if (memcmp(targ->inq_data, targ->dv_buffer,
+				   AHD_LINUX_DV_INQ_LEN) != 0) {
+				/*
+				 * Inquiry data must have changed.
+				 * Try from the top again.
+				 */
+				AHD_SET_DV_STATE(ahd, targ,
+						 AHD_DV_STATE_INQ_SHORT_ASYNC);
+				break;
+			}
+
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state+1);
+			targ->flags |= AHD_INQ_VALID;
+			if (ahd_linux_user_dv_setting(ahd) == 0)
+				break;
+
+			xportflags = targ->inq_data->flags;
+			if ((xportflags & (SID_Sync|SID_WBus16)) == 0)
+				break;
+
+			spi3data = targ->inq_data->spi3data;
+			switch (spi3data & SID_SPI_CLOCK_DT_ST) {
+			default:
+			case SID_SPI_CLOCK_ST:
+				/* Assume only basic DV is supported. */
+				targ->flags |= AHD_BASIC_DV;
+				break;
+			case SID_SPI_CLOCK_DT:
+			case SID_SPI_CLOCK_DT_ST:
+				targ->flags |= AHD_ENHANCED_DV;
+				break;
+			}
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+
+			if ((status & SS_ERRMASK) == EBUSY)
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+	case AHD_DV_STATE_INQ_VERIFY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+
+			if (memcmp(targ->inq_data, targ->dv_buffer,
+				   AHD_LINUX_DV_INQ_LEN) == 0) {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+				break;
+			}
+
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				int i;
+
+				ahd_print_devinfo(ahd, devinfo);
+				printf("Inquiry buffer mismatch:");
+				for (i = 0; i < AHD_LINUX_DV_INQ_LEN; i++) {
+					if ((i & 0xF) == 0)
+						printf("\n        ");
+					printf("0x%x:0x0%x ",
+					       ((uint8_t *)targ->inq_data)[i], 
+					       targ->dv_buffer[i]);
+				}
+				printf("\n");
+			}
+#endif
+
+			if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+				break;
+			}
+			/*
+			 * Do not count "falling back"
+			 * against our retries.
+			 */
+			targ->dv_state_retry = 0;
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			} else if ((status & SS_ERRMASK) == EBUSY)
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_TUR:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			if ((targ->flags & AHD_BASIC_DV) != 0) {
+				ahd_linux_filter_inquiry(ahd, devinfo);
+				AHD_SET_DV_STATE(ahd, targ,
+						 AHD_DV_STATE_INQ_VERIFY);
+			} else if ((targ->flags & AHD_ENHANCED_DV) != 0) {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REBD);
+			} else {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			}
+			break;
+		case SS_RETRY:
+		case SS_TUR:
+			if ((status & SS_ERRMASK) == EBUSY) {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_BUSY);
+				break;
+			}
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			}
+			if (targ->dv_state_retry >= 10) {
+#ifdef AHD_DEBUG
+				if (ahd_debug & AHD_SHOW_DV) {
+					ahd_print_devinfo(ahd, devinfo);
+					printf("DV TUR reties exhausted\n");
+				}
+#endif
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+				break;
+			}
+			if (status & SSQ_DELAY)
+				ssleep(1);
+
+			break;
+		case SS_START:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_SU);
+			break;
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_REBD:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			uint32_t echo_size;
+
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
+			echo_size = scsi_3btoul(&targ->dv_buffer[1]);
+			echo_size &= 0x1FFF;
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("Echo buffer size= %d\n", echo_size);
+			}
+#endif
+			if (echo_size == 0) {
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+				break;
+			}
+
+			/* Generate the buffer pattern */
+			targ->dv_echo_size = echo_size;
+			ahd_linux_generate_dv_pattern(targ);
+			/*
+			 * Setup initial negotiation values.
+			 */
+			ahd_linux_filter_inquiry(ahd, devinfo);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+			if (targ->dv_state_retry <= 10)
+				break;
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("DV REBD reties exhausted\n");
+			}
+#endif
+			/* FALLTHROUGH */
+		case SS_FATAL:
+		default:
+			/*
+			 * Setup initial negotiation values
+			 * and try level 1 DV.
+			 */
+			ahd_linux_filter_inquiry(ahd, devinfo);
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_INQ_VERIFY);
+			targ->dv_echo_size = 0;
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_WEB:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_REB);
+			break;
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			}
+			if (targ->dv_state_retry <= 10)
+				break;
+			/* FALLTHROUGH */
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("DV WEB reties exhausted\n");
+			}
+#endif
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_REB:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			if (memcmp(targ->dv_buffer, targ->dv_buffer1,
+				   targ->dv_echo_size) != 0) {
+				if (ahd_linux_dv_fallback(ahd, devinfo) != 0)
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_EXIT);
+				else
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_WEB);
+				break;
+			}
+			
+			if (targ->dv_buffer != NULL) {
+				free(targ->dv_buffer, M_DEVBUF);
+				targ->dv_buffer = NULL;
+			}
+			if (targ->dv_buffer1 != NULL) {
+				free(targ->dv_buffer1, M_DEVBUF);
+				targ->dv_buffer1 = NULL;
+			}
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahd_linux_dv_fallback(ahd, devinfo) != 0) {
+					AHD_SET_DV_STATE(ahd, targ,
+							 AHD_DV_STATE_EXIT);
+					break;
+				}
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_WEB);
+			}
+			if (targ->dv_state_retry <= 10) {
+				if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0)
+					msleep(ahd->our_id*1000/10);
+				break;
+			}
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_DV) {
+				ahd_print_devinfo(ahd, devinfo);
+				printf("DV REB reties exhausted\n");
+			}
+#endif
+			/* FALLTHROUGH */
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_SU:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHD_DV_STATE_BUSY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		case SS_INQ_REFRESH:
+			AHD_SET_DV_STATE(ahd, targ,
+					 AHD_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHD_SET_DV_STATE(ahd, targ, targ->dv_state);
+			if (ahd_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if (targ->dv_state_retry < 60) {
+				if ((status & SSQ_DELAY) != 0)
+					ssleep(1);
+			} else {
+#ifdef AHD_DEBUG
+				if (ahd_debug & AHD_SHOW_DV) {
+					ahd_print_devinfo(ahd, devinfo);
+					printf("DV BUSY reties exhausted\n");
+				}
+#endif
+				AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			}
+			break;
+		default:
+			AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	default:
+		printf("%s: Invalid DV completion state %d\n", ahd_name(ahd),
+		       targ->dv_state);
+		AHD_SET_DV_STATE(ahd, targ, AHD_DV_STATE_EXIT);
+		break;
+	}
+}
+
+static void
+ahd_linux_dv_fill_cmd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		      struct ahd_devinfo *devinfo)
+{
+	memset(cmd, 0, sizeof(struct scsi_cmnd));
+	cmd->device = ahd->platform_data->dv_scsi_dev;
+	cmd->scsi_done = ahd_linux_dv_complete;
+}
+
+/*
+ * Synthesize an inquiry command.  On the return trip, it'll be
+ * sniffed and the device transfer settings set for us.
+ */
+static void
+ahd_linux_dv_inq(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ,
+		 u_int request_length)
+{
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending INQ\n");
+	}
+#endif
+	if (targ->inq_data == NULL)
+		targ->inq_data = malloc(AHD_LINUX_DV_INQ_LEN,
+					M_DEVBUF, M_WAITOK);
+	if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC) {
+		if (targ->dv_buffer != NULL)
+			free(targ->dv_buffer, M_DEVBUF);
+		targ->dv_buffer = malloc(AHD_LINUX_DV_INQ_LEN,
+					 M_DEVBUF, M_WAITOK);
+	}
+
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = INQUIRY;
+	cmd->cmnd[4] = request_length;
+	cmd->request_bufflen = request_length;
+	if (targ->dv_state > AHD_DV_STATE_INQ_ASYNC)
+		cmd->request_buffer = targ->dv_buffer;
+	else
+		cmd->request_buffer = targ->inq_data;
+	memset(cmd->request_buffer, 0, AHD_LINUX_DV_INQ_LEN);
+}
+
+static void
+ahd_linux_dv_tur(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		 struct ahd_devinfo *devinfo)
+{
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending TUR\n");
+	}
+#endif
+	/* Do a TUR to clear out any non-fatal transitional state */
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = TEST_UNIT_READY;
+}
+
+#define AHD_REBD_LEN 4
+
+static void
+ahd_linux_dv_rebd(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
+{
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending REBD\n");
+	}
+#endif
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	targ->dv_buffer = malloc(AHD_REBD_LEN, M_DEVBUF, M_WAITOK);
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = READ_BUFFER;
+	cmd->cmnd[1] = 0x0b;
+	scsi_ulto3b(AHD_REBD_LEN, &cmd->cmnd[6]);
+	cmd->request_bufflen = AHD_REBD_LEN;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer;
+}
+
+static void
+ahd_linux_dv_web(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
+{
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending WEB\n");
+	}
+#endif
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_WRITE;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = WRITE_BUFFER;
+	cmd->cmnd[1] = 0x0a;
+	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
+	cmd->request_bufflen = targ->dv_echo_size;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer;
+}
+
+static void
+ahd_linux_dv_reb(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		 struct ahd_devinfo *devinfo, struct ahd_linux_target *targ)
+{
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending REB\n");
+	}
+#endif
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = READ_BUFFER;
+	cmd->cmnd[1] = 0x0a;
+	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
+	cmd->request_bufflen = targ->dv_echo_size;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer1;
+}
+
+static void
+ahd_linux_dv_su(struct ahd_softc *ahd, struct scsi_cmnd *cmd,
+		struct ahd_devinfo *devinfo,
+		struct ahd_linux_target *targ)
+{
+	u_int le;
+
+	le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0;
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Sending SU\n");
+	}
+#endif
+	ahd_linux_dv_fill_cmd(ahd, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = START_STOP_UNIT;
+	cmd->cmnd[4] = le | SSS_START;
+}
+
+static int
+ahd_linux_fallback(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	struct	ahd_linux_target *targ;
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_transinfo *goal;
+	struct	ahd_tmode_tstate *tstate;
+	u_int	width;
+	u_int	period;
+	u_int	offset;
+	u_int	ppr_options;
+	u_int	cur_speed;
+	u_int	wide_speed;
+	u_int	narrow_speed;
+	u_int	fallback_speed;
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		ahd_print_devinfo(ahd, devinfo);
+		printf("Trying to fallback\n");
+	}
+#endif
+	targ = ahd->platform_data->targets[devinfo->target_offset];
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	goal = &tinfo->goal;
+	width = goal->width;
+	period = goal->period;
+	offset = goal->offset;
+	ppr_options = goal->ppr_options;
+	if (offset == 0)
+		period = AHD_ASYNC_XFER_PERIOD;
+	if (targ->dv_next_narrow_period == 0)
+		targ->dv_next_narrow_period = MAX(period, AHD_SYNCRATE_ULTRA2);
+	if (targ->dv_next_wide_period == 0)
+		targ->dv_next_wide_period = period;
+	if (targ->dv_max_width == 0)
+		targ->dv_max_width = width;
+	if (targ->dv_max_ppr_options == 0)
+		targ->dv_max_ppr_options = ppr_options;
+	if (targ->dv_last_ppr_options == 0)
+		targ->dv_last_ppr_options = ppr_options;
+
+	cur_speed = aic_calc_speed(width, period, offset, AHD_SYNCRATE_MIN);
+	wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT,
+					  targ->dv_next_wide_period,
+					  MAX_OFFSET, AHD_SYNCRATE_MIN);
+	narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT,
+					    targ->dv_next_narrow_period,
+					    MAX_OFFSET, AHD_SYNCRATE_MIN);
+	fallback_speed = aic_calc_speed(width, period+1, offset,
+					      AHD_SYNCRATE_MIN);
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, "
+		       "fallback_speed= %d\n", cur_speed, wide_speed,
+		       narrow_speed, fallback_speed);
+	}
+#endif
+
+	if (cur_speed > 160000) {
+		/*
+		 * Paced/DT/IU_REQ only transfer speeds.  All we
+		 * can do is fallback in terms of syncrate.
+		 */
+		period++;
+	} else if (cur_speed > 80000) {
+		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+			/*
+			 * Try without IU_REQ as it may be confusing
+			 * an expander.
+			 */
+			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+		} else {
+			/*
+			 * Paced/DT only transfer speeds.  All we
+			 * can do is fallback in terms of syncrate.
+			 */
+			period++;
+			ppr_options = targ->dv_max_ppr_options;
+		}
+	} else if (cur_speed > 3300) {
+
+		/*
+		 * In this range we the following
+		 * options ordered from highest to
+		 * lowest desireability:
+		 *
+		 * o Wide/DT
+		 * o Wide/non-DT
+		 * o Narrow at a potentally higher sync rate.
+		 *
+		 * All modes are tested with and without IU_REQ
+		 * set since using IUs may confuse an expander.
+		 */
+		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+
+			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+		} else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
+			/*
+			 * Try going non-DT.
+			 */
+			ppr_options = targ->dv_max_ppr_options;
+			ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+		} else if (targ->dv_last_ppr_options != 0) {
+			/*
+			 * Try without QAS or any other PPR options.
+			 * We may need a non-PPR message to work with
+			 * an expander.  We look at the "last PPR options"
+			 * so we will perform this fallback even if the
+			 * target responded to our PPR negotiation with
+			 * no option bits set.
+			 */
+			ppr_options = 0;
+		} else if (width == MSG_EXT_WDTR_BUS_16_BIT) {
+			/*
+			 * If the next narrow speed is greater than
+			 * the next wide speed, fallback to narrow.
+			 * Otherwise fallback to the next DT/Wide setting.
+			 * The narrow async speed will always be smaller
+			 * than the wide async speed, so handle this case
+			 * specifically.
+			 */
+			ppr_options = targ->dv_max_ppr_options;
+			if (narrow_speed > fallback_speed
+			 || period >= AHD_ASYNC_XFER_PERIOD) {
+				targ->dv_next_wide_period = period+1;
+				width = MSG_EXT_WDTR_BUS_8_BIT;
+				period = targ->dv_next_narrow_period;
+			} else {
+				period++;
+			}
+		} else if ((ahd->features & AHD_WIDE) != 0
+			&& targ->dv_max_width != 0
+			&& wide_speed >= fallback_speed
+			&& (targ->dv_next_wide_period <= AHD_ASYNC_XFER_PERIOD
+			 || period >= AHD_ASYNC_XFER_PERIOD)) {
+
+			/*
+			 * We are narrow.  Try falling back
+			 * to the next wide speed with 
+			 * all supported ppr options set.
+			 */
+			targ->dv_next_narrow_period = period+1;
+			width = MSG_EXT_WDTR_BUS_16_BIT;
+			period = targ->dv_next_wide_period;
+			ppr_options = targ->dv_max_ppr_options;
+		} else {
+			/* Only narrow fallback is allowed. */
+			period++;
+			ppr_options = targ->dv_max_ppr_options;
+		}
+	} else {
+		return (-1);
+	}
+	offset = MAX_OFFSET;
+	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_PACED);
+	ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, FALSE);
+	if (period == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+		if (width == MSG_EXT_WDTR_BUS_8_BIT)
+			targ->dv_next_narrow_period = AHD_ASYNC_XFER_PERIOD;
+		else
+			targ->dv_next_wide_period = AHD_ASYNC_XFER_PERIOD;
+	}
+	ahd_set_syncrate(ahd, devinfo, period, offset,
+			 ppr_options, AHD_TRANS_GOAL, FALSE);
+	targ->dv_last_ppr_options = ppr_options;
+	return (0);
+}
+
+static void
+ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
+{
+	struct	ahd_softc *ahd;
+	struct	scb *scb;
+	u_long	flags;
+
+	ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
+	ahd_lock(ahd, &flags);
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV) {
+		printf("%s: Timeout while doing DV command %x.\n",
+		       ahd_name(ahd), cmd->cmnd[0]);
+		ahd_dump_card_state(ahd);
+	}
+#endif
+	
+	/*
+	 * Guard against "done race".  No action is
+	 * required if we just completed.
+	 */
+	if ((scb = (struct scb *)cmd->host_scribble) == NULL) {
+		ahd_unlock(ahd, &flags);
+		return;
+	}
+
+	/*
+	 * Command has not completed.  Mark this
+	 * SCB as having failing status prior to
+	 * resetting the bus, so we get the correct
+	 * error code.
+	 */
+	if ((scb->flags & SCB_SENSE) != 0)
+		ahd_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+	else
+		ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
+	ahd_reset_channel(ahd, cmd->device->channel + 'A', /*initiate*/TRUE);
+
+	/*
+	 * Add a minimal bus settle delay for devices that are slow to
+	 * respond after bus resets.
+	 */
+	ahd_freeze_simq(ahd);
+	init_timer(&ahd->platform_data->reset_timer);
+	ahd->platform_data->reset_timer.data = (u_long)ahd;
+	ahd->platform_data->reset_timer.expires = jiffies + HZ / 2;
+	ahd->platform_data->reset_timer.function =
+	    (ahd_linux_callback_t *)ahd_release_simq;
+	add_timer(&ahd->platform_data->reset_timer);
+	if (ahd_linux_next_device_to_run(ahd) != NULL)
+		ahd_schedule_runq(ahd);
+	ahd_linux_run_complete_queue(ahd);
+	ahd_unlock(ahd, &flags);
+}
+
+static void
+ahd_linux_dv_complete(struct scsi_cmnd *cmd)
+{
+	struct ahd_softc *ahd;
+
+	ahd = *((struct ahd_softc **)cmd->device->host->hostdata);
+
+	/* Delete the DV timer before it goes off! */
+	scsi_delete_timer(cmd);
+
+#ifdef AHD_DEBUG
+	if (ahd_debug & AHD_SHOW_DV)
+		printf("%s:%c:%d: Command completed, status= 0x%x\n",
+		       ahd_name(ahd), cmd->device->channel, cmd->device->id,
+		       cmd->result);
+#endif
+
+	/* Wake up the state machine */
+	up(&ahd->platform_data->dv_cmd_sem);
+}
+
+static void
+ahd_linux_generate_dv_pattern(struct ahd_linux_target *targ)
+{
+	uint16_t b;
+	u_int	 i;
+	u_int	 j;
+
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
+	if (targ->dv_buffer1 != NULL)
+		free(targ->dv_buffer1, M_DEVBUF);
+	targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
+
+	i = 0;
+
+	b = 0x0001;
+	for (j = 0 ; i < targ->dv_echo_size; j++) {
+		if (j < 32) {
+			/*
+			 * 32bytes of sequential numbers.
+			 */
+			targ->dv_buffer[i++] = j & 0xff;
+		} else if (j < 48) {
+			/*
+			 * 32bytes of repeating 0x0000, 0xffff.
+			 */
+			targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00;
+		} else if (j < 64) {
+			/*
+			 * 32bytes of repeating 0x5555, 0xaaaa.
+			 */
+			targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55;
+		} else {
+			/*
+			 * Remaining buffer is filled with a repeating
+			 * patter of:
+			 *
+			 *	 0xffff
+			 *	~0x0001 << shifted once in each loop.
+			 */
+			if (j & 0x02) {
+				if (j & 0x01) {
+					targ->dv_buffer[i++] = ~(b >> 8) & 0xff;
+					b <<= 1;
+					if (b == 0x0000)
+						b = 0x0001;
+				} else {
+					targ->dv_buffer[i++] = (~b & 0xff);
+				}
+			} else {
+				targ->dv_buffer[i++] = 0xff;
+			}
+		}
+	}
+}
+
+static u_int
+ahd_linux_user_tagdepth(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	static int warned_user;
+	u_int tags;
+
+	tags = 0;
+	if ((ahd->user_discenable & devinfo->target_mask) != 0) {
+		if (ahd->unit >= NUM_ELEMENTS(aic79xx_tag_info)) {
+
+			if (warned_user == 0) {
+				printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient tag_info instances\n"
+"aic79xx: for installed controllers.  Using defaults\n"
+"aic79xx: Please update the aic79xx_tag_info array in\n"
+"aic79xx: the aic79xx_osm.c source file.\n");
+				warned_user++;
+			}
+			tags = AHD_MAX_QUEUE;
+		} else {
+			adapter_tag_info_t *tag_info;
+
+			tag_info = &aic79xx_tag_info[ahd->unit];
+			tags = tag_info->tag_commands[devinfo->target_offset];
+			if (tags > AHD_MAX_QUEUE)
+				tags = AHD_MAX_QUEUE;
+		}
+	}
+	return (tags);
+}
+
+static u_int
+ahd_linux_user_dv_setting(struct ahd_softc *ahd)
+{
+	static int warned_user;
+	int dv;
+
+	if (ahd->unit >= NUM_ELEMENTS(aic79xx_dv_settings)) {
+
+		if (warned_user == 0) {
+			printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient dv settings instances\n"
+"aic79xx: for installed controllers. Using defaults\n"
+"aic79xx: Please update the aic79xx_dv_settings array in"
+"aic79xx: the aic79xx_osm.c source file.\n");
+			warned_user++;
+		}
+		dv = -1;
+	} else {
+
+		dv = aic79xx_dv_settings[ahd->unit];
+	}
+
+	if (dv < 0) {
+		/*
+		 * Apply the default.
+		 */
+		dv = 1;
+		if (ahd->seep_config != 0)
+			dv = (ahd->seep_config->bios_control & CFENABLEDV);
+	}
+	return (dv);
+}
+
+static void
+ahd_linux_setup_user_rd_strm_settings(struct ahd_softc *ahd)
+{
+	static	int warned_user;
+	u_int	rd_strm_mask;
+	u_int	target_id;
+
+	/*
+	 * If we have specific read streaming info for this controller,
+	 * apply it.  Otherwise use the defaults.
+	 */
+	 if (ahd->unit >= NUM_ELEMENTS(aic79xx_rd_strm_info)) {
+
+		if (warned_user == 0) {
+
+			printf(KERN_WARNING
+"aic79xx: WARNING: Insufficient rd_strm instances\n"
+"aic79xx: for installed controllers. Using defaults\n"
+"aic79xx: Please update the aic79xx_rd_strm_info array\n"
+"aic79xx: in the aic79xx_osm.c source file.\n");
+			warned_user++;
+		}
+		rd_strm_mask = AIC79XX_CONFIGED_RD_STRM;
+	} else {
+
+		rd_strm_mask = aic79xx_rd_strm_info[ahd->unit];
+	}
+	for (target_id = 0; target_id < 16; target_id++) {
+		struct ahd_devinfo devinfo;
+		struct ahd_initiator_tinfo *tinfo;
+		struct ahd_tmode_tstate *tstate;
+
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    target_id, &tstate);
+		ahd_compile_devinfo(&devinfo, ahd->our_id, target_id,
+				    CAM_LUN_WILDCARD, 'A', ROLE_INITIATOR);
+		tinfo->user.ppr_options &= ~MSG_EXT_PPR_RD_STRM;
+		if ((rd_strm_mask & devinfo.target_mask) != 0)
+			tinfo->user.ppr_options |= MSG_EXT_PPR_RD_STRM;
+	}
+}
+
+/*
+ * Determines the queue depth for a given device.
+ */
+static void
+ahd_linux_device_queue_depth(struct ahd_softc *ahd,
+			     struct ahd_linux_device *dev)
+{
+	struct	ahd_devinfo devinfo;
+	u_int	tags;
+
+	ahd_compile_devinfo(&devinfo,
+			    ahd->our_id,
+			    dev->target->target, dev->lun,
+			    dev->target->channel == 0 ? 'A' : 'B',
+			    ROLE_INITIATOR);
+	tags = ahd_linux_user_tagdepth(ahd, &devinfo);
+	if (tags != 0
+	 && dev->scsi_device != NULL
+	 && dev->scsi_device->tagged_supported != 0) {
+
+		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
+		ahd_print_devinfo(ahd, &devinfo);
+		printf("Tagged Queuing enabled.  Depth %d\n", tags);
+	} else {
+		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
+	}
+}
+
+static void
+ahd_linux_run_device_queue(struct ahd_softc *ahd, struct ahd_linux_device *dev)
+{
+	struct	 ahd_cmd *acmd;
+	struct	 scsi_cmnd *cmd;
+	struct	 scb *scb;
+	struct	 hardware_scb *hscb;
+	struct	 ahd_initiator_tinfo *tinfo;
+	struct	 ahd_tmode_tstate *tstate;
+	u_int	 col_idx;
+	uint16_t mask;
+
+	if ((dev->flags & AHD_DEV_ON_RUN_LIST) != 0)
+		panic("running device on run list");
+
+	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
+	    && dev->openings > 0 && dev->qfrozen == 0) {
+
+		/*
+		 * Schedule us to run later.  The only reason we are not
+		 * running is because the whole controller Q is frozen.
+		 */
+		if (ahd->platform_data->qfrozen != 0
+		 && AHD_DV_SIMQ_FROZEN(ahd) == 0) {
+
+			TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
+					  dev, links);
+			dev->flags |= AHD_DEV_ON_RUN_LIST;
+			return;
+		}
+
+		cmd = &acmd_scsi_cmd(acmd);
+
+		/*
+		 * Get an scb to use.
+		 */
+		tinfo = ahd_fetch_transinfo(ahd, 'A', ahd->our_id,
+					    cmd->device->id, &tstate);
+		if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) == 0
+		 || (tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+			col_idx = AHD_NEVER_COL_IDX;
+		} else {
+			col_idx = AHD_BUILD_COL_IDX(cmd->device->id,
+						    cmd->device->lun);
+		}
+		if ((scb = ahd_get_scb(ahd, col_idx)) == NULL) {
+			TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq,
+					 dev, links);
+			dev->flags |= AHD_DEV_ON_RUN_LIST;
+			ahd->flags |= AHD_RESOURCE_SHORTAGE;
+			return;
+		}
+		TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
+		scb->io_ctx = cmd;
+		scb->platform_data->dev = dev;
+		hscb = scb->hscb;
+		cmd->host_scribble = (char *)scb;
+
+		/*
+		 * Fill out basics of the HSCB.
+		 */
+		hscb->control = 0;
+		hscb->scsiid = BUILD_SCSIID(ahd, cmd);
+		hscb->lun = cmd->device->lun;
+		scb->hscb->task_management = 0;
+		mask = SCB_GET_TARGET_MASK(ahd, scb);
+
+		if ((ahd->user_discenable & mask) != 0)
+			hscb->control |= DISCENB;
+
+	 	if (AHD_DV_CMD(cmd) != 0)
+			scb->flags |= SCB_SILENT;
+
+		if ((tinfo->curr.ppr_options & MSG_EXT_PPR_IU_REQ) != 0)
+			scb->flags |= SCB_PACKETIZED;
+
+		if ((tstate->auto_negotiate & mask) != 0) {
+			scb->flags |= SCB_AUTO_NEGOTIATE;
+			scb->hscb->control |= MK_MESSAGE;
+		}
+
+		if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+			int	msg_bytes;
+			uint8_t tag_msgs[2];
+
+			msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
+			if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
+				hscb->control |= tag_msgs[0];
+				if (tag_msgs[0] == MSG_ORDERED_TASK)
+					dev->commands_since_idle_or_otag = 0;
+			} else
+#endif
+			if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
+			 && (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
+				hscb->control |= MSG_ORDERED_TASK;
+				dev->commands_since_idle_or_otag = 0;
+			} else {
+				hscb->control |= MSG_SIMPLE_TASK;
+			}
+		}
+
+		hscb->cdb_len = cmd->cmd_len;
+		memcpy(hscb->shared_data.idata.cdb, cmd->cmnd, hscb->cdb_len);
+
+		scb->sg_count = 0;
+		ahd_set_residual(scb, 0);
+		ahd_set_sense_residual(scb, 0);
+		if (cmd->use_sg != 0) {
+			void	*sg;
+			struct	 scatterlist *cur_seg;
+			u_int	 nseg;
+			int	 dir;
+
+			cur_seg = (struct scatterlist *)cmd->request_buffer;
+			dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+			nseg = pci_map_sg(ahd->dev_softc, cur_seg,
+					  cmd->use_sg, dir);
+			scb->platform_data->xfer_len = 0;
+			for (sg = scb->sg_list; nseg > 0; nseg--, cur_seg++) {
+				dma_addr_t addr;
+				bus_size_t len;
+
+				addr = sg_dma_address(cur_seg);
+				len = sg_dma_len(cur_seg);
+				scb->platform_data->xfer_len += len;
+				sg = ahd_sg_setup(ahd, scb, sg, addr, len,
+						  /*last*/nseg == 1);
+			}
+		} else if (cmd->request_bufflen != 0) {
+			void *sg;
+			dma_addr_t addr;
+			int dir;
+
+			sg = scb->sg_list;
+			dir = scsi_to_pci_dma_dir(cmd->sc_data_direction);
+			addr = pci_map_single(ahd->dev_softc,
+					      cmd->request_buffer,
+					      cmd->request_bufflen, dir);
+			scb->platform_data->xfer_len = cmd->request_bufflen;
+			scb->platform_data->buf_busaddr = addr;
+			sg = ahd_sg_setup(ahd, scb, sg, addr,
+					  cmd->request_bufflen, /*last*/TRUE);
+		}
+
+		LIST_INSERT_HEAD(&ahd->pending_scbs, scb, pending_links);
+		dev->openings--;
+		dev->active++;
+		dev->commands_issued++;
+
+		/* Update the error counting bucket and dump if needed */
+		if (dev->target->cmds_since_error) {
+			dev->target->cmds_since_error++;
+			if (dev->target->cmds_since_error >
+			    AHD_LINUX_ERR_THRESH)
+				dev->target->cmds_since_error = 0;
+		}
+
+		if ((dev->flags & AHD_DEV_PERIODIC_OTAG) != 0)
+			dev->commands_since_idle_or_otag++;
+		scb->flags |= SCB_ACTIVE;
+		ahd_queue_scb(ahd, scb);
+	}
+}
+
+/*
+ * SCSI controller interrupt handler.
+ */
+irqreturn_t
+ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct	ahd_softc *ahd;
+	u_long	flags;
+	int	ours;
+
+	ahd = (struct ahd_softc *) dev_id;
+	ahd_lock(ahd, &flags); 
+	ours = ahd_intr(ahd);
+	if (ahd_linux_next_device_to_run(ahd) != NULL)
+		ahd_schedule_runq(ahd);
+	ahd_linux_run_complete_queue(ahd);
+	ahd_unlock(ahd, &flags);
+	return IRQ_RETVAL(ours);
+}
+
+void
+ahd_platform_flushwork(struct ahd_softc *ahd)
+{
+
+	while (ahd_linux_run_complete_queue(ahd) != NULL)
+		;
+}
+
+static struct ahd_linux_target*
+ahd_linux_alloc_target(struct ahd_softc *ahd, u_int channel, u_int target)
+{
+	struct ahd_linux_target *targ;
+
+	targ = malloc(sizeof(*targ), M_DEVBUF, M_NOWAIT);
+	if (targ == NULL)
+		return (NULL);
+	memset(targ, 0, sizeof(*targ));
+	targ->channel = channel;
+	targ->target = target;
+	targ->ahd = ahd;
+	targ->flags = AHD_DV_REQUIRED;
+	ahd->platform_data->targets[target] = targ;
+	return (targ);
+}
+
+static void
+ahd_linux_free_target(struct ahd_softc *ahd, struct ahd_linux_target *targ)
+{
+	struct ahd_devinfo devinfo;
+	struct ahd_initiator_tinfo *tinfo;
+	struct ahd_tmode_tstate *tstate;
+	u_int our_id;
+	u_int target_offset;
+	char channel;
+
+	/*
+	 * Force a negotiation to async/narrow on any
+	 * future command to this device unless a bus
+	 * reset occurs between now and that command.
+	 */
+	channel = 'A' + targ->channel;
+	our_id = ahd->our_id;
+	target_offset = targ->target;
+	tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
+				    targ->target, &tstate);
+	ahd_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD,
+			    channel, ROLE_INITIATOR);
+	ahd_set_syncrate(ahd, &devinfo, 0, 0, 0,
+			 AHD_TRANS_GOAL, /*paused*/FALSE);
+	ahd_set_width(ahd, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+		      AHD_TRANS_GOAL, /*paused*/FALSE);
+	ahd_update_neg_request(ahd, &devinfo, tstate, tinfo, AHD_NEG_ALWAYS);
+ 	ahd->platform_data->targets[target_offset] = NULL;
+	if (targ->inq_data != NULL)
+		free(targ->inq_data, M_DEVBUF);
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	if (targ->dv_buffer1 != NULL)
+		free(targ->dv_buffer1, M_DEVBUF);
+	free(targ, M_DEVBUF);
+}
+
+static struct ahd_linux_device*
+ahd_linux_alloc_device(struct ahd_softc *ahd,
+		 struct ahd_linux_target *targ, u_int lun)
+{
+	struct ahd_linux_device *dev;
+
+	dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
+	if (dev == NULL)
+		return (NULL);
+	memset(dev, 0, sizeof(*dev));
+	init_timer(&dev->timer);
+	TAILQ_INIT(&dev->busyq);
+	dev->flags = AHD_DEV_UNCONFIGURED;
+	dev->lun = lun;
+	dev->target = targ;
+
+	/*
+	 * We start out life using untagged
+	 * transactions of which we allow one.
+	 */
+	dev->openings = 1;
+
+	/*
+	 * Set maxtags to 0.  This will be changed if we
+	 * later determine that we are dealing with
+	 * a tagged queuing capable device.
+	 */
+	dev->maxtags = 0;
+	
+	targ->refcount++;
+	targ->devices[lun] = dev;
+	return (dev);
+}
+
+static void
+ahd_linux_free_device(struct ahd_softc *ahd, struct ahd_linux_device *dev)
+{
+	struct ahd_linux_target *targ;
+
+	del_timer(&dev->timer);
+	targ = dev->target;
+	targ->devices[dev->lun] = NULL;
+	free(dev, M_DEVBUF);
+	targ->refcount--;
+	if (targ->refcount == 0
+	 && (targ->flags & AHD_DV_REQUIRED) == 0)
+		ahd_linux_free_target(ahd, targ);
+}
+
+void
+ahd_send_async(struct ahd_softc *ahd, char channel,
+	       u_int target, u_int lun, ac_code code, void *arg)
+{
+	switch (code) {
+	case AC_TRANSFER_NEG:
+	{
+		char	buf[80];
+		struct	ahd_linux_target *targ;
+		struct	info_str info;
+		struct	ahd_initiator_tinfo *tinfo;
+		struct	ahd_tmode_tstate *tstate;
+
+		info.buffer = buf;
+		info.length = sizeof(buf);
+		info.offset = 0;
+		info.pos = 0;
+		tinfo = ahd_fetch_transinfo(ahd, channel, ahd->our_id,
+					    target, &tstate);
+
+		/*
+		 * Don't bother reporting results while
+		 * negotiations are still pending.
+		 */
+		if (tinfo->curr.period != tinfo->goal.period
+		 || tinfo->curr.width != tinfo->goal.width
+		 || tinfo->curr.offset != tinfo->goal.offset
+		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		/*
+		 * Don't bother reporting results that
+		 * are identical to those last reported.
+		 */
+		targ = ahd->platform_data->targets[target];
+		if (targ == NULL)
+			break;
+		if (tinfo->curr.period == targ->last_tinfo.period
+		 && tinfo->curr.width == targ->last_tinfo.width
+		 && tinfo->curr.offset == targ->last_tinfo.offset
+		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		targ->last_tinfo.period = tinfo->curr.period;
+		targ->last_tinfo.width = tinfo->curr.width;
+		targ->last_tinfo.offset = tinfo->curr.offset;
+		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
+
+		printf("(%s:%c:", ahd_name(ahd), channel);
+		if (target == CAM_TARGET_WILDCARD)
+			printf("*): ");
+		else
+			printf("%d): ", target);
+		ahd_format_transinfo(&info, &tinfo->curr);
+		if (info.pos < info.length)
+			*info.buffer = '\0';
+		else
+			buf[info.length - 1] = '\0';
+		printf("%s", buf);
+		break;
+	}
+        case AC_SENT_BDR:
+	{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		WARN_ON(lun != CAM_LUN_WILDCARD);
+		scsi_report_device_reset(ahd->platform_data->host,
+					 channel - 'A', target);
+#else
+		Scsi_Device *scsi_dev;
+
+		/*
+		 * Find the SCSI device associated with this
+		 * request and indicate that a UA is expected.
+		 */
+		for (scsi_dev = ahd->platform_data->host->host_queue;
+		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
+			if (channel - 'A' == scsi_dev->channel
+			 && target == scsi_dev->id
+			 && (lun == CAM_LUN_WILDCARD
+			  || lun == scsi_dev->lun)) {
+				scsi_dev->was_reset = 1;
+				scsi_dev->expecting_cc_ua = 1;
+			}
+		}
+#endif
+		break;
+	}
+        case AC_BUS_RESET:
+		if (ahd->platform_data->host != NULL) {
+			scsi_report_bus_reset(ahd->platform_data->host,
+					      channel - 'A');
+		}
+                break;
+        default:
+                panic("ahd_send_async: Unexpected async event");
+        }
+}
+
+/*
+ * Calls the higher level scsi done function and frees the scb.
+ */
+void
+ahd_done(struct ahd_softc *ahd, struct scb *scb)
+{
+	Scsi_Cmnd *cmd;
+	struct	  ahd_linux_device *dev;
+
+	if ((scb->flags & SCB_ACTIVE) == 0) {
+		printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
+		ahd_dump_card_state(ahd);
+		panic("Stopping for safety");
+	}
+	LIST_REMOVE(scb, pending_links);
+	cmd = scb->io_ctx;
+	dev = scb->platform_data->dev;
+	dev->active--;
+	dev->openings++;
+	if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) {
+		cmd->result &= ~(CAM_DEV_QFRZN << 16);
+		dev->qfrozen--;
+	}
+	ahd_linux_unmap_scb(ahd, scb);
+
+	/*
+	 * Guard against stale sense data.
+	 * The Linux mid-layer assumes that sense
+	 * was retrieved anytime the first byte of
+	 * the sense buffer looks "sane".
+	 */
+	cmd->sense_buffer[0] = 0;
+	if (ahd_get_transaction_status(scb) == CAM_REQ_INPROG) {
+		uint32_t amount_xferred;
+
+		amount_xferred =
+		    ahd_get_transfer_length(scb) - ahd_get_residual(scb);
+		if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) {
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_MISC) != 0) {
+				ahd_print_path(ahd, scb);
+				printf("Set CAM_UNCOR_PARITY\n");
+			}
+#endif
+			ahd_set_transaction_status(scb, CAM_UNCOR_PARITY);
+#ifdef AHD_REPORT_UNDERFLOWS
+		/*
+		 * This code is disabled by default as some
+		 * clients of the SCSI system do not properly
+		 * initialize the underflow parameter.  This
+		 * results in spurious termination of commands
+		 * that complete as expected (e.g. underflow is
+		 * allowed as command can return variable amounts
+		 * of data.
+		 */
+		} else if (amount_xferred < scb->io_ctx->underflow) {
+			u_int i;
+
+			ahd_print_path(ahd, scb);
+			printf("CDB:");
+			for (i = 0; i < scb->io_ctx->cmd_len; i++)
+				printf(" 0x%x", scb->io_ctx->cmnd[i]);
+			printf("\n");
+			ahd_print_path(ahd, scb);
+			printf("Saw underflow (%ld of %ld bytes). "
+			       "Treated as error\n",
+				ahd_get_residual(scb),
+				ahd_get_transfer_length(scb));
+			ahd_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+#endif
+		} else {
+			ahd_set_transaction_status(scb, CAM_REQ_CMP);
+		}
+	} else if (ahd_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
+		ahd_linux_handle_scsi_status(ahd, dev, scb);
+	} else if (ahd_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
+		dev->flags |= AHD_DEV_UNCONFIGURED;
+		if (AHD_DV_CMD(cmd) == FALSE)
+			dev->target->flags &= ~AHD_DV_REQUIRED;
+	}
+	/*
+	 * Start DV for devices that require it assuming the first command
+	 * sent does not result in a selection timeout.
+	 */
+	if (ahd_get_transaction_status(scb) != CAM_SEL_TIMEOUT
+	 && (dev->target->flags & AHD_DV_REQUIRED) != 0)
+		ahd_linux_start_dv(ahd);
+
+	if (dev->openings == 1
+	 && ahd_get_transaction_status(scb) == CAM_REQ_CMP
+	 && ahd_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
+		dev->tag_success_count++;
+	/*
+	 * Some devices deal with temporary internal resource
+	 * shortages by returning queue full.  When the queue
+	 * full occurrs, we throttle back.  Slowly try to get
+	 * back to our previous queue depth.
+	 */
+	if ((dev->openings + dev->active) < dev->maxtags
+	 && dev->tag_success_count > AHD_TAG_SUCCESS_INTERVAL) {
+		dev->tag_success_count = 0;
+		dev->openings++;
+	}
+
+	if (dev->active == 0)
+		dev->commands_since_idle_or_otag = 0;
+
+	if (TAILQ_EMPTY(&dev->busyq)) {
+		if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
+		 && dev->active == 0
+		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
+			ahd_linux_free_device(ahd, dev);
+	} else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
+		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
+		dev->flags |= AHD_DEV_ON_RUN_LIST;
+	}
+
+	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
+		printf("Recovery SCB completes\n");
+		if (ahd_get_transaction_status(scb) == CAM_BDR_SENT
+		 || ahd_get_transaction_status(scb) == CAM_REQ_ABORTED)
+			ahd_set_transaction_status(scb, CAM_CMD_TIMEOUT);
+		if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+			scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
+			up(&ahd->platform_data->eh_sem);
+		}
+	}
+
+	ahd_free_scb(ahd, scb);
+	ahd_linux_queue_cmd_complete(ahd, cmd);
+
+	if ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_EMPTY) != 0
+	 && LIST_FIRST(&ahd->pending_scbs) == NULL) {
+		ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_EMPTY;
+		up(&ahd->platform_data->dv_sem);
+	}
+}
+
+static void
+ahd_linux_handle_scsi_status(struct ahd_softc *ahd,
+			     struct ahd_linux_device *dev, struct scb *scb)
+{
+	struct	ahd_devinfo devinfo;
+
+	ahd_compile_devinfo(&devinfo,
+			    ahd->our_id,
+			    dev->target->target, dev->lun,
+			    dev->target->channel == 0 ? 'A' : 'B',
+			    ROLE_INITIATOR);
+	
+	/*
+	 * We don't currently trust the mid-layer to
+	 * properly deal with queue full or busy.  So,
+	 * when one occurs, we tell the mid-layer to
+	 * unconditionally requeue the command to us
+	 * so that we can retry it ourselves.  We also
+	 * implement our own throttling mechanism so
+	 * we don't clobber the device with too many
+	 * commands.
+	 */
+	switch (ahd_get_scsi_status(scb)) {
+	default:
+		break;
+	case SCSI_STATUS_CHECK_COND:
+	case SCSI_STATUS_CMD_TERMINATED:
+	{
+		Scsi_Cmnd *cmd;
+
+		/*
+		 * Copy sense information to the OS's cmd
+		 * structure if it is available.
+		 */
+		cmd = scb->io_ctx;
+		if ((scb->flags & (SCB_SENSE|SCB_PKT_SENSE)) != 0) {
+			struct scsi_status_iu_header *siu;
+			u_int sense_size;
+			u_int sense_offset;
+
+			if (scb->flags & SCB_SENSE) {
+				sense_size = MIN(sizeof(struct scsi_sense_data)
+					       - ahd_get_sense_residual(scb),
+						 sizeof(cmd->sense_buffer));
+				sense_offset = 0;
+			} else {
+				/*
+				 * Copy only the sense data into the provided
+				 * buffer.
+				 */
+				siu = (struct scsi_status_iu_header *)
+				    scb->sense_data;
+				sense_size = MIN(scsi_4btoul(siu->sense_length),
+						sizeof(cmd->sense_buffer));
+				sense_offset = SIU_SENSE_OFFSET(siu);
+			}
+
+			memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+			memcpy(cmd->sense_buffer,
+			       ahd_get_sense_buf(ahd, scb)
+			       + sense_offset, sense_size);
+			cmd->result |= (DRIVER_SENSE << 24);
+
+#ifdef AHD_DEBUG
+			if (ahd_debug & AHD_SHOW_SENSE) {
+				int i;
+
+				printf("Copied %d bytes of sense data at %d:",
+				       sense_size, sense_offset);
+				for (i = 0; i < sense_size; i++) {
+					if ((i & 0xF) == 0)
+						printf("\n");
+					printf("0x%x ", cmd->sense_buffer[i]);
+				}
+				printf("\n");
+			}
+#endif
+		}
+		break;
+	}
+	case SCSI_STATUS_QUEUE_FULL:
+	{
+		/*
+		 * By the time the core driver has returned this
+		 * command, all other commands that were queued
+		 * to us but not the device have been returned.
+		 * This ensures that dev->active is equal to
+		 * the number of commands actually queued to
+		 * the device.
+		 */
+		dev->tag_success_count = 0;
+		if (dev->active != 0) {
+			/*
+			 * Drop our opening count to the number
+			 * of commands currently outstanding.
+			 */
+			dev->openings = 0;
+#ifdef AHD_DEBUG
+			if ((ahd_debug & AHD_SHOW_QFULL) != 0) {
+				ahd_print_path(ahd, scb);
+				printf("Dropping tag count to %d\n",
+				       dev->active);
+			}
+#endif
+			if (dev->active == dev->tags_on_last_queuefull) {
+
+				dev->last_queuefull_same_count++;
+				/*
+				 * If we repeatedly see a queue full
+				 * at the same queue depth, this
+				 * device has a fixed number of tag
+				 * slots.  Lock in this tag depth
+				 * so we stop seeing queue fulls from
+				 * this device.
+				 */
+				if (dev->last_queuefull_same_count
+				 == AHD_LOCK_TAGS_COUNT) {
+					dev->maxtags = dev->active;
+					ahd_print_path(ahd, scb);
+					printf("Locking max tag count at %d\n",
+					       dev->active);
+				}
+			} else {
+				dev->tags_on_last_queuefull = dev->active;
+				dev->last_queuefull_same_count = 0;
+			}
+			ahd_set_transaction_status(scb, CAM_REQUEUE_REQ);
+			ahd_set_scsi_status(scb, SCSI_STATUS_OK);
+			ahd_platform_set_tags(ahd, &devinfo,
+				     (dev->flags & AHD_DEV_Q_BASIC)
+				   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
+			break;
+		}
+		/*
+		 * Drop down to a single opening, and treat this
+		 * as if the target returned BUSY SCSI status.
+		 */
+		dev->openings = 1;
+		ahd_platform_set_tags(ahd, &devinfo,
+			     (dev->flags & AHD_DEV_Q_BASIC)
+			   ? AHD_QUEUE_BASIC : AHD_QUEUE_TAGGED);
+		ahd_set_scsi_status(scb, SCSI_STATUS_BUSY);
+		/* FALLTHROUGH */
+	}
+	case SCSI_STATUS_BUSY:
+		/*
+		 * Set a short timer to defer sending commands for
+		 * a bit since Linux will not delay in this case.
+		 */
+		if ((dev->flags & AHD_DEV_TIMER_ACTIVE) != 0) {
+			printf("%s:%c:%d: Device Timer still active during "
+			       "busy processing\n", ahd_name(ahd),
+				dev->target->channel, dev->target->target);
+			break;
+		}
+		dev->flags |= AHD_DEV_TIMER_ACTIVE;
+		dev->qfrozen++;
+		init_timer(&dev->timer);
+		dev->timer.data = (u_long)dev;
+		dev->timer.expires = jiffies + (HZ/2);
+		dev->timer.function = ahd_linux_dev_timed_unfreeze;
+		add_timer(&dev->timer);
+		break;
+	}
+}
+
+static void
+ahd_linux_queue_cmd_complete(struct ahd_softc *ahd, Scsi_Cmnd *cmd)
+{
+	/*
+	 * Typically, the complete queue has very few entries
+	 * queued to it before the queue is emptied by
+	 * ahd_linux_run_complete_queue, so sorting the entries
+	 * by generation number should be inexpensive.
+	 * We perform the sort so that commands that complete
+	 * with an error are retuned in the order origionally
+	 * queued to the controller so that any subsequent retries
+	 * are performed in order.  The underlying ahd routines do
+	 * not guarantee the order that aborted commands will be
+	 * returned to us.
+	 */
+	struct ahd_completeq *completeq;
+	struct ahd_cmd *list_cmd;
+	struct ahd_cmd *acmd;
+
+	/*
+	 * Map CAM error codes into Linux Error codes.  We
+	 * avoid the conversion so that the DV code has the
+	 * full error information available when making
+	 * state change decisions.
+	 */
+	if (AHD_DV_CMD(cmd) == FALSE) {
+		uint32_t status;
+		u_int new_status;
+
+		status = ahd_cmd_get_transaction_status(cmd);
+		if (status != CAM_REQ_CMP) {
+			struct ahd_linux_device *dev;
+			struct ahd_devinfo devinfo;
+			cam_status cam_status;
+			uint32_t action;
+			u_int scsi_status;
+
+			dev = ahd_linux_get_device(ahd, cmd->device->channel,
+						   cmd->device->id,
+						   cmd->device->lun,
+						   /*alloc*/FALSE);
+
+			if (dev == NULL)
+				goto no_fallback;
+
+			ahd_compile_devinfo(&devinfo,
+					    ahd->our_id,
+					    dev->target->target, dev->lun,
+					    dev->target->channel == 0 ? 'A':'B',
+					    ROLE_INITIATOR);
+
+			scsi_status = ahd_cmd_get_scsi_status(cmd);
+			cam_status = ahd_cmd_get_transaction_status(cmd);
+			action = aic_error_action(cmd, dev->target->inq_data,
+						  cam_status, scsi_status);
+			if ((action & SSQ_FALLBACK) != 0) {
+
+				/* Update stats */
+				dev->target->errors_detected++;
+				if (dev->target->cmds_since_error == 0)
+					dev->target->cmds_since_error++;
+				else {
+					dev->target->cmds_since_error = 0;
+					ahd_linux_fallback(ahd, &devinfo);
+				}
+			}
+		}
+no_fallback:
+		switch (status) {
+		case CAM_REQ_INPROG:
+		case CAM_REQ_CMP:
+		case CAM_SCSI_STATUS_ERROR:
+			new_status = DID_OK;
+			break;
+		case CAM_REQ_ABORTED:
+			new_status = DID_ABORT;
+			break;
+		case CAM_BUSY:
+			new_status = DID_BUS_BUSY;
+			break;
+		case CAM_REQ_INVALID:
+		case CAM_PATH_INVALID:
+			new_status = DID_BAD_TARGET;
+			break;
+		case CAM_SEL_TIMEOUT:
+			new_status = DID_NO_CONNECT;
+			break;
+		case CAM_SCSI_BUS_RESET:
+		case CAM_BDR_SENT:
+			new_status = DID_RESET;
+			break;
+		case CAM_UNCOR_PARITY:
+			new_status = DID_PARITY;
+			break;
+		case CAM_CMD_TIMEOUT:
+			new_status = DID_TIME_OUT;
+			break;
+		case CAM_UA_ABORT:
+		case CAM_REQ_CMP_ERR:
+		case CAM_AUTOSENSE_FAIL:
+		case CAM_NO_HBA:
+		case CAM_DATA_RUN_ERR:
+		case CAM_UNEXP_BUSFREE:
+		case CAM_SEQUENCE_FAIL:
+		case CAM_CCB_LEN_ERR:
+		case CAM_PROVIDE_FAIL:
+		case CAM_REQ_TERMIO:
+		case CAM_UNREC_HBA_ERROR:
+		case CAM_REQ_TOO_BIG:
+			new_status = DID_ERROR;
+			break;
+		case CAM_REQUEUE_REQ:
+			/*
+			 * If we want the request requeued, make sure there
+			 * are sufficent retries.  In the old scsi error code,
+			 * we used to be able to specify a result code that
+			 * bypassed the retry count.  Now we must use this
+			 * hack.  We also "fake" a check condition with
+			 * a sense code of ABORTED COMMAND.  This seems to
+			 * evoke a retry even if this command is being sent
+			 * via the eh thread.  Ick!  Ick!  Ick!
+			 */
+			if (cmd->retries > 0)
+				cmd->retries--;
+			new_status = DID_OK;
+			ahd_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND);
+			cmd->result |= (DRIVER_SENSE << 24);
+			memset(cmd->sense_buffer, 0,
+			       sizeof(cmd->sense_buffer));
+			cmd->sense_buffer[0] = SSD_ERRCODE_VALID
+					     | SSD_CURRENT_ERROR;
+			cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND;
+			break;
+		default:
+			/* We should never get here */
+			new_status = DID_ERROR;
+			break;
+		}
+
+		ahd_cmd_set_transaction_status(cmd, new_status);
+	}
+
+	completeq = &ahd->platform_data->completeq;
+	list_cmd = TAILQ_FIRST(completeq);
+	acmd = (struct ahd_cmd *)cmd;
+	while (list_cmd != NULL
+	    && acmd_scsi_cmd(list_cmd).serial_number
+	     < acmd_scsi_cmd(acmd).serial_number)
+		list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
+	if (list_cmd != NULL)
+		TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
+	else
+		TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
+}
+
+static void
+ahd_linux_filter_inquiry(struct ahd_softc *ahd, struct ahd_devinfo *devinfo)
+{
+	struct	scsi_inquiry_data *sid;
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_transinfo *user;
+	struct	ahd_transinfo *goal;
+	struct	ahd_transinfo *curr;
+	struct	ahd_tmode_tstate *tstate;
+	struct	ahd_linux_device *dev;
+	u_int	width;
+	u_int	period;
+	u_int	offset;
+	u_int	ppr_options;
+	u_int	trans_version;
+	u_int	prot_version;
+
+	/*
+	 * Determine if this lun actually exists.  If so,
+	 * hold on to its corresponding device structure.
+	 * If not, make sure we release the device and
+	 * don't bother processing the rest of this inquiry
+	 * command.
+	 */
+	dev = ahd_linux_get_device(ahd, devinfo->channel - 'A',
+				   devinfo->target, devinfo->lun,
+				   /*alloc*/TRUE);
+
+	sid = (struct scsi_inquiry_data *)dev->target->inq_data;
+	if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
+
+		dev->flags &= ~AHD_DEV_UNCONFIGURED;
+	} else {
+		dev->flags |= AHD_DEV_UNCONFIGURED;
+		return;
+	}
+
+	/*
+	 * Update our notion of this device's transfer
+	 * negotiation capabilities.
+	 */
+	tinfo = ahd_fetch_transinfo(ahd, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	user = &tinfo->user;
+	goal = &tinfo->goal;
+	curr = &tinfo->curr;
+	width = user->width;
+	period = user->period;
+	offset = user->offset;
+	ppr_options = user->ppr_options;
+	trans_version = user->transport_version;
+	prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
+
+	/*
+	 * Only attempt SPI3/4 once we've verified that
+	 * the device claims to support SPI3/4 features.
+	 */
+	if (prot_version < SCSI_REV_2)
+		trans_version = SID_ANSI_REV(sid);
+	else
+		trans_version = SCSI_REV_2;
+
+	if ((sid->flags & SID_WBus16) == 0)
+		width = MSG_EXT_WDTR_BUS_8_BIT;
+	if ((sid->flags & SID_Sync) == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+	}
+	if ((sid->spi3data & SID_SPI_QAS) == 0)
+		ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
+	if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
+		ppr_options &= MSG_EXT_PPR_QAS_REQ;
+	if ((sid->spi3data & SID_SPI_IUS) == 0)
+		ppr_options &= (MSG_EXT_PPR_DT_REQ
+			      | MSG_EXT_PPR_QAS_REQ);
+
+	if (prot_version > SCSI_REV_2
+	 && ppr_options != 0)
+		trans_version = user->transport_version;
+
+	ahd_validate_width(ahd, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN);
+	ahd_find_syncrate(ahd, &period, &ppr_options, AHD_SYNCRATE_MAX);
+	ahd_validate_offset(ahd, /*tinfo limit*/NULL, period,
+			    &offset, width, ROLE_UNKNOWN);
+	if (offset == 0 || period == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+	}
+	/* Apply our filtered user settings. */
+	curr->transport_version = trans_version;
+	curr->protocol_version = prot_version;
+	ahd_set_width(ahd, devinfo, width, AHD_TRANS_GOAL, /*paused*/FALSE);
+	ahd_set_syncrate(ahd, devinfo, period, offset, ppr_options,
+			 AHD_TRANS_GOAL, /*paused*/FALSE);
+}
+
+void
+ahd_freeze_simq(struct ahd_softc *ahd)
+{
+	ahd->platform_data->qfrozen++;
+	if (ahd->platform_data->qfrozen == 1) {
+		scsi_block_requests(ahd->platform_data->host);
+		ahd_platform_abort_scbs(ahd, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+					CAM_LUN_WILDCARD, SCB_LIST_NULL,
+					ROLE_INITIATOR, CAM_REQUEUE_REQ);
+	}
+}
+
+void
+ahd_release_simq(struct ahd_softc *ahd)
+{
+	u_long s;
+	int    unblock_reqs;
+
+	unblock_reqs = 0;
+	ahd_lock(ahd, &s);
+	if (ahd->platform_data->qfrozen > 0)
+		ahd->platform_data->qfrozen--;
+	if (ahd->platform_data->qfrozen == 0) {
+		unblock_reqs = 1;
+	}
+	if (AHD_DV_SIMQ_FROZEN(ahd)
+	 && ((ahd->platform_data->flags & AHD_DV_WAIT_SIMQ_RELEASE) != 0)) {
+		ahd->platform_data->flags &= ~AHD_DV_WAIT_SIMQ_RELEASE;
+		up(&ahd->platform_data->dv_sem);
+	}
+	ahd_schedule_runq(ahd);
+	ahd_unlock(ahd, &s);
+	/*
+	 * There is still a race here.  The mid-layer
+	 * should keep its own freeze count and use
+	 * a bottom half handler to run the queues
+	 * so we can unblock with our own lock held.
+	 */
+	if (unblock_reqs)
+		scsi_unblock_requests(ahd->platform_data->host);
+}
+
+static void
+ahd_linux_sem_timeout(u_long arg)
+{
+	struct	scb *scb;
+	struct	ahd_softc *ahd;
+	u_long	s;
+
+	scb = (struct scb *)arg;
+	ahd = scb->ahd_softc;
+	ahd_lock(ahd, &s);
+	if ((scb->platform_data->flags & AHD_SCB_UP_EH_SEM) != 0) {
+		scb->platform_data->flags &= ~AHD_SCB_UP_EH_SEM;
+		up(&ahd->platform_data->eh_sem);
+	}
+	ahd_unlock(ahd, &s);
+}
+
+static void
+ahd_linux_dev_timed_unfreeze(u_long arg)
+{
+	struct ahd_linux_device *dev;
+	struct ahd_softc *ahd;
+	u_long s;
+
+	dev = (struct ahd_linux_device *)arg;
+	ahd = dev->target->ahd;
+	ahd_lock(ahd, &s);
+	dev->flags &= ~AHD_DEV_TIMER_ACTIVE;
+	if (dev->qfrozen > 0)
+		dev->qfrozen--;
+	if (dev->qfrozen == 0
+	 && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0)
+		ahd_linux_run_device_queue(ahd, dev);
+	if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
+	 && dev->active == 0)
+		ahd_linux_free_device(ahd, dev);
+	ahd_unlock(ahd, &s);
+}
+
+void
+ahd_platform_dump_card_state(struct ahd_softc *ahd)
+{
+	struct ahd_linux_device *dev;
+	int target;
+	int maxtarget;
+	int lun;
+	int i;
+
+	maxtarget = (ahd->features & AHD_WIDE) ? 15 : 7;
+	for (target = 0; target <=maxtarget; target++) {
+
+		for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
+			struct ahd_cmd *acmd;
+
+			dev = ahd_linux_get_device(ahd, 0, target,
+						   lun, /*alloc*/FALSE);
+			if (dev == NULL)
+				continue;
+
+			printf("DevQ(%d:%d:%d): ", 0, target, lun);
+			i = 0;
+			TAILQ_FOREACH(acmd, &dev->busyq, acmd_links.tqe) {
+				if (i++ > AHD_SCB_MAX)
+					break;
+			}
+			printf("%d waiting\n", i);
+		}
+	}
+}
+
+static int __init
+ahd_linux_init(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	return ahd_linux_detect(&aic79xx_driver_template);
+#else
+	scsi_register_module(MODULE_SCSI_HA, &aic79xx_driver_template);
+	if (aic79xx_driver_template.present == 0) {
+		scsi_unregister_module(MODULE_SCSI_HA,
+				       &aic79xx_driver_template);
+		return (-ENODEV);
+	}
+
+	return (0);
+#endif
+}
+
+static void __exit
+ahd_linux_exit(void)
+{
+	struct ahd_softc *ahd;
+
+	/*
+	 * Shutdown DV threads before going into the SCSI mid-layer.
+	 * This avoids situations where the mid-layer locks the entire
+	 * kernel so that waiting for our DV threads to exit leads
+	 * to deadlock.
+	 */
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+
+		ahd_linux_kill_dv_thread(ahd);
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * In 2.4 we have to unregister from the PCI core _after_
+	 * unregistering from the scsi midlayer to avoid dangling
+	 * references.
+	 */
+	scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
+#endif
+	ahd_linux_pci_exit();
+}
+
+module_init(ahd_linux_init);
+module_exit(ahd_linux_exit);
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
new file mode 100644
index 0000000..605f92b
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h
@@ -0,0 +1,1147 @@
+/*
+ * Adaptec AIC79xx device driver for Linux.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#137 $
+ *
+ */
+#ifndef _AIC79XX_LINUX_H_
+#define _AIC79XX_LINUX_H_
+
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <linux/interrupt.h> /* For tasklet support. */
+#include <linux/config.h>
+#include <linux/slab.h>
+
+/* Core SCSI definitions */
+#define AIC_LIB_PREFIX ahd
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+/* Name space conflict with BSD queue macros */
+#ifdef LIST_HEAD
+#undef LIST_HEAD
+#endif
+
+#include "cam.h"
+#include "queue.h"
+#include "scsi_message.h"
+#include "scsi_iu.h"
+#include "aiclib.h"
+
+/*********************************** Debugging ********************************/
+#ifdef CONFIG_AIC79XX_DEBUG_ENABLE
+#ifdef CONFIG_AIC79XX_DEBUG_MASK
+#define AHD_DEBUG 1
+#define AHD_DEBUG_OPTS CONFIG_AIC79XX_DEBUG_MASK
+#else
+/*
+ * Compile in debugging code, but do not enable any printfs.
+ */
+#define AHD_DEBUG 1
+#define AHD_DEBUG_OPTS 0
+#endif
+/* No debugging code. */
+#endif
+
+/********************************** Misc Macros *******************************/
+#define	roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
+#define	powerof2(x)	((((x)-1)&(x))==0)
+
+/************************* Forward Declarations *******************************/
+struct ahd_softc;
+typedef struct pci_dev *ahd_dev_softc_t;
+typedef Scsi_Cmnd      *ahd_io_ctx_t;
+
+/******************************* Byte Order ***********************************/
+#define ahd_htobe16(x)	cpu_to_be16(x)
+#define ahd_htobe32(x)	cpu_to_be32(x)
+#define ahd_htobe64(x)	cpu_to_be64(x)
+#define ahd_htole16(x)	cpu_to_le16(x)
+#define ahd_htole32(x)	cpu_to_le32(x)
+#define ahd_htole64(x)	cpu_to_le64(x)
+
+#define ahd_be16toh(x)	be16_to_cpu(x)
+#define ahd_be32toh(x)	be32_to_cpu(x)
+#define ahd_be64toh(x)	be64_to_cpu(x)
+#define ahd_le16toh(x)	le16_to_cpu(x)
+#define ahd_le32toh(x)	le32_to_cpu(x)
+#define ahd_le64toh(x)	le64_to_cpu(x)
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#ifndef BYTE_ORDER
+#if defined(__BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#if defined(__LITTLE_ENDIAN)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+/************************* Configuration Data *********************************/
+extern uint32_t aic79xx_allow_memio;
+extern int aic79xx_detect_complete;
+extern Scsi_Host_Template aic79xx_driver_template;
+
+/***************************** Bus Space/DMA **********************************/
+
+typedef uint32_t bus_size_t;
+
+typedef enum {
+	BUS_SPACE_MEMIO,
+	BUS_SPACE_PIO
+} bus_space_tag_t;
+
+typedef union {
+	u_long		  ioport;
+	volatile uint8_t __iomem *maddr;
+} bus_space_handle_t;
+
+typedef struct bus_dma_segment
+{
+	dma_addr_t	ds_addr;
+	bus_size_t	ds_len;
+} bus_dma_segment_t;
+
+struct ahd_linux_dma_tag
+{
+	bus_size_t	alignment;
+	bus_size_t	boundary;
+	bus_size_t	maxsize;
+};
+typedef struct ahd_linux_dma_tag* bus_dma_tag_t;
+
+struct ahd_linux_dmamap
+{
+	dma_addr_t	bus_addr;
+};
+typedef struct ahd_linux_dmamap* bus_dmamap_t;
+
+typedef int bus_dma_filter_t(void*, dma_addr_t);
+typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
+
+#define BUS_DMA_WAITOK		0x0
+#define BUS_DMA_NOWAIT		0x1
+#define BUS_DMA_ALLOCNOW	0x2
+#define BUS_DMA_LOAD_SEGS	0x4	/*
+					 * Argument is an S/G list not
+					 * a single buffer.
+					 */
+
+#define BUS_SPACE_MAXADDR	0xFFFFFFFF
+#define BUS_SPACE_MAXADDR_32BIT	0xFFFFFFFF
+#define BUS_SPACE_MAXSIZE_32BIT	0xFFFFFFFF
+
+int	ahd_dma_tag_create(struct ahd_softc *, bus_dma_tag_t /*parent*/,
+			   bus_size_t /*alignment*/, bus_size_t /*boundary*/,
+			   dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/,
+			   bus_dma_filter_t*/*filter*/, void */*filterarg*/,
+			   bus_size_t /*maxsize*/, int /*nsegments*/,
+			   bus_size_t /*maxsegsz*/, int /*flags*/,
+			   bus_dma_tag_t */*dma_tagp*/);
+
+void	ahd_dma_tag_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/);
+
+int	ahd_dmamem_alloc(struct ahd_softc *, bus_dma_tag_t /*dmat*/,
+			 void** /*vaddr*/, int /*flags*/,
+			 bus_dmamap_t* /*mapp*/);
+
+void	ahd_dmamem_free(struct ahd_softc *, bus_dma_tag_t /*dmat*/,
+			void* /*vaddr*/, bus_dmamap_t /*map*/);
+
+void	ahd_dmamap_destroy(struct ahd_softc *, bus_dma_tag_t /*tag*/,
+			   bus_dmamap_t /*map*/);
+
+int	ahd_dmamap_load(struct ahd_softc *ahd, bus_dma_tag_t /*dmat*/,
+			bus_dmamap_t /*map*/, void * /*buf*/,
+			bus_size_t /*buflen*/, bus_dmamap_callback_t *,
+			void */*callback_arg*/, int /*flags*/);
+
+int	ahd_dmamap_unload(struct ahd_softc *, bus_dma_tag_t, bus_dmamap_t);
+
+/*
+ * Operations performed by ahd_dmamap_sync().
+ */
+#define BUS_DMASYNC_PREREAD	0x01	/* pre-read synchronization */
+#define BUS_DMASYNC_POSTREAD	0x02	/* post-read synchronization */
+#define BUS_DMASYNC_PREWRITE	0x04	/* pre-write synchronization */
+#define BUS_DMASYNC_POSTWRITE	0x08	/* post-write synchronization */
+
+/*
+ * XXX
+ * ahd_dmamap_sync is only used on buffers allocated with
+ * the pci_alloc_consistent() API.  Although I'm not sure how
+ * this works on architectures with a write buffer, Linux does
+ * not have an API to sync "coherent" memory.  Perhaps we need
+ * to do an mb()?
+ */
+#define ahd_dmamap_sync(ahd, dma_tag, dmamap, offset, len, op)
+
+/************************** Timer DataStructures ******************************/
+typedef struct timer_list ahd_timer_t;
+
+/********************************** Includes **********************************/
+#ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT
+#define AIC_DEBUG_REGISTERS 1
+#else
+#define AIC_DEBUG_REGISTERS 0
+#endif
+#include "aic79xx.h"
+
+/***************************** Timer Facilities *******************************/
+#define ahd_timer_init init_timer
+#define ahd_timer_stop del_timer_sync
+typedef void ahd_linux_callback_t (u_long);  
+static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec,
+				     ahd_callback_t *func, void *arg);
+static __inline void ahd_scb_timer_reset(struct scb *scb, u_int usec);
+
+static __inline void
+ahd_timer_reset(ahd_timer_t *timer, u_int usec, ahd_callback_t *func, void *arg)
+{
+	struct ahd_softc *ahd;
+
+	ahd = (struct ahd_softc *)arg;
+	del_timer(timer);
+	timer->data = (u_long)arg;
+	timer->expires = jiffies + (usec * HZ)/1000000;
+	timer->function = (ahd_linux_callback_t*)func;
+	add_timer(timer);
+}
+
+static __inline void
+ahd_scb_timer_reset(struct scb *scb, u_int usec)
+{
+	mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000);
+}
+
+/***************************** SMP support ************************************/
+#include <linux/spinlock.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
+#define AHD_SCSI_HAS_HOST_LOCK 1
+#else
+#define AHD_SCSI_HAS_HOST_LOCK 0
+#endif
+
+#define AIC79XX_DRIVER_VERSION "1.3.11"
+
+/**************************** Front End Queues ********************************/
+/*
+ * Data structure used to cast the Linux struct scsi_cmnd to something
+ * that allows us to use the queue macros.  The linux structure has
+ * plenty of space to hold the links fields as required by the queue
+ * macros, but the queue macors require them to have the correct type.
+ */
+struct ahd_cmd_internal {
+	/* Area owned by the Linux scsi layer. */
+	uint8_t	private[offsetof(struct scsi_cmnd, SCp.Status)];
+	union {
+		STAILQ_ENTRY(ahd_cmd)	ste;
+		LIST_ENTRY(ahd_cmd)	le;
+		TAILQ_ENTRY(ahd_cmd)	tqe;
+	} links;
+	uint32_t			end;
+};
+
+struct ahd_cmd {
+	union {
+		struct ahd_cmd_internal	icmd;
+		struct scsi_cmnd	scsi_cmd;
+	} un;
+};
+
+#define acmd_icmd(cmd) ((cmd)->un.icmd)
+#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd)
+#define acmd_links un.icmd.links
+
+/*************************** Device Data Structures ***************************/
+/*
+ * A per probed device structure used to deal with some error recovery
+ * scenarios that the Linux mid-layer code just doesn't know how to
+ * handle.  The structure allocated for a device only becomes persistent
+ * after a successfully completed inquiry command to the target when
+ * that inquiry data indicates a lun is present.
+ */
+TAILQ_HEAD(ahd_busyq, ahd_cmd);
+typedef enum {
+	AHD_DEV_UNCONFIGURED	 = 0x01,
+	AHD_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
+	AHD_DEV_TIMER_ACTIVE	 = 0x04, /* Our timer is active */
+	AHD_DEV_ON_RUN_LIST	 = 0x08, /* Queued to be run later */
+	AHD_DEV_Q_BASIC		 = 0x10, /* Allow basic device queuing */
+	AHD_DEV_Q_TAGGED	 = 0x20, /* Allow full SCSI2 command queueing */
+	AHD_DEV_PERIODIC_OTAG	 = 0x40, /* Send OTAG to prevent starvation */
+	AHD_DEV_SLAVE_CONFIGURED = 0x80	 /* slave_configure() has been called */
+} ahd_linux_dev_flags;
+
+struct ahd_linux_target;
+struct ahd_linux_device {
+	TAILQ_ENTRY(ahd_linux_device) links;
+	struct			ahd_busyq busyq;
+
+	/*
+	 * The number of transactions currently
+	 * queued to the device.
+	 */
+	int			active;
+
+	/*
+	 * The currently allowed number of 
+	 * transactions that can be queued to
+	 * the device.  Must be signed for
+	 * conversion from tagged to untagged
+	 * mode where the device may have more
+	 * than one outstanding active transaction.
+	 */
+	int			openings;
+
+	/*
+	 * A positive count indicates that this
+	 * device's queue is halted.
+	 */
+	u_int			qfrozen;
+	
+	/*
+	 * Cumulative command counter.
+	 */
+	u_long			commands_issued;
+
+	/*
+	 * The number of tagged transactions when
+	 * running at our current opening level
+	 * that have been successfully received by
+	 * this device since the last QUEUE FULL.
+	 */
+	u_int			tag_success_count;
+#define AHD_TAG_SUCCESS_INTERVAL 50
+
+	ahd_linux_dev_flags	flags;
+
+	/*
+	 * Per device timer.
+	 */
+	struct timer_list	timer;
+
+	/*
+	 * The high limit for the tags variable.
+	 */
+	u_int			maxtags;
+
+	/*
+	 * The computed number of tags outstanding
+	 * at the time of the last QUEUE FULL event.
+	 */
+	u_int			tags_on_last_queuefull;
+
+	/*
+	 * How many times we have seen a queue full
+	 * with the same number of tags.  This is used
+	 * to stop our adaptive queue depth algorithm
+	 * on devices with a fixed number of tags.
+	 */
+	u_int			last_queuefull_same_count;
+#define AHD_LOCK_TAGS_COUNT 50
+
+	/*
+	 * How many transactions have been queued
+	 * without the device going idle.  We use
+	 * this statistic to determine when to issue
+	 * an ordered tag to prevent transaction
+	 * starvation.  This statistic is only updated
+	 * if the AHD_DEV_PERIODIC_OTAG flag is set
+	 * on this device.
+	 */
+	u_int			commands_since_idle_or_otag;
+#define AHD_OTAG_THRESH	500
+
+	int			lun;
+	Scsi_Device	       *scsi_device;
+	struct			ahd_linux_target *target;
+};
+
+typedef enum {
+	AHD_DV_REQUIRED		 = 0x01,
+	AHD_INQ_VALID		 = 0x02,
+	AHD_BASIC_DV		 = 0x04,
+	AHD_ENHANCED_DV		 = 0x08
+} ahd_linux_targ_flags;
+
+/* DV States */
+typedef enum {
+	AHD_DV_STATE_EXIT = 0,
+	AHD_DV_STATE_INQ_SHORT_ASYNC,
+	AHD_DV_STATE_INQ_ASYNC,
+	AHD_DV_STATE_INQ_ASYNC_VERIFY,
+	AHD_DV_STATE_TUR,
+	AHD_DV_STATE_REBD,
+	AHD_DV_STATE_INQ_VERIFY,
+	AHD_DV_STATE_WEB,
+	AHD_DV_STATE_REB,
+	AHD_DV_STATE_SU,
+	AHD_DV_STATE_BUSY
+} ahd_dv_state;
+
+struct ahd_linux_target {
+	struct ahd_linux_device	 *devices[AHD_NUM_LUNS];
+	int			  channel;
+	int			  target;
+	int			  refcount;
+	struct ahd_transinfo	  last_tinfo;
+	struct ahd_softc	 *ahd;
+	ahd_linux_targ_flags	  flags;
+	struct scsi_inquiry_data *inq_data;
+	/*
+	 * The next "fallback" period to use for narrow/wide transfers.
+	 */
+	uint8_t			  dv_next_narrow_period;
+	uint8_t			  dv_next_wide_period;
+	uint8_t			  dv_max_width;
+	uint8_t			  dv_max_ppr_options;
+	uint8_t			  dv_last_ppr_options;
+	u_int			  dv_echo_size;
+	ahd_dv_state		  dv_state;
+	u_int			  dv_state_retry;
+	uint8_t			 *dv_buffer;
+	uint8_t			 *dv_buffer1;
+
+	/*
+	 * Cumulative counter of errors.
+	 */
+	u_long			errors_detected;
+	u_long			cmds_since_error;
+};
+
+/********************* Definitions Required by the Core ***********************/
+/*
+ * Number of SG segments we require.  So long as the S/G segments for
+ * a particular transaction are allocated in a physically contiguous
+ * manner and are allocated below 4GB, the number of S/G segments is
+ * unrestricted.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * We dynamically adjust the number of segments in pre-2.5 kernels to
+ * avoid fragmentation issues in the SCSI mid-layer's private memory
+ * allocator.  See aic79xx_osm.c ahd_linux_size_nseg() for details.
+ */
+extern u_int ahd_linux_nseg;
+#define	AHD_NSEG ahd_linux_nseg
+#define	AHD_LINUX_MIN_NSEG 64
+#else
+#define	AHD_NSEG 128
+#endif
+
+/*
+ * Per-SCB OSM storage.
+ */
+typedef enum {
+	AHD_SCB_UP_EH_SEM = 0x1
+} ahd_linux_scb_flags;
+
+struct scb_platform_data {
+	struct ahd_linux_device	*dev;
+	dma_addr_t		 buf_busaddr;
+	uint32_t		 xfer_len;
+	uint32_t		 sense_resid;	/* Auto-Sense residual */
+	ahd_linux_scb_flags	 flags;
+};
+
+/*
+ * Define a structure used for each host adapter.  All members are
+ * aligned on a boundary >= the size of the member to honor the
+ * alignment restrictions of the various platforms supported by
+ * this driver.
+ */
+typedef enum {
+	AHD_DV_WAIT_SIMQ_EMPTY	 = 0x01,
+	AHD_DV_WAIT_SIMQ_RELEASE = 0x02,
+	AHD_DV_ACTIVE		 = 0x04,
+	AHD_DV_SHUTDOWN		 = 0x08,
+	AHD_RUN_CMPLT_Q_TIMER	 = 0x10
+} ahd_linux_softc_flags;
+
+TAILQ_HEAD(ahd_completeq, ahd_cmd);
+
+struct ahd_platform_data {
+	/*
+	 * Fields accessed from interrupt context.
+	 */
+	struct ahd_linux_target *targets[AHD_NUM_TARGETS]; 
+	TAILQ_HEAD(, ahd_linux_device) device_runq;
+	struct ahd_completeq	 completeq;
+
+	spinlock_t		 spin_lock;
+	struct tasklet_struct	 runq_tasklet;
+	u_int			 qfrozen;
+	pid_t			 dv_pid;
+	struct timer_list	 completeq_timer;
+	struct timer_list	 reset_timer;
+	struct timer_list	 stats_timer;
+	struct semaphore	 eh_sem;
+	struct semaphore	 dv_sem;
+	struct semaphore	 dv_cmd_sem;	/* XXX This needs to be in
+						 * the target struct
+						 */
+	struct scsi_device	*dv_scsi_dev;
+	struct Scsi_Host        *host;		/* pointer to scsi host */
+#define AHD_LINUX_NOIRQ	((uint32_t)~0)
+	uint32_t		 irq;		/* IRQ for this adapter */
+	uint32_t		 bios_address;
+	uint32_t		 mem_busaddr;	/* Mem Base Addr */
+	uint64_t		 hw_dma_mask;
+	ahd_linux_softc_flags	 flags;
+};
+
+/************************** OS Utility Wrappers *******************************/
+#define printf printk
+#define M_NOWAIT GFP_ATOMIC
+#define M_WAITOK 0
+#define malloc(size, type, flags) kmalloc(size, flags)
+#define free(ptr, type) kfree(ptr)
+
+static __inline void ahd_delay(long);
+static __inline void
+ahd_delay(long usec)
+{
+	/*
+	 * udelay on Linux can have problems for
+	 * multi-millisecond waits.  Wait at most
+	 * 1024us per call.
+	 */
+	while (usec > 0) {
+		udelay(usec % 1024);
+		usec -= 1024;
+	}
+}
+
+
+/***************************** Low Level I/O **********************************/
+static __inline uint8_t ahd_inb(struct ahd_softc * ahd, long port);
+static __inline uint16_t ahd_inw_atomic(struct ahd_softc * ahd, long port);
+static __inline void ahd_outb(struct ahd_softc * ahd, long port, uint8_t val);
+static __inline void ahd_outw_atomic(struct ahd_softc * ahd,
+				     long port, uint16_t val);
+static __inline void ahd_outsb(struct ahd_softc * ahd, long port,
+			       uint8_t *, int count);
+static __inline void ahd_insb(struct ahd_softc * ahd, long port,
+			       uint8_t *, int count);
+
+static __inline uint8_t
+ahd_inb(struct ahd_softc * ahd, long port)
+{
+	uint8_t x;
+
+	if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+		x = readb(ahd->bshs[0].maddr + port);
+	} else {
+		x = inb(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+	}
+	mb();
+	return (x);
+}
+
+static __inline uint16_t
+ahd_inw_atomic(struct ahd_softc * ahd, long port)
+{
+	uint8_t x;
+
+	if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+		x = readw(ahd->bshs[0].maddr + port);
+	} else {
+		x = inw(ahd->bshs[(port) >> 8].ioport + ((port) & 0xFF));
+	}
+	mb();
+	return (x);
+}
+
+static __inline void
+ahd_outb(struct ahd_softc * ahd, long port, uint8_t val)
+{
+	if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+		writeb(val, ahd->bshs[0].maddr + port);
+	} else {
+		outb(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+	}
+	mb();
+}
+
+static __inline void
+ahd_outw_atomic(struct ahd_softc * ahd, long port, uint16_t val)
+{
+	if (ahd->tags[0] == BUS_SPACE_MEMIO) {
+		writew(val, ahd->bshs[0].maddr + port);
+	} else {
+		outw(val, ahd->bshs[(port) >> 8].ioport + (port & 0xFF));
+	}
+	mb();
+}
+
+static __inline void
+ahd_outsb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		ahd_outb(ahd, port, *array++);
+}
+
+static __inline void
+ahd_insb(struct ahd_softc * ahd, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		*array++ = ahd_inb(ahd, port);
+}
+
+/**************************** Initialization **********************************/
+int		ahd_linux_register_host(struct ahd_softc *,
+					Scsi_Host_Template *);
+
+uint64_t	ahd_linux_get_memsize(void);
+
+/*************************** Pretty Printing **********************************/
+struct info_str {
+	char *buffer;
+	int length;
+	off_t offset;
+	int pos;
+};
+
+void	ahd_format_transinfo(struct info_str *info,
+			     struct ahd_transinfo *tinfo);
+
+/******************************** Locking *************************************/
+/* Lock protecting internal data structures */
+static __inline void ahd_lockinit(struct ahd_softc *);
+static __inline void ahd_lock(struct ahd_softc *, unsigned long *flags);
+static __inline void ahd_unlock(struct ahd_softc *, unsigned long *flags);
+
+/* Lock acquisition and release of the above lock in midlayer entry points. */
+static __inline void ahd_midlayer_entrypoint_lock(struct ahd_softc *,
+						  unsigned long *flags);
+static __inline void ahd_midlayer_entrypoint_unlock(struct ahd_softc *,
+						    unsigned long *flags);
+
+/* Lock held during command compeletion to the upper layer */
+static __inline void ahd_done_lockinit(struct ahd_softc *);
+static __inline void ahd_done_lock(struct ahd_softc *, unsigned long *flags);
+static __inline void ahd_done_unlock(struct ahd_softc *, unsigned long *flags);
+
+/* Lock held during ahd_list manipulation and ahd softc frees */
+extern spinlock_t ahd_list_spinlock;
+static __inline void ahd_list_lockinit(void);
+static __inline void ahd_list_lock(unsigned long *flags);
+static __inline void ahd_list_unlock(unsigned long *flags);
+
+static __inline void
+ahd_lockinit(struct ahd_softc *ahd)
+{
+	spin_lock_init(&ahd->platform_data->spin_lock);
+}
+
+static __inline void
+ahd_lock(struct ahd_softc *ahd, unsigned long *flags)
+{
+	spin_lock_irqsave(&ahd->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahd_unlock(struct ahd_softc *ahd, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahd->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahd_midlayer_entrypoint_lock(struct ahd_softc *ahd, unsigned long *flags)
+{
+	/*
+	 * In 2.5.X and some 2.4.X versions, the midlayer takes our
+	 * lock just before calling us, so we avoid locking again.
+	 * For other kernel versions, the io_request_lock is taken
+	 * just before our entry point is called.  In this case, we
+	 * trade the io_request_lock for our per-softc lock.
+	 */
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&io_request_lock);
+	spin_lock(&ahd->platform_data->spin_lock);
+#endif
+}
+
+static __inline void
+ahd_midlayer_entrypoint_unlock(struct ahd_softc *ahd, unsigned long *flags)
+{
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&ahd->platform_data->spin_lock);
+	spin_lock(&io_request_lock);
+#endif
+}
+
+static __inline void
+ahd_done_lockinit(struct ahd_softc *ahd)
+{
+	/*
+	 * In 2.5.X, our own lock is held during completions.
+	 * In previous versions, the io_request_lock is used.
+	 * In either case, we can't initialize this lock again.
+	 */
+}
+
+static __inline void
+ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags)
+{
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_lock(&io_request_lock);
+#endif
+}
+
+static __inline void
+ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags)
+{
+#if AHD_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&io_request_lock);
+#endif
+}
+
+static __inline void
+ahd_list_lockinit(void)
+{
+	spin_lock_init(&ahd_list_spinlock);
+}
+
+static __inline void
+ahd_list_lock(unsigned long *flags)
+{
+	spin_lock_irqsave(&ahd_list_spinlock, *flags);
+}
+
+static __inline void
+ahd_list_unlock(unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahd_list_spinlock, *flags);
+}
+
+/******************************* PCI Definitions ******************************/
+/*
+ * PCIM_xxx: mask to locate subfield in register
+ * PCIR_xxx: config register offset
+ * PCIC_xxx: device class
+ * PCIS_xxx: device subclass
+ * PCIP_xxx: device programming interface
+ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)
+ * PCID_xxx: device ID
+ */
+#define PCIR_DEVVENDOR		0x00
+#define PCIR_VENDOR		0x00
+#define PCIR_DEVICE		0x02
+#define PCIR_COMMAND		0x04
+#define PCIM_CMD_PORTEN		0x0001
+#define PCIM_CMD_MEMEN		0x0002
+#define PCIM_CMD_BUSMASTEREN	0x0004
+#define PCIM_CMD_MWRICEN	0x0010
+#define PCIM_CMD_PERRESPEN	0x0040
+#define	PCIM_CMD_SERRESPEN	0x0100
+#define PCIR_STATUS		0x06
+#define PCIR_REVID		0x08
+#define PCIR_PROGIF		0x09
+#define PCIR_SUBCLASS		0x0a
+#define PCIR_CLASS		0x0b
+#define PCIR_CACHELNSZ		0x0c
+#define PCIR_LATTIMER		0x0d
+#define PCIR_HEADERTYPE		0x0e
+#define PCIM_MFDEV		0x80
+#define PCIR_BIST		0x0f
+#define PCIR_CAP_PTR		0x34
+
+/* config registers for header type 0 devices */
+#define PCIR_MAPS	0x10
+#define PCIR_SUBVEND_0	0x2c
+#define PCIR_SUBDEV_0	0x2e
+
+/****************************** PCI-X definitions *****************************/
+#define PCIXR_COMMAND	0x96
+#define PCIXR_DEVADDR	0x98
+#define PCIXM_DEVADDR_FNUM	0x0003	/* Function Number */
+#define PCIXM_DEVADDR_DNUM	0x00F8	/* Device Number */
+#define PCIXM_DEVADDR_BNUM	0xFF00	/* Bus Number */
+#define PCIXR_STATUS	0x9A
+#define PCIXM_STATUS_64BIT	0x0001	/* Active 64bit connection to device. */
+#define PCIXM_STATUS_133CAP	0x0002	/* Device is 133MHz capable */
+#define PCIXM_STATUS_SCDISC	0x0004	/* Split Completion Discarded */
+#define PCIXM_STATUS_UNEXPSC	0x0008	/* Unexpected Split Completion */
+#define PCIXM_STATUS_CMPLEXDEV	0x0010	/* Device Complexity (set == bridge) */
+#define PCIXM_STATUS_MAXMRDBC	0x0060	/* Maximum Burst Read Count */
+#define PCIXM_STATUS_MAXSPLITS	0x0380	/* Maximum Split Transactions */
+#define PCIXM_STATUS_MAXCRDS	0x1C00	/* Maximum Cumulative Read Size */
+#define PCIXM_STATUS_RCVDSCEM	0x2000	/* Received a Split Comp w/Error msg */
+
+extern struct pci_driver aic79xx_pci_driver;
+
+typedef enum
+{
+	AHD_POWER_STATE_D0,
+	AHD_POWER_STATE_D1,
+	AHD_POWER_STATE_D2,
+	AHD_POWER_STATE_D3
+} ahd_power_state;
+
+void ahd_power_state_change(struct ahd_softc *ahd,
+			    ahd_power_state new_state);
+
+/******************************* PCI Routines *********************************/
+int			 ahd_linux_pci_init(void);
+void			 ahd_linux_pci_exit(void);
+int			 ahd_pci_map_registers(struct ahd_softc *ahd);
+int			 ahd_pci_map_int(struct ahd_softc *ahd);
+
+static __inline uint32_t ahd_pci_read_config(ahd_dev_softc_t pci,
+					     int reg, int width);
+
+static __inline uint32_t
+ahd_pci_read_config(ahd_dev_softc_t pci, int reg, int width)
+{
+	switch (width) {
+	case 1:
+	{
+		uint8_t retval;
+
+		pci_read_config_byte(pci, reg, &retval);
+		return (retval);
+	}
+	case 2:
+	{
+		uint16_t retval;
+		pci_read_config_word(pci, reg, &retval);
+		return (retval);
+	}
+	case 4:
+	{
+		uint32_t retval;
+		pci_read_config_dword(pci, reg, &retval);
+		return (retval);
+	}
+	default:
+		panic("ahd_pci_read_config: Read size too big");
+		/* NOTREACHED */
+		return (0);
+	}
+}
+
+static __inline void ahd_pci_write_config(ahd_dev_softc_t pci,
+					  int reg, uint32_t value,
+					  int width);
+
+static __inline void
+ahd_pci_write_config(ahd_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+	switch (width) {
+	case 1:
+		pci_write_config_byte(pci, reg, value);
+		break;
+	case 2:
+		pci_write_config_word(pci, reg, value);
+		break;
+	case 4:
+		pci_write_config_dword(pci, reg, value);
+		break;
+	default:
+		panic("ahd_pci_write_config: Write size too big");
+		/* NOTREACHED */
+	}
+}
+
+static __inline int ahd_get_pci_function(ahd_dev_softc_t);
+static __inline int
+ahd_get_pci_function(ahd_dev_softc_t pci)
+{
+	return (PCI_FUNC(pci->devfn));
+}
+
+static __inline int ahd_get_pci_slot(ahd_dev_softc_t);
+static __inline int
+ahd_get_pci_slot(ahd_dev_softc_t pci)
+{
+	return (PCI_SLOT(pci->devfn));
+}
+
+static __inline int ahd_get_pci_bus(ahd_dev_softc_t);
+static __inline int
+ahd_get_pci_bus(ahd_dev_softc_t pci)
+{
+	return (pci->bus->number);
+}
+
+static __inline void ahd_flush_device_writes(struct ahd_softc *);
+static __inline void
+ahd_flush_device_writes(struct ahd_softc *ahd)
+{
+	/* XXX Is this sufficient for all architectures??? */
+	ahd_inb(ahd, INTSTAT);
+}
+
+/**************************** Proc FS Support *********************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+int	ahd_linux_proc_info(char *, char **, off_t, int, int, int);
+#else
+int	ahd_linux_proc_info(struct Scsi_Host *, char *, char **,
+			    off_t, int, int);
+#endif
+
+/*************************** Domain Validation ********************************/
+#define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete)
+#define AHD_DV_SIMQ_FROZEN(ahd)					\
+	((((ahd)->platform_data->flags & AHD_DV_ACTIVE) != 0)	\
+	 && (ahd)->platform_data->qfrozen == 1)
+
+/*********************** Transaction Access Wrappers **************************/
+static __inline void ahd_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahd_set_transaction_status(struct scb *, uint32_t);
+static __inline void ahd_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahd_set_scsi_status(struct scb *, uint32_t);
+static __inline uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahd_get_transaction_status(struct scb *);
+static __inline uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahd_get_scsi_status(struct scb *);
+static __inline void ahd_set_transaction_tag(struct scb *, int, u_int);
+static __inline u_long ahd_get_transfer_length(struct scb *);
+static __inline int ahd_get_transfer_dir(struct scb *);
+static __inline void ahd_set_residual(struct scb *, u_long);
+static __inline void ahd_set_sense_residual(struct scb *scb, u_long resid);
+static __inline u_long ahd_get_residual(struct scb *);
+static __inline u_long ahd_get_sense_residual(struct scb *);
+static __inline int ahd_perform_autosense(struct scb *);
+static __inline uint32_t ahd_get_sense_bufsize(struct ahd_softc *,
+					       struct scb *);
+static __inline void ahd_notify_xfer_settings_change(struct ahd_softc *,
+						     struct ahd_devinfo *);
+static __inline void ahd_platform_scb_free(struct ahd_softc *ahd,
+					   struct scb *scb);
+static __inline void ahd_freeze_scb(struct scb *scb);
+
+static __inline
+void ahd_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status)
+{
+	cmd->result &= ~(CAM_STATUS_MASK << 16);
+	cmd->result |= status << 16;
+}
+
+static __inline
+void ahd_set_transaction_status(struct scb *scb, uint32_t status)
+{
+	ahd_cmd_set_transaction_status(scb->io_ctx,status);
+}
+
+static __inline
+void ahd_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status)
+{
+	cmd->result &= ~0xFFFF;
+	cmd->result |= status;
+}
+
+static __inline
+void ahd_set_scsi_status(struct scb *scb, uint32_t status)
+{
+	ahd_cmd_set_scsi_status(scb->io_ctx, status);
+}
+
+static __inline
+uint32_t ahd_cmd_get_transaction_status(Scsi_Cmnd *cmd)
+{
+	return ((cmd->result >> 16) & CAM_STATUS_MASK);
+}
+
+static __inline
+uint32_t ahd_get_transaction_status(struct scb *scb)
+{
+	return (ahd_cmd_get_transaction_status(scb->io_ctx));
+}
+
+static __inline
+uint32_t ahd_cmd_get_scsi_status(Scsi_Cmnd *cmd)
+{
+	return (cmd->result & 0xFFFF);
+}
+
+static __inline
+uint32_t ahd_get_scsi_status(struct scb *scb)
+{
+	return (ahd_cmd_get_scsi_status(scb->io_ctx));
+}
+
+static __inline
+void ahd_set_transaction_tag(struct scb *scb, int enabled, u_int type)
+{
+	/*
+	 * Nothing to do for linux as the incoming transaction
+	 * has no concept of tag/non tagged, etc.
+	 */
+}
+
+static __inline
+u_long ahd_get_transfer_length(struct scb *scb)
+{
+	return (scb->platform_data->xfer_len);
+}
+
+static __inline
+int ahd_get_transfer_dir(struct scb *scb)
+{
+	return (scb->io_ctx->sc_data_direction);
+}
+
+static __inline
+void ahd_set_residual(struct scb *scb, u_long resid)
+{
+	scb->io_ctx->resid = resid;
+}
+
+static __inline
+void ahd_set_sense_residual(struct scb *scb, u_long resid)
+{
+	scb->platform_data->sense_resid = resid;
+}
+
+static __inline
+u_long ahd_get_residual(struct scb *scb)
+{
+	return (scb->io_ctx->resid);
+}
+
+static __inline
+u_long ahd_get_sense_residual(struct scb *scb)
+{
+	return (scb->platform_data->sense_resid);
+}
+
+static __inline
+int ahd_perform_autosense(struct scb *scb)
+{
+	/*
+	 * We always perform autosense in Linux.
+	 * On other platforms this is set on a
+	 * per-transaction basis.
+	 */
+	return (1);
+}
+
+static __inline uint32_t
+ahd_get_sense_bufsize(struct ahd_softc *ahd, struct scb *scb)
+{
+	return (sizeof(struct scsi_sense_data));
+}
+
+static __inline void
+ahd_notify_xfer_settings_change(struct ahd_softc *ahd,
+				struct ahd_devinfo *devinfo)
+{
+	/* Nothing to do here for linux */
+}
+
+static __inline void
+ahd_platform_scb_free(struct ahd_softc *ahd, struct scb *scb)
+{
+	ahd->flags &= ~AHD_RESOURCE_SHORTAGE;
+}
+
+int	ahd_platform_alloc(struct ahd_softc *ahd, void *platform_arg);
+void	ahd_platform_free(struct ahd_softc *ahd);
+void	ahd_platform_init(struct ahd_softc *ahd);
+void	ahd_platform_freeze_devq(struct ahd_softc *ahd, struct scb *scb);
+void	ahd_freeze_simq(struct ahd_softc *ahd);
+void	ahd_release_simq(struct ahd_softc *ahd);
+
+static __inline void
+ahd_freeze_scb(struct scb *scb)
+{
+	if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) {
+                scb->io_ctx->result |= CAM_DEV_QFRZN << 16;
+                scb->platform_data->dev->qfrozen++;
+        }
+}
+
+void	ahd_platform_set_tags(struct ahd_softc *ahd,
+			      struct ahd_devinfo *devinfo, ahd_queue_alg);
+int	ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
+				char channel, int lun, u_int tag,
+				role_t role, uint32_t status);
+irqreturn_t
+	ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+void	ahd_platform_flushwork(struct ahd_softc *ahd);
+int	ahd_softc_comp(struct ahd_softc *, struct ahd_softc *);
+void	ahd_done(struct ahd_softc*, struct scb*);
+void	ahd_send_async(struct ahd_softc *, char channel,
+		       u_int target, u_int lun, ac_code, void *);
+void	ahd_print_path(struct ahd_softc *, struct scb *);
+void	ahd_platform_dump_card_state(struct ahd_softc *ahd);
+
+#ifdef CONFIG_PCI
+#define AHD_PCI_CONFIG 1
+#else
+#define AHD_PCI_CONFIG 0
+#endif
+#define bootverbose aic79xx_verbose
+extern uint32_t aic79xx_verbose;
+
+#endif /* _AIC79XX_LINUX_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
new file mode 100644
index 0000000..91daf0c
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c
@@ -0,0 +1,368 @@
+/*
+ * Linux driver attachment glue for PCI based U320 controllers.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#25 $
+ */
+
+#include "aic79xx_osm.h"
+#include "aic79xx_inline.h"
+#include "aic79xx_pci.h"
+
+static int	ahd_linux_pci_dev_probe(struct pci_dev *pdev,
+					const struct pci_device_id *ent);
+static int	ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd,
+						 u_long *base, u_long *base2);
+static int	ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
+						 u_long *bus_addr,
+						 uint8_t __iomem **maddr);
+static void	ahd_linux_pci_dev_remove(struct pci_dev *pdev);
+
+/* Define the macro locally since it's different for different class of chips.
+ */
+#define ID(x)            \
+	ID2C(x),         \
+	ID2C(IDIROC(x))
+
+static struct pci_device_id ahd_linux_pci_id_table[] = {
+	/* aic7901 based controllers */
+	ID(ID_AHA_29320A),
+	ID(ID_AHA_29320ALP),
+	/* aic7902 based controllers */
+	ID(ID_AHA_29320),
+	ID(ID_AHA_29320B),
+	ID(ID_AHA_29320LP),
+	ID(ID_AHA_39320),
+	ID(ID_AHA_39320_B),
+	ID(ID_AHA_39320A),
+	ID(ID_AHA_39320D),
+	ID(ID_AHA_39320D_HP),
+	ID(ID_AHA_39320D_B),
+	ID(ID_AHA_39320D_B_HP),
+	/* Generic chip probes for devices we don't know exactly. */
+	ID16(ID_AIC7901 & ID_9005_GENERIC_MASK),
+	ID(ID_AIC7901A & ID_DEV_VENDOR_MASK),
+	ID16(ID_AIC7902 & ID_9005_GENERIC_MASK),
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, ahd_linux_pci_id_table);
+
+struct pci_driver aic79xx_pci_driver = {
+	.name		= "aic79xx",
+	.probe		= ahd_linux_pci_dev_probe,
+	.remove		= ahd_linux_pci_dev_remove,
+	.id_table	= ahd_linux_pci_id_table
+};
+
+static void
+ahd_linux_pci_dev_remove(struct pci_dev *pdev)
+{
+	struct ahd_softc *ahd;
+	u_long l;
+
+	/*
+	 * We should be able to just perform
+	 * the free directly, but check our
+	 * list for extra sanity.
+	 */
+	ahd_list_lock(&l);
+	ahd = ahd_find_softc((struct ahd_softc *)pci_get_drvdata(pdev));
+	if (ahd != NULL) {
+		u_long s;
+
+		TAILQ_REMOVE(&ahd_tailq, ahd, links);
+		ahd_list_unlock(&l);
+		ahd_lock(ahd, &s);
+		ahd_intr_enable(ahd, FALSE);
+		ahd_unlock(ahd, &s);
+		ahd_free(ahd);
+	} else
+		ahd_list_unlock(&l);
+}
+
+static int
+ahd_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	char		 buf[80];
+	struct		 ahd_softc *ahd;
+	ahd_dev_softc_t	 pci;
+	struct		 ahd_pci_identity *entry;
+	char		*name;
+	int		 error;
+
+	/*
+	 * Some BIOSen report the same device multiple times.
+	 */
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+		struct pci_dev *probed_pdev;
+
+		probed_pdev = ahd->dev_softc;
+		if (probed_pdev->bus->number == pdev->bus->number
+		 && probed_pdev->devfn == pdev->devfn)
+			break;
+	}
+	if (ahd != NULL) {
+		/* Skip duplicate. */
+		return (-ENODEV);
+	}
+
+	pci = pdev;
+	entry = ahd_find_pci_device(pci);
+	if (entry == NULL)
+		return (-ENODEV);
+
+	/*
+	 * Allocate a softc for this card and
+	 * set it up for attachment by our
+	 * common detect routine.
+	 */
+	sprintf(buf, "ahd_pci:%d:%d:%d",
+		ahd_get_pci_bus(pci),
+		ahd_get_pci_slot(pci),
+		ahd_get_pci_function(pci));
+	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (name == NULL)
+		return (-ENOMEM);
+	strcpy(name, buf);
+	ahd = ahd_alloc(NULL, name);
+	if (ahd == NULL)
+		return (-ENOMEM);
+	if (pci_enable_device(pdev)) {
+		ahd_free(ahd);
+		return (-ENODEV);
+	}
+	pci_set_master(pdev);
+
+	if (sizeof(dma_addr_t) > 4) {
+		uint64_t   memsize;
+		const uint64_t mask_39bit = 0x7FFFFFFFFFULL;
+
+		memsize = ahd_linux_get_memsize();
+
+		if (memsize >= 0x8000000000ULL
+	 	 && pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
+			ahd->flags |= AHD_64BIT_ADDRESSING;
+			ahd->platform_data->hw_dma_mask = DMA_64BIT_MASK;
+		} else if (memsize > 0x80000000
+			&& pci_set_dma_mask(pdev, mask_39bit) == 0) {
+			ahd->flags |= AHD_39BIT_ADDRESSING;
+			ahd->platform_data->hw_dma_mask = mask_39bit;
+		}
+	} else {
+		pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		ahd->platform_data->hw_dma_mask = DMA_32BIT_MASK;
+	}
+	ahd->dev_softc = pci;
+	error = ahd_pci_config(ahd, entry);
+	if (error != 0) {
+		ahd_free(ahd);
+		return (-error);
+	}
+	pci_set_drvdata(pdev, ahd);
+	if (aic79xx_detect_complete) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		ahd_linux_register_host(ahd, &aic79xx_driver_template);
+#else
+		printf("aic79xx: ignoring PCI device found after "
+		       "initialization\n");
+		return (-ENODEV);
+#endif
+	}
+	return (0);
+}
+
+int
+ahd_linux_pci_init(void)
+{
+	return (pci_module_init(&aic79xx_pci_driver));
+}
+
+void
+ahd_linux_pci_exit(void)
+{
+	pci_unregister_driver(&aic79xx_pci_driver);
+}
+
+static int
+ahd_linux_pci_reserve_io_regions(struct ahd_softc *ahd, u_long *base,
+				 u_long *base2)
+{
+	*base = pci_resource_start(ahd->dev_softc, 0);
+	/*
+	 * This is really the 3rd bar and should be at index 2,
+	 * but the Linux PCI code doesn't know how to "count" 64bit
+	 * bars.
+	 */
+	*base2 = pci_resource_start(ahd->dev_softc, 3);
+	if (*base == 0 || *base2 == 0)
+		return (ENOMEM);
+	if (request_region(*base, 256, "aic79xx") == 0)
+		return (ENOMEM);
+	if (request_region(*base2, 256, "aic79xx") == 0) {
+		release_region(*base2, 256);
+		return (ENOMEM);
+	}
+	return (0);
+}
+
+static int
+ahd_linux_pci_reserve_mem_region(struct ahd_softc *ahd,
+				 u_long *bus_addr,
+				 uint8_t __iomem **maddr)
+{
+	u_long	start;
+	u_long	base_page;
+	u_long	base_offset;
+	int	error;
+
+	if (aic79xx_allow_memio == 0)
+		return (ENOMEM);
+
+	if ((ahd->bugs & AHD_PCIX_MMAPIO_BUG) != 0)
+		return (ENOMEM);
+
+	error = 0;
+	start = pci_resource_start(ahd->dev_softc, 1);
+	base_page = start & PAGE_MASK;
+	base_offset = start - base_page;
+	if (start != 0) {
+		*bus_addr = start;
+		if (request_mem_region(start, 0x1000, "aic79xx") == 0)
+			error = ENOMEM;
+		if (error == 0) {
+			*maddr = ioremap_nocache(base_page, base_offset + 256);
+			if (*maddr == NULL) {
+				error = ENOMEM;
+				release_mem_region(start, 0x1000);
+			} else
+				*maddr += base_offset;
+		}
+	} else
+		error = ENOMEM;
+	return (error);
+}
+
+int
+ahd_pci_map_registers(struct ahd_softc *ahd)
+{
+	uint32_t command;
+	u_long	 base;
+	uint8_t	__iomem *maddr;
+	int	 error;
+
+	/*
+	 * If its allowed, we prefer memory mapped access.
+	 */
+	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, 4);
+	command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
+	base = 0;
+	maddr = NULL;
+	error = ahd_linux_pci_reserve_mem_region(ahd, &base, &maddr);
+	if (error == 0) {
+		ahd->platform_data->mem_busaddr = base;
+		ahd->tags[0] = BUS_SPACE_MEMIO;
+		ahd->bshs[0].maddr = maddr;
+		ahd->tags[1] = BUS_SPACE_MEMIO;
+		ahd->bshs[1].maddr = maddr + 0x100;
+		ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
+				     command | PCIM_CMD_MEMEN, 4);
+
+		if (ahd_pci_test_register_access(ahd) != 0) {
+
+			printf("aic79xx: PCI Device %d:%d:%d "
+			       "failed memory mapped test.  Using PIO.\n",
+			       ahd_get_pci_bus(ahd->dev_softc),
+			       ahd_get_pci_slot(ahd->dev_softc),
+			       ahd_get_pci_function(ahd->dev_softc));
+			iounmap(maddr);
+			release_mem_region(ahd->platform_data->mem_busaddr,
+					   0x1000);
+			ahd->bshs[0].maddr = NULL;
+			maddr = NULL;
+		} else
+			command |= PCIM_CMD_MEMEN;
+	} else if (bootverbose) {
+		printf("aic79xx: PCI%d:%d:%d MEM region 0x%lx "
+		       "unavailable. Cannot memory map device.\n",
+		       ahd_get_pci_bus(ahd->dev_softc),
+		       ahd_get_pci_slot(ahd->dev_softc),
+		       ahd_get_pci_function(ahd->dev_softc),
+		       base);
+	}
+
+	if (maddr == NULL) {
+		u_long	 base2;
+
+		error = ahd_linux_pci_reserve_io_regions(ahd, &base, &base2);
+		if (error == 0) {
+			ahd->tags[0] = BUS_SPACE_PIO;
+			ahd->tags[1] = BUS_SPACE_PIO;
+			ahd->bshs[0].ioport = base;
+			ahd->bshs[1].ioport = base2;
+			command |= PCIM_CMD_PORTEN;
+		} else {
+			printf("aic79xx: PCI%d:%d:%d IO regions 0x%lx and 0x%lx"
+			       "unavailable. Cannot map device.\n",
+			       ahd_get_pci_bus(ahd->dev_softc),
+			       ahd_get_pci_slot(ahd->dev_softc),
+			       ahd_get_pci_function(ahd->dev_softc),
+			       base, base2);
+		}
+	}
+	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, 4);
+	return (error);
+}
+
+int
+ahd_pci_map_int(struct ahd_softc *ahd)
+{
+	int error;
+
+	error = request_irq(ahd->dev_softc->irq, ahd_linux_isr,
+			    SA_SHIRQ, "aic79xx", ahd);
+	if (error == 0)
+		ahd->platform_data->irq = ahd->dev_softc->irq;
+	
+	return (-error);
+}
+
+void
+ahd_power_state_change(struct ahd_softc *ahd, ahd_power_state new_state)
+{
+	pci_set_power_state(ahd->dev_softc, new_state);
+}
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
new file mode 100644
index 0000000..4c3bb7b
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c
@@ -0,0 +1,987 @@
+/*
+ * Product specific probe and attach routines for:
+ *	aic7901 and aic7902 SCSI controllers
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#77 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "aic79xx_osm.h"
+#include "aic79xx_inline.h"
+#else
+#include <dev/aic7xxx/aic79xx_osm.h>
+#include <dev/aic7xxx/aic79xx_inline.h>
+#endif
+
+#include "aic79xx_pci.h"
+
+static __inline uint64_t
+ahd_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
+{
+	uint64_t id;
+
+	id = subvendor
+	   | (subdevice << 16)
+	   | ((uint64_t)vendor << 32)
+	   | ((uint64_t)device << 48);
+
+	return (id);
+}
+
+#define ID_AIC7902_PCI_REV_A4		0x3
+#define ID_AIC7902_PCI_REV_B0		0x10
+#define SUBID_HP			0x0E11
+
+#define DEVID_9005_HOSTRAID(id) ((id) & 0x80)
+
+#define DEVID_9005_TYPE(id) ((id) & 0xF)
+#define		DEVID_9005_TYPE_HBA		0x0	/* Standard Card */
+#define		DEVID_9005_TYPE_HBA_2EXT	0x1	/* 2 External Ports */
+#define		DEVID_9005_TYPE_IROC		0x8	/* Raid(0,1,10) Card */
+#define		DEVID_9005_TYPE_MB		0xF	/* On Motherboard */
+
+#define DEVID_9005_MFUNC(id) ((id) & 0x10)
+
+#define DEVID_9005_PACKETIZED(id) ((id) & 0x8000)
+
+#define SUBID_9005_TYPE(id) ((id) & 0xF)
+#define		SUBID_9005_TYPE_HBA		0x0	/* Standard Card */
+#define		SUBID_9005_TYPE_MB		0xF	/* On Motherboard */
+
+#define SUBID_9005_AUTOTERM(id)	(((id) & 0x10) == 0)
+
+#define SUBID_9005_LEGACYCONN_FUNC(id) ((id) & 0x20)
+
+#define SUBID_9005_SEEPTYPE(id) ((id) & 0x0C0) >> 6)
+#define		SUBID_9005_SEEPTYPE_NONE	0x0
+#define		SUBID_9005_SEEPTYPE_4K		0x1
+
+static ahd_device_setup_t ahd_aic7901_setup;
+static ahd_device_setup_t ahd_aic7901A_setup;
+static ahd_device_setup_t ahd_aic7902_setup;
+static ahd_device_setup_t ahd_aic790X_setup;
+
+struct ahd_pci_identity ahd_pci_ident_table [] =
+{
+	/* aic7901 based controllers */
+	{
+		ID_AHA_29320A,
+		ID_ALL_MASK,
+		"Adaptec 29320A Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
+	{
+		ID_AHA_29320ALP,
+		ID_ALL_MASK,
+		"Adaptec 29320ALP Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
+	/* aic7902 based controllers */	
+	{
+		ID_AHA_29320,
+		ID_ALL_MASK,
+		"Adaptec 29320 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_29320B,
+		ID_ALL_MASK,
+		"Adaptec 29320B Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_29320LP,
+		ID_ALL_MASK,
+		"Adaptec 29320LP Ultra320 SCSI adapter",
+		ahd_aic7901A_setup
+	},
+	{
+		ID_AHA_39320,
+		ID_ALL_MASK,
+		"Adaptec 39320 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320_B,
+		ID_ALL_MASK,
+		"Adaptec 39320 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320A,
+		ID_ALL_MASK,
+		"Adaptec 39320A Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320D,
+		ID_ALL_MASK,
+		"Adaptec 39320D Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320D_HP,
+		ID_ALL_MASK,
+		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320D_B,
+		ID_ALL_MASK,
+		"Adaptec 39320D Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	{
+		ID_AHA_39320D_B_HP,
+		ID_ALL_MASK,
+		"Adaptec (HP OEM) 39320D Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	},
+	/* Generic chip probes for devices we don't know 'exactly' */
+	{
+		ID_AIC7901 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec AIC7901 Ultra320 SCSI adapter",
+		ahd_aic7901_setup
+	},
+	{
+		ID_AIC7901A & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec AIC7901A Ultra320 SCSI adapter",
+		ahd_aic7901A_setup
+	},
+	{
+		ID_AIC7902 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec AIC7902 Ultra320 SCSI adapter",
+		ahd_aic7902_setup
+	}
+};
+
+const u_int ahd_num_pci_devs = NUM_ELEMENTS(ahd_pci_ident_table);
+		
+#define	DEVCONFIG		0x40
+#define		PCIXINITPAT	0x0000E000ul
+#define			PCIXINIT_PCI33_66	0x0000E000ul
+#define			PCIXINIT_PCIX50_66	0x0000C000ul
+#define			PCIXINIT_PCIX66_100	0x0000A000ul
+#define			PCIXINIT_PCIX100_133	0x00008000ul
+#define	PCI_BUS_MODES_INDEX(devconfig)	\
+	(((devconfig) & PCIXINITPAT) >> 13)
+static const char *pci_bus_modes[] =
+{
+	"PCI bus mode unknown",
+	"PCI bus mode unknown",
+	"PCI bus mode unknown",
+	"PCI bus mode unknown",
+	"PCI-X 101-133Mhz",
+	"PCI-X 67-100Mhz",
+	"PCI-X 50-66Mhz",
+	"PCI 33 or 66Mhz"
+};
+
+#define		TESTMODE	0x00000800ul
+#define		IRDY_RST	0x00000200ul
+#define		FRAME_RST	0x00000100ul
+#define		PCI64BIT	0x00000080ul
+#define		MRDCEN		0x00000040ul
+#define		ENDIANSEL	0x00000020ul
+#define		MIXQWENDIANEN	0x00000008ul
+#define		DACEN		0x00000004ul
+#define		STPWLEVEL	0x00000002ul
+#define		QWENDIANSEL	0x00000001ul
+
+#define	DEVCONFIG1		0x44
+#define		PREQDIS		0x01
+
+#define	CSIZE_LATTIME		0x0c
+#define		CACHESIZE	0x000000fful
+#define		LATTIME		0x0000ff00ul
+
+static int	ahd_check_extport(struct ahd_softc *ahd);
+static void	ahd_configure_termination(struct ahd_softc *ahd,
+					  u_int adapter_control);
+static void	ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat);
+
+struct ahd_pci_identity *
+ahd_find_pci_device(ahd_dev_softc_t pci)
+{
+	uint64_t  full_id;
+	uint16_t  device;
+	uint16_t  vendor;
+	uint16_t  subdevice;
+	uint16_t  subvendor;
+	struct	  ahd_pci_identity *entry;
+	u_int	  i;
+
+	vendor = ahd_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
+	device = ahd_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
+	subvendor = ahd_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
+	subdevice = ahd_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
+	full_id = ahd_compose_id(device,
+				 vendor,
+				 subdevice,
+				 subvendor);
+
+	/*
+	 * Controllers, mask out the IROC/HostRAID bit
+	 */
+	
+	full_id &= ID_ALL_IROC_MASK;
+
+	for (i = 0; i < ahd_num_pci_devs; i++) {
+		entry = &ahd_pci_ident_table[i];
+		if (entry->full_id == (full_id & entry->id_mask)) {
+			/* Honor exclusion entries. */
+			if (entry->name == NULL)
+				return (NULL);
+			return (entry);
+		}
+	}
+	return (NULL);
+}
+
+int
+ahd_pci_config(struct ahd_softc *ahd, struct ahd_pci_identity *entry)
+{
+	struct scb_data *shared_scb_data;
+	u_long		 l;
+	u_int		 command;
+	uint32_t	 devconfig;
+	uint16_t	 subvendor; 
+	int		 error;
+
+	shared_scb_data = NULL;
+	ahd->description = entry->name;
+	/*
+	 * Record if this is an HP board.
+	 */
+	subvendor = ahd_pci_read_config(ahd->dev_softc,
+					PCIR_SUBVEND_0, /*bytes*/2);
+	if (subvendor == SUBID_HP)
+		ahd->flags |= AHD_HP_BOARD;
+
+	error = entry->setup(ahd);
+	if (error != 0)
+		return (error);
+	
+	devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
+	if ((devconfig & PCIXINITPAT) == PCIXINIT_PCI33_66) {
+		ahd->chip |= AHD_PCI;
+		/* Disable PCIX workarounds when running in PCI mode. */
+		ahd->bugs &= ~AHD_PCIX_BUG_MASK;
+	} else {
+		ahd->chip |= AHD_PCIX;
+	}
+	ahd->bus_description = pci_bus_modes[PCI_BUS_MODES_INDEX(devconfig)];
+
+	ahd_power_state_change(ahd, AHD_POWER_STATE_D0);
+
+	error = ahd_pci_map_registers(ahd);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * If we need to support high memory, enable dual
+	 * address cycles.  This bit must be set to enable
+	 * high address bit generation even if we are on a
+	 * 64bit bus (PCI64BIT set in devconfig).
+	 */
+	if ((ahd->flags & (AHD_39BIT_ADDRESSING|AHD_64BIT_ADDRESSING)) != 0) {
+		uint32_t devconfig;
+
+		if (bootverbose)
+			printf("%s: Enabling 39Bit Addressing\n",
+			       ahd_name(ahd));
+		devconfig = ahd_pci_read_config(ahd->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		devconfig |= DACEN;
+		ahd_pci_write_config(ahd->dev_softc, DEVCONFIG,
+				     devconfig, /*bytes*/4);
+	}
+	
+	/* Ensure busmastering is enabled */
+	command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
+	command |= PCIM_CMD_BUSMASTEREN;
+	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
+
+	error = ahd_softc_init(ahd);
+	if (error != 0)
+		return (error);
+
+	ahd->bus_intr = ahd_pci_intr;
+
+	error = ahd_reset(ahd, /*reinit*/FALSE);
+	if (error != 0)
+		return (ENXIO);
+
+	ahd->pci_cachesize =
+	    ahd_pci_read_config(ahd->dev_softc, CSIZE_LATTIME,
+				/*bytes*/1) & CACHESIZE;
+	ahd->pci_cachesize *= 4;
+
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	/* See if we have a SEEPROM and perform auto-term */
+	error = ahd_check_extport(ahd);
+	if (error != 0)
+		return (error);
+
+	/* Core initialization */
+	error = ahd_init(ahd);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Allow interrupts now that we are completely setup.
+	 */
+	error = ahd_pci_map_int(ahd);
+	if (error != 0)
+		return (error);
+
+	ahd_list_lock(&l);
+	/*
+	 * Link this softc in with all other ahd instances.
+	 */
+	ahd_softc_insert(ahd);
+	ahd_list_unlock(&l);
+	return (0);
+}
+
+/*
+ * Perform some simple tests that should catch situations where
+ * our registers are invalidly mapped.
+ */
+int
+ahd_pci_test_register_access(struct ahd_softc *ahd)
+{
+	uint32_t cmd;
+	u_int	 targpcistat;
+	u_int	 pci_status1;
+	int	 error;
+	uint8_t	 hcntrl;
+
+	error = EIO;
+
+	/*
+	 * Enable PCI error interrupt status, but suppress NMIs
+	 * generated by SERR raised due to target aborts.
+	 */
+	cmd = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2);
+	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND,
+			     cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2);
+
+	/*
+	 * First a simple test to see if any
+	 * registers can be read.  Reading
+	 * HCNTRL has no side effects and has
+	 * at least one bit that is guaranteed to
+	 * be zero so it is a good register to
+	 * use for this test.
+	 */
+	hcntrl = ahd_inb(ahd, HCNTRL);
+	if (hcntrl == 0xFF)
+		goto fail;
+
+	/*
+	 * Next create a situation where write combining
+	 * or read prefetching could be initiated by the
+	 * CPU or host bridge.  Our device does not support
+	 * either, so look for data corruption and/or flaged
+	 * PCI errors.  First pause without causing another
+	 * chip reset.
+	 */
+	hcntrl &= ~CHIPRST;
+	ahd_outb(ahd, HCNTRL, hcntrl|PAUSE);
+	while (ahd_is_paused(ahd) == 0)
+		;
+
+	/* Clear any PCI errors that occurred before our driver attached. */
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+	targpcistat = ahd_inb(ahd, TARGPCISTAT);
+	ahd_outb(ahd, TARGPCISTAT, targpcistat);
+	pci_status1 = ahd_pci_read_config(ahd->dev_softc,
+					  PCIR_STATUS + 1, /*bytes*/1);
+	ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
+			     pci_status1, /*bytes*/1);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	ahd_outb(ahd, CLRINT, CLRPCIINT);
+
+	ahd_outb(ahd, SEQCTL0, PERRORDIS);
+	ahd_outl(ahd, SRAM_BASE, 0x5aa555aa);
+	if (ahd_inl(ahd, SRAM_BASE) != 0x5aa555aa)
+		goto fail;
+
+	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {
+		u_int targpcistat;
+
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		targpcistat = ahd_inb(ahd, TARGPCISTAT);
+		if ((targpcistat & STA) != 0)
+			goto fail;
+	}
+
+	error = 0;
+
+fail:
+	if ((ahd_inb(ahd, INTSTAT) & PCIINT) != 0) {
+
+		ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+		targpcistat = ahd_inb(ahd, TARGPCISTAT);
+
+		/* Silently clear any latched errors. */
+		ahd_outb(ahd, TARGPCISTAT, targpcistat);
+		pci_status1 = ahd_pci_read_config(ahd->dev_softc,
+						  PCIR_STATUS + 1, /*bytes*/1);
+		ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
+				     pci_status1, /*bytes*/1);
+		ahd_outb(ahd, CLRINT, CLRPCIINT);
+	}
+	ahd_outb(ahd, SEQCTL0, PERRORDIS|FAILDIS);
+	ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);
+	return (error);
+}
+
+/*
+ * Check the external port logic for a serial eeprom
+ * and termination/cable detection contrls.
+ */
+static int
+ahd_check_extport(struct ahd_softc *ahd)
+{
+	struct	vpd_config vpd;
+	struct	seeprom_config *sc;
+	u_int	adapter_control;
+	int	have_seeprom;
+	int	error;
+
+	sc = ahd->seep_config;
+	have_seeprom = ahd_acquire_seeprom(ahd);
+	if (have_seeprom) {
+		u_int start_addr;
+
+		/*
+		 * Fetch VPD for this function and parse it.
+		 */
+		if (bootverbose) 
+			printf("%s: Reading VPD from SEEPROM...",
+			       ahd_name(ahd));
+
+		/* Address is always in units of 16bit words */
+		start_addr = ((2 * sizeof(*sc))
+			    + (sizeof(vpd) * (ahd->channel - 'A'))) / 2;
+
+		error = ahd_read_seeprom(ahd, (uint16_t *)&vpd,
+					 start_addr, sizeof(vpd)/2,
+					 /*bytestream*/TRUE);
+		if (error == 0)
+			error = ahd_parse_vpddata(ahd, &vpd);
+		if (bootverbose) 
+			printf("%s: VPD parsing %s\n",
+			       ahd_name(ahd),
+			       error == 0 ? "successful" : "failed");
+
+		if (bootverbose) 
+			printf("%s: Reading SEEPROM...", ahd_name(ahd));
+
+		/* Address is always in units of 16bit words */
+		start_addr = (sizeof(*sc) / 2) * (ahd->channel - 'A');
+
+		error = ahd_read_seeprom(ahd, (uint16_t *)sc,
+					 start_addr, sizeof(*sc)/2,
+					 /*bytestream*/FALSE);
+
+		if (error != 0) {
+			printf("Unable to read SEEPROM\n");
+			have_seeprom = 0;
+		} else {
+			have_seeprom = ahd_verify_cksum(sc);
+
+			if (bootverbose) {
+				if (have_seeprom == 0)
+					printf ("checksum error\n");
+				else
+					printf ("done.\n");
+			}
+		}
+		ahd_release_seeprom(ahd);
+	}
+
+	if (!have_seeprom) {
+		u_int	  nvram_scb;
+
+		/*
+		 * Pull scratch ram settings and treat them as
+		 * if they are the contents of an seeprom if
+		 * the 'ADPT', 'BIOS', or 'ASPI' signature is found
+		 * in SCB 0xFF.  We manually compose the data as 16bit
+		 * values to avoid endian issues.
+		 */
+		ahd_set_scbptr(ahd, 0xFF);
+		nvram_scb = ahd_inb_scbram(ahd, SCB_BASE + NVRAM_SCB_OFFSET);
+		if (nvram_scb != 0xFF
+		 && ((ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'D'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'T')
+		  || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'B'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'I'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'O'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'S')
+		  || (ahd_inb_scbram(ahd, SCB_BASE + 0) == 'A'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 1) == 'S'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 2) == 'P'
+		   && ahd_inb_scbram(ahd, SCB_BASE + 3) == 'I'))) {
+			uint16_t *sc_data;
+			int	  i;
+
+			ahd_set_scbptr(ahd, nvram_scb);
+			sc_data = (uint16_t *)sc;
+			for (i = 0; i < 64; i += 2)
+				*sc_data++ = ahd_inw_scbram(ahd, SCB_BASE+i);
+			have_seeprom = ahd_verify_cksum(sc);
+			if (have_seeprom)
+				ahd->flags |= AHD_SCB_CONFIG_USED;
+		}
+	}
+
+#if AHD_DEBUG
+	if (have_seeprom != 0
+	 && (ahd_debug & AHD_DUMP_SEEPROM) != 0) {
+		uint16_t *sc_data;
+		int	  i;
+
+		printf("%s: Seeprom Contents:", ahd_name(ahd));
+		sc_data = (uint16_t *)sc;
+		for (i = 0; i < (sizeof(*sc)); i += 2)
+			printf("\n\t0x%.4x", sc_data[i]);
+		printf("\n");
+	}
+#endif
+
+	if (!have_seeprom) {
+		if (bootverbose)
+			printf("%s: No SEEPROM available.\n", ahd_name(ahd));
+		ahd->flags |= AHD_USEDEFAULTS;
+		error = ahd_default_config(ahd);
+		adapter_control = CFAUTOTERM|CFSEAUTOTERM;
+		free(ahd->seep_config, M_DEVBUF);
+		ahd->seep_config = NULL;
+	} else {
+		error = ahd_parse_cfgdata(ahd, sc);
+		adapter_control = sc->adapter_control;
+	}
+	if (error != 0)
+		return (error);
+
+	ahd_configure_termination(ahd, adapter_control);
+
+	return (0);
+}
+
+static void
+ahd_configure_termination(struct ahd_softc *ahd, u_int adapter_control)
+{
+	int	 error;
+	u_int	 sxfrctl1;
+	uint8_t	 termctl;
+	uint32_t devconfig;
+
+	devconfig = ahd_pci_read_config(ahd->dev_softc, DEVCONFIG, /*bytes*/4);
+	devconfig &= ~STPWLEVEL;
+	if ((ahd->flags & AHD_STPWLEVEL_A) != 0)
+		devconfig |= STPWLEVEL;
+	if (bootverbose)
+		printf("%s: STPWLEVEL is %s\n",
+		       ahd_name(ahd), (devconfig & STPWLEVEL) ? "on" : "off");
+	ahd_pci_write_config(ahd->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
+ 
+	/* Make sure current sensing is off. */
+	if ((ahd->flags & AHD_CURRENT_SENSING) != 0) {
+		(void)ahd_write_flexport(ahd, FLXADDR_ROMSTAT_CURSENSECTL, 0);
+	}
+
+	/*
+	 * Read to sense.  Write to set.
+	 */
+	error = ahd_read_flexport(ahd, FLXADDR_TERMCTL, &termctl);
+	if ((adapter_control & CFAUTOTERM) == 0) {
+		if (bootverbose)
+			printf("%s: Manual Primary Termination\n",
+			       ahd_name(ahd));
+		termctl &= ~(FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH);
+		if ((adapter_control & CFSTERM) != 0)
+			termctl |= FLX_TERMCTL_ENPRILOW;
+		if ((adapter_control & CFWSTERM) != 0)
+			termctl |= FLX_TERMCTL_ENPRIHIGH;
+	} else if (error != 0) {
+		printf("%s: Primary Auto-Term Sensing failed! "
+		       "Using Defaults.\n", ahd_name(ahd));
+		termctl = FLX_TERMCTL_ENPRILOW|FLX_TERMCTL_ENPRIHIGH;
+	}
+
+	if ((adapter_control & CFSEAUTOTERM) == 0) {
+		if (bootverbose)
+			printf("%s: Manual Secondary Termination\n",
+			       ahd_name(ahd));
+		termctl &= ~(FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH);
+		if ((adapter_control & CFSELOWTERM) != 0)
+			termctl |= FLX_TERMCTL_ENSECLOW;
+		if ((adapter_control & CFSEHIGHTERM) != 0)
+			termctl |= FLX_TERMCTL_ENSECHIGH;
+	} else if (error != 0) {
+		printf("%s: Secondary Auto-Term Sensing failed! "
+		       "Using Defaults.\n", ahd_name(ahd));
+		termctl |= FLX_TERMCTL_ENSECLOW|FLX_TERMCTL_ENSECHIGH;
+	}
+
+	/*
+	 * Now set the termination based on what we found.
+	 */
+	sxfrctl1 = ahd_inb(ahd, SXFRCTL1) & ~STPWEN;
+	if ((termctl & FLX_TERMCTL_ENPRILOW) != 0) {
+		ahd->flags |= AHD_TERM_ENB_A;
+		sxfrctl1 |= STPWEN;
+	}
+	/* Must set the latch once in order to be effective. */
+	ahd_outb(ahd, SXFRCTL1, sxfrctl1|STPWEN);
+	ahd_outb(ahd, SXFRCTL1, sxfrctl1);
+
+	error = ahd_write_flexport(ahd, FLXADDR_TERMCTL, termctl);
+	if (error != 0) {
+		printf("%s: Unable to set termination settings!\n",
+		       ahd_name(ahd));
+	} else if (bootverbose) {
+		printf("%s: Primary High byte termination %sabled\n",
+		       ahd_name(ahd),
+		       (termctl & FLX_TERMCTL_ENPRIHIGH) ? "En" : "Dis");
+
+		printf("%s: Primary Low byte termination %sabled\n",
+		       ahd_name(ahd),
+		       (termctl & FLX_TERMCTL_ENPRILOW) ? "En" : "Dis");
+
+		printf("%s: Secondary High byte termination %sabled\n",
+		       ahd_name(ahd),
+		       (termctl & FLX_TERMCTL_ENSECHIGH) ? "En" : "Dis");
+
+		printf("%s: Secondary Low byte termination %sabled\n",
+		       ahd_name(ahd),
+		       (termctl & FLX_TERMCTL_ENSECLOW) ? "En" : "Dis");
+	}
+	return;
+}
+
+#define	DPE	0x80
+#define SSE	0x40
+#define	RMA	0x20
+#define	RTA	0x10
+#define STA	0x08
+#define DPR	0x01
+
+static const char *split_status_source[] =
+{
+	"DFF0",
+	"DFF1",
+	"OVLY",
+	"CMC",
+};
+
+static const char *pci_status_source[] =
+{
+	"DFF0",
+	"DFF1",
+	"SG",
+	"CMC",
+	"OVLY",
+	"NONE",
+	"MSI",
+	"TARG"
+};
+
+static const char *split_status_strings[] =
+{
+	"%s: Received split response in %s.\n",
+	"%s: Received split completion error message in %s\n",
+	"%s: Receive overrun in %s\n",
+	"%s: Count not complete in %s\n",
+	"%s: Split completion data bucket in %s\n",
+	"%s: Split completion address error in %s\n",
+	"%s: Split completion byte count error in %s\n",
+	"%s: Signaled Target-abort to early terminate a split in %s\n"
+};
+
+static const char *pci_status_strings[] =
+{
+	"%s: Data Parity Error has been reported via PERR# in %s\n",
+	"%s: Target initial wait state error in %s\n",
+	"%s: Split completion read data parity error in %s\n",
+	"%s: Split completion address attribute parity error in %s\n",
+	"%s: Received a Target Abort in %s\n",
+	"%s: Received a Master Abort in %s\n",
+	"%s: Signal System Error Detected in %s\n",
+	"%s: Address or Write Phase Parity Error Detected in %s.\n"
+};
+
+void
+ahd_pci_intr(struct ahd_softc *ahd)
+{
+	uint8_t		pci_status[8];
+	ahd_mode_state	saved_modes;
+	u_int		pci_status1;
+	u_int		intstat;
+	u_int		i;
+	u_int		reg;
+	
+	intstat = ahd_inb(ahd, INTSTAT);
+
+	if ((intstat & SPLTINT) != 0)
+		ahd_pci_split_intr(ahd, intstat);
+
+	if ((intstat & PCIINT) == 0)
+		return;
+
+	printf("%s: PCI error Interrupt\n", ahd_name(ahd));
+	saved_modes = ahd_save_modes(ahd);
+	ahd_dump_card_state(ahd);
+	ahd_set_modes(ahd, AHD_MODE_CFG, AHD_MODE_CFG);
+	for (i = 0, reg = DF0PCISTAT; i < 8; i++, reg++) {
+
+		if (i == 5)
+			continue;
+		pci_status[i] = ahd_inb(ahd, reg);
+		/* Clear latched errors.  So our interrupt deasserts. */
+		ahd_outb(ahd, reg, pci_status[i]);
+	}
+
+	for (i = 0; i < 8; i++) {
+		u_int bit;
+	
+		if (i == 5)
+			continue;
+
+		for (bit = 0; bit < 8; bit++) {
+
+			if ((pci_status[i] & (0x1 << bit)) != 0) {
+				static const char *s;
+
+				s = pci_status_strings[bit];
+				if (i == 7/*TARG*/ && bit == 3)
+					s = "%s: Signaled Target Abort\n";
+				printf(s, ahd_name(ahd), pci_status_source[i]);
+			}
+		}	
+	}
+	pci_status1 = ahd_pci_read_config(ahd->dev_softc,
+					  PCIR_STATUS + 1, /*bytes*/1);
+	ahd_pci_write_config(ahd->dev_softc, PCIR_STATUS + 1,
+			     pci_status1, /*bytes*/1);
+	ahd_restore_modes(ahd, saved_modes);
+	ahd_outb(ahd, CLRINT, CLRPCIINT);
+	ahd_unpause(ahd);
+}
+
+static void
+ahd_pci_split_intr(struct ahd_softc *ahd, u_int intstat)
+{
+	uint8_t		split_status[4];
+	uint8_t		split_status1[4];
+	uint8_t		sg_split_status[2];
+	uint8_t		sg_split_status1[2];
+	ahd_mode_state	saved_modes;
+	u_int		i;
+	uint16_t	pcix_status;
+
+	/*
+	 * Check for splits in all modes.  Modes 0 and 1
+	 * additionally have SG engine splits to look at.
+	 */
+	pcix_status = ahd_pci_read_config(ahd->dev_softc, PCIXR_STATUS,
+					  /*bytes*/2);
+	printf("%s: PCI Split Interrupt - PCI-X status = 0x%x\n",
+	       ahd_name(ahd), pcix_status);
+	saved_modes = ahd_save_modes(ahd);
+	for (i = 0; i < 4; i++) {
+		ahd_set_modes(ahd, i, i);
+
+		split_status[i] = ahd_inb(ahd, DCHSPLTSTAT0);
+		split_status1[i] = ahd_inb(ahd, DCHSPLTSTAT1);
+		/* Clear latched errors.  So our interrupt deasserts. */
+		ahd_outb(ahd, DCHSPLTSTAT0, split_status[i]);
+		ahd_outb(ahd, DCHSPLTSTAT1, split_status1[i]);
+		if (i > 1)
+			continue;
+		sg_split_status[i] = ahd_inb(ahd, SGSPLTSTAT0);
+		sg_split_status1[i] = ahd_inb(ahd, SGSPLTSTAT1);
+		/* Clear latched errors.  So our interrupt deasserts. */
+		ahd_outb(ahd, SGSPLTSTAT0, sg_split_status[i]);
+		ahd_outb(ahd, SGSPLTSTAT1, sg_split_status1[i]);
+	}
+
+	for (i = 0; i < 4; i++) {
+		u_int bit;
+
+		for (bit = 0; bit < 8; bit++) {
+
+			if ((split_status[i] & (0x1 << bit)) != 0) {
+				static const char *s;
+
+				s = split_status_strings[bit];
+				printf(s, ahd_name(ahd),
+				       split_status_source[i]);
+			}
+
+			if (i > 1)
+				continue;
+
+			if ((sg_split_status[i] & (0x1 << bit)) != 0) {
+				static const char *s;
+
+				s = split_status_strings[bit];
+				printf(s, ahd_name(ahd), "SG");
+			}
+		}
+	}
+	/*
+	 * Clear PCI-X status bits.
+	 */
+	ahd_pci_write_config(ahd->dev_softc, PCIXR_STATUS,
+			     pcix_status, /*bytes*/2);
+	ahd_outb(ahd, CLRINT, CLRSPLTINT);
+	ahd_restore_modes(ahd, saved_modes);
+}
+
+static int
+ahd_aic7901_setup(struct ahd_softc *ahd)
+{
+
+	ahd->chip = AHD_AIC7901;
+	ahd->features = AHD_AIC7901_FE;
+	return (ahd_aic790X_setup(ahd));
+}
+
+static int
+ahd_aic7901A_setup(struct ahd_softc *ahd)
+{
+
+	ahd->chip = AHD_AIC7901A;
+	ahd->features = AHD_AIC7901A_FE;
+	return (ahd_aic790X_setup(ahd));
+}
+
+static int
+ahd_aic7902_setup(struct ahd_softc *ahd)
+{
+	ahd->chip = AHD_AIC7902;
+	ahd->features = AHD_AIC7902_FE;
+	return (ahd_aic790X_setup(ahd));
+}
+
+static int
+ahd_aic790X_setup(struct ahd_softc *ahd)
+{
+	ahd_dev_softc_t pci;
+	u_int rev;
+
+	pci = ahd->dev_softc;
+	rev = ahd_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev < ID_AIC7902_PCI_REV_A4) {
+		printf("%s: Unable to attach to unsupported chip revision %d\n",
+		       ahd_name(ahd), rev);
+		ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2);
+		return (ENXIO);
+	}
+	ahd->channel = ahd_get_pci_function(pci) + 'A';
+	if (rev < ID_AIC7902_PCI_REV_B0) {
+		/*
+		 * Enable A series workarounds.
+		 */
+		ahd->bugs |= AHD_SENT_SCB_UPDATE_BUG|AHD_ABORT_LQI_BUG
+			  |  AHD_PKT_BITBUCKET_BUG|AHD_LONG_SETIMO_BUG
+			  |  AHD_NLQICRC_DELAYED_BUG|AHD_SCSIRST_BUG
+			  |  AHD_LQO_ATNO_BUG|AHD_AUTOFLUSH_BUG
+			  |  AHD_CLRLQO_AUTOCLR_BUG|AHD_PCIX_MMAPIO_BUG
+			  |  AHD_PCIX_CHIPRST_BUG|AHD_PCIX_SCBRAM_RD_BUG
+			  |  AHD_PKTIZED_STATUS_BUG|AHD_PKT_LUN_BUG
+			  |  AHD_MDFF_WSCBPTR_BUG|AHD_REG_SLOW_SETTLE_BUG
+			  |  AHD_SET_MODE_BUG|AHD_BUSFREEREV_BUG
+			  |  AHD_NONPACKFIFO_BUG|AHD_PACED_NEGTABLE_BUG
+			  |  AHD_FAINT_LED_BUG;
+
+		/*
+		 * IO Cell paramter setup.
+		 */
+		AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
+
+		if ((ahd->flags & AHD_HP_BOARD) == 0)
+			AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVA);
+	} else {
+		u_int devconfig1;
+
+		ahd->features |= AHD_RTI|AHD_NEW_IOCELL_OPTS
+			      |  AHD_NEW_DFCNTRL_OPTS|AHD_FAST_CDB_DELIVERY;
+		ahd->bugs |= AHD_LQOOVERRUN_BUG|AHD_EARLY_REQ_BUG;
+
+		/*
+		 * Some issues have been resolved in the 7901B.
+		 */
+		if ((ahd->features & AHD_MULTI_FUNC) != 0)
+			ahd->bugs |= AHD_INTCOLLISION_BUG|AHD_ABORT_LQI_BUG;
+
+		/*
+		 * IO Cell paramter setup.
+		 */
+		AHD_SET_PRECOMP(ahd, AHD_PRECOMP_CUTBACK_29);
+		AHD_SET_SLEWRATE(ahd, AHD_SLEWRATE_DEF_REVB);
+		AHD_SET_AMPLITUDE(ahd, AHD_AMPLITUDE_DEF);
+
+		/*
+		 * Set the PREQDIS bit for H2B which disables some workaround
+		 * that doesn't work on regular PCI busses.
+		 * XXX - Find out exactly what this does from the hardware
+		 * 	 folks!
+		 */
+		devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
+		ahd_pci_write_config(pci, DEVCONFIG1,
+				     devconfig1|PREQDIS, /*bytes*/1);
+		devconfig1 = ahd_pci_read_config(pci, DEVCONFIG1, /*bytes*/1);
+	}
+
+	return (0);
+}
diff --git a/drivers/scsi/aic7xxx/aic79xx_pci.h b/drivers/scsi/aic7xxx/aic79xx_pci.h
new file mode 100644
index 0000000..b5cfeab
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.h
@@ -0,0 +1,70 @@
+/*
+ * Adaptec AIC79xx device driver for Linux.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id$
+ *
+ */
+#ifndef _AIC79XX_PCI_H_
+#define _AIC79XX_PCI_H_
+
+#define ID_ALL_MASK			0xFFFFFFFFFFFFFFFFull
+#define ID_ALL_IROC_MASK		0xFF7FFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK		0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK		0xFFF0FFFF00000000ull
+#define ID_9005_GENERIC_IROC_MASK	0xFF70FFFF00000000ull
+
+#define ID_AIC7901			0x800F9005FFFF9005ull
+#define ID_AHA_29320A			0x8000900500609005ull
+#define ID_AHA_29320ALP			0x8017900500449005ull
+
+#define ID_AIC7901A			0x801E9005FFFF9005ull
+#define ID_AHA_29320			0x8012900500429005ull
+#define ID_AHA_29320B			0x8013900500439005ull
+#define ID_AHA_29320LP			0x8014900500449005ull
+
+#define ID_AIC7902			0x801F9005FFFF9005ull
+#define ID_AIC7902_B			0x801D9005FFFF9005ull
+#define ID_AHA_39320			0x8010900500409005ull
+#define ID_AHA_39320_B			0x8015900500409005ull
+#define ID_AHA_39320A			0x8016900500409005ull
+#define ID_AHA_39320D			0x8011900500419005ull
+#define ID_AHA_39320D_B			0x801C900500419005ull
+#define ID_AHA_39320D_HP		0x8011900500AC0E11ull
+#define ID_AHA_39320D_B_HP		0x801C900500AC0E11ull
+
+#endif /* _AIC79XX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
new file mode 100644
index 0000000..e01cd61
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
+ * sym driver.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#19 $
+ */
+#include "aic79xx_osm.h"
+#include "aic79xx_inline.h"
+
+static void	copy_mem_info(struct info_str *info, char *data, int len);
+static int	copy_info(struct info_str *info, char *fmt, ...);
+static void	ahd_dump_target_state(struct ahd_softc *ahd,
+				      struct info_str *info,
+				      u_int our_id, char channel,
+				      u_int target_id, u_int target_offset);
+static void	ahd_dump_device_state(struct info_str *info,
+				      struct ahd_linux_device *dev);
+static int	ahd_proc_write_seeprom(struct ahd_softc *ahd,
+				       char *buffer, int length);
+
+static void
+copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->offset + info->length)
+		len = info->offset + info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+		off_t partial;
+
+		partial = info->offset - info->pos;
+		data += partial;
+		info->pos += partial;
+		len  -= partial;
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer, data, len);
+		info->pos += len;
+		info->buffer += len;
+	}
+}
+
+static int
+copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[256];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return (len);
+}
+
+void
+ahd_format_transinfo(struct info_str *info, struct ahd_transinfo *tinfo)
+{
+	u_int speed;
+	u_int freq;
+	u_int mb;
+
+	if (tinfo->period == AHD_PERIOD_UNKNOWN) {
+		copy_info(info, "Renegotiation Pending\n");
+		return;
+	}
+        speed = 3300;
+        freq = 0;
+	if (tinfo->offset != 0) {
+		freq = aic_calc_syncsrate(tinfo->period);
+		speed = freq;
+	}
+	speed *= (0x01 << tinfo->width);
+        mb = speed / 1000;
+        if (mb > 0)
+		copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
+        else
+		copy_info(info, "%dKB/s transfers", speed);
+
+	if (freq != 0) {
+		int	printed_options;
+
+		printed_options = 0;
+		copy_info(info, " (%d.%03dMHz", freq / 1000, freq % 1000);
+		if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
+			copy_info(info, " RDSTRM");
+			printed_options++;
+		}
+		if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
+			copy_info(info, "%s", printed_options ? "|DT" : " DT");
+			printed_options++;
+		}
+		if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+			copy_info(info, "%s", printed_options ? "|IU" : " IU");
+			printed_options++;
+		}
+		if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) {
+			copy_info(info, "%s",
+				  printed_options ? "|RTI" : " RTI");
+			printed_options++;
+		}
+		if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
+			copy_info(info, "%s",
+				  printed_options ? "|QAS" : " QAS");
+			printed_options++;
+		}
+	}
+
+	if (tinfo->width > 0) {
+		if (freq != 0) {
+			copy_info(info, ", ");
+		} else {
+			copy_info(info, " (");
+		}
+		copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
+	} else if (freq != 0) {
+		copy_info(info, ")");
+	}
+	copy_info(info, "\n");
+}
+
+static void
+ahd_dump_target_state(struct ahd_softc *ahd, struct info_str *info,
+		      u_int our_id, char channel, u_int target_id,
+		      u_int target_offset)
+{
+	struct	ahd_linux_target *targ;
+	struct	ahd_initiator_tinfo *tinfo;
+	struct	ahd_tmode_tstate *tstate;
+	int	lun;
+
+	tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
+				    target_id, &tstate);
+	copy_info(info, "Target %d Negotiation Settings\n", target_id);
+	copy_info(info, "\tUser: ");
+	ahd_format_transinfo(info, &tinfo->user);
+	targ = ahd->platform_data->targets[target_offset];
+	if (targ == NULL)
+		return;
+
+	copy_info(info, "\tGoal: ");
+	ahd_format_transinfo(info, &tinfo->goal);
+	copy_info(info, "\tCurr: ");
+	ahd_format_transinfo(info, &tinfo->curr);
+	copy_info(info, "\tTransmission Errors %ld\n", targ->errors_detected);
+
+	for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
+		struct ahd_linux_device *dev;
+
+		dev = targ->devices[lun];
+
+		if (dev == NULL)
+			continue;
+
+		ahd_dump_device_state(info, dev);
+	}
+}
+
+static void
+ahd_dump_device_state(struct info_str *info, struct ahd_linux_device *dev)
+{
+	copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
+		  dev->target->channel + 'A', dev->target->target, dev->lun);
+
+	copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
+	copy_info(info, "\t\tCommands Active %d\n", dev->active);
+	copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
+	copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
+	copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
+}
+
+static int
+ahd_proc_write_seeprom(struct ahd_softc *ahd, char *buffer, int length)
+{
+	ahd_mode_state saved_modes;
+	int have_seeprom;
+	u_long s;
+	int paused;
+	int written;
+
+	/* Default to failure. */
+	written = -EINVAL;
+	ahd_lock(ahd, &s);
+	paused = ahd_is_paused(ahd);
+	if (!paused)
+		ahd_pause(ahd);
+
+	saved_modes = ahd_save_modes(ahd);
+	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
+	if (length != sizeof(struct seeprom_config)) {
+		printf("ahd_proc_write_seeprom: incorrect buffer size\n");
+		goto done;
+	}
+
+	have_seeprom = ahd_verify_cksum((struct seeprom_config*)buffer);
+	if (have_seeprom == 0) {
+		printf("ahd_proc_write_seeprom: cksum verification failed\n");
+		goto done;
+	}
+
+	have_seeprom = ahd_acquire_seeprom(ahd);
+	if (!have_seeprom) {
+		printf("ahd_proc_write_seeprom: No Serial EEPROM\n");
+		goto done;
+	} else {
+		u_int start_addr;
+
+		if (ahd->seep_config == NULL) {
+			ahd->seep_config = malloc(sizeof(*ahd->seep_config),
+						  M_DEVBUF, M_NOWAIT);
+			if (ahd->seep_config == NULL) {
+				printf("aic79xx: Unable to allocate serial "
+				       "eeprom buffer.  Write failing\n");
+				goto done;
+			}
+		}
+		printf("aic79xx: Writing Serial EEPROM\n");
+		start_addr = 32 * (ahd->channel - 'A');
+		ahd_write_seeprom(ahd, (u_int16_t *)buffer, start_addr,
+				  sizeof(struct seeprom_config)/2);
+		ahd_read_seeprom(ahd, (uint16_t *)ahd->seep_config,
+				 start_addr, sizeof(struct seeprom_config)/2,
+				 /*ByteStream*/FALSE);
+		ahd_release_seeprom(ahd);
+		written = length;
+	}
+
+done:
+	ahd_restore_modes(ahd, saved_modes);
+	if (!paused)
+		ahd_unpause(ahd);
+	ahd_unlock(ahd, &s);
+	return (written);
+}
+/*
+ * Return information to handle /proc support for the driver.
+ */
+int
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ahd_linux_proc_info(char *buffer, char **start, off_t offset,
+		    int length, int hostno, int inout)
+#else
+ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+		    off_t offset, int length, int inout)
+#endif
+{
+	struct	ahd_softc *ahd;
+	struct	info_str info;
+	char	ahd_info[256];
+	u_long	l;
+	u_int	max_targ;
+	u_int	i;
+	int	retval;
+
+	retval = -EINVAL;
+	ahd_list_lock(&l);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	TAILQ_FOREACH(ahd, &ahd_tailq, links) {
+		if (ahd->platform_data->host->host_no == hostno)
+			break;
+	}
+#else
+	ahd = ahd_find_softc(*(struct ahd_softc **)shost->hostdata);
+#endif
+
+	if (ahd == NULL)
+		goto done;
+
+	 /* Has data been written to the file? */ 
+	if (inout == TRUE) {
+		retval = ahd_proc_write_seeprom(ahd, buffer, length);
+		goto done;
+	}
+
+	if (start)
+		*start = buffer;
+
+	info.buffer	= buffer;
+	info.length	= length;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Adaptec AIC79xx driver version: %s\n",
+		  AIC79XX_DRIVER_VERSION);
+	copy_info(&info, "%s\n", ahd->description);
+	ahd_controller_info(ahd, ahd_info);
+	copy_info(&info, "%s\n", ahd_info);
+	copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+		  ahd->scb_data.numscbs, AHD_NSEG);
+
+	max_targ = 15;
+
+	if (ahd->seep_config == NULL)
+		copy_info(&info, "No Serial EEPROM\n");
+	else {
+		copy_info(&info, "Serial EEPROM:\n");
+		for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) {
+			if (((i % 8) == 0) && (i != 0)) {
+				copy_info(&info, "\n");
+			}
+			copy_info(&info, "0x%.4x ",
+				  ((uint16_t*)ahd->seep_config)[i]);
+		}
+		copy_info(&info, "\n");
+	}
+	copy_info(&info, "\n");
+
+	if ((ahd->features & AHD_WIDE) == 0)
+		max_targ = 7;
+
+	for (i = 0; i <= max_targ; i++) {
+
+		ahd_dump_target_state(ahd, &info, ahd->our_id, 'A',
+				      /*target_id*/i, /*target_offset*/i);
+	}
+	retval = info.pos > info.offset ? info.pos - info.offset : 0;
+done:
+	ahd_list_unlock(&l);
+	return (retval);
+}
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
new file mode 100644
index 0000000..c01ac39
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
@@ -0,0 +1,3776 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ */
+typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
+typedef struct ahd_reg_parse_entry {
+	char	*name;
+	uint8_t	 value;
+	uint8_t	 mask;
+} ahd_reg_parse_entry_t;
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_mode_ptr_print;
+#else
+#define ahd_mode_ptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MODE_PTR", 0x00, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intstat_print;
+#else
+#define ahd_intstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTSTAT", 0x01, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqintcode_print;
+#else
+#define ahd_seqintcode_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQINTCODE", 0x02, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrint_print;
+#else
+#define ahd_clrint_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRINT", 0x03, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_error_print;
+#else
+#define ahd_error_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ERROR", 0x04, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrerr_print;
+#else
+#define ahd_clrerr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRERR", 0x04, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hcntrl_print;
+#else
+#define ahd_hcntrl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HCNTRL", 0x05, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hnscb_qoff_print;
+#else
+#define ahd_hnscb_qoff_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HNSCB_QOFF", 0x06, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hescb_qoff_print;
+#else
+#define ahd_hescb_qoff_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HESCB_QOFF", 0x08, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hs_mailbox_print;
+#else
+#define ahd_hs_mailbox_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HS_MAILBOX", 0x0b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrseqintstat_print;
+#else
+#define ahd_clrseqintstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqintstat_print;
+#else
+#define ahd_seqintstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQINTSTAT", 0x0c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_swtimer_print;
+#else
+#define ahd_swtimer_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SWTIMER", 0x0e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_snscb_qoff_print;
+#else
+#define ahd_snscb_qoff_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SNSCB_QOFF", 0x10, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sescb_qoff_print;
+#else
+#define ahd_sescb_qoff_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SESCB_QOFF", 0x12, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sdscb_qoff_print;
+#else
+#define ahd_sdscb_qoff_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SDSCB_QOFF", 0x14, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qoff_ctlsta_print;
+#else
+#define ahd_qoff_ctlsta_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QOFF_CTLSTA", 0x16, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intctl_print;
+#else
+#define ahd_intctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTCTL", 0x18, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfcntrl_print;
+#else
+#define ahd_dfcntrl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFCNTRL", 0x19, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dscommand0_print;
+#else
+#define ahd_dscommand0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSCOMMAND0", 0x19, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfstatus_print;
+#else
+#define ahd_dfstatus_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFSTATUS", 0x1a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sg_cache_shadow_print;
+#else
+#define ahd_sg_cache_shadow_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SG_CACHE_SHADOW", 0x1b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_arbctl_print;
+#else
+#define ahd_arbctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ARBCTL", 0x1b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sg_cache_pre_print;
+#else
+#define ahd_sg_cache_pre_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SG_CACHE_PRE", 0x1b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqin_print;
+#else
+#define ahd_lqin_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQIN", 0x20, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_typeptr_print;
+#else
+#define ahd_typeptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TYPEPTR", 0x20, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_tagptr_print;
+#else
+#define ahd_tagptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TAGPTR", 0x21, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lunptr_print;
+#else
+#define ahd_lunptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LUNPTR", 0x22, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_datalenptr_print;
+#else
+#define ahd_datalenptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DATALENPTR", 0x23, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_statlenptr_print;
+#else
+#define ahd_statlenptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "STATLENPTR", 0x24, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmdlenptr_print;
+#else
+#define ahd_cmdlenptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMDLENPTR", 0x25, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_attrptr_print;
+#else
+#define ahd_attrptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ATTRPTR", 0x26, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flagptr_print;
+#else
+#define ahd_flagptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLAGPTR", 0x27, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmdptr_print;
+#else
+#define ahd_cmdptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMDPTR", 0x28, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qnextptr_print;
+#else
+#define ahd_qnextptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QNEXTPTR", 0x29, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_idptr_print;
+#else
+#define ahd_idptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "IDPTR", 0x2a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_abrtbyteptr_print;
+#else
+#define ahd_abrtbyteptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ABRTBYTEPTR", 0x2b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_abrtbitptr_print;
+#else
+#define ahd_abrtbitptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ABRTBITPTR", 0x2c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_maxcmdbytes_print;
+#else
+#define ahd_maxcmdbytes_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MAXCMDBYTES", 0x2d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_maxcmd2rcv_print;
+#else
+#define ahd_maxcmd2rcv_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MAXCMD2RCV", 0x2e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_shortthresh_print;
+#else
+#define ahd_shortthresh_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHORTTHRESH", 0x2f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lunlen_print;
+#else
+#define ahd_lunlen_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LUNLEN", 0x30, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cdblimit_print;
+#else
+#define ahd_cdblimit_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CDBLIMIT", 0x31, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_maxcmd_print;
+#else
+#define ahd_maxcmd_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MAXCMD", 0x32, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_maxcmdcnt_print;
+#else
+#define ahd_maxcmdcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MAXCMDCNT", 0x33, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqrsvd01_print;
+#else
+#define ahd_lqrsvd01_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQRSVD01", 0x34, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqrsvd16_print;
+#else
+#define ahd_lqrsvd16_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQRSVD16", 0x35, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqrsvd17_print;
+#else
+#define ahd_lqrsvd17_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQRSVD17", 0x36, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmdrsvd0_print;
+#else
+#define ahd_cmdrsvd0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMDRSVD0", 0x37, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqctl0_print;
+#else
+#define ahd_lqctl0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQCTL0", 0x38, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqctl1_print;
+#else
+#define ahd_lqctl1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQCTL1", 0x38, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsbist0_print;
+#else
+#define ahd_scsbist0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSBIST0", 0x39, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqctl2_print;
+#else
+#define ahd_lqctl2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQCTL2", 0x39, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsbist1_print;
+#else
+#define ahd_scsbist1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSBIST1", 0x3a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsiseq0_print;
+#else
+#define ahd_scsiseq0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSISEQ0", 0x3a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsiseq1_print;
+#else
+#define ahd_scsiseq1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSISEQ1", 0x3b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sxfrctl0_print;
+#else
+#define ahd_sxfrctl0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SXFRCTL0", 0x3c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_businitid_print;
+#else
+#define ahd_businitid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BUSINITID", 0x3c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dlcount_print;
+#else
+#define ahd_dlcount_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DLCOUNT", 0x3c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sxfrctl1_print;
+#else
+#define ahd_sxfrctl1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SXFRCTL1", 0x3d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_bustargid_print;
+#else
+#define ahd_bustargid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BUSTARGID", 0x3e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sxfrctl2_print;
+#else
+#define ahd_sxfrctl2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SXFRCTL2", 0x3e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dffstat_print;
+#else
+#define ahd_dffstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFFSTAT", 0x3f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsisigo_print;
+#else
+#define ahd_scsisigo_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSISIGO", 0x40, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_multargid_print;
+#else
+#define ahd_multargid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MULTARGID", 0x40, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsisigi_print;
+#else
+#define ahd_scsisigi_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSISIGI", 0x41, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsiphase_print;
+#else
+#define ahd_scsiphase_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSIPHASE", 0x42, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsidat0_img_print;
+#else
+#define ahd_scsidat0_img_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSIDAT0_IMG", 0x43, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsidat_print;
+#else
+#define ahd_scsidat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSIDAT", 0x44, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsibus_print;
+#else
+#define ahd_scsibus_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSIBUS", 0x46, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_targidin_print;
+#else
+#define ahd_targidin_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TARGIDIN", 0x48, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_selid_print;
+#else
+#define ahd_selid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SELID", 0x49, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sblkctl_print;
+#else
+#define ahd_sblkctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SBLKCTL", 0x4a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_optionmode_print;
+#else
+#define ahd_optionmode_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OPTIONMODE", 0x4a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat0_print;
+#else
+#define ahd_sstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT0", 0x4b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrsint0_print;
+#else
+#define ahd_clrsint0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT0", 0x4b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_simode0_print;
+#else
+#define ahd_simode0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SIMODE0", 0x4b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrsint1_print;
+#else
+#define ahd_clrsint1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT1", 0x4c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat1_print;
+#else
+#define ahd_sstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT1", 0x4c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat2_print;
+#else
+#define ahd_sstat2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT2", 0x4d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrsint2_print;
+#else
+#define ahd_clrsint2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT2", 0x4d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_simode2_print;
+#else
+#define ahd_simode2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SIMODE2", 0x4d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_perrdiag_print;
+#else
+#define ahd_perrdiag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PERRDIAG", 0x4e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqistate_print;
+#else
+#define ahd_lqistate_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQISTATE", 0x4e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_soffcnt_print;
+#else
+#define ahd_soffcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SOFFCNT", 0x4f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqostate_print;
+#else
+#define ahd_lqostate_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOSTATE", 0x4f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqistat0_print;
+#else
+#define ahd_lqistat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQISTAT0", 0x50, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrlqiint0_print;
+#else
+#define ahd_clrlqiint0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRLQIINT0", 0x50, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqimode0_print;
+#else
+#define ahd_lqimode0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQIMODE0", 0x50, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqimode1_print;
+#else
+#define ahd_lqimode1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQIMODE1", 0x51, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqistat1_print;
+#else
+#define ahd_lqistat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQISTAT1", 0x51, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrlqiint1_print;
+#else
+#define ahd_clrlqiint1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRLQIINT1", 0x51, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqistat2_print;
+#else
+#define ahd_lqistat2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQISTAT2", 0x52, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sstat3_print;
+#else
+#define ahd_sstat3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SSTAT3", 0x53, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_simode3_print;
+#else
+#define ahd_simode3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SIMODE3", 0x53, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrsint3_print;
+#else
+#define ahd_clrsint3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSINT3", 0x53, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode0_print;
+#else
+#define ahd_lqomode0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE0", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqostat0_print;
+#else
+#define ahd_lqostat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOSTAT0", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrlqoint0_print;
+#else
+#define ahd_clrlqoint0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRLQOINT0", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqostat1_print;
+#else
+#define ahd_lqostat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOSTAT1", 0x55, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrlqoint1_print;
+#else
+#define ahd_clrlqoint1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRLQOINT1", 0x55, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqomode1_print;
+#else
+#define ahd_lqomode1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOMODE1", 0x55, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqostat2_print;
+#else
+#define ahd_lqostat2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOSTAT2", 0x56, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_os_space_cnt_print;
+#else
+#define ahd_os_space_cnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OS_SPACE_CNT", 0x56, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_simode1_print;
+#else
+#define ahd_simode1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SIMODE1", 0x57, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_gsfifo_print;
+#else
+#define ahd_gsfifo_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "GSFIFO", 0x58, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dffsxfrctl_print;
+#else
+#define ahd_dffsxfrctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFFSXFRCTL", 0x5a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lqoscsctl_print;
+#else
+#define ahd_lqoscsctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LQOSCSCTL", 0x5a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_nextscb_print;
+#else
+#define ahd_nextscb_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEXTSCB", 0x5a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_clrseqintsrc_print;
+#else
+#define ahd_clrseqintsrc_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CLRSEQINTSRC", 0x5b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqintsrc_print;
+#else
+#define ahd_seqintsrc_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQINTSRC", 0x5b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_currscb_print;
+#else
+#define ahd_currscb_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CURRSCB", 0x5c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqimode_print;
+#else
+#define ahd_seqimode_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQIMODE", 0x5c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_mdffstat_print;
+#else
+#define ahd_mdffstat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MDFFSTAT", 0x5d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_crccontrol_print;
+#else
+#define ahd_crccontrol_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CRCCONTROL", 0x5d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfftag_print;
+#else
+#define ahd_dfftag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFFTAG", 0x5e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lastscb_print;
+#else
+#define ahd_lastscb_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LASTSCB", 0x5e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsitest_print;
+#else
+#define ahd_scsitest_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSITEST", 0x5e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_iopdnctl_print;
+#else
+#define ahd_iopdnctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "IOPDNCTL", 0x5f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_shaddr_print;
+#else
+#define ahd_shaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHADDR", 0x60, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_negoaddr_print;
+#else
+#define ahd_negoaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEGOADDR", 0x60, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dgrpcrci_print;
+#else
+#define ahd_dgrpcrci_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DGRPCRCI", 0x60, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_negperiod_print;
+#else
+#define ahd_negperiod_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEGPERIOD", 0x61, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_packcrci_print;
+#else
+#define ahd_packcrci_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PACKCRCI", 0x62, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_negoffset_print;
+#else
+#define ahd_negoffset_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEGOFFSET", 0x62, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_negppropts_print;
+#else
+#define ahd_negppropts_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEGPPROPTS", 0x63, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_negconopts_print;
+#else
+#define ahd_negconopts_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEGCONOPTS", 0x64, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_annexcol_print;
+#else
+#define ahd_annexcol_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ANNEXCOL", 0x65, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scschkn_print;
+#else
+#define ahd_scschkn_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSCHKN", 0x66, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_annexdat_print;
+#else
+#define ahd_annexdat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ANNEXDAT", 0x66, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_iownid_print;
+#else
+#define ahd_iownid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "IOWNID", 0x67, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll960ctl0_print;
+#else
+#define ahd_pll960ctl0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL960CTL0", 0x68, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_shcnt_print;
+#else
+#define ahd_shcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHCNT", 0x68, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_townid_print;
+#else
+#define ahd_townid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TOWNID", 0x69, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll960ctl1_print;
+#else
+#define ahd_pll960ctl1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL960CTL1", 0x69, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll960cnt0_print;
+#else
+#define ahd_pll960cnt0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL960CNT0", 0x6a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_xsig_print;
+#else
+#define ahd_xsig_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "XSIG", 0x6a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seloid_print;
+#else
+#define ahd_seloid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SELOID", 0x6b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll400ctl0_print;
+#else
+#define ahd_pll400ctl0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL400CTL0", 0x6c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_fairness_print;
+#else
+#define ahd_fairness_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FAIRNESS", 0x6c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll400ctl1_print;
+#else
+#define ahd_pll400ctl1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL400CTL1", 0x6d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pll400cnt0_print;
+#else
+#define ahd_pll400cnt0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLL400CNT0", 0x6e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_unfairness_print;
+#else
+#define ahd_unfairness_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "UNFAIRNESS", 0x6e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_haddr_print;
+#else
+#define ahd_haddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HADDR", 0x70, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_plldelay_print;
+#else
+#define ahd_plldelay_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PLLDELAY", 0x70, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hodmaadr_print;
+#else
+#define ahd_hodmaadr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HODMAADR", 0x70, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hodmacnt_print;
+#else
+#define ahd_hodmacnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HODMACNT", 0x78, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hcnt_print;
+#else
+#define ahd_hcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HCNT", 0x78, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_hodmaen_print;
+#else
+#define ahd_hodmaen_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "HODMAEN", 0x7a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sghaddr_print;
+#else
+#define ahd_sghaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHADDR", 0x7c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scbhaddr_print;
+#else
+#define ahd_scbhaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCBHADDR", 0x7c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sghcnt_print;
+#else
+#define ahd_sghcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGHCNT", 0x84, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scbhcnt_print;
+#else
+#define ahd_scbhcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCBHCNT", 0x84, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dff_thrsh_print;
+#else
+#define ahd_dff_thrsh_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFF_THRSH", 0x88, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_romaddr_print;
+#else
+#define ahd_romaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ROMADDR", 0x8a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_romcntrl_print;
+#else
+#define ahd_romcntrl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ROMCNTRL", 0x8d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_romdata_print;
+#else
+#define ahd_romdata_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ROMDATA", 0x8e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcrxmsg0_print;
+#else
+#define ahd_cmcrxmsg0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCRXMSG0", 0x90, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_roenable_print;
+#else
+#define ahd_roenable_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ROENABLE", 0x90, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg0_print;
+#else
+#define ahd_ovlyrxmsg0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG0", 0x90, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchrxmsg0_print;
+#else
+#define ahd_dchrxmsg0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG0", 0x90, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg1_print;
+#else
+#define ahd_ovlyrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG1", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_nsenable_print;
+#else
+#define ahd_nsenable_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NSENABLE", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchrxmsg1_print;
+#else
+#define ahd_dchrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG1", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcrxmsg1_print;
+#else
+#define ahd_cmcrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCRXMSG1", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchrxmsg2_print;
+#else
+#define ahd_dchrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG2", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg2_print;
+#else
+#define ahd_ovlyrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG2", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcrxmsg2_print;
+#else
+#define ahd_cmcrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCRXMSG2", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ost_print;
+#else
+#define ahd_ost_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OST", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchrxmsg3_print;
+#else
+#define ahd_dchrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHRXMSG3", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcrxmsg3_print;
+#else
+#define ahd_cmcrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCRXMSG3", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_pcixctl_print;
+#else
+#define ahd_pcixctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PCIXCTL", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyrxmsg3_print;
+#else
+#define ahd_ovlyrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYRXMSG3", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyseqbcnt_print;
+#else
+#define ahd_ovlyseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYSEQBCNT", 0x94, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcseqbcnt_print;
+#else
+#define ahd_cmcseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSEQBCNT", 0x94, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchseqbcnt_print;
+#else
+#define ahd_dchseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHSEQBCNT", 0x94, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcspltstat0_print;
+#else
+#define ahd_cmcspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyspltstat0_print;
+#else
+#define ahd_ovlyspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchspltstat0_print;
+#else
+#define ahd_dchspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHSPLTSTAT0", 0x96, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dchspltstat1_print;
+#else
+#define ahd_dchspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DCHSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcspltstat1_print;
+#else
+#define ahd_cmcspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyspltstat1_print;
+#else
+#define ahd_ovlyspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYSPLTSTAT1", 0x97, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgrxmsg0_print;
+#else
+#define ahd_sgrxmsg0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGRXMSG0", 0x98, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutadr0_print;
+#else
+#define ahd_slvspltoutadr0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTADR0", 0x98, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgrxmsg1_print;
+#else
+#define ahd_sgrxmsg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGRXMSG1", 0x99, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutadr1_print;
+#else
+#define ahd_slvspltoutadr1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTADR1", 0x99, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgrxmsg2_print;
+#else
+#define ahd_sgrxmsg2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGRXMSG2", 0x9a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutadr2_print;
+#else
+#define ahd_slvspltoutadr2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTADR2", 0x9a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgrxmsg3_print;
+#else
+#define ahd_sgrxmsg3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGRXMSG3", 0x9b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutadr3_print;
+#else
+#define ahd_slvspltoutadr3_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTADR3", 0x9b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgseqbcnt_print;
+#else
+#define ahd_sgseqbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGSEQBCNT", 0x9c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutattr0_print;
+#else
+#define ahd_slvspltoutattr0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTATTR0", 0x9c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutattr1_print;
+#else
+#define ahd_slvspltoutattr1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTATTR1", 0x9d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_slvspltoutattr2_print;
+#else
+#define ahd_slvspltoutattr2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SLVSPLTOUTATTR2", 0x9e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgspltstat0_print;
+#else
+#define ahd_sgspltstat0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGSPLTSTAT0", 0x9e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sfunct_print;
+#else
+#define ahd_sfunct_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgspltstat1_print;
+#else
+#define ahd_sgspltstat1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGSPLTSTAT1", 0x9f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_df0pcistat_print;
+#else
+#define ahd_df0pcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DF0PCISTAT", 0xa0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_reg0_print;
+#else
+#define ahd_reg0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "REG0", 0xa0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_df1pcistat_print;
+#else
+#define ahd_df1pcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DF1PCISTAT", 0xa1, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sgpcistat_print;
+#else
+#define ahd_sgpcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SGPCISTAT", 0xa2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_reg1_print;
+#else
+#define ahd_reg1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "REG1", 0xa2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmcpcistat_print;
+#else
+#define ahd_cmcpcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMCPCISTAT", 0xa3, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlypcistat_print;
+#else
+#define ahd_ovlypcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYPCISTAT", 0xa4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_reg_isr_print;
+#else
+#define ahd_reg_isr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "REG_ISR", 0xa4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sg_state_print;
+#else
+#define ahd_sg_state_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SG_STATE", 0xa6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_msipcistat_print;
+#else
+#define ahd_msipcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MSIPCISTAT", 0xa6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_targpcistat_print;
+#else
+#define ahd_targpcistat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TARGPCISTAT", 0xa7, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_data_count_odd_print;
+#else
+#define ahd_data_count_odd_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DATA_COUNT_ODD", 0xa7, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scbptr_print;
+#else
+#define ahd_scbptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCBPTR", 0xa8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbacnt_print;
+#else
+#define ahd_ccscbacnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBACNT", 0xab, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scbautoptr_print;
+#else
+#define ahd_scbautoptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCBAUTOPTR", 0xab, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccsgaddr_print;
+#else
+#define ahd_ccsgaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSGADDR", 0xac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbaddr_print;
+#else
+#define ahd_ccscbaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBADDR", 0xac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbadr_bk_print;
+#else
+#define ahd_ccscbadr_bk_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBADR_BK", 0xac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmc_rambist_print;
+#else
+#define ahd_cmc_rambist_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMC_RAMBIST", 0xad, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccsgctl_print;
+#else
+#define ahd_ccsgctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSGCTL", 0xad, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbctl_print;
+#else
+#define ahd_ccscbctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBCTL", 0xad, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccsgram_print;
+#else
+#define ahd_ccsgram_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSGRAM", 0xb0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flexadr_print;
+#else
+#define ahd_flexadr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLEXADR", 0xb0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ccscbram_print;
+#else
+#define ahd_ccscbram_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CCSCBRAM", 0xb0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flexcnt_print;
+#else
+#define ahd_flexcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLEXCNT", 0xb3, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flexdmastat_print;
+#else
+#define ahd_flexdmastat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLEXDMASTAT", 0xb5, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flexdata_print;
+#else
+#define ahd_flexdata_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLEXDATA", 0xb6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_brddat_print;
+#else
+#define ahd_brddat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRDDAT", 0xb8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_brdctl_print;
+#else
+#define ahd_brdctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRDCTL", 0xb9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seeadr_print;
+#else
+#define ahd_seeadr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEEADR", 0xba, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seedat_print;
+#else
+#define ahd_seedat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEEDAT", 0xbc, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seectl_print;
+#else
+#define ahd_seectl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEECTL", 0xbe, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seestat_print;
+#else
+#define ahd_seestat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEESTAT", 0xbe, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scbcnt_print;
+#else
+#define ahd_scbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCBCNT", 0xbf, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfwaddr_print;
+#else
+#define ahd_dfwaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFWADDR", 0xc0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dspfltrctl_print;
+#else
+#define ahd_dspfltrctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSPFLTRCTL", 0xc0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dspdatactl_print;
+#else
+#define ahd_dspdatactl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSPDATACTL", 0xc1, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfraddr_print;
+#else
+#define ahd_dfraddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFRADDR", 0xc2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dspreqctl_print;
+#else
+#define ahd_dspreqctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSPREQCTL", 0xc2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dspackctl_print;
+#else
+#define ahd_dspackctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSPACKCTL", 0xc3, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfdat_print;
+#else
+#define ahd_dfdat_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFDAT", 0xc4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dspselect_print;
+#else
+#define ahd_dspselect_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DSPSELECT", 0xc4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_wrtbiasctl_print;
+#else
+#define ahd_wrtbiasctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "WRTBIASCTL", 0xc5, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_rcvrbiosctl_print;
+#else
+#define ahd_rcvrbiosctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "RCVRBIOSCTL", 0xc6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_wrtbiascalc_print;
+#else
+#define ahd_wrtbiascalc_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "WRTBIASCALC", 0xc7, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfptrs_print;
+#else
+#define ahd_dfptrs_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFPTRS", 0xc8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_rcvrbiascalc_print;
+#else
+#define ahd_rcvrbiascalc_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "RCVRBIASCALC", 0xc8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfbkptr_print;
+#else
+#define ahd_dfbkptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFBKPTR", 0xc9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_skewcalc_print;
+#else
+#define ahd_skewcalc_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SKEWCALC", 0xc9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfdbctl_print;
+#else
+#define ahd_dfdbctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFDBCTL", 0xcb, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfscnt_print;
+#else
+#define ahd_dfscnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFSCNT", 0xcc, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dfbcnt_print;
+#else
+#define ahd_dfbcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DFBCNT", 0xce, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ovlyaddr_print;
+#else
+#define ahd_ovlyaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "OVLYADDR", 0xd4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqctl0_print;
+#else
+#define ahd_seqctl0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQCTL0", 0xd6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqctl1_print;
+#else
+#define ahd_seqctl1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQCTL1", 0xd7, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_flags_print;
+#else
+#define ahd_flags_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FLAGS", 0xd8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqintctl_print;
+#else
+#define ahd_seqintctl_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQINTCTL", 0xd9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seqram_print;
+#else
+#define ahd_seqram_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQRAM", 0xda, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_prgmcnt_print;
+#else
+#define ahd_prgmcnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "PRGMCNT", 0xde, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_accum_print;
+#else
+#define ahd_accum_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ACCUM", 0xe0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sindex_print;
+#else
+#define ahd_sindex_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SINDEX", 0xe2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dindex_print;
+#else
+#define ahd_dindex_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DINDEX", 0xe4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_brkaddr1_print;
+#else
+#define ahd_brkaddr1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRKADDR1", 0xe6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_brkaddr0_print;
+#else
+#define ahd_brkaddr0_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "BRKADDR0", 0xe6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_allones_print;
+#else
+#define ahd_allones_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ALLONES", 0xe8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_allzeros_print;
+#else
+#define ahd_allzeros_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ALLZEROS", 0xea, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_none_print;
+#else
+#define ahd_none_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NONE", 0xea, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sindir_print;
+#else
+#define ahd_sindir_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SINDIR", 0xec, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dindir_print;
+#else
+#define ahd_dindir_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DINDIR", 0xed, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_function1_print;
+#else
+#define ahd_function1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "FUNCTION1", 0xf0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_stack_print;
+#else
+#define ahd_stack_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "STACK", 0xf2, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_curaddr_print;
+#else
+#define ahd_curaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CURADDR", 0xf4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intvec1_addr_print;
+#else
+#define ahd_intvec1_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTVEC1_ADDR", 0xf4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_intvec2_addr_print;
+#else
+#define ahd_intvec2_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INTVEC2_ADDR", 0xf6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lastaddr_print;
+#else
+#define ahd_lastaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LASTADDR", 0xf6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_longjmp_addr_print;
+#else
+#define ahd_longjmp_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LONGJMP_ADDR", 0xf8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_accum_save_print;
+#else
+#define ahd_accum_save_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ACCUM_SAVE", 0xfa, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_waiting_scb_tails_print;
+#else
+#define ahd_waiting_scb_tails_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "WAITING_SCB_TAILS", 0x100, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_ahd_pci_config_base_print;
+#else
+#define ahd_ahd_pci_config_base_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "AHD_PCI_CONFIG_BASE", 0x100, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_sram_base_print;
+#else
+#define ahd_sram_base_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SRAM_BASE", 0x100, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_waiting_tid_head_print;
+#else
+#define ahd_waiting_tid_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "WAITING_TID_HEAD", 0x120, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_waiting_tid_tail_print;
+#else
+#define ahd_waiting_tid_tail_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "WAITING_TID_TAIL", 0x122, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_next_queued_scb_addr_print;
+#else
+#define ahd_next_queued_scb_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "NEXT_QUEUED_SCB_ADDR", 0x124, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_scb_head_print;
+#else
+#define ahd_complete_scb_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_SCB_HEAD", 0x128, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_scb_dmainprog_head_print;
+#else
+#define ahd_complete_scb_dmainprog_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_SCB_DMAINPROG_HEAD", 0x12a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_complete_dma_scb_head_print;
+#else
+#define ahd_complete_dma_scb_head_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_HEAD", 0x12c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qfreeze_count_print;
+#else
+#define ahd_qfreeze_count_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QFREEZE_COUNT", 0x12e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_saved_mode_print;
+#else
+#define ahd_saved_mode_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SAVED_MODE", 0x130, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_msg_out_print;
+#else
+#define ahd_msg_out_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "MSG_OUT", 0x131, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_dmaparams_print;
+#else
+#define ahd_dmaparams_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "DMAPARAMS", 0x132, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seq_flags_print;
+#else
+#define ahd_seq_flags_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQ_FLAGS", 0x133, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_saved_scsiid_print;
+#else
+#define ahd_saved_scsiid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SAVED_SCSIID", 0x134, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_saved_lun_print;
+#else
+#define ahd_saved_lun_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SAVED_LUN", 0x135, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_lastphase_print;
+#else
+#define ahd_lastphase_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LASTPHASE", 0x136, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qoutfifo_entry_valid_tag_print;
+#else
+#define ahd_qoutfifo_entry_valid_tag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG", 0x137, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_shared_data_addr_print;
+#else
+#define ahd_shared_data_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x138, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_qoutfifo_next_addr_print;
+#else
+#define ahd_qoutfifo_next_addr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR", 0x13c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_kernel_tqinpos_print;
+#else
+#define ahd_kernel_tqinpos_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "KERNEL_TQINPOS", 0x140, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_tqinpos_print;
+#else
+#define ahd_tqinpos_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "TQINPOS", 0x141, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_arg_1_print;
+#else
+#define ahd_arg_1_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ARG_1", 0x142, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_arg_2_print;
+#else
+#define ahd_arg_2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ARG_2", 0x143, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_last_msg_print;
+#else
+#define ahd_last_msg_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LAST_MSG", 0x144, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scsiseq_template_print;
+#else
+#define ahd_scsiseq_template_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x145, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_initiator_tag_print;
+#else
+#define ahd_initiator_tag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INITIATOR_TAG", 0x146, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_seq_flags2_print;
+#else
+#define ahd_seq_flags2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SEQ_FLAGS2", 0x147, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_allocfifo_scbptr_print;
+#else
+#define ahd_allocfifo_scbptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR", 0x148, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_int_coalescing_timer_print;
+#else
+#define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_int_coalescing_maxcmds_print;
+#else
+#define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_int_coalescing_mincmds_print;
+#else
+#define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmds_pending_print;
+#else
+#define ahd_cmds_pending_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMDS_PENDING", 0x14e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_int_coalescing_cmdcount_print;
+#else
+#define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_local_hs_mailbox_print;
+#else
+#define ahd_local_hs_mailbox_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX", 0x151, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_cmdsize_table_print;
+#else
+#define ahd_cmdsize_table_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "CMDSIZE_TABLE", 0x152, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_base_print;
+#else
+#define ahd_scb_base_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_BASE", 0x180, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_residual_datacnt_print;
+#else
+#define ahd_scb_residual_datacnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT", 0x180, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_residual_sgptr_print;
+#else
+#define ahd_scb_residual_sgptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_RESIDUAL_SGPTR", 0x184, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_scsi_status_print;
+#else
+#define ahd_scb_scsi_status_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SCSI_STATUS", 0x188, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_target_phases_print;
+#else
+#define ahd_scb_target_phases_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TARGET_PHASES", 0x189, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_target_data_dir_print;
+#else
+#define ahd_scb_target_data_dir_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TARGET_DATA_DIR", 0x18a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_target_itag_print;
+#else
+#define ahd_scb_target_itag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TARGET_ITAG", 0x18b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_sense_busaddr_print;
+#else
+#define ahd_scb_sense_busaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SENSE_BUSADDR", 0x18c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_tag_print;
+#else
+#define ahd_scb_tag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_control_print;
+#else
+#define ahd_scb_control_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_CONTROL", 0x192, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_scsiid_print;
+#else
+#define ahd_scb_scsiid_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SCSIID", 0x193, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_lun_print;
+#else
+#define ahd_scb_lun_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_LUN", 0x194, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_task_attribute_print;
+#else
+#define ahd_scb_task_attribute_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TASK_ATTRIBUTE", 0x195, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_cdb_len_print;
+#else
+#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x196, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_task_management_print;
+#else
+#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x197, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_dataptr_print;
+#else
+#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x198, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_datacnt_print;
+#else
+#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_DATACNT", 0x1a0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_sgptr_print;
+#else
+#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SGPTR", 0x1a4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_busaddr_print;
+#else
+#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_next_print;
+#else
+#define ahd_scb_next_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_NEXT", 0x1ac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_next2_print;
+#else
+#define ahd_scb_next2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1ae, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_spare_print;
+#else
+#define ahd_scb_spare_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SPARE", 0x1b0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_disconnected_lists_print;
+#else
+#define ahd_scb_disconnected_lists_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_DISCONNECTED_LISTS", 0x1b8, regvalue, cur_col, wrap)
+#endif
+
+
+#define	MODE_PTR        		0x00
+#define		DST_MODE        	0x70
+#define		SRC_MODE        	0x07
+
+#define	INTSTAT         		0x01
+#define		INT_PEND        	0xff
+#define		HWERRINT        	0x80
+#define		BRKADRINT       	0x40
+#define		SWTMINT         	0x20
+#define		PCIINT          	0x10
+#define		SCSIINT         	0x08
+#define		SEQINT          	0x04
+#define		CMDCMPLT        	0x02
+#define		SPLTINT         	0x01
+
+#define	SEQINTCODE      		0x02
+#define		BAD_SCB_STATUS  	0x1a
+#define		SAW_HWERR       	0x19
+#define		TRACEPOINT3     	0x18
+#define		TRACEPOINT2     	0x17
+#define		TRACEPOINT1     	0x16
+#define		TRACEPOINT0     	0x15
+#define		TASKMGMT_CMD_CMPLT_OKAY	0x14
+#define		TASKMGMT_FUNC_COMPLETE	0x13
+#define		ENTERING_NONPACK	0x12
+#define		CFG4OVERRUN     	0x11
+#define		STATUS_OVERRUN  	0x10
+#define		CFG4ISTAT_INTR  	0x0f
+#define		INVALID_SEQINT  	0x0e
+#define		ILLEGAL_PHASE   	0x0d
+#define		DUMP_CARD_STATE 	0x0c
+#define		MISSED_BUSFREE  	0x0b
+#define		MKMSG_FAILED    	0x0a
+#define		DATA_OVERRUN    	0x09
+#define		BAD_STATUS      	0x08
+#define		HOST_MSG_LOOP   	0x07
+#define		PDATA_REINIT    	0x06
+#define		IGN_WIDE_RES    	0x05
+#define		NO_MATCH        	0x04
+#define		PROTO_VIOLATION 	0x03
+#define		SEND_REJECT     	0x02
+#define		BAD_PHASE       	0x01
+#define		NO_SEQINT       	0x00
+
+#define	CLRINT          		0x03
+#define		CLRHWERRINT     	0x80
+#define		CLRBRKADRINT    	0x40
+#define		CLRSWTMINT      	0x20
+#define		CLRPCIINT       	0x10
+#define		CLRSCSIINT      	0x08
+#define		CLRSEQINT       	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSPLTINT      	0x01
+
+#define	ERROR           		0x04
+#define		CIOPARERR       	0x80
+#define		CIOACCESFAIL    	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
+
+#define	CLRERR          		0x04
+#define		CLRCIOPARERR    	0x80
+#define		CLRCIOACCESFAIL 	0x40
+#define		CLRMPARERR      	0x20
+#define		CLRDPARERR      	0x10
+#define		CLRSQPARERR     	0x08
+#define		CLRILLOPCODE    	0x04
+#define		CLRDSCTMOUT     	0x02
+
+#define	HCNTRL          		0x05
+#define		SEQ_RESET       	0x80
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		SWTIMER_START_B 	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HNSCB_QOFF      		0x06
+
+#define	HESCB_QOFF      		0x08
+
+#define	HS_MAILBOX      		0x0b
+#define		HOST_TQINPOS    	0x80
+#define		ENINT_COALESCE  	0x40
+
+#define	CLRSEQINTSTAT   		0x0c
+#define		CLRSEQ_SWTMRTO  	0x10
+#define		CLRSEQ_SEQINT   	0x08
+#define		CLRSEQ_SCSIINT  	0x04
+#define		CLRSEQ_PCIINT   	0x02
+#define		CLRSEQ_SPLTINT  	0x01
+
+#define	SEQINTSTAT      		0x0c
+#define		SEQ_SWTMRTO     	0x10
+#define		SEQ_SEQINT      	0x08
+#define		SEQ_SCSIINT     	0x04
+#define		SEQ_PCIINT      	0x02
+#define		SEQ_SPLTINT     	0x01
+
+#define	SWTIMER         		0x0e
+
+#define	SNSCB_QOFF      		0x10
+
+#define	SESCB_QOFF      		0x12
+
+#define	SDSCB_QOFF      		0x14
+
+#define	QOFF_CTLSTA     		0x16
+#define		EMPTY_SCB_AVAIL 	0x80
+#define		NEW_SCB_AVAIL   	0x40
+#define		SDSCB_ROLLOVR   	0x20
+#define		HS_MAILBOX_ACT  	0x10
+#define		SCB_QSIZE       	0x0f
+#define		SCB_QSIZE_16384 	0x0c
+#define		SCB_QSIZE_8192  	0x0b
+#define		SCB_QSIZE_4096  	0x0a
+#define		SCB_QSIZE_2048  	0x09
+#define		SCB_QSIZE_1024  	0x08
+#define		SCB_QSIZE_512   	0x07
+#define		SCB_QSIZE_256   	0x06
+#define		SCB_QSIZE_128   	0x05
+#define		SCB_QSIZE_64    	0x04
+#define		SCB_QSIZE_32    	0x03
+#define		SCB_QSIZE_16    	0x02
+#define		SCB_QSIZE_8     	0x01
+#define		SCB_QSIZE_4     	0x00
+
+#define	INTCTL          		0x18
+#define		SWTMINTMASK     	0x80
+#define		SWTMINTEN       	0x40
+#define		SWTIMER_START   	0x20
+#define		AUTOCLRCMDINT   	0x10
+#define		PCIINTEN        	0x08
+#define		SCSIINTEN       	0x04
+#define		SEQINTEN        	0x02
+#define		SPLTINTEN       	0x01
+
+#define	DFCNTRL         		0x19
+#define		SCSIENWRDIS     	0x40
+#define		SCSIENACK       	0x20
+#define		DIRECTIONACK    	0x04
+#define		FIFOFLUSHACK    	0x02
+#define		DIRECTIONEN     	0x01
+
+#define	DSCOMMAND0      		0x19
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+#define		DISABLE_TWATE   	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	DFSTATUS        		0x1a
+#define		PRELOAD_AVAIL   	0x80
+#define		PKT_PRELOAD_AVAIL	0x40
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	SG_CACHE_SHADOW 		0x1b
+#define		ODD_SEG         	0x04
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+#define	ARBCTL          		0x1b
+#define		RESET_HARB      	0x80
+#define		RETRY_SWEN      	0x08
+#define		USE_TIME        	0x07
+
+#define	SG_CACHE_PRE    		0x1b
+
+#define	LQIN            		0x20
+
+#define	TYPEPTR         		0x20
+
+#define	TAGPTR          		0x21
+
+#define	LUNPTR          		0x22
+
+#define	DATALENPTR      		0x23
+
+#define	STATLENPTR      		0x24
+
+#define	CMDLENPTR       		0x25
+
+#define	ATTRPTR         		0x26
+
+#define	FLAGPTR         		0x27
+
+#define	CMDPTR          		0x28
+
+#define	QNEXTPTR        		0x29
+
+#define	IDPTR           		0x2a
+
+#define	ABRTBYTEPTR     		0x2b
+
+#define	ABRTBITPTR      		0x2c
+
+#define	MAXCMDBYTES     		0x2d
+
+#define	MAXCMD2RCV      		0x2e
+
+#define	SHORTTHRESH     		0x2f
+
+#define	LUNLEN          		0x30
+#define		TLUNLEN         	0xf0
+#define		ILUNLEN         	0x0f
+
+#define	CDBLIMIT        		0x31
+
+#define	MAXCMD          		0x32
+
+#define	MAXCMDCNT       		0x33
+
+#define	LQRSVD01        		0x34
+
+#define	LQRSVD16        		0x35
+
+#define	LQRSVD17        		0x36
+
+#define	CMDRSVD0        		0x37
+
+#define	LQCTL0          		0x38
+#define		LQITARGCLT      	0xc0
+#define		LQIINITGCLT     	0x30
+#define		LQ0TARGCLT      	0x0c
+#define		LQ0INITGCLT     	0x03
+
+#define	LQCTL1          		0x38
+#define		PCI2PCI         	0x04
+#define		SINGLECMD       	0x02
+#define		ABORTPENDING    	0x01
+
+#define	SCSBIST0        		0x39
+#define		GSBISTERR       	0x40
+#define		GSBISTDONE      	0x20
+#define		GSBISTRUN       	0x10
+#define		OSBISTERR       	0x04
+#define		OSBISTDONE      	0x02
+#define		OSBISTRUN       	0x01
+
+#define	LQCTL2          		0x39
+#define		LQIRETRY        	0x80
+#define		LQICONTINUE     	0x40
+#define		LQITOIDLE       	0x20
+#define		LQIPAUSE        	0x10
+#define		LQORETRY        	0x08
+#define		LQOCONTINUE     	0x04
+#define		LQOTOIDLE       	0x02
+#define		LQOPAUSE        	0x01
+
+#define	SCSBIST1        		0x3a
+#define		NTBISTERR       	0x04
+#define		NTBISTDONE      	0x02
+#define		NTBISTRUN       	0x01
+
+#define	SCSISEQ0        		0x3a
+#define		TEMODEO         	0x80
+#define		ENSELO          	0x40
+#define		ENARBO          	0x20
+#define		FORCEBUSFREE    	0x10
+#define		SCSIRSTO        	0x01
+
+#define	SCSISEQ1        		0x3b
+
+#define	SXFRCTL0        		0x3c
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		BIOSCANCELEN    	0x10
+#define		SPIOEN          	0x08
+
+#define	BUSINITID       		0x3c
+
+#define	DLCOUNT         		0x3c
+
+#define	SXFRCTL1        		0x3d
+#define		BITBUCKET       	0x80
+#define		ENSACHK         	0x40
+#define		ENSPCHK         	0x20
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	BUSTARGID       		0x3e
+
+#define	SXFRCTL2        		0x3e
+#define		AUTORSTDIS      	0x10
+#define		CMDDMAEN        	0x08
+#define		ASU             	0x07
+
+#define	DFFSTAT         		0x3f
+#define		CURRFIFO        	0x03
+#define		FIFO1FREE       	0x20
+#define		FIFO0FREE       	0x10
+#define		CURRFIFO_NONE   	0x03
+#define		CURRFIFO_1      	0x01
+#define		CURRFIFO_0      	0x00
+
+#define	SCSISIGO        		0x40
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	MULTARGID       		0x40
+
+#define	SCSISIGI        		0x41
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIPHASE       		0x42
+#define		STATUS_PHASE    	0x20
+#define		COMMAND_PHASE   	0x10
+#define		MSG_IN_PHASE    	0x08
+#define		MSG_OUT_PHASE   	0x04
+#define		DATA_PHASE_MASK 	0x03
+#define		DATA_IN_PHASE   	0x02
+#define		DATA_OUT_PHASE  	0x01
+
+#define	SCSIDAT0_IMG    		0x43
+
+#define	SCSIDAT         		0x44
+
+#define	SCSIBUS         		0x46
+
+#define	TARGIDIN        		0x48
+#define		CLKOUT          	0x80
+#define		TARGID          	0x0f
+
+#define	SELID           		0x49
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SBLKCTL         		0x4a
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		ENAB40          	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+
+#define	OPTIONMODE      		0x4a
+#define		OPTIONMODE_DEFAULTS	0x02
+#define		BIOSCANCTL      	0x80
+#define		AUTOACKEN       	0x40
+#define		BIASCANCTL      	0x20
+#define		BUSFREEREV      	0x10
+#define		ENDGFORMCHK     	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+
+#define	SSTAT0          		0x4b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		IOERR           	0x08
+#define		OVERRUN         	0x04
+#define		SPIORDY         	0x02
+#define		ARBDO           	0x01
+
+#define	CLRSINT0        		0x4b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRIOERR        	0x08
+#define		CLROVERRUN      	0x04
+#define		CLRSPIORDY      	0x02
+#define		CLRARBDO        	0x01
+
+#define	SIMODE0         		0x4b
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENOVERRUN       	0x04
+#define		ENSPIORDY       	0x02
+#define		ENARBDO         	0x01
+
+#define	CLRSINT1        		0x4c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRSTRB2FAST    	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x4c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		STRB2FAST       	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x4d
+#define		BUSFREETIME     	0xc0
+#define		NONPACKREQ      	0x20
+#define		EXP_ACTIVE      	0x10
+#define		BSYX            	0x08
+#define		WIDE_RES        	0x04
+#define		SDONE           	0x02
+#define		DMADONE         	0x01
+#define		BUSFREE_DFF1    	0xc0
+#define		BUSFREE_DFF0    	0x80
+#define		BUSFREE_LQO     	0x40
+
+#define	CLRSINT2        		0x4d
+#define		CLRNONPACKREQ   	0x20
+#define		CLRWIDE_RES     	0x04
+#define		CLRSDONE        	0x02
+#define		CLRDMADONE      	0x01
+
+#define	SIMODE2         		0x4d
+#define		ENWIDE_RES      	0x04
+#define		ENSDONE         	0x02
+#define		ENDMADONE       	0x01
+
+#define	PERRDIAG        		0x4e
+#define		HIZERO          	0x80
+#define		HIPERR          	0x40
+#define		PREVPHASE       	0x20
+#define		PARITYERR       	0x10
+#define		AIPERR          	0x08
+#define		CRCERR          	0x04
+#define		DGFORMERR       	0x02
+#define		DTERR           	0x01
+
+#define	LQISTATE        		0x4e
+
+#define	SOFFCNT         		0x4f
+
+#define	LQOSTATE        		0x4f
+
+#define	LQISTAT0        		0x50
+#define		LQIATNQAS       	0x20
+#define		LQICRCT1        	0x10
+#define		LQICRCT2        	0x08
+#define		LQIBADLQT       	0x04
+#define		LQIATNLQ        	0x02
+#define		LQIATNCMD       	0x01
+
+#define	CLRLQIINT0      		0x50
+#define		CLRLQIATNQAS    	0x20
+#define		CLRLQICRCT1     	0x10
+#define		CLRLQICRCT2     	0x08
+#define		CLRLQIBADLQT    	0x04
+#define		CLRLQIATNLQ     	0x02
+#define		CLRLQIATNCMD    	0x01
+
+#define	LQIMODE0        		0x50
+#define		ENLQIATNQASK    	0x20
+#define		ENLQICRCT1      	0x10
+#define		ENLQICRCT2      	0x08
+#define		ENLQIBADLQT     	0x04
+#define		ENLQIATNLQ      	0x02
+#define		ENLQIATNCMD     	0x01
+
+#define	LQIMODE1        		0x51
+#define		ENLQIPHASE_LQ   	0x80
+#define		ENLQIPHASE_NLQ  	0x40
+#define		ENLIQABORT      	0x20
+#define		ENLQICRCI_LQ    	0x10
+#define		ENLQICRCI_NLQ   	0x08
+#define		ENLQIBADLQI     	0x04
+#define		ENLQIOVERI_LQ   	0x02
+#define		ENLQIOVERI_NLQ  	0x01
+
+#define	LQISTAT1        		0x51
+#define		LQIPHASE_LQ     	0x80
+#define		LQIPHASE_NLQ    	0x40
+#define		LQIABORT        	0x20
+#define		LQICRCI_LQ      	0x10
+#define		LQICRCI_NLQ     	0x08
+#define		LQIBADLQI       	0x04
+#define		LQIOVERI_LQ     	0x02
+#define		LQIOVERI_NLQ    	0x01
+
+#define	CLRLQIINT1      		0x51
+#define		CLRLQIPHASE_LQ  	0x80
+#define		CLRLQIPHASE_NLQ 	0x40
+#define		CLRLIQABORT     	0x20
+#define		CLRLQICRCI_LQ   	0x10
+#define		CLRLQICRCI_NLQ  	0x08
+#define		CLRLQIBADLQI    	0x04
+#define		CLRLQIOVERI_LQ  	0x02
+#define		CLRLQIOVERI_NLQ 	0x01
+
+#define	LQISTAT2        		0x52
+#define		PACKETIZED      	0x80
+#define		LQIPHASE_OUTPKT 	0x40
+#define		LQIWORKONLQ     	0x20
+#define		LQIWAITFIFO     	0x10
+#define		LQISTOPPKT      	0x08
+#define		LQISTOPLQ       	0x04
+#define		LQISTOPCMD      	0x02
+#define		LQIGSAVAIL      	0x01
+
+#define	SSTAT3          		0x53
+#define		NTRAMPERR       	0x02
+#define		OSRAMPERR       	0x01
+
+#define	SIMODE3         		0x53
+#define		ENNTRAMPERR     	0x02
+#define		ENOSRAMPERR     	0x01
+
+#define	CLRSINT3        		0x53
+#define		CLRNTRAMPERR    	0x02
+#define		CLROSRAMPERR    	0x01
+
+#define	LQOMODE0        		0x54
+#define		ENLQOTARGSCBPERR	0x10
+#define		ENLQOSTOPT2     	0x08
+#define		ENLQOATNLQ      	0x04
+#define		ENLQOATNPKT     	0x02
+#define		ENLQOTCRC       	0x01
+
+#define	LQOSTAT0        		0x54
+#define		LQOTARGSCBPERR  	0x10
+#define		LQOSTOPT2       	0x08
+#define		LQOATNLQ        	0x04
+#define		LQOATNPKT       	0x02
+#define		LQOTCRC         	0x01
+
+#define	CLRLQOINT0      		0x54
+#define		CLRLQOTARGSCBPERR	0x10
+#define		CLRLQOSTOPT2    	0x08
+#define		CLRLQOATNLQ     	0x04
+#define		CLRLQOATNPKT    	0x02
+#define		CLRLQOTCRC      	0x01
+
+#define	LQOSTAT1        		0x55
+#define		LQOINITSCBPERR  	0x10
+#define		LQOSTOPI2       	0x08
+#define		LQOBADQAS       	0x04
+#define		LQOBUSFREE      	0x02
+#define		LQOPHACHGINPKT  	0x01
+
+#define	CLRLQOINT1      		0x55
+#define		CLRLQOINITSCBPERR	0x10
+#define		CLRLQOSTOPI2    	0x08
+#define		CLRLQOBADQAS    	0x04
+#define		CLRLQOBUSFREE   	0x02
+#define		CLRLQOPHACHGINPKT	0x01
+
+#define	LQOMODE1        		0x55
+#define		ENLQOINITSCBPERR	0x10
+#define		ENLQOSTOPI2     	0x08
+#define		ENLQOBADQAS     	0x04
+#define		ENLQOBUSFREE    	0x02
+#define		ENLQOPHACHGINPKT	0x01
+
+#define	LQOSTAT2        		0x56
+#define		LQOPKT          	0xe0
+#define		LQOWAITFIFO     	0x10
+#define		LQOPHACHGOUTPKT 	0x02
+#define		LQOSTOP0        	0x01
+
+#define	OS_SPACE_CNT    		0x56
+
+#define	SIMODE1         		0x57
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENSTRB2FAST     	0x02
+#define		ENREQINIT       	0x01
+
+#define	GSFIFO          		0x58
+
+#define	DFFSXFRCTL      		0x5a
+#define		DFFBITBUCKET    	0x08
+#define		CLRSHCNT        	0x04
+#define		CLRCHN          	0x02
+#define		RSTCHN          	0x01
+
+#define	LQOSCSCTL       		0x5a
+#define		LQOH2A_VERSION  	0x80
+#define		LQONOCHKOVER    	0x01
+
+#define	NEXTSCB         		0x5a
+
+#define	CLRSEQINTSRC    		0x5b
+#define		CLRCTXTDONE     	0x40
+#define		CLRSAVEPTRS     	0x20
+#define		CLRCFG4DATA     	0x10
+#define		CLRCFG4ISTAT    	0x08
+#define		CLRCFG4TSTAT    	0x04
+#define		CLRCFG4ICMD     	0x02
+#define		CLRCFG4TCMD     	0x01
+
+#define	SEQINTSRC       		0x5b
+#define		CTXTDONE        	0x40
+#define		SAVEPTRS        	0x20
+#define		CFG4DATA        	0x10
+#define		CFG4ISTAT       	0x08
+#define		CFG4TSTAT       	0x04
+#define		CFG4ICMD        	0x02
+#define		CFG4TCMD        	0x01
+
+#define	CURRSCB         		0x5c
+
+#define	SEQIMODE        		0x5c
+#define		ENCTXTDONE      	0x40
+#define		ENSAVEPTRS      	0x20
+#define		ENCFG4DATA      	0x10
+#define		ENCFG4ISTAT     	0x08
+#define		ENCFG4TSTAT     	0x04
+#define		ENCFG4ICMD      	0x02
+#define		ENCFG4TCMD      	0x01
+
+#define	MDFFSTAT        		0x5d
+#define		SHCNTNEGATIVE   	0x40
+#define		SHCNTMINUS1     	0x20
+#define		LASTSDONE       	0x10
+#define		SHVALID         	0x08
+#define		DLZERO          	0x04
+#define		DATAINFIFO      	0x02
+#define		FIFOFREE        	0x01
+
+#define	CRCCONTROL      		0x5d
+#define		CRCVALCHKEN     	0x40
+
+#define	DFFTAG          		0x5e
+
+#define	LASTSCB         		0x5e
+
+#define	SCSITEST        		0x5e
+#define		CNTRTEST        	0x08
+#define		SEL_TXPLL_DEBUG 	0x04
+
+#define	IOPDNCTL        		0x5f
+#define		DISABLE_OE      	0x80
+#define		PDN_IDIST       	0x04
+#define		PDN_DIFFSENSE   	0x01
+
+#define	SHADDR          		0x60
+
+#define	NEGOADDR        		0x60
+
+#define	DGRPCRCI        		0x60
+
+#define	NEGPERIOD       		0x61
+
+#define	PACKCRCI        		0x62
+
+#define	NEGOFFSET       		0x62
+
+#define	NEGPPROPTS      		0x63
+#define		PPROPT_PACE     	0x08
+#define		PPROPT_QAS      	0x04
+#define		PPROPT_DT       	0x02
+#define		PPROPT_IUT      	0x01
+
+#define	NEGCONOPTS      		0x64
+#define		ENSNAPSHOT      	0x40
+#define		RTI_WRTDIS      	0x20
+#define		RTI_OVRDTRN     	0x10
+#define		ENSLOWCRC       	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNO      	0x02
+#define		WIDEXFER        	0x01
+
+#define	ANNEXCOL        		0x65
+
+#define	SCSCHKN         		0x66
+#define		STSELSKIDDIS    	0x40
+#define		CURRFIFODEF     	0x20
+#define		WIDERESEN       	0x10
+#define		SDONEMSKDIS     	0x08
+#define		DFFACTCLR       	0x04
+#define		SHVALIDSTDIS    	0x02
+#define		LSTSGCLRDIS     	0x01
+
+#define	ANNEXDAT        		0x66
+
+#define	IOWNID          		0x67
+
+#define	PLL960CTL0      		0x68
+
+#define	SHCNT           		0x68
+
+#define	TOWNID          		0x69
+
+#define	PLL960CTL1      		0x69
+
+#define	PLL960CNT0      		0x6a
+
+#define	XSIG            		0x6a
+
+#define	SELOID          		0x6b
+
+#define	PLL400CTL0      		0x6c
+#define		PLL_VCOSEL      	0x80
+#define		PLL_PWDN        	0x40
+#define		PLL_NS          	0x30
+#define		PLL_ENLUD       	0x08
+#define		PLL_ENLPF       	0x04
+#define		PLL_DLPF        	0x02
+#define		PLL_ENFBM       	0x01
+
+#define	FAIRNESS        		0x6c
+
+#define	PLL400CTL1      		0x6d
+#define		PLL_CNTEN       	0x80
+#define		PLL_CNTCLR      	0x40
+#define		PLL_RST         	0x01
+
+#define	PLL400CNT0      		0x6e
+
+#define	UNFAIRNESS      		0x6e
+
+#define	HADDR           		0x70
+
+#define	PLLDELAY        		0x70
+#define		SPLIT_DROP_REQ  	0x80
+
+#define	HODMAADR        		0x70
+
+#define	HODMACNT        		0x78
+
+#define	HCNT            		0x78
+
+#define	HODMAEN         		0x7a
+
+#define	SGHADDR         		0x7c
+
+#define	SCBHADDR        		0x7c
+
+#define	SGHCNT          		0x84
+
+#define	SCBHCNT         		0x84
+
+#define	DFF_THRSH       		0x88
+#define		WR_DFTHRSH      	0x70
+#define		RD_DFTHRSH      	0x07
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		WR_DFTHRSH_MIN  	0x00
+#define		RD_DFTHRSH_MIN  	0x00
+
+#define	ROMADDR         		0x8a
+
+#define	ROMCNTRL        		0x8d
+#define		ROMOP           	0xe0
+#define		ROMSPD          	0x18
+#define		REPEAT          	0x02
+#define		RDY             	0x01
+
+#define	ROMDATA         		0x8e
+
+#define	CMCRXMSG0       		0x90
+
+#define	ROENABLE        		0x90
+#define		MSIROEN         	0x20
+#define		OVLYROEN        	0x10
+#define		CMCROEN         	0x08
+#define		SGROEN          	0x04
+#define		DCH1ROEN        	0x02
+#define		DCH0ROEN        	0x01
+
+#define	OVLYRXMSG0      		0x90
+
+#define	DCHRXMSG0       		0x90
+
+#define	OVLYRXMSG1      		0x91
+
+#define	NSENABLE        		0x91
+#define		MSINSEN         	0x20
+#define		OVLYNSEN        	0x10
+#define		CMCNSEN         	0x08
+#define		SGNSEN          	0x04
+#define		DCH1NSEN        	0x02
+#define		DCH0NSEN        	0x01
+
+#define	DCHRXMSG1       		0x91
+
+#define	CMCRXMSG1       		0x91
+
+#define	DCHRXMSG2       		0x92
+
+#define	OVLYRXMSG2      		0x92
+
+#define	CMCRXMSG2       		0x92
+
+#define	OST             		0x92
+
+#define	DCHRXMSG3       		0x93
+
+#define	CMCRXMSG3       		0x93
+
+#define	PCIXCTL         		0x93
+#define		SERRPULSE       	0x80
+#define		UNEXPSCIEN      	0x20
+#define		SPLTSMADIS      	0x10
+#define		SPLTSTADIS      	0x08
+#define		SRSPDPEEN       	0x04
+#define		TSCSERREN       	0x02
+#define		CMPABCDIS       	0x01
+
+#define	OVLYRXMSG3      		0x93
+
+#define	OVLYSEQBCNT     		0x94
+
+#define	CMCSEQBCNT      		0x94
+
+#define	DCHSEQBCNT      		0x94
+
+#define	CMCSPLTSTAT0    		0x96
+
+#define	OVLYSPLTSTAT0   		0x96
+
+#define	DCHSPLTSTAT0    		0x96
+
+#define	DCHSPLTSTAT1    		0x97
+
+#define	CMCSPLTSTAT1    		0x97
+
+#define	OVLYSPLTSTAT1   		0x97
+
+#define	SGRXMSG0        		0x98
+#define		CDNUM           	0xf8
+#define		CFNUM           	0x07
+
+#define	SLVSPLTOUTADR0  		0x98
+#define		LOWER_ADDR      	0x7f
+
+#define	SGRXMSG1        		0x99
+#define		CBNUM           	0xff
+
+#define	SLVSPLTOUTADR1  		0x99
+#define		REQ_DNUM        	0xf8
+#define		REQ_FNUM        	0x07
+
+#define	SGRXMSG2        		0x9a
+#define		MINDEX          	0xff
+
+#define	SLVSPLTOUTADR2  		0x9a
+#define		REQ_BNUM        	0xff
+
+#define	SGRXMSG3        		0x9b
+#define		MCLASS          	0x0f
+
+#define	SLVSPLTOUTADR3  		0x9b
+#define		TAG_NUM         	0x1f
+#define		RLXORD          	0x10
+
+#define	SGSEQBCNT       		0x9c
+
+#define	SLVSPLTOUTATTR0 		0x9c
+#define		LOWER_BCNT      	0xff
+
+#define	SLVSPLTOUTATTR1 		0x9d
+#define		CMPLT_DNUM      	0xf8
+#define		CMPLT_FNUM      	0x07
+
+#define	SLVSPLTOUTATTR2 		0x9e
+#define		CMPLT_BNUM      	0xff
+
+#define	SGSPLTSTAT0     		0x9e
+#define		STAETERM        	0x80
+#define		SCBCERR         	0x40
+#define		SCADERR         	0x20
+#define		SCDATBUCKET     	0x10
+#define		CNTNOTCMPLT     	0x08
+#define		RXOVRUN         	0x04
+#define		RXSCEMSG        	0x02
+#define		RXSPLTRSP       	0x01
+
+#define	SFUNCT          		0x9f
+#define		TEST_GROUP      	0xf0
+#define		TEST_NUM        	0x0f
+
+#define	SGSPLTSTAT1     		0x9f
+#define		RXDATABUCKET    	0x01
+
+#define	DF0PCISTAT      		0xa0
+
+#define	REG0            		0xa0
+
+#define	DF1PCISTAT      		0xa1
+
+#define	SGPCISTAT       		0xa2
+
+#define	REG1            		0xa2
+
+#define	CMCPCISTAT      		0xa3
+
+#define	OVLYPCISTAT     		0xa4
+#define		SCAAPERR        	0x08
+#define		RDPERR          	0x04
+
+#define	REG_ISR         		0xa4
+
+#define	SG_STATE        		0xa6
+#define		FETCH_INPROG    	0x04
+#define		LOADING_NEEDED  	0x02
+#define		SEGS_AVAIL      	0x01
+
+#define	MSIPCISTAT      		0xa6
+#define		RMA             	0x20
+#define		RTA             	0x10
+#define		CLRPENDMSI      	0x08
+#define		DPR             	0x01
+
+#define	TARGPCISTAT     		0xa7
+#define		DPE             	0x80
+#define		SSE             	0x40
+#define		STA             	0x08
+#define		TWATERR         	0x02
+
+#define	DATA_COUNT_ODD  		0xa7
+
+#define	SCBPTR          		0xa8
+
+#define	CCSCBACNT       		0xab
+
+#define	SCBAUTOPTR      		0xab
+#define		AUSCBPTR_EN     	0x80
+#define		SCBPTR_ADDR     	0x38
+#define		SCBPTR_OFF      	0x07
+
+#define	CCSGADDR        		0xac
+
+#define	CCSCBADDR       		0xac
+
+#define	CCSCBADR_BK     		0xac
+
+#define	CMC_RAMBIST     		0xad
+#define		SG_ELEMENT_SIZE 	0x80
+#define		SCBRAMBIST_FAIL 	0x40
+#define		SG_BIST_FAIL    	0x20
+#define		SG_BIST_EN      	0x10
+#define		CMC_BUFFER_BIST_FAIL	0x02
+#define		CMC_BUFFER_BIST_EN	0x01
+
+#define	CCSGCTL         		0xad
+#define		CCSGEN          	0x0c
+#define		CCSGDONE        	0x80
+#define		SG_CACHE_AVAIL  	0x10
+#define		CCSGENACK       	0x08
+#define		SG_FETCH_REQ    	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBCTL        		0xad
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSGRAM         		0xb0
+
+#define	FLEXADR         		0xb0
+
+#define	CCSCBRAM        		0xb0
+
+#define	FLEXCNT         		0xb3
+
+#define	FLEXDMASTAT     		0xb5
+#define		FLEXDMAERR      	0x02
+#define		FLEXDMADONE     	0x01
+
+#define	FLEXDATA        		0xb6
+
+#define	BRDDAT          		0xb8
+
+#define	BRDCTL          		0xb9
+#define		FLXARBACK       	0x80
+#define		FLXARBREQ       	0x40
+#define		BRDADDR         	0x38
+#define		BRDEN           	0x04
+#define		BRDRW           	0x02
+#define		BRDSTB          	0x01
+
+#define	SEEADR          		0xba
+
+#define	SEEDAT          		0xbc
+
+#define	SEECTL          		0xbe
+#define		SEEOP_EWEN      	0x40
+#define		SEEOP_WALL      	0x40
+#define		SEEOP_EWDS      	0x40
+#define		SEEOPCODE       	0x70
+#define		SEERST          	0x02
+#define		SEESTART        	0x01
+#define		SEEOP_ERASE     	0x70
+#define		SEEOP_READ      	0x60
+#define		SEEOP_WRITE     	0x50
+#define		SEEOP_ERAL      	0x40
+
+#define	SEESTAT         		0xbe
+#define		INIT_DONE       	0x80
+#define		LDALTID_L       	0x08
+#define		SEEARBACK       	0x04
+#define		SEEBUSY         	0x02
+
+#define	SCBCNT          		0xbf
+
+#define	DFWADDR         		0xc0
+
+#define	DSPFLTRCTL      		0xc0
+#define		FLTRDISABLE     	0x20
+#define		EDGESENSE       	0x10
+#define		DSPFCNTSEL      	0x0f
+
+#define	DSPDATACTL      		0xc1
+#define		BYPASSENAB      	0x80
+#define		DESQDIS         	0x10
+#define		RCVROFFSTDIS    	0x04
+#define		XMITOFFSTDIS    	0x02
+
+#define	DFRADDR         		0xc2
+
+#define	DSPREQCTL       		0xc2
+#define		MANREQCTL       	0xc0
+#define		MANREQDLY       	0x3f
+
+#define	DSPACKCTL       		0xc3
+#define		MANACKCTL       	0xc0
+#define		MANACKDLY       	0x3f
+
+#define	DFDAT           		0xc4
+
+#define	DSPSELECT       		0xc4
+#define		AUTOINCEN       	0x80
+#define		DSPSEL          	0x1f
+
+#define	WRTBIASCTL      		0xc5
+#define		AUTOXBCDIS      	0x80
+#define		XMITMANVAL      	0x3f
+
+#define	RCVRBIOSCTL     		0xc6
+#define		AUTORBCDIS      	0x80
+#define		RCVRMANVAL      	0x3f
+
+#define	WRTBIASCALC     		0xc7
+
+#define	DFPTRS          		0xc8
+
+#define	RCVRBIASCALC    		0xc8
+
+#define	DFBKPTR         		0xc9
+
+#define	SKEWCALC        		0xc9
+
+#define	DFDBCTL         		0xcb
+#define		DFF_CIO_WR_RDY  	0x20
+#define		DFF_CIO_RD_RDY  	0x10
+#define		DFF_DIR_ERR     	0x08
+#define		DFF_RAMBIST_FAIL	0x04
+#define		DFF_RAMBIST_DONE	0x02
+#define		DFF_RAMBIST_EN  	0x01
+
+#define	DFSCNT          		0xcc
+
+#define	DFBCNT          		0xce
+
+#define	OVLYADDR        		0xd4
+
+#define	SEQCTL0         		0xd6
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQCTL1         		0xd7
+#define		OVRLAY_DATA_CHK 	0x08
+#define		RAMBIST_DONE    	0x04
+#define		RAMBIST_FAIL    	0x02
+#define		RAMBIST_EN      	0x01
+
+#define	FLAGS           		0xd8
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SEQINTCTL       		0xd9
+#define		INTVEC1DSL      	0x80
+#define		INT1_CONTEXT    	0x20
+#define		SCS_SEQ_INT1M1  	0x10
+#define		SCS_SEQ_INT1M0  	0x08
+#define		INTMASK2        	0x04
+#define		INTMASK1        	0x02
+#define		IRET            	0x01
+
+#define	SEQRAM          		0xda
+
+#define	PRGMCNT         		0xde
+
+#define	ACCUM           		0xe0
+
+#define	SINDEX          		0xe2
+
+#define	DINDEX          		0xe4
+
+#define	BRKADDR1        		0xe6
+#define		BRKDIS          	0x80
+
+#define	BRKADDR0        		0xe6
+
+#define	ALLONES         		0xe8
+
+#define	ALLZEROS        		0xea
+
+#define	NONE            		0xea
+
+#define	SINDIR          		0xec
+
+#define	DINDIR          		0xed
+
+#define	FUNCTION1       		0xf0
+
+#define	STACK           		0xf2
+
+#define	CURADDR         		0xf4
+
+#define	INTVEC1_ADDR    		0xf4
+
+#define	INTVEC2_ADDR    		0xf6
+
+#define	LASTADDR        		0xf6
+
+#define	LONGJMP_ADDR    		0xf8
+
+#define	ACCUM_SAVE      		0xfa
+
+#define	WAITING_SCB_TAILS		0x100
+
+#define	AHD_PCI_CONFIG_BASE		0x100
+
+#define	SRAM_BASE       		0x100
+
+#define	WAITING_TID_HEAD		0x120
+
+#define	WAITING_TID_TAIL		0x122
+
+#define	NEXT_QUEUED_SCB_ADDR		0x124
+
+#define	COMPLETE_SCB_HEAD		0x128
+
+#define	COMPLETE_SCB_DMAINPROG_HEAD		0x12a
+
+#define	COMPLETE_DMA_SCB_HEAD		0x12c
+
+#define	QFREEZE_COUNT   		0x12e
+
+#define	SAVED_MODE      		0x130
+
+#define	MSG_OUT         		0x131
+
+#define	DMAPARAMS       		0x132
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAEN          	0x10
+#define		SDMAENACK       	0x10
+#define		HDMAENACK       	0x08
+#define		HDMAEN          	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x133
+#define		NOT_IDENTIFIED  	0x80
+#define		NO_CDB_SENT     	0x40
+#define		TARGET_CMD_IS_TAGGED	0x40
+#define		DPHASE          	0x20
+#define		TARG_CMD_PENDING	0x10
+#define		CMDPHASE_PENDING	0x08
+#define		DPHASE_PENDING  	0x04
+#define		SPHASE_PENDING  	0x02
+#define		NO_DISCONNECT   	0x01
+
+#define	SAVED_SCSIID    		0x134
+
+#define	SAVED_LUN       		0x135
+
+#define	LASTPHASE       		0x136
+#define		PHASE_MASK      	0xe0
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_MESGIN        	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		P_DATAIN_DT     	0x60
+#define		P_DATAIN        	0x40
+#define		P_DATAOUT_DT    	0x20
+#define		P_DATAOUT       	0x00
+
+#define	QOUTFIFO_ENTRY_VALID_TAG		0x137
+
+#define	SHARED_DATA_ADDR		0x138
+
+#define	QOUTFIFO_NEXT_ADDR		0x13c
+
+#define	KERNEL_TQINPOS  		0x140
+
+#define	TQINPOS         		0x141
+
+#define	ARG_1           		0x142
+#define	RETURN_1        		0x142
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+#define		EXIT_MSG_LOOP   	0x08
+#define		CONT_MSG_LOOP_WRITE	0x04
+#define		CONT_MSG_LOOP_READ	0x03
+#define		CONT_MSG_LOOP_TARG	0x02
+
+#define	ARG_2           		0x143
+#define	RETURN_2        		0x143
+
+#define	LAST_MSG        		0x144
+
+#define	SCSISEQ_TEMPLATE		0x145
+#define		MANUALCTL       	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		MANUALP         	0x0c
+#define		ENAUTOATNP      	0x02
+#define		ALTSTIM         	0x01
+
+#define	INITIATOR_TAG   		0x146
+
+#define	SEQ_FLAGS2      		0x147
+#define		SELECTOUT_QFROZEN	0x04
+#define		TARGET_MSG_PENDING	0x02
+
+#define	ALLOCFIFO_SCBPTR		0x148
+
+#define	INT_COALESCING_TIMER		0x14a
+
+#define	INT_COALESCING_MAXCMDS		0x14c
+
+#define	INT_COALESCING_MINCMDS		0x14d
+
+#define	CMDS_PENDING    		0x14e
+
+#define	INT_COALESCING_CMDCOUNT		0x150
+
+#define	LOCAL_HS_MAILBOX		0x151
+
+#define	CMDSIZE_TABLE   		0x152
+
+#define	SCB_BASE        		0x180
+
+#define	SCB_RESIDUAL_DATACNT		0x180
+#define	SCB_CDB_STORE   		0x180
+#define	SCB_HOST_CDB_PTR		0x180
+
+#define	SCB_RESIDUAL_SGPTR		0x184
+#define		SG_ADDR_MASK    	0xf8
+#define		SG_OVERRUN_RESID	0x02
+
+#define	SCB_SCSI_STATUS 		0x188
+#define	SCB_HOST_CDB_LEN		0x188
+
+#define	SCB_TARGET_PHASES		0x189
+
+#define	SCB_TARGET_DATA_DIR		0x18a
+
+#define	SCB_TARGET_ITAG 		0x18b
+
+#define	SCB_SENSE_BUSADDR		0x18c
+#define	SCB_NEXT_COMPLETE		0x18c
+
+#define	SCB_TAG         		0x190
+#define	SCB_FIFO_USE_COUNT		0x190
+
+#define	SCB_CONTROL     		0x192
+#define		TARGET_SCB      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		MK_MESSAGE      	0x10
+#define		STATUS_RCVD     	0x08
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_SCSIID      		0x193
+#define		TID             	0xf0
+#define		OID             	0x0f
+
+#define	SCB_LUN         		0x194
+#define		LID             	0xff
+
+#define	SCB_TASK_ATTRIBUTE		0x195
+#define		SCB_XFERLEN_ODD 	0x01
+
+#define	SCB_CDB_LEN     		0x196
+#define		SCB_CDB_LEN_PTR 	0x80
+
+#define	SCB_TASK_MANAGEMENT		0x197
+
+#define	SCB_DATAPTR     		0x198
+
+#define	SCB_DATACNT     		0x1a0
+#define		SG_LAST_SEG     	0x80
+#define		SG_HIGH_ADDR_BITS	0x7f
+
+#define	SCB_SGPTR       		0x1a4
+#define		SG_STATUS_VALID 	0x04
+#define		SG_FULL_RESID   	0x02
+#define		SG_LIST_NULL    	0x01
+
+#define	SCB_BUSADDR     		0x1a8
+
+#define	SCB_NEXT        		0x1ac
+#define	SCB_NEXT_SCB_BUSADDR		0x1ac
+
+#define	SCB_NEXT2       		0x1ae
+
+#define	SCB_SPARE       		0x1b0
+#define	SCB_PKT_LUN     		0x1b0
+
+#define	SCB_DISCONNECTED_LISTS		0x1b8
+
+
+#define	AHD_TIMER_US_PER_TICK	0x19
+#define	SCB_TRANSFER_SIZE_FULL_LUN	0x38
+#define	STATUS_QUEUE_FULL	0x28
+#define	STATUS_BUSY	0x08
+#define	MAX_OFFSET_NON_PACED	0x7f
+#define	MAX_OFFSET_PACED	0xfe
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+#define	TID_SHIFT	0x04
+#define	MK_MESSAGE_BIT_OFFSET	0x04
+#define	WRTBIASCTL_HP_DEFAULT	0x00
+#define	SEEOP_EWDS_ADDR	0x00
+#define	AHD_AMPLITUDE_SHIFT	0x00
+#define	AHD_AMPLITUDE_MASK	0x07
+#define	AHD_ANNEXCOL_AMPLITUDE	0x06
+#define	AHD_SLEWRATE_DEF_REVA	0x08
+#define	AHD_SLEWRATE_SHIFT	0x03
+#define	AHD_SLEWRATE_MASK	0x78
+#define	AHD_PRECOMP_CUTBACK_29	0x06
+#define	AHD_NUM_PER_DEV_ANNEXCOLS	0x04
+#define	B_CURRFIFO_0	0x02
+#define	LUNLEN_SINGLE_LEVEL_LUN	0x0f
+#define	NVRAM_SCB_OFFSET	0x2c
+#define	AHD_TIMER_MAX_US	0x18ffe7
+#define	AHD_TIMER_MAX_TICKS	0xffff
+#define	STATUS_PKT_SENSE	0xff
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	AHD_SENSE_BUFSIZE	0x100
+#define	MAX_OFFSET_PACED_BUG	0x7f
+#define	BUS_8_BIT	0x00
+#define	STIMESEL_BUG_ADJ	0x08
+#define	STIMESEL_MIN	0x18
+#define	STIMESEL_SHIFT	0x03
+#define	CCSGRAM_MAXSEGS	0x10
+#define	INVALID_ADDR	0x80
+#define	TARGET_CMD_CMPLT	0xfe
+#define	SEEOP_WRAL_ADDR	0x40
+#define	SEEOP_ERAL_ADDR	0x80
+#define	AHD_AMPLITUDE_DEF	0x07
+#define	AHD_SLEWRATE_DEF_REVB	0x08
+#define	AHD_PRECOMP_CUTBACK_37	0x07
+#define	AHD_PRECOMP_CUTBACK_17	0x04
+#define	AHD_PRECOMP_SHIFT	0x00
+#define	AHD_PRECOMP_MASK	0x07
+#define	AHD_ANNEXCOL_PRECOMP_SLEW	0x04
+#define	SRC_MODE_SHIFT	0x00
+#define	PKT_OVERRUN_BUFSIZE	0x200
+#define	SCB_TRANSFER_SIZE_1BYTE_LUN	0x30
+#define	TARGET_DATA_IN	0x01
+#define	HOST_MSG	0xff
+#define	MAX_OFFSET	0xfe
+#define	BUS_16_BIT	0x01
+#define	CCSCBADDR_MAX	0x80
+#define	NUMDSPS 	0x14
+#define	SEEOP_EWEN_ADDR	0xc0
+#define	AHD_ANNEXCOL_PER_DEV0	0x04
+#define	DST_MODE_SHIFT	0x04
+
+
+/* Downloaded Constant Definitions */
+#define	SCB_TRANSFER_SIZE	0x06
+#define	PKT_OVERRUN_BUFOFFSET	0x05
+#define	SG_SIZEOF	0x04
+#define	SG_PREFETCH_ADDR_MASK	0x03
+#define	SG_PREFETCH_ALIGN_MASK	0x02
+#define	SG_PREFETCH_CNT_LIMIT	0x01
+#define	SG_PREFETCH_CNT	0x00
+#define	DOWNLOAD_CONST_COUNT	0x07
+
+
+/* Exported Labels */
+#define	LABEL_seq_isr 	0x269
+#define	LABEL_timer_isr	0x265
diff --git a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
new file mode 100644
index 0000000..3098a75
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
@@ -0,0 +1,3635 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ */
+
+#include "aic79xx_osm.h"
+
+static ahd_reg_parse_entry_t MODE_PTR_parse_table[] = {
+	{ "SRC_MODE",		0x07, 0x07 },
+	{ "DST_MODE",		0x70, 0x70 }
+};
+
+int
+ahd_mode_ptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(MODE_PTR_parse_table, 2, "MODE_PTR",
+	    0x00, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t INTSTAT_parse_table[] = {
+	{ "SPLTINT",		0x01, 0x01 },
+	{ "CMDCMPLT",		0x02, 0x02 },
+	{ "SEQINT",		0x04, 0x04 },
+	{ "SCSIINT",		0x08, 0x08 },
+	{ "PCIINT",		0x10, 0x10 },
+	{ "SWTMINT",		0x20, 0x20 },
+	{ "BRKADRINT",		0x40, 0x40 },
+	{ "HWERRINT",		0x80, 0x80 },
+	{ "INT_PEND",		0xff, 0xff }
+};
+
+int
+ahd_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(INTSTAT_parse_table, 9, "INTSTAT",
+	    0x01, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQINTCODE_parse_table[] = {
+	{ "NO_SEQINT",		0x00, 0xff },
+	{ "BAD_PHASE",		0x01, 0xff },
+	{ "SEND_REJECT",	0x02, 0xff },
+	{ "PROTO_VIOLATION",	0x03, 0xff },
+	{ "NO_MATCH",		0x04, 0xff },
+	{ "IGN_WIDE_RES",	0x05, 0xff },
+	{ "PDATA_REINIT",	0x06, 0xff },
+	{ "HOST_MSG_LOOP",	0x07, 0xff },
+	{ "BAD_STATUS",		0x08, 0xff },
+	{ "DATA_OVERRUN",	0x09, 0xff },
+	{ "MKMSG_FAILED",	0x0a, 0xff },
+	{ "MISSED_BUSFREE",	0x0b, 0xff },
+	{ "DUMP_CARD_STATE",	0x0c, 0xff },
+	{ "ILLEGAL_PHASE",	0x0d, 0xff },
+	{ "INVALID_SEQINT",	0x0e, 0xff },
+	{ "CFG4ISTAT_INTR",	0x0f, 0xff },
+	{ "STATUS_OVERRUN",	0x10, 0xff },
+	{ "CFG4OVERRUN",	0x11, 0xff },
+	{ "ENTERING_NONPACK",	0x12, 0xff },
+	{ "TASKMGMT_FUNC_COMPLETE",0x13, 0xff },
+	{ "TASKMGMT_CMD_CMPLT_OKAY",0x14, 0xff },
+	{ "TRACEPOINT0",	0x15, 0xff },
+	{ "TRACEPOINT1",	0x16, 0xff },
+	{ "TRACEPOINT2",	0x17, 0xff },
+	{ "TRACEPOINT3",	0x18, 0xff },
+	{ "SAW_HWERR",		0x19, 0xff },
+	{ "BAD_SCB_STATUS",	0x1a, 0xff }
+};
+
+int
+ahd_seqintcode_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQINTCODE_parse_table, 27, "SEQINTCODE",
+	    0x02, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRINT_parse_table[] = {
+	{ "CLRSPLTINT",		0x01, 0x01 },
+	{ "CLRCMDINT",		0x02, 0x02 },
+	{ "CLRSEQINT",		0x04, 0x04 },
+	{ "CLRSCSIINT",		0x08, 0x08 },
+	{ "CLRPCIINT",		0x10, 0x10 },
+	{ "CLRSWTMINT",		0x20, 0x20 },
+	{ "CLRBRKADRINT",	0x40, 0x40 },
+	{ "CLRHWERRINT",	0x80, 0x80 }
+};
+
+int
+ahd_clrint_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRINT_parse_table, 8, "CLRINT",
+	    0x03, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t ERROR_parse_table[] = {
+	{ "DSCTMOUT",		0x02, 0x02 },
+	{ "ILLOPCODE",		0x04, 0x04 },
+	{ "SQPARERR",		0x08, 0x08 },
+	{ "DPARERR",		0x10, 0x10 },
+	{ "MPARERR",		0x20, 0x20 },
+	{ "CIOACCESFAIL",	0x40, 0x40 },
+	{ "CIOPARERR",		0x80, 0x80 }
+};
+
+int
+ahd_error_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(ERROR_parse_table, 7, "ERROR",
+	    0x04, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRERR_parse_table[] = {
+	{ "CLRDSCTMOUT",	0x02, 0x02 },
+	{ "CLRILLOPCODE",	0x04, 0x04 },
+	{ "CLRSQPARERR",	0x08, 0x08 },
+	{ "CLRDPARERR",		0x10, 0x10 },
+	{ "CLRMPARERR",		0x20, 0x20 },
+	{ "CLRCIOACCESFAIL",	0x40, 0x40 },
+	{ "CLRCIOPARERR",	0x80, 0x80 }
+};
+
+int
+ahd_clrerr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRERR_parse_table, 7, "CLRERR",
+	    0x04, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t HCNTRL_parse_table[] = {
+	{ "CHIPRST",		0x01, 0x01 },
+	{ "CHIPRSTACK",		0x01, 0x01 },
+	{ "INTEN",		0x02, 0x02 },
+	{ "PAUSE",		0x04, 0x04 },
+	{ "SWTIMER_START_B",	0x08, 0x08 },
+	{ "SWINT",		0x10, 0x10 },
+	{ "POWRDN",		0x40, 0x40 },
+	{ "SEQ_RESET",		0x80, 0x80 }
+};
+
+int
+ahd_hcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(HCNTRL_parse_table, 8, "HCNTRL",
+	    0x05, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hnscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HNSCB_QOFF",
+	    0x06, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hescb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HESCB_QOFF",
+	    0x08, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
+	{ "ENINT_COALESCE",	0x40, 0x40 },
+	{ "HOST_TQINPOS",	0x80, 0x80 }
+};
+
+int
+ahd_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(HS_MAILBOX_parse_table, 2, "HS_MAILBOX",
+	    0x0b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSEQINTSTAT_parse_table[] = {
+	{ "CLRSEQ_SPLTINT",	0x01, 0x01 },
+	{ "CLRSEQ_PCIINT",	0x02, 0x02 },
+	{ "CLRSEQ_SCSIINT",	0x04, 0x04 },
+	{ "CLRSEQ_SEQINT",	0x08, 0x08 },
+	{ "CLRSEQ_SWTMRTO",	0x10, 0x10 }
+};
+
+int
+ahd_clrseqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSEQINTSTAT_parse_table, 5, "CLRSEQINTSTAT",
+	    0x0c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQINTSTAT_parse_table[] = {
+	{ "SEQ_SPLTINT",	0x01, 0x01 },
+	{ "SEQ_PCIINT",		0x02, 0x02 },
+	{ "SEQ_SCSIINT",	0x04, 0x04 },
+	{ "SEQ_SEQINT",		0x08, 0x08 },
+	{ "SEQ_SWTMRTO",	0x10, 0x10 }
+};
+
+int
+ahd_seqintstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQINTSTAT_parse_table, 5, "SEQINTSTAT",
+	    0x0c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_swtimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SWTIMER",
+	    0x0e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_snscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SNSCB_QOFF",
+	    0x10, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sescb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SESCB_QOFF",
+	    0x12, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sdscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SDSCB_QOFF",
+	    0x14, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
+	{ "SCB_QSIZE_4",	0x00, 0x0f },
+	{ "SCB_QSIZE_8",	0x01, 0x0f },
+	{ "SCB_QSIZE_16",	0x02, 0x0f },
+	{ "SCB_QSIZE_32",	0x03, 0x0f },
+	{ "SCB_QSIZE_64",	0x04, 0x0f },
+	{ "SCB_QSIZE_128",	0x05, 0x0f },
+	{ "SCB_QSIZE_256",	0x06, 0x0f },
+	{ "SCB_QSIZE_512",	0x07, 0x0f },
+	{ "SCB_QSIZE_1024",	0x08, 0x0f },
+	{ "SCB_QSIZE_2048",	0x09, 0x0f },
+	{ "SCB_QSIZE_4096",	0x0a, 0x0f },
+	{ "SCB_QSIZE_8192",	0x0b, 0x0f },
+	{ "SCB_QSIZE_16384",	0x0c, 0x0f },
+	{ "SCB_QSIZE",		0x0f, 0x0f },
+	{ "HS_MAILBOX_ACT",	0x10, 0x10 },
+	{ "SDSCB_ROLLOVR",	0x20, 0x20 },
+	{ "NEW_SCB_AVAIL",	0x40, 0x40 },
+	{ "EMPTY_SCB_AVAIL",	0x80, 0x80 }
+};
+
+int
+ahd_qoff_ctlsta_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(QOFF_CTLSTA_parse_table, 18, "QOFF_CTLSTA",
+	    0x16, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t INTCTL_parse_table[] = {
+	{ "SPLTINTEN",		0x01, 0x01 },
+	{ "SEQINTEN",		0x02, 0x02 },
+	{ "SCSIINTEN",		0x04, 0x04 },
+	{ "PCIINTEN",		0x08, 0x08 },
+	{ "AUTOCLRCMDINT",	0x10, 0x10 },
+	{ "SWTIMER_START",	0x20, 0x20 },
+	{ "SWTMINTEN",		0x40, 0x40 },
+	{ "SWTMINTMASK",	0x80, 0x80 }
+};
+
+int
+ahd_intctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(INTCTL_parse_table, 8, "INTCTL",
+	    0x18, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFCNTRL_parse_table[] = {
+	{ "DIRECTIONEN",	0x01, 0x01 },
+	{ "FIFOFLUSH",		0x02, 0x02 },
+	{ "FIFOFLUSHACK",	0x02, 0x02 },
+	{ "DIRECTION",		0x04, 0x04 },
+	{ "DIRECTIONACK",	0x04, 0x04 },
+	{ "HDMAEN",		0x08, 0x08 },
+	{ "HDMAENACK",		0x08, 0x08 },
+	{ "SCSIEN",		0x20, 0x20 },
+	{ "SCSIENACK",		0x20, 0x20 },
+	{ "SCSIENWRDIS",	0x40, 0x40 },
+	{ "PRELOADEN",		0x80, 0x80 }
+};
+
+int
+ahd_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFCNTRL_parse_table, 11, "DFCNTRL",
+	    0x19, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
+	{ "CIOPARCKEN",		0x01, 0x01 },
+	{ "DISABLE_TWATE",	0x02, 0x02 },
+	{ "EXTREQLCK",		0x10, 0x10 },
+	{ "MPARCKEN",		0x20, 0x20 },
+	{ "DPARCKEN",		0x40, 0x40 },
+	{ "CACHETHEN",		0x80, 0x80 }
+};
+
+int
+ahd_dscommand0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSCOMMAND0_parse_table, 6, "DSCOMMAND0",
+	    0x19, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFSTATUS_parse_table[] = {
+	{ "FIFOEMP",		0x01, 0x01 },
+	{ "FIFOFULL",		0x02, 0x02 },
+	{ "DFTHRESH",		0x04, 0x04 },
+	{ "HDONE",		0x08, 0x08 },
+	{ "MREQPEND",		0x10, 0x10 },
+	{ "PKT_PRELOAD_AVAIL",	0x40, 0x40 },
+	{ "PRELOAD_AVAIL",	0x80, 0x80 }
+};
+
+int
+ahd_dfstatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFSTATUS_parse_table, 7, "DFSTATUS",
+	    0x1a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
+	{ "LAST_SEG_DONE",	0x01, 0x01 },
+	{ "LAST_SEG",		0x02, 0x02 },
+	{ "ODD_SEG",		0x04, 0x04 },
+	{ "SG_ADDR_MASK",	0xf8, 0xf8 }
+};
+
+int
+ahd_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SG_CACHE_SHADOW_parse_table, 4, "SG_CACHE_SHADOW",
+	    0x1b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t ARBCTL_parse_table[] = {
+	{ "USE_TIME",		0x07, 0x07 },
+	{ "RETRY_SWEN",		0x08, 0x08 },
+	{ "RESET_HARB",		0x80, 0x80 }
+};
+
+int
+ahd_arbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(ARBCTL_parse_table, 3, "ARBCTL",
+	    0x1b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
+	{ "LAST_SEG",		0x02, 0x02 },
+	{ "ODD_SEG",		0x04, 0x04 },
+	{ "SG_ADDR_MASK",	0xf8, 0xf8 }
+};
+
+int
+ahd_sg_cache_pre_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SG_CACHE_PRE_parse_table, 3, "SG_CACHE_PRE",
+	    0x1b, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqin_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQIN",
+	    0x20, regvalue, cur_col, wrap));
+}
+
+int
+ahd_typeptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "TYPEPTR",
+	    0x20, regvalue, cur_col, wrap));
+}
+
+int
+ahd_tagptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "TAGPTR",
+	    0x21, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lunptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LUNPTR",
+	    0x22, regvalue, cur_col, wrap));
+}
+
+int
+ahd_datalenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DATALENPTR",
+	    0x23, regvalue, cur_col, wrap));
+}
+
+int
+ahd_statlenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "STATLENPTR",
+	    0x24, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmdlenptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMDLENPTR",
+	    0x25, regvalue, cur_col, wrap));
+}
+
+int
+ahd_attrptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ATTRPTR",
+	    0x26, regvalue, cur_col, wrap));
+}
+
+int
+ahd_flagptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FLAGPTR",
+	    0x27, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmdptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMDPTR",
+	    0x28, regvalue, cur_col, wrap));
+}
+
+int
+ahd_qnextptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "QNEXTPTR",
+	    0x29, regvalue, cur_col, wrap));
+}
+
+int
+ahd_idptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "IDPTR",
+	    0x2a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_abrtbyteptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ABRTBYTEPTR",
+	    0x2b, regvalue, cur_col, wrap));
+}
+
+int
+ahd_abrtbitptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ABRTBITPTR",
+	    0x2c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_maxcmdbytes_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MAXCMDBYTES",
+	    0x2d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_maxcmd2rcv_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MAXCMD2RCV",
+	    0x2e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_shortthresh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SHORTTHRESH",
+	    0x2f, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LUNLEN_parse_table[] = {
+	{ "ILUNLEN",		0x0f, 0x0f },
+	{ "TLUNLEN",		0xf0, 0xf0 }
+};
+
+int
+ahd_lunlen_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LUNLEN_parse_table, 2, "LUNLEN",
+	    0x30, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cdblimit_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CDBLIMIT",
+	    0x31, regvalue, cur_col, wrap));
+}
+
+int
+ahd_maxcmd_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MAXCMD",
+	    0x32, regvalue, cur_col, wrap));
+}
+
+int
+ahd_maxcmdcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MAXCMDCNT",
+	    0x33, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqrsvd01_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQRSVD01",
+	    0x34, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqrsvd16_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQRSVD16",
+	    0x35, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqrsvd17_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQRSVD17",
+	    0x36, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmdrsvd0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMDRSVD0",
+	    0x37, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQCTL0_parse_table[] = {
+	{ "LQ0INITGCLT",	0x03, 0x03 },
+	{ "LQ0TARGCLT",		0x0c, 0x0c },
+	{ "LQIINITGCLT",	0x30, 0x30 },
+	{ "LQITARGCLT",		0xc0, 0xc0 }
+};
+
+int
+ahd_lqctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQCTL0_parse_table, 4, "LQCTL0",
+	    0x38, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQCTL1_parse_table[] = {
+	{ "ABORTPENDING",	0x01, 0x01 },
+	{ "SINGLECMD",		0x02, 0x02 },
+	{ "PCI2PCI",		0x04, 0x04 }
+};
+
+int
+ahd_lqctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQCTL1_parse_table, 3, "LQCTL1",
+	    0x38, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSBIST0_parse_table[] = {
+	{ "OSBISTRUN",		0x01, 0x01 },
+	{ "OSBISTDONE",		0x02, 0x02 },
+	{ "OSBISTERR",		0x04, 0x04 },
+	{ "GSBISTRUN",		0x10, 0x10 },
+	{ "GSBISTDONE",		0x20, 0x20 },
+	{ "GSBISTERR",		0x40, 0x40 }
+};
+
+int
+ahd_scsbist0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSBIST0_parse_table, 6, "SCSBIST0",
+	    0x39, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQCTL2_parse_table[] = {
+	{ "LQOPAUSE",		0x01, 0x01 },
+	{ "LQOTOIDLE",		0x02, 0x02 },
+	{ "LQOCONTINUE",	0x04, 0x04 },
+	{ "LQORETRY",		0x08, 0x08 },
+	{ "LQIPAUSE",		0x10, 0x10 },
+	{ "LQITOIDLE",		0x20, 0x20 },
+	{ "LQICONTINUE",	0x40, 0x40 },
+	{ "LQIRETRY",		0x80, 0x80 }
+};
+
+int
+ahd_lqctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQCTL2_parse_table, 8, "LQCTL2",
+	    0x39, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSBIST1_parse_table[] = {
+	{ "NTBISTRUN",		0x01, 0x01 },
+	{ "NTBISTDONE",		0x02, 0x02 },
+	{ "NTBISTERR",		0x04, 0x04 }
+};
+
+int
+ahd_scsbist1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSBIST1_parse_table, 3, "SCSBIST1",
+	    0x3a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSISEQ0_parse_table[] = {
+	{ "SCSIRSTO",		0x01, 0x01 },
+	{ "FORCEBUSFREE",	0x10, 0x10 },
+	{ "ENARBO",		0x20, 0x20 },
+	{ "ENSELO",		0x40, 0x40 },
+	{ "TEMODEO",		0x80, 0x80 }
+};
+
+int
+ahd_scsiseq0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSISEQ0_parse_table, 5, "SCSISEQ0",
+	    0x3a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSISEQ1_parse_table[] = {
+	{ "ALTSTIM",		0x01, 0x01 },
+	{ "ENAUTOATNP",		0x02, 0x02 },
+	{ "MANUALP",		0x0c, 0x0c },
+	{ "ENRSELI",		0x10, 0x10 },
+	{ "ENSELI",		0x20, 0x20 },
+	{ "MANUALCTL",		0x40, 0x40 }
+};
+
+int
+ahd_scsiseq1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSISEQ1_parse_table, 6, "SCSISEQ1",
+	    0x3b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SXFRCTL0_parse_table[] = {
+	{ "SPIOEN",		0x08, 0x08 },
+	{ "BIOSCANCELEN",	0x10, 0x10 },
+	{ "DFPEXP",		0x40, 0x40 },
+	{ "DFON",		0x80, 0x80 }
+};
+
+int
+ahd_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SXFRCTL0_parse_table, 4, "SXFRCTL0",
+	    0x3c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_businitid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "BUSINITID",
+	    0x3c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dlcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DLCOUNT",
+	    0x3c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SXFRCTL1_parse_table[] = {
+	{ "STPWEN",		0x01, 0x01 },
+	{ "ACTNEGEN",		0x02, 0x02 },
+	{ "ENSTIMER",		0x04, 0x04 },
+	{ "STIMESEL",		0x18, 0x18 },
+	{ "ENSPCHK",		0x20, 0x20 },
+	{ "ENSACHK",		0x40, 0x40 },
+	{ "BITBUCKET",		0x80, 0x80 }
+};
+
+int
+ahd_sxfrctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SXFRCTL1_parse_table, 7, "SXFRCTL1",
+	    0x3d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_bustargid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "BUSTARGID",
+	    0x3e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SXFRCTL2_parse_table[] = {
+	{ "ASU",		0x07, 0x07 },
+	{ "CMDDMAEN",		0x08, 0x08 },
+	{ "AUTORSTDIS",		0x10, 0x10 }
+};
+
+int
+ahd_sxfrctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SXFRCTL2_parse_table, 3, "SXFRCTL2",
+	    0x3e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFFSTAT_parse_table[] = {
+	{ "CURRFIFO_0",		0x00, 0x03 },
+	{ "CURRFIFO_1",		0x01, 0x03 },
+	{ "CURRFIFO_NONE",	0x03, 0x03 },
+	{ "FIFO0FREE",		0x10, 0x10 },
+	{ "FIFO1FREE",		0x20, 0x20 },
+	{ "CURRFIFO",		0x03, 0x03 }
+};
+
+int
+ahd_dffstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFFSTAT_parse_table, 6, "DFFSTAT",
+	    0x3f, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSISIGO_parse_table[] = {
+	{ "P_DATAOUT",		0x00, 0xe0 },
+	{ "P_DATAOUT_DT",	0x20, 0xe0 },
+	{ "P_DATAIN",		0x40, 0xe0 },
+	{ "P_DATAIN_DT",	0x60, 0xe0 },
+	{ "P_COMMAND",		0x80, 0xe0 },
+	{ "P_MESGOUT",		0xa0, 0xe0 },
+	{ "P_STATUS",		0xc0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 },
+	{ "ACKO",		0x01, 0x01 },
+	{ "REQO",		0x02, 0x02 },
+	{ "BSYO",		0x04, 0x04 },
+	{ "SELO",		0x08, 0x08 },
+	{ "ATNO",		0x10, 0x10 },
+	{ "MSGO",		0x20, 0x20 },
+	{ "IOO",		0x40, 0x40 },
+	{ "CDO",		0x80, 0x80 },
+	{ "PHASE_MASK",		0xe0, 0xe0 }
+};
+
+int
+ahd_scsisigo_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSISIGO_parse_table, 17, "SCSISIGO",
+	    0x40, regvalue, cur_col, wrap));
+}
+
+int
+ahd_multargid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MULTARGID",
+	    0x40, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSISIGI_parse_table[] = {
+	{ "P_DATAOUT",		0x00, 0xe0 },
+	{ "P_DATAOUT_DT",	0x20, 0xe0 },
+	{ "P_DATAIN",		0x40, 0xe0 },
+	{ "P_DATAIN_DT",	0x60, 0xe0 },
+	{ "P_COMMAND",		0x80, 0xe0 },
+	{ "P_MESGOUT",		0xa0, 0xe0 },
+	{ "P_STATUS",		0xc0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 },
+	{ "ACKI",		0x01, 0x01 },
+	{ "REQI",		0x02, 0x02 },
+	{ "BSYI",		0x04, 0x04 },
+	{ "SELI",		0x08, 0x08 },
+	{ "ATNI",		0x10, 0x10 },
+	{ "MSGI",		0x20, 0x20 },
+	{ "IOI",		0x40, 0x40 },
+	{ "CDI",		0x80, 0x80 },
+	{ "PHASE_MASK",		0xe0, 0xe0 }
+};
+
+int
+ahd_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSISIGI_parse_table, 17, "SCSISIGI",
+	    0x41, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSIPHASE_parse_table[] = {
+	{ "DATA_OUT_PHASE",	0x01, 0x03 },
+	{ "DATA_IN_PHASE",	0x02, 0x03 },
+	{ "DATA_PHASE_MASK",	0x03, 0x03 },
+	{ "MSG_OUT_PHASE",	0x04, 0x04 },
+	{ "MSG_IN_PHASE",	0x08, 0x08 },
+	{ "COMMAND_PHASE",	0x10, 0x10 },
+	{ "STATUS_PHASE",	0x20, 0x20 }
+};
+
+int
+ahd_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSIPHASE_parse_table, 7, "SCSIPHASE",
+	    0x42, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scsidat0_img_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCSIDAT0_IMG",
+	    0x43, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scsidat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCSIDAT",
+	    0x44, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scsibus_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCSIBUS",
+	    0x46, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t TARGIDIN_parse_table[] = {
+	{ "TARGID",		0x0f, 0x0f },
+	{ "CLKOUT",		0x80, 0x80 }
+};
+
+int
+ahd_targidin_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(TARGIDIN_parse_table, 2, "TARGIDIN",
+	    0x48, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SELID_parse_table[] = {
+	{ "ONEBIT",		0x08, 0x08 },
+	{ "SELID_MASK",		0xf0, 0xf0 }
+};
+
+int
+ahd_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SELID_parse_table, 2, "SELID",
+	    0x49, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SBLKCTL_parse_table[] = {
+	{ "SELWIDE",		0x02, 0x02 },
+	{ "ENAB20",		0x04, 0x04 },
+	{ "ENAB40",		0x08, 0x08 },
+	{ "DIAGLEDON",		0x40, 0x40 },
+	{ "DIAGLEDEN",		0x80, 0x80 }
+};
+
+int
+ahd_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SBLKCTL_parse_table, 5, "SBLKCTL",
+	    0x4a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OPTIONMODE_parse_table[] = {
+	{ "AUTO_MSGOUT_DE",	0x02, 0x02 },
+	{ "ENDGFORMCHK",	0x04, 0x04 },
+	{ "BUSFREEREV",		0x10, 0x10 },
+	{ "BIASCANCTL",		0x20, 0x20 },
+	{ "AUTOACKEN",		0x40, 0x40 },
+	{ "BIOSCANCTL",		0x80, 0x80 },
+	{ "OPTIONMODE_DEFAULTS",0x02, 0x02 }
+};
+
+int
+ahd_optionmode_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OPTIONMODE_parse_table, 7, "OPTIONMODE",
+	    0x4a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SSTAT0_parse_table[] = {
+	{ "ARBDO",		0x01, 0x01 },
+	{ "SPIORDY",		0x02, 0x02 },
+	{ "OVERRUN",		0x04, 0x04 },
+	{ "IOERR",		0x08, 0x08 },
+	{ "SELINGO",		0x10, 0x10 },
+	{ "SELDI",		0x20, 0x20 },
+	{ "SELDO",		0x40, 0x40 },
+	{ "TARGET",		0x80, 0x80 }
+};
+
+int
+ahd_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SSTAT0_parse_table, 8, "SSTAT0",
+	    0x4b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSINT0_parse_table[] = {
+	{ "CLRARBDO",		0x01, 0x01 },
+	{ "CLRSPIORDY",		0x02, 0x02 },
+	{ "CLROVERRUN",		0x04, 0x04 },
+	{ "CLRIOERR",		0x08, 0x08 },
+	{ "CLRSELINGO",		0x10, 0x10 },
+	{ "CLRSELDI",		0x20, 0x20 },
+	{ "CLRSELDO",		0x40, 0x40 }
+};
+
+int
+ahd_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSINT0_parse_table, 7, "CLRSINT0",
+	    0x4b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SIMODE0_parse_table[] = {
+	{ "ENARBDO",		0x01, 0x01 },
+	{ "ENSPIORDY",		0x02, 0x02 },
+	{ "ENOVERRUN",		0x04, 0x04 },
+	{ "ENIOERR",		0x08, 0x08 },
+	{ "ENSELINGO",		0x10, 0x10 },
+	{ "ENSELDI",		0x20, 0x20 },
+	{ "ENSELDO",		0x40, 0x40 }
+};
+
+int
+ahd_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SIMODE0_parse_table, 7, "SIMODE0",
+	    0x4b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSINT1_parse_table[] = {
+	{ "CLRREQINIT",		0x01, 0x01 },
+	{ "CLRSTRB2FAST",	0x02, 0x02 },
+	{ "CLRSCSIPERR",	0x04, 0x04 },
+	{ "CLRBUSFREE",		0x08, 0x08 },
+	{ "CLRSCSIRSTI",	0x20, 0x20 },
+	{ "CLRATNO",		0x40, 0x40 },
+	{ "CLRSELTIMEO",	0x80, 0x80 }
+};
+
+int
+ahd_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSINT1_parse_table, 7, "CLRSINT1",
+	    0x4c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SSTAT1_parse_table[] = {
+	{ "REQINIT",		0x01, 0x01 },
+	{ "STRB2FAST",		0x02, 0x02 },
+	{ "SCSIPERR",		0x04, 0x04 },
+	{ "BUSFREE",		0x08, 0x08 },
+	{ "PHASEMIS",		0x10, 0x10 },
+	{ "SCSIRSTI",		0x20, 0x20 },
+	{ "ATNTARG",		0x40, 0x40 },
+	{ "SELTO",		0x80, 0x80 }
+};
+
+int
+ahd_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SSTAT1_parse_table, 8, "SSTAT1",
+	    0x4c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SSTAT2_parse_table[] = {
+	{ "BUSFREE_LQO",	0x40, 0xc0 },
+	{ "BUSFREE_DFF0",	0x80, 0xc0 },
+	{ "BUSFREE_DFF1",	0xc0, 0xc0 },
+	{ "DMADONE",		0x01, 0x01 },
+	{ "SDONE",		0x02, 0x02 },
+	{ "WIDE_RES",		0x04, 0x04 },
+	{ "BSYX",		0x08, 0x08 },
+	{ "EXP_ACTIVE",		0x10, 0x10 },
+	{ "NONPACKREQ",		0x20, 0x20 },
+	{ "BUSFREETIME",	0xc0, 0xc0 }
+};
+
+int
+ahd_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SSTAT2_parse_table, 10, "SSTAT2",
+	    0x4d, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSINT2_parse_table[] = {
+	{ "CLRDMADONE",		0x01, 0x01 },
+	{ "CLRSDONE",		0x02, 0x02 },
+	{ "CLRWIDE_RES",	0x04, 0x04 },
+	{ "CLRNONPACKREQ",	0x20, 0x20 }
+};
+
+int
+ahd_clrsint2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSINT2_parse_table, 4, "CLRSINT2",
+	    0x4d, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SIMODE2_parse_table[] = {
+	{ "ENDMADONE",		0x01, 0x01 },
+	{ "ENSDONE",		0x02, 0x02 },
+	{ "ENWIDE_RES",		0x04, 0x04 }
+};
+
+int
+ahd_simode2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SIMODE2_parse_table, 3, "SIMODE2",
+	    0x4d, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PERRDIAG_parse_table[] = {
+	{ "DTERR",		0x01, 0x01 },
+	{ "DGFORMERR",		0x02, 0x02 },
+	{ "CRCERR",		0x04, 0x04 },
+	{ "AIPERR",		0x08, 0x08 },
+	{ "PARITYERR",		0x10, 0x10 },
+	{ "PREVPHASE",		0x20, 0x20 },
+	{ "HIPERR",		0x40, 0x40 },
+	{ "HIZERO",		0x80, 0x80 }
+};
+
+int
+ahd_perrdiag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PERRDIAG_parse_table, 8, "PERRDIAG",
+	    0x4e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqistate_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQISTATE",
+	    0x4e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_soffcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SOFFCNT",
+	    0x4f, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lqostate_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LQOSTATE",
+	    0x4f, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQISTAT0_parse_table[] = {
+	{ "LQIATNCMD",		0x01, 0x01 },
+	{ "LQIATNLQ",		0x02, 0x02 },
+	{ "LQIBADLQT",		0x04, 0x04 },
+	{ "LQICRCT2",		0x08, 0x08 },
+	{ "LQICRCT1",		0x10, 0x10 },
+	{ "LQIATNQAS",		0x20, 0x20 }
+};
+
+int
+ahd_lqistat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQISTAT0_parse_table, 6, "LQISTAT0",
+	    0x50, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRLQIINT0_parse_table[] = {
+	{ "CLRLQIATNCMD",	0x01, 0x01 },
+	{ "CLRLQIATNLQ",	0x02, 0x02 },
+	{ "CLRLQIBADLQT",	0x04, 0x04 },
+	{ "CLRLQICRCT2",	0x08, 0x08 },
+	{ "CLRLQICRCT1",	0x10, 0x10 },
+	{ "CLRLQIATNQAS",	0x20, 0x20 }
+};
+
+int
+ahd_clrlqiint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRLQIINT0_parse_table, 6, "CLRLQIINT0",
+	    0x50, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQIMODE0_parse_table[] = {
+	{ "ENLQIATNCMD",	0x01, 0x01 },
+	{ "ENLQIATNLQ",		0x02, 0x02 },
+	{ "ENLQIBADLQT",	0x04, 0x04 },
+	{ "ENLQICRCT2",		0x08, 0x08 },
+	{ "ENLQICRCT1",		0x10, 0x10 },
+	{ "ENLQIATNQASK",	0x20, 0x20 }
+};
+
+int
+ahd_lqimode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQIMODE0_parse_table, 6, "LQIMODE0",
+	    0x50, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQIMODE1_parse_table[] = {
+	{ "ENLQIOVERI_NLQ",	0x01, 0x01 },
+	{ "ENLQIOVERI_LQ",	0x02, 0x02 },
+	{ "ENLQIBADLQI",	0x04, 0x04 },
+	{ "ENLQICRCI_NLQ",	0x08, 0x08 },
+	{ "ENLQICRCI_LQ",	0x10, 0x10 },
+	{ "ENLIQABORT",		0x20, 0x20 },
+	{ "ENLQIPHASE_NLQ",	0x40, 0x40 },
+	{ "ENLQIPHASE_LQ",	0x80, 0x80 }
+};
+
+int
+ahd_lqimode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQIMODE1_parse_table, 8, "LQIMODE1",
+	    0x51, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQISTAT1_parse_table[] = {
+	{ "LQIOVERI_NLQ",	0x01, 0x01 },
+	{ "LQIOVERI_LQ",	0x02, 0x02 },
+	{ "LQIBADLQI",		0x04, 0x04 },
+	{ "LQICRCI_NLQ",	0x08, 0x08 },
+	{ "LQICRCI_LQ",		0x10, 0x10 },
+	{ "LQIABORT",		0x20, 0x20 },
+	{ "LQIPHASE_NLQ",	0x40, 0x40 },
+	{ "LQIPHASE_LQ",	0x80, 0x80 }
+};
+
+int
+ahd_lqistat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQISTAT1_parse_table, 8, "LQISTAT1",
+	    0x51, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRLQIINT1_parse_table[] = {
+	{ "CLRLQIOVERI_NLQ",	0x01, 0x01 },
+	{ "CLRLQIOVERI_LQ",	0x02, 0x02 },
+	{ "CLRLQIBADLQI",	0x04, 0x04 },
+	{ "CLRLQICRCI_NLQ",	0x08, 0x08 },
+	{ "CLRLQICRCI_LQ",	0x10, 0x10 },
+	{ "CLRLIQABORT",	0x20, 0x20 },
+	{ "CLRLQIPHASE_NLQ",	0x40, 0x40 },
+	{ "CLRLQIPHASE_LQ",	0x80, 0x80 }
+};
+
+int
+ahd_clrlqiint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRLQIINT1_parse_table, 8, "CLRLQIINT1",
+	    0x51, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQISTAT2_parse_table[] = {
+	{ "LQIGSAVAIL",		0x01, 0x01 },
+	{ "LQISTOPCMD",		0x02, 0x02 },
+	{ "LQISTOPLQ",		0x04, 0x04 },
+	{ "LQISTOPPKT",		0x08, 0x08 },
+	{ "LQIWAITFIFO",	0x10, 0x10 },
+	{ "LQIWORKONLQ",	0x20, 0x20 },
+	{ "LQIPHASE_OUTPKT",	0x40, 0x40 },
+	{ "PACKETIZED",		0x80, 0x80 }
+};
+
+int
+ahd_lqistat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQISTAT2_parse_table, 8, "LQISTAT2",
+	    0x52, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SSTAT3_parse_table[] = {
+	{ "OSRAMPERR",		0x01, 0x01 },
+	{ "NTRAMPERR",		0x02, 0x02 }
+};
+
+int
+ahd_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SSTAT3_parse_table, 2, "SSTAT3",
+	    0x53, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SIMODE3_parse_table[] = {
+	{ "ENOSRAMPERR",	0x01, 0x01 },
+	{ "ENNTRAMPERR",	0x02, 0x02 }
+};
+
+int
+ahd_simode3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SIMODE3_parse_table, 2, "SIMODE3",
+	    0x53, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSINT3_parse_table[] = {
+	{ "CLROSRAMPERR",	0x01, 0x01 },
+	{ "CLRNTRAMPERR",	0x02, 0x02 }
+};
+
+int
+ahd_clrsint3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSINT3_parse_table, 2, "CLRSINT3",
+	    0x53, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOMODE0_parse_table[] = {
+	{ "ENLQOTCRC",		0x01, 0x01 },
+	{ "ENLQOATNPKT",	0x02, 0x02 },
+	{ "ENLQOATNLQ",		0x04, 0x04 },
+	{ "ENLQOSTOPT2",	0x08, 0x08 },
+	{ "ENLQOTARGSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqomode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOMODE0_parse_table, 5, "LQOMODE0",
+	    0x54, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOSTAT0_parse_table[] = {
+	{ "LQOTCRC",		0x01, 0x01 },
+	{ "LQOATNPKT",		0x02, 0x02 },
+	{ "LQOATNLQ",		0x04, 0x04 },
+	{ "LQOSTOPT2",		0x08, 0x08 },
+	{ "LQOTARGSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqostat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOSTAT0_parse_table, 5, "LQOSTAT0",
+	    0x54, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRLQOINT0_parse_table[] = {
+	{ "CLRLQOTCRC",		0x01, 0x01 },
+	{ "CLRLQOATNPKT",	0x02, 0x02 },
+	{ "CLRLQOATNLQ",	0x04, 0x04 },
+	{ "CLRLQOSTOPT2",	0x08, 0x08 },
+	{ "CLRLQOTARGSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_clrlqoint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRLQOINT0_parse_table, 5, "CLRLQOINT0",
+	    0x54, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOSTAT1_parse_table[] = {
+	{ "LQOPHACHGINPKT",	0x01, 0x01 },
+	{ "LQOBUSFREE",		0x02, 0x02 },
+	{ "LQOBADQAS",		0x04, 0x04 },
+	{ "LQOSTOPI2",		0x08, 0x08 },
+	{ "LQOINITSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqostat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOSTAT1_parse_table, 5, "LQOSTAT1",
+	    0x55, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRLQOINT1_parse_table[] = {
+	{ "CLRLQOPHACHGINPKT",	0x01, 0x01 },
+	{ "CLRLQOBUSFREE",	0x02, 0x02 },
+	{ "CLRLQOBADQAS",	0x04, 0x04 },
+	{ "CLRLQOSTOPI2",	0x08, 0x08 },
+	{ "CLRLQOINITSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_clrlqoint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRLQOINT1_parse_table, 5, "CLRLQOINT1",
+	    0x55, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOMODE1_parse_table[] = {
+	{ "ENLQOPHACHGINPKT",	0x01, 0x01 },
+	{ "ENLQOBUSFREE",	0x02, 0x02 },
+	{ "ENLQOBADQAS",	0x04, 0x04 },
+	{ "ENLQOSTOPI2",	0x08, 0x08 },
+	{ "ENLQOINITSCBPERR",	0x10, 0x10 }
+};
+
+int
+ahd_lqomode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOMODE1_parse_table, 5, "LQOMODE1",
+	    0x55, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOSTAT2_parse_table[] = {
+	{ "LQOSTOP0",		0x01, 0x01 },
+	{ "LQOPHACHGOUTPKT",	0x02, 0x02 },
+	{ "LQOWAITFIFO",	0x10, 0x10 },
+	{ "LQOPKT",		0xe0, 0xe0 }
+};
+
+int
+ahd_lqostat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOSTAT2_parse_table, 4, "LQOSTAT2",
+	    0x56, regvalue, cur_col, wrap));
+}
+
+int
+ahd_os_space_cnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "OS_SPACE_CNT",
+	    0x56, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SIMODE1_parse_table[] = {
+	{ "ENREQINIT",		0x01, 0x01 },
+	{ "ENSTRB2FAST",	0x02, 0x02 },
+	{ "ENSCSIPERR",		0x04, 0x04 },
+	{ "ENBUSFREE",		0x08, 0x08 },
+	{ "ENPHASEMIS",		0x10, 0x10 },
+	{ "ENSCSIRST",		0x20, 0x20 },
+	{ "ENATNTARG",		0x40, 0x40 },
+	{ "ENSELTIMO",		0x80, 0x80 }
+};
+
+int
+ahd_simode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SIMODE1_parse_table, 8, "SIMODE1",
+	    0x57, regvalue, cur_col, wrap));
+}
+
+int
+ahd_gsfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "GSFIFO",
+	    0x58, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFFSXFRCTL_parse_table[] = {
+	{ "RSTCHN",		0x01, 0x01 },
+	{ "CLRCHN",		0x02, 0x02 },
+	{ "CLRSHCNT",		0x04, 0x04 },
+	{ "DFFBITBUCKET",	0x08, 0x08 }
+};
+
+int
+ahd_dffsxfrctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFFSXFRCTL_parse_table, 4, "DFFSXFRCTL",
+	    0x5a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LQOSCSCTL_parse_table[] = {
+	{ "LQONOCHKOVER",	0x01, 0x01 },
+	{ "LQOH2A_VERSION",	0x80, 0x80 }
+};
+
+int
+ahd_lqoscsctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LQOSCSCTL_parse_table, 2, "LQOSCSCTL",
+	    0x5a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_nextscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NEXTSCB",
+	    0x5a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CLRSEQINTSRC_parse_table[] = {
+	{ "CLRCFG4TCMD",	0x01, 0x01 },
+	{ "CLRCFG4ICMD",	0x02, 0x02 },
+	{ "CLRCFG4TSTAT",	0x04, 0x04 },
+	{ "CLRCFG4ISTAT",	0x08, 0x08 },
+	{ "CLRCFG4DATA",	0x10, 0x10 },
+	{ "CLRSAVEPTRS",	0x20, 0x20 },
+	{ "CLRCTXTDONE",	0x40, 0x40 }
+};
+
+int
+ahd_clrseqintsrc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CLRSEQINTSRC_parse_table, 7, "CLRSEQINTSRC",
+	    0x5b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQINTSRC_parse_table[] = {
+	{ "CFG4TCMD",		0x01, 0x01 },
+	{ "CFG4ICMD",		0x02, 0x02 },
+	{ "CFG4TSTAT",		0x04, 0x04 },
+	{ "CFG4ISTAT",		0x08, 0x08 },
+	{ "CFG4DATA",		0x10, 0x10 },
+	{ "SAVEPTRS",		0x20, 0x20 },
+	{ "CTXTDONE",		0x40, 0x40 }
+};
+
+int
+ahd_seqintsrc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQINTSRC_parse_table, 7, "SEQINTSRC",
+	    0x5b, regvalue, cur_col, wrap));
+}
+
+int
+ahd_currscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CURRSCB",
+	    0x5c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQIMODE_parse_table[] = {
+	{ "ENCFG4TCMD",		0x01, 0x01 },
+	{ "ENCFG4ICMD",		0x02, 0x02 },
+	{ "ENCFG4TSTAT",	0x04, 0x04 },
+	{ "ENCFG4ISTAT",	0x08, 0x08 },
+	{ "ENCFG4DATA",		0x10, 0x10 },
+	{ "ENSAVEPTRS",		0x20, 0x20 },
+	{ "ENCTXTDONE",		0x40, 0x40 }
+};
+
+int
+ahd_seqimode_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQIMODE_parse_table, 7, "SEQIMODE",
+	    0x5c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t MDFFSTAT_parse_table[] = {
+	{ "FIFOFREE",		0x01, 0x01 },
+	{ "DATAINFIFO",		0x02, 0x02 },
+	{ "DLZERO",		0x04, 0x04 },
+	{ "SHVALID",		0x08, 0x08 },
+	{ "LASTSDONE",		0x10, 0x10 },
+	{ "SHCNTMINUS1",	0x20, 0x20 },
+	{ "SHCNTNEGATIVE",	0x40, 0x40 }
+};
+
+int
+ahd_mdffstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(MDFFSTAT_parse_table, 7, "MDFFSTAT",
+	    0x5d, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CRCCONTROL_parse_table[] = {
+	{ "CRCVALCHKEN",	0x40, 0x40 }
+};
+
+int
+ahd_crccontrol_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CRCCONTROL_parse_table, 1, "CRCCONTROL",
+	    0x5d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfftag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFFTAG",
+	    0x5e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lastscb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LASTSCB",
+	    0x5e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSITEST_parse_table[] = {
+	{ "SEL_TXPLL_DEBUG",	0x04, 0x04 },
+	{ "CNTRTEST",		0x08, 0x08 }
+};
+
+int
+ahd_scsitest_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSITEST_parse_table, 2, "SCSITEST",
+	    0x5e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t IOPDNCTL_parse_table[] = {
+	{ "PDN_DIFFSENSE",	0x01, 0x01 },
+	{ "PDN_IDIST",		0x04, 0x04 },
+	{ "DISABLE_OE",		0x80, 0x80 }
+};
+
+int
+ahd_iopdnctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(IOPDNCTL_parse_table, 3, "IOPDNCTL",
+	    0x5f, regvalue, cur_col, wrap));
+}
+
+int
+ahd_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SHADDR",
+	    0x60, regvalue, cur_col, wrap));
+}
+
+int
+ahd_negoaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NEGOADDR",
+	    0x60, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dgrpcrci_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DGRPCRCI",
+	    0x60, regvalue, cur_col, wrap));
+}
+
+int
+ahd_negperiod_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NEGPERIOD",
+	    0x61, regvalue, cur_col, wrap));
+}
+
+int
+ahd_packcrci_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "PACKCRCI",
+	    0x62, regvalue, cur_col, wrap));
+}
+
+int
+ahd_negoffset_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NEGOFFSET",
+	    0x62, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t NEGPPROPTS_parse_table[] = {
+	{ "PPROPT_IUT",		0x01, 0x01 },
+	{ "PPROPT_DT",		0x02, 0x02 },
+	{ "PPROPT_QAS",		0x04, 0x04 },
+	{ "PPROPT_PACE",	0x08, 0x08 }
+};
+
+int
+ahd_negppropts_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NEGPPROPTS_parse_table, 4, "NEGPPROPTS",
+	    0x63, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t NEGCONOPTS_parse_table[] = {
+	{ "WIDEXFER",		0x01, 0x01 },
+	{ "ENAUTOATNO",		0x02, 0x02 },
+	{ "ENAUTOATNI",		0x04, 0x04 },
+	{ "ENSLOWCRC",		0x08, 0x08 },
+	{ "RTI_OVRDTRN",	0x10, 0x10 },
+	{ "RTI_WRTDIS",		0x20, 0x20 },
+	{ "ENSNAPSHOT",		0x40, 0x40 }
+};
+
+int
+ahd_negconopts_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NEGCONOPTS_parse_table, 7, "NEGCONOPTS",
+	    0x64, regvalue, cur_col, wrap));
+}
+
+int
+ahd_annexcol_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ANNEXCOL",
+	    0x65, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSCHKN_parse_table[] = {
+	{ "LSTSGCLRDIS",	0x01, 0x01 },
+	{ "SHVALIDSTDIS",	0x02, 0x02 },
+	{ "DFFACTCLR",		0x04, 0x04 },
+	{ "SDONEMSKDIS",	0x08, 0x08 },
+	{ "WIDERESEN",		0x10, 0x10 },
+	{ "CURRFIFODEF",	0x20, 0x20 },
+	{ "STSELSKIDDIS",	0x40, 0x40 }
+};
+
+int
+ahd_scschkn_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSCHKN_parse_table, 7, "SCSCHKN",
+	    0x66, regvalue, cur_col, wrap));
+}
+
+int
+ahd_annexdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ANNEXDAT",
+	    0x66, regvalue, cur_col, wrap));
+}
+
+int
+ahd_iownid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "IOWNID",
+	    0x67, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PLL960CTL0_parse_table[] = {
+	{ "PLL_ENFBM",		0x01, 0x01 },
+	{ "PLL_DLPF",		0x02, 0x02 },
+	{ "PLL_ENLPF",		0x04, 0x04 },
+	{ "PLL_ENLUD",		0x08, 0x08 },
+	{ "PLL_NS",		0x30, 0x30 },
+	{ "PLL_PWDN",		0x40, 0x40 },
+	{ "PLL_VCOSEL",		0x80, 0x80 }
+};
+
+int
+ahd_pll960ctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PLL960CTL0_parse_table, 7, "PLL960CTL0",
+	    0x68, regvalue, cur_col, wrap));
+}
+
+int
+ahd_shcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SHCNT",
+	    0x68, regvalue, cur_col, wrap));
+}
+
+int
+ahd_townid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "TOWNID",
+	    0x69, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PLL960CTL1_parse_table[] = {
+	{ "PLL_RST",		0x01, 0x01 },
+	{ "PLL_CNTCLR",		0x40, 0x40 },
+	{ "PLL_CNTEN",		0x80, 0x80 }
+};
+
+int
+ahd_pll960ctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PLL960CTL1_parse_table, 3, "PLL960CTL1",
+	    0x69, regvalue, cur_col, wrap));
+}
+
+int
+ahd_pll960cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "PLL960CNT0",
+	    0x6a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_xsig_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "XSIG",
+	    0x6a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_seloid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SELOID",
+	    0x6b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PLL400CTL0_parse_table[] = {
+	{ "PLL_ENFBM",		0x01, 0x01 },
+	{ "PLL_DLPF",		0x02, 0x02 },
+	{ "PLL_ENLPF",		0x04, 0x04 },
+	{ "PLL_ENLUD",		0x08, 0x08 },
+	{ "PLL_NS",		0x30, 0x30 },
+	{ "PLL_PWDN",		0x40, 0x40 },
+	{ "PLL_VCOSEL",		0x80, 0x80 }
+};
+
+int
+ahd_pll400ctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PLL400CTL0_parse_table, 7, "PLL400CTL0",
+	    0x6c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_fairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FAIRNESS",
+	    0x6c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PLL400CTL1_parse_table[] = {
+	{ "PLL_RST",		0x01, 0x01 },
+	{ "PLL_CNTCLR",		0x40, 0x40 },
+	{ "PLL_CNTEN",		0x80, 0x80 }
+};
+
+int
+ahd_pll400ctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PLL400CTL1_parse_table, 3, "PLL400CTL1",
+	    0x6d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_pll400cnt0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "PLL400CNT0",
+	    0x6e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_unfairness_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "UNFAIRNESS",
+	    0x6e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_haddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HADDR",
+	    0x70, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PLLDELAY_parse_table[] = {
+	{ "SPLIT_DROP_REQ",	0x80, 0x80 }
+};
+
+int
+ahd_plldelay_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PLLDELAY_parse_table, 1, "PLLDELAY",
+	    0x70, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hodmaadr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HODMAADR",
+	    0x70, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hodmacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HODMACNT",
+	    0x78, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HCNT",
+	    0x78, regvalue, cur_col, wrap));
+}
+
+int
+ahd_hodmaen_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "HODMAEN",
+	    0x7a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sghaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SGHADDR",
+	    0x7c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scbhaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCBHADDR",
+	    0x7c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sghcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SGHCNT",
+	    0x84, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scbhcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCBHCNT",
+	    0x84, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFF_THRSH_parse_table[] = {
+	{ "WR_DFTHRSH_MIN",	0x00, 0x70 },
+	{ "RD_DFTHRSH_MIN",	0x00, 0x07 },
+	{ "RD_DFTHRSH_25",	0x01, 0x07 },
+	{ "RD_DFTHRSH_50",	0x02, 0x07 },
+	{ "RD_DFTHRSH_63",	0x03, 0x07 },
+	{ "RD_DFTHRSH_75",	0x04, 0x07 },
+	{ "RD_DFTHRSH_85",	0x05, 0x07 },
+	{ "RD_DFTHRSH_90",	0x06, 0x07 },
+	{ "RD_DFTHRSH_MAX",	0x07, 0x07 },
+	{ "WR_DFTHRSH_25",	0x10, 0x70 },
+	{ "WR_DFTHRSH_50",	0x20, 0x70 },
+	{ "WR_DFTHRSH_63",	0x30, 0x70 },
+	{ "WR_DFTHRSH_75",	0x40, 0x70 },
+	{ "WR_DFTHRSH_85",	0x50, 0x70 },
+	{ "WR_DFTHRSH_90",	0x60, 0x70 },
+	{ "WR_DFTHRSH_MAX",	0x70, 0x70 },
+	{ "RD_DFTHRSH",		0x07, 0x07 },
+	{ "WR_DFTHRSH",		0x70, 0x70 }
+};
+
+int
+ahd_dff_thrsh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFF_THRSH_parse_table, 18, "DFF_THRSH",
+	    0x88, regvalue, cur_col, wrap));
+}
+
+int
+ahd_romaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ROMADDR",
+	    0x8a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t ROMCNTRL_parse_table[] = {
+	{ "RDY",		0x01, 0x01 },
+	{ "REPEAT",		0x02, 0x02 },
+	{ "ROMSPD",		0x18, 0x18 },
+	{ "ROMOP",		0xe0, 0xe0 }
+};
+
+int
+ahd_romcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(ROMCNTRL_parse_table, 4, "ROMCNTRL",
+	    0x8d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_romdata_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ROMDATA",
+	    0x8e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCRXMSG0_parse_table[] = {
+	{ "CFNUM",		0x07, 0x07 },
+	{ "CDNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_cmcrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCRXMSG0_parse_table, 2, "CMCRXMSG0",
+	    0x90, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t ROENABLE_parse_table[] = {
+	{ "DCH0ROEN",		0x01, 0x01 },
+	{ "DCH1ROEN",		0x02, 0x02 },
+	{ "SGROEN",		0x04, 0x04 },
+	{ "CMCROEN",		0x08, 0x08 },
+	{ "OVLYROEN",		0x10, 0x10 },
+	{ "MSIROEN",		0x20, 0x20 }
+};
+
+int
+ahd_roenable_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(ROENABLE_parse_table, 6, "ROENABLE",
+	    0x90, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYRXMSG0_parse_table[] = {
+	{ "CFNUM",		0x07, 0x07 },
+	{ "CDNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_ovlyrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG0_parse_table, 2, "OVLYRXMSG0",
+	    0x90, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHRXMSG0_parse_table[] = {
+	{ "CFNUM",		0x07, 0x07 },
+	{ "CDNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_dchrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHRXMSG0_parse_table, 2, "DCHRXMSG0",
+	    0x90, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYRXMSG1_parse_table[] = {
+	{ "CBNUM",		0xff, 0xff }
+};
+
+int
+ahd_ovlyrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG1_parse_table, 1, "OVLYRXMSG1",
+	    0x91, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t NSENABLE_parse_table[] = {
+	{ "DCH0NSEN",		0x01, 0x01 },
+	{ "DCH1NSEN",		0x02, 0x02 },
+	{ "SGNSEN",		0x04, 0x04 },
+	{ "CMCNSEN",		0x08, 0x08 },
+	{ "OVLYNSEN",		0x10, 0x10 },
+	{ "MSINSEN",		0x20, 0x20 }
+};
+
+int
+ahd_nsenable_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NSENABLE_parse_table, 6, "NSENABLE",
+	    0x91, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHRXMSG1_parse_table[] = {
+	{ "CBNUM",		0xff, 0xff }
+};
+
+int
+ahd_dchrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHRXMSG1_parse_table, 1, "DCHRXMSG1",
+	    0x91, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCRXMSG1_parse_table[] = {
+	{ "CBNUM",		0xff, 0xff }
+};
+
+int
+ahd_cmcrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCRXMSG1_parse_table, 1, "CMCRXMSG1",
+	    0x91, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHRXMSG2_parse_table[] = {
+	{ "MINDEX",		0xff, 0xff }
+};
+
+int
+ahd_dchrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHRXMSG2_parse_table, 1, "DCHRXMSG2",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYRXMSG2_parse_table[] = {
+	{ "MINDEX",		0xff, 0xff }
+};
+
+int
+ahd_ovlyrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG2_parse_table, 1, "OVLYRXMSG2",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCRXMSG2_parse_table[] = {
+	{ "MINDEX",		0xff, 0xff }
+};
+
+int
+ahd_cmcrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCRXMSG2_parse_table, 1, "CMCRXMSG2",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ost_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "OST",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHRXMSG3_parse_table[] = {
+	{ "MCLASS",		0x0f, 0x0f }
+};
+
+int
+ahd_dchrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHRXMSG3_parse_table, 1, "DCHRXMSG3",
+	    0x93, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCRXMSG3_parse_table[] = {
+	{ "MCLASS",		0x0f, 0x0f }
+};
+
+int
+ahd_cmcrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCRXMSG3_parse_table, 1, "CMCRXMSG3",
+	    0x93, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t PCIXCTL_parse_table[] = {
+	{ "CMPABCDIS",		0x01, 0x01 },
+	{ "TSCSERREN",		0x02, 0x02 },
+	{ "SRSPDPEEN",		0x04, 0x04 },
+	{ "SPLTSTADIS",		0x08, 0x08 },
+	{ "SPLTSMADIS",		0x10, 0x10 },
+	{ "UNEXPSCIEN",		0x20, 0x20 },
+	{ "SERRPULSE",		0x80, 0x80 }
+};
+
+int
+ahd_pcixctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(PCIXCTL_parse_table, 7, "PCIXCTL",
+	    0x93, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYRXMSG3_parse_table[] = {
+	{ "MCLASS",		0x0f, 0x0f }
+};
+
+int
+ahd_ovlyrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYRXMSG3_parse_table, 1, "OVLYRXMSG3",
+	    0x93, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ovlyseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "OVLYSEQBCNT",
+	    0x94, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmcseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMCSEQBCNT",
+	    0x94, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dchseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DCHSEQBCNT",
+	    0x94, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCSPLTSTAT0_parse_table[] = {
+	{ "RXSPLTRSP",		0x01, 0x01 },
+	{ "RXSCEMSG",		0x02, 0x02 },
+	{ "RXOVRUN",		0x04, 0x04 },
+	{ "CNTNOTCMPLT",	0x08, 0x08 },
+	{ "SCDATBUCKET",	0x10, 0x10 },
+	{ "SCADERR",		0x20, 0x20 },
+	{ "SCBCERR",		0x40, 0x40 },
+	{ "STAETERM",		0x80, 0x80 }
+};
+
+int
+ahd_cmcspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCSPLTSTAT0_parse_table, 8, "CMCSPLTSTAT0",
+	    0x96, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYSPLTSTAT0_parse_table[] = {
+	{ "RXSPLTRSP",		0x01, 0x01 },
+	{ "RXSCEMSG",		0x02, 0x02 },
+	{ "RXOVRUN",		0x04, 0x04 },
+	{ "CNTNOTCMPLT",	0x08, 0x08 },
+	{ "SCDATBUCKET",	0x10, 0x10 },
+	{ "SCADERR",		0x20, 0x20 },
+	{ "SCBCERR",		0x40, 0x40 },
+	{ "STAETERM",		0x80, 0x80 }
+};
+
+int
+ahd_ovlyspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYSPLTSTAT0_parse_table, 8, "OVLYSPLTSTAT0",
+	    0x96, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHSPLTSTAT0_parse_table[] = {
+	{ "RXSPLTRSP",		0x01, 0x01 },
+	{ "RXSCEMSG",		0x02, 0x02 },
+	{ "RXOVRUN",		0x04, 0x04 },
+	{ "CNTNOTCMPLT",	0x08, 0x08 },
+	{ "SCDATBUCKET",	0x10, 0x10 },
+	{ "SCADERR",		0x20, 0x20 },
+	{ "SCBCERR",		0x40, 0x40 },
+	{ "STAETERM",		0x80, 0x80 }
+};
+
+int
+ahd_dchspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHSPLTSTAT0_parse_table, 8, "DCHSPLTSTAT0",
+	    0x96, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DCHSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_dchspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DCHSPLTSTAT1_parse_table, 1, "DCHSPLTSTAT1",
+	    0x97, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_cmcspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCSPLTSTAT1_parse_table, 1, "CMCSPLTSTAT1",
+	    0x97, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_ovlyspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYSPLTSTAT1_parse_table, 1, "OVLYSPLTSTAT1",
+	    0x97, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGRXMSG0_parse_table[] = {
+	{ "CFNUM",		0x07, 0x07 },
+	{ "CDNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_sgrxmsg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGRXMSG0_parse_table, 2, "SGRXMSG0",
+	    0x98, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTADR0_parse_table[] = {
+	{ "LOWER_ADDR",		0x7f, 0x7f }
+};
+
+int
+ahd_slvspltoutadr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTADR0_parse_table, 1, "SLVSPLTOUTADR0",
+	    0x98, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGRXMSG1_parse_table[] = {
+	{ "CBNUM",		0xff, 0xff }
+};
+
+int
+ahd_sgrxmsg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGRXMSG1_parse_table, 1, "SGRXMSG1",
+	    0x99, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTADR1_parse_table[] = {
+	{ "REQ_FNUM",		0x07, 0x07 },
+	{ "REQ_DNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_slvspltoutadr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTADR1_parse_table, 2, "SLVSPLTOUTADR1",
+	    0x99, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGRXMSG2_parse_table[] = {
+	{ "MINDEX",		0xff, 0xff }
+};
+
+int
+ahd_sgrxmsg2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGRXMSG2_parse_table, 1, "SGRXMSG2",
+	    0x9a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTADR2_parse_table[] = {
+	{ "REQ_BNUM",		0xff, 0xff }
+};
+
+int
+ahd_slvspltoutadr2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTADR2_parse_table, 1, "SLVSPLTOUTADR2",
+	    0x9a, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGRXMSG3_parse_table[] = {
+	{ "MCLASS",		0x0f, 0x0f }
+};
+
+int
+ahd_sgrxmsg3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGRXMSG3_parse_table, 1, "SGRXMSG3",
+	    0x9b, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTADR3_parse_table[] = {
+	{ "RLXORD",		0x10, 0x10 },
+	{ "TAG_NUM",		0x1f, 0x1f }
+};
+
+int
+ahd_slvspltoutadr3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTADR3_parse_table, 2, "SLVSPLTOUTADR3",
+	    0x9b, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sgseqbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SGSEQBCNT",
+	    0x9c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTATTR0_parse_table[] = {
+	{ "LOWER_BCNT",		0xff, 0xff }
+};
+
+int
+ahd_slvspltoutattr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTATTR0_parse_table, 1, "SLVSPLTOUTATTR0",
+	    0x9c, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTATTR1_parse_table[] = {
+	{ "CMPLT_FNUM",		0x07, 0x07 },
+	{ "CMPLT_DNUM",		0xf8, 0xf8 }
+};
+
+int
+ahd_slvspltoutattr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTATTR1_parse_table, 2, "SLVSPLTOUTATTR1",
+	    0x9d, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SLVSPLTOUTATTR2_parse_table[] = {
+	{ "CMPLT_BNUM",		0xff, 0xff }
+};
+
+int
+ahd_slvspltoutattr2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SLVSPLTOUTATTR2_parse_table, 1, "SLVSPLTOUTATTR2",
+	    0x9e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGSPLTSTAT0_parse_table[] = {
+	{ "RXSPLTRSP",		0x01, 0x01 },
+	{ "RXSCEMSG",		0x02, 0x02 },
+	{ "RXOVRUN",		0x04, 0x04 },
+	{ "CNTNOTCMPLT",	0x08, 0x08 },
+	{ "SCDATBUCKET",	0x10, 0x10 },
+	{ "SCADERR",		0x20, 0x20 },
+	{ "SCBCERR",		0x40, 0x40 },
+	{ "STAETERM",		0x80, 0x80 }
+};
+
+int
+ahd_sgspltstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGSPLTSTAT0_parse_table, 8, "SGSPLTSTAT0",
+	    0x9e, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SFUNCT_parse_table[] = {
+	{ "TEST_NUM",		0x0f, 0x0f },
+	{ "TEST_GROUP",		0xf0, 0xf0 }
+};
+
+int
+ahd_sfunct_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SFUNCT_parse_table, 2, "SFUNCT",
+	    0x9f, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGSPLTSTAT1_parse_table[] = {
+	{ "RXDATABUCKET",	0x01, 0x01 }
+};
+
+int
+ahd_sgspltstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGSPLTSTAT1_parse_table, 1, "SGSPLTSTAT1",
+	    0x9f, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DF0PCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "TWATERR",		0x02, 0x02 },
+	{ "RDPERR",		0x04, 0x04 },
+	{ "SCAAPERR",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_df0pcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DF0PCISTAT_parse_table, 8, "DF0PCISTAT",
+	    0xa0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_reg0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "REG0",
+	    0xa0, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DF1PCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "TWATERR",		0x02, 0x02 },
+	{ "RDPERR",		0x04, 0x04 },
+	{ "SCAAPERR",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_df1pcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DF1PCISTAT_parse_table, 8, "DF1PCISTAT",
+	    0xa1, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SGPCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "RDPERR",		0x04, 0x04 },
+	{ "SCAAPERR",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_sgpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SGPCISTAT_parse_table, 7, "SGPCISTAT",
+	    0xa2, regvalue, cur_col, wrap));
+}
+
+int
+ahd_reg1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "REG1",
+	    0xa2, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMCPCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "TWATERR",		0x02, 0x02 },
+	{ "RDPERR",		0x04, 0x04 },
+	{ "SCAAPERR",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_cmcpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMCPCISTAT_parse_table, 8, "CMCPCISTAT",
+	    0xa3, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t OVLYPCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "RDPERR",		0x04, 0x04 },
+	{ "SCAAPERR",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_ovlypcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(OVLYPCISTAT_parse_table, 7, "OVLYPCISTAT",
+	    0xa4, regvalue, cur_col, wrap));
+}
+
+int
+ahd_reg_isr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "REG_ISR",
+	    0xa4, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SG_STATE_parse_table[] = {
+	{ "SEGS_AVAIL",		0x01, 0x01 },
+	{ "LOADING_NEEDED",	0x02, 0x02 },
+	{ "FETCH_INPROG",	0x04, 0x04 }
+};
+
+int
+ahd_sg_state_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SG_STATE_parse_table, 3, "SG_STATE",
+	    0xa6, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t MSIPCISTAT_parse_table[] = {
+	{ "DPR",		0x01, 0x01 },
+	{ "TWATERR",		0x02, 0x02 },
+	{ "CLRPENDMSI",		0x08, 0x08 },
+	{ "RTA",		0x10, 0x10 },
+	{ "RMA",		0x20, 0x20 },
+	{ "SSE",		0x40, 0x40 }
+};
+
+int
+ahd_msipcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(MSIPCISTAT_parse_table, 6, "MSIPCISTAT",
+	    0xa6, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t TARGPCISTAT_parse_table[] = {
+	{ "TWATERR",		0x02, 0x02 },
+	{ "STA",		0x08, 0x08 },
+	{ "SSE",		0x40, 0x40 },
+	{ "DPE",		0x80, 0x80 }
+};
+
+int
+ahd_targpcistat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(TARGPCISTAT_parse_table, 4, "TARGPCISTAT",
+	    0xa7, regvalue, cur_col, wrap));
+}
+
+int
+ahd_data_count_odd_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DATA_COUNT_ODD",
+	    0xa7, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCBPTR",
+	    0xa8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccscbacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSCBACNT",
+	    0xab, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCBAUTOPTR_parse_table[] = {
+	{ "SCBPTR_OFF",		0x07, 0x07 },
+	{ "SCBPTR_ADDR",	0x38, 0x38 },
+	{ "AUSCBPTR_EN",	0x80, 0x80 }
+};
+
+int
+ahd_scbautoptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCBAUTOPTR_parse_table, 3, "SCBAUTOPTR",
+	    0xab, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSGADDR",
+	    0xac, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSCBADDR",
+	    0xac, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccscbadr_bk_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSCBADR_BK",
+	    0xac, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CMC_RAMBIST_parse_table[] = {
+	{ "CMC_BUFFER_BIST_EN",	0x01, 0x01 },
+	{ "CMC_BUFFER_BIST_FAIL",0x02, 0x02 },
+	{ "SG_BIST_EN",		0x10, 0x10 },
+	{ "SG_BIST_FAIL",	0x20, 0x20 },
+	{ "SCBRAMBIST_FAIL",	0x40, 0x40 },
+	{ "SG_ELEMENT_SIZE",	0x80, 0x80 }
+};
+
+int
+ahd_cmc_rambist_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CMC_RAMBIST_parse_table, 6, "CMC_RAMBIST",
+	    0xad, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CCSGCTL_parse_table[] = {
+	{ "CCSGRESET",		0x01, 0x01 },
+	{ "SG_FETCH_REQ",	0x02, 0x02 },
+	{ "CCSGENACK",		0x08, 0x08 },
+	{ "SG_CACHE_AVAIL",	0x10, 0x10 },
+	{ "CCSGDONE",		0x80, 0x80 },
+	{ "CCSGEN",		0x0c, 0x0c }
+};
+
+int
+ahd_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CCSGCTL_parse_table, 6, "CCSGCTL",
+	    0xad, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t CCSCBCTL_parse_table[] = {
+	{ "CCSCBRESET",		0x01, 0x01 },
+	{ "CCSCBDIR",		0x04, 0x04 },
+	{ "CCSCBEN",		0x08, 0x08 },
+	{ "CCARREN",		0x10, 0x10 },
+	{ "ARRDONE",		0x40, 0x40 },
+	{ "CCSCBDONE",		0x80, 0x80 }
+};
+
+int
+ahd_ccscbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(CCSCBCTL_parse_table, 6, "CCSCBCTL",
+	    0xad, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccsgram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSGRAM",
+	    0xb0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_flexadr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FLEXADR",
+	    0xb0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ccscbram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CCSCBRAM",
+	    0xb0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_flexcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FLEXCNT",
+	    0xb3, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t FLEXDMASTAT_parse_table[] = {
+	{ "FLEXDMADONE",	0x01, 0x01 },
+	{ "FLEXDMAERR",		0x02, 0x02 }
+};
+
+int
+ahd_flexdmastat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(FLEXDMASTAT_parse_table, 2, "FLEXDMASTAT",
+	    0xb5, regvalue, cur_col, wrap));
+}
+
+int
+ahd_flexdata_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FLEXDATA",
+	    0xb6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_brddat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "BRDDAT",
+	    0xb8, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t BRDCTL_parse_table[] = {
+	{ "BRDSTB",		0x01, 0x01 },
+	{ "BRDRW",		0x02, 0x02 },
+	{ "BRDEN",		0x04, 0x04 },
+	{ "BRDADDR",		0x38, 0x38 },
+	{ "FLXARBREQ",		0x40, 0x40 },
+	{ "FLXARBACK",		0x80, 0x80 }
+};
+
+int
+ahd_brdctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(BRDCTL_parse_table, 6, "BRDCTL",
+	    0xb9, regvalue, cur_col, wrap));
+}
+
+int
+ahd_seeadr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SEEADR",
+	    0xba, regvalue, cur_col, wrap));
+}
+
+int
+ahd_seedat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SEEDAT",
+	    0xbc, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEECTL_parse_table[] = {
+	{ "SEEOP_ERAL",		0x40, 0x70 },
+	{ "SEEOP_WRITE",	0x50, 0x70 },
+	{ "SEEOP_READ",		0x60, 0x70 },
+	{ "SEEOP_ERASE",	0x70, 0x70 },
+	{ "SEESTART",		0x01, 0x01 },
+	{ "SEERST",		0x02, 0x02 },
+	{ "SEEOPCODE",		0x70, 0x70 },
+	{ "SEEOP_EWEN",		0x40, 0x40 },
+	{ "SEEOP_WALL",		0x40, 0x40 },
+	{ "SEEOP_EWDS",		0x40, 0x40 }
+};
+
+int
+ahd_seectl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEECTL_parse_table, 10, "SEECTL",
+	    0xbe, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEESTAT_parse_table[] = {
+	{ "SEESTART",		0x01, 0x01 },
+	{ "SEEBUSY",		0x02, 0x02 },
+	{ "SEEARBACK",		0x04, 0x04 },
+	{ "LDALTID_L",		0x08, 0x08 },
+	{ "SEEOPCODE",		0x70, 0x70 },
+	{ "INIT_DONE",		0x80, 0x80 }
+};
+
+int
+ahd_seestat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEESTAT_parse_table, 6, "SEESTAT",
+	    0xbe, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCBCNT",
+	    0xbf, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfwaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFWADDR",
+	    0xc0, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSPFLTRCTL_parse_table[] = {
+	{ "DSPFCNTSEL",		0x0f, 0x0f },
+	{ "EDGESENSE",		0x10, 0x10 },
+	{ "FLTRDISABLE",	0x20, 0x20 }
+};
+
+int
+ahd_dspfltrctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSPFLTRCTL_parse_table, 3, "DSPFLTRCTL",
+	    0xc0, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSPDATACTL_parse_table[] = {
+	{ "XMITOFFSTDIS",	0x02, 0x02 },
+	{ "RCVROFFSTDIS",	0x04, 0x04 },
+	{ "DESQDIS",		0x10, 0x10 },
+	{ "BYPASSENAB",		0x80, 0x80 }
+};
+
+int
+ahd_dspdatactl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSPDATACTL_parse_table, 4, "DSPDATACTL",
+	    0xc1, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfraddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFRADDR",
+	    0xc2, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSPREQCTL_parse_table[] = {
+	{ "MANREQDLY",		0x3f, 0x3f },
+	{ "MANREQCTL",		0xc0, 0xc0 }
+};
+
+int
+ahd_dspreqctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSPREQCTL_parse_table, 2, "DSPREQCTL",
+	    0xc2, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSPACKCTL_parse_table[] = {
+	{ "MANACKDLY",		0x3f, 0x3f },
+	{ "MANACKCTL",		0xc0, 0xc0 }
+};
+
+int
+ahd_dspackctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSPACKCTL_parse_table, 2, "DSPACKCTL",
+	    0xc3, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFDAT",
+	    0xc4, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DSPSELECT_parse_table[] = {
+	{ "DSPSEL",		0x1f, 0x1f },
+	{ "AUTOINCEN",		0x80, 0x80 }
+};
+
+int
+ahd_dspselect_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DSPSELECT_parse_table, 2, "DSPSELECT",
+	    0xc4, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t WRTBIASCTL_parse_table[] = {
+	{ "XMITMANVAL",		0x3f, 0x3f },
+	{ "AUTOXBCDIS",		0x80, 0x80 }
+};
+
+int
+ahd_wrtbiasctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(WRTBIASCTL_parse_table, 2, "WRTBIASCTL",
+	    0xc5, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t RCVRBIOSCTL_parse_table[] = {
+	{ "RCVRMANVAL",		0x3f, 0x3f },
+	{ "AUTORBCDIS",		0x80, 0x80 }
+};
+
+int
+ahd_rcvrbiosctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(RCVRBIOSCTL_parse_table, 2, "RCVRBIOSCTL",
+	    0xc6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_wrtbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "WRTBIASCALC",
+	    0xc7, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfptrs_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFPTRS",
+	    0xc8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_rcvrbiascalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "RCVRBIASCALC",
+	    0xc8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfbkptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFBKPTR",
+	    0xc9, regvalue, cur_col, wrap));
+}
+
+int
+ahd_skewcalc_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SKEWCALC",
+	    0xc9, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DFDBCTL_parse_table[] = {
+	{ "DFF_RAMBIST_EN",	0x01, 0x01 },
+	{ "DFF_RAMBIST_DONE",	0x02, 0x02 },
+	{ "DFF_RAMBIST_FAIL",	0x04, 0x04 },
+	{ "DFF_DIR_ERR",	0x08, 0x08 },
+	{ "DFF_CIO_RD_RDY",	0x10, 0x10 },
+	{ "DFF_CIO_WR_RDY",	0x20, 0x20 }
+};
+
+int
+ahd_dfdbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DFDBCTL_parse_table, 6, "DFDBCTL",
+	    0xcb, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfscnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFSCNT",
+	    0xcc, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dfbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DFBCNT",
+	    0xce, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ovlyaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "OVLYADDR",
+	    0xd4, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQCTL0_parse_table[] = {
+	{ "LOADRAM",		0x01, 0x01 },
+	{ "SEQRESET",		0x02, 0x02 },
+	{ "STEP",		0x04, 0x04 },
+	{ "BRKADRINTEN",	0x08, 0x08 },
+	{ "FASTMODE",		0x10, 0x10 },
+	{ "FAILDIS",		0x20, 0x20 },
+	{ "PAUSEDIS",		0x40, 0x40 },
+	{ "PERRORDIS",		0x80, 0x80 }
+};
+
+int
+ahd_seqctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQCTL0_parse_table, 8, "SEQCTL0",
+	    0xd6, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQCTL1_parse_table[] = {
+	{ "RAMBIST_EN",		0x01, 0x01 },
+	{ "RAMBIST_FAIL",	0x02, 0x02 },
+	{ "RAMBIST_DONE",	0x04, 0x04 },
+	{ "OVRLAY_DATA_CHK",	0x08, 0x08 }
+};
+
+int
+ahd_seqctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQCTL1_parse_table, 4, "SEQCTL1",
+	    0xd7, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t FLAGS_parse_table[] = {
+	{ "CARRY",		0x01, 0x01 },
+	{ "ZERO",		0x02, 0x02 }
+};
+
+int
+ahd_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(FLAGS_parse_table, 2, "FLAGS",
+	    0xd8, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQINTCTL_parse_table[] = {
+	{ "IRET",		0x01, 0x01 },
+	{ "INTMASK1",		0x02, 0x02 },
+	{ "INTMASK2",		0x04, 0x04 },
+	{ "SCS_SEQ_INT1M0",	0x08, 0x08 },
+	{ "SCS_SEQ_INT1M1",	0x10, 0x10 },
+	{ "INT1_CONTEXT",	0x20, 0x20 },
+	{ "INTVEC1DSL",		0x80, 0x80 }
+};
+
+int
+ahd_seqintctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQINTCTL_parse_table, 7, "SEQINTCTL",
+	    0xd9, regvalue, cur_col, wrap));
+}
+
+int
+ahd_seqram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SEQRAM",
+	    0xda, regvalue, cur_col, wrap));
+}
+
+int
+ahd_prgmcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "PRGMCNT",
+	    0xde, regvalue, cur_col, wrap));
+}
+
+int
+ahd_accum_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ACCUM",
+	    0xe0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SINDEX",
+	    0xe2, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DINDEX",
+	    0xe4, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t BRKADDR1_parse_table[] = {
+	{ "BRKDIS",		0x80, 0x80 }
+};
+
+int
+ahd_brkaddr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(BRKADDR1_parse_table, 1, "BRKADDR1",
+	    0xe6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_brkaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "BRKADDR0",
+	    0xe6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_allones_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ALLONES",
+	    0xe8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_allzeros_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ALLZEROS",
+	    0xea, regvalue, cur_col, wrap));
+}
+
+int
+ahd_none_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NONE",
+	    0xea, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SINDIR",
+	    0xec, regvalue, cur_col, wrap));
+}
+
+int
+ahd_dindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "DINDIR",
+	    0xed, regvalue, cur_col, wrap));
+}
+
+int
+ahd_function1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "FUNCTION1",
+	    0xf0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "STACK",
+	    0xf2, regvalue, cur_col, wrap));
+}
+
+int
+ahd_curaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CURADDR",
+	    0xf4, regvalue, cur_col, wrap));
+}
+
+int
+ahd_intvec1_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INTVEC1_ADDR",
+	    0xf4, regvalue, cur_col, wrap));
+}
+
+int
+ahd_intvec2_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INTVEC2_ADDR",
+	    0xf6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_lastaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LASTADDR",
+	    0xf6, regvalue, cur_col, wrap));
+}
+
+int
+ahd_longjmp_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LONGJMP_ADDR",
+	    0xf8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_accum_save_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ACCUM_SAVE",
+	    0xfa, regvalue, cur_col, wrap));
+}
+
+int
+ahd_waiting_scb_tails_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "WAITING_SCB_TAILS",
+	    0x100, regvalue, cur_col, wrap));
+}
+
+int
+ahd_ahd_pci_config_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "AHD_PCI_CONFIG_BASE",
+	    0x100, regvalue, cur_col, wrap));
+}
+
+int
+ahd_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SRAM_BASE",
+	    0x100, regvalue, cur_col, wrap));
+}
+
+int
+ahd_waiting_tid_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "WAITING_TID_HEAD",
+	    0x120, regvalue, cur_col, wrap));
+}
+
+int
+ahd_waiting_tid_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "WAITING_TID_TAIL",
+	    0x122, regvalue, cur_col, wrap));
+}
+
+int
+ahd_next_queued_scb_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "NEXT_QUEUED_SCB_ADDR",
+	    0x124, regvalue, cur_col, wrap));
+}
+
+int
+ahd_complete_scb_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "COMPLETE_SCB_HEAD",
+	    0x128, regvalue, cur_col, wrap));
+}
+
+int
+ahd_complete_scb_dmainprog_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "COMPLETE_SCB_DMAINPROG_HEAD",
+	    0x12a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_complete_dma_scb_head_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "COMPLETE_DMA_SCB_HEAD",
+	    0x12c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_qfreeze_count_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "QFREEZE_COUNT",
+	    0x12e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_saved_mode_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SAVED_MODE",
+	    0x130, regvalue, cur_col, wrap));
+}
+
+int
+ahd_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "MSG_OUT",
+	    0x131, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t DMAPARAMS_parse_table[] = {
+	{ "FIFORESET",		0x01, 0x01 },
+	{ "FIFOFLUSH",		0x02, 0x02 },
+	{ "DIRECTION",		0x04, 0x04 },
+	{ "HDMAEN",		0x08, 0x08 },
+	{ "HDMAENACK",		0x08, 0x08 },
+	{ "SDMAEN",		0x10, 0x10 },
+	{ "SDMAENACK",		0x10, 0x10 },
+	{ "SCSIEN",		0x20, 0x20 },
+	{ "WIDEODD",		0x40, 0x40 },
+	{ "PRELOADEN",		0x80, 0x80 }
+};
+
+int
+ahd_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(DMAPARAMS_parse_table, 10, "DMAPARAMS",
+	    0x132, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
+	{ "NO_DISCONNECT",	0x01, 0x01 },
+	{ "SPHASE_PENDING",	0x02, 0x02 },
+	{ "DPHASE_PENDING",	0x04, 0x04 },
+	{ "CMDPHASE_PENDING",	0x08, 0x08 },
+	{ "TARG_CMD_PENDING",	0x10, 0x10 },
+	{ "DPHASE",		0x20, 0x20 },
+	{ "NO_CDB_SENT",	0x40, 0x40 },
+	{ "TARGET_CMD_IS_TAGGED",0x40, 0x40 },
+	{ "NOT_IDENTIFIED",	0x80, 0x80 }
+};
+
+int
+ahd_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS",
+	    0x133, regvalue, cur_col, wrap));
+}
+
+int
+ahd_saved_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SAVED_SCSIID",
+	    0x134, regvalue, cur_col, wrap));
+}
+
+int
+ahd_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SAVED_LUN",
+	    0x135, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t LASTPHASE_parse_table[] = {
+	{ "P_DATAOUT",		0x00, 0xe0 },
+	{ "P_DATAOUT_DT",	0x20, 0xe0 },
+	{ "P_DATAIN",		0x40, 0xe0 },
+	{ "P_DATAIN_DT",	0x60, 0xe0 },
+	{ "P_COMMAND",		0x80, 0xe0 },
+	{ "P_MESGOUT",		0xa0, 0xe0 },
+	{ "P_STATUS",		0xc0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 },
+	{ "P_BUSFREE",		0x01, 0x01 },
+	{ "MSGI",		0x20, 0x20 },
+	{ "IOI",		0x40, 0x40 },
+	{ "CDI",		0x80, 0x80 },
+	{ "PHASE_MASK",		0xe0, 0xe0 }
+};
+
+int
+ahd_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(LASTPHASE_parse_table, 13, "LASTPHASE",
+	    0x136, regvalue, cur_col, wrap));
+}
+
+int
+ahd_qoutfifo_entry_valid_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "QOUTFIFO_ENTRY_VALID_TAG",
+	    0x137, regvalue, cur_col, wrap));
+}
+
+int
+ahd_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SHARED_DATA_ADDR",
+	    0x138, regvalue, cur_col, wrap));
+}
+
+int
+ahd_qoutfifo_next_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "QOUTFIFO_NEXT_ADDR",
+	    0x13c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_kernel_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "KERNEL_TQINPOS",
+	    0x140, regvalue, cur_col, wrap));
+}
+
+int
+ahd_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "TQINPOS",
+	    0x141, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t ARG_1_parse_table[] = {
+	{ "CONT_MSG_LOOP_TARG",	0x02, 0x02 },
+	{ "CONT_MSG_LOOP_READ",	0x03, 0x03 },
+	{ "CONT_MSG_LOOP_WRITE",0x04, 0x04 },
+	{ "EXIT_MSG_LOOP",	0x08, 0x08 },
+	{ "MSGOUT_PHASEMIS",	0x10, 0x10 },
+	{ "SEND_REJ",		0x20, 0x20 },
+	{ "SEND_SENSE",		0x40, 0x40 },
+	{ "SEND_MSG",		0x80, 0x80 }
+};
+
+int
+ahd_arg_1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(ARG_1_parse_table, 8, "ARG_1",
+	    0x142, regvalue, cur_col, wrap));
+}
+
+int
+ahd_arg_2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ARG_2",
+	    0x143, regvalue, cur_col, wrap));
+}
+
+int
+ahd_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LAST_MSG",
+	    0x144, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
+	{ "ALTSTIM",		0x01, 0x01 },
+	{ "ENAUTOATNP",		0x02, 0x02 },
+	{ "MANUALP",		0x0c, 0x0c },
+	{ "ENRSELI",		0x10, 0x10 },
+	{ "ENSELI",		0x20, 0x20 },
+	{ "MANUALCTL",		0x40, 0x40 }
+};
+
+int
+ahd_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCSISEQ_TEMPLATE_parse_table, 6, "SCSISEQ_TEMPLATE",
+	    0x145, regvalue, cur_col, wrap));
+}
+
+int
+ahd_initiator_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INITIATOR_TAG",
+	    0x146, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
+	{ "TARGET_MSG_PENDING",	0x02, 0x02 },
+	{ "SELECTOUT_QFROZEN",	0x04, 0x04 }
+};
+
+int
+ahd_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SEQ_FLAGS2_parse_table, 2, "SEQ_FLAGS2",
+	    0x147, regvalue, cur_col, wrap));
+}
+
+int
+ahd_allocfifo_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "ALLOCFIFO_SCBPTR",
+	    0x148, regvalue, cur_col, wrap));
+}
+
+int
+ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER",
+	    0x14a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS",
+	    0x14c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS",
+	    0x14d, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmds_pending_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMDS_PENDING",
+	    0x14e, regvalue, cur_col, wrap));
+}
+
+int
+ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT",
+	    0x150, regvalue, cur_col, wrap));
+}
+
+int
+ahd_local_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "LOCAL_HS_MAILBOX",
+	    0x151, regvalue, cur_col, wrap));
+}
+
+int
+ahd_cmdsize_table_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "CMDSIZE_TABLE",
+	    0x152, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_BASE",
+	    0x180, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_residual_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_RESIDUAL_DATACNT",
+	    0x180, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_RESIDUAL_SGPTR_parse_table[] = {
+	{ "SG_LIST_NULL",	0x01, 0x01 },
+	{ "SG_OVERRUN_RESID",	0x02, 0x02 },
+	{ "SG_ADDR_MASK",	0xf8, 0xf8 }
+};
+
+int
+ahd_scb_residual_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_RESIDUAL_SGPTR_parse_table, 3, "SCB_RESIDUAL_SGPTR",
+	    0x184, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_scsi_status_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_SCSI_STATUS",
+	    0x188, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_target_phases_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TARGET_PHASES",
+	    0x189, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_target_data_dir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TARGET_DATA_DIR",
+	    0x18a, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_target_itag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TARGET_ITAG",
+	    0x18b, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_sense_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_SENSE_BUSADDR",
+	    0x18c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TAG",
+	    0x190, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
+	{ "SCB_TAG_TYPE",	0x03, 0x03 },
+	{ "DISCONNECTED",	0x04, 0x04 },
+	{ "STATUS_RCVD",	0x08, 0x08 },
+	{ "MK_MESSAGE",		0x10, 0x10 },
+	{ "TAG_ENB",		0x20, 0x20 },
+	{ "DISCENB",		0x40, 0x40 },
+	{ "TARGET_SCB",		0x80, 0x80 }
+};
+
+int
+ahd_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_CONTROL_parse_table, 7, "SCB_CONTROL",
+	    0x192, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
+	{ "OID",		0x0f, 0x0f },
+	{ "TID",		0xf0, 0xf0 }
+};
+
+int
+ahd_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_SCSIID_parse_table, 2, "SCB_SCSIID",
+	    0x193, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_LUN_parse_table[] = {
+	{ "LID",		0xff, 0xff }
+};
+
+int
+ahd_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_LUN_parse_table, 1, "SCB_LUN",
+	    0x194, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_TASK_ATTRIBUTE_parse_table[] = {
+	{ "SCB_XFERLEN_ODD",	0x01, 0x01 }
+};
+
+int
+ahd_scb_task_attribute_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_TASK_ATTRIBUTE_parse_table, 1, "SCB_TASK_ATTRIBUTE",
+	    0x195, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = {
+	{ "SCB_CDB_LEN_PTR",	0x80, 0x80 }
+};
+
+int
+ahd_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_CDB_LEN_parse_table, 1, "SCB_CDB_LEN",
+	    0x196, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_task_management_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT",
+	    0x197, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_DATAPTR",
+	    0x198, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
+	{ "SG_HIGH_ADDR_BITS",	0x7f, 0x7f },
+	{ "SG_LAST_SEG",	0x80, 0x80 }
+};
+
+int
+ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT",
+	    0x1a0, regvalue, cur_col, wrap));
+}
+
+static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
+	{ "SG_LIST_NULL",	0x01, 0x01 },
+	{ "SG_FULL_RESID",	0x02, 0x02 },
+	{ "SG_STATUS_VALID",	0x04, 0x04 }
+};
+
+int
+ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR",
+	    0x1a4, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_BUSADDR",
+	    0x1a8, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_NEXT",
+	    0x1ac, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_NEXT2",
+	    0x1ae, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_spare_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_SPARE",
+	    0x1b0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_disconnected_lists_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_DISCONNECTED_LISTS",
+	    0x1b8, regvalue, cur_col, wrap));
+}
+
diff --git a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
new file mode 100644
index 0000000..77c471f
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
@@ -0,0 +1,1139 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#70 $
+ */
+static uint8_t seqprog[] = {
+	0xff, 0x02, 0x06, 0x78,
+	0x00, 0xea, 0x50, 0x59,
+	0x01, 0xea, 0x04, 0x30,
+	0xff, 0x04, 0x0c, 0x78,
+	0x19, 0xea, 0x50, 0x59,
+	0x19, 0xea, 0x04, 0x00,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x60, 0x3a, 0x1a, 0x68,
+	0x04, 0x47, 0x1b, 0x68,
+	0xff, 0x21, 0x1b, 0x70,
+	0x40, 0x4b, 0x92, 0x69,
+	0x00, 0xe2, 0x54, 0x59,
+	0x40, 0x4b, 0x92, 0x69,
+	0x20, 0x4b, 0x82, 0x69,
+	0xfc, 0x42, 0x24, 0x78,
+	0x10, 0x40, 0x24, 0x78,
+	0x00, 0xe2, 0xc4, 0x5d,
+	0x20, 0x4d, 0x28, 0x78,
+	0x00, 0xe2, 0xc4, 0x5d,
+	0x30, 0x3f, 0xc0, 0x09,
+	0x30, 0xe0, 0x30, 0x60,
+	0x7f, 0x4a, 0x94, 0x08,
+	0x00, 0xe2, 0x32, 0x40,
+	0xc0, 0x4a, 0x94, 0x00,
+	0x00, 0xe2, 0x3e, 0x58,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0xe2, 0x66, 0x58,
+	0x00, 0xe2, 0x06, 0x40,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x01, 0x52, 0x64, 0x78,
+	0x02, 0x58, 0x50, 0x31,
+	0xff, 0xea, 0x10, 0x0b,
+	0xff, 0x97, 0x4f, 0x78,
+	0x50, 0x4b, 0x4a, 0x68,
+	0xbf, 0x3a, 0x74, 0x08,
+	0x14, 0xea, 0x50, 0x59,
+	0x14, 0xea, 0x04, 0x00,
+	0x08, 0x92, 0x25, 0x03,
+	0xff, 0x90, 0x3f, 0x68,
+	0x00, 0xe2, 0x56, 0x5b,
+	0x00, 0xe2, 0x3e, 0x40,
+	0x00, 0xea, 0x44, 0x59,
+	0x01, 0xea, 0x00, 0x30,
+	0x80, 0xf9, 0x5e, 0x68,
+	0x00, 0xe2, 0x42, 0x59,
+	0x11, 0xea, 0x44, 0x59,
+	0x11, 0xea, 0x00, 0x00,
+	0x80, 0xf9, 0x42, 0x79,
+	0xff, 0xea, 0xd4, 0x0d,
+	0x22, 0xea, 0x44, 0x59,
+	0x22, 0xea, 0x00, 0x00,
+	0x10, 0x16, 0x70, 0x78,
+	0x01, 0x0b, 0xa2, 0x32,
+	0x10, 0x16, 0x2c, 0x00,
+	0x18, 0xad, 0x00, 0x79,
+	0x04, 0xad, 0xca, 0x68,
+	0x80, 0xad, 0x64, 0x78,
+	0x10, 0xad, 0x98, 0x78,
+	0xff, 0x88, 0x83, 0x68,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x02, 0x8c, 0x59, 0x32,
+	0x02, 0x28, 0x19, 0x33,
+	0x02, 0xa8, 0x50, 0x36,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x40, 0x3a, 0x64, 0x68,
+	0x50, 0x4b, 0x64, 0x68,
+	0x22, 0xea, 0x44, 0x59,
+	0x22, 0xea, 0x00, 0x00,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x02, 0x8c, 0x59, 0x32,
+	0x1a, 0xea, 0x50, 0x59,
+	0x1a, 0xea, 0x04, 0x00,
+	0xff, 0xea, 0xd4, 0x0d,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x00, 0xe2, 0xa6, 0x58,
+	0xff, 0xea, 0x56, 0x02,
+	0x04, 0x7c, 0x78, 0x32,
+	0x20, 0x16, 0x64, 0x78,
+	0x04, 0x38, 0x79, 0x32,
+	0x80, 0x37, 0x6f, 0x16,
+	0xff, 0x2d, 0xb5, 0x60,
+	0xff, 0x29, 0xb5, 0x60,
+	0x40, 0x51, 0xc5, 0x78,
+	0xff, 0x4f, 0xb5, 0x68,
+	0xff, 0x4d, 0xc1, 0x19,
+	0x00, 0x4e, 0xd5, 0x19,
+	0x00, 0xe2, 0xc4, 0x50,
+	0x01, 0x4c, 0xc1, 0x31,
+	0x00, 0x50, 0xd5, 0x19,
+	0x00, 0xe2, 0xc4, 0x48,
+	0x80, 0x18, 0x64, 0x78,
+	0x02, 0x4a, 0x1d, 0x30,
+	0x10, 0xea, 0x18, 0x00,
+	0x60, 0x18, 0x30, 0x00,
+	0x7f, 0x18, 0x30, 0x0c,
+	0x02, 0xea, 0x02, 0x00,
+	0xff, 0xea, 0xa0, 0x0a,
+	0x80, 0x18, 0x30, 0x04,
+	0x40, 0xad, 0x64, 0x78,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x02, 0xa8, 0x40, 0x31,
+	0xff, 0xea, 0xc0, 0x09,
+	0x01, 0x4e, 0x9d, 0x1a,
+	0x00, 0x4f, 0x9f, 0x22,
+	0x01, 0x94, 0x6d, 0x33,
+	0x01, 0xea, 0x20, 0x33,
+	0x04, 0xac, 0x49, 0x32,
+	0xff, 0xea, 0x5a, 0x03,
+	0xff, 0xea, 0x5e, 0x03,
+	0x01, 0x10, 0xd4, 0x31,
+	0x10, 0x92, 0xf5, 0x68,
+	0x3d, 0x93, 0xc5, 0x29,
+	0xfe, 0xe2, 0xc4, 0x09,
+	0x01, 0xea, 0xc6, 0x01,
+	0x02, 0xe2, 0xc8, 0x31,
+	0x02, 0xec, 0x50, 0x31,
+	0x02, 0xa0, 0xda, 0x31,
+	0xff, 0xa9, 0xf4, 0x70,
+	0x02, 0xa0, 0x58, 0x37,
+	0xff, 0x21, 0xfd, 0x70,
+	0x02, 0x22, 0x51, 0x31,
+	0x02, 0xa0, 0x5c, 0x33,
+	0x02, 0xa0, 0x44, 0x36,
+	0x02, 0xa0, 0x40, 0x32,
+	0x02, 0xa0, 0x44, 0x36,
+	0x04, 0x47, 0x05, 0x69,
+	0x40, 0x16, 0x30, 0x69,
+	0xff, 0x2d, 0x35, 0x61,
+	0xff, 0x29, 0x65, 0x70,
+	0x01, 0x37, 0xc1, 0x31,
+	0x02, 0x28, 0x55, 0x32,
+	0x01, 0xea, 0x5a, 0x01,
+	0x04, 0x3c, 0xf9, 0x30,
+	0x02, 0x28, 0x51, 0x31,
+	0x01, 0xa8, 0x60, 0x31,
+	0x00, 0xa9, 0x60, 0x01,
+	0x01, 0x14, 0xd4, 0x31,
+	0x01, 0x50, 0xa1, 0x1a,
+	0xff, 0x4e, 0x9d, 0x1a,
+	0xff, 0x4f, 0x9f, 0x22,
+	0xff, 0x8d, 0x29, 0x71,
+	0x80, 0xac, 0x28, 0x71,
+	0x20, 0x16, 0x28, 0x69,
+	0x02, 0x8c, 0x51, 0x31,
+	0x00, 0xe2, 0x12, 0x41,
+	0x01, 0xac, 0x08, 0x31,
+	0x09, 0xea, 0x5a, 0x01,
+	0x02, 0x8c, 0x51, 0x32,
+	0xff, 0xea, 0x1a, 0x07,
+	0x04, 0x24, 0xf9, 0x30,
+	0x1d, 0xea, 0x3a, 0x41,
+	0x02, 0x2c, 0x51, 0x31,
+	0x04, 0xa8, 0xf9, 0x30,
+	0x19, 0xea, 0x3a, 0x41,
+	0x06, 0xea, 0x08, 0x81,
+	0x01, 0xe2, 0x5a, 0x35,
+	0x02, 0xf2, 0xf0, 0x35,
+	0x02, 0xf2, 0xf0, 0x31,
+	0x02, 0xf8, 0xe4, 0x35,
+	0x80, 0xea, 0xb2, 0x01,
+	0x01, 0xe2, 0x00, 0x30,
+	0xff, 0xea, 0xb2, 0x0d,
+	0x80, 0xea, 0xb2, 0x01,
+	0x11, 0x00, 0x00, 0x10,
+	0xff, 0xea, 0xb2, 0x0d,
+	0x01, 0xe2, 0x04, 0x30,
+	0x01, 0xea, 0x04, 0x34,
+	0x02, 0x20, 0xbd, 0x30,
+	0x02, 0x20, 0xb9, 0x30,
+	0x02, 0x20, 0x51, 0x31,
+	0x4c, 0x93, 0xd7, 0x28,
+	0x10, 0x92, 0x63, 0x79,
+	0x01, 0x6b, 0xc0, 0x30,
+	0x02, 0x64, 0xc8, 0x00,
+	0x40, 0x3a, 0x74, 0x04,
+	0x00, 0xe2, 0x56, 0x58,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x30, 0x3f, 0xc0, 0x09,
+	0x30, 0xe0, 0x64, 0x61,
+	0x20, 0x3f, 0x7a, 0x69,
+	0x10, 0x3f, 0x64, 0x79,
+	0x02, 0xea, 0x7e, 0x00,
+	0x00, 0xea, 0x44, 0x59,
+	0x01, 0xea, 0x00, 0x30,
+	0x02, 0x48, 0x51, 0x35,
+	0x01, 0xea, 0x7e, 0x00,
+	0x11, 0xea, 0x44, 0x59,
+	0x11, 0xea, 0x00, 0x00,
+	0x02, 0x48, 0x51, 0x35,
+	0x08, 0xea, 0x98, 0x00,
+	0x08, 0x57, 0xae, 0x00,
+	0x08, 0x3c, 0x78, 0x00,
+	0xf0, 0x49, 0x68, 0x0a,
+	0x0f, 0x67, 0xc0, 0x09,
+	0x00, 0x34, 0x69, 0x02,
+	0x20, 0xea, 0x96, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x40, 0x3a, 0xae, 0x69,
+	0x02, 0x55, 0x06, 0x68,
+	0x02, 0x56, 0xae, 0x69,
+	0xff, 0x5b, 0xae, 0x61,
+	0x02, 0x20, 0x51, 0x31,
+	0x80, 0xea, 0xb2, 0x01,
+	0x44, 0xea, 0x00, 0x00,
+	0x01, 0x33, 0xc0, 0x31,
+	0x33, 0xea, 0x00, 0x00,
+	0xff, 0xea, 0xb2, 0x09,
+	0xff, 0xe0, 0xc0, 0x19,
+	0xff, 0xe0, 0xb0, 0x79,
+	0x02, 0xac, 0x51, 0x31,
+	0x00, 0xe2, 0xa6, 0x41,
+	0x02, 0x5e, 0x50, 0x31,
+	0x02, 0xa8, 0xb8, 0x30,
+	0x02, 0x5c, 0x50, 0x31,
+	0xff, 0xad, 0xc1, 0x71,
+	0x02, 0xac, 0x41, 0x31,
+	0x02, 0x22, 0x51, 0x31,
+	0x02, 0xa0, 0x5c, 0x33,
+	0x02, 0xa0, 0x44, 0x32,
+	0x00, 0xe2, 0xca, 0x41,
+	0x10, 0x92, 0xcb, 0x69,
+	0x3d, 0x93, 0xc9, 0x29,
+	0x01, 0xe4, 0xc8, 0x01,
+	0x01, 0xea, 0xca, 0x01,
+	0xff, 0xea, 0xda, 0x01,
+	0x02, 0x20, 0x51, 0x31,
+	0x02, 0xae, 0x41, 0x32,
+	0xff, 0x21, 0xd3, 0x61,
+	0xff, 0xea, 0x46, 0x02,
+	0x02, 0x5c, 0x50, 0x31,
+	0x40, 0xea, 0x96, 0x00,
+	0x02, 0x56, 0xcc, 0x6d,
+	0x01, 0x55, 0xcc, 0x6d,
+	0x10, 0x92, 0xdf, 0x79,
+	0x10, 0x40, 0xe8, 0x69,
+	0x01, 0x56, 0xe8, 0x79,
+	0xff, 0x97, 0x07, 0x78,
+	0x13, 0xea, 0x50, 0x59,
+	0x13, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x06, 0x40,
+	0xbf, 0x3a, 0x74, 0x08,
+	0x08, 0xea, 0x98, 0x00,
+	0x08, 0x57, 0xae, 0x00,
+	0x01, 0x93, 0x69, 0x32,
+	0x01, 0x94, 0x6b, 0x32,
+	0x40, 0xea, 0x66, 0x02,
+	0x08, 0x3c, 0x78, 0x00,
+	0x80, 0xea, 0x62, 0x02,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0x01, 0x36, 0xc1, 0x31,
+	0x9f, 0xe0, 0x4c, 0x7c,
+	0x80, 0xe0, 0x0c, 0x72,
+	0xa0, 0xe0, 0x44, 0x72,
+	0xc0, 0xe0, 0x3a, 0x72,
+	0xe0, 0xe0, 0x74, 0x72,
+	0x01, 0xea, 0x50, 0x59,
+	0x01, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0x13, 0x7a,
+	0x03, 0xea, 0x50, 0x59,
+	0x03, 0xea, 0x04, 0x00,
+	0xee, 0x00, 0x1a, 0x6a,
+	0x05, 0xea, 0xb4, 0x00,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x02, 0xa8, 0x90, 0x32,
+	0x00, 0xe2, 0x6a, 0x59,
+	0xef, 0x96, 0xd5, 0x19,
+	0x00, 0xe2, 0x2a, 0x52,
+	0x09, 0x80, 0xe1, 0x30,
+	0x02, 0xea, 0x36, 0x00,
+	0xa8, 0xea, 0x32, 0x00,
+	0x00, 0xe2, 0x30, 0x42,
+	0x01, 0x96, 0xd1, 0x30,
+	0x10, 0x80, 0x89, 0x31,
+	0x20, 0xea, 0x32, 0x00,
+	0xbf, 0x33, 0x67, 0x0a,
+	0x20, 0x19, 0x32, 0x6a,
+	0x02, 0x4d, 0xf8, 0x69,
+	0x40, 0x33, 0x67, 0x02,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x80, 0x33, 0xb5, 0x6a,
+	0x01, 0x44, 0x10, 0x33,
+	0x08, 0x92, 0x25, 0x03,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x10, 0xea, 0x80, 0x00,
+	0x01, 0x31, 0xc5, 0x31,
+	0x80, 0xe2, 0x60, 0x62,
+	0x10, 0x92, 0x85, 0x6a,
+	0xc0, 0x94, 0xc5, 0x01,
+	0x40, 0x92, 0x51, 0x6a,
+	0xbf, 0xe2, 0xc4, 0x09,
+	0x20, 0x92, 0x65, 0x7a,
+	0x01, 0xe2, 0x88, 0x30,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
+	0x23, 0x92, 0x89, 0x08,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x6d, 0x62,
+	0x00, 0xa8, 0x64, 0x42,
+	0xff, 0xe2, 0x64, 0x62,
+	0x00, 0xe2, 0x84, 0x42,
+	0x40, 0xea, 0x98, 0x00,
+	0x01, 0xe2, 0x88, 0x30,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0xa0, 0x36, 0x43, 0x72,
+	0x40, 0xea, 0x98, 0x00,
+	0x01, 0x31, 0x89, 0x32,
+	0x08, 0xea, 0x62, 0x02,
+	0x00, 0xe2, 0xf8, 0x41,
+	0xe0, 0xea, 0xd4, 0x5b,
+	0x80, 0xe0, 0xc0, 0x6a,
+	0x04, 0xe0, 0x66, 0x73,
+	0x02, 0xe0, 0x96, 0x73,
+	0x00, 0xea, 0x1e, 0x73,
+	0x03, 0xe0, 0xa6, 0x73,
+	0x23, 0xe0, 0x96, 0x72,
+	0x08, 0xe0, 0xbc, 0x72,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0x07, 0xea, 0x50, 0x59,
+	0x07, 0xea, 0x04, 0x00,
+	0x08, 0x42, 0xf9, 0x71,
+	0x04, 0x42, 0x93, 0x62,
+	0x01, 0x43, 0x89, 0x30,
+	0x00, 0xe2, 0x84, 0x42,
+	0x01, 0x44, 0xd4, 0x31,
+	0x00, 0xe2, 0x84, 0x42,
+	0x01, 0x00, 0x60, 0x32,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x4c, 0x34, 0xc1, 0x28,
+	0x01, 0x64, 0xc0, 0x31,
+	0x00, 0x30, 0x45, 0x59,
+	0x01, 0x30, 0x01, 0x30,
+	0x01, 0xe0, 0xba, 0x7a,
+	0xa0, 0xea, 0xca, 0x5b,
+	0x01, 0xa0, 0xba, 0x62,
+	0x01, 0x84, 0xaf, 0x7a,
+	0x01, 0x95, 0xbd, 0x6a,
+	0x05, 0xea, 0x50, 0x59,
+	0x05, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x03, 0xea, 0x50, 0x59,
+	0x03, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x07, 0xea, 0xdc, 0x5b,
+	0x01, 0x44, 0xd4, 0x31,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x3f, 0xe0, 0x6a, 0x0a,
+	0xc0, 0x34, 0xc1, 0x09,
+	0x00, 0x35, 0x51, 0x01,
+	0xff, 0xea, 0x52, 0x09,
+	0x30, 0x34, 0xc5, 0x09,
+	0x3d, 0xe2, 0xc4, 0x29,
+	0xb8, 0xe2, 0xc4, 0x19,
+	0x01, 0xea, 0xc6, 0x01,
+	0x02, 0xe2, 0xc8, 0x31,
+	0x02, 0xec, 0x40, 0x31,
+	0xff, 0xa1, 0xdc, 0x72,
+	0x02, 0xe8, 0xda, 0x31,
+	0x02, 0xa0, 0x50, 0x31,
+	0x00, 0xe2, 0xfe, 0x42,
+	0x80, 0x33, 0x67, 0x02,
+	0x01, 0x44, 0xd4, 0x31,
+	0x00, 0xe2, 0xb8, 0x5b,
+	0x01, 0x33, 0x67, 0x02,
+	0xe0, 0x36, 0x19, 0x63,
+	0x02, 0x33, 0x67, 0x02,
+	0x20, 0x46, 0x12, 0x63,
+	0xff, 0xea, 0x52, 0x09,
+	0xa8, 0xea, 0xca, 0x5b,
+	0x04, 0x92, 0xf9, 0x7a,
+	0x01, 0x34, 0xc1, 0x31,
+	0x00, 0x93, 0xf9, 0x62,
+	0x01, 0x35, 0xc1, 0x31,
+	0x00, 0x94, 0x03, 0x73,
+	0x01, 0xa9, 0x52, 0x11,
+	0xff, 0xa9, 0xee, 0x6a,
+	0x00, 0xe2, 0x12, 0x43,
+	0x10, 0x33, 0x67, 0x02,
+	0x04, 0x92, 0x13, 0x7b,
+	0xfb, 0x92, 0x25, 0x0b,
+	0xff, 0xea, 0x66, 0x0a,
+	0x01, 0xa4, 0x0d, 0x6b,
+	0x02, 0xa8, 0x90, 0x32,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x10, 0x92, 0xbd, 0x7a,
+	0xff, 0xea, 0xdc, 0x5b,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x04, 0xea, 0x50, 0x59,
+	0x04, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x04, 0xea, 0x50, 0x59,
+	0x04, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0x92, 0xb5, 0x7a,
+	0xc0, 0x33, 0x29, 0x7b,
+	0x80, 0x33, 0xb5, 0x6a,
+	0xff, 0x88, 0x29, 0x6b,
+	0x40, 0x33, 0xb5, 0x6a,
+	0x10, 0x92, 0x2f, 0x7b,
+	0x0a, 0xea, 0x50, 0x59,
+	0x0a, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x4e, 0x5b,
+	0x00, 0xe2, 0x82, 0x43,
+	0x50, 0x4b, 0x36, 0x6b,
+	0xbf, 0x3a, 0x74, 0x08,
+	0x01, 0xe0, 0xf4, 0x31,
+	0xff, 0xea, 0xc0, 0x09,
+	0x01, 0x2e, 0x5d, 0x1a,
+	0x00, 0x2f, 0x5f, 0x22,
+	0x04, 0x47, 0x8f, 0x02,
+	0x01, 0xfa, 0xc0, 0x35,
+	0x02, 0xa8, 0x84, 0x32,
+	0x02, 0xea, 0xb4, 0x00,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x02, 0x42, 0x51, 0x31,
+	0xff, 0x90, 0x65, 0x68,
+	0xff, 0x88, 0x5b, 0x6b,
+	0x01, 0xa4, 0x57, 0x6b,
+	0x02, 0xa4, 0x5f, 0x6b,
+	0x01, 0x84, 0x5f, 0x7b,
+	0x02, 0x28, 0x19, 0x33,
+	0x02, 0xa8, 0x50, 0x36,
+	0xff, 0x88, 0x5f, 0x73,
+	0x00, 0xe2, 0x32, 0x5b,
+	0x02, 0xa8, 0x20, 0x33,
+	0x02, 0x2c, 0x19, 0x33,
+	0x02, 0xa8, 0x58, 0x32,
+	0x04, 0xa4, 0x49, 0x07,
+	0xc0, 0x33, 0xb5, 0x6a,
+	0x04, 0x92, 0x25, 0x03,
+	0x20, 0x92, 0x83, 0x6b,
+	0x02, 0xa8, 0x40, 0x31,
+	0xc0, 0x34, 0xc1, 0x09,
+	0x00, 0x35, 0x51, 0x01,
+	0xff, 0xea, 0x52, 0x09,
+	0x30, 0x34, 0xc5, 0x09,
+	0x3d, 0xe2, 0xc4, 0x29,
+	0xb8, 0xe2, 0xc4, 0x19,
+	0x01, 0xea, 0xc6, 0x01,
+	0x02, 0xe2, 0xc8, 0x31,
+	0x02, 0xa0, 0xda, 0x31,
+	0x02, 0xa0, 0x50, 0x31,
+	0xf7, 0x57, 0xae, 0x08,
+	0x08, 0xea, 0x98, 0x00,
+	0x01, 0x44, 0xd4, 0x31,
+	0xee, 0x00, 0x8c, 0x6b,
+	0x02, 0xea, 0xb4, 0x00,
+	0x00, 0xe2, 0xb4, 0x5b,
+	0x09, 0x4c, 0x8e, 0x7b,
+	0x08, 0x4c, 0x06, 0x68,
+	0x0b, 0xea, 0x50, 0x59,
+	0x0b, 0xea, 0x04, 0x00,
+	0x01, 0x44, 0xd4, 0x31,
+	0x20, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0x9e, 0x5b,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0x84, 0xa3, 0x7b,
+	0x01, 0xa4, 0x49, 0x07,
+	0x08, 0x60, 0x30, 0x33,
+	0x08, 0x80, 0x41, 0x37,
+	0xdf, 0x33, 0x67, 0x0a,
+	0xee, 0x00, 0xb0, 0x6b,
+	0x05, 0xea, 0xb4, 0x00,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x00, 0xe2, 0x6a, 0x59,
+	0x00, 0xe2, 0xbc, 0x42,
+	0x01, 0xea, 0x6c, 0x02,
+	0xc0, 0xea, 0x66, 0x06,
+	0xff, 0x42, 0xc4, 0x6b,
+	0x01, 0x41, 0xb8, 0x6b,
+	0x02, 0x41, 0xb8, 0x7b,
+	0xff, 0x42, 0xc4, 0x6b,
+	0x01, 0x41, 0xb8, 0x6b,
+	0x02, 0x41, 0xb8, 0x7b,
+	0xff, 0x42, 0xc4, 0x7b,
+	0x04, 0x4c, 0xb8, 0x6b,
+	0xe0, 0x41, 0x6c, 0x0e,
+	0x01, 0x44, 0xd4, 0x31,
+	0xff, 0x42, 0xcc, 0x7b,
+	0x04, 0x4c, 0xcc, 0x6b,
+	0xe0, 0x41, 0x6c, 0x0a,
+	0xe0, 0x36, 0xf9, 0x61,
+	0xff, 0xea, 0xca, 0x09,
+	0x01, 0xe2, 0xc8, 0x31,
+	0x01, 0x46, 0xda, 0x35,
+	0x01, 0x44, 0xd4, 0x35,
+	0x10, 0xea, 0x80, 0x00,
+	0x01, 0xe2, 0x62, 0x36,
+	0x04, 0xa6, 0xe4, 0x7b,
+	0xff, 0xea, 0x5a, 0x09,
+	0xff, 0xea, 0x4c, 0x0d,
+	0x01, 0xa6, 0x02, 0x6c,
+	0x10, 0xad, 0x64, 0x78,
+	0x80, 0xad, 0xfa, 0x6b,
+	0x08, 0xad, 0x64, 0x68,
+	0x04, 0x84, 0xf9, 0x30,
+	0x00, 0xea, 0x08, 0x81,
+	0xff, 0xea, 0xd4, 0x09,
+	0x02, 0x84, 0xf9, 0x88,
+	0x0d, 0xea, 0x5a, 0x01,
+	0x04, 0xa6, 0x4c, 0x05,
+	0x04, 0xa6, 0x64, 0x78,
+	0xff, 0xea, 0x5a, 0x09,
+	0x03, 0x84, 0x59, 0x89,
+	0x03, 0xea, 0x4c, 0x01,
+	0x80, 0x1a, 0x64, 0x78,
+	0x08, 0x19, 0x64, 0x78,
+	0x08, 0xb0, 0xe0, 0x30,
+	0x04, 0xb0, 0xe0, 0x30,
+	0x03, 0xb0, 0xf0, 0x30,
+	0x01, 0xb0, 0x06, 0x33,
+	0x7f, 0x83, 0xe9, 0x08,
+	0x04, 0xac, 0x58, 0x19,
+	0xff, 0xea, 0xc0, 0x09,
+	0x04, 0x84, 0x09, 0x9b,
+	0x00, 0x85, 0x0b, 0x23,
+	0x00, 0x86, 0x0d, 0x23,
+	0x00, 0x87, 0x0f, 0x23,
+	0x01, 0x84, 0xc5, 0x31,
+	0x80, 0x83, 0x25, 0x7c,
+	0x02, 0xe2, 0xc4, 0x01,
+	0xff, 0xea, 0x4c, 0x09,
+	0x01, 0xe2, 0x36, 0x30,
+	0xc8, 0x19, 0x32, 0x00,
+	0x88, 0x19, 0x32, 0x00,
+	0x01, 0xac, 0xd4, 0x99,
+	0x00, 0xe2, 0x64, 0x50,
+	0xfe, 0xa6, 0x4c, 0x0d,
+	0x0b, 0x98, 0xe1, 0x30,
+	0xfd, 0xa4, 0x49, 0x09,
+	0x80, 0xa3, 0x39, 0x7c,
+	0x02, 0xa4, 0x48, 0x01,
+	0x01, 0xa4, 0x36, 0x30,
+	0xa8, 0xea, 0x32, 0x00,
+	0xfd, 0xa4, 0x49, 0x0b,
+	0x05, 0xa3, 0x07, 0x33,
+	0x80, 0x83, 0x45, 0x6c,
+	0x02, 0xea, 0x4c, 0x05,
+	0xff, 0xea, 0x4c, 0x0d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x02, 0xa6, 0xe6, 0x6b,
+	0x80, 0xf9, 0xf2, 0x05,
+	0xc0, 0x33, 0x53, 0x7c,
+	0x03, 0xea, 0x50, 0x59,
+	0x03, 0xea, 0x04, 0x00,
+	0x20, 0x33, 0x77, 0x7c,
+	0x01, 0x84, 0x5d, 0x6c,
+	0x06, 0xea, 0x50, 0x59,
+	0x06, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x7a, 0x44,
+	0x01, 0x00, 0x60, 0x32,
+	0xee, 0x00, 0x66, 0x6c,
+	0x05, 0xea, 0xb4, 0x00,
+	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x80, 0x3d, 0x7a, 0x00,
+	0xfc, 0x42, 0x68, 0x7c,
+	0x7f, 0x3d, 0x7a, 0x08,
+	0x00, 0x30, 0x45, 0x59,
+	0x01, 0x30, 0x01, 0x30,
+	0x09, 0xea, 0x50, 0x59,
+	0x09, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0xa4, 0x5d, 0x6c,
+	0x00, 0xe2, 0x30, 0x5c,
+	0x20, 0x33, 0x67, 0x02,
+	0x01, 0x00, 0x60, 0x32,
+	0x02, 0xa6, 0x82, 0x7c,
+	0x00, 0xe2, 0x46, 0x5c,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0xe2, 0x66, 0x58,
+	0x00, 0xe2, 0x3a, 0x58,
+	0x00, 0x30, 0x45, 0x59,
+	0x01, 0x30, 0x01, 0x30,
+	0x20, 0x19, 0x82, 0x6c,
+	0x00, 0xe2, 0xb2, 0x5c,
+	0x04, 0x19, 0x9c, 0x6c,
+	0x02, 0x19, 0x32, 0x00,
+	0x01, 0x84, 0x9d, 0x7c,
+	0x01, 0x1b, 0x96, 0x7c,
+	0x01, 0x1a, 0x9c, 0x6c,
+	0x00, 0xe2, 0x4c, 0x44,
+	0x80, 0x4b, 0xa2, 0x6c,
+	0x01, 0x4c, 0x9e, 0x7c,
+	0x03, 0x42, 0x4c, 0x6c,
+	0x00, 0xe2, 0xe0, 0x5b,
+	0x80, 0xf9, 0xf2, 0x01,
+	0x04, 0x33, 0xf9, 0x79,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x08, 0x5d, 0xba, 0x6c,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0x30, 0x45, 0x59,
+	0x01, 0x30, 0x01, 0x30,
+	0x02, 0x1b, 0xaa, 0x7c,
+	0x08, 0x5d, 0xb8, 0x7c,
+	0x03, 0x68, 0x00, 0x37,
+	0x01, 0x84, 0x09, 0x07,
+	0x80, 0x1b, 0xc4, 0x7c,
+	0x80, 0x84, 0xc5, 0x6c,
+	0xff, 0x85, 0x0b, 0x1b,
+	0xff, 0x86, 0x0d, 0x23,
+	0xff, 0x87, 0x0f, 0x23,
+	0xf8, 0x1b, 0x08, 0x0b,
+	0xff, 0xea, 0x06, 0x0b,
+	0x03, 0x68, 0x00, 0x37,
+	0x00, 0xe2, 0xc4, 0x58,
+	0x10, 0xea, 0x18, 0x00,
+	0xf9, 0xd9, 0xb2, 0x0d,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x01, 0x52, 0x48, 0x31,
+	0x20, 0xa4, 0xee, 0x7c,
+	0x20, 0x5b, 0xee, 0x7c,
+	0x80, 0xf9, 0xfc, 0x7c,
+	0x02, 0xea, 0xb4, 0x00,
+	0x11, 0x00, 0x00, 0x10,
+	0x04, 0x19, 0x08, 0x7d,
+	0xdf, 0x19, 0x32, 0x08,
+	0x60, 0x5b, 0xe6, 0x6c,
+	0x01, 0x4c, 0xe2, 0x7c,
+	0x20, 0x19, 0x32, 0x00,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x02, 0xea, 0xb4, 0x00,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x10, 0x5b, 0x00, 0x6d,
+	0x08, 0x5b, 0x0a, 0x6d,
+	0x20, 0x5b, 0xfa, 0x6c,
+	0x02, 0x5b, 0x2a, 0x6d,
+	0x0e, 0xea, 0x50, 0x59,
+	0x0e, 0xea, 0x04, 0x00,
+	0x80, 0xf9, 0xea, 0x6c,
+	0xdf, 0x5c, 0xb8, 0x08,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x01, 0xa4, 0xe5, 0x6d,
+	0x00, 0xe2, 0x30, 0x5c,
+	0x00, 0xe2, 0x34, 0x5d,
+	0x01, 0x90, 0x21, 0x1b,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x00, 0xe2, 0x32, 0x5b,
+	0xf3, 0x96, 0xd5, 0x19,
+	0x00, 0xe2, 0x18, 0x55,
+	0x80, 0x96, 0x19, 0x6d,
+	0x0f, 0xea, 0x50, 0x59,
+	0x0f, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x20, 0x45,
+	0x04, 0x8c, 0xe1, 0x30,
+	0x01, 0xea, 0xf2, 0x00,
+	0x02, 0xea, 0x36, 0x00,
+	0xa8, 0xea, 0x32, 0x00,
+	0xff, 0x97, 0x27, 0x7d,
+	0x14, 0xea, 0x50, 0x59,
+	0x14, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x96, 0x5d,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x09, 0x80, 0xe1, 0x30,
+	0x02, 0xea, 0x36, 0x00,
+	0xa8, 0xea, 0x32, 0x00,
+	0x00, 0xe2, 0x8e, 0x5d,
+	0x01, 0xd9, 0xb2, 0x05,
+	0x02, 0xa6, 0x44, 0x7d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x52, 0x6d,
+	0xfc, 0x42, 0x3e, 0x7d,
+	0x10, 0x40, 0x40, 0x6d,
+	0x20, 0x4d, 0x42, 0x7d,
+	0x08, 0x5d, 0x52, 0x6d,
+	0x02, 0xa6, 0xe6, 0x6b,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x20, 0x5b, 0x52, 0x6d,
+	0x01, 0x1b, 0x72, 0x6d,
+	0xfc, 0x42, 0x4e, 0x7d,
+	0x10, 0x40, 0x50, 0x6d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x08, 0x5d, 0x64, 0x78,
+	0x02, 0x19, 0x32, 0x00,
+	0x01, 0x5b, 0x40, 0x31,
+	0x00, 0xe2, 0xb2, 0x5c,
+	0x00, 0xe2, 0x9e, 0x5b,
+	0x20, 0xea, 0xb6, 0x00,
+	0x00, 0xe2, 0xe0, 0x5b,
+	0x20, 0x5c, 0xb8, 0x00,
+	0x04, 0x19, 0x68, 0x6d,
+	0x01, 0x1a, 0x68, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x01, 0x1a, 0x64, 0x78,
+	0x80, 0xf9, 0xf2, 0x01,
+	0x20, 0xa0, 0xcc, 0x7d,
+	0xff, 0x90, 0x21, 0x1b,
+	0x08, 0x92, 0x43, 0x6b,
+	0x02, 0xea, 0xb4, 0x04,
+	0x01, 0xa4, 0x49, 0x03,
+	0x40, 0x5b, 0x82, 0x6d,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x40, 0x5b, 0x82, 0x6d,
+	0x04, 0x5d, 0xe6, 0x7d,
+	0x01, 0x1a, 0xe6, 0x7d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x40, 0x5b, 0xcc, 0x7d,
+	0x04, 0x5d, 0xe6, 0x7d,
+	0x01, 0x1a, 0xe6, 0x7d,
+	0x80, 0xf9, 0xf2, 0x01,
+	0xff, 0x90, 0x21, 0x1b,
+	0x08, 0x92, 0x43, 0x6b,
+	0x02, 0xea, 0xb4, 0x04,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x01, 0x1b, 0x64, 0x78,
+	0x80, 0xf9, 0xf2, 0x01,
+	0x02, 0xea, 0xb4, 0x04,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x01, 0x1b, 0xaa, 0x6d,
+	0x40, 0x5b, 0xb8, 0x7d,
+	0x01, 0x1b, 0xaa, 0x6d,
+	0x02, 0x19, 0x32, 0x00,
+	0x01, 0x1a, 0x64, 0x78,
+	0x80, 0xf9, 0xf2, 0x01,
+	0xff, 0xea, 0x10, 0x03,
+	0x08, 0x92, 0x25, 0x03,
+	0x00, 0xe2, 0x42, 0x43,
+	0x01, 0x1a, 0xb4, 0x7d,
+	0x40, 0x5b, 0xb0, 0x7d,
+	0x01, 0x1a, 0x9e, 0x6d,
+	0xfc, 0x42, 0x64, 0x78,
+	0x01, 0x1a, 0xb8, 0x6d,
+	0x10, 0xea, 0x50, 0x59,
+	0x10, 0xea, 0x04, 0x00,
+	0xfc, 0x42, 0x64, 0x78,
+	0x10, 0x40, 0xbe, 0x6d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x40, 0x5b, 0x9e, 0x6d,
+	0x01, 0x1a, 0x64, 0x78,
+	0x01, 0x90, 0x21, 0x1b,
+	0x30, 0x3f, 0xc0, 0x09,
+	0x30, 0xe0, 0x64, 0x60,
+	0x40, 0x4b, 0x64, 0x68,
+	0xff, 0xea, 0x52, 0x01,
+	0xee, 0x00, 0xd2, 0x6d,
+	0x80, 0xf9, 0xf2, 0x01,
+	0xff, 0x90, 0x21, 0x1b,
+	0x02, 0xea, 0xb4, 0x00,
+	0x20, 0xea, 0x9a, 0x00,
+	0xf3, 0x42, 0xde, 0x6d,
+	0x12, 0xea, 0x50, 0x59,
+	0x12, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x0d, 0xea, 0x50, 0x59,
+	0x0d, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0xf8, 0x41,
+	0x01, 0x90, 0x21, 0x1b,
+	0x11, 0xea, 0x50, 0x59,
+	0x11, 0xea, 0x04, 0x00,
+	0x00, 0xe2, 0x32, 0x5b,
+	0x08, 0x5a, 0xb4, 0x00,
+	0x00, 0xe2, 0x0c, 0x5e,
+	0xa8, 0xea, 0x32, 0x00,
+	0x00, 0xe2, 0x3e, 0x59,
+	0x80, 0x1a, 0xfa, 0x7d,
+	0x00, 0xe2, 0x0c, 0x5e,
+	0x80, 0x19, 0x32, 0x00,
+	0x40, 0x5b, 0x00, 0x6e,
+	0x08, 0x5a, 0x00, 0x7e,
+	0x20, 0x4d, 0x64, 0x78,
+	0x02, 0x84, 0x09, 0x03,
+	0x40, 0x5b, 0xcc, 0x7d,
+	0xff, 0x90, 0x21, 0x1b,
+	0x80, 0xf9, 0xf2, 0x01,
+	0x08, 0x92, 0x43, 0x6b,
+	0x02, 0xea, 0xb4, 0x04,
+	0x01, 0x38, 0xe1, 0x30,
+	0x05, 0x39, 0xe3, 0x98,
+	0x01, 0xe0, 0xf4, 0x31,
+	0xff, 0xea, 0xc0, 0x09,
+	0x00, 0x3a, 0xe5, 0x20,
+	0x00, 0x3b, 0xe7, 0x20,
+	0x01, 0xfa, 0xc0, 0x31,
+	0x04, 0xea, 0xe8, 0x30,
+	0xff, 0xea, 0xf0, 0x08,
+	0x02, 0xea, 0xf2, 0x00,
+	0xff, 0xea, 0xf4, 0x0c
+};
+
+typedef int ahd_patch_func_t (struct ahd_softc *ahd);
+static ahd_patch_func_t ahd_patch22_func;
+
+static int
+ahd_patch22_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch21_func;
+
+static int
+ahd_patch21_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0);
+}
+
+static ahd_patch_func_t ahd_patch20_func;
+
+static int
+ahd_patch20_func(struct ahd_softc *ahd)
+{
+	return ((ahd->features & AHD_RTI) == 0);
+}
+
+static ahd_patch_func_t ahd_patch19_func;
+
+static int
+ahd_patch19_func(struct ahd_softc *ahd)
+{
+	return ((ahd->flags & AHD_INITIATORROLE) != 0);
+}
+
+static ahd_patch_func_t ahd_patch18_func;
+
+static int
+ahd_patch18_func(struct ahd_softc *ahd)
+{
+	return ((ahd->flags & AHD_TARGETROLE) != 0);
+}
+
+static ahd_patch_func_t ahd_patch17_func;
+
+static int
+ahd_patch17_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch16_func;
+
+static int
+ahd_patch16_func(struct ahd_softc *ahd)
+{
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0);
+}
+
+static ahd_patch_func_t ahd_patch15_func;
+
+static int
+ahd_patch15_func(struct ahd_softc *ahd)
+{
+	return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0);
+}
+
+static ahd_patch_func_t ahd_patch14_func;
+
+static int
+ahd_patch14_func(struct ahd_softc *ahd)
+{
+	return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0);
+}
+
+static ahd_patch_func_t ahd_patch13_func;
+
+static int
+ahd_patch13_func(struct ahd_softc *ahd)
+{
+	return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0);
+}
+
+static ahd_patch_func_t ahd_patch12_func;
+
+static int
+ahd_patch12_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch11_func;
+
+static int
+ahd_patch11_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch10_func;
+
+static int
+ahd_patch10_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0);
+}
+
+static ahd_patch_func_t ahd_patch9_func;
+
+static int
+ahd_patch9_func(struct ahd_softc *ahd)
+{
+	return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch8_func;
+
+static int
+ahd_patch8_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch7_func;
+
+static int
+ahd_patch7_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch6_func;
+
+static int
+ahd_patch6_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch5_func;
+
+static int
+ahd_patch5_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch4_func;
+
+static int
+ahd_patch4_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch3_func;
+
+static int
+ahd_patch3_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_FAINT_LED_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch2_func;
+
+static int
+ahd_patch2_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_SET_MODE_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch1_func;
+
+static int
+ahd_patch1_func(struct ahd_softc *ahd)
+{
+	return ((ahd->bugs & AHD_INTCOLLISION_BUG) != 0);
+}
+
+static ahd_patch_func_t ahd_patch0_func;
+
+static int
+ahd_patch0_func(struct ahd_softc *ahd)
+{
+	return (0);
+}
+
+static struct patch {
+	ahd_patch_func_t		*patch_func;
+	uint32_t		 begin		:10,
+				 skip_instr	:10,
+				 skip_patch	:12;
+} patches[] = {
+	{ ahd_patch1_func, 0, 3, 3 },
+	{ ahd_patch1_func, 1, 1, 2 },
+	{ ahd_patch0_func, 2, 1, 1 },
+	{ ahd_patch1_func, 3, 3, 3 },
+	{ ahd_patch1_func, 4, 1, 2 },
+	{ ahd_patch0_func, 5, 1, 1 },
+	{ ahd_patch2_func, 6, 1, 2 },
+	{ ahd_patch0_func, 7, 1, 1 },
+	{ ahd_patch3_func, 20, 5, 1 },
+	{ ahd_patch2_func, 29, 1, 2 },
+	{ ahd_patch0_func, 30, 1, 1 },
+	{ ahd_patch1_func, 37, 1, 2 },
+	{ ahd_patch0_func, 38, 1, 1 },
+	{ ahd_patch2_func, 43, 1, 2 },
+	{ ahd_patch0_func, 44, 1, 1 },
+	{ ahd_patch2_func, 47, 1, 2 },
+	{ ahd_patch0_func, 48, 1, 1 },
+	{ ahd_patch2_func, 51, 1, 2 },
+	{ ahd_patch0_func, 52, 1, 1 },
+	{ ahd_patch2_func, 65, 1, 2 },
+	{ ahd_patch0_func, 66, 1, 1 },
+	{ ahd_patch2_func, 69, 1, 2 },
+	{ ahd_patch0_func, 70, 1, 1 },
+	{ ahd_patch1_func, 73, 1, 2 },
+	{ ahd_patch0_func, 74, 1, 1 },
+	{ ahd_patch4_func, 107, 1, 1 },
+	{ ahd_patch2_func, 162, 6, 1 },
+	{ ahd_patch1_func, 168, 2, 1 },
+	{ ahd_patch5_func, 170, 1, 1 },
+	{ ahd_patch2_func, 179, 1, 2 },
+	{ ahd_patch0_func, 180, 1, 1 },
+	{ ahd_patch6_func, 181, 2, 2 },
+	{ ahd_patch0_func, 183, 6, 3 },
+	{ ahd_patch2_func, 186, 1, 2 },
+	{ ahd_patch0_func, 187, 1, 1 },
+	{ ahd_patch2_func, 190, 1, 2 },
+	{ ahd_patch0_func, 191, 1, 1 },
+	{ ahd_patch7_func, 193, 2, 1 },
+	{ ahd_patch5_func, 201, 16, 2 },
+	{ ahd_patch0_func, 217, 1, 1 },
+	{ ahd_patch8_func, 237, 2, 1 },
+	{ ahd_patch1_func, 241, 1, 2 },
+	{ ahd_patch0_func, 242, 1, 1 },
+	{ ahd_patch7_func, 245, 2, 1 },
+	{ ahd_patch1_func, 259, 1, 2 },
+	{ ahd_patch0_func, 260, 1, 1 },
+	{ ahd_patch1_func, 263, 1, 2 },
+	{ ahd_patch0_func, 264, 1, 1 },
+	{ ahd_patch2_func, 267, 1, 2 },
+	{ ahd_patch0_func, 268, 1, 1 },
+	{ ahd_patch1_func, 323, 1, 2 },
+	{ ahd_patch0_func, 324, 1, 1 },
+	{ ahd_patch2_func, 332, 1, 2 },
+	{ ahd_patch0_func, 333, 1, 1 },
+	{ ahd_patch2_func, 336, 1, 2 },
+	{ ahd_patch0_func, 337, 1, 1 },
+	{ ahd_patch1_func, 343, 1, 2 },
+	{ ahd_patch0_func, 344, 1, 1 },
+	{ ahd_patch1_func, 346, 1, 2 },
+	{ ahd_patch0_func, 347, 1, 1 },
+	{ ahd_patch9_func, 366, 1, 1 },
+	{ ahd_patch9_func, 369, 1, 1 },
+	{ ahd_patch9_func, 371, 1, 1 },
+	{ ahd_patch9_func, 383, 1, 1 },
+	{ ahd_patch1_func, 393, 1, 2 },
+	{ ahd_patch0_func, 394, 1, 1 },
+	{ ahd_patch1_func, 396, 1, 2 },
+	{ ahd_patch0_func, 397, 1, 1 },
+	{ ahd_patch1_func, 405, 1, 2 },
+	{ ahd_patch0_func, 406, 1, 1 },
+	{ ahd_patch2_func, 419, 1, 2 },
+	{ ahd_patch0_func, 420, 1, 1 },
+	{ ahd_patch10_func, 450, 1, 1 },
+	{ ahd_patch1_func, 457, 1, 2 },
+	{ ahd_patch0_func, 458, 1, 1 },
+	{ ahd_patch2_func, 470, 1, 2 },
+	{ ahd_patch0_func, 471, 1, 1 },
+	{ ahd_patch11_func, 476, 6, 2 },
+	{ ahd_patch0_func, 482, 1, 1 },
+	{ ahd_patch12_func, 505, 1, 1 },
+	{ ahd_patch13_func, 514, 1, 1 },
+	{ ahd_patch14_func, 515, 1, 2 },
+	{ ahd_patch0_func, 516, 1, 1 },
+	{ ahd_patch15_func, 519, 1, 1 },
+	{ ahd_patch14_func, 520, 1, 1 },
+	{ ahd_patch16_func, 531, 1, 2 },
+	{ ahd_patch0_func, 532, 1, 1 },
+	{ ahd_patch1_func, 551, 1, 2 },
+	{ ahd_patch0_func, 552, 1, 1 },
+	{ ahd_patch1_func, 555, 1, 2 },
+	{ ahd_patch0_func, 556, 1, 1 },
+	{ ahd_patch2_func, 561, 1, 2 },
+	{ ahd_patch0_func, 562, 1, 1 },
+	{ ahd_patch2_func, 566, 1, 2 },
+	{ ahd_patch0_func, 567, 1, 1 },
+	{ ahd_patch1_func, 568, 1, 2 },
+	{ ahd_patch0_func, 569, 1, 1 },
+	{ ahd_patch2_func, 580, 1, 2 },
+	{ ahd_patch0_func, 581, 1, 1 },
+	{ ahd_patch17_func, 585, 1, 1 },
+	{ ahd_patch18_func, 590, 1, 1 },
+	{ ahd_patch19_func, 591, 2, 1 },
+	{ ahd_patch18_func, 595, 1, 2 },
+	{ ahd_patch0_func, 596, 1, 1 },
+	{ ahd_patch2_func, 599, 1, 2 },
+	{ ahd_patch0_func, 600, 1, 1 },
+	{ ahd_patch2_func, 615, 1, 2 },
+	{ ahd_patch0_func, 616, 1, 1 },
+	{ ahd_patch20_func, 617, 14, 1 },
+	{ ahd_patch1_func, 635, 1, 2 },
+	{ ahd_patch0_func, 636, 1, 1 },
+	{ ahd_patch20_func, 637, 1, 1 },
+	{ ahd_patch1_func, 649, 1, 2 },
+	{ ahd_patch0_func, 650, 1, 1 },
+	{ ahd_patch1_func, 657, 1, 2 },
+	{ ahd_patch0_func, 658, 1, 1 },
+	{ ahd_patch17_func, 681, 1, 1 },
+	{ ahd_patch17_func, 719, 1, 1 },
+	{ ahd_patch1_func, 730, 1, 2 },
+	{ ahd_patch0_func, 731, 1, 1 },
+	{ ahd_patch1_func, 748, 1, 2 },
+	{ ahd_patch0_func, 749, 1, 1 },
+	{ ahd_patch1_func, 751, 1, 2 },
+	{ ahd_patch0_func, 752, 1, 1 },
+	{ ahd_patch1_func, 755, 1, 2 },
+	{ ahd_patch0_func, 756, 1, 1 },
+	{ ahd_patch21_func, 758, 1, 2 },
+	{ ahd_patch0_func, 759, 2, 1 },
+	{ ahd_patch22_func, 762, 4, 2 },
+	{ ahd_patch0_func, 766, 1, 1 },
+	{ ahd_patch22_func, 774, 11, 1 }
+};
+
+static struct cs {
+	uint16_t	begin;
+	uint16_t	end;
+} critical_sections[] = {
+	{ 11, 12 },
+	{ 13, 14 },
+	{ 29, 42 },
+	{ 56, 59 },
+	{ 101, 128 },
+	{ 129, 157 },
+	{ 159, 162 },
+	{ 170, 178 },
+	{ 201, 250 },
+	{ 681, 697 },
+	{ 697, 711 },
+	{ 721, 725 }
+};
+
+static const int num_critical_sections = sizeof(critical_sections)
+				       / sizeof(*critical_sections);
diff --git a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
new file mode 100644
index 0000000..8ff16fd
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx.h
@@ -0,0 +1,1352 @@
+/*
+ * Core definitions and data structures shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#79 $
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AIC7XXX_H_
+#define _AIC7XXX_H_
+
+/* Register Definitions */
+#include "aic7xxx_reg.h"
+
+/************************* Forward Declarations *******************************/
+struct ahc_platform_data;
+struct scb_platform_data;
+struct seeprom_descriptor;
+
+/****************************** Useful Macros *********************************/
+#ifndef MAX
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define NUM_ELEMENTS(array) (sizeof(array) / sizeof(*array))
+
+#define ALL_CHANNELS '\0'
+#define ALL_TARGETS_MASK 0xFFFF
+#define INITIATOR_WILDCARD	(~0)
+
+#define SCSIID_TARGET(ahc, scsiid) \
+	(((scsiid) & ((((ahc)->features & AHC_TWIN) != 0) ? TWIN_TID : TID)) \
+	>> TID_SHIFT)
+#define SCSIID_OUR_ID(scsiid) \
+	((scsiid) & OID)
+#define SCSIID_CHANNEL(ahc, scsiid) \
+	((((ahc)->features & AHC_TWIN) != 0) \
+        ? ((((scsiid) & TWIN_CHNLB) != 0) ? 'B' : 'A') \
+       : 'A')
+#define	SCB_IS_SCSIBUS_B(ahc, scb) \
+	(SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) == 'B')
+#define	SCB_GET_OUR_ID(scb) \
+	SCSIID_OUR_ID((scb)->hscb->scsiid)
+#define	SCB_GET_TARGET(ahc, scb) \
+	SCSIID_TARGET((ahc), (scb)->hscb->scsiid)
+#define	SCB_GET_CHANNEL(ahc, scb) \
+	SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid)
+#define	SCB_GET_LUN(scb) \
+	((scb)->hscb->lun & LID)
+#define SCB_GET_TARGET_OFFSET(ahc, scb)	\
+	(SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0))
+#define SCB_GET_TARGET_MASK(ahc, scb) \
+	(0x01 << (SCB_GET_TARGET_OFFSET(ahc, scb)))
+#ifdef AHC_DEBUG
+#define SCB_IS_SILENT(scb)					\
+	((ahc_debug & AHC_SHOW_MASKED_ERRORS) == 0		\
+      && (((scb)->flags & SCB_SILENT) != 0))
+#else
+#define SCB_IS_SILENT(scb)					\
+	(((scb)->flags & SCB_SILENT) != 0)
+#endif
+#define TCL_TARGET_OFFSET(tcl) \
+	((((tcl) >> 4) & TID) >> 4)
+#define TCL_LUN(tcl) \
+	(tcl & (AHC_NUM_LUNS - 1))
+#define BUILD_TCL(scsiid, lun) \
+	((lun) | (((scsiid) & TID) << 4))
+
+#ifndef	AHC_TARGET_MODE
+#undef	AHC_TMODE_ENABLE
+#define	AHC_TMODE_ENABLE 0
+#endif
+
+/**************************** Driver Constants ********************************/
+/*
+ * The maximum number of supported targets.
+ */
+#define AHC_NUM_TARGETS 16
+
+/*
+ * The maximum number of supported luns.
+ * The identify message only supports 64 luns in SPI3.
+ * You can have 2^64 luns when information unit transfers are enabled,
+ * but it is doubtful this driver will ever support IUTs.
+ */
+#define AHC_NUM_LUNS 64
+
+/*
+ * The maximum transfer per S/G segment.
+ */
+#define AHC_MAXTRANSFER_SIZE	 0x00ffffff	/* limited by 24bit counter */
+
+/*
+ * The maximum amount of SCB storage in hardware on a controller.
+ * This value represents an upper bound.  Controllers vary in the number
+ * they actually support.
+ */
+#define AHC_SCB_MAX	255
+
+/*
+ * The maximum number of concurrent transactions supported per driver instance.
+ * Sequencer Control Blocks (SCBs) store per-transaction information.  Although
+ * the space for SCBs on the host adapter varies by model, the driver will
+ * page the SCBs between host and controller memory as needed.  We are limited
+ * to 253 because:
+ * 	1) The 8bit nature of the RISC engine holds us to an 8bit value.
+ * 	2) We reserve one value, 255, to represent the invalid element.
+ *	3) Our input queue scheme requires one SCB to always be reserved
+ *	   in advance of queuing any SCBs.  This takes us down to 254.
+ *	4) To handle our output queue correctly on machines that only
+ * 	   support 32bit stores, we must clear the array 4 bytes at a
+ *	   time.  To avoid colliding with a DMA write from the sequencer,
+ *	   we must be sure that 4 slots are empty when we write to clear
+ *	   the queue.  This reduces us to 253 SCBs: 1 that just completed
+ *	   and the known three additional empty slots in the queue that
+ *	   precede it.
+ */
+#define AHC_MAX_QUEUE	253
+
+/*
+ * The maximum amount of SCB storage we allocate in host memory.  This
+ * number should reflect the 1 additional SCB we require to handle our
+ * qinfifo mechanism.
+ */
+#define AHC_SCB_MAX_ALLOC (AHC_MAX_QUEUE+1)
+
+/*
+ * Ring Buffer of incoming target commands.
+ * We allocate 256 to simplify the logic in the sequencer
+ * by using the natural wrap point of an 8bit counter.
+ */
+#define AHC_TMODE_CMDS	256
+
+/* Reset line assertion time in us */
+#define AHC_BUSRESET_DELAY	25
+
+/******************* Chip Characteristics/Operating Settings  *****************/
+/*
+ * Chip Type
+ * The chip order is from least sophisticated to most sophisticated.
+ */
+typedef enum {
+	AHC_NONE	= 0x0000,
+	AHC_CHIPID_MASK	= 0x00FF,
+	AHC_AIC7770	= 0x0001,
+	AHC_AIC7850	= 0x0002,
+	AHC_AIC7855	= 0x0003,
+	AHC_AIC7859	= 0x0004,
+	AHC_AIC7860	= 0x0005,
+	AHC_AIC7870	= 0x0006,
+	AHC_AIC7880	= 0x0007,
+	AHC_AIC7895	= 0x0008,
+	AHC_AIC7895C	= 0x0009,
+	AHC_AIC7890	= 0x000a,
+	AHC_AIC7896	= 0x000b,
+	AHC_AIC7892	= 0x000c,
+	AHC_AIC7899	= 0x000d,
+	AHC_VL		= 0x0100,	/* Bus type VL */
+	AHC_EISA	= 0x0200,	/* Bus type EISA */
+	AHC_PCI		= 0x0400,	/* Bus type PCI */
+	AHC_BUS_MASK	= 0x0F00
+} ahc_chip;
+
+/*
+ * Features available in each chip type.
+ */
+typedef enum {
+	AHC_FENONE	= 0x00000,
+	AHC_ULTRA	= 0x00001,	/* Supports 20MHz Transfers */
+	AHC_ULTRA2	= 0x00002,	/* Supports 40MHz Transfers */
+	AHC_WIDE  	= 0x00004,	/* Wide Channel */
+	AHC_TWIN	= 0x00008,	/* Twin Channel */
+	AHC_MORE_SRAM	= 0x00010,	/* 80 bytes instead of 64 */
+	AHC_CMD_CHAN	= 0x00020,	/* Has a Command DMA Channel */
+	AHC_QUEUE_REGS	= 0x00040,	/* Has Queue management registers */
+	AHC_SG_PRELOAD	= 0x00080,	/* Can perform auto-SG preload */
+	AHC_SPIOCAP	= 0x00100,	/* Has a Serial Port I/O Cap Register */
+	AHC_MULTI_TID	= 0x00200,	/* Has bitmask of TIDs for select-in */
+	AHC_HS_MAILBOX	= 0x00400,	/* Has HS_MAILBOX register */
+	AHC_DT		= 0x00800,	/* Double Transition transfers */
+	AHC_NEW_TERMCTL	= 0x01000,	/* Newer termination scheme */
+	AHC_MULTI_FUNC	= 0x02000,	/* Multi-Function Twin Channel Device */
+	AHC_LARGE_SCBS	= 0x04000,	/* 64byte SCBs */
+	AHC_AUTORATE	= 0x08000,	/* Automatic update of SCSIRATE/OFFSET*/
+	AHC_AUTOPAUSE	= 0x10000,	/* Automatic pause on register access */
+	AHC_TARGETMODE	= 0x20000,	/* Has tested target mode support */
+	AHC_MULTIROLE	= 0x40000,	/* Space for two roles at a time */
+	AHC_REMOVABLE	= 0x80000,	/* Hot-Swap supported */
+	AHC_AIC7770_FE	= AHC_FENONE,
+	/*
+	 * The real 7850 does not support Ultra modes, but there are
+	 * several cards that use the generic 7850 PCI ID even though
+	 * they are using an Ultra capable chip (7859/7860).  We start
+	 * out with the AHC_ULTRA feature set and then check the DEVSTATUS
+	 * register to determine if the capability is really present.
+	 */
+	AHC_AIC7850_FE	= AHC_SPIOCAP|AHC_AUTOPAUSE|AHC_TARGETMODE|AHC_ULTRA,
+	AHC_AIC7860_FE	= AHC_AIC7850_FE,
+	AHC_AIC7870_FE	= AHC_TARGETMODE,
+	AHC_AIC7880_FE	= AHC_AIC7870_FE|AHC_ULTRA,
+	/*
+	 * Although we have space for both the initiator and
+	 * target roles on ULTRA2 chips, we currently disable
+	 * the initiator role to allow multi-scsi-id target mode
+	 * configurations.  We can only respond on the same SCSI
+	 * ID as our initiator role if we allow initiator operation.
+	 * At some point, we should add a configuration knob to
+	 * allow both roles to be loaded.
+	 */
+	AHC_AIC7890_FE	= AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2
+			  |AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_MULTI_TID
+			  |AHC_HS_MAILBOX|AHC_NEW_TERMCTL|AHC_LARGE_SCBS
+			  |AHC_TARGETMODE,
+	AHC_AIC7892_FE	= AHC_AIC7890_FE|AHC_DT|AHC_AUTORATE|AHC_AUTOPAUSE,
+	AHC_AIC7895_FE	= AHC_AIC7880_FE|AHC_MORE_SRAM|AHC_AUTOPAUSE
+			  |AHC_CMD_CHAN|AHC_MULTI_FUNC|AHC_LARGE_SCBS,
+	AHC_AIC7895C_FE	= AHC_AIC7895_FE|AHC_MULTI_TID,
+	AHC_AIC7896_FE	= AHC_AIC7890_FE|AHC_MULTI_FUNC,
+	AHC_AIC7899_FE	= AHC_AIC7892_FE|AHC_MULTI_FUNC
+} ahc_feature;
+
+/*
+ * Bugs in the silicon that we work around in software.
+ */
+typedef enum {
+	AHC_BUGNONE		= 0x00,
+	/*
+	 * On all chips prior to the U2 product line,
+	 * the WIDEODD S/G segment feature does not
+	 * work during scsi->HostBus transfers.
+	 */
+	AHC_TMODE_WIDEODD_BUG	= 0x01,
+	/*
+	 * On the aic7890/91 Rev 0 chips, the autoflush
+	 * feature does not work.  A manual flush of
+	 * the DMA FIFO is required.
+	 */
+	AHC_AUTOFLUSH_BUG	= 0x02,
+	/*
+	 * On many chips, cacheline streaming does not work.
+	 */
+	AHC_CACHETHEN_BUG	= 0x04,
+	/*
+	 * On the aic7896/97 chips, cacheline
+	 * streaming must be enabled.
+	 */
+	AHC_CACHETHEN_DIS_BUG	= 0x08,
+	/*
+	 * PCI 2.1 Retry failure on non-empty data fifo.
+	 */
+	AHC_PCI_2_1_RETRY_BUG	= 0x10,
+	/*
+	 * Controller does not handle cacheline residuals
+	 * properly on S/G segments if PCI MWI instructions
+	 * are allowed.
+	 */
+	AHC_PCI_MWI_BUG		= 0x20,
+	/*
+	 * An SCB upload using the SCB channel's
+	 * auto array entry copy feature may 
+	 * corrupt data.  This appears to only
+	 * occur on 66MHz systems.
+	 */
+	AHC_SCBCHAN_UPLOAD_BUG	= 0x40
+} ahc_bug;
+
+/*
+ * Configuration specific settings.
+ * The driver determines these settings by probing the
+ * chip/controller's configuration.
+ */
+typedef enum {
+	AHC_FNONE	      = 0x000,
+	AHC_PRIMARY_CHANNEL   = 0x003,  /*
+					 * The channel that should
+					 * be probed first.
+					 */
+	AHC_USEDEFAULTS	      = 0x004,  /*
+					 * For cards without an seeprom
+					 * or a BIOS to initialize the chip's
+					 * SRAM, we use the default target
+					 * settings.
+					 */
+	AHC_SEQUENCER_DEBUG   = 0x008,
+	AHC_SHARED_SRAM	      = 0x010,
+	AHC_LARGE_SEEPROM     = 0x020,  /* Uses C56_66 not C46 */
+	AHC_RESET_BUS_A	      = 0x040,
+	AHC_RESET_BUS_B	      = 0x080,
+	AHC_EXTENDED_TRANS_A  = 0x100,
+	AHC_EXTENDED_TRANS_B  = 0x200,
+	AHC_TERM_ENB_A	      = 0x400,
+	AHC_TERM_ENB_B	      = 0x800,
+	AHC_INITIATORROLE     = 0x1000,  /*
+					  * Allow initiator operations on
+					  * this controller.
+					  */
+	AHC_TARGETROLE	      = 0x2000,  /*
+					  * Allow target operations on this
+					  * controller.
+					  */
+	AHC_NEWEEPROM_FMT     = 0x4000,
+	AHC_RESOURCE_SHORTAGE = 0x8000,
+	AHC_TQINFIFO_BLOCKED  = 0x10000,  /* Blocked waiting for ATIOs */
+	AHC_INT50_SPEEDFLEX   = 0x20000,  /*
+					   * Internal 50pin connector
+					   * sits behind an aic3860
+					   */
+	AHC_SCB_BTT	      = 0x40000,  /*
+					   * The busy targets table is
+					   * stored in SCB space rather
+					   * than SRAM.
+					   */
+	AHC_BIOS_ENABLED      = 0x80000,
+	AHC_ALL_INTERRUPTS    = 0x100000,
+	AHC_PAGESCBS	      = 0x400000,  /* Enable SCB paging */
+	AHC_EDGE_INTERRUPT    = 0x800000,  /* Device uses edge triggered ints */
+	AHC_39BIT_ADDRESSING  = 0x1000000, /* Use 39 bit addressing scheme. */
+	AHC_LSCBS_ENABLED     = 0x2000000, /* 64Byte SCBs enabled */
+	AHC_SCB_CONFIG_USED   = 0x4000000, /* No SEEPROM but SCB2 had info. */
+	AHC_NO_BIOS_INIT      = 0x8000000, /* No BIOS left over settings. */
+	AHC_DISABLE_PCI_PERR  = 0x10000000,
+	AHC_HAS_TERM_LOGIC    = 0x20000000
+} ahc_flag;
+
+/************************* Hardware  SCB Definition ***************************/
+
+/*
+ * The driver keeps up to MAX_SCB scb structures per card in memory.  The SCB
+ * consists of a "hardware SCB" mirroring the fields available on the card
+ * and additional information the kernel stores for each transaction.
+ *
+ * To minimize space utilization, a portion of the hardware scb stores
+ * different data during different portions of a SCSI transaction.
+ * As initialized by the host driver for the initiator role, this area
+ * contains the SCSI cdb (or a pointer to the  cdb) to be executed.  After
+ * the cdb has been presented to the target, this area serves to store
+ * residual transfer information and the SCSI status byte.
+ * For the target role, the contents of this area do not change, but
+ * still serve a different purpose than for the initiator role.  See
+ * struct target_data for details.
+ */
+
+/*
+ * Status information embedded in the shared poriton of
+ * an SCB after passing the cdb to the target.  The kernel
+ * driver will only read this data for transactions that
+ * complete abnormally (non-zero status byte).
+ */
+struct status_pkt {
+	uint32_t residual_datacnt;	/* Residual in the current S/G seg */
+	uint32_t residual_sg_ptr;	/* The next S/G for this transfer */
+	uint8_t	 scsi_status;		/* Standard SCSI status byte */
+};
+
+/*
+ * Target mode version of the shared data SCB segment.
+ */
+struct target_data {
+	uint32_t residual_datacnt;	/* Residual in the current S/G seg */
+	uint32_t residual_sg_ptr;	/* The next S/G for this transfer */
+	uint8_t  scsi_status;		/* SCSI status to give to initiator */
+	uint8_t  target_phases;		/* Bitmap of phases to execute */
+	uint8_t  data_phase;		/* Data-In or Data-Out */
+	uint8_t  initiator_tag;		/* Initiator's transaction tag */
+};
+
+struct hardware_scb {
+/*0*/	union {
+		/*
+		 * If the cdb is 12 bytes or less, we embed it directly
+		 * in the SCB.  For longer cdbs, we embed the address
+		 * of the cdb payload as seen by the chip and a DMA
+		 * is used to pull it in.
+		 */
+		uint8_t	 cdb[12];
+		uint32_t cdb_ptr;
+		struct	 status_pkt status;
+		struct	 target_data tdata;
+	} shared_data;
+/*
+ * A word about residuals.
+ * The scb is presented to the sequencer with the dataptr and datacnt
+ * fields initialized to the contents of the first S/G element to
+ * transfer.  The sgptr field is initialized to the bus address for
+ * the S/G element that follows the first in the in core S/G array
+ * or'ed with the SG_FULL_RESID flag.  Sgptr may point to an invalid
+ * S/G entry for this transfer (single S/G element transfer with the
+ * first elements address and length preloaded in the dataptr/datacnt
+ * fields).  If no transfer is to occur, sgptr is set to SG_LIST_NULL.
+ * The SG_FULL_RESID flag ensures that the residual will be correctly
+ * noted even if no data transfers occur.  Once the data phase is entered,
+ * the residual sgptr and datacnt are loaded from the sgptr and the
+ * datacnt fields.  After each S/G element's dataptr and length are
+ * loaded into the hardware, the residual sgptr is advanced.  After
+ * each S/G element is expired, its datacnt field is checked to see
+ * if the LAST_SEG flag is set.  If so, SG_LIST_NULL is set in the
+ * residual sg ptr and the transfer is considered complete.  If the
+ * sequencer determines that there is a residual in the tranfer, it
+ * will set the SG_RESID_VALID flag in sgptr and dma the scb back into
+ * host memory.  To sumarize:
+ *
+ * Sequencer:
+ *	o A residual has occurred if SG_FULL_RESID is set in sgptr,
+ *	  or residual_sgptr does not have SG_LIST_NULL set.
+ *
+ *	o We are transfering the last segment if residual_datacnt has
+ *	  the SG_LAST_SEG flag set.
+ *
+ * Host:
+ *	o A residual has occurred if a completed scb has the
+ *	  SG_RESID_VALID flag set.
+ *
+ *	o residual_sgptr and sgptr refer to the "next" sg entry
+ *	  and so may point beyond the last valid sg entry for the
+ *	  transfer.
+ */ 
+/*12*/	uint32_t dataptr;
+/*16*/	uint32_t datacnt;		/*
+					 * Byte 3 (numbered from 0) of
+					 * the datacnt is really the
+					 * 4th byte in that data address.
+					 */
+/*20*/	uint32_t sgptr;
+#define SG_PTR_MASK	0xFFFFFFF8
+/*24*/	uint8_t  control;	/* See SCB_CONTROL in aic7xxx.reg for details */
+/*25*/	uint8_t  scsiid;	/* what to load in the SCSIID register */
+/*26*/	uint8_t  lun;
+/*27*/	uint8_t  tag;			/*
+					 * Index into our kernel SCB array.
+					 * Also used as the tag for tagged I/O
+					 */
+/*28*/	uint8_t  cdb_len;
+/*29*/	uint8_t  scsirate;		/* Value for SCSIRATE register */
+/*30*/	uint8_t  scsioffset;		/* Value for SCSIOFFSET register */
+/*31*/	uint8_t  next;			/*
+					 * Used for threading SCBs in the
+					 * "Waiting for Selection" and
+					 * "Disconnected SCB" lists down
+					 * in the sequencer.
+					 */
+/*32*/	uint8_t  cdb32[32];		/*
+					 * CDB storage for cdbs of size
+					 * 13->32.  We store them here
+					 * because hardware scbs are
+					 * allocated from DMA safe
+					 * memory so we are guaranteed
+					 * the controller can access
+					 * this data.
+					 */
+};
+
+/************************ Kernel SCB Definitions ******************************/
+/*
+ * Some fields of the SCB are OS dependent.  Here we collect the
+ * definitions for elements that all OS platforms need to include
+ * in there SCB definition.
+ */
+
+/*
+ * Definition of a scatter/gather element as transfered to the controller.
+ * The aic7xxx chips only support a 24bit length.  We use the top byte of
+ * the length to store additional address bits and a flag to indicate
+ * that a given segment terminates the transfer.  This gives us an
+ * addressable range of 512GB on machines with 64bit PCI or with chips
+ * that can support dual address cycles on 32bit PCI busses.
+ */
+struct ahc_dma_seg {
+	uint32_t	addr;
+	uint32_t	len;
+#define	AHC_DMA_LAST_SEG	0x80000000
+#define	AHC_SG_HIGH_ADDR_MASK	0x7F000000
+#define	AHC_SG_LEN_MASK		0x00FFFFFF
+};
+
+struct sg_map_node {
+	bus_dmamap_t		 sg_dmamap;
+	dma_addr_t		 sg_physaddr;
+	struct ahc_dma_seg*	 sg_vaddr;
+	SLIST_ENTRY(sg_map_node) links;
+};
+
+/*
+ * The current state of this SCB.
+ */
+typedef enum {
+	SCB_FREE		= 0x0000,
+	SCB_OTHERTCL_TIMEOUT	= 0x0002,/*
+					  * Another device was active
+					  * during the first timeout for
+					  * this SCB so we gave ourselves
+					  * an additional timeout period
+					  * in case it was hogging the
+					  * bus.
+				          */
+	SCB_DEVICE_RESET	= 0x0004,
+	SCB_SENSE		= 0x0008,
+	SCB_CDB32_PTR		= 0x0010,
+	SCB_RECOVERY_SCB	= 0x0020,
+	SCB_AUTO_NEGOTIATE	= 0x0040,/* Negotiate to achieve goal. */
+	SCB_NEGOTIATE		= 0x0080,/* Negotiation forced for command. */
+	SCB_ABORT		= 0x0100,
+	SCB_UNTAGGEDQ		= 0x0200,
+	SCB_ACTIVE		= 0x0400,
+	SCB_TARGET_IMMEDIATE	= 0x0800,
+	SCB_TRANSMISSION_ERROR	= 0x1000,/*
+					  * We detected a parity or CRC
+					  * error that has effected the
+					  * payload of the command.  This
+					  * flag is checked when normal
+					  * status is returned to catch
+					  * the case of a target not
+					  * responding to our attempt
+					  * to report the error.
+					  */
+	SCB_TARGET_SCB		= 0x2000,
+	SCB_SILENT		= 0x4000 /*
+					  * Be quiet about transmission type
+					  * errors.  They are expected and we
+					  * don't want to upset the user.  This
+					  * flag is typically used during DV.
+					  */
+} scb_flag;
+
+struct scb {
+	struct	hardware_scb	 *hscb;
+	union {
+		SLIST_ENTRY(scb)  sle;
+		TAILQ_ENTRY(scb)  tqe;
+	} links;
+	LIST_ENTRY(scb)		  pending_links;
+	ahc_io_ctx_t		  io_ctx;
+	struct ahc_softc	 *ahc_softc;
+	scb_flag		  flags;
+#ifndef __linux__
+	bus_dmamap_t		  dmamap;
+#endif
+	struct scb_platform_data *platform_data;
+	struct sg_map_node	 *sg_map;
+	struct ahc_dma_seg 	 *sg_list;
+	dma_addr_t		  sg_list_phys;
+	u_int			  sg_count;/* How full ahc_dma_seg is */
+};
+
+struct scb_data {
+	SLIST_HEAD(, scb) free_scbs;	/*
+					 * Pool of SCBs ready to be assigned
+					 * commands to execute.
+					 */
+	struct	scb *scbindex[256];	/*
+					 * Mapping from tag to SCB.
+					 * As tag identifiers are an
+					 * 8bit value, we provide space
+					 * for all possible tag values.
+					 * Any lookups to entries at or
+					 * above AHC_SCB_MAX_ALLOC will
+					 * always fail.
+					 */
+	struct	hardware_scb	*hscbs;	/* Array of hardware SCBs */
+	struct	scb *scbarray;		/* Array of kernel SCBs */
+	struct	scsi_sense_data *sense; /* Per SCB sense data */
+
+	/*
+	 * "Bus" addresses of our data structures.
+	 */
+	bus_dma_tag_t	 hscb_dmat;	/* dmat for our hardware SCB array */
+	bus_dmamap_t	 hscb_dmamap;
+	dma_addr_t	 hscb_busaddr;
+	bus_dma_tag_t	 sense_dmat;
+	bus_dmamap_t	 sense_dmamap;
+	dma_addr_t	 sense_busaddr;
+	bus_dma_tag_t	 sg_dmat;	/* dmat for our sg segments */
+	SLIST_HEAD(, sg_map_node) sg_maps;
+	uint8_t	numscbs;
+	uint8_t	maxhscbs;		/* Number of SCBs on the card */
+	uint8_t	init_level;		/*
+					 * How far we've initialized
+					 * this structure.
+					 */
+};
+
+/************************ Target Mode Definitions *****************************/
+
+/*
+ * Connection desciptor for select-in requests in target mode.
+ */
+struct target_cmd {
+	uint8_t scsiid;		/* Our ID and the initiator's ID */
+	uint8_t identify;	/* Identify message */
+	uint8_t bytes[22];	/* 
+				 * Bytes contains any additional message
+				 * bytes terminated by 0xFF.  The remainder
+				 * is the cdb to execute.
+				 */
+	uint8_t cmd_valid;	/*
+				 * When a command is complete, the firmware
+				 * will set cmd_valid to all bits set.
+				 * After the host has seen the command,
+				 * the bits are cleared.  This allows us
+				 * to just peek at host memory to determine
+				 * if more work is complete. cmd_valid is on
+				 * an 8 byte boundary to simplify setting
+				 * it on aic7880 hardware which only has
+				 * limited direct access to the DMA FIFO.
+				 */
+	uint8_t pad[7];
+};
+
+/*
+ * Number of events we can buffer up if we run out
+ * of immediate notify ccbs.
+ */
+#define AHC_TMODE_EVENT_BUFFER_SIZE 8
+struct ahc_tmode_event {
+	uint8_t initiator_id;
+	uint8_t event_type;	/* MSG type or EVENT_TYPE_BUS_RESET */
+#define	EVENT_TYPE_BUS_RESET 0xFF
+	uint8_t event_arg;
+};
+
+/*
+ * Per enabled lun target mode state.
+ * As this state is directly influenced by the host OS'es target mode
+ * environment, we let the OS module define it.  Forward declare the
+ * structure here so we can store arrays of them, etc. in OS neutral
+ * data structures.
+ */
+#ifdef AHC_TARGET_MODE 
+struct ahc_tmode_lstate {
+	struct cam_path *path;
+	struct ccb_hdr_slist accept_tios;
+	struct ccb_hdr_slist immed_notifies;
+	struct ahc_tmode_event event_buffer[AHC_TMODE_EVENT_BUFFER_SIZE];
+	uint8_t event_r_idx;
+	uint8_t event_w_idx;
+};
+#else
+struct ahc_tmode_lstate;
+#endif
+
+/******************** Transfer Negotiation Datastructures *********************/
+#define AHC_TRANS_CUR		0x01	/* Modify current neogtiation status */
+#define AHC_TRANS_ACTIVE	0x03	/* Assume this target is on the bus */
+#define AHC_TRANS_GOAL		0x04	/* Modify negotiation goal */
+#define AHC_TRANS_USER		0x08	/* Modify user negotiation settings */
+
+#define AHC_WIDTH_UNKNOWN	0xFF
+#define AHC_PERIOD_UNKNOWN	0xFF
+#define AHC_OFFSET_UNKNOWN	0xFF
+#define AHC_PPR_OPTS_UNKNOWN	0xFF
+
+/*
+ * Transfer Negotiation Information.
+ */
+struct ahc_transinfo {
+	uint8_t protocol_version;	/* SCSI Revision level */
+	uint8_t transport_version;	/* SPI Revision level */
+	uint8_t width;			/* Bus width */
+	uint8_t period;			/* Sync rate factor */
+	uint8_t offset;			/* Sync offset */
+	uint8_t ppr_options;		/* Parallel Protocol Request options */
+};
+
+/*
+ * Per-initiator current, goal and user transfer negotiation information. */
+struct ahc_initiator_tinfo {
+	uint8_t scsirate;		/* Computed value for SCSIRATE reg */
+	struct ahc_transinfo curr;
+	struct ahc_transinfo goal;
+	struct ahc_transinfo user;
+};
+
+/*
+ * Per enabled target ID state.
+ * Pointers to lun target state as well as sync/wide negotiation information
+ * for each initiator<->target mapping.  For the initiator role we pretend
+ * that we are the target and the targets are the initiators since the
+ * negotiation is the same regardless of role.
+ */
+struct ahc_tmode_tstate {
+	struct ahc_tmode_lstate*	enabled_luns[AHC_NUM_LUNS];
+	struct ahc_initiator_tinfo	transinfo[AHC_NUM_TARGETS];
+
+	/*
+	 * Per initiator state bitmasks.
+	 */
+	uint16_t	 auto_negotiate;/* Auto Negotiation Required */
+	uint16_t	 ultraenb;	/* Using ultra sync rate  */
+	uint16_t	 discenable;	/* Disconnection allowed  */
+	uint16_t	 tagenable;	/* Tagged Queuing allowed */
+};
+
+/*
+ * Data structure for our table of allowed synchronous transfer rates.
+ */
+struct ahc_syncrate {
+	u_int sxfr_u2;	/* Value of the SXFR parameter for Ultra2+ Chips */
+	u_int sxfr;	/* Value of the SXFR parameter for <= Ultra Chips */
+#define		ULTRA_SXFR 0x100	/* Rate Requires Ultra Mode set */
+#define		ST_SXFR	   0x010	/* Rate Single Transition Only */
+#define		DT_SXFR	   0x040	/* Rate Double Transition Only */
+	uint8_t period; /* Period to send to SCSI target */
+	char *rate;
+};
+
+/* Safe and valid period for async negotiations. */
+#define	AHC_ASYNC_XFER_PERIOD 0x45
+#define	AHC_ULTRA2_XFER_PERIOD 0x0a
+
+/*
+ * Indexes into our table of syncronous transfer rates.
+ */
+#define AHC_SYNCRATE_DT		0
+#define AHC_SYNCRATE_ULTRA2	1
+#define AHC_SYNCRATE_ULTRA	3
+#define AHC_SYNCRATE_FAST	6
+#define AHC_SYNCRATE_MAX	AHC_SYNCRATE_DT
+#define	AHC_SYNCRATE_MIN	13
+
+/***************************** Lookup Tables **********************************/
+/*
+ * Phase -> name and message out response
+ * to parity errors in each phase table. 
+ */
+struct ahc_phase_table_entry {
+        uint8_t phase;
+        uint8_t mesg_out; /* Message response to parity errors */
+	char *phasemsg;
+};
+
+/************************** Serial EEPROM Format ******************************/
+
+struct seeprom_config {
+/*
+ * Per SCSI ID Configuration Flags
+ */
+	uint16_t device_flags[16];	/* words 0-15 */
+#define		CFXFER		0x0007	/* synchronous transfer rate */
+#define		CFSYNCH		0x0008	/* enable synchronous transfer */
+#define		CFDISC		0x0010	/* enable disconnection */
+#define		CFWIDEB		0x0020	/* wide bus device */
+#define		CFSYNCHISULTRA	0x0040	/* CFSYNCH is an ultra offset (2940AU)*/
+#define		CFSYNCSINGLE	0x0080	/* Single-Transition signalling */
+#define		CFSTART		0x0100	/* send start unit SCSI command */
+#define		CFINCBIOS	0x0200	/* include in BIOS scan */
+#define		CFRNFOUND	0x0400	/* report even if not found */
+#define		CFMULTILUNDEV	0x0800	/* Probe multiple luns in BIOS scan */
+#define		CFWBCACHEENB	0x4000	/* Enable W-Behind Cache on disks */
+#define		CFWBCACHENOP	0xc000	/* Don't touch W-Behind Cache */
+
+/*
+ * BIOS Control Bits
+ */
+	uint16_t bios_control;		/* word 16 */
+#define		CFSUPREM	0x0001	/* support all removeable drives */
+#define		CFSUPREMB	0x0002	/* support removeable boot drives */
+#define		CFBIOSEN	0x0004	/* BIOS enabled */
+#define		CFBIOS_BUSSCAN	0x0008	/* Have the BIOS Scan the Bus */
+#define		CFSM2DRV	0x0010	/* support more than two drives */
+#define		CFSTPWLEVEL	0x0010	/* Termination level control */
+#define		CF284XEXTEND	0x0020	/* extended translation (284x cards) */	
+#define		CFCTRL_A	0x0020	/* BIOS displays Ctrl-A message */	
+#define		CFTERM_MENU	0x0040	/* BIOS displays termination menu */	
+#define		CFEXTEND	0x0080	/* extended translation enabled */
+#define		CFSCAMEN	0x0100	/* SCAM enable */
+#define		CFMSG_LEVEL	0x0600	/* BIOS Message Level */
+#define			CFMSG_VERBOSE	0x0000
+#define			CFMSG_SILENT	0x0200
+#define			CFMSG_DIAG	0x0400
+#define		CFBOOTCD	0x0800  /* Support Bootable CD-ROM */
+/*		UNUSED		0xff00	*/
+
+/*
+ * Host Adapter Control Bits
+ */
+	uint16_t adapter_control;	/* word 17 */	
+#define		CFAUTOTERM	0x0001	/* Perform Auto termination */
+#define		CFULTRAEN	0x0002	/* Ultra SCSI speed enable */
+#define		CF284XSELTO     0x0003	/* Selection timeout (284x cards) */
+#define		CF284XFIFO      0x000C	/* FIFO Threshold (284x cards) */
+#define		CFSTERM		0x0004	/* SCSI low byte termination */
+#define		CFWSTERM	0x0008	/* SCSI high byte termination */
+#define		CFSPARITY	0x0010	/* SCSI parity */
+#define		CF284XSTERM     0x0020	/* SCSI low byte term (284x cards) */	
+#define		CFMULTILUN	0x0020
+#define		CFRESETB	0x0040	/* reset SCSI bus at boot */
+#define		CFCLUSTERENB	0x0080	/* Cluster Enable */
+#define		CFBOOTCHAN	0x0300	/* probe this channel first */
+#define		CFBOOTCHANSHIFT 8
+#define		CFSEAUTOTERM	0x0400	/* Ultra2 Perform secondary Auto Term*/
+#define		CFSELOWTERM	0x0800	/* Ultra2 secondary low term */
+#define		CFSEHIGHTERM	0x1000	/* Ultra2 secondary high term */
+#define		CFENABLEDV	0x4000	/* Perform Domain Validation*/
+
+/*
+ * Bus Release Time, Host Adapter ID
+ */
+	uint16_t brtime_id;		/* word 18 */
+#define		CFSCSIID	0x000f	/* host adapter SCSI ID */
+/*		UNUSED		0x00f0	*/
+#define		CFBRTIME	0xff00	/* bus release time */
+
+/*
+ * Maximum targets
+ */
+	uint16_t max_targets;		/* word 19 */	
+#define		CFMAXTARG	0x00ff	/* maximum targets */
+#define		CFBOOTLUN	0x0f00	/* Lun to boot from */
+#define		CFBOOTID	0xf000	/* Target to boot from */
+	uint16_t res_1[10];		/* words 20-29 */
+	uint16_t signature;		/* Signature == 0x250 */
+#define		CFSIGNATURE	0x250
+#define		CFSIGNATURE2	0x300
+	uint16_t checksum;		/* word 31 */
+};
+
+/****************************  Message Buffer *********************************/
+typedef enum {
+	MSG_TYPE_NONE			= 0x00,
+	MSG_TYPE_INITIATOR_MSGOUT	= 0x01,
+	MSG_TYPE_INITIATOR_MSGIN	= 0x02,
+	MSG_TYPE_TARGET_MSGOUT		= 0x03,
+	MSG_TYPE_TARGET_MSGIN		= 0x04
+} ahc_msg_type;
+
+typedef enum {
+	MSGLOOP_IN_PROG,
+	MSGLOOP_MSGCOMPLETE,
+	MSGLOOP_TERMINATED
+} msg_loop_stat;
+
+/*********************** Software Configuration Structure *********************/
+TAILQ_HEAD(scb_tailq, scb);
+
+struct ahc_aic7770_softc {
+	/*
+	 * Saved register state used for chip_init().
+	 */
+	uint8_t busspd;
+	uint8_t bustime;
+};
+
+struct ahc_pci_softc {
+	/*
+	 * Saved register state used for chip_init().
+	 */
+	uint32_t  devconfig;
+	uint16_t  targcrccnt;
+	uint8_t   command;
+	uint8_t   csize_lattime;
+	uint8_t   optionmode;
+	uint8_t   crccontrol1;
+	uint8_t   dscommand0;
+	uint8_t   dspcistatus;
+	uint8_t   scbbaddr;
+	uint8_t   dff_thrsh;
+};
+
+union ahc_bus_softc {
+	struct ahc_aic7770_softc aic7770_softc;
+	struct ahc_pci_softc pci_softc;
+};
+
+typedef void (*ahc_bus_intr_t)(struct ahc_softc *);
+typedef int (*ahc_bus_chip_init_t)(struct ahc_softc *);
+typedef int (*ahc_bus_suspend_t)(struct ahc_softc *);
+typedef int (*ahc_bus_resume_t)(struct ahc_softc *);
+typedef void ahc_callback_t (void *);
+
+struct ahc_softc {
+	bus_space_tag_t           tag;
+	bus_space_handle_t        bsh;
+#ifndef __linux__
+	bus_dma_tag_t		  buffer_dmat;   /* dmat for buffer I/O */
+#endif
+	struct scb_data		 *scb_data;
+
+	struct scb		 *next_queued_scb;
+
+	/*
+	 * SCBs that have been sent to the controller
+	 */
+	LIST_HEAD(, scb)	  pending_scbs;
+
+	/*
+	 * Counting lock for deferring the release of additional
+	 * untagged transactions from the untagged_queues.  When
+	 * the lock is decremented to 0, all queues in the
+	 * untagged_queues array are run.
+	 */
+	u_int			  untagged_queue_lock;
+
+	/*
+	 * Per-target queue of untagged-transactions.  The
+	 * transaction at the head of the queue is the
+	 * currently pending untagged transaction for the
+	 * target.  The driver only allows a single untagged
+	 * transaction per target.
+	 */
+	struct scb_tailq	  untagged_queues[AHC_NUM_TARGETS];
+
+	/*
+	 * Bus attachment specific data.
+	 */
+	union ahc_bus_softc	  bus_softc;
+
+	/*
+	 * Platform specific data.
+	 */
+	struct ahc_platform_data *platform_data;
+
+	/*
+	 * Platform specific device information.
+	 */
+	ahc_dev_softc_t		  dev_softc;
+
+	/*
+	 * Bus specific device information.
+	 */
+	ahc_bus_intr_t		  bus_intr;
+
+	/*
+	 * Bus specific initialization required
+	 * after a chip reset.
+	 */
+	ahc_bus_chip_init_t	  bus_chip_init;
+
+	/*
+	 * Bus specific suspend routine.
+	 */
+	ahc_bus_suspend_t	  bus_suspend;
+
+	/*
+	 * Bus specific resume routine.
+	 */
+	ahc_bus_resume_t	  bus_resume;
+
+	/*
+	 * Target mode related state kept on a per enabled lun basis.
+	 * Targets that are not enabled will have null entries.
+	 * As an initiator, we keep one target entry for our initiator
+	 * ID to store our sync/wide transfer settings.
+	 */
+	struct ahc_tmode_tstate  *enabled_targets[AHC_NUM_TARGETS];
+
+	/*
+	 * The black hole device responsible for handling requests for
+	 * disabled luns on enabled targets.
+	 */
+	struct ahc_tmode_lstate  *black_hole;
+
+	/*
+	 * Device instance currently on the bus awaiting a continue TIO
+	 * for a command that was not given the disconnect priveledge.
+	 */
+	struct ahc_tmode_lstate  *pending_device;
+
+	/*
+	 * Card characteristics
+	 */
+	ahc_chip		  chip;
+	ahc_feature		  features;
+	ahc_bug			  bugs;
+	ahc_flag		  flags;
+	struct seeprom_config	 *seep_config;
+
+	/* Values to store in the SEQCTL register for pause and unpause */
+	uint8_t			  unpause;
+	uint8_t			  pause;
+
+	/* Command Queues */
+	uint8_t			  qoutfifonext;
+	uint8_t			  qinfifonext;
+	uint8_t			 *qoutfifo;
+	uint8_t			 *qinfifo;
+
+	/* Critical Section Data */
+	struct cs		 *critical_sections;
+	u_int			  num_critical_sections;
+
+	/* Links for chaining softcs */
+	TAILQ_ENTRY(ahc_softc)	  links;
+
+	/* Channel Names ('A', 'B', etc.) */
+	char			  channel;
+	char			  channel_b;
+
+	/* Initiator Bus ID */
+	uint8_t			  our_id;
+	uint8_t			  our_id_b;
+
+	/*
+	 * PCI error detection.
+	 */
+	int			  unsolicited_ints;
+
+	/*
+	 * Target incoming command FIFO.
+	 */
+	struct target_cmd	 *targetcmds;
+	uint8_t			  tqinfifonext;
+
+	/*
+	 * Cached copy of the sequencer control register.
+	 */
+	uint8_t			  seqctl;
+
+	/*
+	 * Incoming and outgoing message handling.
+	 */
+	uint8_t			  send_msg_perror;
+	ahc_msg_type		  msg_type;
+	uint8_t			  msgout_buf[12];/* Message we are sending */
+	uint8_t			  msgin_buf[12];/* Message we are receiving */
+	u_int			  msgout_len;	/* Length of message to send */
+	u_int			  msgout_index;	/* Current index in msgout */
+	u_int			  msgin_index;	/* Current index in msgin */
+
+	/*
+	 * Mapping information for data structures shared
+	 * between the sequencer and kernel.
+	 */
+	bus_dma_tag_t		  parent_dmat;
+	bus_dma_tag_t		  shared_data_dmat;
+	bus_dmamap_t		  shared_data_dmamap;
+	dma_addr_t		  shared_data_busaddr;
+
+	/*
+	 * Bus address of the one byte buffer used to
+	 * work-around a DMA bug for chips <= aic7880
+	 * in target mode.
+	 */
+	dma_addr_t		  dma_bug_buf;
+
+	/* Number of enabled target mode device on this card */
+	u_int			  enabled_luns;
+
+	/* Initialization level of this data structure */
+	u_int			  init_level;
+
+	/* PCI cacheline size. */
+	u_int			  pci_cachesize;
+
+	/*
+	 * Count of parity errors we have seen as a target.
+	 * We auto-disable parity error checking after seeing
+	 * AHC_PCI_TARGET_PERR_THRESH number of errors.
+	 */
+	u_int			  pci_target_perr_count;
+#define		AHC_PCI_TARGET_PERR_THRESH	10
+
+	/* Maximum number of sequencer instructions supported. */
+	u_int			  instruction_ram_size;
+
+	/* Per-Unit descriptive information */
+	const char		 *description;
+	char			 *name;
+	int			  unit;
+
+	/* Selection Timer settings */
+	int			  seltime;
+	int			  seltime_b;
+
+	uint16_t	 	  user_discenable;/* Disconnection allowed  */
+	uint16_t		  user_tagenable;/* Tagged Queuing allowed */
+};
+
+TAILQ_HEAD(ahc_softc_tailq, ahc_softc);
+extern struct ahc_softc_tailq ahc_tailq;
+
+/************************ Active Device Information ***************************/
+typedef enum {
+	ROLE_UNKNOWN,
+	ROLE_INITIATOR,
+	ROLE_TARGET
+} role_t;
+
+struct ahc_devinfo {
+	int	 our_scsiid;
+	int	 target_offset;
+	uint16_t target_mask;
+	u_int	 target;
+	u_int	 lun;
+	char	 channel;
+	role_t	 role;		/*
+				 * Only guaranteed to be correct if not
+				 * in the busfree state.
+				 */
+};
+
+/****************************** PCI Structures ********************************/
+typedef int (ahc_device_setup_t)(struct ahc_softc *);
+
+struct ahc_pci_identity {
+	uint64_t		 full_id;
+	uint64_t		 id_mask;
+	char			*name;
+	ahc_device_setup_t	*setup;
+};
+extern struct ahc_pci_identity ahc_pci_ident_table[];
+extern const u_int ahc_num_pci_devs;
+
+/***************************** VL/EISA Declarations ***************************/
+struct aic7770_identity {
+	uint32_t		 full_id;
+	uint32_t		 id_mask;
+	const char		*name;
+	ahc_device_setup_t	*setup;
+};
+extern struct aic7770_identity aic7770_ident_table[];
+extern const int ahc_num_aic7770_devs;
+
+#define AHC_EISA_SLOT_OFFSET	0xc00
+#define AHC_EISA_IOSIZE		0x100
+
+/*************************** Function Declarations ****************************/
+/******************************************************************************/
+u_int			ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl);
+void			ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl);
+void			ahc_busy_tcl(struct ahc_softc *ahc,
+				     u_int tcl, u_int busyid);
+
+/***************************** PCI Front End *********************************/
+struct ahc_pci_identity	*ahc_find_pci_device(ahc_dev_softc_t);
+int			 ahc_pci_config(struct ahc_softc *,
+					struct ahc_pci_identity *);
+int			 ahc_pci_test_register_access(struct ahc_softc *);
+
+/*************************** EISA/VL Front End ********************************/
+struct aic7770_identity *aic7770_find_device(uint32_t);
+int			 aic7770_config(struct ahc_softc *ahc,
+					struct aic7770_identity *,
+					u_int port);
+
+/************************** SCB and SCB queue management **********************/
+int		ahc_probe_scbs(struct ahc_softc *);
+void		ahc_run_untagged_queues(struct ahc_softc *ahc);
+void		ahc_run_untagged_queue(struct ahc_softc *ahc,
+				       struct scb_tailq *queue);
+void		ahc_qinfifo_requeue_tail(struct ahc_softc *ahc,
+					 struct scb *scb);
+int		ahc_match_scb(struct ahc_softc *ahc, struct scb *scb,
+			      int target, char channel, int lun,
+			      u_int tag, role_t role);
+
+/****************************** Initialization ********************************/
+struct ahc_softc	*ahc_alloc(void *platform_arg, char *name);
+int			 ahc_softc_init(struct ahc_softc *);
+void			 ahc_controller_info(struct ahc_softc *ahc, char *buf);
+int			 ahc_chip_init(struct ahc_softc *ahc);
+int			 ahc_init(struct ahc_softc *ahc);
+void			 ahc_intr_enable(struct ahc_softc *ahc, int enable);
+void			 ahc_pause_and_flushwork(struct ahc_softc *ahc);
+int			 ahc_suspend(struct ahc_softc *ahc); 
+int			 ahc_resume(struct ahc_softc *ahc);
+void			 ahc_softc_insert(struct ahc_softc *);
+struct ahc_softc	*ahc_find_softc(struct ahc_softc *ahc);
+void			 ahc_set_unit(struct ahc_softc *, int);
+void			 ahc_set_name(struct ahc_softc *, char *);
+void			 ahc_alloc_scbs(struct ahc_softc *ahc);
+void			 ahc_free(struct ahc_softc *ahc);
+int			 ahc_reset(struct ahc_softc *ahc, int reinit);
+void			 ahc_shutdown(void *arg);
+
+/*************************** Interrupt Services *******************************/
+void			ahc_clear_intstat(struct ahc_softc *ahc);
+void			ahc_run_qoutfifo(struct ahc_softc *ahc);
+#ifdef AHC_TARGET_MODE
+void			ahc_run_tqinfifo(struct ahc_softc *ahc, int paused);
+#endif
+void			ahc_handle_brkadrint(struct ahc_softc *ahc);
+void			ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat);
+void			ahc_handle_scsiint(struct ahc_softc *ahc,
+					   u_int intstat);
+void			ahc_clear_critical_section(struct ahc_softc *ahc);
+
+/***************************** Error Recovery *********************************/
+typedef enum {
+	SEARCH_COMPLETE,
+	SEARCH_COUNT,
+	SEARCH_REMOVE
+} ahc_search_action;
+int			ahc_search_qinfifo(struct ahc_softc *ahc, int target,
+					   char channel, int lun, u_int tag,
+					   role_t role, uint32_t status,
+					   ahc_search_action action);
+int			ahc_search_untagged_queues(struct ahc_softc *ahc,
+						   ahc_io_ctx_t ctx,
+						   int target, char channel,
+						   int lun, uint32_t status,
+						   ahc_search_action action);
+int			ahc_search_disc_list(struct ahc_softc *ahc, int target,
+					     char channel, int lun, u_int tag,
+					     int stop_on_first, int remove,
+					     int save_state);
+void			ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
+int			ahc_reset_channel(struct ahc_softc *ahc, char channel,
+					  int initiate_reset);
+int			ahc_abort_scbs(struct ahc_softc *ahc, int target,
+				       char channel, int lun, u_int tag,
+				       role_t role, uint32_t status);
+void			ahc_restart(struct ahc_softc *ahc);
+void			ahc_calc_residual(struct ahc_softc *ahc,
+					  struct scb *scb);
+/*************************** Utility Functions ********************************/
+struct ahc_phase_table_entry*
+			ahc_lookup_phase_entry(int phase);
+void			ahc_compile_devinfo(struct ahc_devinfo *devinfo,
+					    u_int our_id, u_int target,
+					    u_int lun, char channel,
+					    role_t role);
+/************************** Transfer Negotiation ******************************/
+struct ahc_syncrate*	ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+					  u_int *ppr_options, u_int maxsync);
+u_int			ahc_find_period(struct ahc_softc *ahc,
+					u_int scsirate, u_int maxsync);
+void			ahc_validate_offset(struct ahc_softc *ahc,
+					    struct ahc_initiator_tinfo *tinfo,
+					    struct ahc_syncrate *syncrate,
+					    u_int *offset, int wide,
+					    role_t role);
+void			ahc_validate_width(struct ahc_softc *ahc,
+					   struct ahc_initiator_tinfo *tinfo,
+					   u_int *bus_width,
+					   role_t role);
+/*
+ * Negotiation types.  These are used to qualify if we should renegotiate
+ * even if our goal and current transport parameters are identical.
+ */
+typedef enum {
+	AHC_NEG_TO_GOAL,	/* Renegotiate only if goal and curr differ. */
+	AHC_NEG_IF_NON_ASYNC,	/* Renegotiate so long as goal is non-async. */
+	AHC_NEG_ALWAYS		/* Renegotiat even if goal is async. */
+} ahc_neg_type;
+int			ahc_update_neg_request(struct ahc_softc*,
+					       struct ahc_devinfo*,
+					       struct ahc_tmode_tstate*,
+					       struct ahc_initiator_tinfo*,
+					       ahc_neg_type);
+void			ahc_set_width(struct ahc_softc *ahc,
+				      struct ahc_devinfo *devinfo,
+				      u_int width, u_int type, int paused);
+void			ahc_set_syncrate(struct ahc_softc *ahc,
+					 struct ahc_devinfo *devinfo,
+					 struct ahc_syncrate *syncrate,
+					 u_int period, u_int offset,
+					 u_int ppr_options,
+					 u_int type, int paused);
+typedef enum {
+	AHC_QUEUE_NONE,
+	AHC_QUEUE_BASIC,
+	AHC_QUEUE_TAGGED
+} ahc_queue_alg;
+
+void			ahc_set_tags(struct ahc_softc *ahc,
+				     struct ahc_devinfo *devinfo,
+				     ahc_queue_alg alg);
+
+/**************************** Target Mode *************************************/
+#ifdef AHC_TARGET_MODE
+void		ahc_send_lstate_events(struct ahc_softc *,
+				       struct ahc_tmode_lstate *);
+void		ahc_handle_en_lun(struct ahc_softc *ahc,
+				  struct cam_sim *sim, union ccb *ccb);
+cam_status	ahc_find_tmode_devs(struct ahc_softc *ahc,
+				    struct cam_sim *sim, union ccb *ccb,
+				    struct ahc_tmode_tstate **tstate,
+				    struct ahc_tmode_lstate **lstate,
+				    int notfound_failure);
+#ifndef AHC_TMODE_ENABLE
+#define AHC_TMODE_ENABLE 0
+#endif
+#endif
+/******************************* Debug ***************************************/
+#ifdef AHC_DEBUG
+extern uint32_t ahc_debug;
+#define	AHC_SHOW_MISC		0x0001
+#define	AHC_SHOW_SENSE		0x0002
+#define AHC_DUMP_SEEPROM	0x0004
+#define AHC_SHOW_TERMCTL	0x0008
+#define AHC_SHOW_MEMORY		0x0010
+#define AHC_SHOW_MESSAGES	0x0020
+#define	AHC_SHOW_DV		0x0040
+#define AHC_SHOW_SELTO		0x0080
+#define AHC_SHOW_QFULL		0x0200
+#define AHC_SHOW_QUEUE		0x0400
+#define AHC_SHOW_TQIN		0x0800
+#define AHC_SHOW_MASKED_ERRORS	0x1000
+#define AHC_DEBUG_SEQUENCER	0x2000
+#endif
+void			ahc_print_scb(struct scb *scb);
+void			ahc_print_devinfo(struct ahc_softc *ahc,
+					  struct ahc_devinfo *dev);
+void			ahc_dump_card_state(struct ahc_softc *ahc);
+int			ahc_print_register(ahc_reg_parse_entry_t *table,
+					   u_int num_entries,
+					   const char *name,
+					   u_int address,
+					   u_int value,
+					   u_int *cur_column,
+					   u_int wrap_point);
+/******************************* SEEPROM *************************************/
+int		ahc_acquire_seeprom(struct ahc_softc *ahc,
+				    struct seeprom_descriptor *sd);
+void		ahc_release_seeprom(struct seeprom_descriptor *sd);
+#endif /* _AIC7XXX_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg
new file mode 100644
index 0000000..810ec70
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx.reg
@@ -0,0 +1,1594 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $"
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+	address			0x000
+	access_mode RW
+	field	TEMODE		0x80
+	field	ENSELO		0x40
+	field	ENSELI		0x20
+	field	ENRSELI		0x10
+	field	ENAUTOATNO	0x08
+	field	ENAUTOATNI	0x04
+	field	ENAUTOATNP	0x02
+	field	SCSIRSTO	0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+	address			0x001
+	access_mode RW
+	field	DFON		0x80
+	field	DFPEXP		0x40
+	field	FAST20		0x20
+	field	CLRSTCNT	0x10
+	field	SPIOEN		0x08
+	field	SCAMEN		0x04
+	field	CLRCHN		0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+	address			0x002
+	access_mode RW
+	field	BITBUCKET	0x80
+	field	SWRAPEN		0x40
+	field	ENSPCHK		0x20
+	mask	STIMESEL	0x18
+	field	ENSTIMER	0x04
+	field	ACTNEGEN	0x02
+	field	STPWEN		0x01	/* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+	address			0x003
+	access_mode RO
+	field	CDI		0x80
+	field	IOI		0x40
+	field	MSGI		0x20
+	field	ATNI		0x10
+	field	SELI		0x08
+	field	BSYI		0x04
+	field	REQI		0x02
+	field	ACKI		0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_DATAOUT_DT	P_DATAOUT|MSGI
+	mask	P_DATAIN_DT	P_DATAIN|MSGI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+	address			0x003
+	access_mode WO
+	field	CDO		0x80
+	field	IOO		0x40
+	field	MSGO		0x20
+	field	ATNO		0x10
+	field	SELO		0x08
+	field	BSYO		0x04
+	field	REQO		0x02
+	field	ACKO		0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+	address			0x004
+	access_mode RW
+	field	WIDEXFER	0x80		/* Wide transfer control */
+	field	ENABLE_CRC	0x40		/* CRC for D-Phases */
+	field	SINGLE_EDGE	0x10		/* Disable DT Transfers */
+	mask	SXFR		0x70		/* Sync transfer rate */
+	mask	SXFR_ULTRA2	0x0f		/* Sync transfer rate */
+	mask	SOFS		0x0f		/* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID	{
+	address			0x005
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	TWIN_TID	0x70
+	field	TWIN_CHNLB	0x80
+	mask	OID		0x0f		/* Our ID mask */
+	/*
+	 * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
+	 * The aic7890/91 allow an offset of up to 127 transfers in both wide
+	 * and narrow mode.
+	 */
+	alias	SCSIOFFSET
+	mask	SOFS_ULTRA2	0x7f		/* Sync offset U2 chips */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+	address			0x006
+	access_mode RW
+}
+
+register SCSIDATH {
+	address			0x007
+	access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transferred.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+register STCNT {
+	address			0x008
+	size	3
+	access_mode RW
+}
+
+/* ALT_MODE registers (Ultra2 and Ultra160 chips) */
+register SXFRCTL2 {
+	address			0x013
+	access_mode RW
+	field	AUTORSTDIS	0x10
+	field	CMDDMAEN	0x08
+	mask	ASYNC_SETUP	0x07
+}
+
+/* ALT_MODE register on Ultra160 chips */
+register OPTIONMODE {
+	address			0x008
+	access_mode RW
+	field	AUTORATEEN		0x80
+	field	AUTOACKEN		0x40
+	field	ATNMGMNTEN		0x20
+	field	BUSFREEREV		0x10
+	field	EXPPHASEDIS		0x08
+	field	SCSIDATL_IMGEN		0x04
+	field	AUTO_MSGOUT_DE		0x02
+	field	DIS_MSGIN_DUALEDGE	0x01
+	mask	OPTIONMODE_DEFAULTS	AUTO_MSGOUT_DE|DIS_MSGIN_DUALEDGE
+}
+
+/* ALT_MODE register on Ultra160 chips */
+register TARGCRCCNT {
+	address			0x00a
+	size	2
+	access_mode RW
+}
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+	address			0x00b
+	access_mode WO
+	field	CLRSELDO	0x40
+	field	CLRSELDI	0x20
+	field	CLRSELINGO	0x10
+	field	CLRSWRAP	0x08
+	field	CLRIOERR	0x08	/* Ultra2 Only */
+	field	CLRSPIORDY	0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0	{
+	address			0x00b
+	access_mode RO
+	field	TARGET		0x80	/* Board acting as target */
+	field	SELDO		0x40	/* Selection Done */
+	field	SELDI		0x20	/* Board has been selected */
+	field	SELINGO		0x10	/* Selection In Progress */
+	field	SWRAP		0x08	/* 24bit counter wrap */
+	field	IOERR		0x08	/* LVD Tranceiver mode changed */
+	field	SDONE		0x04	/* STCNT = 0x000000 */
+	field	SPIORDY		0x02	/* SCSI PIO Ready */
+	field	DMADONE		0x01	/* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+	address			0x00c
+	access_mode WO
+	field	CLRSELTIMEO	0x80
+	field	CLRATNO		0x40
+	field	CLRSCSIRSTI	0x20
+	field	CLRBUSFREE	0x08
+	field	CLRSCSIPERR	0x04
+	field	CLRPHASECHG	0x02
+	field	CLRREQINIT	0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1	{
+	address			0x00c
+	access_mode RO
+	field	SELTO		0x80
+	field	ATNTARG 	0x40
+	field	SCSIRSTI	0x20
+	field	PHASEMIS	0x10
+	field	BUSFREE		0x08
+	field	SCSIPERR	0x04
+	field	PHASECHG	0x02
+	field	REQINIT		0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+	address			0x00d
+	access_mode RO
+	field	OVERRUN		0x80
+	field	SHVALID		0x40	/* Shaddow Layer non-zero */
+	field	EXP_ACTIVE	0x10	/* SCSI Expander Active */
+	field	CRCVALERR	0x08	/* CRC doesn't match (U3 only) */
+	field	CRCENDERR	0x04	/* No terminal CRC packet (U3 only) */
+	field	CRCREQERR	0x02	/* Illegal CRC packet req (U3 only) */
+	field	DUAL_EDGE_ERR	0x01	/* Incorrect data phase (U3 only) */
+	mask	SFCNT		0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+	address			0x00e
+	access_mode RO
+	mask	SCSICNT		0xf0
+	mask	OFFCNT		0x0f
+	mask	U2OFFCNT	0x7f
+}
+
+/*
+ * SCSI ID for the aic7890/91 chips
+ */
+register SCSIID_ULTRA2 {
+	address			0x00f
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+	address			0x010
+	access_mode RW
+	field	ENSELDO		0x40
+	field	ENSELDI		0x20
+	field	ENSELINGO	0x10
+	field	ENSWRAP		0x08
+	field	ENIOERR		0x08	/* LVD Tranceiver mode changes */
+	field	ENSDONE		0x04
+	field	ENSPIORDY	0x02
+	field	ENDMADONE	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+	address			0x011
+	access_mode RW
+	field	ENSELTIMO	0x80
+	field	ENATNTARG	0x40
+	field	ENSCSIRST	0x20
+	field	ENPHASEMIS	0x10
+	field	ENBUSFREE	0x08
+	field	ENSCSIPERR	0x04
+	field	ENPHASECHG	0x02
+	field	ENREQINIT	0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+	address			0x012
+	access_mode RW
+}
+
+register SCSIBUSH {
+	address			0x013
+	access_mode RW
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+	address			0x014
+	size	4
+	access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+	address			0x018
+	access_mode RW
+	field	STAGE6		0x20
+	field	STAGE5		0x10
+	field	STAGE4		0x08
+	field	STAGE3		0x04
+	field	STAGE2		0x02
+	field	STAGE1		0x01
+	alias	TARGIDIN
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+	address			0x019
+	access_mode RW
+	mask	SELID_MASK	0xf0
+	field	ONEBIT		0x08
+}
+
+register SCAMCTL {
+	address			0x01a
+	access_mode RW
+	field	ENSCAMSELO	0x80
+	field	CLRSCAMSELID	0x40
+	field	ALTSTIM		0x20
+	field	DFLTTID		0x10
+	mask	SCAMLVL		0x03
+}
+
+/*
+ * Target Mode Selecting in ID bitmask (aic7890/91/96/97)
+ */
+register TARGID {
+	address			0x01b
+	size			2
+	access_mode RW
+}
+
+/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+	address			0x01b
+	access_mode RW
+	field	SOFT1		0x80
+	field	SOFT0		0x40
+	field	SOFTCMDEN	0x20	
+	field	EXT_BRDCTL	0x10	/* External Board control */
+	field	SEEPROM		0x08	/* External serial eeprom logic */
+	field	EEPROM		0x04	/* Writable external BIOS ROM */
+	field	ROM		0x02	/* Logic for accessing external ROM */
+	field	SSPIOCPS	0x01	/* Termination and cable detection */
+}
+
+register BRDCTL	{
+	address			0x01d
+	field	BRDDAT7		0x80
+	field	BRDDAT6		0x40
+	field	BRDDAT5		0x20
+	field	BRDSTB		0x10
+	field	BRDCS		0x08
+	field	BRDRW		0x04
+	field	BRDCTL1		0x02
+	field	BRDCTL0		0x01
+	/* 7890 Definitions */
+	field	BRDDAT4		0x10
+	field	BRDDAT3		0x08
+	field	BRDDAT2		0x04
+	field	BRDRW_ULTRA2	0x02
+	field	BRDSTB_ULTRA2	0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+	address			0x01e
+	field	EXTARBACK	0x80
+	field	EXTARBREQ	0x40
+	field	SEEMS		0x20
+	field	SEERDY		0x10
+	field	SEECS		0x08
+	field	SEECK		0x04
+	field	SEEDO		0x02
+	field	SEEDI		0x01
+}
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+	address			0x01f
+	access_mode RW
+	field	DIAGLEDEN	0x80	/* Aic78X0 only */
+	field	DIAGLEDON	0x40	/* Aic78X0 only */
+	field	AUTOFLUSHDIS	0x20
+	field	SELBUSB		0x08
+	field	ENAB40		0x08	/* LVD transceiver active */
+	field	ENAB20		0x04	/* SE/HVD transceiver active */
+	field	SELWIDE		0x02
+	field	XCVR		0x01	/* External transceiver active */
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+	address			0x060
+	access_mode RW
+	field	PERRORDIS	0x80
+	field	PAUSEDIS	0x40
+	field	FAILDIS		0x20
+	field	FASTMODE	0x10
+	field	BRKADRINTEN	0x08
+	field	STEP		0x04
+	field	SEQRESET	0x02
+	field	LOADRAM		0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in succession.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+	address			0x061
+	access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+	address			0x062
+	access_mode RW
+}
+
+register SEQADDR1 {
+	address			0x063
+	access_mode RW
+	mask	SEQADDR1_MASK	0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+	address			0x064
+	access_mode RW
+	accumulator
+}
+
+register SINDEX	{
+	address			0x065
+	access_mode RW
+	sindex
+}
+
+register DINDEX {
+	address			0x066
+	access_mode RW
+}
+
+register ALLONES {
+	address			0x069
+	access_mode RO
+	allones
+}
+
+register ALLZEROS {
+	address			0x06a
+	access_mode RO
+	allzeros
+}
+
+register NONE {
+	address			0x06a
+	access_mode WO
+	none
+}
+
+register FLAGS {
+	address			0x06b
+	access_mode RO
+	field	ZERO		0x02
+	field	CARRY		0x01
+}
+
+register SINDIR	{
+	address			0x06c
+	access_mode RO
+}
+
+register DINDIR	 {
+	address			0x06d
+	access_mode WO
+}
+
+register FUNCTION1 {
+	address			0x06e
+	access_mode RW
+}
+
+register STACK {
+	address			0x06f
+	access_mode RO
+}
+
+const	STACK_SIZE	4
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+	address			0x084
+	access_mode RW
+	field	ACE		0x08
+	field	ENABLE		0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND0 {
+	address			0x084
+	access_mode RW
+	field	CACHETHEN	0x80	/* Cache Threshold enable */
+	field	DPARCKEN	0x40	/* Data Parity Check Enable */
+	field	MPARCKEN	0x20	/* Memory Parity Check Enable */
+	field	EXTREQLCK	0x10	/* External Request Lock */
+	/* aic7890/91/96/97 only */
+	field	INTSCBRAMSEL	0x08	/* Internal SCB RAM Select */
+	field	RAMPS		0x04	/* External SCB RAM Present */
+	field	USCBSIZE32	0x02	/* Use 32byte SCB Page Size */
+	field	CIOPARCKEN	0x01	/* Internal bus parity error enable */
+}
+
+register DSCOMMAND1 {
+	address			0x085
+	access_mode RW
+	mask	DSLATT		0xfc	/* PCI latency timer (non-ultra2) */
+	field	HADDLDSEL1	0x02	/* Host Address Load Select Bits */
+	field	HADDLDSEL0	0x01
+}
+
+/*
+ * Bus On/Off Time (p. 3-44) aic7770 only
+ */
+register BUSTIME {
+	address			0x085
+	access_mode RW
+	mask	BOFF		0xf0
+	mask	BON		0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45) aic7770 only
+ */
+register BUSSPD {
+	address			0x086
+	access_mode RW
+	mask	DFTHRSH		0xc0
+	mask	STBOFF		0x38
+	mask	STBON		0x07
+	mask	DFTHRSH_100	0xc0
+	mask	DFTHRSH_75	0x80
+}
+
+/* aic7850/55/60/70/80/95 only */
+register DSPCISTATUS {
+	address			0x086
+	mask	DFTHRSH_100	0xc0
+}
+
+/* aic7890/91/96/97 only */
+register HS_MAILBOX {
+	address			0x086
+	mask	HOST_MAILBOX	0xF0
+	mask	SEQ_MAILBOX	0x0F
+	mask	HOST_TQINPOS	0x80	/* Boundary at either 0 or 128 */
+}
+
+const	HOST_MAILBOX_SHIFT	4
+const	SEQ_MAILBOX_SHIFT	0
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+	address			0x087
+	access_mode RW
+	field	POWRDN		0x40
+	field	SWINT		0x10
+	field	IRQMS		0x08
+	field	PAUSE		0x04
+	field	INTEN		0x02
+	field	CHIPRST		0x01
+	field	CHIPRSTACK	0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+	address			0x088
+	size	4
+	access_mode RW
+}
+
+register HCNT {
+	address			0x08c
+	size	3
+	access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+	address			0x090
+	access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+	address			0x091
+	access_mode RW
+	field	BRKADRINT 0x08
+	field	SCSIINT	  0x04
+	field	CMDCMPLT  0x02
+	field	SEQINT    0x01
+	mask	BAD_PHASE	SEQINT		/* unknown scsi bus phase */
+	mask	SEND_REJECT	0x10|SEQINT	/* sending a message reject */
+	mask	PROTO_VIOLATION	0x20|SEQINT	/* SCSI protocol violation */ 
+	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
+	mask	IGN_WIDE_RES	0x40|SEQINT	/* Complex IGN Wide Res Msg */
+	mask	PDATA_REINIT	0x50|SEQINT	/*
+						 * Returned to data phase
+						 * that requires data
+						 * transfer pointers to be
+						 * recalculated from the
+						 * transfer residual.
+						 */
+	mask	HOST_MSG_LOOP	0x60|SEQINT	/*
+						 * The bus is ready for the
+						 * host to perform another
+						 * message transaction.  This
+						 * mechanism is used for things
+						 * like sync/wide negotiation
+						 * that require a kernel based
+						 * message state engine.
+						 */
+	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
+	mask	PERR_DETECTED	0x80|SEQINT	/*
+						 * Either the phase_lock
+						 * or inb_next routine has
+						 * noticed a parity error.
+						 */
+	mask	DATA_OVERRUN	0x90|SEQINT	/*
+						 * Target attempted to write
+						 * beyond the bounds of its
+						 * command.
+						 */
+	mask	MKMSG_FAILED	0xa0|SEQINT	/*
+						 * Target completed command
+						 * without honoring our ATN
+						 * request to issue a message. 
+						 */
+	mask	MISSED_BUSFREE	0xb0|SEQINT	/*
+						 * The sequencer never saw
+						 * the bus go free after
+						 * either a command complete
+						 * or disconnect message.
+						 */
+	mask	SCB_MISMATCH	0xc0|SEQINT	/*
+						 * Downloaded SCB's tag does
+						 * not match the entry we
+						 * intended to download.
+						 */
+	mask	NO_FREE_SCB	0xd0|SEQINT	/*
+						 * get_free_or_disc_scb failed.
+						 */
+	mask	OUT_OF_RANGE	0xe0|SEQINT
+
+	mask	SEQINT_MASK	0xf0|SEQINT	/* SEQINT Status Codes */
+	mask	INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+	address			0x092
+	access_mode RO
+	field	CIOPARERR	0x80	/* Ultra2 only */
+	field	PCIERRSTAT	0x40	/* PCI only */
+	field	MPARERR		0x20	/* PCI only */
+	field	DPARERR		0x10	/* PCI only */
+	field	SQPARERR	0x08
+	field	ILLOPCODE	0x04
+	field	ILLSADDR	0x02
+	field	ILLHADDR	0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+	address			0x092
+	access_mode WO
+	field	CLRPARERR	0x10	/* PCI only */
+	field	CLRBRKADRINT	0x08
+	field	CLRSCSIINT      0x04
+	field	CLRCMDINT 	0x02
+	field	CLRSEQINT 	0x01
+}
+
+register DFCNTRL {
+	address			0x093
+	access_mode RW
+	field	PRELOADEN	0x80	/* aic7890 only */
+	field	WIDEODD		0x40
+	field	SCSIEN		0x20
+	field	SDMAEN		0x10
+	field	SDMAENACK	0x10
+	field	HDMAEN		0x08
+	field	HDMAENACK	0x08
+	field	DIRECTION	0x04
+	field	FIFOFLUSH	0x02
+	field	FIFORESET	0x01
+}
+
+register DFSTATUS {
+	address			0x094
+	access_mode RO
+	field	PRELOAD_AVAIL	0x80
+	field	DFCACHETH	0x40
+	field	FIFOQWDEMP	0x20
+	field	MREQPEND	0x10
+	field	HDONE		0x08
+	field	DFTHRESH	0x04
+	field	FIFOFULL	0x02
+	field	FIFOEMP		0x01
+}
+
+register DFWADDR {
+	address			0x95
+	access_mode RW
+}
+
+register DFRADDR {
+	address			0x97
+	access_mode RW
+}
+
+register DFDAT {
+	address			0x099
+	access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+	address			0x09a
+	access_mode RW
+	field	SCBAUTO		0x80
+	mask	SCBCNT_MASK	0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+	address			0x09b
+	access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT	{
+	address			0x09c
+	access_mode RO
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+	address			0x09d
+	access_mode WO
+}
+
+register CRCCONTROL1 {
+	address			0x09d
+	access_mode RW
+	field	CRCONSEEN		0x80
+	field	CRCVALCHKEN		0x40
+	field	CRCENDCHKEN		0x20
+	field	CRCREQCHKEN		0x10
+	field	TARGCRCENDEN		0x08
+	field	TARGCRCCNTEN		0x04
+}
+
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+	address			0x09e
+	access_mode RO
+}
+
+register SCSIPHASE {
+	address			0x09e
+	access_mode RO
+	field	STATUS_PHASE	0x20
+	field	COMMAND_PHASE	0x10
+	field	MSG_IN_PHASE	0x08
+	field	MSG_OUT_PHASE	0x04
+	field	DATA_IN_PHASE	0x02
+	field	DATA_OUT_PHASE	0x01
+	mask	DATA_PHASE_MASK	0x03
+}
+
+/*
+ * Special Function
+ */
+register SFUNCT {
+	address			0x09f
+	access_mode RW
+	field	ALT_MODE	0x80
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+	address		0x0a0
+	size		64
+
+	SCB_CDB_PTR {
+		size	4
+		alias	SCB_RESIDUAL_DATACNT
+		alias	SCB_CDB_STORE
+	}
+	SCB_RESIDUAL_SGPTR {
+		size	4
+	}
+	SCB_SCSI_STATUS {
+		size	1
+	}
+	SCB_TARGET_PHASES {
+		size	1
+	}
+	SCB_TARGET_DATA_DIR {
+		size	1
+	}
+	SCB_TARGET_ITAG {
+		size	1
+	}
+	SCB_DATAPTR {
+		size	4
+	}
+	SCB_DATACNT {
+		/*
+		 * The last byte is really the high address bits for
+		 * the data address.
+		 */
+		size	4
+		field	SG_LAST_SEG		0x80	/* In the fourth byte */
+		mask	SG_HIGH_ADDR_BITS	0x7F	/* In the fourth byte */
+	}
+	SCB_SGPTR {
+		size	4
+		field	SG_RESID_VALID	0x04	/* In the first byte */
+		field	SG_FULL_RESID	0x02	/* In the first byte */
+		field	SG_LIST_NULL	0x01	/* In the first byte */
+	}
+	SCB_CONTROL {
+		size	1
+		field	TARGET_SCB			0x80
+		field	STATUS_RCVD			0x80
+		field	DISCENB				0x40
+		field	TAG_ENB				0x20
+		field	MK_MESSAGE			0x10
+		field	ULTRAENB			0x08
+		field	DISCONNECTED			0x04
+		mask	SCB_TAG_TYPE			0x03
+	}
+	SCB_SCSIID {
+		size	1
+		field	TWIN_CHNLB			0x80
+		mask	TWIN_TID			0x70
+		mask	TID				0xf0
+		mask	OID				0x0f
+	}
+	SCB_LUN {
+		field	SCB_XFERLEN_ODD			0x80
+		mask	LID				0x3f
+		size	1
+	}
+	SCB_TAG {
+		size	1
+	}
+	SCB_CDB_LEN {
+		size	1
+	}
+	SCB_SCSIRATE {
+		size	1
+	}
+	SCB_SCSIOFFSET {
+		size	1
+	}
+	SCB_NEXT {
+		size	1
+	}
+	SCB_64_SPARE {
+		size	16
+	}
+	SCB_64_BTT {
+		size	16
+	}
+}
+
+const	SCB_UPLOAD_SIZE		32
+const	SCB_DOWNLOAD_SIZE	32
+const	SCB_DOWNLOAD_SIZE_64	48
+
+const	SG_SIZEOF	0x08		/* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+	address			0x0c0
+	access_mode RW
+	field	CS_2840		0x04
+	field	CK_2840		0x02
+	field	DO_2840		0x01
+}
+
+register STATUS_2840 {
+	address			0x0c1
+	access_mode RW
+	field	EEPROM_TF	0x80
+	mask	BIOS_SEL	0x60
+	mask	ADSEL		0x1e
+	field	DI_2840		0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register CCHADDR {
+	address			0x0E0
+	size 8
+}
+
+register CCHCNT {
+	address			0x0E8
+}
+
+register CCSGRAM {
+	address			0x0E9
+}
+
+register CCSGADDR {
+	address			0x0EA
+}
+
+register CCSGCTL {
+	address			0x0EB
+	field	CCSGDONE	0x80
+	field	CCSGEN		0x08
+	field	SG_FETCH_NEEDED 0x02	/* Bit used for software state */
+	field	CCSGRESET	0x01
+}
+
+register CCSCBCNT {
+	address			0xEF
+}
+
+register CCSCBCTL {
+	address			0x0EE
+	field	CCSCBDONE	0x80
+	field	ARRDONE		0x40	/* SCB Array prefetch done */
+	field	CCARREN		0x10
+	field	CCSCBEN		0x08
+	field	CCSCBDIR	0x04
+	field	CCSCBRESET	0x01
+}
+
+register CCSCBADDR {
+	address			0x0ED
+}
+
+register CCSCBRAM {
+	address			0xEC
+}
+
+/*
+ * SCB bank address (7895/7896/97 only)
+ */
+register SCBBADDR {
+	address			0x0F0
+	access_mode RW
+}
+
+register CCSCBPTR {
+	address			0x0F1
+}
+
+register HNSCB_QOFF {
+	address			0x0F4
+}
+
+register SNSCB_QOFF {
+	address			0x0F6
+}
+
+register SDSCB_QOFF {
+	address			0x0F8
+}
+
+register QOFF_CTLSTA {
+	address			0x0FA
+	field	SCB_AVAIL	0x40
+	field	SNSCB_ROLLOVER	0x20
+	field	SDSCB_ROLLOVER	0x10
+	mask	SCB_QSIZE	0x07
+	mask	SCB_QSIZE_256	0x06
+}
+
+register DFF_THRSH {
+	address			0x0FB
+	mask	WR_DFTHRSH	0x70
+	mask	RD_DFTHRSH	0x07
+	mask	RD_DFTHRSH_MIN	0x00
+	mask	RD_DFTHRSH_25	0x01
+	mask	RD_DFTHRSH_50	0x02
+	mask	RD_DFTHRSH_63	0x03
+	mask	RD_DFTHRSH_75	0x04
+	mask	RD_DFTHRSH_85	0x05
+	mask	RD_DFTHRSH_90	0x06
+	mask	RD_DFTHRSH_MAX	0x07
+	mask	WR_DFTHRSH_MIN	0x00
+	mask	WR_DFTHRSH_25	0x10
+	mask	WR_DFTHRSH_50	0x20
+	mask	WR_DFTHRSH_63	0x30
+	mask	WR_DFTHRSH_75	0x40
+	mask	WR_DFTHRSH_85	0x50
+	mask	WR_DFTHRSH_90	0x60
+	mask	WR_DFTHRSH_MAX	0x70
+}
+
+register SG_CACHE_PRE {
+	access_mode WO
+	address			0x0fc
+	mask	SG_ADDR_MASK	0xf8
+	field	LAST_SEG	0x02
+	field	LAST_SEG_DONE	0x01
+}
+
+register SG_CACHE_SHADOW {
+	access_mode RO
+	address			0x0fc
+	mask	SG_ADDR_MASK	0xf8
+	field	LAST_SEG	0x02
+	field	LAST_SEG_DONE	0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+	address		0x020
+	size		58
+
+	/*
+	 * 1 byte per target starting at this address for configuration values
+	 */
+	BUSY_TARGETS {
+		alias		TARG_SCSIRATE
+		size		16
+	}
+	/*
+	 * Bit vector of targets that have ULTRA enabled as set by
+	 * the BIOS.  The Sequencer relies on a per-SCB field to
+	 * control whether to enable Ultra transfers or not.  During
+	 * initialization, we read this field and reuse it for 2
+	 * entries in the busy target table.
+	 */
+	ULTRA_ENB {
+		alias		CMDSIZE_TABLE
+		size		2
+	}
+	/*
+	 * Bit vector of targets that have disconnection disabled as set by
+	 * the BIOS.  The Sequencer relies in a per-SCB field to control the
+	 * disconnect priveldge.  During initialization, we read this field
+	 * and reuse it for 2 entries in the busy target table.
+	 */
+	DISC_DSB {
+		size		2
+	}
+	CMDSIZE_TABLE_TAIL {
+		size		4
+	}
+	/*
+	 * Partial transfer past cacheline end to be
+	 * transferred using an extra S/G.
+	 */
+	MWI_RESIDUAL {
+		size		1
+		alias	TARG_IMMEDIATE_SCB
+	}
+	/*
+	 * SCBID of the next SCB to be started by the controller.
+	 */
+	NEXT_QUEUED_SCB {
+		size		1
+	}
+	/*
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
+	 */
+	MSG_OUT {
+		size		1
+	}
+	/* Parameters for DMA Logic */
+	DMAPARAMS {
+		size		1
+		field	PRELOADEN	0x80
+		field	WIDEODD		0x40
+		field	SCSIEN		0x20
+		field	SDMAEN		0x10
+		field	SDMAENACK	0x10
+		field	HDMAEN		0x08
+		field	HDMAENACK	0x08
+		field	DIRECTION	0x04	/* Set indicates PCI->SCSI */
+		field	FIFOFLUSH	0x02
+		field	FIFORESET	0x01
+	}
+	SEQ_FLAGS {
+		size		1
+		field	NOT_IDENTIFIED		0x80
+		field	NO_CDB_SENT		0x40
+		field	TARGET_CMD_IS_TAGGED	0x40
+		field	DPHASE			0x20
+		/* Target flags */
+		field	TARG_CMD_PENDING	0x10
+		field	CMDPHASE_PENDING	0x08
+		field	DPHASE_PENDING		0x04
+		field	SPHASE_PENDING		0x02
+		field	NO_DISCONNECT		0x01
+	}
+	/*
+	 * Temporary storage for the
+	 * target/channel/lun of a
+	 * reconnecting target
+	 */
+	SAVED_SCSIID {
+		size		1
+	}
+	SAVED_LUN {
+		size		1
+	}
+	/*
+	 * The last bus phase as seen by the sequencer. 
+	 */
+	LASTPHASE {
+		size		1
+		field	CDI		0x80
+		field	IOI		0x40
+		field	MSGI		0x20
+		mask	PHASE_MASK	CDI|IOI|MSGI
+		mask	P_DATAOUT	0x00
+		mask	P_DATAIN	IOI
+		mask	P_COMMAND	CDI
+		mask	P_MESGOUT	CDI|MSGI
+		mask	P_STATUS	CDI|IOI
+		mask	P_MESGIN	CDI|IOI|MSGI
+		mask	P_BUSFREE	0x01
+	}
+	/*
+	 * head of list of SCBs awaiting
+	 * selection
+	 */
+	WAITING_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * disconnected.  Used for SCB
+	 * paging.
+	 */
+	DISCONNECTED_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * not in use.  Used for SCB paging.
+	 */
+	FREE_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that have
+	 * completed but have not been
+	 * put into the qoutfifo.
+	 */
+	COMPLETE_SCBH {
+		size		1
+	}
+	/*
+	 * Address of the hardware scb array in the host.
+	 */
+	HSCB_ADDR {
+		size		4
+	}
+	/*
+	 * Base address of our shared data with the kernel driver in host
+	 * memory.  This includes the qoutfifo and target mode
+	 * incoming command queue.
+	 */
+	SHARED_DATA_ADDR {
+		size		4
+	}
+	KERNEL_QINPOS {
+		size		1
+	}
+	QINPOS {
+		size		1
+	}
+	QOUTPOS {
+		size		1
+	}
+	/*
+	 * Kernel and sequencer offsets into the queue of
+	 * incoming target mode command descriptors.  The
+	 * queue is full when the KERNEL_TQINPOS == TQINPOS.
+	 */
+	KERNEL_TQINPOS {
+		size		1
+	}
+	TQINPOS {                
+		size		1
+	}
+	ARG_1 {
+		size		1
+		mask	SEND_MSG		0x80
+		mask	SEND_SENSE		0x40
+		mask	SEND_REJ		0x20
+		mask	MSGOUT_PHASEMIS		0x10
+		mask	EXIT_MSG_LOOP		0x08
+		mask	CONT_MSG_LOOP		0x04
+		mask	CONT_TARG_SESSION	0x02
+		alias	RETURN_1
+	}
+	ARG_2 {
+		size		1
+		alias	RETURN_2
+	}
+
+	/*
+	 * Snapshot of MSG_OUT taken after each message is sent.
+	 */
+	LAST_MSG {
+		size		1
+	}
+
+	/*
+	 * Sequences the kernel driver has okayed for us.  This allows
+	 * the driver to do things like prevent initiator or target
+	 * operations.
+	 */
+	SCSISEQ_TEMPLATE {
+		size		1
+		field	ENSELO		0x40
+		field	ENSELI		0x20
+		field	ENRSELI		0x10
+		field	ENAUTOATNO	0x08
+		field	ENAUTOATNI	0x04
+		field	ENAUTOATNP	0x02
+	}
+}
+
+scratch_ram {
+	address		0x056
+	size		4
+	/*
+	 * These scratch ram locations are initialized by the 274X BIOS.
+	 * We reuse them after capturing the BIOS settings during
+	 * initialization.
+	 */
+
+	/*
+	 * The initiator specified tag for this target mode transaction.
+	 */
+	HA_274_BIOSGLOBAL {
+		size	1
+		field	HA_274_EXTENDED_TRANS	0x01
+		alias	INITIATOR_TAG
+	}
+
+	SEQ_FLAGS2 {
+		size	1
+		field	SCB_DMA			0x01
+		field	TARGET_MSG_PENDING	0x02
+	}
+}
+
+scratch_ram {
+	address		0x05a
+	size		6
+	/*
+	 * These are reserved registers in the card's scratch ram on the 2742.
+	 * The EISA configuraiton chip is mapped here.  On Rev E. of the
+	 * aic7770, the sequencer can use this area for scratch, but the
+	 * host cannot directly access these registers.  On later chips, this
+	 * area can be read and written by both the host and the sequencer.
+	 * Even on later chips, many of these locations are initialized by
+	 * the BIOS.
+	 */
+	SCSICONF {
+		size		1
+		field	TERM_ENB	0x80
+		field	RESET_SCSI	0x40
+		field	ENSPCHK		0x20
+		mask	HSCSIID		0x07	/* our SCSI ID */
+		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
+	}
+	INTDEF {
+		address		0x05c
+		size		1
+		field	EDGE_TRIG	0x80
+		mask	VECTOR		0x0f
+	}
+	HOSTCONF {
+		address		0x05d
+		size		1
+	}
+	HA_274_BIOSCTRL	{
+		address		0x05f
+		size		1
+		mask	BIOSMODE		0x30
+		mask	BIOSDISABLED		0x30	
+		field	CHANNEL_B_PRIMARY	0x08
+	}
+}
+
+scratch_ram {
+	address		0x070
+	size		16
+
+	/*
+	 * Per target SCSI offset values for Ultra2 controllers.
+	 */
+	TARG_OFFSET {
+		size		16
+	}
+}
+
+const TID_SHIFT		4
+const SCB_LIST_NULL	0xff
+const TARGET_CMD_CMPLT	0xfe
+
+const CCSGADDR_MAX	0x80
+const CCSGRAM_MAXSEGS	16
+
+/* WDTR Message values */
+const BUS_8_BIT			0x00
+const BUS_16_BIT		0x01
+const BUS_32_BIT		0x02
+
+/* Offset maximums */
+const MAX_OFFSET_8BIT		0x0f
+const MAX_OFFSET_16BIT		0x08
+const MAX_OFFSET_ULTRA2		0x7f
+const MAX_OFFSET		0x7f
+const HOST_MSG			0xff
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+
+const STATUS_BUSY		0x08
+const STATUS_QUEUE_FULL	0x28
+const TARGET_DATA_IN		1
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+/* Offsets into the SCBID array where different data is stored */
+const QOUTFIFO_OFFSET download
+const QINFIFO_OFFSET download
+const CACHESIZE_MASK download
+const INVERTED_CACHESIZE_MASK download
+const SG_PREFETCH_CNT download
+const SG_PREFETCH_ALIGN_MASK download
+const SG_PREFETCH_ADDR_MASK download
diff --git a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq
new file mode 100644
index 0000000..d84b741
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx.seq
@@ -0,0 +1,2398 @@
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $FreeBSD$
+ */
+
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $"
+PATCH_ARG_LIST = "struct ahc_softc *ahc"
+PREFIX = "ahc_"
+
+#include "aic7xxx.reg"
+#include "scsi_message.h"
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a psuedo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
+ * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued.  The sequencer will
+ * automatically consume the entries.
+ */
+
+bus_free_sel:
+	/*
+	 * Turn off the selection hardware.  We need to reset the
+	 * selection request in order to perform a new selection.
+	 */
+	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP;
+	and	SIMODE1, ~ENBUSFREE;
+poll_for_work:
+	call	clear_target_state;
+	and	SXFRCTL0, ~SPIOEN;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		clr	SCSIBUSL;
+	}
+	test	SCSISEQ, ENSELO	jnz poll_for_selection;
+	if ((ahc->features & AHC_TWIN) != 0) {
+		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+		test	SCSISEQ, ENSELO		jnz poll_for_selection;
+	}
+	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+poll_for_work_loop:
+	if ((ahc->features & AHC_TWIN) != 0) {
+		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+	}
+	test	SSTAT0, SELDO|SELDI	jnz selection;
+test_queue:
+	/* Has the driver posted any work for us? */
+BEGIN_CRITICAL;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
+	} else {
+		mov	A, QINPOS;
+		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
+	}
+	mov	ARG_1, NEXT_QUEUED_SCB;
+
+	/*
+	 * We have at least one queued SCB now and we don't have any 
+	 * SCBs in the list of SCBs awaiting selection.  Allocate a
+	 * card SCB for the host's SCB and get to work on it.
+	 */
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		mov	ALLZEROS	call	get_free_or_disc_scb;
+	} else {
+		/* In the non-paging case, the SCBID == hardware SCB index */
+		mov	SCBPTR, ARG_1;
+	}
+	or	SEQ_FLAGS2, SCB_DMA;
+END_CRITICAL;
+dma_queued_scb:
+	/*
+	 * DMA the SCB from host ram into the current SCB location.
+	 */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	ARG_1	call dma_scb;
+	/*
+	 * Check one last time to see if this SCB was canceled
+	 * before we completed the DMA operation.  If it was,
+	 * the QINFIFO next pointer will not match our saved
+	 * value.
+	 */
+	mov	A, ARG_1;
+BEGIN_CRITICAL;
+	cmp	NEXT_QUEUED_SCB, A jne abort_qinscb;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		cmp	SCB_TAG, A je . + 2;
+		mvi	SCB_MISMATCH call set_seqint;
+	}
+	mov	NEXT_QUEUED_SCB, SCB_NEXT;
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		mov	NONE, SNSCB_QOFF;
+	} else {
+		inc	QINPOS;
+	}
+	and	SEQ_FLAGS2, ~SCB_DMA;
+END_CRITICAL;
+start_waiting:
+	/*
+	 * Start the first entry on the waiting SCB list.
+	 */
+	mov	SCBPTR, WAITING_SCBH;
+	call	start_selection;
+
+poll_for_selection:
+	/*
+	 * Twin channel devices cannot handle things like SELTO
+	 * interrupts on the "background" channel.  So, while
+	 * selecting, keep polling the current channel until
+	 * either a selection or reselection occurs.
+	 */
+	test	SSTAT0, SELDO|SELDI	jz poll_for_selection;
+
+selection:
+	/*
+	 * We aren't expecting a bus free, so interrupt
+	 * the kernel driver if it happens.
+	 */
+	mvi	CLRSINT1,CLRBUSFREE;
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SIMODE1, ENBUSFREE;
+	}
+
+	/*
+	 * Guard against a bus free after (re)selection
+	 * but prior to enabling the busfree interrupt.  SELDI
+	 * and SELDO will be cleared in that case.
+	 */
+	test	SSTAT0, SELDI|SELDO	jz bus_free_sel;
+	test	SSTAT0,SELDO	jnz select_out;
+select_in:
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+			test	SSTAT0, TARGET	jz initiator_reselect;
+		}
+		mvi	CLRSINT0, CLRSELDI;
+
+		/*
+		 * We've just been selected.  Assert BSY and
+		 * setup the phase for receiving messages
+		 * from the target.
+		 */
+		mvi	SCSISIGO, P_MESGOUT|BSYO;
+
+		/*
+		 * Setup the DMA for sending the identify and
+		 * command information.
+		 */
+		mvi	SEQ_FLAGS, CMDPHASE_PENDING;
+
+		mov     A, TQINPOS;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mvi	DINDEX, CCHADDR;
+			mvi	SHARED_DATA_ADDR call set_32byte_addr;
+			mvi	CCSCBCTL, CCSCBRESET;
+		} else {
+			mvi	DINDEX, HADDR;
+			mvi	SHARED_DATA_ADDR call set_32byte_addr;
+			mvi	DFCNTRL, FIFORESET;
+		}
+
+		/* Initiator that selected us */
+		and	SAVED_SCSIID, SELID_MASK, SELID;
+		/* The Target ID we were selected at */
+		if ((ahc->features & AHC_MULTI_TID) != 0) {
+			and	A, OID, TARGIDIN;
+		} else if ((ahc->features & AHC_ULTRA2) != 0) {
+			and	A, OID, SCSIID_ULTRA2;
+		} else {
+			and	A, OID, SCSIID;
+		}
+		or	SAVED_SCSIID, A;
+		if ((ahc->features & AHC_TWIN) != 0) {
+			test 	SBLKCTL, SELBUSB jz . + 2;
+			or	SAVED_SCSIID, TWIN_CHNLB;
+		}
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, SAVED_SCSIID;
+		} else {
+			mov	DFDAT, SAVED_SCSIID;
+		}
+
+		/*
+		 * If ATN isn't asserted, the target isn't interested
+		 * in talking to us.  Go directly to bus free.
+		 * XXX SCSI-1 may require us to assume lun 0 if
+		 * ATN is false.
+		 */
+		test	SCSISIGI, ATNI	jz	target_busfree;
+
+		/*
+		 * Watch ATN closely now as we pull in messages from the
+		 * initiator.  We follow the guidlines from section 6.5
+		 * of the SCSI-2 spec for what messages are allowed when.
+		 */
+		call	target_inb;
+
+		/*
+		 * Our first message must be one of IDENTIFY, ABORT, or
+		 * BUS_DEVICE_RESET.
+		 */
+		test	DINDEX, MSG_IDENTIFYFLAG jz host_target_message_loop;
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+		and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, DINDEX;
+
+		/* Remember for disconnection decision */
+		test	DINDEX, MSG_IDENTIFY_DISCFLAG jnz . + 2;
+		/* XXX Honor per target settings too */
+		or	SEQ_FLAGS, NO_DISCONNECT;
+
+		test	SCSISIGI, ATNI	jz	ident_messages_done;
+		call	target_inb;
+		/*
+		 * If this is a tagged request, the tagged message must
+		 * immediately follow the identify.  We test for a valid
+		 * tag message by seeing if it is >= MSG_SIMPLE_Q_TAG and
+		 * < MSG_IGN_WIDE_RESIDUE.
+		 */
+		add	A, -MSG_SIMPLE_Q_TAG, DINDEX;
+		jnc	ident_messages_done_msg_pending;
+		add	A, -MSG_IGN_WIDE_RESIDUE, DINDEX;
+		jc	ident_messages_done_msg_pending;
+
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+		
+		/*
+		 * If the initiator doesn't feel like providing a tag number,
+		 * we've got a failed selection and must transition to bus
+		 * free.
+		 */
+		test	SCSISIGI, ATNI	jz	target_busfree;
+
+		/*
+		 * Store the tag for the host.
+		 */
+		call	target_inb;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, DINDEX;
+		} else {
+			mov	DFDAT, DINDEX;
+		}
+		mov	INITIATOR_TAG, DINDEX;
+		or	SEQ_FLAGS, TARGET_CMD_IS_TAGGED;
+
+ident_messages_done:
+		/* Terminate the ident list */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mvi	CCSCBRAM, SCB_LIST_NULL;
+		} else {
+			mvi	DFDAT, SCB_LIST_NULL;
+		}
+		or	SEQ_FLAGS, TARG_CMD_PENDING;
+		test	SEQ_FLAGS2, TARGET_MSG_PENDING
+			jnz target_mesgout_pending;
+		test	SCSISIGI, ATNI jnz target_mesgout_continue;
+		jmp	target_ITloop;
+
+
+ident_messages_done_msg_pending:
+		or	SEQ_FLAGS2, TARGET_MSG_PENDING;
+		jmp	ident_messages_done;
+
+		/*
+		 * Pushed message loop to allow the kernel to
+		 * run it's own target mode message state engine.
+		 */
+host_target_message_loop:
+		mvi	HOST_MSG_LOOP call set_seqint;
+		cmp	RETURN_1, EXIT_MSG_LOOP	je target_ITloop;
+		test	SSTAT0, SPIORDY jz .;
+		jmp	host_target_message_loop;
+	}
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+initiator_reselect:
+	/* XXX test for and handle ONE BIT condition */
+	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
+	and	SAVED_SCSIID, SELID_MASK, SELID;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		and	A, OID, SCSIID_ULTRA2;
+	} else {
+		and	A, OID, SCSIID;
+	}
+	or	SAVED_SCSIID, A;
+	if ((ahc->features & AHC_TWIN) != 0) {
+		test	SBLKCTL, SELBUSB	jz . + 2;
+		or	SAVED_SCSIID, TWIN_CHNLB;
+	}
+	mvi	CLRSINT0, CLRSELDI;
+	jmp	ITloop;
+}
+
+abort_qinscb:
+	call	add_scb_to_free_list;
+	jmp	poll_for_work_loop;
+
+start_selection:
+	/*
+	 * If bus reset interrupts have been disabled (from a previous
+	 * reset), re-enable them now.  Resets are only of interest
+	 * when we have outstanding transactions, so we can safely
+	 * defer re-enabling the interrupt until, as an initiator,
+	 * we start sending out transactions again.
+	 */
+	test	SIMODE1, ENSCSIRST	jnz . + 3;
+	mvi	CLRSINT1, CLRSCSIRSTI;
+	or	SIMODE1, ENSCSIRST;
+	if ((ahc->features & AHC_TWIN) != 0) {
+		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
+		test	SCB_SCSIID, TWIN_CHNLB jz . + 2;
+		or	SINDEX, SELBUSB;
+		mov	SBLKCTL,SINDEX;		/* select channel */
+	}
+initialize_scsiid:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	SCSIID_ULTRA2, SCB_SCSIID;
+	} else if ((ahc->features & AHC_TWIN) != 0) {
+		and	SCSIID, TWIN_TID|OID, SCB_SCSIID;
+	} else {
+		mov	SCSIID, SCB_SCSIID;
+	}
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		mov	SINDEX, SCSISEQ_TEMPLATE;
+		test	SCB_CONTROL, TARGET_SCB jz . + 2;
+		or	SINDEX, TEMODE;
+		mov	SCSISEQ, SINDEX ret;
+	} else {
+		mov	SCSISEQ, SCSISEQ_TEMPLATE ret;
+	}
+
+/*
+ * Initialize transfer settings with SCB provided settings.
+ */
+set_transfer_settings:
+	if ((ahc->features & AHC_ULTRA) != 0) {
+		test	SCB_CONTROL, ULTRAENB jz . + 2;
+		or	SXFRCTL0, FAST20;
+	} 
+	/*
+	 * Initialize SCSIRATE with the appropriate value for this target.
+	 */
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	SCSIRATE, SCB_SCSIRATE, 2 ret;
+	} else {
+		mov	SCSIRATE, SCB_SCSIRATE ret;
+	}
+
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
+/*
+ * We carefully toggle SPIOEN to allow us to return the 
+ * message byte we receive so it can be checked prior to
+ * driving REQ on the bus for the next byte.
+ */
+target_inb:
+	/*
+	 * Drive REQ on the bus by enabling SCSI PIO.
+	 */
+	or	SXFRCTL0, SPIOEN;
+	/* Wait for the byte */
+	test	SSTAT0, SPIORDY jz .;
+	/* Prevent our read from triggering another REQ */
+	and	SXFRCTL0, ~SPIOEN;
+	/* Save latched contents */
+	mov	DINDEX, SCSIDATL ret;
+}
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select_out:
+	/* Turn off the selection hardware */
+	and	SCSISEQ, TEMODE|ENSELI|ENRSELI|ENAUTOATNP, SCSISEQ;
+	mov	SCBPTR, WAITING_SCBH;
+	mov	WAITING_SCBH,SCB_NEXT;
+	mov	SAVED_SCSIID, SCB_SCSIID;
+	and	SAVED_LUN, LID, SCB_LUN;
+	call	set_transfer_settings;
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SSTAT0, TARGET	jz initiator_select;
+
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+
+		/*
+		 * Put tag in connonical location since not
+		 * all connections have an SCB.
+		 */
+		mov	INITIATOR_TAG, SCB_TARGET_ITAG;
+
+		/*
+		 * We've just re-selected an initiator.
+		 * Assert BSY and setup the phase for
+		 * sending our identify messages.
+		 */
+		mvi	P_MESGIN|BSYO call change_phase;
+		mvi	CLRSINT0, CLRSELDO;
+
+		/*
+		 * Start out with a simple identify message.
+		 */
+		or	SAVED_LUN, MSG_IDENTIFYFLAG call target_outb;
+
+		/*
+		 * If we are the result of a tagged command, send
+		 * a simple Q tag and the tag id.
+		 */
+		test	SCB_CONTROL, TAG_ENB	jz . + 3;
+		mvi	MSG_SIMPLE_Q_TAG call target_outb;
+		mov	SCB_TARGET_ITAG call target_outb;
+target_synccmd:
+		/*
+		 * Now determine what phases the host wants us
+		 * to go through.
+		 */
+		mov	SEQ_FLAGS, SCB_TARGET_PHASES;
+		
+		test	SCB_CONTROL, MK_MESSAGE	jz target_ITloop;
+		mvi	P_MESGIN|BSYO call change_phase;
+		jmp	host_target_message_loop;
+target_ITloop:
+		/*
+		 * Start honoring ATN signals now that
+		 * we properly identified ourselves.
+		 */
+		test	SCSISIGI, ATNI			jnz target_mesgout;
+		test	SEQ_FLAGS, CMDPHASE_PENDING	jnz target_cmdphase;
+		test	SEQ_FLAGS, DPHASE_PENDING	jnz target_dphase;
+		test	SEQ_FLAGS, SPHASE_PENDING	jnz target_sphase;
+
+		/*
+		 * No more work to do.  Either disconnect or not depending
+		 * on the state of NO_DISCONNECT.
+		 */
+		test	SEQ_FLAGS, NO_DISCONNECT jz target_disconnect; 
+		mvi	TARG_IMMEDIATE_SCB, SCB_LIST_NULL;
+		call	complete_target_cmd;
+		if ((ahc->flags & AHC_PAGESCBS) != 0) {
+			mov	ALLZEROS	call	get_free_or_disc_scb;
+		}
+		cmp	TARG_IMMEDIATE_SCB, SCB_LIST_NULL je .;
+		mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+		mov	TARG_IMMEDIATE_SCB call dma_scb;
+		call	set_transfer_settings;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		jmp	target_synccmd;
+
+target_mesgout:
+		mvi	SCSISIGO, P_MESGOUT|BSYO;
+target_mesgout_continue:
+		call	target_inb;
+target_mesgout_pending:
+		and	SEQ_FLAGS2, ~TARGET_MSG_PENDING;
+		/* Local Processing goes here... */
+		jmp	host_target_message_loop;
+		
+target_disconnect:
+		mvi	P_MESGIN|BSYO call change_phase;
+		test	SEQ_FLAGS, DPHASE	jz . + 2;
+		mvi	MSG_SAVEDATAPOINTER call target_outb;
+		mvi	MSG_DISCONNECT call target_outb;
+
+target_busfree_wait:
+		/* Wait for preceding I/O session to complete. */
+		test	SCSISIGI, ACKI jnz .;
+target_busfree:
+		and	SIMODE1, ~ENBUSFREE;
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			clr	SCSIBUSL;
+		}
+		clr	SCSISIGO;
+		mvi	LASTPHASE, P_BUSFREE;
+		call	complete_target_cmd;
+		jmp	poll_for_work;
+
+target_cmdphase:
+		/*
+		 * The target has dropped ATN (doesn't want to abort or BDR)
+		 * and we believe this selection to be valid.  If the ring
+		 * buffer for new commands is full, return busy or queue full.
+		 */
+		if ((ahc->features & AHC_HS_MAILBOX) != 0) {
+			and	A, HOST_TQINPOS, HS_MAILBOX;
+		} else {
+			mov	A, KERNEL_TQINPOS;
+		}
+		cmp	TQINPOS, A jne tqinfifo_has_space;
+		mvi	P_STATUS|BSYO call change_phase;
+		test	SEQ_FLAGS, TARGET_CMD_IS_TAGGED jz . + 3;
+		mvi	STATUS_QUEUE_FULL call target_outb;
+		jmp	target_busfree_wait;
+		mvi	STATUS_BUSY call target_outb;
+		jmp	target_busfree_wait;
+tqinfifo_has_space:	
+		mvi	P_COMMAND|BSYO call change_phase;
+		call	target_inb;
+		mov	A, DINDEX;
+		/* Store for host */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, A;
+		} else {
+			mov	DFDAT, A;
+		}
+
+		/*
+		 * Determine the number of bytes to read
+		 * based on the command group code via table lookup.
+		 * We reuse the first 8 bytes of the TARG_SCSIRATE
+		 * BIOS array for this table. Count is one less than
+		 * the total for the command since we've already fetched
+		 * the first byte.
+		 */
+		shr	A, CMD_GROUP_CODE_SHIFT;
+		add	SINDEX, CMDSIZE_TABLE, A;
+		mov	A, SINDIR;
+
+		test	A, 0xFF jz command_phase_done;
+		or	SXFRCTL0, SPIOEN;
+command_loop:
+		test	SSTAT0, SPIORDY jz .;
+		cmp	A, 1 jne . + 2;
+		and	SXFRCTL0, ~SPIOEN;	/* Last Byte */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			mov	CCSCBRAM, SCSIDATL;
+		} else {
+			mov	DFDAT, SCSIDATL;
+		}
+		dec	A;
+		test	A, 0xFF jnz command_loop;
+
+command_phase_done:
+		and	SEQ_FLAGS, ~CMDPHASE_PENDING;
+		jmp	target_ITloop;
+
+target_dphase:
+		/*
+		 * Data phases on the bus are from the
+		 * perspective of the initiator.  The dma
+		 * code looks at LASTPHASE to determine the
+		 * data direction of the DMA.  Toggle it for
+		 * target transfers.
+		 */
+		xor	LASTPHASE, IOI, SCB_TARGET_DATA_DIR;
+		or	SCB_TARGET_DATA_DIR, BSYO call change_phase;
+		jmp	p_data;
+
+target_sphase:
+		mvi	P_STATUS|BSYO call change_phase;
+		mvi	LASTPHASE, P_STATUS;
+		mov	SCB_SCSI_STATUS call target_outb;
+		/* XXX Watch for ATN or parity errors??? */
+		mvi	SCSISIGO, P_MESGIN|BSYO;
+		/* MSG_CMDCMPLT is 0, but we can't do an immediate of 0 */
+		mov	ALLZEROS call target_outb;
+		jmp	target_busfree_wait;
+	
+complete_target_cmd:
+		test	SEQ_FLAGS, TARG_CMD_PENDING	jnz . + 2;
+		mov	SCB_TAG jmp complete_post;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			/* Set the valid byte */
+			mvi	CCSCBADDR, 24;
+			mov	CCSCBRAM, ALLONES;
+			mvi	CCHCNT, 28;
+			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			test	CCSCBCTL, CCSCBDONE jz .;
+			clr	CCSCBCTL;
+		} else {
+			/* Set the valid byte */
+			or	DFCNTRL, FIFORESET;
+			mvi	DFWADDR, 3; /* Third 64bit word or byte 24 */
+			mov	DFDAT, ALLONES;
+			mvi	28	call set_hcnt;
+			or	DFCNTRL, HDMAEN|FIFOFLUSH;
+			call	dma_finish;
+		}
+		inc	TQINPOS;
+		mvi	INTSTAT,CMDCMPLT ret;
+	}
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+initiator_select:
+	or	SXFRCTL0, SPIOEN|CLRSTCNT|CLRCHN;
+	/*
+	 * As soon as we get a successful selection, the target
+	 * should go into the message out phase since we have ATN
+	 * asserted.
+	 */
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+	mvi	SEQ_FLAGS, NO_CDB_SENT;
+	mvi	CLRSINT0, CLRSELDO;
+
+	/*
+	 * Main loop for information transfer phases.  Wait for the
+	 * target to assert REQ before checking MSG, C/D and I/O for
+	 * the bus phase.
+	 */
+mesgin_phasemis:
+ITloop:
+	call	phase_lock;
+
+	mov	A, LASTPHASE;
+
+	test	A, ~P_DATAIN	jz p_data;
+	cmp	A,P_COMMAND	je p_command;
+	cmp	A,P_MESGOUT	je p_mesgout;
+	cmp	A,P_STATUS	je p_status;
+	cmp	A,P_MESGIN	je p_mesgin;
+
+	mvi	BAD_PHASE call set_seqint;
+	jmp	ITloop;			/* Try reading the bus again. */
+
+await_busfree:
+	and	SIMODE1, ~ENBUSFREE;
+	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		clr	SCSIBUSL;	/* Prevent bit leakage durint SELTO */
+	}
+	and	SXFRCTL0, ~SPIOEN;
+	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	test	SSTAT1, BUSFREE jnz poll_for_work;
+	mvi	MISSED_BUSFREE call set_seqint;
+}
+	
+clear_target_state:
+	/*
+	 * We assume that the kernel driver may reset us
+	 * at any time, even in the middle of a DMA, so
+	 * clear DFCNTRL too.
+	 */
+	clr	DFCNTRL;
+	or	SXFRCTL0, CLRSTCNT|CLRCHN;
+
+	/*
+	 * We don't know the target we will connect to,
+	 * so default to narrow transfers to avoid
+	 * parity problems.
+	 */
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	SCSIRATE, ALLZEROS, 2;
+	} else {
+		clr	SCSIRATE;
+		if ((ahc->features & AHC_ULTRA) != 0) {
+			and	SXFRCTL0, ~(FAST20);
+		}
+	}
+	mvi	LASTPHASE, P_BUSFREE;
+	/* clear target specific flags */
+	mvi	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT ret;
+
+sg_advance:
+	clr	A;			/* add sizeof(struct scatter) */
+	add	SCB_RESIDUAL_SGPTR[0],SG_SIZEOF;
+	adc	SCB_RESIDUAL_SGPTR[1],A;
+	adc	SCB_RESIDUAL_SGPTR[2],A;
+	adc	SCB_RESIDUAL_SGPTR[3],A ret;
+
+if ((ahc->features & AHC_CMD_CHAN) != 0) {
+disable_ccsgen:
+	test	CCSGCTL, CCSGEN jz return;
+	test	CCSGCTL, CCSGDONE jz .;
+disable_ccsgen_fetch_done:
+	clr	CCSGCTL;
+	test	CCSGCTL, CCSGEN jnz .;
+	ret;
+idle_loop:
+	/*
+	 * Do we need any more segments for this transfer?
+	 */
+	test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jnz return;
+
+	/* Did we just finish fetching segs? */
+	cmp	CCSGCTL, CCSGEN|CCSGDONE je idle_sgfetch_complete;
+
+	/* Are we actively fetching segments? */
+	test	CCSGCTL, CCSGEN jnz return;
+
+	/*
+	 * Do we have any prefetch left???
+	 */
+	cmp	CCSGADDR, SG_PREFETCH_CNT jne idle_sg_avail;
+
+	/*
+	 * Need to fetch segments, but we can only do that
+	 * if the command channel is completely idle.  Make
+	 * sure we don't have an SCB prefetch going on.
+	 */
+	test	CCSCBCTL, CCSCBEN jnz return;
+
+	/*
+	 * We fetch a "cacheline aligned" and sized amount of data
+	 * so we don't end up referencing a non-existant page.
+	 * Cacheline aligned is in quotes because the kernel will
+	 * set the prefetch amount to a reasonable level if the
+	 * cacheline size is unknown.
+	 */
+	mvi	CCHCNT, SG_PREFETCH_CNT;
+	and	CCHADDR[0], SG_PREFETCH_ALIGN_MASK, SCB_RESIDUAL_SGPTR;
+	bmov	CCHADDR[1], SCB_RESIDUAL_SGPTR[1], 3;
+	mvi	CCSGCTL, CCSGEN|CCSGRESET ret;
+idle_sgfetch_complete:
+	call	disable_ccsgen_fetch_done;
+	and	CCSGADDR, SG_PREFETCH_ADDR_MASK, SCB_RESIDUAL_SGPTR;
+idle_sg_avail:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/* Does the hardware have space for another SG entry? */
+		test	DFSTATUS, PRELOAD_AVAIL jz return;
+		bmov 	HADDR, CCSGRAM, 7;
+		bmov	SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1;
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+		}
+		call	sg_advance;
+		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+		or	SINDEX, LAST_SEG;
+		mov	SG_CACHE_PRE, SINDEX;
+		/* Load the segment */
+		or	DFCNTRL, PRELOADEN;
+	}
+	ret;
+}
+
+if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
+/*
+ * Calculate the trailing portion of this S/G segment that cannot
+ * be transferred using memory write and invalidate PCI transactions.  
+ * XXX Can we optimize this for PCI writes only???
+ */
+calc_mwi_residual:
+	/*
+	 * If the ending address is on a cacheline boundary,
+	 * there is no need for an extra segment.
+	 */
+	mov	A, HCNT[0];
+	add	A, A, HADDR[0];
+	and	A, CACHESIZE_MASK;
+	test	A, 0xFF jz return;
+
+	/*
+	 * If the transfer is less than a cachline,
+	 * there is no need for an extra segment.
+	 */
+	test	HCNT[1], 0xFF	jnz calc_mwi_residual_final;
+	test	HCNT[2], 0xFF	jnz calc_mwi_residual_final;
+	add	NONE, INVERTED_CACHESIZE_MASK, HCNT[0];
+	jnc	return;
+
+calc_mwi_residual_final:
+	mov	MWI_RESIDUAL, A;
+	not	A;
+	inc	A;
+	add	HCNT[0], A;
+	adc	HCNT[1], -1;
+	adc	HCNT[2], -1 ret;
+}
+
+p_data:
+	test	SEQ_FLAGS,NOT_IDENTIFIED|NO_CDB_SENT jz p_data_allowed;
+	mvi	PROTO_VIOLATION call set_seqint;
+p_data_allowed:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
+	} else {
+		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+	}
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* We don't have any valid S/G elements */
+		mvi	CCSGADDR, SG_PREFETCH_CNT;
+	}
+	test	SEQ_FLAGS, DPHASE	jz data_phase_initialize;
+
+	/*
+	 * If we re-enter the data phase after going through another
+	 * phase, our transfer location has almost certainly been
+	 * corrupted by the interveining, non-data, transfers.  Ask
+	 * the host driver to fix us up based on the transfer residual.
+	 */
+	mvi	PDATA_REINIT	call set_seqint;
+	jmp	data_phase_loop;
+
+data_phase_initialize:
+	/* We have seen a data phase for the first time */
+	or	SEQ_FLAGS, DPHASE;
+
+	/*
+	 * Initialize the DMA address and counter from the SCB.
+	 * Also set SCB_RESIDUAL_SGPTR, including the LAST_SEG
+	 * flag in the highest byte of the data count.  We cannot
+	 * modify the saved values in the SCB until we see a save
+	 * data pointers message.
+	 */
+	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+		/* The lowest address byte must be loaded last. */
+		mov	SCB_DATACNT[3] call set_hhaddr;
+	}
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	HADDR, SCB_DATAPTR, 7;
+		bmov	SCB_RESIDUAL_DATACNT[3], SCB_DATACNT[3], 5;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_DATAPTR	call bcopy_7;
+		mvi	DINDEX, SCB_RESIDUAL_DATACNT + 3;
+		mvi	SCB_DATACNT + 3 call bcopy_5;
+	}
+	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0) {
+		call	calc_mwi_residual;
+	}
+	and	SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID;
+
+	if ((ahc->features & AHC_ULTRA2) == 0) {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	STCNT, HCNT, 3;
+		} else {
+			call	set_stcnt_from_hcnt;
+		}
+	}
+
+data_phase_loop:
+	/* Guard against overruns */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz data_phase_inbounds;
+
+	/*
+	 * Turn on `Bit Bucket' mode, wait until the target takes
+	 * us to another phase, and then notify the host.
+	 */
+	and	DMAPARAMS, DIRECTION;
+	mov	DFCNTRL, DMAPARAMS;
+	or	SXFRCTL1,BITBUCKET;
+	if ((ahc->features & AHC_DT) == 0) {
+		test	SSTAT1,PHASEMIS	jz .;
+	} else {
+		test	SCSIPHASE, DATA_PHASE_MASK jnz .;
+	}
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	DATA_OVERRUN call set_seqint;
+	jmp	ITloop;
+
+data_phase_inbounds:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	SINDEX, SCB_RESIDUAL_SGPTR[0];
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2;
+		or	SINDEX, LAST_SEG;
+		mov	SG_CACHE_PRE, SINDEX;
+		mov	DFCNTRL, DMAPARAMS;
+ultra2_dma_loop:
+		call	idle_loop;
+		/*
+		 * The transfer is complete if either the last segment
+		 * completes or the target changes phase.
+		 */
+		test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz ultra2_dmafinish;
+		if ((ahc->features & AHC_DT) == 0) {
+			if ((ahc->flags & AHC_TARGETROLE) != 0) {
+				 /*
+				  * As a target, we control the phases,
+				  * so ignore PHASEMIS.
+				  */
+				test	SSTAT0, TARGET jnz ultra2_dma_loop;
+			}
+			if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+				test	SSTAT1,PHASEMIS	jz ultra2_dma_loop;
+			}
+		} else {
+			test	DFCNTRL, SCSIEN jnz ultra2_dma_loop;
+		}
+
+ultra2_dmafinish:
+		/*
+		 * The transfer has terminated either due to a phase
+		 * change, and/or the completion of the last segment.
+		 * We have two goals here.  Do as much other work
+		 * as possible while the data fifo drains on a read
+		 * and respond as quickly as possible to the standard
+		 * messages (save data pointers/disconnect and command
+		 * complete) that usually follow a data phase.
+		 */
+		if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
+			/*
+			 * On chips with broken auto-flush, start
+			 * the flushing process now.  We'll poke
+			 * the chip from time to time to keep the
+			 * flush process going as we complete the
+			 * data phase.
+			 */
+			or	DFCNTRL, FIFOFLUSH;
+		}
+		/*
+		 * We assume that, even though data may still be
+		 * transferring to the host, that the SCSI side of
+		 * the DMA engine is now in a static state.  This
+		 * allows us to update our notion of where we are
+		 * in this transfer.
+		 *
+		 * If, by chance, we stopped before being able
+		 * to fetch additional segments for this transfer,
+		 * yet the last S/G was completely exhausted,
+		 * call our idle loop until it is able to load
+		 * another segment.  This will allow us to immediately
+		 * pickup on the next segment on the next data phase.
+		 *
+		 * If we happened to stop on the last segment, then
+		 * our residual information is still correct from
+		 * the idle loop and there is no need to perform
+		 * any fixups.
+		 */
+ultra2_ensure_sg:
+		test	SG_CACHE_SHADOW, LAST_SEG jz ultra2_shvalid;
+		/* Record if we've consumed all S/G entries */
+		test	SSTAT2, SHVALID	jnz residuals_correct;
+		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
+		jmp	residuals_correct;
+
+ultra2_shvalid:
+		test	SSTAT2, SHVALID	jnz sgptr_fixup;
+		call	idle_loop;
+		jmp	ultra2_ensure_sg;
+
+sgptr_fixup:
+		/*
+		 * Fixup the residual next S/G pointer.  The S/G preload
+		 * feature of the chip allows us to load two elements
+		 * in addition to the currently active element.  We
+		 * store the bottom byte of the next S/G pointer in
+		 * the SG_CACEPTR register so we can restore the
+		 * correct value when the DMA completes.  If the next
+		 * sg ptr value has advanced to the point where higher
+		 * bytes in the address have been affected, fix them
+		 * too.
+		 */
+		test	SG_CACHE_SHADOW, 0x80 jz sgptr_fixup_done;
+		test	SCB_RESIDUAL_SGPTR[0], 0x80 jnz sgptr_fixup_done;
+		add	SCB_RESIDUAL_SGPTR[1], -1;
+		adc	SCB_RESIDUAL_SGPTR[2], -1; 
+		adc	SCB_RESIDUAL_SGPTR[3], -1;
+sgptr_fixup_done:
+		and	SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW;
+		/* We are not the last seg */
+		and	SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG;
+residuals_correct:
+		/*
+		 * Go ahead and shut down the DMA engine now.
+		 * In the future, we'll want to handle end of
+		 * transfer messages prior to doing this, but this
+		 * requires similar restructuring for pre-ULTRA2
+		 * controllers.
+		 */
+		test	DMAPARAMS, DIRECTION jnz ultra2_fifoempty;
+ultra2_fifoflush:
+		if ((ahc->features & AHC_DT) == 0) {
+			if ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0) {
+				/*
+				 * On Rev A of the aic7890, the autoflush
+				 * feature doesn't function correctly.
+				 * Perform an explicit manual flush.  During
+				 * a manual flush, the FIFOEMP bit becomes
+				 * true every time the PCI FIFO empties
+				 * regardless of the state of the SCSI FIFO.
+				 * It can take up to 4 clock cycles for the
+				 * SCSI FIFO to get data into the PCI FIFO
+				 * and for FIFOEMP to de-assert.  Here we
+				 * guard against this condition by making
+				 * sure the FIFOEMP bit stays on for 5 full
+				 * clock cycles.
+				 */
+				or	DFCNTRL, FIFOFLUSH;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+				test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+			}
+			test	DFSTATUS, FIFOEMP jz ultra2_fifoflush;
+		} else {
+			/*
+			 * We enable the auto-ack feature on DT capable
+			 * controllers.  This means that the controller may
+			 * have already transferred some overrun bytes into
+			 * the data FIFO and acked them on the bus.  The only
+			 * way to detect this situation is to wait for
+			 * LAST_SEG_DONE to come true on a completed transfer
+			 * and then test to see if the data FIFO is non-empty.
+			 */
+			test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL
+				jz ultra2_wait_fifoemp;
+			test	SG_CACHE_SHADOW, LAST_SEG_DONE jz .;
+			/*
+			 * FIFOEMP can lag LAST_SEG_DONE.  Wait a few
+			 * clocks before calling this an overrun.
+			 */
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+			test	DFSTATUS, FIFOEMP jnz ultra2_fifoempty;
+			/* Overrun */
+			jmp	data_phase_loop;
+ultra2_wait_fifoemp:
+			test	DFSTATUS, FIFOEMP jz .;
+		}
+ultra2_fifoempty:
+		/* Don't clobber an inprogress host data transfer */
+		test	DFSTATUS, MREQPEND	jnz ultra2_fifoempty;
+ultra2_dmahalt:
+		and     DFCNTRL, ~(SCSIEN|HDMAEN);
+		test	DFCNTRL, SCSIEN|HDMAEN jnz .;
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			/*
+			 * Keep HHADDR cleared for future, 32bit addressed
+			 * only, DMA operations.
+			 *
+			 * Due to bayonette style S/G handling, our residual
+			 * data must be "fixed up" once the transfer is halted.
+			 * Here we fixup the HSHADDR stored in the high byte
+			 * of the residual data cnt.  By postponing the fixup,
+			 * we can batch the clearing of HADDR with the fixup.
+			 * If we halted on the last segment, the residual is
+			 * already correct.   If we are not on the last
+			 * segment, copy the high address directly from HSHADDR.
+			 * We don't need to worry about maintaining the
+			 * SG_LAST_SEG flag as it will always be false in the
+			 * case where an update is required.
+			 */
+			or	DSCOMMAND1, HADDLDSEL0;
+			test	SG_CACHE_SHADOW, LAST_SEG jnz . + 2;
+			mov	SCB_RESIDUAL_DATACNT[3], SHADDR;
+			clr	HADDR;
+			and	DSCOMMAND1, ~HADDLDSEL0;
+		}
+	} else {
+		/* If we are the last SG block, tell the hardware. */
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			test	MWI_RESIDUAL, 0xFF jnz dma_mid_sg;
+		}
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz dma_mid_sg;
+		if ((ahc->flags & AHC_TARGETROLE) != 0) {
+			test	SSTAT0, TARGET jz dma_last_sg;
+			if ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0) {
+				test	DMAPARAMS, DIRECTION jz dma_mid_sg;
+			}
+		}
+dma_last_sg:
+		and	DMAPARAMS, ~WIDEODD;
+dma_mid_sg:
+		/* Start DMA data transfer. */
+		mov	DFCNTRL, DMAPARAMS;
+dma_loop:
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			call	idle_loop;
+		}
+		test	SSTAT0,DMADONE	jnz dma_dmadone;
+		test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
+dma_phasemis:
+		/*
+		 * We will be "done" DMAing when the transfer count goes to
+		 * zero, or the target changes the phase (in light of this,
+		 * it makes sense that the DMA circuitry doesn't ACK when
+		 * PHASEMIS is active).  If we are doing a SCSI->Host transfer,
+		 * the data FIFO should be flushed auto-magically on STCNT=0
+		 * or a phase change, so just wait for FIFO empty status.
+		 */
+dma_checkfifo:
+		test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
+dma_fifoflush:
+		test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+dma_fifoempty:
+		/* Don't clobber an inprogress host data transfer */
+		test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
+
+		/*
+		 * Now shut off the DMA and make sure that the DMA
+		 * hardware has actually stopped.  Touching the DMA
+		 * counters, etc. while a DMA is active will result
+		 * in an ILLSADDR exception.
+		 */
+dma_dmadone:
+		and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+		/*
+		 * Some revisions of the aic78XX have a problem where, if the
+		 * data fifo is full, but the PCI input latch is not empty, 
+		 * HDMAEN cannot be cleared.  The fix used here is to drain
+		 * the prefetched but unused data from the data fifo until
+		 * there is space for the input latch to drain.
+		 */
+		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
+			mov	NONE, DFDAT;
+		}
+		test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+
+		/* See if we have completed this last segment */
+		test	STCNT[0], 0xff	jnz data_phase_finish;
+		test	STCNT[1], 0xff	jnz data_phase_finish;
+		test	STCNT[2], 0xff	jnz data_phase_finish;
+
+		/*
+		 * Advance the scatter-gather pointers if needed 
+		 */
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			test	MWI_RESIDUAL, 0xFF jz no_mwi_resid;
+			/*
+			 * Reload HADDR from SHADDR and setup the
+			 * count to be the size of our residual.
+			 */
+			if ((ahc->features & AHC_CMD_CHAN) != 0) {
+				bmov	HADDR, SHADDR, 4;
+				mov	HCNT, MWI_RESIDUAL;
+				bmov	HCNT[1], ALLZEROS, 2;
+			} else {
+				mvi	DINDEX, HADDR;
+				mvi	SHADDR call bcopy_4;
+				mov	MWI_RESIDUAL call set_hcnt;
+			}
+			clr	MWI_RESIDUAL;
+			jmp	sg_load_done;
+no_mwi_resid:
+		}
+		test	SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz sg_load;
+		or	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL;
+		jmp	data_phase_finish;
+sg_load:
+		/*
+		 * Load the next SG element's data address and length
+		 * into the DMA engine.  If we don't have hardware
+		 * to perform a prefetch, we'll have to fetch the
+		 * segment from host memory first.
+		 */
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			/* Wait for the idle loop to complete */
+			test	CCSGCTL, CCSGEN jz . + 3;
+			call	idle_loop;
+			test	CCSGCTL, CCSGEN jnz . - 1;
+			bmov 	HADDR, CCSGRAM, 7;
+			/*
+			 * Workaround for flaky external SCB RAM
+			 * on certain aic7895 setups.  It seems
+			 * unable to handle direct transfers from
+			 * S/G ram to certain SCB locations.
+			 */
+			mov	SINDEX, CCSGRAM;
+			mov	SCB_RESIDUAL_DATACNT[3], SINDEX;
+		} else {
+			if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+				mov	ALLZEROS call set_hhaddr;
+			}
+			mvi	DINDEX, HADDR;
+			mvi	SCB_RESIDUAL_SGPTR	call bcopy_4;
+
+			mvi	SG_SIZEOF	call set_hcnt;
+
+			or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+			call	dma_finish;
+
+			mvi	DINDEX, HADDR;
+			call	dfdat_in_7;
+			mov	SCB_RESIDUAL_DATACNT[3], DFDAT;
+		}
+
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	SCB_RESIDUAL_DATACNT[3] call set_hhaddr;
+
+			/*
+			 * The lowest address byte must be loaded
+			 * last as it triggers the computation of
+			 * some items in the PCI block.  The ULTRA2
+			 * chips do this on PRELOAD.
+			 */
+			mov	HADDR, HADDR;
+		}
+		if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+		  && ahc->pci_cachesize != 0) {
+			call calc_mwi_residual;
+		}
+
+		/* Point to the new next sg in memory */
+		call	sg_advance;
+
+sg_load_done:
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	STCNT, HCNT, 3;
+		} else {
+			call	set_stcnt_from_hcnt;
+		}
+
+		if ((ahc->flags & AHC_TARGETROLE) != 0) {
+			test	SSTAT0, TARGET jnz data_phase_loop;
+		}
+	}
+data_phase_finish:
+	/*
+	 * If the target has left us in data phase, loop through
+	 * the dma code again.  In the case of ULTRA2 adapters,
+	 * we should only loop if there is a data overrun.  For
+	 * all other adapters, we'll loop after each S/G element
+	 * is loaded as well as if there is an overrun.
+	 */
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SSTAT0, TARGET jnz data_phase_done;
+	}
+	if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+		test	SSTAT1, REQINIT jz .;
+		if ((ahc->features & AHC_DT) == 0) {
+			test	SSTAT1,PHASEMIS	jz data_phase_loop;
+		} else {
+			test	SCSIPHASE, DATA_PHASE_MASK jnz data_phase_loop;
+		}
+	}
+
+data_phase_done:
+	/*
+	 * After a DMA finishes, save the SG and STCNT residuals back into
+	 * the SCB.  We use STCNT instead of HCNT, since it's a reflection
+	 * of how many bytes were transferred on the SCSI (as opposed to the
+	 * host) bus.
+	 */
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* Kill off any pending prefetch */
+		call	disable_ccsgen;
+	}
+
+	if ((ahc->features & AHC_ULTRA2) == 0) {
+		/*
+		 * Clear the high address byte so that all other DMA
+		 * operations, which use 32bit addressing, can assume
+		 * HHADDR is 0.
+		 */
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			mov	ALLZEROS call set_hhaddr;
+		}
+	}
+
+	/*
+	 * Update our residual information before the information is
+	 * lost by some other type of SCSI I/O (e.g. PIO).  If we have
+	 * transferred all data, no update is needed.
+	 *
+	 */
+	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jnz residual_update_done;
+	if ((ahc->bugs & AHC_PCI_MWI_BUG) != 0
+	  && ahc->pci_cachesize != 0) {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			test	MWI_RESIDUAL, 0xFF jz bmov_resid;
+		}
+		mov	A, MWI_RESIDUAL;
+		add	SCB_RESIDUAL_DATACNT[0], A, STCNT[0];
+		clr	A;
+		adc	SCB_RESIDUAL_DATACNT[1], A, STCNT[1];
+		adc	SCB_RESIDUAL_DATACNT[2], A, STCNT[2];
+		clr	MWI_RESIDUAL;
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			jmp	. + 2;
+bmov_resid:
+			bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
+		}
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	SCB_RESIDUAL_DATACNT, STCNT, 3;
+	} else {
+		mov	SCB_RESIDUAL_DATACNT[0], STCNT[0];
+		mov	SCB_RESIDUAL_DATACNT[1], STCNT[1];
+		mov	SCB_RESIDUAL_DATACNT[2], STCNT[2];
+	}
+residual_update_done:
+	/*
+	 * Since we've been through a data phase, the SCB_RESID* fields
+	 * are now initialized.  Clear the full residual flag.
+	 */
+	and	SCB_SGPTR[0], ~SG_FULL_RESID;
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		/* Clear the channel in case we return to data phase later */
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+	}
+
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		test	SEQ_FLAGS, DPHASE_PENDING jz ITloop;
+		and	SEQ_FLAGS, ~DPHASE_PENDING;
+		/*
+		 * For data-in phases, wait for any pending acks from the
+		 * initiator before changing phase.  We only need to
+		 * send Ignore Wide Residue messages for data-in phases.
+		 */
+		test	DFCNTRL, DIRECTION jz target_ITloop;
+		test	SSTAT1, REQINIT	jnz .;
+		test	SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop;
+		test	SCSIRATE, WIDEXFER jz target_ITloop;
+		/*
+		 * Issue an Ignore Wide Residue Message.
+		 */
+		mvi	P_MESGIN|BSYO call change_phase;
+		mvi	MSG_IGN_WIDE_RESIDUE call target_outb;
+		mvi	1 call target_outb;
+		jmp	target_ITloop;
+	} else {
+		jmp	ITloop;
+	}
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+	test	SEQ_FLAGS, NOT_IDENTIFIED jz p_command_okay;
+	mvi	PROTO_VIOLATION call set_seqint;
+p_command_okay:
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	HCNT[0], SCB_CDB_LEN,  1;
+		bmov	HCNT[1], ALLZEROS, 2;
+		mvi	SG_CACHE_PRE, LAST_SEG;
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	STCNT[0], SCB_CDB_LEN, 1;
+		bmov	STCNT[1], ALLZEROS, 2;
+	} else {
+		mov	STCNT[0], SCB_CDB_LEN;
+		clr	STCNT[1];
+		clr	STCNT[2];
+	}
+	add	NONE, -13, SCB_CDB_LEN;
+	mvi	SCB_CDB_STORE jnc p_command_embedded;
+p_command_from_host:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		bmov	HADDR[0], SCB_CDB_PTR, 4;
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+	} else {
+		if ((ahc->features & AHC_CMD_CHAN) != 0) {
+			bmov	HADDR[0], SCB_CDB_PTR, 4;
+			bmov	HCNT, STCNT, 3;
+		} else {
+			mvi	DINDEX, HADDR;
+			mvi	SCB_CDB_PTR call bcopy_4;
+			mov	SCB_CDB_LEN call set_hcnt;
+		}
+		mvi	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET);
+	}
+	jmp	p_command_xfer;
+p_command_embedded:
+	/*
+	 * The data fifo seems to require 4 byte aligned
+	 * transfers from the sequencer.  Force this to
+	 * be the case by clearing HADDR[0] even though
+	 * we aren't going to touch host memory.
+	 */
+	clr	HADDR[0];
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|DIRECTION);
+		bmov	DFDAT, SCB_CDB_STORE, 12; 
+	} else if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			/*
+			 * On the 7895 the data FIFO will
+			 * get corrupted if you try to dump
+			 * data from external SCB memory into
+			 * the FIFO while it is enabled.  So,
+			 * fill the fifo and then enable SCSI
+			 * transfers.
+			 */
+			mvi	DFCNTRL, (DIRECTION|FIFORESET);
+		} else {
+			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
+		}
+		bmov	DFDAT, SCB_CDB_STORE, 12; 
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFOFLUSH);
+		} else {
+			or	DFCNTRL, FIFOFLUSH;
+		}
+	} else {
+		mvi	DFCNTRL, (SCSIEN|SDMAEN|DIRECTION|FIFORESET);
+		call	copy_to_fifo_6;
+		call	copy_to_fifo_6;
+		or	DFCNTRL, FIFOFLUSH;
+	}
+p_command_xfer:
+	and	SEQ_FLAGS, ~NO_CDB_SENT;
+	if ((ahc->features & AHC_DT) == 0) {
+		test	SSTAT0, SDONE jnz . + 2;
+		test    SSTAT1, PHASEMIS jz . - 1;
+		/*
+		 * Wait for our ACK to go-away on it's own
+		 * instead of being killed by SCSIEN getting cleared.
+		 */
+		test	SCSISIGI, ACKI jnz .;
+	} else {
+		test	DFCNTRL, SCSIEN jnz .;
+	}
+	test	SSTAT0, SDONE jnz p_command_successful;
+	/*
+	 * Don't allow a data phase if the command
+	 * was not fully transferred.
+	 */
+	or	SEQ_FLAGS, NO_CDB_SENT;
+p_command_successful:
+	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz .;
+	jmp	ITloop;
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+	test	SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
+p_status_okay:
+	mov	SCB_SCSI_STATUS, SCSIDATL;
+	or	SCB_CONTROL, STATUS_RCVD;
+	jmp	ITloop;
+
+/*
+ * Message out phase.  If MSG_OUT is MSG_IDENTIFYFLAG, build a full
+ * indentify message sequence and send it to the target.  The host may
+ * override this behavior by setting the MK_MESSAGE bit in the SCB
+ * control byte.  This will cause us to interrupt the host and allow
+ * it to handle the message phase completely on its own.  If the bit
+ * associated with this target is set, we will also interrupt the host,
+ * thereby allowing it to send a message on the next selection regardless
+ * of the transaction being sent.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the host to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+ *
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
+ */
+p_mesgout_retry:
+	/* Turn on ATN for the retry */
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SCSISIGO, ATNO, LASTPHASE;
+	} else {
+		mvi	SCSISIGO, ATNO;
+	}
+p_mesgout:
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+	test	SCB_CONTROL,MK_MESSAGE	jnz host_message_loop;
+p_mesgout_identify:
+	or	SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN;
+	test	SCB_CONTROL, DISCENB jnz . + 2;
+	and	SINDEX, ~DISCENB;
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDATL, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCB_TAG	jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to handle this message
+ * phase and any required retries.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	jmp	host_message_loop;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDATL, SINDEX;
+
+/*
+ * If the next bus phase after ATN drops is message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	je p_mesgout_retry;
+
+p_mesgout_done:
+	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
+	mov	LAST_MSG, MSG_OUT;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
+	jmp	ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
+
+	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
+	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
+	cmp	ALLZEROS,A		je mesgin_complete;
+	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
+	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_ign_wide_residue;
+	cmp	A,MSG_NOOP		je mesgin_done;
+
+/*
+ * Pushed message loop to allow the kernel to
+ * run it's own message state engine.  To avoid an
+ * extra nop instruction after signaling the kernel,
+ * we perform the phase_lock before checking to see
+ * if we should exit the loop and skip the phase_lock
+ * in the ITloop.  Performing back to back phase_locks
+ * shouldn't hurt, but why do it twice...
+ */
+host_message_loop:
+	mvi	HOST_MSG_LOOP call set_seqint;
+	call	phase_lock;
+	cmp	RETURN_1, EXIT_MSG_LOOP	je ITloop + 1;
+	jmp	host_message_loop;
+
+mesgin_ign_wide_residue:
+if ((ahc->features & AHC_WIDE) != 0) {
+	test	SCSIRATE, WIDEXFER jz mesgin_reject;
+	/* Pull the residue byte */
+	mvi	ARG_1	call inb_next;
+	cmp	ARG_1, 0x01 jne mesgin_reject;
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2;
+	test	SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done;
+	mvi	IGN_WIDE_RES call set_seqint;
+	jmp	mesgin_done;
+}
+
+mesgin_proto_violation:
+	mvi	PROTO_VIOLATION call set_seqint;
+	jmp	mesgin_done;
+mesgin_reject:
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+mesgin_done:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+	jmp	ITloop;
+
+/*
+ * We received a "command complete" message.  Put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt.  Before doing so, check to see if there
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
+ * process this information.  In the case of a non zero status byte, we 
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved.  If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command, requeue
+ * it to the QINFIFO and tell us not to post to the QOUTFIFO by setting 
+ * RETURN_1 to SEND_SENSE.
+ */
+mesgin_complete:
+
+	/*
+	 * If ATN is raised, we still want to give the target a message.
+	 * Perhaps there was a parity error on this last message byte.
+	 * Either way, the target should take us to message out phase
+	 * and then attempt to complete the command again.  We should use a
+	 * critical section here to guard against a timeout triggering
+	 * for this command and setting ATN while we are still processing
+	 * the completion.
+	test	SCSISIGI, ATNI jnz mesgin_done;
+	 */
+
+	/*
+	 * If we are identified and have successfully sent the CDB,
+	 * any status will do.  Optimize this fast path.
+	 */
+	test	SCB_CONTROL, STATUS_RCVD jz mesgin_proto_violation;
+	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT jz complete_accepted; 
+
+	/*
+	 * If the target never sent an identify message but instead went
+	 * to mesgin to give an invalid message, let the host abort us.
+	 */
+	test	SEQ_FLAGS, NOT_IDENTIFIED jnz mesgin_proto_violation;
+
+	/*
+	 * If we recevied good status but never successfully sent the
+	 * cdb, abort the command.
+	 */
+	test	SCB_SCSI_STATUS,0xff	jnz complete_accepted;
+	test	SEQ_FLAGS, NO_CDB_SENT jnz mesgin_proto_violation;
+
+complete_accepted:
+	/*
+	 * See if we attempted to deliver a message but the target ingnored us.
+	 */
+	test	SCB_CONTROL, MK_MESSAGE jz . + 2;
+	mvi	MKMSG_FAILED call set_seqint;
+
+	/*
+	 * Check for residuals
+	 */
+	test	SCB_SGPTR, SG_LIST_NULL jnz check_status;/* No xfer */
+	test	SCB_SGPTR, SG_FULL_RESID jnz upload_scb;/* Never xfered */
+	test	SCB_RESIDUAL_SGPTR, SG_LIST_NULL jz upload_scb;
+check_status:
+	test	SCB_SCSI_STATUS,0xff	jz complete;	/* Good Status? */
+upload_scb:
+	or	SCB_SGPTR, SG_RESID_VALID;
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+	test	SCB_SCSI_STATUS, 0xff	jz complete;	/* Just a residual? */
+	mvi	BAD_STATUS call set_seqint;		/* let driver know */
+	cmp	RETURN_1, SEND_SENSE	jne complete;
+	call	add_scb_to_free_list;
+	jmp	await_busfree;
+complete:
+	mov	SCB_TAG call complete_post;
+	jmp	await_busfree;
+}
+
+complete_post:
+	/* Post the SCBID in SINDEX and issue an interrupt */
+	call	add_scb_to_free_list;
+	mov	ARG_1, SINDEX;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		mov	A, SDSCB_QOFF;
+	} else {
+		mov	A, QOUTPOS;
+	}
+	mvi	QOUTFIFO_OFFSET call post_byte_setup;
+	mov	ARG_1 call post_byte;
+	if ((ahc->features & AHC_QUEUE_REGS) == 0) {
+		inc 	QOUTPOS;
+	}
+	mvi	INTSTAT,CMDCMPLT ret;
+
+if ((ahc->flags & AHC_INITIATORROLE) != 0) {
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.  If this is an untagged transaction
+ * store the SCB id for it in our untagged target table for lookup on
+ * a reselction.
+ */
+mesgin_disconnect:
+	/*
+	 * If ATN is raised, we still want to give the target a message.
+	 * Perhaps there was a parity error on this last message byte
+	 * or we want to abort this command.  Either way, the target
+	 * should take us to message out phase and then attempt to
+	 * disconnect again.
+	 * XXX - Wait for more testing.
+	test	SCSISIGI, ATNI jnz mesgin_done;
+	 */
+	test	SEQ_FLAGS, NOT_IDENTIFIED|NO_CDB_SENT
+		jnz mesgin_proto_violation;
+	or	SCB_CONTROL,DISCONNECTED;
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		call	add_scb_to_disc_list;
+	}
+	test	SCB_CONTROL, TAG_ENB jnz await_busfree;
+	mov	ARG_1, SCB_TAG;
+	and	SAVED_LUN, LID, SCB_LUN;
+	mov	SCB_SCSIID	call set_busy_target;
+	jmp	await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ * Ack the message as soon as possible.  For chips without S/G pipelining,
+ * we can only ack the message after SHADDR has been saved.  On these
+ * chips, SHADDR increments with every bus transaction, even PIO.
+ */
+mesgin_sdptrs:
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+		test	SEQ_FLAGS, DPHASE	jz ITloop;
+	} else {
+		test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+	}
+
+	/*
+	 * If we are asked to save our position at the end of the
+	 * transfer, just mark us at the end rather than perform a
+	 * full save.
+	 */
+	test	SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz mesgin_sdptrs_full;
+	or	SCB_SGPTR, SG_LIST_NULL;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		jmp	ITloop;
+	} else {
+		jmp	mesgin_done;
+	}
+
+mesgin_sdptrs_full:
+
+	/*
+	 * The SCB_SGPTR becomes the next one we'll download,
+	 * and the SCB_DATAPTR becomes the current SHADDR.
+	 * Use the residual number since STCNT is corrupted by
+	 * any message transfer.
+	 */
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	SCB_DATAPTR, SHADDR, 4;
+		if ((ahc->features & AHC_ULTRA2) == 0) {
+			mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
+		}
+		bmov	SCB_DATACNT, SCB_RESIDUAL_DATACNT, 8;
+	} else {
+		mvi	DINDEX, SCB_DATAPTR;
+		mvi	SHADDR call bcopy_4;
+		mov	NONE,SCSIDATL;	/*dummy read from latch to ACK*/
+		mvi	SCB_RESIDUAL_DATACNT call bcopy_8;
+	}
+	jmp	ITloop;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.  We also reset/reallocate the FIFO to make
+ * sure we have a clean start for the next data or command phase.
+ */
+mesgin_rdptrs:
+	and	SEQ_FLAGS, ~DPHASE;		/*
+						 * We'll reload them
+						 * the next time through
+						 * the dataphase.
+						 */
+	or	SXFRCTL0, CLRSTCNT|CLRCHN;
+	jmp	mesgin_done;
+
+/*
+ * Index into our Busy Target table.  SINDEX and DINDEX are modified
+ * upon return.  SCBPTR may be modified by this action.
+ */
+set_busy_target:
+	shr	DINDEX, 4, SINDEX;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	SCBPTR, SAVED_LUN;
+		add	DINDEX, SCB_64_BTT;
+	} else {
+		add	DINDEX, BUSY_TARGETS;
+	}
+	mov	DINDIR, ARG_1 ret;
+
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
+mesgin_identify:
+	/*
+	 * Determine whether a target is using tagged or non-tagged
+	 * transactions by first looking at the transaction stored in
+	 * the busy target array.  If there is no untagged transaction
+	 * for this target or the transaction is for a different lun, then
+	 * this must be a tagged transaction.
+	 */
+	shr	SINDEX, 4, SAVED_SCSIID;
+	and	SAVED_LUN, MSG_IDENTIFY_LUNMASK, A;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		add	SINDEX, SCB_64_BTT;
+		mov	SCBPTR, SAVED_LUN;
+		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+			add	NONE, -SCB_64_BTT, SINDEX;
+			jc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+			add	NONE, -(SCB_64_BTT + 16), SINDEX;
+			jnc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+		}
+	} else {
+		add	SINDEX, BUSY_TARGETS;
+		if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+			add	NONE, -BUSY_TARGETS, SINDEX;
+			jc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+			add	NONE, -(BUSY_TARGETS + 16), SINDEX;
+			jnc	. + 2;
+			mvi	INTSTAT, OUT_OF_RANGE;
+			nop;
+		}
+	}
+	mov	ARG_1, SINDIR;
+	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		mov	ARG_1 call findSCB;
+	} else {
+		mov	SCBPTR, ARG_1;
+	}
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		jmp setup_SCB_id_lun_okay;
+	} else {
+		/*
+		 * We only allow one untagged command per-target
+		 * at a time.  So, if the lun doesn't match, look
+		 * for a tag message.
+		 */
+		and	A, LID, SCB_LUN;
+		cmp	SAVED_LUN, A	je setup_SCB_id_lun_okay;
+		if ((ahc->flags & AHC_PAGESCBS) != 0) {
+			/*
+			 * findSCB removes the SCB from the
+			 * disconnected list, so we must replace
+			 * it there should this SCB be for another
+			 * lun.
+			 */
+			call	cleanup_scb;
+		}
+	}
+
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB.  With SCB paging, we must search for non-tagged
+ * transactions since the SCB may exist in any slot.  If we're not
+ * using SCB paging, we can use the tag as the direct index to the
+ * SCB.
+ */
+snoop_tag:
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x80;
+	}
+	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
+	call	phase_lock;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x1;
+	}
+	cmp	LASTPHASE, P_MESGIN	jne not_found;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x2;
+	}
+	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		mvi	ARG_1	call inb_next;	/* tag value */
+		mov	ARG_1	call findSCB;
+	} else {
+		mvi	ARG_1	call inb_next;	/* tag value */
+		mov	SCBPTR, ARG_1;
+	}
+
+/*
+ * Ensure that the SCB the tag points to is for
+ * an SCB transaction to the reconnecting target.
+ */
+setup_SCB:
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x4;
+	}
+	mov	A, SCB_SCSIID;
+	cmp	SAVED_SCSIID, A	jne not_found_cleanup_scb;
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x8;
+	}
+setup_SCB_id_okay:
+	and	A, LID, SCB_LUN;
+	cmp	SAVED_LUN, A	jne not_found_cleanup_scb;
+setup_SCB_id_lun_okay:
+	if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) {
+		or	SEQ_FLAGS, 0x10;
+	}
+	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
+	and	SCB_CONTROL,~DISCONNECTED;
+	test	SCB_CONTROL, TAG_ENB	jnz setup_SCB_tagged;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	A, SCBPTR;
+	}
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	SAVED_SCSIID	call	set_busy_target;
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		mov	SCBPTR, A;
+	}
+setup_SCB_tagged:
+	clr	SEQ_FLAGS;	/* make note of IDENTIFY */
+	call	set_transfer_settings;
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	mvi	HOST_MSG	call mk_mesg;
+	jmp	mesgin_done;
+
+not_found_cleanup_scb:
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		call	cleanup_scb;
+	}
+not_found:
+	mvi	NO_MATCH call set_seqint;
+	jmp	mesgin_done;
+
+mk_mesg:
+	if ((ahc->features & AHC_DT) == 0) {
+		or	SCSISIGO, ATNO, LASTPHASE;
+	} else {
+		mvi	SCSISIGO, ATNO;
+	}
+	mov	MSG_OUT,SINDEX ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+inb_next_wait_perr:
+	mvi	PERR_DETECTED call set_seqint;
+	jmp	inb_next_wait;
+inb_next:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+inb_next_wait:
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SSTAT1, REQINIT	jz inb_next_wait;
+	test	SSTAT1, SCSIPERR jnz inb_next_wait_perr;
+inb_next_check_phase:
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+	mov	DINDEX,SINDEX;
+	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
+inb_last:
+	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+}
+
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
+/*
+ * Change to a new phase.  If we are changing the state of the I/O signal,
+ * from out to in, wait an additional data release delay before continuing.
+ */
+change_phase:
+	/* Wait for preceeding I/O session to complete. */
+	test	SCSISIGI, ACKI jnz .;
+
+	/* Change the phase */
+	and	DINDEX, IOI, SCSISIGI;
+	mov	SCSISIGO, SINDEX;
+	and	A, IOI, SINDEX;
+
+	/*
+	 * If the data direction has changed, from
+	 * out (initiator driving) to in (target driving),
+	 * we must wait at least a data release delay plus
+	 * the normal bus settle delay. [SCSI III SPI 10.11.0]
+	 */
+	cmp 	DINDEX, A je change_phase_wait;
+	test	SINDEX, IOI jz change_phase_wait;
+	call	change_phase_wait;
+change_phase_wait:
+	nop;
+	nop;
+	nop;
+	nop ret;
+
+/*
+ * Send a byte to an initiator in Automatic PIO mode.
+ */
+target_outb:
+	or	SXFRCTL0, SPIOEN;
+	test	SSTAT0, SPIORDY	jz .;
+	mov	SCSIDATL, SINDEX;
+	test	SSTAT0, SPIORDY	jz .;
+	and	SXFRCTL0, ~SPIOEN ret;
+}
+	
+/*
+ * Locate a disconnected SCB by SCBID.  Upon return, SCBPTR and SINDEX will
+ * be set to the position of the SCB.  If the SCB cannot be found locally,
+ * it will be paged in from host memory.  RETURN_2 stores the address of the
+ * preceding SCB in the disconnected list which can be used to speed up
+ * removal of the found SCB from the disconnected list.
+ */
+if ((ahc->flags & AHC_PAGESCBS) != 0) {
+BEGIN_CRITICAL;
+findSCB:
+	mov	A, SINDEX;			/* Tag passed in SINDEX */
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je findSCB_notFound;
+	mov	SCBPTR, DISCONNECTED_SCBH;	/* Initialize SCBPTR */
+	mvi	ARG_2, SCB_LIST_NULL;		/* Head of list */
+	jmp	findSCB_loop;
+findSCB_next:
+	cmp	SCB_NEXT, SCB_LIST_NULL je findSCB_notFound;
+	mov	ARG_2, SCBPTR;
+	mov	SCBPTR,SCB_NEXT;
+findSCB_loop:
+	cmp	SCB_TAG, A	jne findSCB_next;
+rem_scb_from_disc_list:
+	cmp	ARG_2, SCB_LIST_NULL	je rHead;
+	mov	DINDEX, SCB_NEXT;
+	mov	SINDEX, SCBPTR;
+	mov	SCBPTR, ARG_2;
+	mov	SCB_NEXT, DINDEX;
+	mov	SCBPTR, SINDEX ret;
+rHead:
+	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
+END_CRITICAL;
+findSCB_notFound:
+	/*
+	 * We didn't find it.  Page in the SCB.
+	 */
+	mov	ARG_1, A; /* Save tag */
+	mov	ALLZEROS call get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	ARG_1	jmp dma_scb;
+}
+
+/*
+ * Prepare the hardware to post a byte to host memory given an
+ * index of (A + (256 * SINDEX)) and a base address of SHARED_DATA_ADDR.
+ */
+post_byte_setup:
+	mov	ARG_2, SINDEX;
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
+		mvi	CCHCNT, 1;
+		mvi	CCSCBCTL, CCSCBRESET ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SHARED_DATA_ADDR call	set_1byte_addr;
+		mvi	1	call set_hcnt;
+		mvi	DFCNTRL, FIFORESET ret;
+	}
+
+post_byte:
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		bmov	CCSCBRAM, SINDEX, 1;
+		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+		test	CCSCBCTL, CCSCBDONE jz .;
+		clr	CCSCBCTL ret;
+	} else {
+		mov	DFDAT, SINDEX;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
+	}
+
+phase_lock_perr:
+	mvi	PERR_DETECTED call set_seqint;
+phase_lock:     
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SSTAT1, REQINIT jz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock_perr;
+phase_lock_latch_phase:
+	if ((ahc->features & AHC_DT) == 0) {
+		and	SCSISIGO, PHASE_MASK, SCSISIGI;
+	}
+	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
+
+if ((ahc->features & AHC_CMD_CHAN) == 0) {
+set_hcnt:
+	mov	HCNT[0], SINDEX;
+clear_hcnt:
+	clr	HCNT[1];
+	clr	HCNT[2] ret;
+
+set_stcnt_from_hcnt:
+	mov	STCNT[0], HCNT[0];
+	mov	STCNT[1], HCNT[1];
+	mov	STCNT[2], HCNT[2] ret;
+
+bcopy_8:
+	mov	DINDIR, SINDIR;
+bcopy_7:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+bcopy_5:
+	mov	DINDIR, SINDIR;
+bcopy_4:
+	mov	DINDIR, SINDIR;
+bcopy_3:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR ret;
+}
+
+if ((ahc->flags & AHC_TARGETROLE) != 0) {
+/*
+ * Setup addr assuming that A is an index into
+ * an array of 32byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
+ */
+set_32byte_addr:
+	shr	ARG_2, 3, A;
+	shl	A, 5;
+	jmp	set_1byte_addr;
+}
+
+/*
+ * Setup addr assuming that A is an index into
+ * an array of 64byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
+ */
+set_64byte_addr:
+	shr	ARG_2, 2, A;
+	shl	A, 6;
+
+/*
+ * Setup addr assuming that A + (ARG_2 * 256) is an
+ * index into an array of 1byte objects, SINDEX contains
+ * the base address of that array, and DINDEX contains
+ * the base address of the location to store the computed
+ * address.
+ */
+set_1byte_addr:
+	add     DINDIR, A, SINDIR;
+	mov     A, ARG_2;
+	adc	DINDIR, A, SINDIR;
+	clr	A;
+	adc	DINDIR, A, SINDIR;
+	adc	DINDIR, A, SINDIR ret;
+
+/*
+ * Either post or fetch an SCB from host memory based on the
+ * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
+ */
+dma_scb:
+	mov	A, SINDEX;
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	HSCB_ADDR call set_64byte_addr;
+		mov	CCSCBPTR, SCBPTR;
+		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			mvi	CCHCNT, SCB_DOWNLOAD_SIZE_64;
+		} else {
+			mvi	CCHCNT, SCB_DOWNLOAD_SIZE;
+		}
+		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
+		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
+		jmp	dma_scb_finish;
+dma_scb_tohost:
+		mvi	CCHCNT, SCB_UPLOAD_SIZE;
+		if ((ahc->features & AHC_ULTRA2) == 0) {
+			mvi	CCSCBCTL, CCSCBRESET;
+			bmov	CCSCBRAM, SCB_BASE, SCB_UPLOAD_SIZE;
+			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			test	CCSCBCTL, CCSCBDONE jz .;
+		} else if ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0) {
+			mvi	CCSCBCTL, CCARREN|CCSCBRESET;
+			cmp	CCSCBCTL, ARRDONE|CCARREN jne .;
+			mvi	CCHCNT, SCB_UPLOAD_SIZE;
+			mvi	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			cmp	CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+		} else {
+			mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+			cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+		}
+dma_scb_finish:
+		clr	CCSCBCTL;
+		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
+		ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	HSCB_ADDR call set_64byte_addr;
+		mvi	SCB_DOWNLOAD_SIZE call set_hcnt;
+		mov	DFCNTRL, DMAPARAMS;
+		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
+		/* Fill it with the SCB data */
+copy_scb_tofifo:
+		mvi	SINDEX, SCB_BASE;
+		add	A, SCB_DOWNLOAD_SIZE, SINDEX;
+copy_scb_tofifo_loop:
+		call	copy_to_fifo_8;
+		cmp	SINDEX, A jne copy_scb_tofifo_loop;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
+dma_scb_fromhost:
+		mvi	DINDEX, SCB_BASE;
+		if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0) {
+			/*
+			 * The PCI module will only issue a PCI
+			 * retry if the data FIFO is empty.  If the
+			 * host disconnects in the middle of a
+			 * transfer, we must empty the fifo of all
+			 * available data to force the chip to
+			 * continue the transfer.  This does not
+			 * happen for SCSI transfers as the SCSI module
+			 * will drain the FIFO as data are made available.
+			 * When the hang occurs, we know that a multiple
+			 * of 8 bytes is in the FIFO because the PCI
+			 * module has an 8 byte input latch that only
+			 * dumps to the FIFO when HCNT == 0 or the
+			 * latch is full.
+			 */
+			clr	A;
+			/* Wait for at least 8 bytes of data to arrive. */
+dma_scb_hang_fifo:
+			test	DFSTATUS, FIFOQWDEMP jnz dma_scb_hang_fifo;
+dma_scb_hang_wait:
+			test	DFSTATUS, MREQPEND jnz dma_scb_hang_wait;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE	jnz dma_scb_hang_dma_done;
+			/*
+			 * The PCI module no longer intends to perform
+			 * a PCI transaction.  Drain the fifo.
+			 */
+dma_scb_hang_dma_drain_fifo:
+			not	A, HCNT;
+			add	A, SCB_DOWNLOAD_SIZE+SCB_BASE+1;
+			and	A, ~0x7;
+			mov	DINDIR,DFDAT;
+			cmp	DINDEX, A jne . - 1;
+			cmp	DINDEX, SCB_DOWNLOAD_SIZE+SCB_BASE
+				je	dma_finish_nowait;
+			/* Restore A as the lines left to transfer. */
+			add	A, -SCB_BASE, DINDEX;
+			shr	A, 3;
+			jmp	dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+			and	DFCNTRL, ~HDMAEN;
+			test	DFCNTRL, HDMAEN jnz .;
+			add	SEQADDR0, A;
+		} else {
+			call	dma_finish;
+		}
+		call	dfdat_in_8;
+		call	dfdat_in_8;
+		call	dfdat_in_8;
+dfdat_in_8:
+		mov	DINDIR,DFDAT;
+dfdat_in_7:
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+dfdat_in_2:
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT ret;
+	}
+
+copy_to_fifo_8:
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+copy_to_fifo_6:
+	mov	DFDAT,SINDIR;
+copy_to_fifo_5:
+	mov	DFDAT,SINDIR;
+copy_to_fifo_4:
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR;
+	mov	DFDAT,SINDIR ret;
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+dma_finish:
+	test	DFSTATUS,HDONE	jz dma_finish;
+dma_finish_nowait:
+	/* Turn off DMA */
+	and	DFCNTRL, ~HDMAEN;
+	test	DFCNTRL, HDMAEN jnz .;
+	ret;
+
+/*
+ * Restore an SCB that failed to match an incoming reselection
+ * to the correct/safe state.  If the SCB is for a disconnected
+ * transaction, it must be returned to the disconnected list.
+ * If it is not in the disconnected state, it must be free.
+ */
+cleanup_scb:
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		test	SCB_CONTROL,DISCONNECTED jnz add_scb_to_disc_list;
+	}
+add_scb_to_free_list:
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+BEGIN_CRITICAL;
+		mov	SCB_NEXT, FREE_SCBH;
+		mvi	SCB_TAG, SCB_LIST_NULL;
+		mov	FREE_SCBH, SCBPTR ret;
+END_CRITICAL;
+	} else {
+		mvi	SCB_TAG, SCB_LIST_NULL ret;
+	}
+
+if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+set_hhaddr:
+	or	DSCOMMAND1, HADDLDSEL0;
+	and	HADDR, SG_HIGH_ADDR_BITS, SINDEX;
+	and	DSCOMMAND1, ~HADDLDSEL0 ret;
+}
+
+if ((ahc->flags & AHC_PAGESCBS) != 0) {
+get_free_or_disc_scb:
+BEGIN_CRITICAL;
+	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+	mvi	NO_FREE_SCB call set_seqint;
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+dequeue_disc_scb:
+	mov	SCBPTR, DISCONNECTED_SCBH;
+	mov	DISCONNECTED_SCBH, SCB_NEXT;
+END_CRITICAL;
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG	jmp dma_scb;
+BEGIN_CRITICAL;
+dequeue_free_scb:
+	mov	SCBPTR, FREE_SCBH;
+	mov	FREE_SCBH, SCB_NEXT ret;
+END_CRITICAL;
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+BEGIN_CRITICAL;
+	mov	SCB_NEXT, DISCONNECTED_SCBH;
+	mov	DISCONNECTED_SCBH, SCBPTR ret;
+END_CRITICAL;
+}
+set_seqint:
+	mov	INTSTAT, SINDEX;
+	nop;
+return:
+	ret;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.c b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
new file mode 100644
index 0000000..468d612
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.c
@@ -0,0 +1,306 @@
+/*
+ * Interface for the 93C66/56/46/26/06 serial eeprom parts.
+ *
+ * Copyright (c) 1995, 1996 Daniel M. Eischen
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.c#17 $
+ *
+ * $FreeBSD$
+ */
+
+/*
+ *   The instruction set of the 93C66/56/46/26/06 chips are as follows:
+ *
+ *               Start  OP	    *
+ *     Function   Bit  Code  Address**  Data     Description
+ *     -------------------------------------------------------------------
+ *     READ        1    10   A5 - A0             Reads data stored in memory,
+ *                                               starting at specified address
+ *     EWEN        1    00   11XXXX              Write enable must precede
+ *                                               all programming modes
+ *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
+ *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
+ *     ERAL        1    00   10XXXX              Erase all registers
+ *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
+ *     EWDS        1    00   00XXXX              Disables all programming
+ *                                               instructions
+ *     *Note: A value of X for address is a don't care condition.
+ *    **Note: There are 8 address bits for the 93C56/66 chips unlike
+ *	      the 93C46/26/06 chips which have 6 address bits.
+ *
+ *   The 93C46 has a four wire interface: clock, chip select, data in, and
+ *   data out.  In order to perform one of the above functions, you need
+ *   to enable the chip select for a clock period (typically a minimum of
+ *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ *   respectively).  While the chip select remains high, you can clock in
+ *   the instructions (above) starting with the start bit, followed by the
+ *   OP code, Address, and Data (if needed).  For the READ instruction, the
+ *   requested 16-bit register contents is read from the data out line but
+ *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ *   first).  The clock cycling from low to high initiates the next data
+ *   bit to be sent from the chip.
+ *
+ */
+
+#ifdef __linux__
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+#else
+#include <dev/aic7xxx/aic7xxx_osm.h>
+#include <dev/aic7xxx/aic7xxx_inline.h>
+#include <dev/aic7xxx/aic7xxx_93cx6.h>
+#endif
+
+/*
+ * Right now, we only have to read the SEEPROM.  But we make it easier to
+ * add other 93Cx6 functions.
+ */
+static struct seeprom_cmd {
+  	uint8_t len;
+ 	uint8_t bits[9];
+} seeprom_read = {3, {1, 1, 0}};
+
+static struct seeprom_cmd seeprom_ewen = {9, {1, 0, 0, 1, 1, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_ewds = {9, {1, 0, 0, 0, 0, 0, 0, 0, 0}};
+static struct seeprom_cmd seeprom_write = {3, {1, 0, 1}};
+
+/*
+ * Wait for the SEERDY to go high; about 800 ns.
+ */
+#define CLOCK_PULSE(sd, rdy)				\
+	while ((SEEPROM_STATUS_INB(sd) & rdy) == 0) {	\
+		;  /* Do nothing */			\
+	}						\
+	(void)SEEPROM_INB(sd);	/* Clear clock */
+
+/*
+ * Send a START condition and the given command
+ */
+static void
+send_seeprom_cmd(struct seeprom_descriptor *sd, struct seeprom_cmd *cmd)
+{
+	uint8_t temp;
+	int i = 0;
+
+	/* Send chip select for one clock cycle. */
+	temp = sd->sd_MS ^ sd->sd_CS;
+	SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+
+	for (i = 0; i < cmd->len; i++) {
+		if (cmd->bits[i] != 0)
+			temp ^= sd->sd_DO;
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		if (cmd->bits[i] != 0)
+			temp ^= sd->sd_DO;
+	}
+}
+
+/*
+ * Clear CS put the chip in the reset state, where it can wait for new commands.
+ */
+static void
+reset_seeprom(struct seeprom_descriptor *sd)
+{
+	uint8_t temp;
+
+	temp = sd->sd_MS;
+	SEEPROM_OUTB(sd, temp);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+	SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+	SEEPROM_OUTB(sd, temp);
+	CLOCK_PULSE(sd, sd->sd_RDY);
+}
+
+/*
+ * Read the serial EEPROM and returns 1 if successful and 0 if
+ * not successful.
+ */
+int
+ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		 u_int start_addr, u_int count)
+{
+	int i = 0;
+	u_int k = 0;
+	uint16_t v;
+	uint8_t temp;
+
+	/*
+	 * Read the requested registers of the seeprom.  The loop
+	 * will range from 0 to count-1.
+	 */
+	for (k = start_addr; k < count + start_addr; k++) {
+		/*
+		 * Now we're ready to send the read command followed by the
+		 * address of the 16-bit register we want to read.
+		 */
+		send_seeprom_cmd(sd, &seeprom_read);
+
+		/* Send the 6 or 8 bit address (MSB first, LSB last). */
+		temp = sd->sd_MS ^ sd->sd_CS;
+		for (i = (sd->sd_chip - 1); i >= 0; i--) {
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/*
+		 * Now read the 16 bit register.  An initial 0 precedes the
+		 * register contents which begins with bit 15 (MSB) and ends
+		 * with bit 0 (LSB).  The initial 0 will be shifted off the
+		 * top of our word as we let the loop run from 0 to 16.
+		 */
+		v = 0;
+		for (i = 16; i >= 0; i--) {
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			v <<= 1;
+			if (SEEPROM_DATA_INB(sd) & sd->sd_DI)
+				v |= 1;
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+		}
+
+		buf[k - start_addr] = v;
+
+		/* Reset the chip select for the next command cycle. */
+		reset_seeprom(sd);
+	}
+#ifdef AHC_DUMP_EEPROM
+	printf("\nSerial EEPROM:\n\t");
+	for (k = 0; k < count; k = k + 1) {
+		if (((k % 8) == 0) && (k != 0)) {
+			printf ("\n\t");
+		}
+		printf (" 0x%x", buf[k]);
+	}
+	printf ("\n");
+#endif
+	return (1);
+}
+
+/*
+ * Write the serial EEPROM and return 1 if successful and 0 if
+ * not successful.
+ */
+int
+ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		  u_int start_addr, u_int count)
+{
+	uint16_t v;
+	uint8_t temp;
+	int i, k;
+
+	/* Place the chip into write-enable mode */
+	send_seeprom_cmd(sd, &seeprom_ewen);
+	reset_seeprom(sd);
+
+	/* Write all requested data out to the seeprom. */
+	temp = sd->sd_MS ^ sd->sd_CS;
+	for (k = start_addr; k < count + start_addr; k++) {
+		/* Send the write command */
+		send_seeprom_cmd(sd, &seeprom_write);
+
+		/* Send the 6 or 8 bit address (MSB first). */
+		for (i = (sd->sd_chip - 1); i >= 0; i--) {
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((k & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/* Write the 16 bit value, MSB first */
+		v = buf[k - start_addr];
+		for (i = 15; i >= 0; i--) {
+			if ((v & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			if ((v & (1 << i)) != 0)
+				temp ^= sd->sd_DO;
+		}
+
+		/* Wait for the chip to complete the write */
+		temp = sd->sd_MS;
+		SEEPROM_OUTB(sd, temp);
+		CLOCK_PULSE(sd, sd->sd_RDY);
+		temp = sd->sd_MS ^ sd->sd_CS;
+		do {
+			SEEPROM_OUTB(sd, temp);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+			SEEPROM_OUTB(sd, temp ^ sd->sd_CK);
+			CLOCK_PULSE(sd, sd->sd_RDY);
+		} while ((SEEPROM_DATA_INB(sd) & sd->sd_DI) == 0);
+
+		reset_seeprom(sd);
+	}
+
+	/* Put the chip back into write-protect mode */
+	send_seeprom_cmd(sd, &seeprom_ewds);
+	reset_seeprom(sd);
+
+	return (1);
+}
+
+int
+ahc_verify_cksum(struct seeprom_config *sc)
+{
+	int i;
+	int maxaddr;
+	uint32_t checksum;
+	uint16_t *scarray;
+
+	maxaddr = (sizeof(*sc)/2) - 1;
+	checksum = 0;
+	scarray = (uint16_t *)sc;
+
+	for (i = 0; i < maxaddr; i++)
+		checksum = checksum + scarray[i];
+	if (checksum == 0
+	 || (checksum & 0xFFFF) != sc->checksum) {
+		return (0);
+	} else {
+		return(1);
+	}
+}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_93cx6.h b/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
new file mode 100644
index 0000000..859c43c
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_93cx6.h
@@ -0,0 +1,102 @@
+/*
+ * Interface to the 93C46/56 serial EEPROM that is used to store BIOS
+ * settings for the aic7xxx based adaptec SCSI controllers.  It can
+ * also be used for 93C26 and 93C06 serial EEPROMS.
+ *
+ * Copyright (c) 1994, 1995, 2000 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_93cx6.h#12 $
+ *
+ * $FreeBSD$
+ */
+#ifndef _AIC7XXX_93CX6_H_
+#define _AIC7XXX_93CX6_H_
+
+typedef enum {
+	C46 = 6,
+	C56_66 = 8
+} seeprom_chip_t;
+
+struct seeprom_descriptor {
+	struct ahc_softc *sd_ahc;
+	u_int sd_control_offset;
+	u_int sd_status_offset;
+	u_int sd_dataout_offset;
+	seeprom_chip_t sd_chip;
+	uint16_t sd_MS;
+	uint16_t sd_RDY;
+	uint16_t sd_CS;
+	uint16_t sd_CK;
+	uint16_t sd_DO;
+	uint16_t sd_DI;
+};
+
+/*
+ * This function will read count 16-bit words from the serial EEPROM and
+ * return their value in buf.  The port address of the aic7xxx serial EEPROM
+ * control register is passed in as offset.  The following parameters are
+ * also passed in:
+ *
+ *   CS  - Chip select
+ *   CK  - Clock
+ *   DO  - Data out
+ *   DI  - Data in
+ *   RDY - SEEPROM ready
+ *   MS  - Memory port mode select
+ *
+ *  A failed read attempt returns 0, and a successful read returns 1.
+ */
+
+#define	SEEPROM_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_control_offset)
+#define	SEEPROM_OUTB(sd, value)					\
+do {								\
+	ahc_outb(sd->sd_ahc, sd->sd_control_offset, value);	\
+	ahc_flush_device_writes(sd->sd_ahc);			\
+} while(0)
+
+#define	SEEPROM_STATUS_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_status_offset)
+#define	SEEPROM_DATA_INB(sd) \
+	ahc_inb(sd->sd_ahc, sd->sd_dataout_offset)
+
+int ahc_read_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		     u_int start_addr, u_int count);
+int ahc_write_seeprom(struct seeprom_descriptor *sd, uint16_t *buf,
+		      u_int start_addr, u_int count);
+int ahc_verify_cksum(struct seeprom_config *sc);
+
+#endif /* _AIC7XXX_93CX6_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
new file mode 100644
index 0000000..9a6b4a5
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c
@@ -0,0 +1,7451 @@
+/*
+ * Core routines and tables shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2002 Justin T. Gibbs.
+ * Copyright (c) 2000-2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#134 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aicasm/aicasm_insformat.h"
+#else
+#include <dev/aic7xxx/aic7xxx_osm.h>
+#include <dev/aic7xxx/aic7xxx_inline.h>
+#include <dev/aic7xxx/aicasm/aicasm_insformat.h>
+#endif
+
+/****************************** Softc Data ************************************/
+struct ahc_softc_tailq ahc_tailq = TAILQ_HEAD_INITIALIZER(ahc_tailq);
+
+/***************************** Lookup Tables **********************************/
+char *ahc_chip_names[] =
+{
+	"NONE",
+	"aic7770",
+	"aic7850",
+	"aic7855",
+	"aic7859",
+	"aic7860",
+	"aic7870",
+	"aic7880",
+	"aic7895",
+	"aic7895C",
+	"aic7890/91",
+	"aic7896/97",
+	"aic7892",
+	"aic7899"
+};
+static const u_int num_chip_names = NUM_ELEMENTS(ahc_chip_names);
+
+/*
+ * Hardware error codes.
+ */
+struct ahc_hard_error_entry {
+        uint8_t errno;
+	char *errmesg;
+};
+
+static struct ahc_hard_error_entry ahc_hard_errors[] = {
+	{ ILLHADDR,	"Illegal Host Access" },
+	{ ILLSADDR,	"Illegal Sequencer Address referrenced" },
+	{ ILLOPCODE,	"Illegal Opcode in sequencer program" },
+	{ SQPARERR,	"Sequencer Parity Error" },
+	{ DPARERR,	"Data-path Parity Error" },
+	{ MPARERR,	"Scratch or SCB Memory Parity Error" },
+	{ PCIERRSTAT,	"PCI Error detected" },
+	{ CIOPARERR,	"CIOBUS Parity Error" },
+};
+static const u_int num_errors = NUM_ELEMENTS(ahc_hard_errors);
+
+static struct ahc_phase_table_entry ahc_phase_table[] =
+{
+	{ P_DATAOUT,	MSG_NOOP,		"in Data-out phase"	},
+	{ P_DATAIN,	MSG_INITIATOR_DET_ERR,	"in Data-in phase"	},
+	{ P_DATAOUT_DT,	MSG_NOOP,		"in DT Data-out phase"	},
+	{ P_DATAIN_DT,	MSG_INITIATOR_DET_ERR,	"in DT Data-in phase"	},
+	{ P_COMMAND,	MSG_NOOP,		"in Command phase"	},
+	{ P_MESGOUT,	MSG_NOOP,		"in Message-out phase"	},
+	{ P_STATUS,	MSG_INITIATOR_DET_ERR,	"in Status phase"	},
+	{ P_MESGIN,	MSG_PARITY_ERROR,	"in Message-in phase"	},
+	{ P_BUSFREE,	MSG_NOOP,		"while idle"		},
+	{ 0,		MSG_NOOP,		"in unknown phase"	}
+};
+
+/*
+ * In most cases we only wish to itterate over real phases, so
+ * exclude the last element from the count.
+ */
+static const u_int num_phases = NUM_ELEMENTS(ahc_phase_table) - 1;
+
+/*
+ * Valid SCSIRATE values.  (p. 3-17)
+ * Provides a mapping of tranfer periods in ns to the proper value to
+ * stick in the scsixfer reg.
+ */
+static struct ahc_syncrate ahc_syncrates[] =
+{
+      /* ultra2    fast/ultra  period     rate */
+	{ 0x42,      0x000,      9,      "80.0" },
+	{ 0x03,      0x000,     10,      "40.0" },
+	{ 0x04,      0x000,     11,      "33.0" },
+	{ 0x05,      0x100,     12,      "20.0" },
+	{ 0x06,      0x110,     15,      "16.0" },
+	{ 0x07,      0x120,     18,      "13.4" },
+	{ 0x08,      0x000,     25,      "10.0" },
+	{ 0x19,      0x010,     31,      "8.0"  },
+	{ 0x1a,      0x020,     37,      "6.67" },
+	{ 0x1b,      0x030,     43,      "5.7"  },
+	{ 0x1c,      0x040,     50,      "5.0"  },
+	{ 0x00,      0x050,     56,      "4.4"  },
+	{ 0x00,      0x060,     62,      "4.0"  },
+	{ 0x00,      0x070,     68,      "3.6"  },
+	{ 0x00,      0x000,      0,      NULL   }
+};
+
+/* Our Sequencer Program */
+#include "aic7xxx_seq.h"
+
+/**************************** Function Declarations ***************************/
+static void		ahc_force_renegotiation(struct ahc_softc *ahc,
+						struct ahc_devinfo *devinfo);
+static struct ahc_tmode_tstate*
+			ahc_alloc_tstate(struct ahc_softc *ahc,
+					 u_int scsi_id, char channel);
+#ifdef AHC_TARGET_MODE
+static void		ahc_free_tstate(struct ahc_softc *ahc,
+					u_int scsi_id, char channel, int force);
+#endif
+static struct ahc_syncrate*
+			ahc_devlimited_syncrate(struct ahc_softc *ahc,
+					        struct ahc_initiator_tinfo *,
+						u_int *period,
+						u_int *ppr_options,
+						role_t role);
+static void		ahc_update_pending_scbs(struct ahc_softc *ahc);
+static void		ahc_fetch_devinfo(struct ahc_softc *ahc,
+					  struct ahc_devinfo *devinfo);
+static void		ahc_scb_devinfo(struct ahc_softc *ahc,
+					struct ahc_devinfo *devinfo,
+					struct scb *scb);
+static void		ahc_assert_atn(struct ahc_softc *ahc);
+static void		ahc_setup_initiator_msgout(struct ahc_softc *ahc,
+						   struct ahc_devinfo *devinfo,
+						   struct scb *scb);
+static void		ahc_build_transfer_msg(struct ahc_softc *ahc,
+					       struct ahc_devinfo *devinfo);
+static void		ahc_construct_sdtr(struct ahc_softc *ahc,
+					   struct ahc_devinfo *devinfo,
+					   u_int period, u_int offset);
+static void		ahc_construct_wdtr(struct ahc_softc *ahc,
+					   struct ahc_devinfo *devinfo,
+					   u_int bus_width);
+static void		ahc_construct_ppr(struct ahc_softc *ahc,
+					  struct ahc_devinfo *devinfo,
+					  u_int period, u_int offset,
+					  u_int bus_width, u_int ppr_options);
+static void		ahc_clear_msg_state(struct ahc_softc *ahc);
+static void		ahc_handle_proto_violation(struct ahc_softc *ahc);
+static void		ahc_handle_message_phase(struct ahc_softc *ahc);
+typedef enum {
+	AHCMSG_1B,
+	AHCMSG_2B,
+	AHCMSG_EXT
+} ahc_msgtype;
+static int		ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type,
+				     u_int msgval, int full);
+static int		ahc_parse_msg(struct ahc_softc *ahc,
+				      struct ahc_devinfo *devinfo);
+static int		ahc_handle_msg_reject(struct ahc_softc *ahc,
+					      struct ahc_devinfo *devinfo);
+static void		ahc_handle_ign_wide_residue(struct ahc_softc *ahc,
+						struct ahc_devinfo *devinfo);
+static void		ahc_reinitialize_dataptrs(struct ahc_softc *ahc);
+static void		ahc_handle_devreset(struct ahc_softc *ahc,
+					    struct ahc_devinfo *devinfo,
+					    cam_status status, char *message,
+					    int verbose_level);
+#ifdef AHC_TARGET_MODE
+static void		ahc_setup_target_msgin(struct ahc_softc *ahc,
+					       struct ahc_devinfo *devinfo,
+					       struct scb *scb);
+#endif
+
+static bus_dmamap_callback_t	ahc_dmamap_cb; 
+static void			ahc_build_free_scb_list(struct ahc_softc *ahc);
+static int			ahc_init_scbdata(struct ahc_softc *ahc);
+static void			ahc_fini_scbdata(struct ahc_softc *ahc);
+static void		ahc_qinfifo_requeue(struct ahc_softc *ahc,
+					    struct scb *prev_scb,
+					    struct scb *scb);
+static int		ahc_qinfifo_count(struct ahc_softc *ahc);
+static u_int		ahc_rem_scb_from_disc_list(struct ahc_softc *ahc,
+						   u_int prev, u_int scbptr);
+static void		ahc_add_curscb_to_free_list(struct ahc_softc *ahc);
+static u_int		ahc_rem_wscb(struct ahc_softc *ahc,
+				     u_int scbpos, u_int prev);
+static void		ahc_reset_current_bus(struct ahc_softc *ahc);
+#ifdef AHC_DUMP_SEQ
+static void		ahc_dumpseq(struct ahc_softc *ahc);
+#endif
+static int		ahc_loadseq(struct ahc_softc *ahc);
+static int		ahc_check_patch(struct ahc_softc *ahc,
+					struct patch **start_patch,
+					u_int start_instr, u_int *skip_addr);
+static void		ahc_download_instr(struct ahc_softc *ahc,
+					   u_int instrptr, uint8_t *dconsts);
+#ifdef AHC_TARGET_MODE
+static void		ahc_queue_lstate_event(struct ahc_softc *ahc,
+					       struct ahc_tmode_lstate *lstate,
+					       u_int initiator_id,
+					       u_int event_type,
+					       u_int event_arg);
+static void		ahc_update_scsiid(struct ahc_softc *ahc,
+					  u_int targid_mask);
+static int		ahc_handle_target_cmd(struct ahc_softc *ahc,
+					      struct target_cmd *cmd);
+#endif
+/************************* Sequencer Execution Control ************************/
+/*
+ * Restart the sequencer program from address zero
+ */
+void
+ahc_restart(struct ahc_softc *ahc)
+{
+
+	ahc_pause(ahc);
+
+	/* No more pending messages. */
+	ahc_clear_msg_state(ahc);
+
+	ahc_outb(ahc, SCSISIGO, 0);		/* De-assert BSY */
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);	/* No message to send */
+	ahc_outb(ahc, SXFRCTL1, ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+	ahc_outb(ahc, LASTPHASE, P_BUSFREE);
+	ahc_outb(ahc, SAVED_SCSIID, 0xFF);
+	ahc_outb(ahc, SAVED_LUN, 0xFF);
+
+	/*
+	 * Ensure that the sequencer's idea of TQINPOS
+	 * matches our own.  The sequencer increments TQINPOS
+	 * only after it sees a DMA complete and a reset could
+	 * occur before the increment leaving the kernel to believe
+	 * the command arrived but the sequencer to not.
+	 */
+	ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+
+	/* Always allow reselection */
+	ahc_outb(ahc, SCSISEQ,
+		 ahc_inb(ahc, SCSISEQ_TEMPLATE) & (ENSELI|ENRSELI|ENAUTOATNP));
+	if ((ahc->features & AHC_CMD_CHAN) != 0) {
+		/* Ensure that no DMA operations are in progress */
+		ahc_outb(ahc, CCSCBCNT, 0);
+		ahc_outb(ahc, CCSGCTL, 0);
+		ahc_outb(ahc, CCSCBCTL, 0);
+	}
+	/*
+	 * If we were in the process of DMA'ing SCB data into
+	 * an SCB, replace that SCB on the free list.  This prevents
+	 * an SCB leak.
+	 */
+	if ((ahc_inb(ahc, SEQ_FLAGS2) & SCB_DMA) != 0) {
+		ahc_add_curscb_to_free_list(ahc);
+		ahc_outb(ahc, SEQ_FLAGS2,
+			 ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA);
+	}
+	ahc_outb(ahc, MWI_RESIDUAL, 0);
+	ahc_outb(ahc, SEQCTL, ahc->seqctl);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+	ahc_unpause(ahc);
+}
+
+/************************* Input/Output Queues ********************************/
+void
+ahc_run_qoutfifo(struct ahc_softc *ahc)
+{
+	struct scb *scb;
+	u_int  scb_index;
+
+	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
+	while (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL) {
+
+		scb_index = ahc->qoutfifo[ahc->qoutfifonext];
+		if ((ahc->qoutfifonext & 0x03) == 0x03) {
+			u_int modnext;
+
+			/*
+			 * Clear 32bits of QOUTFIFO at a time
+			 * so that we don't clobber an incoming
+			 * byte DMA to the array on architectures
+			 * that only support 32bit load and store
+			 * operations.
+			 */
+			modnext = ahc->qoutfifonext & ~0x3;
+			*((uint32_t *)(&ahc->qoutfifo[modnext])) = 0xFFFFFFFFUL;
+			ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+					ahc->shared_data_dmamap,
+					/*offset*/modnext, /*len*/4,
+					BUS_DMASYNC_PREREAD);
+		}
+		ahc->qoutfifonext++;
+
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s: WARNING no command for scb %d "
+			       "(cmdcmplt)\nQOUTPOS = %d\n",
+			       ahc_name(ahc), scb_index,
+			       (ahc->qoutfifonext - 1) & 0xFF);
+			continue;
+		}
+
+		/*
+		 * Save off the residual
+		 * if there is one.
+		 */
+		ahc_update_residual(ahc, scb);
+		ahc_done(ahc, scb);
+	}
+}
+
+void
+ahc_run_untagged_queues(struct ahc_softc *ahc)
+{
+	int i;
+
+	for (i = 0; i < 16; i++)
+		ahc_run_untagged_queue(ahc, &ahc->untagged_queues[i]);
+}
+
+void
+ahc_run_untagged_queue(struct ahc_softc *ahc, struct scb_tailq *queue)
+{
+	struct scb *scb;
+
+	if (ahc->untagged_queue_lock != 0)
+		return;
+
+	if ((scb = TAILQ_FIRST(queue)) != NULL
+	 && (scb->flags & SCB_ACTIVE) == 0) {
+		scb->flags |= SCB_ACTIVE;
+		ahc_queue_scb(ahc, scb);
+	}
+}
+
+/************************* Interrupt Handling *********************************/
+void
+ahc_handle_brkadrint(struct ahc_softc *ahc)
+{
+	/*
+	 * We upset the sequencer :-(
+	 * Lookup the error message
+	 */
+	int i;
+	int error;
+
+	error = ahc_inb(ahc, ERROR);
+	for (i = 0; error != 1 && i < num_errors; i++)
+		error >>= 1;
+	printf("%s: brkadrint, %s at seqaddr = 0x%x\n",
+	       ahc_name(ahc), ahc_hard_errors[i].errmesg,
+	       ahc_inb(ahc, SEQADDR0) |
+	       (ahc_inb(ahc, SEQADDR1) << 8));
+
+	ahc_dump_card_state(ahc);
+
+	/* Tell everyone that this HBA is no longer available */
+	ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+		       CAM_LUN_WILDCARD, SCB_LIST_NULL, ROLE_UNKNOWN,
+		       CAM_NO_HBA);
+
+	/* Disable all interrupt sources by resetting the controller */
+	ahc_shutdown(ahc);
+}
+
+void
+ahc_handle_seqint(struct ahc_softc *ahc, u_int intstat)
+{
+	struct scb *scb;
+	struct ahc_devinfo devinfo;
+	
+	ahc_fetch_devinfo(ahc, &devinfo);
+
+	/*
+	 * Clear the upper byte that holds SEQINT status
+	 * codes and clear the SEQINT bit. We will unpause
+	 * the sequencer, if appropriate, after servicing
+	 * the request.
+	 */
+	ahc_outb(ahc, CLRINT, CLRSEQINT);
+	switch (intstat & SEQINT_MASK) {
+	case BAD_STATUS:
+	{
+		u_int  scb_index;
+		struct hardware_scb *hscb;
+
+		/*
+		 * Set the default return value to 0 (don't
+		 * send sense).  The sense code will change
+		 * this if needed.
+		 */
+		ahc_outb(ahc, RETURN_1, 0);
+
+		/*
+		 * The sequencer will notify us when a command
+		 * has an error that would be of interest to
+		 * the kernel.  This allows us to leave the sequencer
+		 * running in the common case of command completes
+		 * without error.  The sequencer will already have
+		 * dma'd the SCB back up to us, so we can reference
+		 * the in kernel copy directly.
+		 */
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			ahc_print_devinfo(ahc, &devinfo);
+			printf("ahc_intr - referenced scb "
+			       "not valid during seqint 0x%x scb(%d)\n",
+			       intstat, scb_index);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+			goto unpause;
+		}
+
+		hscb = scb->hscb; 
+
+		/* Don't want to clobber the original sense code */
+		if ((scb->flags & SCB_SENSE) != 0) {
+			/*
+			 * Clear the SCB_SENSE Flag and have
+			 * the sequencer do a normal command
+			 * complete.
+			 */
+			scb->flags &= ~SCB_SENSE;
+			ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+			break;
+		}
+		ahc_set_transaction_status(scb, CAM_SCSI_STATUS_ERROR);
+		/* Freeze the queue until the client sees the error. */
+		ahc_freeze_devq(ahc, scb);
+		ahc_freeze_scb(scb);
+		ahc_set_scsi_status(scb, hscb->shared_data.status.scsi_status);
+		switch (hscb->shared_data.status.scsi_status) {
+		case SCSI_STATUS_OK:
+			printf("%s: Interrupted for staus of 0???\n",
+			       ahc_name(ahc));
+			break;
+		case SCSI_STATUS_CMD_TERMINATED:
+		case SCSI_STATUS_CHECK_COND:
+		{
+			struct ahc_dma_seg *sg;
+			struct scsi_sense *sc;
+			struct ahc_initiator_tinfo *targ_info;
+			struct ahc_tmode_tstate *tstate;
+			struct ahc_transinfo *tinfo;
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_SENSE) {
+				ahc_print_path(ahc, scb);
+				printf("SCB %d: requests Check Status\n",
+				       scb->hscb->tag);
+			}
+#endif
+
+			if (ahc_perform_autosense(scb) == 0)
+				break;
+
+			targ_info = ahc_fetch_transinfo(ahc,
+							devinfo.channel,
+							devinfo.our_scsiid,
+							devinfo.target,
+							&tstate);
+			tinfo = &targ_info->curr;
+			sg = scb->sg_list;
+			sc = (struct scsi_sense *)(&hscb->shared_data.cdb); 
+			/*
+			 * Save off the residual if there is one.
+			 */
+			ahc_update_residual(ahc, scb);
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_SENSE) {
+				ahc_print_path(ahc, scb);
+				printf("Sending Sense\n");
+			}
+#endif
+			sg->addr = ahc_get_sense_bufaddr(ahc, scb);
+			sg->len = ahc_get_sense_bufsize(ahc, scb);
+			sg->len |= AHC_DMA_LAST_SEG;
+
+			/* Fixup byte order */
+			sg->addr = ahc_htole32(sg->addr);
+			sg->len = ahc_htole32(sg->len);
+
+			sc->opcode = REQUEST_SENSE;
+			sc->byte2 = 0;
+			if (tinfo->protocol_version <= SCSI_REV_2
+			 && SCB_GET_LUN(scb) < 8)
+				sc->byte2 = SCB_GET_LUN(scb) << 5;
+			sc->unused[0] = 0;
+			sc->unused[1] = 0;
+			sc->length = sg->len;
+			sc->control = 0;
+
+			/*
+			 * We can't allow the target to disconnect.
+			 * This will be an untagged transaction and
+			 * having the target disconnect will make this
+			 * transaction indestinguishable from outstanding
+			 * tagged transactions.
+			 */
+			hscb->control = 0;
+
+			/*
+			 * This request sense could be because the
+			 * the device lost power or in some other
+			 * way has lost our transfer negotiations.
+			 * Renegotiate if appropriate.  Unit attention
+			 * errors will be reported before any data
+			 * phases occur.
+			 */
+			if (ahc_get_residual(scb) 
+			 == ahc_get_transfer_length(scb)) {
+				ahc_update_neg_request(ahc, &devinfo,
+						       tstate, targ_info,
+						       AHC_NEG_IF_NON_ASYNC);
+			}
+			if (tstate->auto_negotiate & devinfo.target_mask) {
+				hscb->control |= MK_MESSAGE;
+				scb->flags &= ~SCB_NEGOTIATE;
+				scb->flags |= SCB_AUTO_NEGOTIATE;
+			}
+			hscb->cdb_len = sizeof(*sc);
+			hscb->dataptr = sg->addr; 
+			hscb->datacnt = sg->len;
+			hscb->sgptr = scb->sg_list_phys | SG_FULL_RESID;
+			hscb->sgptr = ahc_htole32(hscb->sgptr);
+			scb->sg_count = 1;
+			scb->flags |= SCB_SENSE;
+			ahc_qinfifo_requeue_tail(ahc, scb);
+			ahc_outb(ahc, RETURN_1, SEND_SENSE);
+			/*
+			 * Ensure we have enough time to actually
+			 * retrieve the sense.
+			 */
+			ahc_scb_timer_reset(scb, 5 * 1000000);
+			break;
+		}
+		default:
+			break;
+		}
+		break;
+	}
+	case NO_MATCH:
+	{
+		/* Ensure we don't leave the selection hardware on */
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+		printf("%s:%c:%d: no active SCB for reconnecting "
+		       "target - issuing BUS DEVICE RESET\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target);
+		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
+		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
+		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		       "SINDEX == 0x%x\n",
+		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
+		       ahc_index_busy_tcl(ahc,
+			    BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
+				      ahc_inb(ahc, SAVED_LUN))),
+		       ahc_inb(ahc, SINDEX));
+		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
+		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
+		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
+		       ahc_inb(ahc, SCB_CONTROL));
+		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
+		printf("SXFRCTL0 == 0x%x\n", ahc_inb(ahc, SXFRCTL0));
+		printf("SEQCTL == 0x%x\n", ahc_inb(ahc, SEQCTL));
+		ahc_dump_card_state(ahc);
+		ahc->msgout_buf[0] = MSG_BUS_DEV_RESET;
+		ahc->msgout_len = 1;
+		ahc->msgout_index = 0;
+		ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		ahc_outb(ahc, MSG_OUT, HOST_MSG);
+		ahc_assert_atn(ahc);
+		break;
+	}
+	case SEND_REJECT: 
+	{
+		u_int rejbyte = ahc_inb(ahc, ACCUM);
+		printf("%s:%c:%d: Warning - unknown message received from "
+		       "target (0x%x).  Rejecting\n", 
+		       ahc_name(ahc), devinfo.channel, devinfo.target, rejbyte);
+		break; 
+	}
+	case PROTO_VIOLATION:
+	{
+		ahc_handle_proto_violation(ahc);
+		break;
+	}
+	case IGN_WIDE_RES:
+		ahc_handle_ign_wide_residue(ahc, &devinfo);
+		break;
+	case PDATA_REINIT:
+		ahc_reinitialize_dataptrs(ahc);
+		break;
+	case BAD_PHASE:
+	{
+		u_int lastphase;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		printf("%s:%c:%d: unknown scsi bus phase %x, "
+		       "lastphase = 0x%x.  Attempting to continue\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       lastphase, ahc_inb(ahc, SCSISIGI));
+		break;
+	}
+	case MISSED_BUSFREE:
+	{
+		u_int lastphase;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		printf("%s:%c:%d: Missed busfree. "
+		       "Lastphase = 0x%x, Curphase = 0x%x\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       lastphase, ahc_inb(ahc, SCSISIGI));
+		ahc_restart(ahc);
+		return;
+	}
+	case HOST_MSG_LOOP:
+	{
+		/*
+		 * The sequencer has encountered a message phase
+		 * that requires host assistance for completion.
+		 * While handling the message phase(s), we will be
+		 * notified by the sequencer after each byte is
+		 * transfered so we can track bus phase changes.
+		 *
+		 * If this is the first time we've seen a HOST_MSG_LOOP
+		 * interrupt, initialize the state of the host message
+		 * loop.
+		 */
+		if (ahc->msg_type == MSG_TYPE_NONE) {
+			struct scb *scb;
+			u_int scb_index;
+			u_int bus_phase;
+
+			bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+			if (bus_phase != P_MESGIN
+			 && bus_phase != P_MESGOUT) {
+				printf("ahc_intr: HOST_MSG_LOOP bad "
+				       "phase 0x%x\n",
+				      bus_phase);
+				/*
+				 * Probably transitioned to bus free before
+				 * we got here.  Just punt the message.
+				 */
+				ahc_clear_intstat(ahc);
+				ahc_restart(ahc);
+				return;
+			}
+
+			scb_index = ahc_inb(ahc, SCB_TAG);
+			scb = ahc_lookup_scb(ahc, scb_index);
+			if (devinfo.role == ROLE_INITIATOR) {
+				if (scb == NULL)
+					panic("HOST_MSG_LOOP with "
+					      "invalid SCB %x\n", scb_index);
+
+				if (bus_phase == P_MESGOUT)
+					ahc_setup_initiator_msgout(ahc,
+								   &devinfo,
+								   scb);
+				else {
+					ahc->msg_type =
+					    MSG_TYPE_INITIATOR_MSGIN;
+					ahc->msgin_index = 0;
+				}
+			}
+#ifdef AHC_TARGET_MODE
+			else {
+				if (bus_phase == P_MESGOUT) {
+					ahc->msg_type =
+					    MSG_TYPE_TARGET_MSGOUT;
+					ahc->msgin_index = 0;
+				}
+				else 
+					ahc_setup_target_msgin(ahc,
+							       &devinfo,
+							       scb);
+			}
+#endif
+		}
+
+		ahc_handle_message_phase(ahc);
+		break;
+	}
+	case PERR_DETECTED:
+	{
+		/*
+		 * If we've cleared the parity error interrupt
+		 * but the sequencer still believes that SCSIPERR
+		 * is true, it must be that the parity error is
+		 * for the currently presented byte on the bus,
+		 * and we are not in a phase (data-in) where we will
+		 * eventually ack this byte.  Ack the byte and
+		 * throw it away in the hope that the target will
+		 * take us to message out to deliver the appropriate
+		 * error message.
+		 */
+		if ((intstat & SCSIINT) == 0
+		 && (ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0) {
+
+			if ((ahc->features & AHC_DT) == 0) {
+				u_int curphase;
+
+				/*
+				 * The hardware will only let you ack bytes
+				 * if the expected phase in SCSISIGO matches
+				 * the current phase.  Make sure this is
+				 * currently the case.
+				 */
+				curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+				ahc_outb(ahc, LASTPHASE, curphase);
+				ahc_outb(ahc, SCSISIGO, curphase);
+			}
+			if ((ahc_inb(ahc, SCSISIGI) & (CDI|MSGI)) == 0) {
+				int wait;
+
+				/*
+				 * In a data phase.  Faster to bitbucket
+				 * the data than to individually ack each
+				 * byte.  This is also the only strategy
+				 * that will work with AUTOACK enabled.
+				 */
+				ahc_outb(ahc, SXFRCTL1,
+					 ahc_inb(ahc, SXFRCTL1) | BITBUCKET);
+				wait = 5000;
+				while (--wait != 0) {
+					if ((ahc_inb(ahc, SCSISIGI)
+					  & (CDI|MSGI)) != 0)
+						break;
+					ahc_delay(100);
+				}
+				ahc_outb(ahc, SXFRCTL1,
+					 ahc_inb(ahc, SXFRCTL1) & ~BITBUCKET);
+				if (wait == 0) {
+					struct	scb *scb;
+					u_int	scb_index;
+
+					ahc_print_devinfo(ahc, &devinfo);
+					printf("Unable to clear parity error.  "
+					       "Resetting bus.\n");
+					scb_index = ahc_inb(ahc, SCB_TAG);
+					scb = ahc_lookup_scb(ahc, scb_index);
+					if (scb != NULL)
+						ahc_set_transaction_status(scb,
+						    CAM_UNCOR_PARITY);
+					ahc_reset_channel(ahc, devinfo.channel, 
+							  /*init reset*/TRUE);
+				}
+			} else {
+				ahc_inb(ahc, SCSIDATL);
+			}
+		}
+		break;
+	}
+	case DATA_OVERRUN:
+	{
+		/*
+		 * When the sequencer detects an overrun, it
+		 * places the controller in "BITBUCKET" mode
+		 * and allows the target to complete its transfer.
+		 * Unfortunately, none of the counters get updated
+		 * when the controller is in this mode, so we have
+		 * no way of knowing how large the overrun was.
+		 */
+		u_int scbindex = ahc_inb(ahc, SCB_TAG);
+		u_int lastphase = ahc_inb(ahc, LASTPHASE);
+		u_int i;
+
+		scb = ahc_lookup_scb(ahc, scbindex);
+		for (i = 0; i < num_phases; i++) {
+			if (lastphase == ahc_phase_table[i].phase)
+				break;
+		}
+		ahc_print_path(ahc, scb);
+		printf("data overrun detected %s."
+		       "  Tag == 0x%x.\n",
+		       ahc_phase_table[i].phasemsg,
+  		       scb->hscb->tag);
+		ahc_print_path(ahc, scb);
+		printf("%s seen Data Phase.  Length = %ld.  NumSGs = %d.\n",
+		       ahc_inb(ahc, SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+		       ahc_get_transfer_length(scb), scb->sg_count);
+		if (scb->sg_count > 0) {
+			for (i = 0; i < scb->sg_count; i++) {
+
+				printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+				       i,
+				       (ahc_le32toh(scb->sg_list[i].len) >> 24
+				        & SG_HIGH_ADDR_BITS),
+				       ahc_le32toh(scb->sg_list[i].addr),
+				       ahc_le32toh(scb->sg_list[i].len)
+				       & AHC_SG_LEN_MASK);
+			}
+		}
+		/*
+		 * Set this and it will take effect when the
+		 * target does a command complete.
+		 */
+		ahc_freeze_devq(ahc, scb);
+		if ((scb->flags & SCB_SENSE) == 0) {
+			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+		} else {
+			scb->flags &= ~SCB_SENSE;
+			ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+		}
+		ahc_freeze_scb(scb);
+
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			/*
+			 * Clear the channel in case we return
+			 * to data phase later.
+			 */
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN);
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | CLRSTCNT|CLRCHN);
+		}
+		if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+			u_int dscommand1;
+
+			/* Ensure HHADDR is 0 for future DMA operations. */
+			dscommand1 = ahc_inb(ahc, DSCOMMAND1);
+			ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0);
+			ahc_outb(ahc, HADDR, 0);
+			ahc_outb(ahc, DSCOMMAND1, dscommand1);
+		}
+		break;
+	}
+	case MKMSG_FAILED:
+	{
+		u_int scbindex;
+
+		printf("%s:%c:%d:%d: Attempt to issue message failed\n",
+		       ahc_name(ahc), devinfo.channel, devinfo.target,
+		       devinfo.lun);
+		scbindex = ahc_inb(ahc, SCB_TAG);
+		scb = ahc_lookup_scb(ahc, scbindex);
+		if (scb != NULL
+		 && (scb->flags & SCB_RECOVERY_SCB) != 0)
+			/*
+			 * Ensure that we didn't put a second instance of this
+			 * SCB into the QINFIFO.
+			 */
+			ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+					   SCB_GET_CHANNEL(ahc, scb),
+					   SCB_GET_LUN(scb), scb->hscb->tag,
+					   ROLE_INITIATOR, /*status*/0,
+					   SEARCH_REMOVE);
+		break;
+	}
+	case NO_FREE_SCB:
+	{
+		printf("%s: No free or disconnected SCBs\n", ahc_name(ahc));
+		ahc_dump_card_state(ahc);
+		panic("for safety");
+		break;
+	}
+	case SCB_MISMATCH:
+	{
+		u_int scbptr;
+
+		scbptr = ahc_inb(ahc, SCBPTR);
+		printf("Bogus TAG after DMA.  SCBPTR %d, tag %d, our tag %d\n",
+		       scbptr, ahc_inb(ahc, ARG_1),
+		       ahc->scb_data->hscbs[scbptr].tag);
+		ahc_dump_card_state(ahc);
+		panic("for saftey");
+		break;
+	}
+	case OUT_OF_RANGE:
+	{
+		printf("%s: BTT calculation out of range\n", ahc_name(ahc));
+		printf("SAVED_SCSIID == 0x%x, SAVED_LUN == 0x%x, "
+		       "ARG_1 == 0x%x ACCUM = 0x%x\n",
+		       ahc_inb(ahc, SAVED_SCSIID), ahc_inb(ahc, SAVED_LUN),
+		       ahc_inb(ahc, ARG_1), ahc_inb(ahc, ACCUM));
+		printf("SEQ_FLAGS == 0x%x, SCBPTR == 0x%x, BTT == 0x%x, "
+		       "SINDEX == 0x%x\n, A == 0x%x\n",
+		       ahc_inb(ahc, SEQ_FLAGS), ahc_inb(ahc, SCBPTR),
+		       ahc_index_busy_tcl(ahc,
+			    BUILD_TCL(ahc_inb(ahc, SAVED_SCSIID),
+				      ahc_inb(ahc, SAVED_LUN))),
+		       ahc_inb(ahc, SINDEX),
+		       ahc_inb(ahc, ACCUM));
+		printf("SCSIID == 0x%x, SCB_SCSIID == 0x%x, SCB_LUN == 0x%x, "
+		       "SCB_TAG == 0x%x, SCB_CONTROL == 0x%x\n",
+		       ahc_inb(ahc, SCSIID), ahc_inb(ahc, SCB_SCSIID),
+		       ahc_inb(ahc, SCB_LUN), ahc_inb(ahc, SCB_TAG),
+		       ahc_inb(ahc, SCB_CONTROL));
+		printf("SCSIBUSL == 0x%x, SCSISIGI == 0x%x\n",
+		       ahc_inb(ahc, SCSIBUSL), ahc_inb(ahc, SCSISIGI));
+		ahc_dump_card_state(ahc);
+		panic("for safety");
+		break;
+	}
+	default:
+		printf("ahc_intr: seqint, "
+		       "intstat == 0x%x, scsisigi = 0x%x\n",
+		       intstat, ahc_inb(ahc, SCSISIGI));
+		break;
+	}
+unpause:
+	/*
+	 *  The sequencer is paused immediately on
+	 *  a SEQINT, so we should restart it when
+	 *  we're done.
+	 */
+	ahc_unpause(ahc);
+}
+
+void
+ahc_handle_scsiint(struct ahc_softc *ahc, u_int intstat)
+{
+	u_int	scb_index;
+	u_int	status0;
+	u_int	status;
+	struct	scb *scb;
+	char	cur_channel;
+	char	intr_channel;
+
+	if ((ahc->features & AHC_TWIN) != 0
+	 && ((ahc_inb(ahc, SBLKCTL) & SELBUSB) != 0))
+		cur_channel = 'B';
+	else
+		cur_channel = 'A';
+	intr_channel = cur_channel;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		status0 = ahc_inb(ahc, SSTAT0) & IOERR;
+	else
+		status0 = 0;
+	status = ahc_inb(ahc, SSTAT1) & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
+	if (status == 0 && status0 == 0) {
+		if ((ahc->features & AHC_TWIN) != 0) {
+			/* Try the other channel */
+		 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+			status = ahc_inb(ahc, SSTAT1)
+			       & (SELTO|SCSIRSTI|BUSFREE|SCSIPERR);
+			intr_channel = (cur_channel == 'A') ? 'B' : 'A';
+		}
+		if (status == 0) {
+			printf("%s: Spurious SCSI interrupt\n", ahc_name(ahc));
+			ahc_outb(ahc, CLRINT, CLRSCSIINT);
+			ahc_unpause(ahc);
+			return;
+		}
+	}
+
+	/* Make sure the sequencer is in a safe location. */
+	ahc_clear_critical_section(ahc);
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	if (scb != NULL
+	 && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) != 0)
+		scb = NULL;
+
+	if ((ahc->features & AHC_ULTRA2) != 0
+	 && (status0 & IOERR) != 0) {
+		int now_lvd;
+
+		now_lvd = ahc_inb(ahc, SBLKCTL) & ENAB40;
+		printf("%s: Transceiver State Has Changed to %s mode\n",
+		       ahc_name(ahc), now_lvd ? "LVD" : "SE");
+		ahc_outb(ahc, CLRSINT0, CLRIOERR);
+		/*
+		 * When transitioning to SE mode, the reset line
+		 * glitches, triggering an arbitration bug in some
+		 * Ultra2 controllers.  This bug is cleared when we
+		 * assert the reset line.  Since a reset glitch has
+		 * already occurred with this transition and a
+		 * transceiver state change is handled just like
+		 * a bus reset anyway, asserting the reset line
+		 * ourselves is safe.
+		 */
+		ahc_reset_channel(ahc, intr_channel,
+				 /*Initiate Reset*/now_lvd == 0);
+	} else if ((status & SCSIRSTI) != 0) {
+		printf("%s: Someone reset channel %c\n",
+			ahc_name(ahc), intr_channel);
+		if (intr_channel != cur_channel)
+		 	ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) ^ SELBUSB);
+		ahc_reset_channel(ahc, intr_channel, /*Initiate Reset*/FALSE);
+	} else if ((status & SCSIPERR) != 0) {
+		/*
+		 * Determine the bus phase and queue an appropriate message.
+		 * SCSIPERR is latched true as soon as a parity error
+		 * occurs.  If the sequencer acked the transfer that
+		 * caused the parity error and the currently presented
+		 * transfer on the bus has correct parity, SCSIPERR will
+		 * be cleared by CLRSCSIPERR.  Use this to determine if
+		 * we should look at the last phase the sequencer recorded,
+		 * or the current phase presented on the bus.
+		 */
+		struct	ahc_devinfo devinfo;
+		u_int	mesg_out;
+		u_int	curphase;
+		u_int	errorphase;
+		u_int	lastphase;
+		u_int	scsirate;
+		u_int	i;
+		u_int	sstat2;
+		int	silent;
+
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+		sstat2 = ahc_inb(ahc, SSTAT2);
+		ahc_outb(ahc, CLRSINT1, CLRSCSIPERR);
+		/*
+		 * For all phases save DATA, the sequencer won't
+		 * automatically ack a byte that has a parity error
+		 * in it.  So the only way that the current phase
+		 * could be 'data-in' is if the parity error is for
+		 * an already acked byte in the data phase.  During
+		 * synchronous data-in transfers, we may actually
+		 * ack bytes before latching the current phase in
+		 * LASTPHASE, leading to the discrepancy between
+		 * curphase and lastphase.
+		 */
+		if ((ahc_inb(ahc, SSTAT1) & SCSIPERR) != 0
+		 || curphase == P_DATAIN || curphase == P_DATAIN_DT)
+			errorphase = curphase;
+		else
+			errorphase = lastphase;
+
+		for (i = 0; i < num_phases; i++) {
+			if (errorphase == ahc_phase_table[i].phase)
+				break;
+		}
+		mesg_out = ahc_phase_table[i].mesg_out;
+		silent = FALSE;
+		if (scb != NULL) {
+			if (SCB_IS_SILENT(scb))
+				silent = TRUE;
+			else
+				ahc_print_path(ahc, scb);
+			scb->flags |= SCB_TRANSMISSION_ERROR;
+		} else
+			printf("%s:%c:%d: ", ahc_name(ahc), intr_channel,
+			       SCSIID_TARGET(ahc, ahc_inb(ahc, SAVED_SCSIID)));
+		scsirate = ahc_inb(ahc, SCSIRATE);
+		if (silent == FALSE) {
+			printf("parity error detected %s. "
+			       "SEQADDR(0x%x) SCSIRATE(0x%x)\n",
+			       ahc_phase_table[i].phasemsg,
+			       ahc_inw(ahc, SEQADDR0),
+			       scsirate);
+			if ((ahc->features & AHC_DT) != 0) {
+				if ((sstat2 & CRCVALERR) != 0)
+					printf("\tCRC Value Mismatch\n");
+				if ((sstat2 & CRCENDERR) != 0)
+					printf("\tNo terminal CRC packet "
+					       "recevied\n");
+				if ((sstat2 & CRCREQERR) != 0)
+					printf("\tIllegal CRC packet "
+					       "request\n");
+				if ((sstat2 & DUAL_EDGE_ERR) != 0)
+					printf("\tUnexpected %sDT Data Phase\n",
+					       (scsirate & SINGLE_EDGE)
+					     ? "" : "non-");
+			}
+		}
+
+		if ((ahc->features & AHC_DT) != 0
+		 && (sstat2 & DUAL_EDGE_ERR) != 0) {
+			/*
+			 * This error applies regardless of
+			 * data direction, so ignore the value
+			 * in the phase table.
+			 */
+			mesg_out = MSG_INITIATOR_DET_ERR;
+		}
+
+		/*
+		 * We've set the hardware to assert ATN if we   
+		 * get a parity error on "in" phases, so all we  
+		 * need to do is stuff the message buffer with
+		 * the appropriate message.  "In" phases have set
+		 * mesg_out to something other than MSG_NOP.
+		 */
+		if (mesg_out != MSG_NOOP) {
+			if (ahc->msg_type != MSG_TYPE_NONE)
+				ahc->send_msg_perror = TRUE;
+			else
+				ahc_outb(ahc, MSG_OUT, mesg_out);
+		}
+		/*
+		 * Force a renegotiation with this target just in
+		 * case we are out of sync for some external reason
+		 * unknown (or unreported) by the target.
+		 */
+		ahc_fetch_devinfo(ahc, &devinfo);
+		ahc_force_renegotiation(ahc, &devinfo);
+
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		ahc_unpause(ahc);
+	} else if ((status & SELTO) != 0) {
+		u_int	scbptr;
+
+		/* Stop the selection */
+		ahc_outb(ahc, SCSISEQ, 0);
+
+		/* No more pending messages */
+		ahc_clear_msg_state(ahc);
+
+		/* Clear interrupt state */
+		ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+		ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Although the driver does not care about the
+		 * 'Selection in Progress' status bit, the busy
+		 * LED does.  SELINGO is only cleared by a sucessfull
+		 * selection, so we must manually clear it to insure
+		 * the LED turns off just incase no future successful
+		 * selections occur (e.g. no devices on the bus).
+		 */
+		ahc_outb(ahc, CLRSINT0, CLRSELINGO);
+
+		scbptr = ahc_inb(ahc, WAITING_SCBH);
+		ahc_outb(ahc, SCBPTR, scbptr);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("%s: ahc_intr - referenced scb not "
+			       "valid during SELTO scb(%d, %d)\n",
+			       ahc_name(ahc), scbptr, scb_index);
+			ahc_dump_card_state(ahc);
+		} else {
+			struct ahc_devinfo devinfo;
+#ifdef AHC_DEBUG
+			if ((ahc_debug & AHC_SHOW_SELTO) != 0) {
+				ahc_print_path(ahc, scb);
+				printf("Saw Selection Timeout for SCB 0x%x\n",
+				       scb_index);
+			}
+#endif
+			/*
+			 * Force a renegotiation with this target just in
+			 * case the cable was pulled and will later be
+			 * re-attached.  The target may forget its negotiation
+			 * settings with us should it attempt to reselect
+			 * during the interruption.  The target will not issue
+			 * a unit attention in this case, so we must always
+			 * renegotiate.
+			 */
+			ahc_scb_devinfo(ahc, &devinfo, scb);
+			ahc_force_renegotiation(ahc, &devinfo);
+			ahc_set_transaction_status(scb, CAM_SEL_TIMEOUT);
+			ahc_freeze_devq(ahc, scb);
+		}
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		ahc_restart(ahc);
+	} else if ((status & BUSFREE) != 0
+		&& (ahc_inb(ahc, SIMODE1) & ENBUSFREE) != 0) {
+		struct	ahc_devinfo devinfo;
+		u_int	lastphase;
+		u_int	saved_scsiid;
+		u_int	saved_lun;
+		u_int	target;
+		u_int	initiator_role_id;
+		char	channel;
+		int	printerror;
+
+		/*
+		 * Clear our selection hardware as soon as possible.
+		 * We may have an entry in the waiting Q for this target,
+		 * that is affected by this busfree and we don't want to
+		 * go about selecting the target while we handle the event.
+		 */
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP));
+
+		/*
+		 * Disable busfree interrupts and clear the busfree
+		 * interrupt status.  We do this here so that several
+		 * bus transactions occur prior to clearing the SCSIINT
+		 * latch.  It can take a bit for the clearing to take effect.
+		 */
+		ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENBUSFREE);
+		ahc_outb(ahc, CLRSINT1, CLRBUSFREE|CLRSCSIPERR);
+
+		/*
+		 * Look at what phase we were last in.
+		 * If its message out, chances are pretty good
+		 * that the busfree was in response to one of
+		 * our abort requests.
+		 */
+		lastphase = ahc_inb(ahc, LASTPHASE);
+		saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+		saved_lun = ahc_inb(ahc, SAVED_LUN);
+		target = SCSIID_TARGET(ahc, saved_scsiid);
+		initiator_role_id = SCSIID_OUR_ID(saved_scsiid);
+		channel = SCSIID_CHANNEL(ahc, saved_scsiid);
+		ahc_compile_devinfo(&devinfo, initiator_role_id,
+				    target, saved_lun, channel, ROLE_INITIATOR);
+		printerror = 1;
+
+		if (lastphase == P_MESGOUT) {
+			u_int tag;
+
+			tag = SCB_LIST_NULL;
+			if (ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT_TAG, TRUE)
+			 || ahc_sent_msg(ahc, AHCMSG_1B, MSG_ABORT, TRUE)) {
+				if (ahc->msgout_buf[ahc->msgout_index - 1]
+				 == MSG_ABORT_TAG)
+					tag = scb->hscb->tag;
+				ahc_print_path(ahc, scb);
+				printf("SCB %d - Abort%s Completed.\n",
+				       scb->hscb->tag, tag == SCB_LIST_NULL ?
+				       "" : " Tag");
+				ahc_abort_scbs(ahc, target, channel,
+					       saved_lun, tag,
+					       ROLE_INITIATOR,
+					       CAM_REQ_ABORTED);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_1B,
+						MSG_BUS_DEV_RESET, TRUE)) {
+#ifdef __FreeBSD__
+				/*
+				 * Don't mark the user's request for this BDR
+				 * as completing with CAM_BDR_SENT.  CAM3
+				 * specifies CAM_REQ_CMP.
+				 */
+				if (scb != NULL
+				 && scb->io_ctx->ccb_h.func_code== XPT_RESET_DEV
+				 && ahc_match_scb(ahc, scb, target, channel,
+						  CAM_LUN_WILDCARD,
+						  SCB_LIST_NULL,
+						  ROLE_INITIATOR)) {
+					ahc_set_transaction_status(scb, CAM_REQ_CMP);
+				}
+#endif
+				ahc_compile_devinfo(&devinfo,
+						    initiator_role_id,
+						    target,
+						    CAM_LUN_WILDCARD,
+						    channel,
+						    ROLE_INITIATOR);
+				ahc_handle_devreset(ahc, &devinfo,
+						    CAM_BDR_SENT,
+						    "Bus Device Reset",
+						    /*verbose_level*/0);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_PPR, FALSE)) {
+				struct ahc_initiator_tinfo *tinfo;
+				struct ahc_tmode_tstate *tstate;
+
+				/*
+				 * PPR Rejected.  Try non-ppr negotiation
+				 * and retry command.
+				 */
+				tinfo = ahc_fetch_transinfo(ahc,
+							    devinfo.channel,
+							    devinfo.our_scsiid,
+							    devinfo.target,
+							    &tstate);
+				tinfo->curr.transport_version = 2;
+				tinfo->goal.transport_version = 2;
+				tinfo->goal.ppr_options = 0;
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_WDTR, FALSE)) {
+				/*
+				 * Negotiation Rejected.  Go-narrow and
+				 * retry command.
+				 */
+				ahc_set_width(ahc, &devinfo,
+					      MSG_EXT_WDTR_BUS_8_BIT,
+					      AHC_TRANS_CUR|AHC_TRANS_GOAL,
+					      /*paused*/TRUE);
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				printerror = 0;
+			} else if (ahc_sent_msg(ahc, AHCMSG_EXT,
+						MSG_EXT_SDTR, FALSE)) {
+				/*
+				 * Negotiation Rejected.  Go-async and
+				 * retry command.
+				 */
+				ahc_set_syncrate(ahc, &devinfo,
+						/*syncrate*/NULL,
+						/*period*/0, /*offset*/0,
+						/*ppr_options*/0,
+						AHC_TRANS_CUR|AHC_TRANS_GOAL,
+						/*paused*/TRUE);
+				ahc_qinfifo_requeue_tail(ahc, scb);
+				printerror = 0;
+			}
+		}
+		if (printerror != 0) {
+			u_int i;
+
+			if (scb != NULL) {
+				u_int tag;
+
+				if ((scb->hscb->control & TAG_ENB) != 0)
+					tag = scb->hscb->tag;
+				else
+					tag = SCB_LIST_NULL;
+				ahc_print_path(ahc, scb);
+				ahc_abort_scbs(ahc, target, channel,
+					       SCB_GET_LUN(scb), tag,
+					       ROLE_INITIATOR,
+					       CAM_UNEXP_BUSFREE);
+			} else {
+				/*
+				 * We had not fully identified this connection,
+				 * so we cannot abort anything.
+				 */
+				printf("%s: ", ahc_name(ahc));
+			}
+			for (i = 0; i < num_phases; i++) {
+				if (lastphase == ahc_phase_table[i].phase)
+					break;
+			}
+			if (lastphase != P_BUSFREE) {
+				/*
+				 * Renegotiate with this device at the
+				 * next oportunity just in case this busfree
+				 * is due to a negotiation mismatch with the
+				 * device.
+				 */
+				ahc_force_renegotiation(ahc, &devinfo);
+			}
+			printf("Unexpected busfree %s\n"
+			       "SEQADDR == 0x%x\n",
+			       ahc_phase_table[i].phasemsg,
+			       ahc_inb(ahc, SEQADDR0)
+				| (ahc_inb(ahc, SEQADDR1) << 8));
+		}
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		ahc_restart(ahc);
+	} else {
+		printf("%s: Missing case in ahc_handle_scsiint. status = %x\n",
+		       ahc_name(ahc), status);
+		ahc_outb(ahc, CLRINT, CLRSCSIINT);
+	}
+}
+
+/*
+ * Force renegotiation to occur the next time we initiate
+ * a command to the current device.
+ */
+static void
+ahc_force_renegotiation(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	struct	ahc_initiator_tinfo *targ_info;
+	struct	ahc_tmode_tstate *tstate;
+
+	targ_info = ahc_fetch_transinfo(ahc,
+					devinfo->channel,
+					devinfo->our_scsiid,
+					devinfo->target,
+					&tstate);
+	ahc_update_neg_request(ahc, devinfo, tstate,
+			       targ_info, AHC_NEG_IF_NON_ASYNC);
+}
+
+#define AHC_MAX_STEPS 2000
+void
+ahc_clear_critical_section(struct ahc_softc *ahc)
+{
+	int	stepping;
+	int	steps;
+	u_int	simode0;
+	u_int	simode1;
+
+	if (ahc->num_critical_sections == 0)
+		return;
+
+	stepping = FALSE;
+	steps = 0;
+	simode0 = 0;
+	simode1 = 0;
+	for (;;) {
+		struct	cs *cs;
+		u_int	seqaddr;
+		u_int	i;
+
+		seqaddr = ahc_inb(ahc, SEQADDR0)
+			| (ahc_inb(ahc, SEQADDR1) << 8);
+
+		/*
+		 * Seqaddr represents the next instruction to execute, 
+		 * so we are really executing the instruction just
+		 * before it.
+		 */
+		if (seqaddr != 0)
+			seqaddr -= 1;
+		cs = ahc->critical_sections;
+		for (i = 0; i < ahc->num_critical_sections; i++, cs++) {
+			
+			if (cs->begin < seqaddr && cs->end >= seqaddr)
+				break;
+		}
+
+		if (i == ahc->num_critical_sections)
+			break;
+
+		if (steps > AHC_MAX_STEPS) {
+			printf("%s: Infinite loop in critical section\n",
+			       ahc_name(ahc));
+			ahc_dump_card_state(ahc);
+			panic("critical section loop");
+		}
+
+		steps++;
+		if (stepping == FALSE) {
+
+			/*
+			 * Disable all interrupt sources so that the
+			 * sequencer will not be stuck by a pausing
+			 * interrupt condition while we attempt to
+			 * leave a critical section.
+			 */
+			simode0 = ahc_inb(ahc, SIMODE0);
+			ahc_outb(ahc, SIMODE0, 0);
+			simode1 = ahc_inb(ahc, SIMODE1);
+			if ((ahc->features & AHC_DT) != 0)
+				/*
+				 * On DT class controllers, we
+				 * use the enhanced busfree logic.
+				 * Unfortunately we cannot re-enable
+				 * busfree detection within the
+				 * current connection, so we must
+				 * leave it on while single stepping.
+				 */
+				ahc_outb(ahc, SIMODE1, simode1 & ENBUSFREE);
+			else
+				ahc_outb(ahc, SIMODE1, 0);
+			ahc_outb(ahc, CLRINT, CLRSCSIINT);
+			ahc_outb(ahc, SEQCTL, ahc->seqctl | STEP);
+			stepping = TRUE;
+		}
+		if ((ahc->features & AHC_DT) != 0) {
+			ahc_outb(ahc, CLRSINT1, CLRBUSFREE);
+			ahc_outb(ahc, CLRINT, CLRSCSIINT);
+		}
+		ahc_outb(ahc, HCNTRL, ahc->unpause);
+		while (!ahc_is_paused(ahc))
+			ahc_delay(200);
+	}
+	if (stepping) {
+		ahc_outb(ahc, SIMODE0, simode0);
+		ahc_outb(ahc, SIMODE1, simode1);
+		ahc_outb(ahc, SEQCTL, ahc->seqctl);
+	}
+}
+
+/*
+ * Clear any pending interrupt status.
+ */
+void
+ahc_clear_intstat(struct ahc_softc *ahc)
+{
+	/* Clear any interrupt conditions this may have caused */
+	ahc_outb(ahc, CLRSINT1, CLRSELTIMEO|CLRATNO|CLRSCSIRSTI
+				|CLRBUSFREE|CLRSCSIPERR|CLRPHASECHG|
+				CLRREQINIT);
+	ahc_flush_device_writes(ahc);
+	ahc_outb(ahc, CLRSINT0, CLRSELDO|CLRSELDI|CLRSELINGO);
+ 	ahc_flush_device_writes(ahc);
+	ahc_outb(ahc, CLRINT, CLRSCSIINT);
+	ahc_flush_device_writes(ahc);
+}
+
+/**************************** Debugging Routines ******************************/
+#ifdef AHC_DEBUG
+uint32_t ahc_debug = AHC_DEBUG_OPTS;
+#endif
+
+void
+ahc_print_scb(struct scb *scb)
+{
+	int i;
+
+	struct hardware_scb *hscb = scb->hscb;
+
+	printf("scb:%p control:0x%x scsiid:0x%x lun:%d cdb_len:%d\n",
+	       (void *)scb,
+	       hscb->control,
+	       hscb->scsiid,
+	       hscb->lun,
+	       hscb->cdb_len);
+	printf("Shared Data: ");
+	for (i = 0; i < sizeof(hscb->shared_data.cdb); i++)
+		printf("%#02x", hscb->shared_data.cdb[i]);
+	printf("        dataptr:%#x datacnt:%#x sgptr:%#x tag:%#x\n",
+		ahc_le32toh(hscb->dataptr),
+		ahc_le32toh(hscb->datacnt),
+		ahc_le32toh(hscb->sgptr),
+		hscb->tag);
+	if (scb->sg_count > 0) {
+		for (i = 0; i < scb->sg_count; i++) {
+			printf("sg[%d] - Addr 0x%x%x : Length %d\n",
+			       i,
+			       (ahc_le32toh(scb->sg_list[i].len) >> 24
+			        & SG_HIGH_ADDR_BITS),
+			       ahc_le32toh(scb->sg_list[i].addr),
+			       ahc_le32toh(scb->sg_list[i].len));
+		}
+	}
+}
+
+/************************* Transfer Negotiation *******************************/
+/*
+ * Allocate per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static struct ahc_tmode_tstate *
+ahc_alloc_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel)
+{
+	struct ahc_tmode_tstate *master_tstate;
+	struct ahc_tmode_tstate *tstate;
+	int i;
+
+	master_tstate = ahc->enabled_targets[ahc->our_id];
+	if (channel == 'B') {
+		scsi_id += 8;
+		master_tstate = ahc->enabled_targets[ahc->our_id_b + 8];
+	}
+	if (ahc->enabled_targets[scsi_id] != NULL
+	 && ahc->enabled_targets[scsi_id] != master_tstate)
+		panic("%s: ahc_alloc_tstate - Target already allocated",
+		      ahc_name(ahc));
+	tstate = (struct ahc_tmode_tstate*)malloc(sizeof(*tstate),
+						   M_DEVBUF, M_NOWAIT);
+	if (tstate == NULL)
+		return (NULL);
+
+	/*
+	 * If we have allocated a master tstate, copy user settings from
+	 * the master tstate (taken from SRAM or the EEPROM) for this
+	 * channel, but reset our current and goal settings to async/narrow
+	 * until an initiator talks to us.
+	 */
+	if (master_tstate != NULL) {
+		memcpy(tstate, master_tstate, sizeof(*tstate));
+		memset(tstate->enabled_luns, 0, sizeof(tstate->enabled_luns));
+		tstate->ultraenb = 0;
+		for (i = 0; i < AHC_NUM_TARGETS; i++) {
+			memset(&tstate->transinfo[i].curr, 0,
+			      sizeof(tstate->transinfo[i].curr));
+			memset(&tstate->transinfo[i].goal, 0,
+			      sizeof(tstate->transinfo[i].goal));
+		}
+	} else
+		memset(tstate, 0, sizeof(*tstate));
+	ahc->enabled_targets[scsi_id] = tstate;
+	return (tstate);
+}
+
+#ifdef AHC_TARGET_MODE
+/*
+ * Free per target mode instance (ID we respond to as a target)
+ * transfer negotiation data structures.
+ */
+static void
+ahc_free_tstate(struct ahc_softc *ahc, u_int scsi_id, char channel, int force)
+{
+	struct ahc_tmode_tstate *tstate;
+
+	/*
+	 * Don't clean up our "master" tstate.
+	 * It has our default user settings.
+	 */
+	if (((channel == 'B' && scsi_id == ahc->our_id_b)
+	  || (channel == 'A' && scsi_id == ahc->our_id))
+	 && force == FALSE)
+		return;
+
+	if (channel == 'B')
+		scsi_id += 8;
+	tstate = ahc->enabled_targets[scsi_id];
+	if (tstate != NULL)
+		free(tstate, M_DEVBUF);
+	ahc->enabled_targets[scsi_id] = NULL;
+}
+#endif
+
+/*
+ * Called when we have an active connection to a target on the bus,
+ * this function finds the nearest syncrate to the input period limited
+ * by the capabilities of the bus connectivity of and sync settings for
+ * the target.
+ */
+struct ahc_syncrate *
+ahc_devlimited_syncrate(struct ahc_softc *ahc,
+			struct ahc_initiator_tinfo *tinfo,
+			u_int *period, u_int *ppr_options, role_t role)
+{
+	struct	ahc_transinfo *transinfo;
+	u_int	maxsync;
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		if ((ahc_inb(ahc, SBLKCTL) & ENAB40) != 0
+		 && (ahc_inb(ahc, SSTAT2) & EXP_ACTIVE) == 0) {
+			maxsync = AHC_SYNCRATE_DT;
+		} else {
+			maxsync = AHC_SYNCRATE_ULTRA;
+			/* Can't do DT on an SE bus */
+			*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+		}
+	} else if ((ahc->features & AHC_ULTRA) != 0) {
+		maxsync = AHC_SYNCRATE_ULTRA;
+	} else {
+		maxsync = AHC_SYNCRATE_FAST;
+	}
+	/*
+	 * Never allow a value higher than our current goal
+	 * period otherwise we may allow a target initiated
+	 * negotiation to go above the limit as set by the
+	 * user.  In the case of an initiator initiated
+	 * sync negotiation, we limit based on the user
+	 * setting.  This allows the system to still accept
+	 * incoming negotiations even if target initiated
+	 * negotiation is not performed.
+	 */
+	if (role == ROLE_TARGET)
+		transinfo = &tinfo->user;
+	else 
+		transinfo = &tinfo->goal;
+	*ppr_options &= transinfo->ppr_options;
+	if (transinfo->width == MSG_EXT_WDTR_BUS_8_BIT) {
+		maxsync = MAX(maxsync, AHC_SYNCRATE_ULTRA2);
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	}
+	if (transinfo->period == 0) {
+		*period = 0;
+		*ppr_options = 0;
+		return (NULL);
+	}
+	*period = MAX(*period, transinfo->period);
+	return (ahc_find_syncrate(ahc, period, ppr_options, maxsync));
+}
+
+/*
+ * Look up the valid period to SCSIRATE conversion in our table.
+ * Return the period and offset that should be sent to the target
+ * if this was the beginning of an SDTR.
+ */
+struct ahc_syncrate *
+ahc_find_syncrate(struct ahc_softc *ahc, u_int *period,
+		  u_int *ppr_options, u_int maxsync)
+{
+	struct ahc_syncrate *syncrate;
+
+	if ((ahc->features & AHC_DT) == 0)
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+
+	/* Skip all DT only entries if DT is not available */
+	if ((*ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+	 && maxsync < AHC_SYNCRATE_ULTRA2)
+		maxsync = AHC_SYNCRATE_ULTRA2;
+	
+	for (syncrate = &ahc_syncrates[maxsync];
+	     syncrate->rate != NULL;
+	     syncrate++) {
+
+		/*
+		 * The Ultra2 table doesn't go as low
+		 * as for the Fast/Ultra cards.
+		 */
+		if ((ahc->features & AHC_ULTRA2) != 0
+		 && (syncrate->sxfr_u2 == 0))
+			break;
+
+		if (*period <= syncrate->period) {
+			/*
+			 * When responding to a target that requests
+			 * sync, the requested rate may fall between
+			 * two rates that we can output, but still be
+			 * a rate that we can receive.  Because of this,
+			 * we want to respond to the target with
+			 * the same rate that it sent to us even
+			 * if the period we use to send data to it
+			 * is lower.  Only lower the response period
+			 * if we must.
+			 */
+			if (syncrate == &ahc_syncrates[maxsync])
+				*period = syncrate->period;
+
+			/*
+			 * At some speeds, we only support
+			 * ST transfers.
+			 */
+		 	if ((syncrate->sxfr_u2 & ST_SXFR) != 0)
+				*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+			break;
+		}
+	}
+
+	if ((*period == 0)
+	 || (syncrate->rate == NULL)
+	 || ((ahc->features & AHC_ULTRA2) != 0
+	  && (syncrate->sxfr_u2 == 0))) {
+		/* Use asynchronous transfers. */
+		*period = 0;
+		syncrate = NULL;
+		*ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+	}
+	return (syncrate);
+}
+
+/*
+ * Convert from an entry in our syncrate table to the SCSI equivalent
+ * sync "period" factor.
+ */
+u_int
+ahc_find_period(struct ahc_softc *ahc, u_int scsirate, u_int maxsync)
+{
+	struct ahc_syncrate *syncrate;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		scsirate &= SXFR_ULTRA2;
+	else
+		scsirate &= SXFR;
+
+	syncrate = &ahc_syncrates[maxsync];
+	while (syncrate->rate != NULL) {
+
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			if (syncrate->sxfr_u2 == 0)
+				break;
+			else if (scsirate == (syncrate->sxfr_u2 & SXFR_ULTRA2))
+				return (syncrate->period);
+		} else if (scsirate == (syncrate->sxfr & SXFR)) {
+				return (syncrate->period);
+		}
+		syncrate++;
+	}
+	return (0); /* async */
+}
+
+/*
+ * Truncate the given synchronous offset to a value the
+ * current adapter type and syncrate are capable of.
+ */
+void
+ahc_validate_offset(struct ahc_softc *ahc,
+		    struct ahc_initiator_tinfo *tinfo,
+		    struct ahc_syncrate *syncrate,
+		    u_int *offset, int wide, role_t role)
+{
+	u_int maxoffset;
+
+	/* Limit offset to what we can do */
+	if (syncrate == NULL) {
+		maxoffset = 0;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		maxoffset = MAX_OFFSET_ULTRA2;
+	} else {
+		if (wide)
+			maxoffset = MAX_OFFSET_16BIT;
+		else
+			maxoffset = MAX_OFFSET_8BIT;
+	}
+	*offset = MIN(*offset, maxoffset);
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*offset = MIN(*offset, tinfo->user.offset);
+		else
+			*offset = MIN(*offset, tinfo->goal.offset);
+	}
+}
+
+/*
+ * Truncate the given transfer width parameter to a value the
+ * current adapter type is capable of.
+ */
+void
+ahc_validate_width(struct ahc_softc *ahc, struct ahc_initiator_tinfo *tinfo,
+		   u_int *bus_width, role_t role)
+{
+	switch (*bus_width) {
+	default:
+		if (ahc->features & AHC_WIDE) {
+			/* Respond Wide */
+			*bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+			break;
+		}
+		/* FALLTHROUGH */
+	case MSG_EXT_WDTR_BUS_8_BIT:
+		*bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+		break;
+	}
+	if (tinfo != NULL) {
+		if (role == ROLE_TARGET)
+			*bus_width = MIN(tinfo->user.width, *bus_width);
+		else
+			*bus_width = MIN(tinfo->goal.width, *bus_width);
+	}
+}
+
+/*
+ * Update the bitmask of targets for which the controller should
+ * negotiate with at the next convenient oportunity.  This currently
+ * means the next time we send the initial identify messages for
+ * a new transaction.
+ */
+int
+ahc_update_neg_request(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		       struct ahc_tmode_tstate *tstate,
+		       struct ahc_initiator_tinfo *tinfo, ahc_neg_type neg_type)
+{
+	u_int auto_negotiate_orig;
+
+	auto_negotiate_orig = tstate->auto_negotiate;
+	if (neg_type == AHC_NEG_ALWAYS) {
+		/*
+		 * Force our "current" settings to be
+		 * unknown so that unless a bus reset
+		 * occurs the need to renegotiate is
+		 * recorded persistently.
+		 */
+		if ((ahc->features & AHC_WIDE) != 0)
+			tinfo->curr.width = AHC_WIDTH_UNKNOWN;
+		tinfo->curr.period = AHC_PERIOD_UNKNOWN;
+		tinfo->curr.offset = AHC_OFFSET_UNKNOWN;
+	}
+	if (tinfo->curr.period != tinfo->goal.period
+	 || tinfo->curr.width != tinfo->goal.width
+	 || tinfo->curr.offset != tinfo->goal.offset
+	 || tinfo->curr.ppr_options != tinfo->goal.ppr_options
+	 || (neg_type == AHC_NEG_IF_NON_ASYNC
+	  && (tinfo->goal.offset != 0
+	   || tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT
+	   || tinfo->goal.ppr_options != 0)))
+		tstate->auto_negotiate |= devinfo->target_mask;
+	else
+		tstate->auto_negotiate &= ~devinfo->target_mask;
+
+	return (auto_negotiate_orig != tstate->auto_negotiate);
+}
+
+/*
+ * Update the user/goal/curr tables of synchronous negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahc_set_syncrate(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		 struct ahc_syncrate *syncrate, u_int period,
+		 u_int offset, u_int ppr_options, u_int type, int paused)
+{
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	u_int	old_period;
+	u_int	old_offset;
+	u_int	old_ppr;
+	int	active;
+	int	update_needed;
+
+	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	update_needed = 0;
+
+	if (syncrate == NULL) {
+		period = 0;
+		offset = 0;
+	}
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHC_TRANS_USER) != 0) {
+		tinfo->user.period = period;
+		tinfo->user.offset = offset;
+		tinfo->user.ppr_options = ppr_options;
+	}
+
+	if ((type & AHC_TRANS_GOAL) != 0) {
+		tinfo->goal.period = period;
+		tinfo->goal.offset = offset;
+		tinfo->goal.ppr_options = ppr_options;
+	}
+
+	old_period = tinfo->curr.period;
+	old_offset = tinfo->curr.offset;
+	old_ppr	   = tinfo->curr.ppr_options;
+
+	if ((type & AHC_TRANS_CUR) != 0
+	 && (old_period != period
+	  || old_offset != offset
+	  || old_ppr != ppr_options)) {
+		u_int	scsirate;
+
+		update_needed++;
+		scsirate = tinfo->scsirate;
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+
+			scsirate &= ~(SXFR_ULTRA2|SINGLE_EDGE|ENABLE_CRC);
+			if (syncrate != NULL) {
+				scsirate |= syncrate->sxfr_u2;
+				if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0)
+					scsirate |= ENABLE_CRC;
+				else
+					scsirate |= SINGLE_EDGE;
+			}
+		} else {
+
+			scsirate &= ~(SXFR|SOFS);
+			/*
+			 * Ensure Ultra mode is set properly for
+			 * this target.
+			 */
+			tstate->ultraenb &= ~devinfo->target_mask;
+			if (syncrate != NULL) {
+				if (syncrate->sxfr & ULTRA_SXFR) {
+					tstate->ultraenb |=
+						devinfo->target_mask;
+				}
+				scsirate |= syncrate->sxfr & SXFR;
+				scsirate |= offset & SOFS;
+			}
+			if (active) {
+				u_int sxfrctl0;
+
+				sxfrctl0 = ahc_inb(ahc, SXFRCTL0);
+				sxfrctl0 &= ~FAST20;
+				if (tstate->ultraenb & devinfo->target_mask)
+					sxfrctl0 |= FAST20;
+				ahc_outb(ahc, SXFRCTL0, sxfrctl0);
+			}
+		}
+		if (active) {
+			ahc_outb(ahc, SCSIRATE, scsirate);
+			if ((ahc->features & AHC_ULTRA2) != 0)
+				ahc_outb(ahc, SCSIOFFSET, offset);
+		}
+
+		tinfo->scsirate = scsirate;
+		tinfo->curr.period = period;
+		tinfo->curr.offset = offset;
+		tinfo->curr.ppr_options = ppr_options;
+
+		ahc_send_async(ahc, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+		if (bootverbose) {
+			if (offset != 0) {
+				printf("%s: target %d synchronous at %sMHz%s, "
+				       "offset = 0x%x\n", ahc_name(ahc),
+				       devinfo->target, syncrate->rate,
+				       (ppr_options & MSG_EXT_PPR_DT_REQ)
+				       ? " DT" : "", offset);
+			} else {
+				printf("%s: target %d using "
+				       "asynchronous transfers\n",
+				       ahc_name(ahc), devinfo->target);
+			}
+		}
+	}
+
+	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
+						tinfo, AHC_NEG_TO_GOAL);
+
+	if (update_needed)
+		ahc_update_pending_scbs(ahc);
+}
+
+/*
+ * Update the user/goal/curr tables of wide negotiation
+ * parameters as well as, in the case of a current or active update,
+ * any data structures on the host controller.  In the case of an
+ * active update, the specified target is currently talking to us on
+ * the bus, so the transfer parameter update must take effect
+ * immediately.
+ */
+void
+ahc_set_width(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+	      u_int width, u_int type, int paused)
+{
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	u_int	oldwidth;
+	int	active;
+	int	update_needed;
+
+	active = (type & AHC_TRANS_ACTIVE) == AHC_TRANS_ACTIVE;
+	update_needed = 0;
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+
+	if ((type & AHC_TRANS_USER) != 0)
+		tinfo->user.width = width;
+
+	if ((type & AHC_TRANS_GOAL) != 0)
+		tinfo->goal.width = width;
+
+	oldwidth = tinfo->curr.width;
+	if ((type & AHC_TRANS_CUR) != 0 && oldwidth != width) {
+		u_int	scsirate;
+
+		update_needed++;
+		scsirate =  tinfo->scsirate;
+		scsirate &= ~WIDEXFER;
+		if (width == MSG_EXT_WDTR_BUS_16_BIT)
+			scsirate |= WIDEXFER;
+
+		tinfo->scsirate = scsirate;
+
+		if (active)
+			ahc_outb(ahc, SCSIRATE, scsirate);
+
+		tinfo->curr.width = width;
+
+		ahc_send_async(ahc, devinfo->channel, devinfo->target,
+			       CAM_LUN_WILDCARD, AC_TRANSFER_NEG, NULL);
+		if (bootverbose) {
+			printf("%s: target %d using %dbit transfers\n",
+			       ahc_name(ahc), devinfo->target,
+			       8 * (0x01 << width));
+		}
+	}
+
+	update_needed += ahc_update_neg_request(ahc, devinfo, tstate,
+						tinfo, AHC_NEG_TO_GOAL);
+	if (update_needed)
+		ahc_update_pending_scbs(ahc);
+}
+
+/*
+ * Update the current state of tagged queuing for a given target.
+ */
+void
+ahc_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+	     ahc_queue_alg alg)
+{
+ 	ahc_platform_set_tags(ahc, devinfo, alg);
+ 	ahc_send_async(ahc, devinfo->channel, devinfo->target,
+ 		       devinfo->lun, AC_TRANSFER_NEG, &alg);
+}
+
+/*
+ * When the transfer settings for a connection change, update any
+ * in-transit SCBs to contain the new data so the hardware will
+ * be set correctly during future (re)selections.
+ */
+static void
+ahc_update_pending_scbs(struct ahc_softc *ahc)
+{
+	struct	scb *pending_scb;
+	int	pending_scb_count;
+	int	i;
+	int	paused;
+	u_int	saved_scbptr;
+
+	/*
+	 * Traverse the pending SCB list and ensure that all of the
+	 * SCBs there have the proper settings.
+	 */
+	pending_scb_count = 0;
+	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		struct ahc_devinfo devinfo;
+		struct hardware_scb *pending_hscb;
+		struct ahc_initiator_tinfo *tinfo;
+		struct ahc_tmode_tstate *tstate;
+
+		ahc_scb_devinfo(ahc, &devinfo, pending_scb);
+		tinfo = ahc_fetch_transinfo(ahc, devinfo.channel,
+					    devinfo.our_scsiid,
+					    devinfo.target, &tstate);
+		pending_hscb = pending_scb->hscb;
+		pending_hscb->control &= ~ULTRAENB;
+		if ((tstate->ultraenb & devinfo.target_mask) != 0)
+			pending_hscb->control |= ULTRAENB;
+		pending_hscb->scsirate = tinfo->scsirate;
+		pending_hscb->scsioffset = tinfo->curr.offset;
+		if ((tstate->auto_negotiate & devinfo.target_mask) == 0
+		 && (pending_scb->flags & SCB_AUTO_NEGOTIATE) != 0) {
+			pending_scb->flags &= ~SCB_AUTO_NEGOTIATE;
+			pending_hscb->control &= ~MK_MESSAGE;
+		}
+		ahc_sync_scb(ahc, pending_scb,
+			     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+		pending_scb_count++;
+	}
+
+	if (pending_scb_count == 0)
+		return;
+
+	if (ahc_is_paused(ahc)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahc_pause(ahc);
+	}
+
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+	/* Ensure that the hscbs down on the card match the new information */
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		struct	hardware_scb *pending_hscb;
+		u_int	control;
+		u_int	scb_tag;
+
+		ahc_outb(ahc, SCBPTR, i);
+		scb_tag = ahc_inb(ahc, SCB_TAG);
+		pending_scb = ahc_lookup_scb(ahc, scb_tag);
+		if (pending_scb == NULL)
+			continue;
+
+		pending_hscb = pending_scb->hscb;
+		control = ahc_inb(ahc, SCB_CONTROL);
+		control &= ~(ULTRAENB|MK_MESSAGE);
+		control |= pending_hscb->control & (ULTRAENB|MK_MESSAGE);
+		ahc_outb(ahc, SCB_CONTROL, control);
+		ahc_outb(ahc, SCB_SCSIRATE, pending_hscb->scsirate);
+		ahc_outb(ahc, SCB_SCSIOFFSET, pending_hscb->scsioffset);
+	}
+	ahc_outb(ahc, SCBPTR, saved_scbptr);
+
+	if (paused == 0)
+		ahc_unpause(ahc);
+}
+
+/**************************** Pathing Information *****************************/
+static void
+ahc_fetch_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	u_int	saved_scsiid;
+	role_t	role;
+	int	our_id;
+
+	if (ahc_inb(ahc, SSTAT0) & TARGET)
+		role = ROLE_TARGET;
+	else
+		role = ROLE_INITIATOR;
+
+	if (role == ROLE_TARGET
+	 && (ahc->features & AHC_MULTI_TID) != 0
+	 && (ahc_inb(ahc, SEQ_FLAGS)
+ 	   & (CMDPHASE_PENDING|TARG_CMD_PENDING|NO_DISCONNECT)) != 0) {
+		/* We were selected, so pull our id from TARGIDIN */
+		our_id = ahc_inb(ahc, TARGIDIN) & OID;
+	} else if ((ahc->features & AHC_ULTRA2) != 0)
+		our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+	else
+		our_id = ahc_inb(ahc, SCSIID) & OID;
+
+	saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+	ahc_compile_devinfo(devinfo,
+			    our_id,
+			    SCSIID_TARGET(ahc, saved_scsiid),
+			    ahc_inb(ahc, SAVED_LUN),
+			    SCSIID_CHANNEL(ahc, saved_scsiid),
+			    role);
+}
+
+struct ahc_phase_table_entry*
+ahc_lookup_phase_entry(int phase)
+{
+	struct ahc_phase_table_entry *entry;
+	struct ahc_phase_table_entry *last_entry;
+
+	/*
+	 * num_phases doesn't include the default entry which
+	 * will be returned if the phase doesn't match.
+	 */
+	last_entry = &ahc_phase_table[num_phases];
+	for (entry = ahc_phase_table; entry < last_entry; entry++) {
+		if (phase == entry->phase)
+			break;
+	}
+	return (entry);
+}
+
+void
+ahc_compile_devinfo(struct ahc_devinfo *devinfo, u_int our_id, u_int target,
+		    u_int lun, char channel, role_t role)
+{
+	devinfo->our_scsiid = our_id;
+	devinfo->target = target;
+	devinfo->lun = lun;
+	devinfo->target_offset = target;
+	devinfo->channel = channel;
+	devinfo->role = role;
+	if (channel == 'B')
+		devinfo->target_offset += 8;
+	devinfo->target_mask = (0x01 << devinfo->target_offset);
+}
+
+void
+ahc_print_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	printf("%s:%c:%d:%d: ", ahc_name(ahc), devinfo->channel,
+	       devinfo->target, devinfo->lun);
+}
+
+static void
+ahc_scb_devinfo(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		struct scb *scb)
+{
+	role_t	role;
+	int	our_id;
+
+	our_id = SCSIID_OUR_ID(scb->hscb->scsiid);
+	role = ROLE_INITIATOR;
+	if ((scb->flags & SCB_TARGET_SCB) != 0)
+		role = ROLE_TARGET;
+	ahc_compile_devinfo(devinfo, our_id, SCB_GET_TARGET(ahc, scb),
+			    SCB_GET_LUN(scb), SCB_GET_CHANNEL(ahc, scb), role);
+}
+
+
+/************************ Message Phase Processing ****************************/
+static void
+ahc_assert_atn(struct ahc_softc *ahc)
+{
+	u_int scsisigo;
+
+	scsisigo = ATNO;
+	if ((ahc->features & AHC_DT) == 0)
+		scsisigo |= ahc_inb(ahc, SCSISIGI);
+	ahc_outb(ahc, SCSISIGO, scsisigo);
+}
+
+/*
+ * When an initiator transaction with the MK_MESSAGE flag either reconnects
+ * or enters the initial message out phase, we are interrupted.  Fill our
+ * outgoing message buffer with the appropriate message and beging handing
+ * the message phase(s) manually.
+ */
+static void
+ahc_setup_initiator_msgout(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+			   struct scb *scb)
+{
+	/*
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */
+	ahc->msgout_index = 0;
+	ahc->msgout_len = 0;
+
+	if ((scb->flags & SCB_DEVICE_RESET) == 0
+	 && ahc_inb(ahc, MSG_OUT) == MSG_IDENTIFYFLAG) {
+		u_int identify_msg;
+
+		identify_msg = MSG_IDENTIFYFLAG | SCB_GET_LUN(scb);
+		if ((scb->hscb->control & DISCENB) != 0)
+			identify_msg |= MSG_IDENTIFY_DISCFLAG;
+		ahc->msgout_buf[ahc->msgout_index++] = identify_msg;
+		ahc->msgout_len++;
+
+		if ((scb->hscb->control & TAG_ENB) != 0) {
+			ahc->msgout_buf[ahc->msgout_index++] =
+			    scb->hscb->control & (TAG_ENB|SCB_TAG_TYPE);
+			ahc->msgout_buf[ahc->msgout_index++] = scb->hscb->tag;
+			ahc->msgout_len += 2;
+		}
+	}
+
+	if (scb->flags & SCB_DEVICE_RESET) {
+		ahc->msgout_buf[ahc->msgout_index++] = MSG_BUS_DEV_RESET;
+		ahc->msgout_len++;
+		ahc_print_path(ahc, scb);
+		printf("Bus Device Reset Message Sent\n");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else if ((scb->flags & SCB_ABORT) != 0) {
+		if ((scb->hscb->control & TAG_ENB) != 0)
+			ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT_TAG;
+		else
+			ahc->msgout_buf[ahc->msgout_index++] = MSG_ABORT;
+		ahc->msgout_len++;
+		ahc_print_path(ahc, scb);
+		printf("Abort%s Message Sent\n",
+		       (scb->hscb->control & TAG_ENB) != 0 ? " Tag" : "");
+		/*
+		 * Clear our selection hardware in advance of
+		 * the busfree.  We may have an entry in the waiting
+		 * Q for this target, and we don't want to go about
+		 * selecting while we handle the busfree and blow it
+		 * away.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else if ((scb->flags & (SCB_AUTO_NEGOTIATE|SCB_NEGOTIATE)) != 0) {
+		ahc_build_transfer_msg(ahc, devinfo);
+	} else {
+		printf("ahc_intr: AWAITING_MSG for an SCB that "
+		       "does not have a waiting message\n");
+		printf("SCSIID = %x, target_mask = %x\n", scb->hscb->scsiid,
+		       devinfo->target_mask);
+		panic("SCB = %d, SCB Control = %x, MSG_OUT = %x "
+		      "SCB flags = %x", scb->hscb->tag, scb->hscb->control,
+		      ahc_inb(ahc, MSG_OUT), scb->flags);
+	}
+
+	/*
+	 * Clear the MK_MESSAGE flag from the SCB so we aren't
+	 * asked to send this message again.
+	 */
+	ahc_outb(ahc, SCB_CONTROL, ahc_inb(ahc, SCB_CONTROL) & ~MK_MESSAGE);
+	scb->hscb->control &= ~MK_MESSAGE;
+	ahc->msgout_index = 0;
+	ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+}
+
+/*
+ * Build an appropriate transfer negotiation message for the
+ * currently active target.
+ */
+static void
+ahc_build_transfer_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	/*
+	 * We need to initiate transfer negotiations.
+	 * If our current and goal settings are identical,
+	 * we want to renegotiate due to a check condition.
+	 */
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	struct	ahc_syncrate *rate;
+	int	dowide;
+	int	dosync;
+	int	doppr;
+	u_int	period;
+	u_int	ppr_options;
+	u_int	offset;
+
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	/*
+	 * Filter our period based on the current connection.
+	 * If we can't perform DT transfers on this segment (not in LVD
+	 * mode for instance), then our decision to issue a PPR message
+	 * may change.
+	 */
+	period = tinfo->goal.period;
+	offset = tinfo->goal.offset;
+	ppr_options = tinfo->goal.ppr_options;
+	/* Target initiated PPR is not allowed in the SCSI spec */
+	if (devinfo->role == ROLE_TARGET)
+		ppr_options = 0;
+	rate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+				       &ppr_options, devinfo->role);
+	dowide = tinfo->curr.width != tinfo->goal.width;
+	dosync = tinfo->curr.offset != offset || tinfo->curr.period != period;
+	/*
+	 * Only use PPR if we have options that need it, even if the device
+	 * claims to support it.  There might be an expander in the way
+	 * that doesn't.
+	 */
+	doppr = ppr_options != 0;
+
+	if (!dowide && !dosync && !doppr) {
+		dowide = tinfo->goal.width != MSG_EXT_WDTR_BUS_8_BIT;
+		dosync = tinfo->goal.offset != 0;
+	}
+
+	if (!dowide && !dosync && !doppr) {
+		/*
+		 * Force async with a WDTR message if we have a wide bus,
+		 * or just issue an SDTR with a 0 offset.
+		 */
+		if ((ahc->features & AHC_WIDE) != 0)
+			dowide = 1;
+		else
+			dosync = 1;
+
+		if (bootverbose) {
+			ahc_print_devinfo(ahc, devinfo);
+			printf("Ensuring async\n");
+		}
+	}
+
+	/* Target initiated PPR is not allowed in the SCSI spec */
+	if (devinfo->role == ROLE_TARGET)
+		doppr = 0;
+
+	/*
+	 * Both the PPR message and SDTR message require the
+	 * goal syncrate to be limited to what the target device
+	 * is capable of handling (based on whether an LVD->SE
+	 * expander is on the bus), so combine these two cases.
+	 * Regardless, guarantee that if we are using WDTR and SDTR
+	 * messages that WDTR comes first.
+	 */
+	if (doppr || (dosync && !dowide)) {
+
+		offset = tinfo->goal.offset;
+		ahc_validate_offset(ahc, tinfo, rate, &offset,
+				    doppr ? tinfo->goal.width
+					  : tinfo->curr.width,
+				    devinfo->role);
+		if (doppr) {
+			ahc_construct_ppr(ahc, devinfo, period, offset,
+					  tinfo->goal.width, ppr_options);
+		} else {
+			ahc_construct_sdtr(ahc, devinfo, period, offset);
+		}
+	} else {
+		ahc_construct_wdtr(ahc, devinfo, tinfo->goal.width);
+	}
+}
+
+/*
+ * Build a synchronous negotiation message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_sdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		   u_int period, u_int offset)
+{
+	if (offset == 0)
+		period = AHC_ASYNC_XFER_PERIOD;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_SDTR;
+	ahc->msgout_buf[ahc->msgout_index++] = period;
+	ahc->msgout_buf[ahc->msgout_index++] = offset;
+	ahc->msgout_len += 5;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending SDTR period %x, offset %x\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       devinfo->lun, period, offset);
+	}
+}
+
+/*
+ * Build a wide negotiation message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_wdtr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		   u_int bus_width)
+{
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_WDTR;
+	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+	ahc->msgout_len += 4;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending WDTR %x\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       devinfo->lun, bus_width);
+	}
+}
+
+/*
+ * Build a parallel protocol request message in our message
+ * buffer based on the input parameters.
+ */
+static void
+ahc_construct_ppr(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		  u_int period, u_int offset, u_int bus_width,
+		  u_int ppr_options)
+{
+	if (offset == 0)
+		period = AHC_ASYNC_XFER_PERIOD;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXTENDED;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR_LEN;
+	ahc->msgout_buf[ahc->msgout_index++] = MSG_EXT_PPR;
+	ahc->msgout_buf[ahc->msgout_index++] = period;
+	ahc->msgout_buf[ahc->msgout_index++] = 0;
+	ahc->msgout_buf[ahc->msgout_index++] = offset;
+	ahc->msgout_buf[ahc->msgout_index++] = bus_width;
+	ahc->msgout_buf[ahc->msgout_index++] = ppr_options;
+	ahc->msgout_len += 8;
+	if (bootverbose) {
+		printf("(%s:%c:%d:%d): Sending PPR bus_width %x, period %x, "
+		       "offset %x, ppr_options %x\n", ahc_name(ahc),
+		       devinfo->channel, devinfo->target, devinfo->lun,
+		       bus_width, period, offset, ppr_options);
+	}
+}
+
+/*
+ * Clear any active message state.
+ */
+static void
+ahc_clear_msg_state(struct ahc_softc *ahc)
+{
+	ahc->msgout_len = 0;
+	ahc->msgin_index = 0;
+	ahc->msg_type = MSG_TYPE_NONE;
+	if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0) {
+		/*
+		 * The target didn't care to respond to our
+		 * message request, so clear ATN.
+		 */
+		ahc_outb(ahc, CLRSINT1, CLRATNO);
+	}
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+	ahc_outb(ahc, SEQ_FLAGS2,
+		 ahc_inb(ahc, SEQ_FLAGS2) & ~TARGET_MSG_PENDING);
+}
+
+static void
+ahc_handle_proto_violation(struct ahc_softc *ahc)
+{
+	struct	ahc_devinfo devinfo;
+	struct	scb *scb;
+	u_int	scbid;
+	u_int	seq_flags;
+	u_int	curphase;
+	u_int	lastphase;
+	int	found;
+
+	ahc_fetch_devinfo(ahc, &devinfo);
+	scbid = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scbid);
+	seq_flags = ahc_inb(ahc, SEQ_FLAGS);
+	curphase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+	lastphase = ahc_inb(ahc, LASTPHASE);
+	if ((seq_flags & NOT_IDENTIFIED) != 0) {
+
+		/*
+		 * The reconnecting target either did not send an
+		 * identify message, or did, but we didn't find an SCB
+		 * to match.
+		 */
+		ahc_print_devinfo(ahc, &devinfo);
+		printf("Target did not send an IDENTIFY message. "
+		       "LASTPHASE = 0x%x.\n", lastphase);
+		scb = NULL;
+	} else if (scb == NULL) {
+		/*
+		 * We don't seem to have an SCB active for this
+		 * transaction.  Print an error and reset the bus.
+		 */
+		ahc_print_devinfo(ahc, &devinfo);
+		printf("No SCB found during protocol violation\n");
+		goto proto_violation_reset;
+	} else {
+		ahc_set_transaction_status(scb, CAM_SEQUENCE_FAIL);
+		if ((seq_flags & NO_CDB_SENT) != 0) {
+			ahc_print_path(ahc, scb);
+			printf("No or incomplete CDB sent to device.\n");
+		} else if ((ahc_inb(ahc, SCB_CONTROL) & STATUS_RCVD) == 0) {
+			/*
+			 * The target never bothered to provide status to
+			 * us prior to completing the command.  Since we don't
+			 * know the disposition of this command, we must attempt
+			 * to abort it.  Assert ATN and prepare to send an abort
+			 * message.
+			 */
+			ahc_print_path(ahc, scb);
+			printf("Completed command without status.\n");
+		} else {
+			ahc_print_path(ahc, scb);
+			printf("Unknown protocol violation.\n");
+			ahc_dump_card_state(ahc);
+		}
+	}
+	if ((lastphase & ~P_DATAIN_DT) == 0
+	 || lastphase == P_COMMAND) {
+proto_violation_reset:
+		/*
+		 * Target either went directly to data/command
+		 * phase or didn't respond to our ATN.
+		 * The only safe thing to do is to blow
+		 * it away with a bus reset.
+		 */
+		found = ahc_reset_channel(ahc, 'A', TRUE);
+		printf("%s: Issued Channel %c Bus Reset. "
+		       "%d SCBs aborted\n", ahc_name(ahc), 'A', found);
+	} else {
+		/*
+		 * Leave the selection hardware off in case
+		 * this abort attempt will affect yet to
+		 * be sent commands.
+		 */
+		ahc_outb(ahc, SCSISEQ,
+			 ahc_inb(ahc, SCSISEQ) & ~ENSELO);
+		ahc_assert_atn(ahc);
+		ahc_outb(ahc, MSG_OUT, HOST_MSG);
+		if (scb == NULL) {
+			ahc_print_devinfo(ahc, &devinfo);
+			ahc->msgout_buf[0] = MSG_ABORT_TASK;
+			ahc->msgout_len = 1;
+			ahc->msgout_index = 0;
+			ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+		} else {
+			ahc_print_path(ahc, scb);
+			scb->flags |= SCB_ABORT;
+		}
+		printf("Protocol violation %s.  Attempting to abort.\n",
+		       ahc_lookup_phase_entry(curphase)->phasemsg);
+	}
+}
+
+/*
+ * Manual message loop handler.
+ */
+static void
+ahc_handle_message_phase(struct ahc_softc *ahc)
+{ 
+	struct	ahc_devinfo devinfo;
+	u_int	bus_phase;
+	int	end_session;
+
+	ahc_fetch_devinfo(ahc, &devinfo);
+	end_session = FALSE;
+	bus_phase = ahc_inb(ahc, SCSISIGI) & PHASE_MASK;
+
+reswitch:
+	switch (ahc->msg_type) {
+	case MSG_TYPE_INITIATOR_MSGOUT:
+	{
+		int lastbyte;
+		int phasemis;
+		int msgdone;
+
+		if (ahc->msgout_len == 0)
+			panic("HOST_MSG_LOOP interrupt with no active message");
+
+#ifdef AHC_DEBUG
+		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+			ahc_print_devinfo(ahc, &devinfo);
+			printf("INITIATOR_MSG_OUT");
+		}
+#endif
+		phasemis = bus_phase != P_MESGOUT;
+		if (phasemis) {
+#ifdef AHC_DEBUG
+			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+				printf(" PHASEMIS %s\n",
+				       ahc_lookup_phase_entry(bus_phase)
+							     ->phasemsg);
+			}
+#endif
+			if (bus_phase == P_MESGIN) {
+				/*
+				 * Change gears and see if
+				 * this messages is of interest to
+				 * us or should be passed back to
+				 * the sequencer.
+				 */
+				ahc_outb(ahc, CLRSINT1, CLRATNO);
+				ahc->send_msg_perror = FALSE;
+				ahc->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+				ahc->msgin_index = 0;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		if (ahc->send_msg_perror) {
+			ahc_outb(ahc, CLRSINT1, CLRATNO);
+			ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+#ifdef AHC_DEBUG
+			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+				printf(" byte 0x%x\n", ahc->send_msg_perror);
+#endif
+			ahc_outb(ahc, SCSIDATL, MSG_PARITY_ERROR);
+			break;
+		}
+
+		msgdone	= ahc->msgout_index == ahc->msgout_len;
+		if (msgdone) {
+			/*
+			 * The target has requested a retry.
+			 * Re-assert ATN, reset our message index to
+			 * 0, and try again.
+			 */
+			ahc->msgout_index = 0;
+			ahc_assert_atn(ahc);
+		}
+
+		lastbyte = ahc->msgout_index == (ahc->msgout_len - 1);
+		if (lastbyte) {
+			/* Last byte is signified by dropping ATN */
+			ahc_outb(ahc, CLRSINT1, CLRATNO);
+		}
+
+		/*
+		 * Clear our interrupt status and present
+		 * the next byte on the bus.
+		 */
+		ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+#ifdef AHC_DEBUG
+		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+			printf(" byte 0x%x\n",
+			       ahc->msgout_buf[ahc->msgout_index]);
+#endif
+		ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+		break;
+	}
+	case MSG_TYPE_INITIATOR_MSGIN:
+	{
+		int phasemis;
+		int message_done;
+
+#ifdef AHC_DEBUG
+		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+			ahc_print_devinfo(ahc, &devinfo);
+			printf("INITIATOR_MSG_IN");
+		}
+#endif
+		phasemis = bus_phase != P_MESGIN;
+		if (phasemis) {
+#ifdef AHC_DEBUG
+			if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+				printf(" PHASEMIS %s\n",
+				       ahc_lookup_phase_entry(bus_phase)
+							     ->phasemsg);
+			}
+#endif
+			ahc->msgin_index = 0;
+			if (bus_phase == P_MESGOUT
+			 && (ahc->send_msg_perror == TRUE
+			  || (ahc->msgout_len != 0
+			   && ahc->msgout_index == 0))) {
+				ahc->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+				goto reswitch;
+			}
+			end_session = TRUE;
+			break;
+		}
+
+		/* Pull the byte in without acking it */
+		ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIBUSL);
+#ifdef AHC_DEBUG
+		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+			printf(" byte 0x%x\n",
+			       ahc->msgin_buf[ahc->msgin_index]);
+#endif
+
+		message_done = ahc_parse_msg(ahc, &devinfo);
+
+		if (message_done) {
+			/*
+			 * Clear our incoming message buffer in case there
+			 * is another message following this one.
+			 */
+			ahc->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response,
+			 * assert ATN so the target takes us to the
+			 * message out phase.
+			 */
+			if (ahc->msgout_len != 0) {
+#ifdef AHC_DEBUG
+				if ((ahc_debug & AHC_SHOW_MESSAGES) != 0) {
+					ahc_print_devinfo(ahc, &devinfo);
+					printf("Asserting ATN for response\n");
+				}
+#endif
+				ahc_assert_atn(ahc);
+			}
+		} else 
+			ahc->msgin_index++;
+
+		if (message_done == MSGLOOP_TERMINATED) {
+			end_session = TRUE;
+		} else {
+			/* Ack the byte */
+			ahc_outb(ahc, CLRSINT1, CLRREQINIT);
+			ahc_inb(ahc, SCSIDATL);
+		}
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGIN:
+	{
+		int msgdone;
+		int msgout_request;
+
+		if (ahc->msgout_len == 0)
+			panic("Target MSGIN with no active message");
+
+		/*
+		 * If we interrupted a mesgout session, the initiator
+		 * will not know this until our first REQ.  So, we
+		 * only honor mesgout requests after we've sent our
+		 * first byte.
+		 */
+		if ((ahc_inb(ahc, SCSISIGI) & ATNI) != 0
+		 && ahc->msgout_index > 0)
+			msgout_request = TRUE;
+		else
+			msgout_request = FALSE;
+
+		if (msgout_request) {
+
+			/*
+			 * Change gears and see if
+			 * this messages is of interest to
+			 * us or should be passed back to
+			 * the sequencer.
+			 */
+			ahc->msg_type = MSG_TYPE_TARGET_MSGOUT;
+			ahc_outb(ahc, SCSISIGO, P_MESGOUT | BSYO);
+			ahc->msgin_index = 0;
+			/* Dummy read to REQ for first byte */
+			ahc_inb(ahc, SCSIDATL);
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+			break;
+		}
+
+		msgdone = ahc->msgout_index == ahc->msgout_len;
+		if (msgdone) {
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+			end_session = TRUE;
+			break;
+		}
+
+		/*
+		 * Present the next byte on the bus.
+		 */
+		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+		ahc_outb(ahc, SCSIDATL, ahc->msgout_buf[ahc->msgout_index++]);
+		break;
+	}
+	case MSG_TYPE_TARGET_MSGOUT:
+	{
+		int lastbyte;
+		int msgdone;
+
+		/*
+		 * The initiator signals that this is
+		 * the last byte by dropping ATN.
+		 */
+		lastbyte = (ahc_inb(ahc, SCSISIGI) & ATNI) == 0;
+
+		/*
+		 * Read the latched byte, but turn off SPIOEN first
+		 * so that we don't inadvertently cause a REQ for the
+		 * next byte.
+		 */
+		ahc_outb(ahc, SXFRCTL0, ahc_inb(ahc, SXFRCTL0) & ~SPIOEN);
+		ahc->msgin_buf[ahc->msgin_index] = ahc_inb(ahc, SCSIDATL);
+		msgdone = ahc_parse_msg(ahc, &devinfo);
+		if (msgdone == MSGLOOP_TERMINATED) {
+			/*
+			 * The message is *really* done in that it caused
+			 * us to go to bus free.  The sequencer has already
+			 * been reset at this point, so pull the ejection
+			 * handle.
+			 */
+			return;
+		}
+		
+		ahc->msgin_index++;
+
+		/*
+		 * XXX Read spec about initiator dropping ATN too soon
+		 *     and use msgdone to detect it.
+		 */
+		if (msgdone == MSGLOOP_MSGCOMPLETE) {
+			ahc->msgin_index = 0;
+
+			/*
+			 * If this message illicited a response, transition
+			 * to the Message in phase and send it.
+			 */
+			if (ahc->msgout_len != 0) {
+				ahc_outb(ahc, SCSISIGO, P_MESGIN | BSYO);
+				ahc_outb(ahc, SXFRCTL0,
+					 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+				ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+				ahc->msgin_index = 0;
+				break;
+			}
+		}
+
+		if (lastbyte)
+			end_session = TRUE;
+		else {
+			/* Ask for the next byte. */
+			ahc_outb(ahc, SXFRCTL0,
+				 ahc_inb(ahc, SXFRCTL0) | SPIOEN);
+		}
+
+		break;
+	}
+	default:
+		panic("Unknown REQINIT message type");
+	}
+
+	if (end_session) {
+		ahc_clear_msg_state(ahc);
+		ahc_outb(ahc, RETURN_1, EXIT_MSG_LOOP);
+	} else
+		ahc_outb(ahc, RETURN_1, CONT_MSG_LOOP);
+}
+
+/*
+ * See if we sent a particular extended message to the target.
+ * If "full" is true, return true only if the target saw the full
+ * message.  If "full" is false, return true if the target saw at
+ * least the first byte of the message.
+ */
+static int
+ahc_sent_msg(struct ahc_softc *ahc, ahc_msgtype type, u_int msgval, int full)
+{
+	int found;
+	u_int index;
+
+	found = FALSE;
+	index = 0;
+
+	while (index < ahc->msgout_len) {
+		if (ahc->msgout_buf[index] == MSG_EXTENDED) {
+			u_int end_index;
+
+			end_index = index + 1 + ahc->msgout_buf[index + 1];
+			if (ahc->msgout_buf[index+2] == msgval
+			 && type == AHCMSG_EXT) {
+
+				if (full) {
+					if (ahc->msgout_index > end_index)
+						found = TRUE;
+				} else if (ahc->msgout_index > index)
+					found = TRUE;
+			}
+			index = end_index;
+		} else if (ahc->msgout_buf[index] >= MSG_SIMPLE_TASK
+			&& ahc->msgout_buf[index] <= MSG_IGN_WIDE_RESIDUE) {
+
+			/* Skip tag type and tag id or residue param*/
+			index += 2;
+		} else {
+			/* Single byte message */
+			if (type == AHCMSG_1B
+			 && ahc->msgout_buf[index] == msgval
+			 && ahc->msgout_index > index)
+				found = TRUE;
+			index++;
+		}
+
+		if (found)
+			break;
+	}
+	return (found);
+}
+
+/*
+ * Wait for a complete incoming message, parse it, and respond accordingly.
+ */
+static int
+ahc_parse_msg(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	int	reject;
+	int	done;
+	int	response;
+	u_int	targ_scsirate;
+
+	done = MSGLOOP_IN_PROG;
+	response = FALSE;
+	reject = FALSE;
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel, devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	targ_scsirate = tinfo->scsirate;
+
+	/*
+	 * Parse as much of the message as is available,
+	 * rejecting it if we don't support it.  When
+	 * the entire message is available and has been
+	 * handled, return MSGLOOP_MSGCOMPLETE, indicating
+	 * that we have parsed an entire message.
+	 *
+	 * In the case of extended messages, we accept the length
+	 * byte outright and perform more checking once we know the
+	 * extended message type.
+	 */
+	switch (ahc->msgin_buf[0]) {
+	case MSG_DISCONNECT:
+	case MSG_SAVEDATAPOINTER:
+	case MSG_CMDCOMPLETE:
+	case MSG_RESTOREPOINTERS:
+	case MSG_IGN_WIDE_RESIDUE:
+		/*
+		 * End our message loop as these are messages
+		 * the sequencer handles on its own.
+		 */
+		done = MSGLOOP_TERMINATED;
+		break;
+	case MSG_MESSAGE_REJECT:
+		response = ahc_handle_msg_reject(ahc, devinfo);
+		/* FALLTHROUGH */
+	case MSG_NOOP:
+		done = MSGLOOP_MSGCOMPLETE;
+		break;
+	case MSG_EXTENDED:
+	{
+		/* Wait for enough of the message to begin validation */
+		if (ahc->msgin_index < 2)
+			break;
+		switch (ahc->msgin_buf[2]) {
+		case MSG_EXT_SDTR:
+		{
+			struct	 ahc_syncrate *syncrate;
+			u_int	 period;
+			u_int	 ppr_options;
+			u_int	 offset;
+			u_int	 saved_offset;
+			
+			if (ahc->msgin_buf[1] != MSG_EXT_SDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have both args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_SDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_SDTR_LEN + 1))
+				break;
+
+			period = ahc->msgin_buf[3];
+			ppr_options = 0;
+			saved_offset = offset = ahc->msgin_buf[4];
+			syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+							   &ppr_options,
+							   devinfo->role);
+			ahc_validate_offset(ahc, tinfo, syncrate, &offset,
+					    targ_scsirate & WIDEXFER,
+					    devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received "
+				       "SDTR period %x, offset %x\n\t"
+				       "Filtered to period %x, offset %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       ahc->msgin_buf[3], saved_offset,
+				       period, offset);
+			}
+			ahc_set_syncrate(ahc, devinfo, 
+					 syncrate, period,
+					 offset, ppr_options,
+					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+					 /*paused*/TRUE);
+
+			/*
+			 * See if we initiated Sync Negotiation
+			 * and didn't have to fall down to async
+			 * transfers.
+			 */
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, TRUE)) {
+				/* We started it */
+				if (saved_offset != offset) {
+					/* Went too low - force async */
+					reject = TRUE;
+				}
+			} else {
+				/*
+				 * Send our own SDTR in reply
+				 */
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated SDTR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_sdtr(ahc, devinfo,
+						   period, offset);
+				ahc->msgout_index = 0;
+				response = TRUE;
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_WDTR:
+		{
+			u_int bus_width;
+			u_int saved_width;
+			u_int sending_reply;
+
+			sending_reply = FALSE;
+			if (ahc->msgin_buf[1] != MSG_EXT_WDTR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have our arg before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_WDTR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_WDTR_LEN + 1))
+				break;
+
+			bus_width = ahc->msgin_buf[3];
+			saved_width = bus_width;
+			ahc_validate_width(ahc, tinfo, &bus_width,
+					   devinfo->role);
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received WDTR "
+				       "%x filtered to %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       saved_width, bus_width);
+			}
+
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, TRUE)) {
+				/*
+				 * Don't send a WDTR back to the
+				 * target, since we asked first.
+				 * If the width went higher than our
+				 * request, reject it.
+				 */
+				if (saved_width > bus_width) {
+					reject = TRUE;
+					printf("(%s:%c:%d:%d): requested %dBit "
+					       "transfers.  Rejecting...\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun,
+					       8 * (0x01 << bus_width));
+					bus_width = 0;
+				}
+			} else {
+				/*
+				 * Send our own WDTR in reply
+				 */
+				if (bootverbose
+				 && devinfo->role == ROLE_INITIATOR) {
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated WDTR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				}
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_wdtr(ahc, devinfo, bus_width);
+				ahc->msgout_index = 0;
+				response = TRUE;
+				sending_reply = TRUE;
+			}
+			/*
+			 * After a wide message, we are async, but
+			 * some devices don't seem to honor this portion
+			 * of the spec.  Force a renegotiation of the
+			 * sync component of our transfer agreement even
+			 * if our goal is async.  By updating our width
+			 * after forcing the negotiation, we avoid
+			 * renegotiating for width.
+			 */
+			ahc_update_neg_request(ahc, devinfo, tstate,
+					       tinfo, AHC_NEG_ALWAYS);
+			ahc_set_width(ahc, devinfo, bus_width,
+				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				      /*paused*/TRUE);
+			if (sending_reply == FALSE && reject == FALSE) {
+
+				/*
+				 * We will always have an SDTR to send.
+				 */
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_build_transfer_msg(ahc, devinfo);
+				ahc->msgout_index = 0;
+				response = TRUE;
+			}
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		case MSG_EXT_PPR:
+		{
+			struct	ahc_syncrate *syncrate;
+			u_int	period;
+			u_int	offset;
+			u_int	bus_width;
+			u_int	ppr_options;
+			u_int	saved_width;
+			u_int	saved_offset;
+			u_int	saved_ppr_options;
+
+			if (ahc->msgin_buf[1] != MSG_EXT_PPR_LEN) {
+				reject = TRUE;
+				break;
+			}
+
+			/*
+			 * Wait until we have all args before validating
+			 * and acting on this message.
+			 *
+			 * Add one to MSG_EXT_PPR_LEN to account for
+			 * the extended message preamble.
+			 */
+			if (ahc->msgin_index < (MSG_EXT_PPR_LEN + 1))
+				break;
+
+			period = ahc->msgin_buf[3];
+			offset = ahc->msgin_buf[5];
+			bus_width = ahc->msgin_buf[6];
+			saved_width = bus_width;
+			ppr_options = ahc->msgin_buf[7];
+			/*
+			 * According to the spec, a DT only
+			 * period factor with no DT option
+			 * set implies async.
+			 */
+			if ((ppr_options & MSG_EXT_PPR_DT_REQ) == 0
+			 && period == 9)
+				offset = 0;
+			saved_ppr_options = ppr_options;
+			saved_offset = offset;
+
+			/*
+			 * Mask out any options we don't support
+			 * on any controller.  Transfer options are
+			 * only available if we are negotiating wide.
+			 */
+			ppr_options &= MSG_EXT_PPR_DT_REQ;
+			if (bus_width == 0)
+				ppr_options = 0;
+
+			ahc_validate_width(ahc, tinfo, &bus_width,
+					   devinfo->role);
+			syncrate = ahc_devlimited_syncrate(ahc, tinfo, &period,
+							   &ppr_options,
+							   devinfo->role);
+			ahc_validate_offset(ahc, tinfo, syncrate,
+					    &offset, bus_width,
+					    devinfo->role);
+
+			if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, TRUE)) {
+				/*
+				 * If we are unable to do any of the
+				 * requested options (we went too low),
+				 * then we'll have to reject the message.
+				 */
+				if (saved_width > bus_width
+				 || saved_offset != offset
+				 || saved_ppr_options != ppr_options) {
+					reject = TRUE;
+					period = 0;
+					offset = 0;
+					bus_width = 0;
+					ppr_options = 0;
+					syncrate = NULL;
+				}
+			} else {
+				if (devinfo->role != ROLE_TARGET)
+					printf("(%s:%c:%d:%d): Target "
+					       "Initiated PPR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				else
+					printf("(%s:%c:%d:%d): Initiator "
+					       "Initiated PPR\n",
+					       ahc_name(ahc), devinfo->channel,
+					       devinfo->target, devinfo->lun);
+				ahc->msgout_index = 0;
+				ahc->msgout_len = 0;
+				ahc_construct_ppr(ahc, devinfo, period, offset,
+						  bus_width, ppr_options);
+				ahc->msgout_index = 0;
+				response = TRUE;
+			}
+			if (bootverbose) {
+				printf("(%s:%c:%d:%d): Received PPR width %x, "
+				       "period %x, offset %x,options %x\n"
+				       "\tFiltered to width %x, period %x, "
+				       "offset %x, options %x\n",
+				       ahc_name(ahc), devinfo->channel,
+				       devinfo->target, devinfo->lun,
+				       saved_width, ahc->msgin_buf[3],
+				       saved_offset, saved_ppr_options,
+				       bus_width, period, offset, ppr_options);
+			}
+			ahc_set_width(ahc, devinfo, bus_width,
+				      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				      /*paused*/TRUE);
+			ahc_set_syncrate(ahc, devinfo,
+					 syncrate, period,
+					 offset, ppr_options,
+					 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+					 /*paused*/TRUE);
+			done = MSGLOOP_MSGCOMPLETE;
+			break;
+		}
+		default:
+			/* Unknown extended message.  Reject it. */
+			reject = TRUE;
+			break;
+		}
+		break;
+	}
+#ifdef AHC_TARGET_MODE
+	case MSG_BUS_DEV_RESET:
+		ahc_handle_devreset(ahc, devinfo,
+				    CAM_BDR_SENT,
+				    "Bus Device Reset Received",
+				    /*verbose_level*/0);
+		ahc_restart(ahc);
+		done = MSGLOOP_TERMINATED;
+		break;
+	case MSG_ABORT_TAG:
+	case MSG_ABORT:
+	case MSG_CLEAR_QUEUE:
+	{
+		int tag;
+
+		/* Target mode messages */
+		if (devinfo->role != ROLE_TARGET) {
+			reject = TRUE;
+			break;
+		}
+		tag = SCB_LIST_NULL;
+		if (ahc->msgin_buf[0] == MSG_ABORT_TAG)
+			tag = ahc_inb(ahc, INITIATOR_TAG);
+		ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+			       devinfo->lun, tag, ROLE_TARGET,
+			       CAM_REQ_ABORTED);
+
+		tstate = ahc->enabled_targets[devinfo->our_scsiid];
+		if (tstate != NULL) {
+			struct ahc_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[devinfo->lun];
+			if (lstate != NULL) {
+				ahc_queue_lstate_event(ahc, lstate,
+						       devinfo->our_scsiid,
+						       ahc->msgin_buf[0],
+						       /*arg*/tag);
+				ahc_send_lstate_events(ahc, lstate);
+			}
+		}
+		ahc_restart(ahc);
+		done = MSGLOOP_TERMINATED;
+		break;
+	}
+#endif
+	case MSG_TERM_IO_PROC:
+	default:
+		reject = TRUE;
+		break;
+	}
+
+	if (reject) {
+		/*
+		 * Setup to reject the message.
+		 */
+		ahc->msgout_index = 0;
+		ahc->msgout_len = 1;
+		ahc->msgout_buf[0] = MSG_MESSAGE_REJECT;
+		done = MSGLOOP_MSGCOMPLETE;
+		response = TRUE;
+	}
+
+	if (done != MSGLOOP_IN_PROG && !response)
+		/* Clear the outgoing message buffer */
+		ahc->msgout_len = 0;
+
+	return (done);
+}
+
+/*
+ * Process a message reject message.
+ */
+static int
+ahc_handle_msg_reject(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	/*
+	 * What we care about here is if we had an
+	 * outstanding SDTR or WDTR message for this
+	 * target.  If we did, this is a signal that
+	 * the target is refusing negotiation.
+	 */
+	struct scb *scb;
+	struct ahc_initiator_tinfo *tinfo;
+	struct ahc_tmode_tstate *tstate;
+	u_int scb_index;
+	u_int last_msg;
+	int   response = 0;
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	/* Might be necessary */
+	last_msg = ahc_inb(ahc, LAST_MSG);
+
+	if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_PPR, /*full*/FALSE)) {
+		/*
+		 * Target does not support the PPR message.
+		 * Attempt to negotiate SPI-2 style.
+		 */
+		if (bootverbose) {
+			printf("(%s:%c:%d:%d): PPR Rejected. "
+			       "Trying WDTR/SDTR\n",
+			       ahc_name(ahc), devinfo->channel,
+			       devinfo->target, devinfo->lun);
+		}
+		tinfo->goal.ppr_options = 0;
+		tinfo->curr.transport_version = 2;
+		tinfo->goal.transport_version = 2;
+		ahc->msgout_index = 0;
+		ahc->msgout_len = 0;
+		ahc_build_transfer_msg(ahc, devinfo);
+		ahc->msgout_index = 0;
+		response = 1;
+	} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_WDTR, /*full*/FALSE)) {
+
+		/* note 8bit xfers */
+		printf("(%s:%c:%d:%d): refuses WIDE negotiation.  Using "
+		       "8bit transfers\n", ahc_name(ahc),
+		       devinfo->channel, devinfo->target, devinfo->lun);
+		ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+			      AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+			      /*paused*/TRUE);
+		/*
+		 * No need to clear the sync rate.  If the target
+		 * did not accept the command, our syncrate is
+		 * unaffected.  If the target started the negotiation,
+		 * but rejected our response, we already cleared the
+		 * sync rate before sending our WDTR.
+		 */
+		if (tinfo->goal.offset != tinfo->curr.offset) {
+
+			/* Start the sync negotiation */
+			ahc->msgout_index = 0;
+			ahc->msgout_len = 0;
+			ahc_build_transfer_msg(ahc, devinfo);
+			ahc->msgout_index = 0;
+			response = 1;
+		}
+	} else if (ahc_sent_msg(ahc, AHCMSG_EXT, MSG_EXT_SDTR, /*full*/FALSE)) {
+		/* note asynch xfers and clear flag */
+		ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL, /*period*/0,
+				 /*offset*/0, /*ppr_options*/0,
+				 AHC_TRANS_ACTIVE|AHC_TRANS_GOAL,
+				 /*paused*/TRUE);
+		printf("(%s:%c:%d:%d): refuses synchronous negotiation. "
+		       "Using asynchronous transfers\n",
+		       ahc_name(ahc), devinfo->channel,
+		       devinfo->target, devinfo->lun);
+	} else if ((scb->hscb->control & MSG_SIMPLE_TASK) != 0) {
+		int tag_type;
+		int mask;
+
+		tag_type = (scb->hscb->control & MSG_SIMPLE_TASK);
+
+		if (tag_type == MSG_SIMPLE_TASK) {
+			printf("(%s:%c:%d:%d): refuses tagged commands.  "
+			       "Performing non-tagged I/O\n", ahc_name(ahc),
+			       devinfo->channel, devinfo->target, devinfo->lun);
+			ahc_set_tags(ahc, devinfo, AHC_QUEUE_NONE);
+			mask = ~0x23;
+		} else {
+			printf("(%s:%c:%d:%d): refuses %s tagged commands.  "
+			       "Performing simple queue tagged I/O only\n",
+			       ahc_name(ahc), devinfo->channel, devinfo->target,
+			       devinfo->lun, tag_type == MSG_ORDERED_TASK
+			       ? "ordered" : "head of queue");
+			ahc_set_tags(ahc, devinfo, AHC_QUEUE_BASIC);
+			mask = ~0x03;
+		}
+
+		/*
+		 * Resend the identify for this CCB as the target
+		 * may believe that the selection is invalid otherwise.
+		 */
+		ahc_outb(ahc, SCB_CONTROL,
+			 ahc_inb(ahc, SCB_CONTROL) & mask);
+	 	scb->hscb->control &= mask;
+		ahc_set_transaction_tag(scb, /*enabled*/FALSE,
+					/*type*/MSG_SIMPLE_TASK);
+		ahc_outb(ahc, MSG_OUT, MSG_IDENTIFYFLAG);
+		ahc_assert_atn(ahc);
+
+		/*
+		 * This transaction is now at the head of
+		 * the untagged queue for this target.
+		 */
+		if ((ahc->flags & AHC_SCB_BTT) == 0) {
+			struct scb_tailq *untagged_q;
+
+			untagged_q =
+			    &(ahc->untagged_queues[devinfo->target_offset]);
+			TAILQ_INSERT_HEAD(untagged_q, scb, links.tqe);
+			scb->flags |= SCB_UNTAGGEDQ;
+		}
+		ahc_busy_tcl(ahc, BUILD_TCL(scb->hscb->scsiid, devinfo->lun),
+			     scb->hscb->tag);
+
+		/*
+		 * Requeue all tagged commands for this target
+		 * currently in our posession so they can be
+		 * converted to untagged commands.
+		 */
+		ahc_search_qinfifo(ahc, SCB_GET_TARGET(ahc, scb),
+				   SCB_GET_CHANNEL(ahc, scb),
+				   SCB_GET_LUN(scb), /*tag*/SCB_LIST_NULL,
+				   ROLE_INITIATOR, CAM_REQUEUE_REQ,
+				   SEARCH_COMPLETE);
+	} else {
+		/*
+		 * Otherwise, we ignore it.
+		 */
+		printf("%s:%c:%d: Message reject for %x -- ignored\n",
+		       ahc_name(ahc), devinfo->channel, devinfo->target,
+		       last_msg);
+	}
+	return (response);
+}
+
+/*
+ * Process an ingnore wide residue message.
+ */
+static void
+ahc_handle_ign_wide_residue(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	u_int scb_index;
+	struct scb *scb;
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	/*
+	 * XXX Actually check data direction in the sequencer?
+	 * Perhaps add datadir to some spare bits in the hscb?
+	 */
+	if ((ahc_inb(ahc, SEQ_FLAGS) & DPHASE) == 0
+	 || ahc_get_transfer_dir(scb) != CAM_DIR_IN) {
+		/*
+		 * Ignore the message if we haven't
+		 * seen an appropriate data phase yet.
+		 */
+	} else {
+		/*
+		 * If the residual occurred on the last
+		 * transfer and the transfer request was
+		 * expected to end on an odd count, do
+		 * nothing.  Otherwise, subtract a byte
+		 * and update the residual count accordingly.
+		 */
+		uint32_t sgptr;
+
+		sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
+		if ((sgptr & SG_LIST_NULL) != 0
+		 && (ahc_inb(ahc, SCB_LUN) & SCB_XFERLEN_ODD) != 0) {
+			/*
+			 * If the residual occurred on the last
+			 * transfer and the transfer request was
+			 * expected to end on an odd count, do
+			 * nothing.
+			 */
+		} else {
+			struct ahc_dma_seg *sg;
+			uint32_t data_cnt;
+			uint32_t data_addr;
+			uint32_t sglen;
+
+			/* Pull in all of the sgptr */
+			sgptr = ahc_inl(ahc, SCB_RESIDUAL_SGPTR);
+			data_cnt = ahc_inl(ahc, SCB_RESIDUAL_DATACNT);
+
+			if ((sgptr & SG_LIST_NULL) != 0) {
+				/*
+				 * The residual data count is not updated
+				 * for the command run to completion case.
+				 * Explicitly zero the count.
+				 */
+				data_cnt &= ~AHC_SG_LEN_MASK;
+			}
+
+			data_addr = ahc_inl(ahc, SHADDR);
+
+			data_cnt += 1;
+			data_addr -= 1;
+			sgptr &= SG_PTR_MASK;
+
+			sg = ahc_sg_bus_to_virt(scb, sgptr);
+
+			/*
+			 * The residual sg ptr points to the next S/G
+			 * to load so we must go back one.
+			 */
+			sg--;
+			sglen = ahc_le32toh(sg->len) & AHC_SG_LEN_MASK;
+			if (sg != scb->sg_list
+			 && sglen < (data_cnt & AHC_SG_LEN_MASK)) {
+
+				sg--;
+				sglen = ahc_le32toh(sg->len);
+				/*
+				 * Preserve High Address and SG_LIST bits
+				 * while setting the count to 1.
+				 */
+				data_cnt = 1 | (sglen & (~AHC_SG_LEN_MASK));
+				data_addr = ahc_le32toh(sg->addr)
+					  + (sglen & AHC_SG_LEN_MASK) - 1;
+
+				/*
+				 * Increment sg so it points to the
+				 * "next" sg.
+				 */
+				sg++;
+				sgptr = ahc_sg_virt_to_bus(scb, sg);
+			}
+			ahc_outl(ahc, SCB_RESIDUAL_SGPTR, sgptr);
+			ahc_outl(ahc, SCB_RESIDUAL_DATACNT, data_cnt);
+			/*
+			 * Toggle the "oddness" of the transfer length
+			 * to handle this mid-transfer ignore wide
+			 * residue.  This ensures that the oddness is
+			 * correct for subsequent data transfers.
+			 */
+			ahc_outb(ahc, SCB_LUN,
+				 ahc_inb(ahc, SCB_LUN) ^ SCB_XFERLEN_ODD);
+		}
+	}
+}
+
+
+/*
+ * Reinitialize the data pointers for the active transfer
+ * based on its current residual.
+ */
+static void
+ahc_reinitialize_dataptrs(struct ahc_softc *ahc)
+{
+	struct	 scb *scb;
+	struct	 ahc_dma_seg *sg;
+	u_int	 scb_index;
+	uint32_t sgptr;
+	uint32_t resid;
+	uint32_t dataptr;
+
+	scb_index = ahc_inb(ahc, SCB_TAG);
+	scb = ahc_lookup_scb(ahc, scb_index);
+	sgptr = (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24)
+	      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16)
+	      | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8)
+	      |	ahc_inb(ahc, SCB_RESIDUAL_SGPTR);
+
+	sgptr &= SG_PTR_MASK;
+	sg = ahc_sg_bus_to_virt(scb, sgptr);
+
+	/* The residual sg_ptr always points to the next sg */
+	sg--;
+
+	resid = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 2) << 16)
+	      | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT + 1) << 8)
+	      | ahc_inb(ahc, SCB_RESIDUAL_DATACNT);
+
+	dataptr = ahc_le32toh(sg->addr)
+		+ (ahc_le32toh(sg->len) & AHC_SG_LEN_MASK)
+		- resid;
+	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+		u_int dscommand1;
+
+		dscommand1 = ahc_inb(ahc, DSCOMMAND1);
+		ahc_outb(ahc, DSCOMMAND1, dscommand1 | HADDLDSEL0);
+		ahc_outb(ahc, HADDR,
+			 (ahc_le32toh(sg->len) >> 24) & SG_HIGH_ADDR_BITS);
+		ahc_outb(ahc, DSCOMMAND1, dscommand1);
+	}
+	ahc_outb(ahc, HADDR + 3, dataptr >> 24);
+	ahc_outb(ahc, HADDR + 2, dataptr >> 16);
+	ahc_outb(ahc, HADDR + 1, dataptr >> 8);
+	ahc_outb(ahc, HADDR, dataptr);
+	ahc_outb(ahc, HCNT + 2, resid >> 16);
+	ahc_outb(ahc, HCNT + 1, resid >> 8);
+	ahc_outb(ahc, HCNT, resid);
+	if ((ahc->features & AHC_ULTRA2) == 0) {
+		ahc_outb(ahc, STCNT + 2, resid >> 16);
+		ahc_outb(ahc, STCNT + 1, resid >> 8);
+		ahc_outb(ahc, STCNT, resid);
+	}
+}
+
+/*
+ * Handle the effects of issuing a bus device reset message.
+ */
+static void
+ahc_handle_devreset(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		    cam_status status, char *message, int verbose_level)
+{
+#ifdef AHC_TARGET_MODE
+	struct ahc_tmode_tstate* tstate;
+	u_int lun;
+#endif
+	int found;
+
+	found = ahc_abort_scbs(ahc, devinfo->target, devinfo->channel,
+			       CAM_LUN_WILDCARD, SCB_LIST_NULL, devinfo->role,
+			       status);
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * Send an immediate notify ccb to all target mord peripheral
+	 * drivers affected by this action.
+	 */
+	tstate = ahc->enabled_targets[devinfo->our_scsiid];
+	if (tstate != NULL) {
+		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+			struct ahc_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[lun];
+			if (lstate == NULL)
+				continue;
+
+			ahc_queue_lstate_event(ahc, lstate, devinfo->our_scsiid,
+					       MSG_BUS_DEV_RESET, /*arg*/0);
+			ahc_send_lstate_events(ahc, lstate);
+		}
+	}
+#endif
+
+	/*
+	 * Go back to async/narrow transfers and renegotiate.
+	 */
+	ahc_set_width(ahc, devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+		      AHC_TRANS_CUR, /*paused*/TRUE);
+	ahc_set_syncrate(ahc, devinfo, /*syncrate*/NULL,
+			 /*period*/0, /*offset*/0, /*ppr_options*/0,
+			 AHC_TRANS_CUR, /*paused*/TRUE);
+	
+	ahc_send_async(ahc, devinfo->channel, devinfo->target,
+		       CAM_LUN_WILDCARD, AC_SENT_BDR, NULL);
+
+	if (message != NULL
+	 && (verbose_level <= bootverbose))
+		printf("%s: %s on %c:%d. %d SCBs aborted\n", ahc_name(ahc),
+		       message, devinfo->channel, devinfo->target, found);
+}
+
+#ifdef AHC_TARGET_MODE
+static void
+ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		       struct scb *scb)
+{
+
+	/*              
+	 * To facilitate adding multiple messages together,
+	 * each routine should increment the index and len
+	 * variables instead of setting them explicitly.
+	 */             
+	ahc->msgout_index = 0;
+	ahc->msgout_len = 0;
+
+	if (scb != NULL && (scb->flags & SCB_AUTO_NEGOTIATE) != 0)
+		ahc_build_transfer_msg(ahc, devinfo);
+	else
+		panic("ahc_intr: AWAITING target message with no message");
+
+	ahc->msgout_index = 0;
+	ahc->msg_type = MSG_TYPE_TARGET_MSGIN;
+}
+#endif
+/**************************** Initialization **********************************/
+/*
+ * Allocate a controller structure for a new device
+ * and perform initial initializion.
+ */
+struct ahc_softc *
+ahc_alloc(void *platform_arg, char *name)
+{
+	struct  ahc_softc *ahc;
+	int	i;
+
+#ifndef	__FreeBSD__
+	ahc = malloc(sizeof(*ahc), M_DEVBUF, M_NOWAIT);
+	if (!ahc) {
+		printf("aic7xxx: cannot malloc softc!\n");
+		free(name, M_DEVBUF);
+		return NULL;
+	}
+#else
+	ahc = device_get_softc((device_t)platform_arg);
+#endif
+	memset(ahc, 0, sizeof(*ahc));
+	ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+				  M_DEVBUF, M_NOWAIT);
+	if (ahc->seep_config == NULL) {
+#ifndef	__FreeBSD__
+		free(ahc, M_DEVBUF);
+#endif
+		free(name, M_DEVBUF);
+		return (NULL);
+	}
+	LIST_INIT(&ahc->pending_scbs);
+	/* We don't know our unit number until the OSM sets it */
+	ahc->name = name;
+	ahc->unit = -1;
+	ahc->description = NULL;
+	ahc->channel = 'A';
+	ahc->channel_b = 'B';
+	ahc->chip = AHC_NONE;
+	ahc->features = AHC_FENONE;
+	ahc->bugs = AHC_BUGNONE;
+	ahc->flags = AHC_FNONE;
+	/*
+	 * Default to all error reporting enabled with the
+	 * sequencer operating at its fastest speed.
+	 * The bus attach code may modify this.
+	 */
+	ahc->seqctl = FASTMODE;
+
+	for (i = 0; i < AHC_NUM_TARGETS; i++)
+		TAILQ_INIT(&ahc->untagged_queues[i]);
+	if (ahc_platform_alloc(ahc, platform_arg) != 0) {
+		ahc_free(ahc);
+		ahc = NULL;
+	}
+	return (ahc);
+}
+
+int
+ahc_softc_init(struct ahc_softc *ahc)
+{
+
+	/* The IRQMS bit is only valid on VL and EISA chips */
+	if ((ahc->chip & AHC_PCI) == 0)
+		ahc->unpause = ahc_inb(ahc, HCNTRL) & IRQMS;
+	else
+		ahc->unpause = 0;
+	ahc->pause = ahc->unpause | PAUSE; 
+	/* XXX The shared scb data stuff should be deprecated */
+	if (ahc->scb_data == NULL) {
+		ahc->scb_data = malloc(sizeof(*ahc->scb_data),
+				       M_DEVBUF, M_NOWAIT);
+		if (ahc->scb_data == NULL)
+			return (ENOMEM);
+		memset(ahc->scb_data, 0, sizeof(*ahc->scb_data));
+	}
+
+	return (0);
+}
+
+void
+ahc_softc_insert(struct ahc_softc *ahc)
+{
+	struct ahc_softc *list_ahc;
+
+#if AHC_PCI_CONFIG > 0
+	/*
+	 * Second Function PCI devices need to inherit some
+	 * settings from function 0.
+	 */
+	if ((ahc->chip & AHC_BUS_MASK) == AHC_PCI
+	 && (ahc->features & AHC_MULTI_FUNC) != 0) {
+		TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+			ahc_dev_softc_t list_pci;
+			ahc_dev_softc_t pci;
+
+			list_pci = list_ahc->dev_softc;
+			pci = ahc->dev_softc;
+			if (ahc_get_pci_slot(list_pci) == ahc_get_pci_slot(pci)
+			 && ahc_get_pci_bus(list_pci) == ahc_get_pci_bus(pci)) {
+				struct ahc_softc *master;
+				struct ahc_softc *slave;
+
+				if (ahc_get_pci_function(list_pci) == 0) {
+					master = list_ahc;
+					slave = ahc;
+				} else {
+					master = ahc;
+					slave = list_ahc;
+				}
+				slave->flags &= ~AHC_BIOS_ENABLED; 
+				slave->flags |=
+				    master->flags & AHC_BIOS_ENABLED;
+				slave->flags &= ~AHC_PRIMARY_CHANNEL; 
+				slave->flags |=
+				    master->flags & AHC_PRIMARY_CHANNEL;
+				break;
+			}
+		}
+	}
+#endif
+
+	/*
+	 * Insertion sort into our list of softcs.
+	 */
+	list_ahc = TAILQ_FIRST(&ahc_tailq);
+	while (list_ahc != NULL
+	    && ahc_softc_comp(ahc, list_ahc) <= 0)
+		list_ahc = TAILQ_NEXT(list_ahc, links);
+	if (list_ahc != NULL)
+		TAILQ_INSERT_BEFORE(list_ahc, ahc, links);
+	else
+		TAILQ_INSERT_TAIL(&ahc_tailq, ahc, links);
+	ahc->init_level++;
+}
+
+/*
+ * Verify that the passed in softc pointer is for a
+ * controller that is still configured.
+ */
+struct ahc_softc *
+ahc_find_softc(struct ahc_softc *ahc)
+{
+	struct ahc_softc *list_ahc;
+
+	TAILQ_FOREACH(list_ahc, &ahc_tailq, links) {
+		if (list_ahc == ahc)
+			return (ahc);
+	}
+	return (NULL);
+}
+
+void
+ahc_set_unit(struct ahc_softc *ahc, int unit)
+{
+	ahc->unit = unit;
+}
+
+void
+ahc_set_name(struct ahc_softc *ahc, char *name)
+{
+	if (ahc->name != NULL)
+		free(ahc->name, M_DEVBUF);
+	ahc->name = name;
+}
+
+void
+ahc_free(struct ahc_softc *ahc)
+{
+	int i;
+
+	switch (ahc->init_level) {
+	default:
+	case 5:
+		ahc_shutdown(ahc);
+		/* FALLTHROUGH */
+	case 4:
+		ahc_dmamap_unload(ahc, ahc->shared_data_dmat,
+				  ahc->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 3:
+		ahc_dmamem_free(ahc, ahc->shared_data_dmat, ahc->qoutfifo,
+				ahc->shared_data_dmamap);
+		ahc_dmamap_destroy(ahc, ahc->shared_data_dmat,
+				   ahc->shared_data_dmamap);
+		/* FALLTHROUGH */
+	case 2:
+		ahc_dma_tag_destroy(ahc, ahc->shared_data_dmat);
+	case 1:
+#ifndef __linux__
+		ahc_dma_tag_destroy(ahc, ahc->buffer_dmat);
+#endif
+		break;
+	case 0:
+		break;
+	}
+
+#ifndef __linux__
+	ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
+#endif
+	ahc_platform_free(ahc);
+	ahc_fini_scbdata(ahc);
+	for (i = 0; i < AHC_NUM_TARGETS; i++) {
+		struct ahc_tmode_tstate *tstate;
+
+		tstate = ahc->enabled_targets[i];
+		if (tstate != NULL) {
+#ifdef AHC_TARGET_MODE
+			int j;
+
+			for (j = 0; j < AHC_NUM_LUNS; j++) {
+				struct ahc_tmode_lstate *lstate;
+
+				lstate = tstate->enabled_luns[j];
+				if (lstate != NULL) {
+					xpt_free_path(lstate->path);
+					free(lstate, M_DEVBUF);
+				}
+			}
+#endif
+			free(tstate, M_DEVBUF);
+		}
+	}
+#ifdef AHC_TARGET_MODE
+	if (ahc->black_hole != NULL) {
+		xpt_free_path(ahc->black_hole->path);
+		free(ahc->black_hole, M_DEVBUF);
+	}
+#endif
+	if (ahc->name != NULL)
+		free(ahc->name, M_DEVBUF);
+	if (ahc->seep_config != NULL)
+		free(ahc->seep_config, M_DEVBUF);
+#ifndef __FreeBSD__
+	free(ahc, M_DEVBUF);
+#endif
+	return;
+}
+
+void
+ahc_shutdown(void *arg)
+{
+	struct	ahc_softc *ahc;
+	int	i;
+
+	ahc = (struct ahc_softc *)arg;
+
+	/* This will reset most registers to 0, but not all */
+	ahc_reset(ahc, /*reinit*/FALSE);
+	ahc_outb(ahc, SCSISEQ, 0);
+	ahc_outb(ahc, SXFRCTL0, 0);
+	ahc_outb(ahc, DSPCISTATUS, 0);
+
+	for (i = TARG_SCSIRATE; i < SCSICONF; i++)
+		ahc_outb(ahc, i, 0);
+}
+
+/*
+ * Reset the controller and record some information about it
+ * that is only available just after a reset.  If "reinit" is
+ * non-zero, this reset occured after initial configuration
+ * and the caller requests that the chip be fully reinitialized
+ * to a runable state.  Chip interrupts are *not* enabled after
+ * a reinitialization.  The caller must enable interrupts via
+ * ahc_intr_enable().
+ */
+int
+ahc_reset(struct ahc_softc *ahc, int reinit)
+{
+	u_int	sblkctl;
+	u_int	sxfrctl1_a, sxfrctl1_b;
+	int	error;
+	int	wait;
+	
+	/*
+	 * Preserve the value of the SXFRCTL1 register for all channels.
+	 * It contains settings that affect termination and we don't want
+	 * to disturb the integrity of the bus.
+	 */
+	ahc_pause(ahc);
+	if ((ahc_inb(ahc, HCNTRL) & CHIPRST) != 0) {
+		/*
+		 * The chip has not been initialized since
+		 * PCI/EISA/VLB bus reset.  Don't trust
+		 * "left over BIOS data".
+		 */
+		ahc->flags |= AHC_NO_BIOS_INIT;
+	}
+	sxfrctl1_b = 0;
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7770) {
+		u_int sblkctl;
+
+		/*
+		 * Save channel B's settings in case this chip
+		 * is setup for TWIN channel operation.
+		 */
+		sblkctl = ahc_inb(ahc, SBLKCTL);
+		ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+		sxfrctl1_b = ahc_inb(ahc, SXFRCTL1);
+		ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+	}
+	sxfrctl1_a = ahc_inb(ahc, SXFRCTL1);
+
+	ahc_outb(ahc, HCNTRL, CHIPRST | ahc->pause);
+
+	/*
+	 * Ensure that the reset has finished.  We delay 1000us
+	 * prior to reading the register to make sure the chip
+	 * has sufficiently completed its reset to handle register
+	 * accesses.
+	 */
+	wait = 1000;
+	do {
+		ahc_delay(1000);
+	} while (--wait && !(ahc_inb(ahc, HCNTRL) & CHIPRSTACK));
+
+	if (wait == 0) {
+		printf("%s: WARNING - Failed chip reset!  "
+		       "Trying to initialize anyway.\n", ahc_name(ahc));
+	}
+	ahc_outb(ahc, HCNTRL, ahc->pause);
+
+	/* Determine channel configuration */
+	sblkctl = ahc_inb(ahc, SBLKCTL) & (SELBUSB|SELWIDE);
+	/* No Twin Channel PCI cards */
+	if ((ahc->chip & AHC_PCI) != 0)
+		sblkctl &= ~SELBUSB;
+	switch (sblkctl) {
+	case 0:
+		/* Single Narrow Channel */
+		break;
+	case 2:
+		/* Wide Channel */
+		ahc->features |= AHC_WIDE;
+		break;
+	case 8:
+		/* Twin Channel */
+		ahc->features |= AHC_TWIN;
+		break;
+	default:
+		printf(" Unsupported adapter type.  Ignoring\n");
+		return(-1);
+	}
+
+	/*
+	 * Reload sxfrctl1.
+	 *
+	 * We must always initialize STPWEN to 1 before we
+	 * restore the saved values.  STPWEN is initialized
+	 * to a tri-state condition which can only be cleared
+	 * by turning it on.
+	 */
+	if ((ahc->features & AHC_TWIN) != 0) {
+		u_int sblkctl;
+
+		sblkctl = ahc_inb(ahc, SBLKCTL);
+		ahc_outb(ahc, SBLKCTL, sblkctl | SELBUSB);
+		ahc_outb(ahc, SXFRCTL1, sxfrctl1_b);
+		ahc_outb(ahc, SBLKCTL, sblkctl & ~SELBUSB);
+	}
+	ahc_outb(ahc, SXFRCTL1, sxfrctl1_a);
+
+	error = 0;
+	if (reinit != 0)
+		/*
+		 * If a recovery action has forced a chip reset,
+		 * re-initialize the chip to our liking.
+		 */
+		error = ahc->bus_chip_init(ahc);
+#ifdef AHC_DUMP_SEQ
+	else 
+		ahc_dumpseq(ahc);
+#endif
+
+	return (error);
+}
+
+/*
+ * Determine the number of SCBs available on the controller
+ */
+int
+ahc_probe_scbs(struct ahc_softc *ahc) {
+	int i;
+
+	for (i = 0; i < AHC_SCB_MAX; i++) {
+
+		ahc_outb(ahc, SCBPTR, i);
+		ahc_outb(ahc, SCB_BASE, i);
+		if (ahc_inb(ahc, SCB_BASE) != i)
+			break;
+		ahc_outb(ahc, SCBPTR, 0);
+		if (ahc_inb(ahc, SCB_BASE) != 0)
+			break;
+	}
+	return (i);
+}
+
+static void
+ahc_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) 
+{
+	dma_addr_t *baddr;
+
+	baddr = (dma_addr_t *)arg;
+	*baddr = segs->ds_addr;
+}
+
+static void
+ahc_build_free_scb_list(struct ahc_softc *ahc)
+{
+	int scbsize;
+	int i;
+
+	scbsize = 32;
+	if ((ahc->flags & AHC_LSCBS_ENABLED) != 0)
+		scbsize = 64;
+
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		int j;
+
+		ahc_outb(ahc, SCBPTR, i);
+
+		/*
+		 * Touch all SCB bytes to avoid parity errors
+		 * should one of our debugging routines read
+		 * an otherwise uninitiatlized byte.
+		 */
+		for (j = 0; j < scbsize; j++)
+			ahc_outb(ahc, SCB_BASE+j, 0xFF);
+
+		/* Clear the control byte. */
+		ahc_outb(ahc, SCB_CONTROL, 0);
+
+		/* Set the next pointer */
+		if ((ahc->flags & AHC_PAGESCBS) != 0)
+			ahc_outb(ahc, SCB_NEXT, i+1);
+		else 
+			ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
+
+		/* Make the tag number, SCSIID, and lun invalid */
+		ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+		ahc_outb(ahc, SCB_SCSIID, 0xFF);
+		ahc_outb(ahc, SCB_LUN, 0xFF);
+	}
+
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		/* SCB 0 heads the free list. */
+		ahc_outb(ahc, FREE_SCBH, 0);
+	} else {
+		/* No free list. */
+		ahc_outb(ahc, FREE_SCBH, SCB_LIST_NULL);
+	}
+
+	/* Make sure that the last SCB terminates the free list */
+	ahc_outb(ahc, SCBPTR, i-1);
+	ahc_outb(ahc, SCB_NEXT, SCB_LIST_NULL);
+}
+
+static int
+ahc_init_scbdata(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+
+	scb_data = ahc->scb_data;
+	SLIST_INIT(&scb_data->free_scbs);
+	SLIST_INIT(&scb_data->sg_maps);
+
+	/* Allocate SCB resources */
+	scb_data->scbarray =
+	    (struct scb *)malloc(sizeof(struct scb) * AHC_SCB_MAX_ALLOC,
+				 M_DEVBUF, M_NOWAIT);
+	if (scb_data->scbarray == NULL)
+		return (ENOMEM);
+	memset(scb_data->scbarray, 0, sizeof(struct scb) * AHC_SCB_MAX_ALLOC);
+
+	/* Determine the number of hardware SCBs and initialize them */
+
+	scb_data->maxhscbs = ahc_probe_scbs(ahc);
+	if (ahc->scb_data->maxhscbs == 0) {
+		printf("%s: No SCB space found\n", ahc_name(ahc));
+		return (ENXIO);
+	}
+
+	/*
+	 * Create our DMA tags.  These tags define the kinds of device
+	 * accessible memory allocations and memory mappings we will
+	 * need to perform during normal operation.
+	 *
+	 * Unless we need to further restrict the allocation, we rely
+	 * on the restrictions of the parent dmat, hence the common
+	 * use of MAXADDR and MAXSIZE.
+	 */
+
+	/* DMA tag for our hardware scb structures */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb),
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->hscb_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Allocation for our hscbs */
+	if (ahc_dmamem_alloc(ahc, scb_data->hscb_dmat,
+			     (void **)&scb_data->hscbs,
+			     BUS_DMA_NOWAIT, &scb_data->hscb_dmamap) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* And permanently map them */
+	ahc_dmamap_load(ahc, scb_data->hscb_dmat, scb_data->hscb_dmamap,
+			scb_data->hscbs,
+			AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb),
+			ahc_dmamap_cb, &scb_data->hscb_busaddr, /*flags*/0);
+
+	scb_data->init_level++;
+
+	/* DMA tag for our sense buffers */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data),
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sense_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Allocate them */
+	if (ahc_dmamem_alloc(ahc, scb_data->sense_dmat,
+			     (void **)&scb_data->sense,
+			     BUS_DMA_NOWAIT, &scb_data->sense_dmamap) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* And permanently map them */
+	ahc_dmamap_load(ahc, scb_data->sense_dmat, scb_data->sense_dmamap,
+			scb_data->sense,
+			AHC_SCB_MAX_ALLOC * sizeof(struct scsi_sense_data),
+			ahc_dmamap_cb, &scb_data->sense_busaddr, /*flags*/0);
+
+	scb_data->init_level++;
+
+	/* DMA tag for our S/G structures.  We allocate in page sized chunks */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/8,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       PAGE_SIZE, /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &scb_data->sg_dmat) != 0) {
+		goto error_exit;
+	}
+
+	scb_data->init_level++;
+
+	/* Perform initial CCB allocation */
+	memset(scb_data->hscbs, 0,
+	       AHC_SCB_MAX_ALLOC * sizeof(struct hardware_scb));
+	ahc_alloc_scbs(ahc);
+
+	if (scb_data->numscbs == 0) {
+		printf("%s: ahc_init_scbdata - "
+		       "Unable to allocate initial scbs\n",
+		       ahc_name(ahc));
+		goto error_exit;
+	}
+
+	/*
+	 * Reserve the next queued SCB.
+	 */
+	ahc->next_queued_scb = ahc_get_scb(ahc);
+
+	/*
+	 * Note that we were successfull
+	 */
+	return (0); 
+
+error_exit:
+
+	return (ENOMEM);
+}
+
+static void
+ahc_fini_scbdata(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+
+	scb_data = ahc->scb_data;
+	if (scb_data == NULL)
+		return;
+
+	switch (scb_data->init_level) {
+	default:
+	case 7:
+	{
+		struct sg_map_node *sg_map;
+
+		while ((sg_map = SLIST_FIRST(&scb_data->sg_maps))!= NULL) {
+			SLIST_REMOVE_HEAD(&scb_data->sg_maps, links);
+			ahc_dmamap_unload(ahc, scb_data->sg_dmat,
+					  sg_map->sg_dmamap);
+			ahc_dmamem_free(ahc, scb_data->sg_dmat,
+					sg_map->sg_vaddr,
+					sg_map->sg_dmamap);
+			free(sg_map, M_DEVBUF);
+		}
+		ahc_dma_tag_destroy(ahc, scb_data->sg_dmat);
+	}
+	case 6:
+		ahc_dmamap_unload(ahc, scb_data->sense_dmat,
+				  scb_data->sense_dmamap);
+	case 5:
+		ahc_dmamem_free(ahc, scb_data->sense_dmat, scb_data->sense,
+				scb_data->sense_dmamap);
+		ahc_dmamap_destroy(ahc, scb_data->sense_dmat,
+				   scb_data->sense_dmamap);
+	case 4:
+		ahc_dma_tag_destroy(ahc, scb_data->sense_dmat);
+	case 3:
+		ahc_dmamap_unload(ahc, scb_data->hscb_dmat,
+				  scb_data->hscb_dmamap);
+	case 2:
+		ahc_dmamem_free(ahc, scb_data->hscb_dmat, scb_data->hscbs,
+				scb_data->hscb_dmamap);
+		ahc_dmamap_destroy(ahc, scb_data->hscb_dmat,
+				   scb_data->hscb_dmamap);
+	case 1:
+		ahc_dma_tag_destroy(ahc, scb_data->hscb_dmat);
+		break;
+	case 0:
+		break;
+	}
+	if (scb_data->scbarray != NULL)
+		free(scb_data->scbarray, M_DEVBUF);
+}
+
+void
+ahc_alloc_scbs(struct ahc_softc *ahc)
+{
+	struct scb_data *scb_data;
+	struct scb *next_scb;
+	struct sg_map_node *sg_map;
+	dma_addr_t physaddr;
+	struct ahc_dma_seg *segs;
+	int newcount;
+	int i;
+
+	scb_data = ahc->scb_data;
+	if (scb_data->numscbs >= AHC_SCB_MAX_ALLOC)
+		/* Can't allocate any more */
+		return;
+
+	next_scb = &scb_data->scbarray[scb_data->numscbs];
+
+	sg_map = malloc(sizeof(*sg_map), M_DEVBUF, M_NOWAIT);
+
+	if (sg_map == NULL)
+		return;
+
+	/* Allocate S/G space for the next batch of SCBS */
+	if (ahc_dmamem_alloc(ahc, scb_data->sg_dmat,
+			     (void **)&sg_map->sg_vaddr,
+			     BUS_DMA_NOWAIT, &sg_map->sg_dmamap) != 0) {
+		free(sg_map, M_DEVBUF);
+		return;
+	}
+
+	SLIST_INSERT_HEAD(&scb_data->sg_maps, sg_map, links);
+
+	ahc_dmamap_load(ahc, scb_data->sg_dmat, sg_map->sg_dmamap,
+			sg_map->sg_vaddr, PAGE_SIZE, ahc_dmamap_cb,
+			&sg_map->sg_physaddr, /*flags*/0);
+
+	segs = sg_map->sg_vaddr;
+	physaddr = sg_map->sg_physaddr;
+
+	newcount = (PAGE_SIZE / (AHC_NSEG * sizeof(struct ahc_dma_seg)));
+	newcount = MIN(newcount, (AHC_SCB_MAX_ALLOC - scb_data->numscbs));
+	for (i = 0; i < newcount; i++) {
+		struct scb_platform_data *pdata;
+#ifndef __linux__
+		int error;
+#endif
+		pdata = (struct scb_platform_data *)malloc(sizeof(*pdata),
+							   M_DEVBUF, M_NOWAIT);
+		if (pdata == NULL)
+			break;
+		next_scb->platform_data = pdata;
+		next_scb->sg_map = sg_map;
+		next_scb->sg_list = segs;
+		/*
+		 * The sequencer always starts with the second entry.
+		 * The first entry is embedded in the scb.
+		 */
+		next_scb->sg_list_phys = physaddr + sizeof(struct ahc_dma_seg);
+		next_scb->ahc_softc = ahc;
+		next_scb->flags = SCB_FREE;
+#ifndef __linux__
+		error = ahc_dmamap_create(ahc, ahc->buffer_dmat, /*flags*/0,
+					  &next_scb->dmamap);
+		if (error != 0)
+			break;
+#endif
+		next_scb->hscb = &scb_data->hscbs[scb_data->numscbs];
+		next_scb->hscb->tag = ahc->scb_data->numscbs;
+		SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs,
+				  next_scb, links.sle);
+		segs += AHC_NSEG;
+		physaddr += (AHC_NSEG * sizeof(struct ahc_dma_seg));
+		next_scb++;
+		ahc->scb_data->numscbs++;
+	}
+}
+
+void
+ahc_controller_info(struct ahc_softc *ahc, char *buf)
+{
+	int len;
+
+	len = sprintf(buf, "%s: ", ahc_chip_names[ahc->chip & AHC_CHIPID_MASK]);
+	buf += len;
+	if ((ahc->features & AHC_TWIN) != 0)
+ 		len = sprintf(buf, "Twin Channel, A SCSI Id=%d, "
+			      "B SCSI Id=%d, primary %c, ",
+			      ahc->our_id, ahc->our_id_b,
+			      (ahc->flags & AHC_PRIMARY_CHANNEL) + 'A');
+	else {
+		const char *speed;
+		const char *type;
+
+		speed = "";
+		if ((ahc->features & AHC_ULTRA) != 0) {
+			speed = "Ultra ";
+		} else if ((ahc->features & AHC_DT) != 0) {
+			speed = "Ultra160 ";
+		} else if ((ahc->features & AHC_ULTRA2) != 0) {
+			speed = "Ultra2 ";
+		}
+		if ((ahc->features & AHC_WIDE) != 0) {
+			type = "Wide";
+		} else {
+			type = "Single";
+		}
+		len = sprintf(buf, "%s%s Channel %c, SCSI Id=%d, ",
+			      speed, type, ahc->channel, ahc->our_id);
+	}
+	buf += len;
+
+	if ((ahc->flags & AHC_PAGESCBS) != 0)
+		sprintf(buf, "%d/%d SCBs",
+			ahc->scb_data->maxhscbs, AHC_MAX_QUEUE);
+	else
+		sprintf(buf, "%d SCBs", ahc->scb_data->maxhscbs);
+}
+
+int
+ahc_chip_init(struct ahc_softc *ahc)
+{
+	int	 term;
+	int	 error;
+	u_int	 i;
+	u_int	 scsi_conf;
+	u_int	 scsiseq_template;
+	uint32_t physaddr;
+
+	ahc_outb(ahc, SEQ_FLAGS, 0);
+	ahc_outb(ahc, SEQ_FLAGS2, 0);
+
+	/* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels*/
+	if (ahc->features & AHC_TWIN) {
+
+		/*
+		 * Setup Channel B first.
+		 */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) | SELBUSB);
+		term = (ahc->flags & AHC_TERM_ENB_B) != 0 ? STPWEN : 0;
+		ahc_outb(ahc, SCSIID, ahc->our_id_b);
+		scsi_conf = ahc_inb(ahc, SCSICONF + 1);
+		ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+					|term|ahc->seltime_b|ENSTIMER|ACTNEGEN);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+		ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+		ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+		/* Select Channel A */
+		ahc_outb(ahc, SBLKCTL, ahc_inb(ahc, SBLKCTL) & ~SELBUSB);
+	}
+	term = (ahc->flags & AHC_TERM_ENB_A) != 0 ? STPWEN : 0;
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, ahc->our_id);
+	else
+		ahc_outb(ahc, SCSIID, ahc->our_id);
+	scsi_conf = ahc_inb(ahc, SCSICONF);
+	ahc_outb(ahc, SXFRCTL1, (scsi_conf & (ENSPCHK|STIMESEL))
+				|term|ahc->seltime
+				|ENSTIMER|ACTNEGEN);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SIMODE0, ahc_inb(ahc, SIMODE0)|ENIOERR);
+	ahc_outb(ahc, SIMODE1, ENSELTIMO|ENSCSIRST|ENSCSIPERR);
+	ahc_outb(ahc, SXFRCTL0, DFON|SPIOEN);
+
+	/* There are no untagged SCBs active yet. */
+	for (i = 0; i < 16; i++) {
+		ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, 0));
+		if ((ahc->flags & AHC_SCB_BTT) != 0) {
+			int lun;
+
+			/*
+			 * The SCB based BTT allows an entry per
+			 * target and lun pair.
+			 */
+			for (lun = 1; lun < AHC_NUM_LUNS; lun++)
+				ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, lun));
+		}
+	}
+
+	/* All of our queues are empty */
+	for (i = 0; i < 256; i++)
+		ahc->qoutfifo[i] = SCB_LIST_NULL;
+	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_PREREAD);
+
+	for (i = 0; i < 256; i++)
+		ahc->qinfifo[i] = SCB_LIST_NULL;
+
+	if ((ahc->features & AHC_MULTI_TID) != 0) {
+		ahc_outb(ahc, TARGID, 0);
+		ahc_outb(ahc, TARGID + 1, 0);
+	}
+
+	/*
+	 * Tell the sequencer where it can find our arrays in memory.
+	 */
+	physaddr = ahc->scb_data->hscb_busaddr;
+	ahc_outb(ahc, HSCB_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, HSCB_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	physaddr = ahc->shared_data_busaddr;
+	ahc_outb(ahc, SHARED_DATA_ADDR, physaddr & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 1, (physaddr >> 8) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 2, (physaddr >> 16) & 0xFF);
+	ahc_outb(ahc, SHARED_DATA_ADDR + 3, (physaddr >> 24) & 0xFF);
+
+	/*
+	 * Initialize the group code to command length table.
+	 * This overrides the values in TARG_SCSIRATE, so only
+	 * setup the table after we have processed that information.
+	 */
+	ahc_outb(ahc, CMDSIZE_TABLE, 5);
+	ahc_outb(ahc, CMDSIZE_TABLE + 1, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 2, 9);
+	ahc_outb(ahc, CMDSIZE_TABLE + 3, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 4, 15);
+	ahc_outb(ahc, CMDSIZE_TABLE + 5, 11);
+	ahc_outb(ahc, CMDSIZE_TABLE + 6, 0);
+	ahc_outb(ahc, CMDSIZE_TABLE + 7, 0);
+		
+	if ((ahc->features & AHC_HS_MAILBOX) != 0)
+		ahc_outb(ahc, HS_MAILBOX, 0);
+
+	/* Tell the sequencer of our initial queue positions */
+	if ((ahc->features & AHC_TARGETMODE) != 0) {
+		ahc->tqinfifonext = 1;
+		ahc_outb(ahc, KERNEL_TQINPOS, ahc->tqinfifonext - 1);
+		ahc_outb(ahc, TQINPOS, ahc->tqinfifonext);
+	}
+	ahc->qinfifonext = 0;
+	ahc->qoutfifonext = 0;
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, QOFF_CTLSTA, SCB_QSIZE_256);
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+		ahc_outb(ahc, SNSCB_QOFF, ahc->qinfifonext);
+		ahc_outb(ahc, SDSCB_QOFF, 0);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+		ahc_outb(ahc, QINPOS, ahc->qinfifonext);
+		ahc_outb(ahc, QOUTPOS, ahc->qoutfifonext);
+	}
+
+	/* We don't have any waiting selections */
+	ahc_outb(ahc, WAITING_SCBH, SCB_LIST_NULL);
+
+	/* Our disconnection list is empty too */
+	ahc_outb(ahc, DISCONNECTED_SCBH, SCB_LIST_NULL);
+
+	/* Message out buffer starts empty */
+	ahc_outb(ahc, MSG_OUT, MSG_NOOP);
+
+	/*
+	 * Setup the allowed SCSI Sequences based on operational mode.
+	 * If we are a target, we'll enalbe select in operations once
+	 * we've had a lun enabled.
+	 */
+	scsiseq_template = ENSELO|ENAUTOATNO|ENAUTOATNP;
+	if ((ahc->flags & AHC_INITIATORROLE) != 0)
+		scsiseq_template |= ENRSELI;
+	ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq_template);
+
+	/* Initialize our list of free SCBs. */
+	ahc_build_free_scb_list(ahc);
+
+	/*
+	 * Tell the sequencer which SCB will be the next one it receives.
+	 */
+	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+	/*
+	 * Load the Sequencer program and Enable the adapter
+	 * in "fast" mode.
+	 */
+	if (bootverbose)
+		printf("%s: Downloading Sequencer Program...",
+		       ahc_name(ahc));
+
+	error = ahc_loadseq(ahc);
+	if (error != 0)
+		return (error);
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		int wait;
+
+		/*
+		 * Wait for up to 500ms for our transceivers
+		 * to settle.  If the adapter does not have
+		 * a cable attached, the transceivers may
+		 * never settle, so don't complain if we
+		 * fail here.
+		 */
+		for (wait = 5000;
+		     (ahc_inb(ahc, SBLKCTL) & (ENAB40|ENAB20)) == 0 && wait;
+		     wait--)
+			ahc_delay(100);
+	}
+	ahc_restart(ahc);
+	return (0);
+}
+
+/*
+ * Start the board, ready for normal operation
+ */
+int
+ahc_init(struct ahc_softc *ahc)
+{
+	int	 max_targ;
+	u_int	 i;
+	u_int	 scsi_conf;
+	u_int	 ultraenb;
+	u_int	 discenable;
+	u_int	 tagenable;
+	size_t	 driver_data_size;
+
+#ifdef AHC_DEBUG
+	if ((ahc_debug & AHC_DEBUG_SEQUENCER) != 0)
+		ahc->flags |= AHC_SEQUENCER_DEBUG;
+#endif
+
+#ifdef AHC_PRINT_SRAM
+	printf("Scratch Ram:");
+	for (i = 0x20; i < 0x5f; i++) {
+		if (((i % 8) == 0) && (i != 0)) {
+			printf ("\n              ");
+		}
+		printf (" 0x%x", ahc_inb(ahc, i));
+	}
+	if ((ahc->features & AHC_MORE_SRAM) != 0) {
+		for (i = 0x70; i < 0x7f; i++) {
+			if (((i % 8) == 0) && (i != 0)) {
+				printf ("\n              ");
+			}
+			printf (" 0x%x", ahc_inb(ahc, i));
+		}
+	}
+	printf ("\n");
+	/*
+	 * Reading uninitialized scratch ram may
+	 * generate parity errors.
+	 */
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+#endif
+	max_targ = 15;
+
+	/*
+	 * Assume we have a board at this stage and it has been reset.
+	 */
+	if ((ahc->flags & AHC_USEDEFAULTS) != 0)
+		ahc->our_id = ahc->our_id_b = 7;
+	
+	/*
+	 * Default to allowing initiator operations.
+	 */
+	ahc->flags |= AHC_INITIATORROLE;
+
+	/*
+	 * Only allow target mode features if this unit has them enabled.
+	 */
+	if ((AHC_TMODE_ENABLE & (0x1 << ahc->unit)) == 0)
+		ahc->features &= ~AHC_TARGETMODE;
+
+#ifndef __linux__
+	/* DMA tag for mapping buffers into device visible space. */
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/ahc->flags & AHC_39BIT_ADDRESSING
+					? (dma_addr_t)0x7FFFFFFFFFULL
+					: BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       /*maxsize*/(AHC_NSEG - 1) * PAGE_SIZE,
+			       /*nsegments*/AHC_NSEG,
+			       /*maxsegsz*/AHC_MAXTRANSFER_SIZE,
+			       /*flags*/BUS_DMA_ALLOCNOW,
+			       &ahc->buffer_dmat) != 0) {
+		return (ENOMEM);
+	}
+#endif
+
+	ahc->init_level++;
+
+	/*
+	 * DMA tag for our command fifos and other data in system memory
+	 * the card's sequencer must be able to access.  For initiator
+	 * roles, we need to allocate space for the qinfifo and qoutfifo.
+	 * The qinfifo and qoutfifo are composed of 256 1 byte elements. 
+	 * When providing for the target mode role, we must additionally
+	 * provide space for the incoming target command fifo and an extra
+	 * byte to deal with a dma bug in some chip versions.
+	 */
+	driver_data_size = 2 * 256 * sizeof(uint8_t);
+	if ((ahc->features & AHC_TARGETMODE) != 0)
+		driver_data_size += AHC_TMODE_CMDS * sizeof(struct target_cmd)
+				 + /*DMA WideOdd Bug Buffer*/1;
+	if (ahc_dma_tag_create(ahc, ahc->parent_dmat, /*alignment*/1,
+			       /*boundary*/BUS_SPACE_MAXADDR_32BIT + 1,
+			       /*lowaddr*/BUS_SPACE_MAXADDR_32BIT,
+			       /*highaddr*/BUS_SPACE_MAXADDR,
+			       /*filter*/NULL, /*filterarg*/NULL,
+			       driver_data_size,
+			       /*nsegments*/1,
+			       /*maxsegsz*/BUS_SPACE_MAXSIZE_32BIT,
+			       /*flags*/0, &ahc->shared_data_dmat) != 0) {
+		return (ENOMEM);
+	}
+
+	ahc->init_level++;
+
+	/* Allocation of driver data */
+	if (ahc_dmamem_alloc(ahc, ahc->shared_data_dmat,
+			     (void **)&ahc->qoutfifo,
+			     BUS_DMA_NOWAIT, &ahc->shared_data_dmamap) != 0) {
+		return (ENOMEM);
+	}
+
+	ahc->init_level++;
+
+	/* And permanently map it in */
+	ahc_dmamap_load(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+			ahc->qoutfifo, driver_data_size, ahc_dmamap_cb,
+			&ahc->shared_data_busaddr, /*flags*/0);
+
+	if ((ahc->features & AHC_TARGETMODE) != 0) {
+		ahc->targetcmds = (struct target_cmd *)ahc->qoutfifo;
+		ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[AHC_TMODE_CMDS];
+		ahc->dma_bug_buf = ahc->shared_data_busaddr
+				 + driver_data_size - 1;
+		/* All target command blocks start out invalid. */
+		for (i = 0; i < AHC_TMODE_CMDS; i++)
+			ahc->targetcmds[i].cmd_valid = 0;
+		ahc_sync_tqinfifo(ahc, BUS_DMASYNC_PREREAD);
+		ahc->qoutfifo = (uint8_t *)&ahc->targetcmds[256];
+	}
+	ahc->qinfifo = &ahc->qoutfifo[256];
+
+	ahc->init_level++;
+
+	/* Allocate SCB data now that buffer_dmat is initialized */
+	if (ahc->scb_data->maxhscbs == 0)
+		if (ahc_init_scbdata(ahc) != 0)
+			return (ENOMEM);
+
+	/*
+	 * Allocate a tstate to house information for our
+	 * initiator presence on the bus as well as the user
+	 * data for any target mode initiator.
+	 */
+	if (ahc_alloc_tstate(ahc, ahc->our_id, 'A') == NULL) {
+		printf("%s: unable to allocate ahc_tmode_tstate.  "
+		       "Failing attach\n", ahc_name(ahc));
+		return (ENOMEM);
+	}
+
+	if ((ahc->features & AHC_TWIN) != 0) {
+		if (ahc_alloc_tstate(ahc, ahc->our_id_b, 'B') == NULL) {
+			printf("%s: unable to allocate ahc_tmode_tstate.  "
+			       "Failing attach\n", ahc_name(ahc));
+			return (ENOMEM);
+		}
+	}
+
+	if (ahc->scb_data->maxhscbs < AHC_SCB_MAX_ALLOC) {
+		ahc->flags |= AHC_PAGESCBS;
+	} else {
+		ahc->flags &= ~AHC_PAGESCBS;
+	}
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_MISC) {
+		printf("%s: hardware scb %u bytes; kernel scb %u bytes; "
+		       "ahc_dma %u bytes\n",
+			ahc_name(ahc),
+			(u_int)sizeof(struct hardware_scb),
+			(u_int)sizeof(struct scb),
+			(u_int)sizeof(struct ahc_dma_seg));
+	}
+#endif /* AHC_DEBUG */
+
+	/*
+	 * Look at the information that board initialization or
+	 * the board bios has left us.
+	 */
+	if (ahc->features & AHC_TWIN) {
+		scsi_conf = ahc_inb(ahc, SCSICONF + 1);
+		if ((scsi_conf & RESET_SCSI) != 0
+		 && (ahc->flags & AHC_INITIATORROLE) != 0)
+			ahc->flags |= AHC_RESET_BUS_B;
+	}
+
+	scsi_conf = ahc_inb(ahc, SCSICONF);
+	if ((scsi_conf & RESET_SCSI) != 0
+	 && (ahc->flags & AHC_INITIATORROLE) != 0)
+		ahc->flags |= AHC_RESET_BUS_A;
+
+	ultraenb = 0;	
+	tagenable = ALL_TARGETS_MASK;
+
+	/* Grab the disconnection disable table and invert it for our needs */
+	if ((ahc->flags & AHC_USEDEFAULTS) != 0) {
+		printf("%s: Host Adapter Bios disabled.  Using default SCSI "
+			"device parameters\n", ahc_name(ahc));
+		ahc->flags |= AHC_EXTENDED_TRANS_A|AHC_EXTENDED_TRANS_B|
+			      AHC_TERM_ENB_A|AHC_TERM_ENB_B;
+		discenable = ALL_TARGETS_MASK;
+		if ((ahc->features & AHC_ULTRA) != 0)
+			ultraenb = ALL_TARGETS_MASK;
+	} else {
+		discenable = ~((ahc_inb(ahc, DISC_DSB + 1) << 8)
+			   | ahc_inb(ahc, DISC_DSB));
+		if ((ahc->features & (AHC_ULTRA|AHC_ULTRA2)) != 0)
+			ultraenb = (ahc_inb(ahc, ULTRA_ENB + 1) << 8)
+				      | ahc_inb(ahc, ULTRA_ENB);
+	}
+
+	if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
+		max_targ = 7;
+
+	for (i = 0; i <= max_targ; i++) {
+		struct ahc_initiator_tinfo *tinfo;
+		struct ahc_tmode_tstate *tstate;
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+					    target_id, &tstate);
+		/* Default to async narrow across the board */
+		memset(tinfo, 0, sizeof(*tinfo));
+		if (ahc->flags & AHC_USEDEFAULTS) {
+			if ((ahc->features & AHC_WIDE) != 0)
+				tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+
+			/*
+			 * These will be truncated when we determine the
+			 * connection type we have with the target.
+			 */
+			tinfo->user.period = ahc_syncrates->period;
+			tinfo->user.offset = MAX_OFFSET;
+		} else {
+			u_int scsirate;
+			uint16_t mask;
+
+			/* Take the settings leftover in scratch RAM. */
+			scsirate = ahc_inb(ahc, TARG_SCSIRATE + i);
+			mask = (0x01 << i);
+			if ((ahc->features & AHC_ULTRA2) != 0) {
+				u_int offset;
+				u_int maxsync;
+
+				if ((scsirate & SOFS) == 0x0F) {
+					/*
+					 * Haven't negotiated yet,
+					 * so the format is different.
+					 */
+					scsirate = (scsirate & SXFR) >> 4
+						 | (ultraenb & mask)
+						  ? 0x08 : 0x0
+						 | (scsirate & WIDEXFER);
+					offset = MAX_OFFSET_ULTRA2;
+				} else
+					offset = ahc_inb(ahc, TARG_OFFSET + i);
+				if ((scsirate & ~WIDEXFER) == 0 && offset != 0)
+					/* Set to the lowest sync rate, 5MHz */
+					scsirate |= 0x1c;
+				maxsync = AHC_SYNCRATE_ULTRA2;
+				if ((ahc->features & AHC_DT) != 0)
+					maxsync = AHC_SYNCRATE_DT;
+				tinfo->user.period =
+				    ahc_find_period(ahc, scsirate, maxsync);
+				if (offset == 0)
+					tinfo->user.period = 0;
+				else
+					tinfo->user.offset = MAX_OFFSET;
+				if ((scsirate & SXFR_ULTRA2) <= 8/*10MHz*/
+				 && (ahc->features & AHC_DT) != 0)
+					tinfo->user.ppr_options =
+					    MSG_EXT_PPR_DT_REQ;
+			} else if ((scsirate & SOFS) != 0) {
+				if ((scsirate & SXFR) == 0x40
+				 && (ultraenb & mask) != 0) {
+					/* Treat 10MHz as a non-ultra speed */
+					scsirate &= ~SXFR;
+				 	ultraenb &= ~mask;
+				}
+				tinfo->user.period = 
+				    ahc_find_period(ahc, scsirate,
+						    (ultraenb & mask)
+						   ? AHC_SYNCRATE_ULTRA
+						   : AHC_SYNCRATE_FAST);
+				if (tinfo->user.period != 0)
+					tinfo->user.offset = MAX_OFFSET;
+			}
+			if (tinfo->user.period == 0)
+				tinfo->user.offset = 0;
+			if ((scsirate & WIDEXFER) != 0
+			 && (ahc->features & AHC_WIDE) != 0)
+				tinfo->user.width = MSG_EXT_WDTR_BUS_16_BIT;
+			tinfo->user.protocol_version = 4;
+			if ((ahc->features & AHC_DT) != 0)
+				tinfo->user.transport_version = 3;
+			else
+				tinfo->user.transport_version = 2;
+			tinfo->goal.protocol_version = 2;
+			tinfo->goal.transport_version = 2;
+			tinfo->curr.protocol_version = 2;
+			tinfo->curr.transport_version = 2;
+		}
+		tstate->ultraenb = 0;
+	}
+	ahc->user_discenable = discenable;
+	ahc->user_tagenable = tagenable;
+
+	return (ahc->bus_chip_init(ahc));
+}
+
+void
+ahc_intr_enable(struct ahc_softc *ahc, int enable)
+{
+	u_int hcntrl;
+
+	hcntrl = ahc_inb(ahc, HCNTRL);
+	hcntrl &= ~INTEN;
+	ahc->pause &= ~INTEN;
+	ahc->unpause &= ~INTEN;
+	if (enable) {
+		hcntrl |= INTEN;
+		ahc->pause |= INTEN;
+		ahc->unpause |= INTEN;
+	}
+	ahc_outb(ahc, HCNTRL, hcntrl);
+}
+
+/*
+ * Ensure that the card is paused in a location
+ * outside of all critical sections and that all
+ * pending work is completed prior to returning.
+ * This routine should only be called from outside
+ * an interrupt context.
+ */
+void
+ahc_pause_and_flushwork(struct ahc_softc *ahc)
+{
+	int intstat;
+	int maxloops;
+	int paused;
+
+	maxloops = 1000;
+	ahc->flags |= AHC_ALL_INTERRUPTS;
+	paused = FALSE;
+	do {
+		if (paused)
+			ahc_unpause(ahc);
+		ahc_intr(ahc);
+		ahc_pause(ahc);
+		paused = TRUE;
+		ahc_outb(ahc, SCSISEQ, ahc_inb(ahc, SCSISEQ) & ~ENSELO);
+		ahc_clear_critical_section(ahc);
+		intstat = ahc_inb(ahc, INTSTAT);
+	} while (--maxloops
+	      && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
+	      && ((intstat & INT_PEND) != 0
+	       || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0));
+	if (maxloops == 0) {
+		printf("Infinite interrupt loop, INTSTAT = %x",
+		       ahc_inb(ahc, INTSTAT));
+	}
+	ahc_platform_flushwork(ahc);
+	ahc->flags &= ~AHC_ALL_INTERRUPTS;
+}
+
+int
+ahc_suspend(struct ahc_softc *ahc)
+{
+
+	ahc_pause_and_flushwork(ahc);
+
+	if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+		ahc_unpause(ahc);
+		return (EBUSY);
+	}
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * XXX What about ATIOs that have not yet been serviced?
+	 * Perhaps we should just refuse to be suspended if we
+	 * are acting in a target role.
+	 */
+	if (ahc->pending_device != NULL) {
+		ahc_unpause(ahc);
+		return (EBUSY);
+	}
+#endif
+	ahc_shutdown(ahc);
+	return (0);
+}
+
+int
+ahc_resume(struct ahc_softc *ahc)
+{
+
+	ahc_reset(ahc, /*reinit*/TRUE);
+	ahc_intr_enable(ahc, TRUE); 
+	ahc_restart(ahc);
+	return (0);
+}
+
+/************************** Busy Target Table *********************************/
+/*
+ * Return the untagged transaction id for a given target/channel lun.
+ * Optionally, clear the entry.
+ */
+u_int
+ahc_index_busy_tcl(struct ahc_softc *ahc, u_int tcl)
+{
+	u_int scbid;
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		scbid = ahc_inb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl));
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		scbid = ahc_inb(ahc, BUSY_TARGETS + target_offset);
+	}
+
+	return (scbid);
+}
+
+void
+ahc_unbusy_tcl(struct ahc_softc *ahc, u_int tcl)
+{
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		ahc_outb(ahc, SCB_64_BTT+TCL_TARGET_OFFSET(tcl), SCB_LIST_NULL);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		ahc_outb(ahc, BUSY_TARGETS + target_offset, SCB_LIST_NULL);
+	}
+}
+
+void
+ahc_busy_tcl(struct ahc_softc *ahc, u_int tcl, u_int scbid)
+{
+	u_int target_offset;
+
+	if ((ahc->flags & AHC_SCB_BTT) != 0) {
+		u_int saved_scbptr;
+		
+		saved_scbptr = ahc_inb(ahc, SCBPTR);
+		ahc_outb(ahc, SCBPTR, TCL_LUN(tcl));
+		ahc_outb(ahc, SCB_64_BTT + TCL_TARGET_OFFSET(tcl), scbid);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+	} else {
+		target_offset = TCL_TARGET_OFFSET(tcl);
+		ahc_outb(ahc, BUSY_TARGETS + target_offset, scbid);
+	}
+}
+
+/************************** SCB and SCB queue management **********************/
+int
+ahc_match_scb(struct ahc_softc *ahc, struct scb *scb, int target,
+	      char channel, int lun, u_int tag, role_t role)
+{
+	int targ = SCB_GET_TARGET(ahc, scb);
+	char chan = SCB_GET_CHANNEL(ahc, scb);
+	int slun = SCB_GET_LUN(scb);
+	int match;
+
+	match = ((chan == channel) || (channel == ALL_CHANNELS));
+	if (match != 0)
+		match = ((targ == target) || (target == CAM_TARGET_WILDCARD));
+	if (match != 0)
+		match = ((lun == slun) || (lun == CAM_LUN_WILDCARD));
+	if (match != 0) {
+#ifdef AHC_TARGET_MODE
+		int group;
+
+		group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code);
+		if (role == ROLE_INITIATOR) {
+			match = (group != XPT_FC_GROUP_TMODE)
+			      && ((tag == scb->hscb->tag)
+			       || (tag == SCB_LIST_NULL));
+		} else if (role == ROLE_TARGET) {
+			match = (group == XPT_FC_GROUP_TMODE)
+			      && ((tag == scb->io_ctx->csio.tag_id)
+			       || (tag == SCB_LIST_NULL));
+		}
+#else /* !AHC_TARGET_MODE */
+		match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+#endif /* AHC_TARGET_MODE */
+	}
+
+	return match;
+}
+
+void
+ahc_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
+{
+	int	target;
+	char	channel;
+	int	lun;
+
+	target = SCB_GET_TARGET(ahc, scb);
+	lun = SCB_GET_LUN(scb);
+	channel = SCB_GET_CHANNEL(ahc, scb);
+	
+	ahc_search_qinfifo(ahc, target, channel, lun,
+			   /*tag*/SCB_LIST_NULL, ROLE_UNKNOWN,
+			   CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	ahc_platform_freeze_devq(ahc, scb);
+}
+
+void
+ahc_qinfifo_requeue_tail(struct ahc_softc *ahc, struct scb *scb)
+{
+	struct scb *prev_scb;
+
+	prev_scb = NULL;
+	if (ahc_qinfifo_count(ahc) != 0) {
+		u_int prev_tag;
+		uint8_t prev_pos;
+
+		prev_pos = ahc->qinfifonext - 1;
+		prev_tag = ahc->qinfifo[prev_pos];
+		prev_scb = ahc_lookup_scb(ahc, prev_tag);
+	}
+	ahc_qinfifo_requeue(ahc, prev_scb, scb);
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+	}
+}
+
+static void
+ahc_qinfifo_requeue(struct ahc_softc *ahc, struct scb *prev_scb,
+		    struct scb *scb)
+{
+	if (prev_scb == NULL) {
+		ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);
+	} else {
+		prev_scb->hscb->next = scb->hscb->tag;
+		ahc_sync_scb(ahc, prev_scb, 
+			     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+	}
+	ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+	scb->hscb->next = ahc->next_queued_scb->hscb->tag;
+	ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+}
+
+static int
+ahc_qinfifo_count(struct ahc_softc *ahc)
+{
+	uint8_t qinpos;
+	uint8_t diff;
+
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		qinpos = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinpos);
+	} else
+		qinpos = ahc_inb(ahc, QINPOS);
+	diff = ahc->qinfifonext - qinpos;
+	return (diff);
+}
+
+int
+ahc_search_qinfifo(struct ahc_softc *ahc, int target, char channel,
+		   int lun, u_int tag, role_t role, uint32_t status,
+		   ahc_search_action action)
+{
+	struct	scb *scb;
+	struct	scb *prev_scb;
+	uint8_t qinstart;
+	uint8_t qinpos;
+	uint8_t qintail;
+	uint8_t next;
+	uint8_t prev;
+	uint8_t curscbptr;
+	int	found;
+	int	have_qregs;
+
+	qintail = ahc->qinfifonext;
+	have_qregs = (ahc->features & AHC_QUEUE_REGS) != 0;
+	if (have_qregs) {
+		qinstart = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinstart);
+	} else
+		qinstart = ahc_inb(ahc, QINPOS);
+	qinpos = qinstart;
+	found = 0;
+	prev_scb = NULL;
+
+	if (action == SEARCH_COMPLETE) {
+		/*
+		 * Don't attempt to run any queued untagged transactions
+		 * until we are done with the abort process.
+		 */
+		ahc_freeze_untagged_queues(ahc);
+	}
+
+	/*
+	 * Start with an empty queue.  Entries that are not chosen
+	 * for removal will be re-added to the queue as we go.
+	 */
+	ahc->qinfifonext = qinpos;
+	ahc_outb(ahc, NEXT_QUEUED_SCB, ahc->next_queued_scb->hscb->tag);
+
+	while (qinpos != qintail) {
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinpos]);
+		if (scb == NULL) {
+			printf("qinpos = %d, SCB index = %d\n",
+				qinpos, ahc->qinfifo[qinpos]);
+			panic("Loop 1\n");
+		}
+
+		if (ahc_match_scb(ahc, scb, target, channel, lun, tag, role)) {
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb, status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in qinfifo\n");
+				ahc_done(ahc, scb);
+
+				/* FALLTHROUGH */
+			}
+			case SEARCH_REMOVE:
+				break;
+			case SEARCH_COUNT:
+				ahc_qinfifo_requeue(ahc, prev_scb, scb);
+				prev_scb = scb;
+				break;
+			}
+		} else {
+			ahc_qinfifo_requeue(ahc, prev_scb, scb);
+			prev_scb = scb;
+		}
+		qinpos++;
+	}
+
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+	}
+
+	if (action != SEARCH_COUNT
+	 && (found != 0)
+	 && (qinstart != ahc->qinfifonext)) {
+		/*
+		 * The sequencer may be in the process of dmaing
+		 * down the SCB at the beginning of the queue.
+		 * This could be problematic if either the first,
+		 * or the second SCB is removed from the queue
+		 * (the first SCB includes a pointer to the "next"
+		 * SCB to dma). If we have removed any entries, swap
+		 * the first element in the queue with the next HSCB
+		 * so the sequencer will notice that NEXT_QUEUED_SCB
+		 * has changed during its dma attempt and will retry
+		 * the DMA.
+		 */
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qinstart]);
+
+		if (scb == NULL) {
+			printf("found = %d, qinstart = %d, qinfifionext = %d\n",
+				found, qinstart, ahc->qinfifonext);
+			panic("First/Second Qinfifo fixup\n");
+		}
+		/*
+		 * ahc_swap_with_next_hscb forces our next pointer to
+		 * point to the reserved SCB for future commands.  Save
+		 * and restore our original next pointer to maintain
+		 * queue integrity.
+		 */
+		next = scb->hscb->next;
+		ahc->scb_data->scbindex[scb->hscb->tag] = NULL;
+		ahc_swap_with_next_hscb(ahc, scb);
+		scb->hscb->next = next;
+		ahc->qinfifo[qinstart] = scb->hscb->tag;
+
+		/* Tell the card about the new head of the qinfifo. */
+		ahc_outb(ahc, NEXT_QUEUED_SCB, scb->hscb->tag);
+
+		/* Fixup the tail "next" pointer. */
+		qintail = ahc->qinfifonext - 1;
+		scb = ahc_lookup_scb(ahc, ahc->qinfifo[qintail]);
+		scb->hscb->next = ahc->next_queued_scb->hscb->tag;
+	}
+
+	/*
+	 * Search waiting for selection list.
+	 */
+	curscbptr = ahc_inb(ahc, SCBPTR);
+	next = ahc_inb(ahc, WAITING_SCBH);  /* Start at head of list. */
+	prev = SCB_LIST_NULL;
+
+	while (next != SCB_LIST_NULL) {
+		uint8_t scb_index;
+
+		ahc_outb(ahc, SCBPTR, next);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		if (scb_index >= ahc->scb_data->numscbs) {
+			printf("Waiting List inconsistency. "
+			       "SCB index == %d, yet numscbs == %d.",
+			       scb_index, ahc->scb_data->numscbs);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+		}
+		scb = ahc_lookup_scb(ahc, scb_index);
+		if (scb == NULL) {
+			printf("scb_index = %d, next = %d\n",
+				scb_index, next);
+			panic("Waiting List traversal\n");
+		}
+		if (ahc_match_scb(ahc, scb, target, channel,
+				  lun, SCB_LIST_NULL, role)) {
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb,
+								   status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in Waiting List\n");
+				ahc_done(ahc, scb);
+				/* FALLTHROUGH */
+			}
+			case SEARCH_REMOVE:
+				next = ahc_rem_wscb(ahc, next, prev);
+				break;
+			case SEARCH_COUNT:
+				prev = next;
+				next = ahc_inb(ahc, SCB_NEXT);
+				break;
+			}
+		} else {
+			
+			prev = next;
+			next = ahc_inb(ahc, SCB_NEXT);
+		}
+	}
+	ahc_outb(ahc, SCBPTR, curscbptr);
+
+	found += ahc_search_untagged_queues(ahc, /*ahc_io_ctx_t*/NULL, target,
+					    channel, lun, status, action);
+
+	if (action == SEARCH_COMPLETE)
+		ahc_release_untagged_queues(ahc);
+	return (found);
+}
+
+int
+ahc_search_untagged_queues(struct ahc_softc *ahc, ahc_io_ctx_t ctx,
+			   int target, char channel, int lun, uint32_t status,
+			   ahc_search_action action)
+{
+	struct	scb *scb;
+	int	maxtarget;
+	int	found;
+	int	i;
+
+	if (action == SEARCH_COMPLETE) {
+		/*
+		 * Don't attempt to run any queued untagged transactions
+		 * until we are done with the abort process.
+		 */
+		ahc_freeze_untagged_queues(ahc);
+	}
+
+	found = 0;
+	i = 0;
+	if ((ahc->flags & AHC_SCB_BTT) == 0) {
+
+		maxtarget = 16;
+		if (target != CAM_TARGET_WILDCARD) {
+
+			i = target;
+			if (channel == 'B')
+				i += 8;
+			maxtarget = i + 1;
+		}
+	} else {
+		maxtarget = 0;
+	}
+
+	for (; i < maxtarget; i++) {
+		struct scb_tailq *untagged_q;
+		struct scb *next_scb;
+
+		untagged_q = &(ahc->untagged_queues[i]);
+		next_scb = TAILQ_FIRST(untagged_q);
+		while (next_scb != NULL) {
+
+			scb = next_scb;
+			next_scb = TAILQ_NEXT(scb, links.tqe);
+
+			/*
+			 * The head of the list may be the currently
+			 * active untagged command for a device.
+			 * We're only searching for commands that
+			 * have not been started.  A transaction
+			 * marked active but still in the qinfifo
+			 * is removed by the qinfifo scanning code
+			 * above.
+			 */
+			if ((scb->flags & SCB_ACTIVE) != 0)
+				continue;
+
+			if (ahc_match_scb(ahc, scb, target, channel, lun,
+					  SCB_LIST_NULL, ROLE_INITIATOR) == 0
+			 || (ctx != NULL && ctx != scb->io_ctx))
+				continue;
+
+			/*
+			 * We found an scb that needs to be acted on.
+			 */
+			found++;
+			switch (action) {
+			case SEARCH_COMPLETE:
+			{
+				cam_status ostat;
+				cam_status cstat;
+
+				ostat = ahc_get_transaction_status(scb);
+				if (ostat == CAM_REQ_INPROG)
+					ahc_set_transaction_status(scb, status);
+				cstat = ahc_get_transaction_status(scb);
+				if (cstat != CAM_REQ_CMP)
+					ahc_freeze_scb(scb);
+				if ((scb->flags & SCB_ACTIVE) == 0)
+					printf("Inactive SCB in untaggedQ\n");
+				ahc_done(ahc, scb);
+				break;
+			}
+			case SEARCH_REMOVE:
+				scb->flags &= ~SCB_UNTAGGEDQ;
+				TAILQ_REMOVE(untagged_q, scb, links.tqe);
+				break;
+			case SEARCH_COUNT:
+				break;
+			}
+		}
+	}
+
+	if (action == SEARCH_COMPLETE)
+		ahc_release_untagged_queues(ahc);
+	return (found);
+}
+
+int
+ahc_search_disc_list(struct ahc_softc *ahc, int target, char channel,
+		     int lun, u_int tag, int stop_on_first, int remove,
+		     int save_state)
+{
+	struct	scb *scbp;
+	u_int	next;
+	u_int	prev;
+	u_int	count;
+	u_int	active_scb;
+
+	count = 0;
+	next = ahc_inb(ahc, DISCONNECTED_SCBH);
+	prev = SCB_LIST_NULL;
+
+	if (save_state) {
+		/* restore this when we're done */
+		active_scb = ahc_inb(ahc, SCBPTR);
+	} else
+		/* Silence compiler */
+		active_scb = SCB_LIST_NULL;
+
+	while (next != SCB_LIST_NULL) {
+		u_int scb_index;
+
+		ahc_outb(ahc, SCBPTR, next);
+		scb_index = ahc_inb(ahc, SCB_TAG);
+		if (scb_index >= ahc->scb_data->numscbs) {
+			printf("Disconnected List inconsistency. "
+			       "SCB index == %d, yet numscbs == %d.",
+			       scb_index, ahc->scb_data->numscbs);
+			ahc_dump_card_state(ahc);
+			panic("for safety");
+		}
+
+		if (next == prev) {
+			panic("Disconnected List Loop. "
+			      "cur SCBPTR == %x, prev SCBPTR == %x.",
+			      next, prev);
+		}
+		scbp = ahc_lookup_scb(ahc, scb_index);
+		if (ahc_match_scb(ahc, scbp, target, channel, lun,
+				  tag, ROLE_INITIATOR)) {
+			count++;
+			if (remove) {
+				next =
+				    ahc_rem_scb_from_disc_list(ahc, prev, next);
+			} else {
+				prev = next;
+				next = ahc_inb(ahc, SCB_NEXT);
+			}
+			if (stop_on_first)
+				break;
+		} else {
+			prev = next;
+			next = ahc_inb(ahc, SCB_NEXT);
+		}
+	}
+	if (save_state)
+		ahc_outb(ahc, SCBPTR, active_scb);
+	return (count);
+}
+
+/*
+ * Remove an SCB from the on chip list of disconnected transactions.
+ * This is empty/unused if we are not performing SCB paging.
+ */
+static u_int
+ahc_rem_scb_from_disc_list(struct ahc_softc *ahc, u_int prev, u_int scbptr)
+{
+	u_int next;
+
+	ahc_outb(ahc, SCBPTR, scbptr);
+	next = ahc_inb(ahc, SCB_NEXT);
+
+	ahc_outb(ahc, SCB_CONTROL, 0);
+
+	ahc_add_curscb_to_free_list(ahc);
+
+	if (prev != SCB_LIST_NULL) {
+		ahc_outb(ahc, SCBPTR, prev);
+		ahc_outb(ahc, SCB_NEXT, next);
+	} else
+		ahc_outb(ahc, DISCONNECTED_SCBH, next);
+
+	return (next);
+}
+
+/*
+ * Add the SCB as selected by SCBPTR onto the on chip list of
+ * free hardware SCBs.  This list is empty/unused if we are not
+ * performing SCB paging.
+ */
+static void
+ahc_add_curscb_to_free_list(struct ahc_softc *ahc)
+{
+	/*
+	 * Invalidate the tag so that our abort
+	 * routines don't think it's active.
+	 */
+	ahc_outb(ahc, SCB_TAG, SCB_LIST_NULL);
+
+	if ((ahc->flags & AHC_PAGESCBS) != 0) {
+		ahc_outb(ahc, SCB_NEXT, ahc_inb(ahc, FREE_SCBH));
+		ahc_outb(ahc, FREE_SCBH, ahc_inb(ahc, SCBPTR));
+	}
+}
+
+/*
+ * Manipulate the waiting for selection list and return the
+ * scb that follows the one that we remove.
+ */
+static u_int
+ahc_rem_wscb(struct ahc_softc *ahc, u_int scbpos, u_int prev)
+{       
+	u_int curscb, next;
+
+	/*
+	 * Select the SCB we want to abort and
+	 * pull the next pointer out of it.
+	 */
+	curscb = ahc_inb(ahc, SCBPTR);
+	ahc_outb(ahc, SCBPTR, scbpos);
+	next = ahc_inb(ahc, SCB_NEXT);
+
+	/* Clear the necessary fields */
+	ahc_outb(ahc, SCB_CONTROL, 0);
+
+	ahc_add_curscb_to_free_list(ahc);
+
+	/* update the waiting list */
+	if (prev == SCB_LIST_NULL) {
+		/* First in the list */
+		ahc_outb(ahc, WAITING_SCBH, next); 
+
+		/*
+		 * Ensure we aren't attempting to perform
+		 * selection for this entry.
+		 */
+		ahc_outb(ahc, SCSISEQ, (ahc_inb(ahc, SCSISEQ) & ~ENSELO));
+	} else {
+		/*
+		 * Select the scb that pointed to us 
+		 * and update its next pointer.
+		 */
+		ahc_outb(ahc, SCBPTR, prev);
+		ahc_outb(ahc, SCB_NEXT, next);
+	}
+
+	/*
+	 * Point us back at the original scb position.
+	 */
+	ahc_outb(ahc, SCBPTR, curscb);
+	return next;
+}
+
+/******************************** Error Handling ******************************/
+/*
+ * Abort all SCBs that match the given description (target/channel/lun/tag),
+ * setting their status to the passed in status if the status has not already
+ * been modified from CAM_REQ_INPROG.  This routine assumes that the sequencer
+ * is paused before it is called.
+ */
+int
+ahc_abort_scbs(struct ahc_softc *ahc, int target, char channel,
+	       int lun, u_int tag, role_t role, uint32_t status)
+{
+	struct	scb *scbp;
+	struct	scb *scbp_next;
+	u_int	active_scb;
+	int	i, j;
+	int	maxtarget;
+	int	minlun;
+	int	maxlun;
+
+	int	found;
+
+	/*
+	 * Don't attempt to run any queued untagged transactions
+	 * until we are done with the abort process.
+	 */
+	ahc_freeze_untagged_queues(ahc);
+
+	/* restore this when we're done */
+	active_scb = ahc_inb(ahc, SCBPTR);
+
+	found = ahc_search_qinfifo(ahc, target, channel, lun, SCB_LIST_NULL,
+				   role, CAM_REQUEUE_REQ, SEARCH_COMPLETE);
+
+	/*
+	 * Clean out the busy target table for any untagged commands.
+	 */
+	i = 0;
+	maxtarget = 16;
+	if (target != CAM_TARGET_WILDCARD) {
+		i = target;
+		if (channel == 'B')
+			i += 8;
+		maxtarget = i + 1;
+	}
+
+	if (lun == CAM_LUN_WILDCARD) {
+
+		/*
+		 * Unless we are using an SCB based
+		 * busy targets table, there is only
+		 * one table entry for all luns of
+		 * a target.
+		 */
+		minlun = 0;
+		maxlun = 1;
+		if ((ahc->flags & AHC_SCB_BTT) != 0)
+			maxlun = AHC_NUM_LUNS;
+	} else {
+		minlun = lun;
+		maxlun = lun + 1;
+	}
+
+	if (role != ROLE_TARGET) {
+		for (;i < maxtarget; i++) {
+			for (j = minlun;j < maxlun; j++) {
+				u_int scbid;
+				u_int tcl;
+
+				tcl = BUILD_TCL(i << 4, j);
+				scbid = ahc_index_busy_tcl(ahc, tcl);
+				scbp = ahc_lookup_scb(ahc, scbid);
+				if (scbp == NULL
+				 || ahc_match_scb(ahc, scbp, target, channel,
+						  lun, tag, role) == 0)
+					continue;
+				ahc_unbusy_tcl(ahc, BUILD_TCL(i << 4, j));
+			}
+		}
+
+		/*
+		 * Go through the disconnected list and remove any entries we
+		 * have queued for completion, 0'ing their control byte too.
+		 * We save the active SCB and restore it ourselves, so there
+		 * is no reason for this search to restore it too.
+		 */
+		ahc_search_disc_list(ahc, target, channel, lun, tag,
+				     /*stop_on_first*/FALSE, /*remove*/TRUE,
+				     /*save_state*/FALSE);
+	}
+
+	/*
+	 * Go through the hardware SCB array looking for commands that
+	 * were active but not on any list.  In some cases, these remnants
+	 * might not still have mappings in the scbindex array (e.g. unexpected
+	 * bus free with the same scb queued for an abort).  Don't hold this
+	 * against them.
+	 */
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		u_int scbid;
+
+		ahc_outb(ahc, SCBPTR, i);
+		scbid = ahc_inb(ahc, SCB_TAG);
+		scbp = ahc_lookup_scb(ahc, scbid);
+		if ((scbp == NULL && scbid != SCB_LIST_NULL)
+		 || (scbp != NULL
+		  && ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)))
+			ahc_add_curscb_to_free_list(ahc);
+	}
+
+	/*
+	 * Go through the pending CCB list and look for
+	 * commands for this target that are still active.
+	 * These are other tagged commands that were
+	 * disconnected when the reset occurred.
+	 */
+	scbp_next = LIST_FIRST(&ahc->pending_scbs);
+	while (scbp_next != NULL) {
+		scbp = scbp_next;
+		scbp_next = LIST_NEXT(scbp, pending_links);
+		if (ahc_match_scb(ahc, scbp, target, channel, lun, tag, role)) {
+			cam_status ostat;
+
+			ostat = ahc_get_transaction_status(scbp);
+			if (ostat == CAM_REQ_INPROG)
+				ahc_set_transaction_status(scbp, status);
+			if (ahc_get_transaction_status(scbp) != CAM_REQ_CMP)
+				ahc_freeze_scb(scbp);
+			if ((scbp->flags & SCB_ACTIVE) == 0)
+				printf("Inactive SCB on pending list\n");
+			ahc_done(ahc, scbp);
+			found++;
+		}
+	}
+	ahc_outb(ahc, SCBPTR, active_scb);
+	ahc_platform_abort_scbs(ahc, target, channel, lun, tag, role, status);
+	ahc_release_untagged_queues(ahc);
+	return found;
+}
+
+static void
+ahc_reset_current_bus(struct ahc_softc *ahc)
+{
+	uint8_t scsiseq;
+
+	ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) & ~ENSCSIRST);
+	scsiseq = ahc_inb(ahc, SCSISEQ);
+	ahc_outb(ahc, SCSISEQ, scsiseq | SCSIRSTO);
+	ahc_flush_device_writes(ahc);
+	ahc_delay(AHC_BUSRESET_DELAY);
+	/* Turn off the bus reset */
+	ahc_outb(ahc, SCSISEQ, scsiseq & ~SCSIRSTO);
+
+	ahc_clear_intstat(ahc);
+
+	/* Re-enable reset interrupts */
+	ahc_outb(ahc, SIMODE1, ahc_inb(ahc, SIMODE1) | ENSCSIRST);
+}
+
+int
+ahc_reset_channel(struct ahc_softc *ahc, char channel, int initiate_reset)
+{
+	struct	ahc_devinfo devinfo;
+	u_int	initiator, target, max_scsiid;
+	u_int	sblkctl;
+	u_int	scsiseq;
+	u_int	simode1;
+	int	found;
+	int	restart_needed;
+	char	cur_channel;
+
+	ahc->pending_device = NULL;
+
+	ahc_compile_devinfo(&devinfo,
+			    CAM_TARGET_WILDCARD,
+			    CAM_TARGET_WILDCARD,
+			    CAM_LUN_WILDCARD,
+			    channel, ROLE_UNKNOWN);
+	ahc_pause(ahc);
+
+	/* Make sure the sequencer is in a safe location. */
+	ahc_clear_critical_section(ahc);
+
+	/*
+	 * Run our command complete fifos to ensure that we perform
+	 * completion processing on any commands that 'completed'
+	 * before the reset occurred.
+	 */
+	ahc_run_qoutfifo(ahc);
+#ifdef AHC_TARGET_MODE
+	/*
+	 * XXX - In Twin mode, the tqinfifo may have commands
+	 *	 for an unaffected channel in it.  However, if
+	 *	 we have run out of ATIO resources to drain that
+	 *	 queue, we may not get them all out here.  Further,
+	 *	 the blocked transactions for the reset channel
+	 *	 should just be killed off, irrespecitve of whether
+	 *	 we are blocked on ATIO resources.  Write a routine
+	 *	 to compact the tqinfifo appropriately.
+	 */
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		ahc_run_tqinfifo(ahc, /*paused*/TRUE);
+	}
+#endif
+
+	/*
+	 * Reset the bus if we are initiating this reset
+	 */
+	sblkctl = ahc_inb(ahc, SBLKCTL);
+	cur_channel = 'A';
+	if ((ahc->features & AHC_TWIN) != 0
+	 && ((sblkctl & SELBUSB) != 0))
+	    cur_channel = 'B';
+	scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
+	if (cur_channel != channel) {
+		/* Case 1: Command for another bus is active
+		 * Stealthily reset the other bus without
+		 * upsetting the current bus.
+		 */
+		ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB);
+		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
+#ifdef AHC_TARGET_MODE
+		/*
+		 * Bus resets clear ENSELI, so we cannot
+		 * defer re-enabling bus reset interrupts
+		 * if we are in target mode.
+		 */
+		if ((ahc->flags & AHC_TARGETROLE) != 0)
+			simode1 |= ENSCSIRST;
+#endif
+		ahc_outb(ahc, SIMODE1, simode1);
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
+		ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
+		ahc_outb(ahc, SBLKCTL, sblkctl);
+		restart_needed = FALSE;
+	} else {
+		/* Case 2: A command from this bus is active or we're idle */
+		simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST);
+#ifdef AHC_TARGET_MODE
+		/*
+		 * Bus resets clear ENSELI, so we cannot
+		 * defer re-enabling bus reset interrupts
+		 * if we are in target mode.
+		 */
+		if ((ahc->flags & AHC_TARGETROLE) != 0)
+			simode1 |= ENSCSIRST;
+#endif
+		ahc_outb(ahc, SIMODE1, simode1);
+		if (initiate_reset)
+			ahc_reset_current_bus(ahc);
+		ahc_clear_intstat(ahc);
+		ahc_outb(ahc, SCSISEQ, scsiseq & (ENSELI|ENRSELI|ENAUTOATNP));
+		restart_needed = TRUE;
+	}
+
+	/*
+	 * Clean up all the state information for the
+	 * pending transactions on this bus.
+	 */
+	found = ahc_abort_scbs(ahc, CAM_TARGET_WILDCARD, channel,
+			       CAM_LUN_WILDCARD, SCB_LIST_NULL,
+			       ROLE_UNKNOWN, CAM_SCSI_BUS_RESET);
+
+	max_scsiid = (ahc->features & AHC_WIDE) ? 15 : 7;
+
+#ifdef AHC_TARGET_MODE
+	/*
+	 * Send an immediate notify ccb to all target more peripheral
+	 * drivers affected by this action.
+	 */
+	for (target = 0; target <= max_scsiid; target++) {
+		struct ahc_tmode_tstate* tstate;
+		u_int lun;
+
+		tstate = ahc->enabled_targets[target];
+		if (tstate == NULL)
+			continue;
+		for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+			struct ahc_tmode_lstate* lstate;
+
+			lstate = tstate->enabled_luns[lun];
+			if (lstate == NULL)
+				continue;
+
+			ahc_queue_lstate_event(ahc, lstate, CAM_TARGET_WILDCARD,
+					       EVENT_TYPE_BUS_RESET, /*arg*/0);
+			ahc_send_lstate_events(ahc, lstate);
+		}
+	}
+#endif
+	/* Notify the XPT that a bus reset occurred */
+	ahc_send_async(ahc, devinfo.channel, CAM_TARGET_WILDCARD,
+		       CAM_LUN_WILDCARD, AC_BUS_RESET, NULL);
+
+	/*
+	 * Revert to async/narrow transfers until we renegotiate.
+	 */
+	for (target = 0; target <= max_scsiid; target++) {
+
+		if (ahc->enabled_targets[target] == NULL)
+			continue;
+		for (initiator = 0; initiator <= max_scsiid; initiator++) {
+			struct ahc_devinfo devinfo;
+
+			ahc_compile_devinfo(&devinfo, target, initiator,
+					    CAM_LUN_WILDCARD,
+					    channel, ROLE_UNKNOWN);
+			ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHC_TRANS_CUR, /*paused*/TRUE);
+			ahc_set_syncrate(ahc, &devinfo, /*syncrate*/NULL,
+					 /*period*/0, /*offset*/0,
+					 /*ppr_options*/0, AHC_TRANS_CUR,
+					 /*paused*/TRUE);
+		}
+	}
+
+	if (restart_needed)
+		ahc_restart(ahc);
+	else
+		ahc_unpause(ahc);
+	return found;
+}
+
+
+/***************************** Residual Processing ****************************/
+/*
+ * Calculate the residual for a just completed SCB.
+ */
+void
+ahc_calc_residual(struct ahc_softc *ahc, struct scb *scb)
+{
+	struct hardware_scb *hscb;
+	struct status_pkt *spkt;
+	uint32_t sgptr;
+	uint32_t resid_sgptr;
+	uint32_t resid;
+
+	/*
+	 * 5 cases.
+	 * 1) No residual.
+	 *    SG_RESID_VALID clear in sgptr.
+	 * 2) Transferless command
+	 * 3) Never performed any transfers.
+	 *    sgptr has SG_FULL_RESID set.
+	 * 4) No residual but target did not
+	 *    save data pointers after the
+	 *    last transfer, so sgptr was
+	 *    never updated.
+	 * 5) We have a partial residual.
+	 *    Use residual_sgptr to determine
+	 *    where we are.
+	 */
+
+	hscb = scb->hscb;
+	sgptr = ahc_le32toh(hscb->sgptr);
+	if ((sgptr & SG_RESID_VALID) == 0)
+		/* Case 1 */
+		return;
+	sgptr &= ~SG_RESID_VALID;
+
+	if ((sgptr & SG_LIST_NULL) != 0)
+		/* Case 2 */
+		return;
+
+	spkt = &hscb->shared_data.status;
+	resid_sgptr = ahc_le32toh(spkt->residual_sg_ptr);
+	if ((sgptr & SG_FULL_RESID) != 0) {
+		/* Case 3 */
+		resid = ahc_get_transfer_length(scb);
+	} else if ((resid_sgptr & SG_LIST_NULL) != 0) {
+		/* Case 4 */
+		return;
+	} else if ((resid_sgptr & ~SG_PTR_MASK) != 0) {
+		panic("Bogus resid sgptr value 0x%x\n", resid_sgptr);
+	} else {
+		struct ahc_dma_seg *sg;
+
+		/*
+		 * Remainder of the SG where the transfer
+		 * stopped.  
+		 */
+		resid = ahc_le32toh(spkt->residual_datacnt) & AHC_SG_LEN_MASK;
+		sg = ahc_sg_bus_to_virt(scb, resid_sgptr & SG_PTR_MASK);
+
+		/* The residual sg_ptr always points to the next sg */
+		sg--;
+
+		/*
+		 * Add up the contents of all residual
+		 * SG segments that are after the SG where
+		 * the transfer stopped.
+		 */
+		while ((ahc_le32toh(sg->len) & AHC_DMA_LAST_SEG) == 0) {
+			sg++;
+			resid += ahc_le32toh(sg->len) & AHC_SG_LEN_MASK;
+		}
+	}
+	if ((scb->flags & SCB_SENSE) == 0)
+		ahc_set_residual(scb, resid);
+	else
+		ahc_set_sense_residual(scb, resid);
+
+#ifdef AHC_DEBUG
+	if ((ahc_debug & AHC_SHOW_MISC) != 0) {
+		ahc_print_path(ahc, scb);
+		printf("Handled %sResidual of %d bytes\n",
+		       (scb->flags & SCB_SENSE) ? "Sense " : "", resid);
+	}
+#endif
+}
+
+/******************************* Target Mode **********************************/
+#ifdef AHC_TARGET_MODE
+/*
+ * Add a target mode event to this lun's queue
+ */
+static void
+ahc_queue_lstate_event(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate,
+		       u_int initiator_id, u_int event_type, u_int event_arg)
+{
+	struct ahc_tmode_event *event;
+	int pending;
+
+	xpt_freeze_devq(lstate->path, /*count*/1);
+	if (lstate->event_w_idx >= lstate->event_r_idx)
+		pending = lstate->event_w_idx - lstate->event_r_idx;
+	else
+		pending = AHC_TMODE_EVENT_BUFFER_SIZE + 1
+			- (lstate->event_r_idx - lstate->event_w_idx);
+
+	if (event_type == EVENT_TYPE_BUS_RESET
+	 || event_type == MSG_BUS_DEV_RESET) {
+		/*
+		 * Any earlier events are irrelevant, so reset our buffer.
+		 * This has the effect of allowing us to deal with reset
+		 * floods (an external device holding down the reset line)
+		 * without losing the event that is really interesting.
+		 */
+		lstate->event_r_idx = 0;
+		lstate->event_w_idx = 0;
+		xpt_release_devq(lstate->path, pending, /*runqueue*/FALSE);
+	}
+
+	if (pending == AHC_TMODE_EVENT_BUFFER_SIZE) {
+		xpt_print_path(lstate->path);
+		printf("immediate event %x:%x lost\n",
+		       lstate->event_buffer[lstate->event_r_idx].event_type,
+		       lstate->event_buffer[lstate->event_r_idx].event_arg);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+		xpt_release_devq(lstate->path, /*count*/1, /*runqueue*/FALSE);
+	}
+
+	event = &lstate->event_buffer[lstate->event_w_idx];
+	event->initiator_id = initiator_id;
+	event->event_type = event_type;
+	event->event_arg = event_arg;
+	lstate->event_w_idx++;
+	if (lstate->event_w_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+		lstate->event_w_idx = 0;
+}
+
+/*
+ * Send any target mode events queued up waiting
+ * for immediate notify resources.
+ */
+void
+ahc_send_lstate_events(struct ahc_softc *ahc, struct ahc_tmode_lstate *lstate)
+{
+	struct ccb_hdr *ccbh;
+	struct ccb_immed_notify *inot;
+
+	while (lstate->event_r_idx != lstate->event_w_idx
+	    && (ccbh = SLIST_FIRST(&lstate->immed_notifies)) != NULL) {
+		struct ahc_tmode_event *event;
+
+		event = &lstate->event_buffer[lstate->event_r_idx];
+		SLIST_REMOVE_HEAD(&lstate->immed_notifies, sim_links.sle);
+		inot = (struct ccb_immed_notify *)ccbh;
+		switch (event->event_type) {
+		case EVENT_TYPE_BUS_RESET:
+			ccbh->status = CAM_SCSI_BUS_RESET|CAM_DEV_QFRZN;
+			break;
+		default:
+			ccbh->status = CAM_MESSAGE_RECV|CAM_DEV_QFRZN;
+			inot->message_args[0] = event->event_type;
+			inot->message_args[1] = event->event_arg;
+			break;
+		}
+		inot->initiator_id = event->initiator_id;
+		inot->sense_len = 0;
+		xpt_done((union ccb *)inot);
+		lstate->event_r_idx++;
+		if (lstate->event_r_idx == AHC_TMODE_EVENT_BUFFER_SIZE)
+			lstate->event_r_idx = 0;
+	}
+}
+#endif
+
+/******************** Sequencer Program Patching/Download *********************/
+
+#ifdef AHC_DUMP_SEQ
+void
+ahc_dumpseq(struct ahc_softc* ahc)
+{
+	int i;
+
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+	for (i = 0; i < ahc->instruction_ram_size; i++) {
+		uint8_t ins_bytes[4];
+
+		ahc_insb(ahc, SEQRAM, ins_bytes, 4);
+		printf("0x%08x\n", ins_bytes[0] << 24
+				 | ins_bytes[1] << 16
+				 | ins_bytes[2] << 8
+				 | ins_bytes[3]);
+	}
+}
+#endif
+
+static int
+ahc_loadseq(struct ahc_softc *ahc)
+{
+	struct	cs cs_table[num_critical_sections];
+	u_int	begin_set[num_critical_sections];
+	u_int	end_set[num_critical_sections];
+	struct	patch *cur_patch;
+	u_int	cs_count;
+	u_int	cur_cs;
+	u_int	i;
+	u_int	skip_addr;
+	u_int	sg_prefetch_cnt;
+	int	downloaded;
+	uint8_t	download_consts[7];
+
+	/*
+	 * Start out with 0 critical sections
+	 * that apply to this firmware load.
+	 */
+	cs_count = 0;
+	cur_cs = 0;
+	memset(begin_set, 0, sizeof(begin_set));
+	memset(end_set, 0, sizeof(end_set));
+
+	/* Setup downloadable constant table */
+	download_consts[QOUTFIFO_OFFSET] = 0;
+	if (ahc->targetcmds != NULL)
+		download_consts[QOUTFIFO_OFFSET] += 32;
+	download_consts[QINFIFO_OFFSET] = download_consts[QOUTFIFO_OFFSET] + 1;
+	download_consts[CACHESIZE_MASK] = ahc->pci_cachesize - 1;
+	download_consts[INVERTED_CACHESIZE_MASK] = ~(ahc->pci_cachesize - 1);
+	sg_prefetch_cnt = ahc->pci_cachesize;
+	if (sg_prefetch_cnt < (2 * sizeof(struct ahc_dma_seg)))
+		sg_prefetch_cnt = 2 * sizeof(struct ahc_dma_seg);
+	download_consts[SG_PREFETCH_CNT] = sg_prefetch_cnt;
+	download_consts[SG_PREFETCH_ALIGN_MASK] = ~(sg_prefetch_cnt - 1);
+	download_consts[SG_PREFETCH_ADDR_MASK] = (sg_prefetch_cnt - 1);
+
+	cur_patch = patches;
+	downloaded = 0;
+	skip_addr = 0;
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE|LOADRAM);
+	ahc_outb(ahc, SEQADDR0, 0);
+	ahc_outb(ahc, SEQADDR1, 0);
+
+	for (i = 0; i < sizeof(seqprog)/4; i++) {
+		if (ahc_check_patch(ahc, &cur_patch, i, &skip_addr) == 0) {
+			/*
+			 * Don't download this instruction as it
+			 * is in a patch that was removed.
+			 */
+			continue;
+		}
+
+		if (downloaded == ahc->instruction_ram_size) {
+			/*
+			 * We're about to exceed the instruction
+			 * storage capacity for this chip.  Fail
+			 * the load.
+			 */
+			printf("\n%s: Program too large for instruction memory "
+			       "size of %d!\n", ahc_name(ahc),
+			       ahc->instruction_ram_size);
+			return (ENOMEM);
+		}
+
+		/*
+		 * Move through the CS table until we find a CS
+		 * that might apply to this instruction.
+		 */
+		for (; cur_cs < num_critical_sections; cur_cs++) {
+			if (critical_sections[cur_cs].end <= i) {
+				if (begin_set[cs_count] == TRUE
+				 && end_set[cs_count] == FALSE) {
+					cs_table[cs_count].end = downloaded;
+				 	end_set[cs_count] = TRUE;
+					cs_count++;
+				}
+				continue;
+			}
+			if (critical_sections[cur_cs].begin <= i
+			 && begin_set[cs_count] == FALSE) {
+				cs_table[cs_count].begin = downloaded;
+				begin_set[cs_count] = TRUE;
+			}
+			break;
+		}
+		ahc_download_instr(ahc, i, download_consts);
+		downloaded++;
+	}
+
+	ahc->num_critical_sections = cs_count;
+	if (cs_count != 0) {
+
+		cs_count *= sizeof(struct cs);
+		ahc->critical_sections = malloc(cs_count, M_DEVBUF, M_NOWAIT);
+		if (ahc->critical_sections == NULL)
+			panic("ahc_loadseq: Could not malloc");
+		memcpy(ahc->critical_sections, cs_table, cs_count);
+	}
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS|FASTMODE);
+
+	if (bootverbose) {
+		printf(" %d instructions downloaded\n", downloaded);
+		printf("%s: Features 0x%x, Bugs 0x%x, Flags 0x%x\n",
+		       ahc_name(ahc), ahc->features, ahc->bugs, ahc->flags);
+	}
+	return (0);
+}
+
+static int
+ahc_check_patch(struct ahc_softc *ahc, struct patch **start_patch,
+		u_int start_instr, u_int *skip_addr)
+{
+	struct	patch *cur_patch;
+	struct	patch *last_patch;
+	u_int	num_patches;
+
+	num_patches = sizeof(patches)/sizeof(struct patch);
+	last_patch = &patches[num_patches];
+	cur_patch = *start_patch;
+
+	while (cur_patch < last_patch && start_instr == cur_patch->begin) {
+
+		if (cur_patch->patch_func(ahc) == 0) {
+
+			/* Start rejecting code */
+			*skip_addr = start_instr + cur_patch->skip_instr;
+			cur_patch += cur_patch->skip_patch;
+		} else {
+			/* Accepted this patch.  Advance to the next
+			 * one and wait for our intruction pointer to
+			 * hit this point.
+			 */
+			cur_patch++;
+		}
+	}
+
+	*start_patch = cur_patch;
+	if (start_instr < *skip_addr)
+		/* Still skipping */
+		return (0);
+
+	return (1);
+}
+
+static void
+ahc_download_instr(struct ahc_softc *ahc, u_int instrptr, uint8_t *dconsts)
+{
+	union	ins_formats instr;
+	struct	ins_format1 *fmt1_ins;
+	struct	ins_format3 *fmt3_ins;
+	u_int	opcode;
+
+	/*
+	 * The firmware is always compiled into a little endian format.
+	 */
+	instr.integer = ahc_le32toh(*(uint32_t*)&seqprog[instrptr * 4]);
+
+	fmt1_ins = &instr.format1;
+	fmt3_ins = NULL;
+
+	/* Pull the opcode */
+	opcode = instr.format1.opcode;
+	switch (opcode) {
+	case AIC_OP_JMP:
+	case AIC_OP_JC:
+	case AIC_OP_JNC:
+	case AIC_OP_CALL:
+	case AIC_OP_JNE:
+	case AIC_OP_JNZ:
+	case AIC_OP_JE:
+	case AIC_OP_JZ:
+	{
+		struct patch *cur_patch;
+		int address_offset;
+		u_int address;
+		u_int skip_addr;
+		u_int i;
+
+		fmt3_ins = &instr.format3;
+		address_offset = 0;
+		address = fmt3_ins->address;
+		cur_patch = patches;
+		skip_addr = 0;
+
+		for (i = 0; i < address;) {
+
+			ahc_check_patch(ahc, &cur_patch, i, &skip_addr);
+
+			if (skip_addr > i) {
+				int end_addr;
+
+				end_addr = MIN(address, skip_addr);
+				address_offset += end_addr - i;
+				i = skip_addr;
+			} else {
+				i++;
+			}
+		}
+		address -= address_offset;
+		fmt3_ins->address = address;
+		/* FALLTHROUGH */
+	}
+	case AIC_OP_OR:
+	case AIC_OP_AND:
+	case AIC_OP_XOR:
+	case AIC_OP_ADD:
+	case AIC_OP_ADC:
+	case AIC_OP_BMOV:
+		if (fmt1_ins->parity != 0) {
+			fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+		}
+		fmt1_ins->parity = 0;
+		if ((ahc->features & AHC_CMD_CHAN) == 0
+		 && opcode == AIC_OP_BMOV) {
+			/*
+			 * Block move was added at the same time
+			 * as the command channel.  Verify that
+			 * this is only a move of a single element
+			 * and convert the BMOV to a MOV
+			 * (AND with an immediate of FF).
+			 */
+			if (fmt1_ins->immediate != 1)
+				panic("%s: BMOV not supported\n",
+				      ahc_name(ahc));
+			fmt1_ins->opcode = AIC_OP_AND;
+			fmt1_ins->immediate = 0xff;
+		}
+		/* FALLTHROUGH */
+	case AIC_OP_ROL:
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			int i, count;
+
+			/* Calculate odd parity for the instruction */
+			for (i = 0, count = 0; i < 31; i++) {
+				uint32_t mask;
+
+				mask = 0x01 << i;
+				if ((instr.integer & mask) != 0)
+					count++;
+			}
+			if ((count & 0x01) == 0)
+				instr.format1.parity = 1;
+		} else {
+			/* Compress the instruction for older sequencers */
+			if (fmt3_ins != NULL) {
+				instr.integer =
+					fmt3_ins->immediate
+				      | (fmt3_ins->source << 8)
+				      | (fmt3_ins->address << 16)
+				      |	(fmt3_ins->opcode << 25);
+			} else {
+				instr.integer =
+					fmt1_ins->immediate
+				      | (fmt1_ins->source << 8)
+				      | (fmt1_ins->destination << 16)
+				      |	(fmt1_ins->ret << 24)
+				      |	(fmt1_ins->opcode << 25);
+			}
+		}
+		/* The sequencer is a little endian cpu */
+		instr.integer = ahc_htole32(instr.integer);
+		ahc_outsb(ahc, SEQRAM, instr.bytes, 4);
+		break;
+	default:
+		panic("Unknown opcode encountered in seq program");
+		break;
+	}
+}
+
+int
+ahc_print_register(ahc_reg_parse_entry_t *table, u_int num_entries,
+		   const char *name, u_int address, u_int value,
+		   u_int *cur_column, u_int wrap_point)
+{
+	int	printed;
+	u_int	printed_mask;
+
+	if (cur_column != NULL && *cur_column >= wrap_point) {
+		printf("\n");
+		*cur_column = 0;
+	}
+	printed = printf("%s[0x%x]", name, value);
+	if (table == NULL) {
+		printed += printf(" ");
+		*cur_column += printed;
+		return (printed);
+	}
+	printed_mask = 0;
+	while (printed_mask != 0xFF) {
+		int entry;
+
+		for (entry = 0; entry < num_entries; entry++) {
+			if (((value & table[entry].mask)
+			  != table[entry].value)
+			 || ((printed_mask & table[entry].mask)
+			  == table[entry].mask))
+				continue;
+
+			printed += printf("%s%s",
+					  printed_mask == 0 ? ":(" : "|",
+					  table[entry].name);
+			printed_mask |= table[entry].mask;
+			
+			break;
+		}
+		if (entry >= num_entries)
+			break;
+	}
+	if (printed_mask != 0)
+		printed += printf(") ");
+	else
+		printed += printf(" ");
+	if (cur_column != NULL)
+		*cur_column += printed;
+	return (printed);
+}
+
+void
+ahc_dump_card_state(struct ahc_softc *ahc)
+{
+	struct	scb *scb;
+	struct	scb_tailq *untagged_q;
+	u_int	cur_col;
+	int	paused;
+	int	target;
+	int	maxtarget;
+	int	i;
+	uint8_t last_phase;
+	uint8_t qinpos;
+	uint8_t qintail;
+	uint8_t qoutpos;
+	uint8_t scb_index;
+	uint8_t saved_scbptr;
+
+	if (ahc_is_paused(ahc)) {
+		paused = 1;
+	} else {
+		paused = 0;
+		ahc_pause(ahc);
+	}
+
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+	last_phase = ahc_inb(ahc, LASTPHASE);
+	printf(">>>>>>>>>>>>>>>>>> Dump Card State Begins <<<<<<<<<<<<<<<<<\n"
+	       "%s: Dumping Card State %s, at SEQADDR 0x%x\n",
+	       ahc_name(ahc), ahc_lookup_phase_entry(last_phase)->phasemsg,
+	       ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+	if (paused)
+		printf("Card was paused\n");
+	printf("ACCUM = 0x%x, SINDEX = 0x%x, DINDEX = 0x%x, ARG_2 = 0x%x\n",
+	       ahc_inb(ahc, ACCUM), ahc_inb(ahc, SINDEX), ahc_inb(ahc, DINDEX),
+	       ahc_inb(ahc, ARG_2));
+	printf("HCNT = 0x%x SCBPTR = 0x%x\n", ahc_inb(ahc, HCNT),
+	       ahc_inb(ahc, SCBPTR));
+	cur_col = 0;
+	if ((ahc->features & AHC_DT) != 0)
+		ahc_scsiphase_print(ahc_inb(ahc, SCSIPHASE), &cur_col, 50);
+	ahc_scsisigi_print(ahc_inb(ahc, SCSISIGI), &cur_col, 50);
+	ahc_error_print(ahc_inb(ahc, ERROR), &cur_col, 50);
+	ahc_scsibusl_print(ahc_inb(ahc, SCSIBUSL), &cur_col, 50);
+	ahc_lastphase_print(ahc_inb(ahc, LASTPHASE), &cur_col, 50);
+	ahc_scsiseq_print(ahc_inb(ahc, SCSISEQ), &cur_col, 50);
+	ahc_sblkctl_print(ahc_inb(ahc, SBLKCTL), &cur_col, 50);
+	ahc_scsirate_print(ahc_inb(ahc, SCSIRATE), &cur_col, 50);
+	ahc_seqctl_print(ahc_inb(ahc, SEQCTL), &cur_col, 50);
+	ahc_seq_flags_print(ahc_inb(ahc, SEQ_FLAGS), &cur_col, 50);
+	ahc_sstat0_print(ahc_inb(ahc, SSTAT0), &cur_col, 50);
+	ahc_sstat1_print(ahc_inb(ahc, SSTAT1), &cur_col, 50);
+	ahc_sstat2_print(ahc_inb(ahc, SSTAT2), &cur_col, 50);
+	ahc_sstat3_print(ahc_inb(ahc, SSTAT3), &cur_col, 50);
+	ahc_simode0_print(ahc_inb(ahc, SIMODE0), &cur_col, 50);
+	ahc_simode1_print(ahc_inb(ahc, SIMODE1), &cur_col, 50);
+	ahc_sxfrctl0_print(ahc_inb(ahc, SXFRCTL0), &cur_col, 50);
+	ahc_dfcntrl_print(ahc_inb(ahc, DFCNTRL), &cur_col, 50);
+	ahc_dfstatus_print(ahc_inb(ahc, DFSTATUS), &cur_col, 50);
+	if (cur_col != 0)
+		printf("\n");
+	printf("STACK:");
+	for (i = 0; i < STACK_SIZE; i++)
+	       printf(" 0x%x", ahc_inb(ahc, STACK)|(ahc_inb(ahc, STACK) << 8));
+	printf("\nSCB count = %d\n", ahc->scb_data->numscbs);
+	printf("Kernel NEXTQSCB = %d\n", ahc->next_queued_scb->hscb->tag);
+	printf("Card NEXTQSCB = %d\n", ahc_inb(ahc, NEXT_QUEUED_SCB));
+	/* QINFIFO */
+	printf("QINFIFO entries: ");
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		qinpos = ahc_inb(ahc, SNSCB_QOFF);
+		ahc_outb(ahc, SNSCB_QOFF, qinpos);
+	} else
+		qinpos = ahc_inb(ahc, QINPOS);
+	qintail = ahc->qinfifonext;
+	while (qinpos != qintail) {
+		printf("%d ", ahc->qinfifo[qinpos]);
+		qinpos++;
+	}
+	printf("\n");
+
+	printf("Waiting Queue entries: ");
+	scb_index = ahc_inb(ahc, WAITING_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+
+	printf("Disconnected Queue entries: ");
+	scb_index = ahc_inb(ahc, DISCONNECTED_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d:%d ", scb_index, ahc_inb(ahc, SCB_TAG));
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+		
+	ahc_sync_qoutfifo(ahc, BUS_DMASYNC_POSTREAD);
+	printf("QOUTFIFO entries: ");
+	qoutpos = ahc->qoutfifonext;
+	i = 0;
+	while (ahc->qoutfifo[qoutpos] != SCB_LIST_NULL && i++ < 256) {
+		printf("%d ", ahc->qoutfifo[qoutpos]);
+		qoutpos++;
+	}
+	printf("\n");
+
+	printf("Sequencer Free SCB List: ");
+	scb_index = ahc_inb(ahc, FREE_SCBH);
+	i = 0;
+	while (scb_index != SCB_LIST_NULL && i++ < 256) {
+		ahc_outb(ahc, SCBPTR, scb_index);
+		printf("%d ", scb_index);
+		scb_index = ahc_inb(ahc, SCB_NEXT);
+	}
+	printf("\n");
+
+	printf("Sequencer SCB Info: ");
+	for (i = 0; i < ahc->scb_data->maxhscbs; i++) {
+		ahc_outb(ahc, SCBPTR, i);
+		cur_col = printf("\n%3d ", i);
+
+		ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL), &cur_col, 60);
+		ahc_scb_scsiid_print(ahc_inb(ahc, SCB_SCSIID), &cur_col, 60);
+		ahc_scb_lun_print(ahc_inb(ahc, SCB_LUN), &cur_col, 60);
+		ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
+	}
+	printf("\n");
+
+	printf("Pending list: ");
+	i = 0;
+	LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
+		if (i++ > 256)
+			break;
+		cur_col = printf("\n%3d ", scb->hscb->tag);
+		ahc_scb_control_print(scb->hscb->control, &cur_col, 60);
+		ahc_scb_scsiid_print(scb->hscb->scsiid, &cur_col, 60);
+		ahc_scb_lun_print(scb->hscb->lun, &cur_col, 60);
+		if ((ahc->flags & AHC_PAGESCBS) == 0) {
+			ahc_outb(ahc, SCBPTR, scb->hscb->tag);
+			printf("(");
+			ahc_scb_control_print(ahc_inb(ahc, SCB_CONTROL),
+					      &cur_col, 60);
+			ahc_scb_tag_print(ahc_inb(ahc, SCB_TAG), &cur_col, 60);
+			printf(")");
+		}
+	}
+	printf("\n");
+
+	printf("Kernel Free SCB list: ");
+	i = 0;
+	SLIST_FOREACH(scb, &ahc->scb_data->free_scbs, links.sle) {
+		if (i++ > 256)
+			break;
+		printf("%d ", scb->hscb->tag);
+	}
+	printf("\n");
+
+	maxtarget = (ahc->features & (AHC_WIDE|AHC_TWIN)) ? 15 : 7;
+	for (target = 0; target <= maxtarget; target++) {
+		untagged_q = &ahc->untagged_queues[target];
+		if (TAILQ_FIRST(untagged_q) == NULL)
+			continue;
+		printf("Untagged Q(%d): ", target);
+		i = 0;
+		TAILQ_FOREACH(scb, untagged_q, links.tqe) {
+			if (i++ > 256)
+				break;
+			printf("%d ", scb->hscb->tag);
+		}
+		printf("\n");
+	}
+
+	ahc_platform_dump_card_state(ahc);
+	printf("\n<<<<<<<<<<<<<<<<< Dump Card State Ends >>>>>>>>>>>>>>>>>>\n");
+	ahc_outb(ahc, SCBPTR, saved_scbptr);
+	if (paused == 0)
+		ahc_unpause(ahc);
+}
+
+/************************* Target Mode ****************************************/
+#ifdef AHC_TARGET_MODE
+cam_status
+ahc_find_tmode_devs(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb,
+		    struct ahc_tmode_tstate **tstate,
+		    struct ahc_tmode_lstate **lstate,
+		    int notfound_failure)
+{
+
+	if ((ahc->features & AHC_TARGETMODE) == 0)
+		return (CAM_REQ_INVALID);
+
+	/*
+	 * Handle the 'black hole' device that sucks up
+	 * requests to unattached luns on enabled targets.
+	 */
+	if (ccb->ccb_h.target_id == CAM_TARGET_WILDCARD
+	 && ccb->ccb_h.target_lun == CAM_LUN_WILDCARD) {
+		*tstate = NULL;
+		*lstate = ahc->black_hole;
+	} else {
+		u_int max_id;
+
+		max_id = (ahc->features & AHC_WIDE) ? 15 : 7;
+		if (ccb->ccb_h.target_id > max_id)
+			return (CAM_TID_INVALID);
+
+		if (ccb->ccb_h.target_lun >= AHC_NUM_LUNS)
+			return (CAM_LUN_INVALID);
+
+		*tstate = ahc->enabled_targets[ccb->ccb_h.target_id];
+		*lstate = NULL;
+		if (*tstate != NULL)
+			*lstate =
+			    (*tstate)->enabled_luns[ccb->ccb_h.target_lun];
+	}
+
+	if (notfound_failure != 0 && *lstate == NULL)
+		return (CAM_PATH_INVALID);
+
+	return (CAM_REQ_CMP);
+}
+
+void
+ahc_handle_en_lun(struct ahc_softc *ahc, struct cam_sim *sim, union ccb *ccb)
+{
+	struct	   ahc_tmode_tstate *tstate;
+	struct	   ahc_tmode_lstate *lstate;
+	struct	   ccb_en_lun *cel;
+	cam_status status;
+	u_long	   s;
+	u_int	   target;
+	u_int	   lun;
+	u_int	   target_mask;
+	u_int	   our_id;
+	int	   error;
+	char	   channel;
+
+	status = ahc_find_tmode_devs(ahc, sim, ccb, &tstate, &lstate,
+				     /*notfound_failure*/FALSE);
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	if (cam_sim_bus(sim) == 0)
+		our_id = ahc->our_id;
+	else
+		our_id = ahc->our_id_b;
+
+	if (ccb->ccb_h.target_id != our_id) {
+		/*
+		 * our_id represents our initiator ID, or
+		 * the ID of the first target to have an
+		 * enabled lun in target mode.  There are
+		 * two cases that may preclude enabling a
+		 * target id other than our_id.
+		 *
+		 *   o our_id is for an active initiator role.
+		 *     Since the hardware does not support
+		 *     reselections to the initiator role at
+		 *     anything other than our_id, and our_id
+		 *     is used by the hardware to indicate the
+		 *     ID to use for both select-out and
+		 *     reselect-out operations, the only target
+		 *     ID we can support in this mode is our_id.
+		 *
+		 *   o The MULTARGID feature is not available and
+		 *     a previous target mode ID has been enabled.
+		 */
+		if ((ahc->features & AHC_MULTIROLE) != 0) {
+
+			if ((ahc->features & AHC_MULTI_TID) != 0
+		   	 && (ahc->flags & AHC_INITIATORROLE) != 0) {
+				/*
+				 * Only allow additional targets if
+				 * the initiator role is disabled.
+				 * The hardware cannot handle a re-select-in
+				 * on the initiator id during a re-select-out
+				 * on a different target id.
+				 */
+				status = CAM_TID_INVALID;
+			} else if ((ahc->flags & AHC_INITIATORROLE) != 0
+				|| ahc->enabled_luns > 0) {
+				/*
+				 * Only allow our target id to change
+				 * if the initiator role is not configured
+				 * and there are no enabled luns which
+				 * are attached to the currently registered
+				 * scsi id.
+				 */
+				status = CAM_TID_INVALID;
+			}
+		} else if ((ahc->features & AHC_MULTI_TID) == 0
+			&& ahc->enabled_luns > 0) {
+
+			status = CAM_TID_INVALID;
+		}
+	}
+
+	if (status != CAM_REQ_CMP) {
+		ccb->ccb_h.status = status;
+		return;
+	}
+
+	/*
+	 * We now have an id that is valid.
+	 * If we aren't in target mode, switch modes.
+	 */
+	if ((ahc->flags & AHC_TARGETROLE) == 0
+	 && ccb->ccb_h.target_id != CAM_TARGET_WILDCARD) {
+		u_long	 s;
+		ahc_flag saved_flags;
+
+		printf("Configuring Target Mode\n");
+		ahc_lock(ahc, &s);
+		if (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+			ccb->ccb_h.status = CAM_BUSY;
+			ahc_unlock(ahc, &s);
+			return;
+		}
+		saved_flags = ahc->flags;
+		ahc->flags |= AHC_TARGETROLE;
+		if ((ahc->features & AHC_MULTIROLE) == 0)
+			ahc->flags &= ~AHC_INITIATORROLE;
+		ahc_pause(ahc);
+		error = ahc_loadseq(ahc);
+		if (error != 0) {
+			/*
+			 * Restore original configuration and notify
+			 * the caller that we cannot support target mode.
+			 * Since the adapter started out in this
+			 * configuration, the firmware load will succeed,
+			 * so there is no point in checking ahc_loadseq's
+			 * return value.
+			 */
+			ahc->flags = saved_flags;
+			(void)ahc_loadseq(ahc);
+			ahc_restart(ahc);
+			ahc_unlock(ahc, &s);
+			ccb->ccb_h.status = CAM_FUNC_NOTAVAIL;
+			return;
+		}
+		ahc_restart(ahc);
+		ahc_unlock(ahc, &s);
+	}
+	cel = &ccb->cel;
+	target = ccb->ccb_h.target_id;
+	lun = ccb->ccb_h.target_lun;
+	channel = SIM_CHANNEL(ahc, sim);
+	target_mask = 0x01 << target;
+	if (channel == 'B')
+		target_mask <<= 8;
+
+	if (cel->enable != 0) {
+		u_int scsiseq;
+
+		/* Are we already enabled?? */
+		if (lstate != NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Lun already enabled\n");
+			ccb->ccb_h.status = CAM_LUN_ALRDY_ENA;
+			return;
+		}
+
+		if (cel->grp6_len != 0
+		 || cel->grp7_len != 0) {
+			/*
+			 * Don't (yet?) support vendor
+			 * specific commands.
+			 */
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+			printf("Non-zero Group Codes\n");
+			return;
+		}
+
+		/*
+		 * Seems to be okay.
+		 * Setup our data structures.
+		 */
+		if (target != CAM_TARGET_WILDCARD && tstate == NULL) {
+			tstate = ahc_alloc_tstate(ahc, target, channel);
+			if (tstate == NULL) {
+				xpt_print_path(ccb->ccb_h.path);
+				printf("Couldn't allocate tstate\n");
+				ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+				return;
+			}
+		}
+		lstate = malloc(sizeof(*lstate), M_DEVBUF, M_NOWAIT);
+		if (lstate == NULL) {
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate lstate\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		memset(lstate, 0, sizeof(*lstate));
+		status = xpt_create_path(&lstate->path, /*periph*/NULL,
+					 xpt_path_path_id(ccb->ccb_h.path),
+					 xpt_path_target_id(ccb->ccb_h.path),
+					 xpt_path_lun_id(ccb->ccb_h.path));
+		if (status != CAM_REQ_CMP) {
+			free(lstate, M_DEVBUF);
+			xpt_print_path(ccb->ccb_h.path);
+			printf("Couldn't allocate path\n");
+			ccb->ccb_h.status = CAM_RESRC_UNAVAIL;
+			return;
+		}
+		SLIST_INIT(&lstate->accept_tios);
+		SLIST_INIT(&lstate->immed_notifies);
+		ahc_lock(ahc, &s);
+		ahc_pause(ahc);
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = lstate;
+			ahc->enabled_luns++;
+
+			if ((ahc->features & AHC_MULTI_TID) != 0) {
+				u_int targid_mask;
+
+				targid_mask = ahc_inb(ahc, TARGID)
+					    | (ahc_inb(ahc, TARGID + 1) << 8);
+
+				targid_mask |= target_mask;
+				ahc_outb(ahc, TARGID, targid_mask);
+				ahc_outb(ahc, TARGID+1, (targid_mask >> 8));
+				
+				ahc_update_scsiid(ahc, targid_mask);
+			} else {
+				u_int our_id;
+				char  channel;
+
+				channel = SIM_CHANNEL(ahc, sim);
+				our_id = SIM_SCSI_ID(ahc, sim);
+
+				/*
+				 * This can only happen if selections
+				 * are not enabled
+				 */
+				if (target != our_id) {
+					u_int sblkctl;
+					char  cur_channel;
+					int   swap;
+
+					sblkctl = ahc_inb(ahc, SBLKCTL);
+					cur_channel = (sblkctl & SELBUSB)
+						    ? 'B' : 'A';
+					if ((ahc->features & AHC_TWIN) == 0)
+						cur_channel = 'A';
+					swap = cur_channel != channel;
+					if (channel == 'A')
+						ahc->our_id = target;
+					else
+						ahc->our_id_b = target;
+
+					if (swap)
+						ahc_outb(ahc, SBLKCTL,
+							 sblkctl ^ SELBUSB);
+
+					ahc_outb(ahc, SCSIID, target);
+
+					if (swap)
+						ahc_outb(ahc, SBLKCTL, sblkctl);
+				}
+			}
+		} else
+			ahc->black_hole = lstate;
+		/* Allow select-in operations */
+		if (ahc->black_hole != NULL && ahc->enabled_luns > 0) {
+			scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
+			scsiseq |= ENSELI;
+			ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
+			scsiseq = ahc_inb(ahc, SCSISEQ);
+			scsiseq |= ENSELI;
+			ahc_outb(ahc, SCSISEQ, scsiseq);
+		}
+		ahc_unpause(ahc);
+		ahc_unlock(ahc, &s);
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Lun now enabled for target mode\n");
+	} else {
+		struct scb *scb;
+		int i, empty;
+
+		if (lstate == NULL) {
+			ccb->ccb_h.status = CAM_LUN_INVALID;
+			return;
+		}
+
+		ahc_lock(ahc, &s);
+		
+		ccb->ccb_h.status = CAM_REQ_CMP;
+		LIST_FOREACH(scb, &ahc->pending_scbs, pending_links) {
+			struct ccb_hdr *ccbh;
+
+			ccbh = &scb->io_ctx->ccb_h;
+			if (ccbh->func_code == XPT_CONT_TARGET_IO
+			 && !xpt_path_comp(ccbh->path, ccb->ccb_h.path)){
+				printf("CTIO pending\n");
+				ccb->ccb_h.status = CAM_REQ_INVALID;
+				ahc_unlock(ahc, &s);
+				return;
+			}
+		}
+
+		if (SLIST_FIRST(&lstate->accept_tios) != NULL) {
+			printf("ATIOs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (SLIST_FIRST(&lstate->immed_notifies) != NULL) {
+			printf("INOTs pending\n");
+			ccb->ccb_h.status = CAM_REQ_INVALID;
+		}
+
+		if (ccb->ccb_h.status != CAM_REQ_CMP) {
+			ahc_unlock(ahc, &s);
+			return;
+		}
+
+		xpt_print_path(ccb->ccb_h.path);
+		printf("Target mode disabled\n");
+		xpt_free_path(lstate->path);
+		free(lstate, M_DEVBUF);
+
+		ahc_pause(ahc);
+		/* Can we clean up the target too? */
+		if (target != CAM_TARGET_WILDCARD) {
+			tstate->enabled_luns[lun] = NULL;
+			ahc->enabled_luns--;
+			for (empty = 1, i = 0; i < 8; i++)
+				if (tstate->enabled_luns[i] != NULL) {
+					empty = 0;
+					break;
+				}
+
+			if (empty) {
+				ahc_free_tstate(ahc, target, channel,
+						/*force*/FALSE);
+				if (ahc->features & AHC_MULTI_TID) {
+					u_int targid_mask;
+
+					targid_mask = ahc_inb(ahc, TARGID)
+						    | (ahc_inb(ahc, TARGID + 1)
+						       << 8);
+
+					targid_mask &= ~target_mask;
+					ahc_outb(ahc, TARGID, targid_mask);
+					ahc_outb(ahc, TARGID+1,
+					 	 (targid_mask >> 8));
+					ahc_update_scsiid(ahc, targid_mask);
+				}
+			}
+		} else {
+
+			ahc->black_hole = NULL;
+
+			/*
+			 * We can't allow selections without
+			 * our black hole device.
+			 */
+			empty = TRUE;
+		}
+		if (ahc->enabled_luns == 0) {
+			/* Disallow select-in */
+			u_int scsiseq;
+
+			scsiseq = ahc_inb(ahc, SCSISEQ_TEMPLATE);
+			scsiseq &= ~ENSELI;
+			ahc_outb(ahc, SCSISEQ_TEMPLATE, scsiseq);
+			scsiseq = ahc_inb(ahc, SCSISEQ);
+			scsiseq &= ~ENSELI;
+			ahc_outb(ahc, SCSISEQ, scsiseq);
+
+			if ((ahc->features & AHC_MULTIROLE) == 0) {
+				printf("Configuring Initiator Mode\n");
+				ahc->flags &= ~AHC_TARGETROLE;
+				ahc->flags |= AHC_INITIATORROLE;
+				/*
+				 * Returning to a configuration that
+				 * fit previously will always succeed.
+				 */
+				(void)ahc_loadseq(ahc);
+				ahc_restart(ahc);
+				/*
+				 * Unpaused.  The extra unpause
+				 * that follows is harmless.
+				 */
+			}
+		}
+		ahc_unpause(ahc);
+		ahc_unlock(ahc, &s);
+	}
+}
+
+static void
+ahc_update_scsiid(struct ahc_softc *ahc, u_int targid_mask)
+{
+	u_int scsiid_mask;
+	u_int scsiid;
+
+	if ((ahc->features & AHC_MULTI_TID) == 0)
+		panic("ahc_update_scsiid called on non-multitid unit\n");
+
+	/*
+	 * Since we will rely on the TARGID mask
+	 * for selection enables, ensure that OID
+	 * in SCSIID is not set to some other ID
+	 * that we don't want to allow selections on.
+	 */
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		scsiid = ahc_inb(ahc, SCSIID_ULTRA2);
+	else
+		scsiid = ahc_inb(ahc, SCSIID);
+	scsiid_mask = 0x1 << (scsiid & OID);
+	if ((targid_mask & scsiid_mask) == 0) {
+		u_int our_id;
+
+		/* ffs counts from 1 */
+		our_id = ffs(targid_mask);
+		if (our_id == 0)
+			our_id = ahc->our_id;
+		else
+			our_id--;
+		scsiid &= TID;
+		scsiid |= our_id;
+	}
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, SCSIID_ULTRA2, scsiid);
+	else
+		ahc_outb(ahc, SCSIID, scsiid);
+}
+
+void
+ahc_run_tqinfifo(struct ahc_softc *ahc, int paused)
+{
+	struct target_cmd *cmd;
+
+	/*
+	 * If the card supports auto-access pause,
+	 * we can access the card directly regardless
+	 * of whether it is paused or not.
+	 */
+	if ((ahc->features & AHC_AUTOPAUSE) != 0)
+		paused = TRUE;
+
+	ahc_sync_tqinfifo(ahc, BUS_DMASYNC_POSTREAD);
+	while ((cmd = &ahc->targetcmds[ahc->tqinfifonext])->cmd_valid != 0) {
+
+		/*
+		 * Only advance through the queue if we
+		 * have the resources to process the command.
+		 */
+		if (ahc_handle_target_cmd(ahc, cmd) != 0)
+			break;
+
+		cmd->cmd_valid = 0;
+		ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+				ahc->shared_data_dmamap,
+				ahc_targetcmd_offset(ahc, ahc->tqinfifonext),
+				sizeof(struct target_cmd),
+				BUS_DMASYNC_PREREAD);
+		ahc->tqinfifonext++;
+
+		/*
+		 * Lazily update our position in the target mode incoming
+		 * command queue as seen by the sequencer.
+		 */
+		if ((ahc->tqinfifonext & (HOST_TQINPOS - 1)) == 1) {
+			if ((ahc->features & AHC_HS_MAILBOX) != 0) {
+				u_int hs_mailbox;
+
+				hs_mailbox = ahc_inb(ahc, HS_MAILBOX);
+				hs_mailbox &= ~HOST_TQINPOS;
+				hs_mailbox |= ahc->tqinfifonext & HOST_TQINPOS;
+				ahc_outb(ahc, HS_MAILBOX, hs_mailbox);
+			} else {
+				if (!paused)
+					ahc_pause(ahc);	
+				ahc_outb(ahc, KERNEL_TQINPOS,
+					 ahc->tqinfifonext & HOST_TQINPOS);
+				if (!paused)
+					ahc_unpause(ahc);
+			}
+		}
+	}
+}
+
+static int
+ahc_handle_target_cmd(struct ahc_softc *ahc, struct target_cmd *cmd)
+{
+	struct	  ahc_tmode_tstate *tstate;
+	struct	  ahc_tmode_lstate *lstate;
+	struct	  ccb_accept_tio *atio;
+	uint8_t *byte;
+	int	  initiator;
+	int	  target;
+	int	  lun;
+
+	initiator = SCSIID_TARGET(ahc, cmd->scsiid);
+	target = SCSIID_OUR_ID(cmd->scsiid);
+	lun    = (cmd->identify & MSG_IDENTIFY_LUNMASK);
+
+	byte = cmd->bytes;
+	tstate = ahc->enabled_targets[target];
+	lstate = NULL;
+	if (tstate != NULL)
+		lstate = tstate->enabled_luns[lun];
+
+	/*
+	 * Commands for disabled luns go to the black hole driver.
+	 */
+	if (lstate == NULL)
+		lstate = ahc->black_hole;
+
+	atio = (struct ccb_accept_tio*)SLIST_FIRST(&lstate->accept_tios);
+	if (atio == NULL) {
+		ahc->flags |= AHC_TQINFIFO_BLOCKED;
+		/*
+		 * Wait for more ATIOs from the peripheral driver for this lun.
+		 */
+		if (bootverbose)
+			printf("%s: ATIOs exhausted\n", ahc_name(ahc));
+		return (1);
+	} else
+		ahc->flags &= ~AHC_TQINFIFO_BLOCKED;
+#if 0
+	printf("Incoming command from %d for %d:%d%s\n",
+	       initiator, target, lun,
+	       lstate == ahc->black_hole ? "(Black Holed)" : "");
+#endif
+	SLIST_REMOVE_HEAD(&lstate->accept_tios, sim_links.sle);
+
+	if (lstate == ahc->black_hole) {
+		/* Fill in the wildcards */
+		atio->ccb_h.target_id = target;
+		atio->ccb_h.target_lun = lun;
+	}
+
+	/*
+	 * Package it up and send it off to
+	 * whomever has this lun enabled.
+	 */
+	atio->sense_len = 0;
+	atio->init_id = initiator;
+	if (byte[0] != 0xFF) {
+		/* Tag was included */
+		atio->tag_action = *byte++;
+		atio->tag_id = *byte++;
+		atio->ccb_h.flags = CAM_TAG_ACTION_VALID;
+	} else {
+		atio->ccb_h.flags = 0;
+	}
+	byte++;
+
+	/* Okay.  Now determine the cdb size based on the command code */
+	switch (*byte >> CMD_GROUP_CODE_SHIFT) {
+	case 0:
+		atio->cdb_len = 6;
+		break;
+	case 1:
+	case 2:
+		atio->cdb_len = 10;
+		break;
+	case 4:
+		atio->cdb_len = 16;
+		break;
+	case 5:
+		atio->cdb_len = 12;
+		break;
+	case 3:
+	default:
+		/* Only copy the opcode. */
+		atio->cdb_len = 1;
+		printf("Reserved or VU command code type encountered\n");
+		break;
+	}
+	
+	memcpy(atio->cdb_io.cdb_bytes, byte, atio->cdb_len);
+
+	atio->ccb_h.status |= CAM_CDB_RECVD;
+
+	if ((cmd->identify & MSG_IDENTIFY_DISCFLAG) == 0) {
+		/*
+		 * We weren't allowed to disconnect.
+		 * We're hanging on the bus until a
+		 * continue target I/O comes in response
+		 * to this accept tio.
+		 */
+#if 0
+		printf("Received Immediate Command %d:%d:%d - %p\n",
+		       initiator, target, lun, ahc->pending_device);
+#endif
+		ahc->pending_device = lstate;
+		ahc_freeze_ccb((union ccb *)atio);
+		atio->ccb_h.flags |= CAM_DIS_DISCONNECT;
+	}
+	xpt_done((union ccb*)atio);
+	return (0);
+}
+
+#endif
diff --git a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
new file mode 100644
index 0000000..2cc8a17
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h
@@ -0,0 +1,649 @@
+/*
+ * Inline routines shareable across OS platforms.
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _AIC7XXX_INLINE_H_
+#define _AIC7XXX_INLINE_H_
+
+/************************* Sequencer Execution Control ************************/
+static __inline void ahc_pause_bug_fix(struct ahc_softc *ahc);
+static __inline int  ahc_is_paused(struct ahc_softc *ahc);
+static __inline void ahc_pause(struct ahc_softc *ahc);
+static __inline void ahc_unpause(struct ahc_softc *ahc);
+
+/*
+ * Work around any chip bugs related to halting sequencer execution.
+ * On Ultra2 controllers, we must clear the CIOBUS stretch signal by
+ * reading a register that will set this signal and deassert it.
+ * Without this workaround, if the chip is paused, by an interrupt or
+ * manual pause while accessing scb ram, accesses to certain registers
+ * will hang the system (infinite pci retries).
+ */
+static __inline void
+ahc_pause_bug_fix(struct ahc_softc *ahc)
+{
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		(void)ahc_inb(ahc, CCSCBCTL);
+}
+
+/*
+ * Determine whether the sequencer has halted code execution.
+ * Returns non-zero status if the sequencer is stopped.
+ */
+static __inline int
+ahc_is_paused(struct ahc_softc *ahc)
+{
+	return ((ahc_inb(ahc, HCNTRL) & PAUSE) != 0);
+}
+
+/*
+ * Request that the sequencer stop and wait, indefinitely, for it
+ * to stop.  The sequencer will only acknowledge that it is paused
+ * once it has reached an instruction boundary and PAUSEDIS is
+ * cleared in the SEQCTL register.  The sequencer may use PAUSEDIS
+ * for critical sections.
+ */
+static __inline void
+ahc_pause(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, HCNTRL, ahc->pause);
+
+	/*
+	 * Since the sequencer can disable pausing in a critical section, we
+	 * must loop until it actually stops.
+	 */
+	while (ahc_is_paused(ahc) == 0)
+		;
+
+	ahc_pause_bug_fix(ahc);
+}
+
+/*
+ * Allow the sequencer to continue program execution.
+ * We check here to ensure that no additional interrupt
+ * sources that would cause the sequencer to halt have been
+ * asserted.  If, for example, a SCSI bus reset is detected
+ * while we are fielding a different, pausing, interrupt type,
+ * we don't want to release the sequencer before going back
+ * into our interrupt handler and dealing with this new
+ * condition.
+ */
+static __inline void
+ahc_unpause(struct ahc_softc *ahc)
+{
+	if ((ahc_inb(ahc, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0)
+		ahc_outb(ahc, HCNTRL, ahc->unpause);
+}
+
+/*********************** Untagged Transaction Routines ************************/
+static __inline void	ahc_freeze_untagged_queues(struct ahc_softc *ahc);
+static __inline void	ahc_release_untagged_queues(struct ahc_softc *ahc);
+
+/*
+ * Block our completion routine from starting the next untagged
+ * transaction for this target or target lun.
+ */
+static __inline void
+ahc_freeze_untagged_queues(struct ahc_softc *ahc)
+{
+	if ((ahc->flags & AHC_SCB_BTT) == 0)
+		ahc->untagged_queue_lock++;
+}
+
+/*
+ * Allow the next untagged transaction for this target or target lun
+ * to be executed.  We use a counting semaphore to allow the lock
+ * to be acquired recursively.  Once the count drops to zero, the
+ * transaction queues will be run.
+ */
+static __inline void
+ahc_release_untagged_queues(struct ahc_softc *ahc)
+{
+	if ((ahc->flags & AHC_SCB_BTT) == 0) {
+		ahc->untagged_queue_lock--;
+		if (ahc->untagged_queue_lock == 0)
+			ahc_run_untagged_queues(ahc);
+	}
+}
+
+/************************** Memory mapping routines ***************************/
+static __inline struct ahc_dma_seg *
+			ahc_sg_bus_to_virt(struct scb *scb,
+					   uint32_t sg_busaddr);
+static __inline uint32_t
+			ahc_sg_virt_to_bus(struct scb *scb,
+					   struct ahc_dma_seg *sg);
+static __inline uint32_t
+			ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index);
+static __inline void	ahc_sync_scb(struct ahc_softc *ahc,
+				     struct scb *scb, int op);
+static __inline void	ahc_sync_sglist(struct ahc_softc *ahc,
+					struct scb *scb, int op);
+static __inline uint32_t
+			ahc_targetcmd_offset(struct ahc_softc *ahc,
+					     u_int index);
+
+static __inline struct ahc_dma_seg *
+ahc_sg_bus_to_virt(struct scb *scb, uint32_t sg_busaddr)
+{
+	int sg_index;
+
+	sg_index = (sg_busaddr - scb->sg_list_phys)/sizeof(struct ahc_dma_seg);
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_index++;
+
+	return (&scb->sg_list[sg_index]);
+}
+
+static __inline uint32_t
+ahc_sg_virt_to_bus(struct scb *scb, struct ahc_dma_seg *sg)
+{
+	int sg_index;
+
+	/* sg_list_phys points to entry 1, not 0 */
+	sg_index = sg - &scb->sg_list[1];
+
+	return (scb->sg_list_phys + (sg_index * sizeof(*scb->sg_list)));
+}
+
+static __inline uint32_t
+ahc_hscb_busaddr(struct ahc_softc *ahc, u_int index)
+{
+	return (ahc->scb_data->hscb_busaddr
+		+ (sizeof(struct hardware_scb) * index));
+}
+
+static __inline void
+ahc_sync_scb(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+	ahc_dmamap_sync(ahc, ahc->scb_data->hscb_dmat,
+			ahc->scb_data->hscb_dmamap,
+			/*offset*/(scb->hscb - ahc->hscbs) * sizeof(*scb->hscb),
+			/*len*/sizeof(*scb->hscb), op);
+}
+
+static __inline void
+ahc_sync_sglist(struct ahc_softc *ahc, struct scb *scb, int op)
+{
+	if (scb->sg_count == 0)
+		return;
+
+	ahc_dmamap_sync(ahc, ahc->scb_data->sg_dmat, scb->sg_map->sg_dmamap,
+			/*offset*/(scb->sg_list - scb->sg_map->sg_vaddr)
+				* sizeof(struct ahc_dma_seg),
+			/*len*/sizeof(struct ahc_dma_seg) * scb->sg_count, op);
+}
+
+static __inline uint32_t
+ahc_targetcmd_offset(struct ahc_softc *ahc, u_int index)
+{
+	return (((uint8_t *)&ahc->targetcmds[index]) - ahc->qoutfifo);
+}
+
+/******************************** Debugging ***********************************/
+static __inline char *ahc_name(struct ahc_softc *ahc);
+
+static __inline char *
+ahc_name(struct ahc_softc *ahc)
+{
+	return (ahc->name);
+}
+
+/*********************** Miscelaneous Support Functions ***********************/
+
+static __inline void	ahc_update_residual(struct ahc_softc *ahc,
+					    struct scb *scb);
+static __inline struct ahc_initiator_tinfo *
+			ahc_fetch_transinfo(struct ahc_softc *ahc,
+					    char channel, u_int our_id,
+					    u_int remote_id,
+					    struct ahc_tmode_tstate **tstate);
+static __inline uint16_t
+			ahc_inw(struct ahc_softc *ahc, u_int port);
+static __inline void	ahc_outw(struct ahc_softc *ahc, u_int port,
+				 u_int value);
+static __inline uint32_t
+			ahc_inl(struct ahc_softc *ahc, u_int port);
+static __inline void	ahc_outl(struct ahc_softc *ahc, u_int port,
+				 uint32_t value);
+static __inline uint64_t
+			ahc_inq(struct ahc_softc *ahc, u_int port);
+static __inline void	ahc_outq(struct ahc_softc *ahc, u_int port,
+				 uint64_t value);
+static __inline struct scb*
+			ahc_get_scb(struct ahc_softc *ahc);
+static __inline void	ahc_free_scb(struct ahc_softc *ahc, struct scb *scb);
+static __inline void	ahc_swap_with_next_hscb(struct ahc_softc *ahc,
+						struct scb *scb);
+static __inline void	ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb);
+static __inline struct scsi_sense_data *
+			ahc_get_sense_buf(struct ahc_softc *ahc,
+					  struct scb *scb);
+static __inline uint32_t
+			ahc_get_sense_bufaddr(struct ahc_softc *ahc,
+					      struct scb *scb);
+
+/*
+ * Determine whether the sequencer reported a residual
+ * for this SCB/transaction.
+ */
+static __inline void
+ahc_update_residual(struct ahc_softc *ahc, struct scb *scb)
+{
+	uint32_t sgptr;
+
+	sgptr = ahc_le32toh(scb->hscb->sgptr);
+	if ((sgptr & SG_RESID_VALID) != 0)
+		ahc_calc_residual(ahc, scb);
+}
+
+/*
+ * Return pointers to the transfer negotiation information
+ * for the specified our_id/remote_id pair.
+ */
+static __inline struct ahc_initiator_tinfo *
+ahc_fetch_transinfo(struct ahc_softc *ahc, char channel, u_int our_id,
+		    u_int remote_id, struct ahc_tmode_tstate **tstate)
+{
+	/*
+	 * Transfer data structures are stored from the perspective
+	 * of the target role.  Since the parameters for a connection
+	 * in the initiator role to a given target are the same as
+	 * when the roles are reversed, we pretend we are the target.
+	 */
+	if (channel == 'B')
+		our_id += 8;
+	*tstate = ahc->enabled_targets[our_id];
+	return (&(*tstate)->transinfo[remote_id]);
+}
+
+static __inline uint16_t
+ahc_inw(struct ahc_softc *ahc, u_int port)
+{
+	return ((ahc_inb(ahc, port+1) << 8) | ahc_inb(ahc, port));
+}
+
+static __inline void
+ahc_outw(struct ahc_softc *ahc, u_int port, u_int value)
+{
+	ahc_outb(ahc, port, value & 0xFF);
+	ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+}
+
+static __inline uint32_t
+ahc_inl(struct ahc_softc *ahc, u_int port)
+{
+	return ((ahc_inb(ahc, port))
+	      | (ahc_inb(ahc, port+1) << 8)
+	      | (ahc_inb(ahc, port+2) << 16)
+	      | (ahc_inb(ahc, port+3) << 24));
+}
+
+static __inline void
+ahc_outl(struct ahc_softc *ahc, u_int port, uint32_t value)
+{
+	ahc_outb(ahc, port, (value) & 0xFF);
+	ahc_outb(ahc, port+1, ((value) >> 8) & 0xFF);
+	ahc_outb(ahc, port+2, ((value) >> 16) & 0xFF);
+	ahc_outb(ahc, port+3, ((value) >> 24) & 0xFF);
+}
+
+static __inline uint64_t
+ahc_inq(struct ahc_softc *ahc, u_int port)
+{
+	return ((ahc_inb(ahc, port))
+	      | (ahc_inb(ahc, port+1) << 8)
+	      | (ahc_inb(ahc, port+2) << 16)
+	      | (ahc_inb(ahc, port+3) << 24)
+	      | (((uint64_t)ahc_inb(ahc, port+4)) << 32)
+	      | (((uint64_t)ahc_inb(ahc, port+5)) << 40)
+	      | (((uint64_t)ahc_inb(ahc, port+6)) << 48)
+	      | (((uint64_t)ahc_inb(ahc, port+7)) << 56));
+}
+
+static __inline void
+ahc_outq(struct ahc_softc *ahc, u_int port, uint64_t value)
+{
+	ahc_outb(ahc, port, value & 0xFF);
+	ahc_outb(ahc, port+1, (value >> 8) & 0xFF);
+	ahc_outb(ahc, port+2, (value >> 16) & 0xFF);
+	ahc_outb(ahc, port+3, (value >> 24) & 0xFF);
+	ahc_outb(ahc, port+4, (value >> 32) & 0xFF);
+	ahc_outb(ahc, port+5, (value >> 40) & 0xFF);
+	ahc_outb(ahc, port+6, (value >> 48) & 0xFF);
+	ahc_outb(ahc, port+7, (value >> 56) & 0xFF);
+}
+
+/*
+ * Get a free scb. If there are none, see if we can allocate a new SCB.
+ */
+static __inline struct scb *
+ahc_get_scb(struct ahc_softc *ahc)
+{
+	struct scb *scb;
+
+	if ((scb = SLIST_FIRST(&ahc->scb_data->free_scbs)) == NULL) {
+		ahc_alloc_scbs(ahc);
+		scb = SLIST_FIRST(&ahc->scb_data->free_scbs);
+		if (scb == NULL)
+			return (NULL);
+	}
+	SLIST_REMOVE_HEAD(&ahc->scb_data->free_scbs, links.sle);
+	return (scb);
+}
+
+/*
+ * Return an SCB resource to the free list.
+ */
+static __inline void
+ahc_free_scb(struct ahc_softc *ahc, struct scb *scb)
+{       
+	struct hardware_scb *hscb;
+
+	hscb = scb->hscb;
+	/* Clean up for the next user */
+	ahc->scb_data->scbindex[hscb->tag] = NULL;
+	scb->flags = SCB_FREE;
+	hscb->control = 0;
+
+	SLIST_INSERT_HEAD(&ahc->scb_data->free_scbs, scb, links.sle);
+
+	/* Notify the OSM that a resource is now available. */
+	ahc_platform_scb_free(ahc, scb);
+}
+
+static __inline struct scb *
+ahc_lookup_scb(struct ahc_softc *ahc, u_int tag)
+{
+	struct scb* scb;
+
+	scb = ahc->scb_data->scbindex[tag];
+	if (scb != NULL)
+		ahc_sync_scb(ahc, scb,
+			     BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
+	return (scb);
+}
+
+static __inline void
+ahc_swap_with_next_hscb(struct ahc_softc *ahc, struct scb *scb)
+{
+	struct hardware_scb *q_hscb;
+	u_int  saved_tag;
+
+	/*
+	 * Our queuing method is a bit tricky.  The card
+	 * knows in advance which HSCB to download, and we
+	 * can't disappoint it.  To achieve this, the next
+	 * SCB to download is saved off in ahc->next_queued_scb.
+	 * When we are called to queue "an arbitrary scb",
+	 * we copy the contents of the incoming HSCB to the one
+	 * the sequencer knows about, swap HSCB pointers and
+	 * finally assign the SCB to the tag indexed location
+	 * in the scb_array.  This makes sure that we can still
+	 * locate the correct SCB by SCB_TAG.
+	 */
+	q_hscb = ahc->next_queued_scb->hscb;
+	saved_tag = q_hscb->tag;
+	memcpy(q_hscb, scb->hscb, sizeof(*scb->hscb));
+	if ((scb->flags & SCB_CDB32_PTR) != 0) {
+		q_hscb->shared_data.cdb_ptr =
+		    ahc_htole32(ahc_hscb_busaddr(ahc, q_hscb->tag)
+			      + offsetof(struct hardware_scb, cdb32));
+	}
+	q_hscb->tag = saved_tag;
+	q_hscb->next = scb->hscb->tag;
+
+	/* Now swap HSCB pointers. */
+	ahc->next_queued_scb->hscb = scb->hscb;
+	scb->hscb = q_hscb;
+
+	/* Now define the mapping from tag to SCB in the scbindex */
+	ahc->scb_data->scbindex[scb->hscb->tag] = scb;
+}
+
+/*
+ * Tell the sequencer about a new transaction to execute.
+ */
+static __inline void
+ahc_queue_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc_swap_with_next_hscb(ahc, scb);
+
+	if (scb->hscb->tag == SCB_LIST_NULL
+	 || scb->hscb->next == SCB_LIST_NULL)
+		panic("Attempt to queue invalid SCB tag %x:%x\n",
+		      scb->hscb->tag, scb->hscb->next);
+
+	/*
+	 * Setup data "oddness".
+	 */
+	scb->hscb->lun &= LID;
+	if (ahc_get_transfer_length(scb) & 0x1)
+		scb->hscb->lun |= SCB_XFERLEN_ODD;
+
+	/*
+	 * Keep a history of SCBs we've downloaded in the qinfifo.
+	 */
+	ahc->qinfifo[ahc->qinfifonext++] = scb->hscb->tag;
+
+	/*
+	 * Make sure our data is consistent from the
+	 * perspective of the adapter.
+	 */
+	ahc_sync_scb(ahc, scb, BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
+
+	/* Tell the adapter about the newly queued SCB */
+	if ((ahc->features & AHC_QUEUE_REGS) != 0) {
+		ahc_outb(ahc, HNSCB_QOFF, ahc->qinfifonext);
+	} else {
+		if ((ahc->features & AHC_AUTOPAUSE) == 0)
+			ahc_pause(ahc);
+		ahc_outb(ahc, KERNEL_QINPOS, ahc->qinfifonext);
+		if ((ahc->features & AHC_AUTOPAUSE) == 0)
+			ahc_unpause(ahc);
+	}
+}
+
+static __inline struct scsi_sense_data *
+ahc_get_sense_buf(struct ahc_softc *ahc, struct scb *scb)
+{
+	int offset;
+
+	offset = scb - ahc->scb_data->scbarray;
+	return (&ahc->scb_data->sense[offset]);
+}
+
+static __inline uint32_t
+ahc_get_sense_bufaddr(struct ahc_softc *ahc, struct scb *scb)
+{
+	int offset;
+
+	offset = scb - ahc->scb_data->scbarray;
+	return (ahc->scb_data->sense_busaddr
+	      + (offset * sizeof(struct scsi_sense_data)));
+}
+
+/************************** Interrupt Processing ******************************/
+static __inline void	ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
+static __inline void	ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
+static __inline u_int	ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
+static __inline int	ahc_intr(struct ahc_softc *ahc);
+
+static __inline void
+ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
+{
+	ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+			/*offset*/0, /*len*/256, op);
+}
+
+static __inline void
+ahc_sync_tqinfifo(struct ahc_softc *ahc, int op)
+{
+#ifdef AHC_TARGET_MODE
+	if ((ahc->flags & AHC_TARGETROLE) != 0) {
+		ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+				ahc->shared_data_dmamap,
+				ahc_targetcmd_offset(ahc, 0),
+				sizeof(struct target_cmd) * AHC_TMODE_CMDS,
+				op);
+	}
+#endif
+}
+
+/*
+ * See if the firmware has posted any completed commands
+ * into our in-core command complete fifos.
+ */
+#define AHC_RUN_QOUTFIFO 0x1
+#define AHC_RUN_TQINFIFO 0x2
+static __inline u_int
+ahc_check_cmdcmpltqueues(struct ahc_softc *ahc)
+{
+	u_int retval;
+
+	retval = 0;
+	ahc_dmamap_sync(ahc, ahc->shared_data_dmat, ahc->shared_data_dmamap,
+			/*offset*/ahc->qoutfifonext, /*len*/1,
+			BUS_DMASYNC_POSTREAD);
+	if (ahc->qoutfifo[ahc->qoutfifonext] != SCB_LIST_NULL)
+		retval |= AHC_RUN_QOUTFIFO;
+#ifdef AHC_TARGET_MODE
+	if ((ahc->flags & AHC_TARGETROLE) != 0
+	 && (ahc->flags & AHC_TQINFIFO_BLOCKED) == 0) {
+		ahc_dmamap_sync(ahc, ahc->shared_data_dmat,
+				ahc->shared_data_dmamap,
+				ahc_targetcmd_offset(ahc, ahc->tqinfifofnext),
+				/*len*/sizeof(struct target_cmd),
+				BUS_DMASYNC_POSTREAD);
+		if (ahc->targetcmds[ahc->tqinfifonext].cmd_valid != 0)
+			retval |= AHC_RUN_TQINFIFO;
+	}
+#endif
+	return (retval);
+}
+
+/*
+ * Catch an interrupt from the adapter
+ */
+static __inline int
+ahc_intr(struct ahc_softc *ahc)
+{
+	u_int	intstat;
+
+	if ((ahc->pause & INTEN) == 0) {
+		/*
+		 * Our interrupt is not enabled on the chip
+		 * and may be disabled for re-entrancy reasons,
+		 * so just return.  This is likely just a shared
+		 * interrupt.
+		 */
+		return (0);
+	}
+	/*
+	 * Instead of directly reading the interrupt status register,
+	 * infer the cause of the interrupt by checking our in-core
+	 * completion queues.  This avoids a costly PCI bus read in
+	 * most cases.
+	 */
+	if ((ahc->flags & (AHC_ALL_INTERRUPTS|AHC_EDGE_INTERRUPT)) == 0
+	 && (ahc_check_cmdcmpltqueues(ahc) != 0))
+		intstat = CMDCMPLT;
+	else {
+		intstat = ahc_inb(ahc, INTSTAT);
+	}
+
+	if ((intstat & INT_PEND) == 0) {
+#if AHC_PCI_CONFIG > 0
+		if (ahc->unsolicited_ints > 500) {
+			ahc->unsolicited_ints = 0;
+			if ((ahc->chip & AHC_PCI) != 0
+			 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+				ahc->bus_intr(ahc);
+		}
+#endif
+		ahc->unsolicited_ints++;
+		return (0);
+	}
+	ahc->unsolicited_ints = 0;
+
+	if (intstat & CMDCMPLT) {
+		ahc_outb(ahc, CLRINT, CLRCMDINT);
+
+		/*
+		 * Ensure that the chip sees that we've cleared
+		 * this interrupt before we walk the output fifo.
+		 * Otherwise, we may, due to posted bus writes,
+		 * clear the interrupt after we finish the scan,
+		 * and after the sequencer has added new entries
+		 * and asserted the interrupt again.
+		 */
+		ahc_flush_device_writes(ahc);
+		ahc_run_qoutfifo(ahc);
+#ifdef AHC_TARGET_MODE
+		if ((ahc->flags & AHC_TARGETROLE) != 0)
+			ahc_run_tqinfifo(ahc, /*paused*/FALSE);
+#endif
+	}
+
+	/*
+	 * Handle statuses that may invalidate our cached
+	 * copy of INTSTAT separately.
+	 */
+	if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
+		/* Hot eject.  Do nothing */
+	} else if (intstat & BRKADRINT) {
+		ahc_handle_brkadrint(ahc);
+	} else if ((intstat & (SEQINT|SCSIINT)) != 0) {
+
+		ahc_pause_bug_fix(ahc);
+
+		if ((intstat & SEQINT) != 0)
+			ahc_handle_seqint(ahc, intstat);
+
+		if ((intstat & SCSIINT) != 0)
+			ahc_handle_scsiint(ahc, intstat);
+	}
+	return (1);
+}
+
+#endif  /* _AIC7XXX_INLINE_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
new file mode 100644
index 0000000..031c6aa
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -0,0 +1,5043 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#235 $
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
+ *
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ *  SCB paging, and other rework of the code.
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-2000 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
+ *
+ *  A Boot time option was also added for not resetting the scsi bus.
+ *
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=verbose
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
+ *
+ *  Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp
+ */
+
+/*
+ * Further driver modifications made by Doug Ledford <dledford@redhat.com>
+ *
+ * Copyright (c) 1997-1999 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accommodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include <scsi/scsicam.h>
+
+/*
+ * Include aiclib.c as part of our
+ * "module dependencies are hard" work around.
+ */
+#include "aiclib.c"
+
+#include <linux/init.h>		/* __setup */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#include "sd.h"			/* For geometry detection */
+#endif
+
+#include <linux/mm.h>		/* For fetching system memory size */
+#include <linux/blkdev.h>		/* For block_size() */
+#include <linux/delay.h>	/* For ssleep/msleep */
+
+/*
+ * Lock protecting manipulation of the ahc softc list.
+ */
+spinlock_t ahc_list_spinlock;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/* For dynamic sglist size calculation. */
+u_int ahc_linux_nseg;
+#endif
+
+/*
+ * Set this to the delay in seconds after SCSI bus reset.
+ * Note, we honor this only for the initial bus reset.
+ * The scsi error recovery code performs its own bus settle
+ * delay handling for error recovery actions.
+ */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY_MS
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY_MS
+#else
+#define AIC7XXX_RESET_DELAY 5000
+#endif
+
+/*
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
+ *
+ * NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
+ * NOTE: This does affect performance since it has to maintain statistics.
+ */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
+
+/*
+ * To change the default number of tagged transactions allowed per-device,
+ * add a line to the lilo.conf file like:
+ * append="aic7xxx=verbose,tag_info:{{32,32,32,32},{32,32,32,32}}"
+ * which will result in the first four devices on the first two
+ * controllers being set to a tagged queue depth of 32.
+ *
+ * The tag_commands is an array of 16 to allow for wide and twin adapters.
+ * Twin adapters will use indexes 0-7 for channel 0, and indexes 8-15
+ * for channel 1.
+ */
+typedef struct {
+	uint8_t tag_commands[16];	/* Allow for wide/twin adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Modify this as you see fit for your system.
+ *
+ * 0			tagged queuing disabled
+ * 1 <= n <= 253	n == max tags ever dispatched.
+ *
+ * The driver will throttle the number of commands dispatched to a
+ * device if it returns queue full.  For devices with a fixed maximum
+ * queue depth, the driver will eventually determine this depth and
+ * lock it in (a console message is printed to indicate that a lock
+ * has occurred).  On some devices, queue full is returned for a temporary
+ * resource shortage.  These devices will return queue full at varying
+ * depths.  The driver will throttle back when the queue fulls occur and
+ * attempt to slowly increase the depth over time as the device recovers
+ * from the resource shortage.
+ *
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (0, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to attempt to use up to 64 tags for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+
+/*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is just below this comment block.
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{4, 64, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 0, 4, 4, 4}},
+	{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}},
+	{{0, 16, 4, 0, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+*/
+
+#ifdef CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#define AIC7XXX_CMDS_PER_DEVICE CONFIG_AIC7XXX_CMDS_PER_DEVICE
+#else
+#define AIC7XXX_CMDS_PER_DEVICE AHC_MAX_QUEUE
+#endif
+
+#define AIC7XXX_CONFIGED_TAG_COMMANDS {					\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE,		\
+	AIC7XXX_CMDS_PER_DEVICE, AIC7XXX_CMDS_PER_DEVICE		\
+}
+
+/*
+ * By default, use the number of commands specified by
+ * the users kernel configuration.
+ */
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS},
+	{AIC7XXX_CONFIGED_TAG_COMMANDS}
+};
+
+/*
+ * DV option:
+ *
+ * positive value = DV Enabled
+ * zero		  = DV Disabled
+ * negative value = DV Default for adapter type/seeprom
+ */
+#ifdef CONFIG_AIC7XXX_DV_SETTING
+#define AIC7XXX_CONFIGED_DV CONFIG_AIC7XXX_DV_SETTING
+#else
+#define AIC7XXX_CONFIGED_DV -1
+#endif
+
+static int8_t aic7xxx_dv_settings[] =
+{
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV,
+	AIC7XXX_CONFIGED_DV
+};
+
+/*
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW   DID_ERROR
+
+void
+ahc_print_path(struct ahc_softc *ahc, struct scb *scb)
+{
+	printk("(scsi%d:%c:%d:%d): ",
+	       ahc->platform_data->host->host_no,
+	       scb != NULL ? SCB_GET_CHANNEL(ahc, scb) : 'X',
+	       scb != NULL ? SCB_GET_TARGET(ahc, scb) : -1,
+	       scb != NULL ? SCB_GET_LUN(scb) : -1);
+}
+
+/*
+ * XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
+ */
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static uint32_t aic7xxx_no_reset;
+
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static uint32_t aic7xxx_reverse_scan;
+
+/*
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
+ */
+static uint32_t aic7xxx_extended;
+
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations where stray PCI transactions with bad parity are
+ * the norm rather than the exception, the error messages can be overwelming.
+ * It's included in the driver for completeness.
+ *   0	   = Shut off PCI parity check
+ *   non-0 = reverse polarity pci parity checking
+ */
+static uint32_t aic7xxx_pci_parity = ~0;
+
+/*
+ * Certain newer motherboards have put new PCI based devices into the
+ * IO spaces that used to typically be occupied by VLB or EISA cards.
+ * This overlap can cause these newer motherboards to lock up when scanned
+ * for older EISA and VLB devices.  Setting this option to non-0 will
+ * cause the driver to skip scanning for any VLB or EISA controllers and
+ * only support the PCI controllers.  NOTE: this means that if the kernel
+ * os compiled with PCI support disabled, then setting this to non-0
+ * would result in never finding any devices :)
+ */
+#ifndef CONFIG_AIC7XXX_PROBE_EISA_VL
+uint32_t aic7xxx_probe_eisa_vl;
+#else
+uint32_t aic7xxx_probe_eisa_vl = ~0;
+#endif
+
+/*
+ * There are lots of broken chipsets in the world.  Some of them will
+ * violate the PCI spec when we issue byte sized memory writes to our
+ * controller.  I/O mapped register access, if allowed by the given
+ * platform, will work in almost all cases.
+ */
+uint32_t aic7xxx_allow_memio = ~0;
+
+/*
+ * aic7xxx_detect() has been run, so register all device arrivals
+ * immediately with the system rather than deferring to the sorted
+ * attachment performed by aic7xxx_detect().
+ */
+int aic7xxx_detect_complete;
+
+/*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ *   0 - 256ms
+ *   1 - 128ms
+ *   2 - 64ms
+ *   3 - 32ms
+ * We default to 256ms because some older devices need a longer time
+ * to respond to initial selection.
+ */
+static uint32_t aic7xxx_seltime;
+
+/*
+ * Certain devices do not perform any aging on commands.  Should the
+ * device be saturated by commands in one portion of the disk, it is
+ * possible for transactions on far away sectors to never be serviced.
+ * To handle these devices, we can periodically send an ordered tag to
+ * force all outstanding transactions to be serviced prior to a new
+ * transaction.
+ */
+uint32_t aic7xxx_periodic_otag;
+
+/*
+ * Module information and settable options.
+ */
+static char *aic7xxx = NULL;
+
+MODULE_AUTHOR("Maintainer: Justin T. Gibbs <gibbs@scsiguy.com>");
+MODULE_DESCRIPTION("Adaptec Aic77XX/78XX SCSI Host Bus Adapter driver");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(AIC7XXX_DRIVER_VERSION);
+module_param(aic7xxx, charp, 0444);
+MODULE_PARM_DESC(aic7xxx,
+"period delimited, options string.\n"
+"	verbose			Enable verbose/diagnostic logging\n"
+"	allow_memio		Allow device registers to be memory mapped\n"
+"	debug			Bitmask of debug values to enable\n"
+"	no_probe		Toggle EISA/VLB controller probing\n"
+"	probe_eisa_vl		Toggle EISA/VLB controller probing\n"
+"	no_reset		Supress initial bus resets\n"
+"	extended		Enable extended geometry on all controllers\n"
+"	periodic_otag		Send an ordered tagged transaction\n"
+"				periodically to prevent tag starvation.\n"
+"				This may be required by some older disk\n"
+"				drives or RAID arrays.\n"
+"	reverse_scan		Sort PCI devices highest Bus/Slot to lowest\n"
+"	tag_info:<tag_str>	Set per-target tag depth\n"
+"	global_tag_depth:<int>	Global tag depth for every target\n"
+"				on every bus\n"
+"	dv:<dv_settings>	Set per-controller Domain Validation Setting.\n"
+"	seltime:<int>		Selection Timeout\n"
+"				(0/256ms,1/128ms,2/64ms,3/32ms)\n"
+"\n"
+"	Sample /etc/modprobe.conf line:\n"
+"		Toggle EISA/VLB probing\n"
+"		Set tag depth on Controller 1/Target 1 to 10 tags\n"
+"		Shorten the selection timeout to 128ms\n"
+"\n"
+"	options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n"
+);
+
+static void ahc_linux_handle_scsi_status(struct ahc_softc *,
+					 struct ahc_linux_device *,
+					 struct scb *);
+static void ahc_linux_queue_cmd_complete(struct ahc_softc *ahc,
+					 Scsi_Cmnd *cmd);
+static void ahc_linux_filter_inquiry(struct ahc_softc*, struct ahc_devinfo*);
+static void ahc_linux_sem_timeout(u_long arg);
+static void ahc_linux_freeze_simq(struct ahc_softc *ahc);
+static void ahc_linux_release_simq(u_long arg);
+static void ahc_linux_dev_timed_unfreeze(u_long arg);
+static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
+static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
+static void ahc_linux_size_nseg(void);
+static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc);
+static void ahc_linux_start_dv(struct ahc_softc *ahc);
+static void ahc_linux_dv_timeout(struct scsi_cmnd *cmd);
+static int  ahc_linux_dv_thread(void *data);
+static void ahc_linux_kill_dv_thread(struct ahc_softc *ahc);
+static void ahc_linux_dv_target(struct ahc_softc *ahc, u_int target);
+static void ahc_linux_dv_transition(struct ahc_softc *ahc,
+				    struct scsi_cmnd *cmd,
+				    struct ahc_devinfo *devinfo,
+				    struct ahc_linux_target *targ);
+static void ahc_linux_dv_fill_cmd(struct ahc_softc *ahc,
+				  struct scsi_cmnd *cmd,
+				  struct ahc_devinfo *devinfo);
+static void ahc_linux_dv_inq(struct ahc_softc *ahc,
+			     struct scsi_cmnd *cmd,
+			     struct ahc_devinfo *devinfo,
+			     struct ahc_linux_target *targ,
+			     u_int request_length);
+static void ahc_linux_dv_tur(struct ahc_softc *ahc,
+			     struct scsi_cmnd *cmd,
+			     struct ahc_devinfo *devinfo);
+static void ahc_linux_dv_rebd(struct ahc_softc *ahc,
+			      struct scsi_cmnd *cmd,
+			      struct ahc_devinfo *devinfo,
+			      struct ahc_linux_target *targ);
+static void ahc_linux_dv_web(struct ahc_softc *ahc,
+			     struct scsi_cmnd *cmd,
+			     struct ahc_devinfo *devinfo,
+			     struct ahc_linux_target *targ);
+static void ahc_linux_dv_reb(struct ahc_softc *ahc,
+			     struct scsi_cmnd *cmd,
+			     struct ahc_devinfo *devinfo,
+			     struct ahc_linux_target *targ);
+static void ahc_linux_dv_su(struct ahc_softc *ahc,
+			    struct scsi_cmnd *cmd,
+			    struct ahc_devinfo *devinfo,
+			    struct ahc_linux_target *targ);
+static int ahc_linux_fallback(struct ahc_softc *ahc,
+			      struct ahc_devinfo *devinfo);
+static void ahc_linux_dv_complete(Scsi_Cmnd *cmd);
+static void ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ);
+static u_int ahc_linux_user_tagdepth(struct ahc_softc *ahc,
+				     struct ahc_devinfo *devinfo);
+static u_int ahc_linux_user_dv_setting(struct ahc_softc *ahc);
+static void ahc_linux_device_queue_depth(struct ahc_softc *ahc,
+					 struct ahc_linux_device *dev);
+static struct ahc_linux_target*	ahc_linux_alloc_target(struct ahc_softc*,
+						       u_int, u_int);
+static void			ahc_linux_free_target(struct ahc_softc*,
+						      struct ahc_linux_target*);
+static struct ahc_linux_device*	ahc_linux_alloc_device(struct ahc_softc*,
+						       struct ahc_linux_target*,
+						       u_int);
+static void			ahc_linux_free_device(struct ahc_softc*,
+						      struct ahc_linux_device*);
+static void ahc_linux_run_device_queue(struct ahc_softc*,
+				       struct ahc_linux_device*);
+static void ahc_linux_setup_tag_info_global(char *p);
+static aic_option_callback_t ahc_linux_setup_tag_info;
+static aic_option_callback_t ahc_linux_setup_dv;
+static int  aic7xxx_setup(char *s);
+static int  ahc_linux_next_unit(void);
+static void ahc_runq_tasklet(unsigned long data);
+static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc);
+
+/********************************* Inlines ************************************/
+static __inline void ahc_schedule_runq(struct ahc_softc *ahc);
+static __inline struct ahc_linux_device*
+		     ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
+					  u_int target, u_int lun, int alloc);
+static __inline void ahc_schedule_completeq(struct ahc_softc *ahc);
+static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc,
+						  struct ahc_linux_device *dev);
+static __inline struct ahc_linux_device *
+		     ahc_linux_next_device_to_run(struct ahc_softc *ahc);
+static __inline void ahc_linux_run_device_queues(struct ahc_softc *ahc);
+static __inline void ahc_linux_unmap_scb(struct ahc_softc*, struct scb*);
+
+static __inline int ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
+		 		      struct ahc_dma_seg *sg,
+				      dma_addr_t addr, bus_size_t len);
+
+static __inline void
+ahc_schedule_completeq(struct ahc_softc *ahc)
+{
+	if ((ahc->platform_data->flags & AHC_RUN_CMPLT_Q_TIMER) == 0) {
+		ahc->platform_data->flags |= AHC_RUN_CMPLT_Q_TIMER;
+		ahc->platform_data->completeq_timer.expires = jiffies;
+		add_timer(&ahc->platform_data->completeq_timer);
+	}
+}
+
+/*
+ * Must be called with our lock held.
+ */
+static __inline void
+ahc_schedule_runq(struct ahc_softc *ahc)
+{
+	tasklet_schedule(&ahc->platform_data->runq_tasklet);
+}
+
+static __inline struct ahc_linux_device*
+ahc_linux_get_device(struct ahc_softc *ahc, u_int channel, u_int target,
+		     u_int lun, int alloc)
+{
+	struct ahc_linux_target *targ;
+	struct ahc_linux_device *dev;
+	u_int target_offset;
+
+	target_offset = target;
+	if (channel != 0)
+		target_offset += 8;
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL) {
+		if (alloc != 0) {
+			targ = ahc_linux_alloc_target(ahc, channel, target);
+			if (targ == NULL)
+				return (NULL);
+		} else
+			return (NULL);
+	}
+	dev = targ->devices[lun];
+	if (dev == NULL && alloc != 0)
+		dev = ahc_linux_alloc_device(ahc, targ, lun);
+	return (dev);
+}
+
+#define AHC_LINUX_MAX_RETURNED_ERRORS 4
+static struct ahc_cmd *
+ahc_linux_run_complete_queue(struct ahc_softc *ahc)
+{
+	struct	ahc_cmd *acmd;
+	u_long	done_flags;
+	int	with_errors;
+
+	with_errors = 0;
+	ahc_done_lock(ahc, &done_flags);
+	while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) {
+		Scsi_Cmnd *cmd;
+
+		if (with_errors > AHC_LINUX_MAX_RETURNED_ERRORS) {
+			/*
+			 * Linux uses stack recursion to requeue
+			 * commands that need to be retried.  Avoid
+			 * blowing out the stack by "spoon feeding"
+			 * commands that completed with error back
+			 * the operating system in case they are going
+			 * to be retried. "ick"
+			 */
+			ahc_schedule_completeq(ahc);
+			break;
+		}
+		TAILQ_REMOVE(&ahc->platform_data->completeq,
+			     acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		cmd->host_scribble = NULL;
+		if (ahc_cmd_get_transaction_status(cmd) != DID_OK
+		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
+			with_errors++;
+
+		cmd->scsi_done(cmd);
+	}
+	ahc_done_unlock(ahc, &done_flags);
+	return (acmd);
+}
+
+static __inline void
+ahc_linux_check_device_queue(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev)
+{
+	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) != 0
+	 && dev->active == 0) {
+		dev->flags &= ~AHC_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen--;
+	}
+
+	if (TAILQ_FIRST(&dev->busyq) == NULL
+	 || dev->openings == 0 || dev->qfrozen != 0)
+		return;
+
+	ahc_linux_run_device_queue(ahc, dev);
+}
+
+static __inline struct ahc_linux_device *
+ahc_linux_next_device_to_run(struct ahc_softc *ahc)
+{
+	
+	if ((ahc->flags & AHC_RESOURCE_SHORTAGE) != 0
+	 || (ahc->platform_data->qfrozen != 0
+	  && AHC_DV_SIMQ_FROZEN(ahc) == 0))
+		return (NULL);
+	return (TAILQ_FIRST(&ahc->platform_data->device_runq));
+}
+
+static __inline void
+ahc_linux_run_device_queues(struct ahc_softc *ahc)
+{
+	struct ahc_linux_device *dev;
+
+	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {
+		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
+		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
+		ahc_linux_check_device_queue(ahc, dev);
+	}
+}
+
+static __inline void
+ahc_linux_unmap_scb(struct ahc_softc *ahc, struct scb *scb)
+{
+	Scsi_Cmnd *cmd;
+
+	cmd = scb->io_ctx;
+	ahc_sync_sglist(ahc, scb, BUS_DMASYNC_POSTWRITE);
+	if (cmd->use_sg != 0) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *)cmd->request_buffer;
+		pci_unmap_sg(ahc->dev_softc, sg, cmd->use_sg,
+			     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	} else if (cmd->request_bufflen != 0) {
+		pci_unmap_single(ahc->dev_softc,
+				 scb->platform_data->buf_busaddr,
+				 cmd->request_bufflen,
+				 scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}
+}
+
+static __inline int
+ahc_linux_map_seg(struct ahc_softc *ahc, struct scb *scb,
+		  struct ahc_dma_seg *sg, dma_addr_t addr, bus_size_t len)
+{
+	int	 consumed;
+
+	if ((scb->sg_count + 1) > AHC_NSEG)
+		panic("Too few segs for dma mapping.  "
+		      "Increase AHC_NSEG\n");
+
+	consumed = 1;
+	sg->addr = ahc_htole32(addr & 0xFFFFFFFF);
+	scb->platform_data->xfer_len += len;
+
+	if (sizeof(dma_addr_t) > 4
+	 && (ahc->flags & AHC_39BIT_ADDRESSING) != 0)
+		len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK;
+
+	sg->len = ahc_htole32(len);
+	return (consumed);
+}
+
+/************************  Host template entry points *************************/
+static int	   ahc_linux_detect(Scsi_Host_Template *);
+static int	   ahc_linux_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static const char *ahc_linux_info(struct Scsi_Host *);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int	   ahc_linux_slave_alloc(Scsi_Device *);
+static int	   ahc_linux_slave_configure(Scsi_Device *);
+static void	   ahc_linux_slave_destroy(Scsi_Device *);
+#if defined(__i386__)
+static int	   ahc_linux_biosparam(struct scsi_device*,
+				       struct block_device*,
+				       sector_t, int[]);
+#endif
+#else
+static int	   ahc_linux_release(struct Scsi_Host *);
+static void	   ahc_linux_select_queue_depth(struct Scsi_Host *host,
+						Scsi_Device *scsi_devs);
+#if defined(__i386__)
+static int	   ahc_linux_biosparam(Disk *, kdev_t, int[]);
+#endif
+#endif
+static int	   ahc_linux_bus_reset(Scsi_Cmnd *);
+static int	   ahc_linux_dev_reset(Scsi_Cmnd *);
+static int	   ahc_linux_abort(Scsi_Cmnd *);
+
+/*
+ * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg).
+ *
+ * In pre-2.5.X...
+ * The midlayer allocates an S/G array dynamically when a command is issued
+ * using SCSI malloc.  This array, which is in an OS dependent format that
+ * must later be copied to our private S/G list, is sized to house just the
+ * number of segments needed for the current transfer.  Since the code that
+ * sizes the SCSI malloc pool does not take into consideration fragmentation
+ * of the pool, executing transactions numbering just a fraction of our
+ * concurrent transaction limit with list lengths aproaching AHC_NSEG will
+ * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
+ * mid-layer does not properly handle this scsi malloc failures for the S/G
+ * array and the result can be a lockup of the I/O subsystem.  We try to size
+ * our S/G list so that it satisfies our drivers allocation requirements in
+ * addition to avoiding fragmentation of the SCSI malloc pool.
+ */
+static void
+ahc_linux_size_nseg(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	u_int cur_size;
+	u_int best_size;
+
+	/*
+	 * The SCSI allocator rounds to the nearest 512 bytes
+	 * an cannot allocate across a page boundary.  Our algorithm
+	 * is to start at 1K of scsi malloc space per-command and
+	 * loop through all factors of the PAGE_SIZE and pick the best.
+	 */
+	best_size = 0;
+	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
+		u_int nseg;
+
+		nseg = cur_size / sizeof(struct scatterlist);
+		if (nseg < AHC_LINUX_MIN_NSEG)
+			continue;
+
+		if (best_size == 0) {
+			best_size = cur_size;
+			ahc_linux_nseg = nseg;
+		} else {
+			u_int best_rem;
+			u_int cur_rem;
+
+			/*
+			 * Compare the traits of the current "best_size"
+			 * with the current size to determine if the
+			 * current size is a better size.
+			 */
+			best_rem = best_size % sizeof(struct scatterlist);
+			cur_rem = cur_size % sizeof(struct scatterlist);
+			if (cur_rem < best_rem) {
+				best_size = cur_size;
+				ahc_linux_nseg = nseg;
+			}
+		}
+	}
+#endif
+}
+
+/*
+ * Try to detect an Adaptec 7XXX controller.
+ */
+static int
+ahc_linux_detect(Scsi_Host_Template *template)
+{
+	struct	ahc_softc *ahc;
+	int     found = 0;
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * It is a bug that the upper layer takes
+	 * this lock just prior to calling us.
+	 */
+	spin_unlock_irq(&io_request_lock);
+#endif
+
+	/*
+	 * Sanity checking of Linux SCSI data structures so
+	 * that some of our hacks^H^H^H^H^Hassumptions aren't
+	 * violated.
+	 */
+	if (offsetof(struct ahc_cmd_internal, end)
+	  > offsetof(struct scsi_cmnd, host_scribble)) {
+		printf("ahc_linux_detect: SCSI data structures changed.\n");
+		printf("ahc_linux_detect: Unable to attach\n");
+		return (0);
+	}
+	ahc_linux_size_nseg();
+	/*
+	 * If we've been passed any parameters, process them now.
+	 */
+	if (aic7xxx)
+		aic7xxx_setup(aic7xxx);
+
+	template->proc_name = "aic7xxx";
+
+	/*
+	 * Initialize our softc list lock prior to
+	 * probing for any adapters.
+	 */
+	ahc_list_lockinit();
+
+	found = ahc_linux_pci_init();
+	if (!ahc_linux_eisa_init())
+		found++;
+	
+	/*
+	 * Register with the SCSI layer all
+	 * controllers we've found.
+	 */
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+
+		if (ahc_linux_register_host(ahc, template) == 0)
+			found++;
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	spin_lock_irq(&io_request_lock);
+#endif
+	aic7xxx_detect_complete++;
+
+	return (found);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * Free the passed in Scsi_Host memory structures prior to unloading the
+ * module.
+ */
+int
+ahc_linux_release(struct Scsi_Host * host)
+{
+	struct ahc_softc *ahc;
+	u_long l;
+
+	ahc_list_lock(&l);
+	if (host != NULL) {
+
+		/*
+		 * We should be able to just perform
+		 * the free directly, but check our
+		 * list for extra sanity.
+		 */
+		ahc = ahc_find_softc(*(struct ahc_softc **)host->hostdata);
+		if (ahc != NULL) {
+			u_long s;
+
+			ahc_lock(ahc, &s);
+			ahc_intr_enable(ahc, FALSE);
+			ahc_unlock(ahc, &s);
+			ahc_free(ahc);
+		}
+	}
+	ahc_list_unlock(&l);
+	return (0);
+}
+#endif
+
+/*
+ * Return a string describing the driver.
+ */
+static const char *
+ahc_linux_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	char	ahc_info[256];
+	char   *bp;
+	struct ahc_softc *ahc;
+
+	bp = &buffer[0];
+	ahc = *(struct ahc_softc **)host->hostdata;
+	memset(bp, 0, sizeof(buffer));
+	strcpy(bp, "Adaptec AIC7XXX EISA/VLB/PCI SCSI HBA DRIVER, Rev ");
+	strcat(bp, AIC7XXX_DRIVER_VERSION);
+	strcat(bp, "\n");
+	strcat(bp, "        <");
+	strcat(bp, ahc->description);
+	strcat(bp, ">\n");
+	strcat(bp, "        ");
+	ahc_controller_info(ahc, ahc_info);
+	strcat(bp, ahc_info);
+	strcat(bp, "\n");
+
+	return (bp);
+}
+
+/*
+ * Queue an SCB to the controller.
+ */
+static int
+ahc_linux_queue(Scsi_Cmnd * cmd, void (*scsi_done) (Scsi_Cmnd *))
+{
+	struct	 ahc_softc *ahc;
+	struct	 ahc_linux_device *dev;
+	u_long	 flags;
+
+	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
+
+	/*
+	 * Save the callback on completion function.
+	 */
+	cmd->scsi_done = scsi_done;
+
+	ahc_midlayer_entrypoint_lock(ahc, &flags);
+
+	/*
+	 * Close the race of a command that was in the process of
+	 * being queued to us just as our simq was frozen.  Let
+	 * DV commands through so long as we are only frozen to
+	 * perform DV.
+	 */
+	if (ahc->platform_data->qfrozen != 0
+	 && AHC_DV_CMD(cmd) == 0) {
+
+		ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
+		ahc_linux_queue_cmd_complete(ahc, cmd);
+		ahc_schedule_completeq(ahc);
+		ahc_midlayer_entrypoint_unlock(ahc, &flags);
+		return (0);
+	}
+	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
+				   cmd->device->lun, /*alloc*/TRUE);
+	if (dev == NULL) {
+		ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
+		ahc_linux_queue_cmd_complete(ahc, cmd);
+		ahc_schedule_completeq(ahc);
+		ahc_midlayer_entrypoint_unlock(ahc, &flags);
+		printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n",
+		       ahc_name(ahc));
+		return (0);
+	}
+	cmd->result = CAM_REQ_INPROG << 16;
+	TAILQ_INSERT_TAIL(&dev->busyq, (struct ahc_cmd *)cmd, acmd_links.tqe);
+	if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
+		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
+		dev->flags |= AHC_DEV_ON_RUN_LIST;
+		ahc_linux_run_device_queues(ahc);
+	}
+	ahc_midlayer_entrypoint_unlock(ahc, &flags);
+	return (0);
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+static int
+ahc_linux_slave_alloc(Scsi_Device *device)
+{
+	struct	ahc_softc *ahc;
+
+	ahc = *((struct ahc_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Alloc %d\n", ahc_name(ahc), device->id);
+	return (0);
+}
+
+static int
+ahc_linux_slave_configure(Scsi_Device *device)
+{
+	struct	ahc_softc *ahc;
+	struct	ahc_linux_device *dev;
+	u_long	flags;
+
+	ahc = *((struct ahc_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Configure %d\n", ahc_name(ahc), device->id);
+	ahc_midlayer_entrypoint_lock(ahc, &flags);
+	/*
+	 * Since Linux has attached to the device, configure
+	 * it so we don't free and allocate the device
+	 * structure on every command.
+	 */
+	dev = ahc_linux_get_device(ahc, device->channel,
+				   device->id, device->lun,
+				   /*alloc*/TRUE);
+	if (dev != NULL) {
+		dev->flags &= ~AHC_DEV_UNCONFIGURED;
+		dev->scsi_device = device;
+		ahc_linux_device_queue_depth(ahc, dev);
+	}
+	ahc_midlayer_entrypoint_unlock(ahc, &flags);
+	return (0);
+}
+
+static void
+ahc_linux_slave_destroy(Scsi_Device *device)
+{
+	struct	ahc_softc *ahc;
+	struct	ahc_linux_device *dev;
+	u_long	flags;
+
+	ahc = *((struct ahc_softc **)device->host->hostdata);
+	if (bootverbose)
+		printf("%s: Slave Destroy %d\n", ahc_name(ahc), device->id);
+	ahc_midlayer_entrypoint_lock(ahc, &flags);
+	dev = ahc_linux_get_device(ahc, device->channel,
+				   device->id, device->lun,
+					   /*alloc*/FALSE);
+	/*
+	 * Filter out "silly" deletions of real devices by only
+	 * deleting devices that have had slave_configure()
+	 * called on them.  All other devices that have not
+	 * been configured will automatically be deleted by
+	 * the refcounting process.
+	 */
+	if (dev != NULL
+	 && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) {
+		dev->flags |= AHC_DEV_UNCONFIGURED;
+		if (TAILQ_EMPTY(&dev->busyq)
+		 && dev->active == 0
+	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
+			ahc_linux_free_device(ahc, dev);
+	}
+	ahc_midlayer_entrypoint_unlock(ahc, &flags);
+}
+#else
+/*
+ * Sets the queue depth for each SCSI device hanging
+ * off the input host adapter.
+ */
+static void
+ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs)
+{
+	Scsi_Device *device;
+	Scsi_Device *ldev;
+	struct	ahc_softc *ahc;
+	u_long	flags;
+
+	ahc = *((struct ahc_softc **)host->hostdata);
+	ahc_lock(ahc, &flags);
+	for (device = scsi_devs; device != NULL; device = device->next) {
+
+		/*
+		 * Watch out for duplicate devices.  This works around
+		 * some quirks in how the SCSI scanning code does its
+		 * device management.
+		 */
+		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
+			if (ldev->host == device->host
+			 && ldev->channel == device->channel
+			 && ldev->id == device->id
+			 && ldev->lun == device->lun)
+				break;
+		}
+		/* Skip duplicate. */
+		if (ldev != device)
+			continue;
+
+		if (device->host == host) {
+			struct	 ahc_linux_device *dev;
+
+			/*
+			 * Since Linux has attached to the device, configure
+			 * it so we don't free and allocate the device
+			 * structure on every command.
+			 */
+			dev = ahc_linux_get_device(ahc, device->channel,
+						   device->id, device->lun,
+						   /*alloc*/TRUE);
+			if (dev != NULL) {
+				dev->flags &= ~AHC_DEV_UNCONFIGURED;
+				dev->scsi_device = device;
+				ahc_linux_device_queue_depth(ahc, dev);
+				device->queue_depth = dev->openings
+						    + dev->active;
+				if ((dev->flags & (AHC_DEV_Q_BASIC
+						| AHC_DEV_Q_TAGGED)) == 0) {
+					/*
+					 * We allow the OS to queue 2 untagged
+					 * transactions to us at any time even
+					 * though we can only execute them
+					 * serially on the controller/device.
+					 * This should remove some latency.
+					 */
+					device->queue_depth = 2;
+				}
+			}
+		}
+	}
+	ahc_unlock(ahc, &flags);
+}
+#endif
+
+#if defined(__i386__)
+/*
+ * Return the disk geometry for the given SCSI device.
+ */
+static int
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		    sector_t capacity, int geom[])
+{
+	uint8_t *bh;
+#else
+ahc_linux_biosparam(Disk *disk, kdev_t dev, int geom[])
+{
+	struct	scsi_device *sdev = disk->device;
+	u_long	capacity = disk->capacity;
+	struct	buffer_head *bh;
+#endif
+	int	 heads;
+	int	 sectors;
+	int	 cylinders;
+	int	 ret;
+	int	 extended;
+	struct	 ahc_softc *ahc;
+	u_int	 channel;
+
+	ahc = *((struct ahc_softc **)sdev->host->hostdata);
+	channel = sdev->channel;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	bh = scsi_bios_ptable(bdev);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,17)
+	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, block_size(dev));
+#else
+	bh = bread(MKDEV(MAJOR(dev), MINOR(dev) & ~0xf), 0, 1024);
+#endif
+
+	if (bh) {
+		ret = scsi_partsize(bh, capacity,
+				    &geom[2], &geom[0], &geom[1]);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		kfree(bh);
+#else
+		brelse(bh);
+#endif
+		if (ret != -1)
+			return (ret);
+	}
+	heads = 64;
+	sectors = 32;
+	cylinders = aic_sector_div(capacity, heads, sectors);
+
+	if (aic7xxx_extended != 0)
+		extended = 1;
+	else if (channel == 0)
+		extended = (ahc->flags & AHC_EXTENDED_TRANS_A) != 0;
+	else
+		extended = (ahc->flags & AHC_EXTENDED_TRANS_B) != 0;
+	if (extended && cylinders >= 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = aic_sector_div(capacity, heads, sectors);
+	}
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return (0);
+}
+#endif
+
+/*
+ * Abort the current SCSI command(s).
+ */
+static int
+ahc_linux_abort(Scsi_Cmnd *cmd)
+{
+	int error;
+
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_ABORT);
+	if (error != 0)
+		printf("aic7xxx_abort returns 0x%x\n", error);
+	return (error);
+}
+
+/*
+ * Attempt to send a target reset message to the device that timed out.
+ */
+static int
+ahc_linux_dev_reset(Scsi_Cmnd *cmd)
+{
+	int error;
+
+	error = ahc_linux_queue_recovery_cmd(cmd, SCB_DEVICE_RESET);
+	if (error != 0)
+		printf("aic7xxx_dev_reset returns 0x%x\n", error);
+	return (error);
+}
+
+/*
+ * Reset the SCSI bus.
+ */
+static int
+ahc_linux_bus_reset(Scsi_Cmnd *cmd)
+{
+	struct ahc_softc *ahc;
+	u_long s;
+	int    found;
+
+	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
+	ahc_midlayer_entrypoint_lock(ahc, &s);
+	found = ahc_reset_channel(ahc, cmd->device->channel + 'A',
+				  /*initiate reset*/TRUE);
+	ahc_linux_run_complete_queue(ahc);
+	ahc_midlayer_entrypoint_unlock(ahc, &s);
+
+	if (bootverbose)
+		printf("%s: SCSI bus reset delivered. "
+		       "%d SCBs aborted.\n", ahc_name(ahc), found);
+
+	return SUCCESS;
+}
+
+Scsi_Host_Template aic7xxx_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "aic7xxx",
+	.proc_info		= ahc_linux_proc_info,
+	.info			= ahc_linux_info,
+	.queuecommand		= ahc_linux_queue,
+	.eh_abort_handler	= ahc_linux_abort,
+	.eh_device_reset_handler = ahc_linux_dev_reset,
+	.eh_bus_reset_handler	= ahc_linux_bus_reset,
+#if defined(__i386__)
+	.bios_param		= ahc_linux_biosparam,
+#endif
+	.can_queue		= AHC_MAX_QUEUE,
+	.this_id		= -1,
+	.cmd_per_lun		= 2,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.slave_alloc		= ahc_linux_slave_alloc,
+	.slave_configure	= ahc_linux_slave_configure,
+	.slave_destroy		= ahc_linux_slave_destroy,
+};
+
+/**************************** Tasklet Handler *********************************/
+
+/*
+ * In 2.4.X and above, this routine is called from a tasklet,
+ * so we must re-acquire our lock prior to executing this code.
+ * In all prior kernels, ahc_schedule_runq() calls this routine
+ * directly and ahc_schedule_runq() is called with our lock held.
+ */
+static void
+ahc_runq_tasklet(unsigned long data)
+{
+	struct ahc_softc* ahc;
+	struct ahc_linux_device *dev;
+	u_long flags;
+
+	ahc = (struct ahc_softc *)data;
+	ahc_lock(ahc, &flags);
+	while ((dev = ahc_linux_next_device_to_run(ahc)) != NULL) {
+	
+		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
+		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
+		ahc_linux_check_device_queue(ahc, dev);
+		/* Yeild to our interrupt handler */
+		ahc_unlock(ahc, &flags);
+		ahc_lock(ahc, &flags);
+	}
+	ahc_unlock(ahc, &flags);
+}
+
+/******************************** Macros **************************************/
+#define BUILD_SCSIID(ahc, cmd)						    \
+	((((cmd)->device->id << TID_SHIFT) & TID)			    \
+	| (((cmd)->device->channel == 0) ? (ahc)->our_id : (ahc)->our_id_b) \
+	| (((cmd)->device->channel == 0) ? 0 : TWIN_CHNLB))
+
+/******************************** Bus DMA *************************************/
+int
+ahc_dma_tag_create(struct ahc_softc *ahc, bus_dma_tag_t parent,
+		   bus_size_t alignment, bus_size_t boundary,
+		   dma_addr_t lowaddr, dma_addr_t highaddr,
+		   bus_dma_filter_t *filter, void *filterarg,
+		   bus_size_t maxsize, int nsegments,
+		   bus_size_t maxsegsz, int flags, bus_dma_tag_t *ret_tag)
+{
+	bus_dma_tag_t dmat;
+
+	dmat = malloc(sizeof(*dmat), M_DEVBUF, M_NOWAIT);
+	if (dmat == NULL)
+		return (ENOMEM);
+
+	/*
+	 * Linux is very simplistic about DMA memory.  For now don't
+	 * maintain all specification information.  Once Linux supplies
+	 * better facilities for doing these operations, or the
+	 * needs of this particular driver change, we might need to do
+	 * more here.
+	 */
+	dmat->alignment = alignment;
+	dmat->boundary = boundary;
+	dmat->maxsize = maxsize;
+	*ret_tag = dmat;
+	return (0);
+}
+
+void
+ahc_dma_tag_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat)
+{
+	free(dmat, M_DEVBUF);
+}
+
+int
+ahc_dmamem_alloc(struct ahc_softc *ahc, bus_dma_tag_t dmat, void** vaddr,
+		 int flags, bus_dmamap_t *mapp)
+{
+	bus_dmamap_t map;
+
+	map = malloc(sizeof(*map), M_DEVBUF, M_NOWAIT);
+	if (map == NULL)
+		return (ENOMEM);
+	/*
+	 * Although we can dma data above 4GB, our
+	 * "consistent" memory is below 4GB for
+	 * space efficiency reasons (only need a 4byte
+	 * address).  For this reason, we have to reset
+	 * our dma mask when doing allocations.
+	 */
+	if (ahc->dev_softc != NULL)
+		if (pci_set_dma_mask(ahc->dev_softc, 0xFFFFFFFF)) {
+			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
+			kfree(map);
+			return (ENODEV);
+		}
+	*vaddr = pci_alloc_consistent(ahc->dev_softc,
+				      dmat->maxsize, &map->bus_addr);
+	if (ahc->dev_softc != NULL)
+		if (pci_set_dma_mask(ahc->dev_softc,
+				     ahc->platform_data->hw_dma_mask)) {
+			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
+			kfree(map);
+			return (ENODEV);
+		}
+	if (*vaddr == NULL)
+		return (ENOMEM);
+	*mapp = map;
+	return(0);
+}
+
+void
+ahc_dmamem_free(struct ahc_softc *ahc, bus_dma_tag_t dmat,
+		void* vaddr, bus_dmamap_t map)
+{
+	pci_free_consistent(ahc->dev_softc, dmat->maxsize,
+			    vaddr, map->bus_addr);
+}
+
+int
+ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map,
+		void *buf, bus_size_t buflen, bus_dmamap_callback_t *cb,
+		void *cb_arg, int flags)
+{
+	/*
+	 * Assume for now that this will only be used during
+	 * initialization and not for per-transaction buffer mapping.
+	 */
+	bus_dma_segment_t stack_sg;
+
+	stack_sg.ds_addr = map->bus_addr;
+	stack_sg.ds_len = dmat->maxsize;
+	cb(cb_arg, &stack_sg, /*nseg*/1, /*error*/0);
+	return (0);
+}
+
+void
+ahc_dmamap_destroy(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/*
+	 * The map may is NULL in our < 2.3.X implementation.
+	 * Now it's 2.6.5, but just in case...
+	 */
+	BUG_ON(map == NULL);
+	free(map, M_DEVBUF);
+}
+
+int
+ahc_dmamap_unload(struct ahc_softc *ahc, bus_dma_tag_t dmat, bus_dmamap_t map)
+{
+	/* Nothing to do */
+	return (0);
+}
+
+/********************* Platform Dependent Functions ***************************/
+/*
+ * Compare "left hand" softc with "right hand" softc, returning:
+ * < 0 - lahc has a lower priority than rahc
+ *   0 - Softcs are equal
+ * > 0 - lahc has a higher priority than rahc
+ */
+int
+ahc_softc_comp(struct ahc_softc *lahc, struct ahc_softc *rahc)
+{
+	int	value;
+	int	rvalue;
+	int	lvalue;
+
+	/*
+	 * Under Linux, cards are ordered as follows:
+	 *	1) VLB/EISA BIOS enabled devices sorted by BIOS address.
+	 *	2) PCI devices with BIOS enabled sorted by bus/slot/func.
+	 *	3) All remaining VLB/EISA devices sorted by ioport.
+	 *	4) All remaining PCI devices sorted by bus/slot/func.
+	 */
+	value = (lahc->flags & AHC_BIOS_ENABLED)
+	      - (rahc->flags & AHC_BIOS_ENABLED);
+	if (value != 0)
+		/* Controllers with BIOS enabled have a *higher* priority */
+		return (value);
+
+	/*
+	 * Same BIOS setting, now sort based on bus type.
+	 * EISA and VL controllers sort together.  EISA/VL
+	 * have higher priority than PCI.
+	 */
+	rvalue = (rahc->chip & AHC_BUS_MASK);
+ 	if (rvalue == AHC_VL)
+		rvalue = AHC_EISA;
+	lvalue = (lahc->chip & AHC_BUS_MASK);
+ 	if (lvalue == AHC_VL)
+		lvalue = AHC_EISA;
+	value = rvalue - lvalue;
+	if (value != 0)
+		return (value);
+
+	/* Still equal.  Sort by BIOS address, ioport, or bus/slot/func. */
+	switch (rvalue) {
+#ifdef CONFIG_PCI
+	case AHC_PCI:
+	{
+		char primary_channel;
+
+		if (aic7xxx_reverse_scan != 0)
+			value = ahc_get_pci_bus(lahc->dev_softc)
+			      - ahc_get_pci_bus(rahc->dev_softc);
+		else
+			value = ahc_get_pci_bus(rahc->dev_softc)
+			      - ahc_get_pci_bus(lahc->dev_softc);
+		if (value != 0)
+			break;
+		if (aic7xxx_reverse_scan != 0)
+			value = ahc_get_pci_slot(lahc->dev_softc)
+			      - ahc_get_pci_slot(rahc->dev_softc);
+		else
+			value = ahc_get_pci_slot(rahc->dev_softc)
+			      - ahc_get_pci_slot(lahc->dev_softc);
+		if (value != 0)
+			break;
+		/*
+		 * On multi-function devices, the user can choose
+		 * to have function 1 probed before function 0.
+		 * Give whichever channel is the primary channel
+		 * the highest priority.
+		 */
+		primary_channel = (lahc->flags & AHC_PRIMARY_CHANNEL) + 'A';
+		value = -1;
+		if (lahc->channel == primary_channel)
+			value = 1;
+		break;
+	}
+#endif
+	case AHC_EISA:
+		if ((rahc->flags & AHC_BIOS_ENABLED) != 0) {
+			value = rahc->platform_data->bios_address
+			      - lahc->platform_data->bios_address; 
+		} else {
+			value = rahc->bsh.ioport
+			      - lahc->bsh.ioport; 
+		}
+		break;
+	default:
+		panic("ahc_softc_sort: invalid bus type");
+	}
+	return (value);
+}
+
+static void
+ahc_linux_setup_tag_info_global(char *p)
+{
+	int tags, i, j;
+
+	tags = simple_strtoul(p + 1, NULL, 0) & 0xff;
+	printf("Setting Global Tags= %d\n", tags);
+
+	for (i = 0; i < NUM_ELEMENTS(aic7xxx_tag_info); i++) {
+		for (j = 0; j < AHC_NUM_TARGETS; j++) {
+			aic7xxx_tag_info[i].tag_commands[j] = tags;
+		}
+	}
+}
+
+static void
+ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
+{
+
+	if ((instance >= 0) && (targ >= 0)
+	 && (instance < NUM_ELEMENTS(aic7xxx_tag_info))
+	 && (targ < AHC_NUM_TARGETS)) {
+		aic7xxx_tag_info[instance].tag_commands[targ] = value & 0xff;
+		if (bootverbose)
+			printf("tag_info[%d:%d] = %d\n", instance, targ, value);
+	}
+}
+
+static void
+ahc_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
+{
+
+	if ((instance >= 0)
+	 && (instance < NUM_ELEMENTS(aic7xxx_dv_settings))) {
+		aic7xxx_dv_settings[instance] = value;
+		if (bootverbose)
+			printf("dv[%d] = %d\n", instance, value);
+	}
+}
+
+/*
+ * Handle Linux boot parameters. This routine allows for assigning a value
+ * to a parameter with a ':' between the parameter and the value.
+ * ie. aic7xxx=stpwlev:1,extended
+ */
+static int
+aic7xxx_setup(char *s)
+{
+	int	i, n;
+	char   *p;
+	char   *end;
+
+	static struct {
+		const char *name;
+		uint32_t *flag;
+	} options[] = {
+		{ "extended", &aic7xxx_extended },
+		{ "no_reset", &aic7xxx_no_reset },
+		{ "verbose", &aic7xxx_verbose },
+		{ "allow_memio", &aic7xxx_allow_memio},
+#ifdef AHC_DEBUG
+		{ "debug", &ahc_debug },
+#endif
+		{ "reverse_scan", &aic7xxx_reverse_scan },
+		{ "no_probe", &aic7xxx_probe_eisa_vl },
+		{ "probe_eisa_vl", &aic7xxx_probe_eisa_vl },
+		{ "periodic_otag", &aic7xxx_periodic_otag },
+		{ "pci_parity", &aic7xxx_pci_parity },
+		{ "seltime", &aic7xxx_seltime },
+		{ "tag_info", NULL },
+		{ "global_tag_depth", NULL },
+		{ "dv", NULL }
+	};
+
+	end = strchr(s, '\0');
+
+	/*
+	 * XXX ia64 gcc isn't smart enough to know that NUM_ELEMENTS
+	 * will never be 0 in this case.
+	 */
+	n = 0;
+
+	while ((p = strsep(&s, ",.")) != NULL) {
+		if (*p == '\0')
+			continue;
+		for (i = 0; i < NUM_ELEMENTS(options); i++) {
+
+			n = strlen(options[i].name);
+			if (strncmp(options[i].name, p, n) == 0)
+				break;
+		}
+		if (i == NUM_ELEMENTS(options))
+			continue;
+
+		if (strncmp(p, "global_tag_depth", n) == 0) {
+			ahc_linux_setup_tag_info_global(p + n);
+		} else if (strncmp(p, "tag_info", n) == 0) {
+			s = aic_parse_brace_option("tag_info", p + n, end,
+			    2, ahc_linux_setup_tag_info, 0);
+		} else if (strncmp(p, "dv", n) == 0) {
+			s = aic_parse_brace_option("dv", p + n, end, 1,
+			    ahc_linux_setup_dv, 0);
+		} else if (p[n] == ':') {
+			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+		} else if (strncmp(p, "verbose", n) == 0) {
+			*(options[i].flag) = 1;
+		} else {
+			*(options[i].flag) ^= 0xFFFFFFFF;
+		}
+	}
+	return 1;
+}
+
+__setup("aic7xxx=", aic7xxx_setup);
+
+uint32_t aic7xxx_verbose;
+
+int
+ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
+{
+	char	 buf[80];
+	struct	 Scsi_Host *host;
+	char	*new_name;
+	u_long	 s;
+	u_int	 targ_offset;
+
+	template->name = ahc->description;
+	host = scsi_host_alloc(template, sizeof(struct ahc_softc *));
+	if (host == NULL)
+		return (ENOMEM);
+
+	*((struct ahc_softc **)host->hostdata) = ahc;
+	ahc_lock(ahc, &s);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	scsi_assign_lock(host, &ahc->platform_data->spin_lock);
+#elif AHC_SCSI_HAS_HOST_LOCK != 0
+	host->lock = &ahc->platform_data->spin_lock;
+#endif
+	ahc->platform_data->host = host;
+	host->can_queue = AHC_MAX_QUEUE;
+	host->cmd_per_lun = 2;
+	/* XXX No way to communicate the ID for multiple channels */
+	host->this_id = ahc->our_id;
+	host->irq = ahc->platform_data->irq;
+	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
+	host->max_lun = AHC_NUM_LUNS;
+	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
+	host->sg_tablesize = AHC_NSEG;
+	ahc_set_unit(ahc, ahc_linux_next_unit());
+	sprintf(buf, "scsi%d", host->host_no);
+	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (new_name != NULL) {
+		strcpy(new_name, buf);
+		ahc_set_name(ahc, new_name);
+	}
+	host->unique_id = ahc->unit;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	scsi_set_pci_device(host, ahc->dev_softc);
+#endif
+	ahc_linux_initialize_scsi_bus(ahc);
+	ahc_unlock(ahc, &s);
+	ahc->platform_data->dv_pid = kernel_thread(ahc_linux_dv_thread, ahc, 0);
+	ahc_lock(ahc, &s);
+	if (ahc->platform_data->dv_pid < 0) {
+		printf("%s: Failed to create DV thread, error= %d\n",
+		       ahc_name(ahc), ahc->platform_data->dv_pid);
+		return (-ahc->platform_data->dv_pid);
+	}
+	/*
+	 * Initially allocate *all* of our linux target objects
+	 * so that the DV thread will scan them all in parallel
+	 * just after driver initialization.  Any device that
+	 * does not exist will have its target object destroyed
+	 * by the selection timeout handler.  In the case of a
+	 * device that appears after the initial DV scan, async
+	 * negotiation will occur for the first command, and DV
+	 * will comence should that first command be successful.
+	 */
+	for (targ_offset = 0;
+	     targ_offset < host->max_id * (host->max_channel + 1);
+	     targ_offset++) {
+		u_int channel;
+		u_int target;
+
+		channel = 0;
+		target = targ_offset;
+		if (target > 7
+		 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 1;
+			target &= 0x7;
+		}
+		/*
+		 * Skip our own ID.  Some Compaq/HP storage devices
+		 * have enclosure management devices that respond to
+		 * single bit selection (i.e. selecting ourselves).
+		 * It is expected that either an external application
+		 * or a modified kernel will be used to probe this
+		 * ID if it is appropriate.  To accommodate these
+		 * installations, ahc_linux_alloc_target() will allocate
+		 * for our ID if asked to do so.
+		 */
+		if ((channel == 0 && target == ahc->our_id)
+		 || (channel == 1 && target == ahc->our_id_b))
+			continue;
+
+		ahc_linux_alloc_target(ahc, channel, target);
+	}
+	ahc_intr_enable(ahc, TRUE);
+	ahc_linux_start_dv(ahc);
+	ahc_unlock(ahc, &s);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	scsi_add_host(host, (ahc->dev_softc ? &ahc->dev_softc->dev : NULL)); /* XXX handle failure */
+	scsi_scan_host(host);
+#endif
+	return (0);
+}
+
+uint64_t
+ahc_linux_get_memsize(void)
+{
+	struct sysinfo si;
+
+	si_meminfo(&si);
+	return ((uint64_t)si.totalram << PAGE_SHIFT);
+}
+
+/*
+ * Find the smallest available unit number to use
+ * for a new device.  We don't just use a static
+ * count to handle the "repeated hot-(un)plug"
+ * scenario.
+ */
+static int
+ahc_linux_next_unit(void)
+{
+	struct ahc_softc *ahc;
+	int unit;
+
+	unit = 0;
+retry:
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		if (ahc->unit == unit) {
+			unit++;
+			goto retry;
+		}
+	}
+	return (unit);
+}
+
+/*
+ * Place the SCSI bus into a known state by either resetting it,
+ * or forcing transfer negotiations on the next command to any
+ * target.
+ */
+void
+ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc)
+{
+	int i;
+	int numtarg;
+
+	i = 0;
+	numtarg = 0;
+
+	if (aic7xxx_no_reset != 0)
+		ahc->flags &= ~(AHC_RESET_BUS_A|AHC_RESET_BUS_B);
+
+	if ((ahc->flags & AHC_RESET_BUS_A) != 0)
+		ahc_reset_channel(ahc, 'A', /*initiate_reset*/TRUE);
+	else
+		numtarg = (ahc->features & AHC_WIDE) ? 16 : 8;
+
+	if ((ahc->features & AHC_TWIN) != 0) {
+
+		if ((ahc->flags & AHC_RESET_BUS_B) != 0) {
+			ahc_reset_channel(ahc, 'B', /*initiate_reset*/TRUE);
+		} else {
+			if (numtarg == 0)
+				i = 8;
+			numtarg += 8;
+		}
+	}
+
+	/*
+	 * Force negotiation to async for all targets that
+	 * will not see an initial bus reset.
+	 */
+	for (; i < numtarg; i++) {
+		struct ahc_devinfo devinfo;
+		struct ahc_initiator_tinfo *tinfo;
+		struct ahc_tmode_tstate *tstate;
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+		tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+					    target_id, &tstate);
+		ahc_compile_devinfo(&devinfo, our_id, target_id,
+				    CAM_LUN_WILDCARD, channel, ROLE_INITIATOR);
+		ahc_update_neg_request(ahc, &devinfo, tstate,
+				       tinfo, AHC_NEG_ALWAYS);
+	}
+	/* Give the bus some time to recover */
+	if ((ahc->flags & (AHC_RESET_BUS_A|AHC_RESET_BUS_B)) != 0) {
+		ahc_linux_freeze_simq(ahc);
+		init_timer(&ahc->platform_data->reset_timer);
+		ahc->platform_data->reset_timer.data = (u_long)ahc;
+		ahc->platform_data->reset_timer.expires =
+		    jiffies + (AIC7XXX_RESET_DELAY * HZ)/1000;
+		ahc->platform_data->reset_timer.function =
+		    ahc_linux_release_simq;
+		add_timer(&ahc->platform_data->reset_timer);
+	}
+}
+
+int
+ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg)
+{
+
+	ahc->platform_data =
+	    malloc(sizeof(struct ahc_platform_data), M_DEVBUF, M_NOWAIT);
+	if (ahc->platform_data == NULL)
+		return (ENOMEM);
+	memset(ahc->platform_data, 0, sizeof(struct ahc_platform_data));
+	TAILQ_INIT(&ahc->platform_data->completeq);
+	TAILQ_INIT(&ahc->platform_data->device_runq);
+	ahc->platform_data->irq = AHC_LINUX_NOIRQ;
+	ahc->platform_data->hw_dma_mask = 0xFFFFFFFF;
+	ahc_lockinit(ahc);
+	ahc_done_lockinit(ahc);
+	init_timer(&ahc->platform_data->completeq_timer);
+	ahc->platform_data->completeq_timer.data = (u_long)ahc;
+	ahc->platform_data->completeq_timer.function =
+	    (ahc_linux_callback_t *)ahc_linux_thread_run_complete_queue;
+	init_MUTEX_LOCKED(&ahc->platform_data->eh_sem);
+	init_MUTEX_LOCKED(&ahc->platform_data->dv_sem);
+	init_MUTEX_LOCKED(&ahc->platform_data->dv_cmd_sem);
+	tasklet_init(&ahc->platform_data->runq_tasklet, ahc_runq_tasklet,
+		     (unsigned long)ahc);
+	ahc->seltime = (aic7xxx_seltime & 0x3) << 4;
+	ahc->seltime_b = (aic7xxx_seltime & 0x3) << 4;
+	if (aic7xxx_pci_parity == 0)
+		ahc->flags |= AHC_DISABLE_PCI_PERR;
+
+	return (0);
+}
+
+void
+ahc_platform_free(struct ahc_softc *ahc)
+{
+	struct ahc_linux_target *targ;
+	struct ahc_linux_device *dev;
+	int i, j;
+
+	if (ahc->platform_data != NULL) {
+		del_timer_sync(&ahc->platform_data->completeq_timer);
+		ahc_linux_kill_dv_thread(ahc);
+		tasklet_kill(&ahc->platform_data->runq_tasklet);
+		if (ahc->platform_data->host != NULL) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+			scsi_remove_host(ahc->platform_data->host);
+#endif
+			scsi_host_put(ahc->platform_data->host);
+		}
+
+		/* destroy all of the device and target objects */
+		for (i = 0; i < AHC_NUM_TARGETS; i++) {
+			targ = ahc->platform_data->targets[i];
+			if (targ != NULL) {
+				/* Keep target around through the loop. */
+				targ->refcount++;
+				for (j = 0; j < AHC_NUM_LUNS; j++) {
+
+					if (targ->devices[j] == NULL)
+						continue;
+					dev = targ->devices[j];
+					ahc_linux_free_device(ahc, dev);
+				}
+				/*
+				 * Forcibly free the target now that
+				 * all devices are gone.
+				 */
+				ahc_linux_free_target(ahc, targ);
+ 			}
+ 		}
+
+		if (ahc->platform_data->irq != AHC_LINUX_NOIRQ)
+			free_irq(ahc->platform_data->irq, ahc);
+		if (ahc->tag == BUS_SPACE_PIO
+		 && ahc->bsh.ioport != 0)
+			release_region(ahc->bsh.ioport, 256);
+		if (ahc->tag == BUS_SPACE_MEMIO
+		 && ahc->bsh.maddr != NULL) {
+			iounmap(ahc->bsh.maddr);
+			release_mem_region(ahc->platform_data->mem_busaddr,
+					   0x1000);
+		}
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+		/*
+		 * In 2.4 we detach from the scsi midlayer before the PCI
+		 * layer invokes our remove callback.  No per-instance
+		 * detach is provided, so we must reach inside the PCI
+		 * subsystem's internals and detach our driver manually.
+		 */
+		if (ahc->dev_softc != NULL)
+			ahc->dev_softc->driver = NULL;
+#endif
+		free(ahc->platform_data, M_DEVBUF);
+	}
+}
+
+void
+ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc_platform_abort_scbs(ahc, SCB_GET_TARGET(ahc, scb),
+				SCB_GET_CHANNEL(ahc, scb),
+				SCB_GET_LUN(scb), SCB_LIST_NULL,
+				ROLE_UNKNOWN, CAM_REQUEUE_REQ);
+}
+
+void
+ahc_platform_set_tags(struct ahc_softc *ahc, struct ahc_devinfo *devinfo,
+		      ahc_queue_alg alg)
+{
+	struct ahc_linux_device *dev;
+	int was_queuing;
+	int now_queuing;
+
+	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
+				   devinfo->target,
+				   devinfo->lun, /*alloc*/FALSE);
+	if (dev == NULL)
+		return;
+	was_queuing = dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED);
+	switch (alg) {
+	default:
+	case AHC_QUEUE_NONE:
+		now_queuing = 0;
+		break; 
+	case AHC_QUEUE_BASIC:
+		now_queuing = AHC_DEV_Q_BASIC;
+		break;
+	case AHC_QUEUE_TAGGED:
+		now_queuing = AHC_DEV_Q_TAGGED;
+		break;
+	}
+	if ((dev->flags & AHC_DEV_FREEZE_TIL_EMPTY) == 0
+	 && (was_queuing != now_queuing)
+	 && (dev->active != 0)) {
+		dev->flags |= AHC_DEV_FREEZE_TIL_EMPTY;
+		dev->qfrozen++;
+	}
+
+	dev->flags &= ~(AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED|AHC_DEV_PERIODIC_OTAG);
+	if (now_queuing) {
+		u_int usertags;
+
+		usertags = ahc_linux_user_tagdepth(ahc, devinfo);
+		if (!was_queuing) {
+			/*
+			 * Start out agressively and allow our
+			 * dynamic queue depth algorithm to take
+			 * care of the rest.
+			 */
+			dev->maxtags = usertags;
+			dev->openings = dev->maxtags - dev->active;
+		}
+		if (dev->maxtags == 0) {
+			/*
+			 * Queueing is disabled by the user.
+			 */
+			dev->openings = 1;
+		} else if (alg == AHC_QUEUE_TAGGED) {
+			dev->flags |= AHC_DEV_Q_TAGGED;
+			if (aic7xxx_periodic_otag != 0)
+				dev->flags |= AHC_DEV_PERIODIC_OTAG;
+		} else
+			dev->flags |= AHC_DEV_Q_BASIC;
+	} else {
+		/* We can only have one opening. */
+		dev->maxtags = 0;
+		dev->openings =  1 - dev->active;
+	}
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	if (dev->scsi_device != NULL) {
+		switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
+		case AHC_DEV_Q_BASIC:
+			scsi_adjust_queue_depth(dev->scsi_device,
+						MSG_SIMPLE_TASK,
+						dev->openings + dev->active);
+			break;
+		case AHC_DEV_Q_TAGGED:
+			scsi_adjust_queue_depth(dev->scsi_device,
+						MSG_ORDERED_TASK,
+						dev->openings + dev->active);
+			break;
+		default:
+			/*
+			 * We allow the OS to queue 2 untagged transactions to
+			 * us at any time even though we can only execute them
+			 * serially on the controller/device.  This should
+			 * remove some latency.
+			 */
+			scsi_adjust_queue_depth(dev->scsi_device,
+						/*NON-TAGGED*/0,
+						/*queue depth*/2);
+			break;
+		}
+	}
+#endif
+}
+
+int
+ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel,
+			int lun, u_int tag, role_t role, uint32_t status)
+{
+	int chan;
+	int maxchan;
+	int targ;
+	int maxtarg;
+	int clun;
+	int maxlun;
+	int count;
+
+	if (tag != SCB_LIST_NULL)
+		return (0);
+
+	chan = 0;
+	if (channel != ALL_CHANNELS) {
+		chan = channel - 'A';
+		maxchan = chan + 1;
+	} else {
+		maxchan = (ahc->features & AHC_TWIN) ? 2 : 1;
+	}
+	targ = 0;
+	if (target != CAM_TARGET_WILDCARD) {
+		targ = target;
+		maxtarg = targ + 1;
+	} else {
+		maxtarg = (ahc->features & AHC_WIDE) ? 16 : 8;
+	}
+	clun = 0;
+	if (lun != CAM_LUN_WILDCARD) {
+		clun = lun;
+		maxlun = clun + 1;
+	} else {
+		maxlun = AHC_NUM_LUNS;
+	}
+
+	count = 0;
+	for (; chan < maxchan; chan++) {
+
+		for (; targ < maxtarg; targ++) {
+
+			for (; clun < maxlun; clun++) {
+				struct ahc_linux_device *dev;
+				struct ahc_busyq *busyq;
+				struct ahc_cmd *acmd;
+
+				dev = ahc_linux_get_device(ahc, chan,
+							   targ, clun,
+							   /*alloc*/FALSE);
+				if (dev == NULL)
+					continue;
+
+				busyq = &dev->busyq;
+				while ((acmd = TAILQ_FIRST(busyq)) != NULL) {
+					Scsi_Cmnd *cmd;
+
+					cmd = &acmd_scsi_cmd(acmd);
+					TAILQ_REMOVE(busyq, acmd,
+						     acmd_links.tqe);
+					count++;
+					cmd->result = status << 16;
+					ahc_linux_queue_cmd_complete(ahc, cmd);
+				}
+			}
+		}
+	}
+
+	return (count);
+}
+
+static void
+ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc)
+{
+	u_long flags;
+
+	ahc_lock(ahc, &flags);
+	del_timer(&ahc->platform_data->completeq_timer);
+	ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER;
+	ahc_linux_run_complete_queue(ahc);
+	ahc_unlock(ahc, &flags);
+}
+
+static void
+ahc_linux_start_dv(struct ahc_softc *ahc)
+{
+
+	/*
+	 * Freeze the simq and signal ahc_linux_queue to not let any
+	 * more commands through.
+	 */
+	if ((ahc->platform_data->flags & AHC_DV_ACTIVE) == 0) {
+#ifdef AHC_DEBUG
+		if (ahc_debug & AHC_SHOW_DV)
+			printf("%s: Waking DV thread\n", ahc_name(ahc));
+#endif
+
+		ahc->platform_data->flags |= AHC_DV_ACTIVE;
+		ahc_linux_freeze_simq(ahc);
+
+		/* Wake up the DV kthread */
+		up(&ahc->platform_data->dv_sem);
+	}
+}
+
+static void
+ahc_linux_kill_dv_thread(struct ahc_softc *ahc)
+{
+	u_long s;
+
+	ahc_lock(ahc, &s);
+	if (ahc->platform_data->dv_pid != 0) {
+		ahc->platform_data->flags |= AHC_DV_SHUTDOWN;
+		ahc_unlock(ahc, &s);
+		up(&ahc->platform_data->dv_sem);
+
+		/*
+		 * Use the eh_sem as an indicator that the
+		 * dv thread is exiting.  Note that the dv
+		 * thread must still return after performing
+		 * the up on our semaphore before it has
+		 * completely exited this module.  Unfortunately,
+		 * there seems to be no easy way to wait for the
+		 * exit of a thread for which you are not the
+		 * parent (dv threads are parented by init).
+		 * Cross your fingers...
+		 */
+		down(&ahc->platform_data->eh_sem);
+
+		/*
+		 * Mark the dv thread as already dead.  This
+		 * avoids attempting to kill it a second time.
+		 * This is necessary because we must kill the
+		 * DV thread before calling ahc_free() in the
+		 * module shutdown case to avoid bogus locking
+		 * in the SCSI mid-layer, but we ahc_free() is
+		 * called without killing the DV thread in the
+		 * instance detach case, so ahc_platform_free()
+		 * calls us again to verify that the DV thread
+		 * is dead.
+		 */
+		ahc->platform_data->dv_pid = 0;
+	} else {
+		ahc_unlock(ahc, &s);
+	}
+}
+
+static int
+ahc_linux_dv_thread(void *data)
+{
+	struct	ahc_softc *ahc;
+	int	target;
+	u_long	s;
+
+	ahc = (struct ahc_softc *)data;
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV)
+		printf("Launching DV Thread\n");
+#endif
+
+	/*
+	 * Complete thread creation.
+	 */
+	lock_kernel();
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * Don't care about any signals.
+	 */
+	siginitsetinv(&current->blocked, 0);
+
+	daemonize();
+	sprintf(current->comm, "ahc_dv_%d", ahc->unit);
+#else
+	daemonize("ahc_dv_%d", ahc->unit);
+	current->flags |= PF_FREEZE;
+#endif
+	unlock_kernel();
+
+	while (1) {
+		/*
+		 * Use down_interruptible() rather than down() to
+		 * avoid inclusion in the load average.
+		 */
+		down_interruptible(&ahc->platform_data->dv_sem);
+
+		/* Check to see if we've been signaled to exit */
+		ahc_lock(ahc, &s);
+		if ((ahc->platform_data->flags & AHC_DV_SHUTDOWN) != 0) {
+			ahc_unlock(ahc, &s);
+			break;
+		}
+		ahc_unlock(ahc, &s);
+
+#ifdef AHC_DEBUG
+		if (ahc_debug & AHC_SHOW_DV)
+			printf("%s: Beginning Domain Validation\n",
+			       ahc_name(ahc));
+#endif
+
+		/*
+		 * Wait for any pending commands to drain before proceeding.
+		 */
+		ahc_lock(ahc, &s);
+		while (LIST_FIRST(&ahc->pending_scbs) != NULL) {
+			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_EMPTY;
+			ahc_unlock(ahc, &s);
+			down_interruptible(&ahc->platform_data->dv_sem);
+			ahc_lock(ahc, &s);
+		}
+
+		/*
+		 * Wait for the SIMQ to be released so that DV is the
+		 * only reason the queue is frozen.
+		 */
+		while (AHC_DV_SIMQ_FROZEN(ahc) == 0) {
+			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE;
+			ahc_unlock(ahc, &s);
+			down_interruptible(&ahc->platform_data->dv_sem);
+			ahc_lock(ahc, &s);
+		}
+		ahc_unlock(ahc, &s);
+
+		for (target = 0; target < AHC_NUM_TARGETS; target++)
+			ahc_linux_dv_target(ahc, target);
+
+		ahc_lock(ahc, &s);
+		ahc->platform_data->flags &= ~AHC_DV_ACTIVE;
+		ahc_unlock(ahc, &s);
+
+		/*
+		 * Release the SIMQ so that normal commands are
+		 * allowed to continue on the bus.
+		 */
+		ahc_linux_release_simq((u_long)ahc);
+	}
+	up(&ahc->platform_data->eh_sem);
+	return (0);
+}
+
+#define AHC_LINUX_DV_INQ_SHORT_LEN	36
+#define AHC_LINUX_DV_INQ_LEN		256
+#define AHC_LINUX_DV_TIMEOUT		(HZ / 4)
+
+#define AHC_SET_DV_STATE(ahc, targ, newstate) \
+	ahc_set_dv_state(ahc, targ, newstate, __LINE__)
+
+static __inline void
+ahc_set_dv_state(struct ahc_softc *ahc, struct ahc_linux_target *targ,
+		 ahc_dv_state newstate, u_int line)
+{
+	ahc_dv_state oldstate;
+
+	oldstate = targ->dv_state;
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV)
+		printf("%s:%d: Going from state %d to state %d\n",
+		       ahc_name(ahc), line, oldstate, newstate);
+#endif
+
+	if (oldstate == newstate)
+		targ->dv_state_retry++;
+	else
+		targ->dv_state_retry = 0;
+	targ->dv_state = newstate;
+}
+
+static void
+ahc_linux_dv_target(struct ahc_softc *ahc, u_int target_offset)
+{
+	struct	 ahc_devinfo devinfo;
+	struct	 ahc_linux_target *targ;
+	struct	 scsi_cmnd *cmd;
+	struct	 scsi_device *scsi_dev;
+	struct	 scsi_sense_data *sense;
+	uint8_t *buffer;
+	u_long	 s;
+	u_int	 timeout;
+	int	 echo_size;
+
+	sense = NULL;
+	buffer = NULL;
+	echo_size = 0;
+	ahc_lock(ahc, &s);
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL || (targ->flags & AHC_DV_REQUIRED) == 0) {
+		ahc_unlock(ahc, &s);
+		return;
+	}
+	ahc_compile_devinfo(&devinfo,
+			    targ->channel == 0 ? ahc->our_id : ahc->our_id_b,
+			    targ->target, /*lun*/0, targ->channel + 'A',
+			    ROLE_INITIATOR);
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, &devinfo);
+		printf("Performing DV\n");
+	}
+#endif
+
+	ahc_unlock(ahc, &s);
+
+	cmd = malloc(sizeof(struct scsi_cmnd), M_DEVBUF, M_WAITOK);
+	scsi_dev = malloc(sizeof(struct scsi_device), M_DEVBUF, M_WAITOK);
+	scsi_dev->host = ahc->platform_data->host;
+	scsi_dev->id = devinfo.target;
+	scsi_dev->lun = devinfo.lun;
+	scsi_dev->channel = devinfo.channel - 'A';
+	ahc->platform_data->dv_scsi_dev = scsi_dev;
+
+	AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_SHORT_ASYNC);
+
+	while (targ->dv_state != AHC_DV_STATE_EXIT) {
+		timeout = AHC_LINUX_DV_TIMEOUT;
+		switch (targ->dv_state) {
+		case AHC_DV_STATE_INQ_SHORT_ASYNC:
+		case AHC_DV_STATE_INQ_ASYNC:
+		case AHC_DV_STATE_INQ_ASYNC_VERIFY:
+			/*
+			 * Set things to async narrow to reduce the
+			 * chance that the INQ will fail.
+			 */
+			ahc_lock(ahc, &s);
+			ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0,
+					 AHC_TRANS_GOAL, /*paused*/FALSE);
+			ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+				      AHC_TRANS_GOAL, /*paused*/FALSE);
+			ahc_unlock(ahc, &s);
+			timeout = 10 * HZ;
+			targ->flags &= ~AHC_INQ_VALID;
+			/* FALLTHROUGH */
+		case AHC_DV_STATE_INQ_VERIFY:
+		{
+			u_int inq_len;
+
+			if (targ->dv_state == AHC_DV_STATE_INQ_SHORT_ASYNC)
+				inq_len = AHC_LINUX_DV_INQ_SHORT_LEN;
+			else
+				inq_len = targ->inq_data->additional_length + 5;
+			ahc_linux_dv_inq(ahc, cmd, &devinfo, targ, inq_len);
+			break;
+		}
+		case AHC_DV_STATE_TUR:
+		case AHC_DV_STATE_BUSY:
+			timeout = 5 * HZ;
+			ahc_linux_dv_tur(ahc, cmd, &devinfo);
+			break;
+		case AHC_DV_STATE_REBD:
+			ahc_linux_dv_rebd(ahc, cmd, &devinfo, targ);
+			break;
+		case AHC_DV_STATE_WEB:
+			ahc_linux_dv_web(ahc, cmd, &devinfo, targ);
+			break;
+
+		case AHC_DV_STATE_REB:
+			ahc_linux_dv_reb(ahc, cmd, &devinfo, targ);
+			break;
+
+		case AHC_DV_STATE_SU:
+			ahc_linux_dv_su(ahc, cmd, &devinfo, targ);
+			timeout = 50 * HZ;
+			break;
+
+		default:
+			ahc_print_devinfo(ahc, &devinfo);
+			printf("Unknown DV state %d\n", targ->dv_state);
+			goto out;
+		}
+
+		/* Queue the command and wait for it to complete */
+		/* Abuse eh_timeout in the scsi_cmnd struct for our purposes */
+		init_timer(&cmd->eh_timeout);
+#ifdef AHC_DEBUG
+		if ((ahc_debug & AHC_SHOW_MESSAGES) != 0)
+			/*
+			 * All of the printfs during negotiation
+			 * really slow down the negotiation.
+			 * Add a bit of time just to be safe.
+			 */
+			timeout += HZ;
+#endif
+		scsi_add_timer(cmd, timeout, ahc_linux_dv_timeout);
+		/*
+		 * In 2.5.X, it is assumed that all calls from the
+		 * "midlayer" (which we are emulating) will have the
+		 * ahc host lock held.  For other kernels, the
+		 * io_request_lock must be held.
+		 */
+#if AHC_SCSI_HAS_HOST_LOCK != 0
+		ahc_lock(ahc, &s);
+#else
+		spin_lock_irqsave(&io_request_lock, s);
+#endif
+		ahc_linux_queue(cmd, ahc_linux_dv_complete);
+#if AHC_SCSI_HAS_HOST_LOCK != 0
+		ahc_unlock(ahc, &s);
+#else
+		spin_unlock_irqrestore(&io_request_lock, s);
+#endif
+		down_interruptible(&ahc->platform_data->dv_cmd_sem);
+		/*
+		 * Wait for the SIMQ to be released so that DV is the
+		 * only reason the queue is frozen.
+		 */
+		ahc_lock(ahc, &s);
+		while (AHC_DV_SIMQ_FROZEN(ahc) == 0) {
+			ahc->platform_data->flags |= AHC_DV_WAIT_SIMQ_RELEASE;
+			ahc_unlock(ahc, &s);
+			down_interruptible(&ahc->platform_data->dv_sem);
+			ahc_lock(ahc, &s);
+		}
+		ahc_unlock(ahc, &s);
+
+		ahc_linux_dv_transition(ahc, cmd, &devinfo, targ);
+	}
+
+out:
+	if ((targ->flags & AHC_INQ_VALID) != 0
+	 && ahc_linux_get_device(ahc, devinfo.channel - 'A',
+				 devinfo.target, devinfo.lun,
+				 /*alloc*/FALSE) == NULL) {
+		/*
+		 * The DV state machine failed to configure this device.  
+		 * This is normal if DV is disabled.  Since we have inquiry
+		 * data, filter it and use the "optimistic" negotiation
+		 * parameters found in the inquiry string.
+		 */
+		ahc_linux_filter_inquiry(ahc, &devinfo);
+		if ((targ->flags & (AHC_BASIC_DV|AHC_ENHANCED_DV)) != 0) {
+			ahc_print_devinfo(ahc, &devinfo);
+			printf("DV failed to configure device.  "
+			       "Please file a bug report against "
+			       "this driver.\n");
+		}
+	}
+
+	if (cmd != NULL)
+		free(cmd, M_DEVBUF);
+
+	if (ahc->platform_data->dv_scsi_dev != NULL) {
+		free(ahc->platform_data->dv_scsi_dev, M_DEVBUF);
+		ahc->platform_data->dv_scsi_dev = NULL;
+	}
+
+	ahc_lock(ahc, &s);
+	if (targ->dv_buffer != NULL) {
+		free(targ->dv_buffer, M_DEVBUF);
+		targ->dv_buffer = NULL;
+	}
+	if (targ->dv_buffer1 != NULL) {
+		free(targ->dv_buffer1, M_DEVBUF);
+		targ->dv_buffer1 = NULL;
+	}
+	targ->flags &= ~AHC_DV_REQUIRED;
+	if (targ->refcount == 0)
+		ahc_linux_free_target(ahc, targ);
+	ahc_unlock(ahc, &s);
+}
+
+static void
+ahc_linux_dv_transition(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+			struct ahc_devinfo *devinfo,
+			struct ahc_linux_target *targ)
+{
+	u_int32_t status;
+
+	status = aic_error_action(cmd, targ->inq_data,
+				  ahc_cmd_get_transaction_status(cmd),
+				  ahc_cmd_get_scsi_status(cmd));
+	
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Entering ahc_linux_dv_transition, state= %d, "
+		       "status= 0x%x, cmd->result= 0x%x\n", targ->dv_state,
+		       status, cmd->result);
+	}
+#endif
+
+	switch (targ->dv_state) {
+	case AHC_DV_STATE_INQ_SHORT_ASYNC:
+	case AHC_DV_STATE_INQ_ASYNC:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+			if ((status & SS_ERRMASK) == EBUSY)
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+	case AHC_DV_STATE_INQ_ASYNC_VERIFY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			u_int xportflags;
+			u_int spi3data;
+
+			if (memcmp(targ->inq_data, targ->dv_buffer,
+				   AHC_LINUX_DV_INQ_LEN) != 0) {
+				/*
+				 * Inquiry data must have changed.
+				 * Try from the top again.
+				 */
+				AHC_SET_DV_STATE(ahc, targ,
+						 AHC_DV_STATE_INQ_SHORT_ASYNC);
+				break;
+			}
+
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state+1);
+			targ->flags |= AHC_INQ_VALID;
+			if (ahc_linux_user_dv_setting(ahc) == 0)
+				break;
+
+			xportflags = targ->inq_data->flags;
+			if ((xportflags & (SID_Sync|SID_WBus16)) == 0)
+				break;
+
+			spi3data = targ->inq_data->spi3data;
+			switch (spi3data & SID_SPI_CLOCK_DT_ST) {
+			default:
+			case SID_SPI_CLOCK_ST:
+				/* Assume only basic DV is supported. */
+				targ->flags |= AHC_BASIC_DV;
+				break;
+			case SID_SPI_CLOCK_DT:
+			case SID_SPI_CLOCK_DT_ST:
+				targ->flags |= AHC_ENHANCED_DV;
+				break;
+			}
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+
+			if ((status & SS_ERRMASK) == EBUSY)
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+	case AHC_DV_STATE_INQ_VERIFY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+
+			if (memcmp(targ->inq_data, targ->dv_buffer,
+				   AHC_LINUX_DV_INQ_LEN) == 0) {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+				break;
+			}
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				int i;
+
+				ahc_print_devinfo(ahc, devinfo);
+				printf("Inquiry buffer mismatch:");
+				for (i = 0; i < AHC_LINUX_DV_INQ_LEN; i++) {
+					if ((i & 0xF) == 0)
+						printf("\n        ");
+					printf("0x%x:0x0%x ",
+					       ((uint8_t *)targ->inq_data)[i], 
+					       targ->dv_buffer[i]);
+				}
+				printf("\n");
+			}
+#endif
+
+			if (ahc_linux_fallback(ahc, devinfo) != 0) {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+				break;
+			}
+			/*
+			 * Do not count "falling back"
+			 * against our retries.
+			 */
+			targ->dv_state_retry = 0;
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahc_linux_fallback(ahc, devinfo) != 0) {
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			} else if ((status & SS_ERRMASK) == EBUSY)
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
+			if (targ->dv_state_retry < 10)
+				break;
+			/* FALLTHROUGH */
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("Failed DV inquiry, skipping\n");
+			}
+#endif
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_TUR:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			if ((targ->flags & AHC_BASIC_DV) != 0) {
+				ahc_linux_filter_inquiry(ahc, devinfo);
+				AHC_SET_DV_STATE(ahc, targ,
+						 AHC_DV_STATE_INQ_VERIFY);
+			} else if ((targ->flags & AHC_ENHANCED_DV) != 0) {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REBD);
+			} else {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			}
+			break;
+		case SS_RETRY:
+		case SS_TUR:
+			if ((status & SS_ERRMASK) == EBUSY) {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_BUSY);
+				break;
+			}
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahc_linux_fallback(ahc, devinfo) != 0) {
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			}
+			if (targ->dv_state_retry >= 10) {
+#ifdef AHC_DEBUG
+				if (ahc_debug & AHC_SHOW_DV) {
+					ahc_print_devinfo(ahc, devinfo);
+					printf("DV TUR reties exhausted\n");
+				}
+#endif
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+				break;
+			}
+			if (status & SSQ_DELAY)
+				ssleep(1);
+
+			break;
+		case SS_START:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_SU);
+			break;
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_REBD:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		{
+			uint32_t echo_size;
+
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB);
+			echo_size = scsi_3btoul(&targ->dv_buffer[1]);
+			echo_size &= 0x1FFF;
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("Echo buffer size= %d\n", echo_size);
+			}
+#endif
+			if (echo_size == 0) {
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+				break;
+			}
+
+			/* Generate the buffer pattern */
+			targ->dv_echo_size = echo_size;
+			ahc_linux_generate_dv_pattern(targ);
+			/*
+			 * Setup initial negotiation values.
+			 */
+			ahc_linux_filter_inquiry(ahc, devinfo);
+			break;
+		}
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ)
+				targ->dv_state_retry--;
+			if (targ->dv_state_retry <= 10)
+				break;
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("DV REBD reties exhausted\n");
+			}
+#endif
+			/* FALLTHROUGH */
+		case SS_FATAL:
+		default:
+			/*
+			 * Setup initial negotiation values
+			 * and try level 1 DV.
+			 */
+			ahc_linux_filter_inquiry(ahc, devinfo);
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_INQ_VERIFY);
+			targ->dv_echo_size = 0;
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_WEB:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_REB);
+			break;
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahc_linux_fallback(ahc, devinfo) != 0) {
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_EXIT);
+					break;
+				}
+				/*
+				 * Do not count "falling back"
+				 * against our retries.
+				 */
+				targ->dv_state_retry = 0;
+			}
+			if (targ->dv_state_retry <= 10)
+				break;
+			/* FALLTHROUGH */
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("DV WEB reties exhausted\n");
+			}
+#endif
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_REB:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+			if (memcmp(targ->dv_buffer, targ->dv_buffer1,
+				   targ->dv_echo_size) != 0) {
+				if (ahc_linux_fallback(ahc, devinfo) != 0)
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_EXIT);
+				else
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_WEB);
+				break;
+			}
+			
+			if (targ->dv_buffer != NULL) {
+				free(targ->dv_buffer, M_DEVBUF);
+				targ->dv_buffer = NULL;
+			}
+			if (targ->dv_buffer1 != NULL) {
+				free(targ->dv_buffer1, M_DEVBUF);
+				targ->dv_buffer1 = NULL;
+			}
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if ((status & SSQ_FALLBACK) != 0) {
+				if (ahc_linux_fallback(ahc, devinfo) != 0) {
+					AHC_SET_DV_STATE(ahc, targ,
+							 AHC_DV_STATE_EXIT);
+					break;
+				}
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_WEB);
+			}
+			if (targ->dv_state_retry <= 10) {
+				if ((status & (SSQ_DELAY_RANDOM|SSQ_DELAY))!= 0)
+					msleep(ahc->our_id*1000/10);
+				break;
+			}
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_DV) {
+				ahc_print_devinfo(ahc, devinfo);
+				printf("DV REB reties exhausted\n");
+			}
+#endif
+			/* FALLTHROUGH */
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_SU:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	case AHC_DV_STATE_BUSY:
+		switch (status & SS_MASK) {
+		case SS_NOP:
+		case SS_INQ_REFRESH:
+			AHC_SET_DV_STATE(ahc, targ,
+					 AHC_DV_STATE_INQ_SHORT_ASYNC);
+			break;
+		case SS_TUR:
+		case SS_RETRY:
+			AHC_SET_DV_STATE(ahc, targ, targ->dv_state);
+			if (ahc_cmd_get_transaction_status(cmd)
+			 == CAM_REQUEUE_REQ) {
+				targ->dv_state_retry--;
+			} else if (targ->dv_state_retry < 60) {
+				if ((status & SSQ_DELAY) != 0)
+					ssleep(1);
+			} else {
+#ifdef AHC_DEBUG
+				if (ahc_debug & AHC_SHOW_DV) {
+					ahc_print_devinfo(ahc, devinfo);
+					printf("DV BUSY reties exhausted\n");
+				}
+#endif
+				AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			}
+			break;
+		default:
+			AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+			break;
+		}
+		break;
+
+	default:
+		printf("%s: Invalid DV completion state %d\n", ahc_name(ahc),
+		       targ->dv_state);
+		AHC_SET_DV_STATE(ahc, targ, AHC_DV_STATE_EXIT);
+		break;
+	}
+}
+
+static void
+ahc_linux_dv_fill_cmd(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		      struct ahc_devinfo *devinfo)
+{
+	memset(cmd, 0, sizeof(struct scsi_cmnd));
+	cmd->device = ahc->platform_data->dv_scsi_dev;
+	cmd->scsi_done = ahc_linux_dv_complete;
+}
+
+/*
+ * Synthesize an inquiry command.  On the return trip, it'll be
+ * sniffed and the device transfer settings set for us.
+ */
+static void
+ahc_linux_dv_inq(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ,
+		 u_int request_length)
+{
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending INQ\n");
+	}
+#endif
+	if (targ->inq_data == NULL)
+		targ->inq_data = malloc(AHC_LINUX_DV_INQ_LEN,
+					M_DEVBUF, M_WAITOK);
+	if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC) {
+		if (targ->dv_buffer != NULL)
+			free(targ->dv_buffer, M_DEVBUF);
+		targ->dv_buffer = malloc(AHC_LINUX_DV_INQ_LEN,
+					 M_DEVBUF, M_WAITOK);
+	}
+
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = INQUIRY;
+	cmd->cmnd[4] = request_length;
+	cmd->request_bufflen = request_length;
+	if (targ->dv_state > AHC_DV_STATE_INQ_ASYNC)
+		cmd->request_buffer = targ->dv_buffer;
+	else
+		cmd->request_buffer = targ->inq_data;
+	memset(cmd->request_buffer, 0, AHC_LINUX_DV_INQ_LEN);
+}
+
+static void
+ahc_linux_dv_tur(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		 struct ahc_devinfo *devinfo)
+{
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending TUR\n");
+	}
+#endif
+	/* Do a TUR to clear out any non-fatal transitional state */
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = TEST_UNIT_READY;
+}
+
+#define AHC_REBD_LEN 4
+
+static void
+ahc_linux_dv_rebd(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
+{
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending REBD\n");
+	}
+#endif
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	targ->dv_buffer = malloc(AHC_REBD_LEN, M_DEVBUF, M_WAITOK);
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = READ_BUFFER;
+	cmd->cmnd[1] = 0x0b;
+	scsi_ulto3b(AHC_REBD_LEN, &cmd->cmnd[6]);
+	cmd->request_bufflen = AHC_REBD_LEN;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer;
+}
+
+static void
+ahc_linux_dv_web(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
+{
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending WEB\n");
+	}
+#endif
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_WRITE;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = WRITE_BUFFER;
+	cmd->cmnd[1] = 0x0a;
+	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
+	cmd->request_bufflen = targ->dv_echo_size;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer;
+}
+
+static void
+ahc_linux_dv_reb(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		 struct ahc_devinfo *devinfo, struct ahc_linux_target *targ)
+{
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending REB\n");
+	}
+#endif
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_READ;
+	cmd->cmd_len = 10;
+	cmd->cmnd[0] = READ_BUFFER;
+	cmd->cmnd[1] = 0x0a;
+	scsi_ulto3b(targ->dv_echo_size, &cmd->cmnd[6]);
+	cmd->request_bufflen = targ->dv_echo_size;
+	cmd->underflow = cmd->request_bufflen;
+	cmd->request_buffer = targ->dv_buffer1;
+}
+
+static void
+ahc_linux_dv_su(struct ahc_softc *ahc, struct scsi_cmnd *cmd,
+		struct ahc_devinfo *devinfo,
+		struct ahc_linux_target *targ)
+{
+	u_int le;
+
+	le = SID_IS_REMOVABLE(targ->inq_data) ? SSS_LOEJ : 0;
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Sending SU\n");
+	}
+#endif
+	ahc_linux_dv_fill_cmd(ahc, cmd, devinfo);
+	cmd->sc_data_direction = SCSI_DATA_NONE;
+	cmd->cmd_len = 6;
+	cmd->cmnd[0] = START_STOP_UNIT;
+	cmd->cmnd[4] = le | SSS_START;
+}
+
+static int
+ahc_linux_fallback(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	struct	ahc_linux_target *targ;
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_transinfo *goal;
+	struct	ahc_tmode_tstate *tstate;
+	struct	ahc_syncrate *syncrate;
+	u_long	s;
+	u_int	width;
+	u_int	period;
+	u_int	offset;
+	u_int	ppr_options;
+	u_int	cur_speed;
+	u_int	wide_speed;
+	u_int	narrow_speed;
+	u_int	fallback_speed;
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		ahc_print_devinfo(ahc, devinfo);
+		printf("Trying to fallback\n");
+	}
+#endif
+	ahc_lock(ahc, &s);
+	targ = ahc->platform_data->targets[devinfo->target_offset];
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	goal = &tinfo->goal;
+	width = goal->width;
+	period = goal->period;
+	offset = goal->offset;
+	ppr_options = goal->ppr_options;
+	if (offset == 0)
+		period = AHC_ASYNC_XFER_PERIOD;
+	if (targ->dv_next_narrow_period == 0)
+		targ->dv_next_narrow_period = MAX(period, AHC_SYNCRATE_ULTRA2);
+	if (targ->dv_next_wide_period == 0)
+		targ->dv_next_wide_period = period;
+	if (targ->dv_max_width == 0)
+		targ->dv_max_width = width;
+	if (targ->dv_max_ppr_options == 0)
+		targ->dv_max_ppr_options = ppr_options;
+	if (targ->dv_last_ppr_options == 0)
+		targ->dv_last_ppr_options = ppr_options;
+
+	cur_speed = aic_calc_speed(width, period, offset, AHC_SYNCRATE_MIN);
+	wide_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_16_BIT,
+					  targ->dv_next_wide_period,
+					  MAX_OFFSET,
+					  AHC_SYNCRATE_MIN);
+	narrow_speed = aic_calc_speed(MSG_EXT_WDTR_BUS_8_BIT,
+					    targ->dv_next_narrow_period,
+					    MAX_OFFSET,
+					    AHC_SYNCRATE_MIN);
+	fallback_speed = aic_calc_speed(width, period+1, offset,
+					AHC_SYNCRATE_MIN);
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		printf("cur_speed= %d, wide_speed= %d, narrow_speed= %d, "
+		       "fallback_speed= %d\n", cur_speed, wide_speed,
+		       narrow_speed, fallback_speed);
+	}
+#endif
+
+	if (cur_speed > 160000) {
+		/*
+		 * Paced/DT/IU_REQ only transfer speeds.  All we
+		 * can do is fallback in terms of syncrate.
+		 */
+		period++;
+	} else if (cur_speed > 80000) {
+		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+			/*
+			 * Try without IU_REQ as it may be confusing
+			 * an expander.
+			 */
+			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+		} else {
+			/*
+			 * Paced/DT only transfer speeds.  All we
+			 * can do is fallback in terms of syncrate.
+			 */
+			period++;
+			ppr_options = targ->dv_max_ppr_options;
+		}
+	} else if (cur_speed > 3300) {
+
+		/*
+		 * In this range we the following
+		 * options ordered from highest to
+		 * lowest desireability:
+		 *
+		 * o Wide/DT
+		 * o Wide/non-DT
+		 * o Narrow at a potentally higher sync rate.
+		 *
+		 * All modes are tested with and without IU_REQ
+		 * set since using IUs may confuse an expander.
+		 */
+		if ((ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
+
+			ppr_options &= ~MSG_EXT_PPR_IU_REQ;
+		} else if ((ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
+			/*
+			 * Try going non-DT.
+			 */
+			ppr_options = targ->dv_max_ppr_options;
+			ppr_options &= ~MSG_EXT_PPR_DT_REQ;
+		} else if (targ->dv_last_ppr_options != 0) {
+			/*
+			 * Try without QAS or any other PPR options.
+			 * We may need a non-PPR message to work with
+			 * an expander.  We look at the "last PPR options"
+			 * so we will perform this fallback even if the
+			 * target responded to our PPR negotiation with
+			 * no option bits set.
+			 */
+			ppr_options = 0;
+		} else if (width == MSG_EXT_WDTR_BUS_16_BIT) {
+			/*
+			 * If the next narrow speed is greater than
+			 * the next wide speed, fallback to narrow.
+			 * Otherwise fallback to the next DT/Wide setting.
+			 * The narrow async speed will always be smaller
+			 * than the wide async speed, so handle this case
+			 * specifically.
+			 */
+			ppr_options = targ->dv_max_ppr_options;
+			if (narrow_speed > fallback_speed
+			 || period >= AHC_ASYNC_XFER_PERIOD) {
+				targ->dv_next_wide_period = period+1;
+				width = MSG_EXT_WDTR_BUS_8_BIT;
+				period = targ->dv_next_narrow_period;
+			} else {
+				period++;
+			}
+		} else if ((ahc->features & AHC_WIDE) != 0
+			&& targ->dv_max_width != 0
+			&& wide_speed >= fallback_speed
+			&& (targ->dv_next_wide_period <= AHC_ASYNC_XFER_PERIOD
+			 || period >= AHC_ASYNC_XFER_PERIOD)) {
+
+			/*
+			 * We are narrow.  Try falling back
+			 * to the next wide speed with 
+			 * all supported ppr options set.
+			 */
+			targ->dv_next_narrow_period = period+1;
+			width = MSG_EXT_WDTR_BUS_16_BIT;
+			period = targ->dv_next_wide_period;
+			ppr_options = targ->dv_max_ppr_options;
+		} else {
+			/* Only narrow fallback is allowed. */
+			period++;
+			ppr_options = targ->dv_max_ppr_options;
+		}
+	} else {
+		ahc_unlock(ahc, &s);
+		return (-1);
+	}
+	offset = MAX_OFFSET;
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options,
+				     AHC_SYNCRATE_DT);
+	ahc_set_width(ahc, devinfo, width, AHC_TRANS_GOAL, FALSE);
+	if (period == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+		if (width == MSG_EXT_WDTR_BUS_8_BIT)
+			targ->dv_next_narrow_period = AHC_ASYNC_XFER_PERIOD;
+		else
+			targ->dv_next_wide_period = AHC_ASYNC_XFER_PERIOD;
+	}
+	ahc_set_syncrate(ahc, devinfo, syncrate, period, offset,
+			 ppr_options, AHC_TRANS_GOAL, FALSE);
+	targ->dv_last_ppr_options = ppr_options;
+	ahc_unlock(ahc, &s);
+	return (0);
+}
+
+static void
+ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
+{
+	struct	ahc_softc *ahc;
+	struct	scb *scb;
+	u_long	flags;
+
+	ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
+	ahc_lock(ahc, &flags);
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV) {
+		printf("%s: Timeout while doing DV command %x.\n",
+		       ahc_name(ahc), cmd->cmnd[0]);
+		ahc_dump_card_state(ahc);
+	}
+#endif
+	
+	/*
+	 * Guard against "done race".  No action is
+	 * required if we just completed.
+	 */
+	if ((scb = (struct scb *)cmd->host_scribble) == NULL) {
+		ahc_unlock(ahc, &flags);
+		return;
+	}
+
+	/*
+	 * Command has not completed.  Mark this
+	 * SCB as having failing status prior to
+	 * resetting the bus, so we get the correct
+	 * error code.
+	 */
+	if ((scb->flags & SCB_SENSE) != 0)
+		ahc_set_transaction_status(scb, CAM_AUTOSENSE_FAIL);
+	else
+		ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
+	ahc_reset_channel(ahc, cmd->device->channel + 'A', /*initiate*/TRUE);
+
+	/*
+	 * Add a minimal bus settle delay for devices that are slow to
+	 * respond after bus resets.
+	 */
+	ahc_linux_freeze_simq(ahc);
+	init_timer(&ahc->platform_data->reset_timer);
+	ahc->platform_data->reset_timer.data = (u_long)ahc;
+	ahc->platform_data->reset_timer.expires = jiffies + HZ / 2;
+	ahc->platform_data->reset_timer.function =
+	    (ahc_linux_callback_t *)ahc_linux_release_simq;
+	add_timer(&ahc->platform_data->reset_timer);
+	if (ahc_linux_next_device_to_run(ahc) != NULL)
+		ahc_schedule_runq(ahc);
+	ahc_linux_run_complete_queue(ahc);
+	ahc_unlock(ahc, &flags);
+}
+
+static void
+ahc_linux_dv_complete(struct scsi_cmnd *cmd)
+{
+	struct ahc_softc *ahc;
+
+	ahc = *((struct ahc_softc **)cmd->device->host->hostdata);
+
+	/* Delete the DV timer before it goes off! */
+	scsi_delete_timer(cmd);
+
+#ifdef AHC_DEBUG
+	if (ahc_debug & AHC_SHOW_DV)
+		printf("%s:%d:%d: Command completed, status= 0x%x\n",
+		       ahc_name(ahc), cmd->device->channel,
+		       cmd->device->id, cmd->result);
+#endif
+
+	/* Wake up the state machine */
+	up(&ahc->platform_data->dv_cmd_sem);
+}
+
+static void
+ahc_linux_generate_dv_pattern(struct ahc_linux_target *targ)
+{
+	uint16_t b;
+	u_int	 i;
+	u_int	 j;
+
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	targ->dv_buffer = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
+	if (targ->dv_buffer1 != NULL)
+		free(targ->dv_buffer1, M_DEVBUF);
+	targ->dv_buffer1 = malloc(targ->dv_echo_size, M_DEVBUF, M_WAITOK);
+
+	i = 0;
+	b = 0x0001;
+	for (j = 0 ; i < targ->dv_echo_size; j++) {
+		if (j < 32) {
+			/*
+			 * 32bytes of sequential numbers.
+			 */
+			targ->dv_buffer[i++] = j & 0xff;
+		} else if (j < 48) {
+			/*
+			 * 32bytes of repeating 0x0000, 0xffff.
+			 */
+			targ->dv_buffer[i++] = (j & 0x02) ? 0xff : 0x00;
+		} else if (j < 64) {
+			/*
+			 * 32bytes of repeating 0x5555, 0xaaaa.
+			 */
+			targ->dv_buffer[i++] = (j & 0x02) ? 0xaa : 0x55;
+		} else {
+			/*
+			 * Remaining buffer is filled with a repeating
+			 * patter of:
+			 *
+			 *	 0xffff
+			 *	~0x0001 << shifted once in each loop.
+			 */
+			if (j & 0x02) {
+				if (j & 0x01) {
+					targ->dv_buffer[i++] = ~(b >> 8) & 0xff;
+					b <<= 1;
+					if (b == 0x0000)
+						b = 0x0001;
+				} else {
+					targ->dv_buffer[i++] = (~b & 0xff);
+				}
+			} else {
+				targ->dv_buffer[i++] = 0xff;
+			}
+		}
+	}
+}
+
+static u_int
+ahc_linux_user_tagdepth(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	static int warned_user;
+	u_int tags;
+
+	tags = 0;
+	if ((ahc->user_discenable & devinfo->target_mask) != 0) {
+		if (ahc->unit >= NUM_ELEMENTS(aic7xxx_tag_info)) {
+			if (warned_user == 0) {
+
+				printf(KERN_WARNING
+"aic7xxx: WARNING: Insufficient tag_info instances\n"
+"aic7xxx: for installed controllers. Using defaults\n"
+"aic7xxx: Please update the aic7xxx_tag_info array in\n"
+"aic7xxx: the aic7xxx_osm..c source file.\n");
+				warned_user++;
+			}
+			tags = AHC_MAX_QUEUE;
+		} else {
+			adapter_tag_info_t *tag_info;
+
+			tag_info = &aic7xxx_tag_info[ahc->unit];
+			tags = tag_info->tag_commands[devinfo->target_offset];
+			if (tags > AHC_MAX_QUEUE)
+				tags = AHC_MAX_QUEUE;
+		}
+	}
+	return (tags);
+}
+
+static u_int
+ahc_linux_user_dv_setting(struct ahc_softc *ahc)
+{
+	static int warned_user;
+	int dv;
+
+	if (ahc->unit >= NUM_ELEMENTS(aic7xxx_dv_settings)) {
+		if (warned_user == 0) {
+
+			printf(KERN_WARNING
+"aic7xxx: WARNING: Insufficient dv settings instances\n"
+"aic7xxx: for installed controllers. Using defaults\n"
+"aic7xxx: Please update the aic7xxx_dv_settings array\n"
+"aic7xxx: in the aic7xxx_osm.c source file.\n");
+			warned_user++;
+		}
+		dv = -1;
+	} else {
+
+		dv = aic7xxx_dv_settings[ahc->unit];
+	}
+
+	if (dv < 0) {
+		u_long s;
+
+		/*
+		 * Apply the default.
+		 */
+		/*
+		 * XXX - Enable DV on non-U160 controllers once it
+		 *       has been tested there.
+		 */
+		ahc_lock(ahc, &s);
+		dv = (ahc->features & AHC_DT);
+		if (ahc->seep_config != 0
+		 && ahc->seep_config->signature >= CFSIGNATURE2)
+			dv = (ahc->seep_config->adapter_control & CFENABLEDV);
+		ahc_unlock(ahc, &s);
+	}
+	return (dv);
+}
+
+/*
+ * Determines the queue depth for a given device.
+ */
+static void
+ahc_linux_device_queue_depth(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev)
+{
+	struct	ahc_devinfo devinfo;
+	u_int	tags;
+
+	ahc_compile_devinfo(&devinfo,
+			    dev->target->channel == 0
+			  ? ahc->our_id : ahc->our_id_b,
+			    dev->target->target, dev->lun,
+			    dev->target->channel == 0 ? 'A' : 'B',
+			    ROLE_INITIATOR);
+	tags = ahc_linux_user_tagdepth(ahc, &devinfo);
+	if (tags != 0
+	 && dev->scsi_device != NULL
+	 && dev->scsi_device->tagged_supported != 0) {
+
+		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
+		ahc_print_devinfo(ahc, &devinfo);
+		printf("Tagged Queuing enabled.  Depth %d\n", tags);
+	} else {
+		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
+	}
+}
+
+static void
+ahc_linux_run_device_queue(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	struct	 ahc_cmd *acmd;
+	struct	 scsi_cmnd *cmd;
+	struct	 scb *scb;
+	struct	 hardware_scb *hscb;
+	struct	 ahc_initiator_tinfo *tinfo;
+	struct	 ahc_tmode_tstate *tstate;
+	uint16_t mask;
+
+	if ((dev->flags & AHC_DEV_ON_RUN_LIST) != 0)
+		panic("running device on run list");
+
+	while ((acmd = TAILQ_FIRST(&dev->busyq)) != NULL
+	    && dev->openings > 0 && dev->qfrozen == 0) {
+
+		/*
+		 * Schedule us to run later.  The only reason we are not
+		 * running is because the whole controller Q is frozen.
+		 */
+		if (ahc->platform_data->qfrozen != 0
+	 	 && AHC_DV_SIMQ_FROZEN(ahc) == 0) {
+			TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq,
+					  dev, links);
+			dev->flags |= AHC_DEV_ON_RUN_LIST;
+			return;
+		}
+		/*
+		 * Get an scb to use.
+		 */
+		if ((scb = ahc_get_scb(ahc)) == NULL) {
+			TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq,
+					 dev, links);
+			dev->flags |= AHC_DEV_ON_RUN_LIST;
+			ahc->flags |= AHC_RESOURCE_SHORTAGE;
+			return;
+		}
+		TAILQ_REMOVE(&dev->busyq, acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		scb->io_ctx = cmd;
+		scb->platform_data->dev = dev;
+		hscb = scb->hscb;
+		cmd->host_scribble = (char *)scb;
+
+		/*
+		 * Fill out basics of the HSCB.
+		 */
+		hscb->control = 0;
+		hscb->scsiid = BUILD_SCSIID(ahc, cmd);
+		hscb->lun = cmd->device->lun;
+		mask = SCB_GET_TARGET_MASK(ahc, scb);
+		tinfo = ahc_fetch_transinfo(ahc, SCB_GET_CHANNEL(ahc, scb),
+					    SCB_GET_OUR_ID(scb),
+					    SCB_GET_TARGET(ahc, scb), &tstate);
+		hscb->scsirate = tinfo->scsirate;
+		hscb->scsioffset = tinfo->curr.offset;
+		if ((tstate->ultraenb & mask) != 0)
+			hscb->control |= ULTRAENB;
+
+		if ((ahc->user_discenable & mask) != 0)
+			hscb->control |= DISCENB;
+
+	 	if (AHC_DV_CMD(cmd) != 0)
+			scb->flags |= SCB_SILENT;
+
+		if ((tstate->auto_negotiate & mask) != 0) {
+			scb->flags |= SCB_AUTO_NEGOTIATE;
+			scb->hscb->control |= MK_MESSAGE;
+		}
+
+		if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+			int	msg_bytes;
+			uint8_t tag_msgs[2];
+
+			msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
+			if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
+				hscb->control |= tag_msgs[0];
+				if (tag_msgs[0] == MSG_ORDERED_TASK)
+					dev->commands_since_idle_or_otag = 0;
+			} else
+#endif
+			if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
+			 && (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
+				hscb->control |= MSG_ORDERED_TASK;
+				dev->commands_since_idle_or_otag = 0;
+			} else {
+				hscb->control |= MSG_SIMPLE_TASK;
+			}
+		}
+
+		hscb->cdb_len = cmd->cmd_len;
+		if (hscb->cdb_len <= 12) {
+			memcpy(hscb->shared_data.cdb, cmd->cmnd, hscb->cdb_len);
+		} else {
+			memcpy(hscb->cdb32, cmd->cmnd, hscb->cdb_len);
+			scb->flags |= SCB_CDB32_PTR;
+		}
+
+		scb->platform_data->xfer_len = 0;
+		ahc_set_residual(scb, 0);
+		ahc_set_sense_residual(scb, 0);
+		scb->sg_count = 0;
+		if (cmd->use_sg != 0) {
+			struct	ahc_dma_seg *sg;
+			struct	scatterlist *cur_seg;
+			struct	scatterlist *end_seg;
+			int	nseg;
+
+			cur_seg = (struct scatterlist *)cmd->request_buffer;
+			nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg,
+			    scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			end_seg = cur_seg + nseg;
+			/* Copy the segments into the SG list. */
+			sg = scb->sg_list;
+			/*
+			 * The sg_count may be larger than nseg if
+			 * a transfer crosses a 32bit page.
+			 */ 
+			while (cur_seg < end_seg) {
+				dma_addr_t addr;
+				bus_size_t len;
+				int consumed;
+
+				addr = sg_dma_address(cur_seg);
+				len = sg_dma_len(cur_seg);
+				consumed = ahc_linux_map_seg(ahc, scb,
+							     sg, addr, len);
+				sg += consumed;
+				scb->sg_count += consumed;
+				cur_seg++;
+			}
+			sg--;
+			sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
+
+			/*
+			 * Reset the sg list pointer.
+			 */
+			scb->hscb->sgptr =
+			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+
+			/*
+			 * Copy the first SG into the "current"
+			 * data pointer area.
+			 */
+			scb->hscb->dataptr = scb->sg_list->addr;
+			scb->hscb->datacnt = scb->sg_list->len;
+		} else if (cmd->request_bufflen != 0) {
+			struct	 ahc_dma_seg *sg;
+			dma_addr_t addr;
+
+			sg = scb->sg_list;
+			addr = pci_map_single(ahc->dev_softc,
+			       cmd->request_buffer,
+			       cmd->request_bufflen,
+			       scsi_to_pci_dma_dir(cmd->sc_data_direction));
+			scb->platform_data->buf_busaddr = addr;
+			scb->sg_count = ahc_linux_map_seg(ahc, scb,
+							  sg, addr,
+							  cmd->request_bufflen);
+			sg->len |= ahc_htole32(AHC_DMA_LAST_SEG);
+
+			/*
+			 * Reset the sg list pointer.
+			 */
+			scb->hscb->sgptr =
+			    ahc_htole32(scb->sg_list_phys | SG_FULL_RESID);
+
+			/*
+			 * Copy the first SG into the "current"
+			 * data pointer area.
+			 */
+			scb->hscb->dataptr = sg->addr;
+			scb->hscb->datacnt = sg->len;
+		} else {
+			scb->hscb->sgptr = ahc_htole32(SG_LIST_NULL);
+			scb->hscb->dataptr = 0;
+			scb->hscb->datacnt = 0;
+			scb->sg_count = 0;
+		}
+
+		ahc_sync_sglist(ahc, scb, BUS_DMASYNC_PREWRITE);
+		LIST_INSERT_HEAD(&ahc->pending_scbs, scb, pending_links);
+		dev->openings--;
+		dev->active++;
+		dev->commands_issued++;
+		if ((dev->flags & AHC_DEV_PERIODIC_OTAG) != 0)
+			dev->commands_since_idle_or_otag++;
+
+		/*
+		 * We only allow one untagged transaction
+		 * per target in the initiator role unless
+		 * we are storing a full busy target *lun*
+		 * table in SCB space.
+		 */
+		if ((scb->hscb->control & (TARGET_SCB|TAG_ENB)) == 0
+		 && (ahc->features & AHC_SCB_BTT) == 0) {
+			struct scb_tailq *untagged_q;
+			int target_offset;
+
+			target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
+			untagged_q = &(ahc->untagged_queues[target_offset]);
+			TAILQ_INSERT_TAIL(untagged_q, scb, links.tqe);
+			scb->flags |= SCB_UNTAGGEDQ;
+			if (TAILQ_FIRST(untagged_q) != scb)
+				continue;
+		}
+		scb->flags |= SCB_ACTIVE;
+		ahc_queue_scb(ahc, scb);
+	}
+}
+
+/*
+ * SCSI controller interrupt handler.
+ */
+irqreturn_t
+ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	struct	ahc_softc *ahc;
+	u_long	flags;
+	int	ours;
+
+	ahc = (struct ahc_softc *) dev_id;
+	ahc_lock(ahc, &flags); 
+	ours = ahc_intr(ahc);
+	if (ahc_linux_next_device_to_run(ahc) != NULL)
+		ahc_schedule_runq(ahc);
+	ahc_linux_run_complete_queue(ahc);
+	ahc_unlock(ahc, &flags);
+	return IRQ_RETVAL(ours);
+}
+
+void
+ahc_platform_flushwork(struct ahc_softc *ahc)
+{
+
+	while (ahc_linux_run_complete_queue(ahc) != NULL)
+		;
+}
+
+static struct ahc_linux_target*
+ahc_linux_alloc_target(struct ahc_softc *ahc, u_int channel, u_int target)
+{
+	struct ahc_linux_target *targ;
+	u_int target_offset;
+
+	target_offset = target;
+	if (channel != 0)
+		target_offset += 8;
+
+	targ = malloc(sizeof(*targ), M_DEVBUG, M_NOWAIT);
+	if (targ == NULL)
+		return (NULL);
+	memset(targ, 0, sizeof(*targ));
+	targ->channel = channel;
+	targ->target = target;
+	targ->ahc = ahc;
+	targ->flags = AHC_DV_REQUIRED;
+	ahc->platform_data->targets[target_offset] = targ;
+	return (targ);
+}
+
+static void
+ahc_linux_free_target(struct ahc_softc *ahc, struct ahc_linux_target *targ)
+{
+	struct ahc_devinfo devinfo;
+	struct ahc_initiator_tinfo *tinfo;
+	struct ahc_tmode_tstate *tstate;
+	u_int our_id;
+	u_int target_offset;
+	char channel;
+
+	/*
+	 * Force a negotiation to async/narrow on any
+	 * future command to this device unless a bus
+	 * reset occurs between now and that command.
+	 */
+	channel = 'A' + targ->channel;
+	our_id = ahc->our_id;
+	target_offset = targ->target;
+	if (targ->channel != 0) {
+		target_offset += 8;
+		our_id = ahc->our_id_b;
+	}
+	tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+				    targ->target, &tstate);
+	ahc_compile_devinfo(&devinfo, our_id, targ->target, CAM_LUN_WILDCARD,
+			    channel, ROLE_INITIATOR);
+	ahc_set_syncrate(ahc, &devinfo, NULL, 0, 0, 0,
+			 AHC_TRANS_GOAL, /*paused*/FALSE);
+	ahc_set_width(ahc, &devinfo, MSG_EXT_WDTR_BUS_8_BIT,
+		      AHC_TRANS_GOAL, /*paused*/FALSE);
+	ahc_update_neg_request(ahc, &devinfo, tstate, tinfo, AHC_NEG_ALWAYS);
+	ahc->platform_data->targets[target_offset] = NULL;
+	if (targ->inq_data != NULL)
+		free(targ->inq_data, M_DEVBUF);
+	if (targ->dv_buffer != NULL)
+		free(targ->dv_buffer, M_DEVBUF);
+	if (targ->dv_buffer1 != NULL)
+		free(targ->dv_buffer1, M_DEVBUF);
+	free(targ, M_DEVBUF);
+}
+
+static struct ahc_linux_device*
+ahc_linux_alloc_device(struct ahc_softc *ahc,
+		 struct ahc_linux_target *targ, u_int lun)
+{
+	struct ahc_linux_device *dev;
+
+	dev = malloc(sizeof(*dev), M_DEVBUG, M_NOWAIT);
+	if (dev == NULL)
+		return (NULL);
+	memset(dev, 0, sizeof(*dev));
+	init_timer(&dev->timer);
+	TAILQ_INIT(&dev->busyq);
+	dev->flags = AHC_DEV_UNCONFIGURED;
+	dev->lun = lun;
+	dev->target = targ;
+
+	/*
+	 * We start out life using untagged
+	 * transactions of which we allow one.
+	 */
+	dev->openings = 1;
+
+	/*
+	 * Set maxtags to 0.  This will be changed if we
+	 * later determine that we are dealing with
+	 * a tagged queuing capable device.
+	 */
+	dev->maxtags = 0;
+	
+	targ->refcount++;
+	targ->devices[lun] = dev;
+	return (dev);
+}
+
+static void
+__ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	struct ahc_linux_target *targ;
+
+	targ = dev->target;
+	targ->devices[dev->lun] = NULL;
+	free(dev, M_DEVBUF);
+	targ->refcount--;
+	if (targ->refcount == 0
+	 && (targ->flags & AHC_DV_REQUIRED) == 0)
+		ahc_linux_free_target(ahc, targ);
+}
+
+static void
+ahc_linux_free_device(struct ahc_softc *ahc, struct ahc_linux_device *dev)
+{
+	del_timer_sync(&dev->timer);
+	__ahc_linux_free_device(ahc, dev);
+}
+
+void
+ahc_send_async(struct ahc_softc *ahc, char channel,
+	       u_int target, u_int lun, ac_code code, void *arg)
+{
+	switch (code) {
+	case AC_TRANSFER_NEG:
+	{
+		char	buf[80];
+		struct	ahc_linux_target *targ;
+		struct	info_str info;
+		struct	ahc_initiator_tinfo *tinfo;
+		struct	ahc_tmode_tstate *tstate;
+		int	target_offset;
+
+		info.buffer = buf;
+		info.length = sizeof(buf);
+		info.offset = 0;
+		info.pos = 0;
+		tinfo = ahc_fetch_transinfo(ahc, channel,
+						channel == 'A' ? ahc->our_id
+							       : ahc->our_id_b,
+						target, &tstate);
+
+		/*
+		 * Don't bother reporting results while
+		 * negotiations are still pending.
+		 */
+		if (tinfo->curr.period != tinfo->goal.period
+		 || tinfo->curr.width != tinfo->goal.width
+		 || tinfo->curr.offset != tinfo->goal.offset
+		 || tinfo->curr.ppr_options != tinfo->goal.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		/*
+		 * Don't bother reporting results that
+		 * are identical to those last reported.
+		 */
+		target_offset = target;
+		if (channel == 'B')
+			target_offset += 8;
+		targ = ahc->platform_data->targets[target_offset];
+		if (targ == NULL)
+			break;
+		if (tinfo->curr.period == targ->last_tinfo.period
+		 && tinfo->curr.width == targ->last_tinfo.width
+		 && tinfo->curr.offset == targ->last_tinfo.offset
+		 && tinfo->curr.ppr_options == targ->last_tinfo.ppr_options)
+			if (bootverbose == 0)
+				break;
+
+		targ->last_tinfo.period = tinfo->curr.period;
+		targ->last_tinfo.width = tinfo->curr.width;
+		targ->last_tinfo.offset = tinfo->curr.offset;
+		targ->last_tinfo.ppr_options = tinfo->curr.ppr_options;
+
+		printf("(%s:%c:", ahc_name(ahc), channel);
+		if (target == CAM_TARGET_WILDCARD)
+			printf("*): ");
+		else
+			printf("%d): ", target);
+		ahc_format_transinfo(&info, &tinfo->curr);
+		if (info.pos < info.length)
+			*info.buffer = '\0';
+		else
+			buf[info.length - 1] = '\0';
+		printf("%s", buf);
+		break;
+	}
+        case AC_SENT_BDR:
+	{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		WARN_ON(lun != CAM_LUN_WILDCARD);
+		scsi_report_device_reset(ahc->platform_data->host,
+					 channel - 'A', target);
+#else
+		Scsi_Device *scsi_dev;
+
+		/*
+		 * Find the SCSI device associated with this
+		 * request and indicate that a UA is expected.
+		 */
+		for (scsi_dev = ahc->platform_data->host->host_queue;
+		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
+			if (channel - 'A' == scsi_dev->channel
+			 && target == scsi_dev->id
+			 && (lun == CAM_LUN_WILDCARD
+			  || lun == scsi_dev->lun)) {
+				scsi_dev->was_reset = 1;
+				scsi_dev->expecting_cc_ua = 1;
+			}
+		}
+#endif
+		break;
+	}
+        case AC_BUS_RESET:
+		if (ahc->platform_data->host != NULL) {
+			scsi_report_bus_reset(ahc->platform_data->host,
+					      channel - 'A');
+		}
+                break;
+        default:
+                panic("ahc_send_async: Unexpected async event");
+        }
+}
+
+/*
+ * Calls the higher level scsi done function and frees the scb.
+ */
+void
+ahc_done(struct ahc_softc *ahc, struct scb *scb)
+{
+	Scsi_Cmnd *cmd;
+	struct	   ahc_linux_device *dev;
+
+	LIST_REMOVE(scb, pending_links);
+	if ((scb->flags & SCB_UNTAGGEDQ) != 0) {
+		struct scb_tailq *untagged_q;
+		int target_offset;
+
+		target_offset = SCB_GET_TARGET_OFFSET(ahc, scb);
+		untagged_q = &(ahc->untagged_queues[target_offset]);
+		TAILQ_REMOVE(untagged_q, scb, links.tqe);
+		ahc_run_untagged_queue(ahc, untagged_q);
+	}
+
+	if ((scb->flags & SCB_ACTIVE) == 0) {
+		printf("SCB %d done'd twice\n", scb->hscb->tag);
+		ahc_dump_card_state(ahc);
+		panic("Stopping for safety");
+	}
+	cmd = scb->io_ctx;
+	dev = scb->platform_data->dev;
+	dev->active--;
+	dev->openings++;
+	if ((cmd->result & (CAM_DEV_QFRZN << 16)) != 0) {
+		cmd->result &= ~(CAM_DEV_QFRZN << 16);
+		dev->qfrozen--;
+	}
+	ahc_linux_unmap_scb(ahc, scb);
+
+	/*
+	 * Guard against stale sense data.
+	 * The Linux mid-layer assumes that sense
+	 * was retrieved anytime the first byte of
+	 * the sense buffer looks "sane".
+	 */
+	cmd->sense_buffer[0] = 0;
+	if (ahc_get_transaction_status(scb) == CAM_REQ_INPROG) {
+		uint32_t amount_xferred;
+
+		amount_xferred =
+		    ahc_get_transfer_length(scb) - ahc_get_residual(scb);
+		if ((scb->flags & SCB_TRANSMISSION_ERROR) != 0) {
+#ifdef AHC_DEBUG
+			if ((ahc_debug & AHC_SHOW_MISC) != 0) {
+				ahc_print_path(ahc, scb);
+				printf("Set CAM_UNCOR_PARITY\n");
+			}
+#endif
+			ahc_set_transaction_status(scb, CAM_UNCOR_PARITY);
+#ifdef AHC_REPORT_UNDERFLOWS
+		/*
+		 * This code is disabled by default as some
+		 * clients of the SCSI system do not properly
+		 * initialize the underflow parameter.  This
+		 * results in spurious termination of commands
+		 * that complete as expected (e.g. underflow is
+		 * allowed as command can return variable amounts
+		 * of data.
+		 */
+		} else if (amount_xferred < scb->io_ctx->underflow) {
+			u_int i;
+
+			ahc_print_path(ahc, scb);
+			printf("CDB:");
+			for (i = 0; i < scb->io_ctx->cmd_len; i++)
+				printf(" 0x%x", scb->io_ctx->cmnd[i]);
+			printf("\n");
+			ahc_print_path(ahc, scb);
+			printf("Saw underflow (%ld of %ld bytes). "
+			       "Treated as error\n",
+				ahc_get_residual(scb),
+				ahc_get_transfer_length(scb));
+			ahc_set_transaction_status(scb, CAM_DATA_RUN_ERR);
+#endif
+		} else {
+			ahc_set_transaction_status(scb, CAM_REQ_CMP);
+		}
+	} else if (ahc_get_transaction_status(scb) == CAM_SCSI_STATUS_ERROR) {
+		ahc_linux_handle_scsi_status(ahc, dev, scb);
+	} else if (ahc_get_transaction_status(scb) == CAM_SEL_TIMEOUT) {
+		dev->flags |= AHC_DEV_UNCONFIGURED;
+		if (AHC_DV_CMD(cmd) == FALSE)
+			dev->target->flags &= ~AHC_DV_REQUIRED;
+	}
+	/*
+	 * Start DV for devices that require it assuming the first command
+	 * sent does not result in a selection timeout.
+	 */
+	if (ahc_get_transaction_status(scb) != CAM_SEL_TIMEOUT
+	 && (dev->target->flags & AHC_DV_REQUIRED) != 0)
+		ahc_linux_start_dv(ahc);
+
+	if (dev->openings == 1
+	 && ahc_get_transaction_status(scb) == CAM_REQ_CMP
+	 && ahc_get_scsi_status(scb) != SCSI_STATUS_QUEUE_FULL)
+		dev->tag_success_count++;
+	/*
+	 * Some devices deal with temporary internal resource
+	 * shortages by returning queue full.  When the queue
+	 * full occurrs, we throttle back.  Slowly try to get
+	 * back to our previous queue depth.
+	 */
+	if ((dev->openings + dev->active) < dev->maxtags
+	 && dev->tag_success_count > AHC_TAG_SUCCESS_INTERVAL) {
+		dev->tag_success_count = 0;
+		dev->openings++;
+	}
+
+	if (dev->active == 0)
+		dev->commands_since_idle_or_otag = 0;
+
+	if (TAILQ_EMPTY(&dev->busyq)) {
+		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
+		 && dev->active == 0
+	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
+			ahc_linux_free_device(ahc, dev);
+	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
+		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
+		dev->flags |= AHC_DEV_ON_RUN_LIST;
+	}
+
+	if ((scb->flags & SCB_RECOVERY_SCB) != 0) {
+		printf("Recovery SCB completes\n");
+		if (ahc_get_transaction_status(scb) == CAM_BDR_SENT
+		 || ahc_get_transaction_status(scb) == CAM_REQ_ABORTED)
+			ahc_set_transaction_status(scb, CAM_CMD_TIMEOUT);
+		if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) {
+			ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE;
+			up(&ahc->platform_data->eh_sem);
+		}
+	}
+
+	ahc_free_scb(ahc, scb);
+	ahc_linux_queue_cmd_complete(ahc, cmd);
+
+	if ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_EMPTY) != 0
+	 && LIST_FIRST(&ahc->pending_scbs) == NULL) {
+		ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_EMPTY;
+		up(&ahc->platform_data->dv_sem);
+	}
+		
+}
+
+static void
+ahc_linux_handle_scsi_status(struct ahc_softc *ahc,
+			     struct ahc_linux_device *dev, struct scb *scb)
+{
+	struct	ahc_devinfo devinfo;
+
+	ahc_compile_devinfo(&devinfo,
+			    ahc->our_id,
+			    dev->target->target, dev->lun,
+			    dev->target->channel == 0 ? 'A' : 'B',
+			    ROLE_INITIATOR);
+	
+	/*
+	 * We don't currently trust the mid-layer to
+	 * properly deal with queue full or busy.  So,
+	 * when one occurs, we tell the mid-layer to
+	 * unconditionally requeue the command to us
+	 * so that we can retry it ourselves.  We also
+	 * implement our own throttling mechanism so
+	 * we don't clobber the device with too many
+	 * commands.
+	 */
+	switch (ahc_get_scsi_status(scb)) {
+	default:
+		break;
+	case SCSI_STATUS_CHECK_COND:
+	case SCSI_STATUS_CMD_TERMINATED:
+	{
+		Scsi_Cmnd *cmd;
+
+		/*
+		 * Copy sense information to the OS's cmd
+		 * structure if it is available.
+		 */
+		cmd = scb->io_ctx;
+		if (scb->flags & SCB_SENSE) {
+			u_int sense_size;
+
+			sense_size = MIN(sizeof(struct scsi_sense_data)
+				       - ahc_get_sense_residual(scb),
+					 sizeof(cmd->sense_buffer));
+			memcpy(cmd->sense_buffer,
+			       ahc_get_sense_buf(ahc, scb), sense_size);
+			if (sense_size < sizeof(cmd->sense_buffer))
+				memset(&cmd->sense_buffer[sense_size], 0,
+				       sizeof(cmd->sense_buffer) - sense_size);
+			cmd->result |= (DRIVER_SENSE << 24);
+#ifdef AHC_DEBUG
+			if (ahc_debug & AHC_SHOW_SENSE) {
+				int i;
+
+				printf("Copied %d bytes of sense data:",
+				       sense_size);
+				for (i = 0; i < sense_size; i++) {
+					if ((i & 0xF) == 0)
+						printf("\n");
+					printf("0x%x ", cmd->sense_buffer[i]);
+				}
+				printf("\n");
+			}
+#endif
+		}
+		break;
+	}
+	case SCSI_STATUS_QUEUE_FULL:
+	{
+		/*
+		 * By the time the core driver has returned this
+		 * command, all other commands that were queued
+		 * to us but not the device have been returned.
+		 * This ensures that dev->active is equal to
+		 * the number of commands actually queued to
+		 * the device.
+		 */
+		dev->tag_success_count = 0;
+		if (dev->active != 0) {
+			/*
+			 * Drop our opening count to the number
+			 * of commands currently outstanding.
+			 */
+			dev->openings = 0;
+/*
+			ahc_print_path(ahc, scb);
+			printf("Dropping tag count to %d\n", dev->active);
+ */
+			if (dev->active == dev->tags_on_last_queuefull) {
+
+				dev->last_queuefull_same_count++;
+				/*
+				 * If we repeatedly see a queue full
+				 * at the same queue depth, this
+				 * device has a fixed number of tag
+				 * slots.  Lock in this tag depth
+				 * so we stop seeing queue fulls from
+				 * this device.
+				 */
+				if (dev->last_queuefull_same_count
+				 == AHC_LOCK_TAGS_COUNT) {
+					dev->maxtags = dev->active;
+					ahc_print_path(ahc, scb);
+					printf("Locking max tag count at %d\n",
+					       dev->active);
+				}
+			} else {
+				dev->tags_on_last_queuefull = dev->active;
+				dev->last_queuefull_same_count = 0;
+			}
+			ahc_set_transaction_status(scb, CAM_REQUEUE_REQ);
+			ahc_set_scsi_status(scb, SCSI_STATUS_OK);
+			ahc_platform_set_tags(ahc, &devinfo,
+				     (dev->flags & AHC_DEV_Q_BASIC)
+				   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
+			break;
+		}
+		/*
+		 * Drop down to a single opening, and treat this
+		 * as if the target returned BUSY SCSI status.
+		 */
+		dev->openings = 1;
+		ahc_set_scsi_status(scb, SCSI_STATUS_BUSY);
+		ahc_platform_set_tags(ahc, &devinfo,
+			     (dev->flags & AHC_DEV_Q_BASIC)
+			   ? AHC_QUEUE_BASIC : AHC_QUEUE_TAGGED);
+		/* FALLTHROUGH */
+	}
+	case SCSI_STATUS_BUSY:
+	{
+		/*
+		 * Set a short timer to defer sending commands for
+		 * a bit since Linux will not delay in this case.
+		 */
+		if ((dev->flags & AHC_DEV_TIMER_ACTIVE) != 0) {
+			printf("%s:%c:%d: Device Timer still active during "
+			       "busy processing\n", ahc_name(ahc),
+				dev->target->channel, dev->target->target);
+			break;
+		}
+		dev->flags |= AHC_DEV_TIMER_ACTIVE;
+		dev->qfrozen++;
+		init_timer(&dev->timer);
+		dev->timer.data = (u_long)dev;
+		dev->timer.expires = jiffies + (HZ/2);
+		dev->timer.function = ahc_linux_dev_timed_unfreeze;
+		add_timer(&dev->timer);
+		break;
+	}
+	}
+}
+
+static void
+ahc_linux_queue_cmd_complete(struct ahc_softc *ahc, Scsi_Cmnd *cmd)
+{
+	/*
+	 * Typically, the complete queue has very few entries
+	 * queued to it before the queue is emptied by
+	 * ahc_linux_run_complete_queue, so sorting the entries
+	 * by generation number should be inexpensive.
+	 * We perform the sort so that commands that complete
+	 * with an error are retuned in the order origionally
+	 * queued to the controller so that any subsequent retries
+	 * are performed in order.  The underlying ahc routines do
+	 * not guarantee the order that aborted commands will be
+	 * returned to us.
+	 */
+	struct ahc_completeq *completeq;
+	struct ahc_cmd *list_cmd;
+	struct ahc_cmd *acmd;
+
+	/*
+	 * Map CAM error codes into Linux Error codes.  We
+	 * avoid the conversion so that the DV code has the
+	 * full error information available when making
+	 * state change decisions.
+	 */
+	if (AHC_DV_CMD(cmd) == FALSE) {
+		u_int new_status;
+
+		switch (ahc_cmd_get_transaction_status(cmd)) {
+		case CAM_REQ_INPROG:
+		case CAM_REQ_CMP:
+		case CAM_SCSI_STATUS_ERROR:
+			new_status = DID_OK;
+			break;
+		case CAM_REQ_ABORTED:
+			new_status = DID_ABORT;
+			break;
+		case CAM_BUSY:
+			new_status = DID_BUS_BUSY;
+			break;
+		case CAM_REQ_INVALID:
+		case CAM_PATH_INVALID:
+			new_status = DID_BAD_TARGET;
+			break;
+		case CAM_SEL_TIMEOUT:
+			new_status = DID_NO_CONNECT;
+			break;
+		case CAM_SCSI_BUS_RESET:
+		case CAM_BDR_SENT:
+			new_status = DID_RESET;
+			break;
+		case CAM_UNCOR_PARITY:
+			new_status = DID_PARITY;
+			break;
+		case CAM_CMD_TIMEOUT:
+			new_status = DID_TIME_OUT;
+			break;
+		case CAM_UA_ABORT:
+		case CAM_REQ_CMP_ERR:
+		case CAM_AUTOSENSE_FAIL:
+		case CAM_NO_HBA:
+		case CAM_DATA_RUN_ERR:
+		case CAM_UNEXP_BUSFREE:
+		case CAM_SEQUENCE_FAIL:
+		case CAM_CCB_LEN_ERR:
+		case CAM_PROVIDE_FAIL:
+		case CAM_REQ_TERMIO:
+		case CAM_UNREC_HBA_ERROR:
+		case CAM_REQ_TOO_BIG:
+			new_status = DID_ERROR;
+			break;
+		case CAM_REQUEUE_REQ:
+			/*
+			 * If we want the request requeued, make sure there
+			 * are sufficent retries.  In the old scsi error code,
+			 * we used to be able to specify a result code that
+			 * bypassed the retry count.  Now we must use this
+			 * hack.  We also "fake" a check condition with
+			 * a sense code of ABORTED COMMAND.  This seems to
+			 * evoke a retry even if this command is being sent
+			 * via the eh thread.  Ick!  Ick!  Ick!
+			 */
+			if (cmd->retries > 0)
+				cmd->retries--;
+			new_status = DID_OK;
+			ahc_cmd_set_scsi_status(cmd, SCSI_STATUS_CHECK_COND);
+			cmd->result |= (DRIVER_SENSE << 24);
+			memset(cmd->sense_buffer, 0,
+			       sizeof(cmd->sense_buffer));
+			cmd->sense_buffer[0] = SSD_ERRCODE_VALID
+					     | SSD_CURRENT_ERROR;
+			cmd->sense_buffer[2] = SSD_KEY_ABORTED_COMMAND;
+			break;
+		default:
+			/* We should never get here */
+			new_status = DID_ERROR;
+			break;
+		}
+
+		ahc_cmd_set_transaction_status(cmd, new_status);
+	}
+
+	completeq = &ahc->platform_data->completeq;
+	list_cmd = TAILQ_FIRST(completeq);
+	acmd = (struct ahc_cmd *)cmd;
+	while (list_cmd != NULL
+	    && acmd_scsi_cmd(list_cmd).serial_number
+	     < acmd_scsi_cmd(acmd).serial_number)
+		list_cmd = TAILQ_NEXT(list_cmd, acmd_links.tqe);
+	if (list_cmd != NULL)
+		TAILQ_INSERT_BEFORE(list_cmd, acmd, acmd_links.tqe);
+	else
+		TAILQ_INSERT_TAIL(completeq, acmd, acmd_links.tqe);
+}
+
+static void
+ahc_linux_filter_inquiry(struct ahc_softc *ahc, struct ahc_devinfo *devinfo)
+{
+	struct	scsi_inquiry_data *sid;
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_transinfo *user;
+	struct	ahc_transinfo *goal;
+	struct	ahc_transinfo *curr;
+	struct	ahc_tmode_tstate *tstate;
+	struct	ahc_syncrate *syncrate;
+	struct	ahc_linux_device *dev;
+	u_int	maxsync;
+	u_int	width;
+	u_int	period;
+	u_int	offset;
+	u_int	ppr_options;
+	u_int	trans_version;
+	u_int	prot_version;
+
+	/*
+	 * Determine if this lun actually exists.  If so,
+	 * hold on to its corresponding device structure.
+	 * If not, make sure we release the device and
+	 * don't bother processing the rest of this inquiry
+	 * command.
+	 */
+	dev = ahc_linux_get_device(ahc, devinfo->channel - 'A',
+				   devinfo->target, devinfo->lun,
+				   /*alloc*/TRUE);
+
+	sid = (struct scsi_inquiry_data *)dev->target->inq_data;
+	if (SID_QUAL(sid) == SID_QUAL_LU_CONNECTED) {
+
+		dev->flags &= ~AHC_DEV_UNCONFIGURED;
+	} else {
+		dev->flags |= AHC_DEV_UNCONFIGURED;
+		return;
+	}
+
+	/*
+	 * Update our notion of this device's transfer
+	 * negotiation capabilities.
+	 */
+	tinfo = ahc_fetch_transinfo(ahc, devinfo->channel,
+				    devinfo->our_scsiid,
+				    devinfo->target, &tstate);
+	user = &tinfo->user;
+	goal = &tinfo->goal;
+	curr = &tinfo->curr;
+	width = user->width;
+	period = user->period;
+	offset = user->offset;
+	ppr_options = user->ppr_options;
+	trans_version = user->transport_version;
+	prot_version = MIN(user->protocol_version, SID_ANSI_REV(sid));
+
+	/*
+	 * Only attempt SPI3/4 once we've verified that
+	 * the device claims to support SPI3/4 features.
+	 */
+	if (prot_version < SCSI_REV_2)
+		trans_version = SID_ANSI_REV(sid);
+	else
+		trans_version = SCSI_REV_2;
+
+	if ((sid->flags & SID_WBus16) == 0)
+		width = MSG_EXT_WDTR_BUS_8_BIT;
+	if ((sid->flags & SID_Sync) == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+	}
+	if ((sid->spi3data & SID_SPI_QAS) == 0)
+		ppr_options &= ~MSG_EXT_PPR_QAS_REQ;
+	if ((sid->spi3data & SID_SPI_CLOCK_DT) == 0)
+		ppr_options &= MSG_EXT_PPR_QAS_REQ;
+	if ((sid->spi3data & SID_SPI_IUS) == 0)
+		ppr_options &= (MSG_EXT_PPR_DT_REQ
+			      | MSG_EXT_PPR_QAS_REQ);
+
+	if (prot_version > SCSI_REV_2
+	 && ppr_options != 0)
+		trans_version = user->transport_version;
+
+	ahc_validate_width(ahc, /*tinfo limit*/NULL, &width, ROLE_UNKNOWN);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		maxsync = AHC_SYNCRATE_DT;
+	else if ((ahc->features & AHC_ULTRA) != 0)
+		maxsync = AHC_SYNCRATE_ULTRA;
+	else
+		maxsync = AHC_SYNCRATE_FAST;
+
+	syncrate = ahc_find_syncrate(ahc, &period, &ppr_options, maxsync);
+	ahc_validate_offset(ahc, /*tinfo limit*/NULL, syncrate,
+			    &offset, width, ROLE_UNKNOWN);
+	if (offset == 0 || period == 0) {
+		period = 0;
+		offset = 0;
+		ppr_options = 0;
+	}
+	/* Apply our filtered user settings. */
+	curr->transport_version = trans_version;
+	curr->protocol_version = prot_version;
+	ahc_set_width(ahc, devinfo, width, AHC_TRANS_GOAL, /*paused*/FALSE);
+	ahc_set_syncrate(ahc, devinfo, syncrate, period,
+			 offset, ppr_options, AHC_TRANS_GOAL,
+			 /*paused*/FALSE);
+}
+
+static void
+ahc_linux_sem_timeout(u_long arg)
+{
+	struct	ahc_softc *ahc;
+	u_long	s;
+
+	ahc = (struct ahc_softc *)arg;
+
+	ahc_lock(ahc, &s);
+	if ((ahc->platform_data->flags & AHC_UP_EH_SEMAPHORE) != 0) {
+		ahc->platform_data->flags &= ~AHC_UP_EH_SEMAPHORE;
+		up(&ahc->platform_data->eh_sem);
+	}
+	ahc_unlock(ahc, &s);
+}
+
+static void
+ahc_linux_freeze_simq(struct ahc_softc *ahc)
+{
+	ahc->platform_data->qfrozen++;
+	if (ahc->platform_data->qfrozen == 1) {
+		scsi_block_requests(ahc->platform_data->host);
+
+		/* XXX What about Twin channels? */
+		ahc_platform_abort_scbs(ahc, CAM_TARGET_WILDCARD, ALL_CHANNELS,
+					CAM_LUN_WILDCARD, SCB_LIST_NULL,
+					ROLE_INITIATOR, CAM_REQUEUE_REQ);
+	}
+}
+
+static void
+ahc_linux_release_simq(u_long arg)
+{
+	struct ahc_softc *ahc;
+	u_long s;
+	int    unblock_reqs;
+
+	ahc = (struct ahc_softc *)arg;
+
+	unblock_reqs = 0;
+	ahc_lock(ahc, &s);
+	if (ahc->platform_data->qfrozen > 0)
+		ahc->platform_data->qfrozen--;
+	if (ahc->platform_data->qfrozen == 0)
+		unblock_reqs = 1;
+	if (AHC_DV_SIMQ_FROZEN(ahc)
+	 && ((ahc->platform_data->flags & AHC_DV_WAIT_SIMQ_RELEASE) != 0)) {
+		ahc->platform_data->flags &= ~AHC_DV_WAIT_SIMQ_RELEASE;
+		up(&ahc->platform_data->dv_sem);
+	}
+	ahc_schedule_runq(ahc);
+	ahc_unlock(ahc, &s);
+	/*
+	 * There is still a race here.  The mid-layer
+	 * should keep its own freeze count and use
+	 * a bottom half handler to run the queues
+	 * so we can unblock with our own lock held.
+	 */
+	if (unblock_reqs)
+		scsi_unblock_requests(ahc->platform_data->host);
+}
+
+static void
+ahc_linux_dev_timed_unfreeze(u_long arg)
+{
+	struct ahc_linux_device *dev;
+	struct ahc_softc *ahc;
+	u_long s;
+
+	dev = (struct ahc_linux_device *)arg;
+	ahc = dev->target->ahc;
+	ahc_lock(ahc, &s);
+	dev->flags &= ~AHC_DEV_TIMER_ACTIVE;
+	if (dev->qfrozen > 0)
+		dev->qfrozen--;
+	if (dev->qfrozen == 0
+	 && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0)
+		ahc_linux_run_device_queue(ahc, dev);
+	if (TAILQ_EMPTY(&dev->busyq)
+	 && dev->active == 0)
+		__ahc_linux_free_device(ahc, dev);
+	ahc_unlock(ahc, &s);
+}
+
+static int
+ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag)
+{
+	struct ahc_softc *ahc;
+	struct ahc_cmd *acmd;
+	struct ahc_cmd *list_acmd;
+	struct ahc_linux_device *dev;
+	struct scb *pending_scb;
+	u_long s;
+	u_int  saved_scbptr;
+	u_int  active_scb_index;
+	u_int  last_phase;
+	u_int  saved_scsiid;
+	u_int  cdb_byte;
+	int    retval;
+	int    was_paused;
+	int    paused;
+	int    wait;
+	int    disconnected;
+
+	pending_scb = NULL;
+	paused = FALSE;
+	wait = FALSE;
+	ahc = *(struct ahc_softc **)cmd->device->host->hostdata;
+	acmd = (struct ahc_cmd *)cmd;
+
+	printf("%s:%d:%d:%d: Attempting to queue a%s message\n",
+	       ahc_name(ahc), cmd->device->channel,
+	       cmd->device->id, cmd->device->lun,
+	       flag == SCB_ABORT ? "n ABORT" : " TARGET RESET");
+
+	printf("CDB:");
+	for (cdb_byte = 0; cdb_byte < cmd->cmd_len; cdb_byte++)
+		printf(" 0x%x", cmd->cmnd[cdb_byte]);
+	printf("\n");
+
+	/*
+	 * In all versions of Linux, we have to work around
+	 * a major flaw in how the mid-layer is locked down
+	 * if we are to sleep successfully in our error handler
+	 * while allowing our interrupt handler to run.  Since
+	 * the midlayer acquires either the io_request_lock or
+	 * our lock prior to calling us, we must use the
+	 * spin_unlock_irq() method for unlocking our lock.
+	 * This will force interrupts to be enabled on the
+	 * current CPU.  Since the EH thread should not have
+	 * been running with CPU interrupts disabled other than
+	 * by acquiring either the io_request_lock or our own
+	 * lock, this *should* be safe.
+	 */
+	ahc_midlayer_entrypoint_lock(ahc, &s);
+
+	/*
+	 * First determine if we currently own this command.
+	 * Start by searching the device queue.  If not found
+	 * there, check the pending_scb list.  If not found
+	 * at all, and the system wanted us to just abort the
+	 * command, return success.
+	 */
+	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
+				   cmd->device->lun, /*alloc*/FALSE);
+
+	if (dev == NULL) {
+		/*
+		 * No target device for this command exists,
+		 * so we must not still own the command.
+		 */
+		printf("%s:%d:%d:%d: Is not an active device\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		retval = SUCCESS;
+		goto no_cmd;
+	}
+
+	TAILQ_FOREACH(list_acmd, &dev->busyq, acmd_links.tqe) {
+		if (list_acmd == acmd)
+			break;
+	}
+
+	if (list_acmd != NULL) {
+		printf("%s:%d:%d:%d: Command found on device queue\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		if (flag == SCB_ABORT) {
+			TAILQ_REMOVE(&dev->busyq, list_acmd, acmd_links.tqe);
+			cmd->result = DID_ABORT << 16;
+			ahc_linux_queue_cmd_complete(ahc, cmd);
+			retval = SUCCESS;
+			goto done;
+		}
+	}
+
+	if ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED)) == 0
+	 && ahc_search_untagged_queues(ahc, cmd, cmd->device->id,
+				       cmd->device->channel + 'A',
+				       cmd->device->lun,
+				       CAM_REQ_ABORTED, SEARCH_COMPLETE) != 0) {
+		printf("%s:%d:%d:%d: Command found on untagged queue\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		retval = SUCCESS;
+		goto done;
+	}
+
+	/*
+	 * See if we can find a matching cmd in the pending list.
+	 */
+	LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		if (pending_scb->io_ctx == cmd)
+			break;
+	}
+
+	if (pending_scb == NULL && flag == SCB_DEVICE_RESET) {
+
+		/* Any SCB for this device will do for a target reset */
+		LIST_FOREACH(pending_scb, &ahc->pending_scbs, pending_links) {
+		  	if (ahc_match_scb(ahc, pending_scb, cmd->device->id,
+					  cmd->device->channel + 'A',
+					  CAM_LUN_WILDCARD,
+					  SCB_LIST_NULL, ROLE_INITIATOR) == 0)
+				break;
+		}
+	}
+
+	if (pending_scb == NULL) {
+		printf("%s:%d:%d:%d: Command not found\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		goto no_cmd;
+	}
+
+	if ((pending_scb->flags & SCB_RECOVERY_SCB) != 0) {
+		/*
+		 * We can't queue two recovery actions using the same SCB
+		 */
+		retval = FAILED;
+		goto  done;
+	}
+
+	/*
+	 * Ensure that the card doesn't do anything
+	 * behind our back and that we didn't "just" miss
+	 * an interrupt that would affect this cmd.
+	 */
+	was_paused = ahc_is_paused(ahc);
+	ahc_pause_and_flushwork(ahc);
+	paused = TRUE;
+
+	if ((pending_scb->flags & SCB_ACTIVE) == 0) {
+		printf("%s:%d:%d:%d: Command already completed\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		goto no_cmd;
+	}
+
+	printf("%s: At time of recovery, card was %spaused\n",
+	       ahc_name(ahc), was_paused ? "" : "not ");
+	ahc_dump_card_state(ahc);
+
+	disconnected = TRUE;
+	if (flag == SCB_ABORT) {
+		if (ahc_search_qinfifo(ahc, cmd->device->id,
+				       cmd->device->channel + 'A',
+				       cmd->device->lun,
+				       pending_scb->hscb->tag,
+				       ROLE_INITIATOR, CAM_REQ_ABORTED,
+				       SEARCH_COMPLETE) > 0) {
+			printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
+			       ahc_name(ahc), cmd->device->channel,
+					cmd->device->id, cmd->device->lun);
+			retval = SUCCESS;
+			goto done;
+		}
+	} else if (ahc_search_qinfifo(ahc, cmd->device->id,
+				      cmd->device->channel + 'A',
+				      cmd->device->lun, pending_scb->hscb->tag,
+				      ROLE_INITIATOR, /*status*/0,
+				      SEARCH_COUNT) > 0) {
+		disconnected = FALSE;
+	}
+
+	if (disconnected && (ahc_inb(ahc, SEQ_FLAGS) & NOT_IDENTIFIED) == 0) {
+		struct scb *bus_scb;
+
+		bus_scb = ahc_lookup_scb(ahc, ahc_inb(ahc, SCB_TAG));
+		if (bus_scb == pending_scb)
+			disconnected = FALSE;
+		else if (flag != SCB_ABORT
+		      && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid
+		      && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb))
+			disconnected = FALSE;
+	}
+
+	/*
+	 * At this point, pending_scb is the scb associated with the
+	 * passed in command.  That command is currently active on the
+	 * bus, is in the disconnected state, or we're hoping to find
+	 * a command for the same target active on the bus to abuse to
+	 * send a BDR.  Queue the appropriate message based on which of
+	 * these states we are in.
+	 */
+	last_phase = ahc_inb(ahc, LASTPHASE);
+	saved_scbptr = ahc_inb(ahc, SCBPTR);
+	active_scb_index = ahc_inb(ahc, SCB_TAG);
+	saved_scsiid = ahc_inb(ahc, SAVED_SCSIID);
+	if (last_phase != P_BUSFREE
+	 && (pending_scb->hscb->tag == active_scb_index
+	  || (flag == SCB_DEVICE_RESET
+	   && SCSIID_TARGET(ahc, saved_scsiid) == cmd->device->id))) {
+
+		/*
+		 * We're active on the bus, so assert ATN
+		 * and hope that the target responds.
+		 */
+		pending_scb = ahc_lookup_scb(ahc, active_scb_index);
+		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+		ahc_outb(ahc, MSG_OUT, HOST_MSG);
+		ahc_outb(ahc, SCSISIGO, last_phase|ATNO);
+		printf("%s:%d:%d:%d: Device is active, asserting ATN\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		wait = TRUE;
+	} else if (disconnected) {
+
+		/*
+		 * Actually re-queue this SCB in an attempt
+		 * to select the device before it reconnects.
+		 * In either case (selection or reselection),
+		 * we will now issue the approprate message
+		 * to the timed-out device.
+		 *
+		 * Set the MK_MESSAGE control bit indicating
+		 * that we desire to send a message.  We
+		 * also set the disconnected flag since
+		 * in the paging case there is no guarantee
+		 * that our SCB control byte matches the
+		 * version on the card.  We don't want the
+		 * sequencer to abort the command thinking
+		 * an unsolicited reselection occurred.
+		 */
+		pending_scb->hscb->control |= MK_MESSAGE|DISCONNECTED;
+		pending_scb->flags |= SCB_RECOVERY_SCB|flag;
+
+		/*
+		 * Remove any cached copy of this SCB in the
+		 * disconnected list in preparation for the
+		 * queuing of our abort SCB.  We use the
+		 * same element in the SCB, SCB_NEXT, for
+		 * both the qinfifo and the disconnected list.
+		 */
+		ahc_search_disc_list(ahc, cmd->device->id,
+				     cmd->device->channel + 'A',
+				     cmd->device->lun, pending_scb->hscb->tag,
+				     /*stop_on_first*/TRUE,
+				     /*remove*/TRUE,
+				     /*save_state*/FALSE);
+
+		/*
+		 * In the non-paging case, the sequencer will
+		 * never re-reference the in-core SCB.
+		 * To make sure we are notified during
+		 * reslection, set the MK_MESSAGE flag in
+		 * the card's copy of the SCB.
+		 */
+		if ((ahc->flags & AHC_PAGESCBS) == 0) {
+			ahc_outb(ahc, SCBPTR, pending_scb->hscb->tag);
+			ahc_outb(ahc, SCB_CONTROL,
+				 ahc_inb(ahc, SCB_CONTROL)|MK_MESSAGE);
+		}
+
+		/*
+		 * Clear out any entries in the QINFIFO first
+		 * so we are the next SCB for this target
+		 * to run.
+		 */
+		ahc_search_qinfifo(ahc, cmd->device->id,
+				   cmd->device->channel + 'A',
+				   cmd->device->lun, SCB_LIST_NULL,
+				   ROLE_INITIATOR, CAM_REQUEUE_REQ,
+				   SEARCH_COMPLETE);
+		ahc_qinfifo_requeue_tail(ahc, pending_scb);
+		ahc_outb(ahc, SCBPTR, saved_scbptr);
+		ahc_print_path(ahc, pending_scb);
+		printf("Device is disconnected, re-queuing SCB\n");
+		wait = TRUE;
+	} else {
+		printf("%s:%d:%d:%d: Unable to deliver message\n",
+		       ahc_name(ahc), cmd->device->channel, cmd->device->id,
+		       cmd->device->lun);
+		retval = FAILED;
+		goto done;
+	}
+
+no_cmd:
+	/*
+	 * Our assumption is that if we don't have the command, no
+	 * recovery action was required, so we return success.  Again,
+	 * the semantics of the mid-layer recovery engine are not
+	 * well defined, so this may change in time.
+	 */
+	retval = SUCCESS;
+done:
+	if (paused)
+		ahc_unpause(ahc);
+	if (wait) {
+		struct timer_list timer;
+		int ret;
+
+		ahc->platform_data->flags |= AHC_UP_EH_SEMAPHORE;
+		spin_unlock_irq(&ahc->platform_data->spin_lock);
+		init_timer(&timer);
+		timer.data = (u_long)ahc;
+		timer.expires = jiffies + (5 * HZ);
+		timer.function = ahc_linux_sem_timeout;
+		add_timer(&timer);
+		printf("Recovery code sleeping\n");
+		down(&ahc->platform_data->eh_sem);
+		printf("Recovery code awake\n");
+        	ret = del_timer_sync(&timer);
+		if (ret == 0) {
+			printf("Timer Expired\n");
+			retval = FAILED;
+		}
+		spin_lock_irq(&ahc->platform_data->spin_lock);
+	}
+	ahc_schedule_runq(ahc);
+	ahc_linux_run_complete_queue(ahc);
+	ahc_midlayer_entrypoint_unlock(ahc, &s);
+	return (retval);
+}
+
+void
+ahc_platform_dump_card_state(struct ahc_softc *ahc)
+{
+	struct ahc_linux_device *dev;
+	int channel;
+	int maxchannel;
+	int target;
+	int maxtarget;
+	int lun;
+	int i;
+
+	maxchannel = (ahc->features & AHC_TWIN) ? 1 : 0;
+	maxtarget = (ahc->features & AHC_WIDE) ? 15 : 7;
+	for (channel = 0; channel <= maxchannel; channel++) {
+
+		for (target = 0; target <=maxtarget; target++) {
+
+			for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+				struct ahc_cmd *acmd;
+
+				dev = ahc_linux_get_device(ahc, channel, target,
+							   lun, /*alloc*/FALSE);
+				if (dev == NULL)
+					continue;
+
+				printf("DevQ(%d:%d:%d): ",
+				       channel, target, lun);
+				i = 0;
+				TAILQ_FOREACH(acmd, &dev->busyq,
+					      acmd_links.tqe) {
+					if (i++ > AHC_SCB_MAX)
+						break;
+				}
+				printf("%d waiting\n", i);
+			}
+		}
+	}
+}
+
+static void ahc_linux_exit(void);
+
+static int __init
+ahc_linux_init(void)
+{
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+	int rc = ahc_linux_detect(&aic7xxx_driver_template);
+	if (rc)
+		return rc;
+	ahc_linux_exit();
+	return -ENODEV;
+#else
+	scsi_register_module(MODULE_SCSI_HA, &aic7xxx_driver_template);
+	if (aic7xxx_driver_template.present == 0) {
+		scsi_unregister_module(MODULE_SCSI_HA,
+				       &aic7xxx_driver_template);
+		return (-ENODEV);
+	}
+
+	return (0);
+#endif
+}
+
+static void
+ahc_linux_exit(void)
+{
+	struct ahc_softc *ahc;
+
+	/*
+	 * Shutdown DV threads before going into the SCSI mid-layer.
+	 * This avoids situations where the mid-layer locks the entire
+	 * kernel so that waiting for our DV threads to exit leads
+	 * to deadlock.
+	 */
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+
+		ahc_linux_kill_dv_thread(ahc);
+	}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	/*
+	 * In 2.4 we have to unregister from the PCI core _after_
+	 * unregistering from the scsi midlayer to avoid dangling
+	 * references.
+	 */
+	scsi_unregister_module(MODULE_SCSI_HA, &aic7xxx_driver_template);
+#endif
+	ahc_linux_pci_exit();
+	ahc_linux_eisa_exit();
+}
+
+module_init(ahc_linux_init);
+module_exit(ahc_linux_exit);
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
new file mode 100644
index 0000000..db3bd63
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h
@@ -0,0 +1,1130 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * Copyright (c) 2000-2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#151 $
+ *
+ */
+#ifndef _AIC7XXX_LINUX_H_
+#define _AIC7XXX_LINUX_H_
+
+#include <linux/types.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/smp_lock.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <asm/byteorder.h>
+#include <asm/io.h>
+
+#include <linux/interrupt.h> /* For tasklet support. */
+#include <linux/config.h>
+#include <linux/slab.h>
+
+/* Core SCSI definitions */
+#define AIC_LIB_PREFIX ahc
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+/* Name space conflict with BSD queue macros */
+#ifdef LIST_HEAD
+#undef LIST_HEAD
+#endif
+
+#include "cam.h"
+#include "queue.h"
+#include "scsi_message.h"
+#include "aiclib.h"
+
+/*********************************** Debugging ********************************/
+#ifdef CONFIG_AIC7XXX_DEBUG_ENABLE
+#ifdef CONFIG_AIC7XXX_DEBUG_MASK
+#define AHC_DEBUG 1
+#define AHC_DEBUG_OPTS CONFIG_AIC7XXX_DEBUG_MASK
+#else
+/*
+ * Compile in debugging code, but do not enable any printfs.
+ */
+#define AHC_DEBUG 1
+#endif
+/* No debugging code. */
+#endif
+
+/************************* Forward Declarations *******************************/
+struct ahc_softc;
+typedef struct pci_dev *ahc_dev_softc_t;
+typedef Scsi_Cmnd      *ahc_io_ctx_t;
+
+/******************************* Byte Order ***********************************/
+#define ahc_htobe16(x)	cpu_to_be16(x)
+#define ahc_htobe32(x)	cpu_to_be32(x)
+#define ahc_htobe64(x)	cpu_to_be64(x)
+#define ahc_htole16(x)	cpu_to_le16(x)
+#define ahc_htole32(x)	cpu_to_le32(x)
+#define ahc_htole64(x)	cpu_to_le64(x)
+
+#define ahc_be16toh(x)	be16_to_cpu(x)
+#define ahc_be32toh(x)	be32_to_cpu(x)
+#define ahc_be64toh(x)	be64_to_cpu(x)
+#define ahc_le16toh(x)	le16_to_cpu(x)
+#define ahc_le32toh(x)	le32_to_cpu(x)
+#define ahc_le64toh(x)	le64_to_cpu(x)
+
+#ifndef LITTLE_ENDIAN
+#define LITTLE_ENDIAN 1234
+#endif
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN 4321
+#endif
+
+#ifndef BYTE_ORDER
+#if defined(__BIG_ENDIAN)
+#define BYTE_ORDER BIG_ENDIAN
+#endif
+#if defined(__LITTLE_ENDIAN)
+#define BYTE_ORDER LITTLE_ENDIAN
+#endif
+#endif /* BYTE_ORDER */
+
+/************************* Configuration Data *********************************/
+extern u_int aic7xxx_no_probe;
+extern u_int aic7xxx_allow_memio;
+extern int aic7xxx_detect_complete;
+extern Scsi_Host_Template aic7xxx_driver_template;
+
+/***************************** Bus Space/DMA **********************************/
+
+typedef uint32_t bus_size_t;
+
+typedef enum {
+	BUS_SPACE_MEMIO,
+	BUS_SPACE_PIO
+} bus_space_tag_t;
+
+typedef union {
+	u_long		  ioport;
+	volatile uint8_t __iomem *maddr;
+} bus_space_handle_t;
+
+typedef struct bus_dma_segment
+{
+	dma_addr_t	ds_addr;
+	bus_size_t	ds_len;
+} bus_dma_segment_t;
+
+struct ahc_linux_dma_tag
+{
+	bus_size_t	alignment;
+	bus_size_t	boundary;
+	bus_size_t	maxsize;
+};
+typedef struct ahc_linux_dma_tag* bus_dma_tag_t;
+
+struct ahc_linux_dmamap
+{
+	dma_addr_t	bus_addr;
+};
+typedef struct ahc_linux_dmamap* bus_dmamap_t;
+
+typedef int bus_dma_filter_t(void*, dma_addr_t);
+typedef void bus_dmamap_callback_t(void *, bus_dma_segment_t *, int, int);
+
+#define BUS_DMA_WAITOK		0x0
+#define BUS_DMA_NOWAIT		0x1
+#define BUS_DMA_ALLOCNOW	0x2
+#define BUS_DMA_LOAD_SEGS	0x4	/*
+					 * Argument is an S/G list not
+					 * a single buffer.
+					 */
+
+#define BUS_SPACE_MAXADDR	0xFFFFFFFF
+#define BUS_SPACE_MAXADDR_32BIT	0xFFFFFFFF
+#define BUS_SPACE_MAXSIZE_32BIT	0xFFFFFFFF
+
+int	ahc_dma_tag_create(struct ahc_softc *, bus_dma_tag_t /*parent*/,
+			   bus_size_t /*alignment*/, bus_size_t /*boundary*/,
+			   dma_addr_t /*lowaddr*/, dma_addr_t /*highaddr*/,
+			   bus_dma_filter_t*/*filter*/, void */*filterarg*/,
+			   bus_size_t /*maxsize*/, int /*nsegments*/,
+			   bus_size_t /*maxsegsz*/, int /*flags*/,
+			   bus_dma_tag_t */*dma_tagp*/);
+
+void	ahc_dma_tag_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/);
+
+int	ahc_dmamem_alloc(struct ahc_softc *, bus_dma_tag_t /*dmat*/,
+			 void** /*vaddr*/, int /*flags*/,
+			 bus_dmamap_t* /*mapp*/);
+
+void	ahc_dmamem_free(struct ahc_softc *, bus_dma_tag_t /*dmat*/,
+			void* /*vaddr*/, bus_dmamap_t /*map*/);
+
+void	ahc_dmamap_destroy(struct ahc_softc *, bus_dma_tag_t /*tag*/,
+			   bus_dmamap_t /*map*/);
+
+int	ahc_dmamap_load(struct ahc_softc *ahc, bus_dma_tag_t /*dmat*/,
+			bus_dmamap_t /*map*/, void * /*buf*/,
+			bus_size_t /*buflen*/, bus_dmamap_callback_t *,
+			void */*callback_arg*/, int /*flags*/);
+
+int	ahc_dmamap_unload(struct ahc_softc *, bus_dma_tag_t, bus_dmamap_t);
+
+/*
+ * Operations performed by ahc_dmamap_sync().
+ */
+#define BUS_DMASYNC_PREREAD	0x01	/* pre-read synchronization */
+#define BUS_DMASYNC_POSTREAD	0x02	/* post-read synchronization */
+#define BUS_DMASYNC_PREWRITE	0x04	/* pre-write synchronization */
+#define BUS_DMASYNC_POSTWRITE	0x08	/* post-write synchronization */
+
+/*
+ * XXX
+ * ahc_dmamap_sync is only used on buffers allocated with
+ * the pci_alloc_consistent() API.  Although I'm not sure how
+ * this works on architectures with a write buffer, Linux does
+ * not have an API to sync "coherent" memory.  Perhaps we need
+ * to do an mb()?
+ */
+#define ahc_dmamap_sync(ahc, dma_tag, dmamap, offset, len, op)
+
+/************************** Timer DataStructures ******************************/
+typedef struct timer_list ahc_timer_t;
+
+/********************************** Includes **********************************/
+#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT
+#define AIC_DEBUG_REGISTERS 1
+#else
+#define AIC_DEBUG_REGISTERS 0
+#endif
+#include "aic7xxx.h"
+
+/***************************** Timer Facilities *******************************/
+#define ahc_timer_init init_timer
+#define ahc_timer_stop del_timer_sync
+typedef void ahc_linux_callback_t (u_long);  
+static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec,
+				     ahc_callback_t *func, void *arg);
+static __inline void ahc_scb_timer_reset(struct scb *scb, u_int usec);
+
+static __inline void
+ahc_timer_reset(ahc_timer_t *timer, int usec, ahc_callback_t *func, void *arg)
+{
+	struct ahc_softc *ahc;
+
+	ahc = (struct ahc_softc *)arg;
+	del_timer(timer);
+	timer->data = (u_long)arg;
+	timer->expires = jiffies + (usec * HZ)/1000000;
+	timer->function = (ahc_linux_callback_t*)func;
+	add_timer(timer);
+}
+
+static __inline void
+ahc_scb_timer_reset(struct scb *scb, u_int usec)
+{
+	mod_timer(&scb->io_ctx->eh_timeout, jiffies + (usec * HZ)/1000000);
+}
+
+/***************************** SMP support ************************************/
+#include <linux/spinlock.h>
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) || defined(SCSI_HAS_HOST_LOCK))
+#define AHC_SCSI_HAS_HOST_LOCK 1
+#else
+#define AHC_SCSI_HAS_HOST_LOCK 0
+#endif
+
+#define AIC7XXX_DRIVER_VERSION "6.2.36"
+
+/**************************** Front End Queues ********************************/
+/*
+ * Data structure used to cast the Linux struct scsi_cmnd to something
+ * that allows us to use the queue macros.  The linux structure has
+ * plenty of space to hold the links fields as required by the queue
+ * macros, but the queue macors require them to have the correct type.
+ */
+struct ahc_cmd_internal {
+	/* Area owned by the Linux scsi layer. */
+	uint8_t	private[offsetof(struct scsi_cmnd, SCp.Status)];
+	union {
+		STAILQ_ENTRY(ahc_cmd)	ste;
+		LIST_ENTRY(ahc_cmd)	le;
+		TAILQ_ENTRY(ahc_cmd)	tqe;
+	} links;
+	uint32_t			end;
+};
+
+struct ahc_cmd {
+	union {
+		struct ahc_cmd_internal	icmd;
+		struct scsi_cmnd	scsi_cmd;
+	} un;
+};
+
+#define acmd_icmd(cmd) ((cmd)->un.icmd)
+#define acmd_scsi_cmd(cmd) ((cmd)->un.scsi_cmd)
+#define acmd_links un.icmd.links
+
+/*************************** Device Data Structures ***************************/
+/*
+ * A per probed device structure used to deal with some error recovery
+ * scenarios that the Linux mid-layer code just doesn't know how to
+ * handle.  The structure allocated for a device only becomes persistent
+ * after a successfully completed inquiry command to the target when
+ * that inquiry data indicates a lun is present.
+ */
+TAILQ_HEAD(ahc_busyq, ahc_cmd);
+typedef enum {
+	AHC_DEV_UNCONFIGURED	 = 0x01,
+	AHC_DEV_FREEZE_TIL_EMPTY = 0x02, /* Freeze queue until active == 0 */
+	AHC_DEV_TIMER_ACTIVE	 = 0x04, /* Our timer is active */
+	AHC_DEV_ON_RUN_LIST	 = 0x08, /* Queued to be run later */
+	AHC_DEV_Q_BASIC		 = 0x10, /* Allow basic device queuing */
+	AHC_DEV_Q_TAGGED	 = 0x20, /* Allow full SCSI2 command queueing */
+	AHC_DEV_PERIODIC_OTAG	 = 0x40, /* Send OTAG to prevent starvation */
+	AHC_DEV_SLAVE_CONFIGURED = 0x80	 /* slave_configure() has been called */
+} ahc_linux_dev_flags;
+
+struct ahc_linux_target;
+struct ahc_linux_device {
+	TAILQ_ENTRY(ahc_linux_device) links;
+	struct		ahc_busyq busyq;
+
+	/*
+	 * The number of transactions currently
+	 * queued to the device.
+	 */
+	int			active;
+
+	/*
+	 * The currently allowed number of 
+	 * transactions that can be queued to
+	 * the device.  Must be signed for
+	 * conversion from tagged to untagged
+	 * mode where the device may have more
+	 * than one outstanding active transaction.
+	 */
+	int			openings;
+
+	/*
+	 * A positive count indicates that this
+	 * device's queue is halted.
+	 */
+	u_int			qfrozen;
+	
+	/*
+	 * Cumulative command counter.
+	 */
+	u_long			commands_issued;
+
+	/*
+	 * The number of tagged transactions when
+	 * running at our current opening level
+	 * that have been successfully received by
+	 * this device since the last QUEUE FULL.
+	 */
+	u_int			tag_success_count;
+#define AHC_TAG_SUCCESS_INTERVAL 50
+
+	ahc_linux_dev_flags	flags;
+
+	/*
+	 * Per device timer.
+	 */
+	struct timer_list	timer;
+
+	/*
+	 * The high limit for the tags variable.
+	 */
+	u_int			maxtags;
+
+	/*
+	 * The computed number of tags outstanding
+	 * at the time of the last QUEUE FULL event.
+	 */
+	u_int			tags_on_last_queuefull;
+
+	/*
+	 * How many times we have seen a queue full
+	 * with the same number of tags.  This is used
+	 * to stop our adaptive queue depth algorithm
+	 * on devices with a fixed number of tags.
+	 */
+	u_int			last_queuefull_same_count;
+#define AHC_LOCK_TAGS_COUNT 50
+
+	/*
+	 * How many transactions have been queued
+	 * without the device going idle.  We use
+	 * this statistic to determine when to issue
+	 * an ordered tag to prevent transaction
+	 * starvation.  This statistic is only updated
+	 * if the AHC_DEV_PERIODIC_OTAG flag is set
+	 * on this device.
+	 */
+	u_int			commands_since_idle_or_otag;
+#define AHC_OTAG_THRESH	500
+
+	int			lun;
+	Scsi_Device	       *scsi_device;
+	struct			ahc_linux_target *target;
+};
+
+typedef enum {
+	AHC_DV_REQUIRED		 = 0x01,
+	AHC_INQ_VALID		 = 0x02,
+	AHC_BASIC_DV		 = 0x04,
+	AHC_ENHANCED_DV		 = 0x08
+} ahc_linux_targ_flags;
+
+/* DV States */
+typedef enum {
+	AHC_DV_STATE_EXIT = 0,
+	AHC_DV_STATE_INQ_SHORT_ASYNC,
+	AHC_DV_STATE_INQ_ASYNC,
+	AHC_DV_STATE_INQ_ASYNC_VERIFY,
+	AHC_DV_STATE_TUR,
+	AHC_DV_STATE_REBD,
+	AHC_DV_STATE_INQ_VERIFY,
+	AHC_DV_STATE_WEB,
+	AHC_DV_STATE_REB,
+	AHC_DV_STATE_SU,
+	AHC_DV_STATE_BUSY
+} ahc_dv_state;
+
+struct ahc_linux_target {
+	struct ahc_linux_device	 *devices[AHC_NUM_LUNS];
+	int			  channel;
+	int			  target;
+	int			  refcount;
+	struct ahc_transinfo	  last_tinfo;
+	struct ahc_softc	 *ahc;
+	ahc_linux_targ_flags	  flags;
+	struct scsi_inquiry_data *inq_data;
+	/*
+	 * The next "fallback" period to use for narrow/wide transfers.
+	 */
+	uint8_t			  dv_next_narrow_period;
+	uint8_t			  dv_next_wide_period;
+	uint8_t			  dv_max_width;
+	uint8_t			  dv_max_ppr_options;
+	uint8_t			  dv_last_ppr_options;
+	u_int			  dv_echo_size;
+	ahc_dv_state		  dv_state;
+	u_int			  dv_state_retry;
+	char			 *dv_buffer;
+	char			 *dv_buffer1;
+};
+
+/********************* Definitions Required by the Core ***********************/
+/*
+ * Number of SG segments we require.  So long as the S/G segments for
+ * a particular transaction are allocated in a physically contiguous
+ * manner and are allocated below 4GB, the number of S/G segments is
+ * unrestricted.
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * We dynamically adjust the number of segments in pre-2.5 kernels to
+ * avoid fragmentation issues in the SCSI mid-layer's private memory
+ * allocator.  See aic7xxx_osm.c ahc_linux_size_nseg() for details.
+ */
+extern u_int ahc_linux_nseg;
+#define	AHC_NSEG ahc_linux_nseg
+#define	AHC_LINUX_MIN_NSEG 64
+#else
+#define	AHC_NSEG 128
+#endif
+
+/*
+ * Per-SCB OSM storage.
+ */
+typedef enum {
+	AHC_UP_EH_SEMAPHORE = 0x1
+} ahc_linux_scb_flags;
+
+struct scb_platform_data {
+	struct ahc_linux_device	*dev;
+	dma_addr_t		 buf_busaddr;
+	uint32_t		 xfer_len;
+	uint32_t		 sense_resid;	/* Auto-Sense residual */
+	ahc_linux_scb_flags	 flags;
+};
+
+/*
+ * Define a structure used for each host adapter.  All members are
+ * aligned on a boundary >= the size of the member to honor the
+ * alignment restrictions of the various platforms supported by
+ * this driver.
+ */
+typedef enum {
+	AHC_DV_WAIT_SIMQ_EMPTY	 = 0x01,
+	AHC_DV_WAIT_SIMQ_RELEASE = 0x02,
+	AHC_DV_ACTIVE		 = 0x04,
+	AHC_DV_SHUTDOWN		 = 0x08,
+	AHC_RUN_CMPLT_Q_TIMER	 = 0x10
+} ahc_linux_softc_flags;
+
+TAILQ_HEAD(ahc_completeq, ahc_cmd);
+
+struct ahc_platform_data {
+	/*
+	 * Fields accessed from interrupt context.
+	 */
+	struct ahc_linux_target *targets[AHC_NUM_TARGETS]; 
+	TAILQ_HEAD(, ahc_linux_device) device_runq;
+	struct ahc_completeq	 completeq;
+
+	spinlock_t		 spin_lock;
+	struct tasklet_struct	 runq_tasklet;
+	u_int			 qfrozen;
+	pid_t			 dv_pid;
+	struct timer_list	 completeq_timer;
+	struct timer_list	 reset_timer;
+	struct semaphore	 eh_sem;
+	struct semaphore	 dv_sem;
+	struct semaphore	 dv_cmd_sem;	/* XXX This needs to be in
+						 * the target struct
+						 */
+	struct scsi_device	*dv_scsi_dev;
+	struct Scsi_Host        *host;		/* pointer to scsi host */
+#define AHC_LINUX_NOIRQ	((uint32_t)~0)
+	uint32_t		 irq;		/* IRQ for this adapter */
+	uint32_t		 bios_address;
+	uint32_t		 mem_busaddr;	/* Mem Base Addr */
+	uint64_t		 hw_dma_mask;
+	ahc_linux_softc_flags	 flags;
+};
+
+/************************** OS Utility Wrappers *******************************/
+#define printf printk
+#define M_NOWAIT GFP_ATOMIC
+#define M_WAITOK 0
+#define malloc(size, type, flags) kmalloc(size, flags)
+#define free(ptr, type) kfree(ptr)
+
+static __inline void ahc_delay(long);
+static __inline void
+ahc_delay(long usec)
+{
+	/*
+	 * udelay on Linux can have problems for
+	 * multi-millisecond waits.  Wait at most
+	 * 1024us per call.
+	 */
+	while (usec > 0) {
+		udelay(usec % 1024);
+		usec -= 1024;
+	}
+}
+
+
+/***************************** Low Level I/O **********************************/
+static __inline uint8_t ahc_inb(struct ahc_softc * ahc, long port);
+static __inline void ahc_outb(struct ahc_softc * ahc, long port, uint8_t val);
+static __inline void ahc_outsb(struct ahc_softc * ahc, long port,
+			       uint8_t *, int count);
+static __inline void ahc_insb(struct ahc_softc * ahc, long port,
+			       uint8_t *, int count);
+
+static __inline uint8_t
+ahc_inb(struct ahc_softc * ahc, long port)
+{
+	uint8_t x;
+
+	if (ahc->tag == BUS_SPACE_MEMIO) {
+		x = readb(ahc->bsh.maddr + port);
+	} else {
+		x = inb(ahc->bsh.ioport + port);
+	}
+	mb();
+	return (x);
+}
+
+static __inline void
+ahc_outb(struct ahc_softc * ahc, long port, uint8_t val)
+{
+	if (ahc->tag == BUS_SPACE_MEMIO) {
+		writeb(val, ahc->bsh.maddr + port);
+	} else {
+		outb(val, ahc->bsh.ioport + port);
+	}
+	mb();
+}
+
+static __inline void
+ahc_outsb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		ahc_outb(ahc, port, *array++);
+}
+
+static __inline void
+ahc_insb(struct ahc_softc * ahc, long port, uint8_t *array, int count)
+{
+	int i;
+
+	/*
+	 * There is probably a more efficient way to do this on Linux
+	 * but we don't use this for anything speed critical and this
+	 * should work.
+	 */
+	for (i = 0; i < count; i++)
+		*array++ = ahc_inb(ahc, port);
+}
+
+/**************************** Initialization **********************************/
+int		ahc_linux_register_host(struct ahc_softc *,
+					Scsi_Host_Template *);
+
+uint64_t	ahc_linux_get_memsize(void);
+
+/*************************** Pretty Printing **********************************/
+struct info_str {
+	char *buffer;
+	int length;
+	off_t offset;
+	int pos;
+};
+
+void	ahc_format_transinfo(struct info_str *info,
+			     struct ahc_transinfo *tinfo);
+
+/******************************** Locking *************************************/
+/* Lock protecting internal data structures */
+static __inline void ahc_lockinit(struct ahc_softc *);
+static __inline void ahc_lock(struct ahc_softc *, unsigned long *flags);
+static __inline void ahc_unlock(struct ahc_softc *, unsigned long *flags);
+
+/* Lock acquisition and release of the above lock in midlayer entry points. */
+static __inline void ahc_midlayer_entrypoint_lock(struct ahc_softc *,
+						  unsigned long *flags);
+static __inline void ahc_midlayer_entrypoint_unlock(struct ahc_softc *,
+						    unsigned long *flags);
+
+/* Lock held during command compeletion to the upper layer */
+static __inline void ahc_done_lockinit(struct ahc_softc *);
+static __inline void ahc_done_lock(struct ahc_softc *, unsigned long *flags);
+static __inline void ahc_done_unlock(struct ahc_softc *, unsigned long *flags);
+
+/* Lock held during ahc_list manipulation and ahc softc frees */
+extern spinlock_t ahc_list_spinlock;
+static __inline void ahc_list_lockinit(void);
+static __inline void ahc_list_lock(unsigned long *flags);
+static __inline void ahc_list_unlock(unsigned long *flags);
+
+static __inline void
+ahc_lockinit(struct ahc_softc *ahc)
+{
+	spin_lock_init(&ahc->platform_data->spin_lock);
+}
+
+static __inline void
+ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	spin_lock_irqsave(&ahc->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahc->platform_data->spin_lock, *flags);
+}
+
+static __inline void
+ahc_midlayer_entrypoint_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+	/*
+	 * In 2.5.X and some 2.4.X versions, the midlayer takes our
+	 * lock just before calling us, so we avoid locking again.
+	 * For other kernel versions, the io_request_lock is taken
+	 * just before our entry point is called.  In this case, we
+	 * trade the io_request_lock for our per-softc lock.
+	 */
+#if AHC_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&io_request_lock);
+	spin_lock(&ahc->platform_data->spin_lock);
+#endif
+}
+
+static __inline void
+ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+#if AHC_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock(&ahc->platform_data->spin_lock);
+	spin_lock(&io_request_lock);
+#endif
+}
+
+static __inline void
+ahc_done_lockinit(struct ahc_softc *ahc)
+{
+	/*
+	 * In 2.5.X, our own lock is held during completions.
+	 * In previous versions, the io_request_lock is used.
+	 * In either case, we can't initialize this lock again.
+	 */
+}
+
+static __inline void
+ahc_done_lock(struct ahc_softc *ahc, unsigned long *flags)
+{
+#if AHC_SCSI_HAS_HOST_LOCK == 0
+	spin_lock_irqsave(&io_request_lock, *flags);
+#endif
+}
+
+static __inline void
+ahc_done_unlock(struct ahc_softc *ahc, unsigned long *flags)
+{
+#if AHC_SCSI_HAS_HOST_LOCK == 0
+	spin_unlock_irqrestore(&io_request_lock, *flags);
+#endif
+}
+
+static __inline void
+ahc_list_lockinit(void)
+{
+	spin_lock_init(&ahc_list_spinlock);
+}
+
+static __inline void
+ahc_list_lock(unsigned long *flags)
+{
+	spin_lock_irqsave(&ahc_list_spinlock, *flags);
+}
+
+static __inline void
+ahc_list_unlock(unsigned long *flags)
+{
+	spin_unlock_irqrestore(&ahc_list_spinlock, *flags);
+}
+
+/******************************* PCI Definitions ******************************/
+/*
+ * PCIM_xxx: mask to locate subfield in register
+ * PCIR_xxx: config register offset
+ * PCIC_xxx: device class
+ * PCIS_xxx: device subclass
+ * PCIP_xxx: device programming interface
+ * PCIV_xxx: PCI vendor ID (only required to fixup ancient devices)
+ * PCID_xxx: device ID
+ */
+#define PCIR_DEVVENDOR		0x00
+#define PCIR_VENDOR		0x00
+#define PCIR_DEVICE		0x02
+#define PCIR_COMMAND		0x04
+#define PCIM_CMD_PORTEN		0x0001
+#define PCIM_CMD_MEMEN		0x0002
+#define PCIM_CMD_BUSMASTEREN	0x0004
+#define PCIM_CMD_MWRICEN	0x0010
+#define PCIM_CMD_PERRESPEN	0x0040
+#define	PCIM_CMD_SERRESPEN	0x0100
+#define PCIR_STATUS		0x06
+#define PCIR_REVID		0x08
+#define PCIR_PROGIF		0x09
+#define PCIR_SUBCLASS		0x0a
+#define PCIR_CLASS		0x0b
+#define PCIR_CACHELNSZ		0x0c
+#define PCIR_LATTIMER		0x0d
+#define PCIR_HEADERTYPE		0x0e
+#define PCIM_MFDEV		0x80
+#define PCIR_BIST		0x0f
+#define PCIR_CAP_PTR		0x34
+
+/* config registers for header type 0 devices */
+#define PCIR_MAPS	0x10
+#define PCIR_SUBVEND_0	0x2c
+#define PCIR_SUBDEV_0	0x2e
+
+extern struct pci_driver aic7xxx_pci_driver;
+
+typedef enum
+{
+	AHC_POWER_STATE_D0,
+	AHC_POWER_STATE_D1,
+	AHC_POWER_STATE_D2,
+	AHC_POWER_STATE_D3
+} ahc_power_state;
+
+/**************************** VL/EISA Routines ********************************/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) \
+  && (defined(__i386__) || defined(__alpha__)) \
+  && (!defined(CONFIG_EISA)))
+#define CONFIG_EISA
+#endif
+
+#ifdef CONFIG_EISA
+extern uint32_t aic7xxx_probe_eisa_vl;
+int			 ahc_linux_eisa_init(void);
+void			 ahc_linux_eisa_exit(void);
+int			 aic7770_map_registers(struct ahc_softc *ahc,
+					       u_int port);
+int			 aic7770_map_int(struct ahc_softc *ahc, u_int irq);
+#else
+static inline int	ahc_linux_eisa_init(void) {
+	return -ENODEV;
+}
+static inline void	ahc_linux_eisa_exit(void) {
+}
+#endif
+
+/******************************* PCI Routines *********************************/
+#ifdef CONFIG_PCI
+int			 ahc_linux_pci_init(void);
+void			 ahc_linux_pci_exit(void);
+int			 ahc_pci_map_registers(struct ahc_softc *ahc);
+int			 ahc_pci_map_int(struct ahc_softc *ahc);
+
+static __inline uint32_t ahc_pci_read_config(ahc_dev_softc_t pci,
+					     int reg, int width);
+
+static __inline uint32_t
+ahc_pci_read_config(ahc_dev_softc_t pci, int reg, int width)
+{
+	switch (width) {
+	case 1:
+	{
+		uint8_t retval;
+
+		pci_read_config_byte(pci, reg, &retval);
+		return (retval);
+	}
+	case 2:
+	{
+		uint16_t retval;
+		pci_read_config_word(pci, reg, &retval);
+		return (retval);
+	}
+	case 4:
+	{
+		uint32_t retval;
+		pci_read_config_dword(pci, reg, &retval);
+		return (retval);
+	}
+	default:
+		panic("ahc_pci_read_config: Read size too big");
+		/* NOTREACHED */
+		return (0);
+	}
+}
+
+static __inline void ahc_pci_write_config(ahc_dev_softc_t pci,
+					  int reg, uint32_t value,
+					  int width);
+
+static __inline void
+ahc_pci_write_config(ahc_dev_softc_t pci, int reg, uint32_t value, int width)
+{
+	switch (width) {
+	case 1:
+		pci_write_config_byte(pci, reg, value);
+		break;
+	case 2:
+		pci_write_config_word(pci, reg, value);
+		break;
+	case 4:
+		pci_write_config_dword(pci, reg, value);
+		break;
+	default:
+		panic("ahc_pci_write_config: Write size too big");
+		/* NOTREACHED */
+	}
+}
+
+static __inline int ahc_get_pci_function(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_function(ahc_dev_softc_t pci)
+{
+	return (PCI_FUNC(pci->devfn));
+}
+
+static __inline int ahc_get_pci_slot(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_slot(ahc_dev_softc_t pci)
+{
+	return (PCI_SLOT(pci->devfn));
+}
+
+static __inline int ahc_get_pci_bus(ahc_dev_softc_t);
+static __inline int
+ahc_get_pci_bus(ahc_dev_softc_t pci)
+{
+	return (pci->bus->number);
+}
+#else
+static inline int ahc_linux_pci_init(void) {
+	return 0;
+}
+static inline void ahc_linux_pci_exit(void) {
+}
+#endif
+
+static __inline void ahc_flush_device_writes(struct ahc_softc *);
+static __inline void
+ahc_flush_device_writes(struct ahc_softc *ahc)
+{
+	/* XXX Is this sufficient for all architectures??? */
+	ahc_inb(ahc, INTSTAT);
+}
+
+/**************************** Proc FS Support *********************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+int	ahc_linux_proc_info(char *, char **, off_t, int, int, int);
+#else
+int	ahc_linux_proc_info(struct Scsi_Host *, char *, char **,
+			    off_t, int, int);
+#endif
+
+/*************************** Domain Validation ********************************/
+#define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete)
+#define AHC_DV_SIMQ_FROZEN(ahc)					\
+	((((ahc)->platform_data->flags & AHC_DV_ACTIVE) != 0)	\
+	 && (ahc)->platform_data->qfrozen == 1)
+
+/*********************** Transaction Access Wrappers *************************/
+static __inline void ahc_cmd_set_transaction_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahc_set_transaction_status(struct scb *, uint32_t);
+static __inline void ahc_cmd_set_scsi_status(Scsi_Cmnd *, uint32_t);
+static __inline void ahc_set_scsi_status(struct scb *, uint32_t);
+static __inline uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahc_get_transaction_status(struct scb *);
+static __inline uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd);
+static __inline uint32_t ahc_get_scsi_status(struct scb *);
+static __inline void ahc_set_transaction_tag(struct scb *, int, u_int);
+static __inline u_long ahc_get_transfer_length(struct scb *);
+static __inline int ahc_get_transfer_dir(struct scb *);
+static __inline void ahc_set_residual(struct scb *, u_long);
+static __inline void ahc_set_sense_residual(struct scb *scb, u_long resid);
+static __inline u_long ahc_get_residual(struct scb *);
+static __inline u_long ahc_get_sense_residual(struct scb *);
+static __inline int ahc_perform_autosense(struct scb *);
+static __inline uint32_t ahc_get_sense_bufsize(struct ahc_softc *,
+					       struct scb *);
+static __inline void ahc_notify_xfer_settings_change(struct ahc_softc *,
+						     struct ahc_devinfo *);
+static __inline void ahc_platform_scb_free(struct ahc_softc *ahc,
+					   struct scb *scb);
+static __inline void ahc_freeze_scb(struct scb *scb);
+
+static __inline
+void ahc_cmd_set_transaction_status(Scsi_Cmnd *cmd, uint32_t status)
+{
+	cmd->result &= ~(CAM_STATUS_MASK << 16);
+	cmd->result |= status << 16;
+}
+
+static __inline
+void ahc_set_transaction_status(struct scb *scb, uint32_t status)
+{
+	ahc_cmd_set_transaction_status(scb->io_ctx,status);
+}
+
+static __inline
+void ahc_cmd_set_scsi_status(Scsi_Cmnd *cmd, uint32_t status)
+{
+	cmd->result &= ~0xFFFF;
+	cmd->result |= status;
+}
+
+static __inline
+void ahc_set_scsi_status(struct scb *scb, uint32_t status)
+{
+	ahc_cmd_set_scsi_status(scb->io_ctx, status);
+}
+
+static __inline
+uint32_t ahc_cmd_get_transaction_status(Scsi_Cmnd *cmd)
+{
+	return ((cmd->result >> 16) & CAM_STATUS_MASK);
+}
+
+static __inline
+uint32_t ahc_get_transaction_status(struct scb *scb)
+{
+	return (ahc_cmd_get_transaction_status(scb->io_ctx));
+}
+
+static __inline
+uint32_t ahc_cmd_get_scsi_status(Scsi_Cmnd *cmd)
+{
+	return (cmd->result & 0xFFFF);
+}
+
+static __inline
+uint32_t ahc_get_scsi_status(struct scb *scb)
+{
+	return (ahc_cmd_get_scsi_status(scb->io_ctx));
+}
+
+static __inline
+void ahc_set_transaction_tag(struct scb *scb, int enabled, u_int type)
+{
+	/*
+	 * Nothing to do for linux as the incoming transaction
+	 * has no concept of tag/non tagged, etc.
+	 */
+}
+
+static __inline
+u_long ahc_get_transfer_length(struct scb *scb)
+{
+	return (scb->platform_data->xfer_len);
+}
+
+static __inline
+int ahc_get_transfer_dir(struct scb *scb)
+{
+	return (scb->io_ctx->sc_data_direction);
+}
+
+static __inline
+void ahc_set_residual(struct scb *scb, u_long resid)
+{
+	scb->io_ctx->resid = resid;
+}
+
+static __inline
+void ahc_set_sense_residual(struct scb *scb, u_long resid)
+{
+	scb->platform_data->sense_resid = resid;
+}
+
+static __inline
+u_long ahc_get_residual(struct scb *scb)
+{
+	return (scb->io_ctx->resid);
+}
+
+static __inline
+u_long ahc_get_sense_residual(struct scb *scb)
+{
+	return (scb->platform_data->sense_resid);
+}
+
+static __inline
+int ahc_perform_autosense(struct scb *scb)
+{
+	/*
+	 * We always perform autosense in Linux.
+	 * On other platforms this is set on a
+	 * per-transaction basis.
+	 */
+	return (1);
+}
+
+static __inline uint32_t
+ahc_get_sense_bufsize(struct ahc_softc *ahc, struct scb *scb)
+{
+	return (sizeof(struct scsi_sense_data));
+}
+
+static __inline void
+ahc_notify_xfer_settings_change(struct ahc_softc *ahc,
+				struct ahc_devinfo *devinfo)
+{
+	/* Nothing to do here for linux */
+}
+
+static __inline void
+ahc_platform_scb_free(struct ahc_softc *ahc, struct scb *scb)
+{
+	ahc->flags &= ~AHC_RESOURCE_SHORTAGE;
+}
+
+int	ahc_platform_alloc(struct ahc_softc *ahc, void *platform_arg);
+void	ahc_platform_free(struct ahc_softc *ahc);
+void	ahc_platform_freeze_devq(struct ahc_softc *ahc, struct scb *scb);
+
+static __inline void
+ahc_freeze_scb(struct scb *scb)
+{
+	if ((scb->io_ctx->result & (CAM_DEV_QFRZN << 16)) == 0) {
+                scb->io_ctx->result |= CAM_DEV_QFRZN << 16;
+                scb->platform_data->dev->qfrozen++;
+        }
+}
+
+void	ahc_platform_set_tags(struct ahc_softc *ahc,
+			      struct ahc_devinfo *devinfo, ahc_queue_alg);
+int	ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
+				char channel, int lun, u_int tag,
+				role_t role, uint32_t status);
+irqreturn_t
+	ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+void	ahc_platform_flushwork(struct ahc_softc *ahc);
+int	ahc_softc_comp(struct ahc_softc *, struct ahc_softc *);
+void	ahc_done(struct ahc_softc*, struct scb*);
+void	ahc_send_async(struct ahc_softc *, char channel,
+		       u_int target, u_int lun, ac_code, void *);
+void	ahc_print_path(struct ahc_softc *, struct scb *);
+void	ahc_platform_dump_card_state(struct ahc_softc *ahc);
+
+#ifdef CONFIG_PCI
+#define AHC_PCI_CONFIG 1
+#else
+#define AHC_PCI_CONFIG 0
+#endif
+#define bootverbose aic7xxx_verbose
+extern u_int aic7xxx_verbose;
+#endif /* _AIC7XXX_LINUX_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
new file mode 100644
index 0000000..6f6674a
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c
@@ -0,0 +1,389 @@
+/*
+ * Linux driver attachment glue for PCI based controllers.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#47 $
+ */
+
+#include "aic7xxx_osm.h"
+#include "aic7xxx_pci.h"
+
+static int	ahc_linux_pci_dev_probe(struct pci_dev *pdev,
+					const struct pci_device_id *ent);
+static int	ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc,
+						u_long *base);
+static int	ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
+						 u_long *bus_addr,
+						 uint8_t __iomem **maddr);
+static void	ahc_linux_pci_dev_remove(struct pci_dev *pdev);
+
+/* Define the macro locally since it's different for different class of chips.
+*/
+#define ID(x)	ID_C(x, PCI_CLASS_STORAGE_SCSI)
+
+static struct pci_device_id ahc_linux_pci_id_table[] = {
+	/* aic7850 based controllers */
+	ID(ID_AHA_2902_04_10_15_20C_30C),
+	/* aic7860 based controllers */
+	ID(ID_AHA_2930CU),
+	ID(ID_AHA_1480A & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK),
+	/* aic7870 based controllers */
+	ID(ID_AHA_2940),
+	ID(ID_AHA_3940),
+	ID(ID_AHA_398X),
+	ID(ID_AHA_2944),
+	ID(ID_AHA_3944),
+	ID(ID_AHA_4944),
+	/* aic7880 based controllers */
+	ID(ID_AHA_2940U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_3940U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2944U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_3944U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_398XU & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_4944U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2930U & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK),
+	ID(ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK),
+	/* aic7890 based controllers */
+	ID(ID_AHA_2930U2),
+	ID(ID_AHA_2940U2B),
+	ID(ID_AHA_2940U2_OEM),
+	ID(ID_AHA_2940U2),
+	ID(ID_AHA_2950U2B),
+	ID16(ID_AIC7890_ARO & ID_AIC7895_ARO_MASK),
+	ID(ID_AAA_131U2),
+	/* aic7890 based controllers */
+	ID(ID_AHA_29160),
+	ID(ID_AHA_29160_CPQ),
+	ID(ID_AHA_29160N),
+	ID(ID_AHA_29160C),
+	ID(ID_AHA_29160B),
+	ID(ID_AHA_19160B),
+	ID(ID_AIC7892_ARO),
+	/* aic7892 based controllers */
+	ID(ID_AHA_2940U_DUAL),
+	ID(ID_AHA_3940AU),
+	ID(ID_AHA_3944AU),
+	ID(ID_AIC7895_ARO),
+	ID(ID_AHA_3950U2B_0),
+	ID(ID_AHA_3950U2B_1),
+	ID(ID_AHA_3950U2D_0),
+	ID(ID_AHA_3950U2D_1),
+	ID(ID_AIC7896_ARO),
+	/* aic7899 based controllers */
+	ID(ID_AHA_3960D),
+	ID(ID_AHA_3960D_CPQ),
+	ID(ID_AIC7899_ARO),
+	/* Generic chip probes for devices we don't know exactly. */
+	ID(ID_AIC7850 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7855 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7859 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7860 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7870 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7880 & ID_DEV_VENDOR_MASK),
+ 	ID16(ID_AIC7890 & ID_9005_GENERIC_MASK),
+ 	ID16(ID_AIC7892 & ID_9005_GENERIC_MASK),
+	ID(ID_AIC7895 & ID_DEV_VENDOR_MASK),
+	ID16(ID_AIC7896 & ID_9005_GENERIC_MASK),
+	ID16(ID_AIC7899 & ID_9005_GENERIC_MASK),
+	ID(ID_AIC7810 & ID_DEV_VENDOR_MASK),
+	ID(ID_AIC7815 & ID_DEV_VENDOR_MASK),
+	{ 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, ahc_linux_pci_id_table);
+
+struct pci_driver aic7xxx_pci_driver = {
+	.name		= "aic7xxx",
+	.probe		= ahc_linux_pci_dev_probe,
+	.remove		= ahc_linux_pci_dev_remove,
+	.id_table	= ahc_linux_pci_id_table
+};
+
+static void
+ahc_linux_pci_dev_remove(struct pci_dev *pdev)
+{
+	struct ahc_softc *ahc;
+	u_long l;
+
+	/*
+	 * We should be able to just perform
+	 * the free directly, but check our
+	 * list for extra sanity.
+	 */
+	ahc_list_lock(&l);
+	ahc = ahc_find_softc((struct ahc_softc *)pci_get_drvdata(pdev));
+	if (ahc != NULL) {
+		u_long s;
+
+		TAILQ_REMOVE(&ahc_tailq, ahc, links);
+		ahc_list_unlock(&l);
+		ahc_lock(ahc, &s);
+		ahc_intr_enable(ahc, FALSE);
+		ahc_unlock(ahc, &s);
+		ahc_free(ahc);
+	} else
+		ahc_list_unlock(&l);
+}
+
+static int
+ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	char		 buf[80];
+	const uint64_t	 mask_39bit = 0x7FFFFFFFFFULL;
+	struct		 ahc_softc *ahc;
+	ahc_dev_softc_t	 pci;
+	struct		 ahc_pci_identity *entry;
+	char		*name;
+	int		 error;
+
+	/*
+	 * Some BIOSen report the same device multiple times.
+	 */
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		struct pci_dev *probed_pdev;
+
+		probed_pdev = ahc->dev_softc;
+		if (probed_pdev->bus->number == pdev->bus->number
+		 && probed_pdev->devfn == pdev->devfn)
+			break;
+	}
+	if (ahc != NULL) {
+		/* Skip duplicate. */
+		return (-ENODEV);
+	}
+
+	pci = pdev;
+	entry = ahc_find_pci_device(pci);
+	if (entry == NULL)
+		return (-ENODEV);
+
+	/*
+	 * Allocate a softc for this card and
+	 * set it up for attachment by our
+	 * common detect routine.
+	 */
+	sprintf(buf, "ahc_pci:%d:%d:%d",
+		ahc_get_pci_bus(pci),
+		ahc_get_pci_slot(pci),
+		ahc_get_pci_function(pci));
+	name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
+	if (name == NULL)
+		return (-ENOMEM);
+	strcpy(name, buf);
+	ahc = ahc_alloc(NULL, name);
+	if (ahc == NULL)
+		return (-ENOMEM);
+	if (pci_enable_device(pdev)) {
+		ahc_free(ahc);
+		return (-ENODEV);
+	}
+	pci_set_master(pdev);
+
+	if (sizeof(dma_addr_t) > 4
+	 && ahc_linux_get_memsize() > 0x80000000
+	 && pci_set_dma_mask(pdev, mask_39bit) == 0) {
+		ahc->flags |= AHC_39BIT_ADDRESSING;
+		ahc->platform_data->hw_dma_mask = mask_39bit;
+	} else {
+		if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) {
+			printk(KERN_WARNING "aic7xxx: No suitable DMA available.\n");
+                	return (-ENODEV);
+		}
+		ahc->platform_data->hw_dma_mask = DMA_32BIT_MASK;
+	}
+	ahc->dev_softc = pci;
+	error = ahc_pci_config(ahc, entry);
+	if (error != 0) {
+		ahc_free(ahc);
+		return (-error);
+	}
+	pci_set_drvdata(pdev, ahc);
+	if (aic7xxx_detect_complete) {
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		ahc_linux_register_host(ahc, &aic7xxx_driver_template);
+#else
+		printf("aic7xxx: ignoring PCI device found after "
+		       "initialization\n");
+		return (-ENODEV);
+#endif
+	}
+	return (0);
+}
+
+int
+ahc_linux_pci_init(void)
+{
+	/* Translate error or zero return into zero or one */
+	return pci_module_init(&aic7xxx_pci_driver) ? 0 : 1;
+}
+
+void
+ahc_linux_pci_exit(void)
+{
+	pci_unregister_driver(&aic7xxx_pci_driver);
+}
+
+static int
+ahc_linux_pci_reserve_io_region(struct ahc_softc *ahc, u_long *base)
+{
+	if (aic7xxx_allow_memio == 0)
+		return (ENOMEM);
+
+	*base = pci_resource_start(ahc->dev_softc, 0);
+	if (*base == 0)
+		return (ENOMEM);
+	if (request_region(*base, 256, "aic7xxx") == 0)
+		return (ENOMEM);
+	return (0);
+}
+
+static int
+ahc_linux_pci_reserve_mem_region(struct ahc_softc *ahc,
+				 u_long *bus_addr,
+				 uint8_t __iomem **maddr)
+{
+	u_long	start;
+	int	error;
+
+	error = 0;
+	start = pci_resource_start(ahc->dev_softc, 1);
+	if (start != 0) {
+		*bus_addr = start;
+		if (request_mem_region(start, 0x1000, "aic7xxx") == 0)
+			error = ENOMEM;
+		if (error == 0) {
+			*maddr = ioremap_nocache(start, 256);
+			if (*maddr == NULL) {
+				error = ENOMEM;
+				release_mem_region(start, 0x1000);
+			}
+		}
+	} else
+		error = ENOMEM;
+	return (error);
+}
+
+int
+ahc_pci_map_registers(struct ahc_softc *ahc)
+{
+	uint32_t command;
+	u_long	 base;
+	uint8_t	__iomem *maddr;
+	int	 error;
+
+	/*
+	 * If its allowed, we prefer memory mapped access.
+	 */
+	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, 4);
+	command &= ~(PCIM_CMD_PORTEN|PCIM_CMD_MEMEN);
+	base = 0;
+	maddr = NULL;
+	error = ahc_linux_pci_reserve_mem_region(ahc, &base, &maddr);
+	if (error == 0) {
+		ahc->platform_data->mem_busaddr = base;
+		ahc->tag = BUS_SPACE_MEMIO;
+		ahc->bsh.maddr = maddr;
+		ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+				     command | PCIM_CMD_MEMEN, 4);
+
+		/*
+		 * Do a quick test to see if memory mapped
+		 * I/O is functioning correctly.
+		 */
+		if (ahc_pci_test_register_access(ahc) != 0) {
+
+			printf("aic7xxx: PCI Device %d:%d:%d "
+			       "failed memory mapped test.  Using PIO.\n",
+			       ahc_get_pci_bus(ahc->dev_softc),
+			       ahc_get_pci_slot(ahc->dev_softc),
+			       ahc_get_pci_function(ahc->dev_softc));
+			iounmap(maddr);
+			release_mem_region(ahc->platform_data->mem_busaddr,
+					   0x1000);
+			ahc->bsh.maddr = NULL;
+			maddr = NULL;
+		} else
+			command |= PCIM_CMD_MEMEN;
+	} else {
+		printf("aic7xxx: PCI%d:%d:%d MEM region 0x%lx "
+		       "unavailable. Cannot memory map device.\n",
+		       ahc_get_pci_bus(ahc->dev_softc),
+		       ahc_get_pci_slot(ahc->dev_softc),
+		       ahc_get_pci_function(ahc->dev_softc),
+		       base);
+	}
+
+	/*
+	 * We always prefer memory mapped access.
+	 */
+	if (maddr == NULL) {
+
+		error = ahc_linux_pci_reserve_io_region(ahc, &base);
+		if (error == 0) {
+			ahc->tag = BUS_SPACE_PIO;
+			ahc->bsh.ioport = base;
+			command |= PCIM_CMD_PORTEN;
+		} else {
+			printf("aic7xxx: PCI%d:%d:%d IO region 0x%lx[0..255] "
+			       "unavailable. Cannot map device.\n",
+			       ahc_get_pci_bus(ahc->dev_softc),
+			       ahc_get_pci_slot(ahc->dev_softc),
+			       ahc_get_pci_function(ahc->dev_softc),
+			       base);
+		}
+	}
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, 4);
+	return (error);
+}
+
+int
+ahc_pci_map_int(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = request_irq(ahc->dev_softc->irq, ahc_linux_isr,
+			    SA_SHIRQ, "aic7xxx", ahc);
+	if (error == 0)
+		ahc->platform_data->irq = ahc->dev_softc->irq;
+	
+	return (-error);
+}
+
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
new file mode 100644
index 0000000..7ddcc97
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c
@@ -0,0 +1,2407 @@
+/*
+ * Product specific probe and attach routines for:
+ *      3940, 2940, aic7895, aic7890, aic7880,
+ *	aic7870, aic7860 and aic7850 SCSI controllers
+ *
+ * Copyright (c) 1994-2001 Justin T. Gibbs.
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#69 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+#else
+#include <dev/aic7xxx/aic7xxx_osm.h>
+#include <dev/aic7xxx/aic7xxx_inline.h>
+#include <dev/aic7xxx/aic7xxx_93cx6.h>
+#endif
+
+#include "aic7xxx_pci.h"
+
+static __inline uint64_t
+ahc_compose_id(u_int device, u_int vendor, u_int subdevice, u_int subvendor)
+{
+	uint64_t id;
+
+	id = subvendor
+	   | (subdevice << 16)
+	   | ((uint64_t)vendor << 32)
+	   | ((uint64_t)device << 48);
+
+	return (id);
+}
+
+#define AHC_PCI_IOADDR	PCIR_MAPS	/* I/O Address */
+#define AHC_PCI_MEMADDR	(PCIR_MAPS + 4)	/* Mem I/O Address */
+
+#define DEVID_9005_TYPE(id) ((id) & 0xF)
+#define		DEVID_9005_TYPE_HBA		0x0	/* Standard Card */
+#define		DEVID_9005_TYPE_AAA		0x3	/* RAID Card */
+#define		DEVID_9005_TYPE_SISL		0x5	/* Container ROMB */
+#define		DEVID_9005_TYPE_MB		0xF	/* On Motherboard */
+
+#define DEVID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define		DEVID_9005_MAXRATE_U160		0x0
+#define		DEVID_9005_MAXRATE_ULTRA2	0x1
+#define		DEVID_9005_MAXRATE_ULTRA	0x2
+#define		DEVID_9005_MAXRATE_FAST		0x3
+
+#define DEVID_9005_MFUNC(id) (((id) & 0x40) >> 6)
+
+#define DEVID_9005_CLASS(id) (((id) & 0xFF00) >> 8)
+#define		DEVID_9005_CLASS_SPI		0x0	/* Parallel SCSI */
+
+#define SUBID_9005_TYPE(id) ((id) & 0xF)
+#define		SUBID_9005_TYPE_MB		0xF	/* On Motherboard */
+#define		SUBID_9005_TYPE_CARD		0x0	/* Standard Card */
+#define		SUBID_9005_TYPE_LCCARD		0x1	/* Low Cost Card */
+#define		SUBID_9005_TYPE_RAID		0x3	/* Combined with Raid */
+
+#define SUBID_9005_TYPE_KNOWN(id)			\
+	  ((((id) & 0xF) == SUBID_9005_TYPE_MB)		\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_CARD)	\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_LCCARD)	\
+	|| (((id) & 0xF) == SUBID_9005_TYPE_RAID))
+
+#define SUBID_9005_MAXRATE(id) (((id) & 0x30) >> 4)
+#define		SUBID_9005_MAXRATE_ULTRA2	0x0
+#define		SUBID_9005_MAXRATE_ULTRA	0x1
+#define		SUBID_9005_MAXRATE_U160		0x2
+#define		SUBID_9005_MAXRATE_RESERVED	0x3
+
+#define SUBID_9005_SEEPTYPE(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0xC0) >> 6						\
+	 : ((id) & 0x300) >> 8)
+#define		SUBID_9005_SEEPTYPE_NONE	0x0
+#define		SUBID_9005_SEEPTYPE_1K		0x1
+#define		SUBID_9005_SEEPTYPE_2K_4K	0x2
+#define		SUBID_9005_SEEPTYPE_RESERVED	0x3
+#define SUBID_9005_AUTOTERM(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? (((id) & 0x400) >> 10) == 0					\
+	 : (((id) & 0x40) >> 6) == 0)
+
+#define SUBID_9005_NUMCHAN(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0x300) >> 8						\
+	 : ((id) & 0xC00) >> 10)
+
+#define SUBID_9005_LEGACYCONN(id)					\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? 0								\
+	 : ((id) & 0x80) >> 7)
+
+#define SUBID_9005_MFUNCENB(id)						\
+	((SUBID_9005_TYPE(id) == SUBID_9005_TYPE_MB)			\
+	 ? ((id) & 0x800) >> 11						\
+	 : ((id) & 0x1000) >> 12)
+/*
+ * Informational only. Should use chip register to be
+ * certain, but may be use in identification strings.
+ */
+#define SUBID_9005_CARD_SCSIWIDTH_MASK	0x2000
+#define SUBID_9005_CARD_PCIWIDTH_MASK	0x4000
+#define SUBID_9005_CARD_SEDIFF_MASK	0x8000
+
+static ahc_device_setup_t ahc_aic785X_setup;
+static ahc_device_setup_t ahc_aic7860_setup;
+static ahc_device_setup_t ahc_apa1480_setup;
+static ahc_device_setup_t ahc_aic7870_setup;
+static ahc_device_setup_t ahc_aha394X_setup;
+static ahc_device_setup_t ahc_aha494X_setup;
+static ahc_device_setup_t ahc_aha398X_setup;
+static ahc_device_setup_t ahc_aic7880_setup;
+static ahc_device_setup_t ahc_aha2940Pro_setup;
+static ahc_device_setup_t ahc_aha394XU_setup;
+static ahc_device_setup_t ahc_aha398XU_setup;
+static ahc_device_setup_t ahc_aic7890_setup;
+static ahc_device_setup_t ahc_aic7892_setup;
+static ahc_device_setup_t ahc_aic7895_setup;
+static ahc_device_setup_t ahc_aic7896_setup;
+static ahc_device_setup_t ahc_aic7899_setup;
+static ahc_device_setup_t ahc_aha29160C_setup;
+static ahc_device_setup_t ahc_raid_setup;
+static ahc_device_setup_t ahc_aha394XX_setup;
+static ahc_device_setup_t ahc_aha494XX_setup;
+static ahc_device_setup_t ahc_aha398XX_setup;
+
+struct ahc_pci_identity ahc_pci_ident_table [] =
+{
+	/* aic7850 based controllers */
+	{
+		ID_AHA_2902_04_10_15_20C_30C,
+		ID_ALL_MASK,
+		"Adaptec 2902/04/10/15/20C/30C SCSI adapter",
+		ahc_aic785X_setup
+	},
+	/* aic7860 based controllers */
+	{
+		ID_AHA_2930CU,
+		ID_ALL_MASK,
+		"Adaptec 2930CU SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_1480A & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 1480A Ultra SCSI adapter",
+		ahc_apa1480_setup
+	},
+	{
+		ID_AHA_2940AU_0 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940A Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_2940AU_CN & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940A/CN Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AHA_2930C_VAR & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2930C Ultra SCSI adapter (VAR)",
+		ahc_aic7860_setup
+	},
+	/* aic7870 based controllers */
+	{
+		ID_AHA_2940,
+		ID_ALL_MASK,
+		"Adaptec 2940 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AHA_3940,
+		ID_ALL_MASK,
+		"Adaptec 3940 SCSI adapter",
+		ahc_aha394X_setup
+	},
+	{
+		ID_AHA_398X,
+		ID_ALL_MASK,
+		"Adaptec 398X SCSI RAID adapter",
+		ahc_aha398X_setup
+	},
+	{
+		ID_AHA_2944,
+		ID_ALL_MASK,
+		"Adaptec 2944 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AHA_3944,
+		ID_ALL_MASK,
+		"Adaptec 3944 SCSI adapter",
+		ahc_aha394X_setup
+	},
+	{
+		ID_AHA_4944,
+		ID_ALL_MASK,
+		"Adaptec 4944 SCSI adapter",
+		ahc_aha494X_setup
+	},
+	/* aic7880 based controllers */
+	{
+		ID_AHA_2940U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_3940U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 3940 Ultra SCSI adapter",
+		ahc_aha394XU_setup
+	},
+	{
+		ID_AHA_2944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2944 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_3944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 3944 Ultra SCSI adapter",
+		ahc_aha394XU_setup
+	},
+	{
+		ID_AHA_398XU & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 398X Ultra SCSI RAID adapter",
+		ahc_aha398XU_setup
+	},
+	{
+		/*
+		 * XXX Don't know the slot numbers
+		 * so we can't identify channels
+		 */
+		ID_AHA_4944U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 4944 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_2930U & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2930 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AHA_2940U_PRO & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940 Pro Ultra SCSI adapter",
+		ahc_aha2940Pro_setup
+	},
+	{
+		ID_AHA_2940U_CN & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec 2940/CN Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	/* Ignore all SISL (AAC on MB) based controllers. */
+	{
+		ID_9005_SISL_ID,
+		ID_9005_SISL_MASK,
+		NULL,
+		NULL
+	},
+	/* aic7890 based controllers */
+	{
+		ID_AHA_2930U2,
+		ID_ALL_MASK,
+		"Adaptec 2930 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2B,
+		ID_ALL_MASK,
+		"Adaptec 2940B Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2_OEM,
+		ID_ALL_MASK,
+		"Adaptec 2940 Ultra2 SCSI adapter (OEM)",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2940U2,
+		ID_ALL_MASK,
+		"Adaptec 2940 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AHA_2950U2B,
+		ID_ALL_MASK,
+		"Adaptec 2950 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AIC7890_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7890/91 Ultra2 SCSI adapter (ARO)",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AAA_131U2,
+		ID_ALL_MASK,
+		"Adaptec AAA-131 Ultra2 RAID adapter",
+		ahc_aic7890_setup
+	},
+	/* aic7892 based controllers */
+	{
+		ID_AHA_29160,
+		ID_ALL_MASK,
+		"Adaptec 29160 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160_CPQ,
+		ID_ALL_MASK,
+		"Adaptec (Compaq OEM) 29160 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160N,
+		ID_ALL_MASK,
+		"Adaptec 29160N Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_29160C,
+		ID_ALL_MASK,
+		"Adaptec 29160C Ultra160 SCSI adapter",
+		ahc_aha29160C_setup
+	},
+	{
+		ID_AHA_29160B,
+		ID_ALL_MASK,
+		"Adaptec 29160B Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AHA_19160B,
+		ID_ALL_MASK,
+		"Adaptec 19160B Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AIC7892_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7892 Ultra160 SCSI adapter (ARO)",
+		ahc_aic7892_setup
+	},
+	/* aic7895 based controllers */	
+	{
+		ID_AHA_2940U_DUAL,
+		ID_ALL_MASK,
+		"Adaptec 2940/DUAL Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AHA_3940AU,
+		ID_ALL_MASK,
+		"Adaptec 3940A Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AHA_3944AU,
+		ID_ALL_MASK,
+		"Adaptec 3944A Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AIC7895_ARO,
+		ID_AIC7895_ARO_MASK,
+		"Adaptec aic7895 Ultra SCSI adapter (ARO)",
+		ahc_aic7895_setup
+	},
+	/* aic7896/97 based controllers */	
+	{
+		ID_AHA_3950U2B_0,
+		ID_ALL_MASK,
+		"Adaptec 3950B Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2B_1,
+		ID_ALL_MASK,
+		"Adaptec 3950B Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2D_0,
+		ID_ALL_MASK,
+		"Adaptec 3950D Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AHA_3950U2D_1,
+		ID_ALL_MASK,
+		"Adaptec 3950D Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AIC7896_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7896/97 Ultra2 SCSI adapter (ARO)",
+		ahc_aic7896_setup
+	},
+	/* aic7899 based controllers */	
+	{
+		ID_AHA_3960D,
+		ID_ALL_MASK,
+		"Adaptec 3960D Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AHA_3960D_CPQ,
+		ID_ALL_MASK,
+		"Adaptec (Compaq OEM) 3960D Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AIC7899_ARO,
+		ID_ALL_MASK,
+		"Adaptec aic7899 Ultra160 SCSI adapter (ARO)",
+		ahc_aic7899_setup
+	},
+	/* Generic chip probes for devices we don't know 'exactly' */
+	{
+		ID_AIC7850 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7850 SCSI adapter",
+		ahc_aic785X_setup
+	},
+	{
+		ID_AIC7855 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7855 SCSI adapter",
+		ahc_aic785X_setup
+	},
+	{
+		ID_AIC7859 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7859 SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AIC7860 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7860 Ultra SCSI adapter",
+		ahc_aic7860_setup
+	},
+	{
+		ID_AIC7870 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7870 SCSI adapter",
+		ahc_aic7870_setup
+	},
+	{
+		ID_AIC7880 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7880 Ultra SCSI adapter",
+		ahc_aic7880_setup
+	},
+	{
+		ID_AIC7890 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7890/91 Ultra2 SCSI adapter",
+		ahc_aic7890_setup
+	},
+	{
+		ID_AIC7892 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7892 Ultra160 SCSI adapter",
+		ahc_aic7892_setup
+	},
+	{
+		ID_AIC7895 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7895 Ultra SCSI adapter",
+		ahc_aic7895_setup
+	},
+	{
+		ID_AIC7896 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7896/97 Ultra2 SCSI adapter",
+		ahc_aic7896_setup
+	},
+	{
+		ID_AIC7899 & ID_9005_GENERIC_MASK,
+		ID_9005_GENERIC_MASK,
+		"Adaptec aic7899 Ultra160 SCSI adapter",
+		ahc_aic7899_setup
+	},
+	{
+		ID_AIC7810 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7810 RAID memory controller",
+		ahc_raid_setup
+	},
+	{
+		ID_AIC7815 & ID_DEV_VENDOR_MASK,
+		ID_DEV_VENDOR_MASK,
+		"Adaptec aic7815 RAID memory controller",
+		ahc_raid_setup
+	}
+};
+
+const u_int ahc_num_pci_devs = NUM_ELEMENTS(ahc_pci_ident_table);
+		
+#define AHC_394X_SLOT_CHANNEL_A	4
+#define AHC_394X_SLOT_CHANNEL_B	5
+
+#define AHC_398X_SLOT_CHANNEL_A	4
+#define AHC_398X_SLOT_CHANNEL_B	8
+#define AHC_398X_SLOT_CHANNEL_C	12
+
+#define AHC_494X_SLOT_CHANNEL_A	4
+#define AHC_494X_SLOT_CHANNEL_B	5
+#define AHC_494X_SLOT_CHANNEL_C	6
+#define AHC_494X_SLOT_CHANNEL_D	7
+
+#define	DEVCONFIG		0x40
+#define		PCIERRGENDIS	0x80000000ul
+#define		SCBSIZE32	0x00010000ul	/* aic789X only */
+#define		REXTVALID	0x00001000ul	/* ultra cards only */
+#define		MPORTMODE	0x00000400ul	/* aic7870+ only */
+#define		RAMPSM		0x00000200ul	/* aic7870+ only */
+#define		VOLSENSE	0x00000100ul
+#define		PCI64BIT	0x00000080ul	/* 64Bit PCI bus (Ultra2 Only)*/
+#define		SCBRAMSEL	0x00000080ul
+#define		MRDCEN		0x00000040ul
+#define		EXTSCBTIME	0x00000020ul	/* aic7870 only */
+#define		EXTSCBPEN	0x00000010ul	/* aic7870 only */
+#define		BERREN		0x00000008ul
+#define		DACEN		0x00000004ul
+#define		STPWLEVEL	0x00000002ul
+#define		DIFACTNEGEN	0x00000001ul	/* aic7870 only */
+
+#define	CSIZE_LATTIME		0x0c
+#define		CACHESIZE	0x0000003ful	/* only 5 bits */
+#define		LATTIME		0x0000ff00ul
+
+/* PCI STATUS definitions */
+#define	DPE	0x80
+#define SSE	0x40
+#define	RMA	0x20
+#define	RTA	0x10
+#define STA	0x08
+#define DPR	0x01
+
+static int ahc_9005_subdevinfo_valid(uint16_t vendor, uint16_t device,
+				     uint16_t subvendor, uint16_t subdevice);
+static int ahc_ext_scbram_present(struct ahc_softc *ahc);
+static void ahc_scbram_config(struct ahc_softc *ahc, int enable,
+				  int pcheck, int fast, int large);
+static void ahc_probe_ext_scbram(struct ahc_softc *ahc);
+static void check_extport(struct ahc_softc *ahc, u_int *sxfrctl1);
+static void ahc_parse_pci_eeprom(struct ahc_softc *ahc,
+				 struct seeprom_config *sc);
+static void configure_termination(struct ahc_softc *ahc,
+				  struct seeprom_descriptor *sd,
+				  u_int adapter_control,
+	 			  u_int *sxfrctl1);
+
+static void ahc_new_term_detect(struct ahc_softc *ahc,
+				int *enableSEC_low,
+				int *enableSEC_high,
+				int *enablePRI_low,
+				int *enablePRI_high,
+				int *eeprom_present);
+static void aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+				 int *internal68_present,
+				 int *externalcable_present,
+				 int *eeprom_present);
+static void aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+				 int *externalcable_present,
+				 int *eeprom_present);
+static void    write_brdctl(struct ahc_softc *ahc, uint8_t value);
+static uint8_t read_brdctl(struct ahc_softc *ahc);
+static void ahc_pci_intr(struct ahc_softc *ahc);
+static int  ahc_pci_chip_init(struct ahc_softc *ahc);
+static int  ahc_pci_suspend(struct ahc_softc *ahc);
+static int  ahc_pci_resume(struct ahc_softc *ahc);
+
+static int
+ahc_9005_subdevinfo_valid(uint16_t device, uint16_t vendor,
+			  uint16_t subdevice, uint16_t subvendor)
+{
+	int result;
+
+	/* Default to invalid. */
+	result = 0;
+	if (vendor == 0x9005
+	 && subvendor == 0x9005
+         && subdevice != device
+         && SUBID_9005_TYPE_KNOWN(subdevice) != 0) {
+
+		switch (SUBID_9005_TYPE(subdevice)) {
+		case SUBID_9005_TYPE_MB:
+			break;
+		case SUBID_9005_TYPE_CARD:
+		case SUBID_9005_TYPE_LCCARD:
+			/*
+			 * Currently only trust Adaptec cards to
+			 * get the sub device info correct.
+			 */
+			if (DEVID_9005_TYPE(device) == DEVID_9005_TYPE_HBA)
+				result = 1;
+			break;
+		case SUBID_9005_TYPE_RAID:
+			break;
+		default:
+			break;
+		}
+	}
+	return (result);
+}
+
+struct ahc_pci_identity *
+ahc_find_pci_device(ahc_dev_softc_t pci)
+{
+	uint64_t  full_id;
+	uint16_t  device;
+	uint16_t  vendor;
+	uint16_t  subdevice;
+	uint16_t  subvendor;
+	struct	  ahc_pci_identity *entry;
+	u_int	  i;
+
+	vendor = ahc_pci_read_config(pci, PCIR_DEVVENDOR, /*bytes*/2);
+	device = ahc_pci_read_config(pci, PCIR_DEVICE, /*bytes*/2);
+	subvendor = ahc_pci_read_config(pci, PCIR_SUBVEND_0, /*bytes*/2);
+	subdevice = ahc_pci_read_config(pci, PCIR_SUBDEV_0, /*bytes*/2);
+	full_id = ahc_compose_id(device, vendor, subdevice, subvendor);
+
+	/*
+	 * If the second function is not hooked up, ignore it.
+	 * Unfortunately, not all MB vendors implement the
+	 * subdevice ID as per the Adaptec spec, so do our best
+	 * to sanity check it prior to accepting the subdevice
+	 * ID as valid.
+	 */
+	if (ahc_get_pci_function(pci) > 0
+	 && ahc_9005_subdevinfo_valid(vendor, device, subvendor, subdevice)
+	 && SUBID_9005_MFUNCENB(subdevice) == 0)
+		return (NULL);
+
+	for (i = 0; i < ahc_num_pci_devs; i++) {
+		entry = &ahc_pci_ident_table[i];
+		if (entry->full_id == (full_id & entry->id_mask)) {
+			/* Honor exclusion entries. */
+			if (entry->name == NULL)
+				return (NULL);
+			return (entry);
+		}
+	}
+	return (NULL);
+}
+
+int
+ahc_pci_config(struct ahc_softc *ahc, struct ahc_pci_identity *entry)
+{
+	u_long	 l;
+	u_int	 command;
+	u_int	 our_id;
+	u_int	 sxfrctl1;
+	u_int	 scsiseq;
+	u_int	 dscommand0;
+	uint32_t devconfig;
+	int	 error;
+	uint8_t	 sblkctl;
+
+	our_id = 0;
+	error = entry->setup(ahc);
+	if (error != 0)
+		return (error);
+	ahc->chip |= AHC_PCI;
+	ahc->description = entry->name;
+
+	pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0);
+
+	error = ahc_pci_map_registers(ahc);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Before we continue probing the card, ensure that
+	 * its interrupts are *disabled*.  We don't want
+	 * a misstep to hang the machine in an interrupt
+	 * storm.
+	 */
+	ahc_intr_enable(ahc, FALSE);
+
+	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+
+	/*
+	 * If we need to support high memory, enable dual
+	 * address cycles.  This bit must be set to enable
+	 * high address bit generation even if we are on a
+	 * 64bit bus (PCI64BIT set in devconfig).
+	 */
+	if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) {
+
+		if (bootverbose)
+			printf("%s: Enabling 39Bit Addressing\n",
+			       ahc_name(ahc));
+		devconfig |= DACEN;
+	}
+	
+	/* Ensure that pci error generation, a test feature, is disabled. */
+	devconfig |= PCIERRGENDIS;
+
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
+
+	/* Ensure busmastering is enabled */
+	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
+	command |= PCIM_CMD_BUSMASTEREN;
+
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2);
+
+	/* On all PCI adapters, we allow SCB paging */
+	ahc->flags |= AHC_PAGESCBS;
+
+	error = ahc_softc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Disable PCI parity error checking.  Users typically
+	 * do this to work around broken PCI chipsets that get
+	 * the parity timing wrong and thus generate lots of spurious
+	 * errors.  The chip only allows us to disable *all* parity
+	 * error reporting when doing this, so CIO bus, scb ram, and
+	 * scratch ram parity errors will be ignored too.
+	 */
+	if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
+		ahc->seqctl |= FAILDIS;
+
+	ahc->bus_intr = ahc_pci_intr;
+	ahc->bus_chip_init = ahc_pci_chip_init;
+	ahc->bus_suspend = ahc_pci_suspend;
+	ahc->bus_resume = ahc_pci_resume;
+
+	/* Remeber how the card was setup in case there is no SEEPROM */
+	if ((ahc_inb(ahc, HCNTRL) & POWRDN) == 0) {
+		ahc_pause(ahc);
+		if ((ahc->features & AHC_ULTRA2) != 0)
+			our_id = ahc_inb(ahc, SCSIID_ULTRA2) & OID;
+		else
+			our_id = ahc_inb(ahc, SCSIID) & OID;
+		sxfrctl1 = ahc_inb(ahc, SXFRCTL1) & STPWEN;
+		scsiseq = ahc_inb(ahc, SCSISEQ);
+	} else {
+		sxfrctl1 = STPWEN;
+		our_id = 7;
+		scsiseq = 0;
+	}
+
+	error = ahc_reset(ahc, /*reinit*/FALSE);
+	if (error != 0)
+		return (ENXIO);
+
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		/* Perform ALT-Mode Setup */
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc_outb(ahc, OPTIONMODE,
+			 OPTIONMODE_DEFAULTS|AUTOACKEN|BUSFREEREV|EXPPHASEDIS);
+		ahc_outb(ahc, SFUNCT, sfunct);
+
+		/* Normal mode setup */
+		ahc_outb(ahc, CRCCONTROL1, CRCVALCHKEN|CRCENDCHKEN|CRCREQCHKEN
+					  |TARGCRCENDEN);
+	}
+
+	dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+	dscommand0 |= MPARCKEN|CACHETHEN;
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+
+		/*
+		 * DPARCKEN doesn't work correctly on
+		 * some MBs so don't use it.
+		 */
+		dscommand0 &= ~DPARCKEN;
+	}
+
+	/*
+	 * Handle chips that must have cache line
+	 * streaming (dis/en)abled.
+	 */
+	if ((ahc->bugs & AHC_CACHETHEN_DIS_BUG) != 0)
+		dscommand0 |= CACHETHEN;
+
+	if ((ahc->bugs & AHC_CACHETHEN_BUG) != 0)
+		dscommand0 &= ~CACHETHEN;
+
+	ahc_outb(ahc, DSCOMMAND0, dscommand0);
+
+	ahc->pci_cachesize =
+	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME,
+				/*bytes*/1) & CACHESIZE;
+	ahc->pci_cachesize *= 4;
+
+	if ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0
+	 && ahc->pci_cachesize == 4) {
+
+		ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME,
+				     0, /*bytes*/1);
+		ahc->pci_cachesize = 0;
+	}
+
+	/*
+	 * We cannot perform ULTRA speeds without the presense
+	 * of the external precision resistor.
+	 */
+	if ((ahc->features & AHC_ULTRA) != 0) {
+		uint32_t devconfig;
+
+		devconfig = ahc_pci_read_config(ahc->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		if ((devconfig & REXTVALID) == 0)
+			ahc->features &= ~AHC_ULTRA;
+	}
+
+	/* See if we have a SEEPROM and perform auto-term */
+	check_extport(ahc, &sxfrctl1);
+
+	/*
+	 * Take the LED out of diagnostic mode
+	 */
+	sblkctl = ahc_inb(ahc, SBLKCTL);
+	ahc_outb(ahc, SBLKCTL, (sblkctl & ~(DIAGLEDEN|DIAGLEDON)));
+
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		ahc_outb(ahc, DFF_THRSH, RD_DFTHRSH_MAX|WR_DFTHRSH_MAX);
+	} else {
+		ahc_outb(ahc, DSPCISTATUS, DFTHRSH_100);
+	}
+
+	if (ahc->flags & AHC_USEDEFAULTS) {
+		/*
+		 * PCI Adapter default setup
+		 * Should only be used if the adapter does not have
+		 * a SEEPROM.
+		 */
+		/* See if someone else set us up already */
+		if ((ahc->flags & AHC_NO_BIOS_INIT) == 0
+		 && scsiseq != 0) {
+			printf("%s: Using left over BIOS settings\n",
+				ahc_name(ahc));
+			ahc->flags &= ~AHC_USEDEFAULTS;
+			ahc->flags |= AHC_BIOS_ENABLED;
+		} else {
+			/*
+			 * Assume only one connector and always turn
+			 * on termination.
+			 */
+ 			our_id = 0x07;
+			sxfrctl1 = STPWEN;
+		}
+		ahc_outb(ahc, SCSICONF, our_id|ENSPCHK|RESET_SCSI);
+
+		ahc->our_id = our_id;
+	}
+
+	/*
+	 * Take a look to see if we have external SRAM.
+	 * We currently do not attempt to use SRAM that is
+	 * shared among multiple controllers.
+	 */
+	ahc_probe_ext_scbram(ahc);
+
+	/*
+	 * Record our termination setting for the
+	 * generic initialization routine.
+	 */
+	if ((sxfrctl1 & STPWEN) != 0)
+		ahc->flags |= AHC_TERM_ENB_A;
+
+	/*
+	 * Save chip register configuration data for chip resets
+	 * that occur during runtime and resume events.
+	 */
+	ahc->bus_softc.pci_softc.devconfig =
+	    ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+	ahc->bus_softc.pci_softc.command =
+	    ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
+	ahc->bus_softc.pci_softc.csize_lattime =
+	    ahc_pci_read_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1);
+	ahc->bus_softc.pci_softc.dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+	ahc->bus_softc.pci_softc.dspcistatus = ahc_inb(ahc, DSPCISTATUS);
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc->bus_softc.pci_softc.optionmode = ahc_inb(ahc, OPTIONMODE);
+		ahc->bus_softc.pci_softc.targcrccnt = ahc_inw(ahc, TARGCRCCNT);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc->bus_softc.pci_softc.crccontrol1 =
+		    ahc_inb(ahc, CRCCONTROL1);
+	}
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc->bus_softc.pci_softc.scbbaddr = ahc_inb(ahc, SCBBADDR);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc->bus_softc.pci_softc.dff_thrsh = ahc_inb(ahc, DFF_THRSH);
+
+	/* Core initialization */
+	error = ahc_init(ahc);
+	if (error != 0)
+		return (error);
+
+	/*
+	 * Allow interrupts now that we are completely setup.
+	 */
+	error = ahc_pci_map_int(ahc);
+	if (error != 0)
+		return (error);
+
+	ahc_list_lock(&l);
+	/*
+	 * Link this softc in with all other ahc instances.
+	 */
+	ahc_softc_insert(ahc);
+	ahc_list_unlock(&l);
+	return (0);
+}
+
+/*
+ * Test for the presense of external sram in an
+ * "unshared" configuration.
+ */
+static int
+ahc_ext_scbram_present(struct ahc_softc *ahc)
+{
+	u_int chip;
+	int ramps;
+	int single_user;
+	uint32_t devconfig;
+
+	chip = ahc->chip & AHC_CHIPID_MASK;
+	devconfig = ahc_pci_read_config(ahc->dev_softc,
+					DEVCONFIG, /*bytes*/4);
+	single_user = (devconfig & MPORTMODE) != 0;
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ramps = (ahc_inb(ahc, DSCOMMAND0) & RAMPS) != 0;
+	else if (chip == AHC_AIC7895 || chip == AHC_AIC7895C)
+		/*
+		 * External SCBRAM arbitration is flakey
+		 * on these chips.  Unfortunately this means
+		 * we don't use the extra SCB ram space on the
+		 * 3940AUW.
+		 */
+		ramps = 0;
+	else if (chip >= AHC_AIC7870)
+		ramps = (devconfig & RAMPSM) != 0;
+	else
+		ramps = 0;
+
+	if (ramps && single_user)
+		return (1);
+	return (0);
+}
+
+/*
+ * Enable external scbram.
+ */
+static void
+ahc_scbram_config(struct ahc_softc *ahc, int enable, int pcheck,
+		  int fast, int large)
+{
+	uint32_t devconfig;
+
+	if (ahc->features & AHC_MULTI_FUNC) {
+		/*
+		 * Set the SCB Base addr (highest address bit)
+		 * depending on which channel we are.
+		 */
+		ahc_outb(ahc, SCBBADDR, ahc_get_pci_function(ahc->dev_softc));
+	}
+
+	ahc->flags &= ~AHC_LSCBS_ENABLED;
+	if (large)
+		ahc->flags |= AHC_LSCBS_ENABLED;
+	devconfig = ahc_pci_read_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4);
+	if ((ahc->features & AHC_ULTRA2) != 0) {
+		u_int dscommand0;
+
+		dscommand0 = ahc_inb(ahc, DSCOMMAND0);
+		if (enable)
+			dscommand0 &= ~INTSCBRAMSEL;
+		else
+			dscommand0 |= INTSCBRAMSEL;
+		if (large)
+			dscommand0 &= ~USCBSIZE32;
+		else
+			dscommand0 |= USCBSIZE32;
+		ahc_outb(ahc, DSCOMMAND0, dscommand0);
+	} else {
+		if (fast)
+			devconfig &= ~EXTSCBTIME;
+		else
+			devconfig |= EXTSCBTIME;
+		if (enable)
+			devconfig &= ~SCBRAMSEL;
+		else
+			devconfig |= SCBRAMSEL;
+		if (large)
+			devconfig &= ~SCBSIZE32;
+		else
+			devconfig |= SCBSIZE32;
+	}
+	if (pcheck)
+		devconfig |= EXTSCBPEN;
+	else
+		devconfig &= ~EXTSCBPEN;
+
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4);
+}
+
+/*
+ * Take a look to see if we have external SRAM.
+ * We currently do not attempt to use SRAM that is
+ * shared among multiple controllers.
+ */
+static void
+ahc_probe_ext_scbram(struct ahc_softc *ahc)
+{
+	int num_scbs;
+	int test_num_scbs;
+	int enable;
+	int pcheck;
+	int fast;
+	int large;
+
+	enable = FALSE;
+	pcheck = FALSE;
+	fast = FALSE;
+	large = FALSE;
+	num_scbs = 0;
+	
+	if (ahc_ext_scbram_present(ahc) == 0)
+		goto done;
+
+	/*
+	 * Probe for the best parameters to use.
+	 */
+	ahc_scbram_config(ahc, /*enable*/TRUE, pcheck, fast, large);
+	num_scbs = ahc_probe_scbs(ahc);
+	if (num_scbs == 0) {
+		/* The SRAM wasn't really present. */
+		goto done;
+	}
+	enable = TRUE;
+
+	/*
+	 * Clear any outstanding parity error
+	 * and ensure that parity error reporting
+	 * is enabled.
+	 */
+	ahc_outb(ahc, SEQCTL, 0);
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+
+	/* Now see if we can do parity */
+	ahc_scbram_config(ahc, enable, /*pcheck*/TRUE, fast, large);
+	num_scbs = ahc_probe_scbs(ahc);
+	if ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
+	 || (ahc_inb(ahc, ERROR) & MPARERR) == 0)
+		pcheck = TRUE;
+
+	/* Clear any resulting parity error */
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+
+	/* Now see if we can do fast timing */
+	ahc_scbram_config(ahc, enable, pcheck, /*fast*/TRUE, large);
+	test_num_scbs = ahc_probe_scbs(ahc);
+	if (test_num_scbs == num_scbs
+	 && ((ahc_inb(ahc, INTSTAT) & BRKADRINT) == 0
+	  || (ahc_inb(ahc, ERROR) & MPARERR) == 0))
+		fast = TRUE;
+
+	/*
+	 * See if we can use large SCBs and still maintain
+	 * the same overall count of SCBs.
+	 */
+	if ((ahc->features & AHC_LARGE_SCBS) != 0) {
+		ahc_scbram_config(ahc, enable, pcheck, fast, /*large*/TRUE);
+		test_num_scbs = ahc_probe_scbs(ahc);
+		if (test_num_scbs >= num_scbs) {
+			large = TRUE;
+			num_scbs = test_num_scbs;
+	 		if (num_scbs >= 64) {
+				/*
+				 * We have enough space to move the
+				 * "busy targets table" into SCB space
+				 * and make it qualify all the way to the
+				 * lun level.
+				 */
+				ahc->flags |= AHC_SCB_BTT;
+			}
+		}
+	}
+done:
+	/*
+	 * Disable parity error reporting until we
+	 * can load instruction ram.
+	 */
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);
+	/* Clear any latched parity error */
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+	if (bootverbose && enable) {
+		printf("%s: External SRAM, %s access%s, %dbytes/SCB\n",
+		       ahc_name(ahc), fast ? "fast" : "slow", 
+		       pcheck ? ", parity checking enabled" : "",
+		       large ? 64 : 32);
+	}
+	ahc_scbram_config(ahc, enable, pcheck, fast, large);
+}
+
+/*
+ * Perform some simple tests that should catch situations where
+ * our registers are invalidly mapped.
+ */
+int
+ahc_pci_test_register_access(struct ahc_softc *ahc)
+{
+	int	 error;
+	u_int	 status1;
+	uint32_t cmd;
+	uint8_t	 hcntrl;
+
+	error = EIO;
+
+	/*
+	 * Enable PCI error interrupt status, but suppress NMIs
+	 * generated by SERR raised due to target aborts.
+	 */
+	cmd = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND,
+			     cmd & ~PCIM_CMD_SERRESPEN, /*bytes*/2);
+
+	/*
+	 * First a simple test to see if any
+	 * registers can be read.  Reading
+	 * HCNTRL has no side effects and has
+	 * at least one bit that is guaranteed to
+	 * be zero so it is a good register to
+	 * use for this test.
+	 */
+	hcntrl = ahc_inb(ahc, HCNTRL);
+	if (hcntrl == 0xFF)
+		goto fail;
+
+	/*
+	 * Next create a situation where write combining
+	 * or read prefetching could be initiated by the
+	 * CPU or host bridge.  Our device does not support
+	 * either, so look for data corruption and/or flagged
+	 * PCI errors.  First pause without causing another
+	 * chip reset.
+	 */
+	hcntrl &= ~CHIPRST;
+	ahc_outb(ahc, HCNTRL, hcntrl|PAUSE);
+	while (ahc_is_paused(ahc) == 0)
+		;
+
+	/* Clear any PCI errors that occurred before our driver attached. */
+	status1 = ahc_pci_read_config(ahc->dev_softc,
+				      PCIR_STATUS + 1, /*bytes*/1);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
+			     status1, /*bytes*/1);
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+
+	ahc_outb(ahc, SEQCTL, PERRORDIS);
+	ahc_outb(ahc, SCBPTR, 0);
+	ahc_outl(ahc, SCB_BASE, 0x5aa555aa);
+	if (ahc_inl(ahc, SCB_BASE) != 0x5aa555aa)
+		goto fail;
+
+	status1 = ahc_pci_read_config(ahc->dev_softc,
+				      PCIR_STATUS + 1, /*bytes*/1);
+	if ((status1 & STA) != 0)
+		goto fail;
+
+	error = 0;
+
+fail:
+	/* Silently clear any latched errors. */
+	status1 = ahc_pci_read_config(ahc->dev_softc,
+				      PCIR_STATUS + 1, /*bytes*/1);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
+			     status1, /*bytes*/1);
+	ahc_outb(ahc, CLRINT, CLRPARERR);
+	ahc_outb(ahc, SEQCTL, PERRORDIS|FAILDIS);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, cmd, /*bytes*/2);
+	return (error);
+}
+
+/*
+ * Check the external port logic for a serial eeprom
+ * and termination/cable detection contrls.
+ */
+static void
+check_extport(struct ahc_softc *ahc, u_int *sxfrctl1)
+{
+	struct	seeprom_descriptor sd;
+	struct	seeprom_config *sc;
+	int	have_seeprom;
+	int	have_autoterm;
+
+	sd.sd_ahc = ahc;
+	sd.sd_control_offset = SEECTL;		
+	sd.sd_status_offset = SEECTL;		
+	sd.sd_dataout_offset = SEECTL;		
+	sc = ahc->seep_config;
+
+	/*
+	 * For some multi-channel devices, the c46 is simply too
+	 * small to work.  For the other controller types, we can
+	 * get our information from either SEEPROM type.  Set the
+	 * type to start our probe with accordingly.
+	 */
+	if (ahc->flags & AHC_LARGE_SEEPROM)
+		sd.sd_chip = C56_66;
+	else
+		sd.sd_chip = C46;
+
+	sd.sd_MS = SEEMS;
+	sd.sd_RDY = SEERDY;
+	sd.sd_CS = SEECS;
+	sd.sd_CK = SEECK;
+	sd.sd_DO = SEEDO;
+	sd.sd_DI = SEEDI;
+
+	have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+	if (have_seeprom) {
+
+		if (bootverbose) 
+			printf("%s: Reading SEEPROM...", ahc_name(ahc));
+
+		for (;;) {
+			u_int start_addr;
+
+			start_addr = 32 * (ahc->channel - 'A');
+
+			have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
+							start_addr,
+							sizeof(*sc)/2);
+
+			if (have_seeprom)
+				have_seeprom = ahc_verify_cksum(sc);
+
+			if (have_seeprom != 0 || sd.sd_chip == C56_66) {
+				if (bootverbose) {
+					if (have_seeprom == 0)
+						printf ("checksum error\n");
+					else
+						printf ("done.\n");
+				}
+				break;
+			}
+			sd.sd_chip = C56_66;
+		}
+		ahc_release_seeprom(&sd);
+	}
+
+	if (!have_seeprom) {
+		/*
+		 * Pull scratch ram settings and treat them as
+		 * if they are the contents of an seeprom if
+		 * the 'ADPT' signature is found in SCB2.
+		 * We manually compose the data as 16bit values
+		 * to avoid endian issues.
+		 */
+		ahc_outb(ahc, SCBPTR, 2);
+		if (ahc_inb(ahc, SCB_BASE) == 'A'
+		 && ahc_inb(ahc, SCB_BASE + 1) == 'D'
+		 && ahc_inb(ahc, SCB_BASE + 2) == 'P'
+		 && ahc_inb(ahc, SCB_BASE + 3) == 'T') {
+			uint16_t *sc_data;
+			int	  i;
+
+			sc_data = (uint16_t *)sc;
+			for (i = 0; i < 32; i++, sc_data++) {
+				int	j;
+
+				j = i * 2;
+				*sc_data = ahc_inb(ahc, SRAM_BASE + j)
+					 | ahc_inb(ahc, SRAM_BASE + j + 1) << 8;
+			}
+			have_seeprom = ahc_verify_cksum(sc);
+			if (have_seeprom)
+				ahc->flags |= AHC_SCB_CONFIG_USED;
+		}
+		/*
+		 * Clear any SCB parity errors in case this data and
+		 * its associated parity was not initialized by the BIOS
+		 */
+		ahc_outb(ahc, CLRINT, CLRPARERR);
+		ahc_outb(ahc, CLRINT, CLRBRKADRINT);
+	}
+
+	if (!have_seeprom) {
+		if (bootverbose)
+			printf("%s: No SEEPROM available.\n", ahc_name(ahc));
+		ahc->flags |= AHC_USEDEFAULTS;
+		free(ahc->seep_config, M_DEVBUF);
+		ahc->seep_config = NULL;
+		sc = NULL;
+	} else {
+		ahc_parse_pci_eeprom(ahc, sc);
+	}
+
+	/*
+	 * Cards that have the external logic necessary to talk to
+	 * a SEEPROM, are almost certain to have the remaining logic
+	 * necessary for auto-termination control.  This assumption
+	 * hasn't failed yet...
+	 */
+	have_autoterm = have_seeprom;
+
+	/*
+	 * Some low-cost chips have SEEPROM and auto-term control built
+	 * in, instead of using a GAL.  They can tell us directly
+	 * if the termination logic is enabled.
+	 */
+	if ((ahc->features & AHC_SPIOCAP) != 0) {
+		if ((ahc_inb(ahc, SPIOCAP) & SSPIOCPS) == 0)
+			have_autoterm = FALSE;
+	}
+
+	if (have_autoterm) {
+		ahc->flags |= AHC_HAS_TERM_LOGIC;
+		ahc_acquire_seeprom(ahc, &sd);
+		configure_termination(ahc, &sd, sc->adapter_control, sxfrctl1);
+		ahc_release_seeprom(&sd);
+	} else if (have_seeprom) {
+		*sxfrctl1 &= ~STPWEN;
+		if ((sc->adapter_control & CFSTERM) != 0)
+			*sxfrctl1 |= STPWEN;
+		if (bootverbose)
+			printf("%s: Low byte termination %sabled\n",
+			       ahc_name(ahc),
+			       (*sxfrctl1 & STPWEN) ? "en" : "dis");
+	}
+}
+
+static void
+ahc_parse_pci_eeprom(struct ahc_softc *ahc, struct seeprom_config *sc)
+{
+	/*
+	 * Put the data we've collected down into SRAM
+	 * where ahc_init will find it.
+	 */
+	int	 i;
+	int	 max_targ = sc->max_targets & CFMAXTARG;
+	u_int	 scsi_conf;
+	uint16_t discenable;
+	uint16_t ultraenb;
+
+	discenable = 0;
+	ultraenb = 0;
+	if ((sc->adapter_control & CFULTRAEN) != 0) {
+		/*
+		 * Determine if this adapter has a "newstyle"
+		 * SEEPROM format.
+		 */
+		for (i = 0; i < max_targ; i++) {
+			if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0) {
+				ahc->flags |= AHC_NEWEEPROM_FMT;
+				break;
+			}
+		}
+	}
+
+	for (i = 0; i < max_targ; i++) {
+		u_int     scsirate;
+		uint16_t target_mask;
+
+		target_mask = 0x01 << i;
+		if (sc->device_flags[i] & CFDISC)
+			discenable |= target_mask;
+		if ((ahc->flags & AHC_NEWEEPROM_FMT) != 0) {
+			if ((sc->device_flags[i] & CFSYNCHISULTRA) != 0)
+				ultraenb |= target_mask;
+		} else if ((sc->adapter_control & CFULTRAEN) != 0) {
+			ultraenb |= target_mask;
+		}
+		if ((sc->device_flags[i] & CFXFER) == 0x04
+		 && (ultraenb & target_mask) != 0) {
+			/* Treat 10MHz as a non-ultra speed */
+			sc->device_flags[i] &= ~CFXFER;
+		 	ultraenb &= ~target_mask;
+		}
+		if ((ahc->features & AHC_ULTRA2) != 0) {
+			u_int offset;
+
+			if (sc->device_flags[i] & CFSYNCH)
+				offset = MAX_OFFSET_ULTRA2;
+			else 
+				offset = 0;
+			ahc_outb(ahc, TARG_OFFSET + i, offset);
+
+			/*
+			 * The ultra enable bits contain the
+			 * high bit of the ultra2 sync rate
+			 * field.
+			 */
+			scsirate = (sc->device_flags[i] & CFXFER)
+				 | ((ultraenb & target_mask) ? 0x8 : 0x0);
+			if (sc->device_flags[i] & CFWIDEB)
+				scsirate |= WIDEXFER;
+		} else {
+			scsirate = (sc->device_flags[i] & CFXFER) << 4;
+			if (sc->device_flags[i] & CFSYNCH)
+				scsirate |= SOFS;
+			if (sc->device_flags[i] & CFWIDEB)
+				scsirate |= WIDEXFER;
+		}
+		ahc_outb(ahc, TARG_SCSIRATE + i, scsirate);
+	}
+	ahc->our_id = sc->brtime_id & CFSCSIID;
+
+	scsi_conf = (ahc->our_id & 0x7);
+	if (sc->adapter_control & CFSPARITY)
+		scsi_conf |= ENSPCHK;
+	if (sc->adapter_control & CFRESETB)
+		scsi_conf |= RESET_SCSI;
+
+	ahc->flags |= (sc->adapter_control & CFBOOTCHAN) >> CFBOOTCHANSHIFT;
+
+	if (sc->bios_control & CFEXTEND)
+		ahc->flags |= AHC_EXTENDED_TRANS_A;
+
+	if (sc->bios_control & CFBIOSEN)
+		ahc->flags |= AHC_BIOS_ENABLED;
+	if (ahc->features & AHC_ULTRA
+	 && (ahc->flags & AHC_NEWEEPROM_FMT) == 0) {
+		/* Should we enable Ultra mode? */
+		if (!(sc->adapter_control & CFULTRAEN))
+			/* Treat us as a non-ultra card */
+			ultraenb = 0;
+	}
+
+	if (sc->signature == CFSIGNATURE
+	 || sc->signature == CFSIGNATURE2) {
+		uint32_t devconfig;
+
+		/* Honor the STPWLEVEL settings */
+		devconfig = ahc_pci_read_config(ahc->dev_softc,
+						DEVCONFIG, /*bytes*/4);
+		devconfig &= ~STPWLEVEL;
+		if ((sc->bios_control & CFSTPWLEVEL) != 0)
+			devconfig |= STPWLEVEL;
+		ahc_pci_write_config(ahc->dev_softc, DEVCONFIG,
+				     devconfig, /*bytes*/4);
+	}
+	/* Set SCSICONF info */
+	ahc_outb(ahc, SCSICONF, scsi_conf);
+	ahc_outb(ahc, DISC_DSB, ~(discenable & 0xff));
+	ahc_outb(ahc, DISC_DSB + 1, ~((discenable >> 8) & 0xff));
+	ahc_outb(ahc, ULTRA_ENB, ultraenb & 0xff);
+	ahc_outb(ahc, ULTRA_ENB + 1, (ultraenb >> 8) & 0xff);
+}
+
+static void
+configure_termination(struct ahc_softc *ahc,
+		      struct seeprom_descriptor *sd,
+		      u_int adapter_control,
+		      u_int *sxfrctl1)
+{
+	uint8_t brddat;
+	
+	brddat = 0;
+
+	/*
+	 * Update the settings in sxfrctl1 to match the
+	 * termination settings 
+	 */
+	*sxfrctl1 = 0;
+	
+	/*
+	 * SEECS must be on for the GALS to latch
+	 * the data properly.  Be sure to leave MS
+	 * on or we will release the seeprom.
+	 */
+	SEEPROM_OUTB(sd, sd->sd_MS | sd->sd_CS);
+	if ((adapter_control & CFAUTOTERM) != 0
+	 || (ahc->features & AHC_NEW_TERMCTL) != 0) {
+		int internal50_present;
+		int internal68_present;
+		int externalcable_present;
+		int eeprom_present;
+		int enableSEC_low;
+		int enableSEC_high;
+		int enablePRI_low;
+		int enablePRI_high;
+		int sum;
+
+		enableSEC_low = 0;
+		enableSEC_high = 0;
+		enablePRI_low = 0;
+		enablePRI_high = 0;
+		if ((ahc->features & AHC_NEW_TERMCTL) != 0) {
+			ahc_new_term_detect(ahc, &enableSEC_low,
+					    &enableSEC_high,
+					    &enablePRI_low,
+					    &enablePRI_high,
+					    &eeprom_present);
+			if ((adapter_control & CFSEAUTOTERM) == 0) {
+				if (bootverbose)
+					printf("%s: Manual SE Termination\n",
+					       ahc_name(ahc));
+				enableSEC_low = (adapter_control & CFSELOWTERM);
+				enableSEC_high =
+				    (adapter_control & CFSEHIGHTERM);
+			}
+			if ((adapter_control & CFAUTOTERM) == 0) {
+				if (bootverbose)
+					printf("%s: Manual LVD Termination\n",
+					       ahc_name(ahc));
+				enablePRI_low = (adapter_control & CFSTERM);
+				enablePRI_high = (adapter_control & CFWSTERM);
+			}
+			/* Make the table calculations below happy */
+			internal50_present = 0;
+			internal68_present = 1;
+			externalcable_present = 1;
+		} else if ((ahc->features & AHC_SPIOCAP) != 0) {
+			aic785X_cable_detect(ahc, &internal50_present,
+					     &externalcable_present,
+					     &eeprom_present);
+			/* Can never support a wide connector. */
+			internal68_present = 0;
+		} else {
+			aic787X_cable_detect(ahc, &internal50_present,
+					     &internal68_present,
+					     &externalcable_present,
+					     &eeprom_present);
+		}
+
+		if ((ahc->features & AHC_WIDE) == 0)
+			internal68_present = 0;
+
+		if (bootverbose
+		 && (ahc->features & AHC_ULTRA2) == 0) {
+			printf("%s: internal 50 cable %s present",
+			       ahc_name(ahc),
+			       internal50_present ? "is":"not");
+
+			if ((ahc->features & AHC_WIDE) != 0)
+				printf(", internal 68 cable %s present",
+				       internal68_present ? "is":"not");
+			printf("\n%s: external cable %s present\n",
+			       ahc_name(ahc),
+			       externalcable_present ? "is":"not");
+		}
+		if (bootverbose)
+			printf("%s: BIOS eeprom %s present\n",
+			       ahc_name(ahc), eeprom_present ? "is" : "not");
+
+		if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0) {
+			/*
+			 * The 50 pin connector is a separate bus,
+			 * so force it to always be terminated.
+			 * In the future, perform current sensing
+			 * to determine if we are in the middle of
+			 * a properly terminated bus.
+			 */
+			internal50_present = 0;
+		}
+
+		/*
+		 * Now set the termination based on what
+		 * we found.
+		 * Flash Enable = BRDDAT7
+		 * Secondary High Term Enable = BRDDAT6
+		 * Secondary Low Term Enable = BRDDAT5 (7890)
+		 * Primary High Term Enable = BRDDAT4 (7890)
+		 */
+		if ((ahc->features & AHC_ULTRA2) == 0
+		 && (internal50_present != 0)
+		 && (internal68_present != 0)
+		 && (externalcable_present != 0)) {
+			printf("%s: Illegal cable configuration!!. "
+			       "Only two connectors on the "
+			       "adapter may be used at a "
+			       "time!\n", ahc_name(ahc));
+
+			/*
+			 * Pretend there are no cables in the hope
+			 * that having all of the termination on
+			 * gives us a more stable bus.
+			 */
+		 	internal50_present = 0;
+			internal68_present = 0;
+			externalcable_present = 0;
+		}
+
+		if ((ahc->features & AHC_WIDE) != 0
+		 && ((externalcable_present == 0)
+		  || (internal68_present == 0)
+		  || (enableSEC_high != 0))) {
+			brddat |= BRDDAT6;
+			if (bootverbose) {
+				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+					printf("%s: 68 pin termination "
+					       "Enabled\n", ahc_name(ahc));
+				else
+					printf("%s: %sHigh byte termination "
+					       "Enabled\n", ahc_name(ahc),
+					       enableSEC_high ? "Secondary "
+							      : "");
+			}
+		}
+
+		sum = internal50_present + internal68_present
+		    + externalcable_present;
+		if (sum < 2 || (enableSEC_low != 0)) {
+			if ((ahc->features & AHC_ULTRA2) != 0)
+				brddat |= BRDDAT5;
+			else
+				*sxfrctl1 |= STPWEN;
+			if (bootverbose) {
+				if ((ahc->flags & AHC_INT50_SPEEDFLEX) != 0)
+					printf("%s: 50 pin termination "
+					       "Enabled\n", ahc_name(ahc));
+				else
+					printf("%s: %sLow byte termination "
+					       "Enabled\n", ahc_name(ahc),
+					       enableSEC_low ? "Secondary "
+							     : "");
+			}
+		}
+
+		if (enablePRI_low != 0) {
+			*sxfrctl1 |= STPWEN;
+			if (bootverbose)
+				printf("%s: Primary Low Byte termination "
+				       "Enabled\n", ahc_name(ahc));
+		}
+
+		/*
+		 * Setup STPWEN before setting up the rest of
+		 * the termination per the tech note on the U160 cards.
+		 */
+		ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+		if (enablePRI_high != 0) {
+			brddat |= BRDDAT4;
+			if (bootverbose)
+				printf("%s: Primary High Byte "
+				       "termination Enabled\n",
+				       ahc_name(ahc));
+		}
+		
+		write_brdctl(ahc, brddat);
+
+	} else {
+		if ((adapter_control & CFSTERM) != 0) {
+			*sxfrctl1 |= STPWEN;
+
+			if (bootverbose)
+				printf("%s: %sLow byte termination Enabled\n",
+				       ahc_name(ahc),
+				       (ahc->features & AHC_ULTRA2) ? "Primary "
+								    : "");
+		}
+
+		if ((adapter_control & CFWSTERM) != 0
+		 && (ahc->features & AHC_WIDE) != 0) {
+			brddat |= BRDDAT6;
+			if (bootverbose)
+				printf("%s: %sHigh byte termination Enabled\n",
+				       ahc_name(ahc),
+				       (ahc->features & AHC_ULTRA2)
+				     ? "Secondary " : "");
+		}
+
+		/*
+		 * Setup STPWEN before setting up the rest of
+		 * the termination per the tech note on the U160 cards.
+		 */
+		ahc_outb(ahc, SXFRCTL1, *sxfrctl1);
+
+		if ((ahc->features & AHC_WIDE) != 0)
+			write_brdctl(ahc, brddat);
+	}
+	SEEPROM_OUTB(sd, sd->sd_MS); /* Clear CS */
+}
+
+static void
+ahc_new_term_detect(struct ahc_softc *ahc, int *enableSEC_low,
+		    int *enableSEC_high, int *enablePRI_low,
+		    int *enablePRI_high, int *eeprom_present)
+{
+	uint8_t brdctl;
+
+	/*
+	 * BRDDAT7 = Eeprom
+	 * BRDDAT6 = Enable Secondary High Byte termination
+	 * BRDDAT5 = Enable Secondary Low Byte termination
+	 * BRDDAT4 = Enable Primary high byte termination
+	 * BRDDAT3 = Enable Primary low byte termination
+	 */
+	brdctl = read_brdctl(ahc);
+	*eeprom_present = brdctl & BRDDAT7;
+	*enableSEC_high = (brdctl & BRDDAT6);
+	*enableSEC_low = (brdctl & BRDDAT5);
+	*enablePRI_high = (brdctl & BRDDAT4);
+	*enablePRI_low = (brdctl & BRDDAT3);
+}
+
+static void
+aic787X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+		     int *internal68_present, int *externalcable_present,
+		     int *eeprom_present)
+{
+	uint8_t brdctl;
+
+	/*
+	 * First read the status of our cables.
+	 * Set the rom bank to 0 since the
+	 * bank setting serves as a multiplexor
+	 * for the cable detection logic.
+	 * BRDDAT5 controls the bank switch.
+	 */
+	write_brdctl(ahc, 0);
+
+	/*
+	 * Now read the state of the internal
+	 * connectors.  BRDDAT6 is INT50 and
+	 * BRDDAT7 is INT68.
+	 */
+	brdctl = read_brdctl(ahc);
+	*internal50_present = (brdctl & BRDDAT6) ? 0 : 1;
+	*internal68_present = (brdctl & BRDDAT7) ? 0 : 1;
+
+	/*
+	 * Set the rom bank to 1 and determine
+	 * the other signals.
+	 */
+	write_brdctl(ahc, BRDDAT5);
+
+	/*
+	 * Now read the state of the external
+	 * connectors.  BRDDAT6 is EXT68 and
+	 * BRDDAT7 is EPROMPS.
+	 */
+	brdctl = read_brdctl(ahc);
+	*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+	*eeprom_present = (brdctl & BRDDAT7) ? 1 : 0;
+}
+
+static void
+aic785X_cable_detect(struct ahc_softc *ahc, int *internal50_present,
+		     int *externalcable_present, int *eeprom_present)
+{
+	uint8_t brdctl;
+	uint8_t spiocap;
+
+	spiocap = ahc_inb(ahc, SPIOCAP);
+	spiocap &= ~SOFTCMDEN;
+	spiocap |= EXT_BRDCTL;
+	ahc_outb(ahc, SPIOCAP, spiocap);
+	ahc_outb(ahc, BRDCTL, BRDRW|BRDCS);
+	ahc_flush_device_writes(ahc);
+	ahc_delay(500);
+	ahc_outb(ahc, BRDCTL, 0);
+	ahc_flush_device_writes(ahc);
+	ahc_delay(500);
+	brdctl = ahc_inb(ahc, BRDCTL);
+	*internal50_present = (brdctl & BRDDAT5) ? 0 : 1;
+	*externalcable_present = (brdctl & BRDDAT6) ? 0 : 1;
+	*eeprom_present = (ahc_inb(ahc, SPIOCAP) & EEPROM) ? 1 : 0;
+}
+	
+int
+ahc_acquire_seeprom(struct ahc_softc *ahc, struct seeprom_descriptor *sd)
+{
+	int wait;
+
+	if ((ahc->features & AHC_SPIOCAP) != 0
+	 && (ahc_inb(ahc, SPIOCAP) & SEEPROM) == 0)
+		return (0);
+
+	/*
+	 * Request access of the memory port.  When access is
+	 * granted, SEERDY will go high.  We use a 1 second
+	 * timeout which should be near 1 second more than
+	 * is needed.  Reason: after the chip reset, there
+	 * should be no contention.
+	 */
+	SEEPROM_OUTB(sd, sd->sd_MS);
+	wait = 1000;  /* 1 second timeout in msec */
+	while (--wait && ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0)) {
+		ahc_delay(1000);  /* delay 1 msec */
+	}
+	if ((SEEPROM_STATUS_INB(sd) & sd->sd_RDY) == 0) {
+		SEEPROM_OUTB(sd, 0); 
+		return (0);
+	}
+	return(1);
+}
+
+void
+ahc_release_seeprom(struct seeprom_descriptor *sd)
+{
+	/* Release access to the memory port and the serial EEPROM. */
+	SEEPROM_OUTB(sd, 0);
+}
+
+static void
+write_brdctl(struct ahc_softc *ahc, uint8_t value)
+{
+	uint8_t brdctl;
+
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		brdctl = BRDSTB;
+	 	if (ahc->channel == 'B')
+			brdctl |= BRDCS;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		brdctl = 0;
+	} else {
+		brdctl = BRDSTB|BRDCS;
+	}
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	brdctl |= value;
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		brdctl |= BRDSTB_ULTRA2;
+	else
+		brdctl &= ~BRDSTB;
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		brdctl = 0;
+	else
+		brdctl &= ~BRDCS;
+	ahc_outb(ahc, BRDCTL, brdctl);
+}
+
+static uint8_t
+read_brdctl(struct ahc_softc *ahc)
+{
+	uint8_t brdctl;
+	uint8_t value;
+
+	if ((ahc->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		brdctl = BRDRW;
+	 	if (ahc->channel == 'B')
+			brdctl |= BRDCS;
+	} else if ((ahc->features & AHC_ULTRA2) != 0) {
+		brdctl = BRDRW_ULTRA2;
+	} else {
+		brdctl = BRDRW|BRDCS;
+	}
+	ahc_outb(ahc, BRDCTL, brdctl);
+	ahc_flush_device_writes(ahc);
+	value = ahc_inb(ahc, BRDCTL);
+	ahc_outb(ahc, BRDCTL, 0);
+	return (value);
+}
+
+static void
+ahc_pci_intr(struct ahc_softc *ahc)
+{
+	u_int error;
+	u_int status1;
+
+	error = ahc_inb(ahc, ERROR);
+	if ((error & PCIERRSTAT) == 0)
+		return;
+
+	status1 = ahc_pci_read_config(ahc->dev_softc,
+				      PCIR_STATUS + 1, /*bytes*/1);
+
+	printf("%s: PCI error Interrupt at seqaddr = 0x%x\n",
+	      ahc_name(ahc),
+	      ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
+
+	if (status1 & DPE) {
+		ahc->pci_target_perr_count++;
+		printf("%s: Data Parity Error Detected during address "
+		       "or write data phase\n", ahc_name(ahc));
+	}
+	if (status1 & SSE) {
+		printf("%s: Signal System Error Detected\n", ahc_name(ahc));
+	}
+	if (status1 & RMA) {
+		printf("%s: Received a Master Abort\n", ahc_name(ahc));
+	}
+	if (status1 & RTA) {
+		printf("%s: Received a Target Abort\n", ahc_name(ahc));
+	}
+	if (status1 & STA) {
+		printf("%s: Signaled a Target Abort\n", ahc_name(ahc));
+	}
+	if (status1 & DPR) {
+		printf("%s: Data Parity Error has been reported via PERR#\n",
+		       ahc_name(ahc));
+	}
+
+	/* Clear latched errors. */
+	ahc_pci_write_config(ahc->dev_softc, PCIR_STATUS + 1,
+			     status1, /*bytes*/1);
+
+	if ((status1 & (DPE|SSE|RMA|RTA|STA|DPR)) == 0) {
+		printf("%s: Latched PCIERR interrupt with "
+		       "no status bits set\n", ahc_name(ahc)); 
+	} else {
+		ahc_outb(ahc, CLRINT, CLRPARERR);
+	}
+
+	if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
+		printf(
+"%s: WARNING WARNING WARNING WARNING\n"
+"%s: Too many PCI parity errors observed as a target.\n"
+"%s: Some device on this bus is generating bad parity.\n"
+"%s: This is an error *observed by*, not *generated by*, this controller.\n"
+"%s: PCI parity error checking has been disabled.\n"
+"%s: WARNING WARNING WARNING WARNING\n",
+		       ahc_name(ahc), ahc_name(ahc), ahc_name(ahc),
+		       ahc_name(ahc), ahc_name(ahc), ahc_name(ahc));
+		ahc->seqctl |= FAILDIS;
+		ahc_outb(ahc, SEQCTL, ahc->seqctl);
+	}
+	ahc_unpause(ahc);
+}
+
+static int
+ahc_pci_chip_init(struct ahc_softc *ahc)
+{
+	ahc_outb(ahc, DSCOMMAND0, ahc->bus_softc.pci_softc.dscommand0);
+	ahc_outb(ahc, DSPCISTATUS, ahc->bus_softc.pci_softc.dspcistatus);
+	if ((ahc->features & AHC_DT) != 0) {
+		u_int sfunct;
+
+		sfunct = ahc_inb(ahc, SFUNCT) & ~ALT_MODE;
+		ahc_outb(ahc, SFUNCT, sfunct | ALT_MODE);
+		ahc_outb(ahc, OPTIONMODE, ahc->bus_softc.pci_softc.optionmode);
+		ahc_outw(ahc, TARGCRCCNT, ahc->bus_softc.pci_softc.targcrccnt);
+		ahc_outb(ahc, SFUNCT, sfunct);
+		ahc_outb(ahc, CRCCONTROL1,
+			 ahc->bus_softc.pci_softc.crccontrol1);
+	}
+	if ((ahc->features & AHC_MULTI_FUNC) != 0)
+		ahc_outb(ahc, SCBBADDR, ahc->bus_softc.pci_softc.scbbaddr);
+
+	if ((ahc->features & AHC_ULTRA2) != 0)
+		ahc_outb(ahc, DFF_THRSH, ahc->bus_softc.pci_softc.dff_thrsh);
+
+	return (ahc_chip_init(ahc));
+}
+
+static int
+ahc_pci_suspend(struct ahc_softc *ahc)
+{
+	return (ahc_suspend(ahc));
+}
+
+static int
+ahc_pci_resume(struct ahc_softc *ahc)
+{
+
+	pci_set_power_state(ahc->dev_softc, AHC_POWER_STATE_D0);
+
+	/*
+	 * We assume that the OS has restored our register
+	 * mappings, etc.  Just update the config space registers
+	 * that the OS doesn't know about and rely on our chip
+	 * reset handler to handle the rest.
+	 */
+	ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, /*bytes*/4,
+			     ahc->bus_softc.pci_softc.devconfig);
+	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1,
+			     ahc->bus_softc.pci_softc.command);
+	ahc_pci_write_config(ahc->dev_softc, CSIZE_LATTIME, /*bytes*/1,
+			     ahc->bus_softc.pci_softc.csize_lattime);
+	if ((ahc->flags & AHC_HAS_TERM_LOGIC) != 0) {
+		struct	seeprom_descriptor sd;
+		u_int	sxfrctl1;
+
+		sd.sd_ahc = ahc;
+		sd.sd_control_offset = SEECTL;		
+		sd.sd_status_offset = SEECTL;		
+		sd.sd_dataout_offset = SEECTL;		
+
+		ahc_acquire_seeprom(ahc, &sd);
+		configure_termination(ahc, &sd,
+				      ahc->seep_config->adapter_control,
+				      &sxfrctl1);
+		ahc_release_seeprom(&sd);
+	}
+	return (ahc_resume(ahc));
+}
+
+static int
+ahc_aic785X_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+	uint8_t rev;
+
+	pci = ahc->dev_softc;
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7850;
+	ahc->features = AHC_AIC7850_FE;
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1)
+		ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	ahc->instruction_ram_size = 512;
+	return (0);
+}
+
+static int
+ahc_aic7860_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+	uint8_t rev;
+
+	pci = ahc->dev_softc;
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7860;
+	ahc->features = AHC_AIC7860_FE;
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1)
+		ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	ahc->instruction_ram_size = 512;
+	return (0);
+}
+
+static int
+ahc_apa1480_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7860_setup(ahc);
+	if (error != 0)
+		return (error);
+	ahc->features |= AHC_REMOVABLE;
+	return (0);
+}
+
+static int
+ahc_aic7870_setup(struct ahc_softc *ahc)
+{
+
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7870;
+	ahc->features = AHC_AIC7870_FE;
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	ahc->instruction_ram_size = 512;
+	return (0);
+}
+
+static int
+ahc_aha394X_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7870_setup(ahc);
+	if (error == 0)
+		error = ahc_aha394XX_setup(ahc);
+	return (error);
+}
+
+static int
+ahc_aha398X_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7870_setup(ahc);
+	if (error == 0)
+		error = ahc_aha398XX_setup(ahc);
+	return (error);
+}
+
+static int
+ahc_aha494X_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7870_setup(ahc);
+	if (error == 0)
+		error = ahc_aha494XX_setup(ahc);
+	return (error);
+}
+
+static int
+ahc_aic7880_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+	uint8_t rev;
+
+	pci = ahc->dev_softc;
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7880;
+	ahc->features = AHC_AIC7880_FE;
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 1) {
+		ahc->bugs |= AHC_PCI_2_1_RETRY_BUG;
+	} else {
+		ahc->bugs |= AHC_CACHETHEN_BUG|AHC_PCI_MWI_BUG;
+	}
+	ahc->instruction_ram_size = 512;
+	return (0);
+}
+
+static int
+ahc_aha2940Pro_setup(struct ahc_softc *ahc)
+{
+
+	ahc->flags |= AHC_INT50_SPEEDFLEX;
+	return (ahc_aic7880_setup(ahc));
+}
+
+static int
+ahc_aha394XU_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7880_setup(ahc);
+	if (error == 0)
+		error = ahc_aha394XX_setup(ahc);
+	return (error);
+}
+
+static int
+ahc_aha398XU_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7880_setup(ahc);
+	if (error == 0)
+		error = ahc_aha398XX_setup(ahc);
+	return (error);
+}
+
+static int
+ahc_aic7890_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+	uint8_t rev;
+
+	pci = ahc->dev_softc;
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7890;
+	ahc->features = AHC_AIC7890_FE;
+	ahc->flags |= AHC_NEWEEPROM_FMT;
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev == 0)
+		ahc->bugs |= AHC_AUTOFLUSH_BUG|AHC_CACHETHEN_BUG;
+	ahc->instruction_ram_size = 768;
+	return (0);
+}
+
+static int
+ahc_aic7892_setup(struct ahc_softc *ahc)
+{
+
+	ahc->channel = 'A';
+	ahc->chip = AHC_AIC7892;
+	ahc->features = AHC_AIC7892_FE;
+	ahc->flags |= AHC_NEWEEPROM_FMT;
+	ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	ahc->instruction_ram_size = 1024;
+	return (0);
+}
+
+static int
+ahc_aic7895_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+	uint8_t rev;
+
+	pci = ahc->dev_softc;
+	ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	/*
+	 * The 'C' revision of the aic7895 has a few additional features.
+	 */
+	rev = ahc_pci_read_config(pci, PCIR_REVID, /*bytes*/1);
+	if (rev >= 4) {
+		ahc->chip = AHC_AIC7895C;
+		ahc->features = AHC_AIC7895C_FE;
+	} else  {
+		u_int command;
+
+		ahc->chip = AHC_AIC7895;
+		ahc->features = AHC_AIC7895_FE;
+
+		/*
+		 * The BIOS disables the use of MWI transactions
+		 * since it does not have the MWI bug work around
+		 * we have.  Disabling MWI reduces performance, so
+		 * turn it on again.
+		 */
+		command = ahc_pci_read_config(pci, PCIR_COMMAND, /*bytes*/1);
+		command |= PCIM_CMD_MWRICEN;
+		ahc_pci_write_config(pci, PCIR_COMMAND, command, /*bytes*/1);
+		ahc->bugs |= AHC_PCI_MWI_BUG;
+	}
+	/*
+	 * XXX Does CACHETHEN really not work???  What about PCI retry?
+	 * on C level chips.  Need to test, but for now, play it safe.
+	 */
+	ahc->bugs |= AHC_TMODE_WIDEODD_BUG|AHC_PCI_2_1_RETRY_BUG
+		  |  AHC_CACHETHEN_BUG;
+
+#if 0
+	uint32_t devconfig;
+
+	/*
+	 * Cachesize must also be zero due to stray DAC
+	 * problem when sitting behind some bridges.
+	 */
+	ahc_pci_write_config(pci, CSIZE_LATTIME, 0, /*bytes*/1);
+	devconfig = ahc_pci_read_config(pci, DEVCONFIG, /*bytes*/1);
+	devconfig |= MRDCEN;
+	ahc_pci_write_config(pci, DEVCONFIG, devconfig, /*bytes*/1);
+#endif
+	ahc->flags |= AHC_NEWEEPROM_FMT;
+	ahc->instruction_ram_size = 512;
+	return (0);
+}
+
+static int
+ahc_aic7896_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+
+	pci = ahc->dev_softc;
+	ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	ahc->chip = AHC_AIC7896;
+	ahc->features = AHC_AIC7896_FE;
+	ahc->flags |= AHC_NEWEEPROM_FMT;
+	ahc->bugs |= AHC_CACHETHEN_DIS_BUG;
+	ahc->instruction_ram_size = 768;
+	return (0);
+}
+
+static int
+ahc_aic7899_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+
+	pci = ahc->dev_softc;
+	ahc->channel = ahc_get_pci_function(pci) == 1 ? 'B' : 'A';
+	ahc->chip = AHC_AIC7899;
+	ahc->features = AHC_AIC7899_FE;
+	ahc->flags |= AHC_NEWEEPROM_FMT;
+	ahc->bugs |= AHC_SCBCHAN_UPLOAD_BUG;
+	ahc->instruction_ram_size = 1024;
+	return (0);
+}
+
+static int
+ahc_aha29160C_setup(struct ahc_softc *ahc)
+{
+	int error;
+
+	error = ahc_aic7899_setup(ahc);
+	if (error != 0)
+		return (error);
+	ahc->features |= AHC_REMOVABLE;
+	return (0);
+}
+
+static int
+ahc_raid_setup(struct ahc_softc *ahc)
+{
+	printf("RAID functionality unsupported\n");
+	return (ENXIO);
+}
+
+static int
+ahc_aha394XX_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+
+	pci = ahc->dev_softc;
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_394X_SLOT_CHANNEL_A:
+		ahc->channel = 'A';
+		break;
+	case AHC_394X_SLOT_CHANNEL_B:
+		ahc->channel = 'B';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		ahc->channel = 'A';
+	}
+	return (0);
+}
+
+static int
+ahc_aha398XX_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+
+	pci = ahc->dev_softc;
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_398X_SLOT_CHANNEL_A:
+		ahc->channel = 'A';
+		break;
+	case AHC_398X_SLOT_CHANNEL_B:
+		ahc->channel = 'B';
+		break;
+	case AHC_398X_SLOT_CHANNEL_C:
+		ahc->channel = 'C';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		ahc->channel = 'A';
+		break;
+	}
+	ahc->flags |= AHC_LARGE_SEEPROM;
+	return (0);
+}
+
+static int
+ahc_aha494XX_setup(struct ahc_softc *ahc)
+{
+	ahc_dev_softc_t pci;
+
+	pci = ahc->dev_softc;
+	switch (ahc_get_pci_slot(pci)) {
+	case AHC_494X_SLOT_CHANNEL_A:
+		ahc->channel = 'A';
+		break;
+	case AHC_494X_SLOT_CHANNEL_B:
+		ahc->channel = 'B';
+		break;
+	case AHC_494X_SLOT_CHANNEL_C:
+		ahc->channel = 'C';
+		break;
+	case AHC_494X_SLOT_CHANNEL_D:
+		ahc->channel = 'D';
+		break;
+	default:
+		printf("adapter at unexpected slot %d\n"
+		       "unable to map to a channel\n",
+		       ahc_get_pci_slot(pci));
+		ahc->channel = 'A';
+	}
+	ahc->flags |= AHC_LARGE_SEEPROM;
+	return (0);
+}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_pci.h b/drivers/scsi/aic7xxx/aic7xxx_pci.h
new file mode 100644
index 0000000..be27fcb
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.h
@@ -0,0 +1,124 @@
+/*
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id$
+ *
+ */
+#ifndef _AIC7XXX_PCI_H_
+#define _AIC7XXX_PCI_H_
+
+#define ID_ALL_MASK			0xFFFFFFFFFFFFFFFFull
+#define ID_DEV_VENDOR_MASK		0xFFFFFFFF00000000ull
+#define ID_9005_GENERIC_MASK		0xFFF0FFFF00000000ull
+#define ID_9005_SISL_MASK		0x000FFFFF00000000ull
+#define ID_9005_SISL_ID			0x0005900500000000ull
+#define ID_AIC7850			0x5078900400000000ull
+#define ID_AHA_2902_04_10_15_20C_30C	0x5078900478509004ull
+#define ID_AIC7855			0x5578900400000000ull
+#define ID_AIC7859			0x3860900400000000ull
+#define ID_AHA_2930CU			0x3860900438699004ull
+#define ID_AIC7860			0x6078900400000000ull
+#define ID_AIC7860C			0x6078900478609004ull
+#define ID_AHA_1480A			0x6075900400000000ull
+#define ID_AHA_2940AU_0			0x6178900400000000ull
+#define ID_AHA_2940AU_1			0x6178900478619004ull
+#define ID_AHA_2940AU_CN		0x2178900478219004ull
+#define ID_AHA_2930C_VAR		0x6038900438689004ull
+
+#define ID_AIC7870			0x7078900400000000ull
+#define ID_AHA_2940			0x7178900400000000ull
+#define ID_AHA_3940			0x7278900400000000ull
+#define ID_AHA_398X			0x7378900400000000ull
+#define ID_AHA_2944			0x7478900400000000ull
+#define ID_AHA_3944			0x7578900400000000ull
+#define ID_AHA_4944			0x7678900400000000ull
+
+#define ID_AIC7880			0x8078900400000000ull
+#define ID_AIC7880_B			0x8078900478809004ull
+#define ID_AHA_2940U			0x8178900400000000ull
+#define ID_AHA_3940U			0x8278900400000000ull
+#define ID_AHA_2944U			0x8478900400000000ull
+#define ID_AHA_3944U			0x8578900400000000ull
+#define ID_AHA_398XU			0x8378900400000000ull
+#define ID_AHA_4944U			0x8678900400000000ull
+#define ID_AHA_2940UB			0x8178900478819004ull
+#define ID_AHA_2930U			0x8878900478889004ull
+#define ID_AHA_2940U_PRO		0x8778900478879004ull
+#define ID_AHA_2940U_CN			0x0078900478009004ull
+
+#define ID_AIC7895			0x7895900478959004ull
+#define ID_AIC7895_ARO			0x7890900478939004ull
+#define ID_AIC7895_ARO_MASK		0xFFF0FFFFFFFFFFFFull
+#define ID_AHA_2940U_DUAL		0x7895900478919004ull
+#define ID_AHA_3940AU			0x7895900478929004ull
+#define ID_AHA_3944AU			0x7895900478949004ull
+
+#define ID_AIC7890			0x001F9005000F9005ull
+#define ID_AIC7890_ARO			0x00139005000F9005ull
+#define ID_AAA_131U2			0x0013900500039005ull
+#define ID_AHA_2930U2			0x0011900501819005ull
+#define ID_AHA_2940U2B			0x00109005A1009005ull
+#define ID_AHA_2940U2_OEM		0x0010900521809005ull
+#define ID_AHA_2940U2			0x00109005A1809005ull
+#define ID_AHA_2950U2B			0x00109005E1009005ull
+
+#define ID_AIC7892			0x008F9005FFFF9005ull
+#define ID_AIC7892_ARO			0x00839005FFFF9005ull
+#define ID_AHA_29160			0x00809005E2A09005ull
+#define ID_AHA_29160_CPQ		0x00809005E2A00E11ull
+#define ID_AHA_29160N			0x0080900562A09005ull
+#define ID_AHA_29160C			0x0080900562209005ull
+#define ID_AHA_29160B			0x00809005E2209005ull
+#define ID_AHA_19160B			0x0081900562A19005ull
+
+#define ID_AIC7896			0x005F9005FFFF9005ull
+#define ID_AIC7896_ARO			0x00539005FFFF9005ull
+#define ID_AHA_3950U2B_0		0x00509005FFFF9005ull
+#define ID_AHA_3950U2B_1		0x00509005F5009005ull
+#define ID_AHA_3950U2D_0		0x00519005FFFF9005ull
+#define ID_AHA_3950U2D_1		0x00519005B5009005ull
+
+#define ID_AIC7899			0x00CF9005FFFF9005ull
+#define ID_AIC7899_ARO			0x00C39005FFFF9005ull
+#define ID_AHA_3960D			0x00C09005F6209005ull
+#define ID_AHA_3960D_CPQ		0x00C09005F6200E11ull
+
+#define ID_AIC7810			0x1078900400000000ull
+#define ID_AIC7815			0x7815900400000000ull
+
+#endif /* _AIC7XXX_PCI_H_ */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
new file mode 100644
index 0000000..85e80ee
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2000-2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
+ * sym driver.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#29 $
+ */
+#include "aic7xxx_osm.h"
+#include "aic7xxx_inline.h"
+#include "aic7xxx_93cx6.h"
+
+static void	copy_mem_info(struct info_str *info, char *data, int len);
+static int	copy_info(struct info_str *info, char *fmt, ...);
+static void	ahc_dump_target_state(struct ahc_softc *ahc,
+				      struct info_str *info,
+				      u_int our_id, char channel,
+				      u_int target_id, u_int target_offset);
+static void	ahc_dump_device_state(struct info_str *info,
+				      struct ahc_linux_device *dev);
+static int	ahc_proc_write_seeprom(struct ahc_softc *ahc,
+				       char *buffer, int length);
+
+static void
+copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->offset + info->length)
+		len = info->offset + info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+		off_t partial;
+
+		partial = info->offset - info->pos;
+		data += partial;
+		info->pos += partial;
+		len  -= partial;
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer, data, len);
+		info->pos += len;
+		info->buffer += len;
+	}
+}
+
+static int
+copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[256];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return (len);
+}
+
+void
+ahc_format_transinfo(struct info_str *info, struct ahc_transinfo *tinfo)
+{
+	u_int speed;
+	u_int freq;
+	u_int mb;
+
+        speed = 3300;
+        freq = 0;
+	if (tinfo->offset != 0) {
+		freq = aic_calc_syncsrate(tinfo->period);
+		speed = freq;
+	}
+	speed *= (0x01 << tinfo->width);
+        mb = speed / 1000;
+        if (mb > 0)
+		copy_info(info, "%d.%03dMB/s transfers", mb, speed % 1000);
+        else
+		copy_info(info, "%dKB/s transfers", speed);
+
+	if (freq != 0) {
+		copy_info(info, " (%d.%03dMHz%s, offset %d",
+			 freq / 1000, freq % 1000,
+			 (tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0
+			 ? " DT" : "", tinfo->offset);
+	}
+
+	if (tinfo->width > 0) {
+		if (freq != 0) {
+			copy_info(info, ", ");
+		} else {
+			copy_info(info, " (");
+		}
+		copy_info(info, "%dbit)", 8 * (0x01 << tinfo->width));
+	} else if (freq != 0) {
+		copy_info(info, ")");
+	}
+	copy_info(info, "\n");
+}
+
+static void
+ahc_dump_target_state(struct ahc_softc *ahc, struct info_str *info,
+		      u_int our_id, char channel, u_int target_id,
+		      u_int target_offset)
+{
+	struct	ahc_linux_target *targ;
+	struct	ahc_initiator_tinfo *tinfo;
+	struct	ahc_tmode_tstate *tstate;
+	int	lun;
+
+	tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
+				    target_id, &tstate);
+	if ((ahc->features & AHC_TWIN) != 0)
+		copy_info(info, "Channel %c ", channel);
+	copy_info(info, "Target %d Negotiation Settings\n", target_id);
+	copy_info(info, "\tUser: ");
+	ahc_format_transinfo(info, &tinfo->user);
+	targ = ahc->platform_data->targets[target_offset];
+	if (targ == NULL)
+		return;
+
+	copy_info(info, "\tGoal: ");
+	ahc_format_transinfo(info, &tinfo->goal);
+	copy_info(info, "\tCurr: ");
+	ahc_format_transinfo(info, &tinfo->curr);
+
+	for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
+		struct ahc_linux_device *dev;
+
+		dev = targ->devices[lun];
+
+		if (dev == NULL)
+			continue;
+
+		ahc_dump_device_state(info, dev);
+	}
+}
+
+static void
+ahc_dump_device_state(struct info_str *info, struct ahc_linux_device *dev)
+{
+	copy_info(info, "\tChannel %c Target %d Lun %d Settings\n",
+		  dev->target->channel + 'A', dev->target->target, dev->lun);
+
+	copy_info(info, "\t\tCommands Queued %ld\n", dev->commands_issued);
+	copy_info(info, "\t\tCommands Active %d\n", dev->active);
+	copy_info(info, "\t\tCommand Openings %d\n", dev->openings);
+	copy_info(info, "\t\tMax Tagged Openings %d\n", dev->maxtags);
+	copy_info(info, "\t\tDevice Queue Frozen Count %d\n", dev->qfrozen);
+}
+
+static int
+ahc_proc_write_seeprom(struct ahc_softc *ahc, char *buffer, int length)
+{
+	struct seeprom_descriptor sd;
+	int have_seeprom;
+	u_long s;
+	int paused;
+	int written;
+
+	/* Default to failure. */
+	written = -EINVAL;
+	ahc_lock(ahc, &s);
+	paused = ahc_is_paused(ahc);
+	if (!paused)
+		ahc_pause(ahc);
+
+	if (length != sizeof(struct seeprom_config)) {
+		printf("ahc_proc_write_seeprom: incorrect buffer size\n");
+		goto done;
+	}
+
+	have_seeprom = ahc_verify_cksum((struct seeprom_config*)buffer);
+	if (have_seeprom == 0) {
+		printf("ahc_proc_write_seeprom: cksum verification failed\n");
+		goto done;
+	}
+
+	sd.sd_ahc = ahc;
+#if AHC_PCI_CONFIG > 0
+	if ((ahc->chip & AHC_PCI) != 0) {
+		sd.sd_control_offset = SEECTL;
+		sd.sd_status_offset = SEECTL;
+		sd.sd_dataout_offset = SEECTL;
+		if (ahc->flags & AHC_LARGE_SEEPROM)
+			sd.sd_chip = C56_66;
+		else
+			sd.sd_chip = C46;
+		sd.sd_MS = SEEMS;
+		sd.sd_RDY = SEERDY;
+		sd.sd_CS = SEECS;
+		sd.sd_CK = SEECK;
+		sd.sd_DO = SEEDO;
+		sd.sd_DI = SEEDI;
+		have_seeprom = ahc_acquire_seeprom(ahc, &sd);
+	} else
+#endif
+	if ((ahc->chip & AHC_VL) != 0) {
+		sd.sd_control_offset = SEECTL_2840;
+		sd.sd_status_offset = STATUS_2840;
+		sd.sd_dataout_offset = STATUS_2840;		
+		sd.sd_chip = C46;
+		sd.sd_MS = 0;
+		sd.sd_RDY = EEPROM_TF;
+		sd.sd_CS = CS_2840;
+		sd.sd_CK = CK_2840;
+		sd.sd_DO = DO_2840;
+		sd.sd_DI = DI_2840;
+		have_seeprom = TRUE;
+	} else {
+		printf("ahc_proc_write_seeprom: unsupported adapter type\n");
+		goto done;
+	}
+
+	if (!have_seeprom) {
+		printf("ahc_proc_write_seeprom: No Serial EEPROM\n");
+		goto done;
+	} else {
+		u_int start_addr;
+
+		if (ahc->seep_config == NULL) {
+			ahc->seep_config = malloc(sizeof(*ahc->seep_config),
+						  M_DEVBUF, M_NOWAIT);
+			if (ahc->seep_config == NULL) {
+				printf("aic7xxx: Unable to allocate serial "
+				       "eeprom buffer.  Write failing\n");
+				goto done;
+			}
+		}
+		printf("aic7xxx: Writing Serial EEPROM\n");
+		start_addr = 32 * (ahc->channel - 'A');
+		ahc_write_seeprom(&sd, (u_int16_t *)buffer, start_addr,
+				  sizeof(struct seeprom_config)/2);
+		ahc_read_seeprom(&sd, (uint16_t *)ahc->seep_config,
+				 start_addr, sizeof(struct seeprom_config)/2);
+#if AHC_PCI_CONFIG > 0
+		if ((ahc->chip & AHC_VL) == 0)
+			ahc_release_seeprom(&sd);
+#endif
+		written = length;
+	}
+
+done:
+	if (!paused)
+		ahc_unpause(ahc);
+	ahc_unlock(ahc, &s);
+	return (written);
+}
+
+/*
+ * Return information to handle /proc support for the driver.
+ */
+int
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ahc_linux_proc_info(char *buffer, char **start, off_t offset,
+		    int length, int hostno, int inout)
+#else
+ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start,
+		    off_t offset, int length, int inout)
+#endif
+{
+	struct	ahc_softc *ahc;
+	struct	info_str info;
+	char	ahc_info[256];
+	u_long	s;
+	u_int	max_targ;
+	u_int	i;
+	int	retval;
+
+	retval = -EINVAL;
+	ahc_list_lock(&s);
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	TAILQ_FOREACH(ahc, &ahc_tailq, links) {
+		if (ahc->platform_data->host->host_no == hostno)
+			break;
+	}
+#else
+	ahc = ahc_find_softc(*(struct ahc_softc **)shost->hostdata);
+#endif
+
+	if (ahc == NULL)
+		goto done;
+
+	 /* Has data been written to the file? */ 
+	if (inout == TRUE) {
+		retval = ahc_proc_write_seeprom(ahc, buffer, length);
+		goto done;
+	}
+
+	if (start)
+		*start = buffer;
+
+	info.buffer	= buffer;
+	info.length	= length;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Adaptec AIC7xxx driver version: %s\n",
+		  AIC7XXX_DRIVER_VERSION);
+	copy_info(&info, "%s\n", ahc->description);
+	ahc_controller_info(ahc, ahc_info);
+	copy_info(&info, "%s\n", ahc_info);
+	copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+		  ahc->scb_data->numscbs, AHC_NSEG);
+
+
+	if (ahc->seep_config == NULL)
+		copy_info(&info, "No Serial EEPROM\n");
+	else {
+		copy_info(&info, "Serial EEPROM:\n");
+		for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
+			if (((i % 8) == 0) && (i != 0)) {
+				copy_info(&info, "\n");
+			}
+			copy_info(&info, "0x%.4x ",
+				  ((uint16_t*)ahc->seep_config)[i]);
+		}
+		copy_info(&info, "\n");
+	}
+	copy_info(&info, "\n");
+
+	max_targ = 15;
+	if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
+		max_targ = 7;
+
+	for (i = 0; i <= max_targ; i++) {
+		u_int our_id;
+		u_int target_id;
+		char channel;
+
+		channel = 'A';
+		our_id = ahc->our_id;
+		target_id = i;
+		if (i > 7 && (ahc->features & AHC_TWIN) != 0) {
+			channel = 'B';
+			our_id = ahc->our_id_b;
+			target_id = i % 8;
+		}
+
+		ahc_dump_target_state(ahc, &info, our_id,
+				      channel, target_id, i);
+	}
+	retval = info.pos > info.offset ? info.pos - info.offset : 0;
+done:
+	ahc_list_unlock(&s);
+	return (retval);
+}
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
new file mode 100644
index 0000000..7c1390e
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped
@@ -0,0 +1,1787 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ */
+typedef int (ahc_reg_print_t)(u_int, u_int *, u_int);
+typedef struct ahc_reg_parse_entry {
+	char	*name;
+	uint8_t	 value;
+	uint8_t	 mask;
+} ahc_reg_parse_entry_t;
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiseq_print;
+#else
+#define ahc_scsiseq_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSISEQ", 0x00, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sxfrctl0_print;
+#else
+#define ahc_sxfrctl0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SXFRCTL0", 0x01, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sxfrctl1_print;
+#else
+#define ahc_sxfrctl1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SXFRCTL1", 0x02, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsisigo_print;
+#else
+#define ahc_scsisigo_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSISIGO", 0x03, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsisigi_print;
+#else
+#define ahc_scsisigi_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSISIGI", 0x03, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsirate_print;
+#else
+#define ahc_scsirate_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIRATE", 0x04, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiid_print;
+#else
+#define ahc_scsiid_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIID", 0x05, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsidatl_print;
+#else
+#define ahc_scsidatl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIDATL", 0x06, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsidath_print;
+#else
+#define ahc_scsidath_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIDATH", 0x07, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_stcnt_print;
+#else
+#define ahc_stcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "STCNT", 0x08, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_optionmode_print;
+#else
+#define ahc_optionmode_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "OPTIONMODE", 0x08, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_targcrccnt_print;
+#else
+#define ahc_targcrccnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "TARGCRCCNT", 0x0a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_clrsint0_print;
+#else
+#define ahc_clrsint0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CLRSINT0", 0x0b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sstat0_print;
+#else
+#define ahc_sstat0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SSTAT0", 0x0b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_clrsint1_print;
+#else
+#define ahc_clrsint1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CLRSINT1", 0x0c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sstat1_print;
+#else
+#define ahc_sstat1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SSTAT1", 0x0c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sstat2_print;
+#else
+#define ahc_sstat2_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SSTAT2", 0x0d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sstat3_print;
+#else
+#define ahc_sstat3_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SSTAT3", 0x0e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiid_ultra2_print;
+#else
+#define ahc_scsiid_ultra2_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIID_ULTRA2", 0x0f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_simode0_print;
+#else
+#define ahc_simode0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SIMODE0", 0x10, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_simode1_print;
+#else
+#define ahc_simode1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SIMODE1", 0x11, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsibusl_print;
+#else
+#define ahc_scsibusl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIBUSL", 0x12, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsibush_print;
+#else
+#define ahc_scsibush_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIBUSH", 0x13, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sxfrctl2_print;
+#else
+#define ahc_sxfrctl2_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SXFRCTL2", 0x13, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_shaddr_print;
+#else
+#define ahc_shaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SHADDR", 0x14, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seltimer_print;
+#else
+#define ahc_seltimer_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SELTIMER", 0x18, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_selid_print;
+#else
+#define ahc_selid_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SELID", 0x19, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scamctl_print;
+#else
+#define ahc_scamctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCAMCTL", 0x1a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_targid_print;
+#else
+#define ahc_targid_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "TARGID", 0x1b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_spiocap_print;
+#else
+#define ahc_spiocap_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SPIOCAP", 0x1b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_brdctl_print;
+#else
+#define ahc_brdctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "BRDCTL", 0x1d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seectl_print;
+#else
+#define ahc_seectl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEECTL", 0x1e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sblkctl_print;
+#else
+#define ahc_sblkctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SBLKCTL", 0x1f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_busy_targets_print;
+#else
+#define ahc_busy_targets_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "BUSY_TARGETS", 0x20, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ultra_enb_print;
+#else
+#define ahc_ultra_enb_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ULTRA_ENB", 0x30, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_disc_dsb_print;
+#else
+#define ahc_disc_dsb_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DISC_DSB", 0x32, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_cmdsize_table_tail_print;
+#else
+#define ahc_cmdsize_table_tail_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CMDSIZE_TABLE_TAIL", 0x34, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_mwi_residual_print;
+#else
+#define ahc_mwi_residual_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "MWI_RESIDUAL", 0x38, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_next_queued_scb_print;
+#else
+#define ahc_next_queued_scb_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "NEXT_QUEUED_SCB", 0x39, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_msg_out_print;
+#else
+#define ahc_msg_out_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "MSG_OUT", 0x3a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dmaparams_print;
+#else
+#define ahc_dmaparams_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DMAPARAMS", 0x3b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seq_flags_print;
+#else
+#define ahc_seq_flags_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQ_FLAGS", 0x3c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_saved_scsiid_print;
+#else
+#define ahc_saved_scsiid_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SAVED_SCSIID", 0x3d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_saved_lun_print;
+#else
+#define ahc_saved_lun_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SAVED_LUN", 0x3e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_lastphase_print;
+#else
+#define ahc_lastphase_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "LASTPHASE", 0x3f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_waiting_scbh_print;
+#else
+#define ahc_waiting_scbh_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "WAITING_SCBH", 0x40, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_disconnected_scbh_print;
+#else
+#define ahc_disconnected_scbh_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DISCONNECTED_SCBH", 0x41, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_free_scbh_print;
+#else
+#define ahc_free_scbh_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "FREE_SCBH", 0x42, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_complete_scbh_print;
+#else
+#define ahc_complete_scbh_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "COMPLETE_SCBH", 0x43, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hscb_addr_print;
+#else
+#define ahc_hscb_addr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HSCB_ADDR", 0x44, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_shared_data_addr_print;
+#else
+#define ahc_shared_data_addr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SHARED_DATA_ADDR", 0x48, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_kernel_qinpos_print;
+#else
+#define ahc_kernel_qinpos_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "KERNEL_QINPOS", 0x4c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qinpos_print;
+#else
+#define ahc_qinpos_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QINPOS", 0x4d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qoutpos_print;
+#else
+#define ahc_qoutpos_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QOUTPOS", 0x4e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_kernel_tqinpos_print;
+#else
+#define ahc_kernel_tqinpos_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "KERNEL_TQINPOS", 0x4f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_tqinpos_print;
+#else
+#define ahc_tqinpos_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "TQINPOS", 0x50, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_arg_1_print;
+#else
+#define ahc_arg_1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ARG_1", 0x51, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_arg_2_print;
+#else
+#define ahc_arg_2_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ARG_2", 0x52, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_last_msg_print;
+#else
+#define ahc_last_msg_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "LAST_MSG", 0x53, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiseq_template_print;
+#else
+#define ahc_scsiseq_template_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSISEQ_TEMPLATE", 0x54, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ha_274_biosglobal_print;
+#else
+#define ahc_ha_274_biosglobal_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HA_274_BIOSGLOBAL", 0x56, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seq_flags2_print;
+#else
+#define ahc_seq_flags2_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQ_FLAGS2", 0x57, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiconf_print;
+#else
+#define ahc_scsiconf_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSICONF", 0x5a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_intdef_print;
+#else
+#define ahc_intdef_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "INTDEF", 0x5c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hostconf_print;
+#else
+#define ahc_hostconf_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HOSTCONF", 0x5d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ha_274_biosctrl_print;
+#else
+#define ahc_ha_274_biosctrl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HA_274_BIOSCTRL", 0x5f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seqctl_print;
+#else
+#define ahc_seqctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQCTL", 0x60, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seqram_print;
+#else
+#define ahc_seqram_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQRAM", 0x61, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seqaddr0_print;
+#else
+#define ahc_seqaddr0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQADDR0", 0x62, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seqaddr1_print;
+#else
+#define ahc_seqaddr1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEQADDR1", 0x63, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_accum_print;
+#else
+#define ahc_accum_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ACCUM", 0x64, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sindex_print;
+#else
+#define ahc_sindex_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SINDEX", 0x65, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dindex_print;
+#else
+#define ahc_dindex_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DINDEX", 0x66, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_allones_print;
+#else
+#define ahc_allones_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ALLONES", 0x69, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_allzeros_print;
+#else
+#define ahc_allzeros_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ALLZEROS", 0x6a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_none_print;
+#else
+#define ahc_none_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "NONE", 0x6a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_flags_print;
+#else
+#define ahc_flags_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "FLAGS", 0x6b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sindir_print;
+#else
+#define ahc_sindir_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SINDIR", 0x6c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dindir_print;
+#else
+#define ahc_dindir_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DINDIR", 0x6d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_function1_print;
+#else
+#define ahc_function1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "FUNCTION1", 0x6e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_stack_print;
+#else
+#define ahc_stack_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "STACK", 0x6f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_targ_offset_print;
+#else
+#define ahc_targ_offset_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "TARG_OFFSET", 0x70, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sram_base_print;
+#else
+#define ahc_sram_base_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SRAM_BASE", 0x70, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_bctl_print;
+#else
+#define ahc_bctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "BCTL", 0x84, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dscommand0_print;
+#else
+#define ahc_dscommand0_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DSCOMMAND0", 0x84, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_bustime_print;
+#else
+#define ahc_bustime_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "BUSTIME", 0x85, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dscommand1_print;
+#else
+#define ahc_dscommand1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DSCOMMAND1", 0x85, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_busspd_print;
+#else
+#define ahc_busspd_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "BUSSPD", 0x86, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hs_mailbox_print;
+#else
+#define ahc_hs_mailbox_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HS_MAILBOX", 0x86, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dspcistatus_print;
+#else
+#define ahc_dspcistatus_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DSPCISTATUS", 0x86, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hcntrl_print;
+#else
+#define ahc_hcntrl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HCNTRL", 0x87, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_haddr_print;
+#else
+#define ahc_haddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HADDR", 0x88, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hcnt_print;
+#else
+#define ahc_hcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HCNT", 0x8c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scbptr_print;
+#else
+#define ahc_scbptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCBPTR", 0x90, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_intstat_print;
+#else
+#define ahc_intstat_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "INTSTAT", 0x91, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_clrint_print;
+#else
+#define ahc_clrint_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CLRINT", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_error_print;
+#else
+#define ahc_error_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "ERROR", 0x92, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dfcntrl_print;
+#else
+#define ahc_dfcntrl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFCNTRL", 0x93, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dfstatus_print;
+#else
+#define ahc_dfstatus_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFSTATUS", 0x94, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dfwaddr_print;
+#else
+#define ahc_dfwaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFWADDR", 0x95, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dfraddr_print;
+#else
+#define ahc_dfraddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFRADDR", 0x97, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dfdat_print;
+#else
+#define ahc_dfdat_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFDAT", 0x99, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scbcnt_print;
+#else
+#define ahc_scbcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCBCNT", 0x9a, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qinfifo_print;
+#else
+#define ahc_qinfifo_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QINFIFO", 0x9b, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qincnt_print;
+#else
+#define ahc_qincnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QINCNT", 0x9c, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qoutfifo_print;
+#else
+#define ahc_qoutfifo_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QOUTFIFO", 0x9d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_crccontrol1_print;
+#else
+#define ahc_crccontrol1_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CRCCONTROL1", 0x9d, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qoutcnt_print;
+#else
+#define ahc_qoutcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QOUTCNT", 0x9e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scsiphase_print;
+#else
+#define ahc_scsiphase_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCSIPHASE", 0x9e, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sfunct_print;
+#else
+#define ahc_sfunct_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SFUNCT", 0x9f, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_base_print;
+#else
+#define ahc_scb_base_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_BASE", 0xa0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_cdb_ptr_print;
+#else
+#define ahc_scb_cdb_ptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_CDB_PTR", 0xa0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_residual_sgptr_print;
+#else
+#define ahc_scb_residual_sgptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_RESIDUAL_SGPTR", 0xa4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_scsi_status_print;
+#else
+#define ahc_scb_scsi_status_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_SCSI_STATUS", 0xa8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_target_phases_print;
+#else
+#define ahc_scb_target_phases_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_TARGET_PHASES", 0xa9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_target_data_dir_print;
+#else
+#define ahc_scb_target_data_dir_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_TARGET_DATA_DIR", 0xaa, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_target_itag_print;
+#else
+#define ahc_scb_target_itag_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_TARGET_ITAG", 0xab, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_dataptr_print;
+#else
+#define ahc_scb_dataptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_DATAPTR", 0xac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_datacnt_print;
+#else
+#define ahc_scb_datacnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_DATACNT", 0xb0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_sgptr_print;
+#else
+#define ahc_scb_sgptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_SGPTR", 0xb4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_control_print;
+#else
+#define ahc_scb_control_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_CONTROL", 0xb8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_scsiid_print;
+#else
+#define ahc_scb_scsiid_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_SCSIID", 0xb9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_lun_print;
+#else
+#define ahc_scb_lun_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_LUN", 0xba, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_tag_print;
+#else
+#define ahc_scb_tag_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_TAG", 0xbb, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_cdb_len_print;
+#else
+#define ahc_scb_cdb_len_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_CDB_LEN", 0xbc, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_scsirate_print;
+#else
+#define ahc_scb_scsirate_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_SCSIRATE", 0xbd, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_scsioffset_print;
+#else
+#define ahc_scb_scsioffset_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_SCSIOFFSET", 0xbe, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_next_print;
+#else
+#define ahc_scb_next_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_NEXT", 0xbf, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_64_spare_print;
+#else
+#define ahc_scb_64_spare_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_64_SPARE", 0xc0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_seectl_2840_print;
+#else
+#define ahc_seectl_2840_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SEECTL_2840", 0xc0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_status_2840_print;
+#else
+#define ahc_status_2840_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "STATUS_2840", 0xc1, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scb_64_btt_print;
+#else
+#define ahc_scb_64_btt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCB_64_BTT", 0xd0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_cchaddr_print;
+#else
+#define ahc_cchaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCHADDR", 0xe0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_cchcnt_print;
+#else
+#define ahc_cchcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCHCNT", 0xe8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccsgram_print;
+#else
+#define ahc_ccsgram_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSGRAM", 0xe9, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccsgaddr_print;
+#else
+#define ahc_ccsgaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSGADDR", 0xea, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccsgctl_print;
+#else
+#define ahc_ccsgctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSGCTL", 0xeb, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccscbram_print;
+#else
+#define ahc_ccscbram_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSCBRAM", 0xec, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccscbaddr_print;
+#else
+#define ahc_ccscbaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSCBADDR", 0xed, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccscbctl_print;
+#else
+#define ahc_ccscbctl_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSCBCTL", 0xee, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccscbcnt_print;
+#else
+#define ahc_ccscbcnt_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSCBCNT", 0xef, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_scbbaddr_print;
+#else
+#define ahc_scbbaddr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SCBBADDR", 0xf0, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_ccscbptr_print;
+#else
+#define ahc_ccscbptr_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "CCSCBPTR", 0xf1, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_hnscb_qoff_print;
+#else
+#define ahc_hnscb_qoff_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "HNSCB_QOFF", 0xf4, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_snscb_qoff_print;
+#else
+#define ahc_snscb_qoff_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SNSCB_QOFF", 0xf6, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sdscb_qoff_print;
+#else
+#define ahc_sdscb_qoff_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SDSCB_QOFF", 0xf8, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_qoff_ctlsta_print;
+#else
+#define ahc_qoff_ctlsta_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "QOFF_CTLSTA", 0xfa, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_dff_thrsh_print;
+#else
+#define ahc_dff_thrsh_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "DFF_THRSH", 0xfb, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sg_cache_shadow_print;
+#else
+#define ahc_sg_cache_shadow_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SG_CACHE_SHADOW", 0xfc, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahc_reg_print_t ahc_sg_cache_pre_print;
+#else
+#define ahc_sg_cache_pre_print(regvalue, cur_col, wrap) \
+    ahc_print_register(NULL, 0, "SG_CACHE_PRE", 0xfc, regvalue, cur_col, wrap)
+#endif
+
+
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		STIMESEL        	0x18
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		P_DATAIN_DT     	0x60
+#define		P_DATAOUT_DT    	0x20
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		SXFR            	0x70
+#define		SOFS            	0x0f
+#define		SXFR_ULTRA2     	0x0f
+#define		WIDEXFER        	0x80
+#define		ENABLE_CRC      	0x40
+#define		SINGLE_EDGE     	0x10
+
+#define	SCSIID          		0x05
+#define	SCSIOFFSET      		0x05
+#define		SOFS_ULTRA2     	0x7f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	OPTIONMODE      		0x08
+#define		OPTIONMODE_DEFAULTS	0x03
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
+#define	TARGCRCCNT      		0x0a
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRIOERR        	0x08
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		SWRAP           	0x08
+#define		IOERR           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		SFCNT           	0x1f
+#define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERR   	0x01
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		U2OFFCNT        	0x7f
+#define		OFFCNT          	0x0f
+
+#define	SCSIID_ULTRA2   		0x0f
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SXFRCTL2        		0x13
+#define		ASYNC_SETUP     	0x07
+#define		AUTORSTDIS      	0x10
+#define		CMDDMAEN        	0x08
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define	TARGIDIN        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SCAMCTL         		0x1a
+#define		SCAMLVL         	0x03
+#define		ENSCAMSELO      	0x80
+#define		CLRSCAMSELID    	0x40
+#define		ALTSTIM         	0x20
+#define		DFLTTID         	0x10
+
+#define	TARGID          		0x1b
+
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		EXT_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDDAT4         	0x10
+#define		BRDSTB          	0x10
+#define		BRDDAT3         	0x08
+#define		BRDCS           	0x08
+#define		BRDDAT2         	0x04
+#define		BRDRW           	0x04
+#define		BRDRW_ULTRA2    	0x02
+#define		BRDCTL1         	0x02
+#define		BRDCTL0         	0x01
+#define		BRDSTB_ULTRA2   	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		ENAB40          	0x08
+#define		SELBUSB         	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+#define		XCVR            	0x01
+
+#define	BUSY_TARGETS    		0x20
+#define	TARG_SCSIRATE   		0x20
+
+#define	ULTRA_ENB       		0x30
+#define	CMDSIZE_TABLE   		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	CMDSIZE_TABLE_TAIL		0x34
+
+#define	MWI_RESIDUAL    		0x38
+#define	TARG_IMMEDIATE_SCB		0x38
+
+#define	NEXT_QUEUED_SCB 		0x39
+
+#define	MSG_OUT         		0x3a
+
+#define	DMAPARAMS       		0x3b
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAEN          	0x10
+#define		SDMAENACK       	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x3c
+#define		NOT_IDENTIFIED  	0x80
+#define		NO_CDB_SENT     	0x40
+#define		TARGET_CMD_IS_TAGGED	0x40
+#define		DPHASE          	0x20
+#define		TARG_CMD_PENDING	0x10
+#define		CMDPHASE_PENDING	0x08
+#define		DPHASE_PENDING  	0x04
+#define		SPHASE_PENDING  	0x02
+#define		NO_DISCONNECT   	0x01
+
+#define	SAVED_SCSIID    		0x3d
+
+#define	SAVED_LUN       		0x3e
+
+#define	LASTPHASE       		0x3f
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		P_DATAIN        	0x40
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		MSGI            	0x20
+
+#define	WAITING_SCBH    		0x40
+
+#define	DISCONNECTED_SCBH		0x41
+
+#define	FREE_SCBH       		0x42
+
+#define	COMPLETE_SCBH   		0x43
+
+#define	HSCB_ADDR       		0x44
+
+#define	SHARED_DATA_ADDR		0x48
+
+#define	KERNEL_QINPOS   		0x4c
+
+#define	QINPOS          		0x4d
+
+#define	QOUTPOS         		0x4e
+
+#define	KERNEL_TQINPOS  		0x4f
+
+#define	TQINPOS         		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+#define		EXIT_MSG_LOOP   	0x08
+#define		CONT_MSG_LOOP   	0x04
+#define		CONT_TARG_SESSION	0x02
+
+#define	ARG_2           		0x52
+#define	RETURN_2        		0x52
+
+#define	LAST_MSG        		0x53
+
+#define	SCSISEQ_TEMPLATE		0x54
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+
+#define	HA_274_BIOSGLOBAL		0x56
+#define	INITIATOR_TAG   		0x56
+#define		HA_274_EXTENDED_TRANS	0x01
+
+#define	SEQ_FLAGS2      		0x57
+#define		TARGET_MSG_PENDING	0x02
+#define		SCB_DMA         	0x01
+
+#define	SCSICONF        		0x5a
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
+#define		TERM_ENB        	0x80
+#define		RESET_SCSI      	0x40
+#define		ENSPCHK         	0x20
+
+#define	INTDEF          		0x5c
+#define		VECTOR          	0x0f
+#define		EDGE_TRIG       	0x80
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSDISABLED    	0x30
+#define		BIOSMODE        	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	TARG_OFFSET     		0x70
+
+#define	SRAM_BASE       		0x70
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND0      		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+#define		INTSCBRAMSEL    	0x08
+#define		RAMPS           	0x04
+#define		USCBSIZE32      	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	DSCOMMAND1      		0x85
+#define		DSLATT          	0xfc
+#define		HADDLDSEL1      	0x02
+#define		HADDLDSEL0      	0x01
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH         	0xc0
+#define		DFTHRSH_75      	0x80
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	HS_MAILBOX      		0x86
+#define		HOST_MAILBOX    	0xf0
+#define		HOST_TQINPOS    	0x80
+#define		SEQ_MAILBOX     	0x0f
+
+#define	DSPCISTATUS     		0x86
+#define		DFTHRSH_100     	0xc0
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		OUT_OF_RANGE    	0xe1
+#define		NO_FREE_SCB     	0xd1
+#define		SCB_MISMATCH    	0xc1
+#define		MISSED_BUSFREE  	0xb1
+#define		MKMSG_FAILED    	0xa1
+#define		DATA_OVERRUN    	0x91
+#define		PERR_DETECTED   	0x81
+#define		BAD_STATUS      	0x71
+#define		HOST_MSG_LOOP   	0x61
+#define		PDATA_REINIT    	0x51
+#define		IGN_WIDE_RES    	0x41
+#define		NO_MATCH        	0x31
+#define		PROTO_VIOLATION 	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BAD_PHASE       	0x01
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		CIOPARERR       	0x80
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		PRELOAD_AVAIL   	0x80
+#define		DFCACHETH       	0x40
+#define		FIFOQWDEMP      	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFWADDR         		0x95
+
+#define	DFRADDR         		0x97
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBCNT_MASK     	0x1f
+#define		SCBAUTO         	0x80
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
+
+#define	QOUTCNT         		0x9e
+
+#define	SCSIPHASE       		0x9e
+#define		DATA_PHASE_MASK 	0x03
+#define		STATUS_PHASE    	0x20
+#define		COMMAND_PHASE   	0x10
+#define		MSG_IN_PHASE    	0x08
+#define		MSG_OUT_PHASE   	0x04
+#define		DATA_IN_PHASE   	0x02
+#define		DATA_OUT_PHASE  	0x01
+
+#define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_CDB_PTR     		0xa0
+#define	SCB_RESIDUAL_DATACNT		0xa0
+#define	SCB_CDB_STORE   		0xa0
+
+#define	SCB_RESIDUAL_SGPTR		0xa4
+
+#define	SCB_SCSI_STATUS 		0xa8
+
+#define	SCB_TARGET_PHASES		0xa9
+
+#define	SCB_TARGET_DATA_DIR		0xaa
+
+#define	SCB_TARGET_ITAG 		0xab
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+#define		SG_HIGH_ADDR_BITS	0x7f
+#define		SG_LAST_SEG     	0x80
+
+#define	SCB_SGPTR       		0xb4
+#define		SG_RESID_VALID  	0x04
+#define		SG_FULL_RESID   	0x02
+#define		SG_LIST_NULL    	0x01
+
+#define	SCB_CONTROL     		0xb8
+#define		SCB_TAG_TYPE    	0x03
+#define		STATUS_RCVD     	0x80
+#define		TARGET_SCB      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		MK_MESSAGE      	0x10
+#define		ULTRAENB        	0x08
+#define		DISCONNECTED    	0x04
+
+#define	SCB_SCSIID      		0xb9
+#define		TID             	0xf0
+#define		TWIN_TID        	0x70
+#define		OID             	0x0f
+#define		TWIN_CHNLB      	0x80
+
+#define	SCB_LUN         		0xba
+#define		LID             	0x3f
+#define		SCB_XFERLEN_ODD 	0x80
+
+#define	SCB_TAG         		0xbb
+
+#define	SCB_CDB_LEN     		0xbc
+
+#define	SCB_SCSIRATE    		0xbd
+
+#define	SCB_SCSIOFFSET  		0xbe
+
+#define	SCB_NEXT        		0xbf
+
+#define	SCB_64_SPARE    		0xc0
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	STATUS_2840     		0xc1
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		EEPROM_TF       	0x80
+#define		DI_2840         	0x01
+
+#define	SCB_64_BTT      		0xd0
+
+#define	CCHADDR         		0xe0
+
+#define	CCHCNT          		0xe8
+
+#define	CCSGRAM         		0xe9
+
+#define	CCSGADDR        		0xea
+
+#define	CCSGCTL         		0xeb
+#define		CCSGDONE        	0x80
+#define		CCSGEN          	0x08
+#define		SG_FETCH_NEEDED 	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBRAM        		0xec
+
+#define	CCSCBADDR       		0xed
+
+#define	CCSCBCTL        		0xee
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSCBCNT        		0xef
+
+#define	SCBBADDR        		0xf0
+
+#define	CCSCBPTR        		0xf1
+
+#define	HNSCB_QOFF      		0xf4
+
+#define	SNSCB_QOFF      		0xf6
+
+#define	SDSCB_QOFF      		0xf8
+
+#define	QOFF_CTLSTA     		0xfa
+#define		SCB_QSIZE       	0x07
+#define		SCB_QSIZE_256   	0x06
+#define		SCB_AVAIL       	0x40
+#define		SNSCB_ROLLOVER  	0x20
+#define		SDSCB_ROLLOVER  	0x10
+
+#define	DFF_THRSH       		0xfb
+#define		WR_DFTHRSH      	0x70
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		RD_DFTHRSH_MIN  	0x00
+#define		WR_DFTHRSH_MIN  	0x00
+
+#define	SG_CACHE_SHADOW 		0xfc
+#define		SG_ADDR_MASK    	0xf8
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+#define	SG_CACHE_PRE    		0xfc
+
+
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
+#define	BUS_8_BIT	0x00
+#define	TARGET_CMD_CMPLT	0xfe
+#define	STATUS_QUEUE_FULL	0x28
+#define	STATUS_BUSY	0x08
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+#define	TID_SHIFT	0x04
+#define	SCB_DOWNLOAD_SIZE_64	0x30
+#define	HOST_MAILBOX_SHIFT	0x04
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	CCSGRAM_MAXSEGS	0x10
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	SCB_DOWNLOAD_SIZE	0x20
+#define	SEQ_MAILBOX_SHIFT	0x00
+#define	TARGET_DATA_IN	0x01
+#define	HOST_MSG	0xff
+#define	MAX_OFFSET	0x7f
+#define	BUS_16_BIT	0x01
+#define	SCB_UPLOAD_SIZE	0x20
+#define	STACK_SIZE	0x04
+
+
+/* Downloaded Constant Definitions */
+#define	INVERTED_CACHESIZE_MASK	0x03
+#define	SG_PREFETCH_ADDR_MASK	0x06
+#define	SG_PREFETCH_ALIGN_MASK	0x05
+#define	QOUTFIFO_OFFSET	0x00
+#define	SG_PREFETCH_CNT	0x04
+#define	CACHESIZE_MASK	0x02
+#define	QINFIFO_OFFSET	0x01
+#define	DOWNLOAD_CONST_COUNT	0x07
+
+
+/* Exported Labels */
diff --git a/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
new file mode 100644
index 0000000..9c71377
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_reg_print.c_shipped
@@ -0,0 +1,1681 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ */
+
+#include "aic7xxx_osm.h"
+
+static ahc_reg_parse_entry_t SCSISEQ_parse_table[] = {
+	{ "SCSIRSTO",		0x01, 0x01 },
+	{ "ENAUTOATNP",		0x02, 0x02 },
+	{ "ENAUTOATNI",		0x04, 0x04 },
+	{ "ENAUTOATNO",		0x08, 0x08 },
+	{ "ENRSELI",		0x10, 0x10 },
+	{ "ENSELI",		0x20, 0x20 },
+	{ "ENSELO",		0x40, 0x40 },
+	{ "TEMODE",		0x80, 0x80 }
+};
+
+int
+ahc_scsiseq_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSISEQ_parse_table, 8, "SCSISEQ",
+	    0x00, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SXFRCTL0_parse_table[] = {
+	{ "CLRCHN",		0x02, 0x02 },
+	{ "SCAMEN",		0x04, 0x04 },
+	{ "SPIOEN",		0x08, 0x08 },
+	{ "CLRSTCNT",		0x10, 0x10 },
+	{ "FAST20",		0x20, 0x20 },
+	{ "DFPEXP",		0x40, 0x40 },
+	{ "DFON",		0x80, 0x80 }
+};
+
+int
+ahc_sxfrctl0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SXFRCTL0_parse_table, 7, "SXFRCTL0",
+	    0x01, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SXFRCTL1_parse_table[] = {
+	{ "STPWEN",		0x01, 0x01 },
+	{ "ACTNEGEN",		0x02, 0x02 },
+	{ "ENSTIMER",		0x04, 0x04 },
+	{ "ENSPCHK",		0x20, 0x20 },
+	{ "SWRAPEN",		0x40, 0x40 },
+	{ "BITBUCKET",		0x80, 0x80 },
+	{ "STIMESEL",		0x18, 0x18 }
+};
+
+int
+ahc_sxfrctl1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SXFRCTL1_parse_table, 7, "SXFRCTL1",
+	    0x02, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSISIGO_parse_table[] = {
+	{ "ACKO",		0x01, 0x01 },
+	{ "REQO",		0x02, 0x02 },
+	{ "BSYO",		0x04, 0x04 },
+	{ "SELO",		0x08, 0x08 },
+	{ "ATNO",		0x10, 0x10 },
+	{ "MSGO",		0x20, 0x20 },
+	{ "IOO",		0x40, 0x40 },
+	{ "CDO",		0x80, 0x80 },
+	{ "P_DATAOUT",		0x00, 0x00 },
+	{ "P_DATAIN",		0x40, 0x40 },
+	{ "P_COMMAND",		0x80, 0x80 },
+	{ "P_MESGOUT",		0xa0, 0xa0 },
+	{ "P_STATUS",		0xc0, 0xc0 },
+	{ "PHASE_MASK",		0xe0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 }
+};
+
+int
+ahc_scsisigo_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSISIGO_parse_table, 15, "SCSISIGO",
+	    0x03, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSISIGI_parse_table[] = {
+	{ "ACKI",		0x01, 0x01 },
+	{ "REQI",		0x02, 0x02 },
+	{ "BSYI",		0x04, 0x04 },
+	{ "SELI",		0x08, 0x08 },
+	{ "ATNI",		0x10, 0x10 },
+	{ "MSGI",		0x20, 0x20 },
+	{ "IOI",		0x40, 0x40 },
+	{ "CDI",		0x80, 0x80 },
+	{ "P_DATAOUT",		0x00, 0x00 },
+	{ "P_DATAOUT_DT",	0x20, 0x20 },
+	{ "P_DATAIN",		0x40, 0x40 },
+	{ "P_DATAIN_DT",	0x60, 0x60 },
+	{ "P_COMMAND",		0x80, 0x80 },
+	{ "P_MESGOUT",		0xa0, 0xa0 },
+	{ "P_STATUS",		0xc0, 0xc0 },
+	{ "PHASE_MASK",		0xe0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 }
+};
+
+int
+ahc_scsisigi_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSISIGI_parse_table, 17, "SCSISIGI",
+	    0x03, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSIRATE_parse_table[] = {
+	{ "SINGLE_EDGE",	0x10, 0x10 },
+	{ "ENABLE_CRC",		0x40, 0x40 },
+	{ "WIDEXFER",		0x80, 0x80 },
+	{ "SXFR_ULTRA2",	0x0f, 0x0f },
+	{ "SOFS",		0x0f, 0x0f },
+	{ "SXFR",		0x70, 0x70 }
+};
+
+int
+ahc_scsirate_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSIRATE_parse_table, 6, "SCSIRATE",
+	    0x04, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSIID_parse_table[] = {
+	{ "TWIN_CHNLB",		0x80, 0x80 },
+	{ "OID",		0x0f, 0x0f },
+	{ "TWIN_TID",		0x70, 0x70 },
+	{ "SOFS_ULTRA2",	0x7f, 0x7f },
+	{ "TID",		0xf0, 0xf0 }
+};
+
+int
+ahc_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSIID_parse_table, 5, "SCSIID",
+	    0x05, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scsidatl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCSIDATL",
+	    0x06, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scsidath_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCSIDATH",
+	    0x07, regvalue, cur_col, wrap));
+}
+
+int
+ahc_stcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "STCNT",
+	    0x08, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t OPTIONMODE_parse_table[] = {
+	{ "DIS_MSGIN_DUALEDGE",	0x01, 0x01 },
+	{ "AUTO_MSGOUT_DE",	0x02, 0x02 },
+	{ "SCSIDATL_IMGEN",	0x04, 0x04 },
+	{ "EXPPHASEDIS",	0x08, 0x08 },
+	{ "BUSFREEREV",		0x10, 0x10 },
+	{ "ATNMGMNTEN",		0x20, 0x20 },
+	{ "AUTOACKEN",		0x40, 0x40 },
+	{ "AUTORATEEN",		0x80, 0x80 },
+	{ "OPTIONMODE_DEFAULTS",0x03, 0x03 }
+};
+
+int
+ahc_optionmode_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(OPTIONMODE_parse_table, 9, "OPTIONMODE",
+	    0x08, regvalue, cur_col, wrap));
+}
+
+int
+ahc_targcrccnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "TARGCRCCNT",
+	    0x0a, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CLRSINT0_parse_table[] = {
+	{ "CLRSPIORDY",		0x02, 0x02 },
+	{ "CLRSWRAP",		0x08, 0x08 },
+	{ "CLRIOERR",		0x08, 0x08 },
+	{ "CLRSELINGO",		0x10, 0x10 },
+	{ "CLRSELDI",		0x20, 0x20 },
+	{ "CLRSELDO",		0x40, 0x40 }
+};
+
+int
+ahc_clrsint0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CLRSINT0_parse_table, 6, "CLRSINT0",
+	    0x0b, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SSTAT0_parse_table[] = {
+	{ "DMADONE",		0x01, 0x01 },
+	{ "SPIORDY",		0x02, 0x02 },
+	{ "SDONE",		0x04, 0x04 },
+	{ "SWRAP",		0x08, 0x08 },
+	{ "IOERR",		0x08, 0x08 },
+	{ "SELINGO",		0x10, 0x10 },
+	{ "SELDI",		0x20, 0x20 },
+	{ "SELDO",		0x40, 0x40 },
+	{ "TARGET",		0x80, 0x80 }
+};
+
+int
+ahc_sstat0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SSTAT0_parse_table, 9, "SSTAT0",
+	    0x0b, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CLRSINT1_parse_table[] = {
+	{ "CLRREQINIT",		0x01, 0x01 },
+	{ "CLRPHASECHG",	0x02, 0x02 },
+	{ "CLRSCSIPERR",	0x04, 0x04 },
+	{ "CLRBUSFREE",		0x08, 0x08 },
+	{ "CLRSCSIRSTI",	0x20, 0x20 },
+	{ "CLRATNO",		0x40, 0x40 },
+	{ "CLRSELTIMEO",	0x80, 0x80 }
+};
+
+int
+ahc_clrsint1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CLRSINT1_parse_table, 7, "CLRSINT1",
+	    0x0c, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SSTAT1_parse_table[] = {
+	{ "REQINIT",		0x01, 0x01 },
+	{ "PHASECHG",		0x02, 0x02 },
+	{ "SCSIPERR",		0x04, 0x04 },
+	{ "BUSFREE",		0x08, 0x08 },
+	{ "PHASEMIS",		0x10, 0x10 },
+	{ "SCSIRSTI",		0x20, 0x20 },
+	{ "ATNTARG",		0x40, 0x40 },
+	{ "SELTO",		0x80, 0x80 }
+};
+
+int
+ahc_sstat1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SSTAT1_parse_table, 8, "SSTAT1",
+	    0x0c, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SSTAT2_parse_table[] = {
+	{ "DUAL_EDGE_ERR",	0x01, 0x01 },
+	{ "CRCREQERR",		0x02, 0x02 },
+	{ "CRCENDERR",		0x04, 0x04 },
+	{ "CRCVALERR",		0x08, 0x08 },
+	{ "EXP_ACTIVE",		0x10, 0x10 },
+	{ "SHVALID",		0x40, 0x40 },
+	{ "OVERRUN",		0x80, 0x80 },
+	{ "SFCNT",		0x1f, 0x1f }
+};
+
+int
+ahc_sstat2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SSTAT2_parse_table, 8, "SSTAT2",
+	    0x0d, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SSTAT3_parse_table[] = {
+	{ "OFFCNT",		0x0f, 0x0f },
+	{ "U2OFFCNT",		0x7f, 0x7f },
+	{ "SCSICNT",		0xf0, 0xf0 }
+};
+
+int
+ahc_sstat3_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SSTAT3_parse_table, 3, "SSTAT3",
+	    0x0e, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSIID_ULTRA2_parse_table[] = {
+	{ "OID",		0x0f, 0x0f },
+	{ "TID",		0xf0, 0xf0 }
+};
+
+int
+ahc_scsiid_ultra2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSIID_ULTRA2_parse_table, 2, "SCSIID_ULTRA2",
+	    0x0f, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SIMODE0_parse_table[] = {
+	{ "ENDMADONE",		0x01, 0x01 },
+	{ "ENSPIORDY",		0x02, 0x02 },
+	{ "ENSDONE",		0x04, 0x04 },
+	{ "ENSWRAP",		0x08, 0x08 },
+	{ "ENIOERR",		0x08, 0x08 },
+	{ "ENSELINGO",		0x10, 0x10 },
+	{ "ENSELDI",		0x20, 0x20 },
+	{ "ENSELDO",		0x40, 0x40 }
+};
+
+int
+ahc_simode0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SIMODE0_parse_table, 8, "SIMODE0",
+	    0x10, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SIMODE1_parse_table[] = {
+	{ "ENREQINIT",		0x01, 0x01 },
+	{ "ENPHASECHG",		0x02, 0x02 },
+	{ "ENSCSIPERR",		0x04, 0x04 },
+	{ "ENBUSFREE",		0x08, 0x08 },
+	{ "ENPHASEMIS",		0x10, 0x10 },
+	{ "ENSCSIRST",		0x20, 0x20 },
+	{ "ENATNTARG",		0x40, 0x40 },
+	{ "ENSELTIMO",		0x80, 0x80 }
+};
+
+int
+ahc_simode1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SIMODE1_parse_table, 8, "SIMODE1",
+	    0x11, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scsibusl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCSIBUSL",
+	    0x12, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scsibush_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCSIBUSH",
+	    0x13, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SXFRCTL2_parse_table[] = {
+	{ "CMDDMAEN",		0x08, 0x08 },
+	{ "AUTORSTDIS",		0x10, 0x10 },
+	{ "ASYNC_SETUP",	0x07, 0x07 }
+};
+
+int
+ahc_sxfrctl2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SXFRCTL2_parse_table, 3, "SXFRCTL2",
+	    0x13, regvalue, cur_col, wrap));
+}
+
+int
+ahc_shaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SHADDR",
+	    0x14, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SELTIMER_parse_table[] = {
+	{ "STAGE1",		0x01, 0x01 },
+	{ "STAGE2",		0x02, 0x02 },
+	{ "STAGE3",		0x04, 0x04 },
+	{ "STAGE4",		0x08, 0x08 },
+	{ "STAGE5",		0x10, 0x10 },
+	{ "STAGE6",		0x20, 0x20 }
+};
+
+int
+ahc_seltimer_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SELTIMER_parse_table, 6, "SELTIMER",
+	    0x18, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SELID_parse_table[] = {
+	{ "ONEBIT",		0x08, 0x08 },
+	{ "SELID_MASK",		0xf0, 0xf0 }
+};
+
+int
+ahc_selid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SELID_parse_table, 2, "SELID",
+	    0x19, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCAMCTL_parse_table[] = {
+	{ "DFLTTID",		0x10, 0x10 },
+	{ "ALTSTIM",		0x20, 0x20 },
+	{ "CLRSCAMSELID",	0x40, 0x40 },
+	{ "ENSCAMSELO",		0x80, 0x80 },
+	{ "SCAMLVL",		0x03, 0x03 }
+};
+
+int
+ahc_scamctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCAMCTL_parse_table, 5, "SCAMCTL",
+	    0x1a, regvalue, cur_col, wrap));
+}
+
+int
+ahc_targid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "TARGID",
+	    0x1b, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SPIOCAP_parse_table[] = {
+	{ "SSPIOCPS",		0x01, 0x01 },
+	{ "ROM",		0x02, 0x02 },
+	{ "EEPROM",		0x04, 0x04 },
+	{ "SEEPROM",		0x08, 0x08 },
+	{ "EXT_BRDCTL",		0x10, 0x10 },
+	{ "SOFTCMDEN",		0x20, 0x20 },
+	{ "SOFT0",		0x40, 0x40 },
+	{ "SOFT1",		0x80, 0x80 }
+};
+
+int
+ahc_spiocap_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SPIOCAP_parse_table, 8, "SPIOCAP",
+	    0x1b, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t BRDCTL_parse_table[] = {
+	{ "BRDCTL0",		0x01, 0x01 },
+	{ "BRDSTB_ULTRA2",	0x01, 0x01 },
+	{ "BRDCTL1",		0x02, 0x02 },
+	{ "BRDRW_ULTRA2",	0x02, 0x02 },
+	{ "BRDRW",		0x04, 0x04 },
+	{ "BRDDAT2",		0x04, 0x04 },
+	{ "BRDCS",		0x08, 0x08 },
+	{ "BRDDAT3",		0x08, 0x08 },
+	{ "BRDSTB",		0x10, 0x10 },
+	{ "BRDDAT4",		0x10, 0x10 },
+	{ "BRDDAT5",		0x20, 0x20 },
+	{ "BRDDAT6",		0x40, 0x40 },
+	{ "BRDDAT7",		0x80, 0x80 }
+};
+
+int
+ahc_brdctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(BRDCTL_parse_table, 13, "BRDCTL",
+	    0x1d, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEECTL_parse_table[] = {
+	{ "SEEDI",		0x01, 0x01 },
+	{ "SEEDO",		0x02, 0x02 },
+	{ "SEECK",		0x04, 0x04 },
+	{ "SEECS",		0x08, 0x08 },
+	{ "SEERDY",		0x10, 0x10 },
+	{ "SEEMS",		0x20, 0x20 },
+	{ "EXTARBREQ",		0x40, 0x40 },
+	{ "EXTARBACK",		0x80, 0x80 }
+};
+
+int
+ahc_seectl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEECTL_parse_table, 8, "SEECTL",
+	    0x1e, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SBLKCTL_parse_table[] = {
+	{ "XCVR",		0x01, 0x01 },
+	{ "SELWIDE",		0x02, 0x02 },
+	{ "ENAB20",		0x04, 0x04 },
+	{ "SELBUSB",		0x08, 0x08 },
+	{ "ENAB40",		0x08, 0x08 },
+	{ "AUTOFLUSHDIS",	0x20, 0x20 },
+	{ "DIAGLEDON",		0x40, 0x40 },
+	{ "DIAGLEDEN",		0x80, 0x80 }
+};
+
+int
+ahc_sblkctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SBLKCTL_parse_table, 8, "SBLKCTL",
+	    0x1f, regvalue, cur_col, wrap));
+}
+
+int
+ahc_busy_targets_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "BUSY_TARGETS",
+	    0x20, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ultra_enb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "ULTRA_ENB",
+	    0x30, regvalue, cur_col, wrap));
+}
+
+int
+ahc_disc_dsb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DISC_DSB",
+	    0x32, regvalue, cur_col, wrap));
+}
+
+int
+ahc_cmdsize_table_tail_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CMDSIZE_TABLE_TAIL",
+	    0x34, regvalue, cur_col, wrap));
+}
+
+int
+ahc_mwi_residual_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "MWI_RESIDUAL",
+	    0x38, regvalue, cur_col, wrap));
+}
+
+int
+ahc_next_queued_scb_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "NEXT_QUEUED_SCB",
+	    0x39, regvalue, cur_col, wrap));
+}
+
+int
+ahc_msg_out_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "MSG_OUT",
+	    0x3a, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DMAPARAMS_parse_table[] = {
+	{ "FIFORESET",		0x01, 0x01 },
+	{ "FIFOFLUSH",		0x02, 0x02 },
+	{ "DIRECTION",		0x04, 0x04 },
+	{ "HDMAEN",		0x08, 0x08 },
+	{ "HDMAENACK",		0x08, 0x08 },
+	{ "SDMAEN",		0x10, 0x10 },
+	{ "SDMAENACK",		0x10, 0x10 },
+	{ "SCSIEN",		0x20, 0x20 },
+	{ "WIDEODD",		0x40, 0x40 },
+	{ "PRELOADEN",		0x80, 0x80 }
+};
+
+int
+ahc_dmaparams_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DMAPARAMS_parse_table, 10, "DMAPARAMS",
+	    0x3b, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEQ_FLAGS_parse_table[] = {
+	{ "NO_DISCONNECT",	0x01, 0x01 },
+	{ "SPHASE_PENDING",	0x02, 0x02 },
+	{ "DPHASE_PENDING",	0x04, 0x04 },
+	{ "CMDPHASE_PENDING",	0x08, 0x08 },
+	{ "TARG_CMD_PENDING",	0x10, 0x10 },
+	{ "DPHASE",		0x20, 0x20 },
+	{ "NO_CDB_SENT",	0x40, 0x40 },
+	{ "TARGET_CMD_IS_TAGGED",0x40, 0x40 },
+	{ "NOT_IDENTIFIED",	0x80, 0x80 }
+};
+
+int
+ahc_seq_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEQ_FLAGS_parse_table, 9, "SEQ_FLAGS",
+	    0x3c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_saved_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SAVED_SCSIID",
+	    0x3d, regvalue, cur_col, wrap));
+}
+
+int
+ahc_saved_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SAVED_LUN",
+	    0x3e, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t LASTPHASE_parse_table[] = {
+	{ "MSGI",		0x20, 0x20 },
+	{ "IOI",		0x40, 0x40 },
+	{ "CDI",		0x80, 0x80 },
+	{ "P_DATAOUT",		0x00, 0x00 },
+	{ "P_BUSFREE",		0x01, 0x01 },
+	{ "P_DATAIN",		0x40, 0x40 },
+	{ "P_COMMAND",		0x80, 0x80 },
+	{ "P_MESGOUT",		0xa0, 0xa0 },
+	{ "P_STATUS",		0xc0, 0xc0 },
+	{ "PHASE_MASK",		0xe0, 0xe0 },
+	{ "P_MESGIN",		0xe0, 0xe0 }
+};
+
+int
+ahc_lastphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(LASTPHASE_parse_table, 11, "LASTPHASE",
+	    0x3f, regvalue, cur_col, wrap));
+}
+
+int
+ahc_waiting_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "WAITING_SCBH",
+	    0x40, regvalue, cur_col, wrap));
+}
+
+int
+ahc_disconnected_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DISCONNECTED_SCBH",
+	    0x41, regvalue, cur_col, wrap));
+}
+
+int
+ahc_free_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "FREE_SCBH",
+	    0x42, regvalue, cur_col, wrap));
+}
+
+int
+ahc_complete_scbh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "COMPLETE_SCBH",
+	    0x43, regvalue, cur_col, wrap));
+}
+
+int
+ahc_hscb_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "HSCB_ADDR",
+	    0x44, regvalue, cur_col, wrap));
+}
+
+int
+ahc_shared_data_addr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SHARED_DATA_ADDR",
+	    0x48, regvalue, cur_col, wrap));
+}
+
+int
+ahc_kernel_qinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "KERNEL_QINPOS",
+	    0x4c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QINPOS",
+	    0x4d, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qoutpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QOUTPOS",
+	    0x4e, regvalue, cur_col, wrap));
+}
+
+int
+ahc_kernel_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "KERNEL_TQINPOS",
+	    0x4f, regvalue, cur_col, wrap));
+}
+
+int
+ahc_tqinpos_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "TQINPOS",
+	    0x50, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t ARG_1_parse_table[] = {
+	{ "CONT_TARG_SESSION",	0x02, 0x02 },
+	{ "CONT_MSG_LOOP",	0x04, 0x04 },
+	{ "EXIT_MSG_LOOP",	0x08, 0x08 },
+	{ "MSGOUT_PHASEMIS",	0x10, 0x10 },
+	{ "SEND_REJ",		0x20, 0x20 },
+	{ "SEND_SENSE",		0x40, 0x40 },
+	{ "SEND_MSG",		0x80, 0x80 }
+};
+
+int
+ahc_arg_1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(ARG_1_parse_table, 7, "ARG_1",
+	    0x51, regvalue, cur_col, wrap));
+}
+
+int
+ahc_arg_2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "ARG_2",
+	    0x52, regvalue, cur_col, wrap));
+}
+
+int
+ahc_last_msg_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "LAST_MSG",
+	    0x53, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSISEQ_TEMPLATE_parse_table[] = {
+	{ "ENAUTOATNP",		0x02, 0x02 },
+	{ "ENAUTOATNI",		0x04, 0x04 },
+	{ "ENAUTOATNO",		0x08, 0x08 },
+	{ "ENRSELI",		0x10, 0x10 },
+	{ "ENSELI",		0x20, 0x20 },
+	{ "ENSELO",		0x40, 0x40 }
+};
+
+int
+ahc_scsiseq_template_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSISEQ_TEMPLATE_parse_table, 6, "SCSISEQ_TEMPLATE",
+	    0x54, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t HA_274_BIOSGLOBAL_parse_table[] = {
+	{ "HA_274_EXTENDED_TRANS",0x01, 0x01 }
+};
+
+int
+ahc_ha_274_biosglobal_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(HA_274_BIOSGLOBAL_parse_table, 1, "HA_274_BIOSGLOBAL",
+	    0x56, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEQ_FLAGS2_parse_table[] = {
+	{ "SCB_DMA",		0x01, 0x01 },
+	{ "TARGET_MSG_PENDING",	0x02, 0x02 }
+};
+
+int
+ahc_seq_flags2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEQ_FLAGS2_parse_table, 2, "SEQ_FLAGS2",
+	    0x57, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSICONF_parse_table[] = {
+	{ "ENSPCHK",		0x20, 0x20 },
+	{ "RESET_SCSI",		0x40, 0x40 },
+	{ "TERM_ENB",		0x80, 0x80 },
+	{ "HSCSIID",		0x07, 0x07 },
+	{ "HWSCSIID",		0x0f, 0x0f }
+};
+
+int
+ahc_scsiconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSICONF_parse_table, 5, "SCSICONF",
+	    0x5a, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t INTDEF_parse_table[] = {
+	{ "EDGE_TRIG",		0x80, 0x80 },
+	{ "VECTOR",		0x0f, 0x0f }
+};
+
+int
+ahc_intdef_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(INTDEF_parse_table, 2, "INTDEF",
+	    0x5c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_hostconf_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "HOSTCONF",
+	    0x5d, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t HA_274_BIOSCTRL_parse_table[] = {
+	{ "CHANNEL_B_PRIMARY",	0x08, 0x08 },
+	{ "BIOSMODE",		0x30, 0x30 },
+	{ "BIOSDISABLED",	0x30, 0x30 }
+};
+
+int
+ahc_ha_274_biosctrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(HA_274_BIOSCTRL_parse_table, 3, "HA_274_BIOSCTRL",
+	    0x5f, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEQCTL_parse_table[] = {
+	{ "LOADRAM",		0x01, 0x01 },
+	{ "SEQRESET",		0x02, 0x02 },
+	{ "STEP",		0x04, 0x04 },
+	{ "BRKADRINTEN",	0x08, 0x08 },
+	{ "FASTMODE",		0x10, 0x10 },
+	{ "FAILDIS",		0x20, 0x20 },
+	{ "PAUSEDIS",		0x40, 0x40 },
+	{ "PERRORDIS",		0x80, 0x80 }
+};
+
+int
+ahc_seqctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEQCTL_parse_table, 8, "SEQCTL",
+	    0x60, regvalue, cur_col, wrap));
+}
+
+int
+ahc_seqram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SEQRAM",
+	    0x61, regvalue, cur_col, wrap));
+}
+
+int
+ahc_seqaddr0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SEQADDR0",
+	    0x62, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEQADDR1_parse_table[] = {
+	{ "SEQADDR1_MASK",	0x01, 0x01 }
+};
+
+int
+ahc_seqaddr1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEQADDR1_parse_table, 1, "SEQADDR1",
+	    0x63, regvalue, cur_col, wrap));
+}
+
+int
+ahc_accum_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "ACCUM",
+	    0x64, regvalue, cur_col, wrap));
+}
+
+int
+ahc_sindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SINDEX",
+	    0x65, regvalue, cur_col, wrap));
+}
+
+int
+ahc_dindex_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DINDEX",
+	    0x66, regvalue, cur_col, wrap));
+}
+
+int
+ahc_allones_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "ALLONES",
+	    0x69, regvalue, cur_col, wrap));
+}
+
+int
+ahc_allzeros_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "ALLZEROS",
+	    0x6a, regvalue, cur_col, wrap));
+}
+
+int
+ahc_none_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "NONE",
+	    0x6a, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t FLAGS_parse_table[] = {
+	{ "CARRY",		0x01, 0x01 },
+	{ "ZERO",		0x02, 0x02 }
+};
+
+int
+ahc_flags_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(FLAGS_parse_table, 2, "FLAGS",
+	    0x6b, regvalue, cur_col, wrap));
+}
+
+int
+ahc_sindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SINDIR",
+	    0x6c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_dindir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DINDIR",
+	    0x6d, regvalue, cur_col, wrap));
+}
+
+int
+ahc_function1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "FUNCTION1",
+	    0x6e, regvalue, cur_col, wrap));
+}
+
+int
+ahc_stack_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "STACK",
+	    0x6f, regvalue, cur_col, wrap));
+}
+
+int
+ahc_targ_offset_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "TARG_OFFSET",
+	    0x70, regvalue, cur_col, wrap));
+}
+
+int
+ahc_sram_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SRAM_BASE",
+	    0x70, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t BCTL_parse_table[] = {
+	{ "ENABLE",		0x01, 0x01 },
+	{ "ACE",		0x08, 0x08 }
+};
+
+int
+ahc_bctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(BCTL_parse_table, 2, "BCTL",
+	    0x84, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DSCOMMAND0_parse_table[] = {
+	{ "CIOPARCKEN",		0x01, 0x01 },
+	{ "USCBSIZE32",		0x02, 0x02 },
+	{ "RAMPS",		0x04, 0x04 },
+	{ "INTSCBRAMSEL",	0x08, 0x08 },
+	{ "EXTREQLCK",		0x10, 0x10 },
+	{ "MPARCKEN",		0x20, 0x20 },
+	{ "DPARCKEN",		0x40, 0x40 },
+	{ "CACHETHEN",		0x80, 0x80 }
+};
+
+int
+ahc_dscommand0_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DSCOMMAND0_parse_table, 8, "DSCOMMAND0",
+	    0x84, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t BUSTIME_parse_table[] = {
+	{ "BON",		0x0f, 0x0f },
+	{ "BOFF",		0xf0, 0xf0 }
+};
+
+int
+ahc_bustime_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(BUSTIME_parse_table, 2, "BUSTIME",
+	    0x85, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DSCOMMAND1_parse_table[] = {
+	{ "HADDLDSEL0",		0x01, 0x01 },
+	{ "HADDLDSEL1",		0x02, 0x02 },
+	{ "DSLATT",		0xfc, 0xfc }
+};
+
+int
+ahc_dscommand1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DSCOMMAND1_parse_table, 3, "DSCOMMAND1",
+	    0x85, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t BUSSPD_parse_table[] = {
+	{ "STBON",		0x07, 0x07 },
+	{ "STBOFF",		0x38, 0x38 },
+	{ "DFTHRSH_75",		0x80, 0x80 },
+	{ "DFTHRSH",		0xc0, 0xc0 },
+	{ "DFTHRSH_100",	0xc0, 0xc0 }
+};
+
+int
+ahc_busspd_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(BUSSPD_parse_table, 5, "BUSSPD",
+	    0x86, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t HS_MAILBOX_parse_table[] = {
+	{ "SEQ_MAILBOX",	0x0f, 0x0f },
+	{ "HOST_TQINPOS",	0x80, 0x80 },
+	{ "HOST_MAILBOX",	0xf0, 0xf0 }
+};
+
+int
+ahc_hs_mailbox_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(HS_MAILBOX_parse_table, 3, "HS_MAILBOX",
+	    0x86, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DSPCISTATUS_parse_table[] = {
+	{ "DFTHRSH_100",	0xc0, 0xc0 }
+};
+
+int
+ahc_dspcistatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DSPCISTATUS_parse_table, 1, "DSPCISTATUS",
+	    0x86, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t HCNTRL_parse_table[] = {
+	{ "CHIPRST",		0x01, 0x01 },
+	{ "CHIPRSTACK",		0x01, 0x01 },
+	{ "INTEN",		0x02, 0x02 },
+	{ "PAUSE",		0x04, 0x04 },
+	{ "IRQMS",		0x08, 0x08 },
+	{ "SWINT",		0x10, 0x10 },
+	{ "POWRDN",		0x40, 0x40 }
+};
+
+int
+ahc_hcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(HCNTRL_parse_table, 7, "HCNTRL",
+	    0x87, regvalue, cur_col, wrap));
+}
+
+int
+ahc_haddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "HADDR",
+	    0x88, regvalue, cur_col, wrap));
+}
+
+int
+ahc_hcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "HCNT",
+	    0x8c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCBPTR",
+	    0x90, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t INTSTAT_parse_table[] = {
+	{ "SEQINT",		0x01, 0x01 },
+	{ "CMDCMPLT",		0x02, 0x02 },
+	{ "SCSIINT",		0x04, 0x04 },
+	{ "BRKADRINT",		0x08, 0x08 },
+	{ "BAD_PHASE",		0x01, 0x01 },
+	{ "INT_PEND",		0x0f, 0x0f },
+	{ "SEND_REJECT",	0x11, 0x11 },
+	{ "PROTO_VIOLATION",	0x21, 0x21 },
+	{ "NO_MATCH",		0x31, 0x31 },
+	{ "IGN_WIDE_RES",	0x41, 0x41 },
+	{ "PDATA_REINIT",	0x51, 0x51 },
+	{ "HOST_MSG_LOOP",	0x61, 0x61 },
+	{ "BAD_STATUS",		0x71, 0x71 },
+	{ "PERR_DETECTED",	0x81, 0x81 },
+	{ "DATA_OVERRUN",	0x91, 0x91 },
+	{ "MKMSG_FAILED",	0xa1, 0xa1 },
+	{ "MISSED_BUSFREE",	0xb1, 0xb1 },
+	{ "SCB_MISMATCH",	0xc1, 0xc1 },
+	{ "NO_FREE_SCB",	0xd1, 0xd1 },
+	{ "OUT_OF_RANGE",	0xe1, 0xe1 },
+	{ "SEQINT_MASK",	0xf1, 0xf1 }
+};
+
+int
+ahc_intstat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(INTSTAT_parse_table, 21, "INTSTAT",
+	    0x91, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CLRINT_parse_table[] = {
+	{ "CLRSEQINT",		0x01, 0x01 },
+	{ "CLRCMDINT",		0x02, 0x02 },
+	{ "CLRSCSIINT",		0x04, 0x04 },
+	{ "CLRBRKADRINT",	0x08, 0x08 },
+	{ "CLRPARERR",		0x10, 0x10 }
+};
+
+int
+ahc_clrint_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CLRINT_parse_table, 5, "CLRINT",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t ERROR_parse_table[] = {
+	{ "ILLHADDR",		0x01, 0x01 },
+	{ "ILLSADDR",		0x02, 0x02 },
+	{ "ILLOPCODE",		0x04, 0x04 },
+	{ "SQPARERR",		0x08, 0x08 },
+	{ "DPARERR",		0x10, 0x10 },
+	{ "MPARERR",		0x20, 0x20 },
+	{ "PCIERRSTAT",		0x40, 0x40 },
+	{ "CIOPARERR",		0x80, 0x80 }
+};
+
+int
+ahc_error_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(ERROR_parse_table, 8, "ERROR",
+	    0x92, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DFCNTRL_parse_table[] = {
+	{ "FIFORESET",		0x01, 0x01 },
+	{ "FIFOFLUSH",		0x02, 0x02 },
+	{ "DIRECTION",		0x04, 0x04 },
+	{ "HDMAEN",		0x08, 0x08 },
+	{ "HDMAENACK",		0x08, 0x08 },
+	{ "SDMAEN",		0x10, 0x10 },
+	{ "SDMAENACK",		0x10, 0x10 },
+	{ "SCSIEN",		0x20, 0x20 },
+	{ "WIDEODD",		0x40, 0x40 },
+	{ "PRELOADEN",		0x80, 0x80 }
+};
+
+int
+ahc_dfcntrl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DFCNTRL_parse_table, 10, "DFCNTRL",
+	    0x93, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DFSTATUS_parse_table[] = {
+	{ "FIFOEMP",		0x01, 0x01 },
+	{ "FIFOFULL",		0x02, 0x02 },
+	{ "DFTHRESH",		0x04, 0x04 },
+	{ "HDONE",		0x08, 0x08 },
+	{ "MREQPEND",		0x10, 0x10 },
+	{ "FIFOQWDEMP",		0x20, 0x20 },
+	{ "DFCACHETH",		0x40, 0x40 },
+	{ "PRELOAD_AVAIL",	0x80, 0x80 }
+};
+
+int
+ahc_dfstatus_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DFSTATUS_parse_table, 8, "DFSTATUS",
+	    0x94, regvalue, cur_col, wrap));
+}
+
+int
+ahc_dfwaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DFWADDR",
+	    0x95, regvalue, cur_col, wrap));
+}
+
+int
+ahc_dfraddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DFRADDR",
+	    0x97, regvalue, cur_col, wrap));
+}
+
+int
+ahc_dfdat_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "DFDAT",
+	    0x99, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCBCNT_parse_table[] = {
+	{ "SCBAUTO",		0x80, 0x80 },
+	{ "SCBCNT_MASK",	0x1f, 0x1f }
+};
+
+int
+ahc_scbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCBCNT_parse_table, 2, "SCBCNT",
+	    0x9a, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qinfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QINFIFO",
+	    0x9b, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qincnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QINCNT",
+	    0x9c, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qoutfifo_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QOUTFIFO",
+	    0x9d, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CRCCONTROL1_parse_table[] = {
+	{ "TARGCRCCNTEN",	0x04, 0x04 },
+	{ "TARGCRCENDEN",	0x08, 0x08 },
+	{ "CRCREQCHKEN",	0x10, 0x10 },
+	{ "CRCENDCHKEN",	0x20, 0x20 },
+	{ "CRCVALCHKEN",	0x40, 0x40 },
+	{ "CRCONSEEN",		0x80, 0x80 }
+};
+
+int
+ahc_crccontrol1_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CRCCONTROL1_parse_table, 6, "CRCCONTROL1",
+	    0x9d, regvalue, cur_col, wrap));
+}
+
+int
+ahc_qoutcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "QOUTCNT",
+	    0x9e, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCSIPHASE_parse_table[] = {
+	{ "DATA_OUT_PHASE",	0x01, 0x01 },
+	{ "DATA_IN_PHASE",	0x02, 0x02 },
+	{ "MSG_OUT_PHASE",	0x04, 0x04 },
+	{ "MSG_IN_PHASE",	0x08, 0x08 },
+	{ "COMMAND_PHASE",	0x10, 0x10 },
+	{ "STATUS_PHASE",	0x20, 0x20 },
+	{ "DATA_PHASE_MASK",	0x03, 0x03 }
+};
+
+int
+ahc_scsiphase_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCSIPHASE_parse_table, 7, "SCSIPHASE",
+	    0x9e, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SFUNCT_parse_table[] = {
+	{ "ALT_MODE",		0x80, 0x80 }
+};
+
+int
+ahc_sfunct_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SFUNCT_parse_table, 1, "SFUNCT",
+	    0x9f, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_base_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_BASE",
+	    0xa0, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_cdb_ptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_CDB_PTR",
+	    0xa0, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_residual_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_RESIDUAL_SGPTR",
+	    0xa4, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_scsi_status_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_SCSI_STATUS",
+	    0xa8, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_target_phases_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_TARGET_PHASES",
+	    0xa9, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_target_data_dir_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_TARGET_DATA_DIR",
+	    0xaa, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_target_itag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_TARGET_ITAG",
+	    0xab, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_DATAPTR",
+	    0xac, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
+	{ "SG_LAST_SEG",	0x80, 0x80 },
+	{ "SG_HIGH_ADDR_BITS",	0x7f, 0x7f }
+};
+
+int
+ahc_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT",
+	    0xb0, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
+	{ "SG_LIST_NULL",	0x01, 0x01 },
+	{ "SG_FULL_RESID",	0x02, 0x02 },
+	{ "SG_RESID_VALID",	0x04, 0x04 }
+};
+
+int
+ahc_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR",
+	    0xb4, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
+	{ "DISCONNECTED",	0x04, 0x04 },
+	{ "ULTRAENB",		0x08, 0x08 },
+	{ "MK_MESSAGE",		0x10, 0x10 },
+	{ "TAG_ENB",		0x20, 0x20 },
+	{ "DISCENB",		0x40, 0x40 },
+	{ "TARGET_SCB",		0x80, 0x80 },
+	{ "STATUS_RCVD",	0x80, 0x80 },
+	{ "SCB_TAG_TYPE",	0x03, 0x03 }
+};
+
+int
+ahc_scb_control_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCB_CONTROL_parse_table, 8, "SCB_CONTROL",
+	    0xb8, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCB_SCSIID_parse_table[] = {
+	{ "TWIN_CHNLB",		0x80, 0x80 },
+	{ "OID",		0x0f, 0x0f },
+	{ "TWIN_TID",		0x70, 0x70 },
+	{ "TID",		0xf0, 0xf0 }
+};
+
+int
+ahc_scb_scsiid_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCB_SCSIID_parse_table, 4, "SCB_SCSIID",
+	    0xb9, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SCB_LUN_parse_table[] = {
+	{ "SCB_XFERLEN_ODD",	0x80, 0x80 },
+	{ "LID",		0x3f, 0x3f }
+};
+
+int
+ahc_scb_lun_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SCB_LUN_parse_table, 2, "SCB_LUN",
+	    0xba, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_TAG",
+	    0xbb, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_CDB_LEN",
+	    0xbc, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_scsirate_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_SCSIRATE",
+	    0xbd, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_scsioffset_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_SCSIOFFSET",
+	    0xbe, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_NEXT",
+	    0xbf, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_64_spare_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_64_SPARE",
+	    0xc0, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SEECTL_2840_parse_table[] = {
+	{ "DO_2840",		0x01, 0x01 },
+	{ "CK_2840",		0x02, 0x02 },
+	{ "CS_2840",		0x04, 0x04 }
+};
+
+int
+ahc_seectl_2840_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SEECTL_2840_parse_table, 3, "SEECTL_2840",
+	    0xc0, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t STATUS_2840_parse_table[] = {
+	{ "DI_2840",		0x01, 0x01 },
+	{ "EEPROM_TF",		0x80, 0x80 },
+	{ "ADSEL",		0x1e, 0x1e },
+	{ "BIOS_SEL",		0x60, 0x60 }
+};
+
+int
+ahc_status_2840_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(STATUS_2840_parse_table, 4, "STATUS_2840",
+	    0xc1, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scb_64_btt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCB_64_BTT",
+	    0xd0, regvalue, cur_col, wrap));
+}
+
+int
+ahc_cchaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCHADDR",
+	    0xe0, regvalue, cur_col, wrap));
+}
+
+int
+ahc_cchcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCHCNT",
+	    0xe8, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccsgram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSGRAM",
+	    0xe9, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccsgaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSGADDR",
+	    0xea, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CCSGCTL_parse_table[] = {
+	{ "CCSGRESET",		0x01, 0x01 },
+	{ "SG_FETCH_NEEDED",	0x02, 0x02 },
+	{ "CCSGEN",		0x08, 0x08 },
+	{ "CCSGDONE",		0x80, 0x80 }
+};
+
+int
+ahc_ccsgctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CCSGCTL_parse_table, 4, "CCSGCTL",
+	    0xeb, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccscbram_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSCBRAM",
+	    0xec, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccscbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSCBADDR",
+	    0xed, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t CCSCBCTL_parse_table[] = {
+	{ "CCSCBRESET",		0x01, 0x01 },
+	{ "CCSCBDIR",		0x04, 0x04 },
+	{ "CCSCBEN",		0x08, 0x08 },
+	{ "CCARREN",		0x10, 0x10 },
+	{ "ARRDONE",		0x40, 0x40 },
+	{ "CCSCBDONE",		0x80, 0x80 }
+};
+
+int
+ahc_ccscbctl_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(CCSCBCTL_parse_table, 6, "CCSCBCTL",
+	    0xee, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccscbcnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSCBCNT",
+	    0xef, regvalue, cur_col, wrap));
+}
+
+int
+ahc_scbbaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SCBBADDR",
+	    0xf0, regvalue, cur_col, wrap));
+}
+
+int
+ahc_ccscbptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "CCSCBPTR",
+	    0xf1, regvalue, cur_col, wrap));
+}
+
+int
+ahc_hnscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "HNSCB_QOFF",
+	    0xf4, regvalue, cur_col, wrap));
+}
+
+int
+ahc_snscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SNSCB_QOFF",
+	    0xf6, regvalue, cur_col, wrap));
+}
+
+int
+ahc_sdscb_qoff_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(NULL, 0, "SDSCB_QOFF",
+	    0xf8, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t QOFF_CTLSTA_parse_table[] = {
+	{ "SDSCB_ROLLOVER",	0x10, 0x10 },
+	{ "SNSCB_ROLLOVER",	0x20, 0x20 },
+	{ "SCB_AVAIL",		0x40, 0x40 },
+	{ "SCB_QSIZE_256",	0x06, 0x06 },
+	{ "SCB_QSIZE",		0x07, 0x07 }
+};
+
+int
+ahc_qoff_ctlsta_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(QOFF_CTLSTA_parse_table, 5, "QOFF_CTLSTA",
+	    0xfa, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t DFF_THRSH_parse_table[] = {
+	{ "RD_DFTHRSH_MIN",	0x00, 0x00 },
+	{ "WR_DFTHRSH_MIN",	0x00, 0x00 },
+	{ "RD_DFTHRSH_25",	0x01, 0x01 },
+	{ "RD_DFTHRSH_50",	0x02, 0x02 },
+	{ "RD_DFTHRSH_63",	0x03, 0x03 },
+	{ "RD_DFTHRSH_75",	0x04, 0x04 },
+	{ "RD_DFTHRSH_85",	0x05, 0x05 },
+	{ "RD_DFTHRSH_90",	0x06, 0x06 },
+	{ "RD_DFTHRSH",		0x07, 0x07 },
+	{ "RD_DFTHRSH_MAX",	0x07, 0x07 },
+	{ "WR_DFTHRSH_25",	0x10, 0x10 },
+	{ "WR_DFTHRSH_50",	0x20, 0x20 },
+	{ "WR_DFTHRSH_63",	0x30, 0x30 },
+	{ "WR_DFTHRSH_75",	0x40, 0x40 },
+	{ "WR_DFTHRSH_85",	0x50, 0x50 },
+	{ "WR_DFTHRSH_90",	0x60, 0x60 },
+	{ "WR_DFTHRSH",		0x70, 0x70 },
+	{ "WR_DFTHRSH_MAX",	0x70, 0x70 }
+};
+
+int
+ahc_dff_thrsh_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(DFF_THRSH_parse_table, 18, "DFF_THRSH",
+	    0xfb, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SG_CACHE_SHADOW_parse_table[] = {
+	{ "LAST_SEG_DONE",	0x01, 0x01 },
+	{ "LAST_SEG",		0x02, 0x02 },
+	{ "SG_ADDR_MASK",	0xf8, 0xf8 }
+};
+
+int
+ahc_sg_cache_shadow_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SG_CACHE_SHADOW_parse_table, 3, "SG_CACHE_SHADOW",
+	    0xfc, regvalue, cur_col, wrap));
+}
+
+static ahc_reg_parse_entry_t SG_CACHE_PRE_parse_table[] = {
+	{ "LAST_SEG_DONE",	0x01, 0x01 },
+	{ "LAST_SEG",		0x02, 0x02 },
+	{ "SG_ADDR_MASK",	0xf8, 0xf8 }
+};
+
+int
+ahc_sg_cache_pre_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahc_print_register(SG_CACHE_PRE_parse_table, 3, "SG_CACHE_PRE",
+	    0xfc, regvalue, cur_col, wrap));
+}
+
diff --git a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
new file mode 100644
index 0000000..cf41136
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped
@@ -0,0 +1,1307 @@
+/*
+ * DO NOT EDIT - This file is automatically generated
+ *		 from the following source files:
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $
+ */
+static uint8_t seqprog[] = {
+	0xb2, 0x00, 0x00, 0x08,
+	0xf7, 0x11, 0x22, 0x08,
+	0x00, 0x65, 0xec, 0x59,
+	0xf7, 0x01, 0x02, 0x08,
+	0xff, 0x6a, 0x24, 0x08,
+	0x40, 0x00, 0x40, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x40, 0x00, 0x40, 0x68,
+	0xff, 0x40, 0x3c, 0x60,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x60, 0x0b, 0x42, 0x68,
+	0x40, 0xfa, 0x12, 0x78,
+	0x01, 0x4d, 0xc8, 0x30,
+	0x00, 0x4c, 0x12, 0x70,
+	0x01, 0x39, 0xa2, 0x30,
+	0x00, 0x6a, 0xc0, 0x5e,
+	0x01, 0x51, 0x20, 0x31,
+	0x01, 0x57, 0xae, 0x00,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0x51, 0x12, 0x5e,
+	0x01, 0x51, 0xc8, 0x30,
+	0x00, 0x39, 0xc8, 0x60,
+	0x00, 0xbb, 0x30, 0x70,
+	0xc1, 0x6a, 0xd8, 0x5e,
+	0x01, 0xbf, 0x72, 0x30,
+	0x01, 0x40, 0x7e, 0x31,
+	0x01, 0x90, 0x80, 0x30,
+	0x01, 0xf6, 0xd4, 0x30,
+	0x01, 0x4d, 0x9a, 0x18,
+	0xfe, 0x57, 0xae, 0x08,
+	0x01, 0x40, 0x20, 0x31,
+	0x00, 0x65, 0xcc, 0x58,
+	0x60, 0x0b, 0x40, 0x78,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x60, 0x0b, 0x00, 0x78,
+	0x40, 0x0b, 0xfa, 0x68,
+	0x80, 0x0b, 0xb6, 0x78,
+	0x20, 0x6a, 0x16, 0x00,
+	0xa4, 0x6a, 0x06, 0x00,
+	0x08, 0x6a, 0x78, 0x00,
+	0x01, 0x50, 0xc8, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xfc, 0x5d,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0xfc, 0x5d,
+	0x01, 0x6a, 0x26, 0x01,
+	0xf0, 0x19, 0x7a, 0x08,
+	0x0f, 0x18, 0xc8, 0x08,
+	0x0f, 0x0f, 0xc8, 0x08,
+	0x0f, 0x05, 0xc8, 0x08,
+	0x00, 0x3d, 0x7a, 0x00,
+	0x08, 0x1f, 0x6e, 0x78,
+	0x80, 0x3d, 0x7a, 0x00,
+	0x01, 0x3d, 0xd8, 0x31,
+	0x01, 0x3d, 0x32, 0x31,
+	0x10, 0x03, 0x4e, 0x79,
+	0x00, 0x65, 0xf2, 0x58,
+	0x80, 0x66, 0xae, 0x78,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x3f, 0x66, 0x7c, 0x08,
+	0x40, 0x66, 0x82, 0x68,
+	0x01, 0x3c, 0x78, 0x00,
+	0x10, 0x03, 0x9e, 0x78,
+	0x00, 0x65, 0xf2, 0x58,
+	0xe0, 0x66, 0xc8, 0x18,
+	0x00, 0x65, 0xaa, 0x50,
+	0xdd, 0x66, 0xc8, 0x18,
+	0x00, 0x65, 0xaa, 0x48,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x10, 0x03, 0x4e, 0x79,
+	0x00, 0x65, 0xf2, 0x58,
+	0x01, 0x66, 0xd8, 0x31,
+	0x01, 0x66, 0x32, 0x31,
+	0x01, 0x66, 0xac, 0x30,
+	0x40, 0x3c, 0x78, 0x00,
+	0xff, 0x6a, 0xd8, 0x01,
+	0xff, 0x6a, 0x32, 0x01,
+	0x10, 0x3c, 0x78, 0x00,
+	0x02, 0x57, 0x40, 0x69,
+	0x10, 0x03, 0x3e, 0x69,
+	0x00, 0x65, 0x20, 0x41,
+	0x02, 0x57, 0xae, 0x00,
+	0x00, 0x65, 0x9e, 0x40,
+	0x61, 0x6a, 0xd8, 0x5e,
+	0x08, 0x51, 0x20, 0x71,
+	0x02, 0x0b, 0xb2, 0x78,
+	0x00, 0x65, 0xae, 0x40,
+	0x1a, 0x01, 0x02, 0x00,
+	0xf0, 0x19, 0x7a, 0x08,
+	0x0f, 0x0f, 0xc8, 0x08,
+	0x0f, 0x05, 0xc8, 0x08,
+	0x00, 0x3d, 0x7a, 0x00,
+	0x08, 0x1f, 0xc4, 0x78,
+	0x80, 0x3d, 0x7a, 0x00,
+	0x20, 0x6a, 0x16, 0x00,
+	0x00, 0x65, 0xcc, 0x41,
+	0x00, 0x65, 0xb2, 0x5e,
+	0x00, 0x65, 0x12, 0x40,
+	0x20, 0x11, 0xd2, 0x68,
+	0x20, 0x6a, 0x18, 0x00,
+	0x20, 0x11, 0x22, 0x00,
+	0xf7, 0x1f, 0xca, 0x08,
+	0x80, 0xb9, 0xd8, 0x78,
+	0x08, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0x3e, 0x30,
+	0x01, 0xb9, 0x1e, 0x30,
+	0x7f, 0xb9, 0x0a, 0x08,
+	0x01, 0xb9, 0x0a, 0x30,
+	0x01, 0x54, 0xca, 0x30,
+	0x80, 0xb8, 0xe6, 0x78,
+	0x80, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0x00, 0x34,
+	0x01, 0x54, 0x00, 0x34,
+	0x08, 0xb8, 0xee, 0x78,
+	0x20, 0x01, 0x02, 0x00,
+	0x02, 0xbd, 0x08, 0x34,
+	0x01, 0xbd, 0x08, 0x34,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0xf4, 0x78,
+	0xf7, 0x01, 0x02, 0x08,
+	0x01, 0x06, 0xcc, 0x34,
+	0xb2, 0x00, 0x00, 0x08,
+	0x01, 0x40, 0x20, 0x31,
+	0x01, 0xbf, 0x80, 0x30,
+	0x01, 0xb9, 0x7a, 0x30,
+	0x3f, 0xba, 0x7c, 0x08,
+	0x00, 0x65, 0xea, 0x58,
+	0x80, 0x0b, 0xc4, 0x79,
+	0x12, 0x01, 0x02, 0x00,
+	0x01, 0xab, 0xac, 0x30,
+	0xe4, 0x6a, 0x6e, 0x5d,
+	0x40, 0x6a, 0x16, 0x00,
+	0x80, 0x3e, 0x84, 0x5d,
+	0x20, 0xb8, 0x18, 0x79,
+	0x20, 0x6a, 0x84, 0x5d,
+	0x00, 0xab, 0x84, 0x5d,
+	0x01, 0xa9, 0x78, 0x30,
+	0x10, 0xb8, 0x20, 0x79,
+	0xe4, 0x6a, 0x6e, 0x5d,
+	0x00, 0x65, 0xae, 0x40,
+	0x10, 0x03, 0x3c, 0x69,
+	0x08, 0x3c, 0x5a, 0x69,
+	0x04, 0x3c, 0x92, 0x69,
+	0x02, 0x3c, 0x98, 0x69,
+	0x01, 0x3c, 0x44, 0x79,
+	0xff, 0x6a, 0x70, 0x00,
+	0x00, 0x65, 0xa4, 0x59,
+	0x00, 0x6a, 0xc0, 0x5e,
+	0xff, 0x38, 0x30, 0x71,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0x38, 0x12, 0x5e,
+	0x00, 0x65, 0xea, 0x58,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0x18, 0x41,
+	0xa4, 0x6a, 0x06, 0x00,
+	0x00, 0x65, 0xf2, 0x58,
+	0xfd, 0x57, 0xae, 0x08,
+	0x00, 0x65, 0xae, 0x40,
+	0xe4, 0x6a, 0x6e, 0x5d,
+	0x20, 0x3c, 0x4a, 0x79,
+	0x02, 0x6a, 0x84, 0x5d,
+	0x04, 0x6a, 0x84, 0x5d,
+	0x01, 0x03, 0x4c, 0x69,
+	0xf7, 0x11, 0x22, 0x08,
+	0xff, 0x6a, 0x24, 0x08,
+	0xff, 0x6a, 0x06, 0x08,
+	0x01, 0x6a, 0x7e, 0x00,
+	0x00, 0x65, 0xa4, 0x59,
+	0x00, 0x65, 0x04, 0x40,
+	0x80, 0x86, 0xc8, 0x08,
+	0x01, 0x4f, 0xc8, 0x30,
+	0x00, 0x50, 0x6c, 0x61,
+	0xc4, 0x6a, 0x6e, 0x5d,
+	0x40, 0x3c, 0x68, 0x79,
+	0x28, 0x6a, 0x84, 0x5d,
+	0x00, 0x65, 0x4c, 0x41,
+	0x08, 0x6a, 0x84, 0x5d,
+	0x00, 0x65, 0x4c, 0x41,
+	0x84, 0x6a, 0x6e, 0x5d,
+	0x00, 0x65, 0xf2, 0x58,
+	0x01, 0x66, 0xc8, 0x30,
+	0x01, 0x64, 0xd8, 0x31,
+	0x01, 0x64, 0x32, 0x31,
+	0x5b, 0x64, 0xc8, 0x28,
+	0x30, 0x64, 0xca, 0x18,
+	0x01, 0x6c, 0xc8, 0x30,
+	0xff, 0x64, 0x8e, 0x79,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0x80, 0x79,
+	0x01, 0x64, 0x86, 0x61,
+	0xf7, 0x01, 0x02, 0x08,
+	0x01, 0x06, 0xd8, 0x31,
+	0x01, 0x06, 0x32, 0x31,
+	0xff, 0x64, 0xc8, 0x18,
+	0xff, 0x64, 0x80, 0x69,
+	0xf7, 0x3c, 0x78, 0x08,
+	0x00, 0x65, 0x20, 0x41,
+	0x40, 0xaa, 0x7e, 0x10,
+	0x04, 0xaa, 0x6e, 0x5d,
+	0x00, 0x65, 0x56, 0x42,
+	0xc4, 0x6a, 0x6e, 0x5d,
+	0xc0, 0x6a, 0x7e, 0x00,
+	0x00, 0xa8, 0x84, 0x5d,
+	0xe4, 0x6a, 0x06, 0x00,
+	0x00, 0x6a, 0x84, 0x5d,
+	0x00, 0x65, 0x4c, 0x41,
+	0x10, 0x3c, 0xa8, 0x69,
+	0x00, 0xbb, 0x8a, 0x44,
+	0x18, 0x6a, 0xda, 0x01,
+	0x01, 0x69, 0xd8, 0x31,
+	0x1c, 0x6a, 0xd0, 0x01,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xb0, 0x79,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x01, 0x93, 0x26, 0x01,
+	0x03, 0x6a, 0x2a, 0x01,
+	0x01, 0x69, 0x32, 0x31,
+	0x1c, 0x6a, 0xe0, 0x5d,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0xa8, 0x5e,
+	0x01, 0x50, 0xa0, 0x18,
+	0x02, 0x6a, 0x22, 0x05,
+	0x1a, 0x01, 0x02, 0x00,
+	0x80, 0x6a, 0x74, 0x00,
+	0x40, 0x6a, 0x78, 0x00,
+	0x40, 0x6a, 0x16, 0x00,
+	0x00, 0x65, 0xd8, 0x5d,
+	0x01, 0x3f, 0xc8, 0x30,
+	0xbf, 0x64, 0x56, 0x7a,
+	0x80, 0x64, 0x9e, 0x73,
+	0xa0, 0x64, 0x00, 0x74,
+	0xc0, 0x64, 0xf4, 0x73,
+	0xe0, 0x64, 0x30, 0x74,
+	0x01, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0xcc, 0x41,
+	0xf7, 0x11, 0x22, 0x08,
+	0x01, 0x06, 0xd4, 0x30,
+	0xff, 0x6a, 0x24, 0x08,
+	0xf7, 0x01, 0x02, 0x08,
+	0x09, 0x0c, 0xe6, 0x79,
+	0x08, 0x0c, 0x04, 0x68,
+	0xb1, 0x6a, 0xd8, 0x5e,
+	0xff, 0x6a, 0x26, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0x02, 0x6a, 0x08, 0x30,
+	0xff, 0x6a, 0x08, 0x08,
+	0xdf, 0x01, 0x02, 0x08,
+	0x01, 0x6a, 0x7e, 0x00,
+	0xc0, 0x6a, 0x78, 0x04,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x08, 0xa4, 0x48, 0x19,
+	0x00, 0xa5, 0x4a, 0x21,
+	0x00, 0xa6, 0x4c, 0x21,
+	0x00, 0xa7, 0x4e, 0x25,
+	0x08, 0xeb, 0xdc, 0x7e,
+	0x80, 0xeb, 0x06, 0x7a,
+	0xff, 0x6a, 0xd6, 0x09,
+	0x08, 0xeb, 0x0a, 0x6a,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x80, 0xa3, 0xdc, 0x6e,
+	0x88, 0xeb, 0x20, 0x72,
+	0x08, 0xeb, 0xdc, 0x6e,
+	0x04, 0xea, 0x24, 0xe2,
+	0x08, 0xee, 0xdc, 0x6e,
+	0x04, 0x6a, 0xd0, 0x81,
+	0x05, 0xa4, 0xc0, 0x89,
+	0x03, 0xa5, 0xc2, 0x31,
+	0x09, 0x6a, 0xd6, 0x05,
+	0x00, 0x65, 0x08, 0x5a,
+	0x06, 0xa4, 0xd4, 0x89,
+	0x80, 0x94, 0xdc, 0x7e,
+	0x07, 0xe9, 0x10, 0x31,
+	0x01, 0xe9, 0x46, 0x31,
+	0x00, 0xa3, 0xba, 0x5e,
+	0x00, 0x65, 0xfa, 0x59,
+	0x01, 0xa4, 0xca, 0x30,
+	0x80, 0xa3, 0x34, 0x7a,
+	0x02, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0xf8, 0x31,
+	0x80, 0x93, 0x26, 0x01,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x01, 0x8c, 0xc8, 0x30,
+	0x00, 0x88, 0xc8, 0x18,
+	0x02, 0x64, 0xc8, 0x88,
+	0xff, 0x64, 0xdc, 0x7e,
+	0xff, 0x8d, 0x4a, 0x6a,
+	0xff, 0x8e, 0x4a, 0x6a,
+	0x03, 0x8c, 0xd4, 0x98,
+	0x00, 0x65, 0xdc, 0x56,
+	0x01, 0x64, 0x70, 0x30,
+	0xff, 0x64, 0xc8, 0x10,
+	0x01, 0x64, 0xc8, 0x18,
+	0x00, 0x8c, 0x18, 0x19,
+	0xff, 0x8d, 0x1a, 0x21,
+	0xff, 0x8e, 0x1c, 0x25,
+	0xc0, 0x3c, 0x5a, 0x7a,
+	0x21, 0x6a, 0xd8, 0x5e,
+	0xa8, 0x6a, 0x76, 0x00,
+	0x79, 0x6a, 0x76, 0x00,
+	0x40, 0x3f, 0x62, 0x6a,
+	0x04, 0x3b, 0x76, 0x00,
+	0x04, 0x6a, 0xd4, 0x81,
+	0x20, 0x3c, 0x6a, 0x7a,
+	0x51, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x82, 0x42,
+	0x20, 0x3c, 0x78, 0x00,
+	0x00, 0xb3, 0xba, 0x5e,
+	0x07, 0xac, 0x10, 0x31,
+	0x05, 0xb3, 0x46, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xac, 0x6a, 0xee, 0x5d,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0xb3, 0x6a, 0xf2, 0x5d,
+	0x00, 0x65, 0x3a, 0x5a,
+	0xfd, 0xa4, 0x48, 0x09,
+	0x03, 0x8c, 0x10, 0x30,
+	0x00, 0x65, 0xe6, 0x5d,
+	0x01, 0xa4, 0x94, 0x7a,
+	0x04, 0x3b, 0x76, 0x08,
+	0x01, 0x3b, 0x26, 0x31,
+	0x80, 0x02, 0x04, 0x00,
+	0x10, 0x0c, 0x8a, 0x7a,
+	0x03, 0x9e, 0x8c, 0x6a,
+	0x7f, 0x02, 0x04, 0x08,
+	0x91, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0xcc, 0x41,
+	0x01, 0xa4, 0xca, 0x30,
+	0x80, 0xa3, 0x9a, 0x7a,
+	0x02, 0x65, 0xca, 0x00,
+	0x01, 0x65, 0xf8, 0x31,
+	0x01, 0x3b, 0x26, 0x31,
+	0x00, 0x65, 0x0e, 0x5a,
+	0x01, 0xfc, 0xa8, 0x6a,
+	0x80, 0x0b, 0x9e, 0x6a,
+	0x10, 0x0c, 0x9e, 0x7a,
+	0x20, 0x93, 0x9e, 0x6a,
+	0x02, 0x93, 0x26, 0x01,
+	0x02, 0xfc, 0xb2, 0x7a,
+	0x40, 0x0d, 0xc6, 0x6a,
+	0x01, 0xa4, 0x48, 0x01,
+	0x00, 0x65, 0xc6, 0x42,
+	0x40, 0x0d, 0xb8, 0x6a,
+	0x00, 0x65, 0x0e, 0x5a,
+	0x00, 0x65, 0xaa, 0x42,
+	0x80, 0xfc, 0xc2, 0x7a,
+	0x80, 0xa4, 0xc2, 0x6a,
+	0xff, 0xa5, 0x4a, 0x19,
+	0xff, 0xa6, 0x4c, 0x21,
+	0xff, 0xa7, 0x4e, 0x21,
+	0xf8, 0xfc, 0x48, 0x09,
+	0x7f, 0xa3, 0x46, 0x09,
+	0x04, 0x3b, 0xe2, 0x6a,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0x94, 0xc8, 0x7a,
+	0x01, 0xa4, 0xe0, 0x7a,
+	0x01, 0xfc, 0xd6, 0x7a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x01, 0x94, 0xe2, 0x6a,
+	0x00, 0x65, 0x82, 0x42,
+	0x01, 0x94, 0xe0, 0x7a,
+	0x10, 0x94, 0xe2, 0x6a,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xe6, 0x6a,
+	0x01, 0x85, 0x0a, 0x01,
+	0x02, 0xfc, 0xee, 0x6a,
+	0x01, 0x14, 0x46, 0x31,
+	0xff, 0x6a, 0x10, 0x09,
+	0xfe, 0x85, 0x0a, 0x09,
+	0xff, 0x38, 0xfc, 0x6a,
+	0x80, 0xa3, 0xfc, 0x7a,
+	0x80, 0x0b, 0xfa, 0x7a,
+	0x04, 0x3b, 0xfc, 0x7a,
+	0xbf, 0x3b, 0x76, 0x08,
+	0x01, 0x3b, 0x26, 0x31,
+	0x00, 0x65, 0x0e, 0x5a,
+	0x01, 0x0b, 0x0a, 0x6b,
+	0x10, 0x0c, 0xfe, 0x7a,
+	0x04, 0x93, 0x08, 0x6b,
+	0x01, 0x94, 0x06, 0x7b,
+	0x10, 0x94, 0x08, 0x6b,
+	0xc7, 0x93, 0x26, 0x09,
+	0x01, 0x99, 0xd4, 0x30,
+	0x38, 0x93, 0x0c, 0x6b,
+	0xff, 0x08, 0x5a, 0x6b,
+	0xff, 0x09, 0x5a, 0x6b,
+	0xff, 0x0a, 0x5a, 0x6b,
+	0xff, 0x38, 0x28, 0x7b,
+	0x04, 0x14, 0x10, 0x31,
+	0x01, 0x38, 0x18, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xf4, 0x5d,
+	0x00, 0x38, 0xe0, 0x5d,
+	0xff, 0x6a, 0x70, 0x08,
+	0x00, 0x65, 0x54, 0x43,
+	0x80, 0xa3, 0x2e, 0x7b,
+	0x01, 0xa4, 0x48, 0x01,
+	0x00, 0x65, 0x5a, 0x43,
+	0x08, 0xeb, 0x34, 0x7b,
+	0x00, 0x65, 0x0e, 0x5a,
+	0x08, 0xeb, 0x30, 0x6b,
+	0x07, 0xe9, 0x10, 0x31,
+	0x01, 0xe9, 0xca, 0x30,
+	0x01, 0x65, 0x46, 0x31,
+	0x00, 0x6a, 0xba, 0x5e,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xa4, 0x6a, 0xf4, 0x5d,
+	0x08, 0x6a, 0xe0, 0x5d,
+	0x0d, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0xa8, 0x5e,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x8a, 0x5e,
+	0x01, 0x99, 0x46, 0x31,
+	0x00, 0xa3, 0xba, 0x5e,
+	0x01, 0x88, 0x10, 0x31,
+	0x00, 0x65, 0x3a, 0x5a,
+	0x00, 0x65, 0xfa, 0x59,
+	0x03, 0x8c, 0x10, 0x30,
+	0x00, 0x65, 0xe6, 0x5d,
+	0x80, 0x0b, 0x82, 0x6a,
+	0x80, 0x0b, 0x62, 0x6b,
+	0x01, 0x0c, 0x5c, 0x7b,
+	0x10, 0x0c, 0x82, 0x7a,
+	0x03, 0x9e, 0x82, 0x6a,
+	0x00, 0x65, 0x04, 0x5a,
+	0x00, 0x6a, 0xba, 0x5e,
+	0x01, 0xa4, 0x82, 0x6b,
+	0xff, 0x38, 0x78, 0x7b,
+	0x01, 0x38, 0xc8, 0x30,
+	0x00, 0x08, 0x40, 0x19,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x09, 0x42, 0x21,
+	0x00, 0x0a, 0x44, 0x21,
+	0xff, 0x6a, 0x70, 0x08,
+	0x00, 0x65, 0x7a, 0x43,
+	0x03, 0x08, 0x40, 0x31,
+	0x03, 0x08, 0x40, 0x31,
+	0x01, 0x08, 0x40, 0x31,
+	0x01, 0x09, 0x42, 0x31,
+	0x01, 0x0a, 0x44, 0x31,
+	0xfd, 0xb4, 0x68, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0x12, 0x01, 0x02, 0x00,
+	0x04, 0x3c, 0xcc, 0x79,
+	0xfb, 0x3c, 0x78, 0x08,
+	0x04, 0x93, 0x20, 0x79,
+	0x01, 0x0c, 0x8e, 0x6b,
+	0x80, 0xba, 0x20, 0x79,
+	0x80, 0x04, 0x20, 0x79,
+	0xe4, 0x6a, 0x6e, 0x5d,
+	0x23, 0x6a, 0x84, 0x5d,
+	0x01, 0x6a, 0x84, 0x5d,
+	0x00, 0x65, 0x20, 0x41,
+	0x00, 0x65, 0xcc, 0x41,
+	0x80, 0x3c, 0xa2, 0x7b,
+	0x21, 0x6a, 0xd8, 0x5e,
+	0x01, 0xbc, 0x18, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x02, 0x6a, 0xf8, 0x01,
+	0x01, 0xbc, 0x10, 0x30,
+	0x02, 0x6a, 0x12, 0x30,
+	0x01, 0xbc, 0x10, 0x30,
+	0xff, 0x6a, 0x12, 0x08,
+	0xff, 0x6a, 0x14, 0x08,
+	0xf3, 0xbc, 0xd4, 0x18,
+	0xa0, 0x6a, 0xc8, 0x53,
+	0x04, 0xa0, 0x10, 0x31,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0xa0, 0x10, 0x31,
+	0x03, 0x08, 0x18, 0x31,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xa0, 0x6a, 0xf4, 0x5d,
+	0x00, 0xbc, 0xe0, 0x5d,
+	0x3d, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0xe0, 0x43,
+	0xff, 0x6a, 0x10, 0x09,
+	0xa4, 0x6a, 0x26, 0x01,
+	0x0c, 0xa0, 0x32, 0x31,
+	0x05, 0x6a, 0x26, 0x01,
+	0x35, 0x6a, 0x26, 0x01,
+	0x0c, 0xa0, 0x32, 0x31,
+	0x36, 0x6a, 0x26, 0x01,
+	0x02, 0x93, 0x26, 0x01,
+	0x35, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0x9c, 0x5e,
+	0x00, 0x65, 0x9c, 0x5e,
+	0x02, 0x93, 0x26, 0x01,
+	0xbf, 0x3c, 0x78, 0x08,
+	0x04, 0x0b, 0xe6, 0x6b,
+	0x10, 0x0c, 0xe2, 0x7b,
+	0x01, 0x03, 0xe6, 0x6b,
+	0x20, 0x93, 0xe8, 0x6b,
+	0x04, 0x0b, 0xee, 0x6b,
+	0x40, 0x3c, 0x78, 0x00,
+	0xc7, 0x93, 0x26, 0x09,
+	0x38, 0x93, 0xf0, 0x6b,
+	0x00, 0x65, 0xcc, 0x41,
+	0x80, 0x3c, 0x56, 0x6c,
+	0x01, 0x06, 0x50, 0x31,
+	0x80, 0xb8, 0x70, 0x01,
+	0x00, 0x65, 0xcc, 0x41,
+	0x10, 0x3f, 0x06, 0x00,
+	0x10, 0x6a, 0x06, 0x00,
+	0x01, 0x3a, 0xca, 0x30,
+	0x80, 0x65, 0x1c, 0x64,
+	0x10, 0xb8, 0x40, 0x6c,
+	0xc0, 0x3e, 0xca, 0x00,
+	0x40, 0xb8, 0x0c, 0x6c,
+	0xbf, 0x65, 0xca, 0x08,
+	0x20, 0xb8, 0x20, 0x7c,
+	0x01, 0x65, 0x0c, 0x30,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0x28, 0x64,
+	0x23, 0xb8, 0x0c, 0x08,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0x28, 0x64,
+	0x00, 0xbb, 0x20, 0x44,
+	0xff, 0x65, 0x20, 0x64,
+	0x00, 0x65, 0x40, 0x44,
+	0x40, 0x6a, 0x18, 0x00,
+	0x01, 0x65, 0x0c, 0x30,
+	0x00, 0x65, 0xd8, 0x5d,
+	0xa0, 0x3f, 0xfc, 0x73,
+	0x40, 0x6a, 0x18, 0x00,
+	0x01, 0x3a, 0xa6, 0x30,
+	0x08, 0x6a, 0x74, 0x00,
+	0x00, 0x65, 0xcc, 0x41,
+	0x64, 0x6a, 0x68, 0x5d,
+	0x80, 0x64, 0xd8, 0x6c,
+	0x04, 0x64, 0x9a, 0x74,
+	0x02, 0x64, 0xaa, 0x74,
+	0x00, 0x6a, 0x60, 0x74,
+	0x03, 0x64, 0xc8, 0x74,
+	0x23, 0x64, 0x48, 0x74,
+	0x08, 0x64, 0x5c, 0x74,
+	0x61, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0xd8, 0x5d,
+	0x08, 0x51, 0xce, 0x71,
+	0x00, 0x65, 0x40, 0x44,
+	0x80, 0x04, 0x5a, 0x7c,
+	0x51, 0x6a, 0x5e, 0x5d,
+	0x01, 0x51, 0x5a, 0x64,
+	0x01, 0xa4, 0x52, 0x7c,
+	0x80, 0xba, 0x5c, 0x6c,
+	0x41, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
+	0x21, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
+	0x07, 0x6a, 0x54, 0x5d,
+	0x01, 0x06, 0xd4, 0x30,
+	0x00, 0x65, 0xcc, 0x41,
+	0x80, 0xb8, 0x56, 0x7c,
+	0xc0, 0x3c, 0x6a, 0x7c,
+	0x80, 0x3c, 0x56, 0x6c,
+	0xff, 0xa8, 0x6a, 0x6c,
+	0x40, 0x3c, 0x56, 0x6c,
+	0x10, 0xb8, 0x6e, 0x7c,
+	0xa1, 0x6a, 0xd8, 0x5e,
+	0x01, 0xb4, 0x74, 0x6c,
+	0x02, 0xb4, 0x76, 0x6c,
+	0x01, 0xa4, 0x76, 0x7c,
+	0xff, 0xa8, 0x86, 0x7c,
+	0x04, 0xb4, 0x68, 0x01,
+	0x01, 0x6a, 0x76, 0x00,
+	0x00, 0xbb, 0x12, 0x5e,
+	0xff, 0xa8, 0x86, 0x7c,
+	0x71, 0x6a, 0xd8, 0x5e,
+	0x40, 0x51, 0x86, 0x64,
+	0x00, 0x65, 0xb2, 0x5e,
+	0x00, 0x65, 0xde, 0x41,
+	0x00, 0xbb, 0x8a, 0x5c,
+	0x00, 0x65, 0xde, 0x41,
+	0x00, 0x65, 0xb2, 0x5e,
+	0x01, 0x65, 0xa2, 0x30,
+	0x01, 0xf8, 0xc8, 0x30,
+	0x01, 0x4e, 0xc8, 0x30,
+	0x00, 0x6a, 0xb6, 0xdd,
+	0x00, 0x51, 0xc8, 0x5d,
+	0x01, 0x4e, 0x9c, 0x18,
+	0x02, 0x6a, 0x22, 0x05,
+	0xc0, 0x3c, 0x56, 0x6c,
+	0x04, 0xb8, 0x70, 0x01,
+	0x00, 0x65, 0xd4, 0x5e,
+	0x20, 0xb8, 0xde, 0x69,
+	0x01, 0xbb, 0xa2, 0x30,
+	0x3f, 0xba, 0x7c, 0x08,
+	0x00, 0xb9, 0xce, 0x5c,
+	0x00, 0x65, 0xde, 0x41,
+	0x01, 0x06, 0xd4, 0x30,
+	0x20, 0x3c, 0xcc, 0x79,
+	0x20, 0x3c, 0x5c, 0x7c,
+	0x01, 0xa4, 0xb8, 0x7c,
+	0x01, 0xb4, 0x68, 0x01,
+	0x00, 0x65, 0xcc, 0x41,
+	0x00, 0x65, 0x5c, 0x44,
+	0x04, 0x14, 0x58, 0x31,
+	0x01, 0x06, 0xd4, 0x30,
+	0x08, 0xa0, 0x60, 0x31,
+	0xac, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xf4, 0x5d,
+	0x01, 0x06, 0xd4, 0x30,
+	0xa0, 0x6a, 0xec, 0x5d,
+	0x00, 0x65, 0xcc, 0x41,
+	0xdf, 0x3c, 0x78, 0x08,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0x5c, 0x44,
+	0x4c, 0x65, 0xcc, 0x28,
+	0x01, 0x3e, 0x20, 0x31,
+	0xd0, 0x66, 0xcc, 0x18,
+	0x20, 0x66, 0xcc, 0x18,
+	0x01, 0x51, 0xda, 0x34,
+	0x4c, 0x3d, 0xca, 0x28,
+	0x3f, 0x64, 0x7c, 0x08,
+	0xd0, 0x65, 0xca, 0x18,
+	0x01, 0x3e, 0x20, 0x31,
+	0x30, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xe6, 0x4c,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x20, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xee, 0x54,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x20, 0x65, 0xca, 0x18,
+	0xe0, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0xf8, 0x4c,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xd0, 0x65, 0xd4, 0x18,
+	0x00, 0x65, 0x00, 0x55,
+	0xe1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x01, 0x6c, 0xa2, 0x30,
+	0xff, 0x51, 0x12, 0x75,
+	0x00, 0x51, 0x8e, 0x5d,
+	0x01, 0x51, 0x20, 0x31,
+	0x00, 0x65, 0x34, 0x45,
+	0x3f, 0xba, 0xc8, 0x08,
+	0x00, 0x3e, 0x34, 0x75,
+	0x00, 0x65, 0xb0, 0x5e,
+	0x80, 0x3c, 0x78, 0x00,
+	0x01, 0x06, 0xd4, 0x30,
+	0x00, 0x65, 0xd8, 0x5d,
+	0x01, 0x3c, 0x78, 0x00,
+	0xe0, 0x3f, 0x50, 0x65,
+	0x02, 0x3c, 0x78, 0x00,
+	0x20, 0x12, 0x50, 0x65,
+	0x51, 0x6a, 0x5e, 0x5d,
+	0x00, 0x51, 0x8e, 0x5d,
+	0x51, 0x6a, 0x5e, 0x5d,
+	0x01, 0x51, 0x20, 0x31,
+	0x04, 0x3c, 0x78, 0x00,
+	0x01, 0xb9, 0xc8, 0x30,
+	0x00, 0x3d, 0x4e, 0x65,
+	0x08, 0x3c, 0x78, 0x00,
+	0x3f, 0xba, 0xc8, 0x08,
+	0x00, 0x3e, 0x4e, 0x65,
+	0x10, 0x3c, 0x78, 0x00,
+	0x04, 0xb8, 0x4e, 0x7d,
+	0xfb, 0xb8, 0x70, 0x09,
+	0x20, 0xb8, 0x44, 0x6d,
+	0x01, 0x90, 0xc8, 0x30,
+	0xff, 0x6a, 0xa2, 0x00,
+	0x00, 0x3d, 0xce, 0x5c,
+	0x01, 0x64, 0x20, 0x31,
+	0xff, 0x6a, 0x78, 0x08,
+	0x00, 0x65, 0xea, 0x58,
+	0x10, 0xb8, 0x5c, 0x7c,
+	0xff, 0x6a, 0x54, 0x5d,
+	0x00, 0x65, 0x5c, 0x44,
+	0x00, 0x65, 0xb0, 0x5e,
+	0x31, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x5c, 0x44,
+	0x10, 0x3f, 0x06, 0x00,
+	0x10, 0x6a, 0x06, 0x00,
+	0x01, 0x65, 0x74, 0x34,
+	0x81, 0x6a, 0xd8, 0x5e,
+	0x00, 0x65, 0x60, 0x45,
+	0x01, 0x06, 0xd4, 0x30,
+	0x01, 0x0c, 0x60, 0x7d,
+	0x04, 0x0c, 0x5a, 0x6d,
+	0xe0, 0x03, 0x7e, 0x08,
+	0xe0, 0x3f, 0xcc, 0x61,
+	0x01, 0x65, 0xcc, 0x30,
+	0x01, 0x12, 0xda, 0x34,
+	0x01, 0x06, 0xd4, 0x34,
+	0x01, 0x03, 0x6e, 0x6d,
+	0x40, 0x03, 0xcc, 0x08,
+	0x01, 0x65, 0x06, 0x30,
+	0x40, 0x65, 0xc8, 0x08,
+	0x00, 0x66, 0x7c, 0x75,
+	0x40, 0x65, 0x7c, 0x7d,
+	0x00, 0x65, 0x7c, 0x5d,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x08, 0x01, 0x02, 0x00,
+	0x02, 0x0b, 0x86, 0x7d,
+	0x01, 0x65, 0x0c, 0x30,
+	0x02, 0x0b, 0x8a, 0x7d,
+	0xf7, 0x01, 0x02, 0x0c,
+	0x01, 0x65, 0xc8, 0x30,
+	0xff, 0x41, 0xae, 0x75,
+	0x01, 0x41, 0x20, 0x31,
+	0xff, 0x6a, 0xa4, 0x00,
+	0x00, 0x65, 0x9e, 0x45,
+	0xff, 0xbf, 0xae, 0x75,
+	0x01, 0x90, 0xa4, 0x30,
+	0x01, 0xbf, 0x20, 0x31,
+	0x00, 0xbb, 0x98, 0x65,
+	0xff, 0x52, 0xac, 0x75,
+	0x01, 0xbf, 0xcc, 0x30,
+	0x01, 0x90, 0xca, 0x30,
+	0x01, 0x52, 0x20, 0x31,
+	0x01, 0x66, 0x7e, 0x31,
+	0x01, 0x65, 0x20, 0x35,
+	0x01, 0xbf, 0x82, 0x34,
+	0x01, 0x64, 0xa2, 0x30,
+	0x00, 0x6a, 0xc0, 0x5e,
+	0x0d, 0x6a, 0x76, 0x00,
+	0x00, 0x51, 0x12, 0x46,
+	0x01, 0x65, 0xa4, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0x06, 0x5e,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x05,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x48, 0x6a, 0x06, 0x5e,
+	0x01, 0x6a, 0xe0, 0x5d,
+	0x01, 0x6a, 0x26, 0x05,
+	0x01, 0x65, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xcc, 0x7d,
+	0xff, 0x6a, 0xdc, 0x0d,
+	0x01, 0x65, 0x32, 0x31,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0xa8, 0x46,
+	0x81, 0x6a, 0xd8, 0x5e,
+	0x01, 0x0c, 0xd8, 0x7d,
+	0x04, 0x0c, 0xd6, 0x6d,
+	0xe0, 0x03, 0x06, 0x08,
+	0xe0, 0x03, 0x7e, 0x0c,
+	0x01, 0x65, 0x18, 0x31,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x0d,
+	0x01, 0x8c, 0x10, 0x30,
+	0x01, 0x8d, 0x12, 0x30,
+	0x01, 0x8e, 0x14, 0x34,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x30,
+	0x01, 0x6c, 0xda, 0x34,
+	0x3d, 0x64, 0xa4, 0x28,
+	0x55, 0x64, 0xc8, 0x28,
+	0x00, 0x65, 0x06, 0x46,
+	0x2e, 0x64, 0xa4, 0x28,
+	0x66, 0x64, 0xc8, 0x28,
+	0x00, 0x6c, 0xda, 0x18,
+	0x01, 0x52, 0xc8, 0x30,
+	0x00, 0x6c, 0xda, 0x20,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0x00, 0x6c, 0xda, 0x24,
+	0x01, 0x65, 0xc8, 0x30,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x44, 0x6a, 0x02, 0x5e,
+	0x01, 0x90, 0xe2, 0x31,
+	0x04, 0x3b, 0x26, 0x7e,
+	0x30, 0x6a, 0xd0, 0x01,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x1d, 0x6a, 0xdc, 0x01,
+	0xdc, 0xee, 0x22, 0x66,
+	0x00, 0x65, 0x3e, 0x46,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x20, 0xa0, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0x2e, 0x7e,
+	0x11, 0x6a, 0xdc, 0x01,
+	0x50, 0xee, 0x32, 0x66,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xdc, 0x01,
+	0x88, 0xee, 0x38, 0x66,
+	0x19, 0x6a, 0xdc, 0x01,
+	0xd8, 0xee, 0x3c, 0x66,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x18, 0xee, 0x40, 0x6e,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x44, 0x6a, 0x02, 0x5e,
+	0x20, 0x6a, 0xe0, 0x5d,
+	0x01, 0x3b, 0x26, 0x31,
+	0x04, 0x3b, 0x5a, 0x6e,
+	0xa0, 0x6a, 0xca, 0x00,
+	0x20, 0x65, 0xc8, 0x18,
+	0x00, 0x65, 0x98, 0x5e,
+	0x00, 0x65, 0x52, 0x66,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0xa8, 0x46,
+	0xa0, 0x6a, 0xcc, 0x00,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x20, 0x94, 0x5e, 0x6e,
+	0x10, 0x94, 0x60, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
+	0x08, 0x94, 0x7a, 0x6e,
+	0xff, 0x8c, 0xc8, 0x10,
+	0xc1, 0x64, 0xc8, 0x18,
+	0xf8, 0x64, 0xc8, 0x08,
+	0x01, 0x99, 0xda, 0x30,
+	0x00, 0x66, 0x6e, 0x66,
+	0xc0, 0x66, 0xaa, 0x76,
+	0x60, 0x66, 0xc8, 0x18,
+	0x3d, 0x64, 0xc8, 0x28,
+	0x00, 0x65, 0x5e, 0x46,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x7c, 0x6e,
+	0x00, 0x62, 0xc4, 0x18,
+	0x00, 0x65, 0xa8, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
+	0x00, 0x65, 0x88, 0x5e,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x30,
+	0x01, 0x99, 0xda, 0x34,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x31,
+	0x01, 0x6c, 0x32, 0x35,
+	0x08, 0x94, 0xa8, 0x7e,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0xac, 0x6e,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x04, 0xb8, 0xd4, 0x6e,
+	0x01, 0x42, 0x7e, 0x31,
+	0xff, 0x6a, 0x76, 0x01,
+	0x01, 0x90, 0x84, 0x34,
+	0xff, 0x6a, 0x76, 0x05,
+	0x01, 0x85, 0x0a, 0x01,
+	0x7f, 0x65, 0x10, 0x09,
+	0xfe, 0x85, 0x0a, 0x0d,
+	0xff, 0x42, 0xd0, 0x66,
+	0xff, 0x41, 0xc8, 0x66,
+	0xd1, 0x6a, 0xd8, 0x5e,
+	0xff, 0x6a, 0xca, 0x04,
+	0x01, 0x41, 0x20, 0x31,
+	0x01, 0xbf, 0x82, 0x30,
+	0x01, 0x6a, 0x76, 0x00,
+	0x00, 0xbb, 0x12, 0x46,
+	0x01, 0x42, 0x20, 0x31,
+	0x01, 0xbf, 0x84, 0x34,
+	0x01, 0x41, 0x7e, 0x31,
+	0x01, 0x90, 0x82, 0x34,
+	0x01, 0x65, 0x22, 0x31,
+	0xff, 0x6a, 0xd4, 0x08,
+	0xff, 0x6a, 0xd4, 0x0c
+};
+
+typedef int ahc_patch_func_t (struct ahc_softc *ahc);
+static ahc_patch_func_t ahc_patch23_func;
+
+static int
+ahc_patch23_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_SCBCHAN_UPLOAD_BUG) != 0);
+}
+
+static ahc_patch_func_t ahc_patch22_func;
+
+static int
+ahc_patch22_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_CMD_CHAN) == 0);
+}
+
+static ahc_patch_func_t ahc_patch21_func;
+
+static int
+ahc_patch21_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_QUEUE_REGS) == 0);
+}
+
+static ahc_patch_func_t ahc_patch20_func;
+
+static int
+ahc_patch20_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_WIDE) != 0);
+}
+
+static ahc_patch_func_t ahc_patch19_func;
+
+static int
+ahc_patch19_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_SCB_BTT) != 0);
+}
+
+static ahc_patch_func_t ahc_patch18_func;
+
+static int
+ahc_patch18_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_PCI_2_1_RETRY_BUG) != 0);
+}
+
+static ahc_patch_func_t ahc_patch17_func;
+
+static int
+ahc_patch17_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_TMODE_WIDEODD_BUG) != 0);
+}
+
+static ahc_patch_func_t ahc_patch16_func;
+
+static int
+ahc_patch16_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_AUTOFLUSH_BUG) != 0);
+}
+
+static ahc_patch_func_t ahc_patch15_func;
+
+static int
+ahc_patch15_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA2) == 0);
+}
+
+static ahc_patch_func_t ahc_patch14_func;
+
+static int
+ahc_patch14_func(struct ahc_softc *ahc)
+{
+	return ((ahc->bugs & AHC_PCI_MWI_BUG) != 0 && ahc->pci_cachesize != 0);
+}
+
+static ahc_patch_func_t ahc_patch13_func;
+
+static int
+ahc_patch13_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_39BIT_ADDRESSING) != 0);
+}
+
+static ahc_patch_func_t ahc_patch12_func;
+
+static int
+ahc_patch12_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_HS_MAILBOX) != 0);
+}
+
+static ahc_patch_func_t ahc_patch11_func;
+
+static int
+ahc_patch11_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA) != 0);
+}
+
+static ahc_patch_func_t ahc_patch10_func;
+
+static int
+ahc_patch10_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_MULTI_TID) != 0);
+}
+
+static ahc_patch_func_t ahc_patch9_func;
+
+static int
+ahc_patch9_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_CMD_CHAN) != 0);
+}
+
+static ahc_patch_func_t ahc_patch8_func;
+
+static int
+ahc_patch8_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_INITIATORROLE) != 0);
+}
+
+static ahc_patch_func_t ahc_patch7_func;
+
+static int
+ahc_patch7_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_TARGETROLE) != 0);
+}
+
+static ahc_patch_func_t ahc_patch6_func;
+
+static int
+ahc_patch6_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_DT) == 0);
+}
+
+static ahc_patch_func_t ahc_patch5_func;
+
+static int
+ahc_patch5_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0);
+}
+
+static ahc_patch_func_t ahc_patch4_func;
+
+static int
+ahc_patch4_func(struct ahc_softc *ahc)
+{
+	return ((ahc->flags & AHC_PAGESCBS) != 0);
+}
+
+static ahc_patch_func_t ahc_patch3_func;
+
+static int
+ahc_patch3_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_QUEUE_REGS) != 0);
+}
+
+static ahc_patch_func_t ahc_patch2_func;
+
+static int
+ahc_patch2_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_TWIN) != 0);
+}
+
+static ahc_patch_func_t ahc_patch1_func;
+
+static int
+ahc_patch1_func(struct ahc_softc *ahc)
+{
+	return ((ahc->features & AHC_ULTRA2) != 0);
+}
+
+static ahc_patch_func_t ahc_patch0_func;
+
+static int
+ahc_patch0_func(struct ahc_softc *ahc)
+{
+	return (0);
+}
+
+static struct patch {
+	ahc_patch_func_t		*patch_func;
+	uint32_t		 begin		:10,
+				 skip_instr	:10,
+				 skip_patch	:12;
+} patches[] = {
+	{ ahc_patch1_func, 4, 1, 1 },
+	{ ahc_patch2_func, 6, 2, 1 },
+	{ ahc_patch2_func, 9, 1, 1 },
+	{ ahc_patch3_func, 11, 1, 2 },
+	{ ahc_patch0_func, 12, 2, 1 },
+	{ ahc_patch4_func, 15, 1, 2 },
+	{ ahc_patch0_func, 16, 1, 1 },
+	{ ahc_patch5_func, 22, 2, 1 },
+	{ ahc_patch3_func, 27, 1, 2 },
+	{ ahc_patch0_func, 28, 1, 1 },
+	{ ahc_patch6_func, 34, 1, 1 },
+	{ ahc_patch7_func, 37, 54, 19 },
+	{ ahc_patch8_func, 37, 1, 1 },
+	{ ahc_patch9_func, 42, 3, 2 },
+	{ ahc_patch0_func, 45, 3, 1 },
+	{ ahc_patch10_func, 49, 1, 2 },
+	{ ahc_patch0_func, 50, 2, 3 },
+	{ ahc_patch1_func, 50, 1, 2 },
+	{ ahc_patch0_func, 51, 1, 1 },
+	{ ahc_patch2_func, 53, 2, 1 },
+	{ ahc_patch9_func, 55, 1, 2 },
+	{ ahc_patch0_func, 56, 1, 1 },
+	{ ahc_patch9_func, 60, 1, 2 },
+	{ ahc_patch0_func, 61, 1, 1 },
+	{ ahc_patch9_func, 71, 1, 2 },
+	{ ahc_patch0_func, 72, 1, 1 },
+	{ ahc_patch9_func, 75, 1, 2 },
+	{ ahc_patch0_func, 76, 1, 1 },
+	{ ahc_patch9_func, 79, 1, 2 },
+	{ ahc_patch0_func, 80, 1, 1 },
+	{ ahc_patch8_func, 91, 9, 4 },
+	{ ahc_patch1_func, 93, 1, 2 },
+	{ ahc_patch0_func, 94, 1, 1 },
+	{ ahc_patch2_func, 96, 2, 1 },
+	{ ahc_patch2_func, 105, 4, 1 },
+	{ ahc_patch1_func, 109, 1, 2 },
+	{ ahc_patch0_func, 110, 2, 3 },
+	{ ahc_patch2_func, 110, 1, 2 },
+	{ ahc_patch0_func, 111, 1, 1 },
+	{ ahc_patch7_func, 112, 4, 2 },
+	{ ahc_patch0_func, 116, 1, 1 },
+	{ ahc_patch11_func, 117, 2, 1 },
+	{ ahc_patch1_func, 119, 1, 2 },
+	{ ahc_patch0_func, 120, 1, 1 },
+	{ ahc_patch7_func, 121, 4, 1 },
+	{ ahc_patch7_func, 131, 95, 11 },
+	{ ahc_patch4_func, 151, 1, 1 },
+	{ ahc_patch1_func, 168, 1, 1 },
+	{ ahc_patch12_func, 173, 1, 2 },
+	{ ahc_patch0_func, 174, 1, 1 },
+	{ ahc_patch9_func, 185, 1, 2 },
+	{ ahc_patch0_func, 186, 1, 1 },
+	{ ahc_patch9_func, 195, 1, 2 },
+	{ ahc_patch0_func, 196, 1, 1 },
+	{ ahc_patch9_func, 212, 6, 2 },
+	{ ahc_patch0_func, 218, 6, 1 },
+	{ ahc_patch8_func, 226, 20, 2 },
+	{ ahc_patch1_func, 241, 1, 1 },
+	{ ahc_patch1_func, 248, 1, 2 },
+	{ ahc_patch0_func, 249, 2, 2 },
+	{ ahc_patch11_func, 250, 1, 1 },
+	{ ahc_patch9_func, 258, 27, 3 },
+	{ ahc_patch1_func, 274, 10, 2 },
+	{ ahc_patch13_func, 277, 1, 1 },
+	{ ahc_patch14_func, 285, 14, 1 },
+	{ ahc_patch1_func, 301, 1, 2 },
+	{ ahc_patch0_func, 302, 1, 1 },
+	{ ahc_patch9_func, 305, 1, 1 },
+	{ ahc_patch13_func, 310, 1, 1 },
+	{ ahc_patch9_func, 311, 2, 2 },
+	{ ahc_patch0_func, 313, 4, 1 },
+	{ ahc_patch14_func, 317, 1, 1 },
+	{ ahc_patch15_func, 319, 2, 3 },
+	{ ahc_patch9_func, 319, 1, 2 },
+	{ ahc_patch0_func, 320, 1, 1 },
+	{ ahc_patch6_func, 325, 1, 2 },
+	{ ahc_patch0_func, 326, 1, 1 },
+	{ ahc_patch1_func, 330, 47, 11 },
+	{ ahc_patch6_func, 337, 2, 4 },
+	{ ahc_patch7_func, 337, 1, 1 },
+	{ ahc_patch8_func, 338, 1, 1 },
+	{ ahc_patch0_func, 339, 1, 1 },
+	{ ahc_patch16_func, 340, 1, 1 },
+	{ ahc_patch6_func, 356, 6, 3 },
+	{ ahc_patch16_func, 356, 5, 1 },
+	{ ahc_patch0_func, 362, 7, 1 },
+	{ ahc_patch13_func, 372, 5, 1 },
+	{ ahc_patch0_func, 377, 52, 17 },
+	{ ahc_patch14_func, 377, 1, 1 },
+	{ ahc_patch7_func, 379, 2, 2 },
+	{ ahc_patch17_func, 380, 1, 1 },
+	{ ahc_patch9_func, 383, 1, 1 },
+	{ ahc_patch18_func, 390, 1, 1 },
+	{ ahc_patch14_func, 395, 9, 3 },
+	{ ahc_patch9_func, 396, 3, 2 },
+	{ ahc_patch0_func, 399, 3, 1 },
+	{ ahc_patch9_func, 407, 6, 2 },
+	{ ahc_patch0_func, 413, 9, 2 },
+	{ ahc_patch13_func, 413, 1, 1 },
+	{ ahc_patch13_func, 422, 2, 1 },
+	{ ahc_patch14_func, 424, 1, 1 },
+	{ ahc_patch9_func, 426, 1, 2 },
+	{ ahc_patch0_func, 427, 1, 1 },
+	{ ahc_patch7_func, 428, 1, 1 },
+	{ ahc_patch7_func, 429, 1, 1 },
+	{ ahc_patch8_func, 430, 3, 3 },
+	{ ahc_patch6_func, 431, 1, 2 },
+	{ ahc_patch0_func, 432, 1, 1 },
+	{ ahc_patch9_func, 433, 1, 1 },
+	{ ahc_patch15_func, 434, 1, 2 },
+	{ ahc_patch13_func, 434, 1, 1 },
+	{ ahc_patch14_func, 436, 9, 4 },
+	{ ahc_patch9_func, 436, 1, 1 },
+	{ ahc_patch9_func, 443, 2, 1 },
+	{ ahc_patch0_func, 445, 4, 3 },
+	{ ahc_patch9_func, 445, 1, 2 },
+	{ ahc_patch0_func, 446, 3, 1 },
+	{ ahc_patch1_func, 450, 2, 1 },
+	{ ahc_patch7_func, 452, 10, 2 },
+	{ ahc_patch0_func, 462, 1, 1 },
+	{ ahc_patch8_func, 463, 118, 22 },
+	{ ahc_patch1_func, 465, 3, 2 },
+	{ ahc_patch0_func, 468, 5, 3 },
+	{ ahc_patch9_func, 468, 2, 2 },
+	{ ahc_patch0_func, 470, 3, 1 },
+	{ ahc_patch1_func, 475, 2, 2 },
+	{ ahc_patch0_func, 477, 6, 3 },
+	{ ahc_patch9_func, 477, 2, 2 },
+	{ ahc_patch0_func, 479, 3, 1 },
+	{ ahc_patch1_func, 485, 2, 2 },
+	{ ahc_patch0_func, 487, 9, 7 },
+	{ ahc_patch9_func, 487, 5, 6 },
+	{ ahc_patch19_func, 487, 1, 2 },
+	{ ahc_patch0_func, 488, 1, 1 },
+	{ ahc_patch19_func, 490, 1, 2 },
+	{ ahc_patch0_func, 491, 1, 1 },
+	{ ahc_patch0_func, 492, 4, 1 },
+	{ ahc_patch6_func, 497, 3, 2 },
+	{ ahc_patch0_func, 500, 1, 1 },
+	{ ahc_patch6_func, 510, 1, 2 },
+	{ ahc_patch0_func, 511, 1, 1 },
+	{ ahc_patch20_func, 548, 7, 1 },
+	{ ahc_patch3_func, 583, 1, 2 },
+	{ ahc_patch0_func, 584, 1, 1 },
+	{ ahc_patch21_func, 587, 1, 1 },
+	{ ahc_patch8_func, 589, 106, 33 },
+	{ ahc_patch4_func, 591, 1, 1 },
+	{ ahc_patch1_func, 597, 2, 2 },
+	{ ahc_patch0_func, 599, 1, 1 },
+	{ ahc_patch1_func, 602, 1, 2 },
+	{ ahc_patch0_func, 603, 1, 1 },
+	{ ahc_patch9_func, 604, 3, 3 },
+	{ ahc_patch15_func, 605, 1, 1 },
+	{ ahc_patch0_func, 607, 4, 1 },
+	{ ahc_patch19_func, 616, 2, 2 },
+	{ ahc_patch0_func, 618, 1, 1 },
+	{ ahc_patch19_func, 622, 10, 3 },
+	{ ahc_patch5_func, 624, 8, 1 },
+	{ ahc_patch0_func, 632, 9, 2 },
+	{ ahc_patch5_func, 633, 8, 1 },
+	{ ahc_patch4_func, 643, 1, 2 },
+	{ ahc_patch0_func, 644, 1, 1 },
+	{ ahc_patch19_func, 645, 1, 2 },
+	{ ahc_patch0_func, 646, 3, 2 },
+	{ ahc_patch4_func, 648, 1, 1 },
+	{ ahc_patch5_func, 649, 1, 1 },
+	{ ahc_patch5_func, 652, 1, 1 },
+	{ ahc_patch5_func, 654, 1, 1 },
+	{ ahc_patch4_func, 656, 2, 2 },
+	{ ahc_patch0_func, 658, 2, 1 },
+	{ ahc_patch5_func, 660, 1, 1 },
+	{ ahc_patch5_func, 663, 1, 1 },
+	{ ahc_patch5_func, 666, 1, 1 },
+	{ ahc_patch19_func, 670, 1, 1 },
+	{ ahc_patch19_func, 673, 1, 1 },
+	{ ahc_patch4_func, 679, 1, 1 },
+	{ ahc_patch6_func, 682, 1, 2 },
+	{ ahc_patch0_func, 683, 1, 1 },
+	{ ahc_patch7_func, 695, 16, 1 },
+	{ ahc_patch4_func, 711, 20, 1 },
+	{ ahc_patch9_func, 732, 4, 2 },
+	{ ahc_patch0_func, 736, 4, 1 },
+	{ ahc_patch9_func, 740, 4, 2 },
+	{ ahc_patch0_func, 744, 3, 1 },
+	{ ahc_patch6_func, 750, 1, 1 },
+	{ ahc_patch22_func, 752, 14, 1 },
+	{ ahc_patch7_func, 766, 3, 1 },
+	{ ahc_patch9_func, 778, 24, 8 },
+	{ ahc_patch19_func, 782, 1, 2 },
+	{ ahc_patch0_func, 783, 1, 1 },
+	{ ahc_patch15_func, 788, 4, 2 },
+	{ ahc_patch0_func, 792, 7, 3 },
+	{ ahc_patch23_func, 792, 5, 2 },
+	{ ahc_patch0_func, 797, 2, 1 },
+	{ ahc_patch0_func, 802, 42, 3 },
+	{ ahc_patch18_func, 814, 18, 2 },
+	{ ahc_patch0_func, 832, 1, 1 },
+	{ ahc_patch4_func, 856, 1, 1 },
+	{ ahc_patch4_func, 857, 3, 2 },
+	{ ahc_patch0_func, 860, 1, 1 },
+	{ ahc_patch13_func, 861, 3, 1 },
+	{ ahc_patch4_func, 864, 12, 1 }
+};
+
+static struct cs {
+	uint16_t	begin;
+	uint16_t	end;
+} critical_sections[] = {
+	{ 11, 18 },
+	{ 21, 30 },
+	{ 711, 727 },
+	{ 857, 860 },
+	{ 864, 870 },
+	{ 872, 874 },
+	{ 874, 876 }
+};
+
+static const int num_critical_sections = sizeof(critical_sections)
+				       / sizeof(*critical_sections);
diff --git a/drivers/scsi/aic7xxx/aicasm/Makefile b/drivers/scsi/aic7xxx/aicasm/Makefile
new file mode 100644
index 0000000..8c91fda
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/Makefile
@@ -0,0 +1,78 @@
+PROG=	aicasm
+
+.SUFFIXES= .l .y .c .h
+
+CSRCS=	aicasm.c aicasm_symbol.c
+YSRCS=	aicasm_gram.y aicasm_macro_gram.y
+LSRCS=	aicasm_scan.l aicasm_macro_scan.l
+
+GENHDRS=	aicdb.h $(YSRCS:.y=.h)
+GENSRCS=	$(YSRCS:.y=.c) $(LSRCS:.l=.c)
+
+SRCS=	${CSRCS} ${GENSRCS}
+LIBS=	-ldb
+clean-files:= ${GENSRCS} ${GENHDRS} $(YSRCS:.y=.output) $(PROG)
+# Override default kernel CFLAGS.  This is a userland app.
+AICASM_CFLAGS:= -I/usr/include -I.
+YFLAGS= -d
+
+NOMAN=	noman
+
+ifneq ($(HOSTCC),)
+AICASM_CC= $(HOSTCC)
+else
+AICASM_CC= $(CC)
+endif
+
+ifdef DEBUG
+CFLAGS+= -DDEBUG -g
+YFLAGS+= -t -v
+LFLAGS= -d
+endif
+
+$(PROG):  ${GENHDRS} $(SRCS)
+	$(AICASM_CC) $(AICASM_CFLAGS) $(SRCS) -o $(PROG) $(LIBS)
+
+aicdb.h:
+	@if [ -e "/usr/include/db4/db_185.h" ]; then		\
+		echo "#include <db4/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db3/db_185.h" ]; then		\
+		echo "#include <db3/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db2/db_185.h" ]; then		\
+		echo "#include <db2/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db1/db_185.h" ]; then		\
+		echo "#include <db1/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db/db_185.h" ]; then		\
+		echo "#include <db/db_185.h>" > aicdb.h;	\
+	 elif [ -e "/usr/include/db_185.h" ]; then		\
+		echo "#include <db_185.h>" > aicdb.h;		\
+	 else							\
+		echo "*** Install db development libraries";	\
+	 fi
+
+clean:
+	rm -f $(clean-files)
+
+# Create a dependency chain in generated files
+# to avoid concurrent invocations of the single
+# rule that builds them all.
+aicasm_gram.c: aicasm_gram.h
+aicasm_gram.c aicasm_gram.h: aicasm_gram.y
+	$(YACC) $(YFLAGS) -b $(<:.y=) $<
+	mv $(<:.y=).tab.c $(<:.y=.c)
+	mv $(<:.y=).tab.h $(<:.y=.h)
+
+# Create a dependency chain in generated files
+# to avoid concurrent invocations of the single
+# rule that builds them all.
+aicasm_macro_gram.c: aicasm_macro_gram.h
+aicasm_macro_gram.c aicasm_macro_gram.h: aicasm_macro_gram.y
+	$(YACC) $(YFLAGS) -b $(<:.y=) -p mm $<
+	mv $(<:.y=).tab.c $(<:.y=.c)
+	mv $(<:.y=).tab.h $(<:.y=.h)
+
+aicasm_scan.c: aicasm_scan.l
+	$(LEX) $(LFLAGS) -o$@ $<
+
+aicasm_macro_scan.c: aicasm_macro_scan.l
+	$(LEX) $(LFLAGS) -Pmm -o$@ $<
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.c b/drivers/scsi/aic7xxx/aicasm/aicasm.c
new file mode 100644
index 0000000..c346394
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm.c
@@ -0,0 +1,835 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler
+ *
+ * Copyright (c) 1997, 1998, 2000, 2001 Justin T. Gibbs.
+ * Copyright (c) 2001, 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.c#22 $
+ *
+ * $FreeBSD$
+ */
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#include <ctype.h>
+#include <inttypes.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+#include <unistd.h>
+
+#if linux
+#include <endian.h>
+#else
+#include <machine/endian.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_insformat.h"
+
+typedef struct patch {
+	STAILQ_ENTRY(patch) links;
+	int		patch_func;
+	u_int		begin;
+	u_int		skip_instr;
+	u_int		skip_patch;
+} patch_t;
+
+STAILQ_HEAD(patch_list, patch) patches;
+
+static void usage(void);
+static void back_patch(void);
+static void output_code(void);
+static void output_listing(char *ifilename);
+static void dump_scope(scope_t *scope);
+static void emit_patch(scope_t *scope, int patch);
+static int check_patch(patch_t **start_patch, int start_instr,
+		       int *skip_addr, int *func_vals);
+
+struct path_list search_path;
+int includes_search_curdir;
+char *appname;
+char *stock_include_file;
+FILE *ofile;
+char *ofilename;
+char *regfilename;
+FILE *regfile;
+char *listfilename;
+FILE *listfile;
+char *regdiagfilename;
+FILE *regdiagfile;
+int   src_mode;
+int   dst_mode;
+
+static STAILQ_HEAD(,instruction) seq_program;
+struct cs_tailq cs_tailq;
+struct scope_list scope_stack;
+symlist_t patch_functions;
+
+#if DEBUG
+extern int yy_flex_debug;
+extern int mm_flex_debug;
+extern int yydebug;
+extern int mmdebug;
+#endif
+extern FILE *yyin;
+extern int yyparse(void);
+
+int main(int argc, char *argv[]);
+
+int
+main(int argc, char *argv[])
+{
+	extern char *optarg;
+	extern int optind;
+	int  ch;
+	int  retval;
+	char *inputfilename;
+	scope_t *sentinal;
+
+	STAILQ_INIT(&patches);
+	SLIST_INIT(&search_path);
+	STAILQ_INIT(&seq_program);
+	TAILQ_INIT(&cs_tailq);
+	SLIST_INIT(&scope_stack);
+
+	/* Set Sentinal scope node */
+	sentinal = scope_alloc();
+	sentinal->type = SCOPE_ROOT;
+	
+	includes_search_curdir = 1;
+	appname = *argv;
+	regfile = NULL;
+	listfile = NULL;
+#if DEBUG
+	yy_flex_debug = 0;
+	mm_flex_debug = 0;
+	yydebug = 0;
+	mmdebug = 0;
+#endif
+	while ((ch = getopt(argc, argv, "d:i:l:n:o:p:r:I:")) != -1) {
+		switch(ch) {
+		case 'd':
+#if DEBUG
+			if (strcmp(optarg, "s") == 0) {
+				yy_flex_debug = 1;
+				mm_flex_debug = 1;
+			} else if (strcmp(optarg, "p") == 0) {
+				yydebug = 1;
+				mmdebug = 1;
+			} else {
+				fprintf(stderr, "%s: -d Requires either an "
+					"'s' or 'p' argument\n", appname);
+				usage();
+			}
+#else
+			stop("-d: Assembler not built with debugging "
+			     "information", EX_SOFTWARE);
+#endif
+			break;
+		case 'i':
+			stock_include_file = optarg;
+			break;
+		case 'l':
+			/* Create a program listing */
+			if ((listfile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			listfilename = optarg;
+			break;
+		case 'n':
+			/* Don't complain about the -nostdinc directrive */
+			if (strcmp(optarg, "ostdinc")) {
+				fprintf(stderr, "%s: Unknown option -%c%s\n",
+					appname, ch, optarg);
+				usage();
+				/* NOTREACHED */
+			}
+			break;
+		case 'o':
+			if ((ofile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			ofilename = optarg;
+			break;
+		case 'p':
+			/* Create Register Diagnostic "printing" Functions */
+			if ((regdiagfile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			regdiagfilename = optarg;
+			break;
+		case 'r':
+			if ((regfile = fopen(optarg, "w")) == NULL) {
+				perror(optarg);
+				stop(NULL, EX_CANTCREAT);
+			}
+			regfilename = optarg;
+			break;
+		case 'I':
+		{
+			path_entry_t include_dir;
+
+			if (strcmp(optarg, "-") == 0) {
+				if (includes_search_curdir == 0) {
+					fprintf(stderr, "%s: Warning - '-I-' "
+							"specified multiple "
+							"times\n", appname);
+				}
+				includes_search_curdir = 0;
+				for (include_dir = SLIST_FIRST(&search_path);
+				     include_dir != NULL;
+				     include_dir = SLIST_NEXT(include_dir,
+							      links))
+					/*
+					 * All entries before a '-I-' only
+					 * apply to includes specified with
+					 * quotes instead of "<>".
+					 */
+					include_dir->quoted_includes_only = 1;
+			} else {
+				include_dir =
+				    (path_entry_t)malloc(sizeof(*include_dir));
+				if (include_dir == NULL) {
+					perror(optarg);
+					stop(NULL, EX_OSERR);
+				}
+				include_dir->directory = strdup(optarg);
+				if (include_dir->directory == NULL) {
+					perror(optarg);
+					stop(NULL, EX_OSERR);
+				}
+				include_dir->quoted_includes_only = 0;
+				SLIST_INSERT_HEAD(&search_path, include_dir,
+						  links);
+			}
+			break;
+		}
+		case '?':
+		default:
+			usage();
+			/* NOTREACHED */
+		}
+	}
+	argc -= optind;
+	argv += optind;
+
+	if (argc != 1) {
+		fprintf(stderr, "%s: No input file specifiled\n", appname);
+		usage();
+		/* NOTREACHED */
+	}
+
+	if (regdiagfile != NULL
+	 && (regfile == NULL || stock_include_file == NULL)) {
+		fprintf(stderr,
+			"%s: The -p option requires the -r and -i options.\n",
+			appname);
+		usage();
+		/* NOTREACHED */
+	}
+	symtable_open();
+	inputfilename = *argv;
+	include_file(*argv, SOURCE_FILE);
+	retval = yyparse();
+	if (retval == 0) {
+		if (SLIST_FIRST(&scope_stack) == NULL
+		 || SLIST_FIRST(&scope_stack)->type != SCOPE_ROOT) {
+			stop("Unterminated conditional expression", EX_DATAERR);
+			/* NOTREACHED */
+		}
+
+		/* Process outmost scope */
+		process_scope(SLIST_FIRST(&scope_stack));
+		/*
+		 * Decend the tree of scopes and insert/emit
+		 * patches as appropriate.  We perform a depth first
+		 * tranversal, recursively handling each scope.
+		 */
+		/* start at the root scope */
+		dump_scope(SLIST_FIRST(&scope_stack));
+
+		/* Patch up forward jump addresses */
+		back_patch();
+
+		if (ofile != NULL)
+			output_code();
+		if (regfile != NULL)
+			symtable_dump(regfile, regdiagfile);
+		if (listfile != NULL)
+			output_listing(inputfilename);
+	}
+
+	stop(NULL, 0);
+	/* NOTREACHED */
+	return (0);
+}
+
+static void
+usage()
+{
+
+	(void)fprintf(stderr,
+"usage: %-16s [-nostdinc] [-I-] [-I directory] [-o output_file]\n"
+"	[-r register_output_file [-p register_diag_file -i includefile]]\n"
+"	[-l program_list_file]\n"
+"	input_file\n", appname);
+	exit(EX_USAGE);
+}
+
+static void
+back_patch()
+{
+	struct instruction *cur_instr;
+
+	for (cur_instr = STAILQ_FIRST(&seq_program);
+	     cur_instr != NULL;
+	     cur_instr = STAILQ_NEXT(cur_instr, links)) {
+		if (cur_instr->patch_label != NULL) {
+			struct ins_format3 *f3_instr;
+			u_int address;
+
+			if (cur_instr->patch_label->type != LABEL) {
+				char buf[255];
+
+				snprintf(buf, sizeof(buf),
+					 "Undefined label %s",
+					 cur_instr->patch_label->name);
+				stop(buf, EX_DATAERR);
+				/* NOTREACHED */
+			}
+			f3_instr = &cur_instr->format.format3;
+			address = f3_instr->address;
+			address += cur_instr->patch_label->info.linfo->address;
+			f3_instr->address = address;
+		}
+	}
+}
+
+static void
+output_code()
+{
+	struct instruction *cur_instr;
+	patch_t *cur_patch;
+	critical_section_t *cs;
+	symbol_node_t *cur_node;
+	int instrcount;
+
+	instrcount = 0;
+	fprintf(ofile,
+"/*\n"
+" * DO NOT EDIT - This file is automatically generated\n"
+" *		 from the following source files:\n"
+" *\n"
+"%s */\n", versions);
+
+	fprintf(ofile, "static uint8_t seqprog[] = {\n");
+	for (cur_instr = STAILQ_FIRST(&seq_program);
+	     cur_instr != NULL;
+	     cur_instr = STAILQ_NEXT(cur_instr, links)) {
+
+		fprintf(ofile, "%s\t0x%02x, 0x%02x, 0x%02x, 0x%02x",
+			cur_instr == STAILQ_FIRST(&seq_program) ? "" : ",\n",
+#if BYTE_ORDER == LITTLE_ENDIAN
+			cur_instr->format.bytes[0],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[3]);
+#else
+			cur_instr->format.bytes[3],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[0]);
+#endif
+		instrcount++;
+	}
+	fprintf(ofile, "\n};\n\n");
+
+	if (patch_arg_list == NULL)
+		stop("Patch argument list not defined",
+		     EX_DATAERR);
+
+	/*
+	 *  Output patch information.  Patch functions first.
+	 */
+	fprintf(ofile,
+"typedef int %spatch_func_t (%s);\n", prefix, patch_arg_list);
+
+	for (cur_node = SLIST_FIRST(&patch_functions);
+	     cur_node != NULL;
+	     cur_node = SLIST_NEXT(cur_node,links)) {
+		fprintf(ofile,
+"static %spatch_func_t %spatch%d_func;\n"
+"\n"
+"static int\n"
+"%spatch%d_func(%s)\n"
+"{\n"
+"	return (%s);\n"
+"}\n\n",
+			prefix,
+			prefix,
+			cur_node->symbol->info.condinfo->func_num,
+			prefix,
+			cur_node->symbol->info.condinfo->func_num,
+			patch_arg_list,
+			cur_node->symbol->name);
+	}
+
+	fprintf(ofile,
+"static struct patch {\n"
+"	%spatch_func_t		*patch_func;\n"
+"	uint32_t		 begin		:10,\n"
+"				 skip_instr	:10,\n"
+"				 skip_patch	:12;\n"
+"} patches[] = {\n", prefix);
+
+	for (cur_patch = STAILQ_FIRST(&patches);
+	     cur_patch != NULL;
+	     cur_patch = STAILQ_NEXT(cur_patch,links)) {
+		fprintf(ofile, "%s\t{ %spatch%d_func, %d, %d, %d }",
+			cur_patch == STAILQ_FIRST(&patches) ? "" : ",\n",
+			prefix,
+			cur_patch->patch_func, cur_patch->begin,
+			cur_patch->skip_instr, cur_patch->skip_patch);
+	}
+
+	fprintf(ofile, "\n};\n\n");
+
+	fprintf(ofile,
+"static struct cs {\n"
+"	uint16_t	begin;\n"
+"	uint16_t	end;\n"
+"} critical_sections[] = {\n");
+
+	for (cs = TAILQ_FIRST(&cs_tailq);
+	     cs != NULL;
+	     cs = TAILQ_NEXT(cs, links)) {
+		fprintf(ofile, "%s\t{ %d, %d }",
+			cs == TAILQ_FIRST(&cs_tailq) ? "" : ",\n",
+			cs->begin_addr, cs->end_addr);
+	}
+
+	fprintf(ofile, "\n};\n\n");
+
+	fprintf(ofile,
+"static const int num_critical_sections = sizeof(critical_sections)\n"
+"				       / sizeof(*critical_sections);\n");
+
+	fprintf(stderr, "%s: %d instructions used\n", appname, instrcount);
+}
+
+static void
+dump_scope(scope_t *scope)
+{
+	scope_t *cur_scope;
+
+	/*
+	 * Emit the first patch for this scope
+	 */
+	emit_patch(scope, 0);
+
+	/*
+	 * Dump each scope within this one.
+	 */
+	cur_scope = TAILQ_FIRST(&scope->inner_scope);
+
+	while (cur_scope != NULL) {
+
+		dump_scope(cur_scope);
+
+		cur_scope = TAILQ_NEXT(cur_scope, scope_links);
+	}
+
+	/*
+	 * Emit the second, closing, patch for this scope
+	 */
+	emit_patch(scope, 1);
+}
+
+void
+emit_patch(scope_t *scope, int patch)
+{
+	patch_info_t *pinfo;
+	patch_t *new_patch;
+
+	pinfo = &scope->patches[patch];
+
+	if (pinfo->skip_instr == 0)
+		/* No-Op patch */
+		return;
+
+	new_patch = (patch_t *)malloc(sizeof(*new_patch));
+
+	if (new_patch == NULL)
+		stop("Could not malloc patch structure", EX_OSERR);
+
+	memset(new_patch, 0, sizeof(*new_patch));
+
+	if (patch == 0) {
+		new_patch->patch_func = scope->func_num;
+		new_patch->begin = scope->begin_addr;
+	} else {
+		new_patch->patch_func = 0;
+		new_patch->begin = scope->end_addr;
+	}
+	new_patch->skip_instr = pinfo->skip_instr;
+	new_patch->skip_patch = pinfo->skip_patch;
+	STAILQ_INSERT_TAIL(&patches, new_patch, links);
+}
+
+void
+output_listing(char *ifilename)
+{
+	char buf[1024];
+	FILE *ifile;
+	struct instruction *cur_instr;
+	patch_t *cur_patch;
+	symbol_node_t *cur_func;
+	int *func_values;
+	int instrcount;
+	int instrptr;
+	int line;
+	int func_count;
+	int skip_addr;
+
+	instrcount = 0;
+	instrptr = 0;
+	line = 1;
+	skip_addr = 0;
+	if ((ifile = fopen(ifilename, "r")) == NULL) {
+		perror(ifilename);
+		stop(NULL, EX_DATAERR);
+	}
+
+	/*
+	 * Determine which options to apply to this listing.
+	 */
+	for (func_count = 0, cur_func = SLIST_FIRST(&patch_functions);
+	    cur_func != NULL;
+	    cur_func = SLIST_NEXT(cur_func, links))
+		func_count++;
+
+	func_values = NULL;
+	if (func_count != 0) {
+		func_values = (int *)malloc(func_count * sizeof(int));
+
+		if (func_values == NULL)
+			stop("Could not malloc", EX_OSERR);
+		
+		func_values[0] = 0; /* FALSE func */
+		func_count--;
+
+		/*
+		 * Ask the user to fill in the return values for
+		 * the rest of the functions.
+		 */
+		
+		
+		for (cur_func = SLIST_FIRST(&patch_functions);
+		     cur_func != NULL && SLIST_NEXT(cur_func, links) != NULL;
+		     cur_func = SLIST_NEXT(cur_func, links), func_count--) {
+			int input;
+			
+			fprintf(stdout, "\n(%s)\n", cur_func->symbol->name);
+			fprintf(stdout,
+				"Enter the return value for "
+				"this expression[T/F]:");
+
+			while (1) {
+
+				input = getchar();
+				input = toupper(input);
+
+				if (input == 'T') {
+					func_values[func_count] = 1;
+					break;
+				} else if (input == 'F') {
+					func_values[func_count] = 0;
+					break;
+				}
+			}
+			if (isatty(fileno(stdin)) == 0)
+				putchar(input);
+		}
+		fprintf(stdout, "\nThanks!\n");
+	}
+
+	/* Now output the listing */
+	cur_patch = STAILQ_FIRST(&patches);
+	for (cur_instr = STAILQ_FIRST(&seq_program);
+	     cur_instr != NULL;
+	     cur_instr = STAILQ_NEXT(cur_instr, links), instrcount++) {
+
+		if (check_patch(&cur_patch, instrcount,
+				&skip_addr, func_values) == 0) {
+			/* Don't count this instruction as it is in a patch
+			 * that was removed.
+			 */
+                        continue;
+		}
+
+		while (line < cur_instr->srcline) {
+			fgets(buf, sizeof(buf), ifile);
+				fprintf(listfile, "\t\t%s", buf);
+				line++;
+		}
+		fprintf(listfile, "%03x %02x%02x%02x%02x", instrptr,
+#if BYTE_ORDER == LITTLE_ENDIAN
+			cur_instr->format.bytes[0],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[3]);
+#else
+			cur_instr->format.bytes[3],
+			cur_instr->format.bytes[2],
+			cur_instr->format.bytes[1],
+			cur_instr->format.bytes[0]);
+#endif
+		fgets(buf, sizeof(buf), ifile);
+		fprintf(listfile, "\t%s", buf);
+		line++;
+		instrptr++;
+	}
+	/* Dump the remainder of the file */
+	while(fgets(buf, sizeof(buf), ifile) != NULL)
+		fprintf(listfile, "\t\t%s", buf);
+
+	fclose(ifile);
+}
+
+static int
+check_patch(patch_t **start_patch, int start_instr,
+	    int *skip_addr, int *func_vals)
+{
+	patch_t *cur_patch;
+
+	cur_patch = *start_patch;
+
+	while (cur_patch != NULL && start_instr == cur_patch->begin) {
+		if (func_vals[cur_patch->patch_func] == 0) {
+			int skip;
+
+			/* Start rejecting code */
+			*skip_addr = start_instr + cur_patch->skip_instr;
+			for (skip = cur_patch->skip_patch;
+			     skip > 0 && cur_patch != NULL;
+			     skip--)
+				cur_patch = STAILQ_NEXT(cur_patch, links);
+		} else {
+			/* Accepted this patch.  Advance to the next
+			 * one and wait for our intruction pointer to
+			 * hit this point.
+			 */
+			cur_patch = STAILQ_NEXT(cur_patch, links);
+		}
+	}
+
+	*start_patch = cur_patch;
+	if (start_instr < *skip_addr)
+		/* Still skipping */
+		return (0);
+
+	return (1);
+}
+
+/*
+ * Print out error information if appropriate, and clean up before
+ * terminating the program.
+ */
+void
+stop(const char *string, int err_code)
+{
+	if (string != NULL) {
+		fprintf(stderr, "%s: ", appname);
+		if (yyfilename != NULL) {
+			fprintf(stderr, "Stopped at file %s, line %d - ",
+				yyfilename, yylineno);
+		}
+		fprintf(stderr, "%s\n", string);
+	}
+
+	if (ofile != NULL) {
+		fclose(ofile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, ofilename);
+			unlink(ofilename);
+		}
+	}
+
+	if (regfile != NULL) {
+		fclose(regfile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, regfilename);
+			unlink(regfilename);
+		}
+	}
+
+	if (listfile != NULL) {
+		fclose(listfile);
+		if (err_code != 0) {
+			fprintf(stderr, "%s: Removing %s due to error\n",
+				appname, listfilename);
+			unlink(listfilename);
+		}
+	}
+
+	symlist_free(&patch_functions);
+	symtable_close();
+
+	exit(err_code);
+}
+
+struct instruction *
+seq_alloc()
+{
+	struct instruction *new_instr;
+
+	new_instr = (struct instruction *)malloc(sizeof(struct instruction));
+	if (new_instr == NULL)
+		stop("Unable to malloc instruction object", EX_SOFTWARE);
+	memset(new_instr, 0, sizeof(*new_instr));
+	STAILQ_INSERT_TAIL(&seq_program, new_instr, links);
+	new_instr->srcline = yylineno;
+	return new_instr;
+}
+
+critical_section_t *
+cs_alloc()
+{
+	critical_section_t *new_cs;
+
+	new_cs= (critical_section_t *)malloc(sizeof(critical_section_t));
+	if (new_cs == NULL)
+		stop("Unable to malloc critical_section object", EX_SOFTWARE);
+	memset(new_cs, 0, sizeof(*new_cs));
+	
+	TAILQ_INSERT_TAIL(&cs_tailq, new_cs, links);
+	return new_cs;
+}
+
+scope_t *
+scope_alloc()
+{
+	scope_t *new_scope;
+
+	new_scope = (scope_t *)malloc(sizeof(scope_t));
+	if (new_scope == NULL)
+		stop("Unable to malloc scope object", EX_SOFTWARE);
+	memset(new_scope, 0, sizeof(*new_scope));
+	TAILQ_INIT(&new_scope->inner_scope);
+	
+	if (SLIST_FIRST(&scope_stack) != NULL) {
+		TAILQ_INSERT_TAIL(&SLIST_FIRST(&scope_stack)->inner_scope,
+				  new_scope, scope_links);
+	}
+	/* This patch is now the current scope */
+	SLIST_INSERT_HEAD(&scope_stack, new_scope, scope_stack_links);
+	return new_scope;
+}
+
+void
+process_scope(scope_t *scope)
+{
+	/*
+	 * We are "leaving" this scope.  We should now have
+	 * enough information to process the lists of scopes
+	 * we encapsulate.
+	 */
+	scope_t *cur_scope;
+	u_int skip_patch_count;
+	u_int skip_instr_count;
+
+	cur_scope = TAILQ_LAST(&scope->inner_scope, scope_tailq);
+	skip_patch_count = 0;
+	skip_instr_count = 0;
+	while (cur_scope != NULL) {
+		u_int patch0_patch_skip;
+
+		patch0_patch_skip = 0;
+		switch (cur_scope->type) {
+		case SCOPE_IF:
+		case SCOPE_ELSE_IF:
+			if (skip_instr_count != 0) {
+				/* Create a tail patch */
+				patch0_patch_skip++;
+				cur_scope->patches[1].skip_patch =
+				    skip_patch_count + 1;
+				cur_scope->patches[1].skip_instr =
+				    skip_instr_count;
+			}
+
+			/* Count Head patch */
+			patch0_patch_skip++;
+
+			/* Count any patches contained in our inner scope */
+			patch0_patch_skip += cur_scope->inner_scope_patches;
+
+			cur_scope->patches[0].skip_patch = patch0_patch_skip;
+			cur_scope->patches[0].skip_instr =
+			    cur_scope->end_addr - cur_scope->begin_addr;
+
+			skip_instr_count += cur_scope->patches[0].skip_instr;
+
+			skip_patch_count += patch0_patch_skip;
+			if (cur_scope->type == SCOPE_IF) {
+				scope->inner_scope_patches += skip_patch_count;
+				skip_patch_count = 0;
+			        skip_instr_count = 0;
+			}
+			break;
+		case SCOPE_ELSE:
+			/* Count any patches contained in our innter scope */
+			skip_patch_count += cur_scope->inner_scope_patches;
+
+			skip_instr_count += cur_scope->end_addr
+					  - cur_scope->begin_addr;
+			break;
+		case SCOPE_ROOT:
+			stop("Unexpected scope type encountered", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+
+		cur_scope = TAILQ_PREV(cur_scope, scope_tailq, scope_links);
+	}
+}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm.h b/drivers/scsi/aic7xxx/aicasm/aicasm.h
new file mode 100644
index 0000000..51678dd
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm.h
@@ -0,0 +1,95 @@
+/*
+ * Assembler for the sequencer program downloaded to Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2001, 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm.h#14 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+typedef struct path_entry {
+	char	*directory;
+	int	quoted_includes_only;
+	SLIST_ENTRY(path_entry) links;
+} *path_entry_t;
+
+typedef enum {  
+	QUOTED_INCLUDE,
+	BRACKETED_INCLUDE,
+	SOURCE_FILE
+} include_type;
+
+SLIST_HEAD(path_list, path_entry);
+
+extern struct path_list search_path;
+extern struct cs_tailq cs_tailq;
+extern struct scope_list scope_stack;
+extern struct symlist patch_functions;
+extern int includes_search_curdir;		/* False if we've seen -I- */
+extern char *appname;
+extern char *stock_include_file;
+extern int yylineno;
+extern char *yyfilename;
+extern char *prefix;
+extern char *patch_arg_list;
+extern char *versions;
+extern int   src_mode;
+extern int   dst_mode;
+struct symbol;
+
+void stop(const char *errstring, int err_code);
+void include_file(char *file_name, include_type type);
+void expand_macro(struct symbol *macro_symbol);
+struct instruction *seq_alloc(void);
+struct critical_section *cs_alloc(void);
+struct scope *scope_alloc(void);
+void process_scope(struct scope *);
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
new file mode 100644
index 0000000..67e046d
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y
@@ -0,0 +1,1945 @@
+%{
+/*
+ * Parser for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * Copyright (c) 2001, 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_gram.y#29 $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_insformat.h"
+
+int yylineno;
+char *yyfilename;
+char stock_prefix[] = "aic_";
+char *prefix = stock_prefix;
+char *patch_arg_list;
+char *versions;
+static char errbuf[255];
+static char regex_pattern[255];
+static symbol_t *cur_symbol;
+static symbol_t *field_symbol;
+static symbol_t *scb_or_sram_symbol;
+static symtype cur_symtype;
+static symbol_ref_t accumulator;
+static symbol_ref_t mode_ptr;
+static symbol_ref_t allones;
+static symbol_ref_t allzeros;
+static symbol_ref_t none;
+static symbol_ref_t sindex;
+static int instruction_ptr;
+static int num_srams;
+static int sram_or_scb_offset;
+static int download_constant_count;
+static int in_critical_section;
+static u_int enum_increment;
+static u_int enum_next_value;
+
+static void process_field(int field_type, symbol_t *sym, int mask);
+static void initialize_symbol(symbol_t *symbol);
+static void add_macro_arg(const char *argtext, int position);
+static void add_macro_body(const char *bodytext);
+static void process_register(symbol_t **p_symbol);
+static void format_1_instr(int opcode, symbol_ref_t *dest,
+			   expression_t *immed, symbol_ref_t *src, int ret);
+static void format_2_instr(int opcode, symbol_ref_t *dest,
+			   expression_t *places, symbol_ref_t *src, int ret);
+static void format_3_instr(int opcode, symbol_ref_t *src,
+			   expression_t *immed, symbol_ref_t *address);
+static void test_readable_symbol(symbol_t *symbol);
+static void test_writable_symbol(symbol_t *symbol);
+static void type_check(symbol_t *symbol, expression_t *expression, int and_op);
+static void make_expression(expression_t *immed, int value);
+static void add_conditional(symbol_t *symbol);
+static void add_version(const char *verstring);
+static int  is_download_const(expression_t *immed);
+
+#define SRAM_SYMNAME "SRAM_BASE"
+#define SCB_SYMNAME "SCB_BASE"
+%}
+
+%union {
+	u_int		value;
+	char		*str;
+	symbol_t	*sym;
+	symbol_ref_t	sym_ref;
+	expression_t	expression;
+}
+
+%token T_REGISTER
+
+%token <value> T_CONST
+
+%token T_EXPORT
+
+%token T_DOWNLOAD
+
+%token T_SCB
+
+%token T_SRAM
+
+%token T_ALIAS
+
+%token T_SIZE
+
+%token T_EXPR_LSHIFT
+
+%token T_EXPR_RSHIFT
+
+%token <value> T_ADDRESS
+
+%token T_ACCESS_MODE
+
+%token T_MODES
+
+%token T_DEFINE
+
+%token T_SET_SRC_MODE
+
+%token T_SET_DST_MODE
+
+%token <value> T_MODE
+
+%token T_BEGIN_CS
+
+%token T_END_CS
+
+%token T_FIELD
+
+%token T_ENUM
+
+%token T_MASK
+
+%token <value> T_NUMBER
+
+%token <str> T_PATH T_STRING T_ARG T_MACROBODY
+
+%token <sym> T_CEXPR
+
+%token T_EOF T_INCLUDE T_VERSION T_PREFIX T_PATCH_ARG_LIST
+
+%token <value> T_SHR T_SHL T_ROR T_ROL
+
+%token <value> T_MVI T_MOV T_CLR T_BMOV
+
+%token <value> T_JMP T_JC T_JNC T_JE T_JNE T_JNZ T_JZ T_CALL
+
+%token <value> T_ADD T_ADC
+
+%token <value> T_INC T_DEC
+
+%token <value> T_STC T_CLC
+
+%token <value> T_CMP T_NOT T_XOR
+
+%token <value> T_TEST T_AND
+
+%token <value> T_OR
+
+%token T_RET
+
+%token T_NOP
+
+%token T_ACCUM T_ALLONES T_ALLZEROS T_NONE T_SINDEX T_MODE_PTR
+
+%token T_A
+
+%token <sym> T_SYMBOL
+
+%token T_NL
+
+%token T_IF T_ELSE T_ELSE_IF T_ENDIF
+
+%type <sym_ref> reg_symbol address destination source opt_source
+
+%type <expression> expression immediate immediate_or_a
+
+%type <value> export ret f1_opcode f2_opcode jmp_jc_jnc_call jz_jnz je_jne
+
+%type <value> mode_value mode_list macro_arglist
+
+%left '|'
+%left '&'
+%left T_EXPR_LSHIFT T_EXPR_RSHIFT
+%left '+' '-'
+%left '*' '/'
+%right '~'
+%nonassoc UMINUS
+%%
+
+program:
+	include
+|	program include
+|	prefix
+|	program prefix
+|	patch_arg_list
+|	program patch_arg_list
+|	version
+|	program version
+|	register
+|	program register
+|	constant
+|	program constant
+|	macrodefn
+|	program macrodefn
+|	scratch_ram
+|	program scratch_ram
+|	scb
+|	program scb
+|	label
+|	program label
+|	set_src_mode
+|	program set_src_mode
+|	set_dst_mode
+|	program set_dst_mode
+|	critical_section_start
+|	program critical_section_start
+|	critical_section_end
+|	program critical_section_end
+|	conditional
+|	program conditional
+|	code
+|	program code
+;
+
+include:
+	T_INCLUDE '<' T_PATH '>'
+	{
+		include_file($3, BRACKETED_INCLUDE);
+	}
+|	T_INCLUDE '"' T_PATH '"'
+	{
+		include_file($3, QUOTED_INCLUDE);
+	}
+;
+
+prefix:
+	T_PREFIX '=' T_STRING
+	{
+		if (prefix != stock_prefix)
+			stop("Prefix multiply defined",
+			     EX_DATAERR);
+		prefix = strdup($3);
+		if (prefix == NULL)
+			stop("Unable to record prefix", EX_SOFTWARE);
+	}
+;
+
+patch_arg_list:
+	T_PATCH_ARG_LIST '=' T_STRING
+	{
+		if (patch_arg_list != NULL)
+			stop("Patch argument list multiply defined",
+			     EX_DATAERR);
+		patch_arg_list = strdup($3);
+		if (patch_arg_list == NULL)
+			stop("Unable to record patch arg list", EX_SOFTWARE);
+	}
+;
+
+version:
+	T_VERSION '=' T_STRING
+	{ add_version($3); }
+;
+
+register:
+	T_REGISTER { cur_symtype = REGISTER; } reg_definition
+;
+
+reg_definition:
+	T_SYMBOL '{'
+		{
+			if ($1->type != UNINITIALIZED) {
+				stop("Register multiply defined", EX_DATAERR);
+				/* NOTREACHED */
+			}
+			cur_symbol = $1; 
+			cur_symbol->type = cur_symtype;
+			initialize_symbol(cur_symbol);
+		}
+		reg_attribute_list
+	'}'
+		{                    
+			/*
+			 * Default to allowing everything in for registers
+			 * with no bit or mask definitions.
+			 */
+			if (cur_symbol->info.rinfo->valid_bitmask == 0)
+				cur_symbol->info.rinfo->valid_bitmask = 0xFF;
+
+			if (cur_symbol->info.rinfo->size == 0)
+				cur_symbol->info.rinfo->size = 1;
+
+			/*
+			 * This might be useful for registers too.
+			 */
+			if (cur_symbol->type != REGISTER) {
+				if (cur_symbol->info.rinfo->address == 0)
+					cur_symbol->info.rinfo->address =
+					    sram_or_scb_offset;
+				sram_or_scb_offset +=
+				    cur_symbol->info.rinfo->size;
+			}
+			cur_symbol = NULL;
+		}
+;
+
+reg_attribute_list:
+	reg_attribute
+|	reg_attribute_list reg_attribute
+;
+
+reg_attribute:		
+	reg_address
+|	size
+|	access_mode
+|	modes
+|	field_defn
+|	enum_defn
+|	mask_defn
+|	alias
+|	accumulator
+|	mode_pointer
+|	allones
+|	allzeros
+|	none
+|	sindex
+;
+
+reg_address:
+	T_ADDRESS T_NUMBER
+	{
+		cur_symbol->info.rinfo->address = $2;
+	}
+;
+
+size:
+	T_SIZE T_NUMBER
+	{
+		cur_symbol->info.rinfo->size = $2;
+		if (scb_or_sram_symbol != NULL) {
+			u_int max_addr;
+			u_int sym_max_addr;
+
+			max_addr = scb_or_sram_symbol->info.rinfo->address
+				 + scb_or_sram_symbol->info.rinfo->size;
+			sym_max_addr = cur_symbol->info.rinfo->address
+				     + cur_symbol->info.rinfo->size;
+
+			if (sym_max_addr > max_addr)
+				stop("SCB or SRAM space exhausted", EX_DATAERR);
+		}
+	}
+;
+
+access_mode:
+	T_ACCESS_MODE T_MODE
+	{
+		cur_symbol->info.rinfo->mode = $2;
+	}
+;
+
+modes:
+	T_MODES mode_list
+	{
+		cur_symbol->info.rinfo->modes = $2;
+	}
+;
+
+mode_list:
+	mode_value
+	{
+		$$ = $1;
+	}
+|	mode_list ',' mode_value
+	{
+		$$ = $1 | $3;
+	}
+;
+
+mode_value:
+	T_NUMBER
+	{
+		if ($1 > 4) {
+			stop("Valid register modes range between 0 and 4.",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+
+		$$ = (0x1 << $1);
+	}
+|	T_SYMBOL
+	{
+		symbol_t *symbol;
+
+		symbol = $1;
+		if (symbol->type != CONST) {
+			stop("Only \"const\" symbols allowed in "
+			     "mode definitions.", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		if (symbol->info.cinfo->value > 4) {
+			stop("Valid register modes range between 0 and 4.",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$ = (0x1 << symbol->info.cinfo->value);
+	}
+;
+
+field_defn:
+	T_FIELD
+		{
+			field_symbol = NULL;
+			enum_next_value = 0;
+			enum_increment = 1;
+		}
+	'{' enum_entry_list '}'
+|	T_FIELD T_SYMBOL expression
+		{
+			process_field(FIELD, $2, $3.value);
+			field_symbol = $2;
+			enum_next_value = 0;
+			enum_increment = 0x01 << (ffs($3.value) - 1);
+		}
+	'{' enum_entry_list '}'
+|	T_FIELD T_SYMBOL expression
+	{
+		process_field(FIELD, $2, $3.value);
+	}
+;
+
+enum_defn:
+	T_ENUM
+		{
+			field_symbol = NULL;
+			enum_next_value = 0;
+			enum_increment = 1;
+		}
+	'{' enum_entry_list '}'
+|	T_ENUM T_SYMBOL expression
+		{
+			process_field(ENUM, $2, $3.value);
+			field_symbol = $2;
+			enum_next_value = 0;
+			enum_increment = 0x01 << (ffs($3.value) - 1);
+		}
+	'{' enum_entry_list '}'
+;
+
+enum_entry_list:
+	enum_entry
+|	enum_entry_list ',' enum_entry
+;
+
+enum_entry:
+	T_SYMBOL
+	{
+		process_field(ENUM_ENTRY, $1, enum_next_value);
+		enum_next_value += enum_increment;
+	}
+|	T_SYMBOL expression
+	{
+		process_field(ENUM_ENTRY, $1, $2.value);
+		enum_next_value = $2.value + enum_increment;
+	}
+;
+
+mask_defn:
+	T_MASK T_SYMBOL expression
+	{
+		process_field(MASK, $2, $3.value);
+	}
+;
+
+alias:
+	T_ALIAS	T_SYMBOL
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of register alias",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = ALIAS;
+		initialize_symbol($2);
+		$2->info.ainfo->parent = cur_symbol;
+	}
+;
+
+accumulator:
+	T_ACCUM
+	{
+		if (accumulator.symbol != NULL) {
+			stop("Only one accumulator definition allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		accumulator.symbol = cur_symbol;
+	}
+;
+
+mode_pointer:
+	T_MODE_PTR
+	{
+		if (mode_ptr.symbol != NULL) {
+			stop("Only one mode pointer definition allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		mode_ptr.symbol = cur_symbol;
+	}
+;
+
+allones:
+	T_ALLONES
+	{
+		if (allones.symbol != NULL) {
+			stop("Only one definition of allones allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		allones.symbol = cur_symbol;
+	}
+;
+
+allzeros:
+	T_ALLZEROS
+	{
+		if (allzeros.symbol != NULL) {
+			stop("Only one definition of allzeros allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		allzeros.symbol = cur_symbol;
+	}
+;
+
+none:
+	T_NONE
+	{
+		if (none.symbol != NULL) {
+			stop("Only one definition of none allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		none.symbol = cur_symbol;
+	}
+;
+
+sindex:
+	T_SINDEX
+	{
+		if (sindex.symbol != NULL) {
+			stop("Only one definition of sindex allowed",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		sindex.symbol = cur_symbol;
+	}
+;
+
+expression:
+	expression '|' expression
+	{
+		 $$.value = $1.value | $3.value;
+		 symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '&' expression
+	{
+		$$.value = $1.value & $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '+' expression
+	{
+		$$.value = $1.value + $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	expression '-' expression
+	{
+		$$.value = $1.value - $3.value;
+		symlist_merge(&($$.referenced_syms),
+			       &($1.referenced_syms),
+			       &($3.referenced_syms));
+	}
+|	expression '*' expression
+	{
+		$$.value = $1.value * $3.value;
+		symlist_merge(&($$.referenced_syms),
+			       &($1.referenced_syms),
+			       &($3.referenced_syms));
+	}
+|	expression '/' expression
+	{
+		$$.value = $1.value / $3.value;
+		symlist_merge(&($$.referenced_syms),
+			       &($1.referenced_syms),
+			       &($3.referenced_syms));
+	}
+| 	expression T_EXPR_LSHIFT expression
+	{
+		$$.value = $1.value << $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+| 	expression T_EXPR_RSHIFT expression
+	{
+		$$.value = $1.value >> $3.value;
+		symlist_merge(&$$.referenced_syms,
+			       &$1.referenced_syms,
+			       &$3.referenced_syms);
+	}
+|	'(' expression ')'
+	{
+		$$ = $2;
+	}
+|	'~' expression
+	{
+		$$ = $2;
+		$$.value = (~$$.value) & 0xFF;
+	}
+|	'-' expression %prec UMINUS
+	{
+		$$ = $2;
+		$$.value = -$$.value;
+	}
+|	T_NUMBER
+	{
+		$$.value = $1;
+		SLIST_INIT(&$$.referenced_syms);
+	}
+|	T_SYMBOL
+	{
+		symbol_t *symbol;
+
+		symbol = $1;
+		switch (symbol->type) {
+		case ALIAS:
+			symbol = $1->info.ainfo->parent;
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			$$.value = symbol->info.rinfo->address;
+			break;
+		case MASK:
+		case FIELD:
+		case ENUM:
+		case ENUM_ENTRY:
+			$$.value = symbol->info.finfo->value;
+			break;
+		case DOWNLOAD_CONST:
+		case CONST:
+			$$.value = symbol->info.cinfo->value;
+			break;
+		case UNINITIALIZED:
+		default:
+		{
+			snprintf(errbuf, sizeof(errbuf),
+				 "Undefined symbol %s referenced",
+				 symbol->name);
+			stop(errbuf, EX_DATAERR);
+			/* NOTREACHED */
+			break;
+		}
+		}
+		SLIST_INIT(&$$.referenced_syms);
+		symlist_add(&$$.referenced_syms, symbol, SYMLIST_INSERT_HEAD);
+	}
+;
+
+constant:
+	T_CONST T_SYMBOL expression 
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of symbol as a constant",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = CONST;
+		initialize_symbol($2);
+		$2->info.cinfo->value = $3.value;
+	}
+|	T_CONST T_SYMBOL T_DOWNLOAD
+	{
+		if ($1) {
+			stop("Invalid downloaded constant declaration",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of symbol as a downloaded constant",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = DOWNLOAD_CONST;
+		initialize_symbol($2);
+		$2->info.cinfo->value = download_constant_count++;
+	}
+;
+
+macrodefn_prologue:
+	T_DEFINE T_SYMBOL
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Re-definition of symbol as a macro",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		cur_symbol = $2;
+		cur_symbol->type = MACRO;
+		initialize_symbol(cur_symbol);
+	}
+;
+
+macrodefn:
+	macrodefn_prologue T_MACROBODY
+	{
+		add_macro_body($2);
+	}
+|	macrodefn_prologue '(' macro_arglist ')' T_MACROBODY
+	{
+		add_macro_body($5);
+		cur_symbol->info.macroinfo->narg = $3;
+	}
+;
+
+macro_arglist:
+	{
+		/* Macros can take no arguments */
+		$$ = 0;
+	}
+|	T_ARG
+	{
+		$$ = 1;
+		add_macro_arg($1, 0);
+	}
+|	macro_arglist ',' T_ARG
+	{
+		if ($1 == 0) {
+			stop("Comma without preceeding argument in arg list",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$ = $1 + 1;
+		add_macro_arg($3, $1);
+	}
+;
+
+scratch_ram:
+	T_SRAM '{'
+		{
+			snprintf(errbuf, sizeof(errbuf), "%s%d", SRAM_SYMNAME,
+				 num_srams);
+			cur_symbol = symtable_get(SRAM_SYMNAME);
+			cur_symtype = SRAMLOC;
+			cur_symbol->type = SRAMLOC;
+			initialize_symbol(cur_symbol);
+		}
+		reg_address
+		{
+			sram_or_scb_offset = cur_symbol->info.rinfo->address;
+		}
+		size
+		{
+			scb_or_sram_symbol = cur_symbol;
+		}
+		scb_or_sram_attributes
+	'}'
+		{
+			cur_symbol = NULL;
+			scb_or_sram_symbol = NULL;
+		}
+;
+
+scb:
+	T_SCB '{'
+		{
+			cur_symbol = symtable_get(SCB_SYMNAME);
+			cur_symtype = SCBLOC;
+			if (cur_symbol->type != UNINITIALIZED) {
+				stop("Only one SRAM definition allowed",
+				     EX_SOFTWARE);
+				/* NOTREACHED */
+			}
+			cur_symbol->type = SCBLOC;
+			initialize_symbol(cur_symbol);
+			/* 64 bytes of SCB space */
+			cur_symbol->info.rinfo->size = 64;
+		}
+		reg_address
+		{
+			sram_or_scb_offset = cur_symbol->info.rinfo->address;
+		}
+		size
+		{
+			scb_or_sram_symbol = cur_symbol;
+		}
+		scb_or_sram_attributes
+	'}'
+		{
+			cur_symbol = NULL;
+			scb_or_sram_symbol = NULL;
+		}
+;
+
+scb_or_sram_attributes:
+	/* NULL definition is okay */
+|	modes
+|	scb_or_sram_reg_list
+|	modes scb_or_sram_reg_list
+;
+
+scb_or_sram_reg_list:
+	reg_definition
+|	scb_or_sram_reg_list reg_definition
+;
+
+reg_symbol:
+	T_SYMBOL
+	{
+		process_register(&$1);
+		$$.symbol = $1;
+		$$.offset = 0;
+	}
+|	T_SYMBOL '[' T_SYMBOL ']'
+	{
+		process_register(&$1);
+		if ($3->type != CONST) {
+			stop("register offset must be a constant", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		if (($3->info.cinfo->value + 1) > $1->info.rinfo->size) {
+			stop("Accessing offset beyond range of register",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = $1;
+		$$.offset = $3->info.cinfo->value;
+	}
+|	T_SYMBOL '[' T_NUMBER ']'
+	{
+		process_register(&$1);
+		if (($3 + 1) > $1->info.rinfo->size) {
+			stop("Accessing offset beyond range of register",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = $1;
+		$$.offset = $3;
+	}
+|	T_A
+	{
+		if (accumulator.symbol == NULL) {
+			stop("No accumulator has been defined", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$.symbol = accumulator.symbol;
+		$$.offset = 0;
+	}
+;
+
+destination:
+	reg_symbol
+	{
+		test_writable_symbol($1.symbol);
+		$$ = $1;
+	}
+;
+
+immediate:
+	expression
+	{ $$ = $1; }
+;
+
+immediate_or_a:
+	expression
+	{
+		if ($1.value == 0 && is_download_const(&$1) == 0) {
+			snprintf(errbuf, sizeof(errbuf),
+				 "\nExpression evaluates to 0 and thus "
+				 "references the accumulator.\n "
+				 "If this is the desired effect, use 'A' "
+				 "instead.\n");
+			stop(errbuf, EX_DATAERR);
+		}
+		$$ = $1;
+	}
+|	T_A
+	{
+		SLIST_INIT(&$$.referenced_syms);
+		symlist_add(&$$.referenced_syms, accumulator.symbol,
+			    SYMLIST_INSERT_HEAD);
+		$$.value = 0;
+	}
+;
+
+source:
+	reg_symbol
+	{
+		test_readable_symbol($1.symbol);
+		$$ = $1;
+	}
+;
+
+opt_source:
+	{
+		$$.symbol = NULL;
+		$$.offset = 0;
+	}
+|	',' source
+	{ $$ = $2; }
+;
+
+ret:
+	{ $$ = 0; }
+|	T_RET
+	{ $$ = 1; }
+;
+
+set_src_mode:
+	T_SET_SRC_MODE T_NUMBER ';'
+	{
+		src_mode = $2;
+	}
+;
+
+set_dst_mode:
+	T_SET_DST_MODE T_NUMBER ';'
+	{
+		dst_mode = $2;
+	}
+;
+
+critical_section_start:
+	T_BEGIN_CS ';'
+	{
+		critical_section_t *cs;
+
+		if (in_critical_section != FALSE) {
+			stop("Critical Section within Critical Section",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		cs = cs_alloc();
+		cs->begin_addr = instruction_ptr;
+		in_critical_section = TRUE;
+	}
+;
+
+critical_section_end:
+	T_END_CS ';'
+	{
+		critical_section_t *cs;
+
+		if (in_critical_section == FALSE) {
+			stop("Unballanced 'end_cs'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		cs = TAILQ_LAST(&cs_tailq, cs_tailq);
+		cs->end_addr = instruction_ptr;
+		in_critical_section = FALSE;
+	}
+;
+
+export:
+	{ $$ = 0; }
+|	T_EXPORT
+	{ $$ = 1; }
+;
+
+label:
+	export T_SYMBOL ':'
+	{
+		if ($2->type != UNINITIALIZED) {
+			stop("Program label multiply defined", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$2->type = LABEL;
+		initialize_symbol($2);
+		$2->info.linfo->address = instruction_ptr;
+		$2->info.linfo->exported = $1;
+	}
+;
+
+address:
+	T_SYMBOL
+	{
+		$$.symbol = $1;
+		$$.offset = 0;
+	}
+|	T_SYMBOL '+' T_NUMBER
+	{
+		$$.symbol = $1;
+		$$.offset = $3;
+	}
+|	T_SYMBOL '-' T_NUMBER
+	{
+		$$.symbol = $1;
+		$$.offset = -$3;
+	}
+|	'.'
+	{
+		$$.symbol = NULL;
+		$$.offset = 0;
+	}
+|	'.' '+' T_NUMBER
+	{
+		$$.symbol = NULL;
+		$$.offset = $3;
+	}
+|	'.' '-' T_NUMBER
+	{
+		$$.symbol = NULL;
+		$$.offset = -$3;
+	}
+;
+
+conditional:
+	T_IF T_CEXPR '{'
+	{
+		scope_t *new_scope;
+
+		add_conditional($2);
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_IF;
+		new_scope->begin_addr = instruction_ptr;
+		new_scope->func_num = $2->info.condinfo->func_num;
+	}
+|	T_ELSE T_IF T_CEXPR '{'
+	{
+		scope_t *new_scope;
+		scope_t *scope_context;
+		scope_t *last_scope;
+
+		/*
+		 * Ensure that the previous scope is either an
+		 * if or and else if.
+		 */
+		scope_context = SLIST_FIRST(&scope_stack);
+		last_scope = TAILQ_LAST(&scope_context->inner_scope,
+					scope_tailq);
+		if (last_scope == NULL
+		 || last_scope->type == T_ELSE) {
+
+			stop("'else if' without leading 'if'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		add_conditional($3);
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_ELSE_IF;
+		new_scope->begin_addr = instruction_ptr;
+		new_scope->func_num = $3->info.condinfo->func_num;
+	}
+|	T_ELSE '{'
+	{
+		scope_t *new_scope;
+		scope_t *scope_context;
+		scope_t *last_scope;
+
+		/*
+		 * Ensure that the previous scope is either an
+		 * if or and else if.
+		 */
+		scope_context = SLIST_FIRST(&scope_stack);
+		last_scope = TAILQ_LAST(&scope_context->inner_scope,
+					scope_tailq);
+		if (last_scope == NULL
+		 || last_scope->type == SCOPE_ELSE) {
+
+			stop("'else' without leading 'if'", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		new_scope = scope_alloc();
+		new_scope->type = SCOPE_ELSE;
+		new_scope->begin_addr = instruction_ptr;
+	}
+;
+
+conditional:
+	'}'
+	{
+		scope_t *scope_context;
+
+		scope_context = SLIST_FIRST(&scope_stack);
+		if (scope_context->type == SCOPE_ROOT) {
+			stop("Unexpected '}' encountered", EX_DATAERR);
+			/* NOTREACHED */
+		}
+
+		scope_context->end_addr = instruction_ptr;
+
+		/* Pop the scope */
+		SLIST_REMOVE_HEAD(&scope_stack, scope_stack_links);
+
+		process_scope(scope_context);
+
+		if (SLIST_FIRST(&scope_stack) == NULL) {
+			stop("Unexpected '}' encountered", EX_DATAERR);
+			/* NOTREACHED */
+		}
+	}
+;
+
+f1_opcode:
+	T_AND { $$ = AIC_OP_AND; }
+|	T_XOR { $$ = AIC_OP_XOR; }
+|	T_ADD { $$ = AIC_OP_ADD; }
+|	T_ADC { $$ = AIC_OP_ADC; }
+;
+
+code:
+	f1_opcode destination ',' immediate_or_a opt_source ret ';'
+	{
+		format_1_instr($1, &$2, &$4, &$5, $6);
+	}
+;
+
+code:
+	T_OR reg_symbol ',' immediate_or_a opt_source ret ';'
+	{
+		format_1_instr(AIC_OP_OR, &$2, &$4, &$5, $6);
+	}
+;
+
+code:
+	T_INC destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_DEC destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, -1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_CLC ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, -1);
+		format_1_instr(AIC_OP_ADD, &none, &immed, &allzeros, $2);
+	}
+|	T_CLC T_MVI destination ',' immediate_or_a ret ';'
+	{
+		format_1_instr(AIC_OP_ADD, &$3, &$5, &allzeros, $6);
+	}
+;
+
+code:
+	T_STC ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &none, &immed, &allones, $2);
+	}
+|	T_STC destination ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_ADD, &$2, &immed, &allones, $3);
+	}
+;
+
+code:
+	T_BMOV destination ',' source ',' immediate ret ';'
+	{
+		format_1_instr(AIC_OP_BMOV, &$2, &$6, &$4, $7);
+	}
+;
+
+code:
+	T_MOV destination ',' source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 1);
+		format_1_instr(AIC_OP_BMOV, &$2, &immed, &$4, $5);
+	}
+;
+
+code:
+	T_MVI destination ',' immediate ret ';'
+	{
+		if ($4.value == 0
+		 && is_download_const(&$4) == 0) {
+			expression_t immed;
+
+			/*
+			 * Allow move immediates of 0 so that macros,
+			 * that can't know the immediate's value and
+			 * otherwise compensate, still work.
+			 */
+			make_expression(&immed, 1);
+			format_1_instr(AIC_OP_BMOV, &$2, &immed, &allzeros, $5);
+		} else {
+			format_1_instr(AIC_OP_OR, &$2, &$4, &allzeros, $5);
+		}
+	}
+;
+
+code:
+	T_NOT destination opt_source ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_XOR, &$2, &immed, &$3, $4);
+	}
+;
+
+code:
+	T_CLR destination ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &$2, &immed, &allzeros, $3);
+	}
+;
+
+code:
+	T_NOP ret ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, $2);
+	}
+;
+
+code:
+	T_RET ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0xff);
+		format_1_instr(AIC_OP_AND, &none, &immed, &allzeros, TRUE);
+	}
+;
+
+	/*
+	 * This grammer differs from the one in the aic7xxx
+	 * reference manual since the grammer listed there is
+	 * ambiguous and causes a shift/reduce conflict.
+	 * It also seems more logical as the "immediate"
+	 * argument is listed as the second arg like the
+	 * other formats.
+	 */
+
+f2_opcode:
+	T_SHL { $$ = AIC_OP_SHL; }
+|	T_SHR { $$ = AIC_OP_SHR; }
+|	T_ROL { $$ = AIC_OP_ROL; }
+|	T_ROR { $$ = AIC_OP_ROR; }
+;
+
+code:
+	f2_opcode destination ',' expression opt_source ret ';'
+	{
+		format_2_instr($1, &$2, &$4, &$5, $6);
+	}
+;
+
+jmp_jc_jnc_call:
+	T_JMP	{ $$ = AIC_OP_JMP; }
+|	T_JC	{ $$ = AIC_OP_JC; }
+|	T_JNC	{ $$ = AIC_OP_JNC; }
+|	T_CALL	{ $$ = AIC_OP_CALL; }
+;
+
+jz_jnz:
+	T_JZ	{ $$ = AIC_OP_JZ; }
+|	T_JNZ	{ $$ = AIC_OP_JNZ; }
+;
+
+je_jne:
+	T_JE	{ $$ = AIC_OP_JE; }
+|	T_JNE	{ $$ = AIC_OP_JNE; }
+;
+
+code:
+	jmp_jc_jnc_call address ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0);
+		format_3_instr($1, &sindex, &immed, &$2);
+	}
+;
+
+code:
+	T_OR reg_symbol ',' immediate jmp_jc_jnc_call address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_TEST source ',' immediate_or_a jz_jnz address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_CMP source ',' immediate_or_a je_jne address ';'
+	{
+		format_3_instr($5, &$2, &$4, &$6);
+	}
+;
+
+code:
+	T_MOV source jmp_jc_jnc_call address ';'
+	{
+		expression_t immed;
+
+		make_expression(&immed, 0);
+		format_3_instr($3, &$2, &immed, &$4);
+	}
+;
+
+code:
+	T_MVI immediate jmp_jc_jnc_call address ';'
+	{
+		format_3_instr($3, &allzeros, &$2, &$4);
+	}
+;
+
+%%
+
+static void
+process_field(int field_type, symbol_t *sym, int value)
+{
+	/*
+	 * Add the current register to its
+	 * symbol list, if it already exists,
+	 * warn if we are setting it to a
+	 * different value, or in the bit to
+	 * the "allowed bits" of this register.
+	 */
+	if (sym->type == UNINITIALIZED) {
+		sym->type = field_type;
+		initialize_symbol(sym);
+		sym->info.finfo->value = value;
+		if (field_type != ENUM_ENTRY) {
+			if (field_type != MASK && value == 0) {
+				stop("Empty Field, or Enum", EX_DATAERR);
+				/* NOTREACHED */
+			}
+			sym->info.finfo->value = value;
+			sym->info.finfo->mask = value;
+		} else if (field_symbol != NULL) {
+			sym->info.finfo->mask = field_symbol->info.finfo->value;
+		} else {
+			sym->info.finfo->mask = 0xFF;
+		}
+	} else if (sym->type != field_type) {
+		stop("Field definition mirrors a definition of the same "
+		     " name, but a different type", EX_DATAERR);
+		/* NOTREACHED */
+	} else if (value != sym->info.finfo->value) {
+		stop("Field redefined with a conflicting value", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	/* Fail if this symbol is already listed */
+	if (symlist_search(&(sym->info.finfo->symrefs),
+			   cur_symbol->name) != NULL) {
+		stop("Field defined multiple times for register", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	symlist_add(&(sym->info.finfo->symrefs), cur_symbol,
+		    SYMLIST_INSERT_HEAD);
+	cur_symbol->info.rinfo->valid_bitmask |= sym->info.finfo->mask;
+	cur_symbol->info.rinfo->typecheck_masks = TRUE;
+	symlist_add(&(cur_symbol->info.rinfo->fields), sym, SYMLIST_SORT);
+}
+
+static void
+initialize_symbol(symbol_t *symbol)
+{
+	switch (symbol->type) {
+	case UNINITIALIZED:
+		stop("Call to initialize_symbol with type field unset",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+	case REGISTER:
+	case SRAMLOC:
+	case SCBLOC:
+		symbol->info.rinfo =
+		    (struct reg_info *)malloc(sizeof(struct reg_info));
+		if (symbol->info.rinfo == NULL) {
+			stop("Can't create register info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.rinfo, 0,
+		       sizeof(struct reg_info));
+		SLIST_INIT(&(symbol->info.rinfo->fields));
+		/*
+		 * Default to allowing access in all register modes
+		 * or to the mode specified by the SCB or SRAM space
+		 * we are in.
+		 */
+		if (scb_or_sram_symbol != NULL)
+			symbol->info.rinfo->modes =
+			    scb_or_sram_symbol->info.rinfo->modes;
+		else
+			symbol->info.rinfo->modes = ~0;
+		break;
+	case ALIAS:
+		symbol->info.ainfo =
+		    (struct alias_info *)malloc(sizeof(struct alias_info));
+		if (symbol->info.ainfo == NULL) {
+			stop("Can't create alias info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.ainfo, 0,
+		       sizeof(struct alias_info));
+		break;
+	case MASK:
+	case FIELD:
+	case ENUM:
+	case ENUM_ENTRY:
+		symbol->info.finfo =
+		    (struct field_info *)malloc(sizeof(struct field_info));
+		if (symbol->info.finfo == NULL) {
+			stop("Can't create field info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.finfo, 0, sizeof(struct field_info));
+		SLIST_INIT(&(symbol->info.finfo->symrefs));
+		break;
+	case CONST:
+	case DOWNLOAD_CONST:
+		symbol->info.cinfo =
+		    (struct const_info *)malloc(sizeof(struct const_info));
+		if (symbol->info.cinfo == NULL) {
+			stop("Can't create alias info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.cinfo, 0,
+		       sizeof(struct const_info));
+		break;
+	case LABEL:
+		symbol->info.linfo =
+		    (struct label_info *)malloc(sizeof(struct label_info));
+		if (symbol->info.linfo == NULL) {
+			stop("Can't create label info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.linfo, 0,
+		       sizeof(struct label_info));
+		break;
+	case CONDITIONAL:
+		symbol->info.condinfo =
+		    (struct cond_info *)malloc(sizeof(struct cond_info));
+		if (symbol->info.condinfo == NULL) {
+			stop("Can't create conditional info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.condinfo, 0,
+		       sizeof(struct cond_info));
+		break;
+	case MACRO:
+		symbol->info.macroinfo = 
+		    (struct macro_info *)malloc(sizeof(struct macro_info));
+		if (symbol->info.macroinfo == NULL) {
+			stop("Can't create macro info", EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		memset(symbol->info.macroinfo, 0,
+		       sizeof(struct macro_info));
+		STAILQ_INIT(&symbol->info.macroinfo->args);
+		break;
+	default:
+		stop("Call to initialize_symbol with invalid symbol type",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+	}
+}
+
+static void
+add_macro_arg(const char *argtext, int argnum)
+{
+	struct macro_arg *marg;
+	int i;
+	int retval;
+		
+
+	if (cur_symbol == NULL || cur_symbol->type != MACRO) {
+		stop("Invalid current symbol for adding macro arg",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+
+	marg = (struct macro_arg *)malloc(sizeof(*marg));
+	if (marg == NULL) {
+		stop("Can't create macro_arg structure", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	marg->replacement_text = NULL;
+	retval = snprintf(regex_pattern, sizeof(regex_pattern),
+			  "[^-/A-Za-z0-9_](%s)([^-/A-Za-z0-9_]|$)",
+			  argtext);
+	if (retval >= sizeof(regex_pattern)) {
+		stop("Regex text buffer too small for arg",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	retval = regcomp(&marg->arg_regex, regex_pattern, REG_EXTENDED);
+	if (retval != 0) {
+		stop("Regex compilation failed", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	STAILQ_INSERT_TAIL(&cur_symbol->info.macroinfo->args, marg, links);
+}
+
+static void
+add_macro_body(const char *bodytext)
+{
+	if (cur_symbol == NULL || cur_symbol->type != MACRO) {
+		stop("Invalid current symbol for adding macro arg",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	cur_symbol->info.macroinfo->body = strdup(bodytext);
+	if (cur_symbol->info.macroinfo->body == NULL) {
+		stop("Can't duplicate macro body text", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+}
+
+static void
+process_register(symbol_t **p_symbol)
+{
+	symbol_t *symbol = *p_symbol;
+
+	if (symbol->type == UNINITIALIZED) {
+		snprintf(errbuf, sizeof(errbuf), "Undefined register %s",
+			 symbol->name);
+		stop(errbuf, EX_DATAERR);
+		/* NOTREACHED */
+	} else if (symbol->type == ALIAS) {
+		*p_symbol = symbol->info.ainfo->parent;
+	} else if ((symbol->type != REGISTER)
+		&& (symbol->type != SCBLOC)
+		&& (symbol->type != SRAMLOC)) {
+		snprintf(errbuf, sizeof(errbuf),
+			 "Specified symbol %s is not a register",
+			 symbol->name);
+		stop(errbuf, EX_DATAERR);
+	}
+}
+
+static void
+format_1_instr(int opcode, symbol_ref_t *dest, expression_t *immed,
+	       symbol_ref_t *src, int ret)
+{
+	struct instruction *instr;
+	struct ins_format1 *f1_instr;
+
+	if (src->symbol == NULL)
+		src = dest;
+
+	/* Test register permissions */
+	test_writable_symbol(dest->symbol);
+	test_readable_symbol(src->symbol);
+
+	/* Ensure that immediate makes sense for this destination */
+	type_check(dest->symbol, immed, opcode);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f1_instr = &instr->format.format1;
+	f1_instr->ret = ret ? 1 : 0;
+	f1_instr->opcode = opcode;
+	f1_instr->destination = dest->symbol->info.rinfo->address
+			      + dest->offset;
+	f1_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	f1_instr->immediate = immed->value;
+
+	if (is_download_const(immed))
+		f1_instr->parity = 1;
+	else if (dest->symbol == mode_ptr.symbol) {
+		u_int src_value;
+		u_int dst_value;
+
+		/*
+		 * Attempt to update mode information if
+		 * we are operating on the mode register.
+		 */
+		if (src->symbol == allones.symbol)
+			src_value = 0xFF;
+		else if (src->symbol == allzeros.symbol)
+			src_value = 0;
+		else if (src->symbol == mode_ptr.symbol)
+			src_value = (dst_mode << 4) | src_mode;
+		else
+			goto cant_update;
+
+		switch (opcode) {
+		case AIC_OP_AND:
+			dst_value = src_value & immed->value;
+			break;
+		case AIC_OP_XOR:
+			dst_value = src_value ^ immed->value;
+			break;
+		case AIC_OP_ADD:
+			dst_value = (src_value + immed->value) & 0xFF;
+			break;
+		case AIC_OP_OR:
+			dst_value = src_value | immed->value;
+			break;
+		case AIC_OP_BMOV:
+			dst_value = src_value;
+			break;
+		default:
+			goto cant_update;
+		}
+		src_mode = dst_value & 0xF;
+		dst_mode = (dst_value >> 4) & 0xF;
+	}
+
+cant_update:
+	symlist_free(&immed->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+format_2_instr(int opcode, symbol_ref_t *dest, expression_t *places,
+	       symbol_ref_t *src, int ret)
+{
+	struct instruction *instr;
+	struct ins_format2 *f2_instr;
+	uint8_t shift_control;
+
+	if (src->symbol == NULL)
+		src = dest;
+
+	/* Test register permissions */
+	test_writable_symbol(dest->symbol);
+	test_readable_symbol(src->symbol);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f2_instr = &instr->format.format2;
+	f2_instr->ret = ret ? 1 : 0;
+	f2_instr->opcode = AIC_OP_ROL;
+	f2_instr->destination = dest->symbol->info.rinfo->address
+			      + dest->offset;
+	f2_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	if (places->value > 8 || places->value <= 0) {
+		stop("illegal shift value", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	switch (opcode) {
+	case AIC_OP_SHL:
+		if (places->value == 8)
+			shift_control = 0xf0;
+		else
+			shift_control = (places->value << 4) | places->value;
+		break;
+	case AIC_OP_SHR:
+		if (places->value == 8) {
+			shift_control = 0xf8;
+		} else {
+			shift_control = (places->value << 4)
+				      | (8 - places->value)
+				      | 0x08;
+		}
+		break;
+	case AIC_OP_ROL:
+		shift_control = places->value & 0x7;
+		break;
+	case AIC_OP_ROR:
+		shift_control = (8 - places->value) | 0x08;
+		break;
+	default:
+		shift_control = 0; /* Quiet Compiler */
+		stop("Invalid shift operation specified", EX_SOFTWARE);
+		/* NOTREACHED */
+		break;
+	};
+	f2_instr->shift_control = shift_control;
+	symlist_free(&places->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+format_3_instr(int opcode, symbol_ref_t *src,
+	       expression_t *immed, symbol_ref_t *address)
+{
+	struct instruction *instr;
+	struct ins_format3 *f3_instr;
+	int addr;
+
+	/* Test register permissions */
+	test_readable_symbol(src->symbol);
+
+	/* Ensure that immediate makes sense for this source */
+	type_check(src->symbol, immed, opcode);
+
+	/* Allocate sequencer space for the instruction and fill it out */
+	instr = seq_alloc();
+	f3_instr = &instr->format.format3;
+	if (address->symbol == NULL) {
+		/* 'dot' referrence.  Use the current instruction pointer */
+		addr = instruction_ptr + address->offset;
+	} else if (address->symbol->type == UNINITIALIZED) {
+		/* forward reference */
+		addr = address->offset;
+		instr->patch_label = address->symbol;
+	} else
+		addr = address->symbol->info.linfo->address + address->offset;
+	f3_instr->opcode = opcode;
+	f3_instr->address = addr;
+	f3_instr->source = src->symbol->info.rinfo->address
+			 + src->offset;
+	f3_instr->immediate = immed->value;
+
+	if (is_download_const(immed))
+		f3_instr->parity = 1;
+
+	symlist_free(&immed->referenced_syms);
+	instruction_ptr++;
+}
+
+static void
+test_readable_symbol(symbol_t *symbol)
+{
+	
+	if ((symbol->info.rinfo->modes & (0x1 << src_mode)) == 0) {
+		snprintf(errbuf, sizeof(errbuf),
+			"Register %s unavailable in source reg mode %d",
+			symbol->name, src_mode);
+		stop(errbuf, EX_DATAERR);
+	}
+
+	if (symbol->info.rinfo->mode == WO) {
+		stop("Write Only register specified as source",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+}
+
+static void
+test_writable_symbol(symbol_t *symbol)
+{
+	
+	if ((symbol->info.rinfo->modes & (0x1 << dst_mode)) == 0) {
+		snprintf(errbuf, sizeof(errbuf),
+			"Register %s unavailable in destination reg mode %d",
+			symbol->name, dst_mode);
+		stop(errbuf, EX_DATAERR);
+	}
+
+	if (symbol->info.rinfo->mode == RO) {
+		stop("Read Only register specified as destination",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+}
+
+static void
+type_check(symbol_t *symbol, expression_t *expression, int opcode)
+{
+	symbol_node_t *node;
+	int and_op;
+
+	and_op = FALSE;
+	if (opcode == AIC_OP_AND || opcode == AIC_OP_JNZ || AIC_OP_JZ)
+		and_op = TRUE;
+
+	/*
+	 * Make sure that we aren't attempting to write something
+	 * that hasn't been defined.  If this is an and operation,
+	 * this is a mask, so "undefined" bits are okay.
+	 */
+	if (and_op == FALSE
+	 && (expression->value & ~symbol->info.rinfo->valid_bitmask) != 0) {
+		snprintf(errbuf, sizeof(errbuf),
+			 "Invalid bit(s) 0x%x in immediate written to %s",
+			 expression->value & ~symbol->info.rinfo->valid_bitmask,
+			 symbol->name);
+		stop(errbuf, EX_DATAERR);
+		/* NOTREACHED */
+	}
+
+	/*
+	 * Now make sure that all of the symbols referenced by the
+	 * expression are defined for this register.
+	 */
+	if (symbol->info.rinfo->typecheck_masks != FALSE) {
+		for(node = expression->referenced_syms.slh_first;
+		    node != NULL;
+		    node = node->links.sle_next) {
+			if ((node->symbol->type == MASK
+			  || node->symbol->type == FIELD
+			  || node->symbol->type == ENUM
+			  || node->symbol->type == ENUM_ENTRY)
+			 && symlist_search(&node->symbol->info.finfo->symrefs,
+					   symbol->name) == NULL) {
+				snprintf(errbuf, sizeof(errbuf),
+					 "Invalid field or mask %s "
+					 "for register %s",
+					 node->symbol->name, symbol->name);
+				stop(errbuf, EX_DATAERR);
+				/* NOTREACHED */
+			}
+		}
+	}
+}
+
+static void
+make_expression(expression_t *immed, int value)
+{
+	SLIST_INIT(&immed->referenced_syms);
+	immed->value = value & 0xff;
+}
+
+static void
+add_conditional(symbol_t *symbol)
+{
+	static int numfuncs;
+
+	if (numfuncs == 0) {
+		/* add a special conditional, "0" */
+		symbol_t *false_func;
+
+		false_func = symtable_get("0");
+		if (false_func->type != UNINITIALIZED) {
+			stop("Conditional expression '0' "
+			     "conflicts with a symbol", EX_DATAERR);
+			/* NOTREACHED */
+		}
+		false_func->type = CONDITIONAL;
+		initialize_symbol(false_func);
+		false_func->info.condinfo->func_num = numfuncs++;
+		symlist_add(&patch_functions, false_func, SYMLIST_INSERT_HEAD);
+	}
+
+	/* This condition has occurred before */
+	if (symbol->type == CONDITIONAL)
+		return;
+
+	if (symbol->type != UNINITIALIZED) {
+		stop("Conditional expression conflicts with a symbol",
+		     EX_DATAERR);
+		/* NOTREACHED */
+	}
+
+	symbol->type = CONDITIONAL;
+	initialize_symbol(symbol);
+	symbol->info.condinfo->func_num = numfuncs++;
+	symlist_add(&patch_functions, symbol, SYMLIST_INSERT_HEAD);
+}
+
+static void
+add_version(const char *verstring)
+{
+	const char prefix[] = " * ";
+	int newlen;
+	int oldlen;
+
+	newlen = strlen(verstring) + strlen(prefix);
+	oldlen = 0;
+	if (versions != NULL)
+		oldlen = strlen(versions);
+	versions = realloc(versions, newlen + oldlen + 2);
+	if (versions == NULL)
+		stop("Can't allocate version string", EX_SOFTWARE);
+	strcpy(&versions[oldlen], prefix);
+	strcpy(&versions[oldlen + strlen(prefix)], verstring);
+	versions[newlen + oldlen] = '\n';
+	versions[newlen + oldlen + 1] = '\0';
+}
+
+void
+yyerror(const char *string)
+{
+	stop(string, EX_DATAERR);
+}
+
+static int
+is_download_const(expression_t *immed)
+{
+	if ((immed->referenced_syms.slh_first != NULL)
+	 && (immed->referenced_syms.slh_first->symbol->type == DOWNLOAD_CONST))
+		return (TRUE);
+
+	return (FALSE);
+}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
new file mode 100644
index 0000000..3e80f07
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_insformat.h
@@ -0,0 +1,131 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_insformat.h#11 $
+ *
+ * $FreeBSD$
+ */
+
+struct ins_format1 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	immediate	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			immediate	: 8;
+#endif
+};
+
+struct ins_format2 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	shift_control	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			shift_control	: 8;
+#endif
+};
+
+struct ins_format3 {
+#if BYTE_ORDER == LITTLE_ENDIAN
+	uint32_t	immediate	: 8,
+			source		: 9,
+			address		: 10,
+			opcode		: 4,
+			parity		: 1;
+#else
+	uint32_t	parity		: 1,
+			opcode		: 4,
+			address		: 10,
+			source		: 9,
+			immediate	: 8;
+#endif
+};
+
+union ins_formats {
+		struct ins_format1 format1;
+		struct ins_format2 format2;
+		struct ins_format3 format3;
+		uint8_t		   bytes[4];
+		uint32_t	   integer;
+};
+struct instruction {
+	union	ins_formats format;
+	u_int	srcline;
+	struct symbol *patch_label;
+	STAILQ_ENTRY(instruction) links;
+};
+
+#define	AIC_OP_OR	0x0
+#define	AIC_OP_AND	0x1
+#define AIC_OP_XOR	0x2
+#define	AIC_OP_ADD	0x3
+#define	AIC_OP_ADC	0x4
+#define	AIC_OP_ROL	0x5
+#define	AIC_OP_BMOV	0x6
+
+#define	AIC_OP_JMP	0x8
+#define AIC_OP_JC	0x9
+#define AIC_OP_JNC	0xa
+#define AIC_OP_CALL	0xb
+#define	AIC_OP_JNE	0xc
+#define	AIC_OP_JNZ	0xd
+#define	AIC_OP_JE	0xe
+#define	AIC_OP_JZ	0xf
+
+/* Pseudo Ops */
+#define	AIC_OP_SHL	0x10
+#define	AIC_OP_SHR	0x20
+#define	AIC_OP_ROR	0x30
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
new file mode 100644
index 0000000..439f760
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y
@@ -0,0 +1,164 @@
+%{
+/*
+ * Sub-parser for macro invocation in the Aic7xxx SCSI
+ * Host adapter sequencer assembler.
+ *
+ * Copyright (c) 2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_gram.y#5 $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_insformat.h"
+
+static symbol_t *macro_symbol;
+
+static void add_macro_arg(const char *argtext, int position);
+
+%}
+
+%union {
+	int		value;
+	char		*str;
+	symbol_t	*sym;
+}
+
+
+%token <str> T_ARG
+
+%token <sym> T_SYMBOL
+
+%type <value> macro_arglist
+
+%%
+
+macrocall:
+	T_SYMBOL '('
+	{
+		macro_symbol = $1;
+	}
+	macro_arglist ')'
+	{
+		if (macro_symbol->info.macroinfo->narg != $4) {
+			printf("Narg == %d", macro_symbol->info.macroinfo->narg);
+			stop("Too few arguments for macro invocation",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		macro_symbol = NULL;
+		YYACCEPT;
+	}
+;
+
+macro_arglist:
+	{
+		/* Macros can take 0 arguments */
+		$$ = 0;
+	}
+|	T_ARG
+	{
+		$$ = 1;
+		add_macro_arg($1, 1);
+	}
+|	macro_arglist ',' T_ARG
+	{
+		if ($1 == 0) {
+			stop("Comma without preceeding argument in arg list",
+			     EX_DATAERR);
+			/* NOTREACHED */
+		}
+		$$ = $1 + 1;
+		add_macro_arg($3, $$);
+	}
+;
+
+%%
+
+static void
+add_macro_arg(const char *argtext, int argnum)
+{
+	struct macro_arg *marg;
+	int i;
+
+	if (macro_symbol == NULL || macro_symbol->type != MACRO) {
+		stop("Invalid current symbol for adding macro arg",
+		     EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	/*
+	 * Macro Invocation.  Find the appropriate argument and fill
+	 * in the replace ment text for this call.
+	 */
+	i = 0;
+	STAILQ_FOREACH(marg, &macro_symbol->info.macroinfo->args, links) {
+		i++;
+		if (i == argnum)
+			break;
+	}
+	if (marg == NULL) {
+		stop("Too many arguments for macro invocation", EX_DATAERR);
+		/* NOTREACHED */
+	}
+	marg->replacement_text = strdup(argtext);
+	if (marg->replacement_text == NULL) {
+		stop("Unable to replicate replacement text", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+}
+
+void
+mmerror(const char *string)
+{
+	stop(string, EX_DATAERR);
+}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
new file mode 100644
index 0000000..f06e703
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_scan.l
@@ -0,0 +1,156 @@
+%{
+/*
+ * Sub-Lexical Analyzer for macro invokation in 
+ * the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 2001 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_macro_scan.l#8 $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_macro_gram.h"
+
+#define MAX_STR_CONST 4096
+static char string_buf[MAX_STR_CONST];
+static char *string_buf_ptr;
+static int  parren_count;
+static char buf[255];
+%}
+
+WORD		[A-Za-z_][-A-Za-z_0-9]*
+SPACE		[ \t]+
+MCARG		[^(), \t]+
+
+%x ARGLIST
+
+%%
+\n			{
+				++yylineno;
+			}
+\r			;
+<ARGLIST>{SPACE}	;
+<ARGLIST>\(		{
+				parren_count++;
+				if (parren_count == 1) {
+					string_buf_ptr = string_buf;
+					return ('(');
+				}
+				*string_buf_ptr++ = '(';
+			}
+<ARGLIST>\)		{
+				if (parren_count == 1) {
+					if (string_buf_ptr != string_buf) {
+						/*
+						 * Return an argument and
+						 * rescan this parren so we
+						 * can return it as well.
+						 */
+						*string_buf_ptr = '\0';
+						mmlval.str = string_buf;
+						string_buf_ptr = string_buf;
+						unput(')');
+						return T_ARG;
+					}
+					BEGIN INITIAL;
+					return (')');
+				}
+				parren_count--;
+				*string_buf_ptr++ = ')';
+			}
+<ARGLIST>{MCARG}	{
+				char *yptr;
+
+				yptr = mmtext;
+				while (*yptr)
+					*string_buf_ptr++ = *yptr++;
+			}
+<ARGLIST>\,		{
+				if (string_buf_ptr != string_buf) {
+					/*
+					 * Return an argument and
+					 * rescan this comma so we
+					 * can return it as well.
+					 */
+					*string_buf_ptr = '\0';
+					mmlval.str = string_buf;
+					string_buf_ptr = string_buf;
+					unput(',');
+					return T_ARG;
+				}
+				return ',';
+			}
+{WORD}[(]		{
+				/* May be a symbol or a macro invocation. */
+				mmlval.sym = symtable_get(mmtext);
+				if (mmlval.sym->type != MACRO) {
+					stop("Expecting Macro Name",
+					     EX_DATAERR);
+				}
+				unput('(');
+				parren_count = 0;
+				BEGIN ARGLIST;
+				return T_SYMBOL;
+			}
+.			{ 
+				snprintf(buf, sizeof(buf), "Invalid character "
+					 "'%c'", mmtext[0]);
+				stop(buf, EX_DATAERR);
+			}
+%%
+
+int
+mmwrap()
+{
+	stop("EOF encountered in macro call", EX_DATAERR);
+}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
new file mode 100644
index 0000000..45c0b23
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_scan.l
@@ -0,0 +1,607 @@
+%{
+/*
+ * Lexical Analyzer for the Aic7xxx SCSI Host adapter sequencer assembler.
+ *
+ * Copyright (c) 1997, 1998, 2000 Justin T. Gibbs.
+ * Copyright (c) 2001, 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_scan.l#19 $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#include <inttypes.h>
+#include <limits.h>
+#include <regex.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+#include "aicasm.h"
+#include "aicasm_symbol.h"
+#include "aicasm_gram.h"
+
+/* This is used for macro body capture too, so err on the large size. */
+#define MAX_STR_CONST 4096
+static char string_buf[MAX_STR_CONST];
+static char *string_buf_ptr;
+static int  parren_count;
+static int  quote_count;
+static char buf[255];
+%}
+
+PATH		([/]*[-A-Za-z0-9_.])+
+WORD		[A-Za-z_][-A-Za-z_0-9]*
+SPACE		[ \t]+
+MCARG		[^(), \t]+
+MBODY		((\\[^\n])*[^\n\\]*)+
+
+%x COMMENT
+%x CEXPR
+%x INCLUDE
+%x STRING
+%x MACRODEF
+%x MACROARGLIST
+%x MACROCALLARGS
+%x MACROBODY
+
+%%
+\n			{ ++yylineno; }
+\r			;
+"/*"			{ BEGIN COMMENT;  /* Enter comment eating state */ }
+<COMMENT>"/*"		{ fprintf(stderr, "Warning! Comment within comment."); }
+<COMMENT>\n		{ ++yylineno; }
+<COMMENT>[^*/\n]*	;
+<COMMENT>"*"+[^*/\n]*	;
+<COMMENT>"/"+[^*/\n]*	;
+<COMMENT>"*"+"/"	{ BEGIN INITIAL; }
+if[ \t]*\(		{
+				string_buf_ptr = string_buf;
+				parren_count = 1;
+				BEGIN CEXPR;
+				return T_IF;
+			}
+<CEXPR>\(		{	*string_buf_ptr++ = '('; parren_count++; }
+<CEXPR>\)		{
+				parren_count--;
+				if (parren_count == 0) {
+					/* All done */
+					BEGIN INITIAL;
+					*string_buf_ptr = '\0';
+					yylval.sym = symtable_get(string_buf);
+					return T_CEXPR;
+				} else {
+					*string_buf_ptr++ = ')';
+				}
+			}
+<CEXPR>\n		{ ++yylineno; }
+<CEXPR>\r		;
+<CEXPR>[^()\n]+	{
+				char *yptr;
+
+				yptr = yytext;
+				while (*yptr != '\0') {
+					/* Remove duplicate spaces */
+					if (*yptr == '\t')
+						*yptr = ' ';
+					if (*yptr == ' '
+					 && string_buf_ptr != string_buf
+					 && string_buf_ptr[-1] == ' ')
+						yptr++;
+					else 
+						*string_buf_ptr++ = *yptr++;
+				}
+			}
+
+VERSION			{ return T_VERSION; }
+PREFIX			{ return T_PREFIX; }
+PATCH_ARG_LIST		{ return T_PATCH_ARG_LIST; }
+\"			{
+				string_buf_ptr = string_buf;
+				BEGIN STRING;
+			}
+<STRING>[^"]+		{
+				char *yptr;
+
+				yptr = yytext;
+				while (*yptr)
+					*string_buf_ptr++ = *yptr++;
+			}
+<STRING>\"		{
+				/* All done */
+				BEGIN INITIAL;
+				*string_buf_ptr = '\0';
+				yylval.str = string_buf;
+				return T_STRING;
+			}
+{SPACE}			 ;
+
+	/* Register/SCB/SRAM definition keywords */
+export			{ return T_EXPORT; }
+register		{ return T_REGISTER; }
+const			{ yylval.value = FALSE; return T_CONST; }
+download		{ return T_DOWNLOAD; }
+address			{ return T_ADDRESS; }
+access_mode		{ return T_ACCESS_MODE; }
+modes			{ return T_MODES; }
+RW|RO|WO		{
+				 if (strcmp(yytext, "RW") == 0)
+					yylval.value = RW;
+				 else if (strcmp(yytext, "RO") == 0)
+					yylval.value = RO;
+				 else
+					yylval.value = WO;
+				 return T_MODE;
+			}
+BEGIN_CRITICAL		{ return T_BEGIN_CS; }
+END_CRITICAL		{ return T_END_CS; }
+SET_SRC_MODE		{ return T_SET_SRC_MODE; }
+SET_DST_MODE		{ return T_SET_DST_MODE; }
+field			{ return T_FIELD; }
+enum			{ return T_ENUM; }
+mask			{ return T_MASK; }
+alias			{ return T_ALIAS; }
+size			{ return T_SIZE; }
+scb			{ return T_SCB; }
+scratch_ram		{ return T_SRAM; }
+accumulator		{ return T_ACCUM; }
+mode_pointer		{ return T_MODE_PTR; }
+allones			{ return T_ALLONES; }
+allzeros		{ return T_ALLZEROS; }
+none			{ return T_NONE; }
+sindex			{ return T_SINDEX; }
+A			{ return T_A; }
+
+	/* Opcodes */
+shl			{ return T_SHL; }
+shr			{ return T_SHR; }
+ror			{ return T_ROR; }
+rol			{ return T_ROL; }
+mvi			{ return T_MVI; }
+mov			{ return T_MOV; }
+clr			{ return T_CLR; }
+jmp			{ return T_JMP; }
+jc			{ return T_JC;	}
+jnc			{ return T_JNC;	}
+je			{ return T_JE;	}
+jne			{ return T_JNE;	}
+jz			{ return T_JZ;	}
+jnz			{ return T_JNZ;	}
+call			{ return T_CALL; }
+add			{ return T_ADD; }
+adc			{ return T_ADC; }
+bmov			{ return T_BMOV; }
+inc			{ return T_INC; }
+dec			{ return T_DEC; }
+stc			{ return T_STC;	}
+clc			{ return T_CLC; }
+cmp			{ return T_CMP;	}
+not			{ return T_NOT;	}
+xor			{ return T_XOR;	}
+test			{ return T_TEST;}
+and			{ return T_AND;	}
+or			{ return T_OR;	}
+ret			{ return T_RET; }
+nop			{ return T_NOP; }
+else			{ return T_ELSE; }
+
+	/* Allowed Symbols */
+\<\<			{ return T_EXPR_LSHIFT; }
+\>\>			{ return T_EXPR_RSHIFT; }
+[-+,:()~|&."{};<>[\]/*!=] { return yytext[0]; }
+
+	/* Number processing */
+0[0-7]*			{
+				yylval.value = strtol(yytext, NULL, 8);
+				return T_NUMBER;
+			}
+
+0[xX][0-9a-fA-F]+	{
+				yylval.value = strtoul(yytext + 2, NULL, 16);
+				return T_NUMBER;
+			}
+
+[1-9][0-9]*		{
+				yylval.value = strtol(yytext, NULL, 10);
+				return T_NUMBER;
+			}
+	/* Include Files */
+#include{SPACE}		{
+				BEGIN INCLUDE;
+				quote_count = 0;
+				return T_INCLUDE;
+			}
+<INCLUDE>[<]		{ return yytext[0]; }
+<INCLUDE>[>]		{ BEGIN INITIAL; return yytext[0]; }
+<INCLUDE>[\"]		{
+				if (quote_count != 0)
+					BEGIN INITIAL;
+				quote_count++;
+				return yytext[0];
+			}
+<INCLUDE>{PATH}		{
+				char *yptr;
+
+				yptr = yytext;
+				string_buf_ptr = string_buf;
+				while (*yptr)
+					*string_buf_ptr++ = *yptr++;
+				yylval.str = string_buf;
+				*string_buf_ptr = '\0';
+				return T_PATH;
+			}
+<INCLUDE>.		{ stop("Invalid include line", EX_DATAERR); }
+#define{SPACE}		{
+				BEGIN MACRODEF;
+				return T_DEFINE;
+			}
+<MACRODEF>{WORD}{SPACE}	{ 
+				char *yptr;
+
+				/* Strip space and return as a normal symbol */
+				yptr = yytext;
+				while (*yptr != ' ' && *yptr != '\t')
+					yptr++;
+				*yptr = '\0';
+				yylval.sym = symtable_get(yytext);
+				string_buf_ptr = string_buf;
+				BEGIN MACROBODY;
+				return T_SYMBOL;
+			}
+<MACRODEF>{WORD}\(	{
+				/*
+				 * We store the symbol with its opening
+				 * parren so we can differentiate macros
+				 * that take args from macros with the
+				 * same name that do not take args as
+				 * is allowed in C.
+				 */
+				BEGIN MACROARGLIST;
+				yylval.sym = symtable_get(yytext);
+				unput('(');
+				return T_SYMBOL;
+			}
+<MACROARGLIST>{WORD}	{
+				yylval.str = yytext;
+				return T_ARG;
+			}
+<MACROARGLIST>{SPACE}   ;
+<MACROARGLIST>[(,]	{
+				return yytext[0];
+			}
+<MACROARGLIST>[)]	{
+				string_buf_ptr = string_buf;
+				BEGIN MACROBODY;
+				return ')';
+			}
+<MACROARGLIST>.		{
+				snprintf(buf, sizeof(buf), "Invalid character "
+					 "'%c' in macro argument list",
+					 yytext[0]);
+				stop(buf, EX_DATAERR);
+			}
+<MACROCALLARGS>{SPACE}  ;
+<MACROCALLARGS>\(	{
+				parren_count++;
+				if (parren_count == 1)
+					return ('(');
+				*string_buf_ptr++ = '(';
+			}
+<MACROCALLARGS>\)	{
+				parren_count--;
+				if (parren_count == 0) {
+					BEGIN INITIAL;
+					return (')');
+				}
+				*string_buf_ptr++ = ')';
+			}
+<MACROCALLARGS>{MCARG}	{
+				char *yptr;
+
+				yptr = yytext;
+				while (*yptr)
+					*string_buf_ptr++ = *yptr++;
+			}
+<MACROCALLARGS>\,	{
+				if (string_buf_ptr != string_buf) {
+					/*
+					 * Return an argument and
+					 * rescan this comma so we
+					 * can return it as well.
+					 */
+					*string_buf_ptr = '\0';
+					yylval.str = string_buf;
+					string_buf_ptr = string_buf;
+					unput(',');
+					return T_ARG;
+				}
+				return ',';
+			}
+<MACROBODY>\\\n		{
+				/* Eat escaped newlines. */
+				++yylineno;
+			}
+<MACROBODY>\r		;
+<MACROBODY>\n		{
+				/* Macros end on the first unescaped newline. */
+				BEGIN INITIAL;
+				*string_buf_ptr = '\0';
+				yylval.str = string_buf;
+				++yylineno;
+				return T_MACROBODY;
+			}
+<MACROBODY>{MBODY}	{
+				char *yptr;
+				char c;
+
+				yptr = yytext;
+				while (c = *yptr++) {
+					/*
+					 * Strip carriage returns.
+					 */
+					if (c == '\r')
+						continue;
+					*string_buf_ptr++ = c;
+				}
+			}
+{WORD}\(		{
+				char *yptr;
+				char *ycopy;
+
+				/* May be a symbol or a macro invocation. */
+				yylval.sym = symtable_get(yytext);
+				if (yylval.sym->type == MACRO) {
+					YY_BUFFER_STATE old_state;
+					YY_BUFFER_STATE temp_state;
+
+					ycopy = strdup(yytext);
+					yptr = ycopy + yyleng;
+					while (yptr > ycopy)
+						unput(*--yptr);
+					old_state = YY_CURRENT_BUFFER;
+					temp_state =
+					    yy_create_buffer(stdin,
+							     YY_BUF_SIZE);
+					yy_switch_to_buffer(temp_state);
+					mm_switch_to_buffer(old_state);
+					mmparse();
+					mm_switch_to_buffer(temp_state);
+					yy_switch_to_buffer(old_state);
+					mm_delete_buffer(temp_state);
+					expand_macro(yylval.sym);
+				} else {
+					if (yylval.sym->type == UNINITIALIZED) {
+						/* Try without the '(' */
+						symbol_delete(yylval.sym);
+						yytext[yyleng-1] = '\0';
+						yylval.sym =
+						    symtable_get(yytext);
+					}
+					unput('(');
+					return T_SYMBOL;
+				}
+			}
+{WORD}			{
+				yylval.sym = symtable_get(yytext);
+				if (yylval.sym->type == MACRO) {
+					expand_macro(yylval.sym);
+				} else {
+					return T_SYMBOL;
+				}
+			}
+.			{ 
+				snprintf(buf, sizeof(buf), "Invalid character "
+					 "'%c'", yytext[0]);
+				stop(buf, EX_DATAERR);
+			}
+%%
+
+typedef struct include {
+        YY_BUFFER_STATE  buffer;
+        int              lineno;
+        char            *filename;
+	SLIST_ENTRY(include) links;
+}include_t;
+
+SLIST_HEAD(, include) include_stack;
+
+void
+include_file(char *file_name, include_type type)
+{
+	FILE *newfile;
+	include_t *include;
+
+	newfile = NULL;
+	/* Try the current directory first */
+	if (includes_search_curdir != 0 || type == SOURCE_FILE)
+		newfile = fopen(file_name, "r");
+
+	if (newfile == NULL && type != SOURCE_FILE) {
+                path_entry_t include_dir;
+                for (include_dir = search_path.slh_first;
+                     include_dir != NULL;                
+                     include_dir = include_dir->links.sle_next) {
+			char fullname[PATH_MAX];
+
+			if ((include_dir->quoted_includes_only == TRUE)
+			 && (type != QUOTED_INCLUDE))
+				continue;
+
+			snprintf(fullname, sizeof(fullname),
+				 "%s/%s", include_dir->directory, file_name);
+
+			if ((newfile = fopen(fullname, "r")) != NULL)
+				break;
+                }
+        }
+
+	if (newfile == NULL) {
+		perror(file_name);
+		stop("Unable to open input file", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+
+	if (type != SOURCE_FILE) {
+		include = (include_t *)malloc(sizeof(include_t));
+		if (include == NULL) {
+			stop("Unable to allocate include stack entry",
+			     EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+		include->buffer = YY_CURRENT_BUFFER;
+		include->lineno = yylineno;
+		include->filename = yyfilename;
+		SLIST_INSERT_HEAD(&include_stack, include, links);
+	}
+	yy_switch_to_buffer(yy_create_buffer(newfile, YY_BUF_SIZE));
+	yylineno = 1;
+	yyfilename = strdup(file_name);
+}
+
+static void next_substitution(struct symbol *mac_symbol, const char *body_pos,
+			      const char **next_match,
+			      struct macro_arg **match_marg, regmatch_t *match);
+
+void
+expand_macro(struct symbol *macro_symbol)
+{
+	struct macro_arg *marg;
+	struct macro_arg *match_marg;
+	const char *body_head;
+	const char *body_pos;
+	const char *next_match;
+
+	/*
+	 * Due to the nature of unput, we must work
+	 * backwards through the macro body performing
+	 * any expansions.
+	 */
+	body_head = macro_symbol->info.macroinfo->body;
+	body_pos = body_head + strlen(body_head);
+	while (body_pos > body_head) {
+		regmatch_t match;
+
+		next_match = body_head;
+		match_marg = NULL;
+		next_substitution(macro_symbol, body_pos, &next_match,
+				  &match_marg, &match);
+
+		/* Put back everything up until the replacement. */
+		while (body_pos > next_match)
+			unput(*--body_pos);
+
+		/* Perform the replacement. */
+		if (match_marg != NULL) {
+			const char *strp;
+
+			next_match = match_marg->replacement_text;
+			strp = next_match + strlen(next_match);
+			while (strp > next_match)
+				unput(*--strp);
+
+			/* Skip past the unexpanded macro arg. */
+			body_pos -= match.rm_eo - match.rm_so;
+		}
+	}
+
+	/* Cleanup replacement text. */
+	STAILQ_FOREACH(marg, &macro_symbol->info.macroinfo->args, links) {
+		free(marg->replacement_text);
+	}
+}
+
+/*
+ * Find the next substitution in the macro working backwards from
+ * body_pos until the beginning of the macro buffer.  next_match
+ * should be initialized to the beginning of the macro buffer prior
+ * to calling this routine.
+ */
+static void
+next_substitution(struct symbol *mac_symbol, const char *body_pos,
+		  const char **next_match, struct macro_arg **match_marg,
+		  regmatch_t *match)
+{
+	regmatch_t	  matches[2];
+	struct macro_arg *marg;
+	const char	 *search_pos;
+	int		  retval;
+
+	do {
+		search_pos = *next_match;
+
+		STAILQ_FOREACH(marg, &mac_symbol->info.macroinfo->args, links) {
+
+			retval = regexec(&marg->arg_regex, search_pos, 2,
+					 matches, 0);
+			if (retval == 0
+			 && (matches[1].rm_eo + search_pos) <= body_pos
+			 && (matches[1].rm_eo + search_pos) > *next_match) {
+				*match = matches[1];
+				*next_match = match->rm_eo + search_pos;
+				*match_marg = marg;
+			}
+		}
+	} while (search_pos != *next_match);
+}
+
+int
+yywrap()
+{
+	include_t *include;
+
+	yy_delete_buffer(YY_CURRENT_BUFFER);
+	(void)fclose(yyin);
+	if (yyfilename != NULL)
+		free(yyfilename);
+	yyfilename = NULL;
+	include = include_stack.slh_first;
+	if (include != NULL) {
+		yy_switch_to_buffer(include->buffer);
+		yylineno = include->lineno;
+		yyfilename = include->filename;
+		SLIST_REMOVE_HEAD(&include_stack, links);
+		free(include);
+		return (0);
+	}
+	return (1);
+}
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
new file mode 100644
index 0000000..f1f448d
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.c
@@ -0,0 +1,677 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table implementation
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.c#24 $
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+
+#ifdef __linux__
+#include "aicdb.h"
+#else
+#include <db.h>
+#endif
+#include <fcntl.h>
+#include <inttypes.h>
+#include <regex.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysexits.h>
+
+#include "aicasm_symbol.h"
+#include "aicasm.h"
+
+static DB *symtable;
+
+symbol_t *
+symbol_create(char *name)
+{
+	symbol_t *new_symbol;
+
+	new_symbol = (symbol_t *)malloc(sizeof(symbol_t));
+	if (new_symbol == NULL) {
+		perror("Unable to create new symbol");
+		exit(EX_SOFTWARE);
+	}
+	memset(new_symbol, 0, sizeof(*new_symbol));
+	new_symbol->name = strdup(name);
+	if (new_symbol->name == NULL)
+		 stop("Unable to strdup symbol name", EX_SOFTWARE);
+	new_symbol->type = UNINITIALIZED;
+	return (new_symbol);
+}
+
+void
+symbol_delete(symbol_t *symbol)
+{
+	if (symtable != NULL) {
+		DBT	 key;
+
+		key.data = symbol->name;
+		key.size = strlen(symbol->name);
+		symtable->del(symtable, &key, /*flags*/0);
+	}
+	switch(symbol->type) {
+	case SCBLOC:
+	case SRAMLOC:
+	case REGISTER:
+		if (symbol->info.rinfo != NULL)
+			free(symbol->info.rinfo);
+		break;
+	case ALIAS:
+		if (symbol->info.ainfo != NULL)
+			free(symbol->info.ainfo);
+		break;
+	case MASK:
+	case FIELD:
+	case ENUM:
+	case ENUM_ENTRY:
+		if (symbol->info.finfo != NULL) {
+			symlist_free(&symbol->info.finfo->symrefs);
+			free(symbol->info.finfo);
+		}
+		break;
+	case DOWNLOAD_CONST:
+	case CONST:
+		if (symbol->info.cinfo != NULL)
+			free(symbol->info.cinfo);
+		break;
+	case LABEL:
+		if (symbol->info.linfo != NULL)
+			free(symbol->info.linfo);
+		break;
+	case UNINITIALIZED:
+	default:
+		break;
+	}
+	free(symbol->name);
+	free(symbol);
+}
+
+void
+symtable_open()
+{
+	symtable = dbopen(/*filename*/NULL,
+			  O_CREAT | O_NONBLOCK | O_RDWR, /*mode*/0, DB_HASH,
+			  /*openinfo*/NULL);
+
+	if (symtable == NULL) {
+		perror("Symbol table creation failed");
+		exit(EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+}
+
+void
+symtable_close()
+{
+	if (symtable != NULL) {
+		DBT	 key;
+		DBT	 data;
+
+		while (symtable->seq(symtable, &key, &data, R_FIRST) == 0) {
+			symbol_t *stored_ptr;
+
+			memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
+			symbol_delete(stored_ptr);
+		}
+		symtable->close(symtable);
+	}
+}
+
+/*
+ * The semantics of get is to return an uninitialized symbol entry
+ * if a lookup fails.
+ */
+symbol_t *
+symtable_get(char *name)
+{
+	symbol_t *stored_ptr;
+	DBT	  key;
+	DBT	  data;
+	int	  retval;
+
+	key.data = (void *)name;
+	key.size = strlen(name);
+
+	if ((retval = symtable->get(symtable, &key, &data, /*flags*/0)) != 0) {
+		if (retval == -1) {
+			perror("Symbol table get operation failed");
+			exit(EX_SOFTWARE);
+			/* NOTREACHED */
+		} else if (retval == 1) {
+			/* Symbol wasn't found, so create a new one */
+			symbol_t *new_symbol;
+
+			new_symbol = symbol_create(name);
+			data.data = &new_symbol;
+			data.size = sizeof(new_symbol);
+			if (symtable->put(symtable, &key, &data,
+					  /*flags*/0) !=0) {
+				perror("Symtable put failed");
+				exit(EX_SOFTWARE);
+			}
+			return (new_symbol);
+		} else {
+			perror("Unexpected return value from db get routine");
+			exit(EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+	}
+	memcpy(&stored_ptr, data.data, sizeof(stored_ptr));
+	return (stored_ptr);
+}
+
+symbol_node_t *
+symlist_search(symlist_t *symlist, char *symname)
+{
+	symbol_node_t *curnode;
+
+	curnode = SLIST_FIRST(symlist);
+	while(curnode != NULL) {
+		if (strcmp(symname, curnode->symbol->name) == 0)
+			break;
+		curnode = SLIST_NEXT(curnode, links);
+	}
+	return (curnode);
+}
+
+void
+symlist_add(symlist_t *symlist, symbol_t *symbol, int how)
+{
+	symbol_node_t *newnode;
+
+	newnode = (symbol_node_t *)malloc(sizeof(symbol_node_t));
+	if (newnode == NULL) {
+		stop("symlist_add: Unable to malloc symbol_node", EX_SOFTWARE);
+		/* NOTREACHED */
+	}
+	newnode->symbol = symbol;
+	if (how == SYMLIST_SORT) {
+		symbol_node_t *curnode;
+		int field;
+
+		field = FALSE;
+		switch(symbol->type) {
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			break;
+		case FIELD:
+		case MASK:
+		case ENUM:
+		case ENUM_ENTRY:
+			field = TRUE;
+			break;
+		default:
+			stop("symlist_add: Invalid symbol type for sorting",
+			     EX_SOFTWARE);
+			/* NOTREACHED */
+		}
+
+		curnode = SLIST_FIRST(symlist);
+		if (curnode == NULL
+		 || (field
+		  && (curnode->symbol->type > newnode->symbol->type
+		   || (curnode->symbol->type == newnode->symbol->type
+		    && (curnode->symbol->info.finfo->value >
+			newnode->symbol->info.finfo->value))))
+		 || (!field && (curnode->symbol->info.rinfo->address >
+		               newnode->symbol->info.rinfo->address))) {
+			SLIST_INSERT_HEAD(symlist, newnode, links);
+			return;
+		}
+
+		while (1) {
+			if (SLIST_NEXT(curnode, links) == NULL) {
+				SLIST_INSERT_AFTER(curnode, newnode,
+						   links);
+				break;
+			} else {
+				symbol_t *cursymbol;
+
+				cursymbol = SLIST_NEXT(curnode, links)->symbol;
+				if ((field
+		  		  && (cursymbol->type > symbol->type
+				   || (cursymbol->type == symbol->type
+				    && (cursymbol->info.finfo->value >
+					symbol->info.finfo->value))))
+				 || (!field
+				   && (cursymbol->info.rinfo->address >
+				       symbol->info.rinfo->address))) {
+					SLIST_INSERT_AFTER(curnode, newnode,
+							   links);
+					break;
+				}
+			}
+			curnode = SLIST_NEXT(curnode, links);
+		}
+	} else {
+		SLIST_INSERT_HEAD(symlist, newnode, links);
+	}
+}
+
+void
+symlist_free(symlist_t *symlist)
+{
+	symbol_node_t *node1, *node2;
+
+	node1 = SLIST_FIRST(symlist);
+	while (node1 != NULL) {
+		node2 = SLIST_NEXT(node1, links);
+		free(node1);
+		node1 = node2;
+	}
+	SLIST_INIT(symlist);
+}
+
+void
+symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
+	      symlist_t *symlist_src2)
+{
+	symbol_node_t *node;
+
+	*symlist_dest = *symlist_src1;
+	while((node = SLIST_FIRST(symlist_src2)) != NULL) {
+		SLIST_REMOVE_HEAD(symlist_src2, links);
+		SLIST_INSERT_HEAD(symlist_dest, node, links);
+	}
+
+	/* These are now empty */
+	SLIST_INIT(symlist_src1);
+	SLIST_INIT(symlist_src2);
+}
+
+void
+aic_print_file_prologue(FILE *ofile)
+{
+
+	if (ofile == NULL)
+		return;
+
+	fprintf(ofile,
+"/*\n"
+" * DO NOT EDIT - This file is automatically generated\n"
+" *		 from the following source files:\n"
+" *\n"
+"%s */\n",
+		versions);
+}
+
+void
+aic_print_include(FILE *dfile, char *include_file)
+{
+
+	if (dfile == NULL)
+		return;
+	fprintf(dfile, "\n#include \"%s\"\n\n", include_file);
+}
+
+void
+aic_print_reg_dump_types(FILE *ofile)
+{
+	if (ofile == NULL)
+		return;
+		
+	fprintf(ofile,
+"typedef int (%sreg_print_t)(u_int, u_int *, u_int);\n"
+"typedef struct %sreg_parse_entry {\n"
+"	char	*name;\n"
+"	uint8_t	 value;\n"
+"	uint8_t	 mask;\n"
+"} %sreg_parse_entry_t;\n"
+"\n",
+		prefix, prefix, prefix);
+}
+
+static void
+aic_print_reg_dump_start(FILE *dfile, symbol_node_t *regnode)
+{
+	if (dfile == NULL)
+		return;
+
+	fprintf(dfile,
+"static %sreg_parse_entry_t %s_parse_table[] = {\n",
+		prefix,
+		regnode->symbol->name);
+}
+
+static void
+aic_print_reg_dump_end(FILE *ofile, FILE *dfile,
+		       symbol_node_t *regnode, u_int num_entries)
+{
+	char *lower_name;
+	char *letter;
+
+	lower_name = strdup(regnode->symbol->name);
+	if (lower_name == NULL)
+		 stop("Unable to strdup symbol name", EX_SOFTWARE);
+	
+	for (letter = lower_name; *letter != '\0'; letter++)
+		*letter = tolower(*letter);
+
+	if (dfile != NULL) {
+		if (num_entries != 0)
+			fprintf(dfile,
+"\n"
+"};\n"
+"\n");
+
+		fprintf(dfile,
+"int\n"
+"%s%s_print(u_int regvalue, u_int *cur_col, u_int wrap)\n"
+"{\n"
+"	return (%sprint_register(%s%s, %d, \"%s\",\n"
+"	    0x%02x, regvalue, cur_col, wrap));\n"
+"}\n"
+"\n",
+			prefix,
+			lower_name,
+			prefix,
+			num_entries != 0 ? regnode->symbol->name : "NULL",
+			num_entries != 0 ? "_parse_table" : "",
+			num_entries,
+			regnode->symbol->name,
+			regnode->symbol->info.rinfo->address);
+	}
+
+	fprintf(ofile,
+"#if AIC_DEBUG_REGISTERS\n"
+"%sreg_print_t %s%s_print;\n"
+"#else\n"
+"#define %s%s_print(regvalue, cur_col, wrap) \\\n"
+"    %sprint_register(NULL, 0, \"%s\", 0x%02x, regvalue, cur_col, wrap)\n"
+"#endif\n"
+"\n",
+		prefix,
+		prefix,
+		lower_name,
+		prefix,
+		lower_name,
+		prefix,
+		regnode->symbol->name,
+		regnode->symbol->info.rinfo->address);
+}
+
+static void
+aic_print_reg_dump_entry(FILE *dfile, symbol_node_t *curnode)
+{
+	int num_tabs;
+
+	if (dfile == NULL)
+		return;
+
+	fprintf(dfile,
+"	{ \"%s\",",
+		curnode->symbol->name);
+
+	num_tabs = 3 - (strlen(curnode->symbol->name) + 5) / 8;
+
+	while (num_tabs-- > 0)
+		fputc('\t', dfile);
+	fprintf(dfile, "0x%02x, 0x%02x }",
+		curnode->symbol->info.finfo->value,
+		curnode->symbol->info.finfo->mask);
+}
+
+void
+symtable_dump(FILE *ofile, FILE *dfile)
+{
+	/*
+	 * Sort the registers by address with a simple insertion sort.
+	 * Put bitmasks next to the first register that defines them.
+	 * Put constants at the end.
+	 */
+	symlist_t	 registers;
+	symlist_t	 masks;
+	symlist_t	 constants;
+	symlist_t	 download_constants;
+	symlist_t	 aliases;
+	symlist_t	 exported_labels;
+	symbol_node_t	*curnode;
+	symbol_node_t	*regnode;
+	DBT		 key;
+	DBT		 data;
+	int		 flag;
+	u_int		 i;
+
+	if (symtable == NULL)
+		return;
+
+	SLIST_INIT(&registers);
+	SLIST_INIT(&masks);
+	SLIST_INIT(&constants);
+	SLIST_INIT(&download_constants);
+	SLIST_INIT(&aliases);
+	SLIST_INIT(&exported_labels);
+	flag = R_FIRST;
+	while (symtable->seq(symtable, &key, &data, flag) == 0) {
+		symbol_t *cursym;
+
+		memcpy(&cursym, data.data, sizeof(cursym));
+		switch(cursym->type) {
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			symlist_add(&registers, cursym, SYMLIST_SORT);
+			break;
+		case MASK:
+		case FIELD:
+		case ENUM:
+		case ENUM_ENTRY:
+			symlist_add(&masks, cursym, SYMLIST_SORT);
+			break;
+		case CONST:
+			symlist_add(&constants, cursym,
+				    SYMLIST_INSERT_HEAD);
+			break;
+		case DOWNLOAD_CONST:
+			symlist_add(&download_constants, cursym,
+				    SYMLIST_INSERT_HEAD);
+			break;
+		case ALIAS:
+			symlist_add(&aliases, cursym,
+				    SYMLIST_INSERT_HEAD);
+			break;
+		case LABEL:
+			if (cursym->info.linfo->exported == 0)
+				break;
+			symlist_add(&exported_labels, cursym,
+				    SYMLIST_INSERT_HEAD);
+			break;
+		default:
+			break;
+		}
+		flag = R_NEXT;
+	}
+
+	/* Register dianostic functions/declarations first. */
+	aic_print_file_prologue(ofile);
+	aic_print_reg_dump_types(ofile);
+	aic_print_file_prologue(dfile);
+	aic_print_include(dfile, stock_include_file);
+	SLIST_FOREACH(curnode, &registers, links) {
+
+		switch(curnode->symbol->type) {
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+		{
+			symlist_t	*fields;
+			symbol_node_t	*fieldnode;
+			int		 num_entries;
+
+			num_entries = 0;
+			fields = &curnode->symbol->info.rinfo->fields;
+			SLIST_FOREACH(fieldnode, fields, links) {
+				if (num_entries == 0)
+					aic_print_reg_dump_start(dfile,
+								 curnode);
+				else if (dfile != NULL)
+					fputs(",\n", dfile);
+				num_entries++;
+				aic_print_reg_dump_entry(dfile, fieldnode);
+			}
+			aic_print_reg_dump_end(ofile, dfile,
+					       curnode, num_entries);
+		}
+		default:
+			break;
+		}
+	}
+
+	/* Fold in the masks and bits */
+	while (SLIST_FIRST(&masks) != NULL) {
+		char *regname;
+
+		curnode = SLIST_FIRST(&masks);
+		SLIST_REMOVE_HEAD(&masks, links);
+
+		regnode = SLIST_FIRST(&curnode->symbol->info.finfo->symrefs);
+		regname = regnode->symbol->name;
+		regnode = symlist_search(&registers, regname);
+		SLIST_INSERT_AFTER(regnode, curnode, links);
+	}
+
+	/* Add the aliases */
+	while (SLIST_FIRST(&aliases) != NULL) {
+		char *regname;
+
+		curnode = SLIST_FIRST(&aliases);
+		SLIST_REMOVE_HEAD(&aliases, links);
+
+		regname = curnode->symbol->info.ainfo->parent->name;
+		regnode = symlist_search(&registers, regname);
+		SLIST_INSERT_AFTER(regnode, curnode, links);
+	}
+
+	/* Output generated #defines. */
+	while (SLIST_FIRST(&registers) != NULL) {
+		symbol_node_t *curnode;
+		u_int value;
+		char *tab_str;
+		char *tab_str2;
+
+		curnode = SLIST_FIRST(&registers);
+		SLIST_REMOVE_HEAD(&registers, links);
+		switch(curnode->symbol->type) {
+		case REGISTER:
+		case SCBLOC:
+		case SRAMLOC:
+			fprintf(ofile, "\n");
+			value = curnode->symbol->info.rinfo->address;
+			tab_str = "\t";
+			tab_str2 = "\t\t";
+			break;
+		case ALIAS:
+		{
+			symbol_t *parent;
+
+			parent = curnode->symbol->info.ainfo->parent;
+			value = parent->info.rinfo->address;
+			tab_str = "\t";
+			tab_str2 = "\t\t";
+			break;
+		}
+		case MASK:
+		case FIELD:
+		case ENUM:
+		case ENUM_ENTRY:
+			value = curnode->symbol->info.finfo->value;
+			tab_str = "\t\t";
+			tab_str2 = "\t";
+			break;
+		default:
+			value = 0; /* Quiet compiler */
+			tab_str = NULL;
+			tab_str2 = NULL;
+			stop("symtable_dump: Invalid symbol type "
+			     "encountered", EX_SOFTWARE);
+			break;
+		}
+		fprintf(ofile, "#define%s%-16s%s0x%02x\n",
+			tab_str, curnode->symbol->name, tab_str2,
+			value);
+		free(curnode);
+	}
+	fprintf(ofile, "\n\n");
+
+	while (SLIST_FIRST(&constants) != NULL) {
+		symbol_node_t *curnode;
+
+		curnode = SLIST_FIRST(&constants);
+		SLIST_REMOVE_HEAD(&constants, links);
+		fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+			curnode->symbol->name,
+			curnode->symbol->info.cinfo->value);
+		free(curnode);
+	}
+
+	
+	fprintf(ofile, "\n\n/* Downloaded Constant Definitions */\n");
+
+	for (i = 0; SLIST_FIRST(&download_constants) != NULL; i++) {
+		symbol_node_t *curnode;
+
+		curnode = SLIST_FIRST(&download_constants);
+		SLIST_REMOVE_HEAD(&download_constants, links);
+		fprintf(ofile, "#define\t%-8s\t0x%02x\n",
+			curnode->symbol->name,
+			curnode->symbol->info.cinfo->value);
+		free(curnode);
+	}
+	fprintf(ofile, "#define\tDOWNLOAD_CONST_COUNT\t0x%02x\n", i);
+
+	fprintf(ofile, "\n\n/* Exported Labels */\n");
+
+	while (SLIST_FIRST(&exported_labels) != NULL) {
+		symbol_node_t *curnode;
+
+		curnode = SLIST_FIRST(&exported_labels);
+		SLIST_REMOVE_HEAD(&exported_labels, links);
+		fprintf(ofile, "#define\tLABEL_%-8s\t0x%02x\n",
+			curnode->symbol->name,
+			curnode->symbol->info.linfo->address);
+		free(curnode);
+	}
+}
+
diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
new file mode 100644
index 0000000..afc22e8
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aicasm/aicasm_symbol.h
@@ -0,0 +1,207 @@
+/*
+ * Aic7xxx SCSI host adapter firmware asssembler symbol table definitions
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2002 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id: //depot/aic7xxx/aic7xxx/aicasm/aicasm_symbol.h#17 $
+ *
+ * $FreeBSD$
+ */
+
+#ifdef __linux__
+#include "../queue.h"
+#else
+#include <sys/queue.h>
+#endif
+
+typedef enum {
+	UNINITIALIZED,
+	REGISTER,
+	ALIAS,
+	SCBLOC,
+	SRAMLOC,
+	ENUM_ENTRY,
+	FIELD,
+	MASK,
+	ENUM,
+	CONST,
+	DOWNLOAD_CONST,
+	LABEL,
+	CONDITIONAL,
+	MACRO
+} symtype;
+
+typedef enum {
+	RO = 0x01,
+	WO = 0x02,
+	RW = 0x03
+}amode_t;
+
+typedef SLIST_HEAD(symlist, symbol_node) symlist_t;
+
+struct reg_info {
+	u_int	  address;
+	int	  size;
+	amode_t	  mode;
+	symlist_t fields;
+	uint8_t	  valid_bitmask;
+	uint8_t	  modes;
+	int	  typecheck_masks;
+};
+
+struct field_info {
+	symlist_t symrefs;
+	uint8_t	  value;
+	uint8_t	  mask;
+};
+
+struct const_info {
+	u_int	value;
+	int	define;
+};
+
+struct alias_info {
+	struct symbol *parent;
+};
+
+struct label_info {
+	int	address;
+	int	exported;
+};
+
+struct cond_info {
+	int	func_num;
+};
+
+struct macro_arg {
+	STAILQ_ENTRY(macro_arg)	links;
+	regex_t	arg_regex;
+	char   *replacement_text;
+};
+STAILQ_HEAD(macro_arg_list, macro_arg) args;
+
+struct macro_info {
+	struct macro_arg_list args;
+	int   narg;
+	const char* body;
+};
+
+typedef struct expression_info {
+        symlist_t       referenced_syms;
+        int             value;
+} expression_t;
+
+typedef struct symbol {
+	char	*name;
+	symtype	type;
+	union	{
+		struct reg_info	  *rinfo;
+		struct field_info *finfo;
+		struct const_info *cinfo;
+		struct alias_info *ainfo;
+		struct label_info *linfo;
+		struct cond_info  *condinfo;
+		struct macro_info *macroinfo;
+	}info;
+} symbol_t;
+
+typedef struct symbol_ref {
+	symbol_t *symbol;
+	int	 offset;
+} symbol_ref_t;
+
+typedef struct symbol_node {
+	SLIST_ENTRY(symbol_node) links;
+	symbol_t *symbol;
+} symbol_node_t;
+
+typedef struct critical_section {
+	TAILQ_ENTRY(critical_section) links;
+	int begin_addr;
+	int end_addr;
+} critical_section_t;
+
+typedef enum {
+	SCOPE_ROOT,
+	SCOPE_IF,
+	SCOPE_ELSE_IF,
+	SCOPE_ELSE
+} scope_type;
+
+typedef struct patch_info {
+	int skip_patch;
+	int skip_instr;
+} patch_info_t;
+
+typedef struct scope {
+	SLIST_ENTRY(scope) scope_stack_links;
+	TAILQ_ENTRY(scope) scope_links;
+	TAILQ_HEAD(, scope) inner_scope;
+	scope_type type;
+	int inner_scope_patches;
+	int begin_addr;
+        int end_addr;
+	patch_info_t patches[2];
+	int func_num;
+} scope_t;
+
+TAILQ_HEAD(cs_tailq, critical_section);
+SLIST_HEAD(scope_list, scope);
+TAILQ_HEAD(scope_tailq, scope);
+
+void	symbol_delete(symbol_t *symbol);
+
+void	symtable_open(void);
+
+void	symtable_close(void);
+
+symbol_t *
+	symtable_get(char *name);
+
+symbol_node_t *
+	symlist_search(symlist_t *symlist, char *symname);
+
+void
+	symlist_add(symlist_t *symlist, symbol_t *symbol, int how);
+#define SYMLIST_INSERT_HEAD	0x00
+#define SYMLIST_SORT		0x01
+
+void	symlist_free(symlist_t *symlist);
+
+void	symlist_merge(symlist_t *symlist_dest, symlist_t *symlist_src1,
+		      symlist_t *symlist_src2);
+void	symtable_dump(FILE *ofile, FILE *dfile);
diff --git a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
new file mode 100644
index 0000000..79bfd9e
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aiclib.c
@@ -0,0 +1,1412 @@
+/*
+ * Implementation of Utility functions for all SCSI device types.
+ *
+ * Copyright (c) 1997, 1998, 1999 Justin T. Gibbs.
+ * Copyright (c) 1997, 1998 Kenneth D. Merry.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD: src/sys/cam/scsi/scsi_all.c,v 1.38 2002/09/23 04:56:35 mjacob Exp $
+ * $Id$
+ */
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+
+/* Core SCSI definitions */
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aiclib.h"
+#include "cam.h"
+
+#ifndef FALSE
+#define FALSE   0
+#endif /* FALSE */
+#ifndef TRUE
+#define TRUE    1
+#endif /* TRUE */
+#ifndef ERESTART
+#define ERESTART        -1              /* restart syscall */
+#endif
+#ifndef EJUSTRETURN
+#define EJUSTRETURN     -2              /* don't modify regs, just return */
+#endif
+
+static int	ascentrycomp(const void *key, const void *member);
+static int	senseentrycomp(const void *key, const void *member);
+static void	fetchtableentries(int sense_key, int asc, int ascq,
+				  struct scsi_inquiry_data *,
+				  const struct sense_key_table_entry **,
+				  const struct asc_table_entry **);
+static void *	scsibsearch(const void *key, const void *base, size_t nmemb,
+			    size_t size,
+			    int (*compar)(const void *, const void *));
+typedef int (cam_quirkmatch_t)(caddr_t, caddr_t);
+static int	cam_strmatch(const u_int8_t *str, const u_int8_t *pattern,
+			     int str_len);
+static caddr_t	cam_quirkmatch(caddr_t target, caddr_t quirk_table,
+			       int num_entries, int entry_size,
+			       cam_quirkmatch_t *comp_func);
+
+#define SCSI_NO_SENSE_STRINGS 1
+#if !defined(SCSI_NO_SENSE_STRINGS)
+#define SST(asc, ascq, action, desc) \
+	asc, ascq, action, desc
+#else 
+static const char empty_string[] = "";
+
+#define SST(asc, ascq, action, desc) \
+	asc, ascq, action, empty_string
+#endif 
+
+static const struct sense_key_table_entry sense_key_table[] = 
+{
+	{ SSD_KEY_NO_SENSE, SS_NOP, "NO SENSE" },
+	{ SSD_KEY_RECOVERED_ERROR, SS_NOP|SSQ_PRINT_SENSE, "RECOVERED ERROR" },
+	{
+	  SSD_KEY_NOT_READY, SS_TUR|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
+	  "NOT READY"
+	},
+	{ SSD_KEY_MEDIUM_ERROR, SS_RDEF, "MEDIUM ERROR" },
+	{ SSD_KEY_HARDWARE_ERROR, SS_RDEF, "HARDWARE FAILURE" },
+	{ SSD_KEY_ILLEGAL_REQUEST, SS_FATAL|EINVAL, "ILLEGAL REQUEST" },
+	{ SSD_KEY_UNIT_ATTENTION, SS_FATAL|ENXIO, "UNIT ATTENTION" },
+	{ SSD_KEY_DATA_PROTECT, SS_FATAL|EACCES, "DATA PROTECT" },
+	{ SSD_KEY_BLANK_CHECK, SS_FATAL|ENOSPC, "BLANK CHECK" },
+	{ SSD_KEY_Vendor_Specific, SS_FATAL|EIO, "Vendor Specific" },
+	{ SSD_KEY_COPY_ABORTED, SS_FATAL|EIO, "COPY ABORTED" },
+	{ SSD_KEY_ABORTED_COMMAND, SS_RDEF, "ABORTED COMMAND" },
+	{ SSD_KEY_EQUAL, SS_NOP, "EQUAL" },
+	{ SSD_KEY_VOLUME_OVERFLOW, SS_FATAL|EIO, "VOLUME OVERFLOW" },
+	{ SSD_KEY_MISCOMPARE, SS_NOP, "MISCOMPARE" },
+	{ SSD_KEY_RESERVED, SS_FATAL|EIO, "RESERVED" }
+};
+
+static const int sense_key_table_size =
+    sizeof(sense_key_table)/sizeof(sense_key_table[0]);
+
+static struct asc_table_entry quantum_fireball_entries[] = {
+	{SST(0x04, 0x0b, SS_START|SSQ_DECREMENT_COUNT|ENXIO, 
+	     "Logical unit not ready, initializing cmd. required")}
+};
+
+static struct asc_table_entry sony_mo_entries[] = {
+	{SST(0x04, 0x00, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
+	     "Logical unit not ready, cause not reportable")}
+};
+
+static struct scsi_sense_quirk_entry sense_quirk_table[] = {
+	{
+		/*
+		 * The Quantum Fireball ST and SE like to return 0x04 0x0b when
+		 * they really should return 0x04 0x02.  0x04,0x0b isn't
+		 * defined in any SCSI spec, and it isn't mentioned in the
+		 * hardware manual for these drives.
+		 */
+		{T_DIRECT, SIP_MEDIA_FIXED, "QUANTUM", "FIREBALL S*", "*"},
+		/*num_sense_keys*/0,
+		sizeof(quantum_fireball_entries)/sizeof(struct asc_table_entry),
+		/*sense key entries*/NULL,
+		quantum_fireball_entries
+	},
+	{
+		/*
+		 * This Sony MO drive likes to return 0x04, 0x00 when it
+		 * isn't spun up.
+		 */
+		{T_DIRECT, SIP_MEDIA_REMOVABLE, "SONY", "SMO-*", "*"},
+		/*num_sense_keys*/0,
+		sizeof(sony_mo_entries)/sizeof(struct asc_table_entry),
+		/*sense key entries*/NULL,
+		sony_mo_entries
+	}
+};
+
+static const int sense_quirk_table_size =
+    sizeof(sense_quirk_table)/sizeof(sense_quirk_table[0]);
+
+static struct asc_table_entry asc_table[] = {
+/*
+ * From File: ASC-NUM.TXT
+ * SCSI ASC/ASCQ Assignments
+ * Numeric Sorted Listing
+ * as of  5/12/97
+ *
+ * D - DIRECT ACCESS DEVICE (SBC)                     device column key
+ * .T - SEQUENTIAL ACCESS DEVICE (SSC)               -------------------
+ * . L - PRINTER DEVICE (SSC)                           blank = reserved
+ * .  P - PROCESSOR DEVICE (SPC)                     not blank = allowed
+ * .  .W - WRITE ONCE READ MULTIPLE DEVICE (SBC)
+ * .  . R - CD DEVICE (MMC)
+ * .  .  S - SCANNER DEVICE (SGC)
+ * .  .  .O - OPTICAL MEMORY DEVICE (SBC)
+ * .  .  . M - MEDIA CHANGER DEVICE (SMC)
+ * .  .  .  C - COMMUNICATION DEVICE (SSC)
+ * .  .  .  .A - STORAGE ARRAY DEVICE (SCC)
+ * .  .  .  . E - ENCLOSURE SERVICES DEVICE (SES)
+ * DTLPWRSOMCAE        ASC   ASCQ  Action  Description
+ * ------------        ----  ----  ------  -----------------------------------*/
+/* DTLPWRSOMCAE */{SST(0x00, 0x00, SS_NOP,
+			"No additional sense information") },
+/*  T    S      */{SST(0x00, 0x01, SS_RDEF,
+			"Filemark detected") },
+/*  T    S      */{SST(0x00, 0x02, SS_RDEF,
+			"End-of-partition/medium detected") },
+/*  T           */{SST(0x00, 0x03, SS_RDEF,
+			"Setmark detected") },
+/*  T    S      */{SST(0x00, 0x04, SS_RDEF,
+			"Beginning-of-partition/medium detected") },
+/*  T    S      */{SST(0x00, 0x05, SS_RDEF,
+			"End-of-data detected") },
+/* DTLPWRSOMCAE */{SST(0x00, 0x06, SS_RDEF,
+			"I/O process terminated") },
+/*      R       */{SST(0x00, 0x11, SS_FATAL|EBUSY,
+			"Audio play operation in progress") },
+/*      R       */{SST(0x00, 0x12, SS_NOP,
+			"Audio play operation paused") },
+/*      R       */{SST(0x00, 0x13, SS_NOP,
+			"Audio play operation successfully completed") },
+/*      R       */{SST(0x00, 0x14, SS_RDEF,
+			"Audio play operation stopped due to error") },
+/*      R       */{SST(0x00, 0x15, SS_NOP,
+			"No current audio status to return") },
+/* DTLPWRSOMCAE */{SST(0x00, 0x16, SS_FATAL|EBUSY,
+			"Operation in progress") },
+/* DTL WRSOM AE */{SST(0x00, 0x17, SS_RDEF,
+			"Cleaning requested") },
+/* D   W  O     */{SST(0x01, 0x00, SS_RDEF,
+			"No index/sector signal") },
+/* D   WR OM    */{SST(0x02, 0x00, SS_RDEF,
+			"No seek complete") },
+/* DTL W SO     */{SST(0x03, 0x00, SS_RDEF,
+			"Peripheral device write fault") },
+/*  T           */{SST(0x03, 0x01, SS_RDEF,
+			"No write current") },
+/*  T           */{SST(0x03, 0x02, SS_RDEF,
+			"Excessive write errors") },
+/* DTLPWRSOMCAE */{SST(0x04, 0x00,
+			SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EIO,
+			"Logical unit not ready, cause not reportable") },
+/* DTLPWRSOMCAE */{SST(0x04, 0x01,
+			SS_TUR|SSQ_DELAY|SSQ_MANY|SSQ_DECREMENT_COUNT|EBUSY,
+			"Logical unit is in process of becoming ready") },
+/* DTLPWRSOMCAE */{SST(0x04, 0x02, SS_START|SSQ_DECREMENT_COUNT|ENXIO,
+			"Logical unit not ready, initializing cmd. required") },
+/* DTLPWRSOMCAE */{SST(0x04, 0x03, SS_FATAL|ENXIO,
+			"Logical unit not ready, manual intervention required")},
+/* DTL    O     */{SST(0x04, 0x04, SS_FATAL|EBUSY,
+			"Logical unit not ready, format in progress") },
+/* DT  W  OMCA  */{SST(0x04, 0x05, SS_FATAL|EBUSY,
+			"Logical unit not ready, rebuild in progress") },
+/* DT  W  OMCA  */{SST(0x04, 0x06, SS_FATAL|EBUSY,
+			"Logical unit not ready, recalculation in progress") },
+/* DTLPWRSOMCAE */{SST(0x04, 0x07, SS_FATAL|EBUSY,
+			"Logical unit not ready, operation in progress") },
+/*      R       */{SST(0x04, 0x08, SS_FATAL|EBUSY,
+			"Logical unit not ready, long write in progress") },
+/* DTL WRSOMCAE */{SST(0x05, 0x00, SS_RDEF,
+			"Logical unit does not respond to selection") },
+/* D   WR OM    */{SST(0x06, 0x00, SS_RDEF,
+			"No reference position found") },
+/* DTL WRSOM    */{SST(0x07, 0x00, SS_RDEF,
+			"Multiple peripheral devices selected") },
+/* DTL WRSOMCAE */{SST(0x08, 0x00, SS_RDEF,
+			"Logical unit communication failure") },
+/* DTL WRSOMCAE */{SST(0x08, 0x01, SS_RDEF,
+			"Logical unit communication time-out") },
+/* DTL WRSOMCAE */{SST(0x08, 0x02, SS_RDEF,
+			"Logical unit communication parity error") },
+/* DT   R OM    */{SST(0x08, 0x03, SS_RDEF,
+			"Logical unit communication crc error (ultra-dma/32)")},
+/* DT  WR O     */{SST(0x09, 0x00, SS_RDEF,
+			"Track following error") },
+/*     WR O     */{SST(0x09, 0x01, SS_RDEF,
+			"Tracking servo failure") },
+/*     WR O     */{SST(0x09, 0x02, SS_RDEF,
+			"Focus servo failure") },
+/*     WR O     */{SST(0x09, 0x03, SS_RDEF,
+			"Spindle servo failure") },
+/* DT  WR O     */{SST(0x09, 0x04, SS_RDEF,
+			"Head select fault") },
+/* DTLPWRSOMCAE */{SST(0x0A, 0x00, SS_FATAL|ENOSPC,
+			"Error log overflow") },
+/* DTLPWRSOMCAE */{SST(0x0B, 0x00, SS_RDEF,
+			"Warning") },
+/* DTLPWRSOMCAE */{SST(0x0B, 0x01, SS_RDEF,
+			"Specified temperature exceeded") },
+/* DTLPWRSOMCAE */{SST(0x0B, 0x02, SS_RDEF,
+			"Enclosure degraded") },
+/*  T   RS      */{SST(0x0C, 0x00, SS_RDEF,
+			"Write error") },
+/* D   W  O     */{SST(0x0C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
+			"Write error - recovered with auto reallocation") },
+/* D   W  O     */{SST(0x0C, 0x02, SS_RDEF,
+			"Write error - auto reallocation failed") },
+/* D   W  O     */{SST(0x0C, 0x03, SS_RDEF,
+			"Write error - recommend reassignment") },
+/* DT  W  O     */{SST(0x0C, 0x04, SS_RDEF,
+			"Compression check miscompare error") },
+/* DT  W  O     */{SST(0x0C, 0x05, SS_RDEF,
+			"Data expansion occurred during compression") },
+/* DT  W  O     */{SST(0x0C, 0x06, SS_RDEF,
+			"Block not compressible") },
+/*      R       */{SST(0x0C, 0x07, SS_RDEF,
+			"Write error - recovery needed") },
+/*      R       */{SST(0x0C, 0x08, SS_RDEF,
+			"Write error - recovery failed") },
+/*      R       */{SST(0x0C, 0x09, SS_RDEF,
+			"Write error - loss of streaming") },
+/*      R       */{SST(0x0C, 0x0A, SS_RDEF,
+			"Write error - padding blocks added") },
+/* D   W  O     */{SST(0x10, 0x00, SS_RDEF,
+			"ID CRC or ECC error") },
+/* DT  WRSO     */{SST(0x11, 0x00, SS_RDEF,
+			"Unrecovered read error") },
+/* DT  W SO     */{SST(0x11, 0x01, SS_RDEF,
+			"Read retries exhausted") },
+/* DT  W SO     */{SST(0x11, 0x02, SS_RDEF,
+			"Error too long to correct") },
+/* DT  W SO     */{SST(0x11, 0x03, SS_RDEF,
+			"Multiple read errors") },
+/* D   W  O     */{SST(0x11, 0x04, SS_RDEF,
+			"Unrecovered read error - auto reallocate failed") },
+/*     WR O     */{SST(0x11, 0x05, SS_RDEF,
+			"L-EC uncorrectable error") },
+/*     WR O     */{SST(0x11, 0x06, SS_RDEF,
+			"CIRC unrecovered error") },
+/*     W  O     */{SST(0x11, 0x07, SS_RDEF,
+			"Data re-synchronization error") },
+/*  T           */{SST(0x11, 0x08, SS_RDEF,
+			"Incomplete block read") },
+/*  T           */{SST(0x11, 0x09, SS_RDEF,
+			"No gap found") },
+/* DT     O     */{SST(0x11, 0x0A, SS_RDEF,
+			"Miscorrected error") },
+/* D   W  O     */{SST(0x11, 0x0B, SS_RDEF,
+			"Unrecovered read error - recommend reassignment") },
+/* D   W  O     */{SST(0x11, 0x0C, SS_RDEF,
+			"Unrecovered read error - recommend rewrite the data")},
+/* DT  WR O     */{SST(0x11, 0x0D, SS_RDEF,
+			"De-compression CRC error") },
+/* DT  WR O     */{SST(0x11, 0x0E, SS_RDEF,
+			"Cannot decompress using declared algorithm") },
+/*      R       */{SST(0x11, 0x0F, SS_RDEF,
+			"Error reading UPC/EAN number") },
+/*      R       */{SST(0x11, 0x10, SS_RDEF,
+			"Error reading ISRC number") },
+/*      R       */{SST(0x11, 0x11, SS_RDEF,
+			"Read error - loss of streaming") },
+/* D   W  O     */{SST(0x12, 0x00, SS_RDEF,
+			"Address mark not found for id field") },
+/* D   W  O     */{SST(0x13, 0x00, SS_RDEF,
+			"Address mark not found for data field") },
+/* DTL WRSO     */{SST(0x14, 0x00, SS_RDEF,
+			"Recorded entity not found") },
+/* DT  WR O     */{SST(0x14, 0x01, SS_RDEF,
+			"Record not found") },
+/*  T           */{SST(0x14, 0x02, SS_RDEF,
+			"Filemark or setmark not found") },
+/*  T           */{SST(0x14, 0x03, SS_RDEF,
+			"End-of-data not found") },
+/*  T           */{SST(0x14, 0x04, SS_RDEF,
+			"Block sequence error") },
+/* DT  W  O     */{SST(0x14, 0x05, SS_RDEF,
+			"Record not found - recommend reassignment") },
+/* DT  W  O     */{SST(0x14, 0x06, SS_RDEF,
+			"Record not found - data auto-reallocated") },
+/* DTL WRSOM    */{SST(0x15, 0x00, SS_RDEF,
+			"Random positioning error") },
+/* DTL WRSOM    */{SST(0x15, 0x01, SS_RDEF,
+			"Mechanical positioning error") },
+/* DT  WR O     */{SST(0x15, 0x02, SS_RDEF,
+			"Positioning error detected by read of medium") },
+/* D   W  O     */{SST(0x16, 0x00, SS_RDEF,
+			"Data synchronization mark error") },
+/* D   W  O     */{SST(0x16, 0x01, SS_RDEF,
+			"Data sync error - data rewritten") },
+/* D   W  O     */{SST(0x16, 0x02, SS_RDEF,
+			"Data sync error - recommend rewrite") },
+/* D   W  O     */{SST(0x16, 0x03, SS_NOP|SSQ_PRINT_SENSE,
+			"Data sync error - data auto-reallocated") },
+/* D   W  O     */{SST(0x16, 0x04, SS_RDEF,
+			"Data sync error - recommend reassignment") },
+/* DT  WRSO     */{SST(0x17, 0x00, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with no error correction applied") },
+/* DT  WRSO     */{SST(0x17, 0x01, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with retries") },
+/* DT  WR O     */{SST(0x17, 0x02, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with positive head offset") },
+/* DT  WR O     */{SST(0x17, 0x03, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with negative head offset") },
+/*     WR O     */{SST(0x17, 0x04, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with retries and/or CIRC applied") },
+/* D   WR O     */{SST(0x17, 0x05, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data using previous sector id") },
+/* D   W  O     */{SST(0x17, 0x06, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data without ECC - data auto-reallocated") },
+/* D   W  O     */{SST(0x17, 0x07, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data without ECC - recommend reassignment")},
+/* D   W  O     */{SST(0x17, 0x08, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data without ECC - recommend rewrite") },
+/* D   W  O     */{SST(0x17, 0x09, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data without ECC - data rewritten") },
+/* D   W  O     */{SST(0x18, 0x00, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with error correction applied") },
+/* D   WR O     */{SST(0x18, 0x01, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with error corr. & retries applied") },
+/* D   WR O     */{SST(0x18, 0x02, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data - data auto-reallocated") },
+/*      R       */{SST(0x18, 0x03, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with CIRC") },
+/*      R       */{SST(0x18, 0x04, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with L-EC") },
+/* D   WR O     */{SST(0x18, 0x05, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data - recommend reassignment") },
+/* D   WR O     */{SST(0x18, 0x06, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data - recommend rewrite") },
+/* D   W  O     */{SST(0x18, 0x07, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered data with ECC - data rewritten") },
+/* D      O     */{SST(0x19, 0x00, SS_RDEF,
+			"Defect list error") },
+/* D      O     */{SST(0x19, 0x01, SS_RDEF,
+			"Defect list not available") },
+/* D      O     */{SST(0x19, 0x02, SS_RDEF,
+			"Defect list error in primary list") },
+/* D      O     */{SST(0x19, 0x03, SS_RDEF,
+			"Defect list error in grown list") },
+/* DTLPWRSOMCAE */{SST(0x1A, 0x00, SS_RDEF,
+			"Parameter list length error") },
+/* DTLPWRSOMCAE */{SST(0x1B, 0x00, SS_RDEF,
+			"Synchronous data transfer error") },
+/* D      O     */{SST(0x1C, 0x00, SS_RDEF,
+			"Defect list not found") },
+/* D      O     */{SST(0x1C, 0x01, SS_RDEF,
+			"Primary defect list not found") },
+/* D      O     */{SST(0x1C, 0x02, SS_RDEF,
+			"Grown defect list not found") },
+/* D   W  O     */{SST(0x1D, 0x00, SS_FATAL,
+			"Miscompare during verify operation" )},
+/* D   W  O     */{SST(0x1E, 0x00, SS_NOP|SSQ_PRINT_SENSE,
+			"Recovered id with ecc correction") },
+/* D      O     */{SST(0x1F, 0x00, SS_RDEF,
+			"Partial defect list transfer") },
+/* DTLPWRSOMCAE */{SST(0x20, 0x00, SS_FATAL|EINVAL,
+			"Invalid command operation code") },
+/* DT  WR OM    */{SST(0x21, 0x00, SS_FATAL|EINVAL,
+			"Logical block address out of range" )},
+/* DT  WR OM    */{SST(0x21, 0x01, SS_FATAL|EINVAL,
+			"Invalid element address") },
+/* D            */{SST(0x22, 0x00, SS_FATAL|EINVAL,
+			"Illegal function") }, /* Deprecated. Use 20 00, 24 00, or 26 00 instead */
+/* DTLPWRSOMCAE */{SST(0x24, 0x00, SS_FATAL|EINVAL,
+			"Invalid field in CDB") },
+/* DTLPWRSOMCAE */{SST(0x25, 0x00, SS_FATAL|ENXIO,
+			"Logical unit not supported") },
+/* DTLPWRSOMCAE */{SST(0x26, 0x00, SS_FATAL|EINVAL,
+			"Invalid field in parameter list") },
+/* DTLPWRSOMCAE */{SST(0x26, 0x01, SS_FATAL|EINVAL,
+			"Parameter not supported") },
+/* DTLPWRSOMCAE */{SST(0x26, 0x02, SS_FATAL|EINVAL,
+			"Parameter value invalid") },
+/* DTLPWRSOMCAE */{SST(0x26, 0x03, SS_FATAL|EINVAL,
+			"Threshold parameters not supported") },
+/* DTLPWRSOMCAE */{SST(0x26, 0x04, SS_FATAL|EINVAL,
+			"Invalid release of active persistent reservation") },
+/* DT  W  O     */{SST(0x27, 0x00, SS_FATAL|EACCES,
+			"Write protected") },
+/* DT  W  O     */{SST(0x27, 0x01, SS_FATAL|EACCES,
+			"Hardware write protected") },
+/* DT  W  O     */{SST(0x27, 0x02, SS_FATAL|EACCES,
+			"Logical unit software write protected") },
+/*  T           */{SST(0x27, 0x03, SS_FATAL|EACCES,
+			"Associated write protect") },
+/*  T           */{SST(0x27, 0x04, SS_FATAL|EACCES,
+			"Persistent write protect") },
+/*  T           */{SST(0x27, 0x05, SS_FATAL|EACCES,
+			"Permanent write protect") },
+/* DTLPWRSOMCAE */{SST(0x28, 0x00, SS_RDEF,
+			"Not ready to ready change, medium may have changed") },
+/* DTLPWRSOMCAE */{SST(0x28, 0x01, SS_FATAL|ENXIO,
+			"Import or export element accessed") },
+/*
+ * XXX JGibbs - All of these should use the same errno, but I don't think
+ * ENXIO is the correct choice.  Should we borrow from the networking
+ * errnos?  ECONNRESET anyone?
+ */
+/* DTLPWRSOMCAE */{SST(0x29, 0x00, SS_RDEF,
+			"Power on, reset, or bus device reset occurred") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x01, SS_RDEF,
+			"Power on occurred") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x02, SS_RDEF,
+			"Scsi bus reset occurred") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x03, SS_RDEF,
+			"Bus device reset function occurred") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x04, SS_RDEF,
+			"Device internal reset") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x05, SS_RDEF,
+			"Transceiver mode changed to single-ended") },
+/* DTLPWRSOMCAE */{SST(0x29, 0x06, SS_RDEF,
+			"Transceiver mode changed to LVD") },
+/* DTL WRSOMCAE */{SST(0x2A, 0x00, SS_RDEF,
+			"Parameters changed") },
+/* DTL WRSOMCAE */{SST(0x2A, 0x01, SS_RDEF,
+			"Mode parameters changed") },
+/* DTL WRSOMCAE */{SST(0x2A, 0x02, SS_RDEF,
+			"Log parameters changed") },
+/* DTLPWRSOMCAE */{SST(0x2A, 0x03, SS_RDEF,
+			"Reservations preempted") },
+/* DTLPWRSO C   */{SST(0x2B, 0x00, SS_RDEF,
+			"Copy cannot execute since host cannot disconnect") },
+/* DTLPWRSOMCAE */{SST(0x2C, 0x00, SS_RDEF,
+			"Command sequence error") },
+/*       S      */{SST(0x2C, 0x01, SS_RDEF,
+			"Too many windows specified") },
+/*       S      */{SST(0x2C, 0x02, SS_RDEF,
+			"Invalid combination of windows specified") },
+/*      R       */{SST(0x2C, 0x03, SS_RDEF,
+			"Current program area is not empty") },
+/*      R       */{SST(0x2C, 0x04, SS_RDEF,
+			"Current program area is empty") },
+/*  T           */{SST(0x2D, 0x00, SS_RDEF,
+			"Overwrite error on update in place") },
+/* DTLPWRSOMCAE */{SST(0x2F, 0x00, SS_RDEF,
+			"Commands cleared by another initiator") },
+/* DT  WR OM    */{SST(0x30, 0x00, SS_RDEF,
+			"Incompatible medium installed") },
+/* DT  WR O     */{SST(0x30, 0x01, SS_RDEF,
+			"Cannot read medium - unknown format") },
+/* DT  WR O     */{SST(0x30, 0x02, SS_RDEF,
+			"Cannot read medium - incompatible format") },
+/* DT           */{SST(0x30, 0x03, SS_RDEF,
+			"Cleaning cartridge installed") },
+/* DT  WR O     */{SST(0x30, 0x04, SS_RDEF,
+			"Cannot write medium - unknown format") },
+/* DT  WR O     */{SST(0x30, 0x05, SS_RDEF,
+			"Cannot write medium - incompatible format") },
+/* DT  W  O     */{SST(0x30, 0x06, SS_RDEF,
+			"Cannot format medium - incompatible medium") },
+/* DTL WRSOM AE */{SST(0x30, 0x07, SS_RDEF,
+			"Cleaning failure") },
+/*      R       */{SST(0x30, 0x08, SS_RDEF,
+			"Cannot write - application code mismatch") },
+/*      R       */{SST(0x30, 0x09, SS_RDEF,
+			"Current session not fixated for append") },
+/* DT  WR O     */{SST(0x31, 0x00, SS_RDEF,
+			"Medium format corrupted") },
+/* D L  R O     */{SST(0x31, 0x01, SS_RDEF,
+			"Format command failed") },
+/* D   W  O     */{SST(0x32, 0x00, SS_RDEF,
+			"No defect spare location available") },
+/* D   W  O     */{SST(0x32, 0x01, SS_RDEF,
+			"Defect list update failure") },
+/*  T           */{SST(0x33, 0x00, SS_RDEF,
+			"Tape length error") },
+/* DTLPWRSOMCAE */{SST(0x34, 0x00, SS_RDEF,
+			"Enclosure failure") },
+/* DTLPWRSOMCAE */{SST(0x35, 0x00, SS_RDEF,
+			"Enclosure services failure") },
+/* DTLPWRSOMCAE */{SST(0x35, 0x01, SS_RDEF,
+			"Unsupported enclosure function") },
+/* DTLPWRSOMCAE */{SST(0x35, 0x02, SS_RDEF,
+			"Enclosure services unavailable") },
+/* DTLPWRSOMCAE */{SST(0x35, 0x03, SS_RDEF,
+			"Enclosure services transfer failure") },
+/* DTLPWRSOMCAE */{SST(0x35, 0x04, SS_RDEF,
+			"Enclosure services transfer refused") },
+/*   L          */{SST(0x36, 0x00, SS_RDEF,
+			"Ribbon, ink, or toner failure") },
+/* DTL WRSOMCAE */{SST(0x37, 0x00, SS_RDEF,
+			"Rounded parameter") },
+/* DTL WRSOMCAE */{SST(0x39, 0x00, SS_RDEF,
+			"Saving parameters not supported") },
+/* DTL WRSOM    */{SST(0x3A, 0x00, SS_NOP,
+			"Medium not present") },
+/* DT  WR OM    */{SST(0x3A, 0x01, SS_NOP,
+			"Medium not present - tray closed") },
+/* DT  WR OM    */{SST(0x3A, 0x01, SS_NOP,
+			"Medium not present - tray open") },
+/* DT  WR OM    */{SST(0x3A, 0x03, SS_NOP,
+			"Medium not present - Loadable") },
+/* DT  WR OM    */{SST(0x3A, 0x04, SS_NOP,
+			"Medium not present - medium auxiliary "
+			"memory accessible") },
+/* DT  WR OM    */{SST(0x3A, 0xFF, SS_NOP, NULL) },/* Range 0x05->0xFF */
+/*  TL          */{SST(0x3B, 0x00, SS_RDEF,
+			"Sequential positioning error") },
+/*  T           */{SST(0x3B, 0x01, SS_RDEF,
+			"Tape position error at beginning-of-medium") },
+/*  T           */{SST(0x3B, 0x02, SS_RDEF,
+			"Tape position error at end-of-medium") },
+/*   L          */{SST(0x3B, 0x03, SS_RDEF,
+			"Tape or electronic vertical forms unit not ready") },
+/*   L          */{SST(0x3B, 0x04, SS_RDEF,
+			"Slew failure") },
+/*   L          */{SST(0x3B, 0x05, SS_RDEF,
+			"Paper jam") },
+/*   L          */{SST(0x3B, 0x06, SS_RDEF,
+			"Failed to sense top-of-form") },
+/*   L          */{SST(0x3B, 0x07, SS_RDEF,
+			"Failed to sense bottom-of-form") },
+/*  T           */{SST(0x3B, 0x08, SS_RDEF,
+			"Reposition error") },
+/*       S      */{SST(0x3B, 0x09, SS_RDEF,
+			"Read past end of medium") },
+/*       S      */{SST(0x3B, 0x0A, SS_RDEF,
+			"Read past beginning of medium") },
+/*       S      */{SST(0x3B, 0x0B, SS_RDEF,
+			"Position past end of medium") },
+/*  T    S      */{SST(0x3B, 0x0C, SS_RDEF,
+			"Position past beginning of medium") },
+/* DT  WR OM    */{SST(0x3B, 0x0D, SS_FATAL|ENOSPC,
+			"Medium destination element full") },
+/* DT  WR OM    */{SST(0x3B, 0x0E, SS_RDEF,
+			"Medium source element empty") },
+/*      R       */{SST(0x3B, 0x0F, SS_RDEF,
+			"End of medium reached") },
+/* DT  WR OM    */{SST(0x3B, 0x11, SS_RDEF,
+			"Medium magazine not accessible") },
+/* DT  WR OM    */{SST(0x3B, 0x12, SS_RDEF,
+			"Medium magazine removed") },
+/* DT  WR OM    */{SST(0x3B, 0x13, SS_RDEF,
+			"Medium magazine inserted") },
+/* DT  WR OM    */{SST(0x3B, 0x14, SS_RDEF,
+			"Medium magazine locked") },
+/* DT  WR OM    */{SST(0x3B, 0x15, SS_RDEF,
+			"Medium magazine unlocked") },
+/* DTLPWRSOMCAE */{SST(0x3D, 0x00, SS_RDEF,
+			"Invalid bits in identify message") },
+/* DTLPWRSOMCAE */{SST(0x3E, 0x00, SS_RDEF,
+			"Logical unit has not self-configured yet") },
+/* DTLPWRSOMCAE */{SST(0x3E, 0x01, SS_RDEF,
+			"Logical unit failure") },
+/* DTLPWRSOMCAE */{SST(0x3E, 0x02, SS_RDEF,
+			"Timeout on logical unit") },
+/* DTLPWRSOMCAE */{SST(0x3F, 0x00, SS_RDEF,
+			"Target operating conditions have changed") },
+/* DTLPWRSOMCAE */{SST(0x3F, 0x01, SS_RDEF,
+			"Microcode has been changed") },
+/* DTLPWRSOMC   */{SST(0x3F, 0x02, SS_RDEF,
+			"Changed operating definition") },
+/* DTLPWRSOMCAE */{SST(0x3F, 0x03, SS_INQ_REFRESH|SSQ_DECREMENT_COUNT,
+			"Inquiry data has changed") },
+/* DT  WR OMCAE */{SST(0x3F, 0x04, SS_RDEF,
+			"Component device attached") },
+/* DT  WR OMCAE */{SST(0x3F, 0x05, SS_RDEF,
+			"Device identifier changed") },
+/* DT  WR OMCAE */{SST(0x3F, 0x06, SS_RDEF,
+			"Redundancy group created or modified") },
+/* DT  WR OMCAE */{SST(0x3F, 0x07, SS_RDEF,
+			"Redundancy group deleted") },
+/* DT  WR OMCAE */{SST(0x3F, 0x08, SS_RDEF,
+			"Spare created or modified") },
+/* DT  WR OMCAE */{SST(0x3F, 0x09, SS_RDEF,
+			"Spare deleted") },
+/* DT  WR OMCAE */{SST(0x3F, 0x0A, SS_RDEF,
+			"Volume set created or modified") },
+/* DT  WR OMCAE */{SST(0x3F, 0x0B, SS_RDEF,
+			"Volume set deleted") },
+/* DT  WR OMCAE */{SST(0x3F, 0x0C, SS_RDEF,
+			"Volume set deassigned") },
+/* DT  WR OMCAE */{SST(0x3F, 0x0D, SS_RDEF,
+			"Volume set reassigned") },
+/* DTLPWRSOMCAE */{SST(0x3F, 0x0E, SS_RDEF,
+			"Reported luns data has changed") },
+/* DTLPWRSOMCAE */{SST(0x3F, 0x0F, SS_RETRY|SSQ_DECREMENT_COUNT
+				 | SSQ_DELAY_RANDOM|EBUSY,
+			"Echo buffer overwritten") },
+/* DT  WR OM   B*/{SST(0x3F, 0x0F, SS_RDEF, "Medium Loadable") },
+/* DT  WR OM   B*/{SST(0x3F, 0x0F, SS_RDEF,
+			"Medium auxiliary memory accessible") },
+/* D            */{SST(0x40, 0x00, SS_RDEF,
+			"Ram failure") }, /* deprecated - use 40 NN instead */
+/* DTLPWRSOMCAE */{SST(0x40, 0x80, SS_RDEF,
+			"Diagnostic failure: ASCQ = Component ID") },
+/* DTLPWRSOMCAE */{SST(0x40, 0xFF, SS_RDEF|SSQ_RANGE,
+			NULL) },/* Range 0x80->0xFF */
+/* D            */{SST(0x41, 0x00, SS_RDEF,
+			"Data path failure") }, /* deprecated - use 40 NN instead */
+/* D            */{SST(0x42, 0x00, SS_RDEF,
+			"Power-on or self-test failure") }, /* deprecated - use 40 NN instead */
+/* DTLPWRSOMCAE */{SST(0x43, 0x00, SS_RDEF,
+			"Message error") },
+/* DTLPWRSOMCAE */{SST(0x44, 0x00, SS_RDEF,
+			"Internal target failure") },
+/* DTLPWRSOMCAE */{SST(0x45, 0x00, SS_RDEF,
+			"Select or reselect failure") },
+/* DTLPWRSOMC   */{SST(0x46, 0x00, SS_RDEF,
+			"Unsuccessful soft reset") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x00, SS_RDEF|SSQ_FALLBACK,
+			"SCSI parity error") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x01, SS_RDEF|SSQ_FALLBACK,
+			"Data Phase CRC error detected") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x02, SS_RDEF|SSQ_FALLBACK,
+			"SCSI parity error detected during ST data phase") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x03, SS_RDEF|SSQ_FALLBACK,
+			"Information Unit iuCRC error") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x04, SS_RDEF|SSQ_FALLBACK,
+			"Asynchronous information protection error detected") },
+/* DTLPWRSOMCAE */{SST(0x47, 0x05, SS_RDEF|SSQ_FALLBACK,
+			"Protocol server CRC error") },
+/* DTLPWRSOMCAE */{SST(0x48, 0x00, SS_RDEF|SSQ_FALLBACK,
+			"Initiator detected error message received") },
+/* DTLPWRSOMCAE */{SST(0x49, 0x00, SS_RDEF,
+			"Invalid message error") },
+/* DTLPWRSOMCAE */{SST(0x4A, 0x00, SS_RDEF,
+			"Command phase error") },
+/* DTLPWRSOMCAE */{SST(0x4B, 0x00, SS_RDEF,
+			"Data phase error") },
+/* DTLPWRSOMCAE */{SST(0x4C, 0x00, SS_RDEF,
+			"Logical unit failed self-configuration") },
+/* DTLPWRSOMCAE */{SST(0x4D, 0x00, SS_RDEF,
+			"Tagged overlapped commands: ASCQ = Queue tag ID") },
+/* DTLPWRSOMCAE */{SST(0x4D, 0xFF, SS_RDEF|SSQ_RANGE,
+			NULL)}, /* Range 0x00->0xFF */
+/* DTLPWRSOMCAE */{SST(0x4E, 0x00, SS_RDEF,
+			"Overlapped commands attempted") },
+/*  T           */{SST(0x50, 0x00, SS_RDEF,
+			"Write append error") },
+/*  T           */{SST(0x50, 0x01, SS_RDEF,
+			"Write append position error") },
+/*  T           */{SST(0x50, 0x02, SS_RDEF,
+			"Position error related to timing") },
+/*  T     O     */{SST(0x51, 0x00, SS_RDEF,
+			"Erase failure") },
+/*  T           */{SST(0x52, 0x00, SS_RDEF,
+			"Cartridge fault") },
+/* DTL WRSOM    */{SST(0x53, 0x00, SS_RDEF,
+			"Media load or eject failed") },
+/*  T           */{SST(0x53, 0x01, SS_RDEF,
+			"Unload tape failure") },
+/* DT  WR OM    */{SST(0x53, 0x02, SS_RDEF,
+			"Medium removal prevented") },
+/*    P         */{SST(0x54, 0x00, SS_RDEF,
+			"Scsi to host system interface failure") },
+/*    P         */{SST(0x55, 0x00, SS_RDEF,
+			"System resource failure") },
+/* D      O     */{SST(0x55, 0x01, SS_FATAL|ENOSPC,
+			"System buffer full") },
+/*      R       */{SST(0x57, 0x00, SS_RDEF,
+			"Unable to recover table-of-contents") },
+/*        O     */{SST(0x58, 0x00, SS_RDEF,
+			"Generation does not exist") },
+/*        O     */{SST(0x59, 0x00, SS_RDEF,
+			"Updated block read") },
+/* DTLPWRSOM    */{SST(0x5A, 0x00, SS_RDEF,
+			"Operator request or state change input") },
+/* DT  WR OM    */{SST(0x5A, 0x01, SS_RDEF,
+			"Operator medium removal request") },
+/* DT  W  O     */{SST(0x5A, 0x02, SS_RDEF,
+			"Operator selected write protect") },
+/* DT  W  O     */{SST(0x5A, 0x03, SS_RDEF,
+			"Operator selected write permit") },
+/* DTLPWRSOM    */{SST(0x5B, 0x00, SS_RDEF,
+			"Log exception") },
+/* DTLPWRSOM    */{SST(0x5B, 0x01, SS_RDEF,
+			"Threshold condition met") },
+/* DTLPWRSOM    */{SST(0x5B, 0x02, SS_RDEF,
+			"Log counter at maximum") },
+/* DTLPWRSOM    */{SST(0x5B, 0x03, SS_RDEF,
+			"Log list codes exhausted") },
+/* D      O     */{SST(0x5C, 0x00, SS_RDEF,
+			"RPL status change") },
+/* D      O     */{SST(0x5C, 0x01, SS_NOP|SSQ_PRINT_SENSE,
+			"Spindles synchronized") },
+/* D      O     */{SST(0x5C, 0x02, SS_RDEF,
+			"Spindles not synchronized") },
+/* DTLPWRSOMCAE */{SST(0x5D, 0x00, SS_RDEF,
+			"Failure prediction threshold exceeded") },
+/* DTLPWRSOMCAE */{SST(0x5D, 0xFF, SS_RDEF,
+			"Failure prediction threshold exceeded (false)") },
+/* DTLPWRSO CA  */{SST(0x5E, 0x00, SS_RDEF,
+			"Low power condition on") },
+/* DTLPWRSO CA  */{SST(0x5E, 0x01, SS_RDEF,
+			"Idle condition activated by timer") },
+/* DTLPWRSO CA  */{SST(0x5E, 0x02, SS_RDEF,
+			"Standby condition activated by timer") },
+/* DTLPWRSO CA  */{SST(0x5E, 0x03, SS_RDEF,
+			"Idle condition activated by command") },
+/* DTLPWRSO CA  */{SST(0x5E, 0x04, SS_RDEF,
+			"Standby condition activated by command") },
+/*       S      */{SST(0x60, 0x00, SS_RDEF,
+			"Lamp failure") },
+/*       S      */{SST(0x61, 0x00, SS_RDEF,
+			"Video acquisition error") },
+/*       S      */{SST(0x61, 0x01, SS_RDEF,
+			"Unable to acquire video") },
+/*       S      */{SST(0x61, 0x02, SS_RDEF,
+			"Out of focus") },
+/*       S      */{SST(0x62, 0x00, SS_RDEF,
+			"Scan head positioning error") },
+/*      R       */{SST(0x63, 0x00, SS_RDEF,
+			"End of user area encountered on this track") },
+/*      R       */{SST(0x63, 0x01, SS_FATAL|ENOSPC,
+			"Packet does not fit in available space") },
+/*      R       */{SST(0x64, 0x00, SS_RDEF,
+			"Illegal mode for this track") },
+/*      R       */{SST(0x64, 0x01, SS_RDEF,
+			"Invalid packet size") },
+/* DTLPWRSOMCAE */{SST(0x65, 0x00, SS_RDEF,
+			"Voltage fault") },
+/*       S      */{SST(0x66, 0x00, SS_RDEF,
+			"Automatic document feeder cover up") },
+/*       S      */{SST(0x66, 0x01, SS_RDEF,
+			"Automatic document feeder lift up") },
+/*       S      */{SST(0x66, 0x02, SS_RDEF,
+			"Document jam in automatic document feeder") },
+/*       S      */{SST(0x66, 0x03, SS_RDEF,
+			"Document miss feed automatic in document feeder") },
+/*           A  */{SST(0x67, 0x00, SS_RDEF,
+			"Configuration failure") },
+/*           A  */{SST(0x67, 0x01, SS_RDEF,
+			"Configuration of incapable logical units failed") },
+/*           A  */{SST(0x67, 0x02, SS_RDEF,
+			"Add logical unit failed") },
+/*           A  */{SST(0x67, 0x03, SS_RDEF,
+			"Modification of logical unit failed") },
+/*           A  */{SST(0x67, 0x04, SS_RDEF,
+			"Exchange of logical unit failed") },
+/*           A  */{SST(0x67, 0x05, SS_RDEF,
+			"Remove of logical unit failed") },
+/*           A  */{SST(0x67, 0x06, SS_RDEF,
+			"Attachment of logical unit failed") },
+/*           A  */{SST(0x67, 0x07, SS_RDEF,
+			"Creation of logical unit failed") },
+/*           A  */{SST(0x68, 0x00, SS_RDEF,
+			"Logical unit not configured") },
+/*           A  */{SST(0x69, 0x00, SS_RDEF,
+			"Data loss on logical unit") },
+/*           A  */{SST(0x69, 0x01, SS_RDEF,
+			"Multiple logical unit failures") },
+/*           A  */{SST(0x69, 0x02, SS_RDEF,
+			"Parity/data mismatch") },
+/*           A  */{SST(0x6A, 0x00, SS_RDEF,
+			"Informational, refer to log") },
+/*           A  */{SST(0x6B, 0x00, SS_RDEF,
+			"State change has occurred") },
+/*           A  */{SST(0x6B, 0x01, SS_RDEF,
+			"Redundancy level got better") },
+/*           A  */{SST(0x6B, 0x02, SS_RDEF,
+			"Redundancy level got worse") },
+/*           A  */{SST(0x6C, 0x00, SS_RDEF,
+			"Rebuild failure occurred") },
+/*           A  */{SST(0x6D, 0x00, SS_RDEF,
+			"Recalculate failure occurred") },
+/*           A  */{SST(0x6E, 0x00, SS_RDEF,
+			"Command to logical unit failed") },
+/*  T           */{SST(0x70, 0x00, SS_RDEF,
+			"Decompression exception short: ASCQ = Algorithm ID") },
+/*  T           */{SST(0x70, 0xFF, SS_RDEF|SSQ_RANGE,
+			NULL) }, /* Range 0x00 -> 0xFF */
+/*  T           */{SST(0x71, 0x00, SS_RDEF,
+			"Decompression exception long: ASCQ = Algorithm ID") },
+/*  T           */{SST(0x71, 0xFF, SS_RDEF|SSQ_RANGE,
+			NULL) }, /* Range 0x00 -> 0xFF */	
+/*      R       */{SST(0x72, 0x00, SS_RDEF,
+			"Session fixation error") },
+/*      R       */{SST(0x72, 0x01, SS_RDEF,
+			"Session fixation error writing lead-in") },
+/*      R       */{SST(0x72, 0x02, SS_RDEF,
+			"Session fixation error writing lead-out") },
+/*      R       */{SST(0x72, 0x03, SS_RDEF,
+			"Session fixation error - incomplete track in session") },
+/*      R       */{SST(0x72, 0x04, SS_RDEF,
+			"Empty or partially written reserved track") },
+/*      R       */{SST(0x73, 0x00, SS_RDEF,
+			"CD control error") },
+/*      R       */{SST(0x73, 0x01, SS_RDEF,
+			"Power calibration area almost full") },
+/*      R       */{SST(0x73, 0x02, SS_FATAL|ENOSPC,
+			"Power calibration area is full") },
+/*      R       */{SST(0x73, 0x03, SS_RDEF,
+			"Power calibration area error") },
+/*      R       */{SST(0x73, 0x04, SS_RDEF,
+			"Program memory area update failure") },
+/*      R       */{SST(0x73, 0x05, SS_RDEF,
+			"program memory area is full") }
+};
+
+static const int asc_table_size = sizeof(asc_table)/sizeof(asc_table[0]);
+
+struct asc_key
+{
+	int asc;
+	int ascq;
+};
+
+static int
+ascentrycomp(const void *key, const void *member)
+{
+	int asc;
+	int ascq;
+	const struct asc_table_entry *table_entry;
+
+	asc = ((const struct asc_key *)key)->asc;
+	ascq = ((const struct asc_key *)key)->ascq;
+	table_entry = (const struct asc_table_entry *)member;
+
+	if (asc >= table_entry->asc) {
+
+		if (asc > table_entry->asc)
+			return (1);
+
+		if (ascq <= table_entry->ascq) {
+			/* Check for ranges */
+			if (ascq == table_entry->ascq
+		 	 || ((table_entry->action & SSQ_RANGE) != 0
+		  	   && ascq >= (table_entry - 1)->ascq))
+				return (0);
+			return (-1);
+		}
+		return (1);
+	}
+	return (-1);
+}
+
+static int
+senseentrycomp(const void *key, const void *member)
+{
+	int sense_key;
+	const struct sense_key_table_entry *table_entry;
+
+	sense_key = *((const int *)key);
+	table_entry = (const struct sense_key_table_entry *)member;
+
+	if (sense_key >= table_entry->sense_key) {
+		if (sense_key == table_entry->sense_key)
+			return (0);
+		return (1);
+	}
+	return (-1);
+}
+
+static void
+fetchtableentries(int sense_key, int asc, int ascq,
+		  struct scsi_inquiry_data *inq_data,
+		  const struct sense_key_table_entry **sense_entry,
+		  const struct asc_table_entry **asc_entry)
+{
+	void *match;
+	const struct asc_table_entry *asc_tables[2];
+	const struct sense_key_table_entry *sense_tables[2];
+	struct asc_key asc_ascq;
+	size_t asc_tables_size[2];
+	size_t sense_tables_size[2];
+	int num_asc_tables;
+	int num_sense_tables;
+	int i;
+
+	/* Default to failure */
+	*sense_entry = NULL;
+	*asc_entry = NULL;
+	match = NULL;
+	if (inq_data != NULL)
+		match = cam_quirkmatch((void *)inq_data,
+				       (void *)sense_quirk_table,
+				       sense_quirk_table_size,
+				       sizeof(*sense_quirk_table),
+				       aic_inquiry_match);
+
+	if (match != NULL) {
+		struct scsi_sense_quirk_entry *quirk;
+
+		quirk = (struct scsi_sense_quirk_entry *)match;
+		asc_tables[0] = quirk->asc_info;
+		asc_tables_size[0] = quirk->num_ascs;
+		asc_tables[1] = asc_table;
+		asc_tables_size[1] = asc_table_size;
+		num_asc_tables = 2;
+		sense_tables[0] = quirk->sense_key_info;
+		sense_tables_size[0] = quirk->num_sense_keys;
+		sense_tables[1] = sense_key_table;
+		sense_tables_size[1] = sense_key_table_size;
+		num_sense_tables = 2;
+	} else {
+		asc_tables[0] = asc_table;
+		asc_tables_size[0] = asc_table_size;
+		num_asc_tables = 1;
+		sense_tables[0] = sense_key_table;
+		sense_tables_size[0] = sense_key_table_size;
+		num_sense_tables = 1;
+	}
+
+	asc_ascq.asc = asc;
+	asc_ascq.ascq = ascq;
+	for (i = 0; i < num_asc_tables; i++) {
+		void *found_entry;
+
+		found_entry = scsibsearch(&asc_ascq, asc_tables[i],
+					  asc_tables_size[i],
+					  sizeof(**asc_tables),
+					  ascentrycomp);
+
+		if (found_entry) {
+			*asc_entry = (struct asc_table_entry *)found_entry;
+			break;
+		}
+	}
+
+	for (i = 0; i < num_sense_tables; i++) {
+		void *found_entry;
+
+		found_entry = scsibsearch(&sense_key, sense_tables[i],
+					  sense_tables_size[i],
+					  sizeof(**sense_tables),
+					  senseentrycomp);
+
+		if (found_entry) {
+			*sense_entry =
+			    (struct sense_key_table_entry *)found_entry;
+			break;
+		}
+	}
+}
+
+static void *
+scsibsearch(const void *key, const void *base, size_t nmemb, size_t size,
+		 int (*compar)(const void *, const void *))
+{
+	const void *entry;
+	u_int l;
+	u_int u;
+	u_int m;
+
+	l = -1;
+	u = nmemb;
+	while (l + 1 != u) {
+		m = (l + u) / 2;
+		entry = base + m * size;
+		if (compar(key, entry) > 0)
+			l = m;
+		else
+			u = m;
+	}
+
+	entry = base + u * size;
+	if (u == nmemb
+	 || compar(key, entry) != 0)
+		return (NULL);
+
+	return ((void *)entry);
+}
+
+/*
+ * Compare string with pattern, returning 0 on match.
+ * Short pattern matches trailing blanks in name,
+ * wildcard '*' in pattern matches rest of name,
+ * wildcard '?' matches a single non-space character.
+ */
+static int
+cam_strmatch(const uint8_t *str, const uint8_t *pattern, int str_len)
+{
+
+	while (*pattern != '\0'&& str_len > 0) {  
+
+		if (*pattern == '*') {
+			return (0);
+		}
+		if ((*pattern != *str)
+		 && (*pattern != '?' || *str == ' ')) {
+			return (1);
+		}
+		pattern++;
+		str++;
+		str_len--;
+	}
+	while (str_len > 0 && *str++ == ' ')
+		str_len--;
+
+	return (str_len);
+}
+
+static caddr_t
+cam_quirkmatch(caddr_t target, caddr_t quirk_table, int num_entries,
+	       int entry_size, cam_quirkmatch_t *comp_func)
+{
+	for (; num_entries > 0; num_entries--, quirk_table += entry_size) {
+		if ((*comp_func)(target, quirk_table) == 0)
+			return (quirk_table);
+	}
+	return (NULL);
+}
+
+void
+aic_sense_desc(int sense_key, int asc, int ascq,
+	       struct scsi_inquiry_data *inq_data,
+	       const char **sense_key_desc, const char **asc_desc)
+{
+	const struct asc_table_entry *asc_entry;
+	const struct sense_key_table_entry *sense_entry;
+
+	fetchtableentries(sense_key, asc, ascq,
+			  inq_data,
+			  &sense_entry,
+			  &asc_entry);
+
+	*sense_key_desc = sense_entry->desc;
+
+	if (asc_entry != NULL)
+		*asc_desc = asc_entry->desc;
+	else if (asc >= 0x80 && asc <= 0xff)
+		*asc_desc = "Vendor Specific ASC";
+	else if (ascq >= 0x80 && ascq <= 0xff)
+		*asc_desc = "Vendor Specific ASCQ";
+	else
+		*asc_desc = "Reserved ASC/ASCQ pair";
+}
+
+/*
+ * Given sense and device type information, return the appropriate action.
+ * If we do not understand the specific error as identified by the ASC/ASCQ
+ * pair, fall back on the more generic actions derived from the sense key.
+ */
+aic_sense_action
+aic_sense_error_action(struct scsi_sense_data *sense_data,
+		       struct scsi_inquiry_data *inq_data, uint32_t sense_flags)
+{
+	const struct asc_table_entry *asc_entry;
+	const struct sense_key_table_entry *sense_entry;
+	int error_code, sense_key, asc, ascq;
+	aic_sense_action action;
+
+	scsi_extract_sense(sense_data, &error_code, &sense_key, &asc, &ascq);
+
+	if (error_code == SSD_DEFERRED_ERROR) {
+		/*
+		 * XXX dufault@FreeBSD.org
+		 * This error doesn't relate to the command associated
+		 * with this request sense.  A deferred error is an error
+		 * for a command that has already returned GOOD status
+		 * (see SCSI2 8.2.14.2).
+		 *
+		 * By my reading of that section, it looks like the current
+		 * command has been cancelled, we should now clean things up
+		 * (hopefully recovering any lost data) and then retry the
+		 * current command.  There are two easy choices, both wrong:
+		 *
+		 * 1. Drop through (like we had been doing), thus treating
+		 *    this as if the error were for the current command and
+		 *    return and stop the current command.
+		 * 
+		 * 2. Issue a retry (like I made it do) thus hopefully
+		 *    recovering the current transfer, and ignoring the
+		 *    fact that we've dropped a command.
+		 *
+		 * These should probably be handled in a device specific
+		 * sense handler or punted back up to a user mode daemon
+		 */
+		action = SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE;
+	} else {
+		fetchtableentries(sense_key, asc, ascq,
+				  inq_data,
+				  &sense_entry,
+				  &asc_entry);
+
+		/*
+		 * Override the 'No additional Sense' entry (0,0)
+		 * with the error action of the sense key.
+		 */
+		if (asc_entry != NULL
+		 && (asc != 0 || ascq != 0))
+			action = asc_entry->action;
+		else
+			action = sense_entry->action;
+
+		if (sense_key == SSD_KEY_RECOVERED_ERROR) {
+			/*
+			 * The action succeeded but the device wants
+			 * the user to know that some recovery action
+			 * was required.
+			 */
+			action &= ~(SS_MASK|SSQ_MASK|SS_ERRMASK);
+			action |= SS_NOP|SSQ_PRINT_SENSE;
+		} else if (sense_key == SSD_KEY_ILLEGAL_REQUEST) {
+			if ((sense_flags & SF_QUIET_IR) != 0)
+				action &= ~SSQ_PRINT_SENSE;
+		} else if (sense_key == SSD_KEY_UNIT_ATTENTION) {
+			if ((sense_flags & SF_RETRY_UA) != 0
+			 && (action & SS_MASK) == SS_FAIL) {
+				action &= ~(SS_MASK|SSQ_MASK);
+				action |= SS_RETRY|SSQ_DECREMENT_COUNT|
+					  SSQ_PRINT_SENSE;
+			}
+		}
+	}
+
+	if ((sense_flags & SF_PRINT_ALWAYS) != 0)
+		action |= SSQ_PRINT_SENSE;
+	else if ((sense_flags & SF_NO_PRINT) != 0)
+		action &= ~SSQ_PRINT_SENSE;
+
+	return (action);
+}
+
+/*      
+ * Try make as good a match as possible with
+ * available sub drivers
+ */
+int
+aic_inquiry_match(caddr_t inqbuffer, caddr_t table_entry)
+{
+	struct scsi_inquiry_pattern *entry;
+	struct scsi_inquiry_data *inq;
+ 
+	entry = (struct scsi_inquiry_pattern *)table_entry;
+	inq = (struct scsi_inquiry_data *)inqbuffer;
+
+	if (((SID_TYPE(inq) == entry->type)
+	  || (entry->type == T_ANY))
+	 && (SID_IS_REMOVABLE(inq) ? entry->media_type & SIP_MEDIA_REMOVABLE
+				   : entry->media_type & SIP_MEDIA_FIXED)
+	 && (cam_strmatch(inq->vendor, entry->vendor, sizeof(inq->vendor)) == 0)
+	 && (cam_strmatch(inq->product, entry->product,
+			  sizeof(inq->product)) == 0)
+	 && (cam_strmatch(inq->revision, entry->revision,
+			  sizeof(inq->revision)) == 0)) {
+		return (0);
+	}
+        return (-1);
+}
+
+/*
+ * Table of syncrates that don't follow the "divisible by 4"
+ * rule. This table will be expanded in future SCSI specs.
+ */
+static struct {
+	u_int period_factor;
+	u_int period;	/* in 100ths of ns */
+} scsi_syncrates[] = {
+	{ 0x08, 625 },	/* FAST-160 */
+	{ 0x09, 1250 },	/* FAST-80 */
+	{ 0x0a, 2500 },	/* FAST-40 40MHz */
+	{ 0x0b, 3030 },	/* FAST-40 33MHz */
+	{ 0x0c, 5000 }	/* FAST-20 */
+};
+
+/*
+ * Return the frequency in kHz corresponding to the given
+ * sync period factor.
+ */
+u_int
+aic_calc_syncsrate(u_int period_factor)
+{
+	int i;
+	int num_syncrates;
+
+	num_syncrates = sizeof(scsi_syncrates) / sizeof(scsi_syncrates[0]);
+	/* See if the period is in the "exception" table */
+	for (i = 0; i < num_syncrates; i++) {
+
+		if (period_factor == scsi_syncrates[i].period_factor) {
+			/* Period in kHz */
+			return (100000000 / scsi_syncrates[i].period);
+		}
+	}
+
+	/*
+	 * Wasn't in the table, so use the standard
+	 * 4 times conversion.
+	 */
+	return (10000000 / (period_factor * 4 * 10));
+}
+
+/*
+ * Return speed in KB/s.
+ */
+u_int
+aic_calc_speed(u_int width, u_int period, u_int offset, u_int min_rate)
+{
+	u_int freq;
+
+	if (offset != 0 && period < min_rate)
+		freq  = aic_calc_syncsrate(period);
+	else
+		/* Roughly 3.3MB/s for async */
+		freq  = 3300;
+	freq <<= width;
+	return (freq);
+}
+
+uint32_t
+aic_error_action(struct scsi_cmnd *cmd, struct scsi_inquiry_data *inq_data,
+		 cam_status status, u_int scsi_status)
+{
+	aic_sense_action  err_action;
+	int		  sense;
+
+	sense  = (cmd->result >> 24) == DRIVER_SENSE;
+
+	switch (status) {
+	case CAM_REQ_CMP:
+		err_action = SS_NOP;
+		break;
+	case CAM_AUTOSENSE_FAIL:
+	case CAM_SCSI_STATUS_ERROR:
+
+		switch (scsi_status) {
+		case SCSI_STATUS_OK:
+		case SCSI_STATUS_COND_MET:
+		case SCSI_STATUS_INTERMED:
+		case SCSI_STATUS_INTERMED_COND_MET:
+			err_action = SS_NOP;
+			break;
+		case SCSI_STATUS_CMD_TERMINATED:
+		case SCSI_STATUS_CHECK_COND:
+			if (sense != 0) {
+				struct scsi_sense_data *sense;
+
+				sense = (struct scsi_sense_data *)
+				    &cmd->sense_buffer;
+				err_action =
+				    aic_sense_error_action(sense, inq_data, 0);
+
+			} else {
+				err_action = SS_RETRY|SSQ_FALLBACK
+					   | SSQ_DECREMENT_COUNT|EIO;
+			}
+			break;
+		case SCSI_STATUS_QUEUE_FULL:
+		case SCSI_STATUS_BUSY:
+			err_action = SS_RETRY|SSQ_DELAY|SSQ_MANY
+				   | SSQ_DECREMENT_COUNT|EBUSY;
+			break;
+		case SCSI_STATUS_RESERV_CONFLICT:
+		default:
+			err_action = SS_FAIL|EBUSY;
+			break;
+		}
+		break;
+	case CAM_CMD_TIMEOUT:
+	case CAM_REQ_CMP_ERR:
+	case CAM_UNEXP_BUSFREE:
+	case CAM_UNCOR_PARITY:
+	case CAM_DATA_RUN_ERR:
+		err_action = SS_RETRY|SSQ_FALLBACK|EIO;
+		break;
+	case CAM_UA_ABORT:
+	case CAM_UA_TERMIO:
+	case CAM_MSG_REJECT_REC:
+	case CAM_SEL_TIMEOUT:
+		err_action = SS_FAIL|EIO;
+		break;
+	case CAM_REQ_INVALID:
+	case CAM_PATH_INVALID:
+	case CAM_DEV_NOT_THERE:
+	case CAM_NO_HBA:
+	case CAM_PROVIDE_FAIL:
+	case CAM_REQ_TOO_BIG:		
+	case CAM_RESRC_UNAVAIL:
+	case CAM_BUSY:
+	default:
+		/* panic??  These should never occur in our application. */
+		err_action = SS_FAIL|EIO;
+		break;
+	case CAM_SCSI_BUS_RESET:
+	case CAM_BDR_SENT:		
+	case CAM_REQUEUE_REQ:
+		/* Unconditional requeue */
+		err_action = SS_RETRY;
+		break;
+	}
+
+	return (err_action);
+}
+
+char *
+aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
+		       aic_option_callback_t *callback, u_long callback_arg)
+{
+	char	*tok_end;
+	char	*tok_end2;
+	int      i;
+	int      instance;
+	int	 targ;
+	int	 done;
+	char	 tok_list[] = {'.', ',', '{', '}', '\0'};
+
+	/* All options use a ':' name/arg separator */
+	if (*opt_arg != ':')
+		return (opt_arg);
+	opt_arg++;
+	instance = -1;
+	targ = -1;
+	done = FALSE;
+	/*
+	 * Restore separator that may be in
+	 * the middle of our option argument.
+	 */
+	tok_end = strchr(opt_arg, '\0');
+	if (tok_end < end)
+		*tok_end = ',';
+	while (!done) {
+		switch (*opt_arg) {
+		case '{':
+			if (instance == -1) {
+				instance = 0;
+			} else {
+				if (depth > 1) {
+					if (targ == -1)
+						targ = 0;
+				} else {
+					printf("Malformed Option %s\n",
+					       opt_name);
+					done = TRUE;
+				}
+			}
+			opt_arg++;
+			break;
+		case '}':
+			if (targ != -1)
+				targ = -1;
+			else if (instance != -1)
+				instance = -1;
+			opt_arg++;
+			break;
+		case ',':
+		case '.':
+			if (instance == -1)
+				done = TRUE;
+			else if (targ >= 0)
+				targ++;
+			else if (instance >= 0)
+				instance++;
+			opt_arg++;
+			break;
+		case '\0':
+			done = TRUE;
+			break;
+		default:
+			tok_end = end;
+			for (i = 0; tok_list[i]; i++) {
+				tok_end2 = strchr(opt_arg, tok_list[i]);
+				if ((tok_end2) && (tok_end2 < tok_end))
+					tok_end = tok_end2;
+			}
+			callback(callback_arg, instance, targ,
+				 simple_strtol(opt_arg, NULL, 0));
+			opt_arg = tok_end;
+			break;
+		}
+	}
+	return (opt_arg);
+}
diff --git a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
new file mode 100644
index 0000000..bfe6f95
--- /dev/null
+++ b/drivers/scsi/aic7xxx/aiclib.h
@@ -0,0 +1,1085 @@
+/*
+ * Largely written by Julian Elischer (julian@tfs.com)
+ * for TRW Financial Systems.
+ *
+ * TRW Financial Systems, in accordance with their agreement with Carnegie
+ * Mellon University, makes this software available to CMU to distribute
+ * or use in any manner that they see fit as long as this message is kept with
+ * the software. For this reason TFS also grants any other persons or
+ * organisations permission to use or modify this software.
+ *
+ * TFS supplies this software to be publicly redistributed
+ * on the understanding that TFS is not responsible for the correct
+ * functioning of this software in any circumstances.
+ *
+ * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
+ *
+ * $FreeBSD: src/sys/cam/scsi/scsi_all.h,v 1.21 2002/10/08 17:12:44 ken Exp $
+ *
+ * Copyright (c) 2003 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGES.
+ *
+ * $Id$
+ */
+
+#ifndef	_AICLIB_H
+#define _AICLIB_H
+
+/*
+ * Linux Interrupt Support.
+ */
+#ifndef IRQ_RETVAL
+typedef void irqreturn_t;
+#define	IRQ_RETVAL(x)
+#endif
+
+/*
+ * SCSI command format
+ */
+
+/*
+ * Define dome bits that are in ALL (or a lot of) scsi commands
+ */
+#define SCSI_CTL_LINK		0x01
+#define SCSI_CTL_FLAG		0x02
+#define SCSI_CTL_VENDOR		0xC0
+#define	SCSI_CMD_LUN		0xA0	/* these two should not be needed */
+#define	SCSI_CMD_LUN_SHIFT	5	/* LUN in the cmd is no longer SCSI */
+
+#define SCSI_MAX_CDBLEN		16	/* 
+					 * 16 byte commands are in the 
+					 * SCSI-3 spec 
+					 */
+/* 6byte CDBs special case 0 length to be 256 */
+#define SCSI_CDB6_LEN(len)	((len) == 0 ? 256 : len)
+
+/*
+ * This type defines actions to be taken when a particular sense code is
+ * received.  Right now, these flags are only defined to take up 16 bits,
+ * but can be expanded in the future if necessary.
+ */
+typedef enum {
+	SS_NOP		= 0x000000, /* Do nothing */
+	SS_RETRY	= 0x010000, /* Retry the command */
+	SS_FAIL		= 0x020000, /* Bail out */
+	SS_START	= 0x030000, /* Send a Start Unit command to the device,
+				     * then retry the original command.
+				     */
+	SS_TUR		= 0x040000, /* Send a Test Unit Ready command to the
+				     * device, then retry the original command.
+				     */
+	SS_REQSENSE	= 0x050000, /* Send a RequestSense command to the
+				     * device, then retry the original command.
+				     */
+	SS_INQ_REFRESH	= 0x060000,
+	SS_MASK		= 0xff0000
+} aic_sense_action;
+
+typedef enum {
+	SSQ_NONE		= 0x0000,
+	SSQ_DECREMENT_COUNT	= 0x0100,  /* Decrement the retry count */
+	SSQ_MANY		= 0x0200,  /* send lots of recovery commands */
+	SSQ_RANGE		= 0x0400,  /*
+					    * This table entry represents the
+					    * end of a range of ASCQs that
+					    * have identical error actions
+					    * and text.
+					    */
+	SSQ_PRINT_SENSE		= 0x0800,
+	SSQ_DELAY		= 0x1000,  /* Delay before retry. */
+	SSQ_DELAY_RANDOM	= 0x2000,  /* Randomized delay before retry. */
+	SSQ_FALLBACK		= 0x4000,  /* Do a speed fallback to recover */
+	SSQ_MASK		= 0xff00
+} aic_sense_action_qualifier;
+
+/* Mask for error status values */
+#define SS_ERRMASK	0xff
+
+/* The default, retyable, error action */
+#define SS_RDEF		SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE|EIO
+
+/* The retyable, error action, with table specified error code */
+#define SS_RET		SS_RETRY|SSQ_DECREMENT_COUNT|SSQ_PRINT_SENSE
+
+/* Fatal error action, with table specified error code */
+#define SS_FATAL	SS_FAIL|SSQ_PRINT_SENSE
+
+struct scsi_generic
+{
+	uint8_t opcode;
+	uint8_t bytes[11];
+};
+
+struct scsi_request_sense
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_test_unit_ready
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[3];
+	uint8_t control;
+};
+
+struct scsi_send_diag
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SSD_UOL		0x01
+#define	SSD_DOL		0x02
+#define	SSD_SELFTEST	0x04
+#define	SSD_PF		0x10
+	uint8_t unused[1];
+	uint8_t paramlen[2];
+	uint8_t control;
+};
+
+struct scsi_sense
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_inquiry
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SI_EVPD 0x01
+	uint8_t page_code;
+	uint8_t reserved;
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_mode_sense_6
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SMS_DBD				0x08
+	uint8_t page;
+#define	SMS_PAGE_CODE 			0x3F
+#define SMS_VENDOR_SPECIFIC_PAGE	0x00
+#define SMS_DISCONNECT_RECONNECT_PAGE	0x02
+#define SMS_PERIPHERAL_DEVICE_PAGE	0x09
+#define SMS_CONTROL_MODE_PAGE		0x0A
+#define SMS_ALL_PAGES_PAGE		0x3F
+#define	SMS_PAGE_CTRL_MASK		0xC0
+#define	SMS_PAGE_CTRL_CURRENT 		0x00
+#define	SMS_PAGE_CTRL_CHANGEABLE 	0x40
+#define	SMS_PAGE_CTRL_DEFAULT 		0x80
+#define	SMS_PAGE_CTRL_SAVED 		0xC0
+	uint8_t unused;
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_mode_sense_10
+{
+	uint8_t opcode;
+	uint8_t byte2;		/* same bits as small version */
+	uint8_t page; 		/* same bits as small version */
+	uint8_t unused[4];
+	uint8_t length[2];
+	uint8_t control;
+};
+
+struct scsi_mode_select_6
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SMS_SP	0x01
+#define	SMS_PF	0x10
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_mode_select_10
+{
+	uint8_t opcode;
+	uint8_t byte2;		/* same bits as small version */
+	uint8_t unused[5];
+	uint8_t length[2];
+	uint8_t control;
+};
+
+/*
+ * When sending a mode select to a tape drive, the medium type must be 0.
+ */
+struct scsi_mode_hdr_6
+{
+	uint8_t datalen;
+	uint8_t medium_type;
+	uint8_t dev_specific;
+	uint8_t block_descr_len;
+};
+
+struct scsi_mode_hdr_10
+{
+	uint8_t datalen[2];
+	uint8_t medium_type;
+	uint8_t dev_specific;
+	uint8_t reserved[2];
+	uint8_t block_descr_len[2];
+};
+
+struct scsi_mode_block_descr
+{
+	uint8_t density_code;
+	uint8_t num_blocks[3];
+	uint8_t reserved;
+	uint8_t block_len[3];
+};
+
+struct scsi_log_sense
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SLS_SP				0x01
+#define	SLS_PPC				0x02
+	uint8_t page;
+#define	SLS_PAGE_CODE 			0x3F
+#define	SLS_ALL_PAGES_PAGE		0x00
+#define	SLS_OVERRUN_PAGE		0x01
+#define	SLS_ERROR_WRITE_PAGE		0x02
+#define	SLS_ERROR_READ_PAGE		0x03
+#define	SLS_ERROR_READREVERSE_PAGE	0x04
+#define	SLS_ERROR_VERIFY_PAGE		0x05
+#define	SLS_ERROR_NONMEDIUM_PAGE	0x06
+#define	SLS_ERROR_LASTN_PAGE		0x07
+#define	SLS_PAGE_CTRL_MASK		0xC0
+#define	SLS_PAGE_CTRL_THRESHOLD		0x00
+#define	SLS_PAGE_CTRL_CUMULATIVE	0x40
+#define	SLS_PAGE_CTRL_THRESH_DEFAULT	0x80
+#define	SLS_PAGE_CTRL_CUMUL_DEFAULT	0xC0
+	uint8_t reserved[2];
+	uint8_t paramptr[2];
+	uint8_t length[2];
+	uint8_t control;
+};
+
+struct scsi_log_select
+{
+	uint8_t opcode;
+	uint8_t byte2;
+/*	SLS_SP				0x01 */
+#define	SLS_PCR				0x02
+	uint8_t page;
+/*	SLS_PAGE_CTRL_MASK		0xC0 */
+/*	SLS_PAGE_CTRL_THRESHOLD		0x00 */
+/*	SLS_PAGE_CTRL_CUMULATIVE	0x40 */
+/*	SLS_PAGE_CTRL_THRESH_DEFAULT	0x80 */
+/*	SLS_PAGE_CTRL_CUMUL_DEFAULT	0xC0 */
+	uint8_t reserved[4];
+	uint8_t length[2];
+	uint8_t control;
+};
+
+struct scsi_log_header
+{
+	uint8_t page;
+	uint8_t reserved;
+	uint8_t datalen[2];
+};
+
+struct scsi_log_param_header {
+	uint8_t param_code[2];
+	uint8_t param_control;
+#define	SLP_LP				0x01
+#define	SLP_LBIN			0x02
+#define	SLP_TMC_MASK			0x0C
+#define	SLP_TMC_ALWAYS			0x00
+#define	SLP_TMC_EQUAL			0x04
+#define	SLP_TMC_NOTEQUAL		0x08
+#define	SLP_TMC_GREATER			0x0C
+#define	SLP_ETC				0x10
+#define	SLP_TSD				0x20
+#define	SLP_DS				0x40
+#define	SLP_DU				0x80
+	uint8_t param_len;
+};
+
+struct scsi_control_page {
+	uint8_t page_code;
+	uint8_t page_length;
+	uint8_t rlec;
+#define SCB_RLEC			0x01	/*Report Log Exception Cond*/
+	uint8_t queue_flags;
+#define SCP_QUEUE_ALG_MASK		0xF0
+#define SCP_QUEUE_ALG_RESTRICTED	0x00
+#define SCP_QUEUE_ALG_UNRESTRICTED	0x10
+#define SCP_QUEUE_ERR			0x02	/*Queued I/O aborted for CACs*/
+#define SCP_QUEUE_DQUE			0x01	/*Queued I/O disabled*/
+	uint8_t eca_and_aen;
+#define SCP_EECA			0x80	/*Enable Extended CA*/
+#define SCP_RAENP			0x04	/*Ready AEN Permission*/
+#define SCP_UAAENP			0x02	/*UA AEN Permission*/
+#define SCP_EAENP			0x01	/*Error AEN Permission*/
+	uint8_t reserved;
+	uint8_t aen_holdoff_period[2];
+};
+
+struct scsi_reserve
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_release
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_prevent
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[2];
+	uint8_t how;
+	uint8_t control;
+};
+#define	PR_PREVENT 0x01
+#define PR_ALLOW   0x00
+
+struct scsi_sync_cache
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t begin_lba[4];
+	uint8_t reserved;
+	uint8_t lb_count[2];
+	uint8_t control;	
+};
+
+
+struct scsi_changedef
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused1;
+	uint8_t how;
+	uint8_t unused[4];
+	uint8_t datalen;
+	uint8_t control;
+};
+
+struct scsi_read_buffer
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	RWB_MODE		0x07
+#define	RWB_MODE_HDR_DATA	0x00
+#define	RWB_MODE_DATA		0x02
+#define	RWB_MODE_DOWNLOAD	0x04
+#define	RWB_MODE_DOWNLOAD_SAVE	0x05
+        uint8_t buffer_id;
+        uint8_t offset[3];
+        uint8_t length[3];
+        uint8_t control;
+};
+
+struct scsi_write_buffer
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t buffer_id;
+	uint8_t offset[3];
+	uint8_t length[3];
+	uint8_t control;
+};
+
+struct scsi_rw_6
+{
+	uint8_t opcode;
+	uint8_t addr[3];
+/* only 5 bits are valid in the MSB address byte */
+#define	SRW_TOPADDR	0x1F
+	uint8_t length;
+	uint8_t control;
+};
+
+struct scsi_rw_10
+{
+	uint8_t opcode;
+#define	SRW10_RELADDR	0x01
+#define SRW10_FUA	0x08
+#define	SRW10_DPO	0x10
+	uint8_t byte2;
+	uint8_t addr[4];
+	uint8_t reserved;
+	uint8_t length[2];
+	uint8_t control;
+};
+
+struct scsi_rw_12
+{
+	uint8_t opcode;
+#define	SRW12_RELADDR	0x01
+#define SRW12_FUA	0x08
+#define	SRW12_DPO	0x10
+	uint8_t byte2;
+	uint8_t addr[4];
+	uint8_t length[4];
+	uint8_t reserved;
+	uint8_t control;
+};
+
+struct scsi_start_stop_unit
+{
+	uint8_t opcode;
+	uint8_t byte2;
+#define	SSS_IMMED		0x01
+	uint8_t reserved[2];
+	uint8_t how;
+#define	SSS_START		0x01
+#define	SSS_LOEJ		0x02
+	uint8_t control;
+};
+
+#define SC_SCSI_1 0x01
+#define SC_SCSI_2 0x03
+
+/*
+ * Opcodes
+ */
+
+#define	TEST_UNIT_READY		0x00
+#define REQUEST_SENSE		0x03
+#define	READ_6			0x08
+#define WRITE_6			0x0a
+#define INQUIRY			0x12
+#define MODE_SELECT_6		0x15
+#define MODE_SENSE_6		0x1a
+#define START_STOP_UNIT		0x1b
+#define START_STOP		0x1b
+#define RESERVE      		0x16
+#define RELEASE      		0x17
+#define	RECEIVE_DIAGNOSTIC	0x1c
+#define	SEND_DIAGNOSTIC		0x1d
+#define PREVENT_ALLOW		0x1e
+#define	READ_CAPACITY		0x25
+#define	READ_10			0x28
+#define WRITE_10		0x2a
+#define POSITION_TO_ELEMENT	0x2b
+#define	SYNCHRONIZE_CACHE	0x35
+#define	WRITE_BUFFER            0x3b
+#define	READ_BUFFER             0x3c
+#define	CHANGE_DEFINITION	0x40
+#define	LOG_SELECT		0x4c
+#define	LOG_SENSE		0x4d
+#ifdef XXXCAM
+#define	MODE_SENSE_10		0x5A
+#endif
+#define	MODE_SELECT_10		0x55
+#define MOVE_MEDIUM     	0xa5
+#define READ_12			0xa8
+#define WRITE_12		0xaa
+#define READ_ELEMENT_STATUS	0xb8
+
+
+/*
+ * Device Types
+ */
+#define T_DIRECT	0x00
+#define T_SEQUENTIAL	0x01
+#define T_PRINTER	0x02
+#define T_PROCESSOR	0x03
+#define T_WORM		0x04
+#define T_CDROM		0x05
+#define T_SCANNER 	0x06
+#define T_OPTICAL 	0x07
+#define T_CHANGER	0x08
+#define T_COMM		0x09
+#define T_ASC0		0x0a
+#define T_ASC1		0x0b
+#define	T_STORARRAY	0x0c
+#define	T_ENCLOSURE	0x0d
+#define	T_RBC		0x0e
+#define	T_OCRW		0x0f
+#define T_NODEVICE	0x1F
+#define	T_ANY		0xFF	/* Used in Quirk table matches */
+
+#define T_REMOV		1
+#define	T_FIXED		0
+
+/*
+ * This length is the initial inquiry length used by the probe code, as    
+ * well as the legnth necessary for aic_print_inquiry() to function 
+ * correctly.  If either use requires a different length in the future, 
+ * the two values should be de-coupled.
+ */
+#define	SHORT_INQUIRY_LENGTH	36
+
+struct scsi_inquiry_data
+{
+	uint8_t device;
+#define	SID_TYPE(inq_data) ((inq_data)->device & 0x1f)
+#define	SID_QUAL(inq_data) (((inq_data)->device & 0xE0) >> 5)
+#define	SID_QUAL_LU_CONNECTED	0x00	/*
+					 * The specified peripheral device
+					 * type is currently connected to
+					 * logical unit.  If the target cannot
+					 * determine whether or not a physical
+					 * device is currently connected, it
+					 * shall also use this peripheral
+					 * qualifier when returning the INQUIRY
+					 * data.  This peripheral qualifier
+					 * does not mean that the device is
+					 * ready for access by the initiator.
+					 */
+#define	SID_QUAL_LU_OFFLINE	0x01	/*
+					 * The target is capable of supporting
+					 * the specified peripheral device type
+					 * on this logical unit; however, the
+					 * physical device is not currently
+					 * connected to this logical unit.
+					 */
+#define SID_QUAL_RSVD		0x02
+#define	SID_QUAL_BAD_LU		0x03	/*
+					 * The target is not capable of
+					 * supporting a physical device on
+					 * this logical unit. For this
+					 * peripheral qualifier the peripheral
+					 * device type shall be set to 1Fh to
+					 * provide compatibility with previous
+					 * versions of SCSI. All other
+					 * peripheral device type values are
+					 * reserved for this peripheral
+					 * qualifier.
+					 */
+#define	SID_QUAL_IS_VENDOR_UNIQUE(inq_data) ((SID_QUAL(inq_data) & 0x08) != 0)
+	uint8_t dev_qual2;
+#define	SID_QUAL2	0x7F
+#define	SID_IS_REMOVABLE(inq_data) (((inq_data)->dev_qual2 & 0x80) != 0)
+	uint8_t version;
+#define SID_ANSI_REV(inq_data) ((inq_data)->version & 0x07)
+#define		SCSI_REV_0		0
+#define		SCSI_REV_CCS		1
+#define		SCSI_REV_2		2
+#define		SCSI_REV_SPC		3
+#define		SCSI_REV_SPC2		4
+
+#define SID_ECMA	0x38
+#define SID_ISO		0xC0
+	uint8_t response_format;
+#define SID_AENC	0x80
+#define SID_TrmIOP	0x40
+	uint8_t additional_length;
+	uint8_t reserved[2];
+	uint8_t flags;
+#define	SID_SftRe	0x01
+#define	SID_CmdQue	0x02
+#define	SID_Linked	0x08
+#define	SID_Sync	0x10
+#define	SID_WBus16	0x20
+#define	SID_WBus32	0x40
+#define	SID_RelAdr	0x80
+#define SID_VENDOR_SIZE   8
+	char	 vendor[SID_VENDOR_SIZE];
+#define SID_PRODUCT_SIZE  16
+	char	 product[SID_PRODUCT_SIZE];
+#define SID_REVISION_SIZE 4
+	char	 revision[SID_REVISION_SIZE];
+	/*
+	 * The following fields were taken from SCSI Primary Commands - 2
+	 * (SPC-2) Revision 14, Dated 11 November 1999
+	 */
+#define	SID_VENDOR_SPECIFIC_0_SIZE	20
+	uint8_t vendor_specific0[SID_VENDOR_SPECIFIC_0_SIZE];
+	/*
+	 * An extension of SCSI Parallel Specific Values
+	 */
+#define	SID_SPI_IUS		0x01
+#define	SID_SPI_QAS		0x02
+#define	SID_SPI_CLOCK_ST	0x00
+#define	SID_SPI_CLOCK_DT	0x04
+#define	SID_SPI_CLOCK_DT_ST	0x0C
+#define	SID_SPI_MASK		0x0F
+	uint8_t spi3data;
+	uint8_t reserved2;
+	/*
+	 * Version Descriptors, stored 2 byte values.
+	 */
+	uint8_t version1[2];
+	uint8_t version2[2];
+	uint8_t version3[2];
+	uint8_t version4[2];
+	uint8_t version5[2];
+	uint8_t version6[2];
+	uint8_t version7[2];
+	uint8_t version8[2];
+
+	uint8_t reserved3[22];
+
+#define	SID_VENDOR_SPECIFIC_1_SIZE	160
+	uint8_t vendor_specific1[SID_VENDOR_SPECIFIC_1_SIZE];
+};
+
+struct scsi_vpd_unit_serial_number
+{
+	uint8_t device;
+	uint8_t page_code;
+#define SVPD_UNIT_SERIAL_NUMBER	0x80
+	uint8_t reserved;
+	uint8_t length; /* serial number length */
+#define SVPD_SERIAL_NUM_SIZE 251
+	uint8_t serial_num[SVPD_SERIAL_NUM_SIZE];
+};
+
+struct scsi_read_capacity
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t addr[4];
+	uint8_t unused[3];
+	uint8_t control;
+};
+
+struct scsi_read_capacity_data
+{
+	uint8_t addr[4];
+	uint8_t length[4];
+};
+
+struct scsi_report_luns
+{
+	uint8_t opcode;
+	uint8_t byte2;
+	uint8_t unused[3];
+	uint8_t addr[4];
+	uint8_t control;
+};
+
+struct scsi_report_luns_data {
+	uint8_t length[4];	/* length of LUN inventory, in bytes */
+	uint8_t reserved[4];	/* unused */
+	/*
+	 * LUN inventory- we only support the type zero form for now.
+	 */
+	struct {
+		uint8_t lundata[8];
+	} luns[1];
+};
+#define	RPL_LUNDATA_ATYP_MASK	0xc0	/* MBZ for type 0 lun */
+#define	RPL_LUNDATA_T0LUN	1	/* @ lundata[1] */
+
+
+struct scsi_sense_data
+{
+	uint8_t error_code;
+#define	SSD_ERRCODE			0x7F
+#define		SSD_CURRENT_ERROR	0x70
+#define		SSD_DEFERRED_ERROR	0x71
+#define	SSD_ERRCODE_VALID	0x80	
+	uint8_t segment;
+	uint8_t flags;
+#define	SSD_KEY				0x0F
+#define		SSD_KEY_NO_SENSE	0x00
+#define		SSD_KEY_RECOVERED_ERROR	0x01
+#define		SSD_KEY_NOT_READY	0x02
+#define		SSD_KEY_MEDIUM_ERROR	0x03
+#define		SSD_KEY_HARDWARE_ERROR	0x04
+#define		SSD_KEY_ILLEGAL_REQUEST	0x05
+#define		SSD_KEY_UNIT_ATTENTION	0x06
+#define		SSD_KEY_DATA_PROTECT	0x07
+#define		SSD_KEY_BLANK_CHECK	0x08
+#define		SSD_KEY_Vendor_Specific	0x09
+#define		SSD_KEY_COPY_ABORTED	0x0a
+#define		SSD_KEY_ABORTED_COMMAND	0x0b		
+#define		SSD_KEY_EQUAL		0x0c
+#define		SSD_KEY_VOLUME_OVERFLOW	0x0d
+#define		SSD_KEY_MISCOMPARE	0x0e
+#define		SSD_KEY_RESERVED	0x0f			
+#define	SSD_ILI		0x20
+#define	SSD_EOM		0x40
+#define	SSD_FILEMARK	0x80
+	uint8_t info[4];
+	uint8_t extra_len;
+	uint8_t cmd_spec_info[4];
+	uint8_t add_sense_code;
+	uint8_t add_sense_code_qual;
+	uint8_t fru;
+	uint8_t sense_key_spec[3];
+#define	SSD_SCS_VALID		0x80
+#define SSD_FIELDPTR_CMD	0x40
+#define SSD_BITPTR_VALID	0x08
+#define SSD_BITPTR_VALUE	0x07
+#define SSD_MIN_SIZE 18
+	uint8_t extra_bytes[14];
+#define SSD_FULL_SIZE sizeof(struct scsi_sense_data)
+};
+
+struct scsi_mode_header_6
+{
+	uint8_t data_length;	/* Sense data length */
+	uint8_t medium_type;
+	uint8_t dev_spec;
+	uint8_t blk_desc_len;
+};
+
+struct scsi_mode_header_10
+{
+	uint8_t data_length[2];/* Sense data length */
+	uint8_t medium_type;
+	uint8_t dev_spec;
+	uint8_t unused[2];
+	uint8_t blk_desc_len[2];
+};
+
+struct scsi_mode_page_header
+{
+	uint8_t page_code;
+	uint8_t page_length;
+};
+
+struct scsi_mode_blk_desc
+{
+	uint8_t density;
+	uint8_t nblocks[3];
+	uint8_t reserved;
+	uint8_t blklen[3];
+};
+
+#define	SCSI_DEFAULT_DENSITY	0x00	/* use 'default' density */
+#define	SCSI_SAME_DENSITY	0x7f	/* use 'same' density- >= SCSI-2 only */
+
+
+/*
+ * Status Byte
+ */
+#define	SCSI_STATUS_OK			0x00
+#define	SCSI_STATUS_CHECK_COND		0x02
+#define	SCSI_STATUS_COND_MET		0x04
+#define	SCSI_STATUS_BUSY		0x08
+#define SCSI_STATUS_INTERMED		0x10
+#define SCSI_STATUS_INTERMED_COND_MET	0x14
+#define SCSI_STATUS_RESERV_CONFLICT	0x18
+#define SCSI_STATUS_CMD_TERMINATED	0x22	/* Obsolete in SAM-2 */
+#define SCSI_STATUS_QUEUE_FULL		0x28
+#define SCSI_STATUS_ACA_ACTIVE		0x30
+#define SCSI_STATUS_TASK_ABORTED	0x40
+
+struct scsi_inquiry_pattern {
+	uint8_t   type;
+	uint8_t   media_type;
+#define	SIP_MEDIA_REMOVABLE	0x01
+#define	SIP_MEDIA_FIXED		0x02
+	const char *vendor;
+	const char *product;
+	const char *revision;
+}; 
+
+struct scsi_static_inquiry_pattern {
+	uint8_t   type;
+	uint8_t   media_type;
+	char       vendor[SID_VENDOR_SIZE+1];
+	char       product[SID_PRODUCT_SIZE+1];
+	char       revision[SID_REVISION_SIZE+1];
+};
+
+struct scsi_sense_quirk_entry {
+	struct scsi_inquiry_pattern	inq_pat;
+	int				num_sense_keys;
+	int				num_ascs;
+	struct sense_key_table_entry	*sense_key_info;
+	struct asc_table_entry		*asc_info;
+};
+
+struct sense_key_table_entry {
+	uint8_t    sense_key;
+	uint32_t   action;
+	const char *desc;
+};
+
+struct asc_table_entry {
+	uint8_t    asc;
+	uint8_t    ascq;
+	uint32_t   action;
+	const char *desc;
+};
+
+struct op_table_entry {
+	uint8_t    opcode;
+	uint16_t   opmask;
+	const char  *desc;
+};
+
+struct scsi_op_quirk_entry {
+	struct scsi_inquiry_pattern	inq_pat;
+	int				num_ops;
+	struct op_table_entry		*op_table;
+};
+
+typedef enum {
+	SSS_FLAG_NONE		= 0x00,
+	SSS_FLAG_PRINT_COMMAND	= 0x01
+} scsi_sense_string_flags;
+
+extern const char *scsi_sense_key_text[];
+
+/************************* Large Disk Handling ********************************/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+static __inline int aic_sector_div(u_long capacity, int heads, int sectors);
+
+static __inline int
+aic_sector_div(u_long capacity, int heads, int sectors)
+{
+	return (capacity / (heads * sectors));
+}
+#else
+static __inline int aic_sector_div(sector_t capacity, int heads, int sectors);
+
+static __inline int
+aic_sector_div(sector_t capacity, int heads, int sectors)
+{
+	/* ugly, ugly sector_div calling convention.. */
+	sector_div(capacity, (heads * sectors));
+	return (int)capacity;
+}
+#endif
+
+/**************************** Module Library Hack *****************************/
+/*
+ * What we'd like to do is have a single "scsi library" module that both the
+ * aic7xxx and aic79xx drivers could load and depend on.  A cursory examination
+ * of implementing module dependencies in Linux (handling the install and
+ * initrd cases) does not look promissing.  For now, we just duplicate this
+ * code in both drivers using a simple symbol renaming scheme that hides this
+ * hack from the drivers.
+ */
+#define AIC_LIB_ENTRY_CONCAT(x, prefix)	prefix ## x
+#define	AIC_LIB_ENTRY_EXPAND(x, prefix) AIC_LIB_ENTRY_CONCAT(x, prefix)
+#define AIC_LIB_ENTRY(x)		AIC_LIB_ENTRY_EXPAND(x, AIC_LIB_PREFIX)
+
+#define	aic_sense_desc			AIC_LIB_ENTRY(_sense_desc)
+#define	aic_sense_error_action		AIC_LIB_ENTRY(_sense_error_action)
+#define	aic_error_action		AIC_LIB_ENTRY(_error_action)
+#define	aic_op_desc			AIC_LIB_ENTRY(_op_desc)
+#define	aic_cdb_string			AIC_LIB_ENTRY(_cdb_string)
+#define aic_print_inquiry		AIC_LIB_ENTRY(_print_inquiry)
+#define aic_calc_syncsrate		AIC_LIB_ENTRY(_calc_syncrate)
+#define	aic_calc_syncparam		AIC_LIB_ENTRY(_calc_syncparam)
+#define	aic_calc_speed			AIC_LIB_ENTRY(_calc_speed)
+#define	aic_inquiry_match		AIC_LIB_ENTRY(_inquiry_match)
+#define	aic_static_inquiry_match	AIC_LIB_ENTRY(_static_inquiry_match)
+#define	aic_parse_brace_option		AIC_LIB_ENTRY(_parse_brace_option)
+
+/******************************************************************************/
+
+void			aic_sense_desc(int /*sense_key*/, int /*asc*/,
+				       int /*ascq*/, struct scsi_inquiry_data*,
+				       const char** /*sense_key_desc*/,
+				       const char** /*asc_desc*/);
+aic_sense_action	aic_sense_error_action(struct scsi_sense_data*,
+					       struct scsi_inquiry_data*,
+					       uint32_t /*sense_flags*/);
+uint32_t		aic_error_action(struct scsi_cmnd *,
+					 struct scsi_inquiry_data *,
+					 cam_status, u_int);
+
+#define	SF_RETRY_UA	0x01
+#define SF_NO_PRINT	0x02
+#define SF_QUIET_IR	0x04	/* Be quiet about Illegal Request reponses */
+#define SF_PRINT_ALWAYS	0x08
+
+
+const char *	aic_op_desc(uint16_t /*opcode*/, struct scsi_inquiry_data*);
+char *		aic_cdb_string(uint8_t* /*cdb_ptr*/, char* /*cdb_string*/,
+			       size_t /*len*/);
+void		aic_print_inquiry(struct scsi_inquiry_data*);
+
+u_int		aic_calc_syncsrate(u_int /*period_factor*/);
+u_int		aic_calc_syncparam(u_int /*period*/);
+u_int		aic_calc_speed(u_int width, u_int period, u_int offset,
+			       u_int min_rate);
+	
+int		aic_inquiry_match(caddr_t /*inqbuffer*/,
+				  caddr_t /*table_entry*/);
+int		aic_static_inquiry_match(caddr_t /*inqbuffer*/,
+					 caddr_t /*table_entry*/);
+
+typedef void aic_option_callback_t(u_long, int, int, int32_t);
+char *		aic_parse_brace_option(char *opt_name, char *opt_arg,
+				       char *end, int depth,
+				       aic_option_callback_t *, u_long);
+
+static __inline void	 scsi_extract_sense(struct scsi_sense_data *sense,
+					    int *error_code, int *sense_key,
+					    int *asc, int *ascq);
+static __inline void	 scsi_ulto2b(uint32_t val, uint8_t *bytes);
+static __inline void	 scsi_ulto3b(uint32_t val, uint8_t *bytes);
+static __inline void	 scsi_ulto4b(uint32_t val, uint8_t *bytes);
+static __inline uint32_t scsi_2btoul(uint8_t *bytes);
+static __inline uint32_t scsi_3btoul(uint8_t *bytes);
+static __inline int32_t	 scsi_3btol(uint8_t *bytes);
+static __inline uint32_t scsi_4btoul(uint8_t *bytes);
+
+static __inline void scsi_extract_sense(struct scsi_sense_data *sense,
+				       int *error_code, int *sense_key,
+				       int *asc, int *ascq)
+{
+	*error_code = sense->error_code & SSD_ERRCODE;
+	*sense_key = sense->flags & SSD_KEY;
+	*asc = (sense->extra_len >= 5) ? sense->add_sense_code : 0;
+	*ascq = (sense->extra_len >= 6) ? sense->add_sense_code_qual : 0;
+}
+
+static __inline void
+scsi_ulto2b(uint32_t val, uint8_t *bytes)
+{
+
+	bytes[0] = (val >> 8) & 0xff;
+	bytes[1] = val & 0xff;
+}
+
+static __inline void
+scsi_ulto3b(uint32_t val, uint8_t *bytes)
+{
+
+	bytes[0] = (val >> 16) & 0xff;
+	bytes[1] = (val >> 8) & 0xff;
+	bytes[2] = val & 0xff;
+}
+
+static __inline void
+scsi_ulto4b(uint32_t val, uint8_t *bytes)
+{
+
+	bytes[0] = (val >> 24) & 0xff;
+	bytes[1] = (val >> 16) & 0xff;
+	bytes[2] = (val >> 8) & 0xff;
+	bytes[3] = val & 0xff;
+}
+
+static __inline uint32_t
+scsi_2btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 8) |
+	     bytes[1];
+	return (rv);
+}
+
+static __inline uint32_t
+scsi_3btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 16) |
+	     (bytes[1] << 8) |
+	     bytes[2];
+	return (rv);
+}
+
+static __inline int32_t 
+scsi_3btol(uint8_t *bytes)
+{
+	uint32_t rc = scsi_3btoul(bytes);
+ 
+	if (rc & 0x00800000)
+		rc |= 0xff000000;
+
+	return (int32_t) rc;
+}
+
+static __inline uint32_t
+scsi_4btoul(uint8_t *bytes)
+{
+	uint32_t rv;
+
+	rv = (bytes[0] << 24) |
+	     (bytes[1] << 16) |
+	     (bytes[2] << 8) |
+	     bytes[3];
+	return (rv);
+}
+
+/* Macros for generating the elements of the PCI ID tables. */
+
+#define GETID(v, s) (unsigned)(((v) >> (s)) & 0xFFFF ?: PCI_ANY_ID)
+
+#define ID_C(x, c)						\
+{								\
+	GETID(x,32), GETID(x,48), GETID(x,0), GETID(x,16),	\
+	(c) << 8, 0xFFFF00, 0					\
+}
+
+#define ID2C(x)                          \
+	ID_C(x, PCI_CLASS_STORAGE_SCSI), \
+	ID_C(x, PCI_CLASS_STORAGE_RAID)
+
+#define IDIROC(x)  ((x) | ~ID_ALL_IROC_MASK)
+
+/* Generate IDs for all 16 possibilites.
+ * The argument has already masked out
+ * the 4 least significant bits of the device id.
+ * (e.g., mask: ID_9005_GENERIC_MASK).
+ */
+#define ID16(x)                          \
+	ID(x),                           \
+	ID((x) | 0x0001000000000000ull), \
+	ID((x) | 0x0002000000000000ull), \
+	ID((x) | 0x0003000000000000ull), \
+	ID((x) | 0x0004000000000000ull), \
+	ID((x) | 0x0005000000000000ull), \
+	ID((x) | 0x0006000000000000ull), \
+	ID((x) | 0x0007000000000000ull), \
+	ID((x) | 0x0008000000000000ull), \
+	ID((x) | 0x0009000000000000ull), \
+	ID((x) | 0x000A000000000000ull), \
+	ID((x) | 0x000B000000000000ull), \
+	ID((x) | 0x000C000000000000ull), \
+	ID((x) | 0x000D000000000000ull), \
+	ID((x) | 0x000E000000000000ull), \
+	ID((x) | 0x000F000000000000ull)
+
+#endif /*_AICLIB_H */
diff --git a/drivers/scsi/aic7xxx/cam.h b/drivers/scsi/aic7xxx/cam.h
new file mode 100644
index 0000000..d40ba07
--- /dev/null
+++ b/drivers/scsi/aic7xxx/cam.h
@@ -0,0 +1,111 @@
+/*
+ * Data structures and definitions for the CAM system.
+ *
+ * Copyright (c) 1997 Justin T. Gibbs.
+ * Copyright (c) 2000 Adaptec Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL").
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/cam.h#15 $
+ */
+
+#ifndef _AIC7XXX_CAM_H
+#define _AIC7XXX_CAM_H 1
+
+#include <linux/types.h>
+
+#define	CAM_BUS_WILDCARD ((u_int)~0)
+#define	CAM_TARGET_WILDCARD ((u_int)~0)
+#define	CAM_LUN_WILDCARD ((u_int)~0)
+
+/* CAM Status field values */
+typedef enum {
+	CAM_REQ_INPROG,		/* CCB request is in progress */
+	CAM_REQ_CMP,		/* CCB request completed without error */
+	CAM_REQ_ABORTED,	/* CCB request aborted by the host */
+	CAM_UA_ABORT,		/* Unable to abort CCB request */
+	CAM_REQ_CMP_ERR,	/* CCB request completed with an error */
+	CAM_BUSY,		/* CAM subsytem is busy */
+	CAM_REQ_INVALID,	/* CCB request was invalid */
+	CAM_PATH_INVALID,	/* Supplied Path ID is invalid */
+	CAM_SEL_TIMEOUT,	/* Target Selection Timeout */
+	CAM_CMD_TIMEOUT,	/* Command timeout */
+	CAM_SCSI_STATUS_ERROR,	/* SCSI error, look at error code in CCB */
+	CAM_SCSI_BUS_RESET,	/* SCSI Bus Reset Sent/Received */
+	CAM_UNCOR_PARITY,	/* Uncorrectable parity error occurred */
+	CAM_AUTOSENSE_FAIL,	/* Autosense: request sense cmd fail */
+	CAM_NO_HBA,		/* No HBA Detected Error */
+	CAM_DATA_RUN_ERR,	/* Data Overrun error */
+	CAM_UNEXP_BUSFREE,	/* Unexpected Bus Free */
+	CAM_SEQUENCE_FAIL,	/* Protocol Violation */
+	CAM_CCB_LEN_ERR,	/* CCB length supplied is inadequate */
+	CAM_PROVIDE_FAIL,	/* Unable to provide requested capability */
+	CAM_BDR_SENT,		/* A SCSI BDR msg was sent to target */
+	CAM_REQ_TERMIO,		/* CCB request terminated by the host */
+	CAM_UNREC_HBA_ERROR,	/* Unrecoverable Host Bus Adapter Error */
+	CAM_REQ_TOO_BIG,	/* The request was too large for this host */
+	CAM_UA_TERMIO,		/* Unable to terminate I/O CCB request */
+	CAM_MSG_REJECT_REC,	/* Message Reject Received */
+	CAM_DEV_NOT_THERE,	/* SCSI Device Not Installed/there */
+	CAM_RESRC_UNAVAIL,	/* Resource Unavailable */
+	/*
+	 * This request should be requeued to preserve
+	 * transaction ordering.  This typically occurs
+	 * when the SIM recognizes an error that should
+	 * freeze the queue and must place additional
+	 * requests for the target at the sim level
+	 * back into the XPT queue.
+	 */
+	CAM_REQUEUE_REQ,
+	CAM_DEV_QFRZN		= 0x40,
+
+	CAM_STATUS_MASK		= 0x3F
+} cam_status;
+
+/*
+ * Definitions for the asynchronous callback CCB fields.
+ */
+typedef enum {
+	AC_GETDEV_CHANGED	= 0x800,/* Getdev info might have changed */
+	AC_INQ_CHANGED		= 0x400,/* Inquiry info might have changed */
+	AC_TRANSFER_NEG		= 0x200,/* New transfer settings in effect */
+	AC_LOST_DEVICE		= 0x100,/* A device went away */
+	AC_FOUND_DEVICE		= 0x080,/* A new device was found */
+	AC_PATH_DEREGISTERED	= 0x040,/* A path has de-registered */
+	AC_PATH_REGISTERED	= 0x020,/* A new path has been registered */
+	AC_SENT_BDR		= 0x010,/* A BDR message was sent to target */
+	AC_SCSI_AEN		= 0x008,/* A SCSI AEN has been received */
+	AC_UNSOL_RESEL		= 0x002,/* Unsolicited reselection occurred */
+	AC_BUS_RESET		= 0x001 /* A SCSI bus reset occurred */
+} ac_code;
+
+typedef enum {
+	CAM_DIR_IN		= SCSI_DATA_READ,
+	CAM_DIR_OUT		= SCSI_DATA_WRITE,
+	CAM_DIR_NONE		= SCSI_DATA_NONE
+} ccb_flags;
+
+#endif /* _AIC7XXX_CAM_H */
diff --git a/drivers/scsi/aic7xxx/queue.h b/drivers/scsi/aic7xxx/queue.h
new file mode 100644
index 0000000..8adf800
--- /dev/null
+++ b/drivers/scsi/aic7xxx/queue.h
@@ -0,0 +1,501 @@
+/*
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)queue.h	8.5 (Berkeley) 8/20/94
+ * $FreeBSD: src/sys/sys/queue.h,v 1.38 2000/05/26 02:06:56 jake Exp $
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines five types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists, tail queues, and circular queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may only be traversed in the forward direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * A circle queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or after
+ * an existing element, at the head of the list, or at the end of the list.
+ * A circle queue may be traversed in either direction, but has a more
+ * complex end of list detection.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ *
+ *			SLIST	LIST	STAILQ	TAILQ	CIRCLEQ
+ * _HEAD		+	+	+	+	+
+ * _HEAD_INITIALIZER	+	+	+	+	+
+ * _ENTRY		+	+	+	+	+
+ * _INIT		+	+	+	+	+
+ * _EMPTY		+	+	+	+	+
+ * _FIRST		+	+	+	+	+
+ * _NEXT		+	+	+	+	+
+ * _PREV		-	-	-	+	+
+ * _LAST		-	-	+	+	+
+ * _FOREACH		+	+	+	+	+
+ * _FOREACH_REVERSE	-	-	-	+	+
+ * _INSERT_HEAD		+	+	+	+	+
+ * _INSERT_BEFORE	-	+	-	+	+
+ * _INSERT_AFTER	+	+	+	+	+
+ * _INSERT_TAIL		-	-	+	+	+
+ * _REMOVE_HEAD		+	-	+	-	-
+ * _REMOVE		+	+	+	+	+
+ *
+ */
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+ 
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+ 
+/*
+ * Singly-linked List functions.
+ */
+#define	SLIST_EMPTY(head)	((head)->slh_first == NULL)
+
+#define	SLIST_FIRST(head)	((head)->slh_first)
+
+#define	SLIST_FOREACH(var, head, field)					\
+	for ((var) = SLIST_FIRST((head));				\
+	    (var);							\
+	    (var) = SLIST_NEXT((var), field))
+
+#define	SLIST_INIT(head) do {						\
+	SLIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	SLIST_INSERT_AFTER(slistelm, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field);	\
+	SLIST_NEXT((slistelm), field) = (elm);				\
+} while (0)
+
+#define	SLIST_INSERT_HEAD(head, elm, field) do {			\
+	SLIST_NEXT((elm), field) = SLIST_FIRST((head));			\
+	SLIST_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	SLIST_NEXT(elm, field)	((elm)->field.sle_next)
+
+#define	SLIST_REMOVE(head, elm, type, field) do {			\
+	if (SLIST_FIRST((head)) == (elm)) {				\
+		SLIST_REMOVE_HEAD((head), field);			\
+	}								\
+	else {								\
+		struct type *curelm = SLIST_FIRST((head));		\
+		while (SLIST_NEXT(curelm, field) != (elm))		\
+			curelm = SLIST_NEXT(curelm, field);		\
+		SLIST_NEXT(curelm, field) =				\
+		    SLIST_NEXT(SLIST_NEXT(curelm, field), field);	\
+	}								\
+} while (0)
+
+#define	SLIST_REMOVE_HEAD(head, field) do {				\
+	SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field);	\
+} while (0)
+
+/*
+ * Singly-linked Tail queue declarations.
+ */
+#define	STAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *stqh_first;/* first element */			\
+	struct type **stqh_last;/* addr of last next element */		\
+}
+
+#define	STAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).stqh_first }
+
+#define	STAILQ_ENTRY(type)						\
+struct {								\
+	struct type *stqe_next;	/* next element */			\
+}
+
+/*
+ * Singly-linked Tail queue functions.
+ */
+#define	STAILQ_EMPTY(head)	((head)->stqh_first == NULL)
+
+#define	STAILQ_FIRST(head)	((head)->stqh_first)
+
+#define	STAILQ_FOREACH(var, head, field)				\
+	for((var) = STAILQ_FIRST((head));				\
+	   (var);							\
+	   (var) = STAILQ_NEXT((var), field))
+
+#define	STAILQ_INIT(head) do {						\
+	STAILQ_FIRST((head)) = NULL;					\
+	(head)->stqh_last = &STAILQ_FIRST((head));			\
+} while (0)
+
+#define	STAILQ_INSERT_AFTER(head, tqelm, elm, field) do {		\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_NEXT((tqelm), field) = (elm);				\
+} while (0)
+
+#define	STAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL)	\
+		(head)->stqh_last = &STAILQ_NEXT((elm), field);		\
+	STAILQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	STAILQ_INSERT_TAIL(head, elm, field) do {			\
+	STAILQ_NEXT((elm), field) = NULL;				\
+	STAILQ_LAST((head)) = (elm);					\
+	(head)->stqh_last = &STAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	STAILQ_LAST(head)	(*(head)->stqh_last)
+
+#define	STAILQ_NEXT(elm, field)	((elm)->field.stqe_next)
+
+#define	STAILQ_REMOVE(head, elm, type, field) do {			\
+	if (STAILQ_FIRST((head)) == (elm)) {				\
+		STAILQ_REMOVE_HEAD(head, field);			\
+	}								\
+	else {								\
+		struct type *curelm = STAILQ_FIRST((head));		\
+		while (STAILQ_NEXT(curelm, field) != (elm))		\
+			curelm = STAILQ_NEXT(curelm, field);		\
+		if ((STAILQ_NEXT(curelm, field) =			\
+		     STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
+			(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
+	}								\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD(head, field) do {				\
+	if ((STAILQ_FIRST((head)) =					\
+	     STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL)		\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+#define	STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do {			\
+	if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL)	\
+		(head)->stqh_last = &STAILQ_FIRST((head));		\
+} while (0)
+
+/*
+ * List declarations.
+ */
+#define	LIST_HEAD(name, type)						\
+struct name {								\
+	struct type *lh_first;	/* first element */			\
+}
+
+#define	LIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	LIST_ENTRY(type)						\
+struct {								\
+	struct type *le_next;	/* next element */			\
+	struct type **le_prev;	/* address of previous next element */	\
+}
+
+/*
+ * List functions.
+ */
+
+#define	LIST_EMPTY(head)	((head)->lh_first == NULL)
+
+#define	LIST_FIRST(head)	((head)->lh_first)
+
+#define	LIST_FOREACH(var, head, field)					\
+	for ((var) = LIST_FIRST((head));				\
+	    (var);							\
+	    (var) = LIST_NEXT((var), field))
+
+#define	LIST_INIT(head) do {						\
+	LIST_FIRST((head)) = NULL;					\
+} while (0)
+
+#define	LIST_INSERT_AFTER(listelm, elm, field) do {			\
+	if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
+		LIST_NEXT((listelm), field)->field.le_prev =		\
+		    &LIST_NEXT((elm), field);				\
+	LIST_NEXT((listelm), field) = (elm);				\
+	(elm)->field.le_prev = &LIST_NEXT((listelm), field);		\
+} while (0)
+
+#define	LIST_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.le_prev = (listelm)->field.le_prev;		\
+	LIST_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.le_prev = (elm);				\
+	(listelm)->field.le_prev = &LIST_NEXT((elm), field);		\
+} while (0)
+
+#define	LIST_INSERT_HEAD(head, elm, field) do {				\
+	if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)	\
+		LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
+	LIST_FIRST((head)) = (elm);					\
+	(elm)->field.le_prev = &LIST_FIRST((head));			\
+} while (0)
+
+#define	LIST_NEXT(elm, field)	((elm)->field.le_next)
+
+#define	LIST_REMOVE(elm, field) do {					\
+	if (LIST_NEXT((elm), field) != NULL)				\
+		LIST_NEXT((elm), field)->field.le_prev = 		\
+		    (elm)->field.le_prev;				\
+	*(elm)->field.le_prev = LIST_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Tail queue declarations.
+ */
+#define	TAILQ_HEAD(name, type)						\
+struct name {								\
+	struct type *tqh_first;	/* first element */			\
+	struct type **tqh_last;	/* addr of last next element */		\
+}
+
+#define	TAILQ_HEAD_INITIALIZER(head)					\
+	{ NULL, &(head).tqh_first }
+
+#define	TAILQ_ENTRY(type)						\
+struct {								\
+	struct type *tqe_next;	/* next element */			\
+	struct type **tqe_prev;	/* address of previous next element */	\
+}
+
+/*
+ * Tail queue functions.
+ */
+#define	TAILQ_EMPTY(head)	((head)->tqh_first == NULL)
+
+#define	TAILQ_FIRST(head)	((head)->tqh_first)
+
+#define	TAILQ_FOREACH(var, head, field)					\
+	for ((var) = TAILQ_FIRST((head));				\
+	    (var);							\
+	    (var) = TAILQ_NEXT((var), field))
+
+#define	TAILQ_FOREACH_REVERSE(var, head, headname, field)		\
+	for ((var) = TAILQ_LAST((head), headname);			\
+	    (var);							\
+	    (var) = TAILQ_PREV((var), headname, field))
+
+#define	TAILQ_INIT(head) do {						\
+	TAILQ_FIRST((head)) = NULL;					\
+	(head)->tqh_last = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_NEXT((listelm), field) = (elm);				\
+	(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_BEFORE(listelm, elm, field) do {			\
+	(elm)->field.tqe_prev = (listelm)->field.tqe_prev;		\
+	TAILQ_NEXT((elm), field) = (listelm);				\
+	*(listelm)->field.tqe_prev = (elm);				\
+	(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field);		\
+} while (0)
+
+#define	TAILQ_INSERT_HEAD(head, elm, field) do {			\
+	if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL)	\
+		TAILQ_FIRST((head))->field.tqe_prev =			\
+		    &TAILQ_NEXT((elm), field);				\
+	else								\
+		(head)->tqh_last = &TAILQ_NEXT((elm), field);		\
+	TAILQ_FIRST((head)) = (elm);					\
+	(elm)->field.tqe_prev = &TAILQ_FIRST((head));			\
+} while (0)
+
+#define	TAILQ_INSERT_TAIL(head, elm, field) do {			\
+	TAILQ_NEXT((elm), field) = NULL;				\
+	(elm)->field.tqe_prev = (head)->tqh_last;			\
+	*(head)->tqh_last = (elm);					\
+	(head)->tqh_last = &TAILQ_NEXT((elm), field);			\
+} while (0)
+
+#define	TAILQ_LAST(head, headname)					\
+	(*(((struct headname *)((head)->tqh_last))->tqh_last))
+
+#define	TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
+
+#define	TAILQ_PREV(elm, headname, field)				\
+	(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
+
+#define	TAILQ_REMOVE(head, elm, field) do {				\
+	if ((TAILQ_NEXT((elm), field)) != NULL)				\
+		TAILQ_NEXT((elm), field)->field.tqe_prev = 		\
+		    (elm)->field.tqe_prev;				\
+	else								\
+		(head)->tqh_last = (elm)->field.tqe_prev;		\
+	*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field);		\
+} while (0)
+
+/*
+ * Circular queue declarations.
+ */
+#define	CIRCLEQ_HEAD(name, type)					\
+struct name {								\
+	struct type *cqh_first;		/* first element */		\
+	struct type *cqh_last;		/* last element */		\
+}
+
+#define	CIRCLEQ_HEAD_INITIALIZER(head)					\
+	{ (void *)&(head), (void *)&(head) }
+
+#define	CIRCLEQ_ENTRY(type)						\
+struct {								\
+	struct type *cqe_next;		/* next element */		\
+	struct type *cqe_prev;		/* previous element */		\
+}
+
+/*
+ * Circular queue functions.
+ */
+#define	CIRCLEQ_EMPTY(head)	((head)->cqh_first == (void *)(head))
+
+#define	CIRCLEQ_FIRST(head)	((head)->cqh_first)
+
+#define	CIRCLEQ_FOREACH(var, head, field)				\
+	for ((var) = CIRCLEQ_FIRST((head));				\
+	    (var) != (void *)(head);					\
+	    (var) = CIRCLEQ_NEXT((var), field))
+
+#define	CIRCLEQ_FOREACH_REVERSE(var, head, field)			\
+	for ((var) = CIRCLEQ_LAST((head));				\
+	    (var) != (void *)(head);					\
+	    (var) = CIRCLEQ_PREV((var), field))
+
+#define	CIRCLEQ_INIT(head) do {						\
+	CIRCLEQ_FIRST((head)) = (void *)(head);				\
+	CIRCLEQ_LAST((head)) = (void *)(head);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_AFTER(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_NEXT((listelm), field);	\
+	CIRCLEQ_PREV((elm), field) = (listelm);				\
+	if (CIRCLEQ_NEXT((listelm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((listelm), field), field) = (elm);\
+	CIRCLEQ_NEXT((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_BEFORE(head, listelm, elm, field) do {		\
+	CIRCLEQ_NEXT((elm), field) = (listelm);				\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_PREV((listelm), field);	\
+	if (CIRCLEQ_PREV((listelm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((listelm), field), field) = (elm);\
+	CIRCLEQ_PREV((listelm), field) = (elm);				\
+} while (0)
+
+#define	CIRCLEQ_INSERT_HEAD(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = CIRCLEQ_FIRST((head));		\
+	CIRCLEQ_PREV((elm), field) = (void *)(head);			\
+	if (CIRCLEQ_LAST((head)) == (void *)(head))			\
+		CIRCLEQ_LAST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_FIRST((head)), field) = (elm);	\
+	CIRCLEQ_FIRST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_INSERT_TAIL(head, elm, field) do {			\
+	CIRCLEQ_NEXT((elm), field) = (void *)(head);			\
+	CIRCLEQ_PREV((elm), field) = CIRCLEQ_LAST((head));		\
+	if (CIRCLEQ_FIRST((head)) == (void *)(head))			\
+		CIRCLEQ_FIRST((head)) = (elm);				\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_LAST((head)), field) = (elm);	\
+	CIRCLEQ_LAST((head)) = (elm);					\
+} while (0)
+
+#define	CIRCLEQ_LAST(head)	((head)->cqh_last)
+
+#define	CIRCLEQ_NEXT(elm,field)	((elm)->field.cqe_next)
+
+#define	CIRCLEQ_PREV(elm,field)	((elm)->field.cqe_prev)
+
+#define	CIRCLEQ_REMOVE(head, elm, field) do {				\
+	if (CIRCLEQ_NEXT((elm), field) == (void *)(head))		\
+		CIRCLEQ_LAST((head)) = CIRCLEQ_PREV((elm), field);	\
+	else								\
+		CIRCLEQ_PREV(CIRCLEQ_NEXT((elm), field), field) =	\
+		    CIRCLEQ_PREV((elm), field);				\
+	if (CIRCLEQ_PREV((elm), field) == (void *)(head))		\
+		CIRCLEQ_FIRST((head)) = CIRCLEQ_NEXT((elm), field);	\
+	else								\
+		CIRCLEQ_NEXT(CIRCLEQ_PREV((elm), field), field) =	\
+		    CIRCLEQ_NEXT((elm), field);				\
+} while (0)
+
+#endif /* !_SYS_QUEUE_H_ */
diff --git a/drivers/scsi/aic7xxx/scsi_iu.h b/drivers/scsi/aic7xxx/scsi_iu.h
new file mode 100644
index 0000000..0eafd3c
--- /dev/null
+++ b/drivers/scsi/aic7xxx/scsi_iu.h
@@ -0,0 +1,39 @@
+/*
+ * This file is in the public domain.
+ */
+#ifndef	_SCSI_SCSI_IU_H
+#define _SCSI_SCSI_IU_H 1
+
+struct scsi_status_iu_header
+{
+	u_int8_t reserved[2];
+	u_int8_t flags;
+#define	SIU_SNSVALID 0x2
+#define	SIU_RSPVALID 0x1
+	u_int8_t status;
+	u_int8_t sense_length[4];
+	u_int8_t pkt_failures_length[4];
+	u_int8_t pkt_failures[1];
+};
+
+#define SIU_PKTFAIL_OFFSET(siu) 12
+#define SIU_PKTFAIL_CODE(siu) (scsi_4btoul((siu)->pkt_failures) & 0xFF)
+#define		SIU_PFC_NONE			0
+#define		SIU_PFC_CIU_FIELDS_INVALID	2
+#define		SIU_PFC_TMF_NOT_SUPPORTED	4
+#define		SIU_PFC_TMF_FAILED		5
+#define		SIU_PFC_INVALID_TYPE_CODE	6
+#define		SIU_PFC_ILLEGAL_REQUEST		7
+#define SIU_SENSE_OFFSET(siu)				\
+    (12 + (((siu)->flags & SIU_RSPVALID)		\
+	? scsi_4btoul((siu)->pkt_failures_length)	\
+	: 0))
+
+#define	SIU_TASKMGMT_NONE		0x00
+#define	SIU_TASKMGMT_ABORT_TASK		0x01
+#define	SIU_TASKMGMT_ABORT_TASK_SET	0x02
+#define	SIU_TASKMGMT_CLEAR_TASK_SET	0x04
+#define	SIU_TASKMGMT_LUN_RESET		0x08
+#define	SIU_TASKMGMT_TARGET_RESET	0x20
+#define	SIU_TASKMGMT_CLEAR_ACA		0x40
+#endif /*_SCSI_SCSI_IU_H*/
diff --git a/drivers/scsi/aic7xxx/scsi_message.h b/drivers/scsi/aic7xxx/scsi_message.h
new file mode 100644
index 0000000..75811e2
--- /dev/null
+++ b/drivers/scsi/aic7xxx/scsi_message.h
@@ -0,0 +1,70 @@
+/*
+ * This file is in the public domain.
+ * $FreeBSD: src/sys/cam/scsi/scsi_message.h,v 1.2 2000/05/01 20:21:29 peter Exp $
+ */
+
+/* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
+#define MSG_CMDCOMPLETE		0x00 /* M/M */
+#define MSG_TASK_COMPLETE	0x00 /* M/M */ /* SPI3 Terminology */
+#define MSG_EXTENDED		0x01 /* O/O */
+#define MSG_SAVEDATAPOINTER	0x02 /* O/O */
+#define MSG_RESTOREPOINTERS	0x03 /* O/O */
+#define MSG_DISCONNECT		0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
+#define MSG_ABORT		0x06 /* O/M */
+#define MSG_ABORT_TASK_SET	0x06 /* O/M */ /* SPI3 Terminology */
+#define MSG_MESSAGE_REJECT	0x07 /* M/M */
+#define MSG_NOOP		0x08 /* M/M */
+#define MSG_PARITY_ERROR	0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */
+#define MSG_BUS_DEV_RESET	0x0c /* O/M */
+#define MSG_TARGET_RESET	0x0c /* O/M */ /* SPI3 Terminology */
+#define MSG_ABORT_TAG		0x0d /* O/O */
+#define MSG_ABORT_TASK		0x0d /* O/O */ /* SPI3 Terminology */
+#define MSG_CLEAR_QUEUE		0x0e /* O/O */
+#define MSG_CLEAR_TASK_SET	0x0e /* O/O */ /* SPI3 Terminology */
+#define MSG_INIT_RECOVERY	0x0f /* O/O */ /* Deprecated in SPI3 */
+#define MSG_REL_RECOVERY	0x10 /* O/O */ /* Deprecated in SPI3 */
+#define MSG_TERM_IO_PROC	0x11 /* O/O */ /* Deprecated in SPI3 */
+#define MSG_CLEAR_ACA		0x16 /* O/O */ /* SPI3 */
+#define MSG_LOGICAL_UNIT_RESET	0x17 /* O/O */ /* SPI3 */
+#define MSG_QAS_REQUEST		0x55 /* O/O */ /* SPI3 */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
+#define MSG_SIMPLE_TASK		0x20 /* O/O */ /* SPI3 Terminology */
+#define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
+#define MSG_HEAD_OF_QUEUE_TASK	0x21 /* O/O */ /* SPI3 Terminology */
+#define MSG_ORDERED_Q_TAG	0x22 /* O/O */
+#define MSG_ORDERED_TASK	0x22 /* O/O */ /* SPI3 Terminology */
+#define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
+#define MSG_ACA_TASK		0x24 /* 0/0 */ /* SPI3 */
+
+/* Identify message */		     /* M/M */	
+#define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY_DISCFLAG	0x40 
+#define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
+#define MSG_IDENTIFY_LUNMASK	0x3F 
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR		0x01
+#define MSG_EXT_SDTR_LEN	0x03
+
+#define MSG_EXT_WDTR		0x03
+#define MSG_EXT_WDTR_LEN	0x02
+#define MSG_EXT_WDTR_BUS_8_BIT	0x00
+#define MSG_EXT_WDTR_BUS_16_BIT	0x01
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02 /* Deprecated in SPI3 */
+
+#define MSG_EXT_PPR		0x04 /* SPI3 */
+#define MSG_EXT_PPR_LEN		0x06
+#define	MSG_EXT_PPR_PCOMP_EN	0x80
+#define	MSG_EXT_PPR_RTI		0x40
+#define	MSG_EXT_PPR_RD_STRM	0x20
+#define	MSG_EXT_PPR_WR_FLOW	0x10
+#define	MSG_EXT_PPR_HOLD_MCS	0x08
+#define	MSG_EXT_PPR_QAS_REQ	0x04
+#define	MSG_EXT_PPR_DT_REQ	0x02
+#define MSG_EXT_PPR_IU_REQ	0x01
diff --git a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
new file mode 100644
index 0000000..a6e7bb0
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old.c
@@ -0,0 +1,11178 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
+ *
+ * --------------------------------------------------------------------------
+ *
+ *  Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ *  Substantially modified to include support for wide and twin bus
+ *  adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ *  SCB paging, and other rework of the code.
+ *
+ *  Parts of this driver were also based on the FreeBSD driver by
+ *  Justin T. Gibbs.  His copyright follows:
+ *
+ * --------------------------------------------------------------------------  
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ *  Thanks also go to (in alphabetical order) the following:
+ *
+ *    Rory Bolt     - Sequencer bug fixes
+ *    Jay Estabrook - Initial DEC Alpha support
+ *    Doug Ledford  - Much needed abort/reset bug fixes
+ *    Kai Makisara  - DMAing of SCBs
+ *
+ *  A Boot time option was also added for not resetting the scsi bus.
+ *
+ *    Form:  aic7xxx=extended
+ *           aic7xxx=no_reset
+ *           aic7xxx=ultra
+ *           aic7xxx=irq_trigger:[0,1]  # 0 edge, 1 level
+ *           aic7xxx=verbose
+ *
+ *  Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
+ *
+ *  $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
+ *-M*************************************************************************/
+
+/*+M**************************************************************************
+ *
+ * Further driver modifications made by Doug Ledford <dledford@redhat.com>
+ *
+ * Copyright (c) 1997-1999 Doug Ledford
+ *
+ * These changes are released under the same licensing terms as the FreeBSD
+ * driver written by Justin Gibbs.  Please see his Copyright notice above
+ * for the exact terms and conditions covering my changes as well as the
+ * warranty statement.
+ *
+ * Modifications made to the aic7xxx.c,v 4.1 driver from Dan Eischen include
+ * but are not limited to:
+ *
+ *  1: Import of the latest FreeBSD sequencer code for this driver
+ *  2: Modification of kernel code to accommodate different sequencer semantics
+ *  3: Extensive changes throughout kernel portion of driver to improve
+ *     abort/reset processing and error hanndling
+ *  4: Other work contributed by various people on the Internet
+ *  5: Changes to printk information and verbosity selection code
+ *  6: General reliability related changes, especially in IRQ management
+ *  7: Modifications to the default probe/attach order for supported cards
+ *  8: SMP friendliness has been improved
+ *
+ * Overall, this driver represents a significant departure from the official
+ * aic7xxx driver released by Dan Eischen in two ways.  First, in the code
+ * itself.  A diff between the two version of the driver is now a several
+ * thousand line diff.  Second, in approach to solving the same problem.  The
+ * problem is importing the FreeBSD aic7xxx driver code to linux can be a
+ * difficult and time consuming process, that also can be error prone.  Dan
+ * Eischen's official driver uses the approach that the linux and FreeBSD
+ * drivers should be as identical as possible.  To that end, his next version
+ * of this driver will be using a mid-layer code library that he is developing
+ * to moderate communications between the linux mid-level SCSI code and the
+ * low level FreeBSD driver.  He intends to be able to essentially drop the
+ * FreeBSD driver into the linux kernel with only a few minor tweaks to some
+ * include files and the like and get things working, making for fast easy
+ * imports of the FreeBSD code into linux.
+ *
+ * I disagree with Dan's approach.  Not that I don't think his way of doing
+ * things would be nice, easy to maintain, and create a more uniform driver
+ * between FreeBSD and Linux.  I have no objection to those issues.  My
+ * disagreement is on the needed functionality.  There simply are certain
+ * things that are done differently in FreeBSD than linux that will cause
+ * problems for this driver regardless of any middle ware Dan implements.
+ * The biggest example of this at the moment is interrupt semantics.  Linux
+ * doesn't provide the same protection techniques as FreeBSD does, nor can
+ * they be easily implemented in any middle ware code since they would truly
+ * belong in the kernel proper and would effect all drivers.  For the time
+ * being, I see issues such as these as major stumbling blocks to the 
+ * reliability of code based upon such middle ware.  Therefore, I choose to
+ * use a different approach to importing the FreeBSD code that doesn't
+ * involve any middle ware type code.  My approach is to import the sequencer
+ * code from FreeBSD wholesale.  Then, to only make changes in the kernel
+ * portion of the driver as they are needed for the new sequencer semantics.
+ * In this way, the portion of the driver that speaks to the rest of the
+ * linux kernel is fairly static and can be changed/modified to solve
+ * any problems one might encounter without concern for the FreeBSD driver.
+ *
+ * Note: If time and experience should prove me wrong that the middle ware
+ * code Dan writes is reliable in its operation, then I'll retract my above
+ * statements.  But, for those that don't know, I'm from Missouri (in the US)
+ * and our state motto is "The Show-Me State".  Well, before I will put
+ * faith into it, you'll have to show me that it works :)
+ *
+ *_M*************************************************************************/
+
+/*
+ * The next three defines are user configurable.  These should be the only
+ * defines a user might need to get in here and change.  There are other
+ * defines buried deeper in the code, but those really shouldn't need touched
+ * under normal conditions.
+ */
+
+/*
+ * AIC7XXX_STRICT_PCI_SETUP
+ *   Should we assume the PCI config options on our controllers are set with
+ *   sane and proper values, or should we be anal about our PCI config
+ *   registers and force them to what we want?  The main advantage to
+ *   defining this option is on non-Intel hardware where the BIOS may not
+ *   have been run to set things up, or if you have one of the BIOSless
+ *   Adaptec controllers, such as a 2910, that don't get set up by the
+ *   BIOS.  However, keep in mind that we really do set the most important
+ *   items in the driver regardless of this setting, this only controls some
+ *   of the more esoteric PCI options on these cards.  In that sense, I
+ *   would default to leaving this off.  However, if people wish to try
+ *   things both ways, that would also help me to know if there are some
+ *   machines where it works one way but not another.
+ *
+ *   -- July 7, 17:09
+ *     OK...I need this on my machine for testing, so the default is to
+ *     leave it defined.
+ *
+ *   -- July 7, 18:49
+ *     I needed it for testing, but it didn't make any difference, so back
+ *     off she goes.
+ *
+ *   -- July 16, 23:04
+ *     I turned it back on to try and compensate for the 2.1.x PCI code
+ *     which no longer relies solely on the BIOS and now tries to set
+ *     things itself.
+ */
+
+#define AIC7XXX_STRICT_PCI_SETUP
+
+/*
+ * AIC7XXX_VERBOSE_DEBUGGING
+ *   This option enables a lot of extra printk();s in the code, surrounded
+ *   by if (aic7xxx_verbose ...) statements.  Executing all of those if
+ *   statements and the extra checks can get to where it actually does have
+ *   an impact on CPU usage and such, as well as code size.  Disabling this
+ *   define will keep some of those from becoming part of the code.
+ *
+ *   NOTE:  Currently, this option has no real effect, I will be adding the
+ *   various #ifdef's in the code later when I've decided a section is
+ *   complete and no longer needs debugging.  OK...a lot of things are now
+ *   surrounded by this define, so turning this off does have an impact.
+ */
+ 
+/*
+ * #define AIC7XXX_VERBOSE_DEBUGGING
+ */
+ 
+#include <linux/module.h>
+#include <stdarg.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/smp.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aic7xxx_old/aic7xxx.h"
+
+#include "aic7xxx_old/sequencer.h"
+#include "aic7xxx_old/scsi_message.h"
+#include "aic7xxx_old/aic7xxx_reg.h"
+#include <scsi/scsicam.h>
+
+#include <linux/stat.h>
+#include <linux/slab.h>        /* for kmalloc() */
+
+#include <linux/config.h>        /* for CONFIG_PCI */
+
+#define AIC7XXX_C_VERSION  "5.2.6"
+
+#define ALL_TARGETS -1
+#define ALL_CHANNELS -1
+#define ALL_LUNS -1
+#define MAX_TARGETS  16
+#define MAX_LUNS     8
+#ifndef TRUE
+#  define TRUE 1
+#endif
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+#if defined(__powerpc__) || defined(__i386__) || defined(__x86_64__)
+#  define MMAPIO
+#endif
+
+/*
+ * You can try raising me for better performance or lowering me if you have
+ * flaky devices that go off the scsi bus when hit with too many tagged
+ * commands (like some IBM SCSI-3 LVD drives).
+ */
+#define AIC7XXX_CMDS_PER_DEVICE 32
+
+typedef struct
+{
+  unsigned char tag_commands[16];   /* Allow for wide/twin adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver not to the default tag depth
+ * everywhere.
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0,\
+                              0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * Modify this as you see fit for your system.  By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above).  When 255, the driver will
+ * not enable tagged queueing for that particular device.  When positive
+ * (> 0) and (< 255) the values in the array are used for the queue_depth.
+ * Note that the maximum value for an entry is 254, but you're insane if
+ * you try to use that many commands on one device.
+ *
+ * In this example, the first line will disable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3.  It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+
+/*
+ * NOTE: The below structure is for reference only, the actual structure
+ *       to modify in order to change things is found after this fake one.
+ *
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 255, 4, 4, 4}},
+  {DEFAULT_TAG_COMMANDS},
+  {{255, 16, 4, 255, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+*/
+
+static adapter_tag_info_t aic7xxx_tag_info[] =
+{
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS},
+  {DEFAULT_TAG_COMMANDS}
+};
+
+
+/*
+ * Define an array of board names that can be indexed by aha_type.
+ * Don't forget to change this when changing the types!
+ */
+static const char *board_names[] = {
+  "AIC-7xxx Unknown",                                   /* AIC_NONE */
+  "Adaptec AIC-7810 Hardware RAID Controller",          /* AIC_7810 */
+  "Adaptec AIC-7770 SCSI host adapter",                 /* AIC_7770 */
+  "Adaptec AHA-274X SCSI host adapter",                 /* AIC_7771 */
+  "Adaptec AHA-284X SCSI host adapter",                 /* AIC_284x */
+  "Adaptec AIC-7850 SCSI host adapter",                 /* AIC_7850 */
+  "Adaptec AIC-7855 SCSI host adapter",                 /* AIC_7855 */
+  "Adaptec AIC-7860 Ultra SCSI host adapter",           /* AIC_7860 */
+  "Adaptec AHA-2940A Ultra SCSI host adapter",          /* AIC_7861 */
+  "Adaptec AIC-7870 SCSI host adapter",                 /* AIC_7870 */
+  "Adaptec AHA-294X SCSI host adapter",                 /* AIC_7871 */
+  "Adaptec AHA-394X SCSI host adapter",                 /* AIC_7872 */
+  "Adaptec AHA-398X SCSI host adapter",                 /* AIC_7873 */
+  "Adaptec AHA-2944 SCSI host adapter",                 /* AIC_7874 */
+  "Adaptec AIC-7880 Ultra SCSI host adapter",           /* AIC_7880 */
+  "Adaptec AHA-294X Ultra SCSI host adapter",           /* AIC_7881 */
+  "Adaptec AHA-394X Ultra SCSI host adapter",           /* AIC_7882 */
+  "Adaptec AHA-398X Ultra SCSI host adapter",           /* AIC_7883 */
+  "Adaptec AHA-2944 Ultra SCSI host adapter",           /* AIC_7884 */
+  "Adaptec AHA-2940UW Pro Ultra SCSI host adapter",     /* AIC_7887 */
+  "Adaptec AIC-7895 Ultra SCSI host adapter",           /* AIC_7895 */
+  "Adaptec AIC-7890/1 Ultra2 SCSI host adapter",        /* AIC_7890 */
+  "Adaptec AHA-293X Ultra2 SCSI host adapter",          /* AIC_7890 */
+  "Adaptec AHA-294X Ultra2 SCSI host adapter",          /* AIC_7890 */
+  "Adaptec AIC-7896/7 Ultra2 SCSI host adapter",        /* AIC_7896 */
+  "Adaptec AHA-394X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec AHA-395X Ultra2 SCSI host adapter",          /* AIC_7897 */
+  "Adaptec PCMCIA SCSI controller",                     /* card bus stuff */
+  "Adaptec AIC-7892 Ultra 160/m SCSI host adapter",     /* AIC_7892 */
+  "Adaptec AIC-7899 Ultra 160/m SCSI host adapter",     /* AIC_7899 */
+};
+
+/*
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
+ */
+#define DID_UNDERFLOW   DID_ERROR
+
+/*
+ *  What we want to do is have the higher level scsi driver requeue
+ *  the command to us. There is no specific driver status for this
+ *  condition, but the higher level scsi driver will requeue the
+ *  command on a DID_BUS_BUSY error.
+ *
+ *  Upon further inspection and testing, it seems that DID_BUS_BUSY
+ *  will *always* retry the command.  We can get into an infinite loop
+ *  if this happens when we really want some sort of counter that
+ *  will automatically abort/reset the command after so many retries.
+ *  Using DID_ERROR will do just that.  (Made by a suggestion by
+ *  Doug Ledford 8/1/96)
+ */
+#define DID_RETRY_COMMAND DID_ERROR
+
+#define HSCSIID        0x07
+#define SCSI_RESET     0x040
+
+/*
+ * EISA/VL-bus stuff
+ */
+#define MINSLOT                1
+#define MAXSLOT                15
+#define SLOTBASE(x)        ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
+
+/*
+ * Standard EISA Host ID regs  (Offset from slot base)
+ */
+#define AHC_HID0              0x80   /* 0,1: msb of ID2, 2-7: ID1      */
+#define AHC_HID1              0x81   /* 0-4: ID3, 5-7: LSB ID2         */
+#define AHC_HID2              0x82   /* product                        */
+#define AHC_HID3              0x83   /* firmware revision              */
+
+/*
+ * AIC-7770 I/O range to reserve for a card
+ */
+#define MINREG                0xC00
+#define MAXREG                0xCFF
+
+#define INTDEF                0x5C      /* Interrupt Definition Register */
+
+/*
+ * AIC-78X0 PCI registers
+ */
+#define        CLASS_PROGIF_REVID        0x08
+#define                DEVREVID        0x000000FFul
+#define                PROGINFC        0x0000FF00ul
+#define                SUBCLASS        0x00FF0000ul
+#define                BASECLASS        0xFF000000ul
+
+#define        CSIZE_LATTIME                0x0C
+#define                CACHESIZE        0x0000003Ful        /* only 5 bits */
+#define                LATTIME                0x0000FF00ul
+
+#define        DEVCONFIG                0x40
+#define                SCBSIZE32        0x00010000ul        /* aic789X only */
+#define                MPORTMODE        0x00000400ul        /* aic7870 only */
+#define                RAMPSM           0x00000200ul        /* aic7870 only */
+#define                RAMPSM_ULTRA2    0x00000004
+#define                VOLSENSE         0x00000100ul
+#define                SCBRAMSEL        0x00000080ul
+#define                SCBRAMSEL_ULTRA2 0x00000008
+#define                MRDCEN           0x00000040ul
+#define                EXTSCBTIME       0x00000020ul        /* aic7870 only */
+#define                EXTSCBPEN        0x00000010ul        /* aic7870 only */
+#define                BERREN           0x00000008ul
+#define                DACEN            0x00000004ul
+#define                STPWLEVEL        0x00000002ul
+#define                DIFACTNEGEN      0x00000001ul        /* aic7870 only */
+
+#define        SCAMCTL                  0x1a                /* Ultra2 only  */
+#define        CCSCBBADDR               0xf0                /* aic7895/6/7  */
+
+/*
+ * Define the different types of SEEPROMs on aic7xxx adapters
+ * and make it also represent the address size used in accessing
+ * its registers.  The 93C46 chips have 1024 bits organized into
+ * 64 16-bit words, while the 93C56 chips have 2048 bits organized
+ * into 128 16-bit words.  The C46 chips use 6 bits to address
+ * each word, while the C56 and C66 (4096 bits) use 8 bits to
+ * address each word.
+ */
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
+
+/*
+ *
+ * Define the format of the SEEPROM registers (16 bits).
+ *
+ */
+struct seeprom_config {
+
+/*
+ * SCSI ID Configuration Flags
+ */
+#define CFXFER                0x0007      /* synchronous transfer rate */
+#define CFSYNCH               0x0008      /* enable synchronous transfer */
+#define CFDISC                0x0010      /* enable disconnection */
+#define CFWIDEB               0x0020      /* wide bus device (wide card) */
+#define CFSYNCHISULTRA        0x0040      /* CFSYNC is an ultra offset */
+#define CFNEWULTRAFORMAT      0x0080      /* Use the Ultra2 SEEPROM format */
+#define CFSTART               0x0100      /* send start unit SCSI command */
+#define CFINCBIOS             0x0200      /* include in BIOS scan */
+#define CFRNFOUND             0x0400      /* report even if not found */
+#define CFMULTILUN            0x0800      /* probe mult luns in BIOS scan */
+#define CFWBCACHEYES          0x4000      /* Enable W-Behind Cache on drive */
+#define CFWBCACHENC           0xc000      /* Don't change W-Behind Cache */
+/* UNUSED                0x3000 */
+  unsigned short device_flags[16];        /* words 0-15 */
+
+/*
+ * BIOS Control Bits
+ */
+#define CFSUPREM        0x0001  /* support all removable drives */
+#define CFSUPREMB       0x0002  /* support removable drives for boot only */
+#define CFBIOSEN        0x0004  /* BIOS enabled */
+/* UNUSED                0x0008 */
+#define CFSM2DRV        0x0010  /* support more than two drives */
+#define CF284XEXTEND    0x0020  /* extended translation (284x cards) */
+/* UNUSED                0x0040 */
+#define CFEXTEND        0x0080  /* extended translation enabled */
+/* UNUSED                0xFF00 */
+  unsigned short bios_control;  /* word 16 */
+
+/*
+ * Host Adapter Control Bits
+ */
+#define CFAUTOTERM      0x0001  /* Perform Auto termination */
+#define CFULTRAEN       0x0002  /* Ultra SCSI speed enable (Ultra cards) */
+#define CF284XSELTO     0x0003  /* Selection timeout (284x cards) */
+#define CF284XFIFO      0x000C  /* FIFO Threshold (284x cards) */
+#define CFSTERM         0x0004  /* SCSI low byte termination */
+#define CFWSTERM        0x0008  /* SCSI high byte termination (wide card) */
+#define CFSPARITY       0x0010  /* SCSI parity */
+#define CF284XSTERM     0x0020  /* SCSI low byte termination (284x cards) */
+#define CFRESETB        0x0040  /* reset SCSI bus at boot */
+#define CFBPRIMARY      0x0100  /* Channel B primary on 7895 chipsets */
+#define CFSEAUTOTERM    0x0400  /* aic7890 Perform SE Auto Term */
+#define CFLVDSTERM      0x0800  /* aic7890 LVD Termination */
+/* UNUSED                0xF280 */
+  unsigned short adapter_control;        /* word 17 */
+
+/*
+ * Bus Release, Host Adapter ID
+ */
+#define CFSCSIID        0x000F                /* host adapter SCSI ID */
+/* UNUSED                0x00F0 */
+#define CFBRTIME        0xFF00                /* bus release time */
+  unsigned short brtime_id;                /* word 18 */
+
+/*
+ * Maximum targets
+ */
+#define CFMAXTARG        0x00FF        /* maximum targets */
+/* UNUSED                0xFF00 */
+  unsigned short max_targets;                /* word 19 */
+
+  unsigned short res_1[11];                /* words 20-30 */
+  unsigned short checksum;                /* word 31 */
+};
+
+#define SELBUS_MASK                0x0a
+#define         SELNARROW        0x00
+#define         SELBUSB                0x08
+#define SINGLE_BUS                0x00
+
+#define SCB_TARGET(scb)         \
+       (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb)            \
+       ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb)   \
+       (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
+
+/*
+ * If an error occurs during a data transfer phase, run the command
+ * to completion - it's easier that way - making a note of the error
+ * condition in this location. This then will modify a DID_OK status
+ * into an appropriate error for the higher-level SCSI code.
+ */
+#define aic7xxx_error(cmd)        ((cmd)->SCp.Status)
+
+/*
+ * Keep track of the targets returned status.
+ */
+#define aic7xxx_status(cmd)        ((cmd)->SCp.sent_command)
+
+/*
+ * The position of the SCSI commands scb within the scb array.
+ */
+#define aic7xxx_position(cmd)        ((cmd)->SCp.have_data_in)
+
+/*
+ * The stored DMA mapping for single-buffer data transfers.
+ */
+#define aic7xxx_mapping(cmd)	     ((cmd)->SCp.phase)
+
+/*
+ * Get out private data area from a scsi cmd pointer
+ */
+#define AIC_DEV(cmd)	((struct aic_dev_data *)(cmd)->device->hostdata)
+
+/*
+ * So we can keep track of our host structs
+ */
+static struct aic7xxx_host *first_aic7xxx = NULL;
+
+/*
+ * As of Linux 2.1, the mid-level SCSI code uses virtual addresses
+ * in the scatter-gather lists.  We need to convert the virtual
+ * addresses to physical addresses.
+ */
+struct hw_scatterlist {
+  unsigned int address;
+  unsigned int length;
+};
+
+/*
+ * Maximum number of SG segments these cards can support.
+ */
+#define        AIC7XXX_MAX_SG 128
+
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB        255
+
+
+struct aic7xxx_hwscb {
+/* ------------    Begin hardware supported fields    ---------------- */
+/* 0*/  unsigned char control;
+/* 1*/  unsigned char target_channel_lun;       /* 4/1/3 bits */
+/* 2*/  unsigned char target_status;
+/* 3*/  unsigned char SG_segment_count;
+/* 4*/  unsigned int  SG_list_pointer;
+/* 8*/  unsigned char residual_SG_segment_count;
+/* 9*/  unsigned char residual_data_count[3];
+/*12*/  unsigned int  data_pointer;
+/*16*/  unsigned int  data_count;
+/*20*/  unsigned int  SCSI_cmd_pointer;
+/*24*/  unsigned char SCSI_cmd_length;
+/*25*/  unsigned char tag;          /* Index into our kernel SCB array.
+                                     * Also used as the tag for tagged I/O
+                                     */
+#define SCB_PIO_TRANSFER_SIZE  26   /* amount we need to upload/download
+                                     * via PIO to initialize a transaction.
+                                     */
+/*26*/  unsigned char next;         /* Used to thread SCBs awaiting selection
+                                     * or disconnected down in the sequencer.
+                                     */
+/*27*/  unsigned char prev;
+/*28*/  unsigned int pad;           /*
+                                     * Unused by the kernel, but we require
+                                     * the padding so that the array of
+                                     * hardware SCBs is aligned on 32 byte
+                                     * boundaries so the sequencer can index
+                                     */
+};
+
+typedef enum {
+        SCB_FREE                = 0x0000,
+        SCB_DTR_SCB             = 0x0001,
+        SCB_WAITINGQ            = 0x0002,
+        SCB_ACTIVE              = 0x0004,
+        SCB_SENSE               = 0x0008,
+        SCB_ABORT               = 0x0010,
+        SCB_DEVICE_RESET        = 0x0020,
+        SCB_RESET               = 0x0040,
+        SCB_RECOVERY_SCB        = 0x0080,
+        SCB_MSGOUT_PPR          = 0x0100,
+        SCB_MSGOUT_SENT         = 0x0200,
+        SCB_MSGOUT_SDTR         = 0x0400,
+        SCB_MSGOUT_WDTR         = 0x0800,
+        SCB_MSGOUT_BITS         = SCB_MSGOUT_PPR |
+                                  SCB_MSGOUT_SENT | 
+                                  SCB_MSGOUT_SDTR |
+                                  SCB_MSGOUT_WDTR,
+        SCB_QUEUED_ABORT        = 0x1000,
+        SCB_QUEUED_FOR_DONE     = 0x2000,
+        SCB_WAS_BUSY            = 0x4000,
+	SCB_QUEUE_FULL		= 0x8000
+} scb_flag_type;
+
+typedef enum {
+        AHC_FNONE                 = 0x00000000,
+        AHC_PAGESCBS              = 0x00000001,
+        AHC_CHANNEL_B_PRIMARY     = 0x00000002,
+        AHC_USEDEFAULTS           = 0x00000004,
+        AHC_INDIRECT_PAGING       = 0x00000008,
+        AHC_CHNLB                 = 0x00000020,
+        AHC_CHNLC                 = 0x00000040,
+        AHC_EXTEND_TRANS_A        = 0x00000100,
+        AHC_EXTEND_TRANS_B        = 0x00000200,
+        AHC_TERM_ENB_A            = 0x00000400,
+        AHC_TERM_ENB_SE_LOW       = 0x00000400,
+        AHC_TERM_ENB_B            = 0x00000800,
+        AHC_TERM_ENB_SE_HIGH      = 0x00000800,
+        AHC_HANDLING_REQINITS     = 0x00001000,
+        AHC_TARGETMODE            = 0x00002000,
+        AHC_NEWEEPROM_FMT         = 0x00004000,
+ /*
+  *  Here ends the FreeBSD defined flags and here begins the linux defined
+  *  flags.  NOTE: I did not preserve the old flag name during this change
+  *  specifically to force me to evaluate what flags were being used properly
+  *  and what flags weren't.  This way, I could clean up the flag usage on
+  *  a use by use basis.  Doug Ledford
+  */
+        AHC_MOTHERBOARD           = 0x00020000,
+        AHC_NO_STPWEN             = 0x00040000,
+        AHC_RESET_DELAY           = 0x00080000,
+        AHC_A_SCANNED             = 0x00100000,
+        AHC_B_SCANNED             = 0x00200000,
+        AHC_MULTI_CHANNEL         = 0x00400000,
+        AHC_BIOS_ENABLED          = 0x00800000,
+        AHC_SEEPROM_FOUND         = 0x01000000,
+        AHC_TERM_ENB_LVD          = 0x02000000,
+        AHC_ABORT_PENDING         = 0x04000000,
+        AHC_RESET_PENDING         = 0x08000000,
+#define AHC_IN_ISR_BIT              28
+        AHC_IN_ISR                = 0x10000000,
+        AHC_IN_ABORT              = 0x20000000,
+        AHC_IN_RESET              = 0x40000000,
+        AHC_EXTERNAL_SRAM         = 0x80000000
+} ahc_flag_type;
+
+typedef enum {
+  AHC_NONE             = 0x0000,
+  AHC_CHIPID_MASK      = 0x00ff,
+  AHC_AIC7770          = 0x0001,
+  AHC_AIC7850          = 0x0002,
+  AHC_AIC7860          = 0x0003,
+  AHC_AIC7870          = 0x0004,
+  AHC_AIC7880          = 0x0005,
+  AHC_AIC7890          = 0x0006,
+  AHC_AIC7895          = 0x0007,
+  AHC_AIC7896          = 0x0008,
+  AHC_AIC7892          = 0x0009,
+  AHC_AIC7899          = 0x000a,
+  AHC_VL               = 0x0100,
+  AHC_EISA             = 0x0200,
+  AHC_PCI              = 0x0400,
+} ahc_chip;
+
+typedef enum {
+  AHC_FENONE           = 0x0000,
+  AHC_ULTRA            = 0x0001,
+  AHC_ULTRA2           = 0x0002,
+  AHC_WIDE             = 0x0004,
+  AHC_TWIN             = 0x0008,
+  AHC_MORE_SRAM        = 0x0010,
+  AHC_CMD_CHAN         = 0x0020,
+  AHC_QUEUE_REGS       = 0x0040,
+  AHC_SG_PRELOAD       = 0x0080,
+  AHC_SPIOCAP          = 0x0100,
+  AHC_ULTRA3           = 0x0200,
+  AHC_NEW_AUTOTERM     = 0x0400,
+  AHC_AIC7770_FE       = AHC_FENONE,
+  AHC_AIC7850_FE       = AHC_SPIOCAP,
+  AHC_AIC7860_FE       = AHC_ULTRA|AHC_SPIOCAP,
+  AHC_AIC7870_FE       = AHC_FENONE,
+  AHC_AIC7880_FE       = AHC_ULTRA,
+  AHC_AIC7890_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA2|
+                         AHC_QUEUE_REGS|AHC_SG_PRELOAD|AHC_NEW_AUTOTERM,
+  AHC_AIC7895_FE       = AHC_MORE_SRAM|AHC_CMD_CHAN|AHC_ULTRA,
+  AHC_AIC7896_FE       = AHC_AIC7890_FE,
+  AHC_AIC7892_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+  AHC_AIC7899_FE       = AHC_AIC7890_FE|AHC_ULTRA3,
+} ahc_feature;
+
+#define SCB_DMA_ADDR(scb, addr) ((unsigned long)(addr) + (scb)->scb_dma->dma_offset)
+
+struct aic7xxx_scb_dma {
+	unsigned long	       dma_offset;    /* Correction you have to add
+					       * to virtual address to get
+					       * dma handle in this region */
+	dma_addr_t	       dma_address;   /* DMA handle of the start,
+					       * for unmap */
+	unsigned int	       dma_len;	      /* DMA length */
+};
+
+typedef enum {
+  AHC_BUG_NONE            = 0x0000,
+  AHC_BUG_TMODE_WIDEODD   = 0x0001,
+  AHC_BUG_AUTOFLUSH       = 0x0002,
+  AHC_BUG_CACHETHEN       = 0x0004,
+  AHC_BUG_CACHETHEN_DIS   = 0x0008,
+  AHC_BUG_PCI_2_1_RETRY   = 0x0010,
+  AHC_BUG_PCI_MWI         = 0x0020,
+  AHC_BUG_SCBCHAN_UPLOAD  = 0x0040,
+} ahc_bugs;
+
+struct aic7xxx_scb {
+        struct aic7xxx_hwscb  *hscb;          /* corresponding hardware scb */
+        Scsi_Cmnd             *cmd;              /* Scsi_Cmnd for this scb */
+        struct aic7xxx_scb    *q_next;        /* next scb in queue */
+        volatile scb_flag_type flags;         /* current state of scb */
+        struct hw_scatterlist *sg_list;       /* SG list in adapter format */
+        unsigned char          tag_action;
+        unsigned char          sg_count;
+        unsigned char          *sense_cmd;    /*
+                                               * Allocate 6 characters for
+                                               * sense command.
+                                               */
+	unsigned char	       *cmnd;
+        unsigned int           sg_length; /* We init this during buildscb so we
+                                           * don't have to calculate anything
+                                           * during underflow/overflow/stat code
+                                           */
+        void                  *kmalloc_ptr;
+	struct aic7xxx_scb_dma *scb_dma;
+};
+
+/*
+ * Define a linked list of SCBs.
+ */
+typedef struct {
+  struct aic7xxx_scb *head;
+  struct aic7xxx_scb *tail;
+} scb_queue_type;
+
+static struct {
+  unsigned char errno;
+  const char *errmesg;
+} hard_error[] = {
+  { ILLHADDR,  "Illegal Host Access" },
+  { ILLSADDR,  "Illegal Sequencer Address referenced" },
+  { ILLOPCODE, "Illegal Opcode in sequencer program" },
+  { SQPARERR,  "Sequencer Ram Parity Error" },
+  { DPARERR,   "Data-Path Ram Parity Error" },
+  { MPARERR,   "Scratch Ram/SCB Array Ram Parity Error" },
+  { PCIERRSTAT,"PCI Error detected" },
+  { CIOPARERR, "CIOBUS Parity Error" }
+};
+
+static unsigned char
+generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
+
+typedef struct {
+  scb_queue_type free_scbs;        /*
+                                    * SCBs assigned to free slot on
+                                    * card (no paging required)
+                                    */
+  struct aic7xxx_scb   *scb_array[AIC7XXX_MAXSCB];
+  struct aic7xxx_hwscb *hscbs;
+  unsigned char  numscbs;          /* current number of scbs */
+  unsigned char  maxhscbs;         /* hardware scbs */
+  unsigned char  maxscbs;          /* max scbs including pageable scbs */
+  dma_addr_t	 hscbs_dma;	   /* DMA handle to hscbs */
+  unsigned int   hscbs_dma_len;    /* length of the above DMA area */
+  void          *hscb_kmalloc_ptr;
+} scb_data_type;
+
+struct target_cmd {
+  unsigned char mesg_bytes[4];
+  unsigned char command[28];
+};
+
+#define AHC_TRANS_CUR    0x0001
+#define AHC_TRANS_ACTIVE 0x0002
+#define AHC_TRANS_GOAL   0x0004
+#define AHC_TRANS_USER   0x0008
+#define AHC_TRANS_QUITE  0x0010
+typedef struct {
+  unsigned char width;
+  unsigned char period;
+  unsigned char offset;
+  unsigned char options;
+} transinfo_type;
+
+struct aic_dev_data {
+  volatile scb_queue_type  delayed_scbs;
+  volatile unsigned short  temp_q_depth;
+  unsigned short           max_q_depth;
+  volatile unsigned char   active_cmds;
+  /*
+   * Statistics Kept:
+   *
+   * Total Xfers (count for each command that has a data xfer),
+   * broken down by reads && writes.
+   *
+   * Further sorted into a few bins for keeping tabs on how many commands
+   * we get of various sizes.
+   *
+   */
+  long w_total;                          /* total writes */
+  long r_total;                          /* total reads */
+  long barrier_total;			 /* total num of REQ_BARRIER commands */
+  long ordered_total;			 /* How many REQ_BARRIER commands we
+					    used ordered tags to satisfy */
+  long w_bins[6];                       /* binned write */
+  long r_bins[6];                       /* binned reads */
+  transinfo_type	cur;
+  transinfo_type	goal;
+#define  BUS_DEVICE_RESET_PENDING       0x01
+#define  DEVICE_RESET_DELAY             0x02
+#define  DEVICE_PRINT_DTR               0x04
+#define  DEVICE_WAS_BUSY                0x08
+#define  DEVICE_DTR_SCANNED		0x10
+#define  DEVICE_SCSI_3			0x20
+  volatile unsigned char   flags;
+  unsigned needppr:1;
+  unsigned needppr_copy:1;
+  unsigned needsdtr:1;
+  unsigned needsdtr_copy:1;
+  unsigned needwdtr:1;
+  unsigned needwdtr_copy:1;
+  unsigned dtr_pending:1;
+  struct scsi_device *SDptr;
+  struct list_head list;
+};
+
+/*
+ * Define a structure used for each host adapter.  Note, in order to avoid
+ * problems with architectures I can't test on (because I don't have one,
+ * such as the Alpha based systems) which happen to give faults for
+ * non-aligned memory accesses, care was taken to align this structure
+ * in a way that gauranteed all accesses larger than 8 bits were aligned
+ * on the appropriate boundary.  It's also organized to try and be more
+ * cache line efficient.  Be careful when changing this lest you might hurt
+ * overall performance and bring down the wrath of the masses.
+ */
+struct aic7xxx_host {
+  /*
+   *  This is the first 64 bytes in the host struct
+   */
+
+  /*
+   * We are grouping things here....first, items that get either read or
+   * written with nearly every interrupt
+   */
+  volatile long            flags;
+  ahc_feature              features;         /* chip features */
+  unsigned long            base;             /* card base address */
+  volatile unsigned char  __iomem *maddr;            /* memory mapped address */
+  unsigned long            isr_count;        /* Interrupt count */
+  unsigned long            spurious_int;
+  scb_data_type           *scb_data;
+  struct aic7xxx_cmd_queue {
+    Scsi_Cmnd *head;
+    Scsi_Cmnd *tail;
+  } completeq;
+
+  /*
+   * Things read/written on nearly every entry into aic7xxx_queue()
+   */
+  volatile scb_queue_type  waiting_scbs;
+  unsigned char            unpause;          /* unpause value for HCNTRL */
+  unsigned char            pause;            /* pause value for HCNTRL */
+  volatile unsigned char   qoutfifonext;
+  volatile unsigned char   activescbs;       /* active scbs */
+  volatile unsigned char   max_activescbs;
+  volatile unsigned char   qinfifonext;
+  volatile unsigned char  *untagged_scbs;
+  volatile unsigned char  *qoutfifo;
+  volatile unsigned char  *qinfifo;
+
+  unsigned char            dev_last_queue_full[MAX_TARGETS];
+  unsigned char            dev_last_queue_full_count[MAX_TARGETS];
+  unsigned short	   ultraenb;         /* Gets downloaded to card as a
+						bitmap */
+  unsigned short	   discenable;       /* Gets downloaded to card as a
+						bitmap */
+  transinfo_type           user[MAX_TARGETS];
+
+  unsigned char            msg_buf[13];      /* The message for the target */
+  unsigned char            msg_type;
+#define MSG_TYPE_NONE              0x00
+#define MSG_TYPE_INITIATOR_MSGOUT  0x01
+#define MSG_TYPE_INITIATOR_MSGIN   0x02
+  unsigned char            msg_len;          /* Length of message */
+  unsigned char            msg_index;        /* Index into msg_buf array */
+
+
+  /*
+   * We put the less frequently used host structure items after the more
+   * frequently used items to try and ease the burden on the cache subsystem.
+   * These entries are not *commonly* accessed, whereas the preceding entries
+   * are accessed very often.
+   */
+
+  unsigned int             irq;              /* IRQ for this adapter */
+  int                      instance;         /* aic7xxx instance number */
+  int                      scsi_id;          /* host adapter SCSI ID */
+  int                      scsi_id_b;        /* channel B for twin adapters */
+  unsigned int             bios_address;
+  int                      board_name_index;
+  unsigned short           bios_control;     /* bios control - SEEPROM */
+  unsigned short           adapter_control;  /* adapter control - SEEPROM */
+  struct pci_dev	  *pdev;
+  unsigned char            pci_bus;
+  unsigned char            pci_device_fn;
+  struct seeprom_config    sc;
+  unsigned short           sc_type;
+  unsigned short           sc_size;
+  struct aic7xxx_host     *next;             /* allow for multiple IRQs */
+  struct Scsi_Host        *host;             /* pointer to scsi host */
+  struct list_head	   aic_devs;	     /* all aic_dev structs on host */
+  int                      host_no;          /* SCSI host number */
+  unsigned long            mbase;            /* I/O memory address */
+  ahc_chip                 chip;             /* chip type */
+  ahc_bugs                 bugs;
+  dma_addr_t		   fifo_dma;	     /* DMA handle for fifo arrays */
+
+};
+
+/*
+ * Valid SCSIRATE values. (p. 3-17)
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
+ */
+#define AHC_SYNCRATE_ULTRA3 0
+#define AHC_SYNCRATE_ULTRA2 1
+#define AHC_SYNCRATE_ULTRA  3
+#define AHC_SYNCRATE_FAST   6
+#define AHC_SYNCRATE_CRC 0x40
+#define AHC_SYNCRATE_SE  0x10
+static struct aic7xxx_syncrate {
+  /* Rates in Ultra mode have bit 8 of sxfr set */
+#define                ULTRA_SXFR 0x100
+  int sxfr_ultra2;
+  int sxfr;
+  unsigned char period;
+  const char *rate[2];
+} aic7xxx_syncrates[] = {
+  { 0x42,  0x000,   9,  {"80.0", "160.0"} },
+  { 0x13,  0x000,  10,  {"40.0", "80.0"} },
+  { 0x14,  0x000,  11,  {"33.0", "66.6"} },
+  { 0x15,  0x100,  12,  {"20.0", "40.0"} },
+  { 0x16,  0x110,  15,  {"16.0", "32.0"} },
+  { 0x17,  0x120,  18,  {"13.4", "26.8"} },
+  { 0x18,  0x000,  25,  {"10.0", "20.0"} },
+  { 0x19,  0x010,  31,  {"8.0",  "16.0"} },
+  { 0x1a,  0x020,  37,  {"6.67", "13.3"} },
+  { 0x1b,  0x030,  43,  {"5.7",  "11.4"} },
+  { 0x10,  0x040,  50,  {"5.0",  "10.0"} },
+  { 0x00,  0x050,  56,  {"4.4",  "8.8" } },
+  { 0x00,  0x060,  62,  {"4.0",  "8.0" } },
+  { 0x00,  0x070,  68,  {"3.6",  "7.2" } },
+  { 0x00,  0x000,  0,   {NULL, NULL}   },
+};
+
+#define CTL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 3) & 0x1),  \
+                        (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+                        ((scb->hscb)->target_channel_lun & 0x07)
+
+#define CTL_OF_CMD(cmd) ((cmd->device->channel) & 0x01),  \
+                        ((cmd->device->id) & 0x0f), \
+                        ((cmd->device->lun) & 0x07)
+
+#define TARGET_INDEX(cmd)  ((cmd)->device->id | ((cmd)->device->channel << 3))
+
+/*
+ * A nice little define to make doing our printks a little easier
+ */
+
+#define WARN_LEAD KERN_WARNING "(scsi%d:%d:%d:%d) "
+#define INFO_LEAD KERN_INFO "(scsi%d:%d:%d:%d) "
+
+/*
+ * XXX - these options apply unilaterally to _all_ 274x/284x/294x
+ *       cards in the system.  This should be fixed.  Exceptions to this
+ *       rule are noted in the comments.
+ */
+
+/*
+ * Use this as the default queue depth when setting tagged queueing on.
+ */
+static unsigned int aic7xxx_default_queue_depth = AIC7XXX_CMDS_PER_DEVICE;
+
+/*
+ * Skip the scsi bus reset.  Non 0 make us skip the reset at startup.  This
+ * has no effect on any later resets that might occur due to things like
+ * SCSI bus timeouts.
+ */
+static unsigned int aic7xxx_no_reset = 0;
+/*
+ * Certain PCI motherboards will scan PCI devices from highest to lowest,
+ * others scan from lowest to highest, and they tend to do all kinds of
+ * strange things when they come into contact with PCI bridge chips.  The
+ * net result of all this is that the PCI card that is actually used to boot
+ * the machine is very hard to detect.  Most motherboards go from lowest
+ * PCI slot number to highest, and the first SCSI controller found is the
+ * one you boot from.  The only exceptions to this are when a controller
+ * has its BIOS disabled.  So, we by default sort all of our SCSI controllers
+ * from lowest PCI slot number to highest PCI slot number.  We also force
+ * all controllers with their BIOS disabled to the end of the list.  This
+ * works on *almost* all computers.  Where it doesn't work, we have this
+ * option.  Setting this option to non-0 will reverse the order of the sort
+ * to highest first, then lowest, but will still leave cards with their BIOS
+ * disabled at the very end.  That should fix everyone up unless there are
+ * really strange cirumstances.
+ */
+static int aic7xxx_reverse_scan = 0;
+/*
+ * Should we force EXTENDED translation on a controller.
+ *     0 == Use whatever is in the SEEPROM or default to off
+ *     1 == Use whatever is in the SEEPROM or default to on
+ */
+static unsigned int aic7xxx_extended = 0;
+/*
+ * The IRQ trigger method used on EISA controllers. Does not effect PCI cards.
+ *   -1 = Use detected settings.
+ *    0 = Force Edge triggered mode.
+ *    1 = Force Level triggered mode.
+ */
+static int aic7xxx_irq_trigger = -1;
+/*
+ * This variable is used to override the termination settings on a controller.
+ * This should not be used under normal conditions.  However, in the case
+ * that a controller does not have a readable SEEPROM (so that we can't
+ * read the SEEPROM settings directly) and that a controller has a buggered
+ * version of the cable detection logic, this can be used to force the 
+ * correct termination.  It is preferable to use the manual termination
+ * settings in the BIOS if possible, but some motherboard controllers store
+ * those settings in a format we can't read.  In other cases, auto term
+ * should also work, but the chipset was put together with no auto term
+ * logic (common on motherboard controllers).  In those cases, we have
+ * 32 bits here to work with.  That's good for 8 controllers/channels.  The
+ * bits are organized as 4 bits per channel, with scsi0 getting the lowest
+ * 4 bits in the int.  A 1 in a bit position indicates the termination setting
+ * that corresponds to that bit should be enabled, a 0 is disabled.
+ * It looks something like this:
+ *
+ *    0x0f =  1111-Single Ended Low Byte Termination on/off
+ *            ||\-Single Ended High Byte Termination on/off
+ *            |\-LVD Low Byte Termination on/off
+ *            \-LVD High Byte Termination on/off
+ *
+ * For non-Ultra2 controllers, the upper 2 bits are not important.  So, to
+ * enable both high byte and low byte termination on scsi0, I would need to
+ * make sure that the override_term variable was set to 0x03 (bits 0011).
+ * To make sure that all termination is enabled on an Ultra2 controller at
+ * scsi2 and only high byte termination on scsi1 and high and low byte
+ * termination on scsi0, I would set override_term=0xf23 (bits 1111 0010 0011)
+ *
+ * For the most part, users should never have to use this, that's why I
+ * left it fairly cryptic instead of easy to understand.  If you need it,
+ * most likely someone will be telling you what your's needs to be set to.
+ */
+static int aic7xxx_override_term = -1;
+/*
+ * Certain motherboard chipset controllers tend to screw
+ * up the polarity of the term enable output pin.  Use this variable
+ * to force the correct polarity for your system.  This is a bitfield variable
+ * similar to the previous one, but this one has one bit per channel instead
+ * of four.
+ *    0 = Force the setting to active low.
+ *    1 = Force setting to active high.
+ * Most Adaptec cards are active high, several motherboards are active low.
+ * To force a 2940 card at SCSI 0 to active high and a motherboard 7895
+ * controller at scsi1 and scsi2 to active low, and a 2910 card at scsi3
+ * to active high, you would need to set stpwlev=0x9 (bits 1001).
+ *
+ * People shouldn't need to use this, but if you are experiencing lots of
+ * SCSI timeout problems, this may help.  There is one sure way to test what
+ * this option needs to be.  Using a boot floppy to boot the system, configure
+ * your system to enable all SCSI termination (in the Adaptec SCSI BIOS) and
+ * if needed then also pass a value to override_term to make sure that the
+ * driver is enabling SCSI termination, then set this variable to either 0
+ * or 1.  When the driver boots, make sure there are *NO* SCSI cables
+ * connected to your controller.  If it finds and inits the controller
+ * without problem, then the setting you passed to stpwlev was correct.  If
+ * the driver goes into a reset loop and hangs the system, then you need the
+ * other setting for this variable.  If neither setting lets the machine
+ * boot then you have definite termination problems that may not be fixable.
+ */
+static int aic7xxx_stpwlev = -1;
+/*
+ * Set this to non-0 in order to force the driver to panic the kernel
+ * and print out debugging info on a SCSI abort or reset cycle.
+ */
+static int aic7xxx_panic_on_abort = 0;
+/*
+ * PCI bus parity checking of the Adaptec controllers.  This is somewhat
+ * dubious at best.  To my knowledge, this option has never actually
+ * solved a PCI parity problem, but on certain machines with broken PCI
+ * chipset configurations, it can generate tons of false error messages.
+ * It's included in the driver for completeness.
+ *   0 = Shut off PCI parity check
+ *  -1 = Normal polarity pci parity checking
+ *   1 = reverse polarity pci parity checking
+ *
+ * NOTE: you can't actually pass -1 on the lilo prompt.  So, to set this
+ * variable to -1 you would actually want to simply pass the variable
+ * name without a number.  That will invert the 0 which will result in
+ * -1.
+ */
+static int aic7xxx_pci_parity = 0;
+/*
+ * Set this to any non-0 value to cause us to dump the contents of all
+ * the card's registers in a hex dump format tailored to each model of
+ * controller.
+ * 
+ * NOTE: THE CONTROLLER IS LEFT IN AN UNUSEABLE STATE BY THIS OPTION.
+ *       YOU CANNOT BOOT UP WITH THIS OPTION, IT IS FOR DEBUGGING PURPOSES
+ *       ONLY
+ */
+static int aic7xxx_dump_card = 0;
+/*
+ * Set this to a non-0 value to make us dump out the 32 bit instruction
+ * registers on the card after completing the sequencer download.  This
+ * allows the actual sequencer download to be verified.  It is possible
+ * to use this option and still boot up and run your system.  This is
+ * only intended for debugging purposes.
+ */
+static int aic7xxx_dump_sequencer = 0;
+/*
+ * Certain newer motherboards have put new PCI based devices into the
+ * IO spaces that used to typically be occupied by VLB or EISA cards.
+ * This overlap can cause these newer motherboards to lock up when scanned
+ * for older EISA and VLB devices.  Setting this option to non-0 will
+ * cause the driver to skip scanning for any VLB or EISA controllers and
+ * only support the PCI controllers.  NOTE: this means that if the kernel
+ * os compiled with PCI support disabled, then setting this to non-0
+ * would result in never finding any devices :)
+ */
+static int aic7xxx_no_probe = 0;
+/*
+ * On some machines, enabling the external SCB RAM isn't reliable yet.  I
+ * haven't had time to make test patches for things like changing the
+ * timing mode on that external RAM either.  Some of those changes may
+ * fix the problem.  Until then though, we default to external SCB RAM
+ * off and give a command line option to enable it.
+ */
+static int aic7xxx_scbram = 0;
+/*
+ * So that we can set how long each device is given as a selection timeout.
+ * The table of values goes like this:
+ *   0 - 256ms
+ *   1 - 128ms
+ *   2 - 64ms
+ *   3 - 32ms
+ * We default to 64ms because it's fast.  Some old SCSI-I devices need a
+ * longer time.  The final value has to be left shifted by 3, hence 0x10
+ * is the final value.
+ */
+static int aic7xxx_seltime = 0x10;
+/*
+ * So that insmod can find the variable and make it point to something
+ */
+#ifdef MODULE
+static char * aic7xxx = NULL;
+module_param(aic7xxx, charp, 0);
+#endif
+
+#define VERBOSE_NORMAL         0x0000
+#define VERBOSE_NEGOTIATION    0x0001
+#define VERBOSE_SEQINT         0x0002
+#define VERBOSE_SCSIINT        0x0004
+#define VERBOSE_PROBE          0x0008
+#define VERBOSE_PROBE2         0x0010
+#define VERBOSE_NEGOTIATION2   0x0020
+#define VERBOSE_MINOR_ERROR    0x0040
+#define VERBOSE_TRACING        0x0080
+#define VERBOSE_ABORT          0x0f00
+#define VERBOSE_ABORT_MID      0x0100
+#define VERBOSE_ABORT_FIND     0x0200
+#define VERBOSE_ABORT_PROCESS  0x0400
+#define VERBOSE_ABORT_RETURN   0x0800
+#define VERBOSE_RESET          0xf000
+#define VERBOSE_RESET_MID      0x1000
+#define VERBOSE_RESET_FIND     0x2000
+#define VERBOSE_RESET_PROCESS  0x4000
+#define VERBOSE_RESET_RETURN   0x8000
+static int aic7xxx_verbose = VERBOSE_NORMAL | VERBOSE_NEGOTIATION |
+           VERBOSE_PROBE;                     /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * We're going to start putting in function declarations so that order of
+ * functions is no longer important.  As needed, they are added here.
+ *
+ ***************************************************************************/
+
+static int aic7xxx_release(struct Scsi_Host *host);
+static void aic7xxx_set_syncrate(struct aic7xxx_host *p, 
+		struct aic7xxx_syncrate *syncrate, int target, int channel,
+		unsigned int period, unsigned int offset, unsigned char options,
+		unsigned int type, struct aic_dev_data *aic_dev);
+static void aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel,
+		int lun, unsigned int width, unsigned int type,
+		struct aic_dev_data *aic_dev);
+static void aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd);
+static void aic7xxx_print_card(struct aic7xxx_host *p);
+static void aic7xxx_print_scratch_ram(struct aic7xxx_host *p);
+static void aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer);
+#endif
+
+/****************************************************************************
+ *
+ * These functions are now used.  They happen to be wrapped in useless
+ * inb/outb port read/writes around the real reads and writes because it
+ * seems that certain very fast CPUs have a problem dealing with us when
+ * going at full speed.
+ *
+ ***************************************************************************/
+
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+#ifdef MMAPIO
+  unsigned char x;
+  if(p->maddr)
+  {
+    x = readb(p->maddr + port);
+  }
+  else
+  {
+    x = inb(p->base + port);
+  }
+  return(x);
+#else
+  return(inb(p->base + port));
+#endif
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+#ifdef MMAPIO
+  if(p->maddr)
+  {
+    writeb(val, p->maddr + port);
+    mb(); /* locked operation in order to force CPU ordering */
+    readb(p->maddr + HCNTRL); /* dummy read to flush the PCI write */
+  }
+  else
+  {
+    outb(val, p->base + port);
+    mb(); /* locked operation in order to force CPU ordering */
+  }
+#else
+  outb(val, p->base + port);
+  mb(); /* locked operation in order to force CPU ordering */
+#endif
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_setup
+ *
+ * Description:
+ *   Handle Linux boot parameters. This routine allows for assigning a value
+ *   to a parameter with a ':' between the parameter and the value.
+ *   ie. aic7xxx=unpause:0x0A,extended
+ *-F*************************************************************************/
+static int
+aic7xxx_setup(char *s)
+{
+  int   i, n;
+  char *p;
+  char *end;
+
+  static struct {
+    const char *name;
+    unsigned int *flag;
+  } options[] = {
+    { "extended",    &aic7xxx_extended },
+    { "no_reset",    &aic7xxx_no_reset },
+    { "irq_trigger", &aic7xxx_irq_trigger },
+    { "verbose",     &aic7xxx_verbose },
+    { "reverse_scan",&aic7xxx_reverse_scan },
+    { "override_term", &aic7xxx_override_term },
+    { "stpwlev", &aic7xxx_stpwlev },
+    { "no_probe", &aic7xxx_no_probe },
+    { "panic_on_abort", &aic7xxx_panic_on_abort },
+    { "pci_parity", &aic7xxx_pci_parity },
+    { "dump_card", &aic7xxx_dump_card },
+    { "dump_sequencer", &aic7xxx_dump_sequencer },
+    { "default_queue_depth", &aic7xxx_default_queue_depth },
+    { "scbram", &aic7xxx_scbram },
+    { "seltime", &aic7xxx_seltime },
+    { "tag_info",    NULL }
+  };
+
+  end = strchr(s, '\0');
+
+  while ((p = strsep(&s, ",.")) != NULL)
+  {
+    for (i = 0; i < ARRAY_SIZE(options); i++)
+    {
+      n = strlen(options[i].name);
+      if (!strncmp(options[i].name, p, n))
+      {
+        if (!strncmp(p, "tag_info", n))
+        {
+          if (p[n] == ':')
+          {
+            char *base;
+            char *tok, *tok_end, *tok_end2;
+            char tok_list[] = { '.', ',', '{', '}', '\0' };
+            int i, instance = -1, device = -1;
+            unsigned char done = FALSE;
+
+            base = p;
+            tok = base + n + 1;  /* Forward us just past the ':' */
+            tok_end = strchr(tok, '\0');
+            if (tok_end < end)
+              *tok_end = ',';
+            while(!done)
+            {
+              switch(*tok)
+              {
+                case '{':
+                  if (instance == -1)
+                    instance = 0;
+                  else if (device == -1)
+                    device = 0;
+                  tok++;
+                  break;
+                case '}':
+                  if (device != -1)
+                    device = -1;
+                  else if (instance != -1)
+                    instance = -1;
+                  tok++;
+                  break;
+                case ',':
+                case '.':
+                  if (instance == -1)
+                    done = TRUE;
+                  else if (device >= 0)
+                    device++;
+                  else if (instance >= 0)
+                    instance++;
+                  if ( (device >= MAX_TARGETS) || 
+                       (instance >= ARRAY_SIZE(aic7xxx_tag_info)) )
+                    done = TRUE;
+                  tok++;
+                  if (!done)
+                  {
+                    base = tok;
+                  }
+                  break;
+                case '\0':
+                  done = TRUE;
+                  break;
+                default:
+                  done = TRUE;
+                  tok_end = strchr(tok, '\0');
+                  for(i=0; tok_list[i]; i++)
+                  {
+                    tok_end2 = strchr(tok, tok_list[i]);
+                    if ( (tok_end2) && (tok_end2 < tok_end) )
+                    {
+                      tok_end = tok_end2;
+                      done = FALSE;
+                    }
+                  }
+                  if ( (instance >= 0) && (device >= 0) &&
+                       (instance < ARRAY_SIZE(aic7xxx_tag_info)) &&
+                       (device < MAX_TARGETS) )
+                    aic7xxx_tag_info[instance].tag_commands[device] =
+                      simple_strtoul(tok, NULL, 0) & 0xff;
+                  tok = tok_end;
+                  break;
+              }
+            }
+            while((p != base) && (p != NULL))
+              p = strsep(&s, ",.");
+          }
+        }
+        else if (p[n] == ':')
+        {
+          *(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
+        }
+        else if (!strncmp(p, "verbose", n))
+        {
+          *(options[i].flag) = 0xff29;
+        }
+        else
+        {
+          *(options[i].flag) = ~(*(options[i].flag));
+          if(!strncmp(p, "seltime", n))
+          {
+            *(options[i].flag) = (*(options[i].flag) % 4) << 3;
+          }
+        }
+      }
+    }
+  }
+  return 1;
+}
+
+__setup("aic7xxx=", aic7xxx_setup);
+
+/*+F*************************************************************************
+ * Function:
+ *   pause_sequencer
+ *
+ * Description:
+ *   Pause the sequencer and wait for it to actually stop - this
+ *   is important since the sequencer can disable pausing for critical
+ *   sections.
+ *-F*************************************************************************/
+static void
+pause_sequencer(struct aic7xxx_host *p)
+{
+  aic_outb(p, p->pause, HCNTRL);
+  while ((aic_inb(p, HCNTRL) & PAUSE) == 0)
+  {
+    ;
+  }
+  if(p->features & AHC_ULTRA2)
+  {
+    aic_inb(p, CCSCBCTL);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   unpause_sequencer
+ *
+ * Description:
+ *   Unpause the sequencer. Unremarkable, yet done often enough to
+ *   warrant an easy way to do it.
+ *-F*************************************************************************/
+static void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
+{
+  if (unpause_always ||
+      ( !(aic_inb(p, INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) &&
+        !(p->flags & AHC_HANDLING_REQINITS) ) )
+  {
+    aic_outb(p, p->unpause, HCNTRL);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   restart_sequencer
+ *
+ * Description:
+ *   Restart the sequencer program from address zero.  This assumes
+ *   that the sequencer is already paused.
+ *-F*************************************************************************/
+static void
+restart_sequencer(struct aic7xxx_host *p)
+{
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE, SEQCTL);
+}
+
+/*
+ * We include the aic7xxx_seq.c file here so that the other defines have
+ * already been made, and so that it comes before the code that actually
+ * downloads the instructions (since we don't typically use function
+ * prototype, our code has to be ordered that way, it's a left-over from
+ * the original driver days.....I should fix it some time DL).
+ */
+#include "aic7xxx_old/aic7xxx_seq.c"
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_check_patch
+ *
+ * Description:
+ *   See if the next patch to download should be downloaded.
+ *-F*************************************************************************/
+static int
+aic7xxx_check_patch(struct aic7xxx_host *p,
+  struct sequencer_patch **start_patch, int start_instr, int *skip_addr)
+{
+  struct sequencer_patch *cur_patch;
+  struct sequencer_patch *last_patch;
+  int num_patches;
+
+  num_patches = sizeof(sequencer_patches)/sizeof(struct sequencer_patch);
+  last_patch = &sequencer_patches[num_patches];
+  cur_patch = *start_patch;
+
+  while ((cur_patch < last_patch) && (start_instr == cur_patch->begin))
+  {
+    if (cur_patch->patch_func(p) == 0)
+    {
+      /*
+       * Start rejecting code.
+       */
+      *skip_addr = start_instr + cur_patch->skip_instr;
+      cur_patch += cur_patch->skip_patch;
+    }
+    else
+    {
+      /*
+       * Found an OK patch.  Advance the patch pointer to the next patch
+       * and wait for our instruction pointer to get here.
+       */
+      cur_patch++;
+    }
+  }
+
+  *start_patch = cur_patch;
+  if (start_instr < *skip_addr)
+    /*
+     * Still skipping
+     */
+    return (0);
+  return(1);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_download_instr
+ *
+ * Description:
+ *   Find the next patch to download.
+ *-F*************************************************************************/
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int instrptr,
+  unsigned char *dconsts)
+{
+  union ins_formats instr;
+  struct ins_format1 *fmt1_ins;
+  struct ins_format3 *fmt3_ins;
+  unsigned char opcode;
+
+  instr = *(union ins_formats*) &seqprog[instrptr * 4];
+
+  instr.integer = le32_to_cpu(instr.integer);
+  
+  fmt1_ins = &instr.format1;
+  fmt3_ins = NULL;
+
+  /* Pull the opcode */
+  opcode = instr.format1.opcode;
+  switch (opcode)
+  {
+    case AIC_OP_JMP:
+    case AIC_OP_JC:
+    case AIC_OP_JNC:
+    case AIC_OP_CALL:
+    case AIC_OP_JNE:
+    case AIC_OP_JNZ:
+    case AIC_OP_JE:
+    case AIC_OP_JZ:
+    {
+      struct sequencer_patch *cur_patch;
+      int address_offset;
+      unsigned int address;
+      int skip_addr;
+      int i;
+
+      fmt3_ins = &instr.format3;
+      address_offset = 0;
+      address = fmt3_ins->address;
+      cur_patch = sequencer_patches;
+      skip_addr = 0;
+
+      for (i = 0; i < address;)
+      {
+        aic7xxx_check_patch(p, &cur_patch, i, &skip_addr);
+        if (skip_addr > i)
+        {
+          int end_addr;
+
+          end_addr = min_t(int, address, skip_addr);
+          address_offset += end_addr - i;
+          i = skip_addr;
+        }
+        else
+        {
+          i++;
+        }
+      }
+      address -= address_offset;
+      fmt3_ins->address = address;
+      /* Fall Through to the next code section */
+    }
+    case AIC_OP_OR:
+    case AIC_OP_AND:
+    case AIC_OP_XOR:
+    case AIC_OP_ADD:
+    case AIC_OP_ADC:
+    case AIC_OP_BMOV:
+      if (fmt1_ins->parity != 0)
+      {
+        fmt1_ins->immediate = dconsts[fmt1_ins->immediate];
+      }
+      fmt1_ins->parity = 0;
+      /* Fall Through to the next code section */
+    case AIC_OP_ROL:
+      if ((p->features & AHC_ULTRA2) != 0)
+      {
+        int i, count;
+
+        /* Calculate odd parity for the instruction */
+        for ( i=0, count=0; i < 31; i++)
+        {
+          unsigned int mask;
+
+          mask = 0x01 << i;
+          if ((instr.integer & mask) != 0)
+            count++;
+        }
+        if (!(count & 0x01))
+          instr.format1.parity = 1;
+      }
+      else
+      {
+        if (fmt3_ins != NULL)
+        {
+          instr.integer =  fmt3_ins->immediate |
+                          (fmt3_ins->source << 8) |
+                          (fmt3_ins->address << 16) |
+                          (fmt3_ins->opcode << 25);
+        }
+        else
+        {
+          instr.integer =  fmt1_ins->immediate |
+                          (fmt1_ins->source << 8) |
+                          (fmt1_ins->destination << 16) |
+                          (fmt1_ins->ret << 24) |
+                          (fmt1_ins->opcode << 25);
+        }
+      }
+      aic_outb(p, (instr.integer & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
+      aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
+      udelay(10);
+      break;
+
+    default:
+      panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+      break;
+  }
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_loadseq
+ *
+ * Description:
+ *   Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(struct aic7xxx_host *p)
+{
+  struct sequencer_patch *cur_patch;
+  int i;
+  int downloaded;
+  int skip_addr;
+  unsigned char download_consts[4] = {0, 0, 0, 0};
+
+  if (aic7xxx_verbose & VERBOSE_PROBE)
+  {
+    printk(KERN_INFO "(scsi%d) Downloading sequencer code...", p->host_no);
+  }
+#if 0
+  download_consts[TMODE_NUMCMDS] = p->num_targetcmds;
+#endif
+  download_consts[TMODE_NUMCMDS] = 0;
+  cur_patch = &sequencer_patches[0];
+  downloaded = 0;
+  skip_addr = 0;
+
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  for (i = 0; i < sizeof(seqprog) / 4;  i++)
+  {
+    if (aic7xxx_check_patch(p, &cur_patch, i, &skip_addr) == 0)
+    {
+      /* Skip this instruction for this configuration. */
+      continue;
+    }
+    aic7xxx_download_instr(p, i, &download_consts[0]);
+    downloaded++;
+  }
+
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
+  unpause_sequencer(p, TRUE);
+  mdelay(1);
+  pause_sequencer(p);
+  aic_outb(p, FASTMODE, SEQCTL);
+  if (aic7xxx_verbose & VERBOSE_PROBE)
+  {
+    printk(" %d instructions downloaded\n", downloaded);
+  }
+  if (aic7xxx_dump_sequencer)
+    aic7xxx_print_sequencer(p, downloaded);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_sequencer
+ *
+ * Description:
+ *   Print the contents of the sequencer memory to the screen.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_sequencer(struct aic7xxx_host *p, int downloaded)
+{
+  int i, k, temp;
+  
+  aic_outb(p, PERRORDIS|LOADRAM|FAILDIS|FASTMODE, SEQCTL);
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+
+  k = 0;
+  for (i=0; i < downloaded; i++)
+  {
+    if ( k == 0 )
+      printk("%03x: ", i);
+    temp = aic_inb(p, SEQRAM);
+    temp |= (aic_inb(p, SEQRAM) << 8);
+    temp |= (aic_inb(p, SEQRAM) << 16);
+    temp |= (aic_inb(p, SEQRAM) << 24);
+    printk("%08x", temp);
+    if ( ++k == 8 )
+    {
+      printk("\n");
+      k = 0;
+    }
+    else
+      printk(" ");
+  }
+  aic_outb(p, 0, SEQADDR0);
+  aic_outb(p, 0, SEQADDR1);
+  aic_outb(p, FASTMODE | FAILDIS, SEQCTL);
+  unpause_sequencer(p, TRUE);
+  mdelay(1);
+  pause_sequencer(p);
+  aic_outb(p, FASTMODE, SEQCTL);
+  printk("\n");
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_info
+ *
+ * Description:
+ *   Return a string describing the driver.
+ *-F*************************************************************************/
+static const char *
+aic7xxx_info(struct Scsi_Host *dooh)
+{
+  static char buffer[256];
+  char *bp;
+  struct aic7xxx_host *p;
+
+  bp = &buffer[0];
+  p = (struct aic7xxx_host *)dooh->hostdata;
+  memset(bp, 0, sizeof(buffer));
+  strcpy(bp, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+  strcat(bp, AIC7XXX_C_VERSION);
+  strcat(bp, "/");
+  strcat(bp, AIC7XXX_H_VERSION);
+  strcat(bp, "\n");
+  strcat(bp, "       <");
+  strcat(bp, board_names[p->board_name_index]);
+  strcat(bp, ">");
+
+  return(bp);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_syncrate
+ *
+ * Description:
+ *   Look up the valid period to SCSIRATE conversion in our table
+ *-F*************************************************************************/
+static struct aic7xxx_syncrate *
+aic7xxx_find_syncrate(struct aic7xxx_host *p, unsigned int *period,
+  unsigned int maxsync, unsigned char *options)
+{
+  struct aic7xxx_syncrate *syncrate;
+  int done = FALSE;
+
+  switch(*options)
+  {
+    case MSG_EXT_PPR_OPTION_DT_CRC:
+    case MSG_EXT_PPR_OPTION_DT_UNITS:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      break;
+    case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+    case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+      if(!(p->features & AHC_ULTRA3))
+      {
+        *options = 0;
+        maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2);
+      }
+      else
+      {
+        /*
+         * we don't support the Quick Arbitration variants of dual edge
+         * clocking.  As it turns out, we want to send back the
+         * same basic option, but without the QA attribute.
+         * We know that we are responding because we would never set
+         * these options ourself, we would only respond to them.
+         */
+        switch(*options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_CRC_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_CRC;
+            break;
+          case MSG_EXT_PPR_OPTION_DT_UNITS_QUICK:
+            *options = MSG_EXT_PPR_OPTION_DT_UNITS;
+            break;
+        }
+      }
+      break;
+    default:
+      *options = 0;
+      maxsync = max_t(unsigned int, maxsync, AHC_SYNCRATE_ULTRA2);
+      break;
+  }
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while ( (syncrate->rate[0] != NULL) &&
+         (!(p->features & AHC_ULTRA2) || syncrate->sxfr_ultra2) )
+  {
+    if (*period <= syncrate->period) 
+    {
+      switch(*options)
+      {
+        case MSG_EXT_PPR_OPTION_DT_CRC:
+        case MSG_EXT_PPR_OPTION_DT_UNITS:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            /*
+             * oops, we went too low for the CRC/DualEdge signalling, so
+             * clear the options byte
+             */
+            *options = 0;
+            /*
+             * We'll be sending a reply to this packet to set the options
+             * properly, so unilaterally set the period as well.
+             */
+            *period = syncrate->period;
+          }
+          else
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+        default:
+          if(!(syncrate->sxfr_ultra2 & AHC_SYNCRATE_CRC))
+          {
+            done = TRUE;
+            if(syncrate == &aic7xxx_syncrates[maxsync])
+            {
+              *period = syncrate->period;
+            }
+          }
+          break;
+      }
+      if(done)
+      {
+        break;
+      }
+    }
+    syncrate++;
+  }
+  if ( (*period == 0) || (syncrate->rate[0] == NULL) ||
+       ((p->features & AHC_ULTRA2) && (syncrate->sxfr_ultra2 == 0)) )
+  {
+    /*
+     * Use async transfers for this target
+     */
+    *options = 0;
+    *period = 255;
+    syncrate = NULL;
+  }
+  return (syncrate);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_period
+ *
+ * Description:
+ *   Look up the valid SCSIRATE to period conversion in our table
+ *-F*************************************************************************/
+static unsigned int
+aic7xxx_find_period(struct aic7xxx_host *p, unsigned int scsirate,
+  unsigned int maxsync)
+{
+  struct aic7xxx_syncrate *syncrate;
+
+  if (p->features & AHC_ULTRA2)
+  {
+    scsirate &= SXFR_ULTRA2;
+  }
+  else
+  {
+    scsirate &= SXFR;
+  }
+
+  syncrate = &aic7xxx_syncrates[maxsync];
+  while (syncrate->rate[0] != NULL)
+  {
+    if (p->features & AHC_ULTRA2)
+    {
+      if (syncrate->sxfr_ultra2 == 0)
+        break;
+      else if (scsirate == syncrate->sxfr_ultra2)
+        return (syncrate->period);
+      else if (scsirate == (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC))
+        return (syncrate->period);
+    }
+    else if (scsirate == (syncrate->sxfr & ~ULTRA_SXFR))
+    {
+      return (syncrate->period);
+    }
+    syncrate++;
+  }
+  return (0); /* async */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_validate_offset
+ *
+ * Description:
+ *   Set a valid offset value for a particular card in use and transfer
+ *   settings in use.
+ *-F*************************************************************************/
+static void
+aic7xxx_validate_offset(struct aic7xxx_host *p,
+  struct aic7xxx_syncrate *syncrate, unsigned int *offset, int wide)
+{
+  unsigned int maxoffset;
+
+  /* Limit offset to what the card (and device) can do */
+  if (syncrate == NULL)
+  {
+    maxoffset = 0;
+  }
+  else if (p->features & AHC_ULTRA2)
+  {
+    maxoffset = MAX_OFFSET_ULTRA2;
+  }
+  else
+  {
+    if (wide)
+      maxoffset = MAX_OFFSET_16BIT;
+    else
+      maxoffset = MAX_OFFSET_8BIT;
+  }
+  *offset = min(*offset, maxoffset);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_syncrate
+ *
+ * Description:
+ *   Set the actual syncrate down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_syncrate(struct aic7xxx_host *p, struct aic7xxx_syncrate *syncrate,
+    int target, int channel, unsigned int period, unsigned int offset,
+    unsigned char options, unsigned int type, struct aic_dev_data *aic_dev)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned char lun, old_options;
+  unsigned int old_period, old_offset;
+
+  tindex = target | (channel << 3);
+  target_mask = 0x01 << tindex;
+  lun = aic_inb(p, SCB_TCL) & 0x07;
+
+  if (syncrate == NULL)
+  {
+    period = 0;
+    offset = 0;
+  }
+
+  old_period = aic_dev->cur.period;
+  old_offset = aic_dev->cur.offset;
+  old_options = aic_dev->cur.options;
+
+  
+  if (type & AHC_TRANS_CUR)
+  {
+    unsigned int scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+    if (p->features & AHC_ULTRA2)
+    {
+      scsirate &= ~SXFR_ULTRA2;
+      if (syncrate != NULL)
+      {
+        switch(options)
+        {
+          case MSG_EXT_PPR_OPTION_DT_UNITS:
+            /*
+             * mask off the CRC bit in the xfer settings
+             */
+            scsirate |= (syncrate->sxfr_ultra2 & ~AHC_SYNCRATE_CRC);
+            break;
+          default:
+            scsirate |= syncrate->sxfr_ultra2;
+            break;
+        }
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        aic_outb(p, offset, SCSIOFFSET);
+      }
+      aic_outb(p, offset, TARG_OFFSET + tindex);
+    }
+    else /* Not an Ultra2 controller */
+    {
+      scsirate &= ~(SXFR|SOFS);
+      p->ultraenb &= ~target_mask;
+      if (syncrate != NULL)
+      {
+        if (syncrate->sxfr & ULTRA_SXFR)
+        {
+          p->ultraenb |= target_mask;
+        }
+        scsirate |= (syncrate->sxfr & SXFR);
+        scsirate |= (offset & SOFS);
+      }
+      if (type & AHC_TRANS_ACTIVE)
+      {
+        unsigned char sxfrctl0;
+
+        sxfrctl0 = aic_inb(p, SXFRCTL0);
+        sxfrctl0 &= ~FAST20;
+        if (p->ultraenb & target_mask)
+          sxfrctl0 |= FAST20;
+        aic_outb(p, sxfrctl0, SXFRCTL0);
+      }
+      aic_outb(p, p->ultraenb & 0xff, ULTRA_ENB);
+      aic_outb(p, (p->ultraenb >> 8) & 0xff, ULTRA_ENB + 1 );
+    }
+    if (type & AHC_TRANS_ACTIVE)
+    {
+      aic_outb(p, scsirate, SCSIRATE);
+    }
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+    aic_dev->cur.period = period;
+    aic_dev->cur.offset = offset;
+    aic_dev->cur.options = options;
+    if ( !(type & AHC_TRANS_QUITE) &&
+         (aic7xxx_verbose & VERBOSE_NEGOTIATION) &&
+         (aic_dev->flags & DEVICE_PRINT_DTR) )
+    {
+      if (offset)
+      {
+        int rate_mod = (scsirate & WIDEXFER) ? 1 : 0;
+      
+        printk(INFO_LEAD "Synchronous at %s Mbyte/sec, "
+               "offset %d.\n", p->host_no, channel, target, lun,
+               syncrate->rate[rate_mod], offset);
+      }
+      else
+      {
+        printk(INFO_LEAD "Using asynchronous transfers.\n",
+               p->host_no, channel, target, lun);
+      }
+      aic_dev->flags &= ~DEVICE_PRINT_DTR;
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+  {
+    aic_dev->goal.period = period;
+    aic_dev->goal.offset = offset;
+    aic_dev->goal.options = options;
+  }
+
+  if (type & AHC_TRANS_USER)
+  {
+    p->user[tindex].period = period;
+    p->user[tindex].offset = offset;
+    p->user[tindex].options = options;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_width
+ *
+ * Description:
+ *   Set the actual width down in the card and in our host structs
+ *-F*************************************************************************/
+static void
+aic7xxx_set_width(struct aic7xxx_host *p, int target, int channel, int lun,
+    unsigned int width, unsigned int type, struct aic_dev_data *aic_dev)
+{
+  unsigned char tindex;
+  unsigned short target_mask;
+  unsigned int old_width;
+
+  tindex = target | (channel << 3);
+  target_mask = 1 << tindex;
+  
+  old_width = aic_dev->cur.width;
+
+  if (type & AHC_TRANS_CUR) 
+  {
+    unsigned char scsirate;
+
+    scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+
+    scsirate &= ~WIDEXFER;
+    if (width == MSG_EXT_WDTR_BUS_16_BIT)
+      scsirate |= WIDEXFER;
+
+    aic_outb(p, scsirate, TARG_SCSIRATE + tindex);
+
+    if (type & AHC_TRANS_ACTIVE)
+      aic_outb(p, scsirate, SCSIRATE);
+
+    aic_dev->cur.width = width;
+
+    if ( !(type & AHC_TRANS_QUITE) &&
+          (aic7xxx_verbose & VERBOSE_NEGOTIATION2) && 
+          (aic_dev->flags & DEVICE_PRINT_DTR) )
+    {
+      printk(INFO_LEAD "Using %s transfers\n", p->host_no, channel, target,
+        lun, (scsirate & WIDEXFER) ? "Wide(16bit)" : "Narrow(8bit)" );
+    }
+  }
+
+  if (type & AHC_TRANS_GOAL)
+    aic_dev->goal.width = width;
+  if (type & AHC_TRANS_USER)
+    p->user[tindex].width = width;
+
+  if (aic_dev->goal.offset)
+  {
+    if (p->features & AHC_ULTRA2)
+    {
+      aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+    }
+    else if (width == MSG_EXT_WDTR_BUS_16_BIT)
+    {
+      aic_dev->goal.offset = MAX_OFFSET_16BIT;
+    }
+    else
+    {
+      aic_dev->goal.offset = MAX_OFFSET_8BIT;
+    }
+  }
+}
+      
+/*+F*************************************************************************
+ * Function:
+ *   scbq_init
+ *
+ * Description:
+ *   SCB queue initialization.
+ *
+ *-F*************************************************************************/
+static void
+scbq_init(volatile scb_queue_type *queue)
+{
+  queue->head = NULL;
+  queue->tail = NULL;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_head
+ *
+ * Description:
+ *   Add an SCB to the head of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_head(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  scb->q_next = queue->head;
+  queue->head = scb;
+  if (queue->tail == NULL)       /* If list was empty, update tail. */
+    queue->tail = queue->head;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove_head
+ *
+ * Description:
+ *   Remove an SCB from the head of the list.
+ *
+ *-F*************************************************************************/
+static inline struct aic7xxx_scb *
+scbq_remove_head(volatile scb_queue_type *queue)
+{
+  struct aic7xxx_scb * scbp;
+
+  scbp = queue->head;
+  if (queue->head != NULL)
+    queue->head = queue->head->q_next;
+  if (queue->head == NULL)       /* If list is now empty, update tail. */
+    queue->tail = NULL;
+  return(scbp);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_remove
+ *
+ * Description:
+ *   Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  if (queue->head == scb)
+  {
+    /* At beginning of queue, remove from head. */
+    scbq_remove_head(queue);
+  }
+  else
+  {
+    struct aic7xxx_scb *curscb = queue->head;
+
+    /*
+     * Search until the next scb is the one we're looking for, or
+     * we run out of queue.
+     */
+    while ((curscb != NULL) && (curscb->q_next != scb))
+    {
+      curscb = curscb->q_next;
+    }
+    if (curscb != NULL)
+    {
+      /* Found it. */
+      curscb->q_next = scb->q_next;
+      if (scb->q_next == NULL)
+      {
+        /* Update the tail when removing the tail. */
+        queue->tail = curscb;
+      }
+    }
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   scbq_insert_tail
+ *
+ * Description:
+ *   Add an SCB at the tail of the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_insert_tail(volatile scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+  scb->q_next = NULL;
+  if (queue->tail != NULL)       /* Add the scb at the end of the list. */
+    queue->tail->q_next = scb;
+  queue->tail = scb;             /* Update the tail. */
+  if (queue->head == NULL)       /* If list was empty, update head. */
+    queue->head = queue->tail;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_match_scb
+ *
+ * Description:
+ *   Checks to see if an scb matches the target/channel as specified.
+ *   If target is ALL_TARGETS (-1), then we're looking for any device
+ *   on the specified channel; this happens when a channel is going
+ *   to be reset and all devices on that channel must be aborted.
+ *-F*************************************************************************/
+static int
+aic7xxx_match_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    int target, int channel, int lun, unsigned char tag)
+{
+  int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+  int chan = (scb->hscb->target_channel_lun >> 3) & 0x01;
+  int slun = scb->hscb->target_channel_lun & 0x07;
+  int match;
+
+  match = ((chan == channel) || (channel == ALL_CHANNELS));
+  if (match != 0)
+    match = ((targ == target) || (target == ALL_TARGETS));
+  if (match != 0)
+    match = ((lun == slun) || (lun == ALL_LUNS));
+  if (match != 0)
+    match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+  return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ *   Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+  /*
+   * Invalidate the tag so that aic7xxx_find_scb doesn't think
+   * it's active
+   */
+  aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+  aic_outb(p, 0, SCB_CONTROL);
+
+  aic_outb(p, aic_inb(p, FREE_SCBH), SCB_NEXT);
+  aic_outb(p, aic_inb(p, SCBPTR), FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ *   Removes the current SCB from the disconnected list and adds it
+ *   to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr,
+                               unsigned char prev)
+{
+  unsigned char next;
+
+  aic_outb(p, scbptr, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+  aic7xxx_add_curscb_to_free_list(p);
+
+  if (prev != SCB_LIST_NULL)
+  {
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
+  }
+  else
+  {
+    aic_outb(p, next, DISCONNECTED_SCBH);
+  }
+
+  return next;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_busy_target
+ *
+ * Description:
+ *   Set the specified target busy.
+ *-F*************************************************************************/
+static inline void
+aic7xxx_busy_target(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  p->untagged_scbs[scb->hscb->target_channel_lun] = scb->hscb->tag;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_index_busy_target
+ *
+ * Description:
+ *   Returns the index of the busy target, and optionally sets the
+ *   target inactive.
+ *-F*************************************************************************/
+static inline unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char tcl,
+    int unbusy)
+{
+  unsigned char busy_scbid;
+
+  busy_scbid = p->untagged_scbs[tcl];
+  if (unbusy)
+  {
+    p->untagged_scbs[tcl] = SCB_LIST_NULL;
+  }
+  return (busy_scbid);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_find_scb
+ *
+ * Description:
+ *   Look through the SCB array of the card and attempt to find the
+ *   hardware SCB that corresponds to the passed in SCB.  Return
+ *   SCB_LIST_NULL if unsuccessful.  This routine assumes that the
+ *   card is already paused.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char saved_scbptr;
+  unsigned char curindex;
+
+  saved_scbptr = aic_inb(p, SCBPTR);
+  curindex = 0;
+  for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
+  {
+    aic_outb(p, curindex, SCBPTR);
+    if (aic_inb(p, SCB_TAG) == scb->hscb->tag)
+    {
+      break;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  if (curindex >= p->scb_data->maxhscbs)
+  {
+    curindex = SCB_LIST_NULL;
+  }
+
+  return (curindex);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_allocate_scb
+ *
+ * Description:
+ *   Get an SCB from the free list or by allocating a new one.
+ *-F*************************************************************************/
+static int
+aic7xxx_allocate_scb(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb   *scbp = NULL;
+  int scb_size = (sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG) + 12 + 6;
+  int i;
+  int step = PAGE_SIZE / 1024;
+  unsigned long scb_count = 0;
+  struct hw_scatterlist *hsgp;
+  struct aic7xxx_scb *scb_ap;
+  struct aic7xxx_scb_dma *scb_dma;
+  unsigned char *bufs;
+
+  if (p->scb_data->numscbs < p->scb_data->maxscbs)
+  {
+    /*
+     * Calculate the optimal number of SCBs to allocate.
+     *
+     * NOTE: This formula works because the sizeof(sg_array) is always
+     * 1024.  Therefore, scb_size * i would always be > PAGE_SIZE *
+     * (i/step).  The (i-1) allows the left hand side of the equation
+     * to grow into the right hand side to a point of near perfect
+     * efficiency since scb_size * (i -1) is growing slightly faster
+     * than the right hand side.  If the number of SG array elements
+     * is changed, this function may not be near so efficient any more.
+     *
+     * Since the DMA'able buffers are now allocated in a separate
+     * chunk this algorithm has been modified to match.  The '12'
+     * and '6' factors in scb_size are for the DMA'able command byte
+     * and sensebuffers respectively.  -DaveM
+     */
+    for ( i=step;; i *= 2 )
+    {
+      if ( (scb_size * (i-1)) >= ( (PAGE_SIZE * (i/step)) - 64 ) )
+      {
+        i /= 2;
+        break;
+      }
+    }
+    scb_count = min( (i-1), p->scb_data->maxscbs - p->scb_data->numscbs);
+    scb_ap = (struct aic7xxx_scb *)kmalloc(sizeof (struct aic7xxx_scb) * scb_count
+					   + sizeof(struct aic7xxx_scb_dma), GFP_ATOMIC);
+    if (scb_ap == NULL)
+      return(0);
+    scb_dma = (struct aic7xxx_scb_dma *)&scb_ap[scb_count];
+    hsgp = (struct hw_scatterlist *)
+      pci_alloc_consistent(p->pdev, scb_size * scb_count,
+			   &scb_dma->dma_address);
+    if (hsgp == NULL)
+    {
+      kfree(scb_ap);
+      return(0);
+    }
+    bufs = (unsigned char *)&hsgp[scb_count * AIC7XXX_MAX_SG];
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+    {
+      if (p->scb_data->numscbs == 0)
+	printk(INFO_LEAD "Allocating initial %ld SCB structures.\n",
+	  p->host_no, -1, -1, -1, scb_count);
+      else
+	printk(INFO_LEAD "Allocating %ld additional SCB structures.\n",
+	  p->host_no, -1, -1, -1, scb_count);
+    }
+#endif
+    memset(scb_ap, 0, sizeof (struct aic7xxx_scb) * scb_count);
+    scb_dma->dma_offset = (unsigned long)scb_dma->dma_address
+			  - (unsigned long)hsgp;
+    scb_dma->dma_len = scb_size * scb_count;
+    for (i=0; i < scb_count; i++)
+    {
+      scbp = &scb_ap[i];
+      scbp->hscb = &p->scb_data->hscbs[p->scb_data->numscbs];
+      scbp->sg_list = &hsgp[i * AIC7XXX_MAX_SG];
+      scbp->sense_cmd = bufs;
+      scbp->cmnd = bufs + 6;
+      bufs += 12 + 6;
+      scbp->scb_dma = scb_dma;
+      memset(scbp->hscb, 0, sizeof(struct aic7xxx_hwscb));
+      scbp->hscb->tag = p->scb_data->numscbs;
+      /*
+       * Place in the scb array; never is removed
+       */
+      p->scb_data->scb_array[p->scb_data->numscbs++] = scbp;
+      scbq_insert_tail(&p->scb_data->free_scbs, scbp);
+    }
+    scbp->kmalloc_ptr = scb_ap;
+  }
+  return(scb_count);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue_cmd_complete
+ *
+ * Description:
+ *   Due to race conditions present in the SCSI subsystem, it is easier
+ *   to queue completed commands, then call scsi_done() on them when
+ *   we're finished.  This function queues the completed commands.
+ *-F*************************************************************************/
+static void
+aic7xxx_queue_cmd_complete(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+  aic7xxx_position(cmd) = SCB_LIST_NULL;
+  cmd->host_scribble = (char *)p->completeq.head;
+  p->completeq.head = cmd;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_done_cmds_complete
+ *
+ * Description:
+ *   Process the completed command queue.
+ *-F*************************************************************************/
+static void
+aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
+{
+  Scsi_Cmnd *cmd;
+  
+  while (p->completeq.head != NULL)
+  {
+    cmd = p->completeq.head;
+    p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
+    cmd->host_scribble = NULL;
+    cmd->scsi_done(cmd);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free_scb
+ *
+ * Description:
+ *   Free the scb and insert into the free scb list.
+ *-F*************************************************************************/
+static void
+aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+
+  scb->flags = SCB_FREE;
+  scb->cmd = NULL;
+  scb->sg_count = 0;
+  scb->sg_length = 0;
+  scb->tag_action = 0;
+  scb->hscb->control = 0;
+  scb->hscb->target_status = 0;
+  scb->hscb->target_channel_lun = SCB_LIST_NULL;
+
+  scbq_insert_head(&p->scb_data->free_scbs, scb);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_done
+ *
+ * Description:
+ *   Calls the higher level scsi done function and frees the scb.
+ *-F*************************************************************************/
+static void
+aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  Scsi_Cmnd *cmd = scb->cmd;
+  struct aic_dev_data *aic_dev = cmd->device->hostdata;
+  int tindex = TARGET_INDEX(cmd);
+  struct aic7xxx_scb *scbp;
+  unsigned char queue_depth;
+
+  if (cmd->use_sg > 1)
+  {
+    struct scatterlist *sg;
+
+    sg = (struct scatterlist *)cmd->request_buffer;
+    pci_unmap_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  }
+  else if (cmd->request_bufflen)
+    pci_unmap_single(p->pdev, aic7xxx_mapping(cmd),
+		     cmd->request_bufflen,
+                     scsi_to_pci_dma_dir(cmd->sc_data_direction));
+  if (scb->flags & SCB_SENSE)
+  {
+    pci_unmap_single(p->pdev,
+                     le32_to_cpu(scb->sg_list[0].address),
+                     sizeof(cmd->sense_buffer),
+                     PCI_DMA_FROMDEVICE);
+  }
+  if (scb->flags & SCB_RECOVERY_SCB)
+  {
+    p->flags &= ~AHC_ABORT_PENDING;
+  }
+  if (scb->flags & (SCB_RESET|SCB_ABORT))
+  {
+    cmd->result |= (DID_RESET << 16);
+  }
+
+  if ((scb->flags & SCB_MSGOUT_BITS) != 0)
+  {
+    unsigned short mask;
+    int message_error = FALSE;
+
+    mask = 0x01 << tindex;
+ 
+    /*
+     * Check to see if we get an invalid message or a message error
+     * after failing to negotiate a wide or sync transfer message.
+     */
+    if ((scb->flags & SCB_SENSE) && 
+          ((scb->cmd->sense_buffer[12] == 0x43) ||  /* INVALID_MESSAGE */
+          (scb->cmd->sense_buffer[12] == 0x49))) /* MESSAGE_ERROR  */
+    {
+      message_error = TRUE;
+    }
+
+    if (scb->flags & SCB_MSGOUT_WDTR)
+    {
+      if (message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Wide Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Wide negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+        }
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+      }
+    }
+    if (scb->flags & SCB_MSGOUT_SDTR)
+    {
+      if (message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Sync Negotiation "
+            "processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Sync negotiation to this device.\n", p->host_no,
+            CTL_OF_SCB(scb));
+          aic_dev->flags &= ~DEVICE_PRINT_DTR;
+        }
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+      }
+    }
+    if (scb->flags & SCB_MSGOUT_PPR)
+    {
+      if(message_error)
+      {
+        if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+             (aic_dev->flags & DEVICE_PRINT_DTR) )
+        {
+          printk(INFO_LEAD "Device failed to complete Parallel Protocol "
+            "Request processing and\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "returned a sense error code for invalid message, "
+            "disabling future\n", p->host_no, CTL_OF_SCB(scb));
+          printk(INFO_LEAD "Parallel Protocol Request negotiation to this "
+            "device.\n", p->host_no, CTL_OF_SCB(scb));
+        }
+        /*
+         * Disable PPR negotiation and revert back to WDTR and SDTR setup
+         */
+        aic_dev->needppr = aic_dev->needppr_copy = 0;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+      }
+    }
+  }
+
+  queue_depth = aic_dev->temp_q_depth;
+  if (queue_depth >= aic_dev->active_cmds)
+  {
+    scbp = scbq_remove_head(&aic_dev->delayed_scbs);
+    if (scbp)
+    {
+      if (queue_depth == 1)
+      {
+        /*
+         * Give extra preference to untagged devices, such as CD-R devices
+         * This makes it more likely that a drive *won't* stuff up while
+         * waiting on data at a critical time, such as CD-R writing and
+         * audio CD ripping operations.  Should also benefit tape drives.
+         */
+        scbq_insert_head(&p->waiting_scbs, scbp);
+      }
+      else
+      {
+        scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Moving SCB from delayed to waiting queue.\n",
+               p->host_no, CTL_OF_SCB(scbp));
+#endif
+      if (queue_depth > aic_dev->active_cmds)
+      {
+        scbp = scbq_remove_head(&aic_dev->delayed_scbs);
+        if (scbp)
+          scbq_insert_tail(&p->waiting_scbs, scbp);
+      }
+    }
+  }
+  if (!(scb->tag_action))
+  {
+    aic7xxx_index_busy_target(p, scb->hscb->target_channel_lun,
+                              /* unbusy */ TRUE);
+    if (cmd->device->simple_tags)
+    {
+      aic_dev->temp_q_depth = aic_dev->max_q_depth;
+    }
+  }
+  if(scb->flags & SCB_DTR_SCB)
+  {
+    aic_dev->dtr_pending = 0;
+  }
+  aic_dev->active_cmds--;
+  p->activescbs--;
+
+  if ((scb->sg_length >= 512) && (((cmd->result >> 16) & 0xf) == DID_OK))
+  {
+    long *ptr;
+    int x, i;
+
+
+    if (rq_data_dir(cmd->request) == WRITE)
+    {
+      aic_dev->w_total++;
+      ptr = aic_dev->w_bins;
+    }
+    else
+    {
+      aic_dev->r_total++;
+      ptr = aic_dev->r_bins;
+    }
+    if(cmd->device->simple_tags && cmd->request->flags & REQ_HARDBARRIER)
+    {
+      aic_dev->barrier_total++;
+      if(scb->tag_action == MSG_ORDERED_Q_TAG)
+        aic_dev->ordered_total++;
+    }
+    x = scb->sg_length;
+    x >>= 10;
+    for(i=0; i<6; i++)
+    {
+      x >>= 2;
+      if(!x) {
+        ptr[i]++;
+	break;
+      }
+    }
+    if(i == 6 && x)
+      ptr[5]++;
+  }
+  aic7xxx_free_scb(p, scb);
+  aic7xxx_queue_cmd_complete(p, cmd);
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_run_done_queue
+ *
+ * Description:
+ *   Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ *   aborted list, and adds each scb to the free list.  If complete
+ *   is TRUE, we also process the commands complete list.
+ *-F*************************************************************************/
+static void
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
+{
+  struct aic7xxx_scb *scb;
+  int i, found = 0;
+
+  for (i = 0; i < p->scb_data->numscbs; i++)
+  {
+    scb = p->scb_data->scb_array[i];
+    if (scb->flags & SCB_QUEUED_FOR_DONE)
+    {
+      if (scb->flags & SCB_QUEUE_FULL)
+      {
+	scb->cmd->result = QUEUE_FULL << 1;
+      }
+      else
+      {
+        if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+          printk(INFO_LEAD "Aborting scb %d\n",
+               p->host_no, CTL_OF_SCB(scb), scb->hscb->tag);
+        /*
+         * Clear any residual information since the normal aic7xxx_done() path
+         * doesn't touch the residuals.
+         */
+        scb->hscb->residual_SG_segment_count = 0;
+        scb->hscb->residual_data_count[0] = 0;
+        scb->hscb->residual_data_count[1] = 0;
+        scb->hscb->residual_data_count[2] = 0;
+      }
+      found++;
+      aic7xxx_done(p, scb);
+    }
+  }
+  if (aic7xxx_verbose & (VERBOSE_ABORT_RETURN | VERBOSE_RESET_RETURN))
+  {
+    printk(INFO_LEAD "%d commands found and queued for "
+        "completion.\n", p->host_no, -1, -1, -1, found);
+  }
+  if (complete)
+  {
+    aic7xxx_done_cmds_complete(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_abort_waiting_scb
+ *
+ * Description:
+ *   Manipulate the waiting for selection list and return the
+ *   scb that follows the one that we remove.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
+    unsigned char scbpos, unsigned char prev)
+{
+  unsigned char curscb, next;
+
+  /*
+   * Select the SCB we want to abort and pull the next pointer out of it.
+   */
+  curscb = aic_inb(p, SCBPTR);
+  aic_outb(p, scbpos, SCBPTR);
+  next = aic_inb(p, SCB_NEXT);
+
+  aic7xxx_add_curscb_to_free_list(p);
+
+  /*
+   * Update the waiting list
+   */
+  if (prev == SCB_LIST_NULL)
+  {
+    /*
+     * First in the list
+     */
+    aic_outb(p, next, WAITING_SCBH);
+  }
+  else
+  {
+    /*
+     * Select the scb that pointed to us and update its next pointer.
+     */
+    aic_outb(p, prev, SCBPTR);
+    aic_outb(p, next, SCB_NEXT);
+  }
+  /*
+   * Point us back at the original scb position and inform the SCSI
+   * system that the command has been aborted.
+   */
+  aic_outb(p, curscb, SCBPTR);
+  return (next);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_search_qinfifo
+ *
+ * Description:
+ *   Search the queue-in FIFO for matching SCBs and conditionally
+ *   requeue.  Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, int channel,
+    int lun, unsigned char tag, int flags, int requeue,
+    volatile scb_queue_type *queue)
+{
+  int      found;
+  unsigned char qinpos, qintail;
+  struct aic7xxx_scb *scbp;
+
+  found = 0;
+  qinpos = aic_inb(p, QINPOS);
+  qintail = p->qinfifonext;
+
+  p->qinfifonext = qinpos;
+
+  while (qinpos != qintail)
+  {
+    scbp = p->scb_data->scb_array[p->qinfifo[qinpos++]];
+    if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+    {
+       /*
+        * We found an scb that needs to be removed.
+        */
+       if (requeue && (queue != NULL))
+       {
+         if (scbp->flags & SCB_WAITINGQ)
+         {
+           scbq_remove(queue, scbp);
+           scbq_remove(&p->waiting_scbs, scbp);
+           scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp);
+           AIC_DEV(scbp->cmd)->active_cmds++;
+           p->activescbs++;
+         }
+         scbq_insert_tail(queue, scbp);
+         AIC_DEV(scbp->cmd)->active_cmds--;
+         p->activescbs--;
+         scbp->flags |= SCB_WAITINGQ;
+         if ( !(scbp->tag_action & TAG_ENB) )
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       else if (requeue)
+       {
+         p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
+       }
+       else
+       {
+        /*
+         * Preserve any SCB_RECOVERY_SCB flags on this scb then set the
+         * flags we were called with, presumeably so aic7xxx_run_done_queue
+         * can find this scb
+         */
+         scbp->flags = flags | (scbp->flags & SCB_RECOVERY_SCB);
+         if (aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+                                       FALSE) == scbp->hscb->tag)
+         {
+           aic7xxx_index_busy_target(p, scbp->hscb->target_channel_lun,
+             TRUE);
+         }
+       }
+       found++;
+    }
+    else
+    {
+      p->qinfifo[p->qinfifonext++] = scbp->hscb->tag;
+    }
+  }
+  /*
+   * Now that we've done the work, clear out any left over commands in the
+   * qinfifo and update the KERNEL_QINPOS down on the card.
+   *
+   *  NOTE: This routine expect the sequencer to already be paused when
+   *        it is run....make sure it's that way!
+   */
+  qinpos = p->qinfifonext;
+  while(qinpos != qintail)
+  {
+    p->qinfifo[qinpos++] = SCB_LIST_NULL;
+  }
+  if (p->features & AHC_QUEUE_REGS)
+    aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+  else
+    aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_scb_on_qoutfifo
+ *
+ * Description:
+ *   Is the scb that was passed to us currently on the qoutfifo?
+ *-F*************************************************************************/
+static int
+aic7xxx_scb_on_qoutfifo(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int i=0;
+
+  while(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] != SCB_LIST_NULL)
+  {
+    if(p->qoutfifo[(p->qoutfifonext + i) & 0xff ] == scb->hscb->tag)
+      return TRUE;
+    else
+      i++;
+  }
+  return FALSE;
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_device
+ *
+ * Description:
+ *   The device at the given target/channel has been reset.  Abort
+ *   all active and queued scbs for that target/channel.  This function
+ *   need not worry about linked next pointers because if was a MSG_ABORT_TAG
+ *   then we had a tagged command (no linked next), if it was MSG_ABORT or
+ *   MSG_BUS_DEV_RESET then the device won't know about any commands any more
+ *   and no busy commands will exist, and if it was a bus reset, then nothing
+ *   knows about any linked next commands any more.  In all cases, we don't
+ *   need to worry about the linked next or busy scb, we just need to clear
+ *   them.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, int channel,
+                     int lun, unsigned char tag)
+{
+  struct aic7xxx_scb *scbp, *prev_scbp;
+  struct scsi_device *sd;
+  unsigned char active_scb, tcl, scb_tag;
+  int i = 0, init_lists = FALSE;
+  struct aic_dev_data *aic_dev;
+
+  /*
+   * Restore this when we're done
+   */
+  active_scb = aic_inb(p, SCBPTR);
+  scb_tag = aic_inb(p, SCB_TAG);
+
+  if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+  {
+    printk(INFO_LEAD "Reset device, hardware_scb %d,\n",
+         p->host_no, channel, target, lun, active_scb);
+    printk(INFO_LEAD "Current scb %d, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, channel, target, lun, scb_tag,
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, channel, target, lun,
+         (p->features & AHC_ULTRA2) ?  aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SG_COUNT), aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, channel, target, lun, aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
+
+  /*
+   * Deal with the busy target and linked next issues.
+   */
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
+  {
+    if (aic7xxx_verbose & (VERBOSE_RESET_PROCESS | VERBOSE_ABORT_PROCESS))
+      printk(INFO_LEAD "processing aic_dev %p\n", p->host_no, channel, target,
+		    lun, aic_dev);
+    sd = aic_dev->SDptr;
+
+    if((target != ALL_TARGETS && target != sd->id) ||
+       (channel != ALL_CHANNELS && channel != sd->channel))
+      continue;
+    if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+        printk(INFO_LEAD "Cleaning up status information "
+          "and delayed_scbs.\n", p->host_no, sd->channel, sd->id, sd->lun);
+    aic_dev->flags &= ~BUS_DEVICE_RESET_PENDING;
+    if ( tag == SCB_LIST_NULL )
+    {
+      aic_dev->dtr_pending = 0;
+      aic_dev->needppr = aic_dev->needppr_copy;
+      aic_dev->needsdtr = aic_dev->needsdtr_copy;
+      aic_dev->needwdtr = aic_dev->needwdtr_copy;
+      aic_dev->flags = DEVICE_PRINT_DTR;
+      aic_dev->temp_q_depth = aic_dev->max_q_depth;
+    }
+    tcl = (sd->id << 4) | (sd->channel << 3) | sd->lun;
+    if ( (aic7xxx_index_busy_target(p, tcl, FALSE) == tag) ||
+         (tag == SCB_LIST_NULL) )
+      aic7xxx_index_busy_target(p, tcl, /* unbusy */ TRUE);
+    prev_scbp = NULL; 
+    scbp = aic_dev->delayed_scbs.head;
+    while (scbp != NULL)
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&aic_dev->delayed_scbs, prev_scbp);
+        if (prev_scbp->flags & SCB_WAITINGQ)
+        {
+          aic_dev->active_cmds++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      }
+    }
+  }
+
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning QINFIFO.\n", p->host_no, channel, target, lun );
+  aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+      SCB_RESET | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE, NULL);
+
+/*
+ *  Search the waiting_scbs queue for matches, this catches any SCB_QUEUED
+ *  ABORT/RESET commands.
+ */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting_scbs.\n", p->host_no, channel,
+      target, lun );
+  {
+    struct aic7xxx_scb *scbp, *prev_scbp;
+
+    prev_scbp = NULL; 
+    scbp = p->waiting_scbs.head;
+    while (scbp != NULL)
+    {
+      prev_scbp = scbp;
+      scbp = scbp->q_next;
+      if (aic7xxx_match_scb(p, prev_scbp, target, channel, lun, tag))
+      {
+        scbq_remove(&p->waiting_scbs, prev_scbp);
+        if (prev_scbp->flags & SCB_WAITINGQ)
+        {
+          AIC_DEV(prev_scbp->cmd)->active_cmds++;
+          p->activescbs++;
+        }
+        prev_scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+        prev_scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      }
+    }
+  }
+
+
+  /*
+   * Search waiting for selection list.
+   */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning waiting for selection "
+      "list.\n", p->host_no, channel, target, lun);
+  {
+    unsigned char next, prev, scb_index;
+
+    next = aic_inb(p, WAITING_SCBH);  /* Start at head of list. */
+    prev = SCB_LIST_NULL;
+    while (next != SCB_LIST_NULL)
+    {
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+      if (scb_index >= p->scb_data->numscbs)
+      {
+       /*
+        * No aic7xxx_verbose check here.....we want to see this since it
+        * means either the kernel driver or the sequencer screwed things up
+        */
+        printk(WARN_LEAD "Waiting List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic_inb(p, SCB_NEXT);
+        aic7xxx_add_curscb_to_free_list(p);
+      }
+      else
+      {
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            AIC_DEV(scbp->cmd)->active_cmds++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          if (prev == SCB_LIST_NULL)
+          {
+            /*
+             * This is either the first scb on the waiting list, or we
+             * have already yanked the first and haven't left any behind.
+             * Either way, we need to turn off the selection hardware if
+             * it isn't already off.
+             */
+            aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+            aic_outb(p, CLRSELTIMEO, CLRSINT1);
+          }
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
+      }
+    }
+  }
+
+  /*
+   * Go through disconnected list and remove any entries we have queued
+   * for completion, zeroing their control byte too.
+   */
+  if (aic7xxx_verbose & (VERBOSE_ABORT_PROCESS | VERBOSE_RESET_PROCESS))
+    printk(INFO_LEAD "Cleaning disconnected scbs "
+      "list.\n", p->host_no, channel, target, lun);
+  if (p->flags & AHC_PAGESCBS)
+  {
+    unsigned char next, prev, scb_index;
+
+    next = aic_inb(p, DISCONNECTED_SCBH);
+    prev = SCB_LIST_NULL;
+    while (next != SCB_LIST_NULL)
+    {
+      aic_outb(p, next, SCBPTR);
+      scb_index = aic_inb(p, SCB_TAG);
+      if (scb_index > p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "Disconnected List inconsistency; SCB index=%d, "
+          "numscbs=%d\n", p->host_no, channel, target, lun, scb_index,
+          p->scb_data->numscbs);
+        next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
+      }
+      else
+      {
+        scbp = p->scb_data->scb_array[scb_index];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          next = aic7xxx_rem_scb_from_disc_list(p, next, prev);
+          if (scbp->flags & SCB_WAITINGQ)
+          {
+            AIC_DEV(scbp->cmd)->active_cmds++;
+            p->activescbs++;
+          }
+          scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+          scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+          scbp->hscb->control = 0;
+        }
+        else
+        {
+          prev = next;
+          next = aic_inb(p, SCB_NEXT);
+        }
+      }
+    }
+  }
+
+  /*
+   * Walk the free list making sure no entries on the free list have
+   * a valid SCB_TAG value or SCB_CONTROL byte.
+   */
+  if (p->flags & AHC_PAGESCBS)
+  {
+    unsigned char next;
+
+    next = aic_inb(p, FREE_SCBH);
+    while (next != SCB_LIST_NULL)
+    {
+      aic_outb(p, next, SCBPTR);
+      if (aic_inb(p, SCB_TAG) < p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "Free list inconsistency!.\n", p->host_no, channel,
+          target, lun);
+        init_lists = TRUE;
+        next = SCB_LIST_NULL;
+      }
+      else
+      {
+        aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+        aic_outb(p, 0, SCB_CONTROL);
+        next = aic_inb(p, SCB_NEXT);
+      }
+    }
+  }
+
+  /*
+   * Go through the hardware SCB array looking for commands that
+   * were active but not on any list.
+   */
+  if (init_lists)
+  {
+    aic_outb(p, SCB_LIST_NULL, FREE_SCBH);
+    aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+    aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+  }
+  for (i = p->scb_data->maxhscbs - 1; i >= 0; i--)
+  {
+    unsigned char scbid;
+
+    aic_outb(p, i, SCBPTR);
+    if (init_lists)
+    {
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+    }
+    else
+    {
+      scbid = aic_inb(p, SCB_TAG);
+      if (scbid < p->scb_data->numscbs)
+      {
+        scbp = p->scb_data->scb_array[scbid];
+        if (aic7xxx_match_scb(p, scbp, target, channel, lun, tag))
+        {
+          aic_outb(p, 0, SCB_CONTROL);
+          aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+          aic7xxx_add_curscb_to_free_list(p);
+        }
+      }
+    }
+  }
+
+  /*
+   * Go through the entire SCB array now and look for commands for
+   * for this target that are stillactive.  These are other (most likely
+   * tagged) commands that were disconnected when the reset occurred.
+   * Any commands we find here we know this about, it wasn't on any queue,
+   * it wasn't in the qinfifo, it wasn't in the disconnected or waiting
+   * lists, so it really must have been a paged out SCB.  In that case,
+   * we shouldn't need to bother with updating any counters, just mark
+   * the correct flags and go on.
+   */
+  for (i = 0; i < p->scb_data->numscbs; i++)
+  {
+    scbp = p->scb_data->scb_array[i];
+    if ((scbp->flags & SCB_ACTIVE) &&
+        aic7xxx_match_scb(p, scbp, target, channel, lun, tag) &&
+        !aic7xxx_scb_on_qoutfifo(p, scbp))
+    {
+      if (scbp->flags & SCB_WAITINGQ)
+      {
+        scbq_remove(&p->waiting_scbs, scbp);
+        scbq_remove(&AIC_DEV(scbp->cmd)->delayed_scbs, scbp);
+        AIC_DEV(scbp->cmd)->active_cmds++;
+        p->activescbs++;
+      }
+      scbp->flags |= SCB_RESET | SCB_QUEUED_FOR_DONE;
+      scbp->flags &= ~(SCB_ACTIVE | SCB_WAITINGQ);
+    }
+  }
+
+  aic_outb(p, active_scb, SCBPTR);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_clear_intstat
+ *
+ * Description:
+ *   Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+  /* Clear any interrupt conditions this may have caused. */
+  aic_outb(p, CLRSELDO | CLRSELDI | CLRSELINGO, CLRSINT0);
+  aic_outb(p, CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+       CLRPHASECHG | CLRREQINIT, CLRSINT1);
+  aic_outb(p, CLRSCSIINT | CLRSEQINT | CLRBRKADRINT | CLRPARERR, CLRINT);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_current_bus
+ *
+ * Description:
+ *   Reset the current SCSI bus.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
+{
+
+  /* Disable reset interrupts. */
+  aic_outb(p, aic_inb(p, SIMODE1) & ~ENSCSIRST, SIMODE1);
+
+  /* Turn off the bus' current operations, after all, we shouldn't have any
+   * valid commands left to cause a RSELI and SELO once we've tossed the
+   * bus away with this reset, so we might as well shut down the sequencer
+   * until the bus is restarted as oppossed to saving the current settings
+   * and restoring them (which makes no sense to me). */
+
+  /* Turn on the bus reset. */
+  aic_outb(p, aic_inb(p, SCSISEQ) | SCSIRSTO, SCSISEQ);
+  while ( (aic_inb(p, SCSISEQ) & SCSIRSTO) == 0)
+    mdelay(5);
+
+  /*
+   * Some of the new Ultra2 chipsets need a longer delay after a chip
+   * reset than just the init setup creates, so we have to delay here
+   * before we go into a reset in order to make the chips happy.
+   */
+  if (p->features & AHC_ULTRA2)
+    mdelay(250);
+  else
+    mdelay(50);
+
+  /* Turn off the bus reset. */
+  aic_outb(p, 0, SCSISEQ);
+  mdelay(10);
+
+  aic7xxx_clear_intstat(p);
+  /* Re-enable reset interrupts. */
+  aic_outb(p, aic_inb(p, SIMODE1) | ENSCSIRST, SIMODE1);
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset_channel
+ *
+ * Description:
+ *   Reset the channel.
+ *-F*************************************************************************/
+static void
+aic7xxx_reset_channel(struct aic7xxx_host *p, int channel, int initiate_reset)
+{
+  unsigned long offset_min, offset_max;
+  unsigned char sblkctl;
+  int cur_channel;
+
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Reset channel called, %s initiate reset.\n",
+      p->host_no, channel, -1, -1, (initiate_reset==TRUE) ? "will" : "won't" );
+
+
+  if (channel == 1)
+  {
+    offset_min = 8;
+    offset_max = 16;
+  }
+  else
+  {
+    if (p->features & AHC_TWIN)
+    {
+      /* Channel A */
+      offset_min = 0;
+      offset_max = 8;
+    }
+    else
+    {
+      offset_min = 0;
+      if (p->features & AHC_WIDE)
+      {
+        offset_max = 16;
+      }
+      else
+      {
+        offset_max = 8;
+      }
+    }
+  }
+
+  while (offset_min < offset_max)
+  {
+    /*
+     * Revert to async/narrow transfers until we renegotiate.
+     */
+    aic_outb(p, 0, TARG_SCSIRATE + offset_min);
+    if (p->features & AHC_ULTRA2)
+    {
+      aic_outb(p, 0, TARG_OFFSET + offset_min);
+    }
+    offset_min++;
+  }
+
+  /*
+   * Reset the bus and unpause/restart the controller
+   */
+  sblkctl = aic_inb(p, SBLKCTL);
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    cur_channel = (sblkctl & SELBUSB) >> 3;
+  else
+    cur_channel = 0;
+  if ( (cur_channel != channel) && (p->features & AHC_TWIN) )
+  {
+    /*
+     * Case 1: Command for another bus is active
+     */
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Stealthily resetting idle channel.\n", p->host_no,
+        channel, -1, -1);
+    /*
+     * Stealthily reset the other bus without upsetting the current bus.
+     */
+    aic_outb(p, sblkctl ^ SELBUSB, SBLKCTL);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~ENBUSFREE, SIMODE1);
+    if (initiate_reset)
+    {
+      aic7xxx_reset_current_bus(p);
+    }
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
+    aic7xxx_clear_intstat(p);
+    aic_outb(p, sblkctl, SBLKCTL);
+  }
+  else
+  {
+    /*
+     * Case 2: A command from this bus is active or we're idle.
+     */
+    if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+      printk(INFO_LEAD "Resetting currently active channel.\n", p->host_no,
+        channel, -1, -1);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    p->msg_type = MSG_TYPE_NONE;
+    p->msg_len = 0;
+    if (initiate_reset)
+    {
+      aic7xxx_reset_current_bus(p);
+    }
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP), SCSISEQ);
+    aic7xxx_clear_intstat(p);
+  }
+  if (aic7xxx_verbose & VERBOSE_RESET_RETURN)
+    printk(INFO_LEAD "Channel reset\n", p->host_no, channel, -1, -1);
+  /*
+   * Clean up all the state information for the pending transactions
+   * on this bus.
+   */
+  aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
+
+  if ( !(p->features & AHC_TWIN) )
+  {
+    restart_sequencer(p);
+  }
+
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_run_waiting_queues
+ *
+ * Description:
+ *   Scan the awaiting_scbs queue downloading and starting as many
+ *   scbs as we can.
+ *-F*************************************************************************/
+static void
+aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
+  int sent;
+
+
+  if (p->waiting_scbs.head == NULL)
+    return;
+
+  sent = 0;
+
+  /*
+   * First handle SCBs that are waiting but have been assigned a slot.
+   */
+  while ((scb = scbq_remove_head(&p->waiting_scbs)) != NULL)
+  {
+    aic_dev = scb->cmd->device->hostdata;
+    if ( !scb->tag_action )
+    {
+      aic_dev->temp_q_depth = 1;
+    }
+    if ( aic_dev->active_cmds >= aic_dev->temp_q_depth)
+    {
+      scbq_insert_tail(&aic_dev->delayed_scbs, scb);
+    }
+    else
+    {
+        scb->flags &= ~SCB_WAITINGQ;
+        aic_dev->active_cmds++;
+        p->activescbs++;
+        if ( !(scb->tag_action) )
+        {
+          aic7xxx_busy_target(p, scb);
+        }
+        p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+        sent++;
+    }
+  }
+  if (sent)
+  {
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+    {
+      pause_sequencer(p);
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      unpause_sequencer(p, FALSE);
+    }
+    if (p->activescbs > p->max_activescbs)
+      p->max_activescbs = p->activescbs;
+  }
+}
+
+#ifdef CONFIG_PCI
+
+#define  DPE 0x80
+#define  SSE 0x40
+#define  RMA 0x20
+#define  RTA 0x10
+#define  STA 0x08
+#define  DPR 0x01
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_pci_intr
+ *
+ * Description:
+ *   Check the scsi card for PCI errors and clear the interrupt
+ *
+ *   NOTE: If you don't have this function and a 2940 card encounters
+ *         a PCI error condition, the machine will end up locked as the
+ *         interrupt handler gets slammed with non-stop PCI error interrupts
+ *-F*************************************************************************/
+static void
+aic7xxx_pci_intr(struct aic7xxx_host *p)
+{
+  unsigned char status1;
+
+  pci_read_config_byte(p->pdev, PCI_STATUS + 1, &status1);
+
+  if ( (status1 & DPE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error during PCI address or PCI write"
+      "phase.\n", p->host_no, -1, -1, -1);
+  if ( (status1 & SSE) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signal System Error Detected\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RMA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Master Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & RTA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Received a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & STA) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Signaled a PCI Target Abort\n", p->host_no,
+      -1, -1, -1);
+  if ( (status1 & DPR) && (aic7xxx_verbose & VERBOSE_MINOR_ERROR) )
+    printk(WARN_LEAD "Data Parity Error has been reported via PCI pin "
+      "PERR#\n", p->host_no, -1, -1, -1);
+  
+  pci_write_config_byte(p->pdev, PCI_STATUS + 1, status1);
+  if (status1 & (DPR|RMA|RTA))
+    aic_outb(p,  CLRPARERR, CLRINT);
+
+  if ( (aic7xxx_panic_on_abort) && (p->spurious_int > 500) )
+    aic7xxx_panic_abort(p, NULL);
+
+}
+#endif /* CONFIG_PCI */
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_ppr
+ *
+ * Description:
+ *   Build up a Parallel Protocol Request message for use with SCSI-3
+ *   devices.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_ppr(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_PPR;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.period;
+  p->msg_buf[p->msg_index++] = 0;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.offset;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.width;
+  p->msg_buf[p->msg_index++] = AIC_DEV(scb->cmd)->goal.options;
+  p->msg_len += 8;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_sdtr
+ *
+ * Description:
+ *   Constucts a synchronous data transfer message in the message
+ *   buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, unsigned char period,
+        unsigned char offset)
+{
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_SDTR;
+  p->msg_buf[p->msg_index++] = period;
+  p->msg_buf[p->msg_index++] = offset;
+  p->msg_len += 5;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_construct_wdtr
+ *
+ * Description:
+ *   Constucts a wide data transfer message in the message buffer
+ *   on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, unsigned char bus_width)
+{
+  p->msg_buf[p->msg_index++] = MSG_EXTENDED;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR_LEN;
+  p->msg_buf[p->msg_index++] = MSG_EXT_WDTR;
+  p->msg_buf[p->msg_index++] = bus_width;
+  p->msg_len += 4;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_calc_residual
+ *
+ * Description:
+ *   Calculate the residual data not yet transferred.
+ *-F*************************************************************************/
+static void
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  struct aic7xxx_hwscb *hscb;
+  Scsi_Cmnd *cmd;
+  int actual, i;
+
+  cmd = scb->cmd;
+  hscb = scb->hscb;
+
+  /*
+   *  Don't destroy valid residual information with
+   *  residual coming from a check sense operation.
+   */
+  if (((scb->hscb->control & DISCONNECTED) == 0) &&
+      (scb->flags & SCB_SENSE) == 0)
+  {
+    /*
+     *  We had an underflow. At this time, there's only
+     *  one other driver that bothers to check for this,
+     *  and cmd->underflow seems to be set rather half-
+     *  heartedly in the higher-level SCSI code.
+     */
+    actual = scb->sg_length;
+    for (i=1; i < hscb->residual_SG_segment_count; i++)
+    {
+      actual -= scb->sg_list[scb->sg_count - i].length;
+    }
+    actual -= (hscb->residual_data_count[2] << 16) |
+              (hscb->residual_data_count[1] <<  8) |
+              hscb->residual_data_count[0];
+
+    if (actual < cmd->underflow)
+    {
+      if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+      {
+        printk(INFO_LEAD "Underflow - Wanted %u, %s %u, residual SG "
+          "count %d.\n", p->host_no, CTL_OF_SCB(scb), cmd->underflow,
+          (rq_data_dir(cmd->request) == WRITE) ? "wrote" : "read", actual,
+          hscb->residual_SG_segment_count);
+        printk(INFO_LEAD "status 0x%x.\n", p->host_no, CTL_OF_SCB(scb),
+          hscb->target_status);
+      }
+      /*
+       * In 2.4, only send back the residual information, don't flag this
+       * as an error.  Before 2.4 we had to flag this as an error because
+       * the mid layer didn't check residual data counts to see if the
+       * command needs retried.
+       */
+      cmd->resid = scb->sg_length - actual;
+      aic7xxx_status(cmd) = hscb->target_status;
+    }
+  }
+
+  /*
+   * Clean out the residual information in the SCB for the
+   * next consumer.
+   */
+  hscb->residual_data_count[2] = 0;
+  hscb->residual_data_count[1] = 0;
+  hscb->residual_data_count[0] = 0;
+  hscb->residual_SG_segment_count = 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_device_reset
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, int channel)
+{
+  unsigned char tindex = target;
+
+  tindex |= ((channel & 0x01) << 3);
+
+  /*
+   * Go back to async/narrow transfers and renegotiate.
+   */
+  aic_outb(p, 0, TARG_SCSIRATE + tindex);
+  if (p->features & AHC_ULTRA2)
+    aic_outb(p, 0, TARG_OFFSET + tindex);
+  aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+    printk(INFO_LEAD "Bus Device Reset delivered.\n", p->host_no, channel,
+      target, -1);
+  aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_seqint
+ *
+ * Description:
+ *   Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
+  unsigned short target_mask;
+  unsigned char target, lun, tindex;
+  unsigned char queue_flag = FALSE;
+  char channel;
+  int result;
+
+  target = ((aic_inb(p, SAVED_TCL) >> 4) & 0x0f);
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+    channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+  else
+    channel = 0;
+  tindex = target + (channel << 3);
+  lun = aic_inb(p, SAVED_TCL) & 0x07;
+  target_mask = (0x01 << tindex);
+
+  /*
+   * Go ahead and clear the SEQINT now, that avoids any interrupt race
+   * conditions later on in case we enable some other interrupt.
+   */
+  aic_outb(p, CLRSEQINT, CLRINT);
+  switch (intstat & SEQINT_MASK)
+  {
+    case NO_MATCH:
+      {
+        aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+                 SCSISEQ);
+        printk(WARN_LEAD "No active SCB for reconnecting target - Issuing "
+               "BUS DEVICE RESET.\n", p->host_no, channel, target, lun);
+        printk(WARN_LEAD "      SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+               p->host_no, channel, target, lun,
+               aic_inb(p, SAVED_TCL), aic_inb(p, ARG_1),
+               (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+        if (aic7xxx_panic_on_abort)
+          aic7xxx_panic_abort(p, NULL);
+      }
+      break;
+
+    case SEND_REJECT:
+      {
+        if (aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Rejecting unknown message (0x%x) received from "
+            "target, SEQ_FLAGS=0x%x\n", p->host_no, channel, target, lun,
+            aic_inb(p, ACCUM), aic_inb(p, SEQ_FLAGS));
+      }
+      break;
+
+    case NO_IDENT:
+      {
+        /*
+         * The reconnecting target either did not send an identify
+         * message, or did, but we didn't find an SCB to match and
+         * before it could respond to our ATN/abort, it hit a dataphase.
+         * The only safe thing to do is to blow it away with a bus
+         * reset.
+         */
+        if (aic7xxx_verbose & (VERBOSE_SEQINT | VERBOSE_RESET_MID))
+          printk(INFO_LEAD "Target did not send an IDENTIFY message; "
+            "LASTPHASE 0x%x, SAVED_TCL 0x%x\n", p->host_no, channel, target,
+            lun, aic_inb(p, LASTPHASE), aic_inb(p, SAVED_TCL));
+
+        aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+        aic7xxx_run_done_queue(p, TRUE);
+
+      }
+      break;
+
+    case BAD_PHASE:
+      if (aic_inb(p, LASTPHASE) == P_BUSFREE)
+      {
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Missed busfree.\n", p->host_no, channel,
+            target, lun);
+        restart_sequencer(p);
+      }
+      else
+      {
+        if (aic7xxx_verbose & VERBOSE_SEQINT)
+          printk(INFO_LEAD "Unknown scsi bus phase, continuing\n", p->host_no,
+            channel, target, lun);
+      }
+      break;
+
+    case EXTENDED_MSG:
+      {
+        p->msg_type = MSG_TYPE_INITIATOR_MSGIN;
+        p->msg_len = 0;
+        p->msg_index = 0;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+        if (aic7xxx_verbose > 0xffff)
+          printk(INFO_LEAD "Enabling REQINITs for MSG_IN\n", p->host_no,
+                 channel, target, lun);
+#endif
+
+       /*      
+        * To actually receive the message, simply turn on
+        * REQINIT interrupts and let our interrupt handler
+        * do the rest (REQINIT should already be true).
+        */
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+
+       /*
+        * We don't want the sequencer unpaused yet so we return early
+        */
+        return;
+      }
+
+    case REJECT_MSG:
+      {
+        /*
+         * What we care about here is if we had an outstanding SDTR
+         * or WDTR message for this target. If we did, this is a
+         * signal that the target is refusing negotiation.
+         */
+        unsigned char scb_index;
+        unsigned char last_msg;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        scb = p->scb_data->scb_array[scb_index];
+	aic_dev = AIC_DEV(scb->cmd);
+        last_msg = aic_inb(p, LAST_MSG);
+
+        if ( (last_msg == MSG_IDENTIFYFLAG) &&
+             (scb->tag_action) &&
+            !(scb->flags & SCB_MSGOUT_BITS) )
+        {
+          if (scb->tag_action == MSG_ORDERED_Q_TAG)
+          {
+            /*
+             * OK...the device seems able to accept tagged commands, but
+             * not ordered tag commands, only simple tag commands.  So, we
+             * disable ordered tag commands and go on with life just like
+             * normal.
+             */
+	    scsi_adjust_queue_depth(scb->cmd->device, MSG_SIMPLE_TAG,
+			    scb->cmd->device->queue_depth);
+            scb->tag_action = MSG_SIMPLE_Q_TAG;
+            scb->hscb->control &= ~SCB_TAG_TYPE;
+            scb->hscb->control |= MSG_SIMPLE_Q_TAG;
+            aic_outb(p, scb->hscb->control, SCB_CONTROL);
+            /*
+             * OK..we set the tag type to simple tag command, now we re-assert
+             * ATNO and hope this will take us into the identify phase again
+             * so we can resend the tag type and info to the device.
+             */
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+          else if (scb->tag_action == MSG_SIMPLE_Q_TAG)
+          {
+            unsigned char i;
+            struct aic7xxx_scb *scbp;
+            int old_verbose;
+            /*
+             * Hmmmm....the device is flaking out on tagged commands.
+             */
+	    scsi_adjust_queue_depth(scb->cmd->device, 0 /* untagged */,
+			    p->host->cmd_per_lun);
+            aic_dev->max_q_depth = aic_dev->temp_q_depth = 1;
+            /*
+             * We set this command up as a bus device reset.  However, we have
+             * to clear the tag type as it's causing us problems.  We shouldnt
+             * have to worry about any other commands being active, since if
+             * the device is refusing tagged commands, this should be the
+             * first tagged command sent to the device, however, we do have
+             * to worry about any other tagged commands that may already be
+             * in the qinfifo.  The easiest way to do this, is to issue a BDR,
+             * send all the commands back to the mid level code, then let them
+             * come back and get rebuilt as untagged commands.
+             */
+            scb->tag_action = 0;
+            scb->hscb->control &= ~(TAG_ENB | SCB_TAG_TYPE);
+            aic_outb(p,  scb->hscb->control, SCB_CONTROL);
+
+            old_verbose = aic7xxx_verbose;
+            aic7xxx_verbose &= ~(VERBOSE_RESET|VERBOSE_ABORT);
+            for (i=0; i < p->scb_data->numscbs; i++)
+            {
+              scbp = p->scb_data->scb_array[i];
+              if ((scbp->flags & SCB_ACTIVE) && (scbp != scb))
+              {
+                if (aic7xxx_match_scb(p, scbp, target, channel, lun, i))
+                {
+                  aic7xxx_reset_device(p, target, channel, lun, i);
+                }
+              }
+            }
+            aic7xxx_run_done_queue(p, TRUE);
+            aic7xxx_verbose = old_verbose;
+            /*
+             * Wait until after the for loop to set the busy index since
+             * aic7xxx_reset_device will clear the busy index during its
+             * operation.
+             */
+            aic7xxx_busy_target(p, scb);
+            printk(INFO_LEAD "Device is refusing tagged commands, using "
+              "untagged I/O.\n", p->host_no, channel, target, lun);
+            aic_outb(p, MSG_IDENTIFYFLAG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          /*
+           * As per the draft specs, any device capable of supporting any of
+           * the option values other than 0 are not allowed to reject the
+           * PPR message.  Instead, they must negotiate out what they do
+           * support instead of rejecting our offering or else they cause
+           * a parity error during msg_out phase to signal that they don't
+           * like our settings.
+           */
+          aic_dev->needppr = aic_dev->needppr_copy = 0;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE), aic_dev);
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			       aic_dev);
+          aic_dev->goal.options = aic_dev->dtr_pending = 0;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting PPR messages, falling "
+              "back.\n", p->host_no, channel, target, lun);
+          }
+          if ( aic_dev->goal.width )
+          {
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+            aic_dev->dtr_pending = 1;
+            scb->flags |= SCB_MSGOUT_WDTR;
+          }
+          if ( aic_dev->goal.offset )
+          {
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+            if( !aic_dev->dtr_pending )
+            {
+              aic_dev->dtr_pending = 1;
+              scb->flags |= SCB_MSGOUT_SDTR;
+            }
+          }
+          if ( aic_dev->dtr_pending )
+          {
+            aic_outb(p, HOST_MSG, MSG_OUT);
+            aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+          }
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          /*
+           * note 8bit xfers and clear flag
+           */
+          aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          aic7xxx_set_width(p, target, channel, lun, MSG_EXT_WDTR_BUS_8_BIT,
+            (AHC_TRANS_ACTIVE|AHC_TRANS_GOAL|AHC_TRANS_CUR), aic_dev);
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			       aic_dev);
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting WDTR messages, using "
+              "narrow transfers.\n", p->host_no, channel, target, lun);
+          }
+          aic_dev->needsdtr = aic_dev->needsdtr_copy;
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+         /*
+          * note asynch xfers and clear flag
+          */
+          aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+            (AHC_TRANS_CUR|AHC_TRANS_ACTIVE|AHC_TRANS_GOAL), aic_dev);
+          if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Device is rejecting SDTR messages, using "
+              "async transfers.\n", p->host_no, channel, target, lun);
+          }
+        }
+        else if (aic7xxx_verbose & VERBOSE_SEQINT)
+        {
+          /*
+           * Otherwise, we ignore it.
+           */
+          printk(INFO_LEAD "Received MESSAGE_REJECT for unknown cause.  "
+            "Ignoring.\n", p->host_no, channel, target, lun);
+        }
+      }
+      break;
+
+    case BAD_STATUS:
+      {
+        unsigned char scb_index;
+        struct aic7xxx_hwscb *hscb;
+        Scsi_Cmnd *cmd;
+
+        /* The sequencer will notify us when a command has an error that
+         * would be of interest to the kernel.  This allows us to leave
+         * the sequencer running in the common case of command completes
+         * without error.  The sequencer will have DMA'd the SCB back
+         * up to us, so we can reference the drivers SCB array.
+         *
+         * Set the default return value to 0 indicating not to send
+         * sense.  The sense code will change this if needed and this
+         * reduces code duplication.
+         */
+        aic_outb(p, 0, RETURN_1);
+        scb_index = aic_inb(p, SCB_TAG);
+        if (scb_index > p->scb_data->numscbs)
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%02x, SCB_TAG %d.\n",
+            p->host_no, channel, target, lun, intstat, scb_index);
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        hscb = scb->hscb;
+
+        if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "Invalid SCB during SEQINT 0x%x, scb %d, flags 0x%x,"
+            " cmd 0x%lx.\n", p->host_no, channel, target, lun, intstat,
+            scb_index, scb->flags, (unsigned long) scb->cmd);
+        }
+        else
+        {
+          cmd = scb->cmd;
+	  aic_dev = AIC_DEV(scb->cmd);
+          hscb->target_status = aic_inb(p, SCB_TARGET_STATUS);
+          aic7xxx_status(cmd) = hscb->target_status;
+
+          cmd->result = hscb->target_status;
+
+          switch (status_byte(hscb->target_status))
+          {
+            case GOOD:
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Interrupted for status of GOOD???\n",
+                  p->host_no, CTL_OF_SCB(scb));
+              break;
+
+            case COMMAND_TERMINATED:
+            case CHECK_CONDITION:
+              if ( !(scb->flags & SCB_SENSE) )
+              {
+                /*
+                 * Send a sense command to the requesting target.
+                 * XXX - revisit this and get rid of the memcopys.
+                 */
+                memcpy(scb->sense_cmd, &generic_sense[0],
+                       sizeof(generic_sense));
+
+                scb->sense_cmd[1] = (cmd->device->lun << 5);
+                scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+                scb->sg_list[0].length = 
+                  cpu_to_le32(sizeof(cmd->sense_buffer));
+		scb->sg_list[0].address =
+                        cpu_to_le32(pci_map_single(p->pdev, cmd->sense_buffer,
+                                                   sizeof(cmd->sense_buffer),
+                                                   PCI_DMA_FROMDEVICE));
+
+                /*
+                 * XXX - We should allow disconnection, but can't as it
+                 * might allow overlapped tagged commands.
+                 */
+                /* hscb->control &= DISCENB; */
+                hscb->control = 0;
+                hscb->target_status = 0;
+                hscb->SG_list_pointer = 
+		  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sg_list));
+                hscb->SCSI_cmd_pointer = 
+                  cpu_to_le32(SCB_DMA_ADDR(scb, scb->sense_cmd));
+                hscb->data_count = scb->sg_list[0].length;
+                hscb->data_pointer = scb->sg_list[0].address;
+                hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+                hscb->residual_SG_segment_count = 0;
+                hscb->residual_data_count[0] = 0;
+                hscb->residual_data_count[1] = 0;
+                hscb->residual_data_count[2] = 0;
+
+                scb->sg_count = hscb->SG_segment_count = 1;
+                scb->sg_length = sizeof(cmd->sense_buffer);
+                scb->tag_action = 0;
+                scb->flags |= SCB_SENSE;
+                /*
+                 * Ensure the target is busy since this will be an
+                 * an untagged request.
+                 */
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+                if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+                {
+                  if (scb->flags & SCB_MSGOUT_BITS)
+                    printk(INFO_LEAD "Requesting SENSE with %s\n", p->host_no,
+                           CTL_OF_SCB(scb), (scb->flags & SCB_MSGOUT_SDTR) ?
+                           "SDTR" : "WDTR");
+                  else
+                    printk(INFO_LEAD "Requesting SENSE, no MSG\n", p->host_no,
+                           CTL_OF_SCB(scb));
+                }
+#endif
+                aic7xxx_busy_target(p, scb);
+                aic_outb(p, SEND_SENSE, RETURN_1);
+                aic7xxx_error(cmd) = DID_OK;
+                break;
+              }  /* first time sense, no errors */
+              printk(INFO_LEAD "CHECK_CONDITION on REQUEST_SENSE, returning "
+                     "an error.\n", p->host_no, CTL_OF_SCB(scb));
+              aic7xxx_error(cmd) = DID_ERROR;
+              scb->flags &= ~SCB_SENSE;
+              break;
+
+            case QUEUE_FULL:
+              queue_flag = TRUE;    /* Mark that this is a QUEUE_FULL and */
+            case BUSY:              /* drop through to here */
+            {
+              struct aic7xxx_scb *next_scbp, *prev_scbp;
+              unsigned char active_hscb, next_hscb, prev_hscb, scb_index;
+              /*
+               * We have to look three places for queued commands:
+               *  1: p->waiting_scbs queue
+               *  2: QINFIFO
+               *  3: WAITING_SCBS list on card (for commands that are started
+               *     but haven't yet made it to the device)
+	       *
+	       * Of special note here is that commands on 2 or 3 above will
+	       * have already been marked as active, while commands on 1 will
+	       * not.  The aic7xxx_done() function will want to unmark them
+	       * from active, so any commands we pull off of 1 need to
+	       * up the active count.
+               */
+              next_scbp = p->waiting_scbs.head;
+              while ( next_scbp != NULL )
+              {
+                prev_scbp = next_scbp;
+                next_scbp = next_scbp->q_next;
+                if ( aic7xxx_match_scb(p, prev_scbp, target, channel, lun,
+                     SCB_LIST_NULL) )
+                {
+                  scbq_remove(&p->waiting_scbs, prev_scbp);
+		  scb->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL;
+		  p->activescbs++;
+		  aic_dev->active_cmds++;
+                }
+              }
+              aic7xxx_search_qinfifo(p, target, channel, lun,
+                SCB_LIST_NULL, SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL,
+	       	FALSE, NULL);
+              next_scbp = NULL;
+              active_hscb = aic_inb(p, SCBPTR);
+              prev_hscb = next_hscb = scb_index = SCB_LIST_NULL;
+              next_hscb = aic_inb(p, WAITING_SCBH);
+              while (next_hscb != SCB_LIST_NULL)
+              {
+                aic_outb(p, next_hscb, SCBPTR);
+                scb_index = aic_inb(p, SCB_TAG);
+                if (scb_index < p->scb_data->numscbs)
+                {
+                  next_scbp = p->scb_data->scb_array[scb_index];
+                  if (aic7xxx_match_scb(p, next_scbp, target, channel, lun,
+                      SCB_LIST_NULL) )
+                  {
+		    next_scbp->flags = SCB_QUEUED_FOR_DONE | SCB_QUEUE_FULL;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                    aic_outb(p, 0, SCB_CONTROL);
+                    aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+                    aic7xxx_add_curscb_to_free_list(p);
+                    if (prev_hscb == SCB_LIST_NULL)
+                    {
+                      /* We were first on the list,
+                       * so we kill the selection
+                       * hardware.  Let the sequencer
+                       * re-init the hardware itself
+                       */
+                      aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+                      aic_outb(p, CLRSELTIMEO, CLRSINT1);
+                      aic_outb(p, next_hscb, WAITING_SCBH);
+                    }
+                    else
+                    {
+                      aic_outb(p, prev_hscb, SCBPTR);
+                      aic_outb(p, next_hscb, SCB_NEXT);
+                    }
+                  }
+                  else
+                  {
+                    prev_hscb = next_hscb;
+                    next_hscb = aic_inb(p, SCB_NEXT);
+                  }
+                } /* scb_index >= p->scb_data->numscbs */
+              }
+              aic_outb(p, active_hscb, SCBPTR);
+	      aic7xxx_run_done_queue(p, FALSE);
+                  
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+              if( (aic7xxx_verbose & VERBOSE_MINOR_ERROR) ||
+                  (aic7xxx_verbose > 0xffff) )
+              {
+                if (queue_flag)
+                  printk(INFO_LEAD "Queue full received; queue depth %d, "
+                    "active %d\n", p->host_no, CTL_OF_SCB(scb),
+                    aic_dev->max_q_depth, aic_dev->active_cmds);
+                else
+                  printk(INFO_LEAD "Target busy\n", p->host_no, CTL_OF_SCB(scb));
+              }
+#endif
+              if (queue_flag)
+              {
+		int diff;
+		result = scsi_track_queue_full(cmd->device,
+			       	aic_dev->active_cmds);
+		if ( result < 0 )
+		{
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+                    printk(INFO_LEAD "Tagged Command Queueing disabled.\n",
+			p->host_no, CTL_OF_SCB(scb));
+		  diff = aic_dev->max_q_depth - p->host->cmd_per_lun;
+		  aic_dev->temp_q_depth = 1;
+		  aic_dev->max_q_depth = 1;
+		}
+		else if ( result > 0 )
+		{
+                  if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+                    printk(INFO_LEAD "Queue depth reduced to %d\n", p->host_no,
+                      CTL_OF_SCB(scb), result);
+		  diff = aic_dev->max_q_depth - result;
+		  aic_dev->max_q_depth = result;
+		  /* temp_q_depth could have been dropped to 1 for an untagged
+		   * command that might be coming up */
+		  if(aic_dev->temp_q_depth > result)
+		    aic_dev->temp_q_depth = result;
+		}
+		/* We should free up the no unused SCB entries.  But, that's
+		 * a difficult thing to do because we use a direct indexed
+		 * array, so we can't just take any entries and free them,
+		 * we *have* to free the ones at the end of the array, and
+		 * they very well could be in use right now, which means
+		 * in order to do this right, we have to add a delayed
+		 * freeing mechanism tied into the scb_free() code area.
+		 * We'll add that later.
+		 */
+	      }
+              break;
+            }
+            
+            default:
+              if (aic7xxx_verbose & VERBOSE_SEQINT)
+                printk(INFO_LEAD "Unexpected target status 0x%x.\n", p->host_no,
+                     CTL_OF_SCB(scb), scb->hscb->target_status);
+              if (!aic7xxx_error(cmd))
+              {
+                aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+              }
+              break;
+          }  /* end switch */
+        }  /* end else of */
+      }
+      break;
+
+    case AWAITING_MSG:
+      {
+        unsigned char scb_index, msg_out;
+
+        scb_index = aic_inb(p, SCB_TAG);
+        msg_out = aic_inb(p, MSG_OUT);
+        scb = p->scb_data->scb_array[scb_index];
+	aic_dev = AIC_DEV(scb->cmd);
+        p->msg_index = p->msg_len = 0;
+        /*
+         * This SCB had a MK_MESSAGE set in its control byte informing
+         * the sequencer that we wanted to send a special message to
+         * this target.
+         */
+
+        if ( !(scb->flags & SCB_DEVICE_RESET) &&
+              (msg_out == MSG_IDENTIFYFLAG) &&
+              (scb->hscb->control & TAG_ENB) )
+        {
+          p->msg_buf[p->msg_index++] = scb->tag_action;
+          p->msg_buf[p->msg_index++] = scb->hscb->tag;
+          p->msg_len += 2;
+        }
+
+        if (scb->flags & SCB_DEVICE_RESET)
+        {
+          p->msg_buf[p->msg_index++] = MSG_BUS_DEV_RESET;
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+            printk(INFO_LEAD "Bus device reset mailed.\n",
+                 p->host_no, CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_ABORT)
+        {
+          if (scb->tag_action)
+          {
+            p->msg_buf[p->msg_index++] = MSG_ABORT_TAG;
+          }
+          else
+          {
+            p->msg_buf[p->msg_index++] = MSG_ABORT;
+          }
+          p->msg_len++;
+          if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+            printk(INFO_LEAD "Abort message mailed.\n", p->host_no,
+              CTL_OF_SCB(scb));
+        }
+        else if (scb->flags & SCB_MSGOUT_PPR)
+        {
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending PPR (%d/%d/%d/%d) message.\n",
+                   p->host_no, CTL_OF_SCB(scb),
+                   aic_dev->goal.period,
+                   aic_dev->goal.offset,
+                   aic_dev->goal.width,
+                   aic_dev->goal.options);
+          }
+          aic7xxx_construct_ppr(p, scb);
+        }
+        else if (scb->flags & SCB_MSGOUT_WDTR)
+        {
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending WDTR message.\n", p->host_no,
+                   CTL_OF_SCB(scb));
+          }
+          aic7xxx_construct_wdtr(p, aic_dev->goal.width);
+        }
+        else if (scb->flags & SCB_MSGOUT_SDTR)
+        {
+          unsigned int max_sync, period;
+          unsigned char options = 0;
+          /*
+           * Now that the device is selected, use the bits in SBLKCTL and
+           * SSTAT2 to determine the max sync rate for this device.
+           */
+          if (p->features & AHC_ULTRA2)
+          {
+            if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+                !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+            {
+              max_sync = AHC_SYNCRATE_ULTRA2;
+            }
+            else
+            {
+              max_sync = AHC_SYNCRATE_ULTRA;
+            }
+          }
+          else if (p->features & AHC_ULTRA)
+          {
+            max_sync = AHC_SYNCRATE_ULTRA;
+          }
+          else
+          {
+            max_sync = AHC_SYNCRATE_FAST;
+          }
+          period = aic_dev->goal.period;
+          aic7xxx_find_syncrate(p, &period, max_sync, &options);
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Sending SDTR %d/%d message.\n", p->host_no,
+                   CTL_OF_SCB(scb), period,
+                   aic_dev->goal.offset);
+          }
+          aic7xxx_construct_sdtr(p, period, aic_dev->goal.offset);
+        }
+        else 
+        {
+          panic("aic7xxx: AWAITING_MSG for an SCB that does "
+                "not have a waiting message.\n");
+        }
+        /*
+         * We've set everything up to send our message, now to actually do
+         * so we need to enable reqinit interrupts and let the interrupt
+         * handler do the rest.  We don't want to unpause the sequencer yet
+         * though so we'll return early.  We also have to make sure that
+         * we clear the SEQINT *BEFORE* we set the REQINIT handler active
+         * or else it's possible on VLB cards to lose the first REQINIT
+         * interrupt.  Edge triggered EISA cards could also lose this
+         * interrupt, although PCI and level triggered cards should not
+         * have this problem since they continually interrupt the kernel
+         * until we take care of the situation.
+         */
+        scb->flags |= SCB_MSGOUT_SENT;
+        p->msg_index = 0;
+        p->msg_type = MSG_TYPE_INITIATOR_MSGOUT;
+        p->flags |= AHC_HANDLING_REQINITS;
+        aic_outb(p, aic_inb(p, SIMODE1) | ENREQINIT, SIMODE1);
+        return;
+      }
+      break;
+
+    case DATA_OVERRUN:
+      {
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned char lastphase = aic_inb(p, LASTPHASE);
+        unsigned int i;
+
+        scb = (p->scb_data->scb_array[scb_index]);
+        /*
+         * XXX - What do we really want to do on an overrun?  The
+         *       mid-level SCSI code should handle this, but for now,
+         *       we'll just indicate that the command should retried.
+         *    If we retrieved sense info on this target, then the 
+         *    base SENSE info should have been saved prior to the
+         *    overrun error.  In that case, we return DID_OK and let
+         *    the mid level code pick up on the sense info.  Otherwise
+         *    we return DID_ERROR so the command will get retried.
+         */
+        if ( !(scb->flags & SCB_SENSE) )
+        {
+          printk(WARN_LEAD "Data overrun detected in %s phase, tag %d;\n",
+            p->host_no, CTL_OF_SCB(scb), 
+            (lastphase == P_DATAIN) ? "Data-In" : "Data-Out", scb->hscb->tag);
+          printk(KERN_WARNING "  %s seen Data Phase. Length=%d, NumSGs=%d.\n",
+            (aic_inb(p, SEQ_FLAGS) & DPHASE) ? "Have" : "Haven't",
+            scb->sg_length, scb->sg_count);
+          printk(KERN_WARNING "  Raw SCSI Command: 0x");
+          for (i = 0; i < scb->hscb->SCSI_cmd_length; i++)
+          {
+            printk("%02x ", scb->cmd->cmnd[i]);
+          }
+          printk("\n");
+          if(aic7xxx_verbose > 0xffff)
+          {
+            for (i = 0; i < scb->sg_count; i++)
+            {
+              printk(KERN_WARNING "     sg[%d] - Addr 0x%x : Length %d\n",
+                 i, 
+                 le32_to_cpu(scb->sg_list[i].address),
+                 le32_to_cpu(scb->sg_list[i].length) );
+            }
+          }
+          aic7xxx_error(scb->cmd) = DID_ERROR;
+        }
+        else
+          printk(INFO_LEAD "Data Overrun during SEND_SENSE operation.\n",
+            p->host_no, CTL_OF_SCB(scb));
+      }
+      break;
+
+    case WIDE_RESIDUE:
+      {
+        unsigned char resid_sgcnt, index;
+        unsigned char scb_index = aic_inb(p, SCB_TAG);
+        unsigned int cur_addr, resid_dcnt;
+        unsigned int native_addr, native_length, sg_addr;
+        int i;
+
+        if(scb_index > p->scb_data->numscbs)
+        {
+          printk(WARN_LEAD "invalid scb_index during WIDE_RESIDUE.\n",
+            p->host_no, -1, -1, -1);
+          /*
+           * XXX: Add error handling here
+           */
+          break;
+        }
+        scb = p->scb_data->scb_array[scb_index];
+        if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+        {
+          printk(WARN_LEAD "invalid scb during WIDE_RESIDUE flags:0x%x "
+                 "scb->cmd:0x%lx\n", p->host_no, CTL_OF_SCB(scb),
+                 scb->flags, (unsigned long)scb->cmd);
+          break;
+        }
+        if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+          printk(INFO_LEAD "Got WIDE_RESIDUE message, patching up data "
+                 "pointer.\n", p->host_no, CTL_OF_SCB(scb));
+
+        /*
+         * We have a valid scb to use on this WIDE_RESIDUE message, so
+         * we need to walk the sg list looking for this particular sg
+         * segment, then see if we happen to be at the very beginning of
+         * the segment.  If we are, then we have to back things up to
+         * the previous segment.  If not, then we simply need to remove
+         * one byte from this segments address and add one to the byte
+         * count.
+         */
+        cur_addr = aic_inb(p, SHADDR) | (aic_inb(p, SHADDR + 1) << 8) |
+          (aic_inb(p, SHADDR + 2) << 16) | (aic_inb(p, SHADDR + 3) << 24);
+        sg_addr = aic_inb(p, SG_COUNT + 1) | (aic_inb(p, SG_COUNT + 2) << 8) |
+          (aic_inb(p, SG_COUNT + 3) << 16) | (aic_inb(p, SG_COUNT + 4) << 24);
+        resid_sgcnt = aic_inb(p, SCB_RESID_SGCNT);
+        resid_dcnt = aic_inb(p, SCB_RESID_DCNT) |
+          (aic_inb(p, SCB_RESID_DCNT + 1) << 8) |
+          (aic_inb(p, SCB_RESID_DCNT + 2) << 16);
+        index = scb->sg_count - ((resid_sgcnt) ? resid_sgcnt : 1);
+        native_addr = le32_to_cpu(scb->sg_list[index].address);
+        native_length = le32_to_cpu(scb->sg_list[index].length);
+        /*
+         * If resid_dcnt == native_length, then we just loaded this SG
+         * segment and we need to back it up one...
+         */
+        if(resid_dcnt == native_length)
+        {
+          if(index == 0)
+          {
+            /*
+             * Oops, this isn't right, we can't back up to before the
+             * beginning.  This must be a bogus message, ignore it.
+             */
+            break;
+          }
+          resid_dcnt = 1;
+          resid_sgcnt += 1;
+          native_addr = le32_to_cpu(scb->sg_list[index - 1].address);
+          native_length = le32_to_cpu(scb->sg_list[index - 1].length);
+          cur_addr = native_addr + (native_length - 1);
+          sg_addr -= sizeof(struct hw_scatterlist);
+        }
+        else
+        {
+          /*
+           * resid_dcnt != native_length, so we are in the middle of a SG
+           * element.  Back it up one byte and leave the rest alone.
+           */
+          resid_dcnt += 1;
+          cur_addr -= 1;
+        }
+        
+        /*
+         * Output the new addresses and counts to the right places on the
+         * card.
+         */
+        aic_outb(p, resid_sgcnt, SG_COUNT);
+        aic_outb(p, resid_sgcnt, SCB_RESID_SGCNT);
+        aic_outb(p, sg_addr & 0xff, SG_COUNT + 1);
+        aic_outb(p, (sg_addr >> 8) & 0xff, SG_COUNT + 2);
+        aic_outb(p, (sg_addr >> 16) & 0xff, SG_COUNT + 3);
+        aic_outb(p, (sg_addr >> 24) & 0xff, SG_COUNT + 4);
+        aic_outb(p, resid_dcnt & 0xff, SCB_RESID_DCNT);
+        aic_outb(p, (resid_dcnt >> 8) & 0xff, SCB_RESID_DCNT + 1);
+        aic_outb(p, (resid_dcnt >> 16) & 0xff, SCB_RESID_DCNT + 2);
+
+        /*
+         * The sequencer actually wants to find the new address
+         * in the SHADDR register set.  On the Ultra2 and later controllers
+         * this register set is readonly.  In order to get the right number
+         * into the register, you actually have to enter it in HADDR and then
+         * use the PRELOADEN bit of DFCNTRL to drop it through from the
+         * HADDR register to the SHADDR register.  On non-Ultra2 controllers,
+         * we simply write it direct.
+         */
+        if(p->features & AHC_ULTRA2)
+        {
+          /*
+           * We might as well be accurate and drop both the resid_dcnt and
+           * cur_addr into HCNT and HADDR and have both of them drop
+           * through to the shadow layer together.
+           */
+          aic_outb(p, resid_dcnt & 0xff, HCNT);
+          aic_outb(p, (resid_dcnt >> 8) & 0xff, HCNT + 1);
+          aic_outb(p, (resid_dcnt >> 16) & 0xff, HCNT + 2);
+          aic_outb(p, cur_addr & 0xff, HADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, HADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, HADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, HADDR + 3);
+          aic_outb(p, aic_inb(p, DMAPARAMS) | PRELOADEN, DFCNTRL);
+          udelay(1);
+          aic_outb(p, aic_inb(p, DMAPARAMS) & ~(SCSIEN|HDMAEN), DFCNTRL);
+          i=0;
+          while(((aic_inb(p, DFCNTRL) & (SCSIEN|HDMAEN)) != 0) && (i++ < 1000))
+          {
+            udelay(1);
+          }
+        }
+        else
+        {
+          aic_outb(p, cur_addr & 0xff, SHADDR);
+          aic_outb(p, (cur_addr >> 8) & 0xff, SHADDR + 1);
+          aic_outb(p, (cur_addr >> 16) & 0xff, SHADDR + 2);
+          aic_outb(p, (cur_addr >> 24) & 0xff, SHADDR + 3);
+        }
+      }
+      break;
+
+    case SEQ_SG_FIXUP:
+    {
+      unsigned char scb_index, tmp;
+      int sg_addr, sg_length;
+
+      scb_index = aic_inb(p, SCB_TAG);
+
+      if(scb_index > p->scb_data->numscbs)
+      {
+        printk(WARN_LEAD "invalid scb_index during SEQ_SG_FIXUP.\n",
+          p->host_no, -1, -1, -1);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, -1, -1, -1,
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, -1, -1, -1, aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        /*
+         * XXX: Add error handling here
+         */
+        break;
+      }
+      scb = p->scb_data->scb_array[scb_index];
+      if(!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+      {
+        printk(WARN_LEAD "invalid scb during SEQ_SG_FIXUP flags:0x%x "
+               "scb->cmd:0x%p\n", p->host_no, CTL_OF_SCB(scb),
+               scb->flags, scb->cmd);
+        printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+           "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+           aic_inb(p, SCSISIGI),
+           aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+           aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+        printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n",
+           p->host_no, CTL_OF_SCB(scb), aic_inb(p, SG_CACHEPTR),
+           aic_inb(p, SSTAT2), aic_inb(p, STCNT + 2) << 16 |
+           aic_inb(p, STCNT + 1) << 8 | aic_inb(p, STCNT));
+        break;
+      }
+      if(aic7xxx_verbose & VERBOSE_MINOR_ERROR)
+        printk(INFO_LEAD "Fixing up SG address for sequencer.\n", p->host_no,
+               CTL_OF_SCB(scb));
+      /*
+       * Advance the SG pointer to the next element in the list
+       */
+      tmp = aic_inb(p, SG_NEXT);
+      tmp += SG_SIZEOF;
+      aic_outb(p, tmp, SG_NEXT);
+      if( tmp < SG_SIZEOF )
+        aic_outb(p, aic_inb(p, SG_NEXT + 1) + 1, SG_NEXT + 1);
+      tmp = aic_inb(p, SG_COUNT) - 1;
+      aic_outb(p, tmp, SG_COUNT);
+      sg_addr = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].address);
+      sg_length = le32_to_cpu(scb->sg_list[scb->sg_count - tmp].length);
+      /*
+       * Now stuff the element we just advanced past down onto the
+       * card so it can be stored in the residual area.
+       */
+      aic_outb(p, sg_addr & 0xff, HADDR);
+      aic_outb(p, (sg_addr >> 8) & 0xff, HADDR + 1);
+      aic_outb(p, (sg_addr >> 16) & 0xff, HADDR + 2);
+      aic_outb(p, (sg_addr >> 24) & 0xff, HADDR + 3);
+      aic_outb(p, sg_length & 0xff, HCNT);
+      aic_outb(p, (sg_length >> 8) & 0xff, HCNT + 1);
+      aic_outb(p, (sg_length >> 16) & 0xff, HCNT + 2);
+      aic_outb(p, (tmp << 2) | ((tmp == 1) ? LAST_SEG : 0), SG_CACHEPTR);
+      aic_outb(p, aic_inb(p, DMAPARAMS), DFCNTRL);
+      while(aic_inb(p, SSTAT0) & SDONE) udelay(1);
+      while(aic_inb(p, DFCNTRL) & (HDMAEN|SCSIEN)) aic_outb(p, 0, DFCNTRL);
+    }
+    break;
+
+#ifdef AIC7XXX_NOT_YET 
+    case TRACEPOINT2:
+      {
+        printk(INFO_LEAD "Tracepoint #2 reached.\n", p->host_no,
+               channel, target, lun);
+      }
+      break;
+
+    /* XXX Fill these in later */
+    case MSG_BUFFER_BUSY:
+      printk("aic7xxx: Message buffer busy.\n");
+      break;
+    case MSGIN_PHASEMIS:
+      printk("aic7xxx: Message-in phasemis.\n");
+      break;
+#endif
+
+    default:                   /* unknown */
+      printk(WARN_LEAD "Unknown SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+             p->host_no, channel, target, lun, intstat,
+             aic_inb(p, SCSISIGI));
+      break;
+  }
+
+  /*
+   * Clear the sequencer interrupt and unpause the sequencer.
+   */
+  unpause_sequencer(p, /* unpause always */ TRUE);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_parse_msg
+ *
+ * Description:
+ *   Parses incoming messages into actions on behalf of
+ *   aic7xxx_handle_reqinit
+ *_F*************************************************************************/
+static int
+aic7xxx_parse_msg(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  int reject, reply, done;
+  unsigned char target_scsirate, tindex;
+  unsigned short target_mask;
+  unsigned char target, channel, lun;
+  unsigned char bus_width, new_bus_width;
+  unsigned char trans_options, new_trans_options;
+  unsigned int period, new_period, offset, new_offset, maxsync;
+  struct aic7xxx_syncrate *syncrate;
+  struct aic_dev_data *aic_dev;
+
+  target = scb->cmd->device->id;
+  channel = scb->cmd->device->channel;
+  lun = scb->cmd->device->lun;
+  reply = reject = done = FALSE;
+  tindex = TARGET_INDEX(scb->cmd);
+  aic_dev = AIC_DEV(scb->cmd);
+  target_scsirate = aic_inb(p, TARG_SCSIRATE + tindex);
+  target_mask = (0x01 << tindex);
+
+  /*
+   * Parse as much of the message as is available,
+   * rejecting it if we don't support it.  When
+   * the entire message is available and has been
+   * handled, return TRUE indicating that we have
+   * parsed an entire message.
+   */
+
+  if (p->msg_buf[0] != MSG_EXTENDED)
+  {
+    reject = TRUE;
+  }
+
+  /*
+   * Even if we are an Ultra3 card, don't allow Ultra3 sync rates when
+   * using the SDTR messages.  We need the PPR messages to enable the
+   * higher speeds that include things like Dual Edge clocking.
+   */
+  if (p->features & AHC_ULTRA2)
+  {
+    if ( (aic_inb(p, SBLKCTL) & ENAB40) &&
+         !(aic_inb(p, SSTAT2) & EXP_ACTIVE) )
+    {
+      if (p->features & AHC_ULTRA3)
+        maxsync = AHC_SYNCRATE_ULTRA3;
+      else
+        maxsync = AHC_SYNCRATE_ULTRA2;
+    }
+    else
+    {
+      maxsync = AHC_SYNCRATE_ULTRA;
+    }
+  }
+  else if (p->features & AHC_ULTRA)
+  {
+    maxsync = AHC_SYNCRATE_ULTRA;
+  }
+  else
+  {
+    maxsync = AHC_SYNCRATE_FAST;
+  }
+
+  /*
+   * Just accept the length byte outright and perform
+   * more checking once we know the message type.
+   */
+
+  if ( !reject && (p->msg_len > 2) )
+  {
+    switch(p->msg_buf[2])
+    {
+      case MSG_EXT_SDTR:
+      {
+        
+        if (p->msg_buf[1] != MSG_EXT_SDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_SDTR_LEN + 2))
+        {
+          break;
+        }
+
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[4];
+        trans_options = new_trans_options = 0;
+        bus_width = new_bus_width = target_scsirate & WIDEXFER;
+
+        /*
+         * If our current max syncrate is in the Ultra3 range, bump it back
+         * down to Ultra2 since we can't negotiate DT transfers using SDTR
+         */
+        if(maxsync == AHC_SYNCRATE_ULTRA3)
+          maxsync = AHC_SYNCRATE_ULTRA2;
+
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_SDTR) )
+        {
+          if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
+          {
+            /*
+             * We shouldn't get here unless this is a narrow drive, wide
+             * devices should trigger this same section of code in the WDTR
+             * handler first instead.
+             */
+            aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT;
+            aic_dev->goal.options = 0;
+            if(p->user[tindex].offset)
+            {
+              aic_dev->needsdtr_copy = 1;
+              aic_dev->goal.period = max_t(unsigned char, 10,p->user[tindex].period);
+              if(p->features & AHC_ULTRA2)
+              {
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+              }
+              else
+              {
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
+              }
+            }
+            else
+            {
+              aic_dev->needsdtr_copy = 0;
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
+            }
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if (aic_dev->needsdtr_copy == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a SDTR with this target (for whatever reason),
+             * so reject this incoming SDTR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive SDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          /*
+           * Validate the values the device passed to us against our SEEPROM
+           * settings.  We don't have to do this if we aren't replying since
+           * the device isn't allowed to send values greater than the ones
+           * we first sent to it.
+           */
+          new_period = max_t(unsigned int, period, aic_dev->goal.period);
+          new_offset = min_t(unsigned int, offset, aic_dev->goal.offset);
+        }
+ 
+        /*
+         * Use our new_period, new_offset, bus_width, and card options
+         * to determine the actual syncrate settings
+         */
+        syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                         &trans_options);
+        aic7xxx_validate_offset(p, syncrate, &new_offset, bus_width);
+
+        /*
+         * Did we drop to async?  If so, send a reply regardless of whether
+         * or not we initiated this negotiation.
+         */
+        if ((new_offset == 0) && (new_offset != offset))
+        {
+          aic_dev->needsdtr_copy = 0;
+          reply = TRUE;
+        }
+        
+        /*
+         * Did we start this, if not, or if we went too low and had to
+         * go async, then send an SDTR back to the target
+         */
+        if(reply)
+        {
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			       aic_dev);
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_SDTR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        else
+        {
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
+          aic_dev->needsdtr = 0;
+        }
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_WDTR:
+      {
+          
+        if (p->msg_buf[1] != MSG_EXT_WDTR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_WDTR_LEN + 2))
+        {
+          break;
+        }
+
+        bus_width = new_bus_width = p->msg_buf[3];
+
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR)) ==
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_WDTR) )
+        {
+          switch(bus_width)
+          {
+            default:
+            {
+              reject = TRUE;
+              if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                   ((aic_dev->flags & DEVICE_PRINT_DTR) ||
+                    (aic7xxx_verbose > 0xffff)) )
+              {
+                printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                  p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+              }
+            } /* We fall through on purpose */
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              aic_dev->goal.width = MSG_EXT_WDTR_BUS_8_BIT;
+              aic_dev->needwdtr_copy &= ~target_mask;
+              break;
+            }
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              break;
+            }
+          }
+          aic_dev->needwdtr = 0;
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
+        }
+        else
+        {
+          if ( !(aic_dev->flags & DEVICE_DTR_SCANNED) )
+          {
+            /* 
+             * Well, we now know the WDTR and SYNC caps of this device since
+             * it contacted us first, mark it as such and copy the user stuff
+             * over to the goal stuff.
+             */
+            if( (p->features & AHC_WIDE) && p->user[tindex].width )
+            {
+              aic_dev->goal.width = MSG_EXT_WDTR_BUS_16_BIT;
+              aic_dev->needwdtr_copy = 1;
+            }
+            
+            /*
+             * Devices that support DT transfers don't start WDTR requests
+             */
+            aic_dev->goal.options = 0;
+
+            if(p->user[tindex].offset)
+            {
+              aic_dev->needsdtr_copy = 1;
+              aic_dev->goal.period = max_t(unsigned char, 10, p->user[tindex].period);
+              if(p->features & AHC_ULTRA2)
+              {
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( aic_dev->goal.width )
+              {
+                aic_dev->goal.offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
+              }
+            } else {
+              aic_dev->needsdtr_copy = 0;
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
+            }
+            
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if (aic_dev->needwdtr_copy == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a WDTR with this target (for whatever reason),
+             * so reject this incoming WDTR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive WDTR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+          switch(bus_width)
+          {
+            case MSG_EXT_WDTR_BUS_16_BIT:
+            {
+              if ( (p->features & AHC_WIDE) &&
+                   (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) )
+              {
+                new_bus_width = MSG_EXT_WDTR_BUS_16_BIT;
+                break;
+              }
+            } /* Fall through if we aren't a wide card */
+            default:
+            case MSG_EXT_WDTR_BUS_8_BIT:
+            {
+              aic_dev->needwdtr_copy = 0;
+              new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+              break;
+            }
+          }
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_WDTR;
+          aic_dev->needwdtr = 0;
+          if(aic_dev->dtr_pending == 0)
+          {
+            /* there is no other command with SCB_DTR_SCB already set that will
+             * trigger the release of the dtr_pending bit.  Both set the bit
+             * and set scb->flags |= SCB_DTR_SCB
+             */
+            aic_dev->dtr_pending = 1;
+            scb->flags |= SCB_DTR_SCB;
+          }
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                          AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			  aic_dev);
+        }
+        
+        /*
+         * By virtue of the SCSI spec, a WDTR message negates any existing
+         * SDTR negotiations.  So, even if needsdtr isn't marked for this
+         * device, we still have to do a new SDTR message if the device
+         * supports SDTR at all.  Therefore, we check needsdtr_copy instead
+         * of needstr.
+         */
+        aic7xxx_set_syncrate(p, NULL, target, channel, 0, 0, 0,
+                             AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			     aic_dev);
+        aic_dev->needsdtr = aic_dev->needsdtr_copy;
+        done = TRUE;
+        break;
+      }
+      case MSG_EXT_PPR:
+      {
+        
+        if (p->msg_buf[1] != MSG_EXT_PPR_LEN)
+        {
+          reject = TRUE;
+          break;
+        }
+
+        if (p->msg_len < (MSG_EXT_PPR_LEN + 2))
+        {
+          break;
+        }
+
+        period = new_period = p->msg_buf[3];
+        offset = new_offset = p->msg_buf[5];
+        bus_width = new_bus_width = p->msg_buf[6];
+        trans_options = new_trans_options = p->msg_buf[7] & 0xf;
+
+        if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        {
+          printk(INFO_LEAD "Parsing PPR message (%d/%d/%d/%d)\n",
+                 p->host_no, CTL_OF_SCB(scb), period, offset, bus_width,
+                 trans_options);
+        }
+
+        /*
+         * We might have a device that is starting negotiation with us
+         * before we can start up negotiation with it....be prepared to
+         * have a device ask for a higher speed then we want to give it
+         * in that case
+         */
+        if ( (scb->flags & (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR)) !=
+             (SCB_MSGOUT_SENT|SCB_MSGOUT_PPR) )
+        { 
+          /* Have we scanned the device yet? */
+          if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
+          {
+            /* The device is electing to use PPR messages, so we will too until
+             * we know better */
+            aic_dev->needppr = aic_dev->needppr_copy = 1;
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+          
+            /* We know the device is SCSI-3 compliant due to PPR */
+            aic_dev->flags |= DEVICE_SCSI_3;
+          
+            /*
+             * Not only is the device starting this up, but it also hasn't
+             * been scanned yet, so this would likely be our TUR or our
+             * INQUIRY command at scan time, so we need to use the
+             * settings from the SEEPROM if they existed.  Of course, even
+             * if we didn't find a SEEPROM, we stuffed default values into
+             * the user settings anyway, so use those in all cases.
+             */
+            aic_dev->goal.width = p->user[tindex].width;
+            if(p->user[tindex].offset)
+            {
+              aic_dev->goal.period = p->user[tindex].period;
+              aic_dev->goal.options = p->user[tindex].options;
+              if(p->features & AHC_ULTRA2)
+              {
+                aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+              }
+              else if( aic_dev->goal.width &&
+                       (bus_width == MSG_EXT_WDTR_BUS_16_BIT) &&
+                       p->features & AHC_WIDE )
+              {
+                aic_dev->goal.offset = MAX_OFFSET_16BIT;
+              }
+              else
+              {
+                aic_dev->goal.offset = MAX_OFFSET_8BIT;
+              }
+            }
+            else
+            {
+              aic_dev->goal.period = 255;
+              aic_dev->goal.offset = 0;
+              aic_dev->goal.options = 0;
+            }
+            aic_dev->flags |= DEVICE_DTR_SCANNED | DEVICE_PRINT_DTR;
+          }
+          else if (aic_dev->needppr_copy == 0)
+          {
+            /*
+             * This is a preemptive message from the target, we've already
+             * scanned this target and set our options for it, and we
+             * don't need a PPR with this target (for whatever reason),
+             * so reject this incoming PPR
+             */
+            reject = TRUE;
+            break;
+          }
+
+          /* The device is sending this message first and we have to reply */
+          reply = TRUE;
+          
+          if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+          {
+            printk(INFO_LEAD "Received pre-emptive PPR message from "
+                   "target.\n", p->host_no, CTL_OF_SCB(scb));
+          }
+
+        }
+
+        switch(bus_width)
+        {
+          case MSG_EXT_WDTR_BUS_16_BIT:
+          {
+            if ( (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT) &&
+			    p->features & AHC_WIDE)
+            {
+              break;
+            }
+          }
+          default:
+          {
+            if ( (aic7xxx_verbose & VERBOSE_NEGOTIATION2) &&
+                 ((aic_dev->flags & DEVICE_PRINT_DTR) ||
+                  (aic7xxx_verbose > 0xffff)) )
+            {
+              reply = TRUE;
+              printk(INFO_LEAD "Requesting %d bit transfers, rejecting.\n",
+                p->host_no, CTL_OF_SCB(scb), 8 * (0x01 << bus_width));
+            }
+          } /* We fall through on purpose */
+          case MSG_EXT_WDTR_BUS_8_BIT:
+          {
+            /*
+             * According to the spec, if we aren't wide, we also can't be
+             * Dual Edge so clear the options byte
+             */
+            new_trans_options = 0;
+            new_bus_width = MSG_EXT_WDTR_BUS_8_BIT;
+            break;
+          }
+        }
+
+        if(reply)
+        {
+          /* when sending a reply, make sure that the goal settings are
+           * updated along with current and active since the code that
+           * will actually build the message for the sequencer uses the
+           * goal settings as its guidelines.
+           */
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			    aic_dev);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_GOAL|AHC_TRANS_ACTIVE|AHC_TRANS_CUR,
+			       aic_dev);
+        }
+        else
+        {
+          aic7xxx_set_width(p, target, channel, lun, new_bus_width,
+                            AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
+          syncrate = aic7xxx_find_syncrate(p, &new_period, maxsync,
+                                           &new_trans_options);
+          aic7xxx_validate_offset(p, syncrate, &new_offset, new_bus_width);
+          aic7xxx_set_syncrate(p, syncrate, target, channel, new_period,
+                               new_offset, new_trans_options,
+                               AHC_TRANS_ACTIVE|AHC_TRANS_CUR, aic_dev);
+        }
+
+        /*
+         * As it turns out, if we don't *have* to have PPR messages, then
+         * configure ourselves not to use them since that makes some
+         * external drive chassis work (those chassis can't parse PPR
+         * messages and they mangle the SCSI bus until you send a WDTR
+         * and SDTR that they can understand).
+         */
+        if(new_trans_options == 0)
+        {
+          aic_dev->needppr = aic_dev->needppr_copy = 0;
+          if(new_offset)
+          {
+            aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+          }
+          if (new_bus_width)
+          {
+            aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+          }
+        }
+
+        if((new_offset == 0) && (offset != 0))
+        {
+          /*
+           * Oops, the syncrate went to low for this card and we fell off
+           * to async (should never happen with a device that uses PPR
+           * messages, but have to be complete)
+           */
+          reply = TRUE;
+        }
+
+        if(reply)
+        {
+          scb->flags &= ~SCB_MSGOUT_BITS;
+          scb->flags |= SCB_MSGOUT_PPR;
+          aic_outb(p, HOST_MSG, MSG_OUT);
+          aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+        }
+        else
+        {
+          aic_dev->needppr = 0;
+        }
+        done = TRUE;
+        break;
+      }
+      default:
+      {
+        reject = TRUE;
+        break;
+      }
+    } /* end of switch(p->msg_type) */
+  } /* end of if (!reject && (p->msg_len > 2)) */
+
+  if (!reply && reject)
+  {
+    aic_outb(p, MSG_MESSAGE_REJECT, MSG_OUT);
+    aic_outb(p, aic_inb(p, SCSISIGO) | ATNO, SCSISIGO);
+    done = TRUE;
+  }
+  return(done);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_reqinit
+ *
+ * Description:
+ *   Interrupt handler for REQINIT interrupts (used to transfer messages to
+ *    and from devices).
+ *_F*************************************************************************/
+static void
+aic7xxx_handle_reqinit(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
+{
+  unsigned char lastbyte;
+  unsigned char phasemis;
+  int done = FALSE;
+
+  switch(p->msg_type)
+  {
+    case MSG_TYPE_INITIATOR_MSGOUT:
+      {
+        if (p->msg_len == 0)
+          panic("aic7xxx: REQINIT with no active message!\n");
+
+        lastbyte = (p->msg_index == (p->msg_len - 1));
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK) != P_MESGOUT;
+
+        if (lastbyte || phasemis)
+        {
+          /* Time to end the message */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          /*
+           * NOTE-TO-MYSELF: If you clear the REQINIT after you
+           * disable REQINITs, then cases of REJECT_MSG stop working
+           * and hang the bus
+           */
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+
+          if (phasemis == 0)
+          {
+            aic_outb(p, p->msg_buf[p->msg_index], SINDEX);
+            aic_outb(p, 0, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "Completed sending of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
+          }
+          else
+          {
+            aic_outb(p, MSGOUT_PHASEMIS, RETURN_1);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+            if (aic7xxx_verbose > 0xffff)
+              printk(INFO_LEAD "PHASEMIS while sending REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+#endif
+          }
+          unpause_sequencer(p, TRUE);
+        }
+        else
+        {
+          /*
+           * Present the byte on the bus (clearing REQINIT) but don't
+           * unpause the sequencer.
+           */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_outb(p,  p->msg_buf[p->msg_index++], SCSIDATL);
+        }
+        break;
+      }
+    case MSG_TYPE_INITIATOR_MSGIN:
+      {
+        phasemis = ( aic_inb(p, SCSISIGI) & PHASE_MASK ) != P_MESGIN;
+
+        if (phasemis == 0)
+        {
+          p->msg_len++;
+          /* Pull the byte in without acking it */
+          p->msg_buf[p->msg_index] = aic_inb(p, SCSIBUSL);
+          done = aic7xxx_parse_msg(p, scb);
+          /* Ack the byte */
+          aic_outb(p, CLRREQINIT, CLRSINT1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          aic_inb(p, SCSIDATL);
+          p->msg_index++;
+        }
+        if (phasemis || done)
+        {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+          if (aic7xxx_verbose > 0xffff)
+          {
+            if (phasemis)
+              printk(INFO_LEAD "PHASEMIS while receiving REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+            else
+              printk(INFO_LEAD "Completed receipt of REQINIT message.\n",
+                     p->host_no, CTL_OF_SCB(scb));
+          }
+#endif
+          /* Time to end our message session */
+          p->msg_len = 0;
+          p->msg_type = MSG_TYPE_NONE;
+          aic_outb(p, aic_inb(p, SIMODE1) & ~ENREQINIT, SIMODE1);
+          aic_outb(p, CLRSCSIINT, CLRINT);
+          p->flags &= ~AHC_HANDLING_REQINITS;
+          unpause_sequencer(p, TRUE);
+        }
+        break;
+      }
+    default:
+      {
+        panic("aic7xxx: Unknown REQINIT message type.\n");
+        break;
+      }
+  } /* End of switch(p->msg_type) */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_scsiint
+ *
+ * Description:
+ *   Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+  unsigned char scb_index;
+  unsigned char status;
+  struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
+
+  scb_index = aic_inb(p, SCB_TAG);
+  status = aic_inb(p, SSTAT1);
+
+  if (scb_index < p->scb_data->numscbs)
+  {
+    scb = p->scb_data->scb_array[scb_index];
+    if ((scb->flags & SCB_ACTIVE) == 0)
+    {
+      scb = NULL;
+    }
+  }
+  else
+  {
+    scb = NULL;
+  }
+
+
+  if ((status & SCSIRSTI) != 0)
+  {
+    int channel;
+
+    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
+
+    if (aic7xxx_verbose & VERBOSE_RESET)
+      printk(WARN_LEAD "Someone else reset the channel!!\n",
+           p->host_no, channel, -1, -1);
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
+    /*
+     * Go through and abort all commands for the channel, but do not
+     * reset the channel again.
+     */
+    aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+    aic7xxx_run_done_queue(p, TRUE);
+    scb = NULL;
+  }
+  else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
+  {
+    /*
+     * First look at what phase we were last in.  If it's message-out,
+     * chances are pretty good that the bus free was in response to
+     * one of our abort requests.
+     */
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char saved_tcl = aic_inb(p, SAVED_TCL);
+    unsigned char target = (saved_tcl >> 4) & 0x0F;
+    int channel;
+    int printerror = TRUE;
+
+    if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+      channel = (aic_inb(p, SBLKCTL) & SELBUSB) >> 3;
+    else
+      channel = 0;
+
+    aic_outb(p, aic_inb(p, SCSISEQ) & (ENSELI|ENRSELI|ENAUTOATNP),
+             SCSISEQ);
+    if (lastphase == P_MESGOUT)
+    {
+      unsigned char message;
+
+      message = aic_inb(p, SINDEX);
+
+      if ((message == MSG_ABORT) || (message == MSG_ABORT_TAG))
+      {
+        if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+          printk(INFO_LEAD "SCB %d abort delivered.\n", p->host_no,
+            CTL_OF_SCB(scb), scb->hscb->tag);
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS,
+                (message == MSG_ABORT) ? SCB_LIST_NULL : scb->hscb->tag );
+        aic7xxx_run_done_queue(p, TRUE);
+        scb = NULL;
+        printerror = 0;
+      }
+      else if (message == MSG_BUS_DEV_RESET)
+      {
+        aic7xxx_handle_device_reset(p, target, channel);
+        scb = NULL;
+        printerror = 0;
+      }
+    }
+    if ( (scb != NULL) && (scb->flags & SCB_DTR_SCB) ) 
+    {
+      /*
+       * Hmmm...error during a negotiation command.  Either we have a
+       * borken bus, or the device doesn't like our negotiation message.
+       * Since we check the INQUIRY data of a device before sending it
+       * negotiation messages, assume the bus is borken for whatever
+       * reason.  Complete the command.
+       */
+      printerror = 0;
+      aic7xxx_reset_device(p, target, channel, ALL_LUNS, scb->hscb->tag);
+      aic7xxx_run_done_queue(p, TRUE);
+      scb = NULL;
+    }
+    if (printerror != 0)
+    {
+      if (scb != NULL)
+      {
+        unsigned char tag;
+
+        if ((scb->hscb->control & TAG_ENB) != 0)
+        {
+          tag = scb->hscb->tag;
+        }
+        else
+        {
+          tag = SCB_LIST_NULL;
+        }
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, tag);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      else
+      {
+        aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+        aic7xxx_run_done_queue(p, TRUE);
+      }
+      printk(INFO_LEAD "Unexpected busfree, LASTPHASE = 0x%x, "
+             "SEQADDR = 0x%x\n", p->host_no, channel, target, -1, lastphase,
+             (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+      scb = NULL;
+    }
+    aic_outb(p, MSG_NOOP, MSG_OUT);
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENBUSFREE|ENREQINIT),
+      SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
+  }
+  else if ((status & SELTO) != 0)
+  {
+    unsigned char scbptr;
+    unsigned char nextscb;
+    Scsi_Cmnd *cmd;
+
+    scbptr = aic_inb(p, WAITING_SCBH);
+    if (scbptr > p->scb_data->maxhscbs)
+    {
+      /*
+       * I'm still trying to track down exactly how this happens, but until
+       * I find it, this code will make sure we aren't passing bogus values
+       * into the SCBPTR register, even if that register will just wrap
+       * things around, we still don't like having out of range variables.
+       *
+       * NOTE: Don't check the aic7xxx_verbose variable, I want this message
+       * to always be displayed.
+       */
+      printk(INFO_LEAD "Invalid WAITING_SCBH value %d, improvising.\n",
+             p->host_no, -1, -1, -1, scbptr);
+      if (p->scb_data->maxhscbs > 4)
+        scbptr &= (p->scb_data->maxhscbs - 1);
+      else
+        scbptr &= 0x03;
+    }
+    aic_outb(p, scbptr, SCBPTR);
+    scb_index = aic_inb(p, SCB_TAG);
+
+    scb = NULL;
+    if (scb_index < p->scb_data->numscbs)
+    {
+      scb = p->scb_data->scb_array[scb_index];
+      if ((scb->flags & SCB_ACTIVE) == 0)
+      {
+        scb = NULL;
+      }
+    }
+    if (scb == NULL)
+    {
+      printk(WARN_LEAD "Referenced SCB %d not valid during SELTO.\n",
+             p->host_no, -1, -1, -1, scb_index);
+      printk(KERN_WARNING "        SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+             "SSTAT1 = 0x%x\n", aic_inb(p, SCSISEQ),
+             aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+             aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+      if (aic7xxx_panic_on_abort)
+        aic7xxx_panic_abort(p, NULL);
+    }
+    else
+    {
+      cmd = scb->cmd;
+      cmd->result = (DID_TIME_OUT << 16);
+
+      /*
+       * Clear out this hardware SCB
+       */
+      aic_outb(p, 0, SCB_CONTROL);
+
+      /*
+       * Clear out a few values in the card that are in an undetermined
+       * state.
+       */
+      aic_outb(p, MSG_NOOP, MSG_OUT);
+
+      /*
+       * Shift the waiting for selection queue forward
+       */
+      nextscb = aic_inb(p, SCB_NEXT);
+      aic_outb(p, nextscb, WAITING_SCBH);
+
+      /*
+       * Put this SCB back on the free list.
+       */
+      aic7xxx_add_curscb_to_free_list(p);
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+      if (aic7xxx_verbose > 0xffff)
+        printk(INFO_LEAD "Selection Timeout.\n", p->host_no, CTL_OF_SCB(scb));
+#endif
+      if (scb->flags & SCB_QUEUED_ABORT)
+      {
+        /*
+         * We know that this particular SCB had to be the queued abort since
+         * the disconnected SCB would have gotten a reconnect instead.
+         * What we need to do then is to let the command timeout again so
+         * we get a reset since this abort just failed.
+         */
+        cmd->result = 0;
+        scb = NULL;
+      }
+    }
+    /*
+     * Keep the sequencer from trying to restart any selections
+     */
+    aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+    /*
+     * Make sure the data bits on the bus are released
+     * Don't do this on 7770 chipsets, it makes them give us
+     * a BRKADDRINT and kills the card.
+     */
+    if( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+      aic_outb(p, 0, SCSIBUSL);
+
+    /*
+     * Delay for the selection timeout delay period then stop the selection
+     */
+    udelay(301);
+    aic_outb(p, CLRSELINGO, CLRSINT0);
+    /*
+     * Clear out all the interrupt status bits
+     */
+    aic_outb(p, aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
+    p->flags &= ~AHC_HANDLING_REQINITS;
+    aic_outb(p, CLRSELTIMEO | CLRBUSFREE, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    /*
+     * Restarting the sequencer will stop the selection and make sure devices
+     * are allowed to reselect in.
+     */
+    restart_sequencer(p);
+    unpause_sequencer(p, TRUE);
+  }
+  else if (scb == NULL)
+  {
+    printk(WARN_LEAD "aic7xxx_isr - referenced scb not valid "
+           "during scsiint 0x%x scb(%d)\n"
+           "      SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+           p->host_no, -1, -1, -1, status, scb_index, aic_inb(p, SIMODE0),
+           aic_inb(p, SIMODE1), aic_inb(p, SSTAT0),
+           (aic_inb(p, SEQADDR1) << 8) | aic_inb(p, SEQADDR0));
+    /*
+     * Turn off the interrupt and set status to zero, so that it
+     * falls through the rest of the SCSIINT code.
+     */
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  else if (status & SCSIPERR)
+  {
+    /*
+     * Determine the bus phase and queue an appropriate message.
+     */
+    char  *phase;
+    Scsi_Cmnd *cmd;
+    unsigned char mesg_out = MSG_NOOP;
+    unsigned char lastphase = aic_inb(p, LASTPHASE);
+    unsigned char sstat2 = aic_inb(p, SSTAT2);
+
+    cmd = scb->cmd;
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        phase = "Data-Out";
+        break;
+      case P_DATAIN:
+        phase = "Data-In";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_COMMAND:
+        phase = "Command";
+        break;
+      case P_MESGOUT:
+        phase = "Message-Out";
+        break;
+      case P_STATUS:
+        phase = "Status";
+        mesg_out = MSG_INITIATOR_DET_ERR;
+        break;
+      case P_MESGIN:
+        phase = "Message-In";
+        mesg_out = MSG_PARITY_ERROR;
+        break;
+      default:
+        phase = "unknown";
+        break;
+    }
+
+    /*
+     * A parity error has occurred during a data
+     * transfer phase. Flag it and continue.
+     */
+    if( (p->features & AHC_ULTRA3) && 
+        (aic_inb(p, SCSIRATE) & AHC_SYNCRATE_CRC) &&
+        (lastphase == P_DATAIN) )
+    {
+      printk(WARN_LEAD "CRC error during %s phase.\n",
+             p->host_no, CTL_OF_SCB(scb), phase);
+      if(sstat2 & CRCVALERR)
+      {
+        printk(WARN_LEAD "  CRC error in intermediate CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCENDERR)
+      {
+        printk(WARN_LEAD "  CRC error in ending CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & CRCREQERR)
+      {
+        printk(WARN_LEAD "  Target incorrectly requested a CRC packet.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+      if(sstat2 & DUAL_EDGE_ERROR)
+      {
+        printk(WARN_LEAD "  Dual Edge transmission error.\n",
+               p->host_no, CTL_OF_SCB(scb));
+      }
+    }
+    else if( (lastphase == P_MESGOUT) &&
+             (scb->flags & SCB_MSGOUT_PPR) )
+    {
+      /*
+       * As per the draft specs, any device capable of supporting any of
+       * the option values other than 0 are not allowed to reject the
+       * PPR message.  Instead, they must negotiate out what they do
+       * support instead of rejecting our offering or else they cause
+       * a parity error during msg_out phase to signal that they don't
+       * like our settings.
+       */
+      aic_dev = AIC_DEV(scb->cmd);
+      aic_dev->needppr = aic_dev->needppr_copy = 0;
+      aic7xxx_set_width(p, scb->cmd->device->id, scb->cmd->device->channel, scb->cmd->device->lun,
+                        MSG_EXT_WDTR_BUS_8_BIT,
+                        (AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE),
+			aic_dev);
+      aic7xxx_set_syncrate(p, NULL, scb->cmd->device->id, scb->cmd->device->channel, 0, 0,
+                           0, AHC_TRANS_ACTIVE|AHC_TRANS_CUR|AHC_TRANS_QUITE,
+			   aic_dev);
+      aic_dev->goal.options = 0;
+      scb->flags &= ~SCB_MSGOUT_BITS;
+      if(aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+      {
+        printk(INFO_LEAD "parity error during PPR message, reverting "
+               "to WDTR/SDTR\n", p->host_no, CTL_OF_SCB(scb));
+      }
+      if ( aic_dev->goal.width )
+      {
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+      }
+      if ( aic_dev->goal.offset )
+      {
+        if( aic_dev->goal.period <= 9 )
+        {
+          aic_dev->goal.period = 10;
+        }
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+      }
+      scb = NULL;
+    }
+
+    /*
+     * We've set the hardware to assert ATN if we get a parity
+     * error on "in" phases, so all we need to do is stuff the
+     * message buffer with the appropriate message.  "In" phases
+     * have set mesg_out to something other than MSG_NOP.
+     */
+    if (mesg_out != MSG_NOOP)
+    {
+      aic_outb(p, mesg_out, MSG_OUT);
+      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+      scb = NULL;
+    }
+    aic_outb(p, CLRSCSIPERR, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause_always */ TRUE);
+  }
+  else if ( (status & REQINIT) &&
+            (p->flags & AHC_HANDLING_REQINITS) )
+  {
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (aic7xxx_verbose > 0xffff)
+      printk(INFO_LEAD "Handling REQINIT, SSTAT1=0x%x.\n", p->host_no,
+             CTL_OF_SCB(scb), aic_inb(p, SSTAT1));
+#endif
+    aic7xxx_handle_reqinit(p, scb);
+    return;
+  }
+  else
+  {
+    /*
+     * We don't know what's going on. Turn off the
+     * interrupt source and try to continue.
+     */
+    if (aic7xxx_verbose & VERBOSE_SCSIINT)
+      printk(INFO_LEAD "Unknown SCSIINT status, SSTAT1(0x%x).\n",
+        p->host_no, -1, -1, -1, status);
+    aic_outb(p, status, CLRSINT1);
+    aic_outb(p, CLRSCSIINT, CLRINT);
+    unpause_sequencer(p, /* unpause always */ TRUE);
+    scb = NULL;
+  }
+  if (scb != NULL)
+  {
+    aic7xxx_done(p, scb);
+  }
+}
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+static void
+aic7xxx_check_scbs(struct aic7xxx_host *p, char *buffer)
+{
+  unsigned char saved_scbptr, free_scbh, dis_scbh, wait_scbh, temp;
+  int i, bogus, lost;
+  static unsigned char scb_status[AIC7XXX_MAXSCB];
+
+#define SCB_NO_LIST 0
+#define SCB_FREE_LIST 1
+#define SCB_WAITING_LIST 2
+#define SCB_DISCONNECTED_LIST 4
+#define SCB_CURRENTLY_ACTIVE 8
+
+  /*
+   * Note, these checks will fail on a regular basis once the machine moves
+   * beyond the bus scan phase.  The problem is race conditions concerning
+   * the scbs and where they are linked in.  When you have 30 or so commands
+   * outstanding on the bus, and run this twice with every interrupt, the
+   * chances get pretty good that you'll catch the sequencer with an SCB
+   * only partially linked in.  Therefore, once we pass the scan phase
+   * of the bus, we really should disable this function.
+   */
+  bogus = FALSE;
+  memset(&scb_status[0], 0, sizeof(scb_status));
+  pause_sequencer(p);
+  saved_scbptr = aic_inb(p, SCBPTR);
+  if (saved_scbptr >= p->scb_data->maxhscbs)
+  {
+    printk("Bogus SCBPTR %d\n", saved_scbptr);
+    bogus = TRUE;
+  }
+  scb_status[saved_scbptr] = SCB_CURRENTLY_ACTIVE;
+  free_scbh = aic_inb(p, FREE_SCBH);
+  if ( (free_scbh != SCB_LIST_NULL) &&
+       (free_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus FREE_SCBH %d\n", free_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = free_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_FREE_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_FREE_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+
+  dis_scbh = aic_inb(p, DISCONNECTED_SCBH);
+  if ( (dis_scbh != SCB_LIST_NULL) &&
+       (dis_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus DISCONNECTED_SCBH %d\n", dis_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = dis_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_DISCONNECTED_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_DISCONNECTED_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+  
+  wait_scbh = aic_inb(p, WAITING_SCBH);
+  if ( (wait_scbh != SCB_LIST_NULL) &&
+       (wait_scbh >= p->scb_data->maxhscbs) )
+  {
+    printk("Bogus WAITING_SCBH %d\n", wait_scbh);
+    bogus = TRUE;
+  }
+  else
+  {
+    temp = wait_scbh;
+    while( (temp != SCB_LIST_NULL) && (temp < p->scb_data->maxhscbs) )
+    {
+      if(scb_status[temp] & 0x07)
+      {
+        printk("HSCB %d on multiple lists, status 0x%02x", temp,
+               scb_status[temp] | SCB_WAITING_LIST);
+        bogus = TRUE;
+      }
+      scb_status[temp] |= SCB_WAITING_LIST;
+      aic_outb(p, temp, SCBPTR);
+      temp = aic_inb(p, SCB_NEXT);
+    }
+  }
+
+  lost=0;
+  for(i=0; i < p->scb_data->maxhscbs; i++)
+  {
+    aic_outb(p, i, SCBPTR);
+    temp = aic_inb(p, SCB_NEXT);
+    if ( ((temp != SCB_LIST_NULL) &&
+          (temp >= p->scb_data->maxhscbs)) )
+    {
+      printk("HSCB %d bad, SCB_NEXT invalid(%d).\n", i, temp);
+      bogus = TRUE;
+    }
+    if ( temp == i )
+    {
+      printk("HSCB %d bad, SCB_NEXT points to self.\n", i);
+      bogus = TRUE;
+    }
+    if (scb_status[i] == 0)
+      lost++;
+    if (lost > 1)
+    {
+      printk("Too many lost scbs.\n");
+      bogus=TRUE;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  unpause_sequencer(p, FALSE);
+  if (bogus)
+  {
+    printk("Bogus parameters found in card SCB array structures.\n");
+    printk("%s\n", buffer);
+    aic7xxx_panic_abort(p, NULL);
+  }
+  return;
+}
+#endif
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_handle_command_completion_intr
+ *
+ * Description:
+ *   SCSI command completion interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_command_completion_intr(struct aic7xxx_host *p)
+{
+  struct aic7xxx_scb *scb = NULL;
+  struct aic_dev_data *aic_dev;
+  Scsi_Cmnd *cmd;
+  unsigned char scb_index, tindex;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) )
+    printk(INFO_LEAD "Command Complete Int.\n", p->host_no, -1, -1, -1);
+#endif
+    
+  /*
+   * Read the INTSTAT location after clearing the CMDINT bit.  This forces
+   * any posted PCI writes to flush to memory.  Gerard Roudier suggested
+   * this fix to the possible race of clearing the CMDINT bit but not
+   * having all command bytes flushed onto the qoutfifo.
+   */
+  aic_outb(p, CLRCMDINT, CLRINT);
+  aic_inb(p, INTSTAT);
+  /*
+   * The sequencer will continue running when it
+   * issues this interrupt. There may be >1 commands
+   * finished, so loop until we've processed them all.
+   */
+
+  while (p->qoutfifo[p->qoutfifonext] != SCB_LIST_NULL)
+  {
+    scb_index = p->qoutfifo[p->qoutfifonext];
+    p->qoutfifo[p->qoutfifonext++] = SCB_LIST_NULL;
+    if ( scb_index >= p->scb_data->numscbs )
+    {
+      printk(WARN_LEAD "CMDCMPLT with invalid SCB index %d\n", p->host_no,
+        -1, -1, -1, scb_index);
+      continue;
+    }
+    scb = p->scb_data->scb_array[scb_index];
+    if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+    {
+      printk(WARN_LEAD "CMDCMPLT without command for SCB %d, SCB flags "
+        "0x%x, cmd 0x%lx\n", p->host_no, -1, -1, -1, scb_index, scb->flags,
+        (unsigned long) scb->cmd);
+      continue;
+    }
+    tindex = TARGET_INDEX(scb->cmd);
+    aic_dev = AIC_DEV(scb->cmd);
+    if (scb->flags & SCB_QUEUED_ABORT)
+    {
+      pause_sequencer(p);
+      if ( ((aic_inb(p, LASTPHASE) & PHASE_MASK) != P_BUSFREE) &&
+           (aic_inb(p, SCB_TAG) == scb->hscb->tag) )
+      {
+        unpause_sequencer(p, FALSE);
+        continue;
+      }
+      aic7xxx_reset_device(p, scb->cmd->device->id, scb->cmd->device->channel,
+        scb->cmd->device->lun, scb->hscb->tag);
+      scb->flags &= ~(SCB_QUEUED_FOR_DONE | SCB_RESET | SCB_ABORT |
+        SCB_QUEUED_ABORT);
+      unpause_sequencer(p, FALSE);
+    }
+    else if (scb->flags & SCB_ABORT)
+    {
+      /*
+       * We started to abort this, but it completed on us, let it
+       * through as successful
+       */
+      scb->flags &= ~(SCB_ABORT|SCB_RESET);
+    }
+    else if (scb->flags & SCB_SENSE)
+    {
+      char *buffer = &scb->cmd->sense_buffer[0];
+
+      if (buffer[12] == 0x47 || buffer[12] == 0x54)
+      {
+        /*
+         * Signal that we need to re-negotiate things.
+         */
+        aic_dev->needppr = aic_dev->needppr_copy;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy;
+      }
+    }
+    cmd = scb->cmd;
+    if (scb->hscb->residual_SG_segment_count != 0)
+    {
+      aic7xxx_calculate_residual(p, scb);
+    }
+    cmd->result |= (aic7xxx_error(cmd) << 16);
+    aic7xxx_done(p, scb);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_isr
+ *
+ * Description:
+ *   SCSI controller interrupt handler.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  struct aic7xxx_host *p;
+  unsigned char intstat;
+
+  p = (struct aic7xxx_host *)dev_id;
+
+  /*
+   * Just a few sanity checks.  Make sure that we have an int pending.
+   * Also, if PCI, then we are going to check for a PCI bus error status
+   * should we get too many spurious interrupts.
+   */
+  if (!((intstat = aic_inb(p, INTSTAT)) & INT_PEND))
+  {
+#ifdef CONFIG_PCI
+    if ( (p->chip & AHC_PCI) && (p->spurious_int > 500) &&
+        !(p->flags & AHC_HANDLING_REQINITS) )
+    {
+      if ( aic_inb(p, ERROR) & PCIERRSTAT )
+      {
+        aic7xxx_pci_intr(p);
+      }
+      p->spurious_int = 0;
+    }
+    else if ( !(p->flags & AHC_HANDLING_REQINITS) )
+    {
+      p->spurious_int++;
+    }
+#endif
+    return;
+  }
+
+  p->spurious_int = 0;
+
+  /*
+   * Keep track of interrupts for /proc/scsi
+   */
+  p->isr_count++;
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at start of interrupt.");
+#endif
+
+  /*
+   * Handle all the interrupt sources - especially for SCSI
+   * interrupts, we won't get a second chance at them.
+   */
+  if (intstat & CMDCMPLT)
+  {
+    aic7xxx_handle_command_completion_intr(p);
+  }
+
+  if (intstat & BRKADRINT)
+  {
+    int i;
+    unsigned char errno = aic_inb(p, ERROR);
+
+    printk(KERN_ERR "(scsi%d) BRKADRINT error(0x%x):\n", p->host_no, errno);
+    for (i = 0; i < ARRAY_SIZE(hard_error); i++)
+    {
+      if (errno & hard_error[i].errno)
+      {
+        printk(KERN_ERR "  %s\n", hard_error[i].errmesg);
+      }
+    }
+    printk(KERN_ERR "(scsi%d)   SEQADDR=0x%x\n", p->host_no,
+      (((aic_inb(p, SEQADDR1) << 8) & 0x100) | aic_inb(p, SEQADDR0)));
+    if (aic7xxx_panic_on_abort)
+      aic7xxx_panic_abort(p, NULL);
+#ifdef CONFIG_PCI
+    if (errno & PCIERRSTAT)
+      aic7xxx_pci_intr(p);
+#endif
+    if (errno & (SQPARERR | ILLOPCODE | ILLSADDR))
+    {
+      panic("aic7xxx: unrecoverable BRKADRINT.\n");
+    }
+    if (errno & ILLHADDR)
+    {
+      printk(KERN_ERR "(scsi%d) BUG! Driver accessed chip without first "
+             "pausing controller!\n", p->host_no);
+    }
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+    if (errno & DPARERR)
+    {
+      if (aic_inb(p, DMAPARAMS) & DIRECTION)
+        printk("(scsi%d) while DMAing SCB from host to card.\n", p->host_no);
+      else
+        printk("(scsi%d) while DMAing SCB from card to host.\n", p->host_no);
+    }
+#endif
+    aic_outb(p, CLRPARERR | CLRBRKADRINT, CLRINT);
+    unpause_sequencer(p, FALSE);
+  }
+
+  if (intstat & SEQINT)
+  {
+    /*
+     * Read the CCSCBCTL register to work around a bug in the Ultra2 cards
+     */
+    if(p->features & AHC_ULTRA2)
+    {
+      aic_inb(p, CCSCBCTL);
+    }
+    aic7xxx_handle_seqint(p, intstat);
+  }
+
+  if (intstat & SCSIINT)
+  {
+    aic7xxx_handle_scsiint(p, intstat);
+  }
+
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if ( (p->isr_count < 16) && (aic7xxx_verbose > 0xffff) &&
+       (aic7xxx_panic_on_abort) && (p->flags & AHC_PAGESCBS) )
+    aic7xxx_check_scbs(p, "Bogus settings at end of interrupt.");
+#endif
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   do_aic7xxx_isr
+ *
+ * Description:
+ *   This is a gross hack to solve a problem in linux kernels 2.1.85 and
+ *   above.  Please, children, do not try this at home, and if you ever see
+ *   anything like it, please inform the Gross Hack Police immediately
+ *-F*************************************************************************/
+static irqreturn_t
+do_aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+  unsigned long cpu_flags;
+  struct aic7xxx_host *p;
+  
+  p = (struct aic7xxx_host *)dev_id;
+  if(!p)
+    return IRQ_NONE;
+  spin_lock_irqsave(p->host->host_lock, cpu_flags);
+  p->flags |= AHC_IN_ISR;
+  do
+  {
+    aic7xxx_isr(irq, dev_id, regs);
+  } while ( (aic_inb(p, INTSTAT) & INT_PEND) );
+  aic7xxx_done_cmds_complete(p);
+  aic7xxx_run_waiting_queues(p);
+  p->flags &= ~AHC_IN_ISR;
+  spin_unlock_irqrestore(p->host->host_lock, cpu_flags);
+
+  return IRQ_HANDLED;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_init_transinfo
+ *
+ * Description:
+ *   Set up the initial aic_dev values from the BIOS settings and from
+ *   INQUIRY results
+ *-F*************************************************************************/
+static void
+aic7xxx_init_transinfo(struct aic7xxx_host *p, struct aic_dev_data *aic_dev)
+{
+  Scsi_Device *sdpnt = aic_dev->SDptr;
+  unsigned char tindex;
+
+  tindex = sdpnt->id | (sdpnt->channel << 3);
+  if (!(aic_dev->flags & DEVICE_DTR_SCANNED))
+  {
+    aic_dev->flags |= DEVICE_DTR_SCANNED;
+
+    if ( sdpnt->wdtr && (p->features & AHC_WIDE) )
+    {
+      aic_dev->needwdtr = aic_dev->needwdtr_copy = 1;
+      aic_dev->goal.width = p->user[tindex].width;
+    }
+    else
+    {
+      aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+      pause_sequencer(p);
+      aic7xxx_set_width(p, sdpnt->id, sdpnt->channel, sdpnt->lun,
+                        MSG_EXT_WDTR_BUS_8_BIT, (AHC_TRANS_ACTIVE |
+                                                 AHC_TRANS_GOAL |
+                                                 AHC_TRANS_CUR), aic_dev );
+      unpause_sequencer(p, FALSE);
+    }
+    if ( sdpnt->sdtr && p->user[tindex].offset )
+    {
+      aic_dev->goal.period = p->user[tindex].period;
+      aic_dev->goal.options = p->user[tindex].options;
+      if (p->features & AHC_ULTRA2)
+        aic_dev->goal.offset = MAX_OFFSET_ULTRA2;
+      else if (aic_dev->goal.width == MSG_EXT_WDTR_BUS_16_BIT)
+        aic_dev->goal.offset = MAX_OFFSET_16BIT;
+      else
+        aic_dev->goal.offset = MAX_OFFSET_8BIT;
+      if ( sdpnt->ppr && p->user[tindex].period <= 9 &&
+             p->user[tindex].options )
+      {
+        aic_dev->needppr = aic_dev->needppr_copy = 1;
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+        aic_dev->needwdtr = aic_dev->needwdtr_copy = 0;
+        aic_dev->flags |= DEVICE_SCSI_3;
+      }
+      else
+      {
+        aic_dev->needsdtr = aic_dev->needsdtr_copy = 1;
+        aic_dev->goal.period = max_t(unsigned char, 10, aic_dev->goal.period);
+        aic_dev->goal.options = 0;
+      }
+    }
+    else
+    {
+      aic_dev->needsdtr = aic_dev->needsdtr_copy = 0;
+      aic_dev->goal.period = 255;
+      aic_dev->goal.offset = 0;
+      aic_dev->goal.options = 0;
+    }
+    aic_dev->flags |= DEVICE_PRINT_DTR;
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_slave_alloc
+ *
+ * Description:
+ *   Set up the initial aic_dev struct pointers
+ *-F*************************************************************************/
+static int
+aic7xxx_slave_alloc(Scsi_Device *SDptr)
+{
+  struct aic7xxx_host *p = (struct aic7xxx_host *)SDptr->host->hostdata;
+  struct aic_dev_data *aic_dev;
+
+  aic_dev = kmalloc(sizeof(struct aic_dev_data), GFP_ATOMIC | GFP_KERNEL);
+  if(!aic_dev)
+    return 1;
+  /*
+   * Check to see if channel was scanned.
+   */
+  
+  if (!(p->flags & AHC_A_SCANNED) && (SDptr->channel == 0))
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+      printk(INFO_LEAD "Scanning channel for devices.\n",
+        p->host_no, 0, -1, -1);
+    p->flags |= AHC_A_SCANNED;
+  }
+  else
+  {
+    if (!(p->flags & AHC_B_SCANNED) && (SDptr->channel == 1))
+    {
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(INFO_LEAD "Scanning channel for devices.\n",
+          p->host_no, 1, -1, -1);
+      p->flags |= AHC_B_SCANNED;
+    }
+  }
+
+  memset(aic_dev, 0, sizeof(struct aic_dev_data));
+  SDptr->hostdata = aic_dev;
+  aic_dev->SDptr = SDptr;
+  aic_dev->max_q_depth = 1;
+  aic_dev->temp_q_depth = 1;
+  scbq_init(&aic_dev->delayed_scbs);
+  INIT_LIST_HEAD(&aic_dev->list);
+  list_add_tail(&aic_dev->list, &p->aic_devs);
+  return 0;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_device_queue_depth
+ *
+ * Description:
+ *   Determines the queue depth for a given device.  There are two ways
+ *   a queue depth can be obtained for a tagged queueing device.  One
+ *   way is the default queue depth which is determined by whether
+ *   aic7xxx_default_queue_depth.  The other is by the aic7xxx_tag_info
+ *   array.
+ *
+ *   If tagged queueing isn't supported on the device, then we set the
+ *   depth to p->host->hostt->cmd_per_lun for internal driver queueing.
+ *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
+ *   default queue depth (dependent on the number of hardware SCBs).
+ *   The other way we determine queue depth is through the use of the
+ *   aic7xxx_tag_info array which is enabled by defining
+ *   AIC7XXX_TAGGED_QUEUEING_BY_DEVICE.  This array can be initialized
+ *   with queue depths for individual devices.  It also allows tagged
+ *   queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+  int tag_enabled = FALSE;
+  struct aic_dev_data *aic_dev = device->hostdata;
+  unsigned char tindex;
+
+  tindex = device->id | (device->channel << 3);
+
+  if (device->simple_tags)
+    return; // We've already enabled this device
+
+  if (device->tagged_supported)
+  {
+    tag_enabled = TRUE;
+
+    if (!(p->discenable & (1 << tindex)))
+    {
+      if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+        printk(INFO_LEAD "Disconnection disabled, unable to "
+             "enable tagged queueing.\n",
+             p->host_no, device->channel, device->id, device->lun);
+      tag_enabled = FALSE;
+    }
+    else
+    {
+      if (p->instance >= ARRAY_SIZE(aic7xxx_tag_info))
+      {
+        static int print_warning = TRUE;
+        if(print_warning)
+        {
+          printk(KERN_INFO "aic7xxx: WARNING, insufficient tag_info instances for"
+                           " installed controllers.\n");
+          printk(KERN_INFO "aic7xxx: Please update the aic7xxx_tag_info array in"
+                           " the aic7xxx.c source file.\n");
+          print_warning = FALSE;
+        }
+        aic_dev->max_q_depth = aic_dev->temp_q_depth =
+		aic7xxx_default_queue_depth;
+      }
+      else
+      {
+
+        if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 255)
+        {
+          tag_enabled = FALSE;
+        }
+        else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
+        {
+          aic_dev->max_q_depth = aic_dev->temp_q_depth =
+		  aic7xxx_default_queue_depth;
+        }
+        else
+        {
+          aic_dev->max_q_depth = aic_dev->temp_q_depth = 
+            aic7xxx_tag_info[p->instance].tag_commands[tindex];
+        }
+      }
+    }
+  }
+  if (tag_enabled)
+  {
+    if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+    {
+          printk(INFO_LEAD "Tagged queuing enabled, queue depth %d.\n",
+            p->host_no, device->channel, device->id,
+            device->lun, aic_dev->max_q_depth);
+    }
+    scsi_adjust_queue_depth(device, MSG_ORDERED_TAG, aic_dev->max_q_depth);
+  }
+  else
+  {
+    if (aic7xxx_verbose & VERBOSE_NEGOTIATION2)
+    {
+          printk(INFO_LEAD "Tagged queuing disabled, queue depth %d.\n",
+            p->host_no, device->channel, device->id,
+            device->lun, device->host->cmd_per_lun);
+    }
+    scsi_adjust_queue_depth(device, 0, device->host->cmd_per_lun);
+  }
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_slave_destroy
+ *
+ * Description:
+ *   prepare for this device to go away
+ *-F*************************************************************************/
+static void
+aic7xxx_slave_destroy(Scsi_Device *SDptr)
+{
+  struct aic_dev_data *aic_dev = SDptr->hostdata;
+
+  list_del(&aic_dev->list);
+  SDptr->hostdata = NULL;
+  kfree(aic_dev);
+  return;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_slave_configure
+ *
+ * Description:
+ *   Configure the device we are attaching to the controller.  This is
+ *   where we get to do things like scan the INQUIRY data, set queue
+ *   depths, allocate command structs, etc.
+ *-F*************************************************************************/
+static int
+aic7xxx_slave_configure(Scsi_Device *SDptr)
+{
+  struct aic7xxx_host *p = (struct aic7xxx_host *) SDptr->host->hostdata;
+  struct aic_dev_data *aic_dev;
+  int scbnum;
+
+  aic_dev = (struct aic_dev_data *)SDptr->hostdata;
+
+  aic7xxx_init_transinfo(p, aic_dev);
+  aic7xxx_device_queue_depth(p, SDptr);
+  if(list_empty(&aic_dev->list))
+    list_add_tail(&aic_dev->list, &p->aic_devs);
+
+  scbnum = 0;
+  list_for_each_entry(aic_dev, &p->aic_devs, list) {
+    scbnum += aic_dev->max_q_depth;
+  }
+  while (scbnum > p->scb_data->numscbs)
+  {
+    /*
+     * Pre-allocate the needed SCBs to get around the possibility of having
+     * to allocate some when memory is more or less exhausted and we need
+     * the SCB in order to perform a swap operation (possible deadlock)
+     */
+    if ( aic7xxx_allocate_scb(p) == 0 )
+      break;
+  }
+
+
+  return(0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_probe
+ *
+ * Description:
+ *   Probing for EISA boards: it looks like the first two bytes
+ *   are a manufacturer code - three characters, five bits each:
+ *
+ *               BYTE 0   BYTE 1   BYTE 2   BYTE 3
+ *              ?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ *   The characters are baselined off ASCII '@', so add that value
+ *   to each to get the real ASCII code for it. The next two bytes
+ *   appear to be a product and revision number, probably vendor-
+ *   specific. This is what is being searched for at each port,
+ *   and what should probably correspond to the ID= field in the
+ *   ECU's .cfg file for the card - if your card is not detected,
+ *   make sure your signature is listed in the array.
+ *
+ *   The fourth byte's lowest bit seems to be an enabled/disabled
+ *   flag (rest of the bits are reserved?).
+ *
+ * NOTE:  This function is only needed on Intel and Alpha platforms,
+ *   the other platforms we support don't have EISA/VLB busses.  So,
+ *   we #ifdef this entire function to avoid compiler warnings about
+ *   an unused function.
+ *-F*************************************************************************/
+#if defined(__i386__) || defined(__alpha__)
+static int
+aic7xxx_probe(int slot, int base, ahc_flag_type *flags)
+{
+  int i;
+  unsigned char buf[4];
+
+  static struct {
+    int n;
+    unsigned char signature[sizeof(buf)];
+    ahc_chip type;
+    int bios_disabled;
+  } AIC7xxx[] = {
+    { 4, { 0x04, 0x90, 0x77, 0x70 },
+      AHC_AIC7770|AHC_EISA, FALSE },  /* mb 7770  */
+    { 4, { 0x04, 0x90, 0x77, 0x71 },
+      AHC_AIC7770|AHC_EISA, FALSE }, /* host adapter 274x */
+    { 4, { 0x04, 0x90, 0x77, 0x56 },
+      AHC_AIC7770|AHC_VL, FALSE }, /* 284x BIOS enabled */
+    { 4, { 0x04, 0x90, 0x77, 0x57 },
+      AHC_AIC7770|AHC_VL, TRUE }   /* 284x BIOS disabled */
+  };
+
+  /*
+   * The VL-bus cards need to be primed by
+   * writing before a signature check.
+   */
+  for (i = 0; i < sizeof(buf); i++)
+  {
+    outb(0x80 + i, base);
+    buf[i] = inb(base + i);
+  }
+
+  for (i = 0; i < ARRAY_SIZE(AIC7xxx); i++)
+  {
+    /*
+     * Signature match on enabled card?
+     */
+    if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
+    {
+      if (inb(base + 4) & 1)
+      {
+        if (AIC7xxx[i].bios_disabled)
+        {
+          *flags |= AHC_USEDEFAULTS;
+        }
+        else
+        {
+          *flags |= AHC_BIOS_ENABLED;
+        }
+        return (i);
+      }
+
+      printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+             "disabled at slot %d, ignored.\n", slot);
+    }
+  }
+
+  return (-1);
+}
+#endif /* (__i386__) || (__alpha__) */
+
+
+/*+F*************************************************************************
+ * Function:
+ *   read_2840_seeprom
+ *
+ * Description:
+ *   Reads the 2840 serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   See read_seeprom (for the 2940) for the instruction set of the 93C46
+ *   chip.
+ *
+ *   The 2840 interface to the 93C46 serial EEPROM is through the
+ *   STATUS_2840 and SEECTL_2840 registers.  The CS_2840, CK_2840, and
+ *   DO_2840 bits of the SEECTL_2840 register are connected to the chip
+ *   select, clock, and data out lines respectively of the serial EEPROM.
+ *   The DI_2840 bit of the STATUS_2840 is connected to the data in line
+ *   of the serial EEPROM.  The EEPROM_TF bit of STATUS_2840 register is
+ *   useful in that it gives us an 800 nsec timer.  After a read from the
+ *   SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
+ *   later.
+ *-F*************************************************************************/
+static int
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
+{
+  int i = 0, k = 0;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  unsigned short *seeprom = (unsigned short *) sc;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+  while ((aic_inb(p, STATUS_2840) & EEPROM_TF) == 0)        \
+  {                                                \
+    ;  /* Do nothing */                                \
+  }                                                \
+  (void) aic_inb(p, SEECTL_2840);
+
+  /*
+   * Read the first 32 registers of the seeprom.  For the 2840,
+   * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
+   * but only the first 32 are used by Adaptec BIOS.  The loop
+   * will range from 0 to 31.
+   */
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    /*
+     * Send chip select for one clock cycle.
+     */
+    aic_outb(p, CK_2840 | CS_2840, SEECTL_2840);
+    CLOCK_PULSE(p);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i++)
+    {
+      temp = CS_2840 | seeprom_read.bits[i];
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * Send the 6 bit address (MSB first, LSB last).
+     */
+    for (i = 5; i >= 0; i--)
+    {
+      temp = k;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = CS_2840 | temp;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i++)
+    {
+      temp = CS_2840;
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+      temp = temp ^ CK_2840;
+      seeprom[k] = (seeprom[k] << 1) | (aic_inb(p, STATUS_2840) & DI_2840);
+      aic_outb(p, temp, SEECTL_2840);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * The serial EEPROM has a checksum in the last word.  Keep a
+     * running checksum for all words read except for the last
+     * word.  We'll verify the checksum after all words have been
+     * read.
+     */
+    if (k < (sizeof(*sc) / 2) - 1)
+    {
+      checksum = checksum + seeprom[k];
+    }
+
+    /*
+     * Reset the chip select for the next command cycle.
+     */
+    aic_outb(p, 0, SEECTL_2840);
+    CLOCK_PULSE(p);
+    aic_outb(p, CK_2840, SEECTL_2840);
+    CLOCK_PULSE(p);
+    aic_outb(p, 0, SEECTL_2840);
+    CLOCK_PULSE(p);
+  }
+
+#if 0
+  printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+  printk("Serial EEPROM:");
+  for (k = 0; k < (sizeof(*sc) / 2); k++)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk("\n              ");
+    }
+    printk(" 0x%x", seeprom[k]);
+  }
+  printk("\n");
+#endif
+
+  if (checksum != sc->checksum)
+  {
+    printk("aic7xxx: SEEPROM checksum error, ignoring SEEPROM settings.\n");
+    return (0);
+  }
+
+  return (1);
+#undef CLOCK_PULSE
+}
+
+#define CLOCK_PULSE(p)                                               \
+  do {                                                               \
+    int limit = 0;                                                   \
+    do {                                                             \
+      mb();                                                          \
+      pause_sequencer(p);  /* This is just to generate some PCI */   \
+                           /* traffic so the PCI read is flushed */  \
+                           /* it shouldn't be needed, but some */    \
+                           /* chipsets do indeed appear to need */   \
+                           /* something to force PCI reads to get */ \
+                           /* flushed */                             \
+      udelay(1);           /* Do nothing */                          \
+    } while (((aic_inb(p, SEECTL) & SEERDY) == 0) && (++limit < 1000)); \
+  } while(0)
+
+/*+F*************************************************************************
+ * Function:
+ *   acquire_seeprom
+ *
+ * Description:
+ *   Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+
+  /*
+   * Request access of the memory port.  When access is
+   * granted, SEERDY will go high.  We use a 1 second
+   * timeout which should be near 1 second more than
+   * is needed.  Reason: after the 7870 chip reset, there
+   * should be no contention.
+   */
+  aic_outb(p, SEEMS, SEECTL);
+  CLOCK_PULSE(p);
+  if ((aic_inb(p, SEECTL) & SEERDY) == 0)
+  {
+    aic_outb(p, 0, SEECTL);
+    return (0);
+  }
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   release_seeprom
+ *
+ * Description:
+ *   Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static void
+release_seeprom(struct aic7xxx_host *p)
+{
+  /*
+   * Make sure the SEEPROM is ready before we release it.
+   */
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, SEECTL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   read_seeprom
+ *
+ * Description:
+ *   Reads the serial EEPROM and returns 1 if successful and 0 if
+ *   not successful.
+ *
+ *   The instruction set of the 93C46/56/66 chips is as follows:
+ *
+ *               Start  OP
+ *     Function   Bit  Code  Address    Data     Description
+ *     -------------------------------------------------------------------
+ *     READ        1    10   A5 - A0             Reads data stored in memory,
+ *                                               starting at specified address
+ *     EWEN        1    00   11XXXX              Write enable must precede
+ *                                               all programming modes
+ *     ERASE       1    11   A5 - A0             Erase register A5A4A3A2A1A0
+ *     WRITE       1    01   A5 - A0   D15 - D0  Writes register
+ *     ERAL        1    00   10XXXX              Erase all registers
+ *     WRAL        1    00   01XXXX    D15 - D0  Writes to all registers
+ *     EWDS        1    00   00XXXX              Disables all programming
+ *                                               instructions
+ *     *Note: A value of X for address is a don't care condition.
+ *     *Note: The 93C56 and 93C66 have 8 address bits.
+ * 
+ *
+ *   The 93C46 has a four wire interface: clock, chip select, data in, and
+ *   data out.  In order to perform one of the above functions, you need
+ *   to enable the chip select for a clock period (typically a minimum of
+ *   1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ *   respectively.  While the chip select remains high, you can clock in
+ *   the instructions (above) starting with the start bit, followed by the
+ *   OP code, Address, and Data (if needed).  For the READ instruction, the
+ *   requested 16-bit register contents is read from the data out line but
+ *   is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ *   first).  The clock cycling from low to high initiates the next data
+ *   bit to be sent from the chip.
+ *
+ *   The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
+ *   register.  After successful arbitration for the memory port, the
+ *   SEECS bit of the SEECTL register is connected to the chip select.
+ *   The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
+ *   and data in lines respectively.  The SEERDY bit of SEECTL is useful
+ *   in that it gives us an 800 nsec timer.  After a write to the SEECTL
+ *   register, the SEERDY goes high 800 nsec later.  The one exception
+ *   to this is when we first request access to the memory port.  The
+ *   SEERDY goes high to signify that access has been granted and, for
+ *   this case, has no implied timing.
+ *-F*************************************************************************/
+static int
+read_seeprom(struct aic7xxx_host *p, int offset, 
+    unsigned short *scarray, unsigned int len, seeprom_chip_type chip)
+{
+  int i = 0, k;
+  unsigned char temp;
+  unsigned short checksum = 0;
+  struct seeprom_cmd {
+    unsigned char len;
+    unsigned char bits[3];
+  };
+  struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+  /*
+   * Request access of the memory port.
+   */
+  if (acquire_seeprom(p) == 0)
+  {
+    return (0);
+  }
+
+  /*
+   * Read 'len' registers of the seeprom.  For the 7870, the 93C46
+   * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+   * the first 32 are used by Adaptec BIOS.  Some adapters use the
+   * 93C56 SEEPROM which is a 2048-bit device.  The loop will range
+   * from 0 to 'len' - 1.
+   */
+  for (k = 0; k < len; k++)
+  {
+    /*
+     * Send chip select for one clock cycle.
+     */
+    aic_outb(p, SEEMS | SEECK | SEECS, SEECTL);
+    CLOCK_PULSE(p);
+
+    /*
+     * Now we're ready to send the read command followed by the
+     * address of the 16-bit register we want to read.
+     */
+    for (i = 0; i < seeprom_read.len; i++)
+    {
+      temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+    /*
+     * Send the 6 or 8 bit address (MSB first, LSB last).
+     */
+    for (i = ((int) chip - 1); i >= 0; i--)
+    {
+      temp = k + offset;
+      temp = (temp >> i) & 1;  /* Mask out all but lower bit. */
+      temp = SEEMS | SEECS | (temp << 1);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * Now read the 16 bit register.  An initial 0 precedes the
+     * register contents which begins with bit 15 (MSB) and ends
+     * with bit 0 (LSB).  The initial 0 will be shifted off the
+     * top of our word as we let the loop run from 0 to 16.
+     */
+    for (i = 0; i <= 16; i++)
+    {
+      temp = SEEMS | SEECS;
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+      temp = temp ^ SEECK;
+      scarray[k] = (scarray[k] << 1) | (aic_inb(p, SEECTL) & SEEDI);
+      aic_outb(p, temp, SEECTL);
+      CLOCK_PULSE(p);
+    }
+
+    /*
+     * The serial EEPROM should have a checksum in the last word.
+     * Keep a running checksum for all words read except for the
+     * last word.  We'll verify the checksum after all words have
+     * been read.
+     */
+    if (k < (len - 1))
+    {
+      checksum = checksum + scarray[k];
+    }
+
+    /*
+     * Reset the chip select for the next command cycle.
+     */
+    aic_outb(p, SEEMS, SEECTL);
+    CLOCK_PULSE(p);
+    aic_outb(p, SEEMS | SEECK, SEECTL);
+    CLOCK_PULSE(p);
+    aic_outb(p, SEEMS, SEECTL);
+    CLOCK_PULSE(p);
+  }
+
+  /*
+   * Release access to the memory port and the serial EEPROM.
+   */
+  release_seeprom(p);
+
+#if 0
+  printk("Computed checksum 0x%x, checksum read 0x%x\n",
+         checksum, scarray[len - 1]);
+  printk("Serial EEPROM:");
+  for (k = 0; k < len; k++)
+  {
+    if (((k % 8) == 0) && (k != 0))
+    {
+      printk("\n              ");
+    }
+    printk(" 0x%x", scarray[k]);
+  }
+  printk("\n");
+#endif
+  if ( (checksum != scarray[len - 1]) || (checksum == 0) )
+  {
+    return (0);
+  }
+
+  return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   read_brdctl
+ *
+ * Description:
+ *   Reads the BRDCTL register.
+ *-F*************************************************************************/
+static unsigned char
+read_brdctl(struct aic7xxx_host *p)
+{
+  unsigned char brdctl, value;
+
+  /*
+   * Make sure the SEEPROM is ready before we access it
+   */
+  CLOCK_PULSE(p);
+  if (p->features & AHC_ULTRA2)
+  {
+    brdctl = BRDRW_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    value = aic_inb(p, BRDCTL);
+    CLOCK_PULSE(p);
+    return(value);
+  }
+  brdctl = BRDRW;
+  if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+        (p->flags & AHC_CHNLB) )
+  {
+    brdctl |= BRDCS;
+  }
+  aic_outb(p, brdctl, BRDCTL);
+  CLOCK_PULSE(p);
+  value = aic_inb(p, BRDCTL);
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, BRDCTL);
+  CLOCK_PULSE(p);
+  return (value);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   write_brdctl
+ *
+ * Description:
+ *   Writes a value to the BRDCTL register.
+ *-F*************************************************************************/
+static void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
+{
+  unsigned char brdctl;
+
+  /*
+   * Make sure the SEEPROM is ready before we access it
+   */
+  CLOCK_PULSE(p);
+  if (p->features & AHC_ULTRA2)
+  {
+    brdctl = value;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl |= BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDSTB_ULTRA2;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    read_brdctl(p);
+    CLOCK_PULSE(p);
+  }
+  else
+  {
+    brdctl = BRDSTB;
+    if ( !((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) ||
+          (p->flags & AHC_CHNLB) )
+    {
+      brdctl |= BRDCS;
+    }
+    brdctl = BRDSTB | BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl |= value;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDSTB;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+    brdctl &= ~BRDCS;
+    aic_outb(p, brdctl, BRDCTL);
+    CLOCK_PULSE(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic785x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic785x class controller chips
+ *-F*************************************************************************/
+static void
+aic785x_cable_detect(struct aic7xxx_host *p, int *int_50,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  aic_outb(p, BRDRW | BRDCS, BRDCTL);
+  CLOCK_PULSE(p);
+  aic_outb(p, 0, BRDCTL);
+  CLOCK_PULSE(p);
+  brdctl = aic_inb(p, BRDCTL);
+  CLOCK_PULSE(p);
+  *int_50 = !(brdctl & BRDDAT5);
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = (aic_inb(p, SPIOCAP) & EEPROM);
+}
+
+#undef CLOCK_PULSE
+
+/*+F*************************************************************************
+ * Function:
+ *   aic2940_uwpro_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on the 2940-UWPro cards
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic2940_uwpro_wide_cable_detect(struct aic7xxx_host *p, int *int_68,
+    int *ext_68, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the internal 68 connector.  BRDDAT6
+   * is don't care, BRDDAT7 is internal 68.  The cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_68 = !(brdctl & BRDDAT6);
+  *eeprom = !(brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_cable_detect
+ *
+ * Description:
+ *   Detect the cables that are present on aic787x class controller chips
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic787x_cable_detect(struct aic7xxx_host *p, int *int_50, int *int_68,
+    int *ext_present, int *eeprom)
+{
+  unsigned char brdctl;
+
+  /*
+   * First read the status of our cables.  Set the rom bank to
+   * 0 since the bank setting serves as a multiplexor for the
+   * cable detection logic.  BRDDAT5 controls the bank switch.
+   */
+  write_brdctl(p, 0);
+
+  /*
+   * Now we read the state of the two internal connectors.  BRDDAT6
+   * is internal 50, BRDDAT7 is internal 68.  For each, the cable is
+   * present if the bit is 0
+   */
+  brdctl = read_brdctl(p);
+  *int_50 = !(brdctl & BRDDAT6);
+  *int_68 = !(brdctl & BRDDAT7);
+
+  /*
+   * Set the bank bit in brdctl and then read the external cable state
+   * and the EEPROM status
+   */
+  write_brdctl(p, BRDDAT5);
+  brdctl = read_brdctl(p);
+
+  *ext_present = !(brdctl & BRDDAT6);
+  *eeprom = !(brdctl & BRDDAT7);
+
+  /*
+   * We're done, the calling function will release the SEEPROM for us
+   */
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic787x_ultra2_term_detect
+ *
+ * Description:
+ *   Detect the termination settings present on ultra2 class controllers
+ *
+ * NOTE: This function assumes the SEEPROM will have already been acquired
+ *       prior to invocation of this function.
+ *-F*************************************************************************/
+static void
+aic7xxx_ultra2_term_detect(struct aic7xxx_host *p, int *enableSE_low,
+                           int *enableSE_high, int *enableLVD_low,
+                           int *enableLVD_high, int *eprom_present)
+{
+  unsigned char brdctl;
+
+  brdctl = read_brdctl(p);
+
+  *eprom_present  = (brdctl & BRDDAT7);
+  *enableSE_high  = (brdctl & BRDDAT6);
+  *enableSE_low   = (brdctl & BRDDAT5);
+  *enableLVD_high = (brdctl & BRDDAT4);
+  *enableLVD_low  = (brdctl & BRDDAT3);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   configure_termination
+ *
+ * Description:
+ *   Configures the termination settings on PCI adapters that have
+ *   SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p)
+{
+  int internal50_present = 0;
+  int internal68_present = 0;
+  int external_present = 0;
+  int eprom_present = 0;
+  int enableSE_low = 0;
+  int enableSE_high = 0;
+  int enableLVD_low = 0;
+  int enableLVD_high = 0;
+  unsigned char brddat = 0;
+  unsigned char max_target = 0;
+  unsigned char sxfrctl1 = aic_inb(p, SXFRCTL1);
+
+  if (acquire_seeprom(p))
+  {
+    if (p->features & (AHC_WIDE|AHC_TWIN))
+      max_target = 16;
+    else
+      max_target = 8;
+    aic_outb(p, SEEMS | SEECS, SEECTL);
+    sxfrctl1 &= ~STPWEN;
+    /*
+     * The termination/cable detection logic is split into three distinct
+     * groups.  Ultra2 and later controllers, 2940UW-Pro controllers, and
+     * older 7850, 7860, 7870, 7880, and 7895 controllers.  Each has its
+     * own unique way of detecting their cables and writing the results
+     * back to the card.
+     */
+    if (p->features & AHC_ULTRA2)
+    {
+      /*
+       * As long as user hasn't overridden term settings, always check the
+       * cable detection logic
+       */
+      if (aic7xxx_override_term == -1)
+      {
+        aic7xxx_ultra2_term_detect(p, &enableSE_low, &enableSE_high,
+                                   &enableLVD_low, &enableLVD_high,
+                                   &eprom_present);
+      }
+      
+      /*
+       * If the user is overriding settings, then they have been preserved
+       * to here as fake adapter_control entries.  Parse them and allow
+       * them to override the detected settings (if we even did detection).
+       */
+      if (!(p->adapter_control & CFSEAUTOTERM))
+      {
+        enableSE_low = (p->adapter_control & CFSTERM);
+        enableSE_high = (p->adapter_control & CFWSTERM);
+      }
+      if (!(p->adapter_control & CFAUTOTERM))
+      {
+        enableLVD_low = enableLVD_high = (p->adapter_control & CFLVDSTERM);
+      }
+
+      /*
+       * Now take those settings that we have and translate them into the
+       * values that must be written into the registers.
+       *
+       * Flash Enable = BRDDAT7
+       * Secondary High Term Enable = BRDDAT6
+       * Secondary Low Term Enable = BRDDAT5
+       * LVD/Primary High Term Enable = BRDDAT4
+       * LVD/Primary Low Term Enable = STPWEN bit in SXFRCTL1
+       */
+      if (enableLVD_low != 0)
+      {
+        sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_LVD;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD/Primary Low byte termination "
+                 "Enabled\n", p->host_no);
+      }
+          
+      if (enableLVD_high != 0)
+      {
+        brddat |= BRDDAT4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) LVD/Primary High byte termination "
+                 "Enabled\n", p->host_no);
+      }
+
+      if (enableSE_low != 0)
+      {
+        brddat |= BRDDAT5;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) Secondary Low byte termination "
+                 "Enabled\n", p->host_no);
+      }
+
+      if (enableSE_high != 0)
+      {
+        brddat |= BRDDAT6;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) Secondary High byte termination "
+                 "Enabled\n", p->host_no);
+      }
+    }
+    else if (p->features & AHC_NEW_AUTOTERM)
+    {
+      /*
+       * The 50 pin connector termination is controlled by STPWEN in the
+       * SXFRCTL1 register.  Since the Adaptec docs typically say the
+       * controller is not allowed to be in the middle of a cable and
+       * this is the only connection on that stub of the bus, there is
+       * no need to even check for narrow termination, it's simply
+       * always on.
+       */
+      sxfrctl1 |= STPWEN;
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "(scsi%d) Narrow channel termination Enabled\n",
+               p->host_no);
+
+      if (p->adapter_control & CFAUTOTERM)
+      {
+        aic2940_uwpro_wide_cable_detect(p, &internal68_present,
+                                        &external_present,
+                                        &eprom_present);
+        printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+               "Ext-68 %s)\n", p->host_no,
+               "Don't Care",
+               internal68_present ? "YES" : "NO",
+               external_present ? "YES" : "NO");
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+               eprom_present ? "is" : "is not");
+        if (internal68_present && external_present)
+        {
+          brddat = 0;
+          p->flags &= ~AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Disabled\n",
+                   p->host_no);
+        }
+        else
+        {
+          brddat = BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+                   p->host_no);
+        }
+      }
+      else
+      {
+        /*
+         * The termination of the Wide channel is done more like normal
+         * though, and the setting of this termination is done by writing
+         * either a 0 or 1 to BRDDAT6 of the BRDDAT register
+         */
+        if (p->adapter_control & CFWSTERM)
+        {
+          brddat = BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) Wide channel termination Enabled\n",
+                   p->host_no);
+        }
+        else
+        {
+          brddat = 0;
+        }
+      }
+    }
+    else
+    {
+      if (p->adapter_control & CFAUTOTERM)
+      {
+        if (p->flags & AHC_MOTHERBOARD)
+        {
+          printk(KERN_INFO "(scsi%d) Warning - detected auto-termination\n",
+                 p->host_no);
+          printk(KERN_INFO "(scsi%d) Please verify driver detected settings "
+            "are correct.\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) If not, then please properly set the "
+            "device termination\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) in the Adaptec SCSI BIOS by hitting "
+            "CTRL-A when prompted\n", p->host_no);
+          printk(KERN_INFO "(scsi%d) during machine bootup.\n", p->host_no);
+        }
+        /* Configure auto termination. */
+
+        if ( (p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870 )
+        {
+          aic787x_cable_detect(p, &internal50_present, &internal68_present,
+            &external_present, &eprom_present);
+        }
+        else
+        {
+          aic785x_cable_detect(p, &internal50_present, &external_present,
+            &eprom_present);
+        }
+
+        if (max_target <= 8)
+          internal68_present = 0;
+
+        if (max_target > 8)
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Int-68 %s, "
+                 "Ext-68 %s)\n", p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 internal68_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
+        else
+        {
+          printk(KERN_INFO "(scsi%d) Cables present (Int-50 %s, Ext-50 %s)\n",
+                 p->host_no,
+                 internal50_present ? "YES" : "NO",
+                 external_present ? "YES" : "NO");
+        }
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk(KERN_INFO "(scsi%d) EEPROM %s present.\n", p->host_no,
+               eprom_present ? "is" : "is not");
+
+        /*
+         * Now set the termination based on what we found.  BRDDAT6
+         * controls wide termination enable.
+         * Flash Enable = BRDDAT7
+         * SE High Term Enable = BRDDAT6
+         */
+        if (internal50_present && internal68_present && external_present)
+        {
+          printk(KERN_INFO "(scsi%d) Illegal cable configuration!!  Only two\n",
+                 p->host_no);
+          printk(KERN_INFO "(scsi%d) connectors on the SCSI controller may be "
+                 "in use at a time!\n", p->host_no);
+          /*
+           * Force termination (low and high byte) on.  This is safer than
+           * leaving it completely off, especially since this message comes
+           * most often from motherboard controllers that don't even have 3
+           * connectors, but instead are failing the cable detection.
+           */
+          internal50_present = external_present = 0;
+          enableSE_high = enableSE_low = 1;
+        }
+
+        if ((max_target > 8) &&
+            ((external_present == 0) || (internal68_present == 0)) )
+        {
+          brddat |= BRDDAT6;
+          p->flags |= AHC_TERM_ENB_SE_HIGH;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                   p->host_no);
+        }
+
+        if ( ((internal50_present ? 1 : 0) +
+              (internal68_present ? 1 : 0) +
+              (external_present   ? 1 : 0)) <= 1 )
+        {
+          sxfrctl1 |= STPWEN;
+          p->flags |= AHC_TERM_ENB_SE_LOW;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                   p->host_no);
+        }
+      }
+      else /* p->adapter_control & CFAUTOTERM */
+      {
+        if (p->adapter_control & CFSTERM)
+        {
+          sxfrctl1 |= STPWEN;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE Low byte termination Enabled\n",
+                   p->host_no);
+        }
+
+        if (p->adapter_control & CFWSTERM)
+        {
+          brddat |= BRDDAT6;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk(KERN_INFO "(scsi%d) SE High byte termination Enabled\n",
+                   p->host_no);
+        }
+      }
+    }
+
+    aic_outb(p, sxfrctl1, SXFRCTL1);
+    write_brdctl(p, brddat);
+    release_seeprom(p);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   detect_maxscb
+ *
+ * Description:
+ *   Detects the maximum number of SCBs for the controller and returns
+ *   the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * It's possible that we've already done this for multichannel
+   * adapters.
+   */
+  if (p->scb_data->maxhscbs == 0)
+  {
+    /*
+     * We haven't initialized the SCB settings yet.  Walk the SCBs to
+     * determince how many there are.
+     */
+    aic_outb(p, 0, FREE_SCBH);
+
+    for (i = 0; i < AIC7XXX_MAXSCB; i++)
+    {
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, i, SCB_CONTROL);
+      if (aic_inb(p, SCB_CONTROL) != i)
+        break;
+      aic_outb(p, 0, SCBPTR);
+      if (aic_inb(p, SCB_CONTROL) != 0)
+        break;
+
+      aic_outb(p, i, SCBPTR);
+      aic_outb(p, 0, SCB_CONTROL);   /* Clear the control byte. */
+      aic_outb(p, i + 1, SCB_NEXT);  /* Set the next pointer. */
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);  /* Make the tag invalid. */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS);  /* no busy untagged */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+1);/* targets active yet */
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+2);
+      aic_outb(p, SCB_LIST_NULL, SCB_BUSYTARGETS+3);
+    }
+
+    /* Make sure the last SCB terminates the free list. */
+    aic_outb(p, i - 1, SCBPTR);
+    aic_outb(p, SCB_LIST_NULL, SCB_NEXT);
+
+    /* Ensure we clear the first (0) SCBs control byte. */
+    aic_outb(p, 0, SCBPTR);
+    aic_outb(p, 0, SCB_CONTROL);
+
+    p->scb_data->maxhscbs = i;
+    /*
+     * Use direct indexing instead for speed
+     */
+    if ( i == AIC7XXX_MAXSCB )
+      p->flags &= ~AHC_PAGESCBS;
+  }
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_register
+ *
+ * Description:
+ *   Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p,
+  int reset_delay)
+{
+  int i, result;
+  int max_targets;
+  int found = 1;
+  unsigned char term, scsi_conf;
+  struct Scsi_Host *host;
+
+  host = p->host;
+
+  p->scb_data->maxscbs = AIC7XXX_MAXSCB;
+  host->can_queue = AIC7XXX_MAXSCB;
+  host->cmd_per_lun = 3;
+  host->sg_tablesize = AIC7XXX_MAX_SG;
+  host->this_id = p->scsi_id;
+  host->io_port = p->base;
+  host->n_io_port = 0xFF;
+  host->base = p->mbase;
+  host->irq = p->irq;
+  if (p->features & AHC_WIDE)
+  {
+    host->max_id = 16;
+  }
+  if (p->features & AHC_TWIN)
+  {
+    host->max_channel = 1;
+  }
+
+  p->host = host;
+  p->host_no = host->host_no;
+  host->unique_id = p->instance;
+  p->isr_count = 0;
+  p->next = NULL;
+  p->completeq.head = NULL;
+  p->completeq.tail = NULL;
+  scbq_init(&p->scb_data->free_scbs);
+  scbq_init(&p->waiting_scbs);
+  INIT_LIST_HEAD(&p->aic_devs);
+
+  /*
+   * We currently have no commands of any type
+   */
+  p->qinfifonext = 0;
+  p->qoutfifonext = 0;
+
+  printk(KERN_INFO "(scsi%d) <%s> found at ", p->host_no,
+    board_names[p->board_name_index]);
+  switch(p->chip)
+  {
+    case (AHC_AIC7770|AHC_EISA):
+      printk("EISA slot %d\n", p->pci_device_fn);
+      break;
+    case (AHC_AIC7770|AHC_VL):
+      printk("VLB slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      printk("PCI %d/%d/%d\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
+        PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if (p->features & AHC_TWIN)
+  {
+    printk(KERN_INFO "(scsi%d) Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+           p->host_no, p->scsi_id, p->scsi_id_b);
+  }
+  else
+  {
+    char *channel;
+
+    channel = "";
+
+    if ((p->flags & AHC_MULTI_CHANNEL) != 0)
+    {
+      channel = " A";
+
+      if ( (p->flags & (AHC_CHNLB|AHC_CHNLC)) != 0 )
+      {
+        channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+    }
+    if (p->features & AHC_WIDE)
+    {
+      printk(KERN_INFO "(scsi%d) Wide ", p->host_no);
+    }
+    else
+    {
+      printk(KERN_INFO "(scsi%d) Narrow ", p->host_no);
+    }
+    printk("Channel%s, SCSI ID=%d, ", channel, p->scsi_id);
+  }
+  aic_outb(p, 0, SEQ_FLAGS);
+
+  detect_maxscb(p);
+
+  printk("%d/%d SCBs\n", p->scb_data->maxhscbs, p->scb_data->maxscbs);
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+  {
+    printk(KERN_INFO "(scsi%d) BIOS %sabled, IO Port 0x%lx, IRQ %d\n",
+      p->host_no, (p->flags & AHC_BIOS_ENABLED) ? "en" : "dis",
+      p->base, p->irq);
+    printk(KERN_INFO "(scsi%d) IO Memory at 0x%lx, MMAP Memory at %p\n",
+      p->host_no, p->mbase, p->maddr);
+  }
+
+#ifdef CONFIG_PCI
+  /*
+   * Now that we know our instance number, we can set the flags we need to
+   * force termination if need be.
+   */
+  if (aic7xxx_stpwlev != -1)
+  {
+    /*
+     * This option only applies to PCI controllers.
+     */
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+    {
+      unsigned char devconfig;
+
+      pci_read_config_byte(p->pdev, DEVCONFIG, &devconfig);
+      if ( (aic7xxx_stpwlev >> p->instance) & 0x01 )
+      {
+        devconfig |= STPWLEVEL;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force setting STPWLEVEL bit\n", p->host_no);
+      }
+      else
+      {
+        devconfig &= ~STPWLEVEL;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("(scsi%d) Force clearing STPWLEVEL bit\n", p->host_no);
+      }
+      pci_write_config_byte(p->pdev, DEVCONFIG, devconfig);
+    }
+  }
+#endif
+
+  /*
+   * That took care of devconfig and stpwlev, now for the actual termination
+   * settings.
+   */
+  if (aic7xxx_override_term != -1)
+  {
+    /*
+     * Again, this only applies to PCI controllers.  We don't have problems
+     * with the termination on 274x controllers to the best of my knowledge.
+     */
+    if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI)
+    {
+      unsigned char term_override;
+
+      term_override = ( (aic7xxx_override_term >> (p->instance * 4)) & 0x0f);
+      p->adapter_control &= 
+        ~(CFSTERM|CFWSTERM|CFLVDSTERM|CFAUTOTERM|CFSEAUTOTERM);
+      if ( (p->features & AHC_ULTRA2) && (term_override & 0x0c) )
+      {
+        p->adapter_control |= CFLVDSTERM;
+      }
+      if (term_override & 0x02)
+      {
+        p->adapter_control |= CFWSTERM;
+      }
+      if (term_override & 0x01)
+      {
+        p->adapter_control |= CFSTERM;
+      }
+    }
+  }
+
+  if ( (p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1) )
+  {
+    if (p->features & AHC_SPIOCAP)
+    {
+      if ( aic_inb(p, SPIOCAP) & SSPIOCPS )
+      /*
+       * Update the settings in sxfrctl1 to match the termination
+       * settings.
+       */
+        configure_termination(p);
+    }
+    else if ((p->chip & AHC_CHIPID_MASK) >= AHC_AIC7870)
+    {
+      configure_termination(p);
+    }
+  }
+
+  /*
+   * Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
+   */
+  if (p->features & AHC_TWIN)
+  {
+    /* Select channel B */
+    aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
+
+    if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+      term = (aic_inb(p, SXFRCTL1) & STPWEN);
+    else
+      term = ((p->flags & AHC_TERM_ENB_B) ? STPWEN : 0);
+
+    aic_outb(p, p->scsi_id_b, SCSIID);
+    scsi_conf = aic_inb(p, SCSICONF + 1);
+    aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+    aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
+         ENSTIMER | ACTNEGEN, SXFRCTL1);
+    aic_outb(p, 0, SIMODE0);
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+    aic_outb(p, 0, SCSIRATE);
+
+    /* Select channel A */
+    aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
+  }
+
+  if (p->features & AHC_ULTRA2)
+  {
+    aic_outb(p, p->scsi_id, SCSIID_ULTRA2);
+  }
+  else
+  {
+    aic_outb(p, p->scsi_id, SCSIID);
+  }
+  if ((p->flags & AHC_SEEPROM_FOUND) || (aic7xxx_override_term != -1))
+    term = (aic_inb(p, SXFRCTL1) & STPWEN);
+  else
+    term = ((p->flags & (AHC_TERM_ENB_A|AHC_TERM_ENB_LVD)) ? STPWEN : 0);
+  scsi_conf = aic_inb(p, SCSICONF);
+  aic_outb(p, DFON | SPIOEN, SXFRCTL0);
+  aic_outb(p, (scsi_conf & ENSPCHK) | aic7xxx_seltime | term | 
+       ENSTIMER | ACTNEGEN, SXFRCTL1);
+  aic_outb(p, 0, SIMODE0);
+  /*
+   * If we are a cardbus adapter then don't enable SCSI reset detection.
+   * We shouldn't likely be sharing SCSI busses with someone else, and
+   * if we don't have a cable currently plugged into the controller then
+   * we won't have a power source for the SCSI termination, which means
+   * we'll see infinite incoming bus resets.
+   */
+  if(p->flags & AHC_NO_STPWEN)
+    aic_outb(p, ENSELTIMO | ENSCSIPERR, SIMODE1);
+  else
+    aic_outb(p, ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1);
+  aic_outb(p, 0, SCSIRATE);
+  if ( p->features & AHC_ULTRA2)
+    aic_outb(p, 0, SCSIOFFSET);
+
+  /*
+   * Look at the information that board initialization or the board
+   * BIOS has left us. In the lower four bits of each target's
+   * scratch space any value other than 0 indicates that we should
+   * initiate synchronous transfers. If it's zero, the user or the
+   * BIOS has decided to disable synchronous negotiation to that
+   * target so we don't activate the needsdtr flag.
+   */
+  if ((p->features & (AHC_TWIN|AHC_WIDE)) == 0)
+  {
+    max_targets = 8;
+  }
+  else
+  {
+    max_targets = 16;
+  }
+
+  if (!(aic7xxx_no_reset))
+  {
+    /*
+     * If we reset the bus, then clear the transfer settings, else leave
+     * them be.
+     */
+    aic_outb(p, 0, ULTRA_ENB);
+    aic_outb(p, 0, ULTRA_ENB + 1);
+    p->ultraenb = 0;
+  }
+
+  /*
+   * Allocate enough hardware scbs to handle the maximum number of
+   * concurrent transactions we can have.  We have to make sure that
+   * the allocated memory is contiguous memory.  The Linux kmalloc
+   * routine should only allocate contiguous memory, but note that
+   * this could be a problem if kmalloc() is changed.
+   */
+  {
+    size_t array_size;
+    unsigned int hscb_physaddr;
+
+    array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+    if (p->scb_data->hscbs == NULL)
+    {
+      /* pci_alloc_consistent enforces the alignment already and
+       * clears the area as well.
+       */
+      p->scb_data->hscbs = pci_alloc_consistent(p->pdev, array_size,
+						&p->scb_data->hscbs_dma);
+      /* We have to use pci_free_consistent, not kfree */
+      p->scb_data->hscb_kmalloc_ptr = NULL;
+      p->scb_data->hscbs_dma_len = array_size;
+    }
+    if (p->scb_data->hscbs == NULL)
+    {
+      printk("(scsi%d) Unable to allocate hardware SCB array; "
+             "failing detection.\n", p->host_no);
+      aic_outb(p, 0, SIMODE1);
+      p->irq = 0;
+      return(0);
+    }
+
+    hscb_physaddr = p->scb_data->hscbs_dma;
+    aic_outb(p, hscb_physaddr & 0xFF, HSCB_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, HSCB_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, HSCB_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, HSCB_ADDR + 3);
+
+    /* Set up the fifo areas at the same time */
+    p->untagged_scbs = pci_alloc_consistent(p->pdev, 3*256, &p->fifo_dma);
+    if (p->untagged_scbs == NULL)
+    {
+      printk("(scsi%d) Unable to allocate hardware FIFO arrays; "
+             "failing detection.\n", p->host_no);
+      p->irq = 0;
+      return(0);
+    }
+
+    p->qoutfifo = p->untagged_scbs + 256;
+    p->qinfifo = p->qoutfifo + 256;
+    for (i = 0; i < 256; i++)
+    {
+      p->untagged_scbs[i] = SCB_LIST_NULL;
+      p->qinfifo[i] = SCB_LIST_NULL;
+      p->qoutfifo[i] = SCB_LIST_NULL;
+    }
+
+    hscb_physaddr = p->fifo_dma;
+    aic_outb(p, hscb_physaddr & 0xFF, SCBID_ADDR);
+    aic_outb(p, (hscb_physaddr >> 8) & 0xFF, SCBID_ADDR + 1);
+    aic_outb(p, (hscb_physaddr >> 16) & 0xFF, SCBID_ADDR + 2);
+    aic_outb(p, (hscb_physaddr >> 24) & 0xFF, SCBID_ADDR + 3);
+  }
+
+  /* The Q-FIFOs we just set up are all empty */
+  aic_outb(p, 0, QINPOS);
+  aic_outb(p, 0, KERNEL_QINPOS);
+  aic_outb(p, 0, QOUTPOS);
+
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, SCB_QSIZE_256, QOFF_CTLSTA);
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
+  }
+
+  /*
+   * We don't have any waiting selections or disconnected SCBs.
+   */
+  aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+  aic_outb(p, SCB_LIST_NULL, DISCONNECTED_SCBH);
+
+  /*
+   * Message out buffer starts empty
+   */
+  aic_outb(p, MSG_NOOP, MSG_OUT);
+  aic_outb(p, MSG_NOOP, LAST_MSG);
+
+  /*
+   * Set all the other asundry items that haven't been set yet.
+   * This includes just dumping init values to a lot of registers simply
+   * to make sure they've been touched and are ready for use parity wise
+   * speaking.
+   */
+  aic_outb(p, 0, TMODE_CMDADDR);
+  aic_outb(p, 0, TMODE_CMDADDR + 1);
+  aic_outb(p, 0, TMODE_CMDADDR + 2);
+  aic_outb(p, 0, TMODE_CMDADDR + 3);
+  aic_outb(p, 0, TMODE_CMDADDR_NEXT);
+
+  /*
+   * Link us into the list of valid hosts
+   */
+  p->next = first_aic7xxx;
+  first_aic7xxx = p;
+
+  /*
+   * Allocate the first set of scbs for this controller.  This is to stream-
+   * line code elsewhere in the driver.  If we have to check for the existence
+   * of scbs in certain code sections, it slows things down.  However, as
+   * soon as we register the IRQ for this card, we could get an interrupt that
+   * includes possibly the SCSI_RSTI interrupt.  If we catch that interrupt
+   * then we are likely to segfault if we don't have at least one chunk of
+   * SCBs allocated or add checks all through the reset code to make sure
+   * that the SCBs have been allocated which is an invalid running condition
+   * and therefore I think it's preferable to simply pre-allocate the first
+   * chunk of SCBs.
+   */
+  aic7xxx_allocate_scb(p);
+
+  /*
+   * Load the sequencer program, then re-enable the board -
+   * resetting the AIC-7770 disables it, leaving the lights
+   * on with nobody home.
+   */
+  aic7xxx_loadseq(p);
+
+  /*
+   * Make sure the AUTOFLUSHDIS bit is *not* set in the SBLKCTL register
+   */
+  aic_outb(p, aic_inb(p, SBLKCTL) & ~AUTOFLUSHDIS, SBLKCTL);
+
+  if ( (p->chip & AHC_CHIPID_MASK) == AHC_AIC7770 )
+  {
+    aic_outb(p, ENABLE, BCTL);  /* Enable the boards BUS drivers. */
+  }
+
+  if ( !(aic7xxx_no_reset) )
+  {
+    if (p->features & AHC_TWIN)
+    {
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+        printk(KERN_INFO "(scsi%d) Resetting channel B\n", p->host_no);
+      aic_outb(p, aic_inb(p, SBLKCTL) | SELBUSB, SBLKCTL);
+      aic7xxx_reset_current_bus(p);
+      aic_outb(p, aic_inb(p, SBLKCTL) & ~SELBUSB, SBLKCTL);
+    }
+    /* Reset SCSI bus A. */
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {  /* In case we are a 3940, 3985, or 7895, print the right channel */
+      char *channel = "";
+      if (p->flags & AHC_MULTI_CHANNEL)
+      {
+        channel = " A";
+        if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+          channel = (p->flags & AHC_CHNLB) ? " B" : " C";
+      }
+      printk(KERN_INFO "(scsi%d) Resetting channel%s\n", p->host_no, channel);
+    }
+    
+    aic7xxx_reset_current_bus(p);
+
+  }
+  else
+  {
+    if (!reset_delay)
+    {
+      printk(KERN_INFO "(scsi%d) Not resetting SCSI bus.  Note: Don't use "
+             "the no_reset\n", p->host_no);
+      printk(KERN_INFO "(scsi%d) option unless you have a verifiable need "
+             "for it.\n", p->host_no);
+    }
+  }
+  
+  /*
+   * Register IRQ with the kernel.  Only allow sharing IRQs with
+   * PCI devices.
+   */
+  if (!(p->chip & AHC_PCI))
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, 0, "aic7xxx", p));
+  }
+  else
+  {
+    result = (request_irq(p->irq, do_aic7xxx_isr, SA_SHIRQ,
+              "aic7xxx", p));
+    if (result < 0)
+    {
+      result = (request_irq(p->irq, do_aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
+              "aic7xxx", p));
+    }
+  }
+  if (result < 0)
+  {
+    printk(KERN_WARNING "(scsi%d) Couldn't register IRQ %d, ignoring "
+           "controller.\n", p->host_no, p->irq);
+    aic_outb(p, 0, SIMODE1);
+    p->irq = 0;
+    return (0);
+  }
+
+  if(aic_inb(p, INTSTAT) & INT_PEND)
+    printk(INFO_LEAD "spurious interrupt during configuration, cleared.\n",
+      p->host_no, -1, -1 , -1);
+  aic7xxx_clear_intstat(p);
+
+  unpause_sequencer(p, /* unpause_always */ TRUE);
+
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_chip_reset
+ *
+ * Description:
+ *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
+ *   is paused upon return.
+ *-F*************************************************************************/
+static int
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+  unsigned char sblkctl;
+  int wait;
+
+  /*
+   * For some 274x boards, we must clear the CHIPRST bit and pause
+   * the sequencer. For some reason, this makes the driver work.
+   */
+  aic_outb(p, PAUSE | CHIPRST, HCNTRL);
+
+  /*
+   * In the future, we may call this function as a last resort for
+   * error handling.  Let's be nice and not do any unnecessary delays.
+   */
+  wait = 1000;  /* 1 msec (1000 * 1 msec) */
+  while (--wait && !(aic_inb(p, HCNTRL) & CHIPRSTACK))
+  {
+    udelay(1);  /* 1 usec */
+  }
+
+  pause_sequencer(p);
+
+  sblkctl = aic_inb(p, SBLKCTL) & (SELBUSB|SELWIDE);
+  if (p->chip & AHC_PCI)
+    sblkctl &= ~SELBUSB;
+  switch( sblkctl )
+  {
+    case 0:  /* normal narrow card */
+      break;
+    case 2:  /* Wide card */
+      p->features |= AHC_WIDE;
+      break;
+    case 8:  /* Twin card */
+      p->features |= AHC_TWIN;
+      p->flags |= AHC_MULTI_CHANNEL;
+      break;
+    default: /* hmmm...we don't know what this is */
+      printk(KERN_WARNING "aic7xxx: Unsupported adapter type %d, ignoring.\n",
+        aic_inb(p, SBLKCTL) & 0x0a);
+      return(-1);
+  }
+  return(0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_alloc
+ *
+ * Description:
+ *   Allocate and initialize a host structure.  Returns NULL upon error
+ *   and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, struct aic7xxx_host *temp)
+{
+  struct aic7xxx_host *p = NULL;
+  struct Scsi_Host *host;
+
+  /*
+   * Allocate a storage area by registering us with the mid-level
+   * SCSI layer.
+   */
+  host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+  if (host != NULL)
+  {
+    p = (struct aic7xxx_host *) host->hostdata;
+    memset(p, 0, sizeof(struct aic7xxx_host));
+    *p = *temp;
+    p->host = host;
+
+    p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+    if (p->scb_data != NULL)
+    {
+      memset(p->scb_data, 0, sizeof(scb_data_type));
+      scbq_init (&p->scb_data->free_scbs);
+    }
+    else
+    {
+      /*
+       * For some reason we don't have enough memory.  Free the
+       * allocated memory for the aic7xxx_host struct, and return NULL.
+       */
+      release_region(p->base, MAXREG - MINREG);
+      scsi_unregister(host);
+      return(NULL);
+    }
+    p->host_no = host->host_no;
+  }
+  scsi_set_device(host, &p->pdev->dev);
+  return (p);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_free
+ *
+ * Description:
+ *   Frees and releases all resources associated with an instance of
+ *   the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free(struct aic7xxx_host *p)
+{
+  int i;
+
+  /*
+   * Free the allocated hardware SCB space.
+   */
+  if (p->scb_data != NULL)
+  {
+    struct aic7xxx_scb_dma *scb_dma = NULL;
+    if (p->scb_data->hscbs != NULL)
+    {
+      pci_free_consistent(p->pdev, p->scb_data->hscbs_dma_len,
+			  p->scb_data->hscbs, p->scb_data->hscbs_dma);
+      p->scb_data->hscbs = p->scb_data->hscb_kmalloc_ptr = NULL;
+    }
+    /*
+     * Free the driver SCBs.  These were allocated on an as-need
+     * basis.  We allocated these in groups depending on how many
+     * we could fit into a given amount of RAM.  The tail SCB for
+     * these allocations has a pointer to the alloced area.
+     */
+    for (i = 0; i < p->scb_data->numscbs; i++)
+    {
+      if (p->scb_data->scb_array[i]->scb_dma != scb_dma)
+      {
+	scb_dma = p->scb_data->scb_array[i]->scb_dma;
+	pci_free_consistent(p->pdev, scb_dma->dma_len,
+			    (void *)((unsigned long)scb_dma->dma_address
+                                     - scb_dma->dma_offset),
+			    scb_dma->dma_address);
+      }
+      if (p->scb_data->scb_array[i]->kmalloc_ptr != NULL)
+        kfree(p->scb_data->scb_array[i]->kmalloc_ptr);
+      p->scb_data->scb_array[i] = NULL;
+    }
+  
+    /*
+     * Free the SCB data area.
+     */
+    kfree(p->scb_data);
+  }
+
+  pci_free_consistent(p->pdev, 3*256, (void *)p->untagged_scbs, p->fifo_dma);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_load_seeprom
+ *
+ * Description:
+ *   Load the seeprom and configure adapter and target settings.
+ *   Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_load_seeprom(struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+  int have_seeprom = 0;
+  int i, max_targets, mask;
+  unsigned char scsirate, scsi_conf;
+  unsigned short scarray[128];
+  struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+  if (aic7xxx_verbose & VERBOSE_PROBE2)
+  {
+    printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+  }
+  switch (p->chip)
+  {
+    case (AHC_AIC7770|AHC_EISA):  /* None of these adapters have seeproms. */
+      if (aic_inb(p, SCSICONF) & TERM_ENB)
+        p->flags |= AHC_TERM_ENB_A;
+      if ( (p->features & AHC_TWIN) && (aic_inb(p, SCSICONF + 1) & TERM_ENB) )
+        p->flags |= AHC_TERM_ENB_B;
+      break;
+
+    case (AHC_AIC7770|AHC_VL):
+      have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+      break;
+
+    default:
+      have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                  scarray, p->sc_size, p->sc_type);
+      if (!have_seeprom)
+      {
+        if(p->sc_type == C46)
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C56_66);
+        else
+          have_seeprom = read_seeprom(p, (p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                      scarray, p->sc_size, C46);
+      }
+      if (!have_seeprom)
+      {
+        p->sc_size = 128;
+        have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                    scarray, p->sc_size, p->sc_type);
+        if (!have_seeprom)
+        {
+          if(p->sc_type == C46)
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C56_66);
+          else
+            have_seeprom = read_seeprom(p, 4*(p->flags & (AHC_CHNLB|AHC_CHNLC)),
+                                        scarray, p->sc_size, C46);
+        }
+      }
+      break;
+  }
+
+  if (!have_seeprom)
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("\naic7xxx: No SEEPROM available.\n");
+    }
+    p->flags |= AHC_NEWEEPROM_FMT;
+    if (aic_inb(p, SCSISEQ) == 0)
+    {
+      p->flags |= AHC_USEDEFAULTS;
+      p->flags &= ~AHC_BIOS_ENABLED;
+      p->scsi_id = p->scsi_id_b = 7;
+      *sxfrctl1 |= STPWEN;
+      if (aic7xxx_verbose & VERBOSE_PROBE2)
+      {
+        printk("aic7xxx: Using default values.\n");
+      }
+    }
+    else if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("aic7xxx: Using leftover BIOS values.\n");
+    }
+    if ( ((p->chip & ~AHC_CHIPID_MASK) == AHC_PCI) && (*sxfrctl1 & STPWEN) )
+    {
+      p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      sc->adapter_control &= ~CFAUTOTERM;
+      sc->adapter_control |= CFSTERM | CFWSTERM | CFLVDSTERM;
+    }
+    if (aic7xxx_extended)
+      p->flags |= (AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+    else
+      p->flags &= ~(AHC_EXTEND_TRANS_A | AHC_EXTEND_TRANS_B);
+  }
+  else
+  {
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk("done\n");
+    }
+
+    /*
+     * Note things in our flags
+     */
+    p->flags |= AHC_SEEPROM_FOUND;
+
+    /*
+     * Update the settings in sxfrctl1 to match the termination settings.
+     */
+    *sxfrctl1 = 0;
+
+    /*
+     * Get our SCSI ID from the SEEPROM setting...
+     */
+    p->scsi_id = (sc->brtime_id & CFSCSIID);
+
+    /*
+     * First process the settings that are different between the VLB
+     * and PCI adapter seeproms.
+     */
+    if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7770)
+    {
+      /* VLB adapter seeproms */
+      if (sc->bios_control & CF284XEXTEND)
+        p->flags |= AHC_EXTEND_TRANS_A;
+
+      if (sc->adapter_control & CF284XSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      }
+    }
+    else
+    {
+      /* PCI adapter seeproms */
+      if (sc->bios_control & CFEXTEND)
+        p->flags |= AHC_EXTEND_TRANS_A;
+      if (sc->bios_control & CFBIOSEN)
+        p->flags |= AHC_BIOS_ENABLED;
+      else
+        p->flags &= ~AHC_BIOS_ENABLED;
+
+      if (sc->adapter_control & CFSTERM)
+      {
+        *sxfrctl1 |= STPWEN;
+        p->flags |= AHC_TERM_ENB_SE_LOW | AHC_TERM_ENB_SE_HIGH;
+      }
+    }
+    memcpy(&p->sc, sc, sizeof(struct seeprom_config));
+  }
+
+  p->discenable = 0;
+
+  /*
+   * Limit to 16 targets just in case.  The 2842 for one is known to
+   * blow the max_targets setting, future cards might also.
+   */
+  max_targets = ((p->features & (AHC_TWIN | AHC_WIDE)) ? 16 : 8);
+
+  if (have_seeprom)
+  {
+    for (i = 0; i < max_targets; i++)
+    {
+      if( ((p->features & AHC_ULTRA) &&
+          !(sc->adapter_control & CFULTRAEN) &&
+           (sc->device_flags[i] & CFSYNCHISULTRA)) ||
+          (sc->device_flags[i] & CFNEWULTRAFORMAT) )
+      {
+        p->flags |= AHC_NEWEEPROM_FMT;
+        break;
+      }
+    }
+  }
+
+  for (i = 0; i < max_targets; i++)
+  {
+    mask = (0x01 << i);
+    if (!have_seeprom)
+    {
+      if (aic_inb(p, SCSISEQ) != 0)
+      {
+        /*
+         * OK...the BIOS set things up and left behind the settings we need.
+         * Just make our sc->device_flags[i] entry match what the card has
+         * set for this device.
+         */
+	p->discenable =
+	  ~(aic_inb(p, DISC_DSB) | (aic_inb(p, DISC_DSB + 1) << 8) );
+        p->ultraenb =
+          (aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8) );
+	sc->device_flags[i] = (p->discenable & mask) ? CFDISC : 0;
+        if (aic_inb(p, TARG_SCSIRATE + i) & WIDEXFER)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA2)
+        {
+          if (aic_inb(p, TARG_OFFSET + i))
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            sc->device_flags[i] |= (aic_inb(p, TARG_SCSIRATE + i) & 0x07);
+            if ( (aic_inb(p, TARG_SCSIRATE + i) & 0x18) == 0x18 )
+              sc->device_flags[i] |= CFSYNCHISULTRA;
+          }
+        }
+        else
+        {
+          if (aic_inb(p, TARG_SCSIRATE + i) & ~WIDEXFER)
+          {
+            sc->device_flags[i] |= CFSYNCH;
+            if (p->features & AHC_ULTRA)
+              sc->device_flags[i] |= ((p->ultraenb & mask) ?
+                                      CFSYNCHISULTRA : 0);
+          }
+        }
+      }
+      else
+      {
+        /*
+         * Assume the BIOS has NOT been run on this card and nothing between
+         * the card and the devices is configured yet.
+         */
+        sc->device_flags[i] = CFDISC;
+        if (p->features & AHC_WIDE)
+          sc->device_flags[i] |= CFWIDEB;
+        if (p->features & AHC_ULTRA3)
+          sc->device_flags[i] |= 2;
+        else if (p->features & AHC_ULTRA2)
+          sc->device_flags[i] |= 3;
+        else if (p->features & AHC_ULTRA)
+          sc->device_flags[i] |= CFSYNCHISULTRA;
+        sc->device_flags[i] |= CFSYNCH;
+        aic_outb(p, 0, TARG_SCSIRATE + i);
+        if (p->features & AHC_ULTRA2)
+          aic_outb(p, 0, TARG_OFFSET + i);
+      }
+    }
+    if (sc->device_flags[i] & CFDISC)
+    {
+      p->discenable |= mask;
+    }
+    if (p->flags & AHC_NEWEEPROM_FMT)
+    {
+      if ( !(p->features & AHC_ULTRA2) )
+      {
+        /*
+         * I know of two different Ultra BIOSes that do this differently.
+         * One on the Gigabyte 6BXU mb that wants flags[i] & CFXFER to
+         * be == to 0x03 and SYNCHISULTRA to be true to mean 40MByte/s
+         * while on the IBM Netfinity 5000 they want the same thing
+         * to be something else, while flags[i] & CFXFER == 0x03 and
+         * SYNCHISULTRA false should be 40MByte/s.  So, we set both to
+         * 40MByte/s and the lower speeds be damned.  People will have
+         * to select around the conversely mapped lower speeds in order
+         * to select lower speeds on these boards.
+         */
+        if ( (sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+            ((sc->device_flags[i] & CFXFER) == 0x03) )
+        {
+          sc->device_flags[i] &= ~CFXFER;
+          sc->device_flags[i] |= CFSYNCHISULTRA;
+        }
+        if (sc->device_flags[i] & CFSYNCHISULTRA)
+        {
+          p->ultraenb |= mask;
+        }
+      }
+      else if ( !(sc->device_flags[i] & CFNEWULTRAFORMAT) &&
+                 (p->features & AHC_ULTRA2) &&
+		 (sc->device_flags[i] & CFSYNCHISULTRA) )
+      {
+        p->ultraenb |= mask;
+      }
+    }
+    else if (sc->adapter_control & CFULTRAEN)
+    {
+      p->ultraenb |= mask;
+    }
+    if ( (sc->device_flags[i] & CFSYNCH) == 0)
+    {
+      sc->device_flags[i] &= ~CFXFER;
+      p->ultraenb &= ~mask;
+      p->user[i].offset = 0;
+      p->user[i].period = 0;
+      p->user[i].options = 0;
+    }
+    else
+    {
+      if (p->features & AHC_ULTRA3)
+      {
+        p->user[i].offset = MAX_OFFSET_ULTRA2;
+        if( (sc->device_flags[i] & CFXFER) < 0x03 )
+        {
+          scsirate = (sc->device_flags[i] & CFXFER);
+          p->user[i].options = MSG_EXT_PPR_OPTION_DT_CRC;
+        }
+        else
+        {
+          scsirate = (sc->device_flags[i] & CFXFER) |
+                     ((p->ultraenb & mask) ? 0x18 : 0x10);
+          p->user[i].options = 0;
+        }
+        p->user[i].period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA3);
+      }
+      else if (p->features & AHC_ULTRA2)
+      {
+        p->user[i].offset = MAX_OFFSET_ULTRA2;
+        scsirate = (sc->device_flags[i] & CFXFER) |
+                   ((p->ultraenb & mask) ? 0x18 : 0x10);
+        p->user[i].options = 0;
+        p->user[i].period = aic7xxx_find_period(p, scsirate,
+                                       AHC_SYNCRATE_ULTRA2);
+      }
+      else
+      {
+        scsirate = (sc->device_flags[i] & CFXFER) << 4;
+        p->user[i].options = 0;
+        p->user[i].offset = MAX_OFFSET_8BIT;
+        if (p->features & AHC_ULTRA)
+        {
+          short ultraenb;
+          ultraenb = aic_inb(p, ULTRA_ENB) |
+            (aic_inb(p, ULTRA_ENB + 1) << 8);
+          p->user[i].period = aic7xxx_find_period(p, scsirate,
+                                          (p->ultraenb & mask) ?
+                                          AHC_SYNCRATE_ULTRA :
+                                          AHC_SYNCRATE_FAST);
+        }
+        else
+          p->user[i].period = aic7xxx_find_period(p, scsirate,
+			  		  AHC_SYNCRATE_FAST);
+      }
+    }
+    if ( (sc->device_flags[i] & CFWIDEB) && (p->features & AHC_WIDE) )
+    {
+      p->user[i].width = MSG_EXT_WDTR_BUS_16_BIT;
+    }
+    else
+    {
+      p->user[i].width = MSG_EXT_WDTR_BUS_8_BIT;
+    }
+  }
+  aic_outb(p, ~(p->discenable & 0xFF), DISC_DSB);
+  aic_outb(p, ~((p->discenable >> 8) & 0xFF), DISC_DSB + 1);
+
+  /*
+   * We set the p->ultraenb from the SEEPROM to begin with, but now we make
+   * it match what is already down in the card.  If we are doing a reset
+   * on the card then this will get put back to a default state anyway.
+   * This allows us to not have to pre-emptively negotiate when using the
+   * no_reset option.
+   */
+  if (p->features & AHC_ULTRA)
+    p->ultraenb = aic_inb(p, ULTRA_ENB) | (aic_inb(p, ULTRA_ENB + 1) << 8);
+
+  
+  scsi_conf = (p->scsi_id & HSCSIID);
+
+  if(have_seeprom)
+  {
+    p->adapter_control = sc->adapter_control;
+    p->bios_control = sc->bios_control;
+
+    switch (p->chip & AHC_CHIPID_MASK)
+    {
+      case AHC_AIC7895:
+      case AHC_AIC7896:
+      case AHC_AIC7899:
+        if (p->adapter_control & CFBPRIMARY)
+          p->flags |= AHC_CHANNEL_B_PRIMARY;
+      default:
+        break;
+    }
+
+    if (sc->adapter_control & CFSPARITY)
+      scsi_conf |= ENSPCHK;
+  }
+  else
+  {
+    scsi_conf |= ENSPCHK | RESET_SCSI;
+  }
+
+  /*
+   * Only set the SCSICONF and SCSICONF + 1 registers if we are a PCI card.
+   * The 2842 and 2742 cards already have these registers set and we don't
+   * want to muck with them since we don't set all the bits they do.
+   */
+  if ( (p->chip & ~AHC_CHIPID_MASK) == AHC_PCI )
+  {
+    /* Set the host ID */
+    aic_outb(p, scsi_conf, SCSICONF);
+    /* In case we are a wide card */
+    aic_outb(p, p->scsi_id, SCSICONF + 1);
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_configure_bugs
+ *
+ * Description:
+ *   Take the card passed in and set the appropriate bug flags based upon
+ *   the card model.  Also make any changes needed to device registers or
+ *   PCI registers while we are here.
+ *-F*************************************************************************/
+static void
+aic7xxx_configure_bugs(struct aic7xxx_host *p)
+{
+  unsigned short tmp_word;
+ 
+  switch(p->chip & AHC_CHIPID_MASK)
+  {
+    case AHC_AIC7860:
+      p->bugs |= AHC_BUG_PCI_2_1_RETRY;
+      /* fall through */
+    case AHC_AIC7850:
+    case AHC_AIC7870:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7880:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7890:
+      p->bugs |= AHC_BUG_AUTOFLUSH | AHC_BUG_CACHETHEN;
+      break;
+    case AHC_AIC7892:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    case AHC_AIC7895:
+      p->bugs |= AHC_BUG_TMODE_WIDEODD | AHC_BUG_PCI_2_1_RETRY |
+                 AHC_BUG_CACHETHEN | AHC_BUG_PCI_MWI;
+      break;
+    case AHC_AIC7896:
+      p->bugs |= AHC_BUG_CACHETHEN_DIS;
+      break;
+    case AHC_AIC7899:
+      p->bugs |= AHC_BUG_SCBCHAN_UPLOAD;
+      break;
+    default:
+      /* Nothing to do */
+      break;
+  }
+
+  /*
+   * Now handle the bugs that require PCI register or card register tweaks
+   */
+  pci_read_config_word(p->pdev, PCI_COMMAND, &tmp_word);
+  if(p->bugs & AHC_BUG_PCI_MWI)
+  {
+    tmp_word &= ~PCI_COMMAND_INVALIDATE;
+  }
+  else
+  {
+    tmp_word |= PCI_COMMAND_INVALIDATE;
+  }
+  pci_write_config_word(p->pdev, PCI_COMMAND, tmp_word);
+
+  if(p->bugs & AHC_BUG_CACHETHEN)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) & ~CACHETHEN, DSCOMMAND0);
+  }
+  else if (p->bugs & AHC_BUG_CACHETHEN_DIS)
+  {
+    aic_outb(p, aic_inb(p, DSCOMMAND0) | CACHETHEN, DSCOMMAND0);
+  }
+
+  return;
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_detect
+ *
+ * Description:
+ *   Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe().  A sequence of
+ *       probe(), attach()/detach(), and init() makes more sense than
+ *       one do-it-all function.  This may be useful when (and if) the
+ *       mid-level SCSI code is overhauled.
+ *-F*************************************************************************/
+static int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+  struct aic7xxx_host *temp_p = NULL;
+  struct aic7xxx_host *current_p = NULL;
+  struct aic7xxx_host *list_p = NULL;
+  int found = 0;
+#if defined(__i386__) || defined(__alpha__)
+  ahc_flag_type flags = 0;
+  int type;
+#endif
+  unsigned char sxfrctl1;
+#if defined(__i386__) || defined(__alpha__)
+  unsigned char hcntrl, hostconf;
+  unsigned int slot, base;
+#endif
+
+#ifdef MODULE
+  /*
+   * If we are called as a module, the aic7xxx pointer may not be null
+   * and it would point to our bootup string, just like on the lilo
+   * command line.  IF not NULL, then process this config string with
+   * aic7xxx_setup
+   */
+  if(aic7xxx)
+    aic7xxx_setup(aic7xxx);
+#endif
+
+  template->proc_name = "aic7xxx";
+  template->sg_tablesize = AIC7XXX_MAX_SG;
+
+
+#ifdef CONFIG_PCI
+  /*
+   * PCI-bus probe.
+   */
+  {
+    static struct
+    {
+      unsigned short      vendor_id;
+      unsigned short      device_id;
+      ahc_chip            chip;
+      ahc_flag_type       flags;
+      ahc_feature         features;
+      int                 board_name_index;
+      unsigned short      seeprom_size;
+      unsigned short      seeprom_type;
+    } const aic_pdevs[] = {
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7810, AHC_NONE,
+       AHC_FNONE, AHC_FENONE,                                1,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AHC_AIC7850,
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         5,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+       AHC_PAGESCBS, AHC_AIC7850_FE,                         6,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7821, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_3860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_38602, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7860_FE,                                       7,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7860_FE,                                       8,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7870_FE,                                       9,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     10,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      11,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7873, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7870_FE,                                      12,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7874, AHC_AIC7870,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7870_FE,     13,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7880, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MOTHERBOARD,
+       AHC_AIC7880_FE,                                      14,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7881, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     15,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7882, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      16,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7883, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7880_FE,                                      17,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7885, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7886, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7887, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE | AHC_NEW_AUTOTERM, 19,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7888, AHC_AIC7880,
+       AHC_PAGESCBS | AHC_BIOS_ENABLED, AHC_AIC7880_FE,     18,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7895, AHC_AIC7895,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7895_FE,                                      20,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      21,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7890B, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      21,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2930U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      22,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_2940U2, AHC_AIC7890,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7890_FE,                                      23,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7896, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      24,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3940U2, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      25,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_3950U2D, AHC_AIC7896,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7896_FE,                                      26,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_1480A, AHC_AIC7860,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_NO_STPWEN,
+       AHC_AIC7860_FE,                                      27,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892A, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892B, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892D, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7892P, AHC_AIC7892,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,
+       AHC_AIC7892_FE,                                      28,
+       32, C46 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899A, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899B, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899D, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+      {PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_7899P, AHC_AIC7899,
+       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED | AHC_MULTI_CHANNEL,
+       AHC_AIC7899_FE,                                      29,
+       32, C56_66 },
+    };
+
+    unsigned short command;
+    unsigned int  devconfig, i, oldverbose;
+    struct pci_dev *pdev = NULL;
+
+    for (i = 0; i < ARRAY_SIZE(aic_pdevs); i++)
+    {
+      pdev = NULL;
+      while ((pdev = pci_find_device(aic_pdevs[i].vendor_id,
+                                     aic_pdevs[i].device_id,
+                                     pdev))) {
+	if (pci_enable_device(pdev))
+		continue;
+        if ( i == 0 ) /* We found one, but it's the 7810 RAID cont. */
+        {
+          if (aic7xxx_verbose & (VERBOSE_PROBE|VERBOSE_PROBE2))
+          {
+            printk(KERN_INFO "aic7xxx: The 7810 RAID controller is not "
+              "supported by\n");
+            printk(KERN_INFO "         this driver, we are ignoring it.\n");
+          }
+        }
+        else if ( (temp_p = kmalloc(sizeof(struct aic7xxx_host),
+                                    GFP_ATOMIC)) != NULL )
+        {
+          memset(temp_p, 0, sizeof(struct aic7xxx_host));
+          temp_p->chip = aic_pdevs[i].chip | AHC_PCI;
+          temp_p->flags = aic_pdevs[i].flags;
+          temp_p->features = aic_pdevs[i].features;
+          temp_p->board_name_index = aic_pdevs[i].board_name_index;
+          temp_p->sc_size = aic_pdevs[i].seeprom_size;
+          temp_p->sc_type = aic_pdevs[i].seeprom_type;
+
+          /*
+           * Read sundry information from PCI BIOS.
+           */
+          temp_p->irq = pdev->irq;
+          temp_p->pdev = pdev;
+          temp_p->pci_bus = pdev->bus->number;
+          temp_p->pci_device_fn = pdev->devfn;
+          temp_p->base = pci_resource_start(pdev, 0);
+          temp_p->mbase = pci_resource_start(pdev, 1);
+          current_p = list_p;
+	  while(current_p && temp_p)
+	  {
+	    if ( ((current_p->pci_bus == temp_p->pci_bus) &&
+	          (current_p->pci_device_fn == temp_p->pci_device_fn)) ||
+                 (temp_p->base && (current_p->base == temp_p->base)) ||
+                 (temp_p->mbase && (current_p->mbase == temp_p->mbase)) )
+	    {
+              /* duplicate PCI entry, skip it */
+	      kfree(temp_p);
+	      temp_p = NULL;
+              continue;
+	    }
+	    current_p = current_p->next;
+	  }
+          if(pci_request_regions(temp_p->pdev, "aic7xxx"))
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              temp_p->pci_bus,
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+            printk("aic7xxx: I/O ports already in use, ignoring.\n");
+            kfree(temp_p);
+            continue;
+          }
+
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at PCI %d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              PCI_SLOT(pdev->devfn),
+              PCI_FUNC(pdev->devfn));
+          pci_read_config_word(pdev, PCI_COMMAND, &command);
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+          {
+            printk("aic7xxx: Initial PCI_COMMAND value was 0x%x\n",
+              (int)command);
+          }
+#ifdef AIC7XXX_STRICT_PCI_SETUP
+          command |= PCI_COMMAND_SERR | PCI_COMMAND_PARITY |
+            PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#else
+          command |= PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+#endif
+          command &= ~PCI_COMMAND_INVALIDATE;
+          if (aic7xxx_pci_parity == 0)
+            command &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
+          pci_write_config_word(pdev, PCI_COMMAND, command);
+#ifdef AIC7XXX_STRICT_PCI_SETUP
+          pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+          {
+            printk("aic7xxx: Initial DEVCONFIG value was 0x%x\n", devconfig);
+          }
+          devconfig |= 0x80000040;
+          pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+#endif /* AIC7XXX_STRICT_PCI_SETUP */
+
+          temp_p->unpause = INTEN;
+          temp_p->pause = temp_p->unpause | PAUSE;
+          if ( ((temp_p->base == 0) &&
+                (temp_p->mbase == 0)) ||
+               (temp_p->irq == 0) )
+          {
+            printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+              board_names[aic_pdevs[i].board_name_index],
+              temp_p->pci_bus,
+              PCI_SLOT(temp_p->pci_device_fn),
+              PCI_FUNC(temp_p->pci_device_fn));
+            printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+            goto skip_pci_controller;
+          }
+
+#ifdef MMAPIO
+          if ( !(temp_p->base) || !(temp_p->flags & AHC_MULTI_CHANNEL) ||
+               ((temp_p->chip != (AHC_AIC7870 | AHC_PCI)) &&
+                (temp_p->chip != (AHC_AIC7880 | AHC_PCI))) )
+          {
+            temp_p->maddr = ioremap_nocache(temp_p->mbase, 256);
+            if(temp_p->maddr)
+            {
+              /*
+               * We need to check the I/O with the MMAPed address.  Some machines
+               * simply fail to work with MMAPed I/O and certain controllers.
+               */
+              if(aic_inb(temp_p, HCNTRL) == 0xff)
+              {
+                /*
+                 * OK.....we failed our test....go back to programmed I/O
+                 */
+                printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                  board_names[aic_pdevs[i].board_name_index],
+                  temp_p->pci_bus,
+                  PCI_SLOT(temp_p->pci_device_fn),
+                  PCI_FUNC(temp_p->pci_device_fn));
+                printk(KERN_INFO "aic7xxx: MMAPed I/O failed, reverting to "
+                                 "Programmed I/O.\n");
+                iounmap(temp_p->maddr);
+                temp_p->maddr = NULL;
+                if(temp_p->base == 0)
+                {
+                  printk("aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: Controller disabled by BIOS, ignoring.\n");
+                  goto skip_pci_controller;
+                }
+              }
+            }
+          }
+#endif
+
+          /*
+           * We HAVE to make sure the first pause_sequencer() and all other
+           * subsequent I/O that isn't PCI config space I/O takes place
+           * after the MMAPed I/O region is configured and tested.  The
+           * problem is the PowerPC architecture that doesn't support
+           * programmed I/O at all, so we have to have the MMAP I/O set up
+           * for this pause to even work on those machines.
+           */
+          pause_sequencer(temp_p);
+
+          /*
+           * Clear out any pending PCI error status messages.  Also set
+           * verbose to 0 so that we don't emit strange PCI error messages
+           * while cleaning out the current status bits.
+           */
+          oldverbose = aic7xxx_verbose;
+          aic7xxx_verbose = 0;
+          aic7xxx_pci_intr(temp_p);
+          aic7xxx_verbose = oldverbose;
+
+          temp_p->bios_address = 0;
+
+          /*
+           * Remember how the card was setup in case there is no seeprom.
+           */
+          if (temp_p->features & AHC_ULTRA2)
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID_ULTRA2) & OID;
+          else
+            temp_p->scsi_id = aic_inb(temp_p, SCSIID) & OID;
+          /*
+           * Get current termination setting
+           */
+          sxfrctl1 = aic_inb(temp_p, SXFRCTL1);
+
+          if (aic7xxx_chip_reset(temp_p) == -1)
+          {
+            goto skip_pci_controller;
+          }
+          /*
+           * Very quickly put the term setting back into the register since
+           * the chip reset may cause odd things to happen.  This is to keep
+           * LVD busses with lots of drives from draining the power out of
+           * the diffsense line before we get around to running the
+           * configure_termination() function.  Also restore the STPWLEVEL
+           * bit of DEVCONFIG
+           */
+          aic_outb(temp_p, sxfrctl1, SXFRCTL1);
+          pci_write_config_dword(temp_p->pdev, DEVCONFIG, devconfig);
+          sxfrctl1 &= STPWEN;
+
+          /*
+           * We need to set the CHNL? assignments before loading the SEEPROM
+           * The 3940 and 3985 cards (original stuff, not any of the later
+           * stuff) are 7870 and 7880 class chips.  The Ultra2 stuff falls
+           * under 7896 and 7897.  The 7895 is in a class by itself :)
+           */
+          switch (temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7870: /* 3840 / 3985 */
+            case AHC_AIC7880: /* 3840 UW / 3985 UW */
+              if(temp_p->flags & AHC_MULTI_CHANNEL)
+              {
+                switch(PCI_SLOT(temp_p->pci_device_fn))
+                {
+                  case 5:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 8:
+                    temp_p->flags |= AHC_CHNLB;
+                    break;
+                  case 12:
+                    temp_p->flags |= AHC_CHNLC;
+                    break;
+                  default:
+                    break;
+                }
+              }
+              break;
+
+            case AHC_AIC7895: /* 7895 */
+            case AHC_AIC7896: /* 7896/7 */
+            case AHC_AIC7899: /* 7899 */
+              if (PCI_FUNC(pdev->devfn) != 0)
+              {
+                temp_p->flags |= AHC_CHNLB;
+              }
+              /*
+               * The 7895 is the only chipset that sets the SCBSIZE32 param
+               * in the DEVCONFIG register.  The Ultra2 chipsets use
+               * the DSCOMMAND0 register instead.
+               */
+              if ((temp_p->chip & AHC_CHIPID_MASK) == AHC_AIC7895)
+              {
+                pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+                devconfig |= SCBSIZE32;
+                pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * Loading of the SEEPROM needs to come after we've set the flags
+           * to indicate possible CHNLB and CHNLC assigments.  Otherwise,
+           * on 394x and 398x cards we'll end up reading the wrong settings
+           * for channels B and C
+           */
+          switch (temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7892:
+            case AHC_AIC7899:
+              aic_outb(temp_p, 0, SCAMCTL);
+              /*
+               * Switch to the alt mode of the chip...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) | ALT_MODE, SFUNCT);
+              /*
+               * Set our options...the last two items set our CRC after x byte
+	       * count in target mode...
+               */
+              aic_outb(temp_p, AUTO_MSGOUT_DE | DIS_MSGIN_DUALEDGE, OPTIONMODE);
+	      aic_outb(temp_p, 0x00, 0x0b);
+	      aic_outb(temp_p, 0x10, 0x0a);
+              /*
+               * switch back to normal mode...
+               */
+              aic_outb(temp_p, aic_inb(temp_p, SFUNCT) & ~ALT_MODE, SFUNCT);
+              aic_outb(temp_p, CRCVALCHKEN | CRCENDCHKEN | CRCREQCHKEN |
+			       TARGCRCENDEN | TARGCRCCNTEN,
+                       CRCCONTROL1);
+              aic_outb(temp_p, ((aic_inb(temp_p, DSCOMMAND0) | USCBSIZE32 |
+                                 MPARCKEN | CIOPARCKEN | CACHETHEN) & 
+                               ~DPARCKEN), DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7890:
+            case AHC_AIC7896:
+              aic_outb(temp_p, 0, SCAMCTL);
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN | USCBSIZE32 |
+                                CIOPARCKEN) & ~DPARCKEN, DSCOMMAND0);
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7850:
+            case AHC_AIC7860:
+              /*
+               * Set the DSCOMMAND0 register on these cards different from
+               * on the 789x cards.  Also, read the SEEPROM as well.
+               */
+              aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                       DSCOMMAND0);
+              /* FALLTHROUGH */
+            default:
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+            case AHC_AIC7880:
+              /*
+               * Check the rev of the chipset before we change DSCOMMAND0
+               */
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              if ((devconfig & 0xff) >= 1)
+              {
+                aic_outb(temp_p, (aic_inb(temp_p, DSCOMMAND0) |
+                                  CACHETHEN | MPARCKEN) & ~DPARCKEN,
+                         DSCOMMAND0);
+              }
+              aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+              break;
+          }
+          
+
+          /*
+           * and then we need another switch based on the type in order to
+           * make sure the channel B primary flag is set properly on 7895
+           * controllers....Arrrgggghhh!!!  We also have to catch the fact
+           * that when you disable the BIOS on the 7895 on the Intel DK440LX
+           * motherboard, and possibly others, it only sets the BIOS disabled
+           * bit on the A channel...I think I'm starting to lean towards
+           * going postal....
+           */
+          switch(temp_p->chip & AHC_CHIPID_MASK)
+          {
+            case AHC_AIC7895:
+            case AHC_AIC7896:
+            case AHC_AIC7899:
+              current_p = list_p;
+              while(current_p != NULL)
+              {
+                if ( (current_p->pci_bus == temp_p->pci_bus) &&
+                     (PCI_SLOT(current_p->pci_device_fn) ==
+                      PCI_SLOT(temp_p->pci_device_fn)) )
+                {
+                  if ( PCI_FUNC(current_p->pci_device_fn) == 0 )
+                  {
+                    temp_p->flags |= 
+                      (current_p->flags & AHC_CHANNEL_B_PRIMARY);
+                    temp_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    temp_p->flags |=
+                      (current_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
+                  else
+                  {
+                    current_p->flags |=
+                      (temp_p->flags & AHC_CHANNEL_B_PRIMARY);
+                    current_p->flags &= ~(AHC_BIOS_ENABLED|AHC_USEDEFAULTS);
+                    current_p->flags |=
+                      (temp_p->flags & (AHC_BIOS_ENABLED|AHC_USEDEFAULTS));
+                  }
+                }
+                current_p = current_p->next;
+              }
+              break;
+            default:
+              break;
+          }
+
+          /*
+           * We only support external SCB RAM on the 7895/6/7 chipsets.
+           * We could support it on the 7890/1 easy enough, but I don't
+           * know of any 7890/1 based cards that have it.  I do know
+           * of 7895/6/7 cards that have it and they work properly.
+           */
+          switch(temp_p->chip & AHC_CHIPID_MASK)
+          {
+            default:
+              break;
+            case AHC_AIC7895:
+            case AHC_AIC7896:
+            case AHC_AIC7899:
+              pci_read_config_dword(pdev, DEVCONFIG, &devconfig);
+              if (temp_p->features & AHC_ULTRA2)
+              {
+                if ( (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2) &&
+                     (aic7xxx_scbram) )
+                {
+                  aic_outb(temp_p,
+                           aic_inb(temp_p, DSCOMMAND0) & ~SCBRAMSEL_ULTRA2,
+                           DSCOMMAND0);
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                  devconfig |= EXTSCBPEN;
+                }
+                else if (aic_inb(temp_p, DSCOMMAND0) & RAMPSM_ULTRA2)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
+              }
+              else
+              {
+                if ((devconfig & RAMPSM) && (aic7xxx_scbram))
+                {
+                  devconfig &= ~SCBRAMSEL;
+                  devconfig |= EXTSCBPEN;
+                  temp_p->flags |= AHC_EXTERNAL_SRAM;
+                }
+                else if (devconfig & RAMPSM)
+                {
+                  printk(KERN_INFO "aic7xxx: <%s> at PCI %d/%d/%d\n", 
+                    board_names[aic_pdevs[i].board_name_index],
+                    temp_p->pci_bus,
+                    PCI_SLOT(temp_p->pci_device_fn),
+                    PCI_FUNC(temp_p->pci_device_fn));
+                  printk("aic7xxx: external SCB RAM detected, "
+                         "but not enabled\n");
+                }
+              }
+              pci_write_config_dword(pdev, DEVCONFIG, devconfig);
+              if ( (temp_p->flags & AHC_EXTERNAL_SRAM) &&
+                   (temp_p->flags & AHC_CHNLB) )
+                aic_outb(temp_p, 1, CCSCBBADDR);
+              break;
+          }
+
+          /*
+           * Take the LED out of diagnostic mode
+           */
+          aic_outb(temp_p, 
+            (aic_inb(temp_p, SBLKCTL) & ~(DIAGLEDEN | DIAGLEDON)),
+            SBLKCTL);
+
+          /*
+           * We don't know where this is set in the SEEPROM or by the
+           * BIOS, so we default to 100%.  On Ultra2 controllers, use 75%
+           * instead.
+           */
+          if (temp_p->features & AHC_ULTRA2)
+          {
+            aic_outb(temp_p, RD_DFTHRSH_MAX | WR_DFTHRSH_MAX, DFF_THRSH);
+          }
+          else
+          {
+            aic_outb(temp_p, DFTHRSH_100, DSPCISTATUS);
+          }
+
+          /*
+           * Call our function to fixup any bugs that exist on this chipset.
+           * This may muck with PCI settings and other device settings, so
+           * make sure it's after all the other PCI and device register
+           * tweaks so it can back out bad settings on specific broken cards.
+           */
+          aic7xxx_configure_bugs(temp_p);
+
+          if ( list_p == NULL )
+          {
+            list_p = current_p = temp_p;
+          }
+          else
+          {
+            current_p = list_p;
+            while(current_p->next != NULL)
+              current_p = current_p->next;
+            current_p->next = temp_p;
+          }
+          temp_p->next = NULL;
+          found++;
+	  continue;
+skip_pci_controller:
+#ifdef CONFIG_PCI
+	  pci_release_regions(temp_p->pdev);
+#endif
+	  kfree(temp_p);
+        }  /* Found an Adaptec PCI device. */
+        else /* Well, we found one, but we couldn't get any memory */
+        {
+          printk("aic7xxx: Found <%s>\n", 
+            board_names[aic_pdevs[i].board_name_index]);
+          printk(KERN_INFO "aic7xxx: Unable to allocate device memory, "
+            "skipping.\n");
+        }
+      } /* while(pdev=....) */
+    } /* for PCI_DEVICES */
+  }
+#endif /* CONFIG_PCI */
+
+#if defined(__i386__) || defined(__alpha__)
+  /*
+   * EISA/VL-bus card signature probe.
+   */
+  slot = MINSLOT;
+  while ( (slot <= MAXSLOT) &&
+         !(aic7xxx_no_probe) )
+  {
+    base = SLOTBASE(slot) + MINREG;
+
+    if (!request_region(base, MAXREG - MINREG, "aic7xxx"))
+    {
+      /*
+       * Some other driver has staked a
+       * claim to this i/o region already.
+       */
+      slot++;
+      continue; /* back to the beginning of the for loop */
+    }
+    flags = 0;
+    type = aic7xxx_probe(slot, base + AHC_HID0, &flags);
+    if (type == -1)
+    {
+      release_region(base, MAXREG - MINREG);
+      slot++;
+      continue;
+    }
+    temp_p = kmalloc(sizeof(struct aic7xxx_host), GFP_ATOMIC);
+    if (temp_p == NULL)
+    {
+      printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+      release_region(base, MAXREG - MINREG);
+      slot++;
+      continue; /* back to the beginning of the while loop */
+    }
+
+    /*
+     * Pause the card preserving the IRQ type.  Allow the operator
+     * to override the IRQ trigger.
+     */
+    if (aic7xxx_irq_trigger == 1)
+      hcntrl = IRQMS;  /* Level */
+    else if (aic7xxx_irq_trigger == 0)
+      hcntrl = 0;  /* Edge */
+    else
+      hcntrl = inb(base + HCNTRL) & IRQMS;  /* Default */
+    memset(temp_p, 0, sizeof(struct aic7xxx_host));
+    temp_p->unpause = hcntrl | INTEN;
+    temp_p->pause = hcntrl | PAUSE | INTEN;
+    temp_p->base = base;
+    temp_p->mbase = 0;
+    temp_p->maddr = NULL;
+    temp_p->pci_bus = 0;
+    temp_p->pci_device_fn = slot;
+    aic_outb(temp_p, hcntrl | PAUSE, HCNTRL);
+    while( (aic_inb(temp_p, HCNTRL) & PAUSE) == 0 ) ;
+    if (aic7xxx_chip_reset(temp_p) == -1)
+      temp_p->irq = 0;
+    else
+      temp_p->irq = aic_inb(temp_p, INTDEF) & 0x0F;
+    temp_p->flags |= AHC_PAGESCBS;
+
+    switch (temp_p->irq)
+    {
+      case 9:
+      case 10:
+      case 11:
+      case 12:
+      case 14:
+      case 15:
+        break;
+
+      default:
+        printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+          "level %d, ignoring.\n", temp_p->irq);
+        kfree(temp_p);
+        release_region(base, MAXREG - MINREG);
+        slot++;
+        continue; /* back to the beginning of the while loop */
+    }
+
+    /*
+     * We are commited now, everything has been checked and this card
+     * has been found, now we just set it up
+     */
+
+    /*
+     * Insert our new struct into the list at the end
+     */
+    if (list_p == NULL)
+    {
+      list_p = current_p = temp_p;
+    }
+    else
+    {
+      current_p = list_p;
+      while (current_p->next != NULL)
+        current_p = current_p->next;
+      current_p->next = temp_p;
+    }
+
+    switch (type)
+    {
+      case 0:
+        temp_p->board_name_index = 2;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at EISA %d\n",
+               board_names[2], slot);
+        /* FALLTHROUGH */
+      case 1:
+      {
+        temp_p->chip = AHC_AIC7770 | AHC_EISA;
+        temp_p->features |= AHC_AIC7770_FE;
+        temp_p->bios_control = aic_inb(temp_p, HA_274_BIOSCTRL);
+
+        /*
+         * Get the primary channel information.  Right now we don't
+         * do anything with this, but someday we will be able to inform
+         * the mid-level SCSI code which channel is primary.
+         */
+        if (temp_p->board_name_index == 0)
+        {
+          temp_p->board_name_index = 3;
+          if (aic7xxx_verbose & VERBOSE_PROBE2)
+            printk("aic7xxx: <%s> at EISA %d\n",
+                 board_names[3], slot);
+        }
+        if (temp_p->bios_control & CHANNEL_B_PRIMARY)
+        {
+          temp_p->flags |= AHC_CHANNEL_B_PRIMARY;
+        }
+
+        if ((temp_p->bios_control & BIOSMODE) == BIOSDISABLED)
+        {
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        }
+        else
+        {
+          temp_p->flags &= ~AHC_USEDEFAULTS;
+          temp_p->flags |= AHC_BIOS_ENABLED;
+          if ( (temp_p->bios_control & 0x20) == 0 )
+          {
+            temp_p->bios_address = 0xcc000;
+            temp_p->bios_address += (0x4000 * (temp_p->bios_control & 0x07));
+          }
+          else
+          {
+            temp_p->bios_address = 0xd0000;
+            temp_p->bios_address += (0x8000 * (temp_p->bios_control & 0x06));
+          }
+        }
+        temp_p->adapter_control = aic_inb(temp_p, SCSICONF) << 8;
+        temp_p->adapter_control |= aic_inb(temp_p, SCSICONF + 1);
+        if (temp_p->features & AHC_WIDE)
+        {
+          temp_p->scsi_id = temp_p->adapter_control & HWSCSIID;
+          temp_p->scsi_id_b = temp_p->scsi_id;
+        }
+        else
+        {
+          temp_p->scsi_id = (temp_p->adapter_control >> 8) & HSCSIID;
+          temp_p->scsi_id_b = temp_p->adapter_control & HSCSIID;
+        }
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+        break;
+      }
+
+      case 2:
+      case 3:
+        temp_p->chip = AHC_AIC7770 | AHC_VL;
+        temp_p->features |= AHC_AIC7770_FE;
+        if (type == 2)
+          temp_p->flags |= AHC_BIOS_ENABLED;
+        else
+          temp_p->flags &= ~AHC_BIOS_ENABLED;
+        if (aic_inb(temp_p, SCSICONF) & TERM_ENB)
+          sxfrctl1 = STPWEN;
+        aic7xxx_load_seeprom(temp_p, &sxfrctl1);
+        temp_p->board_name_index = 4;
+        if (aic7xxx_verbose & VERBOSE_PROBE2)
+          printk("aic7xxx: <%s> at VLB %d\n",
+               board_names[2], slot);
+        switch( aic_inb(temp_p, STATUS_2840) & BIOS_SEL )
+        {
+          case 0x00:
+            temp_p->bios_address = 0xe0000;
+            break;
+          case 0x20:
+            temp_p->bios_address = 0xc8000;
+            break;
+          case 0x40:
+            temp_p->bios_address = 0xd0000;
+            break;
+          case 0x60:
+            temp_p->bios_address = 0xd8000;
+            break;
+          default:
+            break; /* can't get here */
+        }
+        break;
+
+      default:  /* Won't get here. */
+        break;
+    }
+    if (aic7xxx_verbose & VERBOSE_PROBE2)
+    {
+      printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%lx, IRQ %d (%s)\n",
+        (temp_p->flags & AHC_USEDEFAULTS) ? "dis" : "en", temp_p->base,
+        temp_p->irq,
+        (temp_p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+      printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+             (temp_p->flags & AHC_EXTEND_TRANS_A) ? "en" : "dis");
+    }
+
+    /*
+     * All the 7770 based chipsets have this bug
+     */
+    temp_p->bugs |= AHC_BUG_TMODE_WIDEODD;
+
+    /*
+     * Set the FIFO threshold and the bus off time.
+     */
+    hostconf = aic_inb(temp_p, HOSTCONF);
+    aic_outb(temp_p, hostconf & DFTHRSH, BUSSPD);
+    aic_outb(temp_p, (hostconf << 2) & BOFF, BUSTIME);
+    slot++;
+    found++;
+  }
+
+#endif /* defined(__i386__) || defined(__alpha__) */
+
+  /*
+   * Now, we re-order the probed devices by BIOS address and BUS class.
+   * In general, we follow this algorithm to make the adapters show up
+   * in the same order under linux that the computer finds them.
+   *  1: All VLB/EISA cards with BIOS_ENABLED first, according to BIOS
+   *     address, going from lowest to highest.
+   *  2: All PCI controllers with BIOS_ENABLED next, according to BIOS
+   *     address, going from lowest to highest.
+   *  3: Remaining VLB/EISA controllers going in slot order.
+   *  4: Remaining PCI controllers, going in PCI device order (reversable)
+   */
+
+  {
+    struct aic7xxx_host *sort_list[4] = { NULL, NULL, NULL, NULL };
+    struct aic7xxx_host *vlb, *pci;
+    struct aic7xxx_host *prev_p;
+    struct aic7xxx_host *p;
+    unsigned char left;
+
+    prev_p = vlb = pci = NULL;
+
+    temp_p = list_p;
+    while (temp_p != NULL)
+    {
+      switch(temp_p->chip & ~AHC_CHIPID_MASK)
+      {
+        case AHC_EISA:
+        case AHC_VL:
+        {
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED)
+            vlb = sort_list[0];
+          else
+            vlb = sort_list[2];
+
+          if (vlb == NULL)
+          {
+            vlb = temp_p;
+            temp_p = temp_p->next;
+            vlb->next = NULL;
+          }
+          else
+          {
+            current_p = vlb;
+            prev_p = NULL;
+            while ( (current_p != NULL) &&
+                    (current_p->bios_address < temp_p->bios_address))
+            {
+              prev_p = current_p;
+              current_p = current_p->next;
+            }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              vlb = temp_p;
+              temp_p = temp_p->next;
+              vlb->next = current_p;
+            }
+          }
+          
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[0] = vlb;
+          else
+            sort_list[2] = vlb;
+          
+          break;
+        }
+        default:  /* All PCI controllers fall through to default */
+        {
+
+          p = temp_p;
+          if (p->flags & AHC_BIOS_ENABLED) 
+            pci = sort_list[1];
+          else
+            pci = sort_list[3];
+
+          if (pci == NULL)
+          {
+            pci = temp_p;
+            temp_p = temp_p->next;
+            pci->next = NULL;
+          }
+          else
+          {
+            current_p = pci;
+            prev_p = NULL;
+            if (!aic7xxx_reverse_scan)
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) < 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            else
+            {
+              while ( (current_p != NULL) &&
+                      ( (PCI_SLOT(current_p->pci_device_fn) |
+                        (current_p->pci_bus << 8)) > 
+                        (PCI_SLOT(temp_p->pci_device_fn) |
+                        (temp_p->pci_bus << 8)) ) )
+              {
+                prev_p = current_p;
+                current_p = current_p->next;
+              }
+            }
+            /*
+             * Are we dealing with a 7895/6/7/9 where we need to sort the
+             * channels as well, if so, the bios_address values should
+             * be the same
+             */
+            if ( (current_p) && (temp_p->flags & AHC_MULTI_CHANNEL) &&
+                 (temp_p->pci_bus == current_p->pci_bus) &&
+                 (PCI_SLOT(temp_p->pci_device_fn) ==
+                  PCI_SLOT(current_p->pci_device_fn)) )
+            {
+              if (temp_p->flags & AHC_CHNLB)
+              {
+                if ( !(temp_p->flags & AHC_CHANNEL_B_PRIMARY) )
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+              else
+              {
+                if (temp_p->flags & AHC_CHANNEL_B_PRIMARY)
+                {
+                  prev_p = current_p;
+                  current_p = current_p->next;
+                }
+              }
+            }
+            if (prev_p != NULL)
+            {
+              prev_p->next = temp_p;
+              temp_p = temp_p->next;
+              prev_p->next->next = current_p;
+            }
+            else
+            {
+              pci = temp_p;
+              temp_p = temp_p->next;
+              pci->next = current_p;
+            }
+          }
+
+          if (p->flags & AHC_BIOS_ENABLED)
+            sort_list[1] = pci;
+          else
+            sort_list[3] = pci;
+
+          break;
+        }
+      }  /* End of switch(temp_p->type) */
+    } /* End of while (temp_p != NULL) */
+    /*
+     * At this point, the cards have been broken into 4 sorted lists, now
+     * we run through the lists in order and register each controller
+     */
+    {
+      int i;
+      
+      left = found;
+      for (i=0; i<ARRAY_SIZE(sort_list); i++)
+      {
+        temp_p = sort_list[i];
+        while(temp_p != NULL)
+        {
+          template->name = board_names[temp_p->board_name_index];
+          p = aic7xxx_alloc(template, temp_p);
+          if (p != NULL)
+          {
+            p->instance = found - left;
+            if (aic7xxx_register(template, p, (--left)) == 0)
+            {
+              found--;
+              aic7xxx_release(p->host);
+              scsi_unregister(p->host);
+            }
+            else if (aic7xxx_dump_card)
+            {
+              pause_sequencer(p);
+              aic7xxx_print_card(p);
+              aic7xxx_print_scratch_ram(p);
+              unpause_sequencer(p, TRUE);
+            }
+          }
+          current_p = temp_p;
+          temp_p = (struct aic7xxx_host *)temp_p->next;
+          kfree(current_p);
+        }
+      }
+    }
+  }
+  return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_buildscb
+ *
+ * Description:
+ *   Build a SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
+    struct aic7xxx_scb *scb)
+{
+  unsigned short mask;
+  struct aic7xxx_hwscb *hscb;
+  struct aic_dev_data *aic_dev = cmd->device->hostdata;
+  struct scsi_device *sdptr = cmd->device;
+  unsigned char tindex = TARGET_INDEX(cmd);
+  struct request *req = cmd->request;
+
+  mask = (0x01 << tindex);
+  hscb = scb->hscb;
+
+  /*
+   * Setup the control byte if we need negotiation and have not
+   * already requested it.
+   */
+  hscb->control = 0;
+  scb->tag_action = 0;
+
+  if (p->discenable & mask)
+  {
+    hscb->control |= DISCENB;
+    /* We always force TEST_UNIT_READY to untagged */
+    if (cmd->cmnd[0] != TEST_UNIT_READY && sdptr->simple_tags)
+    {
+      if (req->flags & REQ_HARDBARRIER)
+      {
+	if(sdptr->ordered_tags)
+	{
+          hscb->control |= MSG_ORDERED_Q_TAG;
+          scb->tag_action = MSG_ORDERED_Q_TAG;
+	}
+      }
+      else
+      {
+        hscb->control |= MSG_SIMPLE_Q_TAG;
+        scb->tag_action = MSG_SIMPLE_Q_TAG;
+      }
+    }
+  }
+  if ( !(aic_dev->dtr_pending) &&
+        (aic_dev->needppr || aic_dev->needwdtr || aic_dev->needsdtr) &&
+        (aic_dev->flags & DEVICE_DTR_SCANNED) )
+  {
+    aic_dev->dtr_pending = 1;
+    scb->tag_action = 0;
+    hscb->control &= DISCENB;
+    hscb->control |= MK_MESSAGE;
+    if(aic_dev->needppr)
+    {
+      scb->flags |= SCB_MSGOUT_PPR;
+    }
+    else if(aic_dev->needwdtr)
+    {
+      scb->flags |= SCB_MSGOUT_WDTR;
+    }
+    else if(aic_dev->needsdtr)
+    {
+      scb->flags |= SCB_MSGOUT_SDTR;
+    }
+    scb->flags |= SCB_DTR_SCB;
+  }
+  hscb->target_channel_lun = ((cmd->device->id << 4) & 0xF0) |
+        ((cmd->device->channel & 0x01) << 3) | (cmd->device->lun & 0x07);
+
+  /*
+   * The interpretation of request_buffer and request_bufflen
+   * changes depending on whether or not use_sg is zero; a
+   * non-zero use_sg indicates the number of elements in the
+   * scatter-gather array.
+   */
+
+  /*
+   * XXX - this relies on the host data being stored in a
+   *       little-endian format.
+   */
+  hscb->SCSI_cmd_length = cmd->cmd_len;
+  memcpy(scb->cmnd, cmd->cmnd, cmd->cmd_len);
+  hscb->SCSI_cmd_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, scb->cmnd));
+
+  if (cmd->use_sg)
+  {
+    struct scatterlist *sg;  /* Must be mid-level SCSI code scatterlist */
+
+    /*
+     * We must build an SG list in adapter format, as the kernel's SG list
+     * cannot be used directly because of data field size (__alpha__)
+     * differences and the kernel SG list uses virtual addresses where
+     * we need physical addresses.
+     */
+    int i, use_sg;
+
+    sg = (struct scatterlist *)cmd->request_buffer;
+    scb->sg_length = 0;
+    use_sg = pci_map_sg(p->pdev, sg, cmd->use_sg, scsi_to_pci_dma_dir(cmd->sc_data_direction));
+    /*
+     * Copy the segments into the SG array.  NOTE!!! - We used to
+     * have the first entry both in the data_pointer area and the first
+     * SG element.  That has changed somewhat.  We still have the first
+     * entry in both places, but now we download the address of
+     * scb->sg_list[1] instead of 0 to the sg pointer in the hscb.
+     */
+    for (i = 0; i < use_sg; i++)
+    {
+      unsigned int len = sg_dma_len(sg+i);
+      scb->sg_list[i].address = cpu_to_le32(sg_dma_address(sg+i));
+      scb->sg_list[i].length = cpu_to_le32(len);
+      scb->sg_length += len;
+    }
+    /* Copy the first SG into the data pointer area. */
+    hscb->data_pointer = scb->sg_list[0].address;
+    hscb->data_count = scb->sg_list[0].length;
+    scb->sg_count = i;
+    hscb->SG_segment_count = i;
+    hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[1]));
+  }
+  else
+  {
+    if (cmd->request_bufflen)
+    {
+      unsigned int address = pci_map_single(p->pdev, cmd->request_buffer,
+					    cmd->request_bufflen,
+                                            scsi_to_pci_dma_dir(cmd->sc_data_direction));
+      aic7xxx_mapping(cmd) = address;
+      scb->sg_list[0].address = cpu_to_le32(address);
+      scb->sg_list[0].length = cpu_to_le32(cmd->request_bufflen);
+      scb->sg_count = 1;
+      scb->sg_length = cmd->request_bufflen;
+      hscb->SG_segment_count = 1;
+      hscb->SG_list_pointer = cpu_to_le32(SCB_DMA_ADDR(scb, &scb->sg_list[0]));
+      hscb->data_count = scb->sg_list[0].length;
+      hscb->data_pointer = scb->sg_list[0].address;
+    }
+    else
+    {
+      scb->sg_count = 0;
+      scb->sg_length = 0;
+      hscb->SG_segment_count = 0;
+      hscb->SG_list_pointer = 0;
+      hscb->data_count = 0;
+      hscb->data_pointer = 0;
+    }
+  }
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_queue
+ *
+ * Description:
+ *   Queue a SCB to the controller.
+ *-F*************************************************************************/
+static int
+aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
+{
+  struct aic7xxx_host *p;
+  struct aic7xxx_scb *scb;
+  struct aic_dev_data *aic_dev;
+
+  p = (struct aic7xxx_host *) cmd->device->host->hostdata;
+
+  aic_dev = cmd->device->hostdata;  
+#ifdef AIC7XXX_VERBOSE_DEBUGGING
+  if (aic_dev->active_cmds > aic_dev->max_q_depth)
+  {
+    printk(WARN_LEAD "Commands queued exceeds queue "
+           "depth, active=%d\n",
+           p->host_no, CTL_OF_CMD(cmd), 
+           aic_dev->active_cmds);
+  }
+#endif
+
+  scb = scbq_remove_head(&p->scb_data->free_scbs);
+  if (scb == NULL)
+  {
+    aic7xxx_allocate_scb(p);
+    scb = scbq_remove_head(&p->scb_data->free_scbs);
+    if(scb == NULL)
+    {
+      printk(WARN_LEAD "Couldn't get a free SCB.\n", p->host_no,
+             CTL_OF_CMD(cmd));
+      return 1;
+    }
+  }
+  scb->cmd = cmd;
+
+  /*
+   * Make sure the Scsi_Cmnd pointer is saved, the struct it points to
+   * is set up properly, and the parity error flag is reset, then send
+   * the SCB to the sequencer and watch the fun begin.
+   */
+  aic7xxx_position(cmd) = scb->hscb->tag;
+  cmd->scsi_done = fn;
+  cmd->result = DID_OK;
+  memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+  aic7xxx_error(cmd) = DID_OK;
+  aic7xxx_status(cmd) = 0;
+  cmd->host_scribble = NULL;
+
+  /*
+   * Construct the SCB beforehand, so the sequencer is
+   * paused a minimal amount of time.
+   */
+  aic7xxx_buildscb(p, cmd, scb);
+
+  scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
+
+  scbq_insert_tail(&p->waiting_scbs, scb);
+  aic7xxx_run_waiting_queues(p);
+  return (0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_bus_device_reset
+ *
+ * Description:
+ *   Abort or reset the current SCSI command(s).  If the scb has not
+ *   previously been aborted, then we attempt to send a BUS_DEVICE_RESET
+ *   message to the target.  If the scb has previously been unsuccessfully
+ *   aborted, then we will reset the channel and have all devices renegotiate.
+ *   Returns an enumerated type that indicates the status of the operation.
+ *-F*************************************************************************/
+static int
+aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
+{
+  struct aic7xxx_host  *p;
+  struct aic7xxx_scb   *scb;
+  struct aic7xxx_hwscb *hscb;
+  int channel;
+  unsigned char saved_scbptr, lastphase;
+  unsigned char hscb_index;
+  int disconnected;
+  struct aic_dev_data *aic_dev;
+
+  if(cmd == NULL)
+  {
+    printk(KERN_ERR "aic7xxx_bus_device_reset: called with NULL cmd!\n");
+    return FAILED;
+  }
+  p = (struct aic7xxx_host *)cmd->device->host->hostdata;
+  aic_dev = AIC_DEV(cmd);
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  else
+    return FAILED;
+
+  hscb = scb->hscb;
+
+  aic7xxx_isr(p->irq, (void *)p, NULL);
+  aic7xxx_done_cmds_complete(p);
+  /* If the command was already complete or just completed, then we didn't
+   * do a reset, return FAILED */
+  if(!(scb->flags & SCB_ACTIVE))
+    return FAILED;
+
+  pause_sequencer(p);
+  lastphase = aic_inb(p, LASTPHASE);
+  if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+  {
+    printk(INFO_LEAD "Bus Device reset, scb flags 0x%x, ",
+         p->host_no, CTL_OF_SCB(scb), scb->flags);
+    switch (lastphase)
+    {
+      case P_DATAOUT:
+        printk("Data-Out phase\n");
+        break;
+      case P_DATAIN:
+        printk("Data-In phase\n");
+        break;
+      case P_COMMAND:
+        printk("Command phase\n");
+        break;
+      case P_MESGOUT:
+        printk("Message-Out phase\n");
+        break;
+      case P_STATUS:
+        printk("Status phase\n");
+        break;
+      case P_MESGIN:
+        printk("Message-In phase\n");
+        break;
+      default:
+      /*
+       * We're not in a valid phase, so assume we're idle.
+       */
+        printk("while idle, LASTPHASE = 0x%x\n", lastphase);
+        break;
+    }
+    printk(INFO_LEAD "SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 "
+         "0x%x\n", p->host_no, CTL_OF_SCB(scb),
+         aic_inb(p, SCSISIGI),
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, SSTAT0), aic_inb(p, SSTAT1));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SSTAT2 0x%x, STCNT 0x%x\n", p->host_no,
+         CTL_OF_SCB(scb),
+         (p->features & AHC_ULTRA2) ? aic_inb(p, SG_CACHEPTR) : 0,
+         aic_inb(p, SSTAT2),
+         aic_inb(p, STCNT + 2) << 16 | aic_inb(p, STCNT + 1) << 8 |
+         aic_inb(p, STCNT));
+  }
+
+  channel = cmd->device->channel;
+
+    /*
+     * Send a Device Reset Message:
+     * The target that is holding up the bus may not be the same as
+     * the one that triggered this timeout (different commands have
+     * different timeout lengths).  Our strategy here is to queue an
+     * abort message to the timed out target if it is disconnected.
+     * Otherwise, if we have an active target we stuff the message buffer
+     * with an abort message and assert ATN in the hopes that the target
+     * will let go of the bus and go to the mesgout phase.  If this
+     * fails, we'll get another timeout a few seconds later which will
+     * attempt a bus reset.
+     */
+  saved_scbptr = aic_inb(p, SCBPTR);
+  disconnected = FALSE;
+
+  if (lastphase != P_BUSFREE)
+  {
+    if (aic_inb(p, SCB_TAG) >= p->scb_data->numscbs)
+    {
+      printk(WARN_LEAD "Invalid SCB ID %d is active, "
+             "SCB flags = 0x%x.\n", p->host_no,
+            CTL_OF_CMD(cmd), scb->hscb->tag, scb->flags);
+      unpause_sequencer(p, FALSE);
+      return FAILED;
+    }
+    if (scb->hscb->tag == aic_inb(p, SCB_TAG))
+    { 
+      if ( (lastphase == P_MESGOUT) || (lastphase == P_MESGIN) )
+      {
+        printk(WARN_LEAD "Device reset, Message buffer "
+                "in use\n", p->host_no, CTL_OF_SCB(scb));
+        unpause_sequencer(p, FALSE);
+	return FAILED;
+      }
+	
+      if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+        printk(INFO_LEAD "Device reset message in "
+              "message buffer\n", p->host_no, CTL_OF_SCB(scb));
+      scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+      aic7xxx_error(cmd) = DID_RESET;
+      aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
+      /* Send the abort message to the active SCB. */
+      aic_outb(p, HOST_MSG, MSG_OUT);
+      aic_outb(p, lastphase | ATNO, SCSISIGO);
+      unpause_sequencer(p, FALSE);
+      spin_unlock_irq(p->host->host_lock);
+      ssleep(1);
+      spin_lock_irq(p->host->host_lock);
+      if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
+        return FAILED;
+      else
+        return SUCCESS;
+    }
+  } /* if (last_phase != P_BUSFREE).....indicates we are idle and can work */
+  /*
+   * Simply set the MK_MESSAGE flag and the SEQINT handler will do
+   * the rest on a reconnect/connect.
+   */
+  scb->hscb->control |= MK_MESSAGE;
+  scb->flags |= SCB_RESET | SCB_DEVICE_RESET;
+  aic_dev->flags |= BUS_DEVICE_RESET_PENDING;
+  /*
+   * Check to see if the command is on the qinfifo.  If it is, then we will
+   * not need to queue the command again since the card should start it soon
+   */
+  if (aic7xxx_search_qinfifo(p, cmd->device->channel, cmd->device->id, cmd->device->lun, hscb->tag,
+			  0, TRUE, NULL) == 0)
+  {
+    disconnected = TRUE;
+    if ((hscb_index = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
+    {
+      unsigned char scb_control;
+
+      aic_outb(p, hscb_index, SCBPTR);
+      scb_control = aic_inb(p, SCB_CONTROL);
+      /*
+       * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
+       * actually on the waiting list, not disconnected, and we don't
+       * need to requeue the command.
+       */
+      disconnected = (scb_control & DISCONNECTED);
+      aic_outb(p, scb_control | MK_MESSAGE, SCB_CONTROL);
+    }
+    if (disconnected)
+    {
+      /*
+       * Actually requeue this SCB in case we can select the
+       * device before it reconnects.  This can result in the command
+       * being on the qinfifo twice, but we don't care because it will
+       * all get cleaned up if/when the reset takes place.
+       */
+      if (aic7xxx_verbose & VERBOSE_RESET_PROCESS)
+        printk(INFO_LEAD "Queueing device reset command.\n", p->host_no,
+		      CTL_OF_SCB(scb));
+      p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+      if (p->features & AHC_QUEUE_REGS)
+        aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+      else
+        aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+      scb->flags |= SCB_QUEUED_ABORT;
+    }
+  }
+  aic_outb(p, saved_scbptr, SCBPTR);
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  msleep(1000/4);
+  spin_lock_irq(p->host->host_lock);
+  if(aic_dev->flags & BUS_DEVICE_RESET_PENDING)
+    return FAILED;
+  else
+    return SUCCESS;
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_panic_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+static void
+aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
+{
+
+  printk("aic7xxx driver version %s\n", AIC7XXX_C_VERSION);
+  printk("Controller type:\n    %s\n", board_names[p->board_name_index]);
+  printk("p->flags=0x%lx, p->chip=0x%x, p->features=0x%x, "
+         "sequencer %s paused\n",
+     p->flags, p->chip, p->features,
+    (aic_inb(p, HCNTRL) & PAUSE) ? "is" : "isn't" );
+  pause_sequencer(p);
+  disable_irq(p->irq);
+  aic7xxx_print_card(p);
+  aic7xxx_print_scratch_ram(p);
+  spin_unlock_irq(p->host->host_lock);
+  for(;;) barrier();
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_abort
+ *
+ * Description:
+ *   Abort the current SCSI command(s).
+ *-F*************************************************************************/
+static int
+aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+  struct aic7xxx_scb  *scb = NULL;
+  struct aic7xxx_host *p;
+  int    found=0, disconnected;
+  unsigned char saved_hscbptr, hscbptr, scb_control;
+  struct aic_dev_data *aic_dev;
+
+  if(cmd == NULL)
+  {
+    printk(KERN_ERR "aic7xxx_abort: called with NULL cmd!\n");
+    return FAILED;
+  }
+  p = (struct aic7xxx_host *)cmd->device->host->hostdata;
+  aic_dev = AIC_DEV(cmd);
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+  else
+    return FAILED;
+
+  aic7xxx_isr(p->irq, (void *)p, NULL);
+  aic7xxx_done_cmds_complete(p);
+  /* If the command was already complete or just completed, then we didn't
+   * do a reset, return FAILED */
+  if(!(scb->flags & SCB_ACTIVE))
+    return FAILED;
+
+  pause_sequencer(p);
+
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * useful information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p, cmd);
+
+  if (aic7xxx_verbose & VERBOSE_ABORT)
+  {
+    printk(INFO_LEAD "Aborting scb %d, flags 0x%x, SEQADDR 0x%x, LASTPHASE "
+           "0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), scb->hscb->tag, scb->flags,
+         aic_inb(p, SEQADDR0) | (aic_inb(p, SEQADDR1) << 8),
+         aic_inb(p, LASTPHASE));
+    printk(INFO_LEAD "SG_CACHEPTR 0x%x, SG_COUNT %d, SCSISIGI 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), (p->features & AHC_ULTRA2) ?
+         aic_inb(p, SG_CACHEPTR) : 0, aic_inb(p, SG_COUNT),
+         aic_inb(p, SCSISIGI));
+    printk(INFO_LEAD "SSTAT0 0x%x, SSTAT1 0x%x, SSTAT2 0x%x\n",
+         p->host_no, CTL_OF_SCB(scb), aic_inb(p, SSTAT0),
+         aic_inb(p, SSTAT1), aic_inb(p, SSTAT2));
+  }
+
+  if (scb->flags & SCB_WAITINGQ)
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS) 
+      printk(INFO_LEAD "SCB found on waiting list and "
+          "aborted.\n", p->host_no, CTL_OF_SCB(scb));
+    scbq_remove(&p->waiting_scbs, scb);
+    scbq_remove(&aic_dev->delayed_scbs, scb);
+    aic_dev->active_cmds++;
+    p->activescbs++;
+    scb->flags &= ~(SCB_WAITINGQ | SCB_ACTIVE);
+    scb->flags |= SCB_ABORT | SCB_QUEUED_FOR_DONE;
+    goto success;
+  }
+
+/*
+ *  We just checked the waiting_q, now for the QINFIFO
+ */
+  if ( ((found = aic7xxx_search_qinfifo(p, cmd->device->id, cmd->device->channel,
+                     cmd->device->lun, scb->hscb->tag, SCB_ABORT | SCB_QUEUED_FOR_DONE,
+                     FALSE, NULL)) != 0) &&
+                    (aic7xxx_verbose & VERBOSE_ABORT_PROCESS))
+  {
+    printk(INFO_LEAD "SCB found in QINFIFO and aborted.\n", p->host_no,
+		    CTL_OF_SCB(scb));
+    goto success;
+  }
+
+/*
+ *  QINFIFO, waitingq, completeq done.  Next, check WAITING_SCB list in card
+ */
+
+  saved_hscbptr = aic_inb(p, SCBPTR);
+  if ((hscbptr = aic7xxx_find_scb(p, scb)) != SCB_LIST_NULL)
+  {
+    aic_outb(p, hscbptr, SCBPTR);
+    scb_control = aic_inb(p, SCB_CONTROL);
+    disconnected = scb_control & DISCONNECTED;
+    /*
+     * If the DISCONNECTED bit is not set in SCB_CONTROL, then we are
+     * either currently active or on the waiting list.
+     */
+    if(!disconnected && aic_inb(p, LASTPHASE) == P_BUSFREE) {
+      if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+        printk(INFO_LEAD "SCB found on hardware waiting"
+          " list and aborted.\n", p->host_no, CTL_OF_SCB(scb));
+      /* If we are the only waiting command, stop the selection engine */
+      if (aic_inb(p, WAITING_SCBH) == hscbptr && aic_inb(p, SCB_NEXT) ==
+			SCB_LIST_NULL)
+      {
+        aic_outb(p, aic_inb(p, SCSISEQ) & ~ENSELO, SCSISEQ);
+        aic_outb(p, CLRSELTIMEO, CLRSINT1);
+	aic_outb(p, SCB_LIST_NULL, WAITING_SCBH);
+      }
+      else
+      {
+	unsigned char prev, next;
+	prev = SCB_LIST_NULL;
+	next = aic_inb(p, WAITING_SCBH);
+	while(next != SCB_LIST_NULL)
+	{
+	  aic_outb(p, next, SCBPTR);
+	  if (next == hscbptr)
+	  {
+	    next = aic_inb(p, SCB_NEXT);
+	    if (prev != SCB_LIST_NULL)
+	    {
+	      aic_outb(p, prev, SCBPTR);
+	      aic_outb(p, next, SCB_NEXT);
+	    }
+	    else
+	      aic_outb(p, next, WAITING_SCBH);
+	    aic_outb(p, hscbptr, SCBPTR);
+	    next = SCB_LIST_NULL;
+	  }
+	  else
+	  {
+	    prev = next;
+	    next = aic_inb(p, SCB_NEXT);
+	  }
+	}
+      }
+      aic_outb(p, SCB_LIST_NULL, SCB_TAG);
+      aic_outb(p, 0, SCB_CONTROL);
+      aic7xxx_add_curscb_to_free_list(p);
+      scb->flags = SCB_ABORT | SCB_QUEUED_FOR_DONE;
+      goto success;
+    }
+    else if (!disconnected)
+    {
+      /*
+       * We are the currently active command
+       */
+      if((aic_inb(p, LASTPHASE) == P_MESGIN) ||
+	 (aic_inb(p, LASTPHASE) == P_MESGOUT))
+      {
+	/*
+	 * Message buffer busy, unable to abort
+	 */
+	printk(INFO_LEAD "message buffer busy, unable to abort.\n",
+			  p->host_no, CTL_OF_SCB(scb));
+	unpause_sequencer(p, FALSE);
+	return FAILED;
+      }
+      /* Fallthrough to below, set ATNO after we set SCB_CONTROL */
+    } 
+    aic_outb(p,  scb_control | MK_MESSAGE, SCB_CONTROL);
+    if(!disconnected)
+    {
+      aic_outb(p, HOST_MSG, MSG_OUT);
+      aic_outb(p, aic_inb(p, SCSISIGI) | ATNO, SCSISIGO);
+    }
+    aic_outb(p, saved_hscbptr, SCBPTR);
+  } 
+  else
+  {
+    /*
+     * The scb isn't in the card at all and it is active and it isn't in
+     * any of the queues, so it must be disconnected and paged out.  Fall
+     * through to the code below.
+     */
+    disconnected = 1;
+  }
+        
+  p->flags |= AHC_ABORT_PENDING;
+  scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+  scb->hscb->control |= MK_MESSAGE;
+  if(disconnected)
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_PROCESS)
+      printk(INFO_LEAD "SCB disconnected.  Queueing Abort"
+        " SCB.\n", p->host_no, CTL_OF_SCB(scb));
+    p->qinfifo[p->qinfifonext++] = scb->hscb->tag;
+    if (p->features & AHC_QUEUE_REGS)
+      aic_outb(p, p->qinfifonext, HNSCB_QOFF);
+    else
+      aic_outb(p, p->qinfifonext, KERNEL_QINPOS);
+  }
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  msleep(1000/4);
+  spin_lock_irq(p->host->host_lock);
+  if (p->flags & AHC_ABORT_PENDING)
+  {
+    if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+      printk(INFO_LEAD "Abort never delivered, returning FAILED\n", p->host_no,
+		    CTL_OF_CMD(cmd));
+    p->flags &= ~AHC_ABORT_PENDING;
+    return FAILED;
+  }
+  if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+    printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
+  return SUCCESS;
+
+success:
+  if (aic7xxx_verbose & VERBOSE_ABORT_RETURN)
+    printk(INFO_LEAD "Abort successful.\n", p->host_no, CTL_OF_CMD(cmd));
+  aic7xxx_run_done_queue(p, TRUE);
+  unpause_sequencer(p, FALSE);
+  return SUCCESS;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_reset
+ *
+ * Description:
+ *   Resetting the bus always succeeds - is has to, otherwise the
+ *   kernel will panic! Try a surgical technique - sending a BUS
+ *   DEVICE RESET message - on the offending target before pulling
+ *   the SCSI bus reset line.
+ *-F*************************************************************************/
+static int
+aic7xxx_reset(Scsi_Cmnd *cmd)
+{
+  struct aic7xxx_scb *scb;
+  struct aic7xxx_host *p;
+  struct aic_dev_data *aic_dev;
+
+  p = (struct aic7xxx_host *) cmd->device->host->hostdata;
+  aic_dev = AIC_DEV(cmd);
+  if(aic7xxx_position(cmd) < p->scb_data->numscbs)
+  {
+    scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+    if (scb->cmd != cmd)
+      scb = NULL;
+  }
+  else
+  {
+    scb = NULL;
+  }
+
+  /*
+   * I added a new config option to the driver: "panic_on_abort" that will
+   * cause the driver to panic and the machine to stop on the first abort
+   * or reset call into the driver.  At that point, it prints out a lot of
+   * useful information for me which I can then use to try and debug the
+   * problem.  Simply enable the boot time prompt in order to activate this
+   * code.
+   */
+  if (aic7xxx_panic_on_abort)
+    aic7xxx_panic_abort(p, cmd);
+
+  pause_sequencer(p);
+
+  while((aic_inb(p, INTSTAT) & INT_PEND) && !(p->flags & AHC_IN_ISR))
+  {
+    aic7xxx_isr(p->irq, p, (void *)NULL );
+    pause_sequencer(p);
+  }
+  aic7xxx_done_cmds_complete(p);
+
+  if(scb && (scb->cmd == NULL))
+  {
+    /*
+     * We just completed the command when we ran the isr stuff, so we no
+     * longer have it.
+     */
+    unpause_sequencer(p, FALSE);
+    return SUCCESS;
+  }
+    
+/*
+ *  By this point, we want to already know what we are going to do and
+ *  only have the following code implement our course of action.
+ */
+  aic7xxx_reset_channel(p, cmd->device->channel, TRUE);
+  if (p->features & AHC_TWIN)
+  {
+    aic7xxx_reset_channel(p, cmd->device->channel ^ 0x01, TRUE);
+    restart_sequencer(p);
+  }
+  aic_outb(p,  aic_inb(p, SIMODE1) & ~(ENREQINIT|ENBUSFREE), SIMODE1);
+  aic7xxx_clear_intstat(p);
+  p->flags &= ~AHC_HANDLING_REQINITS;
+  p->msg_type = MSG_TYPE_NONE;
+  p->msg_index = 0;
+  p->msg_len = 0;
+  aic7xxx_run_done_queue(p, TRUE);
+  unpause_sequencer(p, FALSE);
+  spin_unlock_irq(p->host->host_lock);
+  ssleep(2);
+  spin_lock_irq(p->host->host_lock);
+  return SUCCESS;
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_biosparam
+ *
+ * Description:
+ *   Return the disk geometry for the given SCSI device.
+ *
+ * Note:
+ *   This function is broken for today's really large drives and needs
+ *   fixed.
+ *-F*************************************************************************/
+static int
+aic7xxx_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int geom[])
+{
+  sector_t heads, sectors, cylinders;
+  int ret;
+  struct aic7xxx_host *p;
+  unsigned char *buf;
+
+  p = (struct aic7xxx_host *) sdev->host->hostdata;
+  buf = scsi_bios_ptable(bdev);
+
+  if ( buf )
+  {
+    ret = scsi_partsize(buf, capacity, &geom[2], &geom[0], &geom[1]);
+    kfree(buf);
+    if ( ret != -1 )
+      return(ret);
+  }
+  
+  heads = 64;
+  sectors = 32;
+  cylinders = capacity >> 11;
+
+  if ((p->flags & AHC_EXTEND_TRANS_A) && (cylinders > 1024))
+  {
+    heads = 255;
+    sectors = 63;
+    cylinders = capacity >> 14;
+    if(capacity > (65535 * heads * sectors))
+      cylinders = 65535;
+    else
+      cylinders = ((unsigned int)capacity) / (unsigned int)(heads * sectors);
+  }
+
+  geom[0] = (int)heads;
+  geom[1] = (int)sectors;
+  geom[2] = (int)cylinders;
+
+  return (0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_release
+ *
+ * Description:
+ *   Free the passed in Scsi_Host memory structures prior to unloading the
+ *   module.
+ *-F*************************************************************************/
+static int
+aic7xxx_release(struct Scsi_Host *host)
+{
+  struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
+  struct aic7xxx_host *next, *prev;
+
+  if(p->irq)
+    free_irq(p->irq, p);
+#ifdef MMAPIO
+  if(p->maddr)
+  {
+    iounmap(p->maddr);
+  }
+#endif /* MMAPIO */
+  if(!p->pdev)
+    release_region(p->base, MAXREG - MINREG);
+#ifdef CONFIG_PCI
+  else
+    pci_release_regions(p->pdev);
+#endif
+  prev = NULL;
+  next = first_aic7xxx;
+  while(next != NULL)
+  {
+    if(next == p)
+    {
+      if(prev == NULL)
+        first_aic7xxx = next->next;
+      else
+        prev->next = next->next;
+    }
+    else
+    {
+      prev = next;
+    }
+    next = next->next;
+  }
+  aic7xxx_free(p);
+  return(0);
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_card
+ *
+ * Description:
+ *   Print out all of the control registers on the card
+ *
+ *   NOTE: This function is not yet safe for use on the VLB and EISA
+ *   controllers, so it isn't used on those controllers at all.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_card(struct aic7xxx_host *p)
+{
+  int i, j, k, chip;
+  static struct register_ranges {
+    int num_ranges;
+    int range_val[32];
+  } cards_ds[] = {
+    { 0, {0,} }, /* none */
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1f, 0x1f, 0x60, 0x60, /*7771*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9b, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7850*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    { 9, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7860*/
+          0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1c, 0x1f, 0x60, 0x60, /*7870*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {10, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1a, 0x1c, 0x1f, 0x60, 0x60, /*7880*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9f} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7890*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x19, 0x1b, 0x1f, 0x60, 0x60, /*7895*/
+          0x62, 0x66, 0x80, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a,
+          0x9f, 0x9f, 0xe0, 0xf1} },
+    {16, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7896*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9f, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xf4, 0xf6, 0xf6, 0xf8, 0xf8, 0xfa, 0xfc,
+          0xfe, 0xff} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7892*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+    {12, {0x00, 0x05, 0x08, 0x11, 0x18, 0x1f, 0x60, 0x60, 0x62, 0x66, /*7899*/
+          0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
+          0xe0, 0xf1, 0xf4, 0xfc} },
+  };
+  chip = p->chip & AHC_CHIPID_MASK;
+  printk("%s at ",
+         board_names[p->board_name_index]);
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      printk("VLB Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      printk("EISA Slot %d.\n", p->pci_device_fn);
+      break;
+    case AHC_PCI:
+    default:
+      printk("PCI %d/%d/%d.\n", p->pci_bus, PCI_SLOT(p->pci_device_fn),
+             PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+
+  /*
+   * the registers on the card....
+   */
+  printk("Card Dump:\n");
+  k = 0;
+  for(i=0; i<cards_ds[chip].num_ranges; i++)
+  {
+    for(j  = cards_ds[chip].range_val[ i * 2 ];
+        j <= cards_ds[chip].range_val[ i * 2 + 1 ] ;
+        j++)
+    {
+      printk("%02x:%02x ", j, aic_inb(p, j));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  if(k != 0)
+    printk("\n");
+
+  /*
+   * If this was an Ultra2 controller, then we just hosed the card in terms
+   * of the QUEUE REGS.  This function is only called at init time or by
+   * the panic_abort function, so it's safe to assume a generic init time
+   * setting here
+   */
+
+  if(p->features & AHC_QUEUE_REGS)
+  {
+    aic_outb(p, 0, SDSCB_QOFF);
+    aic_outb(p, 0, SNSCB_QOFF);
+    aic_outb(p, 0, HNSCB_QOFF);
+  }
+
+}
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_print_scratch_ram
+ *
+ * Description:
+ *   Print out the scratch RAM values on the card.
+ *-F*************************************************************************/
+static void
+aic7xxx_print_scratch_ram(struct aic7xxx_host *p)
+{
+  int i, k;
+
+  k = 0;
+  printk("Scratch RAM:\n");
+  for(i = SRAM_BASE; i < SEQCTL; i++)
+  {
+    printk("%02x:%02x ", i, aic_inb(p, i));
+    if(++k == 13)
+    {
+      printk("\n");
+      k=0;
+    }
+  }
+  if (p->features & AHC_MORE_SRAM)
+  {
+    for(i = TARG_OFFSET; i < 0x80; i++)
+    {
+      printk("%02x:%02x ", i, aic_inb(p, i));
+      if(++k == 13)
+      {
+        printk("\n");
+        k=0;
+      }
+    }
+  }
+  printk("\n");
+}
+
+
+#include "aic7xxx_old/aic7xxx_proc.c"
+
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_VERSION(AIC7XXX_H_VERSION);
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_info		= aic7xxx_proc_info,
+	.detect			= aic7xxx_detect,
+	.release		= aic7xxx_release,
+	.info			= aic7xxx_info,	
+	.queuecommand		= aic7xxx_queue,
+	.slave_alloc		= aic7xxx_slave_alloc,
+	.slave_configure	= aic7xxx_slave_configure,
+	.slave_destroy		= aic7xxx_slave_destroy,
+	.bios_param		= aic7xxx_biosparam,
+	.eh_abort_handler	= aic7xxx_abort,
+	.eh_device_reset_handler	= aic7xxx_bus_device_reset,
+	.eh_host_reset_handler	= aic7xxx_reset,
+	.can_queue		= 255,
+	.this_id		= -1,
+	.max_sectors		= 2048,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+#include "scsi_module.c"
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h
new file mode 100644
index 0000000..0116c81
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.h
@@ -0,0 +1,28 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver for Linux.
+ *
+ * Copyright (c) 1994 John Aycock
+ *   The University of Calgary Department of Computer Science.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * 
+ * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+ *-M*************************************************************************/
+#ifndef _aic7xxx_h
+#define _aic7xxx_h
+
+#define AIC7XXX_H_VERSION  "5.2.0"
+
+#endif /* _aic7xxx_h */
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.reg b/drivers/scsi/aic7xxx_old/aic7xxx.reg
new file mode 100644
index 0000000..f67b4bc
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.reg
@@ -0,0 +1,1401 @@
+/*
+ * Aic7xxx register and scratch ram definitions.
+ *
+ * Copyright (c) 1994-1998 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$Id: aic7xxx.reg,v 1.4 1997/06/27 19:38:39 gibbs Exp $
+ */
+
+/*
+ * This file is processed by the aic7xxx_asm utility for use in assembling
+ * firmware for the aic7xxx family of SCSI host adapters as well as to generate
+ * a C header file for use in the kernel portion of the Aic7xxx driver.
+ *
+ * All page numbers refer to the Adaptec AIC-7770 Data Book available from
+ * Adaptec's Technical Documents Department 1-800-934-2766
+ */
+
+/*
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
+ */
+register SCSISEQ {
+	address			0x000
+	access_mode RW
+	bit	TEMODE		0x80
+	bit	ENSELO		0x40
+	bit	ENSELI		0x20
+	bit	ENRSELI		0x10
+	bit	ENAUTOATNO	0x08
+	bit	ENAUTOATNI	0x04
+	bit	ENAUTOATNP	0x02
+	bit	SCSIRSTO	0x01
+}
+
+/*
+ * SCSI Transfer Control 0 Register (pp. 3-13).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL0 {
+	address			0x001
+	access_mode RW
+	bit	DFON		0x80
+	bit	DFPEXP		0x40
+	bit	FAST20		0x20
+	bit	CLRSTCNT	0x10
+	bit	SPIOEN		0x08
+	bit	SCAMEN		0x04
+	bit	CLRCHN		0x02
+}
+
+/*
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
+ */
+register SXFRCTL1 {
+	address			0x002
+	access_mode RW
+	bit	BITBUCKET	0x80
+	bit	SWRAPEN		0x40
+	bit	ENSPCHK		0x20
+	mask	STIMESEL	0x18
+	bit	ENSTIMER	0x04
+	bit	ACTNEGEN	0x02
+	bit	STPWEN		0x01	/* Powered Termination */
+}
+
+/*
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
+ */
+register SCSISIGI {
+	address			0x003
+	access_mode RO
+	bit	CDI		0x80
+	bit	IOI		0x40
+	bit	MSGI		0x20
+	bit	ATNI		0x10
+	bit	SELI		0x08
+	bit	BSYI		0x04
+	bit	REQI		0x02
+	bit	ACKI		0x01
+/*
+ * Possible phases in SCSISIGI
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/*
+ * SCSI Control Signal Write Register (p. 3-16).
+ * Writing to this register modifies the control signals on the bus.  Only
+ * those signals that are allowed in the current mode (Initiator/Target) are
+ * asserted.
+ */
+register SCSISIGO {
+	address			0x003
+	access_mode WO
+	bit	CDO		0x80
+	bit	IOO		0x40
+	bit	MSGO		0x20
+	bit	ATNO		0x10
+	bit	SELO		0x08
+	bit	BSYO		0x04
+	bit	REQO		0x02
+	bit	ACKO		0x01
+/*
+ * Possible phases to write into SCSISIG0
+ */
+	mask	PHASE_MASK	CDI|IOI|MSGI
+	mask	P_DATAOUT	0x00
+	mask	P_DATAIN	IOI
+	mask	P_COMMAND	CDI
+	mask	P_MESGOUT	CDI|MSGI
+	mask	P_STATUS	CDI|IOI
+	mask	P_MESGIN	CDI|IOI|MSGI
+}
+
+/* 
+ * SCSI Rate Control (p. 3-17).
+ * Contents of this register determine the Synchronous SCSI data transfer
+ * rate and the maximum synchronous Req/Ack offset.  An offset of 0 in the
+ * SOFS (3:0) bits disables synchronous data transfers.  Any offset value
+ * greater than 0 enables synchronous transfers.
+ */
+register SCSIRATE {
+	address			0x004
+	access_mode RW
+	bit	WIDEXFER	0x80		/* Wide transfer control */
+	mask	SXFR		0x70		/* Sync transfer rate */
+	mask	SXFR_ULTRA2	0x7f		/* Sync transfer rate */
+	mask	SOFS		0x0f		/* Sync offset */
+}
+
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel.
+ */
+register SCSIID	{
+	address			0x005
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+	/*
+	 * SCSI Maximum Offset (p. 4-61 aic7890/91 Data Book)
+	 * The aic7890/91 allow an offset of up to 127 transfers in both wide
+	 * and narrow mode.
+	 */
+	alias	SCSIOFFSET
+	mask	SOFS_ULTRA2	0x7f		/* Sync offset U2 chips */
+}
+
+/*
+ * SCSI Latched Data (p. 3-19).
+ * Read/Write latches used to transfer data on the SCSI bus during
+ * Automatic or Manual PIO mode.  SCSIDATH can be used for the
+ * upper byte of a 16bit wide asynchronouse data phase transfer.
+ */
+register SCSIDATL {
+	address			0x006
+	access_mode RW
+}
+
+register SCSIDATH {
+	address			0x007
+	access_mode RW
+}
+
+/*
+ * SCSI Transfer Count (pp. 3-19,20)
+ * These registers count down the number of bytes transferred
+ * across the SCSI bus.  The counter is decremented only once
+ * the data has been safely transferred.  SDONE in SSTAT0 is
+ * set when STCNT goes to 0
+ */ 
+register STCNT {
+	address			0x008
+	size	3
+	access_mode RW
+}
+
+/*
+ * Option Mode Register (Alternate Mode) (p. 5-198)
+ * This register is used to set certain options on Ultra3 based chips.
+ * The chip must be in alternate mode (bit ALT_MODE in SFUNCT must be set)
+ */
+register OPTIONMODE {
+	address			0x008
+	access_mode RW
+	bit	AUTORATEEN	0x80
+	bit	AUTOACKEN	0x40
+	bit	ATNMGMNTEN	0x20
+	bit	BUSFREEREV	0x10
+	bit	EXPPHASEDIS	0x08
+	bit	SCSIDATL_IMGEN	0x04
+	bit	AUTO_MSGOUT_DE	0x02
+	bit	DIS_MSGIN_DUALEDGE	0x01
+}
+
+
+/*
+ * Clear SCSI Interrupt 0 (p. 3-20)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
+ */
+register CLRSINT0 {
+	address			0x00b
+	access_mode WO
+	bit	CLRSELDO	0x40
+	bit	CLRSELDI	0x20
+	bit	CLRSELINGO	0x10
+	bit	CLRSWRAP	0x08
+	bit	CLRSPIORDY	0x02
+}
+
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+register SSTAT0	{
+	address			0x00b
+	access_mode RO
+	bit	TARGET		0x80	/* Board acting as target */
+	bit	SELDO		0x40	/* Selection Done */
+	bit	SELDI		0x20	/* Board has been selected */
+	bit	SELINGO		0x10	/* Selection In Progress */
+	bit	SWRAP		0x08	/* 24bit counter wrap */
+	bit	IOERR		0x08	/* LVD Tranceiver mode changed */
+	bit	SDONE		0x04	/* STCNT = 0x000000 */
+	bit	SPIORDY		0x02	/* SCSI PIO Ready */
+	bit	DMADONE		0x01	/* DMA transfer completed */
+}
+
+/*
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
+ */
+register CLRSINT1 {
+	address			0x00c
+	access_mode WO
+	bit	CLRSELTIMEO	0x80
+	bit	CLRATNO		0x40
+	bit	CLRSCSIRSTI	0x20
+	bit	CLRBUSFREE	0x08
+	bit	CLRSCSIPERR	0x04
+	bit	CLRPHASECHG	0x02
+	bit	CLRREQINIT	0x01
+}
+
+/*
+ * SCSI Status 1 (p. 3-24)
+ */
+register SSTAT1	{
+	address			0x00c
+	access_mode RO
+	bit	SELTO		0x80
+	bit	ATNTARG 	0x40
+	bit	SCSIRSTI	0x20
+	bit	PHASEMIS	0x10
+	bit	BUSFREE		0x08
+	bit	SCSIPERR	0x04
+	bit	PHASECHG	0x02
+	bit	REQINIT		0x01
+}
+
+/*
+ * SCSI Status 2 (pp. 3-25,26)
+ */
+register SSTAT2 {
+	address			0x00d
+	access_mode RO
+	bit	OVERRUN		0x80
+	bit	SHVALID		0x40
+	bit	WIDE_RES	0x20
+	bit	EXP_ACTIVE	0x10	/* SCSI Expander Active */
+	bit	CRCVALERR	0x08	/* CRC Value Error */
+	bit	CRCENDERR	0x04	/* CRC End Error */
+	bit	CRCREQERR	0x02	/* CRC REQ Error */
+	bit	DUAL_EDGE_ERROR	0x01	/* Invalid pins for Dual Edge phase */
+	mask	SFCNT		0x1f
+}
+
+/*
+ * SCSI Status 3 (p. 3-26)
+ */
+register SSTAT3 {
+	address			0x00e
+	access_mode RO
+	mask	SCSICNT		0xf0
+	mask	OFFCNT		0x0f
+}
+
+/*
+ * SCSI ID for the aic7890/91 chips
+ */
+register SCSIID_ULTRA2 {
+	address			0x00f
+	access_mode RW
+	mask	TID		0xf0		/* Target ID mask */
+	mask	OID		0x0f		/* Our ID mask */
+}
+
+/*
+ * SCSI Interrupt Mode 1 (p. 3-28)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE0 to interrupt via the IRQ pin.
+ */
+register SIMODE0 {
+	address			0x010
+	access_mode RW
+	bit	ENSELDO		0x40
+	bit	ENSELDI		0x20
+	bit	ENSELINGO	0x10
+	bit	ENSWRAP		0x08
+	bit	ENIOERR		0x08	/* LVD Tranceiver mode changes */
+	bit	ENSDONE		0x04
+	bit	ENSPIORDY	0x02
+	bit	ENDMADONE	0x01
+}
+
+/*
+ * SCSI Interrupt Mode 1 (pp. 3-28,29)
+ * Setting any bit will enable the corresponding function
+ * in SIMODE1 to interrupt via the IRQ pin.
+ */
+register SIMODE1 {
+	address			0x011
+	access_mode RW
+	bit	ENSELTIMO	0x80
+	bit	ENATNTARG	0x40
+	bit	ENSCSIRST	0x20
+	bit	ENPHASEMIS	0x10
+	bit	ENBUSFREE	0x08
+	bit	ENSCSIPERR	0x04
+	bit	ENPHASECHG	0x02
+	bit	ENREQINIT	0x01
+}
+
+/*
+ * SCSI Data Bus (High) (p. 3-29)
+ * This register reads data on the SCSI Data bus directly.
+ */
+register SCSIBUSL {
+	address			0x012
+	access_mode RO
+}
+
+register SCSIBUSH {
+	address			0x013
+	access_mode RO
+}
+
+/*
+ * SCSI/Host Address (p. 3-30)
+ * These registers hold the host address for the byte about to be
+ * transferred on the SCSI bus.  They are counted up in the same
+ * manner as STCNT is counted down.  SHADDR should always be used
+ * to determine the address of the last byte transferred since HADDR
+ * can be skewed by write ahead.
+ */
+register SHADDR {
+	address			0x014
+	size	4
+	access_mode RO
+}
+
+/*
+ * Selection Timeout Timer (p. 3-30)
+ */
+register SELTIMER {
+	address			0x018
+	access_mode RW
+	bit	STAGE6		0x20
+	bit	STAGE5		0x10
+	bit	STAGE4		0x08
+	bit	STAGE3		0x04
+	bit	STAGE2		0x02
+	bit	STAGE1		0x01
+}
+
+/*
+ * Selection/Reselection ID (p. 3-31)
+ * Upper four bits are the device id.  The ONEBIT is set when the re/selecting
+ * device did not set its own ID.
+ */
+register SELID {
+	address			0x019
+	access_mode RW
+	mask	SELID_MASK	0xf0
+	bit	ONEBIT		0x08
+}
+
+/*
+ * Serial Port I/O Cabability register (p. 4-95 aic7860 Data Book)
+ * Indicates if external logic has been attached to the chip to
+ * perform the tasks of accessing a serial eeprom, testing termination
+ * strength, and performing cable detection.  On the aic7860, most of
+ * these features are handled on chip, but on the aic7855 an attached
+ * aic3800 does the grunt work.
+ */
+register SPIOCAP {
+	address			0x01b
+	access_mode RW
+	bit	SOFT1		0x80
+	bit	SOFT0		0x40
+	bit	SOFTCMDEN	0x20	
+	bit	HAS_BRDCTL	0x10	/* External Board control */
+	bit	SEEPROM		0x08	/* External serial eeprom logic */
+	bit	EEPROM		0x04	/* Writable external BIOS ROM */
+	bit	ROM		0x02	/* Logic for accessing external ROM */
+	bit	SSPIOCPS	0x01	/* Termination and cable detection */
+}
+
+/*
+ * SCSI Block Control (p. 3-32)
+ * Controls Bus type and channel selection.  In a twin channel configuration
+ * addresses 0x00-0x1e are gated to the appropriate channel based on this
+ * register.  SELWIDE allows for the coexistence of 8bit and 16bit devices
+ * on a wide bus.
+ */
+register SBLKCTL {
+	address			0x01f
+	access_mode RW
+	bit	DIAGLEDEN	0x80	/* Aic78X0 only */
+	bit	DIAGLEDON	0x40	/* Aic78X0 only */
+	bit	AUTOFLUSHDIS	0x20
+	bit	SELBUSB		0x08
+	bit	ENAB40		0x08	/* LVD transceiver active */
+	bit	ENAB20		0x04	/* SE/HVD transceiver active */
+	bit	SELWIDE		0x02
+	bit	XCVR		0x01	/* External transceiver active */
+}
+
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+register SEQCTL {
+	address			0x060
+	access_mode RW
+	bit	PERRORDIS	0x80
+	bit	PAUSEDIS	0x40
+	bit	FAILDIS		0x20
+	bit	FASTMODE	0x10
+	bit	BRKADRINTEN	0x08
+	bit	STEP		0x04
+	bit	SEQRESET	0x02
+	bit	LOADRAM		0x01
+}
+
+/*
+ * Sequencer RAM Data (p. 3-34)
+ * Single byte window into the Scratch Ram area starting at the address
+ * specified by SEQADDR0 and SEQADDR1.  To write a full word, simply write
+ * four bytes in succession.  The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+register SEQRAM {
+	address			0x061
+	access_mode RW
+}
+
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+register SEQADDR0 {
+	address			0x062
+	access_mode RW
+}
+
+register SEQADDR1 {
+	address			0x063
+	access_mode RW
+	mask	SEQADDR1_MASK	0x01
+}
+
+/*
+ * Accumulator
+ * We cheat by passing arguments in the Accumulator up to the kernel driver
+ */
+register ACCUM {
+	address			0x064
+	access_mode RW
+	accumulator
+}
+
+register SINDEX	{
+	address			0x065
+	access_mode RW
+	sindex
+}
+
+register DINDEX {
+	address			0x066
+	access_mode RW
+}
+
+register ALLONES {
+	address			0x069
+	access_mode RO
+	allones
+}
+
+register ALLZEROS {
+	address			0x06a
+	access_mode RO
+	allzeros
+}
+
+register NONE {
+	address			0x06a
+	access_mode WO
+	none
+}
+
+register FLAGS {
+	address			0x06b
+	access_mode RO
+	bit	ZERO		0x02
+	bit	CARRY		0x01
+}
+
+register SINDIR	{
+	address			0x06c
+	access_mode RO
+}
+
+register DINDIR	 {
+	address			0x06d
+	access_mode WO
+}
+
+register FUNCTION1 {
+	address			0x06e
+	access_mode RW
+}
+
+register STACK {
+	address			0x06f
+	access_mode RO
+}
+
+/*
+ * Board Control (p. 3-43)
+ */
+register BCTL {
+	address			0x084
+	access_mode RW
+	bit	ACE		0x08
+	bit	ENABLE		0x01
+}
+
+register DSCOMMAND0 {
+	address			0x084
+	access_mode RW
+	bit	CACHETHEN	0x80
+	bit	DPARCKEN	0x40
+	bit	MPARCKEN	0x20
+	bit	EXTREQLCK	0x10
+	bit	INTSCBRAMSEL	0x08
+	bit	RAMPS		0x04
+	bit	USCBSIZE32	0x02
+	bit	CIOPARCKEN	0x01
+}
+
+/*
+ * On the aic78X0 chips, Board Control is replaced by the DSCommand
+ * register (p. 4-64)
+ */
+register DSCOMMAND {
+	address			0x084
+	access_mode RW
+	bit	CACHETHEN	0x80	/* Cache Threshold enable */
+	bit	DPARCKEN	0x40	/* Data Parity Check Enable */
+	bit	MPARCKEN	0x20	/* Memory Parity Check Enable */
+	bit	EXTREQLCK	0x10	/* External Request Lock */
+}
+
+/*
+ * Bus On/Off Time (p. 3-44)
+ */
+register BUSTIME {
+	address			0x085
+	access_mode RW
+	mask	BOFF		0xf0
+	mask	BON		0x0f
+}
+
+/*
+ * Bus Speed (p. 3-45)
+ */
+register BUSSPD {
+	address			0x086
+	access_mode RW
+	mask	DFTHRSH		0xc0
+	mask	STBOFF		0x38
+	mask	STBON		0x07
+	mask	DFTHRSH_100	0xc0
+}
+
+/*
+ * Host Control (p. 3-47) R/W
+ * Overall host control of the device.
+ */
+register HCNTRL {
+	address			0x087
+	access_mode RW
+	bit	POWRDN		0x40
+	bit	SWINT		0x10
+	bit	IRQMS		0x08
+	bit	PAUSE		0x04
+	bit	INTEN		0x02
+	bit	CHIPRST		0x01
+	bit	CHIPRSTACK	0x01
+}
+
+/*
+ * Host Address (p. 3-48)
+ * This register contains the address of the byte about
+ * to be transferred across the host bus.
+ */
+register HADDR {
+	address			0x088
+	size	4
+	access_mode RW
+}
+
+register HCNT {
+	address			0x08c
+	size	3
+	access_mode RW
+}
+
+/*
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
+ */
+register SCBPTR {
+	address			0x090
+	access_mode RW
+}
+
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+register INTSTAT {
+	address			0x091
+	access_mode RW
+	bit	BRKADRINT 0x08
+	bit	SCSIINT	  0x04
+	bit	CMDCMPLT  0x02
+	bit	SEQINT    0x01
+	mask	BAD_PHASE	SEQINT		/* unknown scsi bus phase */
+	mask	SEND_REJECT	0x10|SEQINT	/* sending a message reject */
+	mask	NO_IDENT	0x20|SEQINT	/* no IDENTIFY after reconnect*/
+	mask	NO_MATCH	0x30|SEQINT	/* no cmd match for reconnect */
+	mask	EXTENDED_MSG	0x40|SEQINT	/* Extended message received */
+	mask	WIDE_RESIDUE	0x50|SEQINT	/* need kernel to back up */
+						/* the SG array for us */
+	mask	REJECT_MSG	0x60|SEQINT	/* Reject message received */
+	mask	BAD_STATUS	0x70|SEQINT	/* Bad status from target */
+	mask	RESIDUAL	0x80|SEQINT	/* Residual byte count != 0 */
+	mask	AWAITING_MSG	0xa0|SEQINT	/*
+						 * Kernel requested to specify
+						 * a message to this target
+						 * (command was null), so tell
+						 * it that it can fill the
+						 * message buffer.
+						 */
+	mask	SEQ_SG_FIXUP	0xb0|SEQINT	/* need help with fixing up
+						 * the sg array pointer after
+						 * a phasemis with no valid
+						 * sg elements in the shadow
+						 * pipeline.
+						 */
+	mask	TRACEPOINT2	0xc0|SEQINT
+	mask	MSGIN_PHASEMIS	0xd0|SEQINT	/*
+						 * Target changed phase on us
+						 * when we were expecting
+						 * another msgin byte.
+						 */
+	mask	DATA_OVERRUN	0xe0|SEQINT	/*
+						 * Target attempted to write
+						 * beyond the bounds of its
+						 * command.
+						 */
+
+	mask	SEQINT_MASK	0xf0|SEQINT	/* SEQINT Status Codes */
+	mask	INT_PEND  (BRKADRINT|SEQINT|SCSIINT|CMDCMPLT)
+}
+
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors.  You usually cannot recover from
+ * these without a full board reset.
+ */
+register ERROR {
+	address			0x092
+	access_mode RO
+	bit	CIOPARERR	0x80	/* Ultra2 only */
+	bit	PCIERRSTAT	0x40	/* PCI only */
+	bit	MPARERR		0x20	/* PCI only */
+	bit	DPARERR		0x10	/* PCI only */
+	bit	SQPARERR	0x08
+	bit	ILLOPCODE	0x04
+	bit	ILLSADDR	0x02
+	bit	DSCTMOUT	0x02	/* Ultra3 only */
+	bit	ILLHADDR	0x01
+}
+
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+register CLRINT {
+	address			0x092
+	access_mode WO
+	bit	CLRPARERR	0x10	/* PCI only */
+	bit	CLRBRKADRINT	0x08
+	bit	CLRSCSIINT      0x04
+	bit	CLRCMDINT 	0x02
+	bit	CLRSEQINT 	0x01
+}
+
+register DFCNTRL {
+	address			0x093
+	access_mode RW
+	bit	PRELOADEN	0x80	/* aic7890 only */
+	bit	WIDEODD		0x40
+	bit	SCSIEN		0x20
+	bit	SDMAEN		0x10
+	bit	SDMAENACK	0x10
+	bit	HDMAEN		0x08
+	bit	HDMAENACK	0x08
+	bit	DIRECTION	0x04
+	bit	FIFOFLUSH	0x02
+	bit	FIFORESET	0x01
+}
+
+register DFSTATUS {
+	address			0x094
+	access_mode RO
+	bit	PRELOAD_AVAIL	0x80
+	bit	DWORDEMP	0x20
+	bit	MREQPEND	0x10
+	bit	HDONE		0x08
+	bit	DFTHRESH	0x04
+	bit	FIFOFULL	0x02
+	bit	FIFOEMP		0x01
+}
+
+register DFDAT {
+	address			0x099
+	access_mode RW
+}
+
+/*
+ * SCB Auto Increment (p. 3-59)
+ * Byte offset into the SCB Array and an optional bit to allow auto
+ * incrementing of the address during download and upload operations
+ */
+register SCBCNT {
+	address			0x09a
+	access_mode RW
+	bit	SCBAUTO		0x80
+	mask	SCBCNT_MASK	0x1f
+}
+
+/*
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
+ */
+register QINFIFO {
+	address			0x09b
+	access_mode RW
+}
+
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+register QINCNT	{
+	address			0x09c
+	access_mode RO
+}
+
+/*
+ * SCSIDATL IMAGE Register (p. 5-104)
+ * Write to this register also go to SCSIDATL but this register will preserve
+ * the data for later reading as long as the SCSIDATL_IMGEN bit in the
+ * OPTIONMODE register is set.
+ */
+register SCSIDATL_IMG {
+	address			0x09c
+	access_mode RW
+}
+
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+register QOUTFIFO {
+	address			0x09d
+	access_mode WO
+}
+
+/*
+ * CRC Control 1 Register (p. 5-105)
+ * Control bits for the Ultra 160/m CRC facilities
+ */
+register CRCCONTROL1 {
+	address			0x09d
+	access_mode RW
+	bit	CRCONSEEN	0x80 /* CRC ON Single Edge ENable */
+	bit	CRCVALCHKEN	0x40 /* CRC Value Check Enable */
+	bit	CRCENDCHKEN	0x20 /* CRC End Check Enable */
+	bit	CRCREQCHKEN	0x10
+	bit	TARGCRCENDEN	0x08 /* Enable End CRC transfer when target */
+	bit	TARGCRCCNTEN	0x04 /* Enable CRC transfer when target */
+}
+
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+register QOUTCNT {
+	address			0x09e
+	access_mode RO
+}
+
+/*
+ * SCSI Phase Register (p. 5-106)
+ * Current bus phase
+ */
+register SCSIPHASE {
+	address			0x09e
+	access_mode RO
+	bit	SP_STATUS		0x20
+	bit	SP_COMMAND		0x10
+	bit	SP_MSG_IN		0x08
+	bit	SP_MSG_OUT		0x04
+	bit	SP_DATA_IN		0x02
+	bit	SP_DATA_OUT	0x01
+}
+
+/*
+ * Special Function
+ */
+register SFUNCT {
+	address			0x09f
+	access_mode RW
+	bit	ALT_MODE	0x80
+}
+
+/*
+ * SCB Definition (p. 5-4)
+ */
+scb {
+	address			0x0a0
+	SCB_CONTROL {
+		size	1
+		bit	MK_MESSAGE      0x80
+		bit	DISCENB         0x40
+		bit	TAG_ENB		0x20
+		bit	DISCONNECTED	0x04
+		mask	SCB_TAG_TYPE	0x03
+	}
+	SCB_TCL {
+		size	1
+		bit	SELBUSB		0x08
+		mask	TID		0xf0
+		mask	LID		0x07
+	}
+	SCB_TARGET_STATUS {
+		size	1
+	}
+	SCB_SGCOUNT {
+		size	1
+	}
+	SCB_SGPTR {
+		size	4
+	}
+	SCB_RESID_SGCNT {
+		size	1
+	}
+	SCB_RESID_DCNT	{
+		size	3
+	}
+	SCB_DATAPTR {
+		size	4
+	}
+	SCB_DATACNT {
+		/*
+		 * Really only 3 bytes, but padded to make
+		 * the kernel's job easier.
+		 */
+		size	4
+	}
+	SCB_CMDPTR {
+		size	4
+	}
+	SCB_CMDLEN {
+		size	1
+	}
+	SCB_TAG {
+		size	1
+	}
+	SCB_NEXT {
+		size	1
+	}
+	SCB_PREV {
+		size	1
+	}
+	SCB_BUSYTARGETS {
+		size	4
+	}
+}
+
+const	SG_SIZEOF	0x08		/* sizeof(struct ahc_dma) */
+
+/* --------------------- AHA-2840-only definitions -------------------- */
+
+register SEECTL_2840 {
+	address			0x0c0
+	access_mode RW
+	bit	CS_2840		0x04
+	bit	CK_2840		0x02
+	bit	DO_2840		0x01
+}
+
+register STATUS_2840 {
+	address			0x0c1
+	access_mode RW
+	bit	EEPROM_TF	0x80
+	mask	BIOS_SEL	0x60
+	mask	ADSEL		0x1e
+	bit	DI_2840		0x01
+}
+
+/* --------------------- AIC-7870-only definitions -------------------- */
+
+register DSPCISTATUS {
+	address			0x086
+	mask	DFTHRSH_100	0xc0
+}
+
+register CCHADDR {
+	address			0x0E0
+	size 8
+}
+
+register CCHCNT {
+	address			0x0E8
+}
+
+register CCSGRAM {
+	address			0x0E9
+}
+
+register CCSGADDR {
+	address			0x0EA
+}
+
+register CCSGCTL {
+	address			0x0EB
+	bit	CCSGDONE	0x80
+	bit	CCSGEN		0x08
+	bit	FLAG		0x02
+	bit	CCSGRESET	0x01
+}
+
+register CCSCBCNT {
+	address			0xEF
+}
+
+register CCSCBCTL {
+	address			0x0EE
+	bit	CCSCBDONE	0x80
+	bit	ARRDONE		0x40	/* SCB Array prefetch done */
+	bit	CCARREN		0x10
+	bit	CCSCBEN		0x08
+	bit	CCSCBDIR	0x04
+	bit	CCSCBRESET	0x01
+}
+
+register CCSCBADDR {
+	address			0x0ED
+}
+
+register CCSCBRAM {
+	address			0xEC
+}
+
+register CCSCBPTR {
+	address			0x0F1
+}
+
+register HNSCB_QOFF {
+	address			0x0F4
+}
+
+register HESCB_QOFF {
+	address			0x0F5
+}
+
+register SNSCB_QOFF {
+	address			0x0F6
+}
+
+register SESCB_QOFF {
+	address			0x0F7
+}
+
+register SDSCB_QOFF {
+	address			0x0F8
+}
+
+register QOFF_CTLSTA {
+	address			0x0FA
+	bit	ESTABLISH_SCB_AVAIL	0x80
+	bit	SCB_AVAIL	0x40
+	bit	SNSCB_ROLLOVER	0x20
+	bit	SDSCB_ROLLOVER	0x10
+	bit	SESCB_ROLLOVER	0x08
+	mask	SCB_QSIZE	0x07
+	mask	SCB_QSIZE_256	0x06
+}
+
+register DFF_THRSH {
+	address			0x0FB
+	mask	WR_DFTHRSH	0x70
+	mask	RD_DFTHRSH	0x07
+	mask	RD_DFTHRSH_MIN	0x00
+	mask	RD_DFTHRSH_25	0x01
+	mask	RD_DFTHRSH_50	0x02
+	mask	RD_DFTHRSH_63	0x03
+	mask	RD_DFTHRSH_75	0x04
+	mask	RD_DFTHRSH_85	0x05
+	mask	RD_DFTHRSH_90	0x06
+	mask	RD_DFTHRSH_MAX	0x07
+	mask	WR_DFTHRSH_MIN	0x00
+	mask	WR_DFTHRSH_25	0x10
+	mask	WR_DFTHRSH_50	0x20
+	mask	WR_DFTHRSH_63	0x30
+	mask	WR_DFTHRSH_75	0x40
+	mask	WR_DFTHRSH_85	0x50
+	mask	WR_DFTHRSH_90	0x60
+	mask	WR_DFTHRSH_MAX	0x70
+}
+
+register SG_CACHEPTR {
+	access_mode RW
+	address			0x0fc
+	mask	SG_USER_DATA	0xfc
+	bit	LAST_SEG	0x02
+	bit	LAST_SEG_DONE	0x01
+}
+
+register BRDCTL	{
+	address			0x01d
+	bit	BRDDAT7		0x80
+	bit	BRDDAT6		0x40
+	bit	BRDDAT5		0x20
+	bit	BRDSTB		0x10
+	bit	BRDCS		0x08
+	bit	BRDRW		0x04
+	bit	BRDCTL1		0x02
+	bit	BRDCTL0		0x01
+	/* 7890 Definitions */
+	bit	BRDDAT4		0x10
+	bit	BRDDAT3		0x08
+	bit	BRDDAT2		0x04
+	bit	BRDRW_ULTRA2	0x02
+	bit	BRDSTB_ULTRA2	0x01
+}
+
+/*
+ * Serial EEPROM Control (p. 4-92 in 7870 Databook)
+ * Controls the reading and writing of an external serial 1-bit
+ * EEPROM Device.  In order to access the serial EEPROM, you must
+ * first set the SEEMS bit that generates a request to the memory
+ * port for access to the serial EEPROM device.  When the memory
+ * port is not busy servicing another request, it reconfigures
+ * to allow access to the serial EEPROM.  When this happens, SEERDY
+ * gets set high to verify that the memory port access has been
+ * granted.  
+ *
+ * After successful arbitration for the memory port, the SEECS bit of 
+ * the SEECTL register is connected to the chip select.  The SEECK, 
+ * SEEDO, and SEEDI are connected to the clock, data out, and data in 
+ * lines respectively.  The SEERDY bit of SEECTL is useful in that it 
+ * gives us an 800 nsec timer.  After a write to the SEECTL register, 
+ * the SEERDY goes high 800 nsec later.  The one exception to this is 
+ * when we first request access to the memory port.  The SEERDY goes 
+ * high to signify that access has been granted and, for this case, has 
+ * no implied timing.
+ *
+ * See 93cx6.c for detailed information on the protocol necessary to 
+ * read the serial EEPROM.
+ */
+register SEECTL {
+	address			0x01e
+	bit	EXTARBACK	0x80
+	bit	EXTARBREQ	0x40
+	bit	SEEMS		0x20
+	bit	SEERDY		0x10
+	bit	SEECS		0x08
+	bit	SEECK		0x04
+	bit	SEEDO		0x02
+	bit	SEEDI		0x01
+}
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the sequencer code.
+ *
+ * The host adapter card (at least the BIOS) uses 20-2f for SCSI
+ * device information, 32-33 and 5a-5f as well. As it turns out, the
+ * BIOS trashes 20-2f, writing the synchronous negotiation results
+ * on top of the BIOS values, so we re-use those for our per-target
+ * scratchspace (actually a value that can be copied directly into
+ * SCSIRATE).  The kernel driver will enable synchronous negotiation
+ * for all targets that have a value other than 0 in the lower four
+ * bits of the target scratch space.  This should work regardless of
+ * whether the bios has been installed.
+ */
+
+scratch_ram {
+	address			0x020
+
+	/*
+	 * 1 byte per target starting at this address for configuration values
+	 */
+	TARG_SCSIRATE {
+		size		16
+	}
+	/*
+	 * Bit vector of targets that have ULTRA enabled.
+	 */
+	ULTRA_ENB {
+		size		2
+	}
+	/*
+	 * Bit vector of targets that have disconnection disabled.
+	 */
+	DISC_DSB {
+		size		2
+	}
+	/*
+	 * Single byte buffer used to designate the type or message
+	 * to send to a target.
+	 */
+	MSG_OUT {
+		size		1
+	}
+	/* Parameters for DMA Logic */
+	DMAPARAMS {
+		size		1
+		bit	PRELOADEN	0x80
+		bit	WIDEODD		0x40
+		bit	SCSIEN		0x20
+		bit	SDMAEN		0x10
+		bit	SDMAENACK	0x10
+		bit	HDMAEN		0x08
+		bit	HDMAENACK	0x08
+		bit	DIRECTION	0x04
+		bit	FIFOFLUSH	0x02
+		bit	FIFORESET	0x01
+	}
+	SEQ_FLAGS {
+		size		1
+		bit	IDENTIFY_SEEN	0x80
+		bit	SCBPTR_VALID	0x20
+		bit	DPHASE		0x10
+		bit	AMTARGET	0x08
+		bit	WIDE_BUS	0x02
+		bit	TWIN_BUS	0x01
+	}
+	/*
+	 * Temporary storage for the
+	 * target/channel/lun of a
+	 * reconnecting target
+	 */
+	SAVED_TCL {
+		size		1
+	}
+	/* Working value of the number of SG segments left */
+	SG_COUNT {
+		size		1
+	}
+	/* Working value of SG pointer */
+	SG_NEXT	{
+		size		4
+	}
+	/*
+	 * The last bus phase as seen by the sequencer. 
+	 */
+	LASTPHASE {
+		size		1
+		bit	CDI		0x80
+		bit	IOI		0x40
+		bit	MSGI		0x20
+		mask	PHASE_MASK	CDI|IOI|MSGI
+		mask	P_DATAOUT	0x00
+		mask	P_DATAIN	IOI
+		mask	P_COMMAND	CDI
+		mask	P_MESGOUT	CDI|MSGI
+		mask	P_STATUS	CDI|IOI
+		mask	P_MESGIN	CDI|IOI|MSGI
+		mask	P_BUSFREE	0x01
+	}
+	/*
+	 * head of list of SCBs awaiting
+	 * selection
+	 */
+	WAITING_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * disconnected.  Used for SCB
+	 * paging.
+	 */
+	DISCONNECTED_SCBH {
+		size		1
+	}
+	/*
+	 * head of list of SCBs that are
+	 * not in use.  Used for SCB paging.
+	 */
+	FREE_SCBH {
+		size		1
+	}
+	/*
+	 * Address of the hardware scb array in the host.
+	 */
+	HSCB_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the 256 byte array storing the SCBID of outstanding
+	 * untagged SCBs indexed by TCL.
+	 */
+	SCBID_ADDR {
+		size		4
+	}
+	/*
+	 * Address of the array of command descriptors used to store
+	 * information about incoming selections.
+	 */
+	TMODE_CMDADDR {
+		size		4
+	}
+	KERNEL_QINPOS {
+		size		1
+	}
+	QINPOS {
+		size		1
+	}
+	QOUTPOS {
+		size		1
+	}
+	/*
+	 * Offset into the command descriptor array for the next
+	 * available desciptor to use.
+	 */
+	TMODE_CMDADDR_NEXT {
+		size		1
+	}
+	ARG_1 {
+		size		1
+		mask	SEND_MSG	0x80
+		mask	SEND_SENSE	0x40
+		mask	SEND_REJ	0x20
+		mask	MSGOUT_PHASEMIS	0x10
+		alias	RETURN_1
+	}
+	ARG_2 {
+		size		1
+		alias	RETURN_2
+	}
+
+	/*
+	 * Snapshot of MSG_OUT taken after each message is sent.
+	 */
+	LAST_MSG {
+		size		1
+	}
+
+	/*
+	 * Number of times we have filled the CCSGRAM with prefetched
+	 * SG elements.
+	 */
+	PREFETCH_CNT {
+		size		1
+	}
+
+
+	/*
+	 * These are reserved registers in the card's scratch ram.  Some of
+	 * the values are specified in the AHA2742 technical reference manual
+	 * and are initialized by the BIOS at boot time.
+	 */
+	SCSICONF {
+		address		0x05a
+		size		1
+		bit	TERM_ENB	0x80
+		bit	RESET_SCSI	0x40
+		mask	HSCSIID		0x07	/* our SCSI ID */
+		mask	HWSCSIID	0x0f	/* our SCSI ID if Wide Bus */
+	}
+	HOSTCONF {
+		address		0x05d
+		size		1
+	}
+	HA_274_BIOSCTRL	{
+		address		0x05f
+		size		1
+		mask	BIOSMODE		0x30
+		mask	BIOSDISABLED		0x30	
+		bit	CHANNEL_B_PRIMARY	0x08
+	}
+	/*
+	 * Per target SCSI offset values for Ultra2 controllers.
+	 */
+	TARG_OFFSET {
+		address		0x070
+		size		16
+	}
+}
+
+const SCB_LIST_NULL	0xff
+
+const CCSGADDR_MAX	0x80
+const CCSGRAM_MAXSEGS	16
+
+/* Offsets into the SCBID array where different data is stored */
+const UNTAGGEDSCB_OFFSET	0
+const QOUTFIFO_OFFSET		1
+const QINFIFO_OFFSET		2
+
+/* WDTR Message values */
+const BUS_8_BIT			0x00
+const BUS_16_BIT		0x01
+const BUS_32_BIT		0x02
+
+/* Offset maximums */
+const MAX_OFFSET_8BIT		0x0f
+const MAX_OFFSET_16BIT		0x08
+const MAX_OFFSET_ULTRA2		0x7f
+const HOST_MSG			0xff
+
+/* Target mode command processing constants */
+const CMD_GROUP_CODE_SHIFT	0x05
+const CMD_GROUP0_BYTE_DELTA	-4
+const CMD_GROUP2_BYTE_DELTA	-6
+const CMD_GROUP4_BYTE_DELTA	4
+const CMD_GROUP5_BYTE_DELTA	11
+
+/*
+ * Downloaded (kernel inserted) constants
+ */
+
+/*
+ * Number of command descriptors in the command descriptor array.
+ */
+const TMODE_NUMCMDS	download
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx.seq b/drivers/scsi/aic7xxx_old/aic7xxx.seq
new file mode 100644
index 0000000..f6fc4b7
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.seq
@@ -0,0 +1,1539 @@
+/*
+ * Adaptec 274x/284x/294x device driver firmware for Linux and FreeBSD.
+ *
+ * Copyright (c) 1994-1999 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License (GPL) and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	$Id: aic7xxx.seq,v 1.77 1998/06/28 02:58:57 gibbs Exp $
+ */
+
+#include "aic7xxx.reg"
+#include "scsi_message.h"
+
+/*
+ * A few words on the waiting SCB list:
+ * After starting the selection hardware, we check for reconnecting targets
+ * as well as for our selection to complete just in case the reselection wins
+ * bus arbitration.  The problem with this is that we must keep track of the
+ * SCB that we've already pulled from the QINFIFO and started the selection
+ * on just in case the reselection wins so that we can retry the selection at
+ * a later time.  This problem cannot be resolved by holding a single entry
+ * in scratch ram since a reconnecting target can request sense and this will
+ * create yet another SCB waiting for selection.  The solution used here is to 
+ * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
+ * of SCBs that are awaiting selection.  Since 0-0xfe are valid SCB indexes, 
+ * SCB_LIST_NULL is 0xff which is out of range.  An entry is also added to
+ * this list everytime a request sense occurs or after completing a non-tagged
+ * command for which a second SCB has been queued.  The sequencer will
+ * automatically consume the entries.
+ */
+
+reset:
+	clr	SCSISIGO;		/* De-assert BSY */
+	and	SXFRCTL1, ~BITBUCKET;
+	/* Always allow reselection */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;
+
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		/* Ensure that no DMA operations are in progress */
+		clr	CCSGCTL;
+		clr	CCSCBCTL;
+	}
+
+	call	clear_target_state;
+poll_for_work:
+	and	SXFRCTL0, ~SPIOEN;
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		mov	A, QINPOS;
+	}
+poll_for_work_loop:
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		and	SEQCTL, ~PAUSEDIS;
+	}
+	test	SSTAT0, SELDO|SELDI	jnz selection;
+	test	SCSISEQ, ENSELO	jnz poll_for_work;
+	if ((p->features & AHC_TWIN) != 0) {
+		/*
+		 * Twin channel devices cannot handle things like SELTO
+		 * interrupts on the "background" channel.  So, if we
+		 * are selecting, keep polling the current channel util
+		 * either a selection or reselection occurs.
+		 */
+		xor	SBLKCTL,SELBUSB;	/* Toggle to the other bus */
+		test	SSTAT0, SELDO|SELDI	jnz selection;
+		test	SCSISEQ, ENSELO	jnz poll_for_work;
+		xor	SBLKCTL,SELBUSB;	/* Toggle back */
+	}
+	cmp	WAITING_SCBH,SCB_LIST_NULL jne start_waiting;
+test_queue:
+	/* Has the driver posted any work for us? */
+	if ((p->features & AHC_QUEUE_REGS) != 0) {
+		test	QOFF_CTLSTA, SCB_AVAIL jz poll_for_work_loop;
+		mov	NONE, SNSCB_QOFF;
+		inc	QINPOS;
+	} else {
+		or	SEQCTL, PAUSEDIS;
+		cmp	KERNEL_QINPOS, A je poll_for_work_loop;
+		inc	QINPOS;
+		and	SEQCTL, ~PAUSEDIS;
+	}
+
+/*
+ * We have at least one queued SCB now and we don't have any 
+ * SCBs in the list of SCBs awaiting selection.  If we have
+ * any SCBs available for use, pull the tag from the QINFIFO
+ * and get to work on it.
+ */
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		mov	ALLZEROS	call	get_free_or_disc_scb;
+	}
+
+dequeue_scb:
+	add	A, -1, QINPOS;
+	mvi	QINFIFO_OFFSET call fetch_byte;
+
+	if ((p->flags & AHC_PAGESCBS) == 0) {
+		/* In the non-paging case, the SCBID == hardware SCB index */
+		mov	SCBPTR, RETURN_2;
+	}
+dma_queued_scb:
+/*
+ * DMA the SCB from host ram into the current SCB location.
+ */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	RETURN_2	 call dma_scb;
+
+/*
+ * Preset the residual fields in case we never go through a data phase.
+ * This isn't done by the host so we can avoid a DMA to clear these
+ * fields for the normal case of I/O that completes without underrun
+ * or overrun conditions.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, SCB_DATACNT, 3;
+	} else {
+		mov     SCB_RESID_DCNT[0],SCB_DATACNT[0];
+		mov     SCB_RESID_DCNT[1],SCB_DATACNT[1];
+		mov     SCB_RESID_DCNT[2],SCB_DATACNT[2];
+	}
+	mov     SCB_RESID_SGCNT, SCB_SGCOUNT;
+
+start_scb:
+	/*
+	 * Place us on the waiting list in case our selection
+	 * doesn't win during bus arbitration.
+	 */
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+start_waiting:
+	/*
+	 * Pull the first entry off of the waiting SCB list.
+	 */
+	mov	SCBPTR, WAITING_SCBH;
+	call	start_selection;
+	jmp	poll_for_work;
+
+start_selection:
+	if ((p->features & AHC_TWIN) != 0) {
+		and	SINDEX,~SELBUSB,SBLKCTL;/* Clear channel select bit */
+		and	A,SELBUSB,SCB_TCL;	/* Get new channel bit */
+		or	SINDEX,A;
+		mov	SBLKCTL,SINDEX;		/* select channel */
+	}
+initialize_scsiid:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		and	A, TID, SCB_TCL;	/* Get target ID */
+		and	SCSIID_ULTRA2, OID;	/* Clear old target */
+		or	SCSIID_ULTRA2, A;
+	} else {
+		and	A, TID, SCB_TCL;	/* Get target ID */
+		and	SCSIID, OID;		/* Clear old target */
+		or	SCSIID, A;
+	}
+	mov	SCSIDATL, ALLZEROS;		/* clear out the latched */
+						/* data register, this */
+						/* fixes a bug on some */
+						/* controllers where the */
+						/* last byte written to */
+						/* this register can leak */
+						/* onto the data bus at */
+						/* bad times, such as during */
+						/* selection timeouts */
+	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
+
+/*
+ * Initialize Ultra mode setting and clear the SCSI channel.
+ * SINDEX should contain any additional bit's the client wants
+ * set in SXFRCTL0.
+ */
+initialize_channel:
+	or	SXFRCTL0, CLRSTCNT|CLRCHN, SINDEX;
+	if ((p->features & AHC_ULTRA) != 0) {
+ultra:
+		mvi	SINDEX, ULTRA_ENB+1;
+		test	SAVED_TCL, 0x80		jnz ultra_2; /* Target ID > 7 */
+		dec	SINDEX;
+ultra_2:
+		mov     FUNCTION1,SAVED_TCL;
+		mov     A,FUNCTION1;
+		test	SINDIR, A	jz ndx_dtr;
+		or	SXFRCTL0, FAST20;
+	} 
+/*
+ * Initialize SCSIRATE with the appropriate value for this target.
+ * The SCSIRATE settings for each target are stored in an array
+ * based at TARG_SCSIRATE.
+ */
+ndx_dtr:
+	shr	A,4,SAVED_TCL;
+	if ((p->features & AHC_TWIN) != 0) {
+		test	SBLKCTL,SELBUSB	jz ndx_dtr_2;
+		or	SAVED_TCL, SELBUSB; 
+		or	A,0x08;			/* Channel B entries add 8 */
+ndx_dtr_2:
+	}
+
+	if ((p->features & AHC_ULTRA2) != 0) {
+		add	SINDEX, TARG_OFFSET, A;
+		mov	SCSIOFFSET, SINDIR;
+	}
+
+	add	SINDEX,TARG_SCSIRATE,A;
+	mov	SCSIRATE,SINDIR ret;
+
+
+selection:
+	test	SSTAT0,SELDO	jnz select_out;
+/*
+ * Reselection has been initiated by a target. Make a note that we've been
+ * reselected, but haven't seen an IDENTIFY message from the target yet.
+ */
+initiator_reselect:
+	mvi	CLRSINT0, CLRSELDI;
+	/* XXX test for and handle ONE BIT condition */
+	and	SAVED_TCL, SELID_MASK, SELID;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+	mvi	MSG_OUT, MSG_NOOP;		/* No message to send */
+	jmp	ITloop;
+
+/*
+ * After the selection, remove this SCB from the "waiting SCB"
+ * list.  This is achieved by simply moving our "next" pointer into
+ * WAITING_SCBH.  Our next pointer will be set to null the next time this
+ * SCB is used, so don't bother with it now.
+ */
+select_out:
+	/* Turn off the selection hardware */
+	mvi	SCSISEQ, ENRSELI|ENAUTOATNP;	/*
+						 * ATN on parity errors
+						 * for "in" phases
+						 */
+	mvi	CLRSINT0, CLRSELDO;
+	mov	SCBPTR, WAITING_SCBH;
+	mov	WAITING_SCBH,SCB_NEXT;
+	mov	SAVED_TCL, SCB_TCL;
+	mvi	CLRSINT1,CLRBUSFREE;
+	or	SIMODE1, ENBUSFREE;		/*
+						 * We aren't expecting a
+						 * bus free, so interrupt
+						 * the kernel driver if it
+						 * happens.
+						 */
+	mvi	SPIOEN call	initialize_channel;
+/*
+ * As soon as we get a successful selection, the target should go
+ * into the message out phase since we have ATN asserted.
+ */
+	mvi	MSG_OUT, MSG_IDENTIFYFLAG;
+	or	SEQ_FLAGS, IDENTIFY_SEEN;
+
+/*
+ * Main loop for information transfer phases.  Wait for the target
+ * to assert REQ before checking MSG, C/D and I/O for the bus phase.
+ */
+ITloop:
+	call	phase_lock;
+
+	mov	A, LASTPHASE;
+
+	test	A, ~P_DATAIN	jz p_data;
+	cmp	A,P_COMMAND	je p_command;
+	cmp	A,P_MESGOUT	je p_mesgout;
+	cmp	A,P_STATUS	je p_status;
+	cmp	A,P_MESGIN	je p_mesgin;
+
+	mvi	INTSTAT,BAD_PHASE;	/* unknown phase - signal driver */
+	jmp	ITloop;			/* Try reading the bus again. */
+
+await_busfree:
+	and	SIMODE1, ~ENBUSFREE;
+	call	clear_target_state;
+	mov	NONE, SCSIDATL;		/* Ack the last byte */
+	and	SXFRCTL0, ~SPIOEN;
+	test	SSTAT1,REQINIT|BUSFREE	jz .;
+	test	SSTAT1, BUSFREE jnz poll_for_work;
+	mvi	INTSTAT, BAD_PHASE;
+	
+clear_target_state:
+	/*
+	 * We assume that the kernel driver may reset us
+	 * at any time, even in the middle of a DMA, so
+	 * clear DFCNTRL too.
+	 */
+	clr	DFCNTRL;
+
+	/*
+	 * We don't know the target we will connect to,
+	 * so default to narrow transfers to avoid
+	 * parity problems.
+	 */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov    SCSIRATE, ALLZEROS, 2;
+	} else {
+		clr     SCSIRATE;
+		and     SXFRCTL0, ~(FAST20);
+	}
+	mvi	LASTPHASE, P_BUSFREE;
+	/* clear target specific flags */
+	clr	SEQ_FLAGS ret;
+
+
+data_phase_reinit:
+/*
+ * If we re-enter the data phase after going through another phase, the
+ * STCNT may have been cleared, so restore it from the residual field.
+ * On Ultra2, we have to put it into the HCNT field because we have to
+ * drop the data down into the shadow layer via the preload ability.
+ */
+ 	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov	HADDR, SHADDR, 4;
+		bmov    HCNT, SCB_RESID_DCNT, 3;
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		bmov    STCNT, SCB_RESID_DCNT, 3;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	DINDEX, STCNT;
+		mvi	SCB_RESID_DCNT	call bcopy_3;
+	}
+	jmp	data_phase_loop;
+p_data:
+ 	if ((p->features & AHC_ULTRA2) != 0) {
+		mvi	DMAPARAMS, PRELOADEN|SCSIEN|HDMAEN;
+	} else {
+		mvi	DMAPARAMS, WIDEODD|SCSIEN|SDMAEN|HDMAEN|FIFORESET;
+	}
+	test	LASTPHASE, IOI jnz . + 2;
+	or	DMAPARAMS, DIRECTION;
+	call	assert;		/*
+				 * Ensure entering a data
+				 * phase is okay - seen identify, etc.
+				 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	CCSGADDR, CCSGADDR_MAX;
+	}
+
+	test	SEQ_FLAGS, DPHASE	jnz data_phase_reinit;
+	or	SEQ_FLAGS, DPHASE;	/* we've seen a data phase */
+	/*
+	 * Initialize the DMA address and counter from the SCB.
+	 * Also set SG_COUNT and SG_NEXT in memory since we cannot
+	 * modify the values in the SCB itself until we see a
+	 * save data pointers message.
+	 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	HADDR, SCB_DATAPTR, 7;
+		bmov    SG_COUNT, SCB_SGCOUNT, 5;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_DATAPTR	call bcopy_7;
+		call	set_stcnt_from_hcnt;
+		mvi	DINDEX, SG_COUNT;
+		mvi	SCB_SGCOUNT	call bcopy_5;
+	}
+data_phase_loop:
+	/* Guard against overruns */
+	test	SG_COUNT, 0xff jnz data_phase_inbounds;
+/*
+ * Turn on 'Bit Bucket' mode, set the transfer count to
+ * 16meg and let the target run until it changes phase.
+ * When the transfer completes, notify the host that we
+ * had an overrun.
+ */
+	or	SXFRCTL1,BITBUCKET;
+	and	DMAPARAMS, ~(HDMAEN|SDMAEN);
+	if ((p->features & AHC_ULTRA2) != 0) {
+		bmov	HCNT, ALLONES, 3;
+	}
+	if ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895) {
+		bmov	STCNT, ALLONES, 3;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	STCNT[0], 0xFF;
+		mvi	STCNT[1], 0xFF;
+		mvi	STCNT[2], 0xFF;
+	}
+
+data_phase_inbounds:
+/* If we are the last SG block, tell the hardware. */
+	if ((p->features & AHC_ULTRA2) != 0) {
+		shl	A, 2, SG_COUNT;
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		or	A, LAST_SEG;
+	} else {
+		cmp	SG_COUNT,0x01 jne data_phase_wideodd;
+		and	DMAPARAMS, ~WIDEODD;
+	}
+data_phase_wideodd:
+	if ((p->features & AHC_ULTRA2) != 0) {	
+		mov	SG_CACHEPTR, A;
+		mov	DFCNTRL, DMAPARAMS; /* start the operation */
+		test	SXFRCTL1, BITBUCKET jnz data_phase_overrun;
+u2_preload_wait:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	DFSTATUS, PRELOAD_AVAIL jz u2_preload_wait;
+	} else {
+		mov	DMAPARAMS  call dma;
+data_phase_dma_done:
+/* Go tell the host about any overruns */
+		test	SXFRCTL1,BITBUCKET jnz data_phase_overrun;
+
+/* Exit if we had an underrun.  dma clears SINDEX in this case. */
+		test	SINDEX,0xff	jz data_phase_finish;
+	}
+/*
+ * Advance the scatter-gather pointers 
+ */
+sg_advance:
+	if ((p->features & AHC_ULTRA2) != 0) {
+		cmp	SG_COUNT, 0x01	je u2_data_phase_finish;
+	} else {
+		dec	SG_COUNT;
+		test	SG_COUNT, 0xff	jz data_phase_finish;
+	}
+
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+
+		/*
+		 * Do we have any prefetch left???
+		 */
+		cmp	CCSGADDR, CCSGADDR_MAX jne prefetch_avail;
+
+		/*
+		 * Fetch MIN(CCSGADDR_MAX, (SG_COUNT * 8)) bytes.
+		 */
+		add	A, -(CCSGRAM_MAXSEGS + 1), SG_COUNT;
+		mvi	A, CCSGADDR_MAX;
+		jc	. + 2;
+		shl	A, 3, SG_COUNT;
+		mov	CCHCNT, A;
+		bmov	CCHADDR, SG_NEXT, 4;
+		mvi	CCSGCTL, CCSGEN|CCSGRESET;
+		test	CCSGCTL, CCSGDONE jz .;
+		and	CCSGCTL, ~CCSGEN;
+		test	CCSGCTL, CCSGEN jnz .;
+		mvi	CCSGCTL, CCSGRESET;
+prefetch_avail:
+		bmov 	HADDR, CCSGRAM, 8;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov    STCNT, HCNT, 3;
+		} else {
+			dec	SG_COUNT;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SG_NEXT	call bcopy_4;
+
+		mvi	HCNT[0],SG_SIZEOF;
+		clr	HCNT[1];
+		clr	HCNT[2];
+
+		or	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+
+		call	dma_finish;
+
+/*
+ * Copy data from FIFO into SCB data pointer and data count.
+ * This assumes that the SG segments are of the form:
+ * struct ahc_dma_seg {
+ *	u_int32_t	addr;	four bytes, little-endian order
+ *	u_int32_t	len;	four bytes, little endian order
+ * };
+ */
+ 		mvi	DINDEX, HADDR;
+		call	dfdat_in_7;
+		call	set_stcnt_from_hcnt;
+	}
+/* Advance the SG pointer */
+	clr	A;		/* add sizeof(struct scatter) */
+	add	SG_NEXT[0],SG_SIZEOF;
+	adc	SG_NEXT[1],A;
+
+	if ((p->features & AHC_ULTRA2) != 0) {
+		jmp	data_phase_loop;
+	} else {
+		test    SSTAT1, REQINIT jz .;
+		test	SSTAT1,PHASEMIS	jz data_phase_loop;
+	}
+
+
+/*
+ * We've loaded all of our segments into the preload layer.  Now, we simply
+ * have to wait for it to finish or for us to get a phasemis.  And, since
+ * we'll get a phasemis if we do finish, all we really need to do is wait
+ * for a phasemis then check if we did actually complete all the segments.
+ */
+	if ((p->features & AHC_ULTRA2) != 0) {
+u2_data_phase_finish:
+		test	SSTAT1, PHASEMIS jnz u2_phasemis;
+		test	SG_CACHEPTR, LAST_SEG_DONE jz u2_data_phase_finish;
+		clr	SG_COUNT;
+		test	SSTAT1, REQINIT	jz .;
+		test	SSTAT1, PHASEMIS jz data_phase_loop;
+u2_phasemis:
+		call	ultra2_dmafinish;
+		test	SG_CACHEPTR, LAST_SEG_DONE jnz data_phase_finish;
+		test	SSTAT2, SHVALID jnz u2_fixup_residual;
+		mvi	INTSTAT, SEQ_SG_FIXUP;
+		jmp	data_phase_finish;
+u2_fixup_residual:
+		shr	ARG_1, 2, SG_CACHEPTR;
+u2_phasemis_loop:
+		and	A, 0x3f, SG_COUNT;
+		cmp	ARG_1, A je data_phase_finish;
+/*
+ * Subtract SG_SIZEOF from the SG_NEXT pointer and add 1 to the SG_COUNT
+ */
+ 		clr	A;
+		add	SG_NEXT[0], -SG_SIZEOF;
+		adc	SG_NEXT[1], 0xff;
+		inc	SG_COUNT;
+		jmp	u2_phasemis_loop;
+	}
+
+data_phase_finish:
+/*
+ * After a DMA finishes, save the SG and STCNT residuals back into the SCB
+ * We use STCNT instead of HCNT, since it's a reflection of how many bytes 
+ * were transferred on the SCSI (as opposed to the host) bus.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_RESID_DCNT, STCNT, 3;
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+		if ((p->features & AHC_ULTRA2) != 0) {
+			or	SXFRCTL0, CLRSTCNT|CLRCHN;
+		}
+	} else {
+		mov	SCB_RESID_DCNT[0],STCNT[0];
+		mov	SCB_RESID_DCNT[1],STCNT[1];
+		mov	SCB_RESID_DCNT[2],STCNT[2];
+		mov	SCB_RESID_SGCNT, SG_COUNT;
+	}
+
+	jmp	ITloop;
+
+data_phase_overrun:
+/*
+ * Turn off BITBUCKET mode and notify the host
+ */
+	if ((p->features & AHC_ULTRA2) != 0) {
+/*
+ * Wait for the target to quit transferring data on the SCSI bus
+ */
+ 		test	SSTAT1, PHASEMIS jz .;
+		call	ultra2_dmafinish;
+	}
+	and	SXFRCTL1, ~BITBUCKET;
+	mvi	INTSTAT,DATA_OVERRUN;
+	jmp	ITloop;
+
+
+
+
+/*
+ * Actually turn off the DMA hardware, save our current position into the
+ * proper residual variables, wait for the next REQ signal, then jump to
+ * the ITloop.  Jumping to the ITloop ensures that if we happen to get
+ * brought into the data phase again (or are still in it after our last
+ * segment) that we will properly signal an overrun to the kernel.
+ */
+	if ((p->features & AHC_ULTRA2) != 0) {
+ultra2_dmafinish:
+		test	DFCNTRL, DIRECTION jnz ultra2_dmahalt;
+		and	DFCNTRL, ~SCSIEN;
+		test	DFCNTRL, SCSIEN jnz .;
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			or	DFCNTRL, FIFOFLUSH;
+		}
+ultra2_dmafifoflush:
+		if ((p->bugs & AHC_BUG_AUTOFLUSH) != 0) {
+			/*
+			 * hardware bug alert!  This needless set of jumps
+			 * works around a glitch in the silicon.  When the
+			 * PCI DMA fifo goes empty, but there is still SCSI
+			 * data to be flushed into the PCI DMA fifo (and from
+			 * there on into main memory), the FIFOEMP bit will
+			 * come on between the time when the PCI DMA buffer
+			 * went empty and the next bit of data is copied from
+			 * the SCSI fifo into the PCI fifo.  It should only
+			 * come on when both FIFOs (meaning the entire FIFO
+			 * chain) are emtpy.  Since it can take up to 4 cycles
+			 * for new data to be copied from the SCSI fifo into
+			 * the PCI fifo, testing for FIFOEMP status for 4
+			 * extra times gives the needed time for any
+			 * remaining SCSI fifo data to be put in the PCI fifo
+			 * before we declare it *truly* empty.
+			 */
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+			test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		}
+		test	DFSTATUS, FIFOEMP jz ultra2_dmafifoflush;
+		test	DFSTATUS, MREQPEND	jnz .;
+ultra2_dmahalt:
+		and     DFCNTRL, ~(HDMAEN|SCSIEN);
+		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
+		ret;
+	}
+
+/*
+ * Command phase.  Set up the DMA registers and let 'er rip.
+ */
+p_command:
+	call	assert;
+
+/*
+ * Load HADDR and HCNT.
+ */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	HADDR, SCB_CMDPTR, 5;
+		bmov	HCNT[1], ALLZEROS, 2;
+		if ((p->features & AHC_ULTRA2) == 0) {
+			bmov	STCNT, HCNT, 3;
+		}
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCB_CMDPTR	call bcopy_5;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		call	set_stcnt_from_hcnt;
+	}
+
+	if ((p->features & AHC_ULTRA2) == 0) {
+		mvi	(SCSIEN|SDMAEN|HDMAEN|DIRECTION|FIFORESET) call dma;
+	} else {
+		mvi	DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN|DIRECTION);
+		test	SSTAT0, SDONE jnz .;
+p_command_dma_loop:
+		test	SSTAT0, SDONE jnz p_command_ultra2_dma_done;
+		test	SSTAT1,PHASEMIS	jz p_command_dma_loop;	/* ie. underrun */
+p_command_ultra2_dma_done:
+		test	SCSISIGI, REQI	jz p_command_ultra2_shutdown;
+		test	SSTAT1, (PHASEMIS|REQINIT)	jz p_command_ultra2_dma_done;
+p_command_ultra2_shutdown:
+		and     DFCNTRL, ~(HDMAEN|SCSIEN);
+		test	DFCNTRL, (HDMAEN|SCSIEN) jnz .;
+		or	SXFRCTL0, CLRSTCNT|CLRCHN;
+	}
+	jmp	ITloop;
+
+/*
+ * Status phase.  Wait for the data byte to appear, then read it
+ * and store it into the SCB.
+ */
+p_status:
+	call	assert;
+
+	mov	SCB_TARGET_STATUS, SCSIDATL;
+	jmp	ITloop;
+
+/*
+ * Message out phase.  If MSG_OUT is 0x80, build I full indentify message
+ * sequence and send it to the target.  In addition, if the MK_MESSAGE bit
+ * is set in the SCB_CONTROL byte, interrupt the host and allow it to send
+ * it's own message.
+ * 
+ * If MSG_OUT is == HOST_MSG, also interrupt the host and take a message.
+ * This is done to allow the hsot to send messages outside of an identify
+ * sequence while protecting the seqencer from testing the MK_MESSAGE bit
+ * on an SCB that might not be for the current nexus. (For example, a
+ * BDR message in responce to a bad reselection would leave us pointed to
+ * an SCB that doesn't have anything to do with the current target).
+ * Otherwise, treat MSG_OUT as a 1 byte message to send (abort, abort tag,
+ * bus device reset).
+ *
+ * When there are no messages to send, MSG_OUT should be set to MSG_NOOP,
+ * in case the target decides to put us in this phase for some strange
+ * reason.
+ */
+p_mesgout_retry:
+	or      SCSISIGO,ATNO,LASTPHASE;/* turn on ATN for the retry */
+p_mesgout:
+	mov	SINDEX, MSG_OUT;
+	cmp	SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host;
+p_mesgout_identify:
+	if ((p->features & AHC_WIDE) != 0) {
+		and	SINDEX,0xf,SCB_TCL;	/* lun */
+	} else {
+		and	SINDEX,0x7,SCB_TCL;	/* lun */
+	}
+	and	A,DISCENB,SCB_CONTROL;	/* mask off disconnect privledge */
+	or	SINDEX,A;		/* or in disconnect privledge */
+	or	SINDEX,MSG_IDENTIFYFLAG;
+p_mesgout_mk_message:
+	test	SCB_CONTROL,MK_MESSAGE  jz p_mesgout_tag;
+	mov	SCSIDATL, SINDEX;	/* Send the last byte */
+	jmp	p_mesgout_from_host + 1;/* Skip HOST_MSG test */
+/*
+ * Send a tag message if TAG_ENB is set in the SCB control block.
+ * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
+ */
+p_mesgout_tag:
+	test	SCB_CONTROL,TAG_ENB jz  p_mesgout_onebyte;
+	mov	SCSIDATL, SINDEX;	/* Send the identify message */
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	and	SCSIDATL,TAG_ENB|SCB_TAG_TYPE,SCB_CONTROL;
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGOUT	jne p_mesgout_done;
+	mov	SCB_TAG	jmp p_mesgout_onebyte;
+/*
+ * Interrupt the driver, and allow it to send a message
+ * if it asks.
+ */
+p_mesgout_from_host:
+	cmp	SINDEX, HOST_MSG	jne p_mesgout_onebyte;
+	mvi     INTSTAT,AWAITING_MSG;
+	nop;
+	/*
+	 * Did the host detect a phase change?
+	 */
+	cmp	RETURN_1, MSGOUT_PHASEMIS je p_mesgout_done;
+
+p_mesgout_onebyte:
+	mvi	CLRSINT1, CLRATNO;
+	mov	SCSIDATL, SINDEX;
+
+/*
+ * If the next bus phase after ATN drops is a message out, it means
+ * that the target is requesting that the last message(s) be resent.
+ */
+	call	phase_lock;
+	cmp     LASTPHASE, P_MESGOUT    je p_mesgout_retry;
+
+p_mesgout_done:
+	mvi	CLRSINT1,CLRATNO;	/* Be sure to turn ATNO off */
+	mov	LAST_MSG, MSG_OUT;
+	cmp	MSG_OUT, MSG_IDENTIFYFLAG jne . + 2;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	MSG_OUT, MSG_NOOP;	/* No message left */
+	jmp	ITloop;
+
+/*
+ * Message in phase.  Bytes are read using Automatic PIO mode.
+ */
+p_mesgin:
+	mvi	ACCUM		call inb_first;	/* read the 1st message byte */
+
+	test	A,MSG_IDENTIFYFLAG	jnz mesgin_identify;
+	cmp	A,MSG_DISCONNECT	je mesgin_disconnect;
+	cmp	A,MSG_SAVEDATAPOINTER	je mesgin_sdptrs;
+	cmp	ALLZEROS,A		je mesgin_complete;
+	cmp	A,MSG_RESTOREPOINTERS	je mesgin_rdptrs;
+	cmp	A,MSG_EXTENDED		je mesgin_extended;
+	cmp	A,MSG_MESSAGE_REJECT	je mesgin_reject;
+	cmp	A,MSG_NOOP		je mesgin_done;
+	cmp	A,MSG_IGN_WIDE_RESIDUE	je mesgin_wide_residue;
+
+rej_mesgin:
+/*
+ * We have no idea what this message in is, so we issue a message reject
+ * and hope for the best.  In any case, rejection should be a rare
+ * occurrence - signal the driver when it happens.
+ */
+	mvi	INTSTAT,SEND_REJECT;		/* let driver know */
+
+	mvi	MSG_MESSAGE_REJECT	call mk_mesg;
+
+mesgin_done:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+	jmp	ITloop;
+
+
+mesgin_complete:
+/*
+ * We got a "command complete" message, so put the SCB_TAG into the QOUTFIFO,
+ * and trigger a completion interrupt.  Before doing so, check to see if there
+ * is a residual or the status byte is something other than STATUS_GOOD (0).
+ * In either of these conditions, we upload the SCB back to the host so it can
+ * process this information.  In the case of a non zero status byte, we 
+ * additionally interrupt the kernel driver synchronously, allowing it to
+ * decide if sense should be retrieved.  If the kernel driver wishes to request
+ * sense, it will fill the kernel SCB with a request sense command and set
+ * RETURN_1 to SEND_SENSE.  If RETURN_1 is set to SEND_SENSE we redownload
+ * the SCB, and process it as the next command by adding it to the waiting list.
+ * If the kernel driver does not wish to request sense, it need only clear
+ * RETURN_1, and the command is allowed to complete normally.  We don't bother
+ * to post to the QOUTFIFO in the error cases since it would require extra
+ * work in the kernel driver to ensure that the entry was removed before the
+ * command complete code tried processing it.
+ */
+
+/*
+ * First check for residuals
+ */
+	test	SCB_RESID_SGCNT,0xff	jnz upload_scb;
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Good Status? */
+upload_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+check_status:
+	test	SCB_TARGET_STATUS,0xff	jz complete;	/* Just a residual? */
+	mvi	INTSTAT,BAD_STATUS;			/* let driver know */
+	nop;
+	cmp	RETURN_1, SEND_SENSE	jne complete;
+	/* This SCB becomes the next to execute as it will retrieve sense */
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+add_to_waiting_list:
+	mov	SCB_NEXT,WAITING_SCBH;
+	mov	WAITING_SCBH, SCBPTR;
+	/*
+	 * Prepare our selection hardware before the busfree so we have a
+	 * high probability of winning arbitration.
+	 */
+	call	start_selection;
+	jmp	await_busfree;
+
+complete:
+	/* If we are untagged, clear our address up in host ram */
+	test	SCB_CONTROL, TAG_ENB jnz complete_post;
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call post_byte_setup;
+	mvi	SCB_LIST_NULL call post_byte;
+
+complete_post:
+	/* Post the SCB and issue an interrupt */
+	if ((p->features & AHC_QUEUE_REGS) != 0) {
+		mov	A, SDSCB_QOFF;
+	} else {
+		mov	A, QOUTPOS;
+	}
+	mvi	QOUTFIFO_OFFSET call post_byte_setup;
+	mov	SCB_TAG call post_byte;
+	if ((p->features & AHC_QUEUE_REGS) == 0) {
+		inc 	QOUTPOS;
+	}
+	mvi	INTSTAT,CMDCMPLT;
+
+add_to_free_list:
+	call	add_scb_to_free_list;
+	jmp	await_busfree;
+
+/*
+ * Is it an extended message?  Copy the message to our message buffer and
+ * notify the host.  The host will tell us whether to reject this message,
+ * respond to it with the message that the host placed in our message buffer,
+ * or simply to do nothing.
+ */
+mesgin_extended:
+	mvi	INTSTAT,EXTENDED_MSG;		/* let driver know */
+	jmp	ITloop;
+
+/*
+ * Is it a disconnect message?  Set a flag in the SCB to remind us
+ * and await the bus going free.
+ */
+mesgin_disconnect:
+	or	SCB_CONTROL,DISCONNECTED;
+	call	add_scb_to_disc_list;
+	jmp	await_busfree;
+
+/*
+ * Save data pointers message:
+ * Copying RAM values back to SCB, for Save Data Pointers message, but
+ * only if we've actually been into a data phase to change them.  This
+ * protects against bogus data in scratch ram and the residual counts
+ * since they are only initialized when we go into data_in or data_out.
+ */
+mesgin_sdptrs:
+	test	SEQ_FLAGS, DPHASE	jz mesgin_done;
+	/*
+	 * The SCB SGPTR becomes the next one we'll download,
+	 * and the SCB DATAPTR becomes the current SHADDR.
+	 * Use the residual number since STCNT is corrupted by
+	 * any message transfer.
+	 */
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov    SCB_SGCOUNT, SG_COUNT, 5;
+		bmov    SCB_DATAPTR, SHADDR, 4;
+		bmov    SCB_DATACNT, SCB_RESID_DCNT, 3;
+	} else {
+		mvi	DINDEX, SCB_SGCOUNT;
+		mvi	SG_COUNT	call bcopy_5;
+		mvi	DINDEX, SCB_DATAPTR;
+		mvi	SHADDR		call bcopy_4;
+		mvi	SCB_RESID_DCNT	call	bcopy_3;
+	}
+	jmp	mesgin_done;
+
+/*
+ * Restore pointers message?  Data pointers are recopied from the
+ * SCB anytime we enter a data phase for the first time, so all
+ * we need to do is clear the DPHASE flag and let the data phase
+ * code do the rest.
+ */
+mesgin_rdptrs:
+	and	SEQ_FLAGS, ~DPHASE;		/*
+						 * We'll reload them
+						 * the next time through
+						 * the dataphase.
+						 */
+	jmp	mesgin_done;
+
+/*
+ * Identify message?  For a reconnecting target, this tells us the lun
+ * that the reconnection is for - find the correct SCB and switch to it,
+ * clearing the "disconnected" bit so we don't "find" it by accident later.
+ */
+mesgin_identify:
+	
+	if ((p->features & AHC_WIDE) != 0) {
+		and	A,0x0f;		/* lun in lower four bits */
+	} else {
+		and	A,0x07;		/* lun in lower three bits */
+	}
+	or      SAVED_TCL,A;		/* SAVED_TCL should be complete now */
+
+	mvi     ARG_2, SCB_LIST_NULL;   /* SCBID of prev SCB in disc List */
+	call	get_untagged_SCBID;
+	cmp	ARG_1, SCB_LIST_NULL	je snoop_tag;
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		test	SEQ_FLAGS, SCBPTR_VALID	jz use_retrieveSCB;
+	}
+	/*
+	 * If the SCB was found in the disconnected list (as is
+	 * always the case in non-paging scenarios), SCBPTR is already
+	 * set to the correct SCB.  So, simply setup the SCB and get
+	 * on with things.
+	 */
+	mov	SCBPTR	call rem_scb_from_disc_list;
+	jmp	setup_SCB;
+/*
+ * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
+ * If we get one, we use the tag returned to find the proper
+ * SCB.  With SCB paging, this requires using search for both tagged
+ * and non-tagged transactions since the SCB may exist in any slot.
+ * If we're not using SCB paging, we can use the tag as the direct
+ * index to the SCB.
+ */
+snoop_tag:
+	mov	NONE,SCSIDATL;		/* ACK Identify MSG */
+snoop_tag_loop:
+	call	phase_lock;
+	cmp	LASTPHASE, P_MESGIN	jne not_found;
+	cmp	SCSIBUSL,MSG_SIMPLE_Q_TAG jne not_found;
+get_tag:
+	mvi	ARG_1	call inb_next;	/* tag value */
+
+use_retrieveSCB:
+	call	retrieveSCB;
+setup_SCB:
+	mov	A, SAVED_TCL;
+	cmp	SCB_TCL, A	jne not_found_cleanup_scb;
+	test	SCB_CONTROL,DISCONNECTED jz not_found_cleanup_scb;
+	and	SCB_CONTROL,~DISCONNECTED;
+	or	SEQ_FLAGS,IDENTIFY_SEEN;	  /* make note of IDENTIFY */
+	/* See if the host wants to send a message upon reconnection */
+	test	SCB_CONTROL, MK_MESSAGE jz mesgin_done;
+	and	SCB_CONTROL, ~MK_MESSAGE;
+	mvi	HOST_MSG	call mk_mesg;
+	jmp	mesgin_done;
+
+not_found_cleanup_scb:
+	test	SCB_CONTROL, DISCONNECTED jz . + 3;
+	call	add_scb_to_disc_list;
+	jmp	not_found;
+	call	add_scb_to_free_list;
+not_found:
+	mvi	INTSTAT, NO_MATCH;
+	mvi	MSG_BUS_DEV_RESET	call mk_mesg;
+	jmp	mesgin_done;
+
+/*
+ * Message reject?  Let the kernel driver handle this.  If we have an 
+ * outstanding WDTR or SDTR negotiation, assume that it's a response from 
+ * the target selecting 8bit or asynchronous transfer, otherwise just ignore 
+ * it since we have no clue what it pertains to.
+ */
+mesgin_reject:
+	mvi	INTSTAT, REJECT_MSG;
+	jmp	mesgin_done;
+
+/*
+ * Wide Residue.  We handle the simple cases, but pass of the one hard case
+ * to the kernel (when the residue byte happened to cause us to advance our
+ * sg element array, so we know have to back that advance out).
+ */
+mesgin_wide_residue:
+	mvi	ARG_1	call inb_next; /* ACK the wide_residue and get */
+				       /* the size byte */
+/*
+ * In order for this to be reliable, we have to do all sorts of horrible
+ * magic in terms of resetting the datafifo and reloading the shadow layer
+ * with the correct new values (so that a subsequent save data pointers
+ * message will do the right thing).  We let the kernel do that work.
+ */
+ 	mvi	INTSTAT, WIDE_RESIDUE;
+	jmp	mesgin_done;
+	
+/*
+ * [ ADD MORE MESSAGE HANDLING HERE ]
+ */
+
+/*
+ * Locking the driver out, build a one-byte message passed in SINDEX
+ * if there is no active message already.  SINDEX is returned intact.
+ */
+mk_mesg:
+	or	SCSISIGO,ATNO,LASTPHASE;/* turn on ATNO */
+	mov	MSG_OUT,SINDEX ret;
+
+/*
+ * Functions to read data in Automatic PIO mode.
+ *
+ * According to Adaptec's documentation, an ACK is not sent on input from
+ * the target until SCSIDATL is read from.  So we wait until SCSIDATL is
+ * latched (the usual way), then read the data byte directly off the bus
+ * using SCSIBUSL.  When we have pulled the ATN line, or we just want to
+ * acknowledge the byte, then we do a dummy read from SCISDATL.  The SCSI
+ * spec guarantees that the target will hold the data byte on the bus until
+ * we send our ACK.
+ *
+ * The assumption here is that these are called in a particular sequence,
+ * and that REQ is already set when inb_first is called.  inb_{first,next}
+ * use the same calling convention as inb.
+ */
+
+inb_next:
+	mov	NONE,SCSIDATL;		/*dummy read from latch to ACK*/
+inb_next_wait:
+	/*
+	 * If there is a parity error, wait for the kernel to
+	 * see the interrupt and prepare our message response
+	 * before continuing.
+	 */
+	test	SSTAT1, REQINIT	jz inb_next_wait;
+	test	SSTAT1, SCSIPERR jnz .;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI;
+	cmp	LASTPHASE, P_MESGIN jne mesgin_phasemis;
+inb_first:
+	mov	DINDEX,SINDEX;
+	mov	DINDIR,SCSIBUSL	ret;		/*read byte directly from bus*/
+inb_last:
+	mov	NONE,SCSIDATL ret;		/*dummy read from latch to ACK*/
+
+	
+mesgin_phasemis:
+/*
+ * We expected to receive another byte, but the target changed phase
+ */
+	mvi	INTSTAT, MSGIN_PHASEMIS;
+	jmp	ITloop;
+
+/*
+ * DMA data transfer.  HADDR and HCNT must be loaded first, and
+ * SINDEX should contain the value to load DFCNTRL with - 0x3d for
+ * host->scsi, or 0x39 for scsi->host.  The SCSI channel is cleared
+ * during initialization.
+ */
+if ((p->features & AHC_ULTRA2) == 0) {
+dma:
+	mov	DFCNTRL,SINDEX;
+dma_loop:
+	test	SSTAT0,DMADONE	jnz dma_dmadone;
+	test	SSTAT1,PHASEMIS	jz dma_loop;	/* ie. underrun */
+dma_phasemis:
+	test	SSTAT0,SDONE	jnz dma_checkfifo;
+	mov	SINDEX,ALLZEROS;		/* Notify caller of phasemiss */
+
+/*
+ * We will be "done" DMAing when the transfer count goes to zero, or
+ * the target changes the phase (in light of this, it makes sense that
+ * the DMA circuitry doesn't ACK when PHASEMIS is active).  If we are
+ * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
+ * magically on STCNT=0 or a phase change, so just wait for FIFO empty
+ * status.
+ */
+dma_checkfifo:
+	test	DFCNTRL,DIRECTION	jnz dma_fifoempty;
+dma_fifoflush:
+	test	DFSTATUS,FIFOEMP	jz dma_fifoflush;
+
+dma_fifoempty:
+	/* Don't clobber an inprogress host data transfer */
+	test	DFSTATUS, MREQPEND	jnz dma_fifoempty;
+/*
+ * Now shut the DMA enables off and make sure that the DMA enables are 
+ * actually off first lest we get an ILLSADDR.
+ */
+dma_dmadone:
+	cmp	LASTPHASE, P_COMMAND	je dma_await_nreq;
+	test	SCSIRATE, 0x0f	jnz dma_shutdown;
+dma_await_nreq:
+	test	SCSISIGI, REQI	jz dma_shutdown;
+	test	SSTAT1, (PHASEMIS|REQINIT)	jz dma_await_nreq;
+dma_shutdown:
+	and	DFCNTRL, ~(SCSIEN|SDMAEN|HDMAEN);
+dma_halt:
+	/*
+	 * Some revisions of the aic7880 have a problem where, if the
+	 * data fifo is full, but the PCI input latch is not empty, 
+	 * HDMAEN cannot be cleared.  The fix used here is to attempt
+	 * to drain the data fifo until there is space for the input
+	 * latch to drain and HDMAEN de-asserts.
+	 */
+	if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+		mov	NONE, DFDAT;
+	}
+	test	DFCNTRL, (SCSIEN|SDMAEN|HDMAEN) jnz dma_halt;
+}
+return:
+	ret;
+
+/*
+ * Assert that if we've been reselected, then we've seen an IDENTIFY
+ * message.
+ */
+assert:
+	test	SEQ_FLAGS,IDENTIFY_SEEN	jnz return;	/* seen IDENTIFY? */
+
+	mvi	INTSTAT,NO_IDENT 	ret;	/* no - tell the kernel */
+
+/*
+ * Locate a disconnected SCB either by SAVED_TCL (ARG_1 is SCB_LIST_NULL)
+ * or by the SCBID ARG_1.  The search begins at the SCB index passed in
+ * via SINDEX which is an SCB that must be on the disconnected list.  If
+ * the SCB cannot be found, SINDEX will be SCB_LIST_NULL, otherwise, SCBPTR
+ * is set to the proper SCB.
+ */
+findSCB:
+	mov	SCBPTR,SINDEX;			/* Initialize SCBPTR */
+	cmp	ARG_1, SCB_LIST_NULL	jne findSCB_by_SCBID;
+	mov	A, SAVED_TCL;
+	mvi	SCB_TCL	jmp findSCB_loop;	/* &SCB_TCL -> SINDEX */
+findSCB_by_SCBID:
+	mov	A, ARG_1;			/* Tag passed in ARG_1 */
+	mvi	SCB_TAG	jmp findSCB_loop;	/* &SCB_TAG -> SINDEX */
+findSCB_next:
+	mov     ARG_2, SCBPTR;
+	cmp	SCB_NEXT, SCB_LIST_NULL je notFound;
+	mov	SCBPTR,SCB_NEXT;
+	dec	SINDEX;		/* Last comparison moved us too far */
+findSCB_loop:
+	cmp	SINDIR, A	jne findSCB_next;
+	mov	SINDEX, SCBPTR 	ret;
+notFound:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+
+/*
+ * Retrieve an SCB by SCBID first searching the disconnected list falling
+ * back to DMA'ing the SCB down from the host.  This routine assumes that
+ * ARG_1 is the SCBID of interrest and that SINDEX is the position in the
+ * disconnected list to start the search from.  If SINDEX is SCB_LIST_NULL,
+ * we go directly to the host for the SCB.
+ */
+retrieveSCB:
+	test	SEQ_FLAGS, SCBPTR_VALID	jz retrieve_from_host;
+	mov	SCBPTR	call findSCB;	/* Continue the search */
+	cmp	SINDEX, SCB_LIST_NULL	je retrieve_from_host;
+
+/*
+ * This routine expects SINDEX to contain the index of the SCB to be
+ * removed, SCBPTR to be pointing to that SCB, and ARG_2 to be the
+ * SCBID of the SCB just previous to this one in the list or SCB_LIST_NULL
+ * if it is at the head.
+ */
+rem_scb_from_disc_list:
+/* Remove this SCB from the disconnection list */
+	cmp     ARG_2, SCB_LIST_NULL    je rHead;
+	mov	DINDEX, SCB_NEXT;
+	mov	SCBPTR, ARG_2;
+	mov	SCB_NEXT, DINDEX;
+	mov	SCBPTR, SINDEX ret;
+rHead:
+	mov	DISCONNECTED_SCBH,SCB_NEXT ret;
+
+retrieve_from_host:
+/*
+ * We didn't find it.  Pull an SCB and DMA down the one we want.
+ * We should never get here in the non-paging case.
+ */
+	mov	ALLZEROS	call	get_free_or_disc_scb;
+	mvi	DMAPARAMS, HDMAEN|DIRECTION|FIFORESET;
+	/* Jump instead of call as we want to return anyway */
+	mov	ARG_1	jmp dma_scb;
+
+/*
+ * Determine whether a target is using tagged or non-tagged transactions
+ * by first looking for a matching transaction based on the TCL and if
+ * that fails, looking up this device in the host's untagged SCB array.
+ * The TCL to search for is assumed to be in SAVED_TCL.  The value is
+ * returned in ARG_1 (SCB_LIST_NULL for tagged, SCBID for non-tagged).
+ * The SCBPTR_VALID bit is set in SEQ_FLAGS if we found the information
+ * in an SCB instead of having to go to the host.
+ */
+get_untagged_SCBID:
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL je get_SCBID_from_host;
+	mvi	ARG_1, SCB_LIST_NULL;
+	mov	DISCONNECTED_SCBH call findSCB;
+	cmp	SINDEX, SCB_LIST_NULL	je get_SCBID_from_host;
+	or	SEQ_FLAGS, SCBPTR_VALID;/* Was in disconnected list */
+	test	SCB_CONTROL, TAG_ENB	jnz . + 2;
+	mov	ARG_1, SCB_TAG	ret;
+	mvi	ARG_1, SCB_LIST_NULL ret;
+
+/*
+ * Fetch a byte from host memory given an index of (A + (256 * SINDEX))
+ * and a base address of SCBID_ADDR.  The byte is returned in RETURN_2.
+ */
+fetch_byte:
+	mov	ARG_2, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	SCBID_ADDR call set_1byte_addr;
+		mvi	CCHCNT, 1;
+		mvi	CCSGCTL, CCSGEN|CCSGRESET;
+		test	CCSGCTL, CCSGDONE jz .;
+		mvi	CCSGCTL, CCSGRESET;
+		bmov	RETURN_2, CCSGRAM, 1 ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCBID_ADDR call set_1byte_addr;
+		mvi	HCNT[0], 1;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mvi	DFCNTRL, HDMAEN|DIRECTION|FIFORESET;
+		call	dma_finish;
+		mov	RETURN_2, DFDAT ret;
+	}
+
+/*
+ * Prepare the hardware to post a byte to host memory given an
+ * index of (A + (256 * SINDEX)) and a base address of SCBID_ADDR.
+ */
+post_byte_setup:
+	mov	ARG_2, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	SCBID_ADDR call	set_1byte_addr;
+		mvi	CCHCNT, 1;
+		mvi	CCSCBCTL, CCSCBRESET ret;
+	} else {
+		mvi	DINDEX, HADDR;
+		mvi	SCBID_ADDR call	set_1byte_addr;
+		mvi	HCNT[0], 1;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mvi	DFCNTRL, FIFORESET ret;
+	}
+
+post_byte:
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		bmov	CCSCBRAM, SINDEX, 1;
+		or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+		test	CCSCBCTL, CCSCBDONE jz .;
+		clr	CCSCBCTL ret;
+	} else {
+		mov	DFDAT, SINDEX;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
+	}
+
+get_SCBID_from_host:
+	mov	A, SAVED_TCL;
+	mvi	UNTAGGEDSCB_OFFSET call fetch_byte;
+	mov	RETURN_1,  RETURN_2 ret;
+
+phase_lock:     
+	test	SSTAT1, REQINIT jz phase_lock;
+	test	SSTAT1, SCSIPERR jnz phase_lock;
+	and	SCSISIGO, PHASE_MASK, SCSISIGI;
+	and	LASTPHASE, PHASE_MASK, SCSISIGI ret;
+
+if ((p->features & AHC_CMD_CHAN) == 0) {
+set_stcnt_from_hcnt:
+	mov	STCNT[0], HCNT[0];
+	mov	STCNT[1], HCNT[1];
+	mov	STCNT[2], HCNT[2] ret;
+
+bcopy_7:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+bcopy_5:
+	mov	DINDIR, SINDIR;
+bcopy_4:
+	mov	DINDIR, SINDIR;
+bcopy_3:
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR;
+	mov	DINDIR, SINDIR ret;
+}
+
+/*
+ * Setup addr assuming that A is an index into
+ * an array of 32byte objects, SINDEX contains
+ * the base address of that array, and DINDEX
+ * contains the base address of the location
+ * to store the indexed address.
+ */
+set_32byte_addr:
+	shr	ARG_2, 3, A;
+	shl	A, 5;
+/*
+ * Setup addr assuming that A + (ARG_1 * 256) is an
+ * index into an array of 1byte objects, SINDEX contains
+ * the base address of that array, and DINDEX contains
+ * the base address of the location to store the computed
+ * address.
+ */
+set_1byte_addr:
+	add	DINDIR, A, SINDIR;
+	mov	A, ARG_2;
+	adc	DINDIR, A, SINDIR;
+	clr	A;
+	adc	DINDIR, A, SINDIR;
+	adc	DINDIR, A, SINDIR ret;
+
+/*
+ * Either post or fetch and SCB from host memory based on the
+ * DIRECTION bit in DMAPARAMS. The host SCB index is in SINDEX.
+ */
+dma_scb:
+	mov	A, SINDEX;
+	if ((p->features & AHC_CMD_CHAN) != 0) {
+		mvi	DINDEX, CCHADDR;
+		mvi	HSCB_ADDR call set_32byte_addr;
+		mov	CCSCBPTR, SCBPTR;
+		mvi	CCHCNT, 32;
+		test	DMAPARAMS, DIRECTION jz dma_scb_tohost;
+		mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBDIR|CCSCBRESET;
+		cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN|CCSCBDIR jne .;
+		jmp	dma_scb_finish;
+dma_scb_tohost:
+		if ((p->features & AHC_ULTRA2) == 0) {
+			mvi	CCSCBCTL, CCSCBRESET;
+			bmov	CCSCBRAM, SCB_CONTROL, 32;
+			or	CCSCBCTL, CCSCBEN|CCSCBRESET;
+			test	CCSCBCTL, CCSCBDONE jz .;
+		}
+		if ((p->features & AHC_ULTRA2) != 0) {
+			if ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0) {
+				mvi     CCSCBCTL, CCARREN|CCSCBRESET;
+				cmp     CCSCBCTL, ARRDONE|CCARREN jne .;
+                        	mvi     CCHCNT, 32;
+				mvi     CCSCBCTL, CCSCBEN|CCSCBRESET;
+				cmp     CCSCBCTL, CCSCBDONE|CCSCBEN jne .;
+			} else {
+				mvi	CCSCBCTL, CCARREN|CCSCBEN|CCSCBRESET;
+				cmp	CCSCBCTL, CCSCBDONE|ARRDONE|CCARREN|CCSCBEN jne .;
+			}
+		}
+dma_scb_finish:
+		clr	CCSCBCTL;
+		test	CCSCBCTL, CCARREN|CCSCBEN jnz .;
+		ret;
+	}
+	if ((p->features & AHC_CMD_CHAN) == 0) {
+		mvi	DINDEX, HADDR;
+		mvi	HSCB_ADDR call set_32byte_addr;
+		mvi	HCNT[0], 32;
+		clr	HCNT[1];
+		clr	HCNT[2];
+		mov	DFCNTRL, DMAPARAMS;
+		test	DMAPARAMS, DIRECTION	jnz dma_scb_fromhost;
+		/* Fill it with the SCB data */
+copy_scb_tofifo:
+		mvi	SINDEX, SCB_CONTROL;
+		add	A, 32, SINDEX;
+copy_scb_tofifo_loop:
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		mov	DFDAT,SINDIR;
+		cmp	SINDEX, A jne copy_scb_tofifo_loop;
+		or	DFCNTRL, HDMAEN|FIFOFLUSH;
+		jmp	dma_finish;
+dma_scb_fromhost:
+		mvi	DINDEX, SCB_CONTROL;
+		if ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0) {
+			/*
+			 * Set the A to -24.  It it hits 0, then we let
+			 * our code fall through to dfdat_in_8 to complete
+			 * the last of the copy.
+			 *
+			 * Also, things happen 8 bytes at a time in this
+			 * case, so we may need to drain the fifo at most
+			 * 3 times to keep things flowing
+			 */
+			mvi	A, -24;
+dma_scb_hang_fifo:
+			/* Wait for the first bit of data to hit the fifo */
+			test	DFSTATUS, FIFOEMP jnz .;
+dma_scb_hang_wait:
+			/* OK, now they've started to transfer into the fifo,
+			 * so wait for them to stop trying to transfer any
+			 * more data.
+			 */
+			test	DFSTATUS, MREQPEND jnz .;
+			/*
+			 * OK, they started, then they stopped, now see if they
+			 * managed to complete the job before stopping.  Try
+			 * it multiple times to give the chip a few cycles to
+			 * set the flag if it did complete.
+			 */
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			test	DFSTATUS, HDONE jnz dma_scb_hang_dma_done;
+			/*
+			 * Too bad, the chip didn't complete the DMA, but there
+			 * aren't any more memory requests pending, so that
+			 * means it stopped part way through and hung.  That's
+			 * our bug, so now we drain what data there is in the
+			 * fifo in order to get things going again.
+			 */
+dma_scb_hang_empty_fifo:
+			call	dfdat_in_8;
+			add	A, 8;
+			add	SINDEX, A, HCNT;
+			/*
+			 * If there are another 8 bytes of data waiting in the
+			 * fifo, then the carry bit will be set as a result
+			 * of the above add command (unless A is non-negative,
+			 * in which case the carry bit won't be set).
+			 */
+			jc	dma_scb_hang_empty_fifo;
+			/*
+			 * We've emptied the fifo now, but we wouldn't have got
+			 * here if the memory transfer hadn't stopped part way
+			 * through, so go back up to the beginning of the
+			 * loop and start over.  When it succeeds in getting
+			 * all the data down, HDONE will be set and we'll
+			 * jump to the code just below here.
+			 */
+			jmp	dma_scb_hang_fifo;
+dma_scb_hang_dma_done:
+			and	DFCNTRL, ~HDMAEN;
+			test	DFCNTRL, HDMAEN jnz .;
+			call	dfdat_in_8;
+			add	A, 8;
+			cmp	A, 8 jne . - 2;
+			ret;
+		} else {
+			call	dma_finish;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+			call	dfdat_in_8;
+		}
+dfdat_in_8:
+		mov	DINDIR,DFDAT;
+dfdat_in_7:
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT;
+		mov	DINDIR,DFDAT ret;
+	}
+
+
+/*
+ * Wait for DMA from host memory to data FIFO to complete, then disable
+ * DMA and wait for it to acknowledge that it's off.
+ */
+if ((p->features & AHC_CMD_CHAN) == 0) {
+dma_finish:
+	test	DFSTATUS,HDONE	jz dma_finish;
+	/* Turn off DMA */
+	and	DFCNTRL, ~HDMAEN;
+	test	DFCNTRL, HDMAEN jnz .;
+	ret;
+}
+
+add_scb_to_free_list:
+	if ((p->flags & AHC_PAGESCBS) != 0) {
+		mov	SCB_NEXT, FREE_SCBH;
+		mov	FREE_SCBH, SCBPTR;
+	}
+	mvi	SCB_TAG, SCB_LIST_NULL ret;
+
+if ((p->flags & AHC_PAGESCBS) != 0) {
+get_free_or_disc_scb:
+	cmp	FREE_SCBH, SCB_LIST_NULL jne dequeue_free_scb;
+	cmp	DISCONNECTED_SCBH, SCB_LIST_NULL jne dequeue_disc_scb;
+return_error:
+	mvi	SINDEX, SCB_LIST_NULL	ret;
+dequeue_disc_scb:
+	mov	SCBPTR, DISCONNECTED_SCBH;
+dma_up_scb:
+	mvi	DMAPARAMS, FIFORESET;
+	mov	SCB_TAG		call dma_scb;
+unlink_disc_scb:
+	mov	DISCONNECTED_SCBH, SCB_NEXT ret;
+dequeue_free_scb:
+	mov	SCBPTR, FREE_SCBH;
+	mov	FREE_SCBH, SCB_NEXT ret;
+}
+
+add_scb_to_disc_list:
+/*
+ * Link this SCB into the DISCONNECTED list.  This list holds the
+ * candidates for paging out an SCB if one is needed for a new command.
+ * Modifying the disconnected list is a critical(pause dissabled) section.
+ */
+	mov	SCB_NEXT, DISCONNECTED_SCBH;
+	mov	DISCONNECTED_SCBH, SCBPTR ret;
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
new file mode 100644
index 0000000..3bf3349
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c
@@ -0,0 +1,374 @@
+/*+M*************************************************************************
+ * Adaptec AIC7xxx device driver proc support for Linux.
+ *
+ * Copyright (c) 1995, 1996 Dean W. Gehnert
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * ----------------------------------------------------------------
+ *  o Modified from the EATA-DMA /proc support.
+ *  o Additional support for device block statistics provided by
+ *    Matthew Jacob.
+ *  o Correction of overflow by Heinz Mauelshagen
+ *  o Adittional corrections by Doug Ledford
+ *
+ *  Dean W. Gehnert, deang@teleport.com, 05/01/96
+ *
+ *  $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
+ *-M*************************************************************************/
+
+#include <linux/config.h>
+
+#define	BLS	(&aic7xxx_buffer[size])
+#define HDRB \
+"               0 - 4K   4 - 16K   16 - 64K  64 - 256K  256K - 1M        1M+"
+
+#ifdef PROC_DEBUG
+extern int vsprintf(char *, const char *, va_list);
+
+static void
+proc_debug(const char *fmt, ...)
+{
+  va_list ap;
+  char buf[256];
+
+  va_start(ap, fmt);
+  vsprintf(buf, fmt, ap);
+  printk(buf);
+  va_end(ap);
+}
+#else /* PROC_DEBUG */
+#  define proc_debug(fmt, args...)
+#endif /* PROC_DEBUG */
+
+static int aic7xxx_buffer_size = 0;
+static char *aic7xxx_buffer = NULL;
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_set_info
+ *
+ * Description:
+ *   Set parameters for the driver from the /proc filesystem.
+ *-F*************************************************************************/
+static int
+aic7xxx_set_info(char *buffer, int length, struct Scsi_Host *HBAptr)
+{
+  proc_debug("aic7xxx_set_info(): %s\n", buffer);
+  return (-ENOSYS);  /* Currently this is a no-op */
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ *   aic7xxx_proc_info
+ *
+ * Description:
+ *   Return information to handle /proc support for the driver.
+ *-F*************************************************************************/
+int
+aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, 
+                    int inout)
+{
+  struct aic7xxx_host *p;
+  struct aic_dev_data *aic_dev;
+  struct scsi_device *sdptr;
+  int    size = 0;
+  unsigned char i;
+  unsigned char tindex;
+
+  for(p=first_aic7xxx; p && p->host != HBAptr; p=p->next)
+    ;
+
+  if (!p)
+  {
+    size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no);
+    if (size > length)
+    {
+      return (size);
+    }
+    else
+    {
+      return (length);
+    }
+  }
+
+  if (inout == TRUE) /* Has data been written to the file? */ 
+  {
+    return (aic7xxx_set_info(buffer, length, HBAptr));
+  }
+
+  p = (struct aic7xxx_host *) HBAptr->hostdata;
+
+  /*
+   * It takes roughly 1K of space to hold all relevant card info, not
+   * counting any proc stats, so we start out with a 1.5k buffer size and
+   * if proc_stats is defined, then we sweep the stats structure to see
+   * how many drives we will be printing out for and add 384 bytes per
+   * device with active stats.
+   *
+   * Hmmmm...that 1.5k seems to keep growing as items get added so they
+   * can be easily viewed for debugging purposes.  So, we bumped that
+   * 1.5k to 4k so we can quit having to bump it all the time.
+   */
+
+  size = 4096;
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
+    size += 512;
+  if (aic7xxx_buffer_size != size)
+  {
+    if (aic7xxx_buffer != NULL) 
+    {
+      kfree(aic7xxx_buffer);
+      aic7xxx_buffer_size = 0;
+    }
+    aic7xxx_buffer = kmalloc(size, GFP_KERNEL);
+  }
+  if (aic7xxx_buffer == NULL)
+  {
+    size = sprintf(buffer, "AIC7xxx - kmalloc error at line %d\n",
+        __LINE__);
+    return size;
+  }
+  aic7xxx_buffer_size = size;
+
+  size = 0;
+  size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
+  size += sprintf(BLS, "%s/", AIC7XXX_C_VERSION);
+  size += sprintf(BLS, "%s", AIC7XXX_H_VERSION);
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Adapter Configuration:\n");
+  size += sprintf(BLS, "           SCSI Adapter: %s\n",
+      board_names[p->board_name_index]);
+  if (p->flags & AHC_TWIN)
+    size += sprintf(BLS, "                         Twin Channel Controller ");
+  else
+  {
+    char *channel = "";
+    char *ultra = "";
+    char *wide = "Narrow ";
+    if (p->flags & AHC_MULTI_CHANNEL)
+    {
+      channel = " Channel A";
+      if (p->flags & (AHC_CHNLB|AHC_CHNLC))
+        channel = (p->flags & AHC_CHNLB) ? " Channel B" : " Channel C";
+    }
+    if (p->features & AHC_WIDE)
+      wide = "Wide ";
+    if (p->features & AHC_ULTRA3)
+    {
+      switch(p->chip & AHC_CHIPID_MASK)
+      {
+        case AHC_AIC7892:
+        case AHC_AIC7899:
+          ultra = "Ultra-160/m LVD/SE ";
+          break;
+        default:
+          ultra = "Ultra-3 LVD/SE ";
+          break;
+      }
+    }
+    else if (p->features & AHC_ULTRA2)
+      ultra = "Ultra-2 LVD/SE ";
+    else if (p->features & AHC_ULTRA)
+      ultra = "Ultra ";
+    size += sprintf(BLS, "                           %s%sController%s ",
+      ultra, wide, channel);
+  }
+  switch(p->chip & ~AHC_CHIPID_MASK)
+  {
+    case AHC_VL:
+      size += sprintf(BLS, "at VLB slot %d\n", p->pci_device_fn);
+      break;
+    case AHC_EISA:
+      size += sprintf(BLS, "at EISA slot %d\n", p->pci_device_fn);
+      break;
+    default:
+      size += sprintf(BLS, "at PCI %d/%d/%d\n", p->pci_bus,
+        PCI_SLOT(p->pci_device_fn), PCI_FUNC(p->pci_device_fn));
+      break;
+  }
+  if( !(p->maddr) )
+  {
+    size += sprintf(BLS, "    Programmed I/O Base: %lx\n", p->base);
+  }
+  else
+  {
+    size += sprintf(BLS, "    PCI MMAPed I/O Base: 0x%lx\n", p->mbase);
+  }
+  if( (p->chip & (AHC_VL | AHC_EISA)) )
+  {
+    size += sprintf(BLS, "    BIOS Memory Address: 0x%08x\n", p->bios_address);
+  }
+  size += sprintf(BLS, " Adapter SEEPROM Config: %s\n",
+          (p->flags & AHC_SEEPROM_FOUND) ? "SEEPROM found and used." :
+         ((p->flags & AHC_USEDEFAULTS) ? "SEEPROM not found, using defaults." :
+           "SEEPROM not found, using leftover BIOS values.") );
+  size += sprintf(BLS, "      Adaptec SCSI BIOS: %s\n",
+          (p->flags & AHC_BIOS_ENABLED) ? "Enabled" : "Disabled");
+  size += sprintf(BLS, "                    IRQ: %d\n", HBAptr->irq);
+  size += sprintf(BLS, "                   SCBs: Active %d, Max Active %d,\n",
+            p->activescbs, p->max_activescbs);
+  size += sprintf(BLS, "                         Allocated %d, HW %d, "
+            "Page %d\n", p->scb_data->numscbs, p->scb_data->maxhscbs,
+            p->scb_data->maxscbs);
+  if (p->flags & AHC_EXTERNAL_SRAM)
+    size += sprintf(BLS, "                         Using External SCB SRAM\n");
+  size += sprintf(BLS, "             Interrupts: %ld", p->isr_count);
+  if (p->chip & AHC_EISA)
+  {
+    size += sprintf(BLS, " %s\n",
+        (p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
+  }
+  else
+  {
+    size += sprintf(BLS, "\n");
+  }
+  size += sprintf(BLS, "      BIOS Control Word: 0x%04x\n",
+            p->bios_control);
+  size += sprintf(BLS, "   Adapter Control Word: 0x%04x\n",
+            p->adapter_control);
+  size += sprintf(BLS, "   Extended Translation: %sabled\n",
+      (p->flags & AHC_EXTEND_TRANS_A) ? "En" : "Dis");
+  size += sprintf(BLS, "Disconnect Enable Flags: 0x%04x\n", p->discenable);
+  if (p->features & (AHC_ULTRA | AHC_ULTRA2))
+  {
+    size += sprintf(BLS, "     Ultra Enable Flags: 0x%04x\n", p->ultraenb);
+  }
+  size += sprintf(BLS, "Default Tag Queue Depth: %d\n", aic7xxx_default_queue_depth);
+  size += sprintf(BLS, "    Tagged Queue By Device array for aic7xxx host "
+                       "instance %d:\n", p->instance);
+  size += sprintf(BLS, "      {");
+  for(i=0; i < (MAX_TARGETS - 1); i++)
+    size += sprintf(BLS, "%d,",aic7xxx_tag_info[p->instance].tag_commands[i]);
+  size += sprintf(BLS, "%d}\n",aic7xxx_tag_info[p->instance].tag_commands[i]);
+
+  size += sprintf(BLS, "\n");
+  size += sprintf(BLS, "Statistics:\n\n");
+  list_for_each_entry(aic_dev, &p->aic_devs, list)
+  {
+    sdptr = aic_dev->SDptr;
+    tindex = sdptr->channel << 3 | sdptr->id;
+    size += sprintf(BLS, "(scsi%d:%d:%d:%d)\n",
+        p->host_no, sdptr->channel, sdptr->id, sdptr->lun);
+    size += sprintf(BLS, "  Device using %s/%s",
+          (aic_dev->cur.width == MSG_EXT_WDTR_BUS_16_BIT) ?
+          "Wide" : "Narrow",
+          (aic_dev->cur.offset != 0) ?
+          "Sync transfers at " : "Async transfers.\n" );
+    if (aic_dev->cur.offset != 0)
+    {
+      struct aic7xxx_syncrate *sync_rate;
+      unsigned char options = aic_dev->cur.options;
+      int period = aic_dev->cur.period;
+      int rate = (aic_dev->cur.width ==
+                  MSG_EXT_WDTR_BUS_16_BIT) ? 1 : 0;
+
+      sync_rate = aic7xxx_find_syncrate(p, &period, 0, &options);
+      if (sync_rate != NULL)
+      {
+        size += sprintf(BLS, "%s MByte/sec, offset %d\n",
+                        sync_rate->rate[rate],
+                        aic_dev->cur.offset );
+      }
+      else
+      {
+        size += sprintf(BLS, "3.3 MByte/sec, offset %d\n",
+                        aic_dev->cur.offset );
+      }
+    }
+    size += sprintf(BLS, "  Transinfo settings: ");
+    size += sprintf(BLS, "current(%d/%d/%d/%d), ",
+                    aic_dev->cur.period,
+                    aic_dev->cur.offset,
+                    aic_dev->cur.width,
+                    aic_dev->cur.options);
+    size += sprintf(BLS, "goal(%d/%d/%d/%d), ",
+                    aic_dev->goal.period,
+                    aic_dev->goal.offset,
+                    aic_dev->goal.width,
+                    aic_dev->goal.options);
+    size += sprintf(BLS, "user(%d/%d/%d/%d)\n",
+                    p->user[tindex].period,
+                    p->user[tindex].offset,
+                    p->user[tindex].width,
+                    p->user[tindex].options);
+    if(sdptr->simple_tags)
+    {
+      size += sprintf(BLS, "  Tagged Command Queueing Enabled, Ordered Tags %s, Depth %d/%d\n", sdptr->ordered_tags ? "Enabled" : "Disabled", sdptr->queue_depth, aic_dev->max_q_depth);
+    }
+    if(aic_dev->barrier_total)
+      size += sprintf(BLS, "  Total transfers %ld:\n    (%ld/%ld/%ld/%ld reads/writes/REQ_BARRIER/Ordered Tags)\n",
+        aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total,
+        aic_dev->barrier_total, aic_dev->ordered_total);
+    else
+      size += sprintf(BLS, "  Total transfers %ld:\n    (%ld/%ld reads/writes)\n",
+        aic_dev->r_total+aic_dev->w_total, aic_dev->r_total, aic_dev->w_total);
+    size += sprintf(BLS, "%s\n", HDRB);
+    size += sprintf(BLS, "   Reads:");
+    for (i = 0; i < ARRAY_SIZE(aic_dev->r_bins); i++)
+    {
+      size += sprintf(BLS, " %10ld", aic_dev->r_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+    size += sprintf(BLS, "  Writes:");
+    for (i = 0; i < ARRAY_SIZE(aic_dev->w_bins); i++)
+    {
+      size += sprintf(BLS, " %10ld", aic_dev->w_bins[i]);
+    }
+    size += sprintf(BLS, "\n");
+    size += sprintf(BLS, "\n\n");
+  }
+  if (size >= aic7xxx_buffer_size)
+  {
+    printk(KERN_WARNING "aic7xxx: Overflow in aic7xxx_proc.c\n");
+  }
+
+  if (offset > size - 1)
+  {
+    kfree(aic7xxx_buffer);
+    aic7xxx_buffer = NULL;
+    aic7xxx_buffer_size = length = 0;
+    *start = NULL;
+  }
+  else
+  {
+    *start = buffer;
+    length = min_t(int, length, size - offset);
+    memcpy(buffer, &aic7xxx_buffer[offset], length);
+  }
+
+  return (length);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_reg.h b/drivers/scsi/aic7xxx_old/aic7xxx_reg.h
new file mode 100644
index 0000000..27f2334
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_reg.h
@@ -0,0 +1,629 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+
+#define	SCSISEQ         		0x00
+#define		TEMODE          	0x80
+#define		ENSELO          	0x40
+#define		ENSELI          	0x20
+#define		ENRSELI         	0x10
+#define		ENAUTOATNO      	0x08
+#define		ENAUTOATNI      	0x04
+#define		ENAUTOATNP      	0x02
+#define		SCSIRSTO        	0x01
+
+#define	SXFRCTL0        		0x01
+#define		DFON            	0x80
+#define		DFPEXP          	0x40
+#define		FAST20          	0x20
+#define		CLRSTCNT        	0x10
+#define		SPIOEN          	0x08
+#define		SCAMEN          	0x04
+#define		CLRCHN          	0x02
+
+#define	SXFRCTL1        		0x02
+#define		BITBUCKET       	0x80
+#define		SWRAPEN         	0x40
+#define		ENSPCHK         	0x20
+#define		STIMESEL        	0x18
+#define		ENSTIMER        	0x04
+#define		ACTNEGEN        	0x02
+#define		STPWEN          	0x01
+
+#define	SCSISIGO        		0x03
+#define		CDO             	0x80
+#define		IOO             	0x40
+#define		MSGO            	0x20
+#define		ATNO            	0x10
+#define		SELO            	0x08
+#define		BSYO            	0x04
+#define		REQO            	0x02
+#define		ACKO            	0x01
+
+#define	SCSISIGI        		0x03
+#define		ATNI            	0x10
+#define		SELI            	0x08
+#define		BSYI            	0x04
+#define		REQI            	0x02
+#define		ACKI            	0x01
+
+#define	SCSIRATE        		0x04
+#define		WIDEXFER        	0x80
+#define		SXFR_ULTRA2     	0x7f
+#define		SXFR            	0x70
+#define		SOFS            	0x0f
+
+#define	SCSIID          		0x05
+#define	SCSIOFFSET      		0x05
+#define		SOFS_ULTRA2     	0x7f
+
+#define	SCSIDATL        		0x06
+
+#define	SCSIDATH        		0x07
+
+#define	STCNT           		0x08
+
+#define	OPTIONMODE      		0x08
+#define		AUTORATEEN      	0x80
+#define		AUTOACKEN       	0x40
+#define		ATNMGMNTEN      	0x20
+#define		BUSFREEREV      	0x10
+#define		EXPPHASEDIS     	0x08
+#define		SCSIDATL_IMGEN  	0x04
+#define		AUTO_MSGOUT_DE  	0x02
+#define		DIS_MSGIN_DUALEDGE	0x01
+
+#define	CLRSINT0        		0x0b
+#define		CLRSELDO        	0x40
+#define		CLRSELDI        	0x20
+#define		CLRSELINGO      	0x10
+#define		CLRSWRAP        	0x08
+#define		CLRSPIORDY      	0x02
+
+#define	SSTAT0          		0x0b
+#define		TARGET          	0x80
+#define		SELDO           	0x40
+#define		SELDI           	0x20
+#define		SELINGO         	0x10
+#define		IOERR           	0x08
+#define		SWRAP           	0x08
+#define		SDONE           	0x04
+#define		SPIORDY         	0x02
+#define		DMADONE         	0x01
+
+#define	CLRSINT1        		0x0c
+#define		CLRSELTIMEO     	0x80
+#define		CLRATNO         	0x40
+#define		CLRSCSIRSTI     	0x20
+#define		CLRBUSFREE      	0x08
+#define		CLRSCSIPERR     	0x04
+#define		CLRPHASECHG     	0x02
+#define		CLRREQINIT      	0x01
+
+#define	SSTAT1          		0x0c
+#define		SELTO           	0x80
+#define		ATNTARG         	0x40
+#define		SCSIRSTI        	0x20
+#define		PHASEMIS        	0x10
+#define		BUSFREE         	0x08
+#define		SCSIPERR        	0x04
+#define		PHASECHG        	0x02
+#define		REQINIT         	0x01
+
+#define	SSTAT2          		0x0d
+#define		OVERRUN         	0x80
+#define		SHVALID         	0x40
+#define		WIDE_RES        	0x20
+#define		SFCNT           	0x1f
+#define		EXP_ACTIVE      	0x10
+#define		CRCVALERR       	0x08
+#define		CRCENDERR       	0x04
+#define		CRCREQERR       	0x02
+#define		DUAL_EDGE_ERROR 	0x01
+
+#define	SSTAT3          		0x0e
+#define		SCSICNT         	0xf0
+#define		OFFCNT          	0x0f
+
+#define	SCSIID_ULTRA2   		0x0f
+#define		OID             	0x0f
+
+#define	SIMODE0         		0x10
+#define		ENSELDO         	0x40
+#define		ENSELDI         	0x20
+#define		ENSELINGO       	0x10
+#define		ENIOERR         	0x08
+#define		ENSWRAP         	0x08
+#define		ENSDONE         	0x04
+#define		ENSPIORDY       	0x02
+#define		ENDMADONE       	0x01
+
+#define	SIMODE1         		0x11
+#define		ENSELTIMO       	0x80
+#define		ENATNTARG       	0x40
+#define		ENSCSIRST       	0x20
+#define		ENPHASEMIS      	0x10
+#define		ENBUSFREE       	0x08
+#define		ENSCSIPERR      	0x04
+#define		ENPHASECHG      	0x02
+#define		ENREQINIT       	0x01
+
+#define	SCSIBUSL        		0x12
+
+#define	SCSIBUSH        		0x13
+
+#define	SHADDR          		0x14
+
+#define	SELTIMER        		0x18
+#define		STAGE6          	0x20
+#define		STAGE5          	0x10
+#define		STAGE4          	0x08
+#define		STAGE3          	0x04
+#define		STAGE2          	0x02
+#define		STAGE1          	0x01
+
+#define	SELID           		0x19
+#define		SELID_MASK      	0xf0
+#define		ONEBIT          	0x08
+
+#define	SPIOCAP         		0x1b
+#define		SOFT1           	0x80
+#define		SOFT0           	0x40
+#define		SOFTCMDEN       	0x20
+#define		HAS_BRDCTL      	0x10
+#define		SEEPROM         	0x08
+#define		EEPROM          	0x04
+#define		ROM             	0x02
+#define		SSPIOCPS        	0x01
+
+#define	BRDCTL          		0x1d
+#define		BRDDAT7         	0x80
+#define		BRDDAT6         	0x40
+#define		BRDDAT5         	0x20
+#define		BRDDAT4         	0x10
+#define		BRDSTB          	0x10
+#define		BRDCS           	0x08
+#define		BRDDAT3         	0x08
+#define		BRDDAT2         	0x04
+#define		BRDRW           	0x04
+#define		BRDRW_ULTRA2    	0x02
+#define		BRDCTL1         	0x02
+#define		BRDSTB_ULTRA2   	0x01
+#define		BRDCTL0         	0x01
+
+#define	SEECTL          		0x1e
+#define		EXTARBACK       	0x80
+#define		EXTARBREQ       	0x40
+#define		SEEMS           	0x20
+#define		SEERDY          	0x10
+#define		SEECS           	0x08
+#define		SEECK           	0x04
+#define		SEEDO           	0x02
+#define		SEEDI           	0x01
+
+#define	SBLKCTL         		0x1f
+#define		DIAGLEDEN       	0x80
+#define		DIAGLEDON       	0x40
+#define		AUTOFLUSHDIS    	0x20
+#define		ENAB40          	0x08
+#define		ENAB20          	0x04
+#define		SELWIDE         	0x02
+#define		XCVR            	0x01
+
+#define	SRAM_BASE       		0x20
+
+#define	TARG_SCSIRATE   		0x20
+
+#define	ULTRA_ENB       		0x30
+
+#define	DISC_DSB        		0x32
+
+#define	MSG_OUT         		0x34
+
+#define	DMAPARAMS       		0x35
+#define		PRELOADEN       	0x80
+#define		WIDEODD         	0x40
+#define		SCSIEN          	0x20
+#define		SDMAENACK       	0x10
+#define		SDMAEN          	0x10
+#define		HDMAEN          	0x08
+#define		HDMAENACK       	0x08
+#define		DIRECTION       	0x04
+#define		FIFOFLUSH       	0x02
+#define		FIFORESET       	0x01
+
+#define	SEQ_FLAGS       		0x36
+#define		IDENTIFY_SEEN   	0x80
+#define		SCBPTR_VALID    	0x20
+#define		DPHASE          	0x10
+#define		AMTARGET        	0x08
+#define		WIDE_BUS        	0x02
+#define		TWIN_BUS        	0x01
+
+#define	SAVED_TCL       		0x37
+
+#define	SG_COUNT        		0x38
+
+#define	SG_NEXT         		0x39
+
+#define	LASTPHASE       		0x3d
+#define		P_MESGIN        	0xe0
+#define		PHASE_MASK      	0xe0
+#define		P_STATUS        	0xc0
+#define		P_MESGOUT       	0xa0
+#define		P_COMMAND       	0x80
+#define		CDI             	0x80
+#define		IOI             	0x40
+#define		P_DATAIN        	0x40
+#define		MSGI            	0x20
+#define		P_BUSFREE       	0x01
+#define		P_DATAOUT       	0x00
+
+#define	WAITING_SCBH    		0x3e
+
+#define	DISCONNECTED_SCBH		0x3f
+
+#define	FREE_SCBH       		0x40
+
+#define	HSCB_ADDR       		0x41
+
+#define	SCBID_ADDR      		0x45
+
+#define	TMODE_CMDADDR   		0x49
+
+#define	KERNEL_QINPOS   		0x4d
+
+#define	QINPOS          		0x4e
+
+#define	QOUTPOS         		0x4f
+
+#define	TMODE_CMDADDR_NEXT		0x50
+
+#define	ARG_1           		0x51
+#define	RETURN_1        		0x51
+#define		SEND_MSG        	0x80
+#define		SEND_SENSE      	0x40
+#define		SEND_REJ        	0x20
+#define		MSGOUT_PHASEMIS 	0x10
+
+#define	ARG_2           		0x52
+#define	RETURN_2        		0x52
+
+#define	LAST_MSG        		0x53
+
+#define	PREFETCH_CNT    		0x54
+
+#define	SCSICONF        		0x5a
+#define		TERM_ENB        	0x80
+#define		RESET_SCSI      	0x40
+#define		HWSCSIID        	0x0f
+#define		HSCSIID         	0x07
+
+#define	HOSTCONF        		0x5d
+
+#define	HA_274_BIOSCTRL 		0x5f
+#define		BIOSMODE        	0x30
+#define		BIOSDISABLED    	0x30
+#define		CHANNEL_B_PRIMARY	0x08
+
+#define	SEQCTL          		0x60
+#define		PERRORDIS       	0x80
+#define		PAUSEDIS        	0x40
+#define		FAILDIS         	0x20
+#define		FASTMODE        	0x10
+#define		BRKADRINTEN     	0x08
+#define		STEP            	0x04
+#define		SEQRESET        	0x02
+#define		LOADRAM         	0x01
+
+#define	SEQRAM          		0x61
+
+#define	SEQADDR0        		0x62
+
+#define	SEQADDR1        		0x63
+#define		SEQADDR1_MASK   	0x01
+
+#define	ACCUM           		0x64
+
+#define	SINDEX          		0x65
+
+#define	DINDEX          		0x66
+
+#define	ALLONES         		0x69
+
+#define	ALLZEROS        		0x6a
+
+#define	NONE            		0x6a
+
+#define	FLAGS           		0x6b
+#define		ZERO            	0x02
+#define		CARRY           	0x01
+
+#define	SINDIR          		0x6c
+
+#define	DINDIR          		0x6d
+
+#define	FUNCTION1       		0x6e
+
+#define	STACK           		0x6f
+
+#define	TARG_OFFSET     		0x70
+
+#define	BCTL            		0x84
+#define		ACE             	0x08
+#define		ENABLE          	0x01
+
+#define	DSCOMMAND0      		0x84
+#define		INTSCBRAMSEL    	0x08
+#define		RAMPS           	0x04
+#define		USCBSIZE32      	0x02
+#define		CIOPARCKEN      	0x01
+
+#define	DSCOMMAND       		0x84
+#define		CACHETHEN       	0x80
+#define		DPARCKEN        	0x40
+#define		MPARCKEN        	0x20
+#define		EXTREQLCK       	0x10
+
+#define	BUSTIME         		0x85
+#define		BOFF            	0xf0
+#define		BON             	0x0f
+
+#define	BUSSPD          		0x86
+#define		DFTHRSH         	0xc0
+#define		STBOFF          	0x38
+#define		STBON           	0x07
+
+#define	DSPCISTATUS     		0x86
+#define		DFTHRSH_100     	0xc0
+
+#define	HCNTRL          		0x87
+#define		POWRDN          	0x40
+#define		SWINT           	0x10
+#define		IRQMS           	0x08
+#define		PAUSE           	0x04
+#define		INTEN           	0x02
+#define		CHIPRST         	0x01
+#define		CHIPRSTACK      	0x01
+
+#define	HADDR           		0x88
+
+#define	HCNT            		0x8c
+
+#define	SCBPTR          		0x90
+
+#define	INTSTAT         		0x91
+#define		SEQINT_MASK     	0xf1
+#define		DATA_OVERRUN    	0xe1
+#define		MSGIN_PHASEMIS  	0xd1
+#define		TRACEPOINT2     	0xc1
+#define		SEQ_SG_FIXUP    	0xb1
+#define		AWAITING_MSG    	0xa1
+#define		RESIDUAL        	0x81
+#define		BAD_STATUS      	0x71
+#define		REJECT_MSG      	0x61
+#define		WIDE_RESIDUE    	0x51
+#define		EXTENDED_MSG    	0x41
+#define		NO_MATCH        	0x31
+#define		NO_IDENT        	0x21
+#define		SEND_REJECT     	0x11
+#define		INT_PEND        	0x0f
+#define		BRKADRINT       	0x08
+#define		SCSIINT         	0x04
+#define		CMDCMPLT        	0x02
+#define		BAD_PHASE       	0x01
+#define		SEQINT          	0x01
+
+#define	CLRINT          		0x92
+#define		CLRPARERR       	0x10
+#define		CLRBRKADRINT    	0x08
+#define		CLRSCSIINT      	0x04
+#define		CLRCMDINT       	0x02
+#define		CLRSEQINT       	0x01
+
+#define	ERROR           		0x92
+#define		CIOPARERR       	0x80
+#define		PCIERRSTAT      	0x40
+#define		MPARERR         	0x20
+#define		DPARERR         	0x10
+#define		SQPARERR        	0x08
+#define		ILLOPCODE       	0x04
+#define		DSCTMOUT        	0x02
+#define		ILLSADDR        	0x02
+#define		ILLHADDR        	0x01
+
+#define	DFCNTRL         		0x93
+
+#define	DFSTATUS        		0x94
+#define		PRELOAD_AVAIL   	0x80
+#define		DWORDEMP        	0x20
+#define		MREQPEND        	0x10
+#define		HDONE           	0x08
+#define		DFTHRESH        	0x04
+#define		FIFOFULL        	0x02
+#define		FIFOEMP         	0x01
+
+#define	DFDAT           		0x99
+
+#define	SCBCNT          		0x9a
+#define		SCBAUTO         	0x80
+#define		SCBCNT_MASK     	0x1f
+
+#define	QINFIFO         		0x9b
+
+#define	QINCNT          		0x9c
+
+#define	SCSIDATL_IMG    		0x9c
+
+#define	QOUTFIFO        		0x9d
+
+#define	CRCCONTROL1     		0x9d
+#define		CRCONSEEN       	0x80
+#define		CRCVALCHKEN     	0x40
+#define		CRCENDCHKEN     	0x20
+#define		CRCREQCHKEN     	0x10
+#define		TARGCRCENDEN    	0x08
+#define		TARGCRCCNTEN    	0x04
+
+#define	SCSIPHASE       		0x9e
+#define		SP_STATUS       	0x20
+#define		SP_COMMAND      	0x10
+#define		SP_MSG_IN       	0x08
+#define		SP_MSG_OUT      	0x04
+#define		SP_DATA_IN      	0x02
+#define		SP_DATA_OUT     	0x01
+
+#define	QOUTCNT         		0x9e
+
+#define	SFUNCT          		0x9f
+#define		ALT_MODE        	0x80
+
+#define	SCB_CONTROL     		0xa0
+#define		MK_MESSAGE      	0x80
+#define		DISCENB         	0x40
+#define		TAG_ENB         	0x20
+#define		DISCONNECTED    	0x04
+#define		SCB_TAG_TYPE    	0x03
+
+#define	SCB_BASE        		0xa0
+
+#define	SCB_TCL         		0xa1
+#define		TID             	0xf0
+#define		SELBUSB         	0x08
+#define		LID             	0x07
+
+#define	SCB_TARGET_STATUS		0xa2
+
+#define	SCB_SGCOUNT     		0xa3
+
+#define	SCB_SGPTR       		0xa4
+
+#define	SCB_RESID_SGCNT 		0xa8
+
+#define	SCB_RESID_DCNT  		0xa9
+
+#define	SCB_DATAPTR     		0xac
+
+#define	SCB_DATACNT     		0xb0
+
+#define	SCB_CMDPTR      		0xb4
+
+#define	SCB_CMDLEN      		0xb8
+
+#define	SCB_TAG         		0xb9
+
+#define	SCB_NEXT        		0xba
+
+#define	SCB_PREV        		0xbb
+
+#define	SCB_BUSYTARGETS 		0xbc
+
+#define	SEECTL_2840     		0xc0
+#define		CS_2840         	0x04
+#define		CK_2840         	0x02
+#define		DO_2840         	0x01
+
+#define	STATUS_2840     		0xc1
+#define		EEPROM_TF       	0x80
+#define		BIOS_SEL        	0x60
+#define		ADSEL           	0x1e
+#define		DI_2840         	0x01
+
+#define	CCHADDR         		0xe0
+
+#define	CCHCNT          		0xe8
+
+#define	CCSGRAM         		0xe9
+
+#define	CCSGADDR        		0xea
+
+#define	CCSGCTL         		0xeb
+#define		CCSGDONE        	0x80
+#define		CCSGEN          	0x08
+#define		FLAG            	0x02
+#define		CCSGRESET       	0x01
+
+#define	CCSCBRAM        		0xec
+
+#define	CCSCBADDR       		0xed
+
+#define	CCSCBCTL        		0xee
+#define		CCSCBDONE       	0x80
+#define		ARRDONE         	0x40
+#define		CCARREN         	0x10
+#define		CCSCBEN         	0x08
+#define		CCSCBDIR        	0x04
+#define		CCSCBRESET      	0x01
+
+#define	CCSCBCNT        		0xef
+
+#define	CCSCBPTR        		0xf1
+
+#define	HNSCB_QOFF      		0xf4
+
+#define	HESCB_QOFF      		0xf5
+
+#define	SNSCB_QOFF      		0xf6
+
+#define	SESCB_QOFF      		0xf7
+
+#define	SDSCB_QOFF      		0xf8
+
+#define	QOFF_CTLSTA     		0xfa
+#define		ESTABLISH_SCB_AVAIL	0x80
+#define		SCB_AVAIL       	0x40
+#define		SNSCB_ROLLOVER  	0x20
+#define		SDSCB_ROLLOVER  	0x10
+#define		SESCB_ROLLOVER  	0x08
+#define		SCB_QSIZE       	0x07
+#define		SCB_QSIZE_256   	0x06
+
+#define	DFF_THRSH       		0xfb
+#define		WR_DFTHRSH      	0x70
+#define		WR_DFTHRSH_MAX  	0x70
+#define		WR_DFTHRSH_90   	0x60
+#define		WR_DFTHRSH_85   	0x50
+#define		WR_DFTHRSH_75   	0x40
+#define		WR_DFTHRSH_63   	0x30
+#define		WR_DFTHRSH_50   	0x20
+#define		WR_DFTHRSH_25   	0x10
+#define		RD_DFTHRSH_MAX  	0x07
+#define		RD_DFTHRSH      	0x07
+#define		RD_DFTHRSH_90   	0x06
+#define		RD_DFTHRSH_85   	0x05
+#define		RD_DFTHRSH_75   	0x04
+#define		RD_DFTHRSH_63   	0x03
+#define		RD_DFTHRSH_50   	0x02
+#define		RD_DFTHRSH_25   	0x01
+#define		WR_DFTHRSH_MIN  	0x00
+#define		RD_DFTHRSH_MIN  	0x00
+
+#define	SG_CACHEPTR     		0xfc
+#define		SG_USER_DATA    	0xfc
+#define		LAST_SEG        	0x02
+#define		LAST_SEG_DONE   	0x01
+
+
+#define	CMD_GROUP2_BYTE_DELTA	0xfa
+#define	MAX_OFFSET_8BIT	0x0f
+#define	BUS_16_BIT	0x01
+#define	QINFIFO_OFFSET	0x02
+#define	CMD_GROUP5_BYTE_DELTA	0x0b
+#define	CMD_GROUP_CODE_SHIFT	0x05
+#define	MAX_OFFSET_ULTRA2	0x7f
+#define	MAX_OFFSET_16BIT	0x08
+#define	BUS_8_BIT	0x00
+#define	QOUTFIFO_OFFSET	0x01
+#define	UNTAGGEDSCB_OFFSET	0x00
+#define	CCSGRAM_MAXSEGS	0x10
+#define	SCB_LIST_NULL	0xff
+#define	SG_SIZEOF	0x08
+#define	CMD_GROUP4_BYTE_DELTA	0x04
+#define	CMD_GROUP0_BYTE_DELTA	0xfc
+#define	HOST_MSG	0xff
+#define	BUS_32_BIT	0x02
+#define	CCSGADDR_MAX	0x80
+
+
+/* Downloaded Constant Definitions */
+#define	TMODE_NUMCMDS	0x00
diff --git a/drivers/scsi/aic7xxx_old/aic7xxx_seq.c b/drivers/scsi/aic7xxx_old/aic7xxx_seq.c
new file mode 100644
index 0000000..e1bc140
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/aic7xxx_seq.c
@@ -0,0 +1,817 @@
+/*
+  * DO NOT EDIT - This file is automatically generated.
+  */
+static unsigned char seqprog[] = {
+	0xff, 0x6a, 0x06, 0x08,
+	0x7f, 0x02, 0x04, 0x08,
+	0x12, 0x6a, 0x00, 0x00,
+	0xff, 0x6a, 0xd6, 0x09,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x00, 0x65, 0xca, 0x58,
+	0xf7, 0x01, 0x02, 0x08,
+	0xff, 0x4e, 0xc8, 0x08,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0x60, 0x0b, 0x86, 0x68,
+	0x40, 0x00, 0x0c, 0x68,
+	0x08, 0x1f, 0x3e, 0x10,
+	0xff, 0x3e, 0x48, 0x60,
+	0x40, 0xfa, 0x10, 0x78,
+	0xff, 0xf6, 0xd4, 0x08,
+	0x01, 0x4e, 0x9c, 0x18,
+	0x40, 0x60, 0xc0, 0x00,
+	0x00, 0x4d, 0x10, 0x70,
+	0x01, 0x4e, 0x9c, 0x18,
+	0xbf, 0x60, 0xc0, 0x08,
+	0x00, 0x6a, 0x86, 0x5c,
+	0xff, 0x4e, 0xc8, 0x18,
+	0x02, 0x6a, 0x70, 0x5b,
+	0xff, 0x52, 0x20, 0x09,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x52, 0xe6, 0x5b,
+	0x03, 0xb0, 0x52, 0x31,
+	0xff, 0xb0, 0x52, 0x09,
+	0xff, 0xb1, 0x54, 0x09,
+	0xff, 0xb2, 0x56, 0x09,
+	0xff, 0xa3, 0x50, 0x09,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0xff, 0x3e, 0x20, 0x09,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0x0c, 0x40,
+	0xf7, 0x1f, 0xca, 0x08,
+	0x08, 0xa1, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0xff, 0x65, 0x3e, 0x08,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x0f, 0x1e, 0x08,
+	0x00, 0x0f, 0x1e, 0x00,
+	0xf0, 0xa1, 0xc8, 0x08,
+	0x0f, 0x05, 0x0a, 0x08,
+	0x00, 0x05, 0x0a, 0x00,
+	0xff, 0x6a, 0x0c, 0x08,
+	0x5a, 0x6a, 0x00, 0x04,
+	0x12, 0x65, 0x02, 0x00,
+	0x31, 0x6a, 0xca, 0x00,
+	0x80, 0x37, 0x6e, 0x68,
+	0xff, 0x65, 0xca, 0x18,
+	0xff, 0x37, 0xdc, 0x08,
+	0xff, 0x6e, 0xc8, 0x08,
+	0x00, 0x6c, 0x76, 0x78,
+	0x20, 0x01, 0x02, 0x00,
+	0x4c, 0x37, 0xc8, 0x28,
+	0x08, 0x1f, 0x7e, 0x78,
+	0x08, 0x37, 0x6e, 0x00,
+	0x08, 0x64, 0xc8, 0x00,
+	0x70, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x0a, 0x08,
+	0x20, 0x64, 0xca, 0x18,
+	0xff, 0x6c, 0x08, 0x0c,
+	0x40, 0x0b, 0x96, 0x68,
+	0x20, 0x6a, 0x16, 0x00,
+	0xf0, 0x19, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x12, 0x6a, 0x00, 0x00,
+	0x40, 0x6a, 0x16, 0x00,
+	0xff, 0x3e, 0x20, 0x09,
+	0xff, 0xba, 0x7c, 0x08,
+	0xff, 0xa1, 0x6e, 0x08,
+	0x08, 0x6a, 0x18, 0x00,
+	0x08, 0x11, 0x22, 0x00,
+	0x08, 0x6a, 0x66, 0x58,
+	0x80, 0x6a, 0x68, 0x00,
+	0x80, 0x36, 0x6c, 0x00,
+	0x00, 0x65, 0xba, 0x5b,
+	0xff, 0x3d, 0xc8, 0x08,
+	0xbf, 0x64, 0xe2, 0x78,
+	0x80, 0x64, 0xc8, 0x71,
+	0xa0, 0x64, 0xf8, 0x71,
+	0xc0, 0x64, 0xf0, 0x71,
+	0xe0, 0x64, 0x38, 0x72,
+	0x01, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xf7, 0x11, 0x22, 0x08,
+	0x00, 0x65, 0xca, 0x58,
+	0xff, 0x06, 0xd4, 0x08,
+	0xf7, 0x01, 0x02, 0x08,
+	0x09, 0x0c, 0xc4, 0x78,
+	0x08, 0x0c, 0x0c, 0x68,
+	0x01, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0x26, 0x09,
+	0x02, 0x6a, 0x08, 0x30,
+	0xff, 0x6a, 0x08, 0x08,
+	0xdf, 0x01, 0x02, 0x08,
+	0x01, 0x6a, 0x7a, 0x00,
+	0xff, 0x6a, 0x6c, 0x0c,
+	0x04, 0x14, 0x10, 0x31,
+	0x03, 0xa9, 0x18, 0x31,
+	0x03, 0xa9, 0x10, 0x30,
+	0x08, 0x6a, 0xcc, 0x00,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x02, 0x41,
+	0xa8, 0x6a, 0x6a, 0x00,
+	0x79, 0x6a, 0x6a, 0x00,
+	0x40, 0x3d, 0xea, 0x68,
+	0x04, 0x35, 0x6a, 0x00,
+	0x00, 0x65, 0x2a, 0x5b,
+	0x80, 0x6a, 0xd4, 0x01,
+	0x10, 0x36, 0xd6, 0x68,
+	0x10, 0x36, 0x6c, 0x00,
+	0x07, 0xac, 0x10, 0x31,
+	0x05, 0xa3, 0x70, 0x30,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xac, 0x6a, 0xc8, 0x5b,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x38, 0x6a, 0xcc, 0x00,
+	0xa3, 0x6a, 0xcc, 0x5b,
+	0xff, 0x38, 0x12, 0x69,
+	0x80, 0x02, 0x04, 0x00,
+	0xe7, 0x35, 0x6a, 0x08,
+	0x03, 0x69, 0x18, 0x31,
+	0x03, 0x69, 0x10, 0x30,
+	0xff, 0x6a, 0x10, 0x00,
+	0xff, 0x6a, 0x12, 0x00,
+	0xff, 0x6a, 0x14, 0x00,
+	0x22, 0x38, 0xc8, 0x28,
+	0x01, 0x38, 0x1c, 0x61,
+	0x02, 0x64, 0xc8, 0x00,
+	0x01, 0x38, 0x1c, 0x61,
+	0xbf, 0x35, 0x6a, 0x08,
+	0xff, 0x64, 0xf8, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x80, 0x02, 0xa4, 0x69,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x80, 0x94, 0x22, 0x79,
+	0x00, 0x35, 0x0a, 0x5b,
+	0x80, 0x02, 0xa4, 0x69,
+	0xff, 0x65, 0x94, 0x79,
+	0x01, 0x38, 0x70, 0x71,
+	0xff, 0x38, 0x70, 0x18,
+	0xff, 0x38, 0x94, 0x79,
+	0x80, 0xea, 0x4a, 0x61,
+	0xef, 0x38, 0xc8, 0x18,
+	0x80, 0x6a, 0xc8, 0x00,
+	0x00, 0x65, 0x3c, 0x49,
+	0x33, 0x38, 0xc8, 0x28,
+	0xff, 0x64, 0xd0, 0x09,
+	0x04, 0x39, 0xc0, 0x31,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x42, 0x79,
+	0xf7, 0xeb, 0xd6, 0x09,
+	0x08, 0xeb, 0x46, 0x69,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x08, 0xe9, 0x10, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0xff, 0x38, 0x70, 0x18,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x39, 0x6a, 0xce, 0x5b,
+	0x08, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x5c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x00, 0x65, 0x6a, 0x5c,
+	0x00, 0x65, 0xc2, 0x5b,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x08, 0x39, 0x72, 0x18,
+	0x00, 0x3a, 0x74, 0x20,
+	0x00, 0x65, 0x02, 0x41,
+	0x01, 0x0c, 0x6c, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x10, 0x0c, 0x7a, 0x69,
+	0x01, 0xfc, 0x70, 0x79,
+	0xff, 0x6a, 0x70, 0x08,
+	0x01, 0x0c, 0x76, 0x79,
+	0x10, 0x0c, 0x02, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x01, 0xfc, 0x94, 0x69,
+	0x40, 0x0d, 0x84, 0x69,
+	0xb1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x94, 0x41,
+	0x2e, 0xfc, 0xa2, 0x28,
+	0x3f, 0x38, 0xc8, 0x08,
+	0x00, 0x51, 0x94, 0x71,
+	0xff, 0x6a, 0xc8, 0x08,
+	0xf8, 0x39, 0x72, 0x18,
+	0xff, 0x3a, 0x74, 0x20,
+	0x01, 0x38, 0x70, 0x18,
+	0x00, 0x65, 0x86, 0x41,
+	0x03, 0x08, 0x52, 0x31,
+	0xff, 0x38, 0x50, 0x09,
+	0x12, 0x01, 0x02, 0x00,
+	0xff, 0x08, 0x52, 0x09,
+	0xff, 0x09, 0x54, 0x09,
+	0xff, 0x0a, 0x56, 0x09,
+	0xff, 0x38, 0x50, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x0c, 0xa4, 0x79,
+	0x00, 0x65, 0xae, 0x59,
+	0x7f, 0x02, 0x04, 0x08,
+	0xe1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0x93, 0xc2, 0x69,
+	0xdf, 0x93, 0x26, 0x09,
+	0x20, 0x93, 0xb2, 0x69,
+	0x02, 0x93, 0x26, 0x01,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x01, 0x94, 0xb6, 0x79,
+	0x10, 0x94, 0xc0, 0x69,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xc4, 0x69,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x2a, 0x5b,
+	0x05, 0xb4, 0x10, 0x31,
+	0x02, 0x6a, 0x1a, 0x31,
+	0x03, 0x8c, 0x10, 0x30,
+	0x88, 0x6a, 0xcc, 0x00,
+	0xb4, 0x6a, 0xcc, 0x5b,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x00, 0x65, 0xc2, 0x5b,
+	0x3d, 0x6a, 0x0a, 0x5b,
+	0xac, 0x6a, 0x26, 0x01,
+	0x04, 0x0b, 0xde, 0x69,
+	0x04, 0x0b, 0xe4, 0x69,
+	0x10, 0x0c, 0xe0, 0x79,
+	0x02, 0x03, 0xe8, 0x79,
+	0x11, 0x0c, 0xe4, 0x79,
+	0xd7, 0x93, 0x26, 0x09,
+	0x28, 0x93, 0xea, 0x69,
+	0x12, 0x01, 0x02, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x00, 0x65, 0x2a, 0x5b,
+	0xff, 0x06, 0x44, 0x09,
+	0x00, 0x65, 0xaa, 0x40,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x34, 0xca, 0x08,
+	0x80, 0x65, 0x1c, 0x62,
+	0x0f, 0xa1, 0xca, 0x08,
+	0x07, 0xa1, 0xca, 0x08,
+	0x40, 0xa0, 0xc8, 0x08,
+	0x00, 0x65, 0xca, 0x00,
+	0x80, 0x65, 0xca, 0x00,
+	0x80, 0xa0, 0x0c, 0x7a,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0x1e, 0x42,
+	0x20, 0xa0, 0x24, 0x7a,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x23, 0xa0, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0x2c, 0x62,
+	0x00, 0xb9, 0x24, 0x42,
+	0xff, 0x65, 0x24, 0x62,
+	0xa1, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x10, 0x51, 0x2c, 0x72,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x65, 0x0c, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xa0, 0x3d, 0xf6, 0x71,
+	0x40, 0x6a, 0x18, 0x00,
+	0xff, 0x34, 0xa6, 0x08,
+	0x80, 0x34, 0x34, 0x62,
+	0x7f, 0xa0, 0x40, 0x09,
+	0x08, 0x6a, 0x68, 0x00,
+	0x00, 0x65, 0xaa, 0x40,
+	0x64, 0x6a, 0x00, 0x5b,
+	0x80, 0x64, 0xaa, 0x6a,
+	0x04, 0x64, 0x8c, 0x72,
+	0x02, 0x64, 0x92, 0x72,
+	0x00, 0x6a, 0x54, 0x72,
+	0x03, 0x64, 0xa6, 0x72,
+	0x01, 0x64, 0x88, 0x72,
+	0x07, 0x64, 0xe8, 0x72,
+	0x08, 0x64, 0x50, 0x72,
+	0x23, 0x64, 0xec, 0x72,
+	0x11, 0x6a, 0x22, 0x01,
+	0x07, 0x6a, 0xf2, 0x5a,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0xa8, 0x58, 0x6a,
+	0xff, 0xa2, 0x70, 0x7a,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xa2, 0x70, 0x7a,
+	0x71, 0x6a, 0x22, 0x01,
+	0xff, 0x6a, 0xd4, 0x08,
+	0x40, 0x51, 0x70, 0x62,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0x3e, 0x74, 0x09,
+	0xff, 0x90, 0x7c, 0x08,
+	0x00, 0x65, 0x4e, 0x58,
+	0x00, 0x65, 0xbc, 0x40,
+	0x20, 0xa0, 0x78, 0x6a,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x90, 0x5b,
+	0xff, 0x6a, 0xa6, 0x5b,
+	0xff, 0xf8, 0xc8, 0x08,
+	0xff, 0x4f, 0xc8, 0x08,
+	0x01, 0x6a, 0x90, 0x5b,
+	0x00, 0xb9, 0xa6, 0x5b,
+	0x01, 0x4f, 0x9e, 0x18,
+	0x02, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x80, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x41, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0x04, 0xa0, 0x40, 0x01,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xbc, 0x40,
+	0x10, 0x36, 0x50, 0x7a,
+	0x05, 0x38, 0x46, 0x31,
+	0x04, 0x14, 0x58, 0x31,
+	0x03, 0xa9, 0x60, 0x31,
+	0xa3, 0x6a, 0xcc, 0x00,
+	0x38, 0x6a, 0xcc, 0x5b,
+	0xac, 0x6a, 0xcc, 0x00,
+	0x14, 0x6a, 0xce, 0x5b,
+	0xa9, 0x6a, 0xd0, 0x5b,
+	0x00, 0x65, 0x50, 0x42,
+	0xef, 0x36, 0x6c, 0x08,
+	0x00, 0x65, 0x50, 0x42,
+	0x0f, 0x64, 0xc8, 0x08,
+	0x07, 0x64, 0xc8, 0x08,
+	0x00, 0x37, 0x6e, 0x00,
+	0xff, 0x6a, 0xa4, 0x00,
+	0x00, 0x65, 0x60, 0x5b,
+	0xff, 0x51, 0xbc, 0x72,
+	0x20, 0x36, 0xc6, 0x7a,
+	0x00, 0x90, 0x4e, 0x5b,
+	0x00, 0x65, 0xc8, 0x42,
+	0xff, 0x06, 0xd4, 0x08,
+	0x00, 0x65, 0xba, 0x5b,
+	0xe0, 0x3d, 0xe2, 0x62,
+	0x20, 0x12, 0xe2, 0x62,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x00, 0x65, 0x48, 0x5b,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0xa1, 0xda, 0x62,
+	0x04, 0xa0, 0xda, 0x7a,
+	0xfb, 0xa0, 0x40, 0x09,
+	0x80, 0x36, 0x6c, 0x00,
+	0x80, 0xa0, 0x50, 0x7a,
+	0x7f, 0xa0, 0x40, 0x09,
+	0xff, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x04, 0xa0, 0xe0, 0x7a,
+	0x00, 0x65, 0x98, 0x5c,
+	0x00, 0x65, 0xe2, 0x42,
+	0x00, 0x65, 0x80, 0x5c,
+	0x31, 0x6a, 0x22, 0x01,
+	0x0c, 0x6a, 0xf2, 0x5a,
+	0x00, 0x65, 0x50, 0x42,
+	0x61, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x50, 0x42,
+	0x51, 0x6a, 0xf6, 0x5a,
+	0x51, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0x50, 0x42,
+	0x10, 0x3d, 0x06, 0x00,
+	0xff, 0x65, 0x68, 0x0c,
+	0xff, 0x06, 0xd4, 0x08,
+	0x01, 0x0c, 0xf8, 0x7a,
+	0x04, 0x0c, 0xfa, 0x6a,
+	0xe0, 0x03, 0x7a, 0x08,
+	0xe0, 0x3d, 0x06, 0x63,
+	0xff, 0x65, 0xcc, 0x08,
+	0xff, 0x12, 0xda, 0x0c,
+	0xff, 0x06, 0xd4, 0x0c,
+	0xd1, 0x6a, 0x22, 0x01,
+	0x00, 0x65, 0xaa, 0x40,
+	0xff, 0x65, 0x26, 0x09,
+	0x01, 0x0b, 0x1a, 0x6b,
+	0x10, 0x0c, 0x0c, 0x7b,
+	0x04, 0x0b, 0x14, 0x6b,
+	0xff, 0x6a, 0xca, 0x08,
+	0x04, 0x93, 0x18, 0x6b,
+	0x01, 0x94, 0x16, 0x7b,
+	0x10, 0x94, 0x18, 0x6b,
+	0x80, 0x3d, 0x1e, 0x73,
+	0x0f, 0x04, 0x22, 0x6b,
+	0x02, 0x03, 0x22, 0x7b,
+	0x11, 0x0c, 0x1e, 0x7b,
+	0xc7, 0x93, 0x26, 0x09,
+	0xff, 0x99, 0xd4, 0x08,
+	0x38, 0x93, 0x24, 0x6b,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x80, 0x36, 0x28, 0x6b,
+	0x21, 0x6a, 0x22, 0x05,
+	0xff, 0x65, 0x20, 0x09,
+	0xff, 0x51, 0x36, 0x63,
+	0xff, 0x37, 0xc8, 0x08,
+	0xa1, 0x6a, 0x42, 0x43,
+	0xff, 0x51, 0xc8, 0x08,
+	0xb9, 0x6a, 0x42, 0x43,
+	0xff, 0x90, 0xa4, 0x08,
+	0xff, 0xba, 0x46, 0x73,
+	0xff, 0xba, 0x20, 0x09,
+	0xff, 0x65, 0xca, 0x18,
+	0x00, 0x6c, 0x3a, 0x63,
+	0xff, 0x90, 0xca, 0x0c,
+	0xff, 0x6a, 0xca, 0x04,
+	0x20, 0x36, 0x5a, 0x7b,
+	0x00, 0x90, 0x2e, 0x5b,
+	0xff, 0x65, 0x5a, 0x73,
+	0xff, 0x52, 0x58, 0x73,
+	0xff, 0xba, 0xcc, 0x08,
+	0xff, 0x52, 0x20, 0x09,
+	0xff, 0x66, 0x74, 0x09,
+	0xff, 0x65, 0x20, 0x0d,
+	0xff, 0xba, 0x7e, 0x0c,
+	0x00, 0x6a, 0x86, 0x5c,
+	0x0d, 0x6a, 0x6a, 0x00,
+	0x00, 0x51, 0xe6, 0x43,
+	0xff, 0x3f, 0xb4, 0x73,
+	0xff, 0x6a, 0xa2, 0x00,
+	0x00, 0x3f, 0x2e, 0x5b,
+	0xff, 0x65, 0xb4, 0x73,
+	0x20, 0x36, 0x6c, 0x00,
+	0x20, 0xa0, 0x6e, 0x6b,
+	0xff, 0xb9, 0xa2, 0x0c,
+	0xff, 0x6a, 0xa2, 0x04,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xd6, 0x01,
+	0x80, 0xeb, 0x7a, 0x7b,
+	0x01, 0x6a, 0xd6, 0x01,
+	0x01, 0xe9, 0xa4, 0x34,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x0d, 0x6a, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x5c,
+	0xff, 0x99, 0xa4, 0x0c,
+	0xff, 0x65, 0xa4, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0xd0, 0x01,
+	0x01, 0x6a, 0xdc, 0x05,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x45, 0x6a, 0xda, 0x5b,
+	0x01, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0x01, 0x6a, 0x26, 0x05,
+	0x01, 0x65, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xaa, 0x7b,
+	0xff, 0x6a, 0xdc, 0x0d,
+	0xff, 0x65, 0x32, 0x09,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x44,
+	0xff, 0x37, 0xc8, 0x08,
+	0x00, 0x6a, 0x70, 0x5b,
+	0xff, 0x52, 0xa2, 0x0c,
+	0x01, 0x0c, 0xba, 0x7b,
+	0x04, 0x0c, 0xba, 0x6b,
+	0xe0, 0x03, 0x06, 0x08,
+	0xe0, 0x03, 0x7a, 0x0c,
+	0xff, 0x8c, 0x10, 0x08,
+	0xff, 0x8d, 0x12, 0x08,
+	0xff, 0x8e, 0x14, 0x0c,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x08,
+	0xff, 0x6c, 0xda, 0x0c,
+	0x3d, 0x64, 0xa4, 0x28,
+	0x55, 0x64, 0xc8, 0x28,
+	0x00, 0x6c, 0xda, 0x18,
+	0xff, 0x52, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0xff, 0x6a, 0xc8, 0x08,
+	0x00, 0x6c, 0xda, 0x20,
+	0x00, 0x6c, 0xda, 0x24,
+	0xff, 0x65, 0xc8, 0x08,
+	0xe0, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xd6, 0x5b,
+	0xff, 0x90, 0xe2, 0x09,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x04, 0x35, 0xf8, 0x7b,
+	0x1d, 0x6a, 0xdc, 0x01,
+	0xdc, 0xee, 0xf4, 0x63,
+	0x00, 0x65, 0x0e, 0x44,
+	0x01, 0x6a, 0xdc, 0x01,
+	0x20, 0xa0, 0xd8, 0x31,
+	0x09, 0xee, 0xdc, 0x01,
+	0x80, 0xee, 0xfe, 0x7b,
+	0x11, 0x6a, 0xdc, 0x01,
+	0x50, 0xee, 0x02, 0x64,
+	0x20, 0x6a, 0xd0, 0x01,
+	0x09, 0x6a, 0xdc, 0x01,
+	0x88, 0xee, 0x08, 0x64,
+	0x19, 0x6a, 0xdc, 0x01,
+	0xd8, 0xee, 0x0c, 0x64,
+	0xff, 0x6a, 0xdc, 0x09,
+	0x18, 0xee, 0x10, 0x6c,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x88, 0x6a, 0xcc, 0x00,
+	0x41, 0x6a, 0xd6, 0x5b,
+	0x20, 0x6a, 0x18, 0x01,
+	0xff, 0x6a, 0x1a, 0x09,
+	0xff, 0x6a, 0x1c, 0x09,
+	0xff, 0x35, 0x26, 0x09,
+	0x04, 0x35, 0x3c, 0x6c,
+	0xa0, 0x6a, 0xca, 0x00,
+	0x20, 0x65, 0xc8, 0x18,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0xff, 0x6c, 0x32, 0x09,
+	0x00, 0x65, 0x26, 0x64,
+	0x0a, 0x93, 0x26, 0x01,
+	0x00, 0x65, 0x78, 0x44,
+	0xa0, 0x6a, 0xcc, 0x00,
+	0xe8, 0x6a, 0xc8, 0x00,
+	0x01, 0x94, 0x40, 0x6c,
+	0x10, 0x94, 0x42, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x08, 0x94, 0x54, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x00, 0x8c, 0xca, 0x18,
+	0x00, 0x65, 0x4a, 0x4c,
+	0x00, 0x65, 0x40, 0x44,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x56, 0x6c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x08, 0x64, 0xc8, 0x18,
+	0x08, 0x64, 0x58, 0x64,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0x00, 0x65, 0x78, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0x00, 0x65, 0x68, 0x5c,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x08,
+	0xff, 0x99, 0xda, 0x0c,
+	0x08, 0x94, 0x78, 0x7c,
+	0xf7, 0x93, 0x26, 0x09,
+	0x08, 0x93, 0x7c, 0x6c,
+	0xff, 0x6a, 0xd4, 0x0c,
+	0xff, 0x40, 0x74, 0x09,
+	0xff, 0x90, 0x80, 0x08,
+	0xff, 0x6a, 0x72, 0x05,
+	0xff, 0x40, 0x94, 0x64,
+	0xff, 0x3f, 0x8c, 0x64,
+	0xff, 0x6a, 0xca, 0x04,
+	0xff, 0x3f, 0x20, 0x09,
+	0x01, 0x6a, 0x6a, 0x00,
+	0x00, 0xb9, 0xe6, 0x5b,
+	0xff, 0xba, 0x7e, 0x0c,
+	0xff, 0x40, 0x20, 0x09,
+	0xff, 0xba, 0x80, 0x0c,
+	0xff, 0x3f, 0x74, 0x09,
+	0xff, 0x90, 0x7e, 0x0c,
+};
+
+static int aic7xxx_patch15_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch15_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_SCBCHAN_UPLOAD) != 0);
+}
+
+static int aic7xxx_patch14_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch14_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_PCI_2_1_RETRY) != 0);
+}
+
+static int aic7xxx_patch13_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch13_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_WIDE) != 0);
+}
+
+static int aic7xxx_patch12_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch12_func(struct aic7xxx_host *p)
+{
+	return ((p->bugs & AHC_BUG_AUTOFLUSH) != 0);
+}
+
+static int aic7xxx_patch11_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch11_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) == 0);
+}
+
+static int aic7xxx_patch10_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch10_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) == 0);
+}
+
+static int aic7xxx_patch9_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch9_func(struct aic7xxx_host *p)
+{
+	return ((p->chip & AHC_CHIPID_MASK) == AHC_AIC7895);
+}
+
+static int aic7xxx_patch8_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch8_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA) != 0);
+}
+
+static int aic7xxx_patch7_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch7_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_ULTRA2) != 0);
+}
+
+static int aic7xxx_patch6_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch6_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) == 0);
+}
+
+static int aic7xxx_patch5_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch5_func(struct aic7xxx_host *p)
+{
+	return ((p->flags & AHC_PAGESCBS) != 0);
+}
+
+static int aic7xxx_patch4_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch4_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) != 0);
+}
+
+static int aic7xxx_patch3_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch3_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_TWIN) != 0);
+}
+
+static int aic7xxx_patch2_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch2_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_QUEUE_REGS) == 0);
+}
+
+static int aic7xxx_patch1_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch1_func(struct aic7xxx_host *p)
+{
+	return ((p->features & AHC_CMD_CHAN) != 0);
+}
+
+static int aic7xxx_patch0_func(struct aic7xxx_host *p);
+
+static int
+aic7xxx_patch0_func(struct aic7xxx_host *p)
+{
+	return (0);
+}
+
+struct sequencer_patch {
+	int		(*patch_func)(struct aic7xxx_host *);
+	unsigned int	begin	   :10,
+			skip_instr :10,
+			skip_patch :12;
+} sequencer_patches[] = {
+	{ aic7xxx_patch1_func, 3, 2, 1 },
+	{ aic7xxx_patch2_func, 7, 1, 1 },
+	{ aic7xxx_patch2_func, 8, 1, 1 },
+	{ aic7xxx_patch3_func, 11, 4, 1 },
+	{ aic7xxx_patch4_func, 16, 3, 2 },
+	{ aic7xxx_patch0_func, 19, 4, 1 },
+	{ aic7xxx_patch5_func, 23, 1, 1 },
+	{ aic7xxx_patch6_func, 26, 1, 1 },
+	{ aic7xxx_patch1_func, 29, 1, 2 },
+	{ aic7xxx_patch0_func, 30, 3, 1 },
+	{ aic7xxx_patch3_func, 39, 4, 1 },
+	{ aic7xxx_patch7_func, 43, 3, 2 },
+	{ aic7xxx_patch0_func, 46, 3, 1 },
+	{ aic7xxx_patch8_func, 52, 7, 1 },
+	{ aic7xxx_patch3_func, 60, 3, 1 },
+	{ aic7xxx_patch7_func, 63, 2, 1 },
+	{ aic7xxx_patch7_func, 102, 1, 2 },
+	{ aic7xxx_patch0_func, 103, 2, 1 },
+	{ aic7xxx_patch7_func, 107, 2, 1 },
+	{ aic7xxx_patch9_func, 109, 1, 1 },
+	{ aic7xxx_patch10_func, 110, 2, 1 },
+	{ aic7xxx_patch7_func, 113, 1, 2 },
+	{ aic7xxx_patch0_func, 114, 1, 1 },
+	{ aic7xxx_patch1_func, 118, 1, 1 },
+	{ aic7xxx_patch1_func, 121, 3, 3 },
+	{ aic7xxx_patch11_func, 123, 1, 1 },
+	{ aic7xxx_patch0_func, 124, 5, 1 },
+	{ aic7xxx_patch7_func, 132, 1, 1 },
+	{ aic7xxx_patch9_func, 133, 1, 1 },
+	{ aic7xxx_patch10_func, 134, 3, 1 },
+	{ aic7xxx_patch7_func, 137, 3, 2 },
+	{ aic7xxx_patch0_func, 140, 2, 1 },
+	{ aic7xxx_patch7_func, 142, 5, 2 },
+	{ aic7xxx_patch0_func, 147, 3, 1 },
+	{ aic7xxx_patch7_func, 150, 1, 2 },
+	{ aic7xxx_patch0_func, 151, 2, 1 },
+	{ aic7xxx_patch1_func, 153, 15, 4 },
+	{ aic7xxx_patch11_func, 166, 1, 2 },
+	{ aic7xxx_patch0_func, 167, 1, 1 },
+	{ aic7xxx_patch0_func, 168, 10, 1 },
+	{ aic7xxx_patch7_func, 181, 1, 2 },
+	{ aic7xxx_patch0_func, 182, 2, 1 },
+	{ aic7xxx_patch7_func, 184, 18, 1 },
+	{ aic7xxx_patch1_func, 202, 3, 3 },
+	{ aic7xxx_patch7_func, 204, 1, 1 },
+	{ aic7xxx_patch0_func, 205, 4, 1 },
+	{ aic7xxx_patch7_func, 210, 2, 1 },
+	{ aic7xxx_patch7_func, 215, 13, 3 },
+	{ aic7xxx_patch12_func, 218, 1, 1 },
+	{ aic7xxx_patch12_func, 219, 4, 1 },
+	{ aic7xxx_patch1_func, 229, 3, 3 },
+	{ aic7xxx_patch11_func, 231, 1, 1 },
+	{ aic7xxx_patch0_func, 232, 5, 1 },
+	{ aic7xxx_patch11_func, 237, 1, 2 },
+	{ aic7xxx_patch0_func, 238, 9, 1 },
+	{ aic7xxx_patch13_func, 254, 1, 2 },
+	{ aic7xxx_patch0_func, 255, 1, 1 },
+	{ aic7xxx_patch4_func, 316, 1, 2 },
+	{ aic7xxx_patch0_func, 317, 1, 1 },
+	{ aic7xxx_patch2_func, 320, 1, 1 },
+	{ aic7xxx_patch1_func, 330, 3, 2 },
+	{ aic7xxx_patch0_func, 333, 5, 1 },
+	{ aic7xxx_patch13_func, 341, 1, 2 },
+	{ aic7xxx_patch0_func, 342, 1, 1 },
+	{ aic7xxx_patch5_func, 347, 1, 1 },
+	{ aic7xxx_patch11_func, 389, 15, 2 },
+	{ aic7xxx_patch14_func, 402, 1, 1 },
+	{ aic7xxx_patch1_func, 441, 7, 2 },
+	{ aic7xxx_patch0_func, 448, 8, 1 },
+	{ aic7xxx_patch1_func, 457, 4, 2 },
+	{ aic7xxx_patch0_func, 461, 6, 1 },
+	{ aic7xxx_patch1_func, 467, 4, 2 },
+	{ aic7xxx_patch0_func, 471, 3, 1 },
+	{ aic7xxx_patch10_func, 481, 10, 1 },
+	{ aic7xxx_patch1_func, 500, 22, 5 },
+	{ aic7xxx_patch11_func, 508, 4, 1 },
+	{ aic7xxx_patch7_func, 512, 7, 3 },
+	{ aic7xxx_patch15_func, 512, 5, 2 },
+	{ aic7xxx_patch0_func, 517, 2, 1 },
+	{ aic7xxx_patch10_func, 522, 50, 3 },
+	{ aic7xxx_patch14_func, 543, 17, 2 },
+	{ aic7xxx_patch0_func, 560, 4, 1 },
+	{ aic7xxx_patch10_func, 572, 4, 1 },
+	{ aic7xxx_patch5_func, 576, 2, 1 },
+	{ aic7xxx_patch5_func, 579, 9, 1 },
+
+};
diff --git a/drivers/scsi/aic7xxx_old/scsi_message.h b/drivers/scsi/aic7xxx_old/scsi_message.h
new file mode 100644
index 0000000..a79f89c
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/scsi_message.h
@@ -0,0 +1,49 @@
+/* Messages (1 byte) */		     /* I/T (M)andatory or (O)ptional */
+#define MSG_CMDCOMPLETE		0x00 /* M/M */
+#define MSG_EXTENDED		0x01 /* O/O */
+#define MSG_SAVEDATAPOINTER	0x02 /* O/O */
+#define MSG_RESTOREPOINTERS	0x03 /* O/O */
+#define MSG_DISCONNECT		0x04 /* O/O */
+#define MSG_INITIATOR_DET_ERR	0x05 /* M/M */
+#define MSG_ABORT		0x06 /* O/M */
+#define MSG_MESSAGE_REJECT	0x07 /* M/M */
+#define MSG_NOOP		0x08 /* M/M */
+#define MSG_PARITY_ERROR	0x09 /* M/M */
+#define MSG_LINK_CMD_COMPLETE	0x0a /* O/O */
+#define MSG_LINK_CMD_COMPLETEF	0x0b /* O/O */
+#define MSG_BUS_DEV_RESET	0x0c /* O/M */
+#define MSG_ABORT_TAG		0x0d /* O/O */
+#define MSG_CLEAR_QUEUE		0x0e /* O/O */
+#define MSG_INIT_RECOVERY	0x0f /* O/O */
+#define MSG_REL_RECOVERY	0x10 /* O/O */
+#define MSG_TERM_IO_PROC	0x11 /* O/O */
+
+/* Messages (2 byte) */
+#define MSG_SIMPLE_Q_TAG	0x20 /* O/O */
+#define MSG_HEAD_OF_Q_TAG	0x21 /* O/O */
+#define MSG_ORDERED_Q_TAG	0x22 /* O/O */
+#define MSG_IGN_WIDE_RESIDUE	0x23 /* O/O */
+
+/* Identify message */		     /* M/M */	
+#define MSG_IDENTIFYFLAG	0x80 
+#define MSG_IDENTIFY_DISCFLAG	0x40 
+#define MSG_IDENTIFY(lun, disc)	(((disc) ? 0xc0 : MSG_IDENTIFYFLAG) | (lun))
+#define MSG_ISIDENTIFY(m)	((m) & MSG_IDENTIFYFLAG)
+
+/* Extended messages (opcode and length) */
+#define MSG_EXT_SDTR		0x01
+#define MSG_EXT_SDTR_LEN	0x03
+
+#define MSG_EXT_WDTR		0x03
+#define MSG_EXT_WDTR_LEN	0x02
+#define MSG_EXT_WDTR_BUS_8_BIT	0x00
+#define MSG_EXT_WDTR_BUS_16_BIT	0x01
+#define MSG_EXT_WDTR_BUS_32_BIT	0x02
+
+#define MSG_EXT_PPR     0x04
+#define MSG_EXT_PPR_LEN	0x06
+#define MSG_EXT_PPR_OPTION_ST 0x00
+#define MSG_EXT_PPR_OPTION_DT_CRC 0x02
+#define MSG_EXT_PPR_OPTION_DT_UNITS 0x03
+#define MSG_EXT_PPR_OPTION_DT_CRC_QUICK 0x04
+#define MSG_EXT_PPR_OPTION_DT_UNITS_QUICK 0x05
diff --git a/drivers/scsi/aic7xxx_old/sequencer.h b/drivers/scsi/aic7xxx_old/sequencer.h
new file mode 100644
index 0000000..ee66855
--- /dev/null
+++ b/drivers/scsi/aic7xxx_old/sequencer.h
@@ -0,0 +1,135 @@
+/*
+ * Instruction formats for the sequencer program downloaded to
+ * Aic7xxx SCSI host adapters
+ *
+ * Copyright (c) 1997, 1998 Justin T. Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *      $Id: sequencer.h,v 1.3 1997/09/27 19:37:31 gibbs Exp $
+ */
+
+#ifdef __LITTLE_ENDIAN_BITFIELD
+struct ins_format1 {
+	unsigned int
+			immediate	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+};
+
+struct ins_format2 {
+	unsigned int
+			shift_control	: 8,
+			source		: 9,
+			destination	: 9,
+			ret		: 1,
+			opcode		: 4,
+			parity		: 1;
+};
+
+struct ins_format3 {
+	unsigned int
+			immediate	: 8,
+			source		: 9,
+			address		: 10,
+			opcode		: 4,
+			parity		: 1;
+};
+#elif defined(__BIG_ENDIAN_BITFIELD)
+struct ins_format1 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			immediate	: 8;
+};
+
+struct ins_format2 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			ret		: 1,
+			destination	: 9,
+			source		: 9,
+			shift_control	: 8;
+};
+
+struct ins_format3 {
+	unsigned int
+			parity		: 1,
+			opcode		: 4,
+			address		: 10,
+			source		: 9,
+			immediate	: 8;
+};
+#endif
+
+union ins_formats {
+		struct ins_format1 format1;
+		struct ins_format2 format2;
+		struct ins_format3 format3;
+		unsigned char	   bytes[4];
+		unsigned int	   integer;
+};
+struct instruction {
+	union	ins_formats format;
+	unsigned int	srcline;
+	struct symbol *patch_label;
+  struct {
+    struct instruction *stqe_next;
+  } links;
+};
+
+#define	AIC_OP_OR	0x0
+#define	AIC_OP_AND	0x1
+#define AIC_OP_XOR	0x2
+#define	AIC_OP_ADD	0x3
+#define	AIC_OP_ADC	0x4
+#define	AIC_OP_ROL	0x5
+#define	AIC_OP_BMOV	0x6
+
+#define	AIC_OP_JMP	0x8
+#define AIC_OP_JC	0x9
+#define AIC_OP_JNC	0xa
+#define AIC_OP_CALL	0xb
+#define	AIC_OP_JNE	0xc
+#define	AIC_OP_JNZ	0xd
+#define	AIC_OP_JE	0xe
+#define	AIC_OP_JZ	0xf
+
+/* Pseudo Ops */
+#define	AIC_OP_SHL	0x10
+#define	AIC_OP_SHR	0x20
+#define	AIC_OP_ROR	0x30
diff --git a/drivers/scsi/amiga7xx.c b/drivers/scsi/amiga7xx.c
new file mode 100644
index 0000000..5f13546
--- /dev/null
+++ b/drivers/scsi/amiga7xx.c
@@ -0,0 +1,141 @@
+/*
+ * Detection routine for the NCR53c710 based Amiga SCSI Controllers for Linux.
+ *		Amiga MacroSystemUS WarpEngine SCSI controller.
+ *		Amiga Technologies A4000T SCSI controller.
+ *		Amiga Technologies/DKB A4091 SCSI controller.
+ *
+ * Written 1997 by Alan Hourihane <alanh@fairlite.demon.co.uk>
+ * plus modifications of the 53c7xx.c driver to support the Amiga.
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/zorro.h>
+#include <linux/stat.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "53c7xx.h"
+#include "amiga7xx.h"
+
+
+static int amiga7xx_register_one(Scsi_Host_Template *tpnt,
+				 unsigned long address)
+{
+    long long options;
+    int clock;
+
+    if (!request_mem_region(address, 0x1000, "ncr53c710"))
+	return 0;
+
+    address = (unsigned long)z_ioremap(address, 0x1000);
+    options = OPTION_MEMORY_MAPPED | OPTION_DEBUG_TEST1 | OPTION_INTFLY |
+	      OPTION_SYNCHRONOUS | OPTION_ALWAYS_SYNCHRONOUS |
+	      OPTION_DISCONNECT;
+    clock = 50000000;	/* 50 MHz SCSI Clock */
+    ncr53c7xx_init(tpnt, 0, 710, address, 0, IRQ_AMIGA_PORTS, DMA_NONE,
+		   options, clock);
+    return 1;
+}
+
+
+#ifdef CONFIG_ZORRO
+
+static struct {
+    zorro_id id;
+    unsigned long offset;
+    int absolute;	/* offset is absolute address */
+} amiga7xx_table[] = {
+    { .id = ZORRO_PROD_PHASE5_BLIZZARD_603E_PLUS, .offset = 0xf40000,
+      .absolute = 1 },
+    { .id = ZORRO_PROD_MACROSYSTEMS_WARP_ENGINE_40xx, .offset = 0x40000 },
+    { .id = ZORRO_PROD_CBM_A4091_1, .offset = 0x800000 },
+    { .id = ZORRO_PROD_CBM_A4091_2, .offset = 0x800000 },
+    { .id = ZORRO_PROD_GVP_GFORCE_040_060, .offset = 0x40000 },
+    { 0 }
+};
+
+static int __init amiga7xx_zorro_detect(Scsi_Host_Template *tpnt)
+{
+    int num = 0, i;
+    struct zorro_dev *z = NULL;
+    unsigned long address;
+
+    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	for (i = 0; amiga7xx_table[i].id; i++)
+	    if (z->id == amiga7xx_table[i].id)
+		break;
+	if (!amiga7xx_table[i].id)
+	    continue;
+	if (amiga7xx_table[i].absolute)
+	    address = amiga7xx_table[i].offset;
+	else
+	    address = z->resource.start + amiga7xx_table[i].offset;
+	num += amiga7xx_register_one(tpnt, address);
+    }
+    return num;
+}
+
+#endif /* CONFIG_ZORRO */
+
+
+int __init amiga7xx_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    int num = 0;
+
+    if (called || !MACH_IS_AMIGA)
+	return 0;
+
+    tpnt->proc_name = "Amiga7xx";
+
+    if (AMIGAHW_PRESENT(A4000_SCSI))
+	num += amiga7xx_register_one(tpnt, 0xdd0040);
+
+#ifdef CONFIG_ZORRO
+    num += amiga7xx_zorro_detect(tpnt);
+#endif
+
+    called = 1;
+    return num;
+}
+
+static int amiga7xx_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name			= "Amiga NCR53c710 SCSI",
+	.detect			= amiga7xx_detect,
+	.release		= amiga7xx_release,
+	.queuecommand		= NCR53c7xx_queue_command,
+	.abort			= NCR53c7xx_abort,
+	.reset			= NCR53c7xx_reset,
+	.can_queue		= 24,
+	.this_id		= 7,
+	.sg_tablesize		= 63,
+	.cmd_per_lun		= 3,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
new file mode 100644
index 0000000..8cc54a5
--- /dev/null
+++ b/drivers/scsi/amiga7xx.h
@@ -0,0 +1,23 @@
+#ifndef AMIGA7XX_H
+
+#include <linux/types.h>
+
+int amiga7xx_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (struct Scsi_Host *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#include <scsi/scsicam.h>
+
+#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
new file mode 100644
index 0000000..54b3286
--- /dev/null
+++ b/drivers/scsi/arm/Kconfig
@@ -0,0 +1,89 @@
+#
+# SCSI driver configuration for Acorn
+#
+config SCSI_ACORNSCSI_3
+	tristate "Acorn SCSI card (aka30) support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Acorn SCSI card (aka30). If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_ACORNSCSI_TAGGED_QUEUE
+	bool "Support SCSI 2 Tagged queueing"
+	depends on SCSI_ACORNSCSI_3
+	help
+	  Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
+	  This is a feature of SCSI-2 which improves performance: the host
+	  adapter can send several SCSI commands to a device's queue even if
+	  previous commands haven't finished yet. Some SCSI devices don't
+	  implement this properly, so the safe answer is N.
+
+config SCSI_ACORNSCSI_SYNC
+	bool "Support SCSI 2 Synchronous Transfers"
+	depends on SCSI_ACORNSCSI_3
+	help
+	  Say Y here to enable synchronous transfer negotiation with all
+	  targets on the Acorn SCSI card.
+
+	  In general, this improves performance; however some SCSI devices
+	  don't implement it properly, so the safe answer is N.
+
+config SCSI_ARXESCSI
+	tristate "ARXE SCSI support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  Around 1991, Arxe Systems Limited released a high density floppy
+	  disc interface for the Acorn Archimedes range, to allow the use of
+	  HD discs from the then new A5000 on earlier models. This interface
+	  was either sold on its own or with an integral SCSI controller.
+	  Technical details on this NCR53c94-based device are available at
+	  <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html>
+	  Say Y here to compile in support for the SCSI controller.
+
+config SCSI_CUMANA_2
+	tristate "CumanaSCSI II support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Cumana SCSI II card. If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_EESOXSCSI
+	tristate "EESOX support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the EESOX SCSI card. If you have an Acorn
+	  system with one of these, say Y, otherwise say N.
+
+config SCSI_POWERTECSCSI
+	tristate "PowerTec support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Powertec SCSI card on Acorn systems. If
+	  you have one of these, say Y. If unsure, say N.
+
+comment "The following drivers are not fully supported"
+	depends on ARCH_ACORN && EXPERIMENTAL
+
+config SCSI_CUMANA_1
+	tristate "CumanaSCSI I support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+	help
+	  This enables support for the Cumana SCSI I card. If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_ECOSCSI
+	tristate "EcoScsi support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
+	help
+	  This enables support for the EcoSCSI card -- a small card that sits
+	  in the Econet socket. If you have an Acorn system with one of these,
+	  say Y. If unsure, say N.
+
+config SCSI_OAK1
+	tristate "Oak SCSI support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+	help
+	  This enables support for the Oak SCSI card. If you have an Acorn
+	  system with one of these, say Y. If unsure, say N.
+
diff --git a/drivers/scsi/arm/Makefile b/drivers/scsi/arm/Makefile
new file mode 100644
index 0000000..e8db179
--- /dev/null
+++ b/drivers/scsi/arm/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for drivers/scsi/arm
+#
+
+acornscsi_mod-objs	:= acornscsi.o acornscsi-io.o
+
+obj-$(CONFIG_SCSI_ACORNSCSI_3)	+= acornscsi_mod.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_ARXESCSI)	+= arxescsi.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_CUMANA_1)	+= cumana_1.o
+obj-$(CONFIG_SCSI_CUMANA_2)	+= cumana_2.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_ECOSCSI)	+= ecoscsi.o
+obj-$(CONFIG_SCSI_OAK1)		+= oak.o
+obj-$(CONFIG_SCSI_POWERTECSCSI)	+= powertec.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_EESOXSCSI)	+= eesox.o fas216.o queue.o msgqueue.o
diff --git a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S
new file mode 100644
index 0000000..93467e6
--- /dev/null
+++ b/drivers/scsi/arm/acornscsi-io.S
@@ -0,0 +1,145 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+#if (IO_BASE == (PCIO_BASE & 0xff000000))
+#define ADDR(off,reg)						\
+		tst	off, $0x80000000			;\
+		mov	reg, $IO_BASE				;\
+		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
+#else
+#define ADDR(off,reg)						\
+		tst	off, $0x80000000			;\
+		movne	reg, $IO_BASE				;\
+		moveq	reg, $(PCIO_BASE & 0xff000000)		;\
+		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
+#endif
+
+@ Purpose: transfer a block of data from the acorn scsi card to memory
+@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
+@ Returns: nothing
+
+		.align
+ENTRY(__acornscsi_in)
+		stmfd	sp!, {r4 - r7, lr}
+		bic	r0, r0, #3
+		mov	lr, #0xff
+		orr	lr, lr, #0xff00
+acornscsi_in16lp:
+		subs	r2, r2, #16
+		bmi	acornscsi_in8
+		ldmia	r0!, {r3, r4, r5, r6}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		and 	r4, r5, lr
+		orr	r4, r4, r6, lsl #16
+		ldmia	r0!, {r5, r6, r7, ip}
+		and	r5, r5, lr
+		orr	r5, r5, r6, lsl #16
+		and	r6, r7, lr
+		orr	r6, r6, ip, lsl #16
+		stmia	r1!, {r3 - r6}
+		bne	acornscsi_in16lp
+		LOADREGS(fd, sp!, {r4 - r7, pc})
+
+acornscsi_in8:	adds	r2, r2, #8
+		bmi	acornscsi_in4
+		ldmia	r0!, {r3, r4, r5, r6}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		and	r4, r5, lr
+		orr	r4, r4, r6, lsl #16
+		stmia	r1!, {r3 - r4}
+		LOADREGS(eqfd, sp!, {r4 - r7, pc})
+		sub	r2, r2, #8
+
+acornscsi_in4:	adds	r2, r2, #4
+		bmi	acornscsi_in2
+		ldmia	r0!, {r3, r4}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		str	r3, [r1], #4
+		LOADREGS(eqfd, sp!, {r4 - r7, pc})
+		sub	r2, r2, #4
+
+acornscsi_in2:	adds	r2, r2, #2
+		ldr	r3, [r0], #4
+		and	r3, r3, lr
+		strb	r3, [r1], #1
+		mov	r3, r3, lsr #8
+		strplb	r3, [r1], #1
+		LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@ Purpose: transfer a block of data from memory to the acorn scsi card
+@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
+@ Returns: nothing
+
+ENTRY(__acornscsi_out)
+		stmfd	sp!, {r4 - r6, lr}
+		bic	r0, r0, #3
+acornscsi_out16lp:
+		subs	r2, r2, #16
+		bmi	acornscsi_out8
+		ldmia	r1!, {r4, r6, ip, lr}
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	r5, r6, lsl #16
+		orr	r5, r5, r5, lsr #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r6, lsl #16
+		stmia	r0!, {r3, r4, r5, r6}
+		mov	r3, ip, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, ip, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	ip, lr, lsl #16
+		orr	ip, ip, ip, lsr #16
+		mov	lr, lr, lsr #16
+		orr	lr, lr, lr, lsl #16
+		stmia	r0!, {r3, r4, ip, lr}
+		bne	acornscsi_out16lp
+		LOADREGS(fd, sp!, {r4 - r6, pc})
+
+acornscsi_out8:	adds	r2, r2, #8
+		bmi	acornscsi_out4
+		ldmia	r1!, {r4, r6}
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	r5, r6, lsl #16
+		orr	r5, r5, r5, lsr #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r6, lsl #16
+		stmia	r0!, {r3, r4, r5, r6}
+		LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+		sub	r2, r2, #8
+acornscsi_out4:	adds	r2, r2, #4
+		bmi	acornscsi_out2
+		ldr	r4, [r1], #4
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		stmia	r0!, {r3, r4}
+		LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+		sub	r2, r2, #4
+acornscsi_out2:	adds	r2, r2, #2
+		ldr	r3, [r1], #2
+		strb	r3, [r0], #1
+		mov	r3, r3, lsr #8
+		strplb	r3, [r0], #1
+		LOADREGS(fd, sp!, {r4 - r6, pc})
+
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
new file mode 100644
index 0000000..24dd0b8
--- /dev/null
+++ b/drivers/scsi/arm/acornscsi.c
@@ -0,0 +1,3130 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi.c
+ *
+ *  Acorn SCSI 3 driver
+ *  By R.M.King.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Abandoned using the Select and Transfer command since there were
+ * some nasty races between our software and the target devices that
+ * were not easy to solve, and the device errata had a lot of entries
+ * for this command, some of them quite nasty...
+ *
+ * Changelog:
+ *  26-Sep-1997	RMK	Re-jigged to use the queue module.
+ *			Re-coded state machine to be based on driver
+ *			state not scsi state.  Should be easier to debug.
+ *			Added acornscsi_release to clean up properly.
+ *			Updated proc/scsi reporting.
+ *  05-Oct-1997	RMK	Implemented writing to SCSI devices.
+ *  06-Oct-1997	RMK	Corrected small (non-serious) bug with the connect/
+ *			reconnect race condition causing a warning message.
+ *  12-Oct-1997	RMK	Added catch for re-entering interrupt routine.
+ *  15-Oct-1997	RMK	Improved handling of commands.
+ *  27-Jun-1998	RMK	Changed asm/delay.h to linux/delay.h.
+ *  13-Dec-1998	RMK	Better abort code and command handling.  Extra state
+ *			transitions added to allow dodgy devices to work.
+ */
+#define DEBUG_NO_WRITE	1
+#define DEBUG_QUEUES	2
+#define DEBUG_DMA	4
+#define DEBUG_ABORT	8
+#define DEBUG_DISCON	16
+#define DEBUG_CONNECT	32
+#define DEBUG_PHASES	64
+#define DEBUG_WRITE	128
+#define DEBUG_LINK	256
+#define DEBUG_MESSAGES	512
+#define DEBUG_RESET	1024
+#define DEBUG_ALL	(DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
+			 DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
+			 DEBUG_DMA|DEBUG_QUEUES)
+
+/* DRIVER CONFIGURATION
+ *
+ * SCSI-II Tagged queue support.
+ *
+ * I don't have any SCSI devices that support it, so it is totally untested
+ * (except to make sure that it doesn't interfere with any non-tagging
+ * devices).  It is not fully implemented either - what happens when a
+ * tagging device reconnects???
+ *
+ * You can tell if you have a device that supports tagged queueing my
+ * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported
+ * as '2 TAG'.
+ *
+ * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config
+ * scripts, but disabled here.  Once debugged, remove the #undef, otherwise to debug,
+ * comment out the undef.
+ */
+#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+/*
+ * SCSI-II Linked command support.
+ *
+ * The higher level code doesn't support linked commands yet, and so the option
+ * is undef'd here.
+ */
+#undef CONFIG_SCSI_ACORNSCSI_LINK
+/*
+ * SCSI-II Synchronous transfer support.
+ *
+ * Tried and tested...
+ *
+ * SDTR_SIZE	  - maximum number of un-acknowledged bytes (0 = off, 12 = max)
+ * SDTR_PERIOD	  - period of REQ signal (min=125, max=1020)
+ * DEFAULT_PERIOD - default REQ period.
+ */
+#define SDTR_SIZE	12
+#define SDTR_PERIOD	125
+#define DEFAULT_PERIOD	500
+
+/*
+ * Debugging information
+ *
+ * DEBUG	  - bit mask from list above
+ * DEBUG_TARGET   - is defined to the target number if you want to debug
+ *		    a specific target. [only recon/write/dma].
+ */
+#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE)
+/* only allow writing to SCSI device 0 */
+#define NO_WRITE 0xFE
+/*#define DEBUG_TARGET 2*/
+/*
+ * Select timeout time (in 10ms units)
+ *
+ * This is the timeout used between the start of selection and the WD33C93
+ * chip deciding that the device isn't responding.
+ */
+#define TIMEOUT_TIME 10
+/*
+ * Define this if you want to have verbose explaination of SCSI
+ * status/messages.
+ */
+#undef CONFIG_ACORNSCSI_CONSTANTS
+/*
+ * Define this if you want to use the on board DMAC [don't remove this option]
+ * If not set, then use PIO mode (not currently supported).
+ */
+#define USE_DMAC
+
+/*
+ * ====================================================================================
+ */
+
+#ifdef DEBUG_TARGET
+#define DBG(cmd,xxx...) \
+  if (cmd->device->id == DEBUG_TARGET) { \
+    xxx; \
+  }
+#else
+#define DBG(cmd,xxx...) xxx
+#endif
+
+#ifndef STRINGIFY
+#define STRINGIFY(x) #x
+#endif
+#define STRx(x) STRINGIFY(x)
+#define NO_WRITE_STR STRx(NO_WRITE)
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/bitops.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "acornscsi.h"
+#include "msgqueue.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define VER_MAJOR 2
+#define VER_MINOR 0
+#define VER_PATCH 6
+
+#ifndef ABORT_TAG
+#define ABORT_TAG 0xd
+#else
+#error "Yippee!  ABORT TAG is now defined!  Remove this error!"
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+#error SCSI2 LINKed commands not supported (yet)!
+#endif
+
+#ifdef USE_DMAC
+/*
+ * DMAC setup parameters
+ */ 
+#define INIT_DEVCON0	(DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)
+#define INIT_DEVCON1	(DEVCON1_BHLD)
+#define DMAC_READ	(MODECON_READ)
+#define DMAC_WRITE	(MODECON_WRITE)
+#define INIT_SBICDMA	(CTRL_DMABURST)
+
+#define scsi_xferred	have_data_in
+
+/*
+ * Size of on-board DMA buffer
+ */
+#define DMAC_BUFFER_SIZE	65536
+#endif
+
+#define STATUS_BUFFER_TO_PRINT	24
+
+unsigned int sdtr_period = SDTR_PERIOD;
+unsigned int sdtr_size   = SDTR_SIZE;
+
+static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static int acornscsi_reconnect_finish(AS_Host *host);
+static void acornscsi_dma_cleanup(AS_Host *host);
+static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
+
+/* ====================================================================================
+ * Miscellaneous
+ */
+
+static inline void
+sbic_arm_write(unsigned int io_port, int reg, int value)
+{
+    __raw_writeb(reg, io_port);
+    __raw_writeb(value, io_port + 4);
+}
+
+#define sbic_arm_writenext(io,val) \
+	__raw_writeb((val), (io) + 4)
+
+static inline
+int sbic_arm_read(unsigned int io_port, int reg)
+{
+    if(reg == SBIC_ASR)
+	   return __raw_readl(io_port) & 255;
+    __raw_writeb(reg, io_port);
+    return __raw_readl(io_port + 4) & 255;
+}
+
+#define sbic_arm_readnext(io) \
+	__raw_readb((io) + 4)
+
+#ifdef USE_DMAC
+#define dmac_read(io_port,reg) \
+	inb((io_port) + (reg))
+
+#define dmac_write(io_port,reg,value) \
+	({ outb((value), (io_port) + (reg)); })
+
+#define dmac_clearintr(io_port) \
+	({ outb(0, (io_port)); })
+
+static inline
+unsigned int dmac_address(unsigned int io_port)
+{
+    return dmac_read(io_port, DMAC_TXADRHI) << 16 |
+	   dmac_read(io_port, DMAC_TXADRMD) << 8 |
+	   dmac_read(io_port, DMAC_TXADRLO);
+}
+
+static
+void acornscsi_dumpdma(AS_Host *host, char *where)
+{
+	unsigned int mode, addr, len;
+
+	mode = dmac_read(host->dma.io_port, DMAC_MODECON);
+	addr = dmac_address(host->dma.io_port);
+	len  = dmac_read(host->dma.io_port, DMAC_TXCNTHI) << 8 |
+	       dmac_read(host->dma.io_port, DMAC_TXCNTLO);
+
+	printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
+		host->host->host_no, where,
+		mode, addr, (len + 1) & 0xffff,
+		dmac_read(host->dma.io_port, DMAC_MASKREG));
+
+	printk("DMA @%06x, ", host->dma.start_addr);
+	printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
+		host->scsi.SCp.this_residual);
+	printk("DT @+%04x ST @+%04x", host->dma.transferred,
+		host->scsi.SCp.scsi_xferred);
+	printk("\n");
+}
+#endif
+
+static
+unsigned long acornscsi_sbic_xfcount(AS_Host *host)
+{
+    unsigned long length;
+
+    length = sbic_arm_read(host->scsi.io_port, SBIC_TRANSCNTH) << 16;
+    length |= sbic_arm_readnext(host->scsi.io_port) << 8;
+    length |= sbic_arm_readnext(host->scsi.io_port);
+
+    return length;
+}
+
+static int
+acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
+{
+	int asr;
+
+	do {
+		asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+
+		if ((asr & stat_mask) == stat)
+			return 0;
+
+		udelay(1);
+	} while (--timeout);
+
+	printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
+
+	return -1;
+}
+
+static
+int acornscsi_sbic_issuecmd(AS_Host *host, int command)
+{
+    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
+	return -1;
+
+    sbic_arm_write(host->scsi.io_port, SBIC_CMND, command);
+
+    return 0;
+}
+
+static void
+acornscsi_csdelay(unsigned int cs)
+{
+    unsigned long target_jiffies, flags;
+
+    target_jiffies = jiffies + 1 + cs * HZ / 100;
+
+    local_save_flags(flags);
+    local_irq_enable();
+
+    while (time_before(jiffies, target_jiffies)) barrier();
+
+    local_irq_restore(flags);
+}
+
+static
+void acornscsi_resetcard(AS_Host *host)
+{
+    unsigned int i, timeout;
+
+    /* assert reset line */
+    host->card.page_reg = 0x80;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /* wait 3 cs.  SCSI standard says 25ms. */
+    acornscsi_csdelay(3);
+
+    host->card.page_reg = 0;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /*
+     * Should get a reset from the card
+     */
+    timeout = 1000;
+    do {
+	if (inb(host->card.io_intr) & 8)
+	    break;
+	udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+	printk("scsi%d: timeout while resetting card\n",
+		host->host->host_no);
+
+    sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+    sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+
+    /* setup sbic - WD33C93A */
+    sbic_arm_write(host->scsi.io_port, SBIC_OWNID, OWNID_EAF | host->host->this_id);
+    sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_RESET);
+
+    /*
+     * Command should cause a reset interrupt
+     */
+    timeout = 1000;
+    do {
+	if (inb(host->card.io_intr) & 8)
+	    break;
+	udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+	printk("scsi%d: timeout while resetting card\n",
+		host->host->host_no);
+
+    sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+    if (sbic_arm_read(host->scsi.io_port, SBIC_SSR) != 0x01)
+	printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+		host->host->host_no);
+
+    sbic_arm_write(host->scsi.io_port, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI);
+    sbic_arm_write(host->scsi.io_port, SBIC_TIMEOUT, TIMEOUT_TIME);
+    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+    sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+
+    host->card.page_reg = 0x40;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /* setup dmac - uPC71071 */
+    dmac_write(host->dma.io_port, DMAC_INIT, 0);
+#ifdef USE_DMAC
+    dmac_write(host->dma.io_port, DMAC_INIT, INIT_8BIT);
+    dmac_write(host->dma.io_port, DMAC_CHANNEL, CHANNEL_0);
+    dmac_write(host->dma.io_port, DMAC_DEVCON0, INIT_DEVCON0);
+    dmac_write(host->dma.io_port, DMAC_DEVCON1, INIT_DEVCON1);
+#endif
+
+    host->SCpnt = NULL;
+    host->scsi.phase = PHASE_IDLE;
+    host->scsi.disconnectable = 0;
+
+    memset(host->busyluns, 0, sizeof(host->busyluns));
+
+    for (i = 0; i < 8; i++) {
+	host->device[i].sync_state = SYNC_NEGOCIATE;
+	host->device[i].disconnect_ok = 1;
+    }
+
+    /* wait 25 cs.  SCSI standard says 250ms. */
+    acornscsi_csdelay(25);
+}
+
+/*=============================================================================================
+ * Utility routines (eg. debug)
+ */
+#ifdef CONFIG_ACORNSCSI_CONSTANTS
+static char *acornscsi_interrupttype[] = {
+  "rst",  "suc",  "p/a",  "3",
+  "term", "5",	  "6",	  "7",
+  "serv", "9",	  "a",	  "b",
+  "c",	  "d",	  "e",	  "f"
+};
+
+static signed char acornscsi_map[] = {
+  0,  1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1,  2, -1, -1,  -1, -1,  3, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ 12, 13, 14, -1,  -1, -1, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ 15, 16, 17, 18,  19, -1, -1, 20,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ 21, 22, -1, -1,  -1, 23, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1
+};      
+
+static char *acornscsi_interruptcode[] = {
+    /* 0 */
+    "reset - normal mode",	/* 00 */
+    "reset - advanced mode",	/* 01 */
+
+    /* 2 */
+    "sel",			/* 11 */
+    "sel+xfer", 		/* 16 */
+    "data-out", 		/* 18 */
+    "data-in",			/* 19 */
+    "cmd",			/* 1A */
+    "stat",			/* 1B */
+    "??-out",			/* 1C */
+    "??-in",			/* 1D */
+    "msg-out",			/* 1E */
+    "msg-in",			/* 1F */
+
+    /* 12 */
+    "/ACK asserted",		/* 20 */
+    "save-data-ptr",		/* 21 */
+    "{re}sel",			/* 22 */
+
+    /* 15 */
+    "inv cmd",			/* 40 */
+    "unexpected disconnect",	/* 41 */
+    "sel timeout",		/* 42 */
+    "P err",			/* 43 */
+    "P err+ATN",		/* 44 */
+    "bad status byte",		/* 47 */
+
+    /* 21 */
+    "resel, no id",		/* 80 */
+    "resel",			/* 81 */
+    "discon",			/* 85 */
+};
+
+static
+void print_scsi_status(unsigned int ssr)
+{
+    if (acornscsi_map[ssr] != -1)
+	printk("%s:%s",
+		acornscsi_interrupttype[(ssr >> 4)],
+		acornscsi_interruptcode[acornscsi_map[ssr]]);
+    else
+	printk("%X:%X", ssr >> 4, ssr & 0x0f);    
+}    
+#endif
+
+static
+void print_sbic_status(int asr, int ssr, int cmdphase)
+{
+#ifdef CONFIG_ACORNSCSI_CONSTANTS
+    printk("sbic: %c%c%c%c%c%c ",
+	    asr & ASR_INT ? 'I' : 'i',
+	    asr & ASR_LCI ? 'L' : 'l',
+	    asr & ASR_BSY ? 'B' : 'b',
+	    asr & ASR_CIP ? 'C' : 'c',
+	    asr & ASR_PE  ? 'P' : 'p',
+	    asr & ASR_DBR ? 'D' : 'd');
+    printk("scsi: ");
+    print_scsi_status(ssr);
+    printk(" ph %02X\n", cmdphase);
+#else
+    printk("sbic: %02X scsi: %X:%X ph: %02X\n",
+	    asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
+#endif
+}
+
+static void
+acornscsi_dumplogline(AS_Host *host, int target, int line)
+{
+	unsigned long prev;
+	signed int ptr;
+
+	ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
+	if (ptr < 0)
+		ptr += STATUS_BUFFER_SIZE;
+
+	printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
+		line == 0 ? "ph" : line == 1 ? "ssr" : "int");
+
+	prev = host->status[target][ptr].when;
+
+	for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+		unsigned long time_diff;
+
+		if (!host->status[target][ptr].when)
+			continue;
+
+		switch (line) {
+		case 0:
+			printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
+					 host->status[target][ptr].ph);
+			break;
+
+		case 1:
+			printk(" %02X", host->status[target][ptr].ssr);
+			break;
+
+		case 2:
+			time_diff = host->status[target][ptr].when - prev;
+			prev = host->status[target][ptr].when;
+			if (time_diff == 0)
+				printk("==^");
+			else if (time_diff >= 100)
+				printk("   ");
+			else
+				printk(" %02ld", time_diff);
+			break;
+		}
+	}
+
+	printk("\n");
+}
+
+static
+void acornscsi_dumplog(AS_Host *host, int target)
+{
+    do {
+	acornscsi_dumplogline(host, target, 0);
+	acornscsi_dumplogline(host, target, 1);
+	acornscsi_dumplogline(host, target, 2);
+
+	if (target == 8)
+	    break;
+
+	target = 8;
+    } while (1);
+}
+
+static
+char acornscsi_target(AS_Host *host)
+{
+	if (host->SCpnt)
+		return '0' + host->SCpnt->device->id;
+	return 'H';
+}
+
+/*
+ * Prototype: cmdtype_t acornscsi_cmdtype(int command)
+ * Purpose  : differentiate READ from WRITE from other commands
+ * Params   : command - command to interpret
+ * Returns  : CMD_READ	- command reads data,
+ *	      CMD_WRITE - command writes data,
+ *	      CMD_MISC	- everything else
+ */
+static inline
+cmdtype_t acornscsi_cmdtype(int command)
+{
+    switch (command) {
+    case WRITE_6:  case WRITE_10:  case WRITE_12:
+	return CMD_WRITE;
+    case READ_6:   case READ_10:   case READ_12:
+	return CMD_READ;
+    default:
+	return CMD_MISC;
+    }
+}
+
+/*
+ * Prototype: int acornscsi_datadirection(int command)
+ * Purpose  : differentiate between commands that have a DATA IN phase
+ *	      and a DATA OUT phase
+ * Params   : command - command to interpret
+ * Returns  : DATADIR_OUT - data out phase expected
+ *	      DATADIR_IN  - data in phase expected
+ */
+static
+datadir_t acornscsi_datadirection(int command)
+{
+    switch (command) {
+    case CHANGE_DEFINITION:	case COMPARE:		case COPY:
+    case COPY_VERIFY:		case LOG_SELECT:	case MODE_SELECT:
+    case MODE_SELECT_10:	case SEND_DIAGNOSTIC:	case WRITE_BUFFER:
+    case FORMAT_UNIT:		case REASSIGN_BLOCKS:	case RESERVE:
+    case SEARCH_EQUAL:		case SEARCH_HIGH:	case SEARCH_LOW:
+    case WRITE_6:		case WRITE_10:		case WRITE_VERIFY:
+    case UPDATE_BLOCK:		case WRITE_LONG:	case WRITE_SAME:
+    case SEARCH_HIGH_12:	case SEARCH_EQUAL_12:	case SEARCH_LOW_12:
+    case WRITE_12:		case WRITE_VERIFY_12:	case SET_WINDOW:
+    case MEDIUM_SCAN:		case SEND_VOLUME_TAG:	case 0xea:
+	return DATADIR_OUT;
+    default:
+	return DATADIR_IN;
+    }
+}
+
+/*
+ * Purpose  : provide values for synchronous transfers with 33C93.
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *	Modified by Russell King for 8MHz WD33C93A
+ */
+static struct sync_xfer_tbl {
+    unsigned int period_ns;
+    unsigned char reg_value;
+} sync_xfer_table[] = {
+    {	1, 0x20 },    { 249, 0x20 },	{ 374, 0x30 },
+    { 499, 0x40 },    { 624, 0x50 },	{ 749, 0x60 },
+    { 874, 0x70 },    { 999, 0x00 },	{   0,	  0 }
+};
+
+/*
+ * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
+ * Purpose  : period for the synchronous transfer setting
+ * Params   : syncxfer SYNCXFER register value
+ * Returns  : period in ns.
+ */
+static
+int acornscsi_getperiod(unsigned char syncxfer)
+{
+    int i;
+
+    syncxfer &= 0xf0;
+    if (syncxfer == 0x10)
+	syncxfer = 0;
+
+    for (i = 1; sync_xfer_table[i].period_ns; i++)
+	if (syncxfer == sync_xfer_table[i].reg_value)
+	    return sync_xfer_table[i].period_ns;
+    return 0;
+}
+
+/*
+ * Prototype: int round_period(unsigned int period)
+ * Purpose  : return index into above table for a required REQ period
+ * Params   : period - time (ns) for REQ
+ * Returns  : table index
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ */
+static inline
+int round_period(unsigned int period)
+{
+    int i;
+
+    for (i = 1; sync_xfer_table[i].period_ns; i++) {
+	if ((period <= sync_xfer_table[i].period_ns) &&
+	    (period > sync_xfer_table[i - 1].period_ns))
+	    return i;
+    }
+    return 7;
+}
+
+/*
+ * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+ * Purpose  : calculate value for 33c93s SYNC register
+ * Params   : period - time (ns) for REQ
+ *	      offset - offset in bytes between REQ/ACK
+ * Returns  : value for SYNC register
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ */
+static
+unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+    return sync_xfer_table[round_period(period)].reg_value |
+		((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
+}
+
+/* ====================================================================================
+ * Command functions
+ */
+/*
+ * Function: acornscsi_kick(AS_Host *host)
+ * Purpose : kick next command to interface
+ * Params  : host - host to send command to
+ * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
+ * Notes   : interrupts are always disabled!
+ */
+static
+intr_ret_t acornscsi_kick(AS_Host *host)
+{
+    int from_queue = 0;
+    Scsi_Cmnd *SCpnt;
+
+    /* first check to see if a command is waiting to be executed */
+    SCpnt = host->origSCpnt;
+    host->origSCpnt = NULL;
+
+    /* retrieve next command */
+    if (!SCpnt) {
+	SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
+	if (!SCpnt)
+	    return INTR_IDLE;
+
+	from_queue = 1;
+    }
+
+    if (host->scsi.disconnectable && host->SCpnt) {
+	queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+	host->scsi.disconnectable = 0;
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
+		host->host->host_no, acornscsi_target(host)));
+#endif
+	host->SCpnt = NULL;
+    }
+
+    /*
+     * If we have an interrupt pending, then we may have been reselected.
+     * In this case, we don't want to write to the registers
+     */
+    if (!(sbic_arm_read(host->scsi.io_port, SBIC_ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
+	sbic_arm_write(host->scsi.io_port, SBIC_DESTID, SCpnt->device->id);
+	sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_SELWITHATN);
+    }
+
+    /*
+     * claim host busy - all of these must happen atomically wrt
+     * our interrupt routine.  Failure means command loss.
+     */
+    host->scsi.phase = PHASE_CONNECTING;
+    host->SCpnt = SCpnt;
+    host->scsi.SCp = SCpnt->SCp;
+    host->dma.xfer_setup = 0;
+    host->dma.xfer_required = 0;
+    host->dma.xfer_done = 0;
+
+#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
+    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
+	    host->host->host_no, '0' + SCpnt->device->id,
+	    SCpnt->cmnd[0]));
+#endif
+
+    if (from_queue) {
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+	/*
+	 * tagged queueing - allocate a new tag to this command
+	 */
+	if (SCpnt->device->simple_tags) {
+	    SCpnt->device->current_tag += 1;
+	    if (SCpnt->device->current_tag == 0)
+		SCpnt->device->current_tag = 1;
+	    SCpnt->tag = SCpnt->device->current_tag;
+	} else
+#endif
+	    set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	host->stats.removes += 1;
+
+	switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
+	case CMD_WRITE:
+	    host->stats.writes += 1;
+	    break;
+	case CMD_READ:
+	    host->stats.reads += 1;
+	    break;
+	case CMD_MISC:
+	    host->stats.miscs += 1;
+	    break;
+	}
+    }
+
+    return INTR_PROCESSING;
+}    
+
+/*
+ * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Purpose : complete processing for command
+ * Params  : host   - interface that completed
+ *	     result - driver byte of result
+ */
+static
+void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+{
+    Scsi_Cmnd *SCpnt = *SCpntp;
+
+    /* clean up */
+    sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+
+    host->stats.fins += 1;
+
+    if (SCpnt) {
+	*SCpntp = NULL;
+
+	acornscsi_dma_cleanup(host);
+
+	SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
+
+	/*
+	 * In theory, this should not happen.  In practice, it seems to.
+	 * Only trigger an error if the device attempts to report all happy
+	 * but with untransferred buffers...  If we don't do something, then
+	 * data loss will occur.  Should we check SCpnt->underflow here?
+	 * It doesn't appear to be set to something meaningful by the higher
+	 * levels all the time.
+	 */
+	if (result == DID_OK) {
+		int xfer_warn = 0;
+
+		if (SCpnt->underflow == 0) {
+			if (host->scsi.SCp.ptr &&
+			    acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
+				xfer_warn = 1;
+		} else {
+			if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
+			    host->scsi.SCp.scsi_xferred != host->dma.transferred)
+				xfer_warn = 1;
+		}
+
+		/* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
+		 *  Targets which break data transfers into multiple
+		 *  connections shall end each successful connection
+		 *  (except possibly the last) with a SAVE DATA
+		 *  POINTER - DISCONNECT message sequence.
+		 *
+		 * This makes it difficult to ensure that a transfer has
+		 * completed.  If we reach the end of a transfer during
+		 * the command, then we can only have finished the transfer.
+		 * therefore, if we seem to have some data remaining, this
+		 * is not a problem.
+		 */
+		if (host->dma.xfer_done)
+			xfer_warn = 0;
+
+		if (xfer_warn) {
+		    switch (status_byte(SCpnt->result)) {
+		    case CHECK_CONDITION:
+		    case COMMAND_TERMINATED:
+		    case BUSY:
+		    case QUEUE_FULL:
+		    case RESERVATION_CONFLICT:
+			break;
+
+		    default:
+			printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
+				host->host->host_no, SCpnt->result);
+			print_command(SCpnt->cmnd);
+			acornscsi_dumpdma(host, "done");
+		 	acornscsi_dumplog(host, SCpnt->device->id);
+			SCpnt->result &= 0xffff;
+			SCpnt->result |= DID_ERROR << 16;
+		    }
+		}
+	}
+
+	if (!SCpnt->scsi_done)
+	    panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
+
+	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	SCpnt->scsi_done(SCpnt);
+    } else
+	printk("scsi%d: null command in acornscsi_done", host->host->host_no);
+
+    host->scsi.phase = PHASE_IDLE;
+}
+
+/* ====================================================================================
+ * DMA routines
+ */
+/*
+ * Purpose  : update SCSI Data Pointer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
+{
+    SCp->ptr += length;
+    SCp->this_residual -= length;
+
+    if (SCp->this_residual == 0 && next_SCp(SCp) == 0)
+	host->dma.xfer_done = 1;
+}
+
+/*
+ * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
+ *				unsigned int start_addr, unsigned int length)
+ * Purpose  : read data from DMA RAM
+ * Params   : host - host to transfer from
+ *	      ptr  - DRAM address
+ *	      start_addr - host mem address
+ *	      length - number of bytes to transfer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_read(AS_Host *host, char *ptr,
+				 unsigned int start_addr, unsigned int length)
+{
+    extern void __acornscsi_in(int port, char *buf, int len);
+    unsigned int page, offset, len = length;
+
+    page = (start_addr >> 12);
+    offset = start_addr & ((1 << 12) - 1);
+
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+
+    while (len > 0) {
+	unsigned int this_len;
+
+	if (len + offset > (1 << 12))
+	    this_len = (1 << 12) - offset;
+	else
+	    this_len = len;
+
+	__acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
+
+	offset += this_len;
+	ptr += this_len;
+	len -= this_len;
+
+	if (offset == (1 << 12)) {
+	    offset = 0;
+	    page ++;
+	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+	}
+    }
+    outb(host->card.page_reg, host->card.io_page);
+}
+
+/*
+ * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
+ *				unsigned int start_addr, unsigned int length)
+ * Purpose  : write data to DMA RAM
+ * Params   : host - host to transfer from
+ *	      ptr  - DRAM address
+ *	      start_addr - host mem address
+ *	      length - number of bytes to transfer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_write(AS_Host *host, char *ptr,
+				 unsigned int start_addr, unsigned int length)
+{
+    extern void __acornscsi_out(int port, char *buf, int len);
+    unsigned int page, offset, len = length;
+
+    page = (start_addr >> 12);
+    offset = start_addr & ((1 << 12) - 1);
+
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+
+    while (len > 0) {
+	unsigned int this_len;
+
+	if (len + offset > (1 << 12))
+	    this_len = (1 << 12) - offset;
+	else
+	    this_len = len;
+
+	__acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
+
+	offset += this_len;
+	ptr += this_len;
+	len -= this_len;
+
+	if (offset == (1 << 12)) {
+	    offset = 0;
+	    page ++;
+	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+	}
+    }
+    outb(host->card.page_reg, host->card.io_page);
+}
+
+/* =========================================================================================
+ * On-board DMA routines
+ */
+#ifdef USE_DMAC
+/*
+ * Prototype: void acornscsi_dmastop(AS_Host *host)
+ * Purpose  : stop all DMA
+ * Params   : host - host on which to stop DMA
+ * Notes    : This is called when leaving DATA IN/OUT phase,
+ *	      or when interface is RESET
+ */
+static inline
+void acornscsi_dma_stop(AS_Host *host)
+{
+    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+#if (DEBUG & DEBUG_DMA)
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
+#endif
+}
+
+/*
+ * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
+ * Purpose : setup DMA controller for data transfer
+ * Params  : host - host to setup
+ *	     direction - data transfer direction
+ * Notes   : This is called when entering DATA I/O phase, not
+ *	     while we're in a DATA I/O phase
+ */
+static
+void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
+{
+    unsigned int address, length, mode;
+
+    host->dma.direction = direction;
+
+    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);
+
+    if (direction == DMA_OUT) {
+#if (DEBUG & DEBUG_NO_WRITE)
+	if (NO_WRITE & (1 << host->SCpnt->device->id)) {
+	    printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
+		    host->host->host_no, acornscsi_target(host));
+	    return;
+	}
+#endif
+	mode = DMAC_WRITE;
+    } else
+	mode = DMAC_READ;
+
+    /*
+     * Allocate some buffer space, limited to half the buffer size
+     */
+    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    if (length) {
+	host->dma.start_addr = address = host->dma.free_addr;
+	host->dma.free_addr = (host->dma.free_addr + length) &
+				(DMAC_BUFFER_SIZE - 1);
+
+	/*
+	 * Transfer data to DMA memory
+	 */
+	if (direction == DMA_OUT)
+	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
+				length);
+
+	length -= 1;
+	dmac_write(host->dma.io_port, DMAC_TXCNTLO, length);
+	dmac_write(host->dma.io_port, DMAC_TXCNTHI, length >> 8);
+	dmac_write(host->dma.io_port, DMAC_TXADRLO, address);
+	dmac_write(host->dma.io_port, DMAC_TXADRMD, address >> 8);
+	dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);
+	dmac_write(host->dma.io_port, DMAC_MODECON, mode);
+	dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
+#endif
+	host->dma.xfer_setup = 1;
+    }
+}
+
+/*
+ * Function: void acornscsi_dma_cleanup(AS_Host *host)
+ * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
+ * Params  : host - host to finish
+ * Notes   : This is called when a command is:
+ *		terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT
+ *	   : This must not return until all transfers are completed.
+ */
+static
+void acornscsi_dma_cleanup(AS_Host *host)
+{
+    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+    /*
+     * Check for a pending transfer
+     */
+    if (host->dma.xfer_required) {
+	host->dma.xfer_required = 0;
+	if (host->dma.direction == DMA_IN)
+	    acornscsi_data_read(host, host->dma.xfer_ptr,
+				 host->dma.xfer_start, host->dma.xfer_length);
+    }
+
+    /*
+     * Has a transfer been setup?
+     */
+    if (host->dma.xfer_setup) {
+	unsigned int transferred;
+
+	host->dma.xfer_setup = 0;
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));
+#endif
+
+	/*
+	 * Calculate number of bytes transferred from DMA.
+	 */
+	transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
+	host->dma.transferred += transferred;
+
+	if (host->dma.direction == DMA_IN)
+	    acornscsi_data_read(host, host->scsi.SCp.ptr,
+				 host->dma.start_addr, transferred);
+
+	/*
+	 * Update SCSI pointers
+	 */
+	acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
+#endif
+    }
+}
+
+/*
+ * Function: void acornscsi_dmacintr(AS_Host *host)
+ * Purpose : handle interrupts from DMAC device
+ * Params  : host - host to process
+ * Notes   : If reading, we schedule the read to main memory &
+ *	     allow the transfer to continue.
+ *	   : If writing, we fill the onboard DMA memory from main
+ *	     memory.
+ *	   : Called whenever DMAC finished it's current transfer.
+ */
+static
+void acornscsi_dma_intr(AS_Host *host)
+{
+    unsigned int address, length, transferred;
+
+#if (DEBUG & DEBUG_DMA)
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
+#endif
+
+    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+    /*
+     * Calculate amount transferred via DMA
+     */
+    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
+    host->dma.transferred += transferred;
+
+    /*
+     * Schedule DMA transfer off board
+     */
+    if (host->dma.direction == DMA_IN) {
+	host->dma.xfer_start = host->dma.start_addr;
+	host->dma.xfer_length = transferred;
+	host->dma.xfer_ptr = host->scsi.SCp.ptr;
+	host->dma.xfer_required = 1;
+    }
+
+    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
+
+    /*
+     * Allocate some buffer space, limited to half the on-board RAM size
+     */
+    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    if (length) {
+	host->dma.start_addr = address = host->dma.free_addr;
+	host->dma.free_addr = (host->dma.free_addr + length) &
+				(DMAC_BUFFER_SIZE - 1);
+
+	/*
+	 * Transfer data to DMA memory
+	 */
+	if (host->dma.direction == DMA_OUT)
+	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
+				length);
+
+	length -= 1;
+	dmac_write(host->dma.io_port, DMAC_TXCNTLO, length);
+	dmac_write(host->dma.io_port, DMAC_TXCNTHI, length >> 8);
+	dmac_write(host->dma.io_port, DMAC_TXADRLO, address);
+	dmac_write(host->dma.io_port, DMAC_TXADRMD, address >> 8);
+	dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);
+	dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
+#endif
+    } else {
+	host->dma.xfer_setup = 0;
+#if 0
+	/*
+	 * If the interface still wants more, then this is an error.
+	 * We give it another byte, but we also attempt to raise an
+	 * attention condition.  We continue giving one byte until
+	 * the device recognises the attention.
+	 */
+	if (dmac_read(host->dma.io_port, DMAC_STATUS) & STATUS_RQ0) {
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+
+	    dmac_write(host->dma.io_port, DMAC_TXCNTLO, 0);
+	    dmac_write(host->dma.io_port, DMAC_TXCNTHI, 0);
+	    dmac_write(host->dma.io_port, DMAC_TXADRLO, 0);
+	    dmac_write(host->dma.io_port, DMAC_TXADRMD, 0);
+	    dmac_write(host->dma.io_port, DMAC_TXADRHI, 0);
+	    dmac_write(host->dma.io_port, DMAC_MASKREG, MASK_OFF);
+	}
+#endif
+    }
+}
+
+/*
+ * Function: void acornscsi_dma_xfer(AS_Host *host)
+ * Purpose : transfer data between AcornSCSI and memory
+ * Params  : host - host to process
+ */
+static
+void acornscsi_dma_xfer(AS_Host *host)
+{
+    host->dma.xfer_required = 0;
+
+    if (host->dma.direction == DMA_IN)
+	acornscsi_data_read(host, host->dma.xfer_ptr,
+				host->dma.xfer_start, host->dma.xfer_length);
+}
+
+/*
+ * Function: void acornscsi_dma_adjust(AS_Host *host)
+ * Purpose : adjust DMA pointers & count for bytes transferred to
+ *	     SBIC but not SCSI bus.
+ * Params  : host - host to adjust DMA count for
+ */
+static
+void acornscsi_dma_adjust(AS_Host *host)
+{
+    if (host->dma.xfer_setup) {
+	signed long transferred;
+#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
+#endif
+	/*
+	 * Calculate correct DMA address - DMA is ahead of SCSI bus while
+	 * writing.
+	 *  host->scsi.SCp.scsi_xferred is the number of bytes
+	 *  actually transferred to/from the SCSI bus.
+	 *  host->dma.transferred is the number of bytes transferred
+	 *  over DMA since host->dma.start_addr was last set.
+	 *
+	 * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred
+	 *		   - host->dma.transferred
+	 */
+	transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
+	if (transferred < 0)
+	    printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
+		    host->host->host_no, acornscsi_target(host), transferred);
+	else if (transferred == 0)
+	    host->dma.xfer_setup = 0;
+	else {
+	    transferred += host->dma.start_addr;
+	    dmac_write(host->dma.io_port, DMAC_TXADRLO, transferred);
+	    dmac_write(host->dma.io_port, DMAC_TXADRMD, transferred >> 8);
+	    dmac_write(host->dma.io_port, DMAC_TXADRHI, transferred >> 16);
+#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
+	    DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
+#endif
+	}
+    }
+}
+#endif
+
+/* =========================================================================================
+ * Data I/O
+ */
+static int
+acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
+{
+	unsigned int asr, timeout = max_timeout;
+	int my_ptr = *ptr;
+
+	while (my_ptr < len) {
+		asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+
+		if (asr & ASR_DBR) {
+			timeout = max_timeout;
+
+			sbic_arm_write(host->scsi.io_port, SBIC_DATA, bytes[my_ptr++]);
+		} else if (asr & ASR_INT)
+			break;
+		else if (--timeout == 0)
+			break;
+		udelay(1);
+	}
+
+	*ptr = my_ptr;
+
+	return (timeout == 0) ? -1 : 0;
+}
+
+/*
+ * Function: void acornscsi_sendcommand(AS_Host *host)
+ * Purpose : send a command to a target
+ * Params  : host - host which is connected to target
+ */
+static void
+acornscsi_sendcommand(AS_Host *host)
+{
+    Scsi_Cmnd *SCpnt = host->SCpnt;
+
+    sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
+    sbic_arm_writenext(host->scsi.io_port, 0);
+    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
+
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+    if (acornscsi_write_pio(host, SCpnt->cmnd,
+	(int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
+	printk("scsi%d: timeout while sending command\n", host->host->host_no);
+
+    host->scsi.phase = PHASE_COMMAND;
+}
+
+static
+void acornscsi_sendmessage(AS_Host *host)
+{
+    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
+    unsigned int msgnr;
+    struct message *msg;
+
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("scsi%d.%c: sending message ",
+	    host->host->host_no, acornscsi_target(host));
+#endif
+
+    switch (message_length) {
+    case 0:
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
+
+	sbic_arm_write(host->scsi.io_port, SBIC_DATA, NOP);
+
+	host->scsi.last_message = NOP;
+#if (DEBUG & DEBUG_MESSAGES)
+	printk("NOP");
+#endif
+	break;
+
+    case 1:
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+	msg = msgqueue_getmsg(&host->scsi.msgs, 0);
+
+	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
+
+	sbic_arm_write(host->scsi.io_port, SBIC_DATA, msg->msg[0]);
+
+	host->scsi.last_message = msg->msg[0];
+#if (DEBUG & DEBUG_MESSAGES)
+	print_msg(msg->msg);
+#endif
+	break;
+
+    default:
+	/*
+	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)
+	 * 'When a target sends this (MESSAGE_REJECT) message, it
+	 *  shall change to MESSAGE IN phase and send this message
+	 *  prior to requesting additional message bytes from the
+	 *  initiator.  This provides an interlock so that the
+	 *  initiator can determine which message byte is rejected.
+	 */
+	sbic_arm_write(host->scsi.io_port, SBIC_TRANSCNTH, 0);
+	sbic_arm_writenext(host->scsi.io_port, 0);
+	sbic_arm_writenext(host->scsi.io_port, message_length);
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+	msgnr = 0;
+	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
+	    unsigned int i;
+#if (DEBUG & DEBUG_MESSAGES)
+	    print_msg(msg);
+#endif
+	    i = 0;
+	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
+		printk("scsi%d: timeout while sending message\n", host->host->host_no);
+
+	    host->scsi.last_message = msg->msg[0];
+	    if (msg->msg[0] == EXTENDED_MESSAGE)
+		host->scsi.last_message |= msg->msg[2] << 8;
+
+	    if (i != msg->length)
+		break;
+	}
+	break;
+    }
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("\n");
+#endif
+}
+
+/*
+ * Function: void acornscsi_readstatusbyte(AS_Host *host)
+ * Purpose : Read status byte from connected target
+ * Params  : host - host connected to target
+ */
+static
+void acornscsi_readstatusbyte(AS_Host *host)
+{
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
+    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, SBIC_DATA);
+}
+
+/*
+ * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
+ * Purpose : Read one message byte from connected target
+ * Params  : host - host connected to target
+ */
+static
+unsigned char acornscsi_readmessagebyte(AS_Host *host)
+{
+    unsigned char message;
+
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
+
+    message = sbic_arm_read(host->scsi.io_port, SBIC_DATA);
+
+    /* wait for MSGIN-XFER-PAUSED */
+    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
+
+    sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+
+    return message;
+}
+
+/*
+ * Function: void acornscsi_message(AS_Host *host)
+ * Purpose : Read complete message from connected target & action message
+ * Params  : host - host connected to target
+ */
+static
+void acornscsi_message(AS_Host *host)
+{
+    unsigned char message[16];
+    unsigned int msgidx = 0, msglen = 1;
+
+    do {
+	message[msgidx] = acornscsi_readmessagebyte(host);
+
+	switch (msgidx) {
+	case 0:
+	    if (message[0] == EXTENDED_MESSAGE ||
+		(message[0] >= 0x20 && message[0] <= 0x2f))
+		msglen = 2;
+	    break;
+
+	case 1:
+	    if (message[0] == EXTENDED_MESSAGE)
+		msglen += message[msgidx];
+	    break;
+	}
+	msgidx += 1;
+	if (msgidx < msglen) {
+	    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+
+	    /* wait for next msg-in */
+	    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
+	    sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+	}
+    } while (msgidx < msglen);
+
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("scsi%d.%c: message in: ",
+	    host->host->host_no, acornscsi_target(host));
+    print_msg(message);
+    printk("\n");
+#endif
+
+    if (host->scsi.phase == PHASE_RECONNECTED) {
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
+	 * 'Whenever a target reconnects to an initiator to continue
+	 *  a tagged I/O process, the SIMPLE QUEUE TAG message shall
+	 *  be sent immediately following the IDENTIFY message...'
+	 */
+	if (message[0] == SIMPLE_QUEUE_TAG)
+	    host->scsi.reconnected.tag = message[1];
+	if (acornscsi_reconnect_finish(host))
+	    host->scsi.phase = PHASE_MSGIN;
+    }
+
+    switch (message[0]) {
+    case ABORT:
+    case ABORT_TAG:
+    case COMMAND_COMPLETE:
+	if (host->scsi.phase != PHASE_STATUSIN) {
+	    printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
+		    host->host->host_no, acornscsi_target(host));
+	    acornscsi_dumplog(host, host->SCpnt->device->id);
+	}
+	host->scsi.phase = PHASE_DONE;
+	host->scsi.SCp.Message = message[0];
+	break;
+
+    case SAVE_POINTERS:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)
+	 * 'The SAVE DATA POINTER message is sent from a target to
+	 *  direct the initiator to copy the active data pointer to
+	 *  the saved data pointer for the current I/O process.
+	 */
+	acornscsi_dma_cleanup(host);
+	host->SCpnt->SCp = host->scsi.SCp;
+	host->SCpnt->SCp.sent_command = 0;
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+
+    case RESTORE_POINTERS:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)
+	 * 'The RESTORE POINTERS message is sent from a target to
+	 *  direct the initiator to copy the most recently saved
+	 *  command, data, and status pointers for the I/O process
+	 *  to the corresponding active pointers.  The command and
+	 *  status pointers shall be restored to the beginning of
+	 *  the present command and status areas.'
+	 */
+	acornscsi_dma_cleanup(host);
+	host->scsi.SCp = host->SCpnt->SCp;
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+
+    case DISCONNECT:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)
+	 * 'On those occasions when an error or exception condition occurs
+	 *  and the target elects to repeat the information transfer, the
+	 *  target may repeat the transfer either issuing a RESTORE POINTERS
+	 *  message or by disconnecting without issuing a SAVE POINTERS
+	 *  message.  When reconnection is completed, the most recent
+	 *  saved pointer values are restored.'
+	 */
+	acornscsi_dma_cleanup(host);
+	host->scsi.phase = PHASE_DISCONNECT;
+	break;
+
+    case MESSAGE_REJECT:
+#if 0 /* this isn't needed any more */
+	/*
+	 * If we were negociating sync transfer, we don't yet know if
+	 * this REJECT is for the sync transfer or for the tagged queue/wide
+	 * transfer.  Re-initiate sync transfer negociation now, and if
+	 * we got a REJECT in response to SDTR, then it'll be set to DONE.
+	 */
+	if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST)
+	    host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE;
+#endif
+
+	/*
+	 * If we have any messages waiting to go out, then assert ATN now
+	 */
+	if (msgqueue_msglength(&host->scsi.msgs))
+	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+
+	switch (host->scsi.last_message) {
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+	case HEAD_OF_QUEUE_TAG:
+	case ORDERED_QUEUE_TAG:
+	case SIMPLE_QUEUE_TAG:
+	    /*
+	     * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
+	     *  If a target does not implement tagged queuing and a queue tag
+	     *  message is received, it shall respond with a MESSAGE REJECT
+	     *  message and accept the I/O process as if it were untagged.
+	     */
+	    printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
+		    host->host->host_no, acornscsi_target(host));
+	    host->SCpnt->device->simple_tags = 0;
+	    set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->lun, host->busyluns);
+	    break;
+#endif
+	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
+	    /*
+	     * Target can't handle synchronous transfers
+	     */
+	    printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
+		    host->host->host_no, acornscsi_target(host));
+	    host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA;
+	    host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS;
+	    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+	    break;
+
+	default:
+	    break;
+	}
+	break;
+
+    case QUEUE_FULL:
+	/* TODO: target queue is full */
+	break;
+
+    case SIMPLE_QUEUE_TAG:
+	/* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */
+	printk("scsi%d.%c: reconnect queue tag %02X\n",
+		host->host->host_no, acornscsi_target(host),
+		message[1]);
+	break;
+
+    case EXTENDED_MESSAGE:
+	switch (message[2]) {
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+	case EXTENDED_SDTR:
+	    if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) {
+		/*
+		 * We requested synchronous transfers.  This isn't quite right...
+		 * We can only say if this succeeded if we proceed on to execute the
+		 * command from this message.  If we get a MESSAGE PARITY ERROR,
+		 * and the target retries fail, then we fallback to asynchronous mode
+		 */
+		host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED;
+		printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
+			host->host->host_no, acornscsi_target(host),
+			message[4], message[3] * 4);
+		host->device[host->SCpnt->device->id].sync_xfer =
+			calc_sync_xfer(message[3] * 4, message[4]);
+	    } else {
+		unsigned char period, length;
+		/*
+		 * Target requested synchronous transfers.  The agreement is only
+		 * to be in operation AFTER the target leaves message out phase.
+		 */
+		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+		period = max_t(unsigned int, message[3], sdtr_period / 4);
+		length = min_t(unsigned int, message[4], sdtr_size);
+		msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
+				 EXTENDED_SDTR, period, length);
+		host->device[host->SCpnt->device->id].sync_xfer =
+			calc_sync_xfer(period * 4, length);
+	    }
+	    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+	    break;
+#else
+	    /* We do not accept synchronous transfers.  Respond with a
+	     * MESSAGE_REJECT.
+	     */
+#endif
+
+	case EXTENDED_WDTR:
+	    /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT
+	     * to a wide data transfer request.
+	     */
+	default:
+	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+	    msgqueue_flush(&host->scsi.msgs);
+	    msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
+	    break;
+	}
+	break;
+
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    case LINKED_CMD_COMPLETE:
+    case LINKED_FLG_CMD_COMPLETE:
+	/*
+	 * We don't support linked commands yet
+	 */
+	if (0) {
+#if (DEBUG & DEBUG_LINK)
+	    printk("scsi%d.%c: lun %d tag %d linked command complete\n",
+		    host->host->host_no, acornscsi_target(host), host->SCpnt->tag);
+#endif
+	    /*
+	     * A linked command should only terminate with one of these messages
+	     * if there are more linked commands available.
+	     */
+	    if (!host->SCpnt->next_link) {
+		printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
+			instance->host_no, acornscsi_target(host), host->SCpnt->tag);
+		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+		msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
+	    } else {
+		Scsi_Cmnd *SCpnt = host->SCpnt;
+
+		acornscsi_dma_cleanup(host);
+
+		host->SCpnt = host->SCpnt->next_link;
+		host->SCpnt->tag = SCpnt->tag;
+		SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
+		SCpnt->done(SCpnt);
+
+		/* initialise host->SCpnt->SCp */
+	    }
+	    break;
+	}
+#endif
+
+    default: /* reject message */
+	printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
+		host->host->host_no, acornscsi_target(host),
+		message[0]);
+	acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+	msgqueue_flush(&host->scsi.msgs);
+	msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+    }
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+}
+
+/*
+ * Function: int acornscsi_buildmessages(AS_Host *host)
+ * Purpose : build the connection messages for a host
+ * Params  : host - host to add messages to
+ */
+static
+void acornscsi_buildmessages(AS_Host *host)
+{
+#if 0
+    /* does the device need resetting? */
+    if (cmd_reset) {
+	msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
+	return;
+    }
+#endif
+
+    msgqueue_addmsg(&host->scsi.msgs, 1,
+		     IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok,
+			     host->SCpnt->device->lun));
+
+#if 0
+    /* does the device need the current command aborted */
+    if (cmd_aborted) {
+	acornscsi_abortcmd(host->SCpnt->tag);
+	return;
+    }
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    if (host->SCpnt->tag) {
+	unsigned int tag_type;
+
+	if (host->SCpnt->cmnd[0] == REQUEST_SENSE ||
+	    host->SCpnt->cmnd[0] == TEST_UNIT_READY ||
+	    host->SCpnt->cmnd[0] == INQUIRY)
+	    tag_type = HEAD_OF_QUEUE_TAG;
+	else
+	    tag_type = SIMPLE_QUEUE_TAG;
+	msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
+    }
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) {
+	host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST;
+	msgqueue_addmsg(&host->scsi.msgs, 5,
+			 EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+			 sdtr_period / 4, sdtr_size);
+    }
+#endif
+}
+
+/*
+ * Function: int acornscsi_starttransfer(AS_Host *host)
+ * Purpose : transfer data to/from connected target
+ * Params  : host - host to which target is connected
+ * Returns : 0 if failure
+ */
+static
+int acornscsi_starttransfer(AS_Host *host)
+{
+    int residual;
+
+    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
+	printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
+		host->host->host_no, acornscsi_target(host));
+	return 0;
+    }
+
+    residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
+
+    sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 16);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 8);
+    sbic_arm_writenext(host->scsi.io_port, residual);
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+    return 1;
+}
+
+/* =========================================================================================
+ * Connection & Disconnection
+ */
+/*
+ * Function : acornscsi_reconnect(AS_Host *host)
+ * Purpose  : reconnect a previously disconnected command
+ * Params   : host - host specific data
+ * Remarks  : SCSI spec says:
+ *		'The set of active pointers is restored from the set
+ *		 of saved pointers upon reconnection of the I/O process'
+ */
+static
+int acornscsi_reconnect(AS_Host *host)
+{
+    unsigned int target, lun, ok = 0;
+
+    target = sbic_arm_read(host->scsi.io_port, SBIC_SOURCEID);
+
+    if (!(target & 8))
+	printk(KERN_ERR "scsi%d: invalid source id after reselection "
+		"- device fault?\n",
+		host->host->host_no);
+
+    target &= 7;
+
+    if (host->SCpnt && !host->scsi.disconnectable) {
+	printk(KERN_ERR "scsi%d.%d: reconnected while command in "
+		"progress to target %d?\n",
+		host->host->host_no, target, host->SCpnt->device->id);
+	host->SCpnt = NULL;
+    }
+
+    lun = sbic_arm_read(host->scsi.io_port, SBIC_DATA) & 7;
+
+    host->scsi.reconnected.target = target;
+    host->scsi.reconnected.lun = lun;
+    host->scsi.reconnected.tag = 0;
+
+    if (host->scsi.disconnectable && host->SCpnt &&
+	host->SCpnt->device->id == target && host->SCpnt->device->lun == lun)
+	ok = 1;
+
+    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
+	ok = 1;
+
+    ADD_STATUS(target, 0x81, host->scsi.phase, 0);
+
+    if (ok) {
+	host->scsi.phase = PHASE_RECONNECTED;
+    } else {
+	/* this doesn't seem to work */
+	printk(KERN_ERR "scsi%d.%c: reselected with no command "
+		"to reconnect with\n",
+		host->host->host_no, '0' + target);
+	acornscsi_dumplog(host, target);
+	acornscsi_abortcmd(host, 0);
+	if (host->SCpnt) {
+	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+	    host->SCpnt = NULL;
+	}
+    }
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+    return !ok;
+}
+
+/*
+ * Function: int acornscsi_reconect_finish(AS_Host *host)
+ * Purpose : finish reconnecting a command
+ * Params  : host - host to complete
+ * Returns : 0 if failed
+ */
+static
+int acornscsi_reconnect_finish(AS_Host *host)
+{
+    if (host->scsi.disconnectable && host->SCpnt) {
+	host->scsi.disconnectable = 0;
+	if (host->SCpnt->device->id  == host->scsi.reconnected.target &&
+	    host->SCpnt->device->lun == host->scsi.reconnected.lun &&
+	    host->SCpnt->tag         == host->scsi.reconnected.tag) {
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	    DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
+		    host->host->host_no, acornscsi_target(host)));
+#endif
+	} else {
+	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	    DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
+		    "to disconnected queue\n",
+		    host->host->host_no, acornscsi_target(host)));
+#endif
+	    host->SCpnt = NULL;
+	}
+    }
+    if (!host->SCpnt) {
+	host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
+				host->scsi.reconnected.target,
+				host->scsi.reconnected.lun,
+				host->scsi.reconnected.tag);
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
+		host->host->host_no, acornscsi_target(host)));
+#endif
+    }
+
+    if (!host->SCpnt)
+	acornscsi_abortcmd(host, host->scsi.reconnected.tag);
+    else {
+	/*
+	 * Restore data pointer from SAVED pointers.
+	 */
+	host->scsi.SCp = host->SCpnt->SCp;
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	printk(", data pointers: [%p, %X]",
+		host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
+#endif
+    }
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+    printk("\n");
+#endif
+
+    host->dma.transferred = host->scsi.SCp.scsi_xferred;
+
+    return host->SCpnt != NULL;
+}
+
+/*
+ * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
+ * Purpose : handle an unexpected disconnect
+ * Params  : host - host on which disconnect occurred
+ */
+static
+void acornscsi_disconnect_unexpected(AS_Host *host)
+{
+    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
+	    host->host->host_no, acornscsi_target(host));
+#if (DEBUG & DEBUG_ABORT)
+    acornscsi_dumplog(host, 8);
+#endif
+
+    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+}
+
+/*
+ * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
+ * Purpose : abort a currently executing command
+ * Params  : host - host with connected command to abort
+ *	     tag  - tag to abort
+ */
+static
+void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
+{
+    host->scsi.phase = PHASE_ABORTED;
+    sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_ASSERTATN);
+
+    msgqueue_flush(&host->scsi.msgs);
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    if (tag)
+	msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
+    else
+#endif
+	msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
+}
+
+/* ==========================================================================================
+ * Interrupt routines.
+ */
+/*
+ * Function: int acornscsi_sbicintr(AS_Host *host)
+ * Purpose : handle interrupts from SCSI device
+ * Params  : host - host to process
+ * Returns : INTR_PROCESS if expecting another SBIC interrupt
+ *	     INTR_IDLE if no interrupt
+ *	     INTR_NEXT_COMMAND if we have finished processing the command
+ */
+static
+intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
+{
+    unsigned int asr, ssr;
+
+    asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+    if (!(asr & ASR_INT))
+	return INTR_IDLE;
+
+    ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+
+#if (DEBUG & DEBUG_PHASES)
+    print_sbic_status(asr, ssr, host->scsi.phase);
+#endif
+
+    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);
+
+    if (host->SCpnt && !host->scsi.disconnectable)
+	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
+
+    switch (ssr) {
+    case 0x00:				/* reset state - not advanced			*/
+	printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
+		host->host->host_no);
+	/* setup sbic - WD33C93A */
+	sbic_arm_write(host->scsi.io_port, SBIC_OWNID, OWNID_EAF | host->host->this_id);
+	sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_RESET);
+	return INTR_IDLE;
+
+    case 0x01:				/* reset state - advanced			*/
+	sbic_arm_write(host->scsi.io_port, SBIC_CTRL, INIT_SBICDMA | CTRL_IDI);
+	sbic_arm_write(host->scsi.io_port, SBIC_TIMEOUT, TIMEOUT_TIME);
+	sbic_arm_write(host->scsi.io_port, SBIC_SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+	sbic_arm_write(host->scsi.io_port, SBIC_SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+	msgqueue_flush(&host->scsi.msgs);
+	return INTR_IDLE;
+
+    case 0x41:				/* unexpected disconnect aborted command	*/
+	acornscsi_disconnect_unexpected(host);
+	return INTR_NEXT_COMMAND;
+    }
+
+    switch (host->scsi.phase) {
+    case PHASE_CONNECTING:		/* STATE: command removed from issue queue	*/
+	switch (ssr) {
+	case 0x11:			/* -> PHASE_CONNECTED				*/
+	    /* BUS FREE -> SELECTION */
+	    host->scsi.phase = PHASE_CONNECTED;
+	    msgqueue_flush(&host->scsi.msgs);
+	    host->dma.transferred = host->scsi.SCp.scsi_xferred;
+	    /* 33C93 gives next interrupt indicating bus phase */
+	    asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+	    if (!(asr & ASR_INT))
+		break;
+	    ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+	    ADD_STATUS(8, ssr, host->scsi.phase, 1);
+	    ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1);
+	    goto connected;
+	    
+	case 0x42:			/* select timed out				*/
+					/* -> PHASE_IDLE				*/
+	    acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
+	    return INTR_NEXT_COMMAND;
+
+	case 0x81:			/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
+	    /* BUS FREE -> RESELECTION */
+	    host->origSCpnt = host->SCpnt;
+	    host->SCpnt = NULL;
+	    msgqueue_flush(&host->scsi.msgs);
+	    acornscsi_reconnect(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	}
+	return INTR_PROCESSING;
+
+    connected:
+    case PHASE_CONNECTED:		/* STATE: device selected ok			*/
+	switch (ssr) {
+#ifdef NONSTANDARD
+	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    /* SELECTION -> COMMAND */
+	    acornscsi_sendcommand(host);
+	    break;
+
+	case 0x8b:			/* -> PHASE_STATUS				*/
+	    /* SELECTION -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+#endif
+
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* SELECTION ->MESSAGE OUT */
+	    host->scsi.phase = PHASE_MSGOUT;
+	    acornscsi_buildmessages(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	/* these should not happen */
+	case 0x85:			/* target disconnected				*/
+	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_MSGOUT:			/* STATE: connected & sent IDENTIFY message	*/
+	/*
+	 * SCSI standard says that MESSAGE OUT phases can be followed by a
+	 * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
+	 */
+	switch (ssr) {
+	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	case 0x1a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    /* MESSAGE OUT -> COMMAND */
+	    acornscsi_sendcommand(host);
+	    break;
+
+	case 0x8b:			/* -> PHASE_STATUS				*/
+	case 0x1b:			/* -> PHASE_STATUS				*/
+	    /* MESSAGE OUT -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x4f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    /* MESSAGE OUT -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_COMMAND: 		/* STATE: connected & command sent		*/
+	switch (ssr) {
+	case 0x18:			/* -> PHASE_DATAOUT				*/
+	    /* COMMAND -> DATA OUT */
+	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    acornscsi_dma_setup(host, DMA_OUT);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAOUT;
+	    return INTR_IDLE;
+
+	case 0x19:			/* -> PHASE_DATAIN				*/
+	    /* COMMAND -> DATA IN */
+	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    acornscsi_dma_setup(host, DMA_IN);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAIN;
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUS				*/
+	    /* COMMAND -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	    /* COMMAND -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    /* COMMAND -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DISCONNECT:		/* STATE: connected, received DISCONNECT msg	*/
+	if (ssr == 0x85) {		/* -> PHASE_IDLE				*/
+	    host->scsi.disconnectable = 1;
+	    host->scsi.reconnected.tag = 0;
+	    host->scsi.phase = PHASE_IDLE;
+	    host->stats.disconnects += 1;
+	} else {
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_NEXT_COMMAND;
+
+    case PHASE_IDLE:			/* STATE: disconnected				*/
+	if (ssr == 0x81)		/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
+	    acornscsi_reconnect(host);
+	else {
+	    printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_RECONNECTED:		/* STATE: device reconnected to initiator	*/
+	/*
+	 * Command reconnected - if MESGIN, get message - it may be
+	 * the tag.  If not, get command out of disconnected queue
+	 */
+	/*
+	 * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
+	 * reconnect I_T_L command
+	 */
+	if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
+	    return INTR_IDLE;
+	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
+	switch (ssr) {
+	case 0x88:			/* data out phase				*/
+					/* -> PHASE_DATAOUT				*/
+	    /* MESSAGE IN -> DATA OUT */
+	    acornscsi_dma_setup(host, DMA_OUT);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAOUT;
+	    return INTR_IDLE;
+
+	case 0x89:			/* data in phase				*/
+					/* -> PHASE_DATAIN				*/
+	    /* MESSAGE IN -> DATA IN */
+	    acornscsi_dma_setup(host, DMA_IN);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAIN;
+	    return INTR_IDLE;
+
+	case 0x8a:			/* command out					*/
+	    /* MESSAGE IN -> COMMAND */
+	    acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    break;
+
+	case 0x8b:			/* status in					*/
+					/* -> PHASE_STATUSIN				*/
+	    /* MESSAGE IN -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x8e:			/* message out					*/
+					/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE IN -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x8f:			/* message in					*/
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DATAIN:			/* STATE: transferred data in			*/
+	/*
+	 * This is simple - if we disconnect then the DMA address & count is
+	 * correct.
+	 */
+	switch (ssr) {
+	case 0x19:			/* -> PHASE_DATAIN				*/
+	case 0x89:			/* -> PHASE_DATAIN				*/
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUSIN				*/
+	case 0x4b:			/* -> PHASE_STATUSIN				*/
+	case 0x8b:			/* -> PHASE_STATUSIN				*/
+	    /* DATA IN -> STATUS */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* DATA IN -> MESSAGE OUT */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* message in					*/
+	case 0x4f:			/* message in					*/
+	case 0x8f:			/* message in					*/
+	    /* DATA IN -> MESSAGE IN */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DATAOUT: 		/* STATE: transferred data out			*/
+	/*
+	 * This is more complicated - if we disconnect, the DMA could be 12
+	 * bytes ahead of us.  We need to correct this.
+	 */
+	switch (ssr) {
+	case 0x18:			/* -> PHASE_DATAOUT				*/
+	case 0x88:			/* -> PHASE_DATAOUT				*/
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUSIN				*/
+	case 0x4b:			/* -> PHASE_STATUSIN				*/
+	case 0x8b:			/* -> PHASE_STATUSIN				*/
+	    /* DATA OUT -> STATUS */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* DATA OUT -> MESSAGE OUT */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* message in					*/
+	case 0x4f:			/* message in					*/
+	case 0x8f:			/* message in					*/
+	    /* DATA OUT -> MESSAGE IN */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_STATUSIN:		/* STATE: status in complete			*/
+	switch (ssr) {
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	case 0x8f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	    /* STATUS -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* STATUS -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_MSGIN:			/* STATE: message in				*/
+	switch (ssr) {
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE IN -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	case 0x2f:
+	case 0x4f:
+	case 0x8f:
+	    acornscsi_message(host);
+	    break;
+
+	case 0x85:
+	    printk("scsi%d.%c: strange message in disconnection\n",
+		host->host->host_no, acornscsi_target(host));
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DONE:			/* STATE: received status & message		*/
+	switch (ssr) {
+	case 0x85:			/* -> PHASE_IDLE				*/
+	    acornscsi_done(host, &host->SCpnt, DID_OK);
+	    return INTR_NEXT_COMMAND;
+
+	case 0x1e:
+	case 0x8e:
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_ABORTED:
+	switch (ssr) {
+	case 0x85:
+	    if (host->SCpnt)
+		acornscsi_done(host, &host->SCpnt, DID_ABORT);
+	    else {
+		clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
+			  host->busyluns);
+		host->scsi.phase = PHASE_IDLE;
+	    }
+	    return INTR_NEXT_COMMAND;
+
+	case 0x1e:
+	case 0x2e:
+	case 0x4e:
+	case 0x8e:
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    default:
+	printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
+		host->host->host_no, acornscsi_target(host), ssr);
+	acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+    }
+    return INTR_PROCESSING;
+}
+
+/*
+ * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+ * Purpose  : handle interrupts from Acorn SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - device specific data (AS_Host structure)
+ *	      regs   - processor registers when interrupt occurred
+ */
+static irqreturn_t
+acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+    AS_Host *host = (AS_Host *)dev_id;
+    intr_ret_t ret;
+    int iostatus;
+    int in_irq = 0;
+
+    do {
+	ret = INTR_IDLE;
+
+	iostatus = inb(host->card.io_intr);
+
+	if (iostatus & 2) {
+	    acornscsi_dma_intr(host);
+	    iostatus = inb(host->card.io_intr);
+	}
+
+	if (iostatus & 8)
+	    ret = acornscsi_sbicintr(host, in_irq);
+
+	/*
+	 * If we have a transfer pending, start it.
+	 * Only start it if the interface has already started transferring
+	 * it's data
+	 */
+	if (host->dma.xfer_required)
+	    acornscsi_dma_xfer(host);
+
+	if (ret == INTR_NEXT_COMMAND)
+	    ret = acornscsi_kick(host);
+
+	in_irq = 1;
+    } while (ret != INTR_IDLE);
+
+    return IRQ_HANDLED;
+}
+
+/*=============================================================================================
+ * Interfaces between interrupt handler and rest of scsi code
+ */
+
+/*
+ * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Purpose  : queues a SCSI command
+ * Params   : cmd  - SCSI command
+ *	      done - function called on completion, with pointer to command descriptor
+ * Returns  : 0, or < 0 on error.
+ */
+int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+
+    if (!done) {
+	/* there should be some way of rejecting errors like this without panicing... */
+	panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
+		host->host->host_no, SCpnt);
+	return -EINVAL;
+    }
+
+#if (DEBUG & DEBUG_NO_WRITE)
+    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) {
+	printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
+	    host->host->host_no, '0' + SCpnt->device->id);
+	SCpnt->result = DID_NO_CONNECT << 16;
+	done(SCpnt);
+	return 0;
+    }
+#endif
+
+    SCpnt->scsi_done = done;
+    SCpnt->host_scribble = NULL;
+    SCpnt->result = 0;
+    SCpnt->tag = 0;
+    SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
+    SCpnt->SCp.sent_command = 0;
+    SCpnt->SCp.scsi_xferred = 0;
+
+    init_SCp(SCpnt);
+
+    host->stats.queues += 1;
+
+    {
+	unsigned long flags;
+
+	if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
+	    SCpnt->result = DID_ERROR << 16;
+	    done(SCpnt);
+	    return 0;
+	}
+	local_irq_save(flags);
+	if (host->scsi.phase == PHASE_IDLE)
+	    acornscsi_kick(host);
+	local_irq_restore(flags);
+    }
+    return 0;
+}
+
+/*
+ * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
+ * Params   : SCpntp1 - pointer to command to return
+ *	      SCpntp2 - pointer to command to check
+ *	      result  - result to pass back to mid-level done function
+ * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
+ */
+static inline
+void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+{
+    Scsi_Cmnd *SCpnt = *SCpntp1;
+
+    if (SCpnt) {
+	*SCpntp1 = NULL;
+
+	SCpnt->result = result;
+	SCpnt->scsi_done(SCpnt);
+    }
+
+    if (SCpnt == *SCpntp2)
+	*SCpntp2 = NULL;
+}
+
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
+/*
+ * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : our abort status
+ */
+static enum res_abort
+acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
+{
+	enum res_abort res = res_not_running;
+
+	if (queue_remove_cmd(&host->queues.issue, SCpnt)) {
+		/*
+		 * The command was on the issue queue, and has not been
+		 * issued yet.  We can remove the command from the queue,
+		 * and acknowledge the abort.  Neither the devices nor the
+		 * interface know about the command.
+		 */
+//#if (DEBUG & DEBUG_ABORT)
+		printk("on issue queue ");
+//#endif
+		res = res_success;
+	} else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) {
+		/*
+		 * The command was on the disconnected queue.  Simply
+		 * acknowledge the abort condition, and when the target
+		 * reconnects, we will give it an ABORT message.  The
+		 * target should then disconnect, and we will clear
+		 * the busylun bit.
+		 */
+//#if (DEBUG & DEBUG_ABORT)
+		printk("on disconnected queue ");
+//#endif
+		res = res_success;
+	} else if (host->SCpnt == SCpnt) {
+		unsigned long flags;
+
+//#if (DEBUG & DEBUG_ABORT)
+		printk("executing ");
+//#endif
+
+		local_irq_save(flags);
+		switch (host->scsi.phase) {
+		/*
+		 * If the interface is idle, and the command is 'disconnectable',
+		 * then it is the same as on the disconnected queue.  We simply
+		 * remove all traces of the command.  When the target reconnects,
+		 * we will give it an ABORT message since the command could not
+		 * be found.  When the target finally disconnects, we will clear
+		 * the busylun bit.
+		 */
+		case PHASE_IDLE:
+			if (host->scsi.disconnectable) {
+				host->scsi.disconnectable = 0;
+				host->SCpnt = NULL;
+				res = res_success;
+			}
+			break;
+
+		/*
+		 * If the command has connected and done nothing further,
+		 * simply force a disconnect.  We also need to clear the
+		 * busylun bit.
+		 */
+		case PHASE_CONNECTED:
+			sbic_arm_write(host->scsi.io_port, SBIC_CMND, CMND_DISCONNECT);
+			host->SCpnt = NULL;
+			res = res_success_clear;
+			break;
+
+		default:
+			acornscsi_abortcmd(host, host->SCpnt->tag);
+			res = res_snooze;
+		}
+		local_irq_restore(flags);
+	} else if (host->origSCpnt == SCpnt) {
+		/*
+		 * The command will be executed next, but a command
+		 * is currently using the interface.  This is similar to
+		 * being on the issue queue, except the busylun bit has
+		 * been set.
+		 */
+		host->origSCpnt = NULL;
+//#if (DEBUG & DEBUG_ABORT)
+		printk("waiting for execution ");
+//#endif
+		res = res_success_clear;
+	} else
+		printk("unknown ");
+
+	return res;
+}
+
+/*
+ * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : one of SCSI_ABORT_ macros
+ */
+int acornscsi_abort(Scsi_Cmnd *SCpnt)
+{
+	AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
+	int result;
+
+	host->stats.aborts += 1;
+
+#if (DEBUG & DEBUG_ABORT)
+	{
+		int asr, ssr;
+		asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+		ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+
+		printk(KERN_WARNING "acornscsi_abort: ");
+		print_sbic_status(asr, ssr, host->scsi.phase);
+		acornscsi_dumplog(host, SCpnt->device->id);
+	}
+#endif
+
+	printk("scsi%d: ", host->host->host_no);
+
+	switch (acornscsi_do_abort(host, SCpnt)) {
+	/*
+	 * We managed to find the command and cleared it out.
+	 * We do not expect the command to be executing on the
+	 * target, but we have set the busylun bit.
+	 */
+	case res_success_clear:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("clear ");
+//#endif
+		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	/*
+	 * We found the command, and cleared it out.  Either
+	 * the command is still known to be executing on the
+	 * target, or the busylun bit is not set.
+	 */
+	case res_success:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("success\n");
+//#endif
+		SCpnt->result = DID_ABORT << 16;
+		SCpnt->scsi_done(SCpnt);
+		result = SCSI_ABORT_SUCCESS;
+		break;
+
+	/*
+	 * We did find the command, but unfortunately we couldn't
+	 * unhook it from ourselves.  Wait some more, and if it
+	 * still doesn't complete, reset the interface.
+	 */
+	case res_snooze:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("snooze\n");
+//#endif
+		result = SCSI_ABORT_SNOOZE;
+		break;
+
+	/*
+	 * The command could not be found (either because it completed,
+	 * or it got dropped.
+	 */
+	default:
+	case res_not_running:
+		acornscsi_dumplog(host, SCpnt->device->id);
+#if (DEBUG & DEBUG_ABORT)
+		result = SCSI_ABORT_SNOOZE;
+#else
+		result = SCSI_ABORT_NOT_RUNNING;
+#endif
+//#if (DEBUG & DEBUG_ABORT)
+		printk("not running\n");
+//#endif
+		break;
+	}
+
+	return result;
+}
+
+/*
+ * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Purpose  : reset a command on this host/reset this host
+ * Params   : SCpnt  - command causing reset
+ *	      result - what type of reset to perform
+ * Returns  : one of SCSI_RESET_ macros
+ */
+int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+    Scsi_Cmnd *SCptr;
+    
+    host->stats.resets += 1;
+
+#if (DEBUG & DEBUG_RESET)
+    {
+	int asr, ssr;
+
+	asr = sbic_arm_read(host->scsi.io_port, SBIC_ASR);
+	ssr = sbic_arm_read(host->scsi.io_port, SBIC_SSR);
+
+	printk(KERN_WARNING "acornscsi_reset: ");
+	print_sbic_status(asr, ssr, host->scsi.phase);
+	acornscsi_dumplog(host, SCpnt->device->id);
+    }
+#endif
+
+    acornscsi_dma_stop(host);
+
+    SCptr = host->SCpnt;
+
+    /*
+     * do hard reset.  This resets all devices on this host, and so we
+     * must set the reset status on all commands.
+     */
+    acornscsi_resetcard(host);
+
+    /*
+     * report reset on commands current connected/disconnected
+     */
+    acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET);
+
+    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
+	acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET);
+
+    if (SCpnt) {
+	SCpnt->result = DID_RESET << 16;
+	SCpnt->scsi_done(SCpnt);
+    }
+
+    return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
+}
+
+/*==============================================================================================
+ * initialisation & miscellaneous support
+ */
+
+/*
+ * Function: char *acornscsi_info(struct Scsi_Host *host)
+ * Purpose : return a string describing this interface
+ * Params  : host - host to give information on
+ * Returns : a constant string
+ */
+const
+char *acornscsi_info(struct Scsi_Host *host)
+{
+    static char string[100], *p;
+
+    p = string;
+    
+    p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d"
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    " SYNC"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    " TAG"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    " LINK"
+#endif
+#if (DEBUG & DEBUG_NO_WRITE)
+    " NOWRITE ("NO_WRITE_STR")"
+#endif
+		, host->hostt->name, host->io_port, host->irq,
+		VER_MAJOR, VER_MINOR, VER_PATCH);
+    return string;
+}
+
+int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+			int length, int inout)
+{
+    int pos, begin = 0, devidx;
+    Scsi_Device *scd;
+    AS_Host *host;
+    char *p = buffer;
+
+    if (inout == 1)
+	return -EINVAL;
+
+    host  = (AS_Host *)instance->hostdata;
+    
+    p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    " SYNC"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    " TAG"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    " LINK"
+#endif
+#if (DEBUG & DEBUG_NO_WRITE)
+    " NOWRITE ("NO_WRITE_STR")"
+#endif
+		"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
+
+    p += sprintf(p,	"SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
+			host->scsi.io_port, host->scsi.irq);
+#ifdef USE_DMAC
+    p += sprintf(p,	"DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
+			host->dma.io_port, host->scsi.irq);
+#endif
+
+    p += sprintf(p,	"Statistics:\n"
+			"Queued commands: %-10u    Issued commands: %-10u\n"
+			"Done commands  : %-10u    Reads          : %-10u\n"
+			"Writes         : %-10u    Others         : %-10u\n"
+			"Disconnects    : %-10u    Aborts         : %-10u\n"
+			"Resets         : %-10u\n\nLast phases:",
+			host->stats.queues,		host->stats.removes,
+			host->stats.fins,		host->stats.reads,
+			host->stats.writes,		host->stats.miscs,
+			host->stats.disconnects,	host->stats.aborts,
+			host->stats.resets);
+
+    for (devidx = 0; devidx < 9; devidx ++) {
+	unsigned int statptr, prev;
+
+	p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
+	statptr = host->status_ptr[devidx] - 10;
+
+	if ((signed int)statptr < 0)
+	    statptr += STATUS_BUFFER_SIZE;
+
+	prev = host->status[devidx][statptr].when;
+
+	for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+	    if (host->status[devidx][statptr].when) {
+		p += sprintf(p, "%c%02X:%02X+%2ld",
+			host->status[devidx][statptr].irq ? '-' : ' ',
+			host->status[devidx][statptr].ph,
+			host->status[devidx][statptr].ssr,
+			(host->status[devidx][statptr].when - prev) < 100 ?
+				(host->status[devidx][statptr].when - prev) : 99);
+		prev = host->status[devidx][statptr].when;
+	    }
+	}
+    }
+
+    p += sprintf(p, "\nAttached devices:\n");
+
+    shost_for_each_device(scd, instance) {
+	p += sprintf(p, "Device/Lun TaggedQ      Sync\n");
+	p += sprintf(p, "     %d/%d   ", scd->id, scd->lun);
+	if (scd->tagged_supported)
+		p += sprintf(p, "%3sabled(%3d) ",
+			     scd->simple_tags ? "en" : "dis",
+			     scd->current_tag);
+	else
+		p += sprintf(p, "unsupported  ");
+
+	if (host->device[scd->id].sync_xfer & 15)
+		p += sprintf(p, "offset %d, %d ns\n",
+			     host->device[scd->id].sync_xfer & 15,
+			     acornscsi_getperiod(host->device[scd->id].sync_xfer));
+	else
+		p += sprintf(p, "async\n");
+
+	pos = p - buffer;
+	if (pos + begin < offset) {
+	    begin += pos;
+	    p = buffer;
+	}
+	pos = p - buffer;
+	if (pos + begin > offset + length) {
+	    scsi_device_put(scd);
+	    break;
+	}
+    }
+
+    pos = p - buffer;
+
+    *start = buffer + (offset - begin);
+    pos -= offset - begin;
+
+    if (pos > length)
+	pos = length;
+
+    return pos;
+}
+
+static Scsi_Host_Template acornscsi_template = {
+	.module			= THIS_MODULE,
+	.proc_info		= acornscsi_proc_info,
+	.name			= "AcornSCSI",
+	.info			= acornscsi_info,
+	.queuecommand		= acornscsi_queuecmd,
+#warning fixme
+	.abort			= acornscsi_abort,
+	.reset			= acornscsi_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.unchecked_isa_dma	= 0,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "acornscsi",
+};
+
+static int __devinit
+acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	AS_Host *ashost;
+	int ret = -ENOMEM;
+
+	host = scsi_host_alloc(&acornscsi_template, sizeof(AS_Host));
+	if (!host)
+		goto out;
+
+	ashost = (AS_Host *)host->hostdata;
+
+	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+	host->irq = ec->irq;
+
+	ashost->host		= host;
+	ashost->scsi.io_port	= ioaddr(host->io_port + 0x800);
+	ashost->scsi.irq	= host->irq;
+	ashost->card.io_intr	= POD_SPACE(host->io_port) + 0x800;
+	ashost->card.io_page	= POD_SPACE(host->io_port) + 0xc00;
+	ashost->card.io_ram	= ioaddr(host->io_port);
+	ashost->dma.io_port	= host->io_port + 0xc00;
+	ashost->dma.io_intr_clear = POD_SPACE(host->io_port) + 0x800;
+
+	ec->irqaddr	= (char *)ioaddr(ashost->card.io_intr);
+	ec->irqmask	= 0x0a;
+
+	ret = -EBUSY;
+	if (!request_region(host->io_port + 0x800, 2, "acornscsi(sbic)"))
+		goto err_1;
+	if (!request_region(ashost->card.io_intr, 1, "acornscsi(intr)"))
+		goto err_2;
+	if (!request_region(ashost->card.io_page, 1, "acornscsi(page)"))
+		goto err_3;
+#ifdef USE_DMAC
+	if (!request_region(ashost->dma.io_port, 256, "acornscsi(dmac)"))
+		goto err_4;
+#endif
+	if (!request_region(host->io_port, 2048, "acornscsi(ram)"))
+		goto err_5;
+
+	ret = request_irq(host->irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", ashost);
+	if (ret) {
+		printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
+			host->host_no, ashost->scsi.irq, ret);
+		goto err_6;
+	}
+
+	memset(&ashost->stats, 0, sizeof (ashost->stats));
+	queue_initialise(&ashost->queues.issue);
+	queue_initialise(&ashost->queues.disconnected);
+	msgqueue_initialise(&ashost->scsi.msgs);
+
+	acornscsi_resetcard(ashost);
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret)
+		goto err_7;
+
+	scsi_scan_host(host);
+	goto out;
+
+ err_7:
+	free_irq(host->irq, ashost);
+ err_6:
+	release_region(host->io_port, 2048);
+ err_5:
+#ifdef USE_DMAC
+	release_region(ashost->dma.io_port, 256);
+#endif
+ err_4:
+	release_region(ashost->card.io_page, 1);
+ err_3:
+	release_region(ashost->card.io_intr, 1);    
+ err_2:
+	release_region(host->io_port + 0x800, 2);
+ err_1:
+	scsi_host_put(host);
+ out:
+	return ret;
+}
+
+static void __devexit acornscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	AS_Host *ashost = (AS_Host *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	scsi_remove_host(host);
+
+	/*
+	 * Put card into RESET state
+	 */
+	outb(0x80, ashost->card.io_page);
+
+	free_irq(host->irq, ashost);
+
+	release_region(host->io_port + 0x800, 2);
+	release_region(ashost->card.io_intr, 1);
+	release_region(ashost->card.io_page, 1);
+	release_region(ashost->dma.io_port, 256);
+	release_region(host->io_port, 2048);
+
+	msgqueue_free(&ashost->scsi.msgs);
+	queue_free(&ashost->queues.disconnected);
+	queue_free(&ashost->queues.issue);
+	scsi_host_put(host);
+}
+
+static const struct ecard_id acornscsi_cids[] = {
+	{ MANU_ACORN, PROD_ACORN_SCSI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver acornscsi_driver = {
+	.probe		= acornscsi_probe,
+	.remove		= __devexit_p(acornscsi_remove),
+	.id_table	= acornscsi_cids,
+	.drv = {
+		.name		= "acornscsi",
+	},
+};
+
+static int __init acornscsi_init(void)
+{
+	return ecard_register_driver(&acornscsi_driver);
+}
+
+static void __exit acornscsi_exit(void)
+{
+	ecard_remove_driver(&acornscsi_driver);
+}
+
+module_init(acornscsi_init);
+module_exit(acornscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("AcornSCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
new file mode 100644
index 0000000..03881f0
--- /dev/null
+++ b/drivers/scsi/arm/acornscsi.h
@@ -0,0 +1,358 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi.h
+ *
+ *  Copyright (C) 1997 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Acorn SCSI driver
+ */
+#ifndef ACORNSCSI_H
+#define ACORNSCSI_H
+
+/* SBIC registers */
+#define SBIC_OWNID		0
+#define OWNID_FS1		(1<<7)
+#define OWNID_FS2		(1<<6)
+#define OWNID_EHP		(1<<4)
+#define OWNID_EAF		(1<<3)
+
+#define SBIC_CTRL		1
+#define CTRL_DMAMODE		(1<<7)
+#define CTRL_DMADBAMODE		(1<<6)
+#define CTRL_DMABURST		(1<<5)
+#define CTRL_DMAPOLLED		0
+#define CTRL_HHP		(1<<4)
+#define CTRL_EDI		(1<<3)
+#define CTRL_IDI		(1<<2)
+#define CTRL_HA			(1<<1)
+#define CTRL_HSP		(1<<0)
+
+#define SBIC_TIMEOUT		2
+#define SBIC_TOTSECTS		3
+#define SBIC_TOTHEADS		4
+#define SBIC_TOTCYLH		5
+#define SBIC_TOTCYLL		6
+#define SBIC_LOGADDRH		7
+#define SBIC_LOGADDRM2		8
+#define SBIC_LOGADDRM1		9
+#define SBIC_LOGADDRL		10
+#define SBIC_SECTORNUM		11
+#define SBIC_HEADNUM		12
+#define SBIC_CYLH		13
+#define SBIC_CYLL		14
+#define SBIC_TARGETLUN		15
+#define TARGETLUN_TLV		(1<<7)
+#define TARGETLUN_DOK		(1<<6)
+
+#define SBIC_CMNDPHASE		16
+#define SBIC_SYNCHTRANSFER	17
+#define SYNCHTRANSFER_OF0	0x00
+#define SYNCHTRANSFER_OF1	0x01
+#define SYNCHTRANSFER_OF2	0x02
+#define SYNCHTRANSFER_OF3	0x03
+#define SYNCHTRANSFER_OF4	0x04
+#define SYNCHTRANSFER_OF5	0x05
+#define SYNCHTRANSFER_OF6	0x06
+#define SYNCHTRANSFER_OF7	0x07
+#define SYNCHTRANSFER_OF8	0x08
+#define SYNCHTRANSFER_OF9	0x09
+#define SYNCHTRANSFER_OF10	0x0A
+#define SYNCHTRANSFER_OF11	0x0B
+#define SYNCHTRANSFER_OF12	0x0C
+#define SYNCHTRANSFER_8DBA	0x00
+#define SYNCHTRANSFER_2DBA	0x20
+#define SYNCHTRANSFER_3DBA	0x30
+#define SYNCHTRANSFER_4DBA	0x40
+#define SYNCHTRANSFER_5DBA	0x50
+#define SYNCHTRANSFER_6DBA	0x60
+#define SYNCHTRANSFER_7DBA	0x70
+
+#define SBIC_TRANSCNTH		18
+#define SBIC_TRANSCNTM		19
+#define SBIC_TRANSCNTL		20
+#define SBIC_DESTID		21
+#define DESTID_SCC		(1<<7)
+#define DESTID_DPD		(1<<6)
+
+#define SBIC_SOURCEID		22
+#define SOURCEID_ER		(1<<7)
+#define SOURCEID_ES		(1<<6)
+#define SOURCEID_DSP		(1<<5)
+#define SOURCEID_SIV		(1<<4)
+
+#define SBIC_SSR		23
+#define SBIC_CMND		24
+#define CMND_RESET		0x00
+#define CMND_ABORT		0x01
+#define CMND_ASSERTATN		0x02
+#define CMND_NEGATEACK		0x03
+#define CMND_DISCONNECT		0x04
+#define CMND_RESELECT		0x05
+#define CMND_SELWITHATN		0x06
+#define CMND_SELECT		0x07
+#define CMND_SELECTATNTRANSFER	0x08
+#define CMND_SELECTTRANSFER	0x09
+#define CMND_RESELECTRXDATA	0x0A
+#define CMND_RESELECTTXDATA	0x0B
+#define CMND_WAITFORSELRECV	0x0C
+#define CMND_SENDSTATCMD	0x0D
+#define CMND_SENDDISCONNECT	0x0E
+#define CMND_SETIDI		0x0F
+#define CMND_RECEIVECMD		0x10
+#define CMND_RECEIVEDTA		0x11
+#define CMND_RECEIVEMSG		0x12
+#define CMND_RECEIVEUSP		0x13
+#define CMND_SENDCMD		0x14
+#define CMND_SENDDATA		0x15
+#define CMND_SENDMSG		0x16
+#define CMND_SENDUSP		0x17
+#define CMND_TRANSLATEADDR	0x18
+#define CMND_XFERINFO		0x20
+#define CMND_SBT		(1<<7)
+
+#define SBIC_DATA		25
+#define SBIC_ASR		26
+#define ASR_INT			(1<<7)
+#define ASR_LCI			(1<<6)
+#define ASR_BSY			(1<<5)
+#define ASR_CIP			(1<<4)
+#define ASR_PE			(1<<1)
+#define ASR_DBR			(1<<0)
+
+/* DMAC registers */
+#define DMAC_INIT		0x00
+#define INIT_8BIT		(1)
+
+#define DMAC_CHANNEL		0x80
+#define CHANNEL_0		0x00
+#define CHANNEL_1		0x01
+#define CHANNEL_2		0x02
+#define CHANNEL_3		0x03
+
+#define DMAC_TXCNTLO		0x01
+#define DMAC_TXCNTHI		0x81
+#define DMAC_TXADRLO		0x02
+#define DMAC_TXADRMD		0x82
+#define DMAC_TXADRHI		0x03
+
+#define DMAC_DEVCON0		0x04
+#define DEVCON0_AKL		(1<<7)
+#define DEVCON0_RQL		(1<<6)
+#define DEVCON0_EXW		(1<<5)
+#define DEVCON0_ROT		(1<<4)
+#define DEVCON0_CMP		(1<<3)
+#define DEVCON0_DDMA		(1<<2)
+#define DEVCON0_AHLD		(1<<1)
+#define DEVCON0_MTM		(1<<0)
+
+#define DMAC_DEVCON1		0x84
+#define DEVCON1_WEV		(1<<1)
+#define DEVCON1_BHLD		(1<<0)
+
+#define DMAC_MODECON		0x05
+#define MODECON_WOED		0x01
+#define MODECON_VERIFY		0x00
+#define MODECON_READ		0x04
+#define MODECON_WRITE		0x08
+#define MODECON_AUTOINIT	0x10
+#define MODECON_ADDRDIR		0x20
+#define MODECON_DEMAND		0x00
+#define MODECON_SINGLE		0x40
+#define MODECON_BLOCK		0x80
+#define MODECON_CASCADE		0xC0
+
+#define DMAC_STATUS		0x85
+#define STATUS_TC0		(1<<0)
+#define STATUS_RQ0		(1<<4)
+
+#define DMAC_TEMPLO		0x06
+#define DMAC_TEMPHI		0x86
+#define DMAC_REQREG		0x07
+#define DMAC_MASKREG		0x87
+#define MASKREG_M0		0x01
+#define MASKREG_M1		0x02
+#define MASKREG_M2		0x04
+#define MASKREG_M3		0x08
+
+/* miscellaneous internal variables */
+
+#define POD_SPACE(x)	((x) + 0xd0000)
+#define MASK_ON		(MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0)
+#define MASK_OFF	(MASKREG_M3|MASKREG_M2|MASKREG_M1)
+
+/*
+ * SCSI driver phases
+ */
+typedef enum {
+    PHASE_IDLE,					/* we're not planning on doing anything	 */
+    PHASE_CONNECTING,				/* connecting to a target		 */
+    PHASE_CONNECTED,				/* connected to a target		 */
+    PHASE_MSGOUT,				/* message out to device		 */
+    PHASE_RECONNECTED,				/* reconnected				 */
+    PHASE_COMMANDPAUSED,			/* command partly sent			 */
+    PHASE_COMMAND,				/* command all sent			 */
+    PHASE_DATAOUT,				/* data out to device			 */
+    PHASE_DATAIN,				/* data in from device			 */
+    PHASE_STATUSIN,				/* status in from device		 */
+    PHASE_MSGIN,				/* message in from device		 */
+    PHASE_DONE,					/* finished				 */
+    PHASE_ABORTED,				/* aborted				 */
+    PHASE_DISCONNECT,				/* disconnecting			 */
+} phase_t;
+
+/*
+ * After interrupt, what to do now
+ */
+typedef enum {
+    INTR_IDLE,					/* not expecting another IRQ		 */
+    INTR_NEXT_COMMAND,				/* start next command			 */
+    INTR_PROCESSING,				/* interrupt routine still processing	 */
+} intr_ret_t;
+
+/*
+ * DMA direction
+ */
+typedef enum {
+    DMA_OUT,					/* DMA from memory to chip		*/
+    DMA_IN					/* DMA from chip to memory		*/
+} dmadir_t;
+
+/*
+ * Synchronous transfer state
+ */
+typedef enum {					/* Synchronous transfer state		*/
+    SYNC_ASYNCHRONOUS,				/* don't negociate synchronous transfers*/
+    SYNC_NEGOCIATE,				/* start negociation			*/
+    SYNC_SENT_REQUEST,				/* sent SDTR message			*/
+    SYNC_COMPLETED,				/* received SDTR reply			*/
+} syncxfer_t;
+
+/*
+ * Command type
+ */
+typedef enum {					/* command type				*/
+    CMD_READ,					/* READ_6, READ_10, READ_12		*/
+    CMD_WRITE,					/* WRITE_6, WRITE_10, WRITE_12		*/
+    CMD_MISC,					/* Others				*/
+} cmdtype_t;
+
+/*
+ * Data phase direction
+ */
+typedef enum {					/* Data direction			*/
+    DATADIR_IN,					/* Data in phase expected		*/
+    DATADIR_OUT					/* Data out phase expected		*/
+} datadir_t;
+
+#include "queue.h"
+#include "msgqueue.h"
+
+#define STATUS_BUFFER_SIZE	32
+/*
+ * This is used to dump the previous states of the SBIC
+ */
+struct status_entry {
+	unsigned long	when;
+	unsigned char	ssr;
+	unsigned char	ph;
+	unsigned char	irq;
+	unsigned char	unused;
+};
+
+#define ADD_STATUS(_q,_ssr,_ph,_irq) \
+({									\
+	host->status[(_q)][host->status_ptr[(_q)]].when = jiffies;	\
+	host->status[(_q)][host->status_ptr[(_q)]].ssr  = (_ssr);	\
+	host->status[(_q)][host->status_ptr[(_q)]].ph   = (_ph);	\
+	host->status[(_q)][host->status_ptr[(_q)]].irq  = (_irq);	\
+	host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \
+})
+
+/*
+ * AcornSCSI host specific data
+ */
+typedef struct acornscsi_hostdata {
+    /* miscellaneous */
+    struct Scsi_Host	*host;			/* host					*/
+    Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
+    Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
+
+    /* driver information */
+    struct {
+	unsigned int	io_port;		/* base address of WD33C93		*/
+	unsigned int	irq;			/* interrupt				*/
+	phase_t		phase;			/* current phase			*/
+
+	struct {
+	    unsigned char	target;		/* reconnected target			*/
+	    unsigned char	lun;		/* reconnected lun			*/
+	    unsigned char	tag;		/* reconnected tag			*/
+	} reconnected;
+
+	Scsi_Pointer	SCp;			/* current commands data pointer	*/
+
+	MsgQueue_t	msgs;
+
+	unsigned short	last_message;		/* last message to be sent		*/
+	unsigned char	disconnectable:1;	/* this command can be disconnected	*/
+    } scsi;
+
+    /* statistics information */
+    struct {
+	unsigned int	queues;
+	unsigned int	removes;
+	unsigned int	fins;
+	unsigned int	reads;
+	unsigned int	writes;
+	unsigned int	miscs;
+	unsigned int	disconnects;
+	unsigned int	aborts;
+	unsigned int	resets;
+    } stats;
+
+    /* queue handling */
+    struct {
+	Queue_t		issue;			/* issue queue				*/
+	Queue_t		disconnected;		/* disconnected command queue		*/
+    } queues;
+
+    /* per-device info */
+    struct {
+	unsigned char	sync_xfer;		/* synchronous transfer (SBIC value)	*/
+	syncxfer_t	sync_state;		/* sync xfer negociation state		*/
+	unsigned char	disconnect_ok:1;	/* device can disconnect		*/
+    } device[8];
+    unsigned long	busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
+
+    /* DMA info */
+    struct {
+	unsigned int	io_port;		/* base address of DMA controller	*/
+	unsigned int	io_intr_clear;		/* address of DMA interrupt clear	*/
+	unsigned int	free_addr;		/* next free address			*/
+	unsigned int	start_addr;		/* start address of current transfer	*/
+	dmadir_t	direction;		/* dma direction			*/
+	unsigned int	transferred;		/* number of bytes transferred		*/
+	unsigned int	xfer_start;		/* scheduled DMA transfer start		*/
+	unsigned int	xfer_length;		/* scheduled DMA transfer length	*/
+	char		*xfer_ptr;		/* pointer to area			*/
+	unsigned char	xfer_required:1;	/* set if we need to transfer something	*/
+	unsigned char	xfer_setup:1;		/* set if DMA is setup			*/
+	unsigned char	xfer_done:1;		/* set if DMA reached end of BH list	*/
+    } dma;
+
+    /* card info */
+    struct {
+	unsigned int	io_intr;		/* base address of interrupt id reg	*/
+	unsigned int	io_page;		/* base address of page reg		*/
+	unsigned int	io_ram;			/* base address of RAM access		*/
+	unsigned char	page_reg;		/* current setting of page reg		*/
+    } card;
+
+    unsigned char status_ptr[9];
+    struct status_entry status[9][STATUS_BUFFER_SIZE];
+} AS_Host;
+
+#endif /* ACORNSCSI_H */
diff --git a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
new file mode 100644
index 0000000..29811f5
--- /dev/null
+++ b/drivers/scsi/arm/arxescsi.c
@@ -0,0 +1,395 @@
+/*
+ * linux/arch/arm/drivers/scsi/arxescsi.c
+ *
+ * Copyright (C) 1997-2000 Russell King, Stefan Hanske
+ *
+ * This driver is based on experimentation.  Hence, it may have made
+ * assumptions about the particular card that I have available, and
+ * may not be reliable!
+ *
+ * Changelog:
+ *  30-08-1997	RMK	0.0.0	Created, READONLY version as cumana_2.c
+ *  22-01-1998	RMK	0.0.1	Updated to 2.1.80
+ *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
+ *  11-06-1998 	SH	0.0.2   Changed to support ARXE 16-bit SCSI card
+ *				enabled writing
+ *  01-01-2000	SH	0.1.0   Added *real* pseudo dma writing
+ *				(arxescsi_pseudo_dma_write)
+ *  02-04-2000	RMK	0.1.1	Updated for new error handling code.
+ *  22-10-2000  SH		Updated for new registering scheme.
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "fas216.h"
+
+struct arxescsi_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+	void __iomem		*base;
+};
+
+#define DMADATA_OFFSET	(0x200)
+
+#define DMASTAT_OFFSET	(0x600)
+#define DMASTAT_DRQ	(1 << 0)
+
+#define CSTATUS_IRQ	(1 << 0)
+
+#define VERSION "1.10 (23/01/2003 2.5.57)"
+
+/*
+ * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose : initialises DMA/PIO
+ * Params  : host      - host
+ *	     SCpnt     - command
+ *	     direction - DMA on to/off of card
+ *	     min_type  - minimum DMA support that we must have for this transfer
+ * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
+ */
+static fasdmatype_t
+arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	/*
+	 * We don't do real DMA
+	 */
+	return fasdma_pseudo;
+}
+
+static void arxescsi_pseudo_dma_write(unsigned char *addr, void __iomem *base)
+{
+       __asm__ __volatile__(
+       "               stmdb   sp!, {r0-r12}\n"
+       "               mov     r3, %0\n"
+       "               mov     r1, %1\n"
+       "               add     r2, r1, #512\n"
+       "               mov     r4, #256\n"
+       ".loop_1:       ldmia   r3!, {r6, r8, r10, r12}\n"
+       "               mov     r5, r6, lsl #16\n"
+       "               mov     r7, r8, lsl #16\n"
+       ".loop_2:       ldrb    r0, [r1, #1536]\n"
+       "               tst     r0, #1\n"
+       "               beq     .loop_2\n"
+       "               stmia   r2, {r5-r8}\n\t"
+       "               mov     r9, r10, lsl #16\n"
+       "               mov     r11, r12, lsl #16\n"
+       ".loop_3:       ldrb    r0, [r1, #1536]\n"
+       "               tst     r0, #1\n"
+       "               beq     .loop_3\n"
+       "               stmia   r2, {r9-r12}\n"
+       "               subs    r4, r4, #16\n"
+       "               bne     .loop_1\n"
+       "               ldmia   sp!, {r0-r12}\n"
+       :
+       : "r" (addr), "r" (base));
+}
+
+/*
+ * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose : handles pseudo DMA
+ * Params  : host      - host
+ *	     SCpnt     - command
+ *	     direction - DMA on to/off of card
+ *	     transfer  - minimum number of bytes we expect to transfer
+ */
+static void
+arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		    fasdmadir_t direction, int transfer)
+{
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
+	unsigned int length, error = 0;
+	void __iomem *base = info->info.scsi.io_base;
+	unsigned char *addr;
+
+	length = SCp->this_residual;
+	addr = SCp->ptr;
+
+	if (direction == DMA_OUT) {
+		unsigned int word;
+		while (length > 256) {
+			if (readb(base + 0x80) & STAT_INT) {
+				error = 1;
+				break;
+			}
+			arxescsi_pseudo_dma_write(addr, base);
+			addr += 256;
+			length -= 256;
+		}
+
+		if (!error)
+			while (length > 0) {
+				if (readb(base + 0x80) & STAT_INT)
+					break;
+	 
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				word = *addr | *(addr + 1) << 8;
+
+				writew(word, base + DMADATA_OFFSET);
+				if (length > 1) {
+					addr += 2;
+					length -= 2;
+				} else {
+					addr += 1;
+					length -= 1;
+				}
+			}
+	}
+	else {
+		if (transfer && (transfer & 255)) {
+			while (length >= 256) {
+				if (readb(base + 0x80) & STAT_INT) {
+					error = 1;
+					break;
+				}
+	    
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				readsw(base + DMADATA_OFFSET, addr, 256 >> 1);
+				addr += 256;
+				length -= 256;
+			}
+		}
+
+		if (!(error))
+			while (length > 0) {
+				unsigned long word;
+
+				if (readb(base + 0x80) & STAT_INT)
+					break;
+
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				word = readw(base + DMADATA_OFFSET);
+				*addr++ = word;
+				if (--length > 0) {
+					*addr++ = word >> 8;
+					length --;
+				}
+			}
+	}
+}
+
+/*
+ * Function: int arxescsi_dma_stop(host, SCpnt)
+ * Purpose : stops DMA/PIO
+ * Params  : host  - host
+ *	     SCpnt - command
+ */
+static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	/*
+	 * no DMA to stop
+	 */
+}
+
+/*
+ * Function: const char *arxescsi_info(struct Scsi_Host * host)
+ * Purpose : returns a descriptive string about this interface,
+ * Params  : host - driver host structure to return info for.
+ * Returns : pointer to a static buffer containing null terminated string.
+ */
+static const char *arxescsi_info(struct Scsi_Host *host)
+{
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION);
+
+	return string;
+}
+
+/*
+ * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+ *					 int length, int host_no, int inout)
+ * Purpose : Return information about the driver to a user process accessing
+ *	     the /proc filesystem.
+ * Params  : buffer - a buffer to write information to
+ *	     start  - a pointer into this buffer set by this routine to the start
+ *		      of the required information.
+ *	     offset - offset into information that we have read upto.
+ *	     length - length of buffer
+ *	     host_no - host number to return information for
+ *	     inout  - 0 for reading, 1 for writing.
+ * Returns : length of data written to buffer.
+ */
+static int
+arxescsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,
+		   int inout)
+{
+	struct arxescsi_info *info;
+	char *p = buffer;
+	int pos;
+
+	info = (struct arxescsi_info *)host->hostdata;
+	if (inout == 1)
+		return -EINVAL;
+
+	p += sprintf(p, "ARXE 16-bit SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static Scsi_Host_Template arxescsi_template = {
+	.proc_info			= arxescsi_proc_info,
+	.name				= "ARXE SCSI card",
+	.info				= arxescsi_info,
+	.queuecommand			= fas216_noqueue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 0,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "arxescsi",
+};
+
+static int __devinit
+arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct arxescsi_info *info;
+	unsigned long resbase, reslen;
+	void __iomem *base;
+	int ret;
+
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_host_alloc(&arxescsi_template, sizeof(struct arxescsi_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	info = (struct arxescsi_info *)host->hostdata;
+	info->ec = ec;
+	info->base = base;
+
+	info->info.scsi.io_base		= base + 0x2000;
+	info->info.scsi.irq		= NO_IRQ;
+	info->info.scsi.dma		= NO_DMA;
+	info->info.scsi.io_shift	= 5;
+	info->info.ifcfg.clockrate	= 24; /* MHz */
+	info->info.ifcfg.select_timeout = 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 0;
+	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 0;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= arxescsi_dma_setup;
+	info->info.dma.pseudo		= arxescsi_dma_pseudo;
+	info->info.dma.stop		= arxescsi_dma_stop;
+		
+	ec->irqaddr = base;
+	ec->irqmask = CSTATUS_IRQ;
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_unregister;
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	fas216_release(host);
+ out_unregister:
+	scsi_host_put(host);
+ out_unmap:
+	iounmap(base);
+ out_region:
+	ecard_release_resources(ec);
+ out:
+	return ret;
+}
+
+static void __devexit arxescsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	iounmap(info->base);
+
+	fas216_release(host);
+	scsi_host_put(host);
+	ecard_release_resources(ec);
+}
+
+static const struct ecard_id arxescsi_cids[] = {
+	{ MANU_ARXE, PROD_ARXE_SCSI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver arxescsi_driver = {
+	.probe		= arxescsi_probe,
+	.remove		= __devexit_p(arxescsi_remove),
+	.id_table	= arxescsi_cids,
+	.drv = {
+		.name		= "arxescsi",
+	},
+};
+
+static int __init init_arxe_scsi_driver(void)
+{
+	return ecard_register_driver(&arxescsi_driver);
+}
+
+static void __exit exit_arxe_scsi_driver(void)
+{
+	ecard_remove_driver(&arxescsi_driver);
+}
+
+module_init(init_arxe_scsi_driver);
+module_exit(exit_arxe_scsi_driver);
+
+MODULE_AUTHOR("Stefan Hanske");
+MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
new file mode 100644
index 0000000..27271bf
--- /dev/null
+++ b/drivers/scsi/arm/cumana_1.c
@@ -0,0 +1,357 @@
+/*
+ * Generic Generic NCR5380 driver
+ *
+ * Copyright 1995-2002, Russell King
+ */
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+
+#include <scsi/scsicam.h>
+
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+#define CUMANASCSI_PUBLIC_RELEASE 1
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+#define NCR5380_read(reg)		cumanascsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	cumanascsi_write(_instance, reg, value)
+#define NCR5380_intr			cumanascsi_intr
+#define NCR5380_queue_command		cumanascsi_queue_command
+#define NCR5380_proc_info		cumanascsi_proc_info
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.h"
+
+void cumanascsi_setup(char *str, int *ints)
+{
+}
+
+const char *cumanascsi_info(struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#ifdef NOT_EFFICIENT
+#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
+#define STAT(p)       inb((p)+1)
+#define IN(p)         inb((p))
+#define OUT(v,p)      outb((v), (p))
+#else
+#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
+#define STAT(p)		(p[4])
+#define IN(p)		(*(p))
+#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
+#define OUT(v,p)	(*(p) = (v))
+#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
+#endif
+#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
+#define H(v)		(((v)>>16)|((v) & 0xffff0000))
+
+static inline int
+NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+{
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+  int oldctrl = *ctrl;
+  unsigned long *laddr;
+#ifdef NOT_EFFICIENT
+  int iobase = instance->io_port;
+  int dma_io = iobase & ~(0x3C0000>>2);
+#else
+  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
+  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
+#endif
+
+  if(!len) return 0;
+
+  CTRL(iobase, 0x02);
+  laddr = (unsigned long *)addr;
+  while(len >= 32)
+  {
+    int status;
+    unsigned long v;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(!(status & 0x40))
+      continue;
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    len -= 32;
+    if(len == 0)
+      break;
+  }
+
+  addr = (unsigned char *)laddr;
+  CTRL(iobase, 0x12);
+  while(len > 0)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      OUT(*addr++, dma_io);
+      if(--len == 0)
+        break;
+    }
+
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      OUT(*addr++, dma_io);
+      if(--len == 0)
+        break;
+    }
+  }
+end:
+  CTRL(iobase, oldctrl|0x40);
+  return len;
+}
+
+static inline int
+NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+{
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+  int oldctrl = *ctrl;
+  unsigned long *laddr;
+#ifdef NOT_EFFICIENT
+  int iobase = instance->io_port;
+  int dma_io = iobase & ~(0x3C0000>>2);
+#else
+  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
+  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
+#endif
+
+  if(!len) return 0;
+
+  CTRL(iobase, 0x00);
+  laddr = (unsigned long *)addr;
+  while(len >= 32)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(!(status & 0x40))
+      continue;
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    len -= 32;
+    if(len == 0)
+      break;
+  }
+
+  addr = (unsigned char *)laddr;
+  CTRL(iobase, 0x10);
+  while(len > 0)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      *addr++ = IN(dma_io);
+      if(--len == 0)
+        break;
+    }
+
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      *addr++ = IN(dma_io);
+      if(--len == 0)
+        break;
+    }
+  }
+end:
+  CTRL(iobase, oldctrl|0x40);
+  return len;
+}
+
+#undef STAT
+#undef CTRL
+#undef IN
+#undef OUT
+
+#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
+
+static char cumanascsi_read(struct Scsi_Host *instance, int reg)
+{
+	unsigned int iobase = instance->io_port;
+	int i;
+	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+	CTRL(iobase, 0);
+	i = inb(iobase + 64 + reg);
+	CTRL(iobase, 0x40);
+
+	return i;
+}
+
+static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+	int iobase = instance->io_port;
+	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+	CTRL(iobase, 0);
+	outb(value, iobase + 64 + reg);
+	CTRL(iobase, 0x40);
+}
+
+#undef CTRL
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template cumanascsi_template = {
+	.module			= THIS_MODULE,
+	.name			= "Cumana 16-bit SCSI",
+	.info			= cumanascsi_info,
+	.queuecommand		= cumanascsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.unchecked_isa_dma	= 0,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "CumanaSCSI-1",
+};
+
+static int __devinit
+cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	int ret = -ENOMEM;
+
+	host = scsi_host_alloc(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		goto out;
+
+        host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+	host->irq = ec->irq;
+
+	NCR5380_init(host, 0);
+
+	host->n_io_port = 255;
+	if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
+		ret = -EBUSY;
+		goto out_free;
+	}
+
+        ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
+        outb(0x00, host->io_port - 577);
+
+	ret = request_irq(host->irq, cumanascsi_intr, SA_INTERRUPT,
+			  "CumanaSCSI-1", host);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		    host->host_no, host->irq, ret);
+		goto out_release;
+	}
+
+	printk("scsi%d: at port 0x%08lx irq %d",
+		host->host_no, host->io_port, host->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret)
+		goto out_free_irq;
+
+	scsi_scan_host(host);
+	goto out;
+
+ out_free_irq:
+	free_irq(host->irq, host);
+ out_release:
+	release_region(host->io_port, host->n_io_port);
+ out_free:
+	scsi_host_put(host);
+ out:
+	return ret;
+}
+
+static void __devexit cumanascsi1_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);
+
+	scsi_remove_host(host);
+	free_irq(host->irq, host);
+	NCR5380_exit(host);
+	release_region(host->io_port, host->n_io_port);
+	scsi_host_put(host);
+}
+
+static const struct ecard_id cumanascsi1_cids[] = {
+	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver cumanascsi1_driver = {
+	.probe		= cumanascsi1_probe,
+	.remove		= __devexit_p(cumanascsi1_remove),
+	.id_table	= cumanascsi1_cids,
+	.drv = {
+		.name		= "cumanascsi1",
+	},
+};
+
+static int __init cumanascsi_init(void)
+{
+	return ecard_register_driver(&cumanascsi1_driver);
+}
+
+static void __exit cumanascsi_exit(void)
+{
+	ecard_remove_driver(&cumanascsi1_driver);
+}
+
+module_init(cumanascsi_init);
+module_exit(cumanascsi_exit);
+
+MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
new file mode 100644
index 0000000..0ef0644
--- /dev/null
+++ b/drivers/scsi/arm/cumana_2.c
@@ -0,0 +1,556 @@
+/*
+ *  linux/drivers/acorn/scsi/cumana_2.c
+ *
+ *  Copyright (C) 1997-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Changelog:
+ *   30-08-1997	RMK	0.0.0	Created, READONLY version.
+ *   22-01-1998	RMK	0.0.1	Updated to 2.1.80.
+ *   15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
+ *   02-05-1998	RMK	0.0.2	Updated & added DMA support.
+ *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *   18-08-1998	RMK	0.0.3	Fixed synchronous transfer depth.
+ *   02-04-2000	RMK	0.0.4	Updated for new error handling code.
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define CUMANASCSI2_STATUS		(0x0000)
+#define STATUS_INT			(1 << 0)
+#define STATUS_DRQ			(1 << 1)
+#define STATUS_LATCHED			(1 << 3)
+
+#define CUMANASCSI2_ALATCH		(0x0014)
+#define ALATCH_ENA_INT			(3)
+#define ALATCH_DIS_INT			(2)
+#define ALATCH_ENA_TERM			(5)
+#define ALATCH_DIS_TERM			(4)
+#define ALATCH_ENA_BIT32		(11)
+#define ALATCH_DIS_BIT32		(10)
+#define ALATCH_ENA_DMA			(13)
+#define ALATCH_DIS_DMA			(12)
+#define ALATCH_DMA_OUT			(15)
+#define ALATCH_DMA_IN			(14)
+
+#define CUMANASCSI2_PSEUDODMA		(0x0200)
+
+#define CUMANASCSI2_FAS216_OFFSET	(0x0300)
+#define CUMANASCSI2_FAS216_SHIFT	2
+
+/*
+ * Version
+ */
+#define VERSION "1.00 (13/11/2002 2.5.47)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct cumanascsi2_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+	void __iomem		*base;
+	unsigned int		terms;		/* Terminator state	*/
+	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
+};
+
+#define CSTATUS_IRQ	(1 << 0)
+#define CSTATUS_DRQ	(1 << 1)
+
+/* Prototype: void cumanascsi_2_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on Cumana SCSI 2 card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr)
+{
+	struct cumanascsi2_info *info = ec->irq_data;
+	writeb(ALATCH_ENA_INT, info->base + CUMANASCSI2_ALATCH);
+}
+
+/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on Cumana SCSI 2 card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	struct cumanascsi2_info *info = ec->irq_data;
+	writeb(ALATCH_DIS_INT, info->base + CUMANASCSI2_ALATCH);
+}
+
+static const expansioncard_ops_t cumanascsi_2_ops = {
+	.irqenable	= cumanascsi_2_irqenable,
+	.irqdisable	= cumanascsi_2_irqdisable,
+};
+
+/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off)
+ * Purpose  : Turn the Cumana SCSI 2 terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+
+	if (on_off) {
+		info->terms = 1;
+		writeb(ALATCH_ENA_TERM, info->base + CUMANASCSI2_ALATCH);
+	} else {
+		info->terms = 0;
+		writeb(ALATCH_DIS_TERM, info->base + CUMANASCSI2_ALATCH);
+	}
+}
+
+/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from Cumana SCSI 2 card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct cumanascsi2_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = info->info.scsi.dma;
+
+	writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH);
+
+	if (dmach != NO_DMA &&
+	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
+		int bufs, map_dir, dma_dir, alatch_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE,
+			alatch_dir = ALATCH_DMA_OUT;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ,
+			alatch_dir = ALATCH_DMA_IN;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		writeb(alatch_dir, info->base + CUMANASCSI2_ALATCH);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		writeb(ALATCH_ENA_DMA, info->base + CUMANASCSI2_ALATCH);
+		writeb(ALATCH_DIS_BIT32, info->base + CUMANASCSI2_ALATCH);
+		return fasdma_real_all;
+	}
+
+	/*
+	 * If we're not doing DMA,
+	 *  we'll do pseudo DMA
+	 */
+	return fasdma_pio;
+}
+
+/*
+ * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose  : handles pseudo DMA
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      transfer  - minimum number of bytes we expect to transfer
+ */
+static void
+cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+			fasdmadir_t direction, int transfer)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	unsigned int length;
+	unsigned char *addr;
+
+	length = SCp->this_residual;
+	addr = SCp->ptr;
+
+	if (direction == DMA_OUT)
+#if 0
+		while (length > 1) {
+			unsigned long word;
+			unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
+
+			if (status & STATUS_INT)
+				goto end;
+
+			if (!(status & STATUS_DRQ))
+				continue;
+
+			word = *addr | *(addr + 1) << 8;
+			writew(word, info->base + CUMANASCSI2_PSEUDODMA);
+			addr += 2;
+			length -= 2;
+		}
+#else
+		printk ("PSEUDO_OUT???\n");
+#endif
+	else {
+		if (transfer && (transfer & 255)) {
+			while (length >= 256) {
+				unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
+
+				if (status & STATUS_INT)
+					return;
+	    
+				if (!(status & STATUS_DRQ))
+					continue;
+
+				readsw(info->base + CUMANASCSI2_PSEUDODMA,
+				       addr, 256 >> 1);
+				addr += 256;
+				length -= 256;
+			}
+		}
+
+		while (length > 0) {
+			unsigned long word;
+			unsigned int status = readb(info->base + CUMANASCSI2_STATUS);
+
+			if (status & STATUS_INT)
+				return;
+
+			if (!(status & STATUS_DRQ))
+				continue;
+
+			word = readw(info->base + CUMANASCSI2_PSEUDODMA);
+			*addr++ = word;
+			if (--length > 0) {
+				*addr++ = word >> 8;
+				length --;
+			}
+		}
+	}
+}
+
+/* Prototype: int cumanascsi_2_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	if (info->info.scsi.dma != NO_DMA) {
+		writeb(ALATCH_DIS_DMA, info->base + CUMANASCSI2_ALATCH);
+		disable_dma(info->info.scsi.dma);
+	}
+}
+
+/* Prototype: const char *cumanascsi_2_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *cumanascsi_2_info(struct Scsi_Host *host)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->terms ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 11 && strcmp(buffer, "CUMANASCSI2") == 0) {
+		buffer += 11;
+		length -= 11;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				cumanascsi_2_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				cumanascsi_2_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset,
+ *					 int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer - a buffer to write information to
+ *	      start  - a pointer into this buffer set by this routine to the start
+ *		       of the required information.
+ *	      offset - offset into information that we have read upto.
+ *	      length - length of buffer
+ *	      host_no - host number to return information for
+ *	      inout  - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int cumanascsi_2_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			    int length, int inout)
+{
+	struct cumanascsi2_info *info;
+	char *p = buffer;
+	int pos;
+
+	if (inout == 1)
+		return cumanascsi_2_set_proc_info(host, buffer, length);
+
+	info = (struct cumanascsi2_info *)host->hostdata;
+
+	p += sprintf(p, "Cumana SCSI II driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->terms ? "n" : "ff");
+
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static Scsi_Host_Template cumanascsi2_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= cumanascsi_2_proc_info,
+	.name				= "Cumana SCSI II",
+	.info				= cumanascsi_2_info,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "cumanascsi2",
+};
+
+static int __devinit
+cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct cumanascsi2_info *info;
+	unsigned long resbase, reslen;
+	void __iomem *base;
+	int ret;
+
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_host_alloc(&cumanascsi2_template,
+			       sizeof(struct cumanascsi2_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct cumanascsi2_info *)host->hostdata;
+	info->ec	= ec;
+	info->base	= base;
+
+	cumanascsi_2_terminator_ctl(host, term[ec->slot_no]);
+
+	info->info.scsi.io_base		= base + CUMANASCSI2_FAS216_OFFSET;
+	info->info.scsi.io_shift	= CUMANASCSI2_FAS216_SHIFT;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= cumanascsi_2_dma_setup;
+	info->info.dma.pseudo		= cumanascsi_2_dma_pseudo;
+	info->info.dma.stop		= cumanascsi_2_dma_stop;
+
+	ec->irqaddr	= info->base + CUMANASCSI2_STATUS;
+	ec->irqmask	= STATUS_INT;
+	ec->irq_data	= info;
+	ec->ops		= &cumanascsi_2_ops;
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(ec->irq, cumanascsi_2_intr,
+			  SA_INTERRUPT, "cumanascsi2", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, ec->irq, ret);
+		goto out_release;
+	}
+
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "cumanascsi2")) {
+			printk("scsi%d: DMA%d not free, using PIO\n",
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
+		} else {
+			set_dma_speed(info->info.scsi.dma, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
+
+ out_release:
+	fas216_release(host);
+
+ out_free:
+	scsi_host_put(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	ecard_release_resources(ec);
+
+ out:
+	return ret;
+}
+
+static void __devexit cumanascsi2_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
+
+	iounmap(info->base);
+
+	fas216_release(host);
+	scsi_host_put(host);
+	ecard_release_resources(ec);
+}
+
+static const struct ecard_id cumanascsi2_cids[] = {
+	{ MANU_CUMANA, PROD_CUMANA_SCSI_2 },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver cumanascsi2_driver = {
+	.probe		= cumanascsi2_probe,
+	.remove		= __devexit_p(cumanascsi2_remove),
+	.id_table	= cumanascsi2_cids,
+	.drv = {
+		.name		= "cumanascsi2",
+	},
+};
+
+static int __init cumanascsi2_init(void)
+{
+	return ecard_register_driver(&cumanascsi2_driver);
+}
+
+static void __exit cumanascsi2_exit(void)
+{
+	ecard_remove_driver(&cumanascsi2_driver);
+}
+
+module_init(cumanascsi2_init);
+module_exit(cumanascsi2_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
new file mode 100644
index 0000000..303648a
--- /dev/null
+++ b/drivers/scsi/arm/ecoscsi.c
@@ -0,0 +1,239 @@
+#define AUTOSENSE
+/* #define PSEUDO_DMA */
+
+/*
+ * EcoSCSI Generic NCR5380 driver
+ *
+ * Copyright 1995, Russell King
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+
+#define NCR5380_read(reg)		ecoscsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	ecoscsi_write(_instance, reg, value)
+
+#define NCR5380_intr			ecoscsi_intr
+#define NCR5380_queue_command		ecoscsi_queue_command
+#define NCR5380_proc_info		ecoscsi_proc_info
+
+#include "../NCR5380.h"
+
+#define ECOSCSI_PUBLIC_RELEASE 1
+
+static char ecoscsi_read(struct Scsi_Host *instance, int reg)
+{
+  int iobase = instance->io_port;
+  outb(reg | 8, iobase);
+  return inb(iobase + 1);
+}
+
+static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  int iobase = instance->io_port;
+  outb(reg | 8, iobase);
+  outb(value, iobase + 1);
+}
+
+/*
+ * Function : ecoscsi_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ */
+
+void ecoscsi_setup(char *str, int *ints)
+{
+}
+
+const char * ecoscsi_info (struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#if 0
+#define STAT(p) inw(p + 144)
+
+static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
+              int len)
+{
+  int iobase = host->io_port;
+printk("writing %p len %d\n",addr, len);
+  if(!len) return -1;
+
+  while(1)
+  {
+    int status;
+    while(((status = STAT(iobase)) & 0x100)==0);
+  }
+}
+
+static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
+              int len)
+{
+  int iobase = host->io_port;
+  int iobase2= host->io_port + 0x100;
+  unsigned char *start = addr;
+  int s;
+printk("reading %p len %d\n",addr, len);
+  outb(inb(iobase + 128), iobase + 135);
+  while(len > 0)
+  {
+    int status,b,i, timeout;
+    timeout = 0x07FFFFFF;
+    while(((status = STAT(iobase)) & 0x100)==0)
+    {
+      timeout--;
+      if(status & 0x200 || !timeout)
+      {
+        printk("status = %p\n",status);
+        outb(0, iobase + 135);
+        return 1;
+      }
+    }
+    if(len >= 128)
+    {
+      for(i=0; i<64; i++)
+      {
+        b = inw(iobase + 136);
+        *addr++ = b;
+        *addr++ = b>>8;
+      }
+      len -= 128;
+    }
+    else
+    {
+      b = inw(iobase + 136);
+      *addr ++ = b;
+      len -= 1;
+      if(len)
+        *addr ++ = b>>8;
+      len -= 1;
+    }
+  }
+  outb(0, iobase + 135);
+  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
+  return 1;
+}
+#endif
+#undef STAT
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template ecoscsi_template =  {
+	.module		= THIS_MODULE,
+	.name		= "Serial Port EcoSCSI NCR5380",
+	.proc_name	= "ecoscsi",
+	.info		= ecoscsi_info,
+	.queuecommand	= ecoscsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue	= 16,
+	.this_id	= 7,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun	= 2,
+	.use_clustering	= DISABLE_CLUSTERING
+};
+
+static struct Scsi_Host *host;
+
+static int __init ecoscsi_init(void)
+{
+
+	host = scsi_host_alloc(tpnt, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		return 0;
+
+	host->io_port = 0x80ce8000;
+	host->n_io_port = 144;
+	host->irq = IRQ_NONE;
+
+	if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
+		goto unregister_scsi;
+
+	ecoscsi_write(host, MODE_REG, 0x20);		/* Is it really SCSI? */
+	if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg.    */
+		goto release_reg;
+
+	ecoscsi_write(host, MODE_REG, 0x00 );		/* it back.	      */
+	if (ecoscsi_read(host, MODE_REG) != 0x00)
+		goto release_reg;
+
+	NCR5380_init(host, 0);
+
+	printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	scsi_add_host(host, NULL); /* XXX handle failure */
+	scsi_scan_host(host);
+	return 0;
+
+release_reg:
+	release_region(host->io_port, host->n_io_port);
+unregister_scsi:
+	scsi_host_put(host);
+	return -ENODEV;
+}
+
+static void __exit ecoscsi_exit(void)
+{
+	scsi_remove_host(host);
+
+	if (shpnt->irq != IRQ_NONE)
+		free_irq(shpnt->irq, NULL);
+	NCR5380_exit(host);
+	if (shpnt->io_port)
+		release_region(shpnt->io_port, shpnt->n_io_port);
+
+	scsi_host_put(host);
+	return 0;
+}
+
+module_init(ecoscsi_init);
+module_exit(ecoscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
new file mode 100644
index 0000000..78b7e54
--- /dev/null
+++ b/drivers/scsi/arm/eesox.c
@@ -0,0 +1,680 @@
+/*
+ *  linux/drivers/acorn/scsi/eesox.c
+ *
+ *  Copyright (C) 1997-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  This driver is based on experimentation.  Hence, it may have made
+ *  assumptions about the particular card that I have available, and
+ *  may not be reliable!
+ *
+ *  Changelog:
+ *   01-10-1997	RMK		Created, READONLY version
+ *   15-02-1998	RMK		READ/WRITE version
+ *				added DMA support and hardware definitions
+ *   14-03-1998	RMK		Updated DMA support
+ *				Added terminator control
+ *   15-04-1998	RMK		Only do PIO if FAS216 will allow it.
+ *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *   02-04-2000	RMK	0.0.3	Fixed NO_IRQ/NO_DMA problem, updated for new
+ *				error handling code.
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define EESOX_FAS216_OFFSET	0x3000
+#define EESOX_FAS216_SHIFT	5
+
+#define EESOX_DMASTAT		0x2800
+#define EESOX_STAT_INTR		0x01
+#define EESOX_STAT_DMA		0x02
+
+#define EESOX_CONTROL		0x2800
+#define EESOX_INTR_ENABLE	0x04
+#define EESOX_TERM_ENABLE	0x02
+#define EESOX_RESET		0x01
+
+#define EESOX_DMADATA		0x3800
+
+#define VERSION "1.10 (17/01/2003 2.5.59)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct eesoxscsi_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+	void __iomem		*base;
+	void __iomem		*ctl_port;
+	unsigned int		control;
+	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
+};
+
+/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on EESOX SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
+
+	info->control |= EESOX_INTR_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+}
+
+/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on EESOX SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
+
+	info->control &= ~EESOX_INTR_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+}
+
+static const expansioncard_ops_t eesoxscsi_ops = {
+	.irqenable	= eesoxscsi_irqenable,
+	.irqdisable	= eesoxscsi_irqdisable,
+};
+
+/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
+ * Purpose  : Turn the EESOX SCSI terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	if (on_off)
+		info->control |= EESOX_TERM_ENABLE;
+	else
+		info->control &= ~EESOX_TERM_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+	spin_unlock_irqrestore(host->host_lock, flags);
+}
+
+/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from EESOX SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct eesoxscsi_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = info->info.scsi.dma;
+
+	if (dmach != NO_DMA &&
+	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
+		int bufs, map_dir, dma_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		return fasdma_real_all;
+	}
+	/*
+	 * We don't do DMA, we only do slow PIO
+	 *
+	 * Some day, we will do Pseudo DMA
+	 */
+	return fasdma_pseudo;
+}
+
+static void eesoxscsi_buffer_in(void *buf, int length, void __iomem *base)
+{
+	const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
+	const void __iomem *reg_dmadata = base + EESOX_DMADATA;
+	const register unsigned long mask = 0xffff;
+
+	do {
+		unsigned int status;
+
+		/*
+		 * Interrupt request?
+		 */
+		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
+		if (status & STAT_INT)
+			break;
+
+		/*
+		 * DMA request active?
+		 */
+		status = readb(reg_dmastat);
+		if (!(status & EESOX_STAT_DMA))
+			continue;
+
+		/*
+		 * Get number of bytes in FIFO
+		 */
+		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
+		if (status > 16)
+			status = 16;
+		if (status > length)
+			status = length;
+
+		/*
+		 * Align buffer.
+		 */
+		if (((u32)buf) & 2 && status >= 2) {
+			*(u16 *)buf = readl(reg_dmadata);
+			buf += 2;
+			status -= 2;
+			length -= 2;
+		}
+
+		if (status >= 8) {
+			unsigned long l1, l2;
+
+			l1 = readl(reg_dmadata) & mask;
+			l1 |= readl(reg_dmadata) << 16;
+			l2 = readl(reg_dmadata) & mask;
+			l2 |= readl(reg_dmadata) << 16;
+			*(u32 *)buf = l1;
+			buf += 4;
+			*(u32 *)buf = l2;
+			buf += 4;
+			length -= 8;
+			continue;
+		}
+
+		if (status >= 4) {
+			unsigned long l1;
+
+			l1 = readl(reg_dmadata) & mask;
+			l1 |= readl(reg_dmadata) << 16;
+
+			*(u32 *)buf = l1;
+			buf += 4;
+			length -= 4;
+			continue;
+		}
+
+		if (status >= 2) {
+			*(u16 *)buf = readl(reg_dmadata);
+			buf += 2;
+			length -= 2;
+		}
+	} while (length);
+}
+
+static void eesoxscsi_buffer_out(void *buf, int length, void __iomem *base)
+{
+	const void __iomem *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void __iomem *reg_dmastat = base + EESOX_DMASTAT;
+	const void __iomem *reg_dmadata = base + EESOX_DMADATA;
+
+	do {
+		unsigned int status;
+
+		/*
+		 * Interrupt request?
+		 */
+		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
+		if (status & STAT_INT)
+			break;
+
+		/*
+		 * DMA request active?
+		 */
+		status = readb(reg_dmastat);
+		if (!(status & EESOX_STAT_DMA))
+			continue;
+
+		/*
+		 * Get number of bytes in FIFO
+		 */
+		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
+		if (status > 16)
+			status = 16;
+		status = 16 - status;
+		if (status > length)
+			status = length;
+		status &= ~1;
+
+		/*
+		 * Align buffer.
+		 */
+		if (((u32)buf) & 2 && status >= 2) {
+			writel(*(u16 *)buf << 16, reg_dmadata);
+			buf += 2;
+			status -= 2;
+			length -= 2;
+		}
+
+		if (status >= 8) {
+			unsigned long l1, l2;
+
+			l1 = *(u32 *)buf;
+			buf += 4;
+			l2 = *(u32 *)buf;
+			buf += 4;
+
+			writel(l1 << 16, reg_dmadata);
+			writel(l1, reg_dmadata);
+			writel(l2 << 16, reg_dmadata);
+			writel(l2, reg_dmadata);
+			length -= 8;
+			continue;
+		}
+
+		if (status >= 4) {
+			unsigned long l1;
+
+			l1 = *(u32 *)buf;
+			buf += 4;
+
+			writel(l1 << 16, reg_dmadata);
+			writel(l1, reg_dmadata);
+			length -= 4;
+			continue;
+		}
+
+		if (status >= 2) {
+			writel(*(u16 *)buf << 16, reg_dmadata);
+			buf += 2;
+			length -= 2;
+		}
+	} while (length);
+}
+
+static void
+eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		     fasdmadir_t dir, int transfer_size)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	if (dir == DMA_IN) {
+		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, info->base);
+	} else {
+		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, info->base);
+	}
+}
+
+/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	if (info->info.scsi.dma != NO_DMA)
+		disable_dma(info->info.scsi.dma);
+}
+
+/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *eesoxscsi_info(struct Scsi_Host *host)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
+		buffer += 9;
+		length -= 9;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				eesoxscsi_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				eesoxscsi_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
+ *				      int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer - a buffer to write information to
+ *	      start  - a pointer into this buffer set by this routine to the start
+ *		       of the required information.
+ *	      offset - offset into information that we have read upto.
+ *	      length - length of buffer
+ *	      host_no - host number to return information for
+ *	      inout  - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			    int length, int inout)
+{
+	struct eesoxscsi_info *info;
+	char *p = buffer;
+	int pos;
+
+	if (inout == 1)
+		return eesoxscsi_set_proc_info(host, buffer, length);
+
+	info = (struct eesoxscsi_info *)host->hostdata;
+
+	p += sprintf(p, "EESOX SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static ssize_t eesoxscsi_show_term(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+
+	return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0);
+}
+
+static ssize_t eesoxscsi_store_term(struct device *dev, const char *buf, size_t len)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	unsigned long flags;
+
+	if (len > 1) {
+		spin_lock_irqsave(host->host_lock, flags);
+		if (buf[0] != '0') {
+			info->control |= EESOX_TERM_ENABLE;
+		} else {
+			info->control &= ~EESOX_TERM_ENABLE;
+		}
+		writeb(info->control, info->ctl_port);
+		spin_unlock_irqrestore(host->host_lock, flags);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
+		   eesoxscsi_show_term, eesoxscsi_store_term);
+
+static Scsi_Host_Template eesox_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= eesoxscsi_proc_info,
+	.name				= "EESOX SCSI",
+	.info				= eesoxscsi_info,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "eesox",
+};
+
+static int __devinit
+eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct eesoxscsi_info *info;
+	unsigned long resbase, reslen;
+	void __iomem *base;
+	int ret;
+
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_host_alloc(&eesox_template,
+			       sizeof(struct eesoxscsi_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct eesoxscsi_info *)host->hostdata;
+	info->ec	= ec;
+	info->base	= base;
+	info->ctl_port	= base + EESOX_CONTROL;
+	info->control	= term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
+	writeb(info->control, info->ctl_port);
+
+	info->info.scsi.io_base		= base + EESOX_FAS216_OFFSET;
+	info->info.scsi.io_shift	= EESOX_FAS216_SHIFT;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= eesoxscsi_dma_setup;
+	info->info.dma.pseudo		= eesoxscsi_dma_pseudo;
+	info->info.dma.stop		= eesoxscsi_dma_stop;
+
+	ec->irqaddr	= base + EESOX_DMASTAT;
+	ec->irqmask	= EESOX_STAT_INTR;
+	ec->irq_data	= info;
+	ec->ops		= &eesoxscsi_ops;
+
+	device_create_file(&ec->dev, &dev_attr_bus_term);
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(ec->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, ec->irq, ret);
+		goto out_remove;
+	}
+
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "eesox")) {
+			printk("scsi%d: DMA%d not free, DMA disabled\n",
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
+		} else {
+			set_dma_speed(info->info.scsi.dma, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+			info->info.ifcfg.cntl3 |= CNTL3_BS8;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
+
+ out_remove:
+	fas216_remove(host);
+
+ out_free:
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+	scsi_host_put(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	ecard_release_resources(ec);
+
+ out:
+	return ret;
+}
+
+static void __devexit eesoxscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
+
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+
+	iounmap(info->base);
+
+	fas216_release(host);
+	scsi_host_put(host);
+	ecard_release_resources(ec);
+}
+
+static const struct ecard_id eesoxscsi_cids[] = {
+	{ MANU_EESOX, PROD_EESOX_SCSI2 },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver eesoxscsi_driver = {
+	.probe		= eesoxscsi_probe,
+	.remove		= __devexit_p(eesoxscsi_remove),
+	.id_table	= eesoxscsi_cids,
+	.drv = {
+		.name		= "eesoxscsi",
+	},
+};
+
+static int __init eesox_init(void)
+{
+	return ecard_register_driver(&eesoxscsi_driver);
+}
+
+static void __exit eesox_exit(void)
+{
+	ecard_remove_driver(&eesoxscsi_driver);
+}
+
+module_init(eesox_init);
+module_exit(eesox_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
new file mode 100644
index 0000000..5411e85
--- /dev/null
+++ b/drivers/scsi/arm/fas216.c
@@ -0,0 +1,3043 @@
+/*
+ *  linux/drivers/acorn/scsi/fas216.c
+ *
+ *  Copyright (C) 1997-2003 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
+ * other sources, including:
+ *   the AMD Am53CF94 data sheet
+ *   the AMD Am53C94 data sheet
+ *
+ * This is a generic driver.  To use it, have a look at cumana_2.c.  You
+ * should define your own structure that overlays FAS216_Info, eg:
+ * struct my_host_data {
+ *    FAS216_Info info;
+ *    ... my host specific data ...
+ * };
+ *
+ * Changelog:
+ *  30-08-1997	RMK	Created
+ *  14-09-1997	RMK	Started disconnect support
+ *  08-02-1998	RMK	Corrected real DMA support
+ *  15-02-1998	RMK	Started sync xfer support
+ *  06-04-1998	RMK	Tightened conditions for printing incomplete
+ *			transfers
+ *  02-05-1998	RMK	Added extra checks in fas216_reset
+ *  24-05-1998	RMK	Fixed synchronous transfers with period >= 200ns
+ *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
+ *  26-08-1998	RMK	Improved message support wrt MESSAGE_REJECT
+ *  02-04-2000	RMK	Converted to use the new error handling, and
+ *			automatically request sense data upon check
+ *			condition status from targets.
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "fas216.h"
+#include "scsi.h"
+
+/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
+ *  the data sheet.  This restriction is crazy, especially when
+ *  you only want to send 16 bytes!  What were the guys who
+ *  designed this chip on at that time?  Did they read the SCSI2
+ *  spec at all?  The following sections are taken from the SCSI2
+ *  standard (s2r10) concerning this:
+ *
+ * > IMPLEMENTORS NOTES:
+ * >   (1)  Re-negotiation at every selection is not recommended, since a
+ * >   significant performance impact is likely.
+ *
+ * >  The implied synchronous agreement shall remain in effect until a BUS DEVICE
+ * >  RESET message is received, until a hard reset condition occurs, or until one
+ * >  of the two SCSI devices elects to modify the agreement.  The default data
+ * >  transfer mode is asynchronous data transfer mode.  The default data transfer
+ * >  mode is entered at power on, after a BUS DEVICE RESET message, or after a hard
+ * >  reset condition.
+ *
+ *  In total, this means that once you have elected to use synchronous
+ *  transfers, you must always use DMA.
+ *
+ *  I was thinking that this was a good chip until I found this restriction ;(
+ */
+#define SCSI2_SYNC
+#undef  SCSI2_TAG
+
+#undef DEBUG_CONNECT
+#undef DEBUG_MESSAGES
+
+#undef CHECK_STRUCTURE
+
+#define LOG_CONNECT		(1 << 0)
+#define LOG_BUSSERVICE		(1 << 1)
+#define LOG_FUNCTIONDONE	(1 << 2)
+#define LOG_MESSAGES		(1 << 3)
+#define LOG_BUFFER		(1 << 4)
+#define LOG_ERROR		(1 << 8)
+
+static int level_mask = LOG_ERROR;
+
+module_param(level_mask, int, 0644);
+
+static int __init fas216_log_setup(char *str)
+{
+	char *s;
+
+	level_mask = 0;
+
+	while ((s = strsep(&str, ",")) != NULL) {
+		switch (s[0]) {
+		case 'a':
+			if (strcmp(s, "all") == 0)
+				level_mask |= -1;
+			break;
+		case 'b':
+			if (strncmp(s, "bus", 3) == 0)
+				level_mask |= LOG_BUSSERVICE;
+			if (strncmp(s, "buf", 3) == 0)
+				level_mask |= LOG_BUFFER;
+			break;
+		case 'c':
+			level_mask |= LOG_CONNECT;
+			break;
+		case 'e':
+			level_mask |= LOG_ERROR;
+			break;
+		case 'm':
+			level_mask |= LOG_MESSAGES;
+			break;
+		case 'n':
+			if (strcmp(s, "none") == 0)
+				level_mask = 0;
+			break;
+		case 's':
+			level_mask |= LOG_FUNCTIONDONE;
+			break;
+		}
+	}
+	return 1;
+}
+
+__setup("fas216_logging=", fas216_log_setup);
+
+static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
+{
+	unsigned int off = reg << info->scsi.io_shift;
+	return readb(info->scsi.io_base + off);
+}
+
+static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val)
+{
+	unsigned int off = reg << info->scsi.io_shift;
+	writeb(val, info->scsi.io_base + off);
+}
+
+static void fas216_dumpstate(FAS216_Info *info)
+{
+	unsigned char is, stat, inst;
+
+	is   = fas216_readb(info, REG_IS);
+	stat = fas216_readb(info, REG_STAT);
+	inst = fas216_readb(info, REG_INST);
+	
+	printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"
+	       " INST=%02X IS=%02X CFIS=%02X",
+		fas216_readb(info, REG_CTCL),
+		fas216_readb(info, REG_CTCM),
+		fas216_readb(info, REG_CMD),  stat, inst, is,
+		fas216_readb(info, REG_CFIS));
+	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",
+		fas216_readb(info, REG_CNTL1),
+		fas216_readb(info, REG_CNTL2),
+		fas216_readb(info, REG_CNTL3),
+		fas216_readb(info, REG_CTCH));
+}
+
+static void print_SCp(Scsi_Pointer *SCp, const char *prefix, const char *suffix)
+{
+	printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s",
+		prefix, SCp->ptr, SCp->this_residual, SCp->buffer,
+		SCp->buffers_residual, suffix);
+}
+
+static void fas216_dumpinfo(FAS216_Info *info)
+{
+	static int used = 0;
+	int i;
+
+	if (used++)
+		return;
+
+	printk("FAS216_Info=\n");
+	printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",
+		info->magic_start, info->host, info->SCpnt,
+		info->origSCpnt);
+	printk("    scsi={ io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
+		info->scsi.io_shift, info->scsi.irq,
+		info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],
+		info->scsi.cfg[3]);
+	printk("           type=%p phase=%X\n",
+		info->scsi.type, info->scsi.phase);
+	print_SCp(&info->scsi.SCp, "           SCp={ ", " }\n");
+	printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",
+		info->scsi.async_stp,
+		info->scsi.disconnectable, info->scsi.aborting);
+	printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
+	       "            disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
+		info->stats.queues, info->stats.removes, info->stats.fins,
+		info->stats.reads, info->stats.writes, info->stats.miscs,
+		info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
+		info->stats.host_resets);
+	printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
+		info->ifcfg.clockrate, info->ifcfg.select_timeout,
+		info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
+	for (i = 0; i < 8; i++) {
+		printk("    busyluns[%d]=%08lx dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
+			i, info->busyluns[i], i,
+			info->device[i].disconnect_ok, info->device[i].stp,
+			info->device[i].sof, info->device[i].sync_state);
+	}
+	printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
+		info->dma.transfer_type, info->dma.setup,
+		info->dma.pseudo, info->dma.stop);
+	printk("    internal_done=%X magic_end=%lX }\n",
+		info->internal_done, info->magic_end);
+}
+
+#ifdef CHECK_STRUCTURE
+static void __fas216_checkmagic(FAS216_Info *info, const char *func)
+{
+	int corruption = 0;
+	if (info->magic_start != MAGIC) {
+		printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n");
+		corruption++;
+	}
+	if (info->magic_end != MAGIC) {
+		printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n");
+		corruption++;
+	}
+	if (corruption) {
+		fas216_dumpinfo(info);
+		panic("scsi memory space corrupted in %s", func);
+	}
+}
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
+#else
+#define fas216_checkmagic(info)
+#endif
+
+static const char *fas216_bus_phase(int stat)
+{
+	static const char *phases[] = {
+		"DATA OUT", "DATA IN",
+		"COMMAND", "STATUS",
+		"MISC OUT", "MISC IN",
+		"MESG OUT", "MESG IN"
+	};
+
+	return phases[stat & STAT_BUSMASK];
+}
+
+static const char *fas216_drv_phase(FAS216_Info *info)
+{
+	static const char *phases[] = {
+		[PHASE_IDLE]		= "idle",
+		[PHASE_SELECTION]	= "selection",
+		[PHASE_COMMAND]		= "command",
+		[PHASE_DATAOUT]		= "data out",
+		[PHASE_DATAIN]		= "data in",
+		[PHASE_MSGIN]		= "message in",
+		[PHASE_MSGIN_DISCONNECT]= "disconnect",
+		[PHASE_MSGOUT_EXPECT]	= "expect message out",
+		[PHASE_MSGOUT]		= "message out",
+		[PHASE_STATUS]		= "status",
+		[PHASE_DONE]		= "done",
+	};
+
+	if (info->scsi.phase < ARRAY_SIZE(phases) &&
+	    phases[info->scsi.phase])
+		return phases[info->scsi.phase];
+	return "???";
+}
+
+static char fas216_target(FAS216_Info *info)
+{
+	if (info->SCpnt)
+		return '0' + info->SCpnt->device->id;
+	else
+		return 'H';
+}
+
+static void
+fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
+{
+	static char buf[1024];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	printk("scsi%d.%c: %s", info->host->host_no, target, buf);
+}
+
+static void
+fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	va_start(args, fmt);
+	fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);
+	va_end(args);
+
+	printk(" CDB: ");
+	print_command(SCpnt->cmnd);
+}
+
+static void
+fas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	if (target < 0)
+		target = 'H';
+	else
+		target += '0';
+
+	va_start(args, fmt);
+	fas216_do_log(info, target, fmt, args);
+	va_end(args);
+
+	printk("\n");
+}
+
+static void fas216_log(FAS216_Info *info, int level, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	va_start(args, fmt);
+	fas216_do_log(info, fas216_target(info), fmt, args);
+	va_end(args);
+
+	printk("\n");
+}
+
+#define PH_SIZE	32
+
+static struct { int stat, ssr, isr, ph; } ph_list[PH_SIZE];
+static int ph_ptr;
+
+static void add_debug_list(int stat, int ssr, int isr, int ph)
+{
+	ph_list[ph_ptr].stat = stat;
+	ph_list[ph_ptr].ssr = ssr;
+	ph_list[ph_ptr].isr = isr;
+	ph_list[ph_ptr].ph = ph;
+
+	ph_ptr = (ph_ptr + 1) & (PH_SIZE-1);
+}
+
+static struct { int command; void *from; } cmd_list[8];
+static int cmd_ptr;
+
+static void fas216_cmd(FAS216_Info *info, unsigned int command)
+{
+	cmd_list[cmd_ptr].command = command;
+	cmd_list[cmd_ptr].from = __builtin_return_address(0);
+
+	cmd_ptr = (cmd_ptr + 1) & 7;
+
+	fas216_writeb(info, REG_CMD, command);
+}
+
+static void print_debug_list(void)
+{
+	int i;
+
+	i = ph_ptr;
+
+	printk(KERN_ERR "SCSI IRQ trail\n");
+	do {
+		printk(" %02x:%02x:%02x:%1x",
+			ph_list[i].stat, ph_list[i].ssr,
+			ph_list[i].isr, ph_list[i].ph);
+		i = (i + 1) & (PH_SIZE - 1);
+		if (((i ^ ph_ptr) & 7) == 0)
+			printk("\n");
+	} while (i != ph_ptr);
+	if ((i ^ ph_ptr) & 7)
+		printk("\n");
+
+	i = cmd_ptr;
+	printk(KERN_ERR "FAS216 commands: ");
+	do {
+		printk("%02x:%p ", cmd_list[i].command, cmd_list[i].from);
+		i = (i + 1) & 7;
+	} while (i != cmd_ptr);
+	printk("\n");
+}
+
+static void fas216_done(FAS216_Info *info, unsigned int result);
+
+/**
+ * fas216_get_last_msg - retrive last message from the list
+ * @info: interface to search
+ * @pos: current fifo position
+ *
+ * Retrieve a last message from the list, using position in fifo.
+ */
+static inline unsigned short
+fas216_get_last_msg(FAS216_Info *info, int pos)
+{
+	unsigned short packed_msg = NOP;
+	struct message *msg;
+	int msgnr = 0;
+
+	while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+		if (pos >= msg->fifo)
+			break;
+	}
+
+	if (msg) {
+		if (msg->msg[0] == EXTENDED_MESSAGE)
+			packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
+		else
+			packed_msg = msg->msg[0];
+	}
+
+	fas216_log(info, LOG_MESSAGES,
+		"Message: %04x found at position %02x\n", packed_msg, pos);
+
+	return packed_msg;
+}
+
+/**
+ * fas216_syncperiod - calculate STP register value
+ * @info: state structure for interface connected to device
+ * @ns: period in ns (between subsequent bytes)
+ *
+ * Calculate value to be loaded into the STP register for a given period
+ * in ns. Returns a value suitable for REG_STP.
+ */
+static int fas216_syncperiod(FAS216_Info *info, int ns)
+{
+	int value = (info->ifcfg.clockrate * ns) / 1000;
+
+	fas216_checkmagic(info);
+
+	if (value < 4)
+		value = 4;
+	else if (value > 35)
+		value = 35;
+
+	return value & 31;
+}
+
+/**
+ * fas216_set_sync - setup FAS216 chip for specified transfer period.
+ * @info: state structure for interface connected to device
+ * @target: target
+ *
+ * Correctly setup FAS216 chip for specified transfer period.
+ * Notes   : we need to switch the chip out of FASTSCSI mode if we have
+ *           a transfer period >= 200ns - otherwise the chip will violate
+ *           the SCSI timings.
+ */
+static void fas216_set_sync(FAS216_Info *info, int target)
+{
+	unsigned int cntl3;
+
+	fas216_writeb(info, REG_SOF, info->device[target].sof);
+	fas216_writeb(info, REG_STP, info->device[target].stp);
+
+	cntl3 = info->scsi.cfg[2];
+	if (info->device[target].period >= (200 / 4))
+		cntl3 = cntl3 & ~CNTL3_FASTSCSI;
+
+	fas216_writeb(info, REG_CNTL3, cntl3);
+}
+
+/* Synchronous transfer support
+ *
+ * Note: The SCSI II r10 spec says (5.6.12):
+ *
+ *  (2)  Due to historical problems with early host adapters that could
+ *  not accept an SDTR message, some targets may not initiate synchronous
+ *  negotiation after a power cycle as required by this standard.  Host
+ *  adapters that support synchronous mode may avoid the ensuing failure
+ *  modes when the target is independently power cycled by initiating a
+ *  synchronous negotiation on each REQUEST SENSE and INQUIRY command.
+ *  This approach increases the SCSI bus overhead and is not recommended
+ *  for new implementations.  The correct method is to respond to an
+ *  SDTR message with a MESSAGE REJECT message if the either the
+ *  initiator or target devices does not support synchronous transfers
+ *  or does not want to negotiate for synchronous transfers at the time.
+ *  Using the correct method assures compatibility with wide data
+ *  transfers and future enhancements.
+ *
+ * We will always initiate a synchronous transfer negotiation request on
+ * every INQUIRY or REQUEST SENSE message, unless the target itself has
+ * at some point performed a synchronous transfer negotiation request, or
+ * we have synchronous transfers disabled for this device.
+ */
+
+/**
+ * fas216_handlesync - Handle a synchronous transfer message
+ * @info: state structure for interface
+ * @msg: message from target
+ *
+ * Handle a synchronous transfer message from the target
+ */
+static void fas216_handlesync(FAS216_Info *info, char *msg)
+{
+	struct fas216_device *dev = &info->device[info->SCpnt->device->id];
+	enum { sync, async, none, reject } res = none;
+
+#ifdef SCSI2_SYNC
+	switch (msg[0]) {
+	case MESSAGE_REJECT:
+		/* Synchronous transfer request failed.
+		 * Note: SCSI II r10:
+		 *
+		 *  SCSI devices that are capable of synchronous
+		 *  data transfers shall not respond to an SDTR
+		 *  message with a MESSAGE REJECT message.
+		 *
+		 * Hence, if we get this condition, we disable
+		 * negotiation for this device.
+		 */
+		if (dev->sync_state == neg_inprogress) {
+			dev->sync_state = neg_invalid;
+			res = async;
+		}
+		break;
+
+	case EXTENDED_MESSAGE:
+		switch (dev->sync_state) {
+		/* We don't accept synchronous transfer requests.
+		 * Respond with a MESSAGE_REJECT to prevent a
+		 * synchronous transfer agreement from being reached.
+		 */
+		case neg_invalid:
+			res = reject;
+			break;
+
+		/* We were not negotiating a synchronous transfer,
+		 * but the device sent us a negotiation request.
+		 * Honour the request by sending back a SDTR
+		 * message containing our capability, limited by
+		 * the targets capability.
+		 */
+		default:
+			fas216_cmd(info, CMD_SETATN);
+			if (msg[4] > info->ifcfg.sync_max_depth)
+				msg[4] = info->ifcfg.sync_max_depth;
+			if (msg[3] < 1000 / info->ifcfg.clockrate)
+				msg[3] = 1000 / info->ifcfg.clockrate;
+
+			msgqueue_flush(&info->scsi.msgs);
+			msgqueue_addmsg(&info->scsi.msgs, 5,
+					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+					msg[3], msg[4]);
+			info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+			/* This is wrong.  The agreement is not in effect
+			 * until this message is accepted by the device
+			 */
+			dev->sync_state = neg_targcomplete;
+			res = sync;
+			break;
+
+		/* We initiated the synchronous transfer negotiation,
+		 * and have successfully received a response from the
+		 * target.  The synchronous transfer agreement has been
+		 * reached.  Note: if the values returned are out of our
+		 * bounds, we must reject the message.
+		 */
+		case neg_inprogress:
+			res = reject;
+			if (msg[4] <= info->ifcfg.sync_max_depth &&
+			    msg[3] >= 1000 / info->ifcfg.clockrate) {
+				dev->sync_state = neg_complete;
+				res = sync;
+			}
+			break;
+		}
+	}
+#else
+	res = reject;
+#endif
+
+	switch (res) {
+	case sync:
+		dev->period = msg[3];
+		dev->sof    = msg[4];
+		dev->stp    = fas216_syncperiod(info, msg[3] * 4);
+		fas216_set_sync(info, info->SCpnt->device->id);
+		break;
+
+	case reject:
+		fas216_cmd(info, CMD_SETATN);
+		msgqueue_flush(&info->scsi.msgs);
+		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+	case async:
+		dev->period = info->ifcfg.asyncperiod / 4;
+		dev->sof    = 0;
+		dev->stp    = info->scsi.async_stp;
+		fas216_set_sync(info, info->SCpnt->device->id);
+		break;
+
+	case none:
+		break;
+	}
+}
+
+/**
+ * fas216_updateptrs - update data pointers after transfer suspended/paused
+ * @info: interface's local pointer to update
+ * @bytes_transferred: number of bytes transferred
+ *
+ * Update data pointers after transfer suspended/paused
+ */
+static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
+{
+	Scsi_Pointer *SCp = &info->scsi.SCp;
+
+	fas216_checkmagic(info);
+
+	BUG_ON(bytes_transferred < 0);
+
+	info->SCpnt->request_bufflen -= bytes_transferred;
+
+	while (bytes_transferred != 0) {
+		if (SCp->this_residual > bytes_transferred)
+			break;
+		/*
+		 * We have used up this buffer.  Move on to the
+		 * next buffer.
+		 */
+		bytes_transferred -= SCp->this_residual;
+		if (!next_SCp(SCp) && bytes_transferred) {
+			printk(KERN_WARNING "scsi%d.%c: out of buffers\n",
+				info->host->host_no, '0' + info->SCpnt->device->id);
+			return;
+		}
+	}
+
+	SCp->this_residual -= bytes_transferred;
+	if (SCp->this_residual)
+		SCp->ptr += bytes_transferred;
+	else
+		SCp->ptr = NULL;
+}
+
+/**
+ * fas216_pio - transfer data off of/on to card using programmed IO
+ * @info: interface to transfer data to/from
+ * @direction: direction to transfer data (DMA_OUT/DMA_IN)
+ *
+ * Transfer data off of/on to card using programmed IO.
+ * Notes: this is incredibly slow.
+ */
+static void fas216_pio(FAS216_Info *info, fasdmadir_t direction)
+{
+	Scsi_Pointer *SCp = &info->scsi.SCp;
+
+	fas216_checkmagic(info);
+
+	if (direction == DMA_OUT)
+		fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp));
+	else
+		put_next_SCp_byte(SCp, fas216_readb(info, REG_FF));
+
+	if (SCp->this_residual == 0)
+		next_SCp(SCp);
+}
+
+static void fas216_set_stc(FAS216_Info *info, unsigned int length)
+{
+	fas216_writeb(info, REG_STCL, length);
+	fas216_writeb(info, REG_STCM, length >> 8);
+	fas216_writeb(info, REG_STCH, length >> 16);
+}
+
+static unsigned int fas216_get_ctc(FAS216_Info *info)
+{
+	return fas216_readb(info, REG_CTCL) +
+	       (fas216_readb(info, REG_CTCM) << 8) +
+	       (fas216_readb(info, REG_CTCH) << 16);
+}
+
+/**
+ * fas216_cleanuptransfer - clean up after a transfer has completed.
+ * @info: interface to clean up
+ *
+ * Update the data pointers according to the number of bytes transferred
+ * on the SCSI bus.
+ */
+static void fas216_cleanuptransfer(FAS216_Info *info)
+{
+	unsigned long total, residual, fifo;
+	fasdmatype_t dmatype = info->dma.transfer_type;
+
+	info->dma.transfer_type = fasdma_none;
+
+	/*
+	 * PIO transfers do not need to be cleaned up.
+	 */
+	if (dmatype == fasdma_pio || dmatype == fasdma_none)
+		return;
+
+	if (dmatype == fasdma_real_all)
+		total = info->SCpnt->request_bufflen;
+	else
+		total = info->scsi.SCp.this_residual;
+
+	residual = fas216_get_ctc(info);
+
+	fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+
+	fas216_log(info, LOG_BUFFER, "cleaning up from previous "
+		   "transfer: length 0x%06x, residual 0x%x, fifo %d",
+		   total, residual, fifo);
+
+	/*
+	 * If we were performing Data-Out, the transfer counter
+	 * counts down each time a byte is transferred by the
+	 * host to the FIFO.  This means we must include the
+	 * bytes left in the FIFO from the transfer counter.
+	 */
+	if (info->scsi.phase == PHASE_DATAOUT)
+		residual += fifo;
+
+	fas216_updateptrs(info, total - residual);
+}
+
+/**
+ * fas216_transfer - Perform a DMA/PIO transfer off of/on to card
+ * @info: interface from which device disconnected from
+ *
+ * Start a DMA/PIO transfer off of/on to card
+ */
+static void fas216_transfer(FAS216_Info *info)
+{
+	fasdmadir_t direction;
+	fasdmatype_t dmatype;
+
+	fas216_log(info, LOG_BUFFER,
+		   "starttransfer: buffer %p length 0x%06x reqlen 0x%06x",
+		   info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
+		   info->SCpnt->request_bufflen);
+
+	if (!info->scsi.SCp.ptr) {
+		fas216_log(info, LOG_ERROR, "null buffer passed to "
+			   "fas216_starttransfer");
+		print_SCp(&info->scsi.SCp, "SCp: ", "\n");
+		print_SCp(&info->SCpnt->SCp, "Cmnd SCp: ", "\n");
+		return;
+	}
+
+	/*
+	 * If we have a synchronous transfer agreement in effect, we must
+	 * use DMA mode.  If we are using asynchronous transfers, we may
+	 * use DMA mode or PIO mode.
+	 */
+	if (info->device[info->SCpnt->device->id].sof)
+		dmatype = fasdma_real_all;
+	else
+		dmatype = fasdma_pio;
+
+	if (info->scsi.phase == PHASE_DATAOUT)
+		direction = DMA_OUT;
+	else
+		direction = DMA_IN;
+
+	if (info->dma.setup)
+		dmatype = info->dma.setup(info->host, &info->scsi.SCp,
+					  direction, dmatype);
+	info->dma.transfer_type = dmatype;
+
+	if (dmatype == fasdma_real_all)
+		fas216_set_stc(info, info->SCpnt->request_bufflen);
+	else
+		fas216_set_stc(info, info->scsi.SCp.this_residual);
+
+	switch (dmatype) {
+	case fasdma_pio:
+		fas216_log(info, LOG_BUFFER, "PIO transfer");
+		fas216_writeb(info, REG_SOF, 0);
+		fas216_writeb(info, REG_STP, info->scsi.async_stp);
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		fas216_pio(info, direction);
+		break;
+
+	case fasdma_pseudo:
+		fas216_log(info, LOG_BUFFER, "pseudo transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		info->dma.pseudo(info->host, &info->scsi.SCp,
+				 direction, info->SCpnt->transfersize);
+		break;
+
+	case fasdma_real_block:
+		fas216_log(info, LOG_BUFFER, "block dma transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		break;
+
+	case fasdma_real_all:
+		fas216_log(info, LOG_BUFFER, "total dma transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		break;
+
+	default:
+		fas216_log(info, LOG_BUFFER | LOG_ERROR,
+			   "invalid FAS216 DMA type");
+		break;
+	}
+}
+
+/**
+ * fas216_stoptransfer - Stop a DMA transfer onto / off of the card
+ * @info: interface from which device disconnected from
+ *
+ * Called when we switch away from DATA IN or DATA OUT phases.
+ */
+static void fas216_stoptransfer(FAS216_Info *info)
+{
+	fas216_checkmagic(info);
+
+	if (info->dma.transfer_type == fasdma_real_all ||
+	    info->dma.transfer_type == fasdma_real_block)
+		info->dma.stop(info->host, &info->scsi.SCp);
+
+	fas216_cleanuptransfer(info);
+
+	if (info->scsi.phase == PHASE_DATAIN) {
+		unsigned int fifo;
+
+		/*
+		 * If we were performing Data-In, then the FIFO counter
+		 * contains the number of bytes not transferred via DMA
+		 * from the on-board FIFO.  Read them manually.
+		 */
+		fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		while (fifo && info->scsi.SCp.ptr) {
+			*info->scsi.SCp.ptr = fas216_readb(info, REG_FF);
+			fas216_updateptrs(info, 1);
+			fifo--;
+		}
+	} else {
+		/*
+		 * After a Data-Out phase, there may be unsent
+		 * bytes left in the FIFO.  Flush them out.
+		 */
+		fas216_cmd(info, CMD_FLUSHFIFO);
+	}
+}
+
+static void fas216_aborttransfer(FAS216_Info *info)
+{
+	fas216_checkmagic(info);
+
+	if (info->dma.transfer_type == fasdma_real_all ||
+	    info->dma.transfer_type == fasdma_real_block)
+		info->dma.stop(info->host, &info->scsi.SCp);
+
+	info->dma.transfer_type = fasdma_none;
+	fas216_cmd(info, CMD_FLUSHFIFO);
+}
+
+static void fas216_kick(FAS216_Info *info);
+
+/**
+ * fas216_disconnected_intr - handle device disconnection
+ * @info: interface from which device disconnected from
+ *
+ * Handle device disconnection
+ */
+static void fas216_disconnect_intr(FAS216_Info *info)
+{
+	unsigned long flags;
+
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_CONNECT, "disconnect phase=%02x",
+		   info->scsi.phase);
+
+	msgqueue_flush(&info->scsi.msgs);
+
+	switch (info->scsi.phase) {
+	case PHASE_SELECTION:			/* while selecting - no target		*/
+	case PHASE_SELSTEPS:
+		fas216_done(info, DID_NO_CONNECT);
+		break;
+
+	case PHASE_MSGIN_DISCONNECT:		/* message in - disconnecting		*/
+		info->scsi.disconnectable = 1;
+		info->scsi.phase = PHASE_IDLE;
+		info->stats.disconnects += 1;
+		spin_lock_irqsave(&info->host_lock, flags);
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+		break;
+
+	case PHASE_DONE:			/* at end of command - complete		*/
+		fas216_done(info, DID_OK);
+		break;
+
+	case PHASE_MSGOUT:			/* message out - possible ABORT message	*/
+		if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
+			info->scsi.aborting = 0;
+			fas216_done(info, DID_ABORT);
+			break;
+		}
+
+	default:				/* huh?					*/
+		printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",
+			info->host->host_no, fas216_target(info), fas216_drv_phase(info));
+		print_debug_list();
+		fas216_stoptransfer(info);
+		fas216_done(info, DID_ERROR);
+		break;
+	}
+}
+
+/**
+ * fas216_reselected_intr - start reconnection of a device
+ * @info: interface which was reselected
+ *
+ * Start reconnection of a device
+ */
+static void
+fas216_reselected_intr(FAS216_Info *info)
+{
+	unsigned int cfis, i;
+	unsigned char msg[4];
+	unsigned char target, lun, tag;
+
+	fas216_checkmagic(info);
+
+	WARN_ON(info->scsi.phase == PHASE_SELECTION ||
+		info->scsi.phase == PHASE_SELSTEPS);
+
+	cfis = fas216_readb(info, REG_CFIS);
+
+	fas216_log(info, LOG_CONNECT, "reconnect phase=%02x cfis=%02x",
+		   info->scsi.phase, cfis);
+
+	cfis &= CFIS_CF;
+
+	if (cfis < 2 || cfis > 4) {
+		printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
+			info->host->host_no);
+		goto bad_message;
+	}
+
+	for (i = 0; i < cfis; i++)
+		msg[i] = fas216_readb(info, REG_FF);
+
+	if (!(msg[0] & (1 << info->host->this_id)) ||
+	    !(msg[1] & 0x80))
+		goto initiator_error;
+
+	target = msg[0] & ~(1 << info->host->this_id);
+	target = ffs(target) - 1;
+	lun = msg[1] & 7;
+	tag = 0;
+
+	if (cfis >= 3) {
+		if (msg[2] != SIMPLE_QUEUE_TAG)
+			goto initiator_error;
+
+		tag = msg[3];
+	}
+
+	/* set up for synchronous transfers */
+	fas216_writeb(info, REG_SDID, target);
+	fas216_set_sync(info, target);
+	msgqueue_flush(&info->scsi.msgs);
+
+	fas216_log(info, LOG_CONNECT, "Reconnected: target %1x lun %1x tag %02x",
+		   target, lun, tag);
+
+	if (info->scsi.disconnectable && info->SCpnt) {
+		info->scsi.disconnectable = 0;
+		if (info->SCpnt->device->id  == target &&
+		    info->SCpnt->device->lun == lun &&
+		    info->SCpnt->tag         == tag) {
+			fas216_log(info, LOG_CONNECT, "reconnected previously executing command");
+		} else {
+			queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
+			fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue");
+			info->SCpnt = NULL;
+		}
+	}
+	if (!info->SCpnt) {
+		info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected,
+					target, lun, tag);
+		fas216_log(info, LOG_CONNECT, "had to get command");
+	}
+
+	if (info->SCpnt) {
+		/*
+		 * Restore data pointer from SAVED data pointer
+		 */
+		info->scsi.SCp = info->SCpnt->SCp;
+
+		fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		info->scsi.phase = PHASE_MSGIN;
+	} else {
+		/*
+		 * Our command structure not found - abort the
+		 * command on the target.  Since we have no
+		 * record of this command, we can't send
+		 * an INITIATOR DETECTED ERROR message.
+		 */
+		fas216_cmd(info, CMD_SETATN);
+
+#if 0
+		if (tag)
+			msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, tag);
+		else
+#endif
+			msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		info->scsi.aborting = 1;
+	}
+
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+
+ initiator_error:
+	printk(KERN_ERR "scsi%d.H: error during reselection: bytes",
+		info->host->host_no);
+	for (i = 0; i < cfis; i++)
+		printk(" %02x", msg[i]);
+	printk("\n");
+ bad_message:
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+	fas216_cmd(info, CMD_MSGACCEPTED);
+}
+
+static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen)
+{
+	int i;
+
+	switch (message[0]) {
+	case COMMAND_COMPLETE:
+		if (msglen != 1)
+			goto unrecognised;
+
+		printk(KERN_ERR "scsi%d.%c: command complete with no "
+			"status in MESSAGE_IN?\n",
+			info->host->host_no, fas216_target(info));
+		break;
+
+	case SAVE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
+		/*
+		 * Save current data pointer to SAVED data pointer
+		 * SCSI II standard says that we must not acknowledge
+		 * this until we have really saved pointers.
+		 * NOTE: we DO NOT save the command nor status pointers
+		 * as required by the SCSI II standard.  These always
+		 * point to the start of their respective areas.
+		 */
+		info->SCpnt->SCp = info->scsi.SCp;
+		info->SCpnt->SCp.sent_command = 0;
+		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
+			"save data pointers: [%p, %X]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		break;
+
+	case RESTORE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
+		/*
+		 * Restore current data pointer from SAVED data pointer
+		 */
+		info->scsi.SCp = info->SCpnt->SCp;
+		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
+			"restore data pointers: [%p, 0x%x]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		break;
+
+	case DISCONNECT:
+		if (msglen != 1)
+			goto unrecognised;
+
+		info->scsi.phase = PHASE_MSGIN_DISCONNECT;
+		break;
+
+	case MESSAGE_REJECT:
+		if (msglen != 1)
+			goto unrecognised;
+
+		switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
+		case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
+			fas216_handlesync(info, message);
+			break;
+
+		default:
+			fas216_log(info, 0, "reject, last message 0x%04x",
+				fas216_get_last_msg(info, info->scsi.msgin_fifo));
+		}
+		break;
+
+	case NOP:
+		break;
+
+	case EXTENDED_MESSAGE:
+		if (msglen < 3)
+			goto unrecognised;
+
+		switch (message[2]) {
+		case EXTENDED_SDTR:	/* Sync transfer negotiation request/reply */
+			fas216_handlesync(info, message);
+			break;
+
+		default:
+			goto unrecognised;
+		}
+		break;
+
+	default:
+		goto unrecognised;
+	}
+	return;
+
+unrecognised:
+	fas216_log(info, 0, "unrecognised message, rejecting");
+	printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info));
+	for (i = 0; i < msglen; i++)
+		printk("%s%02X", i & 31 ? " " : "\n  ", message[i]);
+	printk("\n");
+
+	/*
+	 * Something strange seems to be happening here -
+	 * I can't use SETATN since the chip gives me an
+	 * invalid command interrupt when I do.  Weird.
+	 */
+fas216_cmd(info, CMD_NOP);
+fas216_dumpstate(info);
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+fas216_dumpstate(info);
+}
+
+static int fas216_wait_cmd(FAS216_Info *info, int cmd)
+{
+	int tout;
+	int stat;
+
+	fas216_cmd(info, cmd);
+
+	for (tout = 1000; tout; tout -= 1) {
+		stat = fas216_readb(info, REG_STAT);
+		if (stat & (STAT_INT|STAT_PARITYERROR))
+			break;
+		udelay(1);
+	}
+
+	return stat;
+}
+
+static int fas216_get_msg_byte(FAS216_Info *info)
+{
+	unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED);
+
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
+
+	fas216_readb(info, REG_INST);
+
+	stat = fas216_wait_cmd(info, CMD_TRANSFERINFO);
+
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if (stat & STAT_PARITYERROR)
+		goto parity_error;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
+
+	fas216_readb(info, REG_INST);
+
+	return fas216_readb(info, REG_FF);
+
+timedout:
+	fas216_log(info, LOG_ERROR, "timed out waiting for message byte");
+	return -1;
+
+unexpected_phase_change:
+	fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat);
+	return -2;
+
+parity_error:
+	fas216_log(info, LOG_ERROR, "parity error during message in phase");
+	return -3;
+}
+
+/**
+ * fas216_message - handle a function done interrupt from FAS216 chip
+ * @info: interface which caused function done interrupt
+ *
+ * Handle a function done interrupt from FAS216 chip
+ */
+static void fas216_message(FAS216_Info *info)
+{
+	unsigned char *message = info->scsi.message;
+	unsigned int msglen = 1;
+	int msgbyte = 0;
+
+	fas216_checkmagic(info);
+
+	message[0] = fas216_readb(info, REG_FF);
+
+	if (message[0] == EXTENDED_MESSAGE) {
+		msgbyte = fas216_get_msg_byte(info);
+
+		if (msgbyte >= 0) {
+			message[1] = msgbyte;
+
+			for (msglen = 2; msglen < message[1] + 2; msglen++) {
+				msgbyte = fas216_get_msg_byte(info);
+
+				if (msgbyte >= 0)
+					message[msglen] = msgbyte;
+				else
+					break;
+			}
+		}
+	}
+
+	if (msgbyte == -3)
+		goto parity_error;
+
+#ifdef DEBUG_MESSAGES
+	{
+		int i;
+
+		printk("scsi%d.%c: message in: ",
+			info->host->host_no, fas216_target(info));
+		for (i = 0; i < msglen; i++)
+			printk("%02X ", message[i]);
+		printk("\n");
+	}
+#endif
+
+	fas216_parse_message(info, message, msglen);
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+
+parity_error:
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+}
+
+/**
+ * fas216_send_command - send command after all message bytes have been sent
+ * @info: interface which caused bus service
+ *
+ * Send a command to a target after all message bytes have been sent
+ */
+static void fas216_send_command(FAS216_Info *info)
+{
+	int i;
+
+	fas216_checkmagic(info);
+
+	fas216_cmd(info, CMD_NOP|CMD_WITHDMA);
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load command */
+	for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
+		fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]);
+
+	fas216_cmd(info, CMD_TRANSFERINFO);
+
+	info->scsi.phase = PHASE_COMMAND;
+}
+
+/**
+ * fas216_send_messageout - handle bus service to send a message
+ * @info: interface which caused bus service
+ *
+ * Handle bus service to send a message.
+ * Note: We do not allow the device to change the data direction!
+ */
+static void fas216_send_messageout(FAS216_Info *info, int start)
+{
+	unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+
+	fas216_checkmagic(info);
+
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	if (tot_msglen) {
+		struct message *msg;
+		int msgnr = 0;
+
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			int i;
+
+			for (i = start; i < msg->length; i++)
+				fas216_writeb(info, REG_FF, msg->msg[i]);
+
+			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
+			start = 0;
+		}
+	} else
+		fas216_writeb(info, REG_FF, NOP);
+
+	fas216_cmd(info, CMD_TRANSFERINFO);
+
+	info->scsi.phase = PHASE_MSGOUT;
+}
+
+/**
+ * fas216_busservice_intr - handle bus service interrupt from FAS216 chip
+ * @info: interface which caused bus service interrupt
+ * @stat: Status register contents
+ * @is: SCSI Status register contents
+ *
+ * Handle a bus service interrupt from FAS216 chip
+ */
+static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int is)
+{
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_BUSSERVICE,
+		   "bus service: stat=%02x is=%02x phase=%02x",
+		   stat, is, info->scsi.phase);
+
+	switch (info->scsi.phase) {
+	case PHASE_SELECTION:
+		if ((is & IS_BITS) != IS_MSGBYTESENT)
+			goto bad_is;
+		break;
+
+	case PHASE_SELSTEPS:
+		switch (is & IS_BITS) {
+		case IS_SELARB:
+		case IS_MSGBYTESENT:
+			goto bad_is;
+
+		case IS_NOTCOMMAND:
+		case IS_EARLYPHASE:
+			if ((stat & STAT_BUSMASK) == STAT_MESGIN)
+				break;
+			goto bad_is;
+
+		case IS_COMPLETE:
+			break;
+		}
+
+	default:
+		break;
+	}
+
+	fas216_cmd(info, CMD_NOP);
+
+#define STATE(st,ph) ((ph) << 3 | (st))
+	/* This table describes the legal SCSI state transitions,
+	 * as described by the SCSI II spec.
+	 */
+	switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
+	case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
+		info->scsi.phase = PHASE_DATAIN;
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
+	case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
+		fas216_cleanuptransfer(info);
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
+		fas216_cmd(info, CMD_FLUSHFIFO);
+		info->scsi.phase = PHASE_DATAOUT;
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
+	case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
+		fas216_stoptransfer(info);
+	case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
+	case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
+		fas216_cmd(info, CMD_INITCMDCOMPLETE);
+		info->scsi.phase = PHASE_STATUS;
+		return;
+
+	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
+		fas216_stoptransfer(info);
+	case STATE(STAT_MESGIN, PHASE_COMMAND):	/* Command	-> Message In	*/
+	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
+		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		fas216_cmd(info, CMD_FLUSHFIFO);
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		info->scsi.phase = PHASE_MSGIN;
+		return;
+
+	case STATE(STAT_MESGIN, PHASE_MSGIN):
+		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		return;
+
+	case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
+	case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
+		fas216_send_command(info);
+		info->scsi.phase = PHASE_COMMAND;
+		return;
+
+
+	/*
+	 * Selection    -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_SELECTION):
+		fas216_send_messageout(info, 1);
+		return;
+
+	/*
+	 * Message Out  -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT):
+		/*
+		 * If we get another message out phase, this usually
+		 * means some parity error occurred.  Resend complete
+		 * set of messages.  If we have more than one byte to
+		 * send, we need to assert ATN again.
+		 */
+		if (info->device[info->SCpnt->device->id].parity_check) {
+			/*
+			 * We were testing... good, the device
+			 * supports parity checking.
+			 */
+			info->device[info->SCpnt->device->id].parity_check = 0;
+			info->device[info->SCpnt->device->id].parity_enabled = 1;
+			fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+		}
+
+		if (msgqueue_msglength(&info->scsi.msgs) > 1)
+			fas216_cmd(info, CMD_SETATN);
+		/*FALLTHROUGH*/
+
+	/*
+	 * Any          -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
+		fas216_send_messageout(info, 0);
+		return;
+
+	/* Error recovery rules.
+	 *   These either attempt to abort or retry the operation.
+	 * TODO: we need more of these
+	 */
+	case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
+		/* error - we've sent out all the command bytes
+		 * we have.
+		 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
+		 * to include the command bytes sent for this to work
+		 * correctly.
+		 */
+		printk(KERN_ERR "scsi%d.%c: "
+			"target trying to receive more command bytes\n",
+			info->host->host_no, fas216_target(info));
+		fas216_cmd(info, CMD_SETATN);
+		fas216_set_stc(info, 15);
+		fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA);
+		msgqueue_flush(&info->scsi.msgs);
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		return;
+	}
+
+	if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
+		printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
+			info->host->host_no, fas216_target(info),
+			fas216_bus_phase(stat));
+		msgqueue_flush(&info->scsi.msgs);
+		fas216_cmd(info, CMD_SETATN);
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		info->scsi.aborting = 1;
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		return;
+	}
+	printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
+		info->host->host_no, fas216_target(info),
+		fas216_bus_phase(stat),
+		fas216_drv_phase(info));
+	print_debug_list();
+	return;
+
+bad_is:
+	fas216_log(info, 0, "bus service at step %d?", is & IS_BITS);
+	fas216_dumpstate(info);
+	print_debug_list();
+
+	fas216_done(info, DID_ERROR);
+}
+
+/**
+ * fas216_funcdone_intr - handle a function done interrupt from FAS216 chip
+ * @info: interface which caused function done interrupt
+ * @stat: Status register contents
+ * @is: SCSI Status register contents
+ *
+ * Handle a function done interrupt from FAS216 chip
+ */
+static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int is)
+{
+	unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF;
+
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_FUNCTIONDONE,
+		   "function done: stat=%02x is=%02x phase=%02x",
+		   stat, is, info->scsi.phase);
+
+	switch (info->scsi.phase) {
+	case PHASE_STATUS:			/* status phase - read status and msg	*/
+		if (fifo_len != 2) {
+			fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len);
+		}
+		/*
+		 * Read status then message byte.
+		 */
+		info->scsi.SCp.Status = fas216_readb(info, REG_FF);
+		info->scsi.SCp.Message = fas216_readb(info, REG_FF);
+		info->scsi.phase = PHASE_DONE;
+		fas216_cmd(info, CMD_MSGACCEPTED);
+		break;
+
+	case PHASE_IDLE:
+	case PHASE_SELECTION:
+	case PHASE_SELSTEPS:
+		break;
+
+	case PHASE_MSGIN:			/* message in phase			*/
+		if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
+			info->scsi.msgin_fifo = fifo_len;
+			fas216_message(info);
+			break;
+		}
+
+	default:
+		fas216_log(info, 0, "internal phase %s for function done?"
+			"  What do I do with this?",
+			fas216_target(info), fas216_drv_phase(info));
+	}
+}
+
+static void fas216_bus_reset(FAS216_Info *info)
+{
+	neg_t sync_state;
+	int i;
+
+	msgqueue_flush(&info->scsi.msgs);
+
+	sync_state = neg_invalid;
+
+#ifdef SCSI2_SYNC
+	if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA))
+		sync_state = neg_wait;
+#endif
+
+	info->scsi.phase = PHASE_IDLE;
+	info->SCpnt = NULL; /* bug! */
+	memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp));
+
+	for (i = 0; i < 8; i++) {
+		info->device[i].disconnect_ok	= info->ifcfg.disconnect_ok;
+		info->device[i].sync_state	= sync_state;
+		info->device[i].period		= info->ifcfg.asyncperiod / 4;
+		info->device[i].stp		= info->scsi.async_stp;
+		info->device[i].sof		= 0;
+		info->device[i].wide_xfer	= 0;
+	}
+
+	info->rst_bus_status = 1;
+	wake_up(&info->eh_wait);
+}
+
+/**
+ * fas216_intr - handle interrupts to progress a command
+ * @info: interface to service
+ *
+ * Handle interrupts from the interface to progress a command
+ */
+irqreturn_t fas216_intr(FAS216_Info *info)
+{
+	unsigned char inst, is, stat;
+	int handled = IRQ_NONE;
+
+	fas216_checkmagic(info);
+
+	stat = fas216_readb(info, REG_STAT);
+	is = fas216_readb(info, REG_IS);
+	inst = fas216_readb(info, REG_INST);
+
+	add_debug_list(stat, is, inst, info->scsi.phase);
+
+	if (stat & STAT_INT) {
+		if (inst & INST_BUSRESET) {
+			fas216_log(info, 0, "bus reset detected");
+			fas216_bus_reset(info);
+			scsi_report_bus_reset(info->host, 0);
+		} else if (inst & INST_ILLEGALCMD) {
+			fas216_log(info, LOG_ERROR, "illegal command given\n");
+			fas216_dumpstate(info);
+			print_debug_list();
+		} else if (inst & INST_DISCONNECT)
+			fas216_disconnect_intr(info);
+		else if (inst & INST_RESELECTED)	/* reselected			*/
+			fas216_reselected_intr(info);
+		else if (inst & INST_BUSSERVICE)	/* bus service request		*/
+			fas216_busservice_intr(info, stat, is);
+		else if (inst & INST_FUNCDONE)		/* function done		*/
+			fas216_funcdone_intr(info, stat, is);
+		else
+		    	fas216_log(info, 0, "unknown interrupt received:"
+				" phase %s inst %02X is %02X stat %02X",
+				fas216_drv_phase(info), inst, is, stat);
+		handled = IRQ_HANDLED;
+	}
+	return handled;
+}
+
+static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	int tot_msglen;
+
+	/* following what the ESP driver says */
+	fas216_set_stc(info, 0);
+	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
+
+	/* flush FIFO */
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load bus-id and timeout */
+	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+
+	/* synchronous transfers */
+	fas216_set_sync(info, SCpnt->device->id);
+
+	tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+
+#ifdef DEBUG_MESSAGES
+	{
+		struct message *msg;
+		int msgnr = 0, i;
+
+		printk("scsi%d.%c: message out: ",
+			info->host->host_no, '0' + SCpnt->device->id);
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			printk("{ ");
+			for (i = 0; i < msg->length; i++)
+				printk("%02x ", msg->msg[i]);
+			printk("} ");
+		}
+		printk("\n");
+	}
+#endif
+
+	if (tot_msglen == 1 || tot_msglen == 3) {
+		/*
+		 * We have an easy message length to send...
+		 */
+		struct message *msg;
+		int msgnr = 0, i;
+
+		info->scsi.phase = PHASE_SELSTEPS;
+
+		/* load message bytes */
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			for (i = 0; i < msg->length; i++)
+				fas216_writeb(info, REG_FF, msg->msg[i]);
+			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
+		}
+
+		/* load command */
+		for (i = 0; i < SCpnt->cmd_len; i++)
+			fas216_writeb(info, REG_FF, SCpnt->cmnd[i]);
+
+		if (tot_msglen == 1)
+			fas216_cmd(info, CMD_SELECTATN);
+		else
+			fas216_cmd(info, CMD_SELECTATN3);
+	} else {
+		/*
+		 * We have an unusual number of message bytes to send.
+		 *  Load first byte into fifo, and issue SELECT with ATN and
+		 *  stop steps.
+		 */
+		struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
+
+		fas216_writeb(info, REG_FF, msg->msg[0]);
+		msg->fifo = 1;
+
+		fas216_cmd(info, CMD_SELECTATNSTOP);
+	}
+}
+
+/*
+ * Decide whether we need to perform a parity test on this device.
+ * Can also be used to force parity error conditions during initial
+ * information transfer phase (message out) for test purposes.
+ */
+static int parity_test(FAS216_Info *info, int target)
+{
+#if 0
+	if (target == 3) {
+		info->device[target].parity_check = 0;
+		return 1;
+	}
+#endif
+	return info->device[target].parity_check;
+}
+
+static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	int disconnect_ok;
+
+	/*
+	 * claim host busy
+	 */
+	info->scsi.phase = PHASE_SELECTION;
+	info->scsi.SCp = SCpnt->SCp;
+	info->SCpnt = SCpnt;
+	info->dma.transfer_type = fasdma_none;
+
+	if (parity_test(info, SCpnt->device->id))
+		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE);
+	else
+		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+
+	/*
+	 * Don't allow request sense commands to disconnect.
+	 */
+	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
+			info->device[SCpnt->device->id].disconnect_ok;
+
+	/*
+	 * build outgoing message bytes
+	 */
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->device->lun));
+
+	/*
+	 * add tag message if required
+	 */
+	if (SCpnt->tag)
+		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
+
+	do {
+#ifdef SCSI2_SYNC
+		if ((info->device[SCpnt->device->id].sync_state == neg_wait ||
+		     info->device[SCpnt->device->id].sync_state == neg_complete) &&
+		    (SCpnt->cmnd[0] == REQUEST_SENSE ||
+		     SCpnt->cmnd[0] == INQUIRY)) {
+			info->device[SCpnt->device->id].sync_state = neg_inprogress;
+			msgqueue_addmsg(&info->scsi.msgs, 5,
+					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+					1000 / info->ifcfg.clockrate,
+					info->ifcfg.sync_max_depth);
+			break;
+		}
+#endif
+	} while (0);
+
+	__fas216_start_command(info, SCpnt);
+}
+
+static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+#ifdef SCSI2_TAG
+	/*
+	 * tagged queuing - allocate a new tag to this command
+	 */
+	if (SCpnt->device->simple_tags && SCpnt->cmnd[0] != REQUEST_SENSE &&
+	    SCpnt->cmnd[0] != INQUIRY) {
+	    SCpnt->device->current_tag += 1;
+		if (SCpnt->device->current_tag == 0)
+		    SCpnt->device->current_tag = 1;
+			SCpnt->tag = SCpnt->device->current_tag;
+	} else
+#endif
+		set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+
+	info->stats.removes += 1;
+	switch (SCpnt->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+		info->stats.writes += 1;
+		break;
+	case READ_6:
+	case READ_10:
+	case READ_12:
+		info->stats.reads += 1;
+		break;
+	default:
+		info->stats.miscs += 1;
+		break;
+	}
+}
+
+static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	struct message *msg;
+
+	/*
+	 * claim host busy
+	 */
+	info->scsi.phase = PHASE_SELECTION;
+	info->scsi.SCp = SCpnt->SCp;
+	info->SCpnt = SCpnt;
+	info->dma.transfer_type = fasdma_none;
+
+	fas216_log(info, LOG_ERROR, "sending bus device reset");
+
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET);
+
+	/* following what the ESP driver says */
+	fas216_set_stc(info, 0);
+	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
+
+	/* flush FIFO */
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load bus-id and timeout */
+	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+
+	/* synchronous transfers */
+	fas216_set_sync(info, SCpnt->device->id);
+
+	msg = msgqueue_getmsg(&info->scsi.msgs, 0);
+
+	fas216_writeb(info, REG_FF, BUS_DEVICE_RESET);
+	msg->fifo = 1;
+
+	fas216_cmd(info, CMD_SELECTATNSTOP);
+}
+
+/**
+ * fas216_kick - kick a command to the interface
+ * @info: our host interface to kick
+ *
+ * Kick a command to the interface, interface should be idle.
+ * Notes: Interrupts are always disabled!
+ */
+static void fas216_kick(FAS216_Info *info)
+{
+	Scsi_Cmnd *SCpnt = NULL;
+#define TYPE_OTHER	0
+#define TYPE_RESET	1
+#define TYPE_QUEUE	2
+	int where_from = TYPE_OTHER;
+
+	fas216_checkmagic(info);
+
+	/*
+	 * Obtain the next command to process.
+	 */
+	do {
+		if (info->rstSCpnt) {
+			SCpnt = info->rstSCpnt;
+			/* don't remove it */
+			where_from = TYPE_RESET;
+			break;
+		}
+
+		if (info->reqSCpnt) {
+			SCpnt = info->reqSCpnt;
+			info->reqSCpnt = NULL;
+			break;
+		}
+
+		if (info->origSCpnt) {
+			SCpnt = info->origSCpnt;
+			info->origSCpnt = NULL;
+			break;
+		}
+
+		/* retrieve next command */
+		if (!SCpnt) {
+			SCpnt = queue_remove_exclude(&info->queues.issue,
+						     info->busyluns);
+			where_from = TYPE_QUEUE;
+			break;
+		}
+	} while (0);
+
+	if (!SCpnt) {
+		/*
+		 * no command pending, so enable reselection.
+		 */
+		fas216_cmd(info, CMD_ENABLESEL);
+		return;
+	}
+
+	/*
+	 * We're going to start a command, so disable reselection
+	 */
+	fas216_cmd(info, CMD_DISABLESEL);
+
+	if (info->scsi.disconnectable && info->SCpnt) {
+		fas216_log(info, LOG_CONNECT,
+			"moved command for %d to disconnected queue",
+			info->SCpnt->device->id);
+		queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
+		info->scsi.disconnectable = 0;
+		info->SCpnt = NULL;
+	}
+
+	fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt,
+			   "starting");
+
+	switch (where_from) {
+	case TYPE_QUEUE:
+		fas216_allocate_tag(info, SCpnt);
+	case TYPE_OTHER:
+		fas216_start_command(info, SCpnt);
+		break;
+	case TYPE_RESET:
+		fas216_do_bus_device_reset(info, SCpnt);
+		break;
+	}
+
+	fas216_log(info, LOG_CONNECT, "select: data pointers [%p, %X]",
+		info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+
+	/*
+	 * should now get either DISCONNECT or
+	 * (FUNCTION DONE with BUS SERVICE) interrupt
+	 */
+}
+
+/*
+ * Clean up from issuing a BUS DEVICE RESET message to a device.
+ */
+static void
+fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	fas216_log(info, LOG_ERROR, "fas216 device reset complete");
+
+	info->rstSCpnt = NULL;
+	info->rst_dev_status = 1;
+	wake_up(&info->eh_wait);
+}
+
+/**
+ * fas216_rq_sns_done - Finish processing automatic request sense command
+ * @info: interface that completed
+ * @SCpnt: command that completed
+ * @result: driver byte of result
+ *
+ * Finish processing automatic request sense command
+ */
+static void
+fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
+		   "request sense complete, result=0x%04x%02x%02x",
+		   result, SCpnt->SCp.Message, SCpnt->SCp.Status);
+
+	if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+		/*
+		 * Something went wrong.  Make sure that we don't
+		 * have valid data in the sense buffer that could
+		 * confuse the higher levels.
+		 */
+		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+//printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);
+//{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); }
+	/*
+	 * Note that we don't set SCpnt->result, since that should
+	 * reflect the status of the command that we were asked by
+	 * the upper layers to process.  This would have been set
+	 * correctly by fas216_std_done.
+	 */
+	SCpnt->scsi_done(SCpnt);
+}
+
+/**
+ * fas216_std_done - finish processing of standard command
+ * @info: interface that completed
+ * @SCpnt: command that completed
+ * @result: driver byte of result
+ *
+ * Finish processing of standard command
+ */
+static void
+fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	info->stats.fins += 1;
+
+	SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
+			info->scsi.SCp.Status;
+
+	fas216_log_command(info, LOG_CONNECT, SCpnt,
+		"command complete, result=0x%08x", SCpnt->result);
+
+	/*
+	 * If the driver detected an error, we're all done.
+	 */
+	if (host_byte(SCpnt->result) != DID_OK ||
+	    msg_byte(SCpnt->result) != COMMAND_COMPLETE)
+		goto done;
+
+	/*
+	 * If the command returned CHECK_CONDITION or COMMAND_TERMINATED
+	 * status, request the sense information.
+	 */
+	if (status_byte(SCpnt->result) == CHECK_CONDITION ||
+	    status_byte(SCpnt->result) == COMMAND_TERMINATED)
+		goto request_sense;
+
+	/*
+	 * If the command did not complete with GOOD status,
+	 * we are all done here.
+	 */
+	if (status_byte(SCpnt->result) != GOOD)
+		goto done;
+
+	/*
+	 * We have successfully completed a command.  Make sure that
+	 * we do not have any buffers left to transfer.  The world
+	 * is not perfect, and we seem to occasionally hit this.
+	 * It can be indicative of a buggy driver, target or the upper
+	 * levels of the SCSI code.
+	 */
+	if (info->scsi.SCp.ptr) {
+		switch (SCpnt->cmnd[0]) {
+		case INQUIRY:
+		case START_STOP:
+		case MODE_SENSE:
+			break;
+
+		default:
+			printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
+				"detected: res=%08X ptr=%p len=%X CDB: ",
+				info->host->host_no, '0' + SCpnt->device->id,
+				SCpnt->result, info->scsi.SCp.ptr,
+				info->scsi.SCp.this_residual);
+			print_command(SCpnt->cmnd);
+			SCpnt->result &= ~(255 << 16);
+			SCpnt->result |= DID_BAD_TARGET << 16;
+			goto request_sense;
+		}
+	}
+
+done:
+	if (SCpnt->scsi_done) {
+		SCpnt->scsi_done(SCpnt);
+		return;
+	}
+
+	panic("scsi%d.H: null scsi_done function in fas216_done",
+		info->host->host_no);
+
+
+request_sense:
+	if (SCpnt->cmnd[0] == REQUEST_SENSE)
+		goto done;
+
+	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
+			  "requesting sense");
+	memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
+	SCpnt->cmnd[0] = REQUEST_SENSE;
+	SCpnt->cmnd[1] = SCpnt->device->lun << 5;
+	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->SCp.buffer = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+	SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
+	SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+	SCpnt->SCp.Message = 0;
+	SCpnt->SCp.Status = 0;
+	SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
+	SCpnt->use_sg = 0;
+	SCpnt->tag = 0;
+	SCpnt->host_scribble = (void *)fas216_rq_sns_done;
+
+	/*
+	 * Place this command into the high priority "request
+	 * sense" slot.  This will be the very next command
+	 * executed, unless a target connects to us.
+	 */
+	if (info->reqSCpnt)
+		printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
+			info->host->host_no, '0' + SCpnt->device->id);
+	info->reqSCpnt = SCpnt;
+}
+
+/**
+ * fas216_done - complete processing for current command
+ * @info: interface that completed
+ * @result: driver byte of result
+ *
+ * Complete processing for current command
+ */
+static void fas216_done(FAS216_Info *info, unsigned int result)
+{
+	void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
+	Scsi_Cmnd *SCpnt;
+	unsigned long flags;
+
+	fas216_checkmagic(info);
+
+	if (!info->SCpnt)
+		goto no_command;
+
+	SCpnt = info->SCpnt;
+	info->SCpnt = NULL;
+    	info->scsi.phase = PHASE_IDLE;
+
+	if (info->scsi.aborting) {
+		fas216_log(info, 0, "uncaught abort - returning DID_ABORT");
+		result = DID_ABORT;
+		info->scsi.aborting = 0;
+	}
+
+	/*
+	 * Sanity check the completion - if we have zero bytes left
+	 * to transfer, we should not have a valid pointer.
+	 */
+	if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
+		printk("scsi%d.%c: zero bytes left to transfer, but "
+		       "buffer pointer still valid: ptr=%p len=%08x CDB: ",
+		       info->host->host_no, '0' + SCpnt->device->id,
+		       info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		info->scsi.SCp.ptr = NULL;
+		print_command(SCpnt->cmnd);
+	}
+
+	/*
+	 * Clear down this command as completed.  If we need to request
+	 * the sense information, fas216_kick will re-assert the busy
+	 * status.
+	 */
+	info->device[SCpnt->device->id].parity_check = 0;
+	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+
+	fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+	fn(info, SCpnt, result);
+
+	if (info->scsi.irq != NO_IRQ) {
+		spin_lock_irqsave(&info->host_lock, flags);
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+	}
+	return;
+
+no_command:
+	panic("scsi%d.H: null command in fas216_done",
+		info->host->host_no);
+}
+
+/**
+ * fas216_queue_command - queue a command for adapter to process.
+ * @SCpnt: Command to queue
+ * @done: done function to call once command is complete
+ *
+ * Queue a command for adapter to process.
+ * Returns: 0 on success, else error.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	int result;
+
+	fas216_checkmagic(info);
+
+	fas216_log_command(info, LOG_CONNECT, SCpnt,
+			   "received command (%p)", SCpnt);
+
+	SCpnt->scsi_done = done;
+	SCpnt->host_scribble = (void *)fas216_std_done;
+	SCpnt->result = 0;
+
+	init_SCp(SCpnt);
+
+	info->stats.queues += 1;
+	SCpnt->tag = 0;
+
+	spin_lock(&info->host_lock);
+
+	/*
+	 * Add command into execute queue and let it complete under
+	 * whatever scheme we're using.
+	 */
+	result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
+
+	/*
+	 * If we successfully added the command,
+	 * kick the interface to get it moving.
+	 */
+	if (result == 0 && info->scsi.phase == PHASE_IDLE)
+		fas216_kick(info);
+	spin_unlock(&info->host_lock);
+
+	fas216_log_target(info, LOG_CONNECT, -1, "queue %s",
+		result ? "failure" : "success");
+
+	return result;
+}
+
+/**
+ * fas216_internal_done - trigger restart of a waiting thread in fas216_noqueue_command
+ * @SCpnt: Command to wake
+ *
+ * Trigger restart of a waiting thread in fas216_command
+ */
+static void fas216_internal_done(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	info->internal_done = 1;
+}
+
+/**
+ * fas216_noqueue_command - process a command for the adapter.
+ * @SCpnt: Command to queue
+ *
+ * Queue a command for adapter to process.
+ * Returns: scsi result code.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+int fas216_noqueue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	/*
+	 * We should only be using this if we don't have an interrupt.
+	 * Provide some "incentive" to use the queueing code.
+	 */
+	BUG_ON(info->scsi.irq != NO_IRQ);
+
+	info->internal_done = 0;
+	fas216_queue_command(SCpnt, fas216_internal_done);
+
+	/*
+	 * This wastes time, since we can't return until the command is
+	 * complete. We can't sleep either since we may get re-entered!
+	 * However, we must re-enable interrupts, or else we'll be
+	 * waiting forever.
+	 */
+	spin_unlock_irq(info->host->host_lock);
+
+	while (!info->internal_done) {
+		/*
+		 * If we don't have an IRQ, then we must poll the card for
+		 * it's interrupt, and use that to call this driver's
+		 * interrupt routine.  That way, we keep the command
+		 * progressing.  Maybe we can add some inteligence here
+		 * and go to sleep if we know that the device is going
+		 * to be some time (eg, disconnected).
+		 */
+		if (fas216_readb(info, REG_STAT) & STAT_INT) {
+			spin_lock_irq(info->host->host_lock);
+			fas216_intr(info);
+			spin_unlock_irq(info->host->host_lock);
+		}
+	}
+
+	spin_lock_irq(info->host->host_lock);
+
+	done(SCpnt);
+
+	return 0;
+}
+
+/*
+ * Error handler timeout function.  Indicate that we timed out,
+ * and wake up any error handler process so it can continue.
+ */
+static void fas216_eh_timer(unsigned long data)
+{
+	FAS216_Info *info = (FAS216_Info *)data;
+
+	fas216_log(info, LOG_ERROR, "error handling timed out\n");
+
+	del_timer(&info->eh_timer);
+
+	if (info->rst_bus_status == 0)
+		info->rst_bus_status = -1;
+	if (info->rst_dev_status == 0)
+		info->rst_dev_status = -1;
+
+	wake_up(&info->eh_wait);
+}
+
+enum res_find {
+	res_failed,		/* not found			*/
+	res_success,		/* command on issue queue	*/
+	res_hw_abort		/* command on disconnected dev	*/
+};
+
+/**
+ * fas216_do_abort - decide how to abort a command
+ * @SCpnt: command to abort
+ *
+ * Decide how to abort a command.
+ * Returns: abort status
+ */
+static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	enum res_find res = res_failed;
+
+	if (queue_remove_cmd(&info->queues.issue, SCpnt)) {
+		/*
+		 * The command was on the issue queue, and has not been
+		 * issued yet.  We can remove the command from the queue,
+		 * and acknowledge the abort.  Neither the device nor the
+		 * interface know about the command.
+		 */
+		printk("on issue queue ");
+
+		res = res_success;
+	} else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) {
+		/*
+		 * The command was on the disconnected queue.  We must
+		 * reconnect with the device if possible, and send it
+		 * an abort message.
+		 */
+		printk("on disconnected queue ");
+
+		res = res_hw_abort;
+	} else if (info->SCpnt == SCpnt) {
+		printk("executing ");
+
+		switch (info->scsi.phase) {
+		/*
+		 * If the interface is idle, and the command is 'disconnectable',
+		 * then it is the same as on the disconnected queue.
+		 */
+		case PHASE_IDLE:
+			if (info->scsi.disconnectable) {
+				info->scsi.disconnectable = 0;
+				info->SCpnt = NULL;
+				res = res_hw_abort;
+			}
+			break;
+
+		default:
+			break;
+		}
+	} else if (info->origSCpnt == SCpnt) {
+		/*
+		 * The command will be executed next, but a command
+		 * is currently using the interface.  This is similar to
+		 * being on the issue queue, except the busylun bit has
+		 * been set.
+		 */
+		info->origSCpnt = NULL;
+		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+		printk("waiting for execution ");
+		res = res_success;
+	} else
+		printk("unknown ");
+
+	return res;
+}
+
+/**
+ * fas216_eh_abort - abort this command
+ * @SCpnt: command to abort
+ *
+ * Abort this command.
+ * Returns: FAILED if unable to abort
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	int result = FAILED;
+
+	fas216_checkmagic(info);
+
+	info->stats.aborts += 1;
+
+	printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
+	print_command(SCpnt->data_cmnd);
+
+	print_debug_list();
+	fas216_dumpstate(info);
+
+	printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt);
+
+	switch (fas216_find_command(info, SCpnt)) {
+	/*
+	 * We found the command, and cleared it out.  Either
+	 * the command is still known to be executing on the
+	 * target, or the busylun bit is not set.
+	 */
+	case res_success:
+		printk("success\n");
+		result = SUCCESS;
+		break;
+
+	/*
+	 * We need to reconnect to the target and send it an
+	 * ABORT or ABORT_TAG message.  We can only do this
+	 * if the bus is free.
+	 */
+	case res_hw_abort:
+		
+
+	/*
+	 * We are unable to abort the command for some reason.
+	 */
+	default:
+	case res_failed:
+		printk("failed\n");
+		break;
+	}
+
+	return result;
+}
+
+/**
+ * fas216_eh_device_reset - Reset the device associated with this command
+ * @SCpnt: command specifing device to reset
+ *
+ * Reset the device associated with this command.
+ * Returns: FAILED if unable to reset.
+ * Notes: We won't be re-entered, so we'll only have one device
+ * reset on the go at one time.
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	unsigned long flags;
+	int i, res = FAILED, target = SCpnt->device->id;
+
+	fas216_log(info, LOG_ERROR, "device reset for target %d", target);
+
+	spin_lock_irqsave(&info->host_lock, flags);
+
+	do {
+		/*
+		 * If we are currently connected to a device, and
+		 * it is the device we want to reset, there is
+		 * nothing we can do here.  Chances are it is stuck,
+		 * and we need a bus reset.
+		 */
+		if (info->SCpnt && !info->scsi.disconnectable &&
+		    info->SCpnt->device->id == SCpnt->device->id)
+			break;
+
+		/*
+		 * We're going to be resetting this device.  Remove
+		 * all pending commands from the driver.  By doing
+		 * so, we guarantee that we won't touch the command
+		 * structures except to process the reset request.
+		 */
+		queue_remove_all_target(&info->queues.issue, target);
+		queue_remove_all_target(&info->queues.disconnected, target);
+		if (info->origSCpnt && info->origSCpnt->device->id == target)
+			info->origSCpnt = NULL;
+		if (info->reqSCpnt && info->reqSCpnt->device->id == target)
+			info->reqSCpnt = NULL;
+		for (i = 0; i < 8; i++)
+			clear_bit(target * 8 + i, info->busyluns);
+
+		/*
+		 * Hijack this SCSI command structure to send
+		 * a bus device reset message to this device.
+		 */
+		SCpnt->host_scribble = (void *)fas216_devicereset_done;
+
+		info->rst_dev_status = 0;
+		info->rstSCpnt = SCpnt;
+
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+
+		mod_timer(&info->eh_timer, 30 * HZ);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+
+		/*
+		 * Wait up to 30 seconds for the reset to complete.
+		 */
+		wait_event(info->eh_wait, info->rst_dev_status);
+
+		del_timer_sync(&info->eh_timer);
+		spin_lock_irqsave(&info->host_lock, flags);
+		info->rstSCpnt = NULL;
+
+		if (info->rst_dev_status == 1)
+			res = SUCCESS;
+	} while (0);
+
+	SCpnt->host_scribble = NULL;
+	spin_unlock_irqrestore(&info->host_lock, flags);
+
+	fas216_log(info, LOG_ERROR, "device reset complete: %s\n",
+		   res == SUCCESS ? "success" : "failed");
+
+	return res;
+}
+
+/**
+ * fas216_eh_bus_reset - Reset the bus associated with the command
+ * @SCpnt: command specifing bus to reset
+ *
+ * Reset the bus associated with the command.
+ * Returns: FAILED if unable to reset.
+ * Notes: Further commands are blocked.
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	unsigned long flags;
+	Scsi_Device *SDpnt;
+
+	fas216_checkmagic(info);
+	fas216_log(info, LOG_ERROR, "resetting bus");
+
+	info->stats.bus_resets += 1;
+
+	spin_lock_irqsave(&info->host_lock, flags);
+
+	/*
+	 * Stop all activity on this interface.
+	 */
+	fas216_aborttransfer(info);
+	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
+
+	/*
+	 * Clear any pending interrupts.
+	 */
+	while (fas216_readb(info, REG_STAT) & STAT_INT)
+		fas216_readb(info, REG_INST);
+
+	info->rst_bus_status = 0;
+
+	/*
+	 * For each attached hard-reset device, clear out
+	 * all command structures.  Leave the running
+	 * command in place.
+	 */
+	shost_for_each_device(SDpnt, info->host) {
+		int i;
+
+		if (SDpnt->soft_reset)
+			continue;
+
+		queue_remove_all_target(&info->queues.issue, SDpnt->id);
+		queue_remove_all_target(&info->queues.disconnected, SDpnt->id);
+		if (info->origSCpnt && info->origSCpnt->device->id == SDpnt->id)
+			info->origSCpnt = NULL;
+		if (info->reqSCpnt && info->reqSCpnt->device->id == SDpnt->id)
+			info->reqSCpnt = NULL;
+		info->SCpnt = NULL;
+
+		for (i = 0; i < 8; i++)
+			clear_bit(SDpnt->id * 8 + i, info->busyluns);
+	}
+
+	info->scsi.phase = PHASE_IDLE;
+
+	/*
+	 * Reset the SCSI bus.  Device cleanup happens in
+	 * the interrupt handler.
+	 */
+	fas216_cmd(info, CMD_RESETSCSI);
+
+	mod_timer(&info->eh_timer, jiffies + HZ);
+	spin_unlock_irqrestore(&info->host_lock, flags);
+
+	/*
+	 * Wait one second for the interrupt.
+	 */
+	wait_event(info->eh_wait, info->rst_bus_status);
+	del_timer_sync(&info->eh_timer);
+
+	fas216_log(info, LOG_ERROR, "bus reset complete: %s\n",
+		   info->rst_bus_status == 1 ? "success" : "failed");
+
+	return info->rst_bus_status == 1 ? SUCCESS : FAILED;
+}
+
+/**
+ * fas216_init_chip - Initialise FAS216 state after reset
+ * @info: state structure for interface
+ *
+ * Initialise FAS216 state after reset
+ */
+static void fas216_init_chip(FAS216_Info *info)
+{
+	unsigned int clock = ((info->ifcfg.clockrate - 1) / 5 + 1) & 7;
+	fas216_writeb(info, REG_CLKF, clock);
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+	fas216_writeb(info, REG_CNTL2, info->scsi.cfg[1]);
+	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+	fas216_writeb(info, REG_SOF, 0);
+	fas216_writeb(info, REG_STP, info->scsi.async_stp);
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+}
+
+/**
+ * fas216_eh_host_reset - Reset the host associated with this command
+ * @SCpnt: command specifing host to reset
+ *
+ * Reset the host associated with this command.
+ * Returns: FAILED if unable to reset.
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	printk("scsi%d.%c: %s: resetting host\n",
+		info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
+
+	/*
+	 * Reset the SCSI chip.
+	 */
+	fas216_cmd(info, CMD_RESETCHIP);
+
+	/*
+	 * Ugly ugly ugly!
+	 * We need to release the host_lock and enable
+	 * IRQs if we sleep, but we must relock and disable
+	 * IRQs after the sleep.
+	 */
+	spin_unlock_irq(info->host->host_lock);
+	msleep(50 * 1000/100);
+	spin_lock_irq(info->host->host_lock);
+
+	/*
+	 * Release the SCSI reset.
+	 */
+	fas216_cmd(info, CMD_NOP);
+
+	fas216_init_chip(info);
+
+	return SUCCESS;
+}
+
+#define TYPE_UNKNOWN	0
+#define TYPE_NCR53C90	1
+#define TYPE_NCR53C90A	2
+#define TYPE_NCR53C9x	3
+#define TYPE_Am53CF94	4
+#define TYPE_EmFAS216	5
+#define TYPE_QLFAS216	6
+
+static char *chip_types[] = {
+	"unknown",
+	"NS NCR53C90",
+	"NS NCR53C90A",
+	"NS NCR53C9x",
+	"AMD Am53CF94",
+	"Emulex FAS216",
+	"QLogic FAS216"
+};
+
+static int fas216_detect_type(FAS216_Info *info)
+{
+	int family, rev;
+
+	/*
+	 * Reset the chip.
+	 */
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_NOP);
+
+	/*
+	 * Check to see if control reg 2 is present.
+	 */
+	fas216_writeb(info, REG_CNTL3, 0);
+	fas216_writeb(info, REG_CNTL2, CNTL2_S2FE);
+
+	/*
+	 * If we are unable to read back control reg 2
+	 * correctly, it is not present, and we have a
+	 * NCR53C90.
+	 */
+	if ((fas216_readb(info, REG_CNTL2) & (~0xe0)) != CNTL2_S2FE)
+		return TYPE_NCR53C90;
+
+	/*
+	 * Now, check control register 3
+	 */
+	fas216_writeb(info, REG_CNTL2, 0);
+	fas216_writeb(info, REG_CNTL3, 0);
+	fas216_writeb(info, REG_CNTL3, 5);
+
+	/*
+	 * If we are unable to read the register back
+	 * correctly, we have a NCR53C90A
+	 */
+	if (fas216_readb(info, REG_CNTL3) != 5)
+		return TYPE_NCR53C90A;
+
+	/*
+	 * Now read the ID from the chip.
+	 */
+	fas216_writeb(info, REG_CNTL3, 0);
+
+	fas216_writeb(info, REG_CNTL3, CNTL3_ADIDCHK);
+	fas216_writeb(info, REG_CNTL3, 0);
+
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_WITHDMA | CMD_NOP);
+
+	fas216_writeb(info, REG_CNTL2, CNTL2_ENF);
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_NOP);
+
+	rev     = fas216_readb(info, REG_ID);
+	family  = rev >> 3;
+	rev    &= 7;
+
+	switch (family) {
+	case 0x01:
+		if (rev == 4)
+			return TYPE_Am53CF94;
+		break;
+
+	case 0x02:
+		switch (rev) {
+		case 2:
+			return TYPE_EmFAS216;
+		case 3:
+			return TYPE_QLFAS216;
+		}
+		break;
+
+	default:
+		break;
+	}
+	printk("family %x rev %x\n", family, rev);
+	return TYPE_NCR53C9x;
+}
+
+/**
+ * fas216_reset_state - Initialise driver internal state
+ * @info: state to initialise
+ *
+ * Initialise driver internal state
+ */
+static void fas216_reset_state(FAS216_Info *info)
+{
+	int i;
+
+	fas216_checkmagic(info);
+
+	fas216_bus_reset(info);
+
+	/*
+	 * Clear out all stale info in our state structure
+	 */
+	memset(info->busyluns, 0, sizeof(info->busyluns));
+	info->scsi.disconnectable = 0;
+	info->scsi.aborting = 0;
+
+	for (i = 0; i < 8; i++) {
+		info->device[i].parity_enabled	= 0;
+		info->device[i].parity_check	= 1;
+	}
+
+	/*
+	 * Drain all commands on disconnected queue
+	 */
+	while (queue_remove(&info->queues.disconnected) != NULL);
+
+	/*
+	 * Remove executing commands.
+	 */
+	info->SCpnt     = NULL;
+	info->reqSCpnt  = NULL;
+	info->rstSCpnt  = NULL;
+	info->origSCpnt = NULL;
+}
+
+/**
+ * fas216_init - initialise FAS/NCR/AMD SCSI structures.
+ * @host: a driver-specific filled-out structure
+ *
+ * Initialise FAS/NCR/AMD SCSI structures.
+ * Returns: 0 on success
+ */
+int fas216_init(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	info->magic_start    = MAGIC;
+	info->magic_end      = MAGIC;
+	info->host           = host;
+	info->scsi.cfg[0]    = host->this_id | CNTL1_PERE;
+	info->scsi.cfg[1]    = CNTL2_ENF | CNTL2_S2FE;
+	info->scsi.cfg[2]    = info->ifcfg.cntl3 |
+			       CNTL3_ADIDCHK | CNTL3_QTAG | CNTL3_G2CB | CNTL3_LBTM;
+	info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
+
+	info->rst_dev_status = -1;
+	info->rst_bus_status = -1;
+	init_waitqueue_head(&info->eh_wait);
+	init_timer(&info->eh_timer);
+	info->eh_timer.data  = (unsigned long)info;
+	info->eh_timer.function = fas216_eh_timer;
+	
+	spin_lock_init(&info->host_lock);
+
+	memset(&info->stats, 0, sizeof(info->stats));
+
+	msgqueue_initialise(&info->scsi.msgs);
+
+	if (!queue_initialise(&info->queues.issue))
+		return -ENOMEM;
+
+	if (!queue_initialise(&info->queues.disconnected)) {
+		queue_free(&info->queues.issue);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * fas216_add - initialise FAS/NCR/AMD SCSI ic.
+ * @host: a driver-specific filled-out structure
+ * @dev: parent device
+ *
+ * Initialise FAS/NCR/AMD SCSI ic.
+ * Returns: 0 on success
+ */
+int fas216_add(struct Scsi_Host *host, struct device *dev)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+	int type, ret;
+
+	if (info->ifcfg.clockrate <= 10 || info->ifcfg.clockrate > 40) {
+		printk(KERN_CRIT "fas216: invalid clock rate %u MHz\n",
+			info->ifcfg.clockrate);
+		return -EINVAL;
+	}
+
+	fas216_reset_state(info);
+	type = fas216_detect_type(info);
+	info->scsi.type = chip_types[type];
+
+	udelay(300);
+
+	/*
+	 * Initialise the chip correctly.
+	 */
+	fas216_init_chip(info);
+
+	/*
+	 * Reset the SCSI bus.  We don't want to see
+	 * the resulting reset interrupt, so mask it
+	 * out.
+	 */
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_DISR);
+	fas216_writeb(info, REG_CMD, CMD_RESETSCSI);
+
+	/*
+	 * scsi standard says wait 250ms
+	 */
+	spin_unlock_irq(info->host->host_lock);
+	msleep(100*1000/100);
+	spin_lock_irq(info->host->host_lock);
+
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+	fas216_readb(info, REG_INST);
+
+	fas216_checkmagic(info);
+
+	ret = scsi_add_host(host, dev);
+	if (ret)
+		fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	else
+		scsi_scan_host(host);
+
+	return ret;
+}
+
+void fas216_remove(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	fas216_checkmagic(info);
+	scsi_remove_host(host);
+
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	scsi_host_put(host);
+}
+
+/**
+ * fas216_release - release all resources for FAS/NCR/AMD SCSI ic.
+ * @host: a driver-specific filled-out structure
+ *
+ * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
+ */
+void fas216_release(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	queue_free(&info->queues.disconnected);
+	queue_free(&info->queues.issue);
+}
+
+int fas216_print_host(FAS216_Info *info, char *buffer)
+{
+	return sprintf(buffer,
+			"\n"
+			"Chip    : %s\n"
+			" Address: 0x%p\n"
+			" IRQ    : %d\n"
+			" DMA    : %d\n",
+			info->scsi.type, info->scsi.io_base,
+			info->scsi.irq, info->scsi.dma);
+}
+
+int fas216_print_stats(FAS216_Info *info, char *buffer)
+{
+	char *p = buffer;
+
+	p += sprintf(p, "\n"
+			"Command Statistics:\n"
+			" Queued     : %u\n"
+			" Issued     : %u\n"
+			" Completed  : %u\n"
+			" Reads      : %u\n"
+			" Writes     : %u\n"
+			" Others     : %u\n"
+			" Disconnects: %u\n"
+			" Aborts     : %u\n"
+			" Bus resets : %u\n"
+			" Host resets: %u\n",
+			info->stats.queues,	 info->stats.removes,
+			info->stats.fins,	 info->stats.reads,
+			info->stats.writes,	 info->stats.miscs,
+			info->stats.disconnects, info->stats.aborts,
+			info->stats.bus_resets,	 info->stats.host_resets);
+
+	return p - buffer;
+}
+
+int fas216_print_devices(FAS216_Info *info, char *buffer)
+{
+	struct fas216_device *dev;
+	Scsi_Device *scd;
+	char *p = buffer;
+
+	p += sprintf(p, "Device/Lun TaggedQ       Parity   Sync\n");
+
+	shost_for_each_device(scd, info->host) {
+		dev = &info->device[scd->id];
+		p += sprintf(p, "     %d/%d   ", scd->id, scd->lun);
+		if (scd->tagged_supported)
+			p += sprintf(p, "%3sabled(%3d) ",
+				     scd->simple_tags ? "en" : "dis",
+				     scd->current_tag);
+		else
+			p += sprintf(p, "unsupported   ");
+
+		p += sprintf(p, "%3sabled ", dev->parity_enabled ? "en" : "dis");
+
+		if (dev->sof)
+			p += sprintf(p, "offset %d, %d ns\n",
+				     dev->sof, dev->period * 4);
+		else
+			p += sprintf(p, "async\n");
+	}
+
+	return p - buffer;
+}
+
+EXPORT_SYMBOL(fas216_init);
+EXPORT_SYMBOL(fas216_add);
+EXPORT_SYMBOL(fas216_queue_command);
+EXPORT_SYMBOL(fas216_noqueue_command);
+EXPORT_SYMBOL(fas216_intr);
+EXPORT_SYMBOL(fas216_remove);
+EXPORT_SYMBOL(fas216_release);
+EXPORT_SYMBOL(fas216_eh_abort);
+EXPORT_SYMBOL(fas216_eh_device_reset);
+EXPORT_SYMBOL(fas216_eh_bus_reset);
+EXPORT_SYMBOL(fas216_eh_host_reset);
+EXPORT_SYMBOL(fas216_print_host);
+EXPORT_SYMBOL(fas216_print_stats);
+EXPORT_SYMBOL(fas216_print_devices);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver core");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
new file mode 100644
index 0000000..60a2a12
--- /dev/null
+++ b/drivers/scsi/arm/fas216.h
@@ -0,0 +1,394 @@
+/*
+ *  linux/drivers/acorn/scsi/fas216.h
+ *
+ *  Copyright (C) 1997-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  FAS216 generic driver
+ */
+#ifndef FAS216_H
+#define FAS216_H
+
+#ifndef NO_IRQ
+#define NO_IRQ 255
+#endif
+
+#include "queue.h"
+#include "msgqueue.h"
+
+/* FAS register definitions */
+
+/* transfer count low */
+#define REG_CTCL		(0)
+#define REG_STCL		(0)
+
+/* transfer count medium */
+#define REG_CTCM		(1)
+#define REG_STCM		(1)
+
+/* fifo data */
+#define REG_FF			(2)
+
+/* command */
+#define REG_CMD			(3)
+#define CMD_NOP			0x00
+#define CMD_FLUSHFIFO		0x01
+#define CMD_RESETCHIP		0x02
+#define CMD_RESETSCSI		0x03
+
+#define CMD_TRANSFERINFO	0x10
+#define CMD_INITCMDCOMPLETE	0x11
+#define CMD_MSGACCEPTED		0x12
+#define CMD_PADBYTES		0x18
+#define CMD_SETATN		0x1a
+#define CMD_RSETATN		0x1b
+
+#define CMD_SELECTWOATN		0x41
+#define CMD_SELECTATN		0x42
+#define CMD_SELECTATNSTOP	0x43
+#define CMD_ENABLESEL		0x44
+#define CMD_DISABLESEL		0x45
+#define CMD_SELECTATN3		0x46
+#define CMD_RESEL3		0x47
+
+#define CMD_WITHDMA		0x80
+
+/* status register (read) */
+#define REG_STAT		(4)
+#define STAT_IO			(1 << 0)			/* IO phase		*/
+#define STAT_CD			(1 << 1)			/* CD phase		*/
+#define STAT_MSG		(1 << 2)			/* MSG phase		*/
+#define STAT_TRANSFERDONE	(1 << 3)			/* Transfer completed	*/
+#define STAT_TRANSFERCNTZ	(1 << 4)			/* Transfer counter is zero */
+#define STAT_PARITYERROR	(1 << 5)			/* Parity error		*/
+#define STAT_REALBAD		(1 << 6)			/* Something bad	*/
+#define STAT_INT		(1 << 7)			/* Interrupt		*/
+
+#define STAT_BUSMASK		(STAT_MSG|STAT_CD|STAT_IO)
+#define STAT_DATAOUT		(0)				/* Data out		*/
+#define STAT_DATAIN		(STAT_IO)			/* Data in		*/
+#define STAT_COMMAND		(STAT_CD)			/* Command out		*/
+#define STAT_STATUS		(STAT_CD|STAT_IO)		/* Status In		*/
+#define STAT_MESGOUT		(STAT_MSG|STAT_CD)		/* Message out		*/
+#define STAT_MESGIN		(STAT_MSG|STAT_CD|STAT_IO)	/* Message In		*/
+
+/* bus ID for select / reselect */
+#define REG_SDID		(4)
+#define BUSID(target)		((target) & 7)
+
+/* Interrupt status register (read) */
+#define REG_INST		(5)
+#define INST_SELWOATN		(1 << 0)			/* Select w/o ATN	*/
+#define INST_SELATN		(1 << 1)			/* Select w/ATN		*/
+#define INST_RESELECTED		(1 << 2)			/* Reselected		*/
+#define INST_FUNCDONE		(1 << 3)			/* Function done	*/
+#define INST_BUSSERVICE		(1 << 4)			/* Bus service		*/
+#define INST_DISCONNECT		(1 << 5)			/* Disconnect		*/
+#define INST_ILLEGALCMD		(1 << 6)			/* Illegal command	*/
+#define INST_BUSRESET		(1 << 7)			/* SCSI Bus reset	*/
+
+/* Timeout register (write) */
+#define REG_STIM		(5)
+
+/* Sequence step register (read) */
+#define REG_IS			(6)
+#define IS_BITS			0x07
+#define IS_SELARB		0x00				/* Select & Arb ok	*/
+#define IS_MSGBYTESENT		0x01				/* One byte message sent*/
+#define IS_NOTCOMMAND		0x02				/* Not in command state	*/
+#define IS_EARLYPHASE		0x03				/* Early phase change	*/
+#define IS_COMPLETE		0x04				/* Command ok		*/
+#define IS_SOF			0x08				/* Sync off flag	*/
+
+/* Transfer period step (write) */
+#define REG_STP			(6)
+
+/* Synchronous Offset (write) */
+#define REG_SOF			(7)
+
+/* Fifo state register (read) */
+#define REG_CFIS		(7)
+#define CFIS_CF			0x1f				/* Num bytes in FIFO	*/
+#define CFIS_IS			0xe0				/* Step			*/
+
+/* config register 1 */
+#define REG_CNTL1		(8)
+#define CNTL1_CID		(7 << 0)			/* Chip ID			*/
+#define CNTL1_STE		(1 << 3)			/* Self test enable		*/
+#define CNTL1_PERE		(1 << 4)			/* Parity enable reporting en.	*/
+#define CNTL1_PTE		(1 << 5)			/* Parity test enable		*/
+#define CNTL1_DISR		(1 << 6)			/* Disable Irq on SCSI reset	*/
+#define CNTL1_ETM		(1 << 7)			/* Extended Timing Mode		*/
+
+/* Clock conversion factor (read) */
+#define REG_CLKF		(9)
+#define CLKF_F37MHZ		0x00				/* 35.01 - 40 MHz		*/
+#define CLKF_F10MHZ		0x02				/* 10 MHz			*/
+#define CLKF_F12MHZ		0x03				/* 10.01 - 15 MHz		*/
+#define CLKF_F17MHZ		0x04				/* 15.01 - 20 MHz		*/
+#define CLKF_F22MHZ		0x05				/* 20.01 - 25 MHz		*/
+#define CLKF_F27MHZ		0x06				/* 25.01 - 30 MHz		*/
+#define CLKF_F32MHZ		0x07				/* 30.01 - 35 MHz		*/
+
+/* Chip test register (write) */
+#define REG_FTM			(10)
+#define TEST_FTM		0x01				/* Force target mode		*/
+#define TEST_FIM		0x02				/* Force initiator mode		*/
+#define TEST_FHI		0x04				/* Force high impedance mode	*/
+
+/* Configuration register 2 (read/write) */
+#define REG_CNTL2		(11)
+#define CNTL2_PGDP		(1 << 0)			/* Pass Th/Generate Data Parity	*/
+#define CNTL2_PGRP		(1 << 1)			/* Pass Th/Generate Reg Parity	*/
+#define CNTL2_ACDPE		(1 << 2)			/* Abort on Cmd/Data Parity Err	*/
+#define CNTL2_S2FE		(1 << 3)			/* SCSI2 Features Enable	*/
+#define CNTL2_TSDR		(1 << 4)			/* Tristate DREQ		*/
+#define CNTL2_SBO		(1 << 5)			/* Select Byte Order		*/
+#define CNTL2_ENF		(1 << 6)			/* Enable features		*/
+#define CNTL2_DAE		(1 << 7)			/* Data Alignment Enable	*/
+
+/* Configuration register 3 (read/write) */
+#define REG_CNTL3		(12)
+#define CNTL3_BS8		(1 << 0)			/* Burst size 8			*/
+#define CNTL3_MDM		(1 << 1)			/* Modify DMA mode		*/
+#define CNTL3_LBTM		(1 << 2)			/* Last Byte Transfer mode	*/
+#define CNTL3_FASTCLK		(1 << 3)			/* Fast SCSI clocking		*/
+#define CNTL3_FASTSCSI		(1 << 4)			/* Fast SCSI			*/
+#define CNTL3_G2CB		(1 << 5)			/* Group2 SCSI support		*/
+#define CNTL3_QTAG		(1 << 6)			/* Enable 3 byte msgs		*/
+#define CNTL3_ADIDCHK		(1 << 7)			/* Additional ID check		*/
+
+/* High transfer count (read/write) */
+#define REG_CTCH		(14)
+#define REG_STCH		(14)
+
+/* ID register (read only) */
+#define REG_ID			(14)
+
+/* Data alignment */
+#define REG_DAL			(15)
+
+typedef enum {
+	PHASE_IDLE,					/* we're not planning on doing anything	*/
+	PHASE_SELECTION,				/* selecting a device			*/
+	PHASE_SELSTEPS,					/* selection with command steps		*/
+	PHASE_COMMAND,					/* command sent				*/
+	PHASE_MESSAGESENT,				/* selected, and we're sending cmd	*/
+	PHASE_DATAOUT,					/* data out to device			*/
+	PHASE_DATAIN,					/* data in from device			*/
+	PHASE_MSGIN,					/* message in from device		*/
+	PHASE_MSGIN_DISCONNECT,				/* disconnecting from bus		*/
+	PHASE_MSGOUT,					/* after message out phase		*/
+	PHASE_MSGOUT_EXPECT,				/* expecting message out		*/
+	PHASE_STATUS,					/* status from device			*/
+	PHASE_DONE					/* Command complete			*/
+} phase_t;
+
+typedef enum {
+	DMA_OUT,					/* DMA from memory to chip		*/
+	DMA_IN						/* DMA from chip to memory		*/
+} fasdmadir_t;
+
+typedef enum {
+	fasdma_none,					/* No dma				*/
+	fasdma_pio,					/* PIO mode				*/
+	fasdma_pseudo,					/* Pseudo DMA				*/
+	fasdma_real_block,				/* Real DMA, on block by block basis	*/
+	fasdma_real_all					/* Real DMA, on request by request	*/
+} fasdmatype_t;
+
+typedef enum {
+	neg_wait,					/* Negociate with device		*/
+	neg_inprogress,					/* Negociation sent			*/
+	neg_complete,					/* Negociation complete			*/
+	neg_targcomplete,				/* Target completed negociation		*/
+	neg_invalid					/* Negociation not supported		*/
+} neg_t;
+
+#define MAGIC	0x441296bdUL
+#define NR_MSGS	8
+
+#define FASCAP_DMA		(1 << 0)
+#define FASCAP_PSEUDODMA	(1 << 1)
+
+typedef struct {
+	unsigned long		magic_start;
+	spinlock_t		host_lock;
+	struct Scsi_Host	*host;			/* host					*/
+	Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
+	Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
+	Scsi_Cmnd		*reqSCpnt;		/* request sense command		*/
+	Scsi_Cmnd		*rstSCpnt;		/* reset command			*/
+	Scsi_Cmnd		*pending_SCpnt[8];	/* per-device pending commands		*/
+	int			next_pending;		/* next pending device			*/
+
+	/*
+	 * Error recovery
+	 */
+	wait_queue_head_t	eh_wait;
+	struct timer_list	eh_timer;
+	unsigned int		rst_dev_status;
+	unsigned int		rst_bus_status;
+
+	/* driver information */
+	struct {
+		phase_t		phase;			/* current phase			*/
+		void __iomem	*io_base;		/* iomem base of FAS216			*/
+		unsigned int	io_shift;		/* shift to adjust reg offsets by	*/
+		unsigned char	cfg[4];			/* configuration registers		*/
+		const char	*type;			/* chip type				*/
+		unsigned int	irq;			/* interrupt				*/
+		int		dma;			/* dma channel				*/
+
+		Scsi_Pointer	SCp;			/* current commands data pointer	*/
+
+		MsgQueue_t	msgs;			/* message queue for connected device	*/
+
+		unsigned int	async_stp;		/* Async transfer STP value		*/
+		unsigned char	msgin_fifo;		/* bytes in fifo at time of message in	*/
+		unsigned char	message[256];		/* last message received from device	*/
+
+		unsigned char	disconnectable:1;	/* this command can be disconnected	*/
+		unsigned char	aborting:1;		/* aborting command			*/
+	} scsi;
+
+	/* statistics information */
+	struct {
+		unsigned int	queues;
+		unsigned int	removes;
+		unsigned int	fins;
+		unsigned int	reads;
+		unsigned int	writes;
+		unsigned int	miscs;
+		unsigned int	disconnects;
+		unsigned int	aborts;
+		unsigned int	bus_resets;
+		unsigned int	host_resets;
+	} stats;
+
+	/* configuration information */
+	struct {
+		unsigned char	clockrate;		/* clock rate of FAS device (MHz)	*/
+		unsigned char	select_timeout;		/* timeout (R5)				*/
+		unsigned char	sync_max_depth;		/* Synchronous xfer max fifo depth	*/
+		unsigned char	wide_max_size;		/* Maximum wide transfer size		*/
+		unsigned char	cntl3;			/* Control Reg 3			*/
+		unsigned int	asyncperiod;		/* Async transfer period (ns)		*/
+		unsigned int	capabilities;		/* driver capabilities			*/
+		unsigned int	disconnect_ok:1;	/* Disconnects allowed?			*/
+	} ifcfg;
+
+	/* queue handling */
+	struct {
+	    	Queue_t		issue;			/* issue queue				*/
+    		Queue_t		disconnected;		/* disconnected command queue		*/
+	} queues;
+
+	/* per-device info */
+	struct fas216_device {
+		unsigned char	disconnect_ok:1;	/* device can disconnect		*/
+		unsigned char	parity_enabled:1;	/* parity checking enabled		*/
+		unsigned char	parity_check:1;		/* need to check parity checking	*/
+		unsigned char	period;			/* sync xfer period in (*4ns)		*/
+		unsigned char	stp;			/* synchronous transfer period		*/
+		unsigned char	sof;			/* synchronous offset register		*/
+		unsigned char	wide_xfer;		/* currently negociated wide transfer	*/
+		neg_t		sync_state;		/* synchronous transfer mode		*/
+		neg_t		wide_state;		/* wide transfer mode			*/
+	} device[8];
+	unsigned long	busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
+
+	/* dma */
+	struct {
+		fasdmatype_t	transfer_type;		/* current type of DMA transfer		*/
+		fasdmatype_t	(*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma);
+		void		(*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer);
+		void		(*stop)  (struct Scsi_Host *host, Scsi_Pointer *SCp);
+	} dma;
+
+	/* miscellaneous */
+	int			internal_done;		/* flag to indicate request done */
+	unsigned long		magic_end;
+} FAS216_Info;
+
+/* Function: int fas216_init (struct Scsi_Host *instance)
+ * Purpose : initialise FAS/NCR/AMD SCSI structures.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern int fas216_init (struct Scsi_Host *instance);
+
+/* Function: int fas216_add (struct Scsi_Host *instance, struct device *dev)
+ * Purpose : initialise FAS/NCR/AMD SCSI ic.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
+
+/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+ * Purpose : queue a command for adapter to process.
+ * Params  : SCpnt - Command to queue
+ *	     done  - done function to call once command is complete
+ * Returns : 0 - success, else error
+ */
+extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+/* Function: int fas216_noqueue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+ * Purpose : queue a command for adapter to process, and process it to completion.
+ * Params  : SCpnt - Command to queue
+ *	     done  - done function to call once command is complete
+ * Returns : 0 - success, else error
+ */
+extern int fas216_noqueue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
+ * Purpose : handle interrupts from the interface to progress a command
+ * Params  : info - interface to service
+ */
+extern irqreturn_t fas216_intr (FAS216_Info *info);
+
+extern void fas216_remove (struct Scsi_Host *instance);
+
+/* Function: void fas216_release (struct Scsi_Host *instance)
+ * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern void fas216_release (struct Scsi_Host *instance);
+
+extern int fas216_print_host(FAS216_Info *info, char *buffer);
+extern int fas216_print_stats(FAS216_Info *info, char *buffer);
+extern int fas216_print_devices(FAS216_Info *info, char *buffer);
+
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params  : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ */
+extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params  : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the complete bus associated with this command
+ * Params  : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params  : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
+
+#endif /* FAS216_H */
diff --git a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c
new file mode 100644
index 0000000..7c95c75
--- /dev/null
+++ b/drivers/scsi/arm/msgqueue.c
@@ -0,0 +1,171 @@
+/*
+ *  linux/drivers/acorn/scsi/msgqueue.c
+ *
+ *  Copyright (C) 1997-1998 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  message queue handling
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+
+#include "msgqueue.h"
+
+/*
+ * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+ * Purpose : Allocate a message queue entry
+ * Params  : msgq - message queue to claim entry for
+ * Returns : message queue entry or NULL.
+ */
+static struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq;
+
+	if ((mq = msgq->free) != NULL)
+		msgq->free = mq->next;
+
+	return mq;
+}
+
+/*
+ * Function: void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+ * Purpose : free a message queue entry
+ * Params  : msgq - message queue to free entry from
+ *	     mq   - message queue entry to free
+ */
+static void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+{
+	if (mq) {
+		mq->next = msgq->free;
+		msgq->free = mq;
+	}
+}
+
+/*
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
+ * Purpose : initialise a message queue
+ * Params  : msgq - queue to initialise
+ */
+void msgqueue_initialise(MsgQueue_t *msgq)
+{
+	int i;
+
+	msgq->qe = NULL;
+	msgq->free = &msgq->entries[0];
+
+	for (i = 0; i < NR_MESSAGES; i++)
+		msgq->entries[i].next = &msgq->entries[i + 1];
+
+	msgq->entries[NR_MESSAGES - 1].next = NULL;
+}
+
+
+/*
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
+ * Purpose : free a queue
+ * Params  : msgq - queue to free
+ */
+void msgqueue_free(MsgQueue_t *msgq)
+{
+}
+
+/*
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
+ * Purpose : calculate the total length of all messages on the message queue
+ * Params  : msgq - queue to examine
+ * Returns : number of bytes of messages in queue
+ */
+int msgqueue_msglength(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq = msgq->qe;
+	int length = 0;
+
+	for (mq = msgq->qe; mq; mq = mq->next)
+		length += mq->msg.length;
+
+	return length;
+}
+
+/*
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message
+ * Params  : msgq   - queue to obtain message from
+ *	   : msgno  - message number
+ * Returns : pointer to message string, or NULL
+ */
+struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+{
+	struct msgqueue_entry *mq;
+
+	for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
+
+	return mq ? &mq->msg : NULL;
+}
+
+/*
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+ * Purpose : add a message onto a message queue
+ * Params  : msgq   - queue to add message on
+ *	     length - length of message
+ *	     ...    - message bytes
+ * Returns : != 0 if successful
+ */
+int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+{
+	struct msgqueue_entry *mq = mqe_alloc(msgq);
+	va_list ap;
+
+	if (mq) {
+		struct msgqueue_entry **mqp;
+		int i;
+
+		va_start(ap, length);
+		for (i = 0; i < length; i++)
+			mq->msg.msg[i] = va_arg(ap, unsigned int);
+		va_end(ap);
+
+		mq->msg.length = length;
+		mq->msg.fifo = 0;
+		mq->next = NULL;
+
+		mqp = &msgq->qe;
+		while (*mqp)
+			mqp = &(*mqp)->next;
+
+		*mqp = mq;
+	}
+
+	return mq != NULL;
+}
+
+/*
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
+ * Purpose : flush all messages from message queue
+ * Params  : msgq - queue to flush
+ */
+void msgqueue_flush(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq, *mqnext;
+
+	for (mq = msgq->qe; mq; mq = mqnext) {
+		mqnext = mq->next;
+		mqe_free(msgq, mq);
+	}
+	msgq->qe = NULL;
+}
+
+EXPORT_SYMBOL(msgqueue_initialise);
+EXPORT_SYMBOL(msgqueue_free);
+EXPORT_SYMBOL(msgqueue_msglength);
+EXPORT_SYMBOL(msgqueue_getmsg);
+EXPORT_SYMBOL(msgqueue_addmsg);
+EXPORT_SYMBOL(msgqueue_flush);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI message queue handling");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h
new file mode 100644
index 0000000..41c7333
--- /dev/null
+++ b/drivers/scsi/arm/msgqueue.h
@@ -0,0 +1,82 @@
+/*
+ *  linux/drivers/acorn/scsi/msgqueue.h
+ *
+ *  Copyright (C) 1997 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  message queue handling
+ */
+#ifndef MSGQUEUE_H
+#define MSGQUEUE_H
+
+struct message {
+    char msg[8];
+    int length;
+    int fifo;
+};
+
+struct msgqueue_entry {
+    struct message msg;
+    struct msgqueue_entry *next;
+};
+
+#define NR_MESSAGES 4
+
+typedef struct {
+    struct msgqueue_entry *qe;
+    struct msgqueue_entry *free;
+    struct msgqueue_entry entries[NR_MESSAGES];
+} MsgQueue_t;
+
+/*
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
+ * Purpose : initialise a message queue
+ * Params  : msgq - queue to initialise
+ */
+extern void msgqueue_initialise(MsgQueue_t *msgq);
+
+/*
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
+ * Purpose : free a queue
+ * Params  : msgq - queue to free
+ */
+extern void msgqueue_free(MsgQueue_t *msgq);
+
+/*
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
+ * Purpose : calculate the total length of all messages on the message queue
+ * Params  : msgq - queue to examine
+ * Returns : number of bytes of messages in queue
+ */
+extern int msgqueue_msglength(MsgQueue_t *msgq);
+
+/*
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message & its length
+ * Params  : msgq   - queue to obtain message from
+ *         : msgno  - message number
+ * Returns : pointer to message string, or NULL
+ */
+extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno);
+
+/*
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+ * Purpose : add a message onto a message queue
+ * Params  : msgq   - queue to add message on
+ *	     length - length of message
+ *	     ...    - message bytes
+ * Returns : != 0 if successful
+ */
+extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...);
+
+/*
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
+ * Purpose : flush all messages from message queue
+ * Params  : msgq - queue to flush
+ */
+extern void msgqueue_flush(MsgQueue_t *msgq);
+
+#endif
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
new file mode 100644
index 0000000..ff2554f
--- /dev/null
+++ b/drivers/scsi/arm/oak.c
@@ -0,0 +1,217 @@
+/*
+ * Oak Generic NCR5380 driver
+ *
+ * Copyright 1995-2002, Russell King
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+
+#define AUTOSENSE
+/*#define PSEUDO_DMA*/
+
+#define OAKSCSI_PUBLIC_RELEASE 1
+
+#define NCR5380_read(reg)		oakscsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	oakscsi_write(_instance, reg, value)
+#define NCR5380_intr			oakscsi_intr
+#define NCR5380_queue_command		oakscsi_queue_command
+#define NCR5380_proc_info		oakscsi_proc_info
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.h"
+
+#undef START_DMA_INITIATOR_RECEIVE_REG
+#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+
+const char * oakscsi_info (struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#define STAT(p)   inw(p + 144)
+extern void inswb(int from, void *to, int len);
+
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
+              int len)
+{
+  int iobase = instance->io_port;
+printk("writing %p len %d\n",addr, len);
+  if(!len) return -1;
+
+  while(1)
+  {
+    int status;
+    while(((status = STAT(iobase)) & 0x100)==0);
+  }
+}
+
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
+              int len)
+{
+  int iobase = instance->io_port;
+printk("reading %p len %d\n", addr, len);
+  while(len > 0)
+  {
+    int status, timeout;
+    unsigned long b;
+    
+    timeout = 0x01FFFFFF;
+    
+    while(((status = STAT(iobase)) & 0x100)==0)
+    {
+      timeout--;
+      if(status & 0x200 || !timeout)
+      {
+        printk("status = %08X\n",status);
+        return 1;
+      }
+    }
+    if(len >= 128)
+    {
+      inswb(iobase + 136, addr, 128);
+      addr += 128;
+      len -= 128;
+    }
+    else
+    {
+      b = (unsigned long) inw(iobase + 136);
+      *addr ++ = b;
+      len -= 1;
+      if(len)
+        *addr ++ = b>>8;
+      len -= 1;
+    }
+  }
+  return 0;
+}
+
+#define oakscsi_read(instance,reg)	(inb((instance)->io_port + (reg)))
+#define oakscsi_write(instance,reg,val)	(outb((val), (instance)->io_port + (reg)))
+
+#undef STAT
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template oakscsi_template = {
+	.module			= THIS_MODULE,
+	.proc_info		= oakscsi_proc_info,
+	.name			= "Oak 16-bit SCSI",
+	.info			= oakscsi_info,
+	.queuecommand		= oakscsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "oakscsi",
+};
+
+static int __devinit
+oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	int ret = -ENOMEM;
+
+	host = scsi_host_alloc(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		goto out;
+
+	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+	host->irq = IRQ_NONE;
+	host->n_io_port = 255;
+
+	ret = -EBUSY;
+	if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
+		goto unreg;
+
+	NCR5380_init(host, 0);
+
+	printk("scsi%d: at port 0x%08lx irqs disabled",
+		host->host_no, host->io_port);
+	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret)
+		goto out_release;
+
+	scsi_scan_host(host);
+	goto out;
+
+ out_release:
+	release_region(host->io_port, host->n_io_port);
+ unreg:
+	scsi_host_put(host);
+ out:
+	return ret;
+}
+
+static void __devexit oakscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);
+	scsi_remove_host(host);
+
+	NCR5380_exit(host);
+	release_region(host->io_port, host->n_io_port);
+	scsi_host_put(host);
+}
+
+static const struct ecard_id oakscsi_cids[] = {
+	{ MANU_OAK, PROD_OAK_SCSI },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver oakscsi_driver = {
+	.probe		= oakscsi_probe,
+	.remove		= __devexit_p(oakscsi_remove),
+	.id_table	= oakscsi_cids,
+	.drv = {
+		.name		= "oakscsi",
+	},
+};
+
+static int __init oakscsi_init(void)
+{
+	return ecard_register_driver(&oakscsi_driver);
+}
+
+static void __exit oakscsi_exit(void)
+{
+	ecard_remove_driver(&oakscsi_driver);
+}
+
+module_init(oakscsi_init);
+module_exit(oakscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Oak SCSI driver");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
new file mode 100644
index 0000000..54f23be
--- /dev/null
+++ b/drivers/scsi/arm/powertec.c
@@ -0,0 +1,472 @@
+/*
+ *  linux/drivers/acorn/scsi/powertec.c
+ *
+ *  Copyright (C) 1997-2005 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include <scsi/scsi_host.h>
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define POWERTEC_FAS216_OFFSET	0x3000
+#define POWERTEC_FAS216_SHIFT	6
+
+#define POWERTEC_INTR_STATUS	0x2000
+#define POWERTEC_INTR_BIT	0x80
+
+#define POWERTEC_RESET_CONTROL	0x1018
+#define POWERTEC_RESET_BIT	1
+
+#define POWERTEC_TERM_CONTROL	0x2018
+#define POWERTEC_TERM_ENABLE	1
+
+#define POWERTEC_INTR_CONTROL	0x101c
+#define POWERTEC_INTR_ENABLE	1
+#define POWERTEC_INTR_DISABLE	0
+
+#define VERSION	"1.10 (19/01/2003 2.5.59)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off.
+ * One entry per slot.
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct powertec_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+	void __iomem		*base;
+	unsigned int		term_ctl;
+	struct scatterlist	sg[NR_SG];
+};
+
+/* Prototype: void powertecscsi_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on Powertec SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+powertecscsi_irqenable(struct expansion_card *ec, int irqnr)
+{
+	struct powertec_info *info = ec->irq_data;
+	writeb(POWERTEC_INTR_ENABLE, info->base + POWERTEC_INTR_CONTROL);
+}
+
+/* Prototype: void powertecscsi_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on Powertec SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+powertecscsi_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	struct powertec_info *info = ec->irq_data;
+	writeb(POWERTEC_INTR_DISABLE, info->base + POWERTEC_INTR_CONTROL);
+}
+
+static const expansioncard_ops_t powertecscsi_ops = {
+	.irqenable	= powertecscsi_irqenable,
+	.irqdisable	= powertecscsi_irqdisable,
+};
+
+/* Prototype: void powertecscsi_terminator_ctl(host, on_off)
+ * Purpose  : Turn the Powertec SCSI terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+
+	info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0;
+	writeb(info->term_ctl, info->base + POWERTEC_TERM_CONTROL);
+}
+
+/* Prototype: void powertecscsi_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from Powertec SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct powertec_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = info->info.scsi.dma;
+
+	if (info->info.ifcfg.capabilities & FASCAP_DMA &&
+	    min_type == fasdma_real_all) {
+		int bufs, map_dir, dma_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		return fasdma_real_all;
+	}
+
+	/*
+	 * If we're not doing DMA,
+	 *  we'll do slow PIO
+	 */
+	return fasdma_pio;
+}
+
+/* Prototype: int powertecscsi_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	if (info->info.scsi.dma != NO_DMA)
+		disable_dma(info->info.scsi.dma);
+}
+
+/* Prototype: const char *powertecscsi_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *powertecscsi_info(struct Scsi_Host *host)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->term_ctl ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 12 && strncmp(buffer, "POWERTECSCSI", 12) == 0) {
+		buffer += 12;
+		length -= 12;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				powertecscsi_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				powertecscsi_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
+ *					int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer  - a buffer to write information to
+ *	      start   - a pointer into this buffer set by this routine to the start
+ *		        of the required information.
+ *	      offset  - offset into information that we have read upto.
+ *	      length  - length of buffer
+ *	      inout   - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			    int length, int inout)
+{
+	struct powertec_info *info;
+	char *p = buffer;
+	int pos;
+
+	if (inout == 1)
+		return powertecscsi_set_proc_info(host, buffer, length);
+
+	info = (struct powertec_info *)host->hostdata;
+
+	p += sprintf(p, "PowerTec SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->term_ctl ? "n" : "ff");
+
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static ssize_t powertecscsi_show_term(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+
+	return sprintf(buf, "%d\n", info->term_ctl ? 1 : 0);
+}
+
+static ssize_t
+powertecscsi_store_term(struct device *dev, const char *buf, size_t len)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	if (len > 1)
+		powertecscsi_terminator_ctl(host, buf[0] != '0');
+
+	return len;
+}
+
+static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
+		   powertecscsi_show_term, powertecscsi_store_term);
+
+static Scsi_Host_Template powertecscsi_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= powertecscsi_proc_info,
+	.name				= "PowerTec SCSI",
+	.info				= powertecscsi_info,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+
+	.can_queue			= 8,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 2,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.proc_name			= "powertec",
+};
+
+static int __devinit
+powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct powertec_info *info;
+	unsigned long resbase, reslen;
+	void __iomem *base;
+	int ret;
+
+	ret = ecard_request_resources(ec);
+	if (ret)
+		goto out;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_host_alloc(&powertecscsi_template,
+			       sizeof (struct powertec_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct powertec_info *)host->hostdata;
+	info->base = base;
+	powertecscsi_terminator_ctl(host, term[ec->slot_no]);
+
+	info->info.scsi.io_base		= base + POWERTEC_FAS216_OFFSET;
+	info->info.scsi.io_shift	= POWERTEC_FAS216_SHIFT;
+	info->info.scsi.irq		= ec->irq;
+	info->info.scsi.dma		= ec->dma;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= 0;
+	info->info.dma.setup		= powertecscsi_dma_setup;
+	info->info.dma.pseudo		= NULL;
+	info->info.dma.stop		= powertecscsi_dma_stop;
+
+	ec->irqaddr	= base + POWERTEC_INTR_STATUS;
+	ec->irqmask	= POWERTEC_INTR_BIT;
+	ec->irq_data	= info;
+	ec->ops		= &powertecscsi_ops;
+
+	device_create_file(&ec->dev, &dev_attr_bus_term);
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(ec->irq, powertecscsi_intr,
+			  SA_INTERRUPT, "powertec", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, ec->irq, ret);
+		goto out_release;
+	}
+
+	if (info->info.scsi.dma != NO_DMA) {
+		if (request_dma(info->info.scsi.dma, "powertec")) {
+			printk("scsi%d: DMA%d not free, using PIO\n",
+			       host->host_no, info->info.scsi.dma);
+			info->info.scsi.dma = NO_DMA;
+		} else {
+			set_dma_speed(info->info.scsi.dma, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, host);
+
+ out_release:
+	fas216_release(host);
+
+ out_free:
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+	scsi_host_put(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	ecard_release_resources(ec);
+
+ out:
+	return ret;
+}
+
+static void __devexit powertecscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+
+	if (info->info.scsi.dma != NO_DMA)
+		free_dma(info->info.scsi.dma);
+	free_irq(ec->irq, info);
+
+	iounmap(info->base);
+
+	fas216_release(host);
+	scsi_host_put(host);
+	ecard_release_resources(ec);
+}
+
+static const struct ecard_id powertecscsi_cids[] = {
+	{ MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver powertecscsi_driver = {
+	.probe		= powertecscsi_probe,
+	.remove		= __devexit_p(powertecscsi_remove),
+	.id_table	= powertecscsi_cids,
+	.drv = {
+		.name		= "powertecscsi",
+	},
+};
+
+static int __init powertecscsi_init(void)
+{
+	return ecard_register_driver(&powertecscsi_driver);
+}
+
+static void __exit powertecscsi_exit(void)
+{
+	ecard_remove_driver(&powertecscsi_driver);
+}
+
+module_init(powertecscsi_init);
+module_exit(powertecscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Powertec SCSI driver");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
new file mode 100644
index 0000000..e6d1592
--- /dev/null
+++ b/drivers/scsi/arm/queue.c
@@ -0,0 +1,319 @@
+/*
+ *  linux/drivers/acorn/scsi/queue.c: queue handling primitives
+ *
+ *  Copyright (C) 1997-2000 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Changelog:
+ *   15-Sep-1997 RMK	Created.
+ *   11-Oct-1997 RMK	Corrected problem with queue_remove_exclude
+ *			not updating internal linked list properly
+ *			(was causing commands to go missing).
+ *   30-Aug-2000 RMK	Use Linux list handling and spinlocks
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/init.h>
+
+#include "../scsi.h"
+
+#define DEBUG
+
+typedef struct queue_entry {
+	struct list_head   list;
+	Scsi_Cmnd	   *SCpnt;
+#ifdef DEBUG
+	unsigned long	   magic;
+#endif
+} QE_t;
+
+#ifdef DEBUG
+#define QUEUE_MAGIC_FREE	0xf7e1c9a3
+#define QUEUE_MAGIC_USED	0xf7e1cc33
+
+#define SET_MAGIC(q,m)	((q)->magic = (m))
+#define BAD_MAGIC(q,m)	((q)->magic != (m))
+#else
+#define SET_MAGIC(q,m)	do { } while (0)
+#define BAD_MAGIC(q,m)	(0)
+#endif
+
+#include "queue.h"
+
+#define NR_QE	32
+
+/*
+ * Function: void queue_initialise (Queue_t *queue)
+ * Purpose : initialise a queue
+ * Params  : queue - queue to initialise
+ */
+int queue_initialise (Queue_t *queue)
+{
+	unsigned int nqueues = NR_QE;
+	QE_t *q;
+
+	spin_lock_init(&queue->queue_lock);
+	INIT_LIST_HEAD(&queue->head);
+	INIT_LIST_HEAD(&queue->free);
+
+	/*
+	 * If life was easier, then SCpnt would have a
+	 * host-available list head, and we wouldn't
+	 * need to keep free lists or allocate this
+	 * memory.
+	 */
+	queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL);
+	if (q) {
+		for (; nqueues; q++, nqueues--) {
+			SET_MAGIC(q, QUEUE_MAGIC_FREE);
+			q->SCpnt = NULL;
+			list_add(&q->list, &queue->free);
+		}
+	}
+
+	return queue->alloc != NULL;
+}
+
+/*
+ * Function: void queue_free (Queue_t *queue)
+ * Purpose : free a queue
+ * Params  : queue - queue to free
+ */
+void queue_free (Queue_t *queue)
+{
+	if (!list_empty(&queue->head))
+		printk(KERN_WARNING "freeing non-empty queue %p\n", queue);
+	if (queue->alloc)
+		kfree(queue->alloc);
+}
+     
+
+/*
+ * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
+ * Params  : queue - destination queue
+ *	     SCpnt - command to add
+ *	     head  - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+{
+	unsigned long flags;
+	struct list_head *l;
+	QE_t *q;
+	int ret = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	if (list_empty(&queue->free))
+		goto empty;
+
+	l = queue->free.next;
+	list_del(l);
+
+	q = list_entry(l, QE_t, list);
+	if (BAD_MAGIC(q, QUEUE_MAGIC_FREE))
+		BUG();
+
+	SET_MAGIC(q, QUEUE_MAGIC_USED);
+	q->SCpnt = SCpnt;
+
+	if (head)
+		list_add(l, &queue->head);
+	else
+		list_add_tail(l, &queue->head);
+
+	ret = 1;
+empty:
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+	return ret;
+}
+
+static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
+{
+	QE_t *q;
+
+	/*
+	 * Move the entry from the "used" list onto the "free" list
+	 */
+	list_del(ent);
+	q = list_entry(ent, QE_t, list);
+	if (BAD_MAGIC(q, QUEUE_MAGIC_USED))
+		BUG();
+
+	SET_MAGIC(q, QUEUE_MAGIC_FREE);
+	list_add(ent, &queue->free);
+
+	return q->SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ *	     exclude - bit array of target&lun which is busy
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
+{
+	unsigned long flags;
+	struct list_head *l;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (!test_bit(q->SCpnt->device->id * 8 + q->SCpnt->device->lun, exclude)) {
+			SCpnt = __queue_remove(queue, l);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+Scsi_Cmnd *queue_remove(Queue_t *queue)
+{
+	unsigned long flags;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	if (!list_empty(&queue->head))
+		SCpnt = __queue_remove(queue, queue->head.next);
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params  : queue  - queue to remove command from
+ *	     target - target that we want
+ *	     lun    - lun on device
+ *	     tag    - tag on device
+ * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ */
+Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
+{
+	unsigned long flags;
+	struct list_head *l;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun &&
+		    q->SCpnt->tag == tag) {
+			SCpnt = __queue_remove(queue, l);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: queue_remove_all_target(queue, target)
+ * Purpose : remove all SCSI commands from the queue for a specified target
+ * Params  : queue  - queue to remove command from
+ *           target - target device id
+ * Returns : nothing
+ */
+void queue_remove_all_target(Queue_t *queue, int target)
+{
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target)
+			__queue_remove(queue, l);
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+}
+
+/*
+ * Function: int queue_probetgtlun (queue, target, lun)
+ * Purpose : check to see if we have a command in the queue for the specified
+ *	     target/lun.
+ * Params  : queue  - queue to look in
+ *	     target - target we want to probe
+ *	     lun    - lun on target
+ * Returns : 0 if not found, != 0 if found
+ */
+int queue_probetgtlun (Queue_t *queue, int target, int lun)
+{
+	unsigned long flags;
+	struct list_head *l;
+	int found = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return found;
+}
+
+/*
+ * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params  : queue - queue to look in
+ *	     SCpnt - command to find
+ * Returns : 0 if not found
+ */
+int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+{
+	unsigned long flags;
+	struct list_head *l;
+	int found = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt == SCpnt) {
+			__queue_remove(queue, l);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return found;
+}
+
+EXPORT_SYMBOL(queue_initialise);
+EXPORT_SYMBOL(queue_free);
+EXPORT_SYMBOL(__queue_add);
+EXPORT_SYMBOL(queue_remove);
+EXPORT_SYMBOL(queue_remove_exclude);
+EXPORT_SYMBOL(queue_remove_tgtluntag);
+EXPORT_SYMBOL(queue_remove_cmd);
+EXPORT_SYMBOL(queue_remove_all_target);
+EXPORT_SYMBOL(queue_probetgtlun);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI command queueing");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
new file mode 100644
index 0000000..0c9dec4
--- /dev/null
+++ b/drivers/scsi/arm/queue.h
@@ -0,0 +1,105 @@
+/*
+ *  linux/drivers/acorn/scsi/queue.h: queue handling
+ *
+ *  Copyright (C) 1997 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef struct {
+	struct list_head head;
+	struct list_head free;
+	spinlock_t queue_lock;
+	void *alloc;			/* start of allocated mem */
+} Queue_t;
+
+/*
+ * Function: void queue_initialise (Queue_t *queue)
+ * Purpose : initialise a queue
+ * Params  : queue - queue to initialise
+ */
+extern int queue_initialise (Queue_t *queue);
+
+/*
+ * Function: void queue_free (Queue_t *queue)
+ * Purpose : free a queue
+ * Params  : queue - queue to free
+ */
+extern void queue_free (Queue_t *queue);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+extern Scsi_Cmnd *queue_remove (Queue_t *queue);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ *	     exclude - array of busy LUNs
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
+
+#define queue_add_cmd_ordered(queue,SCpnt) \
+	__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
+#define queue_add_cmd_tail(queue,SCpnt) \
+	__queue_add(queue,SCpnt,0)
+/*
+ * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue
+ * Params  : queue - destination queue
+ *	     SCpnt - command to add
+ *	     head  - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params  : queue  - queue to remove command from
+ *	     target - target that we want
+ *	     lun    - lun on device
+ *	     tag    - tag on device
+ * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ */
+extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
+
+/*
+ * Function: queue_remove_all_target(queue, target)
+ * Purpose : remove all SCSI commands from the queue for a specified target
+ * Params  : queue  - queue to remove command from
+ *           target - target device id
+ * Returns : nothing
+ */
+extern void queue_remove_all_target(Queue_t *queue, int target);
+
+/*
+ * Function: int queue_probetgtlun (queue, target, lun)
+ * Purpose : check to see if we have a command in the queue for the specified
+ *	     target/lun.
+ * Params  : queue  - queue to look in
+ *	     target - target we want to probe
+ *	     lun    - lun on target
+ * Returns : 0 if not found, != 0 if found
+ */
+extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
+
+/*
+ * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params  : queue - queue to look in
+ *	     SCpnt - command to find
+ * Returns : 0 if not found
+ */
+int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
+
+#endif /* QUEUE_H */
diff --git a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
new file mode 100644
index 0000000..2f1b3f4
--- /dev/null
+++ b/drivers/scsi/arm/scsi.h
@@ -0,0 +1,115 @@
+/*
+ *  linux/drivers/acorn/scsi/scsi.h
+ *
+ *  Copyright (C) 2002 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  Commonly used scsi driver functions.
+ */
+
+#define BELT_AND_BRACES
+
+/*
+ * The scatter-gather list handling.  This contains all
+ * the yucky stuff that needs to be fixed properly.
+ */
+static inline int copy_SCp_to_sg(struct scatterlist *sg, Scsi_Pointer *SCp, int max)
+{
+	int bufs = SCp->buffers_residual;
+
+	BUG_ON(bufs + 1 > max);
+
+	sg->page   = virt_to_page(SCp->ptr);
+	sg->offset = offset_in_page(SCp->ptr);
+	sg->length = SCp->this_residual;
+
+	if (bufs)
+		memcpy(sg + 1, SCp->buffer + 1,
+		       sizeof(struct scatterlist) * bufs);
+	return bufs + 1;
+}
+
+static inline int next_SCp(Scsi_Pointer *SCp)
+{
+	int ret = SCp->buffers_residual;
+	if (ret) {
+		SCp->buffer++;
+		SCp->buffers_residual--;
+		SCp->ptr = (char *)
+			 (page_address(SCp->buffer->page) +
+			  SCp->buffer->offset);
+		SCp->this_residual = SCp->buffer->length;
+	} else {
+		SCp->ptr = NULL;
+		SCp->this_residual = 0;
+	}
+	return ret;
+}
+
+static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp)
+{
+	char c = *SCp->ptr;
+
+	SCp->ptr += 1;
+	SCp->this_residual -= 1;
+
+	return c;
+}
+
+static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c)
+{
+	*SCp->ptr = c;
+	SCp->ptr += 1;
+	SCp->this_residual -= 1;
+}
+
+static inline void init_SCp(Scsi_Cmnd *SCpnt)
+{
+	memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
+
+	if (SCpnt->use_sg) {
+		unsigned long len = 0;
+		int buf;
+
+		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+		SCpnt->SCp.ptr = (char *)
+			 (page_address(SCpnt->SCp.buffer->page) +
+			  SCpnt->SCp.buffer->offset);
+		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+
+#ifdef BELT_AND_BRACES
+		/*
+		 * Calculate correct buffer length.  Some commands
+		 * come in with the wrong request_bufflen.
+		 */
+		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
+			len += SCpnt->SCp.buffer[buf].length;
+
+		if (SCpnt->request_bufflen != len)
+			printk(KERN_WARNING "scsi%d.%c: bad request buffer "
+			       "length %d, should be %ld\n", SCpnt->device->host->host_no,
+			       '0' + SCpnt->device->id, SCpnt->request_bufflen, len);
+		SCpnt->request_bufflen = len;
+#endif
+	} else {
+		SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
+		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+	}
+
+	/*
+	 * If the upper SCSI layers pass a buffer, but zero length,
+	 * we aren't interested in the buffer pointer.
+	 */
+	if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
+#if 0 //def BELT_AND_BRACES
+		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+		       "command ", SCpnt->host->host_no, '0' + SCpnt->target);
+		print_command(SCpnt->cmnd);
+#endif
+		SCpnt->SCp.ptr = NULL;
+	}
+}
diff --git a/drivers/scsi/ata_piix.c b/drivers/scsi/ata_piix.c
new file mode 100644
index 0000000..ce19728
--- /dev/null
+++ b/drivers/scsi/ata_piix.c
@@ -0,0 +1,690 @@
+/*
+
+    ata_piix.c - Intel PATA/SATA controllers
+
+    Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+    		    Please ALWAYS copy linux-ide@vger.kernel.org
+		    on emails.
+
+
+	Copyright 2003-2004 Red Hat Inc
+	Copyright 2003-2004 Jeff Garzik
+
+
+	Copyright header from piix.c:
+
+    Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer
+    Copyright (C) 1998-2000 Andre Hedrick <andre@linux-ide.org>
+    Copyright (C) 2003 Red Hat Inc <alan@redhat.com>
+
+    May be copied or modified under the terms of the GNU General Public License
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"ata_piix"
+#define DRV_VERSION	"1.03"
+
+enum {
+	PIIX_IOCFG		= 0x54, /* IDE I/O configuration register */
+	ICH5_PMR		= 0x90, /* port mapping register */
+	ICH5_PCS		= 0x92,	/* port control and status */
+
+	PIIX_FLAG_AHCI		= (1 << 28), /* AHCI possible */
+	PIIX_FLAG_CHECKINTR	= (1 << 29), /* make sure PCI INTx enabled */
+	PIIX_FLAG_COMBINED	= (1 << 30), /* combined mode possible */
+
+	/* combined mode.  if set, PATA is channel 0.
+	 * if clear, PATA is channel 1.
+	 */
+	PIIX_COMB_PATA_P0	= (1 << 1),
+	PIIX_COMB		= (1 << 2), /* combined mode enabled? */
+
+	PIIX_PORT_PRESENT	= (1 << 0),
+	PIIX_PORT_ENABLED	= (1 << 4),
+
+	PIIX_80C_PRI		= (1 << 5) | (1 << 4),
+	PIIX_80C_SEC		= (1 << 7) | (1 << 6),
+
+	ich5_pata		= 0,
+	ich5_sata		= 1,
+	piix4_pata		= 2,
+	ich6_sata		= 3,
+	ich6_sata_rm		= 4,
+	ich7_sata		= 5,
+};
+
+static int piix_init_one (struct pci_dev *pdev,
+				    const struct pci_device_id *ent);
+
+static void piix_pata_phy_reset(struct ata_port *ap);
+static void piix_sata_phy_reset(struct ata_port *ap);
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev);
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev);
+
+static unsigned int in_module_init = 1;
+
+static struct pci_device_id piix_pci_tbl[] = {
+#ifdef ATA_ENABLE_PATA
+	{ 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata },
+	{ 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+	{ 0x8086, 0x25a2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata },
+#endif
+
+	/* NOTE: The following PCI ids must be kept in sync with the
+	 * list in drivers/pci/quirks.c.
+	 */
+
+	{ 0x8086, 0x24d1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x24df, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x25a3, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x25b0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_sata },
+	{ 0x8086, 0x2651, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata },
+	{ 0x8086, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+	{ 0x8086, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_rm },
+	{ 0x8086, 0x27c0, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+	{ 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7_sata },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver piix_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= piix_pci_tbl,
+	.probe			= piix_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template piix_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations piix_pata_ops = {
+	.port_disable		= ata_port_disable,
+	.set_piomode		= piix_set_piomode,
+	.set_dmamode		= piix_set_dmamode,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.phy_reset		= piix_pata_phy_reset,
+
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_operations piix_sata_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.phy_reset		= piix_sata_phy_reset,
+
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info piix_port_info[] = {
+	/* ich5_pata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST |
+				  PIIX_FLAG_CHECKINTR,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+#if 0
+		.mwdma_mask	= 0x06, /* mwdma1-2 */
+#else
+		.mwdma_mask	= 0x00, /* mwdma broken */
+#endif
+		.udma_mask	= 0x3f, /* udma0-5 */
+		.port_ops	= &piix_pata_ops,
+	},
+
+	/* ich5_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+
+	/* piix4_pata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SLAVE_POSS | ATA_FLAG_SRST,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+#if 0
+		.mwdma_mask	= 0x06, /* mwdma1-2 */
+#else
+		.mwdma_mask	= 0x00, /* mwdma broken */
+#endif
+		.udma_mask	= ATA_UDMA_MASK_40C,
+		.port_ops	= &piix_pata_ops,
+	},
+
+	/* ich6_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+
+	/* ich6_sata_rm */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+
+	/* ich7_sata */
+	{
+		.sht		= &piix_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST |
+				  PIIX_FLAG_COMBINED | PIIX_FLAG_CHECKINTR |
+				  ATA_FLAG_SLAVE_POSS | PIIX_FLAG_AHCI,
+		.pio_mask	= 0x1f,	/* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f,	/* udma0-6 */
+		.port_ops	= &piix_sata_ops,
+	},
+};
+
+static struct pci_bits piix_enable_bits[] = {
+	{ 0x41U, 1U, 0x80UL, 0x80UL },	/* port 0 */
+	{ 0x43U, 1U, 0x80UL, 0x80UL },	/* port 1 */
+};
+
+MODULE_AUTHOR("Andre Hedrick, Alan Cox, Andrzej Krzysztofowicz, Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for Intel PIIX/ICH ATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, piix_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ *	piix_pata_cbl_detect - Probe host controller cable detect info
+ *	@ap: Port for which cable detect info is desired
+ *
+ *	Read 80c cable indicator from ATA PCI device's PCI config
+ *	register.  This register is normally set by firmware (BIOS).
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+static void piix_pata_cbl_detect(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	u8 tmp, mask;
+
+	/* no 80c support in host controller? */
+	if ((ap->udma_mask & ~ATA_UDMA_MASK_40C) == 0)
+		goto cbl40;
+
+	/* check BIOS cable detect results */
+	mask = ap->hard_port_no == 0 ? PIIX_80C_PRI : PIIX_80C_SEC;
+	pci_read_config_byte(pdev, PIIX_IOCFG, &tmp);
+	if ((tmp & mask) == 0)
+		goto cbl40;
+
+	ap->cbl = ATA_CBL_PATA80;
+	return;
+
+cbl40:
+	ap->cbl = ATA_CBL_PATA40;
+	ap->udma_mask &= ATA_UDMA_MASK_40C;
+}
+
+/**
+ *	piix_pata_phy_reset - Probe specified port on PATA host controller
+ *	@ap: Port to probe
+ *
+ *	Probe PATA phy.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_pata_phy_reset(struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+
+	if (!pci_test_config_bits(pdev, &piix_enable_bits[ap->hard_port_no])) {
+		ata_port_disable(ap);
+		printk(KERN_INFO "ata%u: port disabled. ignoring.\n", ap->id);
+		return;
+	}
+
+	piix_pata_cbl_detect(ap);
+
+	ata_port_probe(ap);
+
+	ata_bus_reset(ap);
+}
+
+/**
+ *	piix_sata_probe - Probe PCI device for present SATA devices
+ *	@ap: Port associated with the PCI device we wish to probe
+ *
+ *	Reads SATA PCI device's PCI config register Port Configuration
+ *	and Status (PCS) to determine port and device availability.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ *
+ *	RETURNS:
+ *	Non-zero if device detected, zero otherwise.
+ */
+static int piix_sata_probe (struct ata_port *ap)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	int combined = (ap->flags & ATA_FLAG_SLAVE_POSS);
+	int orig_mask, mask, i;
+	u8 pcs;
+
+	mask = (PIIX_PORT_PRESENT << ap->hard_port_no) |
+	       (PIIX_PORT_ENABLED << ap->hard_port_no);
+
+	pci_read_config_byte(pdev, ICH5_PCS, &pcs);
+	orig_mask = (int) pcs & 0xff;
+
+	/* TODO: this is vaguely wrong for ICH6 combined mode,
+	 * where only two of the four SATA ports are mapped
+	 * onto a single ATA channel.  It is also vaguely inaccurate
+	 * for ICH5, which has only two ports.  However, this is ok,
+	 * as further device presence detection code will handle
+	 * any false positives produced here.
+	 */
+
+	for (i = 0; i < 4; i++) {
+		mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i);
+
+		if ((orig_mask & mask) == mask)
+			if (combined || (i == ap->hard_port_no))
+				return 1;
+	}
+
+	return 0;
+}
+
+/**
+ *	piix_sata_phy_reset - Probe specified port on SATA host controller
+ *	@ap: Port to probe
+ *
+ *	Probe SATA phy.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_sata_phy_reset(struct ata_port *ap)
+{
+	if (!piix_sata_probe(ap)) {
+		ata_port_disable(ap);
+		printk(KERN_INFO "ata%u: SATA port has no device.\n", ap->id);
+		return;
+	}
+
+	ap->cbl = ATA_CBL_SATA;
+
+	ata_port_probe(ap);
+
+	ata_bus_reset(ap);
+}
+
+/**
+ *	piix_set_piomode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *	@pio: PIO mode, 0 - 4
+ *
+ *	Set PIO mode for device, in host controller PCI config space.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_set_piomode (struct ata_port *ap, struct ata_device *adev)
+{
+	unsigned int pio	= adev->pio_mode - XFER_PIO_0;
+	struct pci_dev *dev	= to_pci_dev(ap->host_set->dev);
+	unsigned int is_slave	= (adev->devno != 0);
+	unsigned int master_port= ap->hard_port_no ? 0x42 : 0x40;
+	unsigned int slave_port	= 0x44;
+	u16 master_data;
+	u8 slave_data;
+
+	static const	 /* ISP  RTC */
+	u8 timings[][2]	= { { 0, 0 },
+			    { 0, 0 },
+			    { 1, 0 },
+			    { 2, 1 },
+			    { 2, 3 }, };
+
+	pci_read_config_word(dev, master_port, &master_data);
+	if (is_slave) {
+		master_data |= 0x4000;
+		/* enable PPE, IE and TIME */
+		master_data |= 0x0070;
+		pci_read_config_byte(dev, slave_port, &slave_data);
+		slave_data &= (ap->hard_port_no ? 0x0f : 0xf0);
+		slave_data |=
+			(timings[pio][0] << 2) |
+			(timings[pio][1] << (ap->hard_port_no ? 4 : 0));
+	} else {
+		master_data &= 0xccf8;
+		/* enable PPE, IE and TIME */
+		master_data |= 0x0007;
+		master_data |=
+			(timings[pio][0] << 12) |
+			(timings[pio][1] << 8);
+	}
+	pci_write_config_word(dev, master_port, master_data);
+	if (is_slave)
+		pci_write_config_byte(dev, slave_port, slave_data);
+}
+
+/**
+ *	piix_set_dmamode - Initialize host controller PATA PIO timings
+ *	@ap: Port whose timings we are configuring
+ *	@adev: um
+ *	@udma: udma mode, 0 - 6
+ *
+ *	Set UDMA mode for device, in host controller PCI config space.
+ *
+ *	LOCKING:
+ *	None (inherited from caller).
+ */
+
+static void piix_set_dmamode (struct ata_port *ap, struct ata_device *adev)
+{
+	unsigned int udma	= adev->dma_mode; /* FIXME: MWDMA too */
+	struct pci_dev *dev	= to_pci_dev(ap->host_set->dev);
+	u8 maslave		= ap->hard_port_no ? 0x42 : 0x40;
+	u8 speed		= udma;
+	unsigned int drive_dn	= (ap->hard_port_no ? 2 : 0) + adev->devno;
+	int a_speed		= 3 << (drive_dn * 4);
+	int u_flag		= 1 << drive_dn;
+	int v_flag		= 0x01 << drive_dn;
+	int w_flag		= 0x10 << drive_dn;
+	int u_speed		= 0;
+	int			sitre;
+	u16			reg4042, reg4a;
+	u8			reg48, reg54, reg55;
+
+	pci_read_config_word(dev, maslave, &reg4042);
+	DPRINTK("reg4042 = 0x%04x\n", reg4042);
+	sitre = (reg4042 & 0x4000) ? 1 : 0;
+	pci_read_config_byte(dev, 0x48, &reg48);
+	pci_read_config_word(dev, 0x4a, &reg4a);
+	pci_read_config_byte(dev, 0x54, &reg54);
+	pci_read_config_byte(dev, 0x55, &reg55);
+
+	switch(speed) {
+		case XFER_UDMA_4:
+		case XFER_UDMA_2:	u_speed = 2 << (drive_dn * 4); break;
+		case XFER_UDMA_6:
+		case XFER_UDMA_5:
+		case XFER_UDMA_3:
+		case XFER_UDMA_1:	u_speed = 1 << (drive_dn * 4); break;
+		case XFER_UDMA_0:	u_speed = 0 << (drive_dn * 4); break;
+		case XFER_MW_DMA_2:
+		case XFER_MW_DMA_1:	break;
+		default:
+			BUG();
+			return;
+	}
+
+	if (speed >= XFER_UDMA_0) {
+		if (!(reg48 & u_flag))
+			pci_write_config_byte(dev, 0x48, reg48 | u_flag);
+		if (speed == XFER_UDMA_5) {
+			pci_write_config_byte(dev, 0x55, (u8) reg55|w_flag);
+		} else {
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+		}
+		if ((reg4a & a_speed) != u_speed)
+			pci_write_config_word(dev, 0x4a, (reg4a & ~a_speed) | u_speed);
+		if (speed > XFER_UDMA_2) {
+			if (!(reg54 & v_flag))
+				pci_write_config_byte(dev, 0x54, reg54 | v_flag);
+		} else
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+	} else {
+		if (reg48 & u_flag)
+			pci_write_config_byte(dev, 0x48, reg48 & ~u_flag);
+		if (reg4a & a_speed)
+			pci_write_config_word(dev, 0x4a, reg4a & ~a_speed);
+		if (reg54 & v_flag)
+			pci_write_config_byte(dev, 0x54, reg54 & ~v_flag);
+		if (reg55 & w_flag)
+			pci_write_config_byte(dev, 0x55, (u8) reg55 & ~w_flag);
+	}
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+#define AHCI_PCI_BAR 5
+#define AHCI_GLOBAL_CTL 0x04
+#define AHCI_ENABLE (1 << 31)
+static int piix_disable_ahci(struct pci_dev *pdev)
+{
+	void *mmio;
+	unsigned long addr;
+	u32 tmp;
+	int rc = 0;
+
+	/* BUG: pci_enable_device has not yet been called.  This
+	 * works because this device is usually set up by BIOS.
+	 */
+
+	addr = pci_resource_start(pdev, AHCI_PCI_BAR);
+	if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR))
+		return 0;
+	
+	mmio = ioremap(addr, 64);
+	if (!mmio)
+		return -ENOMEM;
+	
+	tmp = readl(mmio + AHCI_GLOBAL_CTL);
+	if (tmp & AHCI_ENABLE) {
+		tmp &= ~AHCI_ENABLE;
+		writel(tmp, mmio + AHCI_GLOBAL_CTL);
+
+		tmp = readl(mmio + AHCI_GLOBAL_CTL);
+		if (tmp & AHCI_ENABLE)
+			rc = -EIO;
+	}
+	
+	iounmap(mmio);
+	return rc;
+}
+
+/**
+ *	piix_init_one - Register PIIX ATA PCI device with kernel services
+ *	@pdev: PCI device to register
+ *	@ent: Entry in piix_pci_tbl matching with @pdev
+ *
+ *	Called from kernel PCI layer.  We probe for combined mode (sigh),
+ *	and then hand over control to libata, for it to do the rest.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *	Zero on success, or -ERRNO value.
+ */
+
+static int piix_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_port_info *port_info[2];
+	unsigned int combined = 0, n_ports = 1;
+	unsigned int pata_chan = 0, sata_chan = 0;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/* no hotplugging support (FIXME) */
+	if (!in_module_init)
+		return -ENODEV;
+
+	port_info[0] = &piix_port_info[ent->driver_data];
+	port_info[1] = NULL;
+
+	if (port_info[0]->host_flags & PIIX_FLAG_AHCI) {
+		int rc = piix_disable_ahci(pdev);
+		if (rc)
+			return rc;
+	}
+
+	if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) {
+		u8 tmp;
+		pci_read_config_byte(pdev, ICH5_PMR, &tmp);
+
+		if (tmp & PIIX_COMB) {
+			combined = 1;
+			if (tmp & PIIX_COMB_PATA_P0)
+				sata_chan = 1;
+			else
+				pata_chan = 1;
+		}
+	}
+
+	/* On ICH5, some BIOSen disable the interrupt using the
+	 * PCI_COMMAND_INTX_DISABLE bit added in PCI 2.3.
+	 * On ICH6, this bit has the same effect, but only when
+	 * MSI is disabled (and it is disabled, as we don't use
+	 * message-signalled interrupts currently).
+	 */
+	if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR)
+		pci_enable_intx(pdev);
+
+	if (combined) {
+		port_info[sata_chan] = &piix_port_info[ent->driver_data];
+		port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS;
+		port_info[pata_chan] = &piix_port_info[ich5_pata];
+		n_ports++;
+
+		printk(KERN_WARNING DRV_NAME ": combined mode detected\n");
+	}
+
+	return ata_pci_init_one(pdev, port_info, n_ports);
+}
+
+/**
+ *	piix_init -
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int __init piix_init(void)
+{
+	int rc;
+
+	DPRINTK("pci_module_init\n");
+	rc = pci_module_init(&piix_pci_driver);
+	if (rc)
+		return rc;
+
+	in_module_init = 0;
+
+	DPRINTK("done\n");
+	return 0;
+}
+
+/**
+ *	piix_exit -
+ *
+ *	LOCKING:
+ *
+ */
+
+static void __exit piix_exit(void)
+{
+	pci_unregister_driver(&piix_pci_driver);
+}
+
+module_init(piix_init);
+module_exit(piix_exit);
+
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
new file mode 100644
index 0000000..5d1e78e
--- /dev/null
+++ b/drivers/scsi/atari_NCR5380.c
@@ -0,0 +1,2986 @@
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	architecture.
+ *
+ *	Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing 
+ *	(Unix and Linux consulting and custom programming)
+ * 	drew@colorado.edu
+ *	+1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ *  - Some of the debug statements were incorrect (undefined variables and the
+ *    like). I fixed that.
+ *
+ *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ *    possible DMA transfer size should also happen for REAL_DMA. I added this
+ *    in the #if statement.
+ *
+ *  - When using real DMA, information_transfer() should return in a DATAOUT
+ *    phase after starting the DMA. It has nothing more to do.
+ *
+ *  - The interrupt service routine should run main after end of DMA, too (not
+ *    only after RESELECTION interrupts). Additionally, it should _not_ test
+ *    for more interrupts after running main, since a DMA process may have
+ *    been started and interrupts are turned on now. The new int could happen
+ *    inside the execution of NCR5380_intr(), leading to recursive
+ *    calls.
+ *
+ *  - I've added a function merge_contiguous_buffers() that tries to
+ *    merge scatter-gather buffers that are located at contiguous
+ *    physical addresses and can be processed with the same DMA setup.
+ *    Since most scatter-gather operations work on a page (4K) of
+ *    4 buffers (1K), in more than 90% of all cases three interrupts and
+ *    DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ *    and USLEEP, because these were messing up readability and will never be
+ *    needed for Atari SCSI.
+ * 
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ *   stuff), and 'main' is executed in a bottom half if awoken by an
+ *   interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ *   constructs. In my eyes, this made the source rather unreadable, so I
+ *   finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Test linked command handling code after Eric is ready with 
+ *     the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+    if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
+	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+    if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip.  This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued 
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that 
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what 
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem, 
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system.  So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.  
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the 
+ * NCR5380_print_options command, which should be called from the 
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function.  It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the 
+ * issue queue and calling NCR5380_select() if a nexus 
+ * is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write an architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *	for commands that return with a CHECK CONDITION status. 
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *	that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *	available as NCR5380_i386_dma_write_setup,
+ *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define 
+ *  
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie 
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.  Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define	SETUP_HOSTDATA(in)				\
+    struct NCR5380_hostdata *hostdata =			\
+	(struct NCR5380_hostdata *)(in)->hostdata
+#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))
+#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define	HOSTNO		instance->host_no
+#define	H_NO(cmd)	(cmd)->device->host->host_no
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+typedef struct {
+    DECLARE_BITMAP(allocated, MAX_TAGS);
+    int		nr_allocated;
+    int		queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void __init init_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+    
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    bitmap_zero(ta->allocated, MAX_TAGS);
+	    ta->nr_allocated = 0;
+	    /* At the beginning, assume the maximum queue size we could
+	     * support (MAX_TAGS). This value will be decreased if the target
+	     * returns QUEUE_FULL status.
+	     */
+	    ta->queue_size = MAX_TAGS;
+	}
+    }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */ 
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+	return( 1 );
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
+	return( 0 );
+    if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+	TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
+	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
+	return( 1 );
+    }
+    return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    /* If we or the target don't support tagged queuing, allocate the LUN for
+     * an untagged command.
+     */
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+	cmd->tag = TAG_NONE;
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+		    "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+
+	cmd->tag = find_first_zero_bit( ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, ta->allocated );
+	ta->nr_allocated++;
+	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+		    "(now %d tags in use)\n",
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
+		    ta->nr_allocated );
+    }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    if (cmd->tag == TAG_NONE) {
+	hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
+    }
+    else if (cmd->tag >= MAX_TAGS) {
+	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+		H_NO(cmd), cmd->tag );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+	clear_bit( cmd->tag, ta->allocated );
+	ta->nr_allocated--;
+	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
+    }
+}
+
+
+static void free_all_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    bitmap_zero(ta->allocated, MAX_TAGS);
+	    ta->nr_allocated = 0;
+	}
+    }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ *    transfer. This is possible if the scatter buffers lie on
+ *    physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ *    The command to work on. The first scatter buffer's data are
+ *    assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+    unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+    unsigned long oldlen = cmd->SCp.this_residual;
+    int		  cnt = 1;
+#endif
+
+    for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+	 cmd->SCp.buffers_residual &&
+	 virt_to_phys(page_address(cmd->SCp.buffer[1].page)+
+		      cmd->SCp.buffer[1].offset) == endaddr; ) {
+	MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+		   cmd->SCp.buffer[1].address, endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+	++cnt;
+#endif
+	++cmd->SCp.buffer;
+	--cmd->SCp.buffers_residual;
+	cmd->SCp.this_residual += cmd->SCp.buffer->length;
+	endaddr += cmd->SCp.buffer->length;
+    }
+#if (NDEBUG & NDEBUG_MERGING)
+    if (oldlen != cmd->SCp.this_residual)
+	MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+		   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the 
+ *	start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+    /* 
+     * Initialize the Scsi Pointer field so that all of the commands in the 
+     * various queues are valid.
+     */
+
+    if (cmd->use_sg) {
+	cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	cmd->SCp.ptr = (char *)page_address(cmd->SCp.buffer->page)+
+		       cmd->SCp.buffer->offset;
+	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	/* ++roman: Try to merge some scatter-buffers if they are at
+	 * contiguous physical addresses.
+	 */
+	merge_contiguous_buffers( cmd );
+    } else {
+	cmd->SCp.buffer = NULL;
+	cmd->SCp.buffers_residual = 0;
+	cmd->SCp.ptr = (char *) cmd->request_buffer;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+    }
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if NDEBUG
+static struct {
+    unsigned char mask;
+    const char * name;} 
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
+    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
+    { SR_SEL, "SEL" }, {0, NULL}}, 
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
+    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+    {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
+    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
+    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
+    {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+    unsigned char status, data, basr, mr, icr, i;
+    unsigned long flags;
+
+    local_irq_save(flags);
+    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+    status = NCR5380_read(STATUS_REG);
+    mr = NCR5380_read(MODE_REG);
+    icr = NCR5380_read(INITIATOR_COMMAND_REG);
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    local_irq_restore(flags);
+    printk("STATUS_REG: %02x ", status);
+    for (i = 0; signals[i].mask ; ++i) 
+	if (status & signals[i].mask)
+	    printk(",%s", signals[i].name);
+    printk("\nBASR: %02x ", basr);
+    for (i = 0; basrs[i].mask ; ++i) 
+	if (basr & basrs[i].mask)
+	    printk(",%s", basrs[i].name);
+    printk("\nICR: %02x ", icr);
+    for (i = 0; icrs[i].mask; ++i) 
+	if (icr & icrs[i].mask)
+	    printk(",%s", icrs[i].name);
+    printk("\nMODE: %02x ", mr);
+    for (i = 0; mrs[i].mask; ++i) 
+	if (mr & mrs[i].mask)
+	    printk(",%s", mrs[i].name);
+    printk("\n");
+}
+
+static struct {
+    unsigned char value;
+    const char *name;
+} phases[] = {
+    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+    {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/* 
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+    unsigned char status;
+    int i;
+
+    status = NCR5380_read(STATUS_REG);
+    if (!(status & SR_REQ)) 
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+    else {
+	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
+	    (phases[i].value != (status & PHASE_MASK)); ++i); 
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+    }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ * 
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+
+static __inline__ void queue_main(void)
+{
+    if (!main_running) {
+	/* If in interrupt and NCR5380_main() not already running,
+	   queue it on the 'immediate' task queue, to be processed
+	   immediately after the current interrupt processing has
+	   finished. */
+	schedule_work(&NCR5380_tqueue);
+    }
+    /* else: nothing to do: the running NCR5380_main() will pick up
+       any newly queued command. */
+}
+
+
+static inline void NCR5380_all_init (void)
+{
+    static int done = 0;
+    if (!done) {
+	INI_PRINTK("scsi : NCR5380_all_init()\n");
+	done = 1;
+    }
+}
+
+ 
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ *	     options that were selected.
+ *
+ * Inputs : instance, pointer to this instance.  Unused.
+ */
+
+static void __init NCR5380_print_options (struct Scsi_Host *instance)
+{
+    printk(" generic options"
+#ifdef AUTOSENSE 
+    " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+    " REAL DMA"
+#endif
+#ifdef PARITY
+    " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+    " SCSI-2 TAGGED QUEUING"
+#endif
+    );
+    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ *	NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.  
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+    char *pr_bfr;
+    char *start;
+    int len;
+
+    NCR_PRINT(NDEBUG_ANY);
+    NCR_PRINT_PHASE(NDEBUG_ANY);
+
+    pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+    if (!pr_bfr) {
+	printk("NCR5380_print_status: no memory for print buffer\n");
+	return;
+    }
+    len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0);
+    pr_bfr[len] = 0;
+    printk("\n%s\n", pr_bfr);
+    free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+  do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+	 pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+static
+int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset,
+		       int length, int inout)
+{
+    char *pos = buffer;
+    struct NCR5380_hostdata *hostdata;
+    Scsi_Cmnd *ptr;
+    unsigned long flags;
+    off_t begin = 0;
+#define check_offset()				\
+    do {					\
+	if (pos - buffer < offset - begin) {	\
+	    begin += pos - buffer;		\
+	    pos = buffer;			\
+	}					\
+    } while (0)
+
+    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+    if (inout) { /* Has data been written to the file ? */
+	return(-ENOSYS);  /* Currently this is a no-op */
+    }
+    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+    check_offset();
+    local_irq_save(flags);
+    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+    check_offset();
+    if (!hostdata->connected)
+	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+    else
+	pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+				pos, buffer, length);
+    SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	 ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    local_irq_restore(flags);
+    *start = buffer + (offset - begin);
+    if (pos - buffer < offset - begin)
+	return 0;
+    else if (pos - buffer - (offset - begin) < length)
+	return pos - buffer - (offset - begin);
+    return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+    int i, s;
+    unsigned char *command;
+    SPRINTF("scsi%d: destination target %d, lun %d\n",
+	    H_NO(cmd), cmd->device->id, cmd->device->lun);
+    SPRINTF("        command = ");
+    command = cmd->cmnd;
+    SPRINTF("%2d (0x%02x)", command[0], command[0]);
+    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+	SPRINTF(" %02x", command[i]);
+    SPRINTF("\n");
+    return pos;
+}
+
+
+/* 
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.  
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * 	set correctly.  I don't care about the irq and other fields. 
+ * 
+ */
+
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+    int i;
+    SETUP_HOSTDATA(instance);
+
+    NCR5380_all_init();
+
+    hostdata->aborted = 0;
+    hostdata->id_mask = 1 << instance->this_id;
+    hostdata->id_higher_mask = 0;
+    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+	if (i > hostdata->id_mask)
+	    hostdata->id_higher_mask |= i;
+    for (i = 0; i < 8; ++i)
+	hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+    init_tags();
+#endif
+#if defined (REAL_DMA)
+    hostdata->dma_len = 0;
+#endif
+    hostdata->targets_present = 0;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+    if (!the_template) {
+	the_template = instance->hostt;
+	first_instance = instance;
+    }
+	
+
+#ifndef AUTOSENSE
+    if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
+	        "        be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+ *	void (*done)(Scsi_Cmnd *)) 
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	a pointer to the command descriptor.
+ * 
+ * Returns : 0
+ *
+ * Side effects : 
+ *      cmd is added to the per instance issue_queue, with minor 
+ *	twiddling done to the host specific fields of cmd.  If the 
+ *	main coroutine is not running, it is restarted.
+ *
+ */
+
+static
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+    SETUP_HOSTDATA(cmd->device->host);
+    Scsi_Cmnd *tmp;
+    int oldto;
+    unsigned long flags;
+    extern int update_timeout(Scsi_Cmnd * SCset, int timeout);
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+    switch (cmd->cmnd[0]) {
+    case WRITE_6:
+    case WRITE_10:
+	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	       H_NO(cmd));
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	return 0;
+    }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+    if (!hostdata->connected && !hostdata->issue_queue &&
+	!hostdata->disconnected_queue) {
+	hostdata->timebase = jiffies;
+    }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+		hostdata->pendingw++;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+		hostdata->pendingr++;
+		break;
+	}
+#endif
+
+    /* 
+     * We use the host_scribble field as a pointer to the next command  
+     * in a queue 
+     */
+
+    NEXT(cmd) = NULL;
+    cmd->scsi_done = done;
+
+    cmd->result = 0;
+
+
+    /* 
+     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+     * commands are added to the head of the queue since any command will
+     * clear the contingent allegiance condition that exists and the 
+     * sense data is only guaranteed to be valid while the condition exists.
+     */
+
+    local_irq_save(flags);
+    /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+     * Otherwise a running NCR5380_main may steal the lock.
+     * Lock before actually inserting due to fairness reasons explained in
+     * atari_scsi.c. If we insert first, then it's impossible for this driver
+     * to release the lock.
+     * Stop timer for this command while waiting for the lock, or timeouts
+     * may happen (and they really do), and it's no good if the command doesn't
+     * appear in any of the queues.
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which would
+     * alter queues and touch the lock.
+     */
+    if (!IS_A_TT()) {
+	oldto = update_timeout(cmd, 0);
+	falcon_get_lock();
+	update_timeout(cmd, oldto);
+    }
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	LIST(cmd, hostdata->issue_queue);
+	NEXT(cmd) = hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+	     NEXT(tmp); tmp = NEXT(tmp))
+	    ;
+	LIST(cmd, tmp);
+	NEXT(tmp) = cmd;
+    }
+    local_irq_restore(flags);
+
+    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+    /* If queue_command() is called from an interrupt (real one or bottom
+     * half), we let queue_main() do the job of taking care about main. If it
+     * is already running, this is a no-op, else main will be queued.
+     *
+     * If we're not in an interrupt, we can call NCR5380_main()
+     * unconditionally, because it cannot be already running.
+     */
+    if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+	queue_main();
+    else
+	NCR5380_main(NULL);
+    return 0;
+}
+
+/*
+ * Function : NCR5380_main (void) 
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	be done on the NCR5380 host adapters in a system.  Both 
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *	in case it is not running.
+ * 
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ */ 	
+    
+static void NCR5380_main (void *bl)
+{
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *instance = first_instance;
+    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+    int done;
+    unsigned long flags;
+    
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set main_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     * this should prevent any race conditions.
+     * 
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which can
+     * alter queues and touch the Falcon lock.
+     */
+
+    /* Tell int handlers main() is now already executing.  Note that
+       no races are possible here. If an int comes in before
+       'main_running' is set here, and queues/executes main via the
+       task queue, it doesn't do any harm, just this instance of main
+       won't find any work left to do. */
+    if (main_running)
+    	return;
+    main_running = 1;
+
+    local_save_flags(flags);
+    do {
+	local_irq_disable(); /* Freeze request queues */
+	done = 1;
+	
+	if (!hostdata->connected) {
+	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+	    /*
+	     * Search through the issue_queue for a command destined
+	     * for a target that's not busy.
+	     */
+#if (NDEBUG & NDEBUG_LISTS)
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+		;
+		/*printk("%p  ", tmp);*/
+	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+		if (prev != tmp)
+		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+			   tmp, tmp->device->id, hostdata->busy[tmp->device->id],
+			   tmp->device->lun);
+#endif
+		/*  When we find one, remove it from the issue queue. */
+		/* ++guenther: possible race with Falcon locking */
+		if (
+#ifdef SUPPORT_TAGS
+		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+		    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+#endif
+		    ) {
+		    /* ++guenther: just to be sure, this must be atomic */
+		    local_irq_disable();
+		    if (prev) {
+		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+			NEXT(prev) = NEXT(tmp);
+		    } else {
+		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+			hostdata->issue_queue = NEXT(tmp);
+		    }
+		    NEXT(tmp) = NULL;
+		    falcon_dont_release++;
+		    
+		    /* reenable interrupts after finding one */
+		    local_irq_restore(flags);
+		    
+		    /* 
+		     * Attempt to establish an I_T_L nexus here. 
+		     * On success, instance->hostdata->connected is set.
+		     * On failure, we must add the command back to the
+		     *   issue queue so we can keep trying.	
+		     */
+		    MAIN_PRINTK("scsi%d: main(): command for target %d "
+				"lun %d removed from issue_queue\n",
+				HOSTNO, tmp->device->id, tmp->device->lun);
+		    /* 
+		     * REQUEST SENSE commands are issued without tagged
+		     * queueing, even on SCSI-II devices because the 
+		     * contingent allegiance condition exists for the 
+		     * entire unit.
+		     */
+		    /* ++roman: ...and the standard also requires that
+		     * REQUEST SENSE command are untagged.
+		     */
+		    
+#ifdef SUPPORT_TAGS
+		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+		    if (!NCR5380_select(instance, tmp, 
+			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
+			    TAG_NEXT)) {
+			falcon_dont_release--;
+			/* release if target did not response! */
+			falcon_release_lock_if_possible( hostdata );
+			break;
+		    } else {
+			local_irq_disable();
+			LIST(tmp, hostdata->issue_queue);
+			NEXT(tmp) = hostdata->issue_queue;
+			hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+			cmd_free_tag( tmp );
+#endif
+			falcon_dont_release--;
+			local_irq_restore(flags);
+			MAIN_PRINTK("scsi%d: main(): select() failed, "
+				    "returned to issue_queue\n", HOSTNO);
+			if (hostdata->connected)
+			    break;
+		    }
+		} /* if target/lun/target queue is not busy */
+	    } /* for issue_queue */
+	} /* if (!hostdata->connected) */
+		
+	if (hostdata->connected 
+#ifdef REAL_DMA
+	    && !hostdata->dma_len
+#endif
+	    ) {
+	    local_irq_restore(flags);
+	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+			HOSTNO);
+	    NCR5380_information_transfer(instance);
+	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+	    done = 0;
+	}
+    } while (!done);
+
+    /* Better allow ints _after_ 'main_running' has been cleared, else
+       an interrupt could believe we'll pick up the work it left for
+       us, but we won't see it anymore here... */
+    main_running = 0;
+    local_irq_restore(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ *	mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+    SETUP_HOSTDATA(instance);
+    int           transfered, saved_data = 0, overrun = 0, cnt, toPIO;
+    unsigned char **data, p;
+    volatile int  *count;
+
+    if (!hostdata->connected) {
+	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+	       "no connected cmd\n", HOSTNO);
+	return;
+    }
+    
+    if (atari_read_overruns) {
+	p = hostdata->connected->SCp.phase;
+	if (p & SR_IO) {
+	    udelay(10);
+	    if ((((NCR5380_read(BUS_AND_STATUS_REG)) &
+		  (BASR_PHASE_MATCH|BASR_ACK)) ==
+		 (BASR_PHASE_MATCH|BASR_ACK))) {
+		saved_data = NCR5380_read(INPUT_DATA_REG);
+		overrun = 1;
+		DMA_PRINTK("scsi%d: read overrun handled\n", HOSTNO);
+	    }
+	}
+    }
+
+    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	       NCR5380_read(STATUS_REG));
+
+    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+    hostdata->dma_len = 0;
+
+    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+    count = &(hostdata->connected->SCp.this_residual);
+    *data += transfered;
+    *count -= transfered;
+
+    if (atari_read_overruns) {
+	if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
+	    cnt = toPIO = atari_read_overruns;
+	    if (overrun) {
+		DMA_PRINTK("Got an input overrun, using saved byte\n");
+		*(*data)++ = saved_data;
+		(*count)--;
+		cnt--;
+		toPIO--;
+	    }
+	    DMA_PRINTK("Doing %d-byte PIO to 0x%08lx\n", cnt, (long)*data);
+	    NCR5380_transfer_pio(instance, &p, &cnt, data);
+	    *count -= toPIO - cnt;
+	}
+    }
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ * 
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *	from the disconnected queue, and restarting NCR5380_main() 
+ *	as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct Scsi_Host *instance = first_instance;
+    int done = 1, handled = 0;
+    unsigned char basr;
+
+    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+    /* Look for pending interrupts */
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+    /* dispatch to appropriate routine if found and done=0 */
+    if (basr & BASR_IRQ) {
+	NCR_PRINT(NDEBUG_INTR);
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+	    done = 0;
+	    ENABLE_IRQ();
+	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+	    NCR5380_reselect(instance);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if (basr & BASR_PARITY_ERROR) {
+	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else {
+	    /*  
+	     * The rest of the interrupt conditions can occur only during a
+	     * DMA transfer
+	     */
+
+#if defined(REAL_DMA)
+	    /*
+	     * We should only get PHASE MISMATCH and EOP interrupts if we have
+	     * DMA enabled, so do a sanity check based on the current setting
+	     * of the MODE register.
+	     */
+
+	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+		((basr & BASR_END_DMA_TRANSFER) || 
+		 !(basr & BASR_PHASE_MATCH))) {
+		    
+		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+		NCR5380_dma_complete( instance );
+		done = 0;
+		ENABLE_IRQ();
+	    } else
+#endif /* REAL_DMA */
+	    {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+		if (basr & BASR_PHASE_MATCH)
+		    printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+			   HOSTNO, basr, NCR5380_read(MODE_REG),
+			   NCR5380_read(STATUS_REG));
+		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    }
+	} /* if !(SELECTION || PARITY) */
+	handled = 1;
+    } /* BASR & IRQ */
+    else {
+	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    }
+    
+    if (!done) {
+	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+	/* Put a call to NCR5380_main() on the queue... */
+	queue_main();
+    }
+    return IRQ_RETVAL(handled);
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+		hostdata->pendingw--;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+		hostdata->pendingr--;
+		break;
+	}
+}
+#endif
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *	int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *	including ARBITRATION, SELECTION, and initial message out for 
+ *	IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *	the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *	0 if selection succeeded or failed because the target 
+ * 	did not respond.
+ *
+ * Side effects : 
+ * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *		with registers as they should have been on entry - ie
+ *		SELECT_ENABLE will be set appropriately, the NCR5380
+ *		will cease to drive any SCSI bus signals.
+ *
+ *	If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *		instance->connected will be set to cmd.  
+ * 		SELECT interrupt will be disabled.
+ *
+ *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *		cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char tmp[3], phase;
+    unsigned char *data;
+    int len;
+    unsigned long timeout;
+    unsigned long flags;
+
+    hostdata->restart_select = 0;
+    NCR_PRINT(NDEBUG_ARBITRATION);
+    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	       instance->this_id);
+
+    /* 
+     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+     * data bus during SELECTION.
+     */
+
+    local_irq_save(flags);
+    if (hostdata->connected) {
+	local_irq_restore(flags);
+	return -1;
+    }
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+    /* 
+     * Start arbitration.
+     */
+    
+    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+    NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+    local_irq_restore(flags);
+
+    /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+    {
+      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	   && time_before(jiffies, timeout) && !hostdata->connected)
+	;
+      if (time_after_eq(jiffies, timeout))
+      {
+	printk("scsi : arbitration timeout at %d\n", __LINE__);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return -1;
+      }
+    }
+#else /* NCR_TIMEOUT */
+    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	 && !hostdata->connected);
+#endif
+
+    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	return -1;
+    }
+    /* 
+     * The arbitration delay is 2.2us, but this is a minimum and there is 
+     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+     * the integral nature of udelay().
+     *
+     */
+
+    udelay(3);
+
+    /* Check for lost arbitration */
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+		   HOSTNO);
+	return -1;
+    }
+
+     /* after/during arbitration, BSY should be asserted.
+	IBM DPES-31080 Version S31Q works now */
+     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+					 ICR_ASSERT_BSY ) ;
+    
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+		   HOSTNO);
+	return -1;
+    }
+
+    /* 
+     * Again, bus clear + bus settle time is 1.2us, however, this is 
+     * a minimum so we'll udelay ceil(1.2)
+     */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+    /* 
+     * Now that we have won arbitration, start Selection process, asserting 
+     * the host and target ID's on the SCSI bus.
+     */
+
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+    /* 
+     * Raise ATN while SEL is true before BSY goes false from arbitration,
+     * since this is the only way to guarantee that we'll get a MESSAGE OUT
+     * phase immediately after selection.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
+	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+    NCR5380_write(MODE_REG, MR_BASE);
+
+    /* 
+     * Reselect interrupts must be turned off prior to the dropping of BSY,
+     * otherwise we will trigger an interrupt.
+     */
+
+    if (hostdata->connected) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    /*
+     * The initiator shall then wait at least two deskew delays and release 
+     * the BSY signal.
+     */
+    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+    /* Reset BSY */
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
+	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+    /* 
+     * Something weird happens when we cease to drive BSY - looks
+     * like the board/chip is letting us do another read before the 
+     * appropriate propagation delay has expired, and we're confusing
+     * a BSY signal from ourselves as the target's response to SELECTION.
+     *
+     * A small delay (the 'C++' frontend breaks the pipeline with an
+     * unnecessary jump, making it work on my 386-33/Trantor T128, the
+     * tighter 'C' code breaks and requires this) solves the problem - 
+     * the 1 us delay is arbitrary, and only used because this delay will 
+     * be the same on other platforms and since it works here, it should 
+     * work there.
+     *
+     * wingel suggests that this could be due to failing to wait
+     * one deskew delay.
+     */
+
+    udelay(1);
+
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+
+    /* 
+     * The SCSI specification calls for a 250 ms timeout for the actual 
+     * selection.
+     */
+
+    timeout = jiffies + 25; 
+
+    /* 
+     * XXX very interesting - we're seeing a bounce where the BSY we 
+     * asserted is being reflected / still asserted (propagation delay?)
+     * and it's detecting as true.  Sigh.
+     */
+
+#if 0
+    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+     * IO while SEL is true. But again, there are some disks out the in the
+     * world that do that nevertheless. (Somebody claimed that this announces
+     * reselection capability of the target.) So we better skip that test and
+     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+     */
+
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & 
+	(SR_BSY | SR_IO)));
+
+    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
+	    (SR_SEL | SR_IO)) {
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	    NCR5380_reselect(instance);
+	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		    HOSTNO);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+    }
+#else
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+    /* 
+     * No less than two deskew delays after the initiator detects the 
+     * BSY signal is true, it shall release the SEL signal and may 
+     * change the DATA BUS.                                     -wingel
+     */
+
+    udelay(1);
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	if (hostdata->targets_present & (1 << cmd->device->id)) {
+	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+	    if (hostdata->restart_select)
+		printk(KERN_NOTICE "\trestart select\n");
+	    NCR_PRINT(NDEBUG_ANY);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+	}
+	cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+	collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#endif
+	cmd->scsi_done(cmd);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return 0;
+    } 
+
+    hostdata->targets_present |= (1 << cmd->device->id);
+
+    /*
+     * Since we followed the SCSI spec, and raised ATN while SEL 
+     * was true but before BSY was false during selection, the information
+     * transfer phase should be a MESSAGE OUT phase so that we can send the
+     * IDENTIFY message.
+     * 
+     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+     * message (2 bytes) with a tag ID that we increment with every command
+     * until it wraps back to 0.
+     *
+     * XXX - it turns out that there are some broken SCSI-II devices,
+     *	     which claim to support tagged queuing but fail when more than
+     *	     some number of commands are issued at once.
+     */
+
+    /* Wait for start of REQ/ACK handshake */
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	       HOSTNO, cmd->device->id);
+    tmp[0] = IDENTIFY(1, cmd->device->lun);
+
+#ifdef SUPPORT_TAGS
+    if (cmd->tag != TAG_NONE) {
+	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+	tmp[2] = cmd->tag;
+	len = 3;
+    } else 
+	len = 1;
+#else
+    len = 1;
+    cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+    /* Send message(s) */
+    data = tmp;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+    /* XXX need to handle errors here */
+    hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+    hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+#endif    
+
+    initialize_SCp(cmd);
+
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes are transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    register unsigned char p = *phase, tmp;
+    register int c = *count;
+    register unsigned char *d = *data;
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+    do {
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR_PRINT_PHASE(NDEBUG_PIO);
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to / from memory */
+	if (!(p & SR_IO)) 
+	    NCR5380_write(OUTPUT_DATA_REG, *d);
+	else 
+	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	++d;
+
+	/* 
+	 * The SCSI standard suggests that in MSGOUT phase, the initiator
+	 * should drop ATN on the last byte of the message phase
+	 * after REQ has been asserted for the handshake but before
+	 * the initiator raises ACK.
+	 */
+
+	if (!(p & SR_IO)) {
+	    if (!((p & SR_MSG) && c > 1)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+	    } else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+	    }
+	} else {
+	    NCR_PRINT(NDEBUG_PIO);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	}
+
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *	message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *	message.  We must exit with ACK asserted, so that the calling
+ *	code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+	if (!(p == PHASE_MSGIN && c == 1)) {  
+	    if (p == PHASE_MSGOUT && c > 1)
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	    else
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	} 
+    } while (--c);
+
+    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+    *count = c;
+    *data = d;
+    tmp = NCR5380_read(STATUS_REG);
+    /* The phase read from the bus is valid if either REQ is (already)
+     * asserted or if ACK hasn't been released yet. The latter is the case if
+     * we're in MSGIN and all wanted bytes have been received. */
+    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+	*phase = tmp & PHASE_MASK;
+    else 
+	*phase = PHASE_UNKNOWN;
+
+    if (!c || (*phase == p))
+	return 0;
+    else 
+	return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ * 	called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host) 
+{
+    unsigned char tmp, *msgptr, phase;
+    int len;
+
+    /* Request message out phase */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    /* 
+     * Wait for the target to indicate a valid phase by asserting 
+     * REQ.  Once this happens, we'll have either a MSGOUT phase 
+     * and can immediately send the ABORT message, or we'll have some 
+     * other phase and will have to source/sink data.
+     * 
+     * We really don't care what value was on the bus or what value
+     * the target sees, so we just handshake.
+     */
+    
+    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		      ICR_ASSERT_ACK);
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+    }
+   
+    tmp = ABORT;
+    msgptr = &tmp;
+    len = 1;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+    /*
+     * If we got here, and the command completed successfully,
+     * we're about to go into bus free state.
+     */
+
+    return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *	or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes or transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    SETUP_HOSTDATA(instance);
+    register int c = *count;
+    register unsigned char p = *phase;
+    register unsigned char *d = *data;
+    unsigned char tmp;
+    unsigned long flags;
+
+    if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+        *phase = tmp;
+        return -1;
+    }
+
+    if (atari_read_overruns && (p & SR_IO)) {
+	c -= atari_read_overruns;
+    }
+
+    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
+	       c, (p & SR_IO) ? "to" : "from", d);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+#ifdef REAL_DMA
+    NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#endif /* def REAL_DMA  */
+
+    if (IS_A_TT()) {
+	/* On the Medusa, it is a must to initialize the DMA before
+	 * starting the NCR. This is also the cleaner way for the TT.
+	 */
+	local_irq_save(flags);
+	hostdata->dma_len = (p & SR_IO) ?
+	    NCR5380_dma_read_setup(instance, d, c) : 
+	    NCR5380_dma_write_setup(instance, d, c);
+	local_irq_restore(flags);
+    }
+    
+    if (p & SR_IO)
+	NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+    else {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+	NCR5380_write(START_DMA_SEND_REG, 0);
+    }
+
+    if (!IS_A_TT()) {
+	/* On the Falcon, the DMA setup must be done after the last */
+	/* NCR access, else the DMA setup gets trashed!
+	 */
+	local_irq_save(flags);
+	hostdata->dma_len = (p & SR_IO) ?
+	    NCR5380_dma_read_setup(instance, d, c) : 
+	    NCR5380_dma_write_setup(instance, d, c);
+	local_irq_restore(flags);
+    }
+    return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ * 	directs us to.  Operates on the currently connected command, 
+ *	instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *	modified if a command disconnects, *instance->connected will
+ *	change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ * 	to recover from an unexpected bus free condition.
+ */
+ 
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned long flags;
+    unsigned char msgout = NOP;
+    int sink = 0;
+    int len;
+#if defined(REAL_DMA)
+    int transfersize;
+#endif
+    unsigned char *data;
+    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+    while (1) {
+	tmp = NCR5380_read(STATUS_REG);
+	/* We only have a valid SCSI phase when REQ is asserted */
+	if (tmp & SR_REQ) {
+	    phase = (tmp & PHASE_MASK); 
+	    if (phase != old_phase) {
+		old_phase = phase;
+		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+	    }
+	    
+	    if (sink && (phase != PHASE_MSGOUT)) {
+		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		    ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_ATN);
+		sink = 0;
+		continue;
+	    }
+
+	    switch (phase) {
+	    case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+		       "aborted\n", HOSTNO);
+		sink = 1;
+		do_abort(instance);
+		cmd->result = DID_ERROR  << 16;
+		cmd->done(cmd);
+		return;
+#endif
+	    case PHASE_DATAIN:
+		/* 
+		 * If there is no room left in the current buffer in the
+		 * scatter-gather list, move onto the next one.
+		 */
+
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		    ++cmd->SCp.buffer;
+		    --cmd->SCp.buffers_residual;
+		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		    cmd->SCp.ptr = page_address(cmd->SCp.buffer->page)+
+				   cmd->SCp.buffer->offset;
+		    /* ++roman: Try to merge some scatter-buffers if
+		     * they are at contiguous physical addresses.
+		     */
+		    merge_contiguous_buffers( cmd );
+		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+			       HOSTNO, cmd->SCp.this_residual,
+			       cmd->SCp.buffers_residual);
+		}
+
+		/*
+		 * The preferred transfer method is going to be 
+		 * PSEUDO-DMA for systems that are strictly PIO,
+		 * since we can let the hardware do the handshaking.
+		 *
+		 * For this to work, we need to know the transfersize
+		 * ahead of time, since the pseudo-DMA code will sit
+		 * in an unconditional loop.
+		 */
+
+/* ++roman: I suggest, this should be
+ *   #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+		if (!cmd->device->borken &&
+		    (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+		    len = transfersize;
+		    cmd->SCp.phase = phase;
+		    if (NCR5380_transfer_dma(instance, &phase,
+			&len, (unsigned char **) &cmd->SCp.ptr)) {
+			/*
+			 * If the watchdog timer fires, all future
+			 * accesses to this device will use the
+			 * polled-IO. */ 
+			printk(KERN_NOTICE "scsi%d: switching target %d "
+			       "lun %d to slow handshake\n", HOSTNO,
+			       cmd->device->id, cmd->device->lun);
+			cmd->device->borken = 1;
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			    ICR_ASSERT_ATN);
+			sink = 1;
+			do_abort(instance);
+			cmd->result = DID_ERROR  << 16;
+			cmd->done(cmd);
+			/* XXX - need to source or sink data here, as appropriate */
+		    } else {
+#ifdef REAL_DMA
+			/* ++roman: When using real DMA,
+			 * information_transfer() should return after
+			 * starting DMA since it has nothing more to
+			 * do.
+			 */
+			return;
+#else			
+			cmd->SCp.this_residual -= transfersize - len;
+#endif
+		    }
+		} else
+#endif /* defined(REAL_DMA) */
+		  NCR5380_transfer_pio(instance, &phase, 
+		    (int *) &cmd->SCp.this_residual, (unsigned char **)
+		    &cmd->SCp.ptr);
+		break;
+	    case PHASE_MSGIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Message = tmp;
+
+		switch (tmp) {
+		/*
+		 * Linking lets us reduce the time required to get the 
+		 * next command out to the device, hopefully this will
+		 * mean we don't waste another revolution due to the delays
+		 * required by ARBITRATION and another SELECTION.
+		 *
+		 * In the current implementation proposal, low level drivers
+		 * merely have to start the next command, pointed to by 
+		 * next_link, done() is called as with unlinked commands.
+		 */
+#ifdef LINKED
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    
+		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
+			       "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /*
+		     * Sanity check : A linked command should only terminate
+		     * with one of these messages if there are more linked
+		     * commands available.
+		     */
+
+		    if (!cmd->next_link) {
+			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+				"linked command complete, no next_link\n",
+				HOSTNO, cmd->device->id, cmd->device->lun);
+			    sink = 1;
+			    do_abort (instance);
+			    return;
+		    }
+
+		    initialize_SCp(cmd->next_link);
+		    /* The next command is still part of this process; copy it
+		     * and don't free it! */
+		    cmd->next_link->tag = cmd->tag;
+		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
+			       "done, calling scsi_done().\n",
+			       HOSTNO, cmd->device->id, cmd->device->lun);
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    cmd = hostdata->connected;
+		    break;
+#endif /* def LINKED */
+		case ABORT:
+		case COMMAND_COMPLETE: 
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* ++guenther: possible race with Falcon locking */
+		    falcon_dont_release++;
+		    hostdata->connected = NULL;
+		    QU_PRINTK("scsi%d: command for target %d, lun %d "
+			      "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+			/* Turn a QUEUE FULL status into BUSY, I think the
+			 * mid level cannot handle QUEUE FULL :-( (The
+			 * command is retried after BUSY). Also update our
+			 * queue size to the number of currently issued
+			 * commands now.
+			 */
+			/* ++Andreas: the mid level code knows about
+			   QUEUE_FULL now. */
+			TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+			TAG_PRINTK("scsi%d: target %d lun %d returned "
+				   "QUEUE_FULL after %d commands\n",
+				   HOSTNO, cmd->device->id, cmd->device->lun,
+				   ta->nr_allocated);
+			if (ta->queue_size > ta->nr_allocated)
+			    ta->nr_allocated = ta->queue_size;
+		    }
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+		    /* 
+		     * I'm not sure what the correct thing to do here is : 
+		     * 
+		     * If the command that just executed is NOT a request 
+		     * sense, the obvious thing to do is to set the result
+		     * code to the values of the stored parameters.
+		     * 
+		     * If it was a REQUEST SENSE command, we need some way to
+		     * differentiate between the failure code of the original
+		     * and the failure code of the REQUEST sense - the obvious
+		     * case is success, where we fall through and leave the
+		     * result code unchanged.
+		     * 
+		     * The non-obvious place is where the REQUEST SENSE failed
+		     */
+
+		    if (cmd->cmnd[0] != REQUEST_SENSE) 
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    else if (status_byte(cmd->SCp.Status) != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		    
+#ifdef AUTOSENSE
+		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
+			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+			ASEN_PRINTK("scsi%d: performing request sense\n",
+				    HOSTNO);
+			cmd->cmnd[0] = REQUEST_SENSE;
+			cmd->cmnd[1] &= 0xe0;
+			cmd->cmnd[2] = 0;
+			cmd->cmnd[3] = 0;
+			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+			cmd->cmnd[5] = 0;
+			cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+			cmd->use_sg = 0;
+			/* this is initialized from initialize_SCp 
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.buffers_residual = 0;
+			*/
+			cmd->request_buffer = (char *) cmd->sense_buffer;
+			cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+			local_irq_save(flags);
+			LIST(cmd,hostdata->issue_queue);
+			NEXT(cmd) = hostdata->issue_queue;
+		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+		        local_irq_restore(flags);
+			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+				  "issue queue\n", H_NO(cmd));
+		   } else
+#endif /* def AUTOSENSE */
+		   {
+#ifdef NCR5380_STATS
+		       collect_stats(hostdata, cmd);
+#endif
+		       cmd->scsi_done(cmd);
+		    }
+
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+		    
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
+
+		    falcon_dont_release--;
+		    /* ++roman: For Falcon SCSI, release the lock on the
+		     * ST-DMA here if no other commands are waiting on the
+		     * disconnected queue.
+		     */
+		    falcon_release_lock_if_possible( hostdata );
+		    return;
+		case MESSAGE_REJECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    switch (hostdata->last_message) {
+		    case HEAD_OF_QUEUE_TAG:
+		    case ORDERED_QUEUE_TAG:
+		    case SIMPLE_QUEUE_TAG:
+			/* The target obviously doesn't support tagged
+			 * queuing, even though it announced this ability in
+			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+			 * clear 'tagged_supported' and lock the LUN, since
+			 * the command is treated as untagged further on.
+			 */
+			cmd->device->tagged_supported = 0;
+			hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+			cmd->tag = TAG_NONE;
+			TAG_PRINTK("scsi%d: target %d lun %d rejected "
+				   "QUEUE_TAG message; tagged queuing "
+				   "disabled\n",
+				   HOSTNO, cmd->device->id, cmd->device->lun);
+			break;
+		    }
+		    break;
+		case DISCONNECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    local_irq_save(flags);
+		    cmd->device->disconnect = 1;
+		    LIST(cmd,hostdata->disconnected_queue);
+		    NEXT(cmd) = hostdata->disconnected_queue;
+		    hostdata->connected = NULL;
+		    hostdata->disconnected_queue = cmd;
+		    local_irq_restore(flags);
+		    QU_PRINTK("scsi%d: command for target %d lun %d was "
+			      "moved from connected to the "
+			      "disconnected_queue\n", HOSTNO, 
+			      cmd->device->id, cmd->device->lun);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* Wait for bus free to avoid nasty timeouts */
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
+		    return;
+		/* 
+		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+		 * operation, in violation of the SCSI spec so we can safely 
+		 * ignore SAVE/RESTORE pointers calls.
+		 *
+		 * Unfortunately, some disks violate the SCSI spec and 
+		 * don't issue the required SAVE_POINTERS message before
+		 * disconnecting, and we have to break spec to remain 
+		 * compatible.
+		 */
+		case SAVE_POINTERS:
+		case RESTORE_POINTERS:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    break;
+		case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte 	
+ * 0		EXTENDED_MESSAGE == 1
+ * 1		length (includes one byte for code, doesn't 
+ *		include first two bytes)
+ * 2 		code
+ * 3..length+1	arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+		    extended_msg[0] = EXTENDED_MESSAGE;
+		    /* Accept first byte by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+		    len = 2;
+		    data = extended_msg + 1;
+		    phase = PHASE_MSGIN;
+		    NCR5380_transfer_pio(instance, &phase, &len, &data);
+		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			       (int)extended_msg[1], (int)extended_msg[2]);
+
+		    if (!len && extended_msg[1] <= 
+			(sizeof (extended_msg) - 1)) {
+			/* Accept third byte by clearing ACK */
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			len = extended_msg[1] - 1;
+			data = extended_msg + 3;
+			phase = PHASE_MSGIN;
+
+			NCR5380_transfer_pio(instance, &phase, &len, &data);
+			EXT_PRINTK("scsi%d: message received, residual %d\n",
+				   HOSTNO, len);
+
+			switch (extended_msg[2]) {
+			case EXTENDED_SDTR:
+			case EXTENDED_WDTR:
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			    tmp = 0;
+			}
+		    } else if (len) {
+			printk(KERN_NOTICE "scsi%d: error receiving "
+			       "extended message\n", HOSTNO);
+			tmp = 0;
+		    } else {
+			printk(KERN_NOTICE "scsi%d: extended message "
+			       "code %02x length %d is too long\n",
+			       HOSTNO, extended_msg[2], extended_msg[1]);
+			tmp = 0;
+		    }
+		/* Fall through to reject message */
+
+		/* 
+  		 * If we get something weird that we aren't expecting, 
+ 		 * reject it.
+		 */
+		default:
+		    if (!tmp) {
+			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+			print_msg (extended_msg);
+			printk("\n");
+		    } else if (tmp != EXTENDED_MESSAGE)
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "message %02x from target %d, lun %d\n",
+			       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+		    else
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "extended message "
+			       "code %02x, length %d from target %d, lun %d\n",
+			       HOSTNO, extended_msg[1], extended_msg[0],
+			       cmd->device->id, cmd->device->lun);
+   
+
+		    msgout = MESSAGE_REJECT;
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_ATN);
+		    break;
+		} /* switch (tmp) */
+		break;
+	    case PHASE_MSGOUT:
+		len = 1;
+		data = &msgout;
+		hostdata->last_message = msgout;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    hostdata->connected = NULL;
+		    cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    falcon_release_lock_if_possible( hostdata );
+		    return;
+		}
+		msgout = NOP;
+		break;
+	    case PHASE_CMDOUT:
+		len = cmd->cmd_len;
+		data = cmd->cmnd;
+		/* 
+		 * XXX for performance reasons, on machines with a 
+		 * PSEUDO-DMA architecture we should probably 
+		 * use the dma transfer function.  
+		 */
+		NCR5380_transfer_pio(instance, &phase, &len, 
+		    &data);
+		break;
+	    case PHASE_STATIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Status = tmp;
+		break;
+	    default:
+		printk("scsi%d: unknown phase\n", HOSTNO);
+		NCR_PRINT(NDEBUG_ANY);
+	    } /* switch(phase) */
+	} /* if (tmp * SR_REQ) */ 
+    } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *	field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *	nexus has been reestablished,
+ *	
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char target_mask;
+    unsigned char lun, phase;
+    int len;
+#ifdef SUPPORT_TAGS
+    unsigned char tag;
+#endif
+    unsigned char msg[3];
+    unsigned char *data;
+    Scsi_Cmnd *tmp = NULL, *prev;
+/*    unsigned long flags; */
+
+    /*
+     * Disable arbitration, etc. since the host adapter obviously
+     * lost, and tell an interrupted NCR5380_select() to restart.
+     */
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    hostdata->restart_select = 1;
+
+    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+    /* 
+     * At this point, we have detected that our SCSI ID is on the bus,
+     * SEL is true and BSY was false for at least one bus settle delay
+     * (400 ns).
+     *
+     * We must assert BSY ourselves, until the target drops the SEL
+     * signal.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
+    while (NCR5380_read(STATUS_REG) & SR_SEL);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    /*
+     * Wait for target to go into MSGIN.
+     */
+
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    len = 1;
+    data = msg;
+    phase = PHASE_MSGIN;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+    if (!(msg[0] & 0x80)) {
+	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	print_msg(msg);
+	do_abort(instance);
+	return;
+    }
+    lun = (msg[0] & 0x07);
+
+#ifdef SUPPORT_TAGS
+    /* If the phase is still MSGIN, the target wants to send some more
+     * messages. In case it supports tagged queuing, this is probably a
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+     */
+    tag = TAG_NONE;
+    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+	/* Accept previous IDENTIFY message by clearing ACK */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	len = 2;
+	data = msg+1;
+	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+	    msg[1] == SIMPLE_QUEUE_TAG)
+	    tag = msg[2];
+	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+		   "reselection\n", HOSTNO, target_mask, lun, tag);
+    }
+#endif
+    
+    /* 
+     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+     * just reestablished, and remove it from the disconnected queue.
+     */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
+	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
+	if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+#ifdef SUPPORT_TAGS
+	    && (tag == tmp->tag) 
+#endif
+	    ) {
+	    /* ++guenther: prevent race with falcon_release_lock */
+	    falcon_dont_release++;
+	    if (prev) {
+		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+		NEXT(prev) = NEXT(tmp);
+	    } else {
+		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+		hostdata->disconnected_queue = NEXT(tmp);
+	    }
+	    NEXT(tmp) = NULL;
+	    break;
+	}
+    }
+    
+    if (!tmp) {
+	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+		"tag %d "
+#endif
+		"not in disconnected_queue.\n",
+		HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+		, tag
+#endif
+		);
+	/* 
+	 * Since we have an established nexus that we can't do anything
+	 * with, we must abort it.  
+	 */
+	do_abort(instance);
+	return;
+    }
+
+    /* Accept message by clearing ACK */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    hostdata->connected = tmp;
+    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	       HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
+    falcon_dont_release--;
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ * 	host byte of the result field to, if zero DID_ABORTED is 
+ *	used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently 
+ * 	 connected, you have to wait for it to complete.  If this is 
+ *	 a problem, we could implement longjmp() / setjmp(), setjmp()
+ * 	 called where the loop started in NCR5380_main().
+ */
+
+static
+int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *instance = cmd->device->host;
+    SETUP_HOSTDATA(instance);
+    Scsi_Cmnd *tmp, **prev;
+    unsigned long flags;
+
+    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+    print_Scsi_Cmnd (cmd);
+
+    NCR5380_print_status (instance);
+
+    local_irq_save(flags);
+    
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
+	       HOSTNO);
+
+    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		NCR5380_read(BUS_AND_STATUS_REG),
+		NCR5380_read(STATUS_REG));
+
+#if 1
+/* 
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+    if (hostdata->connected == cmd) {
+
+	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */ 
+
+	if (do_abort(instance) == 0) {
+	  hostdata->aborted = 1;
+	  hostdata->connected = NULL;
+	  cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+	  cmd_free_tag( cmd );
+#else
+	  hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+	  local_irq_restore(flags);
+	  cmd->scsi_done(cmd);
+	  falcon_release_lock_if_possible( hostdata );
+	  return SCSI_ABORT_SUCCESS;
+	} else {
+/*	  local_irq_restore(flags); */
+	  printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+	  return SCSI_ABORT_ERROR;
+	} 
+   }
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ * 	    from the issue queue.
+ */
+    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
+	tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+	tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+	if (cmd == tmp) {
+	    REMOVE(5, *prev, tmp, NEXT(tmp));
+	    (*prev) = NEXT(tmp);
+	    NEXT(tmp) = NULL;
+	    tmp->result = DID_ABORT << 16;
+	    local_irq_restore(flags);
+	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+			HOSTNO);
+	    /* Tagged queuing note: no tag to free here, hasn't been assigned
+	     * yet... */
+	    tmp->scsi_done(tmp);
+	    falcon_release_lock_if_possible( hostdata );
+	    return SCSI_ABORT_SUCCESS;
+	}
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *	    and let the high level SCSI driver retry at a later time or 
+ *	    issue a reset.
+ *
+ *	    Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *	    case of noresets less efficient, and would pollute our code.  So,
+ *	    we fail.
+ */
+
+    if (hostdata->connected) {
+	local_irq_restore(flags);
+	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+        return SCSI_ABORT_SNOOZE;
+    }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ * 	there are no connected commands, we reconnect the I_T_L or 
+ *	I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	 tmp = NEXT(tmp)) 
+        if (cmd == tmp) {
+            local_irq_restore(flags);
+	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+  
+            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+		return SCSI_ABORT_BUSY;
+
+	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+	    do_abort (instance);
+
+	    local_irq_save(flags);
+	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
+		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+		    if (cmd == tmp) {
+		    REMOVE(5, *prev, tmp, NEXT(tmp));
+		    *prev = NEXT(tmp);
+		    NEXT(tmp) = NULL;
+		    tmp->result = DID_ABORT << 16;
+		    /* We must unlock the tag/LUN immediately here, since the
+		     * target goes to BUS FREE and doesn't send us another
+		     * message (COMMAND_COMPLETE or the like)
+		     */
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( tmp );
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    local_irq_restore(flags);
+		    tmp->scsi_done(tmp);
+		    falcon_release_lock_if_possible( hostdata );
+		    return SCSI_ABORT_SUCCESS;
+		}
+	}
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *	    the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+    local_irq_restore(flags);
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+           KERN_INFO "        before abortion\n", HOSTNO); 
+
+/* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+    falcon_release_lock_if_possible( hostdata );
+
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/* 
+ * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */ 
+
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+{
+    SETUP_HOSTDATA(cmd->device->host);
+    int           i;
+    unsigned long flags;
+#if 1
+    Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+    if (!IS_A_TT() && !falcon_got_lock)
+	printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
+	       H_NO(cmd) );
+
+    NCR5380_print_status (cmd->device->host);
+
+    /* get in phase */
+    NCR5380_write( TARGET_COMMAND_REG,
+		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+    /* assert RST */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+    udelay (40);
+    /* reset NCR registers */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+    NCR5380_write( MODE_REG, MR_BASE );
+    NCR5380_write( TARGET_COMMAND_REG, 0 );
+    NCR5380_write( SELECT_ENABLE_REG, 0 );
+    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+     * through anymore ... */
+    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+      /* XXX see below                                            XXX */
+
+    /* MSch: old-style reset: actually abort all command processing here */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; to avoid problems with re-inserting the commands
+     * into the issue_queue (via scsi_done()), the aborted commands are
+     * remembered in local variables first.
+     */
+    local_irq_save(flags);
+    connected = (Scsi_Cmnd *)hostdata->connected;
+    hostdata->connected = NULL;
+    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    local_irq_restore(flags);
+
+    /* In order to tell the mid-level code which commands were aborted, 
+     * set the command status to DID_RESET and call scsi_done() !!!
+     * This ultimately aborts processing of these commands in the mid-level.
+     */
+
+    if ((cmd = connected)) {
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+
+    for (i = 0; (cmd = disconnected_queue); ++i) {
+	disconnected_queue = NEXT(cmd);
+	NEXT(cmd) = NULL;
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+    if (i > 0)
+	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+/* The Falcon lock should be released after a reset...
+ */
+/* ++guenther: moved to atari_scsi_reset(), to prevent a race between
+ * unlocking and enabling dma interrupt.
+ */
+/*    falcon_release_lock_if_possible( hostdata );*/
+
+    /* since all commands have been explicitly terminated, we need to tell
+     * the midlevel code that the reset was SUCCESSFUL, and there is no 
+     * need to 'wake up' the commands by a request_sense
+     */
+    return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+    /* MSch: new-style reset handling: let the mid-level do what it can */
+
+    /* ++guenther: MID-LEVEL IS STILL BROKEN.
+     * Mid-level is supposed to requeue all commands that were active on the
+     * various low-level queues. In fact it does this, but that's not enough
+     * because all these commands are subject to timeout. And if a timeout
+     * happens for any removed command, *_abort() is called but all queues
+     * are now empty. Abort then gives up the falcon lock, which is fatal,
+     * since the mid-level will queue more commands and must have the lock
+     * (it's all happening inside timer interrupt handler!!).
+     * Even worse, abort will return NOT_RUNNING for all those commands not
+     * on any queue, so they won't be retried ...
+     *
+     * Conclusion: either scsi.c disables timeout for all resetted commands
+     * immediately, or we lose!  As of linux-2.0.20 it doesn't.
+     */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; so clear the low-level status here to avoid 
+     * conflicts when the mid-level code tries to wake up the affected 
+     * commands!
+     */
+
+    if (hostdata->issue_queue)
+	ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+    if (hostdata->connected) 
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+    if (hostdata->disconnected_queue)
+	ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+    local_irq_save(flags);
+    hostdata->issue_queue = NULL;
+    hostdata->connected = NULL;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    local_irq_restore(flags);
+
+    /* we did no complete reset of all commands, so a wakeup is required */
+    return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8     */
+/* End:             */
diff --git a/drivers/scsi/atari_dma_emul.c b/drivers/scsi/atari_dma_emul.c
new file mode 100644
index 0000000..7026045
--- /dev/null
+++ b/drivers/scsi/atari_dma_emul.c
@@ -0,0 +1,466 @@
+/*
+ * atari_dma_emul.c -- TT SCSI DMA emulator for the Hades.
+ *
+ * Copyright 1997 Wout Klaren <W.Klaren@inter.nl.net>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ * This code was written using the Hades TOS source code as a
+ * reference. This source code can be found on the home page
+ * of Medusa Computer Systems.
+ *
+ * Version 0.1, 1997-09-24.
+ * 
+ * This code should be considered experimental. It has only been
+ * tested on a Hades with a 68060. It might not work on a Hades
+ * with a 68040. Make backups of your hard drives before using
+ * this code.
+ */
+
+#include <asm/uaccess.h>
+
+#define hades_dma_ctrl		(*(unsigned char *) 0xffff8717)
+#define hades_psdm_reg		(*(unsigned char *) 0xffff8741)
+
+#define TRANSFER_SIZE		16
+
+struct m68040_frame {
+	unsigned long  effaddr;  /* effective address */
+	unsigned short ssw;      /* special status word */
+	unsigned short wb3s;     /* write back 3 status */
+	unsigned short wb2s;     /* write back 2 status */
+	unsigned short wb1s;     /* write back 1 status */
+	unsigned long  faddr;    /* fault address */
+	unsigned long  wb3a;     /* write back 3 address */
+	unsigned long  wb3d;     /* write back 3 data */
+	unsigned long  wb2a;     /* write back 2 address */
+	unsigned long  wb2d;     /* write back 2 data */
+	unsigned long  wb1a;     /* write back 1 address */
+	unsigned long  wb1dpd0;  /* write back 1 data/push data 0*/
+	unsigned long  pd1;      /* push data 1*/
+	unsigned long  pd2;      /* push data 2*/
+	unsigned long  pd3;      /* push data 3*/
+};
+
+static void writeback (unsigned short wbs, unsigned long wba,
+		       unsigned long wbd, void *old_buserr)
+{
+	mm_segment_t fs = get_fs();
+	static void *save_buserr;
+
+	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
+			      "move.l	%0,8(%%a0)\n\t"
+			      :
+			      : "r" (&&bus_error)
+			      : "a0" );
+
+	save_buserr = old_buserr;
+
+	set_fs (MAKE_MM_SEG(wbs & WBTM_040));
+
+	switch (wbs & WBSIZ_040) {
+	    case BA_SIZE_BYTE:
+		put_user (wbd & 0xff, (char *)wba);
+		break;
+	    case BA_SIZE_WORD:
+		put_user (wbd & 0xffff, (short *)wba);
+		break;
+	    case BA_SIZE_LONG:
+		put_user (wbd, (int *)wba);
+		break;
+	}
+
+	set_fs (fs);
+	return;
+
+bus_error:
+	__asm__ __volatile__ ("cmp.l	%0,2(%%sp)\n\t"
+			      "bcs.s	.jump_old\n\t"
+			      "cmp.l	%1,2(%%sp)\n\t"
+			      "bls.s	.restore_old\n"
+			".jump_old:\n\t"
+			      "move.l	%2,-(%%sp)\n\t"
+			      "rts\n"
+			".restore_old:\n\t"
+			      "move.l	%%a0,-(%%sp)\n\t"
+			      "movec.l	%%vbr,%%a0\n\t"
+			      "move.l	%2,8(%%a0)\n\t"
+			      "move.l	(%%sp)+,%%a0\n\t"
+			      "rte\n\t"
+			      :
+			      : "i" (writeback), "i" (&&bus_error),
+			        "m" (save_buserr) );
+}
+
+/*
+ * static inline void set_restdata_reg(unsigned char *cur_addr)
+ *
+ * Set the rest data register if necessary.
+ */
+
+static inline void set_restdata_reg(unsigned char *cur_addr)
+{
+	if (((long) cur_addr & ~3) != 0)
+		tt_scsi_dma.dma_restdata =
+			*((unsigned long *) ((long) cur_addr & ~3));
+}
+
+/*
+ * void hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+ * 
+ * This code emulates TT SCSI DMA on the Hades.
+ * 
+ * Note the following:
+ * 
+ * 1. When there is no byte available to read from the SCSI bus, or
+ *    when a byte cannot yet bet written to the SCSI bus, a bus
+ *    error occurs when reading or writing the pseudo DMA data
+ *    register (hades_psdm_reg). We have to catch this bus error
+ *    and try again to read or write the byte. If after several tries
+ *    we still get a bus error, the interrupt handler is left. When
+ *    the byte can be read or written, the interrupt handler is
+ *    called again.
+ * 
+ * 2. The SCSI interrupt must be disabled in this interrupt handler.
+ * 
+ * 3. If we set the EOP signal, the SCSI controller still expects one
+ *    byte to be read or written. Therefore the last byte is transferred
+ *    separately, after setting the EOP signal.
+ * 
+ * 4. When this function is left, the address pointer (start_addr) is
+ *    converted to a physical address. Because it points one byte
+ *    further than the last transferred byte, it can point outside the
+ *    current page. If virt_to_phys() is called with this address we
+ *    might get an access error. Therefore virt_to_phys() is called with
+ *    start_addr - 1 if the count has reached zero. The result is
+ *    increased with one.
+ */
+
+static irqreturn_t hades_dma_emulator(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned long dma_base;
+	register unsigned long dma_cnt asm ("d3");
+	static long save_buserr;
+	register unsigned long save_sp asm ("d4");
+	register int tries asm ("d5");
+	register unsigned char *start_addr asm ("a3"), *end_addr asm ("a4");
+	register unsigned char *eff_addr;
+	register unsigned char *psdm_reg;
+	unsigned long rem;
+
+	atari_disable_irq(IRQ_TT_MFP_SCSI);
+
+	/*
+	 * Read the dma address and count registers.
+	 */
+
+	dma_base = SCSI_DMA_READ_P(dma_addr);
+	dma_cnt = SCSI_DMA_READ_P(dma_cnt);
+
+	/*
+	 * Check if DMA is still enabled.
+	 */
+
+	if ((tt_scsi_dma.dma_ctrl & 2) == 0)
+	{
+		atari_enable_irq(IRQ_TT_MFP_SCSI);
+		return IRQ_HANDLED;
+	}
+
+	if (dma_cnt == 0)
+	{
+		printk(KERN_NOTICE "DMA emulation: count is zero.\n");
+		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
+		atari_enable_irq(IRQ_TT_MFP_SCSI);
+		return IRQ_HANDLED;
+	}
+
+	/*
+	 * Install new bus error routine.
+	 */
+
+	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
+			      "move.l	8(%%a0),%0\n\t"
+			      "move.l	%1,8(%%a0)\n\t"
+			      : "=&r" (save_buserr)
+			      : "r" (&&scsi_bus_error)
+			      : "a0" );
+
+	hades_dma_ctrl &= 0xfc;		/* Bus error and EOP off. */
+
+	/*
+	 * Save the stack pointer.
+	 */
+
+	__asm__ __volatile__ ("move.l	%%sp,%0\n\t"
+			      : "=&r" (save_sp) );
+
+	tries = 100;			/* Maximum number of bus errors. */
+	start_addr = phys_to_virt(dma_base);
+	end_addr = start_addr + dma_cnt;
+
+scsi_loop:
+	dma_cnt--;
+	rem = dma_cnt & (TRANSFER_SIZE - 1);
+	dma_cnt &= ~(TRANSFER_SIZE - 1);
+	psdm_reg = &hades_psdm_reg;
+
+	if (tt_scsi_dma.dma_ctrl & 1)	/* Read or write? */
+	{
+		/*
+		 * SCSI write. Abort when count is zero.
+		 */
+
+		switch (rem)
+		{
+		case 0:
+			while (dma_cnt > 0)
+			{
+				dma_cnt -= TRANSFER_SIZE;
+
+				*psdm_reg = *start_addr++;
+		case 15:
+				*psdm_reg = *start_addr++;
+		case 14:
+				*psdm_reg = *start_addr++;
+		case 13:
+				*psdm_reg = *start_addr++;
+		case 12:
+				*psdm_reg = *start_addr++;
+		case 11:
+				*psdm_reg = *start_addr++;
+		case 10:
+				*psdm_reg = *start_addr++;
+		case 9:
+				*psdm_reg = *start_addr++;
+		case 8:
+				*psdm_reg = *start_addr++;
+		case 7:
+				*psdm_reg = *start_addr++;
+		case 6:
+				*psdm_reg = *start_addr++;
+		case 5:
+				*psdm_reg = *start_addr++;
+		case 4:
+				*psdm_reg = *start_addr++;
+		case 3:
+				*psdm_reg = *start_addr++;
+		case 2:
+				*psdm_reg = *start_addr++;
+		case 1:
+				*psdm_reg = *start_addr++;
+			}
+		}
+
+		hades_dma_ctrl |= 1;	/* Set EOP. */
+		udelay(10);
+		*psdm_reg = *start_addr++;	/* Dummy byte. */
+		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
+	}
+	else
+	{
+		/*
+		 * SCSI read. Abort when count is zero.
+		 */
+
+		switch (rem)
+		{
+		case 0:
+			while (dma_cnt > 0)
+			{
+				dma_cnt -= TRANSFER_SIZE;
+
+				*start_addr++ = *psdm_reg;
+		case 15:
+				*start_addr++ = *psdm_reg;
+		case 14:
+				*start_addr++ = *psdm_reg;
+		case 13:
+				*start_addr++ = *psdm_reg;
+		case 12:
+				*start_addr++ = *psdm_reg;
+		case 11:
+				*start_addr++ = *psdm_reg;
+		case 10:
+				*start_addr++ = *psdm_reg;
+		case 9:
+				*start_addr++ = *psdm_reg;
+		case 8:
+				*start_addr++ = *psdm_reg;
+		case 7:
+				*start_addr++ = *psdm_reg;
+		case 6:
+				*start_addr++ = *psdm_reg;
+		case 5:
+				*start_addr++ = *psdm_reg;
+		case 4:
+				*start_addr++ = *psdm_reg;
+		case 3:
+				*start_addr++ = *psdm_reg;
+		case 2:
+				*start_addr++ = *psdm_reg;
+		case 1:
+				*start_addr++ = *psdm_reg;
+			}
+		}
+
+		hades_dma_ctrl |= 1;	/* Set EOP. */
+		udelay(10);
+		*start_addr++ = *psdm_reg;
+		tt_scsi_dma.dma_ctrl &= 0xfd;	/* DMA ready. */
+
+		set_restdata_reg(start_addr);
+	}
+
+	if (start_addr != end_addr)
+		printk(KERN_CRIT "DMA emulation: FATAL: Count is not zero at end of transfer.\n");
+
+	dma_cnt = end_addr - start_addr;
+
+scsi_end:
+	dma_base = (dma_cnt == 0) ? virt_to_phys(start_addr - 1) + 1 :  
+				    virt_to_phys(start_addr);
+
+	SCSI_DMA_WRITE_P(dma_addr, dma_base);
+	SCSI_DMA_WRITE_P(dma_cnt, dma_cnt);
+
+	/*
+	 * Restore old bus error routine.
+	 */
+
+	__asm__ __volatile__ ("movec.l	%%vbr,%%a0\n\t"
+			      "move.l	%0,8(%%a0)\n\t"
+			      :
+			      : "r" (save_buserr)
+			      : "a0" );
+
+	atari_enable_irq(IRQ_TT_MFP_SCSI);
+
+	return IRQ_HANDLED;
+
+scsi_bus_error:
+	/*
+	 * First check if the bus error is caused by our code.
+	 * If not, call the original handler.
+	 */
+
+	__asm__ __volatile__ ("cmp.l	%0,2(%%sp)\n\t"
+			      "bcs.s	.old_vector\n\t"
+			      "cmp.l	%1,2(%%sp)\n\t"
+			      "bls.s	.scsi_buserr\n"
+			".old_vector:\n\t"
+			      "move.l	%2,-(%%sp)\n\t"
+			      "rts\n"
+			".scsi_buserr:\n\t"
+			      :
+			      : "i" (&&scsi_loop), "i" (&&scsi_end),
+			        "m" (save_buserr) );
+
+	if (CPU_IS_060)
+	{
+		/*
+		 * Get effective address and restore the stack.
+		 */
+
+		__asm__ __volatile__ ("move.l	8(%%sp),%0\n\t"
+				      "move.l	%1,%%sp\n\t"
+				      : "=a&" (eff_addr)
+				      : "r" (save_sp) );
+	}
+	else
+	{
+		register struct m68040_frame *frame;
+
+		__asm__ __volatile__ ("lea	8(%%sp),%0\n\t"
+				      : "=a&" (frame) );
+
+		if (tt_scsi_dma.dma_ctrl & 1)
+		{
+			/*
+			 * Bus error while writing.
+			 */
+
+			if (frame->wb3s & WBV_040)
+			{
+				if (frame->wb3a == (long) &hades_psdm_reg)
+					start_addr--;
+				else
+					writeback(frame->wb3s, frame->wb3a,
+						  frame->wb3d, &&scsi_bus_error);
+			}
+
+			if (frame->wb2s & WBV_040)
+			{
+				if (frame->wb2a == (long) &hades_psdm_reg)
+					start_addr--;
+				else
+					writeback(frame->wb2s, frame->wb2a,
+						  frame->wb2d, &&scsi_bus_error);
+			}
+
+			if (frame->wb1s & WBV_040)
+			{
+				if (frame->wb1a == (long) &hades_psdm_reg)
+					start_addr--;
+			}
+		}
+		else
+		{
+			/*
+			 * Bus error while reading.
+			 */
+
+			if (frame->wb3s & WBV_040)
+				writeback(frame->wb3s, frame->wb3a,
+					  frame->wb3d, &&scsi_bus_error);
+		}
+
+		eff_addr = (unsigned char *) frame->faddr;
+
+		__asm__ __volatile__ ("move.l	%0,%%sp\n\t"
+				      :
+				      : "r" (save_sp) );
+	}
+
+	dma_cnt = end_addr - start_addr;
+
+	if (eff_addr == &hades_psdm_reg)
+	{
+		/*
+		 * Bus error occurred while reading the pseudo
+		 * DMA register. Time out.
+		 */
+
+		tries--;
+
+		if (tries <= 0)
+		{
+			if ((tt_scsi_dma.dma_ctrl & 1) == 0)	/* Read or write? */
+				set_restdata_reg(start_addr);
+
+			if (dma_cnt <= 1)
+				printk(KERN_CRIT "DMA emulation: Fatal "
+				       "error while %s the last byte.\n",
+				       (tt_scsi_dma.dma_ctrl & 1)
+				       ? "writing" : "reading");
+
+			goto scsi_end;
+		}
+		else
+			goto scsi_loop;
+	}
+	else
+	{
+		/*
+		 * Bus error during pseudo DMA transfer.
+		 * Terminate the DMA transfer.
+		 */
+
+		hades_dma_ctrl |= 3;	/* Set EOP and bus error. */
+		if ((tt_scsi_dma.dma_ctrl & 1) == 0)	/* Read or write? */
+			set_restdata_reg(start_addr);
+		goto scsi_end;
+	}
+}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
new file mode 100644
index 0000000..af8adb6
--- /dev/null
+++ b/drivers/scsi/atari_scsi.c
@@ -0,0 +1,1163 @@
+/*
+ * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ *   Loosely based on the work of Robert De Vries' team and added:
+ *    - working real DMA
+ *    - Falcon support (untested yet!)   ++bjoern fixed and now it works
+ *    - lots of extensions and bug fixes.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+/**************************************************************************/
+/*                                                                        */
+/* Notes for Falcon SCSI:                                                 */
+/* ----------------------                                                 */
+/*                                                                        */
+/* Since the Falcon SCSI uses the ST-DMA chip, that is shared among       */
+/* several device drivers, locking and unlocking the access to this       */
+/* chip is required. But locking is not possible from an interrupt,       */
+/* since it puts the process to sleep if the lock is not available.       */
+/* This prevents "late" locking of the DMA chip, i.e. locking it just     */
+/* before using it, since in case of disconnection-reconnection           */
+/* commands, the DMA is started from the reselection interrupt.           */
+/*                                                                        */
+/* Two possible schemes for ST-DMA-locking would be:                      */
+/*  1) The lock is taken for each command separately and disconnecting    */
+/*     is forbidden (i.e. can_queue = 1).                                 */
+/*  2) The DMA chip is locked when the first command comes in and         */
+/*     released when the last command is finished and all queues are      */
+/*     empty.                                                             */
+/* The first alternative would result in bad performance, since the       */
+/* interleaving of commands would not be used. The second is unfair to    */
+/* other drivers using the ST-DMA, because the queues will seldom be      */
+/* totally empty if there is a lot of disk traffic.                       */
+/*                                                                        */
+/* For this reasons I decided to employ a more elaborate scheme:          */
+/*  - First, we give up the lock every time we can (for fairness), this    */
+/*    means every time a command finishes and there are no other commands */
+/*    on the disconnected queue.                                          */
+/*  - If there are others waiting to lock the DMA chip, we stop           */
+/*    issuing commands, i.e. moving them onto the issue queue.           */
+/*    Because of that, the disconnected queue will run empty in a         */
+/*    while. Instead we go to sleep on a 'fairness_queue'.                */
+/*  - If the lock is released, all processes waiting on the fairness      */
+/*    queue will be woken. The first of them tries to re-lock the DMA,     */
+/*    the others wait for the first to finish this task. After that,      */
+/*    they can all run on and do their commands...                        */
+/* This sounds complicated (and it is it :-(), but it seems to be a       */
+/* good compromise between fairness and performance: As long as no one     */
+/* else wants to work with the ST-DMA chip, SCSI can go along as          */
+/* usual. If now someone else comes, this behaviour is changed to a       */
+/* "fairness mode": just already initiated commands are finished and      */
+/* then the lock is released. The other one waiting will probably win     */
+/* the race for locking the DMA, since it was waiting for longer. And     */
+/* after it has finished, SCSI can go ahead again. Finally: I hope I      */
+/* have not produced any deadlock possibilities!                          */
+/*                                                                        */
+/**************************************************************************/
+
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#define NDEBUG (0)
+
+#define NDEBUG_ABORT	0x800000
+#define NDEBUG_TAGS	0x1000000
+#define NDEBUG_MERGING	0x2000000
+
+#define AUTOSENSE
+/* For the Atari version, use only polled IO or REAL_DMA */
+#define	REAL_DMA
+/* Support tagged queuing? (on devices that are able to... :-) */
+#define	SUPPORT_TAGS
+#define	MAX_TAGS 32
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/nvram.h>
+#include <linux/bitops.h>
+
+#include <asm/setup.h>
+#include <asm/atarihw.h>
+#include <asm/atariints.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/traps.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "atari_scsi.h"
+#include "NCR5380.h"
+#include <asm/atari_stdma.h>
+#include <asm/atari_stram.h>
+#include <asm/io.h>
+
+#include <linux/stat.h>
+
+#define	IS_A_TT()	ATARIHW_PRESENT(TT_SCSI)
+
+#define	SCSI_DMA_WRITE_P(elt,val)				\
+	do {							\
+		unsigned long v = val;				\
+		tt_scsi_dma.elt##_lo = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_lmd = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_hmd = v & 0xff;		\
+		v >>= 8;					\
+		tt_scsi_dma.elt##_hi = v & 0xff;		\
+	} while(0)
+
+#define	SCSI_DMA_READ_P(elt)					\
+	(((((((unsigned long)tt_scsi_dma.elt##_hi << 8) |	\
+	     (unsigned long)tt_scsi_dma.elt##_hmd) << 8) |	\
+	   (unsigned long)tt_scsi_dma.elt##_lmd) << 8) |	\
+	 (unsigned long)tt_scsi_dma.elt##_lo)
+
+
+static inline void SCSI_DMA_SETADR(unsigned long adr)
+{
+	st_dma.dma_lo = (unsigned char)adr;
+	MFPDELAY();
+	adr >>= 8;
+	st_dma.dma_md = (unsigned char)adr;
+	MFPDELAY();
+	adr >>= 8;
+	st_dma.dma_hi = (unsigned char)adr;
+	MFPDELAY();
+}
+
+static inline unsigned long SCSI_DMA_GETADR(void)
+{
+	unsigned long adr;
+	adr = st_dma.dma_lo;
+	MFPDELAY();
+	adr |= (st_dma.dma_md & 0xff) << 8;
+	MFPDELAY();
+	adr |= (st_dma.dma_hi & 0xff) << 16;
+	MFPDELAY();
+	return adr;
+}
+
+static inline void ENABLE_IRQ(void)
+{
+	if (IS_A_TT())
+		atari_enable_irq(IRQ_TT_MFP_SCSI);
+	else
+		atari_enable_irq(IRQ_MFP_FSCSI);
+}
+
+static inline void DISABLE_IRQ(void)
+{
+	if (IS_A_TT())
+		atari_disable_irq(IRQ_TT_MFP_SCSI);
+	else
+		atari_disable_irq(IRQ_MFP_FSCSI);
+}
+
+
+#define HOSTDATA_DMALEN		(((struct NCR5380_hostdata *) \
+				(atari_scsi_host->hostdata))->dma_len)
+
+/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
+ * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
+ * need ten times the standard value... */
+#ifndef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+#define	AFTER_RESET_DELAY	(HZ/2)
+#else
+#define	AFTER_RESET_DELAY	(5*HZ/2)
+#endif
+
+/***************************** Prototypes *****************************/
+
+#ifdef REAL_DMA
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat );
+static void atari_scsi_fetch_restbytes( void );
+static long atari_scsi_dma_residual( struct Scsi_Host *instance );
+static int falcon_classify_cmd( Scsi_Cmnd *cmd );
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+                                         Scsi_Cmnd *cmd, int write_flag );
+#endif
+static irqreturn_t scsi_tt_intr( int irq, void *dummy, struct pt_regs *fp);
+static irqreturn_t scsi_falcon_intr( int irq, void *dummy, struct pt_regs *fp);
+static void falcon_release_lock_if_possible( struct NCR5380_hostdata *
+                                             hostdata );
+static void falcon_get_lock( void );
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+static void atari_scsi_reset_boot( void );
+#endif
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg );
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value);
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg );
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value );
+
+/************************* End of Prototypes **************************/
+
+
+static struct Scsi_Host *atari_scsi_host = NULL;
+static unsigned char (*atari_scsi_reg_read)( unsigned char reg );
+static void (*atari_scsi_reg_write)( unsigned char reg, unsigned char value );
+
+#ifdef REAL_DMA
+static unsigned long	atari_dma_residual, atari_dma_startaddr;
+static short		atari_dma_active;
+/* pointer to the dribble buffer */
+static char		*atari_dma_buffer = NULL;
+/* precalculated physical address of the dribble buffer */
+static unsigned long	atari_dma_phys_buffer;
+/* != 0 tells the Falcon int handler to copy data from the dribble buffer */
+static char		*atari_dma_orig_addr;
+/* size of the dribble buffer; 4k seems enough, since the Falcon cannot use
+ * scatter-gather anyway, so most transfers are 1024 byte only. In the rare
+ * cases where requests to physical contiguous buffers have been merged, this
+ * request is <= 4k (one page). So I don't think we have to split transfers
+ * just due to this buffer size...
+ */
+#define	STRAM_BUFFER_SIZE	(4096)
+/* mask for address bits that can't be used with the ST-DMA */
+static unsigned long	atari_dma_stram_mask;
+#define STRAM_ADDR(a)	(((a) & atari_dma_stram_mask) == 0)
+/* number of bytes to cut from a transfer to handle NCR overruns */
+static int atari_read_overruns = 0;
+#endif
+
+static int setup_can_queue = -1;
+MODULE_PARM(setup_can_queue, "i");
+static int setup_cmd_per_lun = -1;
+MODULE_PARM(setup_cmd_per_lun, "i");
+static int setup_sg_tablesize = -1;
+MODULE_PARM(setup_sg_tablesize, "i");
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+MODULE_PARM(setup_use_tagged_queuing, "i");
+#endif
+static int setup_hostid = -1;
+MODULE_PARM(setup_hostid, "i");
+
+
+#if defined(CONFIG_TT_DMA_EMUL)
+#include "atari_dma_emul.c"
+#endif
+
+#if defined(REAL_DMA)
+
+static int scsi_dma_is_ignored_buserr( unsigned char dma_stat )
+{
+	int i;
+	unsigned long	addr = SCSI_DMA_READ_P( dma_addr ), end_addr;
+
+	if (dma_stat & 0x01) {
+
+		/* A bus error happens when DMA-ing from the last page of a
+		 * physical memory chunk (DMA prefetch!), but that doesn't hurt.
+		 * Check for this case:
+		 */
+		
+		for( i = 0; i < m68k_num_memory; ++i ) {
+			end_addr = m68k_memory[i].addr +
+				m68k_memory[i].size;
+			if (end_addr <= addr && addr <= end_addr + 4)
+				return( 1 );
+		}
+	}
+	return( 0 );
+}
+
+
+#if 0
+/* Dead code... wasn't called anyway :-) and causes some trouble, because at
+ * end-of-DMA, both SCSI ints are triggered simultaneously, so the NCR int has
+ * to clear the DMA int pending bit before it allows other level 6 interrupts.
+ */
+static void scsi_dma_buserr (int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned char	dma_stat = tt_scsi_dma.dma_ctrl;
+
+	/* Don't do anything if a NCR interrupt is pending. Probably it's just
+	 * masked... */
+	if (atari_irq_pending( IRQ_TT_MFP_SCSI ))
+		return;
+	
+	printk("Bad SCSI DMA interrupt! dma_addr=0x%08lx dma_stat=%02x dma_cnt=%08lx\n",
+	       SCSI_DMA_READ_P(dma_addr), dma_stat, SCSI_DMA_READ_P(dma_cnt));
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat ))
+			printk( "SCSI DMA bus error -- bad DMA programming!\n" );
+	}
+	else {
+		/* Under normal circumstances we never should get to this point,
+		 * since both interrupts are triggered simultaneously and the 5380
+		 * int has higher priority. When this irq is handled, that DMA
+		 * interrupt is cleared. So a warning message is printed here.
+		 */
+		printk( "SCSI DMA intr ?? -- this shouldn't happen!\n" );
+	}
+}
+#endif
+
+#endif
+
+
+static irqreturn_t scsi_tt_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+#ifdef REAL_DMA
+	int dma_stat;
+
+	dma_stat = tt_scsi_dma.dma_ctrl;
+
+	INT_PRINTK("scsi%d: NCR5380 interrupt, DMA status = %02x\n",
+		   atari_scsi_host->host_no, dma_stat & 0xff);
+
+	/* Look if it was the DMA that has interrupted: First possibility
+	 * is that a bus error occurred...
+	 */
+	if (dma_stat & 0x80) {
+		if (!scsi_dma_is_ignored_buserr( dma_stat )) {
+			printk(KERN_ERR "SCSI DMA caused bus error near 0x%08lx\n",
+			       SCSI_DMA_READ_P(dma_addr));
+			printk(KERN_CRIT "SCSI DMA bus error -- bad DMA programming!");
+		}
+	}
+
+	/* If the DMA is active but not finished, we have the case
+	 * that some other 5380 interrupt occurred within the DMA transfer.
+	 * This means we have residual bytes, if the desired end address
+	 * is not yet reached. Maybe we have to fetch some bytes from the
+	 * rest data register, too. The residual must be calculated from
+	 * the address pointer, not the counter register, because only the
+	 * addr reg counts bytes not yet written and pending in the rest
+	 * data reg!
+	 */
+	if ((dma_stat & 0x02) && !(dma_stat & 0x40)) {
+		atari_dma_residual = HOSTDATA_DMALEN - (SCSI_DMA_READ_P( dma_addr ) -
+												atari_dma_startaddr);
+
+		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+			   atari_dma_residual);
+
+		if ((signed int)atari_dma_residual < 0)
+			atari_dma_residual = 0;
+		if ((dma_stat & 1) == 0) {
+			/* After read operations, we maybe have to
+			   transport some rest bytes */
+			atari_scsi_fetch_restbytes();
+		}
+		else {
+			/* There seems to be a nasty bug in some SCSI-DMA/NCR
+			   combinations: If a target disconnects while a write
+			   operation is going on, the address register of the
+			   DMA may be a few bytes farer than it actually read.
+			   This is probably due to DMA prefetching and a delay
+			   between DMA and NCR.  Experiments showed that the
+			   dma_addr is 9 bytes to high, but this could vary.
+			   The problem is, that the residual is thus calculated
+			   wrong and the next transfer will start behind where
+			   it should.  So we round up the residual to the next
+			   multiple of a sector size, if it isn't already a
+			   multiple and the originally expected transfer size
+			   was.  The latter condition is there to ensure that
+			   the correction is taken only for "real" data
+			   transfers and not for, e.g., the parameters of some
+			   other command.  These shouldn't disconnect anyway.
+			   */
+			if (atari_dma_residual & 0x1ff) {
+				DMA_PRINTK("SCSI DMA: DMA bug corrected, "
+					   "difference %ld bytes\n",
+					   512 - (atari_dma_residual & 0x1ff));
+				atari_dma_residual = (atari_dma_residual + 511) & ~0x1ff;
+			}
+		}
+		tt_scsi_dma.dma_ctrl = 0;
+	}
+
+	/* If the DMA is finished, fetch the rest bytes and turn it off */
+	if (dma_stat & 0x40) {
+		atari_dma_residual = 0;
+		if ((dma_stat & 1) == 0)
+			atari_scsi_fetch_restbytes();
+		tt_scsi_dma.dma_ctrl = 0;
+	}
+
+#endif /* REAL_DMA */
+	
+	NCR5380_intr (0, 0, 0);
+
+#if 0
+	/* To be sure the int is not masked */
+	atari_enable_irq( IRQ_TT_MFP_SCSI );
+#endif
+	return IRQ_HANDLED;
+}
+
+
+static irqreturn_t scsi_falcon_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+#ifdef REAL_DMA
+	int dma_stat;
+
+	/* Turn off DMA and select sector counter register before
+	 * accessing the status register (Atari recommendation!)
+	 */
+	st_dma.dma_mode_status = 0x90;
+	dma_stat = st_dma.dma_mode_status;
+
+	/* Bit 0 indicates some error in the DMA process... don't know
+	 * what happened exactly (no further docu).
+	 */
+	if (!(dma_stat & 0x01)) {
+		/* DMA error */
+		printk(KERN_CRIT "SCSI DMA error near 0x%08lx!\n", SCSI_DMA_GETADR());
+	}
+
+	/* If the DMA was active, but now bit 1 is not clear, it is some
+	 * other 5380 interrupt that finishes the DMA transfer. We have to
+	 * calculate the number of residual bytes and give a warning if
+	 * bytes are stuck in the ST-DMA fifo (there's no way to reach them!)
+	 */
+	if (atari_dma_active && (dma_stat & 0x02)) {
+		unsigned long	transferred;
+
+		transferred = SCSI_DMA_GETADR() - atari_dma_startaddr;
+		/* The ST-DMA address is incremented in 2-byte steps, but the
+		 * data are written only in 16-byte chunks. If the number of
+		 * transferred bytes is not divisible by 16, the remainder is
+		 * lost somewhere in outer space.
+		 */
+		if (transferred & 15)
+			printk(KERN_ERR "SCSI DMA error: %ld bytes lost in "
+			       "ST-DMA fifo\n", transferred & 15);
+
+		atari_dma_residual = HOSTDATA_DMALEN - transferred;
+		DMA_PRINTK("SCSI DMA: There are %ld residual bytes.\n",
+			   atari_dma_residual);
+	}
+	else
+		atari_dma_residual = 0;
+	atari_dma_active = 0;
+
+	if (atari_dma_orig_addr) {
+		/* If the dribble buffer was used on a read operation, copy the DMA-ed
+		 * data to the original destination address.
+		 */
+		memcpy(atari_dma_orig_addr, phys_to_virt(atari_dma_startaddr),
+		       HOSTDATA_DMALEN - atari_dma_residual);
+		atari_dma_orig_addr = NULL;
+	}
+
+#endif /* REAL_DMA */
+
+	NCR5380_intr (0, 0, 0);
+	return IRQ_HANDLED;
+}
+
+
+#ifdef REAL_DMA
+static void atari_scsi_fetch_restbytes( void )
+{
+	int nr;
+	char *src, *dst;
+	unsigned long phys_dst;
+
+	/* fetch rest bytes in the DMA register */
+	phys_dst = SCSI_DMA_READ_P(dma_addr);
+	nr = phys_dst & 3;
+	if (nr) {
+		/* there are 'nr' bytes left for the last long address
+		   before the DMA pointer */
+		phys_dst ^= nr;
+		DMA_PRINTK("SCSI DMA: there are %d rest bytes for phys addr 0x%08lx",
+			   nr, phys_dst);
+		/* The content of the DMA pointer is a physical address!  */
+		dst = phys_to_virt(phys_dst);
+		DMA_PRINTK(" = virt addr %p\n", dst);
+		for (src = (char *)&tt_scsi_dma.dma_restdata; nr != 0; --nr)
+			*dst++ = *src++;
+	}
+}
+#endif /* REAL_DMA */
+
+
+static int falcon_got_lock = 0;
+static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);
+static int falcon_trying_lock = 0;
+static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);
+static int falcon_dont_release = 0;
+
+/* This function releases the lock on the DMA chip if there is no
+ * connected command and the disconnected queue is empty. On
+ * releasing, instances of falcon_get_lock are awoken, that put
+ * themselves to sleep for fairness. They can now try to get the lock
+ * again (but others waiting longer more probably will win).
+ */
+
+static void
+falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata )
+{
+	unsigned long flags;
+		
+	if (IS_A_TT()) return;
+	
+	local_irq_save(flags);
+
+	if (falcon_got_lock &&
+		!hostdata->disconnected_queue &&
+		!hostdata->issue_queue &&
+		!hostdata->connected) {
+
+		if (falcon_dont_release) {
+#if 0
+			printk("WARNING: Lock release not allowed. Ignored\n");
+#endif
+			local_irq_restore(flags);
+			return;
+		}
+		falcon_got_lock = 0;
+		stdma_release();
+		wake_up( &falcon_fairness_wait );
+	}
+
+	local_irq_restore(flags);
+}
+
+/* This function manages the locking of the ST-DMA.
+ * If the DMA isn't locked already for SCSI, it tries to lock it by
+ * calling stdma_lock(). But if the DMA is locked by the SCSI code and
+ * there are other drivers waiting for the chip, we do not issue the
+ * command immediately but wait on 'falcon_fairness_queue'. We will be
+ * waked up when the DMA is unlocked by some SCSI interrupt. After that
+ * we try to get the lock again.
+ * But we must be prepared that more than one instance of
+ * falcon_get_lock() is waiting on the fairness queue. They should not
+ * try all at once to call stdma_lock(), one is enough! For that, the
+ * first one sets 'falcon_trying_lock', others that see that variable
+ * set wait on the queue 'falcon_try_wait'.
+ * Complicated, complicated.... Sigh...
+ */
+
+static void falcon_get_lock( void )
+{
+	unsigned long flags;
+
+	if (IS_A_TT()) return;
+
+	local_irq_save(flags);
+
+	while( !in_interrupt() && falcon_got_lock && stdma_others_waiting() )
+		sleep_on( &falcon_fairness_wait );
+
+	while (!falcon_got_lock) {
+		if (in_interrupt())
+			panic( "Falcon SCSI hasn't ST-DMA lock in interrupt" );
+		if (!falcon_trying_lock) {
+			falcon_trying_lock = 1;
+			stdma_lock(scsi_falcon_intr, NULL);
+			falcon_got_lock = 1;
+			falcon_trying_lock = 0;
+			wake_up( &falcon_try_wait );
+		}
+		else {
+			sleep_on( &falcon_try_wait );
+		}
+	}	
+
+	local_irq_restore(flags);
+	if (!falcon_got_lock)
+		panic("Falcon SCSI: someone stole the lock :-(\n");
+}
+
+
+/* This is the wrapper function for NCR5380_queue_command(). It just
+ * tries to get the lock on the ST-DMA (see above) and then calls the
+ * original function.
+ */
+
+#if 0
+int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+	/* falcon_get_lock();
+	 * ++guenther: moved to NCR5380_queue_command() to prevent
+	 * race condition, see there for an explanation.
+	 */
+	return( NCR5380_queue_command( cmd, done ) );
+}
+#endif
+
+
+int atari_scsi_detect (Scsi_Host_Template *host)
+{
+	static int called = 0;
+	struct Scsi_Host *instance;
+
+	if (!MACH_IS_ATARI ||
+	    (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
+	    called)
+		return( 0 );
+
+	host->proc_name = "Atari";
+
+	atari_scsi_reg_read  = IS_A_TT() ? atari_scsi_tt_reg_read :
+					   atari_scsi_falcon_reg_read;
+	atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
+					   atari_scsi_falcon_reg_write;
+
+	/* setup variables */
+	host->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue :
+		IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE;
+	host->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun :
+		IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN;
+	/* Force sg_tablesize to 0 on a Falcon! */
+	host->sg_tablesize =
+		!IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE :
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE;
+
+	if (setup_hostid >= 0)
+		host->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		host->this_id = 7;
+		/* Test if a host id is set in the NVRam */
+		if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+			unsigned char b = nvram_read_byte( 14 );
+			/* Arbitration enabled? (for TOS) If yes, use configured host ID */
+			if (b & 0x80)
+				host->this_id = b & 7;
+		}
+	}
+
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+#endif
+#ifdef REAL_DMA
+	/* If running on a Falcon and if there's TT-Ram (i.e., more than one
+	 * memory block, since there's always ST-Ram in a Falcon), then allocate a
+	 * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative
+	 * Ram.
+	 */
+	if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
+	    !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
+		atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
+		if (!atari_dma_buffer) {
+			printk( KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
+					"double buffer\n" );
+			return( 0 );
+		}
+		atari_dma_phys_buffer = virt_to_phys( atari_dma_buffer );
+		atari_dma_orig_addr = 0;
+	}
+#endif
+	instance = scsi_register (host, sizeof (struct NCR5380_hostdata));
+	if(instance == NULL)
+	{
+		atari_stram_free(atari_dma_buffer);
+		atari_dma_buffer = 0;
+		return 0;
+	}
+	atari_scsi_host = instance;
+       /* Set irq to 0, to avoid that the mid-level code disables our interrupt
+        * during queue_command calls. This is completely unnecessary, and even
+        * worse causes bad problems on the Falcon, where the int is shared with
+        * IDE and floppy! */
+       instance->irq = 0;
+
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+	atari_scsi_reset_boot();
+#endif
+	NCR5380_init (instance, 0);
+
+	if (IS_A_TT()) {
+
+		/* This int is actually "pseudo-slow", i.e. it acts like a slow
+		 * interrupt after having cleared the pending flag for the DMA
+		 * interrupt. */
+		if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
+				 "SCSI NCR5380", scsi_tt_intr)) {
+			printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI);
+			scsi_unregister(atari_scsi_host);
+			atari_stram_free(atari_dma_buffer);
+			atari_dma_buffer = 0;
+			return 0;
+		}
+		tt_mfp.active_edge |= 0x80;		/* SCSI int on L->H */
+#ifdef REAL_DMA
+		tt_scsi_dma.dma_ctrl = 0;
+		atari_dma_residual = 0;
+#ifdef CONFIG_TT_DMA_EMUL
+		if (MACH_IS_HADES) {
+			if (request_irq(IRQ_AUTO_2, hades_dma_emulator,
+					 IRQ_TYPE_PRIO, "Hades DMA emulator",
+					 hades_dma_emulator)) {
+				printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting (MACH_IS_HADES)",IRQ_AUTO_2);
+				free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
+				scsi_unregister(atari_scsi_host);
+				atari_stram_free(atari_dma_buffer);
+				atari_dma_buffer = 0;
+				return 0;
+			}
+		}
+#endif
+		if (MACH_IS_MEDUSA || MACH_IS_HADES) {
+			/* While the read overruns (described by Drew Eckhardt in
+			 * NCR5380.c) never happened on TTs, they do in fact on the Medusa
+			 * (This was the cause why SCSI didn't work right for so long
+			 * there.) Since handling the overruns slows down a bit, I turned
+			 * the #ifdef's into a runtime condition.
+			 *
+			 * In principle it should be sufficient to do max. 1 byte with
+			 * PIO, but there is another problem on the Medusa with the DMA
+			 * rest data register. So 'atari_read_overruns' is currently set
+			 * to 4 to avoid having transfers that aren't a multiple of 4. If
+			 * the rest data bug is fixed, this can be lowered to 1.
+			 */
+			atari_read_overruns = 4;
+		}		
+#endif /*REAL_DMA*/
+	}
+	else { /* ! IS_A_TT */
+		
+		/* Nothing to do for the interrupt: the ST-DMA is initialized
+		 * already by atari_init_INTS()
+		 */
+
+#ifdef REAL_DMA
+		atari_dma_residual = 0;
+		atari_dma_active = 0;
+		atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
+					: 0xff000000);
+#endif
+	}
+
+	printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
+#ifdef SUPPORT_TAGS
+			"TAGGED-QUEUING=%s "
+#endif
+			"HOSTID=%d",
+			instance->host_no, instance->hostt->can_queue,
+			instance->hostt->cmd_per_lun,
+			instance->hostt->sg_tablesize,
+#ifdef SUPPORT_TAGS
+			setup_use_tagged_queuing ? "yes" : "no",
+#endif
+			instance->hostt->this_id );
+	NCR5380_print_options (instance);
+	printk ("\n");
+
+	called = 1;
+	return( 1 );
+}
+
+#ifdef MODULE
+int atari_scsi_release (struct Scsi_Host *sh)
+{
+	if (IS_A_TT())
+		free_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr);
+	if (atari_dma_buffer)
+		atari_stram_free (atari_dma_buffer);
+	return 1;
+}
+#endif
+
+void __init atari_scsi_setup(char *str, int *ints)
+{
+	/* Format of atascsi parameter is:
+	 *   atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
+	 * Defaults depend on TT or Falcon, hostid determined at run time.
+	 * Negative values mean don't change.
+	 */
+	
+	if (ints[0] < 1) {
+		printk( "atari_scsi_setup: no arguments!\n" );
+		return;
+	}
+
+	if (ints[0] >= 1) {
+		if (ints[1] > 0)
+			/* no limits on this, just > 0 */
+			setup_can_queue = ints[1];
+	}
+	if (ints[0] >= 2) {
+		if (ints[2] > 0)
+			setup_cmd_per_lun = ints[2];
+	}
+	if (ints[0] >= 3) {
+		if (ints[3] >= 0) {
+			setup_sg_tablesize = ints[3];
+			/* Must be <= SG_ALL (255) */
+			if (setup_sg_tablesize > SG_ALL)
+				setup_sg_tablesize = SG_ALL;
+		}
+	}
+	if (ints[0] >= 4) {
+		/* Must be between 0 and 7 */
+		if (ints[4] >= 0 && ints[4] <= 7)
+			setup_hostid = ints[4];
+		else if (ints[4] > 7)
+			printk( "atari_scsi_setup: invalid host ID %d !\n", ints[4] );
+	}
+#ifdef SUPPORT_TAGS
+	if (ints[0] >= 5) {
+		if (ints[5] >= 0)
+			setup_use_tagged_queuing = !!ints[5];
+	}
+#endif
+}
+
+int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
+{
+	int		rv;
+	struct NCR5380_hostdata *hostdata =
+		(struct NCR5380_hostdata *)cmd->device->host->hostdata;
+
+	/* For doing the reset, SCSI interrupts must be disabled first,
+	 * since the 5380 raises its IRQ line while _RST is active and we
+	 * can't disable interrupts completely, since we need the timer.
+	 */
+	/* And abort a maybe active DMA transfer */
+	if (IS_A_TT()) {
+		atari_turnoff_irq( IRQ_TT_MFP_SCSI );
+#ifdef REAL_DMA
+		tt_scsi_dma.dma_ctrl = 0;
+#endif /* REAL_DMA */
+	}
+	else {
+		atari_turnoff_irq( IRQ_MFP_FSCSI );
+#ifdef REAL_DMA
+		st_dma.dma_mode_status = 0x90;
+		atari_dma_active = 0;
+		atari_dma_orig_addr = NULL;
+#endif /* REAL_DMA */
+	}
+
+	rv = NCR5380_bus_reset(cmd);
+
+	/* Re-enable ints */
+	if (IS_A_TT()) {
+		atari_turnon_irq( IRQ_TT_MFP_SCSI );
+	}
+	else {
+		atari_turnon_irq( IRQ_MFP_FSCSI );
+	}
+	if ((rv & SCSI_RESET_ACTION) == SCSI_RESET_SUCCESS)
+		falcon_release_lock_if_possible(hostdata);
+
+	return( rv );
+}
+
+	
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+static void __init atari_scsi_reset_boot(void)
+{
+	unsigned long end;
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No messing
+	 * with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Atari SCSI: resetting the SCSI bus..." );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	end = jiffies + AFTER_RESET_DELAY;
+	while (time_before(jiffies, end))
+		barrier();
+
+	printk( " done\n" );
+}
+#endif
+
+
+const char * atari_scsi_info (struct Scsi_Host *host)
+{
+	/* atari_scsi_detect() is verbose enough... */
+	static const char string[] = "Atari native SCSI";
+	return string;
+}
+
+
+#if defined(REAL_DMA)
+
+unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data,
+				   unsigned long count, int dir )
+{
+	unsigned long addr = virt_to_phys( data );
+
+	DMA_PRINTK("scsi%d: setting up dma, data = %p, phys = %lx, count = %ld, "
+		   "dir = %d\n", instance->host_no, data, addr, count, dir);
+
+	if (!IS_A_TT() && !STRAM_ADDR(addr)) {
+		/* If we have a non-DMAable address on a Falcon, use the dribble
+		 * buffer; 'orig_addr' != 0 in the read case tells the interrupt
+		 * handler to copy data from the dribble buffer to the originally
+		 * wanted address.
+		 */
+		if (dir)
+			memcpy( atari_dma_buffer, data, count );
+		else
+			atari_dma_orig_addr = data;
+		addr = atari_dma_phys_buffer;
+	}
+	
+	atari_dma_startaddr = addr;	/* Needed for calculating residual later. */
+  
+	/* Cache cleanup stuff: On writes, push any dirty cache out before sending
+	 * it to the peripheral. (Must be done before DMA setup, since at least
+	 * the ST-DMA begins to fill internal buffers right after setup. For
+	 * reads, invalidate any cache, may be altered after DMA without CPU
+	 * knowledge.
+	 * 
+	 * ++roman: For the Medusa, there's no need at all for that cache stuff,
+	 * because the hardware does bus snooping (fine!).
+	 */
+	dma_cache_maintenance( addr, count, dir );
+
+	if (count == 0)
+		printk(KERN_NOTICE "SCSI warning: DMA programmed for 0 bytes !\n");
+
+	if (IS_A_TT()) {
+		tt_scsi_dma.dma_ctrl = dir;
+		SCSI_DMA_WRITE_P( dma_addr, addr );
+		SCSI_DMA_WRITE_P( dma_cnt, count );
+		tt_scsi_dma.dma_ctrl = dir | 2;
+	}
+	else { /* ! IS_A_TT */
+  
+		/* set address */
+		SCSI_DMA_SETADR( addr );
+
+		/* toggle direction bit to clear FIFO and set DMA direction */
+		dir <<= 8;
+		st_dma.dma_mode_status = 0x90 | dir;
+		st_dma.dma_mode_status = 0x90 | (dir ^ 0x100);
+		st_dma.dma_mode_status = 0x90 | dir;
+		udelay(40);
+		/* On writes, round up the transfer length to the next multiple of 512
+		 * (see also comment at atari_dma_xfer_len()). */
+		st_dma.fdc_acces_seccount = (count + (dir ? 511 : 0)) >> 9;
+		udelay(40);
+		st_dma.dma_mode_status = 0x10 | dir;
+		udelay(40);
+		/* need not restore value of dir, only boolean value is tested */
+		atari_dma_active = 1;
+	}
+
+	return( count );
+}
+
+
+static long atari_scsi_dma_residual( struct Scsi_Host *instance )
+{
+	return( atari_dma_residual );
+}
+
+
+#define	CMD_SURELY_BLOCK_MODE	0
+#define	CMD_SURELY_BYTE_MODE	1
+#define	CMD_MODE_UNKNOWN		2
+
+static int falcon_classify_cmd( Scsi_Cmnd *cmd )
+{
+	unsigned char opcode = cmd->cmnd[0];
+	
+	if (opcode == READ_DEFECT_DATA || opcode == READ_LONG ||
+		opcode == READ_BUFFER)
+		return( CMD_SURELY_BYTE_MODE );
+	else if (opcode == READ_6 || opcode == READ_10 ||
+		 opcode == 0xa8 /* READ_12 */ || opcode == READ_REVERSE ||
+		 opcode == RECOVER_BUFFERED_DATA) {
+		/* In case of a sequential-access target (tape), special care is
+		 * needed here: The transfer is block-mode only if the 'fixed' bit is
+		 * set! */
+		if (cmd->device->type == TYPE_TAPE && !(cmd->cmnd[1] & 1))
+			return( CMD_SURELY_BYTE_MODE );
+		else
+			return( CMD_SURELY_BLOCK_MODE );
+	}
+	else
+		return( CMD_MODE_UNKNOWN );
+}
+
+
+/* This function calculates the number of bytes that can be transferred via
+ * DMA. On the TT, this is arbitrary, but on the Falcon we have to use the
+ * ST-DMA chip. There are only multiples of 512 bytes possible and max.
+ * 255*512 bytes :-( This means also, that defining READ_OVERRUNS is not
+ * possible on the Falcon, since that would require to program the DMA for
+ * n*512 - atari_read_overrun bytes. But it seems that the Falcon doesn't have
+ * the overrun problem, so this question is academic :-)
+ */
+
+static unsigned long atari_dma_xfer_len( unsigned long wanted_len,
+					Scsi_Cmnd *cmd,
+					int write_flag )
+{
+	unsigned long	possible_len, limit;
+#ifndef CONFIG_TT_DMA_EMUL
+	if (MACH_IS_HADES)
+		/* Hades has no SCSI DMA at all :-( Always force use of PIO */
+		return( 0 );
+#endif	
+	if (IS_A_TT())
+		/* TT SCSI DMA can transfer arbitrary #bytes */
+		return( wanted_len );
+
+	/* ST DMA chip is stupid -- only multiples of 512 bytes! (and max.
+	 * 255*512 bytes, but this should be enough)
+	 *
+	 * ++roman: Aaargl! Another Falcon-SCSI problem... There are some commands
+	 * that return a number of bytes which cannot be known beforehand. In this
+	 * case, the given transfer length is an "allocation length". Now it
+	 * can happen that this allocation length is a multiple of 512 bytes and
+	 * the DMA is used. But if not n*512 bytes really arrive, some input data
+	 * will be lost in the ST-DMA's FIFO :-( Thus, we have to distinguish
+	 * between commands that do block transfers and those that do byte
+	 * transfers. But this isn't easy... there are lots of vendor specific
+	 * commands, and the user can issue any command via the
+	 * SCSI_IOCTL_SEND_COMMAND.
+	 *
+	 * The solution: We classify SCSI commands in 1) surely block-mode cmd.s,
+	 * 2) surely byte-mode cmd.s and 3) cmd.s with unknown mode. In case 1)
+	 * and 3), the thing to do is obvious: allow any number of blocks via DMA
+	 * or none. In case 2), we apply some heuristic: Byte mode is assumed if
+	 * the transfer (allocation) length is < 1024, hoping that no cmd. not
+	 * explicitly known as byte mode have such big allocation lengths...
+	 * BTW, all the discussion above applies only to reads. DMA writes are
+	 * unproblematic anyways, since the targets aborts the transfer after
+	 * receiving a sufficient number of bytes.
+	 *
+	 * Another point: If the transfer is from/to an non-ST-RAM address, we
+	 * use the dribble buffer and thus can do only STRAM_BUFFER_SIZE bytes.
+	 */
+
+	if (write_flag) {
+		/* Write operation can always use the DMA, but the transfer size must
+		 * be rounded up to the next multiple of 512 (atari_dma_setup() does
+		 * this).
+		 */
+		possible_len = wanted_len;
+	}
+	else {
+		/* Read operations: if the wanted transfer length is not a multiple of
+		 * 512, we cannot use DMA, since the ST-DMA cannot split transfers
+		 * (no interrupt on DMA finished!)
+		 */
+		if (wanted_len & 0x1ff)
+			possible_len = 0;
+		else {
+			/* Now classify the command (see above) and decide whether it is
+			 * allowed to do DMA at all */
+			switch( falcon_classify_cmd( cmd )) {
+			  case CMD_SURELY_BLOCK_MODE:
+				possible_len = wanted_len;
+				break;
+			  case CMD_SURELY_BYTE_MODE:
+				possible_len = 0; /* DMA prohibited */
+				break;
+			  case CMD_MODE_UNKNOWN:
+			  default:
+				/* For unknown commands assume block transfers if the transfer
+				 * size/allocation length is >= 1024 */
+				possible_len = (wanted_len < 1024) ? 0 : wanted_len;
+				break;
+			}
+		}
+	}
+	
+	/* Last step: apply the hard limit on DMA transfers */
+	limit = (atari_dma_buffer && !STRAM_ADDR( virt_to_phys(cmd->SCp.ptr) )) ?
+		    STRAM_BUFFER_SIZE : 255*512;
+	if (possible_len > limit)
+		possible_len = limit;
+
+	if (possible_len != wanted_len)
+		DMA_PRINTK("Sorry, must cut DMA transfer size to %ld bytes "
+			   "instead of %ld\n", possible_len, wanted_len);
+
+	return( possible_len );
+}
+
+
+#endif	/* REAL_DMA */
+
+
+/* NCR5380 register access functions
+ *
+ * There are separate functions for TT and Falcon, because the access
+ * methods are quite different. The calling macros NCR5380_read and
+ * NCR5380_write call these functions via function pointers.
+ */
+
+static unsigned char atari_scsi_tt_reg_read( unsigned char reg )
+{
+	return( tt_scsi_regp[reg * 2] );
+}
+
+static void atari_scsi_tt_reg_write( unsigned char reg, unsigned char value )
+{
+	tt_scsi_regp[reg * 2] = value;
+}
+
+static unsigned char atari_scsi_falcon_reg_read( unsigned char reg )
+{
+	dma_wd.dma_mode_status= (u_short)(0x88 + reg);
+	return( (u_char)dma_wd.fdc_acces_seccount );
+}
+
+static void atari_scsi_falcon_reg_write( unsigned char reg, unsigned char value )
+{
+	dma_wd.dma_mode_status = (u_short)(0x88 + reg);
+	dma_wd.fdc_acces_seccount = (u_short)value;
+}
+
+
+#include "atari_NCR5380.c"
+
+static Scsi_Host_Template driver_template = {
+	.proc_info		= atari_scsi_proc_info,
+	.name			= "Atari native SCSI",
+	.detect			= atari_scsi_detect,
+	.release		= atari_scsi_release,
+	.info			= atari_scsi_info,
+	.queuecommand		= atari_scsi_queue_command,
+	.eh_abort_handler	= atari_scsi_abort,
+	.eh_bus_reset_handler	= atari_scsi_bus_reset,
+	.can_queue		= 0, /* initialized at run-time */
+	.this_id		= 0, /* initialized at run-time */
+	.sg_tablesize		= 0, /* initialized at run-time */
+	.cmd_per_lun		= 0, /* initialized at run-time */
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
new file mode 100644
index 0000000..cc12569
--- /dev/null
+++ b/drivers/scsi/atari_scsi.h
@@ -0,0 +1,248 @@
+/*
+ * atari_scsi.h -- Header file for the Atari native SCSI driver
+ *
+ * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
+ *
+ * (Loosely based on the work of Robert De Vries' team)
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file COPYING in the main directory of this archive
+ * for more details.
+ *
+ */
+
+
+#ifndef ATARI_SCSI_H
+#define ATARI_SCSI_H
+
+/* (I_HAVE_OVERRUNS stuff removed) */
+
+#ifndef ASM
+int atari_scsi_detect (Scsi_Host_Template *);
+const char *atari_scsi_info (struct Scsi_Host *);
+int atari_scsi_reset (Scsi_Cmnd *, unsigned int);
+#ifdef MODULE
+int atari_scsi_release (struct Scsi_Host *);
+#else
+#define atari_scsi_release NULL
+#endif
+
+/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
+ * values should work, too; try it! (but cmd_per_lun costs memory!) */
+
+/* But there seems to be a bug somewhere that requires CAN_QUEUE to be
+ * 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
+ * changed CMD_PER_LUN... */
+
+/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
+ * cmd_per_lun != 1 */
+
+#define ATARI_TT_CAN_QUEUE		16
+#define ATARI_TT_CMD_PER_LUN		8
+#define ATARI_TT_SG_TABLESIZE		SG_ALL
+
+#define ATARI_FALCON_CAN_QUEUE		8
+#define ATARI_FALCON_CMD_PER_LUN	1
+#define ATARI_FALCON_SG_TABLESIZE	SG_NONE
+
+#define	DEFAULT_USE_TAGGED_QUEUING	0
+
+
+#define	NCR5380_implementation_fields	/* none */
+
+#define NCR5380_read(reg)		  atari_scsi_reg_read( reg )
+#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value )
+
+#define NCR5380_intr atari_scsi_intr
+#define NCR5380_queue_command atari_scsi_queue_command
+#define NCR5380_abort atari_scsi_abort
+#define NCR5380_proc_info atari_scsi_proc_info
+#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0)
+#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1)
+#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst )
+#define	NCR5380_dma_xfer_len(i,cmd,phase) \
+	atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+/* Debugging printk definitions:
+ *
+ *  ARB  -> arbitration
+ *  ASEN -> auto-sense
+ *  DMA  -> DMA
+ *  HSH  -> PIO handshake
+ *  INF  -> information transfer
+ *  INI  -> initialization
+ *  INT  -> interrupt
+ *  LNK  -> linked commands
+ *  MAIN -> NCR5380_main() control flow
+ *  NDAT -> no data-out phase
+ *  NWR  -> no write commands
+ *  PIO  -> PIO transfers
+ *  PDMA -> pseudo DMA (unused on Atari)
+ *  QU   -> queues
+ *  RSL  -> reselections
+ *  SEL  -> selections
+ *  USL  -> usleep cpde (unused on Atari)
+ *  LBS  -> last byte sent (unused on Atari)
+ *  RSS  -> restarting of selections
+ *  EXT  -> extended messages
+ *  ABRT -> aborting and resetting
+ *  TAG  -> queue tag handling
+ *  MER  -> merging of consec. buffers
+ *
+ */
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask)	\
+	((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+
+#endif /* ndef ASM */
+#endif /* ATARI_SCSI_H */
+
+
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
new file mode 100644
index 0000000..45b75dda
--- /dev/null
+++ b/drivers/scsi/atp870u.c
@@ -0,0 +1,3970 @@
+/* 
+ *  Copyright (C) 1997	Wu Ching Chen
+ *  2.1.x update (C) 1998  Krzysztof G. Baranowski
+ *  2.5.x update (C) 2002  Red Hat <alan@redhat.com>
+ *  2.6.x update (C) 2004  Red Hat <alan@redhat.com>
+ *
+ * Marcelo Tosatti <marcelo@conectiva.com.br> : SMP fixes
+ *
+ * Wu Ching Chen : NULL pointer fixes  2000/06/02
+ *		   support atp876 chip
+ *		   enable 32 bit fifo transfer
+ *		   support cdrom & remove device run ultra speed
+ *		   fix disconnect bug  2000/12/21
+ *		   support atp880 chip lvd u160 2001/05/15
+ *		   fix prd table bug 2001/09/12 (7.1)
+ *
+ * atp885 support add by ACARD Hao Ping Lian 2005/01/05
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "atp870u.h"
+
+static struct scsi_host_template atp870u_template;
+static void send_s870(struct atp_unit *dev,unsigned char c);
+static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c);
+static void tscam_885(void);
+
+static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	unsigned short int tmpcip, id;
+	unsigned char i, j, c, target_id, lun,cmdp;
+	unsigned char *prd;
+	struct scsi_cmnd *workreq;
+	unsigned int workport, tmport, tmport1;
+	unsigned long adrcnt, k;
+#ifdef ED_DBGP
+	unsigned long l;
+#endif
+	int errstus;
+	struct Scsi_Host *host = dev_id;
+	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
+
+	for (c = 0; c < 2; c++) {
+		tmport = dev->ioport[c] + 0x1f;
+		j = inb(tmport);
+		if ((j & 0x80) != 0)
+		{			
+	   		goto ch_sel;
+		}
+		dev->in_int[c] = 0;
+	}
+	return IRQ_NONE;
+ch_sel:
+#ifdef ED_DBGP	
+	printk("atp870u_intr_handle enter\n");
+#endif	
+	dev->in_int[c] = 1;
+	cmdp = inb(dev->ioport[c] + 0x10);
+	workport = dev->ioport[c];
+	if (dev->working[c] != 0) {
+		if (dev->dev_id == ATP885_DEVID) {
+			tmport1 = workport + 0x16;
+			if ((inb(tmport1) & 0x80) == 0)
+				outb((inb(tmport1) | 0x80), tmport1);
+		}		
+		tmpcip = dev->pciport[c];
+		if ((inb(tmpcip) & 0x08) != 0)
+		{
+			tmpcip += 0x2;
+			for (k=0; k < 1000; k++) {
+				if ((inb(tmpcip) & 0x08) == 0) {
+					goto stop_dma;
+				}
+				if ((inb(tmpcip) & 0x01) == 0) {
+					goto stop_dma;
+				}
+			}
+		}
+stop_dma:
+		tmpcip = dev->pciport[c];
+		outb(0x00, tmpcip);
+		tmport -= 0x08;
+		
+		i = inb(tmport);
+		
+		if (dev->dev_id == ATP885_DEVID) {
+			tmpcip += 2;
+			outb(0x06, tmpcip);
+			tmpcip -= 2;
+		}
+
+		tmport -= 0x02;
+		target_id = inb(tmport);
+		tmport += 0x02;
+
+		/*
+		 *	Remap wide devices onto id numbers
+		 */
+
+		if ((target_id & 0x40) != 0) {
+			target_id = (target_id & 0x07) | 0x08;
+		} else {
+			target_id &= 0x07;
+		}
+
+		if ((j & 0x40) != 0) {
+		     if (dev->last_cmd[c] == 0xff) {
+			dev->last_cmd[c] = target_id;
+		     }
+		     dev->last_cmd[c] |= 0x40;
+		}
+		if (dev->dev_id == ATP885_DEVID) 
+			dev->r1f[c][target_id] |= j;
+#ifdef ED_DBGP
+		printk("atp870u_intr_handle status = %x\n",i);
+#endif	
+		if (i == 0x85) {
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
+			}
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport -= 0x05;
+				adrcnt = 0;
+				((unsigned char *) &adrcnt)[2] = inb(tmport++);
+				((unsigned char *) &adrcnt)[1] = inb(tmport++);
+				((unsigned char *) &adrcnt)[0] = inb(tmport);
+				if (dev->id[c][target_id].last_len != adrcnt)
+				{
+			   		k = dev->id[c][target_id].last_len;
+			   		k -= adrcnt;
+			   		dev->id[c][target_id].tran_len = k;			   
+			   	dev->id[c][target_id].last_len = adrcnt;			   
+				}
+#ifdef ED_DBGP
+				printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len);
+#endif		
+			}
+
+			/*
+			 *      Flip wide
+			 */			
+			if (dev->wide_id[c] != 0) {
+				tmport = workport + 0x1b;
+				outb(0x01, tmport);
+				while ((inb(tmport) & 0x01) != 0x01) {
+					outb(0x01, tmport);
+				}
+			}		
+			/*
+			 *	Issue more commands
+			 */
+			spin_lock_irqsave(dev->host->host_lock, flags);			 			 
+			if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) &&
+			    (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+				printk("Call sent_s870\n");
+#endif				
+				send_s870(dev,c);
+			}
+			spin_unlock_irqrestore(dev->host->host_lock, flags);
+			/*
+			 *	Done
+			 */
+			dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("Status 0x85 return\n");
+#endif				
+			goto handled;
+		}
+
+		if (i == 0x40) {
+		     dev->last_cmd[c] |= 0x40;
+		     dev->in_int[c] = 0;
+		     goto handled;
+		}
+
+		if (i == 0x21) {
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
+			}
+			tmport -= 0x05;
+			adrcnt = 0;
+			((unsigned char *) &adrcnt)[2] = inb(tmport++);
+			((unsigned char *) &adrcnt)[1] = inb(tmport++);
+			((unsigned char *) &adrcnt)[0] = inb(tmport);
+			k = dev->id[c][target_id].last_len;
+			k -= adrcnt;
+			dev->id[c][target_id].tran_len = k;
+			dev->id[c][target_id].last_len = adrcnt;
+			tmport -= 0x04;
+			outb(0x41, tmport);
+			tmport += 0x08;
+			outb(0x08, tmport);
+			dev->in_int[c] = 0;
+			goto handled;
+		}
+
+		if (dev->dev_id == ATP885_DEVID) {
+			if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) {
+		   		if ((i == 0x4c) || (i == 0x8c)) 
+		      			i=0x48;
+		   		else 
+		      			i=0x49;
+		   	}	
+			
+		}
+		if ((i == 0x80) || (i == 0x8f)) {
+#ifdef ED_DBGP
+			printk(KERN_DEBUG "Device reselect\n");
+#endif			
+			lun = 0;
+			tmport -= 0x07;
+			if (cmdp == 0x44 || i==0x80) {
+				tmport += 0x0d;
+				lun = inb(tmport) & 0x07;
+			} else {
+				if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+				   dev->last_cmd[c] = 0xff;
+				}
+				if (cmdp == 0x41) {
+#ifdef ED_DBGP
+					printk("cmdp = 0x41\n");
+#endif						
+					tmport += 0x02;
+					adrcnt = 0;
+					((unsigned char *) &adrcnt)[2] = inb(tmport++);
+					((unsigned char *) &adrcnt)[1] = inb(tmport++);
+					((unsigned char *) &adrcnt)[0] = inb(tmport);
+					k = dev->id[c][target_id].last_len;
+					k -= adrcnt;
+					dev->id[c][target_id].tran_len = k;
+					dev->id[c][target_id].last_len = adrcnt;
+					tmport += 0x04;
+					outb(0x08, tmport);
+					dev->in_int[c] = 0;
+					goto handled;
+				} else {
+#ifdef ED_DBGP
+					printk("cmdp != 0x41\n");
+#endif						
+					outb(0x46, tmport);
+					dev->id[c][target_id].dirct = 0x00;
+					tmport += 0x02;
+					outb(0x00, tmport++);
+					outb(0x00, tmport++);
+					outb(0x00, tmport++);
+					tmport += 0x03;
+					outb(0x08, tmport);
+					dev->in_int[c] = 0;
+					goto handled;
+				}
+			}
+			if (dev->last_cmd[c] != 0xff) {
+			   dev->last_cmd[c] |= 0x40;
+			}
+			if (dev->dev_id == ATP885_DEVID) {
+				j = inb(dev->baseport + 0x29) & 0xfe;
+				outb(j, dev->baseport + 0x29);
+				tmport = workport + 0x16;
+			} else {
+				tmport = workport + 0x10;
+				outb(0x45, tmport);
+				tmport += 0x06;				
+			}
+			
+			target_id = inb(tmport);
+			/*
+			 *	Remap wide identifiers
+			 */
+			if ((target_id & 0x10) != 0) {
+				target_id = (target_id & 0x07) | 0x08;
+			} else {
+				target_id &= 0x07;
+			}
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport = workport + 0x10;
+				outb(0x45, tmport);
+			}
+			workreq = dev->id[c][target_id].curr_req;
+#ifdef ED_DBGP			
+			printk(KERN_DEBUG "Channel = %d ID = %d LUN = %d CDB",c,workreq->device->id,workreq->device->lun);
+			for(l=0;l<workreq->cmd_len;l++)
+			{
+				printk(KERN_DEBUG " %x",workreq->cmnd[l]);
+			}
+#endif	
+			
+			tmport = workport + 0x0f;
+			outb(lun, tmport);
+			tmport += 0x02;
+			outb(dev->id[c][target_id].devsp, tmport++);
+			adrcnt = dev->id[c][target_id].tran_len;
+			k = dev->id[c][target_id].last_len;
+
+			outb(((unsigned char *) &k)[2], tmport++);
+			outb(((unsigned char *) &k)[1], tmport++);
+			outb(((unsigned char *) &k)[0], tmport++);
+#ifdef ED_DBGP			
+			printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3));
+#endif			
+			/* Remap wide */
+			j = target_id;
+			if (target_id > 7) {
+				j = (j & 0x07) | 0x40;
+			}
+			/* Add direction */
+			j |= dev->id[c][target_id].dirct;
+			outb(j, tmport++);
+			outb(0x80,tmport);
+			
+			/* enable 32 bit fifo transfer */	
+			if (dev->dev_id == ATP885_DEVID) {
+				tmpcip = dev->pciport[c] + 1;
+				i=inb(tmpcip) & 0xf3;
+				//j=workreq->cmnd[0];	    		    	
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+				   i |= 0x0c;
+				}
+				outb(i,tmpcip);		    		    		
+			} else if ((dev->dev_id == ATP880_DEVID1) ||
+	    		    	   (dev->dev_id == ATP880_DEVID2) ) {
+				tmport = workport - 0x05;
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+					outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
+				} else {
+					outb((unsigned char) (inb(tmport) & 0x3f), tmport);
+				}
+			} else {				
+				tmport = workport + 0x3a;
+				if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+					outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport);
+				} else {
+					outb((unsigned char) (inb(tmport) & 0xf3), tmport);
+				}														
+			}	
+			tmport = workport + 0x1b;
+			j = 0;
+			id = 1;
+			id = id << target_id;
+			/*
+			 *	Is this a wide device
+			 */
+			if ((id & dev->wide_id[c]) != 0) {
+				j |= 0x01;
+			}
+			outb(j, tmport);
+			while ((inb(tmport) & 0x01) != j) {
+				outb(j,tmport);
+			}
+			if (dev->id[c][target_id].last_len == 0) {
+				tmport = workport + 0x18;
+				outb(0x08, tmport);
+				dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("dev->id[c][target_id].last_len = 0\n");
+#endif					
+				goto handled;
+			}
+#ifdef ED_DBGP
+			printk("target_id = %d adrcnt = %d\n",target_id,adrcnt);
+#endif			
+			prd = dev->id[c][target_id].prd_pos;
+			while (adrcnt != 0) {
+				id = ((unsigned short int *)prd)[2];
+				if (id == 0) {
+					k = 0x10000;
+				} else {
+					k = id;
+				}
+				if (k > adrcnt) {
+					((unsigned short int *)prd)[2] = (unsigned short int)
+					    (k - adrcnt);
+					((unsigned long *)prd)[0] += adrcnt;
+					adrcnt = 0;
+					dev->id[c][target_id].prd_pos = prd;
+				} else {
+					adrcnt -= k;
+					dev->id[c][target_id].prdaddr += 0x08;
+					prd += 0x08;
+					if (adrcnt == 0) {
+						dev->id[c][target_id].prd_pos = prd;
+					}
+				}				
+			}
+			tmpcip = dev->pciport[c] + 0x04;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
+#ifdef ED_DBGP
+			printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr);
+#endif
+			if (dev->dev_id == ATP885_DEVID) {
+				tmpcip -= 0x04;
+			} else {
+				tmpcip -= 0x02;
+				outb(0x06, tmpcip);
+				outb(0x00, tmpcip);
+				tmpcip -= 0x02;
+			}
+			tmport = workport + 0x18;
+			/*
+			 *	Check transfer direction
+			 */
+			if (dev->id[c][target_id].dirct != 0) {
+				outb(0x08, tmport);
+				outb(0x01, tmpcip);
+				dev->in_int[c] = 0;
+#ifdef ED_DBGP
+				printk("status 0x80 return dirct != 0\n");
+#endif				
+				goto handled;
+			}
+			outb(0x08, tmport);
+			outb(0x09, tmpcip);
+			dev->in_int[c] = 0;
+#ifdef ED_DBGP
+			printk("status 0x80 return dirct = 0\n");
+#endif			
+			goto handled;
+		}
+
+		/*
+		 *	Current scsi request on this target
+		 */
+
+		workreq = dev->id[c][target_id].curr_req;
+
+		if (i == 0x42) {
+			if ((dev->last_cmd[c] & 0xf0) != 0x40)
+			{
+			   dev->last_cmd[c] = 0xff;
+			}
+			errstus = 0x02;
+			workreq->result = errstus;
+			goto go_42;
+		}
+		if (i == 0x16) {
+			if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+			   dev->last_cmd[c] = 0xff;
+			}
+			errstus = 0;
+			tmport -= 0x08;
+			errstus = inb(tmport);
+			if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) {
+			   printk(KERN_WARNING "AEC67162 CRC ERROR !\n");
+			   errstus = 0x02;
+			}
+			workreq->result = errstus;
+go_42:
+			if (dev->dev_id == ATP885_DEVID) {		
+				j = inb(dev->baseport + 0x29) | 0x01;
+				outb(j, dev->baseport + 0x29);
+			}
+			/*
+			 *	Complete the command
+			 */
+			if (workreq->use_sg) {
+				pci_unmap_sg(dev->pdev,
+					(struct scatterlist *)workreq->buffer,
+					workreq->use_sg,
+					workreq->sc_data_direction);
+			} else if (workreq->request_bufflen &&
+					workreq->sc_data_direction != DMA_NONE) {
+				pci_unmap_single(dev->pdev,
+					workreq->SCp.dma_handle,
+					workreq->request_bufflen,
+					workreq->sc_data_direction);
+			}			
+			spin_lock_irqsave(dev->host->host_lock, flags);
+			(*workreq->scsi_done) (workreq);
+#ifdef ED_DBGP
+			   printk("workreq->scsi_done\n");
+#endif	
+			/*
+			 *	Clear it off the queue
+			 */
+			dev->id[c][target_id].curr_req = NULL;
+			dev->working[c]--;
+			spin_unlock_irqrestore(dev->host->host_lock, flags);
+			/*
+			 *      Take it back wide
+			 */
+			if (dev->wide_id[c] != 0) {
+				tmport = workport + 0x1b;
+				outb(0x01, tmport);
+				while ((inb(tmport) & 0x01) != 0x01) {
+					outb(0x01, tmport);
+				}       
+			} 
+			/*
+			 *	If there is stuff to send and nothing going then send it
+			 */
+			spin_lock_irqsave(dev->host->host_lock, flags);
+			if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) &&
+			    (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+			   printk("Call sent_s870(scsi_done)\n");
+#endif				   
+			   send_s870(dev,c);
+			}
+			spin_unlock_irqrestore(dev->host->host_lock, flags);
+			dev->in_int[c] = 0;
+			goto handled;
+		}
+		if ((dev->last_cmd[c] & 0xf0) != 0x40) {
+		   dev->last_cmd[c] = 0xff;
+		}
+		if (i == 0x4f) {
+			i = 0x89;
+		}
+		i &= 0x0f;
+		if (i == 0x09) {
+			tmpcip += 4;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
+			tmpcip = tmpcip - 2;
+			outb(0x06, tmpcip);
+			outb(0x00, tmpcip);
+			tmpcip = tmpcip - 2;
+			tmport = workport + 0x10;
+			outb(0x41, tmport);
+			if (dev->dev_id == ATP885_DEVID) {
+				tmport += 2;
+				k = dev->id[c][target_id].last_len;
+				outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[0]), tmport);
+				dev->id[c][target_id].dirct = 0x00;
+				tmport += 0x04;
+			} else {
+				dev->id[c][target_id].dirct = 0x00;
+				tmport += 0x08;				
+			}
+			outb(0x08, tmport);
+			outb(0x09, tmpcip);
+			dev->in_int[c] = 0;
+			goto handled;
+		}
+		if (i == 0x08) {
+			tmpcip += 4;
+			outl(dev->id[c][target_id].prdaddr, tmpcip);
+			tmpcip = tmpcip - 2;
+			outb(0x06, tmpcip);
+			outb(0x00, tmpcip);
+			tmpcip = tmpcip - 2;
+			tmport = workport + 0x10;
+			outb(0x41, tmport);
+			if (dev->dev_id == ATP885_DEVID) {		
+				tmport += 2;
+				k = dev->id[c][target_id].last_len;
+				outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++);
+				outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++);
+			} else {
+				tmport += 5;
+			}
+			outb((unsigned char) (inb(tmport) | 0x20), tmport);
+			dev->id[c][target_id].dirct = 0x20;
+			tmport += 0x03;
+			outb(0x08, tmport);
+			outb(0x01, tmpcip);
+			dev->in_int[c] = 0;
+			goto handled;
+		}
+		tmport -= 0x07;
+		if (i == 0x0a) {
+			outb(0x30, tmport);
+		} else {
+			outb(0x46, tmport);
+		}
+		dev->id[c][target_id].dirct = 0x00;
+		tmport += 0x02;
+		outb(0x00, tmport++);
+		outb(0x00, tmport++);
+		outb(0x00, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		dev->in_int[c] = 0;
+		goto handled;
+	} else {
+//		tmport = workport + 0x17;
+//		inb(tmport);
+//		dev->working[c] = 0;
+		dev->in_int[c] = 0;
+		goto handled;
+	}
+	
+handled:
+#ifdef ED_DBGP
+	printk("atp870u_intr_handle exit\n");
+#endif			
+	return IRQ_HANDLED;
+}
+/**
+ *	atp870u_queuecommand	-	Queue SCSI command
+ *	@req_p: request block
+ *	@done: completion function
+ *
+ *	Queue a command to the ATP queue. Called with the host lock held.
+ */
+static int atp870u_queuecommand(struct scsi_cmnd * req_p, 
+			 void (*done) (struct scsi_cmnd *))
+{
+	unsigned char c;
+	unsigned int tmport,m;	
+	struct atp_unit *dev;
+	struct Scsi_Host *host;
+
+	c = req_p->device->channel;	
+	req_p->sense_buffer[0]=0;
+	req_p->resid = 0;
+	if (req_p->device->channel > 1) {
+		req_p->result = 0x00040000;
+		done(req_p);
+#ifdef ED_DBGP		
+		printk("atp870u_queuecommand : req_p->device->channel > 1\n");	
+#endif			
+		return 0;
+	}
+
+	host = req_p->device->host;
+	dev = (struct atp_unit *)&host->hostdata;
+		
+
+		
+	m = 1;
+	m = m << req_p->device->id;
+
+	/*
+	 *      Fake a timeout for missing targets
+	 */
+
+	if ((m & dev->active_id[c]) == 0) {
+		req_p->result = 0x00040000;
+		done(req_p);
+		return 0;
+	}
+
+	if (done) {
+		req_p->scsi_done = done;
+	} else {
+#ifdef ED_DBGP		
+		printk( "atp870u_queuecommand: done can't be NULL\n");
+#endif		
+		req_p->result = 0;
+		done(req_p);
+		return 0;
+	}
+	
+	/*
+	 *	Count new command
+	 */
+	dev->quend[c]++;
+	if (dev->quend[c] >= qcnt) {
+		dev->quend[c] = 0;
+	}
+	
+	/*
+	 *	Check queue state
+	 */
+	if (dev->quhd[c] == dev->quend[c]) {
+		if (dev->quend[c] == 0) {
+			dev->quend[c] = qcnt;
+		}
+#ifdef ED_DBGP		
+		printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n");
+#endif		
+		dev->quend[c]--;
+		req_p->result = 0x00020000;
+		done(req_p);	
+		return 0;
+	}
+	dev->quereq[c][dev->quend[c]] = req_p;
+	tmport = dev->ioport[c] + 0x1c;
+#ifdef ED_DBGP	
+	printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]);
+#endif
+	if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) {
+#ifdef ED_DBGP
+		printk("Call sent_s870(atp870u_queuecommand)\n");
+#endif		
+		send_s870(dev,c);
+	}
+#ifdef ED_DBGP	
+	printk("atp870u_queuecommand : exit\n");
+#endif	
+	return 0;
+}
+
+/**
+ *	send_s870	-	send a command to the controller
+ *	@host: host
+ *
+ *	On entry there is work queued to be done. We move some of that work to the
+ *	controller itself. 
+ *
+ *	Caller holds the host lock.
+ */
+static void send_s870(struct atp_unit *dev,unsigned char c)
+{
+	unsigned int tmport;
+	struct scsi_cmnd *workreq;
+	unsigned int i;//,k;
+	unsigned char  j, target_id;
+	unsigned char *prd;
+	unsigned short int tmpcip, w;
+	unsigned long l, bttl = 0;
+	unsigned int workport;
+	struct scatterlist *sgpnt;
+	unsigned long  sg_count;
+
+	if (dev->in_snd[c] != 0) {
+#ifdef ED_DBGP		
+		printk("cmnd in_snd\n");
+#endif
+		return;
+	}
+#ifdef ED_DBGP
+	printk("Sent_s870 enter\n");
+#endif
+	dev->in_snd[c] = 1;
+	if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) {
+		dev->last_cmd[c] &= 0x0f;
+		workreq = dev->id[c][dev->last_cmd[c]].curr_req;
+		if (workreq != NULL) {	/* check NULL pointer */
+		   goto cmd_subp;
+		}
+		dev->last_cmd[c] = 0xff;	
+		if (dev->quhd[c] == dev->quend[c]) {
+		   	dev->in_snd[c] = 0;
+		   	return ;
+		}
+	}
+	if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) {
+	     	dev->in_snd[c] = 0;
+	     	return ;
+	}
+	dev->working[c]++;
+	j = dev->quhd[c];
+	dev->quhd[c]++;
+	if (dev->quhd[c] >= qcnt) {
+		dev->quhd[c] = 0;
+	}
+	workreq = dev->quereq[c][dev->quhd[c]];
+	if (dev->id[c][workreq->device->id].curr_req == 0) {	
+		dev->id[c][workreq->device->id].curr_req = workreq;
+		dev->last_cmd[c] = workreq->device->id;
+		goto cmd_subp;
+	}	
+	dev->quhd[c] = j;
+	dev->working[c]--;
+	dev->in_snd[c] = 0;
+	return;
+cmd_subp:
+	workport = dev->ioport[c];
+	tmport = workport + 0x1f;
+	if ((inb(tmport) & 0xb0) != 0) {
+		goto abortsnd;
+	}
+	tmport = workport + 0x1c;
+	if (inb(tmport) == 0) {
+		goto oktosend;
+	}
+abortsnd:
+#ifdef ED_DBGP
+	printk("Abort to Send\n");
+#endif
+	dev->last_cmd[c] |= 0x40;
+	dev->in_snd[c] = 0;
+	return;
+oktosend:
+#ifdef ED_DBGP
+	printk("OK to Send\n");
+	printk("CDB");
+	for(i=0;i<workreq->cmd_len;i++) {
+		printk(" %x",workreq->cmnd[i]);
+	}
+	printk("\nChannel = %d ID = %d LUN = %d\n",c,workreq->device->id,workreq->device->lun);
+#endif	
+	if (dev->dev_id == ATP885_DEVID) {
+		j = inb(dev->baseport + 0x29) & 0xfe;
+		outb(j, dev->baseport + 0x29);
+		dev->r1f[c][workreq->device->id] = 0;
+	}
+	
+	if (workreq->cmnd[0] == READ_CAPACITY) {
+		if (workreq->request_bufflen > 8) {
+			workreq->request_bufflen = 0x08;
+		}
+	}
+	if (workreq->cmnd[0] == 0x00) {
+		workreq->request_bufflen = 0;
+	}
+
+	tmport = workport + 0x1b;
+	j = 0;
+	target_id = workreq->device->id;
+
+	/*
+	 *	Wide ?
+	 */
+	w = 1;
+	w = w << target_id;
+	if ((w & dev->wide_id[c]) != 0) {
+		j |= 0x01;
+	}
+	outb(j, tmport);
+	while ((inb(tmport) & 0x01) != j) {
+		outb(j,tmport);
+#ifdef ED_DBGP
+		printk("send_s870 while loop 1\n");
+#endif
+	}
+	/*
+	 *	Write the command
+	 */
+
+	tmport = workport;
+	outb(workreq->cmd_len, tmport++);
+	outb(0x2c, tmport++);
+	if (dev->dev_id == ATP885_DEVID) {
+		outb(0x7f, tmport++);
+	} else {
+		outb(0xcf, tmport++); 	
+	}	
+	for (i = 0; i < workreq->cmd_len; i++) {
+		outb(workreq->cmnd[i], tmport++);
+	}
+	tmport = workport + 0x0f;
+	outb(workreq->device->lun, tmport);
+	tmport += 0x02;
+	/*
+	 *	Write the target
+	 */
+	outb(dev->id[c][target_id].devsp, tmport++);	 
+#ifdef ED_DBGP	
+	printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp);
+#endif
+	/*
+	 *	Figure out the transfer size
+	 */
+	if (workreq->use_sg) {
+#ifdef ED_DBGP
+		printk("Using SGL\n");
+#endif		
+		l = 0;
+		
+		sgpnt = (struct scatterlist *) workreq->request_buffer;
+		sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg,
+	   			workreq->sc_data_direction);		
+		
+		for (i = 0; i < workreq->use_sg; i++) {
+			if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) {
+				panic("Foooooooood fight!");
+			}
+			l += sgpnt[i].length;
+		}
+#ifdef ED_DBGP		
+		printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l);
+#endif
+	} else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) {
+#ifdef ED_DBGP
+		printk("Not using SGL\n");
+#endif					
+		workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer,
+				workreq->request_bufflen,
+				workreq->sc_data_direction);		
+		l = workreq->request_bufflen;
+#ifdef ED_DBGP		
+		printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l);
+#endif
+	} else l = 0;
+	/*
+	 *	Write transfer size
+	 */
+	outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++);
+	outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++);
+	outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++);
+	j = target_id;	
+	dev->id[c][j].last_len = l;
+	dev->id[c][j].tran_len = 0;
+#ifdef ED_DBGP	
+	printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len);
+#endif	
+	/*
+	 *	Flip the wide bits
+	 */
+	if ((j & 0x08) != 0) {
+		j = (j & 0x07) | 0x40;
+	}
+	/*
+	 *	Check transfer direction
+	 */
+	if (workreq->sc_data_direction == DMA_TO_DEVICE) {
+		outb((unsigned char) (j | 0x20), tmport++);
+	} else {
+		outb(j, tmport++);
+	}
+	outb((unsigned char) (inb(tmport) | 0x80), tmport);
+	outb(0x80, tmport);
+	tmport = workport + 0x1c;
+	dev->id[c][target_id].dirct = 0;
+	if (l == 0) {
+		if (inb(tmport) == 0) {
+			tmport = workport + 0x18;
+#ifdef ED_DBGP
+			printk("change SCSI_CMD_REG 0x08\n");	
+#endif				
+			outb(0x08, tmport);
+		} else {
+			dev->last_cmd[c] |= 0x40;
+		}
+		dev->in_snd[c] = 0;
+		return;
+	}
+	tmpcip = dev->pciport[c];
+	prd = dev->id[c][target_id].prd_table;
+	dev->id[c][target_id].prd_pos = prd;
+
+	/*
+	 *	Now write the request list. Either as scatter/gather or as
+	 *	a linear chain.
+	 */
+
+	if (workreq->use_sg) {
+		sgpnt = (struct scatterlist *) workreq->request_buffer;
+		i = 0;
+		for (j = 0; j < workreq->use_sg; j++) {
+			bttl = sg_dma_address(&sgpnt[j]);
+			l=sg_dma_len(&sgpnt[j]);
+#ifdef ED_DBGP		
+		printk("1. bttl %x, l %x\n",bttl, l);
+#endif			
+		while (l > 0x10000) {
+				(((u16 *) (prd))[i + 3]) = 0x0000;
+				(((u16 *) (prd))[i + 2]) = 0x0000;
+				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+				l -= 0x10000;
+				bttl += 0x10000;
+				i += 0x04;
+			}
+			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
+			(((u16 *) (prd))[i + 3]) = 0;
+			i += 0x04;			
+		}
+		(((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000);	
+#ifdef ED_DBGP		
+		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+		printk("2. bttl %x, l %x\n",bttl, l);
+#endif			
+	} else {
+		/*
+		 *	For a linear request write a chain of blocks
+		 */        
+		bttl = workreq->SCp.dma_handle;
+		l = workreq->request_bufflen;
+		i = 0;
+#ifdef ED_DBGP		
+		printk("3. bttl %x, l %x\n",bttl, l);
+#endif			
+		while (l > 0x10000) {
+				(((u16 *) (prd))[i + 3]) = 0x0000;
+				(((u16 *) (prd))[i + 2]) = 0x0000;
+				(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);
+				l -= 0x10000;
+				bttl += 0x10000;
+				i += 0x04;
+			}
+			(((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000);
+			(((u16 *) (prd))[i + 2]) = cpu_to_le16(l);
+			(((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl);		
+#ifdef ED_DBGP		
+		printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3]));
+		printk("4. bttl %x, l %x\n",bttl, l);
+#endif			
+		
+	}
+	tmpcip += 4;
+#ifdef ED_DBGP		
+	printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id);
+#endif	
+	outl(dev->id[c][target_id].prdaddr, tmpcip);
+	tmpcip = tmpcip - 2;
+	outb(0x06, tmpcip);
+	outb(0x00, tmpcip);
+	if (dev->dev_id == ATP885_DEVID) {
+		tmpcip--;
+		j=inb(tmpcip) & 0xf3;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) ||
+	    	(workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+	   		j |= 0x0c;
+		}
+		outb(j,tmpcip);
+		tmpcip--;	    	
+	} else if ((dev->dev_id == ATP880_DEVID1) ||
+	    	   (dev->dev_id == ATP880_DEVID2)) {
+		tmpcip =tmpcip -2;	
+		tmport = workport - 0x05;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+			outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport);
+		} else {
+			outb((unsigned char) (inb(tmport) & 0x3f), tmport);
+		}		
+	} else {		
+		tmpcip =tmpcip -2;
+		tmport = workport + 0x3a;
+		if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) {
+			outb((inb(tmport) & 0xf3) | 0x08, tmport);
+		} else {
+			outb(inb(tmport) & 0xf3, tmport);
+		}		
+	}	
+	tmport = workport + 0x1c;
+
+	if(workreq->sc_data_direction == DMA_TO_DEVICE) {
+		dev->id[c][target_id].dirct = 0x20;
+		if (inb(tmport) == 0) {
+			tmport = workport + 0x18;
+			outb(0x08, tmport);
+			outb(0x01, tmpcip);
+#ifdef ED_DBGP		
+		printk( "start DMA(to target)\n");
+#endif				
+		} else {
+			dev->last_cmd[c] |= 0x40;
+		}
+		dev->in_snd[c] = 0;
+		return;
+	}
+	if (inb(tmport) == 0) {		
+		tmport = workport + 0x18;
+		outb(0x08, tmport);
+		outb(0x09, tmpcip);
+#ifdef ED_DBGP		
+		printk( "start DMA(to host)\n");
+#endif			
+	} else {
+		dev->last_cmd[c] |= 0x40;
+	}
+	dev->in_snd[c] = 0;
+	return;
+
+}
+
+static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val)
+{
+	unsigned int tmport;
+	unsigned short int i, k;
+	unsigned char j;
+
+	tmport = dev->ioport[0] + 0x1c;
+	outw(*val, tmport);
+FUN_D7:
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
+		k = inw(tmport);
+		j = (unsigned char) (k >> 8);
+		if ((k & 0x8000) != 0) {	/* DB7 all release?    */
+			goto FUN_D7;
+		}
+	}
+	*val |= 0x4000;		/* assert DB6           */
+	outw(*val, tmport);
+	*val &= 0xdfff;		/* assert DB5           */
+	outw(*val, tmport);
+FUN_D5:
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns) */
+		if ((inw(tmport) & 0x2000) != 0) {	/* DB5 all release?       */
+			goto FUN_D5;
+		}
+	}
+	*val |= 0x8000;		/* no DB4-0, assert DB7    */
+	*val &= 0xe0ff;
+	outw(*val, tmport);
+	*val &= 0xbfff;		/* release DB6             */
+	outw(*val, tmport);
+FUN_D6:
+	for (i = 0; i < 10; i++) {	/* stable >= bus settle delay(400 ns)  */
+		if ((inw(tmport) & 0x4000) != 0) {	/* DB6 all release?  */
+			goto FUN_D6;
+		}
+	}
+
+	return j;
+}
+
+static void tscam(struct Scsi_Host *host)
+{
+
+	unsigned int tmport;
+	unsigned char i, j, k;
+	unsigned long n;
+	unsigned short int m, assignid_map, val;
+	unsigned char mbuf[33], quintet[2];
+	struct atp_unit *dev = (struct atp_unit *)&host->hostdata;
+	static unsigned char g2q_tab[8] = {
+		0x38, 0x31, 0x32, 0x2b, 0x34, 0x2d, 0x2e, 0x27
+	};
+
+/*  I can't believe we need this before we've even done anything.  Remove it
+ *  and see if anyone bitches.
+	for (i = 0; i < 0x10; i++) {
+		udelay(0xffff);
+	}
+ */
+
+	tmport = dev->ioport[0] + 1;
+	outb(0x08, tmport++);
+	outb(0x7f, tmport);
+	tmport = dev->ioport[0] + 0x11;
+	outb(0x20, tmport);
+
+	if ((dev->scam_on & 0x40) == 0) {
+		return;
+	}
+	m = 1;
+	m <<= dev->host_id[0];
+	j = 16;
+	if (dev->chip_ver < 4) {
+		m |= 0xff00;
+		j = 8;
+	}
+	assignid_map = m;
+	tmport = dev->ioport[0] + 0x02;
+	outb(0x02, tmport++);	/* 2*2=4ms,3EH 2/32*3E=3.9ms */
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+	outb(0, tmport++);
+
+	for (i = 0; i < j; i++) {
+		m = 1;
+		m = m << i;
+		if ((m & assignid_map) != 0) {
+			continue;
+		}
+		tmport = dev->ioport[0] + 0x0f;
+		outb(0, tmport++);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		if (i > 7) {
+			k = (i & 0x07) | 0x40;
+		} else {
+			k = i;
+		}
+		outb(k, tmport++);
+		tmport = dev->ioport[0] + 0x1b;
+		if (dev->chip_ver == 4) {
+			outb(0x01, tmport);
+		} else {
+			outb(0x00, tmport);
+		}
+wait_rdyok:
+		tmport = dev->ioport[0] + 0x18;
+		outb(0x09, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		k = inb(tmport);
+		if (k != 0x16) {
+			if ((k == 0x85) || (k == 0x42)) {
+				continue;
+			}
+			tmport = dev->ioport[0] + 0x10;
+			outb(0x41, tmport);
+			goto wait_rdyok;
+		}
+		assignid_map |= m;
+
+	}
+	tmport = dev->ioport[0] + 0x02;
+	outb(0x7f, tmport);
+	tmport = dev->ioport[0] + 0x1b;
+	outb(0x02, tmport);
+
+	outb(0, 0x80);
+
+	val = 0x0080;		/* bsy  */
+	tmport = dev->ioport[0] + 0x1c;
+	outw(val, tmport);
+	val |= 0x0040;		/* sel  */
+	outw(val, tmport);
+	val |= 0x0004;		/* msg  */
+	outw(val, tmport);
+	inb(0x80);		/* 2 deskew delay(45ns*2=90ns) */
+	val &= 0x007f;		/* no bsy  */
+	outw(val, tmport);
+	mdelay(128);
+	val &= 0x00fb;		/* after 1ms no msg */
+	outw(val, tmport);
+wait_nomsg:
+	if ((inb(tmport) & 0x04) != 0) {
+		goto wait_nomsg;
+	}
+	outb(1, 0x80);
+	udelay(100);
+	for (n = 0; n < 0x30000; n++) {
+		if ((inb(tmport) & 0x80) != 0) {	/* bsy ? */
+			goto wait_io;
+		}
+	}
+	goto TCM_SYNC;
+wait_io:
+	for (n = 0; n < 0x30000; n++) {
+		if ((inb(tmport) & 0x81) == 0x0081) {
+			goto wait_io1;
+		}
+	}
+	goto TCM_SYNC;
+wait_io1:
+	inb(0x80);
+	val |= 0x8003;		/* io,cd,db7  */
+	outw(val, tmport);
+	inb(0x80);
+	val &= 0x00bf;		/* no sel     */
+	outw(val, tmport);
+	outb(2, 0x80);
+TCM_SYNC:
+	udelay(0x800);
+	if ((inb(tmport) & 0x80) == 0x00) {	/* bsy ? */
+		outw(0, tmport--);
+		outb(0, tmport);
+		tmport = dev->ioport[0] + 0x15;
+		outb(0, tmport);
+		tmport += 0x03;
+		outb(0x09, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
+		tmport -= 0x08;
+		inb(tmport);
+		return;
+	}
+	val &= 0x00ff;		/* synchronization  */
+	val |= 0x3f00;
+	fun_scam(dev, &val);
+	outb(3, 0x80);
+	val &= 0x00ff;		/* isolation        */
+	val |= 0x2000;
+	fun_scam(dev, &val);
+	outb(4, 0x80);
+	i = 8;
+	j = 0;
+TCM_ID:
+	if ((inw(tmport) & 0x2000) == 0) {
+		goto TCM_ID;
+	}
+	outb(5, 0x80);
+	val &= 0x00ff;		/* get ID_STRING */
+	val |= 0x2000;
+	k = fun_scam(dev, &val);
+	if ((k & 0x03) == 0) {
+		goto TCM_5;
+	}
+	mbuf[j] <<= 0x01;
+	mbuf[j] &= 0xfe;
+	if ((k & 0x02) != 0) {
+		mbuf[j] |= 0x01;
+	}
+	i--;
+	if (i > 0) {
+		goto TCM_ID;
+	}
+	j++;
+	i = 8;
+	goto TCM_ID;
+
+TCM_5:			/* isolation complete..  */
+/*    mbuf[32]=0;
+	printk(" \n%x %x %x %s\n ",assignid_map,mbuf[0],mbuf[1],&mbuf[2]); */
+	i = 15;
+	j = mbuf[0];
+	if ((j & 0x20) != 0) {	/* bit5=1:ID upto 7      */
+		i = 7;
+	}
+	if ((j & 0x06) == 0) {	/* IDvalid?             */
+		goto G2Q5;
+	}
+	k = mbuf[1];
+small_id:
+	m = 1;
+	m <<= k;
+	if ((m & assignid_map) == 0) {
+		goto G2Q_QUIN;
+	}
+	if (k > 0) {
+		k--;
+		goto small_id;
+	}
+G2Q5:			/* srch from max acceptable ID#  */
+	k = i;			/* max acceptable ID#            */
+G2Q_LP:
+	m = 1;
+	m <<= k;
+	if ((m & assignid_map) == 0) {
+		goto G2Q_QUIN;
+	}
+	if (k > 0) {
+		k--;
+		goto G2Q_LP;
+	}
+G2Q_QUIN:		/* k=binID#,       */
+	assignid_map |= m;
+	if (k < 8) {
+		quintet[0] = 0x38;	/* 1st dft ID<8    */
+	} else {
+		quintet[0] = 0x31;	/* 1st  ID>=8      */
+	}
+	k &= 0x07;
+	quintet[1] = g2q_tab[k];
+
+	val &= 0x00ff;		/* AssignID 1stQuintet,AH=001xxxxx  */
+	m = quintet[0] << 8;
+	val |= m;
+	fun_scam(dev, &val);
+	val &= 0x00ff;		/* AssignID 2ndQuintet,AH=001xxxxx */
+	m = quintet[1] << 8;
+	val |= m;
+	fun_scam(dev, &val);
+
+	goto TCM_SYNC;
+
+}
+
+static void is870(struct atp_unit *dev, unsigned int wkport)
+{
+	unsigned int tmport;
+	unsigned char i, j, k, rmb, n;
+	unsigned short int m;
+	static unsigned char mbuf[512];
+	static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+	static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+	static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+	static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e };
+	static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 };
+	static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+	
+	tmport = wkport + 0x3a;
+	outb((unsigned char) (inb(tmport) | 0x10), tmport);
+
+	for (i = 0; i < 16; i++) {
+		if ((dev->chip_ver != 4) && (i > 7)) {
+			break;
+		}
+		m = 1;
+		m = m << i;
+		if ((m & dev->active_id[0]) != 0) {
+			continue;
+		}
+		if (i == dev->host_id[0]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
+			continue;
+		}
+		tmport = wkport + 0x1b;
+		if (dev->chip_ver == 4) {
+			outb(0x01, tmport);
+		} else {
+			outb(0x00, tmport);
+		}
+		tmport = wkport + 1;
+		outb(0x08, tmport++);
+		outb(0x7f, tmport++);
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		j = i;
+		if ((j & 0x08) != 0) {
+			j = (j & 0x07) | 0x40;
+		}
+		outb(j, tmport);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
+		dev->active_id[0] |= m;
+
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x04;
+		outb(0x00, tmport);
+
+phase_cmd:
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			tmport = wkport + 0x10;
+			outb(0x41, tmport);
+			goto phase_cmd;
+		}
+sel_ok:
+		tmport = wkport + 3;
+		outb(inqd[0], tmport++);
+		outb(inqd[1], tmport++);
+		outb(inqd[2], tmport++);
+		outb(inqd[3], tmport++);
+		outb(inqd[4], tmport++);
+		outb(inqd[5], tmport);
+		tmport += 0x07;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(inqd[6], tmport++);
+		outb(inqd[7], tmport++);
+		tmport += 0x03;
+		outb(inqd[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+		tmport = wkport + 0x1b;
+		if (dev->chip_ver == 4)
+			outb(0x00, tmport);
+
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		j = 0;
+rd_inq_data:
+		k = inb(tmport);
+		if ((k & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[j++] = inb(tmport);
+			tmport += 0x06;
+			goto rd_inq_data;
+		}
+		if ((k & 0x80) == 0) {
+			goto rd_inq_data;
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x16) {
+			goto inq_ok;
+		}
+		tmport = wkport + 0x10;
+		outb(0x46, tmport);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x16) {
+			goto sel_ok;
+		}
+inq_ok:
+		mbuf[36] = 0;
+		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
+		dev->id[0][i].devtype = mbuf[0];
+		rmb = mbuf[1];
+		n = mbuf[7];
+		if (dev->chip_ver != 4) {
+			goto not_wide;
+		}
+		if ((mbuf[7] & 0x60) == 0) {
+			goto not_wide;
+		}
+		if ((dev->global_map[0] & 0x20) == 0) {
+			goto not_wide;
+		}
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 3;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+try_wide:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x05, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(wide[j++], tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_wide;
+		}
+		continue;
+widep_out:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_in:
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+widep_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto widep_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto widep_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_cmd:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto widep_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto not_wide;
+		}
+		if (mbuf[1] != 0x02) {
+			goto not_wide;
+		}
+		if (mbuf[2] != 0x03) {
+			goto not_wide;
+		}
+		if (mbuf[3] != 0x01) {
+			goto not_wide;
+		}
+		m = 1;
+		m = m << i;
+		dev->wide_id[0] |= m;
+not_wide:
+		if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+			goto set_sync;
+		}
+		continue;
+set_sync:
+		tmport = wkport + 0x1b;
+		j = 0;
+		if ((m & dev->wide_id[0]) != 0) {
+			j |= 0x01;
+		}
+		outb(j, tmport);
+		tmport = wkport + 3;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+try_sync:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				if ((m & dev->wide_id[0]) != 0) {
+					outb(synw[j++], tmport);
+				} else {
+					if ((m & dev->ultra_map[0]) != 0) {
+						outb(synu[j++], tmport);
+					} else {
+						outb(synn[j++], tmport);
+					}
+				}
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto try_sync;
+		}
+		continue;
+phase_outs:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00) {
+			if ((inb(tmport) & 0x01) != 0x00) {
+				tmport -= 0x06;
+				outb(0x00, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_ins:
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+phase_ins1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0x00) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto phase_ins1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto phase_ins1;
+		}
+		tmport -= 0x08;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_cmds:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+tar_dcons:
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			continue;
+		}
+		if (mbuf[1] != 0x03) {
+			continue;
+		}
+		if (mbuf[4] == 0x00) {
+			continue;
+		}
+		if (mbuf[3] > 0x64) {
+			continue;
+		}
+		if (mbuf[4] > 0x0c) {
+			mbuf[4] = 0x0c;
+		}
+		dev->id[0][i].devsp = mbuf[4];
+		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+			j = 0xa0;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x1a) {
+			j = 0x20;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x33) {
+			j = 0x40;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x4c) {
+			j = 0x50;
+			goto set_syn_ok;
+		}
+		j = 0x60;
+set_syn_ok:
+		dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
+	}
+	tmport = wkport + 0x3a;
+	outb((unsigned char) (inb(tmport) & 0xef), tmport);
+}
+
+static void is880(struct atp_unit *dev, unsigned int wkport)
+{
+	unsigned int tmport;
+	unsigned char i, j, k, rmb, n, lvdmode;
+	unsigned short int m;
+	static unsigned char mbuf[512];
+	static unsigned char satn[9] = { 0, 0, 0, 0, 0, 0, 0, 6, 6 };
+	static unsigned char inqd[9] = { 0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6 };
+	static unsigned char synn[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+	unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+	static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x19, 0x0e };
+	unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e };
+	static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 };
+	static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 };
+
+	lvdmode = inb(wkport + 0x3f) & 0x40;
+
+	for (i = 0; i < 16; i++) {
+		m = 1;
+		m = m << i;
+		if ((m & dev->active_id[0]) != 0) {
+			continue;
+		}
+		if (i == dev->host_id[0]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[0]);
+			continue;
+		}
+		tmport = wkport + 0x5b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x41;
+		outb(0x08, tmport++);
+		outb(0x7f, tmport++);
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		j = i;
+		if ((j & 0x08) != 0) {
+			j = (j & 0x07) | 0x40;
+		}
+		outb(j, tmport);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+		dev->active_id[0] |= m;
+
+		tmport = wkport + 0x50;
+		outb(0x30, tmport);
+		tmport = wkport + 0x54;
+		outb(0x00, tmport);
+
+phase_cmd:
+		tmport = wkport + 0x58;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			tmport = wkport + 0x50;
+			outb(0x41, tmport);
+			goto phase_cmd;
+		}
+sel_ok:
+		tmport = wkport + 0x43;
+		outb(inqd[0], tmport++);
+		outb(inqd[1], tmport++);
+		outb(inqd[2], tmport++);
+		outb(inqd[3], tmport++);
+		outb(inqd[4], tmport++);
+		outb(inqd[5], tmport);
+		tmport += 0x07;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(inqd[6], tmport++);
+		outb(inqd[7], tmport++);
+		tmport += 0x03;
+		outb(inqd[8], tmport);
+		tmport += 0x07;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+		tmport = wkport + 0x5b;
+		outb(0x00, tmport);
+		tmport = wkport + 0x58;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		j = 0;
+rd_inq_data:
+		k = inb(tmport);
+		if ((k & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[j++] = inb(tmport);
+			tmport += 0x06;
+			goto rd_inq_data;
+		}
+		if ((k & 0x80) == 0) {
+			goto rd_inq_data;
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x16) {
+			goto inq_ok;
+		}
+		tmport = wkport + 0x50;
+		outb(0x46, tmport);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x16)
+			goto sel_ok;
+
+inq_ok:
+		mbuf[36] = 0;
+		printk(KERN_INFO "         ID: %2d  %s\n", i, &mbuf[8]);
+		dev->id[0][i].devtype = mbuf[0];
+		rmb = mbuf[1];
+		n = mbuf[7];
+		if ((mbuf[7] & 0x60) == 0) {
+			goto not_wide;
+		}
+		if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) {
+			goto not_wide;
+		}
+		if (lvdmode == 0) {
+			goto chg_wide;
+		}
+		if (dev->sp[0][i] != 0x04)	// force u2
+		{
+			goto chg_wide;
+		}
+
+		tmport = wkport + 0x5b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x43;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
+try_u3:
+		j = 0;
+		tmport = wkport + 0x54;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(u3[j++], tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_u3;
+		}
+		continue;
+u3p_out:
+		tmport = wkport + 0x58;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_in:
+		tmport = wkport + 0x54;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+u3p_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto u3p_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto u3p_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_cmd:
+		tmport = wkport + 0x50;
+		outb(0x30, tmport);
+		tmport = wkport + 0x54;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto u3p_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto chg_wide;
+		}
+		if (mbuf[1] != 0x06) {
+			goto chg_wide;
+		}
+		if (mbuf[2] != 0x04) {
+			goto chg_wide;
+		}
+		if (mbuf[3] == 0x09) {
+			m = 1;
+			m = m << i;
+			dev->wide_id[0] |= m;
+			dev->id[0][i].devsp = 0xce;
+			continue;
+		}
+chg_wide:
+		tmport = wkport + 0x5b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x43;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		tmport -= 0x08;
+		if (inb(tmport) != 0x11 && inb(tmport) != 0x8e)
+			continue;
+
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+			
+try_wide:
+		j = 0;
+		tmport = wkport + 0x54;
+		outb(0x05, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(wide[j++], tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+			
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_wide;
+		}
+		continue;
+widep_out:
+		tmport = wkport + 0x58;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_in:
+		tmport = wkport + 0x54;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+widep_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto widep_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto widep_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_cmd:
+		tmport = wkport + 0x50;
+		outb(0x30, tmport);
+		tmport = wkport + 0x54;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto widep_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto not_wide;
+		}
+		if (mbuf[1] != 0x02) {
+			goto not_wide;
+		}
+		if (mbuf[2] != 0x03) {
+			goto not_wide;
+		}
+		if (mbuf[3] != 0x01) {
+			goto not_wide;
+		}
+		m = 1;
+		m = m << i;
+		dev->wide_id[0] |= m;
+not_wide:
+		if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+			m = 1;
+			m = m << i;
+			if ((dev->async[0] & m) != 0) {
+				goto set_sync;
+			}
+		}
+		continue;
+set_sync:
+		if (dev->sp[0][i] == 0x02) {
+			synu[4] = 0x0c;
+			synuw[4] = 0x0c;
+		} else {
+			if (dev->sp[0][i] >= 0x03) {
+				synu[4] = 0x0a;
+				synuw[4] = 0x0a;
+			}
+		}
+		tmport = wkport + 0x5b;
+		j = 0;
+		if ((m & dev->wide_id[0]) != 0) {
+			j |= 0x01;
+		}
+		outb(j, tmport);
+		tmport = wkport + 0x43;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[0][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+
+try_sync:
+		j = 0;
+		tmport = wkport + 0x54;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				if ((m & dev->wide_id[0]) != 0) {
+					if ((m & dev->ultra_map[0]) != 0) {
+						outb(synuw[j++], tmport);
+					} else {
+						outb(synw[j++], tmport);
+					}
+				} else {
+					if ((m & dev->ultra_map[0]) != 0) {
+						outb(synu[j++], tmport);
+					} else {
+						outb(synn[j++], tmport);
+					}
+				}
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto try_sync;
+		}
+		continue;
+phase_outs:
+		tmport = wkport + 0x58;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00) {
+			if ((inb(tmport) & 0x01) != 0x00) {
+				tmport -= 0x06;
+				outb(0x00, tmport);
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_ins:
+		tmport = wkport + 0x54;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+phase_ins1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0x00) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto phase_ins1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto phase_ins1;
+		}
+		tmport -= 0x08;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_cmds:
+		tmport = wkport + 0x50;
+		outb(0x30, tmport);
+tar_dcons:
+		tmport = wkport + 0x54;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			continue;
+		}
+		if (mbuf[1] != 0x03) {
+			continue;
+		}
+		if (mbuf[4] == 0x00) {
+			continue;
+		}
+		if (mbuf[3] > 0x64) {
+			continue;
+		}
+		if (mbuf[4] > 0x0e) {
+			mbuf[4] = 0x0e;
+		}
+		dev->id[0][i].devsp = mbuf[4];
+		if (mbuf[3] < 0x0c) {
+			j = 0xb0;
+			goto set_syn_ok;
+		}
+		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+			j = 0xa0;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x1a) {
+			j = 0x20;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x33) {
+			j = 0x40;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x4c) {
+			j = 0x50;
+			goto set_syn_ok;
+		}
+		j = 0x60;
+set_syn_ok:
+		dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j;
+	}
+}
+
+static void atp870u_free_tables(struct Scsi_Host *host)
+{
+	struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
+	int j, k;
+	for (j=0; j < 2; j++) {
+		for (k = 0; k < 16; k++) {
+			if (!atp_dev->id[j][k].prd_table)
+				continue;
+			pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prdaddr);
+			atp_dev->id[j][k].prd_table = NULL;
+		}
+	}
+}
+
+static int atp870u_init_tables(struct Scsi_Host *host)
+{
+	struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata;
+	int c,k;
+	for(c=0;c < 2;c++) {
+	   	for(k=0;k<16;k++) {
+	   			atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prdaddr));
+	   			if (!atp_dev->id[c][k].prd_table) {
+	   				printk("atp870u_init_tables fail\n");
+				atp870u_free_tables(host);
+				return -ENOMEM;
+			}
+			atp_dev->id[c][k].devsp=0x20;
+			atp_dev->id[c][k].devtype = 0x7f;
+			atp_dev->id[c][k].curr_req = NULL;			   
+	   	}
+	   			
+	   	atp_dev->active_id[c] = 0;
+	   	atp_dev->wide_id[c] = 0;
+	   	atp_dev->host_id[c] = 0x07;
+	   	atp_dev->quhd[c] = 0;
+	   	atp_dev->quend[c] = 0;
+	   	atp_dev->last_cmd[c] = 0xff;
+	   	atp_dev->in_snd[c] = 0;
+	   	atp_dev->in_int[c] = 0;
+	   	
+	   	for (k = 0; k < qcnt; k++) {
+	   		  atp_dev->quereq[c][k] = NULL;
+	   	}	   		   
+	   	for (k = 0; k < 16; k++) {
+			   atp_dev->id[c][k].curr_req = NULL;
+			   atp_dev->sp[c][k] = 0x04;
+	   	}		   
+	}
+	return 0;
+}
+
+/* return non-zero on detection */
+static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	unsigned char k, m, c;
+	unsigned long flags;
+	unsigned int base_io, tmport, error,n;
+	unsigned char host_id;
+	struct Scsi_Host *shpnt = NULL;
+	struct atp_unit atp_dev, *p;
+	unsigned char setupdata[2][16];
+	int count = 0;
+	
+	if (pci_enable_device(pdev))
+		return -EIO;
+
+        if (!pci_set_dma_mask(pdev, 0xFFFFFFFFUL)) {
+                printk(KERN_INFO "atp870u: use 32bit DMA mask.\n");
+        } else {
+                printk(KERN_ERR "atp870u: DMA mask required but not available.\n");
+                return -EIO;
+        }
+
+	memset(&atp_dev, 0, sizeof atp_dev);
+	/*
+	 * It's probably easier to weed out some revisions like
+	 * this than via the PCI device table
+	 */
+	if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) {
+		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+		if (atp_dev.chip_ver < 2)
+			return -EIO;
+	}
+
+	switch (ent->device) {
+	case PCI_DEVICE_ID_ARTOP_AEC7612UW:
+	case PCI_DEVICE_ID_ARTOP_AEC7612SUW:
+	case ATP880_DEVID1:	
+	case ATP880_DEVID2:	
+	case ATP885_DEVID:	
+		atp_dev.chip_ver = 0x04;
+	default:
+		break;
+	}
+	base_io = pci_resource_start(pdev, 0);
+	base_io &= 0xfffffff8;
+	
+	if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) {
+		error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver);
+		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803
+
+		host_id = inb(base_io + 0x39);
+		host_id >>= 0x04;
+
+		printk(KERN_INFO "   ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d"
+			"    IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+		atp_dev.ioport[0] = base_io + 0x40;
+		atp_dev.pciport[0] = base_io + 0x28;
+		atp_dev.dev_id = ent->device;
+		atp_dev.host_id[0] = host_id;
+
+		tmport = base_io + 0x22;
+		atp_dev.scam_on = inb(tmport);
+		tmport += 0x13;
+		atp_dev.global_map[0] = inb(tmport);
+		tmport += 0x07;
+		atp_dev.ultra_map[0] = inw(tmport);
+
+		n = 0x3f09;
+next_fblk_880:
+		if (n >= 0x4000)
+			goto flash_ok_880;
+
+		m = 0;
+		outw(n, base_io + 0x34);
+		n += 0x0002;
+		if (inb(base_io + 0x30) == 0xff)
+			goto flash_ok_880;
+
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
+		outw(n, base_io + 0x34);
+		n += 0x0002;
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
+		outw(n, base_io + 0x34);
+		n += 0x0002;
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
+		outw(n, base_io + 0x34);
+		n += 0x0002;
+		atp_dev.sp[0][m++] = inb(base_io + 0x30);
+		atp_dev.sp[0][m++] = inb(base_io + 0x31);
+		atp_dev.sp[0][m++] = inb(base_io + 0x32);
+		atp_dev.sp[0][m++] = inb(base_io + 0x33);
+		n += 0x0018;
+		goto next_fblk_880;
+flash_ok_880:
+		outw(0, base_io + 0x34);
+		atp_dev.ultra_map[0] = 0;
+		atp_dev.async[0] = 0;
+		for (k = 0; k < 16; k++) {
+			n = 1;
+			n = n << k;
+			if (atp_dev.sp[0][k] > 1) {
+				atp_dev.ultra_map[0] |= n;
+			} else {
+				if (atp_dev.sp[0][k] == 0)
+					atp_dev.async[0] |= n;
+ 			}
+	 	}
+		atp_dev.async[0] = ~(atp_dev.async[0]);
+		outb(atp_dev.global_map[0], base_io + 0x35);
+ 
+		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+		if (!shpnt)
+			return -ENOMEM;
+
+		p = (struct atp_unit *)&shpnt->hostdata;
+
+		atp_dev.host = shpnt;
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
+		memcpy(p, &atp_dev, sizeof atp_dev);
+		if (atp870u_init_tables(shpnt) < 0) {
+			printk(KERN_ERR "Unable to allocate tables for Acard controller\n");
+			goto unregister;
+		}
+
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp880i", shpnt)) {
+ 			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
+			goto free_tables;
+		}
+
+		spin_lock_irqsave(shpnt->host_lock, flags);
+		tmport = base_io + 0x38;
+		k = inb(tmport) & 0x80;
+		outb(k, tmport);
+		tmport += 0x03;
+		outb(0x20, tmport);
+		mdelay(32);
+		outb(0, tmport);
+		mdelay(32);
+		tmport = base_io + 0x5b;
+		inb(tmport);
+		tmport -= 0x04;
+		inb(tmport);
+		tmport = base_io + 0x40;
+		outb((host_id | 0x08), tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0)
+			mdelay(1);
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 0x41;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x51;
+		outb(0x20, tmport);
+
+		tscam(shpnt);
+		is880(p, base_io);
+		tmport = base_io + 0x38;
+		outb(0xb0, tmport);
+		shpnt->max_id = 16;
+		shpnt->this_id = host_id;
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
+		shpnt->n_io_port = 0x60;	/* Number of bytes of I/O space used */
+		shpnt->irq = pdev->irq;			
+	} else if (ent->device == ATP885_DEVID) {	
+			printk(KERN_INFO "   ACARD AEC-67162 PCI Ultra3 LVD Host Adapter:  IO:%x, IRQ:%d.\n"
+			       , base_io, pdev->irq);
+        	
+		atp_dev.pdev = pdev;	
+		atp_dev.dev_id  = ent->device;
+		atp_dev.baseport = base_io;
+		atp_dev.ioport[0] = base_io + 0x80;
+		atp_dev.ioport[1] = base_io + 0xc0;
+		atp_dev.pciport[0] = base_io + 0x40;
+		atp_dev.pciport[1] = base_io + 0x50;
+				
+		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+		if (!shpnt)
+			return -ENOMEM;
+        	
+		p = (struct atp_unit *)&shpnt->hostdata;
+        	
+		atp_dev.host = shpnt;
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
+		memcpy(p, &atp_dev, sizeof(struct atp_unit));
+		if (atp870u_init_tables(shpnt) < 0)
+			goto unregister;
+			
+#ifdef ED_DBGP		
+	printk("request_irq() shpnt %p hostdata %p\n", shpnt, p);
+#endif	        
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) {
+				printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n");
+			goto free_tables;
+		}
+		
+		spin_lock_irqsave(shpnt->host_lock, flags);        					
+        			
+		c=inb(base_io + 0x29);
+		outb((c | 0x04),base_io + 0x29);
+        	
+		n=0x1f80;
+next_fblk_885:
+		if (n >= 0x2000) {
+		   goto flash_ok_885;
+		}
+		outw(n,base_io + 0x3c);
+		if (inl(base_io + 0x38) == 0xffffffff) {
+		   goto flash_ok_885;
+		}
+		for (m=0; m < 2; m++) {
+		    p->global_map[m]= 0;
+		    for (k=0; k < 4; k++) {
+			outw(n++,base_io + 0x3c);
+			((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38);
+		    }
+		    for (k=0; k < 4; k++) {
+			outw(n++,base_io + 0x3c);
+			((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38);
+		    }
+		    n += 8;
+		}
+		goto next_fblk_885;
+flash_ok_885:
+#ifdef ED_DBGP
+		printk( "Flash Read OK\n");
+#endif	
+		c=inb(base_io + 0x29);
+		outb((c & 0xfb),base_io + 0x29);
+		for (c=0;c < 2;c++) {
+		    p->ultra_map[c]=0;
+		    p->async[c] = 0;
+		    for (k=0; k < 16; k++) {
+			n=1;
+			n = n << k;
+			if (p->sp[c][k] > 1) {
+			   p->ultra_map[c] |= n;
+			} else {
+			   if (p->sp[c][k] == 0) {
+			      p->async[c] |= n;
+			   }
+			}
+		    }
+		    p->async[c] = ~(p->async[c]);
+
+		    if (p->global_map[c] == 0) {
+		       k=setupdata[c][1];
+		       if ((k & 0x40) != 0)
+			  p->global_map[c] |= 0x20;
+		       k &= 0x07;
+		       p->global_map[c] |= k;
+		       if ((setupdata[c][2] & 0x04) != 0)
+			  p->global_map[c] |= 0x08;
+		       p->host_id[c] = setupdata[c][0] & 0x07;
+		    }
+		}
+
+		k = inb(base_io + 0x28) & 0x8f;
+		k |= 0x10;
+		outb(k, base_io + 0x28);
+		outb(0x80, base_io + 0x41);
+		outb(0x80, base_io + 0x51);
+		mdelay(100);
+		outb(0, base_io + 0x41);
+		outb(0, base_io + 0x51);
+		mdelay(1000);
+		inb(base_io + 0x9b);
+		inb(base_io + 0x97);
+		inb(base_io + 0xdb);
+		inb(base_io + 0xd7);
+		tmport = base_io + 0x80;
+		k=p->host_id[0];
+		if (k > 7)
+		   k = (k & 0x07) | 0x40;
+		k |= 0x08;
+		outb(k, tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
+	
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 0x81;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x91;
+		outb(0x20, tmport);
+
+		tmport = base_io + 0xc0;
+		k=p->host_id[1];
+		if (k > 7)
+		   k = (k & 0x07) | 0x40;
+		k |= 0x08;
+		outb(k, tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0)
+			cpu_relax();
+
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 0xc1;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0xd1;
+		outb(0x20, tmport);
+
+		tscam_885();
+		printk(KERN_INFO "   Scanning Channel A SCSI Device ...\n");
+		is885(p, base_io + 0x80, 0);
+		printk(KERN_INFO "   Scanning Channel B SCSI Device ...\n");
+		is885(p, base_io + 0xc0, 1);
+
+		k = inb(base_io + 0x28) & 0xcf;
+		k |= 0xc0;
+		outb(k, base_io + 0x28);
+		k = inb(base_io + 0x1f) | 0x80;
+		outb(k, base_io + 0x1f);
+		k = inb(base_io + 0x29) | 0x01;
+		outb(k, base_io + 0x29);
+#ifdef ED_DBGP
+		//printk("atp885: atp_host[0] 0x%p\n", atp_host[0]);
+#endif		
+		shpnt->max_id = 16;
+		shpnt->max_lun = (p->global_map[0] & 0x07) + 1;
+		shpnt->max_channel = 1;
+		shpnt->this_id = p->host_id[0];
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
+		shpnt->n_io_port = 0xff;	/* Number of bytes of I/O space used */
+		shpnt->irq = pdev->irq;
+				
+	} else {
+		error = pci_read_config_byte(pdev, 0x49, &host_id);
+
+		printk(KERN_INFO "   ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d "
+			"IO:%x, IRQ:%d.\n", count, base_io, pdev->irq);
+
+		atp_dev.ioport[0] = base_io;
+		atp_dev.pciport[0] = base_io + 0x20;
+		atp_dev.dev_id = ent->device;
+		host_id &= 0x07;
+		atp_dev.host_id[0] = host_id;
+		tmport = base_io + 0x22;
+		atp_dev.scam_on = inb(tmport);
+		tmport += 0x0b;
+		atp_dev.global_map[0] = inb(tmport++);
+		atp_dev.ultra_map[0] = inw(tmport);
+
+		if (atp_dev.ultra_map[0] == 0) {
+			atp_dev.scam_on = 0x00;
+			atp_dev.global_map[0] = 0x20;
+			atp_dev.ultra_map[0] = 0xffff;
+		}
+
+		shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit));
+		if (!shpnt)
+			return -ENOMEM;
+
+		p = (struct atp_unit *)&shpnt->hostdata;
+		
+		atp_dev.host = shpnt;
+		atp_dev.pdev = pdev;
+		pci_set_drvdata(pdev, p);
+		memcpy(p, &atp_dev, sizeof atp_dev);
+		if (atp870u_init_tables(shpnt) < 0)
+			goto unregister;
+
+		if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870i", shpnt)) {
+			printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq);
+			goto free_tables;
+		}
+
+		spin_lock_irqsave(shpnt->host_lock, flags);
+		if (atp_dev.chip_ver > 0x07) {	/* check if atp876 chip then enable terminator */
+			tmport = base_io + 0x3e;
+			outb(0x00, tmport);
+		}
+ 
+		tmport = base_io + 0x3a;
+		k = (inb(tmport) & 0xf3) | 0x10;
+		outb(k, tmport);
+		outb((k & 0xdf), tmport);
+		mdelay(32);
+		outb(k, tmport);
+		mdelay(32);
+		tmport = base_io;
+		outb((host_id | 0x08), tmport);
+		tmport += 0x18;
+		outb(0, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0)
+			mdelay(1);
+
+		tmport -= 0x08;
+		inb(tmport);
+		tmport = base_io + 1;
+		outb(8, tmport++);
+		outb(0x7f, tmport);
+		tmport = base_io + 0x11;
+		outb(0x20, tmport);
+
+		tscam(shpnt);
+		is870(p, base_io);
+		tmport = base_io + 0x3a;
+		outb((inb(tmport) & 0xef), tmport);
+		tmport++;
+		outb((inb(tmport) | 0x20), tmport);
+		if (atp_dev.chip_ver == 4)
+			shpnt->max_id = 16;
+		else		
+			shpnt->max_id = 7;
+		shpnt->this_id = host_id;
+		shpnt->unique_id = base_io;
+		shpnt->io_port = base_io;
+		shpnt->n_io_port = 0x40;	/* Number of bytes of I/O space used */
+		shpnt->irq = pdev->irq;		
+	} 
+		spin_unlock_irqrestore(shpnt->host_lock, flags);
+		if(ent->device==ATP885_DEVID) {
+			if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
+			if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		} else {
+			if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */
+				goto request_io_fail;
+		}				
+		count++;
+		if (scsi_add_host(shpnt, &pdev->dev))
+			goto scsi_add_fail;
+		scsi_scan_host(shpnt);
+#ifdef ED_DBGP			
+		printk("atp870u_prob : exit\n");
+#endif		
+		return 0;
+
+scsi_add_fail:
+	printk("atp870u_prob:scsi_add_fail\n");
+	if(ent->device==ATP885_DEVID) {
+		release_region(base_io, 0xff);
+	} else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) {
+		release_region(base_io, 0x60);
+	} else {
+		release_region(base_io, 0x40);
+	}
+request_io_fail:
+	printk("atp870u_prob:request_io_fail\n");
+	free_irq(pdev->irq, shpnt);
+free_tables:
+	printk("atp870u_prob:free_table\n");
+	atp870u_free_tables(shpnt);
+unregister:
+	printk("atp870u_prob:unregister\n");
+	scsi_host_put(shpnt);
+	return -1;		
+}
+
+/* The abort command does not leave the device in a clean state where
+   it is available to be used again.  Until this gets worked out, we will
+   leave it commented out.  */
+
+static int atp870u_abort(struct scsi_cmnd * SCpnt)
+{
+	unsigned char  j, k, c;
+	struct scsi_cmnd *workrequ;
+	unsigned int tmport;
+	struct atp_unit *dev;	
+	struct Scsi_Host *host;
+	host = SCpnt->device->host;
+
+	dev = (struct atp_unit *)&host->hostdata;
+	c=SCpnt->device->channel;
+	printk(" atp870u: abort Channel = %x \n", c);
+	printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]);
+	printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]);
+	tmport = dev->ioport[c];
+	for (j = 0; j < 0x18; j++) {
+		printk(" r%2x=%2x", j, inb(tmport++));
+	}
+	tmport += 0x04;
+	printk(" r1c=%2x", inb(tmport));
+	tmport += 0x03;
+	printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]);
+	tmport= dev->pciport[c];
+	printk(" d00=%2x", inb(tmport));
+	tmport += 0x02;
+	printk(" d02=%2x", inb(tmport));
+	for(j=0;j<16;j++) {
+	   if (dev->id[c][j].curr_req != NULL) {
+		workrequ = dev->id[c][j].curr_req;
+		printk("\n que cdb= ");
+		for (k=0; k < workrequ->cmd_len; k++) {
+		    printk(" %2x ",workrequ->cmnd[k]);
+		}
+		printk(" last_lenu= %x ",(unsigned int)dev->id[c][j].last_len);
+	   }
+	}
+	return SUCCESS;
+}
+
+static const char *atp870u_info(struct Scsi_Host *notused)
+{
+	static char buffer[128];
+
+	strcpy(buffer, "ACARD AEC-6710/6712/67160 PCI Ultra/W/LVD SCSI-3 Adapter Driver V2.6+ac ");
+
+	return buffer;
+}
+
+#define BLS buffer + len + size
+int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, 
+		      char **start, off_t offset, int length, int inout)
+{
+	static u8 buff[512];
+	int size = 0;
+	int len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
+	
+	if (inout) 	
+		return -EINVAL;
+	if (offset == 0)
+		memset(buff, 0, sizeof(buff));
+	size += sprintf(BLS, "ACARD AEC-671X Driver Version: 2.6+ac\n");
+	len += size;
+	pos = begin + len;
+	size = 0;
+
+	size += sprintf(BLS, "\n");
+	size += sprintf(BLS, "Adapter Configuration:\n");
+	size += sprintf(BLS, "               Base IO: %#.4lx\n", HBAptr->io_port);
+	size += sprintf(BLS, "                   IRQ: %d\n", HBAptr->irq);
+	len += size;
+	pos = begin + len;
+	
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);	/* Start slop */
+	if (len > length) {
+		len = length;	/* Ending slop */
+	}
+	return (len);
+}
+
+
+static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev,
+			sector_t capacity, int *ip)
+{
+	int heads, sectors, cylinders;
+
+	heads = 64;
+	sectors = 32;
+	cylinders = (unsigned long)capacity / (heads * sectors);
+	if (cylinders > 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = (unsigned long)capacity / (heads * sectors);
+	}
+	ip[0] = heads;
+	ip[1] = sectors;
+	ip[2] = cylinders;
+
+	return 0;
+}
+
+static void atp870u_remove (struct pci_dev *pdev)
+{	
+	struct atp_unit *devext = pci_get_drvdata(pdev);
+	struct Scsi_Host *pshost = devext->host;
+	
+	
+	scsi_remove_host(pshost);
+	printk(KERN_INFO "free_irq : %d\n",pshost->irq);
+	free_irq(pshost->irq, pshost);
+	release_region(pshost->io_port, pshost->n_io_port);
+	printk(KERN_INFO "atp870u_free_tables : %p\n",pshost);
+	atp870u_free_tables(pshost);
+	printk(KERN_INFO "scsi_host_put : %p\n",pshost);
+	scsi_host_put(pshost);
+	printk(KERN_INFO "pci_set_drvdata : %p\n",pdev);
+	pci_set_drvdata(pdev, NULL);	
+}
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template atp870u_template = {
+     .module			= THIS_MODULE,
+     .name              	= "atp870u"		/* name */,
+     .proc_name			= "atp870u",
+     .proc_info			= atp870u_proc_info,
+     .info              	= atp870u_info		/* info */,
+     .queuecommand      	= atp870u_queuecommand	/* queuecommand */,
+     .eh_abort_handler  	= atp870u_abort		/* abort */,
+     .bios_param        	= atp870u_biosparam	/* biosparm */,
+     .can_queue         	= qcnt			/* can_queue */,
+     .this_id           	= 7			/* SCSI ID */,
+     .sg_tablesize      	= ATP870U_SCATTER	/*SG_ALL*/ /*SG_NONE*/,
+     .cmd_per_lun       	= ATP870U_CMDLUN		/* commands per lun */,
+     .use_clustering    	= ENABLE_CLUSTERING,
+     .max_sectors		= ATP870U_MAX_SECTORS,
+};
+
+static struct pci_device_id atp870u_id_table[] = {
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP885_DEVID)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID1)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID2)			  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7610)    },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612UW)  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612U)   },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612S)   },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612D)	  },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612SUW) },
+	{ PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_8060)	  },
+	{ 0, },
+};
+
+MODULE_DEVICE_TABLE(pci, atp870u_id_table);
+
+static struct pci_driver atp870u_driver = {
+	.id_table	= atp870u_id_table,
+	.name		= "atp870u",
+	.probe		= atp870u_probe,
+	.remove		= __devexit_p(atp870u_remove),
+};
+
+static int __init atp870u_init(void)
+{
+#ifdef ED_DBGP	
+	printk("atp870u_init: Entry\n");
+#endif	
+	return pci_register_driver(&atp870u_driver);
+}
+
+static void __exit atp870u_exit(void)
+{
+#ifdef ED_DBGP	
+	printk("atp870u_exit: Entry\n");
+#endif
+	pci_unregister_driver(&atp870u_driver);
+}
+
+static void tscam_885(void)
+{
+	unsigned char i;
+
+	for (i = 0; i < 0x2; i++) {
+		mdelay(300);
+	}
+	return;
+}
+
+
+
+static void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c)
+{
+	unsigned int tmport;
+	unsigned char i, j, k, rmb, n, lvdmode;
+	unsigned short int m;
+	static unsigned char mbuf[512];
+	static unsigned char satn[9] =	{0, 0, 0, 0, 0, 0, 0, 6, 6};
+	static unsigned char inqd[9] =	{0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6};
+	static unsigned char synn[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synu[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char synw[6] =	{0x80, 1, 3, 1, 0x19, 0x0e};
+	unsigned char synuw[6] =  {0x80, 1, 3, 1, 0x0a, 0x0e};
+	static unsigned char wide[6] =	{0x80, 1, 2, 3, 1, 0};
+	static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 };
+
+	lvdmode=inb(wkport + 0x1b) >> 7;
+
+	for (i = 0; i < 16; i++) {
+		m = 1;
+		m = m << i;
+		if ((m & dev->active_id[c]) != 0) {
+			continue;
+		}
+		if (i == dev->host_id[c]) {
+			printk(KERN_INFO "         ID: %2d  Host Adapter\n", dev->host_id[c]);
+			continue;
+		}
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x01;
+		outb(0x08, tmport++);
+		outb(0x7f, tmport++);
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		j = i;
+		if ((j & 0x08) != 0) {
+			j = (j & 0x07) | 0x40;
+		}
+		outb(j, tmport);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+		dev->active_id[c] |= m;
+
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+
+phase_cmd:
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			tmport = wkport + 0x10;
+			outb(0x41, tmport);
+			goto phase_cmd;
+		}
+sel_ok:
+		tmport = wkport + 0x03;
+		outb(inqd[0], tmport++);
+		outb(inqd[1], tmport++);
+		outb(inqd[2], tmport++);
+		outb(inqd[3], tmport++);
+		outb(inqd[4], tmport++);
+		outb(inqd[5], tmport);
+		tmport += 0x07;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(inqd[6], tmport++);
+		outb(inqd[7], tmport++);
+		tmport += 0x03;
+		outb(inqd[8], tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+		tmport = wkport + 0x1b;
+		outb(0x00, tmport);
+		tmport = wkport + 0x18;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		j = 0;
+rd_inq_data:
+		k = inb(tmport);
+		if ((k & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[j++] = inb(tmport);
+			tmport += 0x06;
+			goto rd_inq_data;
+		}
+		if ((k & 0x80) == 0) {
+			goto rd_inq_data;
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x16) {
+			goto inq_ok;
+		}
+		tmport = wkport + 0x10;
+		outb(0x46, tmport);
+		tmport += 0x02;
+		outb(0, tmport++);
+		outb(0, tmport++);
+		outb(0, tmport++);
+		tmport += 0x03;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if (inb(tmport) != 0x16) {
+			goto sel_ok;
+		}
+inq_ok:
+		mbuf[36] = 0;
+		printk( KERN_INFO"         ID: %2d  %s\n", i, &mbuf[8]);
+		dev->id[c][i].devtype = mbuf[0];
+		rmb = mbuf[1];
+		n = mbuf[7];
+		if ((mbuf[7] & 0x60) == 0) {
+			goto not_wide;
+		}
+		if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) {
+			goto not_wide;
+		}
+		if (lvdmode == 0) {
+		   goto chg_wide;
+		}
+		if (dev->sp[c][i] != 0x04) {	// force u2
+		   goto chg_wide;
+		}
+
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_u3:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(u3[j++], tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_u3;
+		}
+		continue;
+u3p_out:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_in:
+		tmport = wkport + 0x14;
+		outb(0x09, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+u3p_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto u3p_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto u3p_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto u3p_in;
+		}
+		if (j == 0x0a) {
+			goto u3p_cmd;
+		}
+		if (j == 0x0e) {
+			goto u3p_out;
+		}
+		continue;
+u3p_cmd:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00);
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto u3p_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto chg_wide;
+		}
+		if (mbuf[1] != 0x06) {
+			goto chg_wide;
+		}
+		if (mbuf[2] != 0x04) {
+			goto chg_wide;
+		}
+		if (mbuf[3] == 0x09) {
+			m = 1;
+			m = m << i;
+			dev->wide_id[c] |= m;
+			dev->id[c][i].devsp = 0xce;
+#ifdef ED_DBGP		   
+			printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
+#endif
+			continue;
+		}
+chg_wide:
+		tmport = wkport + 0x1b;
+		outb(0x01, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_wide:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x05, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(wide[j++], tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto try_wide;
+		}
+		continue;
+widep_out:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				outb(0, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_in:
+		tmport = wkport + 0x14;
+		outb(0xff, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+widep_in1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto widep_in1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto widep_in1;
+		}
+		tmport -= 0x08;
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto widep_in;
+		}
+		if (j == 0x0a) {
+			goto widep_cmd;
+		}
+		if (j == 0x0e) {
+			goto widep_out;
+		}
+		continue;
+widep_cmd:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			if (j == 0x4e) {
+				goto widep_out;
+			}
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			goto not_wide;
+		}
+		if (mbuf[1] != 0x02) {
+			goto not_wide;
+		}
+		if (mbuf[2] != 0x03) {
+			goto not_wide;
+		}
+		if (mbuf[3] != 0x01) {
+			goto not_wide;
+		}
+		m = 1;
+		m = m << i;
+		dev->wide_id[c] |= m;
+not_wide:
+		if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) ||
+		    ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) {
+			m = 1;
+			m = m << i;
+			if ((dev->async[c] & m) != 0) {
+			   goto set_sync;
+			}
+		}
+		continue;
+set_sync:
+		if (dev->sp[c][i] == 0x02) {
+		   synu[4]=0x0c;
+		   synuw[4]=0x0c;
+		} else {
+		   if (dev->sp[c][i] >= 0x03) {
+		      synu[4]=0x0a;
+		      synuw[4]=0x0a;
+		   }
+		}
+		tmport = wkport + 0x1b;
+		j = 0;
+		if ((m & dev->wide_id[c]) != 0) {
+			j |= 0x01;
+		}
+		outb(j, tmport);
+		tmport = wkport + 0x03;
+		outb(satn[0], tmport++);
+		outb(satn[1], tmport++);
+		outb(satn[2], tmport++);
+		outb(satn[3], tmport++);
+		outb(satn[4], tmport++);
+		outb(satn[5], tmport++);
+		tmport += 0x06;
+		outb(0, tmport);
+		tmport += 0x02;
+		outb(dev->id[c][i].devsp, tmport++);
+		outb(0, tmport++);
+		outb(satn[6], tmport++);
+		outb(satn[7], tmport++);
+		tmport += 0x03;
+		outb(satn[8], tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) {
+			continue;
+		}
+		while (inb(tmport) != 0x8e)
+			cpu_relax();
+try_sync:
+		j = 0;
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+
+		while ((inb(tmport) & 0x80) == 0) {
+			if ((inb(tmport) & 0x01) != 0) {
+				tmport -= 0x06;
+				if ((m & dev->wide_id[c]) != 0) {
+					if ((m & dev->ultra_map[c]) != 0) {
+						outb(synuw[j++], tmport);
+					} else {
+						outb(synw[j++], tmport);
+					}
+				} else {
+					if ((m & dev->ultra_map[c]) != 0) {
+						outb(synu[j++], tmport);
+					} else {
+						outb(synn[j++], tmport);
+					}
+				}
+				tmport += 0x06;
+			}
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		j = inb(tmport) & 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto try_sync;
+		}
+		continue;
+phase_outs:
+		tmport = wkport + 0x18;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00) {
+			if ((inb(tmport) & 0x01) != 0x00) {
+				tmport -= 0x06;
+				outb(0x00, tmport);
+				tmport += 0x06;
+			}
+			cpu_relax();
+		}
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_ins:
+		tmport = wkport + 0x14;
+		outb(0x06, tmport);
+		tmport += 0x04;
+		outb(0x20, tmport);
+		tmport += 0x07;
+		k = 0;
+phase_ins1:
+		j = inb(tmport);
+		if ((j & 0x01) != 0x00) {
+			tmport -= 0x06;
+			mbuf[k++] = inb(tmport);
+			tmport += 0x06;
+			goto phase_ins1;
+		}
+		if ((j & 0x80) == 0x00) {
+			goto phase_ins1;
+		}
+		tmport -= 0x08;
+		while ((inb(tmport) & 0x80) == 0x00);
+		j = inb(tmport);
+		if (j == 0x85) {
+			goto tar_dcons;
+		}
+		j &= 0x0f;
+		if (j == 0x0f) {
+			goto phase_ins;
+		}
+		if (j == 0x0a) {
+			goto phase_cmds;
+		}
+		if (j == 0x0e) {
+			goto phase_outs;
+		}
+		continue;
+phase_cmds:
+		tmport = wkport + 0x10;
+		outb(0x30, tmport);
+tar_dcons:
+		tmport = wkport + 0x14;
+		outb(0x00, tmport);
+		tmport += 0x04;
+		outb(0x08, tmport);
+		tmport += 0x07;
+		while ((inb(tmport) & 0x80) == 0x00)
+			cpu_relax();
+		tmport -= 0x08;
+		j = inb(tmport);
+		if (j != 0x16) {
+			continue;
+		}
+		if (mbuf[0] != 0x01) {
+			continue;
+		}
+		if (mbuf[1] != 0x03) {
+			continue;
+		}
+		if (mbuf[4] == 0x00) {
+			continue;
+		}
+		if (mbuf[3] > 0x64) {
+			continue;
+		}
+		if (mbuf[4] > 0x0e) {
+			mbuf[4] = 0x0e;
+		}
+		dev->id[c][i].devsp = mbuf[4];
+		if (mbuf[3] < 0x0c){
+			j = 0xb0;
+			goto set_syn_ok;
+		}
+		if ((mbuf[3] < 0x0d) && (rmb == 0)) {
+			j = 0xa0;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x1a) {
+			j = 0x20;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x33) {
+			j = 0x40;
+			goto set_syn_ok;
+		}
+		if (mbuf[3] < 0x4c) {
+			j = 0x50;
+			goto set_syn_ok;
+		}
+		j = 0x60;
+	      set_syn_ok:
+		dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j;
+#ifdef ED_DBGP		
+		printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp);
+#endif
+	}
+	tmport = wkport + 0x16;
+	outb(0x80, tmport);
+}
+
+module_init(atp870u_init);
+module_exit(atp870u_exit);
+
diff --git a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
new file mode 100644
index 0000000..89f43af
--- /dev/null
+++ b/drivers/scsi/atp870u.h
@@ -0,0 +1,66 @@
+#ifndef _ATP870U_H
+#define _ATP870U_H
+
+#include <linux/types.h>
+#include <linux/kdev_t.h>
+
+/* I/O Port */
+
+#define MAX_CDB 	12
+#define MAX_SENSE 	14
+#define qcnt	       	32
+#define ATP870U_SCATTER 	128
+#define ATP870U_CMDLUN  	1
+
+#define MAX_ADAPTER	8
+#define MAX_SCSI_ID	16
+#define ATP870U_MAX_SECTORS 128
+
+#define ATP885_DEVID 0x808A
+#define ATP880_DEVID1 0x8080
+#define ATP880_DEVID2 0x8081
+
+//#define ED_DBGP
+
+struct atp_unit
+{
+	unsigned long baseport;
+	unsigned long ioport[2];
+	unsigned long pciport[2];
+	unsigned long irq;
+	unsigned char last_cmd[2];
+	unsigned char in_snd[2];
+	unsigned char in_int[2];
+	unsigned char quhd[2];
+	unsigned char quend[2];
+	unsigned char global_map[2];
+	unsigned char chip_ver;
+	unsigned char scam_on;
+	unsigned char host_id[2];
+	unsigned int working[2];
+	unsigned short wide_id[2];
+	unsigned short active_id[2];
+	unsigned short ultra_map[2];
+	unsigned short async[2];
+	unsigned short dev_id;
+	unsigned char sp[2][16];
+	unsigned char r1f[2][16];		
+	struct scsi_cmnd *quereq[2][qcnt];
+	struct atp_id
+	{
+		unsigned char dirct;
+		unsigned char devsp;
+		unsigned char devtype;
+		unsigned long tran_len;
+		unsigned long last_len;
+		unsigned char *prd_pos;
+		unsigned char *prd_table;
+		dma_addr_t prdaddr;
+		struct scsi_cmnd *curr_req;
+	} id[2][16];
+    	struct Scsi_Host *host;
+    	struct pci_dev *pdev;
+	unsigned int unit;
+};
+
+#endif
diff --git a/drivers/scsi/blz1230.c b/drivers/scsi/blz1230.c
new file mode 100644
index 0000000..4cd9fcf
--- /dev/null
+++ b/drivers/scsi/blz1230.c
@@ -0,0 +1,352 @@
+/* blz1230.c: Driver for Blizzard 1230 SCSI IV Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ *    to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ *    routines in this file used to be inline!
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+#define MKIV 1
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ1230_ESP_ADDR 0x8000
+#define BLZ1230_DMA_ADDR 0x10000
+#define BLZ1230II_ESP_ADDR 0x10000
+#define BLZ1230II_DMA_ADDR 0x10021
+
+
+/* The Blizzard 1230 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ *  1) The data direction is controlled by the status of bit 31 (1 = write)
+ *  2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Program DMA by first latching the highest byte of the address/direction
+ * (i.e. bits 31-24 of the long word constructed as described in steps 1+2
+ * above). Then write each byte of the address/direction (starting with the
+ * top byte, working down) to the DMA address register.
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz1230_dma_registers {
+	volatile unsigned char dma_addr; 	/* DMA address      [0x0000] */
+	unsigned char dmapad2[0x7fff];
+	volatile unsigned char dma_latch; 	/* DMA latch        [0x8000] */
+};
+
+struct blz1230II_dma_registers {
+	volatile unsigned char dma_addr; 	/* DMA address      [0x0000] */
+	unsigned char dmapad2[0xf];
+	volatile unsigned char dma_latch; 	/* DMA latch        [0x0010] */
+};
+
+#define BLZ1230_DMA_WRITE 0x80000000
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int __init blz1230_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+	struct ESP_regs *eregs;
+	unsigned long board;
+
+#if MKIV
+#define REAL_BLZ1230_ID		ZORRO_PROD_PHASE5_BLIZZARD_1230_IV_1260
+#define REAL_BLZ1230_ESP_ADDR	BLZ1230_ESP_ADDR
+#define REAL_BLZ1230_DMA_ADDR	BLZ1230_DMA_ADDR
+#else
+#define REAL_BLZ1230_ID		ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060
+#define REAL_BLZ1230_ESP_ADDR	BLZ1230II_ESP_ADDR
+#define REAL_BLZ1230_DMA_ADDR	BLZ1230II_DMA_ADDR
+#endif
+
+	if ((z = zorro_find_device(REAL_BLZ1230_ID, z))) {
+	    board = z->resource.start;
+	    if (request_mem_region(board+REAL_BLZ1230_ESP_ADDR,
+				   sizeof(struct ESP_regs), "NCR53C9x")) {
+		/* Do some magic to figure out if the blizzard is
+		 * equipped with a SCSI controller
+		 */
+		address = ZTWO_VADDR(board);
+		eregs = (struct ESP_regs *)(address + REAL_BLZ1230_ESP_ADDR);
+		esp = esp_allocate(tpnt, (void *)board+REAL_BLZ1230_ESP_ADDR);
+
+		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+		udelay(5);
+		if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
+			goto err_out;
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = 0;
+		esp->dma_led_on = 0;
+		esp->dma_led_off = 0;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		/* SCSI chip speed */
+		esp->cfreq = 40000000;
+
+		/* The DMA registers on the Blizzard are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		esp->dregs = (void *)(address + REAL_BLZ1230_DMA_ADDR);
+	
+		/* ESP register base */
+		esp->eregs = eregs;
+
+		/* Set the command buffer */
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		esp->slot = board+REAL_BLZ1230_ESP_ADDR;
+		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+				 "Blizzard 1230 SCSI IV", esp->ehost))
+			goto err_out;
+
+		/* Figure out our scsi ID on the bus */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	    }
+	}
+	return 0;
+ 
+ err_out:
+	scsi_unregister(esp->ehost);
+	esp_deallocate(esp);
+	release_mem_region(board+REAL_BLZ1230_ESP_ADDR,
+			   sizeof(struct ESP_regs));
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the Blizzard DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	/* I don't think there's any limit on the Blizzard DMA. So we use what
+	 * the ESP chip can handle (24 bit).
+	 */
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0x1000000)
+		sz = 0x1000000;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+		custom.intreqr, custom.intenar));
+}
+
+void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+#if MKIV
+	struct blz1230_dma_registers *dregs = 
+		(struct blz1230_dma_registers *) (esp->dregs);
+#else
+	struct blz1230II_dma_registers *dregs = 
+		(struct blz1230II_dma_registers *) (esp->dregs);
+#endif
+
+	cache_clear(addr, length);
+
+	addr >>= 1;
+	addr &= ~(BLZ1230_DMA_WRITE);
+
+	/* First set latch */
+	dregs->dma_latch = (addr >> 24) & 0xff;
+
+	/* Then pump the address to the DMA address register */
+#if MKIV
+	dregs->dma_addr = (addr >> 24) & 0xff;
+#endif
+	dregs->dma_addr = (addr >> 16) & 0xff;
+	dregs->dma_addr = (addr >>  8) & 0xff;
+	dregs->dma_addr = (addr      ) & 0xff;
+}
+
+void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+#if MKIV
+	struct blz1230_dma_registers *dregs = 
+		(struct blz1230_dma_registers *) (esp->dregs);
+#else
+	struct blz1230II_dma_registers *dregs = 
+		(struct blz1230II_dma_registers *) (esp->dregs);
+#endif
+
+	cache_push(addr, length);
+
+	addr >>= 1;
+	addr |= BLZ1230_DMA_WRITE;
+
+	/* First set latch */
+	dregs->dma_latch = (addr >> 24) & 0xff;
+
+	/* Then pump the address to the DMA address register */
+#if MKIV
+	dregs->dma_addr = (addr >> 24) & 0xff;
+#endif
+	dregs->dma_addr = (addr >> 16) & 0xff;
+	dregs->dma_addr = (addr >>  8) & 0xff;
+	dregs->dma_addr = (addr      ) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+#define HOSTS_C
+
+int blz1230_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+	esp_deallocate((struct NCR_ESP *)instance->hostdata);
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-blz1230",
+	.proc_info		= esp_proc_info,
+	.name			= "Blizzard1230 SCSI IV",
+	.detect			= blz1230_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= blz1230_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/blz2060.c b/drivers/scsi/blz2060.c
new file mode 100644
index 0000000..c5221d0
--- /dev/null
+++ b/drivers/scsi/blz2060.c
@@ -0,0 +1,306 @@
+/* blz2060.c: Driver for Blizzard 2060 SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ *    to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ *    routines in this file used to be inline!
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define BLZ2060_ESP_ADDR 0x1ff00
+#define BLZ2060_DMA_ADDR 0x1ffe0
+
+
+/* The Blizzard 2060 DMA interface
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ * Only two things can be programmed in the Blizzard DMA:
+ *  1) The data direction is controlled by the status of bit 31 (1 = write)
+ *  2) The source/dest address (word aligned, shifted one right) in bits 30-0
+ *
+ * Figure out interrupt status by reading the ESP status byte.
+ */
+struct blz2060_dma_registers {
+	volatile unsigned char dma_led_ctrl;	/* DMA led control   [0x000] */
+	unsigned char dmapad1[0x0f];
+	volatile unsigned char dma_addr0; 	/* DMA address (MSB) [0x010] */
+	unsigned char dmapad2[0x03];
+	volatile unsigned char dma_addr1; 	/* DMA address       [0x014] */
+	unsigned char dmapad3[0x03];
+	volatile unsigned char dma_addr2; 	/* DMA address       [0x018] */
+	unsigned char dmapad4[0x03];
+	volatile unsigned char dma_addr3; 	/* DMA address (LSB) [0x01c] */
+};
+
+#define BLZ2060_DMA_WRITE 0x80000000
+
+/* DMA control bits */
+#define BLZ2060_DMA_LED    0x02		/* HD led control 1 = off */
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int __init blz2060_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+
+	if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_2060, z))) {
+	    unsigned long board = z->resource.start;
+	    if (request_mem_region(board+BLZ2060_ESP_ADDR,
+				   sizeof(struct ESP_regs), "NCR53C9x")) {
+		esp = esp_allocate(tpnt, (void *)board+BLZ2060_ESP_ADDR);
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = 0;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		/* SCSI chip speed */
+		esp->cfreq = 40000000;
+
+		/* The DMA registers on the Blizzard are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		address = (unsigned long)ZTWO_VADDR(board);
+		esp->dregs = (void *)(address + BLZ2060_DMA_ADDR);
+
+		/* ESP register base */
+		esp->eregs = (struct ESP_regs *)(address + BLZ2060_ESP_ADDR);
+		
+		/* Set the command buffer */
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+			    "Blizzard 2060 SCSI", esp->ehost);
+
+		/* Figure out our scsi ID on the bus */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	    }
+	}
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the Blizzard DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	/* I don't think there's any limit on the Blizzard DMA. So we use what
+	 * the ESP chip can handle (24 bit).
+	 */
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0x1000000)
+		sz = 0x1000000;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+		custom.intreqr, custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct blz2060_dma_registers *dregs = 
+		(struct blz2060_dma_registers *) (esp->dregs);
+
+	cache_clear(addr, length);
+
+	addr >>= 1;
+	addr &= ~(BLZ2060_DMA_WRITE);
+	dregs->dma_addr3 = (addr      ) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct blz2060_dma_registers *dregs = 
+		(struct blz2060_dma_registers *) (esp->dregs);
+
+	cache_push(addr, length);
+
+	addr >>= 1;
+	addr |= BLZ2060_DMA_WRITE;
+	dregs->dma_addr3 = (addr      ) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+	((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl =
+		BLZ2060_DMA_LED;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+	((struct blz2060_dma_registers *) (esp->dregs))->dma_led_ctrl = 0;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+#define HOSTS_C
+
+int blz2060_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+	esp_deallocate((struct NCR_ESP *)instance->hostdata);
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-blz2060",
+	.proc_info		= esp_proc_info,
+	.name			= "Blizzard2060 SCSI",
+	.detect			= blz2060_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= blz2060_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/bvme6000.c b/drivers/scsi/bvme6000.c
new file mode 100644
index 0000000..29c7ed3
--- /dev/null
+++ b/drivers/scsi/bvme6000.c
@@ -0,0 +1,78 @@
+/*
+ * Detection routine for the NCR53c710 based BVME6000 SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/zorro.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/bvme6000hw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "53c7xx.h"
+#include "bvme6000.h"
+
+#include<linux/stat.h>
+
+
+int bvme6000_scsi_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    int clock;
+    long long options;
+
+    if (called)
+	return 0;
+    if (!MACH_IS_BVME6000)
+	return 0;
+
+    tpnt->proc_name = "BVME6000";
+
+    options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+    clock = 40000000;	/* 66MHz SCSI Clock */
+
+    ncr53c7xx_init(tpnt, 0, 710, (unsigned long)BVME_NCR53C710_BASE,
+			0, BVME_IRQ_SCSI, DMA_NONE,
+			options, clock);
+    called = 1;
+    return 1;
+}
+
+static int bvme6000_scsi_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name			= "BVME6000 NCR53c710 SCSI",
+	.detect			= bvme6000_scsi_detect,
+	.release		= bvme6000_scsi_release,
+	.queuecommand		= NCR53c7xx_queue_command,
+	.abort			= NCR53c7xx_abort,
+	.reset			= NCR53c7xx_reset,
+	.can_queue		= 24,
+	.this_id		= 7,
+	.sg_tablesize		= 63,
+	.cmd_per_lun		= 3,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/bvme6000.h b/drivers/scsi/bvme6000.h
new file mode 100644
index 0000000..49b6bbb
--- /dev/null
+++ b/drivers/scsi/bvme6000.h
@@ -0,0 +1,24 @@
+#ifndef BVME6000_SCSI_H
+#define BVME6000_SCSI_H
+
+#include <linux/types.h>
+
+int bvme6000_scsi_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (struct Scsi_Host *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#include <scsi/scsicam.h>
+
+#endif /* BVME6000_SCSI_H */
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
new file mode 100644
index 0000000..d625fde
--- /dev/null
+++ b/drivers/scsi/constants.c
@@ -0,0 +1,1448 @@
+/* 
+ * ASCII values for a number of symbolic constants, printing functions,
+ * etc.
+ * Additions for SCSI 2 and Linux 2.2.x by D. Gilbert (990422)
+ * Additions for SCSI 3+ (SPC-3 T10/1416-D Rev 07 3 May 2002)
+ *   by D. Gilbert and aeb (20020609)
+ * Additions for SPC-3 T10/1416-D Rev 21 22 Sept 2004, D. Gilbert 20041025
+ */
+
+#include <linux/config.h>
+#include <linux/blkdev.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_eh.h>
+
+
+
+/* Commands with service actions that change the command name */
+#define MAINTENANCE_IN 0xa3
+#define MAINTENANCE_OUT 0xa4
+#define SERVICE_ACTION_IN_12 0xab
+#define SERVICE_ACTION_OUT_12 0xa9
+#define SERVICE_ACTION_IN_16 0x9e
+#define SERVICE_ACTION_OUT_16 0x9f
+#define VARIABLE_LENGTH_CMD 0x7f
+
+
+
+#ifdef CONFIG_SCSI_CONSTANTS
+static const char * cdb_byte0_names[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
+/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
+	    "Reasssign Blocks",
+/* 08-0d */ "Read (6)", NULL, "Write (6)", "Seek (6)", NULL, NULL,
+/* 0e-12 */ NULL, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ "Verify (6)", "Recover Buffered Data", "Mode Select (6)",
+	    "Reserve (6)",
+/* 17-1a */ "Release (6)", "Copy", "Erase", "Mode Sense (6)", 
+/* 1b-1d */ "Start/Stop Unit", "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", NULL,
+/* 20-22 */  NULL, NULL, NULL,
+/* 23-28 */ "Read Format Capacities", "Set Window",
+	    "Read Capacity (10)", NULL, NULL, "Read (10)", 
+/* 29-2d */ "Read Generation", "Write (10)", "Seek (10)", "Erase (10)", 
+            "Read updated block", 
+/* 2e-31 */ "Write Verify (10)", "Verify (10)", "Search High", "Search Equal", 
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch/Read Position", 
+/* 35-37 */ "Synchronize Cache (10)", "Lock/Unlock Cache (10)",
+	    "Read Defect Data(10)", 
+/* 38-3c */ "Medium Scan", "Compare", "Copy Verify", "Write Buffer", 
+            "Read Buffer", 
+/* 3d-3f */ "Update Block", "Read Long (10)",  "Write Long (10)",
+/* 40-41 */ "Change Definition", "Write Same (10)",
+/* 42-48 */ "Read sub-channel", "Read TOC/PMA/ATIP", "Read density support",
+            "Play audio (10)", "Get configuration", "Play audio msf",
+            "Play audio track/index",
+/* 49-4f */ "Play track relative (10)", "Get event status notification",
+            "Pause/resume", "Log Select", "Log Sense", "Stop play/scan",
+            NULL,
+/* 50-55 */ "Xdwrite", "Xpwrite, Read disk info", "Xdread, Read track info",
+            "Reserve track", "Send OPC info", "Mode Select (10)",
+/* 56-5b */ "Reserve (10)", "Release (10)", "Repair track", "Read master cue",
+            "Mode Sense (10)", "Close track/session",
+/* 5c-5f */ "Read buffer capacity", "Send cue sheet", "Persistent reserve in",
+            "Persistent reserve out",
+/* 60-67 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+/* 68-6f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+/* 70-77 */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+/* 78-7f */ NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Variable length",
+/* 80-84 */ "Xdwrite (16)", "Rebuild (16)", "Regenerate (16)", "Extended copy",
+            "Receive copy results",
+/* 85-89 */ "Memory Export In (16)", "Access control in", "Access control out",
+            "Read (16)", "Memory Export Out (16)",
+/* 8a-8f */ "Write (16)", NULL, "Read attributes", "Write attributes",
+            "Write and verify (16)", "Verify (16)",
+/* 90-94 */ "Pre-fetch (16)", "Synchronize cache (16)",
+            "Lock/unlock cache (16)", "Write same (16)", NULL,
+/* 95-99 */ NULL, NULL, NULL, NULL, NULL,
+/* 9a-9f */ NULL, NULL, NULL, NULL, "Service action in (16)",
+            "Service action out (16)",
+/* a0-a5 */ "Report luns", "Blank", "Send event", "Maintenance in",
+            "Maintenance out", "Move medium/play audio(12)",
+/* a6-a9 */ "Exchange medium", "Move medium attached", "Read(12)",
+            "Play track relative(12)",
+/* aa-ae */ "Write(12)", NULL, "Erase(12), Get Performance",
+            "Read DVD structure", "Write and verify(12)",
+/* af-b1 */ "Verify(12)", "Search data high(12)", "Search data equal(12)",
+/* b2-b4 */ "Search data low(12)", "Set limits(12)",
+            "Read element status attached",
+/* b5-b6 */ "Request volume element address", "Send volume tag, set streaming",
+/* b7-b9 */ "Read defect data(12)", "Read element status", "Read CD msf",
+/* ba-bc */ "Redundancy group (in), Scan",
+            "Redundancy group (out), Set cd-rom speed", "Spare in, Play cd",
+/* bd-bf */ "Spare out, Mechanism status", "Volume set in, Read cd",
+            "Volume set out, Send DVD structure",
+};
+
+struct value_name_pair {
+	int value;
+	const char * name;
+};
+
+static const struct value_name_pair maint_in_arr[] = {
+	{0x5, "Report device identifier"},
+	{0xa, "Report target port groups"},
+	{0xb, "Report aliases"},
+	{0xc, "Report supported operation codes"},
+	{0xd, "Report supported task management functions"},
+	{0xe, "Report priority"},
+};
+#define MAINT_IN_SZ \
+        (int)(sizeof(maint_in_arr) / sizeof(maint_in_arr[0]))
+
+static const struct value_name_pair maint_out_arr[] = {
+	{0x6, "Set device identifier"},
+	{0xa, "Set target port groups"},
+	{0xb, "Change aliases"},
+	{0xe, "Set priority"},
+};
+#define MAINT_OUT_SZ \
+        (int)(sizeof(maint_out_arr) / sizeof(maint_out_arr[0]))
+
+static const struct value_name_pair serv_in12_arr[] = {
+	{0x1, "Read media serial number"},
+};
+#define SERV_IN12_SZ  \
+        (int)(sizeof(serv_in12_arr) / sizeof(serv_in12_arr[0]))
+
+static const struct value_name_pair serv_out12_arr[] = {
+	{-1, "dummy entry"},
+};
+#define SERV_OUT12_SZ \
+        (int)(sizeof(serv_out12_arr) / sizeof(serv_in12_arr[0]))
+
+static const struct value_name_pair serv_in16_arr[] = {
+	{0x10, "Read capacity(16)"},
+	{0x11, "Read long(16)"},
+};
+#define SERV_IN16_SZ  \
+        (int)(sizeof(serv_in16_arr) / sizeof(serv_in16_arr[0]))
+
+static const struct value_name_pair serv_out16_arr[] = {
+	{0x11, "Write long(16)"},
+	{0x1f, "Notify data transfer device(16)"},
+};
+#define SERV_OUT16_SZ \
+        (int)(sizeof(serv_out16_arr) / sizeof(serv_in16_arr[0]))
+
+static const struct value_name_pair variable_length_arr[] = {
+	{0x1, "Rebuild(32)"},
+	{0x2, "Regenerate(32)"},
+	{0x3, "Xdread(32)"},
+	{0x4, "Xdwrite(32)"},
+	{0x5, "Xdwrite extended(32)"},
+	{0x6, "Xpwrite(32)"},
+	{0x7, "Xdwriteread(32)"},
+	{0x8, "Xdwrite extended(64)"},
+	{0x9, "Read(32)"},
+	{0xa, "Verify(32)"},
+	{0xb, "Write(32)"},
+	{0xc, "Write an verify(32)"},
+	{0xd, "Write same(32)"},
+	{0x8801, "Format OSD"},
+	{0x8802, "Create (osd)"},
+	{0x8803, "List (osd)"},
+	{0x8805, "Read (osd)"},
+	{0x8806, "Write (osd)"},
+	{0x8807, "Append (osd)"},
+	{0x8808, "Flush (osd)"},
+	{0x880a, "Remove (osd)"},
+	{0x880b, "Create partition (osd)"},
+	{0x880c, "Remove partition (osd)"},
+	{0x880e, "Get attributes (osd)"},
+	{0x880f, "Set attributes (osd)"},
+	{0x8812, "Create and write (osd)"},
+	{0x8815, "Create collection (osd)"},
+	{0x8816, "Remove collection (osd)"},
+	{0x8817, "List collection (osd)"},
+	{0x8818, "Set key (osd)"},
+	{0x8819, "Set master key (osd)"},
+	{0x881a, "Flush collection (osd)"},
+	{0x881b, "Flush partition (osd)"},
+	{0x881c, "Flush OSD"},
+	{0x8f7e, "Perform SCSI command (osd)"},
+	{0x8f7f, "Perform task management function (osd)"},
+};
+#define VARIABLE_LENGTH_SZ \
+        (int)(sizeof(variable_length_arr) / sizeof(variable_length_arr[0]))
+
+static const char * get_sa_name(const struct value_name_pair * arr,
+			        int arr_sz, int service_action)
+{
+	int k;
+
+	for (k = 0; k < arr_sz; ++k, ++arr) {
+		if (service_action == arr->value)
+			break;
+	}
+	return (k < arr_sz) ? arr->name : NULL;
+}
+
+/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
+static void print_opcode_name(unsigned char * cdbp, int cdb_len,
+			      int start_of_line)
+{
+	int sa, len, cdb0;
+	const char * name;
+	const char * leadin = start_of_line ? KERN_INFO : "";
+
+	cdb0 = cdbp[0];
+	switch(cdb0) {
+	case VARIABLE_LENGTH_CMD:
+		len = cdbp[7] + 8;
+		if (len < 10) {
+			printk("%sshort variable length command, "
+			       "len=%d ext_len=%d", leadin, len, cdb_len);
+			break;
+		}
+		sa = (cdbp[8] << 8) + cdbp[9];
+		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
+		if (name) {
+			printk("%s%s", leadin, name);
+			if ((cdb_len > 0) && (len != cdb_len))
+				printk(", in_cdb_len=%d, ext_len=%d",
+				       len, cdb_len);
+		} else {
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+			if ((cdb_len > 0) && (len != cdb_len))
+				printk(", in_cdb_len=%d, ext_len=%d",
+				       len, cdb_len);
+		}
+		break;
+	case MAINTENANCE_IN:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	case MAINTENANCE_OUT:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	case SERVICE_ACTION_IN_12:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	case SERVICE_ACTION_OUT_12:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	case SERVICE_ACTION_IN_16:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	case SERVICE_ACTION_OUT_16:
+		sa = cdbp[1] & 0x1f;
+		name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
+		if (name)
+			printk("%s%s", leadin, name);
+		else
+			printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	default:
+		if (cdb0 < 0xc0) {
+			name = cdb_byte0_names[cdb0];
+			if (name)
+				printk("%s%s", leadin, name);
+			else
+				printk("%scdb[0]=0x%x (reserved)",
+				       leadin, cdb0);
+		} else
+			printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+		break;
+	}
+}
+
+#else /* ifndef CONFIG_SCSI_CONSTANTS */
+
+static void print_opcode_name(unsigned char * cdbp, int cdb_len,
+			      int start_of_line)
+{
+	int sa, len, cdb0;
+	const char * leadin = start_of_line ? KERN_INFO : "";
+
+	cdb0 = cdbp[0];
+	switch(cdb0) {
+	case VARIABLE_LENGTH_CMD:
+		len = cdbp[7] + 8;
+		if (len < 10) {
+			printk("%sshort opcode=0x%x command, len=%d "
+			       "ext_len=%d", leadin, cdb0, len, cdb_len);
+			break;
+		}
+		sa = (cdbp[8] << 8) + cdbp[9];
+		printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		if (len != cdb_len)
+			printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
+		break;
+	case MAINTENANCE_IN:
+	case MAINTENANCE_OUT:
+	case SERVICE_ACTION_IN_12:
+	case SERVICE_ACTION_OUT_12:
+	case SERVICE_ACTION_IN_16:
+	case SERVICE_ACTION_OUT_16:
+		sa = cdbp[1] & 0x1f;
+		printk("%scdb[0]=0x%x, sa=0x%x", leadin, cdb0, sa);
+		break;
+	default:
+		if (cdb0 < 0xc0)
+			printk("%scdb[0]=0x%x", leadin, cdb0);
+		else
+			printk("%scdb[0]=0x%x (vendor)", leadin, cdb0);
+		break;
+	}
+}
+#endif  
+
+void __scsi_print_command(unsigned char *command)
+{
+	int k, len;
+
+	print_opcode_name(command, 0, 1);
+	if (VARIABLE_LENGTH_CMD == command[0])
+		len = command[7] + 8;
+	else
+		len = COMMAND_SIZE(command[0]);
+	/* print out all bytes in cdb */
+	for (k = 0; k < len; ++k) 
+		printk(" %02x", command[k]);
+	printk("\n");
+}
+EXPORT_SYMBOL(__scsi_print_command);
+
+/* This function (perhaps with the addition of peripheral device type)
+ * is more approriate than __scsi_print_command(). Perhaps that static
+ * can be dropped later if it replaces the __scsi_print_command version.
+ */
+static void scsi_print_cdb(unsigned char *cdb, int cdb_len, int start_of_line)
+{
+	int k;
+
+	print_opcode_name(cdb, cdb_len, start_of_line);
+	/* print out all bytes in cdb */
+	printk(":");
+	for (k = 0; k < cdb_len; ++k) 
+		printk(" %02x", cdb[k]);
+	printk("\n");
+}
+
+/**
+ *
+ *	print_status - print scsi status description
+ *	@scsi_status: scsi status value
+ *
+ *	If the status is recognized, the description is printed.
+ *	Otherwise "Unknown status" is output. No trailing space.
+ *	If CONFIG_SCSI_CONSTANTS is not set, then print status in hex
+ *	(e.g. "0x2" for Check Condition).
+ **/
+void
+scsi_print_status(unsigned char scsi_status) {
+#ifdef CONFIG_SCSI_CONSTANTS
+	const char * ccp;
+
+	switch (scsi_status) {
+	case 0:    ccp = "Good"; break;
+	case 0x2:  ccp = "Check Condition"; break;
+	case 0x4:  ccp = "Condition Met"; break;
+	case 0x8:  ccp = "Busy"; break;
+	case 0x10: ccp = "Intermediate"; break;
+	case 0x14: ccp = "Intermediate-Condition Met"; break;
+	case 0x18: ccp = "Reservation Conflict"; break;
+	case 0x22: ccp = "Command Terminated"; break;	/* obsolete */
+	case 0x28: ccp = "Task set Full"; break;	/* was: Queue Full */
+	case 0x30: ccp = "ACA Active"; break;
+	case 0x40: ccp = "Task Aborted"; break;
+	default:   ccp = "Unknown status";
+	}
+	printk(KERN_INFO "%s", ccp);
+#else
+	printk(KERN_INFO "0x%0x", scsi_status);
+#endif
+}
+EXPORT_SYMBOL(scsi_print_status);
+
+#ifdef CONFIG_SCSI_CONSTANTS
+
+struct error_info {
+	unsigned short code12;	/* 0x0302 looks better than 0x03,0x02 */
+	const char * text;
+};
+
+static struct error_info additional[] =
+{
+	{0x0000, "No additional sense information"},
+	{0x0001, "Filemark detected"},
+	{0x0002, "End-of-partition/medium detected"},
+	{0x0003, "Setmark detected"},
+	{0x0004, "Beginning-of-partition/medium detected"},
+	{0x0005, "End-of-data detected"},
+	{0x0006, "I/O process terminated"},
+	{0x0011, "Audio play operation in progress"},
+	{0x0012, "Audio play operation paused"},
+	{0x0013, "Audio play operation successfully completed"},
+	{0x0014, "Audio play operation stopped due to error"},
+	{0x0015, "No current audio status to return"},
+	{0x0016, "Operation in progress"},
+	{0x0017, "Cleaning requested"},
+	{0x0018, "Erase operation in progress"},
+	{0x0019, "Locate operation in progress"},
+	{0x001A, "Rewind operation in progress"},
+	{0x001B, "Set capacity operation in progress"},
+	{0x001C, "Verify operation in progress"},
+
+	{0x0100, "No index/sector signal"},
+
+	{0x0200, "No seek complete"},
+
+	{0x0300, "Peripheral device write fault"},
+	{0x0301, "No write current"},
+	{0x0302, "Excessive write errors"},
+
+	{0x0400, "Logical unit not ready, cause not reportable"},
+	{0x0401, "Logical unit is in process of becoming ready"},
+	{0x0402, "Logical unit not ready, initializing cmd. required"},
+	{0x0403, "Logical unit not ready, manual intervention required"},
+	{0x0404, "Logical unit not ready, format in progress"},
+	{0x0405, "Logical unit not ready, rebuild in progress"},
+	{0x0406, "Logical unit not ready, recalculation in progress"},
+	{0x0407, "Logical unit not ready, operation in progress"},
+	{0x0408, "Logical unit not ready, long write in progress"},
+	{0x0409, "Logical unit not ready, self-test in progress"},
+	{0x040A, "Logical unit not accessible, asymmetric access state "
+	 "transition"},
+	{0x040B, "Logical unit not accessible, target port in standby state"},
+	{0x040C, "Logical unit not accessible, target port in unavailable "
+	 "state"},
+	{0x0410, "Logical unit not ready, auxiliary memory not accessible"},
+	{0x0411, "Logical unit not ready, notify (enable spinup) required"},
+	{0x0412, "Logical unit not ready, offline"},
+
+	{0x0500, "Logical unit does not respond to selection"},
+
+	{0x0600, "No reference position found"},
+
+	{0x0700, "Multiple peripheral devices selected"},
+
+	{0x0800, "Logical unit communication failure"},
+	{0x0801, "Logical unit communication time-out"},
+	{0x0802, "Logical unit communication parity error"},
+	{0x0803, "Logical unit communication CRC error (Ultra-DMA/32)"},
+	{0x0804, "Unreachable copy target"},
+
+	{0x0900, "Track following error"},
+	{0x0901, "Tracking servo failure"},
+	{0x0902, "Focus servo failure"},
+	{0x0903, "Spindle servo failure"},
+	{0x0904, "Head select fault"},
+
+	{0x0A00, "Error log overflow"},
+
+	{0x0B00, "Warning"},
+	{0x0B01, "Warning - specified temperature exceeded"},
+	{0x0B02, "Warning - enclosure degraded"},
+
+	{0x0C00, "Write error"},
+	{0x0C01, "Write error - recovered with auto reallocation"},
+	{0x0C02, "Write error - auto reallocation failed"},
+	{0x0C03, "Write error - recommend reassignment"},
+	{0x0C04, "Compression check miscompare error"},
+	{0x0C05, "Data expansion occurred during compression"},
+	{0x0C06, "Block not compressible"},
+	{0x0C07, "Write error - recovery needed"},
+	{0x0C08, "Write error - recovery failed"},
+	{0x0C09, "Write error - loss of streaming"},
+	{0x0C0A, "Write error - padding blocks added"},
+	{0x0C0B, "Auxiliary memory write error"},
+	{0x0C0C, "Write error - unexpected unsolicited data"},
+	{0x0C0D, "Write error - not enough unsolicited data"},
+
+	{0x0D00, "Error detected by third party temporary initiator"},
+	{0x0D01, "Third party device failure"},
+	{0x0D02, "Copy target device not reachable"},
+	{0x0D03, "Incorrect copy target device type"},
+	{0x0D04, "Copy target device data underrun"},
+	{0x0D05, "Copy target device data overrun"},
+
+	{0x0E00, "Invalid information unit"},
+	{0x0E01, "Information unit too short"},
+	{0x0E02, "Information unit too long"},
+
+	{0x1000, "Id CRC or ECC error"},
+	{0x1001, "Data block guard check failed"},
+	{0x1002, "Data block application tag check failed"},
+	{0x1003, "Data block reference tag check failed"},
+
+	{0x1100, "Unrecovered read error"},
+	{0x1101, "Read retries exhausted"},
+	{0x1102, "Error too long to correct"},
+	{0x1103, "Multiple read errors"},
+	{0x1104, "Unrecovered read error - auto reallocate failed"},
+	{0x1105, "L-EC uncorrectable error"},
+	{0x1106, "CIRC unrecovered error"},
+	{0x1107, "Data re-synchronization error"},
+	{0x1108, "Incomplete block read"},
+	{0x1109, "No gap found"},
+	{0x110A, "Miscorrected error"},
+	{0x110B, "Unrecovered read error - recommend reassignment"},
+	{0x110C, "Unrecovered read error - recommend rewrite the data"},
+	{0x110D, "De-compression CRC error"},
+	{0x110E, "Cannot decompress using declared algorithm"},
+	{0x110F, "Error reading UPC/EAN number"},
+	{0x1110, "Error reading ISRC number"},
+	{0x1111, "Read error - loss of streaming"},
+	{0x1112, "Auxiliary memory read error"},
+	{0x1113, "Read error - failed retransmission request"},
+
+	{0x1200, "Address mark not found for id field"},
+
+	{0x1300, "Address mark not found for data field"},
+
+	{0x1400, "Recorded entity not found"},
+	{0x1401, "Record not found"},
+	{0x1402, "Filemark or setmark not found"},
+	{0x1403, "End-of-data not found"},
+	{0x1404, "Block sequence error"},
+	{0x1405, "Record not found - recommend reassignment"},
+	{0x1406, "Record not found - data auto-reallocated"},
+	{0x1407, "Locate operation failure"},
+
+	{0x1500, "Random positioning error"},
+	{0x1501, "Mechanical positioning error"},
+	{0x1502, "Positioning error detected by read of medium"},
+
+	{0x1600, "Data synchronization mark error"},
+	{0x1601, "Data sync error - data rewritten"},
+	{0x1602, "Data sync error - recommend rewrite"},
+	{0x1603, "Data sync error - data auto-reallocated"},
+	{0x1604, "Data sync error - recommend reassignment"},
+
+	{0x1700, "Recovered data with no error correction applied"},
+	{0x1701, "Recovered data with retries"},
+	{0x1702, "Recovered data with positive head offset"},
+	{0x1703, "Recovered data with negative head offset"},
+	{0x1704, "Recovered data with retries and/or circ applied"},
+	{0x1705, "Recovered data using previous sector id"},
+	{0x1706, "Recovered data without ECC - data auto-reallocated"},
+	{0x1707, "Recovered data without ECC - recommend reassignment"},
+	{0x1708, "Recovered data without ECC - recommend rewrite"},
+	{0x1709, "Recovered data without ECC - data rewritten"},
+
+	{0x1800, "Recovered data with error correction applied"},
+	{0x1801, "Recovered data with error corr. & retries applied"},
+	{0x1802, "Recovered data - data auto-reallocated"},
+	{0x1803, "Recovered data with CIRC"},
+	{0x1804, "Recovered data with L-EC"},
+	{0x1805, "Recovered data - recommend reassignment"},
+	{0x1806, "Recovered data - recommend rewrite"},
+	{0x1807, "Recovered data with ECC - data rewritten"},
+	{0x1808, "Recovered data with linking"},
+
+	{0x1900, "Defect list error"},
+	{0x1901, "Defect list not available"},
+	{0x1902, "Defect list error in primary list"},
+	{0x1903, "Defect list error in grown list"},
+
+	{0x1A00, "Parameter list length error"},
+
+	{0x1B00, "Synchronous data transfer error"},
+
+	{0x1C00, "Defect list not found"},
+	{0x1C01, "Primary defect list not found"},
+	{0x1C02, "Grown defect list not found"},
+
+	{0x1D00, "Miscompare during verify operation"},
+
+	{0x1E00, "Recovered id with ECC correction"},
+
+	{0x1F00, "Partial defect list transfer"},
+
+	{0x2000, "Invalid command operation code"},
+	{0x2001, "Access denied - initiator pending-enrolled"},
+	{0x2002, "Access denied - no access rights"},
+	{0x2003, "Access denied - invalid mgmt id key"},
+	{0x2004, "Illegal command while in write capable state"},
+	{0x2005, "Obsolete"},
+	{0x2006, "Illegal command while in explicit address mode"},
+	{0x2007, "Illegal command while in implicit address mode"},
+	{0x2008, "Access denied - enrollment conflict"},
+	{0x2009, "Access denied - invalid LU identifier"},
+	{0x200A, "Access denied - invalid proxy token"},
+	{0x200B, "Access denied - ACL LUN conflict"},
+
+	{0x2100, "Logical block address out of range"},
+	{0x2101, "Invalid element address"},
+	{0x2102, "Invalid address for write"},
+
+	{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
+
+	{0x2400, "Invalid field in cdb"},
+	{0x2401, "CDB decryption error"},
+	{0x2404, "Security audit value frozen"},
+	{0x2405, "Security working key frozen"},
+	{0x2406, "Nonce not unique"},
+	{0x2407, "Nonce timestamp out of range"},
+
+	{0x2500, "Logical unit not supported"},
+
+	{0x2600, "Invalid field in parameter list"},
+	{0x2601, "Parameter not supported"},
+	{0x2602, "Parameter value invalid"},
+	{0x2603, "Threshold parameters not supported"},
+	{0x2604, "Invalid release of persistent reservation"},
+	{0x2605, "Data decryption error"},
+	{0x2606, "Too many target descriptors"},
+	{0x2607, "Unsupported target descriptor type code"},
+	{0x2608, "Too many segment descriptors"},
+	{0x2609, "Unsupported segment descriptor type code"},
+	{0x260A, "Unexpected inexact segment"},
+	{0x260B, "Inline data length exceeded"},
+	{0x260C, "Invalid operation for copy source or destination"},
+	{0x260D, "Copy segment granularity violation"},
+	{0x260E, "Invalid parameter while port is enabled"},
+	{0x260F, "Invalid data-out buffer integrity"},
+
+	{0x2700, "Write protected"},
+	{0x2701, "Hardware write protected"},
+	{0x2702, "Logical unit software write protected"},
+	{0x2703, "Associated write protect"},
+	{0x2704, "Persistent write protect"},
+	{0x2705, "Permanent write protect"},
+	{0x2706, "Conditional write protect"},
+
+	{0x2800, "Not ready to ready change, medium may have changed"},
+	{0x2801, "Import or export element accessed"},
+
+	{0x2900, "Power on, reset, or bus device reset occurred"},
+	{0x2901, "Power on occurred"},
+	{0x2902, "Scsi bus reset occurred"},
+	{0x2903, "Bus device reset function occurred"},
+	{0x2904, "Device internal reset"},
+	{0x2905, "Transceiver mode changed to single-ended"},
+	{0x2906, "Transceiver mode changed to lvd"},
+	{0x2907, "I_T nexus loss occurred"},
+
+	{0x2A00, "Parameters changed"},
+	{0x2A01, "Mode parameters changed"},
+	{0x2A02, "Log parameters changed"},
+	{0x2A03, "Reservations preempted"},
+	{0x2A04, "Reservations released"},
+	{0x2A05, "Registrations preempted"},
+	{0x2A06, "Asymmetric access state changed"},
+	{0x2A07, "Implicit asymmetric access state transition failed"},
+	{0x2A08, "Priority changed"},
+	{0x2A09, "Capacity data has changed"},
+
+	{0x2B00, "Copy cannot execute since host cannot disconnect"},
+
+	{0x2C00, "Command sequence error"},
+	{0x2C01, "Too many windows specified"},
+	{0x2C02, "Invalid combination of windows specified"},
+	{0x2C03, "Current program area is not empty"},
+	{0x2C04, "Current program area is empty"},
+	{0x2C05, "Illegal power condition request"},
+	{0x2C06, "Persistent prevent conflict"},
+	{0x2C07, "Previous busy status"},
+	{0x2C08, "Previous task set full status"},
+	{0x2C09, "Previous reservation conflict status"},
+	{0x2C0A, "Partition or collection contains user objects"},
+	{0x2C0B, "Not reserved"},
+
+	{0x2D00, "Overwrite error on update in place"},
+
+	{0x2E00, "Insufficient time for operation"},
+
+	{0x2F00, "Commands cleared by another initiator"},
+
+	{0x3000, "Incompatible medium installed"},
+	{0x3001, "Cannot read medium - unknown format"},
+	{0x3002, "Cannot read medium - incompatible format"},
+	{0x3003, "Cleaning cartridge installed"},
+	{0x3004, "Cannot write medium - unknown format"},
+	{0x3005, "Cannot write medium - incompatible format"},
+	{0x3006, "Cannot format medium - incompatible medium"},
+	{0x3007, "Cleaning failure"},
+	{0x3008, "Cannot write - application code mismatch"},
+	{0x3009, "Current session not fixated for append"},
+	{0x300A, "Cleaning request rejected"},
+	{0x300C, "WORM medium, overwrite attempted"},
+	{0x3010, "Medium not formatted"},
+
+	{0x3100, "Medium format corrupted"},
+	{0x3101, "Format command failed"},
+	{0x3102, "Zoned formatting failed due to spare linking"},
+
+	{0x3200, "No defect spare location available"},
+	{0x3201, "Defect list update failure"},
+
+	{0x3300, "Tape length error"},
+
+	{0x3400, "Enclosure failure"},
+
+	{0x3500, "Enclosure services failure"},
+	{0x3501, "Unsupported enclosure function"},
+	{0x3502, "Enclosure services unavailable"},
+	{0x3503, "Enclosure services transfer failure"},
+	{0x3504, "Enclosure services transfer refused"},
+	{0x3505, "Enclosure services checksum error"},
+
+	{0x3600, "Ribbon, ink, or toner failure"},
+
+	{0x3700, "Rounded parameter"},
+
+	{0x3800, "Event status notification"},
+	{0x3802, "Esn - power management class event"},
+	{0x3804, "Esn - media class event"},
+	{0x3806, "Esn - device busy class event"},
+
+	{0x3900, "Saving parameters not supported"},
+
+	{0x3A00, "Medium not present"},
+	{0x3A01, "Medium not present - tray closed"},
+	{0x3A02, "Medium not present - tray open"},
+	{0x3A03, "Medium not present - loadable"},
+	{0x3A04, "Medium not present - medium auxiliary memory accessible"},
+
+	{0x3B00, "Sequential positioning error"},
+	{0x3B01, "Tape position error at beginning-of-medium"},
+	{0x3B02, "Tape position error at end-of-medium"},
+	{0x3B03, "Tape or electronic vertical forms unit not ready"},
+	{0x3B04, "Slew failure"},
+	{0x3B05, "Paper jam"},
+	{0x3B06, "Failed to sense top-of-form"},
+	{0x3B07, "Failed to sense bottom-of-form"},
+	{0x3B08, "Reposition error"},
+	{0x3B09, "Read past end of medium"},
+	{0x3B0A, "Read past beginning of medium"},
+	{0x3B0B, "Position past end of medium"},
+	{0x3B0C, "Position past beginning of medium"},
+	{0x3B0D, "Medium destination element full"},
+	{0x3B0E, "Medium source element empty"},
+	{0x3B0F, "End of medium reached"},
+	{0x3B11, "Medium magazine not accessible"},
+	{0x3B12, "Medium magazine removed"},
+	{0x3B13, "Medium magazine inserted"},
+	{0x3B14, "Medium magazine locked"},
+	{0x3B15, "Medium magazine unlocked"},
+	{0x3B16, "Mechanical positioning or changer error"},
+	{0x3B17, "Read past end of user object"},
+
+	{0x3D00, "Invalid bits in identify message"},
+
+	{0x3E00, "Logical unit has not self-configured yet"},
+	{0x3E01, "Logical unit failure"},
+	{0x3E02, "Timeout on logical unit"},
+	{0x3E03, "Logical unit failed self-test"},
+	{0x3E04, "Logical unit unable to update self-test log"},
+
+	{0x3F00, "Target operating conditions have changed"},
+	{0x3F01, "Microcode has been changed"},
+	{0x3F02, "Changed operating definition"},
+	{0x3F03, "Inquiry data has changed"},
+	{0x3F04, "Component device attached"},
+	{0x3F05, "Device identifier changed"},
+	{0x3F06, "Redundancy group created or modified"},
+	{0x3F07, "Redundancy group deleted"},
+	{0x3F08, "Spare created or modified"},
+	{0x3F09, "Spare deleted"},
+	{0x3F0A, "Volume set created or modified"},
+	{0x3F0B, "Volume set deleted"},
+	{0x3F0C, "Volume set deassigned"},
+	{0x3F0D, "Volume set reassigned"},
+	{0x3F0E, "Reported luns data has changed"},
+	{0x3F0F, "Echo buffer overwritten"},
+	{0x3F10, "Medium loadable"},
+	{0x3F11, "Medium auxiliary memory accessible"},
+/*
+ *	{0x40NN, "Ram failure"},
+ *	{0x40NN, "Diagnostic failure on component nn"},
+ *	{0x41NN, "Data path failure"},
+ *	{0x42NN, "Power-on or self-test failure"},
+ */
+	{0x4300, "Message error"},
+
+	{0x4400, "Internal target failure"},
+
+	{0x4500, "Select or reselect failure"},
+
+	{0x4600, "Unsuccessful soft reset"},
+
+	{0x4700, "Scsi parity error"},
+	{0x4701, "Data phase CRC error detected"},
+	{0x4702, "Scsi parity error detected during st data phase"},
+	{0x4703, "Information unit CRC error detected"},
+	{0x4704, "Asynchronous information protection error detected"},
+	{0x4705, "Protocol service CRC error"},
+	{0x477f, "Some commands cleared by iSCSI Protocol event"},
+
+	{0x4800, "Initiator detected error message received"},
+
+	{0x4900, "Invalid message error"},
+
+	{0x4A00, "Command phase error"},
+
+	{0x4B00, "Data phase error"},
+	{0x4B01, "Invalid target port transfer tag received"},
+	{0x4B02, "Too much write data"},
+	{0x4B03, "Ack/nak timeout"},
+	{0x4B04, "Nak received"},
+	{0x4B05, "Data offset error"},
+	{0x4B06, "Initiator response timeout"},
+
+	{0x4C00, "Logical unit failed self-configuration"},
+/*
+ *	{0x4DNN, "Tagged overlapped commands (nn = queue tag)"},
+ */
+	{0x4E00, "Overlapped commands attempted"},
+
+	{0x5000, "Write append error"},
+	{0x5001, "Write append position error"},
+	{0x5002, "Position error related to timing"},
+
+	{0x5100, "Erase failure"},
+	{0x5101, "Erase failure - incomplete erase operation detected"},
+
+	{0x5200, "Cartridge fault"},
+
+	{0x5300, "Media load or eject failed"},
+	{0x5301, "Unload tape failure"},
+	{0x5302, "Medium removal prevented"},
+
+	{0x5400, "Scsi to host system interface failure"},
+
+	{0x5500, "System resource failure"},
+	{0x5501, "System buffer full"},
+	{0x5502, "Insufficient reservation resources"},
+	{0x5503, "Insufficient resources"},
+	{0x5504, "Insufficient registration resources"},
+	{0x5505, "Insufficient access control resources"},
+	{0x5506, "Auxiliary memory out of space"},
+	{0x5507, "Quota error"},
+
+	{0x5700, "Unable to recover table-of-contents"},
+
+	{0x5800, "Generation does not exist"},
+
+	{0x5900, "Updated block read"},
+
+	{0x5A00, "Operator request or state change input"},
+	{0x5A01, "Operator medium removal request"},
+	{0x5A02, "Operator selected write protect"},
+	{0x5A03, "Operator selected write permit"},
+
+	{0x5B00, "Log exception"},
+	{0x5B01, "Threshold condition met"},
+	{0x5B02, "Log counter at maximum"},
+	{0x5B03, "Log list codes exhausted"},
+
+	{0x5C00, "Rpl status change"},
+	{0x5C01, "Spindles synchronized"},
+	{0x5C02, "Spindles not synchronized"},
+
+	{0x5D00, "Failure prediction threshold exceeded"},
+	{0x5D01, "Media failure prediction threshold exceeded"},
+	{0x5D02, "Logical unit failure prediction threshold exceeded"},
+	{0x5D03, "Spare area exhaustion prediction threshold exceeded"},
+	{0x5D10, "Hardware impending failure general hard drive failure"},
+	{0x5D11, "Hardware impending failure drive error rate too high"},
+	{0x5D12, "Hardware impending failure data error rate too high"},
+	{0x5D13, "Hardware impending failure seek error rate too high"},
+	{0x5D14, "Hardware impending failure too many block reassigns"},
+	{0x5D15, "Hardware impending failure access times too high"},
+	{0x5D16, "Hardware impending failure start unit times too high"},
+	{0x5D17, "Hardware impending failure channel parametrics"},
+	{0x5D18, "Hardware impending failure controller detected"},
+	{0x5D19, "Hardware impending failure throughput performance"},
+	{0x5D1A, "Hardware impending failure seek time performance"},
+	{0x5D1B, "Hardware impending failure spin-up retry count"},
+	{0x5D1C, "Hardware impending failure drive calibration retry count"},
+	{0x5D20, "Controller impending failure general hard drive failure"},
+	{0x5D21, "Controller impending failure drive error rate too high"},
+	{0x5D22, "Controller impending failure data error rate too high"},
+	{0x5D23, "Controller impending failure seek error rate too high"},
+	{0x5D24, "Controller impending failure too many block reassigns"},
+	{0x5D25, "Controller impending failure access times too high"},
+	{0x5D26, "Controller impending failure start unit times too high"},
+	{0x5D27, "Controller impending failure channel parametrics"},
+	{0x5D28, "Controller impending failure controller detected"},
+	{0x5D29, "Controller impending failure throughput performance"},
+	{0x5D2A, "Controller impending failure seek time performance"},
+	{0x5D2B, "Controller impending failure spin-up retry count"},
+	{0x5D2C, "Controller impending failure drive calibration retry count"},
+	{0x5D30, "Data channel impending failure general hard drive failure"},
+	{0x5D31, "Data channel impending failure drive error rate too high"},
+	{0x5D32, "Data channel impending failure data error rate too high"},
+	{0x5D33, "Data channel impending failure seek error rate too high"},
+	{0x5D34, "Data channel impending failure too many block reassigns"},
+	{0x5D35, "Data channel impending failure access times too high"},
+	{0x5D36, "Data channel impending failure start unit times too high"},
+	{0x5D37, "Data channel impending failure channel parametrics"},
+	{0x5D38, "Data channel impending failure controller detected"},
+	{0x5D39, "Data channel impending failure throughput performance"},
+	{0x5D3A, "Data channel impending failure seek time performance"},
+	{0x5D3B, "Data channel impending failure spin-up retry count"},
+	{0x5D3C, "Data channel impending failure drive calibration retry "
+	 "count"},
+	{0x5D40, "Servo impending failure general hard drive failure"},
+	{0x5D41, "Servo impending failure drive error rate too high"},
+	{0x5D42, "Servo impending failure data error rate too high"},
+	{0x5D43, "Servo impending failure seek error rate too high"},
+	{0x5D44, "Servo impending failure too many block reassigns"},
+	{0x5D45, "Servo impending failure access times too high"},
+	{0x5D46, "Servo impending failure start unit times too high"},
+	{0x5D47, "Servo impending failure channel parametrics"},
+	{0x5D48, "Servo impending failure controller detected"},
+	{0x5D49, "Servo impending failure throughput performance"},
+	{0x5D4A, "Servo impending failure seek time performance"},
+	{0x5D4B, "Servo impending failure spin-up retry count"},
+	{0x5D4C, "Servo impending failure drive calibration retry count"},
+	{0x5D50, "Spindle impending failure general hard drive failure"},
+	{0x5D51, "Spindle impending failure drive error rate too high"},
+	{0x5D52, "Spindle impending failure data error rate too high"},
+	{0x5D53, "Spindle impending failure seek error rate too high"},
+	{0x5D54, "Spindle impending failure too many block reassigns"},
+	{0x5D55, "Spindle impending failure access times too high"},
+	{0x5D56, "Spindle impending failure start unit times too high"},
+	{0x5D57, "Spindle impending failure channel parametrics"},
+	{0x5D58, "Spindle impending failure controller detected"},
+	{0x5D59, "Spindle impending failure throughput performance"},
+	{0x5D5A, "Spindle impending failure seek time performance"},
+	{0x5D5B, "Spindle impending failure spin-up retry count"},
+	{0x5D5C, "Spindle impending failure drive calibration retry count"},
+	{0x5D60, "Firmware impending failure general hard drive failure"},
+	{0x5D61, "Firmware impending failure drive error rate too high"},
+	{0x5D62, "Firmware impending failure data error rate too high"},
+	{0x5D63, "Firmware impending failure seek error rate too high"},
+	{0x5D64, "Firmware impending failure too many block reassigns"},
+	{0x5D65, "Firmware impending failure access times too high"},
+	{0x5D66, "Firmware impending failure start unit times too high"},
+	{0x5D67, "Firmware impending failure channel parametrics"},
+	{0x5D68, "Firmware impending failure controller detected"},
+	{0x5D69, "Firmware impending failure throughput performance"},
+	{0x5D6A, "Firmware impending failure seek time performance"},
+	{0x5D6B, "Firmware impending failure spin-up retry count"},
+	{0x5D6C, "Firmware impending failure drive calibration retry count"},
+	{0x5DFF, "Failure prediction threshold exceeded (false)"},
+
+	{0x5E00, "Low power condition on"},
+	{0x5E01, "Idle condition activated by timer"},
+	{0x5E02, "Standby condition activated by timer"},
+	{0x5E03, "Idle condition activated by command"},
+	{0x5E04, "Standby condition activated by command"},
+	{0x5E41, "Power state change to active"},
+	{0x5E42, "Power state change to idle"},
+	{0x5E43, "Power state change to standby"},
+	{0x5E45, "Power state change to sleep"},
+	{0x5E47, "Power state change to device control"},
+
+	{0x6000, "Lamp failure"},
+
+	{0x6100, "Video acquisition error"},
+	{0x6101, "Unable to acquire video"},
+	{0x6102, "Out of focus"},
+
+	{0x6200, "Scan head positioning error"},
+
+	{0x6300, "End of user area encountered on this track"},
+	{0x6301, "Packet does not fit in available space"},
+
+	{0x6400, "Illegal mode for this track"},
+	{0x6401, "Invalid packet size"},
+
+	{0x6500, "Voltage fault"},
+
+	{0x6600, "Automatic document feeder cover up"},
+	{0x6601, "Automatic document feeder lift up"},
+	{0x6602, "Document jam in automatic document feeder"},
+	{0x6603, "Document miss feed automatic in document feeder"},
+
+	{0x6700, "Configuration failure"},
+	{0x6701, "Configuration of incapable logical units failed"},
+	{0x6702, "Add logical unit failed"},
+	{0x6703, "Modification of logical unit failed"},
+	{0x6704, "Exchange of logical unit failed"},
+	{0x6705, "Remove of logical unit failed"},
+	{0x6706, "Attachment of logical unit failed"},
+	{0x6707, "Creation of logical unit failed"},
+	{0x6708, "Assign failure occurred"},
+	{0x6709, "Multiply assigned logical unit"},
+	{0x670A, "Set target port groups command failed"},
+
+	{0x6800, "Logical unit not configured"},
+
+	{0x6900, "Data loss on logical unit"},
+	{0x6901, "Multiple logical unit failures"},
+	{0x6902, "Parity/data mismatch"},
+
+	{0x6A00, "Informational, refer to log"},
+
+	{0x6B00, "State change has occurred"},
+	{0x6B01, "Redundancy level got better"},
+	{0x6B02, "Redundancy level got worse"},
+
+	{0x6C00, "Rebuild failure occurred"},
+
+	{0x6D00, "Recalculate failure occurred"},
+
+	{0x6E00, "Command to logical unit failed"},
+
+	{0x6F00, "Copy protection key exchange failure - authentication "
+	 "failure"},
+	{0x6F01, "Copy protection key exchange failure - key not present"},
+	{0x6F02, "Copy protection key exchange failure - key not established"},
+	{0x6F03, "Read of scrambled sector without authentication"},
+	{0x6F04, "Media region code is mismatched to logical unit region"},
+	{0x6F05, "Drive region must be permanent/region reset count error"},
+/*
+ *	{0x70NN, "Decompression exception short algorithm id of nn"},
+ */
+	{0x7100, "Decompression exception long algorithm id"},
+
+	{0x7200, "Session fixation error"},
+	{0x7201, "Session fixation error writing lead-in"},
+	{0x7202, "Session fixation error writing lead-out"},
+	{0x7203, "Session fixation error - incomplete track in session"},
+	{0x7204, "Empty or partially written reserved track"},
+	{0x7205, "No more track reservations allowed"},
+
+	{0x7300, "Cd control error"},
+	{0x7301, "Power calibration area almost full"},
+	{0x7302, "Power calibration area is full"},
+	{0x7303, "Power calibration area error"},
+	{0x7304, "Program memory area update failure"},
+	{0x7305, "Program memory area is full"},
+	{0x7306, "RMA/PMA is almost full"},
+	{0, NULL}
+};
+
+struct error_info2 {
+	unsigned char code1, code2_min, code2_max;
+	const char * fmt;
+};
+
+static struct error_info2 additional2[] =
+{
+	{0x40,0x00,0x7f,"Ram failure (%x)"},
+	{0x40,0x80,0xff,"Diagnostic failure on component (%x)"},
+	{0x41,0x00,0xff,"Data path failure (%x)"},
+	{0x42,0x00,0xff,"Power-on or self-test failure (%x)"},
+	{0x4D,0x00,0xff,"Tagged overlapped commands (queue tag %x)"},
+	{0x70,0x00,0xff,"Decompression exception short algorithm id of %x"},
+	{0, 0, 0, NULL}
+};
+
+/* description of the sense key values */
+static const char *snstext[] = {
+	"No Sense",	    /* 0: There is no sense information */
+	"Recovered Error",  /* 1: The last command completed successfully
+				  but used error correction */
+	"Not Ready",	    /* 2: The addressed target is not ready */
+	"Medium Error",	    /* 3: Data error detected on the medium */
+	"Hardware Error",   /* 4: Controller or device failure */
+	"Illegal Request",  /* 5: Error in request */
+	"Unit Attention",   /* 6: Removable medium was changed, or
+				  the target has been reset, or ... */
+	"Data Protect",	    /* 7: Access to the data is blocked */
+	"Blank Check",	    /* 8: Reached unexpected written or unwritten
+				  region of the medium */
+	"Vendor Specific(9)",
+	"Copy Aborted",	    /* A: COPY or COMPARE was aborted */
+	"Aborted Command",  /* B: The target aborted the command */
+	"Equal",	    /* C: A SEARCH DATA command found data equal */
+	"Volume Overflow",  /* D: Medium full with still data to be written */
+	"Miscompare",	    /* E: Source data and data on the medium
+				  do not agree */
+};
+#endif
+
+/* Get sense key string or NULL if not available */
+const char *
+scsi_sense_key_string(unsigned char key) {
+#ifdef CONFIG_SCSI_CONSTANTS
+	if (key <= 0xE)
+		return snstext[key];
+#endif
+	return NULL;
+}
+EXPORT_SYMBOL(scsi_sense_key_string);
+
+/*
+ * Get additional sense code string or NULL if not available.
+ * This string may contain a "%x" and should be printed with ascq as arg.
+ */
+const char *
+scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
+#ifdef CONFIG_SCSI_CONSTANTS
+	int i;
+	unsigned short code = ((asc << 8) | ascq);
+
+	for (i=0; additional[i].text; i++)
+		if (additional[i].code12 == code)
+			return additional[i].text;
+	for (i=0; additional2[i].fmt; i++)
+		if (additional2[i].code1 == asc &&
+		    additional2[i].code2_min >= ascq &&
+		    additional2[i].code2_max <= ascq)
+			return additional2[i].fmt;
+#endif
+	return NULL;
+}
+EXPORT_SYMBOL(scsi_extd_sense_format);
+
+/* Print extended sense information; no leadin, no linefeed */
+static void
+scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
+{
+	const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
+
+	if (extd_sense_fmt) {
+		if (strstr(extd_sense_fmt, "%x")) {
+			printk("Additional sense: ");
+			printk(extd_sense_fmt, ascq);
+		} else
+			printk("Additional sense: %s", extd_sense_fmt);
+	} else {
+		if (asc >= 0x80)
+			printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc, ascq);
+		if (ascq >= 0x80)
+			printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc, ascq);
+		else
+			printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
+	}
+}
+
+/* Print sense information */
+void
+__scsi_print_sense(const char *name, const unsigned char *sense_buffer,
+		   int sense_len)
+{
+	int k, num, res;
+	unsigned int info;
+	const char *error;
+	const char *sense_txt;
+	struct scsi_sense_hdr ssh;
+    
+	res = scsi_normalize_sense(sense_buffer, sense_len, &ssh);
+	if (0 == res) {
+		/* this may be SCSI-1 sense data */
+		num = (sense_len < 32) ? sense_len : 32;
+		printk(KERN_INFO "Unrecognized sense data (in hex):");
+		for (k = 0; k < num; ++k) {
+			if (0 == (k % 16)) {
+				printk("\n");
+				printk(KERN_INFO "        ");
+			}
+			printk("%02x ", sense_buffer[k]);
+		}
+		printk("\n");
+		return;
+	}
+
+	/* An example of deferred is when an earlier write to disk cache
+	 * succeeded, but now the disk discovers that it cannot write the
+	 * data to the magnetic media.
+	 */
+	error = scsi_sense_is_deferred(&ssh) ? 
+			"<<DEFERRED>>" : "Current";
+	printk(KERN_INFO "%s: %s", name, error);
+	if (ssh.response_code >= 0x72)
+		printk(" [descriptor]");
+
+	sense_txt = scsi_sense_key_string(ssh.sense_key);
+	if (sense_txt)
+		printk(": sense key: %s\n", sense_txt);
+	else
+		printk(": sense key=0x%x\n", ssh.sense_key);
+	printk(KERN_INFO "    ");
+	scsi_show_extd_sense(ssh.asc, ssh.ascq);
+	printk("\n");
+
+	if (ssh.response_code < 0x72) {
+		/* only decode extras for "fixed" format now */
+		char buff[80];
+		int blen, fixed_valid;
+
+		fixed_valid = sense_buffer[0] & 0x80;
+		info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
+			(sense_buffer[5] << 8) | sense_buffer[6]);
+		res = 0;
+		memset(buff, 0, sizeof(buff));
+		blen = sizeof(buff) - 1;
+		if (fixed_valid)
+			res += snprintf(buff + res, blen - res,
+					"Info fld=0x%x", info);
+		if (sense_buffer[2] & 0x80) {
+			/* current command has read a filemark */
+			if (res > 0)
+				res += snprintf(buff + res, blen - res, ", ");
+			res += snprintf(buff + res, blen - res, "FMK");
+		}
+		if (sense_buffer[2] & 0x40) {
+			/* end-of-medium condition exists */
+			if (res > 0)
+				res += snprintf(buff + res, blen - res, ", ");
+			res += snprintf(buff + res, blen - res, "EOM");
+		}
+		if (sense_buffer[2] & 0x20) {
+			/* incorrect block length requested */
+			if (res > 0)
+				res += snprintf(buff + res, blen - res, ", ");
+			res += snprintf(buff + res, blen - res, "ILI");
+		}
+		if (res > 0)
+			printk(KERN_INFO "%s\n", buff);
+	} else if (ssh.additional_length > 0) {
+		/* descriptor format with sense descriptors */
+		num = 8 + ssh.additional_length;
+		num = (sense_len < num) ? sense_len : num;
+		printk(KERN_INFO "Descriptor sense data with sense "
+		       "descriptors (in hex):");
+		for (k = 0; k < num; ++k) {
+			if (0 == (k % 16)) {
+				printk("\n");
+				printk(KERN_INFO "        ");
+			}
+			printk("%02x ", sense_buffer[k]);
+		}
+		printk("\n");
+	}
+}
+EXPORT_SYMBOL(__scsi_print_sense);
+
+void scsi_print_sense(const char *devclass, struct scsi_cmnd *cmd)
+{
+	const char *name = devclass;
+
+	if (cmd->request->rq_disk)
+		name = cmd->request->rq_disk->disk_name;
+	__scsi_print_sense(name, cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+}
+EXPORT_SYMBOL(scsi_print_sense);
+
+void scsi_print_req_sense(const char *devclass, struct scsi_request *sreq)
+{
+	const char *name = devclass;
+
+	if (sreq->sr_request->rq_disk)
+		name = sreq->sr_request->rq_disk->disk_name;
+	__scsi_print_sense(name, sreq->sr_sense_buffer, SCSI_SENSE_BUFFERSIZE);
+}
+EXPORT_SYMBOL(scsi_print_req_sense);
+
+#ifdef CONFIG_SCSI_CONSTANTS
+static const char *one_byte_msgs[] = {
+/* 0x00 */ "Command Complete", NULL, "Save Pointers",
+/* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error", 
+/* 0x06 */ "Abort", "Message Reject", "Nop", "Message Parity Error",
+/* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag",
+/* 0x0c */ "Bus device reset", "Abort Tag", "Clear Queue", 
+/* 0x0f */ "Initiate Recovery", "Release Recovery"
+};
+#define NO_ONE_BYTE_MSGS (sizeof(one_byte_msgs)  / sizeof (const char *))
+
+static const char *two_byte_msgs[] = {
+/* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag"
+/* 0x23 */ "Ignore Wide Residue"
+};
+#define NO_TWO_BYTE_MSGS (sizeof(two_byte_msgs)  / sizeof (const char *))
+
+static const char *extended_msgs[] = {
+/* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request",
+/* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Request"
+};
+#define NO_EXTENDED_MSGS (sizeof(two_byte_msgs)  / sizeof (const char *))
+
+
+int scsi_print_msg (const unsigned char *msg)
+{
+	int len = 0, i;
+	if (msg[0] == EXTENDED_MESSAGE) {
+		len = 3 + msg[1];
+		if (msg[2] < NO_EXTENDED_MSGS)
+			printk ("%s ", extended_msgs[msg[2]]); 
+		else 
+			printk ("Extended Message, reserved code (0x%02x) ",
+				(int) msg[2]);
+		switch (msg[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			printk("pointer = %d", (int) (msg[3] << 24) |
+				(msg[4] << 16) | (msg[5] << 8) | msg[6]);
+			break;
+		case EXTENDED_SDTR:
+			printk("period = %d ns, offset = %d",
+				(int) msg[3] * 4, (int) msg[4]);
+			break;
+		case EXTENDED_WDTR:
+			printk("width = 2^%d bytes", msg[3]);
+			break;
+		default:
+		for (i = 2; i < len; ++i) 
+			printk("%02x ", msg[i]);
+		}
+	/* Identify */
+	} else if (msg[0] & 0x80) {
+		printk("Identify disconnect %sallowed %s %d ",
+			(msg[0] & 0x40) ? "" : "not ",
+			(msg[0] & 0x20) ? "target routine" : "lun",
+			msg[0] & 0x7);
+		len = 1;
+	/* Normal One byte */
+	} else if (msg[0] < 0x1f) {
+		if (msg[0] < NO_ONE_BYTE_MSGS)
+			printk(one_byte_msgs[msg[0]]);
+		else
+			printk("reserved (%02x) ", msg[0]);
+		len = 1;
+	/* Two byte */
+	} else if (msg[0] <= 0x2f) {
+		if ((msg[0] - 0x20) < NO_TWO_BYTE_MSGS)
+			printk("%s %02x ", two_byte_msgs[msg[0] - 0x20], 
+				msg[1]);
+		else 
+			printk("reserved two byte (%02x %02x) ", 
+				msg[0], msg[1]);
+		len = 2;
+	} else 
+		printk("reserved");
+	return len;
+}
+EXPORT_SYMBOL(scsi_print_msg);
+
+#else  /* ifndef CONFIG_SCSI_CONSTANTS */
+
+int scsi_print_msg (const unsigned char *msg)
+{
+	int len = 0, i;
+
+	if (msg[0] == EXTENDED_MESSAGE) {
+		len = 3 + msg[1];
+		for (i = 0; i < len; ++i)
+			printk("%02x ", msg[i]);
+	/* Identify */
+	} else if (msg[0] & 0x80) {
+		printk("%02x ", msg[0]);
+		len = 1;
+	/* Normal One byte */
+	} else if (msg[0] < 0x1f) {
+		printk("%02x ", msg[0]);
+		len = 1;
+	/* Two byte */
+	} else if (msg[0] <= 0x2f) {
+		printk("%02x %02x", msg[0], msg[1]);
+		len = 2;
+	} else 
+		printk("%02x ", msg[0]);
+	return len;
+}
+EXPORT_SYMBOL(scsi_print_msg);
+#endif /* ! CONFIG_SCSI_CONSTANTS */
+
+void scsi_print_command(struct scsi_cmnd *cmd)
+{
+	/* Assume appended output (i.e. not at start of line) */
+	printk("scsi%d : destination target %d, lun %d\n", 
+		cmd->device->host->host_no, 
+		cmd->device->id, 
+		cmd->device->lun);
+	printk(KERN_INFO "        command: ");
+	scsi_print_cdb(cmd->cmnd, cmd->cmd_len, 0);
+}
+EXPORT_SYMBOL(scsi_print_command);
+
+#ifdef CONFIG_SCSI_CONSTANTS
+
+static const char * hostbyte_table[]={
+"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET", 
+"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
+"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY"};
+#define NUM_HOSTBYTE_STRS (sizeof(hostbyte_table) / sizeof(const char *))
+
+void scsi_print_hostbyte(int scsiresult)
+{
+	int hb = host_byte(scsiresult);
+
+	printk("Hostbyte=0x%02x", hb);
+	if (hb < NUM_HOSTBYTE_STRS)
+		printk("(%s) ", hostbyte_table[hb]);
+	else
+		printk("is invalid "); 
+}
+#else
+void scsi_print_hostbyte(int scsiresult)
+{
+	printk("Hostbyte=0x%02x ", host_byte(scsiresult));
+}
+#endif
+
+#ifdef CONFIG_SCSI_CONSTANTS
+
+static const char * driverbyte_table[]={
+"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT",  "DRIVER_MEDIA", "DRIVER_ERROR", 
+"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
+#define NUM_DRIVERBYTE_STRS (sizeof(driverbyte_table) / sizeof(const char *))
+
+static const char * driversuggest_table[]={"SUGGEST_OK",
+"SUGGEST_RETRY", "SUGGEST_ABORT", "SUGGEST_REMAP", "SUGGEST_DIE",
+"SUGGEST_5", "SUGGEST_6", "SUGGEST_7", "SUGGEST_SENSE"};
+#define NUM_SUGGEST_STRS (sizeof(driversuggest_table) / sizeof(const char *))
+
+void scsi_print_driverbyte(int scsiresult)
+{
+	int dr = (driver_byte(scsiresult) & DRIVER_MASK);
+	int su = ((driver_byte(scsiresult) & SUGGEST_MASK) >> 4);
+
+	printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
+	printk("(%s,%s) ",
+	       (dr < NUM_DRIVERBYTE_STRS ? driverbyte_table[dr] : "invalid"),
+	       (su < NUM_SUGGEST_STRS ? driversuggest_table[su] : "invalid"));
+}
+#else
+void scsi_print_driverbyte(int scsiresult)
+{
+	printk("Driverbyte=0x%02x ", driver_byte(scsiresult));
+}
+#endif
diff --git a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
new file mode 100644
index 0000000..7ce53d8
--- /dev/null
+++ b/drivers/scsi/cpqfcTS.h
@@ -0,0 +1,19 @@
+#ifndef CPQFCTS_H
+#define CPQFCTS_H
+#include "cpqfcTSstructs.h"
+
+// These functions are required by the Linux SCSI layers
+extern int cpqfcTS_detect(Scsi_Host_Template *);
+extern int cpqfcTS_release(struct Scsi_Host *);
+extern const char * cpqfcTS_info(struct Scsi_Host *);
+extern int cpqfcTS_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
+extern int cpqfcTS_abort(Scsi_Cmnd *);
+extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int);
+extern int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd);
+extern int cpqfcTS_eh_device_reset(Scsi_Cmnd *);
+extern int cpqfcTS_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int[]);
+extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
+
+#endif /* CPQFCTS_H */ 
diff --git a/drivers/scsi/cpqfcTSchip.h b/drivers/scsi/cpqfcTSchip.h
new file mode 100644
index 0000000..14b8337
--- /dev/null
+++ b/drivers/scsi/cpqfcTSchip.h
@@ -0,0 +1,238 @@
+/* Copyright(c) 2000, Compaq Computer Corporation 
+ * Fibre Channel Host Bus Adapter 
+ * 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+*/
+#ifndef CPQFCTSCHIP_H
+#define CPQFCTSCHIP_H
+#ifndef TACHYON_CHIP_INC
+
+// FC-PH (Physical) specification levels for Login payloads
+// NOTE: These are NOT strictly complied with by any FC vendors
+
+#define FC_PH42			0x08
+#define FC_PH43			0x09
+#define FC_PH3			0x20
+
+#define TACHLITE_TS_RX_SIZE     1024  // max inbound frame size
+// "I" prefix is for Include
+
+#define IVENDID    0x00  // word
+#define IDEVID     0x02
+#define ITLCFGCMD 0x04
+#define IMEMBASE   0x18    // Tachyon
+#define ITLMEMBASE   0x1C  // Tachlite
+#define IIOBASEL   0x10    // Tachyon I/O base address, lower 256 bytes
+#define IIOBASEU   0x14    // Tachyon I/O base address, upper 256 bytes
+#define ITLIOBASEL   0x14  // TachLite I/O base address, lower 256 bytes
+#define ITLIOBASEU   0x18  // TachLite I/O base address, upper 256 bytes
+#define ITLRAMBASE   0x20  // TL on-board RAM start
+#define ISROMBASE  0x24
+#define IROMBASE   0x30
+
+#define ICFGCMD    0x04    // PCI config - PCI config access (word)
+#define ICFGSTAT   0x06    // PCI status (R - word)
+#define IRCTR_WCTR 0x1F2   // ROM control / pre-fetch wait counter
+#define IPCIMCTR   0x1F3   // PCI master control register
+#define IINTPEND   0x1FD   // Interrupt pending (I/O Upper - Tachyon & TL)
+#define IINTEN     0x1FE   // Interrupt enable  (I/O Upper - Tachyon & TL)
+#define IINTSTAT   0x1FF   // Interrupt status  (I/O Upper - Tachyon & TL)
+
+#define IMQ_BASE            0x80
+#define IMQ_LENGTH          0x84
+#define IMQ_CONSUMER_INDEX  0x88
+#define IMQ_PRODUCER_INDEX  0x8C   // Tach copies its INDX to bits 0-7 of value
+
+/*
+// IOBASE UPPER
+#define SFSBQ_BASE            0x00   // single-frame sequences
+#define SFSBQ_LENGTH          0x04
+#define SFSBQ_PRODUCER_INDEX  0x08
+#define SFSBQ_CONSUMER_INDEX  0x0C   // (R)
+#define SFS_BUFFER_LENGTH     0X10
+                              // SCSI-FCP hardware assists
+#define SEST_BASE             0x40   // SSCI Exchange State Table
+#define SEST_LENGTH           0x44
+#define SCSI_BUFFER_LENGTH    0x48
+#define SEST_LINKED_LIST      0x4C
+
+#define TACHYON_My_ID         0x6C
+#define TACHYON_CONFIGURATION 0x84   // (R/W) reset val 2
+#define TACHYON_CONTROL       0x88
+#define TACHYON_STATUS        0x8C   // (R)
+#define TACHYON_FLUSH_SEST    0x90   // (R/W)
+#define TACHYON_EE_CREDIT_TMR 0x94   // (R)
+#define TACHYON_BB_CREDIT_TMR 0x98   // (R)
+#define TACHYON_RCV_FRAME_ERR 0x9C   // (R)
+#define FRAME_MANAGER_CONFIG  0xC0   // (R/W)
+#define FRAME_MANAGER_CONTROL 0xC4
+#define FRAME_MANAGER_STATUS  0xC8   // (R)
+#define FRAME_MANAGER_ED_TOV  0xCC
+#define FRAME_MANAGER_LINK_ERR1 0xD0   // (R)
+#define FRAME_MANAGER_LINK_ERR2 0xD4   // (R)
+#define FRAME_MANAGER_TIMEOUT2  0xD8   // (W)
+#define FRAME_MANAGER_BB_CREDIT 0xDC   // (R)
+#define FRAME_MANAGER_WWN_HI    0xE0   // (R/W)
+#define FRAME_MANAGER_WWN_LO    0xE4   // (R/W)
+#define FRAME_MANAGER_RCV_AL_PA 0xE8   // (R)
+#define FRAME_MANAGER_PRIMITIVE 0xEC   // {K28.5} byte1 byte2 byte3
+*/
+		    
+#define TL_MEM_ERQ_BASE                    0x0 //ERQ Base
+#define TL_IO_ERQ_BASE                     0x0 //ERQ base
+
+#define TL_MEM_ERQ_LENGTH                  0x4 //ERQ Length
+#define TL_IO_ERQ_LENGTH                   0x4 //ERQ Length
+
+#define TL_MEM_ERQ_PRODUCER_INDEX          0x8 //ERQ Producer Index  register
+#define TL_IO_ERQ_PRODUCER_INDEX           0x8 //ERQ Producer Index  register
+
+#define TL_MEM_ERQ_CONSUMER_INDEX_ADR 0xC //ERQ Consumer Index address register
+#define TL_IO_ERQ_CONSUMER_INDEX_ADR  0xC //ERQ Consumer Index address register
+
+#define TL_MEM_ERQ_CONSUMER_INDEX     0xC //ERQ Consumer Index 
+#define TL_IO_ERQ_CONSUMER_INDEX      0xC //ERQ Consumer Index 
+
+#define TL_MEM_SFQ_BASE               0x50 //SFQ Base
+#define TL_IO_SFQ_BASE                0x50 //SFQ base
+
+#define TL_MEM_SFQ_LENGTH             0x54 //SFQ Length
+#define TL_IO_SFQ_LENGTH              0x54 //SFQ Length
+
+#define TL_MEM_SFQ_CONSUMER_INDEX     0x58 //SFQ Consumer Index
+#define TL_IO_SFQ_CONSUMER_INDEX      0x58 //SFQ Consumer Index
+
+#define TL_MEM_IMQ_BASE               0x80 //IMQ Base
+#define TL_IO_IMQ_BASE                0x80 //IMQ base
+
+#define TL_MEM_IMQ_LENGTH             0x84 //IMQ Length
+#define TL_IO_IMQ_LENGTH              0x84 //IMQ Length
+
+#define TL_MEM_IMQ_CONSUMER_INDEX     0x88 //IMQ Consumer Index
+#define TL_IO_IMQ_CONSUMER_INDEX      0x88 //IMQ Consumer Index
+
+#define TL_MEM_IMQ_PRODUCER_INDEX_ADR 0x8C //IMQ Producer Index address register
+#define TL_IO_IMQ_PRODUCER_INDEX_ADR  0x8C //IMQ Producer Index address register
+
+#define TL_MEM_SEST_BASE              0x140 //SFQ Base
+#define TL_IO_SEST_BASE               0x40 //SFQ base
+
+#define TL_MEM_SEST_LENGTH            0x144 //SFQ Length
+#define TL_IO_SEST_LENGTH             0x44 //SFQ Length
+
+#define TL_MEM_SEST_LINKED_LIST       0x14C
+
+#define TL_MEM_SEST_SG_PAGE           0x168  // Extended Scatter/Gather page size
+
+#define TL_MEM_TACH_My_ID             0x16C
+#define TL_IO_TACH_My_ID              0x6C //My AL_PA ID
+
+#define TL_MEM_TACH_CONFIG            0x184 //Tachlite Configuration register
+#define TL_IO_CONFIG                  0x84 //Tachlite Configuration register
+
+#define TL_MEM_TACH_CONTROL           0x188 //Tachlite Control register
+#define TL_IO_CTR                     0x88 //Tachlite Control register
+
+#define TL_MEM_TACH_STATUS            0x18C //Tachlite Status register
+#define TL_IO_STAT                    0x8C //Tachlite Status register
+
+#define TL_MEM_FM_CONFIG        0x1C0 //Frame Manager Configuration register
+#define TL_IO_FM_CONFIG         0xC0 //Frame Manager Configuration register
+
+#define TL_MEM_FM_CONTROL       0x1C4 //Frame Manager Control
+#define TL_IO_FM_CTL            0xC4 //Frame Manager Control
+
+#define TL_MEM_FM_STATUS        0x1C8 //Frame Manager Status
+#define TL_IO_FM_STAT           0xC8 //Frame Manager Status
+
+#define TL_MEM_FM_LINK_STAT1    0x1D0 //Frame Manager Link Status 1
+#define TL_IO_FM_LINK_STAT1     0xD0 //Frame Manager Link Status 1
+
+#define TL_MEM_FM_LINK_STAT2    0x1D4 //Frame Manager Link Status 2
+#define TL_IO_FM_LINK_STAT2     0xD4 //Frame Manager Link Status 2
+
+#define TL_MEM_FM_TIMEOUT2      0x1D8   // (W)
+
+#define TL_MEM_FM_BB_CREDIT0    0x1DC
+
+#define TL_MEM_FM_WWN_HI        0x1E0 //Frame Manager World Wide Name High
+#define TL_IO_FM_WWN_HI         0xE0 //Frame Manager World Wide Name High
+
+#define TL_MEM_FM_WWN_LO        0x1E4 //Frame Manager World Wide Name LOW
+#define TL_IO_FM_WWN_LO         0xE4 //Frame Manager World Wide Name Low
+
+#define TL_MEM_FM_RCV_AL_PA     0x1E8 //Frame Manager AL_PA Received register
+#define TL_IO_FM_ALPA           0xE8 //Frame Manager AL_PA Received register
+
+#define TL_MEM_FM_ED_TOV           0x1CC
+
+#define TL_IO_ROMCTR            0xFA //TL PCI ROM Control Register
+#define TL_IO_PCIMCTR           0xFB //TL PCI Master Control Register
+#define TL_IO_SOFTRST           0xFC //Tachlite Configuration register
+#define TL_MEM_SOFTRST          0x1FC //Tachlite Configuration register
+
+// completion message types (bit 8 set means Interrupt generated)
+// CM_Type
+#define OUTBOUND_COMPLETION        0
+#define ERROR_IDLE_COMPLETION   0x01
+#define OUT_HI_PRI_COMPLETION   0x01
+#define INBOUND_MFS_COMPLETION  0x02
+#define INBOUND_000_COMPLETION  0x03
+#define INBOUND_SFS_COMPLETION  0x04  // Tachyon & TachLite
+#define ERQ_FROZEN_COMPLETION   0x06  // TachLite
+#define INBOUND_C1_TIMEOUT      0x05
+#define INBOUND_BUSIED_FRAME    0x06
+#define SFS_BUF_WARN            0x07
+#define FCP_FROZEN_COMPLETION   0x07  // TachLite
+#define MFS_BUF_WARN            0x08
+#define IMQ_BUF_WARN            0x09
+#define FRAME_MGR_INTERRUPT     0x0A
+#define READ_STATUS             0x0B
+#define INBOUND_SCSI_DATA_COMPLETION  0x0C
+#define INBOUND_FCP_XCHG_COMPLETION   0x0C  // TachLite
+#define INBOUND_SCSI_DATA_COMMAND     0x0D
+#define BAD_SCSI_FRAME                0x0E
+#define INB_SCSI_STATUS_COMPLETION    0x0F
+#define BUFFER_PROCESSED_COMPLETION   0x11
+
+// FC-AL (Tachyon) Loop Port State Machine defs
+// (loop "Up" states)
+#define MONITORING 0x0
+#define ARBITRATING 0x1
+#define ARBITRAT_WON 0x2
+#define OPEN 0x3
+#define OPENED 0x4
+#define XMITTD_CLOSE 0x5
+#define RCVD_CLOSE 0x6
+#define TRANSFER 0x7
+
+// (loop "Down" states)
+#define INITIALIZING 0x8
+#define O_I_INIT 0x9
+#define O_I_PROTOCOL 0xa
+#define O_I_LIP_RCVD 0xb
+#define HOST_CONTROL 0xc
+#define LOOP_FAIL 0xd
+// (no 0xe)
+#define OLD_PORT 0xf
+
+
+
+#define TACHYON_CHIP_INC
+#endif
+#endif /* CPQFCTSCHIP_H */
diff --git a/drivers/scsi/cpqfcTScontrol.c b/drivers/scsi/cpqfcTScontrol.c
new file mode 100644
index 0000000..bd94c70
--- /dev/null
+++ b/drivers/scsi/cpqfcTScontrol.c
@@ -0,0 +1,2231 @@
+/* Copyright 2000, Compaq Computer Corporation 
+ * Fibre Channel Host Bus Adapter 
+ * 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+*/
+/* These functions control the host bus adapter (HBA) hardware.  The main chip
+   control takes place in the interrupt handler where we process the IMQ 
+   (Inbound Message Queue).  The IMQ is Tachyon's way of communicating FC link
+   events and state information to the driver.  The Single Frame Queue (SFQ)
+   buffers incoming FC frames for processing by the driver.  References to 
+   "TL/TS UG" are for:
+   "HP HPFC-5100/5166 Tachyon TL/TS ICs User Guide", August 16, 1999, 1st Ed.
+   Hewlitt Packard Manual Part Number 5968-1083E.
+*/
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>  // request_region() prototype
+#include <linux/sched.h>
+#include <linux/slab.h>  // need "kfree" for ext. S/G pages
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+#include <asm/irq.h>
+#include <linux/spinlock.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>   // Scsi_Host definition for INT handler
+#include "cpqfcTSchip.h"
+#include "cpqfcTSstructs.h"
+
+//#define IMQ_DEBUG 1
+
+static void fcParseLinkStatusCounters(TACHYON * fcChip);
+static void CpqTsGetSFQEntry(TACHYON * fcChip, 
+	      USHORT pi, ULONG * buffr, BOOLEAN UpdateChip); 
+
+static void 
+cpqfc_free_dma_consistent(CPQFCHBA *cpqfcHBAdata)
+{
+  	// free up the primary EXCHANGES struct and Link Q
+	PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+	if (fcChip->Exchanges != NULL)
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_EXCHANGES),
+			fcChip->Exchanges, fcChip->exch_dma_handle);
+	fcChip->Exchanges = NULL;
+	if (cpqfcHBAdata->fcLQ != NULL)
+		pci_free_consistent(cpqfcHBAdata->PciDev, sizeof(FC_LINK_QUE),
+			cpqfcHBAdata->fcLQ, cpqfcHBAdata->fcLQ_dma_handle);
+	cpqfcHBAdata->fcLQ = NULL;
+}
+
+// Note special requirements for Q alignment!  (TL/TS UG pg. 190)
+// We place critical index pointers at end of QUE elements to assist
+// in non-symbolic (i.e. memory dump) debugging
+// opcode defines placement of Queues (e.g. local/external RAM)
+
+int CpqTsCreateTachLiteQues( void* pHBA, int opcode)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+  int iStatus=0;
+  unsigned long ulAddr;
+  dma_addr_t ERQdma, IMQdma, SPQdma, SESTdma;
+  int i;
+
+  // NOTE! fcMemManager() will return system virtual addresses.
+  // System (kernel) virtual addresses, though non-paged, still
+  // aren't physical addresses.  Convert to PHYSICAL_ADDRESS for Tachyon's
+  // DMA use.
+  ENTER("CreateTachLiteQues");
+
+
+  // Allocate primary EXCHANGES array...
+  fcChip->Exchanges = NULL;
+  cpqfcHBAdata->fcLQ = NULL;
+  
+  /* printk("Allocating %u for %u Exchanges ", 
+	  (ULONG)sizeof(FC_EXCHANGES), TACH_MAX_XID); */
+  fcChip->Exchanges = pci_alloc_consistent(cpqfcHBAdata->PciDev, 
+			sizeof(FC_EXCHANGES), &fcChip->exch_dma_handle);
+  /* printk("@ %p\n", fcChip->Exchanges); */
+
+  if( fcChip->Exchanges == NULL ) // fatal error!!
+  {
+    printk("pci_alloc_consistent failure on Exchanges: fatal error\n");
+    return -1;
+  }
+  // zero out the entire EXCHANGE space
+  memset( fcChip->Exchanges, 0, sizeof( FC_EXCHANGES));  
+
+
+  /* printk("Allocating %u for LinkQ ", (ULONG)sizeof(FC_LINK_QUE)); */
+  cpqfcHBAdata->fcLQ = pci_alloc_consistent(cpqfcHBAdata->PciDev,
+				 sizeof( FC_LINK_QUE), &cpqfcHBAdata->fcLQ_dma_handle);
+  /* printk("@ %p (%u elements)\n", cpqfcHBAdata->fcLQ, FC_LINKQ_DEPTH); */
+
+  if( cpqfcHBAdata->fcLQ == NULL ) // fatal error!!
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("pci_alloc_consistent() failure on fc Link Que: fatal error\n");
+    return -1;
+  }
+  // zero out the entire EXCHANGE space
+  memset( cpqfcHBAdata->fcLQ, 0, sizeof( FC_LINK_QUE));  
+  
+  // Verify that basic Tach I/O registers are not NULL  
+  if( !fcChip->Registers.ReMapMemBase )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("HBA base address NULL: fatal error\n");
+    return -1;
+  }
+
+
+  // Initialize the fcMemManager memory pairs (stores allocated/aligned
+  // pairs for future freeing)
+  memset( cpqfcHBAdata->dynamic_mem, 0, sizeof(cpqfcHBAdata->dynamic_mem));
+  
+
+  // Allocate Tach's Exchange Request Queue (each ERQ entry 32 bytes)
+  
+  fcChip->ERQ = fcMemManager( cpqfcHBAdata->PciDev, 
+			&cpqfcHBAdata->dynamic_mem[0], 
+			sizeof( TachLiteERQ ), 32*(ERQ_LEN), 0L, &ERQdma);
+  if( !fcChip->ERQ )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("pci_alloc_consistent/alignment failure on ERQ: fatal error\n");
+    return -1;
+  }
+  fcChip->ERQ->length = ERQ_LEN-1;
+  ulAddr = (ULONG) ERQdma; 
+#if BITS_PER_LONG > 32
+  if( (ulAddr >> 32) )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk(" FATAL! ERQ ptr %p exceeds Tachyon's 32-bit register size\n",
+		    (void*)ulAddr);
+    return -1;  // failed
+  }
+#endif
+  fcChip->ERQ->base = (ULONG)ulAddr;  // copy for quick reference
+
+
+  // Allocate Tach's Inbound Message Queue (32 bytes per entry)
+  
+  fcChip->IMQ = fcMemManager( cpqfcHBAdata->PciDev, 
+		  &cpqfcHBAdata->dynamic_mem[0],
+		  sizeof( TachyonIMQ ), 32*(IMQ_LEN), 0L, &IMQdma );
+  if( !fcChip->IMQ )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("pci_alloc_consistent/alignment failure on IMQ: fatal error\n");
+    return -1;
+  }
+  fcChip->IMQ->length = IMQ_LEN-1;
+
+  ulAddr = IMQdma;
+#if BITS_PER_LONG > 32
+  if( (ulAddr >> 32) )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
+		    (void*)ulAddr);
+    return -1;  // failed
+  }
+#endif
+  fcChip->IMQ->base = (ULONG)ulAddr;  // copy for quick reference
+
+
+  // Allocate Tach's  Single Frame Queue (64 bytes per entry)
+  fcChip->SFQ = fcMemManager( cpqfcHBAdata->PciDev, 
+		  &cpqfcHBAdata->dynamic_mem[0],
+		  sizeof( TachLiteSFQ ), 64*(SFQ_LEN),0L, &SPQdma );
+  if( !fcChip->SFQ )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("pci_alloc_consistent/alignment failure on SFQ: fatal error\n");
+    return -1;
+  }
+  fcChip->SFQ->length = SFQ_LEN-1;      // i.e. Que length [# entries -
+                                       // min. 32; max.  4096 (0xffff)]
+  
+  ulAddr = SPQdma;
+#if BITS_PER_LONG > 32
+  if( (ulAddr >> 32) )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
+		    (void*)ulAddr);
+    return -1;  // failed
+  }
+#endif
+  fcChip->SFQ->base = (ULONG)ulAddr;  // copy for quick reference
+
+
+  // Allocate SCSI Exchange State Table; aligned nearest @sizeof
+  // power-of-2 boundary
+  // LIVE DANGEROUSLY!  Assume the boundary for SEST mem will
+  // be on physical page (e.g. 4k) boundary.
+  /* printk("Allocating %u for TachSEST for %u Exchanges\n", 
+		 (ULONG)sizeof(TachSEST), TACH_SEST_LEN); */
+  fcChip->SEST = fcMemManager( cpqfcHBAdata->PciDev,
+		  &cpqfcHBAdata->dynamic_mem[0],
+		  sizeof(TachSEST),  4, 0L, &SESTdma );
+//		  sizeof(TachSEST),  64*TACH_SEST_LEN, 0L );
+  if( !fcChip->SEST )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk("pci_alloc_consistent/alignment failure on SEST: fatal error\n");
+    return -1;
+  }
+
+  for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
+      fcChip->SEST->sgPages[i] = NULL;
+
+  fcChip->SEST->length = TACH_SEST_LEN;  // e.g. DON'T subtract one 
+                                       // (TL/TS UG, pg 153)
+
+  ulAddr = SESTdma; 
+#if BITS_PER_LONG > 32
+  if( (ulAddr >> 32) )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk(" FATAL! SFQ ptr %p exceeds Tachyon's 32-bit register size\n",
+		    (void*)ulAddr);
+    return -1;  // failed
+  }
+#endif
+  fcChip->SEST->base = (ULONG)ulAddr;  // copy for quick reference
+
+
+			      // Now that structures are defined,
+			      // fill in Tachyon chip registers...
+
+			      // EEEEEEEE  EXCHANGE REQUEST QUEUE
+
+  writel( fcChip->ERQ->base, 
+    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
+      
+  writel( fcChip->ERQ->length,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_LENGTH));
+     
+
+  fcChip->ERQ->producerIndex = 0L;
+  writel( fcChip->ERQ->producerIndex,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX));
+      
+
+		// NOTE! write consumer index last, since the write
+		// causes Tachyon to process the other registers
+
+  ulAddr = ((unsigned long)&fcChip->ERQ->consumerIndex - 
+		(unsigned long)fcChip->ERQ) + (unsigned long) ERQdma;
+
+  // NOTE! Tachyon DMAs to the ERQ consumer Index host
+		// address; must be correctly aligned
+  writel( (ULONG)ulAddr,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_CONSUMER_INDEX_ADR));
+
+
+
+				 // IIIIIIIIIIIII  INBOUND MESSAGE QUEUE
+				 // Tell Tachyon where the Que starts
+
+  // set the Host's pointer for Tachyon to access
+
+  /* printk("  cpqfcTS: writing IMQ BASE %Xh  ", fcChip->IMQ->base ); */
+  writel( fcChip->IMQ->base, 
+    (fcChip->Registers.ReMapMemBase + IMQ_BASE));
+
+  writel( fcChip->IMQ->length,
+    (fcChip->Registers.ReMapMemBase + IMQ_LENGTH));
+
+  writel( fcChip->IMQ->consumerIndex,
+    (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
+
+
+		// NOTE: TachLite DMAs to the producerIndex host address
+		// must be correctly aligned with address bits 1-0 cleared
+    // Writing the BASE register clears the PI register, so write it last
+  ulAddr = ((unsigned long)&fcChip->IMQ->producerIndex - 
+		(unsigned long)fcChip->IMQ) + (unsigned long) IMQdma;
+
+#if BITS_PER_LONG > 32
+  if( (ulAddr >> 32) )
+  {
+    cpqfc_free_dma_consistent(cpqfcHBAdata);
+    printk(" FATAL! IMQ ptr %p exceeds Tachyon's 32-bit register size\n",
+		    (void*)ulAddr);
+    return -1;  // failed
+  }
+#endif
+#if DBG
+  printk("  PI %Xh\n", (ULONG)ulAddr );
+#endif
+  writel( (ULONG)ulAddr, 
+    (fcChip->Registers.ReMapMemBase + IMQ_PRODUCER_INDEX));
+
+
+
+				 // SSSSSSSSSSSSSSS SINGLE FRAME SEQUENCE
+				 // Tell TachLite where the Que starts
+
+  writel( fcChip->SFQ->base, 
+    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_BASE));
+
+  writel( fcChip->SFQ->length,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_SFQ_LENGTH));
+
+
+         // tell TachLite where SEST table is & how long
+  writel( fcChip->SEST->base,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE));
+
+  /* printk("  cpqfcTS: SEST %p(virt): Wrote base %Xh @ %p\n",
+    fcChip->SEST, fcChip->SEST->base, 
+    fcChip->Registers.ReMapMemBase + TL_MEM_SEST_BASE); */
+
+  writel( fcChip->SEST->length,
+    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_LENGTH));
+      
+  writel( (TL_EXT_SG_PAGE_COUNT-1),
+    (fcChip->Registers.ReMapMemBase + TL_MEM_SEST_SG_PAGE));
+
+
+  LEAVE("CreateTachLiteQues");
+
+  return iStatus;
+}
+
+
+
+// function to return TachLite to Power On state
+// 1st - reset tachyon ('SOFT' reset)
+// others - future
+
+int CpqTsResetTachLite(void *pHBA, int type)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  ULONG ulBuff, i;
+  int ret_status=0; // def. success
+
+  ENTER("ResetTach");
+  
+  switch(type)
+  {
+
+    case CLEAR_FCPORTS:
+
+      // in case he was running previously, mask Tach's interrupt
+      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
+      
+     // de-allocate mem for any Logged in ports
+      // (e.g., our module is unloading)
+      // search the forward linked list, de-allocating
+      // the memory we allocated when the port was initially logged in
+      {
+        PFC_LOGGEDIN_PORT pLoggedInPort = fcChip->fcPorts.pNextPort;
+        PFC_LOGGEDIN_PORT ptr;
+//        printk("checking for allocated LoggedInPorts...\n");
+			
+        while( pLoggedInPort )
+        {
+          ptr = pLoggedInPort;
+          pLoggedInPort = ptr->pNextPort;
+//	  printk("kfree(%p) on FC LoggedInPort port_id 0x%06lX\n",
+//			  ptr, ptr->port_id);
+          kfree( ptr );
+        }
+      }
+      // (continue resetting hardware...)
+
+    case 1:                   // RESTART Tachyon (power-up state)
+
+      // in case he was running previously, mask Tach's interrupt
+      writeb( 0, (fcChip->Registers.ReMapMemBase + IINTEN));
+			      // turn OFF laser (NOTE: laser is turned
+                              // off during reset, because GPIO4 is cleared
+                              // to 0 by reset action - see TLUM, sec 7.22)
+                              // However, CPQ 64-bit HBAs have a "health
+                              // circuit" which keeps laser ON for a brief
+                              // period after it is turned off ( < 1s)
+      
+      fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 0);
+  
+
+
+            // soft reset timing constraints require:
+            //   1. set RST to 1
+            //   2. read SOFTRST register 
+            //      (128 times per R. Callison code)
+            //   3. clear PCI ints
+            //   4. clear RST to 0
+      writel( 0xff000001L,
+        (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+        
+      for( i=0; i<128; i++)
+        ulBuff = readl( fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST);
+
+        // clear the soft reset
+      for( i=0; i<8; i++)
+  	writel( 0, (fcChip->Registers.ReMapMemBase + TL_MEM_SOFTRST));
+
+               
+
+			       // clear out our copy of Tach regs,
+			       // because they must be invalid now,
+			       // since TachLite reset all his regs.
+      CpqTsDestroyTachLiteQues(cpqfcHBAdata,0); // remove Host-based Que structs
+      cpqfcTSClearLinkStatusCounters(fcChip);  // clear our s/w accumulators
+                               // lower bits give GBIC info
+      fcChip->Registers.TYstatus.value = 
+	              readl( fcChip->Registers.TYstatus.address );
+      break;
+
+/*
+    case 2:                   // freeze SCSI
+    case 3:                   // reset Outbound command que (ERQ)
+    case 4:                   // unfreeze OSM (Outbound Seq. Man.) 'er'
+    case 5:                   // report status
+
+    break;
+*/
+    default:
+      ret_status = -1;  // invalid option passed to RESET function
+      break;
+  }
+  LEAVE("ResetTach");
+  return ret_status;
+}
+
+
+
+
+
+
+// 'addrBase' is IOBaseU for both TachLite and (older) Tachyon
+int CpqTsLaserControl( void* addrBase, int opcode )
+{
+  ULONG dwBuff;
+
+  dwBuff = readl((addrBase + TL_MEM_TACH_CONTROL) ); // read TL Control reg
+                                                    // (change only bit 4)
+  if( opcode == 1)
+    dwBuff |= ~0xffffffefL; // set - ON
+  else
+    dwBuff &= 0xffffffefL;  // clear - OFF
+  writel( dwBuff, (addrBase + TL_MEM_TACH_CONTROL)); // write TL Control reg
+  return 0;
+}
+
+
+
+
+
+// Use controller's "Options" field to determine loopback mode (if any)
+//   internal loopback (silicon - no GBIC)
+//   external loopback (GBIC - no FC loop)
+//   no loopback: L_PORT, external cable from GBIC required
+
+int CpqTsInitializeFrameManager( void *pChip, int opcode)
+{
+  PTACHYON fcChip;
+  int iStatus;
+  ULONG wwnLo, wwnHi; // for readback verification
+
+  ENTER("InitializeFrameManager");
+  fcChip = (PTACHYON)pChip;
+  if( !fcChip->Registers.ReMapMemBase )   // undefined controller?
+    return -1;
+
+  // TL/TS UG, pg. 184
+  // 0x0065 = 100ms for RT_TOV
+  // 0x01f5 = 500ms for ED_TOV
+  // 0x07D1 = 2000ms 
+  fcChip->Registers.ed_tov.value = 0x006507D1; 
+  writel( fcChip->Registers.ed_tov.value,
+    (fcChip->Registers.ed_tov.address));
+      
+
+  // Set LP_TOV to the FC-AL2 specified 2 secs.
+  // TL/TS UG, pg. 185
+  writel( 0x07d00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
+
+
+  // Now try to read the WWN from the adapter's NVRAM
+  iStatus = CpqTsReadWriteWWN( fcChip, 1); // '1' for READ
+
+  if( iStatus )   // NVRAM read failed?
+  {
+    printk(" WARNING! HBA NVRAM WWN read failed - make alias\n");
+    // make up a WWN.  If NULL or duplicated on loop, FC loop may hang!
+
+
+    fcChip->Registers.wwn_hi = (__u32)jiffies;
+    fcChip->Registers.wwn_hi |= 0x50000000L;
+    fcChip->Registers.wwn_lo = 0x44556677L;
+  }
+
+  
+  writel( fcChip->Registers.wwn_hi, 
+	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI);
+  
+  writel( fcChip->Registers.wwn_lo, 
+	  fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+	  
+
+  // readback for verification:
+  wwnHi = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_HI ); 
+          
+  wwnLo = readl( fcChip->Registers.ReMapMemBase + TL_MEM_FM_WWN_LO);
+  // test for correct chip register WRITE/READ
+  DEBUG_PCI( printk("  WWN %08X%08X\n",
+    fcChip->Registers.wwn_hi, fcChip->Registers.wwn_lo ) );
+    
+  if( wwnHi != fcChip->Registers.wwn_hi ||
+      wwnLo != fcChip->Registers.wwn_lo )
+  {
+    printk( "cpqfcTS: WorldWideName register load failed\n");
+    return -1; // FAILED!
+  }
+
+
+
+			// set Frame Manager Initialize command
+  fcChip->Registers.FMcontrol.value = 0x06;
+
+  // Note: for test/debug purposes, we may use "Hard" address,
+  // but we completely support "soft" addressing, including
+  // dynamically changing our address.
+  if( fcChip->Options.intLoopback == 1 )            // internal loopback
+    fcChip->Registers.FMconfig.value = 0x0f002080L;
+  else if( fcChip->Options.extLoopback == 1 )            // internal loopback
+    fcChip->Registers.FMconfig.value = 0x0f004080L;
+  else                  // L_Port
+    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
+//    fcChip->Registers.FMconfig.value = 0x01000080L; // soft address (can't pick)
+//    fcChip->Registers.FMconfig.value = 0x55000100L; // hard address (55h start)
+		
+  // write config to FM
+
+  if( !fcChip->Options.intLoopback && !fcChip->Options.extLoopback )
+                               // (also need LASER for real LOOP)
+    fcChip->LaserControl( fcChip->Registers.ReMapMemBase, 1); // turn on LASER
+
+  writel( fcChip->Registers.FMconfig.value,
+    fcChip->Registers.FMconfig.address);
+    
+
+			       // issue INITIALIZE command to FM - ACTION!
+  writel( fcChip->Registers.FMcontrol.value,
+    fcChip->Registers.FMcontrol.address);
+    
+  LEAVE("InitializeFrameManager");
+  
+  return 0;
+}
+
+
+
+
+
+// This "look ahead" function examines the IMQ for occurrence of
+// "type".  Returns 1 if found, 0 if not.
+static int PeekIMQEntry( PTACHYON fcChip, ULONG type)
+{
+  ULONG CI = fcChip->IMQ->consumerIndex;
+  ULONG PI = fcChip->IMQ->producerIndex; // snapshot of IMQ indexes
+  
+  while( CI != PI )
+  {                             // proceed with search
+    if( (++CI) >= IMQ_LEN ) CI = 0; // rollover check
+    
+    switch( type )
+    {
+      case ELS_LILP_FRAME:
+      {
+      // first, we need to find an Inbound Completion message,
+      // If we find it, check the incoming frame payload (1st word)
+      // for LILP frame
+        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x104 )
+        { 
+          TachFCHDR_GCMND* fchs;
+#error This is too much stack
+          ULONG ulFibreFrame[2048/4];  // max DWORDS in incoming FC Frame
+	  USHORT SFQpi = (USHORT)(fcChip->IMQ->QEntry[CI].word[0] & 0x0fffL);
+
+	  CpqTsGetSFQEntry( fcChip,
+            SFQpi,        // SFQ producer ndx         
+	    ulFibreFrame, // contiguous dest. buffer
+	    FALSE);       // DON'T update chip--this is a "lookahead"
+          
+	  fchs = (TachFCHDR_GCMND*)&ulFibreFrame;
+          if( fchs->pl[0] == ELS_LILP_FRAME)
+	  {
+            return 1; // found the LILP frame!
+	  }
+	  else
+	  {
+	    // keep looking...
+	  }
+	}  
+      }
+      break;
+
+      case OUTBOUND_COMPLETION:
+        if( (fcChip->IMQ->QEntry[CI].type & 0x1FF) == 0x00 )
+	{
+
+          // any OCM errors?
+          if( fcChip->IMQ->QEntry[CI].word[2] & 0x7a000000L )
+            return 1;   	    // found OCM error
+	}
+      break;
+
+
+      
+      default:
+      break;
+    }
+  }
+  return 0; // failed to find "type"
+}
+
+			
+static void SetTachTOV( CPQFCHBA* cpqfcHBAdata)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
+  
+  // TL/TS UG, pg. 184
+  // 0x0065 = 100ms for RT_TOV
+  // 0x01f5 = 500ms for ED_TOV
+  // 0x07d1 = 2000ms for ED_TOV
+
+  // SANMark Level 1 requires an "initialization backoff"
+  // (See "SANMark Test Suite Level 1":
+  // initialization_timeout.fcal.SANMark-1.fc)
+  // We have to use 2sec, 24sec, then 128sec when login/
+  // port discovery processes fail to complete.
+  
+  // when port discovery completes (logins done), we set
+  // ED_TOV to 500ms -- this is the normal operational case
+  // On the first Link Down, we'll move to 2 secs (7D1 ms)
+  if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x1f5)
+    fcChip->Registers.ed_tov.value = 0x006507D1; 
+  
+  // If we get another LST after we moved TOV to 2 sec,
+  // increase to 24 seconds (5DC1 ms) per SANMark!
+  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x7D1)
+    fcChip->Registers.ed_tov.value = 0x00655DC1; 
+
+  // If we get still another LST, set the max TOV (Tachyon
+  // has only 16 bits for ms timer, so the max is 65.5 sec)
+  else if( (fcChip->Registers.ed_tov.value &0xFFFF) <= 0x5DC1)
+    fcChip->Registers.ed_tov.value = 0x0065FFFF; 
+
+  writel( fcChip->Registers.ed_tov.value,
+    (fcChip->Registers.ed_tov.address));
+  // keep the same 2sec LP_TOV 
+  writel( 0x07D00010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
+}	
+
+
+// The IMQ is an array with IMQ_LEN length, each element (QEntry)
+// with eight 32-bit words.  Tachyon PRODUCES a QEntry with each
+// message it wants to send to the host.  The host CONSUMES IMQ entries
+
+// This function copies the current
+// (or oldest not-yet-processed) QEntry to
+// the caller, clears/ re-enables the interrupt, and updates the
+// (Host) Consumer Index.
+// Return value:
+//  0   message processed, none remain (producer and consumer
+//        indexes match)
+//  1   message processed, more messages remain
+// -1   no message processed - none were available to process
+// Remarks:
+//   TL/TS UG specifices that the following actions for
+//   INTA_L handling:
+//   1. read PCI Interrupt Status register (0xff)
+//   2. all IMQ messages should be processed before writing the
+//      IMQ consumer index.
+
+
+int CpqTsProcessIMQEntry(void *host)
+{
+  struct Scsi_Host *HostAdapter = (struct Scsi_Host *)host;
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip; 
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  int iStatus;
+  USHORT i, RPCset, DPCset;
+  ULONG x_ID;
+  ULONG ulBuff, dwStatus;
+  TachFCHDR_GCMND* fchs;
+#error This is too much stack
+  ULONG ulFibreFrame[2048/4];  // max number of DWORDS in incoming Fibre Frame
+  UCHAR ucInboundMessageType;  // Inbound CM, dword 3 "type" field
+
+  ENTER("ProcessIMQEntry");
+   
+
+				// check TachLite's IMQ producer index -
+				// is a new message waiting for us?
+				// equal indexes means empty que
+
+  if( fcChip->IMQ->producerIndex != fcChip->IMQ->consumerIndex )
+  {                             // need to process message
+
+
+#ifdef IMQ_DEBUG
+    printk("PI %X, CI %X  type: %X\n", 
+      fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex,
+      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type);
+#endif                                
+    // Examine Completion Messages in IMQ
+    // what CM_Type?
+    switch( (UCHAR)(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].type
+                    & 0xffL) )
+    {
+    case OUTBOUND_COMPLETION:
+
+      // Remarks:
+      // x_IDs (OX_ID, RX_ID) are partitioned by SEST entries
+      // (starting at 0), and SFS entries (starting at
+      // SEST_LEN -- outside the SEST space).
+      // Psuedo code:
+      // x_ID (OX_ID or RX_ID) from message is Trans_ID or SEST index
+      // range check - x_ID
+      //   if x_ID outside 'Transactions' length, error - exit
+      // if any OCM error, copy error status to Exchange slot
+      // if FCP ASSIST transaction (x_ID within SEST),
+      //   call fcComplete (to App)
+      // ...
+
+
+      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1];
+      x_ID = ulBuff & 0x7fffL;     // lower 14 bits SEST_Index/Trans_ID
+                                     // Range check CM OX/RX_ID value...
+      if( x_ID < TACH_MAX_XID )   // don't go beyond array space
+      {
+
+
+	if( ulBuff & 0x20000000L ) // RPC -Response Phase Complete?
+          RPCset = 1;              // (SEST transactions only)
+        else
+          RPCset = 0;
+
+        if( ulBuff & 0x40000000L ) // DPC -Data Phase Complete?
+          DPCset = 1;              // (SEST transactions only)
+        else
+          DPCset = 0;
+                // set the status for this Outbound transaction's ID
+        dwStatus = 0L;
+        if( ulBuff & 0x10000000L ) // SPE? (SEST Programming Error)
+            dwStatus |= SESTPROG_ERR;
+
+        ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2];
+        if( ulBuff & 0x7a000000L ) // any other errs?
+        {
+          if( ulBuff & 0x40000000L )
+            dwStatus |= INV_ENTRY;
+          if( ulBuff & 0x20000000L )
+            dwStatus |= FRAME_TO;        // FTO
+          if( ulBuff & 0x10000000L )
+            dwStatus |= HOSTPROG_ERR;
+          if( ulBuff & 0x08000000L )
+            dwStatus |= LINKFAIL_TX;
+          if( ulBuff & 0x02000000L )
+            dwStatus |= ABORTSEQ_NOTIFY;  // ASN
+        }
+
+	  
+	if( dwStatus )          // any errors?
+        {
+                  // set the Outbound Completion status
+          Exchanges->fcExchange[ x_ID ].status |= dwStatus;
+
+          // if this Outbound frame was for a SEST entry, automatically
+          // reque it in the case of LINKFAIL (it will restart on PDISC)
+          if( x_ID < TACH_SEST_LEN )
+          {
+
+            printk(" #OCM error %Xh x_ID %X# ", 
+		    dwStatus, x_ID);
+
+	    Exchanges->fcExchange[x_ID].timeOut = 30000; // seconds default
+                                                 
+
+	    // We Q ABTS for each exchange.
+	    // NOTE: We can get FRAME_TO on bad alpa (device gone).  Since
+	    // bad alpa is reported before FRAME_TO, examine the status
+	    // flags to see if the device is removed.  If so, DON'T
+	    // post an ABTS, since it will be terminated by the bad alpa
+	    // message.
+	    if( dwStatus & FRAME_TO ) // check for device removed...
+	    {
+	      if( !(Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED) )
+	      { 
+		// presumes device is still there: send ABTS.
+  
+                cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
+	      }
+	    }
+	    else  // Abort all other errors
+	    {
+              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
+	    }
+
+            // if the HPE bit is set, we have to CLose the LOOP
+            // (see TL/TS UG, pg. 239)
+
+            if( dwStatus &= HOSTPROG_ERR )
+            // set CL bit (see TL/TS UG, pg. 172)
+              writel( 4, fcChip->Registers.FMcontrol.address);
+          }
+        }
+          // NOTE: we don't necessarily care about ALL completion messages...
+                                      // SCSI resp. complete OR
+        if( ((x_ID < TACH_SEST_LEN) && RPCset)|| 
+             (x_ID >= TACH_SEST_LEN) )  // non-SCSI command
+        {
+              // exchange done; complete to upper levels with status
+              // (if necessary) and free the exchange slot
+            
+
+          if( x_ID >= TACH_SEST_LEN ) // Link Service Outbound frame?
+                                    // A Request or Reply has been sent
+          {                         // signal waiting WorkerThread
+
+            up( cpqfcHBAdata->TYOBcomplete);   // frame is OUT of Tach
+
+                                    // WorkerThread will complete Xchng
+          }
+          else  // X_ID is for FCP assist (SEST)
+          {
+              // TBD (target mode)
+//            fcCompleteExchange( fcChip, x_ID); // TRE completed
+          }
+        }
+      }
+      else  // ERROR CONDITION!  bogus x_ID in completion message
+      {
+
+        printk(" ProcessIMQ (OBCM) x_id out of range %Xh\n", x_ID);
+
+      }
+
+
+
+          // Load the Frame Manager's error counters.  We check them here
+          // because presumably the link is up and healthy enough for the
+          // counters to be meaningful (i.e., don't check them while loop
+          // is initializing).
+      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus1.address);
+                  
+      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus2.address);
+            
+
+      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
+    break;
+
+
+
+    case ERROR_IDLE_COMPLETION:  // TachLite Error Idle...
+    
+    // We usually get this when the link goes down during heavy traffic.
+    // For now, presume that if SEST Exchanges are open, we will
+    // get this as our cue to INVALIDATE all SEST entries
+    // (and we OWN all the SEST entries).
+    // See TL/TS UG, pg. 53
+    
+      for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
+      {
+
+        // Does this VALid SEST entry need to be invalidated for Abort?
+        fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF; 
+      }
+      
+      CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachyon, if Link OK
+
+    break;
+
+
+    case INBOUND_SFS_COMPLETION:  //0x04
+          // NOTE! we must process this SFQ message to avoid SFQ filling
+          // up and stopping TachLite.  Incoming commands are placed here,
+          // as well as 'unknown' frames (e.g. LIP loop position data)
+          // write this CM's producer index to global...
+          // TL/TS UG, pg 234:
+          // Type: 0 - reserved
+          //       1 - Unassisted FCP
+          //       2 - BAD FCP
+          //       3 - Unkown Frame
+          //       4-F reserved
+
+
+      fcChip->SFQ->producerIndex = (USHORT)
+        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] & 0x0fffL);
+
+
+      ucInboundMessageType = 0;  // default to useless frame
+
+        // we can only process two Types: 1, Unassisted FCP, and 3, Unknown
+        // Also, we aren't interested in processing frame fragments
+        // so don't Que anything with 'LKF' bit set
+      if( !(fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] 
+        & 0x40000000) )  // 'LKF' link failure bit clear?
+      {
+        ucInboundMessageType = (UCHAR)  // ICM DWord3, "Type"
+        (fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] & 0x0fL);
+      }
+      else
+      {
+	fcChip->fcStats.linkFailRX++;
+//        printk("LKF (link failure) bit set on inbound message\n");
+      }
+
+          // clears SFQ entry from Tachyon buffer; copies to contiguous ulBuff
+      CpqTsGetSFQEntry(
+        fcChip,                  // i.e. this Device Object
+        (USHORT)fcChip->SFQ->producerIndex,  // SFQ producer ndx         
+        ulFibreFrame, TRUE);    // contiguous destination buffer, update chip
+                     
+        // analyze the incoming frame outside the INT handler...
+        // (i.e., Worker)
+
+      if( ucInboundMessageType == 1 )
+      {
+        fchs = (TachFCHDR_GCMND*)ulFibreFrame; // cast to examine IB frame
+        // don't fill up our Q with garbage - only accept FCP-CMND  
+        // or XRDY frames
+        if( (fchs->d_id & 0xFF000000) == 0x06000000 ) // CMND
+        {
+	  // someone sent us a SCSI command
+	  
+//          fcPutScsiQue( cpqfcHBAdata, 
+//                        SFQ_UNASSISTED_FCP, ulFibreFrame); 
+	}
+	else if( ((fchs->d_id & 0xFF000000) == 0x07000000) || // RSP (status)
+            (fchs->d_id & 0xFF000000) == 0x05000000 )  // XRDY  
+	{
+	  ULONG x_ID;
+	  // Unfortunately, ABTS requires a Freeze on the chip so
+	  // we can modify the shared memory SEST.  When frozen,
+	  // any received Exchange frames cannot be processed by
+	  // Tachyon, so they will be dumped in here.  It is too
+	  // complex to attempt the reconstruct these frames in
+	  // the correct Exchange context, so we simply seek to
+	  // find status or transfer ready frames, and cause the
+	  // exchange to complete with errors before the timeout
+	  // expires.  We use a Linux Scsi Cmnd result code that
+	  // causes immediate retry.
+	  
+
+	  // Do we have an open exchange that matches this s_id
+	  // and ox_id?
+	  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
+	  {
+            if( (fchs->s_id & 0xFFFFFF) == 
+                 (Exchanges->fcExchange[x_ID].fchs.d_id & 0xFFFFFF) 
+		       &&
+                (fchs->ox_rx_id & 0xFFFF0000) == 
+                 (Exchanges->fcExchange[x_ID].fchs.ox_rx_id & 0xFFFF0000) )
+	    {
+    //          printk(" #R/X frame x_ID %08X# ", fchs->ox_rx_id );
+              // simulate the anticipated error - since the
+	      // SEST was frozen, frames were lost...
+              Exchanges->fcExchange[ x_ID ].status |= SFQ_FRAME;
+              
+	      // presumes device is still there: send ABTS.
+              cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID);
+	      break;  // done
+	    }
+	  }
+	}
+	  
+      }
+          
+      else if( ucInboundMessageType == 3)
+      {
+        // FC Link Service frames (e.g. PLOGI, ACC) come in here.  
+        cpqfcTSPutLinkQue( cpqfcHBAdata, SFQ_UNKNOWN, ulFibreFrame); 
+                          
+      }
+
+      else if( ucInboundMessageType == 2 ) // "bad FCP"?
+      {
+#ifdef IMQ_DEBUG
+        printk("Bad FCP incoming frame discarded\n");
+#endif
+      }
+
+      else // don't know this type
+      {
+#ifdef IMQ_DEBUG 
+        printk("Incoming frame discarded, type: %Xh\n", ucInboundMessageType);
+#endif
+      }
+        
+        // Check the Frame Manager's error counters.  We check them here
+        // because presumably the link is up and healthy enough for the
+        // counters to be meaningful (i.e., don't check them while loop
+        // is initializing).
+      fcChip->Registers.FMLinkStatus1.value =    // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus1.address);
+                  
+
+      fcChip->Registers.FMLinkStatus2.value =    // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus2.address);
+                
+
+      break;
+
+
+
+
+                    // We get this CM because we issued a freeze
+                    // command to stop outbound frames.  We issue the
+                    // freeze command at Link Up time; when this message
+                    // is received, the ERQ base can be switched and PDISC
+                    // frames can be sent.
+
+      
+    case ERQ_FROZEN_COMPLETION:  // note: expect ERQ followed immediately
+                                 // by FCP when freezing TL
+      fcChip->Registers.TYstatus.value =         // read what's frozen
+        readl(fcChip->Registers.TYstatus.address);
+      // (do nothing; wait for FCP frozen message)
+      break;
+    case FCP_FROZEN_COMPLETION:
+      
+      fcChip->Registers.TYstatus.value =         // read what's frozen
+        readl(fcChip->Registers.TYstatus.address);
+      
+      // Signal the kernel thread to proceed with SEST modification
+      up( cpqfcHBAdata->TachFrozen);
+
+      break;
+
+
+
+    case INBOUND_C1_TIMEOUT:
+    case MFS_BUF_WARN:
+    case IMQ_BUF_WARN:
+    break;
+
+
+
+
+
+        // In older Tachyons, we 'clear' the internal 'core' interrupt state
+        // by reading the FMstatus register.  In newer TachLite (Tachyon),
+        // we must WRITE the register
+        // to clear the condition (TL/TS UG, pg 179)
+    case FRAME_MGR_INTERRUPT:
+    {
+      PFC_LOGGEDIN_PORT pLoggedInPort; 
+
+      fcChip->Registers.FMstatus.value = 
+        readl( fcChip->Registers.FMstatus.address );
+                
+      // PROBLEM: It is possible, especially with "dumb" hubs that
+      // don't automatically LIP on by-pass of ports that are going
+      // away, for the hub by-pass process to destroy critical 
+      // ordered sets of a frame.  The result of this is a hung LPSM
+      // (Loop Port State Machine), which on Tachyon results in a
+      // (default 2 sec) Loop State Timeout (LST) FM message.  We 
+      // want to avoid this relatively huge timeout by detecting
+      // likely scenarios which will result in LST.
+      // To do this, we could examine FMstatus for Loss of Synchronization
+      // and/or Elastic Store (ES) errors.  Of these, Elastic Store is better
+      // because we get this indication more quickly than the LOS.
+      // Not all ES errors are harmfull, so we don't want to LIP on every
+      // ES.  Instead, on every ES, detect whether our LPSM in in one
+      // of the LST states: ARBITRATING, OPEN, OPENED, XMITTED CLOSE,
+      // or RECEIVED CLOSE.  (See TL/TS UG, pg. 181)
+      // If any of these LPSM states are detected
+      // in combination with the LIP while LDn is not set, 
+      // send an FM init (LIP F7,F7 for loops)!
+      // It is critical to the physical link stability NOT to reset (LIP)
+      // more than absolutely necessary; this is a basic premise of the
+      // SANMark level 1 spec.
+      {
+	ULONG Lpsm = (fcChip->Registers.FMstatus.value & 0xF0) >>4;
+	
+	if( (fcChip->Registers.FMstatus.value & 0x400)  // ElasticStore?
+                      &&
+            !(fcChip->Registers.FMstatus.value & 0x100) // NOT LDn
+	              &&
+            !(fcChip->Registers.FMstatus.value & 0x1000)) // NOT LF
+	{
+	  if( (Lpsm != 0) || // not MONITORING? or
+	      !(Lpsm & 0x8) )// not already offline?
+	  {
+	  // now check the particular LST states...
+            if( (Lpsm == ARBITRATING) || (Lpsm == OPEN) ||
+	      (Lpsm == OPENED)      || (Lpsm == XMITTD_CLOSE) ||
+	      (Lpsm == RCVD_CLOSE) )
+	    {
+	      // re-init the loop before it hangs itself!
+              printk(" #req FMinit on E-S: LPSM %Xh# ",Lpsm);
+
+
+	      fcChip->fcStats.FMinits++;
+              writel( 6, fcChip->Registers.FMcontrol.address); // LIP
+	    }
+	  }
+	}
+	else if( fcChip->Registers.FMstatus.value & 0x40000 ) // LST?
+	{
+          printk(" #req FMinit on LST, LPSM %Xh# ",Lpsm);
+	 
+          fcChip->fcStats.FMinits++;
+          writel( 6, fcChip->Registers.FMcontrol.address);  // LIP
+	}  
+      }
+
+
+      // clear only the 'interrupting' type bits for this REG read
+      writel( (fcChip->Registers.FMstatus.value & 0xff3fff00L),
+        fcChip->Registers.FMstatus.address);
+                          
+
+               // copy frame manager status to unused ULONG slot
+      fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0] =
+          fcChip->Registers.FMstatus.value; // (for debugging)
+
+
+          // Load the Frame Manager's error counters.  We check them here
+          // because presumably the link is up and healthy enough for the
+          // counters to be meaningful (i.e., don't check them while loop
+          // is initializing).
+      fcChip->Registers.FMLinkStatus1.value =   // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus1.address);
+            
+      fcChip->Registers.FMLinkStatus2.value =   // get TL's counter
+        readl(fcChip->Registers.FMLinkStatus2.address);
+          
+          // Get FM BB_Credit Zero Reg - does not clear on READ
+      fcChip->Registers.FMBB_CreditZero.value =   // get TL's counter
+        readl(fcChip->Registers.FMBB_CreditZero.address);
+            
+
+
+      fcParseLinkStatusCounters( fcChip); // load into 6 s/w accumulators
+
+
+               // LINK DOWN
+
+      if( fcChip->Registers.FMstatus.value & 0x100L ) // Link DOWN bit
+      {                                 
+	
+#ifdef IMQ_DEBUG
+        printk("LinkDn\n");
+#endif
+        printk(" #LDn# ");
+        
+        fcChip->fcStats.linkDown++;
+        
+	SetTachTOV( cpqfcHBAdata);  // must set according to SANMark
+
+	// Check the ERQ - force it to be "empty" to prevent Tach
+	// from sending out frames before we do logins.
+
+
+  	if( fcChip->ERQ->producerIndex != fcChip->ERQ->consumerIndex)
+	{
+//	  printk("#ERQ PI != CI#");
+          CpqTsFreezeTachlite( fcChip, 1); // freeze ERQ only	  
+	  fcChip->ERQ->producerIndex = fcChip->ERQ->consumerIndex = 0;
+ 	  writel( fcChip->ERQ->base, 
+	    (fcChip->Registers.ReMapMemBase + TL_MEM_ERQ_BASE));
+          // re-writing base forces ERQ PI to equal CI
+  
+	}
+		
+	// link down transition occurred -- port_ids can change
+        // on next LinkUp, so we must invalidate current logins
+        // (and any I/O in progress) until PDISC or PLOGI/PRLI
+        // completes
+        {
+          pLoggedInPort = &fcChip->fcPorts; 
+          while( pLoggedInPort ) // for all ports which are expecting
+                                 // PDISC after the next LIP, set the
+                                 // logoutTimer
+          {
+
+	    if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
+            {
+              pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
+                                              // but Timer granularity
+                                              // is 1 second
+            }
+                                // suspend any I/O in progress until
+                                // PDISC received...
+            pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
+	    
+            pLoggedInPort = pLoggedInPort->pNextPort;
+          }  // ... all Previously known ports checked
+        }
+        
+	// since any hot plugging device may NOT support LILP frames
+	// (such as early Tachyon chips), clear this flag indicating
+	// we shouldn't use (our copy of) a LILP map.
+	// If we receive an LILP frame, we'll set it again.
+	fcChip->Options.LILPin = 0; // our LILPmap is invalid
+        cpqfcHBAdata->PortDiscDone = 0; // must re-validate FC ports!
+
+          // also, we want to invalidate (i.e. INITIATOR_ABORT) any
+          // open Login exchanges, in case the LinkDown happened in the
+          // middle of logins.  It's possible that some ports already
+          // ACCepted login commands which we have not processed before
+          // another LinkDown occurred.  Any accepted Login exhanges are
+          // invalidated by LinkDown, even before they are acknowledged.
+          // It's also possible for a port to have a Queued Reply or Request
+          // for login which was interrupted by LinkDown; it may come later,
+          // but it will be unacceptable to us.
+
+          // we must scan the entire exchange space, find every Login type
+          // originated by us, and abort it. This is NOT an abort due to
+          // timeout, so we don't actually send abort to the other port -
+          // we just complete it to free up the fcExchange slot.
+
+        for( i=TACH_SEST_LEN; i< TACH_MAX_XID; i++)
+        {                     // looking for Extended Link Serv.Exchanges
+          if( Exchanges->fcExchange[i].type == ELS_PDISC ||
+              Exchanges->fcExchange[i].type == ELS_PLOGI ||
+              Exchanges->fcExchange[i].type == ELS_PRLI ) 
+          {
+              // ABORT the exchange!
+#ifdef IMQ_DEBUG
+            printk("Originator ABORT x_id %Xh, type %Xh, port_id %Xh on LDn\n",
+              i, Exchanges->fcExchange[i].type,
+            Exchanges->fcExchange[i].fchs.d_id);
+#endif
+
+            Exchanges->fcExchange[i].status |= INITIATOR_ABORT;
+            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i); // abort on LDn
+          }
+        }
+
+      }
+
+             // ################   LINK UP   ##################
+      if( fcChip->Registers.FMstatus.value & 0x200L ) // Link Up bit
+      {                                 // AL_PA could have changed
+
+          // We need the following code, duplicated from LinkDn condition,
+          // because it's possible for the Tachyon to re-initialize (hard
+          // reset) without ever getting a LinkDn indication.
+        pLoggedInPort = &fcChip->fcPorts; 
+        while( pLoggedInPort )   // for all ports which are expecting
+                                 // PDISC after the next LIP, set the
+                                 // logoutTimer
+        {
+          if( pLoggedInPort->pdisc) // expecting PDISC within 2 sec?
+          {
+            pLoggedInPort->LOGO_timer = 3;  // we want 2 seconds
+                                              // but Timer granularity
+                                              // is 1 second
+             
+                                  // suspend any I/O in progress until
+                                  // PDISC received...
+
+          }
+          pLoggedInPort = pLoggedInPort->pNextPort;
+        }  // ... all Previously known ports checked
+ 
+          // CpqTs acquired AL_PA in register AL_PA (ACQ_ALPA)
+        fcChip->Registers.rcv_al_pa.value = 
+          readl(fcChip->Registers.rcv_al_pa.address);
+ 
+	// Now, if our acquired address is DIFFERENT from our
+        // previous one, we are not allow to do PDISC - we
+        // must go back to PLOGI, which will terminate I/O in
+        // progress for ALL logged in FC devices...
+	// (This is highly unlikely).
+
+	if( (fcChip->Registers.my_al_pa & 0xFF) != 
+	    ((fcChip->Registers.rcv_al_pa.value >> 16) &0xFF) )
+	{
+
+//	  printk(" #our HBA port_id changed!# "); // FC port_id changed!!	
+
+	  pLoggedInPort = &fcChip->fcPorts; 
+          while( pLoggedInPort ) // for all ports which are expecting
+                                 // PDISC after the next LIP, set the
+                                 // logoutTimer
+          {
+	    pLoggedInPort->pdisc  = FALSE;
+            pLoggedInPort->prli = FALSE;
+            pLoggedInPort = pLoggedInPort->pNextPort;
+          }  // ... all Previously known ports checked
+
+	  // when the port_id changes, we must terminate
+	  // all open exchanges.
+          cpqfcTSTerminateExchange( cpqfcHBAdata, NULL, PORTID_CHANGED);
+
+	}
+	               
+	// Replace the entire 24-bit port_id.  We only know the
+	// lower 8 bits (alpa) from Tachyon; if a FLOGI is done,
+	// we'll get the upper 16-bits from the FLOGI ACC frame.
+	// If someone plugs into Fabric switch, we'll do FLOGI and
+	// get full 24-bit port_id; someone could then remove and
+	// hot-plug us into a dumb hub.  If we send a 24-bit PLOGI
+	// to a "private" loop device, it might blow up.
+	// Consequently, we force the upper 16-bits of port_id to
+	// be re-set on every LinkUp transition
+        fcChip->Registers.my_al_pa =
+          (fcChip->Registers.rcv_al_pa.value >> 16) & 0xFF;
+
+              
+              // copy frame manager status to unused ULONG slot
+        fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
+          fcChip->Registers.my_al_pa; // (for debugging)
+
+              // for TachLite, we need to write the acquired al_pa
+              // back into the FMconfig register, because after
+              // first initialization, the AQ (prev. acq.) bit gets
+              // set, causing TL FM to use the AL_PA field in FMconfig.
+              // (In Tachyon, FM writes the acquired AL_PA for us.)
+        ulBuff = readl( fcChip->Registers.FMconfig.address);
+        ulBuff &= 0x00ffffffL;  // mask out current al_pa
+        ulBuff |= ( fcChip->Registers.my_al_pa << 24 ); // or in acq. al_pa
+        fcChip->Registers.FMconfig.value = ulBuff; // copy it back
+        writel( fcChip->Registers.FMconfig.value,  // put in TachLite
+          fcChip->Registers.FMconfig.address);
+            
+
+#ifdef IMQ_DEBUG
+        printk("#LUp %Xh, FMstat 0x%08X#", 
+		fcChip->Registers.my_al_pa, fcChip->Registers.FMstatus.value);
+#endif
+
+              // also set the WRITE-ONLY My_ID Register (for Fabric
+              // initialization)
+        writel( fcChip->Registers.my_al_pa,
+          fcChip->Registers.ReMapMemBase +TL_MEM_TACH_My_ID);
+          
+
+        fcChip->fcStats.linkUp++;
+
+                                     // reset TL statistics counters
+                                     // (we ignore these error counters
+                                     // while link is down)
+        ulBuff =                     // just reset TL's counter
+                 readl( fcChip->Registers.FMLinkStatus1.address);
+          
+        ulBuff =                     // just reset TL's counter
+                 readl( fcChip->Registers.FMLinkStatus2.address);
+
+          // for initiator, need to start verifying ports (e.g. PDISC)
+
+
+
+         
+      
+      
+	CpqTsUnFreezeTachlite( fcChip, 2); // unfreeze Tachlite, if Link OK
+	
+	// Tachyon creates an interesting problem for us on LILP frames.
+	// Instead of writing the incoming LILP frame into the SFQ before
+	// indicating LINK UP (the actual order of events), Tachyon tells
+	// us LINK UP, and later us the LILP.  So we delay, then examine the
+	// IMQ for an Inbound CM (x04); if found, we can set
+	// LINKACTIVE after processing the LILP.  Otherwise, just proceed.
+	// Since Tachyon imposes this time delay (and doesn't tell us
+	// what it is), we have to impose a delay before "Peeking" the IMQ
+	// for Tach hardware (DMA) delivery.
+	// Processing LILP is required by SANMark
+	udelay( 1000);  // microsec delay waiting for LILP (if it comes)
+        if( PeekIMQEntry( fcChip, ELS_LILP_FRAME) )
+	{  // found SFQ LILP, which will post LINKACTIVE	  
+//	  printk("skipping LINKACTIVE post\n");
+
+	}
+	else
+          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, ulFibreFrame);  
+      }
+
+
+
+      // ******* Set Fabric Login indication ********
+      if( fcChip->Registers.FMstatus.value & 0x2000 )
+      {
+	printk(" #Fabric# ");
+        fcChip->Options.fabric = 1;
+      }
+      else
+        fcChip->Options.fabric = 0;
+
+      
+      
+                             // ******* LIP(F8,x) or BAD AL_PA? ********
+      if( fcChip->Registers.FMstatus.value & 0x30000L )
+      {
+                        // copy the error AL_PAs
+        fcChip->Registers.rcv_al_pa.value = 
+          readl(fcChip->Registers.rcv_al_pa.address);
+            
+                        // Bad AL_PA?
+        if( fcChip->Registers.FMstatus.value & 0x10000L )
+        {
+          PFC_LOGGEDIN_PORT pLoggedInPort;
+        
+                       // copy "BAD" al_pa field
+          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1] =
+              (fcChip->Registers.rcv_al_pa.value & 0xff00L) >> 8;
+
+	  pLoggedInPort = fcFindLoggedInPort( fcChip,
+            NULL,     // DON'T search Scsi Nexus
+            fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1], // port id
+            NULL,     // DON'T search linked list for FC WWN
+            NULL);    // DON'T care about end of list
+ 
+	  if( pLoggedInPort )
+	  {
+            // Just in case we got this BAD_ALPA because a device
+	    // quietly disappeared (can happen on non-managed hubs such 
+	    // as the Vixel Rapport 1000),
+	    // do an Implicit Logout.  We never expect this on a Logged
+	    // in port (but do expect it on port discovery).
+	    // (As a reasonable alternative, this could be changed to 
+	    // simply start the implicit logout timer, giving the device
+	    // several seconds to "come back".)
+	    // 
+	    printk(" #BAD alpa %Xh# ",
+		   fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[1]);
+            cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+	  }
+        }
+                        // LIP(f8,x)?
+        if( fcChip->Registers.FMstatus.value & 0x20000L )
+        {
+                        // for debugging, copy al_pa field
+          fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[2] =
+              (fcChip->Registers.rcv_al_pa.value & 0xffL);
+                        // get the other port's al_pa
+                        // (one that sent LIP(F8,?) )
+        }
+      }
+
+                             // Elastic store err
+      if( fcChip->Registers.FMstatus.value & 0x400L )
+      {
+            // don't count e-s if loop is down!
+        if( !(USHORT)(fcChip->Registers.FMstatus.value & 0x80) )
+          fcChip->fcStats.e_stores++;
+          
+      }
+    }
+    break;
+
+
+    case INBOUND_FCP_XCHG_COMPLETION:  // 0x0C
+
+    // Remarks:
+    // On Tachlite TL/TS, we get this message when the data phase
+    // of a SEST inbound transfer is complete.  For example, if a WRITE command
+    // was received with OX_ID 0, we might respond with XFER_RDY with
+    // RX_ID 8001.  This would start the SEST controlled data phases.  When
+    // all data frames are received, we get this inbound completion. This means
+    // we should send a status frame to complete the status phase of the 
+    // FCP-SCSI exchange, using the same OX_ID,RX_ID that we used for data
+    // frames.
+    // See Outbound CM discussion of x_IDs
+    // Psuedo Code
+    //   Get SEST index (x_ID)
+    //     x_ID out of range, return (err condition)
+    //   set status bits from 2nd dword
+    //   free transactionID & SEST entry
+    //   call fcComplete with transactionID & status
+
+      ulBuff = fcChip->IMQ->QEntry[fcChip->IMQ->consumerIndex].word[0];
+      x_ID = ulBuff & 0x7fffL;  // lower 14 bits SEST_Index/Trans_ID
+                                // (mask out MSB "direction" bit)
+                                // Range check CM OX/RX_ID value...
+      if( x_ID < TACH_SEST_LEN )  // don't go beyond SEST array space
+      {
+
+//#define FCP_COMPLETION_DBG 1
+#ifdef FCP_COMPLETION_DBG
+        printk(" FCP_CM x_ID %Xh, status %Xh, Cmnd %p\n", 
+          x_ID, ulBuff, Exchanges->fcExchange[x_ID].Cmnd);
+#endif
+        if( ulBuff & 0x08000000L ) // RPC -Response Phase Complete - or -
+                                   // time to send response frame?
+          RPCset = 1;             // (SEST transaction)
+        else
+          RPCset = 0;
+                // set the status for this Inbound SCSI transaction's ID
+        dwStatus = 0L;
+        if( ulBuff & 0x70000000L ) // any errs?
+        {
+          
+          if( ulBuff & 0x40000000L )
+            dwStatus |= LINKFAIL_RX;
+          
+	  if( ulBuff & 0x20000000L )
+            dwStatus |= COUNT_ERROR;
+          
+          if( ulBuff & 0x10000000L )
+            dwStatus |= OVERFLOW;
+        }
+      
+	
+	  // FCP transaction done - copy status
+        Exchanges->fcExchange[ x_ID ].status = dwStatus;
+
+
+        // Did the exchange get an FCP-RSP response frame?
+        // (Note the little endian/big endian FC payload difference)
+
+        if( RPCset )             // SEST transaction Response frame rec'd
+        {
+    	  // complete the command in our driver...
+          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev,fcChip, x_ID);
+
+        }  // end "RPCset"
+	
+        else  // ("target" logic)
+        {
+            // Tachlite says all data frames have been received - now it's time
+            // to analyze data transfer (successful?), then send a response 
+            // frame for this exchange
+
+          ulFibreFrame[0] = x_ID; // copy for later reference
+
+          // if this was a TWE, we have to send satus response
+          if( Exchanges->fcExchange[ x_ID].type == SCSI_TWE )
+	  {
+//            fcPutScsiQue( cpqfcHBAdata, 
+//                NEED_FCP_RSP, ulFibreFrame);  // (ulFibreFrame not used here)
+	  }
+        }
+      }
+      else  // ERROR CONDITION!  bogus x_ID in completion message
+      {
+        printk("IN FCP_XCHG: bad x_ID: %Xh\n", x_ID);
+      }
+
+    break;
+
+
+
+
+    case INBOUND_SCSI_DATA_COMMAND:
+    case BAD_SCSI_FRAME:
+    case INB_SCSI_STATUS_COMPLETION:
+    case BUFFER_PROCESSED_COMPLETION:
+    break;
+    }
+
+					   // Tachyon is producing;
+					   // we are consuming
+    fcChip->IMQ->consumerIndex++;             // increment OUR consumerIndex
+    if( fcChip->IMQ->consumerIndex >= IMQ_LEN)// check for rollover
+      fcChip->IMQ->consumerIndex = 0L;        // reset it
+
+
+    if( fcChip->IMQ->producerIndex == fcChip->IMQ->consumerIndex )
+    {                           // all Messages are processed -
+      iStatus = 0;              // no more messages to process
+
+    }
+    else
+      iStatus = 1;              // more messages to process
+
+    // update TachLite's ConsumerIndex... (clears INTA_L)
+    // NOTE: according to TL/TS UG, the 
+    // "host must return completion messages in sequential order".
+    // Does this mean one at a time, in the order received?  We
+    // presume so.
+
+    writel( fcChip->IMQ->consumerIndex,
+      (fcChip->Registers.ReMapMemBase + IMQ_CONSUMER_INDEX));
+		    
+#if IMQ_DEBUG
+    printk("Process IMQ: writing consumer ndx %d\n ", 
+      fcChip->IMQ->consumerIndex);
+    printk("PI %X, CI %X\n", 
+    fcChip->IMQ->producerIndex,fcChip->IMQ->consumerIndex );
+#endif
+  
+
+
+  }
+  else
+  {
+   // hmmm... why did we get interrupted/called with no message?
+    iStatus = -1;               // nothing to process
+#if IMQ_DEBUG
+    printk("Process IMQ: no message PI %Xh  CI %Xh", 
+      fcChip->IMQ->producerIndex,
+      fcChip->IMQ->consumerIndex);
+#endif
+  }
+
+  LEAVE("ProcessIMQEntry");
+  
+  return iStatus;
+}
+
+
+
+
+
+// This routine initializes Tachyon according to the following
+// options (opcode1):
+// 1 - RESTART Tachyon, simulate power on condition by shutting
+//     down laser, resetting the hardware, de-allocating all buffers;
+//     continue
+// 2 - Config Tachyon / PCI registers;
+//     continue
+// 3 - Allocating memory and setting Tachyon queues (write Tachyon regs);
+//     continue
+// 4 - Config frame manager registers, initialize, turn on laser
+//
+// Returns:
+//  -1 on fatal error
+//   0 on success
+
+int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  ULONG ulBuff;
+  UCHAR bBuff;
+  int iStatus=-1;  // assume failure
+
+  ENTER("InitializeTachLite");
+
+  // verify board's base address (sanity check)
+
+  if( !fcChip->Registers.ReMapMemBase)                // NULL address for card?
+    return -1;                         // FATAL error!
+
+
+
+  switch( opcode1 )
+  {
+    case 1:       // restore hardware to power-on (hard) restart
+
+
+      iStatus = fcChip->ResetTachyon( 
+		  cpqfcHBAdata, opcode2); // laser off, reset hardware
+				      // de-allocate aligned buffers
+
+
+/* TBD      // reset FC link Q (producer and consumer = 0)
+      fcLinkQReset(cpqfcHBAdata); 
+
+*/
+
+      if( iStatus )
+        break;
+
+    case 2:       // Config PCI/Tachyon registers
+      // NOTE: For Tach TL/TS, bit 31 must be set to 1.  For TS chips, a read
+      // of bit 31 indicates state of M66EN signal; if 1, chip may run at 
+      // 33-66MHz  (see TL/TS UG, pg 159)
+
+      ulBuff = 0x80000000;  // TachLite Configuration Register
+
+      writel( ulBuff, fcChip->Registers.TYconfig.address);
+//      ulBuff = 0x0147L;  // CpqTs PCI CFGCMD register
+//      WritePCIConfiguration( fcChip->Backplane.bus,
+//                           fcChip->Backplane.slot, TLCFGCMD, ulBuff, 4);
+//      ulBuff = 0x0L;  // test!
+//      ReadPCIConfiguration( fcChip->Backplane.bus,
+//                           fcChip->Backplane.slot, TLCFGCMD, &ulBuff, 4);
+
+      // read back for reference...
+      fcChip->Registers.TYconfig.value = 
+         readl( fcChip->Registers.TYconfig.address );
+
+      // what is the PCI bus width?
+      pci_read_config_byte( cpqfcHBAdata->PciDev,
+                                0x43, // PCIMCTR offset
+                                &bBuff);
+      
+      fcChip->Registers.PCIMCTR = bBuff;
+
+      // set string identifying the chip on the circuit board
+
+      fcChip->Registers.TYstatus.value =
+        readl( fcChip->Registers.TYstatus.address);
+      
+      {
+// Now that we are supporting multiple boards, we need to change
+// this logic to check for PCI vendor/device IDs...
+// for now, quick & dirty is simply checking Chip rev
+	
+	ULONG RevId = (fcChip->Registers.TYstatus.value &0x3E0)>>5;
+	UCHAR Minor = (UCHAR)(RevId & 0x3);
+	UCHAR Major = (UCHAR)((RevId & 0x1C) >>2);
+  
+	/* printk("  HBA Tachyon RevId %d.%d\n", Major, Minor); */
+  	if( (Major == 1) && (Minor == 2) )
+        {
+	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS12);
+
+	}
+	else if( (Major == 1) && (Minor == 3) )
+        {
+	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE66_TS13);
+	}
+	else if( (Major == 2) && (Minor == 1) )
+        {
+	  sprintf( cpqfcHBAdata->fcChip.Name, SAGILENT_XL2_21);
+	}
+	else
+	  sprintf( cpqfcHBAdata->fcChip.Name, STACHLITE_UNKNOWN);
+      }
+
+
+
+    case 3:       // allocate mem, set Tachyon Que registers
+      iStatus = CpqTsCreateTachLiteQues( cpqfcHBAdata, opcode2);
+
+      if( iStatus )
+        break;
+
+      // now that the Queues exist, Tach can DMA to them, so
+      // we can begin processing INTs
+      // INTEN register - enable INT (TachLite interrupt)
+      writeb( 0x1F, fcChip->Registers.ReMapMemBase + IINTEN);
+
+	// Fall through
+    case 4:       // Config Fame Manager, Init Loop Command, laser on
+
+                 // L_PORT or loopback
+                 // depending on Options
+      iStatus = CpqTsInitializeFrameManager( fcChip,0 );
+      if( iStatus )
+      {
+           // failed to initialize Frame Manager
+	      break;
+      }
+
+    default:
+      break;
+  }
+  LEAVE("InitializeTachLite");
+  
+  return iStatus;
+}
+
+
+
+
+// Depending on the type of platform memory allocation (e.g. dynamic),
+// it's probably best to free memory in opposite order as it was allocated.
+// Order of allocation: see other function
+
+
+int CpqTsDestroyTachLiteQues( void *pHBA, int opcode)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA*)pHBA;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  USHORT i, iStatus=0;
+  void* vPtr;  // mem Align manager sets this to the freed address on success
+  unsigned long ulPtr;  // for 64-bit pointer cast (e.g. Alpa machine)
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  PSGPAGES j, next;
+
+  ENTER("DestroyTachLiteQues");
+
+  if( fcChip->SEST )
+  {
+                // search out and free Pool for Extended S/G list pages
+
+    for( i=0; i < TACH_SEST_LEN; i++)  // for each exchange
+    {
+      // It's possible that extended S/G pages were allocated, mapped, and
+      // not cleared due to error conditions or O/S driver termination.
+      // Make sure they're all gone.
+      if (Exchanges->fcExchange[i].Cmnd != NULL) 
+      	cpqfc_pci_unmap(cpqfcHBAdata->PciDev, Exchanges->fcExchange[i].Cmnd, 
+			fcChip, i); // undo DMA mappings.
+
+      for (j=fcChip->SEST->sgPages[i] ; j != NULL ; j = next) {
+		next = j->next;
+		kfree(j);
+      }
+      fcChip->SEST->sgPages[i] = NULL;
+    }
+    ulPtr = (unsigned long)fcChip->SEST;
+    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
+		    &cpqfcHBAdata->dynamic_mem[0],
+		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
+    fcChip->SEST = 0L;  // null invalid ptr
+    if( !vPtr )
+    {
+      printk("SEST mem not freed\n");
+      iStatus = -1;
+    }
+  }
+
+  if( fcChip->SFQ )
+  {
+
+    ulPtr = (unsigned long)fcChip->SFQ;
+    vPtr = fcMemManager( cpqfcHBAdata->PciDev, 
+		    &cpqfcHBAdata->dynamic_mem[0],
+		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
+    fcChip->SFQ = 0L;  // null invalid ptr
+    if( !vPtr )
+    {
+      printk("SFQ mem not freed\n");
+      iStatus = -2;
+    }
+  }
+
+
+  if( fcChip->IMQ )
+  {
+      // clear Indexes to show empty Queue
+    fcChip->IMQ->producerIndex = 0;
+    fcChip->IMQ->consumerIndex = 0;
+
+    ulPtr = (unsigned long)fcChip->IMQ;
+    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
+		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
+    fcChip->IMQ = 0L;  // null invalid ptr
+    if( !vPtr )
+    {
+      printk("IMQ mem not freed\n");
+      iStatus = -3;
+    }
+  }
+
+  if( fcChip->ERQ )         // release memory blocks used by the queues
+  {
+    ulPtr = (unsigned long)fcChip->ERQ;
+    vPtr = fcMemManager( cpqfcHBAdata->PciDev, &cpqfcHBAdata->dynamic_mem[0],
+		    0,0, (ULONG)ulPtr, NULL ); // 'free' mem
+    fcChip->ERQ = 0L;  // null invalid ptr
+    if( !vPtr )
+    {
+      printk("ERQ mem not freed\n");
+      iStatus = -4;
+    }
+  }
+    
+  // free up the primary EXCHANGES struct and Link Q
+  cpqfc_free_dma_consistent(cpqfcHBAdata);
+  
+  LEAVE("DestroyTachLiteQues");
+  
+  return iStatus;     // non-zero (failed) if any memory not freed
+}
+
+
+
+
+
+// The SFQ is an array with SFQ_LEN length, each element (QEntry)
+// with eight 32-bit words.  TachLite places incoming FC frames (i.e.
+// a valid FC frame with our AL_PA ) in contiguous SFQ entries
+// and sends a completion message telling the host where the frame is
+// in the que.
+// This function copies the current (or oldest not-yet-processed) QEntry to
+// a caller's contiguous buffer and updates the Tachyon chip's consumer index
+//
+// NOTE:
+//   An FC frame may consume one or many SFQ entries.  We know the total
+//   length from the completion message.  The caller passes a buffer large
+//   enough for the complete message (max 2k).
+
+static void CpqTsGetSFQEntry(
+         PTACHYON fcChip,
+         USHORT producerNdx,
+         ULONG *ulDestPtr,            // contiguous destination buffer
+	 BOOLEAN UpdateChip)
+{
+  ULONG total_bytes=0;
+  ULONG consumerIndex = fcChip->SFQ->consumerIndex;
+  
+				// check passed copy of SFQ producer index -
+				// is a new message waiting for us?
+				// equal indexes means SFS is copied
+
+  while( producerNdx != consumerIndex )
+  {                             // need to process message
+    total_bytes += 64;   // maintain count to prevent writing past buffer
+                   // don't allow copies over Fibre Channel defined length!
+    if( total_bytes <= 2048 )
+    {
+      memcpy( ulDestPtr, 
+              &fcChip->SFQ->QEntry[consumerIndex],
+              64 );  // each SFQ entry is 64 bytes
+      ulDestPtr += 16;   // advance pointer to next 64 byte block
+    }
+		         // Tachyon is producing,
+                         // and we are consuming
+
+    if( ++consumerIndex >= SFQ_LEN)// check for rollover
+      consumerIndex = 0L;        // reset it
+  }
+
+  // if specified, update the Tachlite chip ConsumerIndex...
+  if( UpdateChip )
+  {
+    fcChip->SFQ->consumerIndex = consumerIndex;
+    writel( fcChip->SFQ->consumerIndex,
+      fcChip->Registers.SFQconsumerIndex.address);
+  }
+}
+
+
+
+// TachLite routinely freezes it's core ques - Outbound FIFO, Inbound FIFO,
+// and Exchange Request Queue (ERQ) on error recover - 
+// (e.g. whenever a LIP occurs).  Here
+// we routinely RESUME by clearing these bits, but only if the loop is up
+// to avoid ERROR IDLE messages forever.
+
+void CpqTsUnFreezeTachlite( void *pChip, int type )
+{
+  PTACHYON fcChip = (PTACHYON)pChip;
+  fcChip->Registers.TYcontrol.value = 
+    readl(fcChip->Registers.TYcontrol.address);
+            
+  // (bit 4 of value is GBIC LASER)
+  // if we 'unfreeze' the core machines before the loop is healthy
+  // (i.e. FLT, OS, LS failure bits set in FMstatus)
+  // we can get 'error idle' messages forever.  Verify that
+  // FMstatus (Link Status) is OK before unfreezing.
+
+  if( !(fcChip->Registers.FMstatus.value & 0x07000000L) && // bits clear?
+      !(fcChip->Registers.FMstatus.value & 0x80  ))  // Active LPSM?
+  {
+    fcChip->Registers.TYcontrol.value &=  ~0x300L; // clear FEQ, FFA
+    if( type == 1 )  // unfreeze ERQ only
+    {
+//      printk("Unfreezing ERQ\n");
+      fcChip->Registers.TYcontrol.value |= 0x10000L; // set REQ
+    }
+    else             // unfreeze both ERQ and FCP-ASSIST (SEST)
+    {
+//      printk("Unfreezing ERQ & FCP-ASSIST\n");
+
+                     // set ROF, RIF, REQ - resume Outbound FCP, Inbnd FCP, ERQ
+      fcChip->Registers.TYcontrol.value |= 0x70000L; // set ROF, RIF, REQ
+    }
+
+    writel( fcChip->Registers.TYcontrol.value,
+      fcChip->Registers.TYcontrol.address);
+              
+  }
+          // readback for verify (TachLite still frozen?)
+  fcChip->Registers.TYstatus.value = 
+    readl(fcChip->Registers.TYstatus.address);
+}
+
+
+// Whenever an FC Exchange Abort is required, we must manipulate the
+// Host/Tachyon shared memory SEST table.  Before doing this, we
+// must freeze Tachyon, which flushes certain buffers and ensure we
+// can manipulate the SEST without contention.
+// This freeze function will result in FCP & ERQ FROZEN completion
+// messages (per argument "type").
+
+void CpqTsFreezeTachlite( void *pChip, int type )
+{
+  PTACHYON fcChip = (PTACHYON)pChip;
+  fcChip->Registers.TYcontrol.value = 
+    readl(fcChip->Registers.TYcontrol.address);
+    
+                     //set FFA, FEQ - freezes SCSI assist and ERQ
+  if( type == 1)    // freeze ERQ only
+    fcChip->Registers.TYcontrol.value |= 0x100L; // (bit 4 is laser)
+  else              // freeze both FCP assists (SEST) and ERQ
+    fcChip->Registers.TYcontrol.value |= 0x300L; // (bit 4 is laser)
+  
+  writel( fcChip->Registers.TYcontrol.value,
+    fcChip->Registers.TYcontrol.address);
+              
+}
+
+
+
+
+// TL has two Frame Manager Link Status Registers, with three 8-bit
+// fields each. These eight bit counters are cleared after each read,
+// so we define six 32-bit accumulators for these TL counters. This
+// function breaks out each 8-bit field and adds the value to the existing
+// sum.  (s/w counters cleared independently)
+
+void fcParseLinkStatusCounters(PTACHYON fcChip)
+{
+  UCHAR bBuff;
+  ULONG ulBuff;
+
+
+// The BB0 timer usually increments when TL is initialized, resulting
+// in an initially bogus count.  If our own counter is ZERO, it means we
+// are reading this thing for the first time, so we ignore the first count.
+// Also, reading the register does not clear it, so we have to keep an
+// additional static counter to detect rollover (yuk).
+
+  if( fcChip->fcStats.lastBB0timer == 0L)  // TL was reset? (ignore 1st values)
+  {
+                           // get TL's register counter - the "last" count
+    fcChip->fcStats.lastBB0timer = 
+      fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+  }
+  else  // subsequent pass - check for rollover
+  {
+                              // "this" count
+    ulBuff = fcChip->Registers.FMBB_CreditZero.value & 0x00ffffffL;
+    if( fcChip->fcStats.lastBB0timer > ulBuff ) // rollover happened
+    {
+                                // counter advanced to max...
+      fcChip->fcStats.BB0_Timer += (0x00FFFFFFL - fcChip->fcStats.lastBB0timer);
+      fcChip->fcStats.BB0_Timer += ulBuff;  // plus some more
+
+
+    }
+    else // no rollover -- more counts or no change
+    {
+      fcChip->fcStats.BB0_Timer +=  (ulBuff - fcChip->fcStats.lastBB0timer);
+
+    }
+
+    fcChip->fcStats.lastBB0timer = ulBuff;
+  }
+
+
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 24);
+  fcChip->fcStats.LossofSignal += bBuff;
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 16);
+  fcChip->fcStats.BadRXChar += bBuff;
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus1.value >> 8);
+  fcChip->fcStats.LossofSync += bBuff;
+
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 24);
+  fcChip->fcStats.Rx_EOFa += bBuff;
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 16);
+  fcChip->fcStats.Dis_Frm += bBuff;
+
+  bBuff = (UCHAR)(fcChip->Registers.FMLinkStatus2.value >> 8);
+  fcChip->fcStats.Bad_CRC += bBuff;
+}
+
+
+void cpqfcTSClearLinkStatusCounters(PTACHYON fcChip)
+{
+  ENTER("ClearLinkStatusCounters");
+  memset( &fcChip->fcStats, 0, sizeof( FCSTATS));
+  LEAVE("ClearLinkStatusCounters");
+
+}
+
+
+
+
+// The following function reads the I2C hardware to get the adapter's
+// World Wide Name (WWN).
+// If the WWN is "500805f1fadb43e8" (as printed on the card), the
+// Tachyon WWN_hi (32-bit) register is 500805f1, and WWN_lo register
+// is fadb43e8.
+// In the NVRAM, the bytes appear as:
+// [2d] ..
+// [2e] .. 
+// [2f] 50
+// [30] 08
+// [31] 05
+// [32] f1
+// [33] fa
+// [34] db
+// [35] 43
+// [36] e8
+//
+// In the Fibre Channel (Big Endian) format, the FC-AL LISM frame will
+// be correctly loaded by Tachyon silicon.  In the login payload, bytes
+// must be correctly swapped for Big Endian format.
+
+int CpqTsReadWriteWWN( PVOID pChip, int Read)
+{
+  PTACHYON fcChip = (PTACHYON)pChip;
+#define NVRAM_SIZE 512
+  unsigned short i, count = NVRAM_SIZE;
+  UCHAR nvRam[NVRAM_SIZE], WWNbuf[8];
+  ULONG ulBuff;
+  int iStatus=-1;  // assume failure
+  int WWNoffset;
+
+  ENTER("ReadWriteWWN");
+  // Now try to read the WWN from the adapter's NVRAM
+
+  if( Read )  // READing NVRAM WWN?
+  {
+    ulBuff = cpqfcTS_ReadNVRAM( fcChip->Registers.TYstatus.address,
+                              fcChip->Registers.TYcontrol.address,
+                              count, &nvRam[0] );
+
+    if( ulBuff )   // NVRAM read successful?
+    {
+      iStatus = 0; // success!
+      
+                   // for engineering/ prototype boards, the data may be
+                   // invalid (GIGO, usually all "FF"); this prevents the
+                   // parse routine from working correctly, which means
+                   // nothing will be written to our passed buffer.
+
+      WWNoffset = cpqfcTS_GetNVRAM_data( WWNbuf, nvRam );
+
+      if( !WWNoffset ) // uninitialized NVRAM -- copy bytes directly
+      {
+        printk( "CAUTION: Copying NVRAM data on fcChip\n");
+        for( i= 0; i < 8; i++)
+          WWNbuf[i] = nvRam[i +0x2f]; // dangerous! some formats won't work
+      }
+      
+      fcChip->Registers.wwn_hi = 0L;
+      fcChip->Registers.wwn_lo = 0L;
+      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
+      {
+        ulBuff = 0L;
+        ulBuff = (ULONG)(WWNbuf[i]) << (8 * (3-i));
+        fcChip->Registers.wwn_hi |= ulBuff;
+      }
+      for( i=0; i<4; i++)  // WWN bytes are big endian in NVRAM
+      {
+        ulBuff = 0L;
+        ulBuff = (ULONG)(WWNbuf[i+4]) << (8 * (3-i));
+        fcChip->Registers.wwn_lo |= ulBuff;
+      }
+    }  // done reading
+    else
+    {
+
+      printk( "cpqfcTS: NVRAM read failed\n");
+
+    }
+  }
+
+  else  // WRITE
+  {
+
+    // NOTE: WRITE not supported & not used in released driver.
+
+   
+    printk("ReadWriteNRAM: can't write NVRAM; aborting write\n");
+  }
+  
+  LEAVE("ReadWriteWWN");
+  return iStatus;
+}
+
+
+
+
+
+// The following function reads or writes the entire "NVRAM" contents of 
+// the I2C hardware (i.e. the NM24C03).  Note that HP's 5121A (TS 66Mhz)
+// adapter does not use the NM24C03 chip, so this function only works on
+// Compaq's adapters.
+
+int CpqTsReadWriteNVRAM( PVOID pChip, PVOID buf, int Read)
+{
+  PTACHYON fcChip = (PTACHYON)pChip;
+#define NVRAM_SIZE 512
+  ULONG ulBuff;
+  UCHAR *ucPtr = buf; // cast caller's void ptr to UCHAR array
+  int iStatus=-1;  // assume failure
+
+     
+  if( Read )  // READing NVRAM?
+  {
+    ulBuff = cpqfcTS_ReadNVRAM(   // TRUE on success
+                fcChip->Registers.TYstatus.address,
+                fcChip->Registers.TYcontrol.address,
+                256,            // bytes to write
+                ucPtr );        // source ptr
+
+
+    if( ulBuff )
+      iStatus = 0; // success
+    else
+    {
+#ifdef DBG
+      printk( "CAUTION: NVRAM read failed\n");
+#endif
+    }
+  }  // done reading
+
+  else  // WRITING NVRAM 
+  {
+
+    printk("cpqfcTS: WRITE of FC Controller's NVRAM disabled\n");
+  }
+    
+  return iStatus;
+}
diff --git a/drivers/scsi/cpqfcTSi2c.c b/drivers/scsi/cpqfcTSi2c.c
new file mode 100644
index 0000000..b38a6a9
--- /dev/null
+++ b/drivers/scsi/cpqfcTSi2c.c
@@ -0,0 +1,493 @@
+/* Copyright(c) 2000, Compaq Computer Corporation 
+ * Fibre Channel Host Bus Adapter 
+ * 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+*/
+// These functions control the NVRAM I2C hardware on 
+// non-intelligent Fibre Host Adapters.
+// The primary purpose is to read the HBA's NVRAM to get adapter's 
+// manufactured WWN to copy into Tachyon chip registers
+// Orignal source author unknown
+
+#include <linux/types.h>
+enum boolean { FALSE, TRUE } ;
+
+
+#ifndef UCHAR
+typedef __u8 UCHAR;
+#endif
+#ifndef BOOLEAN
+typedef __u8 BOOLEAN;
+#endif
+#ifndef USHORT
+typedef __u16 USHORT;
+#endif
+#ifndef ULONG
+typedef __u32 ULONG;
+#endif
+
+
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/io.h>  // struct pt_regs for IRQ handler & Port I/O
+
+#include "cpqfcTSchip.h"
+
+static void tl_i2c_tx_byte( void* GPIOout, UCHAR data );
+/*static BOOLEAN tl_write_i2c_page_portion( void* GPIOin, void* GPIOout,
+  USHORT startOffset,  // e.g. 0x2f for WWN start
+  USHORT count,
+  UCHAR *buf );
+*/
+
+//
+// Tachlite GPIO2, GPIO3 (I2C) DEFINES
+// The NVRAM chip NM24C03 defines SCL (serial clock) and SDA (serial data)
+// GPIO2 drives SDA, and GPIO3 drives SCL
+// 
+// Since Tachlite inverts the state of the GPIO 0-3 outputs, SET writes 0
+// and clear writes 1. The input lines (read in TL status) is NOT inverted
+// This really helps confuse the code and debugging.
+
+#define SET_DATA_HI  0x0
+#define SET_DATA_LO  0x8
+#define SET_CLOCK_HI 0x0
+#define SET_CLOCK_LO 0x4
+
+#define SENSE_DATA_HI  0x8
+#define SENSE_DATA_LO  0x0
+#define SENSE_CLOCK_HI 0x4
+#define SENSE_CLOCK_LO 0x0
+
+#define SLAVE_READ_ADDRESS    0xA1
+#define SLAVE_WRITE_ADDRESS   0xA0
+					      
+
+static void i2c_delay(ULONG mstime);
+static void tl_i2c_clock_pulse( UCHAR , void* GPIOout);
+static UCHAR tl_read_i2c_data( void* );
+
+
+//-----------------------------------------------------------------------------
+//
+//      Name:   I2C_RX_ACK
+//
+//      This routine receives an acknowledge over the I2C bus.
+//
+//-----------------------------------------------------------------------------
+static unsigned short tl_i2c_rx_ack( void* GPIOin, void* GPIOout )
+{
+  unsigned long value;
+
+	// do clock pulse, let data line float high
+  tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+
+	// slave must drive data low for acknowledge
+  value = tl_read_i2c_data( GPIOin);
+  if (value & SENSE_DATA_HI )
+    return( FALSE );
+
+  return( TRUE );
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   READ_I2C_REG
+//
+//      This routine reads the I2C control register using the global
+//      IO address stored in gpioreg.
+//
+//-----------------------------------------------------------------------------
+static UCHAR tl_read_i2c_data( void* gpioreg )
+{
+  return( (UCHAR)(readl( gpioreg ) & 0x08L) ); // GPIO3
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   WRITE_I2C_REG
+//
+//      This routine writes the I2C control register using the global
+//      IO address stored in gpioreg.
+//      In Tachlite, we don't want to modify other bits in TL Control reg.
+//
+//-----------------------------------------------------------------------------
+static void tl_write_i2c_reg( void* gpioregOUT, UCHAR value )
+{
+  ULONG  temp;
+
+	// First read the register and clear out the old bits
+  temp = readl( gpioregOUT ) & 0xfffffff3L;
+
+	// Now or in the new data and send it back out
+  writel( temp | value, gpioregOUT);
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   I2C_TX_START
+//
+//      This routine transmits a start condition over the I2C bus.
+//      1. Set SCL (clock, GPIO2) HIGH, set SDA (data, GPIO3) HIGH,
+//      wait 5us to stabilize.
+//      2. With SCL still HIGH, drive SDA low.  The low transition marks
+//         the start condition to NM24Cxx (the chip)
+//      NOTE! In TL control reg., output 1 means chip sees LOW
+//
+//-----------------------------------------------------------------------------
+static unsigned short tl_i2c_tx_start( void* GPIOin, void* GPIOout )
+{
+  unsigned short i;
+  ULONG value;
+
+  if ( !(tl_read_i2c_data(GPIOin) & SENSE_DATA_HI))
+  {
+    // start with clock high, let data float high
+    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
+
+    // keep sending clock pulses if slave is driving data line
+    for (i = 0; i < 10; i++)
+    {
+      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+
+      if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
+	break;
+    }
+
+		// if he's still driving data low after 10 clocks, abort
+    value = tl_read_i2c_data( GPIOin ); // read status
+    if (!(value & 0x08) )
+      return( FALSE );
+  }
+
+
+	// To START, bring data low while clock high
+  tl_write_i2c_reg(  GPIOout, SET_CLOCK_HI | SET_DATA_LO );
+
+  i2c_delay(0);
+
+  return( TRUE );                           // TX start successful
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   I2C_TX_STOP
+//
+//      This routine transmits a stop condition over the I2C bus.
+//
+//-----------------------------------------------------------------------------
+
+static unsigned short tl_i2c_tx_stop( void* GPIOin, void* GPIOout )
+{
+  int i;
+
+  for (i = 0; i < 10; i++) 
+  {
+  // Send clock pulse, drive data line low
+    tl_i2c_clock_pulse( SET_DATA_LO, GPIOout );
+
+  // To STOP, bring data high while clock high
+    tl_write_i2c_reg(  GPIOout, SET_DATA_HI | SET_CLOCK_HI );
+
+  // Give the data line time to float high
+    i2c_delay(0);
+
+  // If slave is driving data line low, there's a problem; retry
+    if ( tl_read_i2c_data(GPIOin) & SENSE_DATA_HI )
+      return( TRUE );  // TX STOP successful!
+  }
+
+  return( FALSE );                      // error
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   I2C_TX_uchar
+//
+//      This routine transmits a byte across the I2C bus.
+//
+//-----------------------------------------------------------------------------
+static void tl_i2c_tx_byte( void* GPIOout, UCHAR data )
+{
+  UCHAR bit;
+
+  for (bit = 0x80; bit; bit >>= 1)
+  {
+    if( data & bit )
+      tl_i2c_clock_pulse( (UCHAR)SET_DATA_HI, GPIOout);
+    else
+      tl_i2c_clock_pulse( (UCHAR)SET_DATA_LO, GPIOout);
+  }  
+}
+//-----------------------------------------------------------------------------
+//
+//      Name:   I2C_RX_uchar
+//
+//      This routine receives a byte across the I2C bus.
+//
+//-----------------------------------------------------------------------------
+static UCHAR tl_i2c_rx_byte( void* GPIOin, void* GPIOout )
+{
+  UCHAR bit;
+  UCHAR data = 0;
+
+
+  for (bit = 0x80; bit; bit >>= 1) {
+    // do clock pulse, let data line float high
+    tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+
+    // read data line
+    if ( tl_read_i2c_data( GPIOin) & 0x08 )
+      data |= bit;
+  }
+
+  return (data);
+}
+//*****************************************************************************
+//*****************************************************************************
+// Function:   read_i2c_nvram
+// Arguments:  UCHAR count     number of bytes to read
+//             UCHAR *buf      area to store the bytes read
+// Returns:    0 - failed
+//             1 - success
+//*****************************************************************************
+//*****************************************************************************
+unsigned long cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
+	UCHAR *buf )
+{
+  unsigned short i;
+
+  if( !( tl_i2c_tx_start(GPIOin, GPIOout) ))
+    return FALSE;
+
+  // Select the NVRAM for "dummy" write, to set the address
+  tl_i2c_tx_byte( GPIOout , SLAVE_WRITE_ADDRESS );
+  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
+    return( FALSE );
+
+  // Now send the address where we want to start reading  
+  tl_i2c_tx_byte( GPIOout , 0 );
+  if ( !tl_i2c_rx_ack(GPIOin, GPIOout ) )
+    return( FALSE );
+
+  // Send a repeated start condition and select the
+  //  slave for reading now.
+  if( tl_i2c_tx_start(GPIOin, GPIOout) )
+    tl_i2c_tx_byte( GPIOout, SLAVE_READ_ADDRESS );
+
+  if ( !tl_i2c_rx_ack(GPIOin, GPIOout) )
+    return( FALSE );
+
+  // this loop will now read out the data and store it
+  //  in the buffer pointed to by buf
+  for ( i=0; i<count; i++) 
+  {
+    *buf++ = tl_i2c_rx_byte(GPIOin, GPIOout);
+
+    // Send ACK by holding data line low for 1 clock
+    if ( i < (count-1) )
+      tl_i2c_clock_pulse( 0x08, GPIOout );
+    else {
+	// Don't send ack for final byte
+      tl_i2c_clock_pulse( SET_DATA_HI, GPIOout );
+    }
+  }
+
+  tl_i2c_tx_stop(GPIOin, GPIOout);
+
+  return( TRUE );
+}
+
+//****************************************************************
+//
+//
+//
+// routines to set and clear the data and clock bits
+//
+//
+//
+//****************************************************************
+
+static void tl_set_clock(void* gpioreg)
+{
+  ULONG ret_val;
+
+  ret_val = readl( gpioreg );
+  ret_val &= 0xffffffFBL;  // clear GPIO2 (SCL)
+  writel( ret_val, gpioreg);
+}
+
+static void tl_clr_clock(void* gpioreg)
+{
+  ULONG ret_val;
+
+  ret_val = readl( gpioreg );
+  ret_val |= SET_CLOCK_LO;
+  writel( ret_val, gpioreg);
+}
+
+//*****************************************************************
+//
+//
+// This routine will advance the clock by one period
+//
+//
+//*****************************************************************
+static void tl_i2c_clock_pulse( UCHAR value, void* GPIOout  )
+{
+  ULONG ret_val;
+
+  // clear the clock bit
+  tl_clr_clock( GPIOout );
+
+  i2c_delay(0);
+
+
+  // read the port to preserve non-I2C bits
+  ret_val = readl( GPIOout );
+
+  // clear the data & clock bits
+  ret_val &= 0xFFFFFFf3;
+
+  // write the value passed in...
+  // data can only change while clock is LOW!
+  ret_val |= value;           // the data
+  ret_val |= SET_CLOCK_LO;    // the clock
+  writel( ret_val, GPIOout );
+
+  i2c_delay(0);
+
+
+  //set clock bit
+  tl_set_clock( GPIOout);
+}
+
+
+
+
+//*****************************************************************
+//
+//
+// This routine returns the 64-bit WWN
+//
+//
+//*****************************************************************
+int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf )
+{
+  ULONG len;
+  ULONG sub_len;
+  ULONG ptr_inc;
+  ULONG i;
+  ULONG j;
+  UCHAR *data_ptr;
+  UCHAR  z;
+  UCHAR  name;
+  UCHAR  sub_name;
+  UCHAR  done;
+  int iReturn=0;  // def. 0 offset is failure to find WWN field
+  
+
+	  
+  data_ptr = (UCHAR *)buf;
+
+  done = FALSE;
+  i = 0;
+
+  while ( (i < 128) && (!done) ) 
+  {
+    z = data_ptr[i];\
+    if ( !(z & 0x80) )  
+    {	
+      len  = 1 + (z & 0x07);
+
+      name = (z & 0x78) >> 3;
+      if (name == 0x0F)
+        done = TRUE;
+    }
+    else 
+    {
+      name = z & 0x7F;
+      len  = 3 + data_ptr[i+1] + (data_ptr[i+2] << 8);
+           
+      switch (name) 
+      {
+      case 0x0D:
+	//
+	  j = i + 3;
+	  //
+	  if ( data_ptr[j] == 0x3b ) {
+	    len = 6;
+	    break;
+	  }
+
+	  while ( j<(i+len) ) {
+	    sub_name = (data_ptr[j] & 0x3f);
+	    sub_len  = data_ptr[j+1] + 
+	               (data_ptr[j+2] << 8);
+            ptr_inc  = sub_len + 3; 
+	    switch (sub_name) 
+	    {
+	    case 0x3C:
+              memcpy( wwnbuf, &data_ptr[j+3], 8);
+              iReturn = j+3;
+              break;
+            default:
+              break;
+	    }
+	    j += ptr_inc;
+          }
+	  break;
+        default:
+	  break;
+      }  
+    }  
+  //
+    i += len;
+  }  // end while 
+  return iReturn;
+}
+
+
+
+
+
+// define a short 5 micro sec delay, and longer (ms) delay
+
+static void i2c_delay(ULONG mstime)
+{
+  ULONG i;
+  
+// NOTE: we only expect to use these delays when reading
+// our adapter's NVRAM, which happens only during adapter reset.
+// Delay technique from "Linux Device Drivers", A. Rubini 
+// (1st Ed.) pg 137.
+
+//  printk(" delay %lx  ", mstime);
+  if( mstime ) // ms delay?
+  {
+    // delay technique
+    for( i=0; i < mstime; i++)
+      udelay(1000); // 1ms per loop
+	
+  }
+  else  // 5 micro sec delay
+  
+    udelay( 5 ); // micro secs
+  
+//  printk("done\n");
+}
+
+
+
diff --git a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
new file mode 100644
index 0000000..2eeb493
--- /dev/null
+++ b/drivers/scsi/cpqfcTSinit.c
@@ -0,0 +1,2098 @@
+/* Copyright(c) 2000, Compaq Computer Corporation 
+ * Fibre Channel Host Bus Adapter 
+ * 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+ * IOCTL and procfs added by Jouke Numan
+ * SMP testing by Chel Van Gennip
+ *
+ * portions copied from:
+ * QLogic CPQFCTS SCSI-FCP
+ * Written by Erik H. Moe, ehm@cris.com
+ * Copyright 1995, Erik H. Moe
+ * Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> 
+ * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
+*/
+
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+
+#include <linux/config.h>  
+#include <linux/interrupt.h>  
+#include <linux/module.h>
+#include <linux/version.h> 
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/init.h>
+#include <linux/ioport.h>  // request_region() prototype
+#include <linux/completion.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>   // ioctl related
+#include <asm/irq.h>
+#include <linux/spinlock.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include "cpqfcTSchip.h"
+#include "cpqfcTSstructs.h"
+#include "cpqfcTStrigger.h"
+
+#include "cpqfcTS.h"
+
+/* Embedded module documentation macros - see module.h */
+MODULE_AUTHOR("Compaq Computer Corporation");
+MODULE_DESCRIPTION("Driver for Compaq 64-bit/66Mhz PCI Fibre Channel HBA v. 2.5.4");
+MODULE_LICENSE("GPL");
+  
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags);
+
+// This struct was originally defined in 
+// /usr/src/linux/include/linux/proc_fs.h
+// since it's only partially implemented, we only use first
+// few fields...
+// NOTE: proc_fs changes in 2.4 kernel
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+static struct proc_dir_entry proc_scsi_cpqfcTS =
+{
+  PROC_SCSI_CPQFCTS,           // ushort low_ino (enumerated list)
+  7,                           // ushort namelen
+  DEV_NAME,                    // const char* name
+  S_IFDIR | S_IRUGO | S_IXUGO, // mode_t mode
+  2                            // nlink_t nlink
+	                       // etc. ...
+};
+
+
+#endif
+
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,7)
+#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_COMPLETION(x)
+#  define CPQFC_WAITING waiting
+#  define CPQFC_COMPLETE(x) complete(x)
+#  define CPQFC_WAIT_FOR_COMPLETION(x) wait_for_completion(x);
+#else
+#  define CPQFC_DECLARE_COMPLETION(x) DECLARE_MUTEX_LOCKED(x)
+#  define CPQFC_WAITING sem
+#  define CPQFC_COMPLETE(x) up(x)
+#  define CPQFC_WAIT_FOR_COMPLETION(x) down(x)
+#endif
+
+static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba);
+
+/* local function to load our per-HBA (local) data for chip
+   registers, FC link state, all FC exchanges, etc.
+
+   We allocate space and compute address offsets for the
+   most frequently accessed addresses; others (like World Wide
+   Name) are not necessary.
+*/
+static void Cpqfc_initHBAdata(CPQFCHBA *cpqfcHBAdata, struct pci_dev *PciDev )
+{
+             
+  cpqfcHBAdata->PciDev = PciDev; // copy PCI info ptr
+
+  // since x86 port space is 64k, we only need the lower 16 bits
+  cpqfcHBAdata->fcChip.Registers.IOBaseL = 
+    PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+  
+  cpqfcHBAdata->fcChip.Registers.IOBaseU = 
+    PciDev->resource[2].start & PCI_BASE_ADDRESS_IO_MASK;
+  
+  // 32-bit memory addresses
+  cpqfcHBAdata->fcChip.Registers.MemBase = 
+    PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK;
+
+  cpqfcHBAdata->fcChip.Registers.ReMapMemBase = 
+    ioremap( PciDev->resource[3].start & PCI_BASE_ADDRESS_MEM_MASK,
+             0x200);
+  
+  cpqfcHBAdata->fcChip.Registers.RAMBase = 
+    PciDev->resource[4].start;
+  
+  cpqfcHBAdata->fcChip.Registers.SROMBase =  // NULL for HP TS adapter
+    PciDev->resource[5].start;
+  
+  // now the Tachlite chip registers
+  // the REGISTER struct holds both the physical address & last
+  // written value (some TL registers are WRITE ONLY)
+
+  cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_SFQ_CONSUMER_INDEX;
+
+  cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_ERQ_PRODUCER_INDEX;
+      
+  // TL Frame Manager
+  cpqfcHBAdata->fcChip.Registers.FMconfig.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONFIG;
+  cpqfcHBAdata->fcChip.Registers.FMcontrol.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_CONTROL;
+  cpqfcHBAdata->fcChip.Registers.FMstatus.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_STATUS;
+  cpqfcHBAdata->fcChip.Registers.FMLinkStatus1.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT1;
+  cpqfcHBAdata->fcChip.Registers.FMLinkStatus2.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_LINK_STAT2;
+  cpqfcHBAdata->fcChip.Registers.FMBB_CreditZero.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_BB_CREDIT0;
+      
+      // TL Control Regs
+  cpqfcHBAdata->fcChip.Registers.TYconfig.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONFIG;
+  cpqfcHBAdata->fcChip.Registers.TYcontrol.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_CONTROL;
+  cpqfcHBAdata->fcChip.Registers.TYstatus.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_TACH_STATUS;
+  cpqfcHBAdata->fcChip.Registers.rcv_al_pa.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_RCV_AL_PA;
+  cpqfcHBAdata->fcChip.Registers.ed_tov.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + TL_MEM_FM_ED_TOV;
+
+
+  cpqfcHBAdata->fcChip.Registers.INTEN.address = 
+	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTEN;
+  cpqfcHBAdata->fcChip.Registers.INTPEND.address = 
+	        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTPEND;
+  cpqfcHBAdata->fcChip.Registers.INTSTAT.address = 
+        cpqfcHBAdata->fcChip.Registers.ReMapMemBase + IINTSTAT;
+
+  DEBUG_PCI(printk("  cpqfcHBAdata->fcChip.Registers. :\n"));
+  DEBUG_PCI(printk("    IOBaseL = %x\n", 
+    cpqfcHBAdata->fcChip.Registers.IOBaseL));
+  DEBUG_PCI(printk("    IOBaseU = %x\n", 
+    cpqfcHBAdata->fcChip.Registers.IOBaseU));
+  
+  /* printk(" ioremap'd Membase: %p\n", cpqfcHBAdata->fcChip.Registers.ReMapMemBase); */
+  
+  DEBUG_PCI(printk("    SFQconsumerIndex.address = %p\n", 
+    cpqfcHBAdata->fcChip.Registers.SFQconsumerIndex.address));
+  DEBUG_PCI(printk("    ERQproducerIndex.address = %p\n", 
+    cpqfcHBAdata->fcChip.Registers.ERQproducerIndex.address));
+  DEBUG_PCI(printk("    TYconfig.address = %p\n", 
+    cpqfcHBAdata->fcChip.Registers.TYconfig.address));
+  DEBUG_PCI(printk("    FMconfig.address = %p\n", 
+    cpqfcHBAdata->fcChip.Registers.FMconfig.address));
+  DEBUG_PCI(printk("    FMcontrol.address = %p\n", 
+    cpqfcHBAdata->fcChip.Registers.FMcontrol.address));
+
+  // set default options for FC controller (chip)
+  cpqfcHBAdata->fcChip.Options.initiator = 1;  // default: SCSI initiator
+  cpqfcHBAdata->fcChip.Options.target = 0;     // default: SCSI target
+  cpqfcHBAdata->fcChip.Options.extLoopback = 0;// default: no loopback @GBIC
+  cpqfcHBAdata->fcChip.Options.intLoopback = 0;// default: no loopback inside chip
+
+  // set highest and lowest FC-PH version the adapter/driver supports
+  // (NOT strict compliance)
+  cpqfcHBAdata->fcChip.highest_FCPH_ver = FC_PH3;
+  cpqfcHBAdata->fcChip.lowest_FCPH_ver = FC_PH43;
+
+  // set function points for this controller / adapter
+  cpqfcHBAdata->fcChip.ResetTachyon = CpqTsResetTachLite;
+  cpqfcHBAdata->fcChip.FreezeTachyon = CpqTsFreezeTachlite;
+  cpqfcHBAdata->fcChip.UnFreezeTachyon = CpqTsUnFreezeTachlite;
+  cpqfcHBAdata->fcChip.CreateTachyonQues = CpqTsCreateTachLiteQues;
+  cpqfcHBAdata->fcChip.DestroyTachyonQues = CpqTsDestroyTachLiteQues;
+  cpqfcHBAdata->fcChip.InitializeTachyon = CpqTsInitializeTachLite;  
+  cpqfcHBAdata->fcChip.LaserControl = CpqTsLaserControl;  
+  cpqfcHBAdata->fcChip.ProcessIMQEntry = CpqTsProcessIMQEntry;
+  cpqfcHBAdata->fcChip.InitializeFrameManager = CpqTsInitializeFrameManager;
+  cpqfcHBAdata->fcChip.ReadWriteWWN = CpqTsReadWriteWWN;
+  cpqfcHBAdata->fcChip.ReadWriteNVRAM = CpqTsReadWriteNVRAM;
+
+      if (cpqfc_alloc_private_data_pool(cpqfcHBAdata) != 0) {
+		printk(KERN_WARNING 
+			"cpqfc: unable to allocate pool for passthru ioctls.  "
+			"Passthru ioctls disabled.\n");
+      }
+}
+
+
+/* (borrowed from linux/drivers/scsi/hosts.c) */
+static void launch_FCworker_thread(struct Scsi_Host *HostAdapter)
+{
+  DECLARE_MUTEX_LOCKED(sem);
+
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+
+  ENTER("launch_FC_worker_thread");
+             
+  cpqfcHBAdata->notify_wt = &sem;
+
+  /* must unlock before kernel_thread(), for it may cause a reschedule. */
+  spin_unlock_irq(HostAdapter->host_lock);
+  kernel_thread((int (*)(void *))cpqfcTSWorkerThread, 
+                          (void *) HostAdapter, 0);
+  /*
+   * Now wait for the kernel error thread to initialize itself
+
+   */
+  down (&sem);
+  spin_lock_irq(HostAdapter->host_lock);
+  cpqfcHBAdata->notify_wt = NULL;
+
+  LEAVE("launch_FC_worker_thread");
+ 
+}
+
+
+/* "Entry" point to discover if any supported PCI 
+   bus adapter can be found
+*/
+/* We're supporting:
+ * Compaq 64-bit, 66MHz HBA with Tachyon TS
+ * Agilent XL2 
+ * HP Tachyon
+ */
+#define HBA_TYPES 3
+
+#ifndef PCI_DEVICE_ID_COMPAQ_
+#define PCI_DEVICE_ID_COMPAQ_TACHYON	0xa0fc
+#endif
+
+static struct SupportedPCIcards cpqfc_boards[] __initdata = {
+	{PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TACHYON},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHLITE},
+	{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_TACHYON},
+};
+
+
+int cpqfcTS_detect(Scsi_Host_Template *ScsiHostTemplate)
+{
+  int NumberOfAdapters=0; // how many of our PCI adapters are found?
+  struct pci_dev *PciDev = NULL;
+  struct Scsi_Host *HostAdapter = NULL;
+  CPQFCHBA *cpqfcHBAdata = NULL; 
+  struct timer_list *cpqfcTStimer = NULL;
+  int i;
+
+  ENTER("cpqfcTS_detect");
+
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+  ScsiHostTemplate->proc_dir = &proc_scsi_cpqfcTS;
+#else
+  ScsiHostTemplate->proc_name = "cpqfcTS";
+#endif
+
+  for( i=0; i < HBA_TYPES; i++)
+  {
+    // look for all HBAs of each type
+
+    while((PciDev = pci_find_device(cpqfc_boards[i].vendor_id,
+				    cpqfc_boards[i].device_id, PciDev)))
+    {
+
+      if (pci_enable_device(PciDev)) {
+	printk(KERN_ERR
+		"cpqfc: can't enable PCI device at %s\n", pci_name(PciDev));
+	goto err_continue;
+      }
+
+      if (pci_set_dma_mask(PciDev, CPQFCTS_DMA_MASK) != 0) {
+	printk(KERN_WARNING 
+		"cpqfc: HBA cannot support required DMA mask, skipping.\n");
+	goto err_disable_dev;
+      }
+
+      // NOTE: (kernel 2.2.12-32) limits allocation to 128k bytes...
+      /* printk(" scsi_register allocating %d bytes for FC HBA\n",
+		      (ULONG)sizeof(CPQFCHBA)); */
+
+      HostAdapter = scsi_register( ScsiHostTemplate, sizeof( CPQFCHBA ) );
+      
+      if(HostAdapter == NULL) {
+	printk(KERN_WARNING
+		"cpqfc: can't register SCSI HBA, skipping.\n");
+      	goto err_disable_dev;
+      }
+      DEBUG_PCI( printk("  HBA found!\n"));
+      DEBUG_PCI( printk("  HostAdapter->PciDev->irq = %u\n", PciDev->irq) );
+      DEBUG_PCI(printk("  PciDev->baseaddress[0]= %lx\n", 
+				PciDev->resource[0].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[1]= %lx\n", 
+				PciDev->resource[1].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[2]= %lx\n", 
+				PciDev->resource[2].start));
+      DEBUG_PCI(printk("  PciDev->baseaddress[3]= %lx\n", 
+				PciDev->resource[3].start));
+
+      scsi_set_device(HostAdapter, &PciDev->dev);
+      HostAdapter->irq = PciDev->irq;  // copy for Scsi layers
+      
+      // HP Tachlite uses two (255-byte) ranges of Port I/O (lower & upper),
+      // for a total I/O port address space of 512 bytes.
+      // mask out the I/O port address (lower) & record
+      HostAdapter->io_port = (unsigned int)
+	     PciDev->resource[1].start & PCI_BASE_ADDRESS_IO_MASK;
+      HostAdapter->n_io_port = 0xff;
+      
+      // i.e., expect 128 targets (arbitrary number), while the
+      //  RA-4000 supports 32 LUNs
+      HostAdapter->max_id =  0;   // incremented as devices log in    
+      HostAdapter->max_lun = CPQFCTS_MAX_LUN;         // LUNs per FC device
+      HostAdapter->max_channel = CPQFCTS_MAX_CHANNEL; // multiple busses?
+      
+      // get the pointer to our HBA specific data... (one for
+      // each HBA on the PCI bus(ses)).
+      cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+      
+      // make certain our data struct is clear
+      memset( cpqfcHBAdata, 0, sizeof( CPQFCHBA ) );
+
+
+      // initialize our HBA info
+      cpqfcHBAdata->HBAnum = NumberOfAdapters;
+
+      cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr
+      Cpqfc_initHBAdata( cpqfcHBAdata, PciDev ); // fill MOST fields
+     
+      cpqfcHBAdata->HBAnum = NumberOfAdapters;
+      spin_lock_init(&cpqfcHBAdata->hba_spinlock);
+
+      // request necessary resources and check for conflicts
+      if( request_irq( HostAdapter->irq,
+		       cpqfcTS_intr_handler,
+	               SA_INTERRUPT | SA_SHIRQ,
+	               DEV_NAME,
+		       HostAdapter) )
+      {
+	printk(KERN_WARNING "cpqfc: IRQ %u already used\n", HostAdapter->irq);
+	goto err_unregister;
+      }
+
+      // Since we have two 256-byte I/O port ranges (upper
+      // and lower), check them both
+      if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseU,
+      	                   0xff, DEV_NAME ) )
+      {
+	printk(KERN_WARNING "cpqfc: address in use: %x\n",
+			cpqfcHBAdata->fcChip.Registers.IOBaseU);
+	goto err_free_irq;
+      }	
+      
+      if( !request_region( cpqfcHBAdata->fcChip.Registers.IOBaseL,
+      			   0xff, DEV_NAME ) )
+      {
+  	printk(KERN_WARNING "cpqfc: address in use: %x\n",
+	      			cpqfcHBAdata->fcChip.Registers.IOBaseL);
+	goto err_release_region_U;
+      }	
+      
+      // OK, we have grabbed everything we need now.
+      DEBUG_PCI(printk("  Reserved 255 I/O addresses @ %x\n",
+        cpqfcHBAdata->fcChip.Registers.IOBaseL ));
+      DEBUG_PCI(printk("  Reserved 255 I/O addresses @ %x\n",
+        cpqfcHBAdata->fcChip.Registers.IOBaseU ));
+
+     
+ 
+      // start our kernel worker thread
+
+      spin_lock_irq(HostAdapter->host_lock);
+      launch_FCworker_thread(HostAdapter);
+
+
+      // start our TimerTask...
+
+      cpqfcTStimer = &cpqfcHBAdata->cpqfcTStimer;
+
+      init_timer( cpqfcTStimer); // Linux clears next/prev values
+      cpqfcTStimer->expires = jiffies + HZ; // one second
+      cpqfcTStimer->data = (unsigned long)cpqfcHBAdata; // this adapter
+      cpqfcTStimer->function = cpqfcTSheartbeat; // handles timeouts, housekeeping
+
+      add_timer( cpqfcTStimer);  // give it to Linux
+
+
+      // now initialize our hardware...
+      if (cpqfcHBAdata->fcChip.InitializeTachyon( cpqfcHBAdata, 1,1)) {
+	printk(KERN_WARNING "cpqfc: initialization of HBA hardware failed.\n");
+	goto err_release_region_L;
+      }
+
+      cpqfcHBAdata->fcStatsTime = jiffies;  // (for FC Statistics delta)
+      
+      // give our HBA time to initialize and login current devices...
+      {
+	// The Brocade switch (e.g. 2400, 2010, etc.) as of March 2000,
+	// has the following algorithm for FL_Port startup:
+	// Time(sec) Action
+	// 0:        Device Plugin and LIP(F7,F7) transmission
+	// 1.0       LIP incoming
+        // 1.027     LISA incoming, no CLS! (link not up)
+	// 1.028     NOS incoming (switch test for N_Port)
+        // 1.577     ED_TOV expired, transmit LIPs again	
+	// 3.0       LIP(F8,F7) incoming (switch passes Tach Prim.Sig)
+	// 3.028     LILP received, link up, FLOGI starts
+	// slowest(worst) case, measured on 1Gb Finisar GT analyzer
+	
+	unsigned long stop_time;
+
+	spin_unlock_irq(HostAdapter->host_lock);
+	stop_time = jiffies + 4*HZ;
+        while ( time_before(jiffies, stop_time) ) 
+	  	schedule();  // (our worker task needs to run)
+
+      }
+      
+      spin_lock_irq(HostAdapter->host_lock);
+      NumberOfAdapters++; 
+      spin_unlock_irq(HostAdapter->host_lock);
+
+      continue;
+
+err_release_region_L:
+      release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff );
+err_release_region_U:
+      release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff );
+err_free_irq:
+      free_irq( HostAdapter->irq, HostAdapter);
+err_unregister:
+      scsi_unregister( HostAdapter);
+err_disable_dev:
+      pci_disable_device( PciDev );
+err_continue:
+      continue;
+    } // end of while()
+  }
+
+  LEAVE("cpqfcTS_detect");
+ 
+  return NumberOfAdapters;
+}
+
+#ifdef SUPPORT_RESET
+static void my_ioctl_done (Scsi_Cmnd * SCpnt)
+{
+    struct request * req;
+    
+    req = SCpnt->request;
+    req->rq_status = RQ_SCSI_DONE; /* Busy, but indicate request done */
+  
+    if (req->CPQFC_WAITING != NULL)
+	CPQFC_COMPLETE(req->CPQFC_WAITING);
+}   
+#endif
+
+static int cpqfc_alloc_private_data_pool(CPQFCHBA *hba)
+{
+	hba->private_data_bits = NULL;
+	hba->private_data_pool = NULL;
+	hba->private_data_bits = 
+		kmalloc(((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
+				BITS_PER_LONG)*sizeof(unsigned long), 
+				GFP_KERNEL);
+	if (hba->private_data_bits == NULL)
+		return -1;
+	memset(hba->private_data_bits, 0,
+		((CPQFC_MAX_PASSTHRU_CMDS+BITS_PER_LONG-1) /
+				BITS_PER_LONG)*sizeof(unsigned long));
+	hba->private_data_pool = kmalloc(sizeof(cpqfc_passthru_private_t) *
+			CPQFC_MAX_PASSTHRU_CMDS, GFP_KERNEL);
+	if (hba->private_data_pool == NULL) {
+		kfree(hba->private_data_bits);
+		hba->private_data_bits = NULL;
+		return -1;
+	}
+	return 0;
+}
+
+static void cpqfc_free_private_data_pool(CPQFCHBA *hba)
+{
+	kfree(hba->private_data_bits);
+	kfree(hba->private_data_pool);
+}
+
+int is_private_data_of_cpqfc(CPQFCHBA *hba, void *pointer)
+{
+	/* Is pointer within our private data pool?
+	   We use Scsi_Request->upper_private_data (normally
+	   reserved for upper layer drivers, e.g. the sg driver)
+	   We check to see if the pointer is ours by looking at
+	   its address.  Is this ok?   Hmm, it occurs to me that
+	   a user app might do something bad by using sg to send
+	   a cpqfc passthrough ioctl with upper_data_private
+	   forged to be somewhere in our pool..., though they'd
+	   normally have to be root already to do this.  */
+
+	return (pointer != NULL && 
+		pointer >= (void *) hba->private_data_pool && 
+		pointer < (void *) hba->private_data_pool + 
+			sizeof(*hba->private_data_pool) * 
+				CPQFC_MAX_PASSTHRU_CMDS);
+}
+
+cpqfc_passthru_private_t *cpqfc_alloc_private_data(CPQFCHBA *hba)
+{
+	int i;
+
+	do {
+		i = find_first_zero_bit(hba->private_data_bits, 
+			CPQFC_MAX_PASSTHRU_CMDS);
+		if (i == CPQFC_MAX_PASSTHRU_CMDS)
+			return NULL;
+	} while ( test_and_set_bit(i & (BITS_PER_LONG - 1), 
+			hba->private_data_bits+(i/BITS_PER_LONG)) != 0);
+	return &hba->private_data_pool[i];
+}
+
+void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data)
+{
+	int i;
+	i = data - hba->private_data_pool;
+	clear_bit(i&(BITS_PER_LONG-1), 
+			hba->private_data_bits+(i/BITS_PER_LONG));
+}
+
+int cpqfcTS_ioctl( struct scsi_device *ScsiDev, int Cmnd, void *arg)
+{
+  int result = 0;
+  struct Scsi_Host *HostAdapter = ScsiDev->host;
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  PFC_LOGGEDIN_PORT pLoggedInPort = NULL;
+  struct scsi_cmnd *DumCmnd;
+  int i, j;
+  VENDOR_IOCTL_REQ ioc;
+  cpqfc_passthru_t *vendor_cmd;
+  Scsi_Device *SDpnt;
+  Scsi_Request *ScsiPassThruReq;
+  cpqfc_passthru_private_t *privatedata;
+
+  ENTER("cpqfcTS_ioctl ");
+
+    // printk("ioctl CMND %d", Cmnd);
+    switch (Cmnd) {
+      // Passthrough provides a mechanism to bypass the RAID
+      // or other controller and talk directly to the devices
+      // (e.g. physical disk drive)
+      // Passthrough commands, unfortunately, tend to be vendor
+      // specific; this is tailored to COMPAQ's RAID (RA4x00)
+      case CPQFCTS_SCSI_PASSTHRU:
+      {
+	void *buf = NULL; // for kernel space buffer for user data
+
+	/* Check that our pool got allocated ok. */
+	if (cpqfcHBAdata->private_data_pool == NULL)
+		return -ENOMEM;
+	
+	if( !arg)
+	  return -EINVAL;
+
+	// must be super user to send stuff directly to the
+	// controller and/or physical drives...
+	if( !capable(CAP_SYS_RAWIO) )
+	  return -EPERM;
+
+	// copy the caller's struct to our space.
+        if( copy_from_user( &ioc, arg, sizeof( VENDOR_IOCTL_REQ)))
+		return( -EFAULT);
+
+	vendor_cmd = ioc.argp;  // i.e., CPQ specific command struct
+
+	// If necessary, grab a kernel/DMA buffer
+	if( vendor_cmd->len)
+	{
+  	  buf = kmalloc( vendor_cmd->len, GFP_KERNEL);
+	  if( !buf)
+	    return -ENOMEM;
+	}
+        // Now build a Scsi_Request to pass down...
+        ScsiPassThruReq = scsi_allocate_request(ScsiDev, GFP_KERNEL);
+	if (ScsiPassThruReq == NULL) {
+		kfree(buf);
+		return -ENOMEM;
+	}
+	ScsiPassThruReq->upper_private_data = 
+			cpqfc_alloc_private_data(cpqfcHBAdata);
+	if (ScsiPassThruReq->upper_private_data == NULL) {
+		kfree(buf);
+		scsi_release_request(ScsiPassThruReq); // "de-allocate"
+		return -ENOMEM;
+	}
+
+	if (vendor_cmd->rw_flag == VENDOR_WRITE_OPCODE) {
+		if (vendor_cmd->len) { // Need data from user?
+        		if (copy_from_user(buf, vendor_cmd->bufp, 
+						vendor_cmd->len)) {
+				kfree(buf);
+				cpqfc_free_private_data(cpqfcHBAdata, 
+					ScsiPassThruReq->upper_private_data);
+				scsi_release_request(ScsiPassThruReq);
+				return( -EFAULT);
+			}
+		}
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_WRITE; 
+	} else if (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) {
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_READ; 
+	} else
+		// maybe this means a bug in the user app
+		ScsiPassThruReq->sr_data_direction = SCSI_DATA_NONE;
+	    
+	ScsiPassThruReq->sr_cmd_len = 0; // set correctly by scsi_do_req()
+	ScsiPassThruReq->sr_sense_buffer[0] = 0;
+	ScsiPassThruReq->sr_sense_buffer[2] = 0;
+
+        // We copy the scheme used by sd.c:spinup_disk() to submit commands
+	// to our own HBA.  We do this in order to stall the
+	// thread calling the IOCTL until it completes, and use
+	// the same "_quecommand" function for synchronizing
+	// FC Link events with our "worker thread".
+
+	privatedata = ScsiPassThruReq->upper_private_data;
+	privatedata->bus = vendor_cmd->bus;
+	privatedata->pdrive = vendor_cmd->pdrive;
+	
+        // eventually gets us to our own _quecommand routine
+	scsi_wait_req(ScsiPassThruReq, 
+		&vendor_cmd->cdb[0], buf, vendor_cmd->len, 
+		10*HZ,  // timeout
+		1);	// retries
+        result = ScsiPassThruReq->sr_result;
+
+        // copy any sense data back to caller
+        if( result != 0 )
+	{
+	  memcpy( vendor_cmd->sense_data, // see struct def - size=40
+		  ScsiPassThruReq->sr_sense_buffer, 
+		  sizeof(ScsiPassThruReq->sr_sense_buffer) <
+                  sizeof(vendor_cmd->sense_data)           ?
+                  sizeof(ScsiPassThruReq->sr_sense_buffer) :
+                  sizeof(vendor_cmd->sense_data)
+                ); 
+	}
+        SDpnt = ScsiPassThruReq->sr_device;
+	/* upper_private_data is already freed in call_scsi_done() */
+        scsi_release_request(ScsiPassThruReq); // "de-allocate"
+        ScsiPassThruReq = NULL;
+
+	// need to pass data back to user (space)?
+	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
+	     vendor_cmd->len )
+        if(  copy_to_user( vendor_cmd->bufp, buf, vendor_cmd->len))
+		result = -EFAULT;
+
+        if( buf) 
+	  kfree( buf);
+
+        return result;
+      }
+      
+      case CPQFCTS_GETPCIINFO:
+      {
+	cpqfc_pci_info_struct pciinfo;
+	
+	if( !arg)
+	  return -EINVAL;
+
+         	
+	
+        pciinfo.bus = cpqfcHBAdata->PciDev->bus->number;
+        pciinfo.dev_fn = cpqfcHBAdata->PciDev->devfn;  
+	pciinfo.board_id = cpqfcHBAdata->PciDev->device |
+			  (cpqfcHBAdata->PciDev->vendor <<16); 
+	      
+        if(copy_to_user( arg, &pciinfo, sizeof(cpqfc_pci_info_struct)))
+		return( -EFAULT);
+        return 0;
+      }
+
+      case CPQFCTS_GETDRIVVER:
+      {
+	DriverVer_type DriverVer = 
+		CPQFCTS_DRIVER_VER( VER_MAJOR,VER_MINOR,VER_SUBMINOR);
+	
+	if( !arg)
+	  return -EINVAL;
+
+        if(copy_to_user( arg, &DriverVer, sizeof(DriverVer)))
+		return( -EFAULT);
+        return 0;
+      }
+
+
+
+      case CPQFC_IOCTL_FC_TARGET_ADDRESS:
+	// can we find an FC device mapping to this SCSI target?
+/* 	DumCmnd.channel = ScsiDev->channel; */		// For searching
+/* 	DumCmnd.target  = ScsiDev->id; */
+/* 	DumCmnd.lun     = ScsiDev->lun; */
+
+	DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
+	if (!DumCmnd)
+		return -ENOMEM;
+	
+	pLoggedInPort = fcFindLoggedInPort( fcChip,
+		DumCmnd, // search Scsi Nexus
+		0,        // DON'T search linked list for FC port id
+		NULL,     // DON'T search linked list for FC WWN
+		NULL);    // DON'T care about end of list
+	scsi_put_command (DumCmnd);
+	if (pLoggedInPort == NULL) {
+		result = -ENXIO;
+		break;
+	}
+	result = access_ok(VERIFY_WRITE, arg, sizeof(Scsi_FCTargAddress)) ? 0 : -EFAULT;
+	if (result) break;
+ 
+      put_user(pLoggedInPort->port_id,
+		&((Scsi_FCTargAddress *) arg)->host_port_id);
+ 
+      for( i=3,j=0; i>=0; i--)   	// copy the LOGIN port's WWN
+        put_user(pLoggedInPort->u.ucWWN[i], 
+		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+      for( i=7; i>3; i--)		// copy the LOGIN port's WWN
+        put_user(pLoggedInPort->u.ucWWN[i], 
+		&((Scsi_FCTargAddress *) arg)->host_wwn[j++]);
+        break;
+
+
+      case CPQFC_IOCTL_FC_TDR:
+          
+        result = cpqfcTS_TargetDeviceReset( ScsiDev, 0);
+
+        break;
+
+
+
+
+    default:
+      result = -EINVAL;
+      break;
+    }
+
+  LEAVE("cpqfcTS_ioctl");
+  return result;
+}
+
+
+/* "Release" the Host Bus Adapter...
+   disable interrupts, stop the HBA, release the interrupt,
+   and free all resources */
+
+int cpqfcTS_release(struct Scsi_Host *HostAdapter)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+
+
+  ENTER("cpqfcTS_release");
+	
+  DEBUG_PCI( printk(" cpqfcTS: delete timer...\n"));
+  del_timer( &cpqfcHBAdata->cpqfcTStimer);  
+    
+  // disable the hardware...
+  DEBUG_PCI( printk(" disable hardware, destroy queues, free mem\n"));
+  cpqfcHBAdata->fcChip.ResetTachyon( cpqfcHBAdata, CLEAR_FCPORTS);
+
+  // kill kernel thread
+  if( cpqfcHBAdata->worker_thread ) // (only if exists)
+  {
+    DECLARE_MUTEX_LOCKED(sem);  // synchronize thread kill
+
+    cpqfcHBAdata->notify_wt = &sem;
+    DEBUG_PCI( printk(" killing kernel thread\n"));
+    send_sig( SIGKILL, cpqfcHBAdata->worker_thread, 1);
+    down( &sem);
+    cpqfcHBAdata->notify_wt = NULL;
+    
+  }
+
+  cpqfc_free_private_data_pool(cpqfcHBAdata);
+  // free Linux resources
+  DEBUG_PCI( printk(" cpqfcTS: freeing resources...\n"));
+  free_irq( HostAdapter->irq, HostAdapter);
+  scsi_unregister( HostAdapter);
+  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseL, 0xff);
+  release_region( cpqfcHBAdata->fcChip.Registers.IOBaseU, 0xff);
+ /* we get "vfree: bad address" executing this - need to investigate... 
+  if( (void*)((unsigned long)cpqfcHBAdata->fcChip.Registers.MemBase) !=
+      cpqfcHBAdata->fcChip.Registers.ReMapMemBase)
+    vfree( cpqfcHBAdata->fcChip.Registers.ReMapMemBase);
+*/
+  pci_disable_device( cpqfcHBAdata->PciDev);
+
+  LEAVE("cpqfcTS_release");
+  return 0;
+}
+
+
+const char * cpqfcTS_info(struct Scsi_Host *HostAdapter)
+{
+  static char buf[300];
+  CPQFCHBA *cpqfcHBA;
+  int BusSpeed, BusWidth;
+  
+  // get the pointer to our Scsi layer HBA buffer  
+  cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
+
+  BusWidth = (cpqfcHBA->fcChip.Registers.PCIMCTR &0x4) > 0 ?
+               64 : 32;
+
+  if( cpqfcHBA->fcChip.Registers.TYconfig.value & 0x80000000)
+    BusSpeed = 66;
+  else
+    BusSpeed = 33;
+
+  sprintf(buf, 
+"%s: WWN %08X%08X\n on PCI bus %d device 0x%02x irq %d IObaseL 0x%x, MEMBASE 0x%x\nPCI bus width %d bits, bus speed %d MHz\nFCP-SCSI Driver v%d.%d.%d",
+      cpqfcHBA->fcChip.Name, 
+      cpqfcHBA->fcChip.Registers.wwn_hi,
+      cpqfcHBA->fcChip.Registers.wwn_lo,
+      cpqfcHBA->PciDev->bus->number,
+      cpqfcHBA->PciDev->device,  
+      HostAdapter->irq,
+      cpqfcHBA->fcChip.Registers.IOBaseL,
+      cpqfcHBA->fcChip.Registers.MemBase,
+      BusWidth,
+      BusSpeed,
+      VER_MAJOR, VER_MINOR, VER_SUBMINOR
+);
+
+  
+  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
+  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
+  return buf;
+}
+
+//
+// /proc/scsi support. The following routines allow us to do 'normal'
+// sprintf like calls to return the currently requested piece (buflenght
+// chars, starting at bufoffset) of the file. Although procfs allows for
+// a 1 Kb bytes overflow after te supplied buffer, I consider it bad 
+// programming to use it to make programming a little simpler. This piece
+// of coding is borrowed from ncr53c8xx.c with some modifications 
+//
+struct info_str
+{
+        char *buffer;			// Pointer to output buffer
+        int buflength;			// It's length
+        int bufoffset;			// File offset corresponding with buf[0]
+	int buffillen;			// Current filled length 
+        int filpos;			// Current file offset
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int datalen)
+{
+
+  if (info->filpos < info->bufoffset) {	// Current offset before buffer offset
+    if (info->filpos + datalen <= info->bufoffset) {
+      info->filpos += datalen; 		// Discard if completely before buffer
+      return;
+    } else {				// Partial copy, set to begin
+      data += (info->bufoffset - info->filpos);
+      datalen  -= (info->bufoffset - info->filpos);
+      info->filpos = info->bufoffset;
+    }
+  }
+
+  info->filpos += datalen;		// Update current offset
+
+  if (info->buffillen == info->buflength) // Buffer full, discard
+    return;
+
+  if (info->buflength - info->buffillen < datalen)  // Overflows buffer ?
+    datalen = info->buflength - info->buffillen;
+
+  memcpy(info->buffer + info->buffillen, data, datalen);
+  info->buffillen += datalen;
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+        va_list args;
+        char buf[400];
+        int len;
+
+        va_start(args, fmt);
+        len = vsprintf(buf, fmt, args);
+        va_end(args);
+
+        copy_mem_info(info, buf, len);
+        return len;
+}
+
+
+// Routine to get data for /proc RAM filesystem
+//
+int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, 
+		       int inout)
+{
+  struct scsi_cmnd *DumCmnd;
+  struct scsi_device *ScsiDev;
+  int Chan, Targ, i;
+  struct info_str info;
+  CPQFCHBA *cpqfcHBA;
+  PTACHYON fcChip;
+  PFC_LOGGEDIN_PORT pLoggedInPort;
+  char buf[81];
+
+  if (inout) return -EINVAL;
+
+  // get the pointer to our Scsi layer HBA buffer  
+  cpqfcHBA = (CPQFCHBA *)host->hostdata;
+  fcChip = &cpqfcHBA->fcChip;
+  
+  *start 	  = buffer;
+
+  info.buffer     = buffer;
+  info.buflength  = length;
+  info.bufoffset  = offset;
+  info.filpos     = 0;
+  info.buffillen  = 0;
+  copy_info(&info, "Driver version = %d.%d.%d", VER_MAJOR, VER_MINOR, VER_SUBMINOR); 
+  cpqfcTSDecodeGBICtype( &cpqfcHBA->fcChip, &buf[0]);
+  cpqfcTSGetLPSM( &cpqfcHBA->fcChip, &buf[ strlen(buf)]);
+  copy_info(&info, "%s\n", buf); 
+
+#define DISPLAY_WWN_INFO
+#ifdef DISPLAY_WWN_INFO
+  ScsiDev = scsi_get_host_dev (host);
+  if (!ScsiDev) 
+    return -ENOMEM;
+  DumCmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
+  if (!DumCmnd) {
+    scsi_free_host_dev (ScsiDev);
+    return -ENOMEM;
+  }
+  copy_info(&info, "WWN database: (\"port_id: 000000\" means disconnected)\n");
+  for ( Chan=0; Chan <= host->max_channel; Chan++) {
+    DumCmnd->device->channel = Chan;
+    for (Targ=0; Targ <= host->max_id; Targ++) {
+      DumCmnd->device->id = Targ;
+      if ((pLoggedInPort = fcFindLoggedInPort( fcChip,
+	    			DumCmnd,  // search Scsi Nexus
+    				0,        // DON'T search list for FC port id
+    				NULL,     // DON'T search list for FC WWN
+    				NULL))){   // DON'T care about end of list
+	copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ",
+			   host->host_no, Chan, Targ);
+        for( i=3; i>=0; i--)        // copy the LOGIN port's WWN
+          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+        for( i=7; i>3; i--)             // copy the LOGIN port's WWN
+          copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]);
+	copy_info(&info, " port_id: %06X\n", pLoggedInPort->port_id); 
+      }
+    }
+  }
+
+  scsi_put_command (DumCmnd);
+  scsi_free_host_dev (ScsiDev);
+#endif
+
+
+
+  
+  
+// Unfortunately, the proc_info buffer isn't big enough
+// for everything we would like...
+// For FC stats, compile this and turn off WWN stuff above  
+//#define DISPLAY_FC_STATS
+#ifdef DISPLAY_FC_STATS
+// get the Fibre Channel statistics
+  {
+    int DeltaSecs = (jiffies - cpqfcHBA->fcStatsTime) / HZ;
+    int days,hours,minutes,secs;
+    
+    days = DeltaSecs / (3600*24); // days
+    hours = (DeltaSecs% (3600*24)) / 3600; // hours
+    minutes = (DeltaSecs%3600 /60); // minutes
+    secs =  DeltaSecs%60;  // secs
+copy_info( &info, "Fibre Channel Stats (time dd:hh:mm:ss %02u:%02u:%02u:%02u\n",
+      days, hours, minutes, secs);
+  }
+    
+  cpqfcHBA->fcStatsTime = jiffies;  // (for next delta)
+
+  copy_info( &info, "  LinkUp           %9u     LinkDown      %u\n",
+        fcChip->fcStats.linkUp, fcChip->fcStats.linkDown);
+        
+  copy_info( &info, "  Loss of Signal   %9u     Loss of Sync  %u\n",
+    fcChip->fcStats.LossofSignal, fcChip->fcStats.LossofSync);
+		  
+  copy_info( &info, "  Discarded Frames %9u     Bad CRC Frame %u\n",
+    fcChip->fcStats.Dis_Frm, fcChip->fcStats.Bad_CRC);
+
+  copy_info( &info, "  TACH LinkFailTX  %9u     TACH LinkFailRX     %u\n",
+    fcChip->fcStats.linkFailTX, fcChip->fcStats.linkFailRX);
+  
+  copy_info( &info, "  TACH RxEOFa      %9u     TACH Elastic Store  %u\n",
+    fcChip->fcStats.Rx_EOFa, fcChip->fcStats.e_stores);
+
+  copy_info( &info, "  BufferCreditWait %9uus   TACH FM Inits %u\n",
+    fcChip->fcStats.BB0_Timer*10, fcChip->fcStats.FMinits );
+	
+  copy_info( &info, "  FC-2 Timeouts    %9u     FC-2 Logouts  %u\n",
+    fcChip->fcStats.timeouts, fcChip->fcStats.logouts); 
+        
+  copy_info( &info, "  FC-2 Aborts      %9u     FC-4 Aborts   %u\n",
+    fcChip->fcStats.FC2aborted, fcChip->fcStats.FC4aborted);
+   
+  // clear the counters
+  cpqfcTSClearLinkStatusCounters( fcChip);
+#endif
+	
+  return info.buffillen;
+}
+
+
+#if DEBUG_CMND
+
+UCHAR *ScsiToAscii( UCHAR ScsiCommand)
+{
+
+/*++
+
+Routine Description:
+
+   Converts a SCSI command to a text string for debugging purposes.
+
+
+Arguments:
+
+   ScsiCommand -- hex value SCSI Command
+
+
+Return Value:
+
+   An ASCII, null-terminated string if found, else returns NULL.
+
+Original code from M. McGowen, Compaq
+--*/
+
+
+   switch (ScsiCommand)
+   {
+      case 0x00:
+         return( "Test Unit Ready" );
+
+      case 0x01:
+         return( "Rezero Unit or Rewind" );
+
+      case 0x02:
+         return( "Request Block Address" );
+
+      case 0x03:
+         return( "Requese Sense" );
+
+      case 0x04:
+         return( "Format Unit" );
+
+      case 0x05:
+         return( "Read Block Limits" );
+
+      case 0x07:
+         return( "Reassign Blocks" );
+
+      case 0x08:
+         return( "Read (6)" );
+
+      case 0x0a:
+         return( "Write (6)" );
+
+      case 0x0b:
+         return( "Seek (6)" );
+
+      case 0x12:
+         return( "Inquiry" );
+
+      case 0x15:
+         return( "Mode Select (6)" );
+
+      case 0x16:
+         return( "Reserve" );
+
+      case 0x17:
+         return( "Release" );
+
+      case 0x1a:
+         return( "ModeSen(6)" );
+
+      case 0x1b:
+         return( "Start/Stop Unit" );
+
+      case 0x1c:
+         return( "Receive Diagnostic Results" );
+
+      case 0x1d:
+         return( "Send Diagnostic" );
+
+      case 0x25:
+         return( "Read Capacity" );
+
+      case 0x28:
+         return( "Read (10)" );
+
+      case 0x2a:
+         return( "Write (10)" );
+
+      case 0x2b:
+         return( "Seek (10)" );
+
+      case 0x2e:
+         return( "Write and Verify" );
+
+      case 0x2f:
+         return( "Verify" );
+
+      case 0x34:
+         return( "Pre-Fetch" );
+
+      case 0x35:
+         return( "Synchronize Cache" );
+
+      case 0x37:
+         return( "Read Defect Data (10)" );
+
+      case 0x3b:
+         return( "Write Buffer" );
+
+      case 0x3c:
+         return( "Read Buffer" );
+
+      case 0x3e:
+         return( "Read Long" );
+
+      case 0x3f:
+         return( "Write Long" );
+
+      case 0x41:
+         return( "Write Same" );
+
+      case 0x4c:
+         return( "Log Select" );
+
+      case 0x4d:
+         return( "Log Sense" );
+
+      case 0x56:
+         return( "Reserve (10)" );
+
+      case 0x57:
+         return( "Release (10)" );
+
+      case 0xa0:
+         return( "ReportLuns" );
+
+      case 0xb7:
+         return( "Read Defect Data (12)" );
+
+      case 0xca:
+         return( "Peripheral Device Addressing SCSI Passthrough" );
+
+      case 0xcb:
+         return( "Compaq Array Firmware Passthrough" );
+
+      default:
+         return( NULL );
+   }
+
+} // end ScsiToAscii()
+
+void cpqfcTS_print_scsi_cmd(Scsi_Cmnd * cmd)
+{
+
+printk("cpqfcTS: (%s) chnl 0x%02x, trgt = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
+    ScsiToAscii( cmd->cmnd[0]), cmd->channel, cmd->target, cmd->lun, cmd->cmd_len);
+
+if( cmd->cmnd[0] == 0)   // Test Unit Ready?
+{
+  int i;
+
+  printk("Cmnd->request_bufflen = 0x%X, ->use_sg = %d, ->bufflen = %d\n",
+    cmd->request_bufflen, cmd->use_sg, cmd->bufflen);
+  printk("Cmnd->request_buffer = %p, ->sglist_len = %d, ->buffer = %p\n",
+    cmd->request_buffer, cmd->sglist_len, cmd->buffer);
+  for (i = 0; i < cmd->cmd_len; i++)
+    printk("0x%02x ", cmd->cmnd[i]);
+  printk("\n");
+}
+
+}
+
+#endif				/* DEBUG_CMND */
+
+
+
+
+static void QueCmndOnBoardLock( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+{
+  int i;
+
+  for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
+  {    // find spare slot
+    if( cpqfcHBAdata->BoardLockCmnd[i] == NULL )
+    {
+      cpqfcHBAdata->BoardLockCmnd[i] = Cmnd;
+//      printk(" BoardLockCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
+//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+      break;
+    }
+  }
+  if( i >= CPQFCTS_REQ_QUEUE_LEN)
+  {
+    printk(" cpqfcTS WARNING: Lost Cmnd %p on BoardLock Q full!", Cmnd);
+  }
+
+}
+
+
+static void QueLinkDownCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+{
+  int indx;
+
+  // Remember the command ptr so we can return; we'll complete when
+  // the device comes back, causing immediate retry
+  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++)//, SCptr++)
+  {
+    if( cpqfcHBAdata->LinkDnCmnd[indx] == NULL ) // available?
+    {
+#ifdef DUMMYCMND_DBG
+      printk(" @add Cmnd %p to LnkDnCmnd[%d]@ ", Cmnd,indx);
+#endif
+      cpqfcHBAdata->LinkDnCmnd[indx] = Cmnd;
+      break;
+    }
+  }
+
+  if( indx >= CPQFCTS_REQ_QUEUE_LEN ) // no space for Cmnd??
+  {
+    // this will result in an _abort call later (with possible trouble)
+    printk("no buffer for LinkDnCmnd!! %p\n", Cmnd);
+  }
+}
+
+
+
+
+
+// The file <scsi/scsi_host.h> says not to call scsi_done from
+// inside _queuecommand, so we'll do it from the heartbeat timer
+// (clarification: Turns out it's ok to call scsi_done from queuecommand 
+// for cases that don't go to the hardware like scsi cmds destined
+// for LUNs we know don't exist, so this code might be simplified...)
+
+static void QueBadTargetCmnd( CPQFCHBA *cpqfcHBAdata, Scsi_Cmnd *Cmnd)
+{
+  int i;
+    //    printk(" can't find target %d\n", Cmnd->target);
+
+  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
+  {    // find spare slot
+    if( cpqfcHBAdata->BadTargetCmnd[i] == NULL )
+    {
+      cpqfcHBAdata->BadTargetCmnd[i] = Cmnd;
+//      printk(" BadTargetCmnd[%d] %p Queued, chnl/target/lun %d/%d/%d\n",
+//          i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+      break;
+    }
+  }
+}
+
+
+// This is the "main" entry point for Linux Scsi commands --
+// it all starts here.
+
+int cpqfcTS_queuecommand(Scsi_Cmnd *Cmnd, void (* done)(Scsi_Cmnd *))
+{
+  struct Scsi_Host *HostAdapter = Cmnd->device->host;
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  TachFCHDR_GCMND fchs;  // only use for FC destination id field  
+  PFC_LOGGEDIN_PORT pLoggedInPort;
+  ULONG ulStatus, SESTtype;
+  LONG ExchangeID;
+
+
+
+
+  ENTER("cpqfcTS_queuecommand");
+      
+  PCI_TRACEO( (ULONG)Cmnd, 0x98)
+      
+  
+  Cmnd->scsi_done = done;
+#ifdef DEBUG_CMND  
+  cpqfcTS_print_scsi_cmd( Cmnd);
+#endif
+
+  // prevent board contention with kernel thread...  
+  
+   if( cpqfcHBAdata->BoardLock )
+  {
+//    printk(" @BrdLck Hld@ ");
+    QueCmndOnBoardLock( cpqfcHBAdata, Cmnd);
+  }
+  
+  else
+  {
+
+    // in the current system (2.2.12), this routine is called
+    // after spin_lock_irqsave(), so INTs are disabled. However,
+    // we might have something pending in the LinkQ, which
+    // might cause the WorkerTask to run.  In case that
+    // happens, make sure we lock it out.
+    
+    
+    
+    PCI_TRACE( 0x98) 
+    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
+    PCI_TRACE( 0x98) 
+	    
+  // can we find an FC device mapping to this SCSI target?
+    pLoggedInPort = fcFindLoggedInPort( fcChip,
+      Cmnd,     // search Scsi Nexus
+      0,        // DON'T search linked list for FC port id
+      NULL,     // DON'T search linked list for FC WWN
+      NULL);    // DON'T care about end of list
+ 
+    if( pLoggedInPort == NULL )      // not found!
+    {
+//    printk(" @Q bad targ cmnd %p@ ", Cmnd);
+      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
+    }
+    else if (Cmnd->device->lun >= CPQFCTS_MAX_LUN)
+    {
+      printk(KERN_WARNING "cpqfc: Invalid LUN: %d\n", Cmnd->device->lun);
+      QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
+    } 
+
+    else  // we know what FC device to send to...
+    {
+
+      // does this device support FCP target functions?
+      // (determined by PRLI field)
+
+      if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
+      {
+        printk(" Doesn't support TARGET functions port_id %Xh\n",
+          pLoggedInPort->port_id );
+        QueBadTargetCmnd( cpqfcHBAdata, Cmnd);
+      }
+
+    // In this case (previous login OK), the device is temporarily
+    // unavailable waiting for re-login, in which case we expect it
+    // to be back in between 25 - 500ms.  
+    // If the FC port doesn't log back in within several seconds
+    // (i.e. implicit "logout"), or we get an explicit logout,
+    // we set "device_blocked" in Scsi_Device struct; in this
+    // case 30 seconds will elapse before Linux/Scsi sends another
+    // command to the device.
+      else if( pLoggedInPort->prli != TRUE )
+      {
+//      printk("Device (Chnl/Target %d/%d) invalid PRLI, port_id %06lXh\n",
+//        Cmnd->channel, Cmnd->target, pLoggedInPort->port_id);
+        QueLinkDownCmnd( cpqfcHBAdata, Cmnd);
+//    Need to use "blocked" flag??   	
+//	Cmnd->device->device_blocked = TRUE; // just let it timeout
+      }
+      else  // device supports TARGET functions, and is logged in...
+      {
+      // (context of fchs is to "reply" to...)
+        fchs.s_id = pLoggedInPort->port_id; // destination FC address
+
+      // what is the data direction?  For data TO the device,
+      // we need IWE (Intiator Write Entry).  Otherwise, IRE.
+
+        if( Cmnd->cmnd[0] == WRITE_10 ||
+  	  Cmnd->cmnd[0] == WRITE_6 ||
+	  Cmnd->cmnd[0] == WRITE_BUFFER ||      
+	  Cmnd->cmnd[0] == VENDOR_WRITE_OPCODE ||  // CPQ specific 
+	  Cmnd->cmnd[0] == MODE_SELECT )
+        {
+          SESTtype = SCSI_IWE; // data from HBA to Device
+        }
+        else
+          SESTtype = SCSI_IRE; // data from Device to HBA
+    	  
+        ulStatus = cpqfcTSBuildExchange(
+          cpqfcHBAdata,
+          SESTtype,     // e.g. Initiator Read Entry (IRE)
+          &fchs,        // we are originator; only use d_id
+          Cmnd,         // Linux SCSI command (with scatter/gather list)
+          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+
+        if( !ulStatus ) // Exchange setup?
+   
+        {
+          if( cpqfcHBAdata->BoardLock )
+          {
+    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+	    printk(" @bl! %d, xID %Xh@ ", current->pid, ExchangeID);
+          }
+
+	  ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
+	  if( !ulStatus )
+          {
+            PCI_TRACEO( ExchangeID, 0xB8) 
+          // submitted to Tach's Outbound Que (ERQ PI incremented)
+          // waited for completion for ELS type (Login frames issued
+          // synchronously)
+	  }
+          else
+            // check reason for Exchange not being started - we might
+            // want to Queue and start later, or fail with error
+          {
+            printk("quecommand: cpqfcTSStartExchange failed: %Xh\n", ulStatus );
+          }
+        }            // end good BuildExchange status
+        
+        else  // SEST table probably full  -- why? hardware hang?
+        {
+	  printk("quecommand: cpqfcTSBuildExchange faild: %Xh\n", ulStatus);
+        }
+      }  // end can't do FCP-SCSI target functions
+    } // end can't find target (FC device)
+
+    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+  }
+	
+  PCI_TRACEO( (ULONG)Cmnd, 0x9C) 
+  LEAVE("cpqfcTS_queuecommand");
+  return 0;
+}    
+
+
+// Entry point for upper Scsi layer intiated abort.  Typically
+// this is called if the command (for hard disk) fails to complete
+// in 30 seconds.  This driver intends to complete all disk commands
+// within Exchange ".timeOut" seconds (now 7) with target status, or
+// in case of ".timeOut" expiration, a DID_SOFT_ERROR which causes
+// immediate retry.
+// If any disk commands get the _abort call, except for the case that
+// the physical device was removed or unavailable due to hardware
+// errors, it should be considered a driver error and reported to
+// the author.
+
+int cpqfcTS_abort(Scsi_Cmnd *Cmnd)
+{
+//	printk(" cpqfcTS_abort called?? \n");
+ 	return 0;
+}
+ 
+int cpqfcTS_eh_abort(Scsi_Cmnd *Cmnd)
+{
+
+  struct Scsi_Host *HostAdapter = Cmnd->device->host;
+  // get the pointer to our Scsi layer HBA buffer  
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  int i;
+  ENTER("cpqfcTS_eh_abort");
+
+  Cmnd->result = DID_ABORT <<16;  // assume we'll find it
+
+  printk(" @Linux _abort Scsi_Cmnd %p ", Cmnd);
+  // See if we can find a Cmnd pointer that matches...
+  // The most likely case is we accepted the command
+  // from Linux Scsi (e.g. ceated a SEST entry) and it
+  // got lost somehow.  If we can't find any reference
+  // to the passed pointer, we can only presume it
+  // got completed as far as our driver is concerned.
+  // If we found it, we will try to abort it through
+  // common mechanism.  If FC ABTS is successful (ACC)
+  // or is rejected (RJT) by target, we will call
+  // Scsi "done" quickly.  Otherwise, the ABTS will timeout
+  // and we'll call "done" later.
+
+  // Search the SEST exchanges for a matching Cmnd ptr.
+  for( i=0; i< TACH_SEST_LEN; i++)
+  {
+    if( Exchanges->fcExchange[i].Cmnd == Cmnd )
+    {
+      
+      // found it!
+      printk(" x_ID %Xh, type %Xh\n", i, Exchanges->fcExchange[i].type);
+
+      Exchanges->fcExchange[i].status = INITIATOR_ABORT; // seconds default
+      Exchanges->fcExchange[i].timeOut = 10; // seconds default (changed later)
+
+      // Since we need to immediately return the aborted Cmnd to Scsi 
+      // upper layers, we can't make future reference to any of its 
+      // fields (e.g the Nexus).
+
+      cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i);
+
+      break;
+    }
+  }
+
+  if( i >= TACH_SEST_LEN ) // didn't find Cmnd ptr in chip's SEST?
+  {
+    // now search our non-SEST buffers (i.e. Cmnd waiting to
+    // start on the HBA or waiting to complete with error for retry).
+    
+    // first check BadTargetCmnd
+    for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
+    { 
+      if( cpqfcHBAdata->BadTargetCmnd[i] == Cmnd )
+      {
+        cpqfcHBAdata->BadTargetCmnd[i] = NULL;
+	printk("in BadTargetCmnd Q\n");
+	goto Done; // exit
+      }
+    }
+
+    // if not found above...
+
+    for( i=0; i < CPQFCTS_REQ_QUEUE_LEN; i++)
+    {
+      if( cpqfcHBAdata->LinkDnCmnd[i] == Cmnd ) 
+      {
+	cpqfcHBAdata->LinkDnCmnd[i] = NULL;
+	printk("in LinkDnCmnd Q\n");
+	goto Done;
+      }
+    }
+
+
+    for( i=0; i< CPQFCTS_REQ_QUEUE_LEN; i++)
+    {    // find spare slot
+      if( cpqfcHBAdata->BoardLockCmnd[i] == Cmnd )
+      {
+        cpqfcHBAdata->BoardLockCmnd[i] = NULL;
+	printk("in BoardLockCmnd Q\n");
+	goto Done;
+      }
+    }
+    
+    Cmnd->result = DID_ERROR <<16;  // Hmmm...
+    printk("Not found! ");
+//    panic("_abort");
+  }
+  
+Done:
+  
+//    panic("_abort");
+  LEAVE("cpqfcTS_eh_abort");
+  return 0;  // (see scsi.h)
+}    
+
+
+// FCP-SCSI Target Device Reset
+// See dpANS Fibre Channel Protocol for SCSI
+// X3.269-199X revision 12, pg 25
+
+#ifdef SUPPORT_RESET
+
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
+                               unsigned int reset_flags)
+{
+  int timeout = 10*HZ;
+  int retries = 1;
+  char scsi_cdb[12];
+  int result;
+  Scsi_Cmnd * SCpnt;
+  Scsi_Device * SDpnt;
+
+// FIXME, cpqfcTS_TargetDeviceReset needs to be fixed 
+// similarly to how the passthrough ioctl was fixed 
+// around the 2.5.30 kernel.  Scsi_Cmnd replaced with 
+// Scsi_Request, etc.
+// For now, so people don't fall into a hole...
+
+  // printk("   ENTERING cpqfcTS_TargetDeviceReset() - flag=%d \n",reset_flags);
+
+  if (ScsiDev->host->eh_active) return FAILED;
+
+  memset( scsi_cdb, 0, sizeof( scsi_cdb));
+
+  scsi_cdb[0] = RELEASE;
+
+  SCpnt = scsi_get_command(ScsiDev, GFP_KERNEL);
+  {
+    CPQFC_DECLARE_COMPLETION(wait);
+    
+    SCpnt->SCp.buffers_residual = FCP_TARGET_RESET;
+
+	// FIXME: this would panic, SCpnt->request would be NULL.
+	SCpnt->request->CPQFC_WAITING = &wait;
+	scsi_do_cmd(SCpnt,  scsi_cdb, NULL,  0, my_ioctl_done,  timeout, retries);
+	CPQFC_WAIT_FOR_COMPLETION(&wait);
+	SCpnt->request->CPQFC_WAITING = NULL;
+  }
+    
+
+      if(driver_byte(SCpnt->result) != 0)
+	  switch(SCpnt->sense_buffer[2] & 0xf) {
+	case ILLEGAL_REQUEST:
+	    if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
+	    else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
+	    break;
+	case NOT_READY: // This happens if there is no disc in drive 
+	    if(dev->removable && (cmd[0] != TEST_UNIT_READY)){
+		printk(KERN_INFO "Device not ready.  Make sure there is a disc in the drive.\n");
+		break;
+	    }
+	case UNIT_ATTENTION:
+	    if (dev->removable){
+		dev->changed = 1;
+		SCpnt->result = 0; // This is no longer considered an error
+		// gag this error, VFS will log it anyway /axboe 
+		// printk(KERN_INFO "Disc change detected.\n"); 
+		break;
+	    };
+	default: // Fall through for non-removable media
+	    printk("SCSI error: host %d id %d lun %d return code = %x\n",
+		   dev->host->host_no,
+		   dev->id,
+		   dev->lun,
+		   SCpnt->result);
+	    printk("\tSense class %x, sense error %x, extended sense %x\n",
+		   sense_class(SCpnt->sense_buffer[0]),
+		   sense_error(SCpnt->sense_buffer[0]),
+		   SCpnt->sense_buffer[2] & 0xf);
+	    
+      };
+  result = SCpnt->result;
+
+  SDpnt = SCpnt->device;
+  scsi_put_command(SCpnt);
+  SCpnt = NULL;
+
+  // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
+  return SUCCESS;
+}
+
+#else
+int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, 
+                               unsigned int reset_flags)
+{
+	return -ENOTSUPP;
+}
+
+#endif /* SUPPORT_RESET */
+
+int cpqfcTS_eh_device_reset(Scsi_Cmnd *Cmnd)
+{
+  int retval;
+  Scsi_Device *SDpnt = Cmnd->device;
+  // printk("   ENTERING cpqfcTS_eh_device_reset() \n");
+  spin_unlock_irq(Cmnd->device->host->host_lock);
+  retval = cpqfcTS_TargetDeviceReset( SDpnt, 0);
+  spin_lock_irq(Cmnd->device->host->host_lock);
+  return retval;
+}
+
+	
+int cpqfcTS_reset(Scsi_Cmnd *Cmnd, unsigned int reset_flags)
+{
+
+  ENTER("cpqfcTS_reset");
+
+  LEAVE("cpqfcTS_reset");
+  return SCSI_RESET_ERROR;      /* Bus Reset Not supported */
+}
+
+/* This function determines the bios parameters for a given
+   harddisk. These tend to be numbers that are made up by the
+   host adapter.  Parameters:
+   size, device number, list (heads, sectors,cylinders).
+   (from hosts.h)
+*/
+
+int cpqfcTS_biosparam(struct scsi_device *sdev, struct block_device *n,
+		sector_t capacity, int ip[])
+{
+  int size = capacity;
+  
+  ENTER("cpqfcTS_biosparam");
+  ip[0] = 64;
+  ip[1] = 32;
+  ip[2] = size >> 11;
+  
+  if( ip[2] > 1024 )
+  {
+    ip[0] = 255;
+    ip[1] = 63;
+    ip[2] = size / (ip[0] * ip[1]);
+  }
+
+  LEAVE("cpqfcTS_biosparam");
+  return 0;
+}    
+
+
+
+irqreturn_t cpqfcTS_intr_handler( int irq, 
+		void *dev_id, 
+		struct pt_regs *regs)
+{
+
+  unsigned long flags, InfLoopBrk=0;
+  struct Scsi_Host *HostAdapter = dev_id;
+  CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata;
+  int MoreMessages = 1; // assume we have something to do
+  UCHAR IntPending;
+  int handled = 0;
+
+  ENTER("intr_handler");
+  spin_lock_irqsave( HostAdapter->host_lock, flags);
+  // is this our INT?
+  IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address);
+
+  // broken boards can generate messages forever, so
+  // prevent the infinite loop
+#define INFINITE_IMQ_BREAK 10000
+  if( IntPending )
+  {
+    handled = 1;
+    // mask our HBA interrupts until we handle it...
+    writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address);
+
+    if( IntPending & 0x4) // "INT" - Tach wrote to IMQ
+    {
+      while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) 
+      {
+        MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done
+      }
+      if( InfLoopBrk >= INFINITE_IMQ_BREAK )
+      {
+        printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n");
+        printk("or investigate alternate causes (e.g. physical FC layer)\n");
+      }
+
+      else  // working normally - re-enable INTs and continue
+        writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address);
+    
+    }  // (...ProcessIMQEntry() clears INT by writing IMQ consumer)
+    else  // indications of errors or problems...
+          // these usually indicate critical system hardware problems.
+    {
+      if( IntPending & 0x10 )
+  	printk(" cpqfcTS adapter external memory parity error detected\n");
+      if( IntPending & 0x8 )
+  	printk(" cpqfcTS adapter PCI master address crossed 45-bit boundary\n");
+      if( IntPending & 0x2 )
+	printk(" cpqfcTS adapter DMA error detected\n");
+      if( IntPending & 0x1 ) {
+  	UCHAR IntStat;
+  	printk(" cpqfcTS adapter PCI error detected\n");
+  	IntStat = readb( cpqfcHBA->fcChip.Registers.INTSTAT.address);
+	printk("cpqfc: ISR = 0x%02x\n", IntStat);
+	if (IntStat & 0x1) {
+		__u16 pcistat;
+		/* read the pci status register */
+		pci_read_config_word(cpqfcHBA->PciDev, 0x06, &pcistat);
+		printk("PCI status register is 0x%04x\n", pcistat);
+		if (pcistat & 0x8000) printk("Parity Error Detected.\n");
+		if (pcistat & 0x4000) printk("Signalled System Error\n");
+		if (pcistat & 0x2000) printk("Received Master Abort\n");
+		if (pcistat & 0x1000) printk("Received Target Abort\n");
+		if (pcistat & 0x0800) printk("Signalled Target Abort\n");
+	}
+	if (IntStat & 0x4) printk("(INT)\n");
+	if (IntStat & 0x8) 
+		printk("CRS: PCI master address crossed 46 bit bouandary\n");
+	if (IntStat & 0x10) printk("MRE: external memory parity error.\n");
+      }
+    }      
+  }
+  spin_unlock_irqrestore( HostAdapter->host_lock, flags);
+  LEAVE("intr_handler");
+  return IRQ_RETVAL(handled);
+}
+
+
+
+
+int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[])
+{
+        // Verify GBIC type (if any) and correct Tachyon Port State Machine
+        // (GBIC) module definition is:
+        // GPIO1, GPIO0, GPIO4 for MD2, MD1, MD0.  The input states appear
+        // to be inverted -- i.e., a setting of 111 is read when there is NO
+        // GBIC present.  The Module Def (MD) spec says 000 is "no GBIC"
+        // Hard code the bit states to detect Copper, 
+        // Long wave (single mode), Short wave (multi-mode), and absent GBIC
+
+  ULONG ulBuff;
+
+  sprintf( cErrorString, "\nGBIC detected: ");
+
+  ulBuff = fcChip->Registers.TYstatus.value & 0x13; 
+  switch( ulBuff )
+  {
+  case 0x13:  // GPIO4, GPIO1, GPIO0 = 111; no GBIC!
+    sprintf( &cErrorString[ strlen( cErrorString)],
+            "NONE! ");
+    return FALSE;          
+          
+       
+  case 0x11:   // Copper GBIC detected
+    sprintf( &cErrorString[ strlen( cErrorString)],
+            "Copper. ");
+    break;
+
+  case 0x10:   // Long-wave (single mode) GBIC detected
+    sprintf( &cErrorString[ strlen( cErrorString)],
+        "Long-wave. ");
+    break;
+  case 0x1:    // Short-wave (multi mode) GBIC detected
+    sprintf( &cErrorString[ strlen( cErrorString)],
+        "Short-wave. ");
+    break;
+  default:     // unknown GBIC - presumably it will work (?)
+    sprintf( &cErrorString[ strlen( cErrorString)],
+            "Unknown. ");
+          
+    break;
+  }  // end switch GBIC detection
+
+  return TRUE;
+}
+
+
+
+
+
+
+int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[])
+{
+  // Tachyon's Frame Manager LPSM in LinkDown state?
+  // (For non-loop port, check PSM instead.)
+  // return string with state and FALSE is Link Down
+
+  int LinkUp;
+
+  if( fcChip->Registers.FMstatus.value & 0x80 ) 
+    LinkUp = FALSE;
+  else
+    LinkUp = TRUE;
+
+  sprintf( &cErrorString[ strlen( cErrorString)],
+    " LPSM %Xh ", 
+     (fcChip->Registers.FMstatus.value >>4) & 0xf );
+
+
+  switch( fcChip->Registers.FMstatus.value & 0xF0)
+  {
+                    // bits set in LPSM
+    case 0x10:
+      sprintf( &cErrorString[ strlen( cErrorString)], "ARB");
+      break;
+    case 0x20:
+      sprintf( &cErrorString[ strlen( cErrorString)], "ARBwon");
+      break;
+    case 0x30:
+      sprintf( &cErrorString[ strlen( cErrorString)], "OPEN");
+      break;
+    case 0x40:
+      sprintf( &cErrorString[ strlen( cErrorString)], "OPENed");
+      break;
+    case 0x50:
+      sprintf( &cErrorString[ strlen( cErrorString)], "XmitCLS");
+      break;
+    case 0x60:
+      sprintf( &cErrorString[ strlen( cErrorString)], "RxCLS");
+      break;
+    case 0x70:
+      sprintf( &cErrorString[ strlen( cErrorString)], "Xfer");
+      break;
+    case 0x80:
+      sprintf( &cErrorString[ strlen( cErrorString)], "Init");
+      break;
+    case 0x90:
+      sprintf( &cErrorString[ strlen( cErrorString)], "O-IInitFin");
+      break;
+    case 0xa0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "O-IProtocol");
+      break;
+    case 0xb0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "O-ILipRcvd");
+      break;
+    case 0xc0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "HostControl");
+      break;
+    case 0xd0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "LoopFail");
+      break;
+    case 0xe0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "Offline");
+      break;
+    case 0xf0:
+      sprintf( &cErrorString[ strlen( cErrorString)], "OldPort");
+      break;
+    case 0:
+    default:
+      sprintf( &cErrorString[ strlen( cErrorString)], "Monitor");
+      break;
+
+  }
+
+  return LinkUp;
+}
+
+
+
+
+#include "linux/slab.h"
+
+// Dynamic memory allocation alignment routines
+// HP's Tachyon Fibre Channel Controller chips require
+// certain memory queues and register pointers to be aligned
+// on various boundaries, usually the size of the Queue in question.
+// Alignment might be on 2, 4, 8, ... or even 512 byte boundaries.
+// Since most O/Ss don't allow this (usually only Cache aligned -
+// 32-byte boundary), these routines provide generic alignment (after
+// O/S allocation) at any boundary, and store the original allocated
+// pointer for deletion (O/S free function).  Typically, we expect
+// these functions to only be called at HBA initialization and
+// removal time (load and unload times)
+// ALGORITHM notes:
+// Memory allocation varies by compiler and platform.  In the worst case,
+// we are only assured BYTE alignment, but in the best case, we can
+// request allocation on any desired boundary.  Our strategy: pad the
+// allocation request size (i.e. waste memory) so that we are assured
+// of passing desired boundary near beginning of contiguous space, then
+// mask out lower address bits.
+// We define the following algorithm:
+//   allocBoundary - compiler/platform specific address alignment
+//                   in number of bytes (default is single byte; i.e. 1)
+//   n_alloc       - number of bytes application wants @ aligned address
+//   ab            - alignment boundary, in bytes (e.g. 4, 32, ...)
+//   t_alloc       - total allocation needed to ensure desired boundary
+//   mask          - to clear least significant address bits for boundary
+//   Compute:
+//   t_alloc = n_alloc + (ab - allocBoundary)
+//   allocate t_alloc bytes @ alloc_address
+//   mask =  NOT (ab - 1)
+//       (e.g. if ab=32  _0001 1111  -> _1110 0000
+//   aligned_address = alloc_address & mask
+//   set n_alloc bytes to 0
+//   return aligned_address (NULL if failed)
+//
+// If u32_AlignedAddress is non-zero, then search for BaseAddress (stored
+// from previous allocation).  If found, invoke call to FREE the memory.
+// Return NULL if BaseAddress not found
+
+// we need about 8 allocations per HBA.  Figuring at most 10 HBAs per server
+// size the dynamic_mem array at 80.
+
+void* fcMemManager( struct pci_dev *pdev, ALIGNED_MEM *dynamic_mem, 
+		   ULONG n_alloc, ULONG ab, ULONG u32_AlignedAddress,
+			dma_addr_t *dma_handle)
+{
+  USHORT allocBoundary=1;   // compiler specific - worst case 1
+                                  // best case - replace malloc() call
+                                  // with function that allocates exactly
+                                  // at desired boundary
+
+  unsigned long ulAddress;
+  ULONG t_alloc, i;
+  void *alloc_address = 0;  // def. error code / address not found
+  LONG mask;                // must be 32-bits wide!
+
+  ENTER("fcMemManager");
+  if( u32_AlignedAddress )          // are we freeing existing memory?
+  {
+//    printk(" freeing AlignedAddress %Xh\n", u32_AlignedAddress);
+    for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for the base address
+    {
+//    printk("dynamic_mem[%u].AlignedAddress %lX\n", i, dynamic_mem[i].AlignedAddress);
+      if( dynamic_mem[i].AlignedAddress == u32_AlignedAddress )
+      {
+        alloc_address = dynamic_mem[i].BaseAllocated; // 'success' status
+	pci_free_consistent(pdev,dynamic_mem[i].size, 
+				alloc_address, 
+				dynamic_mem[i].dma_handle);
+        dynamic_mem[i].BaseAllocated = 0;   // clear for next use
+        dynamic_mem[i].AlignedAddress = 0;
+        dynamic_mem[i].size = 0;
+        break;                        // quit for loop; done
+      }
+    }
+  }
+  else if( n_alloc )                   // want new memory?
+  {
+    dma_addr_t handle;
+    t_alloc = n_alloc + (ab - allocBoundary); // pad bytes for alignment
+//    printk("pci_alloc_consistent() for Tach alignment: %ld bytes\n", t_alloc);
+
+// (would like to) allow thread block to free pages 
+    alloc_address =                  // total bytes (NumberOfBytes)
+      pci_alloc_consistent(pdev, t_alloc, &handle); 
+
+                                  // now mask off least sig. bits of address
+    if( alloc_address )           // (only if non-NULL)
+    {
+                                  // find place to store ptr, so we
+                                  // can free it later...
+
+      mask = (LONG)(ab - 1);            // mask all low-order bits
+      mask = ~mask;                            // invert bits
+      for( i=0; i<DYNAMIC_ALLOCATIONS; i++) // look for free slot
+      {
+        if( dynamic_mem[i].BaseAllocated == 0) // take 1st available
+        {
+          dynamic_mem[i].BaseAllocated = alloc_address;// address from O/S
+          dynamic_mem[i].dma_handle = handle;
+	  if (dma_handle != NULL) 
+	  {
+//             printk("handle = %p, ab=%d, boundary = %d, mask=0x%08x\n", 
+//			handle, ab, allocBoundary, mask);
+	    *dma_handle = (dma_addr_t) 
+		((((ULONG)handle) + (ab - allocBoundary)) & mask);
+	  }
+          dynamic_mem[i].size = t_alloc;
+          break;
+        }
+      }
+      ulAddress = (unsigned long)alloc_address;
+      
+      ulAddress += (ab - allocBoundary);    // add the alignment bytes-
+                                            // then truncate address...
+      alloc_address = (void*)(ulAddress & mask);
+      
+      dynamic_mem[i].AlignedAddress = 
+	(ULONG)(ulAddress & mask); // 32bit Tach address
+      memset( alloc_address, 0, n_alloc );  // clear new memory
+    }
+    else  // O/S dynamic mem alloc failed!
+      alloc_address = 0;  // (for debugging breakpt)
+
+  }
+
+  LEAVE("fcMemManager");
+  return alloc_address;  // good (or NULL) address
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.detect                 = cpqfcTS_detect,
+	.release                = cpqfcTS_release,
+	.info                   = cpqfcTS_info,
+	.proc_info              = cpqfcTS_proc_info,
+	.ioctl                  = cpqfcTS_ioctl,
+	.queuecommand           = cpqfcTS_queuecommand,
+	.eh_device_reset_handler   = cpqfcTS_eh_device_reset,
+	.eh_abort_handler       = cpqfcTS_eh_abort, 
+	.bios_param             = cpqfcTS_biosparam, 
+	.can_queue              = CPQFCTS_REQ_QUEUE_LEN,
+	.this_id                = -1, 
+	.sg_tablesize           = SG_ALL, 
+	.cmd_per_lun            = CPQFCTS_CMD_PER_LUN,
+	.use_clustering         = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+
diff --git a/drivers/scsi/cpqfcTSioctl.h b/drivers/scsi/cpqfcTSioctl.h
new file mode 100644
index 0000000..8255369
--- /dev/null
+++ b/drivers/scsi/cpqfcTSioctl.h
@@ -0,0 +1,94 @@
+// for user apps, make sure data size types are defined
+// with 
+
+
+#define CCPQFCTS_IOC_MAGIC 'Z'
+
+typedef struct 
+{
+  __u8 bus;
+  __u8 dev_fn;
+  __u32 board_id;
+} cpqfc_pci_info_struct;
+
+typedef __u32 DriverVer_type;
+/*
+typedef union
+{
+  struct  // Peripheral Unit Device
+  { 
+    __u8 Bus:6;
+    __u8 Mode:2;  // b00
+    __u8 Dev;
+  } PeripDev;
+  struct  // Volume Set Address
+  { 
+    __u8 DevMSB:6;
+    __u8 Mode:2;  // b01
+    __u8 DevLSB;
+  } LogDev;
+  struct  // Logical Unit Device (SCSI-3, SCC-2 defined)
+  { 
+    __u8 Targ:6;
+    __u8 Mode:2;  // b10
+    __u8 Dev:5;
+    __u8 Bus:3;
+
+  } LogUnit;
+} SCSI3Addr_struct;
+
+
+typedef struct
+{
+  SCSI3Addr_struct FCP_Nexus;
+  __u8 cdb[16];
+} PassThru_Command_struct;
+*/
+
+/* this is nearly duplicated in idashare.h */
+typedef struct {
+  int	lc;    		/* Controller number */
+  int	node;		/* Node (box) number */
+  int	ld;		/* Logical Drive on this box, if required */
+  __u32 nexus;          /* SCSI Nexus */
+  void	*argp;		/* Argument pointer */
+} VENDOR_IOCTL_REQ;
+
+
+typedef struct {
+  char	cdb[16];	/* SCSI CDB for the pass-through */
+  ushort bus;		/* Target bus on the box */
+  ushort pdrive;	/* Physical drive on the box */
+  int len;              /* Length of the data area of the CDB */
+  int sense_len;	/* Length of the sense data */
+  char sense_data[40];  /* Sense data */
+  void *bufp;		/* Data area for the CDB */
+  char rw_flag;		/* Read CDB or Write CDB */
+} cpqfc_passthru_t;
+
+/*
+** Defines for the IOCTLS.
+*/
+
+#define VENDOR_READ_OPCODE			0x26
+#define VENDOR_WRITE_OPCODE			0x27
+
+#define CPQFCTS_GETPCIINFO _IOR( CCPQFCTS_IOC_MAGIC, 1, cpqfc_pci_info_struct)
+#define CPQFCTS_GETDRIVVER _IOR( CCPQFCTS_IOC_MAGIC, 9, DriverVer_type)
+
+#define CPQFCTS_SCSI_PASSTHRU _IOWR( CCPQFCTS_IOC_MAGIC,11, VENDOR_IOCTL_REQ)
+
+/* We would rather have equivalent generic, low-level driver agnostic 
+ioctls that do what CPQFC_IOCTL_FC_TARGET_ADDRESS and 
+CPQFC_IOCTL_FC_TDR 0x5388 do, but currently, we do not have them, 
+consequently applications would have to know they are talking to cpqfc. */
+   
+/* Used to get Fibre Channel WWN and port_id from device */
+// #define CPQFC_IOCTL_FC_TARGET_ADDRESS 0x5387
+#define CPQFC_IOCTL_FC_TARGET_ADDRESS \
+	_IOR( CCPQFCTS_IOC_MAGIC, 13, Scsi_FCTargAddress)
+
+/* Used to invoke Target Defice Reset for Fibre Channel */
+// #define CPQFC_IOCTL_FC_TDR 0x5388
+#define CPQFC_IOCTL_FC_TDR _IO( CCPQFCTS_IOC_MAGIC, 15)
+
diff --git a/drivers/scsi/cpqfcTSstructs.h b/drivers/scsi/cpqfcTSstructs.h
new file mode 100644
index 0000000..0bae329
--- /dev/null
+++ b/drivers/scsi/cpqfcTSstructs.h
@@ -0,0 +1,1530 @@
+/* Copyright(c) 2000, Compaq Computer Corporation
+ * Fibre Channel Host Bus Adapter 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *  
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+*/
+#ifndef CPQFCTSSTRUCTS_H
+#define CPQFCTSSTRUCTS_H
+
+#include <linux/timer.h>  // timer declaration in our host data
+#include <linux/interrupt.h>
+#include <asm/atomic.h>
+#include "cpqfcTSioctl.h"
+
+#define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
+                         for( wait_time=jiffies + (secs*HZ); \
+		         time_before(jiffies, wait_time) ;) ; }
+
+#define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
+// don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c
+#define VER_MAJOR 2
+#define VER_MINOR 5
+#define VER_SUBMINOR 4
+
+// Macros for kernel (esp. SMP) tracing using a PCI analyzer
+// (e.g. x86).
+//#define PCI_KERNEL_TRACE
+#ifdef PCI_KERNEL_TRACE
+#define PCI_TRACE(x) inl( fcChip->Registers.IOBaseL +x);
+#define PCI_TRACEO(x,y) outl( x, (fcChip->Registers.IOBaseL +y));
+#else
+
+#define PCI_TRACE(x) 
+#define PCI_TRACEO(x,y)
+#endif
+
+			 
+//#define DEBUG_CMND 1   // debug output for Linux Scsi CDBs
+//#define DUMMYCMND_DBG 1
+
+//#define DEBUG_CPQFCTS 1
+//#undef DEBUG_CPQFCTS 
+#ifdef DEBUG_CPQFCTS
+#define ENTER(x)	printk("cpqfcts : entering %s()\n", x);
+#define LEAVE(x)	printk("cpqfcts : leaving %s()\n", x);
+#define DEBUG(x)	x
+#else
+#define ENTER(x)
+#define LEAVE(x)
+#define DEBUG(x)
+#endif				/* DEBUG_CPQFCTS */
+
+//#define DEBUG_CPQFCTS_PCI 1
+//#undef DEBUG_CPQFCTS_PCI
+#if DEBUG_CPQFCTS_PCI
+#define DEBUG_PCI(x)	x
+#else
+#define DEBUG_PCI(x)
+#endif				/* DEBUG_CPQFCTS_PCI */
+
+#define STACHLITE66_TS12  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
+#define STACHLITE66_TS13  "Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
+#define STACHLITE_UNKNOWN "Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
+#define SAGILENT_XL2_21   "Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"
+
+// PDA is Peripheral Device Address, VSA is Volume Set Addressing
+// Linux SCSI parameters
+#define CPQFCTS_MAX_TARGET_ID 64
+
+// Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
+// strange behavior if a box with more than, e.g. 8, is on the loop.
+#define CPQFCTS_MAX_LUN 32    // The RA-4x00 supports 32 (Linux SCSI supports 8)
+#define CPQFCTS_MAX_CHANNEL 0 // One FC port on cpqfcTS HBA
+
+#define CPQFCTS_CMD_PER_LUN 15 // power of 2 -1, must be >0 
+#define CPQFCTS_REQ_QUEUE_LEN (TACH_SEST_LEN/2) // must be < TACH_SEST_LEN
+
+#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
+#ifndef DECLARE_MUTEX_LOCKED
+#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
+#endif
+
+#define DEV_NAME "cpqfcTS"
+
+struct SupportedPCIcards
+{
+  __u16 vendor_id;
+  __u16 device_id;
+};
+			 
+// nn:nn denotes bit field
+                            // TachyonHeader struct def.
+                            // the fields shared with ODB
+                            // need to have same value
+
+
+
+
+#ifndef BYTE
+//typedef UCHAR BYTE;
+typedef __u8 BYTE;
+#endif
+#ifndef UCHAR
+typedef __u8 UCHAR;
+#endif
+#ifndef LONG
+typedef __s32 LONG;
+#endif
+#ifndef ULONG
+typedef __u32 ULONG;
+#endif
+#ifndef PVOID
+typedef void * PVOID;
+#endif
+#ifndef USHORT
+typedef __u16 USHORT;
+#endif
+#ifndef BOOLEAN
+typedef __u8 BOOLEAN;
+#endif
+
+
+// macro for FC-PH reject codes
+// payload format for LS_RJT (FC payloads are big endian):
+//     byte  0         1         2         3  (MSB)
+// DWORD 0   01        00        00        00
+// DWORD 1   resvd     code      expl.     vendor
+
+#define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))
+
+
+#define TachLiteSTATUS 0x12
+
+// Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
+// 32-bit ERROR word defines
+#define INVALID_ARGS 0x1
+#define LNKDWN_OSLS  0x2
+#define LNKDWN_LASER 0x4
+#define OUTQUE_FULL  0x8
+#define DRIVERQ_FULL 0x10
+#define SEST_FULL    0x20
+#define BAD_ALPA     0x40
+#define OVERFLOW     0x80  // inbound CM
+#define COUNT_ERROR     0x100  // inbound CM
+#define LINKFAIL_RX     0x200  // inbound CM
+#define ABORTSEQ_NOTIFY 0x400  // outbound CM
+#define LINKFAIL_TX     0x800  // outbound CM
+#define HOSTPROG_ERR     0x1000  // outbound CM
+#define FRAME_TO         0x2000  // outbound CM
+#define INV_ENTRY        0x4000  // outbound CM
+#define SESTPROG_ERR     0x8000  // outbound CM
+#define OUTBOUND_TIMEOUT 0x10000L // timeout waiting for Tachyon outbound CM
+#define INITIATOR_ABORT  0x20000L // initiator exchange timeout or O/S ABORT
+#define MEMPOOL_FAIL     0x40000L // O/S memory pool allocation failed
+#define FC2_TIMEOUT      0x80000L // driver timeout for lost frames
+#define TARGET_ABORT     0x100000L // ABTS received from FC port
+#define EXCHANGE_QUEUED  0x200000L // e.g. Link State was LDn on fcStart
+#define PORTID_CHANGED   0x400000L // fc Port address changed
+#define DEVICE_REMOVED   0x800000L // fc Port address changed
+// Several error scenarios result in SEST Exchange frames 
+// unexpectedly arriving in the SFQ
+#define SFQ_FRAME        0x1000000L // SFQ frames from open Exchange
+
+// Maximum number of Host Bus Adapters (HBA) / controllers supported
+// only important for mem allocation dimensions - increase as necessary
+
+#define MAX_ADAPTERS 8
+#define MAX_RX_PAYLOAD 1024  // hardware dependent max frame payload
+// Tach header struc defines
+#define SOFi3 0x7
+#define SOFf  0x8
+#define SOFn3 0xB
+#define EOFn  0x5
+#define EOFt  0x6
+
+// FCP R_CTL defines
+#define FCP_CMND 0x6
+#define FCP_XFER_RDY 0x5
+#define FCP_RSP 0x7
+#define FCP_RESPONSE 0x777 // (arbitrary #)
+#define NEED_FCP_RSP 0x77  // (arbitrary #)
+#define FCP_DATA 0x1
+
+#define RESET_TACH 0x100 // Reset Tachyon/TachLite
+#define SCSI_IWE 0x2000  // initiator write entry (for SEST)
+#define SCSI_IRE 0x3000  // initiator read entry (for SEST)
+#define SCSI_TRE 0x400  // target read entry (for SEST)
+#define SCSI_TWE 0x500  // target write entry (for SEST)
+#define TOGGLE_LASER 0x800
+#define LIP 0x900
+#define CLEAR_FCPORTS 99 // (arbitrary #) free mem for Logged in ports
+#define FMINIT 0x707     // (arbitrary) for Frame Manager Init command
+
+// BLS == Basic Link Service
+// ELS == Extended Link Service
+#define BLS_NOP 4
+#define BLS_ABTS 0x10   // FC-PH Basic Link Service Abort Sequence
+#define BLS_ABTS_ACC 0x100  // FC-PH Basic Link Service Abort Sequence Accept
+#define BLS_ABTS_RJT 0x101  // FC-PH Basic Link Service Abort Sequence Reject
+#define ELS_PLOGI 0x03  // FC-PH Port Login (arbitrary assign)
+#define ELS_SCR   0x70  // (arb assign) State Change Registration (Fabric)
+#define FCS_NSR   0x72  // (arb assign) Name Service Request (Fabric)
+#define ELS_FLOGI 0x44  // (arb assign) Fabric Login
+#define ELS_FDISC 0x41  // (arb assign) Fabric Discovery (Login)
+#define ELS_PDISC 0x50  // FC-PH2 Port Discovery
+#define ELS_ABTX  0x06  // FC-PH Abort Exchange 
+#define ELS_LOGO 0x05   // FC-PH Port Logout
+#define ELS_PRLI 0x20   // FCP-SCSI Process Login
+#define ELS_PRLO 0x21   // FCP-SCSI Process Logout
+#define ELS_LOGO_ACC 0x07   // {FC-PH} Port Logout Accept
+#define ELS_PLOGI_ACC 0x08  // {FC-PH} Port Login Accept
+#define ELS_ACC 0x18        // {FC-PH} (generic) ACCept
+#define ELS_PRLI_ACC 0x22  // {FCP-SCSI} Process Login Accept
+#define ELS_RJT 0x1000000
+#define SCSI_REPORT_LUNS 0x0A0
+#define FCP_TARGET_RESET 0x200
+
+#define ELS_LILP_FRAME 0x00000711 // 1st payload word of LILP frame
+
+#define SFQ_UNASSISTED_FCP  1  // ICM, DWord3, "Type" unassisted FCP
+#define SFQ_UNKNOWN         0x31 // (arbitrary) ICM, DWord3, "Type" unknown
+
+// these "LINK" bits refer to loop or non-loop
+#define LINKACTIVE 0x2    // fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
+#define LINKDOWN 0xf2     // fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set
+
+//#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1
+
+typedef struct      // 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
+{
+  ULONG reserved;   // dword 0 (don't use)
+  ULONG sof_eof;
+  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
+  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
+  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
+  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
+  ULONG ro;         // dword 7 - relative offset
+} TachFCHDR;
+
+                    // NOTE!! the following struct MUST be 64 bytes.
+typedef struct      // 32 bytes hdr + 32 bytes payload
+{
+  ULONG reserved;   // dword 0 (don't use - must clear to 0)
+  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
+  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
+  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
+  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
+  ULONG ro;  // dword 7 - relative offset
+//---------
+  __u32 pl[8];              // dwords 8-15 frame data payload
+} TachFCHDR_CMND;
+
+
+typedef struct      // 32 bytes hdr + 120 bytes payload
+{
+  ULONG reserved;   // dword 0 (don't use - must clear to 0)
+  ULONG sof_eof;    // dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
+  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
+  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
+  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
+  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
+  ULONG ro;  // dword 7 - relative offset
+//---------
+  __u32 pl[30];              // largest necessary payload (for LOGIN cmnds)
+} TachFCHDR_GCMND;
+
+typedef struct      // 32 bytes hdr + 64 bytes payload
+{
+  ULONG reserved;   // dword 0 (don't use)
+  ULONG sof_eof;
+  ULONG d_id;       // dword 2 - 31:24 R_CTL, 23:0 D_ID
+  ULONG s_id;       // dword 3 - 31:24 CS_CTL, 23:0 S_ID
+  ULONG f_ctl;      // dword 4 - 31:24 Type,  23:0 F_CTL
+  ULONG seq_cnt;    // dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
+  ULONG ox_rx_id;   // dword 6 - 31:16 OX_ID,  15:0 RX_ID
+  ULONG ro;  // dword 7 - relative offset
+//---------
+  __u32 pl[18]; // payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
+} TachFCHDR_RSP;
+
+
+
+
+
+
+// Inbound Message Queue structures...
+typedef struct              // each entry 8 words (32 bytes)
+{
+  ULONG type;               // IMQ completion message types
+  ULONG word[7];            // remainder of structure
+                            // interpreted by IMQ type
+} TachyonIMQE;
+
+
+// Queues for TachLite not in original Tachyon
+// ERQ       - Exchange Request Queue (for outbound commands)
+// SFQ       - Single Frame Queue (for incoming frames)
+
+                            // Define Tachyon Outbound Command Que
+                            // (Since many Tachyon registers are Read
+                            // only, maintain copies for debugging)
+                            // most Tach ques need power-of-2 sizes,
+                            // where registers are loaded with po2 -1
+#define TACH_SEST_LEN 512   // TachLite SEST
+
+#define ELS_EXCHANGES 64    // e.g. PLOGI, RSCN, ...
+// define the total number of outstanding (simultaneous) exchanges
+#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)  // ELS exchanges
+
+#define ERQ_LEN 128         // power of 2, max 4096
+
+// Inbound Message Queue structures...
+#define IMQ_LEN 512              // minimum 4 entries [(power of 2) - 1]
+typedef struct                   // 8 words - 32 bytes
+{
+  TachyonIMQE QEntry[IMQ_LEN];
+  ULONG producerIndex;   // IMQ Producer Index register
+                                 // @32 byte align
+  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
+  ULONG length;          // Length register
+  ULONG base;
+} TachyonIMQ;                    // @ 32 * IMQ_LEN align
+
+
+
+typedef struct           // inbound completion message
+{
+  ULONG Type;
+  ULONG Index;
+  ULONG TransferLength;
+} TachyonInbCM;
+
+
+
+// arbitrary numeric tags for TL structures
+#define TL_FCHS 1  // TachLite Fibre Channel Header Structure
+#define TL_IWE 2  // initiator write entry (for SEST)
+#define TL_TWE 3  // target write entry (for SEST)
+#define TL_IRE 4  // initiator read entry (for SEST)
+#define TL_TRE 5  // target read entry (for SEST)
+#define TL_IRB 6  // I/O request block
+
+                                // for INCOMING frames
+#define SFQ_LEN 32              // minimum 32 entries, max 4096
+
+typedef struct                  // Single Frame Que
+{
+  TachFCHDR_CMND QEntry[SFQ_LEN]; // must be 64 bytes!!
+  ULONG producerIndex;   // IMQ Producer Index register
+                                 // @32 byte align
+  ULONG consumerIndex;   // Consumer Index register (in Tachyon)
+  ULONG length;          // Length register
+  ULONG base;
+} TachLiteSFQ;
+
+
+typedef struct                 // I/O Request Block flags
+{
+  UCHAR  BRD : 1;
+  UCHAR      : 1; // reserved
+  UCHAR  SFA : 1;
+  UCHAR  DNC : 1;
+  UCHAR  DIN : 1;
+  UCHAR  DCM : 1;
+  UCHAR  CTS : 1;
+  UCHAR  SBV : 1;  // IRB entry valid - IRB'B' only
+} IRBflags;
+
+typedef struct                  // I/O Request Block
+{                          // Request 'A'
+  ULONG Req_A_SFS_Len;     // total frame len (hdr + payload), min 32
+  ULONG Req_A_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
+  ULONG Req_A_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
+  ULONG Req_A_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
+                           // Request 'B'
+  ULONG Req_B_SFS_Len;     // total frame len (hdr + payload), min 32
+  ULONG Req_B_SFS_Addr;    // 32-bit pointer to FCHS struct (to be sent)
+  ULONG Req_B_SFS_D_ID;    // 24-bit FC destination (i.e. 8 bit al_pa)
+  ULONG Req_B_Trans_ID;    // X_ID (OX_ID or RX_ID) and/or Index in SEST
+} TachLiteIRB;
+
+
+typedef struct           // TachLite placeholder for IRBs
+{                        // aligned @sizeof(ERQ) for TachLite
+                         // MAX commands is sum of SEST len and ERQ
+                         // we know that each SEST entry requires an
+                         // IRB (ERQ) entry; in addition, we provide
+                         // ERQ_LEN
+  TachLiteIRB QEntry[ERQ_LEN]; // Base register; entries 32 bytes ea.
+  ULONG consumerIndex;   // Consumer Index register
+  ULONG producerIndex;   // ERQ Producer Index register
+  ULONG length;          // Length register
+  ULONG base;            // copy of base ptr for debug
+                         // struct is sized for largest expected cmnd (LOGIN)
+} TachLiteERQ;
+
+// for now, just 32 bit DMA, eventually 40something, with code changes
+#define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))
+
+#define TL_MAX_SG_ELEM_LEN 0x7ffff  // Max buffer length a single S/G entry
+				// may represent (a hardware limitation).  The
+				// only reason to ever change this is if you
+				// want to exercise very-hard-to-reach code in
+				// cpqfcTSworker.c:build_SEST_sglist().
+
+#define TL_DANGER_SGPAGES 7  // arbitrary high water mark for # of S/G pages
+				// we must exceed to elicit a warning indicative
+				// of EXTREMELY large data transfers or 
+				// EXTREME memory fragmentation.
+				// (means we just used up 2048 S/G elements,
+				// Never seen this is real life, only in 
+				// testing with tricked up driver.)
+
+#define TL_EXT_SG_PAGE_COUNT 256  // Number of Extended Scatter/Gather a/l PAIRS
+                                  // Tachyon register (IOBaseU 0x68)
+                                  // power-of-2 value ONLY!  4 min, 256 max
+
+                          // byte len is #Pairs * 2 ULONG/Pair * 4 bytes/ULONG
+#define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)
+
+
+
+// SEST entry types: IWE, IRE, TWE, TRE
+typedef struct 
+{
+  ULONG Hdr_Len;
+  ULONG Hdr_Addr;
+  ULONG RSP_Len;
+  ULONG RSP_Addr;
+  ULONG Buff_Off;
+#define USES_EXTENDED_SGLIST(this_sest, x_ID) \
+	(!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
+  ULONG Link;
+  ULONG RX_ID;
+  ULONG Data_Len;
+  ULONG Exp_RO;
+  ULONG Exp_Byte_Cnt;
+   // --- extended/local Gather Len/Address pairs
+  ULONG GLen1;
+  ULONG GAddr1;
+  ULONG GLen2;
+  ULONG GAddr2;
+  ULONG GLen3;
+  ULONG GAddr3;
+} TachLiteIWE;
+
+
+typedef struct 
+{
+  ULONG Seq_Accum;
+  ULONG reserved;       // must clear to 0
+  ULONG RSP_Len;
+  ULONG RSP_Addr;
+  ULONG Buff_Off;
+  ULONG Buff_Index;           // ULONG 5
+  ULONG Exp_RO;
+  ULONG Byte_Count;
+  ULONG reserved_;      // ULONG 8
+  ULONG Exp_Byte_Cnt;
+   // --- extended/local Scatter Len/Address pairs
+  ULONG SLen1;
+  ULONG SAddr1;
+  ULONG SLen2;
+  ULONG SAddr2;
+  ULONG SLen3;
+  ULONG SAddr3;
+} TachLiteIRE;
+
+
+typedef struct          // Target Write Entry
+{
+  ULONG Seq_Accum;      // dword 0
+  ULONG reserved;       // dword 1  must clear to 0
+  ULONG Remote_Node_ID;
+  ULONG reserved1;      // dword 3  must clear to 0
+  ULONG Buff_Off;
+  ULONG Buff_Index;     // ULONG 5
+  ULONG Exp_RO;
+  ULONG Byte_Count;
+  ULONG reserved_;      // ULONG 8
+  ULONG Exp_Byte_Cnt;
+   // --- extended/local Scatter Len/Address pairs
+  ULONG SLen1;
+  ULONG SAddr1;
+  ULONG SLen2;
+  ULONG SAddr2;
+  ULONG SLen3;
+  ULONG SAddr3;
+} TachLiteTWE;
+
+typedef struct      
+{
+  ULONG Hdr_Len;
+  ULONG Hdr_Addr;
+  ULONG RSP_Len;        // DWord 2
+  ULONG RSP_Addr;
+  ULONG Buff_Off;
+  ULONG Buff_Index;     // DWord 5
+  ULONG reserved;
+  ULONG Data_Len;
+  ULONG reserved_;
+  ULONG reserved__;
+   // --- extended/local Gather Len/Address pairs
+  ULONG GLen1;          // DWord A
+  ULONG GAddr1;
+  ULONG GLen2;
+  ULONG GAddr2;
+  ULONG GLen3;
+  ULONG GAddr3;
+} TachLiteTRE;
+
+typedef struct ext_sg_page_ptr_t *PSGPAGES;
+typedef struct ext_sg_page_ptr_t 
+{
+  unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2]; // 2x for alignment
+  dma_addr_t busaddr; 	// need the bus addresses and
+  unsigned int maplen;  // lengths for later pci unmapping.
+  PSGPAGES next;
+} SGPAGES; // linked list of S/G pairs, by Exchange
+
+typedef struct                  // SCSI Exchange State Table
+{
+  union                         // Entry can be IWE, IRE, TWE, TRE
+  {                             // 64 bytes per entry
+    TachLiteIWE IWE;
+    TachLiteIRE IRE;
+    TachLiteTWE TWE;
+    TachLiteTRE TRE;
+  } u[TACH_SEST_LEN];
+
+  TachFCHDR DataHDR[TACH_SEST_LEN]; // for SEST FCP_DATA frame hdr (no pl)
+  TachFCHDR_RSP RspHDR[TACH_SEST_LEN]; // space for SEST FCP_RSP frame
+  PSGPAGES sgPages[TACH_SEST_LEN]; // head of linked list of Pool-allocations
+  ULONG length;          // Length register
+  ULONG base;            // copy of base ptr for debug
+} TachSEST;
+
+
+
+typedef struct                  // each register has it's own address
+                                // and value (used for write-only regs)
+{
+  void* address;
+  volatile ULONG value;
+} FCREGISTER;
+
+typedef struct         // Host copy - TachLite Registers
+{
+  ULONG IOBaseL, IOBaseU;  // I/O port lower and upper TL register addresses
+  ULONG MemBase;           // memory mapped register addresses
+  void* ReMapMemBase;      // O/S VM reference for MemBase
+  ULONG wwn_hi;            // WWN is set once at startup
+  ULONG wwn_lo;
+  ULONG my_al_pa;          // al_pa received after LIP()
+  ULONG ROMCTR;            // flags for on-board RAM/ROM
+  ULONG RAMBase;           // on-board RAM (i.e. some Tachlites)
+  ULONG SROMBase;          // on-board EEPROM (some Tachlites)
+  ULONG PCIMCTR;           // PCI Master Control Reg (has bus width)
+
+  FCREGISTER INTEN;        // copy of interrupt enable mask
+  FCREGISTER INTPEND;      // interrupt pending
+  FCREGISTER INTSTAT;      // interrupt status
+  FCREGISTER SFQconsumerIndex; 
+  FCREGISTER ERQproducerIndex; 
+  FCREGISTER TYconfig;   // TachYon (chip level)
+  FCREGISTER TYcontrol;
+  FCREGISTER TYstatus;
+  FCREGISTER FMconfig;   // Frame Manager (FC loop level)
+  FCREGISTER FMcontrol;
+  FCREGISTER FMstatus;
+  FCREGISTER FMLinkStatus1;
+  FCREGISTER FMLinkStatus2;
+  FCREGISTER FMBB_CreditZero;
+  FCREGISTER status;
+  FCREGISTER ed_tov;     // error detect time-out value
+  FCREGISTER rcv_al_pa;  // received arb. loop physical address
+  FCREGISTER primitive;  // e.g. LIP(), OPN(), ...
+} TL_REGISTERS;
+
+
+
+typedef struct 
+{
+  ULONG ok;
+  ULONG invalidArgs;
+  ULONG linkDown;
+  ULONG linkUp;
+  ULONG outQueFull;
+  ULONG SESTFull;
+  ULONG hpe;    // host programming err (from Tach)
+  ULONG FC4aborted; // aborts from Application or upper driver layer
+  ULONG FC2aborted; // aborts from our driver's timeouts
+  ULONG timeouts;   // our driver timeout (on individual exchanges)
+  ULONG logouts;    // explicit - sent LOGO; implicit - device removed
+  ULONG retries;
+  ULONG linkFailTX;
+  ULONG linkFailRX;
+  ULONG CntErrors;  // byte count expected != count received (typ. SEST)
+  ULONG e_stores;   // elastic store errs
+  ULONG resets;     // hard or soft controller resets
+  ULONG FMinits;    // TACH Frame Manager Init (e.g. LIPs)
+  ULONG lnkQueFull;  // too many LOGIN, loop commands
+  ULONG ScsiQueFull; // too many FCP-SCSI inbound frames
+  ULONG LossofSignal;   // FM link status 1 regs
+  ULONG BadRXChar;   // FM link status 1 regs
+  ULONG LossofSync;   // FM link status 1 regs
+  ULONG Rx_EOFa;   // FM link status 2 regs (received EOFa)
+  ULONG Dis_Frm;   // FM link status 2 regs (discarded frames)
+  ULONG Bad_CRC;   // FM link status 2 regs
+  ULONG BB0_Timer; //  FM BB_Credit Zero Timer Reg
+  ULONG loopBreaks; // infinite loop exits
+  ULONG lastBB0timer;  // static accum. buffer needed by Tachlite
+} FCSTATS;
+
+
+typedef struct               // Config Options
+{                            // LS Bit first
+  USHORT        : 1;           // bit0:
+  USHORT  flogi : 1;           // bit1: We sent FLOGI - wait for Fabric logins
+  USHORT  fabric: 1;           // bit2: Tachyon detected Fabric (FM stat LG)
+  USHORT  LILPin: 1;           // bit3: We can use an FC-AL LILP frame
+  USHORT  target: 1;           // bit4: this Port has SCSI target capability
+  USHORT  initiator:    1;     // bit5: this Port has SCSI initiator capability
+  USHORT  extLoopback:  1;     // bit6: loopback at GBIC
+  USHORT  intLoopback:  1;     // bit7: loopback in HP silicon
+  USHORT        : 1;           // bit8:
+  USHORT        : 1;           // bit9:
+  USHORT        : 1;           // bit10:
+  USHORT        : 1;           // bit11:
+  USHORT        : 1;           // bit12:
+  USHORT        : 1;           // bit13:
+  USHORT        : 1;           // bit14:
+  USHORT        : 1;           // bit15:
+} FC_OPTIONS;
+
+
+
+typedef struct dyn_mem_pair
+{
+  void *BaseAllocated;  // address as allocated from O/S;
+  unsigned long AlignedAddress; // aligned address (used by Tachyon DMA)
+  dma_addr_t dma_handle;
+  size_t size;
+} ALIGNED_MEM;
+
+
+
+
+// these structs contain only CRUCIAL (stuff we actually use) parameters
+// from FC-PH(n) logins.  (Don't save entire LOGIN payload to save mem.)
+
+// Implicit logout happens when the loop goes down - we require PDISC
+// to restore.  Explicit logout is when WE decide never to talk to someone,
+// or when a target refuses to talk to us, i.e. sends us a LOGO frame or
+// LS_RJT reject in response to our PLOGI request.
+
+#define IMPLICIT_LOGOUT 1
+#define EXPLICIT_LOGOUT 2
+
+typedef struct 
+{
+  UCHAR channel; // SCSI "bus"
+  UCHAR target;
+  UCHAR InqDeviceType;  // byte 0 from SCSI Inquiry response
+  UCHAR VolumeSetAddressing;  // FCP-SCSI LUN coding (40h for VSA)
+  UCHAR LunMasking;     // True if selective presentation supported
+  UCHAR lun[CPQFCTS_MAX_LUN];
+} SCSI_NEXUS;
+
+
+typedef struct        
+{
+  union 
+  {
+    UCHAR ucWWN[8];  // a FC 64-bit World Wide Name/ PortID of target
+                     // addressing of single target on single loop...
+    u64 liWWN;
+  } u;
+
+  ULONG port_id;     // a FC 24-bit address of port (lower 8 bits = al_pa)
+
+#define REPORT_LUNS_PL 256  
+  UCHAR ReportLunsPayload[REPORT_LUNS_PL];
+  
+  SCSI_NEXUS ScsiNexus; // LUNs per FC device
+
+  ULONG LOGO_counter; // might try several times before logging out for good
+  ULONG LOGO_timer;   // after LIP, ports expecting PDISC must time-out and
+                      // LOGOut if successful PDISC not completed in 2 secs
+
+  ULONG concurrent_seq;  // must be 1 or greater
+  ULONG rx_data_size;    // e.g. 128, 256, 1024, 2048 per FC-PH spec
+  ULONG BB_credit;
+  ULONG EE_credit;
+
+  ULONG fcp_info;        // from PRLI (i.e. INITIATOR/ TARGET flags)
+                         // flags for login process
+  BOOLEAN Originator;    // Login sequence Originated (if false, we
+                         // responded to another port's login sequence)
+  BOOLEAN plogi;         // PLOGI frame ACCepted (originated or responded)
+  BOOLEAN pdisc;         // PDISC frame was ORIGINATED (self-login logic)
+  BOOLEAN prli;          // PRLI frame ACCepted (originated or responded)
+  BOOLEAN flogi;         // FLOGI frame ACCepted (originated or responded)
+  BOOLEAN logo;          // port permanently logged out (invalid login param)
+  BOOLEAN flogiReq;      // Fabric login required (set in LIP process)
+  UCHAR highest_ver;
+  UCHAR lowest_ver;
+
+  
+  // when the "target" (actually FC Port) is waiting for login
+  // (e.g. after Link reset), set the device_blocked bit;
+  // after Port completes login, un-block target.
+  UCHAR device_blocked; // see Scsi_Device struct
+
+                    // define singly-linked list of logged-in ports
+                    // once a port_id is identified, it is remembered,
+                    // even if the port is removed indefinitely
+  PVOID pNextPort;  // actually, type PFC_LOGGEDIN_PORT; void for Compiler
+
+} FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;
+
+
+
+// This serves as the ESB (Exchange Status Block),
+// and has timeout counter; used for ABORTs
+typedef struct                
+{                                  // FC-1 X_IDs
+  ULONG type;            // ELS_PLOGI, SCSI_IWE, ... (0 if free)
+  PFC_LOGGEDIN_PORT pLoggedInPort; // FC device on other end of Exchange
+  Scsi_Cmnd *Cmnd;       // Linux SCSI command packet includes S/G list
+  ULONG timeOut;         // units of ??, DEC by driver, Abort when 0
+  ULONG reTries;         // need one or more retries?
+  ULONG status;          // flags indicating errors (0 if none)
+  TachLiteIRB IRB;       // I/O Request Block, gets copied to ERQ
+  TachFCHDR_GCMND fchs;  // location of IRB's Req_A_SFS_Addr
+} FC_EXCHANGE, *PFC_EXCHANGE;
+
+// Unfortunately, Linux limits our kmalloc() allocations to 128k.
+// Because of this and the fact that our ScsiRegister allocation
+// is also constrained, we move this large structure out for
+// allocation after Scsi Register.
+// (In other words, this cumbersome indirection is necessary
+// because of kernel memory allocation constraints!)
+
+typedef struct // we will allocate this dynamically
+{
+  FC_EXCHANGE fcExchange[ TACH_MAX_XID ];
+} FC_EXCHANGES;
+
+
+
+
+
+
+
+
+
+
+
+typedef struct
+{
+  char Name[64]; // name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
+  //PVOID  pAdapterDevExt; // back pointer to device object/extension
+  ULONG ChipType;        // local numeric key for Tachyon Type / Rev.
+  ULONG status;              // our Driver - logical status
+  
+  TL_REGISTERS Registers;    // reg addresses & host memory copies
+                             // FC-4 mapping of 'transaction' to X_IDs
+  UCHAR LILPmap[32*4];       // Loop Position Map of ALPAs (late FC-AL only)
+  FC_OPTIONS Options;        // e.g. Target, Initiator, loopback...
+  UCHAR highest_FCPH_ver;    // FC-PH version limits
+  UCHAR lowest_FCPH_ver;     // FC-PH version limits
+
+  FC_EXCHANGES *Exchanges;  
+  ULONG fcLsExchangeLRU;       // Least Recently Used counter (Link Service)
+  ULONG fcSestExchangeLRU;       // Least Recently Used counter (FCP-SCSI)
+  FC_LOGGEDIN_PORT fcPorts;  // linked list of every FC port ever seen
+  FCSTATS fcStats;           // FC comm err counters
+
+                             // Host memory QUEUE pointers
+  TachLiteERQ *ERQ;          // Exchange Request Que 
+  TachyonIMQ *IMQ;           // Inbound Message Que 
+  TachLiteSFQ *SFQ;          // Single Frame Queue
+  TachSEST *SEST;            // SCSI Exchange State Table
+
+  dma_addr_t exch_dma_handle;
+
+  // these function pointers are for "generic" functions, which are
+  // replaced with Host Bus Adapter types at
+  // runtime.
+  int (*CreateTachyonQues)( void* , int);
+  int (*DestroyTachyonQues)( void* , int);
+  int (*LaserControl)(void*, int );   // e.g. On/Off
+  int (*ResetTachyon)(void*, int );
+  void (*FreezeTachyon)(void*, int );
+  void (*UnFreezeTachyon)(void*, int );
+  int (*InitializeTachyon)(void*, int, int );
+  int (*InitializeFrameManager)(void*, int );
+  int (*ProcessIMQEntry)(void*);
+  int (*ReadWriteWWN)(void*, int ReadWrite);
+  int (*ReadWriteNVRAM)(void*, void*, int ReadWrite);
+
+} TACHYON, *PTACHYON;
+
+
+void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);
+
+int CpqTsCreateTachLiteQues( void* pHBA, int opcode);
+int CpqTsDestroyTachLiteQues( void* , int);
+int CpqTsInitializeTachLite( void *pHBA, int opcode1, int opcode2);
+
+int CpqTsProcessIMQEntry(void* pHBA);
+int CpqTsResetTachLite(void *pHBA, int type);
+void CpqTsFreezeTachlite(void *pHBA, int type);
+void CpqTsUnFreezeTachlite(void *pHBA, int type);
+int CpqTsInitializeFrameManager(void *pHBA, int);
+int CpqTsLaserControl( void* addrBase, int opcode );
+int CpqTsReadWriteWWN(void*, int ReadWrite);
+int CpqTsReadWriteNVRAM(void*, void* data, int ReadWrite);
+
+void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter);
+void cpqfcTSWorkerThread( void *host);
+
+int cpqfcTS_GetNVRAM_data( UCHAR *wwnbuf, UCHAR *buf );
+ULONG cpqfcTS_ReadNVRAM( void* GPIOin, void* GPIOout , USHORT count,
+	UCHAR *buf );
+
+BOOLEAN tl_write_i2c_nvram( void* GPIOin, void* GPIOout,
+  USHORT startOffset,  // e.g. 0x2f for WWN start
+  USHORT count,
+  UCHAR *buf );
+
+
+// define misc functions 
+int cpqfcTSGetLPSM( PTACHYON fcChip, char cErrorString[]);
+int cpqfcTSDecodeGBICtype( PTACHYON fcChip, char cErrorString[]);
+void* fcMemManager( struct pci_dev *pdev,
+		ALIGNED_MEM *dyn_mem_pair, ULONG n_alloc, ULONG ab,
+                   ULONG ulAlignedAddress, dma_addr_t *dma_handle);
+
+void BigEndianSwap(  UCHAR *source, UCHAR *dest,  USHORT cnt);
+
+//ULONG virt_to_phys( PVOID virtaddr );
+                  
+
+// Linux interrupt handler
+irqreturn_t cpqfcTS_intr_handler( int irq,void *dev_id,struct pt_regs *regs);
+void cpqfcTSheartbeat( unsigned long ptr );
+
+
+
+// The biggest Q element we deal with is Aborts - we
+// need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
+//#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
+#define LINKQ_ITEM_SIZE (3*16)
+typedef struct
+{
+  ULONG Type;              // e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
+  ULONG ulBuff[ LINKQ_ITEM_SIZE ];
+} LINKQ_ITEM;
+
+#define FC_LINKQ_DEPTH TACH_MAX_XID
+typedef struct
+{
+  ULONG producer;
+  ULONG consumer;  // when producer equals consumer, Q empty
+
+  LINKQ_ITEM Qitem[ FC_LINKQ_DEPTH ];
+
+} FC_LINK_QUE, *PFC_LINK_QUE;
+
+
+     // DPC routines post to here on Inbound SCSI frames
+     // User thread processes
+#define FC_SCSIQ_DEPTH 32
+
+typedef struct
+{
+  int Type;              // e.g. SCSI
+  ULONG ulBuff[ 3*16 ];
+} SCSIQ_ITEM;
+
+typedef struct
+{
+  ULONG producer;
+  ULONG consumer;  // when producer equals consumer, Q empty
+
+  SCSIQ_ITEM Qitem[ FC_SCSIQ_DEPTH ];
+
+} FC_SCSI_QUE, *PFC_SCSI_QUE;
+
+typedef struct {
+	/* This is tacked on to a Scsi_Request in upper_private_data 
+	   for pasthrough ioctls, as a place to hold data that can't 
+	   be stashed anywhere else in the Scsi_Request.  We differentiate
+	   this from _real_ upper_private_data by checking if the virt addr
+	   is within our special pool.  */
+	ushort bus;
+	ushort pdrive;
+} cpqfc_passthru_private_t;
+
+#define CPQFC_MAX_PASSTHRU_CMDS 100
+
+#define DYNAMIC_ALLOCATIONS 4  // Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST
+
+// Linux space allocated per HBA (chip state, etc.)
+typedef struct 
+{
+  struct Scsi_Host *HostAdapter; // back pointer to Linux Scsi struct
+
+  TACHYON fcChip;    // All Tachyon registers, Queues, functions
+  ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];
+
+  struct pci_dev *PciDev;
+  dma_addr_t fcLQ_dma_handle;
+
+  Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN]; // collects Cmnds during LDn
+                                                // (for Acceptable targets)
+  Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN]; // SEST was full
+  
+  Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID]; // missing targets
+
+  u_char HBAnum;     // 0-based host number
+
+
+  struct timer_list cpqfcTStimer; // FC utility timer for implicit
+                                  // logouts, FC protocol timeouts, etc.
+  int fcStatsTime;  // Statistics delta reporting time
+
+  struct task_struct *worker_thread; // our kernel thread
+  int PortDiscDone;    // set by SendLogins(), cleared by LDn
+  
+  struct semaphore *TachFrozen;
+  struct semaphore *TYOBcomplete;    // handshake for Tach outbound frames
+  struct semaphore *fcQueReady;      // FibreChannel work for our kernel thread
+  struct semaphore *notify_wt;       // synchronizes kernel thread kill
+  struct semaphore *BoardLock;
+  
+  PFC_LINK_QUE fcLQ;             // the WorkerThread operates on this
+
+  spinlock_t hba_spinlock;           // held/released by WorkerThread
+  cpqfc_passthru_private_t *private_data_pool;
+  unsigned long *private_data_bits;
+
+} CPQFCHBA;
+
+#define	CPQ_SPINLOCK_HBA( x )   spin_lock(&x->hba_spinlock);
+#define CPQ_SPINUNLOCK_HBA(x)   spin_unlock(&x->hba_spinlock);
+
+
+
+void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
+		PFC_LOGGEDIN_PORT pFcPort);
+
+
+void cpqfcTSTerminateExchange( CPQFCHBA*, SCSI_NEXUS *target, int );
+
+PFC_LOGGEDIN_PORT fcPortLoggedIn( 
+   CPQFCHBA *cpqfcHBAdata, 
+   TachFCHDR_GCMND* fchs, 
+   BOOLEAN, 
+   BOOLEAN);
+void fcProcessLoggedIn( 
+   CPQFCHBA *cpqfcHBAdata, TachFCHDR_GCMND* fchs);
+
+
+ULONG cpqfcTSBuildExchange( 
+  CPQFCHBA *cpqfcHBAdata,
+  ULONG type, // e.g. PLOGI
+  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
+  void *Data,               // the CDB, scatter/gather, etc.  
+  LONG *ExchangeID );       // allocated exchange ID
+
+ULONG cpqfcTSStartExchange( 
+  CPQFCHBA *cpqfcHBAdata,
+  LONG ExchangeID );
+
+void cpqfcTSCompleteExchange( 
+       struct pci_dev *pcidev,
+       PTACHYON fcChip, 
+       ULONG exchange_ID);
+
+
+PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
+  PTACHYON fcChip, 
+  Scsi_Cmnd *Cmnd,  // (We want the channel/target/lun Nexus from Cmnd)
+  ULONG port_id,  // search linked list for al_pa, or
+  UCHAR wwn[8],    // search linked list for WWN, or...
+  PFC_LOGGEDIN_PORT *pLastLoggedInPort
+);
+
+void cpqfcTSPutLinkQue( 
+  CPQFCHBA *cpqfcHBAdata, 
+  int Type, 
+  void *QueContent);
+
+void fcPutScsiQue( 
+  CPQFCHBA *cpqfcHBAdata, 
+  int Type, 
+  void *QueContent);
+
+void fcLinkQReset(
+   CPQFCHBA *);
+void fcScsiQReset(
+   CPQFCHBA *);
+void fcSestReset(
+   CPQFCHBA *);
+
+void cpqfc_pci_unmap(struct pci_dev *pcidev, 
+	Scsi_Cmnd *cmd, 
+	PTACHYON fcChip, 
+	ULONG x_ID);
+
+extern const UCHAR valid_al_pa[];
+extern const int number_of_al_pa;
+
+#define FCP_RESID_UNDER   0x80000
+#define FCP_RESID_OVER    0x40000
+#define FCP_SNS_LEN_VALID 0x20000
+#define FCP_RSP_LEN_VALID 0x10000
+
+// RSP_CODE definitions (dpANS Fibre Channel Protocol for SCSI, pg 34)
+#define FCP_DATA_LEN_NOT_BURST_LEN 0x1000000
+#define FCP_CMND_FIELD_INVALID     0x2000000
+#define FCP_DATA_RO_NOT_XRDY_RO    0x3000000
+#define FCP_TASKFUNCTION_NS        0x4000000
+#define FCP_TASKFUNCTION_FAIL      0x5000000
+
+// FCP-SCSI response status struct
+typedef struct  // see "TachFCHDR_RSP" definition - 64 bytes
+{
+  __u32 reserved;
+  __u32 reserved1;
+  __u32 fcp_status;    // field validity and SCSI status
+  __u32 fcp_resid;
+  __u32 fcp_sns_len;   // length of FCP_SNS_INFO field
+  __u32 fcp_rsp_len;   // length of FCP_RSP_INFO field (expect 8)
+  __u32 fcp_rsp_info;  // 4 bytes of FCP protocol response information
+  __u32 fcp_rsp_info2; // (4 more bytes, since most implementations use 8)
+  __u8  fcp_sns_info[36]; // bytes for SCSI sense (ASC, ASCQ)
+
+} FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;
+
+
+// Fabric State Change Registration
+typedef struct scrpl
+{
+  __u32 command;
+  __u32 function;
+} SCR_PL;
+
+// Fabric Name Service Request
+typedef struct nsrpl
+{
+  __u32 CT_Rev;  // (& IN_ID)   WORD 0
+  __u32 FCS_Type;            // WORD 1
+  __u32 Command_code;        // WORD 2
+  __u32 reason_code;         // WORD 3
+  __u32 FCP;                 // WORD 4 (lower byte)
+  
+} NSR_PL;
+
+
+
+// "FC.H"
+#define MAX_RX_SIZE		0x800	// Max Receive Buffer Size is 2048
+#define MIN_RX_SIZE		0x100	// Min Size is 256, per FC-PLDA Spec
+#define	MAX_TARGET_RXIDS	SEST_DEPTH
+#define TARGET_RX_SIZE		SEST_BUFFER_LENGTH
+
+#define CLASS_1			0x01
+#define CLASS_2			0x02
+#define CLASS_3			0x03
+
+#define FC_PH42			0x08
+#define FC_PH43			0x09
+#define FC_PH3			0x20
+
+#define RR_TOV			2	// Minimum Time for target to wait for
+					// PDISC after a LIP.
+#define E_D_TOV			2	// Minimum Time to wait for Sequence
+					// Completion.
+#define R_A_TOV			0	// Minimum Time for Target to wait 
+					// before reclaiming resources.
+//
+//	R_CTL Field
+//
+//	Routing Bits (31-28)
+//
+#define FC4_DEVICE_DATA		0x00000000
+#define EXT_LINK_DATA		0x20000000
+#define FC4_LINK_DATA		0x30000000
+#define VIDEO_DATA		0x40000000
+#define BASIC_LINK_DATA		0x80000000
+#define LINK_CONTROL		0xC0000000
+#define ROUTING_MASK		0xF0000000
+
+//
+//	Information Bits (27-24)
+//
+#define UNCAT_INFORMATION	0x00000000
+#define SOLICITED_DATA		0x01000000
+#define UNSOLICITED_CONTROL	0x02000000
+#define SOLICITED_CONTROL	0x03000000
+#define UNSOLICITED_DATA	0x04000000
+#define DATA_DESCRIPTOR		0x05000000
+#define UNSOLICITED_COMMAND	0x06000000
+#define COMMAND_STATUS		0x07000000
+#define INFO_MASK		0x0F000000
+//
+//	(Link Control Codes)
+//
+#define ACK_1			0x00000000
+#define ACK_0_OR_N		0x01000000
+#define P_RJT			0x02000000 
+#define F_RJT			0x03000000 
+#define P_BSY			0x04000000
+#define FABRIC_BUSY_TO_DF	0x05000000	// Fabric Busy to Data Frame
+#define FABRIC_BUSY_TO_LC	0x06000000	// Fabric Busy to Link Ctl Frame
+#define LINK_CREDIT_RESET	0x07000000
+//
+//	(Link Service Command Codes)
+//
+//#define LS_RJT			0x01000000	// LS Reject
+
+#define LS_ACC			0x02000000	// LS Accept
+#define LS_PLOGI		0x03000000	// N_PORT Login
+#define LS_FLOGI		0x04000000	// F_PORT Login
+#define LS_LOGO			0x05000000	// Logout
+#define LS_ABTX			0x06000000	// Abort Exchange
+#define LS_RCS			0x07000000	// Read Connection Status
+#define LS_RES			0x08000000	// Read Exchange Status
+#define LS_RSS			0x09000000	// Read Sequence Status
+#define LS_RSI			0x0A000000	// Request Seq Initiative
+#define LS_ESTS			0x0B000000	// Establish Steaming
+#define LS_ESTC			0x0C000000	// Estimate Credit
+#define LS_ADVC			0x0D000000	// Advice Credit
+#define LS_RTV			0x0E000000	// Read Timeout Value
+#define LS_RLS			0x0F000000	// Read Link Status
+#define LS_ECHO			0x10000000	// Echo
+#define LS_TEST			0x11000000	// Test
+#define LS_RRQ			0x12000000	// Reinstate Rec. Qual.
+#define LS_PRLI			0x20000000	// Process Login
+#define LS_PRLO			0x21000000	// Process Logout
+#define LS_TPRLO		0x24000000	// 3rd Party Process Logout
+#define LS_PDISC		0x50000000	// Process Discovery
+#define LS_FDISC		0x51000000	// Fabric Discovery
+#define LS_ADISC		0x52000000	// Discover Address
+#define LS_RNC			0x53000000	// Report Node Capability
+#define LS_SCR                  0x62000000      // State Change Registration
+#define LS_MASK			0xFF000000	
+
+//
+// 	TYPE Bit Masks
+//
+#define BASIC_LINK_SERVICE	0x00000000
+#define EXT_LINK_SERVICE	0x01000000
+
+#define LLC			0x04000000
+#define LLC_SNAP		0x05000000
+#define SCSI_FCP		0x08000000
+#define SCSI_GPP		0x09000000
+#define IPI3_MASTER		0x11000000
+#define IPI3_SLAVE		0x12000000
+#define IPI3_PEER		0x13000000
+#define CP_IPI3_MASTER		0x15000000
+#define CP_IPI3_SLAVE		0x16000000
+#define CP_IPI3_PEER		0x17000000
+#define SBCCS_CHANNEL		0x19000000
+#define SBCCS_CONTROL		0x1A000000
+#define FIBRE_SERVICES		0x20000000
+#define FC_FG			0x21000000
+#define FC_XS			0x22000000
+#define FC_AL			0x23000000
+#define SNMP			0x24000000
+#define HIPPI_FP		0x40000000
+#define TYPE_MASK		0xFF000000
+
+typedef struct {
+	UCHAR seq_id_valid;
+	UCHAR seq_id;
+	USHORT reserved;  // 2 bytes reserved
+	ULONG ox_rx_id;
+	USHORT low_seq_cnt;
+	USHORT high_seq_cnt;
+} BA_ACC_PAYLOAD;
+
+typedef struct {
+	UCHAR reserved;
+	UCHAR reason_code;
+	UCHAR reason_explain;
+	UCHAR vendor_unique;
+} BA_RJT_PAYLOAD;
+
+
+typedef struct {
+	ULONG 	command_code;
+	ULONG 	sid;
+	USHORT	ox_id;
+	USHORT	rx_id;
+} RRQ_MESSAGE;
+
+typedef struct {
+	ULONG command_code;
+	UCHAR vendor;
+	UCHAR explain;
+	UCHAR reason;
+	UCHAR reserved;
+} REJECT_MESSAGE;
+
+
+#define	N_OR_F_PORT		0x1000
+#define RANDOM_RELATIVE_OFFSET	0x4000
+#define CONTINUOSLY_INCREASING	0x8000
+
+#define CLASS_VALID		0x8000
+#define INTERMIX_MODE		0x4000
+#define TRANSPARENT_STACKED	0x2000
+#define LOCKDOWN_STACKED	0x1000
+#define SEQ_DELIVERY		0x800
+
+#define XID_NOT_SUPPORTED	0x00
+#define XID_SUPPORTED		0x4000
+#define XID_REQUIRED		0xC000
+
+#define ASSOCIATOR_NOT_SUPPORTED	0x00
+#define ASSOCIATOR_SUPPORTED	0x1000
+#define ASSOCIATOR_REQUIRED	0x3000
+
+#define	INIT_ACK0_SUPPORT	0x800
+#define INIT_ACKN_SUPPORT	0x400
+
+#define	RECIP_ACK0_SUPPORT	0x8000
+#define RECIP_ACKN_SUPPORT	0x4000
+
+#define X_ID_INTERLOCK		0x2000
+
+#define ERROR_POLICY		0x1800		// Error Policy Supported
+#define ERROR_DISCARD		0x00		// Only Discard Supported
+#define ERROR_DISC_PROCESS	0x02		// Discard and process supported
+
+#define NODE_ID			0x01
+#define IEEE_EXT		0x20
+
+//
+// Categories Supported Per Sequence
+//
+#define	CATEGORIES_PER_SEQUENCE	0x300
+#define ONE_CATEGORY_SEQUENCE	0x00		// 1 Category per Sequence
+#define TWO_CATEGORY_SEQUENCE	0x01		// 2 Categories per Sequence
+#define MANY_CATEGORY_SEQUENCE	0x03		// > 2 Categories/Sequence
+
+typedef struct {
+
+	USHORT initiator_control;
+	USHORT service_options;
+
+	USHORT rx_data_size;
+	USHORT recipient_control;
+
+	USHORT ee_credit;
+	USHORT concurrent_sequences;
+
+	USHORT reserved;
+	USHORT open_sequences;
+
+} CLASS_PARAMETERS;
+
+typedef struct {
+	ULONG	login_cmd;
+	//
+	// Common Service Parameters
+	//
+	struct {
+
+		USHORT bb_credit;
+		UCHAR lowest_ver;
+		UCHAR highest_ver;
+
+		USHORT bb_rx_size;
+		USHORT common_features;
+
+		USHORT rel_offset;
+		USHORT concurrent_seq;
+
+
+		ULONG e_d_tov;
+	} cmn_services;
+
+	//
+	// Port Name
+	//
+	UCHAR port_name[8];
+
+	//
+	// Node/Fabric Name
+	//
+	UCHAR node_name[8];
+
+	//
+	// Class 1, 2 and 3 Service Parameters
+	//
+	CLASS_PARAMETERS	class1;
+	CLASS_PARAMETERS	class2;
+	CLASS_PARAMETERS	class3;
+
+	ULONG reserved[4];
+
+	//
+	// Vendor Version Level
+	//
+	UCHAR		vendor_id[2];
+	UCHAR		vendor_version[6];
+	ULONG		buffer_size;
+	USHORT		rxid_start;
+	USHORT		total_rxids;
+} LOGIN_PAYLOAD;
+
+
+typedef struct
+{
+  ULONG cmd;  // 4 bytes
+  UCHAR n_port_identifier[3];
+  UCHAR reserved;
+  UCHAR port_name[8];
+} LOGOUT_PAYLOAD;
+
+
+//
+//	PRLI Request Service Parameter Defines
+//
+#define PRLI_ACC			0x01
+#define PRLI_REQ			0x02
+#define ORIG_PROCESS_ASSOC_VALID	0x8000
+#define RESP_PROCESS_ASSOC_VALID	0x4000
+#define ESTABLISH_PAIR			0x2000
+#define DATA_OVERLAY_ALLOWED		0x40
+#define	INITIATOR_FUNCTION		0x20
+#define	TARGET_FUNCTION			0x10
+#define CMD_DATA_MIXED			0x08
+#define DATA_RESP_MIXED			0x04
+#define READ_XFER_RDY			0x02
+#define WRITE_XFER_RDY			0x01
+
+#define RESPONSE_CODE_MASK	0xF00
+#define REQUEST_EXECUTED	0x100
+#define NO_RESOURCES		0x200
+#define INIT_NOT_COMPLETE	0x300
+#define IMAGE_DOES_NOT_EXIST	0x400
+#define BAD_PREDEFINED_COND	0x500
+#define REQ_EXEC_COND		0x600
+#define NO_MULTI_PAGE		0x700
+
+typedef struct {
+	USHORT	payload_length;
+	UCHAR	page_length;
+	UCHAR	cmd;
+
+
+	ULONG	valid;
+
+	ULONG	orig_process_associator;
+
+	ULONG	resp_process_associator;
+	
+	ULONG	fcp_info;
+} PRLI_REQUEST;
+
+typedef struct {
+
+	USHORT	payload_length;
+	UCHAR	page_length;
+	UCHAR	cmd;
+
+	ULONG	valid;
+	ULONG	orig_process_associator;
+
+	ULONG	resp_process_associator;
+	ULONG	reserved;
+} PRLO_REQUEST;
+
+typedef struct {
+	ULONG	cmd;
+
+	ULONG	hard_address;
+	
+	UCHAR	port_name[8];
+
+	UCHAR	node_name[8];
+
+	ULONG	s_id;
+} ADISC_PAYLOAD;
+
+struct ext_sg_entry_t {
+	__u32 len:18;		/* buffer length, bits 0-17 */
+	__u32 uba:13;		/* upper bus address bits 18-31 */
+	__u32 lba;		/* lower bus address bits 0-31 */
+}; 
+
+
+// J. McCarty's LINK.H
+//
+//	LS_RJT Reason Codes
+//
+
+#define INVALID_COMMAND_CODE	0x01
+#define LOGICAL_ERROR		0x03
+#define LOGICAL_BUSY		0x05
+#define PROTOCOL_ERROR		0x07
+#define UNABLE_TO_PERFORM	0x09
+#define COMMAND_NOT_SUPPORTED	0x0B
+#define LS_VENDOR_UNIQUE	0xFF
+
+//
+// 	LS_RJT Reason Codes Explanations
+//
+#define NO_REASON		0x00
+#define OPTIONS_ERROR		0x01
+#define INITIATOR_CTL_ERROR	0x03
+#define RECIPIENT_CTL_ERROR	0x05
+#define DATA_FIELD_SIZE_ERROR	0x07
+#define CONCURRENT_SEQ_ERROR	0x09
+#define CREDIT_ERROR		0x0B
+#define INVALID_PORT_NAME	0x0D
+#define INVALID_NODE_NAME	0x0E
+#define INVALID_CSP		0x0F	// Invalid Service Parameters
+#define INVALID_ASSOC_HDR	0x11	// Invalid Association Header
+#define ASSOC_HDR_REQUIRED	0x13	// Association Header Required
+#define LS_INVALID_S_ID		0x15
+#define INVALID_OX_RX_ID	0x17	// Invalid OX_ID RX_ID Combination
+#define CMD_IN_PROCESS		0x19
+#define INVALID_IDENTIFIER	0x1F	// Invalid N_PORT Identifier
+#define INVALID_SEQ_ID		0x21
+#define ABT_INVALID_XCHNG	0x23 	// Attempt to Abort an invalid Exchange
+#define ABT_INACTIVE_XCHNG	0x25 	// Attempt to Abort an inactive Exchange
+#define NEED_REC_QUAL		0x27	// Recovery Qualifier required
+#define NO_LOGIN_RESOURCES	0x29	// No resources to support login
+#define NO_DATA			0x2A	// Unable to supply requested data
+#define	REQUEST_NOT_SUPPORTED	0x2C	// Request Not Supported
+
+//
+//	Link Control Codes
+//
+
+//
+//	P_BSY Action Codes
+//
+#define SEQUENCE_TERMINATED	0x01000000
+#define SEQUENCE_ACTIVE		0x02000000
+
+//
+//	P_BSY Reason Codes
+//
+#define PHYS_NPORT_BUSY		0x010000
+#define NPORT_RESOURCE_BUSY	0x020000
+
+//
+// 	P_RJT, F_RJT Action Codes
+//
+
+#define RETRYABLE_ERROR		0x01000000
+#define NON_RETRYABLE_ERROR	0x02000000
+
+//
+// 	P_RJT, F_RJT Reason Codes
+//
+#define INVALID_D_ID		0x010000
+#define INVALID_S_ID		0x020000
+#define NPORT_NOT_AVAIL_TMP	0x030000
+#define NPORT_NOT_AVAIL_PERM	0x040000
+#define CLASS_NOT_SUPPORTED	0x050000
+#define USAGE_ERROR		0x060000
+#define TYPE_NOT_SUPPORTED	0x070000
+#define INVAL_LINK_CONTROL	0x080000
+#define INVAL_R_CTL		0x090000
+#define INVAL_F_CTL		0x0A0000
+#define INVAL_OX_ID		0x0B0000
+#define INVAL_RX_ID		0x0C0000
+#define INVAL_SEQ_ID		0x0D0000
+#define INVAL_DF_CTL		0x0E0000
+#define INVAL_SEQ_CNT		0x0F0000
+#define INVAL_PARAMS		0x100000
+#define EXCHANGE_ERROR		0x110000
+#define LS_PROTOCOL_ERROR	0x120000
+#define INCORRECT_LENGTH	0x130000
+#define UNEXPECTED_ACK		0x140000
+#define LOGIN_REQ		0x160000
+#define EXCESSIVE_SEQ		0x170000
+#define NO_EXCHANGE		0x180000
+#define SEC_HDR_NOT_SUPPORTED	0x190000
+#define NO_FABRIC		0x1A0000
+#define P_VENDOR_UNIQUE		0xFF0000
+
+//
+// 	BA_RJT Reason Codes
+//
+#define BA_INVALID_COMMAND	0x00010000
+#define BA_LOGICAL_ERROR	0x00030000
+#define BA_LOGICAL_BUSY		0x00050000
+#define BA_PROTOCOL_ERROR	0x00070000
+#define BA_UNABLE_TO_PERFORM	0x00090000
+
+//
+// 	BA_RJT Reason Explanation Codes
+//
+#define BA_NO_REASON		0x00000000
+#define BA_INVALID_OX_RX	0x00000300
+#define BA_SEQUENCE_ABORTED	0x00000500
+
+
+
+#endif /* CPQFCTSSTRUCTS_H	*/
+
diff --git a/drivers/scsi/cpqfcTStrigger.c b/drivers/scsi/cpqfcTStrigger.c
new file mode 100644
index 0000000..dbb7e65
--- /dev/null
+++ b/drivers/scsi/cpqfcTStrigger.c
@@ -0,0 +1,33 @@
+// Routine to trigger Finisar GTA analyzer. Runs of GPIO2
+// NOTE: DEBUG ONLY! Could interfere with FCMNGR/Miniport operation
+// since it writes directly to the Tachyon board.  This function
+// developed for Compaq HBA Tachyon TS v1.2 (Rev X5 PCB)
+
+#include "cpqfcTStrigger.h"
+#if TRIGGERABLE_HBA
+
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+void TriggerHBA( void* IOBaseUpper, int Print)
+{
+  __u32 long value;
+
+  // get initial value in hopes of not modifying any other GPIO line
+  IOBaseUpper += 0x188;  // TachTL/TS Control reg
+  
+  value = readl( IOBaseUpper);
+  // set HIGH to trigger external analyzer (tested on Dolche Finisar 1Gb GTA)
+  // The Finisar anaylzer triggers on low-to-high TTL transition
+  value |= 0x01; // set bit 0
+
+  writel( value, IOBaseUpper);
+
+  if( Print)
+    printk( " -GPIO0 set- ");
+}
+
+#endif
diff --git a/drivers/scsi/cpqfcTStrigger.h b/drivers/scsi/cpqfcTStrigger.h
new file mode 100644
index 0000000..c961792
--- /dev/null
+++ b/drivers/scsi/cpqfcTStrigger.h
@@ -0,0 +1,8 @@
+// don't do this unless you have the right hardware!
+#define TRIGGERABLE_HBA 0
+#if TRIGGERABLE_HBA
+void TriggerHBA( void*, int);
+#else
+#define TriggerHBA(x, y)
+#endif
+
diff --git a/drivers/scsi/cpqfcTSworker.c b/drivers/scsi/cpqfcTSworker.c
new file mode 100644
index 0000000..a5fd742
--- /dev/null
+++ b/drivers/scsi/cpqfcTSworker.c
@@ -0,0 +1,6516 @@
+/* Copyright(c) 2000, Compaq Computer Corporation 
+ * Fibre Channel Host Bus Adapter 
+ * 64-bit, 66MHz PCI 
+ * Originally developed and tested on:
+ * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
+ *          SP# P225CXCBFIEL6T, Rev XC
+ *          SP# 161290-001, Rev XD
+ * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * Written by Don Zimmerman
+*/
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/smp_lock.h>
+#include <linux/pci.h>
+
+#define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>   // struct Scsi_Host definition for T handler
+#include "cpqfcTSchip.h"
+#include "cpqfcTSstructs.h"
+#include "cpqfcTStrigger.h"
+
+//#define LOGIN_DBG 1
+
+// REMARKS:
+// Since Tachyon chips may be permitted to wait from 500ms up to 2 sec
+// to empty an outgoing frame from its FIFO to the Fibre Channel stream,
+// we cannot do everything we need to in the interrupt handler.  Specifically,
+// every time a link re-init (e.g. LIP) takes place, all SCSI I/O has to be
+// suspended until the login sequences have been completed.  Login commands
+// are frames just like SCSI commands are frames; they are subject to the same
+// timeout issues and delays.  Also, various specs provide up to 2 seconds for
+// devices to log back in (i.e. respond with ACC to a login frame), so I/O to
+// that device has to be suspended.
+// A serious problem here occurs on highly loaded FC-AL systems.  If our FC port
+// has a low priority (e.g. high arbitrated loop physical address, alpa), and
+// some other device is hogging bandwidth (permissible under FC-AL), we might
+// time out thinking the link is hung, when it's simply busy.  Many such
+// considerations complicate the design.  Although Tachyon assumes control
+// (in silicon) for many link-specific issues, the Linux driver is left with the
+// rest, which turns out to be a difficult, time critical chore.
+
+// These "worker" functions will handle things like FC Logins; all
+// processes with I/O to our device must wait for the Login to complete
+// and (if successful) I/O to resume.  In the event of a malfunctioning or  
+// very busy loop, it may take hundreds of millisecs or even seconds to complete
+// a frame send.  We don't want to hang up the entire server (and all
+// processes which don't depend on Fibre) during this wait.
+
+// The Tachyon chip can have around 30,000 I/O operations ("exchanges")
+// open at one time.  However, each exchange must be initiated 
+// synchronously (i.e. each of the 30k I/O had to be started one at a
+// time by sending a starting frame via Tachyon's outbound que).  
+
+// To accommodate kernel "module" build, this driver limits the exchanges
+// to 256, because of the contiguous physical memory limitation of 128M.
+
+// Typical FC Exchanges are opened presuming the FC frames start without errors,
+// while Exchange completion is handled in the interrupt handler.  This
+// optimizes performance for the "everything's working" case.
+// However, when we have FC related errors or hot plugging of FC ports, we pause
+// I/O and handle FC-specific tasks in the worker thread.  These FC-specific
+// functions will handle things like FC Logins and Aborts.  As the Login sequence
+// completes to each and every target, I/O can resume to that target.  
+
+// Our kernel "worker thread" must share the HBA with threads calling 
+// "queuecommand".  We define a "BoardLock" semaphore which indicates
+// to "queuecommand" that the HBA is unavailable, and Cmnds are added to a
+// board lock Q.  When the worker thread finishes with the board, the board
+// lock Q commands are completed with status causing immediate retry.
+// Typically, the board is locked while Logins are in progress after an
+// FC Link Down condition.  When Cmnds are re-queued after board lock, the
+// particular Scsi channel/target may or may not have logged back in.  When
+// the device is waiting for login, the "prli" flag is clear, in which case
+// commands are passed to a Link Down Q.  Whenever the login finally completes,
+// the LinkDown Q is completed, again with status causing immediate retry.
+// When FC devices are logged in, we build and start FC commands to the
+// devices.
+
+// NOTE!! As of May 2000, kernel 2.2.14, the error recovery logic for devices 
+// that never log back in (e.g. physically removed) is NOT completely
+// understood.  I've still seen instances of system hangs on failed Write 
+// commands (possibly from the ext2 layer?) on device removal.  Such special
+// cases need to be evaluated from a system/application view - e.g., how
+// exactly does the system want me to complete commands when the device is
+// physically removed??
+
+// local functions
+
+static void SetLoginFields(
+  PFC_LOGGEDIN_PORT pLoggedInPort,
+  TachFCHDR_GCMND* fchs,
+  BOOLEAN PDisc,
+  BOOLEAN Originator);
+
+static void AnalyzeIncomingFrame( 
+       CPQFCHBA *cpqfcHBAdata,
+       ULONG QNdx );
+
+static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds );
+
+static int verify_PLOGI( PTACHYON fcChip,
+      TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+static int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain);
+
+static void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type);
+static void BuildLinkServicePayload( 
+              PTACHYON fcChip, ULONG type, void* payload);
+
+static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
+        PFC_LOGGEDIN_PORT pLoggedInPort);
+
+static void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID);
+
+static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata);
+
+static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
+		        PFC_LOGGEDIN_PORT pLoggedInPort);
+
+static void IssueReportLunsCommand( 
+              CPQFCHBA* cpqfcHBAdata, 
+	      TachFCHDR_GCMND* fchs);
+
+// (see scsi_error.c comments on kernel task creation)
+
+void cpqfcTSWorkerThread( void *host)
+{
+  struct Scsi_Host *HostAdapter = (struct Scsi_Host*)host;
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata; 
+#ifdef PCI_KERNEL_TRACE
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+#endif
+  DECLARE_MUTEX_LOCKED(fcQueReady);
+  DECLARE_MUTEX_LOCKED(fcTYOBcomplete); 
+  DECLARE_MUTEX_LOCKED(TachFrozen);  
+  DECLARE_MUTEX_LOCKED(BoardLock);  
+
+  ENTER("WorkerThread");
+
+  lock_kernel();
+  daemonize("cpqfcTS_wt_%d", HostAdapter->host_no);
+  siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+
+
+  cpqfcHBAdata->fcQueReady = &fcQueReady;  // primary wait point
+  cpqfcHBAdata->TYOBcomplete = &fcTYOBcomplete;
+  cpqfcHBAdata->TachFrozen = &TachFrozen;
+    
+ 
+  cpqfcHBAdata->worker_thread = current;
+  
+  unlock_kernel();
+
+  if( cpqfcHBAdata->notify_wt != NULL )
+    up( cpqfcHBAdata->notify_wt); // OK to continue
+
+  while(1)
+  {
+    unsigned long flags;
+
+    down_interruptible( &fcQueReady);  // wait for something to do
+
+    if (signal_pending(current) )
+      break;
+    
+    PCI_TRACE( 0x90)
+    // first, take the IO lock so the SCSI upper layers can't call
+    // into our _quecommand function (this also disables INTs)
+    spin_lock_irqsave( HostAdapter->host_lock, flags); // STOP _que function
+    PCI_TRACE( 0x90)
+         
+    CPQ_SPINLOCK_HBA( cpqfcHBAdata)
+    // next, set this pointer to indicate to the _quecommand function
+    // that the board is in use, so it should que the command and 
+    // immediately return (we don't actually require the semaphore function
+    // in this driver rev)
+
+    cpqfcHBAdata->BoardLock = &BoardLock;
+
+    PCI_TRACE( 0x90)
+
+    // release the IO lock (and re-enable interrupts)
+    spin_unlock_irqrestore( HostAdapter->host_lock, flags);
+
+    // disable OUR HBA interrupt (keep them off as much as possible
+    // during error recovery)
+    disable_irq( cpqfcHBAdata->HostAdapter->irq);
+
+    // OK, let's process the Fibre Channel Link Q and do the work
+    cpqfcTS_WorkTask( HostAdapter);
+
+    // hopefully, no more "work" to do;
+    // re-enable our INTs for "normal" completion processing
+    enable_irq( cpqfcHBAdata->HostAdapter->irq);
+ 
+
+    cpqfcHBAdata->BoardLock = NULL; // allow commands to be queued
+    CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+
+
+    // Now, complete any Cmnd we Q'd up while BoardLock was held
+
+    CompleteBoardLockCmnd( cpqfcHBAdata);
+  
+
+  }
+  // hopefully, the signal was for our module exit...
+  if( cpqfcHBAdata->notify_wt != NULL )
+    up( cpqfcHBAdata->notify_wt); // yep, we're outta here
+}
+
+
+// Freeze Tachyon routine.
+// If Tachyon is already frozen, return FALSE
+// If Tachyon is not frozen, call freeze function, return TRUE
+//
+static BOOLEAN FreezeTach( CPQFCHBA *cpqfcHBAdata)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  BOOLEAN FrozeTach = FALSE;
+  // It's possible that the chip is already frozen; if so,
+  // "Freezing" again will NOT! generate another Freeze
+  // Completion Message.
+
+  if( (fcChip->Registers.TYstatus.value & 0x70000) != 0x70000)
+  {  // (need to freeze...)
+    fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+
+    // 2. Get Tach freeze confirmation
+    // (synchronize SEST manipulation with Freeze Completion Message)
+    // we need INTs on so semaphore can be set.	
+    enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Semaphore
+    down_interruptible( cpqfcHBAdata->TachFrozen); // wait for INT handler sem.
+    // can we TIMEOUT semaphore wait?? TBD
+    disable_irq( cpqfcHBAdata->HostAdapter->irq); 
+
+    FrozeTach = TRUE;
+  }  // (else, already frozen)
+ 
+  return FrozeTach;
+}  
+
+
+
+
+// This is the kernel worker thread task, which processes FC
+// tasks which were queued by the Interrupt handler or by
+// other WorkTask functions.
+
+#define DBG 1
+//#undef DBG
+void cpqfcTS_WorkTask( struct Scsi_Host *HostAdapter)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG QconsumerNdx;
+  LONG ExchangeID;
+  ULONG ulStatus=0;
+  TachFCHDR_GCMND fchs;
+  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
+
+  ENTER("WorkTask");
+
+  // copy current index to work on
+  QconsumerNdx = fcLQ->consumer;
+
+  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x90)
+  
+
+  // NOTE: when this switch completes, we will "consume" the Que item
+//  printk("Que type %Xh\n", fcLQ->Qitem[QconsumerNdx].Type);
+  switch( fcLQ->Qitem[QconsumerNdx].Type )
+  {
+      // incoming frame - link service (ACC, UNSOL REQ, etc.)
+      // or FCP-SCSI command
+    case SFQ_UNKNOWN:  
+      AnalyzeIncomingFrame( cpqfcHBAdata, QconsumerNdx );
+
+      break;
+  
+    
+    
+    case EXCHANGE_QUEUED:  // an Exchange (i.e. FCP-SCSI) was previously
+                           // Queued because the link was down.  The  
+                           // heartbeat timer detected it and Queued it here.
+                           // We attempt to start it again, and if
+                           // successful we clear the EXCHANGE_Q flag.
+                           // If the link doesn't come up, the Exchange
+                           // will eventually time-out.
+
+      ExchangeID = (LONG)  // x_ID copied from DPC timeout function
+                   fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+
+      // It's possible that a Q'd exchange could have already
+      // been started by other logic (e.g. ABTS process)
+      // Don't start if already started (Q'd flag clear)
+
+      if( Exchanges->fcExchange[ExchangeID].status & EXCHANGE_QUEUED )
+      {
+//        printk(" *Start Q'd x_ID %Xh: type %Xh ", 
+//          ExchangeID, Exchanges->fcExchange[ExchangeID].type);
+      
+        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID);
+        if( !ulStatus )
+        {
+//          printk("success* ");
+        }	
+        else
+        {
+#ifdef DBG
+      
+          if( ulStatus == EXCHANGE_QUEUED)
+            printk("Queued* ");
+          else
+            printk("failed* ");
+		
+#endif
+	} 
+      }
+      break;
+
+
+    case LINKDOWN:  
+      // (lots of things already done in INT handler) future here?
+      break;
+    
+    
+    case LINKACTIVE:   // Tachyon set the Lup bit in FM status
+                       // NOTE: some misbehaving FC ports (like Tach2.1)
+                       // can re-LIP immediately after a LIP completes.
+      
+      // if "initiator", need to verify LOGs with ports
+//      printk("\n*LNKUP* ");
+
+      if( fcChip->Options.initiator )
+        SendLogins( cpqfcHBAdata, NULL ); // PLOGI or PDISC, based on fcPort data
+                  // if SendLogins successfully completes, PortDiscDone
+                  // will be set.
+      
+      
+      // If SendLogins was successful, then we expect to get incoming
+      // ACCepts or REJECTs, which are handled below.
+
+      break;
+
+    // LinkService and Fabric request/reply processing
+    case ELS_FDISC:      // need to send Fabric Discovery (Login)
+    case ELS_FLOGI:      // need to send Fabric Login
+    case ELS_SCR:        // need to send State Change Registration
+    case FCS_NSR:        // need to send Name Service Request
+    case ELS_PLOGI:      // need to send PLOGI
+    case ELS_ACC:        // send generic ACCept
+    case ELS_PLOGI_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
+    case ELS_PRLI_ACC:   // need to send ELS ACCept frame to recv'd PRLI
+    case ELS_LOGO:      // need to send ELS LOGO (logout)
+    case ELS_LOGO_ACC:  // need to send ELS ACCept frame to recv'd PLOGI
+    case ELS_RJT:         // ReJecT reply
+    case ELS_PRLI:       // need to send ELS PRLI
+ 
+    
+//      printk(" *ELS %Xh* ", fcLQ->Qitem[QconsumerNdx].Type);
+      // if PortDiscDone is not set, it means the SendLogins routine
+      // failed to complete -- assume that LDn occurred, so login frames
+      // are invalid
+      if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
+      {
+        printk("Discard Q'd ELS login frame\n");
+        break;  
+      }
+
+      ulStatus = cpqfcTSBuildExchange(
+          cpqfcHBAdata,
+          fcLQ->Qitem[QconsumerNdx].Type, // e.g. PLOGI
+          (TachFCHDR_GCMND*)
+            fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+          NULL,         // no data (no scatter/gather list)
+          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+
+      if( !ulStatus ) // Exchange setup?
+      {
+        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
+        if( !ulStatus )
+        {
+          // submitted to Tach's Outbound Que (ERQ PI incremented)
+          // waited for completion for ELS type (Login frames issued
+          // synchronously)
+        }
+        else
+          // check reason for Exchange not being started - we might
+          // want to Queue and start later, or fail with error
+        {
+
+        }
+      }
+
+      else   // Xchange setup failed...
+        printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+
+      break;
+
+    case SCSI_REPORT_LUNS:
+      // pass the incoming frame (actually, it's a PRLI frame)
+      // so we can send REPORT_LUNS, in order to determine VSA/PDU
+      // FCP-SCSI Lun address mode
+      IssueReportLunsCommand( cpqfcHBAdata, (TachFCHDR_GCMND*)
+            fcLQ->Qitem[QconsumerNdx].ulBuff); 
+
+      break;
+      
+
+
+
+    case BLS_ABTS:       // need to ABORT one or more exchanges
+    {
+      LONG x_ID = fcLQ->Qitem[QconsumerNdx].ulBuff[0];
+      BOOLEAN FrozeTach = FALSE;   
+     
+      if ( x_ID >= TACH_SEST_LEN )  // (in)sanity check
+      {
+//	printk( " cpqfcTS ERROR! BOGUS x_ID %Xh", x_ID);
+	break;
+      }
+
+
+      if( Exchanges->fcExchange[ x_ID].Cmnd == NULL ) // should be RARE
+      {
+//	printk(" ABTS %Xh Scsi Cmnd null! ", x_ID);
+	
+       break;  // nothing to abort!
+      }
+
+//#define ABTS_DBG
+#ifdef ABTS_DBG
+      printk("INV SEST[%X] ", x_ID); 
+      if( Exchanges->fcExchange[x_ID].status & FC2_TIMEOUT)
+      {
+        printk("FC2TO");
+      }
+      if( Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT)
+      {
+        printk("IA");
+      }
+      if( Exchanges->fcExchange[x_ID].status & PORTID_CHANGED)
+      {
+        printk("PORTID");
+      }
+      if( Exchanges->fcExchange[x_ID].status & DEVICE_REMOVED)
+      {
+        printk("DEVRM");
+      }
+      if( Exchanges->fcExchange[x_ID].status & LINKFAIL_TX)
+      {
+        printk("LKF");
+      }
+      if( Exchanges->fcExchange[x_ID].status & FRAME_TO)
+      {
+        printk("FRMTO");
+      }
+      if( Exchanges->fcExchange[x_ID].status & ABORTSEQ_NOTIFY)
+      {
+        printk("ABSQ");
+      }
+      if( Exchanges->fcExchange[x_ID].status & SFQ_FRAME)
+      {
+        printk("SFQFR");
+      }
+
+      if( Exchanges->fcExchange[ x_ID].type == 0x2000)
+        printk(" WR");
+      else if( Exchanges->fcExchange[ x_ID].type == 0x3000)
+        printk(" RD");
+      else if( Exchanges->fcExchange[ x_ID].type == 0x10)
+        printk(" ABTS");
+      else
+        printk(" %Xh", Exchanges->fcExchange[ x_ID].type); 
+
+      if( !(Exchanges->fcExchange[x_ID].status & INITIATOR_ABORT))
+      {
+	printk(" Cmd %p, ", 
+          Exchanges->fcExchange[ x_ID].Cmnd);
+
+        printk(" brd/chn/trg/lun %d/%d/%d/%d port_id %06X\n", 
+          cpqfcHBAdata->HBAnum,
+          Exchanges->fcExchange[ x_ID].Cmnd->channel,
+          Exchanges->fcExchange[ x_ID].Cmnd->target,
+          Exchanges->fcExchange[ x_ID].Cmnd->lun,
+          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
+      }
+      else  // assume that Cmnd ptr is invalid on _abort()
+      {
+	printk(" Cmd ptr invalid\n");
+      }
+     
+#endif      
+
+      
+      // Steps to ABORT a SEST exchange:
+      // 1. Freeze TL SCSI assists & ERQ (everything)
+      // 2. Receive FROZEN inbound CM (must succeed!)
+      // 3. Invalidate x_ID SEST entry 
+      // 4. Resume TL SCSI assists & ERQ (everything)
+      // 5. Build/start on exchange - change "type" to BLS_ABTS,
+      //    timeout to X sec (RA_TOV from PLDA is actually 0)
+      // 6. Set Exchange Q'd status if ABTS cannot be started,
+      //    or simply complete Exchange in "Terminate" condition
+
+  PCI_TRACEO( x_ID, 0xB4)
+      
+      // 1 & 2 . Freeze Tach & get confirmation of freeze
+      FrozeTach = FreezeTach( cpqfcHBAdata);
+
+      // 3. OK, Tachyon is frozen, so we can invalidate SEST exchange.
+      // FC2_TIMEOUT means we are originating the abort, while
+      // TARGET_ABORT means we are ACCepting an abort.
+      // LINKFAIL_TX, ABORTSEQ_NOFITY, INV_ENTRY or FRAME_TO are 
+      // all from Tachyon:
+      // Exchange was corrupted by LDn or other FC physical failure
+      // INITIATOR_ABORT means the upper layer driver/application
+      // requested the abort.
+
+
+	  
+      // clear bit 31 (VALid), to invalidate & take control from TL
+      fcChip->SEST->u[ x_ID].IWE.Hdr_Len &= 0x7FFFFFFF;
+
+
+      // examine and Tach's "Linked List" for IWEs that 
+      // received (nearly) simultaneous transfer ready (XRDY) 
+      // repair linked list if necessary (TBD!)
+      // (If we ignore the "Linked List", we will time out
+      // WRITE commands where we received the FCP-SCSI XFRDY
+      // frame (because Tachyon didn't processes it).  Linked List
+      // management should be done as an optimization.
+
+//       readl( fcChip->Registers.ReMapMemBase+TL_MEM_SEST_LINKED_LIST ));
+
+
+      
+
+      // 4. Resume all Tachlite functions (for other open Exchanges)
+      // as quickly as possible to allow other exchanges to other ports
+      // to resume.  Freezing Tachyon may cause cascading errors, because
+      // any received SEST frame cannot be processed by the SEST.
+      // Don't "unfreeze" unless Link is operational
+      if( FrozeTach )  // did we just freeze it (above)?
+        fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+      
+
+  PCI_TRACEO( x_ID, 0xB4)
+
+      // Note there is no confirmation that the chip is "unfrozen".  Also,
+      // if the Link is down when unfreeze is called, it has no effect.
+      // Chip will unfreeze when the Link is back up.
+
+      // 5. Now send out Abort commands if possible
+      // Some Aborts can't be "sent" (Port_id changed or gone);
+      // if the device is gone, there is no port_id to send the ABTS to.
+
+      if( !(Exchanges->fcExchange[ x_ID].status & PORTID_CHANGED)
+			  &&
+          !(Exchanges->fcExchange[ x_ID].status & DEVICE_REMOVED) )
+      {
+        Exchanges->fcExchange[ x_ID].type = BLS_ABTS;
+        fchs.s_id = Exchanges->fcExchange[ x_ID].fchs.d_id;
+        ulStatus = cpqfcTSBuildExchange(
+          cpqfcHBAdata,
+          BLS_ABTS,
+          &fchs,        // (uses only s_id)
+          NULL,         // (no scatter/gather list for ABTS)
+          &x_ID );// ABTS on this Exchange ID
+
+        if( !ulStatus ) // Exchange setup build OK?
+        {
+
+            // ABTS may be needed because an Exchange was corrupted
+            // by a Link disruption.  If the Link is UP, we can
+	    // presume that this ABTS can start immediately; otherwise,
+	    // set Que'd status so the Login functions
+            // can restart it when the FC physical Link is restored
+          if( ((fcChip->Registers.FMstatus.value &0xF0) &0x80)) // loop init?
+          {			    
+//                printk(" *set Q status x_ID %Xh on LDn* ", x_ID);
+                Exchanges->fcExchange[ x_ID].status |= EXCHANGE_QUEUED;
+          }
+
+          else  // what FC device (port_id) does the Cmd belong to?
+          {
+            PFC_LOGGEDIN_PORT pLoggedInPort = 
+              Exchanges->fcExchange[ x_ID].pLoggedInPort;
+            
+            // if Port is logged in, we might start the abort.
+	
+            if( (pLoggedInPort != NULL) 
+			      &&
+                (pLoggedInPort->prli == TRUE) ) 
+            {
+              // it's possible that an Exchange has already been Queued
+              // to start after Login completes.  Check and don't
+	      // start it (again) here if Q'd status set
+//	    printk(" ABTS xchg %Xh ", x_ID);            
+ 	      if( Exchanges->fcExchange[x_ID].status & EXCHANGE_QUEUED)
+	      {
+//		    printk("already Q'd ");
+	      }
+	      else
+	      {
+//	            printk("starting ");
+		
+                fcChip->fcStats.FC2aborted++; 
+                ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
+                if( !ulStatus )
+                {
+                    // OK
+                    // submitted to Tach's Outbound Que (ERQ PI incremented)
+                }
+                else
+                {
+/*                   printk("ABTS exchange start failed -status %Xh, x_ID %Xh ",
+                        ulStatus, x_ID);
+*/
+                } 
+	      }
+	    }
+	    else
+	    {
+/*         	  printk(" ABTS NOT starting xchg %Xh, %p ",
+			       x_ID, pLoggedInPort);
+	          if( pLoggedInPort )
+	            printk("prli %d ", pLoggedInPort->prli);
+*/
+	    }		
+ 	  }
+        }
+        else  // what the #@!
+        {  // how do we fail to build an Exchange for ABTS??
+              printk("ABTS exchange build failed -status %Xh, x_ID %Xh\n",
+                ulStatus, x_ID);
+        }
+      }
+      else   // abort without ABTS -- just complete exchange/Cmnd to Linux
+      {
+//            printk(" *Terminating x_ID %Xh on %Xh* ", 
+//		    x_ID, Exchanges->fcExchange[x_ID].status);
+        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, x_ID);
+
+      }
+    } // end of ABTS case
+      break;
+
+
+
+    case BLS_ABTS_ACC:   // need to ACCept one ABTS
+                         // (NOTE! this code not updated for Linux yet..)
+      
+
+      printk(" *ABTS_ACC* ");
+      // 1. Freeze TL
+
+      fcChip->FreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+
+      memcpy(  // copy the incoming ABTS frame
+        &fchs,
+        fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+        sizeof( fchs));
+
+      // 3. OK, Tachyon is frozen so we can invalidate SEST entry 
+      // (if necessary)
+      // Status FC2_TIMEOUT means we are originating the abort, while
+      // TARGET_ABORT means we are ACCepting an abort
+      
+      ExchangeID = fchs.ox_rx_id & 0x7FFF; // RX_ID for exchange
+//      printk("ABTS ACC for Target ExchangeID %Xh\n", ExchangeID);
+
+
+      // sanity check on received ExchangeID
+      if( Exchanges->fcExchange[ ExchangeID].status == TARGET_ABORT )
+      {
+          // clear bit 31 (VALid), to invalidate & take control from TL
+//          printk("Invalidating SEST exchange %Xh\n", ExchangeID);
+          fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len &= 0x7FFFFFFF;
+      }
+
+
+      // 4. Resume all Tachlite functions (for other open Exchanges)
+      // as quickly as possible to allow other exchanges to other ports
+      // to resume.  Freezing Tachyon for too long may royally screw
+      // up everything!
+      fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+      
+      // Note there is no confirmation that the chip is "unfrozen".  Also,
+      // if the Link is down when unfreeze is called, it has no effect.
+      // Chip will unfreeze when the Link is back up.
+
+      // 5. Now send out Abort ACC reply for this exchange
+      Exchanges->fcExchange[ ExchangeID].type = BLS_ABTS_ACC;
+      
+      fchs.s_id = Exchanges->fcExchange[ ExchangeID].fchs.d_id;
+      ulStatus = cpqfcTSBuildExchange(
+            cpqfcHBAdata,
+            BLS_ABTS_ACC,
+            &fchs,
+            NULL,         // no data (no scatter/gather list)
+            &ExchangeID );// fcController->fcExchanges index, -1 if failed
+
+      if( !ulStatus ) // Exchange setup?
+      {
+        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
+        if( !ulStatus )
+        {
+          // submitted to Tach's Outbound Que (ERQ PI incremented)
+          // waited for completion for ELS type (Login frames issued
+          // synchronously)
+        }
+        else
+          // check reason for Exchange not being started - we might
+          // want to Queue and start later, or fail with error
+        {
+
+        } 
+      }
+      break;
+
+
+    case BLS_ABTS_RJT:   // need to ReJecT one ABTS; reject implies the
+                         // exchange doesn't exist in the TARGET context.
+                         // ExchangeID has to come from LinkService space.
+
+      printk(" *ABTS_RJT* ");
+      ulStatus = cpqfcTSBuildExchange(
+            cpqfcHBAdata,
+            BLS_ABTS_RJT,
+            (TachFCHDR_GCMND*)
+              fcLQ->Qitem[QconsumerNdx].ulBuff, // incoming fchs
+            NULL,         // no data (no scatter/gather list)
+            &ExchangeID );// fcController->fcExchanges index, -1 if failed
+
+      if( !ulStatus ) // Exchange setup OK?
+      {
+        ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
+        // If it fails, we aren't required to retry.
+      }
+      if( ulStatus )
+      {
+        printk("Failed to send BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+      }
+      else
+      {
+        printk("Sent BLS_RJT for ABTS, X_ID %Xh\n", ExchangeID);
+      
+      }
+
+      break;
+
+
+
+    default:
+      break;
+  }                   // end switch
+//doNothing:
+    // done with this item - now set the NEXT index
+
+  if( QconsumerNdx+1 >= FC_LINKQ_DEPTH ) // rollover test
+  {
+    fcLQ->consumer = 0;
+  }
+  else
+  { 
+    fcLQ->consumer++;
+  }
+
+  PCI_TRACEO( fcLQ->Qitem[QconsumerNdx].Type, 0x94)
+
+  LEAVE("WorkTask");
+  return;
+}
+
+
+
+
+// When Tachyon reports link down, bad al_pa, or Link Service (e.g. Login)
+// commands come in, post to the LinkQ so that action can be taken outside the
+// interrupt handler.  
+// This circular Q works like Tachyon's que - the producer points to the next
+// (unused) entry.  Called by Interrupt handler, WorkerThread, Timer
+// sputlinkq
+void cpqfcTSPutLinkQue( CPQFCHBA *cpqfcHBAdata,
+  int Type, 
+  void *QueContent)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
+  ULONG ndx;
+  
+  ENTER("cpqfcTSPutLinkQ");
+
+  ndx = fcLQ->producer;
+  
+  ndx += 1;  // test for Que full
+
+
+  
+  if( ndx >= FC_LINKQ_DEPTH ) // rollover test
+    ndx = 0;
+
+  if( ndx == fcLQ->consumer )   // QUE full test
+  {
+                       // QUE was full! lost LK command (fatal to logic)
+    fcChip->fcStats.lnkQueFull++;
+
+    printk("*LinkQ Full!*");
+    TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+/*
+    {
+      int i;
+      printk("LinkQ PI %d, CI %d\n", fcLQ->producer,
+        fcLQ->consumer);
+		      
+      for( i=0; i< FC_LINKQ_DEPTH; )
+      {
+	printk(" [%d]%Xh ", i, fcLQ->Qitem[i].Type);
+	if( (++i %8) == 0) printk("\n");
+      }
+  
+    }
+*/    
+    printk( "cpqfcTS: WARNING!! PutLinkQue - FULL!\n"); // we're hung
+  }
+  else                        // QUE next element
+  {
+    // Prevent certain multiple (back-to-back) requests.
+    // This is important in that we don't want to issue multiple
+    // ABTS for the same Exchange, or do multiple FM inits, etc.
+    // We can never be sure of the timing of events reported to
+    // us by Tach's IMQ, which can depend on system/bus speeds,
+    // FC physical link circumstances, etc.
+     
+    if( (fcLQ->producer != fcLQ->consumer)
+	    && 
+        (Type == FMINIT)  )
+    {
+      LONG lastNdx;  // compute previous producer index
+      if( fcLQ->producer)
+        lastNdx = fcLQ->producer- 1;
+      else
+	lastNdx = FC_LINKQ_DEPTH-1;
+
+
+      if( fcLQ->Qitem[lastNdx].Type == FMINIT)
+      {
+//        printk(" *skip FMINIT Q post* ");
+//        goto DoneWithPutQ;
+      }
+
+    }
+
+    // OK, add the Q'd item...
+    
+    fcLQ->Qitem[fcLQ->producer].Type = Type;
+   
+    memcpy(
+        fcLQ->Qitem[fcLQ->producer].ulBuff,
+        QueContent, 
+        sizeof(fcLQ->Qitem[fcLQ->producer].ulBuff));
+
+    fcLQ->producer = ndx;  // increment Que producer
+
+    // set semaphore to wake up Kernel (worker) thread
+    // 
+    up( cpqfcHBAdata->fcQueReady );
+  }
+
+//DoneWithPutQ:
+
+  LEAVE("cpqfcTSPutLinkQ");
+}
+
+
+
+
+// reset device ext FC link Q
+void cpqfcTSLinkQReset( CPQFCHBA *cpqfcHBAdata)
+   
+{
+  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
+  fcLQ->producer = 0;
+  fcLQ->consumer = 0;
+
+}
+
+
+
+
+
+// When Tachyon gets an unassisted FCP-SCSI frame, post here so
+// an arbitrary context thread (e.g. IOCTL loopback test function)
+// can process it.
+
+// (NOTE: Not revised for Linux)
+// This Q works like Tachyon's que - the producer points to the next
+// (unused) entry.
+void cpqfcTSPutScsiQue( CPQFCHBA *cpqfcHBAdata,
+  int Type, 
+  void *QueContent)
+{
+//  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+//  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+//  ULONG ndx;
+
+//  ULONG *pExchangeID;
+//  LONG ExchangeID;
+
+/*
+  KeAcquireSpinLockAtDpcLevel( &pDevExt->fcScsiQueLock);
+  ndx = pDevExt->fcScsiQue.producer + 1;  // test for Que full
+
+  if( ndx >= FC_SCSIQ_DEPTH ) // rollover test
+    ndx = 0;
+
+  if( ndx == pDevExt->fcScsiQue.consumer )   // QUE full test
+  {
+                       // QUE was full! lost LK command (fatal to logic)
+    fcChip->fcStats.ScsiQueFull++;
+#ifdef DBG
+    printk( "fcPutScsiQue - FULL!\n");
+#endif
+
+  }
+  else                        // QUE next element
+  {
+    pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].Type = Type;
+    
+    if( Type == FCP_RSP )
+    {
+      // this TL inbound message type means that a TL SEST exchange has
+      // copied an FCP response frame into a buffer pointed to by the SEST
+      // entry.  That buffer is allocated in the SEST structure at ->RspHDR.
+      // Copy the RspHDR for use by the Que handler.
+      pExchangeID = (ULONG *)QueContent;
+      
+      memcpy(
+	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
+        &fcChip->SEST->RspHDR[ *pExchangeID ],
+	      sizeof(pDevExt->fcScsiQue.Qitem[0].ulBuff)); // (any element for size)
+      
+    }
+    else
+    {
+      memcpy(
+	      pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff,
+        QueContent, 
+	      sizeof(pDevExt->fcScsiQue.Qitem[pDevExt->fcScsiQue.producer].ulBuff));
+    }
+      
+    pDevExt->fcScsiQue.producer = ndx;  // increment Que
+
+
+    KeSetEvent( &pDevExt->TYIBscsi,  // signal any waiting thread
+       0,                    // no priority boost
+		   FALSE );              // no waiting later for this event
+  }
+  KeReleaseSpinLockFromDpcLevel( &pDevExt->fcScsiQueLock);
+*/
+}
+
+
+
+
+
+
+
+static void ProcessELS_Request( CPQFCHBA*,TachFCHDR_GCMND*);
+
+static void ProcessELS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
+
+static void ProcessFCS_Reply( CPQFCHBA*,TachFCHDR_GCMND*);
+
+void cpqfcTSImplicitLogout( CPQFCHBA* cpqfcHBAdata,
+		PFC_LOGGEDIN_PORT pFcPort)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+
+  if( pFcPort->port_id != 0xFFFC01 ) // don't care about Fabric
+  {
+    fcChip->fcStats.logouts++;
+    printk("cpqfcTS: Implicit logout of WWN %08X%08X, port_id %06X\n", 
+        (ULONG)pFcPort->u.liWWN,
+        (ULONG)(pFcPort->u.liWWN >>32),
+	pFcPort->port_id);
+
+  // Terminate I/O with this (Linux) Scsi target
+    cpqfcTSTerminateExchange( cpqfcHBAdata, 
+                            &pFcPort->ScsiNexus,
+	                    DEVICE_REMOVED);
+  }
+			
+  // Do an "implicit logout" - we can't really Logout the device
+  // (i.e. with LOGOut Request) because of port_id confusion
+  // (i.e. the Other port has no port_id).
+  // A new login for that WWN will have to re-write port_id (0 invalid)
+  pFcPort->port_id = 0;  // invalid!
+  pFcPort->pdisc = FALSE;
+  pFcPort->prli = FALSE;
+  pFcPort->plogi = FALSE;
+  pFcPort->flogi = FALSE;
+  pFcPort->LOGO_timer = 0;
+  pFcPort->device_blocked = TRUE; // block Scsi Requests
+  pFcPort->ScsiNexus.VolumeSetAddressing=0;	
+}
+
+  
+// On FC-AL, there is a chance that a previously known device can
+// be quietly removed (e.g. with non-managed hub), 
+// while a NEW device (with different WWN) took the same alpa or
+// even 24-bit port_id.  This chance is unlikely but we must always
+// check for it.
+static void TestDuplicatePortId( CPQFCHBA* cpqfcHBAdata,
+		PFC_LOGGEDIN_PORT pLoggedInPort)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  // set "other port" at beginning of fcPorts list
+  PFC_LOGGEDIN_PORT pOtherPortWithPortId = fcChip->fcPorts.pNextPort;
+  while( pOtherPortWithPortId ) 
+  {
+    if( (pOtherPortWithPortId->port_id == 
+         pLoggedInPort->port_id) 
+		    &&
+         (pOtherPortWithPortId != pLoggedInPort) )
+    {
+      // trouble!  (Implicitly) Log the other guy out
+      printk(" *port_id %Xh is duplicated!* ", 
+        pOtherPortWithPortId->port_id);
+      cpqfcTSImplicitLogout( cpqfcHBAdata, pOtherPortWithPortId); 
+   }
+    pOtherPortWithPortId = pOtherPortWithPortId->pNextPort;
+  }
+}
+
+
+
+
+
+
+// Dynamic Memory Allocation for newly discovered FC Ports.
+// For simplicity, maintain fcPorts structs for ALL
+// for discovered devices, including those we never do I/O with
+// (e.g. Fabric addresses)
+
+static PFC_LOGGEDIN_PORT CreateFcPort( 
+	  CPQFCHBA* cpqfcHBAdata, 
+	  PFC_LOGGEDIN_PORT pLastLoggedInPort, 
+	  TachFCHDR_GCMND* fchs,
+	  LOGIN_PAYLOAD* plogi)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  PFC_LOGGEDIN_PORT pNextLoggedInPort = NULL;
+  int i;
+
+
+  printk("cpqfcTS: New FC port %06Xh WWN: ", fchs->s_id);
+  for( i=3; i>=0; i--)   // copy the LOGIN port's WWN
+    printk("%02X", plogi->port_name[i]);
+  for( i=7; i>3; i--)   // copy the LOGIN port's WWN
+    printk("%02X", plogi->port_name[i]);
+
+
+  // allocate mem for new port
+  // (these are small and rare allocations...)
+  pNextLoggedInPort = kmalloc( sizeof( FC_LOGGEDIN_PORT), GFP_ATOMIC );
+
+    
+  // allocation succeeded?  Fill out NEW PORT
+  if( pNextLoggedInPort )
+  {    
+                              // clear out any garbage (sometimes exists)
+    memset( pNextLoggedInPort, 0, sizeof( FC_LOGGEDIN_PORT));
+
+
+    // If we login to a Fabric, we don't want to treat it
+    // as a SCSI device...
+    if( (fchs->s_id & 0xFFF000) != 0xFFF000)
+    {
+      int i;
+      
+      // create a unique "virtual" SCSI Nexus (for now, just a
+      // new target ID) -- we will update channel/target on REPORT_LUNS
+      // special case for very first SCSI target...
+      if( cpqfcHBAdata->HostAdapter->max_id == 0)
+      {
+        pNextLoggedInPort->ScsiNexus.target = 0;
+        fcChip->fcPorts.ScsiNexus.target = -1; // don't use "stub"
+      }
+      else
+      {
+        pNextLoggedInPort->ScsiNexus.target =
+          cpqfcHBAdata->HostAdapter->max_id;
+      }
+
+      // initialize the lun[] Nexus struct for lun masking      
+      for( i=0; i< CPQFCTS_MAX_LUN; i++)
+        pNextLoggedInPort->ScsiNexus.lun[i] = 0xFF; // init to NOT USED
+      
+      pNextLoggedInPort->ScsiNexus.channel = 0; // cpqfcTS has 1 FC port
+      
+      printk(" SCSI Chan/Trgt %d/%d", 
+          pNextLoggedInPort->ScsiNexus.channel,
+          pNextLoggedInPort->ScsiNexus.target);
+ 
+      // tell Scsi layers about the new target...
+      cpqfcHBAdata->HostAdapter->max_id++; 
+//    printk("HostAdapter->max_id = %d\n",
+//      cpqfcHBAdata->HostAdapter->max_id);		    
+    }                          
+    else
+    {
+      // device is NOT SCSI (in case of Fabric)
+      pNextLoggedInPort->ScsiNexus.target = -1;  // invalid
+    }
+
+	  // create forward link to new port
+    pLastLoggedInPort->pNextPort = pNextLoggedInPort;
+    printk("\n");
+
+  }     
+  return pNextLoggedInPort;  // NULL on allocation failure
+}   // end NEW PORT (WWN) logic
+
+
+
+// For certain cases, we want to terminate exchanges without
+// sending ABTS to the device.  Examples include when an FC
+// device changed it's port_id after Loop re-init, or when
+// the device sent us a logout.  In the case of changed port_id,
+// we want to complete the command and return SOFT_ERROR to
+// force a re-try.  In the case of LOGOut, we might return
+// BAD_TARGET if the device is really gone.
+// Since we must ensure that Tachyon is not operating on the
+// exchange, we have to freeze the chip
+// sterminateex
+void cpqfcTSTerminateExchange( 
+  CPQFCHBA* cpqfcHBAdata, SCSI_NEXUS *ScsiNexus, int TerminateStatus)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG x_ID;
+
+  if( ScsiNexus )
+  {
+//    printk("TerminateExchange: ScsiNexus chan/target %d/%d\n",
+//		    ScsiNexus->channel, ScsiNexus->target);
+
+  } 
+  
+  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
+  {
+    if( Exchanges->fcExchange[x_ID].type )  // in use?
+    {
+      if( ScsiNexus == NULL ) // our HBA changed - term. all
+      {
+	Exchanges->fcExchange[x_ID].status = TerminateStatus;
+        cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); 
+      }
+      else
+      {
+	// If a device, according to WWN, has been removed, it's
+	// port_id may be used by another working device, so we
+	// have to terminate by SCSI target, NOT port_id.
+        if( Exchanges->fcExchange[x_ID].Cmnd) // Cmnd in progress?
+	{	                 
+	  if( (Exchanges->fcExchange[x_ID].Cmnd->device->id == ScsiNexus->target)
+			&&
+            (Exchanges->fcExchange[x_ID].Cmnd->device->channel == ScsiNexus->channel)) 
+          {
+            Exchanges->fcExchange[x_ID].status = TerminateStatus;
+            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &x_ID ); // timed-out
+          }
+	}
+
+	// (in case we ever need it...)
+	// all SEST structures have a remote node ID at SEST DWORD 2
+        //          if( (fcChip->SEST->u[ x_ID ].TWE.Remote_Node_ID >> 8)
+        //                ==  port_id)
+      } 
+    }
+  }
+}
+
+
+static void ProcessELS_Request( 
+              CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+//  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+//  ULONG ox_id = (fchs->ox_rx_id >>16);
+  PFC_LOGGEDIN_PORT pLoggedInPort=NULL, pLastLoggedInPort;
+  BOOLEAN NeedReject = FALSE;
+  ULONG ls_reject_code = 0; // default don'n know??
+
+
+  // Check the incoming frame for a supported ELS type
+  switch( fchs->pl[0] & 0xFFFF)
+  {
+  case 0x0050: //  PDISC?
+
+    // Payload for PLOGI and PDISC is identical (request & reply)
+    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
+    {
+      LOGIN_PAYLOAD logi;       // FC-PH Port Login
+      
+      // PDISC payload OK. If critical login fields
+      // (e.g. WWN) matches last login for this port_id,
+      // we may resume any prior exchanges
+      // with the other port
+
+      
+      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+   
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+	     NULL,     // don't search Scsi Nexus
+	     0,        // don't search linked list for port_id
+             &logi.port_name[0],     // search linked list for WWN
+             &pLastLoggedInPort);  // must return non-NULL; when a port_id
+                                   // is not found, this pointer marks the
+                                   // end of the singly linked list
+    
+      if( pLoggedInPort != NULL)   // WWN found (prior login OK)
+      { 
+           
+ 	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
+	{
+          // Yes.  We were expecting PDISC?
+          if( pLoggedInPort->pdisc )
+	  {
+	    // Yes; set fields accordingly.     (PDISC, not Originator)
+            SetLoginFields( pLoggedInPort, fchs, TRUE, FALSE);
+       
+            // send 'ACC' reply 
+            cpqfcTSPutLinkQue( cpqfcHBAdata, 
+                          ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
+                          fchs );
+
+	    // OK to resume I/O...
+	  }
+	  else
+ 	  {
+	    printk("Not expecting PDISC (pdisc=FALSE)\n");
+	    NeedReject = TRUE;
+	    // set reject reason code 
+            ls_reject_code = 
+              LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+	  }
+	}
+	else
+	{
+	  if( pLoggedInPort->port_id != 0)
+	  {
+  	    printk("PDISC PortID change: old %Xh, new %Xh\n",
+              pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
+	  }
+          NeedReject = TRUE;
+          // set reject reason code 
+          ls_reject_code = 
+	    LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+		  
+	}
+      }
+      else
+      {
+	printk("PDISC Request from unknown WWN\n");
+        NeedReject = TRUE;
+          
+	// set reject reason code 
+        ls_reject_code = 
+          LS_RJT_REASON( LOGICAL_ERROR, INVALID_PORT_NAME);
+      }
+
+    }
+    else // Payload unacceptable
+    {
+      printk("payload unacceptable\n");
+      NeedReject = TRUE;  // reject code already set
+      
+    }
+
+    if( NeedReject)
+    {
+      ULONG port_id;
+      // The PDISC failed.  Set login struct flags accordingly,
+      // terminate any I/O to this port, and Q a PLOGI
+      if( pLoggedInPort )
+      {
+        pLoggedInPort->pdisc = FALSE;
+        pLoggedInPort->prli = FALSE;
+        pLoggedInPort->plogi = FALSE;
+	
+        cpqfcTSTerminateExchange( cpqfcHBAdata, 
+          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+	port_id = pLoggedInPort->port_id;
+      }
+      else
+      {
+	port_id = fchs->s_id &0xFFFFFF;
+      }
+      fchs->reserved = ls_reject_code; // borrow this (unused) field
+      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
+    }
+   
+    break;
+
+
+
+  case 0x0003: //  PLOGI?
+
+    // Payload for PLOGI and PDISC is identical (request & reply)
+    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) ) // valid payload?
+    {
+      LOGIN_PAYLOAD logi;       // FC-PH Port Login
+      BOOLEAN NeedReject = FALSE;
+      
+      // PDISC payload OK. If critical login fields
+      // (e.g. WWN) matches last login for this port_id,
+      // we may resume any prior exchanges
+      // with the other port
+
+      
+      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+   
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+	     NULL,       // don't search Scsi Nexus
+	     0,        // don't search linked list for port_id
+             &logi.port_name[0],     // search linked list for WWN
+             &pLastLoggedInPort);  // must return non-NULL; when a port_id
+                                   // is not found, this pointer marks the
+                                   // end of the singly linked list
+    
+      if( pLoggedInPort == NULL)   // WWN not found -New Port
+      { 
+      	pLoggedInPort = CreateFcPort( 
+			  cpqfcHBAdata, 
+			  pLastLoggedInPort, 
+			  fchs,
+			  &logi);
+        if( pLoggedInPort == NULL )
+        {
+          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+          // Now Q a LOGOut Request, since we won't be talking to that device
+	
+          NeedReject = TRUE;  
+	  
+          // set reject reason code 
+          ls_reject_code = 
+            LS_RJT_REASON( LOGICAL_ERROR, NO_LOGIN_RESOURCES);
+	    
+	}
+      }
+      if( !NeedReject )
+      {
+      
+        // OK - we have valid fcPort ptr; set fields accordingly.   
+	//                         (not PDISC, not Originator)
+        SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE); 
+
+        // send 'ACC' reply 
+        cpqfcTSPutLinkQue( cpqfcHBAdata, 
+                      ELS_PLOGI_ACC, // (PDISC same as PLOGI ACC)
+                      fchs );
+      }
+    }
+    else // Payload unacceptable
+    {
+      printk("payload unacceptable\n");
+      NeedReject = TRUE;  // reject code already set
+    }
+
+    if( NeedReject)
+    {
+      // The PDISC failed.  Set login struct flags accordingly,
+      // terminate any I/O to this port, and Q a PLOGI
+      pLoggedInPort->pdisc = FALSE;
+      pLoggedInPort->prli = FALSE;
+      pLoggedInPort->plogi = FALSE;
+	
+      fchs->reserved = ls_reject_code; // borrow this (unused) field
+
+      // send 'RJT' reply 
+      cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_RJT, fchs );
+    }
+   
+    // terminate any exchanges with this device...
+    if( pLoggedInPort )
+    {
+      cpqfcTSTerminateExchange( cpqfcHBAdata, 
+        &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+    }
+    break;
+
+
+
+  case 0x1020:  // PRLI?
+  {
+    BOOLEAN NeedReject = TRUE;
+    pLoggedInPort = fcFindLoggedInPort( 
+           fcChip, 
+           NULL,       // don't search Scsi Nexus
+	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
+           NULL,     // DON'T search linked list for WWN
+           NULL);    // don't care
+      
+    if( pLoggedInPort == NULL ) 
+    {
+      // huh?
+      printk(" Unexpected PRLI Request -not logged in!\n");
+
+      // set reject reason code 
+      ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+      
+      // Q a LOGOut here?
+    }
+    else
+    {
+      // verify the PRLI ACC payload
+      if( !verify_PRLI( fchs, &ls_reject_code) )
+      {
+        // PRLI Reply is acceptable; were we expecting it?
+        if( pLoggedInPort->plogi ) 
+        { 
+  	  // yes, we expected the PRLI ACC  (not PDISC; not Originator)
+          SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
+
+          // Q an ACCept Reply
+	  cpqfcTSPutLinkQue( cpqfcHBAdata,
+                        ELS_PRLI_ACC, 
+                        fchs );   
+	  
+	  NeedReject = FALSE;
+	}
+        else
+        {
+          // huh?
+          printk(" (unexpected) PRLI REQEST with plogi FALSE\n");
+
+          // set reject reason code 
+          ls_reject_code = LS_RJT_REASON( PROTOCOL_ERROR, INITIATOR_CTL_ERROR);
+    
+    	  // Q a LOGOut here?
+	  
+        }
+      }
+      else
+      {
+        printk(" PRLI REQUEST payload failed verify\n");
+        // (reject code set by "verify")
+
+        // Q a LOGOut here?
+      }
+    }
+
+    if( NeedReject )
+    {
+      // Q a ReJecT Reply with reason code
+      fchs->reserved = ls_reject_code;
+      cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_RJT, // Q Type
+                    fchs );  
+    }
+  }
+    break;
+ 
+
+    
+
+  case  0x0005:  // LOGOut?
+  {
+  // was this LOGOUT because we sent a ELS_PDISC to an FC device
+  // with changed (or new) port_id, or does the port refuse 
+  // to communicate to us?
+  // We maintain a logout counter - if we get 3 consecutive LOGOuts,
+  // give up!
+    LOGOUT_PAYLOAD logo;
+    BOOLEAN GiveUpOnDevice = FALSE;
+    ULONG ls_reject_code = 0;
+    
+    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logo, sizeof(logo));
+
+    pLoggedInPort = fcFindLoggedInPort( 
+           fcChip, 
+           NULL,     // don't search Scsi Nexus
+	   0,        // don't search linked list for port_id
+           &logo.port_name[0],     // search linked list for WWN
+           NULL);    // don't care about end of list
+    
+    if( pLoggedInPort ) // found the device?
+    {
+      // Q an ACC reply 
+      cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_LOGO_ACC, // Q Type
+                    fchs );       // device to respond to
+
+      // set login struct fields (LOGO_counter increment)
+      SetLoginFields( pLoggedInPort, fchs, FALSE, FALSE);
+      
+      // are we an Initiator?
+      if( fcChip->Options.initiator)  
+      {
+        // we're an Initiator, so check if we should 
+	// try (another?) login
+
+	// Fabrics routinely log out from us after
+	// getting device info - don't try to log them
+	// back in.
+	if( (fchs->s_id & 0xFFF000) == 0xFFF000 )
+	{
+	  ; // do nothing
+	}
+	else if( pLoggedInPort->LOGO_counter <= 3)
+	{
+	  // try (another) login (PLOGI request)
+	  
+          cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_PLOGI, // Q Type
+                    fchs );  
+	
+	  // Terminate I/O with "retry" potential
+	  cpqfcTSTerminateExchange( cpqfcHBAdata, 
+			            &pLoggedInPort->ScsiNexus,
+				    PORTID_CHANGED);
+	}
+	else
+	{
+	  printk(" Got 3 LOGOuts - terminating comm. with port_id %Xh\n",
+			  fchs->s_id &&0xFFFFFF);
+	  GiveUpOnDevice = TRUE;
+	}
+      }
+      else
+      {
+	GiveUpOnDevice = TRUE;
+      }
+
+
+      if( GiveUpOnDevice == TRUE )
+      {
+        cpqfcTSTerminateExchange( cpqfcHBAdata, 
+	                          &pLoggedInPort->ScsiNexus,
+		                  DEVICE_REMOVED);
+      }
+    }  
+    else  // we don't know this WWN!
+    {
+      // Q a ReJecT Reply with reason code
+      fchs->reserved = ls_reject_code;
+      cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_RJT, // Q Type
+                    fchs );  
+    }
+  }
+    break;
+
+
+
+
+  // FABRIC only case
+  case 0x0461:  // ELS RSCN (Registered State Change Notification)?
+  {
+    int Ports;
+    int i;
+    __u32 Buff;
+    // Typically, one or more devices have been added to or dropped
+    // from the Fabric.
+    // The format of this frame is defined in FC-FLA (Rev 2.7, Aug 1997)
+    // The first 32-bit word has a 2-byte Payload Length, which
+    // includes the 4 bytes of the first word.  Consequently,
+    // this PL len must never be less than 4, must be a multiple of 4,
+    // and has a specified max value 256.
+    // (Endianess!)
+    Ports = ((fchs->pl[0] >>24) - 4) / 4;
+    Ports = Ports > 63 ? 63 : Ports;
+    
+    printk(" RSCN ports: %d\n", Ports);
+    if( Ports <= 0 )  // huh?
+    {
+      // ReJecT the command
+      fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 0);
+    
+      cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_RJT, // Q Type
+                    fchs ); 
+      
+      break;
+    }
+    else  // Accept the command
+    {
+       cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_ACC, // Q Type
+                    fchs ); 
+    }
+    
+      // Check the "address format" to determine action.
+      // We have 3 cases:
+      // 0 = Port Address; 24-bit address of affected device
+      // 1 = Area Address; MS 16 bits valid
+      // 2 = Domain Address; MS 8 bits valid
+    for( i=0; i<Ports; i++)
+    { 
+      BigEndianSwap( (UCHAR*)&fchs->pl[i+1],(UCHAR*)&Buff, 4);
+      switch( Buff & 0xFF000000)
+      {
+
+      case 0:  // Port Address?
+	
+      case 0x01000000: // Area Domain?
+      case 0x02000000: // Domain Address
+        // For example, "port_id" 0x201300 
+	// OK, let's try a Name Service Request (Query)
+      fchs->s_id = 0xFFFFFC;  // Name Server Address
+      cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
+
+      break;
+	
+	
+      default:  // huh? new value on version change?
+      break;
+      }
+    }
+  }    
+  break;    
+
+
+
+    
+  default:  // don't support this request (yet)
+    // set reject reason code 
+    fchs->reserved = LS_RJT_REASON( UNABLE_TO_PERFORM, 
+		                    REQUEST_NOT_SUPPORTED);
+    
+    cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_RJT, // Q Type
+                    fchs );     
+    break;  
+  }
+}
+
+
+static void ProcessELS_Reply( 
+		CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG ox_id = (fchs->ox_rx_id >>16);
+  ULONG ls_reject_code;
+  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+  
+  // If this is a valid reply, then we MUST have sent a request.
+  // Verify that we can find a valid request OX_ID corresponding to
+  // this reply
+
+  
+  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
+  {
+    printk(" *Discarding ACC/RJT frame, xID %04X/%04X* ", 
+		    ox_id, fchs->ox_rx_id & 0xffff);
+    goto Quit;  // exit this routine
+  }
+
+
+  // Is the reply a RJT (reject)?
+  if( (fchs->pl[0] & 0xFFFFL) == 0x01) // Reject reply?
+  {
+//  ******  REJECT REPLY  ********
+    switch( Exchanges->fcExchange[ox_id].type )
+    {
+	  
+    case ELS_FDISC:  // we sent out Fabric Discovery
+    case ELS_FLOGI:  // we sent out FLOGI
+
+      printk("RJT received on Fabric Login from %Xh, reason %Xh\n", 
+        fchs->s_id, fchs->pl[1]);    
+
+    break;
+
+    default:
+    break;
+    }
+      
+    goto Done;
+  }
+
+  // OK, we have an ACCept...
+  // What's the ACC type? (according to what we sent)
+  switch( Exchanges->fcExchange[ox_id].type )
+  {
+	  
+  case ELS_PLOGI:  // we sent out PLOGI
+    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
+    {
+      LOGIN_PAYLOAD logi;       // FC-PH Port Login
+      
+      // login ACC payload acceptable; search for WWN in our list
+      // of fcPorts
+      
+      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+   
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+	     NULL,     // don't search Scsi Nexus
+	     0,        // don't search linked list for port_id
+             &logi.port_name[0],     // search linked list for WWN
+             &pLastLoggedInPort);  // must return non-NULL; when a port_id
+                                   // is not found, this pointer marks the
+                                   // end of the singly linked list
+    
+      if( pLoggedInPort == NULL)         // WWN not found - new port
+      {
+
+	pLoggedInPort = CreateFcPort( 
+			  cpqfcHBAdata, 
+			  pLastLoggedInPort, 
+			  fchs,
+			  &logi);
+
+        if( pLoggedInPort == NULL )
+        {
+          printk(" cpqfcTS: New port allocation failed - lost FC device!\n");
+          // Now Q a LOGOut Request, since we won't be talking to that device
+	
+          goto Done;  // exit with error! dropped login frame
+	}
+      }
+      else      // WWN was already known.  Ensure that any open
+	        // exchanges for this WWN are terminated.
+      	// NOTE: It's possible that a device can change its 
+	// 24-bit port_id after a Link init or Fabric change 
+	// (e.g. LIP or Fabric RSCN).  In that case, the old
+	// 24-bit port_id may be duplicated, or no longer exist.
+      {
+
+        cpqfcTSTerminateExchange( cpqfcHBAdata, 
+          &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+      }
+
+      // We have an fcPort struct - set fields accordingly
+                                    // not PDISC, originator 
+      SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
+			
+      // We just set a "port_id"; is it duplicated?
+      TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
+
+      // For Fabric operation, we issued PLOGI to 0xFFFFFC
+      // so we can send SCR (State Change Registration) 
+      // Check for this special case...
+      if( fchs->s_id == 0xFFFFFC ) 
+      {
+        // PLOGI ACC was a Fabric response... issue SCR
+	fchs->s_id = 0xFFFFFD;  // address for SCR
+        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_SCR, fchs);
+      }
+
+      else
+      {
+      // Now we need a PRLI to enable FCP-SCSI operation
+      // set flags and Q up a ELS_PRLI
+        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PRLI, fchs);
+      }
+    }
+    else
+    {
+      // login payload unacceptable - reason in ls_reject_code
+      // Q up a Logout Request
+      printk("Login Payload unacceptable\n");
+
+    }
+    break;
+
+
+  // PDISC logic very similar to PLOGI, except we never want
+  // to allocate mem for "new" port, and we set flags differently
+  // (might combine later with PLOGI logic for efficiency)  
+  case ELS_PDISC:  // we sent out PDISC
+    if( !verify_PLOGI( fcChip, fchs, &ls_reject_code) )
+    {
+      LOGIN_PAYLOAD logi;       // FC-PH Port Login
+      BOOLEAN NeedLogin = FALSE;
+      
+      // login payload acceptable; search for WWN in our list
+      // of (previously seen) fcPorts
+      
+      BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+   
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+	     NULL,     // don't search Scsi Nexus
+	     0,        // don't search linked list for port_id
+             &logi.port_name[0],     // search linked list for WWN
+             &pLastLoggedInPort);  // must return non-NULL; when a port_id
+                                   // is not found, this pointer marks the
+                                   // end of the singly linked list
+    
+      if( pLoggedInPort != NULL)   // WWN found?
+      {
+        // WWN has same port_id as last login?  (Of course, a properly
+	// working FC device should NEVER ACCept a PDISC if it's
+	// port_id changed, but check just in case...)
+	if( (fchs->s_id & 0xFFFFFF) == pLoggedInPort->port_id)
+	{
+          // Yes.  We were expecting PDISC?
+          if( pLoggedInPort->pdisc )
+	  {
+            int i;
+	    
+	    
+	    // PDISC expected -- set fields.  (PDISC, Originator)
+            SetLoginFields( pLoggedInPort, fchs, TRUE, TRUE);
+
+	    // We are ready to resume FCP-SCSI to this device...
+            // Do we need to start anything that was Queued?
+
+            for( i=0; i< TACH_SEST_LEN; i++)
+            {
+              // see if any exchange for this PDISC'd port was queued
+              if( ((fchs->s_id &0xFFFFFF) == 
+                   (Exchanges->fcExchange[i].fchs.d_id & 0xFFFFFF))
+                      &&
+                  (Exchanges->fcExchange[i].status & EXCHANGE_QUEUED))
+              {
+                fchs->reserved = i; // copy ExchangeID
+//                printk(" *Q x_ID %Xh after PDISC* ",i);
+
+                cpqfcTSPutLinkQue( cpqfcHBAdata, EXCHANGE_QUEUED, fchs );
+              }
+            }
+
+	    // Complete commands Q'd while we were waiting for Login
+
+	    UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
+	  }
+	  else
+	  {
+	    printk("Not expecting PDISC (pdisc=FALSE)\n");
+	    NeedLogin = TRUE;
+	  }
+	}
+	else
+	{
+	  printk("PDISC PortID change: old %Xh, new %Xh\n",
+            pLoggedInPort->port_id, fchs->s_id &0xFFFFFF);
+          NeedLogin = TRUE;
+		  
+	}
+      }
+      else
+      {
+	printk("PDISC ACC from unknown WWN\n");
+        NeedLogin = TRUE;
+      }
+
+      if( NeedLogin)
+      {
+	
+        // The PDISC failed.  Set login struct flags accordingly,
+	// terminate any I/O to this port, and Q a PLOGI
+	if( pLoggedInPort )  // FC device previously known?
+	{
+
+          cpqfcTSPutLinkQue( cpqfcHBAdata,
+                    ELS_LOGO, // Q Type
+                    fchs );   // has port_id to send to 
+
+	  // There are a variety of error scenarios which can result
+  	  // in PDISC failure, so as a catchall, add the check for
+	  // duplicate port_id.
+	  TestDuplicatePortId( cpqfcHBAdata, pLoggedInPort);
+
+//    TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+          pLoggedInPort->pdisc = FALSE;
+          pLoggedInPort->prli = FALSE;
+          pLoggedInPort->plogi = FALSE;
+	
+          cpqfcTSTerminateExchange( cpqfcHBAdata, 
+	    &pLoggedInPort->ScsiNexus, PORTID_CHANGED);
+        }
+        cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs );
+      }
+    }
+    else
+    {
+      // login payload unacceptable - reason in ls_reject_code
+      // Q up a Logout Request
+      printk("ERROR: Login Payload unacceptable!\n");
+
+    }
+   
+    break;
+    
+
+
+  case ELS_PRLI:  // we sent out PRLI
+
+
+    pLoggedInPort = fcFindLoggedInPort( 
+           fcChip, 
+           NULL,       // don't search Scsi Nexus
+	   (fchs->s_id & 0xFFFFFF),  // search linked list for port_id
+           NULL,     // DON'T search linked list for WWN
+           NULL);    // don't care
+      
+    if( pLoggedInPort == NULL ) 
+    {
+      // huh?
+      printk(" Unexpected PRLI ACCept frame!\n");
+
+      // Q a LOGOut here?
+
+      goto Done;
+    }
+
+    // verify the PRLI ACC payload
+    if( !verify_PRLI( fchs, &ls_reject_code) )
+    {
+      // PRLI Reply is acceptable; were we expecting it?
+      if( pLoggedInPort->plogi ) 
+      { 
+	// yes, we expected the PRLI ACC  (not PDISC; Originator)
+	SetLoginFields( pLoggedInPort, fchs, FALSE, TRUE);
+
+        // OK, let's send a REPORT_LUNS command to determine
+	// whether VSA or PDA FCP-LUN addressing is used.
+	
+        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
+	
+	// It's possible that a device we were talking to changed 
+	// port_id, and has logged back in.  This function ensures
+	// that I/O will resume.
+        UnblockScsiDevice( cpqfcHBAdata->HostAdapter, pLoggedInPort);
+
+      }
+      else
+      {
+        // huh?
+        printk(" (unexpected) PRLI ACCept with plogi FALSE\n");
+
+        // Q a LOGOut here?
+        goto Done;
+      }
+    }
+    else
+    {
+      printk(" PRLI ACCept payload failed verify\n");
+
+      // Q a LOGOut here?
+    }
+
+    break;
+ 
+  case ELS_FLOGI:  // we sent out FLOGI (Fabric Login)
+
+    // update the upper 16 bits of our port_id in Tachyon
+    // the switch adds those upper 16 bits when responding
+    // to us (i.e. we are the destination_id)
+    fcChip->Registers.my_al_pa = (fchs->d_id & 0xFFFFFF);
+    writel( fcChip->Registers.my_al_pa,  
+      fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+
+    // now send out a PLOGI to the well known port_id 0xFFFFFC
+    fchs->s_id = 0xFFFFFC;
+    cpqfcTSPutLinkQue( cpqfcHBAdata, ELS_PLOGI, fchs);
+  
+   break; 
+
+
+  case ELS_FDISC:  // we sent out FDISC (Fabric Discovery (Login))
+
+   printk( " ELS_FDISC success ");
+   break;
+   
+
+  case ELS_SCR:  // we sent out State Change Registration
+    // now we can issue Name Service Request to find any
+    // Fabric-connected devices we might want to login to.
+   
+	
+    fchs->s_id = 0xFFFFFC;  // Name Server Address
+    cpqfcTSPutLinkQue( cpqfcHBAdata, FCS_NSR, fchs);
+    
+
+    break;
+
+    
+  default:
+    printk(" *Discarding unknown ACC frame, xID %04X/%04X* ", 
+   		    ox_id, fchs->ox_rx_id & 0xffff);
+    break;
+  }
+
+  
+Done:
+  // Regardless of whether the Reply is valid or not, the
+  // the exchange is done - complete
+  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16)); 
+	  
+Quit:    
+  return;
+}
+
+
+
+
+
+
+// ****************  Fibre Channel Services  **************
+// This is where we process the Directory (Name) Service Reply
+// to know which devices are on the Fabric
+
+static void ProcessFCS_Reply( 
+	CPQFCHBA* cpqfcHBAdata, TachFCHDR_GCMND* fchs)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG ox_id = (fchs->ox_rx_id >>16);
+//  ULONG ls_reject_code;
+//  PFC_LOGGEDIN_PORT pLoggedInPort, pLastLoggedInPort;
+  
+  // If this is a valid reply, then we MUST have sent a request.
+  // Verify that we can find a valid request OX_ID corresponding to
+  // this reply
+
+  if( Exchanges->fcExchange[(fchs->ox_rx_id >>16)].type == 0)
+  {
+    printk(" *Discarding Reply frame, xID %04X/%04X* ", 
+		    ox_id, fchs->ox_rx_id & 0xffff);
+    goto Quit;  // exit this routine
+  }
+
+
+  // OK, we were expecting it.  Now check to see if it's a
+  // "Name Service" Reply, and if so force a re-validation of
+  // Fabric device logins (i.e. Start the login timeout and
+  // send PDISC or PLOGI)
+  // (Endianess Byte Swap?)
+  if( fchs->pl[1] == 0x02FC )  // Name Service
+  {
+    // got a new (or NULL) list of Fabric attach devices... 
+    // Invalidate current logins
+    
+    PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts;
+    while( pLoggedInPort ) // for all ports which are expecting
+                           // PDISC after the next LIP, set the
+                           // logoutTimer
+    {
+
+      if( (pLoggedInPort->port_id & 0xFFFF00)  // Fabric device?
+		      &&
+          (pLoggedInPort->port_id != 0xFFFFFC) ) // NOT the F_Port
+      {
+        pLoggedInPort->LOGO_timer = 6;  // what's the Fabric timeout??
+                                // suspend any I/O in progress until
+                                // PDISC received...
+        pLoggedInPort->prli = FALSE;   // block FCP-SCSI commands
+      }
+	    
+      pLoggedInPort = pLoggedInPort->pNextPort;
+    }
+    
+    if( fchs->pl[2] == 0x0280)  // ACCept?
+    {
+      // Send PLOGI or PDISC to these Fabric devices
+      SendLogins( cpqfcHBAdata, &fchs->pl[4] );  
+    }
+
+
+    // As of this writing, the only reason to reject is because NO
+    // devices are left on the Fabric.  We already started
+    // "logged out" timers; if the device(s) don't come
+    // back, we'll do the implicit logout in the heart beat 
+    // timer routine
+    else  // ReJecT
+    {
+      // this just means no Fabric device is visible at this instant
+    } 
+  }
+
+  // Regardless of whether the Reply is valid or not, the
+  // the exchange is done - complete
+  cpqfcTSCompleteExchange(cpqfcHBAdata->PciDev, fcChip, (fchs->ox_rx_id >>16));
+	  
+Quit:    
+  return;
+}
+
+
+
+
+
+
+
+static void AnalyzeIncomingFrame( 
+        CPQFCHBA *cpqfcHBAdata,
+        ULONG QNdx )
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  PFC_LINK_QUE fcLQ = cpqfcHBAdata->fcLQ;
+  TachFCHDR_GCMND* fchs = 
+    (TachFCHDR_GCMND*)fcLQ->Qitem[QNdx].ulBuff;
+//  ULONG ls_reject_code;  // reason for rejecting login
+  LONG ExchangeID;
+//  FC_LOGGEDIN_PORT *pLoggedInPort;
+  BOOLEAN AbortAccept;  
+
+  ENTER("AnalyzeIncomingFrame");
+
+
+
+  switch( fcLQ->Qitem[QNdx].Type) // FCP or Unknown
+  {
+
+  case SFQ_UNKNOWN:  // unknown frame (e.g. LIP position frame, NOP, etc.)
+ 
+
+      // *********  FC-4 Device Data/ Fibre Channel Service *************
+    if( ((fchs->d_id &0xF0000000) == 0)   // R_CTL (upper nibble) 0x0?
+                &&   
+      (fchs->f_ctl & 0x20000000) )  // TYPE 20h is Fibre Channel Service
+    {
+
+      // ************** FCS Reply **********************
+
+      if( (fchs->d_id & 0xff000000L) == 0x03000000L)  // (31:23 R_CTL)
+      {
+	ProcessFCS_Reply( cpqfcHBAdata, fchs );
+
+      }  // end of  FCS logic
+
+    }
+    
+
+      // ***********  Extended Link Service **************
+
+    else if( fchs->d_id & 0x20000000   // R_CTL 0x2?
+                  &&   
+      (fchs->f_ctl & 0x01000000) )  // TYPE = 1
+    {
+
+                           // these frames are either a response to
+                           // something we sent (0x23) or "unsolicited"
+                           // frames (0x22).
+
+
+      // **************Extended Link REPLY **********************
+                           // R_CTL Solicited Control Reply
+
+      if( (fchs->d_id & 0xff000000L) == 0x23000000L)  // (31:23 R_CTL)
+      {
+
+	ProcessELS_Reply( cpqfcHBAdata, fchs );
+
+      }  // end of  "R_CTL Solicited Control Reply"
+
+
+
+
+       // **************Extended Link REQUEST **********************
+       // (unsolicited commands from another port or task...)
+
+                           // R_CTL Ext Link REQUEST
+      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
+              (fchs->ox_rx_id != 0xFFFFFFFFL) ) // (ignore LIP frame)
+      {
+
+
+
+	ProcessELS_Request( cpqfcHBAdata, fchs );
+
+      }
+
+
+
+        // ************** LILP **********************
+      else if( (fchs->d_id & 0xff000000L) == 0x22000000L &&
+               (fchs->ox_rx_id == 0xFFFFFFFFL)) // (e.g., LIP frames)
+
+      {
+        // SANMark specifies that when available, we must use
+	// the LILP frame to determine which ALPAs to send Port Discovery
+	// to...
+
+        if( fchs->pl[0] == 0x0711L) //  ELS_PLOGI?
+	{
+//	  UCHAR *ptr = (UCHAR*)&fchs->pl[1];
+//	  printk(" %d ALPAs found\n", *ptr);
+	  memcpy( fcChip->LILPmap, &fchs->pl[1], 32*4); // 32 DWORDs
+	  fcChip->Options.LILPin = 1; // our LILPmap is valid!
+	  // now post to make Port Discovery happen...
+          cpqfcTSPutLinkQue( cpqfcHBAdata, LINKACTIVE, fchs);  
+	}
+      }
+    }
+
+     
+    // *****************  BASIC LINK SERVICE *****************
+    
+    else if( fchs->d_id & 0x80000000  // R_CTL:
+                    &&           // Basic Link Service Request
+           !(fchs->f_ctl & 0xFF000000) )  // type=0 for BLS
+    {
+
+      // Check for ABTS (Abort Sequence)
+      if( (fchs->d_id & 0x8F000000) == 0x81000000)
+      {
+        // look for OX_ID, S_ID pair that matches in our
+        // fcExchanges table; if found, reply with ACCept and complete
+        // the exchange
+
+        // Per PLDA, an ABTS is sent by an initiator; therefore
+        // assume that if we have an exhange open to the port who
+        // sent ABTS, it will be the d_id of what we sent.  
+        for( ExchangeID = 0, AbortAccept=FALSE;
+             ExchangeID < TACH_SEST_LEN; ExchangeID++)
+        {
+            // Valid "target" exchange 24-bit port_id matches? 
+            // NOTE: For the case of handling Intiator AND Target
+            // functions on the same chip, we can have TWO Exchanges
+            // with the same OX_ID -- OX_ID/FFFF for the CMND, and
+            // OX_ID/RX_ID for the XRDY or DATA frame(s).  Ideally,
+            // we would like to support ABTS from Initiators or Targets,
+            // but it's not clear that can be supported on Tachyon for
+            // all cases (requires more investigation).
+            
+          if( (Exchanges->fcExchange[ ExchangeID].type == SCSI_TWE ||
+               Exchanges->fcExchange[ ExchangeID].type == SCSI_TRE)
+                  &&
+             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
+             (fchs->s_id & 0xFFFFFF)) )
+          {
+              
+              // target xchnge port_id matches -- how about OX_ID?
+            if( (Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id &0xFFFF0000)
+                    == (fchs->ox_rx_id & 0xFFFF0000) )
+                    // yes! post ACCept response; will be completed by fcStart
+            {
+              Exchanges->fcExchange[ ExchangeID].status = TARGET_ABORT;
+                
+                // copy (add) rx_id field for simplified ACCept reply
+              fchs->ox_rx_id = 
+                Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id;
+                
+              cpqfcTSPutLinkQue( cpqfcHBAdata,
+                            BLS_ABTS_ACC, // Q Type 
+                            fchs );    // void QueContent
+              AbortAccept = TRUE;
+      printk("ACCepting ABTS for x_ID %8.8Xh, SEST pair %8.8Xh\n", 
+             fchs->ox_rx_id, Exchanges->fcExchange[ ExchangeID].fchs.ox_rx_id);
+              break;      // ABTS can affect only ONE exchange -exit loop
+            }
+          }
+        }  // end of FOR loop
+        if( !AbortAccept ) // can't ACCept ABTS - send Reject
+        {
+      printk("ReJecTing: can't find ExchangeID %8.8Xh for ABTS command\n", 
+            fchs->ox_rx_id);
+          if( Exchanges->fcExchange[ ExchangeID].type 
+                &&
+              !(fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len
+               & 0x80000000))
+          {
+            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
+          }
+          else
+          {
+            printk("Unexpected ABTS ReJecT! SEST[%X] Dword 0: %Xh\n", 
+              ExchangeID, fcChip->SEST->u[ ExchangeID].IWE.Hdr_Len);
+          }
+        }
+      }
+
+      // Check for BLS {ABTS? (Abort Sequence)} ACCept
+      else if( (fchs->d_id & 0x8F000000) == 0x84000000)
+      {
+        // target has responded with ACC for our ABTS;
+	// complete the indicated exchange with ABORTED status 
+        // Make no checks for correct RX_ID, since
+	// all we need to conform ABTS ACC is the OX_ID.
+        // Verify that the d_id matches!
+ 
+        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
+//	printk("ABTS ACC x_ID 0x%04X 0x%04X, status %Xh\n", 
+//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff,
+//          Exchanges->fcExchange[ExchangeID].status);
+
+
+	
+        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
+        {
+            // Does "target" exchange 24-bit port_id match? 
+            // (See "NOTE" above for handling Intiator AND Target in
+            // the same device driver)
+            // First, if this is a target response, then we originated
+	    // (initiated) it with BLS_ABTS:
+	  
+          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
+
+                  &&
+	    // Second, does the source of this ACC match the destination
+            // of who we originally sent it to?
+             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
+             (fchs->s_id & 0xFFFFFF)) )
+          {
+            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
+	  }
+        }              
+      }
+      // Check for BLS {ABTS? (Abort Sequence)} ReJecT
+      else if( (fchs->d_id & 0x8F000000) == 0x85000000)
+      {
+        // target has responded with RJT for our ABTS;
+	// complete the indicated exchange with ABORTED status 
+        // Make no checks for correct RX_ID, since
+	// all we need to conform ABTS ACC is the OX_ID.
+        // Verify that the d_id matches!
+ 
+        ExchangeID = (fchs->ox_rx_id >> 16) & 0x7FFF; // x_id from ACC
+//	printk("BLS_ABTS RJT on Exchange 0x%04X 0x%04X\n", 
+//          fchs->ox_rx_id >> 16, fchs->ox_rx_id & 0xffff);
+
+        if( ExchangeID < TACH_SEST_LEN ) // x_ID makes sense
+	{  
+            // Does "target" exchange 24-bit port_id match? 
+            // (See "NOTE" above for handling Intiator AND Target in
+            // the same device driver)
+            // First, if this is a target response, then we originated
+	    // (initiated) it with BLS_ABTS:
+		  
+          if( (Exchanges->fcExchange[ ExchangeID].type == BLS_ABTS)
+
+                  &&
+	    // Second, does the source of this ACC match the destination
+            // of who we originally sent it to?
+             ((Exchanges->fcExchange[ ExchangeID].fchs.d_id & 0xFFFFFF) ==
+             (fchs->s_id & 0xFFFFFF)) )
+          {
+	    // YES! NOTE: There is a bug in CPQ's RA-4000 box 
+	    // where the "reason code" isn't returned in the payload
+	    // For now, simply presume the reject is because the target
+	    // already completed the exchange...
+	    
+//            printk("complete x_ID %Xh on ABTS RJT\n", ExchangeID);
+            cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID );
+	  }
+	} 
+      }  // end of ABTS check
+    }  // end of Basic Link Service Request
+    break;
+  
+    default:
+      printk("AnalyzeIncomingFrame: unknown type: %Xh(%d)\n",
+        fcLQ->Qitem[QNdx].Type,
+        fcLQ->Qitem[QNdx].Type);
+    break;
+  }
+}
+
+
+// Function for Port Discovery necessary after every FC 
+// initialization (e.g. LIP).
+// Also may be called if from Fabric Name Service logic.
+
+static void SendLogins( CPQFCHBA *cpqfcHBAdata, __u32 *FabricPortIds )
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG ulStatus=0;
+  TachFCHDR_GCMND fchs;  // copy fields for transmission
+  int i;
+  ULONG loginType;
+  LONG ExchangeID;
+  PFC_LOGGEDIN_PORT pLoggedInPort;
+  __u32 PortIds[ number_of_al_pa];
+  int NumberOfPorts=0;
+
+  // We're going to presume (for now) that our limit of Fabric devices
+  // is the same as the number of alpa on a private loop (126 devices).
+  // (Of course this could be changed to support however many we have
+  // memory for).
+  memset( &PortIds[0], 0, sizeof(PortIds));
+   
+  // First, check if this login is for our own Link Initialization
+  // (e.g. LIP on FC-AL), or if we have knowledge of Fabric devices
+  // from a switch.  If we are logging into Fabric devices, we'll
+  // have a non-NULL FabricPortId pointer
+  
+  if( FabricPortIds != NULL) // may need logins
+  {
+    int LastPort=FALSE;
+    i = 0;
+    while( !LastPort)
+    {
+      // port IDs From NSR payload; byte swap needed?
+      BigEndianSwap( (UCHAR*)FabricPortIds, (UCHAR*)&PortIds[i], 4);
+ 
+//      printk("FPortId[%d] %Xh ", i, PortIds[i]);
+      if( PortIds[i] & 0x80000000)
+	LastPort = TRUE;
+      
+      PortIds[i] &= 0xFFFFFF; // get 24-bit port_id
+      // some non-Fabric devices (like the Crossroads Fibre/Scsi bridge)
+      // erroneously use ALPA 0.
+      if( PortIds[i]  ) // need non-zero port_id...
+        i++;
+      
+      if( i >= number_of_al_pa ) // (in)sanity check
+	break;
+      FabricPortIds++;  // next...
+    }
+
+    NumberOfPorts = i;
+//    printk("NumberOf Fabric ports %d", NumberOfPorts);
+  }
+  
+  else  // need to send logins on our "local" link
+  {
+  
+    // are we a loop port?  If so, check for reception of LILP frame,
+    // and if received use it (SANMark requirement)
+    if( fcChip->Options.LILPin )
+    {
+      int j=0;
+      // sanity check on number of ALPAs from LILP frame...
+      // For format of LILP frame, see FC-AL specs or 
+      // "Fibre Channel Bench Reference", J. Stai, 1995 (ISBN 1-879936-17-8)
+      // First byte is number of ALPAs
+      i = fcChip->LILPmap[0] >= (32*4) ? 32*4 : fcChip->LILPmap[0];
+      NumberOfPorts = i;
+//      printk(" LILP alpa count %d ", i);
+      while( i > 0)
+      {
+	PortIds[j] = fcChip->LILPmap[1+ j];
+	j++; i--;
+      }
+    }
+    else  // have to send login to everybody
+    {
+      int j=0;
+      i = number_of_al_pa;
+      NumberOfPorts = i;
+      while( i > 0)
+      {
+        PortIds[j] = valid_al_pa[j]; // all legal ALPAs
+	j++; i--;
+      }
+    }
+  }
+
+
+  // Now we have a copy of the port_ids (and how many)...
+  for( i = 0; i < NumberOfPorts; i++)
+  {
+    // 24-bit FC Port ID
+    fchs.s_id = PortIds[i];  // note: only 8-bits used for ALPA
+
+
+    // don't log into ourselves (Linux Scsi disk scan will stop on
+    // no TARGET support error on us, and quit trying for rest of devices)
+    if( (fchs.s_id & 0xFF ) == (fcChip->Registers.my_al_pa & 0xFF) )
+      continue;
+
+    // fabric login needed?
+    if( (fchs.s_id == 0) || 
+        (fcChip->Options.fabric == 1) )
+    {
+      fcChip->Options.flogi = 1;  // fabric needs longer for login
+      // Do we need FLOGI or FDISC?
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+             NULL,           // don't search SCSI Nexus
+             0xFFFFFC,       // search linked list for Fabric port_id
+             NULL,           // don't search WWN
+             NULL);          // (don't care about end of list)
+
+      if( pLoggedInPort )    // If found, we have prior experience with
+                             // this port -- check whether PDISC is needed
+      {
+        if( pLoggedInPort->flogi )
+	{
+	  // does the switch support FDISC?? (FLOGI for now...)
+          loginType = ELS_FLOGI;  // prior FLOGI still valid
+	}
+        else
+          loginType = ELS_FLOGI;  // expired FLOGI
+      }
+      else                      // first FLOGI?
+        loginType = ELS_FLOGI;  
+
+
+      fchs.s_id = 0xFFFFFE;   // well known F_Port address
+
+      // Fabrics are not required to support FDISC, and
+      // it's not clear if that helps us anyway, since
+      // we'll want a Name Service Request to re-verify
+      // visible devices...
+      // Consequently, we always want our upper 16 bit
+      // port_id to be zero (we'll be rejected if we
+      // use our prior port_id if we've been plugged into
+      // a different switch port).
+      // Trick Tachyon to send to ALPA 0 (see TL/TS UG, pg 87)
+      // If our ALPA is 55h for instance, we want the FC frame
+      // s_id to be 0x000055, while Tach's my_al_pa register
+      // must be 0x000155, to force an OPN at ALPA 0 
+      // (the Fabric port)
+      fcChip->Registers.my_al_pa &= 0xFF; // only use ALPA for FLOGI
+      writel( fcChip->Registers.my_al_pa | 0x0100,  
+        fcChip->Registers.ReMapMemBase + TL_MEM_TACH_My_ID);
+    }
+
+    else // not FLOGI...
+    {
+      // should we send PLOGI or PDISC?  Check if any prior port_id
+      // (e.g. alpa) completed a PLOGI/PRLI exchange by checking 
+      // the pdisc flag.
+
+      pLoggedInPort = fcFindLoggedInPort( 
+             fcChip, 
+             NULL,           // don't search SCSI Nexus
+             fchs.s_id,      // search linked list for al_pa
+             NULL,           // don't search WWN
+             NULL);          // (don't care about end of list)
+
+             
+
+      if( pLoggedInPort )      // If found, we have prior experience with
+                             // this port -- check whether PDISC is needed
+      {
+        if( pLoggedInPort->pdisc )
+	{
+          loginType = ELS_PDISC;  // prior PLOGI and PRLI maybe still valid
+           
+	}
+        else
+          loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
+      }
+      else                      // never talked to this port_id before
+        loginType = ELS_PLOGI;  // prior knowledge, but can't use PDISC
+    }
+
+
+    
+    ulStatus = cpqfcTSBuildExchange(
+          cpqfcHBAdata,
+          loginType,            // e.g. PLOGI
+          &fchs,        // no incoming frame (we are originator)
+          NULL,         // no data (no scatter/gather list)
+          &ExchangeID );// fcController->fcExchanges index, -1 if failed
+
+    if( !ulStatus ) // Exchange setup OK?
+    {
+      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, ExchangeID );
+      if( !ulStatus )
+      {
+          // submitted to Tach's Outbound Que (ERQ PI incremented)
+          // waited for completion for ELS type (Login frames issued
+          // synchronously)
+
+	if( loginType == ELS_PDISC )
+	{
+	  // now, we really shouldn't Revalidate SEST exchanges until
+	  // we get an ACC reply from our target and verify that
+	  // the target address/WWN is unchanged.  However, when a fast
+	  // target gets the PDISC, they can send SEST Exchange data
+	  // before we even get around to processing the PDISC ACC.
+	  // Consequently, we lose the I/O.
+	  // To avoid this, go ahead and Revalidate when the PDISC goes
+	  // out, anticipating that the ACC will be truly acceptable
+	  // (this happens 99.9999....% of the time).
+	  // If we revalidate a SEST write, and write data goes to a
+	  // target that is NOT the one we originated the WRITE to,
+	  // that target is required (FCP-SCSI specs, etc) to discard 
+	  // our WRITE data.
+
+          // Re-validate SEST entries (Tachyon hardware assists)
+          RevalidateSEST( cpqfcHBAdata->HostAdapter, pLoggedInPort); 
+    //TriggerHBA( fcChip->Registers.ReMapMemBase, 1);
+	}
+      }
+      else  // give up immediately on error
+      {
+#ifdef LOGIN_DBG
+        printk("SendLogins: fcStartExchange failed: %Xh\n", ulStatus );
+#endif
+        break;
+      }
+
+              
+      if( fcChip->Registers.FMstatus.value & 0x080 ) // LDn during Port Disc.
+      {
+        ulStatus = LNKDWN_OSLS;
+#ifdef LOGIN_DBG
+        printk("SendLogins: PortDisc aborted (LDn) @alpa %Xh\n", fchs.s_id);
+#endif
+        break;
+      }
+        // Check the exchange for bad status (i.e. FrameTimeOut),
+        // and complete on bad status (most likely due to BAD_ALPA)
+        // on LDn, DPC function may already complete (ABORT) a started
+        // exchange, so check type first (type = 0 on complete).
+      if( Exchanges->fcExchange[ExchangeID].status )
+      {
+#ifdef LOGIN_DBG 
+ 	printk("completing x_ID %X on status %Xh\n", 
+          ExchangeID, Exchanges->fcExchange[ExchangeID].status);
+#endif
+        cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);
+      }
+    }
+    else   // Xchange setup failed...
+    {
+#ifdef LOGIN_DBG
+      printk("FC: cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+#endif
+      break;
+    }
+  }
+  if( !ulStatus )
+  {
+    // set the event signifying that all ALPAs were sent out.
+#ifdef LOGIN_DBG
+    printk("SendLogins: PortDiscDone\n");
+#endif
+    cpqfcHBAdata->PortDiscDone = 1;
+
+
+    // TL/TS UG, pg. 184
+    // 0x0065 = 100ms for RT_TOV
+    // 0x01f5 = 500ms for ED_TOV
+    fcChip->Registers.ed_tov.value = 0x006501f5L; 
+    writel( fcChip->Registers.ed_tov.value,
+      (fcChip->Registers.ed_tov.address));
+
+    // set the LP_TOV back to ED_TOV (i.e. 500 ms)
+    writel( 0x00000010, fcChip->Registers.ReMapMemBase +TL_MEM_FM_TIMEOUT2);
+  }
+  else
+  {
+    printk("SendLogins: failed at xchng %Xh, alpa %Xh, status %Xh\n", 
+      ExchangeID, fchs.s_id, ulStatus);
+  }
+  LEAVE("SendLogins");
+
+}
+
+
+// for REPORT_LUNS documentation, see "In-Depth Exploration of Scsi",
+// D. Deming, 1994, pg 7-19 (ISBN 1-879936-08-9)
+static void ScsiReportLunsDone(Scsi_Cmnd *Cmnd)
+{
+  struct Scsi_Host *HostAdapter = Cmnd->device->host;
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  PFC_LOGGEDIN_PORT pLoggedInPort; 
+  int LunListLen=0;
+  int i;
+  ULONG x_ID = 0xFFFFFFFF;
+  UCHAR *ucBuff = Cmnd->request_buffer;
+
+//  printk("cpqfcTS: ReportLunsDone \n");
+  // first, we need to find the Exchange for this command,
+  // so we can find the fcPort struct to make the indicated
+  // changes.
+  for( i=0; i< TACH_SEST_LEN; i++)
+  {
+    if( Exchanges->fcExchange[i].type   // exchange defined?
+                   &&
+       (Exchanges->fcExchange[i].Cmnd == Cmnd) ) // matches?
+	      
+    {
+      x_ID = i;  // found exchange!
+      break;
+    }
+  }
+  if( x_ID == 0xFFFFFFFF)
+  {
+//    printk("cpqfcTS: ReportLuns failed - no FC Exchange\n");
+    goto Done;  // Report Luns FC Exchange gone; 
+                // exchange probably Terminated by Implicit logout
+  }
+
+
+  // search linked list for the port_id we sent INQUIRY to
+  pLoggedInPort = fcFindLoggedInPort( fcChip,
+    NULL,     // DON'T search Scsi Nexus (we will set it)
+    Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
+    NULL,     // DON'T search linked list for FC WWN
+    NULL);    // DON'T care about end of list
+ 
+  if( !pLoggedInPort )
+  {
+//    printk("cpqfcTS: ReportLuns failed - device gone\n");
+    goto Done; // error! can't find logged in Port
+  }    
+  LunListLen = ucBuff[3];
+  LunListLen += ucBuff[2]>>8;
+
+  if( !LunListLen )  // failed
+  {
+    // generically speaking, a soft error means we should retry...
+    if( (Cmnd->result >> 16) == DID_SOFT_ERROR )
+    {
+      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
+	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
+      {
+        TachFCHDR_GCMND *fchs = &Exchanges->fcExchange[ x_ID].fchs;
+      // did we fail because of "check condition, device reset?"
+      // e.g. the device was reset (i.e., at every power up)
+      // retry the Report Luns
+      
+      // who are we sending it to?
+      // we know this because we have a copy of the command
+      // frame from the original Report Lun command -
+      // switch the d_id/s_id fields, because the Exchange Build
+      // context is "reply to source".
+      
+        fchs->s_id = fchs->d_id; // (temporarily re-use the struct)
+        cpqfcTSPutLinkQue( cpqfcHBAdata, SCSI_REPORT_LUNS, fchs );
+      }
+    }
+    else  // probably, the device doesn't support Report Luns
+      pLoggedInPort->ScsiNexus.VolumeSetAddressing = 0;  
+  }
+  else  // we have LUN info - check VSA mode
+  {
+    // for now, assume all LUNs will have same addr mode
+    // for VSA, payload byte 8 will be 0x40; otherwise, 0
+    pLoggedInPort->ScsiNexus.VolumeSetAddressing = ucBuff[8];  
+      
+    // Since we got a Report Luns answer, set lun masking flag
+    pLoggedInPort->ScsiNexus.LunMasking = 1;
+
+    if( LunListLen > 8*CPQFCTS_MAX_LUN)   // We expect CPQFCTS_MAX_LUN max
+      LunListLen = 8*CPQFCTS_MAX_LUN;
+
+/*   
+    printk("Device WWN %08X%08X Reports Luns @: ", 
+          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+          (ULONG)(pLoggedInPort->u.liWWN>>32));
+	    
+    for( i=8; i<LunListLen+8; i+=8)
+    {  
+      printk("%02X%02X ", ucBuff[i], ucBuff[i+1] );
+    }
+    printk("\n");
+*/
+    
+    // Since the device was kind enough to tell us where the
+    // LUNs are, lets ensure they are contiguous for Linux's
+    // SCSI driver scan, which expects them to start at 0.
+    // Since Linux only supports 8 LUNs, only copy the first
+    // eight from the report luns command
+
+    // e.g., the Compaq RA4x00 f/w Rev 2.54 and above may report
+    // LUNs 4001, 4004, etc., because other LUNs are masked from
+    // this HBA (owned by someone else).  We'll make those appear as
+    // LUN 0, 1... to Linux
+    {
+      int j;
+      int AppendLunList = 0;
+      // Walk through the LUN list.  The 'j' array number is
+      // Linux's lun #, while the value of .lun[j] is the target's
+      // lun #.
+      // Once we build a LUN list, it's possible for a known device 
+      // to go offline while volumes (LUNs) are added.  Later,
+      // the device will do another PLOGI ... Report Luns command,
+      // and we must not alter the existing Linux Lun map.
+      // (This will be very rare).
+      for( j=0; j < CPQFCTS_MAX_LUN; j++)
+      {
+        if( pLoggedInPort->ScsiNexus.lun[j] != 0xFF )
+	{
+	  AppendLunList = 1;
+	  break;
+	}
+      }
+      if( AppendLunList )
+      {
+	int k;
+        int FreeLunIndex;
+//        printk("cpqfcTS: AppendLunList\n");
+
+	// If we get a new Report Luns, we cannot change
+	// any existing LUN mapping! (Only additive entry)
+	// For all LUNs in ReportLun list
+	// if RL lun != ScsiNexus lun
+	//   if RL lun present in ScsiNexus lun[], continue
+	//   else find ScsiNexus lun[]==FF and add, continue
+	
+        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
+	{
+          if( pLoggedInPort->ScsiNexus.lun[j] != ucBuff[i+1] )
+	  {
+	    // something changed from the last Report Luns
+	    printk(" cpqfcTS: Report Lun change!\n");
+	    for( k=0, FreeLunIndex=CPQFCTS_MAX_LUN; 
+                 k < CPQFCTS_MAX_LUN; k++)
+            {
+	      if( pLoggedInPort->ScsiNexus.lun[k] == 0xFF)
+	      {
+		FreeLunIndex = k;
+		break;
+	      }
+              if( pLoggedInPort->ScsiNexus.lun[k] == ucBuff[i+1] )
+		break; // we already masked this lun
+	    }
+	    if( k >= CPQFCTS_MAX_LUN )
+	    {
+	      printk(" no room for new LUN %d\n", ucBuff[i+1]);
+	    }
+	    else if( k == FreeLunIndex )  // need to add LUN
+	    {
+	      pLoggedInPort->ScsiNexus.lun[k] = ucBuff[i+1];
+//	      printk("add [%d]->%02d\n", k, pLoggedInPort->ScsiNexus.lun[k]);
+	      
+	    }
+	    else
+	    {
+	      // lun already known
+	    }
+	    break;
+	  }
+	}
+	// print out the new list...
+	for( j=0; j< CPQFCTS_MAX_LUN; j++)
+	{
+	  if( pLoggedInPort->ScsiNexus.lun[j] == 0xFF)
+	    break; // done
+//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+	}
+      }
+      else
+      {
+//	  printk("Linux SCSI LUNs[] -> Device LUNs: ");
+	// first time - this is easy
+        for( i=8, j=0; i<LunListLen+8 && j< CPQFCTS_MAX_LUN; i+=8, j++)
+	{
+          pLoggedInPort->ScsiNexus.lun[j] = ucBuff[i+1];
+//	  printk("[%d]->%02d ", j, pLoggedInPort->ScsiNexus.lun[j]);
+	}
+//	printk("\n");
+      }
+    }
+  }
+
+Done: ;
+}
+
+extern int is_private_data_of_cpqfc(CPQFCHBA *hba, void * pointer);
+extern void cpqfc_free_private_data(CPQFCHBA *hba, cpqfc_passthru_private_t *data);
+
+static void 
+call_scsi_done(Scsi_Cmnd *Cmnd)
+{
+	CPQFCHBA *hba;
+	hba = (CPQFCHBA *) Cmnd->device->host->hostdata;
+	// Was this command a cpqfc passthru ioctl ?
+        if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL && 
+		Cmnd->device->host->hostdata != NULL &&
+		is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
+			Cmnd->sc_request->upper_private_data)) {
+		cpqfc_free_private_data(hba, 
+			Cmnd->sc_request->upper_private_data);	
+		Cmnd->sc_request->upper_private_data = NULL;
+		Cmnd->result &= 0xff00ffff;
+		Cmnd->result |= (DID_PASSTHROUGH << 16);  // prevents retry
+	}
+	if (Cmnd->scsi_done != NULL)
+		(*Cmnd->scsi_done)(Cmnd);
+}
+
+// After successfully getting a "Process Login" (PRLI) from an
+// FC port, we want to Discover the LUNs so that we know the
+// addressing type (e.g., FCP-SCSI Volume Set Address, Peripheral
+// Unit Device), and whether SSP (Selective Storage Presentation or
+// Lun Masking) has made the LUN numbers non-zero based or 
+// non-contiguous.  To remain backward compatible with the SCSI-2
+// driver model, which expects a contiguous LUNs starting at 0,
+// will use the ReportLuns info to map from "device" to "Linux" 
+// LUNs.
+static void IssueReportLunsCommand( 
+              CPQFCHBA* cpqfcHBAdata, 
+	      TachFCHDR_GCMND* fchs)
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  PFC_LOGGEDIN_PORT pLoggedInPort; 
+  struct scsi_cmnd *Cmnd = NULL;
+  struct scsi_device *ScsiDev = NULL;
+  LONG x_ID;
+  ULONG ulStatus;
+  UCHAR *ucBuff;
+
+  if( !cpqfcHBAdata->PortDiscDone) // cleared by LDn
+  {
+    printk("Discard Q'd ReportLun command\n");
+    goto Done;
+  }
+
+  // find the device (from port_id) we're talking to
+  pLoggedInPort = fcFindLoggedInPort( fcChip,
+        NULL,     // DON'T search Scsi Nexus 
+  	fchs->s_id & 0xFFFFFF,        
+	NULL,     // DON'T search linked list for FC WWN
+        NULL);    // DON'T care about end of list
+  if( pLoggedInPort ) // we'd BETTER find it!
+  {
+
+
+    if( !(pLoggedInPort->fcp_info & TARGET_FUNCTION) )
+      goto Done;  // forget it - FC device not a "target"
+
+ 
+    ScsiDev = scsi_get_host_dev (cpqfcHBAdata->HostAdapter);
+    if (!ScsiDev)
+      goto Done;
+    
+    Cmnd = scsi_get_command (ScsiDev, GFP_KERNEL);
+    if (!Cmnd) 
+      goto Done;
+
+    ucBuff = pLoggedInPort->ReportLunsPayload;
+    
+    memset( ucBuff, 0, REPORT_LUNS_PL);
+    
+    Cmnd->scsi_done = ScsiReportLunsDone;
+
+    Cmnd->request_buffer = pLoggedInPort->ReportLunsPayload; 
+    Cmnd->request_bufflen = REPORT_LUNS_PL; 
+	    
+    Cmnd->cmnd[0] = 0xA0;
+    Cmnd->cmnd[8] = REPORT_LUNS_PL >> 8;
+    Cmnd->cmnd[9] = (UCHAR)REPORT_LUNS_PL;
+    Cmnd->cmd_len = 12;
+
+    Cmnd->device->channel = pLoggedInPort->ScsiNexus.channel;
+    Cmnd->device->id = pLoggedInPort->ScsiNexus.target;
+
+	    
+    ulStatus = cpqfcTSBuildExchange(
+      cpqfcHBAdata,
+      SCSI_IRE, 
+      fchs,
+      Cmnd,         // buffer for Report Lun data
+      &x_ID );// fcController->fcExchanges index, -1 if failed
+
+    if( !ulStatus ) // Exchange setup?
+    {
+      ulStatus = cpqfcTSStartExchange( cpqfcHBAdata, x_ID );
+      if( !ulStatus )
+      {
+        // submitted to Tach's Outbound Que (ERQ PI incremented)
+        // waited for completion for ELS type (Login frames issued
+        // synchronously)
+      }
+      else
+        // check reason for Exchange not being started - we might
+        // want to Queue and start later, or fail with error
+      {
+  
+      }
+    }
+
+    else   // Xchange setup failed...
+      printk(" cpqfcTSBuildExchange failed: %Xh\n", ulStatus );
+  }
+  else     // like, we just got a PRLI ACC, and now the port is gone?
+  {
+    printk(" can't send ReportLuns - no login for port_id %Xh\n",
+	    fchs->s_id & 0xFFFFFF);
+  }
+
+
+
+Done:
+
+  if (Cmnd)
+    scsi_put_command (Cmnd);
+  if (ScsiDev) 
+    scsi_free_host_dev (ScsiDev);
+}
+
+
+
+
+
+
+
+static void CompleteBoardLockCmnd( CPQFCHBA *cpqfcHBAdata)
+{
+  int i;
+  for( i = CPQFCTS_REQ_QUEUE_LEN-1; i>= 0; i--)
+  {
+    if( cpqfcHBAdata->BoardLockCmnd[i] != NULL )
+    {
+      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BoardLockCmnd[i];
+      cpqfcHBAdata->BoardLockCmnd[i] = NULL;
+      Cmnd->result = (DID_SOFT_ERROR << 16);  // ask for retry
+//      printk(" BoardLockCmnd[%d] %p Complete, chnl/target/lun %d/%d/%d\n",
+//        i,Cmnd, Cmnd->channel, Cmnd->target, Cmnd->lun);
+      call_scsi_done(Cmnd);
+    }
+  }
+}
+
+
+
+
+
+
+// runs every 1 second for FC exchange timeouts and implicit FC device logouts
+
+void cpqfcTSheartbeat( unsigned long ptr )
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)ptr;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
+  ULONG i;
+  unsigned long flags;
+  DECLARE_MUTEX_LOCKED(BoardLock);
+  
+  PCI_TRACE( 0xA8)
+
+  if( cpqfcHBAdata->BoardLock) // Worker Task Running?
+    goto Skip;
+
+  // STOP _que function
+  spin_lock_irqsave( cpqfcHBAdata->HostAdapter->host_lock, flags); 
+
+  PCI_TRACE( 0xA8)
+
+
+  cpqfcHBAdata->BoardLock = &BoardLock; // stop Linux SCSI command queuing
+  
+  // release the IO lock (and re-enable interrupts)
+  spin_unlock_irqrestore( cpqfcHBAdata->HostAdapter->host_lock, flags);
+  
+  // Ensure no contention from  _quecommand or Worker process 
+  CPQ_SPINLOCK_HBA( cpqfcHBAdata)
+  
+  PCI_TRACE( 0xA8)
+  
+
+  disable_irq( cpqfcHBAdata->HostAdapter->irq);  // our IRQ
+
+  // Complete the "bad target" commands (normally only used during
+  // initialization, since we aren't supposed to call "scsi_done"
+  // inside the queuecommand() function).  (this is overly contorted,
+  // scsi_done can be safely called from queuecommand for
+  // this bad target case.  May want to simplify this later)
+
+  for( i=0; i< CPQFCTS_MAX_TARGET_ID; i++)
+  {
+    if( cpqfcHBAdata->BadTargetCmnd[i] )
+    {
+      Scsi_Cmnd *Cmnd = cpqfcHBAdata->BadTargetCmnd[i];
+      cpqfcHBAdata->BadTargetCmnd[i] = NULL;
+      Cmnd->result = (DID_BAD_TARGET << 16);
+      call_scsi_done(Cmnd);
+    }
+    else
+      break;
+  }
+
+  
+  // logged in ports -- re-login check (ports required to verify login with
+  // PDISC after LIP within 2 secs)
+
+  // prevent contention
+  while( pLoggedInPort ) // for all ports which are expecting
+                         // PDISC after the next LIP, check to see if
+                         // time is up!
+  {
+      // Important: we only detect "timeout" condition on TRANSITION
+      // from non-zero to zero
+    if( pLoggedInPort->LOGO_timer )  // time-out "armed"?
+    {
+      if( !(--pLoggedInPort->LOGO_timer) ) // DEC from 1 to 0?
+      {
+          // LOGOUT time!  Per PLDA, PDISC hasn't complete in 2 secs, so
+          // issue LOGO request and destroy all I/O with other FC port(s).
+        
+/*          
+        printk(" ~cpqfcTS heartbeat: LOGOut!~ ");
+        printk("Linux SCSI Chanl/Target %d/%d (port_id %06Xh) WWN %08X%08X\n", 
+        pLoggedInPort->ScsiNexus.channel, 
+        pLoggedInPort->ScsiNexus.target, 
+	pLoggedInPort->port_id,
+          (ULONG)(pLoggedInPort->u.liWWN &0xFFFFFFFF), 
+          (ULONG)(pLoggedInPort->u.liWWN>>32));
+
+*/
+        cpqfcTSImplicitLogout( cpqfcHBAdata, pLoggedInPort);
+
+      }
+      // else simply decremented - maybe next time...
+    }
+    pLoggedInPort = pLoggedInPort->pNextPort;
+  }
+
+
+
+  
+  
+  // ************  FC EXCHANGE TIMEOUT CHECK **************
+  
+  for( i=0; i< TACH_MAX_XID; i++)
+  {
+    if( Exchanges->fcExchange[i].type )  // exchange defined?
+    {
+
+      if( !Exchanges->fcExchange[i].timeOut ) // time expired
+      {
+        // Set Exchange timeout status
+        Exchanges->fcExchange[i].status |= FC2_TIMEOUT;
+
+        if( i >= TACH_SEST_LEN ) // Link Service Exchange
+        {
+          cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, i);  // Don't "abort" LinkService
+        }
+        
+        else  // SEST Exchange TO -- may post ABTS to Worker Thread Que
+        {
+	  // (Make sure we don't keep timing it out; let other functions
+	  // complete it or set the timeOut as needed)
+	  Exchanges->fcExchange[i].timeOut = 30000; // seconds default
+
+          if( Exchanges->fcExchange[i].type 
+                  & 
+              (BLS_ABTS | BLS_ABTS_ACC )  )
+          {
+	    // For BLS_ABTS*, an upper level might still have
+	    // an outstanding command waiting for low-level completion.
+	    // Also, in the case of a WRITE, we MUST get confirmation
+	    // of either ABTS ACC or RJT before re-using the Exchange.
+	    // It's possible that the RAID cache algorithm can hang
+	    // if we fail to complete a WRITE to a LBA, when a READ
+	    // comes later to that same LBA.  Therefore, we must
+	    // ensure that the target verifies receipt of ABTS for
+	    // the exchange
+	   
+	    printk("~TO Q'd ABTS (x_ID %Xh)~ ", i); 
+//            TriggerHBA( fcChip->Registers.ReMapMemBase);
+
+	    // On timeout of a ABTS exchange, check to
+	    // see if the FC device has a current valid login.
+	    // If so, restart it.
+	    pLoggedInPort = fcFindLoggedInPort( fcChip,
+              Exchanges->fcExchange[i].Cmnd, // find Scsi Nexus
+              0,        // DON'T search linked list for FC port id
+	      NULL,     // DON'T search linked list for FC WWN
+              NULL);    // DON'T care about end of list
+
+	    // device exists?
+	    if( pLoggedInPort ) // device exists?
+	    {
+	      if( pLoggedInPort->prli ) // logged in for FCP-SCSI?
+	      {
+		// attempt to restart the ABTS
+		printk(" ~restarting ABTS~ ");
+                cpqfcTSStartExchange( cpqfcHBAdata, i );
+
+	      }
+	    }
+          }
+	  else  // not an ABTS
+	  { 
+           
+            // We expect the WorkerThread to change the xchng type to
+            // abort and set appropriate timeout.
+            cpqfcTSPutLinkQue( cpqfcHBAdata, BLS_ABTS, &i ); // timed-out
+	  }
+        }
+      }
+      else  // time not expired...
+      {
+        // decrement timeout: 1 or more seconds left
+        --Exchanges->fcExchange[i].timeOut;
+      }
+    }
+  }
+
+
+  enable_irq( cpqfcHBAdata->HostAdapter->irq);
+ 
+
+  CPQ_SPINUNLOCK_HBA( cpqfcHBAdata)
+
+  cpqfcHBAdata->BoardLock = NULL; // Linux SCSI commands may be queued
+
+  // Now, complete any Cmnd we Q'd up while BoardLock was held
+
+  CompleteBoardLockCmnd( cpqfcHBAdata);
+ 
+
+  // restart the timer to run again (1 sec later)
+Skip:
+  mod_timer( &cpqfcHBAdata->cpqfcTStimer, jiffies + HZ);
+  
+  PCI_TRACEO( i, 0xA8)
+  return;
+}
+
+
+// put valid FC-AL physical address in spec order
+static const UCHAR valid_al_pa[]={
+    0xef, 0xe8, 0xe4, 0xe2, 
+    0xe1, 0xE0, 0xDC, 0xDA, 
+    0xD9, 0xD6, 0xD5, 0xD4, 
+    0xD3, 0xD2, 0xD1, 0xCe, 
+    0xCd, 0xCc, 0xCb, 0xCa, 
+    0xC9, 0xC7, 0xC6, 0xC5, 
+    0xC3, 0xBc, 0xBa, 0xB9,
+    0xB6, 0xB5, 0xB4, 0xB3, 
+    0xB2, 0xB1, 0xae, 0xad,
+    0xAc, 0xAb, 0xAa, 0xA9, 
+
+    0xA7, 0xA6, 0xA5, 0xA3, 
+    0x9f, 0x9e, 0x9d, 0x9b, 
+    0x98, 0x97, 0x90, 0x8f, 
+    0x88, 0x84, 0x82, 0x81, 
+    0x80, 0x7c, 0x7a, 0x79, 
+    0x76, 0x75, 0x74, 0x73, 
+    0x72, 0x71, 0x6e, 0x6d, 
+    0x6c, 0x6b, 0x6a, 0x69, 
+    0x67, 0x66, 0x65, 0x63, 
+    0x5c, 0x5a, 0x59, 0x56, 
+    
+    0x55, 0x54, 0x53, 0x52, 
+    0x51, 0x4e, 0x4d, 0x4c, 
+    0x4b, 0x4a, 0x49, 0x47, 
+    0x46, 0x45, 0x43, 0x3c,
+    0x3a, 0x39, 0x36, 0x35, 
+    0x34, 0x33, 0x32, 0x31, 
+    0x2e, 0x2d, 0x2c, 0x2b, 
+    0x2a, 0x29, 0x27, 0x26, 
+    0x25, 0x23, 0x1f, 0x1E,
+    0x1d, 0x1b, 0x18, 0x17, 
+
+    0x10, 0x0f, 8, 4, 2, 1 }; // ALPA 0 (Fabric) is special case
+
+const int number_of_al_pa = (sizeof(valid_al_pa) );
+
+
+
+// this function looks up an al_pa from the table of valid al_pa's
+// we decrement from the last decimal loop ID, because soft al_pa
+// (our typical case) are assigned with highest priority (and high al_pa)
+// first.  See "In-Depth FC-AL", R. Kembel pg. 38
+// INPUTS:
+//   al_pa - 24 bit port identifier (8 bit al_pa on private loop)
+// RETURN:
+//  Loop ID - serves are index to array of logged in ports
+//  -1      - invalid al_pa (not all 8 bit values are legal)
+
+#if (0)
+static int GetLoopID( ULONG al_pa )
+{
+  int i;
+
+  for( i = number_of_al_pa -1; i >= 0; i--)  // dec.
+  {
+    if( valid_al_pa[i] == (UCHAR)al_pa )  // take lowest 8 bits
+      return i;  // success - found valid al_pa; return decimal LoopID
+  }
+  return -1; // failed - not found
+}
+#endif
+
+extern cpqfc_passthru_private_t *cpqfc_private(Scsi_Request *sr);
+
+// Search the singly (forward) linked list "fcPorts" looking for 
+// either the SCSI target (if != -1), port_id (if not NULL), 
+// or WWN (if not null), in that specific order.
+// If we find a SCSI nexus (from Cmnd arg), set the SCp.phase
+// field according to VSA or PDU
+// RETURNS:
+//   Ptr to logged in port struct if found
+//     (NULL if not found)
+//   pLastLoggedInPort - ptr to last struct (for adding new ones)
+// 
+PFC_LOGGEDIN_PORT  fcFindLoggedInPort( 
+  PTACHYON fcChip, 
+  Scsi_Cmnd *Cmnd, // search linked list for Scsi Nexus (channel/target/lun)
+  ULONG port_id,   // search linked list for al_pa, or
+  UCHAR wwn[8],    // search linked list for WWN, or...
+  PFC_LOGGEDIN_PORT *pLastLoggedInPort )
+             
+{
+  PFC_LOGGEDIN_PORT pLoggedInPort = &fcChip->fcPorts; 
+  BOOLEAN target_id_valid=FALSE;
+  BOOLEAN port_id_valid=FALSE;
+  BOOLEAN wwn_valid=FALSE;
+  int i;
+
+
+  if( Cmnd != NULL )
+    target_id_valid = TRUE;
+  
+  else if( port_id ) // note! 24-bit NULL address is illegal
+    port_id_valid = TRUE;
+
+  else
+  {
+    if( wwn ) // non-null arg? (OK to pass NULL when not searching WWN)
+    {
+      for( i=0; i<8; i++)  // valid WWN passed?  NULL WWN invalid
+      {
+        if( wwn[i] != 0 )
+          wwn_valid = TRUE;  // any non-zero byte makes (presumably) valid
+      }
+    }
+  }
+                // check other options ...
+
+
+  // In case multiple search options are given, we use a priority
+  // scheme:
+  // While valid pLoggedIn Ptr
+  //   If port_id is valid
+  //     if port_id matches, return Ptr
+  //   If wwn is valid
+  //     if wwn matches, return Ptr
+  //   Next Ptr in list
+  //
+  // Return NULL (not found)
+ 
+      
+  while( pLoggedInPort ) // NULL marks end of list (1st ptr always valid)
+  {
+    if( pLastLoggedInPort ) // caller's pointer valid?
+      *pLastLoggedInPort = pLoggedInPort;  // end of linked list
+    
+    if( target_id_valid )
+    {
+      // check Linux Scsi Cmnd for channel/target Nexus match
+      // (all luns are accessed through matching "pLoggedInPort")
+      if( (pLoggedInPort->ScsiNexus.target == Cmnd->device->id)
+                &&
+          (pLoggedInPort->ScsiNexus.channel == Cmnd->device->channel))
+      {
+        // For "passthru" modes, the IOCTL caller is responsible
+	// for setting the FCP-LUN addressing
+	if (Cmnd->sc_request != NULL && Cmnd->device->host != NULL && 
+		Cmnd->device->host->hostdata != NULL &&
+		is_private_data_of_cpqfc((CPQFCHBA *) Cmnd->device->host->hostdata,
+			Cmnd->sc_request->upper_private_data)) { 
+		/* This is a passthru... */
+		cpqfc_passthru_private_t *pd;
+		pd = Cmnd->sc_request->upper_private_data;
+        	Cmnd->SCp.phase = pd->bus;
+		// Cmnd->SCp.have_data_in = pd->pdrive;
+		Cmnd->SCp.have_data_in = Cmnd->device->lun;
+	} else {
+	  /* This is not a passthru... */
+	
+          // set the FCP-LUN addressing type
+          Cmnd->SCp.phase = pLoggedInPort->ScsiNexus.VolumeSetAddressing;	
+
+          // set the Device Type we got from the snooped INQUIRY string
+	  Cmnd->SCp.Message = pLoggedInPort->ScsiNexus.InqDeviceType;
+
+	  // handle LUN masking; if not "default" (illegal) lun value,
+	  // the use it.  These lun values are set by a successful
+	  // Report Luns command
+          if( pLoggedInPort->ScsiNexus.LunMasking == 1) 
+	  {
+	    if (Cmnd->device->lun > sizeof(pLoggedInPort->ScsiNexus.lun))
+		return NULL;
+            // we KNOW all the valid LUNs... 0xFF is invalid!
+            Cmnd->SCp.have_data_in = pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun];
+	    if (pLoggedInPort->ScsiNexus.lun[Cmnd->device->lun] == 0xFF)
+		return NULL;
+	    // printk("xlating lun %d to 0x%02x\n", Cmnd->lun, 
+            //	pLoggedInPort->ScsiNexus.lun[Cmnd->lun]);
+	  }
+	  else
+	    Cmnd->SCp.have_data_in = Cmnd->device->lun; // Linux & target luns match
+	}
+	break; // found it!
+      }
+    }
+    
+    if( port_id_valid ) // look for alpa first
+    {
+      if( pLoggedInPort->port_id == port_id )
+          break;  // found it!
+    }
+    if( wwn_valid ) // look for wwn second
+    {
+
+      if( !memcmp( &pLoggedInPort->u.ucWWN[0], &wwn[0], 8))
+      {  
+                 // all 8 bytes of WWN match
+        break;   // found it!
+      }
+    }
+                
+    pLoggedInPort = pLoggedInPort->pNextPort; // try next port
+  }
+
+  return pLoggedInPort;
+}
+
+
+
+
+// 
+// We need to examine the SEST table and re-validate
+// any open Exchanges for this LoggedInPort
+// To make Tachyon pay attention, Freeze FCP assists,
+// set VAL bits, Unfreeze FCP assists
+static void RevalidateSEST( struct Scsi_Host *HostAdapter, 
+		        PFC_LOGGEDIN_PORT pLoggedInPort)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG x_ID;
+  BOOLEAN TachFroze = FALSE;
+  
+  
+  // re-validate any SEST exchanges that are permitted
+  // to survive the link down (e.g., good PDISC performed)
+  for( x_ID = 0; x_ID < TACH_SEST_LEN; x_ID++)
+  {
+
+    // If the SEST entry port_id matches the pLoggedInPort,
+    // we need to re-validate
+    if( (Exchanges->fcExchange[ x_ID].type == SCSI_IRE)
+         || 
+	(Exchanges->fcExchange[ x_ID].type == SCSI_IWE))
+    {
+		     
+      if( (Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF)  // (24-bit port ID)
+            == pLoggedInPort->port_id) 
+      {
+//	printk(" re-val xID %Xh ", x_ID);
+        if( !TachFroze )  // freeze if not already frozen
+          TachFroze |= FreezeTach( cpqfcHBAdata);
+        fcChip->SEST->u[ x_ID].IWE.Hdr_Len |= 0x80000000; // set VAL bit
+      }
+    } 
+  }
+
+  if( TachFroze) 
+  { 
+    fcChip->UnFreezeTachyon( fcChip, 2);  // both ERQ and FCP assists
+  }
+} 
+
+
+// Complete an Linux Cmnds that we Queued because
+// our FC link was down (cause immediate retry)
+
+static void UnblockScsiDevice( struct Scsi_Host *HostAdapter, 
+		        PFC_LOGGEDIN_PORT pLoggedInPort)
+{
+  CPQFCHBA *cpqfcHBAdata = (CPQFCHBA *)HostAdapter->hostdata;
+  Scsi_Cmnd* *SCptr = &cpqfcHBAdata->LinkDnCmnd[0];
+  Scsi_Cmnd *Cmnd;
+  int indx;
+
+ 
+  
+  // if the device was previously "blocked", make sure
+  // we unblock it so Linux SCSI will resume
+
+  pLoggedInPort->device_blocked = FALSE; // clear our flag
+
+  // check the Link Down command ptr buffer;
+  // we can complete now causing immediate retry
+  for( indx=0; indx < CPQFCTS_REQ_QUEUE_LEN; indx++, SCptr++)
+  {
+    if( *SCptr != NULL ) // scsi command to complete?
+    {
+#ifdef DUMMYCMND_DBG
+      printk("complete Cmnd %p in LinkDnCmnd[%d]\n", *SCptr,indx);
+#endif
+      Cmnd = *SCptr;
+
+
+      // Are there any Q'd commands for this target?
+      if( (Cmnd->device->id == pLoggedInPort->ScsiNexus.target)
+	       &&
+          (Cmnd->device->channel == pLoggedInPort->ScsiNexus.channel) )
+      {
+        Cmnd->result = (DID_SOFT_ERROR <<16); // force retry
+        if( Cmnd->scsi_done == NULL) 
+	{
+          printk("LinkDnCmnd scsi_done ptr null, port_id %Xh\n",
+		  pLoggedInPort->port_id);
+	}
+	else
+	  call_scsi_done(Cmnd);
+        *SCptr = NULL;  // free this slot for next use
+      }
+    }
+  }
+}
+
+  
+//#define WWN_DBG 1
+
+static void SetLoginFields(
+  PFC_LOGGEDIN_PORT pLoggedInPort,
+  TachFCHDR_GCMND* fchs,
+  BOOLEAN PDisc,
+  BOOLEAN Originator)
+{
+  LOGIN_PAYLOAD logi;       // FC-PH Port Login
+  PRLI_REQUEST prli;  // copy for BIG ENDIAN switch
+  int i;
+#ifdef WWN_DBG
+  ULONG ulBuff;
+#endif
+
+  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&logi, sizeof(logi));
+
+  pLoggedInPort->Originator = Originator;
+  pLoggedInPort->port_id = fchs->s_id & 0xFFFFFF;
+  
+  switch( fchs->pl[0] & 0xffff )
+  {
+  case 0x00000002:  //  PLOGI or PDISC ACCept?
+    if( PDisc )     // PDISC accept
+      goto PDISC_case;
+
+  case 0x00000003:  //  ELS_PLOGI or ELS_PLOGI_ACC
+
+  // Login BB_credit typically 0 for Tachyons
+    pLoggedInPort->BB_credit = logi.cmn_services.bb_credit;
+
+    // e.g. 128, 256, 1024, 2048 per FC-PH spec
+    // We have to use this when setting up SEST Writes,
+    // since that determines frame size we send.
+    pLoggedInPort->rx_data_size = logi.class3.rx_data_size;
+    pLoggedInPort->plogi = TRUE;
+    pLoggedInPort->pdisc = FALSE;
+    pLoggedInPort->prli = FALSE;    // ELS_PLOGI resets
+    pLoggedInPort->flogi = FALSE;   // ELS_PLOGI resets
+    pLoggedInPort->logo = FALSE;    // ELS_PLOGI resets
+    pLoggedInPort->LOGO_counter = 0;// ELS_PLOGI resets
+    pLoggedInPort->LOGO_timer = 0;// ELS_PLOGI resets
+
+    // was this PLOGI to a Fabric?
+    if( pLoggedInPort->port_id == 0xFFFFFC ) // well know address
+      pLoggedInPort->flogi = TRUE;
+
+
+    for( i=0; i<8; i++)   // copy the LOGIN port's WWN
+      pLoggedInPort->u.ucWWN[i] = logi.port_name[i];  
+
+#ifdef WWN_DBG
+    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
+    if( pLoggedInPort->Originator)
+      printk("o");
+    else
+      printk("r");
+    printk("PLOGI port_id %Xh, WWN %08X",
+      pLoggedInPort->port_id, ulBuff);
+
+    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
+    printk("%08Xh fcPort %p\n", ulBuff, pLoggedInPort);
+#endif
+    break;
+
+
+
+  
+  case 0x00000005:  //  ELS_LOGO (logout)
+
+
+    pLoggedInPort->plogi = FALSE;
+    pLoggedInPort->pdisc = FALSE;
+    pLoggedInPort->prli = FALSE;   // ELS_PLOGI resets
+    pLoggedInPort->flogi = FALSE;  // ELS_PLOGI resets
+    pLoggedInPort->logo = TRUE;    // ELS_PLOGI resets
+    pLoggedInPort->LOGO_counter++; // ELS_PLOGI resets
+    pLoggedInPort->LOGO_timer = 0;
+#ifdef WWN_DBG
+    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
+    if( pLoggedInPort->Originator)
+      printk("o");
+    else
+      printk("r");
+    printk("LOGO port_id %Xh, WWN %08X",
+      pLoggedInPort->port_id, ulBuff);
+
+    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
+    printk("%08Xh\n", ulBuff);
+#endif
+    break;
+
+
+
+PDISC_case:
+  case 0x00000050: //  ELS_PDISC or ELS_PDISC_ACC
+    pLoggedInPort->LOGO_timer = 0;  // stop the time-out
+      
+    pLoggedInPort->prli = TRUE;     // ready to accept FCP-SCSI I/O
+    
+
+      
+#ifdef WWN_DBG
+    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
+    if( pLoggedInPort->Originator)
+      printk("o");
+    else
+      printk("r");
+    printk("PDISC port_id %Xh, WWN %08X",
+      pLoggedInPort->port_id, ulBuff);
+
+    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
+    printk("%08Xh\n", ulBuff);
+#endif
+
+
+    
+    break;
+
+
+    
+  case  0x1020L: //  PRLI?
+  case  0x1002L: //  PRLI ACCept?
+    BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli, sizeof(prli));
+
+    pLoggedInPort->fcp_info = prli.fcp_info; // target/initiator flags
+    pLoggedInPort->prli = TRUE;  // PLOGI resets, PDISC doesn't
+
+    pLoggedInPort->pdisc = TRUE;  // expect to send (or receive) PDISC
+                                  // next time
+    pLoggedInPort->LOGO_timer = 0;  // will be set next LinkDown
+#ifdef WWN_DBG
+    ulBuff = (ULONG)pLoggedInPort->u.liWWN;
+    if( pLoggedInPort->Originator)
+      printk("o");
+    else
+      printk("r");
+    printk("PRLI port_id %Xh, WWN %08X",
+      pLoggedInPort->port_id, ulBuff);
+
+    ulBuff = (ULONG)(pLoggedInPort->u.liWWN >> 32);
+      printk("%08Xh\n", ulBuff);
+#endif
+
+    break;
+
+  }
+
+  return;
+}
+
+
+
+
+
+
+static void BuildLinkServicePayload( PTACHYON fcChip, ULONG type, void* payload)
+{
+  LOGIN_PAYLOAD *plogi;  // FC-PH Port Login
+  LOGIN_PAYLOAD PlogiPayload;   // copy for BIG ENDIAN switch
+  PRLI_REQUEST  *prli;          // FCP-SCSI Process Login
+  PRLI_REQUEST  PrliPayload;    // copy for BIG ENDIAN switch
+  LOGOUT_PAYLOAD  *logo;
+  LOGOUT_PAYLOAD  LogoutPayload;
+//  PRLO_REQUEST  *prlo;
+//  PRLO_REQUEST  PrloPayload;
+  REJECT_MESSAGE rjt, *prjt;
+
+  memset( &PlogiPayload, 0, sizeof( PlogiPayload));
+  plogi = &PlogiPayload;    // load into stack buffer,
+                                // then BIG-ENDIAN switch a copy to caller
+
+
+  switch( type )  // payload type can be ELS_PLOGI, ELS_PRLI, ADISC, ...
+  {
+    case ELS_FDISC:
+    case ELS_FLOGI:
+    case ELS_PLOGI_ACC:   // FC-PH PORT Login Accept
+    case ELS_PLOGI:   // FC-PH PORT Login
+    case ELS_PDISC:   // FC-PH2 Port Discovery - same payload as ELS_PLOGI
+      plogi->login_cmd = LS_PLOGI;
+      if( type == ELS_PDISC)
+        plogi->login_cmd = LS_PDISC;
+      else if( type == ELS_PLOGI_ACC )
+        plogi->login_cmd = LS_ACC;
+
+      plogi->cmn_services.bb_credit = 0x00;
+      plogi->cmn_services.lowest_ver = fcChip->lowest_FCPH_ver;
+      plogi->cmn_services.highest_ver = fcChip->highest_FCPH_ver;
+      plogi->cmn_services.bb_rx_size = TACHLITE_TS_RX_SIZE;
+      plogi->cmn_services.common_features = CONTINUOSLY_INCREASING |
+              RANDOM_RELATIVE_OFFSET;
+
+             // fill in with World Wide Name based Port Name - 8 UCHARs
+             // get from Tach registers WWN hi & lo
+      LoadWWN( fcChip, plogi->port_name, 0);
+             // fill in with World Wide Name based Node/Fabric Name - 8 UCHARs
+             // get from Tach registers WWN hi & lo
+      LoadWWN( fcChip, plogi->node_name, 1);
+
+	// For Seagate Drives.
+	//
+      plogi->cmn_services.common_features |= 0x800;
+      plogi->cmn_services.rel_offset = 0xFE;
+      plogi->cmn_services.concurrent_seq = 1;
+      plogi->class1.service_options = 0x00;
+      plogi->class2.service_options = 0x00;
+      plogi->class3.service_options = CLASS_VALID;
+      plogi->class3.initiator_control = 0x00;
+      plogi->class3.rx_data_size = MAX_RX_PAYLOAD;
+      plogi->class3.recipient_control =
+             ERROR_DISCARD | ONE_CATEGORY_SEQUENCE;
+      plogi->class3.concurrent_sequences = 1;
+      plogi->class3.open_sequences = 1;
+      plogi->vendor_id[0] = 'C'; plogi->vendor_id[1] = 'Q';
+      plogi->vendor_version[0] = 'C'; plogi->vendor_version[1] = 'Q';
+      plogi->vendor_version[2] = ' '; plogi->vendor_version[3] = '0';
+      plogi->vendor_version[4] = '0'; plogi->vendor_version[5] = '0';
+
+
+      // FLOGI specific fields... (see FC-FLA, Rev 2.7, Aug 1999, sec 5.1)
+      if( (type == ELS_FLOGI) || (type == ELS_FDISC) )
+      {
+        if( type == ELS_FLOGI )
+  	  plogi->login_cmd = LS_FLOGI;  
+	else
+  	  plogi->login_cmd = LS_FDISC;  
+
+        plogi->cmn_services.lowest_ver = 0x20;
+        plogi->cmn_services.common_features = 0x0800;
+        plogi->cmn_services.rel_offset = 0;
+        plogi->cmn_services.concurrent_seq = 0;
+
+        plogi->class3.service_options = 0x8800;
+        plogi->class3.rx_data_size = 0;
+        plogi->class3.recipient_control = 0;
+        plogi->class3.concurrent_sequences = 0;
+        plogi->class3.open_sequences = 0;
+      }
+      
+              // copy back to caller's buff, w/ BIG ENDIAN swap
+      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  sizeof(PlogiPayload));
+      break;
+
+    
+    case ELS_ACC:       // generic Extended Link Service ACCept	    
+      plogi->login_cmd = LS_ACC;
+              // copy back to caller's buff, w/ BIG ENDIAN swap
+      BigEndianSwap( (UCHAR*)&PlogiPayload, payload,  4);
+      break;
+
+
+      
+    case ELS_SCR:    // Fabric State Change Registration
+    {
+      SCR_PL scr;     // state change registration
+
+      memset( &scr, 0, sizeof(scr));
+
+      scr.command = LS_SCR;  // 0x62000000
+                             // see FC-FLA, Rev 2.7, Table A.22 (pg 82)
+      scr.function = 3;      // 1 = Events detected by Fabric
+                             // 2 = N_Port detected registration
+                             // 3 = Full registration
+      
+      // copy back to caller's buff, w/ BIG ENDIAN swap
+      BigEndianSwap( (UCHAR*)&scr, payload,  sizeof(SCR_PL));
+    }
+    
+    break;
+
+    
+    case FCS_NSR:    // Fabric Name Service Request
+    {
+      NSR_PL nsr;    // Name Server Req. payload
+
+      memset( &nsr, 0, sizeof(NSR_PL));
+
+                             // see Brocade Fabric Programming Guide,
+                             // Rev 1.3, pg 4-44
+      nsr.CT_Rev = 0x01000000;
+      nsr.FCS_Type = 0xFC020000;
+      nsr.Command_code = 0x01710000;
+      nsr.FCP = 8;
+     
+      // copy back to caller's buff, w/ BIG ENDIAN swap
+      BigEndianSwap( (UCHAR*)&nsr, payload,  sizeof(NSR_PL));
+    }
+    
+    break;
+
+
+
+    
+    case ELS_LOGO:   // FC-PH PORT LogOut
+      logo = &LogoutPayload;    // load into stack buffer,
+                                // then BIG-ENDIAN switch a copy to caller
+      logo->cmd = LS_LOGO;
+                                // load the 3 UCHARs of the node name
+                                // (if private loop, upper two UCHARs 0)
+      logo->reserved = 0;
+
+      logo->n_port_identifier[0] = (UCHAR)(fcChip->Registers.my_al_pa);
+      logo->n_port_identifier[1] =
+                     (UCHAR)(fcChip->Registers.my_al_pa>>8);
+      logo->n_port_identifier[2] =
+                     (UCHAR)(fcChip->Registers.my_al_pa>>16);
+             // fill in with World Wide Name based Port Name - 8 UCHARs
+             // get from Tach registers WWN hi & lo
+      LoadWWN( fcChip, logo->port_name, 0);
+
+      BigEndianSwap( (UCHAR*)&LogoutPayload,
+                     payload,  sizeof(LogoutPayload) );  // 16 UCHAR struct
+      break;
+
+
+    case ELS_LOGO_ACC:     // Logout Accept (FH-PH pg 149, table 74)
+      logo = &LogoutPayload;    // load into stack buffer,
+                                // then BIG-ENDIAN switch a copy to caller
+      logo->cmd = LS_ACC;
+      BigEndianSwap( (UCHAR*)&LogoutPayload, payload, 4 );  // 4 UCHAR cmnd
+      break;
+      
+
+    case ELS_RJT:          // ELS_RJT link service reject (FH-PH pg 155)
+
+      prjt = (REJECT_MESSAGE*)payload;  // pick up passed data
+      rjt.command_code = ELS_RJT;
+                       // reverse fields, because of Swap that follows...
+      rjt.vendor = prjt->reserved; // vendor specific
+      rjt.explain = prjt->reason; //
+      rjt.reason = prjt->explain; //
+      rjt.reserved = prjt->vendor; //
+                       // BIG-ENDIAN switch a copy to caller
+      BigEndianSwap( (UCHAR*)&rjt, payload, 8 );  // 8 UCHAR cmnd
+      break;
+
+
+
+
+
+    case ELS_PRLI_ACC:  // Process Login ACCept
+    case ELS_PRLI:  // Process Login
+    case ELS_PRLO:  // Process Logout
+      memset( &PrliPayload, 0, sizeof( PrliPayload));
+      prli = &PrliPayload;      // load into stack buffer,
+
+      if( type == ELS_PRLI )
+        prli->cmd = 0x20;  // Login
+      else if( type == ELS_PRLO )
+        prli->cmd = 0x21;  // Logout
+      else if( type == ELS_PRLI_ACC )
+      {
+        prli->cmd = 0x02;  // Login ACCept
+        prli->valid = REQUEST_EXECUTED;
+      }
+
+
+      prli->valid |= SCSI_FCP | ESTABLISH_PAIR;
+      prli->fcp_info = READ_XFER_RDY;
+      prli->page_length = 0x10;
+      prli->payload_length = 20;
+                                // Can be initiator AND target
+
+      if( fcChip->Options.initiator )
+        prli->fcp_info |= INITIATOR_FUNCTION;
+      if( fcChip->Options.target )
+        prli->fcp_info |= TARGET_FUNCTION;
+
+      BigEndianSwap( (UCHAR*)&PrliPayload, payload,  prli->payload_length);
+      break;
+
+
+
+    default:  // no can do - programming error
+      printk(" BuildLinkServicePayload unknown!\n");
+      break;
+  }
+}
+
+// loads 8 UCHARs for PORT name or NODE name base on
+// controller's WWN.
+void LoadWWN( PTACHYON fcChip, UCHAR* dest, UCHAR type)
+{
+  UCHAR* bPtr, i;
+
+  switch( type )
+  {
+    case 0:  // Port_Name
+      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
+      for( i =0; i<4; i++)
+        dest[i] = *bPtr++;
+      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
+      for( i =4; i<8; i++)
+        dest[i] = *bPtr++;
+      break;
+    case 1:  // Node/Fabric _Name
+      bPtr = (UCHAR*)&fcChip->Registers.wwn_hi;
+      for( i =0; i<4; i++)
+        dest[i] = *bPtr++;
+      bPtr = (UCHAR*)&fcChip->Registers.wwn_lo;
+      for( i =4; i<8; i++)
+        dest[i] = *bPtr++;
+      break;
+  }
+  
+}
+
+
+
+// We check the Port Login payload for required values.  Note that
+// ELS_PLOGI and ELS_PDISC (Port DISCover) use the same payload.
+
+
+int verify_PLOGI( PTACHYON fcChip,
+                  TachFCHDR_GCMND* fchs, 
+                  ULONG* reject_explain)
+{
+  LOGIN_PAYLOAD	login;
+
+                  // source, dest, len (should be mult. of 4)
+  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&login,  sizeof(login));
+
+                            // check FC version
+                            // if other port's highest supported version
+                            // is less than our lowest, and 
+                            // if other port's lowest
+  if( login.cmn_services.highest_ver < fcChip->lowest_FCPH_ver ||
+      login.cmn_services.lowest_ver > fcChip->highest_FCPH_ver )
+  {
+    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
+    return LOGICAL_ERROR;
+  }
+
+                            // Receive Data Field Size must be >=128
+                            // per FC-PH
+  if (login.cmn_services.bb_rx_size < 128)
+  {
+    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, DATA_FIELD_SIZE_ERROR);
+    return LOGICAL_ERROR;
+  }
+
+                            // Only check Class 3 params
+  if( login.class3.service_options & CLASS_VALID)
+  {
+    if (login.class3.rx_data_size < 128)
+    {
+      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INVALID_CSP);
+      return LOGICAL_ERROR;
+    }
+    if( login.class3.initiator_control & XID_REQUIRED)
+    {
+      *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, INITIATOR_CTL_ERROR);
+      return LOGICAL_ERROR;
+    }
+  }
+  return 0;   // success
+}
+
+
+
+
+int verify_PRLI( TachFCHDR_GCMND* fchs, ULONG* reject_explain)
+{
+  PRLI_REQUEST prli;  // buffer for BIG ENDIAN
+
+                  // source, dest, len (should be mult. of 4)
+  BigEndianSwap( (UCHAR*)&fchs->pl[0], (UCHAR*)&prli,  sizeof(prli));
+
+  if( prli.fcp_info == 0 )  // i.e., not target or initiator?
+  {
+    *reject_explain = LS_RJT_REASON( LOGICAL_ERROR, OPTIONS_ERROR);
+    return LOGICAL_ERROR;
+  }
+
+  return 0;  // success
+}
+
+
+// SWAP UCHARs as required by Fibre Channel (i.e. BIG ENDIAN)
+// INPUTS:
+//   source   - ptr to LITTLE ENDIAN ULONGS
+//   cnt      - number of UCHARs to switch (should be mult. of ULONG)
+// OUTPUTS:
+//   dest     - ptr to BIG ENDIAN copy
+// RETURN:
+//   none
+//
+void BigEndianSwap( UCHAR *source, UCHAR *dest,  USHORT cnt)
+{
+  int i,j;
+
+  source+=3;   // start at MSB of 1st ULONG
+  for( j=0; j < cnt; j+=4, source+=4, dest+=4)  // every ULONG
+  {
+    for( i=0; i<4; i++)  // every UCHAR in ULONG
+          *(dest+i) = *(source-i);
+  }
+}
+
+
+
+
+// Build FC Exchanges............
+
+static void  buildFCPstatus( 
+  PTACHYON fcChip, 
+  ULONG ExchangeID);
+
+static LONG FindFreeExchange( PTACHYON fcChip, ULONG type );
+
+static ULONG build_SEST_sgList( 
+  struct pci_dev *pcidev,
+  ULONG *SESTalPairStart,
+  Scsi_Cmnd *Cmnd,
+  ULONG *sgPairs,
+  PSGPAGES *sgPages_head  // link list of TL Ext. S/G pages from O/S Pool
+);
+
+static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
+  UCHAR* payload, ULONG type, ULONG fcp_dl );
+
+
+/*
+                             IRB
+      ERQ           __________________
+  |          |   / | Req_A_SFS_Len    |        ____________________
+  |----------|  /  | Req_A_SFS_Addr   |------->|  Reserved         |
+  |   IRB    | /   | Req_A_D_ID       |        | SOF EOF TimeStamp |
+  |-----------/    | Req_A_SEST_Index |-+      | R_CTL |   D_ID    |
+  |   IRB    |     | Req_B...         | |      | CS_CTL|   S_ID    | 
+  |-----------\    |                  | |      | TYPE  |   F_CTL   |
+  |   IRB    | \   |                  | |      | SEQ_ID  | SEQ_CNT |
+  |-----------  \  |                  | +-->+--| OX_ID   | RX_ID   |
+  |          |   \ |__________________|     |  |       RO          |
+                                            |  | pl (payload/cmnd) |
+                                            |  |        .....      |
+                                            |  |___________________|
+                                            |
+                                            |
++-------------------------------------------+
+|
+|
+|                        e.g. IWE    
+|    SEST           __________________             for FCP_DATA
+| |          |   / |       | Hdr_Len  |        ____________________
+| |----------|  /  |  Hdr_Addr_Addr   |------->|  Reserved         |
+| |   [0]    | /   |Remote_ID| RSP_Len|        | SOF EOF TimeStamp |
+| |-----------/    |   RSP_Addr       |---+    | R_CTL |   D_ID    |
++->   [1]    |     |       | Buff_Off |   |    | CS_CTL|   S_ID    | 
+  |-----------\    |BuffIndex| Link   |   |    | TYPE  |   F_CTL   |
+  |   [2]    | \   | Rsvd  |   RX_ID  |   |    | SEQ_ID  | SEQ_CNT |
+  |-----------  \  |    Data_Len      |   |    | OX_ID   | RX_ID   |
+  |    ...   |   \ |     Exp_RO       |   |    |       RO          |
+  |----------|     |   Exp_Byte_Cnt   |   |    |___________________|
+  | SEST_LEN |  +--|    Len           |   |                                             
+  |__________|  |  |   Address        |   |                                              
+                |  |    ...           |   |         for FCP_RSP  
+                |  |__________________|   |    ____________________
+                |                         +----|  Reserved         |   
+                |                              | SOF EOF TimeStamp |
+                |                              | R_CTL |   D_ID    |
+                |                              | CS_CTL|   S_ID    | 
+                +--- local or extended         |     ....          |
+                     scatter/gather lists
+                     defining upper-layer
+                     data (e.g. from user's App)
+
+
+*/
+// All TachLite commands must start with a SFS (Single Frame Sequence)
+// command.  In the simplest case (a NOP Basic Link command),
+// only one frame header and ERQ entry is required.  The most complex
+// case is the SCSI assisted command, which requires an ERQ entry,
+// SEST entry, and several frame headers and data buffers all
+// logically linked together.
+// Inputs:
+//   cpqfcHBAdata  - controller struct
+//   type          - PLOGI, SCSI_IWE, etc.
+//   InFCHS        - Incoming Tachlite FCHS which prompted this exchange
+//                   (only s_id set if we are originating)
+//   Data          - PVOID to data struct consistent with "type"
+//   fcExchangeIndex - pointer to OX/RD ID value of built exchange
+// Return:
+//   fcExchangeIndex - OX/RD ID value if successful
+//   0    - success
+//  INVALID_ARGS    - NULL/ invalid passed args
+//  BAD_ALPA        - Bad source al_pa address
+//  LNKDWN_OSLS     - Link Down (according to this controller)
+//  OUTQUE_FULL     - Outbound Que full
+//  DRIVERQ_FULL    - controller's Exchange array full
+//  SEST_FULL       - SEST table full
+//
+// Remarks:
+// Psuedo code:
+// Check for NULL pointers / bad args
+// Build outgoing FCHS - the header/payload struct
+// Build IRB (for ERQ entry)
+// if SCSI command, build SEST entry (e.g. IWE, TRE,...)
+// return success
+
+//sbuildex
+ULONG cpqfcTSBuildExchange(
+  CPQFCHBA *cpqfcHBAdata,
+  ULONG type, // e.g. PLOGI
+  TachFCHDR_GCMND* InFCHS,  // incoming FCHS
+  void *Data,               // the CDB, scatter/gather, etc.  
+  LONG *fcExchangeIndex )   // points to allocated exchange, 
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG ulStatus = 0;  // assume OK
+  USHORT ox_ID, rx_ID=0xFFFF;
+  ULONG SfsLen=0L;
+  TachLiteIRB* pIRB;
+  IRBflags IRB_flags;
+  UCHAR *pIRB_flags = (UCHAR*)&IRB_flags;
+  TachFCHDR_GCMND* CMDfchs;
+  TachFCHDR* dataHDR;     // 32 byte HEADER ONLY FCP-DATA buffer
+  TachFCHDR_RSP* rspHDR;     // 32 byte header + RSP payload
+  Scsi_Cmnd *Cmnd = (Scsi_Cmnd*)Data;   // Linux Scsi CDB, S/G, ...
+  TachLiteIWE* pIWE;
+  TachLiteIRE* pIRE;
+  TachLiteTWE* pTWE;
+  TachLiteTRE* pTRE;
+  ULONG fcp_dl;           // total byte length of DATA transferred
+  ULONG fl;               // frame length (FC frame size, 128, 256, 512, 1024)
+  ULONG sgPairs;          // number of valid scatter/gather pairs
+  int FCP_SCSI_command;
+  BA_ACC_PAYLOAD *ba_acc;
+  BA_RJT_PAYLOAD *ba_rjt;
+
+                          // check passed ARGS
+  if( !fcChip->ERQ )      // NULL ptr means uninitialized Tachlite chip
+    return INVALID_ARGS;
+
+
+  if( type == SCSI_IRE ||
+      type == SCSI_TRE ||
+      type == SCSI_IWE ||
+      type == SCSI_TWE)
+    FCP_SCSI_command = 1;
+
+  else
+    FCP_SCSI_command = 0;
+
+
+                     // for commands that pass payload data (e.g. SCSI write)
+                     // examine command struct - verify that the
+                     // length of s/g buffers is adequate for total payload
+                     // length (end of list is NULL address)
+
+  if( FCP_SCSI_command )
+  {
+    if( Data )     // must have data descriptor (S/G list -- at least
+                   // one address with at least 1 byte of data)
+    {
+      // something to do (later)?
+    }
+
+    else
+      return INVALID_ARGS;  // invalid DATA ptr
+  }
+
+    
+
+         // we can build an Exchange for later Queuing (on the TL chip)
+         // if an empty slot is available in the DevExt for this controller
+         // look for available Exchange slot...
+
+  if( type != FCP_RESPONSE &&
+      type != BLS_ABTS &&
+      type != BLS_ABTS_ACC )  // already have Exchange slot!
+    *fcExchangeIndex = FindFreeExchange( fcChip, type );
+
+  if( *fcExchangeIndex != -1 )   // Exchange is available?
+  {
+                     // assign tmp ptr (shorthand)
+    CMDfchs = &Exchanges->fcExchange[ *fcExchangeIndex].fchs; 
+
+    if( Cmnd != NULL ) // (necessary for ABTS cases)
+    {
+      Exchanges->fcExchange[ *fcExchangeIndex].Cmnd = Cmnd; // Linux Scsi
+      Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort = 
+	fcFindLoggedInPort( fcChip,
+          Exchanges->fcExchange[ *fcExchangeIndex].Cmnd, // find Scsi Nexus
+          0,        // DON'T search linked list for FC port id
+	  NULL,     // DON'T search linked list for FC WWN
+          NULL);    // DON'T care about end of list
+
+    }
+
+
+                     // Build the command frame header (& data) according
+                     // to command type
+
+                     // fields common for all SFS frame types
+    CMDfchs->reserved = 0L; // must clear
+    CMDfchs->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; LCr=0, no TS
+    
+             // get the destination port_id from incoming FCHS
+             // (initialized before calling if we're Originator)
+             // Frame goes to port it was from - the source_id
+    
+    CMDfchs->d_id = InFCHS->s_id &0xFFFFFF; // destination (add R_CTL later)
+    CMDfchs->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+
+
+    // now enter command-specific fields
+    switch( type )
+    {
+
+    case BLS_NOP:   // FC defined basic link service command NO-OP
+                // ensure unique X_IDs! (use tracking function)
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 32L;        // add len to LSB (header only - no payload)
+
+                   // TYPE[31-24] 00 Basic Link Service
+                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+      CMDfchs->d_id |= 0x80000000L;  // R_CTL = 80 for NOP (Basic Link Ser.)
+      CMDfchs->f_ctl = 0x00310000L;  // xchng originator, 1st seq,....
+      CMDfchs->seq_cnt = 0x0L;
+      CMDfchs->ox_rx_id = 0xFFFF;        // RX_ID for now; OX_ID on start
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+      CMDfchs->pl[0] = 0xaabbccddL;   // words 8-15 frame data payload (n/a)
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // seconds
+                                      // (NOP should complete ~instantly)
+      break;
+
+
+    
+    
+    case BLS_ABTS_ACC:  // Abort Sequence ACCept
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
+
+      CMDfchs->d_id |= 0x84000000L;  // R_CTL = 84 for BASIC ACCept
+                   // TYPE[31-24] 00 Basic Link Service
+                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
+                   // CMDfchs->seq_id & count might be set from DataHdr?
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
+                        // (Timeout in case of weird error)
+      
+      // now set the ACCept payload...
+      ba_acc = (BA_ACC_PAYLOAD*)&CMDfchs->pl[0];
+      memset( ba_acc, 0, sizeof( BA_ACC_PAYLOAD));
+      // Since PLDA requires (only) entire Exchange aborts, we don't need
+      // to worry about what the last sequence was.
+
+      // We expect that a "target" task is accepting the abort, so we
+      // can use the OX/RX ID pair 
+      ba_acc->ox_rx_id = CMDfchs->ox_rx_id;
+ 
+      // source, dest, #bytes
+      BigEndianSwap((UCHAR *)&CMDfchs->ox_rx_id, (UCHAR *)&ba_acc->ox_rx_id, 4);
+
+      ba_acc->low_seq_cnt = 0;
+      ba_acc->high_seq_cnt = 0xFFFF;
+
+
+      break;
+    
+
+    case BLS_ABTS_RJT:  // Abort Sequence ACCept
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 32 + 12;    // add len to LSB (header + 3 DWORD payload)
+
+      CMDfchs->d_id |= 0x85000000L;  // R_CTL = 85 for BASIC ReJecT
+                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+                   // TYPE[31-24] 00 Basic Link Service
+      CMDfchs->f_ctl = 0x00910000L;  // xchnge responder, last seq, xfer SI
+                   // CMDfchs->seq_id & count might be set from DataHdr?
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 5; // seconds
+                        // (Timeout in case of weird error)
+      
+      CMDfchs->ox_rx_id = InFCHS->ox_rx_id; // copy from sender!
+      
+      // now set the ReJecT payload...
+      ba_rjt = (BA_RJT_PAYLOAD*)&CMDfchs->pl[0];
+      memset( ba_rjt, 0, sizeof( BA_RJT_PAYLOAD));
+
+      // We expect that a "target" task couldn't find the Exhange in the
+      // array of active exchanges, so we use a new LinkService X_ID.
+      // See Reject payload description in FC-PH (Rev 4.3), pg. 140
+      ba_rjt->reason_code = 0x09; // "unable to perform command request"
+      ba_rjt->reason_explain = 0x03; // invalid OX/RX ID pair
+
+
+      break;
+    
+    
+    case BLS_ABTS:   // FC defined basic link service command ABTS 
+                     // Abort Sequence
+                     
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 32L;        // add len to LSB (header only - no payload)
+
+                   // TYPE[31-24] 00 Basic Link Service
+                   // f_ctl[23:0] exchg originator, not 1st seq, xfer S.I.
+      CMDfchs->d_id |= 0x81000000L;  // R_CTL = 81 for ABTS
+      CMDfchs->f_ctl = 0x00110000L;  // xchnge originator, last seq, xfer SI
+                   // CMDfchs->seq_id & count might be set from DataHdr?
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
+                        // (ABTS must timeout when responder is gone)
+      break;
+
+    
+    
+    case FCS_NSR:    // Fabric Name Service Request
+       Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
+
+
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
+                         // OX_ID, linked to Driver Transaction ID
+                         // (fix-up at Queing time)
+      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
+                                    // OX_ID set at ERQueing time
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += (32L + sizeof(NSR_PL)); // add len (header & NSR payload)
+
+      CMDfchs->d_id |= 0x02000000L;  // R_CTL = 02 for -
+                                   // Name Service Request: Unsolicited 
+                   // TYPE[31-24] 01 Extended Link Service
+                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+      CMDfchs->f_ctl = 0x20210000L;
+                   // OX_ID will be fixed-up at Tachyon enqueing time
+      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
+
+   
+    
+    
+    
+    
+      break;
+    
+    
+    
+    
+    case ELS_PLOGI:  // FC-PH extended link service command Port Login
+      // (May, 2000)
+      // NOTE! This special case facilitates SANMark testing.  The SANMark
+      // test script for initialization-timeout.fcal.SANMark-1.fc
+      // "eats" the OPN() primitive without issuing an R_RDY, causing
+      // Tachyon to report LST (loop state timeout), which causes a
+      // LIP.  To avoid this, simply send out the frame (i.e. assuming a
+      // buffer credit of 1) without waiting for R_RDY.  Many FC devices
+      // (other than Tachyon) have been doing this for years.  We don't
+      // ever want to do this for non-Link Service frames unless the
+      // other device really did report non-zero login BB credit (i.e.
+      // in the PLOGI ACCept frame).
+//      CMDfchs->sof_eof |= 0x00000400L;  // LCr=1
+    
+    case ELS_FDISC:  // Fabric Discovery (Login)
+    case ELS_FLOGI:  // Fabric Login
+    case ELS_SCR:    // Fabric State Change Registration
+    case ELS_LOGO:   // FC-PH extended link service command Port Logout
+    case ELS_PDISC:  // FC-PH extended link service cmnd Port Discovery
+    case ELS_PRLI:   // FC-PH extended link service cmnd Process Login
+
+      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 2;
+
+
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 2; // seconds
+                         // OX_ID, linked to Driver Transaction ID
+                         // (fix-up at Queing time)
+      CMDfchs->ox_rx_id = 0xFFFF; // RX_ID - Responder (target) to modify
+                                    // OX_ID set at ERQueing time
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      if( type == ELS_LOGO )
+        SfsLen += (32L + 16L); //  add len (header & PLOGI payload)
+      else if( type == ELS_PRLI )
+        SfsLen += (32L + 20L); //  add len (header & PRLI payload)
+      else if( type == ELS_SCR )
+        SfsLen += (32L + sizeof(SCR_PL)); //  add len (header & SCR payload)
+      else
+        SfsLen += (32L + 116L); //  add len (header & PLOGI payload)
+
+      CMDfchs->d_id |= 0x22000000L;  // R_CTL = 22 for -
+                                   // Extended Link_Data: Unsolicited Control
+                   // TYPE[31-24] 01 Extended Link Service
+                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+      CMDfchs->f_ctl = 0x01210000L;
+                   // OX_ID will be fixed-up at Tachyon enqueing time
+      CMDfchs->seq_cnt = 0; // seq ID, DF_ctl, seq cnt
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
+
+      break;
+
+
+
+    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
+    case ELS_RJT:          // extended link service reject (add reason)
+    case ELS_ACC:      // ext. link service generic accept
+    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
+    case ELS_PRLI_ACC: // ext. link service process login accept
+
+
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 1; // assume done
+                // ensure unique X_IDs! (use tracking function)
+                // OX_ID from initiator cmd
+      ox_ID = (USHORT)(InFCHS->ox_rx_id >> 16); 
+      rx_ID = 0xFFFF; // RX_ID, linked to Driver Exchange ID
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (not SEST index)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      if( type == ELS_RJT )
+      {
+        SfsLen += (32L + 8L); //  add len (header + payload)
+
+        // ELS_RJT reason codes (utilize unused "reserved" field)
+        CMDfchs->pl[0] = 1;
+        CMDfchs->pl[1] = InFCHS->reserved;  
+          
+      }
+      else if( (type == ELS_LOGO_ACC) || (type == ELS_ACC)  )
+        SfsLen += (32L + 4L); //  add len (header + payload)
+      else if( type == ELS_PLOGI_ACC )
+        SfsLen += (32L + 116L); //  add len (header + payload)
+      else if( type == ELS_PRLI_ACC )
+        SfsLen += (32L + 20L); //  add len (header + payload)
+
+      CMDfchs->d_id |= 0x23000000L;  // R_CTL = 23 for -
+                                   // Extended Link_Data: Control Reply
+                   // TYPE[31-24] 01 Extended Link Service
+                   // f_ctl[23:0] exchg responder, last seq, e_s, tsi
+      CMDfchs->f_ctl = 0x01990000L;
+      CMDfchs->seq_cnt = 0x0L;
+      CMDfchs->ox_rx_id = 0L;        // clear
+      CMDfchs->ox_rx_id = ox_ID; // load upper 16 bits
+      CMDfchs->ox_rx_id <<= 16;      // shift them
+
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+      BuildLinkServicePayload( fcChip, type, &CMDfchs->pl[0]);
+
+      break;
+
+
+                         // Fibre Channel SCSI 'originator' sequences...
+                         // (originator means 'initiator' in FCP-SCSI)
+
+    case SCSI_IWE: // TachLite Initiator Write Entry
+    {
+      PFC_LOGGEDIN_PORT pLoggedInPort = 
+        Exchanges->fcExchange[ *fcExchangeIndex].pLoggedInPort;
+
+      Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // FC2 timeout
+                       
+      // first, build FCP_CMND
+      // unique X_ID fix-ups in StartExchange 
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
+
+      // NOTE: unlike FC LinkService login frames, normal
+      // SCSI commands are sent without outgoing verification
+      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 64L;        // add len to LSB (header & CMND payload)
+
+      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
+
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+                   //             valid RO
+      CMDfchs->f_ctl = 0x08210008L;
+      CMDfchs->seq_cnt = 0x0L;
+      CMDfchs->ox_rx_id = 0L;        // clear for now (-or- in later)
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+                   // now, fill out FCP-DATA header
+                   // (use buffer inside SEST object)
+      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
+      dataHDR->reserved = 0L; // must clear
+      dataHDR->sof_eof = 0x75002000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
+      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] xfer S.I.| valid RO
+      dataHDR->f_ctl = 0x08010008L;
+      dataHDR->seq_cnt = 0x02000000L;  // sequence ID: df_ctl : seqence count
+      dataHDR->ox_rx_id = 0L;        // clear; fix-up dataHDR fields later
+      dataHDR->ro = 0x0L;    // relative offset (n/a)
+
+                   // Now setup the SEST entry
+      pIWE = &fcChip->SEST->u[ *fcExchangeIndex ].IWE;
+      
+                   // fill out the IWE:
+
+                // VALid entry:Dir outbound:DCM:enable CM:enal INT: FC frame len
+      pIWE->Hdr_Len = 0x8e000020L; // data frame Len always 32 bytes
+      
+      
+      // from login parameters with other port, what's the largest frame
+      // we can send? 
+      if( pLoggedInPort == NULL) 
+      {
+	ulStatus = INVALID_ARGS;  // failed! give up
+	break;
+      }
+      if( pLoggedInPort->rx_data_size  >= 2048)
+        fl = 0x00020000;  // 2048 code (only support 1024!)
+      else if( pLoggedInPort->rx_data_size  >= 1024)
+        fl = 0x00020000;  // 1024 code
+      else if( pLoggedInPort->rx_data_size  >= 512)
+        fl = 0x00010000;  // 512 code
+      else
+	fl = 0;  // 128 bytes -- should never happen
+      
+      
+      pIWE->Hdr_Len |= fl; // add xmit FC frame len for data phase
+      pIWE->Hdr_Addr = fcChip->SEST->base + 
+		((unsigned long)&fcChip->SEST->DataHDR[*fcExchangeIndex] - 
+			(unsigned long)fcChip->SEST);
+
+      pIWE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
+      pIWE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+      
+      memset( &fcChip->SEST->RspHDR[ *fcExchangeIndex].pl, 0, 
+        sizeof( FCP_STATUS_RESPONSE) );  // clear out previous status
+ 
+      pIWE->RSP_Addr = fcChip->SEST->base + 
+		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
+			(unsigned long)fcChip->SEST);
+
+                   // Do we need local or extended gather list?
+                   // depends on size - we can handle 3 len/addr pairs
+                   // locally.
+
+      fcp_dl = build_SEST_sgList( 
+	cpqfcHBAdata->PciDev,
+        &pIWE->GLen1, 
+        Cmnd,       // S/G list
+        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
+        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
+
+      if( !fcp_dl ) // error building S/G list?
+      {
+        ulStatus = MEMPOOL_FAIL;
+        break;      // give up
+      }
+
+                             // Now that we know total data length in
+                             // the passed S/G buffer, set FCP CMND frame
+      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
+
+
+      
+      if( sgPairs > 3 )  // need extended s/g list
+        pIWE->Buff_Off = 0x78000000L; // extended data | (no offset)
+      else               // local data pointers (in SEST)
+        pIWE->Buff_Off = 0xf8000000L; // local data | (no offset)
+
+                              // ULONG 5
+      pIWE->Link = 0x0000ffffL;   // Buff_Index | Link
+
+      pIWE->RX_ID = 0x0L;     // DWord 6: RX_ID set by target XFER_RDY
+
+                                      // DWord 7
+      pIWE->Data_Len = 0L;    // TL enters rcv'd XFER_RDY BURST_LEN
+      pIWE->Exp_RO = 0L;      // DWord 8
+                              // DWord 9
+      pIWE->Exp_Byte_Cnt = fcp_dl;  // sum of gather buffers
+    }
+    break;
+
+
+
+
+
+    case SCSI_IRE: // TachLite Initiator Read Entry
+
+      if( Cmnd->timeout != 0)
+      {
+//	printk("Cmnd->timeout %d\n", Cmnd->timeout);
+	// per Linux Scsi
+        Exchanges->fcExchange[ *fcExchangeIndex].timeOut = Cmnd->timeout;
+      }
+      else  // use our best guess, based on FC & device
+      {
+
+        if( Cmnd->SCp.Message == 1 ) // Tape device? (from INQUIRY)	
+	{
+	  // turn off our timeouts (for now...)
+          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 0xFFFFFFFF; 
+	}
+	else
+	{
+          Exchanges->fcExchange[ *fcExchangeIndex].reTries = 1;
+          Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 7; // per SCSI req.
+	}
+      }
+
+  
+      // first, build FCP_CMND
+
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS FCP-CMND (not SEST index)
+                            // NOTE: unlike FC LinkService login frames,
+                            // normal SCSI commands are sent "open loop"
+      IRB_flags.DCM = 1;    // Disable completion message for Cmnd frame
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += 64L;        // add len to LSB (header & CMND payload)
+
+      CMDfchs->d_id |= (0x06000000L);  // R_CTL = 6 for command
+
+             // TYPE[31-24] 8 for FCP SCSI
+             // f_ctl[23:0] exchg originator, 1st seq, xfer S.I.
+             //             valid RO
+      CMDfchs->f_ctl = 0x08210008L;
+      CMDfchs->seq_cnt = 0x0L;
+      // x_ID & data direction bit set later
+      CMDfchs->ox_rx_id = 0xFFFF;        // clear
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+
+
+                   // Now setup the SEST entry
+      pIRE = &fcChip->SEST->u[ *fcExchangeIndex ].IRE;
+
+      // fill out the IRE:
+      // VALid entry:Dir outbound:enable CM:enal INT:
+      pIRE->Seq_Accum = 0xCE000000L; // VAL,DIR inbound,DCM| INI,DAT,RSP
+
+      pIRE->reserved = 0L;
+      pIRE->RSP_Len = sizeof(TachFCHDR_RSP) ; // hdr+data (recv'd RSP frame)
+      pIRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+
+      pIRE->RSP_Addr = fcChip->SEST->base + 
+		((unsigned long)&fcChip->SEST->RspHDR[*fcExchangeIndex] - 
+			(unsigned long)fcChip->SEST);
+      
+                   // Do we need local or extended gather list?
+                   // depends on size - we can handle 3 len/addr pairs
+                   // locally.
+
+      fcp_dl = build_SEST_sgList( 
+	cpqfcHBAdata->PciDev,
+        &pIRE->SLen1, 
+        Cmnd,       // SCSI command Data desc. with S/G list
+        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
+        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
+      
+      
+      if( !fcp_dl ) // error building S/G list?
+      {
+	// It is permissible to have a ZERO LENGTH Read command.
+	// If there is the case, simply set fcp_dl (and Exp_Byte_Cnt)
+	// to 0 and continue.
+	if( Cmnd->request_bufflen == 0 )
+	{
+	  fcp_dl = 0; // no FC DATA frames expected
+
+	}
+	else
+	{
+          ulStatus = MEMPOOL_FAIL;
+          break;      // give up
+	}
+      }
+
+      // now that we know the S/G length, build CMND payload
+      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
+
+      
+      if( sgPairs > 3 )  // need extended s/g list
+        pIRE->Buff_Off = 0x00000000; // DWord 4: extended s/g list, no offset
+      else
+        pIRE->Buff_Off = 0x80000000; // local data, no offset
+      
+      pIRE->Buff_Index = 0x0L;    // DWord 5: Buff_Index | Reserved
+
+      pIRE->Exp_RO  = 0x0L;       // DWord 6: Expected Rel. Offset
+
+      pIRE->Byte_Count = 0;  // DWord 7: filled in by TL on err
+      pIRE->reserved_ = 0;   // DWord 8: reserved
+                             // NOTE: 0 length READ is OK.
+      pIRE->Exp_Byte_Cnt = fcp_dl;// DWord 9: sum of scatter buffers
+      
+      break;
+
+
+
+
+                         // Fibre Channel SCSI 'responder' sequences...
+                         // (originator means 'target' in FCP-SCSI)
+    case SCSI_TWE: // TachLite Target Write Entry
+
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
+
+                       // first, build FCP_CMND
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (XFER_RDY)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
+
+      CMDfchs->d_id |= (0x05000000L);  // R_CTL = 5 for XFER_RDY
+
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] exchg responder, 1st seq, xfer S.I.
+                //             valid RO
+      CMDfchs->f_ctl = 0x08810008L;
+      CMDfchs->seq_cnt = 0x01000000; // sequence ID: df_ctl: sequence count
+                       // use originator (other port's) OX_ID
+      CMDfchs->ox_rx_id = InFCHS->ox_rx_id;     // we want upper 16 bits
+      CMDfchs->ro = 0x0L;    // relative offset (n/a)
+
+                   // now, fill out FCP-RSP header
+                   // (use buffer inside SEST object)
+
+      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
+      rspHDR->reserved = 0L; // must clear
+      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
+      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] responder|last seq| xfer S.I.
+      rspHDR->f_ctl = 0x08910000L;
+      rspHDR->seq_cnt = 0x03000000;  // sequence ID
+      rspHDR->ox_rx_id = InFCHS->ox_rx_id; // gives us OX_ID
+      rspHDR->ro = 0x0L;    // relative offset (n/a)
+
+
+                   // Now setup the SEST entry
+                   
+      pTWE = &fcChip->SEST->u[ *fcExchangeIndex ].TWE;
+
+      // fill out the TWE:
+
+      // VALid entry:Dir outbound:enable CM:enal INT:
+      pTWE->Seq_Accum = 0xC4000000L;  // upper word flags
+      pTWE->reserved = 0L;
+      pTWE->Remote_Node_ID = 0L; // no more auto RSP frame! (TL/TS change)
+      pTWE->Remote_Node_ID |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+      
+
+                   // Do we need local or extended gather list?
+                   // depends on size - we can handle 3 len/addr pairs
+                   // locally.
+
+      fcp_dl = build_SEST_sgList( 
+	cpqfcHBAdata->PciDev,
+        &pTWE->SLen1, 
+        Cmnd,       // S/G list
+        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
+        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
+      
+      
+      if( !fcp_dl ) // error building S/G list?
+      {
+        ulStatus = MEMPOOL_FAIL;
+        break;      // give up
+      }
+
+      // now that we know the S/G length, build CMND payload
+      build_FCP_payload( Cmnd, (UCHAR*)&CMDfchs->pl[0], type, fcp_dl );
+
+      
+      if( sgPairs > 3 )  // need extended s/g list
+        pTWE->Buff_Off = 0x00000000; // extended s/g list, no offset
+      else
+        pTWE->Buff_Off = 0x80000000; // local data, no offset
+      
+      pTWE->Buff_Index = 0;     // Buff_Index | Link
+      pTWE->Exp_RO = 0;
+      pTWE->Byte_Count = 0;  // filled in by TL on err
+      pTWE->reserved_ = 0;
+      pTWE->Exp_Byte_Cnt = fcp_dl;// sum of scatter buffers
+      
+      break;
+
+
+
+
+
+
+    case SCSI_TRE: // TachLite Target Read Entry
+
+      // It doesn't make much sense for us to "time-out" a READ,
+      // but we'll use it for design consistency and internal error recovery.
+      Exchanges->fcExchange[ *fcExchangeIndex].timeOut = 10; // per SCSI req.
+
+      // I/O request block settings...
+      *pIRB_flags = 0;      // clear IRB flags
+                                  // check PRLI (process login) info
+                                  // to see if Initiator Requires XFER_RDY
+                                  // if not, don't send one!
+                                  // { PRLI check...}
+      IRB_flags.SFA = 0;    // don't send XFER_RDY - start data
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += (32L + 12L);// add SFS len (header & XFER_RDY payload)
+
+
+      
+      // now, fill out FCP-DATA header
+                   // (use buffer inside SEST object)
+      dataHDR = &fcChip->SEST->DataHDR[ *fcExchangeIndex ];
+
+      dataHDR->reserved = 0L; // must clear
+      dataHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn no UAM; no CLS,noLCr,no TS
+      dataHDR->d_id = (InFCHS->s_id | 0x01000000L); // R_CTL= FCP_DATA
+      dataHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+
+
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] exchg responder, not 1st seq, xfer S.I.
+                   //             valid RO
+      dataHDR->f_ctl = 0x08810008L;
+      dataHDR->seq_cnt = 0x01000000;  // sequence ID (no XRDY)
+      dataHDR->ox_rx_id = InFCHS->ox_rx_id & 0xFFFF0000; // we want upper 16 bits
+      dataHDR->ro = 0x0L;    // relative offset (n/a)
+
+                   // now, fill out FCP-RSP header
+                   // (use buffer inside SEST object)
+      rspHDR = &fcChip->SEST->RspHDR[ *fcExchangeIndex ];
+
+      rspHDR->reserved = 0L; // must clear
+      rspHDR->sof_eof = 0x75000000L;  // SOFi3:EOFn  no UAM; no CLS, noLCr, no TS
+      rspHDR->d_id = (InFCHS->s_id | 0x07000000L); // R_CTL= FCP_RSP
+      rspHDR->s_id = fcChip->Registers.my_al_pa; // CS_CTL = 0
+                   // TYPE[31-24] 8 for FCP SCSI
+                   // f_ctl[23:0] responder|last seq| xfer S.I.
+      rspHDR->f_ctl = 0x08910000L;
+      rspHDR->seq_cnt = 0x02000000;  // sequence ID: df_ctl: sequence count
+
+      rspHDR->ro = 0x0L;    // relative offset (n/a)
+
+
+      // Now setup the SEST entry
+      pTRE = &fcChip->SEST->u[ *fcExchangeIndex ].TRE;
+
+
+      // VALid entry:Dir outbound:enable CM:enal INT:
+      pTRE->Hdr_Len = 0x86010020L; // data frame Len always 32 bytes
+      pTRE->Hdr_Addr =  // bus address of dataHDR;
+            fcChip->SEST->base + 
+		((unsigned long)&fcChip->SEST->DataHDR[ *fcExchangeIndex ] -
+			(unsigned long)fcChip->SEST);
+	
+      pTRE->RSP_Len = 64L; // hdr+data (TL assisted RSP frame)
+      pTRE->RSP_Len |= (InFCHS->s_id << 8); // MS 24 bits Remote_ID
+      pTRE->RSP_Addr = // bus address of rspHDR
+		fcChip->SEST->base + 
+			((unsigned long)&fcChip->SEST->RspHDR[ *fcExchangeIndex ] -
+				(unsigned long)fcChip->SEST);
+
+                   // Do we need local or extended gather list?
+                   // depends on size - we can handle 3 len/addr pairs
+                   // locally.
+
+      fcp_dl = build_SEST_sgList( 
+	cpqfcHBAdata->PciDev,
+        &pTRE->GLen1, 
+        Cmnd,       // S/G list
+        &sgPairs,   // return # of pairs in S/G list (from "Data" descriptor)
+        &fcChip->SEST->sgPages[ *fcExchangeIndex ]);// (for Freeing later)
+      
+      
+      if( !fcp_dl ) // error building S/G list?
+      {
+        ulStatus = MEMPOOL_FAIL;
+        break;      // give up
+      }
+
+      // no payload or command to build -- READ doesn't need XRDY
+
+      
+      if( sgPairs > 3 )  // need extended s/g list
+        pTRE->Buff_Off = 0x78000000L; // extended data | (no offset)
+      else               // local data pointers (in SEST)
+        pTRE->Buff_Off = 0xf8000000L; // local data | (no offset)
+
+                                            // ULONG 5
+      pTRE->Buff_Index = 0L;   // Buff_Index | reserved
+      pTRE->reserved = 0x0L;   // DWord 6
+
+                                     // DWord 7: NOTE: zero length will
+                                     // hang TachLite!
+      pTRE->Data_Len = fcp_dl; // e.g. sum of scatter buffers
+
+      pTRE->reserved_ = 0L;     // DWord 8
+      pTRE->reserved__ = 0L;    // DWord 9
+
+      break;
+
+
+
+
+
+    
+
+    case FCP_RESPONSE: 
+                  // Target response frame: this sequence uses an OX/RX ID
+                  // pair from a completed SEST exchange.  We built most
+                  // of the response frame when we created the TWE/TRE.
+
+      *pIRB_flags = 0;      // clear IRB flags
+      IRB_flags.SFA = 1;    // send SFS (RSP)
+      SfsLen = *pIRB_flags;
+
+      SfsLen <<= 24;        // shift flags to MSB
+      SfsLen += sizeof(TachFCHDR_RSP);// add SFS len (header & RSP payload)
+      
+
+      Exchanges->fcExchange[ *fcExchangeIndex].type = 
+        FCP_RESPONSE; // change Exchange type to "response" phase
+
+      // take advantage of prior knowledge of OX/RX_ID pair from
+      // previous XFER outbound frame (still in fchs of exchange)
+      fcChip->SEST->RspHDR[ *fcExchangeIndex ].ox_rx_id = 
+        CMDfchs->ox_rx_id;
+
+      // Check the status of the DATA phase of the exchange so we can report
+      // status to the initiator
+      buildFCPstatus( fcChip, *fcExchangeIndex); // set RSP payload fields
+
+      memcpy(
+        CMDfchs,  // re-use same XFER fchs for Response frame
+        &fcChip->SEST->RspHDR[ *fcExchangeIndex ],
+        sizeof( TachFCHDR_RSP ));
+      
+        
+      break;
+
+    default:
+      printk("cpqfcTS: don't know how to build FC type: %Xh(%d)\n", type,type);
+      break;
+
+    }
+
+    
+    
+    if( !ulStatus)  // no errors above?
+    {
+      // FCHS is built; now build IRB
+
+      // link the just built FCHS (the "command") to the IRB entry 
+      // for this Exchange.
+      pIRB = &Exchanges->fcExchange[ *fcExchangeIndex].IRB; 
+    
+                          // len & flags according to command type above
+      pIRB->Req_A_SFS_Len = SfsLen;  // includes IRB flags & len
+      pIRB->Req_A_SFS_Addr = // TL needs physical addr of frame to send
+		fcChip->exch_dma_handle + (unsigned long)CMDfchs - 
+			(unsigned long)Exchanges;
+
+      pIRB->Req_A_SFS_D_ID = CMDfchs->d_id << 8; // Dest_ID must be consistent!
+
+    // Exchange is complete except for "fix-up" fields to be set
+    // at Tachyon Queuing time:
+    //    IRB->Req_A_Trans_ID (OX_ID/ RX_ID):  
+    //        for SEST entry, lower bits correspond to actual FC Exchange ID
+    //    fchs->OX_ID or RX_ID
+    }
+    else
+    {
+#ifdef DBG     
+      printk( "FC Error: SEST build Pool Allocation failed\n");
+#endif
+      // return resources...
+      cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, *fcExchangeIndex);  // SEST build failed
+    }
+  }
+  else  // no Exchanges available
+  {
+    ulStatus = SEST_FULL;
+    printk( "FC Error: no fcExchanges available\n");
+  }
+  return ulStatus;
+}
+
+
+
+
+
+
+// set RSP payload fields
+static void  buildFCPstatus( PTACHYON fcChip, ULONG ExchangeID) 
+{
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ExchangeID];  // shorthand
+  PFCP_STATUS_RESPONSE pFcpStatus;
+  
+  memset( &fcChip->SEST->RspHDR[ ExchangeID ].pl, 0,
+    sizeof( FCP_STATUS_RESPONSE) );
+  if( pExchange->status ) // something wrong?
+  {
+    pFcpStatus = (PFCP_STATUS_RESPONSE)  // cast RSP buffer for this xchng
+      &fcChip->SEST->RspHDR[ ExchangeID ].pl;
+    if( pExchange->status & COUNT_ERROR )
+    {
+      
+      // set FCP response len valid (so we can report count error)
+      pFcpStatus->fcp_status |= FCP_RSP_LEN_VALID;
+      pFcpStatus->fcp_rsp_len = 0x04000000;  // 4 byte len (BIG Endian)
+
+      pFcpStatus->fcp_rsp_info = FCP_DATA_LEN_NOT_BURST_LEN; // RSP_CODE
+    }
+  }
+}
+
+
+static dma_addr_t 
+cpqfc_pci_map_sg_page(
+    		struct pci_dev *pcidev,
+		ULONG *hw_paddr, 	// where to put phys addr for HW use
+		void *sgp_vaddr,	// the virtual address of the sg page 
+	 	dma_addr_t *umap_paddr,	// where to put phys addr for unmap
+		unsigned int *maplen,	// where to store sg entry length
+		int PairCount)		// number of sg pairs used in the page.	
+{
+	unsigned long aligned_addr = (unsigned long) sgp_vaddr;
+
+	*maplen = PairCount * 8;
+        aligned_addr += TL_EXT_SG_PAGE_BYTELEN;
+        aligned_addr &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
+	
+	*umap_paddr = pci_map_single(pcidev, (void *) aligned_addr, 
+				*maplen, PCI_DMA_TODEVICE);
+	*hw_paddr = (ULONG) *umap_paddr;
+
+#       if BITS_PER_LONG > 32
+       		if( *umap_paddr >>32 ) {
+       	  		printk("cqpfcTS:Tach SG DMA addr %p>32 bits\n", 
+	  			(void*)umap_paddr);
+       			return 0;
+       		}
+#       endif
+	return *umap_paddr;
+}
+
+static void
+cpqfc_undo_SEST_mappings(struct pci_dev *pcidev,
+			unsigned long contigaddr, int len, int dir,
+  			struct scatterlist *sgl, int use_sg,
+    			PSGPAGES *sgPages_head,
+			int allocated_pages)
+{
+	PSGPAGES i, next;
+
+	if (contigaddr != (unsigned long) NULL)
+		pci_unmap_single(pcidev, contigaddr, len, dir);
+
+	if (sgl != NULL)
+		pci_unmap_sg(pcidev, sgl, use_sg, dir);
+
+	for (i=*sgPages_head; i != NULL ;i = next)
+	{
+		pci_unmap_single(pcidev, i->busaddr, i->maplen, 
+			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+		i->busaddr = (dma_addr_t) NULL; 
+		i->maplen = 0L; 
+		next = i->next;
+		kfree(i); 
+	}
+	*sgPages_head = NULL;
+}
+
+// This routine builds scatter/gather lists into SEST entries
+// INPUTS:
+//   SESTalPair - SEST address @DWordA "Local Buffer Length"
+//   sgList     - Scatter/Gather linked list of Len/Address data buffers
+// OUTPUT:
+//   sgPairs - number of valid address/length pairs
+// Remarks:
+//   The SEST data buffer pointers only depend on number of
+//   length/ address pairs, NOT on the type (IWE, TRE,...)
+//   Up to 3 pairs can be referenced in the SEST - more than 3
+//   require this Extended S/G list page.  The page holds 4, 8, 16...
+//   len/addr pairs, per Scatter/Gather List Page Length Reg.
+//   TachLite allows pages to be linked to any depth.
+
+//#define DBG_SEST_SGLIST 1 // for printing out S/G pairs with Ext. pages
+
+static int ap_hi_water = TL_DANGER_SGPAGES;
+
+static ULONG build_SEST_sgList( 
+    struct pci_dev *pcidev,
+    ULONG *SESTalPairStart,  // the 3 len/address buffers in SEST
+    Scsi_Cmnd *Cmnd,
+    ULONG *sgPairs, 
+    PSGPAGES *sgPages_head)  // link list of TL Ext. S/G pages from O/S Pool
+    
+{
+  ULONG i, AllocatedPages=0; // Tach Ext. S/G page allocations
+  ULONG* alPair = SESTalPairStart;
+  ULONG* ext_sg_page_phys_addr_place = NULL;
+  int PairCount;
+  unsigned long ulBuff, contigaddr;
+  ULONG total_data_len=0; // (in bytes)
+  ULONG bytes_to_go = Cmnd->request_bufflen; // total xfer (S/G sum)
+  ULONG thisMappingLen;
+  struct scatterlist *sgl = NULL;  // S/G list (Linux format)
+  int sg_count, totalsgs; 
+  dma_addr_t busaddr;
+  unsigned long thislen, offset;
+  PSGPAGES *sgpage = sgPages_head;
+  PSGPAGES prev_page = NULL;
+
+# define WE_HAVE_SG_LIST (sgl != (unsigned long) NULL)
+  contigaddr = (unsigned long) NULL;
+
+  if( !Cmnd->use_sg )  // no S/G list?
+  {
+	if (bytes_to_go <= TL_MAX_SG_ELEM_LEN)
+	{
+    		*sgPairs = 1;	// use "local" S/G pair in SEST entry
+				// (for now, ignore address bits above #31)
+
+		*alPair++ = bytes_to_go; // bits 18-0, length
+
+		if (bytes_to_go != 0) {
+			contigaddr = ulBuff = pci_map_single(pcidev, 
+				Cmnd->request_buffer, 
+				Cmnd->request_bufflen,
+				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+			// printk("ms %p ", ulBuff);
+		}
+		else {
+			// No data transfer, (e.g.: Test Unit Ready)
+			// printk("btg=0 ");
+			*sgPairs = 0;
+			memset(alPair, 0, sizeof(*alPair));
+			return 0;
+		}
+
+#		if BITS_PER_LONG > 32
+    			if( ulBuff >>32 ) {
+      				printk("FATAL! Tachyon DMA address %p "
+					"exceeds 32 bits\n", (void*)ulBuff );
+      				return 0;
+    			}
+#		endif
+    		*alPair = (ULONG)ulBuff;      
+    		return bytes_to_go;
+	} 
+	else	// We have a single large (too big) contiguous buffer.
+	{	// We will have to break it up.  We'll use the scatter
+		// gather code way below, but use contigaddr instead
+		// of sg_dma_addr(). (this is a very rare case).
+
+		unsigned long btg;
+		contigaddr = pci_map_single(pcidev, Cmnd->request_buffer, 
+				Cmnd->request_bufflen,
+				scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+		// printk("contigaddr = %p, len = %d\n", 
+		//	(void *) contigaddr, bytes_to_go);
+		totalsgs = 0;
+		for (btg = bytes_to_go; btg > 0; ) {
+			btg -= ( btg > TL_MAX_SG_ELEM_LEN ? 
+				TL_MAX_SG_ELEM_LEN : btg );
+			totalsgs++;
+		}
+		sgl = NULL;
+		*sgPairs = totalsgs;
+	}
+  }
+  else  // we do have a scatter gather list
+  {
+	// [TBD - update for Linux to support > 32 bits addressing]
+	// since the format for local & extended S/G lists is different,
+	// check if S/G pairs exceeds 3.
+	// *sgPairs = Cmnd->use_sg; Nope, that's wrong.
+ 
+	sgl = (struct scatterlist*)Cmnd->request_buffer;  
+	sg_count = pci_map_sg(pcidev, sgl, Cmnd->use_sg, 
+		scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+  	if( sg_count <= 3 ) {
+
+	// we need to be careful here that no individual mapping
+	// is too large, and if any is, that breaking it up
+	// doesn't push us over 3 sgs, or, if it does, that we
+	// handle that case.  Tachyon can take 0x7FFFF bits for length,
+	// but sg structure uses "unsigned int", on the face of it, 
+	// up to 0xFFFFFFFF or even more.
+
+		int i;
+		unsigned long thislen;
+
+		totalsgs = 0;
+		for (i=0;i<sg_count;i++) {
+      			thislen = sg_dma_len(&sgl[i]);
+			while (thislen >= TL_MAX_SG_ELEM_LEN) {
+				totalsgs++;
+				thislen -= TL_MAX_SG_ELEM_LEN;
+			}
+			if (thislen > 0) totalsgs++;
+		}
+		*sgPairs = totalsgs;
+  	} else totalsgs = 999; // as a first estimate, definitely >3, 
+			      
+	// if (totalsgs != sg_count) 
+	//	printk("totalsgs = %d, sgcount=%d\n",totalsgs,sg_count);
+  }
+
+  if( totalsgs <= 3 ) // can (must) use "local" SEST list
+  {
+    while( bytes_to_go)
+    {
+      offset = 0L;
+
+      if ( WE_HAVE_SG_LIST ) 
+	thisMappingLen = sg_dma_len(sgl);
+      else					// or contiguous buffer?
+	thisMappingLen = bytes_to_go;
+
+      while (thisMappingLen > 0)
+      {  
+	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
+		TL_MAX_SG_ELEM_LEN : thisMappingLen;
+	bytes_to_go = bytes_to_go - thislen;
+
+	// we have L/A pair; L = thislen, A = physicalAddress
+	// load into SEST...
+
+	total_data_len += thislen;
+	*alPair = thislen; // bits 18-0, length
+
+	alPair++;
+
+	if ( WE_HAVE_SG_LIST ) 
+		ulBuff = sg_dma_address(sgl) + offset;
+	else
+		ulBuff = contigaddr + offset;
+
+	offset += thislen;
+
+#	if BITS_PER_LONG > 32
+		if( ulBuff >>32 ) {
+        		printk("cqpfcTS: 2Tach DMA address %p > 32 bits\n", 
+				(void*)ulBuff );
+		    printk("%s = %p, offset = %ld\n", 
+			WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
+			WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
+				offset);
+        		return 0;
+      		}
+#	endif
+        *alPair++ = (ULONG)ulBuff; // lower 32 bits (31-0)
+	thisMappingLen -= thislen;
+      }
+
+      if ( WE_HAVE_SG_LIST ) ++sgl;  // next S/G pair
+	else if (bytes_to_go != 0) printk("BTG not zero!\n");
+
+#     ifdef DBG_SEST_SGLIST
+	printk("L=%d ", thisMappingLen);
+	printk("btg=%d ", bytes_to_go);
+#     endif
+
+    }
+    // printk("i:%d\n", *sgPairs);
+  }
+  else    // more than 3 pairs requires Extended S/G page (Pool Allocation)
+  {
+    // clear out SEST DWORDs (local S/G addr) C-F (A-B set in following logic)
+    for( i=2; i<6; i++)
+      alPair[i] = 0;
+
+    PairCount = TL_EXT_SG_PAGE_COUNT;    // forces initial page allocation
+    totalsgs = 0;
+    while( bytes_to_go )
+    {
+      // Per SEST format, we can support 524287 byte lengths per
+      // S/G pair.  Typical user buffers are 4k, and very rarely
+      // exceed 12k due to fragmentation of physical memory pages.
+      // However, on certain O/S system (not "user") buffers (on platforms 
+      // with huge memories), it's possible to exceed this
+      // length in a single S/G address/len mapping, so we have to handle
+      // that.
+
+      offset = 0L;
+      if ( WE_HAVE_SG_LIST ) 
+	thisMappingLen = sg_dma_len(sgl);
+      else
+	thisMappingLen = bytes_to_go;
+
+      while (thisMappingLen > 0)
+      {
+	thislen = thisMappingLen > TL_MAX_SG_ELEM_LEN ? 
+		TL_MAX_SG_ELEM_LEN : thisMappingLen;
+	// printk("%d/%d/%d\n", thislen, thisMappingLen, bytes_to_go);
+      
+  	// should we load into "this" extended S/G page, or allocate
+	// new page?
+
+	if( PairCount >= TL_EXT_SG_PAGE_COUNT )
+	{
+	  // Now, we have to map the previous page, (triggering buffer bounce)
+	  // The first time thru the loop, there won't be a previous page.
+	  if (prev_page != NULL) // is there a prev page? 
+	  {
+		// this code is normally kind of hard to trigger, 
+		// you have to use up more than 256 scatter gather 
+		// elements to get here.  Cranking down TL_MAX_SG_ELEM_LEN
+		// to an absurdly low value (128 bytes or so) to artificially
+		// break i/o's into a zillion pieces is how I tested it. 
+		busaddr = cpqfc_pci_map_sg_page(pcidev,
+				ext_sg_page_phys_addr_place,
+				prev_page->page,
+        			&prev_page->busaddr,
+        			&prev_page->maplen,
+				PairCount);
+          } 
+          // Allocate the TL Extended S/G list page.  We have
+          // to allocate twice what we want to ensure required TL alignment
+          // (Tachlite TL/TS User Man. Rev 6.0, p 168)
+          // We store the original allocated PVOID so we can free later
+	  *sgpage = kmalloc( sizeof(SGPAGES), GFP_ATOMIC);
+	  if ( ! *sgpage )
+          {
+		printk("cpqfc: Allocation failed @ %d S/G page allocations\n",
+			AllocatedPages);
+		total_data_len = 0;  // failure!! Ext. S/G is All-or-none affair
+
+	        // unmap the previous mappings, if any.
+
+	        cpqfc_undo_SEST_mappings(pcidev, contigaddr, 
+			Cmnd->request_bufflen,
+			scsi_to_pci_dma_dir(Cmnd->sc_data_direction),
+  			sgl, Cmnd->use_sg, sgPages_head, AllocatedPages+1);
+
+		// FIXME: testing shows that if we get here, 
+		// it's bad news.  (this has been this way for a long 
+		// time though, AFAIK.  Not that that excuses it.)
+
+		return 0; // give up (and probably hang the system)
+          }
+                               // clear out memory we just allocated
+	  memset( (*sgpage)->page,0,TL_EXT_SG_PAGE_BYTELEN*2);
+	  (*sgpage)->next = NULL;
+	  (*sgpage)->busaddr = (dma_addr_t) NULL;
+	  (*sgpage)->maplen = 0L;
+      
+	  // align the memory - TL requires sizeof() Ext. S/G page alignment.
+	  // We doubled the actual required size so we could mask off LSBs 
+	  // to get desired offset 
+
+	  ulBuff = (unsigned long) (*sgpage)->page;
+	  ulBuff += TL_EXT_SG_PAGE_BYTELEN;
+	  ulBuff &= ~(TL_EXT_SG_PAGE_BYTELEN -1);
+
+	  // set pointer, in SEST if first Ext. S/G page, or in last pair
+	  // of linked Ext. S/G pages... (Only 32-bit PVOIDs, so just 
+	  // load lower 32 bits)
+	  // NOTE: the Len field must be '0' if this is the first Ext. S/G
+	  // pointer in SEST, and not 0 otherwise (we know thislen != 0).
+
+	  *alPair = (alPair != SESTalPairStart) ? thislen : 0;
+
+#	  ifdef DBG_SEST_SGLIST
+        	printk("PairCount %d @%p even %Xh, ", 
+			PairCount, alPair, *alPair);
+#	  endif
+
+	  // Save the place where we need to store the physical
+	  // address of this scatter gather page which we get when we map it
+	  // (and mapping we can do only after we fill it in.)
+	  alPair++;  // next DWORD, will contain phys addr of the ext page
+	  ext_sg_page_phys_addr_place = alPair;
+
+	  // Now, set alPair = the virtual addr of the (Extended) S/G page
+	  // which will accept the Len/ PhysicalAddress pairs
+	  alPair = (ULONG *) ulBuff;
+
+	  AllocatedPages++;
+	  if (AllocatedPages >= ap_hi_water)
+	  {
+		// This message should rarely, if ever, come out.
+		// Previously (cpqfc version <= 2.0.5) the driver would
+		// just puke if more than 4 SG pages were used, and nobody
+		// ever complained about that.  This only comes out if 
+		// more than 8 pages are used.
+
+		printk(KERN_WARNING
+		"cpqfc: Possible danger.  %d scatter gather pages used.\n"
+			"cpqfc: detected seemingly extreme memory "
+			"fragmentation or huge data transfers.\n", 
+			AllocatedPages);
+		ap_hi_water = AllocatedPages+1;
+	  }
+		
+	  PairCount = 1;  // starting new Ext. S/G page
+	  prev_page = (*sgpage);  // remember this page, for next time thru
+	  sgpage = &((*sgpage)->next);
+	}  // end of new TL Ext. S/G page allocation
+
+	*alPair = thislen; // bits 18-0, length (range check above)
+      
+#	ifdef DBG_SEST_SGLIST
+	  printk("PairCount %d @%p, even %Xh, ", PairCount, alPair, *alPair);
+#	endif
+
+	alPair++;    // next DWORD, physical address 
+
+	if ( WE_HAVE_SG_LIST ) 
+		ulBuff = sg_dma_address(sgl) + offset;
+	else
+		ulBuff = contigaddr + offset;
+	offset += thislen;
+
+#	if BITS_PER_LONG > 32
+          if( ulBuff >>32 )
+	  {
+	    printk("cqpfcTS: 1Tach DMA address %p > 32 bits\n", (void*)ulBuff );
+	    printk("%s = %p, offset = %ld\n", 
+		WE_HAVE_SG_LIST ? "ulBuff" : "contigaddr",
+		WE_HAVE_SG_LIST ? (void *) ulBuff : (void *) contigaddr,
+			offset);
+	    return 0;
+	  }
+#	endif
+
+	*alPair = (ULONG) ulBuff; // lower 32 bits (31-0)
+
+#       ifdef DBG_SEST_SGLIST
+        printk("odd %Xh\n", *alPair);
+#       endif
+	alPair++;    // next DWORD, next address/length pair
+                                           
+	PairCount++; // next Length/Address pair
+
+	// if (PairCount > pc_hi_water)
+	// {
+		// printk("pc hi = %d ", PairCount);
+		// pc_hi_water = PairCount;
+	// }
+	bytes_to_go -= thislen;
+	total_data_len += thislen;  
+	thisMappingLen -= thislen;
+	totalsgs++;
+      } // while (thisMappingLen > 0)
+      if ( WE_HAVE_SG_LIST ) sgl++;  // next S/G pair
+    } // while (bytes_to_go)
+
+    // printk("Totalsgs=%d\n", totalsgs);
+    *sgPairs = totalsgs;
+
+    // PCI map (and bounce) the last (and usually only) extended SG page
+    busaddr = cpqfc_pci_map_sg_page(pcidev,
+		ext_sg_page_phys_addr_place,
+		prev_page->page, 
+		&prev_page->busaddr, 
+		&prev_page->maplen,
+		PairCount);
+  }
+  return total_data_len;
+}
+
+
+
+// The Tachlite SEST table is referenced to OX_ID (or RX_ID).  To optimize
+// performance and debuggability, we index the Exchange structure to FC X_ID
+// This enables us to build exchanges for later en-queing to Tachyon,
+// provided we have an open X_ID slot. At Tachyon queing time, we only 
+// need an ERQ slot; then "fix-up" references in the 
+// IRB, FCHS, etc. as needed.
+// RETURNS:
+// 0 if successful
+// non-zero on error
+//sstartex
+ULONG cpqfcTSStartExchange( 
+  CPQFCHBA *cpqfcHBAdata,                      
+  LONG ExchangeID )
+{
+  PTACHYON fcChip = &cpqfcHBAdata->fcChip;
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  FC_EXCHANGE *pExchange = &Exchanges->fcExchange[ ExchangeID ]; // shorthand
+  USHORT producer, consumer;
+  ULONG ulStatus=0;
+  short int ErqIndex;
+  BOOLEAN CompleteExchange = FALSE;  // e.g. ACC replies are complete
+  BOOLEAN SestType=FALSE;
+  ULONG InboundData=0;
+
+  // We will manipulate Tachlite chip registers here to successfully
+  // start exchanges. 
+
+  // Check that link is not down -- we can't start an exchange on a
+  // down link!
+
+  if( fcChip->Registers.FMstatus.value & 0x80) // LPSM offline?
+  {
+printk("fcStartExchange: PSM offline (%Xh), x_ID %Xh, type %Xh, port_id %Xh\n",
+         fcChip->Registers.FMstatus.value & 0xFF,
+         ExchangeID,
+         pExchange->type,
+         pExchange->fchs.d_id);
+
+    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
+    {
+      // Our most popular LinkService commands are port discovery types
+      // (PLOGI/ PDISC...), which are implicitly nullified by Link Down
+      // events, so it makes no sense to Que them.  However, ABTS should
+      // be queued, since exchange sequences are likely destroyed by
+      // Link Down events, and we want to notify other ports of broken
+      // sequences by aborting the corresponding exchanges.
+      if( pExchange->type != BLS_ABTS )
+      {
+	ulStatus = LNKDWN_OSLS;
+	goto Done;
+        // don't Que most LinkServ exchanges on LINK DOWN
+      }
+    }
+
+    printk("fcStartExchange: Que x_ID %Xh, type %Xh\n", 
+      ExchangeID, pExchange->type);
+    pExchange->status |= EXCHANGE_QUEUED;
+    ulStatus = EXCHANGE_QUEUED;
+    goto Done;
+  }
+
+  // Make sure ERQ has available space.
+  
+  producer = (USHORT)fcChip->ERQ->producerIndex; // copies for logical arith.
+  consumer = (USHORT)fcChip->ERQ->consumerIndex;
+  producer++;  // We are testing for full que by incrementing
+  
+  if( producer >= ERQ_LEN )  // rollover condition?
+    producer = 0;
+  if( consumer != producer ) // ERQ not full?
+  {
+    // ****************** Need Atomic access to chip registers!!********
+    
+    // remember ERQ PI for copying IRB
+    ErqIndex = (USHORT)fcChip->ERQ->producerIndex; 
+    fcChip->ERQ->producerIndex = producer; // this is written to Tachyon
+               // we have an ERQ slot! If SCSI command, need SEST slot
+               // otherwise we are done.
+
+    // Note that Tachyon requires that bit 15 of the OX_ID or RX_ID be
+    // set according to direction of data to/from Tachyon for SEST assists.
+    // For consistency, enforce this rule for Link Service (non-SEST)
+    // exchanges as well.
+
+    // fix-up the X_ID field in IRB
+    pExchange->IRB.Req_A_Trans_ID = ExchangeID & 0x7FFF; // 15-bit field
+
+    // fix-up the X_ID field in fchs -- depends on Originator or Responder,
+    // outgoing or incoming data?
+    switch( pExchange->type )
+    {
+               // ORIGINATOR types...  we're setting our OX_ID and
+               // defaulting the responder's RX_ID to 0xFFFF
+    
+    case SCSI_IRE:
+      // Requirement: set MSB of x_ID for Incoming TL data
+      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+      InboundData = 0x8000;
+
+    case SCSI_IWE:   
+      SestType = TRUE;
+      pExchange->fchs.ox_rx_id = (ExchangeID | InboundData);
+      pExchange->fchs.ox_rx_id <<= 16;     // MSW shift
+      pExchange->fchs.ox_rx_id |= 0xffff;  // add default RX_ID
+      
+      // now fix-up the Data HDR OX_ID (TL automatically does rx_id)
+      // (not necessary for IRE -- data buffer unused)
+      if( pExchange->type == SCSI_IWE)
+      {
+        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id = 
+          pExchange->fchs.ox_rx_id;
+
+      }
+
+      break;
+
+
+    case FCS_NSR:  // ext. link service Name Service Request
+    case ELS_SCR:  // ext. link service State Change Registration
+    case ELS_FDISC:// ext. link service login
+    case ELS_FLOGI:// ext. link service login
+    case ELS_LOGO: // FC-PH extended link service logout
+    case BLS_NOP:  // Basic link service No OPeration
+    case ELS_PLOGI:// ext. link service login (PLOGI)
+    case ELS_PDISC:// ext. link service login (PDISC)
+    case ELS_PRLI: // ext. link service process login
+
+      pExchange->fchs.ox_rx_id = ExchangeID;
+      pExchange->fchs.ox_rx_id <<= 16;  // MSW shift
+      pExchange->fchs.ox_rx_id |= 0xffff;  // and RX_ID
+
+      break;
+      
+
+
+
+               // RESPONDER types... we must set our RX_ID while preserving
+               // sender's OX_ID
+               // outgoing (or no) data
+    case ELS_RJT:       // extended link service reject 
+    case ELS_LOGO_ACC: // FC-PH extended link service logout accept
+    case ELS_ACC:      // ext. generic link service accept
+    case ELS_PLOGI_ACC:// ext. link service login accept (PLOGI or PDISC)
+    case ELS_PRLI_ACC: // ext. link service process login accept
+
+      CompleteExchange = TRUE;   // Reply (ACC or RJT) is end of exchange
+      pExchange->fchs.ox_rx_id |= (ExchangeID & 0xFFFF);
+
+      break;
+
+
+      // since we are a Responder, OX_ID should already be set by
+      // cpqfcTSBuildExchange().  We need to -OR- in RX_ID
+    case SCSI_TWE:
+      SestType = TRUE;
+      // Requirement: set MSB of x_ID for Incoming TL data
+      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+
+      pExchange->fchs.ox_rx_id &= 0xFFFF0000;  // clear RX_ID
+      // Requirement: set MSB of RX_ID for Incoming TL data
+      // (see "Tachyon TL/TS User's Manual", Rev 6.0, Sept.'98, pg. 50)
+      pExchange->fchs.ox_rx_id |= (ExchangeID | 0x8000);
+      break;
+          
+    
+    case SCSI_TRE:
+      SestType = TRUE;
+      
+      // there is no XRDY for SEST target read; the data
+      // header needs to be updated. Also update the RSP
+      // exchange IDs for the status frame, in case it is sent automatically
+      fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id |= ExchangeID;
+      fcChip->SEST->RspHDR[ ExchangeID ].ox_rx_id = 
+        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
+      
+      // for easier FCP response logic (works for TWE and TRE), 
+      // copy exchange IDs.  (Not needed if TRE 'RSP' bit set)
+      pExchange->fchs.ox_rx_id =
+        fcChip->SEST->DataHDR[ ExchangeID ].ox_rx_id;
+
+      break;
+
+
+    case FCP_RESPONSE:  // using existing OX_ID/ RX_ID pair,
+                        // start SFS FCP-RESPONSE frame
+      // OX/RX_ID should already be set! (See "fcBuild" above)
+      CompleteExchange = TRUE;   // RSP is end of FCP-SCSI exchange
+
+      
+      break;
+
+
+    case BLS_ABTS_RJT:  // uses new RX_ID, since SEST x_ID non-existent
+    case BLS_ABTS_ACC:  // using existing OX_ID/ RX_ID pair from SEST entry
+      CompleteExchange = TRUE;   // ACC or RJT marks end of FCP-SCSI exchange
+    case BLS_ABTS:  // using existing OX_ID/ RX_ID pair from SEST entry
+
+
+      break;
+
+
+    default:
+      printk("Error on fcStartExchange: undefined type %Xh(%d)\n",
+        pExchange->type, pExchange->type);
+      return INVALID_ARGS;
+    }
+    
+    
+      // X_ID fields are entered -- copy IRB to Tachyon's ERQ
+    
+
+    memcpy(
+        &fcChip->ERQ->QEntry[ ErqIndex ],  // dest.
+        &pExchange->IRB,
+        32);  // fixed (hardware) length!
+
+    PCI_TRACEO( ExchangeID, 0xA0)
+
+    // ACTION!  May generate INT and IMQ entry
+    writel( fcChip->ERQ->producerIndex,
+          fcChip->Registers.ERQproducerIndex.address);
+
+  
+    if( ExchangeID >= TACH_SEST_LEN )  // Link Service Outbound frame?
+    {
+    
+      // wait for completion! (TDB -- timeout and chip reset)
+      
+
+  PCI_TRACEO( ExchangeID, 0xA4)
+  
+      enable_irq( cpqfcHBAdata->HostAdapter->irq); // only way to get Sem.
+      
+      down_interruptible( cpqfcHBAdata->TYOBcomplete); 
+  
+      disable_irq( cpqfcHBAdata->HostAdapter->irq);
+  PCI_TRACE( 0xA4)
+
+      // On login exchanges, BAD_ALPA (non-existent port_id) results in 
+      // FTO (Frame Time Out) on the Outbound Completion message.
+      // If we got an FTO status, complete the exchange (free up slot)
+      if( CompleteExchange ||   // flag from Reply frames
+          pExchange->status )   // typically, can get FRAME_TO
+      {
+    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
+      }
+    }
+
+    else                         // SEST Exchange
+    {
+      ulStatus = 0;   // ship & pray success (e.g. FCP-SCSI)
+      
+      if( CompleteExchange )   // by Type of exchange (e.g. end-of-xchng)
+      {
+    	cpqfcTSCompleteExchange( cpqfcHBAdata->PciDev, fcChip, ExchangeID);  
+      }
+       
+      else
+        pExchange->status &= ~EXCHANGE_QUEUED;  // clear ExchangeQueued flag 
+
+    }
+  }
+
+  
+  else                // ERQ 'producer' = 'consumer' and QUE is full
+  {
+    ulStatus = OUTQUE_FULL; // Outbound (ERQ) Que full
+  }
+ 
+Done: 
+  PCI_TRACE( 0xA0)
+  return ulStatus; 
+}
+
+
+
+
+
+// Scan fcController->fcExchanges array for a usuable index (a "free"
+// exchange).
+// Inputs:
+//   fcChip - pointer to TachLite chip structure
+// Return:
+//  index - exchange array element where exchange can be built
+//  -1    - exchange array is full
+// REMARKS:
+// Although this is a (yuk!) linear search, we presume
+// that the system will complete exchanges about as quickly as
+// they are submitted.  A full Exchange array (and hence, max linear
+// search time for free exchange slot) almost guarantees a Fibre problem 
+// of some sort.
+// In the interest of making exchanges easier to debug, we want a LRU
+// (Least Recently Used) scheme.
+
+
+static LONG FindFreeExchange( PTACHYON fcChip, ULONG type )
+{
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  ULONG i;
+  ULONG ulStatus=-1;  // assume failure
+
+
+  if( type == SCSI_IRE ||
+      type == SCSI_TRE ||
+      type == SCSI_IWE ||
+      type == SCSI_TWE)
+  {
+        // SCSI type - X_IDs should be from 0 to TACH_SEST_LEN-1
+    if( fcChip->fcSestExchangeLRU >= TACH_SEST_LEN) // rollover?
+      fcChip->fcSestExchangeLRU = 0;
+    i = fcChip->fcSestExchangeLRU; // typically it's already free!
+
+    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
+    {
+      ulStatus = 0; // success!
+    }
+    
+    else
+    {         // YUK! we need to do a linear search for free element.
+              // Fragmentation of the fcExchange array is due to excessively
+              // long completions or timeouts.
+      
+      while( TRUE )
+      {
+        if( ++i >= TACH_SEST_LEN ) // rollover check
+          i = 0;  // beginning of SEST X_IDs
+
+//        printk( "looping for SCSI xchng ID: i=%d, type=%Xh\n", 
+//         i, Exchanges->fcExchange[i].type);
+
+        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
+        {
+          ulStatus = 0; // success!
+          break;
+        }
+        if( i == fcChip->fcSestExchangeLRU ) // wrapped-around array?
+        {
+          printk( "SEST X_ID space full\n");
+          break;       // failed - prevent inf. loop
+        }
+      }
+    }
+    fcChip->fcSestExchangeLRU = i + 1; // next! (rollover check next pass)
+  }
+
+  
+  
+  else  // Link Service type - X_IDs should be from TACH_SEST_LEN 
+        // to TACH_MAX_XID
+  {
+    if( fcChip->fcLsExchangeLRU >= TACH_MAX_XID || // range check
+        fcChip->fcLsExchangeLRU < TACH_SEST_LEN ) // (e.g. startup)
+      fcChip->fcLsExchangeLRU = TACH_SEST_LEN;
+
+    i = fcChip->fcLsExchangeLRU; // typically it's already free!
+    if( Exchanges->fcExchange[i].type == 0 ) // check for "free" element
+    {
+      ulStatus = 0; // success!
+    }
+    
+    else
+    {         // YUK! we need to do a linear search for free element
+              // Fragmentation of the fcExchange array is due to excessively
+              // long completions or timeouts.
+      
+      while( TRUE )
+      {
+        if( ++i >= TACH_MAX_XID ) // rollover check
+          i = TACH_SEST_LEN;// beginning of Link Service X_IDs
+
+//        printk( "looping for xchng ID: i=%d, type=%Xh\n", 
+//         i, Exchanges->fcExchange[i].type);
+
+        if( Exchanges->fcExchange[i].type == 0 ) // "free"?
+        {
+          ulStatus = 0; // success!
+          break;
+        }
+        if( i == fcChip->fcLsExchangeLRU ) // wrapped-around array?
+        {
+          printk( "LinkService X_ID space full\n");
+          break;       // failed - prevent inf. loop
+        }
+      }
+    }
+    fcChip->fcLsExchangeLRU = i + 1; // next! (rollover check next pass)
+
+  }
+
+  if( !ulStatus )  // success?
+    Exchanges->fcExchange[i].type = type; // allocate it.
+  
+  else
+    i = -1;  // error - all exchanges "open"
+
+  return i;  
+}
+
+static void
+cpqfc_pci_unmap_extended_sg(struct pci_dev *pcidev,
+	PTACHYON fcChip,
+	ULONG x_ID)
+{
+	// Unmaps the memory regions used to hold the scatter gather lists
+
+	PSGPAGES i;
+
+	// Were there any such regions needing unmapping?
+	if (! USES_EXTENDED_SGLIST(fcChip->SEST, x_ID))
+		return;	// No such regions, we're outta here.
+
+	// for each extended scatter gather region needing unmapping... 
+	for (i=fcChip->SEST->sgPages[x_ID] ; i != NULL ; i = i->next)
+		pci_unmap_single(pcidev, i->busaddr, i->maplen,
+			scsi_to_pci_dma_dir(PCI_DMA_TODEVICE));
+}
+
+// Called also from cpqfcTScontrol.o, so can't be static
+void
+cpqfc_pci_unmap(struct pci_dev *pcidev, 
+	Scsi_Cmnd *cmd, 
+	PTACHYON fcChip, 
+	ULONG x_ID)
+{
+	// Undo the DMA mappings
+	if (cmd->use_sg) {	// Used scatter gather list for data buffer?
+		cpqfc_pci_unmap_extended_sg(pcidev, fcChip, x_ID);
+		pci_unmap_sg(pcidev, cmd->buffer, cmd->use_sg,
+			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+		// printk("umsg %d\n", cmd->use_sg);
+	}
+	else if (cmd->request_bufflen) {
+		// printk("ums %p ", fcChip->SEST->u[ x_ID ].IWE.GAddr1);
+		pci_unmap_single(pcidev, fcChip->SEST->u[ x_ID ].IWE.GAddr1,
+			cmd->request_bufflen,
+			scsi_to_pci_dma_dir(cmd->sc_data_direction));
+	}	 
+}
+
+// We call this routine to free an Exchange for any reason:
+// completed successfully, completed with error, aborted, etc.
+
+// returns FALSE if Exchange failed and "retry" is acceptable
+// returns TRUE if Exchange was successful, or retry is impossible
+// (e.g. port/device gone).
+//scompleteexchange
+
+void cpqfcTSCompleteExchange( 
+       struct pci_dev *pcidev,
+       PTACHYON fcChip, 
+       ULONG x_ID)
+{
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  int already_unmapped = 0;
+  
+  if( x_ID < TACH_SEST_LEN ) // SEST-based (or LinkServ for FCP exchange)
+  {
+    if( Exchanges->fcExchange[ x_ID ].Cmnd == NULL ) // what#@!
+    {
+//      TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+      printk(" x_ID %Xh, type %Xh, NULL ptr!\n", x_ID,
+			Exchanges->fcExchange[ x_ID ].type);
+
+      goto CleanUpSestResources;  // this path should be very rare.
+    }
+
+    // we have Linux Scsi Cmnd ptr..., now check our Exchange status
+    // to decide how to complete this SEST FCP exchange
+
+    if( Exchanges->fcExchange[ x_ID ].status ) // perhaps a Tach indicated problem,
+                                             // or abnormal exchange completion
+    {
+      // set FCP Link statistics
+     
+      if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT)
+        fcChip->fcStats.timeouts++;
+      if( Exchanges->fcExchange[ x_ID ].status & INITIATOR_ABORT)
+        fcChip->fcStats.FC4aborted++;
+      if( Exchanges->fcExchange[ x_ID ].status & COUNT_ERROR)
+        fcChip->fcStats.CntErrors++;
+      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX)
+        fcChip->fcStats.linkFailTX++;
+      if( Exchanges->fcExchange[ x_ID ].status & LINKFAIL_RX)
+        fcChip->fcStats.linkFailRX++;
+      if( Exchanges->fcExchange[ x_ID ].status & OVERFLOW)
+        fcChip->fcStats.CntErrors++;
+
+      // First, see if the Scsi upper level initiated an ABORT on this
+      // exchange...
+      if( Exchanges->fcExchange[ x_ID ].status == INITIATOR_ABORT )
+      {
+        printk(" DID_ABORT, x_ID %Xh, Cmnd %p ", 
+            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+        goto CleanUpSestResources;  // (we don't expect Linux _aborts)
+      }
+
+      // Did our driver timeout the Exchange, or did Tachyon indicate
+      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
+      else if( Exchanges->fcExchange[ x_ID ].status & FC2_TIMEOUT) 
+      {
+//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
+      }
+      
+      // Did frame(s) for an open exchange arrive in the SFQ,
+      // meaning the SEST was unable to process them?
+      else if( Exchanges->fcExchange[ x_ID ].status & SFQ_FRAME) 
+      {
+//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
+      }
+      
+      // Did our driver timeout the Exchange, or did Tachyon indicate
+      // a failure during transmission?  Ask for retry with "SOFT_ERROR"
+      else if( 
+               (Exchanges->fcExchange[ x_ID ].status & LINKFAIL_TX) ||
+               (Exchanges->fcExchange[ x_ID ].status & PORTID_CHANGED) ||
+	       (Exchanges->fcExchange[ x_ID ].status & FRAME_TO)    ||
+	       (Exchanges->fcExchange[ x_ID ].status & INV_ENTRY)    ||
+	       (Exchanges->fcExchange[ x_ID ].status & ABORTSEQ_NOTIFY)    )
+
+
+      {
+//        printk("result DID_SOFT_ERROR, x_ID %Xh, Cmnd %p\n", 
+//            x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
+
+
+      }
+
+      // e.g., a LOGOut happened, or device never logged back in.
+      else if( Exchanges->fcExchange[ x_ID ].status & DEVICE_REMOVED) 
+      {
+//	printk(" *LOGOut or timeout on login!* ");
+	// trigger?
+//        TriggerHBA( fcChip->Registers.ReMapMemBase, 0);
+
+        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_BAD_TARGET <<16);
+      }      
+		
+		      
+      // Did Tachyon indicate a CNT error?  We need further analysis
+      // to determine if the exchange is acceptable
+      else if( Exchanges->fcExchange[ x_ID ].status == COUNT_ERROR)
+      {
+        UCHAR ScsiStatus;
+        FCP_STATUS_RESPONSE *pFcpStatus = 
+	  (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
+
+      	ScsiStatus = pFcpStatus->fcp_status >>24;
+  
+	// If the command is a SCSI Read/Write type, we don't tolerate
+	// count errors of any kind; assume the count error is due to
+	// a dropped frame and ask for retry...
+	
+	if(( (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x8) ||
+	    (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x28) ||		
+            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0xA) ||
+            (Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0] == 0x2A) )
+	                   &&
+                     ScsiStatus == 0 )
+	{
+          // ask for retry
+/*          printk("COUNT_ERROR retry, x_ID %Xh, status %Xh, Cmnd %p\n", 
+            x_ID, Exchanges->fcExchange[ x_ID ].status,
+            Exchanges->fcExchange[ x_ID ].Cmnd);*/
+          Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_SOFT_ERROR <<16);
+	}
+	
+	else  // need more analysis
+	{
+	  cpqfcTSCheckandSnoopFCP(fcChip, x_ID);  // (will set ->result)
+	}
+      }
+      
+      // default: NOTE! We don't ever want to get here.  Getting here
+      // implies something new is happening that we've never had a test
+      // case for.  Need code maintenance!  Return "ERROR"
+      else
+      {
+	unsigned int stat = Exchanges->fcExchange[ x_ID ].status;
+        printk("DEFAULT result %Xh, x_ID %Xh, Cmnd %p", 
+          Exchanges->fcExchange[ x_ID ].status, x_ID, 
+	  Exchanges->fcExchange[ x_ID ].Cmnd);
+
+	if (stat & INVALID_ARGS)	printk(" INVALID_ARGS ");
+	if (stat & LNKDWN_OSLS)		printk(" LNKDWN_OSLS ");
+	if (stat & LNKDWN_LASER)	printk(" LNKDWN_LASER ");
+	if (stat & OUTQUE_FULL)		printk(" OUTQUE_FULL ");
+	if (stat & DRIVERQ_FULL)	printk(" DRIVERQ_FULL ");
+	if (stat & SEST_FULL)		printk(" SEST_FULL ");
+	if (stat & BAD_ALPA)		printk(" BAD_ALPA ");
+	if (stat & OVERFLOW)		printk(" OVERFLOW ");
+	if (stat & COUNT_ERROR)		printk(" COUNT_ERROR ");
+	if (stat & LINKFAIL_RX)		printk(" LINKFAIL_RX ");
+	if (stat & ABORTSEQ_NOTIFY)	printk(" ABORTSEQ_NOTIFY ");
+	if (stat & LINKFAIL_TX)		printk(" LINKFAIL_TX ");
+	if (stat & HOSTPROG_ERR)	printk(" HOSTPROG_ERR ");
+	if (stat & FRAME_TO)		printk(" FRAME_TO ");
+	if (stat & INV_ENTRY)		printk(" INV_ENTRY ");
+	if (stat & SESTPROG_ERR)	printk(" SESTPROG_ERR ");
+	if (stat & OUTBOUND_TIMEOUT)	printk(" OUTBOUND_TIMEOUT ");
+	if (stat & INITIATOR_ABORT)	printk(" INITIATOR_ABORT ");
+	if (stat & MEMPOOL_FAIL)	printk(" MEMPOOL_FAIL ");
+	if (stat & FC2_TIMEOUT)		printk(" FC2_TIMEOUT ");
+	if (stat & TARGET_ABORT)	printk(" TARGET_ABORT ");
+	if (stat & EXCHANGE_QUEUED)	printk(" EXCHANGE_QUEUED ");
+	if (stat & PORTID_CHANGED)	printk(" PORTID_CHANGED ");
+	if (stat & DEVICE_REMOVED)	printk(" DEVICE_REMOVED ");
+	if (stat & SFQ_FRAME)		printk(" SFQ_FRAME ");
+	printk("\n");
+
+        Exchanges->fcExchange[ x_ID ].Cmnd->result = (DID_ERROR <<16);
+      }
+    }
+    else    // definitely no Tach problem, but perhaps an FCP problem
+    {
+      // set FCP Link statistic
+      fcChip->fcStats.ok++;
+      cpqfcTSCheckandSnoopFCP( fcChip, x_ID);  // (will set ->result)    
+    }
+
+    cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
+			fcChip, x_ID); // undo DMA mappings.
+    already_unmapped = 1;
+
+    // OK, we've set the Scsi "->result" field, so proceed with calling
+    // Linux Scsi "done" (if not NULL), and free any kernel memory we
+    // may have allocated for the exchange.
+
+  PCI_TRACEO( (ULONG)Exchanges->fcExchange[x_ID].Cmnd, 0xAC);
+    // complete the command back to upper Scsi drivers
+    if( Exchanges->fcExchange[ x_ID ].Cmnd->scsi_done != NULL)
+    {
+      // Calling "done" on an Linux _abort() aborted
+      // Cmnd causes a kernel panic trying to re-free mem.
+      // Actually, we shouldn't do anything with an _abort CMND
+      if( Exchanges->fcExchange[ x_ID ].Cmnd->result != (DID_ABORT<<16) )
+      {
+        PCI_TRACE(0xAC)
+	call_scsi_done(Exchanges->fcExchange[ x_ID ].Cmnd);
+      }
+      else
+      {
+//	printk(" not calling scsi_done on x_ID %Xh, Cmnd %p\n",
+//			x_ID, Exchanges->fcExchange[ x_ID ].Cmnd);
+      }
+    }
+    else{
+      printk(" x_ID %Xh, type %Xh, Cdb0 %Xh\n", x_ID,
+	Exchanges->fcExchange[ x_ID ].type, 
+	Exchanges->fcExchange[ x_ID ].Cmnd->cmnd[0]);	      
+      printk(" cpqfcTS: Null scsi_done function pointer!\n");
+    }
+
+
+    // Now, clean up non-Scsi_Cmnd items...
+CleanUpSestResources:
+   
+    if (!already_unmapped) 
+	cpqfc_pci_unmap(pcidev, Exchanges->fcExchange[x_ID].Cmnd, 
+			fcChip, x_ID); // undo DMA mappings.
+
+    // Was an Extended Scatter/Gather page allocated?  We know
+    // this by checking DWORD 4, bit 31 ("LOC") of SEST entry
+    if( !(fcChip->SEST->u[ x_ID ].IWE.Buff_Off & 0x80000000))
+    {
+      PSGPAGES p, next;
+
+      // extended S/G list was used -- Free the allocated ext. S/G pages
+      for (p = fcChip->SEST->sgPages[x_ID]; p != NULL; p = next) {
+	 next = p->next;
+	 kfree(p);
+      }
+      fcChip->SEST->sgPages[x_ID] = NULL;
+    }
+  
+    Exchanges->fcExchange[ x_ID ].Cmnd = NULL; 
+  }  // Done with FCP (SEST) exchanges
+
+
+  // the remaining logic is common to ALL Exchanges: 
+  // FCP(SEST) and LinkServ.
+
+  Exchanges->fcExchange[ x_ID ].type = 0; // there -- FREE!  
+  Exchanges->fcExchange[ x_ID ].status = 0; 
+
+  PCI_TRACEO( x_ID, 0xAC)
+     
+  
+  return;
+}   // (END of CompleteExchange function)
+ 
+
+
+
+// Unfortunately, we must snoop all command completions in
+// order to manipulate certain return fields, and take note of
+// device types, etc., to facilitate the Fibre-Channel to SCSI
+// "mapping".  
+// (Watch for BIG Endian confusion on some payload fields)
+void cpqfcTSCheckandSnoopFCP( PTACHYON fcChip, ULONG x_ID)
+{
+  FC_EXCHANGES *Exchanges = fcChip->Exchanges;
+  Scsi_Cmnd *Cmnd = Exchanges->fcExchange[ x_ID].Cmnd;
+  FCP_STATUS_RESPONSE *pFcpStatus = 
+    (PFCP_STATUS_RESPONSE)&fcChip->SEST->RspHDR[ x_ID ].pl;
+  UCHAR ScsiStatus;
+
+  ScsiStatus = pFcpStatus->fcp_status >>24;
+
+#ifdef FCP_COMPLETION_DBG
+  printk("ScsiStatus = 0x%X\n", ScsiStatus);
+#endif	
+
+  // First, check FCP status
+  if( pFcpStatus->fcp_status & FCP_RSP_LEN_VALID )
+  {
+    // check response code (RSP_CODE) -- most popular is bad len
+    // 1st 4 bytes of rsp info -- only byte 3 interesting
+    if( pFcpStatus->fcp_rsp_info & FCP_DATA_LEN_NOT_BURST_LEN )
+    { 
+
+      // do we EVER get here?
+      printk("cpqfcTS: FCP data len not burst len, x_ID %Xh\n", x_ID);
+    }
+  }
+
+  // for now, go by the ScsiStatus, and manipulate certain
+  // commands when necessary...
+  if( ScsiStatus == 0) // SCSI status byte "good"?
+  {
+    Cmnd->result = 0; // everything's OK
+
+    if( (Cmnd->cmnd[0] == INQUIRY)) 
+    {
+      UCHAR *InquiryData = Cmnd->request_buffer;
+      PFC_LOGGEDIN_PORT pLoggedInPort;
+
+      // We need to manipulate INQUIRY
+      // strings for COMPAQ RAID controllers to force
+      // Linux to scan additional LUNs.  Namely, set
+      // the Inquiry string byte 2 (ANSI-approved version)
+      // to 2.
+
+      if( !memcmp( &InquiryData[8], "COMPAQ", 6 ))
+      {
+        InquiryData[2] = 0x2;  // claim SCSI-2 compliance,
+                               // so multiple LUNs may be scanned.
+                               // (no SCSI-2 problems known in CPQ)
+      }
+        
+      // snoop the Inquiry to detect Disk, Tape, etc. type
+      // (search linked list for the port_id we sent INQUIRY to)
+      pLoggedInPort = fcFindLoggedInPort( fcChip,
+        NULL,     // DON'T search Scsi Nexus (we will set it)
+        Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF,        
+        NULL,     // DON'T search linked list for FC WWN
+        NULL);    // DON'T care about end of list
+ 
+      if( pLoggedInPort )
+      {
+        pLoggedInPort->ScsiNexus.InqDeviceType = InquiryData[0];
+      }
+      else
+      {
+	printk("cpqfcTS: can't find LoggedIn FC port %06X for INQUIRY\n",
+          Exchanges->fcExchange[ x_ID].fchs.d_id & 0xFFFFFF);
+      }
+    }
+  }
+
+
+  // Scsi Status not good -- pass it back to caller 
+
+  else
+  {
+    Cmnd->result = ScsiStatus; // SCSI status byte is 1st
+    
+    // check for valid "sense" data
+
+    if( pFcpStatus->fcp_status & FCP_SNS_LEN_VALID ) 
+    {            // limit Scsi Sense field length!
+      int SenseLen = pFcpStatus->fcp_sns_len >>24; // (BigEndian) lower byte
+      
+      SenseLen = SenseLen > sizeof( Cmnd->sense_buffer) ? 
+        sizeof( Cmnd->sense_buffer) : SenseLen;
+	   
+
+#ifdef FCP_COMPLETION_DBG	    
+      printk("copy sense_buffer %p, len %d, result %Xh\n",
+        Cmnd->sense_buffer, SenseLen, Cmnd->result);
+#endif	  
+
+      // NOTE: There is some dispute over the FCP response
+      // format.  Most FC devices assume that FCP_RSP_INFO
+      // is 8 bytes long, in spite of the fact that FCP_RSP_LEN
+      // is (virtually) always 0 and the field is "invalid".  
+      // Some other devices assume that
+      // the FCP_SNS_INFO begins after FCP_RSP_LEN bytes (i.e. 0)
+      // when the FCP_RSP is invalid (this almost appears to be
+      // one of those "religious" issues).
+      // Consequently, we test the usual position of FCP_SNS_INFO
+      // for 7Xh, since the SCSI sense format says the first
+      // byte ("error code") should be 0x70 or 0x71.  In practice,
+      // we find that every device does in fact have 0x70 or 0x71
+      // in the first byte position, so this test works for all
+      // FC devices.  
+      // (This logic is especially effective for the CPQ/DEC HSG80
+      // & HSG60 controllers).
+
+      if( (pFcpStatus->fcp_sns_info[0] & 0x70) == 0x70 )
+        memcpy( Cmnd->sense_buffer, 
+          &pFcpStatus->fcp_sns_info[0], SenseLen);
+      else
+      {
+        unsigned char *sbPtr = 
+		(unsigned char *)&pFcpStatus->fcp_sns_info[0];
+        sbPtr -= 8;  // back up 8 bytes hoping to find the
+	             // start of the sense buffer
+        memcpy( Cmnd->sense_buffer, sbPtr, SenseLen);
+      }
+
+      // in the special case of Device Reset, tell upper layer
+      // to immediately retry (with SOFT_ERROR status)
+      // look for Sense Key Unit Attention (0x6) with ASC Device
+      // Reset (0x29)
+      //	    printk("SenseLen %d, Key = 0x%X, ASC = 0x%X\n",
+      //		    SenseLen, Cmnd->sense_buffer[2], 
+      //                   Cmnd->sense_buffer[12]);
+      if( ((Cmnd->sense_buffer[2] & 0xF) == 0x6) &&
+	        (Cmnd->sense_buffer[12] == 0x29) ) // Sense Code "reset"
+      {
+        Cmnd->result |= (DID_SOFT_ERROR << 16); // "Host" status byte 3rd
+      }
+ 
+      // check for SenseKey "HARDWARE ERROR", ASC InternalTargetFailure
+      else if(  ((Cmnd->sense_buffer[2] & 0xF) == 0x4) &&  // "hardware error"
+      	        (Cmnd->sense_buffer[12] == 0x44) ) // Addtl. Sense Code 
+      {
+//        printk("HARDWARE_ERROR, Channel/Target/Lun %d/%d/%d\n",
+//		Cmnd->channel, Cmnd->target, Cmnd->lun);
+      	Cmnd->result |= (DID_ERROR << 16); // "Host" status byte 3rd
+      }
+      
+    }  // (end of sense len valid)
+
+    // there is no sense data to help out Linux's Scsi layers...
+    // We'll just return the Scsi status and hope he will "do the 
+    // right thing"
+    else
+    {
+      // as far as we know, the Scsi status is sufficient
+      Cmnd->result |= (DID_OK << 16); // "Host" status byte 3rd
+    }
+  }
+}
+
+
+
+//PPPPPPPPPPPPPPPPPPPPPPPPP  PAYLOAD  PPPPPPPPP
+// build data PAYLOAD; SCSI FCP_CMND I.U.
+// remember BIG ENDIAN payload - DWord values must be byte-reversed
+// (hence the affinity for byte pointer building).
+
+static int build_FCP_payload( Scsi_Cmnd *Cmnd, 
+      UCHAR* payload, ULONG type, ULONG fcp_dl )
+{
+  int i;
+
+  
+  switch( type)
+  {
+		  
+    case SCSI_IWE: 
+    case SCSI_IRE:        
+      // 8 bytes FCP_LUN
+      // Peripheral Device or Volume Set addressing, and LUN mapping
+      // When the FC port was looked up, we copied address mode
+      // and any LUN mask to the scratch pad SCp.phase & .mode
+
+      *payload++ = (UCHAR)Cmnd->SCp.phase;
+
+      // Now, because of "lun masking" 
+      // (aka selective storage presentation),
+      // the contiguous Linux Scsi lun number may not match the
+      // device's lun number, so we may have to "map".  
+      
+      *payload++ = (UCHAR)Cmnd->SCp.have_data_in;
+      
+      // We don't know of anyone in the FC business using these 
+      // extra "levels" of addressing.  In fact, confusion still exists
+      // just using the FIRST level... ;-)
+      
+      *payload++ = 0;  // 2nd level addressing
+      *payload++ = 0;
+      *payload++ = 0;  // 3rd level addressing
+      *payload++ = 0;
+      *payload++ = 0;  // 4th level addressing
+      *payload++ = 0;
+
+      // 4 bytes Control Field FCP_CNTL
+      *payload++ = 0;    // byte 0: (MSB) reserved
+      *payload++ = 0;    // byte 1: task codes
+
+                         // byte 2: task management flags
+      // another "use" of the spare field to accomplish TDR
+      // note combination needed
+      if( (Cmnd->cmnd[0] == RELEASE) &&
+          (Cmnd->SCp.buffers_residual == FCP_TARGET_RESET) )
+      {
+        Cmnd->cmnd[0] = 0;    // issue "Test Unit Ready" for TDR
+        *payload++ = 0x20;    // target device reset bit
+      }
+      else
+        *payload++ = 0;    // no TDR
+		      // byte 3: (LSB) execution management codes
+		      // bit 0 write, bit 1 read (don't set together)
+      
+      if( fcp_dl != 0 )
+      {
+        if( type == SCSI_IWE )         // WRITE
+          *payload++ = 1;
+        else                           // READ
+          *payload++ = 2;
+      }
+      else
+      {
+	// On some devices, if RD or WR bits are set,
+	// and fcp_dl is 0, they will generate an error on the command.
+	// (i.e., if direction is specified, they insist on a length).
+	*payload++ = 0;                // no data (necessary for CPQ)
+      }
+
+
+      // NOTE: clean this up if/when MAX_COMMAND_SIZE is increased to 16
+      // FCP_CDB allows 16 byte SCSI command descriptor blk;
+      // Linux SCSI CDB array is MAX_COMMAND_SIZE (12 at this time...)
+      for( i=0; (i < Cmnd->cmd_len) && i < MAX_COMMAND_SIZE; i++)
+	*payload++ = Cmnd->cmnd[i];
+
+      // if( Cmnd->cmd_len == 16 )
+      // {
+      //  memcpy( payload, &Cmnd->SCp.buffers_residual, 4);
+      // }
+      payload+= (16 - i);  
+
+		      // FCP_DL is largest number of expected data bytes
+		      // per CDB (i.e. read/write command)
+      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
+      *payload++ = (UCHAR)(fcp_dl >>16);
+      *payload++ = (UCHAR)(fcp_dl >>8);
+      *payload++ = (UCHAR)fcp_dl;    // (LSB)
+      break;
+
+    case SCSI_TWE:          // need FCP_XFER_RDY
+      *payload++ = 0;     // (4 bytes) DATA_RO (MSB byte 0)
+      *payload++ = 0;
+      *payload++ = 0;
+      *payload++ = 0;     // LSB (byte 3)
+			     // (4 bytes) BURST_LEN
+			     // size of following FCP_DATA payload
+      *payload++ = (UCHAR)(fcp_dl >>24);  // (MSB) 8 bytes data len FCP_DL
+      *payload++ = (UCHAR)(fcp_dl >>16);
+      *payload++ = (UCHAR)(fcp_dl >>8);
+      *payload++ = (UCHAR)fcp_dl;    // (LSB)
+		       // 4 bytes RESERVED
+      *payload++ = 0;
+      *payload++ = 0;
+      *payload++ = 0;
+      *payload++ = 0;
+      break;
+
+    default:
+      break;
+  }
+
+  return 0;
+}
+
diff --git a/drivers/scsi/cyberstorm.c b/drivers/scsi/cyberstorm.c
new file mode 100644
index 0000000..bdbca85d
--- /dev/null
+++ b/drivers/scsi/cyberstorm.c
@@ -0,0 +1,377 @@
+/* cyberstorm.c: Driver for CyberStorm SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * The CyberStorm SCSI driver is based on David S. Miller's ESP driver
+ * for the Sparc computers. 
+ * 
+ * This work was made possible by Phase5 who willingly (and most generously)
+ * supported me with hardware and all the information I needed.
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ *    to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ *    routines in this file used to be inline!
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBER_ESP_ADDR 0xf400
+#define CYBER_DMA_ADDR 0xf800
+
+
+/* The CyberStorm DMA interface */
+struct cyber_dma_registers {
+	volatile unsigned char dma_addr0;	/* DMA address (MSB) [0x000] */
+	unsigned char dmapad1[1];
+	volatile unsigned char dma_addr1;	/* DMA address       [0x002] */
+	unsigned char dmapad2[1];
+	volatile unsigned char dma_addr2;	/* DMA address       [0x004] */
+	unsigned char dmapad3[1];
+	volatile unsigned char dma_addr3;	/* DMA address (LSB) [0x006] */
+	unsigned char dmapad4[0x3fb];
+	volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x402] */
+#define ctrl_reg  cond_reg			/* DMA control (wo)  [0x402] */
+};
+
+/* DMA control bits */
+#define CYBER_DMA_LED    0x80	/* HD led control 1 = on */
+#define CYBER_DMA_WRITE  0x40	/* DMA direction. 1 = write */
+#define CYBER_DMA_Z3     0x20	/* 16 (Z2) or 32 (CHIP/Z3) bit DMA transfer */
+
+/* DMA status bits */
+#define CYBER_DMA_HNDL_INTR 0x80	/* DMA IRQ pending? */
+
+/* The bits below appears to be Phase5 Debug bits only; they were not
+ * described by Phase5 so using them may seem a bit stupid...
+ */
+#define CYBER_HOST_ID 0x02	/* If set, host ID should be 7, otherwise
+				 * it should be 6.
+				 */
+#define CYBER_SLOW_CABLE 0x08	/* If *not* set, assume SLOW_CABLE */
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static unsigned char ctrl_data = 0;	/* Keep backup of the stuff written
+				 * to ctrl_reg. Always write a copy
+				 * to this register when writing to
+				 * the hardware register!
+				 */
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int __init cyber_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+
+	while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	    unsigned long board = z->resource.start;
+	    if ((z->id == ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM ||
+		 z->id == ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060) &&
+		request_mem_region(board+CYBER_ESP_ADDR,
+		    		   sizeof(struct ESP_regs), "NCR53C9x")) {
+		/* Figure out if this is a CyberStorm or really a 
+		 * Fastlane/Blizzard Mk II by looking at the board size.
+		 * CyberStorm maps 64kB
+		 * (ZORRO_PROD_PHASE5_BLIZZARD_1220_CYBERSTORM does anyway)
+		 */
+		if(z->resource.end-board != 0xffff) {
+			release_mem_region(board+CYBER_ESP_ADDR,
+					   sizeof(struct ESP_regs));
+			return 0;
+		}
+		esp = esp_allocate(tpnt, (void *)board+CYBER_ESP_ADDR);
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = 0;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		/* SCSI chip speed */
+		esp->cfreq = 40000000;
+
+		/* The DMA registers on the CyberStorm are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		address = (unsigned long)ZTWO_VADDR(board);
+		esp->dregs = (void *)(address + CYBER_DMA_ADDR);
+
+		/* ESP register base */
+		esp->eregs = (struct ESP_regs *)(address + CYBER_ESP_ADDR);
+		
+		/* Set the command buffer */
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+			    "CyberStorm SCSI", esp->ehost);
+		/* Figure out our scsi ID on the bus */
+		/* The DMA cond flag contains a hardcoded jumper bit
+		 * which can be used to select host number 6 or 7.
+		 * However, even though it may change, we use a hardcoded
+		 * value of 7.
+		 */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	    }
+	}
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	/* I don't think there's any limit on the CyberDMA. So we use what
+	 * the ESP chip can handle (24 bit).
+	 */
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0x1000000)
+		sz = 0x1000000;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+		esp->esp_id, ((struct cyber_dma_registers *)
+			      (esp->dregs))->cond_reg));
+	ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+		custom.intreqr, custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct cyber_dma_registers *dregs = 
+		(struct cyber_dma_registers *) esp->dregs;
+
+	cache_clear(addr, length);
+
+	addr &= ~(1);
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr3 = (addr      ) & 0xff;
+	ctrl_data &= ~(CYBER_DMA_WRITE);
+
+	/* Check if physical address is outside Z2 space and of
+	 * block length/block aligned in memory. If this is the
+	 * case, enable 32 bit transfer. In all other cases, fall back
+	 * to 16 bit transfer.
+	 * Obviously 32 bit transfer should be enabled if the DMA address
+	 * and length are 32 bit aligned. However, this leads to some
+	 * strange behavior. Even 64 bit aligned addr/length fails.
+	 * Until I've found a reason for this, 32 bit transfer is only
+	 * used for full-block transfers (1kB).
+	 *							-jskov
+	 */
+#if 0
+	if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
+						(addr < 0xff0000)))
+		ctrl_data &= ~(CYBER_DMA_Z3);	/* Z2, do 16 bit DMA */
+	else
+		ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
+#else
+	ctrl_data &= ~(CYBER_DMA_Z3);	/* Z2, do 16 bit DMA */
+#endif
+	dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct cyber_dma_registers *dregs = 
+		(struct cyber_dma_registers *) esp->dregs;
+
+	cache_push(addr, length);
+
+	addr |= 1;
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr3 = (addr      ) & 0xff;
+	ctrl_data |= CYBER_DMA_WRITE;
+
+	/* See comment above */
+#if 0
+	if((addr & 0x3fc) || length & 0x3ff || ((addr > 0x200000) &&
+						(addr < 0xff0000)))
+		ctrl_data &= ~(CYBER_DMA_Z3);	/* Z2, do 16 bit DMA */
+	else
+		ctrl_data |= CYBER_DMA_Z3; /* CHIP/Z3, do 32 bit DMA */
+#else
+	ctrl_data &= ~(CYBER_DMA_Z3);	/* Z2, do 16 bit DMA */
+#endif
+	dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	/* It's important to check the DMA IRQ bit in the correct way! */
+	return ((esp_read(esp->eregs->esp_status) & ESP_STAT_INTR) &&
+		((((struct cyber_dma_registers *)(esp->dregs))->cond_reg) &
+		 CYBER_DMA_HNDL_INTR));
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+	ctrl_data &= ~CYBER_DMA_LED;
+	((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+	ctrl_data |= CYBER_DMA_LED;
+	((struct cyber_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+#define HOSTS_C
+
+int cyber_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+	esp_deallocate((struct NCR_ESP *)instance->hostdata);
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-cyberstorm",
+	.proc_info		= esp_proc_info,
+	.name			= "CyberStorm SCSI",
+	.detect			= cyber_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= cyber_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/cyberstormII.c b/drivers/scsi/cyberstormII.c
new file mode 100644
index 0000000..845d925
--- /dev/null
+++ b/drivers/scsi/cyberstormII.c
@@ -0,0 +1,314 @@
+/* cyberstormII.c: Driver for CyberStorm SCSI Mk II
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on cyberstorm.c
+ */
+
+/* TODO:
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ *    to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ *    routines in this file used to be inline!
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define CYBERII_ESP_ADDR 0x1ff03
+#define CYBERII_DMA_ADDR 0x1ff43
+
+
+/* The CyberStorm II DMA interface */
+struct cyberII_dma_registers {
+	volatile unsigned char cond_reg;        /* DMA cond    (ro)  [0x000] */
+#define ctrl_reg  cond_reg			/* DMA control (wo)  [0x000] */
+	unsigned char dmapad4[0x3f];
+	volatile unsigned char dma_addr0;	/* DMA address (MSB) [0x040] */
+	unsigned char dmapad1[3];
+	volatile unsigned char dma_addr1;	/* DMA address       [0x044] */
+	unsigned char dmapad2[3];
+	volatile unsigned char dma_addr2;	/* DMA address       [0x048] */
+	unsigned char dmapad3[3];
+	volatile unsigned char dma_addr3;	/* DMA address (LSB) [0x04c] */
+};
+
+/* DMA control bits */
+#define CYBERII_DMA_LED    0x02	/* HD led control 1 = on */
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int __init cyberII_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+	struct ESP_regs *eregs;
+
+	if ((z = zorro_find_device(ZORRO_PROD_PHASE5_CYBERSTORM_MK_II, z))) {
+	    unsigned long board = z->resource.start;
+	    if (request_mem_region(board+CYBERII_ESP_ADDR,
+				   sizeof(struct ESP_regs), "NCR53C9x")) {
+		/* Do some magic to figure out if the CyberStorm Mk II
+		 * is equipped with a SCSI controller
+		 */
+		address = (unsigned long)ZTWO_VADDR(board);
+		eregs = (struct ESP_regs *)(address + CYBERII_ESP_ADDR);
+
+		esp = esp_allocate(tpnt, (void *)board+CYBERII_ESP_ADDR);
+
+		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+		udelay(5);
+		if(esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7)) {
+			esp_deallocate(esp);
+			scsi_unregister(esp->ehost);
+			release_mem_region(board+CYBERII_ESP_ADDR,
+					   sizeof(struct ESP_regs));
+			return 0; /* Bail out if address did not hold data */
+		}
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = 0;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		/* SCSI chip speed */
+		esp->cfreq = 40000000;
+
+		/* The DMA registers on the CyberStorm are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		esp->dregs = (void *)(address + CYBERII_DMA_ADDR);
+
+		/* ESP register base */
+		esp->eregs = eregs;
+		
+		/* Set the command buffer */
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+			    "CyberStorm SCSI Mk II", esp->ehost);
+
+		/* Figure out our scsi ID on the bus */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	    }
+	}
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	/* I don't think there's any limit on the CyberDMA. So we use what
+	 * the ESP chip can handle (24 bit).
+	 */
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0x1000000)
+		sz = 0x1000000;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+		esp->esp_id, ((struct cyberII_dma_registers *)
+			      (esp->dregs))->cond_reg));
+	ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+		custom.intreqr, custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct cyberII_dma_registers *dregs = 
+		(struct cyberII_dma_registers *) esp->dregs;
+
+	cache_clear(addr, length);
+
+	addr &= ~(1);
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr3 = (addr      ) & 0xff;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct cyberII_dma_registers *dregs = 
+		(struct cyberII_dma_registers *) esp->dregs;
+
+	cache_push(addr, length);
+
+	addr |= 1;
+	dregs->dma_addr0 = (addr >> 24) & 0xff;
+	dregs->dma_addr1 = (addr >> 16) & 0xff;
+	dregs->dma_addr2 = (addr >>  8) & 0xff;
+	dregs->dma_addr3 = (addr      ) & 0xff;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	/* It's important to check the DMA IRQ bit in the correct way! */
+	return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+	((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg &= ~CYBERII_DMA_LED;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+	((struct cyberII_dma_registers *)(esp->dregs))->ctrl_reg |= CYBERII_DMA_LED;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+#define HOSTS_C
+
+int cyberII_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+
+	esp_deallocate((struct NCR_ESP *)instance->hostdata); 
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-cyberstormII",
+	.proc_info		= esp_proc_info,
+	.name			= "CyberStorm Mk II SCSI",
+	.detect			= cyberII_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= cyberII_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
new file mode 100644
index 0000000..cca41cf
--- /dev/null
+++ b/drivers/scsi/dc395x.c
@@ -0,0 +1,4942 @@
+/*
+ * dc395x.c
+ *
+ * Device Driver for Tekram DC395(U/UW/F), DC315(U)
+ * PCI SCSI Bus Master Host Adapter
+ * (SCSI chip set used Tekram ASIC TRM-S1040)
+ *
+ * Authors:
+ *  C.L. Huang <ching@tekram.com.tw>
+ *  Erich Chen <erich@tekram.com.tw>
+ *  (C) Copyright 1995-1999 Tekram Technology Co., Ltd.
+ *
+ *  Kurt Garloff <garloff@suse.de>
+ *  (C) 1999-2000 Kurt Garloff
+ *
+ *  Oliver Neukum <oliver@neukum.name>
+ *  Ali Akcaagac <aliakc@web.de>
+ *  Jamie Lenehan <lenehan@twibble.org>
+ *  (C) 2003
+ *
+ * License: GNU GPL
+ *
+ *************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ************************************************************************
+ */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/vmalloc.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsicam.h>	/* needed for scsicam_bios_param */
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "dc395x.h"
+
+#define DC395X_NAME	"dc395x"
+#define DC395X_BANNER	"Tekram DC395(U/UW/F), DC315(U) - ASIC TRM-S1040"
+#define DC395X_VERSION	"v2.05, 2004/03/08"
+
+/*---------------------------------------------------------------------------
+                                  Features
+ ---------------------------------------------------------------------------*/
+/*
+ * Set to disable parts of the driver
+ */
+/*#define DC395x_NO_DISCONNECT*/
+/*#define DC395x_NO_TAGQ*/
+/*#define DC395x_NO_SYNC*/
+/*#define DC395x_NO_WIDE*/
+
+/*---------------------------------------------------------------------------
+                                  Debugging
+ ---------------------------------------------------------------------------*/
+/*
+ * Types of debugging that can be enabled and disabled
+ */
+#define DBG_KG		0x0001
+#define DBG_0		0x0002
+#define DBG_1		0x0004
+#define DBG_SG		0x0020
+#define DBG_FIFO	0x0040
+#define DBG_PIO		0x0080
+
+
+/*
+ * Set set of things to output debugging for.
+ * Undefine to remove all debugging
+ */
+/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_SG|DBG_FIFO|DBG_PIO)*/
+/*#define  DEBUG_MASK	DBG_0*/
+
+
+/*
+ * Output a kernel mesage at the specified level and append the
+ * driver name and a ": " to the start of the message
+ */
+#define dprintkl(level, format, arg...)  \
+    printk(level DC395X_NAME ": " format , ## arg)
+
+
+#ifdef DEBUG_MASK
+/*
+ * print a debug message - this is formated with KERN_DEBUG, then the
+ * driver name followed by a ": " and then the message is output. 
+ * This also checks that the specified debug level is enabled before
+ * outputing the message
+ */
+#define dprintkdbg(type, format, arg...) \
+	do { \
+		if ((type) & (DEBUG_MASK)) \
+			dprintkl(KERN_DEBUG , format , ## arg); \
+	} while (0)
+
+/*
+ * Check if the specified type of debugging is enabled
+ */
+#define debug_enabled(type)	((DEBUG_MASK) & (type))
+
+#else
+/*
+ * No debugging. Do nothing
+ */
+#define dprintkdbg(type, format, arg...) \
+	do {} while (0)
+#define debug_enabled(type)	(0)
+
+#endif
+
+
+#ifndef PCI_VENDOR_ID_TEKRAM
+#define PCI_VENDOR_ID_TEKRAM                    0x1DE1	/* Vendor ID    */
+#endif
+#ifndef PCI_DEVICE_ID_TEKRAM_TRMS1040
+#define PCI_DEVICE_ID_TEKRAM_TRMS1040           0x0391	/* Device ID    */
+#endif
+
+
+#define DC395x_LOCK_IO(dev,flags)		spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags)
+#define DC395x_UNLOCK_IO(dev,flags)		spin_unlock_irqrestore(((struct Scsi_Host *)dev)->host_lock, flags)
+
+#define DC395x_read8(acb,address)		(u8)(inb(acb->io_port_base + (address)))
+#define DC395x_read16(acb,address)		(u16)(inw(acb->io_port_base + (address)))
+#define DC395x_read32(acb,address)		(u32)(inl(acb->io_port_base + (address)))
+#define DC395x_write8(acb,address,value)	outb((value), acb->io_port_base + (address))
+#define DC395x_write16(acb,address,value)	outw((value), acb->io_port_base + (address))
+#define DC395x_write32(acb,address,value)	outl((value), acb->io_port_base + (address))
+
+/* cmd->result */
+#define RES_TARGET		0x000000FF	/* Target State */
+#define RES_TARGET_LNX  STATUS_MASK	/* Only official ... */
+#define RES_ENDMSG		0x0000FF00	/* End Message */
+#define RES_DID			0x00FF0000	/* DID_ codes */
+#define RES_DRV			0xFF000000	/* DRIVER_ codes */
+
+#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
+#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
+
+#define SET_RES_TARGET(who,tgt) { who &= ~RES_TARGET; who |= (int)(tgt); }
+#define SET_RES_TARGET_LNX(who,tgt) { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; }
+#define SET_RES_MSG(who,msg) { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; }
+#define SET_RES_DID(who,did) { who &= ~RES_DID; who |= (int)(did) << 16; }
+#define SET_RES_DRV(who,drv) { who &= ~RES_DRV; who |= (int)(drv) << 24; }
+
+#define TAG_NONE 255
+
+/*
+ * srb->segement_x is the hw sg list. It is always allocated as a
+ * DC395x_MAX_SG_LISTENTRY entries in a linear block which does not
+ * cross a page boundy.
+ */
+#define SEGMENTX_LEN	(sizeof(struct SGentry)*DC395x_MAX_SG_LISTENTRY)
+#define VIRTX_LEN	(sizeof(void *) * DC395x_MAX_SG_LISTENTRY)
+
+struct SGentry {
+	u32 address;		/* bus! address */
+	u32 length;
+};
+
+/* The SEEPROM structure for TRM_S1040 */
+struct NVRamTarget {
+	u8 cfg0;		/* Target configuration byte 0  */
+	u8 period;		/* Target period                */
+	u8 cfg2;		/* Target configuration byte 2  */
+	u8 cfg3;		/* Target configuration byte 3  */
+};
+
+struct NvRamType {
+	u8 sub_vendor_id[2];	/* 0,1  Sub Vendor ID   */
+	u8 sub_sys_id[2];	/* 2,3  Sub System ID   */
+	u8 sub_class;		/* 4    Sub Class       */
+	u8 vendor_id[2];	/* 5,6  Vendor ID       */
+	u8 device_id[2];	/* 7,8  Device ID       */
+	u8 reserved;		/* 9    Reserved        */
+	struct NVRamTarget target[DC395x_MAX_SCSI_ID];
+						/** 10,11,12,13
+						 ** 14,15,16,17
+						 ** ....
+						 ** ....
+						 ** 70,71,72,73
+						 */
+	u8 scsi_id;		/* 74 Host Adapter SCSI ID      */
+	u8 channel_cfg;		/* 75 Channel configuration     */
+	u8 delay_time;		/* 76 Power on delay time       */
+	u8 max_tag;		/* 77 Maximum tags              */
+	u8 reserved0;		/* 78  */
+	u8 boot_target;		/* 79  */
+	u8 boot_lun;		/* 80  */
+	u8 reserved1;		/* 81  */
+	u16 reserved2[22];	/* 82,..125 */
+	u16 cksum;		/* 126,127 */
+};
+
+struct ScsiReqBlk {
+	struct list_head list;		/* next/prev ptrs for srb lists */
+	struct DeviceCtlBlk *dcb;
+	struct scsi_cmnd *cmd;
+
+	struct SGentry *segment_x;	/* Linear array of hw sg entries (up to 64 entries) */
+	u32 sg_bus_addr;	        /* Bus address of sg list (ie, of segment_x) */
+
+	u8 sg_count;			/* No of HW sg entries for this request */
+	u8 sg_index;			/* Index of HW sg entry for this request */
+	u32 total_xfer_length;		/* Total number of bytes remaining to be transfered */
+	void **virt_map;
+	unsigned char *virt_addr;	/* Virtual address of current transfer position */
+
+	/*
+	 * The sense buffer handling function, request_sense, uses
+	 * the first hw sg entry (segment_x[0]) and the transfer
+	 * length (total_xfer_length). While doing this it stores the
+	 * original values into the last sg hw list
+	 * (srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1] and the
+	 * total_xfer_length in xferred. These values are restored in
+	 * pci_unmap_srb_sense. This is the only place xferred is used.
+	 */
+	u32 xferred;		        /* Saved copy of total_xfer_length */
+
+	u16 state;
+
+	u8 msgin_buf[6];
+	u8 msgout_buf[6];
+
+	u8 adapter_status;
+	u8 target_status;
+	u8 msg_count;
+	u8 end_message;
+
+	u8 tag_number;
+	u8 status;
+	u8 retry_count;
+	u8 flag;
+
+	u8 scsi_phase;
+};
+
+struct DeviceCtlBlk {
+	struct list_head list;		/* next/prev ptrs for the dcb list */
+	struct AdapterCtlBlk *acb;
+	struct list_head srb_going_list;	/* head of going srb list */
+	struct list_head srb_waiting_list;	/* head of waiting srb list */
+
+	struct ScsiReqBlk *active_srb;
+	u32 tag_mask;
+
+	u16 max_command;
+
+	u8 target_id;		/* SCSI Target ID  (SCSI Only) */
+	u8 target_lun;		/* SCSI Log.  Unit (SCSI Only) */
+	u8 identify_msg;
+	u8 dev_mode;
+
+	u8 inquiry7;		/* To store Inquiry flags */
+	u8 sync_mode;		/* 0:async mode */
+	u8 min_nego_period;	/* for nego. */
+	u8 sync_period;		/* for reg.  */
+
+	u8 sync_offset;		/* for reg. and nego.(low nibble) */
+	u8 flag;
+	u8 dev_type;
+	u8 init_tcq_flag;
+};
+
+struct AdapterCtlBlk {
+	struct Scsi_Host *scsi_host;
+
+	unsigned long io_port_base;
+	unsigned long io_port_len;
+
+	struct list_head dcb_list;		/* head of going dcb list */
+	struct DeviceCtlBlk *dcb_run_robin;
+	struct DeviceCtlBlk *active_dcb;
+
+	struct list_head srb_free_list;		/* head of free srb list */
+	struct ScsiReqBlk *tmp_srb;
+	struct timer_list waiting_timer;
+	struct timer_list selto_timer;
+
+	u16 srb_count;
+
+	u8 sel_timeout;
+
+	unsigned int irq_level;
+	u8 tag_max_num;
+	u8 acb_flag;
+	u8 gmode2;
+
+	u8 config;
+	u8 lun_chk;
+	u8 scan_devices;
+	u8 hostid_bit;
+
+	u8 dcb_map[DC395x_MAX_SCSI_ID];
+	struct DeviceCtlBlk *children[DC395x_MAX_SCSI_ID][32];
+
+	struct pci_dev *dev;
+
+	u8 msg_len;
+
+	struct ScsiReqBlk srb_array[DC395x_MAX_SRB_CNT];
+	struct ScsiReqBlk srb;
+
+	struct NvRamType eeprom;	/* eeprom settings for this adapter */
+};
+
+
+/*---------------------------------------------------------------------------
+                            Forward declarations
+ ---------------------------------------------------------------------------*/
+static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status);
+static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb, 
+		u16 *pscsi_status);
+static void set_basic_config(struct AdapterCtlBlk *acb);
+static void cleanup_after_transfer(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb);
+static void reset_scsi_bus(struct AdapterCtlBlk *acb);
+static void data_io_transfer(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb, u16 io_dir);
+static void disconnect(struct AdapterCtlBlk *acb);
+static void reselect(struct AdapterCtlBlk *acb);
+static u8 start_scsi(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
+static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb);
+static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
+static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_code,
+		struct scsi_cmnd *cmd, u8 force);
+static void scsi_reset_detect(struct AdapterCtlBlk *acb);
+static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb);
+static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb);
+static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
+static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb);
+static void set_xfer_rate(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb);
+static void waiting_timeout(unsigned long ptr);
+
+
+/*---------------------------------------------------------------------------
+                                 Static Data
+ ---------------------------------------------------------------------------*/
+static u16 current_sync_offset = 0;
+
+static void *dc395x_scsi_phase0[] = {
+	data_out_phase0,/* phase:0 */
+	data_in_phase0,	/* phase:1 */
+	command_phase0,	/* phase:2 */
+	status_phase0,	/* phase:3 */
+	nop0,		/* phase:4 PH_BUS_FREE .. initial phase */
+	nop0,		/* phase:5 PH_BUS_FREE .. initial phase */
+	msgout_phase0,	/* phase:6 */
+	msgin_phase0,	/* phase:7 */
+};
+
+static void *dc395x_scsi_phase1[] = {
+	data_out_phase1,/* phase:0 */
+	data_in_phase1,	/* phase:1 */
+	command_phase1,	/* phase:2 */
+	status_phase1,	/* phase:3 */
+	nop1,		/* phase:4 PH_BUS_FREE .. initial phase */
+	nop1,		/* phase:5 PH_BUS_FREE .. initial phase */
+	msgout_phase1,	/* phase:6 */
+	msgin_phase1,	/* phase:7 */
+};
+
+/*
+ *Fast20:	000	 50ns, 20.0 MHz
+ *		001	 75ns, 13.3 MHz
+ *		010	100ns, 10.0 MHz
+ *		011	125ns,  8.0 MHz
+ *		100	150ns,  6.6 MHz
+ *		101	175ns,  5.7 MHz
+ *		110	200ns,  5.0 MHz
+ *		111	250ns,  4.0 MHz
+ *
+ *Fast40(LVDS):	000	 25ns, 40.0 MHz
+ *		001	 50ns, 20.0 MHz
+ *		010	 75ns, 13.3 MHz
+ *		011	100ns, 10.0 MHz
+ *		100	125ns,  8.0 MHz
+ *		101	150ns,  6.6 MHz
+ *		110	175ns,  5.7 MHz
+ *		111	200ns,  5.0 MHz
+ */
+/*static u8	clock_period[] = {12,19,25,31,37,44,50,62};*/
+
+/* real period:48ns,76ns,100ns,124ns,148ns,176ns,200ns,248ns */
+static u8 clock_period[] = { 12, 18, 25, 31, 37, 43, 50, 62 };
+static u16 clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 };
+
+
+/*---------------------------------------------------------------------------
+                                Configuration
+  ---------------------------------------------------------------------------*/
+/*
+ * Module/boot parameters currently effect *all* instances of the
+ * card in the system.
+ */
+
+/*
+ * Command line parameters are stored in a structure below.
+ * These are the index's into the structure for the various
+ * command line options.
+ */
+#define CFG_ADAPTER_ID		0
+#define CFG_MAX_SPEED		1
+#define CFG_DEV_MODE		2
+#define CFG_ADAPTER_MODE	3
+#define CFG_TAGS		4
+#define CFG_RESET_DELAY		5
+
+#define CFG_NUM			6	/* number of configuration items */
+
+
+/*
+ * Value used to indicate that a command line override
+ * hasn't been used to modify the value.
+ */
+#define CFG_PARAM_UNSET -1
+
+
+/*
+ * Hold command line parameters.
+ */
+struct ParameterData {
+	int value;		/* value of this setting */
+	int min;		/* minimum value */
+	int max;		/* maximum value */
+	int def;		/* default value */
+	int safe;		/* safe value */
+};
+static struct ParameterData __devinitdata cfg_data[] = {
+	{ /* adapter id */
+		CFG_PARAM_UNSET,
+		0,
+		15,
+		7,
+		7
+	},
+	{ /* max speed */
+		CFG_PARAM_UNSET,
+		  0,
+		  7,
+		  1,	/* 13.3Mhz */
+		  4,	/*  6.7Hmz */
+	},
+	{ /* dev mode */
+		CFG_PARAM_UNSET,
+		0,
+		0x3f,
+		NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO |
+			NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING |
+			NTC_DO_SEND_START,
+		NTC_DO_PARITY_CHK | NTC_DO_SEND_START
+	},
+	{ /* adapter mode */
+		CFG_PARAM_UNSET,
+		0,
+		0x2f,
+#ifdef CONFIG_SCSI_MULTI_LUN
+			NAC_SCANLUN |
+#endif
+		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET
+			/*| NAC_ACTIVE_NEG*/,
+		NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08
+	},
+	{ /* tags */
+		CFG_PARAM_UNSET,
+		0,
+		5,
+		3,	/* 16 tags (??) */
+		2,
+	},
+	{ /* reset delay */
+		CFG_PARAM_UNSET,
+		0,
+		180,
+		1,	/* 1 second */
+		10,	/* 10 seconds */
+	}
+};
+
+
+/*
+ * Safe settings. If set to zero the the BIOS/default values with
+ * command line overrides will be used. If set to 1 then safe and
+ * slow settings will be used.
+ */
+static int use_safe_settings = 0;
+module_param_named(safe, use_safe_settings, bool, 0);
+MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false");
+
+
+module_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0);
+MODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)");
+
+module_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0);
+MODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz");
+
+module_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0);
+MODULE_PARM_DESC(dev_mode, "Device mode.");
+
+module_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0);
+MODULE_PARM_DESC(adapter_mode, "Adapter mode.");
+
+module_param_named(tags, cfg_data[CFG_TAGS].value, int, 0);
+MODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)");
+
+module_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0);
+MODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)");
+
+
+/**
+ * set_safe_settings - if the use_safe_settings option is set then
+ * set all values to the safe and slow values.
+ **/
+static void __devinit set_safe_settings(void)
+{
+	if (use_safe_settings)
+	{
+		int i;
+
+		dprintkl(KERN_INFO, "Using safe settings.\n");
+		for (i = 0; i < CFG_NUM; i++)
+		{
+			cfg_data[i].value = cfg_data[i].safe;
+		}
+	}
+}
+
+
+/**
+ * fix_settings - reset any boot parameters which are out of range
+ * back to the default values.
+ **/
+static void __devinit fix_settings(void)
+{
+	int i;
+
+	dprintkdbg(DBG_1,
+		"setup: AdapterId=%08x MaxSpeed=%08x DevMode=%08x "
+		"AdapterMode=%08x Tags=%08x ResetDelay=%08x\n",
+		cfg_data[CFG_ADAPTER_ID].value,
+		cfg_data[CFG_MAX_SPEED].value,
+		cfg_data[CFG_DEV_MODE].value,
+		cfg_data[CFG_ADAPTER_MODE].value,
+		cfg_data[CFG_TAGS].value,
+		cfg_data[CFG_RESET_DELAY].value);
+	for (i = 0; i < CFG_NUM; i++)
+	{
+		if (cfg_data[i].value < cfg_data[i].min
+		    || cfg_data[i].value > cfg_data[i].max)
+			cfg_data[i].value = cfg_data[i].def;
+	}
+}
+
+
+
+/*
+ * Mapping from the eeprom delay index value (index into this array)
+ * to the the number of actual seconds that the delay should be for.
+ */
+static char __devinitdata eeprom_index_to_delay_map[] = 
+	{ 1, 3, 5, 10, 16, 30, 60, 120 };
+
+
+/**
+ * eeprom_index_to_delay - Take the eeprom delay setting and convert it
+ * into a number of seconds.
+ *
+ * @eeprom: The eeprom structure in which we find the delay index to map.
+ **/
+static void __devinit eeprom_index_to_delay(struct NvRamType *eeprom)
+{
+	eeprom->delay_time = eeprom_index_to_delay_map[eeprom->delay_time];
+}
+
+
+/**
+ * delay_to_eeprom_index - Take a delay in seconds and return the
+ * closest eeprom index which will delay for at least that amount of
+ * seconds.
+ *
+ * @delay: The delay, in seconds, to find the eeprom index for.
+ **/
+static int __devinit delay_to_eeprom_index(int delay)
+{
+	u8 idx = 0;
+	while (idx < 7 && eeprom_index_to_delay_map[idx] < delay)
+		idx++;
+	return idx;
+}
+
+
+/**
+ * eeprom_override - Override the eeprom settings, in the provided
+ * eeprom structure, with values that have been set on the command
+ * line.
+ *
+ * @eeprom: The eeprom data to override with command line options.
+ **/
+static void __devinit eeprom_override(struct NvRamType *eeprom)
+{
+	u8 id;
+
+	/* Adapter Settings */
+	if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET)
+		eeprom->scsi_id = (u8)cfg_data[CFG_ADAPTER_ID].value;
+
+	if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET)
+		eeprom->channel_cfg = (u8)cfg_data[CFG_ADAPTER_MODE].value;
+
+	if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET)
+		eeprom->delay_time = delay_to_eeprom_index(
+					cfg_data[CFG_RESET_DELAY].value);
+
+	if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET)
+		eeprom->max_tag = (u8)cfg_data[CFG_TAGS].value;
+
+	/* Device Settings */
+	for (id = 0; id < DC395x_MAX_SCSI_ID; id++) {
+		if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET)
+			eeprom->target[id].cfg0 =
+				(u8)cfg_data[CFG_DEV_MODE].value;
+
+		if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET)
+			eeprom->target[id].period =
+				(u8)cfg_data[CFG_MAX_SPEED].value;
+
+	}
+}
+
+
+/*---------------------------------------------------------------------------
+ ---------------------------------------------------------------------------*/
+
+static unsigned int list_size(struct list_head *head)
+{
+	unsigned int count = 0;
+	struct list_head *pos;
+	list_for_each(pos, head)
+		count++;
+	return count;
+}
+
+
+static struct DeviceCtlBlk *dcb_get_next(struct list_head *head,
+		struct DeviceCtlBlk *pos)
+{
+	int use_next = 0;
+	struct DeviceCtlBlk* next = NULL;
+	struct DeviceCtlBlk* i;
+
+	if (list_empty(head))
+		return NULL;
+
+	/* find supplied dcb and then select the next one */
+	list_for_each_entry(i, head, list)
+		if (use_next) {
+			next = i;
+			break;
+		} else if (i == pos) {
+			use_next = 1;
+		}
+	/* if no next one take the head one (ie, wraparound) */
+	if (!next)
+        	list_for_each_entry(i, head, list) {
+        		next = i;
+        		break;
+        	}
+
+	return next;
+}
+
+
+static void free_tag(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+{
+	if (srb->tag_number < 255) {
+		dcb->tag_mask &= ~(1 << srb->tag_number);	/* free tag mask */
+		srb->tag_number = 255;
+	}
+}
+
+
+/* Find cmd in SRB list */
+inline static struct ScsiReqBlk *find_cmd(struct scsi_cmnd *cmd, 
+		struct list_head *head)
+{
+	struct ScsiReqBlk *i;
+	list_for_each_entry(i, head, list)
+		if (i->cmd == cmd)
+			return i;
+	return NULL;
+}
+
+
+static struct ScsiReqBlk *srb_get_free(struct AdapterCtlBlk *acb)
+{
+	struct list_head *head = &acb->srb_free_list;
+	struct ScsiReqBlk *srb = NULL;
+
+	if (!list_empty(head)) {
+		srb = list_entry(head->next, struct ScsiReqBlk, list);
+		list_del(head->next);
+		dprintkdbg(DBG_0, "srb_get_free: srb=%p\n", srb);
+	}
+	return srb;
+}
+
+
+static void srb_free_insert(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0, "srb_free_insert: srb=%p\n", srb);
+	list_add_tail(&srb->list, &acb->srb_free_list);
+}
+
+
+static void srb_waiting_insert(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0, "srb_waiting_insert: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add(&srb->list, &dcb->srb_waiting_list);
+}
+
+
+static void srb_waiting_append(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0, "srb_waiting_append: (pid#%li) <%02i-%i> srb=%p\n",
+		 srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add_tail(&srb->list, &dcb->srb_waiting_list);
+}
+
+
+static void srb_going_append(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0, "srb_going_append: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_add_tail(&srb->list, &dcb->srb_going_list);
+}
+
+
+static void srb_going_remove(struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+{
+	struct ScsiReqBlk *i;
+	struct ScsiReqBlk *tmp;
+	dprintkdbg(DBG_0, "srb_going_remove: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+
+	list_for_each_entry_safe(i, tmp, &dcb->srb_going_list, list)
+		if (i == srb) {
+			list_del(&srb->list);
+			break;
+		}
+}
+
+
+static void srb_waiting_remove(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	struct ScsiReqBlk *i;
+	struct ScsiReqBlk *tmp;
+	dprintkdbg(DBG_0, "srb_waiting_remove: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+
+	list_for_each_entry_safe(i, tmp, &dcb->srb_waiting_list, list)
+		if (i == srb) {
+			list_del(&srb->list);
+			break;
+		}
+}
+
+
+static void srb_going_to_waiting_move(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0,
+		"srb_going_to_waiting_move: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_move(&srb->list, &dcb->srb_waiting_list);
+}
+
+
+static void srb_waiting_to_going_move(struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	dprintkdbg(DBG_0,
+		"srb_waiting_to_going_move: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+	list_move(&srb->list, &dcb->srb_going_list);
+}
+
+
+/* Sets the timer to wake us up */
+static void waiting_set_timer(struct AdapterCtlBlk *acb, unsigned long to)
+{
+	if (timer_pending(&acb->waiting_timer))
+		return;
+	init_timer(&acb->waiting_timer);
+	acb->waiting_timer.function = waiting_timeout;
+	acb->waiting_timer.data = (unsigned long) acb;
+	if (time_before(jiffies + to, acb->scsi_host->last_reset - HZ / 2))
+		acb->waiting_timer.expires =
+		    acb->scsi_host->last_reset - HZ / 2 + 1;
+	else
+		acb->waiting_timer.expires = jiffies + to + 1;
+	add_timer(&acb->waiting_timer);
+}
+
+
+/* Send the next command from the waiting list to the bus */
+static void waiting_process_next(struct AdapterCtlBlk *acb)
+{
+	struct DeviceCtlBlk *start = NULL;
+	struct DeviceCtlBlk *pos;
+	struct DeviceCtlBlk *dcb;
+	struct ScsiReqBlk *srb;
+	struct list_head *dcb_list_head = &acb->dcb_list;
+
+	if (acb->active_dcb
+	    || (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV)))
+		return;
+
+	if (timer_pending(&acb->waiting_timer))
+		del_timer(&acb->waiting_timer);
+
+	if (list_empty(dcb_list_head))
+		return;
+
+	/*
+	 * Find the starting dcb. Need to find it again in the list
+	 * since the list may have changed since we set the ptr to it
+	 */
+	list_for_each_entry(dcb, dcb_list_head, list)
+		if (dcb == acb->dcb_run_robin) {
+			start = dcb;
+			break;
+		}
+	if (!start) {
+		/* This can happen! */
+		start = list_entry(dcb_list_head->next, typeof(*start), list);
+		acb->dcb_run_robin = start;
+	}
+
+
+	/*
+	 * Loop over the dcb, but we start somewhere (potentially) in
+	 * the middle of the loop so we need to manully do this.
+	 */
+	pos = start;
+	do {
+		struct list_head *waiting_list_head = &pos->srb_waiting_list;
+
+		/* Make sure, the next another device gets scheduled ... */
+		acb->dcb_run_robin = dcb_get_next(dcb_list_head,
+						  acb->dcb_run_robin);
+
+		if (list_empty(waiting_list_head) ||
+		    pos->max_command <= list_size(&pos->srb_going_list)) {
+			/* move to next dcb */
+			pos = dcb_get_next(dcb_list_head, pos);
+		} else {
+			srb = list_entry(waiting_list_head->next,
+					 struct ScsiReqBlk, list);
+
+			/* Try to send to the bus */
+			if (!start_scsi(acb, pos, srb))
+				srb_waiting_to_going_move(pos, srb);
+			else
+				waiting_set_timer(acb, HZ/50);
+			break;
+		}
+	} while (pos != start);
+}
+
+
+/* Wake up waiting queue */
+static void waiting_timeout(unsigned long ptr)
+{
+	unsigned long flags;
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
+	dprintkdbg(DBG_1,
+		"waiting_timeout: Queue woken up by timer. acb=%p\n", acb);
+	DC395x_LOCK_IO(acb->scsi_host, flags);
+	waiting_process_next(acb);
+	DC395x_UNLOCK_IO(acb->scsi_host, flags);
+}
+
+
+/* Get the DCB for a given ID/LUN combination */
+static struct DeviceCtlBlk *find_dcb(struct AdapterCtlBlk *acb, u8 id, u8 lun)
+{
+	return acb->children[id][lun];
+}
+
+
+/* Send SCSI Request Block (srb) to adapter (acb) */
+static void send_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+
+	if (dcb->max_command <= list_size(&dcb->srb_going_list) ||
+	    acb->active_dcb ||
+	    (acb->acb_flag & (RESET_DETECT + RESET_DONE + RESET_DEV))) {
+		srb_waiting_append(dcb, srb);
+		waiting_process_next(acb);
+		return;
+	}
+
+	if (!start_scsi(acb, dcb, srb))
+		srb_going_append(dcb, srb);
+	else {
+		srb_waiting_insert(dcb, srb);
+		waiting_set_timer(acb, HZ / 50);
+	}
+}
+
+
+/* Prepare SRB for being sent to Device DCB w/ command *cmd */
+static void build_srb(struct scsi_cmnd *cmd, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	enum dma_data_direction dir = cmd->sc_data_direction;
+	dprintkdbg(DBG_0, "build_srb: (pid#%li) <%02i-%i>\n",
+		cmd->pid, dcb->target_id, dcb->target_lun);
+
+	srb->dcb = dcb;
+	srb->cmd = cmd;
+	srb->sg_count = 0;
+	srb->total_xfer_length = 0;
+	srb->sg_bus_addr = 0;
+	srb->virt_addr = NULL;
+	srb->sg_index = 0;
+	srb->adapter_status = 0;
+	srb->target_status = 0;
+	srb->msg_count = 0;
+	srb->status = 0;
+	srb->flag = 0;
+	srb->state = 0;
+	srb->retry_count = 0;
+	srb->tag_number = TAG_NONE;
+	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
+	srb->end_message = 0;
+
+	if (dir == PCI_DMA_NONE || !cmd->request_buffer) {
+		dprintkdbg(DBG_0,
+			"build_srb: [0] len=%d buf=%p use_sg=%d !MAP=%08x\n",
+			cmd->bufflen, cmd->request_buffer,
+			cmd->use_sg, srb->segment_x[0].address);
+	} else if (cmd->use_sg) {
+		int i;
+		u32 reqlen = cmd->request_bufflen;
+		struct scatterlist *sl = (struct scatterlist *)
+					 cmd->request_buffer;
+		struct SGentry *sgp = srb->segment_x;
+		srb->sg_count = pci_map_sg(dcb->acb->dev, sl, cmd->use_sg,
+					   dir);
+		dprintkdbg(DBG_0,
+			"build_srb: [n] len=%d buf=%p use_sg=%d segs=%d\n",
+			reqlen, cmd->request_buffer, cmd->use_sg,
+			srb->sg_count);
+
+		for (i = 0; i < srb->sg_count; i++) {
+			u32 seglen = (u32)sg_dma_len(sl + i);
+			sgp[i].address = (u32)sg_dma_address(sl + i);
+			sgp[i].length = seglen;
+			srb->total_xfer_length += seglen;
+			srb->virt_map[i] = kmap(sl[i].page);
+		}
+		srb->virt_addr = srb->virt_map[0];
+		sgp += srb->sg_count - 1;
+
+		/*
+		 * adjust last page if too big as it is allocated
+		 * on even page boundaries
+		 */
+		if (srb->total_xfer_length > reqlen) {
+			sgp->length -= (srb->total_xfer_length - reqlen);
+			srb->total_xfer_length = reqlen;
+		}
+
+		/* Fixup for WIDE padding - make sure length is even */
+		if (dcb->sync_period & WIDE_SYNC &&
+		    srb->total_xfer_length % 2) {
+			srb->total_xfer_length++;
+			sgp->length++;
+		}
+
+		srb->sg_bus_addr = pci_map_single(dcb->acb->dev,
+						srb->segment_x,
+				            	SEGMENTX_LEN,
+				            	PCI_DMA_TODEVICE);
+
+		dprintkdbg(DBG_SG, "build_srb: [n] map sg %p->%08x(%05x)\n",
+			srb->segment_x, srb->sg_bus_addr, SEGMENTX_LEN);
+	} else {
+		srb->total_xfer_length = cmd->request_bufflen;
+		srb->sg_count = 1;
+		srb->segment_x[0].address =
+			pci_map_single(dcb->acb->dev, cmd->request_buffer,
+				       srb->total_xfer_length, dir);
+
+		/* Fixup for WIDE padding - make sure length is even */
+		if (dcb->sync_period & WIDE_SYNC && srb->total_xfer_length % 2)
+			srb->total_xfer_length++;
+
+		srb->segment_x[0].length = srb->total_xfer_length;
+		srb->virt_addr = cmd->request_buffer;
+		dprintkdbg(DBG_0,
+			"build_srb: [1] len=%d buf=%p use_sg=%d map=%08x\n",
+			srb->total_xfer_length, cmd->request_buffer,
+			cmd->use_sg, srb->segment_x[0].address);
+	}
+}
+
+
+/**
+ * dc395x_queue_command - queue scsi command passed from the mid
+ * layer, invoke 'done' on completion
+ *
+ * @cmd: pointer to scsi command object
+ * @done: function pointer to be invoked on completion
+ *
+ * Returns 1 if the adapter (host) is busy, else returns 0. One
+ * reason for an adapter to be busy is that the number
+ * of outstanding queued commands is already equal to
+ * struct Scsi_Host::can_queue .
+ *
+ * Required: if struct Scsi_Host::can_queue is ever non-zero
+ *           then this function is required.
+ *
+ * Locks: struct Scsi_Host::host_lock held on entry (with "irqsave")
+ *        and is expected to be held on return.
+ *
+ **/
+static int dc395x_queue_command(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct DeviceCtlBlk *dcb;
+	struct ScsiReqBlk *srb;
+	struct AdapterCtlBlk *acb =
+	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
+	dprintkdbg(DBG_0, "queue_command: (pid#%li) <%02i-%i> cmnd=0x%02x\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+
+	/* Assume BAD_TARGET; will be cleared later */
+	cmd->result = DID_BAD_TARGET << 16;
+
+	/* ignore invalid targets */
+	if (cmd->device->id >= acb->scsi_host->max_id ||
+	    cmd->device->lun >= acb->scsi_host->max_lun ||
+	    cmd->device->lun >31) {
+		goto complete;
+	}
+
+	/* does the specified lun on the specified device exist */
+	if (!(acb->dcb_map[cmd->device->id] & (1 << cmd->device->lun))) {
+		dprintkl(KERN_INFO, "queue_command: Ignore target <%02i-%i>\n",
+			cmd->device->id, cmd->device->lun);
+		goto complete;
+	}
+
+	/* do we have a DCB for the device */
+	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
+	if (!dcb) {
+		/* should never happen */
+		dprintkl(KERN_ERR, "queue_command: No such device <%02i-%i>",
+			cmd->device->id, cmd->device->lun);
+		goto complete;
+	}
+
+	/* set callback and clear result in the command */
+	cmd->scsi_done = done;
+	cmd->result = 0;
+
+	srb = srb_get_free(acb);
+	if (!srb)
+	{
+		/*
+		 * Return 1 since we are unable to queue this command at this
+		 * point in time.
+		 */
+		dprintkdbg(DBG_0, "queue_command: No free srb's\n");
+		return 1;
+	}
+
+	build_srb(cmd, dcb, srb);
+
+	if (!list_empty(&dcb->srb_waiting_list)) {
+		/* append to waiting queue */
+		srb_waiting_append(dcb, srb);
+		waiting_process_next(acb);
+	} else {
+		/* process immediately */
+		send_srb(acb, srb);
+	}
+	dprintkdbg(DBG_1, "queue_command: (pid#%li) done\n", cmd->pid);
+	return 0;
+
+complete:
+	/*
+	 * Complete the command immediatey, and then return 0 to
+	 * indicate that we have handled the command. This is usually
+	 * done when the commad is for things like non existent
+	 * devices.
+	 */
+	done(cmd);
+	return 0;
+}
+
+
+/*
+ * Return the disk geometry for the given SCSI device.
+ */
+static int dc395x_bios_param(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int *info)
+{
+#ifdef CONFIG_SCSI_DC395x_TRMS1040_TRADMAP
+	int heads, sectors, cylinders;
+	struct AdapterCtlBlk *acb;
+	int size = capacity;
+
+	dprintkdbg(DBG_0, "dc395x_bios_param..............\n");
+	acb = (struct AdapterCtlBlk *)sdev->host->hostdata;
+	heads = 64;
+	sectors = 32;
+	cylinders = size / (heads * sectors);
+
+	if ((acb->gmode2 & NAC_GREATER_1G) && (cylinders > 1024)) {
+		heads = 255;
+		sectors = 63;
+		cylinders = size / (heads * sectors);
+	}
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	return 0;
+#else
+	return scsicam_bios_param(bdev, capacity, info);
+#endif
+}
+
+
+static void dump_register_info(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb, struct ScsiReqBlk *srb)
+{
+	u16 pstat;
+	struct pci_dev *dev = acb->dev;
+	pci_read_config_word(dev, PCI_STATUS, &pstat);
+	if (!dcb)
+		dcb = acb->active_dcb;
+	if (!srb && dcb)
+		srb = dcb->active_srb;
+	if (srb) {
+		if (!srb->cmd)
+			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p OOOPS!\n",
+				srb, srb->cmd);
+		else
+			dprintkl(KERN_INFO, "dump: srb=%p cmd=%p (pid#%li) "
+				 "cmnd=0x%02x <%02i-%i>\n",
+			    	srb, srb->cmd, srb->cmd->pid,
+				srb->cmd->cmnd[0], srb->cmd->device->id,
+			       	srb->cmd->device->lun);
+		printk("  sglist=%p cnt=%i idx=%i len=%i\n",
+		       srb->segment_x, srb->sg_count, srb->sg_index,
+		       srb->total_xfer_length);
+		printk("  state=0x%04x status=0x%02x phase=0x%02x (%sconn.)\n",
+		       srb->state, srb->status, srb->scsi_phase,
+		       (acb->active_dcb) ? "" : "not");
+	}
+	dprintkl(KERN_INFO, "dump: SCSI{status=0x%04x fifocnt=0x%02x "
+		"signals=0x%02x irqstat=0x%02x sync=0x%02x target=0x%02x "
+		"rselid=0x%02x ctr=0x%08x irqen=0x%02x config=0x%04x "
+		"config2=0x%02x cmd=0x%02x selto=0x%02x}\n",
+		DC395x_read16(acb, TRM_S1040_SCSI_STATUS),
+		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL),
+		DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS),
+		DC395x_read8(acb, TRM_S1040_SCSI_SYNC),
+		DC395x_read8(acb, TRM_S1040_SCSI_TARGETID),
+		DC395x_read8(acb, TRM_S1040_SCSI_IDMSG),
+		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+		DC395x_read8(acb, TRM_S1040_SCSI_INTEN),
+		DC395x_read16(acb, TRM_S1040_SCSI_CONFIG0),
+		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG2),
+		DC395x_read8(acb, TRM_S1040_SCSI_COMMAND),
+		DC395x_read8(acb, TRM_S1040_SCSI_TIMEOUT));
+	dprintkl(KERN_INFO, "dump: DMA{cmd=0x%04x fifocnt=0x%02x fstat=0x%02x "
+		"irqstat=0x%02x irqen=0x%02x cfg=0x%04x tctr=0x%08x "
+		"ctctr=0x%08x addr=0x%08x:0x%08x}\n",
+		DC395x_read16(acb, TRM_S1040_DMA_COMMAND),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+		DC395x_read8(acb, TRM_S1040_DMA_STATUS),
+		DC395x_read8(acb, TRM_S1040_DMA_INTEN),
+		DC395x_read16(acb, TRM_S1040_DMA_CONFIG),
+		DC395x_read32(acb, TRM_S1040_DMA_XCNT),
+		DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
+		DC395x_read32(acb, TRM_S1040_DMA_XHIGHADDR),
+		DC395x_read32(acb, TRM_S1040_DMA_XLOWADDR));
+	dprintkl(KERN_INFO, "dump: gen{gctrl=0x%02x gstat=0x%02x gtmr=0x%02x} "
+		"pci{status=0x%04x}\n",
+		DC395x_read8(acb, TRM_S1040_GEN_CONTROL),
+		DC395x_read8(acb, TRM_S1040_GEN_STATUS),
+		DC395x_read8(acb, TRM_S1040_GEN_TIMER),
+		pstat);
+}
+
+
+static inline void clear_fifo(struct AdapterCtlBlk *acb, char *txt)
+{
+#if debug_enabled(DBG_FIFO)
+	u8 lines = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
+	u8 fifocnt = DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT);
+	if (!(fifocnt & 0x40))
+		dprintkdbg(DBG_FIFO,
+			"clear_fifo: (%i bytes) on phase %02x in %s\n",
+			fifocnt & 0x3f, lines, txt);
+#endif
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRFIFO);
+}
+
+
+static void reset_dev_param(struct AdapterCtlBlk *acb)
+{
+	struct DeviceCtlBlk *dcb;
+	struct NvRamType *eeprom = &acb->eeprom;
+	dprintkdbg(DBG_0, "reset_dev_param: acb=%p\n", acb);
+
+	list_for_each_entry(dcb, &acb->dcb_list, list) {
+		u8 period_index;
+
+		dcb->sync_mode &= ~(SYNC_NEGO_DONE + WIDE_NEGO_DONE);
+		dcb->sync_period = 0;
+		dcb->sync_offset = 0;
+
+		dcb->dev_mode = eeprom->target[dcb->target_id].cfg0;
+		period_index = eeprom->target[dcb->target_id].period & 0x07;
+		dcb->min_nego_period = clock_period[period_index];
+		if (!(dcb->dev_mode & NTC_DO_WIDE_NEGO)
+		    || !(acb->config & HCC_WIDE_CARD))
+			dcb->sync_mode &= ~WIDE_NEGO_ENABLE;
+	}
+}
+
+
+/*
+ * perform a hard reset on the SCSI bus
+ * @cmd - some command for this host (for fetching hooks)
+ * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
+ */
+static int dc395x_eh_bus_reset(struct scsi_cmnd *cmd)
+{
+	struct AdapterCtlBlk *acb =
+		(struct AdapterCtlBlk *)cmd->device->host->hostdata;
+	dprintkl(KERN_INFO,
+		"eh_bus_reset: (pid#%li) target=<%02i-%i> cmd=%p\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+
+	if (timer_pending(&acb->waiting_timer))
+		del_timer(&acb->waiting_timer);
+
+	/*
+	 * disable interrupt    
+	 */
+	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
+	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
+	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
+	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
+
+	reset_scsi_bus(acb);
+	udelay(500);
+
+	/* We may be in serious trouble. Wait some seconds */
+	acb->scsi_host->last_reset =
+	    jiffies + 3 * HZ / 2 +
+	    HZ * acb->eeprom.delay_time;
+
+	/*
+	 * re-enable interrupt      
+	 */
+	/* Clear SCSI FIFO          */
+	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+	clear_fifo(acb, "eh_bus_reset");
+	/* Delete pending IRQ */
+	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
+	set_basic_config(acb);
+
+	reset_dev_param(acb);
+	doing_srb_done(acb, DID_RESET, cmd, 0);
+	acb->active_dcb = NULL;
+	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE ,RESET_DEV */
+	waiting_process_next(acb);
+
+	return SUCCESS;
+}
+
+
+/*
+ * abort an errant SCSI command
+ * @cmd - command to be aborted
+ * Returns: SUCCESS (0x2002) on success, else FAILED (0x2003).
+ */
+static int dc395x_eh_abort(struct scsi_cmnd *cmd)
+{
+	/*
+	 * Look into our command queues: If it has not been sent already,
+	 * we remove it and return success. Otherwise fail.
+	 */
+	struct AdapterCtlBlk *acb =
+	    (struct AdapterCtlBlk *)cmd->device->host->hostdata;
+	struct DeviceCtlBlk *dcb;
+	struct ScsiReqBlk *srb;
+	dprintkl(KERN_INFO, "eh_abort: (pid#%li) target=<%02i-%i> cmd=%p\n",
+		cmd->pid, cmd->device->id, cmd->device->lun, cmd);
+
+	dcb = find_dcb(acb, cmd->device->id, cmd->device->lun);
+	if (!dcb) {
+		dprintkl(KERN_DEBUG, "eh_abort: No such device\n");
+		return FAILED;
+	}
+
+	srb = find_cmd(cmd, &dcb->srb_waiting_list);
+	if (srb) {
+		srb_waiting_remove(dcb, srb);
+		pci_unmap_srb_sense(acb, srb);
+		pci_unmap_srb(acb, srb);
+		free_tag(dcb, srb);
+		srb_free_insert(acb, srb);
+		dprintkl(KERN_DEBUG, "eh_abort: Command was waiting\n");
+		cmd->result = DID_ABORT << 16;
+		return SUCCESS;
+	}
+	srb = find_cmd(cmd, &dcb->srb_going_list);
+	if (srb) {
+		dprintkl(KERN_DEBUG, "eh_abort: Command in progress");
+		/* XXX: Should abort the command here */
+	} else {
+		dprintkl(KERN_DEBUG, "eh_abort: Command not found");
+	}
+	return FAILED;
+}
+
+
+/* SDTR */
+static void build_sdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	u8 *ptr = srb->msgout_buf + srb->msg_count;
+	if (srb->msg_count > 1) {
+		dprintkl(KERN_INFO,
+			"build_sdtr: msgout_buf BUSY (%i: %02x %02x)\n",
+			srb->msg_count, srb->msgout_buf[0],
+			srb->msgout_buf[1]);
+		return;
+	}
+	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO)) {
+		dcb->sync_offset = 0;
+		dcb->min_nego_period = 200 >> 2;
+	} else if (dcb->sync_offset == 0)
+		dcb->sync_offset = SYNC_NEGO_OFFSET;
+
+	*ptr++ = MSG_EXTENDED;	/* (01h) */
+	*ptr++ = 3;		/* length */
+	*ptr++ = EXTENDED_SDTR;	/* (01h) */
+	*ptr++ = dcb->min_nego_period;	/* Transfer period (in 4ns) */
+	*ptr++ = dcb->sync_offset;	/* Transfer period (max. REQ/ACK dist) */
+	srb->msg_count += 5;
+	srb->state |= SRB_DO_SYNC_NEGO;
+}
+
+
+/* WDTR */
+static void build_wdtr(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	u8 wide = ((dcb->dev_mode & NTC_DO_WIDE_NEGO) &
+		   (acb->config & HCC_WIDE_CARD)) ? 1 : 0;
+	u8 *ptr = srb->msgout_buf + srb->msg_count;
+	if (srb->msg_count > 1) {
+		dprintkl(KERN_INFO,
+			"build_wdtr: msgout_buf BUSY (%i: %02x %02x)\n",
+			srb->msg_count, srb->msgout_buf[0],
+			srb->msgout_buf[1]);
+		return;
+	}
+	*ptr++ = MSG_EXTENDED;	/* (01h) */
+	*ptr++ = 2;		/* length */
+	*ptr++ = EXTENDED_WDTR;	/* (03h) */
+	*ptr++ = wide;
+	srb->msg_count += 4;
+	srb->state |= SRB_DO_WIDE_NEGO;
+}
+
+
+#if 0
+/* Timer to work around chip flaw: When selecting and the bus is 
+ * busy, we sometimes miss a Selection timeout IRQ */
+void selection_timeout_missed(unsigned long ptr);
+/* Sets the timer to wake us up */
+static void selto_timer(struct AdapterCtlBlk *acb)
+{
+	if (timer_pending(&acb->selto_timer))
+		return;
+	acb->selto_timer.function = selection_timeout_missed;
+	acb->selto_timer.data = (unsigned long) acb;
+	if (time_before
+	    (jiffies + HZ, acb->scsi_host->last_reset + HZ / 2))
+		acb->selto_timer.expires =
+		    acb->scsi_host->last_reset + HZ / 2 + 1;
+	else
+		acb->selto_timer.expires = jiffies + HZ + 1;
+	add_timer(&acb->selto_timer);
+}
+
+
+void selection_timeout_missed(unsigned long ptr)
+{
+	unsigned long flags;
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)ptr;
+	struct ScsiReqBlk *srb;
+	dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n");
+	if (!acb->active_dcb || !acb->active_dcb->active_srb) {
+		dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n");
+		return;
+	}
+	DC395x_LOCK_IO(acb->scsi_host, flags);
+	srb = acb->active_dcb->active_srb;
+	disconnect(acb);
+	DC395x_UNLOCK_IO(acb->scsi_host, flags);
+}
+#endif
+
+
+static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb,
+		struct ScsiReqBlk* srb)
+{
+	u16 s_stat2, return_code;
+	u8 s_stat, scsicommand, i, identify_message;
+	u8 *ptr;
+	dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> srb=%p\n",
+		srb->cmd->pid, dcb->target_id, dcb->target_lun, srb);
+
+	srb->tag_number = TAG_NONE;	/* acb->tag_max_num: had error read in eeprom */
+
+	s_stat = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
+	s_stat2 = 0;
+	s_stat2 = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
+#if 1
+	if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) {
+		dprintkdbg(DBG_KG, "start_scsi: (pid#%li) BUSY %02x %04x\n",
+			srb->cmd->pid, s_stat, s_stat2);
+		/*
+		 * Try anyway?
+		 *
+		 * We could, BUT: Sometimes the TRM_S1040 misses to produce a Selection
+		 * Timeout, a Disconnect or a Reselction IRQ, so we would be screwed!
+		 * (This is likely to be a bug in the hardware. Obviously, most people
+		 *  only have one initiator per SCSI bus.)
+		 * Instead let this fail and have the timer make sure the command is 
+		 * tried again after a short time
+		 */
+		/*selto_timer (acb); */
+		return 1;
+	}
+#endif
+	if (acb->active_dcb) {
+		dprintkl(KERN_DEBUG, "start_scsi: (pid#%li) Attempt to start a"
+			"command while another command (pid#%li) is active.",
+			srb->cmd->pid,
+			acb->active_dcb->active_srb ?
+			    acb->active_dcb->active_srb->cmd->pid : 0);
+		return 1;
+	}
+	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
+		dprintkdbg(DBG_KG, "start_scsi: (pid#%li) Failed (busy)\n",
+			srb->cmd->pid);
+		return 1;
+	}
+	/* Allow starting of SCSI commands half a second before we allow the mid-level
+	 * to queue them again after a reset */
+	if (time_before(jiffies, acb->scsi_host->last_reset - HZ / 2)) {
+		dprintkdbg(DBG_KG, "start_scsi: Refuse cmds (reset wait)\n");
+		return 1;
+	}
+
+	/* Flush FIFO */
+	clear_fifo(acb, "start_scsi");
+	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
+	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
+	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
+	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
+	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
+
+	identify_message = dcb->identify_msg;
+	/*DC395x_TRM_write8(TRM_S1040_SCSI_IDMSG, identify_message); */
+	/* Don't allow disconnection for AUTO_REQSENSE: Cont.All.Cond.! */
+	if (srb->flag & AUTO_REQSENSE)
+		identify_message &= 0xBF;
+
+	if (((srb->cmd->cmnd[0] == INQUIRY)
+	     || (srb->cmd->cmnd[0] == REQUEST_SENSE)
+	     || (srb->flag & AUTO_REQSENSE))
+	    && (((dcb->sync_mode & WIDE_NEGO_ENABLE)
+		 && !(dcb->sync_mode & WIDE_NEGO_DONE))
+		|| ((dcb->sync_mode & SYNC_NEGO_ENABLE)
+		    && !(dcb->sync_mode & SYNC_NEGO_DONE)))
+	    && (dcb->target_lun == 0)) {
+		srb->msgout_buf[0] = identify_message;
+		srb->msg_count = 1;
+		scsicommand = SCMD_SEL_ATNSTOP;
+		srb->state = SRB_MSGOUT;
+#ifndef SYNC_FIRST
+		if (dcb->sync_mode & WIDE_NEGO_ENABLE
+		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
+			build_wdtr(acb, dcb, srb);
+			goto no_cmd;
+		}
+#endif
+		if (dcb->sync_mode & SYNC_NEGO_ENABLE
+		    && dcb->inquiry7 & SCSI_INQ_SYNC) {
+			build_sdtr(acb, dcb, srb);
+			goto no_cmd;
+		}
+		if (dcb->sync_mode & WIDE_NEGO_ENABLE
+		    && dcb->inquiry7 & SCSI_INQ_WBUS16) {
+			build_wdtr(acb, dcb, srb);
+			goto no_cmd;
+		}
+		srb->msg_count = 0;
+	}
+	/* Send identify message */
+	DC395x_write8(acb, TRM_S1040_SCSI_FIFO, identify_message);
+
+	scsicommand = SCMD_SEL_ATN;
+	srb->state = SRB_START_;
+#ifndef DC395x_NO_TAGQ
+	if ((dcb->sync_mode & EN_TAG_QUEUEING)
+	    && (identify_message & 0xC0)) {
+		/* Send Tag message */
+		u32 tag_mask = 1;
+		u8 tag_number = 0;
+		while (tag_mask & dcb->tag_mask
+		       && tag_number <= dcb->max_command) {
+			tag_mask = tag_mask << 1;
+			tag_number++;
+		}
+		if (tag_number >= dcb->max_command) {
+			dprintkl(KERN_WARNING, "start_scsi: (pid#%li) "
+				"Out of tags target=<%02i-%i>)\n",
+				srb->cmd->pid, srb->cmd->device->id,
+				srb->cmd->device->lun);
+			srb->state = SRB_READY;
+			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
+				       DO_HWRESELECT);
+			return 1;
+		}
+		/* Send Tag id */
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_SIMPLE_QTAG);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, tag_number);
+		dcb->tag_mask |= tag_mask;
+		srb->tag_number = tag_number;
+		scsicommand = SCMD_SEL_ATN3;
+		srb->state = SRB_START_;
+	}
+#endif
+/*polling:*/
+	/* Send CDB ..command block ......... */
+	dprintkdbg(DBG_KG, "start_scsi: (pid#%li) <%02i-%i> cmnd=0x%02x tag=%i\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+		srb->cmd->cmnd[0], srb->tag_number);
+	if (srb->flag & AUTO_REQSENSE) {
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
+			      sizeof(srb->cmd->sense_buffer));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+	} else {
+		ptr = (u8 *)srb->cmd->cmnd;
+		for (i = 0; i < srb->cmd->cmd_len; i++)
+			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
+	}
+      no_cmd:
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
+		       DO_HWRESELECT | DO_DATALATCH);
+	if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) {
+		/* 
+		 * If start_scsi return 1:
+		 * we caught an interrupt (must be reset or reselection ... )
+		 * : Let's process it first!
+		 */
+		dprintkdbg(DBG_0, "start_scsi: (pid#%li) <%02i-%i> Failed - busy\n",
+			srb->cmd->pid, dcb->target_id, dcb->target_lun);
+		srb->state = SRB_READY;
+		free_tag(dcb, srb);
+		srb->msg_count = 0;
+		return_code = 1;
+		/* This IRQ should NOT get lost, as we did not acknowledge it */
+	} else {
+		/* 
+		 * If start_scsi returns 0:
+		 * we know that the SCSI processor is free
+		 */
+		srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
+		dcb->active_srb = srb;
+		acb->active_dcb = dcb;
+		return_code = 0;
+		/* it's important for atn stop */
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
+			       DO_DATALATCH | DO_HWRESELECT);
+		/* SCSI command */
+		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, scsicommand);
+	}
+	return return_code;
+}
+
+
+#define DC395x_ENABLE_MSGOUT \
+ DC395x_write16 (acb, TRM_S1040_SCSI_CONTROL, DO_SETATN); \
+ srb->state |= SRB_MSGOUT
+
+
+/* abort command */
+static inline void enable_msgout_abort(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
+{
+	srb->msgout_buf[0] = ABORT;
+	srb->msg_count = 1;
+	DC395x_ENABLE_MSGOUT;
+	srb->state &= ~SRB_MSGIN;
+	srb->state |= SRB_MSGOUT;
+}
+
+
+/**
+ * dc395x_handle_interrupt - Handle an interrupt that has been confirmed to
+ *                           have been triggered for this card.
+ *
+ * @acb:	 a pointer to the adpter control block
+ * @scsi_status: the status return when we checked the card
+ **/
+static void dc395x_handle_interrupt(struct AdapterCtlBlk *acb,
+		u16 scsi_status)
+{
+	struct DeviceCtlBlk *dcb;
+	struct ScsiReqBlk *srb;
+	u16 phase;
+	u8 scsi_intstatus;
+	unsigned long flags;
+	void (*dc395x_statev)(struct AdapterCtlBlk *, struct ScsiReqBlk *, 
+			      u16 *);
+
+	DC395x_LOCK_IO(acb->scsi_host, flags);
+
+	/* This acknowledges the IRQ */
+	scsi_intstatus = DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
+	if ((scsi_status & 0x2007) == 0x2002)
+		dprintkl(KERN_DEBUG,
+			"COP after COP completed? %04x\n", scsi_status);
+	if (debug_enabled(DBG_KG)) {
+		if (scsi_intstatus & INT_SELTIMEOUT)
+			dprintkdbg(DBG_KG, "handle_interrupt: Selection timeout\n");
+	}
+	/*dprintkl(KERN_DEBUG, "handle_interrupt: intstatus = 0x%02x ", scsi_intstatus); */
+
+	if (timer_pending(&acb->selto_timer))
+		del_timer(&acb->selto_timer);
+
+	if (scsi_intstatus & (INT_SELTIMEOUT | INT_DISCONNECT)) {
+		disconnect(acb);	/* bus free interrupt  */
+		goto out_unlock;
+	}
+	if (scsi_intstatus & INT_RESELECTED) {
+		reselect(acb);
+		goto out_unlock;
+	}
+	if (scsi_intstatus & INT_SELECT) {
+		dprintkl(KERN_INFO, "Host does not support target mode!\n");
+		goto out_unlock;
+	}
+	if (scsi_intstatus & INT_SCSIRESET) {
+		scsi_reset_detect(acb);
+		goto out_unlock;
+	}
+	if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) {
+		dcb = acb->active_dcb;
+		if (!dcb) {
+			dprintkl(KERN_DEBUG,
+				"Oops: BusService (%04x %02x) w/o ActiveDCB!\n",
+				scsi_status, scsi_intstatus);
+			goto out_unlock;
+		}
+		srb = dcb->active_srb;
+		if (dcb->flag & ABORT_DEV_) {
+			dprintkdbg(DBG_0, "MsgOut Abort Device.....\n");
+			enable_msgout_abort(acb, srb);
+		}
+
+		/* software sequential machine */
+		phase = (u16)srb->scsi_phase;
+
+		/* 
+		 * 62037 or 62137
+		 * call  dc395x_scsi_phase0[]... "phase entry"
+		 * handle every phase before start transfer
+		 */
+		/* data_out_phase0,	phase:0 */
+		/* data_in_phase0,	phase:1 */
+		/* command_phase0,	phase:2 */
+		/* status_phase0,	phase:3 */
+		/* nop0,		phase:4 PH_BUS_FREE .. initial phase */
+		/* nop0,		phase:5 PH_BUS_FREE .. initial phase */
+		/* msgout_phase0,	phase:6 */
+		/* msgin_phase0,	phase:7 */
+		dc395x_statev = dc395x_scsi_phase0[phase];
+		dc395x_statev(acb, srb, &scsi_status);
+
+		/* 
+		 * if there were any exception occured scsi_status
+		 * will be modify to bus free phase new scsi_status
+		 * transfer out from ... previous dc395x_statev
+		 */
+		srb->scsi_phase = scsi_status & PHASEMASK;
+		phase = (u16)scsi_status & PHASEMASK;
+
+		/* 
+		 * call  dc395x_scsi_phase1[]... "phase entry" handle
+		 * every phase to do transfer
+		 */
+		/* data_out_phase1,	phase:0 */
+		/* data_in_phase1,	phase:1 */
+		/* command_phase1,	phase:2 */
+		/* status_phase1,	phase:3 */
+		/* nop1,		phase:4 PH_BUS_FREE .. initial phase */
+		/* nop1,		phase:5 PH_BUS_FREE .. initial phase */
+		/* msgout_phase1,	phase:6 */
+		/* msgin_phase1,	phase:7 */
+		dc395x_statev = dc395x_scsi_phase1[phase];
+		dc395x_statev(acb, srb, &scsi_status);
+	}
+      out_unlock:
+	DC395x_UNLOCK_IO(acb->scsi_host, flags);
+}
+
+
+static irqreturn_t dc395x_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)dev_id;
+	u16 scsi_status;
+	u8 dma_status;
+	irqreturn_t handled = IRQ_NONE;
+
+	/*
+	 * Check for pending interupt
+	 */
+	scsi_status = DC395x_read16(acb, TRM_S1040_SCSI_STATUS);
+	dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
+	if (scsi_status & SCSIINTERRUPT) {
+		/* interupt pending - let's process it! */
+		dc395x_handle_interrupt(acb, scsi_status);
+		handled = IRQ_HANDLED;
+	}
+	else if (dma_status & 0x20) {
+		/* Error from the DMA engine */
+		dprintkl(KERN_INFO, "Interrupt from DMA engine: 0x%02x!\n", dma_status);
+#if 0
+		dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n");
+		if (acb->active_dcb) {
+			acb->active_dcb-> flag |= ABORT_DEV_;
+			if (acb->active_dcb->active_srb)
+				enable_msgout_abort(acb, acb->active_dcb->active_srb);
+		}
+		DC395x_write8(acb, TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO);
+#else
+		dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n");
+		acb = NULL;
+#endif
+		handled = IRQ_HANDLED;
+	}
+
+	return handled;
+}
+
+
+static void msgout_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "msgout_phase0: (pid#%li)\n", srb->cmd->pid);
+	if (srb->state & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT))
+		*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
+
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+	srb->state &= ~SRB_MSGOUT;
+}
+
+
+static void msgout_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	u16 i;
+	u8 *ptr;
+	dprintkdbg(DBG_0, "msgout_phase1: (pid#%li)\n", srb->cmd->pid);
+
+	clear_fifo(acb, "msgout_phase1");
+	if (!(srb->state & SRB_MSGOUT)) {
+		srb->state |= SRB_MSGOUT;
+		dprintkl(KERN_DEBUG,
+			"msgout_phase1: (pid#%li) Phase unexpected\n",
+			srb->cmd->pid);	/* So what ? */
+	}
+	if (!srb->msg_count) {
+		dprintkdbg(DBG_0, "msgout_phase1: (pid#%li) NOP msg\n",
+			srb->cmd->pid);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, MSG_NOP);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
+		return;
+	}
+	ptr = (u8 *)srb->msgout_buf;
+	for (i = 0; i < srb->msg_count; i++)
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr++);
+	srb->msg_count = 0;
+	if (srb->msgout_buf[0] == MSG_ABORT)
+		srb->state = SRB_ABORT_SENT;
+
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
+}
+
+
+static void command_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "command_phase0: (pid#%li)\n", srb->cmd->pid);
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+}
+
+
+static void command_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	struct DeviceCtlBlk *dcb;
+	u8 *ptr;
+	u16 i;
+	dprintkdbg(DBG_0, "command_phase1: (pid#%li)\n", srb->cmd->pid);
+
+	clear_fifo(acb, "command_phase1");
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_CLRATN);
+	if (!(srb->flag & AUTO_REQSENSE)) {
+		ptr = (u8 *)srb->cmd->cmnd;
+		for (i = 0; i < srb->cmd->cmd_len; i++) {
+			DC395x_write8(acb, TRM_S1040_SCSI_FIFO, *ptr);
+			ptr++;
+		}
+	} else {
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, REQUEST_SENSE);
+		dcb = acb->active_dcb;
+		/* target id */
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, (dcb->target_lun << 5));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO,
+			      sizeof(srb->cmd->sense_buffer));
+		DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+	}
+	srb->state |= SRB_COMMAND;
+	/* it's important for atn stop */
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+	/* SCSI command */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT);
+}
+
+
+/*
+ * Verify that the remaining space in the hw sg lists is the same as
+ * the count of remaining bytes in srb->total_xfer_length
+ */
+static void sg_verify_length(struct ScsiReqBlk *srb)
+{
+	if (debug_enabled(DBG_SG)) {
+		unsigned len = 0;
+		unsigned idx = srb->sg_index;
+		struct SGentry *psge = srb->segment_x + idx;
+		for (; idx < srb->sg_count; psge++, idx++)
+			len += psge->length;
+		if (len != srb->total_xfer_length)
+			dprintkdbg(DBG_SG,
+			       "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n",
+			       srb->total_xfer_length, len);
+	}			       
+}
+
+
+/*
+ * Compute the next Scatter Gather list index and adjust its length
+ * and address if necessary; also compute virt_addr
+ */
+static void sg_update_list(struct ScsiReqBlk *srb, u32 left)
+{
+	u8 idx;
+	struct scatterlist *sg;
+	struct scsi_cmnd *cmd = srb->cmd;
+	int segment = cmd->use_sg;
+	u32 xferred = srb->total_xfer_length - left; /* bytes transfered */
+	struct SGentry *psge = srb->segment_x + srb->sg_index;
+	void **virt = srb->virt_map;
+
+	dprintkdbg(DBG_0,
+		"sg_update_list: Transfered %i of %i bytes, %i remain\n",
+		xferred, srb->total_xfer_length, left);
+	if (xferred == 0) {
+		/* nothing to update since we did not transfer any data */
+		return;
+	}
+
+	sg_verify_length(srb);
+	srb->total_xfer_length = left;	/* update remaining count */
+	for (idx = srb->sg_index; idx < srb->sg_count; idx++) {
+		if (xferred >= psge->length) {
+			/* Complete SG entries done */
+			xferred -= psge->length;
+		} else {
+			/* Partial SG entry done */
+			psge->length -= xferred;
+			psge->address += xferred;
+			srb->sg_index = idx;
+			pci_dma_sync_single_for_device(srb->dcb->
+					    acb->dev,
+					    srb->sg_bus_addr,
+					    SEGMENTX_LEN,
+					    PCI_DMA_TODEVICE);
+			break;
+		}
+		psge++;
+	}
+	sg_verify_length(srb);
+
+	/* we need the corresponding virtual address */
+	if (!segment) {
+		srb->virt_addr += xferred;
+		return;
+	}
+
+	/* We have to walk the scatterlist to find it */
+	sg = (struct scatterlist *)cmd->request_buffer;
+	idx = 0;
+	while (segment--) {
+		unsigned long mask =
+		    ~((unsigned long)sg->length - 1) & PAGE_MASK;
+		if ((sg_dma_address(sg) & mask) == (psge->address & mask)) {
+			srb->virt_addr = virt[idx] + (psge->address & ~PAGE_MASK);
+			return;
+		}
+		++sg;
+		++idx;
+	}
+
+	dprintkl(KERN_ERR, "sg_update_list: sg_to_virt failed\n");
+	srb->virt_addr = NULL;
+}
+
+
+/*
+ * We have transfered a single byte (PIO mode?) and need to update
+ * the count of bytes remaining (total_xfer_length) and update the sg
+ * entry to either point to next byte in the current sg entry, or of
+ * already at the end to point to the start of the next sg entry
+ */
+static void sg_subtract_one(struct ScsiReqBlk *srb)
+{
+	srb->total_xfer_length--;
+	srb->segment_x[srb->sg_index].length--;
+	if (srb->total_xfer_length &&
+	    !srb->segment_x[srb->sg_index].length) {
+		if (debug_enabled(DBG_PIO))
+			printk(" (next segment)");
+		srb->sg_index++;
+		sg_update_list(srb, srb->total_xfer_length);
+	}
+}
+
+
+/* 
+ * cleanup_after_transfer
+ * 
+ * Makes sure, DMA and SCSI engine are empty, after the transfer has finished
+ * KG: Currently called from  StatusPhase1 ()
+ * Should probably also be called from other places
+ * Best might be to call it in DataXXPhase0, if new phase will differ 
+ */
+static void cleanup_after_transfer(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
+{
+	/*DC395x_write8 (TRM_S1040_DMA_STATUS, FORCEDMACOMP); */
+	if (DC395x_read16(acb, TRM_S1040_DMA_COMMAND) & 0x0001) {	/* read */
+		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
+			clear_fifo(acb, "cleanup/in");
+		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
+			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+	} else {		/* write */
+		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80))
+			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+		if (!(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x40))
+			clear_fifo(acb, "cleanup/out");
+	}
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);
+}
+
+
+/*
+ * Those no of bytes will be transfered w/ PIO through the SCSI FIFO
+ * Seems to be needed for unknown reasons; could be a hardware bug :-(
+ */
+#define DC395x_LASTPIO 4
+
+
+static void data_out_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	u16 scsi_status = *pscsi_status;
+	u32 d_left_counter = 0;
+	dprintkdbg(DBG_0, "data_out_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+
+	/*
+	 * KG: We need to drain the buffers before we draw any conclusions!
+	 * This means telling the DMA to push the rest into SCSI, telling
+	 * SCSI to push the rest to the bus.
+	 * However, the device might have been the one to stop us (phase
+	 * change), and the data in transit just needs to be accounted so
+	 * it can be retransmitted.)
+	 */
+	/* 
+	 * KG: Stop DMA engine pushing more data into the SCSI FIFO
+	 * If we need more data, the DMA SG list will be freshly set up, anyway
+	 */
+	dprintkdbg(DBG_PIO, "data_out_phase0: "
+		"DMA{fifcnt=0x%02x fifostat=0x%02x} "
+		"SCSI{fifocnt=0x%02x cnt=0x%06x status=0x%04x} total=0x%06x\n",
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+		DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+		DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+		DC395x_read32(acb, TRM_S1040_SCSI_COUNTER), scsi_status,
+		srb->total_xfer_length);
+	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO);
+
+	if (!(srb->state & SRB_XFERPAD)) {
+		if (scsi_status & PARITYERROR)
+			srb->status |= PARITY_ERROR;
+
+		/*
+		 * KG: Right, we can't just rely on the SCSI_COUNTER, because this
+		 * is the no of bytes it got from the DMA engine not the no it 
+		 * transferred successfully to the device. (And the difference could
+		 * be as much as the FIFO size, I guess ...)
+		 */
+		if (!(scsi_status & SCSIXFERDONE)) {
+			/*
+			 * when data transfer from DMA FIFO to SCSI FIFO
+			 * if there was some data left in SCSI FIFO
+			 */
+			d_left_counter =
+			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
+				  0x1F);
+			if (dcb->sync_period & WIDE_SYNC)
+				d_left_counter <<= 1;
+
+			dprintkdbg(DBG_KG, "data_out_phase0: FIFO contains %i %s\n"
+				"SCSI{fifocnt=0x%02x cnt=0x%08x} "
+				"DMA{fifocnt=0x%04x cnt=0x%02x ctr=0x%08x}\n",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+				(dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+				DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+				DC395x_read32(acb, TRM_S1040_DMA_CXCNT));
+		}
+		/*
+		 * calculate all the residue data that not yet transfered
+		 * SCSI transfer counter + left in SCSI FIFO data
+		 *
+		 * .....TRM_S1040_SCSI_COUNTER (24bits)
+		 * The counter always decrement by one for every SCSI byte transfer.
+		 * .....TRM_S1040_SCSI_FIFOCNT ( 5bits)
+		 * The counter is SCSI FIFO offset counter (in units of bytes or! words)
+		 */
+		if (srb->total_xfer_length > DC395x_LASTPIO)
+			d_left_counter +=
+			    DC395x_read32(acb, TRM_S1040_SCSI_COUNTER);
+
+		/* Is this a good idea? */
+		/*clear_fifo(acb, "DOP1"); */
+		/* KG: What is this supposed to be useful for? WIDE padding stuff? */
+		if (d_left_counter == 1 && dcb->sync_period & WIDE_SYNC
+		    && srb->cmd->request_bufflen % 2) {
+			d_left_counter = 0;
+			dprintkl(KERN_INFO,
+				"data_out_phase0: Discard 1 byte (0x%02x)\n",
+				scsi_status);
+		}
+		/*
+		 * KG: Oops again. Same thinko as above: The SCSI might have been
+		 * faster than the DMA engine, so that it ran out of data.
+		 * In that case, we have to do just nothing! 
+		 * But: Why the interrupt: No phase change. No XFERCNT_2_ZERO. Or?
+		 */
+		/*
+		 * KG: This is nonsense: We have been WRITING data to the bus
+		 * If the SCSI engine has no bytes left, how should the DMA engine?
+		 */
+		if (d_left_counter == 0) {
+			srb->total_xfer_length = 0;
+		} else {
+			/*
+			 * if transfer not yet complete
+			 * there were some data residue in SCSI FIFO or
+			 * SCSI transfer counter not empty
+			 */
+			long oldxferred =
+			    srb->total_xfer_length - d_left_counter;
+			const int diff =
+			    (dcb->sync_period & WIDE_SYNC) ? 2 : 1;
+			sg_update_list(srb, d_left_counter);
+			/* KG: Most ugly hack! Apparently, this works around a chip bug */
+			if ((srb->segment_x[srb->sg_index].length ==
+			     diff && srb->cmd->use_sg)
+			    || ((oldxferred & ~PAGE_MASK) ==
+				(PAGE_SIZE - diff))
+			    ) {
+				dprintkl(KERN_INFO, "data_out_phase0: "
+					"Work around chip bug (%i)?\n", diff);
+				d_left_counter =
+				    srb->total_xfer_length - diff;
+				sg_update_list(srb, d_left_counter);
+				/*srb->total_xfer_length -= diff; */
+				/*srb->virt_addr += diff; */
+				/*if (srb->cmd->use_sg) */
+				/*      srb->sg_index++; */
+			}
+		}
+	}
+	if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) {
+		cleanup_after_transfer(acb, srb);
+	}
+}
+
+
+static void data_out_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "data_out_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	clear_fifo(acb, "data_out_phase1");
+	/* do prepare before transfer when data out phase */
+	data_io_transfer(acb, srb, XFERDATAOUT);
+}
+
+
+static void data_in_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	u16 scsi_status = *pscsi_status;
+	u32 d_left_counter = 0;
+	dprintkdbg(DBG_0, "data_in_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+
+	/*
+	 * KG: DataIn is much more tricky than DataOut. When the device is finished
+	 * and switches to another phase, the SCSI engine should be finished too.
+	 * But: There might still be bytes left in its FIFO to be fetched by the DMA
+	 * engine and transferred to memory.
+	 * We should wait for the FIFOs to be emptied by that (is there any way to 
+	 * enforce this?) and then stop the DMA engine, because it might think, that
+	 * there are more bytes to follow. Yes, the device might disconnect prior to
+	 * having all bytes transferred! 
+	 * Also we should make sure that all data from the DMA engine buffer's really
+	 * made its way to the system memory! Some documentation on this would not
+	 * seem to be a bad idea, actually.
+	 */
+	if (!(srb->state & SRB_XFERPAD)) {
+		if (scsi_status & PARITYERROR) {
+			dprintkl(KERN_INFO, "data_in_phase0: (pid#%li) "
+				"Parity Error\n", srb->cmd->pid);
+			srb->status |= PARITY_ERROR;
+		}
+		/*
+		 * KG: We should wait for the DMA FIFO to be empty ...
+		 * but: it would be better to wait first for the SCSI FIFO and then the
+		 * the DMA FIFO to become empty? How do we know, that the device not already
+		 * sent data to the FIFO in a MsgIn phase, eg.?
+		 */
+		if (!(DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT) & 0x80)) {
+#if 0
+			int ctr = 6000000;
+			dprintkl(KERN_DEBUG,
+				"DIP0: Wait for DMA FIFO to flush ...\n");
+			/*DC395x_write8  (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */
+			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */
+			/*DC395x_write8  (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */
+			while (!
+			       (DC395x_read16(acb, TRM_S1040_DMA_FIFOSTAT) &
+				0x80) && --ctr);
+			if (ctr < 6000000 - 1)
+				dprintkl(KERN_DEBUG
+				       "DIP0: Had to wait for DMA ...\n");
+			if (!ctr)
+				dprintkl(KERN_ERR,
+				       "Deadlock in DIP0 waiting for DMA FIFO empty!!\n");
+			/*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */
+#endif
+			dprintkdbg(DBG_KG, "data_in_phase0: "
+				"DMA{fifocnt=0x%02x fifostat=0x%02x}\n",
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+				DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT));
+		}
+		/* Now: Check remainig data: The SCSI counters should tell us ... */
+		d_left_counter = DC395x_read32(acb, TRM_S1040_SCSI_COUNTER)
+		    + ((DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f)
+		       << ((srb->dcb->sync_period & WIDE_SYNC) ? 1 :
+			   0));
+		dprintkdbg(DBG_KG, "data_in_phase0: "
+			"SCSI{fifocnt=0x%02x%s ctr=0x%08x} "
+			"DMA{fifocnt=0x%02x fifostat=0x%02x ctr=0x%08x} "
+			"Remain{totxfer=%i scsi_fifo+ctr=%i}\n",
+			DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT),
+			(srb->dcb->sync_period & WIDE_SYNC) ? "words" : "bytes",
+			DC395x_read32(acb, TRM_S1040_SCSI_COUNTER),
+			DC395x_read8(acb, TRM_S1040_DMA_FIFOCNT),
+			DC395x_read8(acb, TRM_S1040_DMA_FIFOSTAT),
+			DC395x_read32(acb, TRM_S1040_DMA_CXCNT),
+			srb->total_xfer_length, d_left_counter);
+#if DC395x_LASTPIO
+		/* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */
+		if (d_left_counter
+		    && srb->total_xfer_length <= DC395x_LASTPIO) {
+			/*u32 addr = (srb->segment_x[srb->sg_index].address); */
+			/*sg_update_list (srb, d_left_counter); */
+			dprintkdbg(DBG_PIO, "data_in_phase0: PIO (%i %s) to "
+				"%p for remaining %i bytes:",
+				DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) & 0x1f,
+				(srb->dcb->sync_period & WIDE_SYNC) ?
+				    "words" : "bytes",
+				srb->virt_addr,
+				srb->total_xfer_length);
+			if (srb->dcb->sync_period & WIDE_SYNC)
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
+					      CFG2_WIDEFIFO);
+			while (DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) != 0x40) {
+				u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+				*(srb->virt_addr)++ = byte;
+				if (debug_enabled(DBG_PIO))
+					printk(" %02x", byte);
+				d_left_counter--;
+				sg_subtract_one(srb);
+			}
+			if (srb->dcb->sync_period & WIDE_SYNC) {
+#if 1
+                /* Read the last byte ... */
+				if (srb->total_xfer_length > 0) {
+					u8 byte = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+					*(srb->virt_addr)++ = byte;
+					srb->total_xfer_length--;
+					if (debug_enabled(DBG_PIO))
+						printk(" %02x", byte);
+				}
+#endif
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+			}
+			/*printk(" %08x", *(u32*)(bus_to_virt (addr))); */
+			/*srb->total_xfer_length = 0; */
+			if (debug_enabled(DBG_PIO))
+				printk("\n");
+		}
+#endif				/* DC395x_LASTPIO */
+
+#if 0
+		/*
+		 * KG: This was in DATAOUT. Does it also belong here?
+		 * Nobody seems to know what counter and fifo_cnt count exactly ...
+		 */
+		if (!(scsi_status & SCSIXFERDONE)) {
+			/*
+			 * when data transfer from DMA FIFO to SCSI FIFO
+			 * if there was some data left in SCSI FIFO
+			 */
+			d_left_counter =
+			    (u32)(DC395x_read8(acb, TRM_S1040_SCSI_FIFOCNT) &
+				  0x1F);
+			if (srb->dcb->sync_period & WIDE_SYNC)
+				d_left_counter <<= 1;
+			/*
+			 * if WIDE scsi SCSI FIFOCNT unit is word !!!
+			 * so need to *= 2
+			 * KG: Seems to be correct ...
+			 */
+		}
+#endif
+		/* KG: This should not be needed any more! */
+		if (d_left_counter == 0
+		    || (scsi_status & SCSIXFERCNT_2_ZERO)) {
+#if 0
+			int ctr = 6000000;
+			u8 TempDMAstatus;
+			do {
+				TempDMAstatus =
+				    DC395x_read8(acb, TRM_S1040_DMA_STATUS);
+			} while (!(TempDMAstatus & DMAXFERCOMP) && --ctr);
+			if (!ctr)
+				dprintkl(KERN_ERR,
+				       "Deadlock in DataInPhase0 waiting for DMA!!\n");
+			srb->total_xfer_length = 0;
+#endif
+			srb->total_xfer_length = d_left_counter;
+		} else {	/* phase changed */
+			/*
+			 * parsing the case:
+			 * when a transfer not yet complete 
+			 * but be disconnected by target
+			 * if transfer not yet complete
+			 * there were some data residue in SCSI FIFO or
+			 * SCSI transfer counter not empty
+			 */
+			sg_update_list(srb, d_left_counter);
+		}
+	}
+	/* KG: The target may decide to disconnect: Empty FIFO before! */
+	if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) {
+		cleanup_after_transfer(acb, srb);
+	}
+}
+
+
+static void data_in_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "data_in_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	data_io_transfer(acb, srb, XFERDATAIN);
+}
+
+
+static void data_io_transfer(struct AdapterCtlBlk *acb, 
+		struct ScsiReqBlk *srb, u16 io_dir)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	u8 bval;
+	dprintkdbg(DBG_0,
+		"data_io_transfer: (pid#%li) <%02i-%i> %c len=%i, sg=(%i/%i)\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun,
+		((io_dir & DMACMD_DIR) ? 'r' : 'w'),
+		srb->total_xfer_length, srb->sg_index, srb->sg_count);
+	if (srb == acb->tmp_srb)
+		dprintkl(KERN_ERR, "data_io_transfer: Using tmp_srb!\n");
+	if (srb->sg_index >= srb->sg_count) {
+		/* can't happen? out of bounds error */
+		return;
+	}
+
+	if (srb->total_xfer_length > DC395x_LASTPIO) {
+		u8 dma_status = DC395x_read8(acb, TRM_S1040_DMA_STATUS);
+		/*
+		 * KG: What should we do: Use SCSI Cmd 0x90/0x92?
+		 * Maybe, even ABORTXFER would be appropriate
+		 */
+		if (dma_status & XFERPENDING) {
+			dprintkl(KERN_DEBUG, "data_io_transfer: Xfer pending! "
+				"Expect trouble!\n");
+			dump_register_info(acb, dcb, srb);
+			DC395x_write8(acb, TRM_S1040_DMA_CONTROL, CLRXFIFO);
+		}
+		/* clear_fifo(acb, "IO"); */
+		/* 
+		 * load what physical address of Scatter/Gather list table
+		 * want to be transfer
+		 */
+		srb->state |= SRB_DATA_XFER;
+		DC395x_write32(acb, TRM_S1040_DMA_XHIGHADDR, 0);
+		if (srb->cmd->use_sg) {	/* with S/G */
+			io_dir |= DMACMD_SG;
+			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
+				       srb->sg_bus_addr +
+				       sizeof(struct SGentry) *
+				       srb->sg_index);
+			/* load how many bytes in the sg list table */
+			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
+				       ((u32)(srb->sg_count -
+					      srb->sg_index) << 3));
+		} else {	/* without S/G */
+			io_dir &= ~DMACMD_SG;
+			DC395x_write32(acb, TRM_S1040_DMA_XLOWADDR,
+				       srb->segment_x[0].address);
+			DC395x_write32(acb, TRM_S1040_DMA_XCNT,
+				       srb->segment_x[0].length);
+		}
+		/* load total transfer length (24bits) max value 16Mbyte */
+		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
+			       srb->total_xfer_length);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		if (io_dir & DMACMD_DIR) {	/* read */
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_DMA_IN);
+			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
+		} else {
+			DC395x_write16(acb, TRM_S1040_DMA_COMMAND, io_dir);
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_DMA_OUT);
+		}
+
+	}
+#if DC395x_LASTPIO
+	else if (srb->total_xfer_length > 0) {	/* The last four bytes: Do PIO */
+		/* 
+		 * load what physical address of Scatter/Gather list table
+		 * want to be transfer
+		 */
+		srb->state |= SRB_DATA_XFER;
+		/* load total transfer length (24bits) max value 16Mbyte */
+		DC395x_write32(acb, TRM_S1040_SCSI_COUNTER,
+			       srb->total_xfer_length);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		if (io_dir & DMACMD_DIR) {	/* read */
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+				      SCMD_FIFO_IN);
+		} else {	/* write */
+			int ln = srb->total_xfer_length;
+			if (srb->dcb->sync_period & WIDE_SYNC)
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
+				     CFG2_WIDEFIFO);
+			dprintkdbg(DBG_PIO,
+				"data_io_transfer: PIO %i bytes from %p:",
+				srb->total_xfer_length, srb->virt_addr);
+
+			while (srb->total_xfer_length) {
+				if (debug_enabled(DBG_PIO))
+					printk(" %02x", (unsigned char) *(srb->virt_addr));
+
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 
+				     *(srb->virt_addr)++);
+
+				sg_subtract_one(srb);
+			}
+			if (srb->dcb->sync_period & WIDE_SYNC) {
+				if (ln % 2) {
+					DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 0);
+					if (debug_enabled(DBG_PIO))
+						printk(" |00");
+				}
+				DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+			}
+			/*DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, ln); */
+			if (debug_enabled(DBG_PIO))
+				printk("\n");
+			DC395x_write8(acb, TRM_S1040_SCSI_COMMAND,
+					  SCMD_FIFO_OUT);
+		}
+	}
+#endif				/* DC395x_LASTPIO */
+	else {		/* xfer pad */
+		u8 data = 0, data2 = 0;
+		if (srb->sg_count) {
+			srb->adapter_status = H_OVER_UNDER_RUN;
+			srb->status |= OVER_RUN;
+		}
+		/*
+		 * KG: despite the fact that we are using 16 bits I/O ops
+		 * the SCSI FIFO is only 8 bits according to the docs
+		 * (we can set bit 1 in 0x8f to serialize FIFO access ...)
+		 */
+		if (dcb->sync_period & WIDE_SYNC) {
+			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 2);
+			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2,
+				      CFG2_WIDEFIFO);
+			if (io_dir & DMACMD_DIR) {
+				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+				data2 = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+			} else {
+				/* Danger, Robinson: If you find KGs
+				 * scattered over the wide disk, the driver
+				 * or chip is to blame :-( */
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'G');
+			}
+			DC395x_write8(acb, TRM_S1040_SCSI_CONFIG2, 0);
+		} else {
+			DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
+			/* Danger, Robinson: If you find a collection of Ks on your disk
+			 * something broke :-( */
+			if (io_dir & DMACMD_DIR)
+				data = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+			else
+				DC395x_write8(acb, TRM_S1040_SCSI_FIFO, 'K');
+		}
+		srb->state |= SRB_XFERPAD;
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		/* SCSI command */
+		bval = (io_dir & DMACMD_DIR) ? SCMD_FIFO_IN : SCMD_FIFO_OUT;
+		DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, bval);
+	}
+}
+
+
+static void status_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "status_phase0: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	srb->target_status = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+	srb->end_message = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);	/* get message */
+	srb->state = SRB_COMPLETED;
+	*pscsi_status = PH_BUS_FREE;	/*.. initial phase */
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+
+static void status_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "status_phase1: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->cmd->device->id, srb->cmd->device->lun);
+	srb->state = SRB_STATUS;
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_COMP);
+}
+
+
+/* Check if the message is complete */
+static inline u8 msgin_completed(u8 * msgbuf, u32 len)
+{
+	if (*msgbuf == EXTENDED_MESSAGE) {
+		if (len < 2)
+			return 0;
+		if (len < msgbuf[1] + 2)
+			return 0;
+	} else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f)	/* two byte messages */
+		if (len < 2)
+			return 0;
+	return 1;
+}
+
+/* reject_msg */
+static inline void msgin_reject(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
+{
+	srb->msgout_buf[0] = MESSAGE_REJECT;
+	srb->msg_count = 1;
+	DC395x_ENABLE_MSGOUT;
+	srb->state &= ~SRB_MSGIN;
+	srb->state |= SRB_MSGOUT;
+	dprintkl(KERN_INFO, "msgin_reject: 0x%02x <%02i-%i>\n",
+		srb->msgin_buf[0],
+		srb->dcb->target_id, srb->dcb->target_lun);
+}
+
+
+static struct ScsiReqBlk *msgin_qtag(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb, u8 tag)
+{
+	struct ScsiReqBlk *srb = NULL;
+	struct ScsiReqBlk *i;
+	dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) tag=%i srb=%p\n",
+		   srb->cmd->pid, tag, srb);
+
+	if (!(dcb->tag_mask & (1 << tag)))
+		dprintkl(KERN_DEBUG,
+			"msgin_qtag: tag_mask=0x%08x does not reserve tag %i!\n",
+			dcb->tag_mask, tag);
+
+	if (list_empty(&dcb->srb_going_list))
+		goto mingx0;
+	list_for_each_entry(i, &dcb->srb_going_list, list) {
+		if (i->tag_number == tag) {
+			srb = i;
+			break;
+		}
+	}
+	if (!srb)
+		goto mingx0;
+
+	dprintkdbg(DBG_0, "msgin_qtag: (pid#%li) <%02i-%i>\n",
+		srb->cmd->pid, srb->dcb->target_id, srb->dcb->target_lun);
+	if (dcb->flag & ABORT_DEV_) {
+		/*srb->state = SRB_ABORT_SENT; */
+		enable_msgout_abort(acb, srb);
+	}
+
+	if (!(srb->state & SRB_DISCONNECT))
+		goto mingx0;
+
+	memcpy(srb->msgin_buf, dcb->active_srb->msgin_buf, acb->msg_len);
+	srb->state |= dcb->active_srb->state;
+	srb->state |= SRB_DATA_XFER;
+	dcb->active_srb = srb;
+	/* How can we make the DORS happy? */
+	return srb;
+
+      mingx0:
+	srb = acb->tmp_srb;
+	srb->state = SRB_UNEXPECT_RESEL;
+	dcb->active_srb = srb;
+	srb->msgout_buf[0] = MSG_ABORT_TAG;
+	srb->msg_count = 1;
+	DC395x_ENABLE_MSGOUT;
+	dprintkl(KERN_DEBUG, "msgin_qtag: Unknown tag %i - abort\n", tag);
+	return srb;
+}
+
+
+static inline void reprogram_regs(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
+{
+	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);
+	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);
+	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);
+	set_xfer_rate(acb, dcb);
+}
+
+
+/* set async transfer mode */
+static void msgin_set_async(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	dprintkl(KERN_DEBUG, "msgin_set_async: No sync transfers <%02i-%i>\n",
+		dcb->target_id, dcb->target_lun);
+
+	dcb->sync_mode &= ~(SYNC_NEGO_ENABLE);
+	dcb->sync_mode |= SYNC_NEGO_DONE;
+	/*dcb->sync_period &= 0; */
+	dcb->sync_offset = 0;
+	dcb->min_nego_period = 200 >> 2;	/* 200ns <=> 5 MHz */
+	srb->state &= ~SRB_DO_SYNC_NEGO;
+	reprogram_regs(acb, dcb);
+	if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
+	    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
+		build_wdtr(acb, dcb, srb);
+		DC395x_ENABLE_MSGOUT;
+		dprintkdbg(DBG_0, "msgin_set_async(rej): Try WDTR anyway\n");
+	}
+}
+
+
+/* set sync transfer mode */
+static void msgin_set_sync(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	u8 bval;
+	int fact;
+	dprintkdbg(DBG_1, "msgin_set_sync: <%02i> Sync: %ins "
+		"(%02i.%01i MHz) Offset %i\n",
+		dcb->target_id, srb->msgin_buf[3] << 2,
+		(250 / srb->msgin_buf[3]),
+		((250 % srb->msgin_buf[3]) * 10) / srb->msgin_buf[3],
+		srb->msgin_buf[4]);
+
+	if (srb->msgin_buf[4] > 15)
+		srb->msgin_buf[4] = 15;
+	if (!(dcb->dev_mode & NTC_DO_SYNC_NEGO))
+		dcb->sync_offset = 0;
+	else if (dcb->sync_offset == 0)
+		dcb->sync_offset = srb->msgin_buf[4];
+	if (srb->msgin_buf[4] > dcb->sync_offset)
+		srb->msgin_buf[4] = dcb->sync_offset;
+	else
+		dcb->sync_offset = srb->msgin_buf[4];
+	bval = 0;
+	while (bval < 7 && (srb->msgin_buf[3] > clock_period[bval]
+			    || dcb->min_nego_period >
+			    clock_period[bval]))
+		bval++;
+	if (srb->msgin_buf[3] < clock_period[bval])
+		dprintkl(KERN_INFO,
+			"msgin_set_sync: Increase sync nego period to %ins\n",
+			clock_period[bval] << 2);
+	srb->msgin_buf[3] = clock_period[bval];
+	dcb->sync_period &= 0xf0;
+	dcb->sync_period |= ALT_SYNC | bval;
+	dcb->min_nego_period = srb->msgin_buf[3];
+
+	if (dcb->sync_period & WIDE_SYNC)
+		fact = 500;
+	else
+		fact = 250;
+
+	dprintkl(KERN_INFO,
+		"Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n",
+		dcb->target_id, (fact == 500) ? "Wide16" : "",
+		dcb->min_nego_period << 2, dcb->sync_offset,
+		(fact / dcb->min_nego_period),
+		((fact % dcb->min_nego_period) * 10 +
+		dcb->min_nego_period / 2) / dcb->min_nego_period);
+
+	if (!(srb->state & SRB_DO_SYNC_NEGO)) {
+		/* Reply with corrected SDTR Message */
+		dprintkl(KERN_DEBUG, "msgin_set_sync: answer w/%ins %i\n",
+			srb->msgin_buf[3] << 2, srb->msgin_buf[4]);
+
+		memcpy(srb->msgout_buf, srb->msgin_buf, 5);
+		srb->msg_count = 5;
+		DC395x_ENABLE_MSGOUT;
+		dcb->sync_mode |= SYNC_NEGO_DONE;
+	} else {
+		if ((dcb->sync_mode & WIDE_NEGO_ENABLE)
+		    && !(dcb->sync_mode & WIDE_NEGO_DONE)) {
+			build_wdtr(acb, dcb, srb);
+			DC395x_ENABLE_MSGOUT;
+			dprintkdbg(DBG_0, "msgin_set_sync: Also try WDTR\n");
+		}
+	}
+	srb->state &= ~SRB_DO_SYNC_NEGO;
+	dcb->sync_mode |= SYNC_NEGO_DONE | SYNC_NEGO_ENABLE;
+
+	reprogram_regs(acb, dcb);
+}
+
+
+static inline void msgin_set_nowide(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	dprintkdbg(DBG_1, "msgin_set_nowide: <%02i>\n", dcb->target_id);
+
+	dcb->sync_period &= ~WIDE_SYNC;
+	dcb->sync_mode &= ~(WIDE_NEGO_ENABLE);
+	dcb->sync_mode |= WIDE_NEGO_DONE;
+	srb->state &= ~SRB_DO_WIDE_NEGO;
+	reprogram_regs(acb, dcb);
+	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
+	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
+		build_sdtr(acb, dcb, srb);
+		DC395x_ENABLE_MSGOUT;
+		dprintkdbg(DBG_0, "msgin_set_nowide: Rejected. Try SDTR anyway\n");
+	}
+}
+
+static void msgin_set_wide(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	struct DeviceCtlBlk *dcb = srb->dcb;
+	u8 wide = (dcb->dev_mode & NTC_DO_WIDE_NEGO
+		   && acb->config & HCC_WIDE_CARD) ? 1 : 0;
+	dprintkdbg(DBG_1, "msgin_set_wide: <%02i>\n", dcb->target_id);
+
+	if (srb->msgin_buf[3] > wide)
+		srb->msgin_buf[3] = wide;
+	/* Completed */
+	if (!(srb->state & SRB_DO_WIDE_NEGO)) {
+		dprintkl(KERN_DEBUG,
+			"msgin_set_wide: Wide nego initiated <%02i>\n",
+			dcb->target_id);
+		memcpy(srb->msgout_buf, srb->msgin_buf, 4);
+		srb->msg_count = 4;
+		srb->state |= SRB_DO_WIDE_NEGO;
+		DC395x_ENABLE_MSGOUT;
+	}
+
+	dcb->sync_mode |= (WIDE_NEGO_ENABLE | WIDE_NEGO_DONE);
+	if (srb->msgin_buf[3] > 0)
+		dcb->sync_period |= WIDE_SYNC;
+	else
+		dcb->sync_period &= ~WIDE_SYNC;
+	srb->state &= ~SRB_DO_WIDE_NEGO;
+	/*dcb->sync_mode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */
+	dprintkdbg(DBG_1,
+		"msgin_set_wide: Wide (%i bit) negotiated <%02i>\n",
+		(8 << srb->msgin_buf[3]), dcb->target_id);
+	reprogram_regs(acb, dcb);
+	if ((dcb->sync_mode & SYNC_NEGO_ENABLE)
+	    && !(dcb->sync_mode & SYNC_NEGO_DONE)) {
+		build_sdtr(acb, dcb, srb);
+		DC395x_ENABLE_MSGOUT;
+		dprintkdbg(DBG_0, "msgin_set_wide: Also try SDTR.\n");
+	}
+}
+
+
+/*
+ * extended message codes:
+ *
+ *	code	description
+ *
+ *	02h	Reserved
+ *	00h	MODIFY DATA  POINTER
+ *	01h	SYNCHRONOUS DATA TRANSFER REQUEST
+ *	03h	WIDE DATA TRANSFER REQUEST
+ *   04h - 7Fh	Reserved
+ *   80h - FFh	Vendor specific
+ */
+static void msgin_phase0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
+	dprintkdbg(DBG_0, "msgin_phase0: (pid#%li)\n", srb->cmd->pid);
+
+	srb->msgin_buf[acb->msg_len++] = DC395x_read8(acb, TRM_S1040_SCSI_FIFO);
+	if (msgin_completed(srb->msgin_buf, acb->msg_len)) {
+		/* Now eval the msg */
+		switch (srb->msgin_buf[0]) {
+		case DISCONNECT:
+			srb->state = SRB_DISCONNECT;
+			break;
+
+		case SIMPLE_QUEUE_TAG:
+		case HEAD_OF_QUEUE_TAG:
+		case ORDERED_QUEUE_TAG:
+			srb =
+			    msgin_qtag(acb, dcb,
+					      srb->msgin_buf[1]);
+			break;
+
+		case MESSAGE_REJECT:
+			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL,
+				       DO_CLRATN | DO_DATALATCH);
+			/* A sync nego message was rejected ! */
+			if (srb->state & SRB_DO_SYNC_NEGO) {
+				msgin_set_async(acb, srb);
+				break;
+			}
+			/* A wide nego message was rejected ! */
+			if (srb->state & SRB_DO_WIDE_NEGO) {
+				msgin_set_nowide(acb, srb);
+				break;
+			}
+			enable_msgout_abort(acb, srb);
+			/*srb->state |= SRB_ABORT_SENT */
+			break;
+
+		case EXTENDED_MESSAGE:
+			/* SDTR */
+			if (srb->msgin_buf[1] == 3
+			    && srb->msgin_buf[2] == EXTENDED_SDTR) {
+				msgin_set_sync(acb, srb);
+				break;
+			}
+			/* WDTR */
+			if (srb->msgin_buf[1] == 2
+			    && srb->msgin_buf[2] == EXTENDED_WDTR
+			    && srb->msgin_buf[3] <= 2) { /* sanity check ... */
+				msgin_set_wide(acb, srb);
+				break;
+			}
+			msgin_reject(acb, srb);
+			break;
+
+		case MSG_IGNOREWIDE:
+			/* Discard  wide residual */
+			dprintkdbg(DBG_0, "msgin_phase0: Ignore Wide Residual!\n");
+			break;
+
+		case COMMAND_COMPLETE:
+			/* nothing has to be done */
+			break;
+
+		case SAVE_POINTERS:
+			/*
+			 * SAVE POINTER may be ignored as we have the struct
+			 * ScsiReqBlk* associated with the scsi command.
+			 */
+			dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+				"SAVE POINTER rem=%i Ignore\n",
+				srb->cmd->pid, srb->total_xfer_length);
+			break;
+
+		case RESTORE_POINTERS:
+			dprintkdbg(DBG_0, "msgin_phase0: RESTORE POINTER. Ignore\n");
+			break;
+
+		case ABORT:
+			dprintkdbg(DBG_0, "msgin_phase0: (pid#%li) "
+				"<%02i-%i> ABORT msg\n",
+				srb->cmd->pid, dcb->target_id,
+				dcb->target_lun);
+			dcb->flag |= ABORT_DEV_;
+			enable_msgout_abort(acb, srb);
+			break;
+
+		default:
+			/* reject unknown messages */
+			if (srb->msgin_buf[0] & IDENTIFY_BASE) {
+				dprintkdbg(DBG_0, "msgin_phase0: Identify msg\n");
+				srb->msg_count = 1;
+				srb->msgout_buf[0] = dcb->identify_msg;
+				DC395x_ENABLE_MSGOUT;
+				srb->state |= SRB_MSGOUT;
+				/*break; */
+			}
+			msgin_reject(acb, srb);
+		}
+
+		/* Clear counter and MsgIn state */
+		srb->state &= ~SRB_MSGIN;
+		acb->msg_len = 0;
+	}
+	*pscsi_status = PH_BUS_FREE;
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important ... you know! */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+
+static void msgin_phase1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+	dprintkdbg(DBG_0, "msgin_phase1: (pid#%li)\n", srb->cmd->pid);
+	clear_fifo(acb, "msgin_phase1");
+	DC395x_write32(acb, TRM_S1040_SCSI_COUNTER, 1);
+	if (!(srb->state & SRB_MSGIN)) {
+		srb->state &= ~SRB_DISCONNECT;
+		srb->state |= SRB_MSGIN;
+	}
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+	/* SCSI command */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_FIFO_IN);
+}
+
+
+static void nop0(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+}
+
+
+static void nop1(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb,
+		u16 *pscsi_status)
+{
+}
+
+
+static void set_xfer_rate(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb)
+{
+	struct DeviceCtlBlk *i;
+
+	/* set all lun device's  period, offset */
+	if (dcb->identify_msg & 0x07)
+		return;
+
+	if (acb->scan_devices) {
+		current_sync_offset = dcb->sync_offset;
+		return;
+	}
+
+	list_for_each_entry(i, &acb->dcb_list, list)
+		if (i->target_id == dcb->target_id) {
+			i->sync_period = dcb->sync_period;
+			i->sync_offset = dcb->sync_offset;
+			i->sync_mode = dcb->sync_mode;
+			i->min_nego_period = dcb->min_nego_period;
+		}
+}
+
+
+static void disconnect(struct AdapterCtlBlk *acb)
+{
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
+	struct ScsiReqBlk *srb;
+
+	if (!dcb) {
+		dprintkl(KERN_ERR, "disconnect: No such device\n");
+		udelay(500);
+		/* Suspend queue for a while */
+		acb->scsi_host->last_reset =
+		    jiffies + HZ / 2 +
+		    HZ * acb->eeprom.delay_time;
+		clear_fifo(acb, "disconnectEx");
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
+		return;
+	}
+	srb = dcb->active_srb;
+	acb->active_dcb = NULL;
+	dprintkdbg(DBG_0, "disconnect: (pid#%li)\n", srb->cmd->pid);
+
+	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
+	clear_fifo(acb, "disconnect");
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT);
+	if (srb->state & SRB_UNEXPECT_RESEL) {
+		dprintkl(KERN_ERR,
+			"disconnect: Unexpected reselection <%02i-%i>\n",
+			dcb->target_id, dcb->target_lun);
+		srb->state = 0;
+		waiting_process_next(acb);
+	} else if (srb->state & SRB_ABORT_SENT) {
+		dcb->flag &= ~ABORT_DEV_;
+		acb->scsi_host->last_reset = jiffies + HZ / 2 + 1;
+		dprintkl(KERN_ERR, "disconnect: SRB_ABORT_SENT\n");
+		doing_srb_done(acb, DID_ABORT, srb->cmd, 1);
+		waiting_process_next(acb);
+	} else {
+		if ((srb->state & (SRB_START_ + SRB_MSGOUT))
+		    || !(srb->
+			 state & (SRB_DISCONNECT + SRB_COMPLETED))) {
+			/*
+			 * Selection time out 
+			 * SRB_START_ || SRB_MSGOUT || (!SRB_DISCONNECT && !SRB_COMPLETED)
+			 */
+			/* Unexp. Disc / Sel Timeout */
+			if (srb->state != SRB_START_
+			    && srb->state != SRB_MSGOUT) {
+				srb->state = SRB_READY;
+				dprintkl(KERN_DEBUG,
+					"disconnect: (pid#%li) Unexpected\n",
+					srb->cmd->pid);
+				srb->target_status = SCSI_STAT_SEL_TIMEOUT;
+				goto disc1;
+			} else {
+				/* Normal selection timeout */
+				dprintkdbg(DBG_KG, "disconnect: (pid#%li) "
+					"<%02i-%i> SelTO\n", srb->cmd->pid,
+					dcb->target_id, dcb->target_lun);
+				if (srb->retry_count++ > DC395x_MAX_RETRIES
+				    || acb->scan_devices) {
+					srb->target_status =
+					    SCSI_STAT_SEL_TIMEOUT;
+					goto disc1;
+				}
+				free_tag(dcb, srb);
+				srb_going_to_waiting_move(dcb, srb);
+				dprintkdbg(DBG_KG,
+					"disconnect: (pid#%li) Retry\n",
+					srb->cmd->pid);
+				waiting_set_timer(acb, HZ / 20);
+			}
+		} else if (srb->state & SRB_DISCONNECT) {
+			u8 bval = DC395x_read8(acb, TRM_S1040_SCSI_SIGNAL);
+			/*
+			 * SRB_DISCONNECT (This is what we expect!)
+			 */
+			if (bval & 0x40) {
+				dprintkdbg(DBG_0, "disconnect: SCSI bus stat "
+					" 0x%02x: ACK set! Other controllers?\n",
+					bval);
+				/* It could come from another initiator, therefore don't do much ! */
+			} else
+				waiting_process_next(acb);
+		} else if (srb->state & SRB_COMPLETED) {
+		      disc1:
+			/*
+			 ** SRB_COMPLETED
+			 */
+			free_tag(dcb, srb);
+			dcb->active_srb = NULL;
+			srb->state = SRB_FREE;
+			srb_done(acb, dcb, srb);
+		}
+	}
+}
+
+
+static void reselect(struct AdapterCtlBlk *acb)
+{
+	struct DeviceCtlBlk *dcb = acb->active_dcb;
+	struct ScsiReqBlk *srb = NULL;
+	u16 rsel_tar_lun_id;
+	u8 id, lun;
+	u8 arblostflag = 0;
+	dprintkdbg(DBG_0, "reselect: acb=%p\n", acb);
+
+	clear_fifo(acb, "reselect");
+	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */
+	/* Read Reselected Target ID and LUN */
+	rsel_tar_lun_id = DC395x_read16(acb, TRM_S1040_SCSI_TARGETID);
+	if (dcb) {		/* Arbitration lost but Reselection win */
+		srb = dcb->active_srb;
+		if (!srb) {
+			dprintkl(KERN_DEBUG, "reselect: Arb lost Resel won, "
+				"but active_srb == NULL\n");
+			DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+			return;
+		}
+		/* Why the if ? */
+		if (!acb->scan_devices) {
+			dprintkdbg(DBG_KG, "reselect: (pid#%li) <%02i-%i> "
+				"Arb lost but Resel win rsel=%i stat=0x%04x\n",
+				srb->cmd->pid, dcb->target_id,
+				dcb->target_lun, rsel_tar_lun_id,
+				DC395x_read16(acb, TRM_S1040_SCSI_STATUS));
+			arblostflag = 1;
+			/*srb->state |= SRB_DISCONNECT; */
+
+			srb->state = SRB_READY;
+			free_tag(dcb, srb);
+			srb_going_to_waiting_move(dcb, srb);
+			waiting_set_timer(acb, HZ / 20);
+
+			/* return; */
+		}
+	}
+	/* Read Reselected Target Id and LUN */
+	if (!(rsel_tar_lun_id & (IDENTIFY_BASE << 8)))
+		dprintkl(KERN_DEBUG, "reselect: Expects identify msg. "
+			"Got %i!\n", rsel_tar_lun_id);
+	id = rsel_tar_lun_id & 0xff;
+	lun = (rsel_tar_lun_id >> 8) & 7;
+	dcb = find_dcb(acb, id, lun);
+	if (!dcb) {
+		dprintkl(KERN_ERR, "reselect: From non existent device "
+			"<%02i-%i>\n", id, lun);
+		DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);	/* it's important for atn stop */
+		return;
+	}
+	acb->active_dcb = dcb;
+
+	if (!(dcb->dev_mode & NTC_DO_DISCONNECT))
+		dprintkl(KERN_DEBUG, "reselect: in spite of forbidden "
+			"disconnection? <%02i-%i>\n",
+			dcb->target_id, dcb->target_lun);
+
+	if (dcb->sync_mode & EN_TAG_QUEUEING /*&& !arblostflag */) {
+		srb = acb->tmp_srb;
+		dcb->active_srb = srb;
+	} else {
+		/* There can be only one! */
+		srb = dcb->active_srb;
+		if (!srb || !(srb->state & SRB_DISCONNECT)) {
+			/*
+			 * abort command
+			 */
+			dprintkl(KERN_DEBUG,
+				"reselect: w/o disconnected cmds <%02i-%i>\n",
+				dcb->target_id, dcb->target_lun);
+			srb = acb->tmp_srb;
+			srb->state = SRB_UNEXPECT_RESEL;
+			dcb->active_srb = srb;
+			enable_msgout_abort(acb, srb);
+		} else {
+			if (dcb->flag & ABORT_DEV_) {
+				/*srb->state = SRB_ABORT_SENT; */
+				enable_msgout_abort(acb, srb);
+			} else
+				srb->state = SRB_DATA_XFER;
+
+		}
+	}
+	srb->scsi_phase = PH_BUS_FREE;	/* initial phase */
+
+	/* Program HA ID, target ID, period and offset */
+	dprintkdbg(DBG_0, "reselect: select <%i>\n", dcb->target_id);
+	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);	/* host   ID */
+	DC395x_write8(acb, TRM_S1040_SCSI_TARGETID, dcb->target_id);		/* target ID */
+	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, dcb->sync_offset);		/* offset    */
+	DC395x_write8(acb, TRM_S1040_SCSI_SYNC, dcb->sync_period);		/* sync period, wide */
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_DATALATCH);		/* it's important for atn stop */
+	/* SCSI command */
+	DC395x_write8(acb, TRM_S1040_SCSI_COMMAND, SCMD_MSGACCEPT);
+}
+
+
+static inline u8 tagq_blacklist(char *name)
+{
+#ifndef DC395x_NO_TAGQ
+#if 0
+	u8 i;
+	for (i = 0; i < BADDEVCNT; i++)
+		if (memcmp(name, DC395x_baddevname1[i], 28) == 0)
+			return 1;
+#endif
+	return 0;
+#else
+	return 1;
+#endif
+}
+
+
+static void disc_tagq_set(struct DeviceCtlBlk *dcb, struct ScsiInqData *ptr)
+{
+	/* Check for SCSI format (ANSI and Response data format) */
+	if ((ptr->Vers & 0x07) >= 2 || (ptr->RDF & 0x0F) == 2) {
+		if ((ptr->Flags & SCSI_INQ_CMDQUEUE)
+		    && (dcb->dev_mode & NTC_DO_TAG_QUEUEING) &&
+		    /*(dcb->dev_mode & NTC_DO_DISCONNECT) */
+		    /* ((dcb->dev_type == TYPE_DISK) 
+		       || (dcb->dev_type == TYPE_MOD)) && */
+		    !tagq_blacklist(((char *)ptr) + 8)) {
+			if (dcb->max_command == 1)
+				dcb->max_command =
+				    dcb->acb->tag_max_num;
+			dcb->sync_mode |= EN_TAG_QUEUEING;
+			/*dcb->tag_mask = 0; */
+		} else
+			dcb->max_command = 1;
+	}
+}
+
+
+static void add_dev(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiInqData *ptr)
+{
+	u8 bval1 = ptr->DevType & SCSI_DEVTYPE;
+	dcb->dev_type = bval1;
+	/* if (bval1 == TYPE_DISK || bval1 == TYPE_MOD) */
+	disc_tagq_set(dcb, ptr);
+}
+
+
+/* unmap mapped pci regions from SRB */
+static void pci_unmap_srb(struct AdapterCtlBlk *acb, struct ScsiReqBlk *srb)
+{
+	struct scsi_cmnd *cmd = srb->cmd;
+	enum dma_data_direction dir = cmd->sc_data_direction;
+	if (cmd->use_sg && dir != PCI_DMA_NONE) {
+		int i;
+		/* unmap DC395x SG list */
+		dprintkdbg(DBG_SG, "pci_unmap_srb: list=%08x(%05x)\n",
+			srb->sg_bus_addr, SEGMENTX_LEN);
+		pci_unmap_single(acb->dev, srb->sg_bus_addr,
+				 SEGMENTX_LEN,
+				 PCI_DMA_TODEVICE);
+		dprintkdbg(DBG_SG, "pci_unmap_srb: segs=%i buffer=%p\n",
+			cmd->use_sg, cmd->request_buffer);
+		/* unmap the sg segments */
+		for (i = 0; i < srb->sg_count; i++)
+			kunmap(virt_to_page(srb->virt_map[i]));
+		pci_unmap_sg(acb->dev,
+			     (struct scatterlist *)cmd->request_buffer,
+			     cmd->use_sg, dir);
+	} else if (cmd->request_buffer && dir != PCI_DMA_NONE) {
+		dprintkdbg(DBG_SG, "pci_unmap_srb: buffer=%08x(%05x)\n",
+			srb->segment_x[0].address, cmd->request_bufflen);
+		pci_unmap_single(acb->dev, srb->segment_x[0].address,
+				 cmd->request_bufflen, dir);
+	}
+}
+
+
+/* unmap mapped pci sense buffer from SRB */
+static void pci_unmap_srb_sense(struct AdapterCtlBlk *acb,
+		struct ScsiReqBlk *srb)
+{
+	if (!(srb->flag & AUTO_REQSENSE))
+		return;
+	/* Unmap sense buffer */
+	dprintkdbg(DBG_SG, "pci_unmap_srb_sense: buffer=%08x\n",
+	       srb->segment_x[0].address);
+	pci_unmap_single(acb->dev, srb->segment_x[0].address,
+			 srb->segment_x[0].length, PCI_DMA_FROMDEVICE);
+	/* Restore SG stuff */
+	srb->total_xfer_length = srb->xferred;
+	srb->segment_x[0].address =
+	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address;
+	srb->segment_x[0].length =
+	    srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length;
+}
+
+
+/*
+ * Complete execution of a SCSI command
+ * Signal completion to the generic SCSI driver  
+ */
+static void srb_done(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	u8 tempcnt, status;
+	struct scsi_cmnd *cmd = srb->cmd;
+	struct ScsiInqData *ptr;
+	enum dma_data_direction dir = cmd->sc_data_direction;
+
+	if (cmd->use_sg) {
+		struct scatterlist* sg = (struct scatterlist *)cmd->request_buffer;
+		ptr = (struct ScsiInqData *)(srb->virt_map[0] + sg->offset);
+	} else {
+		ptr = (struct ScsiInqData *)(cmd->request_buffer);
+	}
+
+	dprintkdbg(DBG_1, "srb_done: (pid#%li) <%02i-%i>\n", srb->cmd->pid,
+		srb->cmd->device->id, srb->cmd->device->lun);
+	dprintkdbg(DBG_SG, "srb_done: srb=%p sg=%i(%i/%i) buf=%p addr=%p\n",
+		srb, cmd->use_sg, srb->sg_index, srb->sg_count,
+		cmd->request_buffer, ptr);
+	status = srb->target_status;
+	if (srb->flag & AUTO_REQSENSE) {
+		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE1\n");
+		pci_unmap_srb_sense(acb, srb);
+		/*
+		 ** target status..........................
+		 */
+		srb->flag &= ~AUTO_REQSENSE;
+		srb->adapter_status = 0;
+		srb->target_status = CHECK_CONDITION << 1;
+		if (debug_enabled(DBG_1)) {
+			switch (cmd->sense_buffer[2] & 0x0f) {
+			case NOT_READY:
+				dprintkl(KERN_DEBUG,
+				     "ReqSense: NOT_READY cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
+				     cmd->cmnd[0], dcb->target_id,
+				     dcb->target_lun, status, acb->scan_devices);
+				break;
+			case UNIT_ATTENTION:
+				dprintkl(KERN_DEBUG,
+				     "ReqSense: UNIT_ATTENTION cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
+				     cmd->cmnd[0], dcb->target_id,
+				     dcb->target_lun, status, acb->scan_devices);
+				break;
+			case ILLEGAL_REQUEST:
+				dprintkl(KERN_DEBUG,
+				     "ReqSense: ILLEGAL_REQUEST cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
+				     cmd->cmnd[0], dcb->target_id,
+				     dcb->target_lun, status, acb->scan_devices);
+				break;
+			case MEDIUM_ERROR:
+				dprintkl(KERN_DEBUG,
+				     "ReqSense: MEDIUM_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
+				     cmd->cmnd[0], dcb->target_id,
+				     dcb->target_lun, status, acb->scan_devices);
+				break;
+			case HARDWARE_ERROR:
+				dprintkl(KERN_DEBUG,
+				     "ReqSense: HARDWARE_ERROR cmnd=0x%02x <%02i-%i> stat=%i scan=%i ",
+				     cmd->cmnd[0], dcb->target_id,
+				     dcb->target_lun, status, acb->scan_devices);
+				break;
+			}
+			if (cmd->sense_buffer[7] >= 6)
+				printk("sense=0x%02x ASC=0x%02x ASCQ=0x%02x "
+					"(0x%08x 0x%08x)\n",
+					cmd->sense_buffer[2], cmd->sense_buffer[12],
+					cmd->sense_buffer[13],
+					*((unsigned int *)(cmd->sense_buffer + 3)),
+					*((unsigned int *)(cmd->sense_buffer + 8)));
+			else
+				printk("sense=0x%02x No ASC/ASCQ (0x%08x)\n",
+					cmd->sense_buffer[2],
+					*((unsigned int *)(cmd->sense_buffer + 3)));
+		}
+
+		if (status == (CHECK_CONDITION << 1)) {
+			cmd->result = DID_BAD_TARGET << 16;
+			goto ckc_e;
+		}
+		dprintkdbg(DBG_0, "srb_done: AUTO_REQSENSE2\n");
+
+		if (srb->total_xfer_length
+		    && srb->total_xfer_length >= cmd->underflow)
+			cmd->result =
+			    MK_RES_LNX(DRIVER_SENSE, DID_OK,
+				       srb->end_message, CHECK_CONDITION);
+		/*SET_RES_DID(cmd->result,DID_OK) */
+		else
+			cmd->result =
+			    MK_RES_LNX(DRIVER_SENSE, DID_OK,
+				       srb->end_message, CHECK_CONDITION);
+
+		goto ckc_e;
+	}
+
+/*************************************************************/
+	if (status) {
+		/*
+		 * target status..........................
+		 */
+		if (status_byte(status) == CHECK_CONDITION) {
+			request_sense(acb, dcb, srb);
+			return;
+		} else if (status_byte(status) == QUEUE_FULL) {
+			tempcnt = (u8)list_size(&dcb->srb_going_list);
+			dprintkl(KERN_INFO, "QUEUE_FULL for dev <%02i-%i> with %i cmnds\n",
+			     dcb->target_id, dcb->target_lun, tempcnt);
+			if (tempcnt > 1)
+				tempcnt--;
+			dcb->max_command = tempcnt;
+			free_tag(dcb, srb);
+			srb_going_to_waiting_move(dcb, srb);
+			waiting_set_timer(acb, HZ / 20);
+			srb->adapter_status = 0;
+			srb->target_status = 0;
+			return;
+		} else if (status == SCSI_STAT_SEL_TIMEOUT) {
+			srb->adapter_status = H_SEL_TIMEOUT;
+			srb->target_status = 0;
+			cmd->result = DID_NO_CONNECT << 16;
+		} else {
+			srb->adapter_status = 0;
+			SET_RES_DID(cmd->result, DID_ERROR);
+			SET_RES_MSG(cmd->result, srb->end_message);
+			SET_RES_TARGET(cmd->result, status);
+
+		}
+	} else {
+		/*
+		 ** process initiator status..........................
+		 */
+		status = srb->adapter_status;
+		if (status & H_OVER_UNDER_RUN) {
+			srb->target_status = 0;
+			SET_RES_DID(cmd->result, DID_OK);
+			SET_RES_MSG(cmd->result, srb->end_message);
+		} else if (srb->status & PARITY_ERROR) {
+			SET_RES_DID(cmd->result, DID_PARITY);
+			SET_RES_MSG(cmd->result, srb->end_message);
+		} else {	/* No error */
+
+			srb->adapter_status = 0;
+			srb->target_status = 0;
+			SET_RES_DID(cmd->result, DID_OK);
+		}
+	}
+
+	if (dir != PCI_DMA_NONE) {
+		if (cmd->use_sg)
+			pci_dma_sync_sg_for_cpu(acb->dev,
+					(struct scatterlist *)cmd->
+					request_buffer, cmd->use_sg, dir);
+		else if (cmd->request_buffer)
+			pci_dma_sync_single_for_cpu(acb->dev,
+					    srb->segment_x[0].address,
+					    cmd->request_bufflen, dir);
+	}
+
+	if ((cmd->result & RES_DID) == 0 && cmd->cmnd[0] == INQUIRY
+	    && cmd->cmnd[2] == 0 && cmd->request_bufflen >= 8
+	    && dir != PCI_DMA_NONE && ptr && (ptr->Vers & 0x07) >= 2)
+		dcb->inquiry7 = ptr->Flags;
+/* Check Error Conditions */
+      ckc_e:
+
+	/*if( srb->cmd->cmnd[0] == INQUIRY && */
+	/*  (host_byte(cmd->result) == DID_OK || status_byte(cmd->result) & CHECK_CONDITION) ) */
+	if (cmd->cmnd[0] == INQUIRY && (cmd->result == (DID_OK << 16)
+					 || status_byte(cmd->
+							result) &
+					 CHECK_CONDITION)) {
+
+		if (!dcb->init_tcq_flag) {
+			add_dev(acb, dcb, ptr);
+			dcb->init_tcq_flag = 1;
+		}
+
+	}
+
+
+	/* Here is the info for Doug Gilbert's sg3 ... */
+	cmd->resid = srb->total_xfer_length;
+	/* This may be interpreted by sb. or not ... */
+	cmd->SCp.this_residual = srb->total_xfer_length;
+	cmd->SCp.buffers_residual = 0;
+	if (debug_enabled(DBG_KG)) {
+		if (srb->total_xfer_length)
+			dprintkdbg(DBG_KG, "srb_done: (pid#%li) <%02i-%i> "
+				"cmnd=0x%02x Missed %i bytes\n",
+				cmd->pid, cmd->device->id, cmd->device->lun,
+				cmd->cmnd[0], srb->total_xfer_length);
+	}
+
+	srb_going_remove(dcb, srb);
+	/* Add to free list */
+	if (srb == acb->tmp_srb)
+		dprintkl(KERN_ERR, "srb_done: ERROR! Completed cmd with tmp_srb\n");
+	else {
+		dprintkdbg(DBG_0, "srb_done: (pid#%li) done result=0x%08x\n",
+			cmd->pid, cmd->result);
+		srb_free_insert(acb, srb);
+	}
+	pci_unmap_srb(acb, srb);
+
+	cmd->scsi_done(cmd);
+	waiting_process_next(acb);
+}
+
+
+/* abort all cmds in our queues */
+static void doing_srb_done(struct AdapterCtlBlk *acb, u8 did_flag,
+		struct scsi_cmnd *cmd, u8 force)
+{
+	struct DeviceCtlBlk *dcb;
+	dprintkl(KERN_INFO, "doing_srb_done: pids ");
+
+	list_for_each_entry(dcb, &acb->dcb_list, list) {
+		struct ScsiReqBlk *srb;
+		struct ScsiReqBlk *tmp;
+		struct scsi_cmnd *p;
+
+		list_for_each_entry_safe(srb, tmp, &dcb->srb_going_list, list) {
+			enum dma_data_direction dir;
+			int result;
+
+			p = srb->cmd;
+			dir = p->sc_data_direction;
+			result = MK_RES(0, did_flag, 0, 0);
+			printk("G:%li(%02i-%i) ", p->pid,
+			       p->device->id, p->device->lun);
+			srb_going_remove(dcb, srb);
+			free_tag(dcb, srb);
+			srb_free_insert(acb, srb);
+			p->result = result;
+			pci_unmap_srb_sense(acb, srb);
+			pci_unmap_srb(acb, srb);
+			if (force) {
+				/* For new EH, we normally don't need to give commands back,
+				 * as they all complete or all time out */
+				p->scsi_done(p);
+			}
+		}
+		if (!list_empty(&dcb->srb_going_list))
+			dprintkl(KERN_DEBUG, 
+			       "How could the ML send cmnds to the Going queue? <%02i-%i>\n",
+			       dcb->target_id, dcb->target_lun);
+		if (dcb->tag_mask)
+			dprintkl(KERN_DEBUG,
+			       "tag_mask for <%02i-%i> should be empty, is %08x!\n",
+			       dcb->target_id, dcb->target_lun,
+			       dcb->tag_mask);
+
+		/* Waiting queue */
+		list_for_each_entry_safe(srb, tmp, &dcb->srb_waiting_list, list) {
+			int result;
+			p = srb->cmd;
+
+			result = MK_RES(0, did_flag, 0, 0);
+			printk("W:%li<%02i-%i>", p->pid, p->device->id,
+			       p->device->lun);
+			srb_waiting_remove(dcb, srb);
+			srb_free_insert(acb, srb);
+			p->result = result;
+			pci_unmap_srb_sense(acb, srb);
+			pci_unmap_srb(acb, srb);
+			if (force) {
+				/* For new EH, we normally don't need to give commands back,
+				 * as they all complete or all time out */
+				cmd->scsi_done(cmd);
+			}
+		}
+		if (!list_empty(&dcb->srb_waiting_list))
+			dprintkl(KERN_DEBUG, "ML queued %i cmnds again to <%02i-%i>\n",
+			     list_size(&dcb->srb_waiting_list), dcb->target_id,
+			     dcb->target_lun);
+		dcb->flag &= ~ABORT_DEV_;
+	}
+	printk("\n");
+}
+
+
+static void reset_scsi_bus(struct AdapterCtlBlk *acb)
+{
+	dprintkdbg(DBG_0, "reset_scsi_bus: acb=%p\n", acb);
+	acb->acb_flag |= RESET_DEV;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
+
+	while (!(DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET))
+		/* nothing */;
+}
+
+
+static void set_basic_config(struct AdapterCtlBlk *acb)
+{
+	u8 bval;
+	u16 wval;
+	DC395x_write8(acb, TRM_S1040_SCSI_TIMEOUT, acb->sel_timeout);
+	if (acb->config & HCC_PARITY)
+		bval = PHASELATCH | INITIATOR | BLOCKRST | PARITYCHECK;
+	else
+		bval = PHASELATCH | INITIATOR | BLOCKRST;
+
+	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG0, bval);
+
+	/* program configuration 1: Act_Neg (+ Act_Neg_Enh? + Fast_Filter? + DataDis?) */
+	DC395x_write8(acb, TRM_S1040_SCSI_CONFIG1, 0x03);	/* was 0x13: default */
+	/* program Host ID                  */
+	DC395x_write8(acb, TRM_S1040_SCSI_HOSTID, acb->scsi_host->this_id);
+	/* set ansynchronous transfer       */
+	DC395x_write8(acb, TRM_S1040_SCSI_OFFSET, 0x00);
+	/* Turn LED control off */
+	wval = DC395x_read16(acb, TRM_S1040_GEN_CONTROL) & 0x7F;
+	DC395x_write16(acb, TRM_S1040_GEN_CONTROL, wval);
+	/* DMA config          */
+	wval = DC395x_read16(acb, TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL;
+	wval |=
+	    DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ;
+	DC395x_write16(acb, TRM_S1040_DMA_CONFIG, wval);
+	/* Clear pending interrupt status */
+	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
+	/* Enable SCSI interrupt    */
+	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x7F);
+	DC395x_write8(acb, TRM_S1040_DMA_INTEN, EN_SCSIINTR | EN_DMAXFERERROR
+		      /*| EN_DMAXFERABORT | EN_DMAXFERCOMP | EN_FORCEDMACOMP */
+		      );
+}
+
+
+static void scsi_reset_detect(struct AdapterCtlBlk *acb)
+{
+	dprintkl(KERN_INFO, "scsi_reset_detect: acb=%p\n", acb);
+	/* delay half a second */
+	if (timer_pending(&acb->waiting_timer))
+		del_timer(&acb->waiting_timer);
+
+	DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
+	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
+	/*DC395x_write8(acb, TRM_S1040_DMA_CONTROL,STOPDMAXFER); */
+	udelay(500);
+	/* Maybe we locked up the bus? Then lets wait even longer ... */
+	acb->scsi_host->last_reset =
+	    jiffies + 5 * HZ / 2 +
+	    HZ * acb->eeprom.delay_time;
+
+	clear_fifo(acb, "scsi_reset_detect");
+	set_basic_config(acb);
+	/*1.25 */
+	/*DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); */
+
+	if (acb->acb_flag & RESET_DEV) {	/* RESET_DETECT, RESET_DONE, RESET_DEV */
+		acb->acb_flag |= RESET_DONE;
+	} else {
+		acb->acb_flag |= RESET_DETECT;
+		reset_dev_param(acb);
+		doing_srb_done(acb, DID_RESET, NULL, 1);
+		/*DC395x_RecoverSRB( acb ); */
+		acb->active_dcb = NULL;
+		acb->acb_flag = 0;
+		waiting_process_next(acb);
+	}
+}
+
+
+static void request_sense(struct AdapterCtlBlk *acb, struct DeviceCtlBlk *dcb,
+		struct ScsiReqBlk *srb)
+{
+	struct scsi_cmnd *cmd = srb->cmd;
+	dprintkdbg(DBG_1, "request_sense: (pid#%li) <%02i-%i>\n",
+		cmd->pid, cmd->device->id, cmd->device->lun);
+
+	srb->flag |= AUTO_REQSENSE;
+	srb->adapter_status = 0;
+	srb->target_status = 0;
+
+	/* KG: Can this prevent crap sense data ? */
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	/* Save some data */
+	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].address =
+	    srb->segment_x[0].address;
+	srb->segment_x[DC395x_MAX_SG_LISTENTRY - 1].length =
+	    srb->segment_x[0].length;
+	srb->xferred = srb->total_xfer_length;
+	/* srb->segment_x : a one entry of S/G list table */
+	srb->total_xfer_length = sizeof(cmd->sense_buffer);
+	srb->segment_x[0].length = sizeof(cmd->sense_buffer);
+	/* Map sense buffer */
+	srb->segment_x[0].address =
+	    pci_map_single(acb->dev, cmd->sense_buffer,
+			   sizeof(cmd->sense_buffer), PCI_DMA_FROMDEVICE);
+	dprintkdbg(DBG_SG, "request_sense: map buffer %p->%08x(%05x)\n",
+	       cmd->sense_buffer, srb->segment_x[0].address,
+	       sizeof(cmd->sense_buffer));
+	srb->sg_count = 1;
+	srb->sg_index = 0;
+
+	if (start_scsi(acb, dcb, srb)) {	/* Should only happen, if sb. else grabs the bus */
+		dprintkl(KERN_DEBUG,
+			"request_sense: (pid#%li) failed <%02i-%i>\n",
+			srb->cmd->pid, dcb->target_id, dcb->target_lun);
+		srb_going_to_waiting_move(dcb, srb);
+		waiting_set_timer(acb, HZ / 100);
+	}
+}
+
+
+/**
+ * device_alloc - Allocate a new device instance. This create the
+ * devices instance and sets up all the data items. The adapter
+ * instance is required to obtain confiuration information for this
+ * device. This does *not* add this device to the adapters device
+ * list.
+ *
+ * @acb: The adapter to obtain configuration information from.
+ * @target: The target for the new device.
+ * @lun: The lun for the new device.
+ *
+ * Return the new device if succesfull or NULL on failure.
+ **/
+static struct DeviceCtlBlk *device_alloc(struct AdapterCtlBlk *acb,
+		u8 target, u8 lun)
+{
+	struct NvRamType *eeprom = &acb->eeprom;
+	u8 period_index = eeprom->target[target].period & 0x07;
+	struct DeviceCtlBlk *dcb;
+
+	dcb = kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC);
+	dprintkdbg(DBG_0, "device_alloc: <%02i-%i>\n", target, lun);
+	if (!dcb)
+		return NULL;
+	dcb->acb = NULL;
+	INIT_LIST_HEAD(&dcb->srb_going_list);
+	INIT_LIST_HEAD(&dcb->srb_waiting_list);
+	dcb->active_srb = NULL;
+	dcb->tag_mask = 0;
+	dcb->max_command = 1;
+	dcb->target_id = target;
+	dcb->target_lun = lun;
+#ifndef DC395x_NO_DISCONNECT
+	dcb->identify_msg =
+	    IDENTIFY(dcb->dev_mode & NTC_DO_DISCONNECT, lun);
+#else
+	dcb->identify_msg = IDENTIFY(0, lun);
+#endif
+	dcb->dev_mode = eeprom->target[target].cfg0;
+	dcb->inquiry7 = 0;
+	dcb->sync_mode = 0;
+	dcb->min_nego_period = clock_period[period_index];
+	dcb->sync_period = 0;
+	dcb->sync_offset = 0;
+	dcb->flag = 0;
+
+#ifndef DC395x_NO_WIDE
+	if ((dcb->dev_mode & NTC_DO_WIDE_NEGO)
+	    && (acb->config & HCC_WIDE_CARD))
+		dcb->sync_mode |= WIDE_NEGO_ENABLE;
+#endif
+#ifndef DC395x_NO_SYNC
+	if (dcb->dev_mode & NTC_DO_SYNC_NEGO)
+		if (!(lun) || current_sync_offset)
+			dcb->sync_mode |= SYNC_NEGO_ENABLE;
+#endif
+	if (dcb->target_lun != 0) {
+		/* Copy settings */
+		struct DeviceCtlBlk *p;
+		list_for_each_entry(p, &acb->dcb_list, list)
+			if (p->target_id == dcb->target_id)
+				break;
+		dprintkdbg(DBG_1, 
+		       "device_alloc: <%02i-%i> copy from <%02i-%i>\n",
+		       dcb->target_id, dcb->target_lun,
+		       p->target_id, p->target_lun);
+		dcb->sync_mode = p->sync_mode;
+		dcb->sync_period = p->sync_period;
+		dcb->min_nego_period = p->min_nego_period;
+		dcb->sync_offset = p->sync_offset;
+		dcb->inquiry7 = p->inquiry7;
+	}
+	return dcb;
+}
+
+
+/**
+ * adapter_add_device - Adds the device instance to the adaptor instance.
+ *
+ * @acb: The adapter device to be updated
+ * @dcb: A newly created and intialised device instance to add.
+ **/
+static void adapter_add_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
+{
+	/* backpointer to adapter */
+	dcb->acb = acb;
+	
+	/* set run_robin to this device if it is currently empty */
+	if (list_empty(&acb->dcb_list))
+		acb->dcb_run_robin = dcb;
+
+	/* add device to list */
+	list_add_tail(&dcb->list, &acb->dcb_list);
+
+	/* update device maps */
+	acb->dcb_map[dcb->target_id] |= (1 << dcb->target_lun);
+	acb->children[dcb->target_id][dcb->target_lun] = dcb;
+}
+
+
+/**
+ * adapter_remove_device - Removes the device instance from the adaptor
+ * instance. The device instance is not check in any way or freed by this. 
+ * The caller is expected to take care of that. This will simply remove the
+ * device from the adapters data strcutures.
+ *
+ * @acb: The adapter device to be updated
+ * @dcb: A device that has previously been added to the adapter.
+ **/
+static void adapter_remove_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
+{
+	struct DeviceCtlBlk *i;
+	struct DeviceCtlBlk *tmp;
+	dprintkdbg(DBG_0, "adapter_remove_device: <%02i-%i>\n",
+		dcb->target_id, dcb->target_lun);
+
+	/* fix up any pointers to this device that we have in the adapter */
+	if (acb->active_dcb == dcb)
+		acb->active_dcb = NULL;
+	if (acb->dcb_run_robin == dcb)
+		acb->dcb_run_robin = dcb_get_next(&acb->dcb_list, dcb);
+
+	/* unlink from list */
+	list_for_each_entry_safe(i, tmp, &acb->dcb_list, list)
+		if (dcb == i) {
+			list_del(&i->list);
+			break;
+		}
+
+	/* clear map and children */	
+	acb->dcb_map[dcb->target_id] &= ~(1 << dcb->target_lun);
+	acb->children[dcb->target_id][dcb->target_lun] = NULL;
+	dcb->acb = NULL;
+}
+
+
+/**
+ * adapter_remove_and_free_device - Removes a single device from the adapter
+ * and then frees the device information.
+ *
+ * @acb: The adapter device to be updated
+ * @dcb: A device that has previously been added to the adapter.
+ */
+static void adapter_remove_and_free_device(struct AdapterCtlBlk *acb,
+		struct DeviceCtlBlk *dcb)
+{
+	if (list_size(&dcb->srb_going_list) > 1) {
+		dprintkdbg(DBG_1, "adapter_remove_and_free_device: <%02i-%i> "
+		           "Won't remove because of %i active requests.\n",
+			   dcb->target_id, dcb->target_lun,
+			   list_size(&dcb->srb_going_list));
+		return;
+	}
+	adapter_remove_device(acb, dcb);
+	kfree(dcb);
+}
+
+
+/**
+ * adapter_remove_and_free_all_devices - Removes and frees all of the
+ * devices associated with the specified adapter.
+ *
+ * @acb: The adapter from which all devices should be removed.
+ **/
+static void adapter_remove_and_free_all_devices(struct AdapterCtlBlk* acb)
+{
+	struct DeviceCtlBlk *dcb;
+	struct DeviceCtlBlk *tmp;
+	dprintkdbg(DBG_1, "adapter_remove_and_free_all_devices: num=%i\n",
+		   list_size(&acb->dcb_list));
+
+	list_for_each_entry_safe(dcb, tmp, &acb->dcb_list, list)
+		adapter_remove_and_free_device(acb, dcb);
+}
+
+
+/**
+ * dc395x_slave_alloc - Called by the scsi mid layer to tell us about a new
+ * scsi device that we need to deal with. We allocate a new device and then
+ * insert that device into the adapters device list.
+ *
+ * @scsi_device: The new scsi device that we need to handle.
+ **/
+static int dc395x_slave_alloc(struct scsi_device *scsi_device)
+{
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
+	struct DeviceCtlBlk *dcb;
+
+	dcb = device_alloc(acb, scsi_device->id, scsi_device->lun);
+	if (!dcb)
+		return -ENOMEM;
+	adapter_add_device(acb, dcb);
+
+	return 0;
+}
+
+
+/**
+ * dc395x_slave_destroy - Called by the scsi mid layer to tell us about a
+ * device that is going away.
+ *
+ * @scsi_device: The new scsi device that we need to handle.
+ **/
+static void dc395x_slave_destroy(struct scsi_device *scsi_device)
+{
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)scsi_device->host->hostdata;
+	struct DeviceCtlBlk *dcb = find_dcb(acb, scsi_device->id, scsi_device->lun);
+	if (dcb)
+		adapter_remove_and_free_device(acb, dcb);
+}
+
+
+
+
+/**
+ * trms1040_wait_30us: wait for 30 us
+ *
+ * Waits for 30us (using the chip by the looks of it..)
+ *
+ * @io_port: base I/O address
+ **/
+static void __devinit trms1040_wait_30us(unsigned long io_port)
+{
+	/* ScsiPortStallExecution(30); wait 30 us */
+	outb(5, io_port + TRM_S1040_GEN_TIMER);
+	while (!(inb(io_port + TRM_S1040_GEN_STATUS) & GTIMEOUT))
+		/* nothing */ ;
+}
+
+
+/**
+ * trms1040_write_cmd - write the secified command and address to
+ * chip
+ *
+ * @io_port:	base I/O address
+ * @cmd:	SB + op code (command) to send
+ * @addr:	address to send
+ **/
+static void __devinit trms1040_write_cmd(unsigned long io_port, u8 cmd, u8 addr)
+{
+	int i;
+	u8 send_data;
+
+	/* program SB + OP code */
+	for (i = 0; i < 3; i++, cmd <<= 1) {
+		send_data = NVR_SELECT;
+		if (cmd & 0x04)	/* Start from bit 2 */
+			send_data |= NVR_BITOUT;
+
+		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+		outb((send_data | NVR_CLOCK),
+		     io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+	}
+
+	/* send address */
+	for (i = 0; i < 7; i++, addr <<= 1) {
+		send_data = NVR_SELECT;
+		if (addr & 0x40)	/* Start from bit 6 */
+			send_data |= NVR_BITOUT;
+
+		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+		outb((send_data | NVR_CLOCK),
+		     io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+	}
+	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+}
+
+
+/**
+ * trms1040_set_data - store a single byte in the eeprom
+ *
+ * Called from write all to write a single byte into the SSEEPROM
+ * Which is done one bit at a time.
+ *
+ * @io_port:	base I/O address
+ * @addr:	offset into EEPROM
+ * @byte:	bytes to write
+ **/
+static void __devinit trms1040_set_data(unsigned long io_port, u8 addr, u8 byte)
+{
+	int i;
+	u8 send_data;
+
+	/* Send write command & address */
+	trms1040_write_cmd(io_port, 0x05, addr);
+
+	/* Write data */
+	for (i = 0; i < 8; i++, byte <<= 1) {
+		send_data = NVR_SELECT;
+		if (byte & 0x80)	/* Start from bit 7 */
+			send_data |= NVR_BITOUT;
+
+		outb(send_data, io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+		outb((send_data | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+	}
+	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+
+	/* Disable chip select */
+	outb(0, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+
+	outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+
+	/* Wait for write ready */
+	while (1) {
+		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+
+		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+
+		if (inb(io_port + TRM_S1040_GEN_NVRAM) & NVR_BITIN)
+			break;
+	}
+
+	/*  Disable chip select */
+	outb(0, io_port + TRM_S1040_GEN_NVRAM);
+}
+
+
+/**
+ * trms1040_write_all - write 128 bytes to the eeprom
+ *
+ * Write the supplied 128 bytes to the chips SEEPROM
+ *
+ * @eeprom:	the data to write
+ * @io_port:	the base io port
+ **/
+static void __devinit trms1040_write_all(struct NvRamType *eeprom, unsigned long io_port)
+{
+	u8 *b_eeprom = (u8 *)eeprom;
+	u8 addr;
+
+	/* Enable SEEPROM */
+	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
+	     io_port + TRM_S1040_GEN_CONTROL);
+
+	/* write enable */
+	trms1040_write_cmd(io_port, 0x04, 0xFF);
+	outb(0, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+
+	/* write */
+	for (addr = 0; addr < 128; addr++, b_eeprom++)
+		trms1040_set_data(io_port, addr, *b_eeprom);
+
+	/* write disable */
+	trms1040_write_cmd(io_port, 0x04, 0x00);
+	outb(0, io_port + TRM_S1040_GEN_NVRAM);
+	trms1040_wait_30us(io_port);
+
+	/* Disable SEEPROM */
+	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
+	     io_port + TRM_S1040_GEN_CONTROL);
+}
+
+
+/**
+ * trms1040_get_data - get a single byte from the eeprom
+ *
+ * Called from read all to read a single byte into the SSEEPROM
+ * Which is done one bit at a time.
+ *
+ * @io_port:	base I/O address
+ * @addr:	offset into SEEPROM
+ *
+ * Returns the the byte read.
+ **/
+static u8 __devinit trms1040_get_data(unsigned long io_port, u8 addr)
+{
+	int i;
+	u8 read_byte;
+	u8 result = 0;
+
+	/* Send read command & address */
+	trms1040_write_cmd(io_port, 0x06, addr);
+
+	/* read data */
+	for (i = 0; i < 8; i++) {
+		outb((NVR_SELECT | NVR_CLOCK), io_port + TRM_S1040_GEN_NVRAM);
+		trms1040_wait_30us(io_port);
+		outb(NVR_SELECT, io_port + TRM_S1040_GEN_NVRAM);
+
+		/* Get data bit while falling edge */
+		read_byte = inb(io_port + TRM_S1040_GEN_NVRAM);
+		result <<= 1;
+		if (read_byte & NVR_BITIN)
+			result |= 1;
+
+		trms1040_wait_30us(io_port);
+	}
+
+	/* Disable chip select */
+	outb(0, io_port + TRM_S1040_GEN_NVRAM);
+	return result;
+}
+
+
+/**
+ * trms1040_read_all - read all bytes from the eeprom
+ *
+ * Read the 128 bytes from the SEEPROM.
+ *
+ * @eeprom:	where to store the data
+ * @io_port:	the base io port
+ **/
+static void __devinit trms1040_read_all(struct NvRamType *eeprom, unsigned long io_port)
+{
+	u8 *b_eeprom = (u8 *)eeprom;
+	u8 addr;
+
+	/* Enable SEEPROM */
+	outb((inb(io_port + TRM_S1040_GEN_CONTROL) | EN_EEPROM),
+	     io_port + TRM_S1040_GEN_CONTROL);
+
+	/* read details */
+	for (addr = 0; addr < 128; addr++, b_eeprom++)
+		*b_eeprom = trms1040_get_data(io_port, addr);
+
+	/* Disable SEEPROM */
+	outb((inb(io_port + TRM_S1040_GEN_CONTROL) & ~EN_EEPROM),
+	     io_port + TRM_S1040_GEN_CONTROL);
+}
+
+
+
+/**
+ * check_eeprom - get and check contents of the eeprom
+ *
+ * Read seeprom 128 bytes into the memory provider in eeprom.
+ * Checks the checksum and if it's not correct it uses a set of default
+ * values.
+ *
+ * @eeprom:	caller allocated strcuture to read the eeprom data into
+ * @io_port:	io port to read from
+ **/
+static void __devinit check_eeprom(struct NvRamType *eeprom, unsigned long io_port)
+{
+	u16 *w_eeprom = (u16 *)eeprom;
+	u16 w_addr;
+	u16 cksum;
+	u32 d_addr;
+	u32 *d_eeprom;
+
+	trms1040_read_all(eeprom, io_port);	/* read eeprom */
+
+	cksum = 0;
+	for (w_addr = 0, w_eeprom = (u16 *)eeprom; w_addr < 64;
+	     w_addr++, w_eeprom++)
+		cksum += *w_eeprom;
+	if (cksum != 0x1234) {
+		/*
+		 * Checksum is wrong.
+		 * Load a set of defaults into the eeprom buffer
+		 */
+		dprintkl(KERN_WARNING,
+			"EEProm checksum error: using default values and options.\n");
+		eeprom->sub_vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
+		eeprom->sub_vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
+		eeprom->sub_sys_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
+		eeprom->sub_sys_id[1] =
+		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
+		eeprom->sub_class = 0x00;
+		eeprom->vendor_id[0] = (u8)PCI_VENDOR_ID_TEKRAM;
+		eeprom->vendor_id[1] = (u8)(PCI_VENDOR_ID_TEKRAM >> 8);
+		eeprom->device_id[0] = (u8)PCI_DEVICE_ID_TEKRAM_TRMS1040;
+		eeprom->device_id[1] =
+		    (u8)(PCI_DEVICE_ID_TEKRAM_TRMS1040 >> 8);
+		eeprom->reserved = 0x00;
+
+		for (d_addr = 0, d_eeprom = (u32 *)eeprom->target;
+		     d_addr < 16; d_addr++, d_eeprom++)
+			*d_eeprom = 0x00000077;	/* cfg3,cfg2,period,cfg0 */
+
+		*d_eeprom++ = 0x04000F07;	/* max_tag,delay_time,channel_cfg,scsi_id */
+		*d_eeprom++ = 0x00000015;	/* reserved1,boot_lun,boot_target,reserved0 */
+		for (d_addr = 0; d_addr < 12; d_addr++, d_eeprom++)
+			*d_eeprom = 0x00;
+
+		/* Now load defaults (maybe set by boot/module params) */
+		set_safe_settings();
+		fix_settings();
+		eeprom_override(eeprom);
+
+		eeprom->cksum = 0x00;
+		for (w_addr = 0, cksum = 0, w_eeprom = (u16 *)eeprom;
+		     w_addr < 63; w_addr++, w_eeprom++)
+			cksum += *w_eeprom;
+
+		*w_eeprom = 0x1234 - cksum;
+		trms1040_write_all(eeprom, io_port);
+		eeprom->delay_time = cfg_data[CFG_RESET_DELAY].value;
+	} else {
+		set_safe_settings();
+		eeprom_index_to_delay(eeprom);
+		eeprom_override(eeprom);
+	}
+}
+
+
+/**
+ * print_eeprom_settings - output the eeprom settings
+ * to the kernel log so people can see what they were.
+ *
+ * @eeprom: The eeprom data strucutre to show details for.
+ **/
+static void __devinit print_eeprom_settings(struct NvRamType *eeprom)
+{
+	dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), dev_mode=0x%02x\n",
+		eeprom->scsi_id,
+		eeprom->target[0].period,
+		clock_speed[eeprom->target[0].period] / 10,
+		clock_speed[eeprom->target[0].period] % 10,
+		eeprom->target[0].cfg0);
+	dprintkl(KERN_INFO, "               AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n",
+		eeprom->channel_cfg, eeprom->max_tag,
+		1 << eeprom->max_tag, eeprom->delay_time);
+}
+
+
+/* Free SG tables */
+static void adapter_sg_tables_free(struct AdapterCtlBlk *acb)
+{
+	int i;
+	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
+
+	for (i = 0; i < DC395x_MAX_SRB_CNT; i += srbs_per_page)
+		kfree(acb->srb_array[i].segment_x);
+
+	vfree(acb->srb_array[0].virt_map);
+}
+
+
+/*
+ * Allocate SG tables; as we have to pci_map them, an SG list (struct SGentry*)
+ * should never cross a page boundary */
+static int __devinit adapter_sg_tables_alloc(struct AdapterCtlBlk *acb)
+{
+	const unsigned mem_needed = (DC395x_MAX_SRB_CNT+1)
+	                            *SEGMENTX_LEN;
+	int pages = (mem_needed+(PAGE_SIZE-1))/PAGE_SIZE;
+	const unsigned srbs_per_page = PAGE_SIZE/SEGMENTX_LEN;
+	int srb_idx = 0;
+	unsigned i = 0;
+	struct SGentry *ptr;
+	void **virt_array;
+
+	for (i = 0; i < DC395x_MAX_SRB_CNT; i++) {
+		acb->srb_array[i].segment_x = NULL;
+		acb->srb_array[i].virt_map = NULL;
+	}
+
+	dprintkdbg(DBG_1, "Allocate %i pages for SG tables\n", pages);
+	while (pages--) {
+		ptr = (struct SGentry *)kmalloc(PAGE_SIZE, GFP_KERNEL);
+		if (!ptr) {
+			adapter_sg_tables_free(acb);
+			return 1;
+		}
+		dprintkdbg(DBG_1, "Allocate %li bytes at %p for SG segments %i\n",
+			PAGE_SIZE, ptr, srb_idx);
+		i = 0;
+		while (i < srbs_per_page && srb_idx < DC395x_MAX_SRB_CNT)
+			acb->srb_array[srb_idx++].segment_x =
+			    ptr + (i++ * DC395x_MAX_SG_LISTENTRY);
+	}
+	if (i < srbs_per_page)
+		acb->srb.segment_x =
+		    ptr + (i * DC395x_MAX_SG_LISTENTRY);
+	else
+		dprintkl(KERN_DEBUG, "No space for tmsrb SG table reserved?!\n");
+
+	virt_array = vmalloc((DC395x_MAX_SRB_CNT + 1) * DC395x_MAX_SG_LISTENTRY * sizeof(void*));
+
+	if (!virt_array) {
+		adapter_sg_tables_free(acb);
+		return 1;
+	}
+
+	for (i = 0; i < DC395x_MAX_SRB_CNT + 1; i++) {
+		acb->srb_array[i].virt_map = virt_array;
+		virt_array += DC395x_MAX_SG_LISTENTRY;
+	}
+
+	return 0;
+}
+
+
+
+/**
+ * adapter_print_config - print adapter connection and termination
+ * config
+ *
+ * The io port in the adapter needs to have been set before calling
+ * this function.
+ *
+ * @acb: The adapter to print the information for.
+ **/
+static void __devinit adapter_print_config(struct AdapterCtlBlk *acb)
+{
+	u8 bval;
+
+	bval = DC395x_read8(acb, TRM_S1040_GEN_STATUS);
+	dprintkl(KERN_INFO, "%sConnectors: ",
+		((bval & WIDESCSI) ? "(Wide) " : ""));
+	if (!(bval & CON5068))
+		printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50");
+	if (!(bval & CON68))
+		printk("int68%s ", !(bval & INT68HIGH) ? "" : "(50)");
+	if (!(bval & CON50))
+		printk("int50 ");
+	if ((bval & (CON5068 | CON50 | CON68)) ==
+	    0 /*(CON5068 | CON50 | CON68) */ )
+		printk(" Oops! (All 3?) ");
+	bval = DC395x_read8(acb, TRM_S1040_GEN_CONTROL);
+	printk(" Termination: ");
+	if (bval & DIS_TERM)
+		printk("Disabled\n");
+	else {
+		if (bval & AUTOTERM)
+			printk("Auto ");
+		if (bval & LOW8TERM)
+			printk("Low ");
+		if (bval & UP8TERM)
+			printk("High ");
+		printk("\n");
+	}
+}
+
+
+/**
+ * adapter_init_params - Initialize the various parameters in the
+ * adapter structure. Note that the pointer to the scsi_host is set
+ * early (when this instance is created) and the io_port and irq
+ * values are set later after they have been reserved. This just gets
+ * everything set to a good starting position.
+ *
+ * The eeprom structure in the adapter needs to have been set before
+ * calling this function.
+ *
+ * @acb: The adapter to initialize.
+ **/
+static void __devinit adapter_init_params(struct AdapterCtlBlk *acb)
+{
+	struct NvRamType *eeprom = &acb->eeprom;
+	int i;
+
+	/* NOTE: acb->scsi_host is set at scsi_host/acb creation time */
+	/* NOTE: acb->io_port_base is set at port registration time */
+	/* NOTE: acb->io_port_len is set at port registration time */
+
+	INIT_LIST_HEAD(&acb->dcb_list);
+	acb->dcb_run_robin = NULL;
+	acb->active_dcb = NULL;
+
+	INIT_LIST_HEAD(&acb->srb_free_list);
+	/*  temp SRB for Q tag used or abort command used  */
+	acb->tmp_srb = &acb->srb;
+	init_timer(&acb->waiting_timer);
+	init_timer(&acb->selto_timer);
+
+	acb->srb_count = DC395x_MAX_SRB_CNT;
+
+	acb->sel_timeout = DC395x_SEL_TIMEOUT;	/* timeout=250ms */
+	/* NOTE: acb->irq_level is set at IRQ registration time */
+
+	acb->tag_max_num = 1 << eeprom->max_tag;
+	if (acb->tag_max_num > 30)
+		acb->tag_max_num = 30;
+
+	acb->acb_flag = 0;	/* RESET_DETECT, RESET_DONE, RESET_DEV */
+	acb->gmode2 = eeprom->channel_cfg;
+	acb->config = 0;	/* NOTE: actually set in adapter_init_chip */
+
+	if (eeprom->channel_cfg & NAC_SCANLUN)
+		acb->lun_chk = 1;
+	acb->scan_devices = 1;
+
+	acb->scsi_host->this_id = eeprom->scsi_id;
+	acb->hostid_bit = (1 << acb->scsi_host->this_id);
+
+	for (i = 0; i < DC395x_MAX_SCSI_ID; i++)
+		acb->dcb_map[i] = 0;
+
+	acb->msg_len = 0;
+	
+	/* link static array of srbs into the srb free list */
+	for (i = 0; i < acb->srb_count - 1; i++)
+		srb_free_insert(acb, &acb->srb_array[i]);
+}
+
+
+/**
+ * adapter_init_host - Initialize the scsi host instance based on
+ * values that we have already stored in the adapter instance. There's
+ * some mention that a lot of these are deprecated, so we won't use
+ * them (we'll use the ones in the adapter instance) but we'll fill
+ * them in in case something else needs them.
+ *
+ * The eeprom structure, irq and io ports in the adapter need to have
+ * been set before calling this function.
+ *
+ * @host: The scsi host instance to fill in the values for.
+ **/
+static void __devinit adapter_init_scsi_host(struct Scsi_Host *host)
+{
+        struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
+	struct NvRamType *eeprom = &acb->eeprom;
+        
+	host->max_cmd_len = 24;
+	host->can_queue = DC395x_MAX_CMD_QUEUE;
+	host->cmd_per_lun = DC395x_MAX_CMD_PER_LUN;
+	host->this_id = (int)eeprom->scsi_id;
+	host->io_port = acb->io_port_base;
+	host->n_io_port = acb->io_port_len;
+	host->dma_channel = -1;
+	host->unique_id = acb->io_port_base;
+	host->irq = acb->irq_level;
+	host->last_reset = jiffies;
+
+	host->max_id = 16;
+	if (host->max_id - 1 == eeprom->scsi_id)
+		host->max_id--;
+
+#ifdef CONFIG_SCSI_MULTI_LUN
+	if (eeprom->channel_cfg & NAC_SCANLUN)
+		host->max_lun = 8;
+	else
+		host->max_lun = 1;
+#else
+	host->max_lun = 1;
+#endif
+
+}
+
+
+/**
+ * adapter_init_chip - Get the chip into a know state and figure out
+ * some of the settings that apply to this adapter.
+ *
+ * The io port in the adapter needs to have been set before calling
+ * this function. The config will be configured correctly on return.
+ *
+ * @acb: The adapter which we are to init.
+ **/
+static void __devinit adapter_init_chip(struct AdapterCtlBlk *acb)
+{
+        struct NvRamType *eeprom = &acb->eeprom;
+        
+        /* Mask all the interrupt */
+	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0x00);
+	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0x00);
+
+	/* Reset SCSI module */
+	DC395x_write16(acb, TRM_S1040_SCSI_CONTROL, DO_RSTMODULE);
+
+	/* Reset PCI/DMA module */
+	DC395x_write8(acb, TRM_S1040_DMA_CONTROL, DMARESETMODULE);
+	udelay(20);
+
+	/* program configuration 0 */
+	acb->config = HCC_AUTOTERM | HCC_PARITY;
+	if (DC395x_read8(acb, TRM_S1040_GEN_STATUS) & WIDESCSI)
+		acb->config |= HCC_WIDE_CARD;
+
+	if (eeprom->channel_cfg & NAC_POWERON_SCSI_RESET)
+		acb->config |= HCC_SCSI_RESET;
+
+	if (acb->config & HCC_SCSI_RESET) {
+		dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n");
+		DC395x_write8(acb, TRM_S1040_SCSI_CONTROL, DO_RSTSCSI);
+
+		/*while (!( DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */
+		/*spin_unlock_irq (&io_request_lock); */
+		udelay(500);
+
+		acb->scsi_host->last_reset =
+		    jiffies + HZ / 2 +
+		    HZ * acb->eeprom.delay_time;
+
+		/*spin_lock_irq (&io_request_lock); */
+	}
+}
+
+
+/**
+ * init_adapter - Grab the resource for the card, setup the adapter
+ * information, set the card into a known state, create the various
+ * tables etc etc. This basically gets all adapter information all up
+ * to date, intialised and gets the chip in sync with it.
+ *
+ * @host:	This hosts adapter structure
+ * @io_port:	The base I/O port
+ * @irq:	IRQ
+ *
+ * Returns 0 if the initialization succeeds, any other value on
+ * failure.
+ **/
+static int __devinit adapter_init(struct AdapterCtlBlk *acb,
+	unsigned long io_port, u32 io_port_len, unsigned int irq)
+{
+	if (!request_region(io_port, io_port_len, DC395X_NAME)) {
+		dprintkl(KERN_ERR, "Failed to reserve IO region 0x%lx\n", io_port);
+		goto failed;
+	}
+	/* store port base to indicate we have registered it */
+	acb->io_port_base = io_port;
+	acb->io_port_len = io_port_len;
+	
+	if (request_irq(irq, dc395x_interrupt, SA_SHIRQ, DC395X_NAME, acb)) {
+	    	/* release the region we just claimed */
+		dprintkl(KERN_INFO, "Failed to register IRQ\n");
+		goto failed;
+	}
+	/* store irq to indicate we have registered it */
+	acb->irq_level = irq;
+
+	/* get eeprom configuration information and command line settings etc */
+	check_eeprom(&acb->eeprom, io_port);
+ 	print_eeprom_settings(&acb->eeprom);
+
+	/* setup adapter control block */	
+	adapter_init_params(acb);
+	
+	/* display card connectors/termination settings */
+ 	adapter_print_config(acb);
+
+	if (adapter_sg_tables_alloc(acb)) {
+		dprintkl(KERN_DEBUG, "Memory allocation for SG tables failed\n");
+		goto failed;
+	}
+	adapter_init_scsi_host(acb->scsi_host);
+	adapter_init_chip(acb);
+	set_basic_config(acb);
+
+	dprintkdbg(DBG_0,
+		"adapter_init: acb=%p, pdcb_map=%p psrb_array=%p "
+		"size{acb=0x%04x dcb=0x%04x srb=0x%04x}\n",
+		acb, acb->dcb_map, acb->srb_array, sizeof(struct AdapterCtlBlk),
+		sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk));
+	return 0;
+
+failed:
+	if (acb->irq_level)
+		free_irq(acb->irq_level, acb);
+	if (acb->io_port_base)
+		release_region(acb->io_port_base, acb->io_port_len);
+	adapter_sg_tables_free(acb);
+
+	return 1;
+}
+
+
+/**
+ * adapter_uninit_chip - cleanly shut down the scsi controller chip,
+ * stopping all operations and disabling interrupt generation on the
+ * card.
+ *
+ * @acb: The adapter which we are to shutdown.
+ **/
+static void adapter_uninit_chip(struct AdapterCtlBlk *acb)
+{
+	/* disable interrupts */
+	DC395x_write8(acb, TRM_S1040_DMA_INTEN, 0);
+	DC395x_write8(acb, TRM_S1040_SCSI_INTEN, 0);
+
+	/* reset the scsi bus */
+	if (acb->config & HCC_SCSI_RESET)
+		reset_scsi_bus(acb);
+
+	/* clear any pending interupt state */
+	DC395x_read8(acb, TRM_S1040_SCSI_INTSTATUS);
+}
+
+
+
+/**
+ * adapter_uninit - Shut down the chip and release any resources that
+ * we had allocated. Once this returns the adapter should not be used
+ * anymore.
+ *
+ * @acb: The adapter which we are to un-initialize.
+ **/
+static void adapter_uninit(struct AdapterCtlBlk *acb)
+{
+	unsigned long flags;
+	DC395x_LOCK_IO(acb->scsi_host, flags);
+
+	/* remove timers */
+	if (timer_pending(&acb->waiting_timer))
+		del_timer(&acb->waiting_timer);
+	if (timer_pending(&acb->selto_timer))
+		del_timer(&acb->selto_timer);
+
+	adapter_uninit_chip(acb);
+	adapter_remove_and_free_all_devices(acb);
+	DC395x_UNLOCK_IO(acb->scsi_host, flags);
+
+	if (acb->irq_level)
+		free_irq(acb->irq_level, acb);
+	if (acb->io_port_base)
+		release_region(acb->io_port_base, acb->io_port_len);
+
+	adapter_sg_tables_free(acb);
+}
+
+
+#undef SPRINTF
+#define SPRINTF(args...) pos += sprintf(pos, args)
+
+#undef YESNO
+#define YESNO(YN) \
+ if (YN) SPRINTF(" Yes ");\
+ else SPRINTF(" No  ")
+
+static int dc395x_proc_info(struct Scsi_Host *host, char *buffer,
+		char **start, off_t offset, int length, int inout)
+{
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)host->hostdata;
+	int spd, spd1;
+	char *pos = buffer;
+	struct DeviceCtlBlk *dcb;
+	unsigned long flags;
+	int dev;
+
+	if (inout)		/* Has data been written to the file ? */
+		return -EPERM;
+
+	SPRINTF(DC395X_BANNER " PCI SCSI Host Adapter\n");
+	SPRINTF(" Driver Version " DC395X_VERSION "\n");
+
+	DC395x_LOCK_IO(acb->scsi_host, flags);
+
+	SPRINTF("SCSI Host Nr %i, ", host->host_no);
+	SPRINTF("DC395U/UW/F DC315/U %s\n",
+		(acb->config & HCC_WIDE_CARD) ? "Wide" : "");
+	SPRINTF("io_port_base 0x%04lx, ", acb->io_port_base);
+	SPRINTF("irq_level 0x%04x, ", acb->irq_level);
+	SPRINTF(" SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
+
+	SPRINTF("MaxID %i, MaxLUN %i, ", host->max_id, host->max_lun);
+	SPRINTF("AdapterID %i\n", host->this_id);
+
+	SPRINTF("tag_max_num %i", acb->tag_max_num);
+	/*SPRINTF(", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */
+	SPRINTF(", FilterCfg 0x%02x",
+		DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1));
+	SPRINTF(", DelayReset %is\n", acb->eeprom.delay_time);
+	/*SPRINTF("\n"); */
+
+	SPRINTF("Nr of DCBs: %i\n", list_size(&acb->dcb_list));
+	SPRINTF
+	    ("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	     acb->dcb_map[0], acb->dcb_map[1], acb->dcb_map[2],
+	     acb->dcb_map[3], acb->dcb_map[4], acb->dcb_map[5],
+	     acb->dcb_map[6], acb->dcb_map[7]);
+	SPRINTF
+	    ("                      %02x %02x %02x %02x %02x %02x %02x %02x\n",
+	     acb->dcb_map[8], acb->dcb_map[9], acb->dcb_map[10],
+	     acb->dcb_map[11], acb->dcb_map[12], acb->dcb_map[13],
+	     acb->dcb_map[14], acb->dcb_map[15]);
+
+	SPRINTF
+	    ("Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
+
+	dev = 0;
+	list_for_each_entry(dcb, &acb->dcb_list, list) {
+		int nego_period;
+		SPRINTF("%02i %02i  %02i ", dev, dcb->target_id,
+			dcb->target_lun);
+		YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK);
+		YESNO(dcb->sync_offset);
+		YESNO(dcb->sync_period & WIDE_SYNC);
+		YESNO(dcb->dev_mode & NTC_DO_DISCONNECT);
+		YESNO(dcb->dev_mode & NTC_DO_SEND_START);
+		YESNO(dcb->sync_mode & EN_TAG_QUEUEING);
+		nego_period = clock_period[dcb->sync_period & 0x07] << 2;
+		if (dcb->sync_offset)
+			SPRINTF("  %03i ns ", nego_period);
+		else
+			SPRINTF(" (%03i ns)", (dcb->min_nego_period << 2));
+
+		if (dcb->sync_offset & 0x0f) {
+			spd = 1000 / (nego_period);
+			spd1 = 1000 % (nego_period);
+			spd1 = (spd1 * 10 + nego_period / 2) / (nego_period);
+			SPRINTF("   %2i.%1i M     %02i ", spd, spd1,
+				(dcb->sync_offset & 0x0f));
+		} else
+			SPRINTF("                 ");
+
+		/* Add more info ... */
+		SPRINTF("     %02i\n", dcb->max_command);
+		dev++;
+	}
+
+	if (timer_pending(&acb->waiting_timer))
+		SPRINTF("Waiting queue timer running\n");
+	else
+		SPRINTF("\n");
+
+	list_for_each_entry(dcb, &acb->dcb_list, list) {
+		struct ScsiReqBlk *srb;
+		if (!list_empty(&dcb->srb_waiting_list))
+			SPRINTF("DCB (%02i-%i): Waiting: %i:",
+				dcb->target_id, dcb->target_lun,
+				list_size(&dcb->srb_waiting_list));
+                list_for_each_entry(srb, &dcb->srb_waiting_list, list)
+			SPRINTF(" %li", srb->cmd->pid);
+		if (!list_empty(&dcb->srb_going_list))
+			SPRINTF("\nDCB (%02i-%i): Going  : %i:",
+				dcb->target_id, dcb->target_lun,
+				list_size(&dcb->srb_going_list));
+		list_for_each_entry(srb, &dcb->srb_going_list, list)
+			SPRINTF(" %li", srb->cmd->pid);
+		if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
+			SPRINTF("\n");
+	}
+
+	if (debug_enabled(DBG_1)) {
+		SPRINTF("DCB list for ACB %p:\n", acb);
+		list_for_each_entry(dcb, &acb->dcb_list, list) {
+			SPRINTF("%p -> ", dcb);
+		}
+		SPRINTF("END\n");
+	}
+
+	*start = buffer + offset;
+	DC395x_UNLOCK_IO(acb->scsi_host, flags);
+
+	if (pos - buffer < offset)
+		return 0;
+	else if (pos - buffer - offset < length)
+		return pos - buffer - offset;
+	else
+		return length;
+}
+
+
+static struct scsi_host_template dc395x_driver_template = {
+	.module                 = THIS_MODULE,
+	.proc_name              = DC395X_NAME,
+	.proc_info              = dc395x_proc_info,
+	.name                   = DC395X_BANNER " " DC395X_VERSION,
+	.queuecommand           = dc395x_queue_command,
+	.bios_param             = dc395x_bios_param,
+	.slave_alloc            = dc395x_slave_alloc,
+	.slave_destroy          = dc395x_slave_destroy,
+	.can_queue              = DC395x_MAX_CAN_QUEUE,
+	.this_id                = 7,
+	.sg_tablesize           = DC395x_MAX_SG_TABLESIZE,
+	.cmd_per_lun            = DC395x_MAX_CMD_PER_LUN,
+	.eh_abort_handler       = dc395x_eh_abort,
+	.eh_bus_reset_handler   = dc395x_eh_bus_reset,
+	.unchecked_isa_dma      = 0,
+	.use_clustering         = DISABLE_CLUSTERING,
+};
+
+
+/**
+ * banner_display - Display banner on first instance of driver
+ * initialized.
+ **/
+static void banner_display(void)
+{
+	static int banner_done = 0;
+	if (!banner_done)
+	{
+		dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION);
+		banner_done = 1;
+	}
+}
+
+
+/**
+ * dc395x_init_one - Initialise a single instance of the adapter.
+ *
+ * The PCI layer will call this once for each instance of the adapter
+ * that it finds in the system. The pci_dev strcuture indicates which
+ * instance we are being called from.
+ * 
+ * @dev: The PCI device to intialize.
+ * @id: Looks like a pointer to the entry in our pci device table
+ * that was actually matched by the PCI subsystem.
+ *
+ * Returns 0 on success, or an error code (-ve) on failure.
+ **/
+static int __devinit dc395x_init_one(struct pci_dev *dev,
+		const struct pci_device_id *id)
+{
+	struct Scsi_Host *scsi_host = NULL;
+	struct AdapterCtlBlk *acb = NULL;
+	unsigned long io_port_base;
+	unsigned int io_port_len;
+	unsigned int irq;
+	
+	dprintkdbg(DBG_0, "Init one instance (%s)\n", pci_name(dev));
+	banner_display();
+
+	if (pci_enable_device(dev))
+	{
+		dprintkl(KERN_INFO, "PCI Enable device failed.\n");
+		return -ENODEV;
+	}
+	io_port_base = pci_resource_start(dev, 0) & PCI_BASE_ADDRESS_IO_MASK;
+	io_port_len = pci_resource_len(dev, 0);
+	irq = dev->irq;
+	dprintkdbg(DBG_0, "IO_PORT=0x%04lx, IRQ=0x%x\n", io_port_base, dev->irq);
+
+	/* allocate scsi host information (includes out adapter) */
+	scsi_host = scsi_host_alloc(&dc395x_driver_template,
+				    sizeof(struct AdapterCtlBlk));
+	if (!scsi_host) {
+		dprintkl(KERN_INFO, "scsi_host_alloc failed\n");
+		goto fail;
+	}
+ 	acb = (struct AdapterCtlBlk*)scsi_host->hostdata;
+ 	acb->scsi_host = scsi_host;
+ 	acb->dev = dev;
+
+	/* initialise the adapter and everything we need */
+ 	if (adapter_init(acb, io_port_base, io_port_len, irq)) {
+		dprintkl(KERN_INFO, "adapter init failed\n");
+		goto fail;
+	}
+
+	pci_set_master(dev);
+
+	/* get the scsi mid level to scan for new devices on the bus */
+	if (scsi_add_host(scsi_host, &dev->dev)) {
+		dprintkl(KERN_ERR, "scsi_add_host failed\n");
+		goto fail;
+	}
+	pci_set_drvdata(dev, scsi_host);
+	scsi_scan_host(scsi_host);
+        	
+	return 0;
+
+fail:
+	if (acb != NULL)
+		adapter_uninit(acb);
+	if (scsi_host != NULL)
+		scsi_host_put(scsi_host);
+	pci_disable_device(dev);
+	return -ENODEV;
+}
+
+
+/**
+ * dc395x_remove_one - Called to remove a single instance of the
+ * adapter.
+ *
+ * @dev: The PCI device to intialize.
+ **/
+static void __devexit dc395x_remove_one(struct pci_dev *dev)
+{
+	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
+	struct AdapterCtlBlk *acb = (struct AdapterCtlBlk *)(scsi_host->hostdata);
+
+	dprintkdbg(DBG_0, "dc395x_remove_one: acb=%p\n", acb);
+
+	scsi_remove_host(scsi_host);
+	adapter_uninit(acb);
+	pci_disable_device(dev);
+	scsi_host_put(scsi_host);
+	pci_set_drvdata(dev, NULL);
+}
+
+
+static struct pci_device_id dc395x_pci_table[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_TEKRAM,
+		.device		= PCI_DEVICE_ID_TEKRAM_TRMS1040,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+	 },
+	{}			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, dc395x_pci_table);
+
+
+static struct pci_driver dc395x_driver = {
+	.name           = DC395X_NAME,
+	.id_table       = dc395x_pci_table,
+	.probe          = dc395x_init_one,
+	.remove         = __devexit_p(dc395x_remove_one),
+};
+
+
+/**
+ * dc395x_module_init - Module initialization function
+ *
+ * Used by both module and built-in driver to initialise this driver.
+ **/
+static int __init dc395x_module_init(void)
+{
+	return pci_module_init(&dc395x_driver);
+}
+
+
+/**
+ * dc395x_module_exit - Module cleanup function.
+ **/
+static void __exit dc395x_module_exit(void)
+{
+	pci_unregister_driver(&dc395x_driver);
+}
+
+
+module_init(dc395x_module_init);
+module_exit(dc395x_module_exit);
+
+MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dc395x.h b/drivers/scsi/dc395x.h
new file mode 100644
index 0000000..b38360e
--- /dev/null
+++ b/drivers/scsi/dc395x.h
@@ -0,0 +1,648 @@
+/************************************************************************/
+/*									*/
+/*	dc395x.h							*/
+/*									*/
+/*	Device Driver for Tekram DC395(U/UW/F), DC315(U)		*/
+/*	PCI SCSI Bus Master Host Adapter				*/
+/*	(SCSI chip set used Tekram ASIC TRM-S1040)			*/
+/*									*/
+/************************************************************************/
+#ifndef DC395x_H
+#define DC395x_H
+
+/************************************************************************/
+/*									*/
+/*	Initial values							*/
+/*									*/
+/************************************************************************/
+#define DC395x_MAX_CMD_QUEUE		32
+/* #define DC395x_MAX_QTAGS		32 */
+#define DC395x_MAX_QTAGS		16
+#define DC395x_MAX_SCSI_ID		16
+#define DC395x_MAX_CMD_PER_LUN		DC395x_MAX_QTAGS
+#define DC395x_MAX_SG_TABLESIZE		64	/* HW limitation			*/
+#define DC395x_MAX_SG_LISTENTRY		64	/* Must be equal or lower to previous	*/
+						/* item					*/
+#define DC395x_MAX_SRB_CNT		63
+/* #define DC395x_MAX_CAN_QUEUE		7 * DC395x_MAX_QTAGS */
+#define DC395x_MAX_CAN_QUEUE		DC395x_MAX_SRB_CNT
+#define DC395x_END_SCAN			2
+#define DC395x_SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz)	*/
+#define DC395x_MAX_RETRIES		3
+
+#if 0
+#define SYNC_FIRST
+#endif
+
+#define NORM_REC_LVL			0
+
+/************************************************************************/
+/*									*/
+/*	Various definitions						*/
+/*									*/
+/************************************************************************/
+#define BIT31				0x80000000
+#define BIT30				0x40000000
+#define BIT29				0x20000000
+#define BIT28				0x10000000
+#define BIT27				0x08000000
+#define BIT26				0x04000000
+#define BIT25				0x02000000
+#define BIT24				0x01000000
+#define BIT23				0x00800000
+#define BIT22				0x00400000
+#define BIT21				0x00200000
+#define BIT20				0x00100000
+#define BIT19				0x00080000
+#define BIT18				0x00040000
+#define BIT17				0x00020000
+#define BIT16				0x00010000
+#define BIT15				0x00008000
+#define BIT14				0x00004000
+#define BIT13				0x00002000
+#define BIT12				0x00001000
+#define BIT11				0x00000800
+#define BIT10				0x00000400
+#define BIT9				0x00000200
+#define BIT8				0x00000100
+#define BIT7				0x00000080
+#define BIT6				0x00000040
+#define BIT5				0x00000020
+#define BIT4				0x00000010
+#define BIT3				0x00000008
+#define BIT2				0x00000004
+#define BIT1				0x00000002
+#define BIT0				0x00000001
+
+/* UnitCtrlFlag */
+#define UNIT_ALLOCATED			BIT0
+#define UNIT_INFO_CHANGED		BIT1
+#define FORMATING_MEDIA			BIT2
+#define UNIT_RETRY			BIT3
+
+/* UnitFlags */
+#define DASD_SUPPORT			BIT0
+#define SCSI_SUPPORT			BIT1
+#define ASPI_SUPPORT			BIT2
+
+/* SRBState machine definition */
+#define SRB_FREE			0x0000
+#define SRB_WAIT			0x0001
+#define SRB_READY			0x0002
+#define SRB_MSGOUT			0x0004	/* arbitration+msg_out 1st byte		*/
+#define SRB_MSGIN			0x0008
+#define SRB_EXTEND_MSGIN		0x0010
+#define SRB_COMMAND			0x0020
+#define SRB_START_			0x0040	/* arbitration+msg_out+command_out	*/
+#define SRB_DISCONNECT			0x0080
+#define SRB_DATA_XFER			0x0100
+#define SRB_XFERPAD			0x0200
+#define SRB_STATUS			0x0400
+#define SRB_COMPLETED			0x0800
+#define SRB_ABORT_SENT			0x1000
+#define SRB_DO_SYNC_NEGO		0x2000
+#define SRB_DO_WIDE_NEGO		0x4000
+#define SRB_UNEXPECT_RESEL		0x8000
+
+/************************************************************************/
+/*									*/
+/*	ACB Config							*/
+/*									*/
+/************************************************************************/
+#define HCC_WIDE_CARD			0x20
+#define HCC_SCSI_RESET			0x10
+#define HCC_PARITY			0x08
+#define HCC_AUTOTERM			0x04
+#define HCC_LOW8TERM			0x02
+#define HCC_UP8TERM			0x01
+
+/* ACBFlag */
+#define RESET_DEV			BIT0
+#define RESET_DETECT			BIT1
+#define RESET_DONE			BIT2
+
+/* DCBFlag */
+#define ABORT_DEV_			BIT0
+
+/* SRBstatus */
+#define SRB_OK				BIT0
+#define ABORTION			BIT1
+#define OVER_RUN			BIT2
+#define UNDER_RUN			BIT3
+#define PARITY_ERROR			BIT4
+#define SRB_ERROR			BIT5
+
+/* SRBFlag */
+#define DATAOUT				BIT7
+#define DATAIN				BIT6
+#define RESIDUAL_VALID			BIT5
+#define ENABLE_TIMER			BIT4
+#define RESET_DEV0			BIT2
+#define ABORT_DEV			BIT1
+#define AUTO_REQSENSE			BIT0
+
+/* Adapter status */
+#define H_STATUS_GOOD			0
+#define H_SEL_TIMEOUT			0x11
+#define H_OVER_UNDER_RUN		0x12
+#define H_UNEXP_BUS_FREE		0x13
+#define H_TARGET_PHASE_F		0x14
+#define H_INVALID_CCB_OP		0x16
+#define H_LINK_CCB_BAD			0x17
+#define H_BAD_TARGET_DIR		0x18
+#define H_DUPLICATE_CCB			0x19
+#define H_BAD_CCB_OR_SG			0x1A
+#define H_ABORT				0x0FF
+
+/* SCSI BUS Status byte codes */
+#define SCSI_STAT_GOOD			0x0	/* Good status				*/
+#define SCSI_STAT_CHECKCOND		0x02	/* SCSI Check Condition			*/
+#define SCSI_STAT_CONDMET		0x04	/* Condition Met			*/
+#define SCSI_STAT_BUSY			0x08	/* Target busy status			*/
+#define SCSI_STAT_INTER			0x10	/* Intermediate status			*/
+#define SCSI_STAT_INTERCONDMET		0x14	/* Intermediate condition met		*/
+#define SCSI_STAT_RESCONFLICT		0x18	/* Reservation conflict			*/
+#define SCSI_STAT_CMDTERM		0x22	/* Command Terminated			*/
+#define SCSI_STAT_QUEUEFULL		0x28	/* Queue Full				*/
+#define SCSI_STAT_UNEXP_BUS_F		0xFD	/* Unexpect Bus Free			*/
+#define SCSI_STAT_BUS_RST_DETECT	0xFE	/* Scsi Bus Reset detected		*/
+#define SCSI_STAT_SEL_TIMEOUT		0xFF	/* Selection Time out			*/
+
+/* Sync_Mode */
+#define SYNC_WIDE_TAG_ATNT_DISABLE	0
+#define SYNC_NEGO_ENABLE		BIT0
+#define SYNC_NEGO_DONE			BIT1
+#define WIDE_NEGO_ENABLE		BIT2
+#define WIDE_NEGO_DONE			BIT3
+#define WIDE_NEGO_STATE			BIT4
+#define EN_TAG_QUEUEING			BIT5
+#define EN_ATN_STOP			BIT6
+
+#define SYNC_NEGO_OFFSET		15
+
+/* SCSI MSG BYTE */
+#define MSG_COMPLETE			0x00
+#define MSG_EXTENDED			0x01
+#define MSG_SAVE_PTR			0x02
+#define MSG_RESTORE_PTR			0x03
+#define MSG_DISCONNECT			0x04
+#define MSG_INITIATOR_ERROR		0x05
+#define MSG_ABORT			0x06
+#define MSG_REJECT_			0x07
+#define MSG_NOP				0x08
+#define MSG_PARITY_ERROR		0x09
+#define MSG_LINK_CMD_COMPL		0x0A
+#define MSG_LINK_CMD_COMPL_FLG		0x0B
+#define MSG_BUS_RESET			0x0C
+#define MSG_ABORT_TAG			0x0D
+#define MSG_SIMPLE_QTAG			0x20
+#define MSG_HEAD_QTAG			0x21
+#define MSG_ORDER_QTAG			0x22
+#define MSG_IGNOREWIDE			0x23
+#define MSG_IDENTIFY			0x80
+#define MSG_HOST_ID			0xC0
+
+/* SCSI STATUS BYTE */
+#define STATUS_GOOD			0x00
+#define CHECK_CONDITION_		0x02
+#define STATUS_BUSY			0x08
+#define STATUS_INTERMEDIATE		0x10
+#define RESERVE_CONFLICT		0x18
+
+/* cmd->result */
+#define STATUS_MASK_			0xFF
+#define MSG_MASK			0xFF00
+#define RETURN_MASK			0xFF0000
+
+/************************************************************************/
+/*									*/
+/*	Inquiry Data format						*/
+/*									*/
+/************************************************************************/
+struct ScsiInqData
+{						/* INQ					*/
+	u8 DevType;				/* Periph Qualifier & Periph Dev Type	*/
+	u8 RMB_TypeMod;				/* rem media bit & Dev Type Modifier	*/
+	u8 Vers;				/* ISO, ECMA, & ANSI versions		*/
+	u8 RDF;					/* AEN, TRMIOP, & response data format	*/
+	u8 AddLen;				/* length of additional data		*/
+	u8 Res1;				/* reserved				*/
+	u8 Res2;				/* reserved				*/
+	u8 Flags;				/* RelADr, Wbus32, Wbus16, Sync, etc.	*/
+	u8 VendorID[8];				/* Vendor Identification		*/
+	u8 ProductID[16];			/* Product Identification		*/
+	u8 ProductRev[4];			/* Product Revision			*/
+};
+
+						/* Inquiry byte 0 masks			*/
+#define SCSI_DEVTYPE			0x1F	/* Peripheral Device Type		*/
+#define SCSI_PERIPHQUAL			0xE0	/* Peripheral Qualifier			*/
+						/* Inquiry byte 1 mask			*/
+#define SCSI_REMOVABLE_MEDIA		0x80	/* Removable Media bit (1=removable)	*/
+						/* Peripheral Device Type definitions	*/
+						/* See include/scsi/scsi.h		*/
+#define TYPE_NODEV		SCSI_DEVTYPE	/* Unknown or no device type		*/
+#ifndef TYPE_PRINTER				/*					*/
+# define TYPE_PRINTER			0x02	/* Printer device			*/
+#endif						/*					*/
+#ifndef TYPE_COMM				/*					*/
+# define TYPE_COMM			0x09	/* Communications device		*/
+#endif
+
+/************************************************************************/
+/*									*/
+/*	Inquiry flag definitions (Inq data byte 7)			*/
+/*									*/
+/************************************************************************/
+#define SCSI_INQ_RELADR			0x80	/* device supports relative addressing	*/
+#define SCSI_INQ_WBUS32			0x40	/* device supports 32 bit data xfers	*/
+#define SCSI_INQ_WBUS16			0x20	/* device supports 16 bit data xfers	*/
+#define SCSI_INQ_SYNC			0x10	/* device supports synchronous xfer	*/
+#define SCSI_INQ_LINKED			0x08	/* device supports linked commands	*/
+#define SCSI_INQ_CMDQUEUE		0x02	/* device supports command queueing	*/
+#define SCSI_INQ_SFTRE			0x01	/* device supports soft resets		*/
+
+#define ENABLE_CE			1
+#define DISABLE_CE			0
+#define EEPROM_READ			0x80
+
+/************************************************************************/
+/*									*/
+/*	The PCI configuration register offset for TRM_S1040		*/
+/*									*/
+/************************************************************************/
+#define TRM_S1040_ID			0x00	/* Vendor and Device ID			*/
+#define TRM_S1040_COMMAND		0x04	/* PCI command register			*/
+#define TRM_S1040_IOBASE		0x10	/* I/O Space base address		*/
+#define TRM_S1040_ROMBASE		0x30	/* Expansion ROM Base Address		*/
+#define TRM_S1040_INTLINE		0x3C	/* Interrupt line			*/
+
+/************************************************************************/
+/*									*/
+/*	The SCSI register offset for TRM_S1040				*/
+/*									*/
+/************************************************************************/
+#define TRM_S1040_SCSI_STATUS		0x80	/* SCSI Status (R)			*/
+#define COMMANDPHASEDONE		0x2000	/* SCSI command phase done		*/
+#define SCSIXFERDONE			0x0800	/* SCSI SCSI transfer done		*/
+#define SCSIXFERCNT_2_ZERO		0x0100	/* SCSI SCSI transfer count to zero	*/
+#define SCSIINTERRUPT			0x0080	/* SCSI interrupt pending		*/
+#define COMMANDABORT			0x0040	/* SCSI command abort			*/
+#define SEQUENCERACTIVE			0x0020	/* SCSI sequencer active		*/
+#define PHASEMISMATCH			0x0010	/* SCSI phase mismatch			*/
+#define PARITYERROR			0x0008	/* SCSI parity error			*/
+
+#define PHASEMASK			0x0007	/* Phase MSG/CD/IO			*/
+#define PH_DATA_OUT			0x00	/* Data out phase			*/
+#define PH_DATA_IN			0x01	/* Data in phase			*/
+#define PH_COMMAND			0x02	/* Command phase			*/
+#define PH_STATUS			0x03	/* Status phase				*/
+#define PH_BUS_FREE			0x05	/* Invalid phase used as bus free	*/
+#define PH_MSG_OUT			0x06	/* Message out phase			*/
+#define PH_MSG_IN			0x07	/* Message in phase			*/
+
+#define TRM_S1040_SCSI_CONTROL		0x80	/* SCSI Control (W)			*/
+#define DO_CLRATN			0x0400	/* Clear ATN				*/
+#define DO_SETATN			0x0200	/* Set ATN				*/
+#define DO_CMDABORT			0x0100	/* Abort SCSI command			*/
+#define DO_RSTMODULE			0x0010	/* Reset SCSI chip			*/
+#define DO_RSTSCSI			0x0008	/* Reset SCSI bus			*/
+#define DO_CLRFIFO			0x0004	/* Clear SCSI transfer FIFO		*/
+#define DO_DATALATCH			0x0002	/* Enable SCSI bus data input (latched)	*/
+/* #define DO_DATALATCH			0x0000 */	/* KG: DISable SCSI bus data latch	*/
+#define DO_HWRESELECT			0x0001	/* Enable hardware reselection		*/
+
+#define TRM_S1040_SCSI_FIFOCNT		0x82	/* SCSI FIFO Counter 5bits(R)		*/
+#define TRM_S1040_SCSI_SIGNAL		0x83	/* SCSI low level signal (R/W)		*/
+
+#define TRM_S1040_SCSI_INTSTATUS	0x84	/* SCSI Interrupt Status (R)		*/
+#define INT_SCAM			0x80	/* SCAM selection interrupt		*/
+#define INT_SELECT			0x40	/* Selection interrupt			*/
+#define INT_SELTIMEOUT			0x20	/* Selection timeout interrupt		*/
+#define INT_DISCONNECT			0x10	/* Bus disconnected interrupt		*/
+#define INT_RESELECTED			0x08	/* Reselected interrupt			*/
+#define INT_SCSIRESET			0x04	/* SCSI reset detected interrupt	*/
+#define INT_BUSSERVICE			0x02	/* Bus service interrupt		*/
+#define INT_CMDDONE			0x01	/* SCSI command done interrupt		*/
+
+#define TRM_S1040_SCSI_OFFSET		0x84	/* SCSI Offset Count (W)		*/
+
+/************************************************************************/
+/*									*/
+/*	Bit		Name		Definition			*/
+/*	---------	-------------	----------------------------	*/
+/*	07-05	0	RSVD		Reversed. Always 0.		*/
+/*	04	0	OFFSET4		Reversed for LVDS. Always 0.	*/
+/*	03-00	0	OFFSET[03:00]	Offset number from 0 to 15	*/
+/*									*/
+/************************************************************************/
+
+#define TRM_S1040_SCSI_SYNC		0x85	/* SCSI Synchronous Control (R/W)	*/
+#define LVDS_SYNC			0x20	/* Enable LVDS synchronous		*/
+#define WIDE_SYNC			0x10	/* Enable WIDE synchronous		*/
+#define ALT_SYNC			0x08	/* Enable Fast-20 alternate synchronous	*/
+
+/************************************************************************/
+/*									*/
+/*	SYNCM	7    6    5    4    3       2       1       0		*/
+/*	Name	RSVD RSVD LVDS WIDE ALTPERD PERIOD2 PERIOD1 PERIOD0	*/
+/*	Default	0    0    0    0    0       0       0       0		*/
+/*									*/
+/*	Bit		Name		Definition			*/
+/*	---------	-------------	---------------------------	*/
+/*	07-06	0	RSVD		Reversed. Always read 0		*/
+/*	05	0	LVDS		Reversed. Always read 0		*/
+/*	04	0	WIDE/WSCSI	Enable wide (16-bits) SCSI	*/
+/*					transfer.			*/
+/*	03	0	ALTPERD/ALTPD	Alternate (Sync./Period) mode.	*/
+/*									*/
+/*			@@ When this bit is set,			*/
+/*			   the synchronous period bits 2:0		*/
+/*			   in the Synchronous Mode register		*/
+/*			   are used to transfer data			*/
+/*			   at the Fast-20 rate.				*/
+/*			@@ When this bit is unset,			*/
+/*			   the synchronous period bits 2:0		*/
+/*			   in the Synchronous Mode Register		*/
+/*			   are used to transfer data			*/
+/*			   at the Fast-10 rate (or Fast-40 w/ LVDS).	*/
+/*									*/
+/*	02-00	0	PERIOD[2:0]/	Synchronous SCSI Transfer Rate.	*/
+/*			SXPD[02:00]	These 3 bits specify		*/
+/*					the Synchronous SCSI Transfer	*/
+/*					Rate for Fast-20 and Fast-10.	*/
+/*					These bits are also reset	*/
+/*					by a SCSI Bus reset.		*/
+/*									*/
+/*	For Fast-10 bit ALTPD = 0 and LVDS = 0				*/
+/*	and bit2,bit1,bit0 is defined as follows :			*/
+/*									*/
+/*	000	100ns, 10.0 MHz						*/
+/*	001	150ns,  6.6 MHz						*/
+/*	010	200ns,  5.0 MHz						*/
+/*	011	250ns,  4.0 MHz						*/
+/*	100	300ns,  3.3 MHz						*/
+/*	101	350ns,  2.8 MHz						*/
+/*	110	400ns,  2.5 MHz						*/
+/*	111	450ns,  2.2 MHz						*/
+/*									*/
+/*	For Fast-20 bit ALTPD = 1 and LVDS = 0				*/
+/*	and bit2,bit1,bit0 is defined as follows :			*/
+/*									*/
+/*	000	 50ns, 20.0 MHz						*/
+/*	001	 75ns, 13.3 MHz						*/
+/*	010	100ns, 10.0 MHz						*/
+/*	011	125ns,  8.0 MHz						*/
+/*	100	150ns,  6.6 MHz						*/
+/*	101	175ns,  5.7 MHz						*/
+/*	110	200ns,  5.0 MHz						*/
+/*	111	250ns,  4.0 MHz   KG: Maybe 225ns, 4.4 MHz		*/
+/*									*/
+/*	For Fast-40 bit ALTPD = 0 and LVDS = 1				*/
+/*	and bit2,bit1,bit0 is defined as follows :			*/
+/*									*/
+/*	000	 25ns, 40.0 MHz						*/
+/*	001	 50ns, 20.0 MHz						*/
+/*	010	 75ns, 13.3 MHz						*/
+/*	011	100ns, 10.0 MHz						*/
+/*	100	125ns,  8.0 MHz						*/
+/*	101	150ns,  6.6 MHz						*/
+/*	110	175ns,  5.7 MHz						*/
+/*	111	200ns,  5.0 MHz						*/
+/*									*/
+/************************************************************************/
+
+#define TRM_S1040_SCSI_TARGETID		0x86	/* SCSI Target ID (R/W)			*/
+#define TRM_S1040_SCSI_IDMSG		0x87	/* SCSI Identify Message (R)		*/
+#define TRM_S1040_SCSI_HOSTID		0x87	/* SCSI Host ID (W)			*/
+#define TRM_S1040_SCSI_COUNTER		0x88	/* SCSI Transfer Counter 24bits(R/W)	*/
+
+#define TRM_S1040_SCSI_INTEN		0x8C	/* SCSI Interrupt Enable (R/W)		*/
+#define EN_SCAM				0x80	/* Enable SCAM selection interrupt	*/
+#define EN_SELECT			0x40	/* Enable selection interrupt		*/
+#define EN_SELTIMEOUT			0x20	/* Enable selection timeout interrupt	*/
+#define EN_DISCONNECT			0x10	/* Enable bus disconnected interrupt	*/
+#define EN_RESELECTED			0x08	/* Enable reselected interrupt		*/
+#define EN_SCSIRESET			0x04	/* Enable SCSI reset detected interrupt	*/
+#define EN_BUSSERVICE			0x02	/* Enable bus service interrupt		*/
+#define EN_CMDDONE			0x01	/* Enable SCSI command done interrupt	*/
+
+#define TRM_S1040_SCSI_CONFIG0		0x8D	/* SCSI Configuration 0 (R/W)		*/
+#define PHASELATCH			0x40	/* Enable phase latch			*/
+#define INITIATOR			0x20	/* Enable initiator mode		*/
+#define PARITYCHECK			0x10	/* Enable parity check			*/
+#define BLOCKRST			0x01	/* Disable SCSI reset1			*/
+
+#define TRM_S1040_SCSI_CONFIG1		0x8E	/* SCSI Configuration 1 (R/W)		*/
+#define ACTIVE_NEGPLUS			0x10	/* Enhance active negation		*/
+#define FILTER_DISABLE			0x08	/* Disable SCSI data filter		*/
+#define FAST_FILTER			0x04	/* ?					*/
+#define ACTIVE_NEG			0x02	/* Enable active negation		*/
+
+#define TRM_S1040_SCSI_CONFIG2		0x8F	/* SCSI Configuration 2 (R/W)		*/
+#define CFG2_WIDEFIFO			0x02	/*					*/
+
+#define TRM_S1040_SCSI_COMMAND		0x90	/* SCSI Command (R/W)			*/
+#define SCMD_COMP			0x12	/* Command complete			*/
+#define SCMD_SEL_ATN			0x60	/* Selection with ATN			*/
+#define SCMD_SEL_ATN3			0x64	/* Selection with ATN3			*/
+#define SCMD_SEL_ATNSTOP		0xB8	/* Selection with ATN and Stop		*/
+#define SCMD_FIFO_OUT			0xC0	/* SCSI FIFO transfer out		*/
+#define SCMD_DMA_OUT			0xC1	/* SCSI DMA transfer out		*/
+#define SCMD_FIFO_IN			0xC2	/* SCSI FIFO transfer in		*/
+#define SCMD_DMA_IN			0xC3	/* SCSI DMA transfer in			*/
+#define SCMD_MSGACCEPT			0xD8	/* Message accept			*/
+
+/************************************************************************/
+/*									*/
+/*	Code	Command Description					*/
+/*	----	----------------------------------------		*/
+/*	02	Enable reselection with FIFO				*/
+/*	40	Select without ATN with FIFO				*/
+/*	60	Select with ATN with FIFO				*/
+/*	64	Select with ATN3 with FIFO				*/
+/*	A0	Select with ATN and stop with FIFO			*/
+/*	C0	Transfer information out with FIFO			*/
+/*	C1	Transfer information out with DMA			*/
+/*	C2	Transfer information in with FIFO			*/
+/*	C3	Transfer information in with DMA			*/
+/*	12	Initiator command complete with FIFO			*/
+/*	50	Initiator transfer information out sequence without ATN	*/
+/*		with FIFO						*/
+/*	70	Initiator transfer information out sequence with ATN	*/
+/*		with FIFO						*/
+/*	74	Initiator transfer information out sequence with ATN3	*/
+/*		with FIFO						*/
+/*	52	Initiator transfer information in sequence without ATN	*/
+/*		with FIFO						*/
+/*	72	Initiator transfer information in sequence with ATN	*/
+/*		with FIFO						*/
+/*	76	Initiator transfer information in sequence with ATN3	*/
+/*		with FIFO						*/
+/*	90	Initiator transfer information out command complete	*/
+/*		with FIFO						*/
+/*	92	Initiator transfer information in command complete	*/
+/*		with FIFO						*/
+/*	D2	Enable selection					*/
+/*	08	Reselection						*/
+/*	48	Disconnect command with FIFO				*/
+/*	88	Terminate command with FIFO				*/
+/*	C8	Target command complete with FIFO			*/
+/*	18	SCAM Arbitration/ Selection				*/
+/*	5A	Enable reselection					*/
+/*	98	Select without ATN with FIFO				*/
+/*	B8	Select with ATN with FIFO				*/
+/*	D8	Message Accepted					*/
+/*	58	NOP							*/
+/*									*/
+/************************************************************************/
+
+#define TRM_S1040_SCSI_TIMEOUT		0x91	/* SCSI Time Out Value (R/W)		*/
+#define TRM_S1040_SCSI_FIFO		0x98	/* SCSI FIFO (R/W)			*/
+
+#define TRM_S1040_SCSI_TCR0		0x9C	/* SCSI Target Control 0 (R/W)		*/
+#define TCR0_WIDE_NEGO_DONE		0x8000	/* Wide nego done			*/
+#define TCR0_SYNC_NEGO_DONE		0x4000	/* Synchronous nego done		*/
+#define TCR0_ENABLE_LVDS		0x2000	/* Enable LVDS synchronous		*/
+#define TCR0_ENABLE_WIDE		0x1000	/* Enable WIDE synchronous		*/
+#define TCR0_ENABLE_ALT			0x0800	/* Enable alternate synchronous		*/
+#define TCR0_PERIOD_MASK		0x0700	/* Transfer rate			*/
+
+#define TCR0_DO_WIDE_NEGO		0x0080	/* Do wide NEGO				*/
+#define TCR0_DO_SYNC_NEGO		0x0040	/* Do sync NEGO				*/
+#define TCR0_DISCONNECT_EN		0x0020	/* Disconnection enable			*/
+#define TCR0_OFFSET_MASK		0x001F	/* Offset number			*/
+
+#define TRM_S1040_SCSI_TCR1		0x9E	/* SCSI Target Control 1 (R/W)		*/
+#define MAXTAG_MASK			0x7F00	/* Maximum tags (127)			*/
+#define NON_TAG_BUSY			0x0080	/* Non tag command active		*/
+#define ACTTAG_MASK			0x007F	/* Active tags				*/
+
+/************************************************************************/
+/*									*/
+/*	The DMA register offset for TRM_S1040				*/
+/*									*/
+/************************************************************************/
+#define TRM_S1040_DMA_COMMAND		0xA0	/* DMA Command (R/W)			*/
+#define DMACMD_SG			0x02	/* Enable HW S/G support		*/
+#define DMACMD_DIR			0x01	/* 1 = read from SCSI write to Host	*/
+#define XFERDATAIN_SG			0x0103	/* Transfer data in  w/  SG		*/
+#define XFERDATAOUT_SG			0x0102	/* Transfer data out w/  SG		*/
+#define XFERDATAIN			0x0101	/* Transfer data in  w/o SG		*/
+#define XFERDATAOUT			0x0100	/* Transfer data out w/o SG		*/
+
+#define TRM_S1040_DMA_FIFOCNT		0xA1	/* DMA FIFO Counter (R)			*/
+
+#define TRM_S1040_DMA_CONTROL		0xA1	/* DMA Control (W)			*/
+#define DMARESETMODULE			0x10	/* Reset PCI/DMA module			*/
+#define STOPDMAXFER			0x08	/* Stop  DMA transfer			*/
+#define ABORTXFER			0x04	/* Abort DMA transfer			*/
+#define CLRXFIFO			0x02	/* Clear DMA transfer FIFO		*/
+#define STARTDMAXFER			0x01	/* Start DMA transfer			*/
+
+#define TRM_S1040_DMA_FIFOSTAT		0xA2	/* DMA FIFO Status (R)			*/
+
+#define TRM_S1040_DMA_STATUS		0xA3	/* DMA Interrupt Status (R/W)		*/
+#define XFERPENDING			0x80	/* Transfer pending			*/
+#define SCSIBUSY			0x40	/* SCSI busy				*/
+#define GLOBALINT			0x20	/* DMA_INTEN bit 0-4 set		*/
+#define FORCEDMACOMP			0x10	/* Force DMA transfer complete		*/
+#define DMAXFERERROR			0x08	/* DMA transfer error			*/
+#define DMAXFERABORT			0x04	/* DMA transfer abort			*/
+#define DMAXFERCOMP			0x02	/* Bus Master XFER Complete status	*/
+#define SCSICOMP			0x01	/* SCSI complete interrupt		*/
+
+#define TRM_S1040_DMA_INTEN		0xA4	/* DMA Interrupt Enable (R/W)		*/
+#define EN_FORCEDMACOMP			0x10	/* Force DMA transfer complete		*/
+#define EN_DMAXFERERROR			0x08	/* DMA transfer error			*/
+#define EN_DMAXFERABORT			0x04	/* DMA transfer abort			*/
+#define EN_DMAXFERCOMP			0x02	/* Bus Master XFER Complete status	*/
+#define EN_SCSIINTR			0x01	/* Enable SCSI complete interrupt	*/
+
+#define TRM_S1040_DMA_CONFIG		0xA6	/* DMA Configuration (R/W)		*/
+#define DMA_ENHANCE			0x8000	/* Enable DMA enhance feature (SG?)	*/
+#define DMA_PCI_DUAL_ADDR		0x4000	/*					*/
+#define DMA_CFG_RES			0x2000	/* Always 1				*/
+#define DMA_AUTO_CLR_FIFO		0x1000	/* DISable DMA auto clear FIFO		*/
+#define DMA_MEM_MULTI_READ		0x0800	/*					*/
+#define DMA_MEM_WRITE_INVAL		0x0400	/* Memory write and invalidate		*/
+#define DMA_FIFO_CTRL			0x0300	/* Control FIFO operation with DMA	*/
+#define DMA_FIFO_HALF_HALF		0x0200	/* Keep half filled on both read/write	*/
+
+#define TRM_S1040_DMA_XCNT		0xA8	/* DMA Transfer Counter (R/W), 24bits	*/
+#define TRM_S1040_DMA_CXCNT		0xAC	/* DMA Current Transfer Counter (R)	*/
+#define TRM_S1040_DMA_XLOWADDR		0xB0	/* DMA Transfer Physical Low Address	*/
+#define TRM_S1040_DMA_XHIGHADDR		0xB4	/* DMA Transfer Physical High Address	*/
+
+/************************************************************************/
+/*									*/
+/*	The general register offset for TRM_S1040			*/
+/*									*/
+/************************************************************************/
+#define TRM_S1040_GEN_CONTROL		0xD4	/* Global Control			*/
+#define CTRL_LED			0x80	/* Control onboard LED			*/
+#define EN_EEPROM			0x10	/* Enable EEPROM programming		*/
+#define DIS_TERM			0x08	/* Disable onboard termination		*/
+#define AUTOTERM			0x04	/* Enable Auto SCSI terminator		*/
+#define LOW8TERM			0x02	/* Enable Lower 8 bit SCSI terminator	*/
+#define UP8TERM				0x01	/* Enable Upper 8 bit SCSI terminator	*/
+
+#define TRM_S1040_GEN_STATUS		0xD5	/* Global Status			*/
+#define GTIMEOUT			0x80	/* Global timer reach 0			*/
+#define EXT68HIGH			0x40	/* Higher 8 bit connected externally	*/
+#define INT68HIGH			0x20	/* Higher 8 bit connected internally	*/
+#define CON5068				0x10	/* External 50/68 pin connected (low)	*/
+#define CON68				0x08	/* Internal 68 pin connected (low)	*/
+#define CON50				0x04	/* Internal 50 pin connected (low!)	*/
+#define WIDESCSI			0x02	/* Wide SCSI card			*/
+#define STATUS_LOAD_DEFAULT		0x01	/*					*/
+
+#define TRM_S1040_GEN_NVRAM		0xD6	/* Serial NON-VOLATILE RAM port		*/
+#define NVR_BITOUT			0x08	/* Serial data out			*/
+#define NVR_BITIN			0x04	/* Serial data in			*/
+#define NVR_CLOCK			0x02	/* Serial clock				*/
+#define NVR_SELECT			0x01	/* Serial select			*/
+
+#define TRM_S1040_GEN_EDATA		0xD7	/* Parallel EEPROM data port		*/
+#define TRM_S1040_GEN_EADDRESS		0xD8	/* Parallel EEPROM address		*/
+#define TRM_S1040_GEN_TIMER		0xDB	/* Global timer				*/
+
+/************************************************************************/
+/*									*/
+/*	NvmTarCfg0: Target configuration byte 0 :..pDCB->DevMode	*/
+/*									*/
+/************************************************************************/
+#define NTC_DO_WIDE_NEGO		0x20	/* Wide negotiate			*/
+#define NTC_DO_TAG_QUEUEING		0x10	/* Enable SCSI tag queuing		*/
+#define NTC_DO_SEND_START		0x08	/* Send start command SPINUP		*/
+#define NTC_DO_DISCONNECT		0x04	/* Enable SCSI disconnect		*/
+#define NTC_DO_SYNC_NEGO		0x02	/* Sync negotiation			*/
+#define NTC_DO_PARITY_CHK		0x01	/* (it sould define at NAC)		*/
+						/* Parity check enable			*/
+
+/************************************************************************/
+/*									*/
+/*	Nvram Initiater bits definition					*/
+/*									*/
+/************************************************************************/
+#if 0
+#define MORE2_DRV			BIT0
+#define GREATER_1G			BIT1
+#define RST_SCSI_BUS			BIT2
+#define ACTIVE_NEGATION			BIT3
+#define NO_SEEK				BIT4
+#define LUN_CHECK			BIT5
+#endif
+
+/************************************************************************/
+/*									*/
+/*	Nvram Adapter Cfg bits definition				*/
+/*									*/
+/************************************************************************/
+#define NAC_SCANLUN			0x20	/* Include LUN as BIOS device		*/
+#define NAC_POWERON_SCSI_RESET		0x04	/* Power on reset enable		*/
+#define NAC_GREATER_1G			0x02	/* > 1G support enable			*/
+#define NAC_GT2DRIVES			0x01	/* Support more than 2 drives		*/
+/* #define NAC_DO_PARITY_CHK		0x08 */	/* Parity check enable			*/
+
+#endif
diff --git a/drivers/scsi/dec_esp.c b/drivers/scsi/dec_esp.c
new file mode 100644
index 0000000..315f95a
--- /dev/null
+++ b/drivers/scsi/dec_esp.c
@@ -0,0 +1,573 @@
+/*
+ * dec_esp.c: Driver for SCSI chips on IOASIC based TURBOchannel DECstations
+ *            and TURBOchannel PMAZ-A cards
+ *
+ * TURBOchannel changes by Harald Koerfgen
+ * PMAZ-A support by David Airlie
+ *
+ * based on jazz_esp.c:
+ * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * jazz_esp is based on David S. Miller's ESP driver and cyber_esp
+ *
+ * 20000819 - Small PMAZ-AA fixes by Florian Lohoff <flo@rfc822.org>
+ *            Be warned the PMAZ-AA works currently as a single card.
+ *            Dont try to put multiple cards in one machine - They are
+ *            both detected but it may crash under high load garbling your
+ *            data.
+ * 20001005	- Initialization fixes for 2.4.0-test9
+ * 			  Florian Lohoff <flo@rfc822.org>
+ *
+ *	Copyright (C) 2002, 2003  Maciej W. Rozycki
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+#include <asm/system.h>
+
+#include <asm/dec/interrupts.h>
+#include <asm/dec/ioasic.h>
+#include <asm/dec/ioasic_addrs.h>
+#include <asm/dec/ioasic_ints.h>
+#include <asm/dec/machtype.h>
+#include <asm/dec/tc.h>
+
+#define DEC_SCSI_SREG 0
+#define DEC_SCSI_DMAREG 0x40000
+#define DEC_SCSI_SRAM 0x80000
+#define DEC_SCSI_DIAG 0xC0000
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static void dma_drain(struct NCR_ESP *esp);
+static int  dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+static void dma_advance_sg(struct scsi_cmnd * sp);
+
+static void pmaz_dma_drain(struct NCR_ESP *esp);
+static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length);
+static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length);
+static void pmaz_dma_ints_off(struct NCR_ESP *esp);
+static void pmaz_dma_ints_on(struct NCR_ESP *esp);
+static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write);
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp);
+
+#define TC_ESP_RAM_SIZE 0x20000
+#define ESP_TGT_DMA_SIZE ((TC_ESP_RAM_SIZE/7) & ~(sizeof(int)-1))
+#define ESP_NCMD 7
+
+#define TC_ESP_DMAR_MASK  0x1ffff
+#define TC_ESP_DMAR_WRITE 0x80000000
+#define TC_ESP_DMA_ADDR(x) ((unsigned)(x) & TC_ESP_DMAR_MASK)
+
+u32 esp_virt_buffer;
+int scsi_current_length;
+
+volatile unsigned char cmd_buffer[16];
+volatile unsigned char pmaz_cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are trasfered to the ESP chip
+				 * via PIO.
+				 */
+
+static irqreturn_t scsi_dma_merr_int(int, void *, struct pt_regs *);
+static irqreturn_t scsi_dma_err_int(int, void *, struct pt_regs *);
+static irqreturn_t scsi_dma_int(int, void *, struct pt_regs *);
+
+static int dec_esp_detect(struct scsi_host_template * tpnt);
+
+static int dec_esp_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static struct scsi_host_template driver_template = {
+	.proc_name		= "dec_esp",
+	.proc_info		= esp_proc_info,
+	.name			= "NCR53C94",
+	.detect			= dec_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= dec_esp_release,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+
+#include "scsi_module.c"
+
+/***************************************************************** Detection */
+static int dec_esp_detect(Scsi_Host_Template * tpnt)
+{
+	struct NCR_ESP *esp;
+	struct ConfigDev *esp_dev;
+	int slot;
+	unsigned long mem_start;
+
+	if (IOASIC) {
+		esp_dev = 0;
+		esp = esp_allocate(tpnt, (void *) esp_dev);
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = &dma_drain;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = 0;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+		esp->dma_led_off = 0;
+		esp->dma_led_on = 0;
+
+		/* virtual DMA functions */
+		esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+		esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+		esp->dma_mmu_release_scsi_one = 0;
+		esp->dma_mmu_release_scsi_sgl = 0;
+		esp->dma_advance_sg = &dma_advance_sg;
+
+
+		/* SCSI chip speed */
+		esp->cfreq = 25000000;
+
+		esp->dregs = 0;
+
+		/* ESP register base */
+		esp->eregs = (struct ESP_regs *) (system_base + IOASIC_SCSI);
+
+		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char *) cmd_buffer;
+
+		/* get virtual dma address for command buffer */
+		esp->esp_command_dvma = virt_to_phys(cmd_buffer);
+
+		esp->irq = dec_interrupt[DEC_IRQ_ASC];
+
+		esp->scsi_id = 7;
+
+		/* Check for differential SCSI-bus */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+				"ncr53c94", esp->ehost))
+			goto err_dealloc;
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_MERR],
+				scsi_dma_merr_int, SA_INTERRUPT,
+				"ncr53c94 error", esp->ehost))
+			goto err_free_irq;
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_ERR],
+				scsi_dma_err_int, SA_INTERRUPT,
+				"ncr53c94 overrun", esp->ehost))
+			goto err_free_irq_merr;
+		if (request_irq(dec_interrupt[DEC_IRQ_ASC_DMA],
+				scsi_dma_int, SA_INTERRUPT,
+				"ncr53c94 dma", esp->ehost))
+			goto err_free_irq_err;
+
+	}
+
+	if (TURBOCHANNEL) {
+		while ((slot = search_tc_card("PMAZ-AA")) >= 0) {
+			claim_tc_card(slot);
+
+			esp_dev = 0;
+			esp = esp_allocate(tpnt, (void *) esp_dev);
+
+			mem_start = get_tc_base_addr(slot);
+
+			/* Store base addr into esp struct */
+			esp->slot = PHYSADDR(mem_start);
+
+			esp->dregs = 0;
+			esp->eregs = (struct ESP_regs *) (mem_start + DEC_SCSI_SREG);
+			esp->do_pio_cmds = 1;
+
+			/* Set the command buffer */
+			esp->esp_command = (volatile unsigned char *) pmaz_cmd_buffer;
+
+			/* get virtual dma address for command buffer */
+			esp->esp_command_dvma = virt_to_phys(pmaz_cmd_buffer);
+
+			esp->cfreq = get_tc_speed();
+
+			esp->irq = get_tc_irq_nr(slot);
+
+			/* Required functions */
+			esp->dma_bytes_sent = &dma_bytes_sent;
+			esp->dma_can_transfer = &dma_can_transfer;
+			esp->dma_dump_state = &dma_dump_state;
+			esp->dma_init_read = &pmaz_dma_init_read;
+			esp->dma_init_write = &pmaz_dma_init_write;
+			esp->dma_ints_off = &pmaz_dma_ints_off;
+			esp->dma_ints_on = &pmaz_dma_ints_on;
+			esp->dma_irq_p = &dma_irq_p;
+			esp->dma_ports_p = &dma_ports_p;
+			esp->dma_setup = &pmaz_dma_setup;
+
+			/* Optional functions */
+			esp->dma_barrier = 0;
+			esp->dma_drain = &pmaz_dma_drain;
+			esp->dma_invalidate = 0;
+			esp->dma_irq_entry = 0;
+			esp->dma_irq_exit = 0;
+			esp->dma_poll = 0;
+			esp->dma_reset = 0;
+			esp->dma_led_off = 0;
+			esp->dma_led_on = 0;
+
+			esp->dma_mmu_get_scsi_one = pmaz_dma_mmu_get_scsi_one;
+			esp->dma_mmu_get_scsi_sgl = 0;
+			esp->dma_mmu_release_scsi_one = 0;
+			esp->dma_mmu_release_scsi_sgl = 0;
+			esp->dma_advance_sg = 0;
+
+ 			if (request_irq(esp->irq, esp_intr, SA_INTERRUPT,
+ 					 "PMAZ_AA", esp->ehost)) {
+ 				esp_deallocate(esp);
+ 				release_tc_card(slot);
+ 				continue;
+ 			}
+			esp->scsi_id = 7;
+			esp->diff = 0;
+			esp_initialize(esp);
+		}
+	}
+
+	if(nesps) {
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	}
+	return 0;
+
+err_free_irq_err:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_ERR], scsi_dma_err_int);
+err_free_irq_merr:
+	free_irq(dec_interrupt[DEC_IRQ_ASC_MERR], scsi_dma_merr_int);
+err_free_irq:
+	free_irq(esp->irq, esp_intr);
+err_dealloc:
+	esp_deallocate(esp);
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static irqreturn_t scsi_dma_merr_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	printk("Got unexpected SCSI DMA Interrupt! < ");
+	printk("SCSI_DMA_MEMRDERR ");
+	printk(">\n");
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t scsi_dma_err_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	/* empty */
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t scsi_dma_int(int irq, void *dev_id, struct pt_regs *regs)
+{
+	u32 scsi_next_ptr;
+
+	scsi_next_ptr = ioasic_read(IO_REG_SCSI_DMA_P);
+
+	/* next page */
+	scsi_next_ptr = (((scsi_next_ptr >> 3) + PAGE_SIZE) & PAGE_MASK) << 3;
+	ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+	fast_iob();
+
+	return IRQ_HANDLED;
+}
+
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	return fifo_count;
+}
+
+static void dma_drain(struct NCR_ESP *esp)
+{
+	u32 nw, data0, data1, scsi_data_ptr;
+	u16 *p;
+
+	nw = ioasic_read(IO_REG_SCSI_SCR);
+
+	/*
+	 * Is there something in the dma buffers left?
+	 */
+	if (nw) {
+		scsi_data_ptr = ioasic_read(IO_REG_SCSI_DMA_P) >> 3;
+		p = phys_to_virt(scsi_data_ptr);
+		switch (nw) {
+		case 1:
+			data0 = ioasic_read(IO_REG_SCSI_SDR0);
+			p[0] = data0 & 0xffff;
+			break;
+		case 2:
+			data0 = ioasic_read(IO_REG_SCSI_SDR0);
+			p[0] = data0 & 0xffff;
+			p[1] = (data0 >> 16) & 0xffff;
+			break;
+		case 3:
+			data0 = ioasic_read(IO_REG_SCSI_SDR0);
+			data1 = ioasic_read(IO_REG_SCSI_SDR1);
+			p[0] = data0 & 0xffff;
+			p[1] = (data0 >> 16) & 0xffff;
+			p[2] = data1 & 0xffff;
+			break;
+		default:
+			printk("Strange: %d words in dma buffer left\n", nw);
+			break;
+		}
+	}
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+	return sp->SCp.this_residual;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+}
+
+static void dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+	u32 scsi_next_ptr, ioasic_ssr;
+	unsigned long flags;
+
+	if (vaddress & 3)
+		panic("dec_esp.c: unable to handle partial word transfers, yet...");
+
+	dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length);
+
+	spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+	fast_mb();
+	ioasic_ssr = ioasic_read(IO_REG_SSR);
+
+	ioasic_ssr &= ~IO_SSR_SCSI_DMA_EN;
+	ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+	fast_wmb();
+	ioasic_write(IO_REG_SCSI_SCR, 0);
+	ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3);
+
+	/* prepare for next page */
+	scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
+	ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+
+	ioasic_ssr |= (IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN);
+	fast_wmb();
+	ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+	fast_iob();
+	spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+	u32 scsi_next_ptr, ioasic_ssr;
+	unsigned long flags;
+
+	if (vaddress & 3)
+		panic("dec_esp.c: unable to handle partial word transfers, yet...");
+
+	dma_cache_wback_inv((unsigned long) phys_to_virt(vaddress), length);
+
+	spin_lock_irqsave(&ioasic_ssr_lock, flags);
+
+	fast_mb();
+	ioasic_ssr = ioasic_read(IO_REG_SSR);
+
+	ioasic_ssr &= ~(IO_SSR_SCSI_DMA_DIR | IO_SSR_SCSI_DMA_EN);
+	ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+	fast_wmb();
+	ioasic_write(IO_REG_SCSI_SCR, 0);
+	ioasic_write(IO_REG_SCSI_DMA_P, vaddress << 3);
+
+	/* prepare for next page */
+	scsi_next_ptr = ((vaddress + PAGE_SIZE) & PAGE_MASK) << 3;
+	ioasic_write(IO_REG_SCSI_DMA_BP, scsi_next_ptr);
+
+	ioasic_ssr |= IO_SSR_SCSI_DMA_EN;
+	fast_wmb();
+	ioasic_write(IO_REG_SSR, ioasic_ssr);
+
+	fast_iob();
+	spin_unlock_irqrestore(&ioasic_ssr_lock, flags);
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(dec_interrupt[DEC_IRQ_ASC_DMA]);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	return (esp->eregs->esp_status & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	/*
+	 * FIXME: what's this good for?
+	 */
+	return 1;
+}
+
+static void dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write)
+{
+	/*
+	 * DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if (write)
+		dma_init_read(esp, addr, count);
+	else
+		dma_init_write(esp, addr, count);
+}
+
+static void dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+	sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+}
+
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+	int sz = sp->SCp.buffers_residual;
+	struct scatterlist *sg = sp->SCp.buffer;
+
+	while (sz >= 0) {
+		sg[sz].dma_address = page_to_phys(sg[sz].page) + sg[sz].offset;
+		sz--;
+	}
+	sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+}
+
+static void dma_advance_sg(struct scsi_cmnd * sp)
+{
+	sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+}
+
+static void pmaz_dma_drain(struct NCR_ESP *esp)
+{
+	memcpy(phys_to_virt(esp_virt_buffer),
+		(void *)KSEG1ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE),
+		scsi_current_length);
+}
+
+static void pmaz_dma_init_read(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+	volatile u32 *dmareg =
+		(volatile u32 *)KSEG1ADDR(esp->slot + DEC_SCSI_DMAREG);
+
+	if (length > ESP_TGT_DMA_SIZE)
+		length = ESP_TGT_DMA_SIZE;
+
+	*dmareg = TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE);
+
+	iob();
+
+	esp_virt_buffer = vaddress;
+	scsi_current_length = length;
+}
+
+static void pmaz_dma_init_write(struct NCR_ESP *esp, u32 vaddress, int length)
+{
+	volatile u32 *dmareg =
+		(volatile u32 *)KSEG1ADDR(esp->slot + DEC_SCSI_DMAREG);
+
+	memcpy((void *)KSEG1ADDR(esp->slot + DEC_SCSI_SRAM + ESP_TGT_DMA_SIZE),
+	       phys_to_virt(vaddress), length);
+
+	wmb();
+	*dmareg = TC_ESP_DMAR_WRITE | TC_ESP_DMA_ADDR(ESP_TGT_DMA_SIZE);
+
+	iob();
+}
+
+static void pmaz_dma_ints_off(struct NCR_ESP *esp)
+{
+}
+
+static void pmaz_dma_ints_on(struct NCR_ESP *esp)
+{
+}
+
+static void pmaz_dma_setup(struct NCR_ESP *esp, u32 addr, int count, int write)
+{
+	/*
+	 * DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if (write)
+		pmaz_dma_init_read(esp, addr, count);
+	else
+		pmaz_dma_init_write(esp, addr, count);
+}
+
+static void pmaz_dma_mmu_get_scsi_one(struct NCR_ESP *esp, struct scsi_cmnd * sp)
+{
+	sp->SCp.ptr = (char *)virt_to_phys(sp->request_buffer);
+}
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
new file mode 100644
index 0000000..1d22424
--- /dev/null
+++ b/drivers/scsi/dmx3191d.c
@@ -0,0 +1,173 @@
+/*
+    dmx3191d.c - driver for the Domex DMX3191D SCSI card.
+    Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it>
+    Portions Copyright (C) 2004 by Christoph Hellwig <hch@lst.de>
+
+    Based on the generic NCR5380 driver by Drew Eckhardt et al.
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+
+#include <scsi/scsi_host.h>
+
+/*
+ * Defintions for the generic 5380 driver.
+ */
+#define AUTOSENSE
+
+#define NCR5380_read(reg)		inb(port + reg)
+#define NCR5380_write(reg, value)	outb(value, port + reg)
+
+#define NCR5380_implementation_fields	unsigned int port
+#define NCR5380_local_declare()		NCR5380_implementation_fields
+#define NCR5380_setup(instance)		port = instance->io_port
+
+/*
+ * Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
+ */
+#include <linux/delay.h>
+#include "scsi.h"
+
+#include "NCR5380.h"
+#include "NCR5380.c"
+
+#define DMX3191D_DRIVER_NAME	"dmx3191d"
+#define DMX3191D_REGION_LEN	8
+
+
+static struct scsi_host_template dmx3191d_driver_template = {
+	.proc_name		= DMX3191D_DRIVER_NAME,
+	.name			= "Domex DMX3191D",
+	.queuecommand		= NCR5380_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue		= 32,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+static int __devinit dmx3191d_probe_one(struct pci_dev *pdev,
+		const struct pci_device_id *id)
+{
+	struct Scsi_Host *shost;
+	unsigned long io;
+	int error = -ENODEV;
+
+	if (pci_enable_device(pdev))
+		goto out;
+
+	io = pci_resource_start(pdev, 0);
+	if (!request_region(io, DMX3191D_REGION_LEN, DMX3191D_DRIVER_NAME)) {
+		printk(KERN_ERR "dmx3191: region 0x%lx-0x%lx already reserved\n",
+				io, io + DMX3191D_REGION_LEN);
+		goto out_disable_device;
+	}
+
+	shost = scsi_host_alloc(&dmx3191d_driver_template,
+			sizeof(struct NCR5380_hostdata));
+	if (!shost)
+		goto out_release_region;       
+	shost->io_port = io;
+	shost->irq = pdev->irq;
+
+	NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+
+	if (request_irq(pdev->irq, NCR5380_intr, SA_SHIRQ,
+				DMX3191D_DRIVER_NAME, shost)) {
+		/*
+		 * Steam powered scsi controllers run without an IRQ anyway
+		 */
+		printk(KERN_WARNING "dmx3191: IRQ %d not available - "
+				    "switching to polled mode.\n", pdev->irq);
+		shost->irq = SCSI_IRQ_NONE;
+	}
+
+	pci_set_drvdata(pdev, shost);
+
+	error = scsi_add_host(shost, &pdev->dev);
+	if (error)
+		goto out_free_irq;
+
+	scsi_scan_host(shost);
+	return 0;
+
+ out_free_irq:
+	free_irq(shost->irq, shost);
+ out_release_region:
+	release_region(shost->io_port, DMX3191D_REGION_LEN);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+static void __devexit dmx3191d_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *shost = pci_get_drvdata(pdev);
+
+	scsi_remove_host(shost);
+
+	NCR5380_exit(shost);
+
+	if (shost->irq != SCSI_IRQ_NONE)
+		free_irq(shost->irq, shost);
+	release_region(shost->io_port, DMX3191D_REGION_LEN);
+	pci_disable_device(pdev);
+
+	scsi_host_put(shost);
+}
+
+static struct pci_device_id dmx3191d_pci_tbl[] = {
+	{PCI_VENDOR_ID_DOMEX, PCI_DEVICE_ID_DOMEX_DMX3191D,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, dmx3191d_pci_tbl);
+
+static struct pci_driver dmx3191d_pci_driver = {
+	.name		= DMX3191D_DRIVER_NAME,
+	.id_table	= dmx3191d_pci_tbl,
+	.probe		= dmx3191d_probe_one,
+	.remove		= __devexit_p(dmx3191d_remove_one),
+};
+
+static int __init dmx3191d_init(void)
+{
+	return pci_module_init(&dmx3191d_pci_driver);
+}
+
+static void __exit dmx3191d_exit(void)
+{
+	pci_unregister_driver(&dmx3191d_pci_driver);
+}
+
+module_init(dmx3191d_init);
+module_exit(dmx3191d_exit);
+
+MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
+MODULE_DESCRIPTION("Domex DMX3191D SCSI driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpt/dpti_i2o.h b/drivers/scsi/dpt/dpti_i2o.h
new file mode 100644
index 0000000..a9585f5
--- /dev/null
+++ b/drivers/scsi/dpt/dpti_i2o.h
@@ -0,0 +1,459 @@
+#ifndef _SCSI_I2O_H
+#define _SCSI_I2O_H
+
+/* I2O kernel space accessible structures/APIs
+ *
+ * (c) Copyright 1999, 2000 Red Hat Software
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *************************************************************************
+ *
+ * This header file defined the I2O APIs/structures for use by
+ * the I2O kernel modules.
+ *
+ */
+
+#ifdef __KERNEL__       /* This file to be included by kernel only */
+
+#include <linux/i2o-dev.h>
+
+#include <asm/semaphore.h> /* Needed for MUTEX init macros */
+#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/notifier.h>
+#include <asm/atomic.h>
+
+
+/*
+ *	Tunable parameters first
+ */
+
+/* How many different OSM's are we allowing */ 
+#define MAX_I2O_MODULES		64
+
+#define I2O_EVT_CAPABILITY_OTHER		0x01
+#define I2O_EVT_CAPABILITY_CHANGED		0x02
+
+#define I2O_EVT_SENSOR_STATE_CHANGED		0x01
+
+//#ifdef __KERNEL__   /* ioctl stuff only thing exported to users */
+
+#define I2O_MAX_MANAGERS	4
+
+/*
+ *	I2O Interface Objects
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+
+#define DECLARE_MUTEX(name) struct semaphore name=MUTEX
+
+typedef struct wait_queue *adpt_wait_queue_head_t;
+#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) adpt_wait_queue_head_t wait = NULL
+typedef struct wait_queue adpt_wait_queue_t;
+#else
+
+#include <linux/wait.h>
+typedef wait_queue_head_t adpt_wait_queue_head_t;
+#define ADPT_DECLARE_WAIT_QUEUE_HEAD(wait) DECLARE_WAIT_QUEUE_HEAD(wait)
+typedef wait_queue_t adpt_wait_queue_t;
+
+#endif
+/*
+ * message structures
+ */
+
+struct i2o_message
+{
+	u8	version_offset;
+	u8	flags;
+	u16	size;
+	u32	target_tid:12;
+	u32	init_tid:12;
+	u32	function:8;	
+	u32	initiator_context;
+	/* List follows */
+};
+
+struct adpt_device;
+struct _adpt_hba;
+struct i2o_device
+{
+	struct i2o_device *next;	/* Chain */
+	struct i2o_device *prev;
+
+	char dev_name[8];		/* linux /dev name if available */
+	i2o_lct_entry lct_data;/* Device LCT information */
+	u32 flags;		
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+	struct adpt_device *owner;
+	struct _adpt_hba *controller;	/* Controlling IOP */
+};
+
+/*
+ *	Each I2O controller has one of these objects
+ */
+ 
+struct i2o_controller
+{
+	char name[16];
+	int unit;
+	int type;
+	int enabled;
+
+	struct notifier_block *event_notifer;	/* Events */
+	atomic_t users;
+	struct i2o_device *devices;		/* I2O device chain */
+	struct i2o_controller *next;		/* Controller chain */
+
+};
+
+/*
+ * I2O System table entry
+ */
+struct i2o_sys_tbl_entry
+{
+	u16	org_id;
+	u16	reserved1;
+	u32	iop_id:12;
+	u32	reserved2:20;
+	u16	seg_num:12;
+	u16 	i2o_version:4;
+	u8 	iop_state;
+	u8 	msg_type;
+	u16	frame_size;
+	u16	reserved3;
+	u32	last_changed;
+	u32	iop_capabilities;
+	u32	inbound_low;
+	u32	inbound_high;
+};
+
+struct i2o_sys_tbl
+{
+	u8 	num_entries;
+	u8 	version;
+	u16 	reserved1;
+	u32	change_ind;
+	u32	reserved2;
+	u32	reserved3;
+	struct i2o_sys_tbl_entry iops[0];
+};	
+
+/*
+ *	I2O classes / subclasses
+ */
+
+/*  Class ID and Code Assignments
+ *  (LCT.ClassID.Version field)
+ */
+#define    I2O_CLASS_VERSION_10                        0x00
+#define    I2O_CLASS_VERSION_11                        0x01
+
+/*  Class code names
+ *  (from v1.5 Table 6-1 Class Code Assignments.)
+ */
+ 
+#define    I2O_CLASS_EXECUTIVE                         0x000
+#define    I2O_CLASS_DDM                               0x001
+#define    I2O_CLASS_RANDOM_BLOCK_STORAGE              0x010
+#define    I2O_CLASS_SEQUENTIAL_STORAGE                0x011
+#define    I2O_CLASS_LAN                               0x020
+#define    I2O_CLASS_WAN                               0x030
+#define    I2O_CLASS_FIBRE_CHANNEL_PORT                0x040
+#define    I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL          0x041
+#define    I2O_CLASS_SCSI_PERIPHERAL                   0x051
+#define    I2O_CLASS_ATE_PORT                          0x060
+#define    I2O_CLASS_ATE_PERIPHERAL                    0x061
+#define    I2O_CLASS_FLOPPY_CONTROLLER                 0x070
+#define    I2O_CLASS_FLOPPY_DEVICE                     0x071
+#define    I2O_CLASS_BUS_ADAPTER_PORT                  0x080
+#define    I2O_CLASS_PEER_TRANSPORT_AGENT              0x090
+#define    I2O_CLASS_PEER_TRANSPORT                    0x091
+
+/*  Rest of 0x092 - 0x09f reserved for peer-to-peer classes
+ */
+ 
+#define    I2O_CLASS_MATCH_ANYCLASS                    0xffffffff
+
+/*  Subclasses
+ */
+
+#define    I2O_SUBCLASS_i960                           0x001
+#define    I2O_SUBCLASS_HDM                            0x020
+#define    I2O_SUBCLASS_ISM                            0x021
+ 
+/* Operation functions */
+
+#define I2O_PARAMS_FIELD_GET	0x0001
+#define I2O_PARAMS_LIST_GET	0x0002
+#define I2O_PARAMS_MORE_GET	0x0003
+#define I2O_PARAMS_SIZE_GET	0x0004
+#define I2O_PARAMS_TABLE_GET	0x0005
+#define I2O_PARAMS_FIELD_SET	0x0006
+#define I2O_PARAMS_LIST_SET	0x0007
+#define I2O_PARAMS_ROW_ADD	0x0008
+#define I2O_PARAMS_ROW_DELETE	0x0009
+#define I2O_PARAMS_TABLE_CLEAR	0x000A
+
+/*
+ *	I2O serial number conventions / formats
+ *	(circa v1.5)
+ */
+
+#define    I2O_SNFORMAT_UNKNOWN                        0
+#define    I2O_SNFORMAT_BINARY                         1
+#define    I2O_SNFORMAT_ASCII                          2
+#define    I2O_SNFORMAT_UNICODE                        3
+#define    I2O_SNFORMAT_LAN48_MAC                      4
+#define    I2O_SNFORMAT_WAN                            5
+
+/* Plus new in v2.0 (Yellowstone pdf doc)
+ */
+
+#define    I2O_SNFORMAT_LAN64_MAC                      6
+#define    I2O_SNFORMAT_DDM                            7
+#define    I2O_SNFORMAT_IEEE_REG64                     8
+#define    I2O_SNFORMAT_IEEE_REG128                    9
+#define    I2O_SNFORMAT_UNKNOWN2                       0xff
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+
+#define TRL_SINGLE_FIXED_LENGTH		0x00
+#define TRL_SINGLE_VARIABLE_LENGTH	0x40
+#define TRL_MULTIPLE_FIXED_LENGTH	0x80
+
+/*
+ *	Messaging API values
+ */
+ 
+#define	I2O_CMD_ADAPTER_ASSIGN		0xB3
+#define	I2O_CMD_ADAPTER_READ		0xB2
+#define	I2O_CMD_ADAPTER_RELEASE		0xB5
+#define	I2O_CMD_BIOS_INFO_SET		0xA5
+#define	I2O_CMD_BOOT_DEVICE_SET		0xA7
+#define	I2O_CMD_CONFIG_VALIDATE		0xBB
+#define	I2O_CMD_CONN_SETUP		0xCA
+#define	I2O_CMD_DDM_DESTROY		0xB1
+#define	I2O_CMD_DDM_ENABLE		0xD5
+#define	I2O_CMD_DDM_QUIESCE		0xC7
+#define	I2O_CMD_DDM_RESET		0xD9
+#define	I2O_CMD_DDM_SUSPEND		0xAF
+#define	I2O_CMD_DEVICE_ASSIGN		0xB7
+#define	I2O_CMD_DEVICE_RELEASE		0xB9
+#define	I2O_CMD_HRT_GET			0xA8
+#define	I2O_CMD_ADAPTER_CLEAR		0xBE
+#define	I2O_CMD_ADAPTER_CONNECT		0xC9
+#define	I2O_CMD_ADAPTER_RESET		0xBD
+#define	I2O_CMD_LCT_NOTIFY		0xA2
+#define	I2O_CMD_OUTBOUND_INIT		0xA1
+#define	I2O_CMD_PATH_ENABLE		0xD3
+#define	I2O_CMD_PATH_QUIESCE		0xC5
+#define	I2O_CMD_PATH_RESET		0xD7
+#define	I2O_CMD_STATIC_MF_CREATE	0xDD
+#define	I2O_CMD_STATIC_MF_RELEASE	0xDF
+#define	I2O_CMD_STATUS_GET		0xA0
+#define	I2O_CMD_SW_DOWNLOAD		0xA9
+#define	I2O_CMD_SW_UPLOAD		0xAB
+#define	I2O_CMD_SW_REMOVE		0xAD
+#define	I2O_CMD_SYS_ENABLE		0xD1
+#define	I2O_CMD_SYS_MODIFY		0xC1
+#define	I2O_CMD_SYS_QUIESCE		0xC3
+#define	I2O_CMD_SYS_TAB_SET		0xA3
+
+#define I2O_CMD_UTIL_NOP		0x00
+#define I2O_CMD_UTIL_ABORT		0x01
+#define I2O_CMD_UTIL_CLAIM		0x09
+#define I2O_CMD_UTIL_RELEASE		0x0B
+#define I2O_CMD_UTIL_PARAMS_GET		0x06
+#define I2O_CMD_UTIL_PARAMS_SET		0x05
+#define I2O_CMD_UTIL_EVT_REGISTER	0x13
+#define I2O_CMD_UTIL_EVT_ACK		0x14
+#define I2O_CMD_UTIL_CONFIG_DIALOG	0x10
+#define I2O_CMD_UTIL_DEVICE_RESERVE	0x0D
+#define I2O_CMD_UTIL_DEVICE_RELEASE	0x0F
+#define I2O_CMD_UTIL_LOCK		0x17
+#define I2O_CMD_UTIL_LOCK_RELEASE	0x19
+#define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY	0x15
+
+#define I2O_CMD_SCSI_EXEC		0x81
+#define I2O_CMD_SCSI_ABORT		0x83
+#define I2O_CMD_SCSI_BUSRESET		0x27
+
+#define I2O_CMD_BLOCK_READ		0x30
+#define I2O_CMD_BLOCK_WRITE		0x31
+#define I2O_CMD_BLOCK_CFLUSH		0x37
+#define I2O_CMD_BLOCK_MLOCK		0x49
+#define I2O_CMD_BLOCK_MUNLOCK		0x4B
+#define I2O_CMD_BLOCK_MMOUNT		0x41
+#define I2O_CMD_BLOCK_MEJECT		0x43
+
+#define I2O_PRIVATE_MSG			0xFF
+
+/*
+ *	Init Outbound Q status 
+ */
+ 
+#define I2O_CMD_OUTBOUND_INIT_IN_PROGRESS	0x01
+#define I2O_CMD_OUTBOUND_INIT_REJECTED		0x02
+#define I2O_CMD_OUTBOUND_INIT_FAILED		0x03
+#define I2O_CMD_OUTBOUND_INIT_COMPLETE		0x04
+
+/*
+ *	I2O Get Status State values 
+ */
+
+#define	ADAPTER_STATE_INITIALIZING		0x01
+#define	ADAPTER_STATE_RESET			0x02
+#define	ADAPTER_STATE_HOLD			0x04
+#define ADAPTER_STATE_READY			0x05
+#define	ADAPTER_STATE_OPERATIONAL		0x08
+#define	ADAPTER_STATE_FAILED			0x10
+#define	ADAPTER_STATE_FAULTED			0x11
+	
+/* I2O API function return values */
+
+#define I2O_RTN_NO_ERROR			0
+#define I2O_RTN_NOT_INIT			1
+#define I2O_RTN_FREE_Q_EMPTY			2
+#define I2O_RTN_TCB_ERROR			3
+#define I2O_RTN_TRANSACTION_ERROR		4
+#define I2O_RTN_ADAPTER_ALREADY_INIT		5
+#define I2O_RTN_MALLOC_ERROR			6
+#define I2O_RTN_ADPTR_NOT_REGISTERED		7
+#define I2O_RTN_MSG_REPLY_TIMEOUT		8
+#define I2O_RTN_NO_STATUS			9
+#define I2O_RTN_NO_FIRM_VER			10
+#define	I2O_RTN_NO_LINK_SPEED			11
+
+/* Reply message status defines for all messages */
+
+#define I2O_REPLY_STATUS_SUCCESS                    	0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY                	0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER     	0x02
+#define	I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER		0x03
+#define	I2O_REPLY_STATUS_ERROR_DIRTY			0x04
+#define	I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER		0x05
+#define	I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER		0x06
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY		0x08
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER	0x09
+#define	I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER	0x0A
+#define	I2O_REPLY_STATUS_TRANSACTION_ERROR		0x0B
+#define	I2O_REPLY_STATUS_PROGRESS_REPORT		0x80
+
+/* Status codes and Error Information for Parameter functions */
+
+#define I2O_PARAMS_STATUS_SUCCESS		0x00
+#define I2O_PARAMS_STATUS_BAD_KEY_ABORT		0x01
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE   	0x02
+#define I2O_PARAMS_STATUS_BUFFER_FULL		0x03
+#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL	0x04
+#define I2O_PARAMS_STATUS_FIELD_UNREADABLE	0x05
+#define I2O_PARAMS_STATUS_FIELD_UNWRITEABLE	0x06
+#define I2O_PARAMS_STATUS_INSUFFICIENT_FIELDS	0x07
+#define I2O_PARAMS_STATUS_INVALID_GROUP_ID	0x08
+#define I2O_PARAMS_STATUS_INVALID_OPERATION	0x09
+#define I2O_PARAMS_STATUS_NO_KEY_FIELD		0x0A
+#define I2O_PARAMS_STATUS_NO_SUCH_FIELD		0x0B
+#define I2O_PARAMS_STATUS_NON_DYNAMIC_GROUP	0x0C
+#define I2O_PARAMS_STATUS_OPERATION_ERROR	0x0D
+#define I2O_PARAMS_STATUS_SCALAR_ERROR		0x0E
+#define I2O_PARAMS_STATUS_TABLE_ERROR		0x0F
+#define I2O_PARAMS_STATUS_WRONG_GROUP_TYPE	0x10
+
+/* DetailedStatusCode defines for Executive, DDM, Util and Transaction error
+ * messages: Table 3-2 Detailed Status Codes.*/
+
+#define I2O_DSC_SUCCESS                        0x0000
+#define I2O_DSC_BAD_KEY                        0x0002
+#define I2O_DSC_TCL_ERROR                      0x0003
+#define I2O_DSC_REPLY_BUFFER_FULL              0x0004
+#define I2O_DSC_NO_SUCH_PAGE                   0x0005
+#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT     0x0006
+#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD     0x0007
+#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE         0x0009
+#define I2O_DSC_UNSUPPORTED_FUNCTION           0x000A
+#define I2O_DSC_DEVICE_LOCKED                  0x000B
+#define I2O_DSC_DEVICE_RESET                   0x000C
+#define I2O_DSC_INAPPROPRIATE_FUNCTION         0x000D
+#define I2O_DSC_INVALID_INITIATOR_ADDRESS      0x000E
+#define I2O_DSC_INVALID_MESSAGE_FLAGS          0x000F
+#define I2O_DSC_INVALID_OFFSET                 0x0010
+#define I2O_DSC_INVALID_PARAMETER              0x0011
+#define I2O_DSC_INVALID_REQUEST                0x0012
+#define I2O_DSC_INVALID_TARGET_ADDRESS         0x0013
+#define I2O_DSC_MESSAGE_TOO_LARGE              0x0014
+#define I2O_DSC_MESSAGE_TOO_SMALL              0x0015
+#define I2O_DSC_MISSING_PARAMETER              0x0016
+#define I2O_DSC_TIMEOUT                        0x0017
+#define I2O_DSC_UNKNOWN_ERROR                  0x0018
+#define I2O_DSC_UNKNOWN_FUNCTION               0x0019
+#define I2O_DSC_UNSUPPORTED_VERSION            0x001A
+#define I2O_DSC_DEVICE_BUSY                    0x001B
+#define I2O_DSC_DEVICE_NOT_AVAILABLE           0x001C
+
+/* Device Claim Types */
+#define	I2O_CLAIM_PRIMARY					0x01000000
+#define	I2O_CLAIM_MANAGEMENT					0x02000000
+#define	I2O_CLAIM_AUTHORIZED					0x03000000
+#define	I2O_CLAIM_SECONDARY					0x04000000
+ 
+/* Message header defines for VersionOffset */
+#define I2OVER15	0x0001
+#define I2OVER20	0x0002
+/* Default is 1.5, FIXME: Need support for both 1.5 and 2.0 */
+#define I2OVERSION	I2OVER15
+#define SGL_OFFSET_0    I2OVERSION
+#define SGL_OFFSET_4    (0x0040 | I2OVERSION)
+#define SGL_OFFSET_5    (0x0050 | I2OVERSION)
+#define SGL_OFFSET_6    (0x0060 | I2OVERSION)
+#define SGL_OFFSET_7    (0x0070 | I2OVERSION)
+#define SGL_OFFSET_8    (0x0080 | I2OVERSION)
+#define SGL_OFFSET_9    (0x0090 | I2OVERSION)
+#define SGL_OFFSET_10   (0x00A0 | I2OVERSION)
+#define SGL_OFFSET_12   (0x00C0 | I2OVERSION)
+
+#define TRL_OFFSET_5    (0x0050 | I2OVERSION)
+#define TRL_OFFSET_6    (0x0060 | I2OVERSION)
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC	0x0100
+#define MSG_64BIT_CNTXT	0x0200
+#define MSG_MULTI_TRANS	0x1000
+#define MSG_FAIL	0x2000
+#define MSG_LAST	0x4000
+#define MSG_REPLY	0x8000
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE	0x00030000
+#define FOUR_WORD_MSG_SIZE	0x00040000
+#define FIVE_WORD_MSG_SIZE	0x00050000
+#define SIX_WORD_MSG_SIZE	0x00060000
+#define SEVEN_WORD_MSG_SIZE	0x00070000
+#define EIGHT_WORD_MSG_SIZE	0x00080000
+#define NINE_WORD_MSG_SIZE	0x00090000
+#define TEN_WORD_MSG_SIZE	0x000A0000
+#define I2O_MESSAGE_SIZE(x)	((x)<<16)
+
+
+/* Special TID Assignments */
+
+#define ADAPTER_TID		0
+#define HOST_TID		1
+
+#define MSG_FRAME_SIZE		128
+#define NMBR_MSG_FRAMES		128
+
+#define MSG_POOL_SIZE		16384
+
+#define I2O_POST_WAIT_OK	0
+#define I2O_POST_WAIT_TIMEOUT	-ETIMEDOUT
+
+
+#endif /* __KERNEL__ */
+
+#endif /* _SCSI_I2O_H */
diff --git a/drivers/scsi/dpt/dpti_ioctl.h b/drivers/scsi/dpt/dpti_ioctl.h
new file mode 100644
index 0000000..82d2486
--- /dev/null
+++ b/drivers/scsi/dpt/dpti_ioctl.h
@@ -0,0 +1,139 @@
+/***************************************************************************
+                          dpti_ioctl.h  -  description
+                             -------------------
+    begin                : Thu Sep 7 2000
+    copyright            : (C) 2001 by Adaptec
+
+    See Documentation/scsi/dpti.txt for history, notes, license info
+    and credits
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+/***************************************************************************
+ * This file is generated from  osd_unix.h                                 *
+ * *************************************************************************/
+
+#ifndef _dpti_ioctl_h
+#define _dpti_ioctl_h
+
+// IOCTL interface commands
+
+#ifndef _IOWR
+# define _IOWR(x,y,z)	(((x)<<8)|y)
+#endif
+#ifndef _IOW
+# define _IOW(x,y,z)	(((x)<<8)|y)
+#endif
+#ifndef _IOR
+# define _IOR(x,y,z)	(((x)<<8)|y)
+#endif
+#ifndef _IO
+# define _IO(x,y)	(((x)<<8)|y)
+#endif
+/* EATA PassThrough Command	*/
+#define EATAUSRCMD      _IOWR('D',65,EATA_CP)
+/* Set Debug Level If Enabled	*/
+#define DPT_DEBUG       _IOW('D',66,int)
+/* Get Signature Structure	*/
+#define DPT_SIGNATURE   _IOR('D',67,dpt_sig_S)
+#if defined __bsdi__
+#define DPT_SIGNATURE_PACKED   _IOR('D',67,dpt_sig_S_Packed)
+#endif
+/* Get Number Of DPT Adapters	*/
+#define DPT_NUMCTRLS    _IOR('D',68,int)
+/* Get Adapter Info Structure	*/
+#define DPT_CTRLINFO    _IOR('D',69,CtrlInfo)
+/* Get Statistics If Enabled	*/
+#define DPT_STATINFO    _IO('D',70)
+/* Clear Stats If Enabled	*/
+#define DPT_CLRSTAT     _IO('D',71)
+/* Get System Info Structure	*/
+#define DPT_SYSINFO     _IOR('D',72,sysInfo_S)
+/* Set Timeout Value		*/
+#define DPT_TIMEOUT     _IO('D',73)
+/* Get config Data  		*/
+#define DPT_CONFIG      _IO('D',74)
+/* Get Blink LED Code	        */
+#define DPT_BLINKLED    _IOR('D',75,int)
+/* Get Statistical information (if available) */
+#define DPT_STATS_INFO        _IOR('D',80,STATS_DATA)
+/* Clear the statistical information          */
+#define DPT_STATS_CLEAR       _IO('D',81)
+/* Get Performance metrics */
+#define DPT_PERF_INFO        _IOR('D',82,dpt_perf_t)
+/* Send an I2O command */
+#define I2OUSRCMD	_IO('D',76)
+/* Inform driver to re-acquire LCT information */
+#define I2ORESCANCMD	_IO('D',77)
+/* Inform driver to reset adapter */
+#define I2ORESETCMD	_IO('D',78)
+/* See if the target is mounted */
+#define DPT_TARGET_BUSY	_IOR('D',79, TARGET_BUSY_T)
+
+
+  /* Structure Returned From Get Controller Info                             */
+
+typedef struct {
+	uCHAR    state;            /* Operational state               */
+	uCHAR    id;               /* Host adapter SCSI id            */
+	int      vect;             /* Interrupt vector number         */
+	int      base;             /* Base I/O address                */
+	int      njobs;            /* # of jobs sent to HA            */
+	int      qdepth;           /* Controller queue depth.         */
+	int      wakebase;         /* mpx wakeup base index.          */
+	uLONG    SGsize;           /* Scatter/Gather list size.       */
+	unsigned heads;            /* heads for drives on cntlr.      */
+	unsigned sectors;          /* sectors for drives on cntlr.    */
+	uCHAR    do_drive32;       /* Flag for Above 16 MB Ability    */
+	uCHAR    BusQuiet;         /* SCSI Bus Quiet Flag             */
+	char     idPAL[4];         /* 4 Bytes Of The ID Pal           */
+	uCHAR    primary;          /* 1 For Primary, 0 For Secondary  */
+	uCHAR    eataVersion;      /* EATA Version                    */
+	uLONG    cpLength;         /* EATA Command Packet Length      */
+	uLONG    spLength;         /* EATA Status Packet Length       */
+	uCHAR    drqNum;           /* DRQ Index (0,5,6,7)             */ 
+	uCHAR    flag1;            /* EATA Flags 1 (Byte 9)           */
+	uCHAR    flag2;            /* EATA Flags 2 (Byte 30)          */
+} CtrlInfo;
+
+typedef struct {
+	uSHORT length;		// Remaining length of this
+	uSHORT drvrHBAnum;	// Relative HBA # used by the driver
+	uLONG baseAddr;		// Base I/O address
+	uSHORT blinkState;	// Blink LED state (0=Not in blink LED)
+	uCHAR pciBusNum;	// PCI Bus # (Optional)
+	uCHAR pciDeviceNum;	// PCI Device # (Optional)
+	uSHORT hbaFlags;	// Miscellaneous HBA flags
+	uSHORT Interrupt;	// Interrupt set for this device.
+#   if (defined(_DPT_ARC))
+	uLONG baseLength;
+	ADAPTER_OBJECT *AdapterObject;
+	LARGE_INTEGER DmaLogicalAddress;
+	PVOID DmaVirtualAddress;
+	LARGE_INTEGER ReplyLogicalAddress;
+	PVOID ReplyVirtualAddress;
+#   else
+	uLONG reserved1;	// Reserved for future expansion
+	uLONG reserved2;	// Reserved for future expansion
+	uLONG reserved3;	// Reserved for future expansion
+#   endif
+} drvrHBAinfo_S;
+
+typedef struct TARGET_BUSY
+{
+  uLONG channel;
+  uLONG id;
+  uLONG lun;
+  uLONG isBusy;
+} TARGET_BUSY_T;
+
+#endif
+
diff --git a/drivers/scsi/dpt/dptsig.h b/drivers/scsi/dpt/dptsig.h
new file mode 100644
index 0000000..95a4cce
--- /dev/null
+++ b/drivers/scsi/dpt/dptsig.h
@@ -0,0 +1,339 @@
+/*	BSDI dptsig.h,v 1.7 1998/06/03 19:15:00 karels Exp	*/
+
+/*
+ * Copyright (c) 1996-1999 Distributed Processing Technology Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source form, with or without modification, are
+ * permitted provided that redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following disclaimer.
+ *
+ * This software is provided `as is' by Distributed Processing Technology and
+ * any express or implied warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose,
+ * are disclaimed. In no event shall Distributed Processing Technology be
+ * liable for any direct, indirect, incidental, special, exemplary or
+ * consequential damages (including, but not limited to, procurement of
+ * substitute goods or services; loss of use, data, or profits; or business
+ * interruptions) however caused and on any theory of liability, whether in
+ * contract, strict liability, or tort (including negligence or otherwise)
+ * arising in any way out of the use of this driver software, even if advised
+ * of the possibility of such damage.
+ *
+ */
+
+#ifndef __DPTSIG_H_
+#define __DPTSIG_H_
+#ifdef _SINIX_ADDON
+#include "dpt.h"
+#endif
+/* DPT SIGNATURE SPEC AND HEADER FILE                           */
+/* Signature Version 1 (sorry no 'A')                           */
+
+/* to make sure we are talking the same size under all OS's     */
+typedef unsigned char sigBYTE;
+typedef unsigned short sigWORD;
+#if (defined(_MULTI_DATAMODEL) && defined(sun) && !defined(_ILP32))
+typedef uint32_t sigLONG;
+#else
+typedef unsigned long sigLONG;
+#endif
+
+/*
+ * use sigWORDLittleEndian for:
+ *  dsCapabilities
+ *  dsDeviceSupp
+ *  dsAdapterSupp
+ *  dsApplication
+ * use sigLONGLittleEndian for:
+ *      dsOS
+ * so that the sig can be standardised to Little Endian
+ */
+#if (defined(_DPT_BIG_ENDIAN))
+# define sigWORDLittleEndian(x) ((((x)&0xFF)<<8)|(((x)>>8)&0xFF))
+# define sigLONGLittleEndian(x) \
+        ((((x)&0xFF)<<24) |             \
+         (((x)&0xFF00)<<8) |    \
+         (((x)&0xFF0000L)>>8) | \
+         (((x)&0xFF000000L)>>24))
+#else
+# define sigWORDLittleEndian(x) (x)
+# define sigLONGLittleEndian(x) (x)
+#endif
+
+/* must make sure the structure is not word or double-word aligned      */
+/* ---------------------------------------------------------------      */
+/* Borland will ignore the following pragma:                            */
+/* Word alignment is OFF by default.  If in the, IDE make               */
+/* sure that Options | Compiler | Code Generation | Word Alignment      */
+/* is not checked.  If using BCC, do not use the -a option.             */
+
+#ifndef NO_PACK
+#if defined (_DPT_AIX)
+#pragma options align=packed
+#else
+#pragma pack(1)
+#endif  /* aix */
+#endif
+/* For the Macintosh */
+#if STRUCTALIGNMENTSUPPORTED
+#pragma options align=mac68k
+#endif
+
+
+/* Current Signature Version - sigBYTE dsSigVersion; */
+/* ------------------------------------------------------------------ */
+#define SIG_VERSION 1
+
+/* Processor Family - sigBYTE dsProcessorFamily;  DISTINCT VALUES */
+/* ------------------------------------------------------------------ */
+/* What type of processor the file is meant to run on. */
+/* This will let us know whether to read sigWORDs as high/low or low/high. */
+#define PROC_INTEL      0x00    /* Intel 80x86 */
+#define PROC_MOTOROLA   0x01    /* Motorola 68K */
+#define PROC_MIPS4000   0x02    /* MIPS RISC 4000 */
+#define PROC_ALPHA      0x03    /* DEC Alpha */
+#define PROC_POWERPC    0x04    /* IBM Power PC */
+#define PROC_i960       0x05    /* Intel i960 */
+#define PROC_ULTRASPARC 0x06    /* SPARC processor */
+
+/* Specific Minimim Processor - sigBYTE dsProcessor;    FLAG BITS */
+/* ------------------------------------------------------------------ */
+/* Different bit definitions dependent on processor_family */
+
+/* PROC_INTEL: */
+#define PROC_8086       0x01    /* Intel 8086 */
+#define PROC_286        0x02    /* Intel 80286 */
+#define PROC_386        0x04    /* Intel 80386 */
+#define PROC_486        0x08    /* Intel 80486 */
+#define PROC_PENTIUM    0x10    /* Intel 586 aka P5 aka Pentium */
+#define PROC_SEXIUM	0x20	/* Intel 686 aka P6 aka Pentium Pro or MMX */
+
+/* PROC_i960: */
+#define PROC_960RX      0x01    /* Intel 80960RC/RD */
+#define PROC_960HX      0x02    /* Intel 80960HA/HD/HT */
+
+/* PROC_MOTOROLA: */
+#define PROC_68000      0x01    /* Motorola 68000 */
+#define PROC_68010	0x02	/* Motorola 68010 */
+#define PROC_68020      0x04    /* Motorola 68020 */
+#define PROC_68030      0x08    /* Motorola 68030 */
+#define PROC_68040      0x10    /* Motorola 68040 */
+
+/* PROC_POWERPC */
+#define PROC_PPC601		0x01	/* PowerPC 601 */
+#define PROC_PPC603		0x02	/* PowerPC 603 */
+#define PROC_PPC604		0x04	/* PowerPC 604 */
+
+/* PROC_MIPS4000: */
+#define PROC_R4000      0x01    /* MIPS R4000 */
+
+/* Filetype - sigBYTE dsFiletype;       DISTINCT VALUES */
+/* ------------------------------------------------------------------ */
+#define FT_EXECUTABLE   0       /* Executable Program */
+#define FT_SCRIPT       1       /* Script/Batch File??? */
+#define FT_HBADRVR      2       /* HBA Driver */
+#define FT_OTHERDRVR    3       /* Other Driver */
+#define FT_IFS          4       /* Installable Filesystem Driver */
+#define FT_ENGINE       5       /* DPT Engine */
+#define FT_COMPDRVR     6       /* Compressed Driver Disk */
+#define FT_LANGUAGE     7       /* Foreign Language file */
+#define FT_FIRMWARE     8       /* Downloadable or actual Firmware */
+#define FT_COMMMODL     9       /* Communications Module */
+#define FT_INT13        10      /* INT 13 style HBA Driver */
+#define FT_HELPFILE     11      /* Help file */
+#define FT_LOGGER       12      /* Event Logger */
+#define FT_INSTALL      13      /* An Install Program */
+#define FT_LIBRARY      14      /* Storage Manager Real-Mode Calls */
+#define FT_RESOURCE 	15 	/* Storage Manager Resource File */
+#define FT_MODEM_DB  	16  	/* Storage Manager Modem Database */
+
+/* Filetype flags - sigBYTE dsFiletypeFlags;    FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define FTF_DLL         0x01    /* Dynamic Link Library */
+#define FTF_NLM         0x02    /* Netware Loadable Module */
+#define FTF_OVERLAYS    0x04    /* Uses overlays */
+#define FTF_DEBUG       0x08    /* Debug version */
+#define FTF_TSR         0x10    /* TSR */
+#define FTF_SYS         0x20    /* DOS Loadable driver */
+#define FTF_PROTECTED   0x40    /* Runs in protected mode */
+#define FTF_APP_SPEC    0x80    /* Application Specific */
+#define FTF_ROM		(FTF_SYS|FTF_TSR)	/* Special Case */
+
+/* OEM - sigBYTE dsOEM;         DISTINCT VALUES */
+/* ------------------------------------------------------------------ */
+#define OEM_DPT         0       /* DPT */
+#define OEM_ATT         1       /* ATT */
+#define OEM_NEC         2       /* NEC */
+#define OEM_ALPHA       3       /* Alphatronix */
+#define OEM_AST         4       /* AST */
+#define OEM_OLIVETTI    5       /* Olivetti */
+#define OEM_SNI         6       /* Siemens/Nixdorf */
+#define OEM_SUN         7       /* SUN Microsystems */
+
+/* Operating System  - sigLONG dsOS;    FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define OS_DOS          0x00000001 /* PC/MS-DOS				*/
+#define OS_WINDOWS      0x00000002 /* Microsoft Windows 3.x		*/
+#define OS_WINDOWS_NT   0x00000004 /* Microsoft Windows NT		*/
+#define OS_OS2M         0x00000008 /* OS/2 1.2.x,MS 1.3.0,IBM 1.3.x - Monolithic */
+#define OS_OS2L         0x00000010 /* Microsoft OS/2 1.301 - LADDR	*/
+#define OS_OS22x        0x00000020 /* IBM OS/2 2.x			*/
+#define OS_NW286        0x00000040 /* Novell NetWare 286		*/
+#define OS_NW386        0x00000080 /* Novell NetWare 386		*/
+#define OS_GEN_UNIX     0x00000100 /* Generic Unix			*/
+#define OS_SCO_UNIX     0x00000200 /* SCO Unix				*/
+#define OS_ATT_UNIX     0x00000400 /* ATT Unix				*/
+#define OS_UNIXWARE     0x00000800 /* USL Unix				*/
+#define OS_INT_UNIX     0x00001000 /* Interactive Unix			*/
+#define OS_SOLARIS      0x00002000 /* SunSoft Solaris			*/
+#define OS_QNX          0x00004000 /* QNX for Tom Moch			*/
+#define OS_NEXTSTEP     0x00008000 /* NeXTSTEP/OPENSTEP/MACH		*/
+#define OS_BANYAN       0x00010000 /* Banyan Vines			*/
+#define OS_OLIVETTI_UNIX 0x00020000/* Olivetti Unix			*/
+#define OS_MAC_OS	0x00040000 /* Mac OS				*/
+#define OS_WINDOWS_95	0x00080000 /* Microsoft Windows '95		*/
+#define OS_NW4x		0x00100000 /* Novell Netware 4.x		*/
+#define OS_BSDI_UNIX	0x00200000 /* BSDi Unix BSD/OS 2.0 and up	*/
+#define OS_AIX_UNIX     0x00400000 /* AIX Unix				*/
+#define OS_FREE_BSD	0x00800000 /* FreeBSD Unix			*/
+#define OS_LINUX	0x01000000 /* Linux				*/
+#define OS_DGUX_UNIX	0x02000000 /* Data General Unix			*/
+#define OS_SINIX_N      0x04000000 /* SNI SINIX-N			*/
+#define OS_PLAN9	0x08000000 /* ATT Plan 9			*/
+#define OS_TSX		0x10000000 /* SNH TSX-32			*/
+
+#define OS_OTHER        0x80000000 /* Other				*/
+
+/* Capabilities - sigWORD dsCapabilities;        FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define CAP_RAID0       0x0001  /* RAID-0 */
+#define CAP_RAID1       0x0002  /* RAID-1 */
+#define CAP_RAID3       0x0004  /* RAID-3 */
+#define CAP_RAID5       0x0008  /* RAID-5 */
+#define CAP_SPAN        0x0010  /* Spanning */
+#define CAP_PASS        0x0020  /* Provides passthrough */
+#define CAP_OVERLAP     0x0040  /* Passthrough supports overlapped commands */
+#define CAP_ASPI        0x0080  /* Supports ASPI Command Requests */
+#define CAP_ABOVE16MB   0x0100  /* ISA Driver supports greater than 16MB */
+#define CAP_EXTEND      0x8000  /* Extended info appears after description */
+#ifdef SNI_MIPS
+#define CAP_CACHEMODE   0x1000  /* dpt_force_cache is set in driver */
+#endif
+
+/* Devices Supported - sigWORD dsDeviceSupp;    FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define DEV_DASD        0x0001  /* DASD (hard drives) */
+#define DEV_TAPE        0x0002  /* Tape drives */
+#define DEV_PRINTER     0x0004  /* Printers */
+#define DEV_PROC        0x0008  /* Processors */
+#define DEV_WORM        0x0010  /* WORM drives */
+#define DEV_CDROM       0x0020  /* CD-ROM drives */
+#define DEV_SCANNER     0x0040  /* Scanners */
+#define DEV_OPTICAL     0x0080  /* Optical Drives */
+#define DEV_JUKEBOX     0x0100  /* Jukebox */
+#define DEV_COMM        0x0200  /* Communications Devices */
+#define DEV_OTHER       0x0400  /* Other Devices */
+#define DEV_ALL         0xFFFF  /* All SCSI Devices */
+
+/* Adapters Families Supported - sigWORD dsAdapterSupp; FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define ADF_2001        0x0001  /* PM2001           */
+#define ADF_2012A       0x0002  /* PM2012A          */
+#define ADF_PLUS_ISA    0x0004  /* PM2011,PM2021    */
+#define ADF_PLUS_EISA   0x0008  /* PM2012B,PM2022   */
+#define ADF_SC3_ISA	0x0010  /* PM2021           */
+#define ADF_SC3_EISA	0x0020  /* PM2022,PM2122, etc */
+#define ADF_SC3_PCI	0x0040  /* SmartCache III PCI */
+#define ADF_SC4_ISA	0x0080  /* SmartCache IV ISA */
+#define ADF_SC4_EISA	0x0100  /* SmartCache IV EISA */
+#define ADF_SC4_PCI	0x0200	/* SmartCache IV PCI */
+#define ADF_SC5_PCI	0x0400	/* Fifth Generation I2O products */
+/*
+ *	Combinations of products
+ */
+#define ADF_ALL_2000	(ADF_2001|ADF_2012A)
+#define ADF_ALL_PLUS	(ADF_PLUS_ISA|ADF_PLUS_EISA)
+#define ADF_ALL_SC3	(ADF_SC3_ISA|ADF_SC3_EISA|ADF_SC3_PCI)
+#define ADF_ALL_SC4	(ADF_SC4_ISA|ADF_SC4_EISA|ADF_SC4_PCI)
+#define ADF_ALL_SC5	(ADF_SC5_PCI)
+/* All EATA Cacheing Products */
+#define ADF_ALL_CACHE	(ADF_ALL_PLUS|ADF_ALL_SC3|ADF_ALL_SC4)
+/* All EATA Bus Mastering Products */
+#define ADF_ALL_MASTER	(ADF_2012A|ADF_ALL_CACHE)
+/* All EATA Adapter Products */
+#define ADF_ALL_EATA	(ADF_2001|ADF_ALL_MASTER)
+#define ADF_ALL		ADF_ALL_EATA
+
+/* Application - sigWORD dsApplication;         FLAG BITS */
+/* ------------------------------------------------------------------ */
+#define APP_DPTMGR      0x0001  /* DPT Storage Manager */
+#define APP_ENGINE      0x0002  /* DPT Engine */
+#define APP_SYTOS       0x0004  /* Sytron Sytos Plus */
+#define APP_CHEYENNE    0x0008  /* Cheyenne ARCServe + ARCSolo */
+#define APP_MSCDEX      0x0010  /* Microsoft CD-ROM extensions */
+#define APP_NOVABACK    0x0020  /* NovaStor Novaback */
+#define APP_AIM         0x0040  /* Archive Information Manager */
+
+/* Requirements - sigBYTE dsRequirements;         FLAG BITS             */
+/* ------------------------------------------------------------------   */
+#define REQ_SMARTROM    0x01    /* Requires SmartROM to be present      */
+#define REQ_DPTDDL      0x02    /* Requires DPTDDL.SYS to be loaded     */
+#define REQ_HBA_DRIVER  0x04    /* Requires an HBA driver to be loaded  */
+#define REQ_ASPI_TRAN   0x08    /* Requires an ASPI Transport Modules   */
+#define REQ_ENGINE      0x10    /* Requires a DPT Engine to be loaded   */
+#define REQ_COMM_ENG    0x20    /* Requires a DPT Communications Engine */
+
+/*
+ * You may adjust dsDescription_size with an override to a value less than
+ * 50 so that the structure allocates less real space.
+ */
+#if (!defined(dsDescription_size))
+# define dsDescription_size 50
+#endif
+
+typedef struct dpt_sig {
+    char    dsSignature[6];      /* ALWAYS "dPtSiG" */
+    sigBYTE dsSigVersion;        /* signature version (currently 1) */
+    sigBYTE dsProcessorFamily;   /* what type of processor */
+    sigBYTE dsProcessor;         /* precise processor */
+    sigBYTE dsFiletype;          /* type of file */
+    sigBYTE dsFiletypeFlags;     /* flags to specify load type, etc. */
+    sigBYTE dsOEM;               /* OEM file was created for */
+    sigLONG dsOS;                /* which Operating systems */
+    sigWORD dsCapabilities;      /* RAID levels, etc. */
+    sigWORD dsDeviceSupp;        /* Types of SCSI devices supported */
+    sigWORD dsAdapterSupp;       /* DPT adapter families supported */
+    sigWORD dsApplication;       /* applications file is for */
+    sigBYTE dsRequirements;      /* Other driver dependencies */
+    sigBYTE dsVersion;           /* 1 */
+    sigBYTE dsRevision;          /* 'J' */
+    sigBYTE dsSubRevision;       /* '9'   ' ' if N/A */
+    sigBYTE dsMonth;             /* creation month */
+    sigBYTE dsDay;               /* creation day */
+    sigBYTE dsYear;              /* creation year since 1980 (1993=13) */
+    /* description (NULL terminated) */
+    char  dsDescription[dsDescription_size];
+} dpt_sig_S;
+/* 32 bytes minimum - with no description.  Put NULL at description[0] */
+/* 81 bytes maximum - with 49 character description plus NULL. */
+
+/* This line added at Roycroft's request */
+/* Microsoft's NT compiler gets confused if you do a pack and don't */
+/* restore it. */
+
+#ifndef NO_UNPACK
+#if defined (_DPT_AIX)
+#pragma options align=reset
+#elif defined (UNPACK_FOUR)
+#pragma pack(4)
+#else
+#pragma pack()
+#endif  /* aix */
+#endif
+/* For the Macintosh */
+#if STRUCTALIGNMENTSUPPORTED
+#pragma options align=reset
+#endif
+
+#endif
diff --git a/drivers/scsi/dpt/osd_defs.h b/drivers/scsi/dpt/osd_defs.h
new file mode 100644
index 0000000..de3ae57
--- /dev/null
+++ b/drivers/scsi/dpt/osd_defs.h
@@ -0,0 +1,79 @@
+/*	BSDI osd_defs.h,v 1.4 1998/06/03 19:14:58 karels Exp	*/
+/*
+ * Copyright (c) 1996-1999 Distributed Processing Technology Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source form, with or without modification, are
+ * permitted provided that redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following disclaimer.
+ *
+ * This software is provided `as is' by Distributed Processing Technology and
+ * any express or implied warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose,
+ * are disclaimed. In no event shall Distributed Processing Technology be
+ * liable for any direct, indirect, incidental, special, exemplary or
+ * consequential damages (including, but not limited to, procurement of
+ * substitute goods or services; loss of use, data, or profits; or business
+ * interruptions) however caused and on any theory of liability, whether in
+ * contract, strict liability, or tort (including negligence or otherwise)
+ * arising in any way out of the use of this driver software, even if advised
+ * of the possibility of such damage.
+ *
+ */
+
+#ifndef		_OSD_DEFS_H
+#define		_OSD_DEFS_H
+
+/*File - OSD_DEFS.H
+ ****************************************************************************
+ *
+ *Description:
+ *
+ *	This file contains the OS dependent defines.  This file is included
+ *in osd_util.h and provides the OS specific defines for that file.
+ *
+ *Copyright Distributed Processing Technology, Corp.
+ *	  140 Candace Dr.
+ *	  Maitland, Fl.	32751   USA
+ *	  Phone: (407) 830-5522  Fax: (407) 260-5366
+ *	  All Rights Reserved
+ *
+ *Author:	Doug Anderson
+ *Date:		1/31/94
+ *
+ *Editors:
+ *
+ *Remarks:
+ *
+ *
+ *****************************************************************************/
+
+
+/*Definitions - Defines & Constants ----------------------------------------- */
+
+  /* Define the operating system */
+#if (defined(__linux__))
+# define _DPT_LINUX
+#elif (defined(__bsdi__))
+# define _DPT_BSDI
+#elif (defined(__FreeBSD__))
+# define _DPT_FREE_BSD
+#else
+# define _DPT_SCO
+#endif
+
+#if defined (ZIL_CURSES)
+#define		_DPT_CURSES
+#else
+#define         _DPT_MOTIF
+#endif
+
+  /* Redefine 'far' to nothing - no far pointer type required in UNIX */
+#define		far
+
+  /* Define the mutually exclusive semaphore type */
+#define		SEMAPHORE_T	unsigned int *
+  /* Define a handle to a DLL */
+#define		DLL_HANDLE_T	unsigned int *
+
+#endif
diff --git a/drivers/scsi/dpt/osd_util.h b/drivers/scsi/dpt/osd_util.h
new file mode 100644
index 0000000..4b56c04
--- /dev/null
+++ b/drivers/scsi/dpt/osd_util.h
@@ -0,0 +1,358 @@
+/*	BSDI osd_util.h,v 1.8 1998/06/03 19:14:58 karels Exp	*/
+
+/*
+ * Copyright (c) 1996-1999 Distributed Processing Technology Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source form, with or without modification, are
+ * permitted provided that redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following disclaimer.
+ *
+ * This software is provided `as is' by Distributed Processing Technology and
+ * any express or implied warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose,
+ * are disclaimed. In no event shall Distributed Processing Technology be
+ * liable for any direct, indirect, incidental, special, exemplary or
+ * consequential damages (including, but not limited to, procurement of
+ * substitute goods or services; loss of use, data, or profits; or business
+ * interruptions) however caused and on any theory of liability, whether in
+ * contract, strict liability, or tort (including negligence or otherwise)
+ * arising in any way out of the use of this driver software, even if advised
+ * of the possibility of such damage.
+ *
+ */
+
+#ifndef         __OSD_UTIL_H
+#define         __OSD_UTIL_H
+
+/*File - OSD_UTIL.H
+ ****************************************************************************
+ *
+ *Description:
+ *
+ *      This file contains defines and function prototypes that are
+ *operating system dependent.  The resources defined in this file
+ *are not specific to any particular application.
+ *
+ *Copyright Distributed Processing Technology, Corp.
+ *        140 Candace Dr.
+ *        Maitland, Fl. 32751   USA
+ *        Phone: (407) 830-5522  Fax: (407) 260-5366
+ *        All Rights Reserved
+ *
+ *Author:       Doug Anderson
+ *Date:         1/7/94
+ *
+ *Editors:
+ *
+ *Remarks:
+ *
+ *
+ *****************************************************************************/
+
+
+/*Definitions - Defines & Constants ----------------------------------------- */
+
+/*----------------------------- */
+/* Operating system selections: */
+/*----------------------------- */
+
+/*#define               _DPT_MSDOS      */
+/*#define               _DPT_WIN_3X     */
+/*#define               _DPT_WIN_4X     */
+/*#define               _DPT_WIN_NT     */
+/*#define               _DPT_NETWARE    */
+/*#define               _DPT_OS2        */
+/*#define               _DPT_SCO        */
+/*#define               _DPT_UNIXWARE   */
+/*#define               _DPT_SOLARIS    */
+/*#define               _DPT_NEXTSTEP   */
+/*#define               _DPT_BANYAN     */
+
+/*-------------------------------- */
+/* Include the OS specific defines */
+/*-------------------------------- */
+
+/*#define       OS_SELECTION    From Above List */
+/*#define       SEMAPHORE_T     ??? */
+/*#define       DLL_HANDLE_T    ??? */
+
+#if (defined(KERNEL) && (defined(__FreeBSD__) || defined(__bsdi__)))
+# include        "i386/isa/dpt_osd_defs.h"
+#else
+# include        "osd_defs.h"
+#endif
+
+#ifndef DPT_UNALIGNED
+   #define      DPT_UNALIGNED
+#endif
+
+#ifndef DPT_EXPORT
+   #define      DPT_EXPORT
+#endif
+
+#ifndef DPT_IMPORT
+   #define      DPT_IMPORT
+#endif
+
+#ifndef DPT_RUNTIME_IMPORT
+   #define      DPT_RUNTIME_IMPORT  DPT_IMPORT
+#endif
+
+/*--------------------- */
+/* OS dependent defines */
+/*--------------------- */
+
+#if defined (_DPT_MSDOS) || defined (_DPT_WIN_3X)
+   #define      _DPT_16_BIT
+#else
+   #define      _DPT_32_BIT
+#endif
+
+#if defined (_DPT_SCO) || defined (_DPT_UNIXWARE) || defined (_DPT_SOLARIS) || defined (_DPT_AIX) || defined (SNI_MIPS) || defined (_DPT_BSDI) || defined (_DPT_FREE_BSD) || defined(_DPT_LINUX)
+   #define      _DPT_UNIX
+#endif
+
+#if defined (_DPT_WIN_3x) || defined (_DPT_WIN_4X) || defined (_DPT_WIN_NT) \
+	    || defined (_DPT_OS2)
+   #define      _DPT_DLL_SUPPORT
+#endif
+
+#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X) && !defined (_DPT_NETWARE)
+   #define      _DPT_PREEMPTIVE
+#endif
+
+#if !defined (_DPT_MSDOS) && !defined (_DPT_WIN_3X)
+   #define      _DPT_MULTI_THREADED
+#endif
+
+#if !defined (_DPT_MSDOS)
+   #define      _DPT_MULTI_TASKING
+#endif
+
+  /* These exist for platforms that   */
+  /* chunk when accessing mis-aligned */
+  /* data                             */
+#if defined (SNI_MIPS) || defined (_DPT_SOLARIS)
+   #if defined (_DPT_BIG_ENDIAN)
+	#if !defined (_DPT_STRICT_ALIGN)
+            #define _DPT_STRICT_ALIGN
+	#endif
+   #endif
+#endif
+
+  /* Determine if in C or C++ mode */
+#ifdef  __cplusplus
+   #define      _DPT_CPP
+#else
+   #define      _DPT_C
+#endif
+
+/*-------------------------------------------------------------------*/
+/* Under Solaris the compiler refuses to accept code like:           */
+/*   { {"DPT"}, 0, NULL .... },                                      */
+/* and complains about the {"DPT"} part by saying "cannot use { }    */
+/* to initialize char*".                                             */
+/*                                                                   */
+/* By defining these ugly macros we can get around this and also     */
+/* not have to copy and #ifdef large sections of code.  I know that  */
+/* these macros are *really* ugly, but they should help reduce       */
+/* maintenance in the long run.                                      */
+/*                                                                   */
+/*-------------------------------------------------------------------*/
+#if !defined (DPTSQO)
+   #if defined (_DPT_SOLARIS)
+      #define DPTSQO
+      #define DPTSQC
+   #else
+      #define DPTSQO {
+      #define DPTSQC }
+   #endif  /* solaris */
+#endif  /* DPTSQO */
+
+
+/*---------------------- */
+/* OS dependent typedefs */
+/*---------------------- */
+
+#if defined (_DPT_MSDOS) || defined (_DPT_SCO)
+   #define BYTE unsigned char
+   #define WORD unsigned short
+#endif
+
+#ifndef _DPT_TYPEDEFS
+   #define _DPT_TYPEDEFS
+   typedef unsigned char   uCHAR;
+   typedef unsigned short  uSHORT;
+   typedef unsigned int    uINT;
+   typedef unsigned long   uLONG;
+
+   typedef union {
+	 uCHAR        u8[4];
+	 uSHORT       u16[2];
+	 uLONG        u32;
+   } access_U;
+#endif
+
+#if !defined (NULL)
+   #define      NULL    0
+#endif
+
+
+/*Prototypes - function ----------------------------------------------------- */
+
+#ifdef  __cplusplus
+   extern "C" {         /* Declare all these functions as "C" functions */
+#endif
+
+/*------------------------ */
+/* Byte reversal functions */
+/*------------------------ */
+
+  /* Reverses the byte ordering of a 2 byte variable */
+#if (!defined(osdSwap2))
+ uSHORT       osdSwap2(DPT_UNALIGNED uSHORT *);
+#endif  // !osdSwap2
+
+  /* Reverses the byte ordering of a 4 byte variable and shifts left 8 bits */
+#if (!defined(osdSwap3))
+ uLONG        osdSwap3(DPT_UNALIGNED uLONG *);
+#endif  // !osdSwap3
+
+
+#ifdef  _DPT_NETWARE
+   #include "novpass.h" /* For DPT_Bswapl() prototype */
+	/* Inline the byte swap */
+   #ifdef __cplusplus
+	 inline uLONG osdSwap4(uLONG *inLong) {
+	 return *inLong = DPT_Bswapl(*inLong);
+	 }
+   #else
+	 #define osdSwap4(inLong)       DPT_Bswapl(inLong)
+   #endif  // cplusplus
+#else
+	/* Reverses the byte ordering of a 4 byte variable */
+# if (!defined(osdSwap4))
+   uLONG        osdSwap4(DPT_UNALIGNED uLONG *);
+# endif  // !osdSwap4
+
+  /* The following functions ALWAYS swap regardless of the *
+   * presence of DPT_BIG_ENDIAN                            */
+
+   uSHORT       trueSwap2(DPT_UNALIGNED uSHORT *);
+   uLONG        trueSwap4(DPT_UNALIGNED uLONG *);
+
+#endif  // netware
+
+
+/*-------------------------------------*
+ * Network order swap functions        *
+ *                                     *
+ * These functions/macros will be used *
+ * by the structure insert()/extract() *
+ * functions.                          *
+ *
+ * We will enclose all structure       *
+ * portability modifications inside    *
+ * #ifdefs.  When we are ready, we     *
+ * will #define DPT_PORTABLE to begin  *
+ * using the modifications.            *
+ *-------------------------------------*/
+uLONG	netSwap4(uLONG val);
+
+#if defined (_DPT_BIG_ENDIAN)
+
+// for big-endian we need to swap
+
+#ifndef NET_SWAP_2
+#define NET_SWAP_2(x) (((x) >> 8) | ((x) << 8))
+#endif  // NET_SWAP_2
+
+#ifndef NET_SWAP_4
+#define NET_SWAP_4(x) netSwap4((x))
+#endif  // NET_SWAP_4
+
+#else
+
+// for little-endian we don't need to do anything
+
+#ifndef NET_SWAP_2
+#define NET_SWAP_2(x) (x)
+#endif  // NET_SWAP_2
+
+#ifndef NET_SWAP_4
+#define NET_SWAP_4(x) (x)
+#endif  // NET_SWAP_4
+
+#endif  // big endian
+
+
+
+/*----------------------------------- */
+/* Run-time loadable module functions */
+/*----------------------------------- */
+
+  /* Loads the specified run-time loadable DLL */
+DLL_HANDLE_T    osdLoadModule(uCHAR *);
+  /* Unloads the specified run-time loadable DLL */
+uSHORT          osdUnloadModule(DLL_HANDLE_T);
+  /* Returns a pointer to a function inside a run-time loadable DLL */
+void *          osdGetFnAddr(DLL_HANDLE_T,uCHAR *);
+
+/*--------------------------------------- */
+/* Mutually exclusive semaphore functions */
+/*--------------------------------------- */
+
+  /* Create a named semaphore */
+SEMAPHORE_T     osdCreateNamedSemaphore(char *);
+  /* Create a mutually exlusive semaphore */
+SEMAPHORE_T     osdCreateSemaphore(void);
+	/* create an event semaphore */
+SEMAPHORE_T              osdCreateEventSemaphore(void);
+	/* create a named event semaphore */
+SEMAPHORE_T             osdCreateNamedEventSemaphore(char *);
+
+  /* Destroy the specified mutually exclusive semaphore object */
+uSHORT          osdDestroySemaphore(SEMAPHORE_T);
+  /* Request access to the specified mutually exclusive semaphore */
+uLONG           osdRequestSemaphore(SEMAPHORE_T,uLONG);
+  /* Release access to the specified mutually exclusive semaphore */
+uSHORT          osdReleaseSemaphore(SEMAPHORE_T);
+	/* wait for a event to happen */
+uLONG                            osdWaitForEventSemaphore(SEMAPHORE_T, uLONG);
+	/* signal an event */
+uLONG                            osdSignalEventSemaphore(SEMAPHORE_T);
+	/* reset the event */
+uLONG                            osdResetEventSemaphore(SEMAPHORE_T);
+
+/*----------------- */
+/* Thread functions */
+/*----------------- */
+
+  /* Releases control to the task switcher in non-preemptive */
+  /* multitasking operating systems. */
+void            osdSwitchThreads(void);
+
+  /* Starts a thread function */
+uLONG   osdStartThread(void *,void *);
+
+/* what is my thread id */
+uLONG osdGetThreadID(void);
+
+/* wakes up the specifed thread */
+void osdWakeThread(uLONG);
+
+/* osd sleep for x miliseconds */
+void osdSleep(uLONG);
+
+#define DPT_THREAD_PRIORITY_LOWEST 0x00
+#define DPT_THREAD_PRIORITY_NORMAL 0x01
+#define DPT_THREAD_PRIORITY_HIGHEST 0x02
+
+uCHAR osdSetThreadPriority(uLONG tid, uCHAR priority);
+
+#ifdef __cplusplus
+   }    /* end the xtern "C" declaration */
+#endif
+
+#endif  /* osd_util_h */
diff --git a/drivers/scsi/dpt/sys_info.h b/drivers/scsi/dpt/sys_info.h
new file mode 100644
index 0000000..d23b70c
--- /dev/null
+++ b/drivers/scsi/dpt/sys_info.h
@@ -0,0 +1,417 @@
+/*	BSDI sys_info.h,v 1.6 1998/06/03 19:14:59 karels Exp	*/
+
+/*
+ * Copyright (c) 1996-1999 Distributed Processing Technology Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source form, with or without modification, are
+ * permitted provided that redistributions of source code must retain the
+ * above copyright notice, this list of conditions and the following disclaimer.
+ *
+ * This software is provided `as is' by Distributed Processing Technology and
+ * any express or implied warranties, including, but not limited to, the
+ * implied warranties of merchantability and fitness for a particular purpose,
+ * are disclaimed. In no event shall Distributed Processing Technology be
+ * liable for any direct, indirect, incidental, special, exemplary or
+ * consequential damages (including, but not limited to, procurement of
+ * substitute goods or services; loss of use, data, or profits; or business
+ * interruptions) however caused and on any theory of liability, whether in
+ * contract, strict liability, or tort (including negligence or otherwise)
+ * arising in any way out of the use of this driver software, even if advised
+ * of the possibility of such damage.
+ *
+ */
+
+#ifndef         __SYS_INFO_H
+#define         __SYS_INFO_H
+
+/*File - SYS_INFO.H
+ ****************************************************************************
+ *
+ *Description:
+ *
+ *      This file contains structure definitions for the OS dependent
+ *layer system information buffers.
+ *
+ *Copyright Distributed Processing Technology, Corp.
+ *        140 Candace Dr.
+ *        Maitland, Fl. 32751   USA
+ *        Phone: (407) 830-5522  Fax: (407) 260-5366
+ *        All Rights Reserved
+ *
+ *Author:       Don Kemper
+ *Date:         5/10/94
+ *
+ *Editors:
+ *
+ *Remarks:
+ *
+ *
+ *****************************************************************************/
+
+
+/*Include Files ------------------------------------------------------------- */
+
+#include        "osd_util.h"
+
+#ifndef NO_PACK
+#if defined (_DPT_AIX)
+#pragma options align=packed
+#else
+#pragma pack(1)
+#endif  /* aix */
+#endif  // no unpack
+
+
+/*struct - driveParam_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the drive parameters seen during
+ *booting.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct driveParam_S {
+#else
+   typedef struct  {
+#endif
+
+   uSHORT       cylinders;      /* Upto 1024 */
+   uCHAR        heads;          /* Upto 255 */
+   uCHAR        sectors;        /* Upto 63 */
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } driveParam_S;
+#endif
+/*driveParam_S - end */
+
+
+/*struct - sysInfo_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the command system information that
+ *should be returned by every OS dependent layer.
+ *
+ *---------------------------------------------------------------------------*/
+
+/*flags - bit definitions */
+#define SI_CMOS_Valid           0x0001
+#define SI_NumDrivesValid       0x0002
+#define SI_ProcessorValid       0x0004
+#define SI_MemorySizeValid      0x0008
+#define SI_DriveParamsValid     0x0010
+#define SI_SmartROMverValid     0x0020
+#define SI_OSversionValid       0x0040
+#define SI_OSspecificValid      0x0080  /* 1 if OS structure returned */
+#define SI_BusTypeValid         0x0100
+
+#define SI_ALL_VALID            0x0FFF  /* All Std SysInfo is valid */
+#define SI_NO_SmartROM          0x8000
+
+/*busType - definitions */
+#define SI_ISA_BUS      0x00
+#define SI_MCA_BUS      0x01
+#define SI_EISA_BUS     0x02
+#define SI_PCI_BUS      0x04
+
+#ifdef  __cplusplus
+   struct sysInfo_S {
+#else
+   typedef struct  {
+#endif
+
+   uCHAR        drive0CMOS;             /* CMOS Drive 0 Type */
+   uCHAR        drive1CMOS;             /* CMOS Drive 1 Type */
+   uCHAR        numDrives;              /* 0040:0075 contents */
+   uCHAR        processorFamily;        /* Same as DPTSIG's definition */
+   uCHAR        processorType;          /* Same as DPTSIG's definition */
+   uCHAR        smartROMMajorVersion;
+   uCHAR        smartROMMinorVersion;   /* SmartROM version */
+   uCHAR        smartROMRevision;
+   uSHORT       flags;                  /* See bit definitions above */
+   uSHORT       conventionalMemSize;    /* in KB */
+   uLONG        extendedMemSize;        /* in KB */
+   uLONG        osType;                 /* Same as DPTSIG's definition */
+   uCHAR        osMajorVersion;
+   uCHAR        osMinorVersion;         /* The OS version */
+   uCHAR        osRevision;
+#ifdef _SINIX_ADDON
+   uCHAR        busType;                /* See defininitions above */
+   uSHORT       osSubRevision;
+   uCHAR        pad[2];                 /* For alignment */
+#else
+   uCHAR        osSubRevision;
+   uCHAR        busType;                /* See defininitions above */
+   uCHAR        pad[3];                 /* For alignment */
+#endif
+   driveParam_S drives[16];             /* SmartROM Logical Drives */
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } sysInfo_S;
+#endif
+/*sysInfo_S - end */
+
+
+/*struct - DOS_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to a
+ *DOS workstation.
+ *
+ *---------------------------------------------------------------------------*/
+
+/*flags - bit definitions */
+#define DI_DOS_HIGH             0x01    /* DOS is loaded high */
+#define DI_DPMI_VALID           0x02    /* DPMI version is valid */
+
+#ifdef  __cplusplus
+   struct DOS_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        flags;          /* See bit definitions above */
+   uSHORT       driverLocation; /* SmartROM BIOS address */
+   uSHORT       DOS_version;
+   uSHORT       DPMI_version;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } DOS_Info_S;
+#endif
+/*DOS_Info_S - end */
+
+
+/*struct - Netware_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to a
+ *Netware machine.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct Netware_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        driverName[13];         /* ie PM12NW31.DSK */
+   uCHAR        serverName[48];
+   uCHAR        netwareVersion;         /* The Netware OS version */
+   uCHAR        netwareSubVersion;
+   uCHAR        netwareRevision;
+   uSHORT       maxConnections;         /* Probably  250 or 1000 */
+   uSHORT       connectionsInUse;
+   uSHORT       maxVolumes;
+   uCHAR        unused;
+   uCHAR        SFTlevel;
+   uCHAR        TTSlevel;
+
+   uCHAR        clibMajorVersion;       /* The CLIB.NLM version */
+   uCHAR        clibMinorVersion;
+   uCHAR        clibRevision;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } Netware_Info_S;
+#endif
+/*Netware_Info_S - end */
+
+
+/*struct - OS2_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to an
+ *OS/2 machine.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct OS2_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        something;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } OS2_Info_S;
+#endif
+/*OS2_Info_S - end */
+
+
+/*struct - WinNT_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to a
+ *Windows NT machine.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct WinNT_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        something;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } WinNT_Info_S;
+#endif
+/*WinNT_Info_S - end */
+
+
+/*struct - SCO_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to an
+ *SCO UNIX machine.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct SCO_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        something;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } SCO_Info_S;
+#endif
+/*SCO_Info_S - end */
+
+
+/*struct - USL_Info_S - start
+ *===========================================================================
+ *
+ *Description:
+ *
+ *      This structure defines the system information specific to a
+ *USL UNIX machine.
+ *
+ *---------------------------------------------------------------------------*/
+
+#ifdef  __cplusplus
+   struct USL_Info_S {
+#else
+   typedef struct {
+#endif
+
+   uCHAR        something;
+
+#ifdef  __cplusplus
+
+//---------- Portability Additions ----------- in sp_sinfo.cpp
+#ifdef DPT_PORTABLE
+	uSHORT		netInsert(dptBuffer_S *buffer);
+	uSHORT		netExtract(dptBuffer_S *buffer);
+#endif // DPT PORTABLE
+//--------------------------------------------
+
+   };
+#else
+   } USL_Info_S;
+#endif
+/*USL_Info_S - end */
+
+
+  /* Restore default structure packing */
+#ifndef NO_UNPACK
+#if defined (_DPT_AIX)
+#pragma options align=reset
+#elif defined (UNPACK_FOUR)
+#pragma pack(4)
+#else
+#pragma pack()
+#endif  /* aix */
+#endif  // no unpack
+
+#endif  // __SYS_INFO_H
+
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
new file mode 100644
index 0000000..53c9b93
--- /dev/null
+++ b/drivers/scsi/dpt_i2o.c
@@ -0,0 +1,3381 @@
+/***************************************************************************
+                          dpti.c  -  description
+                             -------------------
+    begin                : Thu Sep 7 2000
+    copyright            : (C) 2000 by Adaptec
+
+			   July 30, 2001 First version being submitted
+			   for inclusion in the kernel.  V2.4
+
+    See Documentation/scsi/dpti.txt for history, notes, license info
+    and credits
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+/***************************************************************************
+ * Sat Dec 20 2003 Go Taniguchi <go@turbolinux.co.jp>
+ - Support 2.6 kernel and DMA-mapping
+ - ioctl fix for raid tools
+ - use schedule_timeout in long long loop
+ **************************************************************************/
+
+/*#define DEBUG 1 */
+/*#define UARTDELAY 1 */
+
+/* On the real kernel ADDR32 should always be zero for 2.4. GFP_HIGH allocates
+   high pages. Keep the macro around because of the broken unmerged ia64 tree */
+
+#define ADDR32 (0)
+
+#include <linux/version.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("Deanna Bonds, with _lots_ of help from Mark Salyzyn");
+MODULE_DESCRIPTION("Adaptec I2O RAID Driver");
+
+////////////////////////////////////////////////////////////////
+
+#include <linux/ioctl.h>	/* For SCSI-Passthrough */
+#include <asm/uaccess.h>
+
+#include <linux/stat.h>
+#include <linux/slab.h>		/* for kmalloc() */
+#include <linux/config.h>	/* for CONFIG_PCI */
+#include <linux/pci.h>		/* for PCI support */
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>	/* for udelay */
+#include <linux/interrupt.h>
+#include <linux/kernel.h>	/* for printk */
+#include <linux/sched.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <linux/smp_lock.h>
+
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+
+#include <asm/processor.h>	/* for boot_cpu_data */
+#include <asm/pgtable.h>
+#include <asm/io.h>		/* for virt_to_bus, etc. */
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "dpt/dptsig.h"
+#include "dpti.h"
+
+/*============================================================================
+ * Create a binary signature - this is read by dptsig
+ * Needed for our management apps
+ *============================================================================
+ */
+static dpt_sig_S DPTI_sig = {
+	{'d', 'P', 't', 'S', 'i', 'G'}, SIG_VERSION,
+#ifdef __i386__
+	PROC_INTEL, PROC_386 | PROC_486 | PROC_PENTIUM | PROC_SEXIUM,
+#elif defined(__ia64__)
+	PROC_INTEL, PROC_IA64,
+#elif defined(__sparc__)
+	PROC_ULTRASPARC, PROC_ULTRASPARC,
+#elif defined(__alpha__)
+	PROC_ALPHA, PROC_ALPHA,
+#else
+	(-1),(-1),
+#endif
+	 FT_HBADRVR, 0, OEM_DPT, OS_LINUX, CAP_OVERLAP, DEV_ALL,
+	ADF_ALL_SC5, 0, 0, DPT_VERSION, DPT_REVISION, DPT_SUBREVISION,
+	DPT_MONTH, DPT_DAY, DPT_YEAR, "Adaptec Linux I2O RAID Driver"
+};
+
+
+
+
+/*============================================================================
+ * Globals
+ *============================================================================
+ */
+
+static DECLARE_MUTEX(adpt_configuration_lock);
+
+static struct i2o_sys_tbl *sys_tbl = NULL;
+static int sys_tbl_ind = 0;
+static int sys_tbl_len = 0;
+
+static adpt_hba* hbas[DPTI_MAX_HBA];
+static adpt_hba* hba_chain = NULL;
+static int hba_count = 0;
+
+static struct file_operations adpt_fops = {
+	.ioctl		= adpt_ioctl,
+	.open		= adpt_open,
+	.release	= adpt_close
+};
+
+#ifdef REBOOT_NOTIFIER
+static struct notifier_block adpt_reboot_notifier =
+{
+	 adpt_reboot_event,
+	 NULL,
+	 0
+};
+#endif
+
+/* Structures and definitions for synchronous message posting.
+ * See adpt_i2o_post_wait() for description
+ * */
+struct adpt_i2o_post_wait_data
+{
+	int status;
+	u32 id;
+	adpt_wait_queue_head_t *wq;
+	struct adpt_i2o_post_wait_data *next;
+};
+
+static struct adpt_i2o_post_wait_data *adpt_post_wait_queue = NULL;
+static u32 adpt_post_wait_id = 0;
+static DEFINE_SPINLOCK(adpt_post_wait_lock);
+
+
+/*============================================================================
+ * 				Functions
+ *============================================================================
+ */
+
+static u8 adpt_read_blink_led(adpt_hba* host)
+{
+	if(host->FwDebugBLEDflag_P != 0) {
+		if( readb(host->FwDebugBLEDflag_P) == 0xbc ){
+			return readb(host->FwDebugBLEDvalue_P);
+		}
+	}
+	return 0;
+}
+
+/*============================================================================
+ * Scsi host template interface functions
+ *============================================================================
+ */
+
+static struct pci_device_id dptids[] = {
+	{ PCI_DPT_VENDOR_ID, PCI_DPT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{ PCI_DPT_VENDOR_ID, PCI_DPT_RAPTOR_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+	{ 0, }
+};
+MODULE_DEVICE_TABLE(pci,dptids);
+
+static int adpt_detect(struct scsi_host_template* sht)
+{
+	struct pci_dev *pDev = NULL;
+	adpt_hba* pHba;
+
+	adpt_init();
+
+	PINFO("Detecting Adaptec I2O RAID controllers...\n");
+
+        /* search for all Adatpec I2O RAID cards */
+	while ((pDev = pci_find_device( PCI_DPT_VENDOR_ID, PCI_ANY_ID, pDev))) {
+		if(pDev->device == PCI_DPT_DEVICE_ID ||
+		   pDev->device == PCI_DPT_RAPTOR_DEVICE_ID){
+			if(adpt_install_hba(sht, pDev) ){
+				PERROR("Could not Init an I2O RAID device\n");
+				PERROR("Will not try to detect others.\n");
+				return hba_count-1;
+			}
+		}
+	}
+
+	/* In INIT state, Activate IOPs */
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		// Activate does get status , init outbound, and get hrt
+		if (adpt_i2o_activate_hba(pHba) < 0) {
+			adpt_i2o_delete_hba(pHba);
+		}
+	}
+
+
+	/* Active IOPs in HOLD state */
+
+rebuild_sys_tab:
+	if (hba_chain == NULL) 
+		return 0;
+
+	/*
+	 * If build_sys_table fails, we kill everything and bail
+	 * as we can't init the IOPs w/o a system table
+	 */	
+	if (adpt_i2o_build_sys_table() < 0) {
+		adpt_i2o_sys_shutdown();
+		return 0;
+	}
+
+	PDEBUG("HBA's in HOLD state\n");
+
+	/* If IOP don't get online, we need to rebuild the System table */
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if (adpt_i2o_online_hba(pHba) < 0) {
+			adpt_i2o_delete_hba(pHba);	
+			goto rebuild_sys_tab;
+		}
+	}
+
+	/* Active IOPs now in OPERATIONAL state */
+	PDEBUG("HBA's in OPERATIONAL state\n");
+
+	printk("dpti: If you have a lot of devices this could take a few minutes.\n");
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		printk(KERN_INFO"%s: Reading the hardware resource table.\n", pHba->name);
+		if (adpt_i2o_lct_get(pHba) < 0){
+			adpt_i2o_delete_hba(pHba);
+			continue;
+		}
+
+		if (adpt_i2o_parse_lct(pHba) < 0){
+			adpt_i2o_delete_hba(pHba);
+			continue;
+		}
+		adpt_inquiry(pHba);
+	}
+
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if( adpt_scsi_register(pHba,sht) < 0){
+			adpt_i2o_delete_hba(pHba);
+			continue;
+		}
+		pHba->initialized = TRUE;
+		pHba->state &= ~DPTI_STATE_RESET;
+	}
+
+	// Register our control device node
+	// nodes will need to be created in /dev to access this
+	// the nodes can not be created from within the driver
+	if (hba_count && register_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER, &adpt_fops)) {
+		adpt_i2o_sys_shutdown();
+		return 0;
+	}
+	return hba_count;
+}
+
+
+/*
+ * scsi_unregister will be called AFTER we return. 
+ */
+static int adpt_release(struct Scsi_Host *host)
+{
+	adpt_hba* pHba = (adpt_hba*) host->hostdata[0];
+//	adpt_i2o_quiesce_hba(pHba);
+	adpt_i2o_delete_hba(pHba);
+	scsi_unregister(host);
+	return 0;
+}
+
+
+static void adpt_inquiry(adpt_hba* pHba)
+{
+	u32 msg[14]; 
+	u32 *mptr;
+	u32 *lenptr;
+	int direction;
+	int scsidir;
+	u32 len;
+	u32 reqlen;
+	u8* buf;
+	u8  scb[16];
+	s32 rcode;
+
+	memset(msg, 0, sizeof(msg));
+	buf = (u8*)kmalloc(80,GFP_KERNEL|ADDR32);
+	if(!buf){
+		printk(KERN_ERR"%s: Could not allocate buffer\n",pHba->name);
+		return;
+	}
+	memset((void*)buf, 0, 36);
+	
+	len = 36;
+	direction = 0x00000000;	
+	scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+
+	reqlen = 14;		// SINGLE SGE
+	/* Stick the headers on */
+	msg[0] = reqlen<<16 | SGL_OFFSET_12;
+	msg[1] = (0xff<<24|HOST_TID<<12|ADAPTER_TID);
+	msg[2] = 0;
+	msg[3]  = 0;
+	// Adaptec/DPT Private stuff 
+	msg[4] = I2O_CMD_SCSI_EXEC|DPT_ORGANIZATION_ID<<16;
+	msg[5] = ADAPTER_TID | 1<<16 /* Interpret*/;
+	/* Direction, disconnect ok | sense data | simple queue , CDBLen */
+	// I2O_SCB_FLAG_ENABLE_DISCONNECT | 
+	// I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | 
+	// I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
+	msg[6] = scsidir|0x20a00000| 6 /* cmd len*/;
+
+	mptr=msg+7;
+
+	memset(scb, 0, sizeof(scb));
+	// Write SCSI command into the message - always 16 byte block 
+	scb[0] = INQUIRY;
+	scb[1] = 0;
+	scb[2] = 0;
+	scb[3] = 0;
+	scb[4] = 36;
+	scb[5] = 0;
+	// Don't care about the rest of scb
+
+	memcpy(mptr, scb, sizeof(scb));
+	mptr+=4;
+	lenptr=mptr++;		/* Remember me - fill in when we know */
+
+	/* Now fill in the SGList and command */
+	*lenptr = len;
+	*mptr++ = 0xD0000000|direction|len;
+	*mptr++ = virt_to_bus(buf);
+
+	// Send it on it's way
+	rcode = adpt_i2o_post_wait(pHba, msg, reqlen<<2, 120);
+	if (rcode != 0) {
+		sprintf(pHba->detail, "Adaptec I2O RAID");
+		printk(KERN_INFO "%s: Inquiry Error (%d)\n",pHba->name,rcode);
+		if (rcode != -ETIME && rcode != -EINTR)
+			kfree(buf);
+	} else {
+		memset(pHba->detail, 0, sizeof(pHba->detail));
+		memcpy(&(pHba->detail), "Vendor: Adaptec ", 16);
+		memcpy(&(pHba->detail[16]), " Model: ", 8);
+		memcpy(&(pHba->detail[24]), (u8*) &buf[16], 16);
+		memcpy(&(pHba->detail[40]), " FW: ", 4);
+		memcpy(&(pHba->detail[44]), (u8*) &buf[32], 4);
+		pHba->detail[48] = '\0';	/* precautionary */
+		kfree(buf);
+	}
+	adpt_i2o_status_get(pHba);
+	return ;
+}
+
+
+static int adpt_slave_configure(struct scsi_device * device)
+{
+	struct Scsi_Host *host = device->host;
+	adpt_hba* pHba;
+
+	pHba = (adpt_hba *) host->hostdata[0];
+
+	if (host->can_queue && device->tagged_supported) {
+		scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+				host->can_queue - 1);
+	} else {
+		scsi_adjust_queue_depth(device, 0, 1);
+	}
+	return 0;
+}
+
+static int adpt_queue(struct scsi_cmnd * cmd, void (*done) (struct scsi_cmnd *))
+{
+	adpt_hba* pHba = NULL;
+	struct adpt_device* pDev = NULL;	/* dpt per device information */
+	ulong timeout = jiffies + (TMOUT_SCSI*HZ);
+
+	cmd->scsi_done = done;
+	/*
+	 * SCSI REQUEST_SENSE commands will be executed automatically by the 
+	 * Host Adapter for any errors, so they should not be executed 
+	 * explicitly unless the Sense Data is zero indicating that no error 
+	 * occurred.
+	 */
+
+	if ((cmd->cmnd[0] == REQUEST_SENSE) && (cmd->sense_buffer[0] != 0)) {
+		cmd->result = (DID_OK << 16);
+		cmd->scsi_done(cmd);
+		return 0;
+	}
+
+	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
+	if (!pHba) {
+		return FAILED;
+	}
+
+	rmb();
+	/*
+	 * TODO: I need to block here if I am processing ioctl cmds
+	 * but if the outstanding cmds all finish before the ioctl,
+	 * the scsi-core will not know to start sending cmds to me again.
+	 * I need to a way to restart the scsi-cores queues or should I block
+	 * calling scsi_done on the outstanding cmds instead
+	 * for now we don't set the IOCTL state
+	 */
+	if(((pHba->state) & DPTI_STATE_IOCTL) || ((pHba->state) & DPTI_STATE_RESET)) {
+		pHba->host->last_reset = jiffies;
+		pHba->host->resetting = 1;
+		return 1;
+	}
+
+	if(cmd->eh_state != SCSI_STATE_QUEUED){
+		// If we are not doing error recovery
+		mod_timer(&cmd->eh_timeout, timeout);
+	}
+
+	// TODO if the cmd->device if offline then I may need to issue a bus rescan
+	// followed by a get_lct to see if the device is there anymore
+	if((pDev = (struct adpt_device*) (cmd->device->hostdata)) == NULL) {
+		/*
+		 * First command request for this device.  Set up a pointer
+		 * to the device structure.  This should be a TEST_UNIT_READY
+		 * command from scan_scsis_single.
+		 */
+		if ((pDev = adpt_find_device(pHba, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun)) == NULL) {
+			// TODO: if any luns are at this bus, scsi id then fake a TEST_UNIT_READY and INQUIRY response 
+			// with type 7F (for all luns less than the max for this bus,id) so the lun scan will continue.
+			cmd->result = (DID_NO_CONNECT << 16);
+			cmd->scsi_done(cmd);
+			return 0;
+		}
+		cmd->device->hostdata = pDev;
+	}
+	pDev->pScsi_dev = cmd->device;
+
+	/*
+	 * If we are being called from when the device is being reset, 
+	 * delay processing of the command until later.
+	 */
+	if (pDev->state & DPTI_DEV_RESET ) {
+		return FAILED;
+	}
+	return adpt_scsi_to_i2o(pHba, cmd, pDev);
+}
+
+static int adpt_bios_param(struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int geom[])
+{
+	int heads=-1;
+	int sectors=-1;
+	int cylinders=-1;
+
+	// *** First lets set the default geometry ****
+	
+	// If the capacity is less than ox2000
+	if (capacity < 0x2000 ) {	// floppy
+		heads = 18;
+		sectors = 2;
+	} 
+	// else if between 0x2000 and 0x20000
+	else if (capacity < 0x20000) {
+		heads = 64;
+		sectors = 32;
+	}
+	// else if between 0x20000 and 0x40000
+	else if (capacity < 0x40000) {
+		heads = 65;
+		sectors = 63;
+	}
+	// else if between 0x4000 and 0x80000
+	else if (capacity < 0x80000) {
+		heads = 128;
+		sectors = 63;
+	}
+	// else if greater than 0x80000
+	else {
+		heads = 255;
+		sectors = 63;
+	}
+	cylinders = sector_div(capacity, heads * sectors);
+
+	// Special case if CDROM
+	if(sdev->type == 5) {  // CDROM
+		heads = 252;
+		sectors = 63;
+		cylinders = 1111;
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+	
+	PDEBUG("adpt_bios_param: exit\n");
+	return 0;
+}
+
+
+static const char *adpt_info(struct Scsi_Host *host)
+{
+	adpt_hba* pHba;
+
+	pHba = (adpt_hba *) host->hostdata[0];
+	return (char *) (pHba->detail);
+}
+
+static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+		  int length, int inout)
+{
+	struct adpt_device* d;
+	int id;
+	int chan;
+	int len = 0;
+	int begin = 0;
+	int pos = 0;
+	adpt_hba* pHba;
+	int unit;
+
+	*start = buffer;
+	if (inout == TRUE) {
+		/*
+		 * The user has done a write and wants us to take the
+		 * data in the buffer and do something with it.
+		 * proc_scsiwrite calls us with inout = 1
+		 *
+		 * Read data from buffer (writing to us) - NOT SUPPORTED
+		 */
+		return -EINVAL;
+	}
+
+	/*
+	 * inout = 0 means the user has done a read and wants information
+	 * returned, so we write information about the cards into the buffer
+	 * proc_scsiread() calls us with inout = 0
+	 */
+
+	// Find HBA (host bus adapter) we are looking for
+	down(&adpt_configuration_lock);
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if (pHba->host == host) {
+			break;	/* found adapter */
+		}
+	}
+	up(&adpt_configuration_lock);
+	if (pHba == NULL) {
+		return 0;
+	}
+	host = pHba->host;
+
+	len  = sprintf(buffer    , "Adaptec I2O RAID Driver Version: %s\n\n", DPT_I2O_VERSION);
+	len += sprintf(buffer+len, "%s\n", pHba->detail);
+	len += sprintf(buffer+len, "SCSI Host=scsi%d  Control Node=/dev/%s  irq=%d\n", 
+			pHba->host->host_no, pHba->name, host->irq);
+	len += sprintf(buffer+len, "\tpost fifo size  = %d\n\treply fifo size = %d\n\tsg table size   = %d\n\n",
+			host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize);
+
+	pos = begin + len;
+
+	/* CHECKPOINT */
+	if(pos > offset + length) {
+		goto stop_output;
+	}
+	if(pos <= offset) {
+		/*
+		 * If we haven't even written to where we last left
+		 * off (the last time we were called), reset the 
+		 * beginning pointer.
+		 */
+		len = 0;
+		begin = pos;
+	}
+	len +=  sprintf(buffer+len, "Devices:\n");
+	for(chan = 0; chan < MAX_CHANNEL; chan++) {
+		for(id = 0; id < MAX_ID; id++) {
+			d = pHba->channel[chan].device[id];
+			while(d){
+				len += sprintf(buffer+len,"\t%-24.24s", d->pScsi_dev->vendor);
+				len += sprintf(buffer+len," Rev: %-8.8s\n", d->pScsi_dev->rev);
+				pos = begin + len;
+
+
+				/* CHECKPOINT */
+				if(pos > offset + length) {
+					goto stop_output;
+				}
+				if(pos <= offset) {
+					len = 0;
+					begin = pos;
+				}
+
+				unit = d->pI2o_dev->lct_data.tid;
+				len += sprintf(buffer+len, "\tTID=%d, (Channel=%d, Target=%d, Lun=%d)  (%s)\n\n",
+					       unit, (int)d->scsi_channel, (int)d->scsi_id, (int)d->scsi_lun,
+					       scsi_device_online(d->pScsi_dev)? "online":"offline"); 
+				pos = begin + len;
+
+				/* CHECKPOINT */
+				if(pos > offset + length) {
+					goto stop_output;
+				}
+				if(pos <= offset) {
+					len = 0;
+					begin = pos;
+				}
+
+				d = d->next_lun;
+			}
+		}
+	}
+
+	/*
+	 * begin is where we last checked our position with regards to offset
+	 * begin is always less than offset.  len is relative to begin.  It
+	 * is the number of bytes written past begin
+	 *
+	 */
+stop_output:
+	/* stop the output and calculate the correct length */
+	*(buffer + len) = '\0';
+
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);
+	if(len > length) {
+		len = length;
+	} else if(len < 0){
+		len = 0;
+		**start = '\0';
+	}
+	return len;
+}
+
+
+/*===========================================================================
+ * Error Handling routines
+ *===========================================================================
+ */
+
+static int adpt_abort(struct scsi_cmnd * cmd)
+{
+	adpt_hba* pHba = NULL;	/* host bus adapter structure */
+	struct adpt_device* dptdevice;	/* dpt per device information */
+	u32 msg[5];
+	int rcode;
+
+	if(cmd->serial_number == 0){
+		return FAILED;
+	}
+	pHba = (adpt_hba*) cmd->device->host->hostdata[0];
+	printk(KERN_INFO"%s: Trying to Abort cmd=%ld\n",pHba->name, cmd->serial_number);
+	if ((dptdevice = (void*) (cmd->device->hostdata)) == NULL) {
+		printk(KERN_ERR "%s: Unable to abort: No device in cmnd\n",pHba->name);
+		return FAILED;
+	}
+
+	memset(msg, 0, sizeof(msg));
+	msg[0] = FIVE_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SCSI_ABORT<<24|HOST_TID<<12|dptdevice->tid;
+	msg[2] = 0;
+	msg[3]= 0; 
+	msg[4] = (u32)cmd;
+	if( (rcode = adpt_i2o_post_wait(pHba, msg, sizeof(msg), FOREVER)) != 0){
+		if(rcode == -EOPNOTSUPP ){
+			printk(KERN_INFO"%s: Abort cmd not supported\n",pHba->name);
+			return FAILED;
+		}
+		printk(KERN_INFO"%s: Abort cmd=%ld failed.\n",pHba->name, cmd->serial_number);
+		return FAILED;
+	} 
+	printk(KERN_INFO"%s: Abort cmd=%ld complete.\n",pHba->name, cmd->serial_number);
+	return SUCCESS;
+}
+
+
+#define I2O_DEVICE_RESET 0x27
+// This is the same for BLK and SCSI devices
+// NOTE this is wrong in the i2o.h definitions
+// This is not currently supported by our adapter but we issue it anyway
+static int adpt_device_reset(struct scsi_cmnd* cmd)
+{
+	adpt_hba* pHba;
+	u32 msg[4];
+	u32 rcode;
+	int old_state;
+	struct adpt_device* d = (void*) cmd->device->hostdata;
+
+	pHba = (void*) cmd->device->host->hostdata[0];
+	printk(KERN_INFO"%s: Trying to reset device\n",pHba->name);
+	if (!d) {
+		printk(KERN_INFO"%s: Reset Device: Device Not found\n",pHba->name);
+		return FAILED;
+	}
+	memset(msg, 0, sizeof(msg));
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = (I2O_DEVICE_RESET<<24|HOST_TID<<12|d->tid);
+	msg[2] = 0;
+	msg[3] = 0;
+
+	old_state = d->state;
+	d->state |= DPTI_DEV_RESET;
+	if( (rcode = adpt_i2o_post_wait(pHba, (void*)msg,sizeof(msg), FOREVER)) ){
+		d->state = old_state;
+		if(rcode == -EOPNOTSUPP ){
+			printk(KERN_INFO"%s: Device reset not supported\n",pHba->name);
+			return FAILED;
+		}
+		printk(KERN_INFO"%s: Device reset failed\n",pHba->name);
+		return FAILED;
+	} else {
+		d->state = old_state;
+		printk(KERN_INFO"%s: Device reset successful\n",pHba->name);
+		return SUCCESS;
+	}
+}
+
+
+#define I2O_HBA_BUS_RESET 0x87
+// This version of bus reset is called by the eh_error handler
+static int adpt_bus_reset(struct scsi_cmnd* cmd)
+{
+	adpt_hba* pHba;
+	u32 msg[4];
+
+	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
+	memset(msg, 0, sizeof(msg));
+	printk(KERN_WARNING"%s: Bus reset: SCSI Bus %d: tid: %d\n",pHba->name, cmd->device->channel,pHba->channel[cmd->device->channel].tid );
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = (I2O_HBA_BUS_RESET<<24|HOST_TID<<12|pHba->channel[cmd->device->channel].tid);
+	msg[2] = 0;
+	msg[3] = 0;
+	if(adpt_i2o_post_wait(pHba, (void*)msg,sizeof(msg), FOREVER) ){
+		printk(KERN_WARNING"%s: Bus reset failed.\n",pHba->name);
+		return FAILED;
+	} else {
+		printk(KERN_WARNING"%s: Bus reset success.\n",pHba->name);
+		return SUCCESS;
+	}
+}
+
+// This version of reset is called by the eh_error_handler
+static int adpt_reset(struct scsi_cmnd* cmd)
+{
+	adpt_hba* pHba;
+	int rcode;
+	pHba = (adpt_hba*)cmd->device->host->hostdata[0];
+	printk(KERN_WARNING"%s: Hba Reset: scsi id %d: tid: %d\n",pHba->name,cmd->device->channel,pHba->channel[cmd->device->channel].tid );
+	rcode =  adpt_hba_reset(pHba);
+	if(rcode == 0){
+		printk(KERN_WARNING"%s: HBA reset complete\n",pHba->name);
+		return SUCCESS;
+	} else {
+		printk(KERN_WARNING"%s: HBA reset failed (%x)\n",pHba->name, rcode);
+		return FAILED;
+	}
+}
+
+// This version of reset is called by the ioctls and indirectly from eh_error_handler via adpt_reset
+static int adpt_hba_reset(adpt_hba* pHba)
+{
+	int rcode;
+
+	pHba->state |= DPTI_STATE_RESET;
+
+	// Activate does get status , init outbound, and get hrt
+	if ((rcode=adpt_i2o_activate_hba(pHba)) < 0) {
+		printk(KERN_ERR "%s: Could not activate\n", pHba->name);
+		adpt_i2o_delete_hba(pHba);
+		return rcode;
+	}
+
+	if ((rcode=adpt_i2o_build_sys_table()) < 0) {
+		adpt_i2o_delete_hba(pHba);
+		return rcode;
+	}
+	PDEBUG("%s: in HOLD state\n",pHba->name);
+
+	if ((rcode=adpt_i2o_online_hba(pHba)) < 0) {
+		adpt_i2o_delete_hba(pHba);	
+		return rcode;
+	}
+	PDEBUG("%s: in OPERATIONAL state\n",pHba->name);
+
+	if ((rcode=adpt_i2o_lct_get(pHba)) < 0){
+		adpt_i2o_delete_hba(pHba);
+		return rcode;
+	}
+
+	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0){
+		adpt_i2o_delete_hba(pHba);
+		return rcode;
+	}
+	pHba->state &= ~DPTI_STATE_RESET;
+
+	adpt_fail_posted_scbs(pHba);
+	return 0;	/* return success */
+}
+
+/*===========================================================================
+ * 
+ *===========================================================================
+ */
+
+
+static void adpt_i2o_sys_shutdown(void)
+{
+	adpt_hba *pHba, *pNext;
+	struct adpt_i2o_post_wait_data *p1, *p2;
+
+	 printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n");
+	 printk(KERN_INFO"   This could take a few minutes if there are many devices attached\n");
+	/* Delete all IOPs from the controller chain */
+	/* They should have already been released by the
+	 * scsi-core
+	 */
+	for (pHba = hba_chain; pHba; pHba = pNext) {
+		pNext = pHba->next;
+		adpt_i2o_delete_hba(pHba);
+	}
+
+	/* Remove any timedout entries from the wait queue.  */
+	p2 = NULL;
+//	spin_lock_irqsave(&adpt_post_wait_lock, flags);
+	/* Nothing should be outstanding at this point so just
+	 * free them 
+	 */
+	for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p2->next) {
+		kfree(p1);
+	}
+//	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
+	adpt_post_wait_queue = NULL;
+
+	 printk(KERN_INFO "Adaptec I2O controllers down.\n");
+}
+
+/*
+ * reboot/shutdown notification.
+ *
+ * - Quiesce each IOP in the system
+ *
+ */
+
+#ifdef REBOOT_NOTIFIER
+static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p)
+{
+
+	 if(code != SYS_RESTART && code != SYS_HALT && code != SYS_POWER_OFF)
+		  return NOTIFY_DONE;
+
+	 adpt_i2o_sys_shutdown();
+
+	 return NOTIFY_DONE;
+}
+#endif
+
+
+static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) 
+{
+
+	adpt_hba* pHba = NULL;
+	adpt_hba* p = NULL;
+	ulong base_addr0_phys = 0;
+	ulong base_addr1_phys = 0;
+	u32 hba_map0_area_size = 0;
+	u32 hba_map1_area_size = 0;
+	void __iomem *base_addr_virt = NULL;
+	void __iomem *msg_addr_virt = NULL;
+
+	int raptorFlag = FALSE;
+	int i;
+
+	if(pci_enable_device(pDev)) {
+		return -EINVAL;
+	}
+	pci_set_master(pDev);
+	if (pci_set_dma_mask(pDev, 0xffffffffffffffffULL) &&
+	    pci_set_dma_mask(pDev, 0xffffffffULL))
+		return -EINVAL;
+
+	base_addr0_phys = pci_resource_start(pDev,0);
+	hba_map0_area_size = pci_resource_len(pDev,0);
+
+	// Check if standard PCI card or single BAR Raptor
+	if(pDev->device == PCI_DPT_DEVICE_ID){
+		if(pDev->subsystem_device >=0xc032 && pDev->subsystem_device <= 0xc03b){
+			// Raptor card with this device id needs 4M
+			hba_map0_area_size = 0x400000;
+		} else { // Not Raptor - it is a PCI card
+			if(hba_map0_area_size > 0x100000 ){ 
+				hba_map0_area_size = 0x100000;
+			}
+		}
+	} else {// Raptor split BAR config
+		// Use BAR1 in this configuration
+		base_addr1_phys = pci_resource_start(pDev,1);
+		hba_map1_area_size = pci_resource_len(pDev,1);
+		raptorFlag = TRUE;
+	}
+
+
+	base_addr_virt = ioremap(base_addr0_phys,hba_map0_area_size);
+	if (!base_addr_virt) {
+		PERROR("dpti: adpt_config_hba: io remap failed\n");
+		return -EINVAL;
+	}
+
+        if(raptorFlag == TRUE) {
+		msg_addr_virt = ioremap(base_addr1_phys, hba_map1_area_size );
+		if (!msg_addr_virt) {
+			PERROR("dpti: adpt_config_hba: io remap failed on BAR1\n");
+			iounmap(base_addr_virt);
+			return -EINVAL;
+		}
+	} else {
+		msg_addr_virt = base_addr_virt;
+	}
+	
+	// Allocate and zero the data structure
+	pHba = kmalloc(sizeof(adpt_hba), GFP_KERNEL);
+	if( pHba == NULL) {
+		if(msg_addr_virt != base_addr_virt){
+			iounmap(msg_addr_virt);
+		}
+		iounmap(base_addr_virt);
+		return -ENOMEM;
+	}
+	memset(pHba, 0, sizeof(adpt_hba));
+
+	down(&adpt_configuration_lock);
+	for(i=0;i<DPTI_MAX_HBA;i++) {
+		if(hbas[i]==NULL) {
+			hbas[i]=pHba;
+			break;
+		}
+	}
+
+	if(hba_chain != NULL){
+		for(p = hba_chain; p->next; p = p->next);
+		p->next = pHba;
+	} else {
+		hba_chain = pHba;
+	}
+	pHba->next = NULL;
+	pHba->unit = hba_count;
+	sprintf(pHba->name, "dpti%d", i);
+	hba_count++;
+	
+	up(&adpt_configuration_lock);
+
+	pHba->pDev = pDev;
+	pHba->base_addr_phys = base_addr0_phys;
+
+	// Set up the Virtual Base Address of the I2O Device
+	pHba->base_addr_virt = base_addr_virt;
+	pHba->msg_addr_virt = msg_addr_virt;
+	pHba->irq_mask = base_addr_virt+0x30;
+	pHba->post_port = base_addr_virt+0x40;
+	pHba->reply_port = base_addr_virt+0x44;
+
+	pHba->hrt = NULL;
+	pHba->lct = NULL;
+	pHba->lct_size = 0;
+	pHba->status_block = NULL;
+	pHba->post_count = 0;
+	pHba->state = DPTI_STATE_RESET;
+	pHba->pDev = pDev;
+	pHba->devices = NULL;
+
+	// Initializing the spinlocks
+	spin_lock_init(&pHba->state_lock);
+	spin_lock_init(&adpt_post_wait_lock);
+
+	if(raptorFlag == 0){
+		printk(KERN_INFO"Adaptec I2O RAID controller %d at %p size=%x irq=%d\n", 
+			hba_count-1, base_addr_virt, hba_map0_area_size, pDev->irq);
+	} else {
+		printk(KERN_INFO"Adaptec I2O RAID controller %d irq=%d\n",hba_count-1, pDev->irq);
+		printk(KERN_INFO"     BAR0 %p - size= %x\n",base_addr_virt,hba_map0_area_size);
+		printk(KERN_INFO"     BAR1 %p - size= %x\n",msg_addr_virt,hba_map1_area_size);
+	}
+
+	if (request_irq (pDev->irq, adpt_isr, SA_SHIRQ, pHba->name, pHba)) {
+		printk(KERN_ERR"%s: Couldn't register IRQ %d\n", pHba->name, pDev->irq);
+		adpt_i2o_delete_hba(pHba);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+
+static void adpt_i2o_delete_hba(adpt_hba* pHba)
+{
+	adpt_hba* p1;
+	adpt_hba* p2;
+	struct i2o_device* d;
+	struct i2o_device* next;
+	int i;
+	int j;
+	struct adpt_device* pDev;
+	struct adpt_device* pNext;
+
+
+	down(&adpt_configuration_lock);
+	// scsi_unregister calls our adpt_release which
+	// does a quiese
+	if(pHba->host){
+		free_irq(pHba->host->irq, pHba);
+	}
+	for(i=0;i<DPTI_MAX_HBA;i++) {
+		if(hbas[i]==pHba) {
+			hbas[i] = NULL;
+		}
+	}
+	p2 = NULL;
+	for( p1 = hba_chain; p1; p2 = p1,p1=p1->next){
+		if(p1 == pHba) {
+			if(p2) {
+				p2->next = p1->next;
+			} else {
+				hba_chain = p1->next;
+			}
+			break;
+		}
+	}
+
+	hba_count--;
+	up(&adpt_configuration_lock);
+
+	iounmap(pHba->base_addr_virt);
+	if(pHba->msg_addr_virt != pHba->base_addr_virt){
+		iounmap(pHba->msg_addr_virt);
+	}
+	if(pHba->hrt) {
+		kfree(pHba->hrt);
+	}
+	if(pHba->lct){
+		kfree(pHba->lct);
+	}
+	if(pHba->status_block) {
+		kfree(pHba->status_block);
+	}
+	if(pHba->reply_pool){
+		kfree(pHba->reply_pool);
+	}
+
+	for(d = pHba->devices; d ; d = next){
+		next = d->next;
+		kfree(d);
+	}
+	for(i = 0 ; i < pHba->top_scsi_channel ; i++){
+		for(j = 0; j < MAX_ID; j++){
+			if(pHba->channel[i].device[j] != NULL){
+				for(pDev = pHba->channel[i].device[j]; pDev; pDev = pNext){
+					pNext = pDev->next_lun;
+					kfree(pDev);
+				}
+			}
+		}
+	}
+	kfree(pHba);
+
+	if(hba_count <= 0){
+		unregister_chrdev(DPTI_I2O_MAJOR, DPT_DRIVER);   
+	}
+}
+
+
+static int adpt_init(void)
+{
+	int i;
+
+	printk("Loading Adaptec I2O RAID: Version " DPT_I2O_VERSION "\n");
+	for (i = 0; i < DPTI_MAX_HBA; i++) {
+		hbas[i] = NULL;
+	}
+#ifdef REBOOT_NOTIFIER
+	register_reboot_notifier(&adpt_reboot_notifier);
+#endif
+
+	return 0;
+}
+
+
+static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun)
+{
+	struct adpt_device* d;
+
+	if(chan < 0 || chan >= MAX_CHANNEL)
+		return NULL;
+	
+	if( pHba->channel[chan].device == NULL){
+		printk(KERN_DEBUG"Adaptec I2O RAID: Trying to find device before they are allocated\n");
+		return NULL;
+	}
+
+	d = pHba->channel[chan].device[id];
+	if(!d || d->tid == 0) {
+		return NULL;
+	}
+
+	/* If it is the only lun at that address then this should match*/
+	if(d->scsi_lun == lun){
+		return d;
+	}
+
+	/* else we need to look through all the luns */
+	for(d=d->next_lun ; d ; d = d->next_lun){
+		if(d->scsi_lun == lun){
+			return d;
+		}
+	}
+	return NULL;
+}
+
+
+static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout)
+{
+	// I used my own version of the WAIT_QUEUE_HEAD
+	// to handle some version differences
+	// When embedded in the kernel this could go back to the vanilla one
+	ADPT_DECLARE_WAIT_QUEUE_HEAD(adpt_wq_i2o_post);
+	int status = 0;
+	ulong flags = 0;
+	struct adpt_i2o_post_wait_data *p1, *p2;
+	struct adpt_i2o_post_wait_data *wait_data =
+		kmalloc(sizeof(struct adpt_i2o_post_wait_data),GFP_KERNEL);
+	adpt_wait_queue_t wait;
+
+	if(!wait_data){
+		return -ENOMEM;
+	}
+	/*
+	 * The spin locking is needed to keep anyone from playing
+	 * with the queue pointers and id while we do the same
+	 */
+	spin_lock_irqsave(&adpt_post_wait_lock, flags);
+       // TODO we need a MORE unique way of getting ids
+       // to support async LCT get
+	wait_data->next = adpt_post_wait_queue;
+	adpt_post_wait_queue = wait_data;
+	adpt_post_wait_id++;
+	adpt_post_wait_id &= 0x7fff;
+	wait_data->id =  adpt_post_wait_id;
+	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
+
+	wait_data->wq = &adpt_wq_i2o_post;
+	wait_data->status = -ETIMEDOUT;
+
+	// this code is taken from kernel/sched.c:interruptible_sleep_on_timeout
+	wait.task = current;
+	init_waitqueue_entry(&wait, current);
+	spin_lock_irqsave(&adpt_wq_i2o_post.lock, flags);
+	__add_wait_queue(&adpt_wq_i2o_post, &wait);
+	spin_unlock(&adpt_wq_i2o_post.lock);
+
+	msg[2] |= 0x80000000 | ((u32)wait_data->id);
+	timeout *= HZ;
+	if((status = adpt_i2o_post_this(pHba, msg, len)) == 0){
+		set_current_state(TASK_INTERRUPTIBLE);
+		if(pHba->host)
+			spin_unlock_irq(pHba->host->host_lock);
+		if (!timeout)
+			schedule();
+		else{
+			timeout = schedule_timeout(timeout);
+			if (timeout == 0) {
+				// I/O issued, but cannot get result in
+				// specified time. Freeing resorces is
+				// dangerous.
+				status = -ETIME;
+			}
+		}
+		if(pHba->host)
+			spin_lock_irq(pHba->host->host_lock);
+	}
+	spin_lock_irq(&adpt_wq_i2o_post.lock);
+	__remove_wait_queue(&adpt_wq_i2o_post, &wait);
+	spin_unlock_irqrestore(&adpt_wq_i2o_post.lock, flags);
+
+	if(status == -ETIMEDOUT){
+		printk(KERN_INFO"dpti%d: POST WAIT TIMEOUT\n",pHba->unit);
+		// We will have to free the wait_data memory during shutdown
+		return status;
+	}
+
+	/* Remove the entry from the queue.  */
+	p2 = NULL;
+	spin_lock_irqsave(&adpt_post_wait_lock, flags);
+	for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p1->next) {
+		if(p1 == wait_data) {
+			if(p1->status == I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION ) {
+				status = -EOPNOTSUPP;
+			}
+			if(p2) {
+				p2->next = p1->next;
+			} else {
+				adpt_post_wait_queue = p1->next;
+			}
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&adpt_post_wait_lock, flags);
+
+	kfree(wait_data);
+
+	return status;
+}
+
+
+static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len)
+{
+
+	u32 m = EMPTY_QUEUE;
+	u32 __iomem *msg;
+	ulong timeout = jiffies + 30*HZ;
+	do {
+		rmb();
+		m = readl(pHba->post_port);
+		if (m != EMPTY_QUEUE) {
+			break;
+		}
+		if(time_after(jiffies,timeout)){
+			printk(KERN_WARNING"dpti%d: Timeout waiting for message frame!\n", pHba->unit);
+			return -ETIMEDOUT;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while(m == EMPTY_QUEUE);
+		
+	msg = pHba->msg_addr_virt + m;
+	memcpy_toio(msg, data, len);
+	wmb();
+
+	//post message
+	writel(m, pHba->post_port);
+	wmb();
+
+	return 0;
+}
+
+
+static void adpt_i2o_post_wait_complete(u32 context, int status)
+{
+	struct adpt_i2o_post_wait_data *p1 = NULL;
+	/*
+	 * We need to search through the adpt_post_wait
+	 * queue to see if the given message is still
+	 * outstanding.  If not, it means that the IOP
+	 * took longer to respond to the message than we
+	 * had allowed and timer has already expired.
+	 * Not much we can do about that except log
+	 * it for debug purposes, increase timeout, and recompile
+	 *
+	 * Lock needed to keep anyone from moving queue pointers
+	 * around while we're looking through them.
+	 */
+
+	context &= 0x7fff;
+
+	spin_lock(&adpt_post_wait_lock);
+	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {
+		if(p1->id == context) {
+			p1->status = status;
+			spin_unlock(&adpt_post_wait_lock);
+			wake_up_interruptible(p1->wq);
+			return;
+		}
+	}
+	spin_unlock(&adpt_post_wait_lock);
+        // If this happens we lose commands that probably really completed
+	printk(KERN_DEBUG"dpti: Could Not find task %d in wait queue\n",context);
+	printk(KERN_DEBUG"      Tasks in wait queue:\n");
+	for(p1 = adpt_post_wait_queue; p1; p1 = p1->next) {
+		printk(KERN_DEBUG"           %d\n",p1->id);
+	}
+	return;
+}
+
+static s32 adpt_i2o_reset_hba(adpt_hba* pHba)			
+{
+	u32 msg[8];
+	u8* status;
+	u32 m = EMPTY_QUEUE ;
+	ulong timeout = jiffies + (TMOUT_IOPRESET*HZ);
+
+	if(pHba->initialized  == FALSE) {	// First time reset should be quick
+		timeout = jiffies + (25*HZ);
+	} else {
+		adpt_i2o_quiesce_hba(pHba);
+	}
+
+	do {
+		rmb();
+		m = readl(pHba->post_port);
+		if (m != EMPTY_QUEUE) {
+			break;
+		}
+		if(time_after(jiffies,timeout)){
+			printk(KERN_WARNING"Timeout waiting for message!\n");
+			return -ETIMEDOUT;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while (m == EMPTY_QUEUE);
+
+	status = (u8*)kmalloc(4, GFP_KERNEL|ADDR32);
+	if(status == NULL) {
+		adpt_send_nop(pHba, m);
+		printk(KERN_ERR"IOP reset failed - no free memory.\n");
+		return -ENOMEM;
+	}
+	memset(status,0,4);
+
+	msg[0]=EIGHT_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_ADAPTER_RESET<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]=0;
+	msg[3]=0;
+	msg[4]=0;
+	msg[5]=0;
+	msg[6]=virt_to_bus(status);
+	msg[7]=0;     
+
+	memcpy_toio(pHba->msg_addr_virt+m, msg, sizeof(msg));
+	wmb();
+	writel(m, pHba->post_port);
+	wmb();
+
+	while(*status == 0){
+		if(time_after(jiffies,timeout)){
+			printk(KERN_WARNING"%s: IOP Reset Timeout\n",pHba->name);
+			kfree(status);
+			return -ETIMEDOUT;
+		}
+		rmb();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	if(*status == 0x01 /*I2O_EXEC_IOP_RESET_IN_PROGRESS*/) {
+		PDEBUG("%s: Reset in progress...\n", pHba->name);
+		// Here we wait for message frame to become available
+		// indicated that reset has finished
+		do {
+			rmb();
+			m = readl(pHba->post_port);
+			if (m != EMPTY_QUEUE) {
+				break;
+			}
+			if(time_after(jiffies,timeout)){
+				printk(KERN_ERR "%s:Timeout waiting for IOP Reset.\n",pHba->name);
+				return -ETIMEDOUT;
+			}
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			schedule_timeout(1);
+		} while (m == EMPTY_QUEUE);
+		// Flush the offset
+		adpt_send_nop(pHba, m);
+	}
+	adpt_i2o_status_get(pHba);
+	if(*status == 0x02 ||
+			pHba->status_block->iop_state != ADAPTER_STATE_RESET) {
+		printk(KERN_WARNING"%s: Reset reject, trying to clear\n",
+				pHba->name);
+	} else {
+		PDEBUG("%s: Reset completed.\n", pHba->name);
+	}
+
+	kfree(status);
+#ifdef UARTDELAY
+	// This delay is to allow someone attached to the card through the debug UART to 
+	// set up the dump levels that they want before the rest of the initialization sequence
+	adpt_delay(20000);
+#endif
+	return 0;
+}
+
+
+static int adpt_i2o_parse_lct(adpt_hba* pHba)
+{
+	int i;
+	int max;
+	int tid;
+	struct i2o_device *d;
+	i2o_lct *lct = pHba->lct;
+	u8 bus_no = 0;
+	s16 scsi_id;
+	s16 scsi_lun;
+	u32 buf[10]; // larger than 7, or 8 ...
+	struct adpt_device* pDev; 
+	
+	if (lct == NULL) {
+		printk(KERN_ERR "%s: LCT is empty???\n",pHba->name);
+		return -1;
+	}
+	
+	max = lct->table_size;	
+	max -= 3;
+	max /= 9;
+
+	for(i=0;i<max;i++) {
+		if( lct->lct_entry[i].user_tid != 0xfff){
+			/*
+			 * If we have hidden devices, we need to inform the upper layers about
+			 * the possible maximum id reference to handle device access when
+			 * an array is disassembled. This code has no other purpose but to
+			 * allow us future access to devices that are currently hidden
+			 * behind arrays, hotspares or have not been configured (JBOD mode).
+			 */
+			if( lct->lct_entry[i].class_id != I2O_CLASS_RANDOM_BLOCK_STORAGE &&
+			    lct->lct_entry[i].class_id != I2O_CLASS_SCSI_PERIPHERAL &&
+			    lct->lct_entry[i].class_id != I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
+			    	continue;
+			}
+			tid = lct->lct_entry[i].tid;
+			// I2O_DPT_DEVICE_INFO_GROUP_NO;
+			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) {
+				continue;
+			}
+			bus_no = buf[0]>>16;
+			scsi_id = buf[1];
+			scsi_lun = (buf[2]>>8 )&0xff;
+			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
+				printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);
+				continue;
+			}
+			if (scsi_id >= MAX_ID){
+				printk(KERN_WARNING"%s: SCSI ID %d out of range \n", pHba->name, bus_no);
+				continue;
+			}
+			if(bus_no > pHba->top_scsi_channel){
+				pHba->top_scsi_channel = bus_no;
+			}
+			if(scsi_id > pHba->top_scsi_id){
+				pHba->top_scsi_id = scsi_id;
+			}
+			if(scsi_lun > pHba->top_scsi_lun){
+				pHba->top_scsi_lun = scsi_lun;
+			}
+			continue;
+		}
+		d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+		if(d==NULL)
+		{
+			printk(KERN_CRIT"%s: Out of memory for I2O device data.\n",pHba->name);
+			return -ENOMEM;
+		}
+		
+		d->controller = (void*)pHba;
+		d->next = NULL;
+
+		memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
+
+		d->flags = 0;
+		tid = d->lct_data.tid;
+		adpt_i2o_report_hba_unit(pHba, d);
+		adpt_i2o_install_device(pHba, d);
+	}
+	bus_no = 0;
+	for(d = pHba->devices; d ; d = d->next) {
+		if(d->lct_data.class_id  == I2O_CLASS_BUS_ADAPTER_PORT ||
+		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PORT){
+			tid = d->lct_data.tid;
+			// TODO get the bus_no from hrt-but for now they are in order
+			//bus_no = 
+			if(bus_no > pHba->top_scsi_channel){
+				pHba->top_scsi_channel = bus_no;
+			}
+			pHba->channel[bus_no].type = d->lct_data.class_id;
+			pHba->channel[bus_no].tid = tid;
+			if(adpt_i2o_query_scalar(pHba, tid, 0x0200, -1, buf, 28)>=0)
+			{
+				pHba->channel[bus_no].scsi_id = buf[1];
+				PDEBUG("Bus %d - SCSI ID %d.\n", bus_no, buf[1]);
+			}
+			// TODO remove - this is just until we get from hrt
+			bus_no++;
+			if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
+				printk(KERN_WARNING"%s: Channel number %d out of range - LCT\n", pHba->name, bus_no);
+				break;
+			}
+		}
+	}
+
+	// Setup adpt_device table
+	for(d = pHba->devices; d ; d = d->next) {
+		if(d->lct_data.class_id  == I2O_CLASS_RANDOM_BLOCK_STORAGE ||
+		   d->lct_data.class_id  == I2O_CLASS_SCSI_PERIPHERAL ||
+		   d->lct_data.class_id  == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
+
+			tid = d->lct_data.tid;
+			scsi_id = -1;
+			// I2O_DPT_DEVICE_INFO_GROUP_NO;
+			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)>=0) {
+				bus_no = buf[0]>>16;
+				scsi_id = buf[1];
+				scsi_lun = (buf[2]>>8 )&0xff;
+				if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
+					continue;
+				}
+				if (scsi_id >= MAX_ID) {
+					continue;
+				}
+				if( pHba->channel[bus_no].device[scsi_id] == NULL){
+					pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					if(pDev == NULL) {
+						return -ENOMEM;
+					}
+					pHba->channel[bus_no].device[scsi_id] = pDev;
+					memset(pDev,0,sizeof(struct adpt_device));
+				} else {
+					for( pDev = pHba->channel[bus_no].device[scsi_id];	
+							pDev->next_lun; pDev = pDev->next_lun){
+					}
+					pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					if(pDev->next_lun == NULL) {
+						return -ENOMEM;
+					}
+					memset(pDev->next_lun,0,sizeof(struct adpt_device));
+					pDev = pDev->next_lun;
+				}
+				pDev->tid = tid;
+				pDev->scsi_channel = bus_no;
+				pDev->scsi_id = scsi_id;
+				pDev->scsi_lun = scsi_lun;
+				pDev->pI2o_dev = d;
+				d->owner = pDev;
+				pDev->type = (buf[0])&0xff;
+				pDev->flags = (buf[0]>>8)&0xff;
+				if(scsi_id > pHba->top_scsi_id){
+					pHba->top_scsi_id = scsi_id;
+				}
+				if(scsi_lun > pHba->top_scsi_lun){
+					pHba->top_scsi_lun = scsi_lun;
+				}
+			}
+			if(scsi_id == -1){
+				printk(KERN_WARNING"Could not find SCSI ID for %s\n",
+						d->lct_data.identity_tag);
+			}
+		}
+	}
+	return 0;
+}
+
+
+/*
+ *	Each I2O controller has a chain of devices on it - these match
+ *	the useful parts of the LCT of the board.
+ */
+ 
+static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d)
+{
+	down(&adpt_configuration_lock);
+	d->controller=pHba;
+	d->owner=NULL;
+	d->next=pHba->devices;
+	d->prev=NULL;
+	if (pHba->devices != NULL){
+		pHba->devices->prev=d;
+	}
+	pHba->devices=d;
+	*d->dev_name = 0;
+
+	up(&adpt_configuration_lock);
+	return 0;
+}
+
+static int adpt_open(struct inode *inode, struct file *file)
+{
+	int minor;
+	adpt_hba* pHba;
+
+	//TODO check for root access
+	//
+	minor = iminor(inode);
+	if (minor >= hba_count) {
+		return -ENXIO;
+	}
+	down(&adpt_configuration_lock);
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if (pHba->unit == minor) {
+			break;	/* found adapter */
+		}
+	}
+	if (pHba == NULL) {
+		up(&adpt_configuration_lock);
+		return -ENXIO;
+	}
+
+//	if(pHba->in_use){
+	//	up(&adpt_configuration_lock);
+//		return -EBUSY;
+//	}
+
+	pHba->in_use = 1;
+	up(&adpt_configuration_lock);
+
+	return 0;
+}
+
+static int adpt_close(struct inode *inode, struct file *file)
+{
+	int minor;
+	adpt_hba* pHba;
+
+	minor = iminor(inode);
+	if (minor >= hba_count) {
+		return -ENXIO;
+	}
+	down(&adpt_configuration_lock);
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if (pHba->unit == minor) {
+			break;	/* found adapter */
+		}
+	}
+	up(&adpt_configuration_lock);
+	if (pHba == NULL) {
+		return -ENXIO;
+	}
+
+	pHba->in_use = 0;
+
+	return 0;
+}
+
+
+static int adpt_i2o_passthru(adpt_hba* pHba, u32 __user *arg)
+{
+	u32 msg[MAX_MESSAGE_SIZE];
+	u32* reply = NULL;
+	u32 size = 0;
+	u32 reply_size = 0;
+	u32 __user *user_msg = arg;
+	u32 __user * user_reply = NULL;
+	void *sg_list[pHba->sg_tablesize];
+	u32 sg_offset = 0;
+	u32 sg_count = 0;
+	int sg_index = 0;
+	u32 i = 0;
+	u32 rcode = 0;
+	void *p = NULL;
+	ulong flags = 0;
+
+	memset(&msg, 0, MAX_MESSAGE_SIZE*4);
+	// get user msg size in u32s 
+	if(get_user(size, &user_msg[0])){
+		return -EFAULT;
+	}
+	size = size>>16;
+
+	user_reply = &user_msg[size];
+	if(size > MAX_MESSAGE_SIZE){
+		return -EFAULT;
+	}
+	size *= 4; // Convert to bytes
+
+	/* Copy in the user's I2O command */
+	if(copy_from_user(msg, user_msg, size)) {
+		return -EFAULT;
+	}
+	get_user(reply_size, &user_reply[0]);
+	reply_size = reply_size>>16;
+	if(reply_size > REPLY_FRAME_SIZE){
+		reply_size = REPLY_FRAME_SIZE;
+	}
+	reply_size *= 4;
+	reply = kmalloc(REPLY_FRAME_SIZE*4, GFP_KERNEL);
+	if(reply == NULL) {
+		printk(KERN_WARNING"%s: Could not allocate reply buffer\n",pHba->name);
+		return -ENOMEM;
+	}
+	memset(reply,0,REPLY_FRAME_SIZE*4);
+	sg_offset = (msg[0]>>4)&0xf;
+	msg[2] = 0x40000000; // IOCTL context
+	msg[3] = (u32)reply;
+	memset(sg_list,0, sizeof(sg_list[0])*pHba->sg_tablesize);
+	if(sg_offset) {
+		// TODO 64bit fix
+		struct sg_simple_element *sg =  (struct sg_simple_element*) (msg+sg_offset);
+		sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
+		if (sg_count > pHba->sg_tablesize){
+			printk(KERN_DEBUG"%s:IOCTL SG List too large (%u)\n", pHba->name,sg_count);
+			kfree (reply);
+			return -EINVAL;
+		}
+
+		for(i = 0; i < sg_count; i++) {
+			int sg_size;
+
+			if (!(sg[i].flag_count & 0x10000000 /*I2O_SGL_FLAGS_SIMPLE_ADDRESS_ELEMENT*/)) {
+				printk(KERN_DEBUG"%s:Bad SG element %d - not simple (%x)\n",pHba->name,i,  sg[i].flag_count);
+				rcode = -EINVAL;
+				goto cleanup;
+			}
+			sg_size = sg[i].flag_count & 0xffffff;      
+			/* Allocate memory for the transfer */
+			p = kmalloc(sg_size, GFP_KERNEL|ADDR32);
+			if(!p) {
+				printk(KERN_DEBUG"%s: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+						pHba->name,sg_size,i,sg_count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_list[sg_index++] = p; // sglist indexed with input frame, not our internal frame.
+			/* Copy in the user's SG buffer if necessary */
+			if(sg[i].flag_count & 0x04000000 /*I2O_SGL_FLAGS_DIR*/) {
+				// TODO 64bit fix
+				if (copy_from_user(p,(void __user *)sg[i].addr_bus, sg_size)) {
+					printk(KERN_DEBUG"%s: Could not copy SG buf %d FROM user\n",pHba->name,i);
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			//TODO 64bit fix
+			sg[i].addr_bus = (u32)virt_to_bus(p);
+		}
+	}
+
+	do {
+		if(pHba->host)
+			spin_lock_irqsave(pHba->host->host_lock, flags);
+		// This state stops any new commands from enterring the
+		// controller while processing the ioctl
+//		pHba->state |= DPTI_STATE_IOCTL;
+//		We can't set this now - The scsi subsystem sets host_blocked and
+//		the queue empties and stops.  We need a way to restart the queue
+		rcode = adpt_i2o_post_wait(pHba, msg, size, FOREVER);
+		if (rcode != 0)
+			printk("adpt_i2o_passthru: post wait failed %d %p\n",
+					rcode, reply);
+//		pHba->state &= ~DPTI_STATE_IOCTL;
+		if(pHba->host)
+			spin_unlock_irqrestore(pHba->host->host_lock, flags);
+	} while(rcode == -ETIMEDOUT);  
+
+	if(rcode){
+		goto cleanup;
+	}
+
+	if(sg_offset) {
+	/* Copy back the Scatter Gather buffers back to user space */
+		u32 j;
+		// TODO 64bit fix
+		struct sg_simple_element* sg;
+		int sg_size;
+
+		// re-acquire the original message to handle correctly the sg copy operation
+		memset(&msg, 0, MAX_MESSAGE_SIZE*4); 
+		// get user msg size in u32s 
+		if(get_user(size, &user_msg[0])){
+			rcode = -EFAULT; 
+			goto cleanup; 
+		}
+		size = size>>16;
+		size *= 4;
+		/* Copy in the user's I2O command */
+		if (copy_from_user (msg, user_msg, size)) {
+			rcode = -EFAULT;
+			goto cleanup;
+		}
+		sg_count = (size - sg_offset*4) / sizeof(struct sg_simple_element);
+
+		// TODO 64bit fix
+		sg 	 = (struct sg_simple_element*)(msg + sg_offset);
+		for (j = 0; j < sg_count; j++) {
+			/* Copy out the SG list to user's buffer if necessary */
+			if(! (sg[j].flag_count & 0x4000000 /*I2O_SGL_FLAGS_DIR*/)) {
+				sg_size = sg[j].flag_count & 0xffffff; 
+				// TODO 64bit fix
+				if (copy_to_user((void __user *)sg[j].addr_bus,sg_list[j], sg_size)) {
+					printk(KERN_WARNING"%s: Could not copy %p TO user %x\n",pHba->name, sg_list[j], sg[j].addr_bus);
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+		}
+	} 
+
+	/* Copy back the reply to user space */
+	if (reply_size) {
+		// we wrote our own values for context - now restore the user supplied ones
+		if(copy_from_user(reply+2, user_msg+2, sizeof(u32)*2)) {
+			printk(KERN_WARNING"%s: Could not copy message context FROM user\n",pHba->name);
+			rcode = -EFAULT;
+		}
+		if(copy_to_user(user_reply, reply, reply_size)) {
+			printk(KERN_WARNING"%s: Could not copy reply TO user\n",pHba->name);
+			rcode = -EFAULT;
+		}
+	}
+
+
+cleanup:
+	if (rcode != -ETIME && rcode != -EINTR)
+		kfree (reply);
+	while(sg_index) {
+		if(sg_list[--sg_index]) {
+			if (rcode != -ETIME && rcode != -EINTR)
+				kfree(sg_list[sg_index]);
+		}
+	}
+	return rcode;
+}
+
+
+/*
+ * This routine returns information about the system.  This does not effect
+ * any logic and if the info is wrong - it doesn't matter.
+ */
+
+/* Get all the info we can not get from kernel services */
+static int adpt_system_info(void __user *buffer)
+{
+	sysInfo_S si;
+
+	memset(&si, 0, sizeof(si));
+
+	si.osType = OS_LINUX;
+	si.osMajorVersion = (u8) (LINUX_VERSION_CODE >> 16);
+	si.osMinorVersion = (u8) (LINUX_VERSION_CODE >> 8 & 0x0ff);
+	si.osRevision =     (u8) (LINUX_VERSION_CODE & 0x0ff);
+	si.busType = SI_PCI_BUS;
+	si.processorFamily = DPTI_sig.dsProcessorFamily;
+
+#if defined __i386__ 
+	adpt_i386_info(&si);
+#elif defined (__ia64__)
+	adpt_ia64_info(&si);
+#elif defined(__sparc__)
+	adpt_sparc_info(&si);
+#elif defined (__alpha__)
+	adpt_alpha_info(&si);
+#else
+	si.processorType = 0xff ;
+#endif
+	if(copy_to_user(buffer, &si, sizeof(si))){
+		printk(KERN_WARNING"dpti: Could not copy buffer TO user\n");
+		return -EFAULT;
+	}
+
+	return 0;
+}
+
+#if defined __ia64__ 
+static void adpt_ia64_info(sysInfo_S* si)
+{
+	// This is all the info we need for now
+	// We will add more info as our new
+	// managmenent utility requires it
+	si->processorType = PROC_IA64;
+}
+#endif
+
+
+#if defined __sparc__ 
+static void adpt_sparc_info(sysInfo_S* si)
+{
+	// This is all the info we need for now
+	// We will add more info as our new
+	// managmenent utility requires it
+	si->processorType = PROC_ULTRASPARC;
+}
+#endif
+
+#if defined __alpha__ 
+static void adpt_alpha_info(sysInfo_S* si)
+{
+	// This is all the info we need for now
+	// We will add more info as our new
+	// managmenent utility requires it
+	si->processorType = PROC_ALPHA;
+}
+#endif
+
+#if defined __i386__
+
+static void adpt_i386_info(sysInfo_S* si)
+{
+	// This is all the info we need for now
+	// We will add more info as our new
+	// managmenent utility requires it
+	switch (boot_cpu_data.x86) {
+	case CPU_386:
+		si->processorType = PROC_386;
+		break;
+	case CPU_486:
+		si->processorType = PROC_486;
+		break;
+	case CPU_586:
+		si->processorType = PROC_PENTIUM;
+		break;
+	default:  // Just in case 
+		si->processorType = PROC_PENTIUM;
+		break;
+	}
+}
+
+#endif
+
+
+static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd,
+	      ulong arg)
+{
+	int minor;
+	int error = 0;
+	adpt_hba* pHba;
+	ulong flags = 0;
+	void __user *argp = (void __user *)arg;
+
+	minor = iminor(inode);
+	if (minor >= DPTI_MAX_HBA){
+		return -ENXIO;
+	}
+	down(&adpt_configuration_lock);
+	for (pHba = hba_chain; pHba; pHba = pHba->next) {
+		if (pHba->unit == minor) {
+			break;	/* found adapter */
+		}
+	}
+	up(&adpt_configuration_lock);
+	if(pHba == NULL){
+		return -ENXIO;
+	}
+
+	while((volatile u32) pHba->state & DPTI_STATE_RESET ) {
+		set_task_state(current,TASK_UNINTERRUPTIBLE);
+		schedule_timeout(2);
+
+	}
+
+	switch (cmd) {
+	// TODO: handle 3 cases
+	case DPT_SIGNATURE:
+		if (copy_to_user(argp, &DPTI_sig, sizeof(DPTI_sig))) {
+			return -EFAULT;
+		}
+		break;
+	case I2OUSRCMD:
+		return adpt_i2o_passthru(pHba, argp);
+
+	case DPT_CTRLINFO:{
+		drvrHBAinfo_S HbaInfo;
+
+#define FLG_OSD_PCI_VALID 0x0001
+#define FLG_OSD_DMA	  0x0002
+#define FLG_OSD_I2O	  0x0004
+		memset(&HbaInfo, 0, sizeof(HbaInfo));
+		HbaInfo.drvrHBAnum = pHba->unit;
+		HbaInfo.baseAddr = (ulong) pHba->base_addr_phys;
+		HbaInfo.blinkState = adpt_read_blink_led(pHba);
+		HbaInfo.pciBusNum =  pHba->pDev->bus->number;
+		HbaInfo.pciDeviceNum=PCI_SLOT(pHba->pDev->devfn); 
+		HbaInfo.Interrupt = pHba->pDev->irq; 
+		HbaInfo.hbaFlags = FLG_OSD_PCI_VALID | FLG_OSD_DMA | FLG_OSD_I2O;
+		if(copy_to_user(argp, &HbaInfo, sizeof(HbaInfo))){
+			printk(KERN_WARNING"%s: Could not copy HbaInfo TO user\n",pHba->name);
+			return -EFAULT;
+		}
+		break;
+		}
+	case DPT_SYSINFO:
+		return adpt_system_info(argp);
+	case DPT_BLINKLED:{
+		u32 value;
+		value = (u32)adpt_read_blink_led(pHba);
+		if (copy_to_user(argp, &value, sizeof(value))) {
+			return -EFAULT;
+		}
+		break;
+		}
+	case I2ORESETCMD:
+		if(pHba->host)
+			spin_lock_irqsave(pHba->host->host_lock, flags);
+		adpt_hba_reset(pHba);
+		if(pHba->host)
+			spin_unlock_irqrestore(pHba->host->host_lock, flags);
+		break;
+	case I2ORESCANCMD:
+		adpt_rescan(pHba);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return error;
+}
+
+
+static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct scsi_cmnd* cmd;
+	adpt_hba* pHba = dev_id;
+	u32 m;
+	ulong reply;
+	u32 status=0;
+	u32 context;
+	ulong flags = 0;
+	int handled = 0;
+
+	if (pHba == NULL){
+		printk(KERN_WARNING"adpt_isr: NULL dev_id\n");
+		return IRQ_NONE;
+	}
+	if(pHba->host)
+		spin_lock_irqsave(pHba->host->host_lock, flags);
+
+	while( readl(pHba->irq_mask) & I2O_INTERRUPT_PENDING_B) {
+		m = readl(pHba->reply_port);
+		if(m == EMPTY_QUEUE){
+			// Try twice then give up
+			rmb();
+			m = readl(pHba->reply_port);
+			if(m == EMPTY_QUEUE){ 
+				// This really should not happen
+				printk(KERN_ERR"dpti: Could not get reply frame\n");
+				goto out;
+			}
+		}
+		reply = (ulong)bus_to_virt(m);
+
+		if (readl(reply) & MSG_FAIL) {
+			u32 old_m = readl(reply+28); 
+			ulong msg;
+			u32 old_context;
+			PDEBUG("%s: Failed message\n",pHba->name);
+			if(old_m >= 0x100000){
+				printk(KERN_ERR"%s: Bad preserved MFA (%x)- dropping frame\n",pHba->name,old_m);
+				writel(m,pHba->reply_port);
+				continue;
+			}
+			// Transaction context is 0 in failed reply frame
+			msg = (ulong)(pHba->msg_addr_virt + old_m);
+			old_context = readl(msg+12);
+			writel(old_context, reply+12);
+			adpt_send_nop(pHba, old_m);
+		} 
+		context = readl(reply+8);
+		if(context & 0x40000000){ // IOCTL
+			ulong p = (ulong)(readl(reply+12));
+			if( p != 0) {
+				memcpy((void*)p, (void*)reply, REPLY_FRAME_SIZE * 4);
+			}
+			// All IOCTLs will also be post wait
+		}
+		if(context & 0x80000000){ // Post wait message
+			status = readl(reply+16);
+			if(status  >> 24){
+				status &=  0xffff; /* Get detail status */
+			} else {
+				status = I2O_POST_WAIT_OK;
+			}
+			if(!(context & 0x40000000)) {
+				cmd = (struct scsi_cmnd*) readl(reply+12); 
+				if(cmd != NULL) {
+					printk(KERN_WARNING"%s: Apparent SCSI cmd in Post Wait Context - cmd=%p context=%x\n", pHba->name, cmd, context);
+				}
+			}
+			adpt_i2o_post_wait_complete(context, status);
+		} else { // SCSI message
+			cmd = (struct scsi_cmnd*) readl(reply+12); 
+			if(cmd != NULL){
+				if(cmd->serial_number != 0) { // If not timedout
+					adpt_i2o_to_scsi(reply, cmd);
+				}
+			}
+		}
+		writel(m, pHba->reply_port);
+		wmb();
+		rmb();
+	}
+	handled = 1;
+out:	if(pHba->host)
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
+	return IRQ_RETVAL(handled);
+}
+
+static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* d)
+{
+	int i;
+	u32 msg[MAX_MESSAGE_SIZE];
+	u32* mptr;
+	u32 *lenptr;
+	int direction;
+	int scsidir;
+	u32 len;
+	u32 reqlen;
+	s32 rcode;
+
+	memset(msg, 0 , sizeof(msg));
+	len = cmd->request_bufflen;
+	direction = 0x00000000;	
+	
+	scsidir = 0x00000000;			// DATA NO XFER
+	if(len) {
+		/*
+		 * Set SCBFlags to indicate if data is being transferred
+		 * in or out, or no data transfer
+		 * Note:  Do not have to verify index is less than 0 since
+		 * cmd->cmnd[0] is an unsigned char
+		 */
+		switch(cmd->sc_data_direction){
+		case DMA_FROM_DEVICE:
+			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+			break;
+		case DMA_TO_DEVICE:
+			direction=0x04000000;	// SGL OUT
+			scsidir  =0x80000000;	// DATA OUT (iop-->dev)
+			break;
+		case DMA_NONE:
+			break;
+		case DMA_BIDIRECTIONAL:
+			scsidir  =0x40000000;	// DATA IN  (iop<--dev)
+			// Assume In - and continue;
+			break;
+		default:
+			printk(KERN_WARNING"%s: scsi opcode 0x%x not supported.\n",
+			     pHba->name, cmd->cmnd[0]);
+			cmd->result = (DID_OK <<16) | (INITIATOR_ERROR << 8);
+			cmd->scsi_done(cmd);
+			return 	0;
+		}
+	}
+	// msg[0] is set later
+	// I2O_CMD_SCSI_EXEC
+	msg[1] = ((0xff<<24)|(HOST_TID<<12)|d->tid);
+	msg[2] = 0;
+	msg[3] = (u32)cmd;	/* We want the SCSI control block back */
+	// Our cards use the transaction context as the tag for queueing
+	// Adaptec/DPT Private stuff 
+	msg[4] = I2O_CMD_SCSI_EXEC|(DPT_ORGANIZATION_ID<<16);
+	msg[5] = d->tid;
+	/* Direction, disconnect ok | sense data | simple queue , CDBLen */
+	// I2O_SCB_FLAG_ENABLE_DISCONNECT | 
+	// I2O_SCB_FLAG_SIMPLE_QUEUE_TAG | 
+	// I2O_SCB_FLAG_SENSE_DATA_IN_MESSAGE;
+	msg[6] = scsidir|0x20a00000|cmd->cmd_len;
+
+	mptr=msg+7;
+
+	// Write SCSI command into the message - always 16 byte block 
+	memset(mptr, 0,  16);
+	memcpy(mptr, cmd->cmnd, cmd->cmd_len);
+	mptr+=4;
+	lenptr=mptr++;		/* Remember me - fill in when we know */
+	reqlen = 14;		// SINGLE SGE
+	/* Now fill in the SGList and command */
+	if(cmd->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *)cmd->request_buffer;
+		int sg_count = pci_map_sg(pHba->pDev, sg, cmd->use_sg,
+				cmd->sc_data_direction);
+
+
+		len = 0;
+		for(i = 0 ; i < sg_count; i++) {
+			*mptr++ = direction|0x10000000|sg_dma_len(sg);
+			len+=sg_dma_len(sg);
+			*mptr++ = sg_dma_address(sg);
+			sg++;
+		}
+		/* Make this an end of list */
+		mptr[-2] = direction|0xD0000000|sg_dma_len(sg-1);
+		reqlen = mptr - msg;
+		*lenptr = len;
+		
+		if(cmd->underflow && len != cmd->underflow){
+			printk(KERN_WARNING"Cmd len %08X Cmd underflow %08X\n",
+				len, cmd->underflow);
+		}
+	} else {
+		*lenptr = len = cmd->request_bufflen;
+		if(len == 0) {
+			reqlen = 12;
+		} else {
+			*mptr++ = 0xD0000000|direction|cmd->request_bufflen;
+			*mptr++ = pci_map_single(pHba->pDev,
+				cmd->request_buffer,
+				cmd->request_bufflen,
+				cmd->sc_data_direction);
+		}
+	}
+	
+	/* Stick the headers on */
+	msg[0] = reqlen<<16 | ((reqlen > 12) ? SGL_OFFSET_12 : SGL_OFFSET_0);
+	
+	// Send it on it's way
+	rcode = adpt_i2o_post_this(pHba, msg, reqlen<<2);
+	if (rcode == 0) {
+		return 0;
+	}
+	return rcode;
+}
+
+
+static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht)
+{
+	struct Scsi_Host *host = NULL;
+
+	host = scsi_register(sht, sizeof(adpt_hba*));
+	if (host == NULL) {
+		printk ("%s: scsi_register returned NULL\n",pHba->name);
+		return -1;
+	}
+	host->hostdata[0] = (unsigned long)pHba;
+	pHba->host = host;
+
+	host->irq = pHba->pDev->irq;
+	/* no IO ports, so don't have to set host->io_port and 
+	 * host->n_io_port
+	 */
+	host->io_port = 0;
+	host->n_io_port = 0;
+				/* see comments in hosts.h */
+	host->max_id = 16;
+	host->max_lun = 256;
+	host->max_channel = pHba->top_scsi_channel + 1;
+	host->cmd_per_lun = 1;
+	host->unique_id = (uint) pHba;
+	host->sg_tablesize = pHba->sg_tablesize;
+	host->can_queue = pHba->post_fifo_size;
+
+	return 0;
+}
+
+
+static s32 adpt_i2o_to_scsi(ulong reply, struct scsi_cmnd* cmd)
+{
+	adpt_hba* pHba;
+	u32 hba_status;
+	u32 dev_status;
+	u32 reply_flags = readl(reply) & 0xff00; // Leave it shifted up 8 bits 
+	// I know this would look cleaner if I just read bytes
+	// but the model I have been using for all the rest of the
+	// io is in 4 byte words - so I keep that model
+	u16 detailed_status = readl(reply+16) &0xffff;
+	dev_status = (detailed_status & 0xff);
+	hba_status = detailed_status >> 8;
+
+	// calculate resid for sg 
+	cmd->resid = cmd->request_bufflen - readl(reply+5);
+
+	pHba = (adpt_hba*) cmd->device->host->hostdata[0];
+
+	cmd->sense_buffer[0] = '\0';  // initialize sense valid flag to false
+
+	if(!(reply_flags & MSG_FAIL)) {
+		switch(detailed_status & I2O_SCSI_DSC_MASK) {
+		case I2O_SCSI_DSC_SUCCESS:
+			cmd->result = (DID_OK << 16);
+			// handle underflow
+			if(readl(reply+5) < cmd->underflow ) {
+				cmd->result = (DID_ERROR <<16);
+				printk(KERN_WARNING"%s: SCSI CMD underflow\n",pHba->name);
+			}
+			break;
+		case I2O_SCSI_DSC_REQUEST_ABORTED:
+			cmd->result = (DID_ABORT << 16);
+			break;
+		case I2O_SCSI_DSC_PATH_INVALID:
+		case I2O_SCSI_DSC_DEVICE_NOT_PRESENT:
+		case I2O_SCSI_DSC_SELECTION_TIMEOUT:
+		case I2O_SCSI_DSC_COMMAND_TIMEOUT:
+		case I2O_SCSI_DSC_NO_ADAPTER:
+		case I2O_SCSI_DSC_RESOURCE_UNAVAILABLE:
+			printk(KERN_WARNING"%s: SCSI Timeout-Device (%d,%d,%d) hba status=0x%x, dev status=0x%x, cmd=0x%x\n",
+				pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, hba_status, dev_status, cmd->cmnd[0]);
+			cmd->result = (DID_TIME_OUT << 16);
+			break;
+		case I2O_SCSI_DSC_ADAPTER_BUSY:
+		case I2O_SCSI_DSC_BUS_BUSY:
+			cmd->result = (DID_BUS_BUSY << 16);
+			break;
+		case I2O_SCSI_DSC_SCSI_BUS_RESET:
+		case I2O_SCSI_DSC_BDR_MESSAGE_SENT:
+			cmd->result = (DID_RESET << 16);
+			break;
+		case I2O_SCSI_DSC_PARITY_ERROR_FAILURE:
+			printk(KERN_WARNING"%s: SCSI CMD parity error\n",pHba->name);
+			cmd->result = (DID_PARITY << 16);
+			break;
+		case I2O_SCSI_DSC_UNABLE_TO_ABORT:
+		case I2O_SCSI_DSC_COMPLETE_WITH_ERROR:
+		case I2O_SCSI_DSC_UNABLE_TO_TERMINATE:
+		case I2O_SCSI_DSC_MR_MESSAGE_RECEIVED:
+		case I2O_SCSI_DSC_AUTOSENSE_FAILED:
+		case I2O_SCSI_DSC_DATA_OVERRUN:
+		case I2O_SCSI_DSC_UNEXPECTED_BUS_FREE:
+		case I2O_SCSI_DSC_SEQUENCE_FAILURE:
+		case I2O_SCSI_DSC_REQUEST_LENGTH_ERROR:
+		case I2O_SCSI_DSC_PROVIDE_FAILURE:
+		case I2O_SCSI_DSC_REQUEST_TERMINATED:
+		case I2O_SCSI_DSC_IDE_MESSAGE_SENT:
+		case I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT:
+		case I2O_SCSI_DSC_MESSAGE_RECEIVED:
+		case I2O_SCSI_DSC_INVALID_CDB:
+		case I2O_SCSI_DSC_LUN_INVALID:
+		case I2O_SCSI_DSC_SCSI_TID_INVALID:
+		case I2O_SCSI_DSC_FUNCTION_UNAVAILABLE:
+		case I2O_SCSI_DSC_NO_NEXUS:
+		case I2O_SCSI_DSC_CDB_RECEIVED:
+		case I2O_SCSI_DSC_LUN_ALREADY_ENABLED:
+		case I2O_SCSI_DSC_QUEUE_FROZEN:
+		case I2O_SCSI_DSC_REQUEST_INVALID:
+		default:
+			printk(KERN_WARNING"%s: SCSI error %0x-Device(%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n",
+				pHba->name, detailed_status & I2O_SCSI_DSC_MASK, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun,
+			       hba_status, dev_status, cmd->cmnd[0]);
+			cmd->result = (DID_ERROR << 16);
+			break;
+		}
+
+		// copy over the request sense data if it was a check
+		// condition status
+		if(dev_status == 0x02 /*CHECK_CONDITION*/) {
+			u32 len = sizeof(cmd->sense_buffer);
+			len = (len > 40) ?  40 : len;
+			// Copy over the sense data
+			memcpy(cmd->sense_buffer, (void*)(reply+28) , len);
+			if(cmd->sense_buffer[0] == 0x70 /* class 7 */ && 
+			   cmd->sense_buffer[2] == DATA_PROTECT ){
+				/* This is to handle an array failed */
+				cmd->result = (DID_TIME_OUT << 16);
+				printk(KERN_WARNING"%s: SCSI Data Protect-Device (%d,%d,%d) hba_status=0x%x, dev_status=0x%x, cmd=0x%x\n",
+					pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun, 
+					hba_status, dev_status, cmd->cmnd[0]);
+
+			}
+		}
+	} else {
+		/* In this condtion we could not talk to the tid
+		 * the card rejected it.  We should signal a retry
+		 * for a limitted number of retries.
+		 */
+		cmd->result = (DID_TIME_OUT << 16);
+		printk(KERN_WARNING"%s: I2O MSG_FAIL - Device (%d,%d,%d) tid=%d, cmd=0x%x\n",
+			pHba->name, (u32)cmd->device->channel, (u32)cmd->device->id, (u32)cmd->device->lun,
+			((struct adpt_device*)(cmd->device->hostdata))->tid, cmd->cmnd[0]);
+	}
+
+	cmd->result |= (dev_status);
+
+	if(cmd->scsi_done != NULL){
+		cmd->scsi_done(cmd);
+	} 
+	return cmd->result;
+}
+
+
+static s32 adpt_rescan(adpt_hba* pHba)
+{
+	s32 rcode;
+	ulong flags = 0;
+
+	if(pHba->host)
+		spin_lock_irqsave(pHba->host->host_lock, flags);
+	if ((rcode=adpt_i2o_lct_get(pHba)) < 0)
+		goto out;
+	if ((rcode=adpt_i2o_reparse_lct(pHba)) < 0)
+		goto out;
+	rcode = 0;
+out:	if(pHba->host)
+		spin_unlock_irqrestore(pHba->host->host_lock, flags);
+	return rcode;
+}
+
+
+static s32 adpt_i2o_reparse_lct(adpt_hba* pHba)
+{
+	int i;
+	int max;
+	int tid;
+	struct i2o_device *d;
+	i2o_lct *lct = pHba->lct;
+	u8 bus_no = 0;
+	s16 scsi_id;
+	s16 scsi_lun;
+	u32 buf[10]; // at least 8 u32's
+	struct adpt_device* pDev = NULL;
+	struct i2o_device* pI2o_dev = NULL;
+	
+	if (lct == NULL) {
+		printk(KERN_ERR "%s: LCT is empty???\n",pHba->name);
+		return -1;
+	}
+	
+	max = lct->table_size;	
+	max -= 3;
+	max /= 9;
+
+	// Mark each drive as unscanned
+	for (d = pHba->devices; d; d = d->next) {
+		pDev =(struct adpt_device*) d->owner;
+		if(!pDev){
+			continue;
+		}
+		pDev->state |= DPTI_DEV_UNSCANNED;
+	}
+
+	printk(KERN_INFO "%s: LCT has %d entries.\n", pHba->name,max);
+	
+	for(i=0;i<max;i++) {
+		if( lct->lct_entry[i].user_tid != 0xfff){
+			continue;
+		}
+
+		if( lct->lct_entry[i].class_id == I2O_CLASS_RANDOM_BLOCK_STORAGE ||
+		    lct->lct_entry[i].class_id == I2O_CLASS_SCSI_PERIPHERAL ||
+		    lct->lct_entry[i].class_id == I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL ){
+			tid = lct->lct_entry[i].tid;
+			if(adpt_i2o_query_scalar(pHba, tid, 0x8000, -1, buf, 32)<0) {
+				printk(KERN_ERR"%s: Could not query device\n",pHba->name);
+				continue;
+			}
+			bus_no = buf[0]>>16;
+			scsi_id = buf[1];
+			scsi_lun = (buf[2]>>8 )&0xff;
+			pDev = pHba->channel[bus_no].device[scsi_id];
+			/* da lun */
+			while(pDev) {
+				if(pDev->scsi_lun == scsi_lun) {
+					break;
+				}
+				pDev = pDev->next_lun;
+			}
+			if(!pDev ) { // Something new add it
+				d = (struct i2o_device *)kmalloc(sizeof(struct i2o_device), GFP_KERNEL);
+				if(d==NULL)
+				{
+					printk(KERN_CRIT "Out of memory for I2O device data.\n");
+					return -ENOMEM;
+				}
+				
+				d->controller = (void*)pHba;
+				d->next = NULL;
+
+				memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
+
+				d->flags = 0;
+				adpt_i2o_report_hba_unit(pHba, d);
+				adpt_i2o_install_device(pHba, d);
+	
+				if(bus_no >= MAX_CHANNEL) {	// Something wrong skip it
+					printk(KERN_WARNING"%s: Channel number %d out of range \n", pHba->name, bus_no);
+					continue;
+				}
+				pDev = pHba->channel[bus_no].device[scsi_id];	
+				if( pDev == NULL){
+					pDev =  kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					if(pDev == NULL) {
+						return -ENOMEM;
+					}
+					pHba->channel[bus_no].device[scsi_id] = pDev;
+				} else {
+					while (pDev->next_lun) {
+						pDev = pDev->next_lun;
+					}
+					pDev = pDev->next_lun = kmalloc(sizeof(struct adpt_device),GFP_KERNEL);
+					if(pDev == NULL) {
+						return -ENOMEM;
+					}
+				}
+				memset(pDev,0,sizeof(struct adpt_device));
+				pDev->tid = d->lct_data.tid;
+				pDev->scsi_channel = bus_no;
+				pDev->scsi_id = scsi_id;
+				pDev->scsi_lun = scsi_lun;
+				pDev->pI2o_dev = d;
+				d->owner = pDev;
+				pDev->type = (buf[0])&0xff;
+				pDev->flags = (buf[0]>>8)&0xff;
+				// Too late, SCSI system has made up it's mind, but what the hey ...
+				if(scsi_id > pHba->top_scsi_id){
+					pHba->top_scsi_id = scsi_id;
+				}
+				if(scsi_lun > pHba->top_scsi_lun){
+					pHba->top_scsi_lun = scsi_lun;
+				}
+				continue;
+			} // end of new i2o device
+
+			// We found an old device - check it
+			while(pDev) {
+				if(pDev->scsi_lun == scsi_lun) {
+					if(!scsi_device_online(pDev->pScsi_dev)) {
+						printk(KERN_WARNING"%s: Setting device (%d,%d,%d) back online\n",
+								pHba->name,bus_no,scsi_id,scsi_lun);
+						if (pDev->pScsi_dev) {
+							scsi_device_set_state(pDev->pScsi_dev, SDEV_RUNNING);
+						}
+					}
+					d = pDev->pI2o_dev;
+					if(d->lct_data.tid != tid) { // something changed
+						pDev->tid = tid;
+						memcpy(&d->lct_data, &lct->lct_entry[i], sizeof(i2o_lct_entry));
+						if (pDev->pScsi_dev) {
+							pDev->pScsi_dev->changed = TRUE;
+							pDev->pScsi_dev->removable = TRUE;
+						}
+					}
+					// Found it - mark it scanned
+					pDev->state = DPTI_DEV_ONLINE;
+					break;
+				}
+				pDev = pDev->next_lun;
+			}
+		}
+	}
+	for (pI2o_dev = pHba->devices; pI2o_dev; pI2o_dev = pI2o_dev->next) {
+		pDev =(struct adpt_device*) pI2o_dev->owner;
+		if(!pDev){
+			continue;
+		}
+		// Drive offline drives that previously existed but could not be found
+		// in the LCT table
+		if (pDev->state & DPTI_DEV_UNSCANNED){
+			pDev->state = DPTI_DEV_OFFLINE;
+			printk(KERN_WARNING"%s: Device (%d,%d,%d) offline\n",pHba->name,pDev->scsi_channel,pDev->scsi_id,pDev->scsi_lun);
+			if (pDev->pScsi_dev) {
+				scsi_device_set_state(pDev->pScsi_dev, SDEV_OFFLINE);
+			}
+		}
+	}
+	return 0;
+}
+
+static void adpt_fail_posted_scbs(adpt_hba* pHba)
+{
+	struct scsi_cmnd* 	cmd = NULL;
+	struct scsi_device* 	d = NULL;
+
+	shost_for_each_device(d, pHba->host) {
+		unsigned long flags;
+		spin_lock_irqsave(&d->list_lock, flags);
+		list_for_each_entry(cmd, &d->cmd_list, list) {
+			if(cmd->serial_number == 0){
+				continue;
+			}
+			cmd->result = (DID_OK << 16) | (QUEUE_FULL <<1);
+			cmd->scsi_done(cmd);
+		}
+		spin_unlock_irqrestore(&d->list_lock, flags);
+	}
+}
+
+
+/*============================================================================
+ *  Routines from i2o subsystem
+ *============================================================================
+ */
+
+
+
+/*
+ *	Bring an I2O controller into HOLD state. See the spec.
+ */
+static int adpt_i2o_activate_hba(adpt_hba* pHba)
+{
+	int rcode;
+
+	if(pHba->initialized ) {
+		if (adpt_i2o_status_get(pHba) < 0) {
+			if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
+				printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
+				return rcode;
+			}
+			if (adpt_i2o_status_get(pHba) < 0) {
+				printk(KERN_INFO "HBA not responding.\n");
+				return -1;
+			}
+		}
+
+		if(pHba->status_block->iop_state == ADAPTER_STATE_FAULTED) {
+			printk(KERN_CRIT "%s: hardware fault\n", pHba->name);
+			return -1;
+		}
+
+		if (pHba->status_block->iop_state == ADAPTER_STATE_READY ||
+		    pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL ||
+		    pHba->status_block->iop_state == ADAPTER_STATE_HOLD ||
+		    pHba->status_block->iop_state == ADAPTER_STATE_FAILED) {
+			adpt_i2o_reset_hba(pHba);			
+			if (adpt_i2o_status_get(pHba) < 0 || pHba->status_block->iop_state != ADAPTER_STATE_RESET) {
+				printk(KERN_ERR "%s: Failed to initialize.\n", pHba->name);
+				return -1;
+			}
+		}
+	} else {
+		if((rcode = adpt_i2o_reset_hba(pHba)) != 0){
+			printk(KERN_WARNING"%s: Could NOT reset.\n", pHba->name);
+			return rcode;
+		}
+
+	}
+
+	if (adpt_i2o_init_outbound_q(pHba) < 0) {
+		return -1;
+	}
+
+	/* In HOLD state */
+	
+	if (adpt_i2o_hrt_get(pHba) < 0) {
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ *	Bring a controller online into OPERATIONAL state. 
+ */
+ 
+static int adpt_i2o_online_hba(adpt_hba* pHba)
+{
+	if (adpt_i2o_systab_send(pHba) < 0) {
+		adpt_i2o_delete_hba(pHba);
+		return -1;
+	}
+	/* In READY state */
+
+	if (adpt_i2o_enable_hba(pHba) < 0) {
+		adpt_i2o_delete_hba(pHba);
+		return -1;
+	}
+
+	/* In OPERATIONAL state  */
+	return 0;
+}
+
+static s32 adpt_send_nop(adpt_hba*pHba,u32 m)
+{
+	u32 __iomem *msg;
+	ulong timeout = jiffies + 5*HZ;
+
+	while(m == EMPTY_QUEUE){
+		rmb();
+		m = readl(pHba->post_port);
+		if(m != EMPTY_QUEUE){
+			break;
+		}
+		if(time_after(jiffies,timeout)){
+			printk(KERN_ERR "%s: Timeout waiting for message frame!\n",pHba->name);
+			return 2;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+	msg = (u32 __iomem *)(pHba->msg_addr_virt + m);
+	writel( THREE_WORD_MSG_SIZE | SGL_OFFSET_0,&msg[0]);
+	writel( I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | 0,&msg[1]);
+	writel( 0,&msg[2]);
+	wmb();
+
+	writel(m, pHba->post_port);
+	wmb();
+	return 0;
+}
+
+static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba)
+{
+	u8 *status;
+	u32 __iomem *msg = NULL;
+	int i;
+	ulong timeout = jiffies + TMOUT_INITOUTBOUND*HZ;
+	u32* ptr;
+	u32 outbound_frame;  // This had to be a 32 bit address
+	u32 m;
+
+	do {
+		rmb();
+		m = readl(pHba->post_port);
+		if (m != EMPTY_QUEUE) {
+			break;
+		}
+
+		if(time_after(jiffies,timeout)){
+			printk(KERN_WARNING"%s: Timeout waiting for message frame\n",pHba->name);
+			return -ETIMEDOUT;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while(m == EMPTY_QUEUE);
+
+	msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
+
+	status = kmalloc(4,GFP_KERNEL|ADDR32);
+	if (status==NULL) {
+		adpt_send_nop(pHba, m);
+		printk(KERN_WARNING"%s: IOP reset failed - no free memory.\n",
+			pHba->name);
+		return -ENOMEM;
+	}
+	memset(status, 0, 4);
+
+	writel(EIGHT_WORD_MSG_SIZE| SGL_OFFSET_6, &msg[0]);
+	writel(I2O_CMD_OUTBOUND_INIT<<24 | HOST_TID<<12 | ADAPTER_TID, &msg[1]);
+	writel(0, &msg[2]);
+	writel(0x0106, &msg[3]);	/* Transaction context */
+	writel(4096, &msg[4]);		/* Host page frame size */
+	writel((REPLY_FRAME_SIZE)<<16|0x80, &msg[5]);	/* Outbound msg frame size and Initcode */
+	writel(0xD0000004, &msg[6]);		/* Simple SG LE, EOB */
+	writel(virt_to_bus(status), &msg[7]);
+
+	writel(m, pHba->post_port);
+	wmb();
+
+	// Wait for the reply status to come back
+	do {
+		if (*status) {
+			if (*status != 0x01 /*I2O_EXEC_OUTBOUND_INIT_IN_PROGRESS*/) {
+				break;
+			}
+		}
+		rmb();
+		if(time_after(jiffies,timeout)){
+			printk(KERN_WARNING"%s: Timeout Initializing\n",pHba->name);
+			return -ETIMEDOUT;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while (1);
+
+	// If the command was successful, fill the fifo with our reply
+	// message packets
+	if(*status != 0x04 /*I2O_EXEC_OUTBOUND_INIT_COMPLETE*/) {
+		kfree((void*)status);
+		return -2;
+	}
+	kfree((void*)status);
+
+	if(pHba->reply_pool != NULL){
+		kfree(pHba->reply_pool);
+	}
+
+	pHba->reply_pool = (u32*)kmalloc(pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4, GFP_KERNEL|ADDR32);
+	if(!pHba->reply_pool){
+		printk(KERN_ERR"%s: Could not allocate reply pool\n",pHba->name);
+		return -1;
+	}
+	memset(pHba->reply_pool, 0 , pHba->reply_fifo_size * REPLY_FRAME_SIZE * 4);
+
+	ptr = pHba->reply_pool;
+	for(i = 0; i < pHba->reply_fifo_size; i++) {
+		outbound_frame = (u32)virt_to_bus(ptr);
+		writel(outbound_frame, pHba->reply_port);
+		wmb();
+		ptr +=  REPLY_FRAME_SIZE;
+	}
+	adpt_i2o_status_get(pHba);
+	return 0;
+}
+
+
+/*
+ * I2O System Table.  Contains information about
+ * all the IOPs in the system.  Used to inform IOPs
+ * about each other's existence.
+ *
+ * sys_tbl_ver is the CurrentChangeIndicator that is
+ * used by IOPs to track changes.
+ */
+
+
+
+static s32 adpt_i2o_status_get(adpt_hba* pHba)
+{
+	ulong timeout;
+	u32 m;
+	u32 __iomem *msg;
+	u8 *status_block=NULL;
+	ulong status_block_bus;
+
+	if(pHba->status_block == NULL) {
+		pHba->status_block = (i2o_status_block*)
+			kmalloc(sizeof(i2o_status_block),GFP_KERNEL|ADDR32);
+		if(pHba->status_block == NULL) {
+			printk(KERN_ERR
+			"dpti%d: Get Status Block failed; Out of memory. \n", 
+			pHba->unit);
+			return -ENOMEM;
+		}
+	}
+	memset(pHba->status_block, 0, sizeof(i2o_status_block));
+	status_block = (u8*)(pHba->status_block);
+	status_block_bus = virt_to_bus(pHba->status_block);
+	timeout = jiffies+TMOUT_GETSTATUS*HZ;
+	do {
+		rmb();
+		m = readl(pHba->post_port);
+		if (m != EMPTY_QUEUE) {
+			break;
+		}
+		if(time_after(jiffies,timeout)){
+			printk(KERN_ERR "%s: Timeout waiting for message !\n",
+					pHba->name);
+			return -ETIMEDOUT;
+		}
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	} while(m==EMPTY_QUEUE);
+
+	
+	msg=(u32 __iomem *)(pHba->msg_addr_virt+m);
+
+	writel(NINE_WORD_MSG_SIZE|SGL_OFFSET_0, &msg[0]);
+	writel(I2O_CMD_STATUS_GET<<24|HOST_TID<<12|ADAPTER_TID, &msg[1]);
+	writel(1, &msg[2]);
+	writel(0, &msg[3]);
+	writel(0, &msg[4]);
+	writel(0, &msg[5]);
+	writel(((u32)status_block_bus)&0xffffffff, &msg[6]);
+	writel(0, &msg[7]);
+	writel(sizeof(i2o_status_block), &msg[8]); // 88 bytes
+
+	//post message
+	writel(m, pHba->post_port);
+	wmb();
+
+	while(status_block[87]!=0xff){
+		if(time_after(jiffies,timeout)){
+			printk(KERN_ERR"dpti%d: Get status timeout.\n",
+				pHba->unit);
+			return -ETIMEDOUT;
+		}
+		rmb();
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+	}
+
+	// Set up our number of outbound and inbound messages
+	pHba->post_fifo_size = pHba->status_block->max_inbound_frames;
+	if (pHba->post_fifo_size > MAX_TO_IOP_MESSAGES) {
+		pHba->post_fifo_size = MAX_TO_IOP_MESSAGES;
+	}
+
+	pHba->reply_fifo_size = pHba->status_block->max_outbound_frames;
+	if (pHba->reply_fifo_size > MAX_FROM_IOP_MESSAGES) {
+		pHba->reply_fifo_size = MAX_FROM_IOP_MESSAGES;
+	}
+
+	// Calculate the Scatter Gather list size
+	pHba->sg_tablesize = (pHba->status_block->inbound_frame_size * 4 -40)/ sizeof(struct sg_simple_element);
+	if (pHba->sg_tablesize > SG_LIST_ELEMENTS) {
+		pHba->sg_tablesize = SG_LIST_ELEMENTS;
+	}
+
+
+#ifdef DEBUG
+	printk("dpti%d: State = ",pHba->unit);
+	switch(pHba->status_block->iop_state) {
+		case 0x01:
+			printk("INIT\n");
+			break;
+		case 0x02:
+			printk("RESET\n");
+			break;
+		case 0x04:
+			printk("HOLD\n");
+			break;
+		case 0x05:
+			printk("READY\n");
+			break;
+		case 0x08:
+			printk("OPERATIONAL\n");
+			break;
+		case 0x10:
+			printk("FAILED\n");
+			break;
+		case 0x11:
+			printk("FAULTED\n");
+			break;
+		default:
+			printk("%x (unknown!!)\n",pHba->status_block->iop_state);
+	}
+#endif
+	return 0;
+}
+
+/*
+ * Get the IOP's Logical Configuration Table
+ */
+static int adpt_i2o_lct_get(adpt_hba* pHba)
+{
+	u32 msg[8];
+	int ret;
+	u32 buf[16];
+
+	if ((pHba->lct_size == 0) || (pHba->lct == NULL)){
+		pHba->lct_size = pHba->status_block->expected_lct_size;
+	}
+	do {
+		if (pHba->lct == NULL) {
+			pHba->lct = kmalloc(pHba->lct_size, GFP_KERNEL|ADDR32);
+			if(pHba->lct == NULL) {
+				printk(KERN_CRIT "%s: Lct Get failed. Out of memory.\n",
+					pHba->name);
+				return -ENOMEM;
+			}
+		}
+		memset(pHba->lct, 0, pHba->lct_size);
+
+		msg[0] = EIGHT_WORD_MSG_SIZE|SGL_OFFSET_6;
+		msg[1] = I2O_CMD_LCT_NOTIFY<<24 | HOST_TID<<12 | ADAPTER_TID;
+		msg[2] = 0;
+		msg[3] = 0;
+		msg[4] = 0xFFFFFFFF;	/* All devices */
+		msg[5] = 0x00000000;	/* Report now */
+		msg[6] = 0xD0000000|pHba->lct_size;
+		msg[7] = virt_to_bus(pHba->lct);
+
+		if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 360))) {
+			printk(KERN_ERR "%s: LCT Get failed (status=%#10x.\n", 
+				pHba->name, ret);	
+			printk(KERN_ERR"Adaptec: Error Reading Hardware.\n");
+			return ret;
+		}
+
+		if ((pHba->lct->table_size << 2) > pHba->lct_size) {
+			pHba->lct_size = pHba->lct->table_size << 2;
+			kfree(pHba->lct);
+			pHba->lct = NULL;
+		}
+	} while (pHba->lct == NULL);
+
+	PDEBUG("%s: Hardware resource table read.\n", pHba->name);
+
+
+	// I2O_DPT_EXEC_IOP_BUFFERS_GROUP_NO;
+	if(adpt_i2o_query_scalar(pHba, 0 , 0x8000, -1, buf, sizeof(buf))>=0) {
+		pHba->FwDebugBufferSize = buf[1];
+		pHba->FwDebugBuffer_P    = pHba->base_addr_virt + buf[0];
+		pHba->FwDebugFlags_P     = pHba->FwDebugBuffer_P + FW_DEBUG_FLAGS_OFFSET;
+		pHba->FwDebugBLEDvalue_P = pHba->FwDebugBuffer_P + FW_DEBUG_BLED_OFFSET;
+		pHba->FwDebugBLEDflag_P  = pHba->FwDebugBLEDvalue_P + 1;
+		pHba->FwDebugStrLength_P = pHba->FwDebugBuffer_P + FW_DEBUG_STR_LENGTH_OFFSET;
+		pHba->FwDebugBuffer_P += buf[2]; 
+		pHba->FwDebugFlags = 0;
+	}
+
+	return 0;
+}
+
+static int adpt_i2o_build_sys_table(void)
+{
+	adpt_hba* pHba = NULL;
+	int count = 0;
+
+	sys_tbl_len = sizeof(struct i2o_sys_tbl) +	// Header + IOPs
+				(hba_count) * sizeof(struct i2o_sys_tbl_entry);
+
+	if(sys_tbl)
+		kfree(sys_tbl);
+
+	sys_tbl = kmalloc(sys_tbl_len, GFP_KERNEL|ADDR32);
+	if(!sys_tbl) {
+		printk(KERN_WARNING "SysTab Set failed. Out of memory.\n");	
+		return -ENOMEM;
+	}
+	memset(sys_tbl, 0, sys_tbl_len);
+
+	sys_tbl->num_entries = hba_count;
+	sys_tbl->version = I2OVERSION;
+	sys_tbl->change_ind = sys_tbl_ind++;
+
+	for(pHba = hba_chain; pHba; pHba = pHba->next) {
+		// Get updated Status Block so we have the latest information
+		if (adpt_i2o_status_get(pHba)) {
+			sys_tbl->num_entries--;
+			continue; // try next one	
+		}
+
+		sys_tbl->iops[count].org_id = pHba->status_block->org_id;
+		sys_tbl->iops[count].iop_id = pHba->unit + 2;
+		sys_tbl->iops[count].seg_num = 0;
+		sys_tbl->iops[count].i2o_version = pHba->status_block->i2o_version;
+		sys_tbl->iops[count].iop_state = pHba->status_block->iop_state;
+		sys_tbl->iops[count].msg_type = pHba->status_block->msg_type;
+		sys_tbl->iops[count].frame_size = pHba->status_block->inbound_frame_size;
+		sys_tbl->iops[count].last_changed = sys_tbl_ind - 1; // ??
+		sys_tbl->iops[count].iop_capabilities = pHba->status_block->iop_capabilities;
+		sys_tbl->iops[count].inbound_low = (u32)virt_to_bus((void*)pHba->post_port);
+		sys_tbl->iops[count].inbound_high = (u32)((u64)virt_to_bus((void*)pHba->post_port)>>32);
+
+		count++;
+	}
+
+#ifdef DEBUG
+{
+	u32 *table = (u32*)sys_tbl;
+	printk(KERN_DEBUG"sys_tbl_len=%d in 32bit words\n",(sys_tbl_len >>2));
+	for(count = 0; count < (sys_tbl_len >>2); count++) {
+		printk(KERN_INFO "sys_tbl[%d] = %0#10x\n", 
+			count, table[count]);
+	}
+}
+#endif
+
+	return 0;
+}
+
+
+/*
+ *	 Dump the information block associated with a given unit (TID)
+ */
+ 
+static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d)
+{
+	char buf[64];
+	int unit = d->lct_data.tid;
+
+	printk(KERN_INFO "TID %3.3d ", unit);
+
+	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 3, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk(" Vendor: %-12.12s", buf);
+	}
+	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 4, buf, 16)>=0)
+	{
+		buf[16]=0;
+		printk(" Device: %-12.12s", buf);
+	}
+	if(adpt_i2o_query_scalar(pHba, unit, 0xF100, 6, buf, 8)>=0)
+	{
+		buf[8]=0;
+		printk(" Rev: %-12.12s\n", buf);
+	}
+#ifdef DEBUG
+	 printk(KERN_INFO "\tClass: %.21s\n", adpt_i2o_get_class_name(d->lct_data.class_id));
+	 printk(KERN_INFO "\tSubclass: 0x%04X\n", d->lct_data.sub_class);
+	 printk(KERN_INFO "\tFlags: ");
+
+	 if(d->lct_data.device_flags&(1<<0))
+		  printk("C");	     // ConfigDialog requested
+	 if(d->lct_data.device_flags&(1<<1))
+		  printk("U");	     // Multi-user capable
+	 if(!(d->lct_data.device_flags&(1<<4)))
+		  printk("P");	     // Peer service enabled!
+	 if(!(d->lct_data.device_flags&(1<<5)))
+		  printk("M");	     // Mgmt service enabled!
+	 printk("\n");
+#endif
+}
+
+#ifdef DEBUG
+/*
+ *	Do i2o class name lookup
+ */
+static const char *adpt_i2o_get_class_name(int class)
+{
+	int idx = 16;
+	static char *i2o_class_name[] = {
+		"Executive",
+		"Device Driver Module",
+		"Block Device",
+		"Tape Device",
+		"LAN Interface",
+		"WAN Interface",
+		"Fibre Channel Port",
+		"Fibre Channel Device",
+		"SCSI Device",
+		"ATE Port",
+		"ATE Device",
+		"Floppy Controller",
+		"Floppy Device",
+		"Secondary Bus Port",
+		"Peer Transport Agent",
+		"Peer Transport",
+		"Unknown"
+	};
+	
+	switch(class&0xFFF) {
+	case I2O_CLASS_EXECUTIVE:
+		idx = 0; break;
+	case I2O_CLASS_DDM:
+		idx = 1; break;
+	case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+		idx = 2; break;
+	case I2O_CLASS_SEQUENTIAL_STORAGE:
+		idx = 3; break;
+	case I2O_CLASS_LAN:
+		idx = 4; break;
+	case I2O_CLASS_WAN:
+		idx = 5; break;
+	case I2O_CLASS_FIBRE_CHANNEL_PORT:
+		idx = 6; break;
+	case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
+		idx = 7; break;
+	case I2O_CLASS_SCSI_PERIPHERAL:
+		idx = 8; break;
+	case I2O_CLASS_ATE_PORT:
+		idx = 9; break;
+	case I2O_CLASS_ATE_PERIPHERAL:
+		idx = 10; break;
+	case I2O_CLASS_FLOPPY_CONTROLLER:
+		idx = 11; break;
+	case I2O_CLASS_FLOPPY_DEVICE:
+		idx = 12; break;
+	case I2O_CLASS_BUS_ADAPTER_PORT:
+		idx = 13; break;
+	case I2O_CLASS_PEER_TRANSPORT_AGENT:
+		idx = 14; break;
+	case I2O_CLASS_PEER_TRANSPORT:
+		idx = 15; break;
+	}
+	return i2o_class_name[idx];
+}
+#endif
+
+
+static s32 adpt_i2o_hrt_get(adpt_hba* pHba)
+{
+	u32 msg[6];
+	int ret, size = sizeof(i2o_hrt);
+
+	do {
+		if (pHba->hrt == NULL) {
+			pHba->hrt=kmalloc(size, GFP_KERNEL|ADDR32);
+			if (pHba->hrt == NULL) {
+				printk(KERN_CRIT "%s: Hrt Get failed; Out of memory.\n", pHba->name);
+				return -ENOMEM;
+			}
+		}
+
+		msg[0]= SIX_WORD_MSG_SIZE| SGL_OFFSET_4;
+		msg[1]= I2O_CMD_HRT_GET<<24 | HOST_TID<<12 | ADAPTER_TID;
+		msg[2]= 0;
+		msg[3]= 0;
+		msg[4]= (0xD0000000 | size);    /* Simple transaction */
+		msg[5]= virt_to_bus(pHba->hrt);   /* Dump it here */
+
+		if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg),20))) {
+			printk(KERN_ERR "%s: Unable to get HRT (status=%#10x)\n", pHba->name, ret);
+			return ret;
+		}
+
+		if (pHba->hrt->num_entries * pHba->hrt->entry_len << 2 > size) {
+			size = pHba->hrt->num_entries * pHba->hrt->entry_len << 2;
+			kfree(pHba->hrt);
+			pHba->hrt = NULL;
+		}
+	} while(pHba->hrt == NULL);
+	return 0;
+}                                                                                                                                       
+
+/*
+ *	 Query one scalar group value or a whole scalar group.
+ */		    	
+static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, 
+			int group, int field, void *buf, int buflen)
+{
+	u16 opblk[] = { 1, 0, I2O_PARAMS_FIELD_GET, group, 1, field };
+	u8 *resblk;
+
+	int size;
+
+	/* 8 bytes for header */
+	resblk = kmalloc(sizeof(u8) * (8+buflen), GFP_KERNEL|ADDR32);
+	if (resblk == NULL) {
+		printk(KERN_CRIT "%s: query scalar failed; Out of memory.\n", pHba->name);
+		return -ENOMEM;
+	}
+
+	if (field == -1)  		/* whole group */
+			opblk[4] = -1;
+
+	size = adpt_i2o_issue_params(I2O_CMD_UTIL_PARAMS_GET, pHba, tid, 
+		opblk, sizeof(opblk), resblk, sizeof(u8)*(8+buflen));
+	if (size == -ETIME) {
+		printk(KERN_WARNING "%s: issue params failed; Timed out.\n", pHba->name);
+		return -ETIME;
+	} else if (size == -EINTR) {
+		printk(KERN_WARNING "%s: issue params failed; Interrupted.\n", pHba->name);
+		return -EINTR;
+	}
+			
+	memcpy(buf, resblk+8, buflen);  /* cut off header */
+
+	kfree(resblk);
+	if (size < 0)
+		return size;	
+
+	return buflen;
+}
+
+
+/*	Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ *	This function can be used for all UtilParamsGet/Set operations.
+ *	The OperationBlock is given in opblk-buffer, 
+ *	and results are returned in resblk-buffer.
+ *	Note that the minimum sized resblk is 8 bytes and contains
+ *	ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, 
+		  void *opblk, int oplen, void *resblk, int reslen)
+{
+	u32 msg[9]; 
+	u32 *res = (u32 *)resblk;
+	int wait_status;
+
+	msg[0] = NINE_WORD_MSG_SIZE | SGL_OFFSET_5;
+	msg[1] = cmd << 24 | HOST_TID << 12 | tid; 
+	msg[2] = 0;
+	msg[3] = 0;
+	msg[4] = 0;
+	msg[5] = 0x54000000 | oplen;	/* OperationBlock */
+	msg[6] = virt_to_bus(opblk);
+	msg[7] = 0xD0000000 | reslen;	/* ResultBlock */
+	msg[8] = virt_to_bus(resblk);
+
+	if ((wait_status = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 20))) {
+		printk("adpt_i2o_issue_params: post_wait failed (%p)\n", resblk);
+   		return wait_status; 	/* -DetailedStatus */
+	}
+
+	if (res[1]&0x00FF0000) { 	/* BlockStatus != SUCCESS */
+		printk(KERN_WARNING "%s: %s - Error:\n  ErrorInfoSize = 0x%02x, "
+			"BlockStatus = 0x%02x, BlockSize = 0x%04x\n",
+			pHba->name,
+			(cmd == I2O_CMD_UTIL_PARAMS_SET) ? "PARAMS_SET"
+							 : "PARAMS_GET",   
+			res[1]>>24, (res[1]>>16)&0xFF, res[1]&0xFFFF);
+		return -((res[1] >> 16) & 0xFF); /* -BlockStatus */
+	}
+
+	 return 4 + ((res[1] & 0x0000FFFF) << 2); /* bytes used in resblk */ 
+}
+
+
+static s32 adpt_i2o_quiesce_hba(adpt_hba* pHba)
+{
+	u32 msg[4];
+	int ret;
+
+	adpt_i2o_status_get(pHba);
+
+	/* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+
+	if((pHba->status_block->iop_state != ADAPTER_STATE_READY) &&
+   	   (pHba->status_block->iop_state != ADAPTER_STATE_OPERATIONAL)){
+		return 0;
+	}
+
+	msg[0] = FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1] = I2O_CMD_SYS_QUIESCE<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2] = 0;
+	msg[3] = 0;
+
+	if((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) {
+		printk(KERN_INFO"dpti%d: Unable to quiesce (status=%#x).\n",
+				pHba->unit, -ret);
+	} else {
+		printk(KERN_INFO"dpti%d: Quiesced.\n",pHba->unit);
+	}
+
+	adpt_i2o_status_get(pHba);
+	return ret;
+}
+
+
+/* 
+ * Enable IOP. Allows the IOP to resume external operations.
+ */
+static int adpt_i2o_enable_hba(adpt_hba* pHba)
+{
+	u32 msg[4];
+	int ret;
+	
+	adpt_i2o_status_get(pHba);
+	if(!pHba->status_block){
+		return -ENOMEM;
+	}
+	/* Enable only allowed on READY state */
+	if(pHba->status_block->iop_state == ADAPTER_STATE_OPERATIONAL)
+		return 0;
+
+	if(pHba->status_block->iop_state != ADAPTER_STATE_READY)
+		return -EINVAL;
+
+	msg[0]=FOUR_WORD_MSG_SIZE|SGL_OFFSET_0;
+	msg[1]=I2O_CMD_SYS_ENABLE<<24|HOST_TID<<12|ADAPTER_TID;
+	msg[2]= 0;
+	msg[3]= 0;
+
+	if ((ret = adpt_i2o_post_wait(pHba, msg, sizeof(msg), 240))) {
+		printk(KERN_WARNING"%s: Could not enable (status=%#10x).\n", 
+			pHba->name, ret);
+	} else {
+		PDEBUG("%s: Enabled.\n", pHba->name);
+	}
+
+	adpt_i2o_status_get(pHba);
+	return ret;
+}
+
+
+static int adpt_i2o_systab_send(adpt_hba* pHba)
+{
+	 u32 msg[12];
+	 int ret;
+
+	msg[0] = I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6;
+	msg[1] = I2O_CMD_SYS_TAB_SET<<24 | HOST_TID<<12 | ADAPTER_TID;
+	msg[2] = 0;
+	msg[3] = 0;
+	msg[4] = (0<<16) | ((pHba->unit+2) << 12); /* Host 0 IOP ID (unit + 2) */
+	msg[5] = 0;				   /* Segment 0 */
+
+	/* 
+	 * Provide three SGL-elements:
+	 * System table (SysTab), Private memory space declaration and 
+	 * Private i/o space declaration  
+	 */
+	msg[6] = 0x54000000 | sys_tbl_len;
+	msg[7] = virt_to_phys(sys_tbl);
+	msg[8] = 0x54000000 | 0;
+	msg[9] = 0;
+	msg[10] = 0xD4000000 | 0;
+	msg[11] = 0;
+
+	if ((ret=adpt_i2o_post_wait(pHba, msg, sizeof(msg), 120))) {
+		printk(KERN_INFO "%s: Unable to set SysTab (status=%#10x).\n", 
+			pHba->name, ret);
+	}
+#ifdef DEBUG
+	else {
+		PINFO("%s: SysTab set.\n", pHba->name);
+	}
+#endif
+
+	return ret;	
+ }
+
+
+/*============================================================================
+ *
+ *============================================================================
+ */
+
+
+#ifdef UARTDELAY 
+
+static static void adpt_delay(int millisec)
+{
+	int i;
+	for (i = 0; i < millisec; i++) {
+		udelay(1000);	/* delay for one millisecond */
+	}
+}
+
+#endif
+
+static struct scsi_host_template driver_template = {
+	.name			= "dpt_i2o",
+	.proc_name		= "dpt_i2o",
+	.proc_info		= adpt_proc_info,
+	.detect			= adpt_detect,	
+	.release		= adpt_release,
+	.info			= adpt_info,
+	.queuecommand		= adpt_queue,
+	.eh_abort_handler	= adpt_abort,
+	.eh_device_reset_handler = adpt_device_reset,
+	.eh_bus_reset_handler	= adpt_bus_reset,
+	.eh_host_reset_handler	= adpt_reset,
+	.bios_param		= adpt_bios_param,
+	.slave_configure	= adpt_slave_configure,
+	.can_queue		= MAX_TO_IOP_MESSAGES,
+	.this_id		= 7,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
new file mode 100644
index 0000000..426e15d
--- /dev/null
+++ b/drivers/scsi/dpti.h
@@ -0,0 +1,359 @@
+/***************************************************************************
+                          dpti.h  -  description
+                             -------------------
+    begin                : Thu Sep 7 2000
+    copyright            : (C) 2001 by Adaptec
+
+    See Documentation/scsi/dpti.txt for history, notes, license info
+    and credits
+ ***************************************************************************/
+
+/***************************************************************************
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) any later version.                                   *
+ *                                                                         *
+ ***************************************************************************/
+
+#ifndef _DPT_H
+#define _DPT_H
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,00)
+#define MAX_TO_IOP_MESSAGES   (210)
+#else
+#define MAX_TO_IOP_MESSAGES   (255)
+#endif
+#define MAX_FROM_IOP_MESSAGES (255)
+
+
+/*
+ * SCSI interface function Prototypes
+ */
+
+static int adpt_detect(struct scsi_host_template * sht);
+static int adpt_queue(struct scsi_cmnd * cmd, void (*cmdcomplete) (struct scsi_cmnd *));
+static int adpt_abort(struct scsi_cmnd * cmd);
+static int adpt_reset(struct scsi_cmnd* cmd);
+static int adpt_release(struct Scsi_Host *host);
+static int adpt_slave_configure(struct scsi_device *);
+
+static const char *adpt_info(struct Scsi_Host *pSHost);
+static int adpt_bios_param(struct scsi_device * sdev, struct block_device *dev,
+		sector_t, int geom[]);
+
+static int adpt_bus_reset(struct scsi_cmnd* cmd);
+static int adpt_device_reset(struct scsi_cmnd* cmd);
+
+
+/*
+ * Scsi_Host_Template (see hosts.h) 
+ */
+
+#define DPT_DRIVER_NAME	"Adaptec I2O RAID"
+
+#ifndef HOSTS_C
+
+#include "dpt/sys_info.h"
+#include <linux/wait.h>
+#include "dpt/dpti_i2o.h"
+#include "dpt/dpti_ioctl.h"
+
+#define DPT_I2O_VERSION "2.4 Build 5go"
+#define DPT_VERSION     2
+#define DPT_REVISION    '4'
+#define DPT_SUBREVISION '5'
+#define DPT_BETA	""
+#define DPT_MONTH      8 
+#define DPT_DAY        7
+#define DPT_YEAR        (2001-1980)
+
+#define DPT_DRIVER	"dpt_i2o"
+#define DPTI_I2O_MAJOR	(151)
+#define DPT_ORGANIZATION_ID (0x1B)        /* For Private Messages */
+#define DPTI_MAX_HBA	(16)
+#define MAX_CHANNEL     (5)	// Maximum Channel # Supported
+#define MAX_ID        	(128)	// Maximum Target ID Supported
+
+/* Sizes in 4 byte words */
+#define REPLY_FRAME_SIZE  (17)
+#define MAX_MESSAGE_SIZE  (128)
+#define SG_LIST_ELEMENTS  (56)
+
+#define EMPTY_QUEUE           0xffffffff
+#define I2O_INTERRUPT_PENDING_B   (0x08)
+
+#define PCI_DPT_VENDOR_ID         (0x1044)	// DPT PCI Vendor ID
+#define PCI_DPT_DEVICE_ID         (0xA501)	// DPT PCI I2O Device ID
+#define PCI_DPT_RAPTOR_DEVICE_ID  (0xA511)	
+
+//#define REBOOT_NOTIFIER 1
+/* Debugging macro from Linux Device Drivers - Rubini */
+#undef PDEBUG
+#ifdef DEBUG
+//TODO add debug level switch
+#  define PDEBUG(fmt, args...)  printk(KERN_DEBUG "dpti: " fmt, ##args)
+#  define PDEBUGV(fmt, args...) printk(KERN_DEBUG "dpti: " fmt, ##args)
+#else
+# define PDEBUG(fmt, args...) /* not debugging: nothing */
+# define PDEBUGV(fmt, args...) /* not debugging: nothing */
+#endif
+
+#define PERROR(fmt, args...) printk(KERN_ERR fmt, ##args)
+#define PWARN(fmt, args...) printk(KERN_WARNING fmt, ##args)
+#define PINFO(fmt, args...) printk(KERN_INFO fmt, ##args)
+#define PCRIT(fmt, args...) printk(KERN_CRIT fmt, ##args)
+
+#define SHUTDOWN_SIGS	(sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+
+// Command timeouts
+#define FOREVER			(0)
+#define TMOUT_INQUIRY 		(20)
+#define TMOUT_FLUSH		(360/45)
+#define TMOUT_ABORT		(30)
+#define TMOUT_SCSI		(300)
+#define TMOUT_IOPRESET		(360)
+#define TMOUT_GETSTATUS		(15)
+#define TMOUT_INITOUTBOUND	(15)
+#define TMOUT_LCT		(360)
+
+
+#define I2O_SCSI_DEVICE_DSC_MASK                0x00FF
+
+#define I2O_DETAIL_STATUS_UNSUPPORTED_FUNCTION  0x000A
+
+#define I2O_SCSI_DSC_MASK                   0xFF00
+#define I2O_SCSI_DSC_SUCCESS                0x0000
+#define I2O_SCSI_DSC_REQUEST_ABORTED        0x0200
+#define I2O_SCSI_DSC_UNABLE_TO_ABORT        0x0300
+#define I2O_SCSI_DSC_COMPLETE_WITH_ERROR    0x0400
+#define I2O_SCSI_DSC_ADAPTER_BUSY           0x0500
+#define I2O_SCSI_DSC_REQUEST_INVALID        0x0600
+#define I2O_SCSI_DSC_PATH_INVALID           0x0700
+#define I2O_SCSI_DSC_DEVICE_NOT_PRESENT     0x0800
+#define I2O_SCSI_DSC_UNABLE_TO_TERMINATE    0x0900
+#define I2O_SCSI_DSC_SELECTION_TIMEOUT      0x0A00
+#define I2O_SCSI_DSC_COMMAND_TIMEOUT        0x0B00
+#define I2O_SCSI_DSC_MR_MESSAGE_RECEIVED    0x0D00
+#define I2O_SCSI_DSC_SCSI_BUS_RESET         0x0E00
+#define I2O_SCSI_DSC_PARITY_ERROR_FAILURE   0x0F00
+#define I2O_SCSI_DSC_AUTOSENSE_FAILED       0x1000
+#define I2O_SCSI_DSC_NO_ADAPTER             0x1100
+#define I2O_SCSI_DSC_DATA_OVERRUN           0x1200
+#define I2O_SCSI_DSC_UNEXPECTED_BUS_FREE    0x1300
+#define I2O_SCSI_DSC_SEQUENCE_FAILURE       0x1400
+#define I2O_SCSI_DSC_REQUEST_LENGTH_ERROR   0x1500
+#define I2O_SCSI_DSC_PROVIDE_FAILURE        0x1600
+#define I2O_SCSI_DSC_BDR_MESSAGE_SENT       0x1700
+#define I2O_SCSI_DSC_REQUEST_TERMINATED     0x1800
+#define I2O_SCSI_DSC_IDE_MESSAGE_SENT       0x3300
+#define I2O_SCSI_DSC_RESOURCE_UNAVAILABLE   0x3400
+#define I2O_SCSI_DSC_UNACKNOWLEDGED_EVENT   0x3500
+#define I2O_SCSI_DSC_MESSAGE_RECEIVED       0x3600
+#define I2O_SCSI_DSC_INVALID_CDB            0x3700
+#define I2O_SCSI_DSC_LUN_INVALID            0x3800
+#define I2O_SCSI_DSC_SCSI_TID_INVALID       0x3900
+#define I2O_SCSI_DSC_FUNCTION_UNAVAILABLE   0x3A00
+#define I2O_SCSI_DSC_NO_NEXUS               0x3B00
+#define I2O_SCSI_DSC_SCSI_IID_INVALID       0x3C00
+#define I2O_SCSI_DSC_CDB_RECEIVED           0x3D00
+#define I2O_SCSI_DSC_LUN_ALREADY_ENABLED    0x3E00
+#define I2O_SCSI_DSC_BUS_BUSY               0x3F00
+#define I2O_SCSI_DSC_QUEUE_FROZEN           0x4000
+
+
+#ifndef TRUE
+#define TRUE                  1
+#define FALSE                 0
+#endif
+
+#define HBA_FLAGS_INSTALLED_B       0x00000001	// Adapter Was Installed
+#define HBA_FLAGS_BLINKLED_B        0x00000002	// Adapter In Blink LED State
+#define HBA_FLAGS_IN_RESET	0x00000040	/* in reset */
+#define HBA_HOSTRESET_FAILED	0x00000080	/* adpt_resethost failed */
+
+
+// Device state flags
+#define DPTI_DEV_ONLINE    0x00
+#define DPTI_DEV_UNSCANNED 0x01
+#define DPTI_DEV_RESET	   0x02
+#define DPTI_DEV_OFFLINE   0x04
+
+
+struct adpt_device {
+	struct adpt_device* next_lun;
+	u32	flags;
+	u32	type;
+	u32	capacity;
+	u32	block_size;
+	u8	scsi_channel;
+	u8	scsi_id;
+	u8 	scsi_lun;
+	u8	state;
+	u16	tid;
+	struct i2o_device* pI2o_dev;
+	struct scsi_device *pScsi_dev;
+};
+
+struct adpt_channel {
+	struct adpt_device* device[MAX_ID];	/* used as an array of 128 scsi ids */
+	u8	scsi_id;
+	u8	type;
+	u16	tid;
+	u32	state;
+	struct i2o_device* pI2o_dev;
+};
+
+// HBA state flags
+#define DPTI_STATE_RESET	(0x01)
+#define DPTI_STATE_IOCTL	(0x02)
+
+typedef struct _adpt_hba {
+	struct _adpt_hba *next;
+	struct pci_dev *pDev;
+	struct Scsi_Host *host;
+	u32 state;
+	spinlock_t state_lock;
+	int unit;
+	int host_no;		/* SCSI host number */
+	u8 initialized;
+	u8 in_use;		/* is the management node open*/
+
+	char name[32];
+	char detail[55];
+
+	void __iomem *base_addr_virt;
+	void __iomem *msg_addr_virt;
+	ulong base_addr_phys;
+	void __iomem *post_port;
+	void __iomem *reply_port;
+	void __iomem *irq_mask;
+	u16  post_count;
+	u32  post_fifo_size;
+	u32  reply_fifo_size;
+	u32* reply_pool;
+	u32  sg_tablesize;	// Scatter/Gather List Size.       
+	u8  top_scsi_channel;
+	u8  top_scsi_id;
+	u8  top_scsi_lun;
+
+	i2o_status_block* status_block;
+	i2o_hrt* hrt;
+	i2o_lct* lct;
+	uint lct_size;
+	struct i2o_device* devices;
+	struct adpt_channel channel[MAX_CHANNEL];
+	struct proc_dir_entry* proc_entry;	/* /proc dir */
+
+	void __iomem *FwDebugBuffer_P;	// Virtual Address Of FW Debug Buffer
+	u32   FwDebugBufferSize;	// FW Debug Buffer Size In Bytes
+	void __iomem *FwDebugStrLength_P;// Virtual Addr Of FW Debug String Len
+	void __iomem *FwDebugFlags_P;	// Virtual Address Of FW Debug Flags 
+	void __iomem *FwDebugBLEDflag_P;// Virtual Addr Of FW Debug BLED
+	void __iomem *FwDebugBLEDvalue_P;// Virtual Addr Of FW Debug BLED
+	u32 FwDebugFlags;
+} adpt_hba;
+
+struct sg_simple_element {
+   u32  flag_count;
+   u32 addr_bus;
+}; 
+
+/*
+ * Function Prototypes
+ */
+
+static void adpt_i2o_sys_shutdown(void);
+static int adpt_init(void);
+static int adpt_i2o_build_sys_table(void);
+static irqreturn_t adpt_isr(int irq, void *dev_id, struct pt_regs *regs);
+#ifdef REBOOT_NOTIFIER
+static int adpt_reboot_event(struct notifier_block *n, ulong code, void *p);
+#endif
+
+static void adpt_i2o_report_hba_unit(adpt_hba* pHba, struct i2o_device *d);
+static int adpt_i2o_query_scalar(adpt_hba* pHba, int tid, 
+			int group, int field, void *buf, int buflen);
+#ifdef DEBUG
+static const char *adpt_i2o_get_class_name(int class);
+#endif
+static int adpt_i2o_issue_params(int cmd, adpt_hba* pHba, int tid, 
+		  void *opblk, int oplen, void *resblk, int reslen);
+static int adpt_i2o_post_wait(adpt_hba* pHba, u32* msg, int len, int timeout);
+static int adpt_i2o_lct_get(adpt_hba* pHba);
+static int adpt_i2o_parse_lct(adpt_hba* pHba);
+static int adpt_i2o_activate_hba(adpt_hba* pHba);
+static int adpt_i2o_enable_hba(adpt_hba* pHba);
+static int adpt_i2o_install_device(adpt_hba* pHba, struct i2o_device *d);
+static s32 adpt_i2o_post_this(adpt_hba* pHba, u32* data, int len);
+static s32 adpt_i2o_quiesce_hba(adpt_hba* pHba);
+static s32 adpt_i2o_status_get(adpt_hba* pHba);
+static s32 adpt_i2o_init_outbound_q(adpt_hba* pHba);
+static s32 adpt_i2o_hrt_get(adpt_hba* pHba);
+static s32 adpt_scsi_to_i2o(adpt_hba* pHba, struct scsi_cmnd* cmd, struct adpt_device* dptdevice);
+static s32 adpt_i2o_to_scsi(ulong reply, struct scsi_cmnd* cmd);
+static s32 adpt_scsi_register(adpt_hba* pHba,struct scsi_host_template * sht);
+static s32 adpt_hba_reset(adpt_hba* pHba);
+static s32 adpt_i2o_reset_hba(adpt_hba* pHba);
+static s32 adpt_rescan(adpt_hba* pHba);
+static s32 adpt_i2o_reparse_lct(adpt_hba* pHba);
+static s32 adpt_send_nop(adpt_hba*pHba,u32 m);
+static void adpt_i2o_delete_hba(adpt_hba* pHba);
+static void adpt_inquiry(adpt_hba* pHba);
+static void adpt_fail_posted_scbs(adpt_hba* pHba);
+static struct adpt_device* adpt_find_device(adpt_hba* pHba, u32 chan, u32 id, u32 lun);
+static int adpt_install_hba(struct scsi_host_template* sht, struct pci_dev* pDev) ;
+static int adpt_i2o_online_hba(adpt_hba* pHba);
+static void adpt_i2o_post_wait_complete(u32, int);
+static int adpt_i2o_systab_send(adpt_hba* pHba);
+
+static int adpt_ioctl(struct inode *inode, struct file *file, uint cmd, ulong arg);
+static int adpt_open(struct inode *inode, struct file *file);
+static int adpt_close(struct inode *inode, struct file *file);
+
+
+#ifdef UARTDELAY
+static void adpt_delay(int millisec);
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
+static struct pci_dev* adpt_pci_find_device(uint vendor, struct pci_dev* from);
+#endif
+
+#if defined __ia64__ 
+static void adpt_ia64_info(sysInfo_S* si);
+#endif
+#if defined __sparc__ 
+static void adpt_sparc_info(sysInfo_S* si);
+#endif
+#if defined __alpha__ 
+static void adpt_sparc_info(sysInfo_S* si);
+#endif
+#if defined __i386__
+static void adpt_i386_info(sysInfo_S* si);
+#endif
+
+#define PRINT_BUFFER_SIZE     512
+
+#define HBA_FLAGS_DBG_FLAGS_MASK         0xffff0000	// Mask for debug flags
+#define HBA_FLAGS_DBG_KERNEL_PRINT_B     0x00010000	// Kernel Debugger Print
+#define HBA_FLAGS_DBG_FW_PRINT_B         0x00020000	// Firmware Debugger Print
+#define HBA_FLAGS_DBG_FUNCTION_ENTRY_B   0x00040000	// Function Entry Point
+#define HBA_FLAGS_DBG_FUNCTION_EXIT_B    0x00080000	// Function Exit
+#define HBA_FLAGS_DBG_ERROR_B            0x00100000	// Error Conditions
+#define HBA_FLAGS_DBG_INIT_B             0x00200000	// Init Prints
+#define HBA_FLAGS_DBG_OS_COMMANDS_B      0x00400000	// OS Command Info
+#define HBA_FLAGS_DBG_SCAN_B             0x00800000	// Device Scan
+
+#define FW_DEBUG_STR_LENGTH_OFFSET 0
+#define FW_DEBUG_FLAGS_OFFSET      4
+#define FW_DEBUG_BLED_OFFSET       8
+
+#define FW_DEBUG_FLAGS_NO_HEADERS_B    0x01
+#endif				/* !HOSTS_C */
+#endif				/* _DPT_H */
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
new file mode 100644
index 0000000..da1aaa4
--- /dev/null
+++ b/drivers/scsi/dtc.c
@@ -0,0 +1,494 @@
+
+#define AUTOSENSE
+#define PSEUDO_DMA
+#define DONT_USE_INTR
+#define UNSAFE			/* Leave interrupts enabled during pseudo-dma I/O */
+#define xNDEBUG (NDEBUG_INTR+NDEBUG_RESELECTION+\
+		 NDEBUG_SELECTION+NDEBUG_ARBITRATION)
+#define DMA_WORKS_RIGHT
+
+
+/*
+ * DTC 3180/3280 driver, by
+ *	Ray Van Tassle	rayvt@comm.mot.com
+ *
+ *	taken from ...
+ *	Trantor T128/T128F/T228 driver by...
+ *
+ * 	Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 1.
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+*/
+
+/*
+ * Options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *      for commands that return with a CHECK CONDITION status. 
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking.  Not supported.
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. 
+ *		You probably want this.
+ *
+ * The card is detected and initialized in one of several ways : 
+ * 1.  Autoprobe (default) - since the board is memory mapped, 
+ *     a BIOS signature is scanned for to locate the registers.
+ *     An interrupt is triggered to autoprobe for the interrupt
+ *     line.
+ *
+ * 2.  With command line overrides - dtc=address,irq may be 
+ *     used on the LILO command line to override the defaults.
+ * 
+*/
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+ where something crashed or gets stuck at */
+/* 1 = blue
+ 2 = green
+ 3 = cyan
+ 4 = red
+ 5 = magenta
+ 6 = yellow
+ 7 = white
+*/
+#if 0
+#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+
+
+#include <asm/system.h>
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "dtc.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+
+
+#define DTC_PUBLIC_RELEASE 2
+
+/*#define DTCDEBUG 0x1*/
+#define DTCDEBUG_INIT	0x1
+#define DTCDEBUG_TRANSFER 0x2
+
+/*
+ * The DTC3180 & 3280 boards are memory mapped.
+ * 
+ */
+
+/*
+ */
+/* Offset from DTC_5380_OFFSET */
+#define DTC_CONTROL_REG		0x100	/* rw */
+#define D_CR_ACCESS		0x80	/* ro set=can access 3280 registers */
+#define CSR_DIR_READ		0x40	/* rw direction, 1 = read 0 = write */
+
+#define CSR_RESET              0x80	/* wo  Resets 53c400 */
+#define CSR_5380_REG           0x80	/* ro  5380 registers can be accessed */
+#define CSR_TRANS_DIR          0x40	/* rw  Data transfer direction */
+#define CSR_SCSI_BUFF_INTR     0x20	/* rw  Enable int on transfer ready */
+#define CSR_5380_INTR          0x10	/* rw  Enable 5380 interrupts */
+#define CSR_SHARED_INTR        0x08	/* rw  Interrupt sharing */
+#define CSR_HOST_BUF_NOT_RDY   0x04	/* ro  Host buffer not ready */
+#define CSR_SCSI_BUF_RDY       0x02	/* ro  SCSI buffer ready */
+#define CSR_GATED_5380_IRQ     0x01	/* ro  Last block xferred */
+#define CSR_INT_BASE (CSR_SCSI_BUFF_INTR | CSR_5380_INTR)
+
+
+#define DTC_BLK_CNT		0x101	/* rw 
+					 * # of 128-byte blocks to transfer */
+
+
+#define D_CR_ACCESS             0x80	/* ro set=can access 3280 registers */
+
+#define DTC_SWITCH_REG		0x3982	/* ro - DIP switches */
+#define DTC_RESUME_XFER		0x3982	/* wo - resume data xfer 
+					 * after disconnect/reconnect*/
+
+#define DTC_5380_OFFSET		0x3880	/* 8 registers here, see NCR5380.h */
+
+/*!!!! for dtc, it's a 128 byte buffer at 3900 !!! */
+#define DTC_DATA_BUF		0x3900	/* rw 128 bytes long */
+
+static struct override {
+	unsigned int address;
+	int irq;
+} overrides
+#ifdef OVERRIDE
+[] __initdata = OVERRIDE;
+#else
+[4] __initdata = { {
+0, IRQ_AUTO}, {
+0, IRQ_AUTO}, {
+0, IRQ_AUTO}, {
+0, IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+	unsigned long address;
+	int noauto;
+} bases[] __initdata = { 
+	{ 0xcc000, 0 }, 
+	{ 0xc8000, 0 }, 
+	{ 0xdc000, 0 }, 
+	{ 0xd8000, 0 }
+};
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+static const struct signature {
+	const char *string;
+	int offset;
+} signatures[] = { 
+	{"DATA TECHNOLOGY CORPORATION BIOS", 0x25},
+};
+
+#define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
+
+#ifndef MODULE
+/*
+ * Function : dtc_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+*/
+
+static void __init dtc_setup(char *str, int *ints)
+{
+	static int commandline_current = 0;
+	int i;
+	if (ints[0] != 2)
+		printk("dtc_setup: usage dtc=address,irq\n");
+	else if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].address = ints[1];
+		overrides[commandline_current].irq = ints[2];
+		for (i = 0; i < NO_BASES; ++i)
+			if (bases[i].address == ints[1]) {
+				bases[i].noauto = 1;
+				break;
+			}
+		++commandline_current;
+	}
+}
+#endif
+
+/* 
+ * Function : int dtc_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : detects and initializes DTC 3180/3280 controllers
+ *	that were autoprobed, overridden on the LILO command line, 
+ *	or specified at compile time.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ * 
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+*/
+
+static int __init dtc_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0, current_base = 0;
+	struct Scsi_Host *instance;
+	unsigned int addr;
+	void __iomem *base;
+	int sig, count;
+
+	tpnt->proc_name = "dtc3x80";
+	tpnt->proc_info = &dtc_proc_info;
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+		addr = 0;
+		base = NULL;
+
+		if (overrides[current_override].address) {
+			addr = overrides[current_override].address;
+			base = ioremap(addr, 0x2000);
+			if (!base)
+				addr = 0;
+		} else
+			for (; !addr && (current_base < NO_BASES); ++current_base) {
+#if (DTCDEBUG & DTCDEBUG_INIT)
+				printk("scsi-dtc : probing address %08x\n", bases[current_base].address);
+#endif
+				if (bases[current_base].noauto)
+					continue;
+				base = ioremap(bases[current_base].address, 0x2000);
+				if (!base)
+					continue;
+				for (sig = 0; sig < NO_SIGNATURES; ++sig) {
+					if (check_signature(base + signatures[sig].offset, signatures[sig].string, strlen(signatures[sig].string))) {
+						addr = bases[current_base].address;
+#if (DTCDEBUG & DTCDEBUG_INIT)
+						printk("scsi-dtc : detected board.\n");
+#endif
+						goto found;
+					}
+				}
+				iounmap(base);
+			}
+
+#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
+		printk("scsi-dtc : base = %08x\n", addr);
+#endif
+
+		if (!addr)
+			break;
+
+found:
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL)
+			break;
+
+		instance->base = addr;
+		((struct NCR5380_hostdata *)(instance)->hostdata)->base = base;
+
+		NCR5380_init(instance, 0);
+
+		NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);	/* Enable int's */
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
+
+#ifndef DONT_USE_INTR
+		/* With interrupts enabled, it will sometimes hang when doing heavy
+		 * reads. So better not enable them until I finger it out. */
+		if (instance->irq != SCSI_IRQ_NONE)
+			if (request_irq(instance->irq, dtc_intr, SA_INTERRUPT, "dtc", instance)) {
+				printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
+				instance->irq = SCSI_IRQ_NONE;
+			}
+
+		if (instance->irq == SCSI_IRQ_NONE) {
+			printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
+#else
+		if (instance->irq != SCSI_IRQ_NONE)
+			printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
+		instance->irq = SCSI_IRQ_NONE;
+#endif
+#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
+		printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
+#endif
+
+		printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
+		if (instance->irq == SCSI_IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
+
+		++current_override;
+		++count;
+	}
+	return count;
+}
+
+/*
+ * Function : int dtc_biosparam(Disk * disk, struct block_device *dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *	the specified device / size.
+ * 
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ *	major / minor, ip[] = {heads, sectors, cylinders}  
+ *
+ * Returns : always 0 (success), initializes ip
+ *	
+*/
+
+/* 
+ * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+*/
+
+static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
+			 sector_t capacity, int *ip)
+{
+	int size = capacity;
+
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	return 0;
+}
+
+
+/****************************************************************
+ * Function : int NCR5380_pread (struct Scsi_Host *instance, 
+ *	unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, reads len bytes to 
+ *	dst
+ * 
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+*/
+
+static int dtc_maxi = 0;
+static int dtc_wmaxi = 0;
+
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	unsigned char *d = dst;
+	int i;			/* For counting time spent in the poll-loop */
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	i = 0;
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+	if (instance->irq == SCSI_IRQ_NONE)
+		NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
+	else
+		NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
+	NCR5380_write(DTC_BLK_CNT, len >> 7);	/* Block count */
+	rtrc(1);
+	while (len > 0) {
+		rtrc(2);
+		while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+			++i;
+		rtrc(3);
+		memcpy_fromio(d, base + DTC_DATA_BUF, 128);
+		d += 128;
+		len -= 128;
+		rtrc(7);
+		/*** with int's on, it sometimes hangs after here.
+		 * Looks like something makes HBNR go away. */
+	}
+	rtrc(4);
+	while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+		++i;
+	NCR5380_write(MODE_REG, 0);	/* Clear the operating mode */
+	rtrc(0);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	if (i > dtc_maxi)
+		dtc_maxi = i;
+	return (0);
+}
+
+/****************************************************************
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
+ *	unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ *	src
+ * 
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+*/
+
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	int i;
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
+	/* set direction (write) */
+	if (instance->irq == SCSI_IRQ_NONE)
+		NCR5380_write(DTC_CONTROL_REG, 0);
+	else
+		NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
+	NCR5380_write(DTC_BLK_CNT, len >> 7);	/* Block count */
+	for (i = 0; len > 0; ++i) {
+		rtrc(5);
+		/* Poll until the host buffer can accept data. */
+		while (NCR5380_read(DTC_CONTROL_REG) & CSR_HOST_BUF_NOT_RDY)
+			++i;
+		rtrc(3);
+		memcpy_toio(base + DTC_DATA_BUF, src, 128);
+		src += 128;
+		len -= 128;
+	}
+	rtrc(4);
+	while (!(NCR5380_read(DTC_CONTROL_REG) & D_CR_ACCESS))
+		++i;
+	rtrc(6);
+	/* Wait until the last byte has been sent to the disk */
+	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+		++i;
+	rtrc(7);
+	/* Check for parity error here. fixme. */
+	NCR5380_write(MODE_REG, 0);	/* Clear the operating mode */
+	rtrc(0);
+	if (i > dtc_wmaxi)
+		dtc_wmaxi = i;
+	return (0);
+}
+
+MODULE_LICENSE("GPL");
+
+#include "NCR5380.c"
+
+static int dtc_release(struct Scsi_Host *shost)
+{
+	NCR5380_local_declare();
+	NCR5380_setup(shost);
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	NCR5380_exit(shost);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	iounmap(base);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name				= "DTC 3180/3280 ",
+	.detect				= dtc_detect,
+	.release			= dtc_release,
+	.queuecommand			= dtc_queue_command,
+	.eh_abort_handler		= dtc_abort,
+	.eh_bus_reset_handler		= dtc_bus_reset,
+	.eh_device_reset_handler	= dtc_device_reset,
+	.eh_host_reset_handler          = dtc_host_reset,
+	.bios_param     		= dtc_biosparam,
+	.can_queue      		= CAN_QUEUE,
+	.this_id        		= 7,
+	.sg_tablesize   		= SG_ALL,
+	.cmd_per_lun    		= CMD_PER_LUN,
+	.use_clustering 		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
new file mode 100644
index 0000000..c4bcdbf
--- /dev/null
+++ b/drivers/scsi/dtc.h
@@ -0,0 +1,99 @@
+/*
+ * DTC controller, taken from T128 driver by...
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 2. 
+ *
+ * For more information, please consult 
+ *
+ * 
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+#ifndef DTC3280_H
+#define DTC3280_H
+
+static int dtc_abort(Scsi_Cmnd *);
+static int dtc_biosparam(struct scsi_device *, struct block_device *,
+		         sector_t, int*);
+static int dtc_detect(Scsi_Host_Template *);
+static int dtc_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int dtc_bus_reset(Scsi_Cmnd *);
+static int dtc_device_reset(Scsi_Cmnd *);
+static int dtc_host_reset(Scsi_Cmnd *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32 
+#endif
+
+#define NCR5380_implementation_fields \
+    void __iomem *base
+
+#define NCR5380_local_declare() \
+    void __iomem *base
+
+#define NCR5380_setup(instance) \
+    base = ((struct NCR5380_hostdata *)(instance)->hostdata)->base
+
+#define DTC_address(reg) (base + DTC_5380_OFFSET + reg)
+
+#define dbNCR5380_read(reg)                                              \
+    (rval=readb(DTC_address(reg)), \
+     (((unsigned char) printk("DTC : read register %d at addr %p is: %02x\n"\
+    , (reg), DTC_address(reg), rval)), rval ) )
+
+#define dbNCR5380_write(reg, value) do {                                  \
+    printk("DTC : write %02x to register %d at address %p\n",         \
+            (value), (reg), DTC_address(reg));     \
+    writeb(value, DTC_address(reg));} while(0)
+
+
+#if !(DTCDEBUG & DTCDEBUG_TRANSFER) 
+#define NCR5380_read(reg) (readb(DTC_address(reg)))
+#define NCR5380_write(reg, value) (writeb(value, DTC_address(reg)))
+#else
+#define NCR5380_read(reg) (readb(DTC_address(reg)))
+#define xNCR5380_read(reg)						\
+    (((unsigned char) printk("DTC : read register %d at address %p\n"\
+    , (reg), DTC_address(reg))), readb(DTC_address(reg)))
+
+#define NCR5380_write(reg, value) do {					\
+    printk("DTC : write %02x to register %d at address %p\n", 	\
+	    (value), (reg), DTC_address(reg));	\
+    writeb(value, DTC_address(reg));} while(0)
+#endif
+
+#define NCR5380_intr			dtc_intr
+#define NCR5380_queue_command		dtc_queue_command
+#define NCR5380_abort			dtc_abort
+#define NCR5380_bus_reset		dtc_bus_reset
+#define NCR5380_device_reset		dtc_device_reset
+#define NCR5380_host_reset		dtc_host_reset
+#define NCR5380_proc_info		dtc_proc_info 
+
+/* 15 12 11 10
+   1001 1100 0000 0000 */
+
+#define DTC_IRQS 0x9c00
+
+
+#endif /* DTC3280_H */
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
new file mode 100644
index 0000000..81d16cf
--- /dev/null
+++ b/drivers/scsi/eata.c
@@ -0,0 +1,2621 @@
+/*
+ *      eata.c - Low-level driver for EATA/DMA SCSI host adapters.
+ *
+ *      03 Jun 2003 Rev. 8.10 for linux-2.5.70
+ *        + Update for new IRQ API.
+ *        + Use "goto" when appropriate.
+ *        + Drop eata.h.
+ *        + Update for new module_param API.
+ *        + Module parameters  can now be specified only in the
+ *          same format as the kernel boot options.
+ *
+ *             boot option    old module param 
+ *             -----------    ------------------
+ *             addr,...       io_port=addr,...
+ *             lc:[y|n]       linked_comm=[1|0]
+ *             mq:xx          max_queue_depth=xx
+ *             tm:[0|1|2]     tag_mode=[0|1|2]
+ *             et:[y|n]       ext_tran=[1|0]
+ *             rs:[y|n]       rev_scan=[1|0]
+ *             ip:[y|n]       isa_probe=[1|0]
+ *             ep:[y|n]       eisa_probe=[1|0]
+ *             pp:[y|n]       pci_probe=[1|0]
+ *
+ *          A valid example using the new parameter format is:
+ *          modprobe eata "eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n"
+ *
+ *          which is equivalent to the old format:
+ *          modprobe eata io_port=0x7410,0x230 linked_comm=1 tag_mode=0 \
+ *                        max_queue_depth=4 eisa_probe=0
+ *
+ *      12 Feb 2003 Rev. 8.04 for linux 2.5.60
+ *        + Release irq before calling scsi_register.
+ *
+ *      12 Nov 2002 Rev. 8.02 for linux 2.5.47
+ *        + Release driver_lock before calling scsi_register.
+ *
+ *      11 Nov 2002 Rev. 8.01 for linux 2.5.47
+ *        + Fixed bios_param and scsicam_bios_param calling parameters.
+ *
+ *      28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4
+ *        + Use new tcq and adjust_queue_depth api.
+ *        + New command line option (tm:[0-2]) to choose the type of tags:
+ *          0 -> disable tagging ; 1 -> simple tags  ; 2 -> ordered tags.
+ *          Default is tm:0 (tagged commands disabled).
+ *          For compatibility the "tc:" option is an alias of the "tm:"
+ *          option; tc:n is equivalent to tm:0 and tc:y is equivalent to
+ *          tm:1.
+ *        + The tagged_comm module parameter has been removed, use tag_mode
+ *          instead, equivalent to the "tm:" boot option.
+ *
+ *      10 Oct 2002 Rev. 7.70 for linux 2.5.42
+ *        + Foreport from revision 6.70.
+ *
+ *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
+ *        + This release is the first one tested on a Big Endian platform:
+ *          fixed endian-ness problem due to bitfields;
+ *          fixed endian-ness problem in read_pio.
+ *        + Added new options for selectively probing ISA, EISA and PCI bus:
+ *
+ *          Boot option   Parameter name    Default according to
+ *
+ *          ip:[y|n]      isa_probe=[1|0]   CONFIG_ISA  defined
+ *          ep:[y|n]      eisa_probe=[1|0]  CONFIG_EISA defined
+ *          pp:[y|n]      pci_probe=[1|0]   CONFIG_PCI  defined
+ *
+ *          The default action is to perform probing if the corrisponding
+ *          bus is configured and to skip probing otherwise.
+ *
+ *        + If pci_probe is in effect and a list of I/O  ports is specified
+ *          as parameter or boot option, pci_enable_device() is performed
+ *          on all pci devices matching PCI_CLASS_STORAGE_SCSI.
+ *
+ *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
+ *        + Backport from rev. 7.22 (use io_request_lock).
+ *
+ *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
+ *        + Remove any reference to virt_to_bus().
+ *        + Fix pio hang while detecting multiple HBAs.
+ *        + Fixed a board detection bug: in a system with
+ *          multiple ISA/EISA boards, all but the first one
+ *          were erroneously detected as PCI.
+ *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ *        + Use the dynamic DMA mapping API.
+ *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
+ *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
+ *        + Use host->host_lock instead of io_request_lock.
+ *
+ *       1 May 2001 Rev. 6.05 for linux 2.4.4
+ *        + Clean up all pci related routines.
+ *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
+ *
+ *      30 Jan 2001 Rev. 6.04 for linux 2.4.1
+ *        + Call pci_resource_start after pci_enable_device.
+ *
+ *      25 Jan 2001 Rev. 6.03 for linux 2.4.0
+ *        + "check_region" call replaced by "request_region".
+ *
+ *      22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
+ *        + Return code checked when calling pci_enable_device.
+ *        + Removed old scsi error handling support.
+ *        + The obsolete boot option flag eh:n is silently ignored.
+ *        + Removed error messages while a disk drive is powered up at
+ *          boot time.
+ *        + Improved boot messages: all tagged capable device are
+ *          indicated as "tagged" or "soft-tagged" :
+ *          - "soft-tagged"  means that the driver is trying to do its
+ *            own tagging (i.e. the tc:y option is in effect);
+ *          - "tagged" means that the device supports tagged commands,
+ *            but the driver lets the HBA be responsible for tagging
+ *            support.
+ *
+ *      16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
+ *        + Updated to the new __setup interface for boot command line options.
+ *        + When loaded as a module, accepts the new parameter boot_options
+ *          which value is a string with the same format of the kernel boot
+ *          command line options. A valid example is:
+ *          modprobe eata 'boot_options="0x7410,0x230,lc:y,tc:n,mq:4"'
+ *
+ *       9 Sep 1999 Rev. 5.10 for linux 2.2.12 and 2.3.17
+ *        + 64bit cleanup for Linux/Alpha platform support
+ *          (contribution from H.J. Lu).
+ *
+ *      22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
+ *        + Removed pre-2.2 source code compatibility.
+ *        + Added call to pci_set_master.
+ *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *        + Added command line option (rs:[y|n]) to reverse the scan order
+ *          of PCI boards. The default is rs:y, which reverses the BIOS order
+ *          while registering PCI boards. The default value rs:y generates
+ *          the same order of all previous revisions of this driver.
+ *          Pls. note that "BIOS order" might have been reversed itself
+ *          after the 2.1.9x PCI modifications in the linux kernel.
+ *          The rs value is ignored when the explicit list of addresses
+ *          is used by the "eata=port0,port1,..." command line option.
+ *        + Added command line option (et:[y|n]) to force use of extended
+ *          translation (255 heads, 63 sectors) as disk geometry.
+ *          The default is et:n, which uses the disk geometry returned
+ *          by scsicam_bios_param. The default value et:n is compatible with
+ *          all previous revisions of this driver.
+ *
+ *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ *          Increased busy timeout from 10 msec. to 200 msec. while
+ *          processing interrupts.
+ *
+ *      16 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux version >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
+ *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ *          Reworked interrupt handler.
+ *
+ *      11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ *          Major reliability improvement: when a batch with overlapping
+ *          requests is detected, requests are queued one at a time
+ *          eliminating any possible board or drive reordering.
+ *
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Added support for new PCI code and IO-APIC remapping of irqs.
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *
+ *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
+ *          io_port is now unsigned long.
+ *
+ *      17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ *          Use new scsi error handling code (if linux version >= 2.1.88).
+ *          Use new interrupt code.
+ *
+ *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ *          Use of udelay inside the wait loops to avoid timeout
+ *          problems with fast cpus.
+ *          Removed check about useless calls to the interrupt service
+ *          routine (reported on SMP systems only).
+ *          At initialization time "sorted/unsorted" is displayed instead
+ *          of "linked/unlinked" to reinforce the fact that "linking" is
+ *          nothing but "elevator sorting" in the actual implementation.
+ *
+ *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ *          Use of serial_number_at_timeout in abort and reset processing.
+ *          Use of the __initfunc and __initdata macro in setup code.
+ *          Minor cleanups in the list_statistics code.
+ *          Increased controller busy timeout in order to better support
+ *          slow SCSI devices.
+ *
+ *      24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
+ *          When loading as a module, parameter passing is now supported
+ *          both in 2.0 and in 2.1 style.
+ *          Fixed data transfer direction for some SCSI opcodes.
+ *          Immediate acknowledge to request sense commands.
+ *          Linked commands to each disk device are now reordered by elevator
+ *          sorting. Rare cases in which reordering of write requests could
+ *          cause wrong results are managed.
+ *          Fixed spurious timeouts caused by long simple queue tag sequences.
+ *          New command line option (tm:[0-3]) to choose the type of tags:
+ *          0 -> mixed (default); 1 -> simple; 2 -> head; 3 -> ordered.
+ *
+ *      18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
+ *          Added command line options to enable/disable linked commands
+ *          (lc:[y|n]), tagged commands (tc:[y|n]) and to set the max queue
+ *          depth (mq:xx). Default is "eata=lc:n,tc:n,mq:16".
+ *          Improved command linking.
+ *          Documented how to setup RAID-0 with DPT SmartRAID boards.
+ *
+ *       8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27
+ *          Added linked command support.
+ *          Improved detection of PCI boards using ISA base addresses.
+ *
+ *       3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27
+ *          Added support for tagged commands and queue depth adjustment.
+ *
+ *      22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
+ *          When CONFIG_PCI is defined, BIOS32 is used to include in the
+ *          list of i/o ports to be probed all the PCI SCSI controllers.
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "eata=port0,port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
+ *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
+ *          Added support for EATA 2.0C, PCI, multichannel and wide SCSI.
+ *
+ *      27 Sep 1996 rev. 2.12 for linux 2.1.0
+ *          Portability cleanups (virtual/bus addressing, little/big endian
+ *          support).
+ *
+ *      09 Jul 1996 rev. 2.11 for linux 2.0.4
+ *          Number of internal retries is now limited.
+ *
+ *      16 Apr 1996 rev. 2.10 for linux 1.3.90
+ *          New argument "reset_flags" to the reset routine.
+ *
+ *       6 Jul 1995 rev. 2.01 for linux 1.3.7
+ *          Update required by the new /proc/scsi support.
+ *
+ *      11 Mar 1995 rev. 2.00 for linux 1.2.0
+ *          Fixed a bug which prevented media change detection for removable
+ *          disk drives.
+ *
+ *      23 Feb 1995 rev. 1.18 for linux 1.1.94
+ *          Added a check for scsi_register returning NULL.
+ *
+ *      11 Feb 1995 rev. 1.17 for linux 1.1.91
+ *          Now DEBUG_RESET is disabled by default.
+ *          Register a board even if it does not assert DMA protocol support
+ *          (DPT SK2011B does not report correctly the dmasup bit).
+ *
+ *       9 Feb 1995 rev. 1.16 for linux 1.1.90
+ *          Use host->wish_block instead of host->block.
+ *          New list of Data Out SCSI commands.
+ *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while performing a reset.
+ *          All external symbols renamed to avoid possible name conflicts.
+ *
+ *      28 Jan 1995 rev. 1.14 for linux 1.1.86
+ *          Added module support.
+ *          Log and do a retry when a disk drive returns a target status
+ *          different from zero on a recovered error.
+ *
+ *      24 Jan 1995 rev. 1.13 for linux 1.1.85
+ *          Use optimized board configuration, with a measured performance
+ *          increase in the range 10%-20% on i/o throughput.
+ *
+ *      16 Jan 1995 rev. 1.12 for linux 1.1.81
+ *          Fix mscp structure comments (no functional change).
+ *          Display a message if check_region detects a port address
+ *          already in use.
+ *
+ *      17 Dec 1994 rev. 1.11 for linux 1.1.74
+ *          Use the scsicam_bios_param routine. This allows an easy
+ *          migration path from disk partition tables created using
+ *          different SCSI drivers and non optimal disk geometry.
+ *
+ *      15 Dec 1994 rev. 1.10 for linux 1.1.74
+ *          Added support for ISA EATA boards (DPT PM2011, DPT PM2021).
+ *          The host->block flag is set for all the detected ISA boards.
+ *          The detect routine no longer enforces LEVEL triggering
+ *          for EISA boards, it just prints a warning message.
+ *
+ *      30 Nov 1994 rev. 1.09 for linux 1.1.68
+ *          Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
+ *          Added optional support for using a single board at a time.
+ *
+ *      18 Nov 1994 rev. 1.08 for linux 1.1.64
+ *          Forces sg_tablesize = 64 and can_queue = 64 if these
+ *          values are not correctly detected (DPT PM2012).
+ *
+ *      14 Nov 1994 rev. 1.07 for linux 1.1.63  Final BETA release.
+ *      04 Aug 1994 rev. 1.00 for linux 1.1.39  First BETA release.
+ *
+ *
+ *          This driver is based on the CAM (Common Access Method Committee)
+ *          EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
+ *
+ *  Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com)
+ *
+ *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
+ */
+
+/*
+ *
+ *  Here is a brief description of the DPT SCSI host adapters.
+ *  All these boards provide an EATA/DMA compatible programming interface
+ *  and are fully supported by this driver in any configuration, including
+ *  multiple SCSI channels:
+ *
+ *  PM2011B/9X -  Entry Level ISA
+ *  PM2021A/9X -  High Performance ISA
+ *  PM2012A       Old EISA
+ *  PM2012B       Old EISA
+ *  PM2022A/9X -  Entry Level EISA
+ *  PM2122A/9X -  High Performance EISA
+ *  PM2322A/9X -  Extra High Performance EISA
+ *  PM3021     -  SmartRAID Adapter for ISA
+ *  PM3222     -  SmartRAID Adapter for EISA (PM3222W is 16-bit wide SCSI)
+ *  PM3224     -  SmartRAID Adapter for PCI  (PM3224W is 16-bit wide SCSI)
+ *  PM33340UW  -  SmartRAID Adapter for PCI  ultra wide multichannel
+ *
+ *  The above list is just an indication: as a matter of fact all DPT
+ *  boards using the EATA/DMA protocol are supported by this driver,
+ *  since they use exactely the same programming interface.
+ *
+ *  The DPT PM2001 provides only the EATA/PIO interface and hence is not
+ *  supported by this driver.
+ *
+ *  This code has been tested with up to 3 Distributed Processing Technology
+ *  PM2122A/9X (DPT SCSI BIOS v002.D1, firmware v05E.0) EISA controllers,
+ *  in any combination of private and shared IRQ.
+ *  PCI support has been tested using up to 2 DPT PM3224W (DPT SCSI BIOS
+ *  v003.D0, firmware v07G.0).
+ *
+ *  DPT SmartRAID boards support "Hardware Array" - a group of disk drives
+ *  which are all members of the same RAID-0, RAID-1 or RAID-5 array implemented
+ *  in host adapter hardware. Hardware Arrays are fully compatible with this
+ *  driver, since they look to it as a single disk drive.
+ *
+ *  WARNING: to create a RAID-0 "Hardware Array" you must select "Other Unix"
+ *  as the current OS in the DPTMGR "Initial System Installation" menu.
+ *  Otherwise RAID-0 is generated as an "Array Group" (i.e. software RAID-0),
+ *  which is not supported by the actual SCSI subsystem.
+ *  To get the "Array Group" functionality, the Linux MD driver must be used
+ *  instead of the DPT "Array Group" feature.
+ *
+ *  Multiple ISA, EISA and PCI boards can be configured in the same system.
+ *  It is suggested to put all the EISA boards on the same IRQ level, all
+ *  the PCI  boards on another IRQ level, while ISA boards cannot share
+ *  interrupts.
+ *
+ *  If you configure multiple boards on the same IRQ, the interrupt must
+ *  be _level_ triggered (not _edge_ triggered).
+ *
+ *  This driver detects EATA boards by probes at fixed port addresses,
+ *  so no BIOS32 or PCI BIOS support is required.
+ *  The suggested way to detect a generic EATA PCI board is to force on it
+ *  any unused EISA address, even if there are other controllers on the EISA
+ *  bus, or even if you system has no EISA bus at all.
+ *  Do not force any ISA address on EATA PCI boards.
+ *
+ *  If PCI bios support is configured into the kernel, BIOS32 is used to
+ *  include in the list of i/o ports to be probed all the PCI SCSI controllers.
+ *
+ *  Due to a DPT BIOS "feature", it might not be possible to force an EISA
+ *  address on more than a single DPT PCI board, so in this case you have to
+ *  let the PCI BIOS assign the addresses.
+ *
+ *  The sequence of detection probes is:
+ *
+ *  - ISA 0x1F0;
+ *  - PCI SCSI controllers (only if BIOS32 is available);
+ *  - EISA/PCI 0x1C88 through 0xFC88 (corresponding to EISA slots 1 to 15);
+ *  - ISA  0x170, 0x230, 0x330.
+ *
+ *  The above list of detection probes can be totally replaced by the
+ *  boot command line option: "eata=port0,port1,port2,...", where the
+ *  port0, port1... arguments are ISA/EISA/PCI addresses to be probed.
+ *  For example using "eata=0x7410,0x7450,0x230", the driver probes
+ *  only the two PCI addresses 0x7410 and 0x7450 and the ISA address 0x230,
+ *  in this order; "eata=0" totally disables this driver.
+ *
+ *  After the optional list of detection probes, other possible command line
+ *  options are:
+ *
+ *  et:y  force use of extended translation (255 heads, 63 sectors);
+ *  et:n  use disk geometry detected by scsicam_bios_param;
+ *  rs:y  reverse scan order while detecting PCI boards;
+ *  rs:n  use BIOS order while detecting PCI boards;
+ *  lc:y  enables linked commands;
+ *  lc:n  disables linked commands;
+ *  tm:0  disables tagged commands (same as tc:n);
+ *  tm:1  use simple queue tags (same as tc:y);
+ *  tm:2  use ordered queue tags (same as tc:2);
+ *  mq:xx set the max queue depth to the value xx (2 <= xx <= 32).
+ *
+ *  The default value is: "eata=lc:n,mq:16,tm:0,et:n,rs:n".
+ *  An example using the list of detection probes could be:
+ *  "eata=0x7410,0x230,lc:y,tm:2,mq:4,et:n".
+ *
+ *  When loading as a module, parameters can be specified as well.
+ *  The above example would be (use 1 in place of y and 0 in place of n):
+ *
+ *  modprobe eata io_port=0x7410,0x230 linked_comm=1 \
+ *                max_queue_depth=4 ext_tran=0 tag_mode=2 \
+ *                rev_scan=1
+ *
+ *  ----------------------------------------------------------------------------
+ *  In this implementation, linked commands are designed to work with any DISK
+ *  or CD-ROM, since this linking has only the intent of clustering (time-wise)
+ *  and reordering by elevator sorting commands directed to each device,
+ *  without any relation with the actual SCSI protocol between the controller
+ *  and the device.
+ *  If Q is the queue depth reported at boot time for each device (also named
+ *  cmds/lun) and Q > 2, whenever there is already an active command to the
+ *  device all other commands to the same device  (up to Q-1) are kept waiting
+ *  in the elevator sorting queue. When the active command completes, the
+ *  commands in this queue are sorted by sector address. The sort is chosen
+ *  between increasing or decreasing by minimizing the seek distance between
+ *  the sector of the commands just completed and the sector of the first
+ *  command in the list to be sorted.
+ *  Trivial math assures that the unsorted average seek distance when doing
+ *  random seeks over S sectors is S/3.
+ *  When (Q-1) requests are uniformly distributed over S sectors, the average
+ *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ *  average seek distance for (Q-1) random requests over S sectors is S/Q.
+ *  The elevator sorting hence divides the seek distance by a factor Q/3.
+ *  The above pure geometric remarks are valid in all cases and the
+ *  driver effectively reduces the seek distance by the predicted factor
+ *  when there are Q concurrent read i/o operations on the device, but this
+ *  does not necessarily results in a noticeable performance improvement:
+ *  your mileage may vary....
+ *
+ *  Note: command reordering inside a batch of queued commands could cause
+ *        wrong results only if there is at least one write request and the
+ *        intersection (sector-wise) of all requests is not empty.
+ *        When the driver detects a batch including overlapping requests
+ *        (a really rare event) strict serial (pid) order is enforced.
+ *  ----------------------------------------------------------------------------
+ *  The extended translation option (et:y) is useful when using large physical
+ *  disks/arrays. It could also be useful when switching between Adaptec boards
+ *  and DPT boards without reformatting the disk.
+ *  When a boot disk is partitioned with extended translation, in order to
+ *  be able to boot it with a DPT board is could be necessary to add to
+ *  lilo.conf additional commands as in the following example:
+ *
+ *  fix-table
+ *  disk=/dev/sda bios=0x80 sectors=63 heads=128 cylindres=546
+ *
+ *  where the above geometry should be replaced with the one reported at
+ *  power up by the DPT controller.
+ *  ----------------------------------------------------------------------------
+ *
+ *  The boards are named EATA0, EATA1,... according to the detection order.
+ *
+ *  In order to support multiple ISA boards in a reliable way,
+ *  the driver sets host->wish_block = 1 for all ISA boards.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <asm/byteorder.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+
+static int eata2x_detect(struct scsi_host_template *);
+static int eata2x_release(struct Scsi_Host *);
+static int eata2x_queuecommand(struct scsi_cmnd *,
+			       void (*done) (struct scsi_cmnd *));
+static int eata2x_eh_abort(struct scsi_cmnd *);
+static int eata2x_eh_host_reset(struct scsi_cmnd *);
+static int eata2x_bios_param(struct scsi_device *, struct block_device *,
+			     sector_t, int *);
+static int eata2x_slave_configure(struct scsi_device *);
+
+static struct scsi_host_template driver_template = {
+	.name = "EATA/DMA 2.0x rev. 8.10.00 ",
+	.detect = eata2x_detect,
+	.release = eata2x_release,
+	.queuecommand = eata2x_queuecommand,
+	.eh_abort_handler = eata2x_eh_abort,
+	.eh_device_reset_handler = NULL,
+	.eh_bus_reset_handler = NULL,
+	.eh_host_reset_handler = eata2x_eh_host_reset,
+	.bios_param = eata2x_bios_param,
+	.slave_configure = eata2x_slave_configure,
+	.this_id = 7,
+	.unchecked_isa_dma = 1,
+	.use_clustering = ENABLE_CLUSTERING
+};
+
+#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
+/* Subversion values */
+#define ISA  0
+#define ESA 1
+
+#undef  FORCE_CONFIG
+
+#undef  DEBUG_LINKED_COMMANDS
+#undef  DEBUG_DETECT
+#undef  DEBUG_PCI_DETECT
+#undef  DEBUG_INTERRUPT
+#undef  DEBUG_RESET
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
+
+#define MAX_ISA 4
+#define MAX_VESA 0
+#define MAX_EISA 15
+#define MAX_PCI 16
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
+#define MAX_CHANNEL 4
+#define MAX_LUN 32
+#define MAX_TARGET 32
+#define MAX_MAILBOXES 64
+#define MAX_SGLIST 64
+#define MAX_LARGE_SGLIST 122
+#define MAX_INTERNAL_RETRIES 64
+#define MAX_CMD_PER_LUN 2
+#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
+
+#define SKIP ULONG_MAX
+#define FREE 0
+#define IN_USE   1
+#define LOCKED   2
+#define IN_RESET 3
+#define IGNORE   4
+#define READY    5
+#define ABORTING 6
+#define NO_DMA  0xff
+#define MAXLOOP  10000
+#define TAG_DISABLED 0
+#define TAG_SIMPLE   1
+#define TAG_ORDERED  2
+
+#define REG_CMD         7
+#define REG_STATUS      7
+#define REG_AUX_STATUS  8
+#define REG_DATA        0
+#define REG_DATA2       1
+#define REG_SEE         6
+#define REG_LOW         2
+#define REG_LM          3
+#define REG_MID         4
+#define REG_MSB         5
+#define REGION_SIZE     9UL
+#define MAX_ISA_ADDR    0x03ff
+#define MIN_EISA_ADDR   0x1c88
+#define MAX_EISA_ADDR   0xfc88
+#define BSY_ASSERTED      0x80
+#define DRQ_ASSERTED      0x08
+#define ABSY_ASSERTED     0x01
+#define IRQ_ASSERTED      0x02
+#define READ_CONFIG_PIO   0xf0
+#define SET_CONFIG_PIO    0xf1
+#define SEND_CP_PIO       0xf2
+#define RECEIVE_SP_PIO    0xf3
+#define TRUNCATE_XFR_PIO  0xf4
+#define RESET_PIO         0xf9
+#define READ_CONFIG_DMA   0xfd
+#define SET_CONFIG_DMA    0xfe
+#define SEND_CP_DMA       0xff
+#define ASOK              0x00
+#define ASST              0x01
+
+#define YESNO(a) ((a) ? 'y' : 'n')
+#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
+
+/* "EATA", in Big Endian format */
+#define EATA_SIG_BE 0x45415441
+
+/* Number of valid bytes in the board config structure for EATA 2.0x */
+#define EATA_2_0A_SIZE 28
+#define EATA_2_0B_SIZE 30
+#define EATA_2_0C_SIZE 34
+
+/* Board info structure */
+struct eata_info {
+	u_int32_t data_len;	/* Number of valid bytes after this field */
+	u_int32_t sign;		/* ASCII "EATA" signature */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unchar version	: 4,
+	       		: 4;
+	unchar haaval	: 1,
+	       ata	: 1,
+	       drqvld	: 1,
+	       dmasup	: 1,
+	       morsup	: 1,
+	       trnxfr	: 1,
+	       tarsup	: 1,
+	       ocsena	: 1;
+#else
+	unchar		: 4,	/* unused low nibble */
+	 	version	: 4;	/* EATA version, should be 0x1 */
+	unchar ocsena	: 1,	/* Overlap Command Support Enabled */
+	       tarsup	: 1,	/* Target Mode Supported */
+	       trnxfr	: 1,	/* Truncate Transfer Cmd NOT Necessary */
+	       morsup	: 1,	/* More Supported */
+	       dmasup	: 1,	/* DMA Supported */
+	       drqvld	: 1,	/* DRQ Index (DRQX) is valid */
+	       ata	: 1,	/* This is an ATA device */
+	       haaval	: 1;	/* Host Adapter Address Valid */
+#endif
+
+	ushort cp_pad_len;	/* Number of pad bytes after cp_len */
+	unchar host_addr[4];	/* Host Adapter SCSI ID for channels 3, 2, 1, 0 */
+	u_int32_t cp_len;	/* Number of valid bytes in cp */
+	u_int32_t sp_len;	/* Number of valid bytes in sp */
+	ushort queue_size;	/* Max number of cp that can be queued */
+	ushort unused;
+	ushort scatt_size;	/* Max number of entries in scatter/gather table */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unchar drqx	: 2,
+	       second	: 1,
+	       irq_tr	: 1,
+	       irq	: 4;
+	unchar sync;
+	unchar		: 4,
+	       res1	: 1,
+	       large_sg	: 1,
+	       forcaddr	: 1,
+	       isaena	: 1;
+	unchar max_chan	: 3,
+	       max_id	: 5;
+	unchar max_lun;
+	unchar eisa	: 1,
+	       pci	: 1,
+	       idquest	: 1,
+	       m1	: 1,
+	       		: 4;
+#else
+	unchar irq	: 4,	/* Interrupt Request assigned to this controller */
+	       irq_tr	: 1,	/* 0 for edge triggered, 1 for level triggered */
+	       second	: 1,	/* 1 if this is a secondary (not primary) controller */
+	       drqx	: 2;	/* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
+	unchar sync;		/* 1 if scsi target id 7...0 is running sync scsi */
+
+	/* Structure extension defined in EATA 2.0B */
+	unchar isaena	: 1,	/* ISA i/o addressing is disabled/enabled */
+	       forcaddr	: 1,	/* Port address has been forced */
+	       large_sg	: 1,	/* 1 if large SG lists are supported */
+	       res1	: 1,
+	       		: 4;
+	unchar max_id	: 5,	/* Max SCSI target ID number */
+	       max_chan	: 3;	/* Max SCSI channel number on this board */
+
+	/* Structure extension defined in EATA 2.0C */
+	unchar max_lun;		/* Max SCSI LUN number */
+	unchar
+			: 4,
+	       m1	: 1,	/* This is a PCI with an M1 chip installed */
+	       idquest	: 1,	/* RAIDNUM returned is questionable */
+	       pci	: 1,	/* This board is PCI */
+	       eisa	: 1;	/* This board is EISA */
+#endif
+
+	unchar raidnum;		/* Uniquely identifies this HBA in a system */
+	unchar notused;
+
+	ushort ipad[247];
+};
+
+/* Board config structure */
+struct eata_config {
+	ushort len;		/* Number of bytes following this field */
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unchar		: 4,
+	       tarena	: 1,
+	       mdpena	: 1,
+	       ocena	: 1,
+	       edis	: 1;
+#else
+	unchar edis	: 1,	/* Disable EATA interface after config command */
+	       ocena	: 1,	/* Overlapped Commands Enabled */
+	       mdpena	: 1,	/* Transfer all Modified Data Pointer Messages */
+	       tarena	: 1,	/* Target Mode Enabled for this controller */
+	       		: 4;
+#endif
+	unchar cpad[511];
+};
+
+/* Returned status packet structure */
+struct mssp {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unchar eoc	: 1,
+	       adapter_status : 7;
+#else
+	unchar adapter_status : 7,	/* State related to current command */
+	       eoc	: 1;		/* End Of Command (1 = command completed) */
+#endif
+	unchar target_status;	/* SCSI status received after data transfer */
+	unchar unused[2];
+	u_int32_t inv_res_len;	/* Number of bytes not transferred */
+	u_int32_t cpp_index;	/* Index of address set in cp */
+	char mess[12];
+};
+
+struct sg_list {
+	unsigned int address;	/* Segment Address */
+	unsigned int num_bytes;	/* Segment Length */
+};
+
+/* MailBox SCSI Command Packet */
+struct mscp {
+#if defined(__BIG_ENDIAN_BITFIELD)
+	unchar din	: 1,
+	       dout	: 1,
+	       interp	: 1,
+	       		: 1,
+		sg	: 1,
+		reqsen	:1,
+		init	: 1,
+		sreset	: 1;
+	unchar sense_len;
+	unchar unused[3];
+	unchar		: 7,
+	       fwnest	: 1;
+	unchar		: 5,
+	       hbaci	: 1,
+	       iat	: 1,
+	       phsunit	: 1;
+	unchar channel	: 3,
+	       target	: 5;
+	unchar one	: 1,
+	       dispri	: 1,
+	       luntar	: 1,
+	       lun	: 5;
+#else
+	unchar sreset	:1,	/* SCSI Bus Reset Signal should be asserted */
+	       init	:1,	/* Re-initialize controller and self test */
+	       reqsen	:1,	/* Transfer Request Sense Data to addr using DMA */
+	       sg	:1,	/* Use Scatter/Gather */
+	       		:1,
+	       interp	:1,	/* The controller interprets cp, not the target */
+	       dout	:1,	/* Direction of Transfer is Out (Host to Target) */
+	       din	:1;	/* Direction of Transfer is In (Target to Host) */
+	unchar sense_len;	/* Request Sense Length */
+	unchar unused[3];
+	unchar fwnest	: 1,	/* Send command to a component of an Array Group */
+			: 7;
+	unchar phsunit	: 1,	/* Send to Target Physical Unit (bypass RAID) */
+	       iat	: 1,	/* Inhibit Address Translation */
+	       hbaci	: 1,	/* Inhibit HBA Caching for this command */
+	       		: 5;
+	unchar target	: 5,	/* SCSI target ID */
+	       channel	: 3;	/* SCSI channel number */
+	unchar lun	: 5,	/* SCSI logical unit number */
+	       luntar	: 1,	/* This cp is for Target (not LUN) */
+	       dispri	: 1,	/* Disconnect Privilege granted */
+	       one	: 1;	/* 1 */
+#endif
+
+	unchar mess[3];		/* Massage to/from Target */
+	unchar cdb[12];		/* Command Descriptor Block */
+	u_int32_t data_len;	/* If sg=0 Data Length, if sg=1 sglist length */
+	u_int32_t cpp_index;	/* Index of address to be returned in sp */
+	u_int32_t data_address;	/* If sg=0 Data Address, if sg=1 sglist address */
+	u_int32_t sp_dma_addr;	/* Address where sp is DMA'ed when cp completes */
+	u_int32_t sense_addr;	/* Address where Sense Data is DMA'ed on error */
+
+	/* Additional fields begin here. */
+	struct scsi_cmnd *SCpnt;
+
+	/* All the cp structure is zero filled by queuecommand except the
+	   following CP_TAIL_SIZE bytes, initialized by detect */
+	dma_addr_t cp_dma_addr;	/* dma handle for this cp structure */
+	struct sg_list *sglist;	/* pointer to the allocated SG list */
+};
+
+#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
+
+struct hostdata {
+	struct mscp cp[MAX_MAILBOXES];	/* Mailboxes for this board */
+	unsigned int cp_stat[MAX_MAILBOXES];	/* FREE, IN_USE, LOCKED, IN_RESET */
+	unsigned int last_cp_used;	/* Index of last mailbox used */
+	unsigned int iocount;	/* Total i/o done for this board */
+	int board_number;	/* Number of this board */
+	char board_name[16];	/* Name of this board */
+	int in_reset;		/* True if board is doing a reset */
+	int target_to[MAX_TARGET][MAX_CHANNEL];	/* N. of timeout errors on target */
+	int target_redo[MAX_TARGET][MAX_CHANNEL];	/* If 1 redo i/o on target */
+	unsigned int retries;	/* Number of internal retries */
+	unsigned long last_retried_pid;	/* Pid of last retried command */
+	unsigned char subversion;	/* Bus type, either ISA or EISA/PCI */
+	unsigned char protocol_rev;	/* EATA 2.0 rev., 'A' or 'B' or 'C' */
+	unsigned char is_pci;	/* 1 is bus type is PCI */
+	struct pci_dev *pdev;	/* pdev for PCI bus, NULL otherwise */
+	struct mssp *sp_cpu_addr;	/* cpu addr for DMA buffer sp */
+	dma_addr_t sp_dma_addr;	/* dma handle for DMA buffer sp */
+	struct mssp sp;		/* Local copy of sp buffer */
+};
+
+static struct Scsi_Host *sh[MAX_BOARDS];
+static const char *driver_name = "EATA";
+static char sha[MAX_BOARDS];
+static DEFINE_SPINLOCK(driver_lock);
+
+/* Initialize num_boards so that ihdlr can work while detect is in progress */
+static unsigned int num_boards = MAX_BOARDS;
+
+static unsigned long io_port[] = {
+
+	/* Space for MAX_INT_PARAM ports usable while loading as a module */
+	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
+	SKIP, SKIP,
+
+	/* First ISA */
+	0x1f0,
+
+	/* Space for MAX_PCI ports possibly reported by PCI_BIOS */
+	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
+	SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP, SKIP,
+
+	/* MAX_EISA ports */
+	0x1c88, 0x2c88, 0x3c88, 0x4c88, 0x5c88, 0x6c88, 0x7c88, 0x8c88,
+	0x9c88, 0xac88, 0xbc88, 0xcc88, 0xdc88, 0xec88, 0xfc88,
+
+	/* Other (MAX_ISA - 1) ports */
+	0x170, 0x230, 0x330,
+
+	/* End of list */
+	0x0
+};
+
+/* Device is Big Endian */
+#define H2DEV(x)   cpu_to_be32(x)
+#define DEV2H(x)   be32_to_cpu(x)
+#define H2DEV16(x) cpu_to_be16(x)
+#define DEV2H16(x) be16_to_cpu(x)
+
+/* But transfer orientation from the 16 bit data register is Little Endian */
+#define REG2H(x)   le16_to_cpu(x)
+
+static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static void flush_dev(struct scsi_device *, unsigned long, struct hostdata *,
+		      unsigned int);
+static int do_trace = 0;
+static int setup_done = 0;
+static int link_statistics;
+static int ext_tran = 0;
+static int rev_scan = 1;
+
+#if defined(CONFIG_SCSI_EATA_TAGGED_QUEUE)
+static int tag_mode = TAG_SIMPLE;
+#else
+static int tag_mode = TAG_DISABLED;
+#endif
+
+#if defined(CONFIG_SCSI_EATA_LINKED_COMMANDS)
+static int linked_comm = 1;
+#else
+static int linked_comm = 0;
+#endif
+
+#if defined(CONFIG_SCSI_EATA_MAX_TAGS)
+static int max_queue_depth = CONFIG_SCSI_EATA_MAX_TAGS;
+#else
+static int max_queue_depth = MAX_CMD_PER_LUN;
+#endif
+
+#if defined(CONFIG_ISA)
+static int isa_probe = 1;
+#else
+static int isa_probe = 0;
+#endif
+
+#if defined(CONFIG_EISA)
+static int eisa_probe = 1;
+#else
+static int eisa_probe = 0;
+#endif
+
+#if defined(CONFIG_PCI)
+static int pci_probe = 1;
+#else
+static int pci_probe = 0;
+#endif
+
+#define MAX_INT_PARAM 10
+#define MAX_BOOT_OPTIONS_SIZE 256
+static char boot_options[MAX_BOOT_OPTIONS_SIZE];
+
+#if defined(MODULE)
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+module_param_string(eata, boot_options, MAX_BOOT_OPTIONS_SIZE, 0);
+MODULE_PARM_DESC(eata, " equivalent to the \"eata=...\" kernel boot option."
+		 "            Example: modprobe eata \"eata=0x7410,0x230,lc:y,tm:0,mq:4,ep:n\"");
+MODULE_AUTHOR("Dario Ballabio");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("EATA/DMA SCSI Driver");
+
+#endif
+
+static int eata2x_slave_configure(struct scsi_device *dev)
+{
+	int tqd, utqd;
+	char *tag_suffix, *link_suffix;
+	struct Scsi_Host *shost = dev->host;
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+
+	utqd = MAX_CMD_PER_LUN;
+	tqd = max_queue_depth;
+
+	if (TLDEV(dev->type) && dev->tagged_supported) {
+		if (tag_mode == TAG_SIMPLE) {
+			scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
+			tag_suffix = ", simple tags";
+		} else if (tag_mode == TAG_ORDERED) {
+			scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);
+			tag_suffix = ", ordered tags";
+		} else {
+			scsi_adjust_queue_depth(dev, 0, tqd);
+			tag_suffix = ", no tags";
+		}
+	} else if (TLDEV(dev->type) && linked_comm) {
+		scsi_adjust_queue_depth(dev, 0, tqd);
+		tag_suffix = ", untagged";
+	} else {
+		scsi_adjust_queue_depth(dev, 0, utqd);
+		tag_suffix = "";
+	}
+
+	if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2)
+		link_suffix = ", sorted";
+	else if (TLDEV(dev->type))
+		link_suffix = ", unsorted";
+	else
+		link_suffix = "";
+
+	printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
+	       ha->board_name, shost->host_no, dev->channel, dev->id, dev->lun,
+	       dev->queue_depth, link_suffix, tag_suffix);
+
+	return 0;
+}
+
+static int wait_on_busy(unsigned long iobase, unsigned int loop)
+{
+	while (inb(iobase + REG_AUX_STATUS) & ABSY_ASSERTED) {
+		udelay(1L);
+		if (--loop == 0)
+			return 1;
+	}
+	return 0;
+}
+
+static int do_dma(unsigned long iobase, unsigned long addr, unchar cmd)
+{
+	unsigned char *byaddr;
+	unsigned long devaddr;
+
+	if (wait_on_busy(iobase, (addr ? MAXLOOP * 100 : MAXLOOP)))
+		return 1;
+
+	if (addr) {
+		devaddr = H2DEV(addr);
+		byaddr = (unsigned char *)&devaddr;
+		outb(byaddr[3], iobase + REG_LOW);
+		outb(byaddr[2], iobase + REG_LM);
+		outb(byaddr[1], iobase + REG_MID);
+		outb(byaddr[0], iobase + REG_MSB);
+	}
+
+	outb(cmd, iobase + REG_CMD);
+	return 0;
+}
+
+static int read_pio(unsigned long iobase, ushort * start, ushort * end)
+{
+	unsigned int loop = MAXLOOP;
+	ushort *p;
+
+	for (p = start; p <= end; p++) {
+		while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED)) {
+			udelay(1L);
+			if (--loop == 0)
+				return 1;
+		}
+		loop = MAXLOOP;
+		*p = REG2H(inw(iobase));
+	}
+
+	return 0;
+}
+
+static struct pci_dev *get_pci_dev(unsigned long port_base)
+{
+#if defined(CONFIG_PCI)
+	unsigned int addr;
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+		addr = pci_resource_start(dev, 0);
+
+#if defined(DEBUG_PCI_DETECT)
+		printk("%s: get_pci_dev, bus %d, devfn 0x%x, addr 0x%x.\n",
+		       driver_name, dev->bus->number, dev->devfn, addr);
+#endif
+
+		/* we are in so much trouble for a pci hotplug system with this driver
+		 * anyway, so doing this at least lets people unload the driver and not
+		 * cause memory problems, but in general this is a bad thing to do (this
+		 * driver needs to be converted to the proper PCI api someday... */
+		pci_dev_put(dev);
+		if (addr + PCI_BASE_ADDRESS_0 == port_base)
+			return dev;
+	}
+#endif				/* end CONFIG_PCI */
+	return NULL;
+}
+
+static void enable_pci_ports(void)
+{
+#if defined(CONFIG_PCI)
+	struct pci_dev *dev = NULL;
+
+	while ((dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev))) {
+#if defined(DEBUG_PCI_DETECT)
+		printk("%s: enable_pci_ports, bus %d, devfn 0x%x.\n",
+		       driver_name, dev->bus->number, dev->devfn);
+#endif
+
+		if (pci_enable_device(dev))
+			printk
+			    ("%s: warning, pci_enable_device failed, bus %d devfn 0x%x.\n",
+			     driver_name, dev->bus->number, dev->devfn);
+	}
+
+#endif				/* end CONFIG_PCI */
+}
+
+static int port_detect(unsigned long port_base, unsigned int j,
+		struct scsi_host_template *tpnt)
+{
+	unsigned char irq, dma_channel, subversion, i, is_pci = 0;
+	unsigned char protocol_rev;
+	struct eata_info info;
+	char *bus_type, dma_name[16];
+	struct pci_dev *pdev;
+	/* Allowed DMA channels for ISA (0 indicates reserved) */
+	unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
+	struct Scsi_Host *shost;
+	struct hostdata *ha;
+	char name[16];
+
+	sprintf(name, "%s%d", driver_name, j);
+
+	if (!request_region(port_base, REGION_SIZE, driver_name)) {
+#if defined(DEBUG_DETECT)
+		printk("%s: address 0x%03lx in use, skipping probe.\n", name,
+		       port_base);
+#endif
+		goto fail;
+	}
+
+	spin_lock_irq(&driver_lock);
+
+	if (do_dma(port_base, 0, READ_CONFIG_PIO)) {
+#if defined(DEBUG_DETECT)
+		printk("%s: detect, do_dma failed at 0x%03lx.\n", name,
+		       port_base);
+#endif
+		goto freelock;
+	}
+
+	/* Read the info structure */
+	if (read_pio(port_base, (ushort *) & info, (ushort *) & info.ipad[0])) {
+#if defined(DEBUG_DETECT)
+		printk("%s: detect, read_pio failed at 0x%03lx.\n", name,
+		       port_base);
+#endif
+		goto freelock;
+	}
+
+	info.data_len = DEV2H(info.data_len);
+	info.sign = DEV2H(info.sign);
+	info.cp_pad_len = DEV2H16(info.cp_pad_len);
+	info.cp_len = DEV2H(info.cp_len);
+	info.sp_len = DEV2H(info.sp_len);
+	info.scatt_size = DEV2H16(info.scatt_size);
+	info.queue_size = DEV2H16(info.queue_size);
+
+	/* Check the controller "EATA" signature */
+	if (info.sign != EATA_SIG_BE) {
+#if defined(DEBUG_DETECT)
+		printk("%s: signature 0x%04x discarded.\n", name, info.sign);
+#endif
+		goto freelock;
+	}
+
+	if (info.data_len < EATA_2_0A_SIZE) {
+		printk
+		    ("%s: config structure size (%d bytes) too short, detaching.\n",
+		     name, info.data_len);
+		goto freelock;
+	} else if (info.data_len == EATA_2_0A_SIZE)
+		protocol_rev = 'A';
+	else if (info.data_len == EATA_2_0B_SIZE)
+		protocol_rev = 'B';
+	else
+		protocol_rev = 'C';
+
+	if (protocol_rev != 'A' && info.forcaddr) {
+		printk("%s: warning, port address has been forced.\n", name);
+		bus_type = "PCI";
+		is_pci = 1;
+		subversion = ESA;
+	} else if (port_base > MAX_EISA_ADDR
+		   || (protocol_rev == 'C' && info.pci)) {
+		bus_type = "PCI";
+		is_pci = 1;
+		subversion = ESA;
+	} else if (port_base >= MIN_EISA_ADDR
+		   || (protocol_rev == 'C' && info.eisa)) {
+		bus_type = "EISA";
+		subversion = ESA;
+	} else if (protocol_rev == 'C' && !info.eisa && !info.pci) {
+		bus_type = "ISA";
+		subversion = ISA;
+	} else if (port_base > MAX_ISA_ADDR) {
+		bus_type = "PCI";
+		is_pci = 1;
+		subversion = ESA;
+	} else {
+		bus_type = "ISA";
+		subversion = ISA;
+	}
+
+	if (!info.haaval || info.ata) {
+		printk
+		    ("%s: address 0x%03lx, unusable %s board (%d%d), detaching.\n",
+		     name, port_base, bus_type, info.haaval, info.ata);
+		goto freelock;
+	}
+
+	if (info.drqvld) {
+		if (subversion == ESA)
+			printk("%s: warning, weird %s board using DMA.\n", name,
+			       bus_type);
+
+		subversion = ISA;
+		dma_channel = dma_channel_table[3 - info.drqx];
+	} else {
+		if (subversion == ISA)
+			printk("%s: warning, weird %s board not using DMA.\n",
+			       name, bus_type);
+
+		subversion = ESA;
+		dma_channel = NO_DMA;
+	}
+
+	if (!info.dmasup)
+		printk("%s: warning, DMA protocol support not asserted.\n",
+		       name);
+
+	irq = info.irq;
+
+	if (subversion == ESA && !info.irq_tr)
+		printk
+		    ("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
+		     name, irq);
+
+	if (is_pci) {
+		pdev = get_pci_dev(port_base);
+		if (!pdev)
+			printk
+			    ("%s: warning, failed to get pci_dev structure.\n",
+			     name);
+	} else
+		pdev = NULL;
+
+	if (pdev && (irq != pdev->irq)) {
+		printk("%s: IRQ %u mapped to IO-APIC IRQ %u.\n", name, irq,
+		       pdev->irq);
+		irq = pdev->irq;
+	}
+
+	/* Board detected, allocate its IRQ */
+	if (request_irq(irq, do_interrupt_handler,
+			SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+			driver_name, (void *)&sha[j])) {
+		printk("%s: unable to allocate IRQ %u, detaching.\n", name,
+		       irq);
+		goto freelock;
+	}
+
+	if (subversion == ISA && request_dma(dma_channel, driver_name)) {
+		printk("%s: unable to allocate DMA channel %u, detaching.\n",
+		       name, dma_channel);
+		goto freeirq;
+	}
+#if defined(FORCE_CONFIG)
+	{
+		struct eata_config *cf;
+		dma_addr_t cf_dma_addr;
+
+		cf = pci_alloc_consistent(pdev, sizeof(struct eata_config),
+					  &cf_dma_addr);
+
+		if (!cf) {
+			printk
+			    ("%s: config, pci_alloc_consistent failed, detaching.\n",
+			     name);
+			goto freedma;
+		}
+
+		/* Set board configuration */
+		memset((char *)cf, 0, sizeof(struct eata_config));
+		cf->len = (ushort) H2DEV16((ushort) 510);
+		cf->ocena = 1;
+
+		if (do_dma(port_base, cf_dma_addr, SET_CONFIG_DMA)) {
+			printk
+			    ("%s: busy timeout sending configuration, detaching.\n",
+			     name);
+			pci_free_consistent(pdev, sizeof(struct eata_config),
+					    cf, cf_dma_addr);
+			goto freedma;
+		}
+
+	}
+#endif
+
+	spin_unlock_irq(&driver_lock);
+	sh[j] = shost = scsi_register(tpnt, sizeof(struct hostdata));
+	spin_lock_irq(&driver_lock);
+
+	if (shost == NULL) {
+		printk("%s: unable to register host, detaching.\n", name);
+		goto freedma;
+	}
+
+	shost->io_port = port_base;
+	shost->unique_id = port_base;
+	shost->n_io_port = REGION_SIZE;
+	shost->dma_channel = dma_channel;
+	shost->irq = irq;
+	shost->sg_tablesize = (ushort) info.scatt_size;
+	shost->this_id = (ushort) info.host_addr[3];
+	shost->can_queue = (ushort) info.queue_size;
+	shost->cmd_per_lun = MAX_CMD_PER_LUN;
+
+	ha = (struct hostdata *)shost->hostdata;
+	
+	memset(ha, 0, sizeof(struct hostdata));
+	ha->subversion = subversion;
+	ha->protocol_rev = protocol_rev;
+	ha->is_pci = is_pci;
+	ha->pdev = pdev;
+	ha->board_number = j;
+
+	if (ha->subversion == ESA)
+		shost->unchecked_isa_dma = 0;
+	else {
+		unsigned long flags;
+		shost->unchecked_isa_dma = 1;
+
+		flags = claim_dma_lock();
+		disable_dma(dma_channel);
+		clear_dma_ff(dma_channel);
+		set_dma_mode(dma_channel, DMA_MODE_CASCADE);
+		enable_dma(dma_channel);
+		release_dma_lock(flags);
+
+	}
+
+	strcpy(ha->board_name, name);
+
+	/* DPT PM2012 does not allow to detect sg_tablesize correctly */
+	if (shost->sg_tablesize > MAX_SGLIST || shost->sg_tablesize < 2) {
+		printk("%s: detect, wrong n. of SG lists %d, fixed.\n",
+		       ha->board_name, shost->sg_tablesize);
+		shost->sg_tablesize = MAX_SGLIST;
+	}
+
+	/* DPT PM2012 does not allow to detect can_queue correctly */
+	if (shost->can_queue > MAX_MAILBOXES || shost->can_queue < 2) {
+		printk("%s: detect, wrong n. of mbox %d, fixed.\n",
+		       ha->board_name, shost->can_queue);
+		shost->can_queue = MAX_MAILBOXES;
+	}
+
+	if (protocol_rev != 'A') {
+		if (info.max_chan > 0 && info.max_chan < MAX_CHANNEL)
+			shost->max_channel = info.max_chan;
+
+		if (info.max_id > 7 && info.max_id < MAX_TARGET)
+			shost->max_id = info.max_id + 1;
+
+		if (info.large_sg && shost->sg_tablesize == MAX_SGLIST)
+			shost->sg_tablesize = MAX_LARGE_SGLIST;
+	}
+
+	if (protocol_rev == 'C') {
+		if (info.max_lun > 7 && info.max_lun < MAX_LUN)
+			shost->max_lun = info.max_lun + 1;
+	}
+
+	if (dma_channel == NO_DMA)
+		sprintf(dma_name, "%s", "BMST");
+	else
+		sprintf(dma_name, "DMA %u", dma_channel);
+
+	spin_unlock_irq(&driver_lock);
+
+	for (i = 0; i < shost->can_queue; i++)
+		ha->cp[i].cp_dma_addr = pci_map_single(ha->pdev,
+							  &ha->cp[i],
+							  sizeof(struct mscp),
+							  PCI_DMA_BIDIRECTIONAL);
+
+	for (i = 0; i < shost->can_queue; i++) {
+		size_t sz = shost->sg_tablesize *sizeof(struct sg_list);
+		unsigned int gfp_mask = (shost->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC;
+		ha->cp[i].sglist = kmalloc(sz, gfp_mask);
+		if (!ha->cp[i].sglist) {
+			printk
+			    ("%s: kmalloc SGlist failed, mbox %d, detaching.\n",
+			     ha->board_name, i);
+			goto release;
+		}
+	}
+
+	if (!(ha->sp_cpu_addr = pci_alloc_consistent(ha->pdev,
+							sizeof(struct mssp),
+							&ha->sp_dma_addr))) {
+		printk("%s: pci_alloc_consistent failed, detaching.\n", ha->board_name);
+		goto release;
+	}
+
+	if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
+		max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
+
+	if (max_queue_depth < MAX_CMD_PER_LUN)
+		max_queue_depth = MAX_CMD_PER_LUN;
+
+	if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE)
+		tag_mode = TAG_ORDERED;
+
+	if (j == 0) {
+		printk
+		    ("EATA/DMA 2.0x: Copyright (C) 1994-2003 Dario Ballabio.\n");
+		printk
+		    ("%s config options -> tm:%d, lc:%c, mq:%d, rs:%c, et:%c, "
+		     "ip:%c, ep:%c, pp:%c.\n", driver_name, tag_mode,
+		     YESNO(linked_comm), max_queue_depth, YESNO(rev_scan),
+		     YESNO(ext_tran), YESNO(isa_probe), YESNO(eisa_probe),
+		     YESNO(pci_probe));
+	}
+
+	printk("%s: 2.0%c, %s 0x%03lx, IRQ %u, %s, SG %d, MB %d.\n",
+	       ha->board_name, ha->protocol_rev, bus_type,
+	       (unsigned long)shost->io_port, shost->irq, dma_name,
+	       shost->sg_tablesize, shost->can_queue);
+
+	if (shost->max_id > 8 || shost->max_lun > 8)
+		printk
+		    ("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+		     ha->board_name, shost->max_id, shost->max_lun);
+
+	for (i = 0; i <= shost->max_channel; i++)
+		printk("%s: SCSI channel %u enabled, host target ID %d.\n",
+		       ha->board_name, i, info.host_addr[3 - i]);
+
+#if defined(DEBUG_DETECT)
+	printk("%s: Vers. 0x%x, ocs %u, tar %u, trnxfr %u, more %u, SYNC 0x%x, "
+	       "sec. %u, infol %d, cpl %d spl %d.\n", name, info.version,
+	       info.ocsena, info.tarsup, info.trnxfr, info.morsup, info.sync,
+	       info.second, info.data_len, info.cp_len, info.sp_len);
+
+	if (protocol_rev == 'B' || protocol_rev == 'C')
+		printk("%s: isaena %u, forcaddr %u, max_id %u, max_chan %u, "
+		       "large_sg %u, res1 %u.\n", name, info.isaena,
+		       info.forcaddr, info.max_id, info.max_chan, info.large_sg,
+		       info.res1);
+
+	if (protocol_rev == 'C')
+		printk("%s: max_lun %u, m1 %u, idquest %u, pci %u, eisa %u, "
+		       "raidnum %u.\n", name, info.max_lun, info.m1,
+		       info.idquest, info.pci, info.eisa, info.raidnum);
+#endif
+
+	if (ha->pdev) {
+		pci_set_master(ha->pdev);
+		if (pci_set_dma_mask(ha->pdev, 0xffffffff))
+			printk("%s: warning, pci_set_dma_mask failed.\n",
+			       ha->board_name);
+	}
+
+	return 1;
+
+      freedma:
+	if (subversion == ISA)
+		free_dma(dma_channel);
+      freeirq:
+	free_irq(irq, &sha[j]);
+      freelock:
+	spin_unlock_irq(&driver_lock);
+	release_region(port_base, REGION_SIZE);
+      fail:
+	return 0;
+
+      release:
+	eata2x_release(shost);
+	return 0;
+}
+
+static void internal_setup(char *str, int *ints)
+{
+	int i, argc = ints[0];
+	char *cur = str, *pc;
+
+	if (argc > 0) {
+		if (argc > MAX_INT_PARAM)
+			argc = MAX_INT_PARAM;
+
+		for (i = 0; i < argc; i++)
+			io_port[i] = ints[i + 1];
+
+		io_port[i] = 0;
+		setup_done = 1;
+	}
+
+	while (cur && (pc = strchr(cur, ':'))) {
+		int val = 0, c = *++pc;
+
+		if (c == 'n' || c == 'N')
+			val = 0;
+		else if (c == 'y' || c == 'Y')
+			val = 1;
+		else
+			val = (int)simple_strtoul(pc, NULL, 0);
+
+		if (!strncmp(cur, "lc:", 3))
+			linked_comm = val;
+		else if (!strncmp(cur, "tm:", 3))
+			tag_mode = val;
+		else if (!strncmp(cur, "tc:", 3))
+			tag_mode = val;
+		else if (!strncmp(cur, "mq:", 3))
+			max_queue_depth = val;
+		else if (!strncmp(cur, "ls:", 3))
+			link_statistics = val;
+		else if (!strncmp(cur, "et:", 3))
+			ext_tran = val;
+		else if (!strncmp(cur, "rs:", 3))
+			rev_scan = val;
+		else if (!strncmp(cur, "ip:", 3))
+			isa_probe = val;
+		else if (!strncmp(cur, "ep:", 3))
+			eisa_probe = val;
+		else if (!strncmp(cur, "pp:", 3))
+			pci_probe = val;
+
+		if ((cur = strchr(cur, ',')))
+			++cur;
+	}
+
+	return;
+}
+
+static int option_setup(char *str)
+{
+	int ints[MAX_INT_PARAM];
+	char *cur = str;
+	int i = 1;
+
+	while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+		ints[i++] = simple_strtoul(cur, NULL, 0);
+
+		if ((cur = strchr(cur, ',')) != NULL)
+			cur++;
+	}
+
+	ints[0] = i - 1;
+	internal_setup(cur, ints);
+	return 1;
+}
+
+static void add_pci_ports(void)
+{
+#if defined(CONFIG_PCI)
+	unsigned int addr, k;
+	struct pci_dev *dev = NULL;
+
+	for (k = 0; k < MAX_PCI; k++) {
+
+		if (!(dev = pci_get_class(PCI_CLASS_STORAGE_SCSI << 8, dev)))
+			break;
+
+		if (pci_enable_device(dev)) {
+#if defined(DEBUG_PCI_DETECT)
+			printk
+			    ("%s: detect, bus %d, devfn 0x%x, pci_enable_device failed.\n",
+			     driver_name, dev->bus->number, dev->devfn);
+#endif
+
+			continue;
+		}
+
+		addr = pci_resource_start(dev, 0);
+
+#if defined(DEBUG_PCI_DETECT)
+		printk("%s: detect, seq. %d, bus %d, devfn 0x%x, addr 0x%x.\n",
+		       driver_name, k, dev->bus->number, dev->devfn, addr);
+#endif
+
+		/* Order addresses according to rev_scan value */
+		io_port[MAX_INT_PARAM + (rev_scan ? (MAX_PCI - k) : (1 + k))] =
+		    addr + PCI_BASE_ADDRESS_0;
+	}
+
+	pci_dev_put(dev);
+#endif				/* end CONFIG_PCI */
+}
+
+static int eata2x_detect(struct scsi_host_template *tpnt)
+{
+	unsigned int j = 0, k;
+
+	tpnt->proc_name = "eata2x";
+
+	if (strlen(boot_options))
+		option_setup(boot_options);
+
+#if defined(MODULE)
+	/* io_port could have been modified when loading as a module */
+	if (io_port[0] != SKIP) {
+		setup_done = 1;
+		io_port[MAX_INT_PARAM] = 0;
+	}
+#endif
+
+	for (k = MAX_INT_PARAM; io_port[k]; k++)
+		if (io_port[k] == SKIP)
+			continue;
+		else if (io_port[k] <= MAX_ISA_ADDR) {
+			if (!isa_probe)
+				io_port[k] = SKIP;
+		} else if (io_port[k] >= MIN_EISA_ADDR
+			   && io_port[k] <= MAX_EISA_ADDR) {
+			if (!eisa_probe)
+				io_port[k] = SKIP;
+		}
+
+	if (pci_probe) {
+		if (!setup_done)
+			add_pci_ports();
+		else
+			enable_pci_ports();
+	}
+
+	for (k = 0; io_port[k]; k++) {
+
+		if (io_port[k] == SKIP)
+			continue;
+
+		if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt))
+			j++;
+	}
+
+	num_boards = j;
+	return j;
+}
+
+static void map_dma(unsigned int i, struct hostdata *ha)
+{
+	unsigned int k, count, pci_dir;
+	struct scatterlist *sgpnt;
+	struct mscp *cpp;
+	struct scsi_cmnd *SCpnt;
+
+	cpp = &ha->cp[i];
+	SCpnt = cpp->SCpnt;
+	pci_dir = SCpnt->sc_data_direction;
+
+	if (SCpnt->sense_buffer)
+		cpp->sense_addr =
+		    H2DEV(pci_map_single(ha->pdev, SCpnt->sense_buffer,
+			   sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+	cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+	if (!SCpnt->use_sg) {
+
+		/* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
+		if (!SCpnt->request_bufflen)
+			pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+		if (SCpnt->request_buffer)
+			cpp->data_address = H2DEV(pci_map_single(ha->pdev,
+								 SCpnt->
+								 request_buffer,
+								 SCpnt->
+								 request_bufflen,
+								 pci_dir));
+
+		cpp->data_len = H2DEV(SCpnt->request_bufflen);
+		return;
+	}
+
+	sgpnt = (struct scatterlist *)SCpnt->request_buffer;
+	count = pci_map_sg(ha->pdev, sgpnt, SCpnt->use_sg, pci_dir);
+
+	for (k = 0; k < count; k++) {
+		cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+		cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
+	}
+
+	cpp->sg = 1;
+	cpp->data_address = H2DEV(pci_map_single(ha->pdev, cpp->sglist,
+						 SCpnt->use_sg *
+						 sizeof(struct sg_list),
+						 pci_dir));
+	cpp->data_len = H2DEV((SCpnt->use_sg * sizeof(struct sg_list)));
+}
+
+static void unmap_dma(unsigned int i, struct hostdata *ha)
+{
+	unsigned int pci_dir;
+	struct mscp *cpp;
+	struct scsi_cmnd *SCpnt;
+
+	cpp = &ha->cp[i];
+	SCpnt = cpp->SCpnt;
+	pci_dir = SCpnt->sc_data_direction;
+
+	if (DEV2H(cpp->sense_addr))
+		pci_unmap_single(ha->pdev, DEV2H(cpp->sense_addr),
+				 DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+	if (SCpnt->use_sg)
+		pci_unmap_sg(ha->pdev, SCpnt->request_buffer, SCpnt->use_sg,
+			     pci_dir);
+
+	if (!DEV2H(cpp->data_len))
+		pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+	if (DEV2H(cpp->data_address))
+		pci_unmap_single(ha->pdev, DEV2H(cpp->data_address),
+				 DEV2H(cpp->data_len), pci_dir);
+}
+
+static void sync_dma(unsigned int i, struct hostdata *ha)
+{
+	unsigned int pci_dir;
+	struct mscp *cpp;
+	struct scsi_cmnd *SCpnt;
+
+	cpp = &ha->cp[i];
+	SCpnt = cpp->SCpnt;
+	pci_dir = SCpnt->sc_data_direction;
+
+	if (DEV2H(cpp->sense_addr))
+		pci_dma_sync_single_for_cpu(ha->pdev, DEV2H(cpp->sense_addr),
+					    DEV2H(cpp->sense_len),
+					    PCI_DMA_FROMDEVICE);
+
+	if (SCpnt->use_sg)
+		pci_dma_sync_sg_for_cpu(ha->pdev, SCpnt->request_buffer,
+					SCpnt->use_sg, pci_dir);
+
+	if (!DEV2H(cpp->data_len))
+		pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+	if (DEV2H(cpp->data_address))
+		pci_dma_sync_single_for_cpu(ha->pdev,
+					    DEV2H(cpp->data_address),
+					    DEV2H(cpp->data_len), pci_dir);
+}
+
+static void scsi_to_dev_dir(unsigned int i, struct hostdata *ha)
+{
+	unsigned int k;
+
+	static const unsigned char data_out_cmds[] = {
+		0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
+		0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
+		0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
+	};
+
+	static const unsigned char data_none_cmds[] = {
+		0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
+		0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
+		0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
+	};
+
+	struct mscp *cpp;
+	struct scsi_cmnd *SCpnt;
+
+	cpp = &ha->cp[i];
+	SCpnt = cpp->SCpnt;
+
+	if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
+		cpp->din = 1;
+		cpp->dout = 0;
+		return;
+	} else if (SCpnt->sc_data_direction == DMA_TO_DEVICE) {
+		cpp->din = 0;
+		cpp->dout = 1;
+		return;
+	} else if (SCpnt->sc_data_direction == DMA_NONE) {
+		cpp->din = 0;
+		cpp->dout = 0;
+		return;
+	}
+
+	if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL)
+		panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n",
+				ha->board_name);
+
+	for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+		if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+			cpp->dout = 1;
+			break;
+		}
+
+	if ((cpp->din = !cpp->dout))
+		for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+			if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+				cpp->din = 0;
+				break;
+			}
+
+}
+
+static int eata2x_queuecommand(struct scsi_cmnd *SCpnt,
+			       void (*done) (struct scsi_cmnd *))
+{
+	struct Scsi_Host *shost = SCpnt->device->host;
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+	unsigned int i, k;
+	struct mscp *cpp;
+
+	if (SCpnt->host_scribble)
+		panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+		      ha->board_name, SCpnt->pid, SCpnt);
+
+	/* i is the mailbox number, look for the first free mailbox
+	   starting from last_cp_used */
+	i = ha->last_cp_used + 1;
+
+	for (k = 0; k < shost->can_queue; k++, i++) {
+		if (i >= shost->can_queue)
+			i = 0;
+		if (ha->cp_stat[i] == FREE) {
+			ha->last_cp_used = i;
+			break;
+		}
+	}
+
+	if (k == shost->can_queue) {
+		printk("%s: qcomm, no free mailbox.\n", ha->board_name);
+		return 1;
+	}
+
+	/* Set pointer to control packet structure */
+	cpp = &ha->cp[i];
+
+	memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
+
+	/* Set pointer to status packet structure, Big Endian format */
+	cpp->sp_dma_addr = H2DEV(ha->sp_dma_addr);
+
+	SCpnt->scsi_done = done;
+	cpp->cpp_index = i;
+	SCpnt->host_scribble = (unsigned char *)&cpp->cpp_index;
+
+	if (do_trace)
+		printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
+		       ha->board_name, i, SCpnt->device->channel, SCpnt->device->id,
+		       SCpnt->device->lun, SCpnt->pid);
+
+	cpp->reqsen = 1;
+	cpp->dispri = 1;
+#if 0
+	if (SCpnt->device->type == TYPE_TAPE)
+		cpp->hbaci = 1;
+#endif
+	cpp->one = 1;
+	cpp->channel = SCpnt->device->channel;
+	cpp->target = SCpnt->device->id;
+	cpp->lun = SCpnt->device->lun;
+	cpp->SCpnt = SCpnt;
+	memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+	/* Use data transfer direction SCpnt->sc_data_direction */
+	scsi_to_dev_dir(i, ha);
+
+	/* Map DMA buffers and SG list */
+	map_dma(i, ha);
+
+	if (linked_comm && SCpnt->device->queue_depth > 2
+	    && TLDEV(SCpnt->device->type)) {
+		ha->cp_stat[i] = READY;
+		flush_dev(SCpnt->device, SCpnt->request->sector, ha, 0);
+		return 0;
+	}
+
+	/* Send control packet to the board */
+	if (do_dma(shost->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
+		unmap_dma(i, ha);
+		SCpnt->host_scribble = NULL;
+		printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+		       ha->board_name, SCpnt->device->channel, SCpnt->device->id,
+		       SCpnt->device->lun, SCpnt->pid);
+		return 1;
+	}
+
+	ha->cp_stat[i] = IN_USE;
+	return 0;
+}
+
+static int eata2x_eh_abort(struct scsi_cmnd *SCarg)
+{
+	struct Scsi_Host *shost = SCarg->device->host;
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+	unsigned int i;
+
+	if (SCarg->host_scribble == NULL) {
+		printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+		       ha->board_name, SCarg->device->channel, SCarg->device->id,
+		       SCarg->device->lun, SCarg->pid);
+		return SUCCESS;
+	}
+
+	i = *(unsigned int *)SCarg->host_scribble;
+	printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+	       ha->board_name, i, SCarg->device->channel, SCarg->device->id,
+	       SCarg->device->lun, SCarg->pid);
+
+	if (i >= shost->can_queue)
+		panic("%s: abort, invalid SCarg->host_scribble.\n", ha->board_name);
+
+	if (wait_on_busy(shost->io_port, MAXLOOP)) {
+		printk("%s: abort, timeout error.\n", ha->board_name);
+		return FAILED;
+	}
+
+	if (ha->cp_stat[i] == FREE) {
+		printk("%s: abort, mbox %d is free.\n", ha->board_name, i);
+		return SUCCESS;
+	}
+
+	if (ha->cp_stat[i] == IN_USE) {
+		printk("%s: abort, mbox %d is in use.\n", ha->board_name, i);
+
+		if (SCarg != ha->cp[i].SCpnt)
+			panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+			      ha->board_name, i, SCarg, ha->cp[i].SCpnt);
+
+		if (inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED)
+			printk("%s: abort, mbox %d, interrupt pending.\n",
+			       ha->board_name, i);
+
+		if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+			unmap_dma(i, ha);
+			SCarg->host_scribble = NULL;
+			ha->cp_stat[i] = FREE;
+			printk
+			    ("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+			     ha->board_name, i, SCarg->pid);
+			return SUCCESS;
+		}
+
+		return FAILED;
+	}
+
+	if (ha->cp_stat[i] == IN_RESET) {
+		printk("%s: abort, mbox %d is in reset.\n", ha->board_name, i);
+		return FAILED;
+	}
+
+	if (ha->cp_stat[i] == LOCKED) {
+		printk("%s: abort, mbox %d is locked.\n", ha->board_name, i);
+		return SUCCESS;
+	}
+
+	if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
+		unmap_dma(i, ha);
+		SCarg->result = DID_ABORT << 16;
+		SCarg->host_scribble = NULL;
+		ha->cp_stat[i] = FREE;
+		printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+		       ha->board_name, i, SCarg->pid);
+		SCarg->scsi_done(SCarg);
+		return SUCCESS;
+	}
+
+	panic("%s: abort, mbox %d, invalid cp_stat.\n", ha->board_name, i);
+}
+
+static int eata2x_eh_host_reset(struct scsi_cmnd *SCarg)
+{
+	unsigned int i, time, k, c, limit = 0;
+	int arg_done = 0;
+	struct scsi_cmnd *SCpnt;
+	struct Scsi_Host *shost = SCarg->device->host;
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+
+	printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+	       ha->board_name, SCarg->device->channel, SCarg->device->id,
+	       SCarg->device->lun, SCarg->pid);
+
+	if (SCarg->host_scribble == NULL)
+		printk("%s: reset, pid %ld inactive.\n", ha->board_name, SCarg->pid);
+
+	if (ha->in_reset) {
+		printk("%s: reset, exit, already in reset.\n", ha->board_name);
+		return FAILED;
+	}
+
+	if (wait_on_busy(shost->io_port, MAXLOOP)) {
+		printk("%s: reset, exit, timeout error.\n", ha->board_name);
+		return FAILED;
+	}
+
+	ha->retries = 0;
+
+	for (c = 0; c <= shost->max_channel; c++)
+		for (k = 0; k < shost->max_id; k++) {
+			ha->target_redo[k][c] = 1;
+			ha->target_to[k][c] = 0;
+		}
+
+	for (i = 0; i < shost->can_queue; i++) {
+
+		if (ha->cp_stat[i] == FREE)
+			continue;
+
+		if (ha->cp_stat[i] == LOCKED) {
+			ha->cp_stat[i] = FREE;
+			printk("%s: reset, locked mbox %d forced free.\n",
+			       ha->board_name, i);
+			continue;
+		}
+
+		if (!(SCpnt = ha->cp[i].SCpnt))
+			panic("%s: reset, mbox %d, SCpnt == NULL.\n", ha->board_name, i);
+
+		if (ha->cp_stat[i] == READY || ha->cp_stat[i] == ABORTING) {
+			ha->cp_stat[i] = ABORTING;
+			printk("%s: reset, mbox %d aborting, pid %ld.\n",
+			       ha->board_name, i, SCpnt->pid);
+		}
+
+		else {
+			ha->cp_stat[i] = IN_RESET;
+			printk("%s: reset, mbox %d in reset, pid %ld.\n",
+			       ha->board_name, i, SCpnt->pid);
+		}
+
+		if (SCpnt->host_scribble == NULL)
+			panic("%s: reset, mbox %d, garbled SCpnt.\n", ha->board_name, i);
+
+		if (*(unsigned int *)SCpnt->host_scribble != i)
+			panic("%s: reset, mbox %d, index mismatch.\n", ha->board_name, i);
+
+		if (SCpnt->scsi_done == NULL)
+			panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n",
+			      ha->board_name, i);
+
+		if (SCpnt == SCarg)
+			arg_done = 1;
+	}
+
+	if (do_dma(shost->io_port, 0, RESET_PIO)) {
+		printk("%s: reset, cannot reset, timeout error.\n", ha->board_name);
+		return FAILED;
+	}
+
+	printk("%s: reset, board reset done, enabling interrupts.\n", ha->board_name);
+
+#if defined(DEBUG_RESET)
+	do_trace = 1;
+#endif
+
+	ha->in_reset = 1;
+
+	spin_unlock_irq(shost->host_lock);
+	time = jiffies;
+	while ((jiffies - time) < (10 * HZ) && limit++ < 200000)
+		udelay(100L);
+	spin_lock_irq(shost->host_lock);
+
+	printk("%s: reset, interrupts disabled, loops %d.\n", ha->board_name, limit);
+
+	for (i = 0; i < shost->can_queue; i++) {
+
+		if (ha->cp_stat[i] == IN_RESET) {
+			SCpnt = ha->cp[i].SCpnt;
+			unmap_dma(i, ha);
+			SCpnt->result = DID_RESET << 16;
+			SCpnt->host_scribble = NULL;
+
+			/* This mailbox is still waiting for its interrupt */
+			ha->cp_stat[i] = LOCKED;
+
+			printk
+			    ("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+			     ha->board_name, i, SCpnt->pid);
+		}
+
+		else if (ha->cp_stat[i] == ABORTING) {
+			SCpnt = ha->cp[i].SCpnt;
+			unmap_dma(i, ha);
+			SCpnt->result = DID_RESET << 16;
+			SCpnt->host_scribble = NULL;
+
+			/* This mailbox was never queued to the adapter */
+			ha->cp_stat[i] = FREE;
+
+			printk
+			    ("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+			     ha->board_name, i, SCpnt->pid);
+		}
+
+		else
+			/* Any other mailbox has already been set free by interrupt */
+			continue;
+
+		SCpnt->scsi_done(SCpnt);
+	}
+
+	ha->in_reset = 0;
+	do_trace = 0;
+
+	if (arg_done)
+		printk("%s: reset, exit, pid %ld done.\n", ha->board_name, SCarg->pid);
+	else
+		printk("%s: reset, exit.\n", ha->board_name);
+
+	return SUCCESS;
+}
+
+int eata2x_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+		      sector_t capacity, int *dkinfo)
+{
+	unsigned int size = capacity;
+
+	if (ext_tran || (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
+		dkinfo[0] = 255;
+		dkinfo[1] = 63;
+		dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+	}
+#if defined (DEBUG_GEOMETRY)
+	printk("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name,
+	       dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+	return 0;
+}
+
+static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
+		 unsigned int rev)
+{
+	unsigned int i, j, k, y;
+	unsigned long x;
+
+	for (i = 0; i < n - 1; i++) {
+		k = i;
+
+		for (j = k + 1; j < n; j++)
+			if (rev) {
+				if (sk[j] > sk[k])
+					k = j;
+			} else {
+				if (sk[j] < sk[k])
+					k = j;
+			}
+
+		if (k != i) {
+			x = sk[k];
+			sk[k] = sk[i];
+			sk[i] = x;
+			y = da[k];
+			da[k] = da[i];
+			da[i] = y;
+		}
+	}
+
+	return;
+}
+
+static int reorder(struct hostdata *ha, unsigned long cursec,
+		   unsigned int ihdlr, unsigned int il[], unsigned int n_ready)
+{
+	struct scsi_cmnd *SCpnt;
+	struct mscp *cpp;
+	unsigned int k, n;
+	unsigned int rev = 0, s = 1, r = 1;
+	unsigned int input_only = 1, overlap = 0;
+	unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
+	unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+	unsigned long ioseek = 0;
+
+	static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
+	static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
+	static unsigned int readysorted = 0, revcount = 0;
+	static unsigned long seeksorted = 0, seeknosort = 0;
+
+	if (link_statistics && !(++flushcount % link_statistics))
+		printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"
+		       " av %ldK as %ldK.\n", flushcount, batchcount,
+		       inputcount, ovlcount, readycount, readysorted, sortcount,
+		       revcount, seeknosort / (readycount + 1),
+		       seeksorted / (readycount + 1));
+
+	if (n_ready <= 1)
+		return 0;
+
+	for (n = 0; n < n_ready; n++) {
+		k = il[n];
+		cpp = &ha->cp[k];
+		SCpnt = cpp->SCpnt;
+
+		if (!cpp->din)
+			input_only = 0;
+
+		if (SCpnt->request->sector < minsec)
+			minsec = SCpnt->request->sector;
+		if (SCpnt->request->sector > maxsec)
+			maxsec = SCpnt->request->sector;
+
+		sl[n] = SCpnt->request->sector;
+		ioseek += SCpnt->request->nr_sectors;
+
+		if (!n)
+			continue;
+
+		if (sl[n] < sl[n - 1])
+			s = 0;
+		if (sl[n] > sl[n - 1])
+			r = 0;
+
+		if (link_statistics) {
+			if (sl[n] > sl[n - 1])
+				seek += sl[n] - sl[n - 1];
+			else
+				seek += sl[n - 1] - sl[n];
+		}
+
+	}
+
+	if (link_statistics) {
+		if (cursec > sl[0])
+			seek += cursec - sl[0];
+		else
+			seek += sl[0] - cursec;
+	}
+
+	if (cursec > ((maxsec + minsec) / 2))
+		rev = 1;
+
+	if (ioseek > ((maxsec - minsec) / 2))
+		rev = 0;
+
+	if (!((rev && r) || (!rev && s)))
+		sort(sl, il, n_ready, rev);
+
+	if (!input_only)
+		for (n = 0; n < n_ready; n++) {
+			k = il[n];
+			cpp = &ha->cp[k];
+			SCpnt = cpp->SCpnt;
+			ll[n] = SCpnt->request->nr_sectors;
+			pl[n] = SCpnt->pid;
+
+			if (!n)
+				continue;
+
+			if ((sl[n] == sl[n - 1])
+			    || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
+			    || (rev && ((sl[n] + ll[n]) > sl[n - 1])))
+				overlap = 1;
+		}
+
+	if (overlap)
+		sort(pl, il, n_ready, 0);
+
+	if (link_statistics) {
+		if (cursec > sl[0])
+			iseek = cursec - sl[0];
+		else
+			iseek = sl[0] - cursec;
+		batchcount++;
+		readycount += n_ready;
+		seeknosort += seek / 1024;
+		if (input_only)
+			inputcount++;
+		if (overlap) {
+			ovlcount++;
+			seeksorted += iseek / 1024;
+		} else
+			seeksorted += (iseek + maxsec - minsec) / 1024;
+		if (rev && !r) {
+			revcount++;
+			readysorted += n_ready;
+		}
+		if (!rev && !s) {
+			sortcount++;
+			readysorted += n_ready;
+		}
+	}
+#if defined(DEBUG_LINKED_COMMANDS)
+	if (link_statistics && (overlap || !(flushcount % link_statistics)))
+		for (n = 0; n < n_ready; n++) {
+			k = il[n];
+			cpp = &ha->cp[k];
+			SCpnt = cpp->SCpnt;
+			printk
+			    ("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"
+			     " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
+			     (ihdlr ? "ihdlr" : "qcomm"),
+			     SCpnt->device->channel, SCpnt->device->id,
+			     SCpnt->device->lun, SCpnt->pid, k, flushcount,
+			     n_ready, SCpnt->request->sector,
+			     SCpnt->request->nr_sectors, cursec, YESNO(s),
+			     YESNO(r), YESNO(rev), YESNO(input_only),
+			     YESNO(overlap), cpp->din);
+		}
+#endif
+	return overlap;
+}
+
+static void flush_dev(struct scsi_device *dev, unsigned long cursec,
+		      struct hostdata *ha, unsigned int ihdlr)
+{
+	struct scsi_cmnd *SCpnt;
+	struct mscp *cpp;
+	unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES];
+
+	for (k = 0; k < dev->host->can_queue; k++) {
+
+		if (ha->cp_stat[k] != READY && ha->cp_stat[k] != IN_USE)
+			continue;
+
+		cpp = &ha->cp[k];
+		SCpnt = cpp->SCpnt;
+
+		if (SCpnt->device != dev)
+			continue;
+
+		if (ha->cp_stat[k] == IN_USE)
+			return;
+
+		il[n_ready++] = k;
+	}
+
+	if (reorder(ha, cursec, ihdlr, il, n_ready))
+		n_ready = 1;
+
+	for (n = 0; n < n_ready; n++) {
+		k = il[n];
+		cpp = &ha->cp[k];
+		SCpnt = cpp->SCpnt;
+
+		if (do_dma(dev->host->io_port, cpp->cp_dma_addr, SEND_CP_DMA)) {
+			printk
+			    ("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"
+			     " busy, will abort.\n", ha->board_name,
+			     (ihdlr ? "ihdlr" : "qcomm"),
+			     SCpnt->device->channel, SCpnt->device->id,
+			     SCpnt->device->lun, SCpnt->pid, k);
+			ha->cp_stat[k] = ABORTING;
+			continue;
+		}
+
+		ha->cp_stat[k] = IN_USE;
+	}
+}
+
+static irqreturn_t ihdlr(int irq, struct Scsi_Host *shost)
+{
+	struct scsi_cmnd *SCpnt;
+	unsigned int i, k, c, status, tstatus, reg;
+	struct mssp *spp;
+	struct mscp *cpp;
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+
+	if (shost->irq != irq)
+		panic("%s: ihdlr, irq %d, shost->irq %d.\n", ha->board_name, irq,
+		      shost->irq);
+
+	/* Check if this board need to be serviced */
+	if (!(inb(shost->io_port + REG_AUX_STATUS) & IRQ_ASSERTED))
+		goto none;
+
+	ha->iocount++;
+
+	if (do_trace)
+		printk("%s: ihdlr, enter, irq %d, count %d.\n", ha->board_name, irq,
+		       ha->iocount);
+
+	/* Check if this board is still busy */
+	if (wait_on_busy(shost->io_port, 20 * MAXLOOP)) {
+		reg = inb(shost->io_port + REG_STATUS);
+		printk
+		    ("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
+		     ha->board_name, irq, reg, ha->iocount);
+		goto none;
+	}
+
+	spp = &ha->sp;
+
+	/* Make a local copy just before clearing the interrupt indication */
+	memcpy(spp, ha->sp_cpu_addr, sizeof(struct mssp));
+
+	/* Clear the completion flag and cp pointer on the dynamic copy of sp */
+	memset(ha->sp_cpu_addr, 0, sizeof(struct mssp));
+
+	/* Read the status register to clear the interrupt indication */
+	reg = inb(shost->io_port + REG_STATUS);
+
+#if defined (DEBUG_INTERRUPT)
+	{
+		unsigned char *bytesp;
+		int cnt;
+		bytesp = (unsigned char *)spp;
+		if (ha->iocount < 200) {
+			printk("sp[] =");
+			for (cnt = 0; cnt < 15; cnt++)
+				printk(" 0x%x", bytesp[cnt]);
+			printk("\n");
+		}
+	}
+#endif
+
+	/* Reject any sp with supspect data */
+	if (spp->eoc == 0 && ha->iocount > 1)
+		printk
+		    ("%s: ihdlr, spp->eoc == 0, irq %d, reg 0x%x, count %d.\n",
+		     ha->board_name, irq, reg, ha->iocount);
+	if (spp->cpp_index < 0 || spp->cpp_index >= shost->can_queue)
+		printk
+		    ("%s: ihdlr, bad spp->cpp_index %d, irq %d, reg 0x%x, count %d.\n",
+		     ha->board_name, spp->cpp_index, irq, reg, ha->iocount);
+	if (spp->eoc == 0 || spp->cpp_index < 0
+	    || spp->cpp_index >= shost->can_queue)
+		goto handled;
+
+	/* Find the mailbox to be serviced on this board */
+	i = spp->cpp_index;
+
+	cpp = &(ha->cp[i]);
+
+#if defined(DEBUG_GENERATE_ABORTS)
+	if ((ha->iocount > 500) && ((ha->iocount % 500) < 3))
+		goto handled;
+#endif
+
+	if (ha->cp_stat[i] == IGNORE) {
+		ha->cp_stat[i] = FREE;
+		goto handled;
+	} else if (ha->cp_stat[i] == LOCKED) {
+		ha->cp_stat[i] = FREE;
+		printk("%s: ihdlr, mbox %d unlocked, count %d.\n", ha->board_name, i,
+		       ha->iocount);
+		goto handled;
+	} else if (ha->cp_stat[i] == FREE) {
+		printk("%s: ihdlr, mbox %d is free, count %d.\n", ha->board_name, i,
+		       ha->iocount);
+		goto handled;
+	} else if (ha->cp_stat[i] == IN_RESET)
+		printk("%s: ihdlr, mbox %d is in reset.\n", ha->board_name, i);
+	else if (ha->cp_stat[i] != IN_USE)
+		panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+		      ha->board_name, i, ha->cp_stat[i]);
+
+	ha->cp_stat[i] = FREE;
+	SCpnt = cpp->SCpnt;
+
+	if (SCpnt == NULL)
+		panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", ha->board_name, i);
+
+	if (SCpnt->host_scribble == NULL)
+		panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", ha->board_name,
+		      i, SCpnt->pid, SCpnt);
+
+	if (*(unsigned int *)SCpnt->host_scribble != i)
+		panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+		      ha->board_name, i, SCpnt->pid,
+		      *(unsigned int *)SCpnt->host_scribble);
+
+	sync_dma(i, ha);
+
+	if (linked_comm && SCpnt->device->queue_depth > 2
+	    && TLDEV(SCpnt->device->type))
+		flush_dev(SCpnt->device, SCpnt->request->sector, ha, 1);
+
+	tstatus = status_byte(spp->target_status);
+
+#if defined(DEBUG_GENERATE_ERRORS)
+	if ((ha->iocount > 500) && ((ha->iocount % 200) < 2))
+		spp->adapter_status = 0x01;
+#endif
+
+	switch (spp->adapter_status) {
+	case ASOK:		/* status OK */
+
+		/* Forces a reset if a disk drive keeps returning BUSY */
+		if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+			status = DID_ERROR << 16;
+
+		/* If there was a bus reset, redo operation on each target */
+		else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+			 && ha->target_redo[SCpnt->device->id][SCpnt->
+								  device->
+								  channel])
+			status = DID_BUS_BUSY << 16;
+
+		/* Works around a flaw in scsi.c */
+		else if (tstatus == CHECK_CONDITION
+			 && SCpnt->device->type == TYPE_DISK
+			 && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+			status = DID_BUS_BUSY << 16;
+
+		else
+			status = DID_OK << 16;
+
+		if (tstatus == GOOD)
+			ha->target_redo[SCpnt->device->id][SCpnt->device->
+							      channel] = 0;
+
+		if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
+		    (!(tstatus == CHECK_CONDITION && ha->iocount <= 1000 &&
+		       (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
+			printk("%s: ihdlr, target %d.%d:%d, pid %ld, "
+			       "target_status 0x%x, sense key 0x%x.\n",
+			       ha->board_name,
+			       SCpnt->device->channel, SCpnt->device->id,
+			       SCpnt->device->lun, SCpnt->pid,
+			       spp->target_status, SCpnt->sense_buffer[2]);
+
+		ha->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
+
+		if (ha->last_retried_pid == SCpnt->pid)
+			ha->retries = 0;
+
+		break;
+	case ASST:		/* Selection Time Out */
+	case 0x02:		/* Command Time Out   */
+
+		if (ha->target_to[SCpnt->device->id][SCpnt->device->channel] > 1)
+			status = DID_ERROR << 16;
+		else {
+			status = DID_TIME_OUT << 16;
+			ha->target_to[SCpnt->device->id][SCpnt->device->
+							    channel]++;
+		}
+
+		break;
+
+		/* Perform a limited number of internal retries */
+	case 0x03:		/* SCSI Bus Reset Received */
+	case 0x04:		/* Initial Controller Power-up */
+
+		for (c = 0; c <= shost->max_channel; c++)
+			for (k = 0; k < shost->max_id; k++)
+				ha->target_redo[k][c] = 1;
+
+		if (SCpnt->device->type != TYPE_TAPE
+		    && ha->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+			status = DID_SOFT_ERROR << 16;
+#else
+			status = DID_BUS_BUSY << 16;
+#endif
+
+			ha->retries++;
+			ha->last_retried_pid = SCpnt->pid;
+		} else
+			status = DID_ERROR << 16;
+
+		break;
+	case 0x05:		/* Unexpected Bus Phase */
+	case 0x06:		/* Unexpected Bus Free */
+	case 0x07:		/* Bus Parity Error */
+	case 0x08:		/* SCSI Hung */
+	case 0x09:		/* Unexpected Message Reject */
+	case 0x0a:		/* SCSI Bus Reset Stuck */
+	case 0x0b:		/* Auto Request-Sense Failed */
+	case 0x0c:		/* Controller Ram Parity Error */
+	default:
+		status = DID_ERROR << 16;
+		break;
+	}
+
+	SCpnt->result = status | spp->target_status;
+
+#if defined(DEBUG_INTERRUPT)
+	if (SCpnt->result || do_trace)
+#else
+	if ((spp->adapter_status != ASOK && ha->iocount > 1000) ||
+	    (spp->adapter_status != ASOK &&
+	     spp->adapter_status != ASST && ha->iocount <= 1000) ||
+	    do_trace || msg_byte(spp->target_status))
+#endif
+		printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"
+		       " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
+		       ha->board_name, i, spp->adapter_status, spp->target_status,
+		       SCpnt->device->channel, SCpnt->device->id,
+		       SCpnt->device->lun, SCpnt->pid, reg, ha->iocount);
+
+	unmap_dma(i, ha);
+
+	/* Set the command state to inactive */
+	SCpnt->host_scribble = NULL;
+
+	SCpnt->scsi_done(SCpnt);
+
+	if (do_trace)
+		printk("%s: ihdlr, exit, irq %d, count %d.\n", ha->board_name,
+				irq, ha->iocount);
+
+      handled:
+	return IRQ_HANDLED;
+      none:
+	return IRQ_NONE;
+}
+
+static irqreturn_t do_interrupt_handler(int irq, void *shap,
+					struct pt_regs *regs)
+{
+	struct Scsi_Host *shost;
+	unsigned int j;
+	unsigned long spin_flags;
+	irqreturn_t ret;
+
+	/* Check if the interrupt must be processed by this handler */
+	if ((j = (unsigned int)((char *)shap - sha)) >= num_boards)
+		return IRQ_NONE;
+	shost = sh[j];
+
+	spin_lock_irqsave(shost->host_lock, spin_flags);
+	ret = ihdlr(irq, shost);
+	spin_unlock_irqrestore(shost->host_lock, spin_flags);
+	return ret;
+}
+
+static int eata2x_release(struct Scsi_Host *shost)
+{
+	struct hostdata *ha = (struct hostdata *)shost->hostdata;
+	unsigned int i;
+
+	for (i = 0; i < shost->can_queue; i++)
+		if ((&ha->cp[i])->sglist)
+			kfree((&ha->cp[i])->sglist);
+
+	for (i = 0; i < shost->can_queue; i++)
+		pci_unmap_single(ha->pdev, ha->cp[i].cp_dma_addr,
+				 sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+	if (ha->sp_cpu_addr)
+		pci_free_consistent(ha->pdev, sizeof(struct mssp),
+				    ha->sp_cpu_addr, ha->sp_dma_addr);
+
+	free_irq(shost->irq, &sha[ha->board_number]);
+
+	if (shost->dma_channel != NO_DMA)
+		free_dma(shost->dma_channel);
+
+	release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+#include "scsi_module.c"
+
+#ifndef MODULE
+__setup("eata=", option_setup);
+#endif				/* end MODULE */
diff --git a/drivers/scsi/eata_generic.h b/drivers/scsi/eata_generic.h
new file mode 100644
index 0000000..34bce2c
--- /dev/null
+++ b/drivers/scsi/eata_generic.h
@@ -0,0 +1,406 @@
+/********************************************************
+* Header file for eata_dma.c and eata_pio.c		*
+* Linux EATA SCSI drivers				*
+* (c) 1993-96 Michael Neuffer                           *
+*             mike@i-Connect.Net                        *
+*             neuffer@mail.uni-mainz.de                 *
+*********************************************************
+* last change: 96/08/14                                 *
+********************************************************/
+
+
+#ifndef _EATA_GENERIC_H
+#define _EATA_GENERIC_H
+
+
+
+/*********************************************
+ * Misc. definitions			     *
+ *********************************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define R_LIMIT 0x20000
+
+#define MAXISA	   4
+#define MAXEISA	  16  
+#define MAXPCI	  16
+#define MAXIRQ	  16 
+#define MAXTARGET 16
+#define MAXCHANNEL 3
+
+#define IS_ISA	   'I'
+#define IS_EISA	   'E'
+#define IS_PCI	   'P'
+
+#define BROKEN_INQUIRY	1
+
+#define BUSMASTER       0xff
+#define PIO             0xfe
+
+#define EATA_SIGNATURE	0x45415441     /* BIG ENDIAN coded "EATA" sig.	 */
+
+#define DPT_ID1         0x12
+#define DPT_ID2         0x14
+
+#define ATT_ID1         0x06
+#define ATT_ID2         0x94
+#define ATT_ID3         0x0
+
+#define NEC_ID1         0x38
+#define NEC_ID2         0xa3
+#define NEC_ID3         0x82
+
+ 
+#define EATA_CP_SIZE	 44
+
+#define MAX_PCI_DEVICES  32	       /* Maximum # Of Devices Per Bus	 */
+#define MAX_METHOD_2	 16	       /* Max Devices For Method 2	 */
+#define MAX_PCI_BUS	 16	       /* Maximum # Of Busses Allowed	 */
+
+#define SG_SIZE		 64 
+#define SG_SIZE_BIG	 252	       /* max. 8096 elements, 64k */
+
+#define UPPER_DEVICE_QUEUE_LIMIT 64    /* The limit we have to set for the 
+					* device queue to keep the broken 
+					* midlevel SCSI code from producing
+					* bogus timeouts
+					*/
+
+#define TYPE_DISK_QUEUE  16
+#define TYPE_TAPE_QUEUE  4
+#define TYPE_ROM_QUEUE   4
+#define TYPE_OTHER_QUEUE 2
+
+#define FREE	         0
+#define OK	         0
+#define NO_TIMEOUT       0
+#define USED	         1
+#define TIMEOUT	         2
+#define RESET	         4
+#define LOCKED	         8
+#define ABORTED          16
+
+#define READ             0
+#define WRITE            1
+#define OTHER            2
+
+#define HD(cmd)	 ((hostdata *)&(cmd->device->host->hostdata))
+#define CD(cmd)	 ((struct eata_ccb *)(cmd->host_scribble))
+#define SD(host) ((hostdata *)&(host->hostdata))
+
+/***********************************************
+ *    EATA Command & Register definitions      *
+ ***********************************************/
+#define PCI_REG_DPTconfig	 0x40	 
+#define PCI_REG_PumpModeAddress	 0x44	 
+#define PCI_REG_PumpModeData	 0x48	 
+#define PCI_REG_ConfigParam1	 0x50	 
+#define PCI_REG_ConfigParam2	 0x54	 
+
+
+#define EATA_CMD_PIO_SETUPTEST	 0xc6
+#define EATA_CMD_PIO_READ_CONFIG 0xf0
+#define EATA_CMD_PIO_SET_CONFIG	 0xf1
+#define EATA_CMD_PIO_SEND_CP	 0xf2
+#define EATA_CMD_PIO_RECEIVE_SP	 0xf3
+#define EATA_CMD_PIO_TRUNC	 0xf4
+
+#define EATA_CMD_RESET		 0xf9
+#define EATA_CMD_IMMEDIATE	 0xfa
+
+#define EATA_CMD_DMA_READ_CONFIG 0xfd
+#define EATA_CMD_DMA_SET_CONFIG	 0xfe
+#define EATA_CMD_DMA_SEND_CP	 0xff
+
+#define ECS_EMULATE_SENSE	 0xd4
+
+#define EATA_GENERIC_ABORT       0x00 
+#define EATA_SPECIFIC_RESET      0x01
+#define EATA_BUS_RESET           0x02
+#define EATA_SPECIFIC_ABORT      0x03
+#define EATA_QUIET_INTR          0x04
+#define EATA_COLD_BOOT_HBA       0x06	   /* Only as a last resort	*/
+#define EATA_FORCE_IO            0x07
+
+#define HA_CTRLREG     0x206       /* control register for HBA    */
+#define HA_CTRL_DISINT 0x02        /* CTRLREG: disable interrupts */
+#define HA_CTRL_RESCPU 0x04        /* CTRLREG: reset processor    */
+#define HA_CTRL_8HEADS 0x08        /* CTRLREG: set for drives with* 
+				    * >=8 heads (WD1003 rudimentary :-) */
+
+#define HA_WCOMMAND    0x07	   /* command register offset	*/
+#define HA_WIFC        0x06	   /* immediate command offset  */
+#define HA_WCODE       0x05 
+#define HA_WCODE2      0x04 
+#define HA_WDMAADDR    0x02	   /* DMA address LSB offset	*/  
+#define HA_RAUXSTAT    0x08	   /* aux status register offset*/
+#define HA_RSTATUS     0x07	   /* status register offset	*/
+#define HA_RDATA       0x00	   /* data register (16bit)	*/
+#define HA_WDATA       0x00	   /* data register (16bit)	*/
+
+#define HA_ABUSY       0x01	   /* aux busy bit		*/
+#define HA_AIRQ	       0x02	   /* aux IRQ pending bit	*/
+#define HA_SERROR      0x01	   /* pr. command ended in error*/
+#define HA_SMORE       0x02	   /* more data soon to come	*/
+#define HA_SCORR       0x04	   /* data corrected		*/
+#define HA_SDRQ	       0x08	   /* data request active	*/
+#define HA_SSC	       0x10	   /* seek complete		*/
+#define HA_SFAULT      0x20	   /* write fault		*/
+#define HA_SREADY      0x40	   /* drive ready		*/
+#define HA_SBUSY       0x80	   /* drive busy		*/
+#define HA_SDRDY       HA_SSC+HA_SREADY+HA_SDRQ 
+
+/**********************************************
+ * Message definitions			      *
+ **********************************************/
+
+#define HA_NO_ERROR	 0x00	/* No Error				*/
+#define HA_ERR_SEL_TO	 0x01	/* Selection Timeout			*/
+#define HA_ERR_CMD_TO	 0x02	/* Command Timeout			*/
+#define HA_BUS_RESET	 0x03	/* SCSI Bus Reset Received		*/
+#define HA_INIT_POWERUP	 0x04	/* Initial Controller Power-up		*/
+#define HA_UNX_BUSPHASE	 0x05	/* Unexpected Bus Phase			*/
+#define HA_UNX_BUS_FREE	 0x06	/* Unexpected Bus Free			*/
+#define HA_BUS_PARITY	 0x07	/* Bus Parity Error			*/
+#define HA_SCSI_HUNG	 0x08	/* SCSI Hung				*/
+#define HA_UNX_MSGRJCT	 0x09	/* Unexpected Message Rejected		*/
+#define HA_RESET_STUCK	 0x0a	/* SCSI Bus Reset Stuck			*/
+#define HA_RSENSE_FAIL	 0x0b	/* Auto Request-Sense Failed		*/
+#define HA_PARITY_ERR	 0x0c	/* Controller Ram Parity Error		*/
+#define HA_CP_ABORT_NA	 0x0d	/* Abort Message sent to non-active cmd */
+#define HA_CP_ABORTED	 0x0e	/* Abort Message sent to active cmd	*/
+#define HA_CP_RESET_NA	 0x0f	/* Reset Message sent to non-active cmd */
+#define HA_CP_RESET	 0x10	/* Reset Message sent to active cmd	*/
+#define HA_ECC_ERR	 0x11	/* Controller Ram ECC Error		*/
+#define HA_PCI_PARITY	 0x12	/* PCI Parity Error			*/
+#define HA_PCI_MABORT	 0x13	/* PCI Master Abort			*/
+#define HA_PCI_TABORT	 0x14	/* PCI Target Abort			*/
+#define HA_PCI_STABORT	 0x15	/* PCI Signaled Target Abort		*/
+
+/**********************************************
+ *  Other  definitions			      *
+ **********************************************/
+
+struct reg_bit {      /* reading this one will clear the interrupt    */
+    __u8 error:1;     /* previous command ended in an error	      */
+    __u8 more:1;      /* more DATA coming soon, poll BSY & DRQ (PIO)  */
+    __u8 corr:1;      /* data read was successfully corrected with ECC*/
+    __u8 drq:1;	      /* data request active  */     
+    __u8 sc:1;	      /* seek complete	      */
+    __u8 fault:1;     /* write fault	      */
+    __u8 ready:1;     /* drive ready	      */
+    __u8 busy:1;      /* controller busy      */
+};
+
+struct reg_abit {     /* reading this won't clear the interrupt */
+    __u8 abusy:1;     /* auxiliary busy				*/
+    __u8 irq:1;	      /* set when drive interrupt is asserted	*/
+    __u8 dummy:6;
+};
+
+struct eata_register {	    /* EATA register set */
+    __u8 data_reg[2];	    /* R, couldn't figure this one out		*/
+    __u8 cp_addr[4];	    /* W, CP address register			*/
+    union { 
+	__u8 command;	    /* W, command code: [read|set] conf, send CP*/
+	struct reg_bit status;	/* R, see register_bit1			*/
+	__u8 statusbyte;
+    } ovr;   
+    struct reg_abit aux_stat; /* R, see register_bit2			*/
+};
+
+struct get_conf {	      /* Read Configuration Array		*/
+    __u32  len;		      /* Should return 0x22, 0x24, etc		*/
+    __u32 signature;	      /* Signature MUST be "EATA"		*/
+    __u8    version2:4,
+	     version:4;	      /* EATA Version level			*/
+    __u8 OCS_enabled:1,	      /* Overlap Command Support enabled	*/
+	 TAR_support:1,	      /* SCSI Target Mode supported		*/
+	      TRNXFR:1,	      /* Truncate Transfer Cmd not necessary	*
+			       * Only used in PIO Mode			*/
+	MORE_support:1,	      /* MORE supported (only PIO Mode)		*/
+	 DMA_support:1,	      /* DMA supported Driver uses only		*
+			       * this mode				*/
+	   DMA_valid:1,	      /* DRQ value in Byte 30 is valid		*/
+		 ATA:1,	      /* ATA device connected (not supported)	*/
+	   HAA_valid:1;	      /* Hostadapter Address is valid		*/
+
+    __u16 cppadlen;	      /* Number of pad bytes send after CD data *
+			       * set to zero for DMA commands		*/
+    __u8 scsi_id[4];	      /* SCSI ID of controller 2-0 Byte 0 res.	*
+			       * if not, zero is returned		*/
+    __u32  cplen;	      /* CP length: number of valid cp bytes	*/
+    __u32  splen;	      /* Number of bytes returned after		* 
+			       * Receive SP command			*/
+    __u16 queuesiz;	      /* max number of queueable CPs		*/
+    __u16 dummy;
+    __u16 SGsiz;	      /* max number of SG table entries		*/
+    __u8    IRQ:4,	      /* IRQ used this HA			*/
+	 IRQ_TR:1,	      /* IRQ Trigger: 0=edge, 1=level		*/
+	 SECOND:1,	      /* This is a secondary controller		*/
+    DMA_channel:2;	      /* DRQ index, DRQ is 2comp of DRQX	*/
+    __u8 sync;		      /* device at ID 7 tru 0 is running in	*
+			       * synchronous mode, this will disappear	*/
+    __u8   DSBLE:1,	      /* ISA i/o addressing is disabled		*/
+	 FORCADR:1,	      /* i/o address has been forced		*/
+	  SG_64K:1,
+	  SG_UAE:1,
+		:4;
+    __u8  MAX_ID:5,	      /* Max number of SCSI target IDs		*/
+	MAX_CHAN:3;	      /* Number of SCSI busses on HBA		*/
+    __u8 MAX_LUN;	      /* Max number of LUNs			*/
+    __u8	:3,
+	 AUTOTRM:1,
+	 M1_inst:1,
+	 ID_qest:1,	      /* Raidnum ID is questionable		*/
+	  is_PCI:1,	      /* HBA is PCI				*/
+	 is_EISA:1;	      /* HBA is EISA				*/
+    __u8 RAIDNUM;             /* unique HBA identifier                  */
+    __u8 unused[474]; 
+};
+
+struct eata_sg_list
+{
+    __u32 data;
+    __u32 len;
+};
+
+struct eata_ccb {	      /* Send Command Packet structure	    */
+ 
+    __u8 SCSI_Reset:1,	      /* Cause a SCSI Bus reset on the cmd	*/
+	   HBA_Init:1,	      /* Cause Controller to reinitialize	*/
+       Auto_Req_Sen:1,	      /* Do Auto Request Sense on errors	*/
+	    scatter:1,	      /* Data Ptr points to a SG Packet		*/
+	     Resrvd:1,	      /* RFU					*/
+	  Interpret:1,	      /* Interpret the SCSI cdb of own use	*/
+	    DataOut:1,	      /* Data Out phase with command		*/
+	     DataIn:1;	      /* Data In phase with command		*/
+    __u8 reqlen;	      /* Request Sense Length			* 
+			       * Valid if Auto_Req_Sen=1		*/
+    __u8 unused[3];
+    __u8  FWNEST:1,	      /* send cmd to phys RAID component	*/
+	 unused2:7;
+    __u8 Phsunit:1,	      /* physical unit on mirrored pair		*/
+	    I_AT:1,	      /* inhibit address translation		*/
+	 I_HBA_C:1,	      /* HBA inhibit caching			*/
+	 unused3:5;
+
+    __u8     cp_id:5,	      /* SCSI Device ID of target		*/ 
+	cp_channel:3;	      /* SCSI Channel # of HBA			*/
+    __u8    cp_lun:3,
+		  :2,
+	 cp_luntar:1,	      /* CP is for target ROUTINE		*/
+	 cp_dispri:1,	      /* Grant disconnect privilege		*/
+       cp_identify:1;	      /* Always TRUE				*/
+    __u8 cp_msg1;	      /* Message bytes 0-3			*/
+    __u8 cp_msg2;
+    __u8 cp_msg3;
+    __u8 cp_cdb[12];	      /* Command Descriptor Block		*/
+    __u32 cp_datalen;	      /* Data Transfer Length			*
+			       * If scatter=1 len of sg package		*/
+    void *cp_viraddr;	      /* address of this ccb			*/
+    __u32 cp_dataDMA;	      /* Data Address, if scatter=1		*
+			       * address of scatter packet		*/
+    __u32 cp_statDMA;	      /* address for Status Packet		*/ 
+    __u32 cp_reqDMA;	      /* Request Sense Address, used if		*
+			       * CP command ends with error		*/
+    /* Additional CP info begins here */
+    __u32 timestamp;	      /* Needed to measure command latency	*/
+    __u32 timeout;
+    __u8 sizeindex;
+    __u8 rw_latency;
+    __u8 retries;
+    __u8 status;	      /* status of this queueslot		*/
+    struct scsi_cmnd *cmd;    /* address of cmd				*/
+    struct eata_sg_list *sg_list;
+};
+
+
+struct eata_sp {
+    __u8 hba_stat:7,	      /* HBA status				*/
+	      EOC:1;	      /* True if command finished		*/
+    __u8 scsi_stat;	      /* Target SCSI status			*/
+    __u8 reserved[2];
+    __u32  residue_len;	      /* Number of bytes not transferred	*/
+    struct eata_ccb *ccb;     /* Address set in COMMAND PACKET		*/
+    __u8 msg[12];
+};
+
+typedef struct hstd {
+    __u8   vendor[9];
+    __u8   name[18];
+    __u8   revision[6];
+    __u8   EATA_revision;
+    __u32  firmware_revision;
+    __u8   HBA_number;
+    __u8   bustype;		 /* bustype of HBA	       */
+    __u8   channel;		 /* # of avail. scsi channels  */
+    __u8   state;		 /* state of HBA	       */
+    __u8   primary;		 /* true if primary	       */
+    __u8        more_support:1,  /* HBA supports MORE flag     */
+           immediate_support:1,  /* HBA supports IMMEDIATE CMDs*/
+              broken_INQUIRY:1;	 /* This is an EISA HBA with   *
+				  * broken INQUIRY	       */
+    __u8   do_latency;		 /* Latency measurement flag   */
+    __u32  reads[13];
+    __u32  writes[13];
+    __u32  reads_lat[12][4];
+    __u32  writes_lat[12][4];
+    __u32  all_lat[4];
+    __u8   resetlevel[MAXCHANNEL]; 
+    __u32  last_ccb;		 /* Last used ccb	       */
+    __u32  cplen;		 /* size of CP in words	       */
+    __u16  cppadlen;		 /* pad length of cp in words  */
+    __u16  queuesize;
+    __u16  sgsize;               /* # of entries in the SG list*/
+    __u16  devflags;		 /* bits set for detected devices */
+    __u8   hostid;		 /* SCSI ID of HBA	       */
+    __u8   moresupport;		 /* HBA supports MORE flag     */
+    struct Scsi_Host *next;	    
+    struct Scsi_Host *prev;
+    struct eata_sp sp;		 /* status packet	       */ 
+    struct eata_ccb ccb[0];	 /* ccb array begins here      */
+}hostdata;
+
+/* structure for max. 2 emulated drives */
+struct drive_geom_emul {
+    __u8  trans;		 /* translation flag 1=transl */
+    __u8  channel;		 /* SCSI channel number	      */
+    __u8  HBA;			 /* HBA number (prim/sec)     */
+    __u8  id;			 /* drive id		      */
+    __u8  lun;			 /* drive lun		      */
+    __u32 heads;		 /* number of heads	      */
+    __u32 sectors;		 /* number of sectors	      */
+    __u32 cylinder;		 /* number of cylinders	      */
+};
+
+struct geom_emul {
+    __u8 bios_drives;		 /* number of emulated drives */
+    struct drive_geom_emul drv[2]; /* drive structures	      */
+};
+
+#endif /* _EATA_GENERIC_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
new file mode 100644
index 0000000..0ee49dc
--- /dev/null
+++ b/drivers/scsi/eata_pio.c
@@ -0,0 +1,996 @@
+/************************************************************
+ *                                                          *
+ *               Linux EATA SCSI PIO driver                 *
+ *                                                          *
+ *  based on the CAM document CAM/89-004 rev. 2.0c,         *
+ *  DPT's driver kit, some internal documents and source,   *
+ *  and several other Linux scsi drivers and kernel docs.   *
+ *                                                          *
+ *  The driver currently:                                   *
+ *      -supports all EATA-PIO boards                       *
+ *      -only supports DASD devices                         *
+ *                                                          *
+ *  (c)1993-96 Michael Neuffer, Alfred Arnold               *
+ *             neuffer@goofy.zdv.uni-mainz.de               *
+ *             a.arnold@kfa-juelich.de                      * 
+ *                                                          *
+ *  Updated 2002 by Alan Cox <alan@redhat.com> for Linux    *
+ *  2.5.x and the newer locking and error handling          *
+ *                                                          *
+ *  This program is free software; you can redistribute it  *
+ *  and/or modify it under the terms of the GNU General     *
+ *  Public License as published by the Free Software        *
+ *  Foundation; either version 2 of the License, or         *
+ *  (at your option) any later version.                     *
+ *                                                          *
+ *  This program is distributed in the hope that it will be *
+ *  useful, but WITHOUT ANY WARRANTY; without even the      *
+ *  implied warranty of MERCHANTABILITY or FITNESS FOR A    *
+ *  PARTICULAR PURPOSE.  See the GNU General Public License *
+ *  for more details.                                       *
+ *                                                          *
+ *  You should have received a copy of the GNU General      *
+ *  Public License along with this kernel; if not, write to *
+ *  the Free Software Foundation, Inc., 675 Mass Ave,       *
+ *  Cambridge, MA 02139, USA.                               *
+ *							    *
+ *  For the avoidance of doubt the "preferred form" of this *
+ *  code is one which is in an open non patent encumbered   *
+ *  format. Where cryptographic key signing forms part of   *
+ *  the process of creating an executable the information   *
+ *  including keys needed to generate an equivalently       *
+ *  functional executable are deemed to be part of the 	    *
+ *  source code are deemed to be part of the source code.   *
+ *                                                          *
+ ************************************************************
+ *  last change: 2002/11/02               OS: Linux 2.5.45  *
+ ************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/in.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "eata_generic.h"
+#include "eata_pio.h"
+
+
+static uint ISAbases[MAXISA] =	{
+	 0x1F0, 0x170, 0x330, 0x230
+};
+
+static uint ISAirqs[MAXISA] = {
+	14, 12, 15, 11
+};
+
+static unsigned char EISAbases[] = { 
+	1, 1, 1, 1, 1, 1, 1, 1,
+	1, 1, 1, 1, 1, 1, 1, 1 
+};
+
+static uint registered_HBAs;
+static struct Scsi_Host *last_HBA;
+static struct Scsi_Host *first_HBA;
+static unsigned char reg_IRQ[16];
+static unsigned char reg_IRQL[16];
+static unsigned long int_counter;
+static unsigned long queue_counter;
+
+static struct scsi_host_template driver_template;
+
+/*
+ * eata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the 
+ *         variables
+ * buffer: If inout==FALSE data is being written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file 
+ *         from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer 
+ *         else number of bytes in the buffer
+ */
+static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset,
+			      int length, int rw)
+{
+    static u8 buff[512];
+    int size, len = 0;
+    off_t begin = 0, pos = 0;
+
+    if (rw)
+    	return -ENOSYS;
+    if (offset == 0)
+	memset(buff, 0, sizeof(buff));
+
+    size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+		   "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
+    len += size; pos = begin + len;
+    size = sprintf(buffer + len, "queued commands:     %10ld\n"
+		   "processed interrupts:%10ld\n", queue_counter, int_counter);
+    len += size; pos = begin + len;
+    
+    size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+		   shost->host_no, SD(shost)->name);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Firmware revision: v%s\n", 
+		   SD(shost)->revision);
+    len += size;
+    pos = begin + len;
+    size = sprintf(buffer + len, "IO: PIO\n");
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) shost->base);
+    len += size; 
+    pos = begin + len;
+    size = sprintf(buffer + len, "Host Bus: %s\n", 
+		   (SD(shost)->bustype == 'P')?"PCI ":
+		   (SD(shost)->bustype == 'E')?"EISA":"ISA ");
+    
+    len += size; 
+    pos = begin + len;
+    
+    if (pos < offset) {
+	len = 0;
+	begin = pos;
+    }
+    if (pos > offset + length)
+	goto stop_output;
+    
+ stop_output:
+    DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    *start=buffer+(offset-begin);   /* Start of wanted data */
+    len-=(offset-begin);            /* Start slop */
+    if(len>length)
+	len = length;               /* Ending slop */
+    DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+    
+    return (len);     
+}
+
+static int eata_pio_release(struct Scsi_Host *sh)
+{
+	if (sh->irq && reg_IRQ[sh->irq] == 1)
+		free_irq(sh->irq, NULL);
+	else
+		reg_IRQ[sh->irq]--;
+	if (SD(sh)->channel == 0) {
+		if (sh->io_port && sh->n_io_port)
+			release_region(sh->io_port, sh->n_io_port);
+	}
+	return 1;
+}
+
+static void IncStat(struct scsi_pointer *SCp, uint Increment)
+{
+	SCp->ptr += Increment;
+	if ((SCp->this_residual -= Increment) == 0) {
+		if ((--SCp->buffers_residual) == 0)
+			SCp->Status = 0;
+		else {
+			SCp->buffer++;
+			SCp->ptr = page_address(SCp->buffer->page) + SCp->buffer->offset;
+			SCp->this_residual = SCp->buffer->length;
+		}
+	}
+}
+
+static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs);
+
+static irqreturn_t do_eata_pio_int_handler(int irq, void *dev_id,
+						struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+	eata_pio_int_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void eata_pio_int_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	uint eata_stat = 0xfffff;
+	struct scsi_cmnd *cmd;
+	hostdata *hd;
+	struct eata_ccb *cp;
+	uint base;
+	uint x, z;
+	struct Scsi_Host *sh;
+	unsigned short zwickel = 0;
+	unsigned char stat, odd;
+
+	for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) 
+	{
+		if (sh->irq != irq)
+			continue;
+		if (inb((uint) sh->base + HA_RSTATUS) & HA_SBUSY)
+			continue;
+
+		int_counter++;
+
+		hd = SD(sh);
+
+		cp = &hd->ccb[0];
+		cmd = cp->cmd;
+		base = (uint) cmd->device->host->base;
+
+		do {
+			stat = inb(base + HA_RSTATUS);
+			if (stat & HA_SDRQ) {
+				if (cp->DataIn) {
+					z = 256;
+					odd = 0;
+					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
+						if (odd) {
+							*(cmd->SCp.ptr) = zwickel >> 8;
+							IncStat(&cmd->SCp, 1);
+							odd = 0;
+						}
+						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
+						insw(base + HA_RDATA, cmd->SCp.ptr, x);
+						z -= x;
+						IncStat(&cmd->SCp, 2 * x);
+						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
+							zwickel = inw(base + HA_RDATA);
+							*(cmd->SCp.ptr) = zwickel & 0xff;
+							IncStat(&cmd->SCp, 1);
+							z--;
+							odd = 1;
+						}
+					}
+					while (z > 0) {
+						zwickel = inw(base + HA_RDATA);
+						z--;
+					}
+				} else {	/* cp->DataOut */
+
+					odd = 0;
+					z = 256;
+					while ((cmd->SCp.Status) && ((z > 0) || (odd))) {
+						if (odd) {
+							zwickel += *(cmd->SCp.ptr) << 8;
+							IncStat(&cmd->SCp, 1);
+							outw(zwickel, base + HA_RDATA);
+							z--;
+							odd = 0;
+						}
+						x = min_t(unsigned int, z, cmd->SCp.this_residual / 2);
+						outsw(base + HA_RDATA, cmd->SCp.ptr, x);
+						z -= x;
+						IncStat(&cmd->SCp, 2 * x);
+						if ((z > 0) && (cmd->SCp.this_residual == 1)) {
+							zwickel = *(cmd->SCp.ptr);
+							zwickel &= 0xff;
+							IncStat(&cmd->SCp, 1);
+							odd = 1;
+						}
+					}
+					while (z > 0 || odd) {
+						outw(zwickel, base + HA_RDATA);
+						z--;
+						odd = 0;
+					}
+				}
+			}
+		}
+		while ((stat & HA_SDRQ) || ((stat & HA_SMORE) && hd->moresupport));
+
+		/* terminate handler if HBA goes busy again, i.e. transfers
+		 * more data */
+
+		if (stat & HA_SBUSY)
+			break;
+
+		/* OK, this is quite stupid, but I haven't found any correct
+		 * way to get HBA&SCSI status so far */
+
+		if (!(inb(base + HA_RSTATUS) & HA_SERROR)) {
+			cmd->result = (DID_OK << 16);
+			hd->devflags |= (1 << cp->cp_id);
+		} else if (hd->devflags & 1 << cp->cp_id)
+			cmd->result = (DID_OK << 16) + 0x02;
+		else
+			cmd->result = (DID_NO_CONNECT << 16);
+
+		if (cp->status == LOCKED) {
+			cp->status = FREE;
+			eata_stat = inb(base + HA_RSTATUS);
+			printk(KERN_CRIT "eata_pio: int_handler, freeing locked " "queueslot\n");
+			return;
+		}
+#if DBG_INTR2
+		if (stat != 0x50)
+			printk(KERN_DEBUG "stat: %#.2x, result: %#.8x\n", stat, cmd->result);
+#endif
+
+		cp->status = FREE;	/* now we can release the slot  */
+
+		cmd->scsi_done(cmd);
+	}
+
+	return;
+}
+
+static inline uint eata_pio_send_command(uint base, unsigned char command)
+{
+	uint loop = HZ / 2;
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY)
+		if (--loop == 0)
+			return 1;
+
+	/* Enable interrupts for HBA.  It is not the best way to do it at this
+	 * place, but I hope that it doesn't interfere with the IDE driver 
+	 * initialization this way */
+
+	outb(HA_CTRL_8HEADS, base + HA_CTRLREG);
+
+	outb(command, base + HA_WCOMMAND);
+	return 0;
+}
+
+static int eata_pio_queue(struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	uint x, y;
+	uint base;
+
+	hostdata *hd;
+	struct Scsi_Host *sh;
+	struct eata_ccb *cp;
+
+	queue_counter++;
+
+	hd = HD(cmd);
+	sh = cmd->device->host;
+	base = (uint) sh->base;
+
+	/* use only slot 0, as 2001 can handle only one cmd at a time */
+
+	y = x = 0;
+
+	if (hd->ccb[y].status != FREE) {
+
+		DBG(DBG_QUEUE, printk(KERN_EMERG "can_queue %d, x %d, y %d\n", sh->can_queue, x, y));
+#if DEBUG_EATA
+		panic(KERN_EMERG "eata_pio: run out of queue slots cmdno:%ld " "intrno: %ld\n", queue_counter, int_counter);
+#else
+		panic(KERN_EMERG "eata_pio: run out of queue slots....\n");
+#endif
+	}
+
+	cp = &hd->ccb[y];
+
+	memset(cp, 0, sizeof(struct eata_ccb));
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	cp->status = USED;	/* claim free slot */
+
+	DBG(DBG_QUEUE, printk(KERN_DEBUG "eata_pio_queue pid %ld, target: %x, lun:" " %x, y %d\n", cmd->pid, cmd->device->id, cmd->device->lun, y));
+
+	cmd->scsi_done = (void *) done;
+
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		cp->DataOut = 1;	/* Output mode */
+	else
+		cp->DataIn = 0;	/* Input mode  */
+
+	cp->Interpret = (cmd->device->id == hd->hostid);
+	cp->cp_datalen = htonl((unsigned long) cmd->request_bufflen);
+	cp->Auto_Req_Sen = 0;
+	cp->cp_reqDMA = htonl(0);
+	cp->reqlen = 0;
+
+	cp->cp_id = cmd->device->id;
+	cp->cp_lun = cmd->device->lun;
+	cp->cp_dispri = 0;
+	cp->cp_identify = 1;
+	memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+	cp->cp_statDMA = htonl(0);
+
+	cp->cp_viraddr = cp;
+	cp->cmd = cmd;
+	cmd->host_scribble = (char *) &hd->ccb[y];
+
+	if (cmd->use_sg == 0) {
+		cmd->SCp.buffers_residual = 1;
+		cmd->SCp.ptr = cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+		cmd->SCp.buffer = NULL;
+	} else {
+		cmd->SCp.buffer = cmd->request_buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	}
+	cmd->SCp.Status = (cmd->SCp.this_residual != 0);	/* TRUE as long as bytes 
+								 * are to transfer */
+
+	if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP)) {
+		cmd->result = DID_BUS_BUSY << 16;
+		printk(KERN_NOTICE "eata_pio_queue target %d, pid %ld, HBA busy, " "returning DID_BUS_BUSY, done.\n", cmd->device->id, cmd->pid);
+		done(cmd);
+		cp->status = FREE;
+		return (0);
+	}
+	/* FIXME: timeout */
+	while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+		cpu_relax();
+	outsw(base + HA_RDATA, cp, hd->cplen);
+	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+	for (x = 0; x < hd->cppadlen; x++)
+		outw(0, base + HA_RDATA);
+
+	DBG(DBG_QUEUE, printk(KERN_DEBUG "Queued base %#.4lx pid: %ld target: %x " "lun: %x slot %d irq %d\n", (long) sh->base, cmd->pid, cmd->device->id, cmd->device->lun, y, sh->irq));
+
+	return (0);
+}
+
+static int eata_pio_abort(struct scsi_cmnd *cmd)
+{
+	uint loop = HZ;
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_abort called pid: %ld " "target: %x lun: %x reason %x\n", cmd->pid, cmd->device->id, cmd->device->lun, cmd->abort_reason));
+
+
+	while (inb(cmd->device->host->base + HA_RAUXSTAT) & HA_ABUSY)
+		if (--loop == 0) {
+			printk(KERN_WARNING "eata_pio: abort, timeout error.\n");
+			return FAILED;
+		}
+	if (CD(cmd)->status == FREE) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_NOT_RUNNING\n"));
+		return FAILED;
+	}
+	if (CD(cmd)->status == USED) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "Returning: SCSI_ABORT_BUSY\n"));
+		/* We want to sleep a bit more here */
+		return FAILED;		/* SNOOZE */
+	}
+	if (CD(cmd)->status == RESET) {
+		printk(KERN_WARNING "eata_pio: abort, command reset error.\n");
+		return FAILED;
+	}
+	if (CD(cmd)->status == LOCKED) {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio: abort, queue slot " "locked.\n"));
+		return FAILED;
+	}
+	panic("eata_pio: abort: invalid slot status\n");
+}
+
+static int eata_pio_host_reset(struct scsi_cmnd *cmd)
+{
+	uint x, limit = 0;
+	unsigned char success = 0;
+	struct scsi_cmnd *sp;
+	struct Scsi_Host *host = cmd->device->host;
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset called pid:%ld target:" " %x lun: %x reason %x\n", cmd->pid, cmd->device->id, cmd->device->lun, cmd->abort_reason));
+
+	if (HD(cmd)->state == RESET) {
+		printk(KERN_WARNING "eata_pio_reset: exit, already in reset.\n");
+		return FAILED;
+	}
+
+	/* force all slots to be free */
+
+	for (x = 0; x < cmd->device->host->can_queue; x++) {
+
+		if (HD(cmd)->ccb[x].status == FREE)
+			continue;
+
+		sp = HD(cmd)->ccb[x].cmd;
+		HD(cmd)->ccb[x].status = RESET;
+		printk(KERN_WARNING "eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+
+		if (sp == NULL)
+			panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
+	}
+
+	/* hard reset the HBA  */
+	outb(EATA_CMD_RESET, (uint) cmd->device->host->base + HA_WCOMMAND);
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: board reset done.\n"));
+	HD(cmd)->state = RESET;
+
+	spin_unlock_irq(host->host_lock);
+	msleep(3000);
+	spin_lock_irq(host->host_lock);
+
+	DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: interrupts disabled, " "loops %d.\n", limit));
+
+	for (x = 0; x < cmd->device->host->can_queue; x++) {
+
+		/* Skip slots already set free by interrupt */
+		if (HD(cmd)->ccb[x].status != RESET)
+			continue;
+
+		sp = HD(cmd)->ccb[x].cmd;
+		sp->result = DID_RESET << 16;
+
+		/* This mailbox is terminated */
+		printk(KERN_WARNING "eata_pio_reset: reset ccb %d.\n", x);
+		HD(cmd)->ccb[x].status = FREE;
+
+		sp->scsi_done(sp);
+	}
+
+	HD(cmd)->state = 0;
+
+	if (success) {		/* hmmm... */
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, success.\n"));
+		return SUCCESS;
+	} else {
+		DBG(DBG_ABNORM, printk(KERN_WARNING "eata_pio_reset: exit, wakeup.\n"));
+		return FAILED;
+	}
+}
+
+static char *get_pio_board_data(unsigned long base, uint irq, uint id, unsigned long cplen, unsigned short cppadlen)
+{
+	struct eata_ccb cp;
+	static char buff[256];
+	int z;
+
+	memset(&cp, 0, sizeof(struct eata_ccb));
+	memset(buff, 0, sizeof(buff));
+
+	cp.DataIn = 1;
+	cp.Interpret = 1;	/* Interpret command */
+
+	cp.cp_datalen = htonl(254);
+	cp.cp_dataDMA = htonl(0);
+
+	cp.cp_id = id;
+	cp.cp_lun = 0;
+
+	cp.cp_cdb[0] = INQUIRY;
+	cp.cp_cdb[1] = 0;
+	cp.cp_cdb[2] = 0;
+	cp.cp_cdb[3] = 0;
+	cp.cp_cdb[4] = 254;
+	cp.cp_cdb[5] = 0;
+
+	if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP))
+		return (NULL);
+	while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+	outsw(base + HA_RDATA, &cp, cplen);
+	outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+	for (z = 0; z < cppadlen; z++)
+		outw(0, base + HA_RDATA);
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY);
+	if (inb(base + HA_RSTATUS) & HA_SERROR)
+		return (NULL);
+	else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+		return (NULL);
+	else {
+		insw(base + HA_RDATA, &buff, 127);
+		while (inb(base + HA_RSTATUS) & HA_SDRQ)
+			inw(base + HA_RDATA);
+		return (buff);
+	}
+}
+
+static int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+{
+	unsigned long loop = HZ / 2;
+	int z;
+	unsigned short *p;
+
+	if (!request_region(base, 9, "eata_pio"))
+		return 0;
+
+	memset(buf, 0, sizeof(struct get_conf));
+
+	while (inb(base + HA_RSTATUS) & HA_SBUSY)
+		if (--loop == 0)
+			goto fail;
+
+	DBG(DBG_PIO && DBG_PROBE, printk(KERN_DEBUG "Issuing PIO READ CONFIG to HBA at %#x\n", base));
+	eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
+
+	loop = HZ / 2;
+	for (p = (unsigned short *) buf; (long) p <= ((long) buf + (sizeof(struct get_conf) / 2)); p++) {
+		while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+			if (--loop == 0)
+				goto fail;
+
+		loop = HZ / 2;
+		*p = inw(base + HA_RDATA);
+	}
+	if (inb(base + HA_RSTATUS) & HA_SERROR) {
+		DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during "
+					"transfer for HBA at %x\n", base));
+		goto fail;
+	}
+
+	if (htonl(EATA_SIGNATURE) != buf->signature)
+		goto fail;
+
+	DBG(DBG_PIO && DBG_PROBE, printk(KERN_NOTICE "EATA Controller found "
+				"at %#4x EATA Level: %x\n",
+				base, (uint) (buf->version)));
+
+	while (inb(base + HA_RSTATUS) & HA_SDRQ)
+		inw(base + HA_RDATA);
+
+	if (!ALLOW_DMA_BOARDS) {
+		for (z = 0; z < MAXISA; z++)
+			if (base == ISAbases[z]) {
+				buf->IRQ = ISAirqs[z];
+				break;
+			}
+	}
+
+	return 1;
+
+ fail:
+	release_region(base, 9);
+	return 0;
+}
+
+static void print_pio_config(struct get_conf *gc)
+{
+	printk("Please check values: (read config data)\n");
+	printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n", (uint) ntohl(gc->len), gc->version, gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+	printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n", gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2], gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+	printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n", gc->IRQ, gc->IRQ_TR, gc->FORCADR, gc->MAX_CHAN, gc->ID_qest);
+}
+
+static uint print_selftest(uint base)
+{
+	unsigned char buffer[512];
+#ifdef VERBOSE_SETUP
+	int z;
+#endif
+
+	printk("eata_pio: executing controller self test & setup...\n");
+	while (inb(base + HA_RSTATUS) & HA_SBUSY);
+	outb(EATA_CMD_PIO_SETUPTEST, base + HA_WCOMMAND);
+	do {
+		while (inb(base + HA_RSTATUS) & HA_SBUSY)
+			/* nothing */ ;
+		if (inb(base + HA_RSTATUS) & HA_SDRQ) {
+			insw(base + HA_RDATA, &buffer, 256);
+#ifdef VERBOSE_SETUP
+			/* no beeps please... */
+			for (z = 0; z < 511 && buffer[z]; z++)
+				if (buffer[z] != 7)
+					printk("%c", buffer[z]);
+#endif
+		}
+	} while (inb(base + HA_RSTATUS) & (HA_SBUSY | HA_SDRQ));
+
+	return (!(inb(base + HA_RSTATUS) & HA_SERROR));
+}
+
+static int register_pio_HBA(long base, struct get_conf *gc)
+{
+	unsigned long size = 0;
+	char *buff;
+	unsigned long cplen;
+	unsigned short cppadlen;
+	struct Scsi_Host *sh;
+	hostdata *hd;
+
+	DBG(DBG_REGISTER, print_pio_config(gc));
+
+	if (gc->DMA_support) {
+		printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n", base);
+		if (!ALLOW_DMA_BOARDS)
+			return 0;
+	}
+
+	if ((buff = get_pio_board_data((uint) base, gc->IRQ, gc->scsi_id[3], cplen = (htonl(gc->cplen) + 1) / 2, cppadlen = (htons(gc->cppadlen) + 1) / 2)) == NULL) {
+		printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (unsigned long) base);
+		return 0;
+	}
+
+	if (!print_selftest(base) && !ALLOW_DMA_BOARDS) {
+		printk("HBA at %#lx failed while performing self test & setup.\n", (unsigned long) base);
+		return 0;
+	}
+
+	size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+
+	sh = scsi_register(&driver_template, size);
+	if (sh == NULL)
+		return 0;
+
+	if (!reg_IRQ[gc->IRQ]) {	/* Interrupt already registered ? */
+		if (!request_irq(gc->IRQ, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", sh)) {
+			reg_IRQ[gc->IRQ]++;
+			if (!gc->IRQ_TR)
+				reg_IRQL[gc->IRQ] = 1;	/* IRQ is edge triggered */
+		} else {
+			printk("Couldn't allocate IRQ %d, Sorry.\n", gc->IRQ);
+			return 0;
+		}
+	} else {		/* More than one HBA on this IRQ */
+		if (reg_IRQL[gc->IRQ]) {
+			printk("Can't support more than one HBA on this IRQ,\n" "  if the IRQ is edge triggered. Sorry.\n");
+			return 0;
+		} else
+			reg_IRQ[gc->IRQ]++;
+	}
+
+	hd = SD(sh);
+
+	memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
+	memset(hd->reads, 0, sizeof(unsigned long) * 26);
+
+	strlcpy(SD(sh)->vendor, &buff[8], sizeof(SD(sh)->vendor));
+	strlcpy(SD(sh)->name, &buff[16], sizeof(SD(sh)->name));
+	SD(sh)->revision[0] = buff[32];
+	SD(sh)->revision[1] = buff[33];
+	SD(sh)->revision[2] = buff[34];
+	SD(sh)->revision[3] = '.';
+	SD(sh)->revision[4] = buff[35];
+	SD(sh)->revision[5] = 0;
+
+	switch (ntohl(gc->len)) {
+	case 0x1c:
+		SD(sh)->EATA_revision = 'a';
+		break;
+	case 0x1e:
+		SD(sh)->EATA_revision = 'b';
+		break;
+	case 0x22:
+		SD(sh)->EATA_revision = 'c';
+		break;
+	case 0x24:
+		SD(sh)->EATA_revision = 'z';
+	default:
+		SD(sh)->EATA_revision = '?';
+	}
+
+	if (ntohl(gc->len) >= 0x22) {
+		if (gc->is_PCI)
+			hd->bustype = IS_PCI;
+		else if (gc->is_EISA)
+			hd->bustype = IS_EISA;
+		else
+			hd->bustype = IS_ISA;
+	} else {
+		if (buff[21] == '4')
+			hd->bustype = IS_PCI;
+		else if (buff[21] == '2')
+			hd->bustype = IS_EISA;
+		else
+			hd->bustype = IS_ISA;
+	}
+
+	SD(sh)->cplen = cplen;
+	SD(sh)->cppadlen = cppadlen;
+	SD(sh)->hostid = gc->scsi_id[3];
+	SD(sh)->devflags = 1 << gc->scsi_id[3];
+	SD(sh)->moresupport = gc->MORE_support;
+	sh->unique_id = base;
+	sh->base = base;
+	sh->io_port = base;
+	sh->n_io_port = 9;
+	sh->irq = gc->IRQ;
+	sh->dma_channel = PIO;
+	sh->this_id = gc->scsi_id[3];
+	sh->can_queue = 1;
+	sh->cmd_per_lun = 1;
+	sh->sg_tablesize = SG_ALL;
+
+	hd->channel = 0;
+
+	sh->max_id = 8;
+	sh->max_lun = 8;
+
+	if (gc->SECOND)
+		hd->primary = 0;
+	else
+		hd->primary = 1;
+
+	sh->unchecked_isa_dma = 0;	/* We can only do PIO */
+
+	hd->next = NULL;	/* build a linked list of all HBAs */
+	hd->prev = last_HBA;
+	if (hd->prev != NULL)
+		SD(hd->prev)->next = sh;
+	last_HBA = sh;
+	if (first_HBA == NULL)
+		first_HBA = sh;
+	registered_HBAs++;
+	return (1);
+}
+
+static void find_pio_ISA(struct get_conf *buf)
+{
+	int i;
+
+	for (i = 0; i < MAXISA; i++) {
+		if (!ISAbases[i])
+			continue;
+		if (!get_pio_conf_PIO(ISAbases[i], buf))
+			continue;
+		if (!register_pio_HBA(ISAbases[i], buf))
+			release_region(ISAbases[i], 9);
+		else
+			ISAbases[i] = 0;
+	}
+	return;
+}
+
+static void find_pio_EISA(struct get_conf *buf)
+{
+	u32 base;
+	int i;
+
+#ifdef CHECKPAL
+	u8 pal1, pal2, pal3;
+#endif
+
+	for (i = 0; i < MAXEISA; i++) {
+		if (EISAbases[i]) {	/* Still a possibility ?          */
+
+			base = 0x1c88 + (i * 0x1000);
+#ifdef CHECKPAL
+			pal1 = inb((u16) base - 8);
+			pal2 = inb((u16) base - 7);
+			pal3 = inb((u16) base - 6);
+
+			if (((pal1 == 0x12) && (pal2 == 0x14)) || ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) || ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
+				DBG(DBG_PROBE, printk(KERN_NOTICE "EISA EATA id tags found: " "%x %x %x \n", (int) pal1, (int) pal2, (int) pal3));
+#endif
+				if (get_pio_conf_PIO(base, buf)) {
+					DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
+					if (buf->IRQ) {
+						if (!register_pio_HBA(base, buf))
+							release_region(base, 9);
+					} else {
+						printk(KERN_NOTICE "eata_dma: No valid IRQ. HBA " "removed from list\n");
+						release_region(base, 9);
+					}
+				}
+				/* Nothing found here so we take it from the list */
+				EISAbases[i] = 0;
+#ifdef CHECKPAL
+			}
+#endif
+		}
+	}
+	return;
+}
+
+static void find_pio_PCI(struct get_conf *buf)
+{
+#ifndef CONFIG_PCI
+	printk("eata_dma: kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+#else
+	struct pci_dev *dev = NULL;
+	u32 base, x;
+
+	while ((dev = pci_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, dev)) != NULL) {
+		DBG(DBG_PROBE && DBG_PCI, printk("eata_pio: find_PCI, HBA at %s\n", pci_name(dev)));
+		if (pci_enable_device(dev))
+			continue;
+		pci_set_master(dev);
+		base = pci_resource_flags(dev, 0);
+		if (base & IORESOURCE_MEM) {
+			printk("eata_pio: invalid base address of device %s\n", pci_name(dev));
+			continue;
+		}
+		base = pci_resource_start(dev, 0);
+		/* EISA tag there ? */
+		if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+			continue;	/* Jep, it's forced, so move on  */
+		base += 0x10;	/* Now, THIS is the real address */
+		if (base != 0x1f8) {
+			/* We didn't find it in the primary search */
+			if (get_pio_conf_PIO(base, buf)) {
+				if (buf->FORCADR) {	/* If the address is forced */
+					release_region(base, 9);
+					continue;	/* we'll find it later      */
+				}
+
+				/* OK. We made it till here, so we can go now  
+				 * and register it. We  only have to check and 
+				 * eventually remove it from the EISA and ISA list 
+				 */
+
+				if (!register_pio_HBA(base, buf)) {
+					release_region(base, 9);
+					continue;
+				}
+
+				if (base < 0x1000) {
+					for (x = 0; x < MAXISA; ++x) {
+						if (ISAbases[x] == base) {
+							ISAbases[x] = 0;
+							break;
+						}
+					}
+				} else if ((base & 0x0fff) == 0x0c88) {
+					x = (base >> 12) & 0x0f;
+					EISAbases[x] = 0;
+				}
+			}
+#ifdef CHECK_BLINK
+			else if (check_blink_state(base)) {
+				printk("eata_pio: HBA is in BLINK state.\n" "Consult your HBAs manual to correct this.\n");
+			}
+#endif
+		}
+	}
+#endif				/* #ifndef CONFIG_PCI */
+}
+
+static int eata_pio_detect(struct scsi_host_template *tpnt)
+{
+	struct Scsi_Host *HBA_ptr;
+	struct get_conf gc;
+	int i;
+
+	find_pio_PCI(&gc);
+	find_pio_EISA(&gc);
+	find_pio_ISA(&gc);
+
+	for (i = 0; i <= MAXIRQ; i++)
+		if (reg_IRQ[i])
+			request_irq(i, do_eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO", NULL);
+
+	HBA_ptr = first_HBA;
+
+	if (registered_HBAs != 0) {
+		printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
+		       "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n" "            Alfred Arnold,   a.arnold@kfa-juelich.de\n" "This release only supports DASD devices (harddisks)\n", VER_MAJOR, VER_MINOR, VER_SUB);
+
+		printk("Registered HBAs:\n");
+		printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr:" " QS: SG: CPL:\n");
+		for (i = 1; i <= registered_HBAs; i++) {
+			printk("scsi%-2d: %.10s v%s 2.0%c  %s %#.4x   %2d   %d   %d   %c"
+			       "  %2d  %2d  %2d\n",
+			       HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+			       SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P') ?
+			       "PCI " : (SD(HBA_ptr)->bustype == 'E') ? "EISA" : "ISA ",
+			       (uint) HBA_ptr->base, HBA_ptr->irq, SD(HBA_ptr)->channel, HBA_ptr->this_id,
+			       SD(HBA_ptr)->primary ? 'Y' : 'N', HBA_ptr->can_queue,
+			       HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+			HBA_ptr = SD(HBA_ptr)->next;
+		}
+	}
+	return (registered_HBAs);
+}
+
+static struct scsi_host_template driver_template = {
+	.proc_name		= "eata_pio",
+	.name              	= "EATA (Extended Attachment) PIO driver",
+	.proc_info         	= eata_pio_proc_info,
+	.detect            	= eata_pio_detect,
+	.release           	= eata_pio_release,
+	.queuecommand      	= eata_pio_queue,
+	.eh_abort_handler  	= eata_pio_abort,
+	.eh_host_reset_handler	= eata_pio_host_reset,
+	.use_clustering    	= ENABLE_CLUSTERING,
+};
+
+MODULE_AUTHOR("Michael Neuffer, Alfred Arnold");
+MODULE_DESCRIPTION("EATA SCSI PIO driver");
+MODULE_LICENSE("GPL");
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h
new file mode 100644
index 0000000..7deeb93
--- /dev/null
+++ b/drivers/scsi/eata_pio.h
@@ -0,0 +1,53 @@
+/********************************************************
+* Header file for eata_pio.c Linux EATA-PIO SCSI driver *
+* (c) 1993-96 Michael Neuffer  	                        *
+*********************************************************
+* last change: 2002/11/02				*
+********************************************************/
+
+
+#ifndef _EATA_PIO_H
+#define _EATA_PIO_H
+
+#define VER_MAJOR 0
+#define VER_MINOR 0
+#define VER_SUB	  "1b"
+
+/************************************************************************
+ * Here you can switch parts of the code on and of			*
+ ************************************************************************/
+
+#define VERBOSE_SETUP		/* show startup screen of 2001 */
+#define ALLOW_DMA_BOARDS 1
+
+/************************************************************************
+ * Debug options.							* 
+ * Enable DEBUG and whichever options you require.			*
+ ************************************************************************/
+#define DEBUG_EATA	1	/* Enable debug code.                       */
+#define DPT_DEBUG	0	/* Bobs special                             */
+#define DBG_DELAY	0	/* Build in delays so debug messages can be
+				 * be read before they vanish of the top of
+				 * the screen!
+				 */
+#define DBG_PROBE	0	/* Debug probe routines.                    */
+#define DBG_ISA		0	/* Trace ISA routines                       */
+#define DBG_EISA	0	/* Trace EISA routines                      */
+#define DBG_PCI		0	/* Trace PCI routines                       */
+#define DBG_PIO		0	/* Trace get_config_PIO                     */
+#define DBG_COM		0	/* Trace command call                       */
+#define DBG_QUEUE	0	/* Trace command queueing.                  */
+#define DBG_INTR	0	/* Trace interrupt service routine.         */
+#define DBG_INTR2	0	/* Trace interrupt service routine.         */
+#define DBG_PROC	0	/* Debug proc-fs related statistics         */
+#define DBG_PROC_WRITE	0
+#define DBG_REGISTER	0	/* */
+#define DBG_ABNORM	1	/* Debug abnormal actions (reset, abort)    */
+
+#if DEBUG_EATA
+#define DBG(x, y)   if ((x)) {y;}
+#else
+#define DBG(x, y)
+#endif
+
+#endif				/* _EATA_PIO_H */
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
new file mode 100644
index 0000000..d8ab73b
--- /dev/null
+++ b/drivers/scsi/esp.c
@@ -0,0 +1,4402 @@
+/* $Id: esp.c,v 1.101 2002/01/15 06:48:55 davem Exp $
+ * esp.c:  EnhancedScsiProcessor Sun SCSI driver code.
+ *
+ * Copyright (C) 1995, 1998 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+/* TODO:
+ *
+ * 1) Maybe disable parity checking in config register one for SCSI1
+ *    targets.  (Gilmore says parity error on the SBus can lock up
+ *    old sun4c's)
+ * 2) Add support for DMA2 pipelining.
+ * 3) Add tagged queueing.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include "esp.h"
+
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#ifndef __sparc_v9__
+#include <asm/machines.h>
+#include <asm/idprom.h>
+#endif
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#define DEBUG_ESP
+/* #define DEBUG_ESP_HME */
+/* #define DEBUG_ESP_DATA */
+/* #define DEBUG_ESP_QUEUE */
+/* #define DEBUG_ESP_DISCONNECT */
+/* #define DEBUG_ESP_STATUS */
+/* #define DEBUG_ESP_PHASES */
+/* #define DEBUG_ESP_WORKBUS */
+/* #define DEBUG_STATE_MACHINE */
+/* #define DEBUG_ESP_CMDS */
+/* #define DEBUG_ESP_IRQS */
+/* #define DEBUG_SDTR */
+/* #define DEBUG_ESP_SG */
+
+/* Use the following to sprinkle debugging messages in a way which
+ * suits you if combinations of the above become too verbose when
+ * trying to track down a specific problem.
+ */
+/* #define DEBUG_ESP_MISC */
+
+#if defined(DEBUG_ESP)
+#define ESPLOG(foo)  printk foo
+#else
+#define ESPLOG(foo)
+#endif /* (DEBUG_ESP) */
+
+#if defined(DEBUG_ESP_HME)
+#define ESPHME(foo)  printk foo
+#else
+#define ESPHME(foo)
+#endif
+
+#if defined(DEBUG_ESP_DATA)
+#define ESPDATA(foo)  printk foo
+#else
+#define ESPDATA(foo)
+#endif
+
+#if defined(DEBUG_ESP_QUEUE)
+#define ESPQUEUE(foo)  printk foo
+#else
+#define ESPQUEUE(foo)
+#endif
+
+#if defined(DEBUG_ESP_DISCONNECT)
+#define ESPDISC(foo)  printk foo
+#else
+#define ESPDISC(foo)
+#endif
+
+#if defined(DEBUG_ESP_STATUS)
+#define ESPSTAT(foo)  printk foo
+#else
+#define ESPSTAT(foo)
+#endif
+
+#if defined(DEBUG_ESP_PHASES)
+#define ESPPHASE(foo)  printk foo
+#else
+#define ESPPHASE(foo)
+#endif
+
+#if defined(DEBUG_ESP_WORKBUS)
+#define ESPBUS(foo)  printk foo
+#else
+#define ESPBUS(foo)
+#endif
+
+#if defined(DEBUG_ESP_IRQS)
+#define ESPIRQ(foo)  printk foo
+#else
+#define ESPIRQ(foo)
+#endif
+
+#if defined(DEBUG_SDTR)
+#define ESPSDTR(foo)  printk foo
+#else
+#define ESPSDTR(foo)
+#endif
+
+#if defined(DEBUG_ESP_MISC)
+#define ESPMISC(foo)  printk foo
+#else
+#define ESPMISC(foo)
+#endif
+
+/* Command phase enumeration. */
+enum {
+	not_issued    = 0x00,  /* Still in the issue_SC queue.          */
+
+	/* Various forms of selecting a target. */
+#define in_slct_mask    0x10
+	in_slct_norm  = 0x10,  /* ESP is arbitrating, normal selection  */
+	in_slct_stop  = 0x11,  /* ESP will select, then stop with IRQ   */
+	in_slct_msg   = 0x12,  /* select, then send a message           */
+	in_slct_tag   = 0x13,  /* select and send tagged queue msg      */
+	in_slct_sneg  = 0x14,  /* select and acquire sync capabilities  */
+
+	/* Any post selection activity. */
+#define in_phases_mask  0x20
+	in_datain     = 0x20,  /* Data is transferring from the bus     */
+	in_dataout    = 0x21,  /* Data is transferring to the bus       */
+	in_data_done  = 0x22,  /* Last DMA data operation done (maybe)  */
+	in_msgin      = 0x23,  /* Eating message from target            */
+	in_msgincont  = 0x24,  /* Eating more msg bytes from target     */
+	in_msgindone  = 0x25,  /* Decide what to do with what we got    */
+	in_msgout     = 0x26,  /* Sending message to target             */
+	in_msgoutdone = 0x27,  /* Done sending msg out                  */
+	in_cmdbegin   = 0x28,  /* Sending cmd after abnormal selection  */
+	in_cmdend     = 0x29,  /* Done sending slow cmd                 */
+	in_status     = 0x2a,  /* Was in status phase, finishing cmd    */
+	in_freeing    = 0x2b,  /* freeing the bus for cmd cmplt or disc */
+	in_the_dark   = 0x2c,  /* Don't know what bus phase we are in   */
+
+	/* Special states, ie. not normal bus transitions... */
+#define in_spec_mask    0x80
+	in_abortone   = 0x80,  /* Aborting one command currently        */
+	in_abortall   = 0x81,  /* Blowing away all commands we have     */
+	in_resetdev   = 0x82,  /* SCSI target reset in progress         */
+	in_resetbus   = 0x83,  /* SCSI bus reset in progress            */
+	in_tgterror   = 0x84,  /* Target did something stupid           */
+};
+
+enum {
+	/* Zero has special meaning, see skipahead[12]. */
+/*0*/	do_never,
+
+/*1*/	do_phase_determine,
+/*2*/	do_reset_bus,
+/*3*/	do_reset_complete,
+/*4*/	do_work_bus,
+/*5*/	do_intr_end
+};
+
+/* The master ring of all esp hosts we are managing in this driver. */
+static struct esp *espchain;
+static DEFINE_SPINLOCK(espchain_lock);
+static int esps_running = 0;
+
+/* Forward declarations. */
+static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+
+/* Debugging routines */
+struct esp_cmdstrings {
+	u8 cmdchar;
+	char *text;
+} esp_cmd_strings[] = {
+	/* Miscellaneous */
+	{ ESP_CMD_NULL, "ESP_NOP", },
+	{ ESP_CMD_FLUSH, "FIFO_FLUSH", },
+	{ ESP_CMD_RC, "RSTESP", },
+	{ ESP_CMD_RS, "RSTSCSI", },
+	/* Disconnected State Group */
+	{ ESP_CMD_RSEL, "RESLCTSEQ", },
+	{ ESP_CMD_SEL, "SLCTNATN", },
+	{ ESP_CMD_SELA, "SLCTATN", },
+	{ ESP_CMD_SELAS, "SLCTATNSTOP", },
+	{ ESP_CMD_ESEL, "ENSLCTRESEL", },
+	{ ESP_CMD_DSEL, "DISSELRESEL", },
+	{ ESP_CMD_SA3, "SLCTATN3", },
+	{ ESP_CMD_RSEL3, "RESLCTSEQ", },
+	/* Target State Group */
+	{ ESP_CMD_SMSG, "SNDMSG", },
+	{ ESP_CMD_SSTAT, "SNDSTATUS", },
+	{ ESP_CMD_SDATA, "SNDDATA", },
+	{ ESP_CMD_DSEQ, "DISCSEQ", },
+	{ ESP_CMD_TSEQ, "TERMSEQ", },
+	{ ESP_CMD_TCCSEQ, "TRGTCMDCOMPSEQ", },
+	{ ESP_CMD_DCNCT, "DISC", },
+	{ ESP_CMD_RMSG, "RCVMSG", },
+	{ ESP_CMD_RCMD, "RCVCMD", },
+	{ ESP_CMD_RDATA, "RCVDATA", },
+	{ ESP_CMD_RCSEQ, "RCVCMDSEQ", },
+	/* Initiator State Group */
+	{ ESP_CMD_TI, "TRANSINFO", },
+	{ ESP_CMD_ICCSEQ, "INICMDSEQCOMP", },
+	{ ESP_CMD_MOK, "MSGACCEPTED", },
+	{ ESP_CMD_TPAD, "TPAD", },
+	{ ESP_CMD_SATN, "SATN", },
+	{ ESP_CMD_RATN, "RATN", },
+};
+#define NUM_ESP_COMMANDS  ((sizeof(esp_cmd_strings)) / (sizeof(struct esp_cmdstrings)))
+
+/* Print textual representation of an ESP command */
+static inline void esp_print_cmd(u8 espcmd)
+{
+	u8 dma_bit = espcmd & ESP_CMD_DMA;
+	int i;
+
+	espcmd &= ~dma_bit;
+	for (i = 0; i < NUM_ESP_COMMANDS; i++)
+		if (esp_cmd_strings[i].cmdchar == espcmd)
+			break;
+	if (i == NUM_ESP_COMMANDS)
+		printk("ESP_Unknown");
+	else
+		printk("%s%s", esp_cmd_strings[i].text,
+		       ((dma_bit) ? "+DMA" : ""));
+}
+
+/* Print the status register's value */
+static inline void esp_print_statreg(u8 statreg)
+{
+	u8 phase;
+
+	printk("STATUS<");
+	phase = statreg & ESP_STAT_PMASK;
+	printk("%s,", (phase == ESP_DOP ? "DATA-OUT" :
+		       (phase == ESP_DIP ? "DATA-IN" :
+			(phase == ESP_CMDP ? "COMMAND" :
+			 (phase == ESP_STATP ? "STATUS" :
+			  (phase == ESP_MOP ? "MSG-OUT" :
+			   (phase == ESP_MIP ? "MSG_IN" :
+			    "unknown")))))));
+	if (statreg & ESP_STAT_TDONE)
+		printk("TRANS_DONE,");
+	if (statreg & ESP_STAT_TCNT)
+		printk("TCOUNT_ZERO,");
+	if (statreg & ESP_STAT_PERR)
+		printk("P_ERROR,");
+	if (statreg & ESP_STAT_SPAM)
+		printk("SPAM,");
+	if (statreg & ESP_STAT_INTR)
+		printk("IRQ,");
+	printk(">");
+}
+
+/* Print the interrupt register's value */
+static inline void esp_print_ireg(u8 intreg)
+{
+	printk("INTREG< ");
+	if (intreg & ESP_INTR_S)
+		printk("SLCT_NATN ");
+	if (intreg & ESP_INTR_SATN)
+		printk("SLCT_ATN ");
+	if (intreg & ESP_INTR_RSEL)
+		printk("RSLCT ");
+	if (intreg & ESP_INTR_FDONE)
+		printk("FDONE ");
+	if (intreg & ESP_INTR_BSERV)
+		printk("BSERV ");
+	if (intreg & ESP_INTR_DC)
+		printk("DISCNCT ");
+	if (intreg & ESP_INTR_IC)
+		printk("ILL_CMD ");
+	if (intreg & ESP_INTR_SR)
+		printk("SCSI_BUS_RESET ");
+	printk(">");
+}
+
+/* Print the sequence step registers contents */
+static inline void esp_print_seqreg(u8 stepreg)
+{
+	stepreg &= ESP_STEP_VBITS;
+	printk("STEP<%s>",
+	       (stepreg == ESP_STEP_ASEL ? "SLCT_ARB_CMPLT" :
+		(stepreg == ESP_STEP_SID ? "1BYTE_MSG_SENT" :
+		 (stepreg == ESP_STEP_NCMD ? "NOT_IN_CMD_PHASE" :
+		  (stepreg == ESP_STEP_PPC ? "CMD_BYTES_LOST" :
+		   (stepreg == ESP_STEP_FINI4 ? "CMD_SENT_OK" :
+		    "UNKNOWN"))))));
+}
+
+static char *phase_string(int phase)
+{
+	switch (phase) {
+	case not_issued:
+		return "UNISSUED";
+	case in_slct_norm:
+		return "SLCTNORM";
+	case in_slct_stop:
+		return "SLCTSTOP";
+	case in_slct_msg:
+		return "SLCTMSG";
+	case in_slct_tag:
+		return "SLCTTAG";
+	case in_slct_sneg:
+		return "SLCTSNEG";
+	case in_datain:
+		return "DATAIN";
+	case in_dataout:
+		return "DATAOUT";
+	case in_data_done:
+		return "DATADONE";
+	case in_msgin:
+		return "MSGIN";
+	case in_msgincont:
+		return "MSGINCONT";
+	case in_msgindone:
+		return "MSGINDONE";
+	case in_msgout:
+		return "MSGOUT";
+	case in_msgoutdone:
+		return "MSGOUTDONE";
+	case in_cmdbegin:
+		return "CMDBEGIN";
+	case in_cmdend:
+		return "CMDEND";
+	case in_status:
+		return "STATUS";
+	case in_freeing:
+		return "FREEING";
+	case in_the_dark:
+		return "CLUELESS";
+	case in_abortone:
+		return "ABORTONE";
+	case in_abortall:
+		return "ABORTALL";
+	case in_resetdev:
+		return "RESETDEV";
+	case in_resetbus:
+		return "RESETBUS";
+	case in_tgterror:
+		return "TGTERROR";
+	default:
+		return "UNKNOWN";
+	};
+}
+
+#ifdef DEBUG_STATE_MACHINE
+static inline void esp_advance_phase(struct scsi_cmnd *s, int newphase)
+{
+	ESPLOG(("<%s>", phase_string(newphase)));
+	s->SCp.sent_command = s->SCp.phase;
+	s->SCp.phase = newphase;
+}
+#else
+#define esp_advance_phase(__s, __newphase) \
+	(__s)->SCp.sent_command = (__s)->SCp.phase; \
+	(__s)->SCp.phase = (__newphase);
+#endif
+
+#ifdef DEBUG_ESP_CMDS
+static inline void esp_cmd(struct esp *esp, u8 cmd)
+{
+	esp->espcmdlog[esp->espcmdent] = cmd;
+	esp->espcmdent = (esp->espcmdent + 1) & 31;
+	sbus_writeb(cmd, esp->eregs + ESP_CMD);
+}
+#else
+#define esp_cmd(__esp, __cmd)	\
+	sbus_writeb((__cmd), ((__esp)->eregs) + ESP_CMD)
+#endif
+
+#define ESP_INTSOFF(__dregs)	\
+	sbus_writel(sbus_readl((__dregs)+DMA_CSR)&~(DMA_INT_ENAB), (__dregs)+DMA_CSR)
+#define ESP_INTSON(__dregs)	\
+	sbus_writel(sbus_readl((__dregs)+DMA_CSR)|DMA_INT_ENAB, (__dregs)+DMA_CSR)
+#define ESP_IRQ_P(__dregs)	\
+	(sbus_readl((__dregs)+DMA_CSR) & (DMA_HNDL_INTR|DMA_HNDL_ERROR))
+
+/* How we use the various Linux SCSI data structures for operation.
+ *
+ * struct scsi_cmnd:
+ *
+ *   We keep track of the synchronous capabilities of a target
+ *   in the device member, using sync_min_period and
+ *   sync_max_offset.  These are the values we directly write
+ *   into the ESP registers while running a command.  If offset
+ *   is zero the ESP will use asynchronous transfers.
+ *   If the borken flag is set we assume we shouldn't even bother
+ *   trying to negotiate for synchronous transfer as this target
+ *   is really stupid.  If we notice the target is dropping the
+ *   bus, and we have been allowing it to disconnect, we clear
+ *   the disconnect flag.
+ */
+
+
+/* Manipulation of the ESP command queues.  Thanks to the aha152x driver
+ * and its author, Juergen E. Fischer, for the methods used here.
+ * Note that these are per-ESP queues, not global queues like
+ * the aha152x driver uses.
+ */
+static inline void append_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
+{
+	struct scsi_cmnd *end;
+
+	new_SC->host_scribble = (unsigned char *) NULL;
+	if (!*SC)
+		*SC = new_SC;
+	else {
+		for (end=*SC;end->host_scribble;end=(struct scsi_cmnd *)end->host_scribble)
+			;
+		end->host_scribble = (unsigned char *) new_SC;
+	}
+}
+
+static inline void prepend_SC(struct scsi_cmnd **SC, struct scsi_cmnd *new_SC)
+{
+	new_SC->host_scribble = (unsigned char *) *SC;
+	*SC = new_SC;
+}
+
+static inline struct scsi_cmnd *remove_first_SC(struct scsi_cmnd **SC)
+{
+	struct scsi_cmnd *ptr;
+	ptr = *SC;
+	if (ptr)
+		*SC = (struct scsi_cmnd *) (*SC)->host_scribble;
+	return ptr;
+}
+
+static inline struct scsi_cmnd *remove_SC(struct scsi_cmnd **SC, int target, int lun)
+{
+	struct scsi_cmnd *ptr, *prev;
+
+	for (ptr = *SC, prev = NULL;
+	     ptr && ((ptr->device->id != target) || (ptr->device->lun != lun));
+	     prev = ptr, ptr = (struct scsi_cmnd *) ptr->host_scribble)
+		;
+	if (ptr) {
+		if (prev)
+			prev->host_scribble=ptr->host_scribble;
+		else
+			*SC=(struct scsi_cmnd *)ptr->host_scribble;
+	}
+	return ptr;
+}
+
+/* Resetting various pieces of the ESP scsi driver chipset/buses. */
+static void esp_reset_dma(struct esp *esp)
+{
+	int can_do_burst16, can_do_burst32, can_do_burst64;
+	int can_do_sbus64;
+	u32 tmp;
+
+	can_do_burst16 = (esp->bursts & DMA_BURST16) != 0;
+	can_do_burst32 = (esp->bursts & DMA_BURST32) != 0;
+	can_do_burst64 = 0;
+	can_do_sbus64 = 0;
+	if (sbus_can_dma_64bit(esp->sdev))
+		can_do_sbus64 = 1;
+	if (sbus_can_burst64(esp->sdev))
+		can_do_burst64 = (esp->bursts & DMA_BURST64) != 0;
+
+	/* Punt the DVMA into a known state. */
+	if (esp->dma->revision != dvmahme) {
+		tmp = sbus_readl(esp->dregs + DMA_CSR);
+		sbus_writel(tmp | DMA_RST_SCSI, esp->dregs + DMA_CSR);
+		sbus_writel(tmp & ~DMA_RST_SCSI, esp->dregs + DMA_CSR);
+	}
+	switch (esp->dma->revision) {
+	case dvmahme:
+		/* This is the HME DVMA gate array. */
+
+		sbus_writel(DMA_RESET_FAS366, esp->dregs + DMA_CSR);
+		sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
+
+		esp->prev_hme_dmacsr = (DMA_PARITY_OFF|DMA_2CLKS|DMA_SCSI_DISAB|DMA_INT_ENAB);
+		esp->prev_hme_dmacsr &= ~(DMA_ENABLE|DMA_ST_WRITE|DMA_BRST_SZ);
+
+		if (can_do_burst64)
+			esp->prev_hme_dmacsr |= DMA_BRST64;
+		else if (can_do_burst32)
+			esp->prev_hme_dmacsr |= DMA_BRST32;
+
+		if (can_do_sbus64) {
+			esp->prev_hme_dmacsr |= DMA_SCSI_SBUS64;
+			sbus_set_sbus64(esp->sdev, esp->bursts);
+		}
+
+		/* This chip is horrible. */
+		while (sbus_readl(esp->dregs + DMA_CSR) & DMA_PEND_READ)
+			udelay(1);
+
+		sbus_writel(0, esp->dregs + DMA_CSR);
+		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
+
+		/* This is necessary to avoid having the SCSI channel
+		 * engine lock up on us.
+		 */
+		sbus_writel(0, esp->dregs + DMA_ADDR);
+
+		break;
+	case dvmarev2:
+		/* This is the gate array found in the sun4m
+		 * NCR SBUS I/O subsystem.
+		 */
+		if (esp->erev != esp100) {
+			tmp = sbus_readl(esp->dregs + DMA_CSR);
+			sbus_writel(tmp | DMA_3CLKS, esp->dregs + DMA_CSR);
+		}
+		break;
+	case dvmarev3:
+		tmp = sbus_readl(esp->dregs + DMA_CSR);
+		tmp &= ~DMA_3CLKS;
+		tmp |= DMA_2CLKS;
+		if (can_do_burst32) {
+			tmp &= ~DMA_BRST_SZ;
+			tmp |= DMA_BRST32;
+		}
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+		break;
+	case dvmaesc1:
+		/* This is the DMA unit found on SCSI/Ether cards. */
+		tmp = sbus_readl(esp->dregs + DMA_CSR);
+		tmp |= DMA_ADD_ENABLE;
+		tmp &= ~DMA_BCNT_ENAB;
+		if (!can_do_burst32 && can_do_burst16) {
+			tmp |= DMA_ESC_BURST;
+		} else {
+			tmp &= ~(DMA_ESC_BURST);
+		}
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+		break;
+	default:
+		break;
+	};
+	ESP_INTSON(esp->dregs);
+}
+
+/* Reset the ESP chip, _not_ the SCSI bus. */
+static void __init esp_reset_esp(struct esp *esp)
+{
+	u8 family_code, version;
+	int i;
+
+	/* Now reset the ESP chip */
+	esp_cmd(esp, ESP_CMD_RC);
+	esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+	esp_cmd(esp, ESP_CMD_NULL | ESP_CMD_DMA);
+
+	/* Reload the configuration registers */
+	sbus_writeb(esp->cfact, esp->eregs + ESP_CFACT);
+	esp->prev_stp = 0;
+	sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
+	esp->prev_soff = 0;
+	sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
+	sbus_writeb(esp->neg_defp, esp->eregs + ESP_TIMEO);
+
+	/* This is the only point at which it is reliable to read
+	 * the ID-code for a fast ESP chip variants.
+	 */
+	esp->max_period = ((35 * esp->ccycle) / 1000);
+	if (esp->erev == fast) {
+		version = sbus_readb(esp->eregs + ESP_UID);
+		family_code = (version & 0xf8) >> 3;
+		if (family_code == 0x02)
+			esp->erev = fas236;
+		else if (family_code == 0x0a)
+			esp->erev = fashme; /* Version is usually '5'. */
+		else
+			esp->erev = fas100a;
+		ESPMISC(("esp%d: FAST chip is %s (family=%d, version=%d)\n",
+			 esp->esp_id,
+			 (esp->erev == fas236) ? "fas236" :
+			 ((esp->erev == fas100a) ? "fas100a" :
+			  "fasHME"), family_code, (version & 7)));
+
+		esp->min_period = ((4 * esp->ccycle) / 1000);
+	} else {
+		esp->min_period = ((5 * esp->ccycle) / 1000);
+	}
+	esp->max_period = (esp->max_period + 3)>>2;
+	esp->min_period = (esp->min_period + 3)>>2;
+
+	sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
+	switch (esp->erev) {
+	case esp100:
+		/* nothing to do */
+		break;
+	case esp100a:
+		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		break;
+	case esp236:
+		/* Slow 236 */
+		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		esp->prev_cfg3 = esp->config3[0];
+		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+		break;
+	case fashme:
+		esp->config2 |= (ESP_CONFIG2_HME32 | ESP_CONFIG2_HMEFENAB);
+		/* fallthrough... */
+	case fas236:
+		/* Fast 236 or HME */
+		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		for (i = 0; i < 16; i++) {
+			if (esp->erev == fashme) {
+				u8 cfg3;
+
+				cfg3 = ESP_CONFIG3_FCLOCK | ESP_CONFIG3_OBPUSH;
+				if (esp->scsi_id >= 8)
+					cfg3 |= ESP_CONFIG3_IDBIT3;
+				esp->config3[i] |= cfg3;
+			} else {
+				esp->config3[i] |= ESP_CONFIG3_FCLK;
+			}
+		}
+		esp->prev_cfg3 = esp->config3[0];
+		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+		if (esp->erev == fashme) {
+			esp->radelay = 80;
+		} else {
+			if (esp->diff)
+				esp->radelay = 0;
+			else
+				esp->radelay = 96;
+		}
+		break;
+	case fas100a:
+		/* Fast 100a */
+		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		for (i = 0; i < 16; i++)
+			esp->config3[i] |= ESP_CONFIG3_FCLOCK;
+		esp->prev_cfg3 = esp->config3[0];
+		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+		esp->radelay = 32;
+		break;
+	default:
+		panic("esp: what could it be... I wonder...");
+		break;
+	};
+
+	/* Eat any bitrot in the chip */
+	sbus_readb(esp->eregs + ESP_INTRPT);
+	udelay(100);
+}
+
+/* This places the ESP into a known state at boot time. */
+static void __init esp_bootup_reset(struct esp *esp)
+{
+	u8 tmp;
+
+	/* Reset the DMA */
+	esp_reset_dma(esp);
+
+	/* Reset the ESP */
+	esp_reset_esp(esp);
+
+	/* Reset the SCSI bus, but tell ESP not to generate an irq */
+	tmp = sbus_readb(esp->eregs + ESP_CFG1);
+	tmp |= ESP_CONFIG1_SRRDISAB;
+	sbus_writeb(tmp, esp->eregs + ESP_CFG1);
+
+	esp_cmd(esp, ESP_CMD_RS);
+	udelay(400);
+
+	sbus_writeb(esp->config1, esp->eregs + ESP_CFG1);
+
+	/* Eat any bitrot in the chip and we are done... */
+	sbus_readb(esp->eregs + ESP_INTRPT);
+}
+
+static void esp_chain_add(struct esp *esp)
+{
+	spin_lock_irq(&espchain_lock);
+	if (espchain) {
+		struct esp *elink = espchain;
+		while (elink->next)
+			elink = elink->next;
+		elink->next = esp;
+	} else {
+		espchain = esp;
+	}
+	esp->next = NULL;
+	spin_unlock_irq(&espchain_lock);
+}
+
+static void esp_chain_del(struct esp *esp)
+{
+	spin_lock_irq(&espchain_lock);
+	if (espchain == esp) {
+		espchain = esp->next;
+	} else {
+		struct esp *elink = espchain;
+		while (elink->next != esp)
+			elink = elink->next;
+		elink->next = esp->next;
+	}
+	esp->next = NULL;
+	spin_unlock_irq(&espchain_lock);
+}
+
+static int __init esp_find_dvma(struct esp *esp, struct sbus_dev *dma_sdev)
+{
+	struct sbus_dev *sdev = esp->sdev;
+	struct sbus_dma *dma;
+
+	if (dma_sdev != NULL) {
+		for_each_dvma(dma) {
+			if (dma->sdev == dma_sdev)
+				break;
+		}
+	} else {
+		for_each_dvma(dma) {
+			/* If allocated already, can't use it. */
+			if (dma->allocated)
+				continue;
+
+			if (dma->sdev == NULL)
+				break;
+
+			/* If bus + slot are the same and it has the
+			 * correct OBP name, it's ours.
+			 */
+			if (sdev->bus == dma->sdev->bus &&
+			    sdev->slot == dma->sdev->slot &&
+			    (!strcmp(dma->sdev->prom_name, "dma") ||
+			     !strcmp(dma->sdev->prom_name, "espdma")))
+				break;
+		}
+	}
+
+	/* If we don't know how to handle the dvma,
+	 * do not use this device.
+	 */
+	if (dma == NULL) {
+		printk("Cannot find dvma for ESP%d's SCSI\n", esp->esp_id);
+		return -1;
+	}
+	if (dma->allocated) {
+		printk("esp%d: can't use my espdma\n", esp->esp_id);
+		return -1;
+	}
+	dma->allocated = 1;
+	esp->dma = dma;
+	esp->dregs = dma->regs;
+
+	return 0;
+}
+
+static int __init esp_map_regs(struct esp *esp, int hme)
+{
+	struct sbus_dev *sdev = esp->sdev;
+	struct resource *res;
+
+	/* On HME, two reg sets exist, first is DVMA,
+	 * second is ESP registers.
+	 */
+	if (hme)
+		res = &sdev->resource[1];
+	else
+		res = &sdev->resource[0];
+
+	esp->eregs = sbus_ioremap(res, 0, ESP_REG_SIZE, "ESP Registers");
+
+	if (esp->eregs == 0)
+		return -1;
+	return 0;
+}
+
+static int __init esp_map_cmdarea(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->sdev;
+
+	esp->esp_command = sbus_alloc_consistent(sdev, 16,
+						 &esp->esp_command_dvma);
+	if (esp->esp_command == NULL ||
+	    esp->esp_command_dvma == 0)
+		return -1;
+	return 0;
+}
+
+static int __init esp_register_irq(struct esp *esp)
+{
+	esp->ehost->irq = esp->irq = esp->sdev->irqs[0];
+
+	/* We used to try various overly-clever things to
+	 * reduce the interrupt processing overhead on
+	 * sun4c/sun4m when multiple ESP's shared the
+	 * same IRQ.  It was too complex and messy to
+	 * sanely maintain.
+	 */
+	if (request_irq(esp->ehost->irq, esp_intr,
+			SA_SHIRQ, "ESP SCSI", esp)) {
+		printk("esp%d: Cannot acquire irq line\n",
+		       esp->esp_id);
+		return -1;
+	}
+
+	printk("esp%d: IRQ %s ", esp->esp_id,
+	       __irq_itoa(esp->ehost->irq));
+
+	return 0;
+}
+
+static void __init esp_get_scsi_id(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->sdev;
+
+	esp->scsi_id = prom_getintdefault(esp->prom_node,
+					  "initiator-id",
+					  -1);
+	if (esp->scsi_id == -1)
+		esp->scsi_id = prom_getintdefault(esp->prom_node,
+						  "scsi-initiator-id",
+						  -1);
+	if (esp->scsi_id == -1)
+		esp->scsi_id = (sdev->bus == NULL) ? 7 :
+			prom_getintdefault(sdev->bus->prom_node,
+					   "scsi-initiator-id",
+					   7);
+	esp->ehost->this_id = esp->scsi_id;
+	esp->scsi_id_mask = (1 << esp->scsi_id);
+
+}
+
+static void __init esp_get_clock_params(struct esp *esp)
+{
+	struct sbus_dev *sdev = esp->sdev;
+	int prom_node = esp->prom_node;
+	int sbus_prom_node;
+	unsigned int fmhz;
+	u8 ccf;
+
+	if (sdev != NULL && sdev->bus != NULL)
+		sbus_prom_node = sdev->bus->prom_node;
+	else
+		sbus_prom_node = 0;
+
+	/* This is getting messy but it has to be done
+	 * correctly or else you get weird behavior all
+	 * over the place.  We are trying to basically
+	 * figure out three pieces of information.
+	 *
+	 * a) Clock Conversion Factor
+	 *
+	 *    This is a representation of the input
+	 *    crystal clock frequency going into the
+	 *    ESP on this machine.  Any operation whose
+	 *    timing is longer than 400ns depends on this
+	 *    value being correct.  For example, you'll
+	 *    get blips for arbitration/selection during
+	 *    high load or with multiple targets if this
+	 *    is not set correctly.
+	 *
+	 * b) Selection Time-Out
+	 *
+	 *    The ESP isn't very bright and will arbitrate
+	 *    for the bus and try to select a target
+	 *    forever if you let it.  This value tells
+	 *    the ESP when it has taken too long to
+	 *    negotiate and that it should interrupt
+	 *    the CPU so we can see what happened.
+	 *    The value is computed as follows (from
+	 *    NCR/Symbios chip docs).
+	 *
+	 *          (Time Out Period) *  (Input Clock)
+	 *    STO = ----------------------------------
+	 *          (8192) * (Clock Conversion Factor)
+	 *
+	 *    You usually want the time out period to be
+	 *    around 250ms, I think we'll set it a little
+	 *    bit higher to account for fully loaded SCSI
+	 *    bus's and slow devices that don't respond so
+	 *    quickly to selection attempts. (yeah, I know
+	 *    this is out of spec. but there is a lot of
+	 *    buggy pieces of firmware out there so bite me)
+	 *
+	 * c) Imperical constants for synchronous offset
+	 *    and transfer period register values
+	 *
+	 *    This entails the smallest and largest sync
+	 *    period we could ever handle on this ESP.
+	 */
+
+	fmhz = prom_getintdefault(prom_node, "clock-frequency", -1);
+	if (fmhz == -1)
+		fmhz = (!sbus_prom_node) ? 0 :
+			prom_getintdefault(sbus_prom_node, "clock-frequency", -1);
+
+	if (fmhz <= (5000000))
+		ccf = 0;
+	else
+		ccf = (((5000000 - 1) + (fmhz))/(5000000));
+
+	if (!ccf || ccf > 8) {
+		/* If we can't find anything reasonable,
+		 * just assume 20MHZ.  This is the clock
+		 * frequency of the older sun4c's where I've
+		 * been unable to find the clock-frequency
+		 * PROM property.  All other machines provide
+		 * useful values it seems.
+		 */
+		ccf = ESP_CCF_F4;
+		fmhz = (20000000);
+	}
+
+	if (ccf == (ESP_CCF_F7 + 1))
+		esp->cfact = ESP_CCF_F0;
+	else if (ccf == ESP_CCF_NEVER)
+		esp->cfact = ESP_CCF_F2;
+	else
+		esp->cfact = ccf;
+	esp->raw_cfact = ccf;
+
+	esp->cfreq = fmhz;
+	esp->ccycle = ESP_MHZ_TO_CYCLE(fmhz);
+	esp->ctick = ESP_TICK(ccf, esp->ccycle);
+	esp->neg_defp = ESP_NEG_DEFP(fmhz, ccf);
+	esp->sync_defp = SYNC_DEFP_SLOW;
+
+	printk("SCSI ID %d Clk %dMHz CCYC=%d CCF=%d TOut %d ",
+	       esp->scsi_id, (fmhz / 1000000),
+	       (int)esp->ccycle, (int)ccf, (int) esp->neg_defp);
+}
+
+static void __init esp_get_bursts(struct esp *esp, struct sbus_dev *dma)
+{
+	struct sbus_dev *sdev = esp->sdev;
+	u8 bursts;
+
+	bursts = prom_getintdefault(esp->prom_node, "burst-sizes", 0xff);
+
+	if (dma) {
+		u8 tmp = prom_getintdefault(dma->prom_node,
+					    "burst-sizes", 0xff);
+		if (tmp != 0xff)
+			bursts &= tmp;
+	}
+
+	if (sdev->bus) {
+		u8 tmp = prom_getintdefault(sdev->bus->prom_node,
+					    "burst-sizes", 0xff);
+		if (tmp != 0xff)
+			bursts &= tmp;
+	}
+
+	if (bursts == 0xff ||
+	    (bursts & DMA_BURST16) == 0 ||
+	    (bursts & DMA_BURST32) == 0)
+		bursts = (DMA_BURST32 - 1);
+
+	esp->bursts = bursts;
+}
+
+static void __init esp_get_revision(struct esp *esp)
+{
+	u8 tmp;
+
+	esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
+	esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+	sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+
+	tmp = sbus_readb(esp->eregs + ESP_CFG2);
+	tmp &= ~ESP_CONFIG2_MAGIC;
+	if (tmp != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+		/* If what we write to cfg2 does not come back, cfg2
+		 * is not implemented, therefore this must be a plain
+		 * esp100.
+		 */
+		esp->erev = esp100;
+		printk("NCR53C90(esp100)\n");
+	} else {
+		esp->config2 = 0;
+		esp->prev_cfg3 = esp->config3[0] = 5;
+		sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		sbus_writeb(0, esp->eregs + ESP_CFG3);
+		sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+
+		tmp = sbus_readb(esp->eregs + ESP_CFG3);
+		if (tmp != 5) {
+			/* The cfg2 register is implemented, however
+			 * cfg3 is not, must be esp100a.
+			 */
+			esp->erev = esp100a;
+			printk("NCR53C90A(esp100a)\n");
+		} else {
+			int target;
+
+			for (target = 0; target < 16; target++)
+				esp->config3[target] = 0;
+			esp->prev_cfg3 = 0;
+			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+
+			/* All of cfg{1,2,3} implemented, must be one of
+			 * the fas variants, figure out which one.
+			 */
+			if (esp->raw_cfact > ESP_CCF_F5) {
+				esp->erev = fast;
+				esp->sync_defp = SYNC_DEFP_FAST;
+				printk("NCR53C9XF(espfast)\n");
+			} else {
+				esp->erev = esp236;
+				printk("NCR53C9x(esp236)\n");
+			}
+			esp->config2 = 0;
+			sbus_writeb(esp->config2, esp->eregs + ESP_CFG2);
+		}
+	}
+}
+
+static void __init esp_init_swstate(struct esp *esp)
+{
+	int i;
+
+	/* Command queues... */
+	esp->current_SC = NULL;
+	esp->disconnected_SC = NULL;
+	esp->issue_SC = NULL;
+
+	/* Target and current command state... */
+	esp->targets_present = 0;
+	esp->resetting_bus = 0;
+	esp->snip = 0;
+
+	init_waitqueue_head(&esp->reset_queue);
+
+	/* Debugging... */
+	for(i = 0; i < 32; i++)
+		esp->espcmdlog[i] = 0;
+	esp->espcmdent = 0;
+
+	/* MSG phase state... */
+	for(i = 0; i < 16; i++) {
+		esp->cur_msgout[i] = 0;
+		esp->cur_msgin[i] = 0;
+	}
+	esp->prevmsgout = esp->prevmsgin = 0;
+	esp->msgout_len = esp->msgin_len = 0;
+
+	/* Clear the one behind caches to hold unmatchable values. */
+	esp->prev_soff = esp->prev_stp = esp->prev_cfg3 = 0xff;
+	esp->prev_hme_dmacsr = 0xffffffff;
+}
+
+static int __init detect_one_esp(struct scsi_host_template *tpnt, struct sbus_dev *esp_dev,
+				 struct sbus_dev *espdma, struct sbus_bus *sbus,
+				 int id, int hme)
+{
+	struct Scsi_Host *esp_host = scsi_register(tpnt, sizeof(struct esp));
+	struct esp *esp;
+	
+	if (!esp_host) {
+		printk("ESP: Cannot register SCSI host\n");
+		return -1;
+	}
+	if (hme)
+		esp_host->max_id = 16;
+	esp = (struct esp *) esp_host->hostdata;
+	esp->ehost = esp_host;
+	esp->sdev = esp_dev;
+	esp->esp_id = id;
+	esp->prom_node = esp_dev->prom_node;
+	prom_getstring(esp->prom_node, "name", esp->prom_name,
+		       sizeof(esp->prom_name));
+
+	esp_chain_add(esp);
+	if (esp_find_dvma(esp, espdma) < 0)
+		goto fail_unlink;
+	if (esp_map_regs(esp, hme) < 0) {
+		printk("ESP registers unmappable");
+		goto fail_dvma_release;
+	}
+	if (esp_map_cmdarea(esp) < 0) {
+		printk("ESP DVMA transport area unmappable");
+		goto fail_unmap_regs;
+	}
+	if (esp_register_irq(esp) < 0)
+		goto fail_unmap_cmdarea;
+
+	esp_get_scsi_id(esp);
+
+	esp->diff = prom_getbool(esp->prom_node, "differential");
+	if (esp->diff)
+		printk("Differential ");
+
+	esp_get_clock_params(esp);
+	esp_get_bursts(esp, espdma);
+	esp_get_revision(esp);
+	esp_init_swstate(esp);
+
+	esp_bootup_reset(esp);
+
+	return 0;
+
+fail_unmap_cmdarea:
+	sbus_free_consistent(esp->sdev, 16,
+			     (void *) esp->esp_command,
+			     esp->esp_command_dvma);
+
+fail_unmap_regs:
+	sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+
+fail_dvma_release:
+	esp->dma->allocated = 0;
+
+fail_unlink:
+	esp_chain_del(esp);
+	scsi_unregister(esp_host);
+	return -1;
+}
+
+/* Detecting ESP chips on the machine.  This is the simple and easy
+ * version.
+ */
+
+#ifdef CONFIG_SUN4
+
+#include <asm/sun4paddr.h>
+
+static int __init esp_detect(struct scsi_host_template *tpnt)
+{
+	static struct sbus_dev esp_dev;
+	int esps_in_use = 0;
+
+	espchain = 0;
+
+	if (sun4_esp_physaddr) {
+		memset (&esp_dev, 0, sizeof(esp_dev));
+		esp_dev.reg_addrs[0].phys_addr = sun4_esp_physaddr;
+		esp_dev.irqs[0] = 4;
+		esp_dev.resource[0].start = sun4_esp_physaddr;
+		esp_dev.resource[0].end = sun4_esp_physaddr + ESP_REG_SIZE - 1;
+		esp_dev.resource[0].flags = IORESOURCE_IO;
+
+		if (!detect_one_esp(tpnt, &esp_dev, NULL, NULL, 0, 0))
+			esps_in_use++;
+		printk("ESP: Total of 1 ESP hosts found, %d actually in use.\n", esps_in_use);
+		esps_running =  esps_in_use;
+	}
+	return esps_in_use;
+}
+
+#else /* !CONFIG_SUN4 */
+
+static int __init esp_detect(struct scsi_host_template *tpnt)
+{
+	struct sbus_bus *sbus;
+	struct sbus_dev *esp_dev, *sbdev_iter;
+	int nesps = 0, esps_in_use = 0;
+
+	espchain = 0;
+	if (!sbus_root) {
+#ifdef CONFIG_PCI
+		return 0;
+#else
+		panic("No SBUS in esp_detect()");
+#endif
+	}
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sbdev_iter, sbus) {
+			struct sbus_dev *espdma = NULL;
+			int hme = 0;
+
+			/* Is it an esp sbus device? */
+			esp_dev = sbdev_iter;
+			if (strcmp(esp_dev->prom_name, "esp") &&
+			    strcmp(esp_dev->prom_name, "SUNW,esp")) {
+				if (!strcmp(esp_dev->prom_name, "SUNW,fas")) {
+					hme = 1;
+					espdma = esp_dev;
+				} else {
+					if (!esp_dev->child ||
+					    (strcmp(esp_dev->prom_name, "espdma") &&
+					     strcmp(esp_dev->prom_name, "dma")))
+						continue; /* nope... */
+					espdma = esp_dev;
+					esp_dev = esp_dev->child;
+					if (strcmp(esp_dev->prom_name, "esp") &&
+					    strcmp(esp_dev->prom_name, "SUNW,esp"))
+						continue; /* how can this happen? */
+				}
+			}
+			
+			if (detect_one_esp(tpnt, esp_dev, espdma, sbus, nesps++, hme) < 0)
+				continue;
+				
+			esps_in_use++;
+		} /* for each sbusdev */
+	} /* for each sbus */
+	printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
+	       esps_in_use);
+	esps_running = esps_in_use;
+	return esps_in_use;
+}
+
+#endif /* !CONFIG_SUN4 */
+
+/*
+ */
+static int esp_release(struct Scsi_Host *host)
+{
+	struct esp *esp = (struct esp *) host->hostdata;
+
+	ESP_INTSOFF(esp->dregs);
+#if 0
+	esp_reset_dma(esp);
+	esp_reset_esp(esp);
+#endif
+
+	free_irq(esp->ehost->irq, esp);
+	sbus_free_consistent(esp->sdev, 16,
+			     (void *) esp->esp_command, esp->esp_command_dvma);
+	sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+	esp->dma->allocated = 0;
+	esp_chain_del(esp);
+
+        return 0;
+}
+
+/* The info function will return whatever useful
+ * information the developer sees fit.  If not provided, then
+ * the name field will be used instead.
+ */
+static const char *esp_info(struct Scsi_Host *host)
+{
+	struct esp *esp;
+
+	esp = (struct esp *) host->hostdata;
+	switch (esp->erev) {
+	case esp100:
+		return "Sparc ESP100 (NCR53C90)";
+	case esp100a:
+		return "Sparc ESP100A (NCR53C90A)";
+	case esp236:
+		return "Sparc ESP236";
+	case fas236:
+		return "Sparc ESP236-FAST";
+	case fashme:
+		return "Sparc ESP366-HME";
+	case fas100a:
+		return "Sparc ESP100A-FAST";
+	default:
+		return "Bogon ESP revision";
+	};
+}
+
+/* From Wolfgang Stanglmeier's NCR scsi driver. */
+struct info_str
+{
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+static int esp_host_info(struct esp *esp, char *ptr, off_t offset, int len)
+{
+	struct scsi_device *sdev;
+	struct info_str info;
+	int i;
+
+	info.buffer	= ptr;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Sparc ESP Host Adapter:\n");
+	copy_info(&info, "\tPROM node\t\t%08x\n", (unsigned int) esp->prom_node);
+	copy_info(&info, "\tPROM name\t\t%s\n", esp->prom_name);
+	copy_info(&info, "\tESP Model\t\t");
+	switch (esp->erev) {
+	case esp100:
+		copy_info(&info, "ESP100\n");
+		break;
+	case esp100a:
+		copy_info(&info, "ESP100A\n");
+		break;
+	case esp236:
+		copy_info(&info, "ESP236\n");
+		break;
+	case fas236:
+		copy_info(&info, "FAS236\n");
+		break;
+	case fas100a:
+		copy_info(&info, "FAS100A\n");
+		break;
+	case fast:
+		copy_info(&info, "FAST\n");
+		break;
+	case fashme:
+		copy_info(&info, "Happy Meal FAS\n");
+		break;
+	case espunknown:
+	default:
+		copy_info(&info, "Unknown!\n");
+		break;
+	};
+	copy_info(&info, "\tDMA Revision\t\t");
+	switch (esp->dma->revision) {
+	case dvmarev0:
+		copy_info(&info, "Rev 0\n");
+		break;
+	case dvmaesc1:
+		copy_info(&info, "ESC Rev 1\n");
+		break;
+	case dvmarev1:
+		copy_info(&info, "Rev 1\n");
+		break;
+	case dvmarev2:
+		copy_info(&info, "Rev 2\n");
+		break;
+	case dvmarev3:
+		copy_info(&info, "Rev 3\n");
+		break;
+	case dvmarevplus:
+		copy_info(&info, "Rev 1+\n");
+		break;
+	case dvmahme:
+		copy_info(&info, "Rev HME/FAS\n");
+		break;
+	default:
+		copy_info(&info, "Unknown!\n");
+		break;
+	};
+	copy_info(&info, "\tLive Targets\t\t[ ");
+	for (i = 0; i < 15; i++) {
+		if (esp->targets_present & (1 << i))
+			copy_info(&info, "%d ", i);
+	}
+	copy_info(&info, "]\n\n");
+	
+	/* Now describe the state of each existing target. */
+	copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
+
+	shost_for_each_device(sdev, esp->ehost) {
+		struct esp_device *esp_dev = sdev->hostdata;
+		uint id = sdev->id;
+
+		if (!(esp->targets_present & (1 << id)))
+			continue;
+
+		copy_info(&info, "%d\t\t", id);
+		copy_info(&info, "%08lx\t", esp->config3[id]);
+		copy_info(&info, "[%02lx,%02lx]\t\t\t",
+			esp_dev->sync_max_offset,
+			esp_dev->sync_min_period);
+		copy_info(&info, "%s\t\t",
+			esp_dev->disconnect ? "yes" : "no");
+		copy_info(&info, "%s\n",
+			(esp->config3[id] & ESP_CONFIG3_EWIDE) ? "yes" : "no");
+	}
+	return info.pos > info.offset? info.pos - info.offset : 0;
+}
+
+/* ESP proc filesystem code. */
+static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+			 int length, int inout)
+{
+	struct esp *esp;
+
+	if (inout)
+		return -EINVAL; /* not yet */
+
+	for_each_esp(esp) {
+		if (esp->ehost == host)
+			break;
+	}
+	if (!esp)
+		return -EINVAL;
+
+	if (start)
+		*start = buffer;
+
+	return esp_host_info(esp, buffer, offset, length);
+}
+
+static void esp_get_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
+{
+	if (sp->use_sg == 0) {
+		sp->SCp.this_residual = sp->request_bufflen;
+		sp->SCp.buffer = (struct scatterlist *) sp->request_buffer;
+		sp->SCp.buffers_residual = 0;
+		if (sp->request_bufflen) {
+			sp->SCp.have_data_in = sbus_map_single(esp->sdev, sp->SCp.buffer,
+							       sp->SCp.this_residual,
+							       sp->sc_data_direction);
+			sp->SCp.ptr = (char *) ((unsigned long)sp->SCp.have_data_in);
+		} else {
+			sp->SCp.ptr = NULL;
+		}
+	} else {
+		sp->SCp.buffer = (struct scatterlist *) sp->buffer;
+		sp->SCp.buffers_residual = sbus_map_sg(esp->sdev,
+						       sp->SCp.buffer,
+						       sp->use_sg,
+						       sp->sc_data_direction);
+		sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
+		sp->SCp.ptr = (char *) ((unsigned long)sg_dma_address(sp->SCp.buffer));
+	}
+}
+
+static void esp_release_dmabufs(struct esp *esp, struct scsi_cmnd *sp)
+{
+	if (sp->use_sg) {
+		sbus_unmap_sg(esp->sdev, sp->buffer, sp->use_sg,
+			      sp->sc_data_direction);
+	} else if (sp->request_bufflen) {
+		sbus_unmap_single(esp->sdev,
+				  sp->SCp.have_data_in,
+				  sp->request_bufflen,
+				  sp->sc_data_direction);
+	}
+}
+
+static void esp_restore_pointers(struct esp *esp, struct scsi_cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
+
+	sp->SCp.ptr = ep->saved_ptr;
+	sp->SCp.buffer = ep->saved_buffer;
+	sp->SCp.this_residual = ep->saved_this_residual;
+	sp->SCp.buffers_residual = ep->saved_buffers_residual;
+}
+
+static void esp_save_pointers(struct esp *esp, struct scsi_cmnd *sp)
+{
+	struct esp_pointers *ep = &esp->data_pointers[sp->device->id];
+
+	ep->saved_ptr = sp->SCp.ptr;
+	ep->saved_buffer = sp->SCp.buffer;
+	ep->saved_this_residual = sp->SCp.this_residual;
+	ep->saved_buffers_residual = sp->SCp.buffers_residual;
+}
+
+/* Some rules:
+ *
+ *   1) Never ever panic while something is live on the bus.
+ *      If there is to be any chance of syncing the disks this
+ *      rule is to be obeyed.
+ *
+ *   2) Any target that causes a foul condition will no longer
+ *      have synchronous transfers done to it, no questions
+ *      asked.
+ *
+ *   3) Keep register accesses to a minimum.  Think about some
+ *      day when we have Xbus machines this is running on and
+ *      the ESP chip is on the other end of the machine on a
+ *      different board from the cpu where this is running.
+ */
+
+/* Fire off a command.  We assume the bus is free and that the only
+ * case where we could see an interrupt is where we have disconnected
+ * commands active and they are trying to reselect us.
+ */
+static inline void esp_check_cmd(struct esp *esp, struct scsi_cmnd *sp)
+{
+	switch (sp->cmd_len) {
+	case 6:
+	case 10:
+	case 12:
+		esp->esp_slowcmd = 0;
+		break;
+
+	default:
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = sp->cmd_len;
+		esp->esp_scmdp = &sp->cmnd[0];
+		break;
+	};
+}
+
+static inline void build_sync_nego_msg(struct esp *esp, int period, int offset)
+{
+	esp->cur_msgout[0] = EXTENDED_MESSAGE;
+	esp->cur_msgout[1] = 3;
+	esp->cur_msgout[2] = EXTENDED_SDTR;
+	esp->cur_msgout[3] = period;
+	esp->cur_msgout[4] = offset;
+	esp->msgout_len = 5;
+}
+
+/* SIZE is in bits, currently HME only supports 16 bit wide transfers. */
+static inline void build_wide_nego_msg(struct esp *esp, int size)
+{
+	esp->cur_msgout[0] = EXTENDED_MESSAGE;
+	esp->cur_msgout[1] = 2;
+	esp->cur_msgout[2] = EXTENDED_WDTR;
+	switch (size) {
+	case 32:
+		esp->cur_msgout[3] = 2;
+		break;
+	case 16:
+		esp->cur_msgout[3] = 1;
+		break;
+	case 8:
+	default:
+		esp->cur_msgout[3] = 0;
+		break;
+	};
+
+	esp->msgout_len = 4;
+}
+
+static void esp_exec_cmd(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr;
+	struct scsi_device *SDptr;
+	struct esp_device *esp_dev;
+	volatile u8 *cmdp = esp->esp_command;
+	u8 the_esp_command;
+	int lun, target;
+	int i;
+
+	/* Hold off if we have disconnected commands and
+	 * an IRQ is showing...
+	 */
+	if (esp->disconnected_SC && ESP_IRQ_P(esp->dregs))
+		return;
+
+	/* Grab first member of the issue queue. */
+	SCptr = esp->current_SC = remove_first_SC(&esp->issue_SC);
+
+	/* Safe to panic here because current_SC is null. */
+	if (!SCptr)
+		panic("esp: esp_exec_cmd and issue queue is NULL");
+
+	SDptr = SCptr->device;
+	esp_dev = SDptr->hostdata;
+	lun = SCptr->device->lun;
+	target = SCptr->device->id;
+
+	esp->snip = 0;
+	esp->msgout_len = 0;
+
+	/* Send it out whole, or piece by piece?   The ESP
+	 * only knows how to automatically send out 6, 10,
+	 * and 12 byte commands.  I used to think that the
+	 * Linux SCSI code would never throw anything other
+	 * than that to us, but then again there is the
+	 * SCSI generic driver which can send us anything.
+	 */
+	esp_check_cmd(esp, SCptr);
+
+	/* If arbitration/selection is successful, the ESP will leave
+	 * ATN asserted, causing the target to go into message out
+	 * phase.  The ESP will feed the target the identify and then
+	 * the target can only legally go to one of command,
+	 * datain/out, status, or message in phase, or stay in message
+	 * out phase (should we be trying to send a sync negotiation
+	 * message after the identify).  It is not allowed to drop
+	 * BSY, but some buggy targets do and we check for this
+	 * condition in the selection complete code.  Most of the time
+	 * we'll make the command bytes available to the ESP and it
+	 * will not interrupt us until it finishes command phase, we
+	 * cannot do this for command sizes the ESP does not
+	 * understand and in this case we'll get interrupted right
+	 * when the target goes into command phase.
+	 *
+	 * It is absolutely _illegal_ in the presence of SCSI-2 devices
+	 * to use the ESP select w/o ATN command.  When SCSI-2 devices are
+	 * present on the bus we _must_ always go straight to message out
+	 * phase with an identify message for the target.  Being that
+	 * selection attempts in SCSI-1 w/o ATN was an option, doing SCSI-2
+	 * selections should not confuse SCSI-1 we hope.
+	 */
+
+	if (esp_dev->sync) {
+		/* this targets sync is known */
+#ifndef __sparc_v9__
+do_sync_known:
+#endif
+		if (esp_dev->disconnect)
+			*cmdp++ = IDENTIFY(1, lun);
+		else
+			*cmdp++ = IDENTIFY(0, lun);
+
+		if (esp->esp_slowcmd) {
+			the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_stop);
+		} else {
+			the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+			esp_advance_phase(SCptr, in_slct_norm);
+		}
+	} else if (!(esp->targets_present & (1<<target)) || !(esp_dev->disconnect)) {
+		/* After the bootup SCSI code sends both the
+		 * TEST_UNIT_READY and INQUIRY commands we want
+		 * to at least attempt allowing the device to
+		 * disconnect.
+		 */
+		ESPMISC(("esp: Selecting device for first time. target=%d "
+			 "lun=%d\n", target, SCptr->device->lun));
+		if (!SDptr->borken && !esp_dev->disconnect)
+			esp_dev->disconnect = 1;
+
+		*cmdp++ = IDENTIFY(0, lun);
+		esp->prevmsgout = NOP;
+		esp_advance_phase(SCptr, in_slct_norm);
+		the_esp_command = (ESP_CMD_SELA | ESP_CMD_DMA);
+
+		/* Take no chances... */
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+	} else {
+		/* Sorry, I have had way too many problems with
+		 * various CDROM devices on ESP. -DaveM
+		 */
+		int cdrom_hwbug_wkaround = 0;
+
+#ifndef __sparc_v9__
+		/* Never allow disconnects or synchronous transfers on
+		 * SparcStation1 and SparcStation1+.  Allowing those
+		 * to be enabled seems to lockup the machine completely.
+		 */
+		if ((idprom->id_machtype == (SM_SUN4C | SM_4C_SS1)) ||
+		    (idprom->id_machtype == (SM_SUN4C | SM_4C_SS1PLUS))) {
+			/* But we are nice and allow tapes and removable
+			 * disks (but not CDROMs) to disconnect.
+			 */
+			if(SDptr->type == TYPE_TAPE ||
+			   (SDptr->type != TYPE_ROM && SDptr->removable))
+				esp_dev->disconnect = 1;
+			else
+				esp_dev->disconnect = 0;
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1;
+			esp->snip = 0;
+			goto do_sync_known;
+		}
+#endif /* !(__sparc_v9__) */
+
+		/* We've talked to this guy before,
+		 * but never negotiated.  Let's try,
+		 * need to attempt WIDE first, before
+		 * sync nego, as per SCSI 2 standard.
+		 */
+		if (esp->erev == fashme && !esp_dev->wide) {
+			if (!SDptr->borken &&
+			   SDptr->type != TYPE_ROM &&
+			   SDptr->removable == 0) {
+				build_wide_nego_msg(esp, 16);
+				esp_dev->wide = 1;
+				esp->wnip = 1;
+				goto after_nego_msg_built;
+			} else {
+				esp_dev->wide = 1;
+				/* Fall through and try sync. */
+			}
+		}
+
+		if (!SDptr->borken) {
+			if ((SDptr->type == TYPE_ROM)) {
+				/* Nice try sucker... */
+				ESPMISC(("esp%d: Disabling sync for buggy "
+					 "CDROM.\n", esp->esp_id));
+				cdrom_hwbug_wkaround = 1;
+				build_sync_nego_msg(esp, 0, 0);
+			} else if (SDptr->removable != 0) {
+				ESPMISC(("esp%d: Not negotiating sync/wide but "
+					 "allowing disconnect for removable media.\n",
+					 esp->esp_id));
+				build_sync_nego_msg(esp, 0, 0);
+			} else {
+				build_sync_nego_msg(esp, esp->sync_defp, 15);
+			}
+		} else {
+			build_sync_nego_msg(esp, 0, 0);
+		}
+		esp_dev->sync = 1;
+		esp->snip = 1;
+
+after_nego_msg_built:
+		/* A fix for broken SCSI1 targets, when they disconnect
+		 * they lock up the bus and confuse ESP.  So disallow
+		 * disconnects for SCSI1 targets for now until we
+		 * find a better fix.
+		 *
+		 * Addendum: This is funny, I figured out what was going
+		 *           on.  The blotzed SCSI1 target would disconnect,
+		 *           one of the other SCSI2 targets or both would be
+		 *           disconnected as well.  The SCSI1 target would
+		 *           stay disconnected long enough that we start
+		 *           up a command on one of the SCSI2 targets.  As
+		 *           the ESP is arbitrating for the bus the SCSI1
+		 *           target begins to arbitrate as well to reselect
+		 *           the ESP.  The SCSI1 target refuses to drop it's
+		 *           ID bit on the data bus even though the ESP is
+		 *           at ID 7 and is the obvious winner for any
+		 *           arbitration.  The ESP is a poor sport and refuses
+		 *           to lose arbitration, it will continue indefinitely
+		 *           trying to arbitrate for the bus and can only be
+		 *           stopped via a chip reset or SCSI bus reset.
+		 *           Therefore _no_ disconnects for SCSI1 targets
+		 *           thank you very much. ;-)
+		 */
+		if(((SDptr->scsi_level < 3) &&
+		    (SDptr->type != TYPE_TAPE) &&
+		    SDptr->removable == 0) ||
+		    cdrom_hwbug_wkaround || SDptr->borken) {
+			ESPMISC((KERN_INFO "esp%d: Disabling DISCONNECT for target %d "
+				 "lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+			esp_dev->disconnect = 0;
+			*cmdp++ = IDENTIFY(0, lun);
+		} else {
+			*cmdp++ = IDENTIFY(1, lun);
+		}
+
+		/* ESP fifo is only so big...
+		 * Make this look like a slow command.
+		 */
+		esp->esp_slowcmd = 1;
+		esp->esp_scmdleft = SCptr->cmd_len;
+		esp->esp_scmdp = &SCptr->cmnd[0];
+
+		the_esp_command = (ESP_CMD_SELAS | ESP_CMD_DMA);
+		esp_advance_phase(SCptr, in_slct_msg);
+	}
+
+	if (!esp->esp_slowcmd)
+		for (i = 0; i < SCptr->cmd_len; i++)
+			*cmdp++ = SCptr->cmnd[i];
+
+	/* HME sucks... */
+	if (esp->erev == fashme)
+		sbus_writeb((target & 0xf) | (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT),
+			    esp->eregs + ESP_BUSID);
+	else
+		sbus_writeb(target & 7, esp->eregs + ESP_BUSID);
+	if (esp->prev_soff != esp_dev->sync_max_offset ||
+	    esp->prev_stp  != esp_dev->sync_min_period ||
+	    (esp->erev > esp100a &&
+	     esp->prev_cfg3 != esp->config3[target])) {
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp->prev_stp = esp_dev->sync_min_period;
+		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
+		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
+		if (esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[target];
+			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+		}
+	}
+	i = (cmdp - esp->esp_command);
+
+	if (esp->erev == fashme) {
+		esp_cmd(esp, ESP_CMD_FLUSH); /* Grrr! */
+
+		/* Set up the DMA and HME counters */
+		sbus_writeb(i, esp->eregs + ESP_TCLOW);
+		sbus_writeb(0, esp->eregs + ESP_TCMED);
+		sbus_writeb(0, esp->eregs + FAS_RLO);
+		sbus_writeb(0, esp->eregs + FAS_RHI);
+		esp_cmd(esp, the_esp_command);
+
+		/* Talk about touchy hardware... */
+		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+					 (DMA_SCSI_DISAB | DMA_ENABLE)) &
+					~(DMA_ST_WRITE));
+		sbus_writel(16, esp->dregs + DMA_COUNT);
+		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
+		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
+	} else {
+		u32 tmp;
+
+		/* Set up the DMA and ESP counters */
+		sbus_writeb(i, esp->eregs + ESP_TCLOW);
+		sbus_writeb(0, esp->eregs + ESP_TCMED);
+		tmp = sbus_readl(esp->dregs + DMA_CSR);
+		tmp &= ~DMA_ST_WRITE;
+		tmp |= DMA_ENABLE;
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+		if (esp->dma->revision == dvmaesc1) {
+			if (i) /* Workaround ESC gate array SBUS rerun bug. */
+				sbus_writel(PAGE_SIZE, esp->dregs + DMA_COUNT);
+		}
+		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
+
+		/* Tell ESP to "go". */
+		esp_cmd(esp, the_esp_command);
+	}
+}
+
+/* Queue a SCSI command delivered from the mid-level Linux SCSI code. */
+static int esp_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	struct esp *esp;
+
+	/* Set up func ptr and initial driver cmd-phase. */
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.phase = not_issued;
+
+	/* We use the scratch area. */
+	ESPQUEUE(("esp_queue: target=%d lun=%d ", SCpnt->device->id, SCpnt->device->lun));
+	ESPDISC(("N<%02x,%02x>", SCpnt->device->id, SCpnt->device->lun));
+
+	esp = (struct esp *) SCpnt->device->host->hostdata;
+	esp_get_dmabufs(esp, SCpnt);
+	esp_save_pointers(esp, SCpnt); /* FIXME for tag queueing */
+
+	SCpnt->SCp.Status           = CHECK_CONDITION;
+	SCpnt->SCp.Message          = 0xff;
+	SCpnt->SCp.sent_command     = 0;
+
+	/* Place into our queue. */
+	if (SCpnt->cmnd[0] == REQUEST_SENSE) {
+		ESPQUEUE(("RQSENSE\n"));
+		prepend_SC(&esp->issue_SC, SCpnt);
+	} else {
+		ESPQUEUE(("\n"));
+		append_SC(&esp->issue_SC, SCpnt);
+	}
+
+	/* Run it now if we can. */
+	if (!esp->current_SC && !esp->resetting_bus)
+		esp_exec_cmd(esp);
+
+	return 0;
+}
+
+/* Dump driver state. */
+static void esp_dump_cmd(struct scsi_cmnd *SCptr)
+{
+	ESPLOG(("[tgt<%02x> lun<%02x> "
+		"pphase<%s> cphase<%s>]",
+		SCptr->device->id, SCptr->device->lun,
+		phase_string(SCptr->SCp.sent_command),
+		phase_string(SCptr->SCp.phase)));
+}
+
+static void esp_dump_state(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+#ifdef DEBUG_ESP_CMDS
+	int i;
+#endif
+
+	ESPLOG(("esp%d: dumping state\n", esp->esp_id));
+	ESPLOG(("esp%d: dma -- cond_reg<%08x> addr<%08x>\n",
+		esp->esp_id,
+		sbus_readl(esp->dregs + DMA_CSR),
+		sbus_readl(esp->dregs + DMA_ADDR)));
+	ESPLOG(("esp%d: SW [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id, esp->sreg, esp->seqreg, esp->ireg));
+	ESPLOG(("esp%d: HW reread [sreg<%02x> sstep<%02x> ireg<%02x>]\n",
+		esp->esp_id,
+		sbus_readb(esp->eregs + ESP_STATUS),
+		sbus_readb(esp->eregs + ESP_SSTEP),
+		sbus_readb(esp->eregs + ESP_INTRPT)));
+#ifdef DEBUG_ESP_CMDS
+	printk("esp%d: last ESP cmds [", esp->esp_id);
+	i = (esp->espcmdent - 1) & 31;
+	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
+	i = (i - 1) & 31;
+	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
+	i = (i - 1) & 31;
+	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
+	i = (i - 1) & 31;
+	printk("<"); esp_print_cmd(esp->espcmdlog[i]); printk(">");
+	printk("]\n");
+#endif /* (DEBUG_ESP_CMDS) */
+
+	if (SCptr) {
+		ESPLOG(("esp%d: current command ", esp->esp_id));
+		esp_dump_cmd(SCptr);
+	}
+	ESPLOG(("\n"));
+	SCptr = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected ", esp->esp_id));
+	while (SCptr) {
+		esp_dump_cmd(SCptr);
+		SCptr = (struct scsi_cmnd *) SCptr->host_scribble;
+	}
+	ESPLOG(("\n"));
+}
+
+/* Abort a command.  The host_lock is acquired by caller. */
+static int esp_abort(struct scsi_cmnd *SCptr)
+{
+	struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
+	int don;
+
+	ESPLOG(("esp%d: Aborting command\n", esp->esp_id));
+	esp_dump_state(esp);
+
+	/* Wheee, if this is the current command on the bus, the
+	 * best we can do is assert ATN and wait for msgout phase.
+	 * This should even fix a hung SCSI bus when we lose state
+	 * in the driver and timeout because the eventual phase change
+	 * will cause the ESP to (eventually) give an interrupt.
+	 */
+	if (esp->current_SC == SCptr) {
+		esp->cur_msgout[0] = ABORT;
+		esp->msgout_len = 1;
+		esp->msgout_ctr = 0;
+		esp_cmd(esp, ESP_CMD_SATN);
+		return SUCCESS;
+	}
+
+	/* If it is still in the issue queue then we can safely
+	 * call the completion routine and report abort success.
+	 */
+	don = (sbus_readl(esp->dregs + DMA_CSR) & DMA_INT_ENAB);
+	if (don) {
+		ESP_INTSOFF(esp->dregs);
+	}
+	if (esp->issue_SC) {
+		struct scsi_cmnd **prev, *this;
+		for (prev = (&esp->issue_SC), this = esp->issue_SC;
+		     this != NULL;
+		     prev = (struct scsi_cmnd **) &(this->host_scribble),
+			     this = (struct scsi_cmnd *) this->host_scribble) {
+
+			if (this == SCptr) {
+				*prev = (struct scsi_cmnd *) this->host_scribble;
+				this->host_scribble = NULL;
+
+				esp_release_dmabufs(esp, this);
+				this->result = DID_ABORT << 16;
+				this->scsi_done(this);
+
+				if (don)
+					ESP_INTSON(esp->dregs);
+
+				return SUCCESS;
+			}
+		}
+	}
+
+	/* Yuck, the command to abort is disconnected, it is not
+	 * worth trying to abort it now if something else is live
+	 * on the bus at this time.  So, we let the SCSI code wait
+	 * a little bit and try again later.
+	 */
+	if (esp->current_SC) {
+		if (don)
+			ESP_INTSON(esp->dregs);
+		return FAILED;
+	}
+
+	/* It's disconnected, we have to reconnect to re-establish
+	 * the nexus and tell the device to abort.  However, we really
+	 * cannot 'reconnect' per se.  Don't try to be fancy, just
+	 * indicate failure, which causes our caller to reset the whole
+	 * bus.
+	 */
+
+	if (don)
+		ESP_INTSON(esp->dregs);
+
+	return FAILED;
+}
+
+/* We've sent ESP_CMD_RS to the ESP, the interrupt had just
+ * arrived indicating the end of the SCSI bus reset.  Our job
+ * is to clean out the command queues and begin re-execution
+ * of SCSI commands once more.
+ */
+static int esp_finish_reset(struct esp *esp)
+{
+	struct scsi_cmnd *sp = esp->current_SC;
+
+	/* Clean up currently executing command, if any. */
+	if (sp != NULL) {
+		esp->current_SC = NULL;
+
+		esp_release_dmabufs(esp, sp);
+		sp->result = (DID_RESET << 16);
+
+		sp->scsi_done(sp);
+	}
+
+	/* Clean up disconnected queue, they have been invalidated
+	 * by the bus reset.
+	 */
+	if (esp->disconnected_SC) {
+		while ((sp = remove_first_SC(&esp->disconnected_SC)) != NULL) {
+			esp_release_dmabufs(esp, sp);
+			sp->result = (DID_RESET << 16);
+
+			sp->scsi_done(sp);
+		}
+	}
+
+	/* SCSI bus reset is complete. */
+	esp->resetting_bus = 0;
+	wake_up(&esp->reset_queue);
+
+	/* Ok, now it is safe to get commands going once more. */
+	if (esp->issue_SC)
+		esp_exec_cmd(esp);
+
+	return do_intr_end;
+}
+
+static int esp_do_resetbus(struct esp *esp)
+{
+	ESPLOG(("esp%d: Resetting scsi bus\n", esp->esp_id));
+	esp->resetting_bus = 1;
+	esp_cmd(esp, ESP_CMD_RS);
+
+	return do_intr_end;
+}
+
+/* Reset ESP chip, reset hanging bus, then kill active and
+ * disconnected commands for targets without soft reset.
+ *
+ * The host_lock is acquired by caller.
+ */
+static int esp_reset(struct scsi_cmnd *SCptr)
+{
+	struct esp *esp = (struct esp *) SCptr->device->host->hostdata;
+
+	(void) esp_do_resetbus(esp);
+
+	spin_unlock_irq(esp->ehost->host_lock);
+
+	wait_event(esp->reset_queue, (esp->resetting_bus == 0));
+
+	spin_lock_irq(esp->ehost->host_lock);
+
+	return SUCCESS;
+}
+
+/* Internal ESP done function. */
+static void esp_done(struct esp *esp, int error)
+{
+	struct scsi_cmnd *done_SC = esp->current_SC;
+
+	esp->current_SC = NULL;
+
+	esp_release_dmabufs(esp, done_SC);
+	done_SC->result = error;
+
+	done_SC->scsi_done(done_SC);
+
+	/* Bus is free, issue any commands in the queue. */
+	if (esp->issue_SC && !esp->current_SC)
+		esp_exec_cmd(esp);
+
+}
+
+/* Wheee, ESP interrupt engine. */  
+
+/* Forward declarations. */
+static int esp_do_phase_determine(struct esp *esp);
+static int esp_do_data_finale(struct esp *esp);
+static int esp_select_complete(struct esp *esp);
+static int esp_do_status(struct esp *esp);
+static int esp_do_msgin(struct esp *esp);
+static int esp_do_msgindone(struct esp *esp);
+static int esp_do_msgout(struct esp *esp);
+static int esp_do_cmdbegin(struct esp *esp);
+
+#define sreg_datainp(__sreg)  (((__sreg) & ESP_STAT_PMASK) == ESP_DIP)
+#define sreg_dataoutp(__sreg) (((__sreg) & ESP_STAT_PMASK) == ESP_DOP)
+
+/* Read any bytes found in the FAS366 fifo, storing them into
+ * the ESP driver software state structure.
+ */
+static void hme_fifo_read(struct esp *esp)
+{
+	u8 count = 0;
+	u8 status = esp->sreg;
+
+	/* Cannot safely frob the fifo for these following cases, but
+	 * we must always read the fifo when the reselect interrupt
+	 * is pending.
+	 */
+	if (((esp->ireg & ESP_INTR_RSEL) == 0)	&&
+	    (sreg_datainp(status)		||
+	     sreg_dataoutp(status)		||
+	     (esp->current_SC &&
+	      esp->current_SC->SCp.phase == in_data_done))) {
+		ESPHME(("<wkaround_skipped>"));
+	} else {
+		unsigned long fcnt = sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES;
+
+		/* The HME stores bytes in multiples of 2 in the fifo. */
+		ESPHME(("hme_fifo[fcnt=%d", (int)fcnt));
+		while (fcnt) {
+			esp->hme_fifo_workaround_buffer[count++] =
+				sbus_readb(esp->eregs + ESP_FDATA);
+			esp->hme_fifo_workaround_buffer[count++] =
+				sbus_readb(esp->eregs + ESP_FDATA);
+			ESPHME(("<%02x,%02x>", esp->hme_fifo_workaround_buffer[count-2], esp->hme_fifo_workaround_buffer[count-1]));
+			fcnt--;
+		}
+		if (sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_F1BYTE) {
+			ESPHME(("<poke_byte>"));
+			sbus_writeb(0, esp->eregs + ESP_FDATA);
+			esp->hme_fifo_workaround_buffer[count++] =
+				sbus_readb(esp->eregs + ESP_FDATA);
+			ESPHME(("<%02x,0x00>", esp->hme_fifo_workaround_buffer[count-1]));
+			ESPHME(("CMD_FLUSH"));
+			esp_cmd(esp, ESP_CMD_FLUSH);
+		} else {
+			ESPHME(("no_xtra_byte"));
+		}
+	}
+	ESPHME(("wkarnd_cnt=%d]", (int)count));
+	esp->hme_fifo_workaround_count = count;
+}
+
+static inline void hme_fifo_push(struct esp *esp, u8 *bytes, u8 count)
+{
+	esp_cmd(esp, ESP_CMD_FLUSH);
+	while (count) {
+		u8 tmp = *bytes++;
+		sbus_writeb(tmp, esp->eregs + ESP_FDATA);
+		sbus_writeb(0, esp->eregs + ESP_FDATA);
+		count--;
+	}
+}
+
+/* We try to avoid some interrupts by jumping ahead and see if the ESP
+ * has gotten far enough yet.  Hence the following.
+ */
+static inline int skipahead1(struct esp *esp, struct scsi_cmnd *scp,
+			     int prev_phase, int new_phase)
+{
+	if (scp->SCp.sent_command != prev_phase)
+		return 0;
+	if (ESP_IRQ_P(esp->dregs)) {
+		/* Yes, we are able to save an interrupt. */
+		if (esp->erev == fashme)
+			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
+		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
+		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
+		if (esp->erev == fashme) {
+			/* This chip is really losing. */
+			ESPHME(("HME["));
+			/* Must latch fifo before reading the interrupt
+			 * register else garbage ends up in the FIFO
+			 * which confuses the driver utterly.
+			 * Happy Meal indeed....
+			 */
+			ESPHME(("fifo_workaround]"));
+			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+			    (esp->sreg2 & ESP_STAT2_F1BYTE))
+				hme_fifo_read(esp);
+		}
+		if (!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
+}
+
+static inline int skipahead2(struct esp *esp, struct scsi_cmnd *scp,
+			     int prev_phase1, int prev_phase2, int new_phase)
+{
+	if (scp->SCp.sent_command != prev_phase1 &&
+	    scp->SCp.sent_command != prev_phase2)
+		return 0;
+	if (ESP_IRQ_P(esp->dregs)) {
+		/* Yes, we are able to save an interrupt. */
+		if (esp->erev == fashme)
+			esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
+		esp->sreg = (sbus_readb(esp->eregs + ESP_STATUS) & ~(ESP_STAT_INTR));
+		esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
+		if (esp->erev == fashme) {
+			/* This chip is really losing. */
+			ESPHME(("HME["));
+
+			/* Must latch fifo before reading the interrupt
+			 * register else garbage ends up in the FIFO
+			 * which confuses the driver utterly.
+			 * Happy Meal indeed....
+			 */
+			ESPHME(("fifo_workaround]"));
+			if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+			    (esp->sreg2 & ESP_STAT2_F1BYTE))
+				hme_fifo_read(esp);
+		}
+		if (!(esp->ireg & ESP_INTR_SR))
+			return 0;
+		else
+			return do_reset_complete;
+	}
+	/* Ho hum, target is taking forever... */
+	scp->SCp.sent_command = new_phase; /* so we don't recurse... */
+	return do_intr_end;
+}
+
+/* Now some dma helpers. */
+static void dma_setup(struct esp *esp, __u32 addr, int count, int write)
+{
+	u32 nreg = sbus_readl(esp->dregs + DMA_CSR);
+
+	if (write)
+		nreg |= DMA_ST_WRITE;
+	else
+		nreg &= ~(DMA_ST_WRITE);
+	nreg |= DMA_ENABLE;
+	sbus_writel(nreg, esp->dregs + DMA_CSR);
+	if (esp->dma->revision == dvmaesc1) {
+		/* This ESC gate array sucks! */
+		__u32 src = addr;
+		__u32 dest = src + count;
+
+		if (dest & (PAGE_SIZE - 1))
+			count = PAGE_ALIGN(count);
+		sbus_writel(count, esp->dregs + DMA_COUNT);
+	}
+	sbus_writel(addr, esp->dregs + DMA_ADDR);
+}
+
+static void dma_drain(struct esp *esp)
+{
+	u32 tmp;
+
+	if (esp->dma->revision == dvmahme)
+		return;
+	if ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_FIFO_ISDRAIN) {
+		switch (esp->dma->revision) {
+		default:
+			tmp |= DMA_FIFO_STDRAIN;
+			sbus_writel(tmp, esp->dregs + DMA_CSR);
+
+		case dvmarev3:
+		case dvmaesc1:
+			while (sbus_readl(esp->dregs + DMA_CSR) & DMA_FIFO_ISDRAIN)
+				udelay(1);
+		};
+	}
+}
+
+static void dma_invalidate(struct esp *esp)
+{
+	u32 tmp;
+
+	if (esp->dma->revision == dvmahme) {
+		sbus_writel(DMA_RST_SCSI, esp->dregs + DMA_CSR);
+
+		esp->prev_hme_dmacsr = ((esp->prev_hme_dmacsr |
+					 (DMA_PARITY_OFF | DMA_2CLKS |
+					  DMA_SCSI_DISAB | DMA_INT_ENAB)) &
+					~(DMA_ST_WRITE | DMA_ENABLE));
+
+		sbus_writel(0, esp->dregs + DMA_CSR);
+		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
+
+		/* This is necessary to avoid having the SCSI channel
+		 * engine lock up on us.
+		 */
+		sbus_writel(0, esp->dregs + DMA_ADDR);
+	} else {
+		while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
+			udelay(1);
+
+		tmp &= ~(DMA_ENABLE | DMA_ST_WRITE | DMA_BCNT_ENAB);
+		tmp |= DMA_FIFO_INV;
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+		tmp &= ~DMA_FIFO_INV;
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+	}
+}
+
+static inline void dma_flashclear(struct esp *esp)
+{
+	dma_drain(esp);
+	dma_invalidate(esp);
+}
+
+static int dma_can_transfer(struct esp *esp, struct scsi_cmnd *sp)
+{
+	__u32 base, end, sz;
+
+	if (esp->dma->revision == dvmarev3) {
+		sz = sp->SCp.this_residual;
+		if (sz > 0x1000000)
+			sz = 0x1000000;
+	} else {
+		base = ((__u32)((unsigned long)sp->SCp.ptr));
+		base &= (0x1000000 - 1);
+		end = (base + sp->SCp.this_residual);
+		if (end > 0x1000000)
+			end = 0x1000000;
+		sz = (end - base);
+	}
+	return sz;
+}
+
+/* Misc. esp helper macros. */
+#define esp_setcount(__eregs, __cnt, __hme) \
+	sbus_writeb(((__cnt)&0xff), (__eregs) + ESP_TCLOW); \
+	sbus_writeb((((__cnt)>>8)&0xff), (__eregs) + ESP_TCMED); \
+	if (__hme) { \
+		sbus_writeb((((__cnt)>>16)&0xff), (__eregs) + FAS_RLO); \
+		sbus_writeb(0, (__eregs) + FAS_RHI); \
+	}
+
+#define esp_getcount(__eregs, __hme) \
+	((sbus_readb((__eregs) + ESP_TCLOW)&0xff) | \
+	 ((sbus_readb((__eregs) + ESP_TCMED)&0xff) << 8) | \
+         ((__hme) ? sbus_readb((__eregs) + FAS_RLO) << 16 : 0))
+
+#define fcount(__esp) \
+	(((__esp)->erev == fashme) ? \
+	  (__esp)->hme_fifo_workaround_count : \
+	  sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_FBYTES)
+
+#define fnzero(__esp) \
+	(((__esp)->erev == fashme) ? 0 : \
+	 sbus_readb(((__esp)->eregs) + ESP_FFLAGS) & ESP_FF_ONOTZERO)
+
+/* XXX speculative nops unnecessary when continuing amidst a data phase
+ * XXX even on esp100!!!  another case of flooding the bus with I/O reg
+ * XXX writes...
+ */
+#define esp_maybe_nop(__esp) \
+	if ((__esp)->erev == esp100) \
+		esp_cmd((__esp), ESP_CMD_NULL)
+
+#define sreg_to_dataphase(__sreg) \
+	((((__sreg) & ESP_STAT_PMASK) == ESP_DOP) ? in_dataout : in_datain)
+
+/* The ESP100 when in synchronous data phase, can mistake a long final
+ * REQ pulse from the target as an extra byte, it places whatever is on
+ * the data lines into the fifo.  For now, we will assume when this
+ * happens that the target is a bit quirky and we don't want to
+ * be talking synchronously to it anyways.  Regardless, we need to
+ * tell the ESP to eat the extraneous byte so that we can proceed
+ * to the next phase.
+ */
+static int esp100_sync_hwbug(struct esp *esp, struct scsi_cmnd *sp, int fifocnt)
+{
+	/* Do not touch this piece of code. */
+	if ((!(esp->erev == esp100)) ||
+	    (!(sreg_datainp((esp->sreg = sbus_readb(esp->eregs + ESP_STATUS))) &&
+	       !fifocnt) &&
+	     !(sreg_dataoutp(esp->sreg) && !fnzero(esp)))) {
+		if (sp->SCp.phase == in_dataout)
+			esp_cmd(esp, ESP_CMD_FLUSH);
+		return 0;
+	} else {
+		/* Async mode for this guy. */
+		build_sync_nego_msg(esp, 0, 0);
+
+		/* Ack the bogus byte, but set ATN first. */
+		esp_cmd(esp, ESP_CMD_SATN);
+		esp_cmd(esp, ESP_CMD_MOK);
+		return 1;
+	}
+}
+
+/* This closes the window during a selection with a reselect pending, because
+ * we use DMA for the selection process the FIFO should hold the correct
+ * contents if we get reselected during this process.  So we just need to
+ * ack the possible illegal cmd interrupt pending on the esp100.
+ */
+static inline int esp100_reconnect_hwbug(struct esp *esp)
+{
+	u8 tmp;
+
+	if (esp->erev != esp100)
+		return 0;
+	tmp = sbus_readb(esp->eregs + ESP_INTRPT);
+	if (tmp & ESP_INTR_SR)
+		return 1;
+	return 0;
+}
+
+/* This verifies the BUSID bits during a reselection so that we know which
+ * target is talking to us.
+ */
+static inline int reconnect_target(struct esp *esp)
+{
+	int it, me = esp->scsi_id_mask, targ = 0;
+
+	if (2 != fcount(esp))
+		return -1;
+	if (esp->erev == fashme) {
+		/* HME does not latch it's own BUS ID bits during
+		 * a reselection.  Also the target number is given
+		 * as an unsigned char, not as a sole bit number
+		 * like the other ESP's do.
+		 * Happy Meal indeed....
+		 */
+		targ = esp->hme_fifo_workaround_buffer[0];
+	} else {
+		it = sbus_readb(esp->eregs + ESP_FDATA);
+		if (!(it & me))
+			return -1;
+		it &= ~me;
+		if (it & (it - 1))
+			return -1;
+		while (!(it & 1))
+			targ++, it >>= 1;
+	}
+	return targ;
+}
+
+/* This verifies the identify from the target so that we know which lun is
+ * being reconnected.
+ */
+static inline int reconnect_lun(struct esp *esp)
+{
+	int lun;
+
+	if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP)
+		return -1;
+	if (esp->erev == fashme)
+		lun = esp->hme_fifo_workaround_buffer[1];
+	else
+		lun = sbus_readb(esp->eregs + ESP_FDATA);
+
+	/* Yes, you read this correctly.  We report lun of zero
+	 * if we see parity error.  ESP reports parity error for
+	 * the lun byte, and this is the only way to hope to recover
+	 * because the target is connected.
+	 */
+	if (esp->sreg & ESP_STAT_PERR)
+		return 0;
+
+	/* Check for illegal bits being set in the lun. */
+	if ((lun & 0x40) || !(lun & 0x80))
+		return -1;
+
+	return lun & 7;
+}
+
+/* This puts the driver in a state where it can revitalize a command that
+ * is being continued due to reselection.
+ */
+static inline void esp_connect(struct esp *esp, struct scsi_cmnd *sp)
+{
+	struct esp_device *esp_dev = sp->device->hostdata;
+
+	if (esp->prev_soff  != esp_dev->sync_max_offset ||
+	    esp->prev_stp   != esp_dev->sync_min_period ||
+	    (esp->erev > esp100a &&
+	     esp->prev_cfg3 != esp->config3[sp->device->id])) {
+		esp->prev_soff = esp_dev->sync_max_offset;
+		esp->prev_stp = esp_dev->sync_min_period;
+		sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
+		sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
+		if (esp->erev > esp100a) {
+			esp->prev_cfg3 = esp->config3[sp->device->id];
+			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+		}
+	}
+	esp->current_SC = sp;
+}
+
+/* This will place the current working command back into the issue queue
+ * if we are to receive a reselection amidst a selection attempt.
+ */
+static inline void esp_reconnect(struct esp *esp, struct scsi_cmnd *sp)
+{
+	if (!esp->disconnected_SC)
+		ESPLOG(("esp%d: Weird, being reselected but disconnected "
+			"command queue is empty.\n", esp->esp_id));
+	esp->snip = 0;
+	esp->current_SC = 0;
+	sp->SCp.phase = not_issued;
+	append_SC(&esp->issue_SC, sp);
+}
+
+/* Begin message in phase. */
+static int esp_do_msgin(struct esp *esp)
+{
+	/* Must be very careful with the fifo on the HME */
+	if ((esp->erev != fashme) ||
+	    !(sbus_readb(esp->eregs + ESP_STATUS2) & ESP_STAT2_FEMPTY))
+		esp_cmd(esp, ESP_CMD_FLUSH);
+	esp_maybe_nop(esp);
+	esp_cmd(esp, ESP_CMD_TI);
+	esp->msgin_len = 1;
+	esp->msgin_ctr = 0;
+	esp_advance_phase(esp->current_SC, in_msgindone);
+	return do_work_bus;
+}
+
+/* This uses various DMA csr fields and the fifo flags count value to
+ * determine how many bytes were successfully sent/received by the ESP.
+ */
+static inline int esp_bytes_sent(struct esp *esp, int fifo_count)
+{
+	int rval = sbus_readl(esp->dregs + DMA_ADDR) - esp->esp_command_dvma;
+
+	if (esp->dma->revision == dvmarev1)
+		rval -= (4 - ((sbus_readl(esp->dregs + DMA_CSR) & DMA_READ_AHEAD)>>11));
+	return rval - fifo_count;
+}
+
+static inline void advance_sg(struct scsi_cmnd *sp)
+{
+	++sp->SCp.buffer;
+	--sp->SCp.buffers_residual;
+	sp->SCp.this_residual = sg_dma_len(sp->SCp.buffer);
+	sp->SCp.ptr = (char *)((unsigned long)sg_dma_address(sp->SCp.buffer));
+}
+
+/* Please note that the way I've coded these routines is that I _always_
+ * check for a disconnect during any and all information transfer
+ * phases.  The SCSI standard states that the target _can_ cause a BUS
+ * FREE condition by dropping all MSG/CD/IO/BSY signals.  Also note
+ * that during information transfer phases the target controls every
+ * change in phase, the only thing the initiator can do is "ask" for
+ * a message out phase by driving ATN true.  The target can, and sometimes
+ * will, completely ignore this request so we cannot assume anything when
+ * we try to force a message out phase to abort/reset a target.  Most of
+ * the time the target will eventually be nice and go to message out, so
+ * we may have to hold on to our state about what we want to tell the target
+ * for some period of time.
+ */
+
+/* I think I have things working here correctly.  Even partial transfers
+ * within a buffer or sub-buffer should not upset us at all no matter
+ * how bad the target and/or ESP fucks things up.
+ */
+static int esp_do_data(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	int thisphase, hmuch;
+
+	ESPDATA(("esp_do_data: "));
+	esp_maybe_nop(esp);
+	thisphase = sreg_to_dataphase(esp->sreg);
+	esp_advance_phase(SCptr, thisphase);
+	ESPDATA(("newphase<%s> ", (thisphase == in_datain) ? "DATAIN" : "DATAOUT"));
+	hmuch = dma_can_transfer(esp, SCptr);
+	if (hmuch > (64 * 1024) && (esp->erev != fashme))
+		hmuch = (64 * 1024);
+	ESPDATA(("hmuch<%d> ", hmuch));
+	esp->current_transfer_size = hmuch;
+
+	if (esp->erev == fashme) {
+		u32 tmp = esp->prev_hme_dmacsr;
+
+		/* Always set the ESP count registers first. */
+		esp_setcount(esp->eregs, hmuch, 1);
+
+		/* Get the DMA csr computed. */
+		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
+		if (thisphase == in_datain)
+			tmp |= DMA_ST_WRITE;
+		else
+			tmp &= ~(DMA_ST_WRITE);
+		esp->prev_hme_dmacsr = tmp;
+
+		ESPDATA(("DMA|TI --> do_intr_end\n"));
+		if (thisphase == in_datain) {
+			sbus_writel(hmuch, esp->dregs + DMA_COUNT);
+			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+		} else {
+			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+			sbus_writel(hmuch, esp->dregs + DMA_COUNT);
+		}
+		sbus_writel((__u32)((unsigned long)SCptr->SCp.ptr), esp->dregs+DMA_ADDR);
+		sbus_writel(esp->prev_hme_dmacsr, esp->dregs + DMA_CSR);
+	} else {
+		esp_setcount(esp->eregs, hmuch, 0);
+		dma_setup(esp, ((__u32)((unsigned long)SCptr->SCp.ptr)),
+			  hmuch, (thisphase == in_datain));
+		ESPDATA(("DMA|TI --> do_intr_end\n"));
+		esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+	}
+	return do_intr_end;
+}
+
+/* See how successful the data transfer was. */
+static int esp_do_data_finale(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	int bogus_data = 0, bytes_sent = 0, fifocnt, ecount = 0;
+
+	ESPDATA(("esp_do_data_finale: "));
+
+	if (SCptr->SCp.phase == in_datain) {
+		if (esp->sreg & ESP_STAT_PERR) {
+			/* Yuck, parity error.  The ESP asserts ATN
+			 * so that we can go to message out phase
+			 * immediately and inform the target that
+			 * something bad happened.
+			 */
+			ESPLOG(("esp%d: data bad parity detected.\n",
+				esp->esp_id));
+			esp->cur_msgout[0] = INITIATOR_ERROR;
+			esp->msgout_len = 1;
+		}
+		dma_drain(esp);
+	}
+	dma_invalidate(esp);
+
+	/* This could happen for the above parity error case. */
+	if (esp->ireg != ESP_INTR_BSERV) {
+		/* Please go to msgout phase, please please please... */
+		ESPLOG(("esp%d: !BSERV after data, probably to msgout\n",
+			esp->esp_id));
+		return esp_do_phase_determine(esp);
+	}	
+
+	/* Check for partial transfers and other horrible events.
+	 * Note, here we read the real fifo flags register even
+	 * on HME broken adapters because we skip the HME fifo
+	 * workaround code in esp_handle() if we are doing data
+	 * phase things.  We don't want to fuck directly with
+	 * the fifo like that, especially if doing synchronous
+	 * transfers!  Also, will need to double the count on
+	 * HME if we are doing wide transfers, as the HME fifo
+	 * will move and count 16-bit quantities during wide data.
+	 * SMCC _and_ Qlogic can both bite me.
+	 */
+	fifocnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
+	if (esp->erev != fashme)
+		ecount = esp_getcount(esp->eregs, 0);
+	bytes_sent = esp->current_transfer_size;
+
+	ESPDATA(("trans_sz(%d), ", bytes_sent));
+	if (esp->erev == fashme) {
+		if (!(esp->sreg & ESP_STAT_TCNT)) {
+			ecount = esp_getcount(esp->eregs, 1);
+			bytes_sent -= ecount;
+		}
+
+		/* Always subtract any cruft remaining in the FIFO. */
+		if (esp->prev_cfg3 & ESP_CONFIG3_EWIDE)
+			fifocnt <<= 1;
+		if (SCptr->SCp.phase == in_dataout)
+			bytes_sent -= fifocnt;
+
+		/* I have an IBM disk which exhibits the following
+		 * behavior during writes to it.  It disconnects in
+		 * the middle of a partial transfer, the current sglist
+		 * buffer is 1024 bytes, the disk stops data transfer
+		 * at 512 bytes.
+		 *
+		 * However the FAS366 reports that 32 more bytes were
+		 * transferred than really were.  This is precisely
+		 * the size of a fully loaded FIFO in wide scsi mode.
+		 * The FIFO state recorded indicates that it is empty.
+		 *
+		 * I have no idea if this is a bug in the FAS366 chip
+		 * or a bug in the firmware on this IBM disk.  In any
+		 * event the following seems to be a good workaround.  -DaveM
+		 */
+		if (bytes_sent != esp->current_transfer_size &&
+		    SCptr->SCp.phase == in_dataout) {
+			int mask = (64 - 1);
+
+			if ((esp->prev_cfg3 & ESP_CONFIG3_EWIDE) == 0)
+				mask >>= 1;
+
+			if (bytes_sent & mask)
+				bytes_sent -= (bytes_sent & mask);
+		}
+	} else {
+		if (!(esp->sreg & ESP_STAT_TCNT))
+			bytes_sent -= ecount;
+		if (SCptr->SCp.phase == in_dataout)
+			bytes_sent -= fifocnt;
+	}
+
+	ESPDATA(("bytes_sent(%d), ", bytes_sent));
+
+	/* If we were in synchronous mode, check for peculiarities. */
+	if (esp->erev == fashme) {
+		if (esp_dev->sync_max_offset) {
+			if (SCptr->SCp.phase == in_dataout)
+				esp_cmd(esp, ESP_CMD_FLUSH);
+		} else {
+			esp_cmd(esp, ESP_CMD_FLUSH);
+		}
+	} else {
+		if (esp_dev->sync_max_offset)
+			bogus_data = esp100_sync_hwbug(esp, SCptr, fifocnt);
+		else
+			esp_cmd(esp, ESP_CMD_FLUSH);
+	}
+
+	/* Until we are sure of what has happened, we are certainly
+	 * in the dark.
+	 */
+	esp_advance_phase(SCptr, in_the_dark);
+
+	if (bytes_sent < 0) {
+		/* I've seen this happen due to lost state in this
+		 * driver.  No idea why it happened, but allowing
+		 * this value to be negative caused things to
+		 * lock up.  This allows greater chance of recovery.
+		 * In fact every time I've seen this, it has been
+		 * a driver bug without question.
+		 */
+		ESPLOG(("esp%d: yieee, bytes_sent < 0!\n", esp->esp_id));
+		ESPLOG(("esp%d: csz=%d fifocount=%d ecount=%d\n",
+			esp->esp_id,
+			esp->current_transfer_size, fifocnt, ecount));
+		ESPLOG(("esp%d: use_sg=%d ptr=%p this_residual=%d\n",
+			esp->esp_id,
+			SCptr->use_sg, SCptr->SCp.ptr, SCptr->SCp.this_residual));
+		ESPLOG(("esp%d: Forcing async for target %d\n", esp->esp_id, 
+			SCptr->device->id));
+		SCptr->device->borken = 1;
+		esp_dev->sync = 0;
+		bytes_sent = 0;
+	}
+
+	/* Update the state of our transfer. */
+	SCptr->SCp.ptr += bytes_sent;
+	SCptr->SCp.this_residual -= bytes_sent;
+	if (SCptr->SCp.this_residual < 0) {
+		/* shit */
+		ESPLOG(("esp%d: Data transfer overrun.\n", esp->esp_id));
+		SCptr->SCp.this_residual = 0;
+	}
+
+	/* Maybe continue. */
+	if (!bogus_data) {
+		ESPDATA(("!bogus_data, "));
+
+		/* NO MATTER WHAT, we advance the scatterlist,
+		 * if the target should decide to disconnect
+		 * in between scatter chunks (which is common)
+		 * we could die horribly!  I used to have the sg
+		 * advance occur only if we are going back into
+		 * (or are staying in) a data phase, you can
+		 * imagine the hell I went through trying to
+		 * figure this out.
+		 */
+		if (SCptr->use_sg && !SCptr->SCp.this_residual)
+			advance_sg(SCptr);
+		if (sreg_datainp(esp->sreg) || sreg_dataoutp(esp->sreg)) {
+			ESPDATA(("to more data\n"));
+			return esp_do_data(esp);
+		}
+		ESPDATA(("to new phase\n"));
+		return esp_do_phase_determine(esp);
+	}
+	/* Bogus data, just wait for next interrupt. */
+	ESPLOG(("esp%d: bogus_data during end of data phase\n",
+		esp->esp_id));
+	return do_intr_end;
+}
+
+/* We received a non-good status return at the end of
+ * running a SCSI command.  This is used to decide if
+ * we should clear our synchronous transfer state for
+ * such a device when that happens.
+ *
+ * The idea is that when spinning up a disk or rewinding
+ * a tape, we don't want to go into a loop re-negotiating
+ * synchronous capabilities over and over.
+ */
+static int esp_should_clear_sync(struct scsi_cmnd *sp)
+{
+	u8 cmd1 = sp->cmnd[0];
+	u8 cmd2 = sp->data_cmnd[0];
+
+	/* These cases are for spinning up a disk and
+	 * waiting for that spinup to complete.
+	 */
+	if (cmd1 == START_STOP ||
+	    cmd2 == START_STOP)
+		return 0;
+
+	if (cmd1 == TEST_UNIT_READY ||
+	    cmd2 == TEST_UNIT_READY)
+		return 0;
+
+	/* One more special case for SCSI tape drives,
+	 * this is what is used to probe the device for
+	 * completion of a rewind or tape load operation.
+	 */
+	if (sp->device->type == TYPE_TAPE) {
+		if (cmd1 == MODE_SENSE ||
+		    cmd2 == MODE_SENSE)
+			return 0;
+	}
+
+	return 1;
+}
+
+/* Either a command is completing or a target is dropping off the bus
+ * to continue the command in the background so we can do other work.
+ */
+static int esp_do_freebus(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	int rval;
+
+	rval = skipahead2(esp, SCptr, in_status, in_msgindone, in_freeing);
+	if (rval)
+		return rval;
+	if (esp->ireg != ESP_INTR_DC) {
+		ESPLOG(("esp%d: Target will not disconnect\n", esp->esp_id));
+		return do_reset_bus; /* target will not drop BSY... */
+	}
+	esp->msgout_len = 0;
+	esp->prevmsgout = NOP;
+	if (esp->prevmsgin == COMMAND_COMPLETE) {
+		/* Normal end of nexus. */
+		if (esp->disconnected_SC || (esp->erev == fashme))
+			esp_cmd(esp, ESP_CMD_ESEL);
+
+		if (SCptr->SCp.Status != GOOD &&
+		    SCptr->SCp.Status != CONDITION_GOOD &&
+		    ((1<<SCptr->device->id) & esp->targets_present) &&
+		    esp_dev->sync &&
+		    esp_dev->sync_max_offset) {
+			/* SCSI standard says that the synchronous capabilities
+			 * should be renegotiated at this point.  Most likely
+			 * we are about to request sense from this target
+			 * in which case we want to avoid using sync
+			 * transfers until we are sure of the current target
+			 * state.
+			 */
+			ESPMISC(("esp: Status <%d> for target %d lun %d\n",
+				 SCptr->SCp.Status, SCptr->device->id, SCptr->device->lun));
+
+			/* But don't do this when spinning up a disk at
+			 * boot time while we poll for completion as it
+			 * fills up the console with messages.  Also, tapes
+			 * can report not ready many times right after
+			 * loading up a tape.
+			 */
+			if (esp_should_clear_sync(SCptr) != 0)
+				esp_dev->sync = 0;
+		}
+		ESPDISC(("F<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+		esp_done(esp, ((SCptr->SCp.Status & 0xff) |
+			       ((SCptr->SCp.Message & 0xff)<<8) |
+			       (DID_OK << 16)));
+	} else if (esp->prevmsgin == DISCONNECT) {
+		/* Normal disconnect. */
+		esp_cmd(esp, ESP_CMD_ESEL);
+		ESPDISC(("D<%02x,%02x>", SCptr->device->id, SCptr->device->lun));
+		append_SC(&esp->disconnected_SC, SCptr);
+		esp->current_SC = NULL;
+		if (esp->issue_SC)
+			esp_exec_cmd(esp);
+	} else {
+		/* Driver bug, we do not expect a disconnect here
+		 * and should not have advanced the state engine
+		 * to in_freeing.
+		 */
+		ESPLOG(("esp%d: last msg not disc and not cmd cmplt.\n",
+			esp->esp_id));
+		return do_reset_bus;
+	}
+	return do_intr_end;
+}
+
+/* When a reselect occurs, and we cannot find the command to
+ * reconnect to in our queues, we do this.
+ */
+static int esp_bad_reconnect(struct esp *esp)
+{
+	struct scsi_cmnd *sp;
+
+	ESPLOG(("esp%d: Eieeee, reconnecting unknown command!\n",
+		esp->esp_id));
+	ESPLOG(("QUEUE DUMP\n"));
+	sp = esp->issue_SC;
+	ESPLOG(("esp%d: issue_SC[", esp->esp_id));
+	while (sp) {
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+		sp = (struct scsi_cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	sp = esp->current_SC;
+	ESPLOG(("esp%d: current_SC[", esp->esp_id));
+	if (sp)
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+	else
+		ESPLOG(("<NULL>"));
+	ESPLOG(("]\n"));
+	sp = esp->disconnected_SC;
+	ESPLOG(("esp%d: disconnected_SC[", esp->esp_id));
+	while (sp) {
+		ESPLOG(("<%02x,%02x>", sp->device->id, sp->device->lun));
+		sp = (struct scsi_cmnd *) sp->host_scribble;
+	}
+	ESPLOG(("]\n"));
+	return do_reset_bus;
+}
+
+/* Do the needy when a target tries to reconnect to us. */
+static int esp_do_reconnect(struct esp *esp)
+{
+	int lun, target;
+	struct scsi_cmnd *SCptr;
+
+	/* Check for all bogus conditions first. */
+	target = reconnect_target(esp);
+	if (target < 0) {
+		ESPDISC(("bad bus bits\n"));
+		return do_reset_bus;
+	}
+	lun = reconnect_lun(esp);
+	if (lun < 0) {
+		ESPDISC(("target=%2x, bad identify msg\n", target));
+		return do_reset_bus;
+	}
+
+	/* Things look ok... */
+	ESPDISC(("R<%02x,%02x>", target, lun));
+
+	/* Must not flush FIFO or DVMA on HME. */
+	if (esp->erev != fashme) {
+		esp_cmd(esp, ESP_CMD_FLUSH);
+		if (esp100_reconnect_hwbug(esp))
+			return do_reset_bus;
+		esp_cmd(esp, ESP_CMD_NULL);
+	}
+
+	SCptr = remove_SC(&esp->disconnected_SC, (u8) target, (u8) lun);
+	if (!SCptr)
+		return esp_bad_reconnect(esp);
+
+	esp_connect(esp, SCptr);
+	esp_cmd(esp, ESP_CMD_MOK);
+
+	if (esp->erev == fashme)
+		sbus_writeb(((SCptr->device->id & 0xf) |
+			     (ESP_BUSID_RESELID | ESP_BUSID_CTR32BIT)),
+			    esp->eregs + ESP_BUSID);
+
+	/* Reconnect implies a restore pointers operation. */
+	esp_restore_pointers(esp, SCptr);
+
+	esp->snip = 0;
+	esp_advance_phase(SCptr, in_the_dark);
+	return do_intr_end;
+}
+
+/* End of NEXUS (hopefully), pick up status + message byte then leave if
+ * all goes well.
+ */
+static int esp_do_status(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	int intr, rval;
+
+	rval = skipahead1(esp, SCptr, in_the_dark, in_status);
+	if (rval)
+		return rval;
+	intr = esp->ireg;
+	ESPSTAT(("esp_do_status: "));
+	if (intr != ESP_INTR_DC) {
+		int message_out = 0; /* for parity problems */
+
+		/* Ack the message. */
+		ESPSTAT(("ack msg, "));
+		esp_cmd(esp, ESP_CMD_MOK);
+
+		if (esp->erev != fashme) {
+			dma_flashclear(esp);
+
+			/* Wait till the first bits settle. */
+			while (esp->esp_command[0] == 0xff)
+				udelay(1);
+		} else {
+			esp->esp_command[0] = esp->hme_fifo_workaround_buffer[0];
+			esp->esp_command[1] = esp->hme_fifo_workaround_buffer[1];
+		}
+
+		ESPSTAT(("got something, "));
+		/* ESP chimes in with one of
+		 *
+		 * 1) function done interrupt:
+		 *	both status and message in bytes
+		 *	are available
+		 *
+		 * 2) bus service interrupt:
+		 *	only status byte was acquired
+		 *
+		 * 3) Anything else:
+		 *	can't happen, but we test for it
+		 *	anyways
+		 *
+		 * ALSO: If bad parity was detected on either
+		 *       the status _or_ the message byte then
+		 *       the ESP has asserted ATN on the bus
+		 *       and we must therefore wait for the
+		 *       next phase change.
+		 */
+		if (intr & ESP_INTR_FDONE) {
+			/* We got it all, hallejulia. */
+			ESPSTAT(("got both, "));
+			SCptr->SCp.Status = esp->esp_command[0];
+			SCptr->SCp.Message = esp->esp_command[1];
+			esp->prevmsgin = SCptr->SCp.Message;
+			esp->cur_msgin[0] = SCptr->SCp.Message;
+			if (esp->sreg & ESP_STAT_PERR) {
+				/* There was bad parity for the
+				 * message byte, the status byte
+				 * was ok.
+				 */
+				message_out = MSG_PARITY_ERROR;
+			}
+		} else if (intr == ESP_INTR_BSERV) {
+			/* Only got status byte. */
+			ESPLOG(("esp%d: got status only, ", esp->esp_id));
+			if (!(esp->sreg & ESP_STAT_PERR)) {
+				SCptr->SCp.Status = esp->esp_command[0];
+				SCptr->SCp.Message = 0xff;
+			} else {
+				/* The status byte had bad parity.
+				 * we leave the scsi_pointer Status
+				 * field alone as we set it to a default
+				 * of CHECK_CONDITION in esp_queue.
+				 */
+				message_out = INITIATOR_ERROR;
+			}
+		} else {
+			/* This shouldn't happen ever. */
+			ESPSTAT(("got bolixed\n"));
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp);
+		}
+
+		if (!message_out) {
+			ESPSTAT(("status=%2x msg=%2x, ", SCptr->SCp.Status,
+				SCptr->SCp.Message));
+			if (SCptr->SCp.Message == COMMAND_COMPLETE) {
+				ESPSTAT(("and was COMMAND_COMPLETE\n"));
+				esp_advance_phase(SCptr, in_freeing);
+				return esp_do_freebus(esp);
+			} else {
+				ESPLOG(("esp%d: and _not_ COMMAND_COMPLETE\n",
+					esp->esp_id));
+				esp->msgin_len = esp->msgin_ctr = 1;
+				esp_advance_phase(SCptr, in_msgindone);
+				return esp_do_msgindone(esp);
+			}
+		} else {
+			/* With luck we'll be able to let the target
+			 * know that bad parity happened, it will know
+			 * which byte caused the problems and send it
+			 * again.  For the case where the status byte
+			 * receives bad parity, I do not believe most
+			 * targets recover very well.  We'll see.
+			 */
+			ESPLOG(("esp%d: bad parity somewhere mout=%2x\n",
+				esp->esp_id, message_out));
+			esp->cur_msgout[0] = message_out;
+			esp->msgout_len = esp->msgout_ctr = 1;
+			esp_advance_phase(SCptr, in_the_dark);
+			return esp_do_phase_determine(esp);
+		}
+	} else {
+		/* If we disconnect now, all hell breaks loose. */
+		ESPLOG(("esp%d: whoops, disconnect\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp);
+	}
+}
+
+static int esp_enter_status(struct esp *esp)
+{
+	u8 thecmd = ESP_CMD_ICCSEQ;
+
+	esp_cmd(esp, ESP_CMD_FLUSH);
+	if (esp->erev != fashme) {
+		u32 tmp;
+
+		esp->esp_command[0] = esp->esp_command[1] = 0xff;
+		sbus_writeb(2, esp->eregs + ESP_TCLOW);
+		sbus_writeb(0, esp->eregs + ESP_TCMED);
+		tmp = sbus_readl(esp->dregs + DMA_CSR);
+		tmp |= (DMA_ST_WRITE | DMA_ENABLE);
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+		if (esp->dma->revision == dvmaesc1)
+			sbus_writel(0x100, esp->dregs + DMA_COUNT);
+		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
+		thecmd |= ESP_CMD_DMA;
+	}
+	esp_cmd(esp, thecmd);
+	esp_advance_phase(esp->current_SC, in_status);
+
+	return esp_do_status(esp);
+}
+
+static int esp_disconnect_amidst_phases(struct esp *esp)
+{
+	struct scsi_cmnd *sp = esp->current_SC;
+	struct esp_device *esp_dev = sp->device->hostdata;
+
+	/* This means real problems if we see this
+	 * here.  Unless we were actually trying
+	 * to force the device to abort/reset.
+	 */
+	ESPLOG(("esp%d Disconnect amidst phases, ", esp->esp_id));
+	ESPLOG(("pphase<%s> cphase<%s>, ",
+		phase_string(sp->SCp.phase),
+		phase_string(sp->SCp.sent_command)));
+
+	if (esp->disconnected_SC != NULL || (esp->erev == fashme))
+		esp_cmd(esp, ESP_CMD_ESEL);
+
+	switch (esp->cur_msgout[0]) {
+	default:
+		/* We didn't expect this to happen at all. */
+		ESPLOG(("device is bolixed\n"));
+		esp_advance_phase(sp, in_tgterror);
+		esp_done(esp, (DID_ERROR << 16));
+		break;
+
+	case BUS_DEVICE_RESET:
+		ESPLOG(("device reset successful\n"));
+		esp_dev->sync_max_offset = 0;
+		esp_dev->sync_min_period = 0;
+		esp_dev->sync = 0;
+		esp_advance_phase(sp, in_resetdev);
+		esp_done(esp, (DID_RESET << 16));
+		break;
+
+	case ABORT:
+		ESPLOG(("device abort successful\n"));
+		esp_advance_phase(sp, in_abortone);
+		esp_done(esp, (DID_ABORT << 16));
+		break;
+
+	};
+	return do_intr_end;
+}
+
+static int esp_enter_msgout(struct esp *esp)
+{
+	esp_advance_phase(esp->current_SC, in_msgout);
+	return esp_do_msgout(esp);
+}
+
+static int esp_enter_msgin(struct esp *esp)
+{
+	esp_advance_phase(esp->current_SC, in_msgin);
+	return esp_do_msgin(esp);
+}
+
+static int esp_enter_cmd(struct esp *esp)
+{
+	esp_advance_phase(esp->current_SC, in_cmdbegin);
+	return esp_do_cmdbegin(esp);
+}
+
+static int esp_enter_badphase(struct esp *esp)
+{
+	ESPLOG(("esp%d: Bizarre bus phase %2x.\n", esp->esp_id,
+		esp->sreg & ESP_STAT_PMASK));
+	return do_reset_bus;
+}
+
+typedef int (*espfunc_t)(struct esp *);
+
+static espfunc_t phase_vector[] = {
+	esp_do_data,		/* ESP_DOP */
+	esp_do_data,		/* ESP_DIP */
+	esp_enter_cmd,		/* ESP_CMDP */
+	esp_enter_status,	/* ESP_STATP */
+	esp_enter_badphase,	/* ESP_STAT_PMSG */
+	esp_enter_badphase,	/* ESP_STAT_PMSG | ESP_STAT_PIO */
+	esp_enter_msgout,	/* ESP_MOP */
+	esp_enter_msgin,	/* ESP_MIP */
+};
+
+/* The target has control of the bus and we have to see where it has
+ * taken us.
+ */
+static int esp_do_phase_determine(struct esp *esp)
+{
+	if ((esp->ireg & ESP_INTR_DC) != 0)
+		return esp_disconnect_amidst_phases(esp);
+	return phase_vector[esp->sreg & ESP_STAT_PMASK](esp);
+}
+
+/* First interrupt after exec'ing a cmd comes here. */
+static int esp_select_complete(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	int cmd_bytes_sent, fcnt;
+
+	if (esp->erev != fashme)
+		esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
+
+	if (esp->erev == fashme)
+		fcnt = esp->hme_fifo_workaround_count;
+	else
+		fcnt = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES);
+
+	cmd_bytes_sent = esp_bytes_sent(esp, fcnt);
+	dma_invalidate(esp);
+
+	/* Let's check to see if a reselect happened
+	 * while we we're trying to select.  This must
+	 * be checked first.
+	 */
+	if (esp->ireg == (ESP_INTR_RSEL | ESP_INTR_FDONE)) {
+		esp_reconnect(esp, SCptr);
+		return esp_do_reconnect(esp);
+	}
+
+	/* Looks like things worked, we should see a bus service &
+	 * a function complete interrupt at this point.  Note we
+	 * are doing a direct comparison because we don't want to
+	 * be fooled into thinking selection was successful if
+	 * ESP_INTR_DC is set, see below.
+	 */
+	if (esp->ireg == (ESP_INTR_FDONE | ESP_INTR_BSERV)) {
+		/* target speaks... */
+		esp->targets_present |= (1<<SCptr->device->id);
+
+		/* What if the target ignores the sdtr? */
+		if (esp->snip)
+			esp_dev->sync = 1;
+
+		/* See how far, if at all, we got in getting
+		 * the information out to the target.
+		 */
+		switch (esp->seqreg) {
+		default:
+
+		case ESP_STEP_ASEL:
+			/* Arbitration won, target selected, but
+			 * we are in some phase which is not command
+			 * phase nor is it message out phase.
+			 *
+			 * XXX We've confused the target, obviously.
+			 * XXX So clear it's state, but we also end
+			 * XXX up clearing everyone elses.  That isn't
+			 * XXX so nice.  I'd like to just reset this
+			 * XXX target, but if I cannot even get it's
+			 * XXX attention and finish selection to talk
+			 * XXX to it, there is not much more I can do.
+			 * XXX If we have a loaded bus we're going to
+			 * XXX spend the next second or so renegotiating
+			 * XXX for synchronous transfers.
+			 */
+			ESPLOG(("esp%d: STEP_ASEL for tgt %d\n",
+				esp->esp_id, SCptr->device->id));
+
+		case ESP_STEP_SID:
+			/* Arbitration won, target selected, went
+			 * to message out phase, sent one message
+			 * byte, then we stopped.  ATN is asserted
+			 * on the SCSI bus and the target is still
+			 * there hanging on.  This is a legal
+			 * sequence step if we gave the ESP a select
+			 * and stop command.
+			 *
+			 * XXX See above, I could set the borken flag
+			 * XXX in the device struct and retry the
+			 * XXX command.  But would that help for
+			 * XXX tagged capable targets?
+			 */
+
+		case ESP_STEP_NCMD:
+			/* Arbitration won, target selected, maybe
+			 * sent the one message byte in message out
+			 * phase, but we did not go to command phase
+			 * in the end.  Actually, we could have sent
+			 * only some of the message bytes if we tried
+			 * to send out the entire identify and tag
+			 * message using ESP_CMD_SA3.
+			 */
+			cmd_bytes_sent = 0;
+			break;
+
+		case ESP_STEP_PPC:
+			/* No, not the powerPC pinhead.  Arbitration
+			 * won, all message bytes sent if we went to
+			 * message out phase, went to command phase
+			 * but only part of the command was sent.
+			 *
+			 * XXX I've seen this, but usually in conjunction
+			 * XXX with a gross error which appears to have
+			 * XXX occurred between the time I told the
+			 * XXX ESP to arbitrate and when I got the
+			 * XXX interrupt.  Could I have misloaded the
+			 * XXX command bytes into the fifo?  Actually,
+			 * XXX I most likely missed a phase, and therefore
+			 * XXX went into never never land and didn't even
+			 * XXX know it.  That was the old driver though.
+			 * XXX What is even more peculiar is that the ESP
+			 * XXX showed the proper function complete and
+			 * XXX bus service bits in the interrupt register.
+			 */
+
+		case ESP_STEP_FINI4:
+		case ESP_STEP_FINI5:
+		case ESP_STEP_FINI6:
+		case ESP_STEP_FINI7:
+			/* Account for the identify message */
+			if (SCptr->SCp.phase == in_slct_norm)
+				cmd_bytes_sent -= 1;
+		};
+
+		if (esp->erev != fashme)
+			esp_cmd(esp, ESP_CMD_NULL);
+
+		/* Be careful, we could really get fucked during synchronous
+		 * data transfers if we try to flush the fifo now.
+		 */
+		if ((esp->erev != fashme) && /* not a Happy Meal and... */
+		    !fcnt && /* Fifo is empty and... */
+		    /* either we are not doing synchronous transfers or... */
+		    (!esp_dev->sync_max_offset ||
+		     /* We are not going into data in phase. */
+		     ((esp->sreg & ESP_STAT_PMASK) != ESP_DIP)))
+			esp_cmd(esp, ESP_CMD_FLUSH); /* flush is safe */
+
+		/* See how far we got if this is not a slow command. */
+		if (!esp->esp_slowcmd) {
+			if (cmd_bytes_sent < 0)
+				cmd_bytes_sent = 0;
+			if (cmd_bytes_sent != SCptr->cmd_len) {
+				/* Crapola, mark it as a slowcmd
+				 * so that we have some chance of
+				 * keeping the command alive with
+				 * good luck.
+				 *
+				 * XXX Actually, if we didn't send it all
+				 * XXX this means either we didn't set things
+				 * XXX up properly (driver bug) or the target
+				 * XXX or the ESP detected parity on one of
+				 * XXX the command bytes.  This makes much
+				 * XXX more sense, and therefore this code
+				 * XXX should be changed to send out a
+				 * XXX parity error message or if the status
+				 * XXX register shows no parity error then
+				 * XXX just expect the target to bring the
+				 * XXX bus into message in phase so that it
+				 * XXX can send us the parity error message.
+				 * XXX SCSI sucks...
+				 */
+				esp->esp_slowcmd = 1;
+				esp->esp_scmdp = &(SCptr->cmnd[cmd_bytes_sent]);
+				esp->esp_scmdleft = (SCptr->cmd_len - cmd_bytes_sent);
+			}
+		}
+
+		/* Now figure out where we went. */
+		esp_advance_phase(SCptr, in_the_dark);
+		return esp_do_phase_determine(esp);
+	}
+
+	/* Did the target even make it? */
+	if (esp->ireg == ESP_INTR_DC) {
+		/* wheee... nobody there or they didn't like
+		 * what we told it to do, clean up.
+		 */
+
+		/* If anyone is off the bus, but working on
+		 * a command in the background for us, tell
+		 * the ESP to listen for them.
+		 */
+		if (esp->disconnected_SC)
+			esp_cmd(esp, ESP_CMD_ESEL);
+
+		if (((1<<SCptr->device->id) & esp->targets_present) &&
+		    esp->seqreg != 0 &&
+		    (esp->cur_msgout[0] == EXTENDED_MESSAGE) &&
+		    (SCptr->SCp.phase == in_slct_msg ||
+		     SCptr->SCp.phase == in_slct_stop)) {
+			/* shit */
+			esp->snip = 0;
+			ESPLOG(("esp%d: Failed synchronous negotiation for target %d "
+				"lun %d\n", esp->esp_id, SCptr->device->id, SCptr->device->lun));
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync = 1; /* so we don't negotiate again */
+
+			/* Run the command again, this time though we
+			 * won't try to negotiate for synchronous transfers.
+			 *
+			 * XXX I'd like to do something like send an
+			 * XXX INITIATOR_ERROR or ABORT message to the
+			 * XXX target to tell it, "Sorry I confused you,
+			 * XXX please come back and I will be nicer next
+			 * XXX time".  But that requires having the target
+			 * XXX on the bus, and it has dropped BSY on us.
+			 */
+			esp->current_SC = NULL;
+			esp_advance_phase(SCptr, not_issued);
+			prepend_SC(&esp->issue_SC, SCptr);
+			esp_exec_cmd(esp);
+			return do_intr_end;
+		}
+
+		/* Ok, this is normal, this is what we see during boot
+		 * or whenever when we are scanning the bus for targets.
+		 * But first make sure that is really what is happening.
+		 */
+		if (((1<<SCptr->device->id) & esp->targets_present)) {
+			ESPLOG(("esp%d: Warning, live target %d not responding to "
+				"selection.\n", esp->esp_id, SCptr->device->id));
+
+			/* This _CAN_ happen.  The SCSI standard states that
+			 * the target is to _not_ respond to selection if
+			 * _it_ detects bad parity on the bus for any reason.
+			 * Therefore, we assume that if we've talked successfully
+			 * to this target before, bad parity is the problem.
+			 */
+			esp_done(esp, (DID_PARITY << 16));
+		} else {
+			/* Else, there really isn't anyone there. */
+			ESPMISC(("esp: selection failure, maybe nobody there?\n"));
+			ESPMISC(("esp: target %d lun %d\n",
+				 SCptr->device->id, SCptr->device->lun));
+			esp_done(esp, (DID_BAD_TARGET << 16));
+		}
+		return do_intr_end;
+	}
+
+	ESPLOG(("esp%d: Selection failure.\n", esp->esp_id));
+	printk("esp%d: Currently -- ", esp->esp_id);
+	esp_print_ireg(esp->ireg); printk(" ");
+	esp_print_statreg(esp->sreg); printk(" ");
+	esp_print_seqreg(esp->seqreg); printk("\n");
+	printk("esp%d: New -- ", esp->esp_id);
+	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
+	esp->seqreg = sbus_readb(esp->eregs + ESP_SSTEP);
+	esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);
+	esp_print_ireg(esp->ireg); printk(" ");
+	esp_print_statreg(esp->sreg); printk(" ");
+	esp_print_seqreg(esp->seqreg); printk("\n");
+	ESPLOG(("esp%d: resetting bus\n", esp->esp_id));
+	return do_reset_bus; /* ugh... */
+}
+
+/* Continue reading bytes for msgin phase. */
+static int esp_do_msgincont(struct esp *esp)
+{
+	if (esp->ireg & ESP_INTR_BSERV) {
+		/* in the right phase too? */
+		if ((esp->sreg & ESP_STAT_PMASK) == ESP_MIP) {
+			/* phew... */
+			esp_cmd(esp, ESP_CMD_TI);
+			esp_advance_phase(esp->current_SC, in_msgindone);
+			return do_intr_end;
+		}
+
+		/* We changed phase but ESP shows bus service,
+		 * in this case it is most likely that we, the
+		 * hacker who has been up for 20hrs straight
+		 * staring at the screen, drowned in coffee
+		 * smelling like retched cigarette ashes
+		 * have miscoded something..... so, try to
+		 * recover as best we can.
+		 */
+		ESPLOG(("esp%d: message in mis-carriage.\n", esp->esp_id));
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return do_phase_determine;
+}
+
+static int check_singlebyte_msg(struct esp *esp)
+{
+	esp->prevmsgin = esp->cur_msgin[0];
+	if (esp->cur_msgin[0] & 0x80) {
+		/* wheee... */
+		ESPLOG(("esp%d: target sends identify amidst phases\n",
+			esp->esp_id));
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return 0;
+	} else if (((esp->cur_msgin[0] & 0xf0) == 0x20) ||
+		   (esp->cur_msgin[0] == EXTENDED_MESSAGE)) {
+		esp->msgin_len = 2;
+		esp_advance_phase(esp->current_SC, in_msgincont);
+		return 0;
+	}
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	switch (esp->cur_msgin[0]) {
+	default:
+		/* We don't want to hear about it. */
+		ESPLOG(("esp%d: msg %02x which we don't know about\n", esp->esp_id,
+			esp->cur_msgin[0]));
+		return MESSAGE_REJECT;
+
+	case NOP:
+		ESPLOG(("esp%d: target %d sends a nop\n", esp->esp_id,
+			esp->current_SC->device->id));
+		return 0;
+
+	case RESTORE_POINTERS:
+		/* In this case we might also have to backup the
+		 * "slow command" pointer.  It is rare to get such
+		 * a save/restore pointer sequence so early in the
+		 * bus transition sequences, but cover it.
+		 */
+		if (esp->esp_slowcmd) {
+			esp->esp_scmdleft = esp->current_SC->cmd_len;
+			esp->esp_scmdp = &esp->current_SC->cmnd[0];
+		}
+		esp_restore_pointers(esp, esp->current_SC);
+		return 0;
+
+	case SAVE_POINTERS:
+		esp_save_pointers(esp, esp->current_SC);
+		return 0;
+
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/* Freeing the bus, let it go. */
+		esp->current_SC->SCp.phase = in_freeing;
+		return 0;
+
+	case MESSAGE_REJECT:
+		ESPMISC(("msg reject, "));
+		if (esp->prevmsgout == EXTENDED_MESSAGE) {
+			struct esp_device *esp_dev = esp->current_SC->device->hostdata;
+
+			/* Doesn't look like this target can
+			 * do synchronous or WIDE transfers.
+			 */
+			ESPSDTR(("got reject, was trying nego, clearing sync/WIDE\n"));
+			esp_dev->sync = 1;
+			esp_dev->wide = 1;
+			esp_dev->sync_min_period = 0;
+			esp_dev->sync_max_offset = 0;
+			return 0;
+		} else {
+			ESPMISC(("not sync nego, sending ABORT\n"));
+			return ABORT;
+		}
+	};
+}
+
+/* Target negotiates for synchronous transfers before we do, this
+ * is legal although very strange.  What is even funnier is that
+ * the SCSI2 standard specifically recommends against targets doing
+ * this because so many initiators cannot cope with this occurring.
+ */
+static int target_with_ants_in_pants(struct esp *esp,
+				     struct scsi_cmnd *SCptr,
+				     struct esp_device *esp_dev)
+{
+	if (esp_dev->sync || SCptr->device->borken) {
+		/* sorry, no can do */
+		ESPSDTR(("forcing to async, "));
+		build_sync_nego_msg(esp, 0, 0);
+		esp_dev->sync = 1;
+		esp->snip = 1;
+		ESPLOG(("esp%d: hoping for msgout\n", esp->esp_id));
+		esp_advance_phase(SCptr, in_the_dark);
+		return EXTENDED_MESSAGE;
+	}
+
+	/* Ok, we'll check them out... */
+	return 0;
+}
+
+static void sync_report(struct esp *esp)
+{
+	int msg3, msg4;
+	char *type;
+
+	msg3 = esp->cur_msgin[3];
+	msg4 = esp->cur_msgin[4];
+	if (msg4) {
+		int hz = 1000000000 / (msg3 * 4);
+		int integer = hz / 1000000;
+		int fraction = (hz - (integer * 1000000)) / 10000;
+		if ((esp->erev == fashme) &&
+		    (esp->config3[esp->current_SC->device->id] & ESP_CONFIG3_EWIDE)) {
+			type = "FAST-WIDE";
+			integer <<= 1;
+			fraction <<= 1;
+		} else if ((msg3 * 4) < 200) {
+			type = "FAST";
+		} else {
+			type = "synchronous";
+		}
+
+		/* Do not transform this back into one big printk
+		 * again, it triggers a bug in our sparc64-gcc272
+		 * sibling call optimization.  -DaveM
+		 */
+		ESPLOG((KERN_INFO "esp%d: target %d ",
+			esp->esp_id, esp->current_SC->device->id));
+		ESPLOG(("[period %dns offset %d %d.%02dMHz ",
+			(int) msg3 * 4, (int) msg4,
+			integer, fraction));
+		ESPLOG(("%s SCSI%s]\n", type,
+			(((msg3 * 4) < 200) ? "-II" : "")));
+	} else {
+		ESPLOG((KERN_INFO "esp%d: target %d asynchronous\n",
+			esp->esp_id, esp->current_SC->device->id));
+	}
+}
+
+static int check_multibyte_msg(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	struct esp_device *esp_dev = SCptr->device->hostdata;
+	u8 regval = 0;
+	int message_out = 0;
+
+	ESPSDTR(("chk multibyte msg: "));
+	if (esp->cur_msgin[2] == EXTENDED_SDTR) {
+		int period = esp->cur_msgin[3];
+		int offset = esp->cur_msgin[4];
+
+		ESPSDTR(("is sync nego response, "));
+		if (!esp->snip) {
+			int rval;
+
+			/* Target negotiates first! */
+			ESPSDTR(("target jumps the gun, "));
+			message_out = EXTENDED_MESSAGE; /* we must respond */
+			rval = target_with_ants_in_pants(esp, SCptr, esp_dev);
+			if (rval)
+				return rval;
+		}
+
+		ESPSDTR(("examining sdtr, "));
+
+		/* Offset cannot be larger than ESP fifo size. */
+		if (offset > 15) {
+			ESPSDTR(("offset too big %2x, ", offset));
+			offset = 15;
+			ESPSDTR(("sending back new offset\n"));
+			build_sync_nego_msg(esp, period, offset);
+			return EXTENDED_MESSAGE;
+		}
+
+		if (offset && period > esp->max_period) {
+			/* Yeee, async for this slow device. */
+			ESPSDTR(("period too long %2x, ", period));
+			build_sync_nego_msg(esp, 0, 0);
+			ESPSDTR(("hoping for msgout\n"));
+			esp_advance_phase(esp->current_SC, in_the_dark);
+			return EXTENDED_MESSAGE;
+		} else if (offset && period < esp->min_period) {
+			ESPSDTR(("period too short %2x, ", period));
+			period = esp->min_period;
+			if (esp->erev > esp236)
+				regval = 4;
+			else
+				regval = 5;
+		} else if (offset) {
+			int tmp;
+
+			ESPSDTR(("period is ok, "));
+			tmp = esp->ccycle / 1000;
+			regval = (((period << 2) + tmp - 1) / tmp);
+			if (regval && ((esp->erev == fas100a ||
+					esp->erev == fas236  ||
+					esp->erev == fashme))) {
+				if (period >= 50)
+					regval--;
+			}
+		}
+
+		if (offset) {
+			u8 bit;
+
+			esp_dev->sync_min_period = (regval & 0x1f);
+			esp_dev->sync_max_offset = (offset | esp->radelay);
+			if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
+				if ((esp->erev == fas100a) || (esp->erev == fashme))
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				if (period < 50) {
+					/* On FAS366, if using fast-20 synchronous transfers
+					 * we need to make sure the REQ/ACK assert/deassert
+					 * control bits are clear.
+					 */
+					if (esp->erev == fashme)
+						esp_dev->sync_max_offset &= ~esp->radelay;
+					esp->config3[SCptr->device->id] |= bit;
+				} else {
+					esp->config3[SCptr->device->id] &= ~bit;
+				}
+				esp->prev_cfg3 = esp->config3[SCptr->device->id];
+				sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+			}
+			esp->prev_soff = esp_dev->sync_max_offset;
+			esp->prev_stp = esp_dev->sync_min_period;
+			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
+			sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
+			ESPSDTR(("soff=%2x stp=%2x cfg3=%2x\n",
+				 esp_dev->sync_max_offset,
+				 esp_dev->sync_min_period,
+				 esp->config3[SCptr->device->id]));
+
+			esp->snip = 0;
+		} else if (esp_dev->sync_max_offset) {
+			u8 bit;
+
+			/* back to async mode */
+			ESPSDTR(("unaccaptable sync nego, forcing async\n"));
+			esp_dev->sync_max_offset = 0;
+			esp_dev->sync_min_period = 0;
+			esp->prev_soff = 0;
+			esp->prev_stp = 0;
+			sbus_writeb(esp->prev_soff, esp->eregs + ESP_SOFF);
+			sbus_writeb(esp->prev_stp, esp->eregs + ESP_STP);
+			if (esp->erev == fas100a || esp->erev == fas236 || esp->erev == fashme) {
+				if ((esp->erev == fas100a) || (esp->erev == fashme))
+					bit = ESP_CONFIG3_FAST;
+				else
+					bit = ESP_CONFIG3_FSCSI;
+				esp->config3[SCptr->device->id] &= ~bit;
+				esp->prev_cfg3 = esp->config3[SCptr->device->id];
+				sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+			}
+		}
+
+		sync_report(esp);
+
+		ESPSDTR(("chk multibyte msg: sync is known, "));
+		esp_dev->sync = 1;
+
+		if (message_out) {
+			ESPLOG(("esp%d: sending sdtr back, hoping for msgout\n",
+				esp->esp_id));
+			build_sync_nego_msg(esp, period, offset);
+			esp_advance_phase(SCptr, in_the_dark);
+			return EXTENDED_MESSAGE;
+		}
+
+		ESPSDTR(("returning zero\n"));
+		esp_advance_phase(SCptr, in_the_dark); /* ...or else! */
+		return 0;
+	} else if (esp->cur_msgin[2] == EXTENDED_WDTR) {
+		int size = 8 << esp->cur_msgin[3];
+
+		esp->wnip = 0;
+		if (esp->erev != fashme) {
+			ESPLOG(("esp%d: AIEEE wide msg received and not HME.\n",
+				esp->esp_id));
+			message_out = MESSAGE_REJECT;
+		} else if (size > 16) {
+			ESPLOG(("esp%d: AIEEE wide transfer for %d size "
+				"not supported.\n", esp->esp_id, size));
+			message_out = MESSAGE_REJECT;
+		} else {
+			/* Things look good; let's see what we got. */
+			if (size == 16) {
+				/* Set config 3 register for this target. */
+				esp->config3[SCptr->device->id] |= ESP_CONFIG3_EWIDE;
+			} else {
+				/* Just make sure it was one byte sized. */
+				if (size != 8) {
+					ESPLOG(("esp%d: Aieee, wide nego of %d size.\n",
+						esp->esp_id, size));
+					message_out = MESSAGE_REJECT;
+					goto finish;
+				}
+				/* Pure paranoia. */
+				esp->config3[SCptr->device->id] &= ~(ESP_CONFIG3_EWIDE);
+			}
+			esp->prev_cfg3 = esp->config3[SCptr->device->id];
+			sbus_writeb(esp->prev_cfg3, esp->eregs + ESP_CFG3);
+
+			/* Regardless, next try for sync transfers. */
+			build_sync_nego_msg(esp, esp->sync_defp, 15);
+			esp_dev->sync = 1;
+			esp->snip = 1;
+			message_out = EXTENDED_MESSAGE;
+		}
+	} else if (esp->cur_msgin[2] == EXTENDED_MODIFY_DATA_POINTER) {
+		ESPLOG(("esp%d: rejecting modify data ptr msg\n", esp->esp_id));
+		message_out = MESSAGE_REJECT;
+	}
+finish:
+	esp_advance_phase(SCptr, in_the_dark);
+	return message_out;
+}
+
+static int esp_do_msgindone(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	int message_out = 0, it = 0, rval;
+
+	rval = skipahead1(esp, SCptr, in_msgin, in_msgindone);
+	if (rval)
+		return rval;
+	if (SCptr->SCp.sent_command != in_status) {
+		if (!(esp->ireg & ESP_INTR_DC)) {
+			if (esp->msgin_len && (esp->sreg & ESP_STAT_PERR)) {
+				message_out = MSG_PARITY_ERROR;
+				esp_cmd(esp, ESP_CMD_FLUSH);
+			} else if (esp->erev != fashme &&
+			  (it = (sbus_readb(esp->eregs + ESP_FFLAGS) & ESP_FF_FBYTES)) != 1) {
+				/* We certainly dropped the ball somewhere. */
+				message_out = INITIATOR_ERROR;
+				esp_cmd(esp, ESP_CMD_FLUSH);
+			} else if (!esp->msgin_len) {
+				if (esp->erev == fashme)
+					it = esp->hme_fifo_workaround_buffer[0];
+				else
+					it = sbus_readb(esp->eregs + ESP_FDATA);
+				esp_advance_phase(SCptr, in_msgincont);
+			} else {
+				/* it is ok and we want it */
+				if (esp->erev == fashme)
+					it = esp->cur_msgin[esp->msgin_ctr] =
+						esp->hme_fifo_workaround_buffer[0];
+				else
+					it = esp->cur_msgin[esp->msgin_ctr] =
+						sbus_readb(esp->eregs + ESP_FDATA);
+				esp->msgin_ctr++;
+			}
+		} else {
+			esp_advance_phase(SCptr, in_the_dark);
+			return do_work_bus;
+		}
+	} else {
+		it = esp->cur_msgin[0];
+	}
+	if (!message_out && esp->msgin_len) {
+		if (esp->msgin_ctr < esp->msgin_len) {
+			esp_advance_phase(SCptr, in_msgincont);
+		} else if (esp->msgin_len == 1) {
+			message_out = check_singlebyte_msg(esp);
+		} else if (esp->msgin_len == 2) {
+			if (esp->cur_msgin[0] == EXTENDED_MESSAGE) {
+				if ((it + 2) >= 15) {
+					message_out = MESSAGE_REJECT;
+				} else {
+					esp->msgin_len = (it + 2);
+					esp_advance_phase(SCptr, in_msgincont);
+				}
+			} else {
+				message_out = MESSAGE_REJECT; /* foo on you */
+			}
+		} else {
+			message_out = check_multibyte_msg(esp);
+		}
+	}
+	if (message_out < 0) {
+		return -message_out;
+	} else if (message_out) {
+		if (((message_out != 1) &&
+		     ((message_out < 0x20) || (message_out & 0x80))))
+			esp->msgout_len = 1;
+		esp->cur_msgout[0] = message_out;
+		esp_cmd(esp, ESP_CMD_SATN);
+		esp_advance_phase(SCptr, in_the_dark);
+		esp->msgin_len = 0;
+	}
+	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
+	esp->sreg &= ~(ESP_STAT_INTR);
+	if ((esp->sreg & (ESP_STAT_PMSG|ESP_STAT_PCD)) == (ESP_STAT_PMSG|ESP_STAT_PCD))
+		esp_cmd(esp, ESP_CMD_MOK);
+	if ((SCptr->SCp.sent_command == in_msgindone) &&
+	    (SCptr->SCp.phase == in_freeing))
+		return esp_do_freebus(esp);
+	return do_intr_end;
+}
+
+static int esp_do_cmdbegin(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+
+	esp_advance_phase(SCptr, in_cmdend);
+	if (esp->erev == fashme) {
+		u32 tmp = sbus_readl(esp->dregs + DMA_CSR);
+		int i;
+
+		for (i = 0; i < esp->esp_scmdleft; i++)
+			esp->esp_command[i] = *esp->esp_scmdp++;
+		esp->esp_scmdleft = 0;
+		esp_cmd(esp, ESP_CMD_FLUSH);
+		esp_setcount(esp->eregs, i, 1);
+		esp_cmd(esp, (ESP_CMD_DMA | ESP_CMD_TI));
+		tmp |= (DMA_SCSI_DISAB | DMA_ENABLE);
+		tmp &= ~(DMA_ST_WRITE);
+		sbus_writel(i, esp->dregs + DMA_COUNT);
+		sbus_writel(esp->esp_command_dvma, esp->dregs + DMA_ADDR);
+		sbus_writel(tmp, esp->dregs + DMA_CSR);
+	} else {
+		u8 tmp;
+
+		esp_cmd(esp, ESP_CMD_FLUSH);
+		tmp = *esp->esp_scmdp++;
+		esp->esp_scmdleft--;
+		sbus_writeb(tmp, esp->eregs + ESP_FDATA);
+		esp_cmd(esp, ESP_CMD_TI);
+	}
+	return do_intr_end;
+}
+
+static int esp_do_cmddone(struct esp *esp)
+{
+	if (esp->erev == fashme)
+		dma_invalidate(esp);
+	else
+		esp_cmd(esp, ESP_CMD_NULL);
+
+	if (esp->ireg & ESP_INTR_BSERV) {
+		esp_advance_phase(esp->current_SC, in_the_dark);
+		return esp_do_phase_determine(esp);
+	}
+
+	ESPLOG(("esp%d: in do_cmddone() but didn't get BSERV interrupt.\n",
+		esp->esp_id));
+	return do_reset_bus;
+}
+
+static int esp_do_msgout(struct esp *esp)
+{
+	esp_cmd(esp, ESP_CMD_FLUSH);
+	switch (esp->msgout_len) {
+	case 1:
+		if (esp->erev == fashme)
+			hme_fifo_push(esp, &esp->cur_msgout[0], 1);
+		else
+			sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
+
+		esp_cmd(esp, ESP_CMD_TI);
+		break;
+
+	case 2:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+
+		if (esp->erev == fashme) {
+			hme_fifo_push(esp, &esp->cur_msgout[0], 2);
+			esp_cmd(esp, ESP_CMD_TI);
+		} else {
+			dma_setup(esp, esp->esp_command_dvma, 2, 0);
+			esp_setcount(esp->eregs, 2, 0);
+			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	case 4:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+		esp->esp_command[2] = esp->cur_msgout[2];
+		esp->esp_command[3] = esp->cur_msgout[3];
+		esp->snip = 1;
+
+		if (esp->erev == fashme) {
+			hme_fifo_push(esp, &esp->cur_msgout[0], 4);
+			esp_cmd(esp, ESP_CMD_TI);
+		} else {
+			dma_setup(esp, esp->esp_command_dvma, 4, 0);
+			esp_setcount(esp->eregs, 4, 0);
+			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	case 5:
+		esp->esp_command[0] = esp->cur_msgout[0];
+		esp->esp_command[1] = esp->cur_msgout[1];
+		esp->esp_command[2] = esp->cur_msgout[2];
+		esp->esp_command[3] = esp->cur_msgout[3];
+		esp->esp_command[4] = esp->cur_msgout[4];
+		esp->snip = 1;
+
+		if (esp->erev == fashme) {
+			hme_fifo_push(esp, &esp->cur_msgout[0], 5);
+			esp_cmd(esp, ESP_CMD_TI);
+		} else {
+			dma_setup(esp, esp->esp_command_dvma, 5, 0);
+			esp_setcount(esp->eregs, 5, 0);
+			esp_cmd(esp, ESP_CMD_DMA | ESP_CMD_TI);
+		}
+		break;
+
+	default:
+		/* whoops */
+		ESPMISC(("bogus msgout sending NOP\n"));
+		esp->cur_msgout[0] = NOP;
+
+		if (esp->erev == fashme) {
+			hme_fifo_push(esp, &esp->cur_msgout[0], 1);
+		} else {
+			sbus_writeb(esp->cur_msgout[0], esp->eregs + ESP_FDATA);
+		}
+
+		esp->msgout_len = 1;
+		esp_cmd(esp, ESP_CMD_TI);
+		break;
+	};
+
+	esp_advance_phase(esp->current_SC, in_msgoutdone);
+	return do_intr_end;
+}
+
+static int esp_do_msgoutdone(struct esp *esp)
+{
+	if (esp->msgout_len > 1) {
+		/* XXX HME/FAS ATN deassert workaround required,
+		 * XXX no DMA flushing, only possible ESP_CMD_FLUSH
+		 * XXX to kill the fifo.
+		 */
+		if (esp->erev != fashme) {
+			u32 tmp;
+
+			while ((tmp = sbus_readl(esp->dregs + DMA_CSR)) & DMA_PEND_READ)
+				udelay(1);
+			tmp &= ~DMA_ENABLE;
+			sbus_writel(tmp, esp->dregs + DMA_CSR);
+			dma_invalidate(esp);
+		} else {
+			esp_cmd(esp, ESP_CMD_FLUSH);
+		}
+	}
+	if (!(esp->ireg & ESP_INTR_DC)) {
+		if (esp->erev != fashme)
+			esp_cmd(esp, ESP_CMD_NULL);
+		switch (esp->sreg & ESP_STAT_PMASK) {
+		case ESP_MOP:
+			/* whoops, parity error */
+			ESPLOG(("esp%d: still in msgout, parity error assumed\n",
+				esp->esp_id));
+			if (esp->msgout_len > 1)
+				esp_cmd(esp, ESP_CMD_SATN);
+			esp_advance_phase(esp->current_SC, in_msgout);
+			return do_work_bus;
+
+		case ESP_DIP:
+			break;
+
+		default:
+			/* Happy Meal fifo is touchy... */
+			if ((esp->erev != fashme) &&
+			    !fcount(esp) &&
+			    !(((struct esp_device *)esp->current_SC->device->hostdata)->sync_max_offset))
+				esp_cmd(esp, ESP_CMD_FLUSH);
+			break;
+
+		};
+	} else {
+		ESPLOG(("esp%d: disconnect, resetting bus\n", esp->esp_id));
+		return do_reset_bus;
+	}
+
+	/* If we sent out a synchronous negotiation message, update
+	 * our state.
+	 */
+	if (esp->cur_msgout[2] == EXTENDED_MESSAGE &&
+	    esp->cur_msgout[4] == EXTENDED_SDTR) {
+		esp->snip = 1; /* anal retentiveness... */
+	}
+
+	esp->prevmsgout = esp->cur_msgout[0];
+	esp->msgout_len = 0;
+	esp_advance_phase(esp->current_SC, in_the_dark);
+	return esp_do_phase_determine(esp);
+}
+
+static int esp_bus_unexpected(struct esp *esp)
+{
+	ESPLOG(("esp%d: command in weird state %2x\n",
+		esp->esp_id, esp->current_SC->SCp.phase));
+	return do_reset_bus;
+}
+
+static espfunc_t bus_vector[] = {
+	esp_do_data_finale,
+	esp_do_data_finale,
+	esp_bus_unexpected,
+	esp_do_msgin,
+	esp_do_msgincont,
+	esp_do_msgindone,
+	esp_do_msgout,
+	esp_do_msgoutdone,
+	esp_do_cmdbegin,
+	esp_do_cmddone,
+	esp_do_status,
+	esp_do_freebus,
+	esp_do_phase_determine,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+	esp_bus_unexpected,
+};
+
+/* This is the second tier in our dual-level SCSI state machine. */
+static int esp_work_bus(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr = esp->current_SC;
+	unsigned int phase;
+
+	ESPBUS(("esp_work_bus: "));
+	if (!SCptr) {
+		ESPBUS(("reconnect\n"));
+		return esp_do_reconnect(esp);
+	}
+	phase = SCptr->SCp.phase;
+	if ((phase & 0xf0) == in_phases_mask)
+		return bus_vector[(phase & 0x0f)](esp);
+	else if ((phase & 0xf0) == in_slct_mask)
+		return esp_select_complete(esp);
+	else
+		return esp_bus_unexpected(esp);
+}
+
+static espfunc_t isvc_vector[] = {
+	0,
+	esp_do_phase_determine,
+	esp_do_resetbus,
+	esp_finish_reset,
+	esp_work_bus
+};
+
+/* Main interrupt handler for an esp adapter. */
+static void esp_handle(struct esp *esp)
+{
+	struct scsi_cmnd *SCptr;
+	int what_next = do_intr_end;
+
+	SCptr = esp->current_SC;
+
+	/* Check for errors. */
+	esp->sreg = sbus_readb(esp->eregs + ESP_STATUS);
+	esp->sreg &= (~ESP_STAT_INTR);
+	if (esp->erev == fashme) {
+		esp->sreg2 = sbus_readb(esp->eregs + ESP_STATUS2);
+		esp->seqreg = (sbus_readb(esp->eregs + ESP_SSTEP) & ESP_STEP_VBITS);
+	}
+
+	if (esp->sreg & (ESP_STAT_SPAM)) {
+		/* Gross error, could be due to one of:
+		 *
+		 * - top of fifo overwritten, could be because
+		 *   we tried to do a synchronous transfer with
+		 *   an offset greater than ESP fifo size
+		 *
+		 * - top of command register overwritten
+		 *
+		 * - DMA setup to go in one direction, SCSI
+		 *   bus points in the other, whoops
+		 *
+		 * - weird phase change during asynchronous
+		 *   data phase while we are initiator
+		 */
+		ESPLOG(("esp%d: Gross error sreg=%2x\n", esp->esp_id, esp->sreg));
+
+		/* If a command is live on the bus we cannot safely
+		 * reset the bus, so we'll just let the pieces fall
+		 * where they may.  Here we are hoping that the
+		 * target will be able to cleanly go away soon
+		 * so we can safely reset things.
+		 */
+		if (!SCptr) {
+			ESPLOG(("esp%d: No current cmd during gross error, "
+				"resetting bus\n", esp->esp_id));
+			what_next = do_reset_bus;
+			goto state_machine;
+		}
+	}
+
+	if (sbus_readl(esp->dregs + DMA_CSR) & DMA_HNDL_ERROR) {
+		/* A DMA gate array error.  Here we must
+		 * be seeing one of two things.  Either the
+		 * virtual to physical address translation
+		 * on the SBUS could not occur, else the
+		 * translation it did get pointed to a bogus
+		 * page.  Ho hum...
+		 */
+		ESPLOG(("esp%d: DMA error %08x\n", esp->esp_id,
+			sbus_readl(esp->dregs + DMA_CSR)));
+
+		/* DMA gate array itself must be reset to clear the
+		 * error condition.
+		 */
+		esp_reset_dma(esp);
+
+		what_next = do_reset_bus;
+		goto state_machine;
+	}
+
+	esp->ireg = sbus_readb(esp->eregs + ESP_INTRPT);   /* Unlatch intr reg */
+
+	if (esp->erev == fashme) {
+		/* This chip is really losing. */
+		ESPHME(("HME["));
+
+		ESPHME(("sreg2=%02x,", esp->sreg2));
+		/* Must latch fifo before reading the interrupt
+		 * register else garbage ends up in the FIFO
+		 * which confuses the driver utterly.
+		 */
+		if (!(esp->sreg2 & ESP_STAT2_FEMPTY) ||
+		    (esp->sreg2 & ESP_STAT2_F1BYTE)) {
+			ESPHME(("fifo_workaround]"));
+			hme_fifo_read(esp);
+		} else {
+			ESPHME(("no_fifo_workaround]"));
+		}
+	}
+
+	/* No current cmd is only valid at this point when there are
+	 * commands off the bus or we are trying a reset.
+	 */
+	if (!SCptr && !esp->disconnected_SC && !(esp->ireg & ESP_INTR_SR)) {
+		/* Panic is safe, since current_SC is null. */
+		ESPLOG(("esp%d: no command in esp_handle()\n", esp->esp_id));
+		panic("esp_handle: current_SC == penguin within interrupt!");
+	}
+
+	if (esp->ireg & (ESP_INTR_IC)) {
+		/* Illegal command fed to ESP.  Outside of obvious
+		 * software bugs that could cause this, there is
+		 * a condition with esp100 where we can confuse the
+		 * ESP into an erroneous illegal command interrupt
+		 * because it does not scrape the FIFO properly
+		 * for reselection.  See esp100_reconnect_hwbug()
+		 * to see how we try very hard to avoid this.
+		 */
+		ESPLOG(("esp%d: invalid command\n", esp->esp_id));
+
+		esp_dump_state(esp);
+
+		if (SCptr != NULL) {
+			/* Devices with very buggy firmware can drop BSY
+			 * during a scatter list interrupt when using sync
+			 * mode transfers.  We continue the transfer as
+			 * expected, the target drops the bus, the ESP
+			 * gets confused, and we get a illegal command
+			 * interrupt because the bus is in the disconnected
+			 * state now and ESP_CMD_TI is only allowed when
+			 * a nexus is alive on the bus.
+			 */
+			ESPLOG(("esp%d: Forcing async and disabling disconnect for "
+				"target %d\n", esp->esp_id, SCptr->device->id));
+			SCptr->device->borken = 1; /* foo on you */
+		}
+
+		what_next = do_reset_bus;
+	} else if (!(esp->ireg & ~(ESP_INTR_FDONE | ESP_INTR_BSERV | ESP_INTR_DC))) {
+		if (SCptr) {
+			unsigned int phase = SCptr->SCp.phase;
+
+			if (phase & in_phases_mask) {
+				what_next = esp_work_bus(esp);
+			} else if (phase & in_slct_mask) {
+				what_next = esp_select_complete(esp);
+			} else {
+				ESPLOG(("esp%d: interrupt for no good reason...\n",
+					esp->esp_id));
+				what_next = do_intr_end;
+			}
+		} else {
+			ESPLOG(("esp%d: BSERV or FDONE or DC while SCptr==NULL\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	} else if (esp->ireg & ESP_INTR_SR) {
+		ESPLOG(("esp%d: SCSI bus reset interrupt\n", esp->esp_id));
+		what_next = do_reset_complete;
+	} else if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN)) {
+		ESPLOG(("esp%d: AIEEE we have been selected by another initiator!\n",
+			esp->esp_id));
+		what_next = do_reset_bus;
+	} else if (esp->ireg & ESP_INTR_RSEL) {
+		if (SCptr == NULL) {
+			/* This is ok. */
+			what_next = esp_do_reconnect(esp);
+		} else if (SCptr->SCp.phase & in_slct_mask) {
+			/* Only selection code knows how to clean
+			 * up properly.
+			 */
+			ESPDISC(("Reselected during selection attempt\n"));
+			what_next = esp_select_complete(esp);
+		} else {
+			ESPLOG(("esp%d: Reselected while bus is busy\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	}
+
+	/* This is tier-one in our dual level SCSI state machine. */
+state_machine:
+	while (what_next != do_intr_end) {
+		if (what_next >= do_phase_determine &&
+		    what_next < do_intr_end) {
+			what_next = isvc_vector[what_next](esp);
+		} else {
+			/* state is completely lost ;-( */
+			ESPLOG(("esp%d: interrupt engine loses state, resetting bus\n",
+				esp->esp_id));
+			what_next = do_reset_bus;
+		}
+	}
+}
+
+/* Service only the ESP described by dev_id. */
+static irqreturn_t esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct esp *esp = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(esp->ehost->host_lock, flags);
+	if (ESP_IRQ_P(esp->dregs)) {
+		ESP_INTSOFF(esp->dregs);
+
+		ESPIRQ(("I[%d:%d](", smp_processor_id(), esp->esp_id));
+		esp_handle(esp);
+		ESPIRQ((")"));
+
+		ESP_INTSON(esp->dregs);
+	}
+	spin_unlock_irqrestore(esp->ehost->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int esp_slave_alloc(struct scsi_device *SDptr)
+{
+	struct esp_device *esp_dev =
+		kmalloc(sizeof(struct esp_device), GFP_ATOMIC);
+
+	if (!esp_dev)
+		return -ENOMEM;
+	memset(esp_dev, 0, sizeof(struct esp_device));
+	SDptr->hostdata = esp_dev;
+	return 0;
+}
+
+static void esp_slave_destroy(struct scsi_device *SDptr)
+{
+	struct esp *esp = (struct esp *) SDptr->host->hostdata;
+
+	esp->targets_present &= ~(1 << SDptr->id);
+	kfree(SDptr->hostdata);
+	SDptr->hostdata = NULL;
+}
+
+static struct scsi_host_template driver_template = {
+	.proc_name		= "esp",
+	.proc_info		= esp_proc_info,
+	.name			= "Sun ESP 100/100a/200",
+	.detect			= esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= esp_release,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/esp.h b/drivers/scsi/esp.h
new file mode 100644
index 0000000..73f7d69
--- /dev/null
+++ b/drivers/scsi/esp.h
@@ -0,0 +1,410 @@
+/* $Id: esp.h,v 1.29 2001/12/11 04:55:47 davem Exp $
+ * esp.h:  Defines and structures for the Sparc ESP (Enhanced SCSI
+ *         Processor) driver under Linux.
+ *
+ * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ */
+
+#ifndef _SPARC_ESP_H
+#define _SPARC_ESP_H
+
+/* For dvma controller register definitions. */
+#include <asm/dma.h>
+
+/* The ESP SCSI controllers have their register sets in three
+ * "classes":
+ *
+ * 1) Registers which are both read and write.
+ * 2) Registers which are read only.
+ * 3) Registers which are write only.
+ *
+ * Yet, they all live within the same IO space.
+ */
+
+/* All the ESP registers are one byte each and are accessed longwords
+ * apart with a big-endian ordering to the bytes.
+ */
+					/* Access    Description              Offset */
+#define ESP_TCLOW	0x00UL		/* rw  Low bits of the transfer count 0x00   */
+#define ESP_TCMED	0x04UL		/* rw  Mid bits of the transfer count 0x04   */
+#define ESP_FDATA	0x08UL		/* rw  FIFO data bits                 0x08   */
+#define ESP_CMD		0x0cUL		/* rw  SCSI command bits              0x0c   */
+#define ESP_STATUS	0x10UL		/* ro  ESP status register            0x10   */
+#define ESP_BUSID	ESP_STATUS	/* wo  Bus ID for select/reselect     0x10   */
+#define ESP_INTRPT	0x14UL		/* ro  Kind of interrupt              0x14   */
+#define ESP_TIMEO	ESP_INTRPT	/* wo  Timeout value for select/resel 0x14   */
+#define ESP_SSTEP	0x18UL		/* ro  Sequence step register         0x18   */
+#define ESP_STP		ESP_SSTEP	/* wo  Transfer period per sync       0x18   */
+#define ESP_FFLAGS	0x1cUL		/* ro  Bits of current FIFO info      0x1c   */
+#define ESP_SOFF	ESP_FFLAGS	/* wo  Sync offset                    0x1c   */
+#define ESP_CFG1	0x20UL		/* rw  First configuration register   0x20   */
+#define ESP_CFACT	0x24UL		/* wo  Clock conversion factor        0x24   */
+#define ESP_STATUS2	ESP_CFACT	/* ro  HME status2 register           0x24   */
+#define ESP_CTEST	0x28UL		/* wo  Chip test register             0x28   */
+#define ESP_CFG2	0x2cUL		/* rw  Second configuration register  0x2c   */
+#define ESP_CFG3	0x30UL		/* rw  Third configuration register   0x30   */
+#define ESP_TCHI	0x38UL		/* rw  High bits of transfer count    0x38   */
+#define ESP_UID		ESP_TCHI	/* ro  Unique ID code                 0x38   */
+#define FAS_RLO		ESP_TCHI	/* rw  HME extended counter           0x38   */
+#define ESP_FGRND	0x3cUL		/* rw  Data base for fifo             0x3c   */
+#define FAS_RHI		ESP_FGRND	/* rw  HME extended counter           0x3c   */
+#define ESP_REG_SIZE	0x40UL
+
+/* Various revisions of the ESP board. */
+enum esp_rev {
+	esp100     = 0x00,  /* NCR53C90 - very broken */
+	esp100a    = 0x01,  /* NCR53C90A */
+	esp236     = 0x02,
+	fas236     = 0x03,
+	fas100a    = 0x04,
+	fast       = 0x05,
+	fashme     = 0x06,
+	espunknown = 0x07
+};
+
+/* We allocate one of these for each scsi device and attach it to
+ * SDptr->hostdata for use in the driver
+ */
+struct esp_device {
+  unsigned char sync_min_period;
+  unsigned char sync_max_offset;
+  unsigned sync:1;
+  unsigned wide:1;
+  unsigned disconnect:1;
+};
+
+struct scsi_cmnd;
+
+/* We get one of these for each ESP probed. */
+struct esp {
+	void __iomem		*eregs;		/* ESP controller registers */
+	void __iomem		*dregs;		/* DMA controller registers */
+	struct sbus_dma		*dma;		/* DMA controller sw state */
+	struct Scsi_Host	*ehost;		/* Backpointer to SCSI Host */
+	struct sbus_dev		*sdev;		/* Pointer to SBus entry */
+
+	/* ESP Configuration Registers */
+	u8			config1;	/* Copy of the 1st config register */
+	u8			config2;	/* Copy of the 2nd config register */
+	u8			config3[16];	/* Copy of the 3rd config register */
+
+	/* The current command we are sending to the ESP chip.  This esp_command
+	 * ptr needs to be mapped in DVMA area so we can send commands and read
+	 * from the ESP fifo without burning precious CPU cycles.  Programmed I/O
+	 * sucks when we have the DVMA to do it for us.  The ESP is stupid and will
+	 * only send out 6, 10, and 12 byte SCSI commands, others we need to send
+	 * one byte at a time.  esp_slowcmd being set says that we are doing one
+	 * of the command types ESP doesn't understand, esp_scmdp keeps track of
+	 * which byte we are sending, esp_scmdleft says how many bytes to go.
+	 */
+	volatile u8		*esp_command;    /* Location of command (CPU view)  */
+	__u32			esp_command_dvma;/* Location of command (DVMA view) */
+	unsigned char		esp_clen;	 /* Length of this command */
+	unsigned char		esp_slowcmd;
+	unsigned char		*esp_scmdp;
+	unsigned char		esp_scmdleft;
+
+	/* The following are used to determine the cause of an IRQ. Upon every
+	 * IRQ entry we synchronize these with the hardware registers.
+	 */
+	u8			ireg;		/* Copy of ESP interrupt register */
+	u8			sreg;		/* Copy of ESP status register */
+	u8			seqreg;		/* Copy of ESP sequence step register */
+	u8			sreg2;		/* Copy of HME status2 register */
+
+	/* To save register writes to the ESP, which can be expensive, we
+	 * keep track of the previous value that various registers had for
+	 * the last target we connected to.  If they are the same for the
+	 * current target, we skip the register writes as they are not needed.
+	 */
+	u8			prev_soff, prev_stp;
+	u8			prev_cfg3, __cache_pad;
+
+	/* We also keep a cache of the previous FAS/HME DMA CSR register value.  */
+	u32			prev_hme_dmacsr;
+
+	/* The HME is the biggest piece of shit I have ever seen. */
+	u8			hme_fifo_workaround_buffer[16 * 2];
+	u8			hme_fifo_workaround_count;
+
+	/* For each target we keep track of save/restore data
+	 * pointer information.  This needs to be updated majorly
+	 * when we add support for tagged queueing.  -DaveM
+	 */
+	struct esp_pointers {
+		char			*saved_ptr;
+		struct scatterlist	*saved_buffer;
+		int			saved_this_residual;
+		int			saved_buffers_residual;
+	} data_pointers[16] /*XXX [MAX_TAGS_PER_TARGET]*/;
+
+	/* Clock periods, frequencies, synchronization, etc. */
+	unsigned int		cfreq;		/* Clock frequency in HZ */
+	unsigned int		cfact;		/* Clock conversion factor */
+	unsigned int		raw_cfact;	/* Raw copy from probing */
+	unsigned int		ccycle;		/* One ESP clock cycle */
+	unsigned int		ctick;		/* One ESP clock time */
+	unsigned int		radelay;	/* FAST chip req/ack delay */
+	unsigned int		neg_defp;	/* Default negotiation period */
+	unsigned int		sync_defp;	/* Default sync transfer period */
+	unsigned int		max_period;	/* longest our period can be */
+	unsigned int		min_period;	/* shortest period we can withstand */
+
+	struct esp		*next;		/* Next ESP we probed or NULL */
+	char			prom_name[64];	/* Name of ESP device from prom */
+	int			prom_node;	/* Prom node where ESP found */
+	int			esp_id;		/* Unique per-ESP ID number */
+
+	/* For slow to medium speed input clock rates we shoot for 5mb/s,
+	 * but for high input clock rates we try to do 10mb/s although I
+	 * don't think a transfer can even run that fast with an ESP even
+	 * with DMA2 scatter gather pipelining.
+	 */
+#define SYNC_DEFP_SLOW            0x32   /* 5mb/s  */
+#define SYNC_DEFP_FAST            0x19   /* 10mb/s */
+
+	unsigned int		snip;		/* Sync. negotiation in progress */
+	unsigned int		wnip;		/* WIDE negotiation in progress */
+	unsigned int		targets_present;/* targets spoken to before */
+
+	int		current_transfer_size;	/* Set at beginning of data dma */
+
+	u8			espcmdlog[32];	/* Log of current esp cmds sent. */
+	u8			espcmdent;	/* Current entry in esp cmd log. */
+
+	/* Misc. info about this ESP */
+	enum esp_rev		erev;		/* ESP revision */
+	int			irq;		/* SBus IRQ for this ESP */
+	int			scsi_id;	/* Who am I as initiator? */
+	int			scsi_id_mask;	/* Bitmask of 'me'. */
+	int			diff;		/* Differential SCSI bus? */
+	int			bursts;		/* Burst sizes our DVMA supports */
+
+	/* Our command queues, only one cmd lives in the current_SC queue. */
+	struct scsi_cmnd	*issue_SC;	/* Commands to be issued */
+	struct scsi_cmnd	*current_SC;	/* Who is currently working the bus */
+	struct scsi_cmnd	*disconnected_SC;/* Commands disconnected from the bus */
+
+	/* Message goo */
+	u8			cur_msgout[16];
+	u8			cur_msgin[16];
+	u8			prevmsgout, prevmsgin;
+	u8			msgout_len, msgin_len;
+	u8			msgout_ctr, msgin_ctr;
+
+	/* States that we cannot keep in the per cmd structure because they
+	 * cannot be assosciated with any specific command.
+	 */
+	u8			resetting_bus;
+	wait_queue_head_t	reset_queue;
+};
+
+/* Bitfield meanings for the above registers. */
+
+/* ESP config reg 1, read-write, found on all ESP chips */
+#define ESP_CONFIG1_ID        0x07             /* My BUS ID bits */
+#define ESP_CONFIG1_CHTEST    0x08             /* Enable ESP chip tests */
+#define ESP_CONFIG1_PENABLE   0x10             /* Enable parity checks */
+#define ESP_CONFIG1_PARTEST   0x20             /* Parity test mode enabled? */
+#define ESP_CONFIG1_SRRDISAB  0x40             /* Disable SCSI reset reports */
+#define ESP_CONFIG1_SLCABLE   0x80             /* Enable slow cable mode */
+
+/* ESP config reg 2, read-write, found only on esp100a+esp200+esp236 chips */
+#define ESP_CONFIG2_DMAPARITY 0x01             /* enable DMA Parity (200,236) */
+#define ESP_CONFIG2_REGPARITY 0x02             /* enable reg Parity (200,236) */
+#define ESP_CONFIG2_BADPARITY 0x04             /* Bad parity target abort  */
+#define ESP_CONFIG2_SCSI2ENAB 0x08             /* Enable SCSI-2 features (tmode only) */
+#define ESP_CONFIG2_HI        0x10             /* High Impedance DREQ ???  */
+#define ESP_CONFIG2_HMEFENAB  0x10             /* HME features enable */
+#define ESP_CONFIG2_BCM       0x20             /* Enable byte-ctrl (236)   */
+#define ESP_CONFIG2_DISPINT   0x20             /* Disable pause irq (hme) */
+#define ESP_CONFIG2_FENAB     0x40             /* Enable features (fas100,esp216)      */
+#define ESP_CONFIG2_SPL       0x40             /* Enable status-phase latch (esp236)   */
+#define ESP_CONFIG2_MKDONE    0x40             /* HME magic feature */
+#define ESP_CONFIG2_HME32     0x80             /* HME 32 extended */
+#define ESP_CONFIG2_MAGIC     0xe0             /* Invalid bits... */
+
+/* ESP config register 3 read-write, found only esp236+fas236+fas100a+hme chips */
+#define ESP_CONFIG3_FCLOCK    0x01             /* FAST SCSI clock rate (esp100a/hme) */
+#define ESP_CONFIG3_TEM       0x01             /* Enable thresh-8 mode (esp/fas236)  */
+#define ESP_CONFIG3_FAST      0x02             /* Enable FAST SCSI     (esp100a/hme) */
+#define ESP_CONFIG3_ADMA      0x02             /* Enable alternate-dma (esp/fas236)  */
+#define ESP_CONFIG3_TENB      0x04             /* group2 SCSI2 support (esp100a/hme) */
+#define ESP_CONFIG3_SRB       0x04             /* Save residual byte   (esp/fas236)  */
+#define ESP_CONFIG3_TMS       0x08             /* Three-byte msg's ok  (esp100a/hme) */
+#define ESP_CONFIG3_FCLK      0x08             /* Fast SCSI clock rate (esp/fas236)  */
+#define ESP_CONFIG3_IDMSG     0x10             /* ID message checking  (esp100a/hme) */
+#define ESP_CONFIG3_FSCSI     0x10             /* Enable FAST SCSI     (esp/fas236)  */
+#define ESP_CONFIG3_GTM       0x20             /* group2 SCSI2 support (esp/fas236)  */
+#define ESP_CONFIG3_IDBIT3    0x20             /* Bit 3 of HME SCSI-ID (hme)         */
+#define ESP_CONFIG3_TBMS      0x40             /* Three-byte msg's ok  (esp/fas236)  */
+#define ESP_CONFIG3_EWIDE     0x40             /* Enable Wide-SCSI     (hme)         */
+#define ESP_CONFIG3_IMS       0x80             /* ID msg chk'ng        (esp/fas236)  */
+#define ESP_CONFIG3_OBPUSH    0x80             /* Push odd-byte to dma (hme)         */
+
+/* ESP command register read-write */
+/* Group 1 commands:  These may be sent at any point in time to the ESP
+ *                    chip.  None of them can generate interrupts 'cept
+ *                    the "SCSI bus reset" command if you have not disabled
+ *                    SCSI reset interrupts in the config1 ESP register.
+ */
+#define ESP_CMD_NULL          0x00             /* Null command, ie. a nop */
+#define ESP_CMD_FLUSH         0x01             /* FIFO Flush */
+#define ESP_CMD_RC            0x02             /* Chip reset */
+#define ESP_CMD_RS            0x03             /* SCSI bus reset */
+
+/* Group 2 commands:  ESP must be an initiator and connected to a target
+ *                    for these commands to work.
+ */
+#define ESP_CMD_TI            0x10             /* Transfer Information */
+#define ESP_CMD_ICCSEQ        0x11             /* Initiator cmd complete sequence */
+#define ESP_CMD_MOK           0x12             /* Message okie-dokie */
+#define ESP_CMD_TPAD          0x18             /* Transfer Pad */
+#define ESP_CMD_SATN          0x1a             /* Set ATN */
+#define ESP_CMD_RATN          0x1b             /* De-assert ATN */
+
+/* Group 3 commands:  ESP must be in the MSGOUT or MSGIN state and be connected
+ *                    to a target as the initiator for these commands to work.
+ */
+#define ESP_CMD_SMSG          0x20             /* Send message */
+#define ESP_CMD_SSTAT         0x21             /* Send status */
+#define ESP_CMD_SDATA         0x22             /* Send data */
+#define ESP_CMD_DSEQ          0x23             /* Discontinue Sequence */
+#define ESP_CMD_TSEQ          0x24             /* Terminate Sequence */
+#define ESP_CMD_TCCSEQ        0x25             /* Target cmd cmplt sequence */
+#define ESP_CMD_DCNCT         0x27             /* Disconnect */
+#define ESP_CMD_RMSG          0x28             /* Receive Message */
+#define ESP_CMD_RCMD          0x29             /* Receive Command */
+#define ESP_CMD_RDATA         0x2a             /* Receive Data */
+#define ESP_CMD_RCSEQ         0x2b             /* Receive cmd sequence */
+
+/* Group 4 commands:  The ESP must be in the disconnected state and must
+ *                    not be connected to any targets as initiator for
+ *                    these commands to work.
+ */
+#define ESP_CMD_RSEL          0x40             /* Reselect */
+#define ESP_CMD_SEL           0x41             /* Select w/o ATN */
+#define ESP_CMD_SELA          0x42             /* Select w/ATN */
+#define ESP_CMD_SELAS         0x43             /* Select w/ATN & STOP */
+#define ESP_CMD_ESEL          0x44             /* Enable selection */
+#define ESP_CMD_DSEL          0x45             /* Disable selections */
+#define ESP_CMD_SA3           0x46             /* Select w/ATN3 */
+#define ESP_CMD_RSEL3         0x47             /* Reselect3 */
+
+/* This bit enables the ESP's DMA on the SBus */
+#define ESP_CMD_DMA           0x80             /* Do DMA? */
+
+
+/* ESP status register read-only */
+#define ESP_STAT_PIO          0x01             /* IO phase bit */
+#define ESP_STAT_PCD          0x02             /* CD phase bit */
+#define ESP_STAT_PMSG         0x04             /* MSG phase bit */
+#define ESP_STAT_PMASK        0x07             /* Mask of phase bits */
+#define ESP_STAT_TDONE        0x08             /* Transfer Completed */
+#define ESP_STAT_TCNT         0x10             /* Transfer Counter Is Zero */
+#define ESP_STAT_PERR         0x20             /* Parity error */
+#define ESP_STAT_SPAM         0x40             /* Real bad error */
+/* This indicates the 'interrupt pending' condition on esp236, it is a reserved
+ * bit on other revs of the ESP.
+ */
+#define ESP_STAT_INTR         0x80             /* Interrupt */
+
+/* HME only: status 2 register */
+#define ESP_STAT2_SCHBIT      0x01 /* Upper bits 3-7 of sstep enabled */
+#define ESP_STAT2_FFLAGS      0x02 /* The fifo flags are now latched */
+#define ESP_STAT2_XCNT        0x04 /* The transfer counter is latched */
+#define ESP_STAT2_CREGA       0x08 /* The command reg is active now */
+#define ESP_STAT2_WIDE        0x10 /* Interface on this adapter is wide */
+#define ESP_STAT2_F1BYTE      0x20 /* There is one byte at top of fifo */
+#define ESP_STAT2_FMSB        0x40 /* Next byte in fifo is most significant */
+#define ESP_STAT2_FEMPTY      0x80 /* FIFO is empty */
+
+/* The status register can be masked with ESP_STAT_PMASK and compared
+ * with the following values to determine the current phase the ESP
+ * (at least thinks it) is in.  For our purposes we also add our own
+ * software 'done' bit for our phase management engine.
+ */
+#define ESP_DOP   (0)                                       /* Data Out  */
+#define ESP_DIP   (ESP_STAT_PIO)                            /* Data In   */
+#define ESP_CMDP  (ESP_STAT_PCD)                            /* Command   */
+#define ESP_STATP (ESP_STAT_PCD|ESP_STAT_PIO)               /* Status    */
+#define ESP_MOP   (ESP_STAT_PMSG|ESP_STAT_PCD)              /* Message Out */
+#define ESP_MIP   (ESP_STAT_PMSG|ESP_STAT_PCD|ESP_STAT_PIO) /* Message In */
+
+/* ESP interrupt register read-only */
+#define ESP_INTR_S            0x01             /* Select w/o ATN */
+#define ESP_INTR_SATN         0x02             /* Select w/ATN */
+#define ESP_INTR_RSEL         0x04             /* Reselected */
+#define ESP_INTR_FDONE        0x08             /* Function done */
+#define ESP_INTR_BSERV        0x10             /* Bus service */
+#define ESP_INTR_DC           0x20             /* Disconnect */
+#define ESP_INTR_IC           0x40             /* Illegal command given */
+#define ESP_INTR_SR           0x80             /* SCSI bus reset detected */
+
+/* Interrupt status macros */
+#define ESP_SRESET_IRQ(esp)  ((esp)->intreg & (ESP_INTR_SR))
+#define ESP_ILLCMD_IRQ(esp)  ((esp)->intreg & (ESP_INTR_IC))
+#define ESP_SELECT_WITH_ATN_IRQ(esp)     ((esp)->intreg & (ESP_INTR_SATN))
+#define ESP_SELECT_WITHOUT_ATN_IRQ(esp)  ((esp)->intreg & (ESP_INTR_S))
+#define ESP_SELECTION_IRQ(esp)  ((ESP_SELECT_WITH_ATN_IRQ(esp)) ||         \
+				 (ESP_SELECT_WITHOUT_ATN_IRQ(esp)))
+#define ESP_RESELECTION_IRQ(esp)         ((esp)->intreg & (ESP_INTR_RSEL))
+
+/* ESP sequence step register read-only */
+#define ESP_STEP_VBITS        0x07             /* Valid bits */
+#define ESP_STEP_ASEL         0x00             /* Selection&Arbitrate cmplt */
+#define ESP_STEP_SID          0x01             /* One msg byte sent */
+#define ESP_STEP_NCMD         0x02             /* Was not in command phase */
+#define ESP_STEP_PPC          0x03             /* Early phase chg caused cmnd
+                                                * bytes to be lost
+                                                */
+#define ESP_STEP_FINI4        0x04             /* Command was sent ok */
+
+/* Ho hum, some ESP's set the step register to this as well... */
+#define ESP_STEP_FINI5        0x05
+#define ESP_STEP_FINI6        0x06
+#define ESP_STEP_FINI7        0x07
+
+/* ESP chip-test register read-write */
+#define ESP_TEST_TARG         0x01             /* Target test mode */
+#define ESP_TEST_INI          0x02             /* Initiator test mode */
+#define ESP_TEST_TS           0x04             /* Tristate test mode */
+
+/* ESP unique ID register read-only, found on fas236+fas100a only */
+#define ESP_UID_F100A         0x00             /* ESP FAS100A  */
+#define ESP_UID_F236          0x02             /* ESP FAS236   */
+#define ESP_UID_REV           0x07             /* ESP revision */
+#define ESP_UID_FAM           0xf8             /* ESP family   */
+
+/* ESP fifo flags register read-only */
+/* Note that the following implies a 16 byte FIFO on the ESP. */
+#define ESP_FF_FBYTES         0x1f             /* Num bytes in FIFO */
+#define ESP_FF_ONOTZERO       0x20             /* offset ctr not zero (esp100) */
+#define ESP_FF_SSTEP          0xe0             /* Sequence step */
+
+/* ESP clock conversion factor register write-only */
+#define ESP_CCF_F0            0x00             /* 35.01MHz - 40MHz */
+#define ESP_CCF_NEVER         0x01             /* Set it to this and die */
+#define ESP_CCF_F2            0x02             /* 10MHz */
+#define ESP_CCF_F3            0x03             /* 10.01MHz - 15MHz */
+#define ESP_CCF_F4            0x04             /* 15.01MHz - 20MHz */
+#define ESP_CCF_F5            0x05             /* 20.01MHz - 25MHz */
+#define ESP_CCF_F6            0x06             /* 25.01MHz - 30MHz */
+#define ESP_CCF_F7            0x07             /* 30.01MHz - 35MHz */
+
+/* HME only... */
+#define ESP_BUSID_RESELID     0x10
+#define ESP_BUSID_CTR32BIT    0x40
+
+#define ESP_BUS_TIMEOUT        275             /* In milli-seconds */
+#define ESP_TIMEO_CONST       8192
+#define ESP_NEG_DEFP(mhz, cfact) \
+        ((ESP_BUS_TIMEOUT * ((mhz) / 1000)) / (8192 * (cfact)))
+#define ESP_MHZ_TO_CYCLE(mhertz)  ((1000000000) / ((mhertz) / 1000))
+#define ESP_TICK(ccf, cycle)  ((7682 * (ccf) * (cycle) / 1000))
+
+/* For our interrupt engine. */
+#define for_each_esp(esp) \
+        for((esp) = espchain; (esp); (esp) = (esp)->next)
+
+#endif /* !(_SPARC_ESP_H) */
diff --git a/drivers/scsi/fastlane.c b/drivers/scsi/fastlane.c
new file mode 100644
index 0000000..ae47612
--- /dev/null
+++ b/drivers/scsi/fastlane.c
@@ -0,0 +1,421 @@
+/* fastlane.c: Driver for Phase5's Fastlane SCSI Controller.
+ *
+ * Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * This driver is based on the CyberStorm driver, hence the occasional
+ * reference to CyberStorm.
+ *
+ * Betatesting & crucial adjustments by
+ *        Patrik Rak (prak3264@ss1000.ms.mff.cuni.cz)
+ *
+ */
+
+/* TODO:
+ *
+ * o According to the doc from laire, it is required to reset the DMA when
+ *   the transfer is done. ATM we reset DMA just before every new 
+ *   dma_init_(read|write).
+ *
+ * 1) Figure out how to make a cleaner merge with the sparc driver with regard
+ *    to the caches and the Sparc MMU mapping.
+ * 2) Make as few routines required outside the generic driver. A lot of the
+ *    routines in this file used to be inline!
+ */
+
+#include <linux/module.h>
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#include <asm/pgtable.h>
+
+/* Such day has just come... */
+#if 0
+/* Let this defined unless you really need to enable DMA IRQ one day */
+#define NODMAIRQ
+#endif
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define FASTLANE_ESP_ADDR 0x1000001
+#define FASTLANE_DMA_ADDR 0x1000041
+
+
+/* The Fastlane DMA interface */
+struct fastlane_dma_registers {
+	volatile unsigned char cond_reg;	/* DMA status  (ro) [0x0000] */
+#define ctrl_reg  cond_reg			/* DMA control (wo) [0x0000] */
+	unsigned char dmapad1[0x3f];
+	volatile unsigned char clear_strobe;    /* DMA clear   (wo) [0x0040] */
+};
+
+
+/* DMA status bits */
+#define FASTLANE_DMA_MINT  0x80
+#define FASTLANE_DMA_IACT  0x40
+#define FASTLANE_DMA_CREQ  0x20
+
+/* DMA control bits */
+#define FASTLANE_DMA_FCODE 0xa0
+#define FASTLANE_DMA_MASK  0xf3
+#define FASTLANE_DMA_LED   0x10	/* HD led control 1 = on */
+#define FASTLANE_DMA_WRITE 0x08 /* 1 = write */
+#define FASTLANE_DMA_ENABLE 0x04 /* Enable DMA */
+#define FASTLANE_DMA_EDI   0x02	/* Enable DMA IRQ ? */
+#define FASTLANE_DMA_ESI   0x01	/* Enable SCSI IRQ */
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddr, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_irq_exit(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static unsigned char ctrl_data = 0;	/* Keep backup of the stuff written
+				 * to ctrl_reg. Always write a copy
+				 * to this register when writing to
+				 * the hardware register!
+				 */
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+static inline void dma_clear(struct NCR_ESP *esp)
+{
+	struct fastlane_dma_registers *dregs =
+		(struct fastlane_dma_registers *) (esp->dregs);
+	unsigned long *t;
+
+	ctrl_data = (ctrl_data & FASTLANE_DMA_MASK);
+	dregs->ctrl_reg = ctrl_data;
+
+	t = (unsigned long *)(esp->edev);
+
+	dregs->clear_strobe = 0;
+	*t = 0 ;
+}
+
+/***************************************************************** Detection */
+int __init fastlane_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+
+	if ((z = zorro_find_device(ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060, z))) {
+	    unsigned long board = z->resource.start;
+	    if (request_mem_region(board+FASTLANE_ESP_ADDR,
+				   sizeof(struct ESP_regs), "NCR53C9x")) {
+		/* Check if this is really a fastlane controller. The problem
+		 * is that also the cyberstorm and blizzard controllers use
+		 * this ID value. Fortunately only Fastlane maps in Z3 space
+		 */
+		if (board < 0x1000000) {
+			goto err_release;
+		}
+		esp = esp_allocate(tpnt, (void *)board+FASTLANE_ESP_ADDR);
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = 0;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = &dma_irq_exit;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		/* Initialize the portBits (enable IRQs) */
+		ctrl_data = (FASTLANE_DMA_FCODE |
+#ifndef NODMAIRQ
+			     FASTLANE_DMA_EDI |
+#endif
+			     FASTLANE_DMA_ESI);
+			
+
+		/* SCSI chip clock */
+		esp->cfreq = 40000000;
+
+
+		/* Map the physical address space into virtual kernel space */
+		address = (unsigned long)
+			z_ioremap(board, z->resource.end-board+1);
+
+		if(!address){
+			printk("Could not remap Fastlane controller memory!");
+			goto err_unregister;
+		}
+
+
+		/* The DMA registers on the Fastlane are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		esp->dregs = (void *)(address + FASTLANE_DMA_ADDR);
+
+		/* ESP register base */
+		esp->eregs = (struct ESP_regs *)(address + FASTLANE_ESP_ADDR);
+
+		/* Board base */
+		esp->edev = (void *) address;
+		
+		/* Set the command buffer */
+		esp->esp_command = cmd_buffer;
+		esp->esp_command_dvma = virt_to_bus((void *)cmd_buffer);
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		esp->slot = board+FASTLANE_ESP_ADDR;
+		if (request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+				"Fastlane SCSI", esp->ehost)) {
+			printk(KERN_WARNING "Fastlane: Could not get IRQ%d, aborting.\n", IRQ_AMIGA_PORTS);
+			goto err_unmap;
+		}			
+
+		/* Controller ID */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		dma_clear(esp);
+		esp_initialize(esp);
+
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps, esps_in_use);
+		esps_running = esps_in_use;
+		return esps_in_use;
+	    }
+	}
+	return 0;
+
+ err_unmap:
+	z_iounmap((void *)address);
+ err_unregister:
+	scsi_unregister (esp->ehost);
+ err_release:
+	release_mem_region(z->resource.start+FASTLANE_ESP_ADDR,
+			   sizeof(struct ESP_regs));
+	return 0;
+}
+
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the Fastlane DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0xfffc)
+		sz = 0xfffc;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+		esp->esp_id, ((struct fastlane_dma_registers *)
+			      (esp->dregs))->cond_reg));
+	ESPLOG(("intreq:<%04x>, intena:<%04x>\n",
+		custom.intreqr, custom.intenar));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct fastlane_dma_registers *dregs = 
+		(struct fastlane_dma_registers *) (esp->dregs);
+	unsigned long *t;
+	
+	cache_clear(addr, length);
+
+	dma_clear(esp);
+
+	t = (unsigned long *)((addr & 0x00ffffff) + esp->edev);
+
+	dregs->clear_strobe = 0;
+	*t = addr;
+
+	ctrl_data = (ctrl_data & FASTLANE_DMA_MASK) | FASTLANE_DMA_ENABLE;
+	dregs->ctrl_reg = ctrl_data;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	struct fastlane_dma_registers *dregs = 
+		(struct fastlane_dma_registers *) (esp->dregs);
+	unsigned long *t;
+
+	cache_push(addr, length);
+
+	dma_clear(esp);
+
+	t = (unsigned long *)((addr & 0x00ffffff) + (esp->edev));
+
+	dregs->clear_strobe = 0;
+	*t = addr;
+
+	ctrl_data = ((ctrl_data & FASTLANE_DMA_MASK) | 
+		     FASTLANE_DMA_ENABLE |
+		     FASTLANE_DMA_WRITE);
+	dregs->ctrl_reg = ctrl_data;
+}
+
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+	struct fastlane_dma_registers *dregs = 
+		(struct fastlane_dma_registers *) (esp->dregs);
+
+	dregs->ctrl_reg = ctrl_data & ~(FASTLANE_DMA_EDI|FASTLANE_DMA_ESI);
+#ifdef __mc68000__
+	nop();
+#endif
+	dregs->ctrl_reg = ctrl_data;
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	struct fastlane_dma_registers *dregs = 
+		(struct fastlane_dma_registers *) (esp->dregs);
+	unsigned char dma_status;
+
+	dma_status = dregs->cond_reg;
+
+	if(dma_status & FASTLANE_DMA_IACT)
+		return 0;	/* not our IRQ */
+
+	/* Return non-zero if ESP requested IRQ */
+	return (
+#ifndef NODMAIRQ
+	   (dma_status & FASTLANE_DMA_CREQ) &&
+#endif
+	   (!(dma_status & FASTLANE_DMA_MINT)) &&
+	   (esp_read(((struct ESP_regs *) (esp->eregs))->esp_status) & ESP_STAT_INTR));
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+	ctrl_data &= ~FASTLANE_DMA_LED;
+	((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+	ctrl_data |= FASTLANE_DMA_LED;
+	((struct fastlane_dma_registers *)(esp->dregs))->ctrl_reg = ctrl_data;
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+#define HOSTS_C
+
+int fastlane_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+	esp_deallocate((struct NCR_ESP *)instance->hostdata);
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-fastlane",
+	.proc_info		= esp_proc_info,
+	.name			= "Fastlane SCSI",
+	.detect			= fastlane_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= fastlane_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
new file mode 100644
index 0000000..0dad89d
--- /dev/null
+++ b/drivers/scsi/fcal.c
@@ -0,0 +1,320 @@
+/* fcal.c: Fibre Channel Arbitrated Loop SCSI host adapter driver.
+ *
+ * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "../fc4/fcp_impl.h"
+#include "fcal.h"
+
+#include <linux/module.h>
+
+/* #define FCAL_DEBUG */
+
+#define fcal_printk printk ("FCAL %s: ", fc->name); printk
+
+#ifdef FCAL_DEBUG
+#define FCALD(x)  fcal_printk x;
+#define FCALND(x) printk ("FCAL: "); printk x;
+#else
+#define FCALD(x)
+#define FCALND(x)
+#endif
+
+static unsigned char alpa2target[] = {
+0x7e, 0x7d, 0x7c, 0xff, 0x7b, 0xff, 0xff, 0xff, 0x7a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x79,
+0x78, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x76, 0xff, 0xff, 0x75, 0xff, 0x74, 0x73, 0x72,
+0xff, 0xff, 0xff, 0x71, 0xff, 0x70, 0x6f, 0x6e, 0xff, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x68, 0xff,
+0xff, 0x67, 0x66, 0x65, 0x64, 0x63, 0x62, 0xff, 0xff, 0x61, 0x60, 0xff, 0x5f, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0x5e, 0xff, 0x5d, 0x5c, 0x5b, 0xff, 0x5a, 0x59, 0x58, 0x57, 0x56, 0x55, 0xff,
+0xff, 0x54, 0x53, 0x52, 0x51, 0x50, 0x4f, 0xff, 0xff, 0x4e, 0x4d, 0xff, 0x4c, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0x4b, 0xff, 0x4a, 0x49, 0x48, 0xff, 0x47, 0x46, 0x45, 0x44, 0x43, 0x42, 0xff,
+0xff, 0x41, 0x40, 0x3f, 0x3e, 0x3d, 0x3c, 0xff, 0xff, 0x3b, 0x3a, 0xff, 0x39, 0xff, 0xff, 0xff,
+0x38, 0x37, 0x36, 0xff, 0x35, 0xff, 0xff, 0xff, 0x34, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x33,
+0x32, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x31, 0x30, 0xff, 0xff, 0x2f, 0xff, 0x2e, 0x2d, 0x2c,
+0xff, 0xff, 0xff, 0x2b, 0xff, 0x2a, 0x29, 0x28, 0xff, 0x27, 0x26, 0x25, 0x24, 0x23, 0x22, 0xff,
+0xff, 0x21, 0x20, 0x1f, 0x1e, 0x1d, 0x1c, 0xff, 0xff, 0x1b, 0x1a, 0xff, 0x19, 0xff, 0xff, 0xff,
+0xff, 0xff, 0xff, 0x18, 0xff, 0x17, 0x16, 0x15, 0xff, 0x14, 0x13, 0x12, 0x11, 0x10, 0x0f, 0xff,
+0xff, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a, 0x09, 0xff, 0xff, 0x08, 0x07, 0xff, 0x06, 0xff, 0xff, 0xff,
+0x05, 0x04, 0x03, 0xff, 0x02, 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+};
+
+static unsigned char target2alpa[] = {
+0xef, 0xe8, 0xe4, 0xe2, 0xe1, 0xe0, 0xdc, 0xda, 0xd9, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xce,
+0xcd, 0xcc, 0xcb, 0xca, 0xc9, 0xc7, 0xc6, 0xc5, 0xc3, 0xbc, 0xba, 0xb9, 0xb6, 0xb5, 0xb4, 0xb3,
+0xb2, 0xb1, 0xae, 0xad, 0xac, 0xab, 0xaa, 0xa9, 0xa7, 0xa6, 0xa5, 0xa3, 0x9f, 0x9e, 0x9d, 0x9b,
+0x98, 0x97, 0x90, 0x8f, 0x88, 0x84, 0x82, 0x81, 0x80, 0x7c, 0x7a, 0x79, 0x76, 0x75, 0x74, 0x73,
+0x72, 0x71, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x69, 0x67, 0x66, 0x65, 0x63, 0x5c, 0x5a, 0x59, 0x56,
+0x55, 0x54, 0x53, 0x52, 0x51, 0x4e, 0x4d, 0x4c, 0x4b, 0x4a, 0x49, 0x47, 0x46, 0x45, 0x43, 0x3c,
+0x3a, 0x39, 0x36, 0x35, 0x34, 0x33, 0x32, 0x31, 0x2e, 0x2d, 0x2c, 0x2b, 0x2a, 0x29, 0x27, 0x26,
+0x25, 0x23, 0x1f, 0x1e, 0x1d, 0x1b, 0x18, 0x17, 0x10, 0x0f, 0x08, 0x04, 0x02, 0x01, 0x00
+};
+
+static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
+
+int fcal_slave_configure(Scsi_Device *device)
+{
+	int depth_to_use;
+	
+	if (device->tagged_supported)
+		depth_to_use = /* 254 */ 8;
+	else
+		depth_to_use = 2;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	return 0;
+}
+
+/* Detect all FC Arbitrated Loops attached to the machine.
+   fc4 module has done all the work for us... */
+int __init fcal_detect(Scsi_Host_Template *tpnt)
+{
+	int nfcals = 0;
+	fc_channel *fc;
+	int fcalcount;
+	int i;
+
+	tpnt->proc_name = "fcal";
+	fcalcount = 0;
+	for_each_online_fc_channel(fc)
+		if (fc->posmap)
+			fcalcount++;
+	FCALND(("%d channels online\n", fcalcount))
+	if (!fcalcount) {
+#if defined(MODULE) && defined(CONFIG_FC4_SOCAL_MODULE) && defined(CONFIG_KMOD)
+		request_module("socal");
+		
+		for_each_online_fc_channel(fc)
+			if (fc->posmap)
+				fcalcount++;
+		if (!fcalcount)
+#endif
+			return 0;
+	}
+	for_each_online_fc_channel(fc) {
+		struct Scsi_Host *host;
+		long *ages;
+		struct fcal *fcal;
+		
+		if (!fc->posmap) continue;
+		
+		/* Strange, this is already registered to some other SCSI host, then it cannot be fcal */
+		if (fc->scsi_name[0]) continue;
+		memcpy (fc->scsi_name, "FCAL", 4);
+		
+		fc->can_queue = FCAL_CAN_QUEUE;
+		fc->rsp_size = 64;
+		fc->encode_addr = fcal_encode_addr;
+		
+		ages = kmalloc (128 * sizeof(long), GFP_KERNEL);
+		if (!ages) continue;
+				
+		host = scsi_register (tpnt, sizeof (struct fcal));
+		if (!host) 
+		{
+			kfree(ages);
+			continue;
+		}
+				
+		if (!try_module_get(fc->module)) {
+			kfree(ages);
+			scsi_unregister(host);
+			continue;
+		}
+	
+		nfcals++;
+				
+		fcal = (struct fcal *)host->hostdata;
+		
+		fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
+
+		for (i = 0; i < fc->posmap->len; i++) {
+			int status, target, alpa;
+
+			alpa = fc->posmap->list[i];			
+			FCALD(("Sending PLOGI to %02x\n", alpa))
+			target = alpa2target[alpa];
+			status = fc_do_plogi(fc, alpa, fcal->node_wwn + target, 
+					     fcal->nport_wwn + target);
+			FCALD(("PLOGI returned with status %d\n", status))
+			if (status != FC_STATUS_OK)
+				continue;
+			FCALD(("Sending PRLI to %02x\n", alpa))
+			status = fc_do_prli(fc, alpa);
+			FCALD(("PRLI returned with status %d\n", status))
+			if (status == FC_STATUS_OK)
+				fcal->map[target] = 1;
+		}
+		
+		host->max_id = 127;
+		host->irq = fc->irq;
+#ifdef __sparc_v9__
+		host->unchecked_isa_dma = 1;
+#endif
+
+		fc->channels = 1;
+		fc->targets = 127;
+		fc->ages = ages;
+		memset (ages, 0, 128 * sizeof(long));
+				
+		fcal->fc = fc;
+		
+		FCALD(("Found FCAL\n"))
+	}
+	if (nfcals)
+#ifdef __sparc__
+		printk ("FCAL: Total of %d Sun Enterprise Network Array (A5000 or EX500) channels found\n", nfcals);
+#else
+		printk ("FCAL: Total of %d Fibre Channel Arbitrated Loops found\n", nfcals);
+#endif
+	return nfcals;
+}
+
+int fcal_release(struct Scsi_Host *host)
+{
+	struct fcal *fcal = (struct fcal *)host->hostdata;
+	fc_channel *fc = fcal->fc;
+
+	module_put(fc->module);
+	
+	fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+	FCALND((" releasing fcal.\n"));
+	kfree (fc->ages);
+	FCALND(("released fcal!\n"));
+	return 0;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
+
+int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	struct fcal *fcal;
+	fc_channel *fc;
+	char *pos = buffer;
+	int i, j;
+
+	if (inout) return length;
+    
+	fcal = (struct fcal *)host->hostdata;
+	fc = fcal->fc;
+
+#ifdef __sparc__
+	SPRINTF ("Sun Enterprise Network Array (A5000 or E?500) on %s PROM node %x\n", fc->name, fc->dev->prom_node);
+#else
+	SPRINTF ("Fibre Channel Arbitrated Loop on %s\n", fc->name);
+#endif
+	SPRINTF ("Initiator AL-PA: %02x\n", fc->sid);
+
+	SPRINTF ("\nAttached devices:\n");
+	
+	for (i = 0; i < fc->posmap->len; i++) {
+		unsigned char alpa = fc->posmap->list[i];
+		unsigned char target;
+		u32 *u1, *u2;
+		
+		target = alpa2target[alpa];
+		u1 = (u32 *)&fcal->nport_wwn[target];
+		u2 = (u32 *)&fcal->node_wwn[target];
+		if (!u1[0] && !u1[1]) {
+			SPRINTF ("  [AL-PA: %02x] Not responded to PLOGI\n", alpa);
+		} else if (!fcal->map[target]) {
+			SPRINTF ("  [AL-PA: %02x, Port WWN: %08x%08x, Node WWN: %08x%08x] Not responded to PRLI\n",
+				 alpa, u1[0], u1[1], u2[0], u2[1]);
+		} else {
+			Scsi_Device *scd;
+			shost_for_each_device(scd, host)
+				if (scd->id == target) {
+					SPRINTF ("  [AL-PA: %02x, Id: %02d, Port WWN: %08x%08x, Node WWN: %08x%08x]  ",
+						alpa, target, u1[0], u1[1], u2[0], u2[1]);
+					SPRINTF ("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
+						scsi_device_types[(short) scd->type] : "Unknown device");
+
+					for (j = 0; (j < 8) && (scd->vendor[j] >= 0x20); j++)
+						SPRINTF ("%c", scd->vendor[j]);
+					SPRINTF (" ");
+
+					for (j = 0; (j < 16) && (scd->model[j] >= 0x20); j++)
+						SPRINTF ("%c", scd->model[j]);
+		
+					SPRINTF ("\n");
+				}
+		}
+	}
+	SPRINTF ("\n");
+
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return 0;
+	else if (pos - buffer - offset < length)
+		return pos - buffer - offset;
+	else
+		return length;
+}
+
+/* 
+   For FC-AL, we use a simple addressing: we have just one channel 0,
+   and all AL-PAs are mapped to targets 0..0x7e
+ */
+static int fcal_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd)
+{
+	struct fcal *f;
+	
+	/* We don't support LUNs yet - I'm not sure if LUN should be in SCSI fcp_cdb, or in second byte of addr[0] */
+	if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
+	/* FC-PLDA tells us... */
+	memset(addr, 0, 8);
+	f = (struct fcal *)SCpnt->device->host->hostdata;
+	if (!f->map[SCpnt->device->id])
+		return -EINVAL;
+	/* Now, determine DID: It will be Native Identifier, so we zero upper
+	   2 bytes of the 3 byte DID, lowest byte will be AL-PA */
+	fcmd->did = target2alpa[SCpnt->device->id];
+	FCALD(("trying DID %06x\n", fcmd->did))
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name			= "Fibre Channel Arbitrated Loop",
+	.detect			= fcal_detect,
+	.release		= fcal_release,	
+	.proc_info		= fcal_proc_info,
+	.queuecommand		= fcp_scsi_queuecommand,
+	.slave_configure	= fcal_slave_configure,
+	.can_queue		= FCAL_CAN_QUEUE,
+	.this_id		= -1,
+	.sg_tablesize		= 1,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.eh_abort_handler	= fcp_scsi_abort,
+	.eh_device_reset_handler = fcp_scsi_dev_reset,
+	.eh_bus_reset_handler	= fcp_scsi_bus_reset,
+	.eh_host_reset_handler	= fcp_scsi_host_reset,
+};
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
new file mode 100644
index 0000000..21aa32e
--- /dev/null
+++ b/drivers/scsi/fcal.h
@@ -0,0 +1,27 @@
+/* fcal.h: Generic Fibre Channel Arbitrated Loop SCSI host adapter driver definitions.
+ *
+ * Copyright (C) 1998,1999 Jakub Jelinek (jj@ultra.linux.cz)
+ */
+
+#ifndef _FCAL_H
+#define _FCAL_H
+
+#include "../fc4/fcp_impl.h"
+
+struct fcal {
+	/* fc must be first */
+	fc_channel		*fc;
+	unsigned char		map[128];
+	fc_wwn			nport_wwn[128];
+	fc_wwn			node_wwn[128];
+};
+
+/* Arbitrary constant. Cannot be too large, as fc4 layer has limitations
+   for a particular channel */
+#define FCAL_CAN_QUEUE		512
+
+int fcal_detect(Scsi_Host_Template *);
+int fcal_release(struct Scsi_Host *);
+int fcal_slave_configure(Scsi_Device *);
+
+#endif /* !(_FCAL_H) */
diff --git a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
new file mode 100644
index 0000000..770930e
--- /dev/null
+++ b/drivers/scsi/fd_mcs.c
@@ -0,0 +1,1369 @@
+/* fd_mcs.c -- Future Domain MCS 600/700 (or IBM OEM) driver
+ *
+ * FutureDomain MCS-600/700 v0.2 03/11/1998 by ZP Gu (zpg@castle.net)
+ *
+ * This driver is cloned from fdomain.* to specifically support
+ * the Future Domain MCS 600/700 MCA SCSI adapters. Some PS/2s
+ * also equipped with IBM Fast SCSI Adapter/A which is an OEM
+ * of MCS 700.
+ *
+ * This driver also supports Reply SB16/SCSI card (the SCSI part).
+ *
+ * What makes this driver different is that this driver is MCA only
+ * and it supports multiple adapters in the same system, IRQ 
+ * sharing, some driver statistics, and maps highest SCSI id to sda.
+ * All cards are auto-detected.
+ *
+ * Assumptions: TMC-1800/18C50/18C30, BIOS >= 3.4
+ *
+ * LILO command-line options:
+ *   fd_mcs=<FIFO_COUNT>[,<FIFO_SIZE>]
+ *
+ * ********************************************************
+ * Please see Copyrights/Comments in fdomain.* for credits.
+ * Following is from fdomain.c for acknowledgement:
+ *
+ * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
+ * Revised: Wed Oct  2 11:10:55 1996 by r.faith@ieee.org
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992, 1993, 1994, 1995, 1996 Rickard E. Faith
+ *
+ * $Id: fdomain.c,v 5.45 1996/10/02 15:13:06 root Exp $
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ **************************************************************************
+
+ NOTES ON USER DEFINABLE OPTIONS:
+
+ DEBUG: This turns on the printing of various debug information.
+
+ ENABLE_PARITY: This turns on SCSI parity checking.  With the current
+ driver, all attached devices must support SCSI parity.  If none of your
+ devices support parity, then you can probably get the driver to work by
+ turning this option off.  I have no way of testing this, however, and it
+ would appear that no one ever uses this option.
+
+ FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
+ the SCSI device, an interrupt will be raised.  Therefore, this could be as
+ low as 0, or as high as 16.  Note, however, that values which are too high
+ or too low seem to prevent any interrupts from occurring, and thereby lock
+ up the machine.  I have found that 2 is a good number, but throughput may
+ be increased by changing this value to values which are close to 2.
+ Please let me know if you try any different values.
+ [*****Now a runtime option*****]
+
+ RESELECTION: This is no longer an option, since I gave up trying to
+ implement it in version 4.x of this driver.  It did not improve
+ performance at all and made the driver unstable (because I never found one
+ of the two race conditions which were introduced by the multiple
+ outstanding command code).  The instability seems a very high price to pay
+ just so that you don't have to wait for the tape to rewind.  If you want
+ this feature implemented, send me patches.  I'll be happy to send a copy
+ of my (broken) driver to anyone who would like to see a copy.
+
+ **************************************************************************/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/mca.h>
+#include <linux/spinlock.h>
+#include <scsi/scsicam.h>
+#include <linux/mca-legacy.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#define DRIVER_VERSION "v0.2 by ZP Gu<zpg@castle.net>"
+
+/* START OF USER DEFINABLE OPTIONS */
+
+#define DEBUG            0	/* Enable debugging output */
+#define ENABLE_PARITY    1	/* Enable SCSI Parity */
+
+/* END OF USER DEFINABLE OPTIONS */
+
+#if DEBUG
+#define EVERY_ACCESS     0	/* Write a line on every scsi access */
+#define ERRORS_ONLY      1	/* Only write a line if there is an error */
+#define DEBUG_MESSAGES   1	/* Debug MESSAGE IN phase */
+#define DEBUG_ABORT      1	/* Debug abort() routine */
+#define DEBUG_RESET      1	/* Debug reset() routine */
+#define DEBUG_RACE       1	/* Debug interrupt-driven race condition */
+#else
+#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
+#define ERRORS_ONLY      0
+#define DEBUG_MESSAGES   0
+#define DEBUG_ABORT      0
+#define DEBUG_RESET      0
+#define DEBUG_RACE       0
+#endif
+
+/* Errors are reported on the line, so we don't need to report them again */
+#if EVERY_ACCESS
+#undef ERRORS_ONLY
+#define ERRORS_ONLY      0
+#endif
+
+#if ENABLE_PARITY
+#define PARITY_MASK      0x08
+#else
+#define PARITY_MASK      0x00
+#endif
+
+enum chip_type {
+	unknown = 0x00,
+	tmc1800 = 0x01,
+	tmc18c50 = 0x02,
+	tmc18c30 = 0x03,
+};
+
+enum {
+	in_arbitration = 0x02,
+	in_selection = 0x04,
+	in_other = 0x08,
+	disconnect = 0x10,
+	aborted = 0x20,
+	sent_ident = 0x40,
+};
+
+enum in_port_type {
+	Read_SCSI_Data = 0,
+	SCSI_Status = 1,
+	TMC_Status = 2,
+	FIFO_Status = 3,	/* tmc18c50/tmc18c30 only */
+	Interrupt_Cond = 4,	/* tmc18c50/tmc18c30 only */
+	LSB_ID_Code = 5,
+	MSB_ID_Code = 6,
+	Read_Loopback = 7,
+	SCSI_Data_NoACK = 8,
+	Interrupt_Status = 9,
+	Configuration1 = 10,
+	Configuration2 = 11,	/* tmc18c50/tmc18c30 only */
+	Read_FIFO = 12,
+	FIFO_Data_Count = 14
+};
+
+enum out_port_type {
+	Write_SCSI_Data = 0,
+	SCSI_Cntl = 1,
+	Interrupt_Cntl = 2,
+	SCSI_Mode_Cntl = 3,
+	TMC_Cntl = 4,
+	Memory_Cntl = 5,	/* tmc18c50/tmc18c30 only */
+	Write_Loopback = 7,
+	IO_Control = 11,	/* tmc18c30 only */
+	Write_FIFO = 12
+};
+
+struct fd_hostdata {
+	unsigned long _bios_base;
+	int _bios_major;
+	int _bios_minor;
+	volatile int _in_command;
+	Scsi_Cmnd *_current_SC;
+	enum chip_type _chip;
+	int _adapter_mask;
+	int _fifo_count;	/* Number of 512 byte blocks before INTR */
+
+	char _adapter_name[64];
+#if DEBUG_RACE
+	volatile int _in_interrupt_flag;
+#endif
+
+	int _SCSI_Mode_Cntl_port;
+	int _FIFO_Data_Count_port;
+	int _Interrupt_Cntl_port;
+	int _Interrupt_Status_port;
+	int _Interrupt_Cond_port;
+	int _Read_FIFO_port;
+	int _Read_SCSI_Data_port;
+	int _SCSI_Cntl_port;
+	int _SCSI_Data_NoACK_port;
+	int _SCSI_Status_port;
+	int _TMC_Cntl_port;
+	int _TMC_Status_port;
+	int _Write_FIFO_port;
+	int _Write_SCSI_Data_port;
+
+	int _FIFO_Size;		/* = 0x2000;  8k FIFO for
+				   pre-tmc18c30 chips */
+	/* simple stats */
+	int _Bytes_Read;
+	int _Bytes_Written;
+	int _INTR_Processed;
+};
+
+#define FD_MAX_HOSTS 3		/* enough? */
+
+#define HOSTDATA(shpnt) ((struct fd_hostdata *) shpnt->hostdata)
+#define bios_base             (HOSTDATA(shpnt)->_bios_base)
+#define bios_major            (HOSTDATA(shpnt)->_bios_major)
+#define bios_minor            (HOSTDATA(shpnt)->_bios_minor)
+#define in_command            (HOSTDATA(shpnt)->_in_command)
+#define current_SC            (HOSTDATA(shpnt)->_current_SC)
+#define chip                  (HOSTDATA(shpnt)->_chip)
+#define adapter_mask          (HOSTDATA(shpnt)->_adapter_mask)
+#define FIFO_COUNT            (HOSTDATA(shpnt)->_fifo_count)
+#define adapter_name          (HOSTDATA(shpnt)->_adapter_name)
+#if DEBUG_RACE
+#define in_interrupt_flag     (HOSTDATA(shpnt)->_in_interrupt_flag)
+#endif
+#define SCSI_Mode_Cntl_port   (HOSTDATA(shpnt)->_SCSI_Mode_Cntl_port)
+#define FIFO_Data_Count_port  (HOSTDATA(shpnt)->_FIFO_Data_Count_port)
+#define Interrupt_Cntl_port   (HOSTDATA(shpnt)->_Interrupt_Cntl_port)
+#define Interrupt_Status_port (HOSTDATA(shpnt)->_Interrupt_Status_port)
+#define Interrupt_Cond_port   (HOSTDATA(shpnt)->_Interrupt_Cond_port)
+#define Read_FIFO_port        (HOSTDATA(shpnt)->_Read_FIFO_port)
+#define Read_SCSI_Data_port   (HOSTDATA(shpnt)->_Read_SCSI_Data_port)
+#define SCSI_Cntl_port        (HOSTDATA(shpnt)->_SCSI_Cntl_port)
+#define SCSI_Data_NoACK_port  (HOSTDATA(shpnt)->_SCSI_Data_NoACK_port)
+#define SCSI_Status_port      (HOSTDATA(shpnt)->_SCSI_Status_port)
+#define TMC_Cntl_port         (HOSTDATA(shpnt)->_TMC_Cntl_port)
+#define TMC_Status_port       (HOSTDATA(shpnt)->_TMC_Status_port)
+#define Write_FIFO_port       (HOSTDATA(shpnt)->_Write_FIFO_port)
+#define Write_SCSI_Data_port  (HOSTDATA(shpnt)->_Write_SCSI_Data_port)
+#define FIFO_Size             (HOSTDATA(shpnt)->_FIFO_Size)
+#define Bytes_Read            (HOSTDATA(shpnt)->_Bytes_Read)
+#define Bytes_Written         (HOSTDATA(shpnt)->_Bytes_Written)
+#define INTR_Processed        (HOSTDATA(shpnt)->_INTR_Processed)
+
+struct fd_mcs_adapters_struct {
+	char *name;
+	int id;
+	enum chip_type fd_chip;
+	int fifo_size;
+	int fifo_count;
+};
+
+#define REPLY_ID 0x5137
+
+static struct fd_mcs_adapters_struct fd_mcs_adapters[] = {
+	{"Future Domain SCSI Adapter MCS-700(18C50)",
+	 0x60e9,
+	 tmc18c50,
+	 0x2000,
+	 4},
+	{"Future Domain SCSI Adapter MCS-600/700(TMC-1800)",
+	 0x6127,
+	 tmc1800,
+	 0x2000,
+	 4},
+	{"Reply Sound Blaster/SCSI Adapter",
+	 REPLY_ID,
+	 tmc18c30,
+	 0x800,
+	 2},
+};
+
+#define FD_BRDS sizeof(fd_mcs_adapters)/sizeof(struct fd_mcs_adapters_struct)
+
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+static unsigned long addresses[] = { 0xc8000, 0xca000, 0xce000, 0xde000 };
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+static unsigned short interrupts[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/* host information */
+static int found = 0;
+static struct Scsi_Host *hosts[FD_MAX_HOSTS + 1] = { NULL };
+
+static int user_fifo_count = 0;
+static int user_fifo_size = 0;
+
+static int __init fd_mcs_setup(char *str)
+{
+	static int done_setup = 0;
+	int ints[3];
+
+	get_options(str, 3, ints);
+	if (done_setup++ || ints[0] < 1 || ints[0] > 2 || ints[1] < 1 || ints[1] > 16) {
+		printk("fd_mcs: usage: fd_mcs=FIFO_COUNT, FIFO_SIZE\n");
+		return 0;
+	}
+
+	user_fifo_count = ints[0] >= 1 ? ints[1] : 0;
+	user_fifo_size = ints[0] >= 2 ? ints[2] : 0;
+	return 1;
+}
+
+__setup("fd_mcs=", fd_mcs_setup);
+
+static void print_banner(struct Scsi_Host *shpnt)
+{
+	printk("scsi%d <fd_mcs>: ", shpnt->host_no);
+
+	if (bios_base) {
+		printk("BIOS at 0x%lX", bios_base);
+	} else {
+		printk("No BIOS");
+	}
+
+	printk(", HostID %d, %s Chip, IRQ %d, IO 0x%lX\n", shpnt->this_id, chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? "TMC-18C30" : (chip == tmc1800 ? "TMC-1800" : "Unknown")), shpnt->irq, shpnt->io_port);
+}
+
+
+static void do_pause(unsigned amount)
+{				/* Pause for amount*10 milliseconds */
+	do {
+		mdelay(10);
+	} while (--amount);
+}
+
+static void fd_mcs_make_bus_idle(struct Scsi_Host *shpnt)
+{
+	outb(0, SCSI_Cntl_port);
+	outb(0, SCSI_Mode_Cntl_port);
+	if (chip == tmc18c50 || chip == tmc18c30)
+		outb(0x21 | PARITY_MASK, TMC_Cntl_port);	/* Clear forced intr. */
+	else
+		outb(0x01 | PARITY_MASK, TMC_Cntl_port);
+}
+
+static int fd_mcs_detect(Scsi_Host_Template * tpnt)
+{
+	int loop;
+	struct Scsi_Host *shpnt;
+
+	/* get id, port, bios, irq */
+	int slot;
+	u_char pos2, pos3, pos4;
+	int id, port, irq;
+	unsigned long bios;
+
+	/* if not MCA machine, return */
+	if (!MCA_bus)
+		return 0;
+
+	/* changeable? */
+	id = 7;
+
+	for (loop = 0; loop < FD_BRDS; loop++) {
+		slot = 0;
+		while (MCA_NOTFOUND != (slot = mca_find_adapter(fd_mcs_adapters[loop].id, slot))) {
+
+			/* if we get this far, an adapter has been detected and is
+			   enabled */
+
+			printk(KERN_INFO "scsi  <fd_mcs>: %s at slot %d\n", fd_mcs_adapters[loop].name, slot + 1);
+
+			pos2 = mca_read_stored_pos(slot, 2);
+			pos3 = mca_read_stored_pos(slot, 3);
+			pos4 = mca_read_stored_pos(slot, 4);
+
+			/* ready for next probe */
+			slot++;
+
+			if (fd_mcs_adapters[loop].id == REPLY_ID) {	/* reply card */
+				static int reply_irq[] = { 10, 11, 14, 15 };
+
+				bios = 0;	/* no bios */
+
+				if (pos2 & 0x2)
+					port = ports[pos4 & 0x3];
+				else
+					continue;
+
+				/* can't really disable it, same as irq=10 */
+				irq = reply_irq[((pos4 >> 2) & 0x1) + 2 * ((pos4 >> 4) & 0x1)];
+			} else {
+				bios = addresses[pos2 >> 6];
+				port = ports[(pos2 >> 4) & 0x03];
+				irq = interrupts[(pos2 >> 1) & 0x07];
+			}
+
+			if (irq) {
+				/* claim the slot */
+				mca_set_adapter_name(slot - 1, fd_mcs_adapters[loop].name);
+
+				/* check irq/region */
+				if (request_irq(irq, fd_mcs_intr, SA_SHIRQ, "fd_mcs", hosts)) {
+					printk(KERN_ERR "fd_mcs: interrupt is not available, skipping...\n");
+					continue;
+				}
+
+				/* request I/O region */
+				if (request_region(port, 0x10, "fd_mcs")) {
+					printk(KERN_ERR "fd_mcs: I/O region is already in use, skipping...\n");
+					continue;
+				}
+				/* register */
+				if (!(shpnt = scsi_register(tpnt, sizeof(struct fd_hostdata)))) {
+					printk(KERN_ERR "fd_mcs: scsi_register() failed\n");
+					release_region(port, 0x10);
+					free_irq(irq, hosts);
+					continue;
+				}
+
+
+				/* save name */
+				strcpy(adapter_name, fd_mcs_adapters[loop].name);
+
+				/* chip/fifo */
+				chip = fd_mcs_adapters[loop].fd_chip;
+				/* use boot time value if available */
+				FIFO_COUNT = user_fifo_count ? user_fifo_count : fd_mcs_adapters[loop].fifo_count;
+				FIFO_Size = user_fifo_size ? user_fifo_size : fd_mcs_adapters[loop].fifo_size;
+
+/* FIXME: Do we need to keep this bit of code inside NOT_USED around at all? */
+#ifdef NOT_USED
+				/* *************************************************** */
+				/* Try to toggle 32-bit mode.  This only
+				   works on an 18c30 chip.  (User reports
+				   say this works, so we should switch to
+				   it in the near future.) */
+				outb(0x80, port + IO_Control);
+				if ((inb(port + Configuration2) & 0x80) == 0x80) {
+					outb(0x00, port + IO_Control);
+					if ((inb(port + Configuration2) & 0x80) == 0x00) {
+						chip = tmc18c30;
+						FIFO_Size = 0x800;	/* 2k FIFO */
+
+						printk("FIRST: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
+					}
+				}
+
+				/* That should have worked, but appears to
+				   have problems.  Let's assume it is an
+				   18c30 if the RAM is disabled. */
+
+				if (inb(port + Configuration2) & 0x02) {
+					chip = tmc18c30;
+					FIFO_Size = 0x800;	/* 2k FIFO */
+
+					printk("SECOND: chip=%s, fifo_size=0x%x\n", (chip == tmc18c30) ? "tmc18c30" : "tmc18c50", FIFO_Size);
+				}
+				/* *************************************************** */
+#endif
+
+				/* IBM/ANSI scsi scan ordering */
+				/* Stick this back in when the scsi.c changes are there */
+				shpnt->reverse_ordering = 1;
+
+
+				/* saving info */
+				hosts[found++] = shpnt;
+
+				shpnt->this_id = id;
+				shpnt->irq = irq;
+				shpnt->io_port = port;
+				shpnt->n_io_port = 0x10;
+
+				/* save */
+				bios_base = bios;
+				adapter_mask = (1 << id);
+
+				/* save more */
+				SCSI_Mode_Cntl_port = port + SCSI_Mode_Cntl;
+				FIFO_Data_Count_port = port + FIFO_Data_Count;
+				Interrupt_Cntl_port = port + Interrupt_Cntl;
+				Interrupt_Status_port = port + Interrupt_Status;
+				Interrupt_Cond_port = port + Interrupt_Cond;
+				Read_FIFO_port = port + Read_FIFO;
+				Read_SCSI_Data_port = port + Read_SCSI_Data;
+				SCSI_Cntl_port = port + SCSI_Cntl;
+				SCSI_Data_NoACK_port = port + SCSI_Data_NoACK;
+				SCSI_Status_port = port + SCSI_Status;
+				TMC_Cntl_port = port + TMC_Cntl;
+				TMC_Status_port = port + TMC_Status;
+				Write_FIFO_port = port + Write_FIFO;
+				Write_SCSI_Data_port = port + Write_SCSI_Data;
+
+				Bytes_Read = 0;
+				Bytes_Written = 0;
+				INTR_Processed = 0;
+
+				/* say something */
+				print_banner(shpnt);
+
+				/* reset */
+				outb(1, SCSI_Cntl_port);
+				do_pause(2);
+				outb(0, SCSI_Cntl_port);
+				do_pause(115);
+				outb(0, SCSI_Mode_Cntl_port);
+				outb(PARITY_MASK, TMC_Cntl_port);
+				/* done reset */
+			}
+		}
+
+		if (found == FD_MAX_HOSTS) {
+			printk("fd_mcs: detecting reached max=%d host adapters.\n", FD_MAX_HOSTS);
+			break;
+		}
+	}
+
+	return found;
+}
+
+static const char *fd_mcs_info(struct Scsi_Host *shpnt)
+{
+	return adapter_name;
+}
+
+static int TOTAL_INTR = 0;
+
+/*
+ * inout : decides on the direction of the dataflow and the meaning of the 
+ *         variables
+ * buffer: If inout==FALSE data is being written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file 
+ *         from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer 
+ *         else number of bytes in the buffer
+ */
+static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	int len = 0;
+
+	if (inout)
+		return (-ENOSYS);
+
+	*start = buffer + offset;
+
+	len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION);
+	len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name);
+	len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT);
+	len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written);
+
+	if ((len -= offset) <= 0)
+		return 0;
+	if (len > length)
+		len = length;
+	return len;
+}
+
+static int fd_mcs_select(struct Scsi_Host *shpnt, int target)
+{
+	int status;
+	unsigned long timeout;
+
+	outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
+	outb(adapter_mask | (1 << target), SCSI_Data_NoACK_port);
+
+	/* Stop arbitration and enable parity */
+	outb(PARITY_MASK, TMC_Cntl_port);
+
+	timeout = 350;		/* 350mS -- because of timeouts
+				   (was 250mS) */
+
+	do {
+		status = inb(SCSI_Status_port);	/* Read adapter status */
+		if (status & 1) {	/* Busy asserted */
+			/* Enable SCSI Bus (on error, should make bus idle with 0) */
+			outb(0x80, SCSI_Cntl_port);
+			return 0;
+		}
+		udelay(1000);	/* wait one msec */
+	} while (--timeout);
+
+	/* Make bus idle */
+	fd_mcs_make_bus_idle(shpnt);
+#if EVERY_ACCESS
+	if (!target)
+		printk("Selection failed\n");
+#endif
+#if ERRORS_ONLY
+	if (!target) {
+		static int flag = 0;
+
+		if (!flag)	/* Skip first failure for all chips. */
+			++flag;
+		else
+			printk("fd_mcs: Selection failed\n");
+	}
+#endif
+	return 1;
+}
+
+static void my_done(struct Scsi_Host *shpnt, int error)
+{
+	if (in_command) {
+		in_command = 0;
+		outb(0x00, Interrupt_Cntl_port);
+		fd_mcs_make_bus_idle(shpnt);
+		current_SC->result = error;
+		current_SC->scsi_done(current_SC);
+	} else {
+		panic("fd_mcs: my_done() called outside of command\n");
+	}
+#if DEBUG_RACE
+	in_interrupt_flag = 0;
+#endif
+}
+
+/* only my_done needs to be protected  */
+static irqreturn_t fd_mcs_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	int status;
+	int done = 0;
+	unsigned data_count, tmp_count;
+
+	int i = 0;
+	struct Scsi_Host *shpnt;
+
+	TOTAL_INTR++;
+
+	/* search for one adapter-response on shared interrupt */
+	while ((shpnt = hosts[i++])) {
+		if ((inb(TMC_Status_port)) & 1)
+			break;
+	}
+
+	/* return if some other device on this IRQ caused the interrupt */
+	if (!shpnt) {
+		return IRQ_NONE;
+	}
+
+	INTR_Processed++;
+
+	outb(0x00, Interrupt_Cntl_port);
+
+	/* Abort calls my_done, so we do nothing here. */
+	if (current_SC->SCp.phase & aborted) {
+#if DEBUG_ABORT
+		printk("Interrupt after abort, ignoring\n");
+#endif
+		/* return IRQ_HANDLED; */
+	}
+#if DEBUG_RACE
+	++in_interrupt_flag;
+#endif
+
+	if (current_SC->SCp.phase & in_arbitration) {
+		status = inb(TMC_Status_port);	/* Read adapter status */
+		if (!(status & 0x02)) {
+#if EVERY_ACCESS
+			printk(" AFAIL ");
+#endif
+			spin_lock_irqsave(shpnt->host_lock, flags);
+			my_done(shpnt, DID_BUS_BUSY << 16);
+			spin_unlock_irqrestore(shpnt->host_lock, flags);
+			return IRQ_HANDLED;
+		}
+		current_SC->SCp.phase = in_selection;
+
+		outb(0x40 | FIFO_COUNT, Interrupt_Cntl_port);
+
+		outb(0x82, SCSI_Cntl_port);	/* Bus Enable + Select */
+		outb(adapter_mask | (1 << current_SC->device->id), SCSI_Data_NoACK_port);
+
+		/* Stop arbitration and enable parity */
+		outb(0x10 | PARITY_MASK, TMC_Cntl_port);
+#if DEBUG_RACE
+		in_interrupt_flag = 0;
+#endif
+		return IRQ_HANDLED;
+	} else if (current_SC->SCp.phase & in_selection) {
+		status = inb(SCSI_Status_port);
+		if (!(status & 0x01)) {
+			/* Try again, for slow devices */
+			if (fd_mcs_select(shpnt, current_SC->device->id)) {
+#if EVERY_ACCESS
+				printk(" SFAIL ");
+#endif
+				spin_lock_irqsave(shpnt->host_lock, flags);
+				my_done(shpnt, DID_NO_CONNECT << 16);
+				spin_unlock_irqrestore(shpnt->host_lock, flags);
+				return IRQ_HANDLED;
+			} else {
+#if EVERY_ACCESS
+				printk(" AltSel ");
+#endif
+				/* Stop arbitration and enable parity */
+				outb(0x10 | PARITY_MASK, TMC_Cntl_port);
+			}
+		}
+		current_SC->SCp.phase = in_other;
+		outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
+		outb(0x80, SCSI_Cntl_port);
+#if DEBUG_RACE
+		in_interrupt_flag = 0;
+#endif
+		return IRQ_HANDLED;
+	}
+
+	/* current_SC->SCp.phase == in_other: this is the body of the routine */
+
+	status = inb(SCSI_Status_port);
+
+	if (status & 0x10) {	/* REQ */
+
+		switch (status & 0x0e) {
+
+		case 0x08:	/* COMMAND OUT */
+			outb(current_SC->cmnd[current_SC->SCp.sent_command++], Write_SCSI_Data_port);
+#if EVERY_ACCESS
+			printk("CMD = %x,", current_SC->cmnd[current_SC->SCp.sent_command - 1]);
+#endif
+			break;
+		case 0x00:	/* DATA OUT -- tmc18c50/tmc18c30 only */
+			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+				current_SC->SCp.have_data_in = -1;
+				outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
+			}
+			break;
+		case 0x04:	/* DATA IN -- tmc18c50/tmc18c30 only */
+			if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+				current_SC->SCp.have_data_in = 1;
+				outb(0x90 | PARITY_MASK, TMC_Cntl_port);
+			}
+			break;
+		case 0x0c:	/* STATUS IN */
+			current_SC->SCp.Status = inb(Read_SCSI_Data_port);
+#if EVERY_ACCESS
+			printk("Status = %x, ", current_SC->SCp.Status);
+#endif
+#if ERRORS_ONLY
+			if (current_SC->SCp.Status && current_SC->SCp.Status != 2 && current_SC->SCp.Status != 8) {
+				printk("ERROR fd_mcs: target = %d, command = %x, status = %x\n", current_SC->device->id, current_SC->cmnd[0], current_SC->SCp.Status);
+			}
+#endif
+			break;
+		case 0x0a:	/* MESSAGE OUT */
+			outb(MESSAGE_REJECT, Write_SCSI_Data_port);	/* Reject */
+			break;
+		case 0x0e:	/* MESSAGE IN */
+			current_SC->SCp.Message = inb(Read_SCSI_Data_port);
+#if EVERY_ACCESS
+			printk("Message = %x, ", current_SC->SCp.Message);
+#endif
+			if (!current_SC->SCp.Message)
+				++done;
+#if DEBUG_MESSAGES || EVERY_ACCESS
+			if (current_SC->SCp.Message) {
+				printk("fd_mcs: message = %x\n", current_SC->SCp.Message);
+			}
+#endif
+			break;
+		}
+	}
+
+	if (chip == tmc1800 && !current_SC->SCp.have_data_in && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
+		/* We have to get the FIFO direction
+		   correct, so I've made a table based
+		   on the SCSI Standard of which commands
+		   appear to require a DATA OUT phase.
+		 */
+		/*
+		   p. 94: Command for all device types
+		   CHANGE DEFINITION            40 DATA OUT
+		   COMPARE                      39 DATA OUT
+		   COPY                         18 DATA OUT
+		   COPY AND VERIFY              3a DATA OUT
+		   INQUIRY                      12 
+		   LOG SELECT                   4c DATA OUT
+		   LOG SENSE                    4d
+		   MODE SELECT (6)              15 DATA OUT
+		   MODE SELECT (10)             55 DATA OUT
+		   MODE SENSE (6)               1a
+		   MODE SENSE (10)              5a
+		   READ BUFFER                  3c
+		   RECEIVE DIAGNOSTIC RESULTS   1c
+		   REQUEST SENSE                03
+		   SEND DIAGNOSTIC              1d DATA OUT
+		   TEST UNIT READY              00
+		   WRITE BUFFER                 3b DATA OUT
+
+		   p.178: Commands for direct-access devices (not listed on p. 94)
+		   FORMAT UNIT                  04 DATA OUT
+		   LOCK-UNLOCK CACHE            36
+		   PRE-FETCH                    34
+		   PREVENT-ALLOW MEDIUM REMOVAL 1e
+		   READ (6)/RECEIVE             08
+		   READ (10)                    3c
+		   READ CAPACITY                25
+		   READ DEFECT DATA (10)        37
+		   READ LONG                    3e
+		   REASSIGN BLOCKS              07 DATA OUT
+		   RELEASE                      17
+		   RESERVE                      16 DATA OUT
+		   REZERO UNIT/REWIND           01
+		   SEARCH DATA EQUAL (10)       31 DATA OUT
+		   SEARCH DATA HIGH (10)        30 DATA OUT
+		   SEARCH DATA LOW (10)         32 DATA OUT
+		   SEEK (6)                     0b
+		   SEEK (10)                    2b
+		   SET LIMITS (10)              33
+		   START STOP UNIT              1b
+		   SYNCHRONIZE CACHE            35
+		   VERIFY (10)                  2f
+		   WRITE (6)/PRINT/SEND         0a DATA OUT
+		   WRITE (10)/SEND              2a DATA OUT
+		   WRITE AND VERIFY (10)        2e DATA OUT
+		   WRITE LONG                   3f DATA OUT
+		   WRITE SAME                   41 DATA OUT ?
+
+		   p. 261: Commands for sequential-access devices (not previously listed)
+		   ERASE                        19
+		   LOAD UNLOAD                  1b
+		   LOCATE                       2b
+		   READ BLOCK LIMITS            05
+		   READ POSITION                34
+		   READ REVERSE                 0f
+		   RECOVER BUFFERED DATA        14
+		   SPACE                        11
+		   WRITE FILEMARKS              10 ?
+
+		   p. 298: Commands for printer devices (not previously listed)
+		   ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) *****
+		   SLEW AND PRINT               0b DATA OUT  -- same as seek
+		   STOP PRINT                   1b
+		   SYNCHRONIZE BUFFER           10
+
+		   p. 315: Commands for processor devices (not previously listed)
+
+		   p. 321: Commands for write-once devices (not previously listed)
+		   MEDIUM SCAN                  38
+		   READ (12)                    a8
+		   SEARCH DATA EQUAL (12)       b1 DATA OUT
+		   SEARCH DATA HIGH (12)        b0 DATA OUT
+		   SEARCH DATA LOW (12)         b2 DATA OUT
+		   SET LIMITS (12)              b3
+		   VERIFY (12)                  af
+		   WRITE (12)                   aa DATA OUT
+		   WRITE AND VERIFY (12)        ae DATA OUT
+
+		   p. 332: Commands for CD-ROM devices (not previously listed)
+		   PAUSE/RESUME                 4b
+		   PLAY AUDIO (10)              45
+		   PLAY AUDIO (12)              a5
+		   PLAY AUDIO MSF               47
+		   PLAY TRACK RELATIVE (10)     49
+		   PLAY TRACK RELATIVE (12)     a9
+		   READ HEADER                  44
+		   READ SUB-CHANNEL             42
+		   READ TOC                     43
+
+		   p. 370: Commands for scanner devices (not previously listed)
+		   GET DATA BUFFER STATUS       34
+		   GET WINDOW                   25
+		   OBJECT POSITION              31
+		   SCAN                         1b
+		   SET WINDOW                   24 DATA OUT
+
+		   p. 391: Commands for optical memory devices (not listed)
+		   ERASE (10)                   2c
+		   ERASE (12)                   ac
+		   MEDIUM SCAN                  38 DATA OUT
+		   READ DEFECT DATA (12)        b7
+		   READ GENERATION              29
+		   READ UPDATED BLOCK           2d
+		   UPDATE BLOCK                 3d DATA OUT
+
+		   p. 419: Commands for medium changer devices (not listed)
+		   EXCHANGE MEDIUM              46
+		   INITIALIZE ELEMENT STATUS    07
+		   MOVE MEDIUM                  a5
+		   POSITION TO ELEMENT          2b
+		   READ ELEMENT STATUS          b8
+		   REQUEST VOL. ELEMENT ADDRESS b5
+		   SEND VOLUME TAG              b6 DATA OUT
+
+		   p. 454: Commands for communications devices (not listed previously)
+		   GET MESSAGE (6)              08
+		   GET MESSAGE (10)             28
+		   GET MESSAGE (12)             a8
+		 */
+
+		switch (current_SC->cmnd[0]) {
+		case CHANGE_DEFINITION:
+		case COMPARE:
+		case COPY:
+		case COPY_VERIFY:
+		case LOG_SELECT:
+		case MODE_SELECT:
+		case MODE_SELECT_10:
+		case SEND_DIAGNOSTIC:
+		case WRITE_BUFFER:
+
+		case FORMAT_UNIT:
+		case REASSIGN_BLOCKS:
+		case RESERVE:
+		case SEARCH_EQUAL:
+		case SEARCH_HIGH:
+		case SEARCH_LOW:
+		case WRITE_6:
+		case WRITE_10:
+		case WRITE_VERIFY:
+		case 0x3f:
+		case 0x41:
+
+		case 0xb1:
+		case 0xb0:
+		case 0xb2:
+		case 0xaa:
+		case 0xae:
+
+		case 0x24:
+
+		case 0x38:
+		case 0x3d:
+
+		case 0xb6:
+
+		case 0xea:	/* alternate number for WRITE LONG */
+
+			current_SC->SCp.have_data_in = -1;
+			outb(0xd0 | PARITY_MASK, TMC_Cntl_port);
+			break;
+
+		case 0x00:
+		default:
+
+			current_SC->SCp.have_data_in = 1;
+			outb(0x90 | PARITY_MASK, TMC_Cntl_port);
+			break;
+		}
+	}
+
+	if (current_SC->SCp.have_data_in == -1) {	/* DATA OUT */
+		while ((data_count = FIFO_Size - inw(FIFO_Data_Count_port)) > 512) {
+#if EVERY_ACCESS
+			printk("DC=%d, ", data_count);
+#endif
+			if (data_count > current_SC->SCp.this_residual)
+				data_count = current_SC->SCp.this_residual;
+			if (data_count > 0) {
+#if EVERY_ACCESS
+				printk("%d OUT, ", data_count);
+#endif
+				if (data_count == 1) {
+					Bytes_Written++;
+
+					outb(*current_SC->SCp.ptr++, Write_FIFO_port);
+					--current_SC->SCp.this_residual;
+				} else {
+					data_count >>= 1;
+					tmp_count = data_count << 1;
+					outsw(Write_FIFO_port, current_SC->SCp.ptr, data_count);
+					current_SC->SCp.ptr += tmp_count;
+					Bytes_Written += tmp_count;
+					current_SC->SCp.this_residual -= tmp_count;
+				}
+			}
+			if (!current_SC->SCp.this_residual) {
+				if (current_SC->SCp.buffers_residual) {
+					--current_SC->SCp.buffers_residual;
+					++current_SC->SCp.buffer;
+					current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+					current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+				} else
+					break;
+			}
+		}
+	} else if (current_SC->SCp.have_data_in == 1) {	/* DATA IN */
+		while ((data_count = inw(FIFO_Data_Count_port)) > 0) {
+#if EVERY_ACCESS
+			printk("DC=%d, ", data_count);
+#endif
+			if (data_count > current_SC->SCp.this_residual)
+				data_count = current_SC->SCp.this_residual;
+			if (data_count) {
+#if EVERY_ACCESS
+				printk("%d IN, ", data_count);
+#endif
+				if (data_count == 1) {
+					Bytes_Read++;
+					*current_SC->SCp.ptr++ = inb(Read_FIFO_port);
+					--current_SC->SCp.this_residual;
+				} else {
+					data_count >>= 1;	/* Number of words */
+					tmp_count = data_count << 1;
+					insw(Read_FIFO_port, current_SC->SCp.ptr, data_count);
+					current_SC->SCp.ptr += tmp_count;
+					Bytes_Read += tmp_count;
+					current_SC->SCp.this_residual -= tmp_count;
+				}
+			}
+			if (!current_SC->SCp.this_residual && current_SC->SCp.buffers_residual) {
+				--current_SC->SCp.buffers_residual;
+				++current_SC->SCp.buffer;
+				current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+				current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+			}
+		}
+	}
+
+	if (done) {
+#if EVERY_ACCESS
+		printk(" ** IN DONE %d ** ", current_SC->SCp.have_data_in);
+#endif
+
+#if ERRORS_ONLY
+		if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
+			if ((unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f) {
+				unsigned char key;
+				unsigned char code;
+				unsigned char qualifier;
+
+				key = (unsigned char) (*((char *) current_SC->request_buffer + 2)) & 0x0f;
+				code = (unsigned char) (*((char *) current_SC->request_buffer + 12));
+				qualifier = (unsigned char) (*((char *) current_SC->request_buffer + 13));
+
+				if (key != UNIT_ATTENTION && !(key == NOT_READY && code == 0x04 && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
+				    && !(key == ILLEGAL_REQUEST && (code == 0x25 || code == 0x24 || !code)))
+
+					printk("fd_mcs: REQUEST SENSE " "Key = %x, Code = %x, Qualifier = %x\n", key, code, qualifier);
+			}
+		}
+#endif
+#if EVERY_ACCESS
+		printk("BEFORE MY_DONE. . .");
+#endif
+		spin_lock_irqsave(shpnt->host_lock, flags);
+		my_done(shpnt, (current_SC->SCp.Status & 0xff)
+			| ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
+		spin_unlock_irqrestore(shpnt->host_lock, flags);
+#if EVERY_ACCESS
+		printk("RETURNING.\n");
+#endif
+
+	} else {
+		if (current_SC->SCp.phase & disconnect) {
+			outb(0xd0 | FIFO_COUNT, Interrupt_Cntl_port);
+			outb(0x00, SCSI_Cntl_port);
+		} else {
+			outb(0x90 | FIFO_COUNT, Interrupt_Cntl_port);
+		}
+	}
+#if DEBUG_RACE
+	in_interrupt_flag = 0;
+#endif
+	return IRQ_HANDLED;
+}
+
+static int fd_mcs_release(struct Scsi_Host *shpnt)
+{
+	int i, this_host, irq_usage;
+
+	release_region(shpnt->io_port, shpnt->n_io_port);
+
+	this_host = -1;
+	irq_usage = 0;
+	for (i = 0; i < found; i++) {
+		if (shpnt == hosts[i])
+			this_host = i;
+		if (shpnt->irq == hosts[i]->irq)
+			irq_usage++;
+	}
+
+	/* only for the last one */
+	if (1 == irq_usage)
+		free_irq(shpnt->irq, hosts);
+
+	found--;
+
+	for (i = this_host; i < found; i++)
+		hosts[i] = hosts[i + 1];
+
+	hosts[found] = NULL;
+
+	return 0;
+}
+
+static int fd_mcs_queue(Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+
+	if (in_command) {
+		panic("fd_mcs: fd_mcs_queue() NOT REENTRANT!\n");
+	}
+#if EVERY_ACCESS
+	printk("queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->target, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+#endif
+
+	fd_mcs_make_bus_idle(shpnt);
+
+	SCpnt->scsi_done = done;	/* Save this for the done function */
+	current_SC = SCpnt;
+
+	/* Initialize static data */
+
+	if (current_SC->use_sg) {
+		current_SC->SCp.buffer = (struct scatterlist *) current_SC->request_buffer;
+		current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+		current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+		current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+	} else {
+		current_SC->SCp.ptr = (char *) current_SC->request_buffer;
+		current_SC->SCp.this_residual = current_SC->request_bufflen;
+		current_SC->SCp.buffer = NULL;
+		current_SC->SCp.buffers_residual = 0;
+	}
+
+
+	current_SC->SCp.Status = 0;
+	current_SC->SCp.Message = 0;
+	current_SC->SCp.have_data_in = 0;
+	current_SC->SCp.sent_command = 0;
+	current_SC->SCp.phase = in_arbitration;
+
+	/* Start arbitration */
+	outb(0x00, Interrupt_Cntl_port);
+	outb(0x00, SCSI_Cntl_port);	/* Disable data drivers */
+	outb(adapter_mask, SCSI_Data_NoACK_port);	/* Set our id bit */
+	in_command = 1;
+	outb(0x20, Interrupt_Cntl_port);
+	outb(0x14 | PARITY_MASK, TMC_Cntl_port);	/* Start arbitration */
+
+	return 0;
+}
+
+#if DEBUG_ABORT || DEBUG_RESET
+static void fd_mcs_print_info(Scsi_Cmnd * SCpnt)
+{
+	unsigned int imr;
+	unsigned int irr;
+	unsigned int isr;
+	struct Scsi_Host *shpnt = SCpnt->host;
+
+	if (!SCpnt || !SCpnt->host) {
+		printk("fd_mcs: cannot provide detailed information\n");
+	}
+
+	printk("%s\n", fd_mcs_info(SCpnt->host));
+	print_banner(SCpnt->host);
+	switch (SCpnt->SCp.phase) {
+	case in_arbitration:
+		printk("arbitration ");
+		break;
+	case in_selection:
+		printk("selection ");
+		break;
+	case in_other:
+		printk("other ");
+		break;
+	default:
+		printk("unknown ");
+		break;
+	}
+
+	printk("(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", SCpnt->SCp.phase, SCpnt->device->id, *(unsigned char *) SCpnt->cmnd, SCpnt->use_sg, SCpnt->request_bufflen);
+	printk("sent_command = %d, have_data_in = %d, timeout = %d\n", SCpnt->SCp.sent_command, SCpnt->SCp.have_data_in, SCpnt->timeout);
+#if DEBUG_RACE
+	printk("in_interrupt_flag = %d\n", in_interrupt_flag);
+#endif
+
+	imr = (inb(0x0a1) << 8) + inb(0x21);
+	outb(0x0a, 0xa0);
+	irr = inb(0xa0) << 8;
+	outb(0x0a, 0x20);
+	irr += inb(0x20);
+	outb(0x0b, 0xa0);
+	isr = inb(0xa0) << 8;
+	outb(0x0b, 0x20);
+	isr += inb(0x20);
+
+	/* Print out interesting information */
+	printk("IMR = 0x%04x", imr);
+	if (imr & (1 << shpnt->irq))
+		printk(" (masked)");
+	printk(", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr);
+
+	printk("SCSI Status      = 0x%02x\n", inb(SCSI_Status_port));
+	printk("TMC Status       = 0x%02x", inb(TMC_Status_port));
+	if (inb(TMC_Status_port) & 1)
+		printk(" (interrupt)");
+	printk("\n");
+	printk("Interrupt Status = 0x%02x", inb(Interrupt_Status_port));
+	if (inb(Interrupt_Status_port) & 0x08)
+		printk(" (enabled)");
+	printk("\n");
+	if (chip == tmc18c50 || chip == tmc18c30) {
+		printk("FIFO Status      = 0x%02x\n", inb(shpnt->io_port + FIFO_Status));
+		printk("Int. Condition   = 0x%02x\n", inb(shpnt->io_port + Interrupt_Cond));
+	}
+	printk("Configuration 1  = 0x%02x\n", inb(shpnt->io_port + Configuration1));
+	if (chip == tmc18c50 || chip == tmc18c30)
+		printk("Configuration 2  = 0x%02x\n", inb(shpnt->io_port + Configuration2));
+}
+#endif
+
+static int fd_mcs_abort(Scsi_Cmnd * SCpnt)
+{
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+
+	unsigned long flags;
+#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
+	printk("fd_mcs: abort ");
+#endif
+
+	spin_lock_irqsave(shpnt->host_lock, flags);
+	if (!in_command) {
+#if EVERY_ACCESS || ERRORS_ONLY
+		printk(" (not in command)\n");
+#endif
+		spin_unlock_irqrestore(shpnt->host_lock, flags);
+		return FAILED;
+	} else
+		printk("\n");
+
+#if DEBUG_ABORT
+	fd_mcs_print_info(SCpnt);
+#endif
+
+	fd_mcs_make_bus_idle(shpnt);
+
+	current_SC->SCp.phase |= aborted;
+
+	current_SC->result = DID_ABORT << 16;
+
+	/* Aborts are not done well. . . */
+	my_done(shpnt, DID_ABORT << 16);
+
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
+	return SUCCESS;
+}
+
+static int fd_mcs_host_reset(Scsi_Cmnd * SCpnt)
+{
+	return FAILED;
+}
+
+static int fd_mcs_device_reset(Scsi_Cmnd * SCpnt) 
+{
+	return FAILED;
+}
+
+static int fd_mcs_bus_reset(Scsi_Cmnd * SCpnt) {
+	struct Scsi_Host *shpnt = SCpnt->device->host;
+
+#if DEBUG_RESET
+	static int called_once = 0;
+#endif
+
+#if ERRORS_ONLY
+	if (SCpnt)
+		printk("fd_mcs: SCSI Bus Reset\n");
+#endif
+
+#if DEBUG_RESET
+	if (called_once)
+		fd_mcs_print_info(current_SC);
+	called_once = 1;
+#endif
+
+	outb(1, SCSI_Cntl_port);
+	do_pause(2);
+	outb(0, SCSI_Cntl_port);
+	do_pause(115);
+	outb(0, SCSI_Mode_Cntl_port);
+	outb(PARITY_MASK, TMC_Cntl_port);
+
+	/* Unless this is the very first call (i.e., SCPnt == NULL), everything
+	   is probably hosed at this point.  We will, however, try to keep
+	   things going by informing the high-level code that we need help. */
+		return SUCCESS;
+}
+
+#include <scsi/scsi_ioctl.h>
+
+static int fd_mcs_biosparam(struct scsi_device * disk, struct block_device *bdev,
+			    sector_t capacity, int *info_array) 
+{
+	unsigned char *p = scsi_bios_ptable(bdev);
+	int size = capacity;
+
+	/* BIOS >= 3.4 for MCA cards */
+	/* This algorithm was provided by Future Domain (much thanks!). */
+
+	if (p && p[65] == 0xaa && p[64] == 0x55	/* Partition table valid */
+	    && p[4]) {	/* Partition type */
+		/* The partition table layout is as follows:
+
+		   Start: 0x1b3h
+		   Offset: 0 = partition status
+		   1 = starting head
+		   2 = starting sector and cylinder (word, encoded)
+		   4 = partition type
+		   5 = ending head
+		   6 = ending sector and cylinder (word, encoded)
+		   8 = starting absolute sector (double word)
+		   c = number of sectors (double word)
+		   Signature: 0x1fe = 0x55aa
+
+		   So, this algorithm assumes:
+		   1) the first partition table is in use,
+		   2) the data in the first entry is correct, and
+		   3) partitions never divide cylinders
+
+		   Note that (1) may be FALSE for NetBSD (and other BSD flavors),
+		   as well as for Linux.  Note also, that Linux doesn't pay any
+		   attention to the fields that are used by this algorithm -- it
+		   only uses the absolute sector data.  Recent versions of Linux's
+		   fdisk(1) will fill this data in correctly, and forthcoming
+		   versions will check for consistency.
+
+		   Checking for a non-zero partition type is not part of the
+		   Future Domain algorithm, but it seemed to be a reasonable thing
+		   to do, especially in the Linux and BSD worlds. */
+
+		info_array[0] = p[5] + 1;	/* heads */
+		info_array[1] = p[6] & 0x3f;	/* sectors */
+	} else {
+		/* Note that this new method guarantees that there will always be
+		   less than 1024 cylinders on a platter.  This is good for drives
+		   up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+		if ((unsigned int) size >= 0x7e0000U) 
+		{
+			info_array[0] = 0xff;	/* heads   = 255 */
+			info_array[1] = 0x3f;	/* sectors =  63 */
+		} else if ((unsigned int) size >= 0x200000U) {
+			info_array[0] = 0x80;	/* heads   = 128 */
+			info_array[1] = 0x3f;	/* sectors =  63 */
+		} else {
+			info_array[0] = 0x40;	/* heads   =  64 */
+			info_array[1] = 0x20;	/* sectors =  32 */
+		}
+	}
+	/* For both methods, compute the cylinders */
+	info_array[2] = (unsigned int) size / (info_array[0] * info_array[1]);
+	kfree(p);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "fd_mcs",
+	.proc_info			= fd_mcs_proc_info,
+	.detect				= fd_mcs_detect,
+	.release			= fd_mcs_release,
+	.info				= fd_mcs_info,
+	.queuecommand   		= fd_mcs_queue, 
+	.eh_abort_handler		= fd_mcs_abort,
+	.eh_bus_reset_handler		= fd_mcs_bus_reset,
+	.eh_host_reset_handler		= fd_mcs_host_reset,
+	.eh_device_reset_handler	= fd_mcs_device_reset,
+	.bios_param     		= fd_mcs_biosparam,
+	.can_queue      		= 1,
+	.this_id        		= 7,
+	.sg_tablesize   		= 64,
+	.cmd_per_lun    		= 1,
+	.use_clustering 		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c
new file mode 100644
index 0000000..a843c08
--- /dev/null
+++ b/drivers/scsi/fdomain.c
@@ -0,0 +1,1739 @@
+/* fdomain.c -- Future Domain TMC-16x0 SCSI driver
+ * Created: Sun May  3 18:53:19 1992 by faith@cs.unc.edu
+ * Revised: Mon Dec 28 21:59:02 1998 by faith@acm.org
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org)
+ * Shared IRQ supported added 7/7/2001  Alan Cox <alan@redhat.com>
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ **************************************************************************
+
+ SUMMARY:
+
+ Future Domain BIOS versions supported for autodetect:
+    2.0, 3.0, 3.2, 3.4 (1.0), 3.5 (2.0), 3.6, 3.61
+ Chips are supported:
+    TMC-1800, TMC-18C50, TMC-18C30, TMC-36C70
+ Boards supported:
+    Future Domain TMC-1650, TMC-1660, TMC-1670, TMC-1680, TMC-1610M/MER/MEX
+    Future Domain TMC-3260 (PCI)
+    Quantum ISA-200S, ISA-250MG
+    Adaptec AHA-2920A (PCI) [BUT *NOT* AHA-2920C -- use aic7xxx instead]
+    IBM ?
+ LILO/INSMOD command-line options:
+    fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]
+
+
+    
+ NOTE:
+
+ The Adaptec AHA-2920C has an Adaptec AIC-7850 chip on it.
+ Use the aic7xxx driver for this board.
+       
+ The Adaptec AHA-2920A has a Future Domain chip on it, so this is the right
+ driver for that card.  Unfortunately, the boxes will probably just say
+ "2920", so you'll have to look on the card for a Future Domain logo, or a
+ letter after the 2920.
+
+ 
+ 
+ THANKS:
+
+ Thanks to Adaptec for providing PCI boards for testing.  This finally
+ enabled me to test the PCI detection and correct it for PCI boards that do
+ not have a BIOS at a standard ISA location.  For PCI boards, LILO/INSMOD
+ command-line options should no longer be needed.  --RF 18Nov98
+
+
+ 
+ DESCRIPTION:
+ 
+ This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680
+ TMC-1650/1670, and TMC-3260 SCSI host adapters.  The 1650 and 1670 have a
+ 25-pin external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin
+ high-density external connector.  The 1670 and 1680 have floppy disk
+ controllers built in.  The TMC-3260 is a PCI bus card.
+
+ Future Domain's older boards are based on the TMC-1800 chip, and this
+ driver was originally written for a TMC-1680 board with the TMC-1800 chip.
+ More recently, boards are being produced with the TMC-18C50 and TMC-18C30
+ chips.  The latest and greatest board may not work with this driver.  If
+ you have to patch this driver so that it will recognize your board's BIOS
+ signature, then the driver may fail to function after the board is
+ detected.
+
+ Please note that the drive ordering that Future Domain implemented in BIOS
+ versions 3.4 and 3.5 is the opposite of the order (currently) used by the
+ rest of the SCSI industry.  If you have BIOS version 3.4 or 3.5, and have
+ more than one drive, then the drive ordering will be the reverse of that
+ which you see under DOS.  For example, under DOS SCSI ID 0 will be D: and
+ SCSI ID 1 will be C: (the boot device).  Under Linux, SCSI ID 0 will be
+ /dev/sda and SCSI ID 1 will be /dev/sdb.  The Linux ordering is consistent
+ with that provided by all the other SCSI drivers for Linux.  If you want
+ this changed, you will probably have to patch the higher level SCSI code.
+ If you do so, please send me patches that are protected by #ifdefs.
+
+ If you have a TMC-8xx or TMC-9xx board, then this is not the driver for
+ your board.  Please refer to the Seagate driver for more information and
+ possible support.
+
+ 
+ 
+ HISTORY:
+
+ Linux       Driver      Driver
+ Version     Version     Date         Support/Notes
+
+             0.0          3 May 1992  V2.0 BIOS; 1800 chip
+ 0.97        1.9         28 Jul 1992
+ 0.98.6      3.1         27 Nov 1992
+ 0.99        3.2          9 Dec 1992
+
+ 0.99.3      3.3         10 Jan 1993  V3.0 BIOS
+ 0.99.5      3.5         18 Feb 1993
+ 0.99.10     3.6         15 May 1993  V3.2 BIOS; 18C50 chip
+ 0.99.11     3.17         3 Jul 1993  (now under RCS)
+ 0.99.12     3.18        13 Aug 1993
+ 0.99.14     5.6         31 Oct 1993  (reselection code removed)
+
+ 0.99.15     5.9         23 Jan 1994  V3.4 BIOS (preliminary)
+ 1.0.8/1.1.1 5.15         1 Apr 1994  V3.4 BIOS; 18C30 chip (preliminary)
+ 1.0.9/1.1.3 5.16         7 Apr 1994  V3.4 BIOS; 18C30 chip
+ 1.1.38      5.18        30 Jul 1994  36C70 chip (PCI version of 18C30)
+ 1.1.62      5.20         2 Nov 1994  V3.5 BIOS
+ 1.1.73      5.22         7 Dec 1994  Quantum ISA-200S board; V2.0 BIOS
+
+ 1.1.82      5.26        14 Jan 1995  V3.5 BIOS; TMC-1610M/MER/MEX board
+ 1.2.10      5.28         5 Jun 1995  Quantum ISA-250MG board; V2.0, V2.01 BIOS
+ 1.3.4       5.31        23 Jun 1995  PCI BIOS-32 detection (preliminary)
+ 1.3.7       5.33         4 Jul 1995  PCI BIOS-32 detection
+ 1.3.28      5.36        17 Sep 1995  V3.61 BIOS; LILO command-line support
+ 1.3.34      5.39        12 Oct 1995  V3.60 BIOS; /proc
+ 1.3.72      5.39         8 Feb 1996  Adaptec AHA-2920 board
+ 1.3.85      5.41         4 Apr 1996
+ 2.0.12      5.44         8 Aug 1996  Use ID 7 for all PCI cards
+ 2.1.1       5.45         2 Oct 1996  Update ROM accesses for 2.1.x
+ 2.1.97      5.46	 23 Apr 1998  Rewritten PCI detection routines [mj]
+ 2.1.11x     5.47	  9 Aug 1998  Touched for 8 SCSI disk majors support
+             5.48        18 Nov 1998  BIOS no longer needed for PCI detection
+ 2.2.0       5.50        28 Dec 1998  Support insmod parameters
+ 
+
+ REFERENCES USED:
+
+ "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation,
+ 1990.
+
+ "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain
+ Corporation, January 1992.
+
+ "LXT SCSI Products: Specifications and OEM Technical Manual (Revision
+ B/September 1991)", Maxtor Corporation, 1991.
+
+ "7213S product Manual (Revision P3)", Maxtor Corporation, 1992.
+
+ "Draft Proposed American National Standard: Small Computer System
+ Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109,
+ revision 10h, October 17, 1991)
+
+ Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric
+ Youngdale (ericy@cais.com), 1992.
+
+ Private communication, Tuong Le (Future Domain Engineering department),
+ 1994. (Disk geometry computations for Future Domain BIOS version 3.4, and
+ TMC-18C30 detection.)
+
+ Hogan, Thom. The Programmer's PC Sourcebook. Microsoft Press, 1988. Page
+ 60 (2.39: Disk Partition Table Layout).
+
+ "18C30 Technical Reference Manual", Future Domain Corporation, 1993, page
+ 6-1.
+
+
+ 
+ NOTES ON REFERENCES:
+
+ The Maxtor manuals were free.  Maxtor telephone technical support is
+ great!
+
+ The Future Domain manuals were $25 and $35.  They document the chip, not
+ the TMC-16x0 boards, so some information I had to guess at.  In 1992,
+ Future Domain sold DOS BIOS source for $250 and the UN*X driver source was
+ $750, but these required a non-disclosure agreement, so even if I could
+ have afforded them, they would *not* have been useful for writing this
+ publically distributable driver.  Future Domain technical support has
+ provided some information on the phone and have sent a few useful FAXs.
+ They have been much more helpful since they started to recognize that the
+ word "Linux" refers to an operating system :-).
+
+ 
+
+ ALPHA TESTERS:
+
+ There are many other alpha testers that come and go as the driver
+ develops.  The people listed here were most helpful in times of greatest
+ need (mostly early on -- I've probably left out a few worthy people in
+ more recent times):
+
+ Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
+ Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari
+ Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad
+ Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com).
+
+ Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me
+ his 18C50-based card for debugging.  He is the sole reason that this
+ driver works with the 18C50 chip.
+
+ Thanks to Dave Newman (dnewman@crl.com) for providing initial patches for
+ the version 3.4 BIOS.
+
+ Thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for providing
+ patches that support the TMC-3260, a PCI bus card with the 36C70 chip.
+ The 36C70 chip appears to be "completely compatible" with the 18C30 chip.
+
+ Thanks to Eric Kasten (tigger@petroglyph.cl.msu.edu) for providing the
+ patch for the version 3.5 BIOS.
+
+ Thanks for Stephen Henson (shenson@nyx10.cs.du.edu) for providing the
+ patch for the Quantum ISA-200S SCSI adapter.
+ 
+ Thanks to Adam Bowen for the signature to the 1610M/MER/MEX scsi cards, to
+ Martin Andrews (andrewm@ccfadm.eeg.ccf.org) for the signature to some
+ random TMC-1680 repackaged by IBM; and to Mintak Ng (mintak@panix.com) for
+ the version 3.61 BIOS signature.
+
+ Thanks for Mark Singer (elf@netcom.com) and Richard Simpson
+ (rsimpson@ewrcsdra.demon.co.uk) for more Quantum signatures and detective
+ work on the Quantum RAM layout.
+
+ Special thanks to James T. McKinley (mckinley@msupa.pa.msu.edu) for
+ providing patches for proper PCI BIOS32-mediated detection of the TMC-3260
+ card (a PCI bus card with the 36C70 chip).  Please send James PCI-related
+ bug reports.
+
+ Thanks to Tom Cavin (tec@usa1.com) for preliminary command-line option
+ patches.
+
+ New PCI detection code written by Martin Mares <mj@atrey.karlin.mff.cuni.cz>
+
+ Insmod parameter code based on patches from Daniel Graham
+ <graham@balance.uoregon.edu>. 
+ 
+ All of the alpha testers deserve much thanks.
+
+
+
+ NOTES ON USER DEFINABLE OPTIONS:
+
+ DEBUG: This turns on the printing of various debug information.
+
+ ENABLE_PARITY: This turns on SCSI parity checking.  With the current
+ driver, all attached devices must support SCSI parity.  If none of your
+ devices support parity, then you can probably get the driver to work by
+ turning this option off.  I have no way of testing this, however, and it
+ would appear that no one ever uses this option.
+
+ FIFO_COUNT: The host adapter has an 8K cache (host adapters based on the
+ 18C30 chip have a 2k cache).  When this many 512 byte blocks are filled by
+ the SCSI device, an interrupt will be raised.  Therefore, this could be as
+ low as 0, or as high as 16.  Note, however, that values which are too high
+ or too low seem to prevent any interrupts from occurring, and thereby lock
+ up the machine.  I have found that 2 is a good number, but throughput may
+ be increased by changing this value to values which are close to 2.
+ Please let me know if you try any different values.
+
+ RESELECTION: This is no longer an option, since I gave up trying to
+ implement it in version 4.x of this driver.  It did not improve
+ performance at all and made the driver unstable (because I never found one
+ of the two race conditions which were introduced by the multiple
+ outstanding command code).  The instability seems a very high price to pay
+ just so that you don't have to wait for the tape to rewind.  If you want
+ this feature implemented, send me patches.  I'll be happy to send a copy
+ of my (broken) driver to anyone who would like to see a copy.
+
+ **************************************************************************/
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <scsi/scsicam.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include "fdomain.h"
+
+MODULE_AUTHOR("Rickard E. Faith");
+MODULE_DESCRIPTION("Future domain SCSI driver");
+MODULE_LICENSE("GPL");
+
+  
+#define VERSION          "$Revision: 5.51 $"
+
+/* START OF USER DEFINABLE OPTIONS */
+
+#define DEBUG            0	/* Enable debugging output */
+#define ENABLE_PARITY    1	/* Enable SCSI Parity */
+#define FIFO_COUNT       2	/* Number of 512 byte blocks before INTR */
+
+/* END OF USER DEFINABLE OPTIONS */
+
+#if DEBUG
+#define EVERY_ACCESS     0	/* Write a line on every scsi access */
+#define ERRORS_ONLY      1	/* Only write a line if there is an error */
+#define DEBUG_DETECT     0	/* Debug fdomain_16x0_detect() */
+#define DEBUG_MESSAGES   1	/* Debug MESSAGE IN phase */
+#define DEBUG_ABORT      1	/* Debug abort() routine */
+#define DEBUG_RESET      1	/* Debug reset() routine */
+#define DEBUG_RACE       1      /* Debug interrupt-driven race condition */
+#else
+#define EVERY_ACCESS     0	/* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */
+#define ERRORS_ONLY      0
+#define DEBUG_DETECT     0
+#define DEBUG_MESSAGES   0
+#define DEBUG_ABORT      0
+#define DEBUG_RESET      0
+#define DEBUG_RACE       0
+#endif
+
+/* Errors are reported on the line, so we don't need to report them again */
+#if EVERY_ACCESS
+#undef ERRORS_ONLY
+#define ERRORS_ONLY      0
+#endif
+
+#if ENABLE_PARITY
+#define PARITY_MASK      0x08
+#else
+#define PARITY_MASK      0x00
+#endif
+
+enum chip_type {
+   unknown          = 0x00,
+   tmc1800          = 0x01,
+   tmc18c50         = 0x02,
+   tmc18c30         = 0x03,
+};
+
+enum {
+   in_arbitration   = 0x02,
+   in_selection     = 0x04,
+   in_other         = 0x08,
+   disconnect       = 0x10,
+   aborted          = 0x20,
+   sent_ident       = 0x40,
+};
+
+enum in_port_type {
+   Read_SCSI_Data   =  0,
+   SCSI_Status      =  1,
+   TMC_Status       =  2,
+   FIFO_Status      =  3,	/* tmc18c50/tmc18c30 only */
+   Interrupt_Cond   =  4,	/* tmc18c50/tmc18c30 only */
+   LSB_ID_Code      =  5,
+   MSB_ID_Code      =  6,
+   Read_Loopback    =  7,
+   SCSI_Data_NoACK  =  8,
+   Interrupt_Status =  9,
+   Configuration1   = 10,
+   Configuration2   = 11,	/* tmc18c50/tmc18c30 only */
+   Read_FIFO        = 12,
+   FIFO_Data_Count  = 14
+};
+
+enum out_port_type {
+   Write_SCSI_Data  =  0,
+   SCSI_Cntl        =  1,
+   Interrupt_Cntl   =  2,
+   SCSI_Mode_Cntl   =  3,
+   TMC_Cntl         =  4,
+   Memory_Cntl      =  5,	/* tmc18c50/tmc18c30 only */
+   Write_Loopback   =  7,
+   IO_Control       = 11,	/* tmc18c30 only */
+   Write_FIFO       = 12
+};
+
+/* .bss will zero all the static variables below */
+static int               port_base;
+static unsigned long     bios_base;
+static void __iomem *    bios_mem;
+static int               bios_major;
+static int               bios_minor;
+static int               PCI_bus;
+static int               Quantum;	/* Quantum board variant */
+static int               interrupt_level;
+static volatile int      in_command;
+static struct scsi_cmnd  *current_SC;
+static enum chip_type    chip              = unknown;
+static int               adapter_mask;
+static int               this_id;
+static int               setup_called;
+
+#if DEBUG_RACE
+static volatile int      in_interrupt_flag;
+#endif
+
+static int               FIFO_Size = 0x2000; /* 8k FIFO for
+						pre-tmc18c30 chips */
+
+static irqreturn_t       do_fdomain_16x0_intr( int irq, void *dev_id,
+					    struct pt_regs * regs );
+/* Allow insmod parameters to be like LILO parameters.  For example:
+   insmod fdomain fdomain=0x140,11 */
+static char * fdomain = NULL;
+module_param(fdomain, charp, 0);
+
+static unsigned long addresses[] = {
+   0xc8000,
+   0xca000,
+   0xce000,
+   0xde000,
+   0xcc000,		/* Extra addresses for PCI boards */
+   0xd0000,
+   0xe0000,
+};
+#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
+		       
+static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 };
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 };
+
+/*
+
+  READ THIS BEFORE YOU ADD A SIGNATURE!
+
+  READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME!
+
+  READ EVERY WORD, ESPECIALLY THE WORD *NOT*
+
+  This driver works *ONLY* for Future Domain cards using the TMC-1800,
+  TMC-18C50, or TMC-18C30 chip.  This includes models TMC-1650, 1660, 1670,
+  and 1680.  These are all 16-bit cards.
+
+  The following BIOS signature signatures are for boards which do *NOT*
+  work with this driver (these TMC-8xx and TMC-9xx boards may work with the
+  Seagate driver):
+
+  FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88
+  FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89
+  FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89
+  FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90
+  FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90
+  FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90
+  FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92
+
+  (The cards which do *NOT* work are all 8-bit cards -- although some of
+  them have a 16-bit form-factor, the upper 8-bits are used only for IRQs
+  and are *NOT* used for data.  You can tell the difference by following
+  the tracings on the circuit board -- if only the IRQ lines are involved,
+  you have a "8-bit" card, and should *NOT* use this driver.)
+
+*/
+
+static struct signature {
+   const char *signature;
+   int  sig_offset;
+   int  sig_length;
+   int  major_bios_version;
+   int  minor_bios_version;
+   int  flag; /* 1 == PCI_bus, 2 == ISA_200S, 3 == ISA_250MG, 4 == ISA_200S */
+} signatures[] = {
+   /*          1         2         3         4         5         6 */
+   /* 123456789012345678901234567890123456789012345678901234567890 */
+   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89",  5, 50,  2,  0, 0 },
+   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89",  5, 50,  2,  0, 0 },
+   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 72, 50,  2,  0, 2 },
+   { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.0",        73, 43,  2,  0, 3 },
+   { "FUTURE DOMAIN CORP. (C) 1991 1800-V2.0.",            72, 39,  2,  0, 4 },
+   { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92",        5, 44,  3,  0, 0 },
+   { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93",        5, 44,  3,  2, 0 },
+   { "IBM F1 P2 BIOS v1.0104/29/93",                        5, 28,  3, -1, 0 },
+   { "Future Domain Corp. V1.0008/18/93",                   5, 33,  3,  4, 0 },
+   { "Future Domain Corp. V1.0008/18/93",                  26, 33,  3,  4, 1 },
+   { "Adaptec AHA-2920 PCI-SCSI Card",                     42, 31,  3, -1, 1 },
+   { "IBM F1 P264/32",                                      5, 14,  3, -1, 1 },
+				/* This next signature may not be a 3.5 bios */
+   { "Future Domain Corp. V2.0108/18/93",                   5, 33,  3,  5, 0 },
+   { "FUTURE DOMAIN CORP.  V3.5008/18/93",                  5, 34,  3,  5, 0 },
+   { "FUTURE DOMAIN 18c30/18c50/1800 (C) 1994 V3.5",        5, 44,  3,  5, 0 },
+   { "FUTURE DOMAIN CORP.  V3.6008/18/93",                  5, 34,  3,  6, 0 },
+   { "FUTURE DOMAIN CORP.  V3.6108/18/93",                  5, 34,  3,  6, 0 },
+   { "FUTURE DOMAIN TMC-18XX",                              5, 22, -1, -1, 0 },
+
+   /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGNATURE
+    Also, fix the disk geometry code for your signature and send your
+    changes for faith@cs.unc.edu.  Above all, do *NOT* change any old
+    signatures!
+
+    Note that the last line will match a "generic" 18XX bios.  Because
+    Future Domain has changed the host SCSI ID and/or the location of the
+    geometry information in the on-board RAM area for each of the first
+    three BIOS's, it is still important to enter a fully qualified
+    signature in the table for any new BIOS's (after the host SCSI ID and
+    geometry location are verified). */
+};
+
+#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+
+static void print_banner( struct Scsi_Host *shpnt )
+{
+   if (!shpnt) return;		/* This won't ever happen */
+
+   if (bios_major < 0 && bios_minor < 0) {
+      printk(KERN_INFO "scsi%d: <fdomain> No BIOS; using scsi id %d\n",
+	      shpnt->host_no, shpnt->this_id);
+   } else {
+      printk(KERN_INFO "scsi%d: <fdomain> BIOS version ", shpnt->host_no);
+
+      if (bios_major >= 0) printk("%d.", bios_major);
+      else                 printk("?.");
+
+      if (bios_minor >= 0) printk("%d", bios_minor);
+      else                 printk("?.");
+   
+      printk( " at 0x%lx using scsi id %d\n",
+	      bios_base, shpnt->this_id );
+   }
+
+				/* If this driver works for later FD PCI
+				   boards, we will have to modify banner
+				   for additional PCI cards, but for now if
+				   it's PCI it's a TMC-3260 - JTM */
+   printk(KERN_INFO "scsi%d: <fdomain> %s chip at 0x%x irq ",
+	   shpnt->host_no,
+	   chip == tmc1800 ? "TMC-1800" : (chip == tmc18c50 ? "TMC-18C50" : (chip == tmc18c30 ? (PCI_bus ? "TMC-36C70 (PCI bus)" : "TMC-18C30") : "Unknown")),
+	   port_base);
+
+   if (interrupt_level)
+   	printk("%d", interrupt_level);
+   else
+        printk("<none>");
+
+   printk( "\n" );
+}
+
+int fdomain_setup(char *str)
+{
+	int ints[4];
+
+	(void)get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (setup_called++ || ints[0] < 2 || ints[0] > 3) {
+		printk(KERN_INFO "scsi: <fdomain> Usage: fdomain=<PORT_BASE>,<IRQ>[,<ADAPTER_ID>]\n");
+		printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
+		return 0;
+	}
+
+	port_base       = ints[0] >= 1 ? ints[1] : 0;
+	interrupt_level = ints[0] >= 2 ? ints[2] : 0;
+	this_id         = ints[0] >= 3 ? ints[3] : 0;
+   
+	bios_major = bios_minor = -1; /* Use geometry for BIOS version >= 3.4 */
+	++setup_called;
+	return 1;
+}
+
+__setup("fdomain=", fdomain_setup);
+
+
+static void do_pause(unsigned amount)	/* Pause for amount*10 milliseconds */
+{
+	mdelay(10*amount);
+}
+
+inline static void fdomain_make_bus_idle( void )
+{
+   outb(0, port_base + SCSI_Cntl);
+   outb(0, port_base + SCSI_Mode_Cntl);
+   if (chip == tmc18c50 || chip == tmc18c30)
+	 outb(0x21 | PARITY_MASK, port_base + TMC_Cntl); /* Clear forced intr. */
+   else
+	 outb(0x01 | PARITY_MASK, port_base + TMC_Cntl);
+}
+
+static int fdomain_is_valid_port( int port )
+{
+#if DEBUG_DETECT 
+   printk( " (%x%x),",
+	   inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) );
+#endif
+
+   /* The MCA ID is a unique id for each MCA compatible board.  We
+      are using ISA boards, but Future Domain provides the MCA ID
+      anyway.  We can use this ID to ensure that this is a Future
+      Domain TMC-1660/TMC-1680.
+    */
+
+   if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */
+      if (inb( port + LSB_ID_Code ) != 0x27) return 0;
+      if (inb( port + MSB_ID_Code ) != 0x61) return 0;
+      chip = tmc1800;
+   } else {				    /* test for 0xe960 id */
+      if (inb( port + MSB_ID_Code ) != 0x60) return 0;
+      chip = tmc18c50;
+
+				/* Try to toggle 32-bit mode.  This only
+				   works on an 18c30 chip.  (User reports
+				   say this works, so we should switch to
+				   it in the near future.) */
+
+      outb( 0x80, port + IO_Control );
+      if ((inb( port + Configuration2 ) & 0x80) == 0x80) {
+	 outb( 0x00, port + IO_Control );
+	 if ((inb( port + Configuration2 ) & 0x80) == 0x00) {
+	    chip = tmc18c30;
+	    FIFO_Size = 0x800;	/* 2k FIFO */
+	 }
+      }
+				/* If that failed, we are an 18c50. */
+   }
+
+   return 1;
+}
+
+static int fdomain_test_loopback( void )
+{
+   int i;
+   int result;
+
+   for (i = 0; i < 255; i++) {
+      outb( i, port_base + Write_Loopback );
+      result = inb( port_base + Read_Loopback );
+      if (i != result)
+	    return 1;
+   }
+   return 0;
+}
+
+/* fdomain_get_irq assumes that we have a valid MCA ID for a
+   TMC-1660/TMC-1680 Future Domain board.  Now, check to be sure the
+   bios_base matches these ports.  If someone was unlucky enough to have
+   purchased more than one Future Domain board, then they will have to
+   modify this code, as we only detect one board here.  [The one with the
+   lowest bios_base.]
+
+   Note that this routine is only used for systems without a PCI BIOS32
+   (e.g., ISA bus).  For PCI bus systems, this routine will likely fail
+   unless one of the IRQs listed in the ints array is used by the board.
+   Sometimes it is possible to use the computer's BIOS setup screen to
+   configure a PCI system so that one of these IRQs will be used by the
+   Future Domain card. */
+
+static int fdomain_get_irq( int base )
+{
+   int options = inb(base + Configuration1);
+
+#if DEBUG_DETECT
+   printk("scsi: <fdomain> Options = %x\n", options);
+#endif
+ 
+   /* Check for board with lowest bios_base --
+      this isn't valid for the 18c30 or for
+      boards on the PCI bus, so just assume we
+      have the right board. */
+
+   if (chip != tmc18c30 && !PCI_bus && addresses[(options & 0xc0) >> 6 ] != bios_base)
+   	return 0;
+   return ints[(options & 0x0e) >> 1];
+}
+
+static int fdomain_isa_detect( int *irq, int *iobase )
+{
+#ifndef PCMCIA
+   int i, j;
+   int base = 0xdeadbeef;
+   int flag = 0;
+
+#if DEBUG_DETECT
+   printk( "scsi: <fdomain> fdomain_isa_detect:" );
+#endif
+
+   for (i = 0; i < ADDRESS_COUNT; i++) {
+      void __iomem *p = ioremap(addresses[i], 0x2000);
+      if (!p)
+	continue;
+#if DEBUG_DETECT
+      printk( " %lx(%lx),", addresses[i], bios_base );
+#endif
+      for (j = 0; j < SIGNATURE_COUNT; j++) {
+	 if (check_signature(p + signatures[j].sig_offset,
+			     signatures[j].signature,
+			     signatures[j].sig_length )) {
+	    bios_major = signatures[j].major_bios_version;
+	    bios_minor = signatures[j].minor_bios_version;
+	    PCI_bus    = (signatures[j].flag == 1);
+	    Quantum    = (signatures[j].flag > 1) ? signatures[j].flag : 0;
+	    bios_base  = addresses[i];
+	    bios_mem   = p;
+	    goto found;
+	 }
+      }
+      iounmap(p);
+   }
+ 
+found:
+   if (bios_major == 2) {
+      /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM.
+	 Assuming the ROM is enabled (otherwise we wouldn't have been
+	 able to read the ROM signature :-), then the ROM sets up the
+	 RAM area with some magic numbers, such as a list of port
+	 base addresses and a list of the disk "geometry" reported to
+	 DOS (this geometry has nothing to do with physical geometry).
+       */
+
+      switch (Quantum) {
+      case 2:			/* ISA_200S */
+      case 3:			/* ISA_250MG */
+	 base = readb(bios_mem + 0x1fa2) + (readb(bios_mem + 0x1fa3) << 8);
+	 break;
+      case 4:			/* ISA_200S (another one) */
+	 base = readb(bios_mem + 0x1fa3) + (readb(bios_mem + 0x1fa4) << 8);
+	 break;
+      default:
+	 base = readb(bios_mem + 0x1fcc) + (readb(bios_mem + 0x1fcd) << 8);
+	 break;
+      }
+   
+#if DEBUG_DETECT
+      printk( " %x,", base );
+#endif
+
+      for (i = 0; i < PORT_COUNT; i++) {
+	if (base == ports[i]) {
+		if (!request_region(base, 0x10, "fdomain"))
+			break;
+		if (!fdomain_is_valid_port(base)) {
+			release_region(base, 0x10);
+			break;
+		}
+		*irq    = fdomain_get_irq( base );
+		*iobase = base;
+		return 1;
+	}
+      }
+
+      /* This is a bad sign.  It usually means that someone patched the
+	 BIOS signature list (the signatures variable) to contain a BIOS
+	 signature for a board *OTHER THAN* the TMC-1660/TMC-1680. */
+      
+#if DEBUG_DETECT
+      printk( " RAM FAILED, " );
+#endif
+   }
+
+   /* Anyway, the alternative to finding the address in the RAM is to just
+      search through every possible port address for one that is attached
+      to the Future Domain card.  Don't panic, though, about reading all
+      these random port addresses -- there are rumors that the Future
+      Domain BIOS does something very similar.
+
+      Do not, however, check ports which the kernel knows are being used by
+      another driver. */
+
+   for (i = 0; i < PORT_COUNT; i++) {
+      base = ports[i];
+      if (!request_region(base, 0x10, "fdomain")) {
+#if DEBUG_DETECT
+	 printk( " (%x inuse),", base );
+#endif
+	 continue;
+      }
+#if DEBUG_DETECT
+      printk( " %x,", base );
+#endif
+      flag = fdomain_is_valid_port(base);
+      if (flag)
+	break;
+      release_region(base, 0x10);
+   }
+
+#if DEBUG_DETECT
+   if (flag) printk( " SUCCESS\n" );
+   else      printk( " FAILURE\n" );
+#endif
+
+   if (!flag) return 0;		/* iobase not found */
+
+   *irq    = fdomain_get_irq( base );
+   *iobase = base;
+
+   return 1;			/* success */
+#else
+   return 0;
+#endif
+}
+
+/* PCI detection function: int fdomain_pci_bios_detect(int* irq, int*
+   iobase) This function gets the Interrupt Level and I/O base address from
+   the PCI configuration registers. */
+
+#ifdef CONFIG_PCI
+static int fdomain_pci_bios_detect( int *irq, int *iobase, struct pci_dev **ret_pdev )
+{
+   unsigned int     pci_irq;                /* PCI interrupt line */
+   unsigned long    pci_base;               /* PCI I/O base address */
+   struct pci_dev   *pdev = NULL;
+
+#if DEBUG_DETECT
+   /* Tell how to print a list of the known PCI devices from bios32 and
+      list vendor and device IDs being used if in debug mode.  */
+      
+   printk( "scsi: <fdomain> INFO: use lspci -v to see list of PCI devices\n" );
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+	   " Using Vendor ID: 0x%x and Device ID: 0x%x\n",
+	   PCI_VENDOR_ID_FD, 
+	   PCI_DEVICE_ID_FD_36C70 );
+#endif 
+
+   if ((pdev = pci_find_device(PCI_VENDOR_ID_FD, PCI_DEVICE_ID_FD_36C70, pdev)) == NULL)
+		return 0;
+   if (pci_enable_device(pdev)) return 0;
+       
+#if DEBUG_DETECT
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+	   " PCI bus %u, device %u, function %u\n",
+	   pdev->bus->number,
+	   PCI_SLOT(pdev->devfn),
+	   PCI_FUNC(pdev->devfn));
+#endif
+
+   /* We now have the appropriate device function for the FD board so we
+      just read the PCI config info from the registers.  */
+
+   pci_base = pci_resource_start(pdev, 0);
+   pci_irq = pdev->irq;
+
+   if (!request_region( pci_base, 0x10, "fdomain" ))
+	return 0;
+
+   /* Now we have the I/O base address and interrupt from the PCI
+      configuration registers. */
+
+   *irq    = pci_irq;
+   *iobase = pci_base;
+   *ret_pdev = pdev;
+
+#if DEBUG_DETECT
+   printk( "scsi: <fdomain> TMC-3260 detect:"
+	   " IRQ = %d, I/O base = 0x%x [0x%lx]\n", *irq, *iobase, pci_base );
+#endif
+
+   if (!fdomain_is_valid_port(pci_base)) {
+      printk(KERN_ERR "scsi: <fdomain> PCI card detected, but driver not loaded (invalid port)\n" );
+      release_region(pci_base, 0x10);
+      return 0;
+   }
+
+				/* Fill in a few global variables.  Ugh. */
+   bios_major = bios_minor = -1;
+   PCI_bus    = 1;
+   Quantum    = 0;
+   bios_base  = 0;
+   
+   return 1;
+}
+#endif
+
+struct Scsi_Host *__fdomain_16x0_detect(struct scsi_host_template *tpnt )
+{
+   int              retcode;
+   struct Scsi_Host *shpnt;
+   struct pci_dev *pdev = NULL;
+
+   if (setup_called) {
+#if DEBUG_DETECT
+      printk( "scsi: <fdomain> No BIOS, using port_base = 0x%x, irq = %d\n",
+	      port_base, interrupt_level );
+#endif
+      if (!request_region(port_base, 0x10, "fdomain")) {
+	 printk( "scsi: <fdomain> port 0x%x is busy\n", port_base );
+	 printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+	 return NULL;
+      }
+      if (!fdomain_is_valid_port( port_base )) {
+	 printk( "scsi: <fdomain> Cannot locate chip at port base 0x%x\n",
+		 port_base );
+	 printk( "scsi: <fdomain> Bad LILO/INSMOD parameters?\n" );
+	 release_region(port_base, 0x10);
+	 return NULL;
+      }
+   } else {
+      int flag = 0;
+
+#ifdef CONFIG_PCI
+				/* Try PCI detection first */
+      flag = fdomain_pci_bios_detect( &interrupt_level, &port_base, &pdev );
+#endif
+      if (!flag) {
+				/* Then try ISA bus detection */
+	 flag = fdomain_isa_detect( &interrupt_level, &port_base );
+
+	 if (!flag) {
+	    printk( "scsi: <fdomain> Detection failed (no card)\n" );
+	    return NULL;
+	 }
+      }
+   }
+
+   fdomain_16x0_bus_reset(NULL);
+
+   if (fdomain_test_loopback()) {
+      printk(KERN_ERR  "scsi: <fdomain> Detection failed (loopback test failed at port base 0x%x)\n", port_base);
+      if (setup_called) {
+	 printk(KERN_ERR "scsi: <fdomain> Bad LILO/INSMOD parameters?\n");
+      }
+      release_region(port_base, 0x10);
+      return NULL;
+   }
+
+   if (this_id) {
+      tpnt->this_id = (this_id & 0x07);
+      adapter_mask  = (1 << tpnt->this_id);
+   } else {
+      if (PCI_bus || (bios_major == 3 && bios_minor >= 2) || bios_major < 0) {
+	 tpnt->this_id = 7;
+	 adapter_mask  = 0x80;
+      } else {
+	 tpnt->this_id = 6;
+	 adapter_mask  = 0x40;
+      }
+   }
+
+/* Print out a banner here in case we can't
+   get resources.  */
+
+   shpnt = scsi_register( tpnt, 0 );
+   if(shpnt == NULL) {
+	release_region(port_base, 0x10);
+   	return NULL;
+   }
+   shpnt->irq = interrupt_level;
+   shpnt->io_port = port_base;
+   scsi_set_device(shpnt, &pdev->dev);
+   shpnt->n_io_port = 0x10;
+   print_banner( shpnt );
+
+   /* Log IRQ with kernel */   
+   if (!interrupt_level) {
+      printk(KERN_ERR "scsi: <fdomain> Card Detected, but driver not loaded (no IRQ)\n" );
+      release_region(port_base, 0x10);
+      return NULL;
+   } else {
+      /* Register the IRQ with the kernel */
+
+      retcode = request_irq( interrupt_level,
+			     do_fdomain_16x0_intr, pdev?SA_SHIRQ:0, "fdomain", shpnt);
+
+      if (retcode < 0) {
+	 if (retcode == -EINVAL) {
+	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is bad!\n", interrupt_level );
+	    printk(KERN_ERR "                This shouldn't happen!\n" );
+	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
+	 } else if (retcode == -EBUSY) {
+	    printk(KERN_ERR "scsi: <fdomain> IRQ %d is already in use!\n", interrupt_level );
+	    printk(KERN_ERR "                Please use another IRQ!\n" );
+	 } else {
+	    printk(KERN_ERR "scsi: <fdomain> Error getting IRQ %d\n", interrupt_level );
+	    printk(KERN_ERR "                This shouldn't happen!\n" );
+	    printk(KERN_ERR "                Send mail to faith@acm.org\n" );
+	 }
+	 printk(KERN_ERR "scsi: <fdomain> Detected, but driver not loaded (IRQ)\n" );
+         release_region(port_base, 0x10);
+	 return NULL;
+      }
+   }
+   return shpnt;
+}
+
+static int fdomain_16x0_detect(struct scsi_host_template *tpnt)
+{
+	if (fdomain)
+		fdomain_setup(fdomain);
+	return (__fdomain_16x0_detect(tpnt) != NULL);
+}
+
+static const char *fdomain_16x0_info( struct Scsi_Host *ignore )
+{
+   static char buffer[128];
+   char        *pt;
+   
+   strcpy( buffer, "Future Domain 16-bit SCSI Driver Version" );
+   if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */
+      strcat( buffer, strchr( VERSION, ':' ) + 1 );
+      pt = strrchr( buffer, '$') - 1;
+      if (!pt)  		/* Stripped RCS Revision string? */
+	    pt = buffer + strlen( buffer ) - 1;
+      if (*pt != ' ')
+	    ++pt;
+      *pt = '\0';
+   } else {			/* Assume VERSION is a number */
+      strcat( buffer, " " VERSION );
+   }
+      
+   return buffer;
+}
+
+#if 0
+static int fdomain_arbitrate( void )
+{
+   int           status = 0;
+   unsigned long timeout;
+
+#if EVERY_ACCESS
+   printk( "fdomain_arbitrate()\n" );
+#endif
+   
+   outb(0x00, port_base + SCSI_Cntl);              /* Disable data drivers */
+   outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */
+   outb(0x04 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */
+
+   timeout = 500;
+   do {
+      status = inb(port_base + TMC_Status);        /* Read adapter status */
+      if (status & 0x02)		      /* Arbitration complete */
+	    return 0;
+      mdelay(1);			/* Wait one millisecond */
+   } while (--timeout);
+
+   /* Make bus idle */
+   fdomain_make_bus_idle();
+
+#if EVERY_ACCESS
+   printk( "Arbitration failed, status = %x\n", status );
+#endif
+#if ERRORS_ONLY
+   printk( "scsi: <fdomain> Arbitration failed, status = %x\n", status );
+#endif
+   return 1;
+}
+#endif
+
+static int fdomain_select( int target )
+{
+   int           status;
+   unsigned long timeout;
+#if ERRORS_ONLY
+   static int    flag = 0;
+#endif
+
+   outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */
+   outb(adapter_mask | (1 << target), port_base + SCSI_Data_NoACK);
+
+   /* Stop arbitration and enable parity */
+   outb(PARITY_MASK, port_base + TMC_Cntl); 
+
+   timeout = 350;			/* 350 msec */
+
+   do {
+      status = inb(port_base + SCSI_Status); /* Read adapter status */
+      if (status & 1) {			/* Busy asserted */
+	 /* Enable SCSI Bus (on error, should make bus idle with 0) */
+	 outb(0x80, port_base + SCSI_Cntl);
+	 return 0;
+      }
+      mdelay(1);			/* wait one msec */
+   } while (--timeout);
+   /* Make bus idle */
+   fdomain_make_bus_idle();
+#if EVERY_ACCESS
+   if (!target) printk( "Selection failed\n" );
+#endif
+#if ERRORS_ONLY
+   if (!target) {
+      if (!flag) /* Skip first failure for all chips. */
+	    ++flag;
+      else
+	    printk( "scsi: <fdomain> Selection failed\n" );
+   }
+#endif
+   return 1;
+}
+
+static void my_done(int error)
+{
+   if (in_command) {
+      in_command = 0;
+      outb(0x00, port_base + Interrupt_Cntl);
+      fdomain_make_bus_idle();
+      current_SC->result = error;
+      if (current_SC->scsi_done)
+	    current_SC->scsi_done( current_SC );
+      else panic( "scsi: <fdomain> current_SC->scsi_done() == NULL" );
+   } else {
+      panic( "scsi: <fdomain> my_done() called outside of command\n" );
+   }
+#if DEBUG_RACE
+   in_interrupt_flag = 0;
+#endif
+}
+
+static irqreturn_t do_fdomain_16x0_intr(int irq, void *dev_id,
+					struct pt_regs * regs )
+{
+   unsigned long flags;
+   int      status;
+   int      done = 0;
+   unsigned data_count;
+
+				/* The fdomain_16x0_intr is only called via
+				   the interrupt handler.  The goal of the
+				   sti() here is to allow other
+				   interruptions while this routine is
+				   running. */
+
+   /* Check for other IRQ sources */
+   if ((inb(port_base + TMC_Status) & 0x01) == 0)
+   	return IRQ_NONE;
+
+   /* It is our IRQ */   	
+   outb(0x00, port_base + Interrupt_Cntl);
+
+   /* We usually have one spurious interrupt after each command.  Ignore it. */
+   if (!in_command || !current_SC) {	/* Spurious interrupt */
+#if EVERY_ACCESS
+      printk( "Spurious interrupt, in_command = %d, current_SC = %x\n",
+	      in_command, current_SC );
+#endif
+      return IRQ_NONE;
+   }
+
+   /* Abort calls my_done, so we do nothing here. */
+   if (current_SC->SCp.phase & aborted) {
+#if DEBUG_ABORT
+      printk( "scsi: <fdomain> Interrupt after abort, ignoring\n" );
+#endif
+      /*
+      return IRQ_HANDLED; */
+   }
+
+#if DEBUG_RACE
+   ++in_interrupt_flag;
+#endif
+
+   if (current_SC->SCp.phase & in_arbitration) {
+      status = inb(port_base + TMC_Status);        /* Read adapter status */
+      if (!(status & 0x02)) {
+#if EVERY_ACCESS
+	 printk( " AFAIL " );
+#endif
+         spin_lock_irqsave(current_SC->device->host->host_lock, flags);
+	 my_done( DID_BUS_BUSY << 16 );
+         spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
+	 return IRQ_HANDLED;
+      }
+      current_SC->SCp.phase = in_selection;
+      
+      outb(0x40 | FIFO_COUNT, port_base + Interrupt_Cntl);
+
+      outb(0x82, port_base + SCSI_Cntl); /* Bus Enable + Select */
+      outb(adapter_mask | (1 << current_SC->device->id), port_base + SCSI_Data_NoACK);
+      
+      /* Stop arbitration and enable parity */
+      outb(0x10 | PARITY_MASK, port_base + TMC_Cntl);
+#if DEBUG_RACE
+      in_interrupt_flag = 0;
+#endif
+      return IRQ_HANDLED;
+   } else if (current_SC->SCp.phase & in_selection) {
+      status = inb(port_base + SCSI_Status);
+      if (!(status & 0x01)) {
+	 /* Try again, for slow devices */
+	 if (fdomain_select( current_SC->device->id )) {
+#if EVERY_ACCESS
+	    printk( " SFAIL " );
+#endif
+            spin_lock_irqsave(current_SC->device->host->host_lock, flags);
+	    my_done( DID_NO_CONNECT << 16 );
+            spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
+	    return IRQ_HANDLED;
+	 } else {
+#if EVERY_ACCESS
+	    printk( " AltSel " );
+#endif
+	    /* Stop arbitration and enable parity */
+	    outb(0x10 | PARITY_MASK, port_base + TMC_Cntl);
+	 }
+      }
+      current_SC->SCp.phase = in_other;
+      outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl);
+      outb(0x80, port_base + SCSI_Cntl);
+#if DEBUG_RACE
+      in_interrupt_flag = 0;
+#endif
+      return IRQ_HANDLED;
+   }
+   
+   /* current_SC->SCp.phase == in_other: this is the body of the routine */
+   
+   status = inb(port_base + SCSI_Status);
+   
+   if (status & 0x10) {	/* REQ */
+      
+      switch (status & 0x0e) {
+       
+      case 0x08:		/* COMMAND OUT */
+	 outb(current_SC->cmnd[current_SC->SCp.sent_command++],
+	      port_base + Write_SCSI_Data);
+#if EVERY_ACCESS
+	 printk( "CMD = %x,",
+		 current_SC->cmnd[ current_SC->SCp.sent_command - 1] );
+#endif
+	 break;
+      case 0x00:		/* DATA OUT -- tmc18c50/tmc18c30 only */
+	 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+	    current_SC->SCp.have_data_in = -1;
+	    outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl);
+	 }
+	 break;
+      case 0x04:		/* DATA IN -- tmc18c50/tmc18c30 only */
+	 if (chip != tmc1800 && !current_SC->SCp.have_data_in) {
+	    current_SC->SCp.have_data_in = 1;
+	    outb(0x90 | PARITY_MASK, port_base + TMC_Cntl);
+	 }
+	 break;
+      case 0x0c:		/* STATUS IN */
+	 current_SC->SCp.Status = inb(port_base + Read_SCSI_Data);
+#if EVERY_ACCESS
+	 printk( "Status = %x, ", current_SC->SCp.Status );
+#endif
+#if ERRORS_ONLY
+	 if (current_SC->SCp.Status
+	     && current_SC->SCp.Status != 2
+	     && current_SC->SCp.Status != 8) {
+	    printk( "scsi: <fdomain> target = %d, command = %x, status = %x\n",
+		    current_SC->device->id,
+		    current_SC->cmnd[0],
+		    current_SC->SCp.Status );
+	 }
+#endif
+	       break;
+      case 0x0a:		/* MESSAGE OUT */
+	 outb(MESSAGE_REJECT, port_base + Write_SCSI_Data); /* Reject */
+	 break;
+      case 0x0e:		/* MESSAGE IN */
+	 current_SC->SCp.Message = inb(port_base + Read_SCSI_Data);
+#if EVERY_ACCESS
+	 printk( "Message = %x, ", current_SC->SCp.Message );
+#endif
+	 if (!current_SC->SCp.Message) ++done;
+#if DEBUG_MESSAGES || EVERY_ACCESS
+	 if (current_SC->SCp.Message) {
+	    printk( "scsi: <fdomain> message = %x\n",
+		    current_SC->SCp.Message );
+	 }
+#endif
+	 break;
+      }
+   }
+
+   if (chip == tmc1800 && !current_SC->SCp.have_data_in
+       && (current_SC->SCp.sent_command >= current_SC->cmd_len)) {
+      
+      if(current_SC->sc_data_direction == DMA_TO_DEVICE)
+      {
+	 current_SC->SCp.have_data_in = -1;
+	 outb(0xd0 | PARITY_MASK, port_base + TMC_Cntl);
+      }
+      else
+      {
+	 current_SC->SCp.have_data_in = 1;
+	 outb(0x90 | PARITY_MASK, port_base + TMC_Cntl);
+      }
+   }
+
+   if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */
+      while ((data_count = FIFO_Size - inw(port_base + FIFO_Data_Count)) > 512) {
+#if EVERY_ACCESS
+	 printk( "DC=%d, ", data_count ) ;
+#endif
+	 if (data_count > current_SC->SCp.this_residual)
+	       data_count = current_SC->SCp.this_residual;
+	 if (data_count > 0) {
+#if EVERY_ACCESS
+	    printk( "%d OUT, ", data_count );
+#endif
+	    if (data_count == 1) {
+	       outb(*current_SC->SCp.ptr++, port_base + Write_FIFO);
+	       --current_SC->SCp.this_residual;
+	    } else {
+	       data_count >>= 1;
+	       outsw(port_base + Write_FIFO, current_SC->SCp.ptr, data_count);
+	       current_SC->SCp.ptr += 2 * data_count;
+	       current_SC->SCp.this_residual -= 2 * data_count;
+	    }
+	 }
+	 if (!current_SC->SCp.this_residual) {
+	    if (current_SC->SCp.buffers_residual) {
+	       --current_SC->SCp.buffers_residual;
+	       ++current_SC->SCp.buffer;
+	       current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+	       current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+	    } else
+		  break;
+	 }
+      }
+   }
+   
+   if (current_SC->SCp.have_data_in == 1) { /* DATA IN */
+      while ((data_count = inw(port_base + FIFO_Data_Count)) > 0) {
+#if EVERY_ACCESS
+	 printk( "DC=%d, ", data_count );
+#endif
+	 if (data_count > current_SC->SCp.this_residual)
+	       data_count = current_SC->SCp.this_residual;
+	 if (data_count) {
+#if EVERY_ACCESS
+	    printk( "%d IN, ", data_count );
+#endif
+	    if (data_count == 1) {
+	       *current_SC->SCp.ptr++ = inb(port_base + Read_FIFO);
+	       --current_SC->SCp.this_residual;
+	    } else {
+	       data_count >>= 1; /* Number of words */
+	       insw(port_base + Read_FIFO, current_SC->SCp.ptr, data_count);
+	       current_SC->SCp.ptr += 2 * data_count;
+	       current_SC->SCp.this_residual -= 2 * data_count;
+	    }
+	 }
+	 if (!current_SC->SCp.this_residual
+	     && current_SC->SCp.buffers_residual) {
+	    --current_SC->SCp.buffers_residual;
+	    ++current_SC->SCp.buffer;
+	    current_SC->SCp.ptr = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+	    current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+	 }
+      }
+   }
+   
+   if (done) {
+#if EVERY_ACCESS
+      printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in );
+#endif
+
+#if ERRORS_ONLY
+      if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) {
+	 if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) {
+	    unsigned char key;
+	    unsigned char code;
+	    unsigned char qualifier;
+
+	    key = (unsigned char)(*((char *)current_SC->request_buffer + 2))
+		  & 0x0f;
+	    code = (unsigned char)(*((char *)current_SC->request_buffer + 12));
+	    qualifier = (unsigned char)(*((char *)current_SC->request_buffer
+					  + 13));
+
+	    if (key != UNIT_ATTENTION
+		&& !(key == NOT_READY
+		     && code == 0x04
+		     && (!qualifier || qualifier == 0x02 || qualifier == 0x01))
+		&& !(key == ILLEGAL_REQUEST && (code == 0x25
+						|| code == 0x24
+						|| !code)))
+		  
+		  printk( "scsi: <fdomain> REQUEST SENSE"
+			  " Key = %x, Code = %x, Qualifier = %x\n",
+			  key, code, qualifier );
+	 }
+      }
+#endif
+#if EVERY_ACCESS
+      printk( "BEFORE MY_DONE. . ." );
+#endif
+      spin_lock_irqsave(current_SC->device->host->host_lock, flags);
+      my_done( (current_SC->SCp.Status & 0xff)
+	       | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) );
+      spin_unlock_irqrestore(current_SC->device->host->host_lock, flags);
+#if EVERY_ACCESS
+      printk( "RETURNING.\n" );
+#endif
+      
+   } else {
+      if (current_SC->SCp.phase & disconnect) {
+	 outb(0xd0 | FIFO_COUNT, port_base + Interrupt_Cntl);
+	 outb(0x00, port_base + SCSI_Cntl);
+      } else {
+	 outb(0x90 | FIFO_COUNT, port_base + Interrupt_Cntl);
+      }
+   }
+#if DEBUG_RACE
+   in_interrupt_flag = 0;
+#endif
+   return IRQ_HANDLED;
+}
+
+static int fdomain_16x0_queue(struct scsi_cmnd *SCpnt,
+		void (*done)(struct scsi_cmnd *))
+{
+   if (in_command) {
+      panic( "scsi: <fdomain> fdomain_16x0_queue() NOT REENTRANT!\n" );
+   }
+#if EVERY_ACCESS
+   printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+	   SCpnt->target,
+	   *(unsigned char *)SCpnt->cmnd,
+	   SCpnt->use_sg,
+	   SCpnt->request_bufflen );
+#endif
+
+   fdomain_make_bus_idle();
+
+   current_SC            = SCpnt; /* Save this for the done function */
+   current_SC->scsi_done = done;
+
+   /* Initialize static data */
+
+   if (current_SC->use_sg) {
+      current_SC->SCp.buffer =
+	    (struct scatterlist *)current_SC->request_buffer;
+      current_SC->SCp.ptr              = page_address(current_SC->SCp.buffer->page) + current_SC->SCp.buffer->offset;
+      current_SC->SCp.this_residual    = current_SC->SCp.buffer->length;
+      current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+   } else {
+      current_SC->SCp.ptr              = (char *)current_SC->request_buffer;
+      current_SC->SCp.this_residual    = current_SC->request_bufflen;
+      current_SC->SCp.buffer           = NULL;
+      current_SC->SCp.buffers_residual = 0;
+   }
+	 
+   
+   current_SC->SCp.Status              = 0;
+   current_SC->SCp.Message             = 0;
+   current_SC->SCp.have_data_in        = 0;
+   current_SC->SCp.sent_command        = 0;
+   current_SC->SCp.phase               = in_arbitration;
+
+   /* Start arbitration */
+   outb(0x00, port_base + Interrupt_Cntl);
+   outb(0x00, port_base + SCSI_Cntl);              /* Disable data drivers */
+   outb(adapter_mask, port_base + SCSI_Data_NoACK); /* Set our id bit */
+   ++in_command;
+   outb(0x20, port_base + Interrupt_Cntl);
+   outb(0x14 | PARITY_MASK, port_base + TMC_Cntl); /* Start arbitration */
+
+   return 0;
+}
+
+#if DEBUG_ABORT
+static void print_info(struct scsi_cmnd *SCpnt)
+{
+   unsigned int imr;
+   unsigned int irr;
+   unsigned int isr;
+
+   if (!SCpnt || !SCpnt->device || !SCpnt->device->host) {
+      printk(KERN_WARNING "scsi: <fdomain> Cannot provide detailed information\n");
+      return;
+   }
+   
+   printk(KERN_INFO "%s\n", fdomain_16x0_info( SCpnt->device->host ) );
+   print_banner(SCpnt->device->host);
+   switch (SCpnt->SCp.phase) {
+   case in_arbitration: printk("arbitration"); break;
+   case in_selection:   printk("selection");   break;
+   case in_other:       printk("other");       break;
+   default:             printk("unknown");     break;
+   }
+
+   printk( " (%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n",
+	   SCpnt->SCp.phase,
+	   SCpnt->device->id,
+	   *(unsigned char *)SCpnt->cmnd,
+	   SCpnt->use_sg,
+	   SCpnt->request_bufflen );
+   printk( "sent_command = %d, have_data_in = %d, timeout = %d\n",
+	   SCpnt->SCp.sent_command,
+	   SCpnt->SCp.have_data_in,
+	   SCpnt->timeout );
+#if DEBUG_RACE
+   printk( "in_interrupt_flag = %d\n", in_interrupt_flag );
+#endif
+
+   imr = (inb( 0x0a1 ) << 8) + inb( 0x21 );
+   outb( 0x0a, 0xa0 );
+   irr = inb( 0xa0 ) << 8;
+   outb( 0x0a, 0x20 );
+   irr += inb( 0x20 );
+   outb( 0x0b, 0xa0 );
+   isr = inb( 0xa0 ) << 8;
+   outb( 0x0b, 0x20 );
+   isr += inb( 0x20 );
+
+				/* Print out interesting information */
+   printk( "IMR = 0x%04x", imr );
+   if (imr & (1 << interrupt_level))
+	 printk( " (masked)" );
+   printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr );
+
+   printk( "SCSI Status      = 0x%02x\n", inb(port_base + SCSI_Status));
+   printk( "TMC Status       = 0x%02x", inb(port_base + TMC_Status));
+   if (inb((port_base + TMC_Status) & 1))
+	 printk( " (interrupt)" );
+   printk( "\n" );
+   printk("Interrupt Status = 0x%02x", inb(port_base + Interrupt_Status));
+   if (inb(port_base + Interrupt_Status) & 0x08)
+	 printk( " (enabled)" );
+   printk( "\n" );
+   if (chip == tmc18c50 || chip == tmc18c30) {
+      printk("FIFO Status      = 0x%02x\n", inb(port_base + FIFO_Status));
+      printk( "Int. Condition   = 0x%02x\n",
+	      inb( port_base + Interrupt_Cond ) );
+   }
+   printk( "Configuration 1  = 0x%02x\n", inb( port_base + Configuration1 ) );
+   if (chip == tmc18c50 || chip == tmc18c30)
+	 printk( "Configuration 2  = 0x%02x\n",
+		 inb( port_base + Configuration2 ) );
+}
+#endif
+
+static int fdomain_16x0_abort(struct scsi_cmnd *SCpnt)
+{
+#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT
+   printk( "scsi: <fdomain> abort " );
+#endif
+
+   if (!in_command) {
+#if EVERY_ACCESS || ERRORS_ONLY
+      printk( " (not in command)\n" );
+#endif
+      return FAILED;
+   } else printk( "\n" );
+
+#if DEBUG_ABORT
+   print_info( SCpnt );
+#endif
+
+   fdomain_make_bus_idle();
+   current_SC->SCp.phase |= aborted;
+   current_SC->result = DID_ABORT << 16;
+   
+   /* Aborts are not done well. . . */
+   my_done(DID_ABORT << 16);
+   return SUCCESS;
+}
+
+int fdomain_16x0_bus_reset(struct scsi_cmnd *SCpnt)
+{
+   outb(1, port_base + SCSI_Cntl);
+   do_pause( 2 );
+   outb(0, port_base + SCSI_Cntl);
+   do_pause( 115 );
+   outb(0, port_base + SCSI_Mode_Cntl);
+   outb(PARITY_MASK, port_base + TMC_Cntl);
+   return SUCCESS;
+}
+
+static int fdomain_16x0_biosparam(struct scsi_device *sdev,
+		struct block_device *bdev,
+		sector_t capacity, int *info_array)
+{
+   int              drive;
+   int		    size      = capacity;
+   unsigned long    offset;
+   struct drive_info {
+      unsigned short cylinders;
+      unsigned char  heads;
+      unsigned char  sectors;
+   } i;
+   
+   /* NOTES:
+      The RAM area starts at 0x1f00 from the bios_base address.
+
+      For BIOS Version 2.0:
+      
+      The drive parameter table seems to start at 0x1f30.
+      The first byte's purpose is not known.
+      Next is the cylinder, head, and sector information.
+      The last 4 bytes appear to be the drive's size in sectors.
+      The other bytes in the drive parameter table are unknown.
+      If anyone figures them out, please send me mail, and I will
+      update these notes.
+
+      Tape drives do not get placed in this table.
+
+      There is another table at 0x1fea:
+      If the byte is 0x01, then the SCSI ID is not in use.
+      If the byte is 0x18 or 0x48, then the SCSI ID is in use,
+      although tapes don't seem to be in this table.  I haven't
+      seen any other numbers (in a limited sample).
+
+      0x1f2d is a drive count (i.e., not including tapes)
+
+      The table at 0x1fcc are I/O ports addresses for the various
+      operations.  I calculate these by hand in this driver code.
+
+      
+      
+      For the ISA-200S version of BIOS Version 2.0:
+
+      The drive parameter table starts at 0x1f33.
+
+      WARNING: Assume that the table entry is 25 bytes long.  Someone needs
+      to check this for the Quantum ISA-200S card.
+
+      
+      
+      For BIOS Version 3.2:
+
+      The drive parameter table starts at 0x1f70.  Each entry is
+      0x0a bytes long.  Heads are one less than we need to report.
+    */
+
+   if (MAJOR(bdev->bd_dev) != SCSI_DISK0_MAJOR) {
+      printk("scsi: <fdomain> fdomain_16x0_biosparam: too many disks");
+      return 0;
+   }
+   drive = MINOR(bdev->bd_dev) >> 4;
+
+   if (bios_major == 2) {
+      switch (Quantum) {
+      case 2:			/* ISA_200S */
+				/* The value of 25 has never been verified.
+				   It should probably be 15. */
+	 offset = 0x1f33 + drive * 25;
+	 break;
+      case 3:			/* ISA_250MG */
+	 offset = 0x1f36 + drive * 15;
+	 break;
+      case 4:			/* ISA_200S (another one) */
+	 offset = 0x1f34 + drive * 15;
+	 break;
+      default:
+	 offset = 0x1f31 + drive * 25;
+	 break;
+      }
+      memcpy_fromio( &i, bios_mem + offset, sizeof( struct drive_info ) );
+      info_array[0] = i.heads;
+      info_array[1] = i.sectors;
+      info_array[2] = i.cylinders;
+   } else if (bios_major == 3
+	      && bios_minor >= 0
+	      && bios_minor < 4) { /* 3.0 and 3.2 BIOS */
+      memcpy_fromio( &i, bios_mem + 0x1f71 + drive * 10,
+		     sizeof( struct drive_info ) );
+      info_array[0] = i.heads + 1;
+      info_array[1] = i.sectors;
+      info_array[2] = i.cylinders;
+   } else {			/* 3.4 BIOS (and up?) */
+      /* This algorithm was provided by Future Domain (much thanks!). */
+      unsigned char *p = scsi_bios_ptable(bdev);
+
+      if (p && p[65] == 0xaa && p[64] == 0x55 /* Partition table valid */
+	  && p[4]) {			    /* Partition type */
+
+	 /* The partition table layout is as follows:
+
+	    Start: 0x1b3h
+	    Offset: 0 = partition status
+		    1 = starting head
+		    2 = starting sector and cylinder (word, encoded)
+		    4 = partition type
+		    5 = ending head
+		    6 = ending sector and cylinder (word, encoded)
+		    8 = starting absolute sector (double word)
+		    c = number of sectors (double word)
+	    Signature: 0x1fe = 0x55aa
+
+	    So, this algorithm assumes:
+	    1) the first partition table is in use,
+	    2) the data in the first entry is correct, and
+	    3) partitions never divide cylinders
+
+	    Note that (1) may be FALSE for NetBSD (and other BSD flavors),
+	    as well as for Linux.  Note also, that Linux doesn't pay any
+	    attention to the fields that are used by this algorithm -- it
+	    only uses the absolute sector data.  Recent versions of Linux's
+	    fdisk(1) will fill this data in correctly, and forthcoming
+	    versions will check for consistency.
+
+	    Checking for a non-zero partition type is not part of the
+	    Future Domain algorithm, but it seemed to be a reasonable thing
+	    to do, especially in the Linux and BSD worlds. */
+
+	 info_array[0] = p[5] + 1;	    /* heads */
+	 info_array[1] = p[6] & 0x3f;	    /* sectors */
+      } else {
+
+ 	 /* Note that this new method guarantees that there will always be
+	    less than 1024 cylinders on a platter.  This is good for drives
+	    up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+
+	 if ((unsigned int)size >= 0x7e0000U) {
+	    info_array[0] = 0xff; /* heads   = 255 */
+	    info_array[1] = 0x3f; /* sectors =  63 */
+	 } else if ((unsigned int)size >= 0x200000U) {
+	    info_array[0] = 0x80; /* heads   = 128 */
+	    info_array[1] = 0x3f; /* sectors =  63 */
+	 } else {
+	    info_array[0] = 0x40; /* heads   =  64 */
+	    info_array[1] = 0x20; /* sectors =  32 */
+	 }
+      }
+				/* For both methods, compute the cylinders */
+      info_array[2] = (unsigned int)size / (info_array[0] * info_array[1] );
+      kfree(p);
+   }
+   
+   return 0;
+}
+
+static int fdomain_16x0_release(struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq)
+		free_irq(shpnt->irq, shpnt);
+	if (shpnt->io_port && shpnt->n_io_port)
+		release_region(shpnt->io_port, shpnt->n_io_port);
+	return 0;
+}
+
+struct scsi_host_template fdomain_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "fdomain",
+	.proc_name		= "fdomain",
+	.detect			= fdomain_16x0_detect,
+	.info			= fdomain_16x0_info,
+	.queuecommand		= fdomain_16x0_queue,
+	.eh_abort_handler	= fdomain_16x0_abort,
+	.eh_bus_reset_handler	= fdomain_16x0_bus_reset,
+	.bios_param		= fdomain_16x0_biosparam,
+	.release		= fdomain_16x0_release,
+	.can_queue		= 1,
+	.this_id		= 6,
+	.sg_tablesize		= 64,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+#ifndef PCMCIA
+#define driver_template fdomain_driver_template
+#include "scsi_module.c"
+#endif
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
new file mode 100644
index 0000000..47021d9
--- /dev/null
+++ b/drivers/scsi/fdomain.h
@@ -0,0 +1,24 @@
+/*
+ * fdomain.c -- Future Domain TMC-16x0 SCSI driver
+ * Author: Rickard E. Faith, faith@cs.unc.edu
+ * Copyright 1992-1996, 1998 Rickard E. Faith (faith@acm.org)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+extern struct scsi_host_template fdomain_driver_template;
+extern int fdomain_setup(char *str);
+extern struct Scsi_Host *__fdomain_16x0_detect(struct  scsi_host_template *tpnt );
+extern int fdomain_16x0_bus_reset(struct scsi_cmnd *SCpnt);
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
new file mode 100644
index 0000000..ca9d5bd
--- /dev/null
+++ b/drivers/scsi/g_NCR5380.c
@@ -0,0 +1,947 @@
+/*
+ * Generic Generic NCR5380 driver
+ *	
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
+ *    K.Lentin@cs.monash.edu.au
+ *
+ * NCR53C400A extensions (c) 1996, Ingmar Baumgart
+ *    ingmar@gonzo.schwaben.de
+ *
+ * DTC3181E extensions (c) 1997, Ronald van Cuijlenborg
+ * ronald.van.cuijlenborg@tip.nl or nutty@dds.nl
+ *
+ * Added ISAPNP support for DTC436 adapters,
+ * Thomas Sailer, sailer@ife.ee.ethz.ch
+ *
+ * ALPHA RELEASE 1. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/* 
+ * TODO : flesh out DMA support, find some one actually using this (I have
+ * 	a memory mapped Trantor board that works fine)
+ */
+
+/*
+ * Options :
+ *
+ * PARITY - enable parity checking.  Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
+ *
+ * USLEEP - enable support for devices that don't disconnect.  Untested.
+ *
+ * The card is detected and initialized in one of several ways : 
+ * 1.  With command line overrides - NCR5380=port,irq may be 
+ *     used on the LILO command line to override the defaults.
+ *
+ * 2.  With the GENERIC_NCR5380_OVERRIDE compile time define.  This is 
+ *     specified as an array of address, irq, dma, board tuples.  Ie, for
+ *     one board at 0x350, IRQ5, no dma, I could say  
+ *     -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE, BOARD_NCR5380}}
+ * 
+ * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an 
+ * 	IRQ line if overridden on the command line.
+ *
+ * 3.  When included as a module, with arguments passed on the command line:
+ *         ncr_irq=xx	the interrupt
+ *         ncr_addr=xx  the port or base address (for port or memory
+ *              	mapped, resp.)
+ *         ncr_dma=xx	the DMA
+ *         ncr_5380=1	to set up for a NCR5380 board
+ *         ncr_53c400=1	to set up for a NCR53C400 board
+ *     e.g.
+ *     modprobe g_NCR5380 ncr_irq=5 ncr_addr=0x350 ncr_5380=1
+ *       for a port mapped NCR5380 board or
+ *     modprobe g_NCR5380 ncr_irq=255 ncr_addr=0xc8000 ncr_53c400=1
+ *       for a memory mapped NCR53C400 board with interrupts disabled.
+ * 
+ * 255 should be specified for no or DMA interrupt, 254 to autoprobe for an 
+ * 	IRQ line if overridden on the command line.
+ *     
+ */
+
+/*
+ * $Log: generic_NCR5380.c,v $
+ */
+
+/* settings for DTC3181E card with only Mustek scanner attached */
+#define USLEEP
+#define USLEEP_POLL	1
+#define USLEEP_SLEEP	20
+#define USLEEP_WAITLONG	500
+
+#define AUTOPROBE_IRQ
+#define AUTOSENSE
+
+#include <linux/config.h>
+
+#ifdef CONFIG_SCSI_GENERIC_NCR53C400
+#define NCR53C400_PSEUDO_DMA 1
+#define PSEUDO_DMA
+#define NCR53C400
+#define NCR5380_STATS
+#undef NCR5380_STAT_LIMIT
+#endif
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/blkdev.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "g_NCR5380.h"
+#include "NCR5380.h"
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/isapnp.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#define NCR_NOT_SET 0
+static int ncr_irq = NCR_NOT_SET;
+static int ncr_dma = NCR_NOT_SET;
+static int ncr_addr = NCR_NOT_SET;
+static int ncr_5380 = NCR_NOT_SET;
+static int ncr_53c400 = NCR_NOT_SET;
+static int ncr_53c400a = NCR_NOT_SET;
+static int dtc_3181e = NCR_NOT_SET;
+
+static struct override {
+	NCR5380_implementation_fields;
+	int irq;
+	int dma;
+	int board;		/* Use NCR53c400, Ricoh, etc. extensions ? */
+} overrides
+#ifdef GENERIC_NCR5380_OVERRIDE
+[] __initdata = GENERIC_NCR5380_OVERRIDE;
+#else
+[1] __initdata = { { 0,},};
+#endif
+
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+#ifndef MODULE 
+
+/**
+ *	internal_setup		-	handle lilo command string override
+ *	@board:	BOARD_* identifier for the board
+ *	@str: unused
+ *	@ints: numeric parameters
+ *
+ * 	Do LILO command line initialization of the overrides array. Display
+ *	errors when needed
+ *
+ *	Locks: none
+ */
+
+static void __init internal_setup(int board, char *str, int *ints)
+{
+	static int commandline_current = 0;
+	switch (board) {
+	case BOARD_NCR5380:
+		if (ints[0] != 2 && ints[0] != 3) {
+			printk(KERN_ERR "generic_NCR5380_setup : usage ncr5380=" STRVAL(NCR5380_map_name) ",irq,dma\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400_setup : usage ncr53c400=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_NCR53C400A:
+		if (ints[0] != 2) {
+			printk(KERN_ERR "generic_NCR53C400A_setup : usage ncr53c400a=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	case BOARD_DTC3181E:
+		if (ints[0] != 2) {
+			printk("generic_DTC3181E_setup : usage dtc3181e=" STRVAL(NCR5380_map_name) ",irq\n");
+			return;
+		}
+		break;
+	}
+
+	if (commandline_current < NO_OVERRIDES) {
+		overrides[commandline_current].NCR5380_map_name = (NCR5380_map_type) ints[1];
+		overrides[commandline_current].irq = ints[2];
+		if (ints[0] == 3)
+			overrides[commandline_current].dma = ints[3];
+		else
+			overrides[commandline_current].dma = DMA_NONE;
+		overrides[commandline_current].board = board;
+		++commandline_current;
+	}
+}
+
+
+/**
+ * 	do_NCR53C80_setup		-	set up entry point
+ *	@str: unused
+ *
+ *	Setup function invoked at boot to parse the ncr5380= command
+ *	line.
+ */
+
+static int __init do_NCR5380_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR5380, str, ints);
+	return 1;
+}
+
+/**
+ * 	do_NCR53C400_setup		-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
+ *
+ *	Setup function invoked at boot to parse the ncr53c400= command
+ *	line.
+ */
+
+static int __init do_NCR53C400_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400, str, ints);
+	return 1;
+}
+
+/**
+ * 	do_NCR53C400A_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
+ *
+ *	Setup function invoked at boot to parse the ncr53c400a= command
+ *	line.
+ */
+
+static int __init do_NCR53C400A_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_NCR53C400A, str, ints);
+	return 1;
+}
+
+/**
+ * 	do_DTC3181E_setup	-	set up entry point
+ *	@str: unused
+ *	@ints: integer parameters from kernel setup code 
+ *
+ *	Setup function invoked at boot to parse the dtc3181e= command
+ *	line.
+ */
+
+static int __init do_DTC3181E_setup(char *str)
+{
+	int ints[10];
+
+	get_options(str, sizeof(ints) / sizeof(int), ints);
+	internal_setup(BOARD_DTC3181E, str, ints);
+	return 1;
+}
+
+#endif
+
+/**
+ * 	generic_NCR5380_detect	-	look for NCR5380 controllers
+ *	@tpnt: the scsi template
+ *
+ *	Scan for the present of NCR5380, NCR53C400, NCR53C400A, DTC3181E
+ *	and DTC436(ISAPnP) controllers. If overrides have been set we use
+ *	them.
+ *
+ *	The caller supplied NCR5380_init function is invoked from here, before
+ *	the interrupt line is taken.
+ *
+ *	Locks: none
+ */
+
+int __init generic_NCR5380_detect(Scsi_Host_Template * tpnt)
+{
+	static int current_override = 0;
+	int count, i;
+	unsigned int *ports;
+	unsigned long region_size = 16;
+	static unsigned int __initdata ncr_53c400a_ports[] = {
+		0x280, 0x290, 0x300, 0x310, 0x330, 0x340, 0x348, 0x350, 0
+	};
+	static unsigned int __initdata dtc_3181e_ports[] = {
+		0x220, 0x240, 0x280, 0x2a0, 0x2c0, 0x300, 0x320, 0x340, 0
+	};
+	int flags = 0;
+	struct Scsi_Host *instance;
+
+	if (ncr_irq != NCR_NOT_SET)
+		overrides[0].irq = ncr_irq;
+	if (ncr_dma != NCR_NOT_SET)
+		overrides[0].dma = ncr_dma;
+	if (ncr_addr != NCR_NOT_SET)
+		overrides[0].NCR5380_map_name = (NCR5380_map_type) ncr_addr;
+	if (ncr_5380 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR5380;
+	else if (ncr_53c400 != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400;
+	else if (ncr_53c400a != NCR_NOT_SET)
+		overrides[0].board = BOARD_NCR53C400A;
+	else if (dtc_3181e != NCR_NOT_SET)
+		overrides[0].board = BOARD_DTC3181E;
+
+	if (!current_override && isapnp_present()) {
+		struct pnp_dev *dev = NULL;
+		count = 0;
+		while ((dev = pnp_find_dev(NULL, ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e), dev))) {
+			if (count >= NO_OVERRIDES)
+				break;
+			if (pnp_device_attach(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: attach failed\n");
+				continue;
+			}
+			if (pnp_activate_dev(dev) < 0) {
+				printk(KERN_ERR "dtc436e probe: activate failed\n");
+				pnp_device_detach(dev);
+				continue;
+			}
+			if (!pnp_port_valid(dev, 0)) {
+				printk(KERN_ERR "dtc436e probe: no valid port\n");
+				pnp_device_detach(dev);
+				continue;
+			}
+			if (pnp_irq_valid(dev, 0))
+				overrides[count].irq = pnp_irq(dev, 0);
+			else
+				overrides[count].irq = SCSI_IRQ_NONE;
+			if (pnp_dma_valid(dev, 0))
+				overrides[count].dma = pnp_dma(dev, 0);
+			else
+				overrides[count].dma = DMA_NONE;
+			overrides[count].NCR5380_map_name = (NCR5380_map_type) pnp_port_start(dev, 0);
+			overrides[count].board = BOARD_DTC3181E;
+			count++;
+		}
+	}
+
+	tpnt->proc_name = "g_NCR5380";
+
+	for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+		if (!(overrides[current_override].NCR5380_map_name))
+			continue;
+
+		ports = NULL;
+		switch (overrides[current_override].board) {
+		case BOARD_NCR5380:
+			flags = FLAG_NO_PSEUDO_DMA;
+			break;
+		case BOARD_NCR53C400:
+			flags = FLAG_NCR53C400;
+			break;
+		case BOARD_NCR53C400A:
+			flags = FLAG_NO_PSEUDO_DMA;
+			ports = ncr_53c400a_ports;
+			break;
+		case BOARD_DTC3181E:
+			flags = FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E;
+			ports = dtc_3181e_ports;
+			break;
+		}
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		if (ports) {
+			/* wakeup sequence for the NCR53C400A and DTC3181E */
+
+			/* Disable the adapter and look for a free io port */
+			outb(0x59, 0x779);
+			outb(0xb9, 0x379);
+			outb(0xc5, 0x379);
+			outb(0xae, 0x379);
+			outb(0xa6, 0x379);
+			outb(0x00, 0x379);
+
+			if (overrides[current_override].NCR5380_map_name != PORT_AUTO)
+				for (i = 0; ports[i]; i++) {
+					if (!request_region(ports[i],  16, "ncr53c80"))
+						continue;
+					if (overrides[current_override].NCR5380_map_name == ports[i])
+						break;
+					release_region(ports[i], 16);
+			} else
+				for (i = 0; ports[i]; i++) {
+					if (!request_region(ports[i],  16, "ncr53c80"))
+						continue;
+					if (inb(ports[i]) == 0xff)
+						break;
+					release_region(ports[i], 16);
+				}
+			if (ports[i]) {
+				/* At this point we have our region reserved */
+				outb(0x59, 0x779);
+				outb(0xb9, 0x379);
+				outb(0xc5, 0x379);
+				outb(0xae, 0x379);
+				outb(0xa6, 0x379);
+				outb(0x80 | i, 0x379);	/* set io port to be used */
+				outb(0xc0, ports[i] + 9);
+				if (inb(ports[i] + 9) != 0x80)
+					continue;
+				else
+					overrides[current_override].NCR5380_map_name = ports[i];
+			} else
+				continue;
+		}
+		else
+		{
+			/* Not a 53C400A style setup - just grab */
+			if(!(request_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380")))
+				continue;
+			region_size = NCR5380_region_size;
+		}
+#else
+		if(!request_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size, "ncr5380"))
+			continue;
+#endif
+		instance = scsi_register(tpnt, sizeof(struct NCR5380_hostdata));
+		if (instance == NULL) {
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+			release_region(overrides[current_override].NCR5380_map_name, region_size);
+#else
+			release_mem_region(overrides[current_override].NCR5380_map_name, NCR5380_region_size);
+#endif
+			continue;
+		}
+
+		instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		instance->n_io_port = region_size;
+#endif
+
+		NCR5380_init(instance, flags);
+
+		if (overrides[current_override].irq != IRQ_AUTO)
+			instance->irq = overrides[current_override].irq;
+		else
+			instance->irq = NCR5380_probe_irq(instance, 0xffff);
+
+		if (instance->irq != SCSI_IRQ_NONE)
+			if (request_irq(instance->irq, generic_NCR5380_intr, SA_INTERRUPT, "NCR5380", instance)) {
+				printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
+				instance->irq = SCSI_IRQ_NONE;
+			}
+
+		if (instance->irq == SCSI_IRQ_NONE) {
+			printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+			printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+		}
+
+		printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
+		if (instance->irq == SCSI_IRQ_NONE)
+			printk(" interrupts disabled");
+		else
+			printk(" irq %d", instance->irq);
+		printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
+		NCR5380_print_options(instance);
+		printk("\n");
+
+		++current_override;
+		++count;
+	}
+	return count;
+}
+
+/**
+ *	generic_NCR5380_info	-	reporting string
+ *	@host: NCR5380 to report on
+ *
+ *	Report driver information for the NCR5380
+ */
+ 	
+const char *generic_NCR5380_info(struct Scsi_Host *host)
+{
+	static const char string[] = "Generic NCR5380/53C400 Driver";
+	return string;
+}
+
+/**
+ *	generic_NCR5380_release_resources	-	free resources
+ *	@instance: host adapter to clean up 
+ *
+ *	Free the generic interface resources from this adapter.
+ *
+ *	Locks: none
+ */
+ 
+int generic_NCR5380_release_resources(struct Scsi_Host *instance)
+{
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+	
+	if (instance->irq != SCSI_IRQ_NONE)
+		free_irq(instance->irq, NULL);
+	NCR5380_exit(instance);
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+	release_region(instance->NCR5380_instance_name, instance->n_io_port);
+#else
+	release_mem_region(instance->NCR5380_instance_name, NCR5380_region_size);
+#endif
+
+
+	return 0;
+}
+
+#ifdef BIOSPARAM
+/**
+ *	generic_NCR5380_biosparam
+ *	@disk: disk to compute geometry for
+ *	@dev: device identifier for this disk
+ *	@ip: sizes to fill in
+ *
+ *	Generates a BIOS / DOS compatible H-C-S mapping for the specified 
+ *	device / size.
+ * 
+ * 	XXX Most SCSI boards use this mapping, I could be incorrect.  Someone
+ *	using hard disks on a trantor should verify that this mapping
+ *	corresponds to that used by the BIOS / ASPI driver by running the linux
+ *	fdisk program and matching the H_C_S coordinates to what DOS uses.
+ *
+ *	Locks: none
+ */
+
+static int
+generic_NCR5380_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+			  sector_t capacity, int *ip)
+{
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = capacity >> 11;
+	return 0;
+}
+#endif
+
+#if NCR53C400_PSEUDO_DMA
+
+/**
+ *	NCR5380_pread		-	pseudo DMA read
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
+ 
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE | CSR_TRANS_DIR);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400r: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY);
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		{
+			int i;
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
+#else
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
+#endif
+		start += 128;
+		blocks--;
+	}
+
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+		{
+			// FIXME - no timeout
+		}
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		{
+			int i;	
+			for (i = 0; i < 128; i++)
+				dst[start + i] = NCR5380_read(C400_HOST_BUFFER);
+		}
+#else
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_fromio(dst + start, NCR53C400_host_buffer + NCR5380_map_name, 128);
+#endif
+		start += 128;
+		blocks--;
+	}
+
+	if (!(NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		printk("53C400r: no 53C80 gated irq after transfer");
+
+#if 0
+	/*
+	 *	DON'T DO THIS - THEY NEVER ARRIVE!
+	 */
+	printk("53C400r: Waiting for 53C80 registers\n");
+	while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG)
+		;
+#endif
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER))
+		printk(KERN_ERR "53C400r: no end dma signal\n");
+		
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	return 0;
+}
+
+/**
+ *	NCR5380_write		-	pseudo DMA write
+ *	@instance: adapter to read from
+ *	@dst: buffer to read into
+ *	@len: buffer length
+ *
+ *	Perform a psuedo DMA mode read from an NCR53C400 or equivalent
+ *	controller
+ */
+
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
+{
+	int blocks = len / 128;
+	int start = 0;
+	int bl;
+	int i;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+
+	NCR5380_write(C400_CONTROL_STATUS_REG, CSR_BASE);
+	NCR5380_write(C400_BLOCK_COUNTER_REG, blocks);
+	while (1) {
+		if (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ) {
+			printk(KERN_ERR "53C400w: Got 53C80_IRQ start=%d, blocks=%d\n", start, blocks);
+			return -1;
+		}
+
+		if ((bl = NCR5380_read(C400_BLOCK_COUNTER_REG)) == 0) {
+			break;
+		}
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - timeout
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
+#else
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
+#endif
+		start += 128;
+		blocks--;
+	}
+	if (blocks) {
+		while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_HOST_BUF_NOT_RDY)
+			; // FIXME - no timeout
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+		{
+			for (i = 0; i < 128; i++)
+				NCR5380_write(C400_HOST_BUFFER, src[start + i]);
+		}
+#else
+		/* implies CONFIG_SCSI_G_NCR5380_MEM */
+		isa_memcpy_toio(NCR53C400_host_buffer + NCR5380_map_name, src + start, 128);
+#endif
+		start += 128;
+		blocks--;
+	}
+
+#if 0
+	printk("53C400w: waiting for registers to be available\n");
+	THEY NEVER DO ! while (NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_53C80_REG);
+	printk("53C400w: Got em\n");
+#endif
+
+	/* Let's wait for this instead - could be ugly */
+	/* All documentation says to check for this. Maybe my hardware is too
+	 * fast. Waiting for it seems to work fine! KLL
+	 */
+	while (!(i = NCR5380_read(C400_CONTROL_STATUS_REG) & CSR_GATED_53C80_IRQ))
+		;	// FIXME - no timeout
+
+	/*
+	 * I know. i is certainly != 0 here but the loop is new. See previous
+	 * comment.
+	 */
+	if (i) {
+		if (!((i = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_END_DMA_TRANSFER))
+			printk(KERN_ERR "53C400w: No END OF DMA bit - WHOOPS! BASR=%0x\n", i);
+	} else
+		printk(KERN_ERR "53C400w: no 53C80 gated irq after transfer (last block)\n");
+
+#if 0
+	if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_END_DMA_TRANSFER)) {
+		printk(KERN_ERR "53C400w: no end dma signal\n");
+	}
+#endif
+	while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT))
+		; 	// TIMEOUT
+	return 0;
+}
+#endif				/* PSEUDO_DMA */
+
+/*
+ *	Include the NCR5380 core code that we build our driver around	
+ */
+ 
+#include "NCR5380.c"
+
+#define PRINTP(x) len += sprintf(buffer+len, x)
+#define ANDP ,
+
+static int sprint_opcode(char *buffer, int len, int opcode)
+{
+	int start = len;
+	PRINTP("0x%02x " ANDP opcode);
+	return len - start;
+}
+
+static int sprint_command(char *buffer, int len, unsigned char *command)
+{
+	int i, s, start = len;
+	len += sprint_opcode(buffer, len, command[0]);
+	for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+		PRINTP("%02x " ANDP command[i]);
+	PRINTP("\n");
+	return len - start;
+}
+
+/**
+ *	sprintf_Scsi_Cmnd	-	print a scsi command
+ *	@buffer: buffr to print into
+ *	@len: buffer length
+ *	@cmd: SCSI command block
+ *	
+ *	Print out the target and command data in hex
+ */
+
+static int sprint_Scsi_Cmnd(char *buffer, int len, Scsi_Cmnd * cmd)
+{
+	int start = len;
+	PRINTP("host number %d destination target %d, lun %d\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun);
+	PRINTP("        command = ");
+	len += sprint_command(buffer, len, cmd->cmnd);
+	return len - start;
+}
+
+/**
+ *	generic_NCR5380_proc_info	-	/proc for NCR5380 driver
+ *	@buffer: buffer to print into
+ *	@start: start position
+ *	@offset: offset into buffer
+ *	@len: length
+ *	@hostno: instance to affect
+ *	@inout: read/write
+ *
+ *	Provide the procfs information for the 5380 controller. We fill
+ *	this with useful debugging information including the commands
+ *	being executed, disconnected command queue and the statistical
+ *	data
+ *
+ *	Locks: global cli/lock for queue walk
+ */
+ 
+static int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	int len = 0;
+	NCR5380_local_declare();
+	unsigned long flags;
+	unsigned char status;
+	int i;
+	Scsi_Cmnd *ptr;
+	struct NCR5380_hostdata *hostdata;
+#ifdef NCR5380_STATS
+	Scsi_Device *dev;
+	extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
+#endif
+
+	NCR5380_setup(scsi_ptr);
+	hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
+
+	spin_lock_irqsave(scsi_ptr->host_lock, flags);
+	PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
+	PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
+	PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
+#ifdef NCR53C400
+	PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
+	PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not");
+# if NCR53C400_PSEUDO_DMA
+	PRINTP("NCR53C400 pseudo DMA used\n");
+# endif
+#else
+	PRINTP("NO NCR53C400 driver extensions\n");
+#endif
+	PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
+	if (scsi_ptr->irq == SCSI_IRQ_NONE)
+		PRINTP("no interrupt\n");
+	else
+		PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
+
+#ifdef NCR5380_STATS
+	if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
+		PRINTP("There are commands pending, transfer rates may be crud\n");
+	if (hostdata->pendingr)
+		PRINTP("  %d pending reads" ANDP hostdata->pendingr);
+	if (hostdata->pendingw)
+		PRINTP("  %d pending writes" ANDP hostdata->pendingw);
+	if (hostdata->pendingr || hostdata->pendingw)
+		PRINTP("\n");
+	shost_for_each_device(dev, scsi_ptr) {
+		unsigned long br = hostdata->bytes_read[dev->id];
+		unsigned long bw = hostdata->bytes_write[dev->id];
+		long tr = hostdata->time_read[dev->id] / HZ;
+		long tw = hostdata->time_write[dev->id] / HZ;
+
+		PRINTP("  T:%d %s " ANDP dev->id ANDP(dev->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(int) dev->type] : "Unknown");
+		for (i = 0; i < 8; i++)
+			if (dev->vendor[i] >= 0x20)
+				*(buffer + (len++)) = dev->vendor[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 16; i++)
+			if (dev->model[i] >= 0x20)
+				*(buffer + (len++)) = dev->model[i];
+		*(buffer + (len++)) = ' ';
+		for (i = 0; i < 4; i++)
+			if (dev->rev[i] >= 0x20)
+				*(buffer + (len++)) = dev->rev[i];
+		*(buffer + (len++)) = ' ';
+
+		PRINTP("\n%10ld kb read    in %5ld secs" ANDP br / 1024 ANDP tr);
+		if (tr)
+			PRINTP(" @ %5ld bps" ANDP br / tr);
+
+		PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw);
+		if (tw)
+			PRINTP(" @ %5ld bps" ANDP bw / tw);
+		PRINTP("\n");
+	}
+#endif
+
+	status = NCR5380_read(STATUS_REG);
+	if (!(status & SR_REQ))
+		PRINTP("REQ not asserted, phase unknown.\n");
+	else {
+		for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
+		PRINTP("Phase %s\n" ANDP phases[i].name);
+	}
+
+	if (!hostdata->connected) {
+		PRINTP("No currently connected command\n");
+	} else {
+		len += sprint_Scsi_Cmnd(buffer, len, (Scsi_Cmnd *) hostdata->connected);
+	}
+
+	PRINTP("issue_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	PRINTP("disconnected_queue\n");
+
+	for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+		len += sprint_Scsi_Cmnd(buffer, len, ptr);
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	spin_unlock_irqrestore(scsi_ptr->host_lock, flags);
+	return len;
+}
+
+#undef PRINTP
+#undef ANDP
+
+static Scsi_Host_Template driver_template = {
+	.proc_info      	= generic_NCR5380_proc_info,
+	.name           	= "Generic NCR5380/NCR53C400 Scsi Driver",
+	.detect         	= generic_NCR5380_detect,
+	.release        	= generic_NCR5380_release_resources,
+	.info           	= generic_NCR5380_info,
+	.queuecommand   	= generic_NCR5380_queue_command,
+	.eh_abort_handler	= generic_NCR5380_abort,
+	.eh_bus_reset_handler	= generic_NCR5380_bus_reset,
+	.eh_device_reset_handler = generic_NCR5380_device_reset,
+	.eh_host_reset_handler	= generic_NCR5380_host_reset,
+	.bios_param     	= NCR5380_BIOSPARAM,
+	.can_queue      	= CAN_QUEUE,
+        .this_id        	= 7,
+        .sg_tablesize   	= SG_ALL,
+	.cmd_per_lun    	= CMD_PER_LUN,
+        .use_clustering		= DISABLE_CLUSTERING,
+};
+#include <linux/module.h>
+#include "scsi_module.c"
+
+module_param(ncr_irq, int, 0);
+module_param(ncr_dma, int, 0);
+module_param(ncr_addr, int, 0);
+module_param(ncr_5380, int, 0);
+module_param(ncr_53c400, int, 0);
+module_param(ncr_53c400a, int, 0);
+module_param(dtc_3181e, int, 0);
+MODULE_LICENSE("GPL");
+
+
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{
+	 ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+	 ISAPNP_VENDOR('D', 'T', 'C'), ISAPNP_FUNCTION(0x436e),
+	 0},
+	{0}
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+
+__setup("ncr5380=", do_NCR5380_setup);
+__setup("ncr53c400=", do_NCR53C400_setup);
+__setup("ncr53c400a=", do_NCR53C400A_setup);
+__setup("dtc3181e=", do_DTC3181E_setup);
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
new file mode 100644
index 0000000..0c04cef
--- /dev/null
+++ b/drivers/scsi/g_NCR5380.h
@@ -0,0 +1,131 @@
+/*
+ * Generic Generic NCR5380 driver defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
+ *    K.Lentin@cs.monash.edu.au
+ *
+ * ALPHA RELEASE 1. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: generic_NCR5380.h,v $
+ */
+
+#ifndef GENERIC_NCR5380_H
+#define GENERIC_NCR5380_H
+
+#include <linux/config.h>
+
+#define GENERIC_NCR5380_PUBLIC_RELEASE 1
+
+#ifdef NCR53C400
+#define BIOSPARAM
+#define NCR5380_BIOSPARAM generic_NCR5380_biosparam
+#else
+#define NCR5380_BIOSPARAM NULL
+#endif
+
+#ifndef ASM
+static int generic_NCR5380_abort(Scsi_Cmnd *);
+static int generic_NCR5380_detect(Scsi_Host_Template *);
+static int generic_NCR5380_release_resources(struct Scsi_Host *);
+static int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
+static int generic_NCR5380_host_reset(Scsi_Cmnd *);
+static int generic_NCR5380_device_reset(Scsi_Cmnd *);
+static const char* generic_NCR5380_info(struct Scsi_Host *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifndef HOSTS_C
+
+#define __STRVAL(x) #x
+#define STRVAL(x) __STRVAL(x)
+
+#ifndef CONFIG_SCSI_G_NCR5380_MEM
+
+#define NCR5380_map_config port
+#define NCR5380_map_type int
+#define NCR5380_map_name port
+#define NCR5380_instance_name io_port
+#define NCR53C400_register_offset 0
+#define NCR53C400_address_adjust 8
+
+#ifdef NCR53C400
+#define NCR5380_region_size 16
+#else
+#define NCR5380_region_size 8
+#endif
+
+#define NCR5380_read(reg) (inb(NCR5380_map_name + (reg)))
+#define NCR5380_write(reg, value) (outb((value), (NCR5380_map_name + (reg))))
+
+#else 
+/* therefore CONFIG_SCSI_G_NCR5380_MEM */
+
+#define NCR5380_map_config memory
+#define NCR5380_map_type unsigned long
+#define NCR5380_map_name base
+#define NCR5380_instance_name base
+#define NCR53C400_register_offset 0x108
+#define NCR53C400_address_adjust 0
+#define NCR53C400_mem_base 0x3880
+#define NCR53C400_host_buffer 0x3900
+#define NCR5380_region_size 0x3a00
+
+#define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg))
+#define NCR5380_write(reg, value) isa_writeb(value, NCR5380_map_name + NCR53C400_mem_base + (reg))
+#endif
+
+#define NCR5380_implementation_fields \
+    NCR5380_map_type NCR5380_map_name
+
+#define NCR5380_local_declare() \
+    register NCR5380_implementation_fields
+
+#define NCR5380_setup(instance) \
+    NCR5380_map_name = (NCR5380_map_type)((instance)->NCR5380_instance_name)
+
+#define NCR5380_intr generic_NCR5380_intr
+#define NCR5380_queue_command generic_NCR5380_queue_command
+#define NCR5380_abort generic_NCR5380_abort
+#define NCR5380_bus_reset generic_NCR5380_bus_reset
+#define NCR5380_device_reset generic_NCR5380_device_reset
+#define NCR5380_host_reset generic_NCR5380_host_reset
+#define NCR5380_pread generic_NCR5380_pread
+#define NCR5380_pwrite generic_NCR5380_pwrite
+#define NCR5380_proc_info notyet_generic_proc_info
+
+#define BOARD_NCR5380	0
+#define BOARD_NCR53C400	1
+#define BOARD_NCR53C400A 2
+#define BOARD_DTC3181E	3
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* GENERIC_NCR5380_H */
+
diff --git a/drivers/scsi/g_NCR5380_mmio.c b/drivers/scsi/g_NCR5380_mmio.c
new file mode 100644
index 0000000..8cdde71
--- /dev/null
+++ b/drivers/scsi/g_NCR5380_mmio.c
@@ -0,0 +1,10 @@
+/*
+ *	There is probably a nicer way to do this but this one makes
+ *	pretty obvious what is happening. We rebuild the same file with
+ *	different options for mmio versus pio.
+ */
+
+#define SCSI_G_NCR5380_MEM
+
+#include "g_NCR5380.c"
+
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
new file mode 100644
index 0000000..cc0cb24
--- /dev/null
+++ b/drivers/scsi/gdth.c
@@ -0,0 +1,5738 @@
+/************************************************************************
+ * Linux driver for                                                     *  
+ * ICP vortex GmbH:    GDT ISA/EISA/PCI Disk Array Controllers          *
+ * Intel Corporation:  Storage RAID Controllers                         *
+ *                                                                      *
+ * gdth.c                                                               *
+ * Copyright (C) 1995-04 ICP vortex GmbH, Achim Leubner                 *
+ * Copyright (C) 2002-04 Intel Corporation                              *
+ * Copyright (C) 2003-04 Adaptec Inc.                                   *
+ * <achim_leubner@adaptec.com>                                          *
+ *                                                                      *
+ * Additions/Fixes:                                                     *
+ * Boji Tony Kannanthanam <boji.t.kannanthanam@intel.com>               *
+ * Johannes Dinner <johannes_dinner@adaptec.com>                        *
+ *                                                                      *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published    *
+ * by the Free Software Foundation; either version 2 of the License,    *
+ * or (at your option) any later version.                               *
+ *                                                                      *
+ * This program is distributed in the hope that it will be useful,      *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of       *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the         *
+ * GNU General Public License for more details.                         *
+ *                                                                      *
+ * You should have received a copy of the GNU General Public License    *
+ * along with this kernel; if not, write to the Free Software           *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.            *
+ *                                                                      *
+ * Linux kernel 2.2.x, 2.4.x, 2.6.x supported                           *
+ *                                                                      *
+ * $Log: gdth.c,v $
+ * Revision 1.73  2004/03/31 13:33:03  achim
+ * Special command 0xfd implemented to detect 64-bit DMA support
+ *
+ * Revision 1.72  2004/03/17 08:56:04  achim
+ * 64-bit DMA only enabled if FW >= x.43
+ *
+ * Revision 1.71  2004/03/05 15:51:29  achim
+ * Screen service: separate message buffer, bugfixes
+ *
+ * Revision 1.70  2004/02/27 12:19:07  achim
+ * Bugfix: Reset bit in config (0xfe) call removed
+ *
+ * Revision 1.69  2004/02/20 09:50:24  achim
+ * Compatibility changes for kernels < 2.4.20
+ * Bugfix screen service command size
+ * pci_set_dma_mask() error handling added
+ *
+ * Revision 1.68  2004/02/19 15:46:54  achim
+ * 64-bit DMA bugfixes
+ * Drive size bugfix for drives > 1TB
+ *
+ * Revision 1.67  2004/01/14 13:11:57  achim
+ * Tool access over /proc no longer supported
+ * Bugfixes IOCTLs
+ *
+ * Revision 1.66  2003/12/19 15:04:06  achim
+ * Bugfixes support for drives > 2TB
+ *
+ * Revision 1.65  2003/12/15 11:21:56  achim
+ * 64-bit DMA support added
+ * Support for drives > 2 TB implemented
+ * Kernels 2.2.x, 2.4.x, 2.6.x supported
+ *
+ * Revision 1.64  2003/09/17 08:30:26  achim
+ * EISA/ISA controller scan disabled
+ * Command line switch probe_eisa_isa added
+ *
+ * Revision 1.63  2003/07/12 14:01:00  Daniele Bellucci <bellucda@tiscali.it>
+ * Minor cleanups in gdth_ioctl.
+ *
+ * Revision 1.62  2003/02/27 15:01:59  achim
+ * Dynamic DMA mapping implemented
+ * New (character device) IOCTL interface added
+ * Other controller related changes made
+ *
+ * Revision 1.61  2002/11/08 13:09:52  boji
+ * Added support for XSCALE based RAID Controllers
+ * Fixed SCREENSERVICE initialization in SMP cases
+ * Added checks for gdth_polling before GDTH_HA_LOCK
+ *
+ * Revision 1.60  2002/02/05 09:35:22  achim
+ * MODULE_LICENSE only if kernel >= 2.4.11
+ *
+ * Revision 1.59  2002/01/30 09:46:33  achim
+ * Small changes
+ *
+ * Revision 1.58  2002/01/29 15:30:02  achim
+ * Set default value of shared_access to Y
+ * New status S_CACHE_RESERV for clustering added
+ *
+ * Revision 1.57  2001/08/21 11:16:35  achim
+ * Bugfix free_irq()
+ *
+ * Revision 1.56  2001/08/09 11:19:39  achim
+ * Scsi_Host_Template changes
+ *
+ * Revision 1.55  2001/08/09 10:11:28  achim
+ * Command HOST_UNFREEZE_IO before cache service init.
+ *
+ * Revision 1.54  2001/07/20 13:48:12  achim
+ * Expand: gdth_analyse_hdrive() removed
+ *
+ * Revision 1.53  2001/07/17 09:52:49  achim
+ * Small OEM related change
+ *
+ * Revision 1.52  2001/06/19 15:06:20  achim
+ * New host command GDT_UNFREEZE_IO added
+ *
+ * Revision 1.51  2001/05/22 06:42:37  achim
+ * PCI: Subdevice ID added
+ *
+ * Revision 1.50  2001/05/17 13:42:16  achim
+ * Support for Intel Storage RAID Controllers added
+ *
+ * Revision 1.50  2001/05/17 12:12:34  achim
+ * Support for Intel Storage RAID Controllers added
+ *
+ * Revision 1.49  2001/03/15 15:07:17  achim
+ * New __setup interface for boot command line options added
+ *
+ * Revision 1.48  2001/02/06 12:36:28  achim
+ * Bugfix Cluster protocol
+ *
+ * Revision 1.47  2001/01/10 14:42:06  achim
+ * New switch shared_access added
+ *
+ * Revision 1.46  2001/01/09 08:11:35  achim
+ * gdth_command() removed
+ * meaning of Scsi_Pointer members changed
+ *
+ * Revision 1.45  2000/11/16 12:02:24  achim
+ * Changes for kernel 2.4
+ *
+ * Revision 1.44  2000/10/11 08:44:10  achim
+ * Clustering changes: New flag media_changed added
+ *
+ * Revision 1.43  2000/09/20 12:59:01  achim
+ * DPMEM remap functions for all PCI controller types implemented
+ * Small changes for ia64 platform
+ *
+ * Revision 1.42  2000/07/20 09:04:50  achim
+ * Small changes for kernel 2.4
+ *
+ * Revision 1.41  2000/07/04 14:11:11  achim
+ * gdth_analyse_hdrive() added to rescan drives after online expansion
+ *
+ * Revision 1.40  2000/06/27 11:24:16  achim
+ * Changes Clustering, Screenservice
+ *
+ * Revision 1.39  2000/06/15 13:09:04  achim
+ * Changes for gdth_do_cmd()
+ *
+ * Revision 1.38  2000/06/15 12:08:43  achim
+ * Bugfix gdth_sync_event(), service SCREENSERVICE
+ * Data direction for command 0xc2 changed to DOU
+ *
+ * Revision 1.37  2000/05/25 13:50:10  achim
+ * New driver parameter virt_ctr added
+ *
+ * Revision 1.36  2000/05/04 08:50:46  achim
+ * Event buffer now in gdth_ha_str
+ *
+ * Revision 1.35  2000/03/03 10:44:08  achim
+ * New event_string only valid for the RP controller family
+ *
+ * Revision 1.34  2000/03/02 14:55:29  achim
+ * New mechanism for async. event handling implemented
+ *
+ * Revision 1.33  2000/02/21 15:37:37  achim
+ * Bugfix Alpha platform + DPMEM above 4GB
+ *
+ * Revision 1.32  2000/02/14 16:17:37  achim
+ * Bugfix sense_buffer[] + raw devices
+ *
+ * Revision 1.31  2000/02/10 10:29:00  achim
+ * Delete sense_buffer[0], if command OK
+ *
+ * Revision 1.30  1999/11/02 13:42:39  achim
+ * ARRAY_DRV_LIST2 implemented
+ * Now 255 log. and 100 host drives supported
+ *
+ * Revision 1.29  1999/10/05 13:28:47  achim
+ * GDT_CLUST_RESET added
+ *
+ * Revision 1.28  1999/08/12 13:44:54  achim
+ * MOUNTALL removed
+ * Cluster drives -> removeable drives
+ *
+ * Revision 1.27  1999/06/22 07:22:38  achim
+ * Small changes
+ *
+ * Revision 1.26  1999/06/10 16:09:12  achim
+ * Cluster Host Drive support: Bugfixes
+ *
+ * Revision 1.25  1999/06/01 16:03:56  achim
+ * gdth_init_pci(): Manipulate config. space to start RP controller
+ *
+ * Revision 1.24  1999/05/26 11:53:06  achim
+ * Cluster Host Drive support added
+ *
+ * Revision 1.23  1999/03/26 09:12:31  achim
+ * Default value for hdr_channel set to 0
+ *
+ * Revision 1.22  1999/03/22 16:27:16  achim
+ * Bugfix: gdth_store_event() must not be locked with GDTH_LOCK_HA()
+ *
+ * Revision 1.21  1999/03/16 13:40:34  achim
+ * Problems with reserved drives solved
+ * gdth_eh_bus_reset() implemented
+ *
+ * Revision 1.20  1999/03/10 09:08:13  achim
+ * Bugfix: Corrections in gdth_direction_tab[] made
+ * Bugfix: Increase command timeout (gdth_update_timeout()) NOT in gdth_putq()
+ *
+ * Revision 1.19  1999/03/05 14:38:16  achim
+ * Bugfix: Heads/Sectors mapping for reserved devices possibly wrong
+ * -> gdth_eval_mapping() implemented, changes in gdth_bios_param()
+ * INIT_RETRIES set to 100s to avoid DEINIT-Timeout for controllers
+ * with BIOS disabled and memory test set to Intensive
+ * Enhanced /proc support
+ *
+ * Revision 1.18  1999/02/24 09:54:33  achim
+ * Command line parameter hdr_channel implemented
+ * Bugfix for EISA controllers + Linux 2.2.x
+ *
+ * Revision 1.17  1998/12/17 15:58:11  achim
+ * Command line parameters implemented
+ * Changes for Alpha platforms
+ * PCI controller scan changed
+ * SMP support improved (spin_lock_irqsave(),...)
+ * New async. events, new scan/reserve commands included
+ *
+ * Revision 1.16  1998/09/28 16:08:46  achim
+ * GDT_PCIMPR: DPMEM remapping, if required
+ * mdelay() added
+ *
+ * Revision 1.15  1998/06/03 14:54:06  achim
+ * gdth_delay(), gdth_flush() implemented
+ * Bugfix: gdth_release() changed
+ *
+ * Revision 1.14  1998/05/22 10:01:17  achim
+ * mj: pcibios_strerror() removed
+ * Improved SMP support (if version >= 2.1.95)
+ * gdth_halt(): halt_called flag added (if version < 2.1)
+ *
+ * Revision 1.13  1998/04/16 09:14:57  achim
+ * Reserve drives (for raw service) implemented
+ * New error handling code enabled
+ * Get controller name from board_info() IOCTL
+ * Final round of PCI device driver patches by Martin Mares
+ *
+ * Revision 1.12  1998/03/03 09:32:37  achim
+ * Fibre channel controller support added
+ *
+ * Revision 1.11  1998/01/27 16:19:14  achim
+ * SA_SHIRQ added
+ * add_timer()/del_timer() instead of GDTH_TIMER
+ * scsi_add_timer()/scsi_del_timer() instead of SCSI_TIMER
+ * New error handling included
+ *
+ * Revision 1.10  1997/10/31 12:29:57  achim
+ * Read heads/sectors from host drive
+ *
+ * Revision 1.9  1997/09/04 10:07:25  achim
+ * IO-mapping with virt_to_bus(), gdth_readb(), gdth_writeb(), ...
+ * register_reboot_notifier() to get a notify on shutown used
+ *
+ * Revision 1.8  1997/04/02 12:14:30  achim
+ * Version 1.00 (see gdth.h), tested with kernel 2.0.29
+ *
+ * Revision 1.7  1997/03/12 13:33:37  achim
+ * gdth_reset() changed, new async. events
+ *
+ * Revision 1.6  1997/03/04 14:01:11  achim
+ * Shutdown routine gdth_halt() implemented
+ *
+ * Revision 1.5  1997/02/21 09:08:36  achim
+ * New controller included (RP, RP1, RP2 series)
+ * IOCTL interface implemented
+ *
+ * Revision 1.4  1996/07/05 12:48:55  achim
+ * Function gdth_bios_param() implemented
+ * New constant GDTH_MAXC_P_L inserted
+ * GDT_WRITE_THR, GDT_EXT_INFO implemented
+ * Function gdth_reset() changed
+ *
+ * Revision 1.3  1996/05/10 09:04:41  achim
+ * Small changes for Linux 1.2.13
+ *
+ * Revision 1.2  1996/05/09 12:45:27  achim
+ * Loadable module support implemented
+ * /proc support corrections made
+ *
+ * Revision 1.1  1996/04/11 07:35:57  achim
+ * Initial revision
+ *
+ ************************************************************************/
+
+/* All GDT Disk Array Controllers are fully supported by this driver.
+ * This includes the PCI/EISA/ISA SCSI Disk Array Controllers and the
+ * PCI Fibre Channel Disk Array Controllers. See gdth.h for a complete
+ * list of all controller types.
+ * 
+ * If you have one or more GDT3000/3020 EISA controllers with 
+ * controller BIOS disabled, you have to set the IRQ values with the 
+ * command line option "gdth=irq1,irq2,...", where the irq1,irq2,... are
+ * the IRQ values for the EISA controllers.
+ * 
+ * After the optional list of IRQ values, other possible 
+ * command line options are:
+ * disable:Y                    disable driver
+ * disable:N                    enable driver
+ * reserve_mode:0               reserve no drives for the raw service
+ * reserve_mode:1               reserve all not init., removable drives
+ * reserve_mode:2               reserve all not init. drives
+ * reserve_list:h,b,t,l,h,b,t,l,...     reserve particular drive(s) with 
+ *                              h- controller no., b- channel no., 
+ *                              t- target ID, l- LUN
+ * reverse_scan:Y               reverse scan order for PCI controllers         
+ * reverse_scan:N               scan PCI controllers like BIOS
+ * max_ids:x                    x - target ID count per channel (1..MAXID)
+ * rescan:Y                     rescan all channels/IDs 
+ * rescan:N                     use all devices found until now
+ * virt_ctr:Y                   map every channel to a virtual controller 
+ * virt_ctr:N                   use multi channel support 
+ * hdr_channel:x                x - number of virtual bus for host drives
+ * shared_access:Y              disable driver reserve/release protocol to 
+ *                              access a shared resource from several nodes, 
+ *                              appropiate controller firmware required
+ * shared_access:N              enable driver reserve/release protocol
+ * probe_eisa_isa:Y             scan for EISA/ISA controllers
+ * probe_eisa_isa:N             do not scan for EISA/ISA controllers
+ * force_dma32:Y                use only 32 bit DMA mode
+ * force_dma32:N                use 64 bit DMA mode, if supported
+ *
+ * The default values are: "gdth=disable:N,reserve_mode:1,reverse_scan:N,
+ *                          max_ids:127,rescan:N,virt_ctr:N,hdr_channel:0,
+ *                          shared_access:Y,probe_eisa_isa:N,force_dma32:N".
+ * Here is another example: "gdth=reserve_list:0,1,2,0,0,1,3,0,rescan:Y".
+ * 
+ * When loading the gdth driver as a module, the same options are available. 
+ * You can set the IRQs with "IRQ=...". However, the syntax to specify the
+ * options changes slightly. You must replace all ',' between options 
+ * with ' ' and all ':' with '=' and you must use 
+ * '1' in place of 'Y' and '0' in place of 'N'.
+ * 
+ * Default: "modprobe gdth disable=0 reserve_mode=1 reverse_scan=0
+ *           max_ids=127 rescan=0 virt_ctr=0 hdr_channel=0 shared_access=0 
+ *           probe_eisa_isa=0 force_dma32=0"
+ * The other example: "modprobe gdth reserve_list=0,1,2,0,0,1,3,0 rescan=1".
+ */
+
+/* The meaning of the Scsi_Pointer members in this driver is as follows:
+ * ptr:                     Chaining
+ * this_residual:           Command priority
+ * buffer:                  phys. DMA sense buffer 
+ * dma_handle:              phys. DMA buffer (kernel >= 2.4.0)
+ * buffers_residual:        Timeout value
+ * Status:                  Command status (gdth_do_cmd()), DMA mem. mappings
+ * Message:                 Additional info (gdth_do_cmd()), DMA direction
+ * have_data_in:            Flag for gdth_wait_completion()
+ * sent_command:            Opcode special command
+ * phase:                   Service/parameter/return code special command
+ */
+
+
+/* interrupt coalescing */
+/* #define INT_COAL */
+
+/* statistics */
+#define GDTH_STATISTICS
+
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/proc_fs.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#ifdef GDTH_RTC
+#include <linux/mc146818rtc.h>
+#endif
+#include <linux/reboot.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <linux/spinlock.h>
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#include <linux/blkdev.h>
+#else
+#include <linux/blk.h>
+#include "sd.h"
+#endif
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "gdth.h"
+#include "gdth_kcompat.h"
+
+static void gdth_delay(int milliseconds);
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs);
+static irqreturn_t gdth_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp);
+static int gdth_async_event(int hanum);
+static void gdth_log_event(gdth_evt_data *dvr, char *buffer);
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority);
+static void gdth_next(int hanum);
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b);
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp);
+static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source,
+                                      ushort idx, gdth_evt_data *evt);
+static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr);
+static void gdth_readapp_event(gdth_ha_str *ha, unchar application, 
+                               gdth_evt_str *estr);
+static void gdth_clear_events(void);
+
+static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
+                                    char *buffer,ushort count);
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp);
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive);
+
+static int gdth_search_eisa(ushort eisa_adr);
+static int gdth_search_isa(ulong32 bios_adr);
+static int gdth_search_pci(gdth_pci_str *pcistr);
+static void gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt, 
+                            ushort vendor, ushort dev);
+static void gdth_sort_pci(gdth_pci_str *pcistr, int cnt);
+static int gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha);
+static int gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha);
+static int gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha);
+
+static void gdth_enable_int(int hanum);
+static int gdth_get_status(unchar *pIStatus,int irq);
+static int gdth_test_busy(int hanum);
+static int gdth_get_cmd_index(int hanum);
+static void gdth_release_event(int hanum);
+static int gdth_wait(int hanum,int index,ulong32 time);
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
+                             ulong64 p2,ulong64 p3);
+static int gdth_search_drives(int hanum);
+static int gdth_analyse_hdrive(int hanum, ushort hdrive);
+
+static const char *gdth_ctr_name(int hanum);
+
+static int gdth_open(struct inode *inode, struct file *filep);
+static int gdth_close(struct inode *inode, struct file *filep);
+static int gdth_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg);
+
+static void gdth_flush(int hanum);
+static int gdth_halt(struct notifier_block *nb, ulong event, void *buf);
+
+#ifdef DEBUG_GDTH
+static unchar   DebugState = DEBUG_GDTH;
+
+#ifdef __SERIAL__
+#define MAX_SERBUF 160
+static void ser_init(void);
+static void ser_puts(char *str);
+static void ser_putc(char c);
+static int  ser_printk(const char *fmt, ...);
+static char strbuf[MAX_SERBUF+1];
+#ifdef __COM2__
+#define COM_BASE 0x2f8
+#else
+#define COM_BASE 0x3f8
+#endif
+static void ser_init()
+{
+    unsigned port=COM_BASE;
+
+    outb(0x80,port+3);
+    outb(0,port+1);
+    /* 19200 Baud, if 9600: outb(12,port) */
+    outb(6, port);
+    outb(3,port+3);
+    outb(0,port+1);
+    /*
+    ser_putc('I');
+    ser_putc(' ');
+    */
+}
+
+static void ser_puts(char *str)
+{
+    char *ptr;
+
+    ser_init();
+    for (ptr=str;*ptr;++ptr)
+        ser_putc(*ptr);
+}
+
+static void ser_putc(char c)
+{
+    unsigned port=COM_BASE;
+
+    while ((inb(port+5) & 0x20)==0);
+    outb(c,port);
+    if (c==0x0a)
+    {
+        while ((inb(port+5) & 0x20)==0);
+        outb(0x0d,port);
+    }
+}
+
+static int ser_printk(const char *fmt, ...)
+{
+    va_list args;
+    int i;
+
+    va_start(args,fmt);
+    i = vsprintf(strbuf,fmt,args);
+    ser_puts(strbuf);
+    va_end(args);
+    return i;
+}
+
+#define TRACE(a)    {if (DebugState==1) {ser_printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {ser_printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {ser_printk a;}}
+
+#else /* !__SERIAL__ */
+#define TRACE(a)    {if (DebugState==1) {printk a;}}
+#define TRACE2(a)   {if (DebugState==1 || DebugState==2) {printk a;}}
+#define TRACE3(a)   {if (DebugState!=0) {printk a;}}
+#endif
+
+#else /* !DEBUG */
+#define TRACE(a)
+#define TRACE2(a)
+#define TRACE3(a)
+#endif
+
+#ifdef GDTH_STATISTICS
+static ulong32 max_rq=0, max_index=0, max_sg=0;
+#ifdef INT_COAL
+static ulong32 max_int_coal=0;
+#endif
+static ulong32 act_ints=0, act_ios=0, act_stats=0, act_rq=0;
+static struct timer_list gdth_timer;
+#endif
+
+#define PTR2USHORT(a)   (ushort)(ulong)(a)
+#define GDTOFFSOF(a,b)  (size_t)&(((a*)0)->b)   
+#define INDEX_OK(i,t)   ((i)<sizeof(t)/sizeof((t)[0]))
+
+#define NUMDATA(a)      ( (gdth_num_str  *)((a)->hostdata))
+#define HADATA(a)       (&((gdth_ext_str *)((a)->hostdata))->haext)
+#define CMDDATA(a)      (&((gdth_ext_str *)((a)->hostdata))->cmdext)
+
+#define BUS_L2P(a,b)    ((b)>(a)->virt_bus ? (b-1):(b))
+
+#define gdth_readb(addr)        readb(addr)
+#define gdth_readw(addr)        readw(addr)
+#define gdth_readl(addr)        readl(addr)
+#define gdth_writeb(b,addr)     writeb((b),(addr))
+#define gdth_writew(b,addr)     writew((b),(addr))
+#define gdth_writel(b,addr)     writel((b),(addr))
+
+static unchar   gdth_drq_tab[4] = {5,6,7,7};            /* DRQ table */
+static unchar   gdth_irq_tab[6] = {0,10,11,12,14,0};    /* IRQ table */
+static unchar   gdth_polling;                           /* polling if TRUE */
+static unchar   gdth_from_wait  = FALSE;                /* gdth_wait() */
+static int      wait_index,wait_hanum;                  /* gdth_wait() */
+static int      gdth_ctr_count  = 0;                    /* controller count */
+static int      gdth_ctr_vcount = 0;                    /* virt. ctr. count */
+static int      gdth_ctr_released = 0;                  /* gdth_release() */
+static struct Scsi_Host *gdth_ctr_tab[MAXHA];           /* controller table */
+static struct Scsi_Host *gdth_ctr_vtab[MAXHA*MAXBUS];   /* virt. ctr. table */
+static unchar   gdth_write_through = FALSE;             /* write through */
+static gdth_evt_str ebuffer[MAX_EVENTS];                /* event buffer */
+static int elastidx;
+static int eoldidx;
+static int major;
+
+#define DIN     1                               /* IN data direction */
+#define DOU     2                               /* OUT data direction */
+#define DNO     DIN                             /* no data transfer */
+#define DUN     DIN                             /* unknown data direction */
+static unchar gdth_direction_tab[0x100] = {
+    DNO,DNO,DIN,DIN,DOU,DIN,DIN,DOU,DIN,DUN,DOU,DOU,DUN,DUN,DUN,DIN,
+    DNO,DIN,DIN,DOU,DIN,DOU,DNO,DNO,DOU,DNO,DIN,DNO,DIN,DOU,DNO,DUN,
+    DIN,DUN,DIN,DUN,DOU,DIN,DUN,DUN,DIN,DIN,DOU,DNO,DUN,DIN,DOU,DOU,
+    DOU,DOU,DOU,DNO,DIN,DNO,DNO,DIN,DOU,DOU,DOU,DOU,DIN,DOU,DIN,DOU,
+    DOU,DOU,DIN,DIN,DIN,DNO,DUN,DNO,DNO,DNO,DUN,DNO,DOU,DIN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DIN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DIN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DNO,DNO,DUN,DIN,DNO,DOU,DUN,DNO,DUN,DOU,DOU,
+    DOU,DOU,DOU,DNO,DUN,DIN,DOU,DIN,DIN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DOU,DUN,DUN,DUN,DUN,DUN,
+    DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN,DUN
+};
+
+/* LILO and modprobe/insmod parameters */
+/* IRQ list for GDT3000/3020 EISA controllers */
+static int irq[MAXHA] __initdata = 
+{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+/* disable driver flag */
+static int disable __initdata = 0;
+/* reserve flag */
+static int reserve_mode = 1;                  
+/* reserve list */
+static int reserve_list[MAX_RES_ARGS] = 
+{0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
+/* scan order for PCI controllers */
+static int reverse_scan = 0;
+/* virtual channel for the host drives */
+static int hdr_channel = 0;
+/* max. IDs per channel */
+static int max_ids = MAXID;
+/* rescan all IDs */
+static int rescan = 0;
+/* map channels to virtual controllers */
+static int virt_ctr = 0;
+/* shared access */
+static int shared_access = 1;
+/* enable support for EISA and ISA controllers */
+static int probe_eisa_isa = 0;
+/* 64 bit DMA mode, support for drives > 2 TB, if force_dma32 = 0 */
+static int force_dma32 = 0;
+
+/* parameters for modprobe/insmod */
+module_param_array(irq, int, NULL, 0);
+module_param(disable, int, 0);
+module_param(reserve_mode, int, 0);
+module_param_array(reserve_list, int, NULL, 0);
+module_param(reverse_scan, int, 0);
+module_param(hdr_channel, int, 0);
+module_param(max_ids, int, 0);
+module_param(rescan, int, 0);
+module_param(virt_ctr, int, 0);
+module_param(shared_access, int, 0);
+module_param(probe_eisa_isa, int, 0);
+module_param(force_dma32, int, 0);
+MODULE_AUTHOR("Achim Leubner");
+MODULE_LICENSE("GPL");
+
+/* ioctl interface */
+static struct file_operations gdth_fops = {
+    .ioctl   = gdth_ioctl,
+    .open    = gdth_open,
+    .release = gdth_close,
+};
+
+#include "gdth_proc.h"
+#include "gdth_proc.c"
+
+/* notifier block to get a notify on system shutdown/halt/reboot */
+static struct notifier_block gdth_notifier = {
+    gdth_halt, NULL, 0
+};
+
+
+static void gdth_delay(int milliseconds)
+{
+    if (milliseconds == 0) {
+        udelay(1);
+    } else {
+        mdelay(milliseconds);
+    }
+}
+
+static void gdth_eval_mapping(ulong32 size, ulong32 *cyls, int *heads, int *secs)
+{
+    *cyls = size /HEADS/SECS;
+    if (*cyls <= MAXCYLS) {
+        *heads = HEADS;
+        *secs = SECS;
+    } else {                                        /* too high for 64*32 */
+        *cyls = size /MEDHEADS/MEDSECS;
+        if (*cyls <= MAXCYLS) {
+            *heads = MEDHEADS;
+            *secs = MEDSECS;
+        } else {                                    /* too high for 127*63 */
+            *cyls = size /BIGHEADS/BIGSECS;
+            *heads = BIGHEADS;
+            *secs = BIGSECS;
+        }
+    }
+}
+
+/* controller search and initialization functions */
+
+static int __init gdth_search_eisa(ushort eisa_adr)
+{
+    ulong32 id;
+    
+    TRACE(("gdth_search_eisa() adr. %x\n",eisa_adr));
+    id = inl(eisa_adr+ID0REG);
+    if (id == GDT3A_ID || id == GDT3B_ID) {     /* GDT3000A or GDT3000B */
+        if ((inb(eisa_adr+EISAREG) & 8) == 0)   
+            return 0;                           /* not EISA configured */
+        return 1;
+    }
+    if (id == GDT3_ID)                          /* GDT3000 */
+        return 1;
+
+    return 0;                                   
+}
+
+
+static int __init gdth_search_isa(ulong32 bios_adr)
+{
+    void __iomem *addr;
+    ulong32 id;
+
+    TRACE(("gdth_search_isa() bios adr. %x\n",bios_adr));
+    if ((addr = ioremap(bios_adr+BIOS_ID_OFFS, sizeof(ulong32))) != NULL) {
+        id = gdth_readl(addr);
+        iounmap(addr);
+        if (id == GDT2_ID)                          /* GDT2000 */
+            return 1;
+    }
+    return 0;
+}
+
+
+static int __init gdth_search_pci(gdth_pci_str *pcistr)
+{
+    ushort device, cnt;
+    
+    TRACE(("gdth_search_pci()\n"));
+
+    cnt = 0;
+    for (device = 0; device <= PCI_DEVICE_ID_VORTEX_GDT6555; ++device)
+        gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device);
+    for (device = PCI_DEVICE_ID_VORTEX_GDT6x17RP; 
+         device <= PCI_DEVICE_ID_VORTEX_GDTMAXRP; ++device)
+        gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, device);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
+                    PCI_DEVICE_ID_VORTEX_GDTNEWRX);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_VORTEX, 
+                    PCI_DEVICE_ID_VORTEX_GDTNEWRX2);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
+                    PCI_DEVICE_ID_INTEL_SRC);
+    gdth_search_dev(pcistr, &cnt, PCI_VENDOR_ID_INTEL,
+                    PCI_DEVICE_ID_INTEL_SRC_XSCALE);
+    return cnt;
+}
+
+/* Vortex only makes RAID controllers.
+ * We do not really want to specify all 550 ids here, so wildcard match.
+ */
+static struct pci_device_id gdthtable[] __attribute_used__ = {
+    {PCI_VENDOR_ID_VORTEX,PCI_ANY_ID,PCI_ANY_ID, PCI_ANY_ID},
+    {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC,PCI_ANY_ID,PCI_ANY_ID}, 
+    {PCI_VENDOR_ID_INTEL,PCI_DEVICE_ID_INTEL_SRC_XSCALE,PCI_ANY_ID,PCI_ANY_ID}, 
+    {0}
+};
+MODULE_DEVICE_TABLE(pci,gdthtable);
+
+static void __init gdth_search_dev(gdth_pci_str *pcistr, ushort *cnt,
+                                           ushort vendor, ushort device)
+{
+    ulong base0, base1, base2;
+    struct pci_dev *pdev;
+    
+    TRACE(("gdth_search_dev() cnt %d vendor %x device %x\n",
+          *cnt, vendor, device));
+
+    pdev = NULL;
+    while ((pdev = pci_find_device(vendor, device, pdev)) 
+           != NULL) {
+        if (pci_enable_device(pdev))
+            continue;
+        if (*cnt >= MAXHA)
+            return;
+        /* GDT PCI controller found, resources are already in pdev */
+        pcistr[*cnt].pdev = pdev;
+        pcistr[*cnt].vendor_id = vendor;
+        pcistr[*cnt].device_id = device;
+        pcistr[*cnt].subdevice_id = pdev->subsystem_device;
+        pcistr[*cnt].bus = pdev->bus->number;
+        pcistr[*cnt].device_fn = pdev->devfn;
+        pcistr[*cnt].irq = pdev->irq;
+        base0 = pci_resource_flags(pdev, 0);
+        base1 = pci_resource_flags(pdev, 1);
+        base2 = pci_resource_flags(pdev, 2);
+        if (device <= PCI_DEVICE_ID_VORTEX_GDT6000B ||   /* GDT6000/B */
+            device >= PCI_DEVICE_ID_VORTEX_GDT6x17RP) {  /* MPR */
+            if (!(base0 & IORESOURCE_MEM)) 
+                continue;
+            pcistr[*cnt].dpmem = pci_resource_start(pdev, 0);
+        } else {                                  /* GDT6110, GDT6120, .. */
+            if (!(base0 & IORESOURCE_MEM) ||
+                !(base2 & IORESOURCE_MEM) ||
+                !(base1 & IORESOURCE_IO)) 
+                continue;
+            pcistr[*cnt].dpmem = pci_resource_start(pdev, 2);
+            pcistr[*cnt].io_mm = pci_resource_start(pdev, 0);
+            pcistr[*cnt].io    = pci_resource_start(pdev, 1);
+        }
+        TRACE2(("Controller found at %d/%d, irq %d, dpmem 0x%lx\n",
+                pcistr[*cnt].bus, PCI_SLOT(pcistr[*cnt].device_fn), 
+                pcistr[*cnt].irq, pcistr[*cnt].dpmem));
+        (*cnt)++;
+    }       
+}   
+
+
+static void __init gdth_sort_pci(gdth_pci_str *pcistr, int cnt)
+{    
+    gdth_pci_str temp;
+    int i, changed;
+    
+    TRACE(("gdth_sort_pci() cnt %d\n",cnt));
+    if (cnt == 0)
+        return;
+
+    do {
+        changed = FALSE;
+        for (i = 0; i < cnt-1; ++i) {
+            if (!reverse_scan) {
+                if ((pcistr[i].bus > pcistr[i+1].bus) ||
+                    (pcistr[i].bus == pcistr[i+1].bus &&
+                     PCI_SLOT(pcistr[i].device_fn) > 
+                     PCI_SLOT(pcistr[i+1].device_fn))) {
+                    temp = pcistr[i];
+                    pcistr[i] = pcistr[i+1];
+                    pcistr[i+1] = temp;
+                    changed = TRUE;
+                }
+            } else {
+                if ((pcistr[i].bus < pcistr[i+1].bus) ||
+                    (pcistr[i].bus == pcistr[i+1].bus &&
+                     PCI_SLOT(pcistr[i].device_fn) < 
+                     PCI_SLOT(pcistr[i+1].device_fn))) {
+                    temp = pcistr[i];
+                    pcistr[i] = pcistr[i+1];
+                    pcistr[i+1] = temp;
+                    changed = TRUE;
+                }
+            }
+        }
+    } while (changed);
+}
+
+
+static int __init gdth_init_eisa(ushort eisa_adr,gdth_ha_str *ha)
+{
+    ulong32 retries,id;
+    unchar prot_ver,eisacf,i,irq_found;
+
+    TRACE(("gdth_init_eisa() adr. %x\n",eisa_adr));
+    
+    /* disable board interrupts, deinitialize services */
+    outb(0xff,eisa_adr+EDOORREG);
+    outb(0x00,eisa_adr+EDENABREG);
+    outb(0x00,eisa_adr+EINTENABREG);
+    
+    outb(0xff,eisa_adr+LDOORREG);
+    retries = INIT_RETRIES;
+    gdth_delay(20);
+    while (inb(eisa_adr+EDOORREG) != 0xff) {
+        if (--retries == 0) {
+            printk("GDT-EISA: Initialization error (DEINIT failed)\n");
+            return 0;
+        }
+        gdth_delay(1);
+        TRACE2(("wait for DEINIT: retries=%d\n",retries));
+    }
+    prot_ver = inb(eisa_adr+MAILBOXREG);
+    outb(0xff,eisa_adr+EDOORREG);
+    if (prot_ver != PROTOCOL_VERSION) {
+        printk("GDT-EISA: Illegal protocol version\n");
+        return 0;
+    }
+    ha->bmic = eisa_adr;
+    ha->brd_phys = (ulong32)eisa_adr >> 12;
+
+    outl(0,eisa_adr+MAILBOXREG);
+    outl(0,eisa_adr+MAILBOXREG+4);
+    outl(0,eisa_adr+MAILBOXREG+8);
+    outl(0,eisa_adr+MAILBOXREG+12);
+
+    /* detect IRQ */ 
+    if ((id = inl(eisa_adr+ID0REG)) == GDT3_ID) {
+        ha->oem_id = OEM_ID_ICP;
+        ha->type = GDT_EISA;
+        ha->stype = id;
+        outl(1,eisa_adr+MAILBOXREG+8);
+        outb(0xfe,eisa_adr+LDOORREG);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (inb(eisa_adr+EDOORREG) != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-EISA: Initialization error (get IRQ failed)\n");
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        ha->irq = inb(eisa_adr+MAILBOXREG);
+        outb(0xff,eisa_adr+EDOORREG);
+        TRACE2(("GDT3000/3020: IRQ=%d\n",ha->irq));
+        /* check the result */
+        if (ha->irq == 0) {
+                TRACE2(("Unknown IRQ, use IRQ table from cmd line !\n"));
+                for (i = 0, irq_found = FALSE; 
+                     i < MAXHA && irq[i] != 0xff; ++i) {
+                if (irq[i]==10 || irq[i]==11 || irq[i]==12 || irq[i]==14) {
+                    irq_found = TRUE;
+                    break;
+                }
+                }
+            if (irq_found) {
+                ha->irq = irq[i];
+                irq[i] = 0;
+                printk("GDT-EISA: Can not detect controller IRQ,\n");
+                printk("Use IRQ setting from command line (IRQ = %d)\n",
+                       ha->irq);
+            } else {
+                printk("GDT-EISA: Initialization error (unknown IRQ), Enable\n");
+                printk("the controller BIOS or use command line parameters\n");
+                return 0;
+            }
+        }
+    } else {
+        eisacf = inb(eisa_adr+EISAREG) & 7;
+        if (eisacf > 4)                         /* level triggered */
+            eisacf -= 4;
+        ha->irq = gdth_irq_tab[eisacf];
+        ha->oem_id = OEM_ID_ICP;
+        ha->type = GDT_EISA;
+        ha->stype = id;
+    }
+
+    ha->dma64_support = 0;
+    return 1;
+}
+
+       
+static int __init gdth_init_isa(ulong32 bios_adr,gdth_ha_str *ha)
+{
+    register gdt2_dpram_str __iomem *dp2_ptr;
+    int i;
+    unchar irq_drq,prot_ver;
+    ulong32 retries;
+
+    TRACE(("gdth_init_isa() bios adr. %x\n",bios_adr));
+
+    ha->brd = ioremap(bios_adr, sizeof(gdt2_dpram_str));
+    if (ha->brd == NULL) {
+        printk("GDT-ISA: Initialization error (DPMEM remap error)\n");
+        return 0;
+    }
+    dp2_ptr = ha->brd;
+    gdth_writeb(1, &dp2_ptr->io.memlock); /* switch off write protection */
+    /* reset interface area */
+    memset_io(&dp2_ptr->u, 0, sizeof(dp2_ptr->u));
+    if (gdth_readl(&dp2_ptr->u) != 0) {
+        printk("GDT-ISA: Initialization error (DPMEM write error)\n");
+        iounmap(ha->brd);
+        return 0;
+    }
+
+    /* disable board interrupts, read DRQ and IRQ */
+    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+    gdth_writeb(0x00, &dp2_ptr->io.irqen);
+    gdth_writeb(0x00, &dp2_ptr->u.ic.S_Status);
+    gdth_writeb(0x00, &dp2_ptr->u.ic.Cmd_Index);
+
+    irq_drq = gdth_readb(&dp2_ptr->io.rq);
+    for (i=0; i<3; ++i) {
+        if ((irq_drq & 1)==0)
+            break;
+        irq_drq >>= 1;
+    }
+    ha->drq = gdth_drq_tab[i];
+
+    irq_drq = gdth_readb(&dp2_ptr->io.rq) >> 3;
+    for (i=1; i<5; ++i) {
+        if ((irq_drq & 1)==0)
+            break;
+        irq_drq >>= 1;
+    }
+    ha->irq = gdth_irq_tab[i];
+
+    /* deinitialize services */
+    gdth_writel(bios_adr, &dp2_ptr->u.ic.S_Info[0]);
+    gdth_writeb(0xff, &dp2_ptr->u.ic.S_Cmd_Indx);
+    gdth_writeb(0, &dp2_ptr->io.event);
+    retries = INIT_RETRIES;
+    gdth_delay(20);
+    while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xff) {
+        if (--retries == 0) {
+            printk("GDT-ISA: Initialization error (DEINIT failed)\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+        gdth_delay(1);
+    }
+    prot_ver = (unchar)gdth_readl(&dp2_ptr->u.ic.S_Info[0]);
+    gdth_writeb(0, &dp2_ptr->u.ic.Status);
+    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+    if (prot_ver != PROTOCOL_VERSION) {
+        printk("GDT-ISA: Illegal protocol version\n");
+        iounmap(ha->brd);
+        return 0;
+    }
+
+    ha->oem_id = OEM_ID_ICP;
+    ha->type = GDT_ISA;
+    ha->ic_all_size = sizeof(dp2_ptr->u);
+    ha->stype= GDT2_ID;
+    ha->brd_phys = bios_adr >> 4;
+
+    /* special request to controller BIOS */
+    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[0]);
+    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[1]);
+    gdth_writel(0x01, &dp2_ptr->u.ic.S_Info[2]);
+    gdth_writel(0x00, &dp2_ptr->u.ic.S_Info[3]);
+    gdth_writeb(0xfe, &dp2_ptr->u.ic.S_Cmd_Indx);
+    gdth_writeb(0, &dp2_ptr->io.event);
+    retries = INIT_RETRIES;
+    gdth_delay(20);
+    while (gdth_readb(&dp2_ptr->u.ic.S_Status) != 0xfe) {
+        if (--retries == 0) {
+            printk("GDT-ISA: Initialization error\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+        gdth_delay(1);
+    }
+    gdth_writeb(0, &dp2_ptr->u.ic.Status);
+    gdth_writeb(0xff, &dp2_ptr->io.irqdel);
+
+    ha->dma64_support = 0;
+    return 1;
+}
+
+
+static int __init gdth_init_pci(gdth_pci_str *pcistr,gdth_ha_str *ha)
+{
+    register gdt6_dpram_str __iomem *dp6_ptr;
+    register gdt6c_dpram_str __iomem *dp6c_ptr;
+    register gdt6m_dpram_str __iomem *dp6m_ptr;
+    ulong32 retries;
+    unchar prot_ver;
+    ushort command;
+    int i, found = FALSE;
+
+    TRACE(("gdth_init_pci()\n"));
+
+    if (pcistr->vendor_id == PCI_VENDOR_ID_INTEL)
+        ha->oem_id = OEM_ID_INTEL;
+    else
+        ha->oem_id = OEM_ID_ICP;
+    ha->brd_phys = (pcistr->bus << 8) | (pcistr->device_fn & 0xf8);
+    ha->stype = (ulong32)pcistr->device_id;
+    ha->subdevice_id = pcistr->subdevice_id;
+    ha->irq = pcistr->irq;
+    ha->pdev = pcistr->pdev;
+    
+    if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6000B) {  /* GDT6000/B */
+        TRACE2(("init_pci() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6_dpram_str));
+        if (ha->brd == NULL) {
+            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+            return 0;
+        }
+        /* check and reset interface area */
+        dp6_ptr = ha->brd;
+        gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+        if (gdth_readl(&dp6_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_old() address 0x%x busy\n", i));
+                    continue;
+                }
+                iounmap(ha->brd);
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_0, i);
+                ha->brd = ioremap(i, sizeof(gdt6_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6_ptr = ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6_ptr->u);
+                if (gdth_readl(&dp6_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+        }
+        memset_io(&dp6_ptr->u, 0, sizeof(dp6_ptr->u));
+        if (gdth_readl(&dp6_ptr->u) != 0) {
+            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+        
+        /* disable board interrupts, deinit services */
+        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+        gdth_writeb(0x00, &dp6_ptr->io.irqen);
+        gdth_writeb(0x00, &dp6_ptr->u.ic.S_Status);
+        gdth_writeb(0x00, &dp6_ptr->u.ic.Cmd_Index);
+
+        gdth_writel(pcistr->dpmem, &dp6_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0xff, &dp6_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(0, &dp6_ptr->io.event);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        prot_ver = (unchar)gdth_readl(&dp6_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
+        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+
+        ha->type = GDT_PCI;
+        ha->ic_all_size = sizeof(dp6_ptr->u);
+        
+        /* special command to controller BIOS */
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[0]);
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[1]);
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6_ptr->u.ic.S_Info[3]);
+        gdth_writeb(0xfe, &dp6_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(0, &dp6_ptr->io.event);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6_ptr->u.ic.S_Status) != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        gdth_writeb(0, &dp6_ptr->u.ic.S_Status);
+        gdth_writeb(0xff, &dp6_ptr->io.irqdel);
+
+        ha->dma64_support = 0;
+
+    } else if (ha->stype <= PCI_DEVICE_ID_VORTEX_GDT6555) { /* GDT6110, ... */
+        ha->plx = (gdt6c_plx_regs *)pcistr->io;
+        TRACE2(("init_pci_new() dpmem %lx irq %d\n",
+            pcistr->dpmem,ha->irq));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6c_dpram_str));
+        if (ha->brd == NULL) {
+            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+        /* check and reset interface area */
+        dp6c_ptr = ha->brd;
+        gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+        if (gdth_readl(&dp6c_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_plx() address 0x%x busy\n", i));
+                    continue;
+                }
+                iounmap(ha->brd);
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_2, i);
+                ha->brd = ioremap(i, sizeof(gdt6c_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6c_ptr = ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6c_ptr->u);
+                if (gdth_readl(&dp6c_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+        }
+        memset_io(&dp6c_ptr->u, 0, sizeof(dp6c_ptr->u));
+        if (gdth_readl(&dp6c_ptr->u) != 0) {
+            printk("GDT-PCI: Initialization error (DPMEM write error)\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+        
+        /* disable board interrupts, deinit services */
+        outb(0x00,PTR2USHORT(&ha->plx->control1));
+        outb(0xff,PTR2USHORT(&ha->plx->edoor_reg));
+        
+        gdth_writeb(0x00, &dp6c_ptr->u.ic.S_Status);
+        gdth_writeb(0x00, &dp6c_ptr->u.ic.Cmd_Index);
+
+        gdth_writel(pcistr->dpmem, &dp6c_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0xff, &dp6c_ptr->u.ic.S_Cmd_Indx);
+
+        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        prot_ver = (unchar)gdth_readl(&dp6c_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0, &dp6c_ptr->u.ic.Status);
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+
+        ha->type = GDT_PCINEW;
+        ha->ic_all_size = sizeof(dp6c_ptr->u);
+
+        /* special command to controller BIOS */
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[0]);
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[1]);
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6c_ptr->u.ic.S_Info[3]);
+        gdth_writeb(0xfe, &dp6c_ptr->u.ic.S_Cmd_Indx);
+        
+        outb(1,PTR2USHORT(&ha->plx->ldoor_reg));
+
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6c_ptr->u.ic.S_Status) != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        gdth_writeb(0, &dp6c_ptr->u.ic.S_Status);
+
+        ha->dma64_support = 0;
+
+    } else {                                            /* MPR */
+        TRACE2(("init_pci_mpr() dpmem %lx irq %d\n",pcistr->dpmem,ha->irq));
+        ha->brd = ioremap(pcistr->dpmem, sizeof(gdt6m_dpram_str));
+        if (ha->brd == NULL) {
+            printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+            return 0;
+        }
+
+        /* manipulate config. space to enable DPMEM, start RP controller */
+        pci_read_config_word(pcistr->pdev, PCI_COMMAND, &command);
+        command |= 6;
+        pci_write_config_word(pcistr->pdev, PCI_COMMAND, command);
+        if (pci_resource_start(pcistr->pdev, 8) == 1UL)
+            pci_resource_start(pcistr->pdev, 8) = 0UL;
+        i = 0xFEFF0001UL;
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS, i);
+        gdth_delay(1);
+        pci_write_config_dword(pcistr->pdev, PCI_ROM_ADDRESS,
+                               pci_resource_start(pcistr->pdev, 8));
+        
+        dp6m_ptr = ha->brd;
+
+        /* Ensure that it is safe to access the non HW portions of DPMEM.
+         * Aditional check needed for Xscale based RAID controllers */
+        while( ((int)gdth_readb(&dp6m_ptr->i960r.sema0_reg) ) & 3 )
+            gdth_delay(1);
+        
+        /* check and reset interface area */
+        gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
+        if (gdth_readl(&dp6m_ptr->u) != DPMEM_MAGIC) {
+            printk("GDT-PCI: Cannot access DPMEM at 0x%lx (shadowed?)\n", 
+                   pcistr->dpmem);
+            found = FALSE;
+            for (i = 0xC8000; i < 0xE8000; i += 0x4000) {
+                iounmap(ha->brd);
+                ha->brd = ioremap(i, sizeof(ushort)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                if (gdth_readw(ha->brd) != 0xffff) {
+                    TRACE2(("init_pci_mpr() address 0x%x busy\n", i));
+                    continue;
+                }
+                iounmap(ha->brd);
+                pci_write_config_dword(pcistr->pdev, 
+                                       PCI_BASE_ADDRESS_0, i);
+                ha->brd = ioremap(i, sizeof(gdt6m_dpram_str)); 
+                if (ha->brd == NULL) {
+                    printk("GDT-PCI: Initialization error (DPMEM remap error)\n");
+                    return 0;
+                }
+                dp6m_ptr = ha->brd;
+                gdth_writel(DPMEM_MAGIC, &dp6m_ptr->u);
+                if (gdth_readl(&dp6m_ptr->u) == DPMEM_MAGIC) {
+                    printk("GDT-PCI: Use free address at 0x%x\n", i);
+                    found = TRUE;
+                    break;
+                }
+            }   
+            if (!found) {
+                printk("GDT-PCI: No free address found!\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+        }
+        memset_io(&dp6m_ptr->u, 0, sizeof(dp6m_ptr->u));
+        
+        /* disable board interrupts, deinit services */
+        gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) | 4,
+                    &dp6m_ptr->i960r.edoor_en_reg);
+        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        gdth_writeb(0x00, &dp6m_ptr->u.ic.S_Status);
+        gdth_writeb(0x00, &dp6m_ptr->u.ic.Cmd_Index);
+
+        gdth_writel(pcistr->dpmem, &dp6m_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0xff, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xff) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        prot_ver = (unchar)gdth_readl(&dp6m_ptr->u.ic.S_Info[0]);
+        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        if (prot_ver != PROTOCOL_VERSION) {
+            printk("GDT-PCI: Illegal protocol version\n");
+            iounmap(ha->brd);
+            return 0;
+        }
+
+        ha->type = GDT_PCIMPR;
+        ha->ic_all_size = sizeof(dp6m_ptr->u);
+        
+        /* special command to controller BIOS */
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[0]);
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[1]);
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[2]);
+        gdth_writel(0x00, &dp6m_ptr->u.ic.S_Info[3]);
+        gdth_writeb(0xfe, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfe) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+
+        /* read FW version to detect 64-bit DMA support */
+        gdth_writeb(0xfd, &dp6m_ptr->u.ic.S_Cmd_Indx);
+        gdth_writeb(1, &dp6m_ptr->i960r.ldoor_reg);
+        retries = INIT_RETRIES;
+        gdth_delay(20);
+        while (gdth_readb(&dp6m_ptr->u.ic.S_Status) != 0xfd) {
+            if (--retries == 0) {
+                printk("GDT-PCI: Initialization error (DEINIT failed)\n");
+                iounmap(ha->brd);
+                return 0;
+            }
+            gdth_delay(1);
+        }
+        prot_ver = (unchar)(gdth_readl(&dp6m_ptr->u.ic.S_Info[0]) >> 16);
+        gdth_writeb(0, &dp6m_ptr->u.ic.S_Status);
+        if (prot_ver < 0x2b)      /* FW < x.43: no 64-bit DMA support */
+            ha->dma64_support = 0;
+        else 
+            ha->dma64_support = 1;
+    }
+
+    return 1;
+}
+
+
+/* controller protocol functions */
+
+static void __init gdth_enable_int(int hanum)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    gdt2_dpram_str __iomem *dp2_ptr;
+    gdt6_dpram_str __iomem *dp6_ptr;
+    gdt6m_dpram_str __iomem *dp6m_ptr;
+
+    TRACE(("gdth_enable_int() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    if (ha->type == GDT_EISA) {
+        outb(0xff, ha->bmic + EDOORREG);
+        outb(0xff, ha->bmic + EDENABREG);
+        outb(0x01, ha->bmic + EINTENABREG);
+    } else if (ha->type == GDT_ISA) {
+        dp2_ptr = ha->brd;
+        gdth_writeb(1, &dp2_ptr->io.irqdel);
+        gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);
+        gdth_writeb(1, &dp2_ptr->io.irqen);
+    } else if (ha->type == GDT_PCI) {
+        dp6_ptr = ha->brd;
+        gdth_writeb(1, &dp6_ptr->io.irqdel);
+        gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);
+        gdth_writeb(1, &dp6_ptr->io.irqen);
+    } else if (ha->type == GDT_PCINEW) {
+        outb(0xff, PTR2USHORT(&ha->plx->edoor_reg));
+        outb(0x03, PTR2USHORT(&ha->plx->control1));
+    } else if (ha->type == GDT_PCIMPR) {
+        dp6m_ptr = ha->brd;
+        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        gdth_writeb(gdth_readb(&dp6m_ptr->i960r.edoor_en_reg) & ~4,
+                    &dp6m_ptr->i960r.edoor_en_reg);
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+
+static int gdth_get_status(unchar *pIStatus,int irq)
+{
+    register gdth_ha_str *ha;
+    int i;
+
+    TRACE(("gdth_get_status() irq %d ctr_count %d\n",
+           irq,gdth_ctr_count));
+    
+    *pIStatus = 0;
+    for (i=0; i<gdth_ctr_count; ++i) {
+        ha = HADATA(gdth_ctr_tab[i]);
+        if (ha->irq != (unchar)irq)             /* check IRQ */
+            continue;
+        if (ha->type == GDT_EISA)
+            *pIStatus = inb((ushort)ha->bmic + EDOORREG);
+        else if (ha->type == GDT_ISA)
+            *pIStatus =
+                gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+        else if (ha->type == GDT_PCI)
+            *pIStatus =
+                gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Cmd_Index);
+        else if (ha->type == GDT_PCINEW) 
+            *pIStatus = inb(PTR2USHORT(&ha->plx->edoor_reg));
+        else if (ha->type == GDT_PCIMPR)
+            *pIStatus =
+                gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.edoor_reg);
+   
+        if (*pIStatus)                                  
+            return i;                           /* board found */
+    }
+    return -1;
+}
+                 
+    
+static int gdth_test_busy(int hanum)
+{
+    register gdth_ha_str *ha;
+    register int gdtsema0 = 0;
+
+    TRACE(("gdth_test_busy() hanum %d\n",hanum));
+    
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (ha->type == GDT_EISA)
+        gdtsema0 = (int)inb(ha->bmic + SEMA0REG);
+    else if (ha->type == GDT_ISA)
+        gdtsema0 = (int)gdth_readb(&((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+    else if (ha->type == GDT_PCI)
+        gdtsema0 = (int)gdth_readb(&((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+    else if (ha->type == GDT_PCINEW) 
+        gdtsema0 = (int)inb(PTR2USHORT(&ha->plx->sema0_reg));
+    else if (ha->type == GDT_PCIMPR)
+        gdtsema0 = 
+            (int)gdth_readb(&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+
+    return (gdtsema0 & 1);
+}
+
+
+static int gdth_get_cmd_index(int hanum)
+{
+    register gdth_ha_str *ha;
+    int i;
+
+    TRACE(("gdth_get_cmd_index() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    for (i=0; i<GDTH_MAXCMDS; ++i) {
+        if (ha->cmd_tab[i].cmnd == UNUSED_CMND) {
+            ha->cmd_tab[i].cmnd = ha->pccb->RequestBuffer;
+            ha->cmd_tab[i].service = ha->pccb->Service;
+            ha->pccb->CommandIndex = (ulong32)i+2;
+            return (i+2);
+        }
+    }
+    return 0;
+}
+
+
+static void gdth_set_sema0(int hanum)
+{
+    register gdth_ha_str *ha;
+
+    TRACE(("gdth_set_sema0() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (ha->type == GDT_EISA) {
+        outb(1, ha->bmic + SEMA0REG);
+    } else if (ha->type == GDT_ISA) {
+        gdth_writeb(1, &((gdt2_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+    } else if (ha->type == GDT_PCI) {
+        gdth_writeb(1, &((gdt6_dpram_str __iomem *)ha->brd)->u.ic.Sema0);
+    } else if (ha->type == GDT_PCINEW) { 
+        outb(1, PTR2USHORT(&ha->plx->sema0_reg));
+    } else if (ha->type == GDT_PCIMPR) {
+        gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.sema0_reg);
+    }
+}
+
+
+static void gdth_copy_command(int hanum)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmd_ptr;
+    register gdt6m_dpram_str __iomem *dp6m_ptr;
+    register gdt6c_dpram_str __iomem *dp6c_ptr;
+    gdt6_dpram_str __iomem *dp6_ptr;
+    gdt2_dpram_str __iomem *dp2_ptr;
+    ushort cp_count,dp_offset,cmd_no;
+    
+    TRACE(("gdth_copy_command() hanum %d\n",hanum));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cp_count = ha->cmd_len;
+    dp_offset= ha->cmd_offs_dpmem;
+    cmd_no   = ha->cmd_cnt;
+    cmd_ptr  = ha->pccb;
+
+    ++ha->cmd_cnt;                                                      
+    if (ha->type == GDT_EISA)
+        return;                                 /* no DPMEM, no copy */
+
+    /* set cpcount dword aligned */
+    if (cp_count & 3)
+        cp_count += (4 - (cp_count & 3));
+
+    ha->cmd_offs_dpmem += cp_count;
+    
+    /* set offset and service, copy command to DPMEM */
+    if (ha->type == GDT_ISA) {
+        dp2_ptr = ha->brd;
+        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+                    &dp2_ptr->u.ic.comm_queue[cmd_no].offset);
+        gdth_writew((ushort)cmd_ptr->Service, 
+                    &dp2_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp2_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCI) {
+        dp6_ptr = ha->brd;
+        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+                    &dp6_ptr->u.ic.comm_queue[cmd_no].offset);
+        gdth_writew((ushort)cmd_ptr->Service, 
+                    &dp6_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp6_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCINEW) {
+        dp6c_ptr = ha->brd;
+        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+                    &dp6c_ptr->u.ic.comm_queue[cmd_no].offset);
+        gdth_writew((ushort)cmd_ptr->Service, 
+                    &dp6c_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp6c_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    } else if (ha->type == GDT_PCIMPR) {
+        dp6m_ptr = ha->brd;
+        gdth_writew(dp_offset + DPMEM_COMMAND_OFFSET, 
+                    &dp6m_ptr->u.ic.comm_queue[cmd_no].offset);
+        gdth_writew((ushort)cmd_ptr->Service, 
+                    &dp6m_ptr->u.ic.comm_queue[cmd_no].serv_id);
+        memcpy_toio(&dp6m_ptr->u.ic.gdt_dpr_cmd[dp_offset],cmd_ptr,cp_count);
+    }
+}
+
+
+static void gdth_release_event(int hanum)
+{
+    register gdth_ha_str *ha;
+
+    TRACE(("gdth_release_event() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+#ifdef GDTH_STATISTICS
+    {
+        ulong32 i,j;
+        for (i=0,j=0; j<GDTH_MAXCMDS; ++j) {
+            if (ha->cmd_tab[j].cmnd != UNUSED_CMND)
+                ++i;
+        }
+        if (max_index < i) {
+            max_index = i;
+            TRACE3(("GDT: max_index = %d\n",(ushort)i));
+        }
+    }
+#endif
+
+    if (ha->pccb->OpCode == GDT_INIT)
+        ha->pccb->Service |= 0x80;
+
+    if (ha->type == GDT_EISA) {
+        if (ha->pccb->OpCode == GDT_INIT)               /* store DMA buffer */
+            outl(ha->ccb_phys, ha->bmic + MAILBOXREG);
+        outb(ha->pccb->Service, ha->bmic + LDOORREG);
+    } else if (ha->type == GDT_ISA) {
+        gdth_writeb(0, &((gdt2_dpram_str __iomem *)ha->brd)->io.event);
+    } else if (ha->type == GDT_PCI) {
+        gdth_writeb(0, &((gdt6_dpram_str __iomem *)ha->brd)->io.event);
+    } else if (ha->type == GDT_PCINEW) { 
+        outb(1, PTR2USHORT(&ha->plx->ldoor_reg));
+    } else if (ha->type == GDT_PCIMPR) {
+        gdth_writeb(1, &((gdt6m_dpram_str __iomem *)ha->brd)->i960r.ldoor_reg);
+    }
+}
+
+    
+static int gdth_wait(int hanum,int index,ulong32 time)
+{
+    gdth_ha_str *ha;
+    int answer_found = FALSE;
+
+    TRACE(("gdth_wait() hanum %d index %d time %d\n",hanum,index,time));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (index == 0)
+        return 1;                               /* no wait required */
+
+    gdth_from_wait = TRUE;
+    do {
+        gdth_interrupt((int)ha->irq,ha,NULL);
+        if (wait_hanum==hanum && wait_index==index) {
+            answer_found = TRUE;
+            break;
+        }
+        gdth_delay(1);
+    } while (--time);
+    gdth_from_wait = FALSE;
+    
+    while (gdth_test_busy(hanum))
+        gdth_delay(0);
+
+    return (answer_found);
+}
+
+
+static int gdth_internal_cmd(int hanum,unchar service,ushort opcode,ulong32 p1,
+                             ulong64 p2,ulong64 p3)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmd_ptr;
+    int retries,index;
+
+    TRACE2(("gdth_internal_cmd() service %d opcode %d\n",service,opcode));
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cmd_ptr = ha->pccb;
+    memset((char*)cmd_ptr,0,sizeof(gdth_cmd_str));
+
+    /* make command  */
+    for (retries = INIT_RETRIES;;) {
+        cmd_ptr->Service          = service;
+        cmd_ptr->RequestBuffer    = INTERNAL_CMND;
+        if (!(index=gdth_get_cmd_index(hanum))) {
+            TRACE(("GDT: No free command index found\n"));
+            return 0;
+        }
+        gdth_set_sema0(hanum);
+        cmd_ptr->OpCode           = opcode;
+        cmd_ptr->BoardNode        = LOCALBOARD;
+        if (service == CACHESERVICE) {
+            if (opcode == GDT_IOCTL) {
+                cmd_ptr->u.ioctl.subfunc = p1;
+                cmd_ptr->u.ioctl.channel = (ulong32)p2;
+                cmd_ptr->u.ioctl.param_size = (ushort)p3;
+                cmd_ptr->u.ioctl.p_param = ha->scratch_phys;
+            } else {
+                if (ha->cache_feat & GDT_64BIT) {
+                    cmd_ptr->u.cache64.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache64.BlockNo  = p2;
+                } else {
+                    cmd_ptr->u.cache.DeviceNo = (ushort)p1;
+                    cmd_ptr->u.cache.BlockNo  = (ulong32)p2;
+                }
+            }
+        } else if (service == SCSIRAWSERVICE) {
+            if (ha->raw_feat & GDT_64BIT) {
+                cmd_ptr->u.raw64.direction  = p1;
+                cmd_ptr->u.raw64.bus        = (unchar)p2;
+                cmd_ptr->u.raw64.target     = (unchar)p3;
+                cmd_ptr->u.raw64.lun        = (unchar)(p3 >> 8);
+            } else {
+                cmd_ptr->u.raw.direction  = p1;
+                cmd_ptr->u.raw.bus        = (unchar)p2;
+                cmd_ptr->u.raw.target     = (unchar)p3;
+                cmd_ptr->u.raw.lun        = (unchar)(p3 >> 8);
+            }
+        } else if (service == SCREENSERVICE) {
+            if (opcode == GDT_REALTIME) {
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[0] = p1;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[4] = (ulong32)p2;
+                *(ulong32 *)&cmd_ptr->u.screen.su.data[8] = (ulong32)p3;
+            }
+        }
+        ha->cmd_len          = sizeof(gdth_cmd_str);
+        ha->cmd_offs_dpmem   = 0;
+        ha->cmd_cnt          = 0;
+        gdth_copy_command(hanum);
+        gdth_release_event(hanum);
+        gdth_delay(20);
+        if (!gdth_wait(hanum,index,INIT_TIMEOUT)) {
+            printk("GDT: Initialization error (timeout service %d)\n",service);
+            return 0;
+        }
+        if (ha->status != S_BSY || --retries == 0)
+            break;
+        gdth_delay(1);   
+    }   
+    
+    return (ha->status != S_OK ? 0:1);
+}
+    
+
+/* search for devices */
+
+static int __init gdth_search_drives(int hanum)
+{
+    register gdth_ha_str *ha;
+    ushort cdev_cnt, i;
+    int ok;
+    ulong32 bus_no, drv_cnt, drv_no, j;
+    gdth_getch_str *chn;
+    gdth_drlist_str *drl;
+    gdth_iochan_str *ioc;
+    gdth_raw_iochan_str *iocr;
+    gdth_arcdl_str *alst;
+    gdth_alist_str *alst2;
+    gdth_oem_str_ioctl *oemstr;
+#ifdef INT_COAL
+    gdth_perf_modes *pmod;
+#endif
+
+#ifdef GDTH_RTC
+    unchar rtc[12];
+    ulong flags;
+#endif     
+   
+    TRACE(("gdth_search_drives() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    ok = 0;
+
+    /* initialize controller services, at first: screen service */
+    ha->screen_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_X_INIT_SCR,0,0,0);
+        if (ok)
+            ha->screen_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCREENSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error screen service (code %d)\n",
+               hanum, ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): SCREENSERVICE initialized\n"));
+
+#ifdef GDTH_RTC
+    /* read realtime clock info, send to controller */
+    /* 1. wait for the falling edge of update flag */
+    spin_lock_irqsave(&rtc_lock, flags);
+    for (j = 0; j < 1000000; ++j)
+        if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+            break;
+    for (j = 0; j < 1000000; ++j)
+        if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+            break;
+    /* 2. read info */
+    do {
+        for (j = 0; j < 12; ++j) 
+            rtc[j] = CMOS_READ(j);
+    } while (rtc[0] != CMOS_READ(0));
+    spin_lock_irqrestore(&rtc_lock, flags);
+    TRACE2(("gdth_search_drives(): RTC: %x/%x/%x\n",*(ulong32 *)&rtc[0],
+            *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]));
+    /* 3. send to controller firmware */
+    gdth_internal_cmd(hanum,SCREENSERVICE,GDT_REALTIME, *(ulong32 *)&rtc[0],
+                      *(ulong32 *)&rtc[4], *(ulong32 *)&rtc[8]);
+#endif  
+ 
+    /* unfreeze all IOs */
+    gdth_internal_cmd(hanum,CACHESERVICE,GDT_UNFREEZE_IO,0,0,0);
+ 
+    /* initialize cache service */
+    ha->cache_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INIT_HOST,LINUX_OS,0,0);
+        if (ok)
+            ha->cache_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,CACHESERVICE,GDT_INIT,LINUX_OS,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): CACHESERVICE initialized\n"));
+    cdev_cnt = (ushort)ha->info;
+    ha->fw_vers = ha->service;
+
+#ifdef INT_COAL
+    if (ha->type == GDT_PCIMPR) {
+        /* set perf. modes */
+        pmod = (gdth_perf_modes *)ha->pscratch;
+        pmod->version          = 1;
+        pmod->st_mode          = 1;    /* enable one status buffer */
+        *((ulong64 *)&pmod->st_buff_addr1) = ha->coal_stat_phys;
+        pmod->st_buff_indx1    = COALINDEX;
+        pmod->st_buff_addr2    = 0;
+        pmod->st_buff_u_addr2  = 0;
+        pmod->st_buff_indx2    = 0;
+        pmod->st_buff_size     = sizeof(gdth_coal_status) * MAXOFFSETS;
+        pmod->cmd_mode         = 0;    // disable all cmd buffers
+        pmod->cmd_buff_addr1   = 0;
+        pmod->cmd_buff_u_addr1 = 0;
+        pmod->cmd_buff_indx1   = 0;
+        pmod->cmd_buff_addr2   = 0;
+        pmod->cmd_buff_u_addr2 = 0;
+        pmod->cmd_buff_indx2   = 0;
+        pmod->cmd_buff_size    = 0;
+        pmod->reserved1        = 0;            
+        pmod->reserved2        = 0;            
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,SET_PERF_MODES,
+                              INVALID_CHANNEL,sizeof(gdth_perf_modes))) {
+            printk("GDT-HA %d: Interrupt coalescing activated\n", hanum);
+        }
+    }
+#endif
+
+    /* detect number of buses - try new IOCTL */
+    iocr = (gdth_raw_iochan_str *)ha->pscratch;
+    iocr->hdr.version        = 0xffffffff;
+    iocr->hdr.list_entries   = MAXBUS;
+    iocr->hdr.first_chan     = 0;
+    iocr->hdr.last_chan      = MAXBUS-1;
+    iocr->hdr.list_offset    = GDTOFFSOF(gdth_raw_iochan_str, list[0]);
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_RAW_DESC,
+                          INVALID_CHANNEL,sizeof(gdth_raw_iochan_str))) {
+        TRACE2(("IOCHAN_RAW_DESC supported!\n"));
+        ha->bus_cnt = iocr->hdr.chan_count;
+        for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+            if (iocr->list[bus_no].proc_id < MAXID)
+                ha->bus_id[bus_no] = iocr->list[bus_no].proc_id;
+            else
+                ha->bus_id[bus_no] = 0xff;
+        }
+    } else {
+        /* old method */
+        chn = (gdth_getch_str *)ha->pscratch;
+        for (bus_no = 0; bus_no < MAXBUS; ++bus_no) {
+            chn->channel_no = bus_no;
+            if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                   SCSI_CHAN_CNT | L_CTRL_PATTERN,
+                                   IO_CHANNEL | INVALID_CHANNEL,
+                                   sizeof(gdth_getch_str))) {
+                if (bus_no == 0) {
+                    printk("GDT-HA %d: Error detecting channel count (0x%x)\n",
+                           hanum, ha->status);
+                    return 0;
+                }
+                break;
+            }
+            if (chn->siop_id < MAXID)
+                ha->bus_id[bus_no] = chn->siop_id;
+            else
+                ha->bus_id[bus_no] = 0xff;
+        }       
+        ha->bus_cnt = (unchar)bus_no;
+    }
+    TRACE2(("gdth_search_drives() %d channels\n",ha->bus_cnt));
+
+    /* read cache configuration */
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_INFO,
+                           INVALID_CHANNEL,sizeof(gdth_cinfo_str))) {
+        printk("GDT-HA %d: Initialization error cache service (code %d)\n",
+               hanum, ha->status);
+        return 0;
+    }
+    ha->cpar = ((gdth_cinfo_str *)ha->pscratch)->cpar;
+    TRACE2(("gdth_search_drives() cinfo: vs %x sta %d str %d dw %d b %d\n",
+            ha->cpar.version,ha->cpar.state,ha->cpar.strategy,
+            ha->cpar.write_back,ha->cpar.block_size));
+
+    /* read board info and features */
+    ha->more_proc = FALSE;
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_INFO,
+                          INVALID_CHANNEL,sizeof(gdth_binfo_str))) {
+        memcpy(&ha->binfo, (gdth_binfo_str *)ha->pscratch,
+               sizeof(gdth_binfo_str));
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,BOARD_FEATURES,
+                              INVALID_CHANNEL,sizeof(gdth_bfeat_str))) {
+            TRACE2(("BOARD_INFO/BOARD_FEATURES supported\n"));
+            ha->bfeat = *(gdth_bfeat_str *)ha->pscratch;
+            ha->more_proc = TRUE;
+        }
+    } else {
+        TRACE2(("BOARD_INFO requires firmware >= 1.10/2.08\n"));
+        strcpy(ha->binfo.type_string, gdth_ctr_name(hanum));
+    }
+    TRACE2(("Controller name: %s\n",ha->binfo.type_string));
+
+    /* read more informations */
+    if (ha->more_proc) {
+        /* physical drives, channel addresses */
+        ioc = (gdth_iochan_str *)ha->pscratch;
+        ioc->hdr.version        = 0xffffffff;
+        ioc->hdr.list_entries   = MAXBUS;
+        ioc->hdr.first_chan     = 0;
+        ioc->hdr.last_chan      = MAXBUS-1;
+        ioc->hdr.list_offset    = GDTOFFSOF(gdth_iochan_str, list[0]);
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,IOCHAN_DESC,
+                              INVALID_CHANNEL,sizeof(gdth_iochan_str))) {
+            for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+                ha->raw[bus_no].address = ioc->list[bus_no].address;
+                ha->raw[bus_no].local_no = ioc->list[bus_no].local_no;
+            }
+        } else {
+            for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+                ha->raw[bus_no].address = IO_CHANNEL;
+                ha->raw[bus_no].local_no = bus_no;
+            }
+        }
+        for (bus_no = 0; bus_no < ha->bus_cnt; ++bus_no) {
+            chn = (gdth_getch_str *)ha->pscratch;
+            chn->channel_no = ha->raw[bus_no].local_no;
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                  SCSI_CHAN_CNT | L_CTRL_PATTERN,
+                                  ha->raw[bus_no].address | INVALID_CHANNEL,
+                                  sizeof(gdth_getch_str))) {
+                ha->raw[bus_no].pdev_cnt = chn->drive_cnt;
+                TRACE2(("Channel %d: %d phys. drives\n",
+                        bus_no,chn->drive_cnt));
+            }
+            if (ha->raw[bus_no].pdev_cnt > 0) {
+                drl = (gdth_drlist_str *)ha->pscratch;
+                drl->sc_no = ha->raw[bus_no].local_no;
+                drl->sc_cnt = ha->raw[bus_no].pdev_cnt;
+                if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                      SCSI_DR_LIST | L_CTRL_PATTERN,
+                                      ha->raw[bus_no].address | INVALID_CHANNEL,
+                                      sizeof(gdth_drlist_str))) {
+                    for (j = 0; j < ha->raw[bus_no].pdev_cnt; ++j) 
+                        ha->raw[bus_no].id_list[j] = drl->sc_list[j];
+                } else {
+                    ha->raw[bus_no].pdev_cnt = 0;
+                }
+            }
+        }
+
+        /* logical drives */
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_CNT,
+                              INVALID_CHANNEL,sizeof(ulong32))) {
+            drv_cnt = *(ulong32 *)ha->pscratch;
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,CACHE_DRV_LIST,
+                                  INVALID_CHANNEL,drv_cnt * sizeof(ulong32))) {
+                for (j = 0; j < drv_cnt; ++j) {
+                    drv_no = ((ulong32 *)ha->pscratch)[j];
+                    if (drv_no < MAX_LDRIVES) {
+                        ha->hdr[drv_no].is_logdrv = TRUE;
+                        TRACE2(("Drive %d is log. drive\n",drv_no));
+                    }
+                }
+            }
+            alst = (gdth_arcdl_str *)ha->pscratch;
+            alst->entries_avail = MAX_LDRIVES;
+            alst->first_entry = 0;
+            alst->list_offset = GDTOFFSOF(gdth_arcdl_str, list[0]);
+            if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                  ARRAY_DRV_LIST2 | LA_CTRL_PATTERN, 
+                                  INVALID_CHANNEL, sizeof(gdth_arcdl_str) +
+                                  (alst->entries_avail-1) * sizeof(gdth_alist_str))) { 
+                for (j = 0; j < alst->entries_init; ++j) {
+                    ha->hdr[j].is_arraydrv = alst->list[j].is_arrayd;
+                    ha->hdr[j].is_master = alst->list[j].is_master;
+                    ha->hdr[j].is_parity = alst->list[j].is_parity;
+                    ha->hdr[j].is_hotfix = alst->list[j].is_hotfix;
+                    ha->hdr[j].master_no = alst->list[j].cd_handle;
+                }
+            } else if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                                         ARRAY_DRV_LIST | LA_CTRL_PATTERN,
+                                         0, 35 * sizeof(gdth_alist_str))) {
+                for (j = 0; j < 35; ++j) {
+                    alst2 = &((gdth_alist_str *)ha->pscratch)[j];
+                    ha->hdr[j].is_arraydrv = alst2->is_arrayd;
+                    ha->hdr[j].is_master = alst2->is_master;
+                    ha->hdr[j].is_parity = alst2->is_parity;
+                    ha->hdr[j].is_hotfix = alst2->is_hotfix;
+                    ha->hdr[j].master_no = alst2->cd_handle;
+                }
+            }
+        }
+    }       
+                                  
+    /* initialize raw service */
+    ha->raw_feat = 0;
+    if (!force_dma32) {
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_X_INIT_RAW,0,0,0);
+        if (ok)
+            ha->raw_feat = GDT_64BIT;
+    }
+    if (force_dma32 || (!ok && ha->status == (ushort)S_NOFUNC))
+        ok = gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_INIT,0,0,0);
+    if (!ok) {
+        printk("GDT-HA %d: Initialization error raw service (code %d)\n",
+               hanum, ha->status);
+        return 0;
+    }
+    TRACE2(("gdth_search_drives(): RAWSERVICE initialized\n"));
+
+    /* set/get features raw service (scatter/gather) */
+    if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_SET_FEAT,SCATTER_GATHER,
+                          0,0)) {
+        TRACE2(("gdth_search_drives(): set features RAWSERVICE OK\n"));
+        if (gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_GET_FEAT,0,0,0)) {
+            TRACE2(("gdth_search_dr(): get feat RAWSERVICE %d\n",
+                    ha->info));
+            ha->raw_feat |= (ushort)ha->info;
+        }
+    } 
+
+    /* set/get features cache service (equal to raw service) */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_SET_FEAT,0,
+                          SCATTER_GATHER,0)) {
+        TRACE2(("gdth_search_drives(): set features CACHESERVICE OK\n"));
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_GET_FEAT,0,0,0)) {
+            TRACE2(("gdth_search_dr(): get feat CACHESERV. %d\n",
+                    ha->info));
+            ha->cache_feat |= (ushort)ha->info;
+        }
+    }
+
+    /* reserve drives for raw service */
+    if (reserve_mode != 0) {
+        gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE_ALL,
+                          reserve_mode == 1 ? 1 : 3, 0, 0);
+        TRACE2(("gdth_search_drives(): RESERVE_ALL code %d\n", 
+                ha->status));
+    }
+    for (i = 0; i < MAX_RES_ARGS; i += 4) {
+        if (reserve_list[i] == hanum && reserve_list[i+1] < ha->bus_cnt && 
+            reserve_list[i+2] < ha->tid_cnt && reserve_list[i+3] < MAXLUN) {
+            TRACE2(("gdth_search_drives(): reserve ha %d bus %d id %d lun %d\n",
+                    reserve_list[i], reserve_list[i+1],
+                    reserve_list[i+2], reserve_list[i+3]));
+            if (!gdth_internal_cmd(hanum,SCSIRAWSERVICE,GDT_RESERVE,0,
+                                   reserve_list[i+1], reserve_list[i+2] | 
+                                   (reserve_list[i+3] << 8))) {
+                printk("GDT-HA %d: Error raw service (RESERVE, code %d)\n",
+                       hanum, ha->status);
+             }
+        }
+    }
+
+    /* Determine OEM string using IOCTL */
+    oemstr = (gdth_oem_str_ioctl *)ha->pscratch;
+    oemstr->params.ctl_version = 0x01;
+    oemstr->params.buffer_size = sizeof(oemstr->text);
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_IOCTL,
+                          CACHE_READ_OEM_STRING_RECORD,INVALID_CHANNEL,
+                          sizeof(gdth_oem_str_ioctl))) {
+        TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD OK\n"));
+        printk("GDT-HA %d: Vendor: %s Name: %s\n",
+               hanum,oemstr->text.oem_company_name,ha->binfo.type_string);
+        /* Save the Host Drive inquiry data */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        strlcpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,
+                sizeof(ha->oem_name));
+#else
+        strncpy(ha->oem_name,oemstr->text.scsi_host_drive_inquiry_vendor_id,7);
+        ha->oem_name[7] = '\0';
+#endif
+    } else {
+        /* Old method, based on PCI ID */
+        TRACE2(("gdth_search_drives(): CACHE_READ_OEM_STRING_RECORD failed\n"));
+        printk("GDT-HA %d: Name: %s\n",
+               hanum,ha->binfo.type_string);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        if (ha->oem_id == OEM_ID_INTEL)
+            strlcpy(ha->oem_name,"Intel  ", sizeof(ha->oem_name));
+        else
+            strlcpy(ha->oem_name,"ICP    ", sizeof(ha->oem_name));
+#else 
+        if (ha->oem_id == OEM_ID_INTEL)
+            strcpy(ha->oem_name,"Intel  ");
+        else
+            strcpy(ha->oem_name,"ICP    ");
+#endif
+    }
+
+    /* scanning for host drives */
+    for (i = 0; i < cdev_cnt; ++i) 
+        gdth_analyse_hdrive(hanum,i);
+    
+    TRACE(("gdth_search_drives() OK\n"));
+    return 1;
+}
+
+static int gdth_analyse_hdrive(int hanum,ushort hdrive)
+{
+    register gdth_ha_str *ha;
+    ulong32 drv_cyls;
+    int drv_hds, drv_secs;
+
+    TRACE(("gdth_analyse_hdrive() hanum %d drive %d\n",hanum,hdrive));
+    if (hdrive >= MAX_HDRIVES)
+        return 0;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (!gdth_internal_cmd(hanum,CACHESERVICE,GDT_INFO,hdrive,0,0)) 
+        return 0;
+    ha->hdr[hdrive].present = TRUE;
+    ha->hdr[hdrive].size = ha->info;
+   
+    /* evaluate mapping (sectors per head, heads per cylinder) */
+    ha->hdr[hdrive].size &= ~SECS32;
+    if (ha->info2 == 0) {
+        gdth_eval_mapping(ha->hdr[hdrive].size,&drv_cyls,&drv_hds,&drv_secs);
+    } else {
+        drv_hds = ha->info2 & 0xff;
+        drv_secs = (ha->info2 >> 8) & 0xff;
+        drv_cyls = (ulong32)ha->hdr[hdrive].size / drv_hds / drv_secs;
+    }
+    ha->hdr[hdrive].heads = (unchar)drv_hds;
+    ha->hdr[hdrive].secs  = (unchar)drv_secs;
+    /* round size */
+    ha->hdr[hdrive].size  = drv_cyls * drv_hds * drv_secs;
+    
+    if (ha->cache_feat & GDT_64BIT) {
+        if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_X_INFO,hdrive,0,0)
+            && ha->info2 != 0) {
+            ha->hdr[hdrive].size = ((ulong64)ha->info2 << 32) | ha->info;
+        }
+    }
+    TRACE2(("gdth_search_dr() cdr. %d size %d hds %d scs %d\n",
+            hdrive,ha->hdr[hdrive].size,drv_hds,drv_secs));
+
+    /* get informations about device */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_DEVTYPE,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d devtype %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].devtype = (ushort)ha->info;
+    }
+
+    /* cluster info */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_CLUST_INFO,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d cluster info %d\n",
+                hdrive,ha->info));
+        if (!shared_access)
+            ha->hdr[hdrive].cluster_type = (unchar)ha->info;
+    }
+
+    /* R/W attributes */
+    if (gdth_internal_cmd(hanum,CACHESERVICE,GDT_RW_ATTRIBS,hdrive,0,0)) {
+        TRACE2(("gdth_search_dr() cache drive %d r/w attrib. %d\n",
+                hdrive,ha->info));
+        ha->hdr[hdrive].rw_attribs = (unchar)ha->info;
+    }
+
+    return 1;
+}
+
+
+/* command queueing/sending functions */
+
+static void gdth_putq(int hanum,Scsi_Cmnd *scp,unchar priority)
+{
+    register gdth_ha_str *ha;
+    register Scsi_Cmnd *pscp;
+    register Scsi_Cmnd *nscp;
+    ulong flags;
+    unchar b, t;
+
+    TRACE(("gdth_putq() priority %d\n",priority));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    scp->SCp.this_residual = (int)priority;
+    b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+    t = scp->device->id;
+    if (priority >= DEFAULT_PRI) {
+        if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
+            (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) {
+            TRACE2(("gdth_putq(): locked IO -> update_timeout()\n"));
+            scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+        }
+    }
+
+    if (ha->req_first==NULL) {
+        ha->req_first = scp;                    /* queue was empty */
+        scp->SCp.ptr = NULL;
+    } else {                                    /* queue not empty */
+        pscp = ha->req_first;
+        nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+        /* priority: 0-highest,..,0xff-lowest */
+        while (nscp && (unchar)nscp->SCp.this_residual <= priority) {
+            pscp = nscp;
+            nscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+        }
+        pscp->SCp.ptr = (char *)scp;
+        scp->SCp.ptr  = (char *)nscp;
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+#ifdef GDTH_STATISTICS
+    flags = 0;
+    for (nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+        ++flags;
+    if (max_rq < flags) {
+        max_rq = flags;
+        TRACE3(("GDT: max_rq = %d\n",(ushort)max_rq));
+    }
+#endif
+}
+
+static void gdth_next(int hanum)
+{
+    register gdth_ha_str *ha;
+    register Scsi_Cmnd *pscp;
+    register Scsi_Cmnd *nscp;
+    unchar b, t, l, firsttime;
+    unchar this_cmd, next_cmd;
+    ulong flags = 0;
+    int cmd_index;
+
+    TRACE(("gdth_next() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (!gdth_polling) 
+        spin_lock_irqsave(&ha->smp_lock, flags);
+
+    ha->cmd_cnt = ha->cmd_offs_dpmem = 0;
+    this_cmd = firsttime = TRUE;
+    next_cmd = gdth_polling ? FALSE:TRUE;
+    cmd_index = 0;
+
+    for (nscp = pscp = ha->req_first; nscp; nscp = (Scsi_Cmnd *)nscp->SCp.ptr) {
+        if (nscp != pscp && nscp != (Scsi_Cmnd *)pscp->SCp.ptr)
+            pscp = (Scsi_Cmnd *)pscp->SCp.ptr;
+        b = virt_ctr ? NUMDATA(nscp->device->host)->busnum : nscp->device->channel;
+        t = nscp->device->id;
+        l = nscp->device->lun;
+        if (nscp->SCp.this_residual >= DEFAULT_PRI) {
+            if ((b != ha->virt_bus && ha->raw[BUS_L2P(ha,b)].lock) ||
+                (b == ha->virt_bus && t < MAX_HDRIVES && ha->hdr[t].lock)) 
+                continue;
+        }
+
+        if (firsttime) {
+            if (gdth_test_busy(hanum)) {        /* controller busy ? */
+                TRACE(("gdth_next() controller %d busy !\n",hanum));
+                if (!gdth_polling) {
+                    spin_unlock_irqrestore(&ha->smp_lock, flags);
+                    return;
+                }
+                while (gdth_test_busy(hanum))
+                    gdth_delay(1);
+            }   
+            firsttime = FALSE;
+        }
+
+        if (nscp->done != gdth_scsi_done || nscp->cmnd[0] != 0xff) {        
+        if (nscp->SCp.phase == -1) {
+            nscp->SCp.phase = CACHESERVICE;           /* default: cache svc. */ 
+            if (nscp->cmnd[0] == TEST_UNIT_READY) {
+                TRACE2(("TEST_UNIT_READY Bus %d Id %d LUN %d\n", 
+                        b, t, l));
+                /* TEST_UNIT_READY -> set scan mode */
+                if ((ha->scan_mode & 0x0f) == 0) {
+                    if (b == 0 && t == 0 && l == 0) {
+                        ha->scan_mode |= 1;
+                        TRACE2(("Scan mode: 0x%x\n", ha->scan_mode));
+                    }
+                } else if ((ha->scan_mode & 0x0f) == 1) {
+                    if (b == 0 && ((t == 0 && l == 1) ||
+                         (t == 1 && l == 0))) {
+                        nscp->SCp.sent_command = GDT_SCAN_START;
+                        nscp->SCp.phase = ((ha->scan_mode & 0x10 ? 1:0) << 8) 
+                            | SCSIRAWSERVICE;
+                        ha->scan_mode = 0x12;
+                        TRACE2(("Scan mode: 0x%x (SCAN_START)\n", 
+                                ha->scan_mode));
+                    } else {
+                        ha->scan_mode &= 0x10;
+                        TRACE2(("Scan mode: 0x%x\n", ha->scan_mode));
+                    }                   
+                } else if (ha->scan_mode == 0x12) {
+                    if (b == ha->bus_cnt && t == ha->tid_cnt-1) {
+                        nscp->SCp.phase = SCSIRAWSERVICE;
+                        nscp->SCp.sent_command = GDT_SCAN_END;
+                        ha->scan_mode &= 0x10;
+                        TRACE2(("Scan mode: 0x%x (SCAN_END)\n", 
+                                ha->scan_mode));
+                    }
+                }
+            }
+            if (b == ha->virt_bus && nscp->cmnd[0] != INQUIRY &&
+                nscp->cmnd[0] != READ_CAPACITY && nscp->cmnd[0] != MODE_SENSE &&
+                (ha->hdr[t].cluster_type & CLUSTER_DRIVE)) {
+                /* always GDT_CLUST_INFO! */
+                nscp->SCp.sent_command = GDT_CLUST_INFO;
+            }
+        }
+        }
+
+        if (nscp->SCp.sent_command != -1) {
+            if ((nscp->SCp.phase & 0xff) == CACHESERVICE) {
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                next_cmd = FALSE;
+            } else if ((nscp->SCp.phase & 0xff) == SCSIRAWSERVICE) {
+                if (!(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b))))
+                    this_cmd = FALSE;
+                next_cmd = FALSE;
+            } else {
+                memset((char*)nscp->sense_buffer,0,16);
+                nscp->sense_buffer[0] = 0x70;
+                nscp->sense_buffer[2] = NOT_READY;
+                nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                if (!nscp->SCp.have_data_in)
+                    nscp->SCp.have_data_in++;
+                else
+                    nscp->scsi_done(nscp);
+            }
+        } else if (nscp->done == gdth_scsi_done && nscp->cmnd[0] == 0xff) {
+            if (!(cmd_index=gdth_special_cmd(hanum,nscp)))
+                this_cmd = FALSE;
+            next_cmd = FALSE;
+        } else if (b != ha->virt_bus) {
+            if (ha->raw[BUS_L2P(ha,b)].io_cnt[t] >= GDTH_MAX_RAW ||
+                !(cmd_index=gdth_fill_raw_cmd(hanum,nscp,BUS_L2P(ha,b)))) 
+                this_cmd = FALSE;
+            else 
+                ha->raw[BUS_L2P(ha,b)].io_cnt[t]++;
+        } else if (t >= MAX_HDRIVES || !ha->hdr[t].present || l != 0) {
+            TRACE2(("Command 0x%x to bus %d id %d lun %d -> IGNORE\n",
+                    nscp->cmnd[0], b, t, l));
+            nscp->result = DID_BAD_TARGET << 16;
+            if (!nscp->SCp.have_data_in)
+                nscp->SCp.have_data_in++;
+            else
+                nscp->scsi_done(nscp);
+        } else {
+            switch (nscp->cmnd[0]) {
+              case TEST_UNIT_READY:
+              case INQUIRY:
+              case REQUEST_SENSE:
+              case READ_CAPACITY:
+              case VERIFY:
+              case START_STOP:
+              case MODE_SENSE:
+              case SERVICE_ACTION_IN:
+                TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+                       nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                       nscp->cmnd[4],nscp->cmnd[5]));
+                if (ha->hdr[t].media_changed && nscp->cmnd[0] != INQUIRY) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else
+                        nscp->scsi_done(nscp);
+                } else if (gdth_internal_cache_cmd(hanum,nscp))
+                    nscp->scsi_done(nscp);
+                break;
+
+              case ALLOW_MEDIUM_REMOVAL:
+                TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
+                       nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                       nscp->cmnd[4],nscp->cmnd[5]));
+                if ( (nscp->cmnd[4]&1) && !(ha->hdr[t].devtype&1) ) {
+                    TRACE(("Prevent r. nonremov. drive->do nothing\n"));
+                    nscp->result = DID_OK << 16;
+                    nscp->sense_buffer[0] = 0;
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else
+                        nscp->scsi_done(nscp);
+                } else {
+                    nscp->cmnd[3] = (ha->hdr[t].devtype&1) ? 1:0;
+                    TRACE(("Prevent/allow r. %d rem. drive %d\n",
+                           nscp->cmnd[4],nscp->cmnd[3]));
+                    if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                        this_cmd = FALSE;
+                }
+                break;
+                
+              case RESERVE:
+              case RELEASE:
+                TRACE2(("cache cmd %s\n",nscp->cmnd[0] == RESERVE ?
+                        "RESERVE" : "RELEASE"));
+                if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                break;
+                
+              case READ_6:
+              case WRITE_6:
+              case READ_10:
+              case WRITE_10:
+              case READ_16:
+              case WRITE_16:
+                if (ha->hdr[t].media_changed) {
+                    /* return UNIT_ATTENTION */
+                    TRACE2(("cmd 0x%x target %d: UNIT_ATTENTION\n",
+                             nscp->cmnd[0], t));
+                    ha->hdr[t].media_changed = FALSE;
+                    memset((char*)nscp->sense_buffer,0,16);
+                    nscp->sense_buffer[0] = 0x70;
+                    nscp->sense_buffer[2] = UNIT_ATTENTION;
+                    nscp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                    if (!nscp->SCp.have_data_in)
+                        nscp->SCp.have_data_in++;
+                    else
+                        nscp->scsi_done(nscp);
+                } else if (!(cmd_index=gdth_fill_cache_cmd(hanum,nscp,t)))
+                    this_cmd = FALSE;
+                break;
+
+              default:
+                TRACE2(("cache cmd %x/%x/%x/%x/%x/%x unknown\n",nscp->cmnd[0],
+                        nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
+                        nscp->cmnd[4],nscp->cmnd[5]));
+                printk("GDT-HA %d: Unknown SCSI command 0x%x to cache service !\n",
+                       hanum, nscp->cmnd[0]);
+                nscp->result = DID_ABORT << 16;
+                if (!nscp->SCp.have_data_in)
+                    nscp->SCp.have_data_in++;
+                else
+                    nscp->scsi_done(nscp);
+                break;
+            }
+        }
+
+        if (!this_cmd)
+            break;
+        if (nscp == ha->req_first)
+            ha->req_first = pscp = (Scsi_Cmnd *)nscp->SCp.ptr;
+        else
+            pscp->SCp.ptr = nscp->SCp.ptr;
+        if (!next_cmd)
+            break;
+    }
+
+    if (ha->cmd_cnt > 0) {
+        gdth_release_event(hanum);
+    }
+
+    if (!gdth_polling) 
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+    if (gdth_polling && ha->cmd_cnt > 0) {
+        if (!gdth_wait(hanum,cmd_index,POLL_TIMEOUT))
+            printk("GDT-HA %d: Command %d timed out !\n",
+                   hanum,cmd_index);
+    }
+}
+   
+static void gdth_copy_internal_data(int hanum,Scsi_Cmnd *scp,
+                                    char *buffer,ushort count)
+{
+    ushort cpcount,i;
+    ushort cpsum,cpnow;
+    struct scatterlist *sl;
+    gdth_ha_str *ha;
+    char *address;
+
+    cpcount = count<=(ushort)scp->bufflen ? count:(ushort)scp->bufflen;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (scp->use_sg) {
+        sl = (struct scatterlist *)scp->request_buffer;
+        for (i=0,cpsum=0; i<scp->use_sg; ++i,++sl) {
+	    unsigned long flags;
+            cpnow = (ushort)sl->length;
+            TRACE(("copy_internal() now %d sum %d count %d %d\n",
+                          cpnow,cpsum,cpcount,(ushort)scp->bufflen));
+            if (cpsum+cpnow > cpcount) 
+                cpnow = cpcount - cpsum;
+            cpsum += cpnow;
+            if (!sl->page) {
+                printk("GDT-HA %d: invalid sc/gt element in gdth_copy_internal_data()\n",
+                       hanum);
+                return;
+            }
+	    local_irq_save(flags);
+	    address = kmap_atomic(sl->page, KM_BIO_SRC_IRQ) + sl->offset;
+            memcpy(address,buffer,cpnow);
+	    flush_dcache_page(sl->page);
+	    kunmap_atomic(address, KM_BIO_SRC_IRQ);
+	    local_irq_restore(flags);
+            if (cpsum == cpcount)
+                break;
+            buffer += cpnow;
+        }
+    } else {
+        TRACE(("copy_internal() count %d\n",cpcount));
+        memcpy((char*)scp->request_buffer,buffer,cpcount);
+    }
+}
+
+static int gdth_internal_cache_cmd(int hanum,Scsi_Cmnd *scp)
+{
+    register gdth_ha_str *ha;
+    unchar t;
+    gdth_inq_data inq;
+    gdth_rdcap_data rdc;
+    gdth_sense_data sd;
+    gdth_modep_data mpd;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    t  = scp->device->id;
+    TRACE(("gdth_internal_cache_cmd() cmd 0x%x hdrive %d\n",
+           scp->cmnd[0],t));
+
+    scp->result = DID_OK << 16;
+    scp->sense_buffer[0] = 0;
+
+    switch (scp->cmnd[0]) {
+      case TEST_UNIT_READY:
+      case VERIFY:
+      case START_STOP:
+        TRACE2(("Test/Verify/Start hdrive %d\n",t));
+        break;
+
+      case INQUIRY:
+        TRACE2(("Inquiry hdrive %d devtype %d\n",
+                t,ha->hdr[t].devtype));
+        inq.type_qual = (ha->hdr[t].devtype&4) ? TYPE_ROM:TYPE_DISK;
+        /* you can here set all disks to removable, if you want to do
+           a flush using the ALLOW_MEDIUM_REMOVAL command */
+        inq.modif_rmb = 0x00;
+        if ((ha->hdr[t].devtype & 1) ||
+            (ha->hdr[t].cluster_type & CLUSTER_DRIVE))
+            inq.modif_rmb = 0x80;
+        inq.version   = 2;
+        inq.resp_aenc = 2;
+        inq.add_length= 32;
+        strcpy(inq.vendor,ha->oem_name);
+        sprintf(inq.product,"Host Drive  #%02d",t);
+        strcpy(inq.revision,"   ");
+        gdth_copy_internal_data(hanum,scp,(char*)&inq,sizeof(gdth_inq_data));
+        break;
+
+      case REQUEST_SENSE:
+        TRACE2(("Request sense hdrive %d\n",t));
+        sd.errorcode = 0x70;
+        sd.segno     = 0x00;
+        sd.key       = NO_SENSE;
+        sd.info      = 0;
+        sd.add_length= 0;
+        gdth_copy_internal_data(hanum,scp,(char*)&sd,sizeof(gdth_sense_data));
+        break;
+
+      case MODE_SENSE:
+        TRACE2(("Mode sense hdrive %d\n",t));
+        memset((char*)&mpd,0,sizeof(gdth_modep_data));
+        mpd.hd.data_length = sizeof(gdth_modep_data);
+        mpd.hd.dev_par     = (ha->hdr[t].devtype&2) ? 0x80:0;
+        mpd.hd.bd_length   = sizeof(mpd.bd);
+        mpd.bd.block_length[0] = (SECTOR_SIZE & 0x00ff0000) >> 16;
+        mpd.bd.block_length[1] = (SECTOR_SIZE & 0x0000ff00) >> 8;
+        mpd.bd.block_length[2] = (SECTOR_SIZE & 0x000000ff);
+        gdth_copy_internal_data(hanum,scp,(char*)&mpd,sizeof(gdth_modep_data));
+        break;
+
+      case READ_CAPACITY:
+        TRACE2(("Read capacity hdrive %d\n",t));
+        if (ha->hdr[t].size > (ulong64)0xffffffff)
+            rdc.last_block_no = 0xffffffff;
+        else
+            rdc.last_block_no = cpu_to_be32(ha->hdr[t].size-1);
+        rdc.block_length  = cpu_to_be32(SECTOR_SIZE);
+        gdth_copy_internal_data(hanum,scp,(char*)&rdc,sizeof(gdth_rdcap_data));
+        break;
+
+      case SERVICE_ACTION_IN:
+        if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 &&
+            (ha->cache_feat & GDT_64BIT)) {
+            gdth_rdcap16_data rdc16;
+
+            TRACE2(("Read capacity (16) hdrive %d\n",t));
+            rdc16.last_block_no = cpu_to_be64(ha->hdr[t].size-1);
+            rdc16.block_length  = cpu_to_be32(SECTOR_SIZE);
+            gdth_copy_internal_data(hanum,scp,(char*)&rdc16,sizeof(gdth_rdcap16_data));
+        } else { 
+            scp->result = DID_ABORT << 16;
+        }
+        break;
+
+      default:
+        TRACE2(("Internal cache cmd 0x%x unknown\n",scp->cmnd[0]));
+        break;
+    }
+
+    if (!scp->SCp.have_data_in)
+        scp->SCp.have_data_in++;
+    else 
+        return 1;
+
+    return 0;
+}
+    
+static int gdth_fill_cache_cmd(int hanum,Scsi_Cmnd *scp,ushort hdrive)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    struct scatterlist *sl;
+    ulong32 cnt, blockcnt;
+    ulong64 no, blockno;
+    dma_addr_t phys_addr;
+    int i, cmd_index, read_write, sgcnt, mode64;
+    struct page *page;
+    ulong offset;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    cmdp = ha->pccb;
+    TRACE(("gdth_fill_cache_cmd() cmd 0x%x cmdsize %d hdrive %d\n",
+                 scp->cmnd[0],scp->cmd_len,hdrive));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    mode64 = (ha->cache_feat & GDT_64BIT) ? TRUE : FALSE;
+    /* test for READ_16, WRITE_16 if !mode64 ? ---
+       not required, should not occur due to error return on 
+       READ_CAPACITY_16 */
+
+    cmdp->Service = CACHESERVICE;
+    cmdp->RequestBuffer = scp;
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+        gdth_set_sema0(hanum);
+
+    /* fill command */
+    read_write = 0;
+    if (scp->SCp.sent_command != -1) 
+        cmdp->OpCode = scp->SCp.sent_command;   /* special cache cmd. */
+    else if (scp->cmnd[0] == RESERVE) 
+        cmdp->OpCode = GDT_RESERVE_DRV;
+    else if (scp->cmnd[0] == RELEASE)
+        cmdp->OpCode = GDT_RELEASE_DRV;
+    else if (scp->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
+        if (scp->cmnd[4] & 1)                   /* prevent ? */
+            cmdp->OpCode = GDT_MOUNT;
+        else if (scp->cmnd[3] & 1)              /* removable drive ? */
+            cmdp->OpCode = GDT_UNMOUNT;
+        else
+            cmdp->OpCode = GDT_FLUSH;
+    } else if (scp->cmnd[0] == WRITE_6 || scp->cmnd[0] == WRITE_10 ||
+               scp->cmnd[0] == WRITE_12 || scp->cmnd[0] == WRITE_16
+    ) {
+        read_write = 1;
+        if (gdth_write_through || ((ha->hdr[hdrive].rw_attribs & 1) && 
+                                   (ha->cache_feat & GDT_WR_THROUGH)))
+            cmdp->OpCode = GDT_WRITE_THR;
+        else
+            cmdp->OpCode = GDT_WRITE;
+    } else {
+        read_write = 2;
+        cmdp->OpCode = GDT_READ;
+    }
+
+    cmdp->BoardNode = LOCALBOARD;
+    if (mode64) {
+        cmdp->u.cache64.DeviceNo = hdrive;
+        cmdp->u.cache64.BlockNo  = 1;
+        cmdp->u.cache64.sg_canz  = 0;
+    } else {
+        cmdp->u.cache.DeviceNo = hdrive;
+        cmdp->u.cache.BlockNo  = 1;
+        cmdp->u.cache.sg_canz  = 0;
+    }
+
+    if (read_write) {
+        if (scp->cmd_len == 16) {
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong64));
+            blockno = be64_to_cpu(no);
+            memcpy(&cnt, &scp->cmnd[10], sizeof(ulong32));
+            blockcnt = be32_to_cpu(cnt);
+        } else if (scp->cmd_len == 10) {
+            memcpy(&no, &scp->cmnd[2], sizeof(ulong32));
+            blockno = be32_to_cpu(no);
+            memcpy(&cnt, &scp->cmnd[7], sizeof(ushort));
+            blockcnt = be16_to_cpu(cnt);
+        } else {
+            memcpy(&no, &scp->cmnd[0], sizeof(ulong32));
+            blockno = be32_to_cpu(no) & 0x001fffffUL;
+            blockcnt= scp->cmnd[4]==0 ? 0x100 : scp->cmnd[4];
+        }
+        if (mode64) {
+            cmdp->u.cache64.BlockNo = blockno;
+            cmdp->u.cache64.BlockCnt = blockcnt;
+        } else {
+            cmdp->u.cache.BlockNo = (ulong32)blockno;
+            cmdp->u.cache.BlockCnt = blockcnt;
+        }
+
+        if (scp->use_sg) {
+            sl = (struct scatterlist *)scp->request_buffer;
+            sgcnt = scp->use_sg;
+            scp->SCp.Status = GDTH_MAP_SG;
+            scp->SCp.Message = (read_write == 1 ? 
+                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);   
+            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+            if (mode64) {
+                cmdp->u.cache64.DestAddr= (ulong64)-1;
+                cmdp->u.cache64.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.cache64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.cache.DestAddr= 0xffffffff;
+                cmdp->u.cache.sg_canz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.cache.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.cache.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            }
+
+#ifdef GDTH_STATISTICS
+            if (max_sg < (ulong32)sgcnt) {
+                max_sg = (ulong32)sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",max_sg));
+            }
+#endif
+
+        } else {
+            scp->SCp.Status = GDTH_MAP_SINGLE;
+            scp->SCp.Message = (read_write == 1 ? 
+                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
+            scp->SCp.dma_handle = phys_addr;
+            if (mode64) {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache64.DestAddr = (ulong64)-1;
+                    cmdp->u.cache64.sg_canz = 1;
+                    cmdp->u.cache64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache64.DestAddr  = phys_addr;
+                    cmdp->u.cache64.sg_canz= 0;
+                }
+            } else {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    cmdp->u.cache.DestAddr = 0xffffffff;
+                    cmdp->u.cache.sg_canz = 1;
+                    cmdp->u.cache.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.cache.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.cache.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.cache.DestAddr  = phys_addr;
+                    cmdp->u.cache.sg_canz= 0;
+                }
+            }
+        }
+    }
+    /* evaluate command size, check space */
+    if (mode64) {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache64.DestAddr,cmdp->u.cache64.sg_canz,
+               cmdp->u.cache64.sg_lst[0].sg_ptr,
+               cmdp->u.cache64.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache64.BlockNo,cmdp->u.cache64.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) +
+            (ushort)cmdp->u.cache64.sg_canz * sizeof(gdth_sg64_str);
+    } else {
+        TRACE(("cache cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+               cmdp->u.cache.DestAddr,cmdp->u.cache.sg_canz,
+               cmdp->u.cache.sg_lst[0].sg_ptr,
+               cmdp->u.cache.sg_lst[0].sg_len));
+        TRACE(("cache cmd: cmd %d blockno. %d, blockcnt %d\n",
+               cmdp->OpCode,cmdp->u.cache.BlockNo,cmdp->u.cache.BlockCnt));
+        ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) +
+            (ushort)cmdp->u.cache.sg_canz * sizeof(gdth_sg_str);
+    }
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_fill_cache() DPMEM overflow\n"));
+            ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}
+
+static int gdth_fill_raw_cmd(int hanum,Scsi_Cmnd *scp,unchar b)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    struct scatterlist *sl;
+    ushort i;
+    dma_addr_t phys_addr, sense_paddr;
+    int cmd_index, sgcnt, mode64;
+    unchar t,l;
+    struct page *page;
+    ulong offset;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    t = scp->device->id;
+    l = scp->device->lun;
+    cmdp = ha->pccb;
+    TRACE(("gdth_fill_raw_cmd() cmd 0x%x bus %d ID %d LUN %d\n",
+           scp->cmnd[0],b,t,l));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    mode64 = (ha->raw_feat & GDT_64BIT) ? TRUE : FALSE;
+
+    cmdp->Service = SCSIRAWSERVICE;
+    cmdp->RequestBuffer = scp;
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+        gdth_set_sema0(hanum);
+
+    /* fill command */  
+    if (scp->SCp.sent_command != -1) {
+        cmdp->OpCode           = scp->SCp.sent_command; /* special raw cmd. */
+        cmdp->BoardNode        = LOCALBOARD;
+        if (mode64) {
+            cmdp->u.raw64.direction = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw64.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst);
+        } else {
+            cmdp->u.raw.direction  = (scp->SCp.phase >> 8);
+            TRACE2(("special raw cmd 0x%x param 0x%x\n", 
+                    cmdp->OpCode, cmdp->u.raw.direction));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst);
+        }
+
+    } else {
+        page = virt_to_page(scp->sense_buffer);
+        offset = (ulong)scp->sense_buffer & ~PAGE_MASK;
+        sense_paddr = pci_map_page(ha->pdev,page,offset,
+                                   16,PCI_DMA_FROMDEVICE);
+        scp->SCp.buffer = (struct scatterlist *)((ulong32)sense_paddr);
+        /* high part, if 64bit */
+        scp->host_scribble = (char *)(ulong32)((ulong64)sense_paddr >> 32);
+        cmdp->OpCode           = GDT_WRITE;             /* always */
+        cmdp->BoardNode        = LOCALBOARD;
+        if (mode64) { 
+            cmdp->u.raw64.reserved   = 0;
+            cmdp->u.raw64.mdisc_time = 0;
+            cmdp->u.raw64.mcon_time  = 0;
+            cmdp->u.raw64.clen       = scp->cmd_len;
+            cmdp->u.raw64.target     = t;
+            cmdp->u.raw64.lun        = l;
+            cmdp->u.raw64.bus        = b;
+            cmdp->u.raw64.priority   = 0;
+            cmdp->u.raw64.sdlen      = scp->request_bufflen;
+            cmdp->u.raw64.sense_len  = 16;
+            cmdp->u.raw64.sense_data = sense_paddr;
+            cmdp->u.raw64.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw64.cmd,scp->cmnd,16);
+        } else {
+            cmdp->u.raw.reserved   = 0;
+            cmdp->u.raw.mdisc_time = 0;
+            cmdp->u.raw.mcon_time  = 0;
+            cmdp->u.raw.clen       = scp->cmd_len;
+            cmdp->u.raw.target     = t;
+            cmdp->u.raw.lun        = l;
+            cmdp->u.raw.bus        = b;
+            cmdp->u.raw.priority   = 0;
+            cmdp->u.raw.link_p     = 0;
+            cmdp->u.raw.sdlen      = scp->request_bufflen;
+            cmdp->u.raw.sense_len  = 16;
+            cmdp->u.raw.sense_data = sense_paddr;
+            cmdp->u.raw.direction  = 
+                gdth_direction_tab[scp->cmnd[0]]==DOU ? GDTH_DATA_OUT:GDTH_DATA_IN;
+            memcpy(cmdp->u.raw.cmd,scp->cmnd,12);
+        }
+
+        if (scp->use_sg) {
+            sl = (struct scatterlist *)scp->request_buffer;
+            sgcnt = scp->use_sg;
+            scp->SCp.Status = GDTH_MAP_SG;
+            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
+            sgcnt = pci_map_sg(ha->pdev,sl,scp->use_sg,scp->SCp.Message);
+            if (mode64) {
+                cmdp->u.raw64.sdata = (ulong64)-1;
+                cmdp->u.raw64.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw64.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    if (cmdp->u.raw64.sg_lst[i].sg_ptr > (ulong64)0xffffffff)
+                        ha->dma64_cnt++;
+                    else
+                        ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw64.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            } else {
+                cmdp->u.raw.sdata = 0xffffffff;
+                cmdp->u.raw.sg_ranz = sgcnt;
+                for (i=0; i<sgcnt; ++i,++sl) {
+                    cmdp->u.raw.sg_lst[i].sg_ptr = sg_dma_address(sl);
+#ifdef GDTH_DMA_STATISTICS
+                    ha->dma32_cnt++;
+#endif
+                    cmdp->u.raw.sg_lst[i].sg_len = sg_dma_len(sl);
+                }
+            }
+
+#ifdef GDTH_STATISTICS
+            if (max_sg < sgcnt) {
+                max_sg = sgcnt;
+                TRACE3(("GDT: max_sg = %d\n",sgcnt));
+            }
+#endif
+
+        } else {
+            scp->SCp.Status = GDTH_MAP_SINGLE;
+            scp->SCp.Message = PCI_DMA_BIDIRECTIONAL; 
+            page = virt_to_page(scp->request_buffer);
+            offset = (ulong)scp->request_buffer & ~PAGE_MASK;
+            phys_addr = pci_map_page(ha->pdev,page,offset,
+                                     scp->request_bufflen,scp->SCp.Message);
+            scp->SCp.dma_handle = phys_addr;
+
+            if (mode64) {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw64.sdata  = (ulong64)-1;
+                    cmdp->u.raw64.sg_ranz= 1;
+                    cmdp->u.raw64.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw64.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw64.sdata  = phys_addr;
+                    cmdp->u.raw64.sg_ranz= 0;
+                }
+            } else {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    cmdp->u.raw.sdata  = 0xffffffff;
+                    cmdp->u.raw.sg_ranz= 1;
+                    cmdp->u.raw.sg_lst[0].sg_ptr = phys_addr;
+                    cmdp->u.raw.sg_lst[0].sg_len = scp->request_bufflen;
+                    cmdp->u.raw.sg_lst[1].sg_len = 0;
+                } else {
+                    cmdp->u.raw.sdata  = phys_addr;
+                    cmdp->u.raw.sg_ranz= 0;
+                }
+            }
+        }
+        if (mode64) {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw64.sdata,cmdp->u.raw64.sg_ranz,
+                   cmdp->u.raw64.sg_lst[0].sg_ptr,
+                   cmdp->u.raw64.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) +
+                (ushort)cmdp->u.raw64.sg_ranz * sizeof(gdth_sg64_str);
+        } else {
+            TRACE(("raw cmd: addr. %x sganz %x sgptr0 %x sglen0 %x\n",
+                   cmdp->u.raw.sdata,cmdp->u.raw.sg_ranz,
+                   cmdp->u.raw.sg_lst[0].sg_ptr,
+                   cmdp->u.raw.sg_lst[0].sg_len));
+            /* evaluate command size */
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) +
+                (ushort)cmdp->u.raw.sg_ranz * sizeof(gdth_sg_str);
+        }
+    }
+    /* check space */
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_fill_raw() DPMEM overflow\n"));
+            ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}
+
+static int gdth_special_cmd(int hanum,Scsi_Cmnd *scp)
+{
+    register gdth_ha_str *ha;
+    register gdth_cmd_str *cmdp;
+    int cmd_index;
+
+    ha  = HADATA(gdth_ctr_tab[hanum]);
+    cmdp= ha->pccb;
+    TRACE2(("gdth_special_cmd(): "));
+
+    if (ha->type==GDT_EISA && ha->cmd_cnt>0) 
+        return 0;
+
+    memcpy( cmdp, scp->request_buffer, sizeof(gdth_cmd_str));
+    cmdp->RequestBuffer = scp;
+
+    /* search free command index */
+    if (!(cmd_index=gdth_get_cmd_index(hanum))) {
+        TRACE(("GDT: No free command index found\n"));
+        return 0;
+    }
+
+    /* if it's the first command, set command semaphore */
+    if (ha->cmd_cnt == 0)
+       gdth_set_sema0(hanum);
+
+    /* evaluate command size, check space */
+    if (cmdp->OpCode == GDT_IOCTL) {
+        TRACE2(("IOCTL\n"));
+        ha->cmd_len = 
+            GDTOFFSOF(gdth_cmd_str,u.ioctl.p_param) + sizeof(ulong64);
+    } else if (cmdp->Service == CACHESERVICE) {
+        TRACE2(("cache command %d\n",cmdp->OpCode));
+        if (ha->cache_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.cache.sg_lst) + sizeof(gdth_sg_str);
+    } else if (cmdp->Service == SCSIRAWSERVICE) {
+        TRACE2(("raw command %d\n",cmdp->OpCode));
+        if (ha->raw_feat & GDT_64BIT)
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw64.sg_lst) + sizeof(gdth_sg64_str);
+        else
+            ha->cmd_len = 
+                GDTOFFSOF(gdth_cmd_str,u.raw.sg_lst) + sizeof(gdth_sg_str);
+    }
+
+    if (ha->cmd_len & 3)
+        ha->cmd_len += (4 - (ha->cmd_len & 3));
+
+    if (ha->cmd_cnt > 0) {
+        if ((ha->cmd_offs_dpmem + ha->cmd_len + DPMEM_COMMAND_OFFSET) >
+            ha->ic_all_size) {
+            TRACE2(("gdth_special_cmd() DPMEM overflow\n"));
+            ha->cmd_tab[cmd_index-2].cmnd = UNUSED_CMND;
+            return 0;
+        }
+    }
+
+    /* copy command */
+    gdth_copy_command(hanum);
+    return cmd_index;
+}    
+
+
+/* Controller event handling functions */
+static gdth_evt_str *gdth_store_event(gdth_ha_str *ha, ushort source, 
+                                      ushort idx, gdth_evt_data *evt)
+{
+    gdth_evt_str *e;
+    struct timeval tv;
+
+    /* no GDTH_LOCK_HA() ! */
+    TRACE2(("gdth_store_event() source %d idx %d\n", source, idx));
+    if (source == 0)                        /* no source -> no event */
+        return NULL;
+
+    if (ebuffer[elastidx].event_source == source &&
+        ebuffer[elastidx].event_idx == idx &&
+        ((evt->size != 0 && ebuffer[elastidx].event_data.size != 0 &&
+            !memcmp((char *)&ebuffer[elastidx].event_data.eu,
+            (char *)&evt->eu, evt->size)) ||
+        (evt->size == 0 && ebuffer[elastidx].event_data.size == 0 &&
+            !strcmp((char *)&ebuffer[elastidx].event_data.event_string,
+            (char *)&evt->event_string)))) { 
+        e = &ebuffer[elastidx];
+        do_gettimeofday(&tv);
+        e->last_stamp = tv.tv_sec;
+        ++e->same_count;
+    } else {
+        if (ebuffer[elastidx].event_source != 0) {  /* entry not free ? */
+            ++elastidx;
+            if (elastidx == MAX_EVENTS)
+                elastidx = 0;
+            if (elastidx == eoldidx) {              /* reached mark ? */
+                ++eoldidx;
+                if (eoldidx == MAX_EVENTS)
+                    eoldidx = 0;
+            }
+        }
+        e = &ebuffer[elastidx];
+        e->event_source = source;
+        e->event_idx = idx;
+        do_gettimeofday(&tv);
+        e->first_stamp = e->last_stamp = tv.tv_sec;
+        e->same_count = 1;
+        e->event_data = *evt;
+        e->application = 0;
+    }
+    return e;
+}
+
+static int gdth_read_event(gdth_ha_str *ha, int handle, gdth_evt_str *estr)
+{
+    gdth_evt_str *e;
+    int eindex;
+    ulong flags;
+
+    TRACE2(("gdth_read_event() handle %d\n", handle));
+    spin_lock_irqsave(&ha->smp_lock, flags);
+    if (handle == -1)
+        eindex = eoldidx;
+    else
+        eindex = handle;
+    estr->event_source = 0;
+
+    if (eindex >= MAX_EVENTS) {
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+        return eindex;
+    }
+    e = &ebuffer[eindex];
+    if (e->event_source != 0) {
+        if (eindex != elastidx) {
+            if (++eindex == MAX_EVENTS)
+                eindex = 0;
+        } else {
+            eindex = -1;
+        }
+        memcpy(estr, e, sizeof(gdth_evt_str));
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+    return eindex;
+}
+
+static void gdth_readapp_event(gdth_ha_str *ha,
+                               unchar application, gdth_evt_str *estr)
+{
+    gdth_evt_str *e;
+    int eindex;
+    ulong flags;
+    unchar found = FALSE;
+
+    TRACE2(("gdth_readapp_event() app. %d\n", application));
+    spin_lock_irqsave(&ha->smp_lock, flags);
+    eindex = eoldidx;
+    for (;;) {
+        e = &ebuffer[eindex];
+        if (e->event_source == 0)
+            break;
+        if ((e->application & application) == 0) {
+            e->application |= application;
+            found = TRUE;
+            break;
+        }
+        if (eindex == elastidx)
+            break;
+        if (++eindex == MAX_EVENTS)
+            eindex = 0;
+    }
+    if (found)
+        memcpy(estr, e, sizeof(gdth_evt_str));
+    else
+        estr->event_source = 0;
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+static void gdth_clear_events(void)
+{
+    TRACE(("gdth_clear_events()"));
+
+    eoldidx = elastidx = 0;
+    ebuffer[0].event_source = 0;
+}
+
+
+/* SCSI interface functions */
+
+static irqreturn_t gdth_interrupt(int irq,void *dev_id,struct pt_regs *regs)
+{
+    gdth_ha_str *ha2 = (gdth_ha_str *)dev_id;
+    register gdth_ha_str *ha;
+    gdt6m_dpram_str __iomem *dp6m_ptr = NULL;
+    gdt6_dpram_str __iomem *dp6_ptr;
+    gdt2_dpram_str __iomem *dp2_ptr;
+    Scsi_Cmnd *scp;
+    int hanum, rval, i;
+    unchar IStatus;
+    ushort Service;
+    ulong flags = 0;
+#ifdef INT_COAL
+    int coalesced = FALSE;
+    int next = FALSE;
+    gdth_coal_status *pcs = NULL;
+    int act_int_coal = 0;       
+#endif
+
+    TRACE(("gdth_interrupt() IRQ %d\n",irq));
+
+    /* if polling and not from gdth_wait() -> return */
+    if (gdth_polling) {
+        if (!gdth_from_wait) {
+            return IRQ_HANDLED;
+        }
+    }
+
+    if (!gdth_polling)
+	spin_lock_irqsave(&ha2->smp_lock, flags);
+    wait_index = 0;
+
+    /* search controller */
+    if ((hanum = gdth_get_status(&IStatus,irq)) == -1) {
+        /* spurious interrupt */
+        if (!gdth_polling)
+            spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            return IRQ_HANDLED;
+    }
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+#ifdef GDTH_STATISTICS
+    ++act_ints;
+#endif
+
+#ifdef INT_COAL
+    /* See if the fw is returning coalesced status */
+    if (IStatus == COALINDEX) {
+        /* Coalesced status.  Setup the initial status 
+           buffer pointer and flags */
+        pcs = ha->coal_stat;
+        coalesced = TRUE;        
+        next = TRUE;
+    }
+
+    do {
+        if (coalesced) {
+            /* For coalesced requests all status
+               information is found in the status buffer */
+            IStatus = (unchar)(pcs->status & 0xff);
+        }
+#endif
+    
+        if (ha->type == GDT_EISA) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(ha->bmic + MAILBOXREG+8);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = inl(ha->bmic + MAILBOXREG+12);
+            ha->service = inw(ha->bmic + MAILBOXREG+10);
+            ha->info2 = inl(ha->bmic + MAILBOXREG+4);
+
+            outb(0xff, ha->bmic + EDOORREG);    /* acknowledge interrupt */
+            outb(0x00, ha->bmic + SEMA1REG);    /* reset status semaphore */
+        } else if (ha->type == GDT_ISA) {
+            dp2_ptr = ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp2_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp2_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp2_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp2_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp2_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp2_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp2_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCI) {
+            dp6_ptr = ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = gdth_readw(&dp6_ptr->u.ic.Status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+            ha->info = gdth_readl(&dp6_ptr->u.ic.Info[0]);
+            ha->service = gdth_readw(&dp6_ptr->u.ic.Service);
+            ha->info2 = gdth_readl(&dp6_ptr->u.ic.Info[1]);
+
+            gdth_writeb(0xff, &dp6_ptr->io.irqdel); /* acknowledge interrupt */
+            gdth_writeb(0, &dp6_ptr->u.ic.Cmd_Index);/* reset command index */
+            gdth_writeb(0, &dp6_ptr->io.Sema1);     /* reset status semaphore */
+        } else if (ha->type == GDT_PCINEW) {
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+                ha->status = inw(PTR2USHORT(&ha->plx->status));
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else
+                ha->status = S_OK;
+            ha->info = inl(PTR2USHORT(&ha->plx->info[0]));
+            ha->service = inw(PTR2USHORT(&ha->plx->service));
+            ha->info2 = inl(PTR2USHORT(&ha->plx->info[1]));
+
+            outb(0xff, PTR2USHORT(&ha->plx->edoor_reg)); 
+            outb(0x00, PTR2USHORT(&ha->plx->sema1_reg)); 
+        } else if (ha->type == GDT_PCIMPR) {
+            dp6m_ptr = ha->brd;
+            if (IStatus & 0x80) {                       /* error flag */
+                IStatus &= ~0x80;
+#ifdef INT_COAL
+                if (coalesced)
+                    ha->status = pcs->ext_status && 0xffff;
+                else 
+#endif
+                    ha->status = gdth_readw(&dp6m_ptr->i960r.status);
+                TRACE2(("gdth_interrupt() error %d/%d\n",IStatus,ha->status));
+            } else                                      /* no error */
+                ha->status = S_OK;
+#ifdef INT_COAL
+            /* get information */
+            if (coalesced) {    
+                ha->info = pcs->info0;
+                ha->info2 = pcs->info1;
+                ha->service = (pcs->ext_status >> 16) && 0xffff;
+            } else
+#endif
+            {
+                ha->info = gdth_readl(&dp6m_ptr->i960r.info[0]);
+                ha->service = gdth_readw(&dp6m_ptr->i960r.service);
+                ha->info2 = gdth_readl(&dp6m_ptr->i960r.info[1]);
+            }
+            /* event string */
+            if (IStatus == ASYNCINDEX) {
+                if (ha->service != SCREENSERVICE &&
+                    (ha->fw_vers & 0xff) >= 0x1a) {
+                    ha->dvr.severity = gdth_readb
+                        (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.severity);
+                    for (i = 0; i < 256; ++i) {
+                        ha->dvr.event_string[i] = gdth_readb
+                            (&((gdt6m_dpram_str __iomem *)ha->brd)->i960r.evt_str[i]);
+                        if (ha->dvr.event_string[i] == 0)
+                            break;
+                    }
+                }
+            }
+#ifdef INT_COAL
+            /* Make sure that non coalesced interrupts get cleared
+               before being handled by gdth_async_event/gdth_sync_event */
+            if (!coalesced)
+#endif                          
+            {
+                gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+                gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+            }
+        } else {
+            TRACE2(("gdth_interrupt() unknown controller type\n"));
+            if (!gdth_polling)
+                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            return IRQ_HANDLED;
+        }
+
+        TRACE(("gdth_interrupt() index %d stat %d info %d\n",
+               IStatus,ha->status,ha->info));
+
+        if (gdth_from_wait) {
+            wait_hanum = hanum;
+            wait_index = (int)IStatus;
+        }
+
+        if (IStatus == ASYNCINDEX) {
+            TRACE2(("gdth_interrupt() async. event\n"));
+            gdth_async_event(hanum);
+            if (!gdth_polling)
+                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            gdth_next(hanum);
+            return IRQ_HANDLED;
+        } 
+
+        if (IStatus == SPEZINDEX) {
+            TRACE2(("Service unknown or not initialized !\n"));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            gdth_store_event(ha, ES_DRIVER, 4, &ha->dvr);
+            if (!gdth_polling)
+                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            return IRQ_HANDLED;
+        }
+        scp     = ha->cmd_tab[IStatus-2].cmnd;
+        Service = ha->cmd_tab[IStatus-2].service;
+        ha->cmd_tab[IStatus-2].cmnd = UNUSED_CMND;
+        if (scp == UNUSED_CMND) {
+            TRACE2(("gdth_interrupt() index to unused command (%d)\n",IStatus));
+            ha->dvr.size = sizeof(ha->dvr.eu.driver);
+            ha->dvr.eu.driver.ionode = hanum;
+            ha->dvr.eu.driver.index = IStatus;
+            gdth_store_event(ha, ES_DRIVER, 1, &ha->dvr);
+            if (!gdth_polling)
+                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            return IRQ_HANDLED;
+        }
+        if (scp == INTERNAL_CMND) {
+            TRACE(("gdth_interrupt() answer to internal command\n"));
+            if (!gdth_polling)
+                spin_unlock_irqrestore(&ha2->smp_lock, flags);
+            return IRQ_HANDLED;
+        }
+
+        TRACE(("gdth_interrupt() sync. status\n"));
+        rval = gdth_sync_event(hanum,Service,IStatus,scp);
+        if (!gdth_polling)
+            spin_unlock_irqrestore(&ha2->smp_lock, flags);
+        if (rval == 2) {
+            gdth_putq(hanum,scp,scp->SCp.this_residual);
+        } else if (rval == 1) {
+            scp->scsi_done(scp);
+        }
+
+#ifdef INT_COAL
+        if (coalesced) {
+            /* go to the next status in the status buffer */
+            ++pcs;
+#ifdef GDTH_STATISTICS
+            ++act_int_coal;
+            if (act_int_coal > max_int_coal) {
+                max_int_coal = act_int_coal;
+                printk("GDT: max_int_coal = %d\n",(ushort)max_int_coal);
+            }
+#endif      
+            /* see if there is another status */
+            if (pcs->status == 0)    
+                /* Stop the coalesce loop */
+                next = FALSE;
+        }
+    } while (next);
+
+    /* coalescing only for new GDT_PCIMPR controllers available */      
+    if (ha->type == GDT_PCIMPR && coalesced) {
+        gdth_writeb(0xff, &dp6m_ptr->i960r.edoor_reg);
+        gdth_writeb(0, &dp6m_ptr->i960r.sema1_reg);
+    }
+#endif
+
+    gdth_next(hanum);
+    return IRQ_HANDLED;
+}
+
+static int gdth_sync_event(int hanum,int service,unchar index,Scsi_Cmnd *scp)
+{
+    register gdth_ha_str *ha;
+    gdth_msg_str *msg;
+    gdth_cmd_str *cmdp;
+    unchar b, t;
+
+    ha   = HADATA(gdth_ctr_tab[hanum]);
+    cmdp = ha->pccb;
+    TRACE(("gdth_sync_event() serv %d status %d\n",
+           service,ha->status));
+
+    if (service == SCREENSERVICE) {
+        msg  = ha->pmsg;
+        TRACE(("len: %d, answer: %d, ext: %d, alen: %d\n",
+               msg->msg_len,msg->msg_answer,msg->msg_ext,msg->msg_alen));
+        if (msg->msg_len > MSGLEN+1)
+            msg->msg_len = MSGLEN+1;
+        if (msg->msg_len)
+            if (!(msg->msg_answer && msg->msg_ext)) {
+                msg->msg_text[msg->msg_len] = '\0';
+                printk("%s",msg->msg_text);
+            }
+
+        if (msg->msg_ext && !msg->msg_answer) {
+            while (gdth_test_busy(hanum))
+                gdth_delay(0);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_READ;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
+                + sizeof(ulong64);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            gdth_release_event(hanum);
+            return 0;
+        }
+
+        if (msg->msg_answer && msg->msg_alen) {
+            /* default answers (getchar() not possible) */
+            if (msg->msg_alen == 1) {
+                msg->msg_alen = 0;
+                msg->msg_len = 1;
+                msg->msg_text[0] = 0;
+            } else {
+                msg->msg_alen -= 2;
+                msg->msg_len = 2;
+                msg->msg_text[0] = 1;
+                msg->msg_text[1] = 0;
+            }
+            msg->msg_ext    = 0;
+            msg->msg_answer = 0;
+            while (gdth_test_busy(hanum))
+                gdth_delay(0);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_WRITE;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.su.msg.msg_handle= msg->msg_handle;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
+                + sizeof(ulong64);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            gdth_release_event(hanum);
+            return 0;
+        }
+        printk("\n");
+
+    } else {
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+        if (scp->SCp.sent_command == -1 && b != ha->virt_bus) {
+            ha->raw[BUS_L2P(ha,b)].io_cnt[t]--;
+        }
+        /* cache or raw service */
+        if (ha->status == S_BSY) {
+            TRACE2(("Controller busy -> retry !\n"));
+            if (scp->SCp.sent_command == GDT_MOUNT)
+                scp->SCp.sent_command = GDT_CLUST_INFO;
+            /* retry */
+            return 2;
+        }
+        if (scp->SCp.Status == GDTH_MAP_SG) 
+            pci_unmap_sg(ha->pdev,scp->request_buffer,
+                         scp->use_sg,scp->SCp.Message);
+        else if (scp->SCp.Status == GDTH_MAP_SINGLE) 
+            pci_unmap_page(ha->pdev,scp->SCp.dma_handle,
+                           scp->request_bufflen,scp->SCp.Message);
+        if (scp->SCp.buffer) {
+            dma_addr_t addr;
+            addr = (dma_addr_t)(ulong32)scp->SCp.buffer;
+            if (scp->host_scribble)
+                addr += (dma_addr_t)((ulong64)(ulong32)scp->host_scribble << 32);               
+            pci_unmap_page(ha->pdev,addr,16,PCI_DMA_FROMDEVICE);
+        }
+
+        if (ha->status == S_OK) {
+            scp->SCp.Status = S_OK;
+            scp->SCp.Message = ha->info;
+            if (scp->SCp.sent_command != -1) {
+                TRACE2(("gdth_sync_event(): special cmd 0x%x OK\n",
+                        scp->SCp.sent_command));
+                /* special commands GDT_CLUST_INFO/GDT_MOUNT ? */
+                if (scp->SCp.sent_command == GDT_CLUST_INFO) {
+                    ha->hdr[t].cluster_type = (unchar)ha->info;
+                    if (!(ha->hdr[t].cluster_type & 
+                        CLUSTER_MOUNTED)) {
+                        /* NOT MOUNTED -> MOUNT */
+                        scp->SCp.sent_command = GDT_MOUNT;
+                        if (ha->hdr[t].cluster_type & 
+                            CLUSTER_RESERVED) {
+                            /* cluster drive RESERVED (on the other node) */
+                            scp->SCp.phase = -2;      /* reservation conflict */
+                        }
+                    } else {
+                        scp->SCp.sent_command = -1;
+                    }
+                } else {
+                    if (scp->SCp.sent_command == GDT_MOUNT) {
+                        ha->hdr[t].cluster_type |= CLUSTER_MOUNTED;
+                        ha->hdr[t].media_changed = TRUE;
+                    } else if (scp->SCp.sent_command == GDT_UNMOUNT) {
+                        ha->hdr[t].cluster_type &= ~CLUSTER_MOUNTED;
+                        ha->hdr[t].media_changed = TRUE;
+                    } 
+                    scp->SCp.sent_command = -1;
+                }
+                /* retry */
+                scp->SCp.this_residual = HIGH_PRI;
+                return 2;
+            } else {
+                /* RESERVE/RELEASE ? */
+                if (scp->cmnd[0] == RESERVE) {
+                    ha->hdr[t].cluster_type |= CLUSTER_RESERVED;
+                } else if (scp->cmnd[0] == RELEASE) {
+                    ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED;
+                }           
+                scp->result = DID_OK << 16;
+                scp->sense_buffer[0] = 0;
+            }
+        } else {
+            scp->SCp.Status = ha->status;
+            scp->SCp.Message = ha->info;
+
+            if (scp->SCp.sent_command != -1) {
+                TRACE2(("gdth_sync_event(): special cmd 0x%x error 0x%x\n",
+                        scp->SCp.sent_command, ha->status));
+                if (scp->SCp.sent_command == GDT_SCAN_START ||
+                    scp->SCp.sent_command == GDT_SCAN_END) {
+                    scp->SCp.sent_command = -1;
+                    /* retry */
+                    scp->SCp.this_residual = HIGH_PRI;
+                    return 2;
+                }
+                memset((char*)scp->sense_buffer,0,16);
+                scp->sense_buffer[0] = 0x70;
+                scp->sense_buffer[2] = NOT_READY;
+                scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+            } else if (service == CACHESERVICE) {
+                if (ha->status == S_CACHE_UNKNOWN &&
+                    (ha->hdr[t].cluster_type & 
+                     CLUSTER_RESERVE_STATE) == CLUSTER_RESERVE_STATE) {
+                    /* bus reset -> force GDT_CLUST_INFO */
+                    ha->hdr[t].cluster_type &= ~CLUSTER_RESERVED;
+                }
+                memset((char*)scp->sense_buffer,0,16);
+                if (ha->status == (ushort)S_CACHE_RESERV) {
+                    scp->result = (DID_OK << 16) | (RESERVATION_CONFLICT << 1);
+                } else {
+                    scp->sense_buffer[0] = 0x70;
+                    scp->sense_buffer[2] = NOT_READY;
+                    scp->result = (DID_OK << 16) | (CHECK_CONDITION << 1);
+                }
+                if (scp->done != gdth_scsi_done) {
+                    ha->dvr.size = sizeof(ha->dvr.eu.sync);
+                    ha->dvr.eu.sync.ionode  = hanum;
+                    ha->dvr.eu.sync.service = service;
+                    ha->dvr.eu.sync.status  = ha->status;
+                    ha->dvr.eu.sync.info    = ha->info;
+                    ha->dvr.eu.sync.hostdrive = t;
+                    if (ha->status >= 0x8000)
+                        gdth_store_event(ha, ES_SYNC, 0, &ha->dvr);
+                    else
+                        gdth_store_event(ha, ES_SYNC, service, &ha->dvr);
+                }
+            } else {
+                /* sense buffer filled from controller firmware (DMA) */
+                if (ha->status != S_RAW_SCSI || ha->info >= 0x100) {
+                    scp->result = DID_BAD_TARGET << 16;
+                } else {
+                    scp->result = (DID_OK << 16) | ha->info;
+                }
+            }
+        }
+        if (!scp->SCp.have_data_in)
+            scp->SCp.have_data_in++;
+        else 
+            return 1;
+    }
+
+    return 0;
+}
+
+static char *async_cache_tab[] = {
+/* 0*/  "\011\000\002\002\002\004\002\006\004"
+        "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 1*/  "\011\000\002\002\002\004\002\006\004"
+        "GDT HA %u, service %u, async. status %u/%lu unknown",
+/* 2*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu not ready",
+/* 3*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 4*/  "\005\000\002\006\004"
+        "GDT HA %u, mirror update on Host Drive %lu failed",
+/* 5*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu failed",
+/* 6*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu: REASSIGN not successful and/or data error on reassigned blocks. Drive may crash in the future and should be replaced",
+/* 7*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu write protected",
+/* 8*/  "\005\000\002\006\004"
+        "GDT HA %u, media changed in Host Drive %lu",
+/* 9*/  "\005\000\002\006\004"
+        "GDT HA %u, Host Drive %lu is offline",
+/*10*/  "\005\000\002\006\004"
+        "GDT HA %u, media change of Mirror Drive %lu",
+/*11*/  "\005\000\002\006\004"
+        "GDT HA %u, Mirror Drive %lu is write protected",
+/*12*/  "\005\000\002\006\004"
+        "GDT HA %u, general error on Host Drive %lu. Please check the devices of this drive!",
+/*13*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: Cache Drive %u failed",
+/*14*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: FAIL state entered",
+/*15*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: error",
+/*16*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: failed drive replaced by Cache Drive %u",
+/*17*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity build failed",
+/*18*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild failed",
+/*19*/  "\005\000\002\010\002"
+        "GDT HA %u, Test of Hot Fix %u failed",
+/*20*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive build finished successfully",
+/*21*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild finished successfully",
+/*22*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Array Drive %u: Hot Fix %u activated",
+/*23*/  "\005\000\002\006\002"
+        "GDT HA %u, Host Drive %u: processing of i/o aborted due to serious drive error",
+/*24*/  "\005\000\002\010\002"
+        "GDT HA %u, mirror update on Cache Drive %u completed",
+/*25*/  "\005\000\002\010\002"
+        "GDT HA %u, mirror update on Cache Drive %lu failed",
+/*26*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild started",
+/*27*/  "\005\000\002\012\001"
+        "GDT HA %u, Fault bus %u: SHELF OK detected",
+/*28*/  "\005\000\002\012\001"
+        "GDT HA %u, Fault bus %u: SHELF not OK detected",
+/*29*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug started",
+/*30*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: new disk detected",
+/*31*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: old disk detected",
+/*32*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: plugging an active disk is invalid",
+/*33*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: invalid device detected",
+/*34*/  "\011\000\002\012\001\013\001\006\004"
+        "GDT HA %u, Fault bus %u, ID %u: insufficient disk capacity (%lu MB required)",
+/*35*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: disk write protected",
+/*36*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: disk not available",
+/*37*/  "\007\000\002\012\001\006\004"
+        "GDT HA %u, Fault bus %u: swap detected (%lu)",
+/*38*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug finished successfully",
+/*39*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted due to user Hot Plug",
+/*40*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug aborted",
+/*41*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, Fault bus %u, ID %u: Auto Hot Plug for Hot Fix started",
+/*42*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive build started",
+/*43*/  "\003\000\002"
+        "GDT HA %u, DRAM parity error detected",
+/*44*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: update started",
+/*45*/  "\007\000\002\006\002\010\002"
+        "GDT HA %u, Mirror Drive %u: Hot Fix %u activated",
+/*46*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: no matching Pool Hot Fix Drive available",
+/*47*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: Pool Hot Fix Drive available",
+/*48*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: no matching Pool Hot Fix Drive available",
+/*49*/  "\005\000\002\006\002"
+        "GDT HA %u, Mirror Drive %u: Pool Hot Fix Drive available",
+/*50*/  "\007\000\002\012\001\013\001"
+        "GDT HA %u, SCSI bus %u, ID %u: IGNORE_WIDE_RESIDUE message received",
+/*51*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand started",
+/*52*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand finished successfully",
+/*53*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand failed",
+/*54*/  "\003\000\002"
+        "GDT HA %u, CPU temperature critical",
+/*55*/  "\003\000\002"
+        "GDT HA %u, CPU temperature OK",
+/*56*/  "\005\000\002\006\004"
+        "GDT HA %u, Host drive %lu created",
+/*57*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand restarted",
+/*58*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: expand stopped",
+/*59*/  "\005\000\002\010\002"
+        "GDT HA %u, Mirror Drive %u: drive build quited",
+/*60*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity build quited",
+/*61*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: drive rebuild quited",
+/*62*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity verify started",
+/*63*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity verify done",
+/*64*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity verify failed",
+/*65*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity error detected",
+/*66*/  "\005\000\002\006\002"
+        "GDT HA %u, Array Drive %u: parity verify quited",
+/*67*/  "\005\000\002\006\002"
+        "GDT HA %u, Host Drive %u reserved",
+/*68*/  "\005\000\002\006\002"
+        "GDT HA %u, Host Drive %u mounted and released",
+/*69*/  "\005\000\002\006\002"
+        "GDT HA %u, Host Drive %u released",
+/*70*/  "\003\000\002"
+        "GDT HA %u, DRAM error detected and corrected with ECC",
+/*71*/  "\003\000\002"
+        "GDT HA %u, Uncorrectable DRAM error detected with ECC",
+/*72*/  "\011\000\002\012\001\013\001\014\001"
+        "GDT HA %u, SCSI bus %u, ID %u, LUN %u: reassigning block",
+/*73*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted locally",
+/*74*/  "\005\000\002\006\002"
+        "GDT HA %u, Host drive %u resetted remotely",
+/*75*/  "\003\000\002"
+        "GDT HA %u, async. status 75 unknown",
+};
+
+
+static int gdth_async_event(int hanum)
+{
+    gdth_ha_str *ha;
+    gdth_cmd_str *cmdp;
+    int cmd_index;
+
+    ha  = HADATA(gdth_ctr_tab[hanum]);
+    cmdp= ha->pccb;
+    TRACE2(("gdth_async_event() ha %d serv %d\n",
+            hanum,ha->service));
+
+    if (ha->service == SCREENSERVICE) {
+        if (ha->status == MSG_REQUEST) {
+            while (gdth_test_busy(hanum))
+                gdth_delay(0);
+            cmdp->Service       = SCREENSERVICE;
+            cmdp->RequestBuffer = SCREEN_CMND;
+            cmd_index = gdth_get_cmd_index(hanum);
+            gdth_set_sema0(hanum);
+            cmdp->OpCode        = GDT_READ;
+            cmdp->BoardNode     = LOCALBOARD;
+            cmdp->u.screen.reserved  = 0;
+            cmdp->u.screen.su.msg.msg_handle= MSG_INV_HANDLE;
+            cmdp->u.screen.su.msg.msg_addr  = ha->msg_phys;
+            ha->cmd_offs_dpmem = 0;
+            ha->cmd_len = GDTOFFSOF(gdth_cmd_str,u.screen.su.msg.msg_addr) 
+                + sizeof(ulong64);
+            ha->cmd_cnt = 0;
+            gdth_copy_command(hanum);
+            if (ha->type == GDT_EISA)
+                printk("[EISA slot %d] ",(ushort)ha->brd_phys);
+            else if (ha->type == GDT_ISA)
+                printk("[DPMEM 0x%4X] ",(ushort)ha->brd_phys);
+            else 
+                printk("[PCI %d/%d] ",(ushort)(ha->brd_phys>>8),
+                       (ushort)((ha->brd_phys>>3)&0x1f));
+            gdth_release_event(hanum);
+        }
+
+    } else {
+        if (ha->type == GDT_PCIMPR && 
+            (ha->fw_vers & 0xff) >= 0x1a) {
+            ha->dvr.size = 0;
+            ha->dvr.eu.async.ionode = hanum;
+            ha->dvr.eu.async.status  = ha->status;
+            /* severity and event_string already set! */
+        } else {        
+            ha->dvr.size = sizeof(ha->dvr.eu.async);
+            ha->dvr.eu.async.ionode   = hanum;
+            ha->dvr.eu.async.service = ha->service;
+            ha->dvr.eu.async.status  = ha->status;
+            ha->dvr.eu.async.info    = ha->info;
+            *(ulong32 *)ha->dvr.eu.async.scsi_coord  = ha->info2;
+        }
+        gdth_store_event( ha, ES_ASYNC, ha->service, &ha->dvr );
+        gdth_log_event( &ha->dvr, NULL );
+    
+        /* new host drive from expand? */
+        if (ha->service == CACHESERVICE && ha->status == 56) {
+            TRACE2(("gdth_async_event(): new host drive %d created\n",
+                    (ushort)ha->info));
+            /* gdth_analyse_hdrive(hanum, (ushort)ha->info); */
+        }   
+    }
+    return 1;
+}
+
+static void gdth_log_event(gdth_evt_data *dvr, char *buffer)
+{
+    gdth_stackframe stack;
+    char *f = NULL;
+    int i,j;
+
+    TRACE2(("gdth_log_event()\n"));
+    if (dvr->size == 0) {
+        if (buffer == NULL) {
+            printk("Adapter %d: %s\n",dvr->eu.async.ionode,dvr->event_string); 
+        } else {
+            sprintf(buffer,"Adapter %d: %s\n",
+                dvr->eu.async.ionode,dvr->event_string); 
+        }
+    } else if (dvr->eu.async.service == CACHESERVICE && 
+        INDEX_OK(dvr->eu.async.status, async_cache_tab)) {
+        TRACE2(("GDT: Async. event cache service, event no.: %d\n",
+                dvr->eu.async.status));
+        
+        f = async_cache_tab[dvr->eu.async.status];
+        
+        /* i: parameter to push, j: stack element to fill */
+        for (j=0,i=1; i < f[0]; i+=2) {
+            switch (f[i+1]) {
+              case 4:
+                stack.b[j++] = *(ulong32*)&dvr->eu.stream[(int)f[i]];
+                break;
+              case 2:
+                stack.b[j++] = *(ushort*)&dvr->eu.stream[(int)f[i]];
+                break;
+              case 1:
+                stack.b[j++] = *(unchar*)&dvr->eu.stream[(int)f[i]];
+                break;
+              default:
+                break;
+            }
+        }
+        
+        if (buffer == NULL) {
+            printk(&f[(int)f[0]],stack); 
+            printk("\n");
+        } else {
+            sprintf(buffer,&f[(int)f[0]],stack); 
+        }
+
+    } else {
+        if (buffer == NULL) {
+            printk("GDT HA %u, Unknown async. event service %d event no. %d\n",
+                   dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status);
+        } else {
+            sprintf(buffer,"GDT HA %u, Unknown async. event service %d event no. %d",
+                    dvr->eu.async.ionode,dvr->eu.async.service,dvr->eu.async.status);
+        }
+    }
+}
+
+#ifdef GDTH_STATISTICS
+void gdth_timeout(ulong data)
+{
+    ulong32 i;
+    Scsi_Cmnd *nscp;
+    gdth_ha_str *ha;
+    ulong flags;
+    int hanum = 0;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    for (act_stats=0,i=0; i<GDTH_MAXCMDS; ++i) 
+        if (ha->cmd_tab[i].cmnd != UNUSED_CMND)
+            ++act_stats;
+
+    for (act_rq=0,nscp=ha->req_first; nscp; nscp=(Scsi_Cmnd*)nscp->SCp.ptr)
+        ++act_rq;
+
+    TRACE2(("gdth_to(): ints %d, ios %d, act_stats %d, act_rq %d\n",
+            act_ints, act_ios, act_stats, act_rq));
+    act_ints = act_ios = 0;
+
+    gdth_timer.expires = jiffies + 30 * HZ;
+    add_timer(&gdth_timer);
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+#endif
+
+void __init internal_setup(char *str,int *ints)
+{
+    int i, argc;
+    char *cur_str, *argv;
+
+    TRACE2(("internal_setup() str %s ints[0] %d\n", 
+            str ? str:"NULL", ints ? ints[0]:0));
+
+    /* read irq[] from ints[] */
+    if (ints) {
+        argc = ints[0];
+        if (argc > 0) {
+            if (argc > MAXHA)
+                argc = MAXHA;
+            for (i = 0; i < argc; ++i)
+                irq[i] = ints[i+1];
+        }
+    }
+
+    /* analyse string */
+    argv = str;
+    while (argv && (cur_str = strchr(argv, ':'))) {
+        int val = 0, c = *++cur_str;
+        
+        if (c == 'n' || c == 'N')
+            val = 0;
+        else if (c == 'y' || c == 'Y')
+            val = 1;
+        else
+            val = (int)simple_strtoul(cur_str, NULL, 0);
+
+        if (!strncmp(argv, "disable:", 8))
+            disable = val;
+        else if (!strncmp(argv, "reserve_mode:", 13))
+            reserve_mode = val;
+        else if (!strncmp(argv, "reverse_scan:", 13))
+            reverse_scan = val;
+        else if (!strncmp(argv, "hdr_channel:", 12))
+            hdr_channel = val;
+        else if (!strncmp(argv, "max_ids:", 8))
+            max_ids = val;
+        else if (!strncmp(argv, "rescan:", 7))
+            rescan = val;
+        else if (!strncmp(argv, "virt_ctr:", 9))
+            virt_ctr = val;
+        else if (!strncmp(argv, "shared_access:", 14))
+            shared_access = val;
+        else if (!strncmp(argv, "probe_eisa_isa:", 15))
+            probe_eisa_isa = val;
+        else if (!strncmp(argv, "reserve_list:", 13)) {
+            reserve_list[0] = val;
+            for (i = 1; i < MAX_RES_ARGS; i++) {
+                cur_str = strchr(cur_str, ',');
+                if (!cur_str)
+                    break;
+                if (!isdigit((int)*++cur_str)) {
+                    --cur_str;          
+                    break;
+                }
+                reserve_list[i] = 
+                    (int)simple_strtoul(cur_str, NULL, 0);
+            }
+            if (!cur_str)
+                break;
+            argv = ++cur_str;
+            continue;
+        }
+
+        if ((argv = strchr(argv, ',')))
+            ++argv;
+    }
+}
+
+int __init option_setup(char *str)
+{
+    int ints[MAXHA];
+    char *cur = str;
+    int i = 1;
+
+    TRACE2(("option_setup() str %s\n", str ? str:"NULL")); 
+
+    while (cur && isdigit(*cur) && i <= MAXHA) {
+        ints[i++] = simple_strtoul(cur, NULL, 0);
+        if ((cur = strchr(cur, ',')) != NULL) cur++;
+    }
+
+    ints[0] = i - 1;
+    internal_setup(cur, ints);
+    return 1;
+}
+
+int __init gdth_detect(Scsi_Host_Template *shtp)
+{
+    struct Scsi_Host *shp;
+    gdth_pci_str pcistr[MAXHA];
+    gdth_ha_str *ha;
+    ulong32 isa_bios;
+    ushort eisa_slot;
+    int i,hanum,cnt,ctr,err;
+    unchar b;
+    
+ 
+#ifdef DEBUG_GDTH
+    printk("GDT: This driver contains debugging information !! Trace level = %d\n",
+        DebugState);
+    printk("     Destination of debugging information: ");
+#ifdef __SERIAL__
+#ifdef __COM2__
+    printk("Serial port COM2\n");
+#else
+    printk("Serial port COM1\n");
+#endif
+#else
+    printk("Console\n");
+#endif
+    gdth_delay(3000);
+#endif
+
+    TRACE(("gdth_detect()\n"));
+
+    if (disable) {
+        printk("GDT-HA: Controller driver disabled from command line !\n");
+        return 0;
+    }
+
+    printk("GDT-HA: Storage RAID Controller Driver. Version: %s \n",GDTH_VERSION_STR);
+    /* initializations */
+    gdth_polling = TRUE; b = 0;
+    gdth_clear_events();
+
+    /* As default we do not probe for EISA or ISA controllers */
+    if (probe_eisa_isa) {    
+        /* scanning for controllers, at first: ISA controller */
+        for (isa_bios=0xc8000UL; isa_bios<=0xd8000UL; isa_bios+=0x8000UL) {
+            dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
+
+            if (gdth_ctr_count >= MAXHA) 
+                break;
+            if (gdth_search_isa(isa_bios)) {        /* controller found */
+                shp = scsi_register(shtp,sizeof(gdth_ext_str));
+                if (shp == NULL)
+                    continue;  
+
+                ha = HADATA(shp);
+                if (!gdth_init_isa(isa_bios,ha)) {
+                    scsi_unregister(shp);
+                    continue;
+                }
+#ifdef __ia64__
+                break;
+#else
+                /* controller found and initialized */
+                printk("Configuring GDT-ISA HA at BIOS 0x%05X IRQ %u DRQ %u\n",
+                       isa_bios,ha->irq,ha->drq);
+
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+                    printk("GDT-ISA: Unable to allocate IRQ\n");
+                    scsi_unregister(shp);
+                    continue;
+                }
+                if (request_dma(ha->drq,"gdth")) {
+                    printk("GDT-ISA: Unable to allocate DMA channel\n");
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
+                }
+                set_dma_mode(ha->drq,DMA_MODE_CASCADE);
+                enable_dma(ha->drq);
+                shp->unchecked_isa_dma = 1;
+                shp->irq = ha->irq;
+                shp->dma_channel = ha->drq;
+                hanum = gdth_ctr_count;         
+                gdth_ctr_tab[gdth_ctr_count++] = shp;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum= 0;
+
+                ha->pccb = CMDDATA(shp);
+                ha->ccb_phys = 0L;
+                ha->pdev = NULL;
+                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                                    &scratch_dma_handle);
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                        MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
+
+                ha->scratch_busy = FALSE;
+                ha->req_first = NULL;
+                ha->tid_cnt = MAX_HDRIVES;
+                if (max_ids > 0 && max_ids < ha->tid_cnt)
+                    ha->tid_cnt = max_ids;
+                for (i=0; i<GDTH_MAXCMDS; ++i)
+                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
+                ha->scan_mode = rescan ? 0x10 : 0;
+
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
+                    printk("GDT-ISA: Error during device scan\n");
+                    --gdth_ctr_count;
+                    --gdth_ctr_vcount;
+
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
+                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            ha->pscratch, ha->scratch_phys);
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
+                }
+                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+                    hdr_channel = ha->bus_cnt;
+                ha->virt_bus = hdr_channel;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+
+                shp->max_id      = ha->tid_cnt;
+                shp->max_lun     = MAXLUN;
+                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+                if (virt_ctr) {
+                    virt_ctr = 1;
+                    /* register addit. SCSI channels as virtual controllers */
+                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                        shp = scsi_register(shtp,sizeof(gdth_num_str));
+                        shp->unchecked_isa_dma = 1;
+                        shp->irq = ha->irq;
+                        shp->dma_channel = ha->drq;
+                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                        NUMDATA(shp)->hanum = (ushort)hanum;
+                        NUMDATA(shp)->busnum = b;
+                    }
+                }  
+
+                spin_lock_init(&ha->smp_lock);
+                gdth_enable_int(hanum);
+#endif /* !__ia64__ */
+            }
+        }
+
+        /* scanning for EISA controllers */
+        for (eisa_slot=0x1000; eisa_slot<=0x8000; eisa_slot+=0x1000) {
+            dma_addr_t scratch_dma_handle;
+            scratch_dma_handle = 0;
+
+            if (gdth_ctr_count >= MAXHA) 
+                break;
+            if (gdth_search_eisa(eisa_slot)) {      /* controller found */
+                shp = scsi_register(shtp,sizeof(gdth_ext_str));
+                if (shp == NULL)
+                    continue;  
+
+                ha = HADATA(shp);
+                if (!gdth_init_eisa(eisa_slot,ha)) {
+                    scsi_unregister(shp);
+                    continue;
+                }
+                /* controller found and initialized */
+                printk("Configuring GDT-EISA HA at Slot %d IRQ %u\n",
+                       eisa_slot>>12,ha->irq);
+
+                if (request_irq(ha->irq,gdth_interrupt,SA_INTERRUPT,"gdth",ha)) {
+                    printk("GDT-EISA: Unable to allocate IRQ\n");
+                    scsi_unregister(shp);
+                    continue;
+                }
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                hanum = gdth_ctr_count;
+                gdth_ctr_tab[gdth_ctr_count++] = shp;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum= 0;
+                TRACE2(("EISA detect Bus 0: hanum %d\n",
+                        NUMDATA(shp)->hanum));
+
+                ha->pccb = CMDDATA(shp);
+                ha->ccb_phys = 0L; 
+
+                ha->pdev = NULL;
+                ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                                    &scratch_dma_handle);
+                ha->scratch_phys = scratch_dma_handle;
+                ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                                &scratch_dma_handle);
+                ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+                ha->coal_stat = (gdth_coal_status *)
+                    pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                         MAXOFFSETS, &scratch_dma_handle);
+                ha->coal_stat_phys = scratch_dma_handle;
+#endif
+                ha->ccb_phys = 
+                    pci_map_single(ha->pdev,ha->pccb,
+                                   sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+                ha->scratch_busy = FALSE;
+                ha->req_first = NULL;
+                ha->tid_cnt = MAX_HDRIVES;
+                if (max_ids > 0 && max_ids < ha->tid_cnt)
+                    ha->tid_cnt = max_ids;
+                for (i=0; i<GDTH_MAXCMDS; ++i)
+                    ha->cmd_tab[i].cmnd = UNUSED_CMND;
+                ha->scan_mode = rescan ? 0x10 : 0;
+
+                if (ha->pscratch == NULL || ha->pmsg == NULL || 
+                    !gdth_search_drives(hanum)) {
+                    printk("GDT-EISA: Error during device scan\n");
+                    --gdth_ctr_count;
+                    --gdth_ctr_vcount;
+#ifdef INT_COAL
+                    if (ha->coal_stat)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                            MAXOFFSETS, ha->coal_stat,
+                                            ha->coal_stat_phys);
+#endif
+                    if (ha->pscratch)
+                        pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            ha->pscratch, ha->scratch_phys);
+                    if (ha->pmsg)
+                        pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                            ha->pmsg, ha->msg_phys);
+                    if (ha->ccb_phys)
+                        pci_unmap_single(ha->pdev,ha->ccb_phys,
+                                        sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+                    free_irq(ha->irq,ha);
+                    scsi_unregister(shp);
+                    continue;
+                }
+                if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+                    hdr_channel = ha->bus_cnt;
+                ha->virt_bus = hdr_channel;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) && \
+    LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+                shp->highmem_io  = 0;
+#endif
+                if (ha->cache_feat & ha->raw_feat & ha->screen_feat & GDT_64BIT) 
+                    shp->max_cmd_len = 16;
+
+                shp->max_id      = ha->tid_cnt;
+                shp->max_lun     = MAXLUN;
+                shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+                if (virt_ctr) {
+                    virt_ctr = 1;
+                    /* register addit. SCSI channels as virtual controllers */
+                    for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                        shp = scsi_register(shtp,sizeof(gdth_num_str));
+                        shp->unchecked_isa_dma = 0;
+                        shp->irq = ha->irq;
+                        shp->dma_channel = 0xff;
+                        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                        NUMDATA(shp)->hanum = (ushort)hanum;
+                        NUMDATA(shp)->busnum = b;
+                    }
+                }  
+
+                spin_lock_init(&ha->smp_lock);
+                gdth_enable_int(hanum);
+            }
+        }
+    }
+
+    /* scanning for PCI controllers */
+    cnt = gdth_search_pci(pcistr);
+    printk("GDT-HA: Found %d PCI Storage RAID Controllers\n",cnt);
+    gdth_sort_pci(pcistr,cnt);
+    for (ctr = 0; ctr < cnt; ++ctr) {
+        dma_addr_t scratch_dma_handle;
+        scratch_dma_handle = 0;
+
+        if (gdth_ctr_count >= MAXHA)
+            break;
+        shp = scsi_register(shtp,sizeof(gdth_ext_str));
+        if (shp == NULL)
+            continue;  
+
+        ha = HADATA(shp);
+        if (!gdth_init_pci(&pcistr[ctr],ha)) {
+            scsi_unregister(shp);
+            continue;
+        }
+        /* controller found and initialized */
+        printk("Configuring GDT-PCI HA at %d/%d IRQ %u\n",
+               pcistr[ctr].bus,PCI_SLOT(pcistr[ctr].device_fn),ha->irq);
+
+        if (request_irq(ha->irq, gdth_interrupt,
+                        SA_INTERRUPT|SA_SHIRQ, "gdth", ha))
+        {
+            printk("GDT-PCI: Unable to allocate IRQ\n");
+            scsi_unregister(shp);
+            continue;
+        }
+        shp->unchecked_isa_dma = 0;
+        shp->irq = ha->irq;
+        shp->dma_channel = 0xff;
+        hanum = gdth_ctr_count;
+        gdth_ctr_tab[gdth_ctr_count++] = shp;
+        gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+
+        NUMDATA(shp)->hanum = (ushort)hanum;
+        NUMDATA(shp)->busnum= 0;
+
+        ha->pccb = CMDDATA(shp);
+        ha->ccb_phys = 0L;
+
+        ha->pscratch = pci_alloc_consistent(ha->pdev, GDTH_SCRATCH, 
+                                            &scratch_dma_handle);
+        ha->scratch_phys = scratch_dma_handle;
+        ha->pmsg = pci_alloc_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                        &scratch_dma_handle);
+        ha->msg_phys = scratch_dma_handle;
+#ifdef INT_COAL
+        ha->coal_stat = (gdth_coal_status *)
+            pci_alloc_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                 MAXOFFSETS, &scratch_dma_handle);
+        ha->coal_stat_phys = scratch_dma_handle;
+#endif
+        ha->scratch_busy = FALSE;
+        ha->req_first = NULL;
+        ha->tid_cnt = pcistr[ctr].device_id >= 0x200 ? MAXID : MAX_HDRIVES;
+        if (max_ids > 0 && max_ids < ha->tid_cnt)
+            ha->tid_cnt = max_ids;
+        for (i=0; i<GDTH_MAXCMDS; ++i)
+            ha->cmd_tab[i].cmnd = UNUSED_CMND;
+        ha->scan_mode = rescan ? 0x10 : 0;
+
+        err = FALSE;
+        if (ha->pscratch == NULL || ha->pmsg == NULL || 
+            !gdth_search_drives(hanum)) {
+            err = TRUE;
+        } else {
+            if (hdr_channel < 0 || hdr_channel > ha->bus_cnt)
+                hdr_channel = ha->bus_cnt;
+            ha->virt_bus = hdr_channel;
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            scsi_set_device(shp, &pcistr[ctr].pdev->dev);
+#else
+            scsi_set_pci_device(shp, pcistr[ctr].pdev);
+#endif
+            if (!(ha->cache_feat & ha->raw_feat & ha->screen_feat &GDT_64BIT)||
+                /* 64-bit DMA only supported from FW >= x.43 */
+                (!ha->dma64_support)) {
+                if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 32-bit DMA\n", hanum);
+                    err = TRUE;
+                }
+            } else {
+                shp->max_cmd_len = 16;
+                if (!pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffffffffffffULL)) {
+                    printk("GDT-PCI %d: 64-bit DMA enabled\n", hanum);
+                } else if (pci_set_dma_mask(pcistr[ctr].pdev, 0xffffffff)) {
+                    printk(KERN_WARNING "GDT-PCI %d: Unable to set 64/32-bit DMA\n", hanum);
+                    err = TRUE;
+                }
+            }
+        }
+
+        if (err) {
+            printk("GDT-PCI %d: Error during device scan\n", hanum);
+            --gdth_ctr_count;
+            --gdth_ctr_vcount;
+#ifdef INT_COAL
+            if (ha->coal_stat)
+                pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                    MAXOFFSETS, ha->coal_stat,
+                                    ha->coal_stat_phys);
+#endif
+            if (ha->pscratch)
+                pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                    ha->pscratch, ha->scratch_phys);
+            if (ha->pmsg)
+                pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                    ha->pmsg, ha->msg_phys);
+            free_irq(ha->irq,ha);
+            scsi_unregister(shp);
+            continue;
+        }
+
+        shp->max_id      = ha->tid_cnt;
+        shp->max_lun     = MAXLUN;
+        shp->max_channel = virt_ctr ? 0 : ha->bus_cnt;
+        if (virt_ctr) {
+            virt_ctr = 1;
+            /* register addit. SCSI channels as virtual controllers */
+            for (b = 1; b < ha->bus_cnt + 1; ++b) {
+                shp = scsi_register(shtp,sizeof(gdth_num_str));
+                shp->unchecked_isa_dma = 0;
+                shp->irq = ha->irq;
+                shp->dma_channel = 0xff;
+                gdth_ctr_vtab[gdth_ctr_vcount++] = shp;
+                NUMDATA(shp)->hanum = (ushort)hanum;
+                NUMDATA(shp)->busnum = b;
+            }
+        }  
+
+        spin_lock_init(&ha->smp_lock);
+        gdth_enable_int(hanum);
+    }
+    
+    TRACE2(("gdth_detect() %d controller detected\n",gdth_ctr_count));
+    if (gdth_ctr_count > 0) {
+#ifdef GDTH_STATISTICS
+        TRACE2(("gdth_detect(): Initializing timer !\n"));
+        init_timer(&gdth_timer);
+        gdth_timer.expires = jiffies + HZ;
+        gdth_timer.data = 0L;
+        gdth_timer.function = gdth_timeout;
+        add_timer(&gdth_timer);
+#endif
+        major = register_chrdev(0,"gdth",&gdth_fops);
+        register_reboot_notifier(&gdth_notifier);
+    }
+    gdth_polling = FALSE;
+    return gdth_ctr_vcount;
+}
+
+
+int gdth_release(struct Scsi_Host *shp)
+{
+    int hanum;
+    gdth_ha_str *ha;
+
+    TRACE2(("gdth_release()\n"));
+    if (NUMDATA(shp)->busnum == 0) {
+        hanum = NUMDATA(shp)->hanum;
+        ha    = HADATA(gdth_ctr_tab[hanum]);
+        if (ha->sdev) {
+            scsi_free_host_dev(ha->sdev);
+            ha->sdev = NULL;
+        }
+        gdth_flush(hanum);
+
+        if (shp->irq) {
+            free_irq(shp->irq,ha);
+        }
+#ifndef __ia64__
+        if (shp->dma_channel != 0xff) {
+            free_dma(shp->dma_channel);
+        }
+#endif
+#ifdef INT_COAL
+        if (ha->coal_stat)
+            pci_free_consistent(ha->pdev, sizeof(gdth_coal_status) *
+                                MAXOFFSETS, ha->coal_stat, ha->coal_stat_phys);
+#endif
+        if (ha->pscratch)
+            pci_free_consistent(ha->pdev, GDTH_SCRATCH, 
+                                ha->pscratch, ha->scratch_phys);
+        if (ha->pmsg)
+            pci_free_consistent(ha->pdev, sizeof(gdth_msg_str), 
+                                ha->pmsg, ha->msg_phys);
+        if (ha->ccb_phys)
+            pci_unmap_single(ha->pdev,ha->ccb_phys,
+                             sizeof(gdth_cmd_str),PCI_DMA_BIDIRECTIONAL);
+        gdth_ctr_released++;
+        TRACE2(("gdth_release(): HA %d of %d\n", 
+                gdth_ctr_released, gdth_ctr_count));
+
+        if (gdth_ctr_released == gdth_ctr_count) {
+#ifdef GDTH_STATISTICS
+            del_timer(&gdth_timer);
+#endif
+            unregister_chrdev(major,"gdth");
+            unregister_reboot_notifier(&gdth_notifier);
+        }
+    }
+
+    scsi_unregister(shp);
+    return 0;
+}
+            
+
+static const char *gdth_ctr_name(int hanum)
+{
+    gdth_ha_str *ha;
+
+    TRACE2(("gdth_ctr_name()\n"));
+
+    ha    = HADATA(gdth_ctr_tab[hanum]);
+
+    if (ha->type == GDT_EISA) {
+        switch (ha->stype) {
+          case GDT3_ID:
+            return("GDT3000/3020");
+          case GDT3A_ID:
+            return("GDT3000A/3020A/3050A");
+          case GDT3B_ID:
+            return("GDT3000B/3010A");
+        }
+    } else if (ha->type == GDT_ISA) {
+        return("GDT2000/2020");
+    } else if (ha->type == GDT_PCI) {
+        switch (ha->stype) {
+          case PCI_DEVICE_ID_VORTEX_GDT60x0:
+            return("GDT6000/6020/6050");
+          case PCI_DEVICE_ID_VORTEX_GDT6000B:
+            return("GDT6000B/6010");
+        }
+    } 
+    /* new controllers (GDT_PCINEW, GDT_PCIMPR, ..) use board_info IOCTL! */
+
+    return("");
+}
+
+const char *gdth_info(struct Scsi_Host *shp)
+{
+    int hanum;
+    gdth_ha_str *ha;
+
+    TRACE2(("gdth_info()\n"));
+    hanum = NUMDATA(shp)->hanum;
+    ha    = HADATA(gdth_ctr_tab[hanum]);
+
+    return ((const char *)ha->binfo.type_string);
+}
+
+/* new error handling */
+int gdth_eh_abort(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_abort()\n"));
+    return FAILED;
+}
+
+int gdth_eh_device_reset(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_device_reset()\n"));
+    return FAILED;
+}
+
+int gdth_eh_bus_reset(Scsi_Cmnd *scp)
+{
+    int i, hanum;
+    gdth_ha_str *ha;
+    ulong flags;
+    Scsi_Cmnd *cmnd;
+    unchar b;
+
+    TRACE2(("gdth_eh_bus_reset()\n"));
+
+    hanum = NUMDATA(scp->device->host)->hanum;
+    b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+    ha    = HADATA(gdth_ctr_tab[hanum]);
+
+    /* clear command tab */
+    spin_lock_irqsave(&ha->smp_lock, flags);
+    for (i = 0; i < GDTH_MAXCMDS; ++i) {
+        cmnd = ha->cmd_tab[i].cmnd;
+        if (!SPECIAL_SCP(cmnd) && cmnd->device->channel == b)
+            ha->cmd_tab[i].cmnd = UNUSED_CMND;
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+    if (b == ha->virt_bus) {
+        /* host drives */
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                spin_lock_irqsave(&ha->smp_lock, flags);
+                gdth_polling = TRUE;
+                while (gdth_test_busy(hanum))
+                    gdth_delay(0);
+                if (gdth_internal_cmd(hanum, CACHESERVICE, 
+                                      GDT_CLUST_RESET, i, 0, 0))
+                    ha->hdr[i].cluster_type &= ~CLUSTER_RESERVED;
+                gdth_polling = FALSE;
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
+            }
+        }
+    } else {
+        /* raw devices */
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        for (i = 0; i < MAXID; ++i)
+            ha->raw[BUS_L2P(ha,b)].io_cnt[i] = 0;
+        gdth_polling = TRUE;
+        while (gdth_test_busy(hanum))
+            gdth_delay(0);
+        gdth_internal_cmd(hanum, SCSIRAWSERVICE, GDT_RESET_BUS,
+                          BUS_L2P(ha,b), 0, 0);
+        gdth_polling = FALSE;
+	spin_unlock_irqrestore(&ha->smp_lock, flags);
+    }
+    return SUCCESS;
+}
+
+int gdth_eh_host_reset(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_eh_host_reset()\n"));
+    return FAILED;
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_bios_param(struct scsi_device *sdev,struct block_device *bdev,sector_t cap,int *ip)
+#else
+int gdth_bios_param(Disk *disk,kdev_t dev,int *ip)
+#endif
+{
+    unchar b, t;
+    int hanum;
+    gdth_ha_str *ha;
+    struct scsi_device *sd;
+    unsigned capacity;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sd = sdev;
+    capacity = cap;
+#else
+    sd = disk->device;
+    capacity = disk->capacity;
+#endif
+    hanum = NUMDATA(sd->host)->hanum;
+    b = virt_ctr ? NUMDATA(sd->host)->busnum : sd->channel;
+    t = sd->id;
+    TRACE2(("gdth_bios_param() ha %d bus %d target %d\n", hanum, b, t)); 
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+    if (b != ha->virt_bus || ha->hdr[t].heads == 0) {
+        /* raw device or host drive without mapping information */
+        TRACE2(("Evaluate mapping\n"));
+        gdth_eval_mapping(capacity,&ip[2],&ip[0],&ip[1]);
+    } else {
+        ip[0] = ha->hdr[t].heads;
+        ip[1] = ha->hdr[t].secs;
+        ip[2] = capacity / ip[0] / ip[1];
+    }
+
+    TRACE2(("gdth_bios_param(): %d heads, %d secs, %d cyls\n",
+            ip[0],ip[1],ip[2]));
+    return 0;
+}
+
+
+int gdth_queuecommand(Scsi_Cmnd *scp,void (*done)(Scsi_Cmnd *))
+{
+    int hanum;
+    int priority;
+
+    TRACE(("gdth_queuecommand() cmd 0x%x\n", scp->cmnd[0]));
+    
+    scp->scsi_done = (void *)done;
+    scp->SCp.have_data_in = 1;
+    scp->SCp.phase = -1;
+    scp->SCp.sent_command = -1;
+    scp->SCp.Status = GDTH_MAP_NONE;
+    scp->SCp.buffer = (struct scatterlist *)NULL;
+
+    hanum = NUMDATA(scp->device->host)->hanum;
+#ifdef GDTH_STATISTICS
+    ++act_ios;
+#endif
+
+    priority = DEFAULT_PRI;
+    if (scp->done == gdth_scsi_done)
+        priority = scp->SCp.this_residual;
+    gdth_update_timeout(hanum, scp, scp->timeout_per_command * 6);
+    gdth_putq( hanum, scp, priority );
+    gdth_next( hanum );
+    return 0;
+}
+
+
+static int gdth_open(struct inode *inode, struct file *filep)
+{
+    gdth_ha_str *ha;
+    int i;
+
+    for (i = 0; i < gdth_ctr_count; i++) {
+        ha = HADATA(gdth_ctr_tab[i]);
+        if (!ha->sdev)
+            ha->sdev = scsi_get_host_dev(gdth_ctr_tab[i]);
+    }
+
+    TRACE(("gdth_open()\n"));
+    return 0;
+}
+
+static int gdth_close(struct inode *inode, struct file *filep)
+{
+    TRACE(("gdth_close()\n"));
+    return 0;
+}
+
+static int ioc_event(void __user *arg)
+{
+    gdth_ioctl_event evt;
+    gdth_ha_str *ha;
+    ulong flags;
+
+    if (copy_from_user(&evt, arg, sizeof(gdth_ioctl_event)) ||
+        evt.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[evt.ionode]);
+
+    if (evt.erase == 0xff) {
+        if (evt.event.event_source == ES_TEST)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.test); 
+        else if (evt.event.event_source == ES_DRIVER)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.driver); 
+        else if (evt.event.event_source == ES_SYNC)
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.sync); 
+        else
+            evt.event.event_data.size=sizeof(evt.event.event_data.eu.async);
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        gdth_store_event(ha, evt.event.event_source, evt.event.event_idx,
+                         &evt.event.event_data);
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+    } else if (evt.erase == 0xfe) {
+        gdth_clear_events();
+    } else if (evt.erase == 0) {
+        evt.handle = gdth_read_event(ha, evt.handle, &evt.event);
+    } else {
+        gdth_readapp_event(ha, evt.erase, &evt.event);
+    }     
+    if (copy_to_user(arg, &evt, sizeof(gdth_ioctl_event)))
+        return -EFAULT;
+    return 0;
+}
+
+static int ioc_lockdrv(void __user *arg)
+{
+    gdth_ioctl_lockdrv ldrv;
+    unchar i, j;
+    ulong flags;
+    gdth_ha_str *ha;
+
+    if (copy_from_user(&ldrv, arg, sizeof(gdth_ioctl_lockdrv)) ||
+        ldrv.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    ha = HADATA(gdth_ctr_tab[ldrv.ionode]);
+ 
+    for (i = 0; i < ldrv.drive_cnt && i < MAX_HDRIVES; ++i) {
+        j = ldrv.drives[i];
+        if (j >= MAX_HDRIVES || !ha->hdr[j].present)
+            continue;
+        if (ldrv.lock) {
+            spin_lock_irqsave(&ha->smp_lock, flags);
+            ha->hdr[j].lock = 1;
+            spin_unlock_irqrestore(&ha->smp_lock, flags);
+            gdth_wait_completion(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_stop_timeout(ldrv.ionode, ha->bus_cnt, j); 
+        } else {
+            spin_lock_irqsave(&ha->smp_lock, flags);
+            ha->hdr[j].lock = 0;
+            spin_unlock_irqrestore(&ha->smp_lock, flags);
+            gdth_start_timeout(ldrv.ionode, ha->bus_cnt, j); 
+            gdth_next(ldrv.ionode); 
+        }
+    } 
+    return 0;
+}
+
+static int ioc_resetdrv(void __user *arg, char *cmnd)
+{
+    gdth_ioctl_reset res;
+    gdth_cmd_str cmd;
+    int hanum;
+    gdth_ha_str *ha;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#else
+    Scsi_Cmnd *scp;
+#endif
+
+    if (copy_from_user(&res, arg, sizeof(gdth_ioctl_reset)) ||
+        res.ionode >= gdth_ctr_count || res.number >= MAX_HDRIVES)
+        return -EFAULT;
+    hanum = res.ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+ 
+    if (!ha->hdr[res.number].present)
+        return 0;
+    memset(&cmd, 0, sizeof(gdth_cmd_str));
+    cmd.Service = CACHESERVICE;
+    cmd.OpCode = GDT_CLUST_RESET;
+    if (ha->cache_feat & GDT_64BIT)
+        cmd.u.cache64.DeviceNo = res.number;
+    else
+        cmd.u.cache.DeviceNo = res.number;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &cmd, cmnd, 30);
+    res.status = (ushort)srp->sr_command->SCp.Status;
+    scsi_release_request(srp);
+#else
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &cmd, cmnd, 30);
+    res.status = (ushort)scp->SCp.Status;
+    scsi_release_command(scp);
+#endif
+
+    if (copy_to_user(arg, &res, sizeof(gdth_ioctl_reset)))
+        return -EFAULT;
+    return 0;
+}
+
+static int ioc_general(void __user *arg, char *cmnd)
+{
+    gdth_ioctl_general gen;
+    char *buf = NULL;
+    ulong64 paddr; 
+    int hanum;
+        gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        Scsi_Request *srp;
+#else
+        Scsi_Cmnd *scp;
+#endif
+        
+    if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general)) ||
+        gen.ionode >= gdth_ctr_count)
+        return -EFAULT;
+    hanum = gen.ionode; 
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    if (gen.data_len + gen.sense_len != 0) {
+        if (!(buf = gdth_ioctl_alloc(hanum, gen.data_len + gen.sense_len, 
+                                     FALSE, &paddr)))
+            return -EFAULT;
+        if (copy_from_user(buf, arg + sizeof(gdth_ioctl_general),  
+                           gen.data_len + gen.sense_len)) {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
+        }
+
+        if (gen.command.OpCode == GDT_IOCTL) {
+            gen.command.u.ioctl.p_param = paddr;
+        } else if (gen.command.Service == CACHESERVICE) {
+            if (ha->cache_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                gen.command.u.cache64.BlockCnt = gen.command.u.cache.BlockCnt;
+                gen.command.u.cache64.BlockNo = gen.command.u.cache.BlockNo;
+                gen.command.u.cache64.DeviceNo = gen.command.u.cache.DeviceNo;
+                /* addresses */
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    gen.command.u.cache64.DestAddr = (ulong64)-1;
+                    gen.command.u.cache64.sg_canz = 1;
+                    gen.command.u.cache64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.cache64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.cache64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.cache64.DestAddr = paddr;
+                    gen.command.u.cache64.sg_canz = 0;
+                }
+            } else {
+                if (ha->cache_feat & SCATTER_GATHER) {
+                    gen.command.u.cache.DestAddr = 0xffffffff;
+                    gen.command.u.cache.sg_canz = 1;
+                    gen.command.u.cache.sg_lst[0].sg_ptr = (ulong32)paddr;
+                    gen.command.u.cache.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.cache.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.cache.DestAddr = paddr;
+                    gen.command.u.cache.sg_canz = 0;
+                }
+            }
+        } else if (gen.command.Service == SCSIRAWSERVICE) {
+            if (ha->raw_feat & GDT_64BIT) {
+                /* copy elements from 32-bit IOCTL structure */
+                char cmd[16];
+                gen.command.u.raw64.sense_len = gen.command.u.raw.sense_len;
+                gen.command.u.raw64.bus = gen.command.u.raw.bus;
+                gen.command.u.raw64.lun = gen.command.u.raw.lun;
+                gen.command.u.raw64.target = gen.command.u.raw.target;
+                memcpy(cmd, gen.command.u.raw.cmd, 16);
+                memcpy(gen.command.u.raw64.cmd, cmd, 16);
+                gen.command.u.raw64.clen = gen.command.u.raw.clen;
+                gen.command.u.raw64.sdlen = gen.command.u.raw.sdlen;
+                gen.command.u.raw64.direction = gen.command.u.raw.direction;
+                /* addresses */
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    gen.command.u.raw64.sdata = (ulong64)-1;
+                    gen.command.u.raw64.sg_ranz = 1;
+                    gen.command.u.raw64.sg_lst[0].sg_ptr = paddr;
+                    gen.command.u.raw64.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.raw64.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.raw64.sdata = paddr;
+                    gen.command.u.raw64.sg_ranz = 0;
+                }
+                gen.command.u.raw64.sense_data = paddr + gen.data_len;
+            } else {
+                if (ha->raw_feat & SCATTER_GATHER) {
+                    gen.command.u.raw.sdata = 0xffffffff;
+                    gen.command.u.raw.sg_ranz = 1;
+                    gen.command.u.raw.sg_lst[0].sg_ptr = (ulong32)paddr;
+                    gen.command.u.raw.sg_lst[0].sg_len = gen.data_len;
+                    gen.command.u.raw.sg_lst[1].sg_len = 0;
+                } else {
+                    gen.command.u.raw.sdata = paddr;
+                    gen.command.u.raw.sg_ranz = 0;
+                }
+                gen.command.u.raw.sense_data = (ulong32)paddr + gen.data_len;
+            }
+        } else {
+            gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+            return -EFAULT;
+        }
+    }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        return -ENOMEM;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+    gdth_do_req(srp, &gen.command, cmnd, gen.timeout);
+    gen.status = srp->sr_command->SCp.Status;
+    gen.info = srp->sr_command->SCp.Message;
+    scsi_release_request(srp);
+#else
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+    gdth_do_cmd(scp, &gen.command, cmnd, gen.timeout);
+    gen.status = scp->SCp.Status;
+    gen.info = scp->SCp.Message;
+    scsi_release_command(scp);
+#endif
+
+    if (copy_to_user(arg + sizeof(gdth_ioctl_general), buf, 
+                     gen.data_len + gen.sense_len)) {
+        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        return -EFAULT; 
+    } 
+    if (copy_to_user(arg, &gen, 
+        sizeof(gdth_ioctl_general) - sizeof(gdth_cmd_str))) {
+        gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+        return -EFAULT;
+    }
+    gdth_ioctl_free(hanum, gen.data_len+gen.sense_len, buf, paddr);
+    return 0;
+}
+ 
+static int ioc_hdrlist(void __user *arg, char *cmnd)
+{
+    gdth_ioctl_rescan *rsc;
+    gdth_cmd_str *cmd;
+    gdth_ha_str *ha;
+    unchar i;
+    int hanum, rc = -ENOMEM;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#else
+    Scsi_Cmnd *scp;
+#endif
+        
+    rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
+    cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+    if (!rsc || !cmd)
+	goto free_fail;
+
+    if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc->ionode >= gdth_ctr_count) {
+        rc = -EFAULT;
+	goto free_fail;
+    }
+    hanum = rsc->ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(cmd, 0, sizeof(gdth_cmd_str));
+   
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        goto free_fail;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#else
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        goto free_fail;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#endif
+
+    for (i = 0; i < MAX_HDRIVES; ++i) { 
+        if (!ha->hdr[i].present) {
+            rsc->hdr_list[i].bus = 0xff; 
+            continue;
+        } 
+        rsc->hdr_list[i].bus = ha->virt_bus;
+        rsc->hdr_list[i].target = i;
+        rsc->hdr_list[i].lun = 0;
+        rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+        if (ha->hdr[i].cluster_type & CLUSTER_DRIVE) { 
+            cmd->Service = CACHESERVICE;
+            cmd->OpCode = GDT_CLUST_INFO;
+            if (ha->cache_feat & GDT_64BIT)
+                cmd->u.cache64.DeviceNo = i;
+            else
+                cmd->u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(srp, cmd, cmnd, 30);
+            if (srp->sr_command->SCp.Status == S_OK)
+                rsc->hdr_list[i].cluster_type = srp->sr_command->SCp.Message;
+#else
+            gdth_do_cmd(scp, cmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK)
+                rsc->hdr_list[i].cluster_type = scp->SCp.Message;
+#endif
+        }
+    } 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#else
+    scsi_release_command(scp);
+#endif       
+ 
+    if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan)))
+        rc = -EFAULT;
+    else
+	rc = 0;
+
+free_fail:
+    kfree(rsc);
+    kfree(cmd);
+    return rc;
+}
+
+static int ioc_rescan(void __user *arg, char *cmnd)
+{
+    gdth_ioctl_rescan *rsc;
+    gdth_cmd_str *cmd;
+    ushort i, status, hdr_cnt;
+    ulong32 info;
+    int hanum, cyls, hds, secs;
+    int rc = -ENOMEM;
+    ulong flags;
+    gdth_ha_str *ha; 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *srp;
+#else
+    Scsi_Cmnd *scp;
+#endif
+
+    rsc = kmalloc(sizeof(*rsc), GFP_KERNEL);
+    cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
+    if (!cmd || !rsc)
+	goto free_fail;
+
+    if (copy_from_user(rsc, arg, sizeof(gdth_ioctl_rescan)) ||
+        rsc->ionode >= gdth_ctr_count) {
+	rc = -EFAULT;
+	goto free_fail;
+    }
+    hanum = rsc->ionode;
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    memset(cmd, 0, sizeof(gdth_cmd_str));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    srp  = scsi_allocate_request(ha->sdev, GFP_KERNEL);
+    if (!srp)
+        goto free_fail;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#else
+    scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+    if (!scp)
+        goto free_fail;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#endif
+     
+    if (rsc->flag == 0) {
+        /* old method: re-init. cache service */
+        cmd->Service = CACHESERVICE;
+        if (ha->cache_feat & GDT_64BIT) {
+            cmd->OpCode = GDT_X_INIT_HOST;
+            cmd->u.cache64.DeviceNo = LINUX_OS;
+        } else {
+            cmd->OpCode = GDT_INIT;
+            cmd->u.cache.DeviceNo = LINUX_OS;
+        }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+        gdth_do_cmd(scp, cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#else
+        gdth_do_cmd(&scp, cmd, cmnd, 30);
+        status = (ushort)scp.SCp.Status;
+        info = (ulong32)scp.SCp.Message;
+#endif
+        i = 0;
+        hdr_cnt = (status == S_OK ? (ushort)info : 0);
+    } else {
+        i = rsc->hdr_no;
+        hdr_cnt = i + 1;
+    }
+
+    for (; i < hdr_cnt && i < MAX_HDRIVES; ++i) {
+        cmd->Service = CACHESERVICE;
+        cmd->OpCode = GDT_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd->u.cache64.DeviceNo = i;
+        else 
+            cmd->u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#else
+        gdth_do_cmd(scp, cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#endif
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        rsc->hdr_list[i].bus = ha->virt_bus;
+        rsc->hdr_list[i].target = i;
+        rsc->hdr_list[i].lun = 0;
+        if (status != S_OK) {
+            ha->hdr[i].present = FALSE;
+        } else {
+            ha->hdr[i].present = TRUE;
+            ha->hdr[i].size = info;
+            /* evaluate mapping */
+            ha->hdr[i].size &= ~SECS32;
+            gdth_eval_mapping(ha->hdr[i].size,&cyls,&hds,&secs); 
+            ha->hdr[i].heads = hds;
+            ha->hdr[i].secs = secs;
+            /* round size */
+            ha->hdr[i].size = cyls * hds * secs;
+        }
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+        if (status != S_OK)
+            continue; 
+        
+        /* extended info, if GDT_64BIT, for drives > 2 TB */
+        /* but we need ha->info2, not yet stored in scp->SCp */
+
+        /* devtype, cluster info, R/W attribs */
+        cmd->Service = CACHESERVICE;
+        cmd->OpCode = GDT_DEVTYPE;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd->u.cache64.DeviceNo = i;
+        else
+            cmd->u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#else
+        gdth_do_cmd(scp, cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#endif
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        ha->hdr[i].devtype = (status == S_OK ? (ushort)info : 0);
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+
+        cmd->Service = CACHESERVICE;
+        cmd->OpCode = GDT_CLUST_INFO;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd->u.cache64.DeviceNo = i;
+        else
+            cmd->u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#else
+        gdth_do_cmd(scp, cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#endif
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        ha->hdr[i].cluster_type = 
+            ((status == S_OK && !shared_access) ? (ushort)info : 0);
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+        rsc->hdr_list[i].cluster_type = ha->hdr[i].cluster_type;
+
+        cmd->Service = CACHESERVICE;
+        cmd->OpCode = GDT_RW_ATTRIBS;
+        if (ha->cache_feat & GDT_64BIT) 
+            cmd->u.cache64.DeviceNo = i;
+        else
+            cmd->u.cache.DeviceNo = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(srp, cmd, cmnd, 30);
+        status = (ushort)srp->sr_command->SCp.Status;
+        info = (ulong32)srp->sr_command->SCp.Message;
+#else
+        gdth_do_cmd(scp, cmd, cmnd, 30);
+        status = (ushort)scp->SCp.Status;
+        info = (ulong32)scp->SCp.Message;
+#endif
+        spin_lock_irqsave(&ha->smp_lock, flags);
+        ha->hdr[i].rw_attribs = (status == S_OK ? (ushort)info : 0);
+        spin_unlock_irqrestore(&ha->smp_lock, flags);
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+#else
+    scsi_release_command(scp);
+#endif       
+ 
+    if (copy_to_user(arg, rsc, sizeof(gdth_ioctl_rescan)))
+        rc = -EFAULT;
+    else
+	rc = 0;
+
+free_fail:
+    kfree(rsc);
+    kfree(cmd);
+    return rc;
+}
+  
+static int gdth_ioctl(struct inode *inode, struct file *filep,
+                      unsigned int cmd, unsigned long arg)
+{
+    gdth_ha_str *ha; 
+    Scsi_Cmnd *scp;
+    ulong flags;
+    char cmnd[MAX_COMMAND_SIZE];   
+    void __user *argp = (void __user *)arg;
+
+    memset(cmnd, 0xff, 12);
+    
+    TRACE(("gdth_ioctl() cmd 0x%x\n", cmd));
+ 
+    switch (cmd) {
+      case GDTIOCTL_CTRCNT:
+      { 
+        int cnt = gdth_ctr_count;
+        if (put_user(cnt, (int __user *)argp))
+                return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_DRVERS:
+      { 
+        int ver = (GDTH_VERSION<<8) | GDTH_SUBVERSION;
+        if (put_user(ver, (int __user *)argp))
+                return -EFAULT;
+        break;
+      }
+      
+      case GDTIOCTL_OSVERS:
+      { 
+        gdth_ioctl_osvers osv; 
+
+        osv.version = (unchar)(LINUX_VERSION_CODE >> 16);
+        osv.subversion = (unchar)(LINUX_VERSION_CODE >> 8);
+        osv.revision = (ushort)(LINUX_VERSION_CODE & 0xff);
+        if (copy_to_user(argp, &osv, sizeof(gdth_ioctl_osvers)))
+                return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_CTRTYPE:
+      { 
+        gdth_ioctl_ctrtype ctrt;
+        
+        if (copy_from_user(&ctrt, argp, sizeof(gdth_ioctl_ctrtype)) ||
+            ctrt.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        ha = HADATA(gdth_ctr_tab[ctrt.ionode]);
+        if (ha->type == GDT_ISA || ha->type == GDT_EISA) {
+            ctrt.type = (unchar)((ha->stype>>20) - 0x10);
+        } else {
+            if (ha->type != GDT_PCIMPR) {
+                ctrt.type = (unchar)((ha->stype<<4) + 6);
+            } else {
+                ctrt.type = 
+                    (ha->oem_id == OEM_ID_INTEL ? 0xfd : 0xfe);
+                if (ha->stype >= 0x300)
+                    ctrt.ext_type = 0x6000 | ha->subdevice_id;
+                else 
+                    ctrt.ext_type = 0x6000 | ha->stype;
+            }
+            ctrt.device_id = ha->stype;
+            ctrt.sub_device_id = ha->subdevice_id;
+        }
+        ctrt.info = ha->brd_phys;
+        ctrt.oem_id = ha->oem_id;
+        if (copy_to_user(argp, &ctrt, sizeof(gdth_ioctl_ctrtype)))
+            return -EFAULT;
+        break;
+      }
+        
+      case GDTIOCTL_GENERAL:
+        return ioc_general(argp, cmnd);
+
+      case GDTIOCTL_EVENT:
+        return ioc_event(argp);
+
+      case GDTIOCTL_LOCKDRV:
+        return ioc_lockdrv(argp);
+
+      case GDTIOCTL_LOCKCHN:
+      {
+        gdth_ioctl_lockchn lchn;
+        unchar i, j;
+
+        if (copy_from_user(&lchn, argp, sizeof(gdth_ioctl_lockchn)) ||
+            lchn.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        ha = HADATA(gdth_ctr_tab[lchn.ionode]);
+        
+        i = lchn.channel;
+        if (i < ha->bus_cnt) {
+            if (lchn.lock) {
+                spin_lock_irqsave(&ha->smp_lock, flags);
+                ha->raw[i].lock = 1;
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
+                for (j = 0; j < ha->tid_cnt; ++j) {
+                    gdth_wait_completion(lchn.ionode, i, j); 
+                    gdth_stop_timeout(lchn.ionode, i, j); 
+                }
+            } else {
+                spin_lock_irqsave(&ha->smp_lock, flags);
+                ha->raw[i].lock = 0;
+                spin_unlock_irqrestore(&ha->smp_lock, flags);
+                for (j = 0; j < ha->tid_cnt; ++j) {
+                    gdth_start_timeout(lchn.ionode, i, j); 
+                    gdth_next(lchn.ionode); 
+                }
+            }
+        } 
+        break;
+      }
+
+      case GDTIOCTL_RESCAN:
+        return ioc_rescan(argp, cmnd);
+
+      case GDTIOCTL_HDRLIST:
+        return ioc_hdrlist(argp, cmnd);
+
+      case GDTIOCTL_RESET_BUS:
+      {
+        gdth_ioctl_reset res;
+        int hanum, rval;
+
+        if (copy_from_user(&res, argp, sizeof(gdth_ioctl_reset)) ||
+            res.ionode >= gdth_ctr_count)
+            return -EFAULT;
+        hanum = res.ionode; 
+        ha = HADATA(gdth_ctr_tab[hanum]);
+
+        /* Because we need a Scsi_Cmnd struct., we make a scsi_allocate device also for kernels >=2.6.x */        
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        scp  = scsi_get_command(ha->sdev, GFP_KERNEL);
+        if (!scp)
+            return -ENOMEM;
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+        scp->device->channel = virt_ctr ? 0 : res.number;
+        rval = gdth_eh_bus_reset(scp);
+        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
+        scsi_put_command(scp);
+#else
+        scp  = scsi_allocate_device(ha->sdev, 1, FALSE);
+        if (!scp)
+            return -ENOMEM;
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+        scp->channel = virt_ctr ? 0 : res.number;
+        rval = gdth_eh_bus_reset(scp);
+        res.status = (rval == SUCCESS ? S_OK : S_GENERR);
+        scsi_release_command(scp);
+#endif
+        if (copy_to_user(argp, &res, sizeof(gdth_ioctl_reset)))
+            return -EFAULT;
+        break;
+      }
+
+      case GDTIOCTL_RESET_DRV:
+        return ioc_resetdrv(argp, cmnd);
+
+      default:
+        break; 
+    }
+    return 0;
+}
+
+
+/* flush routine */
+static void gdth_flush(int hanum)
+{
+    int             i;
+    gdth_ha_str     *ha;
+    gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *srp;
+#else
+    Scsi_Cmnd       *scp;
+#endif
+    Scsi_Device     *sdev;
+    char            cmnd[MAX_COMMAND_SIZE];   
+    memset(cmnd, 0xff, MAX_COMMAND_SIZE);
+
+    TRACE2(("gdth_flush() hanum %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+    srp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!srp)
+        return;
+    srp->sr_cmd_len = 12;
+    srp->sr_use_sg = 0;
+#else
+    sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+        return;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#endif
+
+    for (i = 0; i < MAX_HDRIVES; ++i) {
+        if (ha->hdr[i].present) {
+            gdtcmd.BoardNode = LOCALBOARD;
+            gdtcmd.Service = CACHESERVICE;
+            gdtcmd.OpCode = GDT_FLUSH;
+            if (ha->cache_feat & GDT_64BIT) { 
+                gdtcmd.u.cache64.DeviceNo = i;
+                gdtcmd.u.cache64.BlockNo = 1;
+                gdtcmd.u.cache64.sg_canz = 0;
+            } else {
+                gdtcmd.u.cache.DeviceNo = i;
+                gdtcmd.u.cache.BlockNo = 1;
+                gdtcmd.u.cache.sg_canz = 0;
+            }
+            TRACE2(("gdth_flush(): flush ha %d drive %d\n", hanum, i));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(srp, &gdtcmd, cmnd, 30);
+#else
+            gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#endif
+        }
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(srp);
+    scsi_free_host_dev(sdev);
+#else
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
+}
+
+/* shutdown routine */
+static int gdth_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+    int             hanum;
+#ifndef __alpha__
+    gdth_cmd_str    gdtcmd;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *srp;
+    Scsi_Device     *sdev;
+#else
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#endif
+    char            cmnd[MAX_COMMAND_SIZE];   
+#endif
+
+    TRACE2(("gdth_halt() event %d\n",(int)event));
+    if (event != SYS_RESTART && event != SYS_HALT && event != SYS_POWER_OFF)
+        return NOTIFY_DONE;
+
+    printk("GDT-HA: Flushing all host drives .. ");
+    for (hanum = 0; hanum < gdth_ctr_count; ++hanum) {
+        gdth_flush(hanum);
+
+#ifndef __alpha__
+        /* controller reset */
+        memset(cmnd, 0xff, MAX_COMMAND_SIZE);
+        gdtcmd.BoardNode = LOCALBOARD;
+        gdtcmd.Service = CACHESERVICE;
+        gdtcmd.OpCode = GDT_RESET;
+        TRACE2(("gdth_halt(): reset controller %d\n", hanum));
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+        srp  = scsi_allocate_request(sdev, GFP_KERNEL);
+        if (!srp) {
+            unregister_reboot_notifier(&gdth_notifier);
+            return NOTIFY_OK;
+        }
+        srp->sr_cmd_len = 12;
+        srp->sr_use_sg = 0;
+        gdth_do_req(srp, &gdtcmd, cmnd, 10);
+        scsi_release_request(srp);
+        scsi_free_host_dev(sdev);
+#else
+        sdev = scsi_get_host_dev(gdth_ctr_tab[hanum]);
+        scp  = scsi_allocate_device(sdev, 1, FALSE);
+        if (!scp) {
+            unregister_reboot_notifier(&gdth_notifier);
+            return NOTIFY_OK;
+        }
+        scp->cmd_len = 12;
+        scp->use_sg = 0;
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 10);
+        scsi_release_command(scp);
+        scsi_free_host_dev(sdev);
+#endif
+#endif
+    }
+    printk("Done.\n");
+
+#ifdef GDTH_STATISTICS
+    del_timer(&gdth_timer);
+#endif
+    unregister_reboot_notifier(&gdth_notifier);
+    return NOTIFY_OK;
+}
+
+static Scsi_Host_Template driver_template = {
+        .proc_name              = "gdth", 
+        .proc_info              = gdth_proc_info,
+        .name                   = "GDT SCSI Disk Array Controller",
+        .detect                 = gdth_detect, 
+        .release                = gdth_release,
+        .info                   = gdth_info, 
+        .queuecommand           = gdth_queuecommand,
+        .eh_abort_handler       = gdth_eh_abort, 
+        .eh_device_reset_handler = gdth_eh_device_reset,
+        .eh_bus_reset_handler   = gdth_eh_bus_reset,
+        .eh_host_reset_handler  = gdth_eh_host_reset,
+        .bios_param             = gdth_bios_param,
+        .can_queue              = GDTH_MAXCMDS,
+        .this_id                = -1,
+        .sg_tablesize           = GDTH_MAXSG,
+        .cmd_per_lun            = GDTH_MAXC_P_L,
+        .unchecked_isa_dma      = 1,
+        .use_clustering         = ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
+        .use_new_eh_code        = 1,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)
+        .highmem_io             = 1,
+#endif
+#endif
+};
+
+#include "scsi_module.c"
+#ifndef MODULE
+__setup("gdth=", option_setup);
+#endif
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
new file mode 100644
index 0000000..bf269f0
--- /dev/null
+++ b/drivers/scsi/gdth.h
@@ -0,0 +1,1079 @@
+#ifndef _GDTH_H
+#define _GDTH_H
+
+/*
+ * Header file for the GDT Disk Array/Storage RAID controllers driver for Linux
+ * 
+ * gdth.h Copyright (C) 1995-03 ICP vortex, Achim Leubner
+ * See gdth.c for further informations and 
+ * below for supported controller types
+ *
+ * <achim_leubner@adaptec.com>
+ *
+ * $Id: gdth.h,v 1.57 2004/03/31 11:52:09 achim Exp $
+ */
+
+#include <linux/version.h>
+#include <linux/types.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* defines, macros */
+
+/* driver version */
+#define GDTH_VERSION_STR        "3.04"
+#define GDTH_VERSION            3
+#define GDTH_SUBVERSION         4
+
+/* protocol version */
+#define PROTOCOL_VERSION        1
+
+/* OEM IDs */
+#define OEM_ID_ICP      0x941c
+#define OEM_ID_INTEL    0x8000
+
+/* controller classes */
+#define GDT_ISA         0x01                    /* ISA controller */
+#define GDT_EISA        0x02                    /* EISA controller */
+#define GDT_PCI         0x03                    /* PCI controller */
+#define GDT_PCINEW      0x04                    /* new PCI controller */
+#define GDT_PCIMPR      0x05                    /* PCI MPR controller */
+/* GDT_EISA, controller subtypes EISA */
+#define GDT3_ID         0x0130941c              /* GDT3000/3020 */
+#define GDT3A_ID        0x0230941c              /* GDT3000A/3020A/3050A */
+#define GDT3B_ID        0x0330941c              /* GDT3000B/3010A */
+/* GDT_ISA */
+#define GDT2_ID         0x0120941c              /* GDT2000/2020 */
+
+/* vendor ID, device IDs (PCI) */
+/* these defines should already exist in <linux/pci.h> */
+#ifndef PCI_VENDOR_ID_VORTEX
+#define PCI_VENDOR_ID_VORTEX            0x1119  /* PCI controller vendor ID */
+#endif
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL             0x8086  
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDT60x0
+/* GDT_PCI */
+#define PCI_DEVICE_ID_VORTEX_GDT60x0    0       /* GDT6000/6020/6050 */
+#define PCI_DEVICE_ID_VORTEX_GDT6000B   1       /* GDT6000B/6010 */
+/* GDT_PCINEW */
+#define PCI_DEVICE_ID_VORTEX_GDT6x10    2       /* GDT6110/6510 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x20    3       /* GDT6120/6520 */
+#define PCI_DEVICE_ID_VORTEX_GDT6530    4       /* GDT6530 */
+#define PCI_DEVICE_ID_VORTEX_GDT6550    5       /* GDT6550 */
+/* GDT_PCINEW, wide/ultra SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17    6       /* GDT6117/6517 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27    7       /* GDT6127/6527 */
+#define PCI_DEVICE_ID_VORTEX_GDT6537    8       /* GDT6537 */
+#define PCI_DEVICE_ID_VORTEX_GDT6557    9       /* GDT6557/6557-ECC */
+/* GDT_PCINEW, wide SCSI controllers */
+#define PCI_DEVICE_ID_VORTEX_GDT6x15    10      /* GDT6115/6515 */
+#define PCI_DEVICE_ID_VORTEX_GDT6x25    11      /* GDT6125/6525 */
+#define PCI_DEVICE_ID_VORTEX_GDT6535    12      /* GDT6535 */
+#define PCI_DEVICE_ID_VORTEX_GDT6555    13      /* GDT6555/6555-ECC */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RP
+/* GDT_MPR, RP series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RP  0x100   /* GDT6117RP/GDT6517RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RP  0x101   /* GDT6127RP/GDT6527RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RP  0x102   /* GDT6537RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RP  0x103   /* GDT6557RP */
+/* GDT_MPR, RP series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RP  0x104   /* GDT6111RP/GDT6511RP */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RP  0x105   /* GDT6121RP/GDT6521RP */
+#endif
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6x17RD
+/* GDT_MPR, RD series, wide/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x17RD  0x110   /* GDT6117RD/GDT6517RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x27RD  0x111   /* GDT6127RD/GDT6527RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6537RD  0x112   /* GDT6537RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6557RD  0x113   /* GDT6557RD */
+/* GDT_MPR, RD series, narrow/ultra SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x11RD  0x114   /* GDT6111RD/GDT6511RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x21RD  0x115   /* GDT6121RD/GDT6521RD */
+/* GDT_MPR, RD series, wide/ultra2 SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT6x18RD  0x118   /* GDT6118RD/GDT6518RD/
+                                                   GDT6618RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x28RD  0x119   /* GDT6128RD/GDT6528RD/
+                                                   GDT6628RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x38RD  0x11A   /* GDT6538RD/GDT6638RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x58RD  0x11B   /* GDT6558RD/GDT6658RD */
+/* GDT_MPR, RN series (64-bit PCI), wide/ultra2 SCSI */
+#define PCI_DEVICE_ID_VORTEX_GDT7x18RN  0x168   /* GDT7118RN/GDT7518RN/
+                                                   GDT7618RN */
+#define PCI_DEVICE_ID_VORTEX_GDT7x28RN  0x169   /* GDT7128RN/GDT7528RN/
+                                                   GDT7628RN */
+#define PCI_DEVICE_ID_VORTEX_GDT7x38RN  0x16A   /* GDT7538RN/GDT7638RN */
+#define PCI_DEVICE_ID_VORTEX_GDT7x58RN  0x16B   /* GDT7558RN/GDT7658RN */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDT6x19RD
+/* GDT_MPR, RD series, Fibre Channel */
+#define PCI_DEVICE_ID_VORTEX_GDT6x19RD  0x210   /* GDT6519RD/GDT6619RD */
+#define PCI_DEVICE_ID_VORTEX_GDT6x29RD  0x211   /* GDT6529RD/GDT6629RD */
+/* GDT_MPR, RN series (64-bit PCI), Fibre Channel */
+#define PCI_DEVICE_ID_VORTEX_GDT7x19RN  0x260   /* GDT7519RN/GDT7619RN */
+#define PCI_DEVICE_ID_VORTEX_GDT7x29RN  0x261   /* GDT7529RN/GDT7629RN */
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTMAXRP
+/* GDT_MPR, last device ID */
+#define PCI_DEVICE_ID_VORTEX_GDTMAXRP   0x2ff   
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX
+/* new GDT Rx Controller */
+#define PCI_DEVICE_ID_VORTEX_GDTNEWRX   0x300
+#endif
+
+#ifndef PCI_DEVICE_ID_VORTEX_GDTNEWRX2
+/* new(2) GDT Rx Controller */
+#define PCI_DEVICE_ID_VORTEX_GDTNEWRX2  0x301
+#endif        
+
+#ifndef PCI_DEVICE_ID_INTEL_SRC
+/* Intel Storage RAID Controller */
+#define PCI_DEVICE_ID_INTEL_SRC         0x600
+#endif
+
+#ifndef PCI_DEVICE_ID_INTEL_SRC_XSCALE
+/* Intel Storage RAID Controller */
+#define PCI_DEVICE_ID_INTEL_SRC_XSCALE  0x601
+#endif
+
+/* limits */
+#define GDTH_SCRATCH    PAGE_SIZE               /* 4KB scratch buffer */
+#define GDTH_MAXCMDS    120
+#define GDTH_MAXC_P_L   16                      /* max. cmds per lun */
+#define GDTH_MAX_RAW    2                       /* max. cmds per raw device */
+#define MAXOFFSETS      128
+#define MAXHA           16
+#define MAXID           127
+#define MAXLUN          8
+#define MAXBUS          6
+#define MAX_EVENTS      100                     /* event buffer count */
+#define MAX_RES_ARGS    40                      /* device reservation, 
+                                                   must be a multiple of 4 */
+#define MAXCYLS         1024
+#define HEADS           64
+#define SECS            32                      /* mapping 64*32 */
+#define MEDHEADS        127
+#define MEDSECS         63                      /* mapping 127*63 */
+#define BIGHEADS        255
+#define BIGSECS         63                      /* mapping 255*63 */
+
+/* special command ptr. */
+#define UNUSED_CMND     ((Scsi_Cmnd *)-1)
+#define INTERNAL_CMND   ((Scsi_Cmnd *)-2)
+#define SCREEN_CMND     ((Scsi_Cmnd *)-3)
+#define SPECIAL_SCP(p)  (p==UNUSED_CMND || p==INTERNAL_CMND || p==SCREEN_CMND)
+
+/* controller services */
+#define SCSIRAWSERVICE  3
+#define CACHESERVICE    9
+#define SCREENSERVICE   11
+
+/* screenservice defines */
+#define MSG_INV_HANDLE  -1                      /* special message handle */
+#define MSGLEN          16                      /* size of message text */
+#define MSG_SIZE        34                      /* size of message structure */
+#define MSG_REQUEST     0                       /* async. event: message */
+
+/* cacheservice defines */
+#define SECTOR_SIZE     0x200                   /* always 512 bytes per sec. */
+
+/* DPMEM constants */
+#define DPMEM_MAGIC     0xC0FFEE11
+#define IC_HEADER_BYTES 48
+#define IC_QUEUE_BYTES  4
+#define DPMEM_COMMAND_OFFSET    IC_HEADER_BYTES+IC_QUEUE_BYTES*MAXOFFSETS
+
+/* cluster_type constants */
+#define CLUSTER_DRIVE         1
+#define CLUSTER_MOUNTED       2
+#define CLUSTER_RESERVED      4
+#define CLUSTER_RESERVE_STATE (CLUSTER_DRIVE|CLUSTER_MOUNTED|CLUSTER_RESERVED)
+
+/* commands for all services, cache service */
+#define GDT_INIT        0                       /* service initialization */
+#define GDT_READ        1                       /* read command */
+#define GDT_WRITE       2                       /* write command */
+#define GDT_INFO        3                       /* information about devices */
+#define GDT_FLUSH       4                       /* flush dirty cache buffers */
+#define GDT_IOCTL       5                       /* ioctl command */
+#define GDT_DEVTYPE     9                       /* additional information */
+#define GDT_MOUNT       10                      /* mount cache device */
+#define GDT_UNMOUNT     11                      /* unmount cache device */
+#define GDT_SET_FEAT    12                      /* set feat. (scatter/gather) */
+#define GDT_GET_FEAT    13                      /* get features */
+#define GDT_WRITE_THR   16                      /* write through */
+#define GDT_READ_THR    17                      /* read through */
+#define GDT_EXT_INFO    18                      /* extended info */
+#define GDT_RESET       19                      /* controller reset */
+#define GDT_RESERVE_DRV 20                      /* reserve host drive */
+#define GDT_RELEASE_DRV 21                      /* release host drive */
+#define GDT_CLUST_INFO  22                      /* cluster info */
+#define GDT_RW_ATTRIBS  23                      /* R/W attribs (write thru,..)*/
+#define GDT_CLUST_RESET 24                      /* releases the cluster drives*/
+#define GDT_FREEZE_IO   25                      /* freezes all IOs */
+#define GDT_UNFREEZE_IO 26                      /* unfreezes all IOs */
+#define GDT_X_INIT_HOST 29                      /* ext. init: 64 bit support */
+#define GDT_X_INFO      30                      /* ext. info for drives>2TB */
+
+/* raw service commands */
+#define GDT_RESERVE     14                      /* reserve dev. to raw serv. */
+#define GDT_RELEASE     15                      /* release device */
+#define GDT_RESERVE_ALL 16                      /* reserve all devices */
+#define GDT_RELEASE_ALL 17                      /* release all devices */
+#define GDT_RESET_BUS   18                      /* reset bus */
+#define GDT_SCAN_START  19                      /* start device scan */
+#define GDT_SCAN_END    20                      /* stop device scan */  
+#define GDT_X_INIT_RAW  21                      /* ext. init: 64 bit support */
+
+/* screen service commands */
+#define GDT_REALTIME    3                       /* realtime clock to screens. */
+#define GDT_X_INIT_SCR  4                       /* ext. init: 64 bit support */
+
+/* IOCTL command defines */
+#define SCSI_DR_INFO    0x00                    /* SCSI drive info */                   
+#define SCSI_CHAN_CNT   0x05                    /* SCSI channel count */   
+#define SCSI_DR_LIST    0x06                    /* SCSI drive list */
+#define SCSI_DEF_CNT    0x15                    /* grown/primary defects */
+#define DSK_STATISTICS  0x4b                    /* SCSI disk statistics */
+#define IOCHAN_DESC     0x5d                    /* description of IO channel */
+#define IOCHAN_RAW_DESC 0x5e                    /* description of raw IO chn. */
+#define L_CTRL_PATTERN  0x20000000L             /* SCSI IOCTL mask */
+#define ARRAY_INFO      0x12                    /* array drive info */
+#define ARRAY_DRV_LIST  0x0f                    /* array drive list */
+#define ARRAY_DRV_LIST2 0x34                    /* array drive list (new) */
+#define LA_CTRL_PATTERN 0x10000000L             /* array IOCTL mask */
+#define CACHE_DRV_CNT   0x01                    /* cache drive count */
+#define CACHE_DRV_LIST  0x02                    /* cache drive list */
+#define CACHE_INFO      0x04                    /* cache info */
+#define CACHE_CONFIG    0x05                    /* cache configuration */
+#define CACHE_DRV_INFO  0x07                    /* cache drive info */
+#define BOARD_FEATURES  0x15                    /* controller features */
+#define BOARD_INFO      0x28                    /* controller info */
+#define SET_PERF_MODES  0x82                    /* set mode (coalescing,..) */
+#define GET_PERF_MODES  0x83                    /* get mode */
+#define CACHE_READ_OEM_STRING_RECORD 0x84       /* read OEM string record */ 
+#define HOST_GET        0x10001L                /* get host drive list */
+#define IO_CHANNEL      0x00020000L             /* default IO channel */
+#define INVALID_CHANNEL 0x0000ffffL             /* invalid channel */
+
+/* service errors */
+#define S_OK            1                       /* no error */
+#define S_GENERR        6                       /* general error */
+#define S_BSY           7                       /* controller busy */
+#define S_CACHE_UNKNOWN 12                      /* cache serv.: drive unknown */
+#define S_RAW_SCSI      12                      /* raw serv.: target error */
+#define S_RAW_ILL       0xff                    /* raw serv.: illegal */
+#define S_NOFUNC        -2                      /* unknown function */
+#define S_CACHE_RESERV  -24                     /* cache: reserv. conflict */   
+
+/* timeout values */
+#define INIT_RETRIES    100000                  /* 100000 * 1ms = 100s */
+#define INIT_TIMEOUT    100000                  /* 100000 * 1ms = 100s */
+#define POLL_TIMEOUT    10000                   /* 10000 * 1ms = 10s */
+
+/* priorities */
+#define DEFAULT_PRI     0x20
+#define IOCTL_PRI       0x10
+#define HIGH_PRI        0x08
+
+/* data directions */
+#define GDTH_DATA_IN    0x01000000L             /* data from target */
+#define GDTH_DATA_OUT   0x00000000L             /* data to target */
+
+/* BMIC registers (EISA controllers) */
+#define ID0REG          0x0c80                  /* board ID */
+#define EINTENABREG     0x0c89                  /* interrupt enable */
+#define SEMA0REG        0x0c8a                  /* command semaphore */
+#define SEMA1REG        0x0c8b                  /* status semaphore */
+#define LDOORREG        0x0c8d                  /* local doorbell */
+#define EDENABREG       0x0c8e                  /* EISA system doorbell enab. */
+#define EDOORREG        0x0c8f                  /* EISA system doorbell */
+#define MAILBOXREG      0x0c90                  /* mailbox reg. (16 bytes) */
+#define EISAREG         0x0cc0                  /* EISA configuration */
+
+/* DMA memory mappings */
+#define GDTH_MAP_NONE   0
+#define GDTH_MAP_SINGLE 1
+#define GDTH_MAP_SG     2
+#define GDTH_MAP_IOCTL  3 
+
+/* other defines */
+#define LINUX_OS        8                       /* used for cache optim. */
+#define SCATTER_GATHER  1                       /* s/g feature */
+#define SECS32          0x1f                    /* round capacity */
+#define BIOS_ID_OFFS    0x10                    /* offset contr-ID in ISABIOS */
+#define LOCALBOARD      0                       /* board node always 0 */
+#define ASYNCINDEX      0                       /* cmd index async. event */
+#define SPEZINDEX       1                       /* cmd index unknown service */
+#define COALINDEX       (GDTH_MAXCMDS + 2)
+
+/* features */
+#define SCATTER_GATHER  1                       /* s/g feature */
+#define GDT_WR_THROUGH  0x100                   /* WRITE_THROUGH supported */
+#define GDT_64BIT       0x200                   /* 64bit / drv>2TB support */
+
+#include "gdth_ioctl.h"
+
+/* screenservice message */
+typedef struct {                               
+    ulong32     msg_handle;                     /* message handle */
+    ulong32     msg_len;                        /* size of message */
+    ulong32     msg_alen;                       /* answer length */
+    unchar      msg_answer;                     /* answer flag */
+    unchar      msg_ext;                        /* more messages */
+    unchar      msg_reserved[2];
+    char        msg_text[MSGLEN+2];             /* the message text */
+} PACKED gdth_msg_str;
+
+
+/* IOCTL data structures */
+
+/* Status coalescing buffer for returning multiple requests per interrupt */
+typedef struct {
+    ulong32     status;
+    ulong32     ext_status;
+    ulong32     info0;
+    ulong32     info1;
+} PACKED gdth_coal_status;
+
+/* performance mode data structure */
+typedef struct {
+    ulong32     version;            /* The version of this IOCTL structure. */
+    ulong32     st_mode;            /* 0=dis., 1=st_buf_addr1 valid, 2=both  */
+    ulong32     st_buff_addr1;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr1;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx1;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_addr2;      /* physical address of status buffer 1 */
+    ulong32     st_buff_u_addr2;    /* reserved for 64 bit addressing */
+    ulong32     st_buff_indx2;      /* reserved command idx. for this buffer */
+    ulong32     st_buff_size;       /* size of each buffer in bytes */
+    ulong32     cmd_mode;           /* 0 = mode disabled, 1 = cmd_buff_addr1 */ 
+    ulong32     cmd_buff_addr1;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr1;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx1;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_addr2;     /* physical address of cmd buffer 1 */   
+    ulong32     cmd_buff_u_addr2;   /* reserved for 64 bit addressing */
+    ulong32     cmd_buff_indx2;     /* cmd buf addr1 unique identifier */
+    ulong32     cmd_buff_size;      /* size of each cmd bufer in bytes */
+    ulong32     reserved1;
+    ulong32     reserved2;
+} PACKED gdth_perf_modes;
+
+/* SCSI drive info */
+typedef struct {
+    unchar      vendor[8];                      /* vendor string */
+    unchar      product[16];                    /* product string */
+    unchar      revision[4];                    /* revision */
+    ulong32     sy_rate;                        /* current rate for sync. tr. */
+    ulong32     sy_max_rate;                    /* max. rate for sync. tr. */
+    ulong32     no_ldrive;                      /* belongs to this log. drv.*/
+    ulong32     blkcnt;                         /* number of blocks */
+    ushort      blksize;                        /* size of block in bytes */
+    unchar      available;                      /* flag: access is available */
+    unchar      init;                           /* medium is initialized */
+    unchar      devtype;                        /* SCSI devicetype */
+    unchar      rm_medium;                      /* medium is removable */
+    unchar      wp_medium;                      /* medium is write protected */
+    unchar      ansi;                           /* SCSI I/II or III? */
+    unchar      protocol;                       /* same as ansi */
+    unchar      sync;                           /* flag: sync. transfer enab. */
+    unchar      disc;                           /* flag: disconnect enabled */
+    unchar      queueing;                       /* flag: command queing enab. */
+    unchar      cached;                         /* flag: caching enabled */
+    unchar      target_id;                      /* target ID of device */
+    unchar      lun;                            /* LUN id of device */
+    unchar      orphan;                         /* flag: drive fragment */
+    ulong32     last_error;                     /* sense key or drive state */
+    ulong32     last_result;                    /* result of last command */
+    ulong32     check_errors;                   /* err. in last surface check */
+    unchar      percent;                        /* progress for surface check */
+    unchar      last_check;                     /* IOCTRL operation */
+    unchar      res[2];
+    ulong32     flags;                          /* from 1.19/2.19: raw reserv.*/
+    unchar      multi_bus;                      /* multi bus dev? (fibre ch.) */
+    unchar      mb_status;                      /* status: available? */
+    unchar      res2[2];
+    unchar      mb_alt_status;                  /* status on second bus */
+    unchar      mb_alt_bid;                     /* number of second bus */
+    unchar      mb_alt_tid;                     /* target id on second bus */
+    unchar      res3;
+    unchar      fc_flag;                        /* from 1.22/2.22: info valid?*/
+    unchar      res4;
+    ushort      fc_frame_size;                  /* frame size (bytes) */
+    char        wwn[8];                         /* world wide name */
+} PACKED gdth_diskinfo_str;
+
+/* get SCSI channel count  */
+typedef struct {
+    ulong32     channel_no;                     /* number of channel */
+    ulong32     drive_cnt;                      /* drive count */
+    unchar      siop_id;                        /* SCSI processor ID */
+    unchar      siop_state;                     /* SCSI processor state */ 
+} PACKED gdth_getch_str;
+
+/* get SCSI drive numbers */
+typedef struct {
+    ulong32     sc_no;                          /* SCSI channel */
+    ulong32     sc_cnt;                         /* sc_list[] elements */
+    ulong32     sc_list[MAXID];                 /* minor device numbers */
+} PACKED gdth_drlist_str;
+
+/* get grown/primary defect count */
+typedef struct {
+    unchar      sddc_type;                      /* 0x08: grown, 0x10: prim. */
+    unchar      sddc_format;                    /* list entry format */
+    unchar      sddc_len;                       /* list entry length */
+    unchar      sddc_res;
+    ulong32     sddc_cnt;                       /* entry count */
+} PACKED gdth_defcnt_str;
+
+/* disk statistics */
+typedef struct {
+    ulong32     bid;                            /* SCSI channel */
+    ulong32     first;                          /* first SCSI disk */
+    ulong32     entries;                        /* number of elements */
+    ulong32     count;                          /* (R) number of init. el. */
+    ulong32     mon_time;                       /* time stamp */
+    struct {
+        unchar  tid;                            /* target ID */
+        unchar  lun;                            /* LUN */
+        unchar  res[2];
+        ulong32 blk_size;                       /* block size in bytes */
+        ulong32 rd_count;                       /* bytes read */
+        ulong32 wr_count;                       /* bytes written */
+        ulong32 rd_blk_count;                   /* blocks read */
+        ulong32 wr_blk_count;                   /* blocks written */
+        ulong32 retries;                        /* retries */
+        ulong32 reassigns;                      /* reassigns */
+    } PACKED list[1];
+} PACKED gdth_dskstat_str;
+
+/* IO channel header */
+typedef struct {
+    ulong32     version;                        /* version (-1UL: newest) */
+    unchar      list_entries;                   /* list entry count */
+    unchar      first_chan;                     /* first channel number */
+    unchar      last_chan;                      /* last channel number */
+    unchar      chan_count;                     /* (R) channel count */
+    ulong32     list_offset;                    /* offset of list[0] */
+} PACKED gdth_iochan_header;
+
+/* get IO channel description */
+typedef struct {
+    gdth_iochan_header  hdr;
+    struct {
+        ulong32         address;                /* channel address */
+        unchar          type;                   /* type (SCSI, FCAL) */
+        unchar          local_no;               /* local number */
+        ushort          features;               /* channel features */
+    } PACKED list[MAXBUS];
+} PACKED gdth_iochan_str;
+
+/* get raw IO channel description */
+typedef struct {
+    gdth_iochan_header  hdr;
+    struct {
+        unchar      proc_id;                    /* processor id */
+        unchar      proc_defect;                /* defect ? */
+        unchar      reserved[2];
+    } PACKED list[MAXBUS];
+} PACKED gdth_raw_iochan_str;
+
+/* array drive component */
+typedef struct {
+    ulong32     al_controller;                  /* controller ID */
+    unchar      al_cache_drive;                 /* cache drive number */
+    unchar      al_status;                      /* cache drive state */
+    unchar      al_res[2];     
+} PACKED gdth_arraycomp_str;
+
+/* array drive information */
+typedef struct {
+    unchar      ai_type;                        /* array type (RAID0,4,5) */
+    unchar      ai_cache_drive_cnt;             /* active cachedrives */
+    unchar      ai_state;                       /* array drive state */
+    unchar      ai_master_cd;                   /* master cachedrive */
+    ulong32     ai_master_controller;           /* ID of master controller */
+    ulong32     ai_size;                        /* user capacity [sectors] */
+    ulong32     ai_striping_size;               /* striping size [sectors] */
+    ulong32     ai_secsize;                     /* sector size [bytes] */
+    ulong32     ai_err_info;                    /* failed cache drive */
+    unchar      ai_name[8];                     /* name of the array drive */
+    unchar      ai_controller_cnt;              /* number of controllers */
+    unchar      ai_removable;                   /* flag: removable */
+    unchar      ai_write_protected;             /* flag: write protected */
+    unchar      ai_devtype;                     /* type: always direct access */
+    gdth_arraycomp_str  ai_drives[35];          /* drive components: */
+    unchar      ai_drive_entries;               /* number of drive components */
+    unchar      ai_protected;                   /* protection flag */
+    unchar      ai_verify_state;                /* state of a parity verify */
+    unchar      ai_ext_state;                   /* extended array drive state */
+    unchar      ai_expand_state;                /* array expand state (>=2.18)*/
+    unchar      ai_reserved[3];
+} PACKED gdth_arrayinf_str;
+
+/* get array drive list */
+typedef struct {
+    ulong32     controller_no;                  /* controller no. */
+    unchar      cd_handle;                      /* master cachedrive */
+    unchar      is_arrayd;                      /* Flag: is array drive? */
+    unchar      is_master;                      /* Flag: is array master? */
+    unchar      is_parity;                      /* Flag: is parity drive? */
+    unchar      is_hotfix;                      /* Flag: is hotfix drive? */
+    unchar      res[3];
+} PACKED gdth_alist_str;
+
+typedef struct {
+    ulong32     entries_avail;                  /* allocated entries */
+    ulong32     entries_init;                   /* returned entries */
+    ulong32     first_entry;                    /* first entry number */
+    ulong32     list_offset;                    /* offset of following list */
+    gdth_alist_str list[1];                     /* list */
+} PACKED gdth_arcdl_str;
+
+/* cache info/config IOCTL */
+typedef struct {
+    ulong32     version;                        /* firmware version */
+    ushort      state;                          /* cache state (on/off) */
+    ushort      strategy;                       /* cache strategy */
+    ushort      write_back;                     /* write back state (on/off) */
+    ushort      block_size;                     /* cache block size */
+} PACKED gdth_cpar_str;
+
+typedef struct {
+    ulong32     csize;                          /* cache size */
+    ulong32     read_cnt;                       /* read/write counter */
+    ulong32     write_cnt;
+    ulong32     tr_hits;                        /* hits */
+    ulong32     sec_hits;
+    ulong32     sec_miss;                       /* misses */
+} PACKED gdth_cstat_str;
+
+typedef struct {
+    gdth_cpar_str   cpar;
+    gdth_cstat_str  cstat;
+} PACKED gdth_cinfo_str;
+
+/* cache drive info */
+typedef struct {
+    unchar      cd_name[8];                     /* cache drive name */
+    ulong32     cd_devtype;                     /* SCSI devicetype */
+    ulong32     cd_ldcnt;                       /* number of log. drives */
+    ulong32     cd_last_error;                  /* last error */
+    unchar      cd_initialized;                 /* drive is initialized */
+    unchar      cd_removable;                   /* media is removable */
+    unchar      cd_write_protected;             /* write protected */
+    unchar      cd_flags;                       /* Pool Hot Fix? */
+    ulong32     ld_blkcnt;                      /* number of blocks */
+    ulong32     ld_blksize;                     /* blocksize */
+    ulong32     ld_dcnt;                        /* number of disks */
+    ulong32     ld_slave;                       /* log. drive index */
+    ulong32     ld_dtype;                       /* type of logical drive */
+    ulong32     ld_last_error;                  /* last error */
+    unchar      ld_name[8];                     /* log. drive name */
+    unchar      ld_error;                       /* error */
+} PACKED gdth_cdrinfo_str;
+
+/* OEM string */
+typedef struct {
+    ulong32     ctl_version;
+    ulong32     file_major_version;
+    ulong32     file_minor_version;
+    ulong32     buffer_size;
+    ulong32     cpy_count;
+    ulong32     ext_error;
+    ulong32     oem_id;
+    ulong32     board_id;
+} PACKED gdth_oem_str_params;
+
+typedef struct {
+    unchar      product_0_1_name[16];
+    unchar      product_4_5_name[16];
+    unchar      product_cluster_name[16];
+    unchar      product_reserved[16];
+    unchar      scsi_cluster_target_vendor_id[16];
+    unchar      cluster_raid_fw_name[16];
+    unchar      oem_brand_name[16];
+    unchar      oem_raid_type[16];
+    unchar      bios_type[13];
+    unchar      bios_title[50];
+    unchar      oem_company_name[37];
+    ulong32     pci_id_1;
+    ulong32     pci_id_2;
+    unchar      validation_status[80];
+    unchar      reserved_1[4];
+    unchar      scsi_host_drive_inquiry_vendor_id[16];
+    unchar      library_file_template[16];
+    unchar      reserved_2[16];
+    unchar      tool_name_1[32];
+    unchar      tool_name_2[32];
+    unchar      tool_name_3[32];
+    unchar      oem_contact_1[84];
+    unchar      oem_contact_2[84];
+    unchar      oem_contact_3[84];
+} PACKED gdth_oem_str;
+
+typedef struct {
+    gdth_oem_str_params params;
+    gdth_oem_str        text;
+} PACKED gdth_oem_str_ioctl;
+
+/* board features */
+typedef struct {
+    unchar      chaining;                       /* Chaining supported */
+    unchar      striping;                       /* Striping (RAID-0) supp. */
+    unchar      mirroring;                      /* Mirroring (RAID-1) supp. */
+    unchar      raid;                           /* RAID-4/5/10 supported */
+} PACKED gdth_bfeat_str;
+
+/* board info IOCTL */
+typedef struct {
+    ulong32     ser_no;                         /* serial no. */
+    unchar      oem_id[2];                      /* OEM ID */
+    ushort      ep_flags;                       /* eprom flags */
+    ulong32     proc_id;                        /* processor ID */
+    ulong32     memsize;                        /* memory size (bytes) */
+    unchar      mem_banks;                      /* memory banks */
+    unchar      chan_type;                      /* channel type */
+    unchar      chan_count;                     /* channel count */
+    unchar      rdongle_pres;                   /* dongle present? */
+    ulong32     epr_fw_ver;                     /* (eprom) firmware version */
+    ulong32     upd_fw_ver;                     /* (update) firmware version */
+    ulong32     upd_revision;                   /* update revision */
+    char        type_string[16];                /* controller name */
+    char        raid_string[16];                /* RAID firmware name */
+    unchar      update_pres;                    /* update present? */
+    unchar      xor_pres;                       /* XOR engine present? */
+    unchar      prom_type;                      /* ROM type (eprom/flash) */
+    unchar      prom_count;                     /* number of ROM devices */
+    ulong32     dup_pres;                       /* duplexing module present? */
+    ulong32     chan_pres;                      /* number of expansion chn. */
+    ulong32     mem_pres;                       /* memory expansion inst. ? */
+    unchar      ft_bus_system;                  /* fault bus supported? */
+    unchar      subtype_valid;                  /* board_subtype valid? */
+    unchar      board_subtype;                  /* subtype/hardware level */
+    unchar      ramparity_pres;                 /* RAM parity check hardware? */
+} PACKED gdth_binfo_str; 
+
+/* get host drive info */
+typedef struct {
+    char        name[8];                        /* host drive name */
+    ulong32     size;                           /* size (sectors) */
+    unchar      host_drive;                     /* host drive number */
+    unchar      log_drive;                      /* log. drive (master) */
+    unchar      reserved;
+    unchar      rw_attribs;                     /* r/w attribs */
+    ulong32     start_sec;                      /* start sector */
+} PACKED gdth_hentry_str;
+
+typedef struct {
+    ulong32     entries;                        /* entry count */
+    ulong32     offset;                         /* offset of entries */
+    unchar      secs_p_head;                    /* sectors/head */
+    unchar      heads_p_cyl;                    /* heads/cylinder */
+    unchar      reserved;
+    unchar      clust_drvtype;                  /* cluster drive type */
+    ulong32     location;                       /* controller number */
+    gdth_hentry_str entry[MAX_HDRIVES];         /* entries */
+} PACKED gdth_hget_str;    
+
+
+/* DPRAM structures */
+
+/* interface area ISA/PCI */
+typedef struct {
+    unchar              S_Cmd_Indx;             /* special command */
+    unchar volatile     S_Status;               /* status special command */
+    ushort              reserved1;
+    ulong32             S_Info[4];              /* add. info special command */
+    unchar volatile     Sema0;                  /* command semaphore */
+    unchar              reserved2[3];
+    unchar              Cmd_Index;              /* command number */
+    unchar              reserved3[3];
+    ushort volatile     Status;                 /* command status */
+    ushort              Service;                /* service(for async.events) */
+    ulong32             Info[2];                /* additional info */
+    struct {
+        ushort          offset;                 /* command offs. in the DPRAM*/
+        ushort          serv_id;                /* service */
+    } PACKED comm_queue[MAXOFFSETS];            /* command queue */
+    ulong32             bios_reserved[2];
+    unchar              gdt_dpr_cmd[1];         /* commands */
+} PACKED gdt_dpr_if;
+
+/* SRAM structure PCI controllers */
+typedef struct {
+    ulong32     magic;                          /* controller ID from BIOS */
+    ushort      need_deinit;                    /* switch betw. BIOS/driver */
+    unchar      switch_support;                 /* see need_deinit */
+    unchar      padding[9];
+    unchar      os_used[16];                    /* OS code per service */
+    unchar      unused[28];
+    unchar      fw_magic;                       /* contr. ID from firmware */
+} PACKED gdt_pci_sram;
+
+/* SRAM structure EISA controllers (but NOT GDT3000/3020) */
+typedef struct {
+    unchar      os_used[16];                    /* OS code per service */
+    ushort      need_deinit;                    /* switch betw. BIOS/driver */
+    unchar      switch_support;                 /* see need_deinit */
+    unchar      padding;
+} PACKED gdt_eisa_sram;
+
+
+/* DPRAM ISA controllers */
+typedef struct {
+    union {
+        struct {
+            unchar      bios_used[0x3c00-32];   /* 15KB - 32Bytes BIOS */
+            ulong32     magic;                  /* controller (EISA) ID */
+            ushort      need_deinit;            /* switch betw. BIOS/driver */
+            unchar      switch_support;         /* see need_deinit */
+            unchar      padding[9];
+            unchar      os_used[16];            /* OS code per service */
+        } PACKED dp_sram;
+        unchar          bios_area[0x4000];      /* 16KB reserved for BIOS */
+    } bu;
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x3000];        /* 12KB for interface */
+    } u;
+    struct {
+        unchar          memlock;                /* write protection DPRAM */
+        unchar          event;                  /* release event */
+        unchar          irqen;                  /* board interrupts enable */
+        unchar          irqdel;                 /* acknowledge board int. */
+        unchar volatile Sema1;                  /* status semaphore */
+        unchar          rq;                     /* IRQ/DRQ configuration */
+    } PACKED io;
+} PACKED gdt2_dpram_str;
+
+/* DPRAM PCI controllers */
+typedef struct {
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0xff0-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+    struct {
+        unchar          unused0[1];
+        unchar volatile Sema1;                  /* command semaphore */
+        unchar          unused1[3];
+        unchar          irqen;                  /* board interrupts enable */
+        unchar          unused2[2];
+        unchar          event;                  /* release event */
+        unchar          unused3[3];
+        unchar          irqdel;                 /* acknowledge board int. */
+        unchar          unused4[3];
+    } PACKED io;
+} PACKED gdt6_dpram_str;
+
+/* PLX register structure (new PCI controllers) */
+typedef struct {
+    unchar              cfg_reg;        /* DPRAM cfg.(2:below 1MB,0:anywhere)*/
+    unchar              unused1[0x3f];
+    unchar volatile     sema0_reg;              /* command semaphore */
+    unchar volatile     sema1_reg;              /* status semaphore */
+    unchar              unused2[2];
+    ushort volatile     status;                 /* command status */
+    ushort              service;                /* service */
+    ulong32             info[2];                /* additional info */
+    unchar              unused3[0x10];
+    unchar              ldoor_reg;              /* PCI to local doorbell */
+    unchar              unused4[3];
+    unchar volatile     edoor_reg;              /* local to PCI doorbell */
+    unchar              unused5[3];
+    unchar              control0;               /* control0 register(unused) */
+    unchar              control1;               /* board interrupts enable */
+    unchar              unused6[0x16];
+} PACKED gdt6c_plx_regs;
+
+/* DPRAM new PCI controllers */
+typedef struct {
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x4000-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+} PACKED gdt6c_dpram_str;
+
+/* i960 register structure (PCI MPR controllers) */
+typedef struct {
+    unchar              unused1[16];
+    unchar volatile     sema0_reg;              /* command semaphore */
+    unchar              unused2;
+    unchar volatile     sema1_reg;              /* status semaphore */
+    unchar              unused3;
+    ushort volatile     status;                 /* command status */
+    ushort              service;                /* service */
+    ulong32             info[2];                /* additional info */
+    unchar              ldoor_reg;              /* PCI to local doorbell */
+    unchar              unused4[11];
+    unchar volatile     edoor_reg;              /* local to PCI doorbell */
+    unchar              unused5[7];
+    unchar              edoor_en_reg;           /* board interrupts enable */
+    unchar              unused6[27];
+    ulong32             unused7[939];         
+    ulong32             severity;       
+    char                evt_str[256];           /* event string */
+} PACKED gdt6m_i960_regs;
+
+/* DPRAM PCI MPR controllers */
+typedef struct {
+    gdt6m_i960_regs     i960r;                  /* 4KB i960 registers */
+    union {
+        gdt_dpr_if      ic;                     /* interface area */
+        unchar          if_area[0x3000-sizeof(gdt_pci_sram)];
+    } u;
+    gdt_pci_sram        gdt6sr;                 /* SRAM structure */
+} PACKED gdt6m_dpram_str;
+
+
+/* PCI resources */
+typedef struct {
+    struct pci_dev      *pdev;
+    ushort              vendor_id;              /* vendor (ICP, Intel, ..) */
+    ushort              device_id;              /* device ID (0,..,9) */
+    ushort              subdevice_id;           /* sub device ID */
+    unchar              bus;                    /* PCI bus */
+    unchar              device_fn;              /* PCI device/function no. */
+    ulong               dpmem;                  /* DPRAM address */
+    ulong               io;                     /* IO address */
+    ulong               io_mm;                  /* IO address mem. mapped */
+    unchar              irq;                    /* IRQ */
+} gdth_pci_str;
+
+
+/* controller information structure */
+typedef struct {
+    ushort              oem_id;                 /* OEM */
+    ushort              type;                   /* controller class */
+    ulong32             stype;                  /* subtype (PCI: device ID) */
+    ushort              subdevice_id;           /* sub device ID (PCI) */
+    ushort              fw_vers;                /* firmware version */
+    ushort              cache_feat;             /* feat. cache serv. (s/g,..)*/
+    ushort              raw_feat;               /* feat. raw service (s/g,..)*/
+    ushort              screen_feat;            /* feat. raw service (s/g,..)*/
+    ushort              bmic;                   /* BMIC address (EISA) */
+    void __iomem        *brd;                   /* DPRAM address */
+    ulong32             brd_phys;               /* slot number/BIOS address */
+    gdt6c_plx_regs      *plx;                   /* PLX regs (new PCI contr.) */
+    gdth_cmd_str        *pccb;                  /* address command structure */
+    ulong32             ccb_phys;               /* phys. address */
+#ifdef INT_COAL
+    gdth_coal_status    *coal_stat;             /* buffer for coalescing int.*/
+    ulong64             coal_stat_phys;         /* phys. address */
+#endif
+    char                *pscratch;              /* scratch (DMA) buffer */
+    ulong64             scratch_phys;           /* phys. address */
+    unchar              scratch_busy;           /* in use? */
+    unchar              dma64_support;          /* 64-bit DMA supported? */
+    gdth_msg_str        *pmsg;                  /* message buffer */
+    ulong64             msg_phys;               /* phys. address */
+    unchar              scan_mode;              /* current scan mode */
+    unchar              irq;                    /* IRQ */
+    unchar              drq;                    /* DRQ (ISA controllers) */
+    ushort              status;                 /* command status */
+    ushort              service;                /* service/firmware ver./.. */
+    ulong32             info;
+    ulong32             info2;                  /* additional info */
+    Scsi_Cmnd           *req_first;             /* top of request queue */
+    struct {
+        unchar          present;                /* Flag: host drive present? */
+        unchar          is_logdrv;              /* Flag: log. drive (master)? */
+        unchar          is_arraydrv;            /* Flag: array drive? */
+        unchar          is_master;              /* Flag: array drive master? */
+        unchar          is_parity;              /* Flag: parity drive? */
+        unchar          is_hotfix;              /* Flag: hotfix drive? */
+        unchar          master_no;              /* number of master drive */
+        unchar          lock;                   /* drive locked? (hot plug) */
+        unchar          heads;                  /* mapping */
+        unchar          secs;
+        ushort          devtype;                /* further information */
+        ulong64         size;                   /* capacity */
+        unchar          ldr_no;                 /* log. drive no. */
+        unchar          rw_attribs;             /* r/w attributes */
+        unchar          cluster_type;           /* cluster properties */
+        unchar          media_changed;          /* Flag:MOUNT/UNMOUNT occured */
+        ulong32         start_sec;              /* start sector */
+    } hdr[MAX_LDRIVES];                         /* host drives */
+    struct {
+        unchar          lock;                   /* channel locked? (hot plug) */
+        unchar          pdev_cnt;               /* physical device count */
+        unchar          local_no;               /* local channel number */
+        unchar          io_cnt[MAXID];          /* current IO count */
+        ulong32         address;                /* channel address */
+        ulong32         id_list[MAXID];         /* IDs of the phys. devices */
+    } raw[MAXBUS];                              /* SCSI channels */
+    struct {
+        Scsi_Cmnd       *cmnd;                  /* pending request */
+        ushort          service;                /* service */
+    } cmd_tab[GDTH_MAXCMDS];                    /* table of pend. requests */
+    unchar              bus_cnt;                /* SCSI bus count */
+    unchar              tid_cnt;                /* Target ID count */
+    unchar              bus_id[MAXBUS];         /* IOP IDs */
+    unchar              virt_bus;               /* number of virtual bus */
+    unchar              more_proc;              /* more /proc info supported */
+    ushort              cmd_cnt;                /* command count in DPRAM */
+    ushort              cmd_len;                /* length of actual command */
+    ushort              cmd_offs_dpmem;         /* actual offset in DPRAM */
+    ushort              ic_all_size;            /* sizeof DPRAM interf. area */
+    gdth_cpar_str       cpar;                   /* controller cache par. */
+    gdth_bfeat_str      bfeat;                  /* controller features */
+    gdth_binfo_str      binfo;                  /* controller info */
+    gdth_evt_data       dvr;                    /* event structure */
+    spinlock_t          smp_lock;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    struct pci_dev      *pdev;
+#endif
+    char                oem_name[8];
+#ifdef GDTH_DMA_STATISTICS
+    ulong               dma32_cnt, dma64_cnt;   /* statistics: DMA buffer */
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    Scsi_Device         *sdev;
+#else
+    Scsi_Device         sdev;
+#endif
+} gdth_ha_str;
+
+/* structure for scsi_register(), SCSI bus != 0 */
+typedef struct {
+    ushort      hanum;
+    ushort      busnum;
+} gdth_num_str;
+
+/* structure for scsi_register() */
+typedef struct {
+    gdth_num_str        numext;                 /* must be the first element */
+    gdth_ha_str         haext;
+    gdth_cmd_str        cmdext;
+} gdth_ext_str;
+
+
+/* INQUIRY data format */
+typedef struct {
+    unchar      type_qual;
+    unchar      modif_rmb;
+    unchar      version;
+    unchar      resp_aenc;
+    unchar      add_length;
+    unchar      reserved1;
+    unchar      reserved2;
+    unchar      misc;
+    unchar      vendor[8];
+    unchar      product[16];
+    unchar      revision[4];
+} PACKED gdth_inq_data;
+
+/* READ_CAPACITY data format */
+typedef struct {
+    ulong32     last_block_no;
+    ulong32     block_length;
+} PACKED gdth_rdcap_data;
+
+/* READ_CAPACITY (16) data format */
+typedef struct {
+    ulong64     last_block_no;
+    ulong32     block_length;
+} PACKED gdth_rdcap16_data;
+
+/* REQUEST_SENSE data format */
+typedef struct {
+    unchar      errorcode;
+    unchar      segno;
+    unchar      key;
+    ulong32     info;
+    unchar      add_length;
+    ulong32     cmd_info;
+    unchar      adsc;
+    unchar      adsq;
+    unchar      fruc;
+    unchar      key_spec[3];
+} PACKED gdth_sense_data;
+
+/* MODE_SENSE data format */
+typedef struct {
+    struct {
+        unchar  data_length;
+        unchar  med_type;
+        unchar  dev_par;
+        unchar  bd_length;
+    } PACKED hd;
+    struct {
+        unchar  dens_code;
+        unchar  block_count[3];
+        unchar  reserved;
+        unchar  block_length[3];
+    } PACKED bd;
+} PACKED gdth_modep_data;
+
+/* stack frame */
+typedef struct {
+    ulong       b[10];                          /* 32/64 bit compiler ! */
+} PACKED gdth_stackframe;
+
+
+/* function prototyping */
+
+int gdth_detect(Scsi_Host_Template *);
+int gdth_release(struct Scsi_Host *);
+int gdth_queuecommand(Scsi_Cmnd *,void (*done)(Scsi_Cmnd *));
+const char *gdth_info(struct Scsi_Host *);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *);
+int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+int gdth_bios_param(Disk *,kdev_t,int *);
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+#else
+int gdth_bios_param(Disk *,kdev_t,int *);
+extern struct proc_dir_entry proc_scsi_gdth;
+int gdth_proc_info(char *,char **,off_t,int,int,int);
+int gdth_abort(Scsi_Cmnd *);
+int gdth_reset(Scsi_Cmnd *,unsigned int); 
+#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
+               proc_info:       gdth_proc_info,                  \
+               name:            "GDT SCSI Disk Array Controller",\
+               detect:          gdth_detect,                     \
+               release:         gdth_release,                    \
+               info:            gdth_info,                       \
+               command:         NULL,                            \
+               queuecommand:    gdth_queuecommand,               \
+               eh_abort_handler: gdth_eh_abort,                  \
+               eh_device_reset_handler: gdth_eh_device_reset,    \
+               eh_bus_reset_handler: gdth_eh_bus_reset,          \
+               eh_host_reset_handler: gdth_eh_host_reset,        \
+               abort:           gdth_abort,                      \
+               reset:           gdth_reset,                      \
+               bios_param:      gdth_bios_param,                 \
+               can_queue:       GDTH_MAXCMDS,                    \
+               this_id:         -1,                              \
+               sg_tablesize:    GDTH_MAXSG,                      \
+               cmd_per_lun:     GDTH_MAXC_P_L,                   \
+               present:         0,                               \
+               unchecked_isa_dma: 1,                             \
+               use_clustering:  ENABLE_CLUSTERING,               \
+               use_new_eh_code: 1       /* use new error code */ }    
+#endif
+
+int gdth_eh_abort(Scsi_Cmnd *scp);
+int gdth_eh_device_reset(Scsi_Cmnd *scp);
+int gdth_eh_bus_reset(Scsi_Cmnd *scp);
+int gdth_eh_host_reset(Scsi_Cmnd *scp);
+
+#endif
diff --git a/drivers/scsi/gdth_ioctl.h b/drivers/scsi/gdth_ioctl.h
new file mode 100644
index 0000000..783fae7
--- /dev/null
+++ b/drivers/scsi/gdth_ioctl.h
@@ -0,0 +1,347 @@
+#ifndef _GDTH_IOCTL_H
+#define _GDTH_IOCTL_H
+
+/* gdth_ioctl.h
+ * $Id: gdth_ioctl.h,v 1.14 2004/02/19 15:43:15 achim Exp $
+ */
+
+/* IOCTLs */
+#define GDTIOCTL_MASK       ('J'<<8)
+#define GDTIOCTL_GENERAL    (GDTIOCTL_MASK | 0) /* general IOCTL */
+#define GDTIOCTL_DRVERS     (GDTIOCTL_MASK | 1) /* get driver version */
+#define GDTIOCTL_CTRTYPE    (GDTIOCTL_MASK | 2) /* get controller type */
+#define GDTIOCTL_OSVERS     (GDTIOCTL_MASK | 3) /* get OS version */
+#define GDTIOCTL_HDRLIST    (GDTIOCTL_MASK | 4) /* get host drive list */
+#define GDTIOCTL_CTRCNT     (GDTIOCTL_MASK | 5) /* get controller count */
+#define GDTIOCTL_LOCKDRV    (GDTIOCTL_MASK | 6) /* lock host drive */
+#define GDTIOCTL_LOCKCHN    (GDTIOCTL_MASK | 7) /* lock channel */
+#define GDTIOCTL_EVENT      (GDTIOCTL_MASK | 8) /* read controller events */
+#define GDTIOCTL_SCSI       (GDTIOCTL_MASK | 9) /* SCSI command */
+#define GDTIOCTL_RESET_BUS  (GDTIOCTL_MASK |10) /* reset SCSI bus */
+#define GDTIOCTL_RESCAN     (GDTIOCTL_MASK |11) /* rescan host drives */
+#define GDTIOCTL_RESET_DRV  (GDTIOCTL_MASK |12) /* reset (remote) drv. res. */
+
+#define GDTIOCTL_MAGIC  0xaffe0004
+#define EVENT_SIZE      294 
+#define GDTH_MAXSG      32                      /* max. s/g elements */
+
+#define MAX_LDRIVES     255                     /* max. log. drive count */
+#ifdef GDTH_IOCTL_PROC
+#define MAX_HDRIVES     100                     /* max. host drive count */
+#else
+#define MAX_HDRIVES     MAX_LDRIVES             /* max. host drive count */
+#endif
+
+/* typedefs */
+#ifdef __KERNEL__
+typedef u32     ulong32;
+typedef u64     ulong64;
+#endif
+
+#define PACKED  __attribute__((packed))
+
+/* scatter/gather element */
+typedef struct {
+    ulong32     sg_ptr;                         /* address */
+    ulong32     sg_len;                         /* length */
+} PACKED gdth_sg_str;
+
+/* scatter/gather element - 64bit addresses */
+typedef struct {
+    ulong64     sg_ptr;                         /* address */
+    ulong32     sg_len;                         /* length */
+} PACKED gdth_sg64_str;
+
+/* command structure */
+typedef struct {
+    ulong32     BoardNode;                      /* board node (always 0) */
+    ulong32     CommandIndex;                   /* command number */
+    ushort      OpCode;                         /* the command (READ,..) */
+    union {
+        struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong32     BlockNo;                /* block number */
+            ulong32     BlockCnt;               /* block count */
+            ulong32     DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong32     sg_canz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } PACKED cache;                         /* cache service cmd. str. */
+        struct {
+            ushort      DeviceNo;               /* number of cache drive */
+            ulong64     BlockNo;                /* block number */
+            ulong32     BlockCnt;               /* block count */
+            ulong64     DestAddr;               /* dest. addr. (if s/g: -1) */
+            ulong32     sg_canz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED cache64;                       /* cache service cmd. str. */
+        struct {
+            ushort      param_size;             /* size of p_param buffer */
+            ulong32     subfunc;                /* IOCTL function */
+            ulong32     channel;                /* device */
+            ulong64     p_param;                /* buffer */
+        } PACKED ioctl;                         /* IOCTL command structure */
+        struct {
+            ushort      reserved;
+            union {
+                struct {
+                    ulong32  msg_handle;        /* message handle */
+                    ulong64  msg_addr;          /* message buffer address */
+                } PACKED msg;
+                unchar       data[12];          /* buffer for rtc data, ... */
+            } su;
+        } PACKED screen;                        /* screen service cmd. str. */
+        struct {
+            ushort      reserved;
+            ulong32     direction;              /* data direction */
+            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong32     mcon_time;              /* connect time(0: no to.) */
+            ulong32     sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong32     sdlen;                  /* data length (bytes) */
+            ulong32     clen;                   /* SCSI cmd. length(6,10,12) */
+            unchar      cmd[12];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong32     sense_len;              /* sense data length */
+            ulong32     sense_data;             /* sense data addr. */
+            ulong32     link_p;                 /* linked cmds (not supp.) */
+            ulong32     sg_ranz;                /* s/g element count */
+            gdth_sg_str sg_lst[GDTH_MAXSG];     /* s/g list */
+        } PACKED raw;                           /* raw service cmd. struct. */
+        struct {
+            ushort      reserved;
+            ulong32     direction;              /* data direction */
+            ulong32     mdisc_time;             /* disc. time (0: no timeout)*/
+            ulong32     mcon_time;              /* connect time(0: no to.) */
+            ulong64     sdata;                  /* dest. addr. (if s/g: -1) */
+            ulong32     sdlen;                  /* data length (bytes) */
+            ulong32     clen;                   /* SCSI cmd. length(6,..,16) */
+            unchar      cmd[16];                /* SCSI command */
+            unchar      target;                 /* target ID */
+            unchar      lun;                    /* LUN */
+            unchar      bus;                    /* SCSI bus number */
+            unchar      priority;               /* only 0 used */
+            ulong32     sense_len;              /* sense data length */
+            ulong64     sense_data;             /* sense data addr. */
+            ulong32     sg_ranz;                /* s/g element count */
+            gdth_sg64_str sg_lst[GDTH_MAXSG];   /* s/g list */
+        } PACKED raw64;                         /* raw service cmd. struct. */
+    } u;
+    /* additional variables */
+    unchar      Service;                        /* controller service */
+    unchar      reserved;
+    ushort      Status;                         /* command result */
+    ulong32     Info;                           /* additional information */
+    void        *RequestBuffer;                 /* request buffer */
+} PACKED gdth_cmd_str;
+
+/* controller event structure */
+#define ES_ASYNC    1
+#define ES_DRIVER   2
+#define ES_TEST     3
+#define ES_SYNC     4
+typedef struct {
+    ushort                  size;               /* size of structure */
+    union {
+        char                stream[16];
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ulong32         index;
+        } PACKED driver;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong32         info;
+            unchar          scsi_coord[3];
+        } PACKED async;
+        struct {
+            ushort          ionode;
+            ushort          service;
+            ushort          status;
+            ulong32         info;
+            ushort          hostdrive;
+            unchar          scsi_coord[3];
+            unchar          sense_key;
+        } PACKED sync;
+        struct {
+            ulong32         l1, l2, l3, l4;
+        } PACKED test;
+    } eu;
+    ulong32                 severity;
+    unchar                  event_string[256];          
+} PACKED gdth_evt_data;
+
+typedef struct {
+    ulong32         first_stamp;
+    ulong32         last_stamp;
+    ushort          same_count;
+    ushort          event_source;
+    ushort          event_idx;
+    unchar          application;
+    unchar          reserved;
+    gdth_evt_data   event_data;
+} PACKED gdth_evt_str;
+
+
+#ifdef GDTH_IOCTL_PROC
+/* IOCTL structure (write) */
+typedef struct {
+    ulong32                 magic;              /* IOCTL magic */
+    ushort                  ioctl;              /* IOCTL */
+    ushort                  ionode;             /* controller number */
+    ushort                  service;            /* controller service */
+    ushort                  timeout;            /* timeout */
+    union {
+        struct {
+            unchar          command[512];       /* controller command */
+            unchar          data[1];            /* add. data */
+        } general;
+        struct {
+            unchar          lock;               /* lock/unlock */
+            unchar          drive_cnt;          /* drive count */
+            ushort          drives[MAX_HDRIVES];/* drives */
+        } lockdrv;
+        struct {
+            unchar          lock;               /* lock/unlock */
+            unchar          channel;            /* channel */
+        } lockchn;
+        struct {
+            int             erase;              /* erase event ? */
+            int             handle;
+            unchar          evt[EVENT_SIZE];    /* event structure */
+        } event;
+        struct {
+            unchar          bus;                /* SCSI bus */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cmd_len;            /* command length */
+            unchar          cmd[12];            /* SCSI command */
+        } scsi;
+        struct {
+            ushort          hdr_no;             /* host drive number */
+            unchar          flag;               /* old meth./add/remove */
+        } rescan;
+    } iu;
+} gdth_iowr_str;
+
+/* IOCTL structure (read) */
+typedef struct {
+    ulong32                 size;               /* buffer size */
+    ulong32                 status;             /* IOCTL error code */
+    union {
+        struct {
+            unchar          data[1];            /* data */
+        } general;
+        struct {
+            ushort          version;            /* driver version */
+        } drvers;
+        struct {
+            unchar          type;               /* controller type */
+            ushort          info;               /* slot etc. */
+            ushort          oem_id;             /* OEM ID */
+            ushort          bios_ver;           /* not used */
+            ushort          access;             /* not used */
+            ushort          ext_type;           /* extended type */
+            ushort          device_id;          /* device ID */
+            ushort          sub_device_id;      /* sub device ID */
+        } ctrtype;
+        struct {
+            unchar          version;            /* OS version */
+            unchar          subversion;         /* OS subversion */
+            ushort          revision;           /* revision */
+        } osvers;
+        struct {
+            ushort          count;              /* controller count */
+        } ctrcnt;
+        struct {
+            int             handle;
+            unchar          evt[EVENT_SIZE];    /* event structure */
+        } event;
+        struct {
+            unchar          bus;                /* SCSI bus, 0xff: invalid */
+            unchar          target;             /* target ID */
+            unchar          lun;                /* LUN */
+            unchar          cluster_type;       /* cluster properties */
+        } hdr_list[MAX_HDRIVES];                /* index is host drive number */
+    } iu;
+} gdth_iord_str;
+#endif
+
+/* GDTIOCTL_GENERAL */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    ushort timeout;                             /* timeout */
+    ulong32 info;                               /* error info */ 
+    ushort status;                              /* status */
+    ulong data_len;                             /* data buffer size */
+    ulong sense_len;                            /* sense buffer size */
+    gdth_cmd_str command;                       /* command */                   
+} gdth_ioctl_general;
+
+/* GDTIOCTL_LOCKDRV */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar lock;                                /* lock/unlock */
+    unchar drive_cnt;                           /* drive count */
+    ushort drives[MAX_HDRIVES];                 /* drives */
+} gdth_ioctl_lockdrv;
+
+/* GDTIOCTL_LOCKCHN */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar lock;                                /* lock/unlock */
+    unchar channel;                             /* channel */
+} gdth_ioctl_lockchn;
+
+/* GDTIOCTL_OSVERS */
+typedef struct {
+    unchar version;                             /* OS version */
+    unchar subversion;                          /* OS subversion */
+    ushort revision;                            /* revision */
+} gdth_ioctl_osvers;
+
+/* GDTIOCTL_CTRTYPE */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar type;                                /* controller type */
+    ushort info;                                /* slot etc. */
+    ushort oem_id;                              /* OEM ID */
+    ushort bios_ver;                            /* not used */
+    ushort access;                              /* not used */
+    ushort ext_type;                            /* extended type */
+    ushort device_id;                           /* device ID */
+    ushort sub_device_id;                       /* sub device ID */
+} gdth_ioctl_ctrtype;
+
+/* GDTIOCTL_EVENT */
+typedef struct {
+    ushort ionode;
+    int erase;                                  /* erase event? */
+    int handle;                                 /* event handle */
+    gdth_evt_str event;
+} gdth_ioctl_event;
+
+/* GDTIOCTL_RESCAN/GDTIOCTL_HDRLIST */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    unchar flag;                                /* add/remove */
+    ushort hdr_no;                              /* drive no. */
+    struct {
+        unchar bus;                             /* SCSI bus */
+        unchar target;                          /* target ID */
+        unchar lun;                             /* LUN */
+        unchar cluster_type;                    /* cluster properties */
+    } hdr_list[MAX_HDRIVES];                    /* index is host drive number */
+} gdth_ioctl_rescan;
+
+/* GDTIOCTL_RESET_BUS/GDTIOCTL_RESET_DRV */
+typedef struct {
+    ushort ionode;                              /* controller number */
+    ushort number;                              /* bus/host drive number */
+    ushort status;                              /* status */
+} gdth_ioctl_reset;
+
+#endif
diff --git a/drivers/scsi/gdth_kcompat.h b/drivers/scsi/gdth_kcompat.h
new file mode 100644
index 0000000..e6cf0ed
--- /dev/null
+++ b/drivers/scsi/gdth_kcompat.h
@@ -0,0 +1,21 @@
+
+
+#ifndef IRQ_HANDLED
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#endif
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(x)
+#endif
+
+#ifndef SERVICE_ACTION_IN
+#define SERVICE_ACTION_IN	0x9e
+#endif
+#ifndef READ_16
+#define READ_16			0x88
+#endif
+#ifndef WRITE_16
+#define WRITE_16		0x8a
+#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
new file mode 100644
index 0000000..1bd02f8
--- /dev/null
+++ b/drivers/scsi/gdth_proc.c
@@ -0,0 +1,1030 @@
+/* gdth_proc.c 
+ * $Id: gdth_proc.c,v 1.42 2004/03/05 15:50:20 achim Exp $
+ */
+
+#include <linux/completion.h>
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length,   
+                   int inout)
+{
+    int hanum,busnum;
+
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
+
+    hanum = NUMDATA(host)->hanum;
+    busnum= NUMDATA(host)->busnum;
+
+    if (inout)
+        return(gdth_set_info(buffer,length,host,hanum,busnum));
+    else
+        return(gdth_get_info(buffer,start,offset,length,host,hanum,busnum));
+}
+#else
+int gdth_proc_info(char *buffer,char **start,off_t offset,int length,int hostno,   
+                   int inout)
+{
+    int hanum,busnum,i;
+
+    TRACE2(("gdth_proc_info() length %d offs %d inout %d\n",
+            length,(int)offset,inout));
+
+    for (i = 0; i < gdth_ctr_vcount; ++i) {
+        if (gdth_ctr_vtab[i]->host_no == hostno)
+            break;
+    }
+    if (i == gdth_ctr_vcount)
+        return(-EINVAL);
+
+    hanum = NUMDATA(gdth_ctr_vtab[i])->hanum;
+    busnum= NUMDATA(gdth_ctr_vtab[i])->busnum;
+
+    if (inout)
+        return(gdth_set_info(buffer,length,gdth_ctr_vtab[i],hanum,busnum));
+    else
+        return(gdth_get_info(buffer,start,offset,length,
+                             gdth_ctr_vtab[i],hanum,busnum));
+}
+#endif
+
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum)
+{
+    int             ret_val = -EINVAL;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request    *scp;
+    Scsi_Device     *sdev;
+#else
+    Scsi_Cmnd       *scp;
+    Scsi_Device     *sdev;
+#endif
+    TRACE2(("gdth_set_info() ha %d bus %d\n",hanum,busnum));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!scp)
+        return -ENOMEM;
+    scp->sr_cmd_len = 12;
+    scp->sr_use_sg = 0;
+#else
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+        return -ENOMEM;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#endif
+
+    if (length >= 4) {
+        if (strncmp(buffer,"gdth",4) == 0) {
+            buffer += 5;
+            length -= 5;
+            ret_val = gdth_set_asc_info( buffer, length, hanum, scp );
+        }
+    }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(scp);
+    scsi_free_host_dev(sdev);
+#else
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
+    return ret_val;
+}
+         
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp)
+#else
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp)
+#endif
+{
+    int             orig_length, drive, wb_mode;
+    int             i, found;
+    gdth_ha_str     *ha;
+    gdth_cmd_str    gdtcmd;
+    gdth_cpar_str   *pcpar;
+    ulong64         paddr;
+
+    char            cmnd[MAX_COMMAND_SIZE];
+    memset(cmnd, 0xff, 12);
+    memset(&gdtcmd, 0, sizeof(gdth_cmd_str));
+
+    TRACE2(("gdth_set_asc_info() ha %d\n",hanum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    orig_length = length + 5;
+    drive = -1;
+    wb_mode = 0;
+    found = FALSE;
+
+    if (length >= 5 && strncmp(buffer,"flush",5)==0) {
+        buffer += 6;
+        length -= 6;
+        if (length && *buffer>='0' && *buffer<='9') {
+            drive = (int)(*buffer-'0');
+            ++buffer; --length;
+            if (length && *buffer>='0' && *buffer<='9') {
+                drive = drive*10 + (int)(*buffer-'0');
+                ++buffer; --length;
+            }
+            printk("GDT: Flushing host drive %d .. ",drive);
+        } else {
+            printk("GDT: Flushing all host drives .. ");
+        }
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (ha->hdr[i].present) {
+                if (drive != -1 && i != drive)
+                    continue;
+                found = TRUE;
+                gdtcmd.Service = CACHESERVICE;
+                gdtcmd.OpCode = GDT_FLUSH;
+                if (ha->cache_feat & GDT_64BIT) {
+                    gdtcmd.u.cache64.DeviceNo = i;
+                    gdtcmd.u.cache64.BlockNo = 1;
+                } else {
+                    gdtcmd.u.cache.DeviceNo = i;
+                    gdtcmd.u.cache.BlockNo = 1;
+                }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, &gdtcmd, cmnd, 30);
+#else
+                gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#endif
+            }
+        }
+        if (!found)
+            printk("\nNo host drive found !\n");
+        else
+            printk("Done.\n");
+        return(orig_length);
+    }
+
+    if (length >= 7 && strncmp(buffer,"wbp_off",7)==0) {
+        buffer += 8;
+        length -= 8;
+        printk("GDT: Disabling write back permanently .. ");
+        wb_mode = 1;
+    } else if (length >= 6 && strncmp(buffer,"wbp_on",6)==0) {
+        buffer += 7;
+        length -= 7;
+        printk("GDT: Enabling write back permanently .. ");
+        wb_mode = 2;
+    } else if (length >= 6 && strncmp(buffer,"wb_off",6)==0) {
+        buffer += 7;
+        length -= 7;
+        printk("GDT: Disabling write back commands .. ");
+        if (ha->cache_feat & GDT_WR_THROUGH) {
+            gdth_write_through = TRUE;
+            printk("Done.\n");
+        } else {
+            printk("Not supported !\n");
+        }
+        return(orig_length);
+    } else if (length >= 5 && strncmp(buffer,"wb_on",5)==0) {
+        buffer += 6;
+        length -= 6;
+        printk("GDT: Enabling write back commands .. ");
+        gdth_write_through = FALSE;
+        printk("Done.\n");
+        return(orig_length);
+    }
+
+    if (wb_mode) {
+        if (!gdth_ioctl_alloc(hanum, sizeof(gdth_cpar_str), TRUE, &paddr))
+            return(-EBUSY);
+        pcpar = (gdth_cpar_str *)ha->pscratch;
+        memcpy( pcpar, &ha->cpar, sizeof(gdth_cpar_str) );
+        gdtcmd.Service = CACHESERVICE;
+        gdtcmd.OpCode = GDT_IOCTL;
+        gdtcmd.u.ioctl.p_param = paddr;
+        gdtcmd.u.ioctl.param_size = sizeof(gdth_cpar_str);
+        gdtcmd.u.ioctl.subfunc = CACHE_CONFIG;
+        gdtcmd.u.ioctl.channel = INVALID_CHANNEL;
+        pcpar->write_back = wb_mode==1 ? 0:1;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+        gdth_do_req(scp, &gdtcmd, cmnd, 30);
+#else
+        gdth_do_cmd(scp, &gdtcmd, cmnd, 30);
+#endif
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, ha->pscratch, paddr);
+        printk("Done.\n");
+        return(orig_length);
+    }
+
+    printk("GDT: Unknown command: %s  Length: %d\n",buffer,length);
+    return(-EINVAL);
+}
+
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum)
+{
+    int size = 0,len = 0;
+    off_t begin = 0,pos = 0;
+    gdth_ha_str *ha;
+    int id, i, j, k, sec, flag;
+    int no_mdrv = 0, drv_no, is_mirr;
+    ulong32 cnt;
+    ulong64 paddr;
+    int rc = -ENOMEM;
+
+    gdth_cmd_str *gdtcmd;
+    gdth_evt_str *estr;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    Scsi_Request *scp;
+    Scsi_Device *sdev; 
+#else
+    Scsi_Cmnd *scp;
+    Scsi_Device *sdev;
+#endif
+    char hrec[161];
+    struct timeval tv;
+
+    char *buf;
+    gdth_dskstat_str *pds;
+    gdth_diskinfo_str *pdi;
+    gdth_arrayinf_str *pai;
+    gdth_defcnt_str *pdef;
+    gdth_cdrinfo_str *pcdi;
+    gdth_hget_str *phg;
+    char cmnd[MAX_COMMAND_SIZE];
+
+    gdtcmd = kmalloc(sizeof(*gdtcmd), GFP_KERNEL);
+    estr = kmalloc(sizeof(*estr), GFP_KERNEL);
+    if (!gdtcmd || !estr)
+	goto free_fail;
+
+    memset(cmnd, 0xff, 12);
+    memset(gdtcmd, 0, sizeof(gdth_cmd_str));
+
+    TRACE2(("gdth_get_info() ha %d bus %d\n",hanum,busnum));
+    ha = HADATA(gdth_ctr_tab[hanum]);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_request(sdev, GFP_KERNEL);
+    if (!scp)
+        goto free_fail;
+    scp->sr_cmd_len = 12;
+    scp->sr_use_sg = 0;
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+    sdev = scsi_get_host_dev(host);
+    scp  = scsi_allocate_device(sdev, 1, FALSE);
+    if (!scp)
+        goto free_fail;
+    scp->cmd_len = 12;
+    scp->use_sg = 0;
+#else
+    memset(&sdev,0,sizeof(Scsi_Device));
+    memset(&scp, 0,sizeof(Scsi_Cmnd));
+    sdev.host = scp.host = host;
+    sdev.id = scp.target = sdev.host->this_id;
+    scp.device = &sdev;
+#endif
+    
+    
+    /* request is i.e. "cat /proc/scsi/gdth/0" */ 
+    /* format: %-15s\t%-10s\t%-15s\t%s */
+    /* driver parameters */
+    size = sprintf(buffer+len,"Driver Parameters:\n");
+    len += size;  pos = begin + len;
+    if (reserve_list[0] == 0xff)
+        strcpy(hrec, "--");
+    else {
+        sprintf(hrec, "%d", reserve_list[0]);
+        for (i = 1;  i < MAX_RES_ARGS; i++) {
+            if (reserve_list[i] == 0xff) 
+                break;
+            sprintf(hrec,"%s,%d", hrec, reserve_list[i]);
+        }
+    }
+    size = sprintf(buffer+len,
+                   " reserve_mode: \t%d         \treserve_list:  \t%s\n",
+                   reserve_mode, hrec);
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " max_ids:      \t%-3d       \thdr_channel:   \t%d\n",
+                   max_ids, hdr_channel);
+    len += size;  pos = begin + len;
+
+    /* controller information */
+    size = sprintf(buffer+len,"\nDisk Array Controller Information:\n");
+    len += size;  pos = begin + len;
+    if (virt_ctr)
+        sprintf(hrec, "%s (Bus %d)", ha->binfo.type_string, busnum);
+    else
+        strcpy(hrec, ha->binfo.type_string);
+    size = sprintf(buffer+len,
+                   " Number:       \t%d         \tName:          \t%s\n",
+                   hanum, hrec);
+    len += size;  pos = begin + len;
+
+    if (ha->more_proc)
+        sprintf(hrec, "%d.%02d.%02d-%c%03X", 
+                (unchar)(ha->binfo.upd_fw_ver>>24),
+                (unchar)(ha->binfo.upd_fw_ver>>16),
+                (unchar)(ha->binfo.upd_fw_ver),
+                ha->bfeat.raid ? 'R':'N',
+                ha->binfo.upd_revision);
+    else
+        sprintf(hrec, "%d.%02d", (unchar)(ha->cpar.version>>8),
+                (unchar)(ha->cpar.version));
+
+    size = sprintf(buffer+len,
+                   " Driver Ver.:  \t%-10s\tFirmware Ver.: \t%s\n",
+                   GDTH_VERSION_STR, hrec);
+    len += size;  pos = begin + len;
+ 
+    if (ha->more_proc) {
+        /* more information: 1. about controller */
+        size = sprintf(buffer+len,
+                       " Serial No.:   \t0x%8X\tCache RAM size:\t%d KB\n",
+                       ha->binfo.ser_no, ha->binfo.memsize / 1024);
+        len += size;  pos = begin + len;
+    }
+
+#ifdef GDTH_DMA_STATISTICS
+    /* controller statistics */
+    size = sprintf(buffer+len,"\nController Statistics:\n");
+    len += size;  pos = begin + len;
+    size = sprintf(buffer+len,
+                   " 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
+                   ha->dma32_cnt, ha->dma64_cnt);
+    len += size;  pos = begin + len;
+#endif
+
+    if (pos < offset) {
+        len = 0;
+        begin = pos;
+    }
+    if (pos > offset + length)
+        goto stop_output;
+
+    if (ha->more_proc) {
+        /* more information: 2. about physical devices */
+        size = sprintf(buffer+len,"\nPhysical Devices:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+            
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < ha->bus_cnt; ++i) {
+            /* 2.a statistics (and retries/reassigns) */
+            TRACE2(("pdr_statistics() chn %d\n",i));                
+            pds = (gdth_dskstat_str *)(buf + GDTH_SCRATCH/4);
+            gdtcmd->Service = CACHESERVICE;
+            gdtcmd->OpCode = GDT_IOCTL;
+            gdtcmd->u.ioctl.p_param = paddr + GDTH_SCRATCH/4;
+            gdtcmd->u.ioctl.param_size = 3*GDTH_SCRATCH/4;
+            gdtcmd->u.ioctl.subfunc = DSK_STATISTICS | L_CTRL_PATTERN;
+            gdtcmd->u.ioctl.channel = ha->raw[i].address | INVALID_CHANNEL;
+            pds->bid = ha->raw[i].local_no;
+            pds->first = 0;
+            pds->entries = ha->raw[i].pdev_cnt;
+            cnt = (3*GDTH_SCRATCH/4 - 5 * sizeof(ulong32)) /
+                sizeof(pds->list[0]);
+            if (pds->entries > cnt)
+                pds->entries = cnt;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#endif
+            { 
+                pds->count = 0;
+            }
+
+            /* other IOCTLs must fit into area GDTH_SCRATCH/4 */
+            for (j = 0; j < ha->raw[i].pdev_cnt; ++j) {
+                /* 2.b drive info */
+                TRACE2(("scsi_drv_info() chn %d dev %d\n",
+                    i, ha->raw[i].id_list[j]));             
+                pdi = (gdth_diskinfo_str *)buf;
+                gdtcmd->Service = CACHESERVICE;
+                gdtcmd->OpCode = GDT_IOCTL;
+                gdtcmd->u.ioctl.p_param = paddr;
+                gdtcmd->u.ioctl.param_size = sizeof(gdth_diskinfo_str);
+                gdtcmd->u.ioctl.subfunc = SCSI_DR_INFO | L_CTRL_PATTERN;
+                gdtcmd->u.ioctl.channel = 
+                    ha->raw[i].address | ha->raw[i].id_list[j];
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, gdtcmd, cmnd, 30);
+                if (scp->sr_command->SCp.Status == S_OK) 
+#else
+                gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+                if (scp->SCp.Status == S_OK) 
+#endif
+                {
+                    strncpy(hrec,pdi->vendor,8);
+                    strncpy(hrec+8,pdi->product,16);
+                    strncpy(hrec+24,pdi->revision,4);
+                    hrec[28] = 0;
+                    size = sprintf(buffer+len,
+                                   "\n Chn/ID/LUN:   \t%c/%02d/%d    \tName:          \t%s\n",
+                                   'A'+i,pdi->target_id,pdi->lun,hrec);
+                    len += size;  pos = begin + len;
+                    flag = TRUE;
+                    pdi->no_ldrive &= 0xffff;
+                    if (pdi->no_ldrive == 0xffff)
+                        strcpy(hrec,"--");
+                    else
+                        sprintf(hrec,"%d",pdi->no_ldrive);
+                    size = sprintf(buffer+len,
+                                   " Capacity [MB]:\t%-6d    \tTo Log. Drive: \t%s\n",
+                                   pdi->blkcnt/(1024*1024/pdi->blksize),
+                                   hrec);
+                    len += size;  pos = begin + len;
+                } else {
+                    pdi->devtype = 0xff;
+                }
+                    
+                if (pdi->devtype == 0) {
+                    /* search retries/reassigns */
+                    for (k = 0; k < pds->count; ++k) {
+                        if (pds->list[k].tid == pdi->target_id &&
+                            pds->list[k].lun == pdi->lun) {
+                            size = sprintf(buffer+len,
+                                           " Retries:      \t%-6d    \tReassigns:     \t%d\n",
+                                           pds->list[k].retries,
+                                           pds->list[k].reassigns);
+                            len += size;  pos = begin + len;
+                            break;
+                        }
+                    }
+                    /* 2.c grown defects */
+                    TRACE2(("scsi_drv_defcnt() chn %d dev %d\n",
+                            i, ha->raw[i].id_list[j]));             
+                    pdef = (gdth_defcnt_str *)buf;
+                    gdtcmd->Service = CACHESERVICE;
+                    gdtcmd->OpCode = GDT_IOCTL;
+                    gdtcmd->u.ioctl.p_param = paddr;
+                    gdtcmd->u.ioctl.param_size = sizeof(gdth_defcnt_str);
+                    gdtcmd->u.ioctl.subfunc = SCSI_DEF_CNT | L_CTRL_PATTERN;
+                    gdtcmd->u.ioctl.channel = 
+                        ha->raw[i].address | ha->raw[i].id_list[j];
+                    pdef->sddc_type = 0x08;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                    gdth_do_req(scp, gdtcmd, cmnd, 30);
+                    if (scp->sr_command->SCp.Status == S_OK) 
+#else
+                    gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+                    if (scp->SCp.Status == S_OK) 
+#endif
+                    {
+                        size = sprintf(buffer+len,
+                                       " Grown Defects:\t%d\n",
+                                       pdef->sddc_cnt);
+                        len += size;  pos = begin + len;
+                    }
+                }
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }
+
+        /* 3. about logical drives */
+        size = sprintf(buffer+len,"\nLogical Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv)
+                continue;
+            drv_no = i;
+            j = k = 0;
+            is_mirr = FALSE;
+            do {
+                /* 3.a log. drive info */
+                TRACE2(("cache_drv_info() drive no %d\n",drv_no));
+                pcdi = (gdth_cdrinfo_str *)buf;
+                gdtcmd->Service = CACHESERVICE;
+                gdtcmd->OpCode = GDT_IOCTL;
+                gdtcmd->u.ioctl.p_param = paddr;
+                gdtcmd->u.ioctl.param_size = sizeof(gdth_cdrinfo_str);
+                gdtcmd->u.ioctl.subfunc = CACHE_DRV_INFO;
+                gdtcmd->u.ioctl.channel = drv_no;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+                gdth_do_req(scp, gdtcmd, cmnd, 30);
+                if (scp->sr_command->SCp.Status != S_OK) 
+#else
+                gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+                if (scp->SCp.Status != S_OK)
+#endif
+                {
+                    break;
+                }
+                pcdi->ld_dtype >>= 16;
+                j++;
+                if (pcdi->ld_dtype > 2) {
+                    strcpy(hrec, "missing");
+                } else if (pcdi->ld_error & 1) {
+                    strcpy(hrec, "fault");
+                } else if (pcdi->ld_error & 2) {
+                    strcpy(hrec, "invalid");
+                    k++; j--;
+                } else {
+                    strcpy(hrec, "ok");
+                }
+                    
+                if (drv_no == i) {
+                    size = sprintf(buffer+len,
+                                   "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                                   drv_no, hrec);
+                    len += size;  pos = begin + len;
+                    flag = TRUE;
+                    no_mdrv = pcdi->cd_ldcnt;
+                    if (no_mdrv > 1 || pcdi->ld_slave != -1) {
+                        is_mirr = TRUE;
+                        strcpy(hrec, "RAID-1");
+                    } else if (pcdi->ld_dtype == 0) {
+                        strcpy(hrec, "Disk");
+                    } else if (pcdi->ld_dtype == 1) {
+                        strcpy(hrec, "RAID-0");
+                    } else if (pcdi->ld_dtype == 2) {
+                        strcpy(hrec, "Chain");
+                    } else {
+                        strcpy(hrec, "???");
+                    }
+                    size = sprintf(buffer+len,
+                                   " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                                   pcdi->ld_blkcnt/(1024*1024/pcdi->ld_blksize),
+                                   hrec);
+                    len += size;  pos = begin + len;
+                } else {
+                    size = sprintf(buffer+len,
+                                   " Slave Number: \t%-2d        \tStatus:        \t%s\n",
+                                   drv_no & 0x7fff, hrec);
+                    len += size;  pos = begin + len;
+                }
+                drv_no = pcdi->ld_slave;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            } while (drv_no != -1);
+             
+            if (is_mirr) {
+                size = sprintf(buffer+len,
+                               " Missing Drv.: \t%-2d        \tInvalid Drv.:  \t%d\n",
+                               no_mdrv - j - k, k);
+                len += size;  pos = begin + len;
+            }
+              
+            if (!ha->hdr[i].is_arraydrv)
+                strcpy(hrec, "--");
+            else
+                sprintf(hrec, "%d", ha->hdr[i].master_no);
+            size = sprintf(buffer+len,
+                           " To Array Drv.:\t%s\n", hrec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }       
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }   
+
+        /* 4. about array drives */
+        size = sprintf(buffer+len,"\nArray Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, GDTH_SCRATCH, FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!(ha->hdr[i].is_arraydrv && ha->hdr[i].is_master))
+                continue;
+            /* 4.a array drive info */
+            TRACE2(("array_info() drive no %d\n",i));
+            pai = (gdth_arrayinf_str *)buf;
+            gdtcmd->Service = CACHESERVICE;
+            gdtcmd->OpCode = GDT_IOCTL;
+            gdtcmd->u.ioctl.p_param = paddr;
+            gdtcmd->u.ioctl.param_size = sizeof(gdth_arrayinf_str);
+            gdtcmd->u.ioctl.subfunc = ARRAY_INFO | LA_CTRL_PATTERN;
+            gdtcmd->u.ioctl.channel = i;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status == S_OK) 
+#else
+            gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+            if (scp->SCp.Status == S_OK) 
+#endif
+            {
+                if (pai->ai_state == 0)
+                    strcpy(hrec, "idle");
+                else if (pai->ai_state == 2)
+                    strcpy(hrec, "build");
+                else if (pai->ai_state == 4)
+                    strcpy(hrec, "ready");
+                else if (pai->ai_state == 6)
+                    strcpy(hrec, "fail");
+                else if (pai->ai_state == 8 || pai->ai_state == 10)
+                    strcpy(hrec, "rebuild");
+                else
+                    strcpy(hrec, "error");
+                if (pai->ai_ext_state & 0x10)
+                    strcat(hrec, "/expand");
+                else if (pai->ai_ext_state & 0x1)
+                    strcat(hrec, "/patch");
+                size = sprintf(buffer+len,
+                               "\n Number:       \t%-2d        \tStatus:        \t%s\n",
+                               i,hrec);
+                len += size;  pos = begin + len;
+                flag = TRUE;
+
+                if (pai->ai_type == 0)
+                    strcpy(hrec, "RAID-0");
+                else if (pai->ai_type == 4)
+                    strcpy(hrec, "RAID-4");
+                else if (pai->ai_type == 5)
+                    strcpy(hrec, "RAID-5");
+                else 
+                    strcpy(hrec, "RAID-10");
+                size = sprintf(buffer+len,
+                               " Capacity [MB]:\t%-6d    \tType:          \t%s\n",
+                               pai->ai_size/(1024*1024/pai->ai_secsize),
+                               hrec);
+                len += size;  pos = begin + len;
+                if (pos < offset) {
+                    len = 0;
+                    begin = pos;
+                }
+                if (pos > offset + length)
+                    goto stop_output;
+            }
+        }
+        gdth_ioctl_free(hanum, GDTH_SCRATCH, buf, paddr);
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }
+
+        /* 5. about host drives */
+        size = sprintf(buffer+len,"\nHost Drives:");
+        len += size;  pos = begin + len;
+        flag = FALSE;
+
+        buf = gdth_ioctl_alloc(hanum, sizeof(gdth_hget_str), FALSE, &paddr);
+        if (!buf) 
+            goto stop_output;
+        for (i = 0; i < MAX_LDRIVES; ++i) {
+            if (!ha->hdr[i].is_logdrv || 
+                (ha->hdr[i].is_arraydrv && !ha->hdr[i].is_master))
+                continue;
+            /* 5.a get host drive list */
+            TRACE2(("host_get() drv_no %d\n",i));           
+            phg = (gdth_hget_str *)buf;
+            gdtcmd->Service = CACHESERVICE;
+            gdtcmd->OpCode = GDT_IOCTL;
+            gdtcmd->u.ioctl.p_param = paddr;
+            gdtcmd->u.ioctl.param_size = sizeof(gdth_hget_str);
+            gdtcmd->u.ioctl.subfunc = HOST_GET | LA_CTRL_PATTERN;
+            gdtcmd->u.ioctl.channel = i;
+            phg->entries = MAX_HDRIVES;
+            phg->offset = GDTOFFSOF(gdth_hget_str, entry[0]); 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+            gdth_do_req(scp, gdtcmd, cmnd, 30);
+            if (scp->sr_command->SCp.Status != S_OK) 
+#else
+            gdth_do_cmd(scp, gdtcmd, cmnd, 30);
+            if (scp->SCp.Status != S_OK) 
+#endif
+            {
+                ha->hdr[i].ldr_no = i;
+                ha->hdr[i].rw_attribs = 0;
+                ha->hdr[i].start_sec = 0;
+            } else {
+                for (j = 0; j < phg->entries; ++j) {
+                    k = phg->entry[j].host_drive;
+                    if (k >= MAX_LDRIVES)
+                        continue;
+                    ha->hdr[k].ldr_no = phg->entry[j].log_drive;
+                    ha->hdr[k].rw_attribs = phg->entry[j].rw_attribs;
+                    ha->hdr[k].start_sec = phg->entry[j].start_sec;
+                }
+            }
+        }
+        gdth_ioctl_free(hanum, sizeof(gdth_hget_str), buf, paddr);
+
+        for (i = 0; i < MAX_HDRIVES; ++i) {
+            if (!(ha->hdr[i].present))
+                continue;
+              
+            size = sprintf(buffer+len,
+                           "\n Number:       \t%-2d        \tArr/Log. Drive:\t%d\n",
+                           i, ha->hdr[i].ldr_no);
+            len += size;  pos = begin + len;
+            flag = TRUE;
+
+            size = sprintf(buffer+len,
+                           " Capacity [MB]:\t%-6d    \tStart Sector:  \t%d\n",
+                           (ulong32)(ha->hdr[i].size/2048), ha->hdr[i].start_sec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        
+        if (!flag) {
+            size = sprintf(buffer+len, "\n --\n");
+            len += size;  pos = begin + len;
+        }
+    }
+
+    /* controller events */
+    size = sprintf(buffer+len,"\nController Events:\n");
+    len += size;  pos = begin + len;
+
+    for (id = -1;;) {
+        id = gdth_read_event(ha, id, estr);
+        if (estr->event_source == 0)
+            break;
+        if (estr->event_data.eu.driver.ionode == hanum &&
+            estr->event_source == ES_ASYNC) { 
+            gdth_log_event(&estr->event_data, hrec);
+            do_gettimeofday(&tv);
+            sec = (int)(tv.tv_sec - estr->first_stamp);
+            if (sec < 0) sec = 0;
+            size = sprintf(buffer+len," date- %02d:%02d:%02d\t%s\n",
+                           sec/3600, sec%3600/60, sec%60, hrec);
+            len += size;  pos = begin + len;
+            if (pos < offset) {
+                len = 0;
+                begin = pos;
+            }
+            if (pos > offset + length)
+                goto stop_output;
+        }
+        if (id == -1)
+            break;
+    }
+
+stop_output:
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scsi_release_request(scp);
+    scsi_free_host_dev(sdev);
+#else
+    scsi_release_command(scp);
+    scsi_free_host_dev(sdev);
+#endif
+    *start = buffer +(offset-begin);
+    len -= (offset-begin);
+    if (len > length)
+        len = length;
+    TRACE2(("get_info() len %d pos %d begin %d offset %d length %d size %d\n",
+            len,(int)pos,(int)begin,(int)offset,length,size));
+    rc = len;
+
+free_fail:
+    kfree(gdtcmd);
+    kfree(estr);
+    return rc;
+}
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static void gdth_do_req(Scsi_Request *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
+{
+    unsigned bufflen;
+    DECLARE_COMPLETION(wait);
+
+    TRACE2(("gdth_do_req()\n"));
+    if (gdtcmd != NULL) { 
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        bufflen = 0;
+    }
+    scp->sr_request->rq_status = RQ_SCSI_BUSY;
+    scp->sr_request->waiting = &wait;
+    scsi_do_req(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+    wait_for_completion(&wait);
+}
+
+#else
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *gdtcmd, 
+                        char *cmnd, int timeout)
+{
+    unsigned bufflen;
+    DECLARE_COMPLETION(wait);
+
+    TRACE2(("gdth_do_cmd()\n"));
+    if (gdtcmd != NULL) { 
+        scp->SCp.this_residual = IOCTL_PRI;
+        bufflen = sizeof(gdth_cmd_str);
+    } else {
+        scp->SCp.this_residual = DEFAULT_PRI;
+        bufflen = 0;
+    }
+
+    scp->request.rq_status = RQ_SCSI_BUSY;
+    scp->request.waiting = &wait;
+    scsi_do_cmd(scp, cmnd, gdtcmd, bufflen, gdth_scsi_done, timeout*HZ, 1);
+    wait_for_completion(&wait);
+}
+#endif
+
+void gdth_scsi_done(Scsi_Cmnd *scp)
+{
+    TRACE2(("gdth_scsi_done()\n"));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+    scp->request->rq_status = RQ_SCSI_DONE;
+    if (scp->request->waiting != NULL)
+        complete(scp->request->waiting);
+#else
+    scp->request.rq_status = RQ_SCSI_DONE;
+    if (scp->request.waiting != NULL)
+        complete(scp->request.waiting);
+#endif
+}
+
+static char *gdth_ioctl_alloc(int hanum, int size, int scratch, 
+                              ulong64 *paddr)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    char *ret_val;
+
+    if (size == 0)
+        return NULL;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    if (!ha->scratch_busy && size <= GDTH_SCRATCH) {
+        ha->scratch_busy = TRUE;
+        ret_val = ha->pscratch;
+        *paddr = ha->scratch_phys;
+    } else if (scratch) {
+        ret_val = NULL;
+    } else {
+        dma_addr_t dma_addr;
+
+        ret_val = pci_alloc_consistent(ha->pdev, size, &dma_addr);
+        *paddr = dma_addr;
+    }
+
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+    return ret_val;
+}
+
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    if (buf == ha->pscratch) {
+        ha->scratch_busy = FALSE;
+    } else {
+        pci_free_consistent(ha->pdev, size, buf, paddr);
+    }
+
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+#ifdef GDTH_IOCTL_PROC
+static int gdth_ioctl_check_bin(int hanum, ushort size)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    int ret_val;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    ret_val = FALSE;
+    if (ha->scratch_busy) {
+        if (((gdth_iord_str *)ha->pscratch)->size == (ulong32)size)
+            ret_val = TRUE;
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+    return ret_val;
+}
+#endif
+
+static void gdth_wait_completion(int hanum, int busnum, int id)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    int i;
+    Scsi_Cmnd *scp;
+    unchar b, t;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    for (i = 0; i < GDTH_MAXCMDS; ++i) {
+        scp = ha->cmd_tab[i].cmnd;
+
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+        if (!SPECIAL_SCP(scp) && t == (unchar)id && 
+            b == (unchar)busnum) {
+            scp->SCp.have_data_in = 0;
+            spin_unlock_irqrestore(&ha->smp_lock, flags);
+            while (!scp->SCp.have_data_in)
+                barrier();
+            spin_lock_irqsave(&ha->smp_lock, flags);
+        }
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+static void gdth_stop_timeout(int hanum, int busnum, int id)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    Scsi_Cmnd *scp;
+    unchar b, t;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+        if (t == (unchar)id && b == (unchar)busnum) {
+            TRACE2(("gdth_stop_timeout(): update_timeout()\n"));
+            scp->SCp.buffers_residual = gdth_update_timeout(hanum, scp, 0);
+        }
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+static void gdth_start_timeout(int hanum, int busnum, int id)
+{
+    gdth_ha_str *ha;
+    ulong flags;
+    Scsi_Cmnd *scp;
+    unchar b, t;
+
+    ha = HADATA(gdth_ctr_tab[hanum]);
+    spin_lock_irqsave(&ha->smp_lock, flags);
+
+    for (scp = ha->req_first; scp; scp = (Scsi_Cmnd *)scp->SCp.ptr) {
+        b = virt_ctr ? NUMDATA(scp->device->host)->busnum : scp->device->channel;
+        t = scp->device->id;
+        if (t == (unchar)id && b == (unchar)busnum) {
+            TRACE2(("gdth_start_timeout(): update_timeout()\n"));
+            gdth_update_timeout(hanum, scp, scp->SCp.buffers_residual);
+        }
+    }
+    spin_unlock_irqrestore(&ha->smp_lock, flags);
+}
+
+static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout)
+{
+    int oldto;
+
+    oldto = scp->timeout_per_command;
+    scp->timeout_per_command = timeout;
+
+    if (timeout == 0) {
+        del_timer(&scp->eh_timeout);
+        scp->eh_timeout.data = (unsigned long) NULL;
+        scp->eh_timeout.expires = 0;
+    } else {
+        if (scp->eh_timeout.data != (unsigned long) NULL) 
+            del_timer(&scp->eh_timeout);
+        scp->eh_timeout.data = (unsigned long) scp;
+        scp->eh_timeout.expires = jiffies + timeout;
+        add_timer(&scp->eh_timeout);
+    }
+
+    return oldto;
+}
diff --git a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h
new file mode 100644
index 0000000..295e825
--- /dev/null
+++ b/drivers/scsi/gdth_proc.h
@@ -0,0 +1,34 @@
+#ifndef _GDTH_PROC_H
+#define _GDTH_PROC_H
+
+/* gdth_proc.h 
+ * $Id: gdth_proc.h,v 1.16 2004/01/14 13:09:01 achim Exp $
+ */
+
+static int gdth_set_info(char *buffer,int length,struct Scsi_Host *host,
+                         int hanum,int busnum);
+static int gdth_get_info(char *buffer,char **start,off_t offset,int length,
+                         struct Scsi_Host *host,int hanum,int busnum);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Request *scp);
+#else
+static void gdth_do_cmd(Scsi_Cmnd *scp, gdth_cmd_str *cmd, 
+                        char *cmnd, int timeout);
+static int gdth_set_asc_info(char *buffer,int length,int hanum,Scsi_Cmnd *scp);
+#endif
+
+static char *gdth_ioctl_alloc(int hanum, int size, int scratch,
+                              ulong64 *paddr);  
+static void gdth_ioctl_free(int hanum, int size, char *buf, ulong64 paddr);
+static void gdth_wait_completion(int hanum, int busnum, int id);
+static void gdth_stop_timeout(int hanum, int busnum, int id);
+static void gdth_start_timeout(int hanum, int busnum, int id);
+static int gdth_update_timeout(int hanum, Scsi_Cmnd *scp, int timeout);
+
+void gdth_scsi_done(Scsi_Cmnd *scp);
+
+#endif
+
diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c
new file mode 100644
index 0000000..30cbf73
--- /dev/null
+++ b/drivers/scsi/gvp11.c
@@ -0,0 +1,387 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <linux/spinlock.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "wd33c93.h"
+#include "gvp11.h"
+
+#include<linux/stat.h>
+
+#define DMA(ptr) ((gvp11_scsiregs *)((ptr)->base))
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static irqreturn_t gvp11_intr (int irq, void *_instance, struct pt_regs *fp)
+{
+    unsigned long flags;
+    unsigned int status;
+    struct Scsi_Host *instance = (struct Scsi_Host *)_instance;
+
+    status = DMA(instance)->CNTR;
+    if (!(status & GVP11_DMAC_INT_PENDING))
+	return IRQ_NONE;
+
+    spin_lock_irqsave(instance->host_lock, flags);
+    wd33c93_intr(instance);
+    spin_unlock_irqrestore(instance->host_lock, flags);
+    return IRQ_HANDLED;
+}
+
+static int gvp11_xfer_mask = 0;
+
+void gvp11_setup (char *str, int *ints)
+{
+    gvp11_xfer_mask = ints[1];
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned short cntr = GVP11_DMAC_INT_ENABLE;
+    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+    int bank_mask;
+    static int scsi_alloc_out_of_range = 0;
+
+    /* use bounce buffer if the physical address is bad */
+    if (addr & HDATA(cmd->device->host)->dma_xfer_mask ||
+	(!dir_in && mm_end_of_chunk (addr, cmd->SCp.this_residual)))
+    {
+	HDATA(cmd->device->host)->dma_bounce_len = (cmd->SCp.this_residual + 511)
+	    & ~0x1ff;
+
+ 	if( !scsi_alloc_out_of_range ) {
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		kmalloc (HDATA(cmd->device->host)->dma_bounce_len, GFP_KERNEL);
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_SCSI_ALLOCED;
+	}
+
+	if (scsi_alloc_out_of_range ||
+	    !HDATA(cmd->device->host)->dma_bounce_buffer) {
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
+				       "GVP II SCSI Bounce Buffer");
+
+	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
+	    {
+		HDATA(cmd->device->host)->dma_bounce_len = 0;
+		return 1;
+	    }
+
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+	}
+
+	/* check if the address of the bounce buffer is OK */
+	addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
+
+	if (addr & HDATA(cmd->device->host)->dma_xfer_mask) {
+	    /* fall back to Chip RAM if address out of range */
+	    if( HDATA(cmd->device->host)->dma_buffer_pool == BUF_SCSI_ALLOCED) {
+		kfree (HDATA(cmd->device->host)->dma_bounce_buffer);
+		scsi_alloc_out_of_range = 1;
+	    } else {
+		amiga_chip_free (HDATA(cmd->device->host)->dma_bounce_buffer);
+            }
+		
+	    HDATA(cmd->device->host)->dma_bounce_buffer =
+		amiga_chip_alloc(HDATA(cmd->device->host)->dma_bounce_len,
+				       "GVP II SCSI Bounce Buffer");
+
+	    if(!HDATA(cmd->device->host)->dma_bounce_buffer)
+	    {
+		HDATA(cmd->device->host)->dma_bounce_len = 0;
+		return 1;
+	    }
+
+	    addr = virt_to_bus(HDATA(cmd->device->host)->dma_bounce_buffer);
+	    HDATA(cmd->device->host)->dma_buffer_pool = BUF_CHIP_ALLOCED;
+	}
+	    
+	if (!dir_in) {
+	    /* copy to bounce buffer for a write */
+	    memcpy (HDATA(cmd->device->host)->dma_bounce_buffer,
+		    cmd->SCp.ptr, cmd->SCp.this_residual);
+	}
+    }
+
+    /* setup dma direction */
+    if (!dir_in)
+	cntr |= GVP11_DMAC_DIR_WRITE;
+
+    HDATA(cmd->device->host)->dma_dir = dir_in;
+    DMA(cmd->device->host)->CNTR = cntr;
+
+    /* setup DMA *physical* address */
+    DMA(cmd->device->host)->ACR = addr;
+
+    if (dir_in)
+	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    else
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+
+    if ((bank_mask = (~HDATA(cmd->device->host)->dma_xfer_mask >> 18) & 0x01c0))
+	    DMA(cmd->device->host)->BANK = bank_mask & (addr >> 18);
+
+    /* start DMA */
+    DMA(cmd->device->host)->ST_DMA = 1;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		      int status)
+{
+    /* stop DMA */
+    DMA(instance)->SP_DMA = 1;
+    /* remove write bit from CONTROL bits */
+    DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+
+    /* copy from a bounce buffer, if necessary */
+    if (status && HDATA(instance)->dma_bounce_buffer) {
+	if (HDATA(instance)->dma_dir && SCpnt)
+	    memcpy (SCpnt->SCp.ptr, 
+		    HDATA(instance)->dma_bounce_buffer,
+		    SCpnt->SCp.this_residual);
+	
+	if (HDATA(instance)->dma_buffer_pool == BUF_SCSI_ALLOCED)
+	    kfree (HDATA(instance)->dma_bounce_buffer);
+	else
+	    amiga_chip_free(HDATA(instance)->dma_bounce_buffer);
+	
+	HDATA(instance)->dma_bounce_buffer = NULL;
+	HDATA(instance)->dma_bounce_len = 0;
+    }
+}
+
+#define CHECK_WD33C93
+
+int __init gvp11_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    struct Scsi_Host *instance;
+    unsigned long address;
+    unsigned int epc;
+    struct zorro_dev *z = NULL;
+    unsigned int default_dma_xfer_mask;
+    wd33c93_regs regs;
+    int num_gvp11 = 0;
+#ifdef CHECK_WD33C93
+    volatile unsigned char *sasr_3393, *scmd_3393;
+    unsigned char save_sasr;
+    unsigned char q, qq;
+#endif
+
+    if (!MACH_IS_AMIGA || called)
+	return 0;
+    called = 1;
+
+    tpnt->proc_name = "GVP11";
+    tpnt->proc_info = &wd33c93_proc_info;
+
+    while ((z = zorro_find_device(ZORRO_WILDCARD, z))) {
+	/* 
+	 * This should (hopefully) be the correct way to identify
+	 * all the different GVP SCSI controllers (except for the
+	 * SERIES I though).
+	 */
+
+	if (z->id == ZORRO_PROD_GVP_COMBO_030_R3_SCSI ||
+	    z->id == ZORRO_PROD_GVP_SERIES_II)
+	    default_dma_xfer_mask = ~0x00ffffff;
+	else if (z->id == ZORRO_PROD_GVP_GFORCE_030_SCSI ||
+		 z->id == ZORRO_PROD_GVP_A530_SCSI ||
+		 z->id == ZORRO_PROD_GVP_COMBO_030_R4_SCSI)
+	    default_dma_xfer_mask = ~0x01ffffff;
+	else if (z->id == ZORRO_PROD_GVP_A1291 ||
+		 z->id == ZORRO_PROD_GVP_GFORCE_040_SCSI_1)
+	    default_dma_xfer_mask = ~0x07ffffff;
+	else
+	    continue;
+
+	/*
+	 * Rumors state that some GVP ram boards use the same product
+	 * code as the SCSI controllers. Therefore if the board-size
+	 * is not 64KB we asume it is a ram board and bail out.
+	 */
+	if (z->resource.end-z->resource.start != 0xffff)
+		continue;
+
+	address = z->resource.start;
+	if (!request_mem_region(address, 256, "wd33c93"))
+	    continue;
+
+#ifdef CHECK_WD33C93
+
+	/*
+	 * These darn GVP boards are a problem - it can be tough to tell
+	 * whether or not they include a SCSI controller. This is the
+	 * ultimate Yet-Another-GVP-Detection-Hack in that it actually
+	 * probes for a WD33c93 chip: If we find one, it's extremely
+	 * likely that this card supports SCSI, regardless of Product_
+	 * Code, Board_Size, etc. 
+	 */
+
+    /* Get pointers to the presumed register locations and save contents */
+
+	sasr_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SASR);
+	scmd_3393 = &(((gvp11_scsiregs *)(ZTWO_VADDR(address)))->SCMD);
+	save_sasr = *sasr_3393;
+
+    /* First test the AuxStatus Reg */
+
+	q = *sasr_3393;		/* read it */
+	if (q & 0x08)		/* bit 3 should always be clear */
+		goto release;
+	*sasr_3393 = WD_AUXILIARY_STATUS;	 /* setup indirect address */
+	if (*sasr_3393 == WD_AUXILIARY_STATUS) { /* shouldn't retain the write */
+		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
+		goto release;
+		}
+	if (*sasr_3393 != q) {	/* should still read the same */
+		*sasr_3393 = save_sasr;	/* Oops - restore this byte */
+		goto release;
+		}
+	if (*scmd_3393 != q)	/* and so should the image at 0x1f */
+		goto release;
+
+
+    /* Ok, we probably have a wd33c93, but let's check a few other places
+     * for good measure. Make sure that this works for both 'A and 'B    
+     * chip versions.
+     */
+
+	*sasr_3393 = WD_SCSI_STATUS;
+	q = *scmd_3393;
+	*sasr_3393 = WD_SCSI_STATUS;
+	*scmd_3393 = ~q;
+	*sasr_3393 = WD_SCSI_STATUS;
+	qq = *scmd_3393;
+	*sasr_3393 = WD_SCSI_STATUS;
+	*scmd_3393 = q;
+	if (qq != q)			/* should be read only */
+		goto release;
+	*sasr_3393 = 0x1e;	/* this register is unimplemented */
+	q = *scmd_3393;
+	*sasr_3393 = 0x1e;
+	*scmd_3393 = ~q;
+	*sasr_3393 = 0x1e;
+	qq = *scmd_3393;
+	*sasr_3393 = 0x1e;
+	*scmd_3393 = q;
+	if (qq != q || qq != 0xff)	/* should be read only, all 1's */
+		goto release;
+	*sasr_3393 = WD_TIMEOUT_PERIOD;
+	q = *scmd_3393;
+	*sasr_3393 = WD_TIMEOUT_PERIOD;
+	*scmd_3393 = ~q;
+	*sasr_3393 = WD_TIMEOUT_PERIOD;
+	qq = *scmd_3393;
+	*sasr_3393 = WD_TIMEOUT_PERIOD;
+	*scmd_3393 = q;
+	if (qq != (~q & 0xff))		/* should be read/write */
+		goto release;
+#endif
+
+	instance = scsi_register (tpnt, sizeof (struct WD33C93_hostdata));
+	if(instance == NULL)
+		goto release;
+	instance->base = ZTWO_VADDR(address);
+	instance->irq = IRQ_AMIGA_PORTS;
+	instance->unique_id = z->slotaddr;
+
+	if (gvp11_xfer_mask)
+		HDATA(instance)->dma_xfer_mask = gvp11_xfer_mask;
+	else
+		HDATA(instance)->dma_xfer_mask = default_dma_xfer_mask;
+
+
+	DMA(instance)->secret2 = 1;
+	DMA(instance)->secret1 = 0;
+	DMA(instance)->secret3 = 15;
+	while (DMA(instance)->CNTR & GVP11_DMAC_BUSY) ;
+	DMA(instance)->CNTR = 0;
+
+	DMA(instance)->BANK = 0;
+
+	epc = *(unsigned short *)(ZTWO_VADDR(address) + 0x8000);
+
+	/*
+	 * Check for 14MHz SCSI clock
+	 */
+	regs.SASR = &(DMA(instance)->SASR);
+	regs.SCMD = &(DMA(instance)->SCMD);
+	wd33c93_init(instance, regs, dma_setup, dma_stop,
+		     (epc & GVP_SCSICLKMASK) ? WD33C93_FS_8_10
+					     : WD33C93_FS_12_15);
+
+	request_irq(IRQ_AMIGA_PORTS, gvp11_intr, SA_SHIRQ, "GVP11 SCSI",
+		    instance);
+	DMA(instance)->CNTR = GVP11_DMAC_INT_ENABLE;
+	num_gvp11++;
+	continue;
+
+release:
+	release_mem_region(address, 256);
+    }
+
+    return num_gvp11;
+}
+
+static int gvp11_bus_reset(Scsi_Cmnd *cmd)
+{
+	/* FIXME perform bus-specific reset */
+	wd33c93_host_reset(cmd);
+	return SUCCESS;
+}
+
+
+#define HOSTS_C
+
+#include "gvp11.h"
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "GVP11",
+	.name			= "GVP Series II SCSI",
+	.detect			= gvp11_detect,
+	.release		= gvp11_release,
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_bus_reset_handler	= gvp11_bus_reset,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+int gvp11_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+    DMA(instance)->CNTR = 0;
+    release_mem_region(ZTWO_PADDR(instance->base), 256);
+    free_irq(IRQ_AMIGA_PORTS, instance);
+    wd33c93_release();
+#endif
+    return 1;
+}
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
new file mode 100644
index 0000000..5148d9f
--- /dev/null
+++ b/drivers/scsi/gvp11.h
@@ -0,0 +1,63 @@
+#ifndef GVP11_H
+
+/* $Id: gvp11.h,v 1.4 1997/01/19 23:07:12 davem Exp $
+ *
+ * Header file for the GVP Series II SCSI controller for Linux
+ *
+ * Written and (C) 1993, Ralf Baechle, see gvp11.c for more info
+ * based on a2091.h (C) 1993 by Hamish Macdonald
+ *
+ */
+
+#include <linux/types.h>
+
+int gvp11_detect(Scsi_Host_Template *);
+int gvp11_release(struct Scsi_Host *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifndef HOSTS_C
+
+/*
+ * if the transfer address ANDed with this results in a non-zero
+ * result, then we can't use DMA.
+ */
+#define GVP11_XFER_MASK  (0xff000001)
+
+typedef struct {
+             unsigned char      pad1[64];
+    volatile unsigned short     CNTR;
+             unsigned char      pad2[31];
+    volatile unsigned char      SASR;
+             unsigned char      pad3;
+    volatile unsigned char      SCMD;
+             unsigned char      pad4[4];
+    volatile unsigned short     BANK;
+             unsigned char      pad5[6];
+    volatile unsigned long      ACR;
+    volatile unsigned short     secret1; /* store 0 here */
+    volatile unsigned short     ST_DMA;
+    volatile unsigned short     SP_DMA;
+    volatile unsigned short     secret2; /* store 1 here */
+    volatile unsigned short     secret3; /* store 15 here */
+} gvp11_scsiregs;
+
+/* bits in CNTR */
+#define GVP11_DMAC_BUSY		(1<<0)
+#define GVP11_DMAC_INT_PENDING	(1<<1)
+#define GVP11_DMAC_INT_ENABLE	(1<<3)
+#define GVP11_DMAC_DIR_WRITE	(1<<4)
+
+#endif /* else def HOSTS_C */
+
+#endif /* GVP11_H */
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
new file mode 100644
index 0000000..ba34757
--- /dev/null
+++ b/drivers/scsi/hosts.c
@@ -0,0 +1,462 @@
+/*
+ *  hosts.c Copyright (C) 1992 Drew Eckhardt
+ *          Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *          Copyright (C) 2002-2003 Christoph Hellwig
+ *
+ *  mid to lowlevel SCSI driver interface
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
+ *
+ *  <drew@colorado.edu>
+ *
+ *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
+ *  Added QLOGIC QLA1280 SCSI controller kernel host support. 
+ *     August 4, 1999 Fred Lewis, Intel DuPont
+ *
+ *  Updated to reflect the new initialization scheme for the higher 
+ *  level of scsi drivers (sd/sr/st)
+ *  September 17, 2000 Torben Mathiasen <tmm@image.dk>
+ *
+ *  Restructured scsi_host lists and associated functions.
+ *  September 04, 2002 Mike Anderson (andmike@us.ibm.com)
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/transport_class.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
+static int scsi_host_next_hn;		/* host_no for next new host */
+
+
+static void scsi_host_cls_release(struct class_device *class_dev)
+{
+	put_device(&class_to_shost(class_dev)->shost_gendev);
+}
+
+static struct class shost_class = {
+	.name		= "scsi_host",
+	.release	= scsi_host_cls_release,
+};
+
+/**
+ * scsi_host_cancel - cancel outstanding IO to this host
+ * @shost:	pointer to struct Scsi_Host
+ * recovery:	recovery requested to run.
+ **/
+void scsi_host_cancel(struct Scsi_Host *shost, int recovery)
+{
+	struct scsi_device *sdev;
+
+	set_bit(SHOST_CANCEL, &shost->shost_state);
+	shost_for_each_device(sdev, shost) {
+		scsi_device_cancel(sdev, recovery);
+	}
+	wait_event(shost->host_wait, (!test_bit(SHOST_RECOVERY,
+						&shost->shost_state)));
+}
+
+/**
+ * scsi_remove_host - remove a scsi host
+ * @shost:	a pointer to a scsi host to remove
+ **/
+void scsi_remove_host(struct Scsi_Host *shost)
+{
+	scsi_forget_host(shost);
+	scsi_host_cancel(shost, 0);
+	scsi_proc_host_rm(shost);
+
+	set_bit(SHOST_DEL, &shost->shost_state);
+
+	transport_unregister_device(&shost->shost_gendev);
+	class_device_unregister(&shost->shost_classdev);
+	device_del(&shost->shost_gendev);
+}
+EXPORT_SYMBOL(scsi_remove_host);
+
+/**
+ * scsi_add_host - add a scsi host
+ * @shost:	scsi host pointer to add
+ * @dev:	a struct device of type scsi class
+ *
+ * Return value: 
+ * 	0 on success / != 0 for error
+ **/
+int scsi_add_host(struct Scsi_Host *shost, struct device *dev)
+{
+	struct scsi_host_template *sht = shost->hostt;
+	int error = -EINVAL;
+
+	printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
+			sht->info ? sht->info(shost) : sht->name);
+
+	if (!shost->can_queue) {
+		printk(KERN_ERR "%s: can_queue = 0 no longer supported\n",
+				sht->name);
+		goto out;
+	}
+
+	if (!shost->shost_gendev.parent)
+		shost->shost_gendev.parent = dev ? dev : &platform_bus;
+
+	error = device_add(&shost->shost_gendev);
+	if (error)
+		goto out;
+
+	set_bit(SHOST_ADD, &shost->shost_state);
+	get_device(shost->shost_gendev.parent);
+
+	error = class_device_add(&shost->shost_classdev);
+	if (error)
+		goto out_del_gendev;
+
+	get_device(&shost->shost_gendev);
+
+	if (shost->transportt->host_size &&
+	    (shost->shost_data = kmalloc(shost->transportt->host_size,
+					 GFP_KERNEL)) == NULL)
+		goto out_del_classdev;
+
+	if (shost->transportt->create_work_queue) {
+		snprintf(shost->work_q_name, KOBJ_NAME_LEN, "scsi_wq_%d",
+			shost->host_no);
+		shost->work_q = create_singlethread_workqueue(
+					shost->work_q_name);
+		if (!shost->work_q)
+			goto out_free_shost_data;
+	}
+
+	error = scsi_sysfs_add_host(shost);
+	if (error)
+		goto out_destroy_host;
+
+	scsi_proc_host_add(shost);
+	return error;
+
+ out_destroy_host:
+	if (shost->work_q)
+		destroy_workqueue(shost->work_q);
+ out_free_shost_data:
+	kfree(shost->shost_data);
+ out_del_classdev:
+	class_device_del(&shost->shost_classdev);
+ out_del_gendev:
+	device_del(&shost->shost_gendev);
+ out:
+	return error;
+}
+EXPORT_SYMBOL(scsi_add_host);
+
+static void scsi_host_dev_release(struct device *dev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+	struct device *parent = dev->parent;
+
+	if (shost->ehandler) {
+		DECLARE_COMPLETION(sem);
+		shost->eh_notify = &sem;
+		shost->eh_kill = 1;
+		up(shost->eh_wait);
+		wait_for_completion(&sem);
+		shost->eh_notify = NULL;
+	}
+
+	if (shost->work_q)
+		destroy_workqueue(shost->work_q);
+
+	scsi_proc_hostdir_rm(shost->hostt);
+	scsi_destroy_command_freelist(shost);
+	kfree(shost->shost_data);
+
+	/*
+	 * Some drivers (eg aha1542) do scsi_register()/scsi_unregister()
+	 * during probing without performing a scsi_set_device() in between.
+	 * In this case dev->parent is NULL.
+	 */
+	if (parent)
+		put_device(parent);
+	kfree(shost);
+}
+
+/**
+ * scsi_host_alloc - register a scsi host adapter instance.
+ * @sht:	pointer to scsi host template
+ * @privsize:	extra bytes to allocate for driver
+ *
+ * Note:
+ * 	Allocate a new Scsi_Host and perform basic initialization.
+ * 	The host is not published to the scsi midlayer until scsi_add_host
+ * 	is called.
+ *
+ * Return value:
+ * 	Pointer to a new Scsi_Host
+ **/
+struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
+{
+	struct Scsi_Host *shost;
+	int gfp_mask = GFP_KERNEL, rval;
+	DECLARE_COMPLETION(complete);
+
+	if (sht->unchecked_isa_dma && privsize)
+		gfp_mask |= __GFP_DMA;
+
+        /* Check to see if this host has any error handling facilities */
+        if (!sht->eh_strategy_handler && !sht->eh_abort_handler &&
+	    !sht->eh_device_reset_handler && !sht->eh_bus_reset_handler &&
+            !sht->eh_host_reset_handler) {
+		printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\n"
+				"ERROR: This is not a safe way to run your "
+				        "SCSI host\n"
+				"ERROR: The error handling must be added to "
+				"this driver\n", sht->proc_name);
+		dump_stack();
+        }
+
+	shost = kmalloc(sizeof(struct Scsi_Host) + privsize, gfp_mask);
+	if (!shost)
+		return NULL;
+	memset(shost, 0, sizeof(struct Scsi_Host) + privsize);
+
+	spin_lock_init(&shost->default_lock);
+	scsi_assign_lock(shost, &shost->default_lock);
+	INIT_LIST_HEAD(&shost->__devices);
+	INIT_LIST_HEAD(&shost->__targets);
+	INIT_LIST_HEAD(&shost->eh_cmd_q);
+	INIT_LIST_HEAD(&shost->starved_list);
+	init_waitqueue_head(&shost->host_wait);
+
+	init_MUTEX(&shost->scan_mutex);
+
+	shost->host_no = scsi_host_next_hn++; /* XXX(hch): still racy */
+	shost->dma_channel = 0xff;
+
+	/* These three are default values which can be overridden */
+	shost->max_channel = 0;
+	shost->max_id = 8;
+	shost->max_lun = 8;
+
+	/* Give each shost a default transportt */
+	shost->transportt = &blank_transport_template;
+
+	/*
+	 * All drivers right now should be able to handle 12 byte
+	 * commands.  Every so often there are requests for 16 byte
+	 * commands, but individual low-level drivers need to certify that
+	 * they actually do something sensible with such commands.
+	 */
+	shost->max_cmd_len = 12;
+	shost->hostt = sht;
+	shost->this_id = sht->this_id;
+	shost->can_queue = sht->can_queue;
+	shost->sg_tablesize = sht->sg_tablesize;
+	shost->cmd_per_lun = sht->cmd_per_lun;
+	shost->unchecked_isa_dma = sht->unchecked_isa_dma;
+	shost->use_clustering = sht->use_clustering;
+	shost->ordered_flush = sht->ordered_flush;
+	shost->ordered_tag = sht->ordered_tag;
+
+	/*
+	 * hosts/devices that do queueing must support ordered tags
+	 */
+	if (shost->can_queue > 1 && shost->ordered_flush) {
+		printk(KERN_ERR "scsi: ordered flushes don't support queueing\n");
+		shost->ordered_flush = 0;
+	}
+
+	if (sht->max_host_blocked)
+		shost->max_host_blocked = sht->max_host_blocked;
+	else
+		shost->max_host_blocked = SCSI_DEFAULT_HOST_BLOCKED;
+
+	/*
+	 * If the driver imposes no hard sector transfer limit, start at
+	 * machine infinity initially.
+	 */
+	if (sht->max_sectors)
+		shost->max_sectors = sht->max_sectors;
+	else
+		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
+
+	/*
+	 * assume a 4GB boundary, if not set
+	 */
+	if (sht->dma_boundary)
+		shost->dma_boundary = sht->dma_boundary;
+	else
+		shost->dma_boundary = 0xffffffff;
+
+	rval = scsi_setup_command_freelist(shost);
+	if (rval)
+		goto fail_kfree;
+
+	device_initialize(&shost->shost_gendev);
+	snprintf(shost->shost_gendev.bus_id, BUS_ID_SIZE, "host%d",
+		shost->host_no);
+	shost->shost_gendev.release = scsi_host_dev_release;
+
+	class_device_initialize(&shost->shost_classdev);
+	shost->shost_classdev.dev = &shost->shost_gendev;
+	shost->shost_classdev.class = &shost_class;
+	snprintf(shost->shost_classdev.class_id, BUS_ID_SIZE, "host%d",
+		  shost->host_no);
+
+	shost->eh_notify = &complete;
+	rval = kernel_thread(scsi_error_handler, shost, 0);
+	if (rval < 0)
+		goto fail_destroy_freelist;
+	wait_for_completion(&complete);
+	shost->eh_notify = NULL;
+
+	scsi_proc_hostdir_add(shost->hostt);
+	return shost;
+
+ fail_destroy_freelist:
+	scsi_destroy_command_freelist(shost);
+ fail_kfree:
+	kfree(shost);
+	return NULL;
+}
+EXPORT_SYMBOL(scsi_host_alloc);
+
+struct Scsi_Host *scsi_register(struct scsi_host_template *sht, int privsize)
+{
+	struct Scsi_Host *shost = scsi_host_alloc(sht, privsize);
+
+	if (!sht->detect) {
+		printk(KERN_WARNING "scsi_register() called on new-style "
+				    "template for driver %s\n", sht->name);
+		dump_stack();
+	}
+
+	if (shost)
+		list_add_tail(&shost->sht_legacy_list, &sht->legacy_hosts);
+	return shost;
+}
+EXPORT_SYMBOL(scsi_register);
+
+void scsi_unregister(struct Scsi_Host *shost)
+{
+	list_del(&shost->sht_legacy_list);
+	scsi_host_put(shost);
+}
+EXPORT_SYMBOL(scsi_unregister);
+
+/**
+ * scsi_host_lookup - get a reference to a Scsi_Host by host no
+ *
+ * @hostnum:	host number to locate
+ *
+ * Return value:
+ *	A pointer to located Scsi_Host or NULL.
+ **/
+struct Scsi_Host *scsi_host_lookup(unsigned short hostnum)
+{
+	struct class *class = &shost_class;
+	struct class_device *cdev;
+	struct Scsi_Host *shost = ERR_PTR(-ENXIO), *p;
+
+	down_read(&class->subsys.rwsem);
+	list_for_each_entry(cdev, &class->children, node) {
+		p = class_to_shost(cdev);
+		if (p->host_no == hostnum) {
+			shost = scsi_host_get(p);
+			break;
+		}
+	}
+	up_read(&class->subsys.rwsem);
+
+	return shost;
+}
+EXPORT_SYMBOL(scsi_host_lookup);
+
+/**
+ * scsi_host_get - inc a Scsi_Host ref count
+ * @shost:	Pointer to Scsi_Host to inc.
+ **/
+struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost)
+{
+	if (test_bit(SHOST_DEL, &shost->shost_state) ||
+		!get_device(&shost->shost_gendev))
+		return NULL;
+	return shost;
+}
+EXPORT_SYMBOL(scsi_host_get);
+
+/**
+ * scsi_host_put - dec a Scsi_Host ref count
+ * @shost:	Pointer to Scsi_Host to dec.
+ **/
+void scsi_host_put(struct Scsi_Host *shost)
+{
+	put_device(&shost->shost_gendev);
+}
+EXPORT_SYMBOL(scsi_host_put);
+
+int scsi_init_hosts(void)
+{
+	return class_register(&shost_class);
+}
+
+void scsi_exit_hosts(void)
+{
+	class_unregister(&shost_class);
+}
+
+int scsi_is_host_device(const struct device *dev)
+{
+	return dev->release == scsi_host_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_host_device);
+
+/**
+ * scsi_queue_work - Queue work to the Scsi_Host workqueue.
+ * @shost:	Pointer to Scsi_Host.
+ * @work:	Work to queue for execution.
+ *
+ * Return value:
+ * 	0 on success / != 0 for error
+ **/
+int scsi_queue_work(struct Scsi_Host *shost, struct work_struct *work)
+{
+	if (unlikely(!shost->work_q)) {
+		printk(KERN_ERR
+			"ERROR: Scsi host '%s' attempted to queue scsi-work, "
+			"when no workqueue created.\n", shost->hostt->name);
+		dump_stack();
+
+		return -EINVAL;
+	}
+
+	return queue_work(shost->work_q, work);
+}
+EXPORT_SYMBOL_GPL(scsi_queue_work);
+
+/**
+ * scsi_flush_work - Flush a Scsi_Host's workqueue.
+ * @shost:	Pointer to Scsi_Host.
+ **/
+void scsi_flush_work(struct Scsi_Host *shost)
+{
+	if (!shost->work_q) {
+		printk(KERN_ERR
+			"ERROR: Scsi host '%s' attempted to flush scsi-work, "
+			"when no workqueue created.\n", shost->hostt->name);
+		dump_stack();
+		return;
+	}
+
+	flush_workqueue(shost->work_q);
+}
+EXPORT_SYMBOL_GPL(scsi_flush_work);
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
new file mode 100644
index 0000000..c27264b
--- /dev/null
+++ b/drivers/scsi/hosts.h
@@ -0,0 +1,2 @@
+#warning "This file is obsolete, please use <scsi/scsi_host.h> instead"
+#include <scsi/scsi_host.h>
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
new file mode 100644
index 0000000..a3fdead
--- /dev/null
+++ b/drivers/scsi/ibmmca.c
@@ -0,0 +1,2491 @@
+/*
+ Low Level Linux Driver for the IBM Microchannel SCSI Subsystem for
+ Linux Kernel >= 2.4.0.
+ Copyright (c) 1995 Strom Systems, Inc. under the terms of the GNU
+ General Public License. Written by Martin Kolinek, December 1995.
+ Further development by: Chris Beauregard, Klaus Kudielka, Michael Lang
+ See the file Documentation/scsi/ibmmca.txt for a detailed description
+ of this driver, the commandline arguments and the history of its
+ development.
+ See the WWW-page: http://www.uni-mainz.de/~langm000/linux.html for latest
+ updates, info and ADF-files for adapters supported by this driver.
+
+ Alan Cox <alan@redhat.com>
+ Updated for Linux 2.5.45 to use the new error handler, cleaned up the
+ lock macros and did a few unavoidable locking tweaks, plus one locking
+ fix in the irq and completion path.
+ 
+ */
+
+#include <linux/config.h>
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,45)
+#error "This driver works only with kernel 2.5.45 or higher!"
+#endif
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mca.h>
+#include <linux/string.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <linux/mca-legacy.h>
+
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "ibmmca.h"
+
+/* current version of this driver-source: */
+#define IBMMCA_SCSI_DRIVER_VERSION "4.0b-ac"
+
+/* driver configuration */
+#define IM_MAX_HOSTS     8	/* maximum number of host adapters */
+#define IM_RESET_DELAY	60	/* seconds allowed for a reset */
+
+/* driver debugging - #undef all for normal operation */
+/* if defined: count interrupts and ignore this special one: */
+#undef	IM_DEBUG_TIMEOUT	//50
+#define TIMEOUT_PUN	0
+#define TIMEOUT_LUN	0
+/* verbose interrupt: */
+#undef IM_DEBUG_INT
+/* verbose queuecommand: */
+#undef IM_DEBUG_CMD
+/* verbose queucommand for specific SCSI-device type: */
+#undef IM_DEBUG_CMD_SPEC_DEV
+/* verbose device probing */
+#undef IM_DEBUG_PROBE
+
+/* device type that shall be displayed on syslog (only during debugging): */
+#define IM_DEBUG_CMD_DEVICE	TYPE_TAPE
+
+/* relative addresses of hardware registers on a subsystem */
+#define IM_CMD_REG(hi)	(hosts[(hi)]->io_port)	/*Command Interface, (4 bytes long) */
+#define IM_ATTN_REG(hi)	(hosts[(hi)]->io_port+4)	/*Attention (1 byte) */
+#define IM_CTR_REG(hi)	(hosts[(hi)]->io_port+5)	/*Basic Control (1 byte) */
+#define IM_INTR_REG(hi)	(hosts[(hi)]->io_port+6)	/*Interrupt Status (1 byte, r/o) */
+#define IM_STAT_REG(hi)	(hosts[(hi)]->io_port+7)	/*Basic Status (1 byte, read only) */
+
+/* basic I/O-port of first adapter */
+#define IM_IO_PORT	0x3540
+/* maximum number of hosts that can be found */
+#define IM_N_IO_PORT	8
+
+/*requests going into the upper nibble of the Attention register */
+/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
+#define IM_IMM_CMD	0x10	/*immediate command */
+#define IM_SCB		0x30	/*Subsystem Control Block command */
+#define IM_LONG_SCB	0x40	/*long Subsystem Control Block command */
+#define IM_EOI		0xe0	/*end-of-interrupt request */
+
+/*values for bits 7,1,0 of Basic Control reg. (bits 6-2 reserved) */
+#define IM_HW_RESET	0x80	/*hardware reset */
+#define IM_ENABLE_DMA	0x02	/*enable subsystem's busmaster DMA */
+#define IM_ENABLE_INTR	0x01	/*enable interrupts to the system */
+
+/*to interpret the upper nibble of Interrupt Status register */
+/*note: the lower nibble specifies the device(0-14), or subsystem(15) */
+#define IM_SCB_CMD_COMPLETED			0x10
+#define IM_SCB_CMD_COMPLETED_WITH_RETRIES	0x50
+#define IM_LOOP_SCATTER_BUFFER_FULL		0x60
+#define IM_ADAPTER_HW_FAILURE			0x70
+#define IM_IMMEDIATE_CMD_COMPLETED		0xa0
+#define IM_CMD_COMPLETED_WITH_FAILURE		0xc0
+#define IM_CMD_ERROR				0xe0
+#define IM_SOFTWARE_SEQUENCING_ERROR		0xf0
+
+/*to interpret bits 3-0 of Basic Status register (bits 7-4 reserved) */
+#define IM_CMD_REG_FULL		0x08
+#define IM_CMD_REG_EMPTY	0x04
+#define IM_INTR_REQUEST		0x02
+#define IM_BUSY			0x01
+
+/*immediate commands (word written into low 2 bytes of command reg) */
+#define IM_RESET_IMM_CMD	0x0400
+#define IM_FEATURE_CTR_IMM_CMD	0x040c
+#define IM_DMA_PACING_IMM_CMD	0x040d
+#define IM_ASSIGN_IMM_CMD	0x040e
+#define IM_ABORT_IMM_CMD	0x040f
+#define IM_FORMAT_PREP_IMM_CMD	0x0417
+
+/*SCB (Subsystem Control Block) structure */
+struct im_scb {
+	unsigned short command;	/*command word (read, etc.) */
+	unsigned short enable;	/*enable word, modifies cmd */
+	union {
+		unsigned long log_blk_adr;	/*block address on SCSI device */
+		unsigned char scsi_cmd_length;	/*6,10,12, for other scsi cmd */
+	} u1;
+	unsigned long sys_buf_adr;	/*physical system memory adr */
+	unsigned long sys_buf_length;	/*size of sys mem buffer */
+	unsigned long tsb_adr;	/*Termination Status Block adr */
+	unsigned long scb_chain_adr;	/*optional SCB chain address */
+	union {
+		struct {
+			unsigned short count;	/*block count, on SCSI device */
+			unsigned short length;	/*block length, on SCSI device */
+		} blk;
+		unsigned char scsi_command[12];	/*other scsi command */
+	} u2;
+};
+
+/*structure scatter-gather element (for list of system memory areas) */
+struct im_sge {
+	void *address;
+	unsigned long byte_length;
+};
+
+/*structure returned by a get_pos_info command: */
+struct im_pos_info {
+	unsigned short pos_id;	/* adapter id */
+	unsigned char pos_3a;	/* pos 3 (if pos 6 = 0) */
+	unsigned char pos_2;	/* pos 2 */
+	unsigned char int_level;	/* interrupt level IRQ 11 or 14 */
+	unsigned char pos_4a;	/* pos 4 (if pos 6 = 0) */
+	unsigned short connector_size;	/* MCA connector size: 16 or 32 Bit */
+	unsigned char num_luns;	/* number of supported luns per device */
+	unsigned char num_puns;	/* number of supported puns */
+	unsigned char pacing_factor;	/* pacing factor */
+	unsigned char num_ldns;	/* number of ldns available */
+	unsigned char eoi_off;	/* time EOI and interrupt inactive */
+	unsigned char max_busy;	/* time between reset and busy on */
+	unsigned short cache_stat;	/* ldn cachestat. Bit=1 = not cached */
+	unsigned short retry_stat;	/* retry status of ldns. Bit=1=disabled */
+	unsigned char pos_4b;	/* pos 4 (if pos 6 = 1) */
+	unsigned char pos_3b;	/* pos 3 (if pos 6 = 1) */
+	unsigned char pos_6;	/* pos 6 */
+	unsigned char pos_5;	/* pos 5 */
+	unsigned short max_overlap;	/* maximum overlapping requests */
+	unsigned short num_bus;	/* number of SCSI-busses */
+};
+
+/*values for SCB command word */
+#define IM_NO_SYNCHRONOUS      0x0040	/*flag for any command */
+#define IM_NO_DISCONNECT       0x0080	/*flag for any command */
+#define IM_READ_DATA_CMD       0x1c01
+#define IM_WRITE_DATA_CMD      0x1c02
+#define IM_READ_VERIFY_CMD     0x1c03
+#define IM_WRITE_VERIFY_CMD    0x1c04
+#define IM_REQUEST_SENSE_CMD   0x1c08
+#define IM_READ_CAPACITY_CMD   0x1c09
+#define IM_DEVICE_INQUIRY_CMD  0x1c0b
+#define IM_READ_LOGICAL_CMD    0x1c2a
+#define IM_OTHER_SCSI_CMD_CMD  0x241f
+
+/* unused, but supported, SCB commands */
+#define IM_GET_COMMAND_COMPLETE_STATUS_CMD   0x1c07	/* command status */
+#define IM_GET_POS_INFO_CMD                  0x1c0a	/* returns neat stuff */
+#define IM_READ_PREFETCH_CMD                 0x1c31	/* caching controller only */
+#define IM_FOMAT_UNIT_CMD                    0x1c16	/* format unit */
+#define IM_REASSIGN_BLOCK_CMD                0x1c18	/* in case of error */
+
+/*values to set bits in the enable word of SCB */
+#define IM_READ_CONTROL              0x8000
+#define IM_REPORT_TSB_ONLY_ON_ERROR  0x4000
+#define IM_RETRY_ENABLE              0x2000
+#define IM_POINTER_TO_LIST           0x1000
+#define IM_SUPRESS_EXCEPTION_SHORT   0x0400
+#define IM_BYPASS_BUFFER             0x0200
+#define IM_CHAIN_ON_NO_ERROR         0x0001
+
+/*TSB (Termination Status Block) structure */
+struct im_tsb {
+	unsigned short end_status;
+	unsigned short reserved1;
+	unsigned long residual_byte_count;
+	unsigned long sg_list_element_adr;
+	unsigned short status_length;
+	unsigned char dev_status;
+	unsigned char cmd_status;
+	unsigned char dev_error;
+	unsigned char cmd_error;
+	unsigned short reserved2;
+	unsigned short reserved3;
+	unsigned short low_of_last_scb_adr;
+	unsigned short high_of_last_scb_adr;
+};
+
+/*subsystem uses interrupt request level 14 */
+#define IM_IRQ     14
+/*SCSI-2 F/W may evade to interrupt 11 */
+#define IM_IRQ_FW  11
+
+/* Model 95 has an additional alphanumeric display, which can be used
+   to display SCSI-activities. 8595 models do not have any disk led, which
+   makes this feature quite useful.
+   The regular PS/2 disk led is turned on/off by bits 6,7 of system
+   control port. */
+
+/* LED display-port (actually, last LED on display) */
+#define MOD95_LED_PORT	   0x108
+/* system-control-register of PS/2s with diskindicator */
+#define PS2_SYS_CTR        0x92
+/* activity displaying methods */
+#define LED_DISP           1
+#define LED_ADISP          2
+#define LED_ACTIVITY       4
+/* failed intr */
+#define CMD_FAIL           255
+
+/* The SCSI-ID(!) of the accessed SCSI-device is shown on PS/2-95 machines' LED
+   displays. ldn is no longer displayed here, because the ldn mapping is now 
+   done dynamically and the ldn <-> pun,lun maps can be looked-up at boottime 
+   or during uptime in /proc/scsi/ibmmca/<host_no> in case of trouble, 
+   interest, debugging or just for having fun. The left number gives the
+   host-adapter number and the right shows the accessed SCSI-ID. */
+
+/* display_mode is set by the ibmmcascsi= command line arg */
+static int display_mode = 0;
+/* set default adapter timeout */
+static unsigned int adapter_timeout = 45;
+/* for probing on feature-command: */
+static unsigned int global_command_error_excuse = 0;
+/* global setting by command line for adapter_speed */
+static int global_adapter_speed = 0;	/* full speed by default */
+
+/* Panel / LED on, do it right for F/W addressin, too. adisplay will
+ * just ignore ids>7, as the panel has only 7 digits available */
+#define PS2_DISK_LED_ON(ad,id) { if (display_mode & LED_DISP) { if (id>9) \
+    outw((ad+48)|((id+55)<<8), MOD95_LED_PORT ); else \
+    outw((ad+48)|((id+48)<<8), MOD95_LED_PORT ); } else \
+    if (display_mode & LED_ADISP) { if (id<7) outb((char)(id+48),MOD95_LED_PORT+1+id); \
+    outb((char)(ad+48), MOD95_LED_PORT); } \
+    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+    outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); }
+
+/* Panel / LED off */
+/* bug fixed, Dec 15, 1997, where | was replaced by & here */
+#define PS2_DISK_LED_OFF() { if (display_mode & LED_DISP) \
+    outw(0x2020, MOD95_LED_PORT ); else if (display_mode & LED_ADISP) { \
+    outl(0x20202020,MOD95_LED_PORT); outl(0x20202020,MOD95_LED_PORT+4); } \
+    if ((display_mode & LED_ACTIVITY)||(!display_mode)) \
+    outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); }
+
+/*list of supported subsystems */
+struct subsys_list_struct {
+	unsigned short mca_id;
+	char *description;
+};
+
+/* types of different supported hardware that goes to hostdata special */
+#define IBM_SCSI2_FW     0
+#define IBM_7568_WCACHE  1
+#define IBM_EXP_UNIT     2
+#define IBM_SCSI_WCACHE  3
+#define IBM_SCSI         4
+
+/* other special flags for hostdata structure */
+#define FORCED_DETECTION         100
+#define INTEGRATED_SCSI          101
+
+/* List of possible IBM-SCSI-adapters */
+static struct subsys_list_struct subsys_list[] = {
+	{0x8efc, "IBM SCSI-2 F/W Adapter"},	/* special = 0 */
+	{0x8efd, "IBM 7568 Industrial Computer SCSI Adapter w/Cache"},	/* special = 1 */
+	{0x8ef8, "IBM Expansion Unit SCSI Controller"},	/* special = 2 */
+	{0x8eff, "IBM SCSI Adapter w/Cache"},	/* special = 3 */
+	{0x8efe, "IBM SCSI Adapter"},	/* special = 4 */
+};
+
+/* Max number of logical devices (can be up from 0 to 14).  15 is the address
+of the adapter itself. */
+#define MAX_LOG_DEV  15
+
+/*local data for a logical device */
+struct logical_device {
+	struct im_scb scb;	/* SCSI-subsystem-control-block structure */
+	struct im_tsb tsb;	/* SCSI command complete status block structure */
+	struct im_sge sge[16];	/* scatter gather list structure */
+	unsigned char buf[256];	/* SCSI command return data buffer */
+	Scsi_Cmnd *cmd;		/* SCSI-command that is currently in progress */
+	int device_type;	/* type of the SCSI-device. See include/scsi/scsi.h
+				   for interpretation of the possible values */
+	int block_length;	/* blocksize of a particular logical SCSI-device */
+	int cache_flag;		/* 1 if this is uncached, 0 if cache is present for ldn */
+	int retry_flag;		/* 1 if adapter retry is disabled, 0 if enabled */
+};
+
+/* statistics of the driver during operations (for proc_info) */
+struct Driver_Statistics {
+	/* SCSI statistics on the adapter */
+	int ldn_access[MAX_LOG_DEV + 1];	/* total accesses on a ldn */
+	int ldn_read_access[MAX_LOG_DEV + 1];	/* total read-access on a ldn */
+	int ldn_write_access[MAX_LOG_DEV + 1];	/* total write-access on a ldn */
+	int ldn_inquiry_access[MAX_LOG_DEV + 1];	/* total inquiries on a ldn */
+	int ldn_modeselect_access[MAX_LOG_DEV + 1];	/* total mode selects on ldn */
+	int scbs;		/* short SCBs queued */
+	int long_scbs;		/* long SCBs queued */
+	int total_accesses;	/* total accesses on all ldns */
+	int total_interrupts;	/* total interrupts (should be
+				   same as total_accesses) */
+	int total_errors;	/* command completed with error */
+	/* dynamical assignment statistics */
+	int total_scsi_devices;	/* number of physical pun,lun */
+	int dyn_flag;		/* flag showing dynamical mode */
+	int dynamical_assignments;	/* number of remappings of ldns */
+	int ldn_assignments[MAX_LOG_DEV + 1];	/* number of remappings of each
+						   ldn */
+};
+
+/* data structure for each host adapter */
+struct ibmmca_hostdata {
+	/* array of logical devices: */
+	struct logical_device _ld[MAX_LOG_DEV + 1];
+	/* array to convert (pun, lun) into logical device number: */
+	unsigned char _get_ldn[16][8];
+	/*array that contains the information about the physical SCSI-devices
+	   attached to this host adapter: */
+	unsigned char _get_scsi[16][8];
+	/* used only when checking logical devices: */
+	int _local_checking_phase_flag;
+	/* report received interrupt: */
+	int _got_interrupt;
+	/* report termination-status of SCSI-command: */
+	int _stat_result;
+	/* reset status (used only when doing reset): */
+	int _reset_status;
+	/* code of the last SCSI command (needed for panic info): */
+	int _last_scsi_command[MAX_LOG_DEV + 1];
+	/* identifier of the last SCSI-command type */
+	int _last_scsi_type[MAX_LOG_DEV + 1];
+	/* last blockcount */
+	int _last_scsi_blockcount[MAX_LOG_DEV + 1];
+	/* last locgical block address */
+	unsigned long _last_scsi_logical_block[MAX_LOG_DEV + 1];
+	/* Counter that points on the next reassignable ldn for dynamical
+	   remapping. The default value is 7, that is the first reassignable
+	   number in the list at boottime: */
+	int _next_ldn;
+	/* Statistics-structure for this IBM-SCSI-host: */
+	struct Driver_Statistics _IBM_DS;
+	/* This hostadapters pos-registers pos2 until pos6 */
+	unsigned int _pos[8];
+	/* assign a special variable, that contains dedicated info about the
+	   adaptertype */
+	int _special;
+	/* connector size on the MCA bus */
+	int _connector_size;
+	/* synchronous SCSI transfer rate bitpattern */
+	int _adapter_speed;
+};
+
+/* macros to access host data structure */
+#define subsystem_pun(hi) (hosts[(hi)]->this_id)
+#define subsystem_maxid(hi) (hosts[(hi)]->max_id)
+#define ld(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_ld)
+#define get_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_ldn)
+#define get_scsi(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_get_scsi)
+#define local_checking_phase_flag(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_local_checking_phase_flag)
+#define got_interrupt(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_got_interrupt)
+#define stat_result(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_stat_result)
+#define reset_status(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_reset_status)
+#define last_scsi_command(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_command)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define last_scsi_blockcount(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_blockcount)
+#define last_scsi_logical_block(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_logical_block)
+#define last_scsi_type(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_last_scsi_type)
+#define next_ldn(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_next_ldn)
+#define IBM_DS(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_IBM_DS)
+#define special(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_special)
+#define subsystem_connector_size(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_connector_size)
+#define adapter_speed(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_adapter_speed)
+#define pos2(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[2])
+#define pos3(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[3])
+#define pos4(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[4])
+#define pos5(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[5])
+#define pos6(hi) (((struct ibmmca_hostdata *) hosts[(hi)]->hostdata)->_pos[6])
+
+/* Define a arbitrary number as subsystem-marker-type. This number is, as
+   described in the ANSI-SCSI-standard, not occupied by other device-types. */
+#define TYPE_IBM_SCSI_ADAPTER   0x2F
+
+/* Define 0xFF for no device type, because this type is not defined within
+   the ANSI-SCSI-standard, therefore, it can be used and should not cause any
+   harm. */
+#define TYPE_NO_DEVICE          0xFF
+
+/* define medium-changer. If this is not defined previously, e.g. Linux
+   2.0.x, define this type here. */
+#ifndef TYPE_MEDIUM_CHANGER
+#define TYPE_MEDIUM_CHANGER     0x08
+#endif
+
+/* define possible operations for the immediate_assign command */
+#define SET_LDN        0
+#define REMOVE_LDN     1
+
+/* ldn which is used to probe the SCSI devices */
+#define PROBE_LDN      0
+
+/* reset status flag contents */
+#define IM_RESET_NOT_IN_PROGRESS         0
+#define IM_RESET_IN_PROGRESS             1
+#define IM_RESET_FINISHED_OK             2
+#define IM_RESET_FINISHED_FAIL           3
+#define IM_RESET_NOT_IN_PROGRESS_NO_INT  4
+#define IM_RESET_FINISHED_OK_NO_INT      5
+
+/* define undefined SCSI-command */
+#define NO_SCSI                  0xffff
+
+/*-----------------------------------------------------------------------*/
+
+/* if this is nonzero, ibmmcascsi option has been passed to the kernel */
+static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };
+
+/* fill module-parameters only, when this define is present.
+   (that is kernel version 2.1.x) */
+#if defined(MODULE)
+static char *boot_options = NULL;
+module_param(boot_options, charp, 0);
+module_param_array(io_port, int, NULL, 0);
+module_param_array(scsi_id, int, NULL, 0);
+
+#if 0 /* FIXME: No longer exist? --RR */
+MODULE_PARM(display, "1i");
+MODULE_PARM(adisplay, "1i");
+MODULE_PARM(normal, "1i");
+MODULE_PARM(ansi, "1i");
+#endif
+#endif
+/*counter of concurrent disk read/writes, to turn on/off disk led */
+static int disk_rw_in_progress = 0;
+
+/* host information */
+static int found = 0;
+static struct Scsi_Host *hosts[IM_MAX_HOSTS + 1] = {
+	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+static unsigned int pos[8];	/* whole pos register-line for diagnosis */
+/* Taking into account the additions, made by ZP Gu.
+ * This selects now the preset value from the configfile and
+ * offers the 'normal' commandline option to be accepted */
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+static char ibm_ansi_order = 1;
+#else
+static char ibm_ansi_order = 0;
+#endif
+
+static void issue_cmd(int, unsigned long, unsigned char);
+static void internal_done(Scsi_Cmnd * cmd);
+static void check_devices(int, int);
+static int immediate_assign(int, unsigned int, unsigned int, unsigned int, unsigned int);
+static int immediate_feature(int, unsigned int, unsigned int);
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int, unsigned int);
+#endif
+static int device_inquiry(int, int);
+static int read_capacity(int, int);
+static int get_pos_info(int);
+static char *ti_p(int);
+static char *ti_l(int);
+static char *ibmrate(unsigned int, int);
+static int probe_display(int);
+static int probe_bus_mode(int);
+static int device_exists(int, int, int *, int *);
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template *, int, int, int, char *);
+static int option_setup(char *);
+/* local functions needed for proc_info */
+static int ldn_access_load(int, int);
+static int ldn_access_total_read_write(int);
+
+static irqreturn_t interrupt_handler(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	int host_index, ihost_index;
+	unsigned int intr_reg;
+	unsigned int cmd_result;
+	unsigned int ldn;
+	Scsi_Cmnd *cmd;
+	int lastSCSI;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock(dev->host_lock);
+	    /* search for one adapter-response on shared interrupt */
+	    for (host_index = 0; hosts[host_index] && !(inb(IM_STAT_REG(host_index)) & IM_INTR_REQUEST); host_index++);
+	/* return if some other device on this IRQ caused the interrupt */
+	if (!hosts[host_index]) {
+		spin_unlock(dev->host_lock);
+		return IRQ_NONE;
+	}
+
+	/* the reset-function already did all the job, even ints got
+	   renabled on the subsystem, so just return */
+	if ((reset_status(host_index) == IM_RESET_NOT_IN_PROGRESS_NO_INT) || (reset_status(host_index) == IM_RESET_FINISHED_OK_NO_INT)) {
+		reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS;
+		spin_unlock(dev->host_lock);
+		return IRQ_HANDLED;
+	}
+
+	/*must wait for attention reg not busy, then send EOI to subsystem */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		cpu_relax();
+	}
+	ihost_index = host_index;
+	/*get command result and logical device */
+	intr_reg = (unsigned char) (inb(IM_INTR_REG(ihost_index)));
+	cmd_result = intr_reg & 0xf0;
+	ldn = intr_reg & 0x0f;
+	/* get the last_scsi_command here */
+	lastSCSI = last_scsi_command(ihost_index)[ldn];
+	outb(IM_EOI | ldn, IM_ATTN_REG(ihost_index));
+	
+	/*these should never happen (hw fails, or a local programming bug) */
+	if (!global_command_error_excuse) {
+		switch (cmd_result) {
+			/* Prevent from Ooopsing on error to show the real reason */
+		case IM_ADAPTER_HW_FAILURE:
+		case IM_SOFTWARE_SEQUENCING_ERROR:
+		case IM_CMD_ERROR:
+			printk(KERN_ERR "IBM MCA SCSI: Fatal Subsystem ERROR!\n");
+			printk(KERN_ERR "              Last cmd=0x%x, ena=%x, len=", lastSCSI, ld(ihost_index)[ldn].scb.enable);
+			if (ld(ihost_index)[ldn].cmd)
+				printk("%ld/%ld,", (long) (ld(ihost_index)[ldn].cmd->request_bufflen), (long) (ld(ihost_index)[ldn].scb.sys_buf_length));
+			else
+				printk("none,");
+			if (ld(ihost_index)[ldn].cmd)
+				printk("Blocksize=%d", ld(ihost_index)[ldn].scb.u2.blk.length);
+			else
+				printk("Blocksize=none");
+			printk(", host=0x%x, ldn=0x%x\n", ihost_index, ldn);
+			if (ld(ihost_index)[ldn].cmd) {
+				printk(KERN_ERR "Blockcount=%d/%d\n", last_scsi_blockcount(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u2.blk.count);
+				printk(KERN_ERR "Logical block=%lx/%lx\n", last_scsi_logical_block(ihost_index)[ldn], ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+			}
+			printk(KERN_ERR "Reason given: %s\n", (cmd_result == IM_ADAPTER_HW_FAILURE) ? "HARDWARE FAILURE" : (cmd_result == IM_SOFTWARE_SEQUENCING_ERROR) ? "SOFTWARE SEQUENCING ERROR" : (cmd_result == IM_CMD_ERROR) ? "COMMAND ERROR" : "UNKNOWN");
+			/* if errors appear, enter this section to give detailed info */
+			printk(KERN_ERR "IBM MCA SCSI: Subsystem Error-Status follows:\n");
+			printk(KERN_ERR "              Command Type................: %x\n", last_scsi_type(ihost_index)[ldn]);
+			printk(KERN_ERR "              Attention Register..........: %x\n", inb(IM_ATTN_REG(ihost_index)));
+			printk(KERN_ERR "              Basic Control Register......: %x\n", inb(IM_CTR_REG(ihost_index)));
+			printk(KERN_ERR "              Interrupt Status Register...: %x\n", intr_reg);
+			printk(KERN_ERR "              Basic Status Register.......: %x\n", inb(IM_STAT_REG(ihost_index)));
+			if ((last_scsi_type(ihost_index)[ldn] == IM_SCB) || (last_scsi_type(ihost_index)[ldn] == IM_LONG_SCB)) {
+				printk(KERN_ERR "              SCB-Command.................: %x\n", ld(ihost_index)[ldn].scb.command);
+				printk(KERN_ERR "              SCB-Enable..................: %x\n", ld(ihost_index)[ldn].scb.enable);
+				printk(KERN_ERR "              SCB-logical block address...: %lx\n", ld(ihost_index)[ldn].scb.u1.log_blk_adr);
+				printk(KERN_ERR "              SCB-system buffer address...: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_adr);
+				printk(KERN_ERR "              SCB-system buffer length....: %lx\n", ld(ihost_index)[ldn].scb.sys_buf_length);
+				printk(KERN_ERR "              SCB-tsb address.............: %lx\n", ld(ihost_index)[ldn].scb.tsb_adr);
+				printk(KERN_ERR "              SCB-Chain address...........: %lx\n", ld(ihost_index)[ldn].scb.scb_chain_adr);
+				printk(KERN_ERR "              SCB-block count.............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.count);
+				printk(KERN_ERR "              SCB-block length............: %x\n", ld(ihost_index)[ldn].scb.u2.blk.length);
+			}
+			printk(KERN_ERR "              Send this report to the maintainer.\n");
+			panic("IBM MCA SCSI: Fatal error message from the subsystem (0x%X,0x%X)!\n", lastSCSI, cmd_result);
+			break;
+		}
+	} else {
+		/* The command error handling is made silent, but we tell the
+		 * calling function, that there is a reported error from the
+		 * adapter. */
+		switch (cmd_result) {
+		case IM_ADAPTER_HW_FAILURE:
+		case IM_SOFTWARE_SEQUENCING_ERROR:
+		case IM_CMD_ERROR:
+			global_command_error_excuse = CMD_FAIL;
+			break;
+		default:
+			global_command_error_excuse = 0;
+			break;
+		}
+	}
+	/* if no panic appeared, increase the interrupt-counter */
+	IBM_DS(ihost_index).total_interrupts++;
+	/*only for local checking phase */
+	if (local_checking_phase_flag(ihost_index)) {
+		stat_result(ihost_index) = cmd_result;
+		got_interrupt(ihost_index) = 1;
+		reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+		last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+		spin_unlock(dev->host_lock);
+		return IRQ_HANDLED;
+	}
+	/* handling of commands coming from upper level of scsi driver */
+	if (last_scsi_type(ihost_index)[ldn] == IM_IMM_CMD) {
+		/* verify ldn, and may handle rare reset immediate command */
+		if ((reset_status(ihost_index) == IM_RESET_IN_PROGRESS) && (last_scsi_command(ihost_index)[ldn] == IM_RESET_IMM_CMD)) {
+			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
+				disk_rw_in_progress = 0;
+				PS2_DISK_LED_OFF();
+				reset_status(ihost_index) = IM_RESET_FINISHED_FAIL;
+			} else {
+				/*reset disk led counter, turn off disk led */
+				disk_rw_in_progress = 0;
+				PS2_DISK_LED_OFF();
+				reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+			}
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			last_scsi_type(ihost_index)[ldn] = 0;
+			spin_unlock(dev->host_lock);
+			return IRQ_HANDLED;
+		} else if (last_scsi_command(ihost_index)[ldn] == IM_ABORT_IMM_CMD) {
+			/* react on SCSI abort command */
+#ifdef IM_DEBUG_PROBE
+			printk("IBM MCA SCSI: Interrupt from SCSI-abort.\n");
+#endif
+			disk_rw_in_progress = 0;
+			PS2_DISK_LED_OFF();
+			cmd = ld(ihost_index)[ldn].cmd;
+			ld(ihost_index)[ldn].cmd = NULL;
+			if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE)
+				cmd->result = DID_NO_CONNECT << 16;
+			else
+				cmd->result = DID_ABORT << 16;
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			last_scsi_type(ihost_index)[ldn] = 0;
+			if (cmd->scsi_done)
+				(cmd->scsi_done) (cmd);	/* should be the internal_done */
+			spin_unlock(dev->host_lock);
+			return IRQ_HANDLED;
+		} else {
+			disk_rw_in_progress = 0;
+			PS2_DISK_LED_OFF();
+			reset_status(ihost_index) = IM_RESET_FINISHED_OK;
+			stat_result(ihost_index) = cmd_result;
+			last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+			spin_unlock(dev->host_lock);
+			return IRQ_HANDLED;
+		}
+	}
+	last_scsi_command(ihost_index)[ldn] = NO_SCSI;
+	last_scsi_type(ihost_index)[ldn] = 0;
+	cmd = ld(ihost_index)[ldn].cmd;
+	ld(ihost_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_TIMEOUT
+	if (cmd) {
+		if ((cmd->target == TIMEOUT_PUN) && (cmd->device->lun == TIMEOUT_LUN)) {
+			printk("IBM MCA SCSI: Ignoring interrupt from pun=%x, lun=%x.\n", cmd->target, cmd->device->lun);
+			return IRQ_HANDLED;
+		}
+	}
+#endif
+	/*if no command structure, just return, else clear cmd */
+	if (!cmd)
+	{
+		spin_unlock(dev->host_lock);
+		return IRQ_HANDLED;
+	}
+
+#ifdef IM_DEBUG_INT
+	printk("cmd=%02x ireg=%02x ds=%02x cs=%02x de=%02x ce=%02x\n", cmd->cmnd[0], intr_reg, ld(ihost_index)[ldn].tsb.dev_status, ld(ihost_index)[ldn].tsb.cmd_status, ld(ihost_index)[ldn].tsb.dev_error, ld(ihost_index)[ldn].tsb.cmd_error);
+#endif
+	/*if this is end of media read/write, may turn off PS/2 disk led */
+	if ((ld(ihost_index)[ldn].device_type != TYPE_NO_LUN) && (ld(ihost_index)[ldn].device_type != TYPE_NO_DEVICE)) {
+		/* only access this, if there was a valid device addressed */
+		if (--disk_rw_in_progress == 0)
+			PS2_DISK_LED_OFF();
+	}
+
+	/* IBM describes the status-mask to be 0x1e, but this is not conform
+	 * with SCSI-definition, I suppose, the reason for it is that IBM
+	 * adapters do not support CMD_TERMINATED, TASK_SET_FULL and
+	 * ACA_ACTIVE as returning statusbyte information. (ML) */
+	if (cmd_result == IM_CMD_COMPLETED_WITH_FAILURE) {
+		cmd->result = (unsigned char) (ld(ihost_index)[ldn].tsb.dev_status & 0x1e);
+		IBM_DS(ihost_index).total_errors++;
+	} else
+		cmd->result = 0;
+	/* write device status into cmd->result, and call done function */
+	if (lastSCSI == NO_SCSI) {	/* unexpected interrupt :-( */
+		cmd->result |= DID_BAD_INTR << 16;
+		printk("IBM MCA SCSI: WARNING - Interrupt from non-pending SCSI-command!\n");
+	} else			/* things went right :-) */
+		cmd->result |= DID_OK << 16;
+	if (cmd->scsi_done)
+		(cmd->scsi_done) (cmd);
+	spin_unlock(dev->host_lock);
+	return IRQ_HANDLED;
+}
+
+static void issue_cmd(int host_index, unsigned long cmd_reg, unsigned char attn_reg)
+{
+	unsigned long flags;
+	/* must wait for attention reg not busy */
+	while (1) {
+		spin_lock_irqsave(hosts[host_index]->host_lock, flags);
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+	}
+	/* write registers and enable system interrupts */
+	outl(cmd_reg, IM_CMD_REG(host_index));
+	outb(attn_reg, IM_ATTN_REG(host_index));
+	spin_unlock_irqrestore(hosts[host_index]->host_lock, flags);
+}
+
+static void internal_done(Scsi_Cmnd * cmd)
+{
+	cmd->SCp.Status++;
+	return;
+}
+
+/* SCSI-SCB-command for device_inquiry */
+static int device_inquiry(int host_index, int ldn)
+{
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[ldn].scb);
+	tsb = &(ld(host_index)[ldn].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	ld(host_index)[ldn].tsb.dev_status = 0;	/* prepare statusblock */
+	for (retr = 0; retr < 3; retr++) {
+		/* fill scb with inquiry command */
+		scb->command = IM_DEVICE_INQUIRY_CMD | IM_NO_DISCONNECT;
+		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[ldn] = IM_DEVICE_INQUIRY_CMD;
+		last_scsi_type(host_index)[ldn] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		scb->sys_buf_length = 255;	/* maximum bufferlength gives max info */
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/* issue scb to passed ldn, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if command succesful, break */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/*if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+static int read_capacity(int host_index, int ldn)
+{
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[ldn].scb);
+	tsb = &(ld(host_index)[ldn].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	ld(host_index)[ldn].tsb.dev_status = 0;
+	for (retr = 0; retr < 3; retr++) {
+		/*fill scb with read capacity command */
+		scb->command = IM_READ_CAPACITY_CMD;
+		scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_READ_CONTROL | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[ldn] = IM_READ_CAPACITY_CMD;
+		last_scsi_type(host_index)[ldn] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		scb->sys_buf_length = 8;
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/*issue scb to passed ldn, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if got capacity, get block length and return one device found */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/*if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+static int get_pos_info(int host_index)
+{
+	int retr;
+	struct im_scb *scb;
+	struct im_tsb *tsb;
+	unsigned char *buf;
+
+	scb = &(ld(host_index)[MAX_LOG_DEV].scb);
+	tsb = &(ld(host_index)[MAX_LOG_DEV].tsb);
+	buf = (unsigned char *) (&(ld(host_index)[MAX_LOG_DEV].buf));
+	ld(host_index)[MAX_LOG_DEV].tsb.dev_status = 0;
+	for (retr = 0; retr < 3; retr++) {
+		/*fill scb with get_pos_info command */
+		scb->command = IM_GET_POS_INFO_CMD;
+		scb->enable = IM_READ_CONTROL | IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE | IM_BYPASS_BUFFER;
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_GET_POS_INFO_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_SCB;
+		scb->sys_buf_adr = isa_virt_to_bus(buf);
+		if (special(host_index) == IBM_SCSI2_FW)
+			scb->sys_buf_length = 256;	/* get all info from F/W adapter */
+		else
+			scb->sys_buf_length = 18;	/* get exactly 18 bytes for other SCSI */
+		scb->tsb_adr = isa_virt_to_bus(tsb);
+		/*issue scb to ldn=15, and busy wait for interrupt */
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | MAX_LOG_DEV);
+		
+		/* FIXME: timeout */
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if got POS-stuff, get block length and return one device found */
+		if ((stat_result(host_index) == IM_SCB_CMD_COMPLETED) || (stat_result(host_index) == IM_SCB_CMD_COMPLETED_WITH_RETRIES))
+			return 1;
+	}
+	/* if all three retries failed, return "no device at this ldn" */
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+/* SCSI-immediate-command for assign. This functions maps/unmaps specific
+ ldn-numbers on SCSI (PUN,LUN). It is needed for presetting of the
+ subsystem and for dynamical remapping od ldns. */
+static int immediate_assign(int host_index, unsigned int pun, unsigned int lun, unsigned int ldn, unsigned int operation)
+{
+	int retr;
+	unsigned long imm_cmd;
+
+	for (retr = 0; retr < 3; retr++) {
+		/* select mutation level of the SCSI-adapter */
+		switch (special(host_index)) {
+		case IBM_SCSI2_FW:
+			imm_cmd = (unsigned long) (IM_ASSIGN_IMM_CMD);
+			imm_cmd |= (unsigned long) ((lun & 7) << 24);
+			imm_cmd |= (unsigned long) ((operation & 1) << 23);
+			imm_cmd |= (unsigned long) ((pun & 7) << 20) | ((pun & 8) << 24);
+			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
+			break;
+		default:
+			imm_cmd = inl(IM_CMD_REG(host_index));
+			imm_cmd &= (unsigned long) (0xF8000000);	/* keep reserved bits */
+			imm_cmd |= (unsigned long) (IM_ASSIGN_IMM_CMD);
+			imm_cmd |= (unsigned long) ((lun & 7) << 24);
+			imm_cmd |= (unsigned long) ((operation & 1) << 23);
+			imm_cmd |= (unsigned long) ((pun & 7) << 20);
+			imm_cmd |= (unsigned long) ((ldn & 15) << 16);
+			break;
+		}
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_ASSIGN_IMM_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+		while (!got_interrupt(host_index))
+			barrier();
+
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+static int immediate_feature(int host_index, unsigned int speed, unsigned int timeout)
+{
+	int retr;
+	unsigned long imm_cmd;
+
+	for (retr = 0; retr < 3; retr++) {
+		/* select mutation level of the SCSI-adapter */
+		imm_cmd = IM_FEATURE_CTR_IMM_CMD;
+		imm_cmd |= (unsigned long) ((speed & 0x7) << 29);
+		imm_cmd |= (unsigned long) ((timeout & 0x1fff) << 16);
+		last_scsi_command(host_index)[MAX_LOG_DEV] = IM_FEATURE_CTR_IMM_CMD;
+		last_scsi_type(host_index)[MAX_LOG_DEV] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		/* we need to run into command errors in order to probe for the
+		 * right speed! */
+		global_command_error_excuse = 1;
+		issue_cmd(host_index, (unsigned long) (imm_cmd), IM_IMM_CMD | MAX_LOG_DEV);
+		
+		/* FIXME: timeout */
+		while (!got_interrupt(host_index))
+			barrier();
+		if (global_command_error_excuse == CMD_FAIL) {
+			global_command_error_excuse = 0;
+			return 2;
+		} else
+			global_command_error_excuse = 0;
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retr >= 3)
+		return 0;
+	else
+		return 1;
+}
+
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+static int immediate_reset(int host_index, unsigned int ldn)
+{
+	int retries;
+	int ticks;
+	unsigned long imm_command;
+
+	for (retries = 0; retries < 3; retries++) {
+		imm_command = inl(IM_CMD_REG(host_index));
+		imm_command &= (unsigned long) (0xFFFF0000);	/* keep reserved bits */
+		imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
+		last_scsi_command(host_index)[ldn] = IM_RESET_IMM_CMD;
+		last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+		got_interrupt(host_index) = 0;
+		reset_status(host_index) = IM_RESET_IN_PROGRESS;
+		issue_cmd(host_index, (unsigned long) (imm_command), IM_IMM_CMD | ldn);
+		ticks = IM_RESET_DELAY * HZ;
+		while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks) {
+			udelay((1 + 999 / HZ) * 1000);
+			barrier();
+		}
+		/* if reset did not complete, just complain */
+		if (!ticks) {
+			printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
+			reset_status(host_index) = IM_RESET_FINISHED_OK;
+			/* did not work, finish */
+			return 1;
+		}
+		/*if command succesful, break */
+		if (stat_result(host_index) == IM_IMMEDIATE_CMD_COMPLETED)
+			return 1;
+	}
+	if (retries >= 3)
+		return 0;
+	else
+		return 1;
+}
+#endif
+
+/* type-interpreter for physical device numbers */
+static char *ti_p(int dev)
+{
+	switch (dev) {
+	case TYPE_IBM_SCSI_ADAPTER:
+		return ("A");
+	case TYPE_DISK:
+		return ("D");
+	case TYPE_TAPE:
+		return ("T");
+	case TYPE_PROCESSOR:
+		return ("P");
+	case TYPE_WORM:
+		return ("W");
+	case TYPE_ROM:
+		return ("R");
+	case TYPE_SCANNER:
+		return ("S");
+	case TYPE_MOD:
+		return ("M");
+	case TYPE_MEDIUM_CHANGER:
+		return ("C");
+	case TYPE_NO_LUN:
+		return ("+");	/* show NO_LUN */
+	}
+	return ("-");		/* TYPE_NO_DEVICE and others */
+}
+
+/* interpreter for logical device numbers (ldn) */
+static char *ti_l(int val)
+{
+	const char hex[16] = "0123456789abcdef";
+	static char answer[2];
+
+	answer[1] = (char) (0x0);
+	if (val <= MAX_LOG_DEV)
+		answer[0] = hex[val];
+	else
+		answer[0] = '-';
+	return (char *) &answer;
+}
+
+/* transfers bitpattern of the feature command to values in MHz */
+static char *ibmrate(unsigned int speed, int i)
+{
+	switch (speed) {
+	case 0:
+		return i ? "5.00" : "10.00";
+	case 1:
+		return i ? "4.00" : "8.00";
+	case 2:
+		return i ? "3.33" : "6.66";
+	case 3:
+		return i ? "2.86" : "5.00";
+	case 4:
+		return i ? "2.50" : "4.00";
+	case 5:
+		return i ? "2.22" : "3.10";
+	case 6:
+		return i ? "2.00" : "2.50";
+	case 7:
+		return i ? "1.82" : "2.00";
+	}
+	return "---";
+}
+
+static int probe_display(int what)
+{
+	static int rotator = 0;
+	const char rotor[] = "|/-\\";
+
+	if (!(display_mode & LED_DISP))
+		return 0;
+	if (!what) {
+		outl(0x20202020, MOD95_LED_PORT);
+		outl(0x20202020, MOD95_LED_PORT + 4);
+	} else {
+		outb('S', MOD95_LED_PORT + 7);
+		outb('C', MOD95_LED_PORT + 6);
+		outb('S', MOD95_LED_PORT + 5);
+		outb('I', MOD95_LED_PORT + 4);
+		outb('i', MOD95_LED_PORT + 3);
+		outb('n', MOD95_LED_PORT + 2);
+		outb('i', MOD95_LED_PORT + 1);
+		outb((char) (rotor[rotator]), MOD95_LED_PORT);
+		rotator++;
+		if (rotator > 3)
+			rotator = 0;
+	}
+	return 0;
+}
+
+static int probe_bus_mode(int host_index)
+{
+	struct im_pos_info *info;
+	int num_bus = 0;
+	int ldn;
+
+	info = (struct im_pos_info *) (&(ld(host_index)[MAX_LOG_DEV].buf));
+	if (get_pos_info(host_index)) {
+		if (info->connector_size & 0xf000)
+			subsystem_connector_size(host_index) = 16;
+		else
+			subsystem_connector_size(host_index) = 32;
+		num_bus |= (info->pos_4b & 8) >> 3;
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			if ((special(host_index) == IBM_SCSI_WCACHE) || (special(host_index) == IBM_7568_WCACHE)) {
+				if (!((info->cache_stat >> ldn) & 1))
+					ld(host_index)[ldn].cache_flag = 0;
+			}
+			if (!((info->retry_stat >> ldn) & 1))
+				ld(host_index)[ldn].retry_flag = 0;
+		}
+#ifdef IM_DEBUG_PROBE
+		printk("IBM MCA SCSI: SCSI-Cache bits: ");
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			printk("%d", ld(host_index)[ldn].cache_flag);
+		}
+		printk("\nIBM MCA SCSI: SCSI-Retry bits: ");
+		for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+			printk("%d", ld(host_index)[ldn].retry_flag);
+		}
+		printk("\n");
+#endif
+	}
+	return num_bus;
+}
+
+/* probing scsi devices */
+static void check_devices(int host_index, int adaptertype)
+{
+	int id, lun, ldn, ticks;
+	int count_devices;	/* local counter for connected device */
+	int max_pun;
+	int num_bus;
+	int speedrun;		/* local adapter_speed check variable */
+
+	/* assign default values to certain variables */
+	ticks = 0;
+	count_devices = 0;
+	IBM_DS(host_index).dyn_flag = 0;	/* normally no need for dynamical ldn management */
+	IBM_DS(host_index).total_errors = 0;	/* set errorcounter to 0 */
+	next_ldn(host_index) = 7;	/* next ldn to be assigned is 7, because 0-6 is 'hardwired' */
+
+	/* initialize the very important driver-informational arrays/structs */
+	memset(ld(host_index), 0, sizeof(ld(host_index)));
+	for (ldn = 0; ldn <= MAX_LOG_DEV; ldn++) {
+		last_scsi_command(host_index)[ldn] = NO_SCSI;	/* emptify last SCSI-command storage */
+		last_scsi_type(host_index)[ldn] = 0;
+		ld(host_index)[ldn].cache_flag = 1;
+		ld(host_index)[ldn].retry_flag = 1;
+	}
+	memset(get_ldn(host_index), TYPE_NO_DEVICE, sizeof(get_ldn(host_index)));	/* this is essential ! */
+	memset(get_scsi(host_index), TYPE_NO_DEVICE, sizeof(get_scsi(host_index)));	/* this is essential ! */
+	for (lun = 0; lun < 8; lun++) {
+		/* mark the adapter at its pun on all luns */
+		get_scsi(host_index)[subsystem_pun(host_index)][lun] = TYPE_IBM_SCSI_ADAPTER;
+		get_ldn(host_index)[subsystem_pun(host_index)][lun] = MAX_LOG_DEV;	/* make sure, the subsystem
+											   ldn is active for all
+											   luns. */
+	}
+	probe_display(0);	/* Supercool display usage during SCSI-probing. */
+	/* This makes sense, when booting without any */
+	/* monitor connected on model XX95. */
+
+	/* STEP 1: */
+	adapter_speed(host_index) = global_adapter_speed;
+	speedrun = adapter_speed(host_index);
+	while (immediate_feature(host_index, speedrun, adapter_timeout) == 2) {
+		probe_display(1);
+		if (speedrun == 7)
+			panic("IBM MCA SCSI: Cannot set Synchronous-Transfer-Rate!\n");
+		speedrun++;
+		if (speedrun > 7)
+			speedrun = 7;
+	}
+	adapter_speed(host_index) = speedrun;
+	/* Get detailed information about the current adapter, necessary for
+	 * device operations: */
+	num_bus = probe_bus_mode(host_index);
+
+	/* num_bus contains only valid data for the F/W adapter! */
+	if (adaptertype == IBM_SCSI2_FW) {	/* F/W SCSI adapter: */
+		/* F/W adapter PUN-space extension evaluation: */
+		if (num_bus) {
+			printk(KERN_INFO "IBM MCA SCSI: Separate bus mode (wide-addressing enabled)\n");
+			subsystem_maxid(host_index) = 16;
+		} else {
+			printk(KERN_INFO "IBM MCA SCSI: Combined bus mode (wide-addressing disabled)\n");
+			subsystem_maxid(host_index) = 8;
+		}
+		printk(KERN_INFO "IBM MCA SCSI: Sync.-Rate (F/W: 20, Int.: 10, Ext.: %s) MBytes/s\n", ibmrate(speedrun, adaptertype));
+	} else			/* all other IBM SCSI adapters: */
+		printk(KERN_INFO "IBM MCA SCSI: Synchronous-SCSI-Transfer-Rate: %s MBytes/s\n", ibmrate(speedrun, adaptertype));
+
+	/* assign correct PUN device space */
+	max_pun = subsystem_maxid(host_index);
+
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Current SCSI-host index: %d\n", host_index);
+	printk("IBM MCA SCSI: Removing default logical SCSI-device mapping.");
+#else
+	printk(KERN_INFO "IBM MCA SCSI: Dev. Order: %s, Mapping (takes <2min): ", (ibm_ansi_order) ? "ANSI" : "New");
+#endif
+	for (ldn = 0; ldn < MAX_LOG_DEV; ldn++) {
+		probe_display(1);
+#ifdef IM_DEBUG_PROBE
+		printk(".");
+#endif
+		immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);	/* remove ldn (wherever) */
+	}
+	lun = 0;		/* default lun is 0 */
+#ifndef IM_DEBUG_PROBE
+	printk("cleared,");
+#endif
+	/* STEP 2: */
+#ifdef IM_DEBUG_PROBE
+	printk("\nIBM MCA SCSI: Scanning SCSI-devices.");
+#endif
+	for (id = 0; id < max_pun; id++)
+#ifdef CONFIG_SCSI_MULTI_LUN
+		for (lun = 0; lun < 8; lun++)
+#endif
+		{
+			probe_display(1);
+#ifdef IM_DEBUG_PROBE
+			printk(".");
+#endif
+			if (id != subsystem_pun(host_index)) {
+				/* if pun is not the adapter: */
+				/* set ldn=0 to pun,lun */
+				immediate_assign(host_index, id, lun, PROBE_LDN, SET_LDN);
+				if (device_inquiry(host_index, PROBE_LDN)) {	/* probe device */
+					get_scsi(host_index)[id][lun] = (unsigned char) (ld(host_index)[PROBE_LDN].buf[0]);
+					/* entry, even for NO_LUN */
+					if (ld(host_index)[PROBE_LDN].buf[0] != TYPE_NO_LUN)
+						count_devices++;	/* a existing device is found */
+				}
+				/* remove ldn */
+				immediate_assign(host_index, id, lun, PROBE_LDN, REMOVE_LDN);
+			}
+		}
+#ifndef IM_DEBUG_PROBE
+	printk("scanned,");
+#endif
+	/* STEP 3: */
+#ifdef IM_DEBUG_PROBE
+	printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
+#endif
+	ldn = 0;
+	lun = 0;
+#ifdef CONFIG_SCSI_MULTI_LUN
+	for (lun = 0; lun < 8 && ldn < MAX_LOG_DEV; lun++)
+#endif
+		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
+			probe_display(1);
+#ifdef IM_DEBUG_PROBE
+			printk(".");
+#endif
+			if (id != subsystem_pun(host_index)) {
+				if (get_scsi(host_index)[id][lun] != TYPE_NO_LUN && get_scsi(host_index)[id][lun] != TYPE_NO_DEVICE) {
+					/* Only map if accepted type. Always enter for
+					   lun == 0 to get no gaps into ldn-mapping for ldn<7. */
+					immediate_assign(host_index, id, lun, ldn, SET_LDN);
+					get_ldn(host_index)[id][lun] = ldn;	/* map ldn */
+					if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
+						printk("resetting device at ldn=%x ... ", ldn);
+						immediate_reset(host_index, ldn);
+#endif
+						ldn++;
+					} else {
+						/* device vanished, probably because we don't know how to
+						 * handle it or because it has problems */
+						if (lun > 0) {
+							/* remove mapping */
+							get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
+							immediate_assign(host_index, 0, 0, ldn, REMOVE_LDN);
+						} else
+							ldn++;
+					}
+				} else if (lun == 0) {
+					/* map lun == 0, even if no device exists */
+					immediate_assign(host_index, id, lun, ldn, SET_LDN);
+					get_ldn(host_index)[id][lun] = ldn;	/* map ldn */
+					ldn++;
+				}
+			}
+		}
+	/* STEP 4: */
+
+	/* map remaining ldns to non-existing devices */
+	for (lun = 1; lun < 8 && ldn < MAX_LOG_DEV; lun++)
+		for (id = 0; id < max_pun && ldn < MAX_LOG_DEV; id++) {
+			if (get_scsi(host_index)[id][lun] == TYPE_NO_LUN || get_scsi(host_index)[id][lun] == TYPE_NO_DEVICE) {
+				probe_display(1);
+				/* Map remaining ldns only to NON-existing pun,lun
+				   combinations to make sure an inquiry will fail.
+				   For MULTI_LUN, it is needed to avoid adapter autonome
+				   SCSI-remapping. */
+				immediate_assign(host_index, id, lun, ldn, SET_LDN);
+				get_ldn(host_index)[id][lun] = ldn;
+				ldn++;
+			}
+		}
+#ifndef IM_DEBUG_PROBE
+	printk("mapped.");
+#endif
+	printk("\n");
+#ifdef IM_DEBUG_PROBE
+	if (ibm_ansi_order)
+		printk("IBM MCA SCSI: Device order: IBM/ANSI (pun=7 is first).\n");
+	else
+		printk("IBM MCA SCSI: Device order: New Industry Standard (pun=0 is first).\n");
+#endif
+
+#ifdef IM_DEBUG_PROBE
+	/* Show the physical and logical mapping during boot. */
+	printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
+	printk("    Physical SCSI-Device Map               Logical SCSI-Device Map\n");
+	printk("ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
+	for (id = 0; id < max_pun; id++) {
+		printk("%2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			printk("%2s ", ti_p(get_scsi(host_index)[id][lun]));
+		printk("      %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			printk("%2s ", ti_l(get_ldn(host_index)[id][lun]));
+		printk("\n");
+	}
+#endif
+
+	/* assign total number of found SCSI-devices to the statistics struct */
+	IBM_DS(host_index).total_scsi_devices = count_devices;
+
+	/* decide for output in /proc-filesystem, if the configuration of
+	   SCSI-devices makes dynamical reassignment of devices necessary */
+	if (count_devices >= MAX_LOG_DEV)
+		IBM_DS(host_index).dyn_flag = 1;	/* dynamical assignment is necessary */
+	else
+		IBM_DS(host_index).dyn_flag = 0;	/* dynamical assignment is not necessary */
+
+	/* If no SCSI-devices are assigned, return 1 in order to cause message. */
+	if (ldn == 0)
+		printk("IBM MCA SCSI: Warning: No SCSI-devices found/assigned!\n");
+
+	/* reset the counters for statistics on the current adapter */
+	IBM_DS(host_index).scbs = 0;
+	IBM_DS(host_index).long_scbs = 0;
+	IBM_DS(host_index).total_accesses = 0;
+	IBM_DS(host_index).total_interrupts = 0;
+	IBM_DS(host_index).dynamical_assignments = 0;
+	memset(IBM_DS(host_index).ldn_access, 0x0, sizeof(IBM_DS(host_index).ldn_access));
+	memset(IBM_DS(host_index).ldn_read_access, 0x0, sizeof(IBM_DS(host_index).ldn_read_access));
+	memset(IBM_DS(host_index).ldn_write_access, 0x0, sizeof(IBM_DS(host_index).ldn_write_access));
+	memset(IBM_DS(host_index).ldn_inquiry_access, 0x0, sizeof(IBM_DS(host_index).ldn_inquiry_access));
+	memset(IBM_DS(host_index).ldn_modeselect_access, 0x0, sizeof(IBM_DS(host_index).ldn_modeselect_access));
+	memset(IBM_DS(host_index).ldn_assignments, 0x0, sizeof(IBM_DS(host_index).ldn_assignments));
+	probe_display(0);
+	return;
+}
+
+static int device_exists(int host_index, int ldn, int *block_length, int *device_type)
+{
+	unsigned char *buf;
+	/* if no valid device found, return immediately with 0 */
+	if (!(device_inquiry(host_index, ldn)))
+		return 0;
+	buf = (unsigned char *) (&(ld(host_index)[ldn].buf));
+	if (*buf == TYPE_ROM) {
+		*device_type = TYPE_ROM;
+		*block_length = 2048;	/* (standard blocksize for yellow-/red-book) */
+		return 1;
+	}
+	if (*buf == TYPE_WORM) {
+		*device_type = TYPE_WORM;
+		*block_length = 2048;
+		return 1;
+	}
+	if (*buf == TYPE_DISK) {
+		*device_type = TYPE_DISK;
+		if (read_capacity(host_index, ldn)) {
+			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
+			return 1;
+		} else
+			return 0;
+	}
+	if (*buf == TYPE_MOD) {
+		*device_type = TYPE_MOD;
+		if (read_capacity(host_index, ldn)) {
+			*block_length = *(buf + 7) + (*(buf + 6) << 8) + (*(buf + 5) << 16) + (*(buf + 4) << 24);
+			return 1;
+		} else
+			return 0;
+	}
+	if (*buf == TYPE_TAPE) {
+		*device_type = TYPE_TAPE;
+		*block_length = 0;	/* not in use (setting by mt and mtst in op.) */
+		return 1;
+	}
+	if (*buf == TYPE_PROCESSOR) {
+		*device_type = TYPE_PROCESSOR;
+		*block_length = 0;	/* they set their stuff on drivers */
+		return 1;
+	}
+	if (*buf == TYPE_SCANNER) {
+		*device_type = TYPE_SCANNER;
+		*block_length = 0;	/* they set their stuff on drivers */
+		return 1;
+	}
+	if (*buf == TYPE_MEDIUM_CHANGER) {
+		*device_type = TYPE_MEDIUM_CHANGER;
+		*block_length = 0;	/* One never knows, what to expect on a medium
+					   changer device. */
+		return 1;
+	}
+	return 0;
+}
+
+static void internal_ibmmca_scsi_setup(char *str, int *ints)
+{
+	int i, j, io_base, id_base;
+	char *token;
+
+	io_base = 0;
+	id_base = 0;
+	if (str) {
+		j = 0;
+		while ((token = strsep(&str, ",")) != NULL) {
+			if (!strcmp(token, "activity"))
+				display_mode |= LED_ACTIVITY;
+			if (!strcmp(token, "display"))
+				display_mode |= LED_DISP;
+			if (!strcmp(token, "adisplay"))
+				display_mode |= LED_ADISP;
+			if (!strcmp(token, "normal"))
+				ibm_ansi_order = 0;
+			if (!strcmp(token, "ansi"))
+				ibm_ansi_order = 1;
+			if (!strcmp(token, "fast"))
+				global_adapter_speed = 0;
+			if (!strcmp(token, "medium"))
+				global_adapter_speed = 4;
+			if (!strcmp(token, "slow"))
+				global_adapter_speed = 7;
+			if ((*token == '-') || (isdigit(*token))) {
+				if (!(j % 2) && (io_base < IM_MAX_HOSTS))
+					io_port[io_base++] = simple_strtoul(token, NULL, 0);
+				if ((j % 2) && (id_base < IM_MAX_HOSTS))
+					scsi_id[id_base++] = simple_strtoul(token, NULL, 0);
+				j++;
+			}
+		}
+	} else if (ints) {
+		for (i = 0; i < IM_MAX_HOSTS && 2 * i + 2 < ints[0]; i++) {
+			io_port[i] = ints[2 * i + 2];
+			scsi_id[i] = ints[2 * i + 2];
+		}
+	}
+	return;
+}
+
+static int ibmmca_getinfo(char *buf, int slot, void *dev_id)
+{
+	struct Scsi_Host *shpnt;
+	int len, speciale, connectore, k;
+	unsigned int pos[8];
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+	
+	shpnt = dev;		/* assign host-structure to local pointer */
+	len = 0;		/* set filled text-buffer index to 0 */
+	/* get the _special contents of the hostdata structure */
+	speciale = ((struct ibmmca_hostdata *) shpnt->hostdata)->_special;
+	connectore = ((struct ibmmca_hostdata *) shpnt->hostdata)->_connector_size;
+	for (k = 2; k < 4; k++)
+		pos[k] = ((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k];
+	if (speciale == FORCED_DETECTION) {	/* forced detection */
+		len += sprintf(buf + len,
+			       "Adapter category: forced detected\n" "***************************************\n" "***  Forced detected SCSI Adapter   ***\n" "***  No chip-information available  ***\n" "***************************************\n");
+	} else if (speciale == INTEGRATED_SCSI) {
+		/* if the integrated subsystem has been found automatically: */
+		len += sprintf(buf + len,
+			       "Adapter category: integrated\n" "Chip revision level: %d\n" "Chip status: %s\n" "8 kByte NVRAM status: %s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 1) ? "enabled" : "disabled", (pos[2] & 2) ? "locked" : "accessible");
+	} else if ((speciale >= 0) && (speciale < (sizeof(subsys_list) / sizeof(struct subsys_list_struct)))) {
+		/* if the subsystem is a slot adapter */
+		len += sprintf(buf + len, "Adapter category: slot-card\n" "ROM Segment Address: ");
+		if ((pos[2] & 0xf0) == 0xf0)
+			len += sprintf(buf + len, "off\n");
+		else
+			len += sprintf(buf + len, "0x%x\n", ((pos[2] & 0xf0) << 13) + 0xc0000);
+		len += sprintf(buf + len, "Chip status: %s\n", (pos[2] & 1) ? "enabled" : "disabled");
+		len += sprintf(buf + len, "Adapter I/O Offset: 0x%x\n", ((pos[2] & 0x0e) << 2));
+	} else {
+		len += sprintf(buf + len, "Adapter category: unknown\n");
+	}
+	/* common subsystem information to write to the slotn file */
+	len += sprintf(buf + len, "Subsystem PUN: %d\n", shpnt->this_id);
+	len += sprintf(buf + len, "I/O base address range: 0x%x-0x%x\n", (unsigned int) (shpnt->io_port), (unsigned int) (shpnt->io_port + 7));
+	len += sprintf(buf + len, "MCA-slot size: %d bits", connectore);
+	/* Now make sure, the bufferlength is devidable by 4 to avoid
+	 * paging problems of the buffer. */
+	while (len % sizeof(int) != (sizeof(int) - 1))
+		len += sprintf(buf + len, " ");
+	len += sprintf(buf + len, "\n");
+	
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
+	
+	return len;
+}
+
+int ibmmca_detect(Scsi_Host_Template * scsi_template)
+{
+	struct Scsi_Host *shpnt;
+	int port, id, i, j, k, list_size, slot;
+	int devices_on_irq_11 = 0;
+	int devices_on_irq_14 = 0;
+	int IRQ14_registered = 0;
+	int IRQ11_registered = 0;
+
+	found = 0;		/* make absolutely sure, that found is set to 0 */
+
+	/* First of all, print the version number of the driver. This is
+	 * important to allow better user bugreports in case of already
+	 * having problems with the MCA_bus probing. */
+	printk(KERN_INFO "IBM MCA SCSI: Version %s\n", IBMMCA_SCSI_DRIVER_VERSION);
+	/* if this is not MCA machine, return "nothing found" */
+	if (!MCA_bus) {
+		printk(KERN_INFO "IBM MCA SCSI:  No Microchannel-bus present --> Aborting.\n" "      	     This machine does not have any IBM MCA-bus\n" "    	     or the MCA-Kernel-support is not enabled!\n");
+		return 0;
+	}
+
+#ifdef MODULE
+	/* If the driver is run as module, read from conf.modules or cmd-line */
+	if (boot_options)
+		option_setup(boot_options);
+#endif
+
+	/* get interrupt request level */
+	if (request_irq(IM_IRQ, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ);
+		return 0;
+	} else
+		IRQ14_registered++;
+
+	/* if ibmmcascsi setup option was passed to kernel, return "found" */
+	for (i = 0; i < IM_MAX_HOSTS; i++)
+		if (io_port[i] > 0 && scsi_id[i] >= 0 && scsi_id[i] < 8) {
+			printk("IBM MCA SCSI: forced detected SCSI Adapter, io=0x%x, scsi id=%d.\n", io_port[i], scsi_id[i]);
+			if ((shpnt = ibmmca_register(scsi_template, io_port[i], scsi_id[i], FORCED_DETECTION, "forced detected SCSI Adapter"))) {
+				for (k = 2; k < 7; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = 0;
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = FORCED_DETECTION;
+				mca_set_adapter_name(MCA_INTEGSCSI, "forced detected SCSI Adapter");
+				mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(MCA_INTEGSCSI);
+				devices_on_irq_14++;
+			}
+		}
+	if (found)
+		return found;
+
+	/* The POS2-register of all PS/2 model SCSI-subsystems has the following
+	 * interpretation of bits:
+	 *                             Bit 7 - 4 : Chip Revision ID (Release)
+	 *                             Bit 3 - 2 : Reserved
+	 *                             Bit 1     : 8k NVRAM Disabled
+	 *                             Bit 0     : Chip Enable (EN-Signal)
+	 * The POS3-register is interpreted as follows:
+	 *                             Bit 7 - 5 : SCSI ID
+	 *                             Bit 4     : Reserved = 0
+	 *                             Bit 3 - 0 : Reserved = 0
+	 * (taken from "IBM, PS/2 Hardware Interface Technical Reference, Common
+	 * Interfaces (1991)").
+	 * In short words, this means, that IBM PS/2 machines only support
+	 * 1 single subsystem by default. The slot-adapters must have another
+	 * configuration on pos2. Here, one has to assume the following
+	 * things for POS2-register:
+	 *                             Bit 7 - 4 : Chip Revision ID (Release)
+	 *                             Bit 3 - 1 : port offset factor
+	 *                             Bit 0     : Chip Enable (EN-Signal)
+	 * As I found a patch here, setting the IO-registers to 0x3540 forced,
+	 * as there was a 0x05 in POS2 on a model 56, I assume, that the
+	 * port 0x3540 must be fix for integrated SCSI-controllers.
+	 * Ok, this discovery leads to the following implementation: (M.Lang) */
+
+	/* first look for the IBM SCSI integrated subsystem on the motherboard */
+	for (j = 0; j < 8; j++)	/* read the pos-information */
+		pos[j] = mca_read_stored_pos(MCA_INTEGSCSI, j);
+	/* pos2 = pos3 = 0xff if there is no integrated SCSI-subsystem present, but
+	 * if we ignore the settings of all surrounding pos registers, it is not
+	 * completely sufficient to only check pos2 and pos3. */
+	/* Therefore, now the following if statement is used to
+	 * make sure, we see a real integrated onboard SCSI-interface and no
+	 * internal system information, which gets mapped to some pos registers
+	 * on models 95xx. */
+	if ((!pos[0] && !pos[1] && pos[2] > 0 && pos[3] > 0 && !pos[4] && !pos[5] && !pos[6] && !pos[7]) || (pos[0] == 0xff && pos[1] == 0xff && pos[2] < 0xff && pos[3] < 0xff && pos[4] == 0xff && pos[5] == 0xff && pos[6] == 0xff && pos[7] == 0xff)) {
+		if ((pos[2] & 1) == 1)	/* is the subsystem chip enabled ? */
+			port = IM_IO_PORT;
+		else {		/* if disabled, no IRQs will be generated, as the chip won't
+				 * listen to the incoming commands and will do really nothing,
+				 * except for listening to the pos-register settings. If this
+				 * happens, I need to hugely think about it, as one has to
+				 * write something to the MCA-Bus pos register in order to
+				 * enable the chip. Normally, IBM-SCSI won't pass the POST,
+				 * when the chip is disabled (see IBM tech. ref.). */
+			port = IM_IO_PORT;	/* anyway, set the portnumber and warn */
+			printk("IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n" "              SCSI-operations may not work.\n");
+		}
+		id = (pos[3] & 0xe0) >> 5;	/* this is correct and represents the PUN */
+		/* give detailed information on the subsystem. This helps me
+		 * additionally during debugging and analyzing bug-reports. */
+		printk(KERN_INFO "IBM MCA SCSI: IBM Integrated SCSI Controller ffound, io=0x%x, scsi id=%d,\n", port, id);
+		printk(KERN_INFO "              chip rev.=%d, 8K NVRAM=%s, subsystem=%s\n", ((pos[2] & 0xf0) >> 4), (pos[2] & 2) ? "locked" : "accessible", (pos[2] & 1) ? "enabled." : "disabled.");
+
+		/* register the found integrated SCSI-subsystem */
+		if ((shpnt = ibmmca_register(scsi_template, port, id, INTEGRATED_SCSI, "IBM Integrated SCSI Controller"))) 
+		{
+			for (k = 2; k < 7; k++)
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+			((struct ibmmca_hostdata *) shpnt->hostdata)->_special = INTEGRATED_SCSI;
+			mca_set_adapter_name(MCA_INTEGSCSI, "IBM Integrated SCSI Controller");
+			mca_set_adapter_procfn(MCA_INTEGSCSI, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+			mca_mark_as_used(MCA_INTEGSCSI);
+			devices_on_irq_14++;
+		}
+	}
+
+	/* now look for other adapters in MCA slots, */
+	/* determine the number of known IBM-SCSI-subsystem types */
+	/* see the pos[2] dependence to get the adapter port-offset. */
+	list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+	for (i = 0; i < list_size; i++) {
+		/* scan each slot for a fitting adapter id */
+		slot = 0;	/* start at slot 0 */
+		while ((slot = mca_find_adapter(subsys_list[i].mca_id, slot))
+		       != MCA_NOTFOUND) {	/* scan through all slots */
+			for (j = 0; j < 8; j++)	/* read the pos-information */
+				pos[j] = mca_read_stored_pos(slot, j);
+			if ((pos[2] & 1) == 1)
+				/* is the subsystem chip enabled ? */
+				/* (explanations see above) */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+			else {
+				/* anyway, set the portnumber and warn */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+				printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+				printk(KERN_WARNING "              SCSI-operations may not work.\n");
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
+				printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+				printk(KERN_ERR "              Impossible to determine adapter PUN!\n");
+				printk(KERN_ERR "              Guessing adapter PUN = 7.\n");
+				id = 7;
+			} else {
+				id = (pos[3] & 0xe0) >> 5;	/* get subsystem PUN */
+				if (i == IBM_SCSI2_FW) {
+					id |= (pos[3] & 0x10) >> 1;	/* get subsystem PUN high-bit
+									 * for F/W adapters */
+				}
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
+				/* IRQ11 is used by SCSI-2 F/W Adapter/A */
+				printk(KERN_DEBUG "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+				/* get interrupt request level */
+				if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts)) {
+					printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
+				} else
+					IRQ11_registered++;
+			}
+			printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
+			if ((pos[2] & 0xf0) == 0xf0)
+				printk(KERN_DEBUG"              ROM Addr.=off,");
+			else
+				printk(KERN_DEBUG "              ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
+			printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
+
+			/* register the hostadapter */
+			if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
+				for (k = 2; k < 8; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
+				mca_set_adapter_name(slot, subsys_list[i].description);
+				mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(slot);
+				if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
+					devices_on_irq_11++;
+				else
+					devices_on_irq_14++;
+			}
+			slot++;	/* advance to next slot */
+		}		/* advance to next adapter id in the list of IBM-SCSI-subsystems */
+	}
+
+	/* now check for SCSI-adapters, mapped to the integrated SCSI
+	 * area. E.g. a W/Cache in MCA-slot 9(!). Do the check correct here,
+	 * as this is a known effect on some models 95xx. */
+	list_size = sizeof(subsys_list) / sizeof(struct subsys_list_struct);
+	for (i = 0; i < list_size; i++) {
+		/* scan each slot for a fitting adapter id */
+		slot = mca_find_adapter(subsys_list[i].mca_id, MCA_INTEGSCSI);
+		if (slot != MCA_NOTFOUND) {	/* scan through all slots */
+			for (j = 0; j < 8; j++)	/* read the pos-information */
+				pos[j] = mca_read_stored_pos(slot, j);
+			if ((pos[2] & 1) == 1) {	/* is the subsystem chip enabled ? */
+				/* (explanations see above) */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+			} else {	/* anyway, set the portnumber and warn */
+				port = IM_IO_PORT + ((pos[2] & 0x0e) << 2);
+				printk(KERN_WARNING "IBM MCA SCSI: WARNING - Your SCSI-subsystem is disabled!\n");
+				printk(KERN_WARNING "              SCSI-operations may not work.\n");
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[6] != 0)) {
+				printk(KERN_ERR "IBM MCA SCSI: ERROR - Wrong POS(6)-register setting!\n");
+				printk(KERN_ERR  "              Impossible to determine adapter PUN!\n");
+				printk(KERN_ERR "              Guessing adapter PUN = 7.\n");
+				id = 7;
+			} else {
+				id = (pos[3] & 0xe0) >> 5;	/* get subsystem PUN */
+				if (i == IBM_SCSI2_FW)
+					id |= (pos[3] & 0x10) >> 1;	/* get subsystem PUN high-bit
+									 * for F/W adapters */
+			}
+			if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0)) {
+				/* IRQ11 is used by SCSI-2 F/W Adapter/A */
+				printk(KERN_DEBUG  "IBM MCA SCSI: SCSI-2 F/W adapter needs IRQ 11.\n");
+				/* get interrupt request level */
+				if (request_irq(IM_IRQ_FW, interrupt_handler, SA_SHIRQ, "ibmmcascsi", hosts))
+					printk(KERN_ERR "IBM MCA SCSI: Unable to get shared IRQ %d.\n", IM_IRQ_FW);
+				else
+					IRQ11_registered++;
+			}
+			printk(KERN_INFO "IBM MCA SCSI: %s found in slot %d, io=0x%x, scsi id=%d,\n", subsys_list[i].description, slot + 1, port, id);
+			if ((pos[2] & 0xf0) == 0xf0)
+				printk(KERN_DEBUG "              ROM Addr.=off,");
+			else
+				printk(KERN_DEBUG "              ROM Addr.=0x%x,", ((pos[2] & 0xf0) << 13) + 0xc0000);
+			printk(KERN_DEBUG " port-offset=0x%x, subsystem=%s\n", ((pos[2] & 0x0e) << 2), (pos[2] & 1) ? "enabled." : "disabled.");
+
+			/* register the hostadapter */
+			if ((shpnt = ibmmca_register(scsi_template, port, id, i, subsys_list[i].description))) {
+				for (k = 2; k < 7; k++)
+					((struct ibmmca_hostdata *) shpnt->hostdata)->_pos[k] = pos[k];
+				((struct ibmmca_hostdata *) shpnt->hostdata)->_special = i;
+				mca_set_adapter_name(slot, subsys_list[i].description);
+				mca_set_adapter_procfn(slot, (MCA_ProcFn) ibmmca_getinfo, shpnt);
+				mca_mark_as_used(slot);
+				if ((i == IBM_SCSI2_FW) && (pos[4] & 0x01) && (pos[6] == 0))
+					devices_on_irq_11++;
+				else
+					devices_on_irq_14++;
+			}
+			slot++;	/* advance to next slot */
+		}		/* advance to next adapter id in the list of IBM-SCSI-subsystems */
+	}
+	if (IRQ11_registered && !devices_on_irq_11)
+		free_irq(IM_IRQ_FW, hosts);	/* no devices on IRQ 11 */
+	if (IRQ14_registered && !devices_on_irq_14)
+		free_irq(IM_IRQ, hosts);	/* no devices on IRQ 14 */
+	if (!devices_on_irq_11 && !devices_on_irq_14)
+		printk(KERN_WARNING "IBM MCA SCSI: No IBM SCSI-subsystem adapter attached.\n");
+	return found;		/* return the number of found SCSI hosts. Should be 1 or 0. */
+}
+
+static struct Scsi_Host *ibmmca_register(Scsi_Host_Template * scsi_template, int port, int id, int adaptertype, char *hostname)
+{
+	struct Scsi_Host *shpnt;
+	int i, j;
+	unsigned int ctrl;
+
+	/* check I/O region */
+	if (!request_region(port, IM_N_IO_PORT, hostname)) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to get I/O region 0x%x-0x%x (%d ports).\n", port, port + IM_N_IO_PORT - 1, IM_N_IO_PORT);
+		return NULL;
+	}
+
+	/* register host */
+	shpnt = scsi_register(scsi_template, sizeof(struct ibmmca_hostdata));
+	if (!shpnt) {
+		printk(KERN_ERR "IBM MCA SCSI: Unable to register host.\n");
+		release_region(port, IM_N_IO_PORT);
+		return NULL;
+	}
+
+	/* request I/O region */
+	hosts[found] = shpnt;	/* add new found hostadapter to the list */
+	special(found) = adaptertype;	/* important assignment or else crash! */
+	subsystem_connector_size(found) = 0;	/* preset slot-size */
+	shpnt->irq = IM_IRQ;	/* assign necessary stuff for the adapter */
+	shpnt->io_port = port;
+	shpnt->n_io_port = IM_N_IO_PORT;
+	shpnt->this_id = id;
+	shpnt->max_id = 8;	/* 8 PUNs are default */
+	/* now, the SCSI-subsystem is connected to Linux */
+
+	ctrl = (unsigned int) (inb(IM_CTR_REG(found)));	/* get control-register status */
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Control Register contents: %x, status: %x\n", ctrl, inb(IM_STAT_REG(found)));
+	printk("IBM MCA SCSI: This adapters' POS-registers: ");
+	for (i = 0; i < 8; i++)
+		printk("%x ", pos[i]);
+	printk("\n");
+#endif
+	reset_status(found) = IM_RESET_NOT_IN_PROGRESS;
+
+	for (i = 0; i < 16; i++)	/* reset the tables */
+		for (j = 0; j < 8; j++)
+			get_ldn(found)[i][j] = MAX_LOG_DEV;
+
+	/* check which logical devices exist */
+	/* after this line, local interrupting is possible: */
+	local_checking_phase_flag(found) = 1;
+	check_devices(found, adaptertype);	/* call by value, using the global variable hosts */
+	local_checking_phase_flag(found) = 0;
+	found++;		/* now increase index to be prepared for next found subsystem */
+	/* an ibm mca subsystem has been detected */
+	return shpnt;
+}
+
+static int ibmmca_release(struct Scsi_Host *shpnt)
+{
+	release_region(shpnt->io_port, shpnt->n_io_port);
+	if (!(--found))
+		free_irq(shpnt->irq, hosts);
+	return 0;
+}
+
+/* The following routine is the SCSI command queue for the midlevel driver */
+static int ibmmca_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	unsigned int ldn;
+	unsigned int scsi_cmd;
+	struct im_scb *scb;
+	struct Scsi_Host *shpnt;
+	int current_ldn;
+	int id, lun;
+	int target;
+	int host_index;
+	int max_pun;
+	int i;
+	struct scatterlist *sl;
+
+	shpnt = cmd->device->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index]) {	/* invalid hostadapter descriptor address */
+		cmd->result = DID_NO_CONNECT << 16;
+		if (done)
+			done(cmd);
+		return 0;
+	}
+	max_pun = subsystem_maxid(host_index);
+	if (ibm_ansi_order) {
+		target = max_pun - 1 - cmd->device->id;
+		if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+			target--;
+		else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+			target++;
+	} else
+		target = cmd->device->id;
+
+	/* if (target,lun) is NO LUN or not existing at all, return error */
+	if ((get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_LUN) || (get_scsi(host_index)[target][cmd->device->lun] == TYPE_NO_DEVICE)) {
+		cmd->result = DID_NO_CONNECT << 16;
+		if (done)
+			done(cmd);
+		return 0;
+	}
+
+	/*if (target,lun) unassigned, do further checks... */
+	ldn = get_ldn(host_index)[target][cmd->device->lun];
+	if (ldn >= MAX_LOG_DEV) {	/* on invalid ldn do special stuff */
+		if (ldn > MAX_LOG_DEV) {	/* dynamical remapping if ldn unassigned */
+			current_ldn = next_ldn(host_index);	/* stop-value for one circle */
+			while (ld(host_index)[next_ldn(host_index)].cmd) {	/* search for a occupied, but not in */
+				/* command-processing ldn. */
+				next_ldn(host_index)++;
+				if (next_ldn(host_index) >= MAX_LOG_DEV)
+					next_ldn(host_index) = 7;
+				if (current_ldn == next_ldn(host_index)) {	/* One circle done ? */
+					/* no non-processing ldn found */
+					printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n" "              On ldn 7-14 SCSI-commands everywhere in progress.\n" "              Reporting DID_NO_CONNECT for device (%d,%d).\n", target, cmd->device->lun);
+					cmd->result = DID_NO_CONNECT << 16;	/* return no connect */
+					if (done)
+						done(cmd);
+					return 0;
+				}
+			}
+
+			/* unmap non-processing ldn */
+			for (id = 0; id < max_pun; id++)
+				for (lun = 0; lun < 8; lun++) {
+					if (get_ldn(host_index)[id][lun] == next_ldn(host_index)) {
+						get_ldn(host_index)[id][lun] = TYPE_NO_DEVICE;
+						get_scsi(host_index)[id][lun] = TYPE_NO_DEVICE;
+						/* unmap entry */
+					}
+				}
+			/* set reduced interrupt_handler-mode for checking */
+			local_checking_phase_flag(host_index) = 1;
+			/* map found ldn to pun,lun */
+			get_ldn(host_index)[target][cmd->device->lun] = next_ldn(host_index);
+			/* change ldn to the right value, that is now next_ldn */
+			ldn = next_ldn(host_index);
+			/* unassign all ldns (pun,lun,ldn does not matter for remove) */
+			immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+			/* set only LDN for remapped device */
+			immediate_assign(host_index, target, cmd->device->lun, ldn, SET_LDN);
+			/* get device information for ld[ldn] */
+			if (device_exists(host_index, ldn, &ld(host_index)[ldn].block_length, &ld(host_index)[ldn].device_type)) {
+				ld(host_index)[ldn].cmd = NULL;	/* To prevent panic set 0, because
+								   devices that were not assigned,
+								   should have nothing in progress. */
+				get_scsi(host_index)[target][cmd->device->lun] = ld(host_index)[ldn].device_type;
+				/* increase assignment counters for statistics in /proc */
+				IBM_DS(host_index).dynamical_assignments++;
+				IBM_DS(host_index).ldn_assignments[ldn]++;
+			} else
+				/* panic here, because a device, found at boottime has
+				   vanished */
+				panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n", ldn, target, cmd->device->lun);
+			/* unassign again all ldns (pun,lun,ldn does not matter for remove) */
+			immediate_assign(host_index, 0, 0, 0, REMOVE_LDN);
+			/* remap all ldns, as written in the pun/lun table */
+			lun = 0;
+#ifdef CONFIG_SCSI_MULTI_LUN
+			for (lun = 0; lun < 8; lun++)
+#endif
+				for (id = 0; id < max_pun; id++) {
+					if (get_ldn(host_index)[id][lun] <= MAX_LOG_DEV)
+						immediate_assign(host_index, id, lun, get_ldn(host_index)[id][lun], SET_LDN);
+				}
+			/* set back to normal interrupt_handling */
+			local_checking_phase_flag(host_index) = 0;
+#ifdef IM_DEBUG_PROBE
+			/* Information on syslog terminal */
+			printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n", ldn, target, cmd->device->lun);
+#endif
+			/* increase next_ldn for next dynamical assignment */
+			next_ldn(host_index)++;
+			if (next_ldn(host_index) >= MAX_LOG_DEV)
+				next_ldn(host_index) = 7;
+		} else {	/* wall against Linux accesses to the subsystem adapter */
+			cmd->result = DID_BAD_TARGET << 16;
+			if (done)
+				done(cmd);
+			return 0;
+		}
+	}
+
+	/*verify there is no command already in progress for this log dev */
+	if (ld(host_index)[ldn].cmd)
+		panic("IBM MCA SCSI: cmd already in progress for this ldn.\n");
+
+	/*save done in cmd, and save cmd for the interrupt handler */
+	cmd->scsi_done = done;
+	ld(host_index)[ldn].cmd = cmd;
+
+	/*fill scb information independent of the scsi command */
+	scb = &(ld(host_index)[ldn].scb);
+	ld(host_index)[ldn].tsb.dev_status = 0;
+	scb->enable = IM_REPORT_TSB_ONLY_ON_ERROR | IM_RETRY_ENABLE;
+	scb->tsb_adr = isa_virt_to_bus(&(ld(host_index)[ldn].tsb));
+	scsi_cmd = cmd->cmnd[0];
+
+	if (cmd->use_sg) {
+		i = cmd->use_sg;
+		sl = (struct scatterlist *) (cmd->request_buffer);
+		if (i > 16)
+			panic("IBM MCA SCSI: scatter-gather list too long.\n");
+		while (--i >= 0) {
+			ld(host_index)[ldn].sge[i].address = (void *) (isa_page_to_bus(sl[i].page) + sl[i].offset);
+			ld(host_index)[ldn].sge[i].byte_length = sl[i].length;
+		}
+		scb->enable |= IM_POINTER_TO_LIST;
+		scb->sys_buf_adr = isa_virt_to_bus(&(ld(host_index)[ldn].sge[0]));
+		scb->sys_buf_length = cmd->use_sg * sizeof(struct im_sge);
+	} else {
+		scb->sys_buf_adr = isa_virt_to_bus(cmd->request_buffer);
+		/* recent Linux midlevel SCSI places 1024 byte for inquiry
+		 * command. Far too much for old PS/2 hardware. */
+		switch (scsi_cmd) {
+			/* avoid command errors by setting bufferlengths to
+			 * ANSI-standard. Beware of forcing it to 255,
+			 * this could SEGV the kernel!!! */
+		case INQUIRY:
+		case REQUEST_SENSE:
+		case MODE_SENSE:
+		case MODE_SELECT:
+			if (cmd->request_bufflen > 255)
+				scb->sys_buf_length = 255;
+			else
+				scb->sys_buf_length = cmd->request_bufflen;
+			break;
+		case TEST_UNIT_READY:
+			scb->sys_buf_length = 0;
+			break;
+		default:
+			scb->sys_buf_length = cmd->request_bufflen;
+			break;
+		}
+	}
+	/*fill scb information dependent on scsi command */
+
+#ifdef IM_DEBUG_CMD
+	printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
+#endif
+
+	/* for specific device-type debugging: */
+#ifdef IM_DEBUG_CMD_SPEC_DEV
+	if (ld(host_index)[ldn].device_type == IM_DEBUG_CMD_DEVICE)
+		printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n", ld(host_index)[ldn].device_type, scsi_cmd, ldn);
+#endif
+
+	/* for possible panics store current command */
+	last_scsi_command(host_index)[ldn] = scsi_cmd;
+	last_scsi_type(host_index)[ldn] = IM_SCB;
+	/* update statistical info */
+	IBM_DS(host_index).total_accesses++;
+	IBM_DS(host_index).ldn_access[ldn]++;
+
+	switch (scsi_cmd) {
+	case READ_6:
+	case WRITE_6:
+	case READ_10:
+	case WRITE_10:
+	case READ_12:
+	case WRITE_12:
+		/* Distinguish between disk and other devices. Only disks (that are the
+		   most frequently accessed devices) should be supported by the
+		   IBM-SCSI-Subsystem commands. */
+		switch (ld(host_index)[ldn].device_type) {
+		case TYPE_DISK:	/* for harddisks enter here ... */
+		case TYPE_MOD:	/* ... try it also for MO-drives (send flames as */
+			/*     you like, if this won't work.) */
+			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12) {
+				/* read command preparations */
+				scb->enable |= IM_READ_CONTROL;
+				IBM_DS(host_index).ldn_read_access[ldn]++;	/* increase READ-access on ldn stat. */
+				scb->command = IM_READ_DATA_CMD | IM_NO_DISCONNECT;
+			} else {	/* write command preparations */
+				IBM_DS(host_index).ldn_write_access[ldn]++;	/* increase write-count on ldn stat. */
+				scb->command = IM_WRITE_DATA_CMD | IM_NO_DISCONNECT;
+			}
+			if (scsi_cmd == READ_6 || scsi_cmd == WRITE_6) {
+				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[3]) << 0) | (((unsigned) cmd->cmnd[2]) << 8) | ((((unsigned) cmd->cmnd[1]) & 0x1f) << 16);
+				scb->u2.blk.count = (unsigned) cmd->cmnd[4];
+			} else {
+				scb->u1.log_blk_adr = (((unsigned) cmd->cmnd[5]) << 0) | (((unsigned) cmd->cmnd[4]) << 8) | (((unsigned) cmd->cmnd[3]) << 16) | (((unsigned) cmd->cmnd[2]) << 24);
+				scb->u2.blk.count = (((unsigned) cmd->cmnd[8]) << 0) | (((unsigned) cmd->cmnd[7]) << 8);
+			}
+			last_scsi_logical_block(host_index)[ldn] = scb->u1.log_blk_adr;
+			last_scsi_blockcount(host_index)[ldn] = scb->u2.blk.count;
+			scb->u2.blk.length = ld(host_index)[ldn].block_length;
+			break;
+			/* for other devices, enter here. Other types are not known by
+			   Linux! TYPE_NO_LUN is forbidden as valid device. */
+		case TYPE_ROM:
+		case TYPE_TAPE:
+		case TYPE_PROCESSOR:
+		case TYPE_WORM:
+		case TYPE_SCANNER:
+		case TYPE_MEDIUM_CHANGER:
+			/* If there is a sequential-device, IBM recommends to use
+			   IM_OTHER_SCSI_CMD_CMD instead of subsystem READ/WRITE.
+			   This includes CD-ROM devices, too, due to the partial sequential
+			   read capabilities. */
+			scb->command = IM_OTHER_SCSI_CMD_CMD;
+			if (scsi_cmd == READ_6 || scsi_cmd == READ_10 || scsi_cmd == READ_12)
+				/* enable READ */
+				scb->enable |= IM_READ_CONTROL;
+			scb->enable |= IM_BYPASS_BUFFER;
+			scb->u1.scsi_cmd_length = cmd->cmd_len;
+			memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+			last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+			/* Read/write on this non-disk devices is also displayworthy,
+			   so flash-up the LED/display. */
+			break;
+		}
+		break;
+	case INQUIRY:
+		IBM_DS(host_index).ldn_inquiry_access[ldn]++;
+		scb->command = IM_DEVICE_INQUIRY_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.log_blk_adr = 0;
+		break;
+	case TEST_UNIT_READY:
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.log_blk_adr = 0;
+		scb->u1.scsi_cmd_length = 6;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, 6);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+	case READ_CAPACITY:
+		/* the length of system memory buffer must be exactly 8 bytes */
+		scb->command = IM_READ_CAPACITY_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_BYPASS_BUFFER;
+		if (scb->sys_buf_length > 8)
+			scb->sys_buf_length = 8;
+		break;
+		/* Commands that need read-only-mode (system <- device): */
+	case REQUEST_SENSE:
+		scb->command = IM_REQUEST_SENSE_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		break;
+		/* Commands that need write-only-mode (system -> device): */
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+		IBM_DS(host_index).ldn_modeselect_access[ldn]++;
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;	/*Select needs WRITE-enabled */
+		scb->u1.scsi_cmd_length = cmd->cmd_len;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+		/* For other commands, read-only is useful. Most other commands are
+		   running without an input-data-block. */
+	default:
+		scb->command = IM_OTHER_SCSI_CMD_CMD;
+		scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT | IM_BYPASS_BUFFER;
+		scb->u1.scsi_cmd_length = cmd->cmd_len;
+		memcpy(scb->u2.scsi_command, cmd->cmnd, cmd->cmd_len);
+		last_scsi_type(host_index)[ldn] = IM_LONG_SCB;
+		break;
+	}
+	/*issue scb command, and return */
+	if (++disk_rw_in_progress == 1)
+		PS2_DISK_LED_ON(shpnt->host_no, target);
+
+	if (last_scsi_type(host_index)[ldn] == IM_LONG_SCB) {
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_LONG_SCB | ldn);
+		IBM_DS(host_index).long_scbs++;
+	} else {
+		issue_cmd(host_index, isa_virt_to_bus(scb), IM_SCB | ldn);
+		IBM_DS(host_index).scbs++;
+	}
+	return 0;
+}
+
+static int ibmmca_abort(Scsi_Cmnd * cmd)
+{
+	/* Abort does not work, as the adapter never generates an interrupt on
+	 * whatever situation is simulated, even when really pending commands
+	 * are running on the adapters' hardware ! */
+
+	struct Scsi_Host *shpnt;
+	unsigned int ldn;
+	void (*saved_done) (Scsi_Cmnd *);
+	int target;
+	int host_index;
+	int max_pun;
+	unsigned long imm_command;
+
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort subroutine called...\n");
+#endif
+
+	shpnt = cmd->device->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index]) {	/* invalid hostadapter descriptor address */
+		cmd->result = DID_NO_CONNECT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		shpnt = cmd->device->host;
+#ifdef IM_DEBUG_PROBE
+		printk(KERN_DEBUG "IBM MCA SCSI: Abort adapter selection failed!\n");
+#endif
+		return SUCCESS;
+	}
+	max_pun = subsystem_maxid(host_index);
+	if (ibm_ansi_order) {
+		target = max_pun - 1 - cmd->device->id;
+		if ((target <= subsystem_pun(host_index)) && (cmd->device->id <= subsystem_pun(host_index)))
+			target--;
+		else if ((target >= subsystem_pun(host_index)) && (cmd->device->id >= subsystem_pun(host_index)))
+			target++;
+	} else
+		target = cmd->device->id;
+
+	/* get logical device number, and disable system interrupts */
+	printk(KERN_WARNING "IBM MCA SCSI: Sending abort to device pun=%d, lun=%d.\n", target, cmd->device->lun);
+	ldn = get_ldn(host_index)[target][cmd->device->lun];
+
+	/*if cmd for this ldn has already finished, no need to abort */
+	if (!ld(host_index)[ldn].cmd) {
+		    return SUCCESS;
+	}
+
+	/* Clear ld.cmd, save done function, install internal done,
+	 * send abort immediate command (this enables sys. interrupts),
+	 * and wait until the interrupt arrives.
+	 */
+	saved_done = cmd->scsi_done;
+	cmd->scsi_done = internal_done;
+	cmd->SCp.Status = 0;
+	last_scsi_command(host_index)[ldn] = IM_ABORT_IMM_CMD;
+	last_scsi_type(host_index)[ldn] = IM_IMM_CMD;
+	imm_command = inl(IM_CMD_REG(host_index));
+	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
+	imm_command |= (unsigned long) (IM_ABORT_IMM_CMD);
+	/* must wait for attention reg not busy */
+	/* FIXME - timeout, politeness */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+	}
+	/* write registers and enable system interrupts */
+	outl(imm_command, IM_CMD_REG(host_index));
+	outb(IM_IMM_CMD | ldn, IM_ATTN_REG(host_index));
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort queued to adapter...\n");
+#endif
+	spin_unlock_irq(shpnt->host_lock);
+	while (!cmd->SCp.Status)
+		yield();
+	spin_lock_irq(shpnt->host_lock);
+	cmd->scsi_done = saved_done;
+#ifdef IM_DEBUG_PROBE
+	printk("IBM MCA SCSI: Abort returned with adapter response...\n");
+#endif
+
+	/*if abort went well, call saved done, then return success or error */
+	if (cmd->result == (DID_ABORT << 16)) 
+	{
+		cmd->result |= DID_ABORT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+		printk("IBM MCA SCSI: Abort finished with success.\n");
+#endif
+		return SUCCESS;
+	} else {
+		cmd->result |= DID_NO_CONNECT << 16;
+		if (cmd->scsi_done)
+			(cmd->scsi_done) (cmd);
+		ld(host_index)[ldn].cmd = NULL;
+#ifdef IM_DEBUG_PROBE
+		printk("IBM MCA SCSI: Abort failed.\n");
+#endif
+		return FAILED;
+	}
+}
+
+static int ibmmca_host_reset(Scsi_Cmnd * cmd)
+{
+	struct Scsi_Host *shpnt;
+	Scsi_Cmnd *cmd_aid;
+	int ticks, i;
+	int host_index;
+	unsigned long imm_command;
+
+	if (cmd == NULL)
+		BUG();
+
+	ticks = IM_RESET_DELAY * HZ;
+	shpnt = cmd->device->host;
+	/* search for the right hostadapter */
+	for (host_index = 0; hosts[host_index] && hosts[host_index]->host_no != shpnt->host_no; host_index++);
+
+	if (!hosts[host_index])	/* invalid hostadapter descriptor address */
+		return FAILED;
+
+	if (local_checking_phase_flag(host_index)) {
+		printk(KERN_WARNING "IBM MCA SCSI: unable to reset while checking devices.\n");
+		return FAILED;
+	}
+
+	/* issue reset immediate command to subsystem, and wait for interrupt */
+	printk("IBM MCA SCSI: resetting all devices.\n");
+	reset_status(host_index) = IM_RESET_IN_PROGRESS;
+	last_scsi_command(host_index)[0xf] = IM_RESET_IMM_CMD;
+	last_scsi_type(host_index)[0xf] = IM_IMM_CMD;
+	imm_command = inl(IM_CMD_REG(host_index));
+	imm_command &= (unsigned long) (0xffff0000);	/* mask reserved stuff */
+	imm_command |= (unsigned long) (IM_RESET_IMM_CMD);
+	/* must wait for attention reg not busy */
+	while (1) {
+		if (!(inb(IM_STAT_REG(host_index)) & IM_BUSY))
+			break;
+		spin_unlock_irq(shpnt->host_lock);
+		yield();
+		spin_lock_irq(shpnt->host_lock);
+	}
+	/*write registers and enable system interrupts */
+	outl(imm_command, IM_CMD_REG(host_index));
+	outb(IM_IMM_CMD | 0xf, IM_ATTN_REG(host_index));
+	/* wait for interrupt finished or intr_stat register to be set, as the
+	 * interrupt will not be executed, while we are in here! */
+	 
+	/* FIXME: This is really really icky we so want a sleeping version of this ! */
+	while (reset_status(host_index) == IM_RESET_IN_PROGRESS && --ticks && ((inb(IM_INTR_REG(host_index)) & 0x8f) != 0x8f)) {
+		udelay((1 + 999 / HZ) * 1000);
+		barrier();
+	}
+	/* if reset did not complete, just return an error */
+	if (!ticks) {
+		printk(KERN_ERR "IBM MCA SCSI: reset did not complete within %d seconds.\n", IM_RESET_DELAY);
+		reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		return FAILED;
+	}
+
+	if ((inb(IM_INTR_REG(host_index)) & 0x8f) == 0x8f) {
+		/* analysis done by this routine and not by the intr-routine */
+		if (inb(IM_INTR_REG(host_index)) == 0xaf)
+			reset_status(host_index) = IM_RESET_FINISHED_OK_NO_INT;
+		else if (inb(IM_INTR_REG(host_index)) == 0xcf)
+			reset_status(host_index) = IM_RESET_FINISHED_FAIL;
+		else		/* failed, 4get it */
+			reset_status(host_index) = IM_RESET_NOT_IN_PROGRESS_NO_INT;
+		outb(IM_EOI | 0xf, IM_ATTN_REG(host_index));
+	}
+
+	/* if reset failed, just return an error */
+	if (reset_status(host_index) == IM_RESET_FINISHED_FAIL) {
+		printk(KERN_ERR "IBM MCA SCSI: reset failed.\n");
+		return FAILED;
+	}
+
+	/* so reset finished ok - call outstanding done's, and return success */
+	printk(KERN_INFO "IBM MCA SCSI: Reset successfully completed.\n");
+	for (i = 0; i < MAX_LOG_DEV; i++) {
+		cmd_aid = ld(host_index)[i].cmd;
+		if (cmd_aid && cmd_aid->scsi_done) {
+			ld(host_index)[i].cmd = NULL;
+			cmd_aid->result = DID_RESET << 16;
+		}
+	}
+	return SUCCESS;
+}
+
+static int ibmmca_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *info)
+{
+	int size = capacity;
+	info[0] = 64;
+	info[1] = 32;
+	info[2] = size / (info[0] * info[1]);
+	if (info[2] >= 1024) {
+		info[0] = 128;
+		info[1] = 63;
+		info[2] = size / (info[0] * info[1]);
+		if (info[2] >= 1024) {
+			info[0] = 255;
+			info[1] = 63;
+			info[2] = size / (info[0] * info[1]);
+			if (info[2] >= 1024)
+				info[2] = 1023;
+		}
+	}
+	return 0;
+}
+
+/* calculate percentage of total accesses on a ldn */
+static int ldn_access_load(int host_index, int ldn)
+{
+	if (IBM_DS(host_index).total_accesses == 0)
+		return (0);
+	if (IBM_DS(host_index).ldn_access[ldn] == 0)
+		return (0);
+	return (IBM_DS(host_index).ldn_access[ldn] * 100) / IBM_DS(host_index).total_accesses;
+}
+
+/* calculate total amount of r/w-accesses */
+static int ldn_access_total_read_write(int host_index)
+{
+	int a;
+	int i;
+
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_read_access[i] + IBM_DS(host_index).ldn_write_access[i];
+	return (a);
+}
+
+static int ldn_access_total_inquiry(int host_index)
+{
+	int a;
+	int i;
+
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_inquiry_access[i];
+	return (a);
+}
+
+static int ldn_access_total_modeselect(int host_index)
+{
+	int a;
+	int i;
+
+	a = 0;
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		a += IBM_DS(host_index).ldn_modeselect_access[i];
+	return (a);
+}
+
+/* routine to display info in the proc-fs-structure (a deluxe feature) */
+static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	int len = 0;
+	int i, id, lun, host_index;
+	unsigned long flags;
+	int max_pun;
+
+	for (i = 0; hosts[i] && hosts[i] != shpnt; i++);
+	
+	spin_lock_irqsave(hosts[i]->host_lock, flags);	/* Check it */
+	host_index = i;
+	if (!shpnt) {
+		len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n",
+				shpnt->host_no);
+		return len;
+	}
+	max_pun = subsystem_maxid(host_index);
+
+	len += sprintf(buffer + len, "\n             IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n", IBMMCA_SCSI_DRIVER_VERSION);
+	len += sprintf(buffer + len, " SCSI Access-Statistics:\n");
+	len += sprintf(buffer + len, "               Device Scanning Order....: %s\n", (ibm_ansi_order) ? "IBM/ANSI" : "New Industry Standard");
+#ifdef CONFIG_SCSI_MULTI_LUN
+	len += sprintf(buffer + len, "               Multiple LUN probing.....: Yes\n");
+#else
+	len += sprintf(buffer + len, "               Multiple LUN probing.....: No\n");
+#endif
+	len += sprintf(buffer + len, "               This Hostnumber..........: %d\n", shpnt->host_no);
+	len += sprintf(buffer + len, "               Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index)));
+	len += sprintf(buffer + len, "               (Shared) IRQ.............: %d\n", IM_IRQ);
+	len += sprintf(buffer + len, "               Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts);
+	len += sprintf(buffer + len, "               Total SCSI Accesses......: %d\n", IBM_DS(host_index).total_accesses);
+	len += sprintf(buffer + len, "               Total short SCBs.........: %d\n", IBM_DS(host_index).scbs);
+	len += sprintf(buffer + len, "               Total long SCBs..........: %d\n", IBM_DS(host_index).long_scbs);
+	len += sprintf(buffer + len, "                 Total SCSI READ/WRITE..: %d\n", ldn_access_total_read_write(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI Inquiries...: %d\n", ldn_access_total_inquiry(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI Modeselects.: %d\n", ldn_access_total_modeselect(host_index));
+	len += sprintf(buffer + len, "                 Total SCSI other cmds..: %d\n", IBM_DS(host_index).total_accesses - ldn_access_total_read_write(host_index)
+		       - ldn_access_total_modeselect(host_index)
+		       - ldn_access_total_inquiry(host_index));
+	len += sprintf(buffer + len, "               Total SCSI command fails.: %d\n\n", IBM_DS(host_index).total_errors);
+	len += sprintf(buffer + len, " Logical-Device-Number (LDN) Access-Statistics:\n");
+	len += sprintf(buffer + len, "         LDN | Accesses [%%] |   READ    |   WRITE   | ASSIGNMENTS\n");
+	len += sprintf(buffer + len, "        -----|--------------|-----------|-----------|--------------\n");
+	for (i = 0; i <= MAX_LOG_DEV; i++)
+		len += sprintf(buffer + len, "         %2X  |    %3d       |  %8d |  %8d | %8d\n", i, ldn_access_load(host_index, i), IBM_DS(host_index).ldn_read_access[i], IBM_DS(host_index).ldn_write_access[i], IBM_DS(host_index).ldn_assignments[i]);
+	len += sprintf(buffer + len, "        -----------------------------------------------------------\n\n");
+	len += sprintf(buffer + len, " Dynamical-LDN-Assignment-Statistics:\n");
+	len += sprintf(buffer + len, "               Number of physical SCSI-devices..: %d (+ Adapter)\n", IBM_DS(host_index).total_scsi_devices);
+	len += sprintf(buffer + len, "               Dynamical Assignment necessary...: %s\n", IBM_DS(host_index).dyn_flag ? "Yes" : "No ");
+	len += sprintf(buffer + len, "               Next LDN to be assigned..........: 0x%x\n", next_ldn(host_index));
+	len += sprintf(buffer + len, "               Dynamical assignments done yet...: %d\n", IBM_DS(host_index).dynamical_assignments);
+	len += sprintf(buffer + len, "\n Current SCSI-Device-Mapping:\n");
+	len += sprintf(buffer + len, "        Physical SCSI-Device Map               Logical SCSI-Device Map\n");
+	len += sprintf(buffer + len, "    ID\\LUN  0  1  2  3  4  5  6  7       ID\\LUN  0  1  2  3  4  5  6  7\n");
+	for (id = 0; id < max_pun; id++) {
+		len += sprintf(buffer + len, "    %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			len += sprintf(buffer + len, "%2s ", ti_p(get_scsi(host_index)[id][lun]));
+		len += sprintf(buffer + len, "      %2d     ", id);
+		for (lun = 0; lun < 8; lun++)
+			len += sprintf(buffer + len, "%2s ", ti_l(get_ldn(host_index)[id][lun]));
+		len += sprintf(buffer + len, "\n");
+	}
+
+	len += sprintf(buffer + len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
+	len += sprintf(buffer + len, " R = CD-ROM, S = Scanner, M = MO-Drive, C = Medium-Changer, + = unprovided LUN,\n");
+	len += sprintf(buffer + len, " - = nothing found, nothing assigned or unprobed LUN)\n\n");
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	spin_unlock_irqrestore(shpnt->host_lock, flags);
+	return len;
+}
+
+static int option_setup(char *str)
+{
+	int ints[IM_MAX_HOSTS];
+	char *cur = str;
+	int i = 1;
+
+	while (cur && isdigit(*cur) && i <= IM_MAX_HOSTS) {
+		ints[i++] = simple_strtoul(cur, NULL, 0);
+		if ((cur = strchr(cur, ',')) != NULL)
+			cur++;
+	}
+	ints[0] = i - 1;
+	internal_ibmmca_scsi_setup(cur, ints);
+	return 0;
+}
+
+__setup("ibmmcascsi=", option_setup);
+
+static Scsi_Host_Template driver_template = {
+          .proc_name      = "ibmmca",
+	  .proc_info	  = ibmmca_proc_info,
+          .name           = "IBM SCSI-Subsystem",
+          .detect         = ibmmca_detect,
+          .release        = ibmmca_release,
+          .queuecommand   = ibmmca_queuecommand,
+	  .eh_abort_handler = ibmmca_abort,
+	  .eh_host_reset_handler = ibmmca_host_reset,
+          .bios_param     = ibmmca_biosparam,
+          .can_queue      = 16,
+          .this_id        = 7,
+          .sg_tablesize   = 16,
+          .cmd_per_lun    = 1,
+          .use_clustering = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
new file mode 100644
index 0000000..6d68f60
--- /dev/null
+++ b/drivers/scsi/ibmmca.h
@@ -0,0 +1,21 @@
+/*
+ * Low Level Driver for the IBM Microchannel SCSI Subsystem
+ * (Headerfile, see Documentation/scsi/ibmmca.txt for description of the
+ * IBM MCA SCSI-driver.
+ * For use under the GNU General Public License within the Linux-kernel project.
+ * This include file works only correctly with kernel 2.4.0 or higher!!! */
+
+#ifndef _IBMMCA_H
+#define _IBMMCA_H
+
+/* Common forward declarations for all Linux-versions: */
+
+/* Interfaces to the midlevel Linux SCSI driver */
+static int ibmmca_detect (Scsi_Host_Template *);
+static int ibmmca_release (struct Scsi_Host *);
+static int ibmmca_queuecommand (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+static int ibmmca_abort (Scsi_Cmnd *);
+static int ibmmca_host_reset (Scsi_Cmnd *);
+static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
+
+#endif /* _IBMMCA_H */
diff --git a/drivers/scsi/ibmvscsi/Makefile b/drivers/scsi/ibmvscsi/Makefile
new file mode 100644
index 0000000..4e247b6
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_SCSI_IBMVSCSI)	+= ibmvscsic.o
+
+ibmvscsic-y			+= ibmvscsi.o
+ibmvscsic-$(CONFIG_PPC_ISERIES)	+= iseries_vscsi.o 
+ibmvscsic-$(CONFIG_PPC_PSERIES)	+= rpa_vscsi.o 
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
new file mode 100644
index 0000000..e89f76e
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -0,0 +1,1473 @@
+/* ------------------------------------------------------------
+ * ibmvscsi.c
+ * (C) Copyright IBM Corporation 1994, 2004
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ * ------------------------------------------------------------
+ * Emulation of a SCSI host adapter for Virtual I/O devices
+ *
+ * This driver supports the SCSI adapter implemented by the IBM
+ * Power5 firmware.  That SCSI adapter is not a physical adapter,
+ * but allows Linux SCSI peripheral drivers to directly
+ * access devices in another logical partition on the physical system.
+ *
+ * The virtual adapter(s) are present in the open firmware device
+ * tree just like real adapters.
+ *
+ * One of the capabilities provided on these systems is the ability
+ * to DMA between partitions.  The architecture states that for VSCSI,
+ * the server side is allowed to DMA to and from the client.  The client
+ * is never trusted to DMA to or from the server directly.
+ *
+ * Messages are sent between partitions on a "Command/Response Queue" 
+ * (CRQ), which is just a buffer of 16 byte entries in the receiver's 
+ * Senders cannot access the buffer directly, but send messages by
+ * making a hypervisor call and passing in the 16 bytes.  The hypervisor
+ * puts the message in the next 16 byte space in round-robbin fashion,
+ * turns on the high order bit of the message (the valid bit), and 
+ * generates an interrupt to the receiver (if interrupts are turned on.) 
+ * The receiver just turns off the valid bit when they have copied out
+ * the message.
+ *
+ * The VSCSI client builds a SCSI Remote Protocol (SRP) Information Unit
+ * (IU) (as defined in the T10 standard available at www.t10.org), gets 
+ * a DMA address for the message, and sends it to the server as the
+ * payload of a CRQ message.  The server DMAs the SRP IU and processes it,
+ * including doing any additional data transfers.  When it is done, it
+ * DMAs the SRP response back to the same address as the request came from,
+ * and sends a CRQ message back to inform the client that the request has
+ * completed.
+ *
+ * Note that some of the underlying infrastructure is different between
+ * machines conforming to the "RS/6000 Platform Architecture" (RPA) and
+ * the older iSeries hypervisor models.  To support both, some low level
+ * routines have been broken out into rpa_vscsi.c and iseries_vscsi.c.
+ * The Makefile should pick one, not two, not zero, of these.
+ *
+ * TODO: This is currently pretty tied to the IBM i/pSeries hypervisor
+ * interfaces.  It would be really nice to abstract this above an RDMA
+ * layer.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/dma-mapping.h>
+#include <linux/delay.h>
+#include <asm/vio.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include "ibmvscsi.h"
+
+/* The values below are somewhat arbitrary default values, but 
+ * OS/400 will use 3 busses (disks, CDs, tapes, I think.)
+ * Note that there are 3 bits of channel value, 6 bits of id, and
+ * 5 bits of LUN.
+ */
+static int max_id = 64;
+static int max_channel = 3;
+static int init_timeout = 5;
+static int max_requests = 50;
+
+#define IBMVSCSI_VERSION "1.5.5"
+
+MODULE_DESCRIPTION("IBM Virtual SCSI");
+MODULE_AUTHOR("Dave Boutcher");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IBMVSCSI_VERSION);
+
+module_param_named(max_id, max_id, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_id, "Largest ID value for each channel");
+module_param_named(max_channel, max_channel, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_channel, "Largest channel value");
+module_param_named(init_timeout, init_timeout, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(init_timeout, "Initialization timeout in seconds");
+module_param_named(max_requests, max_requests, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(max_requests, "Maximum requests for this adapter");
+
+/* ------------------------------------------------------------
+ * Routines for the event pool and event structs
+ */
+/**
+ * initialize_event_pool: - Allocates and initializes the event pool for a host
+ * @pool:	event_pool to be initialized
+ * @size:	Number of events in pool
+ * @hostdata:	ibmvscsi_host_data who owns the event pool
+ *
+ * Returns zero on success.
+*/
+static int initialize_event_pool(struct event_pool *pool,
+				 int size, struct ibmvscsi_host_data *hostdata)
+{
+	int i;
+
+	pool->size = size;
+	pool->next = 0;
+	pool->events = kmalloc(pool->size * sizeof(*pool->events), GFP_KERNEL);
+	if (!pool->events)
+		return -ENOMEM;
+	memset(pool->events, 0x00, pool->size * sizeof(*pool->events));
+
+	pool->iu_storage =
+	    dma_alloc_coherent(hostdata->dev,
+			       pool->size * sizeof(*pool->iu_storage),
+			       &pool->iu_token, 0);
+	if (!pool->iu_storage) {
+		kfree(pool->events);
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < pool->size; ++i) {
+		struct srp_event_struct *evt = &pool->events[i];
+		memset(&evt->crq, 0x00, sizeof(evt->crq));
+		atomic_set(&evt->free, 1);
+		evt->crq.valid = 0x80;
+		evt->crq.IU_length = sizeof(*evt->xfer_iu);
+		evt->crq.IU_data_ptr = pool->iu_token + 
+			sizeof(*evt->xfer_iu) * i;
+		evt->xfer_iu = pool->iu_storage + i;
+		evt->hostdata = hostdata;
+	}
+
+	return 0;
+}
+
+/**
+ * release_event_pool: - Frees memory of an event pool of a host
+ * @pool:	event_pool to be released
+ * @hostdata:	ibmvscsi_host_data who owns the even pool
+ *
+ * Returns zero on success.
+*/
+static void release_event_pool(struct event_pool *pool,
+			       struct ibmvscsi_host_data *hostdata)
+{
+	int i, in_use = 0;
+	for (i = 0; i < pool->size; ++i)
+		if (atomic_read(&pool->events[i].free) != 1)
+			++in_use;
+	if (in_use)
+		printk(KERN_WARNING
+		       "ibmvscsi: releasing event pool with %d "
+		       "events still in use?\n", in_use);
+	kfree(pool->events);
+	dma_free_coherent(hostdata->dev,
+			  pool->size * sizeof(*pool->iu_storage),
+			  pool->iu_storage, pool->iu_token);
+}
+
+/**
+ * valid_event_struct: - Determines if event is valid.
+ * @pool:	event_pool that contains the event
+ * @evt:	srp_event_struct to be checked for validity
+ *
+ * Returns zero if event is invalid, one otherwise.
+*/
+static int valid_event_struct(struct event_pool *pool,
+				struct srp_event_struct *evt)
+{
+	int index = evt - pool->events;
+	if (index < 0 || index >= pool->size)	/* outside of bounds */
+		return 0;
+	if (evt != pool->events + index)	/* unaligned */
+		return 0;
+	return 1;
+}
+
+/**
+ * ibmvscsi_free-event_struct: - Changes status of event to "free"
+ * @pool:	event_pool that contains the event
+ * @evt:	srp_event_struct to be modified
+ *
+*/
+static void free_event_struct(struct event_pool *pool,
+				       struct srp_event_struct *evt)
+{
+	if (!valid_event_struct(pool, evt)) {
+		printk(KERN_ERR
+		       "ibmvscsi: Freeing invalid event_struct %p "
+		       "(not in pool %p)\n", evt, pool->events);
+		return;
+	}
+	if (atomic_inc_return(&evt->free) != 1) {
+		printk(KERN_ERR
+		       "ibmvscsi: Freeing event_struct %p "
+		       "which is not in use!\n", evt);
+		return;
+	}
+}
+
+/**
+ * get_evt_struct: - Gets the next free event in pool
+ * @pool:	event_pool that contains the events to be searched
+ *
+ * Returns the next event in "free" state, and NULL if none are free.
+ * Note that no synchronization is done here, we assume the host_lock
+ * will syncrhonze things.
+*/
+static struct srp_event_struct *get_event_struct(struct event_pool *pool)
+{
+	int i;
+	int poolsize = pool->size;
+	int offset = pool->next;
+
+	for (i = 0; i < poolsize; i++) {
+		offset = (offset + 1) % poolsize;
+		if (!atomic_dec_if_positive(&pool->events[offset].free)) {
+			pool->next = offset;
+			return &pool->events[offset];
+		}
+	}
+
+	printk(KERN_ERR "ibmvscsi: found no event struct in pool!\n");
+	return NULL;
+}
+
+/**
+ * init_event_struct: Initialize fields in an event struct that are always 
+ *                    required.
+ * @evt:        The event
+ * @done:       Routine to call when the event is responded to
+ * @format:     SRP or MAD format
+ * @timeout:    timeout value set in the CRQ
+ */
+static void init_event_struct(struct srp_event_struct *evt_struct,
+			      void (*done) (struct srp_event_struct *),
+			      u8 format,
+			      int timeout)
+{
+	evt_struct->cmnd = NULL;
+	evt_struct->cmnd_done = NULL;
+	evt_struct->sync_srp = NULL;
+	evt_struct->crq.format = format;
+	evt_struct->crq.timeout = timeout;
+	evt_struct->done = done;
+}
+
+/* ------------------------------------------------------------
+ * Routines for receiving SCSI responses from the hosting partition
+ */
+
+/**
+ * set_srp_direction: Set the fields in the srp related to data
+ *     direction and number of buffers based on the direction in
+ *     the scsi_cmnd and the number of buffers
+ */
+static void set_srp_direction(struct scsi_cmnd *cmd,
+			      struct srp_cmd *srp_cmd, 
+			      int numbuf)
+{
+	if (numbuf == 0)
+		return;
+	
+	if (numbuf == 1) {
+		if (cmd->sc_data_direction == DMA_TO_DEVICE)
+			srp_cmd->data_out_format = SRP_DIRECT_BUFFER;
+		else 
+			srp_cmd->data_in_format = SRP_DIRECT_BUFFER;
+	} else {
+		if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+			srp_cmd->data_out_format = SRP_INDIRECT_BUFFER;
+			srp_cmd->data_out_count = numbuf;
+		} else {
+			srp_cmd->data_in_format = SRP_INDIRECT_BUFFER;
+			srp_cmd->data_in_count = numbuf;
+		}
+	}
+}
+
+/**
+ * unmap_cmd_data: - Unmap data pointed in srp_cmd based on the format
+ * @cmd:	srp_cmd whose additional_data member will be unmapped
+ * @dev:	device for which the memory is mapped
+ *
+*/
+static void unmap_cmd_data(struct srp_cmd *cmd, struct device *dev)
+{
+	int i;
+
+	if ((cmd->data_out_format == SRP_NO_BUFFER) &&
+	    (cmd->data_in_format == SRP_NO_BUFFER))
+		return;
+	else if ((cmd->data_out_format == SRP_DIRECT_BUFFER) ||
+		 (cmd->data_in_format == SRP_DIRECT_BUFFER)) {
+		struct memory_descriptor *data =
+			(struct memory_descriptor *)cmd->additional_data;
+		dma_unmap_single(dev, data->virtual_address, data->length,
+				 DMA_BIDIRECTIONAL);
+	} else {
+		struct indirect_descriptor *indirect =
+			(struct indirect_descriptor *)cmd->additional_data;
+		int num_mapped = indirect->head.length / 
+			sizeof(indirect->list[0]);
+		for (i = 0; i < num_mapped; ++i) {
+			struct memory_descriptor *data = &indirect->list[i];
+			dma_unmap_single(dev,
+					 data->virtual_address,
+					 data->length, DMA_BIDIRECTIONAL);
+		}
+	}
+}
+
+/**
+ * map_sg_data: - Maps dma for a scatterlist and initializes decriptor fields
+ * @cmd:	Scsi_Cmnd with the scatterlist
+ * @srp_cmd:	srp_cmd that contains the memory descriptor
+ * @dev:	device for which to map dma memory
+ *
+ * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
+ * Returns 1 on success.
+*/
+static int map_sg_data(struct scsi_cmnd *cmd,
+		       struct srp_cmd *srp_cmd, struct device *dev)
+{
+
+	int i, sg_mapped;
+	u64 total_length = 0;
+	struct scatterlist *sg = cmd->request_buffer;
+	struct memory_descriptor *data =
+	    (struct memory_descriptor *)srp_cmd->additional_data;
+	struct indirect_descriptor *indirect =
+	    (struct indirect_descriptor *)data;
+
+	sg_mapped = dma_map_sg(dev, sg, cmd->use_sg, DMA_BIDIRECTIONAL);
+
+	if (sg_mapped == 0)
+		return 0;
+
+	set_srp_direction(cmd, srp_cmd, sg_mapped);
+
+	/* special case; we can use a single direct descriptor */
+	if (sg_mapped == 1) {
+		data->virtual_address = sg_dma_address(&sg[0]);
+		data->length = sg_dma_len(&sg[0]);
+		data->memory_handle = 0;
+		return 1;
+	}
+
+	if (sg_mapped > MAX_INDIRECT_BUFS) {
+		printk(KERN_ERR
+		       "ibmvscsi: More than %d mapped sg entries, got %d\n",
+		       MAX_INDIRECT_BUFS, sg_mapped);
+		return 0;
+	}
+
+	indirect->head.virtual_address = 0;
+	indirect->head.length = sg_mapped * sizeof(indirect->list[0]);
+	indirect->head.memory_handle = 0;
+	for (i = 0; i < sg_mapped; ++i) {
+		struct memory_descriptor *descr = &indirect->list[i];
+		struct scatterlist *sg_entry = &sg[i];
+		descr->virtual_address = sg_dma_address(sg_entry);
+		descr->length = sg_dma_len(sg_entry);
+		descr->memory_handle = 0;
+		total_length += sg_dma_len(sg_entry);
+	}
+	indirect->total_length = total_length;
+
+	return 1;
+}
+
+/**
+ * map_single_data: - Maps memory and initializes memory decriptor fields
+ * @cmd:	struct scsi_cmnd with the memory to be mapped
+ * @srp_cmd:	srp_cmd that contains the memory descriptor
+ * @dev:	device for which to map dma memory
+ *
+ * Called by map_data_for_srp_cmd() when building srp cmd from scsi cmd.
+ * Returns 1 on success.
+*/
+static int map_single_data(struct scsi_cmnd *cmd,
+			   struct srp_cmd *srp_cmd, struct device *dev)
+{
+	struct memory_descriptor *data =
+	    (struct memory_descriptor *)srp_cmd->additional_data;
+
+	data->virtual_address =
+		dma_map_single(dev, cmd->request_buffer,
+			       cmd->request_bufflen,
+			       DMA_BIDIRECTIONAL);
+	if (dma_mapping_error(data->virtual_address)) {
+		printk(KERN_ERR
+		       "ibmvscsi: Unable to map request_buffer for command!\n");
+		return 0;
+	}
+	data->length = cmd->request_bufflen;
+	data->memory_handle = 0;
+
+	set_srp_direction(cmd, srp_cmd, 1);
+
+	return 1;
+}
+
+/**
+ * map_data_for_srp_cmd: - Calls functions to map data for srp cmds
+ * @cmd:	struct scsi_cmnd with the memory to be mapped
+ * @srp_cmd:	srp_cmd that contains the memory descriptor
+ * @dev:	dma device for which to map dma memory
+ *
+ * Called by scsi_cmd_to_srp_cmd() when converting scsi cmds to srp cmds 
+ * Returns 1 on success.
+*/
+static int map_data_for_srp_cmd(struct scsi_cmnd *cmd,
+				struct srp_cmd *srp_cmd, struct device *dev)
+{
+	switch (cmd->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+	case DMA_TO_DEVICE:
+		break;
+	case DMA_NONE:
+		return 1;
+	case DMA_BIDIRECTIONAL:
+		printk(KERN_ERR
+		       "ibmvscsi: Can't map DMA_BIDIRECTIONAL to read/write\n");
+		return 0;
+	default:
+		printk(KERN_ERR
+		       "ibmvscsi: Unknown data direction 0x%02x; can't map!\n",
+		       cmd->sc_data_direction);
+		return 0;
+	}
+
+	if (!cmd->request_buffer)
+		return 1;
+	if (cmd->use_sg)
+		return map_sg_data(cmd, srp_cmd, dev);
+	return map_single_data(cmd, srp_cmd, dev);
+}
+
+/* ------------------------------------------------------------
+ * Routines for sending and receiving SRPs
+ */
+/**
+ * ibmvscsi_send_srp_event: - Transforms event to u64 array and calls send_crq()
+ * @evt_struct:	evt_struct to be sent
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+ * Returns the value returned from ibmvscsi_send_crq(). (Zero for success)
+ * Note that this routine assumes that host_lock is held for synchronization
+*/
+static int ibmvscsi_send_srp_event(struct srp_event_struct *evt_struct,
+				   struct ibmvscsi_host_data *hostdata)
+{
+	struct scsi_cmnd *cmnd;
+	u64 *crq_as_u64 = (u64 *) &evt_struct->crq;
+	int rc;
+
+	/* If we have exhausted our request limit, just fail this request.
+	 * Note that there are rare cases involving driver generated requests 
+	 * (such as task management requests) that the mid layer may think we
+	 * can handle more requests (can_queue) when we actually can't
+	 */
+	if ((evt_struct->crq.format == VIOSRP_SRP_FORMAT) &&
+	    (atomic_dec_if_positive(&hostdata->request_limit) < 0)) {
+		/* See if the adapter is disabled */
+		if (atomic_read(&hostdata->request_limit) < 0)
+			goto send_error;
+	
+		printk(KERN_WARNING 
+		       "ibmvscsi: Warning, request_limit exceeded\n");
+		unmap_cmd_data(&evt_struct->iu.srp.cmd,
+			       hostdata->dev);
+		free_event_struct(&hostdata->pool, evt_struct);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	/* Copy the IU into the transfer area */
+	*evt_struct->xfer_iu = evt_struct->iu;
+	evt_struct->xfer_iu->srp.generic.tag = (u64)evt_struct;
+
+	/* Add this to the sent list.  We need to do this 
+	 * before we actually send 
+	 * in case it comes back REALLY fast
+	 */
+	list_add_tail(&evt_struct->list, &hostdata->sent);
+
+	if ((rc =
+	     ibmvscsi_send_crq(hostdata, crq_as_u64[0], crq_as_u64[1])) != 0) {
+		list_del(&evt_struct->list);
+
+		printk(KERN_ERR "ibmvscsi: failed to send event struct rc %d\n",
+		       rc);
+		goto send_error;
+	}
+
+	return 0;
+
+ send_error:
+	unmap_cmd_data(&evt_struct->iu.srp.cmd, hostdata->dev);
+
+	if ((cmnd = evt_struct->cmnd) != NULL) {
+		cmnd->result = DID_ERROR << 16;
+		evt_struct->cmnd_done(cmnd);
+	} else if (evt_struct->done)
+		evt_struct->done(evt_struct);
+	
+	free_event_struct(&hostdata->pool, evt_struct);
+	return 0;
+}
+
+/**
+ * handle_cmd_rsp: -  Handle responses from commands
+ * @evt_struct:	srp_event_struct to be handled
+ *
+ * Used as a callback by when sending scsi cmds.
+ * Gets called by ibmvscsi_handle_crq()
+*/
+static void handle_cmd_rsp(struct srp_event_struct *evt_struct)
+{
+	struct srp_rsp *rsp = &evt_struct->xfer_iu->srp.rsp;
+	struct scsi_cmnd *cmnd = evt_struct->cmnd;
+
+	if (unlikely(rsp->type != SRP_RSP_TYPE)) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING 
+			       "ibmvscsi: bad SRP RSP type %d\n",
+			       rsp->type);
+	}
+	
+	if (cmnd) {
+		cmnd->result = rsp->status;
+		if (((cmnd->result >> 1) & 0x1f) == CHECK_CONDITION)
+			memcpy(cmnd->sense_buffer,
+			       rsp->sense_and_response_data,
+			       rsp->sense_data_list_length);
+		unmap_cmd_data(&evt_struct->iu.srp.cmd, 
+			       evt_struct->hostdata->dev);
+
+		if (rsp->doover)
+			cmnd->resid = rsp->data_out_residual_count;
+		else if (rsp->diover)
+			cmnd->resid = rsp->data_in_residual_count;
+	}
+
+	if (evt_struct->cmnd_done)
+		evt_struct->cmnd_done(cmnd);
+}
+
+/**
+ * lun_from_dev: - Returns the lun of the scsi device
+ * @dev:	struct scsi_device
+ *
+*/
+static inline u16 lun_from_dev(struct scsi_device *dev)
+{
+	return (0x2 << 14) | (dev->id << 8) | (dev->channel << 5) | dev->lun;
+}
+
+/**
+ * ibmvscsi_queue: - The queuecommand function of the scsi template 
+ * @cmd:	struct scsi_cmnd to be executed
+ * @done:	Callback function to be called when cmd is completed
+*/
+static int ibmvscsi_queuecommand(struct scsi_cmnd *cmnd,
+				 void (*done) (struct scsi_cmnd *))
+{
+	struct srp_cmd *srp_cmd;
+	struct srp_event_struct *evt_struct;
+	struct ibmvscsi_host_data *hostdata =
+		(struct ibmvscsi_host_data *)&cmnd->device->host->hostdata;
+	u16 lun = lun_from_dev(cmnd->device);
+
+	evt_struct = get_event_struct(&hostdata->pool);
+	if (!evt_struct)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	init_event_struct(evt_struct,
+			  handle_cmd_rsp,
+			  VIOSRP_SRP_FORMAT,
+			  cmnd->timeout);
+
+	evt_struct->cmnd = cmnd;
+	evt_struct->cmnd_done = done;
+
+	/* Set up the actual SRP IU */
+	srp_cmd = &evt_struct->iu.srp.cmd;
+	memset(srp_cmd, 0x00, sizeof(*srp_cmd));
+	srp_cmd->type = SRP_CMD_TYPE;
+	memcpy(srp_cmd->cdb, cmnd->cmnd, sizeof(cmnd->cmnd));
+	srp_cmd->lun = ((u64) lun) << 48;
+
+	if (!map_data_for_srp_cmd(cmnd, srp_cmd, hostdata->dev)) {
+		printk(KERN_ERR "ibmvscsi: couldn't convert cmd to srp_cmd\n");
+		free_event_struct(&hostdata->pool, evt_struct);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	/* Fix up dma address of the buffer itself */
+	if ((srp_cmd->data_out_format == SRP_INDIRECT_BUFFER) ||
+	    (srp_cmd->data_in_format == SRP_INDIRECT_BUFFER)) {
+		struct indirect_descriptor *indirect =
+		    (struct indirect_descriptor *)srp_cmd->additional_data;
+		indirect->head.virtual_address = evt_struct->crq.IU_data_ptr +
+		    offsetof(struct srp_cmd, additional_data) +
+		    offsetof(struct indirect_descriptor, list);
+	}
+
+	return ibmvscsi_send_srp_event(evt_struct, hostdata);
+}
+
+/* ------------------------------------------------------------
+ * Routines for driver initialization
+ */
+/**
+ * adapter_info_rsp: - Handle response to MAD adapter info request
+ * @evt_struct:	srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending adapter_info. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void adapter_info_rsp(struct srp_event_struct *evt_struct)
+{
+	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+	dma_unmap_single(hostdata->dev,
+			 evt_struct->iu.mad.adapter_info.buffer,
+			 evt_struct->iu.mad.adapter_info.common.length,
+			 DMA_BIDIRECTIONAL);
+
+	if (evt_struct->xfer_iu->mad.adapter_info.common.status) {
+		printk("ibmvscsi: error %d getting adapter info\n",
+		       evt_struct->xfer_iu->mad.adapter_info.common.status);
+	} else {
+		printk("ibmvscsi: host srp version: %s, "
+		       "host partition %s (%d), OS %d, max io %u\n",
+		       hostdata->madapter_info.srp_version,
+		       hostdata->madapter_info.partition_name,
+		       hostdata->madapter_info.partition_number,
+		       hostdata->madapter_info.os_type,
+		       hostdata->madapter_info.port_max_txu[0]);
+		
+		if (hostdata->madapter_info.port_max_txu[0]) 
+			hostdata->host->max_sectors = 
+				hostdata->madapter_info.port_max_txu[0] >> 9;
+	}
+}
+
+/**
+ * send_mad_adapter_info: - Sends the mad adapter info request
+ *      and stores the result so it can be retrieved with
+ *      sysfs.  We COULD consider causing a failure if the
+ *      returned SRP version doesn't match ours.
+ * @hostdata:	ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static void send_mad_adapter_info(struct ibmvscsi_host_data *hostdata)
+{
+	struct viosrp_adapter_info *req;
+	struct srp_event_struct *evt_struct;
+	
+	memset(&hostdata->madapter_info, 0x00, sizeof(hostdata->madapter_info));
+	
+	evt_struct = get_event_struct(&hostdata->pool);
+	if (!evt_struct) {
+		printk(KERN_ERR "ibmvscsi: couldn't allocate an event "
+		       "for ADAPTER_INFO_REQ!\n");
+		return;
+	}
+
+	init_event_struct(evt_struct,
+			  adapter_info_rsp,
+			  VIOSRP_MAD_FORMAT,
+			  init_timeout * HZ);
+	
+	req = &evt_struct->iu.mad.adapter_info;
+	memset(req, 0x00, sizeof(*req));
+	
+	req->common.type = VIOSRP_ADAPTER_INFO_TYPE;
+	req->common.length = sizeof(hostdata->madapter_info);
+	req->buffer = dma_map_single(hostdata->dev,
+				     &hostdata->madapter_info,
+				     sizeof(hostdata->madapter_info),
+				     DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(req->buffer)) {
+		printk(KERN_ERR
+		       "ibmvscsi: Unable to map request_buffer "
+		       "for adapter_info!\n");
+		free_event_struct(&hostdata->pool, evt_struct);
+		return;
+	}
+	
+	if (ibmvscsi_send_srp_event(evt_struct, hostdata))
+		printk(KERN_ERR "ibmvscsi: couldn't send ADAPTER_INFO_REQ!\n");
+};
+
+/**
+ * login_rsp: - Handle response to SRP login request
+ * @evt_struct:	srp_event_struct with the response
+ *
+ * Used as a "done" callback by when sending srp_login. Gets called
+ * by ibmvscsi_handle_crq()
+*/
+static void login_rsp(struct srp_event_struct *evt_struct)
+{
+	struct ibmvscsi_host_data *hostdata = evt_struct->hostdata;
+	switch (evt_struct->xfer_iu->srp.generic.type) {
+	case SRP_LOGIN_RSP_TYPE:	/* it worked! */
+		break;
+	case SRP_LOGIN_REJ_TYPE:	/* refused! */
+		printk(KERN_INFO "ibmvscsi: SRP_LOGIN_REQ rejected\n");
+		/* Login failed.  */
+		atomic_set(&hostdata->request_limit, -1);
+		return;
+	default:
+		printk(KERN_ERR
+		       "ibmvscsi: Invalid login response typecode 0x%02x!\n",
+		       evt_struct->xfer_iu->srp.generic.type);
+		/* Login failed.  */
+		atomic_set(&hostdata->request_limit, -1);
+		return;
+	}
+
+	printk(KERN_INFO "ibmvscsi: SRP_LOGIN succeeded\n");
+
+	if (evt_struct->xfer_iu->srp.login_rsp.request_limit_delta >
+	    (max_requests - 2))
+		evt_struct->xfer_iu->srp.login_rsp.request_limit_delta =
+		    max_requests - 2;
+
+	/* Now we know what the real request-limit is */
+	atomic_set(&hostdata->request_limit,
+		   evt_struct->xfer_iu->srp.login_rsp.request_limit_delta);
+
+	hostdata->host->can_queue =
+	    evt_struct->xfer_iu->srp.login_rsp.request_limit_delta - 2;
+
+	if (hostdata->host->can_queue < 1) {
+		printk(KERN_ERR "ibmvscsi: Invalid request_limit_delta\n");
+		return;
+	}
+
+	send_mad_adapter_info(hostdata);
+	return;
+}
+
+/**
+ * send_srp_login: - Sends the srp login
+ * @hostdata:	ibmvscsi_host_data of host
+ * 
+ * Returns zero if successful.
+*/
+static int send_srp_login(struct ibmvscsi_host_data *hostdata)
+{
+	int rc;
+	unsigned long flags;
+	struct srp_login_req *login;
+	struct srp_event_struct *evt_struct = get_event_struct(&hostdata->pool);
+	if (!evt_struct) {
+		printk(KERN_ERR
+		       "ibmvscsi: couldn't allocate an event for login req!\n");
+		return FAILED;
+	}
+
+	init_event_struct(evt_struct,
+			  login_rsp,
+			  VIOSRP_SRP_FORMAT,
+			  init_timeout * HZ);
+
+	login = &evt_struct->iu.srp.login_req;
+	login->type = SRP_LOGIN_REQ_TYPE;
+	login->max_requested_initiator_to_target_iulen = sizeof(union srp_iu);
+	login->required_buffer_formats = 0x0006;
+	
+	/* Start out with a request limit of 1, since this is negotiated in
+	 * the login request we are just sending
+	 */
+	atomic_set(&hostdata->request_limit, 1);
+
+	spin_lock_irqsave(hostdata->host->host_lock, flags);
+	rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+	return rc;
+};
+
+/**
+ * sync_completion: Signal that a synchronous command has completed
+ * Note that after returning from this call, the evt_struct is freed.
+ * the caller waiting on this completion shouldn't touch the evt_struct
+ * again.
+ */
+static void sync_completion(struct srp_event_struct *evt_struct)
+{
+	/* copy the response back */
+	if (evt_struct->sync_srp)
+		*evt_struct->sync_srp = *evt_struct->xfer_iu;
+	
+	complete(&evt_struct->comp);
+}
+
+/**
+ * ibmvscsi_abort: Abort a command...from scsi host template
+ * send this over to the server and wait synchronously for the response
+ */
+static int ibmvscsi_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+	struct srp_tsk_mgmt *tsk_mgmt;
+	struct srp_event_struct *evt;
+	struct srp_event_struct *tmp_evt, *found_evt;
+	union viosrp_iu srp_rsp;
+	int rsp_rc;
+	u16 lun = lun_from_dev(cmd->device);
+
+	/* First, find this command in our sent list so we can figure
+	 * out the correct tag
+	 */
+	found_evt = NULL;
+	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+		if (tmp_evt->cmnd == cmd) {
+			found_evt = tmp_evt;
+			break;
+		}
+	}
+
+	if (!found_evt) 
+		return FAILED;
+
+	evt = get_event_struct(&hostdata->pool);
+	if (evt == NULL) {
+		printk(KERN_ERR "ibmvscsi: failed to allocate abort event\n");
+		return FAILED;
+	}
+	
+	init_event_struct(evt,
+			  sync_completion,
+			  VIOSRP_SRP_FORMAT,
+			  init_timeout * HZ);
+
+	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+	
+	/* Set up an abort SRP command */
+	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+	tsk_mgmt->type = SRP_TSK_MGMT_TYPE;
+	tsk_mgmt->lun = ((u64) lun) << 48;
+	tsk_mgmt->task_mgmt_flags = 0x01;	/* ABORT TASK */
+	tsk_mgmt->managed_task_tag = (u64) found_evt;
+
+	printk(KERN_INFO "ibmvscsi: aborting command. lun 0x%lx, tag 0x%lx\n",
+	       tsk_mgmt->lun, tsk_mgmt->managed_task_tag);
+
+	evt->sync_srp = &srp_rsp;
+	init_completion(&evt->comp);
+	if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+		printk(KERN_ERR "ibmvscsi: failed to send abort() event\n");
+		return FAILED;
+	}
+
+	spin_unlock_irq(hostdata->host->host_lock);
+	wait_for_completion(&evt->comp);
+	spin_lock_irq(hostdata->host->host_lock);
+
+	/* make sure we got a good response */
+	if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING 
+			       "ibmvscsi: abort bad SRP RSP type %d\n",
+			       srp_rsp.srp.generic.type);
+		return FAILED;
+	}
+
+	if (srp_rsp.srp.rsp.rspvalid)
+		rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data);
+	else
+		rsp_rc = srp_rsp.srp.rsp.status;
+
+	if (rsp_rc) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING 
+		       "ibmvscsi: abort code %d for task tag 0x%lx\n",
+			       rsp_rc,
+			       tsk_mgmt->managed_task_tag);
+		return FAILED;
+	}
+
+	/* Because we dropped the spinlock above, it's possible
+	 * The event is no longer in our list.  Make sure it didn't
+	 * complete while we were aborting
+	 */
+	found_evt = NULL;
+	list_for_each_entry(tmp_evt, &hostdata->sent, list) {
+		if (tmp_evt->cmnd == cmd) {
+			found_evt = tmp_evt;
+			break;
+		}
+	}
+
+	if (found_evt == NULL) {
+		printk(KERN_INFO
+		       "ibmvscsi: aborted task tag 0x%lx completed\n",
+		       tsk_mgmt->managed_task_tag);
+		return SUCCESS;
+	}
+
+	printk(KERN_INFO
+	       "ibmvscsi: successfully aborted task tag 0x%lx\n",
+	       tsk_mgmt->managed_task_tag);
+
+	cmd->result = (DID_ABORT << 16);
+	list_del(&found_evt->list);
+	unmap_cmd_data(&found_evt->iu.srp.cmd, found_evt->hostdata->dev);
+	free_event_struct(&found_evt->hostdata->pool, found_evt);
+	atomic_inc(&hostdata->request_limit);
+	return SUCCESS;
+}
+
+/**
+ * ibmvscsi_eh_device_reset_handler: Reset a single LUN...from scsi host 
+ * template send this over to the server and wait synchronously for the 
+ * response
+ */
+static int ibmvscsi_eh_device_reset_handler(struct scsi_cmnd *cmd)
+{
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)cmd->device->host->hostdata;
+
+	struct srp_tsk_mgmt *tsk_mgmt;
+	struct srp_event_struct *evt;
+	struct srp_event_struct *tmp_evt, *pos;
+	union viosrp_iu srp_rsp;
+	int rsp_rc;
+	u16 lun = lun_from_dev(cmd->device);
+
+	evt = get_event_struct(&hostdata->pool);
+	if (evt == NULL) {
+		printk(KERN_ERR "ibmvscsi: failed to allocate reset event\n");
+		return FAILED;
+	}
+	
+	init_event_struct(evt,
+			  sync_completion,
+			  VIOSRP_SRP_FORMAT,
+			  init_timeout * HZ);
+
+	tsk_mgmt = &evt->iu.srp.tsk_mgmt;
+
+	/* Set up a lun reset SRP command */
+	memset(tsk_mgmt, 0x00, sizeof(*tsk_mgmt));
+	tsk_mgmt->type = SRP_TSK_MGMT_TYPE;
+	tsk_mgmt->lun = ((u64) lun) << 48;
+	tsk_mgmt->task_mgmt_flags = 0x08;	/* LUN RESET */
+
+	printk(KERN_INFO "ibmvscsi: resetting device. lun 0x%lx\n",
+	       tsk_mgmt->lun);
+
+	evt->sync_srp = &srp_rsp;
+	init_completion(&evt->comp);
+	if (ibmvscsi_send_srp_event(evt, hostdata) != 0) {
+		printk(KERN_ERR "ibmvscsi: failed to send reset event\n");
+		return FAILED;
+	}
+
+	spin_unlock_irq(hostdata->host->host_lock);
+	wait_for_completion(&evt->comp);
+	spin_lock_irq(hostdata->host->host_lock);
+
+	/* make sure we got a good response */
+	if (unlikely(srp_rsp.srp.generic.type != SRP_RSP_TYPE)) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING 
+			       "ibmvscsi: reset bad SRP RSP type %d\n",
+			       srp_rsp.srp.generic.type);
+		return FAILED;
+	}
+
+	if (srp_rsp.srp.rsp.rspvalid)
+		rsp_rc = *((int *)srp_rsp.srp.rsp.sense_and_response_data);
+	else
+		rsp_rc = srp_rsp.srp.rsp.status;
+
+	if (rsp_rc) {
+		if (printk_ratelimit())
+			printk(KERN_WARNING 
+			       "ibmvscsi: reset code %d for task tag 0x%lx\n",
+		       rsp_rc,
+			       tsk_mgmt->managed_task_tag);
+		return FAILED;
+	}
+
+	/* We need to find all commands for this LUN that have not yet been
+	 * responded to, and fail them with DID_RESET
+	 */
+	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+		if ((tmp_evt->cmnd) && (tmp_evt->cmnd->device == cmd->device)) {
+			if (tmp_evt->cmnd)
+				tmp_evt->cmnd->result = (DID_RESET << 16);
+			list_del(&tmp_evt->list);
+			unmap_cmd_data(&tmp_evt->iu.srp.cmd, tmp_evt->hostdata->dev);
+			free_event_struct(&tmp_evt->hostdata->pool,
+						   tmp_evt);
+			atomic_inc(&hostdata->request_limit);
+			if (tmp_evt->cmnd_done)
+				tmp_evt->cmnd_done(tmp_evt->cmnd);
+			else if (tmp_evt->done)
+				tmp_evt->done(tmp_evt);
+		}
+	}
+	return SUCCESS;
+}
+
+/**
+ * purge_requests: Our virtual adapter just shut down.  purge any sent requests
+ * @hostdata:    the adapter
+ */
+static void purge_requests(struct ibmvscsi_host_data *hostdata)
+{
+	struct srp_event_struct *tmp_evt, *pos;
+	unsigned long flags;
+
+	spin_lock_irqsave(hostdata->host->host_lock, flags);
+	list_for_each_entry_safe(tmp_evt, pos, &hostdata->sent, list) {
+		list_del(&tmp_evt->list);
+		if (tmp_evt->cmnd) {
+			tmp_evt->cmnd->result = (DID_ERROR << 16);
+			unmap_cmd_data(&tmp_evt->iu.srp.cmd, 
+				       tmp_evt->hostdata->dev);
+			if (tmp_evt->cmnd_done)
+				tmp_evt->cmnd_done(tmp_evt->cmnd);
+		} else {
+			if (tmp_evt->done) {
+				tmp_evt->done(tmp_evt);
+			}
+		}
+		free_event_struct(&tmp_evt->hostdata->pool, tmp_evt);
+	}
+	spin_unlock_irqrestore(hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_handle_crq: - Handles and frees received events in the CRQ
+ * @crq:	Command/Response queue
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+*/
+void ibmvscsi_handle_crq(struct viosrp_crq *crq,
+			 struct ibmvscsi_host_data *hostdata)
+{
+	unsigned long flags;
+	struct srp_event_struct *evt_struct =
+	    (struct srp_event_struct *)crq->IU_data_ptr;
+	switch (crq->valid) {
+	case 0xC0:		/* initialization */
+		switch (crq->format) {
+		case 0x01:	/* Initialization message */
+			printk(KERN_INFO "ibmvscsi: partner initialized\n");
+			/* Send back a response */
+			if (ibmvscsi_send_crq(hostdata,
+					      0xC002000000000000LL, 0) == 0) {
+				/* Now login */
+				send_srp_login(hostdata);
+			} else {
+				printk(KERN_ERR
+				       "ibmvscsi: Unable to send init rsp\n");
+			}
+
+			break;
+		case 0x02:	/* Initialization response */
+			printk(KERN_INFO
+			       "ibmvscsi: partner initialization complete\n");
+
+			/* Now login */
+			send_srp_login(hostdata);
+			break;
+		default:
+			printk(KERN_ERR "ibmvscsi: unknown crq message type\n");
+		}
+		return;
+	case 0xFF:		/* Hypervisor telling us the connection is closed */
+		printk(KERN_INFO "ibmvscsi: Virtual adapter failed!\n");
+
+		atomic_set(&hostdata->request_limit, -1);
+		purge_requests(hostdata);
+		ibmvscsi_reset_crq_queue(&hostdata->queue, hostdata);
+		return;
+	case 0x80:		/* real payload */
+		break;
+	default:
+		printk(KERN_ERR
+		       "ibmvscsi: got an invalid message type 0x%02x\n",
+		       crq->valid);
+		return;
+	}
+
+	/* The only kind of payload CRQs we should get are responses to
+	 * things we send. Make sure this response is to something we
+	 * actually sent
+	 */
+	if (!valid_event_struct(&hostdata->pool, evt_struct)) {
+		printk(KERN_ERR
+		       "ibmvscsi: returned correlation_token 0x%p is invalid!\n",
+		       (void *)crq->IU_data_ptr);
+		return;
+	}
+
+	if (atomic_read(&evt_struct->free)) {
+		printk(KERN_ERR
+		       "ibmvscsi: received duplicate  correlation_token 0x%p!\n",
+		       (void *)crq->IU_data_ptr);
+		return;
+	}
+
+	if (crq->format == VIOSRP_SRP_FORMAT)
+		atomic_add(evt_struct->xfer_iu->srp.rsp.request_limit_delta,
+			   &hostdata->request_limit);
+
+	if (evt_struct->done)
+		evt_struct->done(evt_struct);
+	else
+		printk(KERN_ERR
+		       "ibmvscsi: returned done() is NULL; not running it!\n");
+
+	/*
+	 * Lock the host_lock before messing with these structures, since we
+	 * are running in a task context
+	 */
+	spin_lock_irqsave(evt_struct->hostdata->host->host_lock, flags);
+	list_del(&evt_struct->list);
+	free_event_struct(&evt_struct->hostdata->pool, evt_struct);
+	spin_unlock_irqrestore(evt_struct->hostdata->host->host_lock, flags);
+}
+
+/**
+ * ibmvscsi_get_host_config: Send the command to the server to get host
+ * configuration data.  The data is opaque to us.
+ */
+static int ibmvscsi_do_host_config(struct ibmvscsi_host_data *hostdata,
+				   unsigned char *buffer, int length)
+{
+	struct viosrp_host_config *host_config;
+	struct srp_event_struct *evt_struct;
+	int rc;
+
+	evt_struct = get_event_struct(&hostdata->pool);
+	if (!evt_struct) {
+		printk(KERN_ERR
+		       "ibmvscsi: could't allocate event for HOST_CONFIG!\n");
+		return -1;
+	}
+
+	init_event_struct(evt_struct,
+			  sync_completion,
+			  VIOSRP_MAD_FORMAT,
+			  init_timeout * HZ);
+
+	host_config = &evt_struct->iu.mad.host_config;
+
+	/* Set up a lun reset SRP command */
+	memset(host_config, 0x00, sizeof(*host_config));
+	host_config->common.type = VIOSRP_HOST_CONFIG_TYPE;
+	host_config->common.length = length;
+	host_config->buffer = dma_map_single(hostdata->dev, buffer, length,
+					    DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(host_config->buffer)) {
+		printk(KERN_ERR
+		       "ibmvscsi: dma_mapping error " "getting host config\n");
+		free_event_struct(&hostdata->pool, evt_struct);
+		return -1;
+	}
+
+	init_completion(&evt_struct->comp);
+	rc = ibmvscsi_send_srp_event(evt_struct, hostdata);
+	if (rc == 0) {
+		wait_for_completion(&evt_struct->comp);
+		dma_unmap_single(hostdata->dev, host_config->buffer,
+				 length, DMA_BIDIRECTIONAL);
+	}
+
+	return rc;
+}
+
+/* ------------------------------------------------------------
+ * sysfs attributes
+ */
+static ssize_t show_host_srp_version(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "%s\n",
+		       hostdata->madapter_info.srp_version);
+	return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_srp_version = {
+	.attr = {
+		 .name = "srp_version",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_srp_version,
+};
+
+static ssize_t show_host_partition_name(struct class_device *class_dev,
+					char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "%s\n",
+		       hostdata->madapter_info.partition_name);
+	return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_partition_name = {
+	.attr = {
+		 .name = "partition_name",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_partition_name,
+};
+
+static ssize_t show_host_partition_number(struct class_device *class_dev,
+					  char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "%d\n",
+		       hostdata->madapter_info.partition_number);
+	return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_partition_number = {
+	.attr = {
+		 .name = "partition_number",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_partition_number,
+};
+
+static ssize_t show_host_mad_version(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "%d\n",
+		       hostdata->madapter_info.mad_version);
+	return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_mad_version = {
+	.attr = {
+		 .name = "mad_version",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_mad_version,
+};
+
+static ssize_t show_host_os_type(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+	int len;
+
+	len = snprintf(buf, PAGE_SIZE, "%d\n", hostdata->madapter_info.os_type);
+	return len;
+}
+
+static struct class_device_attribute ibmvscsi_host_os_type = {
+	.attr = {
+		 .name = "os_type",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_os_type,
+};
+
+static ssize_t show_host_config(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)shost->hostdata;
+
+	/* returns null-terminated host config data */
+	if (ibmvscsi_do_host_config(hostdata, buf, PAGE_SIZE) == 0)
+		return strlen(buf);
+	else
+		return 0;
+}
+
+static struct class_device_attribute ibmvscsi_host_config = {
+	.attr = {
+		 .name = "config",
+		 .mode = S_IRUGO,
+		 },
+	.show = show_host_config,
+};
+
+static struct class_device_attribute *ibmvscsi_attrs[] = {
+	&ibmvscsi_host_srp_version,
+	&ibmvscsi_host_partition_name,
+	&ibmvscsi_host_partition_number,
+	&ibmvscsi_host_mad_version,
+	&ibmvscsi_host_os_type,
+	&ibmvscsi_host_config,
+	NULL
+};
+
+/* ------------------------------------------------------------
+ * SCSI driver registration
+ */
+static struct scsi_host_template driver_template = {
+	.module = THIS_MODULE,
+	.name = "IBM POWER Virtual SCSI Adapter " IBMVSCSI_VERSION,
+	.proc_name = "ibmvscsi",
+	.queuecommand = ibmvscsi_queuecommand,
+	.eh_abort_handler = ibmvscsi_eh_abort_handler,
+	.eh_device_reset_handler = ibmvscsi_eh_device_reset_handler,
+	.cmd_per_lun = 16,
+	.can_queue = 1,		/* Updated after SRP_LOGIN */
+	.this_id = -1,
+	.sg_tablesize = MAX_INDIRECT_BUFS,
+	.use_clustering = ENABLE_CLUSTERING,
+	.shost_attrs = ibmvscsi_attrs,
+};
+
+/**
+ * Called by bus code for each adapter
+ */
+static int ibmvscsi_probe(struct vio_dev *vdev, const struct vio_device_id *id)
+{
+	struct ibmvscsi_host_data *hostdata;
+	struct Scsi_Host *host;
+	struct device *dev = &vdev->dev;
+	unsigned long wait_switch = 0;
+
+	vdev->dev.driver_data = NULL;
+
+	host = scsi_host_alloc(&driver_template, sizeof(*hostdata));
+	if (!host) {
+		printk(KERN_ERR "ibmvscsi: couldn't allocate host data\n");
+		goto scsi_host_alloc_failed;
+	}
+
+	hostdata = (struct ibmvscsi_host_data *)host->hostdata;
+	memset(hostdata, 0x00, sizeof(*hostdata));
+	INIT_LIST_HEAD(&hostdata->sent);
+	hostdata->host = host;
+	hostdata->dev = dev;
+	atomic_set(&hostdata->request_limit, -1);
+	hostdata->host->max_sectors = 32 * 8; /* default max I/O 32 pages */
+
+	if (ibmvscsi_init_crq_queue(&hostdata->queue, hostdata,
+				    max_requests) != 0) {
+		printk(KERN_ERR "ibmvscsi: couldn't initialize crq\n");
+		goto init_crq_failed;
+	}
+	if (initialize_event_pool(&hostdata->pool, max_requests, hostdata) != 0) {
+		printk(KERN_ERR "ibmvscsi: couldn't initialize event pool\n");
+		goto init_pool_failed;
+	}
+
+	host->max_lun = 8;
+	host->max_id = max_id;
+	host->max_channel = max_channel;
+
+	if (scsi_add_host(hostdata->host, hostdata->dev))
+		goto add_host_failed;
+
+	/* Try to send an initialization message.  Note that this is allowed
+	 * to fail if the other end is not acive.  In that case we don't
+	 * want to scan
+	 */
+	if (ibmvscsi_send_crq(hostdata, 0xC001000000000000LL, 0) == 0) {
+		/*
+		 * Wait around max init_timeout secs for the adapter to finish
+		 * initializing. When we are done initializing, we will have a
+		 * valid request_limit.  We don't want Linux scanning before
+		 * we are ready.
+		 */
+		for (wait_switch = jiffies + (init_timeout * HZ);
+		     time_before(jiffies, wait_switch) &&
+		     atomic_read(&hostdata->request_limit) < 2;) {
+
+			msleep(10);
+		}
+
+		/* if we now have a valid request_limit, initiate a scan */
+		if (atomic_read(&hostdata->request_limit) > 0)
+			scsi_scan_host(host);
+	}
+
+	vdev->dev.driver_data = hostdata;
+	return 0;
+
+      add_host_failed:
+	release_event_pool(&hostdata->pool, hostdata);
+      init_pool_failed:
+	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata, max_requests);
+      init_crq_failed:
+	scsi_host_put(host);
+      scsi_host_alloc_failed:
+	return -1;
+}
+
+static int ibmvscsi_remove(struct vio_dev *vdev)
+{
+	struct ibmvscsi_host_data *hostdata = vdev->dev.driver_data;
+	release_event_pool(&hostdata->pool, hostdata);
+	ibmvscsi_release_crq_queue(&hostdata->queue, hostdata,
+				   max_requests);
+	
+	scsi_remove_host(hostdata->host);
+	scsi_host_put(hostdata->host);
+
+	return 0;
+}
+
+/**
+ * ibmvscsi_device_table: Used by vio.c to match devices in the device tree we 
+ * support.
+ */
+static struct vio_device_id ibmvscsi_device_table[] __devinitdata = {
+	{"vscsi", "IBM,v-scsi"},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(vio, ibmvscsi_device_table);
+static struct vio_driver ibmvscsi_driver = {
+	.name = "ibmvscsi",
+	.id_table = ibmvscsi_device_table,
+	.probe = ibmvscsi_probe,
+	.remove = ibmvscsi_remove
+};
+
+int __init ibmvscsi_module_init(void)
+{
+	return vio_register_driver(&ibmvscsi_driver);
+}
+
+void __exit ibmvscsi_module_exit(void)
+{
+	vio_unregister_driver(&ibmvscsi_driver);
+}
+
+module_init(ibmvscsi_module_init);
+module_exit(ibmvscsi_module_exit);
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.h b/drivers/scsi/ibmvscsi/ibmvscsi.h
new file mode 100644
index 0000000..1030b70
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.h
@@ -0,0 +1,109 @@
+/* ------------------------------------------------------------
+ * ibmvscsi.h
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ * ------------------------------------------------------------
+ * Emulation of a SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+#ifndef IBMVSCSI_H
+#define IBMVSCSI_H
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include "viosrp.h"
+
+struct scsi_cmnd;
+struct Scsi_Host;
+
+/* Number of indirect bufs...the list of these has to fit in the
+ * additional data of the srp_cmd struct along with the indirect
+ * descriptor
+ */
+#define MAX_INDIRECT_BUFS 10
+
+/* ------------------------------------------------------------
+ * Data Structures
+ */
+/* an RPA command/response transport queue */
+struct crq_queue {
+	struct viosrp_crq *msgs;
+	int size, cur;
+	dma_addr_t msg_token;
+	spinlock_t lock;
+};
+
+/* a unit of work for the hosting partition */
+struct srp_event_struct {
+	union viosrp_iu *xfer_iu;
+	struct scsi_cmnd *cmnd;
+	struct list_head list;
+	void (*done) (struct srp_event_struct *);
+	struct viosrp_crq crq;
+	struct ibmvscsi_host_data *hostdata;
+	atomic_t free;
+	union viosrp_iu iu;
+	void (*cmnd_done) (struct scsi_cmnd *);
+	struct completion comp;
+	union viosrp_iu *sync_srp;
+};
+
+/* a pool of event structs for use */
+struct event_pool {
+	struct srp_event_struct *events;
+	u32 size;
+	int next;
+	union viosrp_iu *iu_storage;
+	dma_addr_t iu_token;
+};
+
+/* all driver data associated with a host adapter */
+struct ibmvscsi_host_data {
+	atomic_t request_limit;
+	struct device *dev;
+	struct event_pool pool;
+	struct crq_queue queue;
+	struct tasklet_struct srp_task;
+	struct list_head sent;
+	struct Scsi_Host *host;
+	struct mad_adapter_info_data madapter_info;
+};
+
+/* routines for managing a command/response queue */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+			    struct ibmvscsi_host_data *hostdata,
+			    int max_requests);
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+				struct ibmvscsi_host_data *hostdata,
+				int max_requests);
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+			      struct ibmvscsi_host_data *hostdata);
+
+void ibmvscsi_handle_crq(struct viosrp_crq *crq,
+			 struct ibmvscsi_host_data *hostdata);
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata,
+		      u64 word1, u64 word2);
+
+#endif				/* IBMVSCSI_H */
diff --git a/drivers/scsi/ibmvscsi/iseries_vscsi.c b/drivers/scsi/ibmvscsi/iseries_vscsi.c
new file mode 100644
index 0000000..e9202f2
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/iseries_vscsi.c
@@ -0,0 +1,144 @@
+/* ------------------------------------------------------------
+ * iSeries_vscsi.c
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *          Dave Boutcher (sleddog@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ * ------------------------------------------------------------
+ * iSeries-specific functions of the SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+
+#include <asm/iSeries/vio.h>
+#include <asm/iSeries/HvLpEvent.h>
+#include <asm/iSeries/HvTypes.h>
+#include <asm/iSeries/HvLpConfig.h>
+#include <asm/vio.h>
+#include <linux/device.h>
+#include "ibmvscsi.h"
+
+/* global variables */
+static struct ibmvscsi_host_data *single_host_data;
+
+/* ------------------------------------------------------------
+ * Routines for direct interpartition interaction
+ */
+struct srp_lp_event {
+	struct HvLpEvent lpevt;	/* 0x00-0x17          */
+	u32 reserved1;		/* 0x18-0x1B; unused  */
+	u16 version;		/* 0x1C-0x1D; unused  */
+	u16 subtype_rc;		/* 0x1E-0x1F; unused  */
+	struct viosrp_crq crq;	/* 0x20-0x3F          */
+};
+
+/** 
+ * standard interface for handling logical partition events.
+ */
+static void ibmvscsi_handle_event(struct HvLpEvent *lpevt)
+{
+	struct srp_lp_event *evt = (struct srp_lp_event *)lpevt;
+
+	if (!evt) {
+		printk(KERN_ERR "ibmvscsi: received null event\n");
+		return;
+	}
+
+	if (single_host_data == NULL) {
+		printk(KERN_ERR
+		       "ibmvscsi: received event, no adapter present\n");
+		return;
+	}
+
+	ibmvscsi_handle_crq(&evt->crq, single_host_data);
+}
+
+/* ------------------------------------------------------------
+ * Routines for driver initialization
+ */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+			    struct ibmvscsi_host_data *hostdata,
+			    int max_requests)
+{
+	int rc;
+
+	single_host_data = hostdata;
+	rc = viopath_open(viopath_hostLp, viomajorsubtype_scsi, 0);
+	if (rc < 0) {
+		printk("viopath_open failed with rc %d in open_event_path\n",
+		       rc);
+		goto viopath_open_failed;
+	}
+
+	rc = vio_setHandler(viomajorsubtype_scsi, ibmvscsi_handle_event);
+	if (rc < 0) {
+		printk("vio_setHandler failed with rc %d in open_event_path\n",
+		       rc);
+		goto vio_setHandler_failed;
+	}
+	return 0;
+
+      vio_setHandler_failed:
+	viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
+      viopath_open_failed:
+	return -1;
+}
+
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+				struct ibmvscsi_host_data *hostdata,
+				int max_requests)
+{
+	vio_clearHandler(viomajorsubtype_scsi);
+	viopath_close(viopath_hostLp, viomajorsubtype_scsi, max_requests);
+}
+
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:	crq_queue to initialize and register
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+ * no-op for iSeries
+ */
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+			      struct ibmvscsi_host_data *hostdata)
+{
+}
+
+/**
+ * ibmvscsi_send_crq: - Send a CRQ
+ * @hostdata:	the adapter
+ * @word1:	the first 64 bits of the data
+ * @word2:	the second 64 bits of the data
+ */
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+{
+	single_host_data = hostdata;
+	return HvCallEvent_signalLpEventFast(viopath_hostLp,
+					     HvLpEvent_Type_VirtualIo,
+					     viomajorsubtype_scsi,
+					     HvLpEvent_AckInd_NoAck,
+					     HvLpEvent_AckType_ImmediateAck,
+					     viopath_sourceinst(viopath_hostLp),
+					     viopath_targetinst(viopath_hostLp),
+					     0,
+					     VIOVERSION << 16, word1, word2, 0,
+					     0);
+}
diff --git a/drivers/scsi/ibmvscsi/rpa_vscsi.c b/drivers/scsi/ibmvscsi/rpa_vscsi.c
new file mode 100644
index 0000000..50cb909
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/rpa_vscsi.c
@@ -0,0 +1,260 @@
+/* ------------------------------------------------------------
+ * rpa_vscsi.c
+ * (C) Copyright IBM Corporation 1994, 2003
+ * Authors: Colin DeVilbiss (devilbis@us.ibm.com)
+ *          Santiago Leon (santil@us.ibm.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
+ * USA
+ *
+ * ------------------------------------------------------------
+ * RPA-specific functions of the SCSI host adapter for Virtual I/O devices
+ *
+ * This driver allows the Linux SCSI peripheral drivers to directly
+ * access devices in the hosting partition, either on an iSeries
+ * hypervisor system or a converged hypervisor system.
+ */
+
+#include <asm/vio.h>
+#include <asm/iommu.h>
+#include <asm/hvcall.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include "ibmvscsi.h"
+
+/* ------------------------------------------------------------
+ * Routines for managing the command/response queue
+ */
+/**
+ * ibmvscsi_handle_event: - Interrupt handler for crq events
+ * @irq:	number of irq to handle, not used
+ * @dev_instance: ibmvscsi_host_data of host that received interrupt
+ * @regs:	pt_regs with registers
+ *
+ * Disables interrupts and schedules srp_task
+ * Always returns IRQ_HANDLED
+ */
+static irqreturn_t ibmvscsi_handle_event(int irq,
+					 void *dev_instance,
+					 struct pt_regs *regs)
+{
+	struct ibmvscsi_host_data *hostdata =
+	    (struct ibmvscsi_host_data *)dev_instance;
+	vio_disable_interrupts(to_vio_dev(hostdata->dev));
+	tasklet_schedule(&hostdata->srp_task);
+	return IRQ_HANDLED;
+}
+
+/**
+ * release_crq_queue: - Deallocates data and unregisters CRQ
+ * @queue:	crq_queue to initialize and register
+ * @host_data:	ibmvscsi_host_data of host
+ *
+ * Frees irq, deallocates a page for messages, unmaps dma, and unregisters
+ * the crq with the hypervisor.
+ */
+void ibmvscsi_release_crq_queue(struct crq_queue *queue,
+				struct ibmvscsi_host_data *hostdata,
+				int max_requests)
+{
+	long rc;
+	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+	free_irq(vdev->irq, (void *)hostdata);
+	tasklet_kill(&hostdata->srp_task);
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while ((rc == H_Busy) || (H_isLongBusy(rc)));
+	dma_unmap_single(hostdata->dev,
+			 queue->msg_token,
+			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+	free_page((unsigned long)queue->msgs);
+}
+
+/**
+ * crq_queue_next_crq: - Returns the next entry in message queue
+ * @queue:	crq_queue to use
+ *
+ * Returns pointer to next entry in queue, or NULL if there are no new 
+ * entried in the CRQ.
+ */
+static struct viosrp_crq *crq_queue_next_crq(struct crq_queue *queue)
+{
+	struct viosrp_crq *crq;
+	unsigned long flags;
+
+	spin_lock_irqsave(&queue->lock, flags);
+	crq = &queue->msgs[queue->cur];
+	if (crq->valid & 0x80) {
+		if (++queue->cur == queue->size)
+			queue->cur = 0;
+	} else
+		crq = NULL;
+	spin_unlock_irqrestore(&queue->lock, flags);
+
+	return crq;
+}
+
+/**
+ * ibmvscsi_send_crq: - Send a CRQ
+ * @hostdata:	the adapter
+ * @word1:	the first 64 bits of the data
+ * @word2:	the second 64 bits of the data
+ */
+int ibmvscsi_send_crq(struct ibmvscsi_host_data *hostdata, u64 word1, u64 word2)
+{
+	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+	return plpar_hcall_norets(H_SEND_CRQ, vdev->unit_address, word1, word2);
+}
+
+/**
+ * ibmvscsi_task: - Process srps asynchronously
+ * @data:	ibmvscsi_host_data of host
+ */
+static void ibmvscsi_task(void *data)
+{
+	struct ibmvscsi_host_data *hostdata = (struct ibmvscsi_host_data *)data;
+	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+	struct viosrp_crq *crq;
+	int done = 0;
+
+	while (!done) {
+		/* Pull all the valid messages off the CRQ */
+		while ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
+			ibmvscsi_handle_crq(crq, hostdata);
+			crq->valid = 0x00;
+		}
+
+		vio_enable_interrupts(vdev);
+		if ((crq = crq_queue_next_crq(&hostdata->queue)) != NULL) {
+			vio_disable_interrupts(vdev);
+			ibmvscsi_handle_crq(crq, hostdata);
+			crq->valid = 0x00;
+		} else {
+			done = 1;
+		}
+	}
+}
+
+/**
+ * initialize_crq_queue: - Initializes and registers CRQ with hypervisor
+ * @queue:	crq_queue to initialize and register
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+ * Allocates a page for messages, maps it for dma, and registers
+ * the crq with the hypervisor.
+ * Returns zero on success.
+ */
+int ibmvscsi_init_crq_queue(struct crq_queue *queue,
+			    struct ibmvscsi_host_data *hostdata,
+			    int max_requests)
+{
+	int rc;
+	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+	queue->msgs = (struct viosrp_crq *)get_zeroed_page(GFP_KERNEL);
+
+	if (!queue->msgs)
+		goto malloc_failed;
+	queue->size = PAGE_SIZE / sizeof(*queue->msgs);
+
+	queue->msg_token = dma_map_single(hostdata->dev, queue->msgs,
+					  queue->size * sizeof(*queue->msgs),
+					  DMA_BIDIRECTIONAL);
+
+	if (dma_mapping_error(queue->msg_token))
+		goto map_failed;
+
+	rc = plpar_hcall_norets(H_REG_CRQ,
+				vdev->unit_address,
+				queue->msg_token, PAGE_SIZE);
+	if (rc == 2) {
+		/* Adapter is good, but other end is not ready */
+		printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+	} else if (rc != 0) {
+		printk(KERN_WARNING "ibmvscsi: Error %d opening adapter\n", rc);
+		goto reg_crq_failed;
+	}
+
+	if (request_irq(vdev->irq,
+			ibmvscsi_handle_event,
+			0, "ibmvscsi", (void *)hostdata) != 0) {
+		printk(KERN_ERR "ibmvscsi: couldn't register irq 0x%x\n",
+		       vdev->irq);
+		goto req_irq_failed;
+	}
+
+	rc = vio_enable_interrupts(vdev);
+	if (rc != 0) {
+		printk(KERN_ERR "ibmvscsi:  Error %d enabling interrupts!!!\n",
+		       rc);
+		goto req_irq_failed;
+	}
+
+	queue->cur = 0;
+	spin_lock_init(&queue->lock);
+
+	tasklet_init(&hostdata->srp_task, (void *)ibmvscsi_task,
+		     (unsigned long)hostdata);
+
+	return 0;
+
+      req_irq_failed:
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while ((rc == H_Busy) || (H_isLongBusy(rc)));
+      reg_crq_failed:
+	dma_unmap_single(hostdata->dev,
+			 queue->msg_token,
+			 queue->size * sizeof(*queue->msgs), DMA_BIDIRECTIONAL);
+      map_failed:
+	free_page((unsigned long)queue->msgs);
+      malloc_failed:
+	return -1;
+}
+
+/**
+ * reset_crq_queue: - resets a crq after a failure
+ * @queue:	crq_queue to initialize and register
+ * @hostdata:	ibmvscsi_host_data of host
+ *
+ */
+void ibmvscsi_reset_crq_queue(struct crq_queue *queue,
+			      struct ibmvscsi_host_data *hostdata)
+{
+	int rc;
+	struct vio_dev *vdev = to_vio_dev(hostdata->dev);
+
+	/* Close the CRQ */
+	do {
+		rc = plpar_hcall_norets(H_FREE_CRQ, vdev->unit_address);
+	} while ((rc == H_Busy) || (H_isLongBusy(rc)));
+
+	/* Clean out the queue */
+	memset(queue->msgs, 0x00, PAGE_SIZE);
+	queue->cur = 0;
+
+	/* And re-open it again */
+	rc = plpar_hcall_norets(H_REG_CRQ,
+				vdev->unit_address,
+				queue->msg_token, PAGE_SIZE);
+	if (rc == 2) {
+		/* Adapter is good, but other end is not ready */
+		printk(KERN_WARNING "ibmvscsi: Partner adapter not ready\n");
+	} else if (rc != 0) {
+		printk(KERN_WARNING
+		       "ibmvscsi: couldn't register crq--rc 0x%x\n", rc);
+	}
+}
diff --git a/drivers/scsi/ibmvscsi/srp.h b/drivers/scsi/ibmvscsi/srp.h
new file mode 100644
index 0000000..e952c1c
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/srp.h
@@ -0,0 +1,225 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for the SCSI RDMA Protocol  */
+/* (SRP) as defined in the T10 standard available at www.t10.org.  This      */
+/* file was based on the 16a version of the standard                         */
+/*                                                                           */
+/*****************************************************************************/
+#ifndef SRP_H
+#define SRP_H
+
+#define PACKED __attribute__((packed))
+
+enum srp_types {
+	SRP_LOGIN_REQ_TYPE = 0x00,
+	SRP_LOGIN_RSP_TYPE = 0xC0,
+	SRP_LOGIN_REJ_TYPE = 0x80,
+	SRP_I_LOGOUT_TYPE = 0x03,
+	SRP_T_LOGOUT_TYPE = 0x80,
+	SRP_TSK_MGMT_TYPE = 0x01,
+	SRP_CMD_TYPE = 0x02,
+	SRP_RSP_TYPE = 0xC1,
+	SRP_CRED_REQ_TYPE = 0x81,
+	SRP_CRED_RSP_TYPE = 0x41,
+	SRP_AER_REQ_TYPE = 0x82,
+	SRP_AER_RSP_TYPE = 0x42
+};
+
+enum srp_descriptor_formats {
+	SRP_NO_BUFFER = 0x00,
+	SRP_DIRECT_BUFFER = 0x01,
+	SRP_INDIRECT_BUFFER = 0x02
+};
+
+struct memory_descriptor {
+	u64 virtual_address;
+	u32 memory_handle;
+	u32 length;
+};
+
+struct indirect_descriptor {
+	struct memory_descriptor head;
+	u32 total_length;
+	struct memory_descriptor list[1] PACKED;
+};
+
+struct srp_generic {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+};
+
+struct srp_login_req {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+	u32 max_requested_initiator_to_target_iulen;
+	u32 reserved2;
+	u16 required_buffer_formats;
+	u8 reserved3:6;
+	u8 multi_channel_action:2;
+	u8 reserved4;
+	u32 reserved5;
+	u8 initiator_port_identifier[16];
+	u8 target_port_identifier[16];
+};
+
+struct srp_login_rsp {
+	u8 type;
+	u8 reserved1[3];
+	u32 request_limit_delta;
+	u64 tag;
+	u32 max_initiator_to_target_iulen;
+	u32 max_target_to_initiator_iulen;
+	u16 supported_buffer_formats;
+	u8 reserved2:6;
+	u8 multi_channel_result:2;
+	u8 reserved3;
+	u8 reserved4[24];
+};
+
+struct srp_login_rej {
+	u8 type;
+	u8 reserved1[3];
+	u32 reason;
+	u64 tag;
+	u64 reserved2;
+	u16 supported_buffer_formats;
+	u8 reserved3[6];
+};
+
+struct srp_i_logout {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+};
+
+struct srp_t_logout {
+	u8 type;
+	u8 reserved1[3];
+	u32 reason;
+	u64 tag;
+};
+
+struct srp_tsk_mgmt {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+	u32 reserved2;
+	u64 lun PACKED;
+	u8 reserved3;
+	u8 reserved4;
+	u8 task_mgmt_flags;
+	u8 reserved5;
+	u64 managed_task_tag;
+	u64 reserved6;
+};
+
+struct srp_cmd {
+	u8 type;
+	u32 reserved1 PACKED;
+	u8 data_out_format:4;
+	u8 data_in_format:4;
+	u8 data_out_count;
+	u8 data_in_count;
+	u64 tag;
+	u32 reserved2;
+	u64 lun PACKED;
+	u8 reserved3;
+	u8 reserved4:5;
+	u8 task_attribute:3;
+	u8 reserved5;
+	u8 additional_cdb_len;
+	u8 cdb[16];
+	u8 additional_data[0x100 - 0x30];
+};
+
+struct srp_rsp {
+	u8 type;
+	u8 reserved1[3];
+	u32 request_limit_delta;
+	u64 tag;
+	u16 reserved2;
+	u8 reserved3:2;
+	u8 diunder:1;
+	u8 diover:1;
+	u8 dounder:1;
+	u8 doover:1;
+	u8 snsvalid:1;
+	u8 rspvalid:1;
+	u8 status;
+	u32 data_in_residual_count;
+	u32 data_out_residual_count;
+	u32 sense_data_list_length;
+	u32 response_data_list_length;
+	u8 sense_and_response_data[18];
+};
+
+struct srp_cred_req {
+	u8 type;
+	u8 reserved1[3];
+	u32 request_limit_delta;
+	u64 tag;
+};
+
+struct srp_cred_rsp {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+};
+
+struct srp_aer_req {
+	u8 type;
+	u8 reserved1[3];
+	u32 request_limit_delta;
+	u64 tag;
+	u32 reserved2;
+	u64 lun;
+	u32 sense_data_list_length;
+	u32 reserved3;
+	u8 sense_data[20];
+};
+
+struct srp_aer_rsp {
+	u8 type;
+	u8 reserved1[7];
+	u64 tag;
+};
+
+union srp_iu {
+	struct srp_generic generic;
+	struct srp_login_req login_req;
+	struct srp_login_rsp login_rsp;
+	struct srp_login_rej login_rej;
+	struct srp_i_logout i_logout;
+	struct srp_t_logout t_logout;
+	struct srp_tsk_mgmt tsk_mgmt;
+	struct srp_cmd cmd;
+	struct srp_rsp rsp;
+	struct srp_cred_req cred_req;
+	struct srp_cred_rsp cred_rsp;
+	struct srp_aer_req aer_req;
+	struct srp_aer_rsp aer_rsp;
+};
+
+#endif
diff --git a/drivers/scsi/ibmvscsi/viosrp.h b/drivers/scsi/ibmvscsi/viosrp.h
new file mode 100644
index 0000000..6a6bba8
--- /dev/null
+++ b/drivers/scsi/ibmvscsi/viosrp.h
@@ -0,0 +1,126 @@
+/*****************************************************************************/
+/* srp.h -- SCSI RDMA Protocol definitions                                   */
+/*                                                                           */
+/* Written By: Colin Devilbis, IBM Corporation                               */
+/*                                                                           */
+/* Copyright (C) 2003 IBM Corporation                                        */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/*                                                                           */
+/* This file contains structures and definitions for IBM RPA (RS/6000        */
+/* platform architecture) implementation of the SRP (SCSI RDMA Protocol)     */
+/* standard.  SRP is used on IBM iSeries and pSeries platforms to send SCSI  */
+/* commands between logical partitions.                                      */
+/*                                                                           */
+/* SRP Information Units (IUs) are sent on a "Command/Response Queue" (CRQ)  */
+/* between partitions.  The definitions in this file are architected,        */
+/* and cannot be changed without breaking compatibility with other versions  */
+/* of Linux and other operating systems (AIX, OS/400) that talk this protocol*/
+/* between logical partitions                                                */
+/*****************************************************************************/
+#ifndef VIOSRP_H
+#define VIOSRP_H
+#include "srp.h"
+
+enum viosrp_crq_formats {
+	VIOSRP_SRP_FORMAT = 0x01,
+	VIOSRP_MAD_FORMAT = 0x02,
+	VIOSRP_OS400_FORMAT = 0x03,
+	VIOSRP_AIX_FORMAT = 0x04,
+	VIOSRP_LINUX_FORMAT = 0x06,
+	VIOSRP_INLINE_FORMAT = 0x07
+};
+
+struct viosrp_crq {
+	u8 valid;		/* used by RPA */
+	u8 format;		/* SCSI vs out-of-band */
+	u8 reserved;
+	u8 status;		/* non-scsi failure? (e.g. DMA failure) */
+	u16 timeout;		/* in seconds */
+	u16 IU_length;		/* in bytes */
+	u64 IU_data_ptr;	/* the TCE for transferring data */
+};
+
+/* MADs are Management requests above and beyond the IUs defined in the SRP
+ * standard.  
+ */
+enum viosrp_mad_types {
+	VIOSRP_EMPTY_IU_TYPE = 0x01,
+	VIOSRP_ERROR_LOG_TYPE = 0x02,
+	VIOSRP_ADAPTER_INFO_TYPE = 0x03,
+	VIOSRP_HOST_CONFIG_TYPE = 0x04
+};
+
+/* 
+ * Common MAD header
+ */
+struct mad_common {
+	u32 type;
+	u16 status;
+	u16 length;
+	u64 tag;
+};
+
+/*
+ * All SRP (and MAD) requests normally flow from the
+ * client to the server.  There is no way for the server to send
+ * an asynchronous message back to the client.  The Empty IU is used
+ * to hang out a meaningless request to the server so that it can respond
+ * asynchrouously with something like a SCSI AER 
+ */
+struct viosrp_empty_iu {
+	struct mad_common common;
+	u64 buffer;
+	u32 port;
+};
+
+struct viosrp_error_log {
+	struct mad_common common;
+	u64 buffer;
+};
+
+struct viosrp_adapter_info {
+	struct mad_common common;
+	u64 buffer;
+};
+
+struct viosrp_host_config {
+	struct mad_common common;
+	u64 buffer;
+};
+
+union mad_iu {
+	struct viosrp_empty_iu empty_iu;
+	struct viosrp_error_log error_log;
+	struct viosrp_adapter_info adapter_info;
+	struct viosrp_host_config host_config;
+};
+
+union viosrp_iu {
+	union srp_iu srp;
+	union mad_iu mad;
+};
+
+struct mad_adapter_info_data {
+	char srp_version[8];
+	char partition_name[96];
+	u32 partition_number;
+	u32 mad_version;
+	u32 os_type;
+	u32 port_max_txu[8];	/* per-port maximum transfer */
+};
+
+#endif
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
new file mode 100644
index 0000000..2e2486b
--- /dev/null
+++ b/drivers/scsi/ide-scsi.c
@@ -0,0 +1,1174 @@
+/*
+ * linux/drivers/scsi/ide-scsi.c	Version 0.9		Jul   4, 1999
+ *
+ * Copyright (C) 1996 - 1999 Gadi Oxman <gadio@netvision.net.il>
+ */
+
+/*
+ * Emulation of a SCSI host adapter for IDE ATAPI devices.
+ *
+ * With this driver, one can use the Linux SCSI drivers instead of the
+ * native IDE ATAPI drivers.
+ *
+ * Ver 0.1   Dec  3 96   Initial version.
+ * Ver 0.2   Jan 26 97   Fixed bug in cleanup_module() and added emulation
+ *                        of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
+ *                        to Janos Farkas for pointing this out.
+ *                       Avoid using bitfields in structures for m68k.
+ *                       Added Scatter/Gather and DMA support.
+ * Ver 0.4   Dec  7 97   Add support for ATAPI PD/CD drives.
+ *                       Use variable timeout for each command.
+ * Ver 0.5   Jan  2 98   Fix previous PD/CD support.
+ *                       Allow disabling of SCSI-6 to SCSI-10 transformation.
+ * Ver 0.6   Jan 27 98   Allow disabling of SCSI command translation layer
+ *                        for access through /dev/sg.
+ *                       Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
+ * Ver 0.7   Dec 04 98   Ignore commands where lun != 0 to avoid multiple
+ *                        detection of devices with CONFIG_SCSI_MULTI_LUN
+ * Ver 0.8   Feb 05 99   Optical media need translation too. Reverse 0.7.
+ * Ver 0.9   Jul 04 99   Fix a bug in SG_SET_TRANSFORM.
+ * Ver 0.91  Jun 10 02   Fix "off by one" error in transforms
+ * Ver 0.92  Dec 31 02   Implement new SCSI mid level API
+ */
+
+#define IDESCSI_VERSION "0.92"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/errno.h>
+#include <linux/hdreg.h>
+#include <linux/slab.h>
+#include <linux/ide.h>
+#include <linux/scatterlist.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/sg.h>
+
+#define IDESCSI_DEBUG_LOG		0
+
+typedef struct idescsi_pc_s {
+	u8 c[12];				/* Actual packet bytes */
+	int request_transfer;			/* Bytes to transfer */
+	int actually_transferred;		/* Bytes actually transferred */
+	int buffer_size;			/* Size of our data buffer */
+	struct request *rq;			/* The corresponding request */
+	u8 *buffer;				/* Data buffer */
+	u8 *current_position;			/* Pointer into the above buffer */
+	struct scatterlist *sg;			/* Scatter gather table */
+	int b_count;				/* Bytes transferred from current entry */
+	struct scsi_cmnd *scsi_cmd;		/* SCSI command */
+	void (*done)(struct scsi_cmnd *);	/* Scsi completion routine */
+	unsigned long flags;			/* Status/Action flags */
+	unsigned long timeout;			/* Command timeout */
+} idescsi_pc_t;
+
+/*
+ *	Packet command status bits.
+ */
+#define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
+#define PC_WRITING			1	/* Data direction */
+#define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_TIMEDOUT			3	/* command timed out */
+#define PC_DMA_OK			4	/* Use DMA */
+
+/*
+ *	SCSI command transformation layer
+ */
+#define IDESCSI_TRANSFORM		0	/* Enable/Disable transformation */
+#define IDESCSI_SG_TRANSFORM		1	/* /dev/sg transformation */
+
+/*
+ *	Log flags
+ */
+#define IDESCSI_LOG_CMD			0	/* Log SCSI commands */
+
+typedef struct ide_scsi_obj {
+	ide_drive_t		*drive;
+	ide_driver_t		*driver;
+	struct gendisk		*disk;
+	struct Scsi_Host	*host;
+
+	idescsi_pc_t *pc;			/* Current packet command */
+	unsigned long flags;			/* Status/Action flags */
+	unsigned long transform;		/* SCSI cmd translation layer */
+	unsigned long log;			/* log flags */
+} idescsi_scsi_t;
+
+static DECLARE_MUTEX(idescsi_ref_sem);
+
+#define ide_scsi_g(disk) \
+	container_of((disk)->private_data, struct ide_scsi_obj, driver)
+
+static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk)
+{
+	struct ide_scsi_obj *scsi = NULL;
+
+	down(&idescsi_ref_sem);
+	scsi = ide_scsi_g(disk);
+	if (scsi)
+		scsi_host_get(scsi->host);
+	up(&idescsi_ref_sem);
+	return scsi;
+}
+
+static void ide_scsi_put(struct ide_scsi_obj *scsi)
+{
+	down(&idescsi_ref_sem);
+	scsi_host_put(scsi->host);
+	up(&idescsi_ref_sem);
+}
+
+static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
+{
+	return (idescsi_scsi_t*) (&host[1]);
+}
+
+static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive)
+{
+	return scsihost_to_idescsi(ide_drive->driver_data);
+}
+
+/*
+ *	Per ATAPI device status bits.
+ */
+#define IDESCSI_DRQ_INTERRUPT		0	/* DRQ interrupt device */
+
+/*
+ *	ide-scsi requests.
+ */
+#define IDESCSI_PC_RQ			90
+
+static void idescsi_discard_data (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		(void) HWIF(drive)->INB(IDE_DATA_REG);
+}
+
+static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
+{
+	while (bcount--)
+		HWIF(drive)->OUTB(0, IDE_DATA_REG);
+}
+
+/*
+ *	PIO data transfer routines using the scatter gather table.
+ */
+static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
+{
+	int count;
+	char *buf;
+
+	while (bcount) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+			printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
+			idescsi_discard_data (drive, bcount);
+			return;
+		}
+		count = min(pc->sg->length - pc->b_count, bcount);
+		buf = page_address(pc->sg->page) + pc->sg->offset;
+		drive->hwif->atapi_input_bytes(drive, buf + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
+		}
+	}
+}
+
+static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
+{
+	int count;
+	char *buf;
+
+	while (bcount) {
+		if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
+			printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
+			idescsi_output_zeros (drive, bcount);
+			return;
+		}
+		count = min(pc->sg->length - pc->b_count, bcount);
+		buf = page_address(pc->sg->page) + pc->sg->offset;
+		drive->hwif->atapi_output_bytes(drive, buf + pc->b_count, count);
+		bcount -= count; pc->b_count += count;
+		if (pc->b_count == pc->sg->length) {
+			pc->sg++;
+			pc->b_count = 0;
+		}
+	}
+}
+
+/*
+ *	Most of the SCSI commands are supported directly by ATAPI devices.
+ *	idescsi_transform_pc handles the few exceptions.
+ */
+static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	u8 *c = pc->c, *scsi_buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
+	char *atapi_buf;
+
+	if (!test_bit(PC_TRANSFORM, &pc->flags))
+		return;
+	if (drive->media == ide_cdrom || drive->media == ide_optical) {
+		if (c[0] == READ_6 || c[0] == WRITE_6) {
+			c[8] = c[4];		c[5] = c[3];		c[4] = c[2];
+			c[3] = c[1] & 0x1f;	c[2] = 0;		c[1] &= 0xe0;
+			c[0] += (READ_10 - READ_6);
+		}
+		if (c[0] == MODE_SENSE || c[0] == MODE_SELECT) {
+			unsigned short new_len;
+			if (!scsi_buf)
+				return;
+			if ((atapi_buf = kmalloc(pc->buffer_size + 4, GFP_ATOMIC)) == NULL)
+				return;
+			memset(atapi_buf, 0, pc->buffer_size + 4);
+			memset (c, 0, 12);
+			c[0] = sc[0] | 0x40;
+			c[1] = sc[1];
+			c[2] = sc[2];
+			new_len = sc[4] + 4;
+			c[8] = new_len;
+			c[7] = new_len >> 8;
+			c[9] = sc[5];
+			if (c[0] == MODE_SELECT_10) {
+				atapi_buf[1] = scsi_buf[0];	/* Mode data length */
+				atapi_buf[2] = scsi_buf[1];	/* Medium type */
+				atapi_buf[3] = scsi_buf[2];	/* Device specific parameter */
+				atapi_buf[7] = scsi_buf[3];	/* Block descriptor length */
+				memcpy(atapi_buf + 8, scsi_buf + 4, pc->buffer_size - 4);
+			}
+			pc->buffer = atapi_buf;
+			pc->request_transfer += 4;
+			pc->buffer_size += 4;
+		}
+	}
+}
+
+static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	u8 *atapi_buf = pc->buffer;
+	u8 *sc = pc->scsi_cmd->cmnd;
+	u8 *scsi_buf = pc->scsi_cmd->request_buffer;
+
+	if (!test_bit(PC_TRANSFORM, &pc->flags))
+		return;
+	if (drive->media == ide_cdrom || drive->media == ide_optical) {
+		if (pc->c[0] == MODE_SENSE_10 && sc[0] == MODE_SENSE) {
+			scsi_buf[0] = atapi_buf[1];		/* Mode data length */
+			scsi_buf[1] = atapi_buf[2];		/* Medium type */
+			scsi_buf[2] = atapi_buf[3];		/* Device specific parameter */
+			scsi_buf[3] = atapi_buf[7];		/* Block descriptor length */
+			memcpy(scsi_buf + 4, atapi_buf + 8, pc->request_transfer - 8);
+		}
+		if (pc->c[0] == INQUIRY) {
+			scsi_buf[2] |= 2;			/* ansi_revision */
+			scsi_buf[3] = (scsi_buf[3] & 0xf0) | 2;	/* response data format */
+		}
+	}
+	if (atapi_buf && atapi_buf != scsi_buf)
+		kfree(atapi_buf);
+}
+
+static void hexdump(u8 *x, int len)
+{
+	int i;
+
+	printk("[ ");
+	for (i = 0; i < len; i++)
+		printk("%x ", x[i]);
+	printk("]\n");
+}
+
+static int idescsi_check_condition(ide_drive_t *drive, struct request *failed_command)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+	idescsi_pc_t   *pc;
+	struct request *rq;
+	u8             *buf;
+
+	/* stuff a sense request in front of our current request */
+	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
+	buf = kmalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
+	if (pc == NULL || rq == NULL || buf == NULL) {
+		if (pc) kfree(pc);
+		if (rq) kfree(rq);
+		if (buf) kfree(buf);
+		return -ENOMEM;
+	}
+	memset (pc, 0, sizeof (idescsi_pc_t));
+	memset (buf, 0, SCSI_SENSE_BUFFERSIZE);
+	ide_init_drive_cmd(rq);
+	rq->special = (char *) pc;
+	pc->rq = rq;
+	pc->buffer = buf;
+	pc->c[0] = REQUEST_SENSE;
+	pc->c[4] = pc->request_transfer = pc->buffer_size = SCSI_SENSE_BUFFERSIZE;
+	rq->flags = REQ_SENSE;
+	pc->timeout = jiffies + WAIT_READY;
+	/* NOTE! Save the failed packet command in "rq->buffer" */
+	rq->buffer = (void *) failed_command->special;
+	pc->scsi_cmd = ((idescsi_pc_t *) failed_command->special)->scsi_cmd;
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+		printk ("ide-scsi: %s: queue cmd = ", drive->name);
+		hexdump(pc->c, 6);
+	}
+	rq->rq_disk = scsi->disk;
+	return ide_do_drive_cmd(drive, rq, ide_preempt);
+}
+
+static int idescsi_end_request(ide_drive_t *, int, int);
+
+static ide_startstop_t
+idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
+{
+	if (HWIF(drive)->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT))
+		/* force an abort */
+		HWIF(drive)->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);
+
+	rq->errors++;
+
+	idescsi_end_request(drive, 0, 0);
+
+	return ide_stopped;
+}
+
+static ide_startstop_t
+idescsi_atapi_abort(ide_drive_t *drive, struct request *rq)
+{
+#if IDESCSI_DEBUG_LOG
+	printk(KERN_WARNING "idescsi_atapi_abort called for %lu\n",
+			((idescsi_pc_t *) rq->special)->scsi_cmd->serial_number);
+#endif
+	rq->errors |= ERROR_MAX;
+
+	idescsi_end_request(drive, 0, 0);
+
+	return ide_stopped;
+}
+
+static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+	struct request *rq = HWGROUP(drive)->rq;
+	idescsi_pc_t *pc = (idescsi_pc_t *) rq->special;
+	int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
+	struct Scsi_Host *host;
+	u8 *scsi_buf;
+	unsigned long flags;
+
+	if (!(rq->flags & (REQ_SPECIAL|REQ_SENSE))) {
+		ide_end_request(drive, uptodate, nrsecs);
+		return 0;
+	}
+	ide_end_drive_cmd (drive, 0, 0);
+	if (rq->flags & REQ_SENSE) {
+		idescsi_pc_t *opc = (idescsi_pc_t *) rq->buffer;
+		if (log) {
+			printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);
+			hexdump(pc->buffer,16);
+		}
+		memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buffer, SCSI_SENSE_BUFFERSIZE);
+		kfree(pc->buffer);
+		kfree(pc);
+		kfree(rq);
+		pc = opc;
+		rq = pc->rq;
+		pc->scsi_cmd->result = (CHECK_CONDITION << 1) |
+					((test_bit(PC_TIMEDOUT, &pc->flags)?DID_TIME_OUT:DID_OK) << 16);
+	} else if (test_bit(PC_TIMEDOUT, &pc->flags)) {
+		if (log)
+			printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n",
+					drive->name, pc->scsi_cmd->serial_number);
+		pc->scsi_cmd->result = DID_TIME_OUT << 16;
+	} else if (rq->errors >= ERROR_MAX) {
+		pc->scsi_cmd->result = DID_ERROR << 16;
+		if (log)
+			printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+	} else if (rq->errors) {
+		if (log)
+			printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
+		if (!idescsi_check_condition(drive, rq))
+			/* we started a request sense, so we'll be back, exit for now */
+			return 0;
+		pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+	} else {
+		pc->scsi_cmd->result = DID_OK << 16;
+		idescsi_transform_pc2 (drive, pc);
+		if (log) {
+			printk ("ide-scsi: %s: suc %lu", drive->name, pc->scsi_cmd->serial_number);
+			if (!test_bit(PC_WRITING, &pc->flags) && pc->actually_transferred && pc->actually_transferred <= 1024 && pc->buffer) {
+				printk(", rst = ");
+				scsi_buf = pc->scsi_cmd->request_buffer;
+				hexdump(scsi_buf, min_t(unsigned, 16, pc->scsi_cmd->request_bufflen));
+			} else printk("\n");
+		}
+	}
+	host = pc->scsi_cmd->device->host;
+	spin_lock_irqsave(host->host_lock, flags);
+	pc->done(pc->scsi_cmd);
+	spin_unlock_irqrestore(host->host_lock, flags);
+	kfree(pc);
+	kfree(rq);
+	scsi->pc = NULL;
+	return 0;
+}
+
+static inline unsigned long get_timeout(idescsi_pc_t *pc)
+{
+	return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
+}
+
+static int idescsi_expiry(ide_drive_t *drive)
+{
+	idescsi_scsi_t *scsi = drive->driver_data;
+	idescsi_pc_t   *pc   = scsi->pc;
+
+#if IDESCSI_DEBUG_LOG
+	printk(KERN_WARNING "idescsi_expiry called for %lu at %lu\n", pc->scsi_cmd->serial_number, jiffies);
+#endif
+	set_bit(PC_TIMEDOUT, &pc->flags);
+
+	return 0;					/* we do not want the ide subsystem to retry */
+}
+
+/*
+ *	Our interrupt handler.
+ */
+static ide_startstop_t idescsi_pc_intr (ide_drive_t *drive)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+	idescsi_pc_t *pc=scsi->pc;
+	struct request *rq = pc->rq;
+	atapi_bcount_t bcount;
+	atapi_status_t status;
+	atapi_ireason_t ireason;
+	atapi_feature_t feature;
+
+	unsigned int temp;
+
+#if IDESCSI_DEBUG_LOG
+	printk (KERN_INFO "ide-scsi: Reached idescsi_pc_intr interrupt handler\n");
+#endif /* IDESCSI_DEBUG_LOG */
+
+	if (test_bit(PC_TIMEDOUT, &pc->flags)){
+#if IDESCSI_DEBUG_LOG
+		printk(KERN_WARNING "idescsi_pc_intr: got timed out packet  %lu at %lu\n",
+				pc->scsi_cmd->serial_number, jiffies);
+#endif
+		/* end this request now - scsi should retry it*/
+		idescsi_end_request (drive, 1, 0);
+		return ide_stopped;
+	}
+	if (test_and_clear_bit (PC_DMA_IN_PROGRESS, &pc->flags)) {
+#if IDESCSI_DEBUG_LOG
+		printk ("ide-scsi: %s: DMA complete\n", drive->name);
+#endif /* IDESCSI_DEBUG_LOG */
+		pc->actually_transferred=pc->request_transfer;
+		(void) HWIF(drive)->ide_dma_end(drive);
+	}
+
+	feature.all = 0;
+	/* Clear the interrupt */
+	status.all = HWIF(drive)->INB(IDE_STATUS_REG);
+
+	if (!status.b.drq) {
+		/* No more interrupts */
+		if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+			printk (KERN_INFO "Packet command completed, %d bytes transferred\n", pc->actually_transferred);
+		local_irq_enable();
+		if (status.b.check)
+			rq->errors++;
+		idescsi_end_request (drive, 1, 0);
+		return ide_stopped;
+	}
+	bcount.b.low	= HWIF(drive)->INB(IDE_BCOUNTL_REG);
+	bcount.b.high	= HWIF(drive)->INB(IDE_BCOUNTH_REG);
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+
+	if (ireason.b.cod) {
+		printk(KERN_ERR "ide-scsi: CoD != 0 in idescsi_pc_intr\n");
+		return ide_do_reset (drive);
+	}
+	if (ireason.b.io) {
+		temp = pc->actually_transferred + bcount.all;
+		if (temp > pc->request_transfer) {
+			if (temp > pc->buffer_size) {
+				printk(KERN_ERR "ide-scsi: The scsi wants to "
+					"send us more data than expected "
+					"- discarding data\n");
+				temp = pc->buffer_size - pc->actually_transferred;
+				if (temp) {
+					clear_bit(PC_WRITING, &pc->flags);
+					if (pc->sg)
+						idescsi_input_buffers(drive, pc, temp);
+					else
+						drive->hwif->atapi_input_bytes(drive, pc->current_position, temp);
+					printk(KERN_ERR "ide-scsi: transferred %d of %d bytes\n", temp, bcount.all);
+				}
+				pc->actually_transferred += temp;
+				pc->current_position += temp;
+				idescsi_discard_data(drive, bcount.all - temp);
+				ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+				return ide_started;
+			}
+#if IDESCSI_DEBUG_LOG
+			printk (KERN_NOTICE "ide-scsi: The scsi wants to send us more data than expected - allowing transfer\n");
+#endif /* IDESCSI_DEBUG_LOG */
+		}
+	}
+	if (ireason.b.io) {
+		clear_bit(PC_WRITING, &pc->flags);
+		if (pc->sg)
+			idescsi_input_buffers(drive, pc, bcount.all);
+		else
+			HWIF(drive)->atapi_input_bytes(drive, pc->current_position, bcount.all);
+	} else {
+		set_bit(PC_WRITING, &pc->flags);
+		if (pc->sg)
+			idescsi_output_buffers (drive, pc, bcount.all);
+		else
+			HWIF(drive)->atapi_output_bytes(drive, pc->current_position, bcount.all);
+	}
+	/* Update the current position */
+	pc->actually_transferred += bcount.all;
+	pc->current_position += bcount.all;
+
+	/* And set the interrupt handler again */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+	return ide_started;
+}
+
+static ide_startstop_t idescsi_transfer_pc(ide_drive_t *drive)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+	idescsi_pc_t *pc = scsi->pc;
+	atapi_ireason_t ireason;
+	ide_startstop_t startstop;
+
+	if (ide_wait_stat(&startstop,drive,DRQ_STAT,BUSY_STAT,WAIT_READY)) {
+		printk(KERN_ERR "ide-scsi: Strange, packet command "
+			"initiated yet DRQ isn't asserted\n");
+		return startstop;
+	}
+	ireason.all	= HWIF(drive)->INB(IDE_IREASON_REG);
+	if (!ireason.b.cod || ireason.b.io) {
+		printk(KERN_ERR "ide-scsi: (IO,CoD) != (0,1) while "
+				"issuing a packet command\n");
+		return ide_do_reset (drive);
+	}
+	if (HWGROUP(drive)->handler != NULL)
+		BUG();
+	/* Set the interrupt routine */
+	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), idescsi_expiry);
+	/* Send the actual packet */
+	drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12);
+	if (test_bit (PC_DMA_OK, &pc->flags)) {
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		hwif->dma_start(drive);
+	}
+	return ide_started;
+}
+
+static inline int idescsi_set_direction(idescsi_pc_t *pc)
+{
+	switch (pc->c[0]) {
+		case READ_6: case READ_10: case READ_12:
+			clear_bit(PC_WRITING, &pc->flags);
+			return 0;
+		case WRITE_6: case WRITE_10: case WRITE_12:
+			set_bit(PC_WRITING, &pc->flags);
+			return 0;
+		default:
+			return 1;
+	}
+}
+
+static int idescsi_map_sg(ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	ide_hwif_t *hwif = drive->hwif;
+	struct scatterlist *sg, *scsi_sg;
+	int segments;
+
+	if (!pc->request_transfer || pc->request_transfer % 1024)
+		return 1;
+
+	if (idescsi_set_direction(pc))
+		return 1;
+
+	sg = hwif->sg_table;
+	scsi_sg = pc->scsi_cmd->request_buffer;
+	segments = pc->scsi_cmd->use_sg;
+
+	if (segments > hwif->sg_max_nents)
+		return 1;
+
+	if (!segments) {
+		hwif->sg_nents = 1;
+		sg_init_one(sg, pc->scsi_cmd->request_buffer, pc->request_transfer);
+	} else {
+		hwif->sg_nents = segments;
+		memcpy(sg, scsi_sg, sizeof(*sg) * segments);
+	}
+
+	return 0;
+}
+
+/*
+ *	Issue a packet command
+ */
+static ide_startstop_t idescsi_issue_pc (ide_drive_t *drive, idescsi_pc_t *pc)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+	ide_hwif_t *hwif = drive->hwif;
+	atapi_feature_t feature;
+	atapi_bcount_t bcount;
+
+	scsi->pc=pc;							/* Set the current packet command */
+	pc->actually_transferred=0;					/* We haven't transferred any data yet */
+	pc->current_position=pc->buffer;
+	bcount.all = min(pc->request_transfer, 63 * 1024);		/* Request to transfer the entire buffer at once */
+
+	feature.all = 0;
+	if (drive->using_dma && !idescsi_map_sg(drive, pc)) {
+		hwif->sg_mapped = 1;
+		feature.b.dma = !hwif->dma_setup(drive);
+		hwif->sg_mapped = 0;
+	}
+
+	SELECT_DRIVE(drive);
+	if (IDE_CONTROL_REG)
+		HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG);
+
+	HWIF(drive)->OUTB(feature.all, IDE_FEATURE_REG);
+	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
+	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
+
+	if (feature.b.dma)
+		set_bit(PC_DMA_OK, &pc->flags);
+
+	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
+		if (HWGROUP(drive)->handler != NULL)
+			BUG();
+		ide_set_handler(drive, &idescsi_transfer_pc,
+				get_timeout(pc), idescsi_expiry);
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return ide_started;
+	} else {
+		/* Issue the packet command */
+		HWIF(drive)->OUTB(WIN_PACKETCMD, IDE_COMMAND_REG);
+		return idescsi_transfer_pc(drive);
+	}
+}
+
+/*
+ *	idescsi_do_request is our request handling function.
+ */
+static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
+{
+#if IDESCSI_DEBUG_LOG
+	printk (KERN_INFO "rq_status: %d, dev: %s, cmd: %x, errors: %d\n",rq->rq_status, rq->rq_disk->disk_name,rq->cmd[0],rq->errors);
+	printk (KERN_INFO "sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",rq->sector,rq->nr_sectors,rq->current_nr_sectors);
+#endif /* IDESCSI_DEBUG_LOG */
+
+	if (rq->flags & (REQ_SPECIAL|REQ_SENSE)) {
+		return idescsi_issue_pc (drive, (idescsi_pc_t *) rq->special);
+	}
+	blk_dump_rq_flags(rq, "ide-scsi: unsup command");
+	idescsi_end_request (drive, 0, 0);
+	return ide_stopped;
+}
+
+static void idescsi_add_settings(ide_drive_t *drive)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+
+/*
+ *			drive	setting name	read/write	ioctl	ioctl		data type	min	max	mul_factor	div_factor	data pointer		set function
+ */
+	ide_add_setting(drive,	"bios_cyl",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1023,	1,		1,		&drive->bios_cyl,	NULL);
+	ide_add_setting(drive,	"bios_head",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	255,	1,		1,		&drive->bios_head,	NULL);
+	ide_add_setting(drive,	"bios_sect",	SETTING_RW,	-1,	-1,		TYPE_BYTE,	0,	63,	1,		1,		&drive->bios_sect,	NULL);
+	ide_add_setting(drive,	"transform",	SETTING_RW,	-1,	-1,		TYPE_INT,	0,	3,	1,		1,		&scsi->transform,	NULL);
+	ide_add_setting(drive,	"log",		SETTING_RW,	-1,	-1,		TYPE_INT,	0,	1,	1,		1,		&scsi->log,		NULL);
+}
+
+/*
+ *	Driver initialization.
+ */
+static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
+{
+	DRIVER(drive)->busy++;
+	if (drive->id && (drive->id->config & 0x0060) == 0x20)
+		set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+	set_bit(IDESCSI_TRANSFORM, &scsi->transform);
+	clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+#if IDESCSI_DEBUG_LOG
+	set_bit(IDESCSI_LOG_CMD, &scsi->log);
+#endif /* IDESCSI_DEBUG_LOG */
+	idescsi_add_settings(drive);
+	DRIVER(drive)->busy--;
+}
+
+static int idescsi_cleanup (ide_drive_t *drive)
+{
+	struct Scsi_Host *scsihost = drive->driver_data;
+	struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
+	struct gendisk *g = scsi->disk;
+
+	if (ide_unregister_subdriver(drive))
+		return 1;
+
+	ide_unregister_region(g);
+
+	drive->driver_data = NULL;
+	g->private_data = NULL;
+	put_disk(g);
+
+	scsi_remove_host(scsihost);
+	ide_scsi_put(scsi);
+
+	return 0;
+}
+
+static int idescsi_attach(ide_drive_t *drive);
+
+#ifdef CONFIG_PROC_FS
+static ide_proc_entry_t idescsi_proc[] = {
+	{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
+	{ NULL, 0, NULL, NULL }
+};
+#else
+# define idescsi_proc	NULL
+#endif
+
+/*
+ *	IDE subdriver functions, registered with ide.c
+ */
+static ide_driver_t idescsi_driver = {
+	.owner			= THIS_MODULE,
+	.name			= "ide-scsi",
+	.version		= IDESCSI_VERSION,
+	.media			= ide_scsi,
+	.busy			= 0,
+	.supports_dsc_overlap	= 0,
+	.proc			= idescsi_proc,
+	.attach			= idescsi_attach,
+	.cleanup		= idescsi_cleanup,
+	.do_request		= idescsi_do_request,
+	.end_request		= idescsi_end_request,
+	.error                  = idescsi_atapi_error,
+	.abort                  = idescsi_atapi_abort,
+	.drives			= LIST_HEAD_INIT(idescsi_driver.drives),
+};
+
+static int idescsi_ide_open(struct inode *inode, struct file *filp)
+{
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_scsi_obj *scsi;
+	ide_drive_t *drive;
+
+	if (!(scsi = ide_scsi_get(disk)))
+		return -ENXIO;
+
+	drive = scsi->drive;
+
+	drive->usage++;
+
+	return 0;
+}
+
+static int idescsi_ide_release(struct inode *inode, struct file *filp)
+{
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct ide_scsi_obj *scsi = ide_scsi_g(disk);
+	ide_drive_t *drive = scsi->drive;
+
+	drive->usage--;
+
+	ide_scsi_put(scsi);
+
+	return 0;
+}
+
+static int idescsi_ide_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk);
+	return generic_ide_ioctl(scsi->drive, file, bdev, cmd, arg);
+}
+
+static struct block_device_operations idescsi_ops = {
+	.owner		= THIS_MODULE,
+	.open		= idescsi_ide_open,
+	.release	= idescsi_ide_release,
+	.ioctl		= idescsi_ide_ioctl,
+};
+
+static int idescsi_attach(ide_drive_t *drive);
+
+static int idescsi_slave_configure(struct scsi_device * sdp)
+{
+	/* Configure detected device */
+	scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
+	return 0;
+}
+
+static const char *idescsi_info (struct Scsi_Host *host)
+{
+	return "SCSI host adapter emulation for IDE ATAPI devices";
+}
+
+static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg)
+{
+	idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host);
+
+	if (cmd == SG_SET_TRANSFORM) {
+		if (arg)
+			set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+		else
+			clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+		return 0;
+	} else if (cmd == SG_GET_TRANSFORM)
+		return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg);
+	return -EINVAL;
+}
+
+static inline int should_transform(ide_drive_t *drive, struct scsi_cmnd *cmd)
+{
+	idescsi_scsi_t *scsi = drive_to_idescsi(drive);
+
+	/* this was a layering violation and we can't support it
+	   anymore, sorry. */
+#if 0
+	struct gendisk *disk = cmd->request->rq_disk;
+
+	if (disk) {
+		struct Scsi_Device_Template **p = disk->private_data;
+		if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0)
+			return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
+	}
+#endif
+	return test_bit(IDESCSI_TRANSFORM, &scsi->transform);
+}
+
+static int idescsi_queue (struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = cmd->device->host;
+	idescsi_scsi_t *scsi = scsihost_to_idescsi(host);
+	ide_drive_t *drive = scsi->drive;
+	struct request *rq = NULL;
+	idescsi_pc_t *pc = NULL;
+
+	if (!drive) {
+		printk (KERN_ERR "ide-scsi: drive id %d not present\n", cmd->device->id);
+		goto abort;
+	}
+	scsi = drive_to_idescsi(drive);
+	pc = kmalloc (sizeof (idescsi_pc_t), GFP_ATOMIC);
+	rq = kmalloc (sizeof (struct request), GFP_ATOMIC);
+	if (rq == NULL || pc == NULL) {
+		printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
+		goto abort;
+	}
+
+	memset (pc->c, 0, 12);
+	pc->flags = 0;
+	pc->rq = rq;
+	memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
+	if (cmd->use_sg) {
+		pc->buffer = NULL;
+		pc->sg = cmd->request_buffer;
+	} else {
+		pc->buffer = cmd->request_buffer;
+		pc->sg = NULL;
+	}
+	pc->b_count = 0;
+	pc->request_transfer = pc->buffer_size = cmd->request_bufflen;
+	pc->scsi_cmd = cmd;
+	pc->done = done;
+	pc->timeout = jiffies + cmd->timeout_per_command;
+
+	if (should_transform(drive, cmd))
+		set_bit(PC_TRANSFORM, &pc->flags);
+	idescsi_transform_pc1 (drive, pc);
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
+		printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
+		hexdump(cmd->cmnd, cmd->cmd_len);
+		if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
+			printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
+			hexdump(pc->c, 12);
+		}
+	}
+
+	ide_init_drive_cmd (rq);
+	rq->special = (char *) pc;
+	rq->flags = REQ_SPECIAL;
+	spin_unlock_irq(host->host_lock);
+	rq->rq_disk = scsi->disk;
+	(void) ide_do_drive_cmd (drive, rq, ide_end);
+	spin_lock_irq(host->host_lock);
+	return 0;
+abort:
+	if (pc) kfree (pc);
+	if (rq) kfree (rq);
+	cmd->result = DID_ERROR << 16;
+	done(cmd);
+	return 0;
+}
+
+static int idescsi_eh_abort (struct scsi_cmnd *cmd)
+{
+	idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
+	ide_drive_t    *drive = scsi->drive;
+	int		busy;
+	int             ret   = FAILED;
+
+	/* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number);
+
+	if (!drive) {
+		printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n");
+		WARN_ON(1);
+		goto no_drive;
+	}
+
+	/* First give it some more time, how much is "right" is hard to say :-( */
+
+	busy = ide_wait_not_busy(HWIF(drive), 100);	/* FIXME - uses mdelay which causes latency? */
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
+
+	spin_lock_irq(&ide_lock);
+
+	/* If there is no pc running we're done (our interrupt took care of it) */
+	if (!scsi->pc) {
+		ret = SUCCESS;
+		goto ide_unlock;
+	}
+
+	/* It's somewhere in flight. Does ide subsystem agree? */
+	if (scsi->pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
+	    elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != scsi->pc->rq) {
+		/*
+		 * FIXME - not sure this condition can ever occur
+		 */
+		printk (KERN_ERR "ide-scsi: cmd aborted!\n");
+
+		if (scsi->pc->rq->flags & REQ_SENSE)
+			kfree(scsi->pc->buffer);
+		kfree(scsi->pc->rq);
+		kfree(scsi->pc);
+		scsi->pc = NULL;
+
+		ret = SUCCESS;
+	}
+
+ide_unlock:
+	spin_unlock_irq(&ide_lock);
+no_drive:
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
+
+	return ret;
+}
+
+static int idescsi_eh_reset (struct scsi_cmnd *cmd)
+{
+	struct request *req;
+	idescsi_scsi_t *scsi  = scsihost_to_idescsi(cmd->device->host);
+	ide_drive_t    *drive = scsi->drive;
+	int             ready = 0;
+	int             ret   = SUCCESS;
+
+	/* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */
+
+	if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
+		printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number);
+
+	if (!drive) {
+		printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n");
+		WARN_ON(1);
+		return FAILED;
+	}
+
+	spin_lock_irq(&ide_lock);
+
+	if (!scsi->pc || (req = scsi->pc->rq) != HWGROUP(drive)->rq || !HWGROUP(drive)->handler) {
+		printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
+		spin_unlock(&ide_lock);
+		return FAILED;
+	}
+
+	/* kill current request */
+	blkdev_dequeue_request(req);
+	end_that_request_last(req);
+	if (req->flags & REQ_SENSE)
+		kfree(scsi->pc->buffer);
+	kfree(scsi->pc);
+	scsi->pc = NULL;
+	kfree(req);
+
+	/* now nuke the drive queue */
+	while ((req = elv_next_request(drive->queue))) {
+		blkdev_dequeue_request(req);
+		end_that_request_last(req);
+	}
+
+	HWGROUP(drive)->rq = NULL;
+	HWGROUP(drive)->handler = NULL;
+	HWGROUP(drive)->busy = 1;		/* will set this to zero when ide reset finished */
+	spin_unlock_irq(&ide_lock);
+
+	ide_do_reset(drive);
+
+	/* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */
+
+	do {
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		spin_unlock_irq(cmd->device->host->host_lock);
+		schedule_timeout(HZ/20);
+		spin_lock_irq(cmd->device->host->host_lock);
+	} while ( HWGROUP(drive)->handler );
+
+	ready = drive_is_ready(drive);
+	HWGROUP(drive)->busy--;
+	if (!ready) {
+		printk (KERN_ERR "ide-scsi: reset failed!\n");
+		ret = FAILED;
+	}
+
+	return ret;
+}
+
+static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int *parm)
+{
+	idescsi_scsi_t *idescsi = scsihost_to_idescsi(sdev->host);
+	ide_drive_t *drive = idescsi->drive;
+
+	if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
+		parm[0] = drive->bios_head;
+		parm[1] = drive->bios_sect;
+		parm[2] = drive->bios_cyl;
+	}
+	return 0;
+}
+
+static struct scsi_host_template idescsi_template = {
+	.module			= THIS_MODULE,
+	.name			= "idescsi",
+	.info			= idescsi_info,
+	.slave_configure        = idescsi_slave_configure,
+	.ioctl			= idescsi_ioctl,
+	.queuecommand		= idescsi_queue,
+	.eh_abort_handler	= idescsi_eh_abort,
+	.eh_host_reset_handler  = idescsi_eh_reset,
+	.bios_param		= idescsi_bios,
+	.can_queue		= 40,
+	.this_id		= -1,
+	.sg_tablesize		= 256,
+	.cmd_per_lun		= 5,
+	.max_sectors		= 128,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.emulated		= 1,
+	.proc_name		= "ide-scsi",
+};
+
+static int idescsi_attach(ide_drive_t *drive)
+{
+	idescsi_scsi_t *idescsi;
+	struct Scsi_Host *host;
+	struct gendisk *g;
+	static int warned;
+	int err = -ENOMEM;
+
+	if (!warned && drive->media == ide_cdrom) {
+		printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
+		warned = 1;
+	}
+
+	if (!strstr("ide-scsi", drive->driver_req) ||
+	    !drive->present ||
+	    drive->media == ide_disk ||
+	    !(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
+		return 1;
+
+	g = alloc_disk(1 << PARTN_BITS);
+	if (!g)
+		goto out_host_put;
+
+	ide_init_disk(g, drive);
+
+	host->max_id = 1;
+
+#if IDESCSI_DEBUG_LOG
+	if (drive->id->last_lun)
+		printk(KERN_NOTICE "%s: id->last_lun=%u\n", drive->name, drive->id->last_lun);
+#endif
+	if ((drive->id->last_lun & 0x7) != 7)
+		host->max_lun = (drive->id->last_lun & 0x7) + 1;
+	else
+		host->max_lun = 1;
+
+	drive->driver_data = host;
+	idescsi = scsihost_to_idescsi(host);
+	idescsi->drive = drive;
+	idescsi->driver = &idescsi_driver;
+	idescsi->host = host;
+	idescsi->disk = g;
+	g->private_data = &idescsi->driver;
+	err = ide_register_subdriver(drive, &idescsi_driver);
+	if (!err) {
+		idescsi_setup (drive, idescsi);
+		g->fops = &idescsi_ops;
+		ide_register_region(g);
+		err = scsi_add_host(host, &drive->gendev);
+		if (!err) {
+			scsi_scan_host(host);
+			return 0;
+		}
+		/* fall through on error */
+		ide_unregister_region(g);
+		ide_unregister_subdriver(drive);
+	}
+
+	put_disk(g);
+out_host_put:
+	scsi_host_put(host);
+	return err;
+}
+
+static int __init init_idescsi_module(void)
+{
+	return ide_register_driver(&idescsi_driver);
+}
+
+static void __exit exit_idescsi_module(void)
+{
+	ide_unregister_driver(&idescsi_driver);
+}
+
+module_init(init_idescsi_module);
+module_exit(exit_idescsi_module);
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
new file mode 100644
index 0000000..be7f2ca
--- /dev/null
+++ b/drivers/scsi/imm.c
@@ -0,0 +1,1300 @@
+/* imm.c   --  low level driver for the IOMEGA MatchMaker
+ * parallel port SCSI host adapter.
+ * 
+ * (The IMM is the embedded controller in the ZIP Plus drive.)
+ * 
+ * Current Maintainer: David Campbell (Perth, Western Australia)
+ *                     campbell@torque.net
+ *
+ * My unoffical company acronym list is 21 pages long:
+ *      FLA:    Four letter acronym with built in facility for
+ *              future expansion to five letters.
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/parport.h>
+#include <linux/workqueue.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+/* The following #define is to avoid a clash with hosts.c */
+#define IMM_PROBE_SPP   0x0001
+#define IMM_PROBE_PS2   0x0002
+#define IMM_PROBE_ECR   0x0010
+#define IMM_PROBE_EPP17 0x0100
+#define IMM_PROBE_EPP19 0x0200
+
+
+typedef struct {
+	struct pardevice *dev;	/* Parport device entry         */
+	int base;		/* Actual port address          */
+	int base_hi;		/* Hi Base address for ECP-ISA chipset */
+	int mode;		/* Transfer mode                */
+	struct scsi_cmnd *cur_cmd;	/* Current queued command       */
+	struct work_struct imm_tq;	/* Polling interrupt stuff       */
+	unsigned long jstart;	/* Jiffies at start             */
+	unsigned failed:1;	/* Failure flag                 */
+	unsigned dp:1;		/* Data phase present           */
+	unsigned rd:1;		/* Read data in data phase      */
+	unsigned wanted:1;	/* Parport sharing busy flag    */
+	wait_queue_head_t *waiting;
+	struct Scsi_Host *host;
+	struct list_head list;
+} imm_struct;
+
+static void imm_reset_pulse(unsigned int base);
+static int device_check(imm_struct *dev);
+
+#include "imm.h"
+
+static inline imm_struct *imm_dev(struct Scsi_Host *host)
+{
+	return *(imm_struct **)&host->hostdata;
+}
+
+static DEFINE_SPINLOCK(arbitration_lock);
+
+static void got_it(imm_struct *dev)
+{
+	dev->base = dev->dev->port->base;
+	if (dev->cur_cmd)
+		dev->cur_cmd->SCp.phase = 1;
+	else
+		wake_up(dev->waiting);
+}
+
+static void imm_wakeup(void *ref)
+{
+	imm_struct *dev = (imm_struct *) ref;
+	unsigned long flags;
+
+	spin_lock_irqsave(&arbitration_lock, flags);
+	if (dev->wanted) {
+		parport_claim(dev->dev);
+		got_it(dev);
+		dev->wanted = 0;
+	}
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+}
+
+static int imm_pb_claim(imm_struct *dev)
+{
+	unsigned long flags;
+	int res = 1;
+	spin_lock_irqsave(&arbitration_lock, flags);
+	if (parport_claim(dev->dev) == 0) {
+		got_it(dev);
+		res = 0;
+	}
+	dev->wanted = res;
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+	return res;
+}
+
+static void imm_pb_dismiss(imm_struct *dev)
+{
+	unsigned long flags;
+	int wanted;
+	spin_lock_irqsave(&arbitration_lock, flags);
+	wanted = dev->wanted;
+	dev->wanted = 0;
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+	if (!wanted)
+		parport_release(dev->dev);
+}
+
+static inline void imm_pb_release(imm_struct *dev)
+{
+	parport_release(dev->dev);
+}
+
+/* This is to give the imm driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/imm/0 file.
+ * Very simple method really... (Too simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+static inline int imm_proc_write(imm_struct *dev, char *buffer, int length)
+{
+	unsigned long x;
+
+	if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
+		x = simple_strtoul(buffer + 5, NULL, 0);
+		dev->mode = x;
+		return length;
+	}
+	printk("imm /proc: invalid variable\n");
+	return (-EINVAL);
+}
+
+static int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start,
+			off_t offset, int length, int inout)
+{
+	imm_struct *dev = imm_dev(host);
+	int len = 0;
+
+	if (inout)
+		return imm_proc_write(dev, buffer, length);
+
+	len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION);
+	len +=
+	    sprintf(buffer + len, "Parport : %s\n",
+		    dev->dev->port->name);
+	len +=
+	    sprintf(buffer + len, "Mode    : %s\n",
+		    IMM_MODE_STRING[dev->mode]);
+
+	/* Request for beyond end of buffer */
+	if (offset > len)
+		return 0;
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	return len;
+}
+
+#if IMM_DEBUG > 0
+#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
+	   y, __FUNCTION__, __LINE__); imm_fail_func(x,y);
+static inline void
+imm_fail_func(imm_struct *dev, int error_code)
+#else
+static inline void
+imm_fail(imm_struct *dev, int error_code)
+#endif
+{
+	/* If we fail a device then we trash status / message bytes */
+	if (dev->cur_cmd) {
+		dev->cur_cmd->result = error_code << 16;
+		dev->failed = 1;
+	}
+}
+
+/*
+ * Wait for the high bit to be set.
+ * 
+ * In principle, this could be tied to an interrupt, but the adapter
+ * doesn't appear to be designed to support interrupts.  We spin on
+ * the 0x80 ready bit. 
+ */
+static unsigned char imm_wait(imm_struct *dev)
+{
+	int k;
+	unsigned short ppb = dev->base;
+	unsigned char r;
+
+	w_ctr(ppb, 0x0c);
+
+	k = IMM_SPIN_TMO;
+	do {
+		r = r_str(ppb);
+		k--;
+		udelay(1);
+	}
+	while (!(r & 0x80) && (k));
+
+	/*
+	 * STR register (LPT base+1) to SCSI mapping:
+	 *
+	 * STR      imm     imm
+	 * ===================================
+	 * 0x80     S_REQ   S_REQ
+	 * 0x40     !S_BSY  (????)
+	 * 0x20     !S_CD   !S_CD
+	 * 0x10     !S_IO   !S_IO
+	 * 0x08     (????)  !S_BSY
+	 *
+	 * imm      imm     meaning
+	 * ==================================
+	 * 0xf0     0xb8    Bit mask
+	 * 0xc0     0x88    ZIP wants more data
+	 * 0xd0     0x98    ZIP wants to send more data
+	 * 0xe0     0xa8    ZIP is expecting SCSI command data
+	 * 0xf0     0xb8    end of transfer, ZIP is sending status
+	 */
+	w_ctr(ppb, 0x04);
+	if (k)
+		return (r & 0xb8);
+
+	/* Counter expired - Time out occurred */
+	imm_fail(dev, DID_TIME_OUT);
+	printk("imm timeout in imm_wait\n");
+	return 0;		/* command timed out */
+}
+
+static int imm_negotiate(imm_struct * tmp)
+{
+	/*
+	 * The following is supposedly the IEEE 1284-1994 negotiate
+	 * sequence. I have yet to obtain a copy of the above standard
+	 * so this is a bit of a guess...
+	 *
+	 * A fair chunk of this is based on the Linux parport implementation
+	 * of IEEE 1284.
+	 *
+	 * Return 0 if data available
+	 *        1 if no data available
+	 */
+
+	unsigned short base = tmp->base;
+	unsigned char a, mode;
+
+	switch (tmp->mode) {
+	case IMM_NIBBLE:
+		mode = 0x00;
+		break;
+	case IMM_PS2:
+		mode = 0x01;
+		break;
+	default:
+		return 0;
+	}
+
+	w_ctr(base, 0x04);
+	udelay(5);
+	w_dtr(base, mode);
+	udelay(100);
+	w_ctr(base, 0x06);
+	udelay(5);
+	a = (r_str(base) & 0x20) ? 0 : 1;
+	udelay(5);
+	w_ctr(base, 0x07);
+	udelay(5);
+	w_ctr(base, 0x06);
+
+	if (a) {
+		printk
+		    ("IMM: IEEE1284 negotiate indicates no data available.\n");
+		imm_fail(tmp, DID_ERROR);
+	}
+	return a;
+}
+
+/* 
+ * Clear EPP timeout bit. 
+ */
+static inline void epp_reset(unsigned short ppb)
+{
+	int i;
+
+	i = r_str(ppb);
+	w_str(ppb, i);
+	w_str(ppb, i & 0xfe);
+}
+
+/* 
+ * Wait for empty ECP fifo (if we are in ECP fifo mode only)
+ */
+static inline void ecp_sync(imm_struct *dev)
+{
+	int i, ppb_hi = dev->base_hi;
+
+	if (ppb_hi == 0)
+		return;
+
+	if ((r_ecr(ppb_hi) & 0xe0) == 0x60) {	/* mode 011 == ECP fifo mode */
+		for (i = 0; i < 100; i++) {
+			if (r_ecr(ppb_hi) & 0x01)
+				return;
+			udelay(5);
+		}
+		printk("imm: ECP sync failed as data still present in FIFO.\n");
+	}
+}
+
+static int imm_byte_out(unsigned short base, const char *buffer, int len)
+{
+	int i;
+
+	w_ctr(base, 0x4);	/* apparently a sane mode */
+	for (i = len >> 1; i; i--) {
+		w_dtr(base, *buffer++);
+		w_ctr(base, 0x5);	/* Drop STROBE low */
+		w_dtr(base, *buffer++);
+		w_ctr(base, 0x0);	/* STROBE high + INIT low */
+	}
+	w_ctr(base, 0x4);	/* apparently a sane mode */
+	return 1;		/* All went well - we hope! */
+}
+
+static int imm_nibble_in(unsigned short base, char *buffer, int len)
+{
+	unsigned char l;
+	int i;
+
+	/*
+	 * The following is based on documented timing signals
+	 */
+	w_ctr(base, 0x4);
+	for (i = len; i; i--) {
+		w_ctr(base, 0x6);
+		l = (r_str(base) & 0xf0) >> 4;
+		w_ctr(base, 0x5);
+		*buffer++ = (r_str(base) & 0xf0) | l;
+		w_ctr(base, 0x4);
+	}
+	return 1;		/* All went well - we hope! */
+}
+
+static int imm_byte_in(unsigned short base, char *buffer, int len)
+{
+	int i;
+
+	/*
+	 * The following is based on documented timing signals
+	 */
+	w_ctr(base, 0x4);
+	for (i = len; i; i--) {
+		w_ctr(base, 0x26);
+		*buffer++ = r_dtr(base);
+		w_ctr(base, 0x25);
+	}
+	return 1;		/* All went well - we hope! */
+}
+
+static int imm_out(imm_struct *dev, char *buffer, int len)
+{
+	unsigned short ppb = dev->base;
+	int r = imm_wait(dev);
+
+	/*
+	 * Make sure that:
+	 * a) the SCSI bus is BUSY (device still listening)
+	 * b) the device is listening
+	 */
+	if ((r & 0x18) != 0x08) {
+		imm_fail(dev, DID_ERROR);
+		printk("IMM: returned SCSI status %2x\n", r);
+		return 0;
+	}
+	switch (dev->mode) {
+	case IMM_EPP_32:
+	case IMM_EPP_16:
+	case IMM_EPP_8:
+		epp_reset(ppb);
+		w_ctr(ppb, 0x4);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+		if (!(((long) buffer | len) & 0x01))
+			outsw(ppb + 4, buffer, len >> 1);
+#else
+		if (!(((long) buffer | len) & 0x03))
+			outsl(ppb + 4, buffer, len >> 2);
+#endif
+		else
+			outsb(ppb + 4, buffer, len);
+		w_ctr(ppb, 0xc);
+		r = !(r_str(ppb) & 0x01);
+		w_ctr(ppb, 0xc);
+		ecp_sync(dev);
+		break;
+
+	case IMM_NIBBLE:
+	case IMM_PS2:
+		/* 8 bit output, with a loop */
+		r = imm_byte_out(ppb, buffer, len);
+		break;
+
+	default:
+		printk("IMM: bug in imm_out()\n");
+		r = 0;
+	}
+	return r;
+}
+
+static int imm_in(imm_struct *dev, char *buffer, int len)
+{
+	unsigned short ppb = dev->base;
+	int r = imm_wait(dev);
+
+	/*
+	 * Make sure that:
+	 * a) the SCSI bus is BUSY (device still listening)
+	 * b) the device is sending data
+	 */
+	if ((r & 0x18) != 0x18) {
+		imm_fail(dev, DID_ERROR);
+		return 0;
+	}
+	switch (dev->mode) {
+	case IMM_NIBBLE:
+		/* 4 bit input, with a loop */
+		r = imm_nibble_in(ppb, buffer, len);
+		w_ctr(ppb, 0xc);
+		break;
+
+	case IMM_PS2:
+		/* 8 bit input, with a loop */
+		r = imm_byte_in(ppb, buffer, len);
+		w_ctr(ppb, 0xc);
+		break;
+
+	case IMM_EPP_32:
+	case IMM_EPP_16:
+	case IMM_EPP_8:
+		epp_reset(ppb);
+		w_ctr(ppb, 0x24);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+		if (!(((long) buffer | len) & 0x01))
+			insw(ppb + 4, buffer, len >> 1);
+#else
+		if (!(((long) buffer | len) & 0x03))
+			insl(ppb + 4, buffer, len >> 2);
+#endif
+		else
+			insb(ppb + 4, buffer, len);
+		w_ctr(ppb, 0x2c);
+		r = !(r_str(ppb) & 0x01);
+		w_ctr(ppb, 0x2c);
+		ecp_sync(dev);
+		break;
+
+	default:
+		printk("IMM: bug in imm_ins()\n");
+		r = 0;
+		break;
+	}
+	return r;
+}
+
+static int imm_cpp(unsigned short ppb, unsigned char b)
+{
+	/*
+	 * Comments on udelay values refer to the
+	 * Command Packet Protocol (CPP) timing diagram.
+	 */
+
+	unsigned char s1, s2, s3;
+	w_ctr(ppb, 0x0c);
+	udelay(2);		/* 1 usec - infinite */
+	w_dtr(ppb, 0xaa);
+	udelay(10);		/* 7 usec - infinite */
+	w_dtr(ppb, 0x55);
+	udelay(10);		/* 7 usec - infinite */
+	w_dtr(ppb, 0x00);
+	udelay(10);		/* 7 usec - infinite */
+	w_dtr(ppb, 0xff);
+	udelay(10);		/* 7 usec - infinite */
+	s1 = r_str(ppb) & 0xb8;
+	w_dtr(ppb, 0x87);
+	udelay(10);		/* 7 usec - infinite */
+	s2 = r_str(ppb) & 0xb8;
+	w_dtr(ppb, 0x78);
+	udelay(10);		/* 7 usec - infinite */
+	s3 = r_str(ppb) & 0x38;
+	/*
+	 * Values for b are:
+	 * 0000 00aa    Assign address aa to current device
+	 * 0010 00aa    Select device aa in EPP Winbond mode
+	 * 0010 10aa    Select device aa in EPP mode
+	 * 0011 xxxx    Deselect all devices
+	 * 0110 00aa    Test device aa
+	 * 1101 00aa    Select device aa in ECP mode
+	 * 1110 00aa    Select device aa in Compatible mode
+	 */
+	w_dtr(ppb, b);
+	udelay(2);		/* 1 usec - infinite */
+	w_ctr(ppb, 0x0c);
+	udelay(10);		/* 7 usec - infinite */
+	w_ctr(ppb, 0x0d);
+	udelay(2);		/* 1 usec - infinite */
+	w_ctr(ppb, 0x0c);
+	udelay(10);		/* 7 usec - infinite */
+	w_dtr(ppb, 0xff);
+	udelay(10);		/* 7 usec - infinite */
+
+	/*
+	 * The following table is electrical pin values.
+	 * (BSY is inverted at the CTR register)
+	 *
+	 *       BSY  ACK  POut SEL  Fault
+	 * S1    0    X    1    1    1
+	 * S2    1    X    0    1    1
+	 * S3    L    X    1    1    S
+	 *
+	 * L => Last device in chain
+	 * S => Selected
+	 *
+	 * Observered values for S1,S2,S3 are:
+	 * Disconnect => f8/58/78
+	 * Connect    => f8/58/70
+	 */
+	if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30))
+		return 1;	/* Connected */
+	if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38))
+		return 0;	/* Disconnected */
+
+	return -1;		/* No device present */
+}
+
+static inline int imm_connect(imm_struct *dev, int flag)
+{
+	unsigned short ppb = dev->base;
+
+	imm_cpp(ppb, 0xe0);	/* Select device 0 in compatible mode */
+	imm_cpp(ppb, 0x30);	/* Disconnect all devices */
+
+	if ((dev->mode == IMM_EPP_8) ||
+	    (dev->mode == IMM_EPP_16) ||
+	    (dev->mode == IMM_EPP_32))
+		return imm_cpp(ppb, 0x28);	/* Select device 0 in EPP mode */
+	return imm_cpp(ppb, 0xe0);	/* Select device 0 in compatible mode */
+}
+
+static void imm_disconnect(imm_struct *dev)
+{
+	imm_cpp(dev->base, 0x30);	/* Disconnect all devices */
+}
+
+static int imm_select(imm_struct *dev, int target)
+{
+	int k;
+	unsigned short ppb = dev->base;
+
+	/*
+	 * Firstly we want to make sure there is nothing
+	 * holding onto the SCSI bus.
+	 */
+	w_ctr(ppb, 0xc);
+
+	k = IMM_SELECT_TMO;
+	do {
+		k--;
+	} while ((r_str(ppb) & 0x08) && (k));
+
+	if (!k)
+		return 0;
+
+	/*
+	 * Now assert the SCSI ID (HOST and TARGET) on the data bus
+	 */
+	w_ctr(ppb, 0x4);
+	w_dtr(ppb, 0x80 | (1 << target));
+	udelay(1);
+
+	/*
+	 * Deassert SELIN first followed by STROBE
+	 */
+	w_ctr(ppb, 0xc);
+	w_ctr(ppb, 0xd);
+
+	/*
+	 * ACK should drop low while SELIN is deasserted.
+	 * FAULT should drop low when the SCSI device latches the bus.
+	 */
+	k = IMM_SELECT_TMO;
+	do {
+		k--;
+	}
+	while (!(r_str(ppb) & 0x08) && (k));
+
+	/*
+	 * Place the interface back into a sane state (status mode)
+	 */
+	w_ctr(ppb, 0xc);
+	return (k) ? 1 : 0;
+}
+
+static int imm_init(imm_struct *dev)
+{
+	if (imm_connect(dev, 0) != 1)
+		return -EIO;
+	imm_reset_pulse(dev->base);
+	udelay(1000);	/* Delay to allow devices to settle */
+	imm_disconnect(dev);
+	udelay(1000);	/* Another delay to allow devices to settle */
+	return device_check(dev);
+}
+
+static inline int imm_send_command(struct scsi_cmnd *cmd)
+{
+	imm_struct *dev = imm_dev(cmd->device->host);
+	int k;
+
+	/* NOTE: IMM uses byte pairs */
+	for (k = 0; k < cmd->cmd_len; k += 2)
+		if (!imm_out(dev, &cmd->cmnd[k], 2))
+			return 0;
+	return 1;
+}
+
+/*
+ * The bulk flag enables some optimisations in the data transfer loops,
+ * it should be true for any command that transfers data in integral
+ * numbers of sectors.
+ * 
+ * The driver appears to remain stable if we speed up the parallel port
+ * i/o in this function, but not elsewhere.
+ */
+static int imm_completion(struct scsi_cmnd *cmd)
+{
+	/* Return codes:
+	 * -1     Error
+	 *  0     Told to schedule
+	 *  1     Finished data transfer
+	 */
+	imm_struct *dev = imm_dev(cmd->device->host);
+	unsigned short ppb = dev->base;
+	unsigned long start_jiffies = jiffies;
+
+	unsigned char r, v;
+	int fast, bulk, status;
+
+	v = cmd->cmnd[0];
+	bulk = ((v == READ_6) ||
+		(v == READ_10) || (v == WRITE_6) || (v == WRITE_10));
+
+	/*
+	 * We only get here if the drive is ready to comunicate,
+	 * hence no need for a full imm_wait.
+	 */
+	w_ctr(ppb, 0x0c);
+	r = (r_str(ppb) & 0xb8);
+
+	/*
+	 * while (device is not ready to send status byte)
+	 *     loop;
+	 */
+	while (r != (unsigned char) 0xb8) {
+		/*
+		 * If we have been running for more than a full timer tick
+		 * then take a rest.
+		 */
+		if (time_after(jiffies, start_jiffies + 1))
+			return 0;
+
+		/*
+		 * FAIL if:
+		 * a) Drive status is screwy (!ready && !present)
+		 * b) Drive is requesting/sending more data than expected
+		 */
+		if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) {
+			imm_fail(dev, DID_ERROR);
+			return -1;	/* ERROR_RETURN */
+		}
+		/* determine if we should use burst I/O */
+		if (dev->rd == 0) {
+			fast = (bulk
+				&& (cmd->SCp.this_residual >=
+				    IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2;
+			status = imm_out(dev, cmd->SCp.ptr, fast);
+		} else {
+			fast = (bulk
+				&& (cmd->SCp.this_residual >=
+				    IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1;
+			status = imm_in(dev, cmd->SCp.ptr, fast);
+		}
+
+		cmd->SCp.ptr += fast;
+		cmd->SCp.this_residual -= fast;
+
+		if (!status) {
+			imm_fail(dev, DID_BUS_BUSY);
+			return -1;	/* ERROR_RETURN */
+		}
+		if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+			/* if scatter/gather, advance to the next segment */
+			if (cmd->SCp.buffers_residual--) {
+				cmd->SCp.buffer++;
+				cmd->SCp.this_residual =
+				    cmd->SCp.buffer->length;
+				cmd->SCp.ptr =
+				    page_address(cmd->SCp.buffer->page) +
+				    cmd->SCp.buffer->offset;
+
+				/*
+				 * Make sure that we transfer even number of bytes
+				 * otherwise it makes imm_byte_out() messy.
+				 */
+				if (cmd->SCp.this_residual & 0x01)
+					cmd->SCp.this_residual++;
+			}
+		}
+		/* Now check to see if the drive is ready to comunicate */
+		w_ctr(ppb, 0x0c);
+		r = (r_str(ppb) & 0xb8);
+
+		/* If not, drop back down to the scheduler and wait a timer tick */
+		if (!(r & 0x80))
+			return 0;
+	}
+	return 1;		/* FINISH_RETURN */
+}
+
+/*
+ * Since the IMM itself doesn't generate interrupts, we use
+ * the scheduler's task queue to generate a stream of call-backs and
+ * complete the request when the drive is ready.
+ */
+static void imm_interrupt(void *data)
+{
+	imm_struct *dev = (imm_struct *) data;
+	struct scsi_cmnd *cmd = dev->cur_cmd;
+	struct Scsi_Host *host = cmd->device->host;
+	unsigned long flags;
+
+	if (!cmd) {
+		printk("IMM: bug in imm_interrupt\n");
+		return;
+	}
+	if (imm_engine(dev, cmd)) {
+		INIT_WORK(&dev->imm_tq, imm_interrupt, (void *) dev);
+		schedule_delayed_work(&dev->imm_tq, 1);
+		return;
+	}
+	/* Command must of completed hence it is safe to let go... */
+#if IMM_DEBUG > 0
+	switch ((cmd->result >> 16) & 0xff) {
+	case DID_OK:
+		break;
+	case DID_NO_CONNECT:
+		printk("imm: no device at SCSI ID %i\n", cmd->device->id);
+		break;
+	case DID_BUS_BUSY:
+		printk("imm: BUS BUSY - EPP timeout detected\n");
+		break;
+	case DID_TIME_OUT:
+		printk("imm: unknown timeout\n");
+		break;
+	case DID_ABORT:
+		printk("imm: told to abort\n");
+		break;
+	case DID_PARITY:
+		printk("imm: parity error (???)\n");
+		break;
+	case DID_ERROR:
+		printk("imm: internal driver error\n");
+		break;
+	case DID_RESET:
+		printk("imm: told to reset device\n");
+		break;
+	case DID_BAD_INTR:
+		printk("imm: bad interrupt (???)\n");
+		break;
+	default:
+		printk("imm: bad return code (%02x)\n",
+		       (cmd->result >> 16) & 0xff);
+	}
+#endif
+
+	if (cmd->SCp.phase > 1)
+		imm_disconnect(dev);
+
+	imm_pb_dismiss(dev);
+
+	spin_lock_irqsave(host->host_lock, flags);
+	dev->cur_cmd = NULL;
+	cmd->scsi_done(cmd);
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return;
+}
+
+static int imm_engine(imm_struct *dev, struct scsi_cmnd *cmd)
+{
+	unsigned short ppb = dev->base;
+	unsigned char l = 0, h = 0;
+	int retv, x;
+
+	/* First check for any errors that may have occurred
+	 * Here we check for internal errors
+	 */
+	if (dev->failed)
+		return 0;
+
+	switch (cmd->SCp.phase) {
+	case 0:		/* Phase 0 - Waiting for parport */
+		if (time_after(jiffies, dev->jstart + HZ)) {
+			/*
+			 * We waited more than a second
+			 * for parport to call us
+			 */
+			imm_fail(dev, DID_BUS_BUSY);
+			return 0;
+		}
+		return 1;	/* wait until imm_wakeup claims parport */
+		/* Phase 1 - Connected */
+	case 1:
+		imm_connect(dev, CONNECT_EPP_MAYBE);
+		cmd->SCp.phase++;
+
+		/* Phase 2 - We are now talking to the scsi bus */
+	case 2:
+		if (!imm_select(dev, cmd->device->id)) {
+			imm_fail(dev, DID_NO_CONNECT);
+			return 0;
+		}
+		cmd->SCp.phase++;
+
+		/* Phase 3 - Ready to accept a command */
+	case 3:
+		w_ctr(ppb, 0x0c);
+		if (!(r_str(ppb) & 0x80))
+			return 1;
+
+		if (!imm_send_command(cmd))
+			return 0;
+		cmd->SCp.phase++;
+
+		/* Phase 4 - Setup scatter/gather buffers */
+	case 4:
+		if (cmd->use_sg) {
+			/* if many buffers are available, start filling the first */
+			cmd->SCp.buffer =
+			    (struct scatterlist *) cmd->request_buffer;
+			cmd->SCp.this_residual = cmd->SCp.buffer->length;
+			cmd->SCp.ptr =
+			    page_address(cmd->SCp.buffer->page) +
+			    cmd->SCp.buffer->offset;
+		} else {
+			/* else fill the only available buffer */
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.this_residual = cmd->request_bufflen;
+			cmd->SCp.ptr = cmd->request_buffer;
+		}
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.phase++;
+		if (cmd->SCp.this_residual & 0x01)
+			cmd->SCp.this_residual++;
+		/* Phase 5 - Pre-Data transfer stage */
+	case 5:
+		/* Spin lock for BUSY */
+		w_ctr(ppb, 0x0c);
+		if (!(r_str(ppb) & 0x80))
+			return 1;
+
+		/* Require negotiation for read requests */
+		x = (r_str(ppb) & 0xb8);
+		dev->rd = (x & 0x10) ? 1 : 0;
+		dev->dp = (x & 0x20) ? 0 : 1;
+
+		if ((dev->dp) && (dev->rd))
+			if (imm_negotiate(dev))
+				return 0;
+		cmd->SCp.phase++;
+
+		/* Phase 6 - Data transfer stage */
+	case 6:
+		/* Spin lock for BUSY */
+		w_ctr(ppb, 0x0c);
+		if (!(r_str(ppb) & 0x80))
+			return 1;
+
+		if (dev->dp) {
+			retv = imm_completion(cmd);
+			if (retv == -1)
+				return 0;
+			if (retv == 0)
+				return 1;
+		}
+		cmd->SCp.phase++;
+
+		/* Phase 7 - Post data transfer stage */
+	case 7:
+		if ((dev->dp) && (dev->rd)) {
+			if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) {
+				w_ctr(ppb, 0x4);
+				w_ctr(ppb, 0xc);
+				w_ctr(ppb, 0xe);
+				w_ctr(ppb, 0x4);
+			}
+		}
+		cmd->SCp.phase++;
+
+		/* Phase 8 - Read status/message */
+	case 8:
+		/* Check for data overrun */
+		if (imm_wait(dev) != (unsigned char) 0xb8) {
+			imm_fail(dev, DID_ERROR);
+			return 0;
+		}
+		if (imm_negotiate(dev))
+			return 0;
+		if (imm_in(dev, &l, 1)) {	/* read status byte */
+			/* Check for optional message byte */
+			if (imm_wait(dev) == (unsigned char) 0xb8)
+				imm_in(dev, &h, 1);
+			cmd->result = (DID_OK << 16) + (l & STATUS_MASK);
+		}
+		if ((dev->mode == IMM_NIBBLE) || (dev->mode == IMM_PS2)) {
+			w_ctr(ppb, 0x4);
+			w_ctr(ppb, 0xc);
+			w_ctr(ppb, 0xe);
+			w_ctr(ppb, 0x4);
+		}
+		return 0;	/* Finished */
+		break;
+
+	default:
+		printk("imm: Invalid scsi phase\n");
+	}
+	return 0;
+}
+
+static int imm_queuecommand(struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	imm_struct *dev = imm_dev(cmd->device->host);
+
+	if (dev->cur_cmd) {
+		printk("IMM: bug in imm_queuecommand\n");
+		return 0;
+	}
+	dev->failed = 0;
+	dev->jstart = jiffies;
+	dev->cur_cmd = cmd;
+	cmd->scsi_done = done;
+	cmd->result = DID_ERROR << 16;	/* default return code */
+	cmd->SCp.phase = 0;	/* bus free */
+
+	INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
+	schedule_work(&dev->imm_tq);
+
+	imm_pb_claim(dev);
+
+	return 0;
+}
+
+/*
+ * Apparently the disk->capacity attribute is off by 1 sector 
+ * for all disk drives.  We add the one here, but it should really
+ * be done in sd.c.  Even if it gets fixed there, this will still
+ * work.
+ */
+static int imm_biosparam(struct scsi_device *sdev, struct block_device *dev,
+			 sector_t capacity, int ip[])
+{
+	ip[0] = 0x40;
+	ip[1] = 0x20;
+	ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]);
+	if (ip[2] > 1024) {
+		ip[0] = 0xff;
+		ip[1] = 0x3f;
+		ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]);
+	}
+	return 0;
+}
+
+static int imm_abort(struct scsi_cmnd *cmd)
+{
+	imm_struct *dev = imm_dev(cmd->device->host);
+	/*
+	 * There is no method for aborting commands since Iomega
+	 * have tied the SCSI_MESSAGE line high in the interface
+	 */
+
+	switch (cmd->SCp.phase) {
+	case 0:		/* Do not have access to parport */
+	case 1:		/* Have not connected to interface */
+		dev->cur_cmd = NULL;	/* Forget the problem */
+		return SUCCESS;
+		break;
+	default:		/* SCSI command sent, can not abort */
+		return FAILED;
+		break;
+	}
+}
+
+static void imm_reset_pulse(unsigned int base)
+{
+	w_ctr(base, 0x04);
+	w_dtr(base, 0x40);
+	udelay(1);
+	w_ctr(base, 0x0c);
+	w_ctr(base, 0x0d);
+	udelay(50);
+	w_ctr(base, 0x0c);
+	w_ctr(base, 0x04);
+}
+
+static int imm_reset(struct scsi_cmnd *cmd)
+{
+	imm_struct *dev = imm_dev(cmd->device->host);
+
+	if (cmd->SCp.phase)
+		imm_disconnect(dev);
+	dev->cur_cmd = NULL;	/* Forget the problem */
+
+	imm_connect(dev, CONNECT_NORMAL);
+	imm_reset_pulse(dev->base);
+	udelay(1000);		/* device settle delay */
+	imm_disconnect(dev);
+	udelay(1000);		/* device settle delay */
+	return SUCCESS;
+}
+
+static int device_check(imm_struct *dev)
+{
+	/* This routine looks for a device and then attempts to use EPP
+	   to send a command. If all goes as planned then EPP is available. */
+
+	static char cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	int loop, old_mode, status, k, ppb = dev->base;
+	unsigned char l;
+
+	old_mode = dev->mode;
+	for (loop = 0; loop < 8; loop++) {
+		/* Attempt to use EPP for Test Unit Ready */
+		if ((ppb & 0x0007) == 0x0000)
+			dev->mode = IMM_EPP_32;
+
+	      second_pass:
+		imm_connect(dev, CONNECT_EPP_MAYBE);
+		/* Select SCSI device */
+		if (!imm_select(dev, loop)) {
+			imm_disconnect(dev);
+			continue;
+		}
+		printk("imm: Found device at ID %i, Attempting to use %s\n",
+		       loop, IMM_MODE_STRING[dev->mode]);
+
+		/* Send SCSI command */
+		status = 1;
+		w_ctr(ppb, 0x0c);
+		for (l = 0; (l < 3) && (status); l++)
+			status = imm_out(dev, &cmd[l << 1], 2);
+
+		if (!status) {
+			imm_disconnect(dev);
+			imm_connect(dev, CONNECT_EPP_MAYBE);
+			imm_reset_pulse(dev->base);
+			udelay(1000);
+			imm_disconnect(dev);
+			udelay(1000);
+			if (dev->mode == IMM_EPP_32) {
+				dev->mode = old_mode;
+				goto second_pass;
+			}
+			printk("imm: Unable to establish communication\n");
+			return -EIO;
+		}
+		w_ctr(ppb, 0x0c);
+
+		k = 1000000;	/* 1 Second */
+		do {
+			l = r_str(ppb);
+			k--;
+			udelay(1);
+		} while (!(l & 0x80) && (k));
+
+		l &= 0xb8;
+
+		if (l != 0xb8) {
+			imm_disconnect(dev);
+			imm_connect(dev, CONNECT_EPP_MAYBE);
+			imm_reset_pulse(dev->base);
+			udelay(1000);
+			imm_disconnect(dev);
+			udelay(1000);
+			if (dev->mode == IMM_EPP_32) {
+				dev->mode = old_mode;
+				goto second_pass;
+			}
+			printk
+			    ("imm: Unable to establish communication\n");
+			return -EIO;
+		}
+		imm_disconnect(dev);
+		printk
+		    ("imm: Communication established at 0x%x with ID %i using %s\n",
+		     ppb, loop, IMM_MODE_STRING[dev->mode]);
+		imm_connect(dev, CONNECT_EPP_MAYBE);
+		imm_reset_pulse(dev->base);
+		udelay(1000);
+		imm_disconnect(dev);
+		udelay(1000);
+		return 0;
+	}
+	printk("imm: No devices found\n");
+	return -ENODEV;
+}
+
+static int imm_adjust_queue(struct scsi_device *device)
+{
+	blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+	return 0;
+}
+
+static struct scsi_host_template imm_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "imm",
+	.proc_info		= imm_proc_info,
+	.name			= "Iomega VPI2 (imm) interface",
+	.queuecommand		= imm_queuecommand,
+	.eh_abort_handler	= imm_abort,
+	.eh_bus_reset_handler	= imm_reset,
+	.eh_host_reset_handler	= imm_reset,
+	.bios_param		= imm_biosparam,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.can_queue		= 1,
+	.slave_alloc		= imm_adjust_queue,
+	.unchecked_isa_dma	= 1, /* imm cannot deal with highmem, so
+				      * this is an easy trick to ensure
+				      * all io pages for this host reside
+				      * in low memory */
+};
+
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+
+static LIST_HEAD(imm_hosts);
+
+static int __imm_attach(struct parport *pb)
+{
+	struct Scsi_Host *host;
+	imm_struct *dev;
+	DECLARE_WAIT_QUEUE_HEAD(waiting);
+	DEFINE_WAIT(wait);
+	int ports;
+	int modes, ppb;
+	int err = -ENOMEM;
+
+	init_waitqueue_head(&waiting);
+
+	dev = kmalloc(sizeof(imm_struct), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	memset(dev, 0, sizeof(imm_struct));
+
+	dev->base = -1;
+	dev->mode = IMM_AUTODETECT;
+	INIT_LIST_HEAD(&dev->list);
+
+	dev->dev = parport_register_device(pb, "imm", NULL, imm_wakeup,
+						NULL, 0, dev);
+
+	if (!dev->dev)
+		goto out;
+
+
+	/* Claim the bus so it remembers what we do to the control
+	 * registers. [ CTR and ECP ]
+	 */
+	err = -EBUSY;
+	dev->waiting = &waiting;
+	prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE);
+	if (imm_pb_claim(dev))
+		schedule_timeout(3 * HZ);
+	if (dev->wanted) {
+		printk(KERN_ERR "imm%d: failed to claim parport because "
+			"a pardevice is owning the port for too long "
+			"time!\n", pb->number);
+		imm_pb_dismiss(dev);
+		dev->waiting = NULL;
+		finish_wait(&waiting, &wait);
+		goto out1;
+	}
+	dev->waiting = NULL;
+	finish_wait(&waiting, &wait);
+	ppb = dev->base = dev->dev->port->base;
+	dev->base_hi = dev->dev->port->base_hi;
+	w_ctr(ppb, 0x0c);
+	modes = dev->dev->port->modes;
+
+	/* Mode detection works up the chain of speed
+	 * This avoids a nasty if-then-else-if-... tree
+	 */
+	dev->mode = IMM_NIBBLE;
+
+	if (modes & PARPORT_MODE_TRISTATE)
+		dev->mode = IMM_PS2;
+
+	/* Done configuration */
+
+	err = imm_init(dev);
+
+	imm_pb_release(dev);
+
+	if (err)
+		goto out1;
+
+	/* now the glue ... */
+	if (dev->mode == IMM_NIBBLE || dev->mode == IMM_PS2)
+		ports = 3;
+	else
+		ports = 8;
+
+	INIT_WORK(&dev->imm_tq, imm_interrupt, dev);
+
+	err = -ENOMEM;
+	host = scsi_host_alloc(&imm_template, sizeof(imm_struct *));
+	if (!host)
+		goto out1;
+	host->io_port = pb->base;
+	host->n_io_port = ports;
+	host->dma_channel = -1;
+	host->unique_id = pb->number;
+	*(imm_struct **)&host->hostdata = dev;
+	dev->host = host;
+	list_add_tail(&dev->list, &imm_hosts);
+	err = scsi_add_host(host, NULL);
+	if (err)
+		goto out2;
+	scsi_scan_host(host);
+	return 0;
+
+out2:
+	list_del_init(&dev->list);
+	scsi_host_put(host);
+out1:
+	parport_unregister_device(dev->dev);
+out:
+	kfree(dev);
+	return err;
+}
+
+static void imm_attach(struct parport *pb)
+{
+	__imm_attach(pb);
+}
+
+static void imm_detach(struct parport *pb)
+{
+	imm_struct *dev;
+	list_for_each_entry(dev, &imm_hosts, list) {
+		if (dev->dev->port == pb) {
+			list_del_init(&dev->list);
+			scsi_remove_host(dev->host);
+			scsi_host_put(dev->host);
+			parport_unregister_device(dev->dev);
+			kfree(dev);
+			break;
+		}
+	}
+}
+
+static struct parport_driver imm_driver = {
+	.name	= "imm",
+	.attach	= imm_attach,
+	.detach	= imm_detach,
+};
+
+static int __init imm_driver_init(void)
+{
+	printk("imm: Version %s\n", IMM_VERSION);
+	return parport_register_driver(&imm_driver);
+}
+
+static void __exit imm_driver_exit(void)
+{
+	parport_unregister_driver(&imm_driver);
+}
+
+module_init(imm_driver_init);
+module_exit(imm_driver_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
new file mode 100644
index 0000000..dc3aebf
--- /dev/null
+++ b/drivers/scsi/imm.h
@@ -0,0 +1,144 @@
+
+/*  Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in 
+ * the Iomega ZIP Plus drive
+ * 
+ * (c) 1998     David Campbell     campbell@torque.net
+ *
+ * Please note that I live in Perth, Western Australia. GMT+0800
+ */
+
+#ifndef _IMM_H
+#define _IMM_H
+
+#define   IMM_VERSION   "2.05 (for Linux 2.4.0)"
+
+/* 
+ * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega.
+ * Scarry thing is the level of support from one of their managers.
+ * The onus is now on us (the developers) to shut up and start coding.
+ *                                              11Apr98 [ 0.10 ]
+ *
+ * --- SNIP ---
+ *
+ * It manages to find the drive which is a good start. Writing data during
+ * data phase is known to be broken (due to requirements of two byte writes).
+ * Removing "Phase" debug messages.
+ *
+ * PS: Took four hours of coding after I bought a drive.
+ *      ANZAC Day (Aus "War Veterans Holiday")  25Apr98 [ 0.14 ]
+ *
+ * Ten minutes later after a few fixes.... (LITERALLY!!!)
+ * Have mounted disk, copied file, dismounted disk, remount disk, diff file
+ *                    -----  It actually works!!! -----
+ *                                              25Apr98 [ 0.15 ]
+ *
+ * Twenty minutes of mucking around, rearanged the IEEE negotiate mechanism.
+ * Now have byte mode working (only EPP and ECP to go now... :=)
+ *                                              26Apr98 [ 0.16 ]
+ *
+ * Thirty minutes of further coding results in EPP working on my machine.
+ *                                              27Apr98 [ 0.17 ]
+ *
+ * Due to work commitments and inability to get a "true" ECP mode functioning
+ * I have decided to code the parport support into imm.
+ *                                              09Jun98 [ 0.18 ]
+ *
+ * Driver is now out of beta testing.
+ * Support for parport has been added.
+ * Now distributed with the ppa driver.
+ *                                              12Jun98 [ 2.00 ]
+ *
+ * Err.. It appears that imm-2.00 was broken....
+ *                                              18Jun98 [ 2.01 ]
+ *
+ * Patch applied to sync this against the Linux 2.1.x kernel code
+ * Included qboot_zip.sh
+ *                                              21Jun98 [ 2.02 ]
+ *
+ * Other clean ups include the follow changes:
+ *    CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
+ *    added CONFIG_SCSI_IZIP_SLOW_CTR option
+ *                                                      [2.03]
+ *  Fix kernel panic on scsi timeout.		20Aug00 [2.04]
+ *
+ *  Avoid io_request_lock problems.
+ *  John Cavan <johncavan@home.com>		16Nov00 [2.05]
+ */
+/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+#include  <linux/config.h>
+#include  <linux/stddef.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <linux/blkdev.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
+
+#include  <asm/io.h>
+#include  <scsi/scsi_host.h>
+/* batteries not included :-) */
+
+/*
+ * modes in which the driver can operate 
+ */
+#define   IMM_AUTODETECT        0	/* Autodetect mode                */
+#define   IMM_NIBBLE            1	/* work in standard 4 bit mode    */
+#define   IMM_PS2               2	/* PS/2 byte mode         */
+#define   IMM_EPP_8             3	/* EPP mode, 8 bit                */
+#define   IMM_EPP_16            4	/* EPP mode, 16 bit               */
+#define   IMM_EPP_32            5	/* EPP mode, 32 bit               */
+#define   IMM_UNKNOWN           6	/* Just in case...                */
+
+static char *IMM_MODE_STRING[] =
+{
+	[IMM_AUTODETECT] = "Autodetect",
+	[IMM_NIBBLE]	 = "SPP",
+	[IMM_PS2]	 = "PS/2",
+	[IMM_EPP_8]	 = "EPP 8 bit",
+	[IMM_EPP_16]	 = "EPP 16 bit",
+#ifdef CONFIG_SCSI_IZIP_EPP16
+	[IMM_EPP_32]	 = "EPP 16 bit",
+#else
+	[IMM_EPP_32]	 = "EPP 32 bit",
+#endif
+	[IMM_UNKNOWN]	 = "Unknown",
+};
+
+/* other options */
+#define IMM_BURST_SIZE	512	/* data burst size */
+#define IMM_SELECT_TMO  500	/* 500 how long to wait for target ? */
+#define IMM_SPIN_TMO    5000	/* 50000 imm_wait loop limiter */
+#define IMM_DEBUG	0	/* debugging option */
+#define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32)
+
+/* args to imm_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x))   /* x must be base_hi */
+					/* On PCI is: base+0x400 != base_hi */
+#define r_ecr(x)        (unsigned char)inb((x)+2) /* x must be base_hi */
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x))     /* x must be base_hi */
+#define w_ecr(x,y)      outb(y, (x)+0x2) /* x must be base_hi */
+
+#ifdef CONFIG_SCSI_IZIP_SLOW_CTR
+#define w_ctr(x,y)      outb_p(y, (x)+2)
+#else
+#define w_ctr(x,y)      outb(y, (x)+2)
+#endif
+
+static int imm_engine(imm_struct *, struct scsi_cmnd *);
+
+#endif				/* _IMM_H */
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
new file mode 100644
index 0000000..0bb0369
--- /dev/null
+++ b/drivers/scsi/in2000.c
@@ -0,0 +1,2323 @@
+/*
+ *    in2000.c -  Linux device driver for the
+ *                Always IN2000 ISA SCSI card.
+ *
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * Drew Eckhardt's excellent 'Generic NCR5380' sources provided
+ * much of the inspiration and some of the code for this driver.
+ * The Linux IN2000 driver distributed in the Linux kernels through
+ * version 1.2.13 was an extremely valuable reference on the arcane
+ * (and still mysterious) workings of the IN2000's fifo. It also
+ * is where I lifted in2000_biosparam(), the gist of the card
+ * detection scheme, and other bits of code. Many thanks to the
+ * talented and courageous people who wrote, contributed to, and
+ * maintained that driver (including Brad McLean, Shaun Savage,
+ * Bill Earnest, Larry Doolittle, Roger Sunshine, John Luckey,
+ * Matt Postiff, Peter Lu, zerucha@shell.portal.com, and Eric
+ * Youngdale). I should also mention the driver written by
+ * Hamish Macdonald for the (GASP!) Amiga A2091 card, included
+ * in the Linux-m68k distribution; it gave me a good initial
+ * understanding of the proper way to run a WD33c93 chip, and I
+ * ended up stealing lots of code from it.
+ *
+ * _This_ driver is (I feel) an improvement over the old one in
+ * several respects:
+ *    -  All problems relating to the data size of a SCSI request are
+ *          gone (as far as I know). The old driver couldn't handle
+ *          swapping to partitions because that involved 4k blocks, nor
+ *          could it deal with the st.c tape driver unmodified, because
+ *          that usually involved 4k - 32k blocks. The old driver never
+ *          quite got away from a morbid dependence on 2k block sizes -
+ *          which of course is the size of the card's fifo.
+ *
+ *    -  Target Disconnection/Reconnection is now supported. Any
+ *          system with more than one device active on the SCSI bus
+ *          will benefit from this. The driver defaults to what I'm
+ *          calling 'adaptive disconnect' - meaning that each command
+ *          is evaluated individually as to whether or not it should
+ *          be run with the option to disconnect/reselect (if the
+ *          device chooses), or as a "SCSI-bus-hog".
+ *
+ *    -  Synchronous data transfers are now supported. Because there
+ *          are a few devices (and many improperly terminated systems)
+ *          that choke when doing sync, the default is sync DISABLED
+ *          for all devices. This faster protocol can (and should!)
+ *          be enabled on selected devices via the command-line.
+ *
+ *    -  Runtime operating parameters can now be specified through
+ *       either the LILO or the 'insmod' command line. For LILO do:
+ *          "in2000=blah,blah,blah"
+ *       and with insmod go like:
+ *          "insmod /usr/src/linux/modules/in2000.o setup_strings=blah,blah"
+ *       The defaults should be good for most people. See the comment
+ *       for 'setup_strings' below for more details.
+ *
+ *    -  The old driver relied exclusively on what the Western Digital
+ *          docs call "Combination Level 2 Commands", which are a great
+ *          idea in that the CPU is relieved of a lot of interrupt
+ *          overhead. However, by accepting a certain (user-settable)
+ *          amount of additional interrupts, this driver achieves
+ *          better control over the SCSI bus, and data transfers are
+ *          almost as fast while being much easier to define, track,
+ *          and debug.
+ *
+ *    -  You can force detection of a card whose BIOS has been disabled.
+ *
+ *    -  Multiple IN2000 cards might almost be supported. I've tried to
+ *       keep it in mind, but have no way to test...
+ *
+ *
+ * TODO:
+ *       tagged queuing. multiple cards.
+ *
+ *
+ * NOTE:
+ *       When using this or any other SCSI driver as a module, you'll
+ *       find that with the stock kernel, at most _two_ SCSI hard
+ *       drives will be linked into the device list (ie, usable).
+ *       If your IN2000 card has more than 2 disks on its bus, you
+ *       might want to change the define of 'SD_EXTRA_DEVS' in the
+ *       'hosts.h' file from 2 to whatever is appropriate. It took
+ *       me a while to track down this surprisingly obscure and
+ *       undocumented little "feature".
+ *
+ *
+ * People with bug reports, wish-lists, complaints, comments,
+ * or improvements are asked to pah-leeez email me (John Shifflett)
+ * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
+ * this thing into as good a shape as possible, and I'm positive
+ * there are lots of lurking bugs and "Stupid Places".
+ *
+ * Updated for Linux 2.5 by Alan Cox <alan@redhat.com>
+ *	- Using new_eh handler
+ *	- Hopefully got all the locking right again
+ *	See "FIXME" notes for items that could do with more work
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#define IN2000_VERSION    "1.33-2.5"
+#define IN2000_DATE       "2002/11/03"
+
+#include "in2000.h"
+
+
+/*
+ * 'setup_strings' is a single string used to pass operating parameters and
+ * settings from the kernel/module command-line to the driver. 'setup_args[]'
+ * is an array of strings that define the compile-time default values for
+ * these settings. If Linux boots with a LILO or insmod command-line, those
+ * settings are combined with 'setup_args[]'. Note that LILO command-lines
+ * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix.
+ * The driver recognizes the following keywords (lower case required) and
+ * arguments:
+ *
+ * -  ioport:addr    -Where addr is IO address of a (usually ROM-less) card.
+ * -  noreset        -No optional args. Prevents SCSI bus reset at boot time.
+ * -  nosync:x       -x is a bitmask where the 1st 7 bits correspond with
+ *                    the 7 possible SCSI devices (bit 0 for device #0, etc).
+ *                    Set a bit to PREVENT sync negotiation on that device.
+ *                    The driver default is sync DISABLED on all devices.
+ * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
+ *                    period. Default is 500; acceptable values are 250 - 1000.
+ * -  disconnect:x   -x = 0 to never allow disconnects, 2 to always allow them.
+ *                    x = 1 does 'adaptive' disconnects, which is the default
+ *                    and generally the best choice.
+ * -  debug:x        -If 'DEBUGGING_ON' is defined, x is a bitmask that causes
+ *                    various types of debug output to printed - see the DB_xxx
+ *                    defines in in2000.h
+ * -  proc:x         -If 'PROC_INTERFACE' is defined, x is a bitmask that
+ *                    determines how the /proc interface works and what it
+ *                    does - see the PR_xxx defines in in2000.h
+ *
+ * Syntax Notes:
+ * -  Numeric arguments can be decimal or the '0x' form of hex notation. There
+ *    _must_ be a colon between a keyword and its numeric argument, with no
+ *    spaces.
+ * -  Keywords are separated by commas, no spaces, in the standard kernel
+ *    command-line manner.
+ * -  A keyword in the 'nth' comma-separated command-line member will overwrite
+ *    the 'nth' element of setup_args[]. A blank command-line member (in
+ *    other words, a comma with no preceding keyword) will _not_ overwrite
+ *    the corresponding setup_args[] element.
+ *
+ * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'):
+ * -  in2000=ioport:0x220,noreset
+ * -  in2000=period:250,disconnect:2,nosync:0x03
+ * -  in2000=debug:0x1e
+ * -  in2000=proc:3
+ */
+
+/* Normally, no defaults are specified... */
+static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
+
+/* filled in by 'insmod' */
+static char *setup_strings;
+
+module_param(setup_strings, charp, 0);
+
+static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num)
+{
+	write1_io(reg_num, IO_WD_ADDR);
+	return read1_io(IO_WD_DATA);
+}
+
+
+#define READ_AUX_STAT() read1_io(IO_WD_ASR)
+
+
+static inline void write_3393(struct IN2000_hostdata *hostdata, uchar reg_num, uchar value)
+{
+	write1_io(reg_num, IO_WD_ADDR);
+	write1_io(value, IO_WD_DATA);
+}
+
+
+static inline void write_3393_cmd(struct IN2000_hostdata *hostdata, uchar cmd)
+{
+/*   while (READ_AUX_STAT() & ASR_CIP)
+      printk("|");*/
+	write1_io(WD_COMMAND, IO_WD_ADDR);
+	write1_io(cmd, IO_WD_DATA);
+}
+
+
+static uchar read_1_byte(struct IN2000_hostdata *hostdata)
+{
+	uchar asr, x = 0;
+
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393_cmd(hostdata, WD_CMD_TRANS_INFO | 0x80);
+	do {
+		asr = READ_AUX_STAT();
+		if (asr & ASR_DBR)
+			x = read_3393(hostdata, WD_DATA);
+	} while (!(asr & ASR_INT));
+	return x;
+}
+
+
+static void write_3393_count(struct IN2000_hostdata *hostdata, unsigned long value)
+{
+	write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
+	write1_io((value >> 16), IO_WD_DATA);
+	write1_io((value >> 8), IO_WD_DATA);
+	write1_io(value, IO_WD_DATA);
+}
+
+
+static unsigned long read_3393_count(struct IN2000_hostdata *hostdata)
+{
+	unsigned long value;
+
+	write1_io(WD_TRANSFER_COUNT_MSB, IO_WD_ADDR);
+	value = read1_io(IO_WD_DATA) << 16;
+	value |= read1_io(IO_WD_DATA) << 8;
+	value |= read1_io(IO_WD_DATA);
+	return value;
+}
+
+
+/* The 33c93 needs to be told which direction a command transfers its
+ * data; we use this function to figure it out. Returns true if there
+ * will be a DATA_OUT phase with this command, false otherwise.
+ * (Thanks to Joerg Dorchain for the research and suggestion.)
+ */
+static int is_dir_out(Scsi_Cmnd * cmd)
+{
+	switch (cmd->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+	case WRITE_LONG:
+	case WRITE_SAME:
+	case WRITE_BUFFER:
+	case WRITE_VERIFY:
+	case WRITE_VERIFY_12:
+	case COMPARE:
+	case COPY:
+	case COPY_VERIFY:
+	case SEARCH_EQUAL:
+	case SEARCH_HIGH:
+	case SEARCH_LOW:
+	case SEARCH_EQUAL_12:
+	case SEARCH_HIGH_12:
+	case SEARCH_LOW_12:
+	case FORMAT_UNIT:
+	case REASSIGN_BLOCKS:
+	case RESERVE:
+	case MODE_SELECT:
+	case MODE_SELECT_10:
+	case LOG_SELECT:
+	case SEND_DIAGNOSTIC:
+	case CHANGE_DEFINITION:
+	case UPDATE_BLOCK:
+	case SET_WINDOW:
+	case MEDIUM_SCAN:
+	case SEND_VOLUME_TAG:
+	case 0xea:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+
+
+static struct sx_period sx_table[] = {
+	{1, 0x20},
+	{252, 0x20},
+	{376, 0x30},
+	{500, 0x40},
+	{624, 0x50},
+	{752, 0x60},
+	{876, 0x70},
+	{1000, 0x00},
+	{0, 0}
+};
+
+static int round_period(unsigned int period)
+{
+	int x;
+
+	for (x = 1; sx_table[x].period_ns; x++) {
+		if ((period <= sx_table[x - 0].period_ns) && (period > sx_table[x - 1].period_ns)) {
+			return x;
+		}
+	}
+	return 7;
+}
+
+static uchar calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+	uchar result;
+
+	period *= 4;		/* convert SDTR code to ns */
+	result = sx_table[round_period(period)].reg_value;
+	result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
+	return result;
+}
+
+
+
+static void in2000_execute(struct Scsi_Host *instance);
+
+static int in2000_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *tmp;
+
+	instance = cmd->device->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	DB(DB_QUEUE_COMMAND, printk("Q-%d-%02x-%ld(", cmd->device->id, cmd->cmnd[0], cmd->pid))
+
+/* Set up a few fields in the Scsi_Cmnd structure for our own use:
+ *  - host_scribble is the pointer to the next cmd in the input queue
+ *  - scsi_done points to the routine we call when a cmd is finished
+ *  - result is what you'd expect
+ */
+	    cmd->host_scribble = NULL;
+	cmd->scsi_done = done;
+	cmd->result = 0;
+
+/* We use the Scsi_Pointer structure that's included with each command
+ * as a scratchpad (as it's intended to be used!). The handy thing about
+ * the SCp.xxx fields is that they're always associated with a given
+ * cmd, and are preserved across disconnect-reselect. This means we
+ * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
+ * if we keep all the critical pointers and counters in SCp:
+ *  - SCp.ptr is the pointer into the RAM buffer
+ *  - SCp.this_residual is the size of that buffer
+ *  - SCp.buffer points to the current scatter-gather buffer
+ *  - SCp.buffers_residual tells us how many S.G. buffers there are
+ *  - SCp.have_data_in helps keep track of >2048 byte transfers
+ *  - SCp.sent_command is not used
+ *  - SCp.phase records this command's SRCID_ER bit setting
+ */
+
+	if (cmd->use_sg) {
+		cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.ptr = (char *) page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	} else {
+		cmd->SCp.buffer = NULL;
+		cmd->SCp.buffers_residual = 0;
+		cmd->SCp.ptr = (char *) cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+	}
+	cmd->SCp.have_data_in = 0;
+
+/* We don't set SCp.phase here - that's done in in2000_execute() */
+
+/* WD docs state that at the conclusion of a "LEVEL2" command, the
+ * status byte can be retrieved from the LUN register. Apparently,
+ * this is the case only for *uninterrupted* LEVEL2 commands! If
+ * there are any unexpected phases entered, even if they are 100%
+ * legal (different devices may choose to do things differently),
+ * the LEVEL2 command sequence is exited. This often occurs prior
+ * to receiving the status byte, in which case the driver does a
+ * status phase interrupt and gets the status byte on its own.
+ * While such a command can then be "resumed" (ie restarted to
+ * finish up as a LEVEL2 command), the LUN register will NOT be
+ * a valid status byte at the command's conclusion, and we must
+ * use the byte obtained during the earlier interrupt. Here, we
+ * preset SCp.Status to an illegal value (0xff) so that when
+ * this command finally completes, we can tell where the actual
+ * status byte is stored.
+ */
+
+	cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
+
+/* We need to disable interrupts before messing with the input
+ * queue and calling in2000_execute().
+ */
+
+	/*
+	 * Add the cmd to the end of 'input_Q'. Note that REQUEST_SENSE
+	 * commands are added to the head of the queue so that the desired
+	 * sense data is not lost before REQUEST_SENSE executes.
+	 */
+
+	if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+		cmd->host_scribble = (uchar *) hostdata->input_Q;
+		hostdata->input_Q = cmd;
+	} else {		/* find the end of the queue */
+		for (tmp = (Scsi_Cmnd *) hostdata->input_Q; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
+		tmp->host_scribble = (uchar *) cmd;
+	}
+
+/* We know that there's at least one command in 'input_Q' now.
+ * Go see if any of them are runnable!
+ */
+
+	in2000_execute(cmd->device->host);
+
+	DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+	    return 0;
+}
+
+
+
+/*
+ * This routine attempts to start a scsi command. If the host_card is
+ * already connected, we give up immediately. Otherwise, look through
+ * the input_Q, using the first command we find that's intended
+ * for a currently non-busy target/lun.
+ * Note that this function is always called with interrupts already
+ * disabled (either from in2000_queuecommand() or in2000_intr()).
+ */
+static void in2000_execute(struct Scsi_Host *instance)
+{
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *cmd, *prev;
+	int i;
+	unsigned short *sp;
+	unsigned short f;
+	unsigned short flushbuf[16];
+
+
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	DB(DB_EXECUTE, printk("EX("))
+
+	    if (hostdata->selecting || hostdata->connected) {
+
+		DB(DB_EXECUTE, printk(")EX-0 "))
+
+		    return;
+	}
+
+	/*
+	 * Search through the input_Q for a command destined
+	 * for an idle target/lun.
+	 */
+
+	cmd = (Scsi_Cmnd *) hostdata->input_Q;
+	prev = NULL;
+	while (cmd) {
+		if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)))
+			break;
+		prev = cmd;
+		cmd = (Scsi_Cmnd *) cmd->host_scribble;
+	}
+
+	/* quit if queue empty or all possible targets are busy */
+
+	if (!cmd) {
+
+		DB(DB_EXECUTE, printk(")EX-1 "))
+
+		    return;
+	}
+
+	/*  remove command from queue */
+
+	if (prev)
+		prev->host_scribble = cmd->host_scribble;
+	else
+		hostdata->input_Q = (Scsi_Cmnd *) cmd->host_scribble;
+
+#ifdef PROC_STATISTICS
+	hostdata->cmd_cnt[cmd->device->id]++;
+#endif
+
+/*
+ * Start the selection process
+ */
+
+	if (is_dir_out(cmd))
+		write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id);
+	else
+		write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
+
+/* Now we need to figure out whether or not this command is a good
+ * candidate for disconnect/reselect. We guess to the best of our
+ * ability, based on a set of hierarchical rules. When several
+ * devices are operating simultaneously, disconnects are usually
+ * an advantage. In a single device system, or if only 1 device
+ * is being accessed, transfers usually go faster if disconnects
+ * are not allowed:
+ *
+ * + Commands should NEVER disconnect if hostdata->disconnect =
+ *   DIS_NEVER (this holds for tape drives also), and ALWAYS
+ *   disconnect if hostdata->disconnect = DIS_ALWAYS.
+ * + Tape drive commands should always be allowed to disconnect.
+ * + Disconnect should be allowed if disconnected_Q isn't empty.
+ * + Commands should NOT disconnect if input_Q is empty.
+ * + Disconnect should be allowed if there are commands in input_Q
+ *   for a different target/lun. In this case, the other commands
+ *   should be made disconnect-able, if not already.
+ *
+ * I know, I know - this code would flunk me out of any
+ * "C Programming 101" class ever offered. But it's easy
+ * to change around and experiment with for now.
+ */
+
+	cmd->SCp.phase = 0;	/* assume no disconnect */
+	if (hostdata->disconnect == DIS_NEVER)
+		goto no;
+	if (hostdata->disconnect == DIS_ALWAYS)
+		goto yes;
+	if (cmd->device->type == 1)	/* tape drive? */
+		goto yes;
+	if (hostdata->disconnected_Q)	/* other commands disconnected? */
+		goto yes;
+	if (!(hostdata->input_Q))	/* input_Q empty? */
+		goto no;
+	for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble) {
+		if ((prev->device->id != cmd->device->id) || (prev->device->lun != cmd->device->lun)) {
+			for (prev = (Scsi_Cmnd *) hostdata->input_Q; prev; prev = (Scsi_Cmnd *) prev->host_scribble)
+				prev->SCp.phase = 1;
+			goto yes;
+		}
+	}
+	goto no;
+
+      yes:
+	cmd->SCp.phase = 1;
+
+#ifdef PROC_STATISTICS
+	hostdata->disc_allowed_cnt[cmd->device->id]++;
+#endif
+
+      no:
+	write_3393(hostdata, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
+
+	write_3393(hostdata, WD_TARGET_LUN, cmd->device->lun);
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]);
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+
+	if ((hostdata->level2 <= L2_NONE) || (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) {
+
+		/*
+		 * Do a 'Select-With-ATN' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    CSR_SELECT:    success - proceed.
+		 */
+
+		hostdata->selecting = cmd;
+
+/* Every target has its own synchronous transfer setting, kept in
+ * the sync_xfer array, and a corresponding status byte in sync_stat[].
+ * Each target's sync_stat[] entry is initialized to SS_UNSET, and its
+ * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
+ * means that the parameters are undetermined as yet, and that we
+ * need to send an SDTR message to this device after selection is
+ * complete. We set SS_FIRST to tell the interrupt routine to do so,
+ * unless we don't want to even _try_ synchronous transfers: In this
+ * case we set SS_SET to make the defaults final.
+ */
+		if (hostdata->sync_stat[cmd->device->id] == SS_UNSET) {
+			if (hostdata->sync_off & (1 << cmd->device->id))
+				hostdata->sync_stat[cmd->device->id] = SS_SET;
+			else
+				hostdata->sync_stat[cmd->device->id] = SS_FIRST;
+		}
+		hostdata->state = S_SELECTING;
+		write_3393_count(hostdata, 0);	/* this guarantees a DATA_PHASE interrupt */
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN);
+	}
+
+	else {
+
+		/*
+		 * Do a 'Select-With-ATN-Xfer' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    anything else: success - proceed.
+		 */
+
+		hostdata->connected = cmd;
+		write_3393(hostdata, WD_COMMAND_PHASE, 0);
+
+		/* copy command_descriptor_block into WD chip
+		 * (take advantage of auto-incrementing)
+		 */
+
+		write1_io(WD_CDB_1, IO_WD_ADDR);
+		for (i = 0; i < cmd->cmd_len; i++)
+			write1_io(cmd->cmnd[i], IO_WD_DATA);
+
+		/* The wd33c93 only knows about Group 0, 1, and 5 commands when
+		 * it's doing a 'select-and-transfer'. To be safe, we write the
+		 * size of the CDB into the OWN_ID register for every case. This
+		 * way there won't be problems with vendor-unique, audio, etc.
+		 */
+
+		write_3393(hostdata, WD_OWN_ID, cmd->cmd_len);
+
+		/* When doing a non-disconnect command, we can save ourselves a DATA
+		 * phase interrupt later by setting everything up now. With writes we
+		 * need to pre-fill the fifo; if there's room for the 32 flush bytes,
+		 * put them in there too - that'll avoid a fifo interrupt. Reads are
+		 * somewhat simpler.
+		 * KLUDGE NOTE: It seems that you can't completely fill the fifo here:
+		 * This results in the IO_FIFO_COUNT register rolling over to zero,
+		 * and apparently the gate array logic sees this as empty, not full,
+		 * so the 3393 chip is never signalled to start reading from the
+		 * fifo. Or maybe it's seen as a permanent fifo interrupt condition.
+		 * Regardless, we fix this by temporarily pretending that the fifo
+		 * is 16 bytes smaller. (I see now that the old driver has a comment
+		 * about "don't fill completely" in an analogous place - must be the
+		 * same deal.) This results in CDROM, swap partitions, and tape drives
+		 * needing an extra interrupt per write command - I think we can live
+		 * with that!
+		 */
+
+		if (!(cmd->SCp.phase)) {
+			write_3393_count(hostdata, cmd->SCp.this_residual);
+			write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
+			write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter, write mode */
+
+			if (is_dir_out(cmd)) {
+				hostdata->fifo = FI_FIFO_WRITING;
+				if ((i = cmd->SCp.this_residual) > (IN2000_FIFO_SIZE - 16))
+					i = IN2000_FIFO_SIZE - 16;
+				cmd->SCp.have_data_in = i;	/* this much data in fifo */
+				i >>= 1;	/* Gulp. Assuming modulo 2. */
+				sp = (unsigned short *) cmd->SCp.ptr;
+				f = hostdata->io_base + IO_FIFO;
+
+#ifdef FAST_WRITE_IO
+
+				FAST_WRITE2_IO();
+#else
+				while (i--)
+					write2_io(*sp++, IO_FIFO);
+
+#endif
+
+				/* Is there room for the flush bytes? */
+
+				if (cmd->SCp.have_data_in <= ((IN2000_FIFO_SIZE - 16) - 32)) {
+					sp = flushbuf;
+					i = 16;
+
+#ifdef FAST_WRITE_IO
+
+					FAST_WRITE2_IO();
+#else
+					while (i--)
+						write2_io(0, IO_FIFO);
+
+#endif
+
+				}
+			}
+
+			else {
+				write1_io(0, IO_FIFO_READ);	/* put fifo in read mode */
+				hostdata->fifo = FI_FIFO_READING;
+				cmd->SCp.have_data_in = 0;	/* nothing transferred yet */
+			}
+
+		} else {
+			write_3393_count(hostdata, 0);	/* this guarantees a DATA_PHASE interrupt */
+		}
+		hostdata->state = S_RUNNING_LEVEL2;
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+	}
+
+	/*
+	 * Since the SCSI bus can handle only 1 connection at a time,
+	 * we get out of here now. If the selection fails, or when
+	 * the command disconnects, we'll come back to this routine
+	 * to search the input_Q again...
+	 */
+
+	DB(DB_EXECUTE, printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+
+}
+
+
+
+static void transfer_pio(uchar * buf, int cnt, int data_in_dir, struct IN2000_hostdata *hostdata)
+{
+	uchar asr;
+
+	DB(DB_TRANSFER, printk("(%p,%d,%s)", buf, cnt, data_in_dir ? "in" : "out"))
+
+	    write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393_count(hostdata, cnt);
+	write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+	if (data_in_dir) {
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				*buf++ = read_3393(hostdata, WD_DATA);
+		} while (!(asr & ASR_INT));
+	} else {
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				write_3393(hostdata, WD_DATA, *buf++);
+		} while (!(asr & ASR_INT));
+	}
+
+	/* Note: we are returning with the interrupt UN-cleared.
+	 * Since (presumably) an entire I/O operation has
+	 * completed, the bus phase is probably different, and
+	 * the interrupt routine will discover this when it
+	 * responds to the uncleared int.
+	 */
+
+}
+
+
+
+static void transfer_bytes(Scsi_Cmnd * cmd, int data_in_dir)
+{
+	struct IN2000_hostdata *hostdata;
+	unsigned short *sp;
+	unsigned short f;
+	int i;
+
+	hostdata = (struct IN2000_hostdata *) cmd->device->host->hostdata;
+
+/* Normally, you'd expect 'this_residual' to be non-zero here.
+ * In a series of scatter-gather transfers, however, this
+ * routine will usually be called with 'this_residual' equal
+ * to 0 and 'buffers_residual' non-zero. This means that a
+ * previous transfer completed, clearing 'this_residual', and
+ * now we need to setup the next scatter-gather buffer as the
+ * source or destination for THIS transfer.
+ */
+	if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		++cmd->SCp.buffer;
+		--cmd->SCp.buffers_residual;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) + cmd->SCp.buffer->offset;
+	}
+
+/* Set up hardware registers */
+
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, hostdata->sync_xfer[cmd->device->id]);
+	write_3393_count(hostdata, cmd->SCp.this_residual);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_BUS);
+	write1_io(0, IO_FIFO_WRITE);	/* zero counter, assume write */
+
+/* Reading is easy. Just issue the command and return - we'll
+ * get an interrupt later when we have actual data to worry about.
+ */
+
+	if (data_in_dir) {
+		write1_io(0, IO_FIFO_READ);
+		if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+		hostdata->fifo = FI_FIFO_READING;
+		cmd->SCp.have_data_in = 0;
+		return;
+	}
+
+/* Writing is more involved - we'll start the WD chip and write as
+ * much data to the fifo as we can right now. Later interrupts will
+ * write any bytes that don't make it at this stage.
+ */
+
+	if ((hostdata->level2 >= L2_DATA) || (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
+		write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		hostdata->state = S_RUNNING_LEVEL2;
+	} else
+		write_3393_cmd(hostdata, WD_CMD_TRANS_INFO);
+	hostdata->fifo = FI_FIFO_WRITING;
+	sp = (unsigned short *) cmd->SCp.ptr;
+
+	if ((i = cmd->SCp.this_residual) > IN2000_FIFO_SIZE)
+		i = IN2000_FIFO_SIZE;
+	cmd->SCp.have_data_in = i;
+	i >>= 1;		/* Gulp. We assume this_residual is modulo 2 */
+	f = hostdata->io_base + IO_FIFO;
+
+#ifdef FAST_WRITE_IO
+
+	FAST_WRITE2_IO();
+#else
+	while (i--)
+		write2_io(*sp++, IO_FIFO);
+
+#endif
+
+}
+
+
+/* We need to use spin_lock_irqsave() & spin_unlock_irqrestore() in this
+ * function in order to work in an SMP environment. (I'd be surprised
+ * if the driver is ever used by anyone on a real multi-CPU motherboard,
+ * but it _does_ need to be able to compile and run in an SMP kernel.)
+ */
+
+static irqreturn_t in2000_intr(int irqnum, void *dev_id, struct pt_regs *ptregs)
+{
+	struct Scsi_Host *instance = dev_id;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *patch, *cmd;
+	uchar asr, sr, phs, id, lun, *ucp, msg;
+	int i, j;
+	unsigned long length;
+	unsigned short *sp;
+	unsigned short f;
+	unsigned long flags;
+
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+/* Get the spin_lock and disable further ints, for SMP */
+
+	spin_lock_irqsave(instance->host_lock, flags);
+
+#ifdef PROC_STATISTICS
+	hostdata->int_cnt++;
+#endif
+
+/* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the
+ * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined
+ * with a big logic array, so it's a little different than what you might
+ * expect). As far as I know, there's no reason that BOTH can't be active
+ * at the same time, but there's a problem: while we can read the 3393
+ * to tell if _it_ wants an interrupt, I don't know of a way to ask the
+ * fifo the same question. The best we can do is check the 3393 and if
+ * it _isn't_ the source of the interrupt, then we can be pretty sure
+ * that the fifo is the culprit.
+ *  UPDATE: I have it on good authority (Bill Earnest) that bit 0 of the
+ *          IO_FIFO_COUNT register mirrors the fifo interrupt state. I
+ *          assume that bit clear means interrupt active. As it turns
+ *          out, the driver really doesn't need to check for this after
+ *          all, so my remarks above about a 'problem' can safely be
+ *          ignored. The way the logic is set up, there's no advantage
+ *          (that I can see) to worrying about it.
+ *
+ * It seems that the fifo interrupt signal is negated when we extract
+ * bytes during read or write bytes during write.
+ *  - fifo will interrupt when data is moving from it to the 3393, and
+ *    there are 31 (or less?) bytes left to go. This is sort of short-
+ *    sighted: what if you don't WANT to do more? In any case, our
+ *    response is to push more into the fifo - either actual data or
+ *    dummy bytes if need be. Note that we apparently have to write at
+ *    least 32 additional bytes to the fifo after an interrupt in order
+ *    to get it to release the ones it was holding on to - writing fewer
+ *    than 32 will result in another fifo int.
+ *  UPDATE: Again, info from Bill Earnest makes this more understandable:
+ *          32 bytes = two counts of the fifo counter register. He tells
+ *          me that the fifo interrupt is a non-latching signal derived
+ *          from a straightforward boolean interpretation of the 7
+ *          highest bits of the fifo counter and the fifo-read/fifo-write
+ *          state. Who'd a thought?
+ */
+
+	write1_io(0, IO_LED_ON);
+	asr = READ_AUX_STAT();
+	if (!(asr & ASR_INT)) {	/* no WD33c93 interrupt? */
+
+/* Ok. This is definitely a FIFO-only interrupt.
+ *
+ * If FI_FIFO_READING is set, there are up to 2048 bytes waiting to be read,
+ * maybe more to come from the SCSI bus. Read as many as we can out of the
+ * fifo and into memory at the location of SCp.ptr[SCp.have_data_in], and
+ * update have_data_in afterwards.
+ *
+ * If we have FI_FIFO_WRITING, the FIFO has almost run out of bytes to move
+ * into the WD3393 chip (I think the interrupt happens when there are 31
+ * bytes left, but it may be fewer...). The 3393 is still waiting, so we
+ * shove some more into the fifo, which gets things moving again. If the
+ * original SCSI command specified more than 2048 bytes, there may still
+ * be some of that data left: fine - use it (from SCp.ptr[SCp.have_data_in]).
+ * Don't forget to update have_data_in. If we've already written out the
+ * entire buffer, feed 32 dummy bytes to the fifo - they're needed to
+ * push out the remaining real data.
+ *    (Big thanks to Bill Earnest for getting me out of the mud in here.)
+ */
+
+		cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */
+		CHECK_NULL(cmd, "fifo_int")
+
+		    if (hostdata->fifo == FI_FIFO_READING) {
+
+			DB(DB_FIFO, printk("{R:%02x} ", read1_io(IO_FIFO_COUNT)))
+
+			    sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+			i = read1_io(IO_FIFO_COUNT) & 0xfe;
+			i <<= 2;	/* # of words waiting in the fifo */
+			f = hostdata->io_base + IO_FIFO;
+
+#ifdef FAST_READ_IO
+
+			FAST_READ2_IO();
+#else
+			while (i--)
+				*sp++ = read2_io(IO_FIFO);
+
+#endif
+
+			i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+			i <<= 1;
+			cmd->SCp.have_data_in += i;
+		}
+
+		else if (hostdata->fifo == FI_FIFO_WRITING) {
+
+			DB(DB_FIFO, printk("{W:%02x} ", read1_io(IO_FIFO_COUNT)))
+
+/* If all bytes have been written to the fifo, flush out the stragglers.
+ * Note that while writing 16 dummy words seems arbitrary, we don't
+ * have another choice that I can see. What we really want is to read
+ * the 3393 transfer count register (that would tell us how many bytes
+ * needed flushing), but the TRANSFER_INFO command hasn't completed
+ * yet (not enough bytes!) and that register won't be accessible. So,
+ * we use 16 words - a number obtained through trial and error.
+ *  UPDATE: Bill says this is exactly what Always does, so there.
+ *          More thanks due him for help in this section.
+ */
+			    if (cmd->SCp.this_residual == cmd->SCp.have_data_in) {
+				i = 16;
+				while (i--)	/* write 32 dummy bytes */
+					write2_io(0, IO_FIFO);
+			}
+
+/* If there are still bytes left in the SCSI buffer, write as many as we
+ * can out to the fifo.
+ */
+
+			else {
+				sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+				i = cmd->SCp.this_residual - cmd->SCp.have_data_in;	/* bytes yet to go */
+				j = read1_io(IO_FIFO_COUNT) & 0xfe;
+				j <<= 2;	/* how many words the fifo has room for */
+				if ((j << 1) > i)
+					j = (i >> 1);
+				while (j--)
+					write2_io(*sp++, IO_FIFO);
+
+				i = sp - (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+				i <<= 1;
+				cmd->SCp.have_data_in += i;
+			}
+		}
+
+		else {
+			printk("*** Spurious FIFO interrupt ***");
+		}
+
+		write1_io(0, IO_LED_OFF);
+
+/* release the SMP spin_lock and restore irq state */
+		spin_unlock_irqrestore(instance->host_lock, flags);
+		return IRQ_HANDLED;
+	}
+
+/* This interrupt was triggered by the WD33c93 chip. The fifo interrupt
+ * may also be asserted, but we don't bother to check it: we get more
+ * detailed info from FIFO_READING and FIFO_WRITING (see below).
+ */
+
+	cmd = (Scsi_Cmnd *) hostdata->connected;	/* assume we're connected */
+	sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear the interrupt */
+	phs = read_3393(hostdata, WD_COMMAND_PHASE);
+
+	if (!cmd && (sr != CSR_RESEL_AM && sr != CSR_TIMEOUT && sr != CSR_SELECT)) {
+		printk("\nNR:wd-intr-1\n");
+		write1_io(0, IO_LED_OFF);
+
+/* release the SMP spin_lock and restore irq state */
+		spin_unlock_irqrestore(instance->host_lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
+
+/* After starting a FIFO-based transfer, the next _WD3393_ interrupt is
+ * guaranteed to be in response to the completion of the transfer.
+ * If we were reading, there's probably data in the fifo that needs
+ * to be copied into RAM - do that here. Also, we have to update
+ * 'this_residual' and 'ptr' based on the contents of the
+ * TRANSFER_COUNT register, in case the device decided to do an
+ * intermediate disconnect (a device may do this if it has to
+ * do a seek,  or just to be nice and let other devices have
+ * some bus time during long transfers).
+ * After doing whatever is necessary with the fifo, we go on and
+ * service the WD3393 interrupt normally.
+ */
+	    if (hostdata->fifo == FI_FIFO_READING) {
+
+/* buffer index = start-of-buffer + #-of-bytes-already-read */
+
+		sp = (unsigned short *) (cmd->SCp.ptr + cmd->SCp.have_data_in);
+
+/* bytes remaining in fifo = (total-wanted - #-not-got) - #-already-read */
+
+		i = (cmd->SCp.this_residual - read_3393_count(hostdata)) - cmd->SCp.have_data_in;
+		i >>= 1;	/* Gulp. We assume this will always be modulo 2 */
+		f = hostdata->io_base + IO_FIFO;
+
+#ifdef FAST_READ_IO
+
+		FAST_READ2_IO();
+#else
+		while (i--)
+			*sp++ = read2_io(IO_FIFO);
+
+#endif
+
+		hostdata->fifo = FI_FIFO_UNUSED;
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_3393_count(hostdata);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+
+		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
+
+	}
+
+	else if (hostdata->fifo == FI_FIFO_WRITING) {
+		hostdata->fifo = FI_FIFO_UNUSED;
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_3393_count(hostdata);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+
+		DB(DB_TRANSFER, printk("(%p,%d)", cmd->SCp.ptr, cmd->SCp.this_residual))
+
+	}
+
+/* Respond to the specific WD3393 interrupt - there are quite a few! */
+
+	switch (sr) {
+
+	case CSR_TIMEOUT:
+		DB(DB_INTR, printk("TIMEOUT"))
+
+		    if (hostdata->state == S_RUNNING_LEVEL2)
+			hostdata->connected = NULL;
+		else {
+			cmd = (Scsi_Cmnd *) hostdata->selecting;	/* get a valid cmd */
+			CHECK_NULL(cmd, "csr_timeout")
+			    hostdata->selecting = NULL;
+		}
+
+		cmd->result = DID_NO_CONNECT << 16;
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->state = S_UNCONNECTED;
+		cmd->scsi_done(cmd);
+
+/* We are not connected to a target - check to see if there
+ * are commands waiting to be executed.
+ */
+
+		in2000_execute(instance);
+		break;
+
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+	case CSR_SELECT:
+		DB(DB_INTR, printk("SELECT"))
+		    hostdata->connected = cmd = (Scsi_Cmnd *) hostdata->selecting;
+		CHECK_NULL(cmd, "csr_select")
+		    hostdata->selecting = NULL;
+
+		/* construct an IDENTIFY message with correct disconnect bit */
+
+		hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);
+		if (cmd->SCp.phase)
+			hostdata->outgoing_msg[0] |= 0x40;
+
+		if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
+#ifdef SYNC_DEBUG
+			printk(" sending SDTR ");
+#endif
+
+			hostdata->sync_stat[cmd->device->id] = SS_WAITING;
+
+			/* tack on a 2nd message to ask about synchronous transfers */
+
+			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
+			hostdata->outgoing_msg[2] = 3;
+			hostdata->outgoing_msg[3] = EXTENDED_SDTR;
+			hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
+			hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+			hostdata->outgoing_len = 6;
+		} else
+			hostdata->outgoing_len = 1;
+
+		hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_DATA_IN:
+	case CSR_UNEXP | PHS_DATA_IN:
+	case CSR_SRV_REQ | PHS_DATA_IN:
+		DB(DB_INTR, printk("IN-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
+		    transfer_bytes(cmd, DATA_IN_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_DATA_OUT:
+	case CSR_UNEXP | PHS_DATA_OUT:
+	case CSR_SRV_REQ | PHS_DATA_OUT:
+		DB(DB_INTR, printk("OUT-%d.%d", cmd->SCp.this_residual, cmd->SCp.buffers_residual))
+		    transfer_bytes(cmd, DATA_OUT_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		break;
+
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+	case CSR_XFER_DONE | PHS_COMMAND:
+	case CSR_UNEXP | PHS_COMMAND:
+	case CSR_SRV_REQ | PHS_COMMAND:
+		DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+		    transfer_pio(cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata);
+		hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_XFER_DONE | PHS_STATUS:
+	case CSR_UNEXP | PHS_STATUS:
+	case CSR_SRV_REQ | PHS_STATUS:
+		DB(DB_INTR, printk("STATUS="))
+
+		    cmd->SCp.Status = read_1_byte(hostdata);
+		DB(DB_INTR, printk("%02x", cmd->SCp.Status))
+		    if (hostdata->level2 >= L2_BASIC) {
+			sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+			hostdata->state = S_RUNNING_LEVEL2;
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x50);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		} else {
+			hostdata->state = S_CONNECTED;
+		}
+		break;
+
+
+	case CSR_XFER_DONE | PHS_MESS_IN:
+	case CSR_UNEXP | PHS_MESS_IN:
+	case CSR_SRV_REQ | PHS_MESS_IN:
+		DB(DB_INTR, printk("MSG_IN="))
+
+		    msg = read_1_byte(hostdata);
+		sr = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+
+		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
+		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
+			msg = EXTENDED_MESSAGE;
+		else
+			hostdata->incoming_ptr = 0;
+
+		cmd->SCp.Message = msg;
+		switch (msg) {
+
+		case COMMAND_COMPLETE:
+			DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_CMP_DISC;
+			break;
+
+		case SAVE_POINTERS:
+			DB(DB_INTR, printk("SDP"))
+			    write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
+
+		case RESTORE_POINTERS:
+			DB(DB_INTR, printk("RDP"))
+			    if (hostdata->level2 >= L2_BASIC) {
+				write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+				write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+				hostdata->state = S_RUNNING_LEVEL2;
+			} else {
+				write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		case DISCONNECT:
+			DB(DB_INTR, printk("DIS"))
+			    cmd->device->disconnect = 1;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_TMP_DISC;
+			break;
+
+		case MESSAGE_REJECT:
+			DB(DB_INTR, printk("REJ"))
+#ifdef SYNC_DEBUG
+			    printk("-REJ-");
+#endif
+			if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)
+				hostdata->sync_stat[cmd->device->id] = SS_SET;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
+
+		case EXTENDED_MESSAGE:
+			DB(DB_INTR, printk("EXT"))
+
+			    ucp = hostdata->incoming_msg;
+
+#ifdef SYNC_DEBUG
+			printk("%02x", ucp[hostdata->incoming_ptr]);
+#endif
+			/* Is this the last byte of the extended message? */
+
+			if ((hostdata->incoming_ptr >= 2) && (hostdata->incoming_ptr == (ucp[1] + 1))) {
+
+				switch (ucp[2]) {	/* what's the EXTENDED code? */
+				case EXTENDED_SDTR:
+					id = calc_sync_xfer(ucp[3], ucp[4]);
+					if (hostdata->sync_stat[cmd->device->id] != SS_WAITING) {
+
+/* A device has sent an unsolicited SDTR message; rather than go
+ * through the effort of decoding it and then figuring out what
+ * our reply should be, we're just gonna say that we have a
+ * synchronous fifo depth of 0. This will result in asynchronous
+ * transfers - not ideal but so much easier.
+ * Actually, this is OK because it assures us that if we don't
+ * specifically ask for sync transfers, we won't do any.
+ */
+
+						write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+						hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+						hostdata->outgoing_msg[1] = 3;
+						hostdata->outgoing_msg[2] = EXTENDED_SDTR;
+						hostdata->outgoing_msg[3] = hostdata->default_sx_per / 4;
+						hostdata->outgoing_msg[4] = 0;
+						hostdata->outgoing_len = 5;
+						hostdata->sync_xfer[cmd->device->id] = calc_sync_xfer(hostdata->default_sx_per / 4, 0);
+					} else {
+						hostdata->sync_xfer[cmd->device->id] = id;
+					}
+#ifdef SYNC_DEBUG
+					printk("sync_xfer=%02x", hostdata->sync_xfer[cmd->device->id]);
+#endif
+					hostdata->sync_stat[cmd->device->id] = SS_SET;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				case EXTENDED_WDTR:
+					write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk("sending WDTR ");
+					hostdata->outgoing_msg[0] = EXTENDED_MESSAGE;
+					hostdata->outgoing_msg[1] = 2;
+					hostdata->outgoing_msg[2] = EXTENDED_WDTR;
+					hostdata->outgoing_msg[3] = 0;	/* 8 bit transfer width */
+					hostdata->outgoing_len = 4;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				default:
+					write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk("Rejecting Unknown Extended Message(%02x). ", ucp[2]);
+					hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+					hostdata->outgoing_len = 1;
+					write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				}
+				hostdata->incoming_ptr = 0;
+			}
+
+			/* We need to read more MESS_IN bytes for the extended message */
+
+			else {
+				hostdata->incoming_ptr++;
+				write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		default:
+			printk("Rejecting Unknown Message(%02x) ", msg);
+			write_3393_cmd(hostdata, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+			hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+			hostdata->outgoing_len = 1;
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+		}
+		break;
+
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+	case CSR_SEL_XFER_DONE:
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		if (phs == 0x60) {
+			DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+			    cmd->SCp.Message = COMMAND_COMPLETE;
+			lun = read_3393(hostdata, WD_TARGET_LUN);
+			DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
+			    hostdata->connected = NULL;
+			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+			hostdata->state = S_UNCONNECTED;
+			if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
+				cmd->SCp.Status = lun;
+			if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+				cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+			in2000_execute(instance);
+		} else {
+			printk("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---", asr, sr, phs, cmd->pid);
+		}
+		break;
+
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+	case CSR_SDP:
+		DB(DB_INTR, printk("SDP"))
+		    hostdata->state = S_RUNNING_LEVEL2;
+		write_3393(hostdata, WD_COMMAND_PHASE, 0x41);
+		write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+		break;
+
+
+	case CSR_XFER_DONE | PHS_MESS_OUT:
+	case CSR_UNEXP | PHS_MESS_OUT:
+	case CSR_SRV_REQ | PHS_MESS_OUT:
+		DB(DB_INTR, printk("MSG_OUT="))
+
+/* To get here, we've probably requested MESSAGE_OUT and have
+ * already put the correct bytes in outgoing_msg[] and filled
+ * in outgoing_len. We simply send them out to the SCSI bus.
+ * Sometimes we get MESSAGE_OUT phase when we're not expecting
+ * it - like when our SDTR message is rejected by a target. Some
+ * targets send the REJECT before receiving all of the extended
+ * message, and then seem to go back to MESSAGE_OUT for a byte
+ * or two. Not sure why, or if I'm doing something wrong to
+ * cause this to happen. Regardless, it seems that sending
+ * NOP messages in these situations results in no harm and
+ * makes everyone happy.
+ */
+		    if (hostdata->outgoing_len == 0) {
+			hostdata->outgoing_len = 1;
+			hostdata->outgoing_msg[0] = NOP;
+		}
+		transfer_pio(hostdata->outgoing_msg, hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
+		DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
+		    hostdata->outgoing_len = 0;
+		hostdata->state = S_CONNECTED;
+		break;
+
+
+	case CSR_UNEXP_DISC:
+
+/* I think I've seen this after a request-sense that was in response
+ * to an error condition, but not sure. We certainly need to do
+ * something when we get this interrupt - the question is 'what?'.
+ * Let's think positively, and assume some command has finished
+ * in a legal manner (like a command that provokes a request-sense),
+ * so we treat it as a normal command-complete-disconnect.
+ */
+
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
+
+/* release the SMP spin_lock and restore irq state */
+			spin_unlock_irqrestore(instance->host_lock, flags);
+			return IRQ_HANDLED;
+		}
+		DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+		    hostdata->connected = NULL;
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->state = S_UNCONNECTED;
+		if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		else
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+		cmd->scsi_done(cmd);
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+		in2000_execute(instance);
+		break;
+
+
+	case CSR_DISC:
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_3393(hostdata, WD_SOURCE_ID, SRCID_ER);
+		DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+		    if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
+		}
+		switch (hostdata->state) {
+		case S_PRE_CMP_DISC:
+			hostdata->connected = NULL;
+			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+			hostdata->state = S_UNCONNECTED;
+			DB(DB_INTR, printk(":%d", cmd->SCp.Status))
+			    if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+				cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
+			break;
+		case S_PRE_TMP_DISC:
+		case S_RUNNING_LEVEL2:
+			cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
+			hostdata->disconnected_Q = cmd;
+			hostdata->connected = NULL;
+			hostdata->state = S_UNCONNECTED;
+
+#ifdef PROC_STATISTICS
+			hostdata->disc_done_cnt[cmd->device->id]++;
+#endif
+
+			break;
+		default:
+			printk("*** Unexpected DISCONNECT interrupt! ***");
+			hostdata->state = S_UNCONNECTED;
+		}
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+
+		in2000_execute(instance);
+		break;
+
+
+	case CSR_RESEL_AM:
+		DB(DB_INTR, printk("RESEL"))
+
+		    /* First we have to make sure this reselection didn't */
+		    /* happen during Arbitration/Selection of some other device. */
+		    /* If yes, put losing command back on top of input_Q. */
+		    if (hostdata->level2 <= L2_NONE) {
+
+			if (hostdata->selecting) {
+				cmd = (Scsi_Cmnd *) hostdata->selecting;
+				hostdata->selecting = NULL;
+				hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+				cmd->host_scribble = (uchar *) hostdata->input_Q;
+				hostdata->input_Q = cmd;
+			}
+		}
+
+		else {
+
+			if (cmd) {
+				if (phs == 0x00) {
+					hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+					cmd->host_scribble = (uchar *) hostdata->input_Q;
+					hostdata->input_Q = cmd;
+				} else {
+					printk("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---", asr, sr, phs);
+					while (1)
+						printk("\r");
+				}
+			}
+
+		}
+
+		/* OK - find out which device reselected us. */
+
+		id = read_3393(hostdata, WD_SOURCE_ID);
+		id &= SRCID_MASK;
+
+		/* and extract the lun from the ID message. (Note that we don't
+		 * bother to check for a valid message here - I guess this is
+		 * not the right way to go, but....)
+		 */
+
+		lun = read_3393(hostdata, WD_DATA);
+		if (hostdata->level2 < L2_RESELECT)
+			write_3393_cmd(hostdata, WD_CMD_NEGATE_ACK);
+		lun &= 7;
+
+		/* Now we look for the command that's reconnecting. */
+
+		cmd = (Scsi_Cmnd *) hostdata->disconnected_Q;
+		patch = NULL;
+		while (cmd) {
+			if (id == cmd->device->id && lun == cmd->device->lun)
+				break;
+			patch = cmd;
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+
+		/* Hmm. Couldn't find a valid command.... What to do? */
+
+		if (!cmd) {
+			printk("---TROUBLE: target %d.%d not in disconnect queue---", id, lun);
+			break;
+		}
+
+		/* Ok, found the command - now start it up again. */
+
+		if (patch)
+			patch->host_scribble = cmd->host_scribble;
+		else
+			hostdata->disconnected_Q = (Scsi_Cmnd *) cmd->host_scribble;
+		hostdata->connected = cmd;
+
+		/* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
+		 * because these things are preserved over a disconnect.
+		 * But we DO need to fix the DPD bit so it's correct for this command.
+		 */
+
+		if (is_dir_out(cmd))
+			write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id);
+		else
+			write_3393(hostdata, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
+		if (hostdata->level2 >= L2_RESELECT) {
+			write_3393_count(hostdata, 0);	/* we want a DATA_PHASE interrupt */
+			write_3393(hostdata, WD_COMMAND_PHASE, 0x45);
+			write_3393_cmd(hostdata, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			hostdata->state = S_CONNECTED;
+
+		DB(DB_INTR, printk("-%ld", cmd->pid))
+		    break;
+
+	default:
+		printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
+	}
+
+	write1_io(0, IO_LED_OFF);
+
+	DB(DB_INTR, printk("} "))
+
+/* release the SMP spin_lock and restore irq state */
+	    spin_unlock_irqrestore(instance->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+
+
+#define RESET_CARD         0
+#define RESET_CARD_AND_BUS 1
+#define B_FLAG 0x80
+
+/*
+ *	Caller must hold instance lock!
+ */
+
+static int reset_hardware(struct Scsi_Host *instance, int type)
+{
+	struct IN2000_hostdata *hostdata;
+	int qt, x;
+
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	write1_io(0, IO_LED_ON);
+	if (type == RESET_CARD_AND_BUS) {
+		write1_io(0, IO_CARD_RESET);
+		x = read1_io(IO_HARDWARE);
+	}
+	x = read_3393(hostdata, WD_SCSI_STATUS);	/* clear any WD intrpt */
+	write_3393(hostdata, WD_OWN_ID, instance->this_id | OWNID_EAF | OWNID_RAF | OWNID_FS_8);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_3393(hostdata, WD_SYNCHRONOUS_TRANSFER, calc_sync_xfer(hostdata->default_sx_per / 4, DEFAULT_SX_OFF));
+
+	write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter */
+	write1_io(0, IO_FIFO_READ);	/* start fifo out in read mode */
+	write_3393(hostdata, WD_COMMAND, WD_CMD_RESET);
+	/* FIXME: timeout ?? */
+	while (!(READ_AUX_STAT() & ASR_INT))
+		cpu_relax();	/* wait for RESET to complete */
+
+	x = read_3393(hostdata, WD_SCSI_STATUS);	/* clear interrupt */
+
+	write_3393(hostdata, WD_QUEUE_TAG, 0xa5);	/* any random number */
+	qt = read_3393(hostdata, WD_QUEUE_TAG);
+	if (qt == 0xa5) {
+		x |= B_FLAG;
+		write_3393(hostdata, WD_QUEUE_TAG, 0);
+	}
+	write_3393(hostdata, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
+	write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write1_io(0, IO_LED_OFF);
+	return x;
+}
+
+
+
+static int in2000_bus_reset(Scsi_Cmnd * cmd)
+{
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	int x;
+
+	instance = cmd->device->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	printk(KERN_WARNING "scsi%d: Reset. ", instance->host_no);
+
+	/* do scsi-reset here */
+
+	reset_hardware(instance, RESET_CARD_AND_BUS);
+	for (x = 0; x < 8; x++) {
+		hostdata->busy[x] = 0;
+		hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+		hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */
+	}
+	hostdata->input_Q = NULL;
+	hostdata->selecting = NULL;
+	hostdata->connected = NULL;
+	hostdata->disconnected_Q = NULL;
+	hostdata->state = S_UNCONNECTED;
+	hostdata->fifo = FI_FIFO_UNUSED;
+	hostdata->incoming_ptr = 0;
+	hostdata->outgoing_len = 0;
+
+	cmd->result = DID_RESET << 16;
+	return SUCCESS;
+}
+
+static int in2000_host_reset(Scsi_Cmnd * cmd)
+{
+	return FAILED;
+}
+
+static int in2000_device_reset(Scsi_Cmnd * cmd)
+{
+	return FAILED;
+}
+
+
+static int in2000_abort(Scsi_Cmnd * cmd)
+{
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	Scsi_Cmnd *tmp, *prev;
+	uchar sr, asr;
+	unsigned long timeout;
+
+	instance = cmd->device->host;
+	hostdata = (struct IN2000_hostdata *) instance->hostdata;
+
+	printk(KERN_DEBUG "scsi%d: Abort-", instance->host_no);
+	printk("(asr=%02x,count=%ld,resid=%d,buf_resid=%d,have_data=%d,FC=%02x)- ", READ_AUX_STAT(), read_3393_count(hostdata), cmd->SCp.this_residual, cmd->SCp.buffers_residual, cmd->SCp.have_data_in, read1_io(IO_FIFO_COUNT));
+
+/*
+ * Case 1 : If the command hasn't been issued yet, we simply remove it
+ *     from the inout_Q.
+ */
+
+	tmp = (Scsi_Cmnd *) hostdata->input_Q;
+	prev = NULL;
+	while (tmp) {
+		if (tmp == cmd) {
+			if (prev)
+				prev->host_scribble = cmd->host_scribble;
+			cmd->host_scribble = NULL;
+			cmd->result = DID_ABORT << 16;
+			printk(KERN_WARNING "scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid);
+			cmd->scsi_done(cmd);
+			return SUCCESS;
+		}
+		prev = tmp;
+		tmp = (Scsi_Cmnd *) tmp->host_scribble;
+	}
+
+/*
+ * Case 2 : If the command is connected, we're going to fail the abort
+ *     and let the high level SCSI driver retry at a later time or
+ *     issue a reset.
+ *
+ *     Timeouts, and therefore aborted commands, will be highly unlikely
+ *     and handling them cleanly in this situation would make the common
+ *     case of noresets less efficient, and would pollute our code.  So,
+ *     we fail.
+ */
+
+	if (hostdata->connected == cmd) {
+
+		printk(KERN_WARNING "scsi%d: Aborting connected command %ld - ", instance->host_no, cmd->pid);
+
+		printk("sending wd33c93 ABORT command - ");
+		write_3393(hostdata, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+		write_3393_cmd(hostdata, WD_CMD_ABORT);
+
+/* Now we have to attempt to flush out the FIFO... */
+
+		printk("flushing fifo - ");
+		timeout = 1000000;
+		do {
+			asr = READ_AUX_STAT();
+			if (asr & ASR_DBR)
+				read_3393(hostdata, WD_DATA);
+		} while (!(asr & ASR_INT) && timeout-- > 0);
+		sr = read_3393(hostdata, WD_SCSI_STATUS);
+		printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", asr, sr, read_3393_count(hostdata), timeout);
+
+		/*
+		 * Abort command processed.
+		 * Still connected.
+		 * We must disconnect.
+		 */
+
+		printk("sending wd33c93 DISCONNECT command - ");
+		write_3393_cmd(hostdata, WD_CMD_DISCONNECT);
+
+		timeout = 1000000;
+		asr = READ_AUX_STAT();
+		while ((asr & ASR_CIP) && timeout-- > 0)
+			asr = READ_AUX_STAT();
+		sr = read_3393(hostdata, WD_SCSI_STATUS);
+		printk("asr=%02x, sr=%02x.", asr, sr);
+
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->connected = NULL;
+		hostdata->state = S_UNCONNECTED;
+		cmd->result = DID_ABORT << 16;
+		cmd->scsi_done(cmd);
+
+		in2000_execute(instance);
+
+		return SUCCESS;
+	}
+
+/*
+ * Case 3: If the command is currently disconnected from the bus,
+ * we're not going to expend much effort here: Let's just return
+ * an ABORT_SNOOZE and hope for the best...
+ */
+
+	for (tmp = (Scsi_Cmnd *) hostdata->disconnected_Q; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
+		if (cmd == tmp) {
+			printk(KERN_DEBUG "scsi%d: unable to abort disconnected command.\n", instance->host_no);
+			return FAILED;
+		}
+
+/*
+ * Case 4 : If we reached this point, the command was not found in any of
+ *     the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+	in2000_execute(instance);
+
+	printk("scsi%d: warning : SCSI command probably completed successfully" "         before abortion. ", instance->host_no);
+	return SUCCESS;
+}
+
+
+
+#define MAX_IN2000_HOSTS 3
+#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_ARGS];
+static int done_setup = 0;
+
+static void __init in2000_setup(char *str, int *ints)
+{
+	int i;
+	char *p1, *p2;
+
+	strlcpy(setup_buffer, str, SETUP_BUFFER_SIZE);
+	p1 = setup_buffer;
+	i = 0;
+	while (*p1 && (i < MAX_SETUP_ARGS)) {
+		p2 = strchr(p1, ',');
+		if (p2) {
+			*p2 = '\0';
+			if (p1 != p2)
+				setup_args[i] = p1;
+			p1 = p2 + 1;
+			i++;
+		} else {
+			setup_args[i] = p1;
+			break;
+		}
+	}
+	for (i = 0; i < MAX_SETUP_ARGS; i++)
+		setup_used[i] = 0;
+	done_setup = 1;
+}
+
+
+/* check_setup_args() returns index if key found, 0 if not
+ */
+
+static int __init check_setup_args(char *key, int *val, char *buf)
+{
+	int x;
+	char *cp;
+
+	for (x = 0; x < MAX_SETUP_ARGS; x++) {
+		if (setup_used[x])
+			continue;
+		if (!strncmp(setup_args[x], key, strlen(key)))
+			break;
+	}
+	if (x == MAX_SETUP_ARGS)
+		return 0;
+	setup_used[x] = 1;
+	cp = setup_args[x] + strlen(key);
+	*val = -1;
+	if (*cp != ':')
+		return ++x;
+	cp++;
+	if ((*cp >= '0') && (*cp <= '9')) {
+		*val = simple_strtoul(cp, NULL, 0);
+	}
+	return ++x;
+}
+
+
+
+/* The "correct" (ie portable) way to access memory-mapped hardware
+ * such as the IN2000 EPROM and dip switch is through the use of
+ * special macros declared in 'asm/io.h'. We use readb() and readl()
+ * when reading from the card's BIOS area in in2000_detect().
+ */
+static u32 bios_tab[] in2000__INITDATA = {
+	0xc8000,
+	0xd0000,
+	0xd8000,
+	0
+};
+
+static unsigned short base_tab[] in2000__INITDATA = {
+	0x220,
+	0x200,
+	0x110,
+	0x100,
+};
+
+static int int_tab[] in2000__INITDATA = {
+	15,
+	14,
+	11,
+	10
+};
+
+
+static int __init in2000_detect(Scsi_Host_Template * tpnt)
+{
+	struct Scsi_Host *instance;
+	struct IN2000_hostdata *hostdata;
+	int detect_count;
+	int bios;
+	int x;
+	unsigned short base;
+	uchar switches;
+	uchar hrev;
+	unsigned long flags;
+	int val;
+	char buf[32];
+
+/* Thanks to help from Bill Earnest, probing for IN2000 cards is a
+ * pretty straightforward and fool-proof operation. There are 3
+ * possible locations for the IN2000 EPROM in memory space - if we
+ * find a BIOS signature, we can read the dip switch settings from
+ * the byte at BIOS+32 (shadowed in by logic on the card). From 2
+ * of the switch bits we get the card's address in IO space. There's
+ * an image of the dip switch there, also, so we have a way to back-
+ * check that this really is an IN2000 card. Very nifty. Use the
+ * 'ioport:xx' command-line parameter if your BIOS EPROM is absent
+ * or disabled.
+ */
+
+	if (!done_setup && setup_strings)
+		in2000_setup(setup_strings, NULL);
+
+	detect_count = 0;
+	for (bios = 0; bios_tab[bios]; bios++) {
+		if (check_setup_args("ioport", &val, buf)) {
+			base = val;
+			switches = ~inb(base + IO_SWITCHES) & 0xff;
+			printk("Forcing IN2000 detection at IOport 0x%x ", base);
+			bios = 2;
+		}
+/*
+ * There have been a couple of BIOS versions with different layouts
+ * for the obvious ID strings. We look for the 2 most common ones and
+ * hope that they cover all the cases...
+ */
+		else if (isa_readl(bios_tab[bios] + 0x10) == 0x41564f4e || isa_readl(bios_tab[bios] + 0x30) == 0x61776c41) {
+			printk("Found IN2000 BIOS at 0x%x ", (unsigned int) bios_tab[bios]);
+
+/* Read the switch image that's mapped into EPROM space */
+
+			switches = ~((isa_readb(bios_tab[bios] + 0x20) & 0xff));
+
+/* Find out where the IO space is */
+
+			x = switches & (SW_ADDR0 | SW_ADDR1);
+			base = base_tab[x];
+
+/* Check for the IN2000 signature in IO space. */
+
+			x = ~inb(base + IO_SWITCHES) & 0xff;
+			if (x != switches) {
+				printk("Bad IO signature: %02x vs %02x.\n", x, switches);
+				continue;
+			}
+		} else
+			continue;
+
+/* OK. We have a base address for the IO ports - run a few safety checks */
+
+		if (!(switches & SW_BIT7)) {	/* I _think_ all cards do this */
+			printk("There is no IN-2000 SCSI card at IOport 0x%03x!\n", base);
+			continue;
+		}
+
+/* Let's assume any hardware version will work, although the driver
+ * has only been tested on 0x21, 0x22, 0x25, 0x26, and 0x27. We'll
+ * print out the rev number for reference later, but accept them all.
+ */
+
+		hrev = inb(base + IO_HARDWARE);
+
+		/* Bit 2 tells us if interrupts are disabled */
+		if (switches & SW_DISINT) {
+			printk("The IN-2000 SCSI card at IOport 0x%03x ", base);
+			printk("is not configured for interrupt operation!\n");
+			printk("This driver requires an interrupt: cancelling detection.\n");
+			continue;
+		}
+
+/* Ok. We accept that there's an IN2000 at ioaddr 'base'. Now
+ * initialize it.
+ */
+
+		tpnt->proc_name = "in2000";
+		instance = scsi_register(tpnt, sizeof(struct IN2000_hostdata));
+		if (instance == NULL)
+			continue;
+		detect_count++;
+		hostdata = (struct IN2000_hostdata *) instance->hostdata;
+		instance->io_port = hostdata->io_base = base;
+		hostdata->dip_switch = switches;
+		hostdata->hrev = hrev;
+
+		write1_io(0, IO_FIFO_WRITE);	/* clear fifo counter */
+		write1_io(0, IO_FIFO_READ);	/* start fifo out in read mode */
+		write1_io(0, IO_INTR_MASK);	/* allow all ints */
+		x = int_tab[(switches & (SW_INT0 | SW_INT1)) >> SW_INT_SHIFT];
+		if (request_irq(x, in2000_intr, SA_INTERRUPT, "in2000", instance)) {
+			printk("in2000_detect: Unable to allocate IRQ.\n");
+			detect_count--;
+			continue;
+		}
+		instance->irq = x;
+		instance->n_io_port = 13;
+		request_region(base, 13, "in2000");	/* lock in this IO space for our use */
+
+		for (x = 0; x < 8; x++) {
+			hostdata->busy[x] = 0;
+			hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+			hostdata->sync_stat[x] = SS_UNSET;	/* using default sync values */
+#ifdef PROC_STATISTICS
+			hostdata->cmd_cnt[x] = 0;
+			hostdata->disc_allowed_cnt[x] = 0;
+			hostdata->disc_done_cnt[x] = 0;
+#endif
+		}
+		hostdata->input_Q = NULL;
+		hostdata->selecting = NULL;
+		hostdata->connected = NULL;
+		hostdata->disconnected_Q = NULL;
+		hostdata->state = S_UNCONNECTED;
+		hostdata->fifo = FI_FIFO_UNUSED;
+		hostdata->level2 = L2_BASIC;
+		hostdata->disconnect = DIS_ADAPTIVE;
+		hostdata->args = DEBUG_DEFAULTS;
+		hostdata->incoming_ptr = 0;
+		hostdata->outgoing_len = 0;
+		hostdata->default_sx_per = DEFAULT_SX_PER;
+
+/* Older BIOS's had a 'sync on/off' switch - use its setting */
+
+		if (isa_readl(bios_tab[bios] + 0x10) == 0x41564f4e && (switches & SW_SYNC_DOS5))
+			hostdata->sync_off = 0x00;	/* sync defaults to on */
+		else
+			hostdata->sync_off = 0xff;	/* sync defaults to off */
+
+#ifdef PROC_INTERFACE
+		hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS | PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
+#ifdef PROC_STATISTICS
+		hostdata->int_cnt = 0;
+#endif
+#endif
+
+		if (check_setup_args("nosync", &val, buf))
+			hostdata->sync_off = val;
+
+		if (check_setup_args("period", &val, buf))
+			hostdata->default_sx_per = sx_table[round_period((unsigned int) val)].period_ns;
+
+		if (check_setup_args("disconnect", &val, buf)) {
+			if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
+				hostdata->disconnect = val;
+			else
+				hostdata->disconnect = DIS_ADAPTIVE;
+		}
+
+		if (check_setup_args("noreset", &val, buf))
+			hostdata->args ^= A_NO_SCSI_RESET;
+
+		if (check_setup_args("level2", &val, buf))
+			hostdata->level2 = val;
+
+		if (check_setup_args("debug", &val, buf))
+			hostdata->args = (val & DB_MASK);
+
+#ifdef PROC_INTERFACE
+		if (check_setup_args("proc", &val, buf))
+			hostdata->proc = val;
+#endif
+
+
+		/* FIXME: not strictly needed I think but the called code expects
+		   to be locked */
+		spin_lock_irqsave(instance->host_lock, flags);
+		x = reset_hardware(instance, (hostdata->args & A_NO_SCSI_RESET) ? RESET_CARD : RESET_CARD_AND_BUS);
+		spin_unlock_irqrestore(instance->host_lock, flags);
+
+		hostdata->microcode = read_3393(hostdata, WD_CDB_1);
+		if (x & 0x01) {
+			if (x & B_FLAG)
+				hostdata->chip = C_WD33C93B;
+			else
+				hostdata->chip = C_WD33C93A;
+		} else
+			hostdata->chip = C_WD33C93;
+
+		printk("dip_switch=%02x irq=%d ioport=%02x floppy=%s sync/DOS5=%s ", (switches & 0x7f), instance->irq, hostdata->io_base, (switches & SW_FLOPPY) ? "Yes" : "No", (switches & SW_SYNC_DOS5) ? "Yes" : "No");
+		printk("hardware_ver=%02x chip=%s microcode=%02x\n", hrev, (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip == C_WD33C93A) ? "WD33c93A" : (hostdata->chip == C_WD33C93B) ? "WD33c93B" : "unknown", hostdata->microcode);
+#ifdef DEBUGGING_ON
+		printk("setup_args = ");
+		for (x = 0; x < MAX_SETUP_ARGS; x++)
+			printk("%s,", setup_args[x]);
+		printk("\n");
+#endif
+		if (hostdata->sync_off == 0xff)
+			printk("Sync-transfer DISABLED on all devices: ENABLE from command-line\n");
+		printk("IN2000 driver version %s - %s\n", IN2000_VERSION, IN2000_DATE);
+	}
+
+	return detect_count;
+}
+
+static int in2000_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, shost);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	return 0;
+}
+
+/* NOTE: I lifted this function straight out of the old driver,
+ *       and have not tested it. Presumably it does what it's
+ *       supposed to do...
+ */
+
+static int in2000_biosparam(struct scsi_device *sdev, struct block_device *bdev, sector_t capacity, int *iinfo)
+{
+	int size;
+
+	size = capacity;
+	iinfo[0] = 64;
+	iinfo[1] = 32;
+	iinfo[2] = size >> 11;
+
+/* This should approximate the large drive handling that the DOS ASPI manager
+   uses.  Drives very near the boundaries may not be handled correctly (i.e.
+   near 2.0 Gb and 4.0 Gb) */
+
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 64;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 128;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	if (iinfo[2] > 1024) {
+		iinfo[0] = 255;
+		iinfo[1] = 63;
+		iinfo[2] = (unsigned long) capacity / (iinfo[0] * iinfo[1]);
+	}
+	return 0;
+}
+
+
+static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
+{
+
+#ifdef PROC_INTERFACE
+
+	char *bp;
+	char tbuf[128];
+	unsigned long flags;
+	struct IN2000_hostdata *hd;
+	Scsi_Cmnd *cmd;
+	int x, i;
+	static int stop = 0;
+
+	hd = (struct IN2000_hostdata *) instance->hostdata;
+
+/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
+ * keywords (same format as command-line, but only ONE per read):
+ *    debug
+ *    disconnect
+ *    period
+ *    resync
+ *    proc
+ */
+
+	if (in) {
+		buf[len] = '\0';
+		bp = buf;
+		if (!strncmp(bp, "debug:", 6)) {
+			bp += 6;
+			hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
+		} else if (!strncmp(bp, "disconnect:", 11)) {
+			bp += 11;
+			x = simple_strtoul(bp, NULL, 0);
+			if (x < DIS_NEVER || x > DIS_ALWAYS)
+				x = DIS_ADAPTIVE;
+			hd->disconnect = x;
+		} else if (!strncmp(bp, "period:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			hd->default_sx_per = sx_table[round_period((unsigned int) x)].period_ns;
+		} else if (!strncmp(bp, "resync:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			for (i = 0; i < 7; i++)
+				if (x & (1 << i))
+					hd->sync_stat[i] = SS_UNSET;
+		} else if (!strncmp(bp, "proc:", 5)) {
+			bp += 5;
+			hd->proc = simple_strtoul(bp, NULL, 0);
+		} else if (!strncmp(bp, "level2:", 7)) {
+			bp += 7;
+			hd->level2 = simple_strtoul(bp, NULL, 0);
+		}
+		return len;
+	}
+
+	spin_lock_irqsave(instance->host_lock, flags);
+	bp = buf;
+	*bp = '\0';
+	if (hd->proc & PR_VERSION) {
+		sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s", IN2000_VERSION, IN2000_DATE, __DATE__, __TIME__);
+		strcat(bp, tbuf);
+	}
+	if (hd->proc & PR_INFO) {
+		sprintf(tbuf, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
+		strcat(bp, tbuf);
+		strcat(bp, "\nsync_xfer[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\nsync_stat[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
+			strcat(bp, tbuf);
+		}
+	}
+#ifdef PROC_STATISTICS
+	if (hd->proc & PR_STATISTICS) {
+		strcat(bp, "\ncommands issued:    ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects allowed:");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects done:   ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		sprintf(tbuf, "\ninterrupts:      \t%ld", hd->int_cnt);
+		strcat(bp, tbuf);
+	}
+#endif
+	if (hd->proc & PR_CONNECTED) {
+		strcat(bp, "\nconnected:     ");
+		if (hd->connected) {
+			cmd = (Scsi_Cmnd *) hd->connected;
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+		}
+	}
+	if (hd->proc & PR_INPUTQ) {
+		strcat(bp, "\ninput_Q:       ");
+		cmd = (Scsi_Cmnd *) hd->input_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+	}
+	if (hd->proc & PR_DISCQ) {
+		strcat(bp, "\ndisconnected_Q:");
+		cmd = (Scsi_Cmnd *) hd->disconnected_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)", cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (Scsi_Cmnd *) cmd->host_scribble;
+		}
+	}
+	if (hd->proc & PR_TEST) {
+		;		/* insert your own custom function here */
+	}
+	strcat(bp, "\n");
+	spin_unlock_irqrestore(instance->host_lock, flags);
+	*start = buf;
+	if (stop) {
+		stop = 0;
+		return 0;	/* return 0 to signal end-of-file */
+	}
+	if (off > 0x40000)	/* ALWAYS stop after 256k bytes have been read */
+		stop = 1;
+	if (hd->proc & PR_STOP)	/* stop every other time */
+		stop = 1;
+	return strlen(bp);
+
+#else				/* PROC_INTERFACE */
+
+	return 0;
+
+#endif				/* PROC_INTERFACE */
+
+}
+
+MODULE_LICENSE("GPL");
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name       		= "in2000",
+	.proc_info       		= in2000_proc_info,
+	.name            		= "Always IN2000",
+	.detect          		= in2000_detect, 
+	.release			= in2000_release,
+	.queuecommand    		= in2000_queuecommand,
+	.eh_abort_handler		= in2000_abort,
+	.eh_bus_reset_handler		= in2000_bus_reset,
+	.eh_device_reset_handler	= in2000_device_reset,
+	.eh_host_reset_handler	= in2000_host_reset, 
+	.bios_param      		= in2000_biosparam, 
+	.can_queue       		= IN2000_CAN_Q,
+	.this_id         		= IN2000_HOST_ID,
+	.sg_tablesize    		= IN2000_SG,
+	.cmd_per_lun     		= IN2000_CPL,
+	.use_clustering  		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
new file mode 100644
index 0000000..019e45d
--- /dev/null
+++ b/drivers/scsi/in2000.h
@@ -0,0 +1,414 @@
+/*
+ *    in2000.h -  Linux device driver definitions for the
+ *                Always IN2000 ISA SCSI card.
+ *
+ *    IMPORTANT: This file is for version 1.33 - 26/Aug/1998
+ *
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef IN2000_H
+#define IN2000_H
+
+#include <asm/io.h>
+
+#define PROC_INTERFACE     /* add code for /proc/scsi/in2000/xxx interface */
+#ifdef  PROC_INTERFACE
+#define PROC_STATISTICS    /* add code for keeping various real time stats */
+#endif
+
+#define SYNC_DEBUG         /* extra info on sync negotiation printed */
+#define DEBUGGING_ON       /* enable command-line debugging bitmask */
+#define DEBUG_DEFAULTS 0   /* default bitmask - change from command-line */
+
+#ifdef __i386__
+#define FAST_READ_IO       /* No problems with these on my machine */
+#define FAST_WRITE_IO
+#endif
+
+#ifdef DEBUGGING_ON
+#define DB(f,a) if (hostdata->args & (f)) a;
+#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */
+#else
+#define DB(f,a)
+#define CHECK_NULL(p,s)
+#endif
+
+#define uchar unsigned char
+
+#define read1_io(a)     (inb(hostdata->io_base+(a)))
+#define read2_io(a)     (inw(hostdata->io_base+(a)))
+#define write1_io(b,a)  (outb((b),hostdata->io_base+(a)))
+#define write2_io(w,a)  (outw((w),hostdata->io_base+(a)))
+
+#ifdef __i386__
+/* These inline assembly defines are derived from a patch
+ * sent to me by Bill Earnest. He's done a lot of very
+ * valuable thinking, testing, and coding during his effort
+ * to squeeze more speed out of this driver. I really think
+ * that we are doing IO at close to the maximum now with
+ * the fifo. (And yes, insw uses 'edi' while outsw uses
+ * 'esi'. Thanks Bill!)
+ */
+
+#define FAST_READ2_IO()    \
+({ \
+int __dummy_1,__dummy_2; \
+   __asm__ __volatile__ ("\n \
+   cld                    \n \
+   orl %%ecx, %%ecx       \n \
+   jz 1f                  \n \
+   rep                    \n \
+   insw (%%dx),%%es:(%%edi) \n \
+1: "                       \
+   : "=D" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)  /* output */   \
+   : "2" (f), "0" (sp), "1" (i)  /* input */    \
+   );       /* trashed */ \
+})
+
+#define FAST_WRITE2_IO()   \
+({ \
+int __dummy_1,__dummy_2; \
+   __asm__ __volatile__ ("\n \
+   cld                    \n \
+   orl %%ecx, %%ecx       \n \
+   jz 1f                  \n \
+   rep                    \n \
+   outsw %%ds:(%%esi),(%%dx) \n \
+1: "                       \
+   : "=S" (sp) ,"=c" (__dummy_1) ,"=d" (__dummy_2)/* output */   \
+   : "2" (f), "0" (sp), "1" (i)  /* input */    \
+   );       /* trashed */ \
+})
+#endif
+
+/* IN2000 io_port offsets */
+#define IO_WD_ASR       0x00     /* R - 3393 auxstat reg */
+#define     ASR_INT        0x80
+#define     ASR_LCI        0x40
+#define     ASR_BSY        0x20
+#define     ASR_CIP        0x10
+#define     ASR_PE         0x02
+#define     ASR_DBR        0x01
+#define IO_WD_ADDR      0x00     /* W - 3393 address reg */
+#define IO_WD_DATA      0x01     /* R/W - rest of 3393 regs */
+#define IO_FIFO         0x02     /* R/W - in2000 dual-port fifo (16 bits) */
+#define IN2000_FIFO_SIZE   2048  /*    fifo capacity in bytes */
+#define IO_CARD_RESET   0x03     /* W - in2000 start master reset */
+#define IO_FIFO_COUNT   0x04     /* R - in2000 fifo counter */
+#define IO_FIFO_WRITE   0x05     /* W - clear fifo counter, start write */
+#define IO_FIFO_READ    0x07     /* W - start fifo read */
+#define IO_LED_OFF      0x08     /* W - turn off in2000 activity LED */
+#define IO_SWITCHES     0x08     /* R - read in2000 dip switch */
+#define     SW_ADDR0       0x01  /*    bit 0 = bit 0 of index to io addr */
+#define     SW_ADDR1       0x02  /*    bit 1 = bit 1 of index io addr */
+#define     SW_DISINT      0x04  /*    bit 2 true if ints disabled */
+#define     SW_INT0        0x08  /*    bit 3 = bit 0 of index to interrupt */
+#define     SW_INT1        0x10  /*    bit 4 = bit 1 of index to interrupt */
+#define     SW_INT_SHIFT   3     /*    shift right this amount to right justify int bits */
+#define     SW_SYNC_DOS5   0x20  /*    bit 5 used by Always BIOS */
+#define     SW_FLOPPY      0x40  /*    bit 6 true if floppy enabled */
+#define     SW_BIT7        0x80  /*    bit 7 hardwired true (ground) */
+#define IO_LED_ON       0x09     /* W - turn on in2000 activity LED */
+#define IO_HARDWARE     0x0a     /* R - read in2000 hardware rev, stop reset */
+#define IO_INTR_MASK    0x0c     /* W - in2000 interrupt mask reg */
+#define     IMASK_WD       0x01  /*    WD33c93 interrupt mask */
+#define     IMASK_FIFO     0x02  /*    FIFO interrupt mask */
+
+/* wd register names */
+#define WD_OWN_ID    0x00
+#define WD_CONTROL   0x01
+#define WD_TIMEOUT_PERIOD  0x02
+#define WD_CDB_1     0x03
+#define WD_CDB_2     0x04
+#define WD_CDB_3     0x05
+#define WD_CDB_4     0x06
+#define WD_CDB_5     0x07
+#define WD_CDB_6     0x08
+#define WD_CDB_7     0x09
+#define WD_CDB_8     0x0a
+#define WD_CDB_9     0x0b
+#define WD_CDB_10    0x0c
+#define WD_CDB_11    0x0d
+#define WD_CDB_12    0x0e
+#define WD_TARGET_LUN      0x0f
+#define WD_COMMAND_PHASE   0x10
+#define WD_SYNCHRONOUS_TRANSFER  0x11
+#define WD_TRANSFER_COUNT_MSB 0x12
+#define WD_TRANSFER_COUNT  0x13
+#define WD_TRANSFER_COUNT_LSB 0x14
+#define WD_DESTINATION_ID  0x15
+#define WD_SOURCE_ID    0x16
+#define WD_SCSI_STATUS     0x17
+#define WD_COMMAND      0x18
+#define WD_DATA      0x19
+#define WD_QUEUE_TAG    0x1a
+#define WD_AUXILIARY_STATUS   0x1f
+
+/* WD commands */
+#define WD_CMD_RESET    0x00
+#define WD_CMD_ABORT    0x01
+#define WD_CMD_ASSERT_ATN  0x02
+#define WD_CMD_NEGATE_ACK  0x03
+#define WD_CMD_DISCONNECT  0x04
+#define WD_CMD_RESELECT    0x05
+#define WD_CMD_SEL_ATN     0x06
+#define WD_CMD_SEL      0x07
+#define WD_CMD_SEL_ATN_XFER   0x08
+#define WD_CMD_SEL_XFER    0x09
+#define WD_CMD_RESEL_RECEIVE  0x0a
+#define WD_CMD_RESEL_SEND  0x0b
+#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
+#define WD_CMD_TRANS_ADDR  0x18
+#define WD_CMD_TRANS_INFO  0x20
+#define WD_CMD_TRANSFER_PAD   0x21
+#define WD_CMD_SBT_MODE    0x80
+
+/* SCSI Bus Phases */
+#define PHS_DATA_OUT    0x00
+#define PHS_DATA_IN     0x01
+#define PHS_COMMAND     0x02
+#define PHS_STATUS      0x03
+#define PHS_MESS_OUT    0x06
+#define PHS_MESS_IN     0x07
+
+/* Command Status Register definitions */
+
+  /* reset state interrupts */
+#define CSR_RESET    0x00
+#define CSR_RESET_AF    0x01
+
+  /* successful completion interrupts */
+#define CSR_RESELECT    0x10
+#define CSR_SELECT      0x11
+#define CSR_SEL_XFER_DONE  0x16
+#define CSR_XFER_DONE      0x18
+
+  /* paused or aborted interrupts */
+#define CSR_MSGIN    0x20
+#define CSR_SDP         0x21
+#define CSR_SEL_ABORT      0x22
+#define CSR_RESEL_ABORT    0x25
+#define CSR_RESEL_ABORT_AM 0x27
+#define CSR_ABORT    0x28
+
+  /* terminated interrupts */
+#define CSR_INVALID     0x40
+#define CSR_UNEXP_DISC     0x41
+#define CSR_TIMEOUT     0x42
+#define CSR_PARITY      0x43
+#define CSR_PARITY_ATN     0x44
+#define CSR_BAD_STATUS     0x45
+#define CSR_UNEXP    0x48
+
+  /* service required interrupts */
+#define CSR_RESEL    0x80
+#define CSR_RESEL_AM    0x81
+#define CSR_DISC     0x85
+#define CSR_SRV_REQ     0x88
+
+   /* Own ID/CDB Size register */
+#define OWNID_EAF    0x08
+#define OWNID_EHP    0x10
+#define OWNID_RAF    0x20
+#define OWNID_FS_8   0x00
+#define OWNID_FS_12  0x40
+#define OWNID_FS_16  0x80
+
+   /* Control register */
+#define CTRL_HSP     0x01
+#define CTRL_HA      0x02
+#define CTRL_IDI     0x04
+#define CTRL_EDI     0x08
+#define CTRL_HHP     0x10
+#define CTRL_POLLED  0x00
+#define CTRL_BURST   0x20
+#define CTRL_BUS     0x40
+#define CTRL_DMA     0x80
+
+   /* Timeout Period register */
+#define TIMEOUT_PERIOD_VALUE  20    /* results in 200 ms. */
+
+   /* Synchronous Transfer Register */
+#define STR_FSS      0x80
+
+   /* Destination ID register */
+#define DSTID_DPD    0x40
+#define DATA_OUT_DIR 0
+#define DATA_IN_DIR  1
+#define DSTID_SCC    0x80
+
+   /* Source ID register */
+#define SRCID_MASK   0x07
+#define SRCID_SIV    0x08
+#define SRCID_DSP    0x20
+#define SRCID_ES     0x40
+#define SRCID_ER     0x80
+
+
+
+#define ILLEGAL_STATUS_BYTE   0xff
+
+
+#define DEFAULT_SX_PER     500   /* (ns) fairly safe */
+#define DEFAULT_SX_OFF     0     /* aka async */
+
+#define OPTIMUM_SX_PER     252   /* (ns) best we can do (mult-of-4) */
+#define OPTIMUM_SX_OFF     12    /* size of in2000 fifo */
+
+struct sx_period {
+   unsigned int   period_ns;
+   uchar          reg_value;
+   };
+
+
+struct IN2000_hostdata {
+    struct Scsi_Host *next;
+    uchar            chip;             /* what kind of wd33c93 chip? */
+    uchar            microcode;        /* microcode rev if 'B' */
+    unsigned short   io_base;          /* IO port base */
+    unsigned int     dip_switch;       /* dip switch settings */
+    unsigned int     hrev;             /* hardware revision of card */
+    volatile uchar   busy[8];          /* index = target, bit = lun */
+    volatile Scsi_Cmnd *input_Q;       /* commands waiting to be started */
+    volatile Scsi_Cmnd *selecting;     /* trying to select this command */
+    volatile Scsi_Cmnd *connected;     /* currently connected command */
+    volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */
+    uchar            state;            /* what we are currently doing */
+    uchar            fifo;             /* what the FIFO is up to */
+    uchar            level2;           /* extent to which Level-2 commands are used */
+    uchar            disconnect;       /* disconnect/reselect policy */
+    unsigned int     args;             /* set from command-line argument */
+    uchar            incoming_msg[8];  /* filled during message_in phase */
+    int              incoming_ptr;     /* mainly used with EXTENDED messages */
+    uchar            outgoing_msg[8];  /* send this during next message_out */
+    int              outgoing_len;     /* length of outgoing message */
+    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
+    uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
+    uchar            sync_stat[8];     /* status of sync negotiation per target */
+    uchar            sync_off;         /* bit mask: don't use sync with these targets */
+#ifdef PROC_INTERFACE
+    uchar            proc;             /* bit mask: what's in proc output */
+#ifdef PROC_STATISTICS
+    unsigned long    cmd_cnt[8];       /* # of commands issued per target */
+    unsigned long    int_cnt;          /* # of interrupts serviced */
+    unsigned long    disc_allowed_cnt[8]; /* # of disconnects allowed per target */
+    unsigned long    disc_done_cnt[8]; /* # of disconnects done per target*/
+#endif
+#endif
+    };
+
+
+/* defines for hostdata->chip */
+
+#define C_WD33C93       0
+#define C_WD33C93A      1
+#define C_WD33C93B      2
+#define C_UNKNOWN_CHIP  100
+
+/* defines for hostdata->state */
+
+#define S_UNCONNECTED         0
+#define S_SELECTING           1
+#define S_RUNNING_LEVEL2      2
+#define S_CONNECTED           3
+#define S_PRE_TMP_DISC        4
+#define S_PRE_CMP_DISC        5
+
+/* defines for hostdata->fifo */
+
+#define FI_FIFO_UNUSED        0
+#define FI_FIFO_READING       1
+#define FI_FIFO_WRITING       2
+
+/* defines for hostdata->level2 */
+/* NOTE: only the first 3 are trustworthy at this point -
+ * having trouble when more than 1 device is reading/writing
+ * at the same time...
+ */
+
+#define L2_NONE      0  /* no combination commands - we get lots of ints */
+#define L2_SELECT    1  /* start with SEL_ATN_XFER, but never resume it */
+#define L2_BASIC     2  /* resume after STATUS ints & RDP messages */
+#define L2_DATA      3  /* resume after DATA_IN/OUT ints */
+#define L2_MOST      4  /* resume after anything except a RESELECT int */
+#define L2_RESELECT  5  /* resume after everything, including RESELECT ints */
+#define L2_ALL       6  /* always resume */
+
+/* defines for hostdata->disconnect */
+
+#define DIS_NEVER    0
+#define DIS_ADAPTIVE 1
+#define DIS_ALWAYS   2
+
+/* defines for hostdata->args */
+
+#define DB_TEST               1<<0
+#define DB_FIFO               1<<1
+#define DB_QUEUE_COMMAND      1<<2
+#define DB_EXECUTE            1<<3
+#define DB_INTR               1<<4
+#define DB_TRANSFER           1<<5
+#define DB_MASK               0x3f
+
+#define A_NO_SCSI_RESET       1<<15
+
+
+/* defines for hostdata->sync_xfer[] */
+
+#define SS_UNSET     0
+#define SS_FIRST     1
+#define SS_WAITING   2
+#define SS_SET       3
+
+/* defines for hostdata->proc */
+
+#define PR_VERSION   1<<0
+#define PR_INFO      1<<1
+#define PR_STATISTICS 1<<2
+#define PR_CONNECTED 1<<3
+#define PR_INPUTQ    1<<4
+#define PR_DISCQ     1<<5
+#define PR_TEST      1<<6
+#define PR_STOP      1<<7
+
+
+# include <linux/init.h>
+# include <linux/spinlock.h>
+# define in2000__INITFUNC(function) __initfunc(function)
+# define in2000__INIT __init
+# define in2000__INITDATA __initdata
+# define CLISPIN_LOCK(host,flags)   spin_lock_irqsave(host->host_lock, flags)
+# define CLISPIN_UNLOCK(host,flags) spin_unlock_irqrestore(host->host_lock, \
+							   flags)
+
+static int in2000_detect(Scsi_Host_Template *) in2000__INIT;
+static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int in2000_abort(Scsi_Cmnd *);
+static void in2000_setup(char *, int *) in2000__INIT;
+static int in2000_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int *);
+static int in2000_host_reset(Scsi_Cmnd *);
+static int in2000_bus_reset(Scsi_Cmnd *);
+static int in2000_device_reset(Scsi_Cmnd *);
+
+
+#define IN2000_CAN_Q    16
+#define IN2000_SG       SG_ALL
+#define IN2000_CPL      2
+#define IN2000_HOST_ID  7
+
+#endif /* IN2000_H */
diff --git a/drivers/scsi/initio.c b/drivers/scsi/initio.c
new file mode 100644
index 0000000..a7b74d8
--- /dev/null
+++ b/drivers/scsi/initio.c
@@ -0,0 +1,3184 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * Copyright (c) 1998 Bas Vermeulen <bvermeul@blackstar.xs4all.nl>
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *************************************************************************
+ *
+ * DESCRIPTION:
+ *
+ * This is the Linux low-level SCSI driver for Initio INI-9X00U/UW SCSI host
+ * adapters
+ *
+ * 08/06/97 hc	- v1.01h
+ *		- Support inic-940 and inic-935
+ * 09/26/97 hc	- v1.01i
+ *		- Make correction from J.W. Schultz suggestion
+ * 10/13/97 hc	- Support reset function
+ * 10/21/97 hc	- v1.01j
+ *		- Support 32 LUN (SCSI 3)
+ * 01/14/98 hc	- v1.01k
+ *		- Fix memory allocation problem
+ * 03/04/98 hc	- v1.01l
+ *		- Fix tape rewind which will hang the system problem
+ *		- Set can_queue to tul_num_scb
+ * 06/25/98 hc	- v1.01m
+ *		- Get it work for kernel version >= 2.1.75
+ *		- Dynamic assign SCSI bus reset holding time in init_tulip()
+ * 07/02/98 hc	- v1.01n
+ *		- Support 0002134A
+ * 08/07/98 hc  - v1.01o
+ *		- Change the tul_abort_srb routine to use scsi_done. <01>
+ * 09/07/98 hl  - v1.02
+ *              - Change the INI9100U define and proc_dir_entry to
+ *                reflect the newer Kernel 2.1.118, but the v1.o1o
+ *                should work with Kernel 2.1.118.
+ * 09/20/98 wh  - v1.02a
+ *              - Support Abort command.
+ *              - Handle reset routine.
+ * 09/21/98 hl  - v1.03
+ *              - remove comments.
+ * 12/09/98 bv	- v1.03a
+ *		- Removed unused code
+ * 12/13/98 bv	- v1.03b
+ *		- Remove cli() locking for kernels >= 2.1.95. This uses
+ *		  spinlocks to serialize access to the pSRB_head and
+ *		  pSRB_tail members of the HCS structure.
+ * 09/01/99 bv	- v1.03d
+ *		- Fixed a deadlock problem in SMP.
+ * 21/01/99 bv	- v1.03e
+ *		- Add support for the Domex 3192U PCI SCSI
+ *		  This is a slightly modified patch by
+ *		  Brian Macy <bmacy@sunshinecomputing.com>
+ * 22/02/99 bv	- v1.03f
+ *		- Didn't detect the INIC-950 in 2.0.x correctly.
+ *		  Now fixed.
+ * 05/07/99 bv	- v1.03g
+ *		- Changed the assumption that HZ = 100
+ * 10/17/03 mc	- v1.04
+ *		- added new DMA API support
+ * 06/01/04 jmd	- v1.04a
+ *		- Re-add reset_bus support
+ **************************************************************************/
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+
+#include "initio.h"
+
+#define SENSE_SIZE		14
+
+#define i91u_MAXQUEUE		2
+#define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.04a"
+
+#define INI_VENDOR_ID   0x1101	/* Initio's PCI vendor ID       */
+#define DMX_VENDOR_ID	0x134a	/* Domex's PCI vendor ID	*/
+#define I950_DEVICE_ID	0x9500	/* Initio's inic-950 product ID   */
+#define I940_DEVICE_ID	0x9400	/* Initio's inic-940 product ID   */
+#define I935_DEVICE_ID	0x9401	/* Initio's inic-935 product ID   */
+#define I920_DEVICE_ID	0x0002	/* Initio's other product ID      */
+
+#ifdef DEBUG_i91u
+static unsigned int i91u_debug = DEBUG_DEFAULT;
+#endif
+
+#define TULSZ(sz)     (sizeof(sz) / sizeof(sz[0]))
+#define TUL_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
+
+typedef struct PCI_ID_Struc {
+	unsigned short vendor_id;
+	unsigned short device_id;
+} PCI_ID;
+
+static int tul_num_ch = 4;	/* Maximum 4 adapters           */
+static int tul_num_scb;
+static int tul_tag_enable = 1;
+static SCB *tul_scb;
+
+#ifdef DEBUG_i91u
+static int setup_debug = 0;
+#endif
+
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb);
+
+static const PCI_ID i91u_pci_devices[] = {
+	{ INI_VENDOR_ID, I950_DEVICE_ID },
+	{ INI_VENDOR_ID, I940_DEVICE_ID },
+	{ INI_VENDOR_ID, I935_DEVICE_ID },
+	{ INI_VENDOR_ID, I920_DEVICE_ID },
+	{ DMX_VENDOR_ID, I920_DEVICE_ID },
+};
+
+#define DEBUG_INTERRUPT 0
+#define DEBUG_QUEUE     0
+#define DEBUG_STATE     0
+#define INT_DISC	0
+
+/*--- external functions --*/
+static void tul_se2_wait(void);
+
+/*--- forward refrence ---*/
+static SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun);
+static SCB *tul_find_done_scb(HCS * pCurHcb);
+
+static int tulip_main(HCS * pCurHcb);
+
+static int tul_next_state(HCS * pCurHcb);
+static int tul_state_1(HCS * pCurHcb);
+static int tul_state_2(HCS * pCurHcb);
+static int tul_state_3(HCS * pCurHcb);
+static int tul_state_4(HCS * pCurHcb);
+static int tul_state_5(HCS * pCurHcb);
+static int tul_state_6(HCS * pCurHcb);
+static int tul_state_7(HCS * pCurHcb);
+static int tul_xfer_data_in(HCS * pCurHcb);
+static int tul_xfer_data_out(HCS * pCurHcb);
+static int tul_xpad_in(HCS * pCurHcb);
+static int tul_xpad_out(HCS * pCurHcb);
+static int tul_status_msg(HCS * pCurHcb);
+
+static int tul_msgin(HCS * pCurHcb);
+static int tul_msgin_sync(HCS * pCurHcb);
+static int tul_msgin_accept(HCS * pCurHcb);
+static int tul_msgout_reject(HCS * pCurHcb);
+static int tul_msgin_extend(HCS * pCurHcb);
+
+static int tul_msgout_ide(HCS * pCurHcb);
+static int tul_msgout_abort_targ(HCS * pCurHcb);
+static int tul_msgout_abort_tag(HCS * pCurHcb);
+
+static int tul_bus_device_reset(HCS * pCurHcb);
+static void tul_select_atn(HCS * pCurHcb, SCB * pCurScb);
+static void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb);
+static void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb);
+static int int_tul_busfree(HCS * pCurHcb);
+int int_tul_scsi_rst(HCS * pCurHcb);
+static int int_tul_bad_seq(HCS * pCurHcb);
+static int int_tul_resel(HCS * pCurHcb);
+static int tul_sync_done(HCS * pCurHcb);
+static int wdtr_done(HCS * pCurHcb);
+static int wait_tulip(HCS * pCurHcb);
+static int tul_wait_done_disc(HCS * pCurHcb);
+static int tul_wait_disc(HCS * pCurHcb);
+static void tulip_scsi(HCS * pCurHcb);
+static int tul_post_scsi_rst(HCS * pCurHcb);
+
+static void tul_se2_ew_en(WORD CurBase);
+static void tul_se2_ew_ds(WORD CurBase);
+static int tul_se2_rd_all(WORD CurBase);
+static void tul_se2_update_all(WORD CurBase);	/* setup default pattern */
+static void tul_read_eeprom(WORD CurBase);
+
+				/* ---- EXTERNAL VARIABLES ---- */
+HCS tul_hcs[MAX_SUPPORTED_ADAPTERS];
+				/* ---- INTERNAL VARIABLES ---- */
+static INI_ADPT_STRUCT i91u_adpt[MAX_SUPPORTED_ADAPTERS];
+
+/*NVRAM nvram, *nvramp = &nvram; */
+static NVRAM i91unvram;
+static NVRAM *i91unvramp;
+
+
+
+static UCHAR i91udftNvRam[64] =
+{
+/*----------- header -----------*/
+	0x25, 0xc9,		/* Signature    */
+	0x40,			/* Size         */
+	0x01,			/* Revision     */
+	/* -- Host Adapter Structure -- */
+	0x95,			/* ModelByte0   */
+	0x00,			/* ModelByte1   */
+	0x00,			/* ModelInfo    */
+	0x01,			/* NumOfCh      */
+	NBC1_DEFAULT,		/* BIOSConfig1  */
+	0,			/* BIOSConfig2  */
+	0,			/* HAConfig1    */
+	0,			/* HAConfig2    */
+	/* SCSI channel 0 and target Structure  */
+	7,			/* SCSIid       */
+	NCC1_DEFAULT,		/* SCSIconfig1  */
+	0,			/* SCSIconfig2  */
+	0x10,			/* NumSCSItarget */
+
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+
+	/* SCSI channel 1 and target Structure  */
+	7,			/* SCSIid       */
+	NCC1_DEFAULT,		/* SCSIconfig1  */
+	0,			/* SCSIconfig2  */
+	0x10,			/* NumSCSItarget */
+
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT, NTC_DEFAULT,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0};			/*      - CheckSum -            */
+
+
+static UCHAR tul_rate_tbl[8] =	/* fast 20      */
+{
+				/* nanosecond devide by 4 */
+	12,			/* 50ns,  20M   */
+	18,			/* 75ns,  13.3M */
+	25,			/* 100ns, 10M   */
+	31,			/* 125ns, 8M    */
+	37,			/* 150ns, 6.6M  */
+	43,			/* 175ns, 5.7M  */
+	50,			/* 200ns, 5M    */
+	62			/* 250ns, 4M    */
+};
+
+static void tul_do_pause(unsigned amount)
+{				/* Pause for amount jiffies */
+	unsigned long the_time = jiffies + amount;
+
+	while (time_before_eq(jiffies, the_time));
+}
+
+/*-- forward reference --*/
+
+/*******************************************************************
+	Use memeory refresh time        ~ 15us * 2
+********************************************************************/
+void tul_se2_wait(void)
+{
+#if 1
+	udelay(30);
+#else
+	UCHAR readByte;
+
+	readByte = TUL_RD(0, 0x61);
+	if ((readByte & 0x10) == 0x10) {
+		for (;;) {
+			readByte = TUL_RD(0, 0x61);
+			if ((readByte & 0x10) == 0x10)
+				break;
+		}
+		for (;;) {
+			readByte = TUL_RD(0, 0x61);
+			if ((readByte & 0x10) != 0x10)
+				break;
+		}
+	} else {
+		for (;;) {
+			readByte = TUL_RD(0, 0x61);
+			if ((readByte & 0x10) == 0x10)
+				break;
+		}
+		for (;;) {
+			readByte = TUL_RD(0, 0x61);
+			if ((readByte & 0x10) != 0x10)
+				break;
+		}
+	}
+#endif
+}
+
+
+/******************************************************************
+ Input: instruction for  Serial E2PROM
+
+ EX: se2_rd(0 call se2_instr() to send address and read command
+
+	 StartBit  OP_Code   Address                Data
+	 --------- --------  ------------------     -------
+	 1         1 , 0     A5,A4,A3,A2,A1,A0      D15-D0
+
+		 +-----------------------------------------------------
+		 |
+ CS -----+
+			+--+  +--+  +--+  +--+  +--+
+			^  |  ^  |  ^  |  ^  |  ^  |
+			|  |  |  |  |  |  |  |  |  |
+ CLK -------+  +--+  +--+  +--+  +--+  +--
+ (leading edge trigger)
+
+		 +--1-----1--+
+		 | SB    OP  |  OP    A5    A4
+ DI  ----+           +--0------------------
+ (address and cmd sent to nvram)
+
+	 -------------------------------------------+
+												|
+ DO                                             +---
+ (data sent from nvram)
+
+
+******************************************************************/
+void tul_se2_instr(WORD CurBase, UCHAR instr)
+{
+	int i;
+	UCHAR b;
+
+	TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);	/* cs+start bit */
+	tul_se2_wait();
+	TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK | SE2DO);	/* +CLK */
+	tul_se2_wait();
+
+	for (i = 0; i < 8; i++) {
+		if (instr & 0x80)
+			b = SE2CS | SE2DO;	/* -CLK+dataBit */
+		else
+			b = SE2CS;	/* -CLK */
+		TUL_WR(CurBase + TUL_NVRAM, b);
+		tul_se2_wait();
+		TUL_WR(CurBase + TUL_NVRAM, b | SE2CLK);	/* +CLK */
+		tul_se2_wait();
+		instr <<= 1;
+	}
+	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
+	tul_se2_wait();
+	return;
+}
+
+
+/******************************************************************
+ Function name  : tul_se2_ew_en
+ Description    : Enable erase/write state of serial EEPROM
+******************************************************************/
+void tul_se2_ew_en(WORD CurBase)
+{
+	tul_se2_instr(CurBase, 0x30);	/* EWEN */
+	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
+	tul_se2_wait();
+	return;
+}
+
+
+/************************************************************************
+ Disable erase/write state of serial EEPROM
+*************************************************************************/
+void tul_se2_ew_ds(WORD CurBase)
+{
+	tul_se2_instr(CurBase, 0);	/* EWDS */
+	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
+	tul_se2_wait();
+	return;
+}
+
+
+/******************************************************************
+	Input  :address of Serial E2PROM
+	Output :value stored in  Serial E2PROM
+*******************************************************************/
+USHORT tul_se2_rd(WORD CurBase, ULONG adr)
+{
+	UCHAR instr, readByte;
+	USHORT readWord;
+	int i;
+
+	instr = (UCHAR) (adr | 0x80);
+	tul_se2_instr(CurBase, instr);	/* READ INSTR */
+	readWord = 0;
+
+	for (i = 15; i >= 0; i--) {
+		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
+		tul_se2_wait();
+		TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
+
+		/* sample data after the following edge of clock  */
+		readByte = TUL_RD(CurBase, TUL_NVRAM);
+		readByte &= SE2DI;
+		readWord += (readByte << i);
+		tul_se2_wait();	/* 6/20/95 */
+	}
+
+	TUL_WR(CurBase + TUL_NVRAM, 0);		/* no chip select */
+	tul_se2_wait();
+	return readWord;
+}
+
+
+/******************************************************************
+ Input: new value in  Serial E2PROM, address of Serial E2PROM
+*******************************************************************/
+void tul_se2_wr(WORD CurBase, UCHAR adr, USHORT writeWord)
+{
+	UCHAR readByte;
+	UCHAR instr;
+	int i;
+
+	instr = (UCHAR) (adr | 0x40);
+	tul_se2_instr(CurBase, instr);	/* WRITE INSTR */
+	for (i = 15; i >= 0; i--) {
+		if (writeWord & 0x8000)
+			TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2DO);	/* -CLK+dataBit 1 */
+		else
+			TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK+dataBit 0 */
+		tul_se2_wait();
+		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
+		tul_se2_wait();
+		writeWord <<= 1;
+	}
+	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
+	tul_se2_wait();
+	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS  */
+	tul_se2_wait();
+
+	TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* +CS  */
+	tul_se2_wait();
+
+	for (;;) {
+		TUL_WR(CurBase + TUL_NVRAM, SE2CS | SE2CLK);	/* +CLK */
+		tul_se2_wait();
+		TUL_WR(CurBase + TUL_NVRAM, SE2CS);	/* -CLK */
+		tul_se2_wait();
+		if ((readByte = TUL_RD(CurBase, TUL_NVRAM)) & SE2DI)
+			break;	/* write complete */
+	}
+	TUL_WR(CurBase + TUL_NVRAM, 0);		/* -CS */
+	return;
+}
+
+
+/***********************************************************************
+ Read SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+int tul_se2_rd_all(WORD CurBase)
+{
+	int i;
+	ULONG chksum = 0;
+	USHORT *np;
+
+	i91unvramp = &i91unvram;
+	np = (USHORT *) i91unvramp;
+	for (i = 0; i < 32; i++) {
+		*np++ = tul_se2_rd(CurBase, i);
+	}
+
+/*--------------------Is signature "ini" ok ? ----------------*/
+	if (i91unvramp->NVM_Signature != INI_SIGNATURE)
+		return -1;
+/*---------------------- Is ckecksum ok ? ----------------------*/
+	np = (USHORT *) i91unvramp;
+	for (i = 0; i < 31; i++)
+		chksum += *np++;
+	if (i91unvramp->NVM_CheckSum != (USHORT) chksum)
+		return -1;
+	return 1;
+}
+
+
+/***********************************************************************
+ Update SCSI H/A configuration parameters from serial EEPROM
+************************************************************************/
+void tul_se2_update_all(WORD CurBase)
+{				/* setup default pattern */
+	int i;
+	ULONG chksum = 0;
+	USHORT *np, *np1;
+
+	i91unvramp = &i91unvram;
+	/* Calculate checksum first */
+	np = (USHORT *) i91udftNvRam;
+	for (i = 0; i < 31; i++)
+		chksum += *np++;
+	*np = (USHORT) chksum;
+	tul_se2_ew_en(CurBase);	/* Enable write  */
+
+	np = (USHORT *) i91udftNvRam;
+	np1 = (USHORT *) i91unvramp;
+	for (i = 0; i < 32; i++, np++, np1++) {
+		if (*np != *np1) {
+			tul_se2_wr(CurBase, i, *np);
+		}
+	}
+
+	tul_se2_ew_ds(CurBase);	/* Disable write   */
+	return;
+}
+
+/*************************************************************************
+ Function name  : read_eeprom
+**************************************************************************/
+void tul_read_eeprom(WORD CurBase)
+{
+	UCHAR gctrl;
+
+	i91unvramp = &i91unvram;
+/*------Enable EEProm programming ---*/
+	gctrl = TUL_RD(CurBase, TUL_GCTRL);
+	TUL_WR(CurBase + TUL_GCTRL, gctrl | TUL_GCTRL_EEPROM_BIT);
+	if (tul_se2_rd_all(CurBase) != 1) {
+		tul_se2_update_all(CurBase);	/* setup default pattern */
+		tul_se2_rd_all(CurBase);	/* load again  */
+	}
+/*------ Disable EEProm programming ---*/
+	gctrl = TUL_RD(CurBase, TUL_GCTRL);
+	TUL_WR(CurBase + TUL_GCTRL, gctrl & ~TUL_GCTRL_EEPROM_BIT);
+}				/* read_eeprom */
+
+int Addi91u_into_Adapter_table(WORD wBIOS, WORD wBASE, BYTE bInterrupt,
+			       BYTE bBus, BYTE bDevice)
+{
+	int i, j;
+
+	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {
+		if (i91u_adpt[i].ADPT_BIOS < wBIOS)
+			continue;
+		if (i91u_adpt[i].ADPT_BIOS == wBIOS) {
+			if (i91u_adpt[i].ADPT_BASE == wBASE) {
+				if (i91u_adpt[i].ADPT_Bus != 0xFF)
+					return 1;
+			} else if (i91u_adpt[i].ADPT_BASE < wBASE)
+					continue;
+		}
+		for (j = MAX_SUPPORTED_ADAPTERS - 1; j > i; j--) {
+			i91u_adpt[j].ADPT_BASE = i91u_adpt[j - 1].ADPT_BASE;
+			i91u_adpt[j].ADPT_INTR = i91u_adpt[j - 1].ADPT_INTR;
+			i91u_adpt[j].ADPT_BIOS = i91u_adpt[j - 1].ADPT_BIOS;
+			i91u_adpt[j].ADPT_Bus = i91u_adpt[j - 1].ADPT_Bus;
+			i91u_adpt[j].ADPT_Device = i91u_adpt[j - 1].ADPT_Device;
+		}
+		i91u_adpt[i].ADPT_BASE = wBASE;
+		i91u_adpt[i].ADPT_INTR = bInterrupt;
+		i91u_adpt[i].ADPT_BIOS = wBIOS;
+		i91u_adpt[i].ADPT_Bus = bBus;
+		i91u_adpt[i].ADPT_Device = bDevice;
+		return 0;
+	}
+	return 1;
+}
+
+void init_i91uAdapter_table(void)
+{
+	int i;
+
+	for (i = 0; i < MAX_SUPPORTED_ADAPTERS; i++) {	/* Initialize adapter structure */
+		i91u_adpt[i].ADPT_BIOS = 0xffff;
+		i91u_adpt[i].ADPT_BASE = 0xffff;
+		i91u_adpt[i].ADPT_INTR = 0xff;
+		i91u_adpt[i].ADPT_Bus = 0xff;
+		i91u_adpt[i].ADPT_Device = 0xff;
+	}
+	return;
+}
+
+void tul_stop_bm(HCS * pCurHcb)
+{
+
+	if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+		/* wait Abort DMA xfer done */
+		while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+}
+
+/***************************************************************************/
+void get_tulipPCIConfig(HCS * pCurHcb, int ch_idx)
+{
+	pCurHcb->HCS_Base = i91u_adpt[ch_idx].ADPT_BASE;	/* Supply base address  */
+	pCurHcb->HCS_BIOS = i91u_adpt[ch_idx].ADPT_BIOS;	/* Supply BIOS address  */
+	pCurHcb->HCS_Intr = i91u_adpt[ch_idx].ADPT_INTR;	/* Supply interrupt line */
+	return;
+}
+
+/***************************************************************************/
+int tul_reset_scsi(HCS * pCurHcb, int seconds)
+{
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_BUS);
+
+	while (!((pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt)) & TSS_SCSIRST_INT));
+	/* reset tulip chip */
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, 0);
+
+	/* Stall for a while, wait for target's firmware ready,make it 2 sec ! */
+	/* SONY 5200 tape drive won't work if only stall for 1 sec */
+	tul_do_pause(seconds * HZ);
+
+	TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+	return (SCSI_RESET_SUCCESS);
+}
+
+/***************************************************************************/
+int init_tulip(HCS * pCurHcb, SCB * scbp, int tul_num_scb, BYTE * pbBiosAdr, int seconds)
+{
+	int i;
+	BYTE *pwFlags;
+	BYTE *pbHeads;
+	SCB *pTmpScb, *pPrevScb = NULL;
+
+	pCurHcb->HCS_NumScbs = tul_num_scb;
+	pCurHcb->HCS_Semaph = 1;
+	spin_lock_init(&pCurHcb->HCS_SemaphLock);
+	pCurHcb->HCS_JSStatus0 = 0;
+	pCurHcb->HCS_Scb = scbp;
+	pCurHcb->HCS_NxtPend = scbp;
+	pCurHcb->HCS_NxtAvail = scbp;
+	for (i = 0, pTmpScb = scbp; i < tul_num_scb; i++, pTmpScb++) {
+		pTmpScb->SCB_TagId = i;
+		if (i != 0)
+			pPrevScb->SCB_NxtScb = pTmpScb;
+		pPrevScb = pTmpScb;
+	}
+	pPrevScb->SCB_NxtScb = NULL;
+	pCurHcb->HCS_ScbEnd = pTmpScb;
+	pCurHcb->HCS_FirstAvail = scbp;
+	pCurHcb->HCS_LastAvail = pPrevScb;
+	spin_lock_init(&pCurHcb->HCS_AvailLock);
+	pCurHcb->HCS_FirstPend = NULL;
+	pCurHcb->HCS_LastPend = NULL;
+	pCurHcb->HCS_FirstBusy = NULL;
+	pCurHcb->HCS_LastBusy = NULL;
+	pCurHcb->HCS_FirstDone = NULL;
+	pCurHcb->HCS_LastDone = NULL;
+	pCurHcb->HCS_ActScb = NULL;
+	pCurHcb->HCS_ActTcs = NULL;
+
+	tul_read_eeprom(pCurHcb->HCS_Base);
+/*---------- get H/A configuration -------------*/
+	if (i91unvramp->NVM_SCSIInfo[0].NVM_NumOfTarg == 8)
+		pCurHcb->HCS_MaxTar = 8;
+	else
+		pCurHcb->HCS_MaxTar = 16;
+
+	pCurHcb->HCS_Config = i91unvramp->NVM_SCSIInfo[0].NVM_ChConfig1;
+
+	pCurHcb->HCS_SCSI_ID = i91unvramp->NVM_SCSIInfo[0].NVM_ChSCSIID;
+	pCurHcb->HCS_IdMask = ~(1 << pCurHcb->HCS_SCSI_ID);
+
+#if CHK_PARITY
+	/* Enable parity error response */
+	TUL_WR(pCurHcb->HCS_Base + TUL_PCMD, TUL_RD(pCurHcb->HCS_Base, TUL_PCMD) | 0x40);
+#endif
+
+	/* Mask all the interrupt       */
+	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+
+	tul_stop_bm(pCurHcb);
+	/* --- Initialize the tulip --- */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_RST_CHIP);
+
+	/* program HBA's SCSI ID        */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId, pCurHcb->HCS_SCSI_ID << 4);
+
+	/* Enable Initiator Mode ,phase latch,alternate sync period mode,
+	   disable SCSI reset */
+	if (pCurHcb->HCS_Config & HCC_EN_PAR)
+		pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT | TSC_EN_SCSI_PAR);
+	else
+		pCurHcb->HCS_SConf1 = (TSC_INITDEFAULT);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_SConf1);
+
+	/* Enable HW reselect           */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, 0);
+
+	/* selection time out = 250 ms */
+	TUL_WR(pCurHcb->HCS_Base + TUL_STimeOut, 153);
+
+/*--------- Enable SCSI terminator -----*/
+	TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, (pCurHcb->HCS_Config & (HCC_ACT_TERM1 | HCC_ACT_TERM2)));
+	TUL_WR(pCurHcb->HCS_Base + TUL_GCTRL1,
+	       ((pCurHcb->HCS_Config & HCC_AUTO_TERM) >> 4) | (TUL_RD(pCurHcb->HCS_Base, TUL_GCTRL1) & 0xFE));
+
+	for (i = 0,
+	     pwFlags = & (i91unvramp->NVM_SCSIInfo[0].NVM_Targ0Config),
+	     pbHeads = pbBiosAdr + 0x180;
+	     i < pCurHcb->HCS_MaxTar;
+	     i++, pwFlags++) {
+		pCurHcb->HCS_Tcs[i].TCS_Flags = *pwFlags & ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+		if (pCurHcb->HCS_Tcs[i].TCS_Flags & TCF_EN_255)
+			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+		else
+			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+		pCurHcb->HCS_Tcs[i].TCS_JS_Period = 0;
+		pCurHcb->HCS_Tcs[i].TCS_SConfig0 = pCurHcb->HCS_SConf1;
+		pCurHcb->HCS_Tcs[i].TCS_DrvHead = *pbHeads++;
+		if (pCurHcb->HCS_Tcs[i].TCS_DrvHead == 255)
+			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = TCF_DRV_255_63;
+		else
+			pCurHcb->HCS_Tcs[i].TCS_DrvFlags = 0;
+		pCurHcb->HCS_Tcs[i].TCS_DrvSector = *pbHeads++;
+		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;
+		pCurHcb->HCS_ActTags[i] = 0;
+		pCurHcb->HCS_MaxTags[i] = 0xFF;
+	}			/* for                          */
+	printk("i91u: PCI Base=0x%04X, IRQ=%d, BIOS=0x%04X0, SCSI ID=%d\n",
+	       pCurHcb->HCS_Base, pCurHcb->HCS_Intr,
+	       pCurHcb->HCS_BIOS, pCurHcb->HCS_SCSI_ID);
+/*------------------- reset SCSI Bus ---------------------------*/
+	if (pCurHcb->HCS_Config & HCC_SCSI_RESET) {
+		printk("i91u: Reset SCSI Bus ... \n");
+		tul_reset_scsi(pCurHcb, seconds);
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCFG1, 0x17);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SIntEnable, 0xE9);
+	return (0);
+}
+
+/***************************************************************************/
+SCB *tul_alloc_scb(HCS * hcsp)
+{
+	SCB *pTmpScb;
+	ULONG flags;
+	spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+	if ((pTmpScb = hcsp->HCS_FirstAvail) != NULL) {
+#if DEBUG_QUEUE
+		printk("find scb at %08lx\n", (ULONG) pTmpScb);
+#endif
+		if ((hcsp->HCS_FirstAvail = pTmpScb->SCB_NxtScb) == NULL)
+			hcsp->HCS_LastAvail = NULL;
+		pTmpScb->SCB_NxtScb = NULL;
+		pTmpScb->SCB_Status = SCB_RENT;
+	}
+	spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+	return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_release_scb(HCS * hcsp, SCB * scbp)
+{
+	ULONG flags;
+
+#if DEBUG_QUEUE
+	printk("Release SCB %lx; ", (ULONG) scbp);
+#endif
+	spin_lock_irqsave(&(hcsp->HCS_AvailLock), flags);
+	scbp->SCB_Srb = NULL;
+	scbp->SCB_Status = 0;
+	scbp->SCB_NxtScb = NULL;
+	if (hcsp->HCS_LastAvail != NULL) {
+		hcsp->HCS_LastAvail->SCB_NxtScb = scbp;
+		hcsp->HCS_LastAvail = scbp;
+	} else {
+		hcsp->HCS_FirstAvail = scbp;
+		hcsp->HCS_LastAvail = scbp;
+	}
+	spin_unlock_irqrestore(&(hcsp->HCS_AvailLock), flags);
+}
+
+/***************************************************************************/
+void tul_append_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+	printk("Append pend SCB %lx; ", (ULONG) scbp);
+#endif
+	scbp->SCB_Status = SCB_PEND;
+	scbp->SCB_NxtScb = NULL;
+	if (pCurHcb->HCS_LastPend != NULL) {
+		pCurHcb->HCS_LastPend->SCB_NxtScb = scbp;
+		pCurHcb->HCS_LastPend = scbp;
+	} else {
+		pCurHcb->HCS_FirstPend = scbp;
+		pCurHcb->HCS_LastPend = scbp;
+	}
+}
+
+/***************************************************************************/
+void tul_push_pend_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+	printk("Push pend SCB %lx; ", (ULONG) scbp);
+#endif
+	scbp->SCB_Status = SCB_PEND;
+	if ((scbp->SCB_NxtScb = pCurHcb->HCS_FirstPend) != NULL) {
+		pCurHcb->HCS_FirstPend = scbp;
+	} else {
+		pCurHcb->HCS_FirstPend = scbp;
+		pCurHcb->HCS_LastPend = scbp;
+	}
+}
+
+/***************************************************************************/
+SCB *tul_find_first_pend_scb(HCS * pCurHcb)
+{
+	SCB *pFirstPend;
+
+
+	pFirstPend = pCurHcb->HCS_FirstPend;
+	while (pFirstPend != NULL) {
+		if (pFirstPend->SCB_Opcode != ExecSCSI) {
+			return (pFirstPend);
+		}
+		if (pFirstPend->SCB_TagMsg == 0) {
+			if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] == 0) &&
+			    !(pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+				return (pFirstPend);
+			}
+		} else {
+			if ((pCurHcb->HCS_ActTags[pFirstPend->SCB_Target] >=
+			  pCurHcb->HCS_MaxTags[pFirstPend->SCB_Target]) |
+			    (pCurHcb->HCS_Tcs[pFirstPend->SCB_Target].TCS_Flags & TCF_BUSY)) {
+				pFirstPend = pFirstPend->SCB_NxtScb;
+				continue;
+			}
+			return (pFirstPend);
+		}
+		pFirstPend = pFirstPend->SCB_NxtScb;
+	}
+
+
+	return (pFirstPend);
+}
+/***************************************************************************/
+SCB *tul_pop_pend_scb(HCS * pCurHcb)
+{
+	SCB *pTmpScb;
+
+	if ((pTmpScb = pCurHcb->HCS_FirstPend) != NULL) {
+		if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+			pCurHcb->HCS_LastPend = NULL;
+		pTmpScb->SCB_NxtScb = NULL;
+	}
+#if DEBUG_QUEUE
+	printk("Pop pend SCB %lx; ", (ULONG) pTmpScb);
+#endif
+	return (pTmpScb);
+}
+
+
+/***************************************************************************/
+void tul_unlink_pend_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+	SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+	printk("unlink pend SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;
+	while (pTmpScb != NULL) {
+		if (pCurScb == pTmpScb) {	/* Unlink this SCB              */
+			if (pTmpScb == pCurHcb->HCS_FirstPend) {
+				if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+					pCurHcb->HCS_LastPend = NULL;
+			} else {
+				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+				if (pTmpScb == pCurHcb->HCS_LastPend)
+					pCurHcb->HCS_LastPend = pPrevScb;
+			}
+			pTmpScb->SCB_NxtScb = NULL;
+			break;
+		}
+		pPrevScb = pTmpScb;
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+	return;
+}
+/***************************************************************************/
+void tul_append_busy_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+	printk("append busy SCB %lx; ", (ULONG) scbp);
+#endif
+	if (scbp->SCB_TagMsg)
+		pCurHcb->HCS_ActTags[scbp->SCB_Target]++;
+	else
+		pCurHcb->HCS_Tcs[scbp->SCB_Target].TCS_Flags |= TCF_BUSY;
+	scbp->SCB_Status = SCB_BUSY;
+	scbp->SCB_NxtScb = NULL;
+	if (pCurHcb->HCS_LastBusy != NULL) {
+		pCurHcb->HCS_LastBusy->SCB_NxtScb = scbp;
+		pCurHcb->HCS_LastBusy = scbp;
+	} else {
+		pCurHcb->HCS_FirstBusy = scbp;
+		pCurHcb->HCS_LastBusy = scbp;
+	}
+}
+
+/***************************************************************************/
+SCB *tul_pop_busy_scb(HCS * pCurHcb)
+{
+	SCB *pTmpScb;
+
+
+	if ((pTmpScb = pCurHcb->HCS_FirstBusy) != NULL) {
+		if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+			pCurHcb->HCS_LastBusy = NULL;
+		pTmpScb->SCB_NxtScb = NULL;
+		if (pTmpScb->SCB_TagMsg)
+			pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+		else
+			pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+	}
+#if DEBUG_QUEUE
+	printk("Pop busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+	return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_unlink_busy_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+	SCB *pTmpScb, *pPrevScb;
+
+#if DEBUG_QUEUE
+	printk("unlink busy SCB %lx; ", (ULONG) pCurScb);
+#endif
+
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+	while (pTmpScb != NULL) {
+		if (pCurScb == pTmpScb) {	/* Unlink this SCB              */
+			if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+				if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+					pCurHcb->HCS_LastBusy = NULL;
+			} else {
+				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+				if (pTmpScb == pCurHcb->HCS_LastBusy)
+					pCurHcb->HCS_LastBusy = pPrevScb;
+			}
+			pTmpScb->SCB_NxtScb = NULL;
+			if (pTmpScb->SCB_TagMsg)
+				pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+			else
+				pCurHcb->HCS_Tcs[pTmpScb->SCB_Target].TCS_Flags &= ~TCF_BUSY;
+			break;
+		}
+		pPrevScb = pTmpScb;
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+	return;
+}
+
+/***************************************************************************/
+SCB *tul_find_busy_scb(HCS * pCurHcb, WORD tarlun)
+{
+	SCB *pTmpScb, *pPrevScb;
+	WORD scbp_tarlun;
+
+
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;
+	while (pTmpScb != NULL) {
+		scbp_tarlun = (pTmpScb->SCB_Lun << 8) | (pTmpScb->SCB_Target);
+		if (scbp_tarlun == tarlun) {	/* Unlink this SCB              */
+			break;
+		}
+		pPrevScb = pTmpScb;
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+#if DEBUG_QUEUE
+	printk("find busy SCB %lx; ", (ULONG) pTmpScb);
+#endif
+	return (pTmpScb);
+}
+
+/***************************************************************************/
+void tul_append_done_scb(HCS * pCurHcb, SCB * scbp)
+{
+
+#if DEBUG_QUEUE
+	printk("append done SCB %lx; ", (ULONG) scbp);
+#endif
+
+	scbp->SCB_Status = SCB_DONE;
+	scbp->SCB_NxtScb = NULL;
+	if (pCurHcb->HCS_LastDone != NULL) {
+		pCurHcb->HCS_LastDone->SCB_NxtScb = scbp;
+		pCurHcb->HCS_LastDone = scbp;
+	} else {
+		pCurHcb->HCS_FirstDone = scbp;
+		pCurHcb->HCS_LastDone = scbp;
+	}
+}
+
+/***************************************************************************/
+SCB *tul_find_done_scb(HCS * pCurHcb)
+{
+	SCB *pTmpScb;
+
+
+	if ((pTmpScb = pCurHcb->HCS_FirstDone) != NULL) {
+		if ((pCurHcb->HCS_FirstDone = pTmpScb->SCB_NxtScb) == NULL)
+			pCurHcb->HCS_LastDone = NULL;
+		pTmpScb->SCB_NxtScb = NULL;
+	}
+#if DEBUG_QUEUE
+	printk("find done SCB %lx; ", (ULONG) pTmpScb);
+#endif
+	return (pTmpScb);
+}
+
+/***************************************************************************/
+int tul_abort_srb(HCS * pCurHcb, struct scsi_cmnd *srbp)
+{
+	ULONG flags;
+	SCB *pTmpScb, *pPrevScb;
+
+	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+	if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+		/* disable Jasmin SCSI Int        */
+
+                spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+		tulip_main(pCurHcb);
+
+        	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+		pCurHcb->HCS_Semaph = 1;
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+		return SCSI_ABORT_SNOOZE;
+	}
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstPend;	/* Check Pend queue */
+	while (pTmpScb != NULL) {
+		/* 07/27/98 */
+		if (pTmpScb->SCB_Srb == srbp) {
+			if (pTmpScb == pCurHcb->HCS_ActScb) {
+				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+				return SCSI_ABORT_BUSY;
+			} else if (pTmpScb == pCurHcb->HCS_FirstPend) {
+				if ((pCurHcb->HCS_FirstPend = pTmpScb->SCB_NxtScb) == NULL)
+					pCurHcb->HCS_LastPend = NULL;
+			} else {
+				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+				if (pTmpScb == pCurHcb->HCS_LastPend)
+					pCurHcb->HCS_LastPend = pPrevScb;
+			}
+			pTmpScb->SCB_HaStat = HOST_ABORTED;
+			pTmpScb->SCB_Flags |= SCF_DONE;
+			if (pTmpScb->SCB_Flags & SCF_POST)
+				(*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+			return SCSI_ABORT_SUCCESS;
+		}
+		pPrevScb = pTmpScb;
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
+	while (pTmpScb != NULL) {
+
+		if (pTmpScb->SCB_Srb == srbp) {
+
+			if (pTmpScb == pCurHcb->HCS_ActScb) {
+				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+				return SCSI_ABORT_BUSY;
+			} else if (pTmpScb->SCB_TagMsg == 0) {
+				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+				return SCSI_ABORT_BUSY;
+			} else {
+				pCurHcb->HCS_ActTags[pTmpScb->SCB_Target]--;
+				if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+					if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+						pCurHcb->HCS_LastBusy = NULL;
+				} else {
+					pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+					if (pTmpScb == pCurHcb->HCS_LastBusy)
+						pCurHcb->HCS_LastBusy = pPrevScb;
+				}
+				pTmpScb->SCB_NxtScb = NULL;
+
+
+				pTmpScb->SCB_HaStat = HOST_ABORTED;
+				pTmpScb->SCB_Flags |= SCF_DONE;
+				if (pTmpScb->SCB_Flags & SCF_POST)
+					(*pTmpScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pTmpScb);
+				spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+				return SCSI_ABORT_SUCCESS;
+			}
+		}
+		pPrevScb = pTmpScb;
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+	return (SCSI_ABORT_NOT_RUNNING);
+}
+
+/***************************************************************************/
+int tul_bad_seq(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+
+	printk("tul_bad_seg c=%d\n", pCurHcb->HCS_Index);
+
+	if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+		tul_unlink_busy_scb(pCurHcb, pCurScb);
+		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+		pCurScb->SCB_TaStat = 0;
+		tul_append_done_scb(pCurHcb, pCurScb);
+	}
+	tul_stop_bm(pCurHcb);
+
+	tul_reset_scsi(pCurHcb, 8);	/* 7/29/98 */
+
+	return (tul_post_scsi_rst(pCurHcb));
+}
+
+/************************************************************************/
+int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
+		unsigned int target, unsigned int ResetFlags)
+{
+	ULONG flags;
+	SCB *pScb;
+	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+	if (ResetFlags & SCSI_RESET_ASYNCHRONOUS) {
+
+		if ((pCurHcb->HCS_Semaph == 0) && (pCurHcb->HCS_ActScb == NULL)) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+			/* disable Jasmin SCSI Int        */
+
+        		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+			tulip_main(pCurHcb);
+
+        		spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+			pCurHcb->HCS_Semaph = 1;
+			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+
+			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+			return SCSI_RESET_SNOOZE;
+		}
+		pScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
+		while (pScb != NULL) {
+			if (pScb->SCB_Srb == pSrb)
+				break;
+			pScb = pScb->SCB_NxtScb;
+		}
+		if (pScb == NULL) {
+			printk("Unable to Reset - No SCB Found\n");
+
+			spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+			return SCSI_RESET_NOT_RUNNING;
+		}
+	}
+	if ((pScb = tul_alloc_scb(pCurHcb)) == NULL) {
+		spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+		return SCSI_RESET_NOT_RUNNING;
+	}
+	pScb->SCB_Opcode = BusDevRst;
+	pScb->SCB_Flags = SCF_POST;
+	pScb->SCB_Target = target;
+	pScb->SCB_Mode = 0;
+
+	pScb->SCB_Srb = NULL;
+	if (ResetFlags & SCSI_RESET_SYNCHRONOUS) {
+		pScb->SCB_Srb = pSrb;
+	}
+	tul_push_pend_scb(pCurHcb, pScb);	/* push this SCB to Pending queue */
+
+	if (pCurHcb->HCS_Semaph == 1) {
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+		/* disable Jasmin SCSI Int        */
+		pCurHcb->HCS_Semaph = 0;
+
+        	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+		tulip_main(pCurHcb);
+
+                spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+		pCurHcb->HCS_Semaph = 1;
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+	}
+	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+	return SCSI_RESET_PENDING;
+}
+
+int tul_reset_scsi_bus(HCS * pCurHcb)
+{
+	ULONG flags;
+
+	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+	pCurHcb->HCS_Semaph = 0;
+
+	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+	tul_stop_bm(pCurHcb);
+
+	tul_reset_scsi(pCurHcb, 2);	/* 7/29/98 */
+
+	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+	tul_post_scsi_rst(pCurHcb);
+
+        spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+	tulip_main(pCurHcb);
+
+        spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+	pCurHcb->HCS_Semaph = 1;
+	TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+	return (SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET);
+}
+
+/************************************************************************/
+void tul_exec_scb(HCS * pCurHcb, SCB * pCurScb)
+{
+	ULONG flags;
+
+	pCurScb->SCB_Mode = 0;
+
+	pCurScb->SCB_SGIdx = 0;
+	pCurScb->SCB_SGMax = pCurScb->SCB_SGLen;
+
+	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+	tul_append_pend_scb(pCurHcb, pCurScb);	/* Append this SCB to Pending queue */
+
+/* VVVVV 07/21/98 */
+	if (pCurHcb->HCS_Semaph == 1) {
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+		/* disable Jasmin SCSI Int        */
+		pCurHcb->HCS_Semaph = 0;
+
+        	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+
+		tulip_main(pCurHcb);
+
+        	spin_lock_irqsave(&(pCurHcb->HCS_SemaphLock), flags);
+
+		pCurHcb->HCS_Semaph = 1;
+		TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+	}
+	spin_unlock_irqrestore(&(pCurHcb->HCS_SemaphLock), flags);
+	return;
+}
+
+/***************************************************************************/
+int tul_isr(HCS * pCurHcb)
+{
+	/* Enter critical section       */
+
+	if (TUL_RD(pCurHcb->HCS_Base, TUL_Int) & TSS_INT_PENDING) {
+		if (pCurHcb->HCS_Semaph == 1) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x1F);
+			/* Disable Tulip SCSI Int */
+			pCurHcb->HCS_Semaph = 0;
+
+			tulip_main(pCurHcb);
+
+			pCurHcb->HCS_Semaph = 1;
+			TUL_WR(pCurHcb->HCS_Base + TUL_Mask, 0x0F);
+			return (1);
+		}
+	}
+	return (0);
+}
+
+/***************************************************************************/
+int tulip_main(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+
+	for (;;) {
+
+		tulip_scsi(pCurHcb);	/* Call tulip_scsi              */
+
+		while ((pCurScb = tul_find_done_scb(pCurHcb)) != NULL) {	/* find done entry */
+			if (pCurScb->SCB_TaStat == INI_QUEUE_FULL) {
+				pCurHcb->HCS_MaxTags[pCurScb->SCB_Target] =
+				    pCurHcb->HCS_ActTags[pCurScb->SCB_Target] - 1;
+				pCurScb->SCB_TaStat = 0;
+				tul_append_pend_scb(pCurHcb, pCurScb);
+				continue;
+			}
+			if (!(pCurScb->SCB_Mode & SCM_RSENS)) {		/* not in auto req. sense mode */
+				if (pCurScb->SCB_TaStat == 2) {
+
+					/* clr sync. nego flag */
+
+					if (pCurScb->SCB_Flags & SCF_SENSE) {
+						BYTE len;
+						len = pCurScb->SCB_SenseLen;
+						if (len == 0)
+							len = 1;
+						pCurScb->SCB_BufLen = pCurScb->SCB_SenseLen;
+						pCurScb->SCB_BufPtr = pCurScb->SCB_SensePtr;
+						pCurScb->SCB_Flags &= ~(SCF_SG | SCF_DIR);	/* for xfer_data_in */
+/*                      pCurScb->SCB_Flags |= SCF_NO_DCHK;      */
+						/* so, we won't report worng direction in xfer_data_in,
+						   and won't report HOST_DO_DU in state_6 */
+						pCurScb->SCB_Mode = SCM_RSENS;
+						pCurScb->SCB_Ident &= 0xBF;	/* Disable Disconnect */
+						pCurScb->SCB_TagMsg = 0;
+						pCurScb->SCB_TaStat = 0;
+						pCurScb->SCB_CDBLen = 6;
+						pCurScb->SCB_CDB[0] = SCSICMD_RequestSense;
+						pCurScb->SCB_CDB[1] = 0;
+						pCurScb->SCB_CDB[2] = 0;
+						pCurScb->SCB_CDB[3] = 0;
+						pCurScb->SCB_CDB[4] = len;
+						pCurScb->SCB_CDB[5] = 0;
+						tul_push_pend_scb(pCurHcb, pCurScb);
+						break;
+					}
+				}
+			} else {	/* in request sense mode */
+
+				if (pCurScb->SCB_TaStat == 2) {		/* check contition status again after sending
+									   requset sense cmd 0x3 */
+					pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+				}
+				pCurScb->SCB_TaStat = 2;
+			}
+			pCurScb->SCB_Flags |= SCF_DONE;
+			if (pCurScb->SCB_Flags & SCF_POST) {
+				(*pCurScb->SCB_Post) ((BYTE *) pCurHcb, (BYTE *) pCurScb);
+			}
+		}		/* while */
+
+		/* find_active: */
+		if (TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0) & TSS_INT_PENDING)
+			continue;
+
+		if (pCurHcb->HCS_ActScb) {	/* return to OS and wait for xfer_done_ISR/Selected_ISR */
+			return 1;	/* return to OS, enable interrupt */
+		}
+		/* Check pending SCB            */
+		if (tul_find_first_pend_scb(pCurHcb) == NULL) {
+			return 1;	/* return to OS, enable interrupt */
+		}
+	}			/* End of for loop */
+	/* statement won't reach here */
+}
+
+
+
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+/***************************************************************************/
+
+/***************************************************************************/
+void tulip_scsi(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+	TCS *pCurTcb;
+
+	/* make sure to service interrupt asap */
+
+	if ((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0)) & TSS_INT_PENDING) {
+
+		pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+		pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+		pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+		if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* SCSI bus reset detected      */
+			int_tul_scsi_rst(pCurHcb);
+			return;
+		}
+		if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {	/* if selected/reselected interrupt */
+			if (int_tul_resel(pCurHcb) == 0)
+				tul_next_state(pCurHcb);
+			return;
+		}
+		if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {
+			int_tul_busfree(pCurHcb);
+			return;
+		}
+		if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
+			int_tul_busfree(pCurHcb);	/* unexpected bus free or sel timeout */
+			return;
+		}
+		if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {	/* func complete or Bus service */
+			if ((pCurScb = pCurHcb->HCS_ActScb) != NULL)
+				tul_next_state(pCurHcb);
+			return;
+		}
+	}
+	if (pCurHcb->HCS_ActScb != NULL)
+		return;
+
+	if ((pCurScb = tul_find_first_pend_scb(pCurHcb)) == NULL)
+		return;
+
+	/* program HBA's SCSI ID & target SCSI ID */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SScsiId,
+	     (pCurHcb->HCS_SCSI_ID << 4) | (pCurScb->SCB_Target & 0x0F));
+	if (pCurScb->SCB_Opcode == ExecSCSI) {
+		pCurTcb = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+
+		if (pCurScb->SCB_TagMsg)
+			pCurTcb->TCS_DrvFlags |= TCF_DRV_EN_TAG;
+		else
+			pCurTcb->TCS_DrvFlags &= ~TCF_DRV_EN_TAG;
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {	/* do wdtr negotiation          */
+			tul_select_atn_stop(pCurHcb, pCurScb);
+		} else {
+			if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync negotiation          */
+				tul_select_atn_stop(pCurHcb, pCurScb);
+			} else {
+				if (pCurScb->SCB_TagMsg)
+					tul_select_atn3(pCurHcb, pCurScb);
+				else
+					tul_select_atn(pCurHcb, pCurScb);
+			}
+		}
+		if (pCurScb->SCB_Flags & SCF_POLL) {
+			while (wait_tulip(pCurHcb) != -1) {
+				if (tul_next_state(pCurHcb) == -1)
+					break;
+			}
+		}
+	} else if (pCurScb->SCB_Opcode == BusDevRst) {
+		tul_select_atn_stop(pCurHcb, pCurScb);
+		pCurScb->SCB_NxtStat = 8;
+		if (pCurScb->SCB_Flags & SCF_POLL) {
+			while (wait_tulip(pCurHcb) != -1) {
+				if (tul_next_state(pCurHcb) == -1)
+					break;
+			}
+		}
+	} else if (pCurScb->SCB_Opcode == AbortCmd) {
+		if (tul_abort_srb(pCurHcb, pCurScb->SCB_Srb) != 0) {
+
+
+			tul_unlink_pend_scb(pCurHcb, pCurScb);
+
+			tul_release_scb(pCurHcb, pCurScb);
+		} else {
+			pCurScb->SCB_Opcode = BusDevRst;
+			tul_select_atn_stop(pCurHcb, pCurScb);
+			pCurScb->SCB_NxtStat = 8;
+		}
+
+/* 08/03/98 */
+	} else {
+		tul_unlink_pend_scb(pCurHcb, pCurScb);
+		pCurScb->SCB_HaStat = 0x16;	/* bad command */
+		tul_append_done_scb(pCurHcb, pCurScb);
+	}
+	return;
+}
+
+
+/***************************************************************************/
+int tul_next_state(HCS * pCurHcb)
+{
+	int next;
+
+	next = pCurHcb->HCS_ActScb->SCB_NxtStat;
+	for (;;) {
+		switch (next) {
+		case 1:
+			next = tul_state_1(pCurHcb);
+			break;
+		case 2:
+			next = tul_state_2(pCurHcb);
+			break;
+		case 3:
+			next = tul_state_3(pCurHcb);
+			break;
+		case 4:
+			next = tul_state_4(pCurHcb);
+			break;
+		case 5:
+			next = tul_state_5(pCurHcb);
+			break;
+		case 6:
+			next = tul_state_6(pCurHcb);
+			break;
+		case 7:
+			next = tul_state_7(pCurHcb);
+			break;
+		case 8:
+			return (tul_bus_device_reset(pCurHcb));
+		default:
+			return (tul_bad_seq(pCurHcb));
+		}
+		if (next <= 0)
+			return next;
+	}
+}
+
+
+/***************************************************************************/
+/* sTate after selection with attention & stop */
+int tul_state_1(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+	printk("-s1-");
+#endif
+
+	tul_unlink_pend_scb(pCurHcb, pCurScb);
+	tul_append_busy_scb(pCurHcb, pCurScb);
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+	/* ATN on */
+	if (pCurHcb->HCS_Phase == MSG_OUT) {
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, (TSC_EN_BUS_IN | TSC_HW_RESELECT));
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+
+		if (pCurScb->SCB_TagMsg) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+		}
+		if ((pCurTcb->TCS_Flags & (TCF_WDTR_DONE | TCF_NO_WDTR)) == 0) {
+
+			pCurTcb->TCS_Flags |= TCF_WDTR_DONE;
+
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);	/* Extended msg length */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* Sync request */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* Start from 16 bits */
+		} else if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {
+
+			pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* extended msg length */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */
+		}
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+		if (wait_tulip(pCurHcb) == -1)
+			return (-1);
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+	return (3);
+}
+
+
+/***************************************************************************/
+/* state after selection with attention */
+/* state after selection with attention3 */
+int tul_state_2(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+#if DEBUG_STATE
+	printk("-s2-");
+#endif
+
+	tul_unlink_pend_scb(pCurHcb, pCurScb);
+	tul_append_busy_scb(pCurHcb, pCurScb);
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+
+	if (pCurHcb->HCS_JSStatus1 & TSS_CMD_PH_CMP) {
+		return (4);
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+	return (3);
+}
+
+/***************************************************************************/
+/* state before CDB xfer is done */
+int tul_state_3(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+	int i;
+
+#if DEBUG_STATE
+	printk("-s3-");
+#endif
+	for (;;) {
+		switch (pCurHcb->HCS_Phase) {
+		case CMD_OUT:	/* Command out phase            */
+			for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+			if (wait_tulip(pCurHcb) == -1)
+				return (-1);
+			if (pCurHcb->HCS_Phase == CMD_OUT) {
+				return (tul_bad_seq(pCurHcb));
+			}
+			return (4);
+
+		case MSG_IN:	/* Message in phase             */
+			pCurScb->SCB_NxtStat = 3;
+			if (tul_msgin(pCurHcb) == -1)
+				return (-1);
+			break;
+
+		case STATUS_IN:	/* Status phase                 */
+			if (tul_status_msg(pCurHcb) == -1)
+				return (-1);
+			break;
+
+		case MSG_OUT:	/* Message out phase            */
+			if (pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) {
+
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+				if (wait_tulip(pCurHcb) == -1)
+					return (-1);
+
+			} else {
+				pCurTcb->TCS_Flags |= TCF_SYNC_DONE;
+
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);	/* ext. msg len */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);	/* sync request */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, tul_rate_tbl[pCurTcb->TCS_Flags & TCF_SCSI_RATE]);
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MAX_OFFSET);	/* REQ/ACK offset */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+				if (wait_tulip(pCurHcb) == -1)
+					return (-1);
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+				TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7));
+
+			}
+			break;
+
+		default:
+			return (tul_bad_seq(pCurHcb));
+		}
+	}
+}
+
+
+/***************************************************************************/
+int tul_state_4(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+	printk("-s4-");
+#endif
+	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_NO_XF) {
+		return (6);	/* Go to state 6                */
+	}
+	for (;;) {
+		if (pCurScb->SCB_BufLen == 0)
+			return (6);	/* Go to state 6                */
+
+		switch (pCurHcb->HCS_Phase) {
+
+		case STATUS_IN:	/* Status phase                 */
+			if ((pCurScb->SCB_Flags & SCF_DIR) != 0) {	/* if direction bit set then report data underrun */
+				pCurScb->SCB_HaStat = HOST_DO_DU;
+			}
+			if ((tul_status_msg(pCurHcb)) == -1)
+				return (-1);
+			break;
+
+		case MSG_IN:	/* Message in phase             */
+			pCurScb->SCB_NxtStat = 0x4;
+			if (tul_msgin(pCurHcb) == -1)
+				return (-1);
+			break;
+
+		case MSG_OUT:	/* Message out phase            */
+			if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+				pCurScb->SCB_BufLen = 0;
+				pCurScb->SCB_HaStat = HOST_DO_DU;
+				if (tul_msgout_ide(pCurHcb) == -1)
+					return (-1);
+				return (6);	/* Go to state 6                */
+			} else {
+				TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+				if (wait_tulip(pCurHcb) == -1)
+					return (-1);
+			}
+			break;
+
+		case DATA_IN:	/* Data in phase                */
+			return (tul_xfer_data_in(pCurHcb));
+
+		case DATA_OUT:	/* Data out phase               */
+			return (tul_xfer_data_out(pCurHcb));
+
+		default:
+			return (tul_bad_seq(pCurHcb));
+		}
+	}
+}
+
+
+/***************************************************************************/
+/* state after dma xfer done or phase change before xfer done */
+int tul_state_5(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	long cnt, xcnt;		/* cannot use unsigned !! code: if (xcnt < 0) */
+
+#if DEBUG_STATE
+	printk("-s5-");
+#endif
+/*------ get remaining count -------*/
+
+	cnt = TUL_RDLONG(pCurHcb->HCS_Base, TUL_SCnt0) & 0x0FFFFFF;
+
+	if (TUL_RD(pCurHcb->HCS_Base, TUL_XCmd) & 0x20) {
+		/* ----------------------- DATA_IN ----------------------------- */
+		/* check scsi parity error */
+		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+			pCurScb->SCB_HaStat = HOST_DO_DU;
+		}
+		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* DMA xfer pending, Send STOP  */
+			/* tell Hardware  scsi xfer has been terminated */
+			TUL_WR(pCurHcb->HCS_Base + TUL_XCtrl, TUL_RD(pCurHcb->HCS_Base, TUL_XCtrl) | 0x80);
+			/* wait until DMA xfer not pending */
+			while (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND);
+		}
+	} else {
+/*-------- DATA OUT -----------*/
+		if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0) {
+			if (pCurHcb->HCS_ActTcs->TCS_JS_Period & TSC_WIDE_SCSI)
+				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F) << 1;
+			else
+				cnt += (TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F);
+		}
+		if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & XPEND) {	/* if DMA xfer is pending, abort DMA xfer */
+			TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT);
+			/* wait Abort DMA xfer done */
+			while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & XABT) == 0);
+		}
+		if ((cnt == 1) && (pCurHcb->HCS_Phase == DATA_OUT)) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+			if (wait_tulip(pCurHcb) == -1) {
+				return (-1);
+			}
+			cnt = 0;
+		} else {
+			if ((TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1) & TSS_XFER_CMP) == 0)
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+		}
+	}
+
+	if (cnt == 0) {
+		pCurScb->SCB_BufLen = 0;
+		return (6);	/* Go to state 6                */
+	}
+	/* Update active data pointer */
+	xcnt = (long) pCurScb->SCB_BufLen - cnt;	/* xcnt== bytes already xferred */
+	pCurScb->SCB_BufLen = (U32) cnt;	/* cnt == bytes left to be xferred */
+	if (pCurScb->SCB_Flags & SCF_SG) {
+		register SG *sgp;
+		ULONG i;
+
+		sgp = &pCurScb->SCB_SGList[pCurScb->SCB_SGIdx];
+		for (i = pCurScb->SCB_SGIdx; i < pCurScb->SCB_SGMax; sgp++, i++) {
+			xcnt -= (long) sgp->SG_Len;
+			if (xcnt < 0) {		/* this sgp xfer half done */
+				xcnt += (long) sgp->SG_Len;	/* xcnt == bytes xferred in this sgp */
+				sgp->SG_Ptr += (U32) xcnt;	/* new ptr to be xfer */
+				sgp->SG_Len -= (U32) xcnt;	/* new len to be xfer */
+				pCurScb->SCB_BufPtr += ((U32) (i - pCurScb->SCB_SGIdx) << 3);
+				/* new SG table ptr */
+				pCurScb->SCB_SGLen = (BYTE) (pCurScb->SCB_SGMax - i);
+				/* new SG table len */
+				pCurScb->SCB_SGIdx = (WORD) i;
+				/* for next disc and come in this loop */
+				return (4);	/* Go to state 4                */
+			}
+			/* else (xcnt >= 0 , i.e. this sgp already xferred */
+		}		/* for */
+		return (6);	/* Go to state 6                */
+	} else {
+		pCurScb->SCB_BufPtr += (U32) xcnt;
+	}
+	return (4);		/* Go to state 4                */
+}
+
+/***************************************************************************/
+/* state after Data phase */
+int tul_state_6(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+#if DEBUG_STATE
+	printk("-s6-");
+#endif
+	for (;;) {
+		switch (pCurHcb->HCS_Phase) {
+		case STATUS_IN:	/* Status phase                 */
+			if ((tul_status_msg(pCurHcb)) == -1)
+				return (-1);
+			break;
+
+		case MSG_IN:	/* Message in phase             */
+			pCurScb->SCB_NxtStat = 6;
+			if ((tul_msgin(pCurHcb)) == -1)
+				return (-1);
+			break;
+
+		case MSG_OUT:	/* Message out phase            */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);		/* msg nop */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+			if (wait_tulip(pCurHcb) == -1)
+				return (-1);
+			break;
+
+		case DATA_IN:	/* Data in phase                */
+			return (tul_xpad_in(pCurHcb));
+
+		case DATA_OUT:	/* Data out phase               */
+			return (tul_xpad_out(pCurHcb));
+
+		default:
+			return (tul_bad_seq(pCurHcb));
+		}
+	}
+}
+
+/***************************************************************************/
+int tul_state_7(HCS * pCurHcb)
+{
+	int cnt, i;
+
+#if DEBUG_STATE
+	printk("-s7-");
+#endif
+	/* flush SCSI FIFO */
+	cnt = TUL_RD(pCurHcb->HCS_Base, TUL_SFifoCnt) & 0x1F;
+	if (cnt) {
+		for (i = 0; i < cnt; i++)
+			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+	}
+	switch (pCurHcb->HCS_Phase) {
+	case DATA_IN:		/* Data in phase                */
+	case DATA_OUT:		/* Data out phase               */
+		return (tul_bad_seq(pCurHcb));
+	default:
+		return (6);	/* Go to state 6                */
+	}
+}
+
+/***************************************************************************/
+int tul_xfer_data_in(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DOUT) {
+		return (6);	/* wrong direction */
+	}
+	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_IN);	/* 7/25/95 */
+
+	if (pCurScb->SCB_Flags & SCF_SG) {	/* S/G xfer */
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_IN);
+	} else {
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_IN);
+	}
+	pCurScb->SCB_NxtStat = 0x5;
+	return (0);		/* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xfer_data_out(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+	if ((pCurScb->SCB_Flags & SCF_DIR) == SCF_DIN) {
+		return (6);	/* wrong direction */
+	}
+	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, pCurScb->SCB_BufLen);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_DMA_OUT);
+
+	if (pCurScb->SCB_Flags & SCF_SG) {	/* S/G xfer */
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, ((ULONG) pCurScb->SCB_SGLen) << 3);
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_SG_OUT);
+	} else {
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XCntH, pCurScb->SCB_BufLen);
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_XAddH, pCurScb->SCB_BufPtr);
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_OUT);
+	}
+
+	pCurScb->SCB_NxtStat = 0x5;
+	return (0);		/* return to OS, wait xfer done , let jas_isr come in */
+}
+
+
+/***************************************************************************/
+int tul_xpad_in(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+	if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+		pCurScb->SCB_HaStat = HOST_DO_DU;	/* over run             */
+	}
+	for (;;) {
+		if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+		else
+			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+		if ((wait_tulip(pCurHcb)) == -1) {
+			return (-1);
+		}
+		if (pCurHcb->HCS_Phase != DATA_IN) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+			return (6);
+		}
+		TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+	}
+}
+
+int tul_xpad_out(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+
+	if ((pCurScb->SCB_Flags & SCF_DIR) != SCF_NO_DCHK) {
+		pCurScb->SCB_HaStat = HOST_DO_DU;	/* over run             */
+	}
+	for (;;) {
+		if (pCurTcb->TCS_JS_Period & TSC_WIDE_SCSI)
+			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 2);
+		else
+			TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+		if ((wait_tulip(pCurHcb)) == -1) {
+			return (-1);
+		}
+		if (pCurHcb->HCS_Phase != DATA_OUT) {	/* Disable wide CPU to allow read 16 bits */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+			return (6);
+		}
+	}
+}
+
+
+/***************************************************************************/
+int tul_status_msg(HCS * pCurHcb)
+{				/* status & MSG_IN */
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	BYTE msg;
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_CMD_COMP);
+	if ((wait_tulip(pCurHcb)) == -1) {
+		return (-1);
+	}
+	/* get status */
+	pCurScb->SCB_TaStat = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+
+	if (pCurHcb->HCS_Phase == MSG_OUT) {
+		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+		} else {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_NOP);
+		}
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+		return (wait_tulip(pCurHcb));
+	}
+	if (pCurHcb->HCS_Phase == MSG_IN) {
+		msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+		if (pCurHcb->HCS_JSStatus0 & TSS_PAR_ERROR) {	/* Parity error                 */
+			if ((tul_msgin_accept(pCurHcb)) == -1)
+				return (-1);
+			if (pCurHcb->HCS_Phase != MSG_OUT)
+				return (tul_bad_seq(pCurHcb));
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_PARITY);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+			return (wait_tulip(pCurHcb));
+		}
+		if (msg == 0) {	/* Command complete             */
+
+			if ((pCurScb->SCB_TaStat & 0x18) == 0x10) {	/* No link support              */
+				return (tul_bad_seq(pCurHcb));
+			}
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+			return tul_wait_done_disc(pCurHcb);
+
+		}
+		if ((msg == MSG_LINK_COMP) || (msg == MSG_LINK_FLAG)) {
+			if ((pCurScb->SCB_TaStat & 0x18) == 0x10)
+				return (tul_msgin_accept(pCurHcb));
+		}
+	}
+	return (tul_bad_seq(pCurHcb));
+}
+
+
+/***************************************************************************/
+/* scsi bus free */
+int int_tul_busfree(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+
+	if (pCurScb != NULL) {
+		if (pCurScb->SCB_Status & SCB_SELECT) {		/* selection timeout */
+			tul_unlink_pend_scb(pCurHcb, pCurScb);
+			pCurScb->SCB_HaStat = HOST_SEL_TOUT;
+			tul_append_done_scb(pCurHcb, pCurScb);
+		} else {	/* Unexpected bus free          */
+			tul_unlink_busy_scb(pCurHcb, pCurScb);
+			pCurScb->SCB_HaStat = HOST_BUS_FREE;
+			tul_append_done_scb(pCurHcb, pCurScb);
+		}
+		pCurHcb->HCS_ActScb = NULL;
+		pCurHcb->HCS_ActTcs = NULL;
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
+	return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi bus reset */
+int int_tul_scsi_rst(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+	int i;
+
+	/* if DMA xfer is pending, abort DMA xfer */
+	if (TUL_RD(pCurHcb->HCS_Base, TUL_XStatus) & 0x01) {
+		TUL_WR(pCurHcb->HCS_Base + TUL_XCmd, TAX_X_ABT | TAX_X_CLR_FIFO);
+		/* wait Abort DMA xfer done */
+		while ((TUL_RD(pCurHcb->HCS_Base, TUL_Int) & 0x04) == 0);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+	}
+	/* Abort all active & disconnected scb */
+	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+		tul_append_done_scb(pCurHcb, pCurScb);
+	}
+	pCurHcb->HCS_ActScb = NULL;
+	pCurHcb->HCS_ActTcs = NULL;
+
+	/* clr sync nego. done flag */
+	for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+	}
+	return (-1);
+}
+
+
+/***************************************************************************/
+/* scsi reselection */
+int int_tul_resel(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+	TCS *pCurTcb;
+	BYTE tag, msg = 0;
+	BYTE tar, lun;
+
+	if ((pCurScb = pCurHcb->HCS_ActScb) != NULL) {
+		if (pCurScb->SCB_Status & SCB_SELECT) {		/* if waiting for selection complete */
+			pCurScb->SCB_Status &= ~SCB_SELECT;
+		}
+		pCurHcb->HCS_ActScb = NULL;
+	}
+	/* --------- get target id---------------------- */
+	tar = TUL_RD(pCurHcb->HCS_Base, TUL_SBusId);
+	/* ------ get LUN from Identify message----------- */
+	lun = TUL_RD(pCurHcb->HCS_Base, TUL_SIdent) & 0x0F;
+	/* 07/22/98 from 0x1F -> 0x0F */
+	pCurTcb = &pCurHcb->HCS_Tcs[tar];
+	pCurHcb->HCS_ActTcs = pCurTcb;
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurTcb->TCS_SConfig0);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurTcb->TCS_JS_Period);
+
+
+	/* ------------- tag queueing ? ------------------- */
+	if (pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG) {
+		if ((tul_msgin_accept(pCurHcb)) == -1)
+			return (-1);
+		if (pCurHcb->HCS_Phase != MSG_IN)
+			goto no_tag;
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+		if ((wait_tulip(pCurHcb)) == -1)
+			return (-1);
+		msg = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* Read Tag Message    */
+
+		if ((msg < MSG_STAG) || (msg > MSG_OTAG))	/* Is simple Tag      */
+			goto no_tag;
+
+		if ((tul_msgin_accept(pCurHcb)) == -1)
+			return (-1);
+
+		if (pCurHcb->HCS_Phase != MSG_IN)
+			goto no_tag;
+
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+		if ((wait_tulip(pCurHcb)) == -1)
+			return (-1);
+		tag = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* Read Tag ID       */
+		pCurScb = pCurHcb->HCS_Scb + tag;
+		if ((pCurScb->SCB_Target != tar) || (pCurScb->SCB_Lun != lun)) {
+			return tul_msgout_abort_tag(pCurHcb);
+		}
+		if (pCurScb->SCB_Status != SCB_BUSY) {	/* 03/24/95             */
+			return tul_msgout_abort_tag(pCurHcb);
+		}
+		pCurHcb->HCS_ActScb = pCurScb;
+		if ((tul_msgin_accept(pCurHcb)) == -1)
+			return (-1);
+	} else {		/* No tag               */
+	      no_tag:
+		if ((pCurScb = tul_find_busy_scb(pCurHcb, tar | (lun << 8))) == NULL) {
+			return tul_msgout_abort_targ(pCurHcb);
+		}
+		pCurHcb->HCS_ActScb = pCurScb;
+		if (!(pCurTcb->TCS_DrvFlags & TCF_DRV_EN_TAG)) {
+			if ((tul_msgin_accept(pCurHcb)) == -1)
+				return (-1);
+		}
+	}
+	return 0;
+}
+
+
+/***************************************************************************/
+int int_tul_bad_seq(HCS * pCurHcb)
+{				/* target wrong phase           */
+	SCB *pCurScb;
+	int i;
+
+	tul_reset_scsi(pCurHcb, 10);
+
+	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+		tul_append_done_scb(pCurHcb, pCurScb);
+	}
+	for (i = 0; i < pCurHcb->HCS_MaxTar; i++) {
+		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+	}
+	return (-1);
+}
+
+
+/***************************************************************************/
+int tul_msgout_abort_targ(HCS * pCurHcb)
+{
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+	if (tul_msgin_accept(pCurHcb) == -1)
+		return (-1);
+	if (pCurHcb->HCS_Phase != MSG_OUT)
+		return (tul_bad_seq(pCurHcb));
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+	return tul_wait_disc(pCurHcb);
+}
+
+/***************************************************************************/
+int tul_msgout_abort_tag(HCS * pCurHcb)
+{
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+	if (tul_msgin_accept(pCurHcb) == -1)
+		return (-1);
+	if (pCurHcb->HCS_Phase != MSG_OUT)
+		return (tul_bad_seq(pCurHcb));
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_ABORT_TAG);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+	return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin(HCS * pCurHcb)
+{
+	TCS *pCurTcb;
+
+	for (;;) {
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+		if ((wait_tulip(pCurHcb)) == -1)
+			return (-1);
+
+		switch (TUL_RD(pCurHcb->HCS_Base, TUL_SFifo)) {
+		case MSG_DISC:	/* Disconnect msg */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+
+			return tul_wait_disc(pCurHcb);
+
+		case MSG_SDP:
+		case MSG_RESTORE:
+		case MSG_NOP:
+			tul_msgin_accept(pCurHcb);
+			break;
+
+		case MSG_REJ:	/* Clear ATN first              */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SSignal,
+			       (TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)));
+			pCurTcb = pCurHcb->HCS_ActTcs;
+			if ((pCurTcb->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0) {	/* do sync nego */
+				TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+			}
+			tul_msgin_accept(pCurHcb);
+			break;
+
+		case MSG_EXTEND:	/* extended msg */
+			tul_msgin_extend(pCurHcb);
+			break;
+
+		case MSG_IGNOREWIDE:
+			tul_msgin_accept(pCurHcb);
+			break;
+
+			/* get */
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+			if (wait_tulip(pCurHcb) == -1)
+				return -1;
+
+			TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 0);	/* put pad  */
+			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* get IGNORE field */
+			TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);	/* get pad */
+
+			tul_msgin_accept(pCurHcb);
+			break;
+
+		case MSG_COMP:
+			{
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+				TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+				return tul_wait_done_disc(pCurHcb);
+			}
+		default:
+			tul_msgout_reject(pCurHcb);
+			break;
+		}
+		if (pCurHcb->HCS_Phase != MSG_IN)
+			return (pCurHcb->HCS_Phase);
+	}
+	/* statement won't reach here */
+}
+
+
+
+
+/***************************************************************************/
+int tul_msgout_reject(HCS * pCurHcb)
+{
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+	if ((tul_msgin_accept(pCurHcb)) == -1)
+		return (-1);
+
+	if (pCurHcb->HCS_Phase == MSG_OUT) {
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_REJ);		/* Msg reject           */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+		return (wait_tulip(pCurHcb));
+	}
+	return (pCurHcb->HCS_Phase);
+}
+
+
+
+/***************************************************************************/
+int tul_msgout_ide(HCS * pCurHcb)
+{
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_IDE);		/* Initiator Detected Error */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+	return (wait_tulip(pCurHcb));
+}
+
+
+/***************************************************************************/
+int tul_msgin_extend(HCS * pCurHcb)
+{
+	BYTE len, idx;
+
+	if (tul_msgin_accept(pCurHcb) != MSG_IN)
+		return (pCurHcb->HCS_Phase);
+
+	/* Get extended msg length      */
+	TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+	if (wait_tulip(pCurHcb) == -1)
+		return (-1);
+
+	len = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+	pCurHcb->HCS_Msg[0] = len;
+	for (idx = 1; len != 0; len--) {
+
+		if ((tul_msgin_accept(pCurHcb)) != MSG_IN)
+			return (pCurHcb->HCS_Phase);
+		TUL_WRLONG(pCurHcb->HCS_Base + TUL_SCnt0, 1);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_IN);
+		if (wait_tulip(pCurHcb) == -1)
+			return (-1);
+		pCurHcb->HCS_Msg[idx++] = TUL_RD(pCurHcb->HCS_Base, TUL_SFifo);
+	}
+	if (pCurHcb->HCS_Msg[1] == 1) {		/* if it's synchronous data transfer request */
+		if (pCurHcb->HCS_Msg[0] != 3)	/* if length is not right */
+			return (tul_msgout_reject(pCurHcb));
+		if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_SYNC_NEGO) {	/* Set OFFSET=0 to do async, nego back */
+			pCurHcb->HCS_Msg[3] = 0;
+		} else {
+			if ((tul_msgin_sync(pCurHcb) == 0) &&
+			    (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SYNC_DONE)) {
+				tul_sync_done(pCurHcb);
+				return (tul_msgin_accept(pCurHcb));
+			}
+		}
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+		if ((tul_msgin_accept(pCurHcb)) != MSG_OUT)
+			return (pCurHcb->HCS_Phase);
+		/* sync msg out */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);
+
+		tul_sync_done(pCurHcb);
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 1);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[3]);
+
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+		return (wait_tulip(pCurHcb));
+	}
+	if ((pCurHcb->HCS_Msg[0] != 2) || (pCurHcb->HCS_Msg[1] != 3))
+		return (tul_msgout_reject(pCurHcb));
+	/* if it's WIDE DATA XFER REQ   */
+	if (pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) {
+		pCurHcb->HCS_Msg[2] = 0;
+	} else {
+		if (pCurHcb->HCS_Msg[2] > 2)	/* > 32 bits            */
+			return (tul_msgout_reject(pCurHcb));
+		if (pCurHcb->HCS_Msg[2] == 2) {		/* == 32                */
+			pCurHcb->HCS_Msg[2] = 1;
+		} else {
+			if ((pCurHcb->HCS_ActTcs->TCS_Flags & TCF_NO_WDTR) == 0) {
+				wdtr_done(pCurHcb);
+				if ((pCurHcb->HCS_ActTcs->TCS_Flags & (TCF_SYNC_DONE | TCF_NO_SYNC_NEGO)) == 0)
+					TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+				return (tul_msgin_accept(pCurHcb));
+			}
+		}
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SSignal, ((TUL_RD(pCurHcb->HCS_Base, TUL_SSignal) & (TSC_SET_ACK | 7)) | TSC_SET_ATN));
+
+	if (tul_msgin_accept(pCurHcb) != MSG_OUT)
+		return (pCurHcb->HCS_Phase);
+	/* WDTR msg out                 */
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_EXTEND);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 2);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, 3);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurHcb->HCS_Msg[2]);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+	return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_msgin_sync(HCS * pCurHcb)
+{
+	char default_period;
+
+	default_period = tul_rate_tbl[pCurHcb->HCS_ActTcs->TCS_Flags & TCF_SCSI_RATE];
+	if (pCurHcb->HCS_Msg[3] > MAX_OFFSET) {
+		pCurHcb->HCS_Msg[3] = MAX_OFFSET;
+		if (pCurHcb->HCS_Msg[2] < default_period) {
+			pCurHcb->HCS_Msg[2] = default_period;
+			return 1;
+		}
+		if (pCurHcb->HCS_Msg[2] >= 59) {	/* Change to async              */
+			pCurHcb->HCS_Msg[3] = 0;
+		}
+		return 1;
+	}
+	/* offset requests asynchronous transfers ? */
+	if (pCurHcb->HCS_Msg[3] == 0) {
+		return 0;
+	}
+	if (pCurHcb->HCS_Msg[2] < default_period) {
+		pCurHcb->HCS_Msg[2] = default_period;
+		return 1;
+	}
+	if (pCurHcb->HCS_Msg[2] >= 59) {
+		pCurHcb->HCS_Msg[3] = 0;
+		return 1;
+	}
+	return 0;
+}
+
+
+/***************************************************************************/
+int wdtr_done(HCS * pCurHcb)
+{
+	pCurHcb->HCS_ActTcs->TCS_Flags &= ~TCF_SYNC_DONE;
+	pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_WDTR_DONE;
+
+	pCurHcb->HCS_ActTcs->TCS_JS_Period = 0;
+	if (pCurHcb->HCS_Msg[2]) {	/* if 16 bit */
+		pCurHcb->HCS_ActTcs->TCS_JS_Period |= TSC_WIDE_SCSI;
+	}
+	pCurHcb->HCS_ActTcs->TCS_SConfig0 &= ~TSC_ALT_PERIOD;
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+	return 1;
+}
+
+/***************************************************************************/
+int tul_sync_done(HCS * pCurHcb)
+{
+	int i;
+
+	pCurHcb->HCS_ActTcs->TCS_Flags |= TCF_SYNC_DONE;
+
+	if (pCurHcb->HCS_Msg[3]) {
+		pCurHcb->HCS_ActTcs->TCS_JS_Period |= pCurHcb->HCS_Msg[3];
+		for (i = 0; i < 8; i++) {
+			if (tul_rate_tbl[i] >= pCurHcb->HCS_Msg[2])	/* pick the big one */
+				break;
+		}
+		pCurHcb->HCS_ActTcs->TCS_JS_Period |= (i << 4);
+		pCurHcb->HCS_ActTcs->TCS_SConfig0 |= TSC_ALT_PERIOD;
+	}
+	TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, pCurHcb->HCS_ActTcs->TCS_SConfig0);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SPeriod, pCurHcb->HCS_ActTcs->TCS_JS_Period);
+
+	return (-1);
+}
+
+
+int tul_post_scsi_rst(HCS * pCurHcb)
+{
+	SCB *pCurScb;
+	TCS *pCurTcb;
+	int i;
+
+	pCurHcb->HCS_ActScb = NULL;
+	pCurHcb->HCS_ActTcs = NULL;
+	pCurHcb->HCS_Flags = 0;
+
+	while ((pCurScb = tul_pop_busy_scb(pCurHcb)) != NULL) {
+		pCurScb->SCB_HaStat = HOST_BAD_PHAS;
+		tul_append_done_scb(pCurHcb, pCurScb);
+	}
+	/* clear sync done flag         */
+	pCurTcb = &pCurHcb->HCS_Tcs[0];
+	for (i = 0; i < pCurHcb->HCS_MaxTar; pCurTcb++, i++) {
+		pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE);
+		/* Initialize the sync. xfer register values to an asyn xfer */
+		pCurTcb->TCS_JS_Period = 0;
+		pCurTcb->TCS_SConfig0 = pCurHcb->HCS_SConf1;
+		pCurHcb->HCS_ActTags[0] = 0;	/* 07/22/98 */
+		pCurHcb->HCS_Tcs[i].TCS_Flags &= ~TCF_BUSY;	/* 07/22/98 */
+	}			/* for */
+
+	return (-1);
+}
+
+/***************************************************************************/
+void tul_select_atn_stop(HCS * pCurHcb, SCB * pCurScb)
+{
+	pCurScb->SCB_Status |= SCB_SELECT;
+	pCurScb->SCB_NxtStat = 0x1;
+	pCurHcb->HCS_ActScb = pCurScb;
+	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SELATNSTOP);
+	return;
+}
+
+
+/***************************************************************************/
+void tul_select_atn(HCS * pCurHcb, SCB * pCurScb)
+{
+	int i;
+
+	pCurScb->SCB_Status |= SCB_SELECT;
+	pCurScb->SCB_NxtStat = 0x2;
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+	for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+	pCurHcb->HCS_ActScb = pCurScb;
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN);
+	return;
+}
+
+/***************************************************************************/
+void tul_select_atn3(HCS * pCurHcb, SCB * pCurScb)
+{
+	int i;
+
+	pCurScb->SCB_Status |= SCB_SELECT;
+	pCurScb->SCB_NxtStat = 0x2;
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_Ident);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagMsg);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_TagId);
+	for (i = 0; i < (int) pCurScb->SCB_CDBLen; i++)
+		TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, pCurScb->SCB_CDB[i]);
+	pCurHcb->HCS_ActTcs = &pCurHcb->HCS_Tcs[pCurScb->SCB_Target];
+	pCurHcb->HCS_ActScb = pCurScb;
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_SEL_ATN3);
+	return;
+}
+
+/***************************************************************************/
+/* SCSI Bus Device Reset */
+int tul_bus_device_reset(HCS * pCurHcb)
+{
+	SCB *pCurScb = pCurHcb->HCS_ActScb;
+	TCS *pCurTcb = pCurHcb->HCS_ActTcs;
+	SCB *pTmpScb, *pPrevScb;
+	BYTE tar;
+
+	if (pCurHcb->HCS_Phase != MSG_OUT) {
+		return (int_tul_bad_seq(pCurHcb));	/* Unexpected phase             */
+	}
+	tul_unlink_pend_scb(pCurHcb, pCurScb);
+	tul_release_scb(pCurHcb, pCurScb);
+
+
+	tar = pCurScb->SCB_Target;	/* target                       */
+	pCurTcb->TCS_Flags &= ~(TCF_SYNC_DONE | TCF_WDTR_DONE | TCF_BUSY);
+	/* clr sync. nego & WDTR flags  07/22/98 */
+
+	/* abort all SCB with same target */
+	pPrevScb = pTmpScb = pCurHcb->HCS_FirstBusy;	/* Check Busy queue */
+	while (pTmpScb != NULL) {
+
+		if (pTmpScb->SCB_Target == tar) {
+			/* unlink it */
+			if (pTmpScb == pCurHcb->HCS_FirstBusy) {
+				if ((pCurHcb->HCS_FirstBusy = pTmpScb->SCB_NxtScb) == NULL)
+					pCurHcb->HCS_LastBusy = NULL;
+			} else {
+				pPrevScb->SCB_NxtScb = pTmpScb->SCB_NxtScb;
+				if (pTmpScb == pCurHcb->HCS_LastBusy)
+					pCurHcb->HCS_LastBusy = pPrevScb;
+			}
+			pTmpScb->SCB_HaStat = HOST_ABORTED;
+			tul_append_done_scb(pCurHcb, pTmpScb);
+		}
+		/* Previous haven't change      */
+		else {
+			pPrevScb = pTmpScb;
+		}
+		pTmpScb = pTmpScb->SCB_NxtScb;
+	}
+
+	TUL_WR(pCurHcb->HCS_Base + TUL_SFifo, MSG_DEVRST);
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_XF_FIFO_OUT);
+
+	return tul_wait_disc(pCurHcb);
+
+}
+
+/***************************************************************************/
+int tul_msgin_accept(HCS * pCurHcb)
+{
+	TUL_WR(pCurHcb->HCS_Base + TUL_SCmd, TSC_MSG_ACCEPT);
+	return (wait_tulip(pCurHcb));
+}
+
+/***************************************************************************/
+int wait_tulip(HCS * pCurHcb)
+{
+
+	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+		 & TSS_INT_PENDING));
+
+	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+	pCurHcb->HCS_Phase = pCurHcb->HCS_JSStatus0 & TSS_PH_MASK;
+	pCurHcb->HCS_JSStatus1 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus1);
+
+	if (pCurHcb->HCS_JSInt & TSS_RESEL_INT) {	/* if SCSI bus reset detected   */
+		return (int_tul_resel(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & TSS_SEL_TIMEOUT) {	/* if selected/reselected timeout interrupt */
+		return (int_tul_busfree(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
+		return (int_tul_scsi_rst(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
+		if (pCurHcb->HCS_Flags & HCF_EXPECT_DONE_DISC) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
+			tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+			pCurHcb->HCS_ActScb->SCB_HaStat = 0;
+			tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+			pCurHcb->HCS_ActScb = NULL;
+			pCurHcb->HCS_ActTcs = NULL;
+			pCurHcb->HCS_Flags &= ~HCF_EXPECT_DONE_DISC;
+			TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
+			return (-1);
+		}
+		if (pCurHcb->HCS_Flags & HCF_EXPECT_DISC) {
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
+			pCurHcb->HCS_ActScb = NULL;
+			pCurHcb->HCS_ActTcs = NULL;
+			pCurHcb->HCS_Flags &= ~HCF_EXPECT_DISC;
+			TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+			TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
+			return (-1);
+		}
+		return (int_tul_busfree(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & (TSS_FUNC_COMP | TSS_BUS_SERV)) {
+		return (pCurHcb->HCS_Phase);
+	}
+	return (pCurHcb->HCS_Phase);
+}
+/***************************************************************************/
+int tul_wait_disc(HCS * pCurHcb)
+{
+
+	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+		 & TSS_INT_PENDING));
+
+
+	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
+		return (int_tul_scsi_rst(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
+		pCurHcb->HCS_ActScb = NULL;
+		return (-1);
+	}
+	return (tul_bad_seq(pCurHcb));
+}
+
+/***************************************************************************/
+int tul_wait_done_disc(HCS * pCurHcb)
+{
+
+
+	while (!((pCurHcb->HCS_JSStatus0 = TUL_RD(pCurHcb->HCS_Base, TUL_SStatus0))
+		 & TSS_INT_PENDING));
+
+	pCurHcb->HCS_JSInt = TUL_RD(pCurHcb->HCS_Base, TUL_SInt);
+
+
+	if (pCurHcb->HCS_JSInt & TSS_SCSIRST_INT) {	/* if SCSI bus reset detected   */
+		return (int_tul_scsi_rst(pCurHcb));
+	}
+	if (pCurHcb->HCS_JSInt & TSS_DISC_INT) {	/* BUS disconnection            */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl0, TSC_FLUSH_FIFO);		/* Flush SCSI FIFO  */
+		TUL_WR(pCurHcb->HCS_Base + TUL_SConfig, TSC_INITDEFAULT);
+		TUL_WR(pCurHcb->HCS_Base + TUL_SCtrl1, TSC_HW_RESELECT);	/* Enable HW reselect       */
+		tul_unlink_busy_scb(pCurHcb, pCurHcb->HCS_ActScb);
+
+		tul_append_done_scb(pCurHcb, pCurHcb->HCS_ActScb);
+		pCurHcb->HCS_ActScb = NULL;
+		return (-1);
+	}
+	return (tul_bad_seq(pCurHcb));
+}
+
+static irqreturn_t i91u_intr(int irqno, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *dev = dev_id;
+	unsigned long flags;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
+	tul_isr((HCS *)dev->base);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static int tul_NewReturnNumberOfAdapters(void)
+{
+	struct pci_dev *pDev = NULL;	/* Start from none              */
+	int iAdapters = 0;
+	long dRegValue;
+	WORD wBIOS;
+	int i = 0;
+
+	init_i91uAdapter_table();
+
+	for (i = 0; i < TULSZ(i91u_pci_devices); i++)
+	{
+		while ((pDev = pci_find_device(i91u_pci_devices[i].vendor_id, i91u_pci_devices[i].device_id, pDev)) != NULL) {
+			if (pci_enable_device(pDev))
+				continue;
+			pci_read_config_dword(pDev, 0x44, (u32 *) & dRegValue);
+			wBIOS = (UWORD) (dRegValue & 0xFF);
+			if (((dRegValue & 0xFF00) >> 8) == 0xFF)
+				dRegValue = 0;
+			wBIOS = (wBIOS << 8) + ((UWORD) ((dRegValue & 0xFF00) >> 8));
+			if (pci_set_dma_mask(pDev, 0xffffffff)) {
+				printk(KERN_WARNING 
+				       "i91u: Could not set 32 bit DMA mask\n");
+				continue;
+			}
+
+			if (Addi91u_into_Adapter_table(wBIOS,
+							(pDev->resource[0].start),
+						       	pDev->irq,
+						       	pDev->bus->number,
+					       		(pDev->devfn >> 3)
+		    		) == 0)
+				iAdapters++;
+		}
+	}
+
+	return (iAdapters);
+}
+
+static int i91u_detect(struct scsi_host_template * tpnt)
+{
+	HCS *pHCB;
+	struct Scsi_Host *hreg;
+	unsigned long i;	/* 01/14/98                     */
+	int ok = 0, iAdapters;
+	ULONG dBiosAdr;
+	BYTE *pbBiosAdr;
+
+	/* Get total number of adapters in the motherboard */
+	iAdapters = tul_NewReturnNumberOfAdapters();
+	if (iAdapters == 0)	/* If no tulip founded, return */
+		return (0);
+
+	tul_num_ch = (iAdapters > tul_num_ch) ? tul_num_ch : iAdapters;
+	/* Update actually channel number */
+	if (tul_tag_enable) {	/* 1.01i                  */
+		tul_num_scb = MAX_TARGETS * i91u_MAXQUEUE;
+	} else {
+		tul_num_scb = MAX_TARGETS + 3;	/* 1-tape, 1-CD_ROM, 1- extra */
+	}			/* Update actually SCBs per adapter */
+
+	/* Get total memory needed for HCS */
+	i = tul_num_ch * sizeof(HCS);
+	memset((unsigned char *) &tul_hcs[0], 0, i);	/* Initialize tul_hcs 0 */
+	/* Get total memory needed for SCB */
+
+	for (; tul_num_scb >= MAX_TARGETS + 3; tul_num_scb--) {
+		i = tul_num_ch * tul_num_scb * sizeof(SCB);
+		if ((tul_scb = (SCB *) kmalloc(i, GFP_ATOMIC | GFP_DMA)) != NULL)
+			break;
+	}
+	if (tul_scb == NULL) {
+		printk("i91u: SCB memory allocation error\n");
+		return (0);
+	}
+	memset((unsigned char *) tul_scb, 0, i);
+
+	for (i = 0, pHCB = &tul_hcs[0];		/* Get pointer for control block */
+	     i < tul_num_ch;
+	     i++, pHCB++) {
+		get_tulipPCIConfig(pHCB, i);
+
+		dBiosAdr = pHCB->HCS_BIOS;
+		dBiosAdr = (dBiosAdr << 4);
+
+		pbBiosAdr = phys_to_virt(dBiosAdr);
+
+		init_tulip(pHCB, tul_scb + (i * tul_num_scb), tul_num_scb, pbBiosAdr, 10);
+		request_region(pHCB->HCS_Base, 256, "i91u"); /* Register */ 
+
+		pHCB->HCS_Index = i;	/* 7/29/98 */
+		hreg = scsi_register(tpnt, sizeof(HCS));
+		if(hreg == NULL) {
+			release_region(pHCB->HCS_Base, 256);
+			return 0;
+		}
+		hreg->io_port = pHCB->HCS_Base;
+		hreg->n_io_port = 0xff;
+		hreg->can_queue = tul_num_scb;	/* 03/05/98                      */
+		hreg->unique_id = pHCB->HCS_Base;
+		hreg->max_id = pHCB->HCS_MaxTar;
+		hreg->max_lun = 32;	/* 10/21/97                     */
+		hreg->irq = pHCB->HCS_Intr;
+		hreg->this_id = pHCB->HCS_SCSI_ID;	/* Assign HCS index           */
+		hreg->base = (unsigned long)pHCB;
+		hreg->sg_tablesize = TOTAL_SG_ENTRY;	/* Maximun support is 32 */
+
+		/* Initial tulip chip           */
+		ok = request_irq(pHCB->HCS_Intr, i91u_intr, SA_INTERRUPT | SA_SHIRQ, "i91u", hreg);
+		if (ok < 0) {
+			printk(KERN_WARNING "i91u: unable to request IRQ %d\n\n", pHCB->HCS_Intr);
+			return 0;
+		}
+	}
+
+	tpnt->this_id = -1;
+	tpnt->can_queue = 1;
+
+	return 1;
+}
+
+static void i91uBuildSCB(HCS * pHCB, SCB * pSCB, struct scsi_cmnd * SCpnt)
+{				/* Create corresponding SCB     */
+	struct scatterlist *pSrbSG;
+	SG *pSG;		/* Pointer to SG list           */
+	int i;
+	long TotalLen;
+	dma_addr_t dma_addr;
+
+	pSCB->SCB_Post = i91uSCBPost;	/* i91u's callback routine      */
+	pSCB->SCB_Srb = SCpnt;
+	pSCB->SCB_Opcode = ExecSCSI;
+	pSCB->SCB_Flags = SCF_POST;	/* After SCSI done, call post routine */
+	pSCB->SCB_Target = SCpnt->device->id;
+	pSCB->SCB_Lun = SCpnt->device->lun;
+	pSCB->SCB_Ident = SCpnt->device->lun | DISC_ALLOW;
+
+	pSCB->SCB_Flags |= SCF_SENSE;	/* Turn on auto request sense   */
+	dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->sense_buffer,
+				  SENSE_SIZE, DMA_FROM_DEVICE);
+	pSCB->SCB_SensePtr = cpu_to_le32((u32)dma_addr);
+	pSCB->SCB_SenseLen = cpu_to_le32(SENSE_SIZE);
+	SCpnt->SCp.ptr = (char *)(unsigned long)dma_addr;
+
+	pSCB->SCB_CDBLen = SCpnt->cmd_len;
+	pSCB->SCB_HaStat = 0;
+	pSCB->SCB_TaStat = 0;
+	memcpy(&pSCB->SCB_CDB[0], &SCpnt->cmnd, SCpnt->cmd_len);
+
+	if (SCpnt->device->tagged_supported) {	/* Tag Support                  */
+		pSCB->SCB_TagMsg = SIMPLE_QUEUE_TAG;	/* Do simple tag only   */
+	} else {
+		pSCB->SCB_TagMsg = 0;	/* No tag support               */
+	}
+	/* todo handle map_sg error */
+	if (SCpnt->use_sg) {
+		dma_addr = dma_map_single(&pHCB->pci_dev->dev, &pSCB->SCB_SGList[0],
+					  sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+					  DMA_BIDIRECTIONAL);
+		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
+		SCpnt->SCp.dma_handle = dma_addr;
+
+		pSrbSG = (struct scatterlist *) SCpnt->request_buffer;
+		pSCB->SCB_SGLen = dma_map_sg(&pHCB->pci_dev->dev, pSrbSG,
+					     SCpnt->use_sg, SCpnt->sc_data_direction);
+
+		pSCB->SCB_Flags |= SCF_SG;	/* Turn on SG list flag       */
+		for (i = 0, TotalLen = 0, pSG = &pSCB->SCB_SGList[0];	/* 1.01g */
+		     i < pSCB->SCB_SGLen; i++, pSG++, pSrbSG++) {
+			pSG->SG_Ptr = cpu_to_le32((u32)sg_dma_address(pSrbSG));
+			TotalLen += pSG->SG_Len = cpu_to_le32((u32)sg_dma_len(pSrbSG));
+		}
+
+		pSCB->SCB_BufLen = (SCpnt->request_bufflen > TotalLen) ?
+		    TotalLen : SCpnt->request_bufflen;
+	} else if (SCpnt->request_bufflen) {		/* Non SG */
+		dma_addr = dma_map_single(&pHCB->pci_dev->dev, SCpnt->request_buffer,
+					  SCpnt->request_bufflen,
+					  SCpnt->sc_data_direction);
+		SCpnt->SCp.dma_handle = dma_addr;
+		pSCB->SCB_BufPtr = cpu_to_le32((u32)dma_addr);
+		pSCB->SCB_BufLen = cpu_to_le32((u32)SCpnt->request_bufflen);
+		pSCB->SCB_SGLen = 0;
+	} else {
+		pSCB->SCB_BufLen = 0;
+		pSCB->SCB_SGLen = 0;
+	}
+}
+
+static int i91u_queuecommand(struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	HCS *pHCB = (HCS *) cmd->device->host->base;
+	register SCB *pSCB;
+
+	cmd->scsi_done = done;
+
+	pSCB = tul_alloc_scb(pHCB);
+	if (!pSCB)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	i91uBuildSCB(pHCB, pSCB, cmd);
+	tul_exec_scb(pHCB, pSCB);
+	return 0;
+}
+
+#if 0 /* no new EH yet */
+/*
+ *  Abort a queued command
+ *  (commands that are on the bus can't be aborted easily)
+ */
+static int i91u_abort(struct scsi_cmnd * SCpnt)
+{
+	HCS *pHCB;
+
+	pHCB = (HCS *) SCpnt->device->host->base;
+	return tul_abort_srb(pHCB, SCpnt);
+}
+
+/*
+ *  Reset registers, reset a hanging bus and
+ *  kill active and disconnected commands for target w/o soft reset
+ */
+static int i91u_reset(struct scsi_cmnd * SCpnt, unsigned int reset_flags)
+{				/* I need Host Control Block Information */
+	HCS *pHCB;
+
+	pHCB = (HCS *) SCpnt->device->host->base;
+
+	if (reset_flags & (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET))
+		return tul_reset_scsi_bus(pHCB);
+	else
+		return tul_device_reset(pHCB, SCpnt, SCpnt->device->id, reset_flags);
+}
+#endif
+
+static int i91u_bus_reset(struct scsi_cmnd * SCpnt)
+{
+	HCS *pHCB;
+
+	pHCB = (HCS *) SCpnt->device->host->base;
+	tul_reset_scsi(pHCB, 0);
+	return SUCCESS;
+}
+
+/*
+ * Return the "logical geometry"
+ */
+static int i91u_biosparam(struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int *info_array)
+{
+	HCS *pHcb;		/* Point to Host adapter control block */
+	TCS *pTcb;
+
+	pHcb = (HCS *) sdev->host->base;
+	pTcb = &pHcb->HCS_Tcs[sdev->id];
+
+	if (pTcb->TCS_DrvHead) {
+		info_array[0] = pTcb->TCS_DrvHead;
+		info_array[1] = pTcb->TCS_DrvSector;
+		info_array[2] = (unsigned long)capacity / pTcb->TCS_DrvHead / pTcb->TCS_DrvSector;
+	} else {
+		if (pTcb->TCS_DrvFlags & TCF_DRV_255_63) {
+			info_array[0] = 255;
+			info_array[1] = 63;
+			info_array[2] = (unsigned long)capacity / 255 / 63;
+		} else {
+			info_array[0] = 64;
+			info_array[1] = 32;
+			info_array[2] = (unsigned long)capacity >> 11;
+		}
+	}
+
+#if defined(DEBUG_BIOSPARAM)
+	if (i91u_debug & debug_biosparam) {
+		printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+		       info_array[0], info_array[1], info_array[2]);
+		printk("WARNING: check, if the bios geometry is correct.\n");
+	}
+#endif
+
+	return 0;
+}
+
+static void i91u_unmap_cmnd(struct pci_dev *pci_dev, struct scsi_cmnd *cmnd)
+{
+	/* auto sense buffer */
+	if (cmnd->SCp.ptr) {
+		dma_unmap_single(&pci_dev->dev,
+				 (dma_addr_t)((unsigned long)cmnd->SCp.ptr),
+				 SENSE_SIZE, DMA_FROM_DEVICE);
+		cmnd->SCp.ptr = NULL;
+	}
+
+	/* request buffer */
+	if (cmnd->use_sg) {
+		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
+				 sizeof(struct SG_Struc) * TOTAL_SG_ENTRY,
+				 DMA_BIDIRECTIONAL);
+
+		dma_unmap_sg(&pci_dev->dev, cmnd->request_buffer,
+			     cmnd->use_sg,
+			     cmnd->sc_data_direction);
+	} else if (cmnd->request_bufflen) {
+		dma_unmap_single(&pci_dev->dev, cmnd->SCp.dma_handle,
+				 cmnd->request_bufflen,
+				 cmnd->sc_data_direction);
+	}
+}
+
+/*****************************************************************************
+ Function name  : i91uSCBPost
+ Description    : This is callback routine be called when tulip finish one
+			SCSI command.
+ Input          : pHCB  -       Pointer to host adapter control block.
+		  pSCB  -       Pointer to SCSI control block.
+ Output         : None.
+ Return         : None.
+*****************************************************************************/
+static void i91uSCBPost(BYTE * pHcb, BYTE * pScb)
+{
+	struct scsi_cmnd *pSRB;	/* Pointer to SCSI request block */
+	HCS *pHCB;
+	SCB *pSCB;
+
+	pHCB = (HCS *) pHcb;
+	pSCB = (SCB *) pScb;
+	if ((pSRB = pSCB->SCB_Srb) == 0) {
+		printk("i91uSCBPost: SRB pointer is empty\n");
+
+		tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
+		return;
+	}
+	switch (pSCB->SCB_HaStat) {
+	case 0x0:
+	case 0xa:		/* Linked command complete without error and linked normally */
+	case 0xb:		/* Linked command complete without error interrupt generated */
+		pSCB->SCB_HaStat = 0;
+		break;
+
+	case 0x11:		/* Selection time out-The initiator selection or target
+				   reselection was not complete within the SCSI Time out period */
+		pSCB->SCB_HaStat = DID_TIME_OUT;
+		break;
+
+	case 0x14:		/* Target bus phase sequence failure-An invalid bus phase or bus
+				   phase sequence was requested by the target. The host adapter
+				   will generate a SCSI Reset Condition, notifying the host with
+				   a SCRD interrupt */
+		pSCB->SCB_HaStat = DID_RESET;
+		break;
+
+	case 0x1a:		/* SCB Aborted. 07/21/98 */
+		pSCB->SCB_HaStat = DID_ABORT;
+		break;
+
+	case 0x12:		/* Data overrun/underrun-The target attempted to transfer more data
+				   than was allocated by the Data Length field or the sum of the
+				   Scatter / Gather Data Length fields. */
+	case 0x13:		/* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */
+	case 0x16:		/* Invalid SCB Operation Code. */
+
+	default:
+		printk("ini9100u: %x %x\n", pSCB->SCB_HaStat, pSCB->SCB_TaStat);
+		pSCB->SCB_HaStat = DID_ERROR;	/* Couldn't find any better */
+		break;
+	}
+
+	pSRB->result = pSCB->SCB_TaStat | (pSCB->SCB_HaStat << 16);
+
+	if (pSRB == NULL) {
+		printk("pSRB is NULL\n");
+	}
+
+	i91u_unmap_cmnd(pHCB->pci_dev, pSRB);
+	pSRB->scsi_done(pSRB);	/* Notify system DONE           */
+
+	tul_release_scb(pHCB, pSCB);	/* Release SCB for current channel */
+}
+
+/*
+ * Release ressources
+ */
+static int i91u_release(struct Scsi_Host *hreg)
+{
+	free_irq(hreg->irq, hreg);
+	release_region(hreg->io_port, 256);
+	return 0;
+}
+MODULE_LICENSE("Dual BSD/GPL");
+
+static struct scsi_host_template driver_template = {
+	.proc_name	= "INI9100U",
+	.name		= i91u_REVID,
+	.detect		= i91u_detect,
+	.release	= i91u_release,
+	.queuecommand	= i91u_queuecommand,
+//	.abort		= i91u_abort,
+//	.reset		= i91u_reset,
+	.eh_bus_reset_handler = i91u_bus_reset,
+	.bios_param	= i91u_biosparam,
+	.can_queue	= 1,
+	.this_id	= 1,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun 	= 1,
+	.use_clustering	= ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+
diff --git a/drivers/scsi/initio.h b/drivers/scsi/initio.h
new file mode 100644
index 0000000..df3ed7c
--- /dev/null
+++ b/drivers/scsi/initio.h
@@ -0,0 +1,739 @@
+/**************************************************************************
+ * Initio 9100 device driver for Linux.
+ *
+ * Copyright (c) 1994-1998 Initio Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of 
+ * the GNU General Public License ("GPL") and the terms of the GPL would require the 
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ **************************************************************************/
+
+
+#include <linux/config.h>
+#include <linux/types.h>
+
+#define ULONG   unsigned long
+#define USHORT  unsigned short
+#define UCHAR   unsigned char
+#define BYTE    unsigned char
+#define WORD    unsigned short
+#define DWORD   unsigned long
+#define UBYTE   unsigned char
+#define UWORD   unsigned short
+#define UDWORD  unsigned long
+#define U32     u32
+
+#define TOTAL_SG_ENTRY		32
+#define MAX_SUPPORTED_ADAPTERS  8
+#define MAX_OFFSET		15
+#define MAX_TARGETS		16
+
+typedef struct {
+	unsigned short base;
+	unsigned short vec;
+} i91u_config;
+
+/***************************************/
+/*  Tulip Configuration Register Set */
+/***************************************/
+#define TUL_PVID        0x00	/* Vendor ID                    */
+#define TUL_PDID        0x02	/* Device ID                    */
+#define TUL_PCMD        0x04	/* Command                      */
+#define TUL_PSTUS       0x06	/* Status                       */
+#define TUL_PRID        0x08	/* Revision number              */
+#define TUL_PPI         0x09	/* Programming interface        */
+#define TUL_PSC         0x0A	/* Sub Class                    */
+#define TUL_PBC         0x0B	/* Base Class                   */
+#define TUL_PCLS        0x0C	/* Cache line size              */
+#define TUL_PLTR        0x0D	/* Latency timer                */
+#define TUL_PHDT        0x0E	/* Header type                  */
+#define TUL_PBIST       0x0F	/* BIST                         */
+#define TUL_PBAD        0x10	/* Base address                 */
+#define TUL_PBAD1       0x14	/* Base address                 */
+#define TUL_PBAD2       0x18	/* Base address                 */
+#define TUL_PBAD3       0x1C	/* Base address                 */
+#define TUL_PBAD4       0x20	/* Base address                 */
+#define TUL_PBAD5       0x24	/* Base address                 */
+#define TUL_PRSVD       0x28	/* Reserved                     */
+#define TUL_PRSVD1      0x2C	/* Reserved                     */
+#define TUL_PRAD        0x30	/* Expansion ROM base address   */
+#define TUL_PRSVD2      0x34	/* Reserved                     */
+#define TUL_PRSVD3      0x38	/* Reserved                     */
+#define TUL_PINTL       0x3C	/* Interrupt line               */
+#define TUL_PINTP       0x3D	/* Interrupt pin                */
+#define TUL_PIGNT       0x3E	/* MIN_GNT                      */
+#define TUL_PMGNT       0x3F	/* MAX_GNT                      */
+
+/************************/
+/*  Jasmin Register Set */
+/************************/
+#define TUL_HACFG0      0x40	/* H/A Configuration Register 0         */
+#define TUL_HACFG1      0x41	/* H/A Configuration Register 1         */
+#define TUL_HACFG2      0x42	/* H/A Configuration Register 2         */
+
+#define TUL_SDCFG0      0x44	/* SCSI Device Configuration 0          */
+#define TUL_SDCFG1      0x45	/* SCSI Device Configuration 1          */
+#define TUL_SDCFG2      0x46	/* SCSI Device Configuration 2          */
+#define TUL_SDCFG3      0x47	/* SCSI Device Configuration 3          */
+
+#define TUL_GINTS       0x50	/* Global Interrupt Status Register     */
+#define TUL_GIMSK       0x52	/* Global Interrupt MASK Register       */
+#define TUL_GCTRL       0x54	/* Global Control Register              */
+#define TUL_GCTRL_EEPROM_BIT    0x04
+#define TUL_GCTRL1      0x55	/* Global Control Register              */
+#define TUL_DMACFG      0x5B	/* DMA configuration                    */
+#define TUL_NVRAM       0x5D	/* Non-volatile RAM port                */
+
+#define TUL_SCnt0       0x80	/* 00 R/W Transfer Counter Low          */
+#define TUL_SCnt1       0x81	/* 01 R/W Transfer Counter Mid          */
+#define TUL_SCnt2       0x82	/* 02 R/W Transfer Count High           */
+#define TUL_SFifoCnt    0x83	/* 03 R   FIFO counter                  */
+#define TUL_SIntEnable  0x84	/* 03 W   Interrupt enble               */
+#define TUL_SInt        0x84	/* 04 R   Interrupt Register            */
+#define TUL_SCtrl0      0x85	/* 05 W   Control 0                     */
+#define TUL_SStatus0    0x85	/* 05 R   Status 0                      */
+#define TUL_SCtrl1      0x86	/* 06 W   Control 1                     */
+#define TUL_SStatus1    0x86	/* 06 R   Status 1                      */
+#define TUL_SConfig     0x87	/* 07 W   Configuration                 */
+#define TUL_SStatus2    0x87	/* 07 R   Status 2                      */
+#define TUL_SPeriod     0x88	/* 08 W   Sync. Transfer Period & Offset */
+#define TUL_SOffset     0x88	/* 08 R   Offset                        */
+#define TUL_SScsiId     0x89	/* 09 W   SCSI ID                       */
+#define TUL_SBusId      0x89	/* 09 R   SCSI BUS ID                   */
+#define TUL_STimeOut    0x8A	/* 0A W   Sel/Resel Time Out Register   */
+#define TUL_SIdent      0x8A	/* 0A R   Identify Message Register     */
+#define TUL_SAvail      0x8A	/* 0A R   Availiable Counter Register   */
+#define TUL_SData       0x8B	/* 0B R/W SCSI data in/out              */
+#define TUL_SFifo       0x8C	/* 0C R/W FIFO                          */
+#define TUL_SSignal     0x90	/* 10 R/W SCSI signal in/out            */
+#define TUL_SCmd        0x91	/* 11 R/W Command                       */
+#define TUL_STest0      0x92	/* 12 R/W Test0                         */
+#define TUL_STest1      0x93	/* 13 R/W Test1                         */
+#define TUL_SCFG1	0x94	/* 14 R/W Configuration                 */
+
+#define TUL_XAddH       0xC0	/*DMA Transfer Physical Address         */
+#define TUL_XAddW       0xC8	/*DMA Current Transfer Physical Address */
+#define TUL_XCntH       0xD0	/*DMA Transfer Counter                  */
+#define TUL_XCntW       0xD4	/*DMA Current Transfer Counter          */
+#define TUL_XCmd        0xD8	/*DMA Command Register                  */
+#define TUL_Int         0xDC	/*Interrupt Register                    */
+#define TUL_XStatus     0xDD	/*DMA status Register                   */
+#define TUL_Mask        0xE0	/*Interrupt Mask Register               */
+#define TUL_XCtrl       0xE4	/*DMA Control Register                  */
+#define TUL_XCtrl1      0xE5	/*DMA Control Register 1                */
+#define TUL_XFifo       0xE8	/*DMA FIFO                              */
+
+#define TUL_WCtrl       0xF7	/*Bus master wait state control         */
+#define TUL_DCtrl       0xFB	/*DMA delay control                     */
+
+/*----------------------------------------------------------------------*/
+/*   bit definition for Command register of Configuration Space Header  */
+/*----------------------------------------------------------------------*/
+#define BUSMS           0x04	/* BUS MASTER Enable                    */
+#define IOSPA           0x01	/* IO Space Enable                      */
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip SCSI Command register                         */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_RESEL    0x80	/* Enable Reselection                   */
+#define TSC_CMD_COMP    0x84	/* Command Complete Sequence            */
+#define TSC_SEL         0x01	/* Select Without ATN Sequence          */
+#define TSC_SEL_ATN     0x11	/* Select With ATN Sequence             */
+#define TSC_SEL_ATN_DMA 0x51	/* Select With ATN Sequence with DMA    */
+#define TSC_SEL_ATN3    0x31	/* Select With ATN3 Sequence            */
+#define TSC_SEL_ATNSTOP 0x12	/* Select With ATN and Stop Sequence    */
+#define TSC_SELATNSTOP  0x1E	/* Select With ATN and Stop Sequence    */
+
+#define TSC_SEL_ATN_DIRECT_IN   0x95	/* Select With ATN Sequence     */
+#define TSC_SEL_ATN_DIRECT_OUT  0x15	/* Select With ATN Sequence     */
+#define TSC_SEL_ATN3_DIRECT_IN  0xB5	/* Select With ATN3 Sequence    */
+#define TSC_SEL_ATN3_DIRECT_OUT 0x35	/* Select With ATN3 Sequence    */
+#define TSC_XF_DMA_OUT_DIRECT   0x06	/* DMA Xfer Infomation out      */
+#define TSC_XF_DMA_IN_DIRECT    0x86	/* DMA Xfer Infomation in       */
+
+#define TSC_XF_DMA_OUT  0x43	/* DMA Xfer Infomation out              */
+#define TSC_XF_DMA_IN   0xC3	/* DMA Xfer Infomation in               */
+#define TSC_XF_FIFO_OUT 0x03	/* FIFO Xfer Infomation out             */
+#define TSC_XF_FIFO_IN  0x83	/* FIFO Xfer Infomation in              */
+
+#define TSC_MSG_ACCEPT  0x0F	/* Message Accept                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 0 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_SEQ     0x20	/* Reset sequence counter               */
+#define TSC_FLUSH_FIFO  0x10	/* Flush FIFO                           */
+#define TSC_ABT_CMD     0x04	/* Abort command (sequence)             */
+#define TSC_RST_CHIP    0x02	/* Reset SCSI Chip                      */
+#define TSC_RST_BUS     0x01	/* Reset SCSI Bus                       */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Control 1 Register                     */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_SCAM     0x80	/* Enable SCAM                          */
+#define TSC_TIMER       0x40	/* Select timeout unit                  */
+#define TSC_EN_SCSI2    0x20	/* SCSI-2 mode                          */
+#define TSC_PWDN        0x10	/* Power down mode                      */
+#define TSC_WIDE_CPU    0x08	/* Wide CPU                             */
+#define TSC_HW_RESELECT 0x04	/* Enable HW reselect                   */
+#define TSC_EN_BUS_OUT  0x02	/* Enable SCSI data bus out latch       */
+#define TSC_EN_BUS_IN   0x01	/* Enable SCSI data bus in latch        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Configuration Register                 */
+/*----------------------------------------------------------------------*/
+#define TSC_EN_LATCH    0x80	/* Enable phase latch                   */
+#define TSC_INITIATOR   0x40	/* Initiator mode                       */
+#define TSC_EN_SCSI_PAR 0x20	/* Enable SCSI parity                   */
+#define TSC_DMA_8BIT    0x10	/* Alternate dma 8-bits mode            */
+#define TSC_DMA_16BIT   0x08	/* Alternate dma 16-bits mode           */
+#define TSC_EN_WDACK    0x04	/* Enable DACK while wide SCSI xfer     */
+#define TSC_ALT_PERIOD  0x02	/* Alternate sync period mode           */
+#define TSC_DIS_SCSIRST 0x01	/* Disable SCSI bus reset us            */
+
+#define TSC_INITDEFAULT (TSC_INITIATOR | TSC_EN_LATCH | TSC_ALT_PERIOD | TSC_DIS_SCSIRST)
+
+#define TSC_WIDE_SCSI   0x80	/* Enable Wide SCSI                     */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI signal Register                        */
+/*----------------------------------------------------------------------*/
+#define TSC_RST_ACK     0x00	/* Release ACK signal                   */
+#define TSC_RST_ATN     0x00	/* Release ATN signal                   */
+#define TSC_RST_BSY     0x00	/* Release BSY signal                   */
+
+#define TSC_SET_ACK     0x40	/* ACK signal                           */
+#define TSC_SET_ATN     0x08	/* ATN signal                           */
+
+#define TSC_REQI        0x80	/* REQ signal                           */
+#define TSC_ACKI        0x40	/* ACK signal                           */
+#define TSC_BSYI        0x20	/* BSY signal                           */
+#define TSC_SELI        0x10	/* SEL signal                           */
+#define TSC_ATNI        0x08	/* ATN signal                           */
+#define TSC_MSGI        0x04	/* MSG signal                           */
+#define TSC_CDI         0x02	/* C/D signal                           */
+#define TSC_IOI         0x01	/* I/O signal                           */
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 0 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_INT_PENDING 0x80	/* Interrupt pending            */
+#define TSS_SEQ_ACTIVE  0x40	/* Sequencer active             */
+#define TSS_XFER_CNT    0x20	/* Transfer counter zero        */
+#define TSS_FIFO_EMPTY  0x10	/* FIFO empty                   */
+#define TSS_PAR_ERROR   0x08	/* SCSI parity error            */
+#define TSS_PH_MASK     0x07	/* SCSI phase mask              */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 1 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_STATUS_RCV  0x08	/* Status received              */
+#define TSS_MSG_SEND    0x40	/* Message sent                 */
+#define TSS_CMD_PH_CMP  0x20	/* command phase done              */
+#define TSS_DATA_PH_CMP 0x10	/* Data phase done              */
+#define TSS_STATUS_SEND 0x08	/* Status sent                  */
+#define TSS_XFER_CMP    0x04	/* Transfer completed           */
+#define TSS_SEL_CMP     0x02	/* Selection completed          */
+#define TSS_ARB_CMP     0x01	/* Arbitration completed        */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Status 2 Register                      */
+/*----------------------------------------------------------------------*/
+#define TSS_CMD_ABTED   0x80	/* Command aborted              */
+#define TSS_OFFSET_0    0x40	/* Offset counter zero          */
+#define TSS_FIFO_FULL   0x20	/* FIFO full                    */
+#define TSS_TIMEOUT_0   0x10	/* Timeout counter zero         */
+#define TSS_BUSY_RLS    0x08	/* Busy release                 */
+#define TSS_PH_MISMATCH 0x04	/* Phase mismatch               */
+#define TSS_SCSI_BUS_EN 0x02	/* SCSI data bus enable         */
+#define TSS_SCSIRST     0x01	/* SCSI bus reset in progress   */
+
+/*----------------------------------------------------------------------*/
+/* bit definition for Tulip SCSI Interrupt Register                     */
+/*----------------------------------------------------------------------*/
+#define TSS_RESEL_INT   0x80	/* Reselected interrupt         */
+#define TSS_SEL_TIMEOUT 0x40	/* Selected/reselected timeout  */
+#define TSS_BUS_SERV    0x20
+#define TSS_SCSIRST_INT 0x10	/* SCSI bus reset detected      */
+#define TSS_DISC_INT    0x08	/* Disconnected interrupt       */
+#define TSS_SEL_INT     0x04	/* Select interrupt             */
+#define TSS_SCAM_SEL    0x02	/* SCAM selected                */
+#define TSS_FUNC_COMP   0x01
+
+/*----------------------------------------------------------------------*/
+/* SCSI Phase Codes.                                                    */
+/*----------------------------------------------------------------------*/
+#define DATA_OUT        0
+#define DATA_IN         1	/* 4                            */
+#define CMD_OUT         2
+#define STATUS_IN       3	/* 6                            */
+#define MSG_OUT         6	/* 3                            */
+#define MSG_IN          7
+
+
+
+/*----------------------------------------------------------------------*/
+/* Command Codes of Tulip xfer Command register                         */
+/*----------------------------------------------------------------------*/
+#define TAX_X_FORC      0x02
+#define TAX_X_ABT       0x04
+#define TAX_X_CLR_FIFO  0x08
+
+#define TAX_X_IN        0x21
+#define TAX_X_OUT       0x01
+#define TAX_SG_IN       0xA1
+#define TAX_SG_OUT      0x81
+
+/*----------------------------------------------------------------------*/
+/* Tulip Interrupt Register                                             */
+/*----------------------------------------------------------------------*/
+#define XCMP            0x01
+#define FCMP            0x02
+#define XABT            0x04
+#define XERR            0x08
+#define SCMP            0x10
+#define IPEND           0x80
+
+/*----------------------------------------------------------------------*/
+/* Tulip DMA Status Register                                            */
+/*----------------------------------------------------------------------*/
+#define XPEND           0x01	/* Transfer pending             */
+#define FEMPTY          0x02	/* FIFO empty                   */
+
+
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_GCTRL                                         */
+/*----------------------------------------------------------------------*/
+#define EXTSG           0x80
+#define EXTAD           0x60
+#define SEG4K           0x08
+#define EEPRG           0x04
+#define MRMUL           0x02
+
+/*----------------------------------------------------------------------*/
+/* bit definition for TUL_NVRAM                                         */
+/*----------------------------------------------------------------------*/
+#define SE2CS           0x08
+#define SE2CLK          0x04
+#define SE2DO           0x02
+#define SE2DI           0x01
+
+
+/************************************************************************/
+/*              Scatter-Gather Element Structure                        */
+/************************************************************************/
+typedef struct SG_Struc {
+	U32 SG_Ptr;		/* Data Pointer */
+	U32 SG_Len;		/* Data Length */
+} SG;
+
+/***********************************************************************
+		SCSI Control Block
+************************************************************************/
+typedef struct Scsi_Ctrl_Blk {
+	struct Scsi_Ctrl_Blk *SCB_NxtScb;
+	UBYTE SCB_Status;	/*4 */
+	UBYTE SCB_NxtStat;	/*5 */
+	UBYTE SCB_Mode;		/*6 */
+	UBYTE SCB_Msgin;	/*7 SCB_Res0 */
+	UWORD SCB_SGIdx;	/*8 */
+	UWORD SCB_SGMax;	/*A */
+#ifdef ALPHA
+	U32 SCB_Reserved[2];	/*C */
+#else
+	U32 SCB_Reserved[3];	/*C */
+#endif
+
+	U32 SCB_XferLen;	/*18 Current xfer len           */
+	U32 SCB_TotXLen;	/*1C Total xfer len             */
+	U32 SCB_PAddr;		/*20 SCB phy. Addr. */
+
+	UBYTE SCB_Opcode;	/*24 SCB command code */
+	UBYTE SCB_Flags;	/*25 SCB Flags */
+	UBYTE SCB_Target;	/*26 Target Id */
+	UBYTE SCB_Lun;		/*27 Lun */
+	U32 SCB_BufPtr;		/*28 Data Buffer Pointer */
+	U32 SCB_BufLen;		/*2C Data Allocation Length */
+	UBYTE SCB_SGLen;	/*30 SG list # */
+	UBYTE SCB_SenseLen;	/*31 Sense Allocation Length */
+	UBYTE SCB_HaStat;	/*32 */
+	UBYTE SCB_TaStat;	/*33 */
+	UBYTE SCB_CDBLen;	/*34 CDB Length */
+	UBYTE SCB_Ident;	/*35 Identify */
+	UBYTE SCB_TagMsg;	/*36 Tag Message */
+	UBYTE SCB_TagId;	/*37 Queue Tag */
+	UBYTE SCB_CDB[12];	/*38 */
+	U32 SCB_SGPAddr;	/*44 SG List/Sense Buf phy. Addr. */
+	U32 SCB_SensePtr;	/*48 Sense data pointer */
+	void (*SCB_Post) (BYTE *, BYTE *);	/*4C POST routine */
+	struct scsi_cmnd *SCB_Srb;	/*50 SRB Pointer */
+	SG SCB_SGList[TOTAL_SG_ENTRY];	/*54 Start of SG list */
+} SCB;
+
+/* Bit Definition for SCB_Status */
+#define SCB_RENT        0x01
+#define SCB_PEND        0x02
+#define SCB_CONTIG      0x04	/* Contigent Allegiance */
+#define SCB_SELECT      0x08
+#define SCB_BUSY        0x10
+#define SCB_DONE        0x20
+
+
+/* Opcodes of SCB_Opcode */
+#define ExecSCSI        0x1
+#define BusDevRst       0x2
+#define AbortCmd        0x3
+
+
+/* Bit Definition for SCB_Mode */
+#define SCM_RSENS       0x01	/* request sense mode */
+
+
+/* Bit Definition for SCB_Flags */
+#define SCF_DONE        0x01
+#define SCF_POST        0x02
+#define SCF_SENSE       0x04
+#define SCF_DIR         0x18
+#define SCF_NO_DCHK     0x00
+#define SCF_DIN         0x08
+#define SCF_DOUT        0x10
+#define SCF_NO_XF       0x18
+#define SCF_WR_VF       0x20	/* Write verify turn on         */
+#define SCF_POLL        0x40
+#define SCF_SG          0x80
+
+/* Error Codes for SCB_HaStat */
+#define HOST_SEL_TOUT   0x11
+#define HOST_DO_DU      0x12
+#define HOST_BUS_FREE   0x13
+#define HOST_BAD_PHAS   0x14
+#define HOST_INV_CMD    0x16
+#define HOST_ABORTED    0x1A	/* 07/21/98 */
+#define HOST_SCSI_RST   0x1B
+#define HOST_DEV_RST    0x1C
+
+/* Error Codes for SCB_TaStat */
+#define TARGET_CHKCOND  0x02
+#define TARGET_BUSY     0x08
+#define INI_QUEUE_FULL	0x28
+
+/* SCSI MESSAGE */
+#define MSG_COMP        0x00
+#define MSG_EXTEND      0x01
+#define MSG_SDP         0x02
+#define MSG_RESTORE     0x03
+#define MSG_DISC        0x04
+#define MSG_IDE         0x05
+#define MSG_ABORT       0x06
+#define MSG_REJ         0x07
+#define MSG_NOP         0x08
+#define MSG_PARITY      0x09
+#define MSG_LINK_COMP   0x0A
+#define MSG_LINK_FLAG   0x0B
+#define MSG_DEVRST      0x0C
+#define MSG_ABORT_TAG   0x0D
+
+/* Queue tag msg: Simple_quque_tag, Head_of_queue_tag, Ordered_queue_tag */
+#define MSG_STAG        0x20
+#define MSG_HTAG        0x21
+#define MSG_OTAG        0x22
+
+#define MSG_IGNOREWIDE  0x23
+
+#define MSG_IDENT   0x80
+
+/***********************************************************************
+		Target Device Control Structure
+**********************************************************************/
+
+typedef struct Tar_Ctrl_Struc {
+	UWORD TCS_Flags;	/* 0 */
+	UBYTE TCS_JS_Period;	/* 2 */
+	UBYTE TCS_SConfig0;	/* 3 */
+
+	UWORD TCS_DrvFlags;	/* 4 */
+	UBYTE TCS_DrvHead;	/* 6 */
+	UBYTE TCS_DrvSector;	/* 7 */
+} TCS;
+
+/***********************************************************************
+		Target Device Control Structure
+**********************************************************************/
+
+/* Bit Definition for TCF_Flags */
+#define TCF_SCSI_RATE           0x0007
+#define TCF_EN_DISC             0x0008
+#define TCF_NO_SYNC_NEGO        0x0010
+#define TCF_NO_WDTR             0x0020
+#define TCF_EN_255              0x0040
+#define TCF_EN_START            0x0080
+#define TCF_WDTR_DONE           0x0100
+#define TCF_SYNC_DONE           0x0200
+#define TCF_BUSY                0x0400
+
+
+/* Bit Definition for TCF_DrvFlags */
+#define TCF_DRV_BUSY            0x01	/* Indicate target busy(driver) */
+#define TCF_DRV_EN_TAG          0x0800
+#define TCF_DRV_255_63          0x0400
+
+typedef struct I91u_Adpt_Struc {
+	UWORD ADPT_BIOS;	/* 0 */
+	UWORD ADPT_BASE;	/* 1 */
+	UBYTE ADPT_Bus;		/* 2 */
+	UBYTE ADPT_Device;	/* 3 */
+	UBYTE ADPT_INTR;	/* 4 */
+} INI_ADPT_STRUCT;
+
+
+/***********************************************************************
+	      Host Adapter Control Structure
+************************************************************************/
+typedef struct Ha_Ctrl_Struc {
+	UWORD HCS_Base;		/* 00 */
+	UWORD HCS_BIOS;		/* 02 */
+	UBYTE HCS_Intr;		/* 04 */
+	UBYTE HCS_SCSI_ID;	/* 05 */
+	UBYTE HCS_MaxTar;	/* 06 */
+	UBYTE HCS_NumScbs;	/* 07 */
+
+	UBYTE HCS_Flags;	/* 08 */
+	UBYTE HCS_Index;	/* 09 */
+	UBYTE HCS_HaId;		/* 0A */
+	UBYTE HCS_Config;	/* 0B */
+	UWORD HCS_IdMask;	/* 0C */
+	UBYTE HCS_Semaph;	/* 0E */
+	UBYTE HCS_Phase;	/* 0F */
+	UBYTE HCS_JSStatus0;	/* 10 */
+	UBYTE HCS_JSInt;	/* 11 */
+	UBYTE HCS_JSStatus1;	/* 12 */
+	UBYTE HCS_SConf1;	/* 13 */
+
+	UBYTE HCS_Msg[8];	/* 14 */
+	SCB *HCS_NxtAvail;	/* 1C */
+	SCB *HCS_Scb;		/* 20 */
+	SCB *HCS_ScbEnd;	/* 24 */
+	SCB *HCS_NxtPend;	/* 28 */
+	SCB *HCS_NxtContig;	/* 2C */
+	SCB *HCS_ActScb;	/* 30 */
+	TCS *HCS_ActTcs;	/* 34 */
+
+	SCB *HCS_FirstAvail;	/* 38 */
+	SCB *HCS_LastAvail;	/* 3C */
+	SCB *HCS_FirstPend;	/* 40 */
+	SCB *HCS_LastPend;	/* 44 */
+	SCB *HCS_FirstBusy;	/* 48 */
+	SCB *HCS_LastBusy;	/* 4C */
+	SCB *HCS_FirstDone;	/* 50 */
+	SCB *HCS_LastDone;	/* 54 */
+	UBYTE HCS_MaxTags[16];	/* 58 */
+	UBYTE HCS_ActTags[16];	/* 68 */
+	TCS HCS_Tcs[MAX_TARGETS];	/* 78 */
+	spinlock_t HCS_AvailLock;
+	spinlock_t HCS_SemaphLock;
+	struct pci_dev *pci_dev;
+} HCS;
+
+/* Bit Definition for HCB_Config */
+#define HCC_SCSI_RESET          0x01
+#define HCC_EN_PAR              0x02
+#define HCC_ACT_TERM1           0x04
+#define HCC_ACT_TERM2           0x08
+#define HCC_AUTO_TERM           0x10
+#define HCC_EN_PWR              0x80
+
+/* Bit Definition for HCB_Flags */
+#define HCF_EXPECT_DISC         0x01
+#define HCF_EXPECT_SELECT       0x02
+#define HCF_EXPECT_RESET        0x10
+#define HCF_EXPECT_DONE_DISC    0x20
+
+/******************************************************************
+	Serial EEProm
+*******************************************************************/
+
+typedef struct _NVRAM_SCSI {	/* SCSI channel configuration   */
+	UCHAR NVM_ChSCSIID;	/* 0Ch -> Channel SCSI ID       */
+	UCHAR NVM_ChConfig1;	/* 0Dh -> Channel config 1      */
+	UCHAR NVM_ChConfig2;	/* 0Eh -> Channel config 2      */
+	UCHAR NVM_NumOfTarg;	/* 0Fh -> Number of SCSI target */
+	/* SCSI target configuration    */
+	UCHAR NVM_Targ0Config;	/* 10h -> Target 0 configuration */
+	UCHAR NVM_Targ1Config;	/* 11h -> Target 1 configuration */
+	UCHAR NVM_Targ2Config;	/* 12h -> Target 2 configuration */
+	UCHAR NVM_Targ3Config;	/* 13h -> Target 3 configuration */
+	UCHAR NVM_Targ4Config;	/* 14h -> Target 4 configuration */
+	UCHAR NVM_Targ5Config;	/* 15h -> Target 5 configuration */
+	UCHAR NVM_Targ6Config;	/* 16h -> Target 6 configuration */
+	UCHAR NVM_Targ7Config;	/* 17h -> Target 7 configuration */
+	UCHAR NVM_Targ8Config;	/* 18h -> Target 8 configuration */
+	UCHAR NVM_Targ9Config;	/* 19h -> Target 9 configuration */
+	UCHAR NVM_TargAConfig;	/* 1Ah -> Target A configuration */
+	UCHAR NVM_TargBConfig;	/* 1Bh -> Target B configuration */
+	UCHAR NVM_TargCConfig;	/* 1Ch -> Target C configuration */
+	UCHAR NVM_TargDConfig;	/* 1Dh -> Target D configuration */
+	UCHAR NVM_TargEConfig;	/* 1Eh -> Target E configuration */
+	UCHAR NVM_TargFConfig;	/* 1Fh -> Target F configuration */
+} NVRAM_SCSI;
+
+typedef struct _NVRAM {
+/*----------header ---------------*/
+	USHORT NVM_Signature;	/* 0,1: Signature */
+	UCHAR NVM_Size;		/* 2:   Size of data structure */
+	UCHAR NVM_Revision;	/* 3:   Revision of data structure */
+	/* ----Host Adapter Structure ---- */
+	UCHAR NVM_ModelByte0;	/* 4:   Model number (byte 0) */
+	UCHAR NVM_ModelByte1;	/* 5:   Model number (byte 1) */
+	UCHAR NVM_ModelInfo;	/* 6:   Model information         */
+	UCHAR NVM_NumOfCh;	/* 7:   Number of SCSI channel */
+	UCHAR NVM_BIOSConfig1;	/* 8:   BIOS configuration 1  */
+	UCHAR NVM_BIOSConfig2;	/* 9:   BIOS configuration 2  */
+	UCHAR NVM_HAConfig1;	/* A:   Hoat adapter configuration 1 */
+	UCHAR NVM_HAConfig2;	/* B:   Hoat adapter configuration 2 */
+	NVRAM_SCSI NVM_SCSIInfo[2];
+	UCHAR NVM_reserved[10];
+	/* ---------- CheckSum ----------       */
+	USHORT NVM_CheckSum;	/* 0x3E, 0x3F: Checksum of NVRam        */
+} NVRAM, *PNVRAM;
+
+/* Bios Configuration for nvram->BIOSConfig1                            */
+#define NBC1_ENABLE             0x01	/* BIOS enable                  */
+#define NBC1_8DRIVE             0x02	/* Support more than 2 drives   */
+#define NBC1_REMOVABLE          0x04	/* Support removable drive      */
+#define NBC1_INT19              0x08	/* Intercept int 19h            */
+#define NBC1_BIOSSCAN           0x10	/* Dynamic BIOS scan            */
+#define NBC1_LUNSUPPORT         0x40	/* Support LUN                  */
+
+/* HA Configuration Byte 1                                              */
+#define NHC1_BOOTIDMASK 0x0F	/* Boot ID number               */
+#define NHC1_LUNMASK    0x70	/* Boot LUN number              */
+#define NHC1_CHANMASK   0x80	/* Boot Channel number          */
+
+/* Bit definition for nvram->SCSIconfig1                                */
+#define NCC1_BUSRESET           0x01	/* Reset SCSI bus at power up   */
+#define NCC1_PARITYCHK          0x02	/* SCSI parity enable           */
+#define NCC1_ACTTERM1           0x04	/* Enable active terminator 1   */
+#define NCC1_ACTTERM2           0x08	/* Enable active terminator 2   */
+#define NCC1_AUTOTERM           0x10	/* Enable auto terminator       */
+#define NCC1_PWRMGR             0x80	/* Enable power management      */
+
+/* Bit definition for SCSI Target configuration byte                    */
+#define NTC_DISCONNECT          0x08	/* Enable SCSI disconnect       */
+#define NTC_SYNC                0x10	/* SYNC_NEGO                    */
+#define NTC_NO_WDTR             0x20	/* SYNC_NEGO                    */
+#define NTC_1GIGA               0x40	/* 255 head / 63 sectors (64/32) */
+#define NTC_SPINUP              0x80	/* Start disk drive             */
+
+/*      Default NVRam values                                            */
+#define INI_SIGNATURE           0xC925
+#define NBC1_DEFAULT            (NBC1_ENABLE)
+#define NCC1_DEFAULT            (NCC1_BUSRESET | NCC1_AUTOTERM | NCC1_PARITYCHK)
+#define NTC_DEFAULT             (NTC_NO_WDTR | NTC_1GIGA | NTC_DISCONNECT)
+
+/* SCSI related definition                                              */
+#define DISC_NOT_ALLOW          0x80	/* Disconnect is not allowed    */
+#define DISC_ALLOW              0xC0	/* Disconnect is allowed        */
+#define SCSICMD_RequestSense    0x03
+
+typedef struct _HCSinfo {
+	ULONG base;
+	UCHAR vec;
+	UCHAR bios;		/* High byte of BIOS address */
+	USHORT BaseAndBios;	/* high byte: pHcsInfo->bios,low byte:pHcsInfo->base */
+} HCSINFO;
+
+#define TUL_RD(x,y)             (UCHAR)(inb(  (int)((ULONG)(x+y)) ))
+#define TUL_RDLONG(x,y)         (ULONG)(inl((int)((ULONG)(x+y)) ))
+#define TUL_WR(     adr,data)   outb( (UCHAR)(data), (int)(adr))
+#define TUL_WRSHORT(adr,data)   outw( (UWORD)(data), (int)(adr))
+#define TUL_WRLONG( adr,data)   outl( (ULONG)(data), (int)(adr))
+
+#define SCSI_ABORT_SNOOZE 0
+#define SCSI_ABORT_SUCCESS 1
+#define SCSI_ABORT_PENDING 2
+#define SCSI_ABORT_BUSY 3
+#define SCSI_ABORT_NOT_RUNNING 4
+#define SCSI_ABORT_ERROR 5
+
+#define SCSI_RESET_SNOOZE 0
+#define SCSI_RESET_PUNT 1
+#define SCSI_RESET_SUCCESS 2
+#define SCSI_RESET_PENDING 3
+#define SCSI_RESET_WAKEUP 4
+#define SCSI_RESET_NOT_RUNNING 5
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS		0x01
+#define SCSI_RESET_ASYNCHRONOUS		0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
+
+#define SCSI_RESET_BUS_RESET 0x100
+#define SCSI_RESET_HOST_RESET 0x200
+#define SCSI_RESET_ACTION   0xff
+
+extern void init_i91uAdapter_table(void);
+extern int Addi91u_into_Adapter_table(WORD, WORD, BYTE, BYTE, BYTE);
+extern int tul_ReturnNumberOfAdapters(void);
+extern void get_tulipPCIConfig(HCS * pHCB, int iChannel_index);
+extern int init_tulip(HCS * pHCB, SCB * pSCB, int tul_num_scb, BYTE * pbBiosAdr, int reset_time);
+extern SCB *tul_alloc_scb(HCS * pHCB);
+extern int tul_abort_srb(HCS * pHCB, struct scsi_cmnd * pSRB);
+extern void tul_exec_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_release_scb(HCS * pHCB, SCB * pSCB);
+extern void tul_stop_bm(HCS * pHCB);
+extern int tul_reset_scsi(HCS * pCurHcb, int seconds);
+extern int tul_isr(HCS * pHCB);
+extern int tul_reset(HCS * pHCB, struct scsi_cmnd * pSRB, unsigned char target);
+extern int tul_reset_scsi_bus(HCS * pCurHcb);
+extern int tul_device_reset(HCS * pCurHcb, struct scsi_cmnd *pSrb,
+		unsigned int target, unsigned int ResetFlags);
+				/* ---- EXTERNAL VARIABLES ---- */
+extern HCS tul_hcs[];
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
new file mode 100644
index 0000000..5441531
--- /dev/null
+++ b/drivers/scsi/ipr.c
@@ -0,0 +1,6083 @@
+/*
+ * ipr.c -- driver for IBM Power Linux RAID adapters
+ *
+ * Written By: Brian King <brking@us.ibm.com>, IBM Corporation
+ *
+ * Copyright (C) 2003, 2004 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+/*
+ * Notes:
+ *
+ * This driver is used to control the following SCSI adapters:
+ *
+ * IBM iSeries: 5702, 5703, 2780, 5709, 570A, 570B
+ *
+ * IBM pSeries: PCI-X Dual Channel Ultra 320 SCSI RAID Adapter
+ *              PCI-X Dual Channel Ultra 320 SCSI Adapter
+ *              PCI-X Dual Channel Ultra 320 SCSI RAID Enablement Card
+ *              Embedded SCSI adapter on p615 and p655 systems
+ *
+ * Supported Hardware Features:
+ *	- Ultra 320 SCSI controller
+ *	- PCI-X host interface
+ *	- Embedded PowerPC RISC Processor and Hardware XOR DMA Engine
+ *	- Non-Volatile Write Cache
+ *	- Supports attachment of non-RAID disks, tape, and optical devices
+ *	- RAID Levels 0, 5, 10
+ *	- Hot spare
+ *	- Background Parity Checking
+ *	- Background Data Scrubbing
+ *	- Ability to increase the capacity of an existing RAID 5 disk array
+ *		by adding disks
+ *
+ * Driver Features:
+ *	- Tagged command queuing
+ *	- Adapter microcode download
+ *	- PCI hot plug
+ *	- SCSI device hot plug
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/wait.h>
+#include <linux/spinlock.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/processor.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_request.h>
+#include "ipr.h"
+
+/*
+ *   Global Data
+ */
+static struct list_head ipr_ioa_head = LIST_HEAD_INIT(ipr_ioa_head);
+static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL;
+static unsigned int ipr_max_speed = 1;
+static int ipr_testmode = 0;
+static unsigned int ipr_fastfail = 0;
+static unsigned int ipr_transop_timeout = IPR_OPERATIONAL_TIMEOUT;
+static DEFINE_SPINLOCK(ipr_driver_lock);
+
+/* This table describes the differences between DMA controller chips */
+static const struct ipr_chip_cfg_t ipr_chip_cfg[] = {
+	{ /* Gemstone and Citrine */
+		.mailbox = 0x0042C,
+		.cache_line_size = 0x20,
+		{
+			.set_interrupt_mask_reg = 0x0022C,
+			.clr_interrupt_mask_reg = 0x00230,
+			.sense_interrupt_mask_reg = 0x0022C,
+			.clr_interrupt_reg = 0x00228,
+			.sense_interrupt_reg = 0x00224,
+			.ioarrin_reg = 0x00404,
+			.sense_uproc_interrupt_reg = 0x00214,
+			.set_uproc_interrupt_reg = 0x00214,
+			.clr_uproc_interrupt_reg = 0x00218
+		}
+	},
+	{ /* Snipe and Scamp */
+		.mailbox = 0x0052C,
+		.cache_line_size = 0x20,
+		{
+			.set_interrupt_mask_reg = 0x00288,
+			.clr_interrupt_mask_reg = 0x0028C,
+			.sense_interrupt_mask_reg = 0x00288,
+			.clr_interrupt_reg = 0x00284,
+			.sense_interrupt_reg = 0x00280,
+			.ioarrin_reg = 0x00504,
+			.sense_uproc_interrupt_reg = 0x00290,
+			.set_uproc_interrupt_reg = 0x00290,
+			.clr_uproc_interrupt_reg = 0x00294
+		}
+	},
+};
+
+static const struct ipr_chip_t ipr_chip[] = {
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE, &ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE, &ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP, &ipr_chip_cfg[1] }
+};
+
+static int ipr_max_bus_speeds [] = {
+	IPR_80MBs_SCSI_RATE, IPR_U160_SCSI_RATE, IPR_U320_SCSI_RATE
+};
+
+MODULE_AUTHOR("Brian King <brking@us.ibm.com>");
+MODULE_DESCRIPTION("IBM Power RAID SCSI Adapter Driver");
+module_param_named(max_speed, ipr_max_speed, uint, 0);
+MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320");
+module_param_named(log_level, ipr_log_level, uint, 0);
+MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver");
+module_param_named(testmode, ipr_testmode, int, 0);
+MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations");
+module_param_named(fastfail, ipr_fastfail, int, 0);
+MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries");
+module_param_named(transop_timeout, ipr_transop_timeout, int, 0);
+MODULE_PARM_DESC(transop_timeout, "Time in seconds to wait for adapter to come operational (default: 300)");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(IPR_DRIVER_VERSION);
+
+static const char *ipr_gpdd_dev_end_states[] = {
+	"Command complete",
+	"Terminated by host",
+	"Terminated by device reset",
+	"Terminated by bus reset",
+	"Unknown",
+	"Command not started"
+};
+
+static const char *ipr_gpdd_dev_bus_phases[] = {
+	"Bus free",
+	"Arbitration",
+	"Selection",
+	"Message out",
+	"Command",
+	"Message in",
+	"Data out",
+	"Data in",
+	"Status",
+	"Reselection",
+	"Unknown"
+};
+
+/*  A constant array of IOASCs/URCs/Error Messages */
+static const
+struct ipr_error_table_t ipr_error_table[] = {
+	{0x00000000, 1, 1,
+	"8155: An unknown error was received"},
+	{0x00330000, 0, 0,
+	"Soft underlength error"},
+	{0x005A0000, 0, 0,
+	"Command to be cancelled not found"},
+	{0x00808000, 0, 0,
+	"Qualified success"},
+	{0x01080000, 1, 1,
+	"FFFE: Soft device bus error recovered by the IOA"},
+	{0x01170600, 0, 1,
+	"FFF9: Device sector reassign successful"},
+	{0x01170900, 0, 1,
+	"FFF7: Media error recovered by device rewrite procedures"},
+	{0x01180200, 0, 1,
+	"7001: IOA sector reassignment successful"},
+	{0x01180500, 0, 1,
+	"FFF9: Soft media error. Sector reassignment recommended"},
+	{0x01180600, 0, 1,
+	"FFF7: Media error recovered by IOA rewrite procedures"},
+	{0x01418000, 0, 1,
+	"FF3D: Soft PCI bus error recovered by the IOA"},
+	{0x01440000, 1, 1,
+	"FFF6: Device hardware error recovered by the IOA"},
+	{0x01448100, 0, 1,
+	"FFF6: Device hardware error recovered by the device"},
+	{0x01448200, 1, 1,
+	"FF3D: Soft IOA error recovered by the IOA"},
+	{0x01448300, 0, 1,
+	"FFFA: Undefined device response recovered by the IOA"},
+	{0x014A0000, 1, 1,
+	"FFF6: Device bus error, message or command phase"},
+	{0x015D0000, 0, 1,
+	"FFF6: Failure prediction threshold exceeded"},
+	{0x015D9200, 0, 1,
+	"8009: Impending cache battery pack failure"},
+	{0x02040400, 0, 0,
+	"34FF: Disk device format in progress"},
+	{0x023F0000, 0, 0,
+	"Synchronization required"},
+	{0x024E0000, 0, 0,
+	"No ready, IOA shutdown"},
+	{0x025A0000, 0, 0,
+	"Not ready, IOA has been shutdown"},
+	{0x02670100, 0, 1,
+	"3020: Storage subsystem configuration error"},
+	{0x03110B00, 0, 0,
+	"FFF5: Medium error, data unreadable, recommend reassign"},
+	{0x03110C00, 0, 0,
+	"7000: Medium error, data unreadable, do not reassign"},
+	{0x03310000, 0, 1,
+	"FFF3: Disk media format bad"},
+	{0x04050000, 0, 1,
+	"3002: Addressed device failed to respond to selection"},
+	{0x04080000, 1, 1,
+	"3100: Device bus error"},
+	{0x04080100, 0, 1,
+	"3109: IOA timed out a device command"},
+	{0x04088000, 0, 0,
+	"3120: SCSI bus is not operational"},
+	{0x04118000, 0, 1,
+	"9000: IOA reserved area data check"},
+	{0x04118100, 0, 1,
+	"9001: IOA reserved area invalid data pattern"},
+	{0x04118200, 0, 1,
+	"9002: IOA reserved area LRC error"},
+	{0x04320000, 0, 1,
+	"102E: Out of alternate sectors for disk storage"},
+	{0x04330000, 1, 1,
+	"FFF4: Data transfer underlength error"},
+	{0x04338000, 1, 1,
+	"FFF4: Data transfer overlength error"},
+	{0x043E0100, 0, 1,
+	"3400: Logical unit failure"},
+	{0x04408500, 0, 1,
+	"FFF4: Device microcode is corrupt"},
+	{0x04418000, 1, 1,
+	"8150: PCI bus error"},
+	{0x04430000, 1, 0,
+	"Unsupported device bus message received"},
+	{0x04440000, 1, 1,
+	"FFF4: Disk device problem"},
+	{0x04448200, 1, 1,
+	"8150: Permanent IOA failure"},
+	{0x04448300, 0, 1,
+	"3010: Disk device returned wrong response to IOA"},
+	{0x04448400, 0, 1,
+	"8151: IOA microcode error"},
+	{0x04448500, 0, 0,
+	"Device bus status error"},
+	{0x04448600, 0, 1,
+	"8157: IOA error requiring IOA reset to recover"},
+	{0x04490000, 0, 0,
+	"Message reject received from the device"},
+	{0x04449200, 0, 1,
+	"8008: A permanent cache battery pack failure occurred"},
+	{0x0444A000, 0, 1,
+	"9090: Disk unit has been modified after the last known status"},
+	{0x0444A200, 0, 1,
+	"9081: IOA detected device error"},
+	{0x0444A300, 0, 1,
+	"9082: IOA detected device error"},
+	{0x044A0000, 1, 1,
+	"3110: Device bus error, message or command phase"},
+	{0x04670400, 0, 1,
+	"9091: Incorrect hardware configuration change has been detected"},
+	{0x046E0000, 0, 1,
+	"FFF4: Command to logical unit failed"},
+	{0x05240000, 1, 0,
+	"Illegal request, invalid request type or request packet"},
+	{0x05250000, 0, 0,
+	"Illegal request, invalid resource handle"},
+	{0x05260000, 0, 0,
+	"Illegal request, invalid field in parameter list"},
+	{0x05260100, 0, 0,
+	"Illegal request, parameter not supported"},
+	{0x05260200, 0, 0,
+	"Illegal request, parameter value invalid"},
+	{0x052C0000, 0, 0,
+	"Illegal request, command sequence error"},
+	{0x06040500, 0, 1,
+	"9031: Array protection temporarily suspended, protection resuming"},
+	{0x06040600, 0, 1,
+	"9040: Array protection temporarily suspended, protection resuming"},
+	{0x06290000, 0, 1,
+	"FFFB: SCSI bus was reset"},
+	{0x06290500, 0, 0,
+	"FFFE: SCSI bus transition to single ended"},
+	{0x06290600, 0, 0,
+	"FFFE: SCSI bus transition to LVD"},
+	{0x06298000, 0, 1,
+	"FFFB: SCSI bus was reset by another initiator"},
+	{0x063F0300, 0, 1,
+	"3029: A device replacement has occurred"},
+	{0x064C8000, 0, 1,
+	"9051: IOA cache data exists for a missing or failed device"},
+	{0x06670100, 0, 1,
+	"9025: Disk unit is not supported at its physical location"},
+	{0x06670600, 0, 1,
+	"3020: IOA detected a SCSI bus configuration error"},
+	{0x06678000, 0, 1,
+	"3150: SCSI bus configuration error"},
+	{0x06690200, 0, 1,
+	"9041: Array protection temporarily suspended"},
+	{0x06698200, 0, 1,
+	"9042: Corrupt array parity detected on specified device"},
+	{0x066B0200, 0, 1,
+	"9030: Array no longer protected due to missing or failed disk unit"},
+	{0x066B8200, 0, 1,
+	"9032: Array exposed but still protected"},
+	{0x07270000, 0, 0,
+	"Failure due to other device"},
+	{0x07278000, 0, 1,
+	"9008: IOA does not support functions expected by devices"},
+	{0x07278100, 0, 1,
+	"9010: Cache data associated with attached devices cannot be found"},
+	{0x07278200, 0, 1,
+	"9011: Cache data belongs to devices other than those attached"},
+	{0x07278400, 0, 1,
+	"9020: Array missing 2 or more devices with only 1 device present"},
+	{0x07278500, 0, 1,
+	"9021: Array missing 2 or more devices with 2 or more devices present"},
+	{0x07278600, 0, 1,
+	"9022: Exposed array is missing a required device"},
+	{0x07278700, 0, 1,
+	"9023: Array member(s) not at required physical locations"},
+	{0x07278800, 0, 1,
+	"9024: Array not functional due to present hardware configuration"},
+	{0x07278900, 0, 1,
+	"9026: Array not functional due to present hardware configuration"},
+	{0x07278A00, 0, 1,
+	"9027: Array is missing a device and parity is out of sync"},
+	{0x07278B00, 0, 1,
+	"9028: Maximum number of arrays already exist"},
+	{0x07278C00, 0, 1,
+	"9050: Required cache data cannot be located for a disk unit"},
+	{0x07278D00, 0, 1,
+	"9052: Cache data exists for a device that has been modified"},
+	{0x07278F00, 0, 1,
+	"9054: IOA resources not available due to previous problems"},
+	{0x07279100, 0, 1,
+	"9092: Disk unit requires initialization before use"},
+	{0x07279200, 0, 1,
+	"9029: Incorrect hardware configuration change has been detected"},
+	{0x07279600, 0, 1,
+	"9060: One or more disk pairs are missing from an array"},
+	{0x07279700, 0, 1,
+	"9061: One or more disks are missing from an array"},
+	{0x07279800, 0, 1,
+	"9062: One or more disks are missing from an array"},
+	{0x07279900, 0, 1,
+	"9063: Maximum number of functional arrays has been exceeded"},
+	{0x0B260000, 0, 0,
+	"Aborted command, invalid descriptor"},
+	{0x0B5A0000, 0, 0,
+	"Command terminated by host"}
+};
+
+static const struct ipr_ses_table_entry ipr_ses_table[] = {
+	{ "2104-DL1        ", "XXXXXXXXXXXXXXXX", 80 },
+	{ "2104-TL1        ", "XXXXXXXXXXXXXXXX", 80 },
+	{ "HSBP07M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 7 slot */
+	{ "HSBP05M P U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Hidive 5 slot */
+	{ "HSBP05M S U2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* Bowtie */
+	{ "HSBP06E ASU2SCSI", "XXXXXXXXXXXXXXXX", 80 }, /* MartinFenning */
+	{ "2104-DU3        ", "XXXXXXXXXXXXXXXX", 160 },
+	{ "2104-TU3        ", "XXXXXXXXXXXXXXXX", 160 },
+	{ "HSBP04C RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 },
+	{ "HSBP06E RSU2SCSI", "XXXXXXX*XXXXXXXX", 160 },
+	{ "St  V1S2        ", "XXXXXXXXXXXXXXXX", 160 },
+	{ "HSBPD4M  PU3SCSI", "XXXXXXX*XXXXXXXX", 160 },
+	{ "VSBPD1H   U3SCSI", "XXXXXXX*XXXXXXXX", 160 }
+};
+
+/*
+ *  Function Prototypes
+ */
+static int ipr_reset_alert(struct ipr_cmnd *);
+static void ipr_process_ccn(struct ipr_cmnd *);
+static void ipr_process_error(struct ipr_cmnd *);
+static void ipr_reset_ioa_job(struct ipr_cmnd *);
+static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *,
+				   enum ipr_shutdown_type);
+
+#ifdef CONFIG_SCSI_IPR_TRACE
+/**
+ * ipr_trc_hook - Add a trace entry to the driver trace
+ * @ipr_cmd:	ipr command struct
+ * @type:		trace type
+ * @add_data:	additional data
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_trc_hook(struct ipr_cmnd *ipr_cmd,
+			 u8 type, u32 add_data)
+{
+	struct ipr_trace_entry *trace_entry;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	trace_entry = &ioa_cfg->trace[ioa_cfg->trace_index++];
+	trace_entry->time = jiffies;
+	trace_entry->op_code = ipr_cmd->ioarcb.cmd_pkt.cdb[0];
+	trace_entry->type = type;
+	trace_entry->cmd_index = ipr_cmd->cmd_index;
+	trace_entry->res_handle = ipr_cmd->ioarcb.res_handle;
+	trace_entry->u.add_data = add_data;
+}
+#else
+#define ipr_trc_hook(ipr_cmd, type, add_data) do { } while(0)
+#endif
+
+/**
+ * ipr_reinit_ipr_cmnd - Re-initialize an IPR Cmnd block for reuse
+ * @ipr_cmd:	ipr command struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_reinit_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+
+	memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
+	ioarcb->write_data_transfer_length = 0;
+	ioarcb->read_data_transfer_length = 0;
+	ioarcb->write_ioadl_len = 0;
+	ioarcb->read_ioadl_len = 0;
+	ioasa->ioasc = 0;
+	ioasa->residual_data_len = 0;
+
+	ipr_cmd->scsi_cmd = NULL;
+	ipr_cmd->sense_buffer[0] = 0;
+	ipr_cmd->dma_use_sg = 0;
+}
+
+/**
+ * ipr_init_ipr_cmnd - Initialize an IPR Cmnd block
+ * @ipr_cmd:	ipr command struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_init_ipr_cmnd(struct ipr_cmnd *ipr_cmd)
+{
+	ipr_reinit_ipr_cmnd(ipr_cmd);
+	ipr_cmd->u.scratch = 0;
+	ipr_cmd->sibling = NULL;
+	init_timer(&ipr_cmd->timer);
+}
+
+/**
+ * ipr_get_free_ipr_cmnd - Get a free IPR Cmnd block
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	pointer to ipr command struct
+ **/
+static
+struct ipr_cmnd *ipr_get_free_ipr_cmnd(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_cmnd *ipr_cmd;
+
+	ipr_cmd = list_entry(ioa_cfg->free_q.next, struct ipr_cmnd, queue);
+	list_del(&ipr_cmd->queue);
+	ipr_init_ipr_cmnd(ipr_cmd);
+
+	return ipr_cmd;
+}
+
+/**
+ * ipr_unmap_sglist - Unmap scatterlist if mapped
+ * @ioa_cfg:	ioa config struct
+ * @ipr_cmd:	ipr command struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_unmap_sglist(struct ipr_ioa_cfg *ioa_cfg,
+			     struct ipr_cmnd *ipr_cmd)
+{
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+
+	if (ipr_cmd->dma_use_sg) {
+		if (scsi_cmd->use_sg > 0) {
+			pci_unmap_sg(ioa_cfg->pdev, scsi_cmd->request_buffer,
+				     scsi_cmd->use_sg,
+				     scsi_cmd->sc_data_direction);
+		} else {
+			pci_unmap_single(ioa_cfg->pdev, ipr_cmd->dma_handle,
+					 scsi_cmd->request_bufflen,
+					 scsi_cmd->sc_data_direction);
+		}
+	}
+}
+
+/**
+ * ipr_mask_and_clear_interrupts - Mask all and clear specified interrupts
+ * @ioa_cfg:	ioa config struct
+ * @clr_ints:     interrupts to clear
+ *
+ * This function masks all interrupts on the adapter, then clears the
+ * interrupts specified in the mask
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_mask_and_clear_interrupts(struct ipr_ioa_cfg *ioa_cfg,
+					  u32 clr_ints)
+{
+	volatile u32 int_reg;
+
+	/* Stop new interrupts */
+	ioa_cfg->allow_interrupts = 0;
+
+	/* Set interrupt mask to stop all new interrupts */
+	writel(~0, ioa_cfg->regs.set_interrupt_mask_reg);
+
+	/* Clear any pending interrupts */
+	writel(clr_ints, ioa_cfg->regs.clr_interrupt_reg);
+	int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+}
+
+/**
+ * ipr_save_pcix_cmd_reg - Save PCI-X command register
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	0 on success / -EIO on failure
+ **/
+static int ipr_save_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
+
+	if (pcix_cmd_reg == 0) {
+		dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");
+		return -EIO;
+	}
+
+	if (pci_read_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
+				 &ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
+		dev_err(&ioa_cfg->pdev->dev, "Failed to save PCI-X command register\n");
+		return -EIO;
+	}
+
+	ioa_cfg->saved_pcix_cmd_reg |= PCI_X_CMD_DPERR_E | PCI_X_CMD_ERO;
+	return 0;
+}
+
+/**
+ * ipr_set_pcix_cmd_reg - Setup PCI-X command register
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	0 on success / -EIO on failure
+ **/
+static int ipr_set_pcix_cmd_reg(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int pcix_cmd_reg = pci_find_capability(ioa_cfg->pdev, PCI_CAP_ID_PCIX);
+
+	if (pcix_cmd_reg) {
+		if (pci_write_config_word(ioa_cfg->pdev, pcix_cmd_reg + PCI_X_CMD,
+					  ioa_cfg->saved_pcix_cmd_reg) != PCIBIOS_SUCCESSFUL) {
+			dev_err(&ioa_cfg->pdev->dev, "Failed to setup PCI-X command register\n");
+			return -EIO;
+		}
+	} else {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Failed to setup PCI-X command register\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * ipr_scsi_eh_done - mid-layer done function for aborted ops
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer which are being aborted.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_scsi_eh_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+
+	scsi_cmd->result |= (DID_ERROR << 16);
+
+	ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+	scsi_cmd->scsi_done(scsi_cmd);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+}
+
+/**
+ * ipr_fail_all_ops - Fails all outstanding ops.
+ * @ioa_cfg:	ioa config struct
+ *
+ * This function fails all outstanding ops.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_fail_all_ops(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_cmnd *ipr_cmd, *temp;
+
+	ENTER;
+	list_for_each_entry_safe(ipr_cmd, temp, &ioa_cfg->pending_q, queue) {
+		list_del(&ipr_cmd->queue);
+
+		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_IOA_WAS_RESET);
+		ipr_cmd->ioasa.ilid = cpu_to_be32(IPR_DRIVER_ILID);
+
+		if (ipr_cmd->scsi_cmd)
+			ipr_cmd->done = ipr_scsi_eh_done;
+
+		ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, IPR_IOASC_IOA_WAS_RESET);
+		del_timer(&ipr_cmd->timer);
+		ipr_cmd->done(ipr_cmd);
+	}
+
+	LEAVE;
+}
+
+/**
+ * ipr_do_req -  Send driver initiated requests.
+ * @ipr_cmd:		ipr command struct
+ * @done:			done function
+ * @timeout_func:	timeout function
+ * @timeout:		timeout value
+ *
+ * This function sends the specified command to the adapter with the
+ * timeout given. The done function is invoked on command completion.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_do_req(struct ipr_cmnd *ipr_cmd,
+		       void (*done) (struct ipr_cmnd *),
+		       void (*timeout_func) (struct ipr_cmnd *), u32 timeout)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+
+	ipr_cmd->done = done;
+
+	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
+	ipr_cmd->timer.expires = jiffies + timeout;
+	ipr_cmd->timer.function = (void (*)(unsigned long))timeout_func;
+
+	add_timer(&ipr_cmd->timer);
+
+	ipr_trc_hook(ipr_cmd, IPR_TRACE_START, 0);
+
+	mb();
+	writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
+	       ioa_cfg->regs.ioarrin_reg);
+}
+
+/**
+ * ipr_internal_cmd_done - Op done function for an internally generated op.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is the op done function for an internally generated,
+ * blocking op. It simply wakes the sleeping thread.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_internal_cmd_done(struct ipr_cmnd *ipr_cmd)
+{
+	if (ipr_cmd->sibling)
+		ipr_cmd->sibling = NULL;
+	else
+		complete(&ipr_cmd->completion);
+}
+
+/**
+ * ipr_send_blocking_cmd - Send command and sleep on its completion.
+ * @ipr_cmd:	ipr command struct
+ * @timeout_func:	function to invoke if command times out
+ * @timeout:	timeout
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_send_blocking_cmd(struct ipr_cmnd *ipr_cmd,
+				  void (*timeout_func) (struct ipr_cmnd *ipr_cmd),
+				  u32 timeout)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	init_completion(&ipr_cmd->completion);
+	ipr_do_req(ipr_cmd, ipr_internal_cmd_done, timeout_func, timeout);
+
+	spin_unlock_irq(ioa_cfg->host->host_lock);
+	wait_for_completion(&ipr_cmd->completion);
+	spin_lock_irq(ioa_cfg->host->host_lock);
+}
+
+/**
+ * ipr_send_hcam - Send an HCAM to the adapter.
+ * @ioa_cfg:	ioa config struct
+ * @type:		HCAM type
+ * @hostrcb:	hostrcb struct
+ *
+ * This function will send a Host Controlled Async command to the adapter.
+ * If HCAMs are currently not allowed to be issued to the adapter, it will
+ * place the hostrcb on the free queue.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_send_hcam(struct ipr_ioa_cfg *ioa_cfg, u8 type,
+			  struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_cmnd *ipr_cmd;
+	struct ipr_ioarcb *ioarcb;
+
+	if (ioa_cfg->allow_cmds) {
+		ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+		list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_pending_q);
+
+		ipr_cmd->u.hostrcb = hostrcb;
+		ioarcb = &ipr_cmd->ioarcb;
+
+		ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+		ioarcb->cmd_pkt.request_type = IPR_RQTYPE_HCAM;
+		ioarcb->cmd_pkt.cdb[0] = IPR_HOST_CONTROLLED_ASYNC;
+		ioarcb->cmd_pkt.cdb[1] = type;
+		ioarcb->cmd_pkt.cdb[7] = (sizeof(hostrcb->hcam) >> 8) & 0xff;
+		ioarcb->cmd_pkt.cdb[8] = sizeof(hostrcb->hcam) & 0xff;
+
+		ioarcb->read_data_transfer_length = cpu_to_be32(sizeof(hostrcb->hcam));
+		ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+		ipr_cmd->ioadl[0].flags_and_data_len =
+			cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(hostrcb->hcam));
+		ipr_cmd->ioadl[0].address = cpu_to_be32(hostrcb->hostrcb_dma);
+
+		if (type == IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE)
+			ipr_cmd->done = ipr_process_ccn;
+		else
+			ipr_cmd->done = ipr_process_error;
+
+		ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_IOA_RES_ADDR);
+
+		mb();
+		writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
+		       ioa_cfg->regs.ioarrin_reg);
+	} else {
+		list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
+	}
+}
+
+/**
+ * ipr_init_res_entry - Initialize a resource entry struct.
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_init_res_entry(struct ipr_resource_entry *res)
+{
+	res->needs_sync_complete = 1;
+	res->in_erp = 0;
+	res->add_to_ml = 0;
+	res->del_from_ml = 0;
+	res->resetting_device = 0;
+	res->sdev = NULL;
+}
+
+/**
+ * ipr_handle_config_change - Handle a config change from the adapter
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_handle_config_change(struct ipr_ioa_cfg *ioa_cfg,
+			      struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_resource_entry *res = NULL;
+	struct ipr_config_table_entry *cfgte;
+	u32 is_ndn = 1;
+
+	cfgte = &hostrcb->hcam.u.ccn.cfgte;
+
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (!memcmp(&res->cfgte.res_addr, &cfgte->res_addr,
+			    sizeof(cfgte->res_addr))) {
+			is_ndn = 0;
+			break;
+		}
+	}
+
+	if (is_ndn) {
+		if (list_empty(&ioa_cfg->free_res_q)) {
+			ipr_send_hcam(ioa_cfg,
+				      IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE,
+				      hostrcb);
+			return;
+		}
+
+		res = list_entry(ioa_cfg->free_res_q.next,
+				 struct ipr_resource_entry, queue);
+
+		list_del(&res->queue);
+		ipr_init_res_entry(res);
+		list_add_tail(&res->queue, &ioa_cfg->used_res_q);
+	}
+
+	memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));
+
+	if (hostrcb->hcam.notify_type == IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY) {
+		if (res->sdev) {
+			res->sdev->hostdata = NULL;
+			res->del_from_ml = 1;
+			if (ioa_cfg->allow_ml_add_del)
+				schedule_work(&ioa_cfg->work_q);
+		} else
+			list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+	} else if (!res->sdev) {
+		res->add_to_ml = 1;
+		if (ioa_cfg->allow_ml_add_del)
+			schedule_work(&ioa_cfg->work_q);
+	}
+
+	ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
+}
+
+/**
+ * ipr_process_ccn - Op done function for a CCN.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is the op done function for a configuration
+ * change notification host controlled async from the adapter.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_process_ccn(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	list_del(&hostrcb->queue);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+
+	if (ioasc) {
+		if (ioasc != IPR_IOASC_IOA_WAS_RESET)
+			dev_err(&ioa_cfg->pdev->dev,
+				"Host RCB failed with IOASC: 0x%08X\n", ioasc);
+
+		ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
+	} else {
+		ipr_handle_config_change(ioa_cfg, hostrcb);
+	}
+}
+
+/**
+ * ipr_log_vpd - Log the passed VPD to the error log.
+ * @vpids:			vendor/product id struct
+ * @serial_num:		serial number string
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_vpd(struct ipr_std_inq_vpids *vpids, u8 *serial_num)
+{
+	char buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN
+		    + IPR_SERIAL_NUM_LEN];
+
+	memcpy(buffer, vpids->vendor_id, IPR_VENDOR_ID_LEN);
+	memcpy(buffer + IPR_VENDOR_ID_LEN, vpids->product_id,
+	       IPR_PROD_ID_LEN);
+	buffer[IPR_VENDOR_ID_LEN + IPR_PROD_ID_LEN] = '\0';
+	ipr_err("Vendor/Product ID: %s\n", buffer);
+
+	memcpy(buffer, serial_num, IPR_SERIAL_NUM_LEN);
+	buffer[IPR_SERIAL_NUM_LEN] = '\0';
+	ipr_err("    Serial Number: %s\n", buffer);
+}
+
+/**
+ * ipr_log_cache_error - Log a cache error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_cache_error(struct ipr_ioa_cfg *ioa_cfg,
+				struct ipr_hostrcb *hostrcb)
+{
+	struct ipr_hostrcb_type_02_error *error =
+		&hostrcb->hcam.u.error.u.type_02_error;
+
+	ipr_err("-----Current Configuration-----\n");
+	ipr_err("Cache Directory Card Information:\n");
+	ipr_log_vpd(&error->ioa_vpids, error->ioa_sn);
+	ipr_err("Adapter Card Information:\n");
+	ipr_log_vpd(&error->cfc_vpids, error->cfc_sn);
+
+	ipr_err("-----Expected Configuration-----\n");
+	ipr_err("Cache Directory Card Information:\n");
+	ipr_log_vpd(&error->ioa_last_attached_to_cfc_vpids,
+		    error->ioa_last_attached_to_cfc_sn);
+	ipr_err("Adapter Card Information:\n");
+	ipr_log_vpd(&error->cfc_last_attached_to_ioa_vpids,
+		    error->cfc_last_attached_to_ioa_sn);
+
+	ipr_err("Additional IOA Data: %08X %08X %08X\n",
+		     be32_to_cpu(error->ioa_data[0]),
+		     be32_to_cpu(error->ioa_data[1]),
+		     be32_to_cpu(error->ioa_data[2]));
+}
+
+/**
+ * ipr_log_config_error - Log a configuration error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_config_error(struct ipr_ioa_cfg *ioa_cfg,
+				 struct ipr_hostrcb *hostrcb)
+{
+	int errors_logged, i;
+	struct ipr_hostrcb_device_data_entry *dev_entry;
+	struct ipr_hostrcb_type_03_error *error;
+
+	error = &hostrcb->hcam.u.error.u.type_03_error;
+	errors_logged = be32_to_cpu(error->errors_logged);
+
+	ipr_err("Device Errors Detected/Logged: %d/%d\n",
+		be32_to_cpu(error->errors_detected), errors_logged);
+
+	dev_entry = error->dev_entry;
+
+	for (i = 0; i < errors_logged; i++, dev_entry++) {
+		ipr_err_separator;
+
+		if (dev_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
+			ipr_err("Device %d: missing\n", i + 1);
+		} else {
+			ipr_err("Device %d: %d:%d:%d:%d\n", i + 1,
+				ioa_cfg->host->host_no, dev_entry->dev_res_addr.bus,
+				dev_entry->dev_res_addr.target, dev_entry->dev_res_addr.lun);
+		}
+		ipr_log_vpd(&dev_entry->dev_vpids, dev_entry->dev_sn);
+
+		ipr_err("-----New Device Information-----\n");
+		ipr_log_vpd(&dev_entry->new_dev_vpids, dev_entry->new_dev_sn);
+
+		ipr_err("Cache Directory Card Information:\n");
+		ipr_log_vpd(&dev_entry->ioa_last_with_dev_vpids,
+			    dev_entry->ioa_last_with_dev_sn);
+
+		ipr_err("Adapter Card Information:\n");
+		ipr_log_vpd(&dev_entry->cfc_last_with_dev_vpids,
+			    dev_entry->cfc_last_with_dev_sn);
+
+		ipr_err("Additional IOA Data: %08X %08X %08X %08X %08X\n",
+			be32_to_cpu(dev_entry->ioa_data[0]),
+			be32_to_cpu(dev_entry->ioa_data[1]),
+			be32_to_cpu(dev_entry->ioa_data[2]),
+			be32_to_cpu(dev_entry->ioa_data[3]),
+			be32_to_cpu(dev_entry->ioa_data[4]));
+	}
+}
+
+/**
+ * ipr_log_array_error - Log an array configuration error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_array_error(struct ipr_ioa_cfg *ioa_cfg,
+				struct ipr_hostrcb *hostrcb)
+{
+	int i;
+	struct ipr_hostrcb_type_04_error *error;
+	struct ipr_hostrcb_array_data_entry *array_entry;
+	const u8 zero_sn[IPR_SERIAL_NUM_LEN] = { [0 ... IPR_SERIAL_NUM_LEN-1] = '0' };
+
+	error = &hostrcb->hcam.u.error.u.type_04_error;
+
+	ipr_err_separator;
+
+	ipr_err("RAID %s Array Configuration: %d:%d:%d:%d\n",
+		error->protection_level,
+		ioa_cfg->host->host_no,
+		error->last_func_vset_res_addr.bus,
+		error->last_func_vset_res_addr.target,
+		error->last_func_vset_res_addr.lun);
+
+	ipr_err_separator;
+
+	array_entry = error->array_member;
+
+	for (i = 0; i < 18; i++) {
+		if (!memcmp(array_entry->serial_num, zero_sn, IPR_SERIAL_NUM_LEN))
+			continue;
+
+		if (be32_to_cpu(error->exposed_mode_adn) == i) {
+			ipr_err("Exposed Array Member %d:\n", i);
+		} else {
+			ipr_err("Array Member %d:\n", i);
+		}
+
+		ipr_log_vpd(&array_entry->vpids, array_entry->serial_num);
+
+		if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
+			ipr_err("Current Location: unknown\n");
+		} else {
+			ipr_err("Current Location: %d:%d:%d:%d\n",
+				ioa_cfg->host->host_no,
+				array_entry->dev_res_addr.bus,
+				array_entry->dev_res_addr.target,
+				array_entry->dev_res_addr.lun);
+		}
+
+		if (array_entry->dev_res_addr.bus >= IPR_MAX_NUM_BUSES) {
+			ipr_err("Expected Location: unknown\n");
+		} else {
+			ipr_err("Expected Location: %d:%d:%d:%d\n",
+				ioa_cfg->host->host_no,
+				array_entry->expected_dev_res_addr.bus,
+				array_entry->expected_dev_res_addr.target,
+				array_entry->expected_dev_res_addr.lun);
+		}
+
+		ipr_err_separator;
+
+		if (i == 9)
+			array_entry = error->array_member2;
+		else
+			array_entry++;
+	}
+}
+
+/**
+ * ipr_log_generic_error - Log an adapter error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_log_generic_error(struct ipr_ioa_cfg *ioa_cfg,
+				  struct ipr_hostrcb *hostrcb)
+{
+	int i;
+	int ioa_data_len = be32_to_cpu(hostrcb->hcam.length);
+
+	if (ioa_data_len == 0)
+		return;
+
+	ipr_err("IOA Error Data:\n");
+	ipr_err("Offset    0 1 2 3  4 5 6 7  8 9 A B  C D E F\n");
+
+	for (i = 0; i < ioa_data_len / 4; i += 4) {
+		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+1]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+2]),
+			be32_to_cpu(hostrcb->hcam.u.raw.data[i+3]));
+	}
+}
+
+/**
+ * ipr_get_error - Find the specfied IOASC in the ipr_error_table.
+ * @ioasc:	IOASC
+ *
+ * This function will return the index of into the ipr_error_table
+ * for the specified IOASC. If the IOASC is not in the table,
+ * 0 will be returned, which points to the entry used for unknown errors.
+ *
+ * Return value:
+ * 	index into the ipr_error_table
+ **/
+static u32 ipr_get_error(u32 ioasc)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(ipr_error_table); i++)
+		if (ipr_error_table[i].ioasc == ioasc)
+			return i;
+
+	return 0;
+}
+
+/**
+ * ipr_handle_log_data - Log an adapter error.
+ * @ioa_cfg:	ioa config struct
+ * @hostrcb:	hostrcb struct
+ *
+ * This function logs an adapter error to the system.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_handle_log_data(struct ipr_ioa_cfg *ioa_cfg,
+				struct ipr_hostrcb *hostrcb)
+{
+	u32 ioasc;
+	int error_index;
+
+	if (hostrcb->hcam.notify_type != IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY)
+		return;
+
+	if (hostrcb->hcam.notifications_lost == IPR_HOST_RCB_NOTIFICATIONS_LOST)
+		dev_err(&ioa_cfg->pdev->dev, "Error notifications lost\n");
+
+	ioasc = be32_to_cpu(hostrcb->hcam.u.error.failing_dev_ioasc);
+
+	if (ioasc == IPR_IOASC_BUS_WAS_RESET ||
+	    ioasc == IPR_IOASC_BUS_WAS_RESET_BY_OTHER) {
+		/* Tell the midlayer we had a bus reset so it will handle the UA properly */
+		scsi_report_bus_reset(ioa_cfg->host,
+				      hostrcb->hcam.u.error.failing_dev_res_addr.bus);
+	}
+
+	error_index = ipr_get_error(ioasc);
+
+	if (!ipr_error_table[error_index].log_hcam)
+		return;
+
+	if (ipr_is_device(&hostrcb->hcam.u.error.failing_dev_res_addr)) {
+		ipr_res_err(ioa_cfg, hostrcb->hcam.u.error.failing_dev_res_addr,
+			    "%s\n", ipr_error_table[error_index].error);
+	} else {
+		dev_err(&ioa_cfg->pdev->dev, "%s\n",
+			ipr_error_table[error_index].error);
+	}
+
+	/* Set indication we have logged an error */
+	ioa_cfg->errors_logged++;
+
+	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
+		return;
+
+	switch (hostrcb->hcam.overlay_id) {
+	case IPR_HOST_RCB_OVERLAY_ID_1:
+		ipr_log_generic_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_2:
+		ipr_log_cache_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_3:
+		ipr_log_config_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_4:
+	case IPR_HOST_RCB_OVERLAY_ID_6:
+		ipr_log_array_error(ioa_cfg, hostrcb);
+		break;
+	case IPR_HOST_RCB_OVERLAY_ID_DEFAULT:
+		ipr_log_generic_error(ioa_cfg, hostrcb);
+		break;
+	default:
+		dev_err(&ioa_cfg->pdev->dev,
+			"Unknown error received. Overlay ID: %d\n",
+			hostrcb->hcam.overlay_id);
+		break;
+	}
+}
+
+/**
+ * ipr_process_error - Op done function for an adapter error log.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is the op done function for an error log host
+ * controlled async from the adapter. It will log the error and
+ * send the HCAM back to the adapter.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_process_error(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_hostrcb *hostrcb = ipr_cmd->u.hostrcb;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	list_del(&hostrcb->queue);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+
+	if (!ioasc) {
+		ipr_handle_log_data(ioa_cfg, hostrcb);
+	} else if (ioasc != IPR_IOASC_IOA_WAS_RESET) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Host RCB failed with IOASC: 0x%08X\n", ioasc);
+	}
+
+	ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
+}
+
+/**
+ * ipr_timeout -  An internally generated op has timed out.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function blocks host requests and initiates an
+ * adapter reset.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_timeout(struct ipr_cmnd *ipr_cmd)
+{
+	unsigned long lock_flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	ioa_cfg->errors_logged++;
+	dev_err(&ioa_cfg->pdev->dev,
+		"Adapter being reset due to command timeout.\n");
+
+	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+		ioa_cfg->sdt_state = GET_DUMP;
+
+	if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd)
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	LEAVE;
+}
+
+/**
+ * ipr_oper_timeout -  Adapter timed out transitioning to operational
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function blocks host requests and initiates an
+ * adapter reset.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_oper_timeout(struct ipr_cmnd *ipr_cmd)
+{
+	unsigned long lock_flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	ioa_cfg->errors_logged++;
+	dev_err(&ioa_cfg->pdev->dev,
+		"Adapter timed out transitioning to operational.\n");
+
+	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+		ioa_cfg->sdt_state = GET_DUMP;
+
+	if (!ioa_cfg->in_reset_reload || ioa_cfg->reset_cmd == ipr_cmd) {
+		if (ipr_fastfail)
+			ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES;
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	LEAVE;
+}
+
+/**
+ * ipr_reset_reload - Reset/Reload the IOA
+ * @ioa_cfg:		ioa config struct
+ * @shutdown_type:	shutdown type
+ *
+ * This function resets the adapter and re-initializes it.
+ * This function assumes that all new host commands have been stopped.
+ * Return value:
+ * 	SUCCESS / FAILED
+ **/
+static int ipr_reset_reload(struct ipr_ioa_cfg *ioa_cfg,
+			    enum ipr_shutdown_type shutdown_type)
+{
+	if (!ioa_cfg->in_reset_reload)
+		ipr_initiate_ioa_reset(ioa_cfg, shutdown_type);
+
+	spin_unlock_irq(ioa_cfg->host->host_lock);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+	spin_lock_irq(ioa_cfg->host->host_lock);
+
+	/* If we got hit with a host reset while we were already resetting
+	 the adapter for some reason, and the reset failed. */
+	if (ioa_cfg->ioa_is_dead) {
+		ipr_trace;
+		return FAILED;
+	}
+
+	return SUCCESS;
+}
+
+/**
+ * ipr_find_ses_entry - Find matching SES in SES table
+ * @res:	resource entry struct of SES
+ *
+ * Return value:
+ * 	pointer to SES table entry / NULL on failure
+ **/
+static const struct ipr_ses_table_entry *
+ipr_find_ses_entry(struct ipr_resource_entry *res)
+{
+	int i, j, matches;
+	const struct ipr_ses_table_entry *ste = ipr_ses_table;
+
+	for (i = 0; i < ARRAY_SIZE(ipr_ses_table); i++, ste++) {
+		for (j = 0, matches = 0; j < IPR_PROD_ID_LEN; j++) {
+			if (ste->compare_product_id_byte[j] == 'X') {
+				if (res->cfgte.std_inq_data.vpids.product_id[j] == ste->product_id[j])
+					matches++;
+				else
+					break;
+			} else
+				matches++;
+		}
+
+		if (matches == IPR_PROD_ID_LEN)
+			return ste;
+	}
+
+	return NULL;
+}
+
+/**
+ * ipr_get_max_scsi_speed - Determine max SCSI speed for a given bus
+ * @ioa_cfg:	ioa config struct
+ * @bus:		SCSI bus
+ * @bus_width:	bus width
+ *
+ * Return value:
+ *	SCSI bus speed in units of 100KHz, 1600 is 160 MHz
+ *	For a 2-byte wide SCSI bus, the maximum transfer speed is
+ *	twice the maximum transfer rate (e.g. for a wide enabled bus,
+ *	max 160MHz = max 320MB/sec).
+ **/
+static u32 ipr_get_max_scsi_speed(struct ipr_ioa_cfg *ioa_cfg, u8 bus, u8 bus_width)
+{
+	struct ipr_resource_entry *res;
+	const struct ipr_ses_table_entry *ste;
+	u32 max_xfer_rate = IPR_MAX_SCSI_RATE(bus_width);
+
+	/* Loop through each config table entry in the config table buffer */
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (!(IPR_IS_SES_DEVICE(res->cfgte.std_inq_data)))
+			continue;
+
+		if (bus != res->cfgte.res_addr.bus)
+			continue;
+
+		if (!(ste = ipr_find_ses_entry(res)))
+			continue;
+
+		max_xfer_rate = (ste->max_bus_speed_limit * 10) / (bus_width / 8);
+	}
+
+	return max_xfer_rate;
+}
+
+/**
+ * ipr_wait_iodbg_ack - Wait for an IODEBUG ACK from the IOA
+ * @ioa_cfg:		ioa config struct
+ * @max_delay:		max delay in micro-seconds to wait
+ *
+ * Waits for an IODEBUG ACK from the IOA, doing busy looping.
+ *
+ * Return value:
+ * 	0 on success / other on failure
+ **/
+static int ipr_wait_iodbg_ack(struct ipr_ioa_cfg *ioa_cfg, int max_delay)
+{
+	volatile u32 pcii_reg;
+	int delay = 1;
+
+	/* Read interrupt reg until IOA signals IO Debug Acknowledge */
+	while (delay < max_delay) {
+		pcii_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+
+		if (pcii_reg & IPR_PCII_IO_DEBUG_ACKNOWLEDGE)
+			return 0;
+
+		/* udelay cannot be used if delay is more than a few milliseconds */
+		if ((delay / 1000) > MAX_UDELAY_MS)
+			mdelay(delay / 1000);
+		else
+			udelay(delay);
+
+		delay += delay;
+	}
+	return -EIO;
+}
+
+/**
+ * ipr_get_ldump_data_section - Dump IOA memory
+ * @ioa_cfg:			ioa config struct
+ * @start_addr:			adapter address to dump
+ * @dest:				destination kernel buffer
+ * @length_in_words:	length to dump in 4 byte words
+ *
+ * Return value:
+ * 	0 on success / -EIO on failure
+ **/
+static int ipr_get_ldump_data_section(struct ipr_ioa_cfg *ioa_cfg,
+				      u32 start_addr,
+				      __be32 *dest, u32 length_in_words)
+{
+	volatile u32 temp_pcii_reg;
+	int i, delay = 0;
+
+	/* Write IOA interrupt reg starting LDUMP state  */
+	writel((IPR_UPROCI_RESET_ALERT | IPR_UPROCI_IO_DEBUG_ALERT),
+	       ioa_cfg->regs.set_uproc_interrupt_reg);
+
+	/* Wait for IO debug acknowledge */
+	if (ipr_wait_iodbg_ack(ioa_cfg,
+			       IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC)) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"IOA dump long data transfer timeout\n");
+		return -EIO;
+	}
+
+	/* Signal LDUMP interlocked - clear IO debug ack */
+	writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,
+	       ioa_cfg->regs.clr_interrupt_reg);
+
+	/* Write Mailbox with starting address */
+	writel(start_addr, ioa_cfg->ioa_mailbox);
+
+	/* Signal address valid - clear IOA Reset alert */
+	writel(IPR_UPROCI_RESET_ALERT,
+	       ioa_cfg->regs.clr_uproc_interrupt_reg);
+
+	for (i = 0; i < length_in_words; i++) {
+		/* Wait for IO debug acknowledge */
+		if (ipr_wait_iodbg_ack(ioa_cfg,
+				       IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC)) {
+			dev_err(&ioa_cfg->pdev->dev,
+				"IOA dump short data transfer timeout\n");
+			return -EIO;
+		}
+
+		/* Read data from mailbox and increment destination pointer */
+		*dest = cpu_to_be32(readl(ioa_cfg->ioa_mailbox));
+		dest++;
+
+		/* For all but the last word of data, signal data received */
+		if (i < (length_in_words - 1)) {
+			/* Signal dump data received - Clear IO debug Ack */
+			writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,
+			       ioa_cfg->regs.clr_interrupt_reg);
+		}
+	}
+
+	/* Signal end of block transfer. Set reset alert then clear IO debug ack */
+	writel(IPR_UPROCI_RESET_ALERT,
+	       ioa_cfg->regs.set_uproc_interrupt_reg);
+
+	writel(IPR_UPROCI_IO_DEBUG_ALERT,
+	       ioa_cfg->regs.clr_uproc_interrupt_reg);
+
+	/* Signal dump data received - Clear IO debug Ack */
+	writel(IPR_PCII_IO_DEBUG_ACKNOWLEDGE,
+	       ioa_cfg->regs.clr_interrupt_reg);
+
+	/* Wait for IOA to signal LDUMP exit - IOA reset alert will be cleared */
+	while (delay < IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC) {
+		temp_pcii_reg =
+		    readl(ioa_cfg->regs.sense_uproc_interrupt_reg);
+
+		if (!(temp_pcii_reg & IPR_UPROCI_RESET_ALERT))
+			return 0;
+
+		udelay(10);
+		delay += 10;
+	}
+
+	return 0;
+}
+
+#ifdef CONFIG_SCSI_IPR_DUMP
+/**
+ * ipr_sdt_copy - Copy Smart Dump Table to kernel buffer
+ * @ioa_cfg:		ioa config struct
+ * @pci_address:	adapter address
+ * @length:			length of data to copy
+ *
+ * Copy data from PCI adapter to kernel buffer.
+ * Note: length MUST be a 4 byte multiple
+ * Return value:
+ * 	0 on success / other on failure
+ **/
+static int ipr_sdt_copy(struct ipr_ioa_cfg *ioa_cfg,
+			unsigned long pci_address, u32 length)
+{
+	int bytes_copied = 0;
+	int cur_len, rc, rem_len, rem_page_len;
+	__be32 *page;
+	unsigned long lock_flags = 0;
+	struct ipr_ioa_dump *ioa_dump = &ioa_cfg->dump->ioa_dump;
+
+	while (bytes_copied < length &&
+	       (ioa_dump->hdr.len + bytes_copied) < IPR_MAX_IOA_DUMP_SIZE) {
+		if (ioa_dump->page_offset >= PAGE_SIZE ||
+		    ioa_dump->page_offset == 0) {
+			page = (__be32 *)__get_free_page(GFP_ATOMIC);
+
+			if (!page) {
+				ipr_trace;
+				return bytes_copied;
+			}
+
+			ioa_dump->page_offset = 0;
+			ioa_dump->ioa_data[ioa_dump->next_page_index] = page;
+			ioa_dump->next_page_index++;
+		} else
+			page = ioa_dump->ioa_data[ioa_dump->next_page_index - 1];
+
+		rem_len = length - bytes_copied;
+		rem_page_len = PAGE_SIZE - ioa_dump->page_offset;
+		cur_len = min(rem_len, rem_page_len);
+
+		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+		if (ioa_cfg->sdt_state == ABORT_DUMP) {
+			rc = -EIO;
+		} else {
+			rc = ipr_get_ldump_data_section(ioa_cfg,
+							pci_address + bytes_copied,
+							&page[ioa_dump->page_offset / 4],
+							(cur_len / sizeof(u32)));
+		}
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+		if (!rc) {
+			ioa_dump->page_offset += cur_len;
+			bytes_copied += cur_len;
+		} else {
+			ipr_trace;
+			break;
+		}
+		schedule();
+	}
+
+	return bytes_copied;
+}
+
+/**
+ * ipr_init_dump_entry_hdr - Initialize a dump entry header.
+ * @hdr:	dump entry header struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_init_dump_entry_hdr(struct ipr_dump_entry_header *hdr)
+{
+	hdr->eye_catcher = IPR_DUMP_EYE_CATCHER;
+	hdr->num_elems = 1;
+	hdr->offset = sizeof(*hdr);
+	hdr->status = IPR_DUMP_STATUS_SUCCESS;
+}
+
+/**
+ * ipr_dump_ioa_type_data - Fill in the adapter type in the dump.
+ * @ioa_cfg:	ioa config struct
+ * @driver_dump:	driver dump struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_dump_ioa_type_data(struct ipr_ioa_cfg *ioa_cfg,
+				   struct ipr_driver_dump *driver_dump)
+{
+	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+
+	ipr_init_dump_entry_hdr(&driver_dump->ioa_type_entry.hdr);
+	driver_dump->ioa_type_entry.hdr.len =
+		sizeof(struct ipr_dump_ioa_type_entry) -
+		sizeof(struct ipr_dump_entry_header);
+	driver_dump->ioa_type_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;
+	driver_dump->ioa_type_entry.hdr.id = IPR_DUMP_DRIVER_TYPE_ID;
+	driver_dump->ioa_type_entry.type = ioa_cfg->type;
+	driver_dump->ioa_type_entry.fw_version = (ucode_vpd->major_release << 24) |
+		(ucode_vpd->card_type << 16) | (ucode_vpd->minor_release[0] << 8) |
+		ucode_vpd->minor_release[1];
+	driver_dump->hdr.num_entries++;
+}
+
+/**
+ * ipr_dump_version_data - Fill in the driver version in the dump.
+ * @ioa_cfg:	ioa config struct
+ * @driver_dump:	driver dump struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_dump_version_data(struct ipr_ioa_cfg *ioa_cfg,
+				  struct ipr_driver_dump *driver_dump)
+{
+	ipr_init_dump_entry_hdr(&driver_dump->version_entry.hdr);
+	driver_dump->version_entry.hdr.len =
+		sizeof(struct ipr_dump_version_entry) -
+		sizeof(struct ipr_dump_entry_header);
+	driver_dump->version_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII;
+	driver_dump->version_entry.hdr.id = IPR_DUMP_DRIVER_VERSION_ID;
+	strcpy(driver_dump->version_entry.version, IPR_DRIVER_VERSION);
+	driver_dump->hdr.num_entries++;
+}
+
+/**
+ * ipr_dump_trace_data - Fill in the IOA trace in the dump.
+ * @ioa_cfg:	ioa config struct
+ * @driver_dump:	driver dump struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_dump_trace_data(struct ipr_ioa_cfg *ioa_cfg,
+				   struct ipr_driver_dump *driver_dump)
+{
+	ipr_init_dump_entry_hdr(&driver_dump->trace_entry.hdr);
+	driver_dump->trace_entry.hdr.len =
+		sizeof(struct ipr_dump_trace_entry) -
+		sizeof(struct ipr_dump_entry_header);
+	driver_dump->trace_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;
+	driver_dump->trace_entry.hdr.id = IPR_DUMP_TRACE_ID;
+	memcpy(driver_dump->trace_entry.trace, ioa_cfg->trace, IPR_TRACE_SIZE);
+	driver_dump->hdr.num_entries++;
+}
+
+/**
+ * ipr_dump_location_data - Fill in the IOA location in the dump.
+ * @ioa_cfg:	ioa config struct
+ * @driver_dump:	driver dump struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_dump_location_data(struct ipr_ioa_cfg *ioa_cfg,
+				   struct ipr_driver_dump *driver_dump)
+{
+	ipr_init_dump_entry_hdr(&driver_dump->location_entry.hdr);
+	driver_dump->location_entry.hdr.len =
+		sizeof(struct ipr_dump_location_entry) -
+		sizeof(struct ipr_dump_entry_header);
+	driver_dump->location_entry.hdr.data_type = IPR_DUMP_DATA_TYPE_ASCII;
+	driver_dump->location_entry.hdr.id = IPR_DUMP_LOCATION_ID;
+	strcpy(driver_dump->location_entry.location, ioa_cfg->pdev->dev.bus_id);
+	driver_dump->hdr.num_entries++;
+}
+
+/**
+ * ipr_get_ioa_dump - Perform a dump of the driver and adapter.
+ * @ioa_cfg:	ioa config struct
+ * @dump:		dump struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_get_ioa_dump(struct ipr_ioa_cfg *ioa_cfg, struct ipr_dump *dump)
+{
+	unsigned long start_addr, sdt_word;
+	unsigned long lock_flags = 0;
+	struct ipr_driver_dump *driver_dump = &dump->driver_dump;
+	struct ipr_ioa_dump *ioa_dump = &dump->ioa_dump;
+	u32 num_entries, start_off, end_off;
+	u32 bytes_to_copy, bytes_copied, rc;
+	struct ipr_sdt *sdt;
+	int i;
+
+	ENTER;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (ioa_cfg->sdt_state != GET_DUMP) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
+	start_addr = readl(ioa_cfg->ioa_mailbox);
+
+	if (!ipr_sdt_is_fmt2(start_addr)) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Invalid dump table format: %lx\n", start_addr);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
+	dev_err(&ioa_cfg->pdev->dev, "Dump of IOA initiated\n");
+
+	driver_dump->hdr.eye_catcher = IPR_DUMP_EYE_CATCHER;
+
+	/* Initialize the overall dump header */
+	driver_dump->hdr.len = sizeof(struct ipr_driver_dump);
+	driver_dump->hdr.num_entries = 1;
+	driver_dump->hdr.first_entry_offset = sizeof(struct ipr_dump_header);
+	driver_dump->hdr.status = IPR_DUMP_STATUS_SUCCESS;
+	driver_dump->hdr.os = IPR_DUMP_OS_LINUX;
+	driver_dump->hdr.driver_name = IPR_DUMP_DRIVER_NAME;
+
+	ipr_dump_version_data(ioa_cfg, driver_dump);
+	ipr_dump_location_data(ioa_cfg, driver_dump);
+	ipr_dump_ioa_type_data(ioa_cfg, driver_dump);
+	ipr_dump_trace_data(ioa_cfg, driver_dump);
+
+	/* Update dump_header */
+	driver_dump->hdr.len += sizeof(struct ipr_dump_entry_header);
+
+	/* IOA Dump entry */
+	ipr_init_dump_entry_hdr(&ioa_dump->hdr);
+	ioa_dump->format = IPR_SDT_FMT2;
+	ioa_dump->hdr.len = 0;
+	ioa_dump->hdr.data_type = IPR_DUMP_DATA_TYPE_BINARY;
+	ioa_dump->hdr.id = IPR_DUMP_IOA_DUMP_ID;
+
+	/* First entries in sdt are actually a list of dump addresses and
+	 lengths to gather the real dump data.  sdt represents the pointer
+	 to the ioa generated dump table.  Dump data will be extracted based
+	 on entries in this table */
+	sdt = &ioa_dump->sdt;
+
+	rc = ipr_get_ldump_data_section(ioa_cfg, start_addr, (__be32 *)sdt,
+					sizeof(struct ipr_sdt) / sizeof(__be32));
+
+	/* Smart Dump table is ready to use and the first entry is valid */
+	if (rc || (be32_to_cpu(sdt->hdr.state) != IPR_FMT2_SDT_READY_TO_USE)) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Dump of IOA failed. Dump table not valid: %d, %X.\n",
+			rc, be32_to_cpu(sdt->hdr.state));
+		driver_dump->hdr.status = IPR_DUMP_STATUS_FAILED;
+		ioa_cfg->sdt_state = DUMP_OBTAINED;
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
+	num_entries = be32_to_cpu(sdt->hdr.num_entries_used);
+
+	if (num_entries > IPR_NUM_SDT_ENTRIES)
+		num_entries = IPR_NUM_SDT_ENTRIES;
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	for (i = 0; i < num_entries; i++) {
+		if (ioa_dump->hdr.len > IPR_MAX_IOA_DUMP_SIZE) {
+			driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS;
+			break;
+		}
+
+		if (sdt->entry[i].flags & IPR_SDT_VALID_ENTRY) {
+			sdt_word = be32_to_cpu(sdt->entry[i].bar_str_offset);
+			start_off = sdt_word & IPR_FMT2_MBX_ADDR_MASK;
+			end_off = be32_to_cpu(sdt->entry[i].end_offset);
+
+			if (ipr_sdt_is_fmt2(sdt_word) && sdt_word) {
+				bytes_to_copy = end_off - start_off;
+				if (bytes_to_copy > IPR_MAX_IOA_DUMP_SIZE) {
+					sdt->entry[i].flags &= ~IPR_SDT_VALID_ENTRY;
+					continue;
+				}
+
+				/* Copy data from adapter to driver buffers */
+				bytes_copied = ipr_sdt_copy(ioa_cfg, sdt_word,
+							    bytes_to_copy);
+
+				ioa_dump->hdr.len += bytes_copied;
+
+				if (bytes_copied != bytes_to_copy) {
+					driver_dump->hdr.status = IPR_DUMP_STATUS_QUAL_SUCCESS;
+					break;
+				}
+			}
+		}
+	}
+
+	dev_err(&ioa_cfg->pdev->dev, "Dump of IOA completed.\n");
+
+	/* Update dump_header */
+	driver_dump->hdr.len += ioa_dump->hdr.len;
+	wmb();
+	ioa_cfg->sdt_state = DUMP_OBTAINED;
+	LEAVE;
+}
+
+#else
+#define ipr_get_ioa_dump(ioa_cfg, dump) do { } while(0)
+#endif
+
+/**
+ * ipr_release_dump - Free adapter dump memory
+ * @kref:	kref struct
+ *
+ * Return value:
+ *	nothing
+ **/
+static void ipr_release_dump(struct kref *kref)
+{
+	struct ipr_dump *dump = container_of(kref,struct ipr_dump,kref);
+	struct ipr_ioa_cfg *ioa_cfg = dump->ioa_cfg;
+	unsigned long lock_flags = 0;
+	int i;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ioa_cfg->dump = NULL;
+	ioa_cfg->sdt_state = INACTIVE;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	for (i = 0; i < dump->ioa_dump.next_page_index; i++)
+		free_page((unsigned long) dump->ioa_dump.ioa_data[i]);
+
+	kfree(dump);
+	LEAVE;
+}
+
+/**
+ * ipr_worker_thread - Worker thread
+ * @data:		ioa config struct
+ *
+ * Called at task level from a work thread. This function takes care
+ * of adding and removing device from the mid-layer as configuration
+ * changes are detected by the adapter.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_worker_thread(void *data)
+{
+	unsigned long lock_flags;
+	struct ipr_resource_entry *res;
+	struct scsi_device *sdev;
+	struct ipr_dump *dump;
+	struct ipr_ioa_cfg *ioa_cfg = data;
+	u8 bus, target, lun;
+	int did_work;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (ioa_cfg->sdt_state == GET_DUMP) {
+		dump = ioa_cfg->dump;
+		if (!dump) {
+			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+			return;
+		}
+		kref_get(&dump->kref);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		ipr_get_ioa_dump(ioa_cfg, dump);
+		kref_put(&dump->kref, ipr_release_dump);
+
+		spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+		if (ioa_cfg->sdt_state == DUMP_OBTAINED)
+			ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
+restart:
+	do {
+		did_work = 0;
+		if (!ioa_cfg->allow_cmds || !ioa_cfg->allow_ml_add_del) {
+			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+			return;
+		}
+
+		list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+			if (res->del_from_ml && res->sdev) {
+				did_work = 1;
+				sdev = res->sdev;
+				if (!scsi_device_get(sdev)) {
+					res->sdev = NULL;
+					list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+					spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+					scsi_remove_device(sdev);
+					scsi_device_put(sdev);
+					spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+				}
+				break;
+			}
+		}
+	} while(did_work);
+
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (res->add_to_ml) {
+			bus = res->cfgte.res_addr.bus;
+			target = res->cfgte.res_addr.target;
+			lun = res->cfgte.res_addr.lun;
+			spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+			scsi_add_device(ioa_cfg->host, bus, target, lun);
+			spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+			goto restart;
+		}
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	kobject_uevent(&ioa_cfg->host->shost_classdev.kobj, KOBJ_CHANGE, NULL);
+	LEAVE;
+}
+
+#ifdef CONFIG_SCSI_IPR_TRACE
+/**
+ * ipr_read_trace - Dump the adapter trace
+ * @kobj:		kobject struct
+ * @buf:		buffer
+ * @off:		offset
+ * @count:		buffer size
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_read_trace(struct kobject *kobj, char *buf,
+			      loff_t off, size_t count)
+{
+	struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int size = IPR_TRACE_SIZE;
+	char *src = (char *)ioa_cfg->trace;
+
+	if (off > size)
+		return 0;
+	if (off + count > size) {
+		size -= off;
+		count = size;
+	}
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	memcpy(buf, &src[off], count);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return count;
+}
+
+static struct bin_attribute ipr_trace_attr = {
+	.attr =	{
+		.name = "trace",
+		.mode = S_IRUGO,
+	},
+	.size = 0,
+	.read = ipr_read_trace,
+};
+#endif
+
+/**
+ * ipr_show_fw_version - Show the firmware version
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_fw_version(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+	unsigned long lock_flags = 0;
+	int len;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	len = snprintf(buf, PAGE_SIZE, "%02X%02X%02X%02X\n",
+		       ucode_vpd->major_release, ucode_vpd->card_type,
+		       ucode_vpd->minor_release[0],
+		       ucode_vpd->minor_release[1]);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+static struct class_device_attribute ipr_fw_version_attr = {
+	.attr = {
+		.name =		"fw_version",
+		.mode =		S_IRUGO,
+	},
+	.show = ipr_show_fw_version,
+};
+
+/**
+ * ipr_show_log_level - Show the adapter's error logging level
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_log_level(struct class_device *class_dev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int len;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	len = snprintf(buf, PAGE_SIZE, "%d\n", ioa_cfg->log_level);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+/**
+ * ipr_store_log_level - Change the adapter's error logging level
+ * @class_dev:	class device struct
+ * @buf:		buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_store_log_level(struct class_device *class_dev,
+				   const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ioa_cfg->log_level = simple_strtoul(buf, NULL, 10);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return strlen(buf);
+}
+
+static struct class_device_attribute ipr_log_level_attr = {
+	.attr = {
+		.name =		"log_level",
+		.mode =		S_IRUGO | S_IWUSR,
+	},
+	.show = ipr_show_log_level,
+	.store = ipr_store_log_level
+};
+
+/**
+ * ipr_store_diagnostics - IOA Diagnostics interface
+ * @class_dev:	class_device struct
+ * @buf:		buffer
+ * @count:		buffer size
+ *
+ * This function will reset the adapter and wait a reasonable
+ * amount of time for any errors that the adapter might log.
+ *
+ * Return value:
+ * 	count on success / other on failure
+ **/
+static ssize_t ipr_store_diagnostics(struct class_device *class_dev,
+				     const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags = 0;
+	int rc = count;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ioa_cfg->errors_logged = 0;
+	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+
+	if (ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+		/* Wait for a second for any errors to be logged */
+		msleep(1000);
+	} else {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return -EIO;
+	}
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (ioa_cfg->in_reset_reload || ioa_cfg->errors_logged)
+		rc = -EIO;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	return rc;
+}
+
+static struct class_device_attribute ipr_diagnostics_attr = {
+	.attr = {
+		.name =		"run_diagnostics",
+		.mode =		S_IWUSR,
+	},
+	.store = ipr_store_diagnostics
+};
+
+/**
+ * ipr_store_reset_adapter - Reset the adapter
+ * @class_dev:	class_device struct
+ * @buf:		buffer
+ * @count:		buffer size
+ *
+ * This function will reset the adapter.
+ *
+ * Return value:
+ * 	count on success / other on failure
+ **/
+static ssize_t ipr_store_reset_adapter(struct class_device *class_dev,
+				       const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	unsigned long lock_flags;
+	int result = count;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (!ioa_cfg->in_reset_reload)
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+	return result;
+}
+
+static struct class_device_attribute ipr_ioa_reset_attr = {
+	.attr = {
+		.name =		"reset_host",
+		.mode =		S_IWUSR,
+	},
+	.store = ipr_store_reset_adapter
+};
+
+/**
+ * ipr_alloc_ucode_buffer - Allocates a microcode download buffer
+ * @buf_len:		buffer length
+ *
+ * Allocates a DMA'able buffer in chunks and assembles a scatter/gather
+ * list to use for microcode download
+ *
+ * Return value:
+ * 	pointer to sglist / NULL on failure
+ **/
+static struct ipr_sglist *ipr_alloc_ucode_buffer(int buf_len)
+{
+	int sg_size, order, bsize_elem, num_elem, i, j;
+	struct ipr_sglist *sglist;
+	struct scatterlist *scatterlist;
+	struct page *page;
+
+	/* Get the minimum size per scatter/gather element */
+	sg_size = buf_len / (IPR_MAX_SGLIST - 1);
+
+	/* Get the actual size per element */
+	order = get_order(sg_size);
+
+	/* Determine the actual number of bytes per element */
+	bsize_elem = PAGE_SIZE * (1 << order);
+
+	/* Determine the actual number of sg entries needed */
+	if (buf_len % bsize_elem)
+		num_elem = (buf_len / bsize_elem) + 1;
+	else
+		num_elem = buf_len / bsize_elem;
+
+	/* Allocate a scatter/gather list for the DMA */
+	sglist = kmalloc(sizeof(struct ipr_sglist) +
+			 (sizeof(struct scatterlist) * (num_elem - 1)),
+			 GFP_KERNEL);
+
+	if (sglist == NULL) {
+		ipr_trace;
+		return NULL;
+	}
+
+	memset(sglist, 0, sizeof(struct ipr_sglist) +
+	       (sizeof(struct scatterlist) * (num_elem - 1)));
+
+	scatterlist = sglist->scatterlist;
+
+	sglist->order = order;
+	sglist->num_sg = num_elem;
+
+	/* Allocate a bunch of sg elements */
+	for (i = 0; i < num_elem; i++) {
+		page = alloc_pages(GFP_KERNEL, order);
+		if (!page) {
+			ipr_trace;
+
+			/* Free up what we already allocated */
+			for (j = i - 1; j >= 0; j--)
+				__free_pages(scatterlist[j].page, order);
+			kfree(sglist);
+			return NULL;
+		}
+
+		scatterlist[i].page = page;
+	}
+
+	return sglist;
+}
+
+/**
+ * ipr_free_ucode_buffer - Frees a microcode download buffer
+ * @p_dnld:		scatter/gather list pointer
+ *
+ * Free a DMA'able ucode download buffer previously allocated with
+ * ipr_alloc_ucode_buffer
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_free_ucode_buffer(struct ipr_sglist *sglist)
+{
+	int i;
+
+	for (i = 0; i < sglist->num_sg; i++)
+		__free_pages(sglist->scatterlist[i].page, sglist->order);
+
+	kfree(sglist);
+}
+
+/**
+ * ipr_copy_ucode_buffer - Copy user buffer to kernel buffer
+ * @sglist:		scatter/gather list pointer
+ * @buffer:		buffer pointer
+ * @len:		buffer length
+ *
+ * Copy a microcode image from a user buffer into a buffer allocated by
+ * ipr_alloc_ucode_buffer
+ *
+ * Return value:
+ * 	0 on success / other on failure
+ **/
+static int ipr_copy_ucode_buffer(struct ipr_sglist *sglist,
+				 u8 *buffer, u32 len)
+{
+	int bsize_elem, i, result = 0;
+	struct scatterlist *scatterlist;
+	void *kaddr;
+
+	/* Determine the actual number of bytes per element */
+	bsize_elem = PAGE_SIZE * (1 << sglist->order);
+
+	scatterlist = sglist->scatterlist;
+
+	for (i = 0; i < (len / bsize_elem); i++, buffer += bsize_elem) {
+		kaddr = kmap(scatterlist[i].page);
+		memcpy(kaddr, buffer, bsize_elem);
+		kunmap(scatterlist[i].page);
+
+		scatterlist[i].length = bsize_elem;
+
+		if (result != 0) {
+			ipr_trace;
+			return result;
+		}
+	}
+
+	if (len % bsize_elem) {
+		kaddr = kmap(scatterlist[i].page);
+		memcpy(kaddr, buffer, len % bsize_elem);
+		kunmap(scatterlist[i].page);
+
+		scatterlist[i].length = len % bsize_elem;
+	}
+
+	sglist->buffer_len = len;
+	return result;
+}
+
+/**
+ * ipr_map_ucode_buffer - Map a microcode download buffer
+ * @ipr_cmd:	ipr command struct
+ * @sglist:		scatter/gather list
+ * @len:		total length of download buffer
+ *
+ * Maps a microcode download scatter/gather list for DMA and
+ * builds the IOADL.
+ *
+ * Return value:
+ * 	0 on success / -EIO on failure
+ **/
+static int ipr_map_ucode_buffer(struct ipr_cmnd *ipr_cmd,
+				struct ipr_sglist *sglist, int len)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+	struct scatterlist *scatterlist = sglist->scatterlist;
+	int i;
+
+	ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev, scatterlist,
+					 sglist->num_sg, DMA_TO_DEVICE);
+
+	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+	ioarcb->write_data_transfer_length = cpu_to_be32(len);
+	ioarcb->write_ioadl_len =
+		cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+
+	for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+		ioadl[i].flags_and_data_len =
+			cpu_to_be32(IPR_IOADL_FLAGS_WRITE | sg_dma_len(&scatterlist[i]));
+		ioadl[i].address =
+			cpu_to_be32(sg_dma_address(&scatterlist[i]));
+	}
+
+	if (likely(ipr_cmd->dma_use_sg)) {
+		ioadl[i-1].flags_and_data_len |=
+			cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+	}
+	else {
+		dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/**
+ * ipr_store_update_fw - Update the firmware on the adapter
+ * @class_dev:	class_device struct
+ * @buf:		buffer
+ * @count:		buffer size
+ *
+ * This function will update the firmware on the adapter.
+ *
+ * Return value:
+ * 	count on success / other on failure
+ **/
+static ssize_t ipr_store_update_fw(struct class_device *class_dev,
+				       const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	struct ipr_ucode_image_header *image_hdr;
+	const struct firmware *fw_entry;
+	struct ipr_sglist *sglist;
+	unsigned long lock_flags;
+	char fname[100];
+	char *src;
+	int len, result, dnld_size;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	len = snprintf(fname, 99, "%s", buf);
+	fname[len-1] = '\0';
+
+	if(request_firmware(&fw_entry, fname, &ioa_cfg->pdev->dev)) {
+		dev_err(&ioa_cfg->pdev->dev, "Firmware file %s not found\n", fname);
+		return -EIO;
+	}
+
+	image_hdr = (struct ipr_ucode_image_header *)fw_entry->data;
+
+	if (be32_to_cpu(image_hdr->header_length) > fw_entry->size ||
+	    (ioa_cfg->vpd_cbs->page3_data.card_type &&
+	     ioa_cfg->vpd_cbs->page3_data.card_type != image_hdr->card_type)) {
+		dev_err(&ioa_cfg->pdev->dev, "Invalid microcode buffer\n");
+		release_firmware(fw_entry);
+		return -EINVAL;
+	}
+
+	src = (u8 *)image_hdr + be32_to_cpu(image_hdr->header_length);
+	dnld_size = fw_entry->size - be32_to_cpu(image_hdr->header_length);
+	sglist = ipr_alloc_ucode_buffer(dnld_size);
+
+	if (!sglist) {
+		dev_err(&ioa_cfg->pdev->dev, "Microcode buffer allocation failed\n");
+		release_firmware(fw_entry);
+		return -ENOMEM;
+	}
+
+	result = ipr_copy_ucode_buffer(sglist, src, dnld_size);
+
+	if (result) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Microcode buffer copy to DMA buffer failed\n");
+		ipr_free_ucode_buffer(sglist);
+		release_firmware(fw_entry);
+		return result;
+	}
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (ioa_cfg->ucode_sglist) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		dev_err(&ioa_cfg->pdev->dev,
+			"Microcode download already in progress\n");
+		ipr_free_ucode_buffer(sglist);
+		release_firmware(fw_entry);
+		return -EIO;
+	}
+
+	ioa_cfg->ucode_sglist = sglist;
+	ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ioa_cfg->ucode_sglist = NULL;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	ipr_free_ucode_buffer(sglist);
+	release_firmware(fw_entry);
+
+	return count;
+}
+
+static struct class_device_attribute ipr_update_fw_attr = {
+	.attr = {
+		.name =		"update_fw",
+		.mode =		S_IWUSR,
+	},
+	.store = ipr_store_update_fw
+};
+
+static struct class_device_attribute *ipr_ioa_attrs[] = {
+	&ipr_fw_version_attr,
+	&ipr_log_level_attr,
+	&ipr_diagnostics_attr,
+	&ipr_ioa_reset_attr,
+	&ipr_update_fw_attr,
+	NULL,
+};
+
+#ifdef CONFIG_SCSI_IPR_DUMP
+/**
+ * ipr_read_dump - Dump the adapter
+ * @kobj:		kobject struct
+ * @buf:		buffer
+ * @off:		offset
+ * @count:		buffer size
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_read_dump(struct kobject *kobj, char *buf,
+			      loff_t off, size_t count)
+{
+	struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	struct ipr_dump *dump;
+	unsigned long lock_flags = 0;
+	char *src;
+	int len;
+	size_t rc = count;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	dump = ioa_cfg->dump;
+
+	if (ioa_cfg->sdt_state != DUMP_OBTAINED || !dump) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return 0;
+	}
+	kref_get(&dump->kref);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	if (off > dump->driver_dump.hdr.len) {
+		kref_put(&dump->kref, ipr_release_dump);
+		return 0;
+	}
+
+	if (off + count > dump->driver_dump.hdr.len) {
+		count = dump->driver_dump.hdr.len - off;
+		rc = count;
+	}
+
+	if (count && off < sizeof(dump->driver_dump)) {
+		if (off + count > sizeof(dump->driver_dump))
+			len = sizeof(dump->driver_dump) - off;
+		else
+			len = count;
+		src = (u8 *)&dump->driver_dump + off;
+		memcpy(buf, src, len);
+		buf += len;
+		off += len;
+		count -= len;
+	}
+
+	off -= sizeof(dump->driver_dump);
+
+	if (count && off < offsetof(struct ipr_ioa_dump, ioa_data)) {
+		if (off + count > offsetof(struct ipr_ioa_dump, ioa_data))
+			len = offsetof(struct ipr_ioa_dump, ioa_data) - off;
+		else
+			len = count;
+		src = (u8 *)&dump->ioa_dump + off;
+		memcpy(buf, src, len);
+		buf += len;
+		off += len;
+		count -= len;
+	}
+
+	off -= offsetof(struct ipr_ioa_dump, ioa_data);
+
+	while (count) {
+		if ((off & PAGE_MASK) != ((off + count) & PAGE_MASK))
+			len = PAGE_ALIGN(off) - off;
+		else
+			len = count;
+		src = (u8 *)dump->ioa_dump.ioa_data[(off & PAGE_MASK) >> PAGE_SHIFT];
+		src += off & ~PAGE_MASK;
+		memcpy(buf, src, len);
+		buf += len;
+		off += len;
+		count -= len;
+	}
+
+	kref_put(&dump->kref, ipr_release_dump);
+	return rc;
+}
+
+/**
+ * ipr_alloc_dump - Prepare for adapter dump
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ *	0 on success / other on failure
+ **/
+static int ipr_alloc_dump(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_dump *dump;
+	unsigned long lock_flags = 0;
+
+	ENTER;
+	dump = kmalloc(sizeof(struct ipr_dump), GFP_KERNEL);
+
+	if (!dump) {
+		ipr_err("Dump memory allocation failed\n");
+		return -ENOMEM;
+	}
+
+	memset(dump, 0, sizeof(struct ipr_dump));
+	kref_init(&dump->kref);
+	dump->ioa_cfg = ioa_cfg;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (INACTIVE != ioa_cfg->sdt_state) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		kfree(dump);
+		return 0;
+	}
+
+	ioa_cfg->dump = dump;
+	ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+	if (ioa_cfg->ioa_is_dead && !ioa_cfg->dump_taken) {
+		ioa_cfg->dump_taken = 1;
+		schedule_work(&ioa_cfg->work_q);
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	LEAVE;
+	return 0;
+}
+
+/**
+ * ipr_free_dump - Free adapter dump memory
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ *	0 on success / other on failure
+ **/
+static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_dump *dump;
+	unsigned long lock_flags = 0;
+
+	ENTER;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	dump = ioa_cfg->dump;
+	if (!dump) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return 0;
+	}
+
+	ioa_cfg->dump = NULL;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	kref_put(&dump->kref, ipr_release_dump);
+
+	LEAVE;
+	return 0;
+}
+
+/**
+ * ipr_write_dump - Setup dump state of adapter
+ * @kobj:		kobject struct
+ * @buf:		buffer
+ * @off:		offset
+ * @count:		buffer size
+ *
+ * Return value:
+ *	number of bytes printed to buffer
+ **/
+static ssize_t ipr_write_dump(struct kobject *kobj, char *buf,
+			      loff_t off, size_t count)
+{
+	struct class_device *cdev = container_of(kobj,struct class_device,kobj);
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)shost->hostdata;
+	int rc;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EACCES;
+
+	if (buf[0] == '1')
+		rc = ipr_alloc_dump(ioa_cfg);
+	else if (buf[0] == '0')
+		rc = ipr_free_dump(ioa_cfg);
+	else
+		return -EINVAL;
+
+	if (rc)
+		return rc;
+	else
+		return count;
+}
+
+static struct bin_attribute ipr_dump_attr = {
+	.attr =	{
+		.name = "dump",
+		.mode = S_IRUSR | S_IWUSR,
+	},
+	.size = 0,
+	.read = ipr_read_dump,
+	.write = ipr_write_dump
+};
+#else
+static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
+#endif
+
+/**
+ * ipr_change_queue_depth - Change the device's queue depth
+ * @sdev:	scsi device struct
+ * @qdepth:	depth to set
+ *
+ * Return value:
+ * 	actual depth set
+ **/
+static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+	scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+	return sdev->queue_depth;
+}
+
+/**
+ * ipr_change_queue_type - Change the device's queue type
+ * @dsev:		scsi device struct
+ * @tag_type:	type of tags to use
+ *
+ * Return value:
+ * 	actual queue type set
+ **/
+static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type)
+{
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = (struct ipr_resource_entry *)sdev->hostdata;
+
+	if (res) {
+		if (ipr_is_gscsi(res) && sdev->tagged_supported) {
+			/*
+			 * We don't bother quiescing the device here since the
+			 * adapter firmware does it for us.
+			 */
+			scsi_set_tag_type(sdev, tag_type);
+
+			if (tag_type)
+				scsi_activate_tcq(sdev, sdev->queue_depth);
+			else
+				scsi_deactivate_tcq(sdev, sdev->queue_depth);
+		} else
+			tag_type = 0;
+	} else
+		tag_type = 0;
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return tag_type;
+}
+
+/**
+ * ipr_show_adapter_handle - Show the adapter's resource handle for this device
+ * @dev:	device struct
+ * @buf:	buffer
+ *
+ * Return value:
+ * 	number of bytes printed to buffer
+ **/
+static ssize_t ipr_show_adapter_handle(struct device *dev, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags = 0;
+	ssize_t len = -ENXIO;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = (struct ipr_resource_entry *)sdev->hostdata;
+	if (res)
+		len = snprintf(buf, PAGE_SIZE, "%08X\n", res->cfgte.res_handle);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return len;
+}
+
+static struct device_attribute ipr_adapter_handle_attr = {
+	.attr = {
+		.name = 	"adapter_handle",
+		.mode =		S_IRUSR,
+	},
+	.show = ipr_show_adapter_handle
+};
+
+static struct device_attribute *ipr_dev_attrs[] = {
+	&ipr_adapter_handle_attr,
+	NULL,
+};
+
+/**
+ * ipr_biosparam - Return the HSC mapping
+ * @sdev:			scsi device struct
+ * @block_device:	block device pointer
+ * @capacity:		capacity of the device
+ * @parm:			Array containing returned HSC values.
+ *
+ * This function generates the HSC parms that fdisk uses.
+ * We want to make sure we return something that places partitions
+ * on 4k boundaries for best performance with the IOA.
+ *
+ * Return value:
+ * 	0 on success
+ **/
+static int ipr_biosparam(struct scsi_device *sdev,
+			 struct block_device *block_device,
+			 sector_t capacity, int *parm)
+{
+	int heads, sectors;
+	sector_t cylinders;
+
+	heads = 128;
+	sectors = 32;
+
+	cylinders = capacity;
+	sector_div(cylinders, (128 * 32));
+
+	/* return result */
+	parm[0] = heads;
+	parm[1] = sectors;
+	parm[2] = cylinders;
+
+	return 0;
+}
+
+/**
+ * ipr_slave_destroy - Unconfigure a SCSI device
+ * @sdev:	scsi device struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_slave_destroy(struct scsi_device *sdev)
+{
+	struct ipr_resource_entry *res;
+	struct ipr_ioa_cfg *ioa_cfg;
+	unsigned long lock_flags = 0;
+
+	ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = (struct ipr_resource_entry *) sdev->hostdata;
+	if (res) {
+		sdev->hostdata = NULL;
+		res->sdev = NULL;
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+}
+
+/**
+ * ipr_slave_configure - Configure a SCSI device
+ * @sdev:	scsi device struct
+ *
+ * This function configures the specified scsi device.
+ *
+ * Return value:
+ * 	0 on success
+ **/
+static int ipr_slave_configure(struct scsi_device *sdev)
+{
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	res = sdev->hostdata;
+	if (res) {
+		if (ipr_is_af_dasd_device(res))
+			sdev->type = TYPE_RAID;
+		if (ipr_is_af_dasd_device(res) || ipr_is_ioa_resource(res))
+			sdev->scsi_level = 4;
+		if (ipr_is_vset_device(res)) {
+			sdev->timeout = IPR_VSET_RW_TIMEOUT;
+			blk_queue_max_sectors(sdev->request_queue, IPR_VSET_MAX_SECTORS);
+		}
+		if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data))
+			sdev->allow_restart = 1;
+		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+	}
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return 0;
+}
+
+/**
+ * ipr_slave_alloc - Prepare for commands to a device.
+ * @sdev:	scsi device struct
+ *
+ * This function saves a pointer to the resource entry
+ * in the scsi device struct if the device exists. We
+ * can then use this pointer in ipr_queuecommand when
+ * handling new commands.
+ *
+ * Return value:
+ * 	0 on success
+ **/
+static int ipr_slave_alloc(struct scsi_device *sdev)
+{
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *) sdev->host->hostdata;
+	struct ipr_resource_entry *res;
+	unsigned long lock_flags;
+
+	sdev->hostdata = NULL;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if ((res->cfgte.res_addr.bus == sdev->channel) &&
+		    (res->cfgte.res_addr.target == sdev->id) &&
+		    (res->cfgte.res_addr.lun == sdev->lun)) {
+			res->sdev = sdev;
+			res->add_to_ml = 0;
+			res->in_erp = 0;
+			sdev->hostdata = res;
+			res->needs_sync_complete = 1;
+			break;
+		}
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+
+	return 0;
+}
+
+/**
+ * ipr_eh_host_reset - Reset the host adapter
+ * @scsi_cmd:	scsi command struct
+ *
+ * Return value:
+ * 	SUCCESS / FAILED
+ **/
+static int ipr_eh_host_reset(struct scsi_cmnd * scsi_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg;
+	int rc;
+
+	ENTER;
+	ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
+
+	dev_err(&ioa_cfg->pdev->dev,
+		"Adapter being reset as a result of error recovery.\n");
+
+	if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+		ioa_cfg->sdt_state = GET_DUMP;
+
+	rc = ipr_reset_reload(ioa_cfg, IPR_SHUTDOWN_ABBREV);
+
+	LEAVE;
+	return rc;
+}
+
+/**
+ * ipr_eh_dev_reset - Reset the device
+ * @scsi_cmd:	scsi command struct
+ *
+ * This function issues a device reset to the affected device.
+ * A LUN reset will be sent to the device first. If that does
+ * not work, a target reset will be sent.
+ *
+ * Return value:
+ *	SUCCESS / FAILED
+ **/
+static int ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd)
+{
+	struct ipr_cmnd *ipr_cmd;
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_resource_entry *res;
+	struct ipr_cmd_pkt *cmd_pkt;
+	u32 ioasc;
+
+	ENTER;
+	ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
+	res = scsi_cmd->device->hostdata;
+
+	if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+		return FAILED;
+
+	/*
+	 * If we are currently going through reset/reload, return failed. This will force the
+	 * mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the
+	 * reset to complete
+	 */
+	if (ioa_cfg->in_reset_reload)
+		return FAILED;
+	if (ioa_cfg->ioa_is_dead)
+		return FAILED;
+
+	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+		if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) {
+			if (ipr_cmd->scsi_cmd)
+				ipr_cmd->done = ipr_scsi_eh_done;
+		}
+	}
+
+	res->resetting_device = 1;
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+
+	ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+	cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
+
+	ipr_sdev_err(scsi_cmd->device, "Resetting device\n");
+	ipr_send_blocking_cmd(ipr_cmd, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
+
+	ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	res->resetting_device = 0;
+
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+
+	LEAVE;
+	return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
+}
+
+/**
+ * ipr_bus_reset_done - Op done function for bus reset.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is the op done function for a bus reset
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_bus_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_resource_entry *res;
+
+	ENTER;
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (!memcmp(&res->cfgte.res_handle, &ipr_cmd->ioarcb.res_handle,
+			    sizeof(res->cfgte.res_handle))) {
+			scsi_report_bus_reset(ioa_cfg->host, res->cfgte.res_addr.bus);
+			break;
+		}
+	}
+
+	/*
+	 * If abort has not completed, indicate the reset has, else call the
+	 * abort's done function to wake the sleeping eh thread
+	 */
+	if (ipr_cmd->sibling->sibling)
+		ipr_cmd->sibling->sibling = NULL;
+	else
+		ipr_cmd->sibling->done(ipr_cmd->sibling);
+
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	LEAVE;
+}
+
+/**
+ * ipr_abort_timeout - An abort task has timed out
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function handles when an abort task times out. If this
+ * happens we issue a bus reset since we have resources tied
+ * up that must be freed before returning to the midlayer.
+ *
+ * Return value:
+ *	none
+ **/
+static void ipr_abort_timeout(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_cmnd *reset_cmd;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_cmd_pkt *cmd_pkt;
+	unsigned long lock_flags = 0;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	if (ipr_cmd->completion.done || ioa_cfg->in_reset_reload) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return;
+	}
+
+	ipr_sdev_err(ipr_cmd->u.sdev, "Abort timed out. Resetting bus\n");
+	reset_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ipr_cmd->sibling = reset_cmd;
+	reset_cmd->sibling = ipr_cmd;
+	reset_cmd->ioarcb.res_handle = ipr_cmd->ioarcb.res_handle;
+	cmd_pkt = &reset_cmd->ioarcb.cmd_pkt;
+	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+	cmd_pkt->cdb[0] = IPR_RESET_DEVICE;
+	cmd_pkt->cdb[2] = IPR_RESET_TYPE_SELECT | IPR_BUS_RESET;
+
+	ipr_do_req(reset_cmd, ipr_bus_reset_done, ipr_timeout, IPR_DEVICE_RESET_TIMEOUT);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	LEAVE;
+}
+
+/**
+ * ipr_cancel_op - Cancel specified op
+ * @scsi_cmd:	scsi command struct
+ *
+ * This function cancels specified op.
+ *
+ * Return value:
+ *	SUCCESS / FAILED
+ **/
+static int ipr_cancel_op(struct scsi_cmnd * scsi_cmd)
+{
+	struct ipr_cmnd *ipr_cmd;
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_resource_entry *res;
+	struct ipr_cmd_pkt *cmd_pkt;
+	u32 ioasc;
+	int op_found = 0;
+
+	ENTER;
+	ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
+	res = scsi_cmd->device->hostdata;
+
+	if (!res || (!ipr_is_gscsi(res) && !ipr_is_vset_device(res)))
+		return FAILED;
+
+	list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) {
+		if (ipr_cmd->scsi_cmd == scsi_cmd) {
+			ipr_cmd->done = ipr_scsi_eh_done;
+			op_found = 1;
+			break;
+		}
+	}
+
+	if (!op_found)
+		return SUCCESS;
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ipr_cmd->ioarcb.res_handle = res->cfgte.res_handle;
+	cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+	cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS;
+	ipr_cmd->u.sdev = scsi_cmd->device;
+
+	ipr_sdev_err(scsi_cmd->device, "Aborting command: %02X\n", scsi_cmd->cmnd[0]);
+	ipr_send_blocking_cmd(ipr_cmd, ipr_abort_timeout, IPR_CANCEL_ALL_TIMEOUT);
+	ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	/*
+	 * If the abort task timed out and we sent a bus reset, we will get
+	 * one the following responses to the abort
+	 */
+	if (ioasc == IPR_IOASC_BUS_WAS_RESET || ioasc == IPR_IOASC_SYNC_REQUIRED) {
+		ioasc = 0;
+		ipr_trace;
+	}
+
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	res->needs_sync_complete = 1;
+
+	LEAVE;
+	return (IPR_IOASC_SENSE_KEY(ioasc) ? FAILED : SUCCESS);
+}
+
+/**
+ * ipr_eh_abort - Abort a single op
+ * @scsi_cmd:	scsi command struct
+ *
+ * Return value:
+ * 	SUCCESS / FAILED
+ **/
+static int ipr_eh_abort(struct scsi_cmnd * scsi_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg;
+
+	ENTER;
+	ioa_cfg = (struct ipr_ioa_cfg *) scsi_cmd->device->host->hostdata;
+
+	/* If we are currently going through reset/reload, return failed. This will force the
+	   mid-layer to call ipr_eh_host_reset, which will then go to sleep and wait for the
+	   reset to complete */
+	if (ioa_cfg->in_reset_reload)
+		return FAILED;
+	if (ioa_cfg->ioa_is_dead)
+		return FAILED;
+	if (!scsi_cmd->device->hostdata)
+		return FAILED;
+
+	LEAVE;
+	return ipr_cancel_op(scsi_cmd);
+}
+
+/**
+ * ipr_handle_other_interrupt - Handle "other" interrupts
+ * @ioa_cfg:	ioa config struct
+ * @int_reg:	interrupt register
+ *
+ * Return value:
+ * 	IRQ_NONE / IRQ_HANDLED
+ **/
+static irqreturn_t ipr_handle_other_interrupt(struct ipr_ioa_cfg *ioa_cfg,
+					      volatile u32 int_reg)
+{
+	irqreturn_t rc = IRQ_HANDLED;
+
+	if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
+		/* Mask the interrupt */
+		writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.set_interrupt_mask_reg);
+
+		/* Clear the interrupt */
+		writel(IPR_PCII_IOA_TRANS_TO_OPER, ioa_cfg->regs.clr_interrupt_reg);
+		int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+
+		list_del(&ioa_cfg->reset_cmd->queue);
+		del_timer(&ioa_cfg->reset_cmd->timer);
+		ipr_reset_ioa_job(ioa_cfg->reset_cmd);
+	} else {
+		if (int_reg & IPR_PCII_IOA_UNIT_CHECKED)
+			ioa_cfg->ioa_unit_checked = 1;
+		else
+			dev_err(&ioa_cfg->pdev->dev,
+				"Permanent IOA failure. 0x%08X\n", int_reg);
+
+		if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+			ioa_cfg->sdt_state = GET_DUMP;
+
+		ipr_mask_and_clear_interrupts(ioa_cfg, ~0);
+		ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+	}
+
+	return rc;
+}
+
+/**
+ * ipr_isr - Interrupt service routine
+ * @irq:	irq number
+ * @devp:	pointer to ioa config struct
+ * @regs:	pt_regs struct
+ *
+ * Return value:
+ * 	IRQ_NONE / IRQ_HANDLED
+ **/
+static irqreturn_t ipr_isr(int irq, void *devp, struct pt_regs *regs)
+{
+	struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)devp;
+	unsigned long lock_flags = 0;
+	volatile u32 int_reg, int_mask_reg;
+	u32 ioasc;
+	u16 cmd_index;
+	struct ipr_cmnd *ipr_cmd;
+	irqreturn_t rc = IRQ_NONE;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	/* If interrupts are disabled, ignore the interrupt */
+	if (!ioa_cfg->allow_interrupts) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return IRQ_NONE;
+	}
+
+	int_mask_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+	int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+
+	/* If an interrupt on the adapter did not occur, ignore it */
+	if (unlikely((int_reg & IPR_PCII_OPER_INTERRUPTS) == 0)) {
+		spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+		return IRQ_NONE;
+	}
+
+	while (1) {
+		ipr_cmd = NULL;
+
+		while ((be32_to_cpu(*ioa_cfg->hrrq_curr) & IPR_HRRQ_TOGGLE_BIT) ==
+		       ioa_cfg->toggle_bit) {
+
+			cmd_index = (be32_to_cpu(*ioa_cfg->hrrq_curr) &
+				     IPR_HRRQ_REQ_RESP_HANDLE_MASK) >> IPR_HRRQ_REQ_RESP_HANDLE_SHIFT;
+
+			if (unlikely(cmd_index >= IPR_NUM_CMD_BLKS)) {
+				ioa_cfg->errors_logged++;
+				dev_err(&ioa_cfg->pdev->dev, "Invalid response handle from IOA\n");
+
+				if (WAIT_FOR_DUMP == ioa_cfg->sdt_state)
+					ioa_cfg->sdt_state = GET_DUMP;
+
+				ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+				spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+				return IRQ_HANDLED;
+			}
+
+			ipr_cmd = ioa_cfg->ipr_cmnd_list[cmd_index];
+
+			ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+			ipr_trc_hook(ipr_cmd, IPR_TRACE_FINISH, ioasc);
+
+			list_del(&ipr_cmd->queue);
+			del_timer(&ipr_cmd->timer);
+			ipr_cmd->done(ipr_cmd);
+
+			rc = IRQ_HANDLED;
+
+			if (ioa_cfg->hrrq_curr < ioa_cfg->hrrq_end) {
+				ioa_cfg->hrrq_curr++;
+			} else {
+				ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start;
+				ioa_cfg->toggle_bit ^= 1u;
+			}
+		}
+
+		if (ipr_cmd != NULL) {
+			/* Clear the PCI interrupt */
+			writel(IPR_PCII_HRRQ_UPDATED, ioa_cfg->regs.clr_interrupt_reg);
+			int_reg = readl(ioa_cfg->regs.sense_interrupt_reg) & ~int_mask_reg;
+		} else
+			break;
+	}
+
+	if (unlikely(rc == IRQ_NONE))
+		rc = ipr_handle_other_interrupt(ioa_cfg, int_reg);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	return rc;
+}
+
+/**
+ * ipr_build_ioadl - Build a scatter/gather list and map the buffer
+ * @ioa_cfg:	ioa config struct
+ * @ipr_cmd:	ipr command struct
+ *
+ * Return value:
+ * 	0 on success / -1 on failure
+ **/
+static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
+			   struct ipr_cmnd *ipr_cmd)
+{
+	int i;
+	struct scatterlist *sglist;
+	u32 length;
+	u32 ioadl_flags = 0;
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+
+	length = scsi_cmd->request_bufflen;
+
+	if (length == 0)
+		return 0;
+
+	if (scsi_cmd->use_sg) {
+		ipr_cmd->dma_use_sg = pci_map_sg(ioa_cfg->pdev,
+						 scsi_cmd->request_buffer,
+						 scsi_cmd->use_sg,
+						 scsi_cmd->sc_data_direction);
+
+		if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
+			ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+			ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+			ioarcb->write_data_transfer_length = cpu_to_be32(length);
+			ioarcb->write_ioadl_len =
+				cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+		} else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
+			ioadl_flags = IPR_IOADL_FLAGS_READ;
+			ioarcb->read_data_transfer_length = cpu_to_be32(length);
+			ioarcb->read_ioadl_len =
+				cpu_to_be32(sizeof(struct ipr_ioadl_desc) * ipr_cmd->dma_use_sg);
+		}
+
+		sglist = scsi_cmd->request_buffer;
+
+		for (i = 0; i < ipr_cmd->dma_use_sg; i++) {
+			ioadl[i].flags_and_data_len =
+				cpu_to_be32(ioadl_flags | sg_dma_len(&sglist[i]));
+			ioadl[i].address =
+				cpu_to_be32(sg_dma_address(&sglist[i]));
+		}
+
+		if (likely(ipr_cmd->dma_use_sg)) {
+			ioadl[i-1].flags_and_data_len |=
+				cpu_to_be32(IPR_IOADL_FLAGS_LAST);
+			return 0;
+		} else
+			dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+	} else {
+		if (scsi_cmd->sc_data_direction == DMA_TO_DEVICE) {
+			ioadl_flags = IPR_IOADL_FLAGS_WRITE;
+			ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+			ioarcb->write_data_transfer_length = cpu_to_be32(length);
+			ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+		} else if (scsi_cmd->sc_data_direction == DMA_FROM_DEVICE) {
+			ioadl_flags = IPR_IOADL_FLAGS_READ;
+			ioarcb->read_data_transfer_length = cpu_to_be32(length);
+			ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+		}
+
+		ipr_cmd->dma_handle = pci_map_single(ioa_cfg->pdev,
+						     scsi_cmd->request_buffer, length,
+						     scsi_cmd->sc_data_direction);
+
+		if (likely(!pci_dma_mapping_error(ipr_cmd->dma_handle))) {
+			ipr_cmd->dma_use_sg = 1;
+			ioadl[0].flags_and_data_len =
+				cpu_to_be32(ioadl_flags | length | IPR_IOADL_FLAGS_LAST);
+			ioadl[0].address = cpu_to_be32(ipr_cmd->dma_handle);
+			return 0;
+		} else
+			dev_err(&ioa_cfg->pdev->dev, "pci_map_single failed!\n");
+	}
+
+	return -1;
+}
+
+/**
+ * ipr_get_task_attributes - Translate SPI Q-Tag to task attributes
+ * @scsi_cmd:	scsi command struct
+ *
+ * Return value:
+ * 	task attributes
+ **/
+static u8 ipr_get_task_attributes(struct scsi_cmnd *scsi_cmd)
+{
+	u8 tag[2];
+	u8 rc = IPR_FLAGS_LO_UNTAGGED_TASK;
+
+	if (scsi_populate_tag_msg(scsi_cmd, tag)) {
+		switch (tag[0]) {
+		case MSG_SIMPLE_TAG:
+			rc = IPR_FLAGS_LO_SIMPLE_TASK;
+			break;
+		case MSG_HEAD_TAG:
+			rc = IPR_FLAGS_LO_HEAD_OF_Q_TASK;
+			break;
+		case MSG_ORDERED_TAG:
+			rc = IPR_FLAGS_LO_ORDERED_TASK;
+			break;
+		};
+	}
+
+	return rc;
+}
+
+/**
+ * ipr_erp_done - Process completion of ERP for a device
+ * @ipr_cmd:		ipr command struct
+ *
+ * This function copies the sense buffer into the scsi_cmd
+ * struct and pushes the scsi_done function.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_erp_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+	struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
+		scsi_cmd->result |= (DID_ERROR << 16);
+		ipr_sdev_err(scsi_cmd->device,
+			     "Request Sense failed with IOASC: 0x%08X\n", ioasc);
+	} else {
+		memcpy(scsi_cmd->sense_buffer, ipr_cmd->sense_buffer,
+		       SCSI_SENSE_BUFFERSIZE);
+	}
+
+	if (res) {
+		res->needs_sync_complete = 1;
+		res->in_erp = 0;
+	}
+	ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	scsi_cmd->scsi_done(scsi_cmd);
+}
+
+/**
+ * ipr_reinit_ipr_cmnd_for_erp - Re-initialize a cmnd block to be used for ERP
+ * @ipr_cmd:	ipr command struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_reinit_ipr_cmnd_for_erp(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioarcb *ioarcb;
+	struct ipr_ioasa *ioasa;
+
+	ioarcb = &ipr_cmd->ioarcb;
+	ioasa = &ipr_cmd->ioasa;
+
+	memset(&ioarcb->cmd_pkt, 0, sizeof(struct ipr_cmd_pkt));
+	ioarcb->write_data_transfer_length = 0;
+	ioarcb->read_data_transfer_length = 0;
+	ioarcb->write_ioadl_len = 0;
+	ioarcb->read_ioadl_len = 0;
+	ioasa->ioasc = 0;
+	ioasa->residual_data_len = 0;
+}
+
+/**
+ * ipr_erp_request_sense - Send request sense to a device
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a request sense to a device as a result
+ * of a check condition.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_erp_request_sense(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_cmd_pkt *cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (IPR_IOASC_SENSE_KEY(ioasc) > 0) {
+		ipr_erp_done(ipr_cmd);
+		return;
+	}
+
+	ipr_reinit_ipr_cmnd_for_erp(ipr_cmd);
+
+	cmd_pkt->request_type = IPR_RQTYPE_SCSICDB;
+	cmd_pkt->cdb[0] = REQUEST_SENSE;
+	cmd_pkt->cdb[4] = SCSI_SENSE_BUFFERSIZE;
+	cmd_pkt->flags_hi |= IPR_FLAGS_HI_SYNC_OVERRIDE;
+	cmd_pkt->flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
+	cmd_pkt->timeout = cpu_to_be16(IPR_REQUEST_SENSE_TIMEOUT / HZ);
+
+	ipr_cmd->ioadl[0].flags_and_data_len =
+		cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | SCSI_SENSE_BUFFERSIZE);
+	ipr_cmd->ioadl[0].address =
+		cpu_to_be32(ipr_cmd->sense_buffer_dma);
+
+	ipr_cmd->ioarcb.read_ioadl_len =
+		cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+	ipr_cmd->ioarcb.read_data_transfer_length =
+		cpu_to_be32(SCSI_SENSE_BUFFERSIZE);
+
+	ipr_do_req(ipr_cmd, ipr_erp_done, ipr_timeout,
+		   IPR_REQUEST_SENSE_TIMEOUT * 2);
+}
+
+/**
+ * ipr_erp_cancel_all - Send cancel all to a device
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a cancel all to a device to clear the
+ * queue. If we are running TCQ on the device, QERR is set to 1,
+ * which means all outstanding ops have been dropped on the floor.
+ * Cancel all will return them to us.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_erp_cancel_all(struct ipr_cmnd *ipr_cmd)
+{
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+	struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
+	struct ipr_cmd_pkt *cmd_pkt;
+
+	res->in_erp = 1;
+
+	ipr_reinit_ipr_cmnd_for_erp(ipr_cmd);
+
+	if (!scsi_get_tag_type(scsi_cmd->device)) {
+		ipr_erp_request_sense(ipr_cmd);
+		return;
+	}
+
+	cmd_pkt = &ipr_cmd->ioarcb.cmd_pkt;
+	cmd_pkt->request_type = IPR_RQTYPE_IOACMD;
+	cmd_pkt->cdb[0] = IPR_CANCEL_ALL_REQUESTS;
+
+	ipr_do_req(ipr_cmd, ipr_erp_request_sense, ipr_timeout,
+		   IPR_CANCEL_ALL_TIMEOUT);
+}
+
+/**
+ * ipr_dump_ioasa - Dump contents of IOASA
+ * @ioa_cfg:	ioa config struct
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is invoked by the interrupt handler when ops
+ * fail. It will log the IOASA if appropriate. Only called
+ * for GPDD ops.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_dump_ioasa(struct ipr_ioa_cfg *ioa_cfg,
+			   struct ipr_cmnd *ipr_cmd)
+{
+	int i;
+	u16 data_len;
+	u32 ioasc;
+	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+	__be32 *ioasa_data = (__be32 *)ioasa;
+	int error_index;
+
+	ioasc = be32_to_cpu(ioasa->ioasc) & IPR_IOASC_IOASC_MASK;
+
+	if (0 == ioasc)
+		return;
+
+	if (ioa_cfg->log_level < IPR_DEFAULT_LOG_LEVEL)
+		return;
+
+	error_index = ipr_get_error(ioasc);
+
+	if (ioa_cfg->log_level < IPR_MAX_LOG_LEVEL) {
+		/* Don't log an error if the IOA already logged one */
+		if (ioasa->ilid != 0)
+			return;
+
+		if (ipr_error_table[error_index].log_ioasa == 0)
+			return;
+	}
+
+	ipr_sdev_err(ipr_cmd->scsi_cmd->device, "%s\n",
+		     ipr_error_table[error_index].error);
+
+	if ((ioasa->u.gpdd.end_state <= ARRAY_SIZE(ipr_gpdd_dev_end_states)) &&
+	    (ioasa->u.gpdd.bus_phase <=  ARRAY_SIZE(ipr_gpdd_dev_bus_phases))) {
+		ipr_sdev_err(ipr_cmd->scsi_cmd->device,
+			     "Device End state: %s Phase: %s\n",
+			     ipr_gpdd_dev_end_states[ioasa->u.gpdd.end_state],
+			     ipr_gpdd_dev_bus_phases[ioasa->u.gpdd.bus_phase]);
+	}
+
+	if (sizeof(struct ipr_ioasa) < be16_to_cpu(ioasa->ret_stat_len))
+		data_len = sizeof(struct ipr_ioasa);
+	else
+		data_len = be16_to_cpu(ioasa->ret_stat_len);
+
+	ipr_err("IOASA Dump:\n");
+
+	for (i = 0; i < data_len / 4; i += 4) {
+		ipr_err("%08X: %08X %08X %08X %08X\n", i*4,
+			be32_to_cpu(ioasa_data[i]),
+			be32_to_cpu(ioasa_data[i+1]),
+			be32_to_cpu(ioasa_data[i+2]),
+			be32_to_cpu(ioasa_data[i+3]));
+	}
+}
+
+/**
+ * ipr_gen_sense - Generate SCSI sense data from an IOASA
+ * @ioasa:		IOASA
+ * @sense_buf:	sense data buffer
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_gen_sense(struct ipr_cmnd *ipr_cmd)
+{
+	u32 failing_lba;
+	u8 *sense_buf = ipr_cmd->scsi_cmd->sense_buffer;
+	struct ipr_resource_entry *res = ipr_cmd->scsi_cmd->device->hostdata;
+	struct ipr_ioasa *ioasa = &ipr_cmd->ioasa;
+	u32 ioasc = be32_to_cpu(ioasa->ioasc);
+
+	memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
+
+	if (ioasc >= IPR_FIRST_DRIVER_IOASC)
+		return;
+
+	ipr_cmd->scsi_cmd->result = SAM_STAT_CHECK_CONDITION;
+
+	if (ipr_is_vset_device(res) &&
+	    ioasc == IPR_IOASC_MED_DO_NOT_REALLOC &&
+	    ioasa->u.vset.failing_lba_hi != 0) {
+		sense_buf[0] = 0x72;
+		sense_buf[1] = IPR_IOASC_SENSE_KEY(ioasc);
+		sense_buf[2] = IPR_IOASC_SENSE_CODE(ioasc);
+		sense_buf[3] = IPR_IOASC_SENSE_QUAL(ioasc);
+
+		sense_buf[7] = 12;
+		sense_buf[8] = 0;
+		sense_buf[9] = 0x0A;
+		sense_buf[10] = 0x80;
+
+		failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_hi);
+
+		sense_buf[12] = (failing_lba & 0xff000000) >> 24;
+		sense_buf[13] = (failing_lba & 0x00ff0000) >> 16;
+		sense_buf[14] = (failing_lba & 0x0000ff00) >> 8;
+		sense_buf[15] = failing_lba & 0x000000ff;
+
+		failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo);
+
+		sense_buf[16] = (failing_lba & 0xff000000) >> 24;
+		sense_buf[17] = (failing_lba & 0x00ff0000) >> 16;
+		sense_buf[18] = (failing_lba & 0x0000ff00) >> 8;
+		sense_buf[19] = failing_lba & 0x000000ff;
+	} else {
+		sense_buf[0] = 0x70;
+		sense_buf[2] = IPR_IOASC_SENSE_KEY(ioasc);
+		sense_buf[12] = IPR_IOASC_SENSE_CODE(ioasc);
+		sense_buf[13] = IPR_IOASC_SENSE_QUAL(ioasc);
+
+		/* Illegal request */
+		if ((IPR_IOASC_SENSE_KEY(ioasc) == 0x05) &&
+		    (be32_to_cpu(ioasa->ioasc_specific) & IPR_FIELD_POINTER_VALID)) {
+			sense_buf[7] = 10;	/* additional length */
+
+			/* IOARCB was in error */
+			if (IPR_IOASC_SENSE_CODE(ioasc) == 0x24)
+				sense_buf[15] = 0xC0;
+			else	/* Parameter data was invalid */
+				sense_buf[15] = 0x80;
+
+			sense_buf[16] =
+			    ((IPR_FIELD_POINTER_MASK &
+			      be32_to_cpu(ioasa->ioasc_specific)) >> 8) & 0xff;
+			sense_buf[17] =
+			    (IPR_FIELD_POINTER_MASK &
+			     be32_to_cpu(ioasa->ioasc_specific)) & 0xff;
+		} else {
+			if (ioasc == IPR_IOASC_MED_DO_NOT_REALLOC) {
+				if (ipr_is_vset_device(res))
+					failing_lba = be32_to_cpu(ioasa->u.vset.failing_lba_lo);
+				else
+					failing_lba = be32_to_cpu(ioasa->u.dasd.failing_lba);
+
+				sense_buf[0] |= 0x80;	/* Or in the Valid bit */
+				sense_buf[3] = (failing_lba & 0xff000000) >> 24;
+				sense_buf[4] = (failing_lba & 0x00ff0000) >> 16;
+				sense_buf[5] = (failing_lba & 0x0000ff00) >> 8;
+				sense_buf[6] = failing_lba & 0x000000ff;
+			}
+
+			sense_buf[7] = 6;	/* additional length */
+		}
+	}
+}
+
+/**
+ * ipr_erp_start - Process an error response for a SCSI op
+ * @ioa_cfg:	ioa config struct
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function determines whether or not to initiate ERP
+ * on the affected device.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_erp_start(struct ipr_ioa_cfg *ioa_cfg,
+			      struct ipr_cmnd *ipr_cmd)
+{
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+	struct ipr_resource_entry *res = scsi_cmd->device->hostdata;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	if (!res) {
+		ipr_scsi_eh_done(ipr_cmd);
+		return;
+	}
+
+	if (ipr_is_gscsi(res))
+		ipr_dump_ioasa(ioa_cfg, ipr_cmd);
+	else
+		ipr_gen_sense(ipr_cmd);
+
+	switch (ioasc & IPR_IOASC_IOASC_MASK) {
+	case IPR_IOASC_ABORTED_CMD_TERM_BY_HOST:
+		scsi_cmd->result |= (DID_IMM_RETRY << 16);
+		break;
+	case IPR_IOASC_IR_RESOURCE_HANDLE:
+		scsi_cmd->result |= (DID_NO_CONNECT << 16);
+		break;
+	case IPR_IOASC_HW_SEL_TIMEOUT:
+		scsi_cmd->result |= (DID_NO_CONNECT << 16);
+		res->needs_sync_complete = 1;
+		break;
+	case IPR_IOASC_SYNC_REQUIRED:
+		if (!res->in_erp)
+			res->needs_sync_complete = 1;
+		scsi_cmd->result |= (DID_IMM_RETRY << 16);
+		break;
+	case IPR_IOASC_MED_DO_NOT_REALLOC: /* prevent retries */
+		scsi_cmd->result |= (DID_PASSTHROUGH << 16);
+		break;
+	case IPR_IOASC_BUS_WAS_RESET:
+	case IPR_IOASC_BUS_WAS_RESET_BY_OTHER:
+		/*
+		 * Report the bus reset and ask for a retry. The device
+		 * will give CC/UA the next command.
+		 */
+		if (!res->resetting_device)
+			scsi_report_bus_reset(ioa_cfg->host, scsi_cmd->device->channel);
+		scsi_cmd->result |= (DID_ERROR << 16);
+		res->needs_sync_complete = 1;
+		break;
+	case IPR_IOASC_HW_DEV_BUS_STATUS:
+		scsi_cmd->result |= IPR_IOASC_SENSE_STATUS(ioasc);
+		if (IPR_IOASC_SENSE_STATUS(ioasc) == SAM_STAT_CHECK_CONDITION) {
+			ipr_erp_cancel_all(ipr_cmd);
+			return;
+		}
+		res->needs_sync_complete = 1;
+		break;
+	case IPR_IOASC_NR_INIT_CMD_REQUIRED:
+		break;
+	default:
+		scsi_cmd->result |= (DID_ERROR << 16);
+		if (!ipr_is_vset_device(res))
+			res->needs_sync_complete = 1;
+		break;
+	}
+
+	ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	scsi_cmd->scsi_done(scsi_cmd);
+}
+
+/**
+ * ipr_scsi_done - mid-layer done function
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is invoked by the interrupt handler for
+ * ops generated by the SCSI mid-layer
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_scsi_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct scsi_cmnd *scsi_cmd = ipr_cmd->scsi_cmd;
+	u32 ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+	scsi_cmd->resid = be32_to_cpu(ipr_cmd->ioasa.residual_data_len);
+
+	if (likely(IPR_IOASC_SENSE_KEY(ioasc) == 0)) {
+		ipr_unmap_sglist(ioa_cfg, ipr_cmd);
+		list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+		scsi_cmd->scsi_done(scsi_cmd);
+	} else
+		ipr_erp_start(ioa_cfg, ipr_cmd);
+}
+
+/**
+ * ipr_save_ioafp_mode_select - Save adapters mode select data
+ * @ioa_cfg:	ioa config struct
+ * @scsi_cmd:	scsi command struct
+ *
+ * This function saves mode select data for the adapter to
+ * use following an adapter reset.
+ *
+ * Return value:
+ *	0 on success / SCSI_MLQUEUE_HOST_BUSY on failure
+ **/
+static int ipr_save_ioafp_mode_select(struct ipr_ioa_cfg *ioa_cfg,
+				       struct scsi_cmnd *scsi_cmd)
+{
+	if (!ioa_cfg->saved_mode_pages) {
+		ioa_cfg->saved_mode_pages  = kmalloc(sizeof(struct ipr_mode_pages),
+						     GFP_ATOMIC);
+		if (!ioa_cfg->saved_mode_pages) {
+			dev_err(&ioa_cfg->pdev->dev,
+				"IOA mode select buffer allocation failed\n");
+			return SCSI_MLQUEUE_HOST_BUSY;
+		}
+	}
+
+	memcpy(ioa_cfg->saved_mode_pages, scsi_cmd->buffer, scsi_cmd->cmnd[4]);
+	ioa_cfg->saved_mode_page_len = scsi_cmd->cmnd[4];
+	return 0;
+}
+
+/**
+ * ipr_queuecommand - Queue a mid-layer request
+ * @scsi_cmd:	scsi command struct
+ * @done:		done function
+ *
+ * This function queues a request generated by the mid-layer.
+ *
+ * Return value:
+ *	0 on success
+ *	SCSI_MLQUEUE_DEVICE_BUSY if device is busy
+ *	SCSI_MLQUEUE_HOST_BUSY if host is busy
+ **/
+static int ipr_queuecommand(struct scsi_cmnd *scsi_cmd,
+			    void (*done) (struct scsi_cmnd *))
+{
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_resource_entry *res;
+	struct ipr_ioarcb *ioarcb;
+	struct ipr_cmnd *ipr_cmd;
+	int rc = 0;
+
+	scsi_cmd->scsi_done = done;
+	ioa_cfg = (struct ipr_ioa_cfg *)scsi_cmd->device->host->hostdata;
+	res = scsi_cmd->device->hostdata;
+	scsi_cmd->result = (DID_OK << 16);
+
+	/*
+	 * We are currently blocking all devices due to a host reset
+	 * We have told the host to stop giving us new requests, but
+	 * ERP ops don't count. FIXME
+	 */
+	if (unlikely(!ioa_cfg->allow_cmds && !ioa_cfg->ioa_is_dead))
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	/*
+	 * FIXME - Create scsi_set_host_offline interface
+	 *  and the ioa_is_dead check can be removed
+	 */
+	if (unlikely(ioa_cfg->ioa_is_dead || !res)) {
+		memset(scsi_cmd->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+		scsi_cmd->result = (DID_NO_CONNECT << 16);
+		scsi_cmd->scsi_done(scsi_cmd);
+		return 0;
+	}
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ioarcb = &ipr_cmd->ioarcb;
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+
+	memcpy(ioarcb->cmd_pkt.cdb, scsi_cmd->cmnd, scsi_cmd->cmd_len);
+	ipr_cmd->scsi_cmd = scsi_cmd;
+	ioarcb->res_handle = res->cfgte.res_handle;
+	ipr_cmd->done = ipr_scsi_done;
+	ipr_trc_hook(ipr_cmd, IPR_TRACE_START, IPR_GET_PHYS_LOC(res->cfgte.res_addr));
+
+	if (ipr_is_gscsi(res) || ipr_is_vset_device(res)) {
+		if (scsi_cmd->underflow == 0)
+			ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_ULEN_CHK;
+
+		if (res->needs_sync_complete) {
+			ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_SYNC_COMPLETE;
+			res->needs_sync_complete = 0;
+		}
+
+		ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_NO_LINK_DESC;
+		ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
+		ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
+		ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
+	}
+
+	if (scsi_cmd->cmnd[0] >= 0xC0 &&
+	    (!ipr_is_gscsi(res) || scsi_cmd->cmnd[0] == IPR_QUERY_RSRC_STATE))
+		ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+
+	if (ipr_is_ioa_resource(res) && scsi_cmd->cmnd[0] == MODE_SELECT)
+		rc = ipr_save_ioafp_mode_select(ioa_cfg, scsi_cmd);
+
+	if (likely(rc == 0))
+		rc = ipr_build_ioadl(ioa_cfg, ipr_cmd);
+
+	if (likely(rc == 0)) {
+		mb();
+		writel(be32_to_cpu(ipr_cmd->ioarcb.ioarcb_host_pci_addr),
+		       ioa_cfg->regs.ioarrin_reg);
+	} else {
+		 list_move_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+		 return SCSI_MLQUEUE_HOST_BUSY;
+	}
+
+	return 0;
+}
+
+/**
+ * ipr_info - Get information about the card/driver
+ * @scsi_host:	scsi host struct
+ *
+ * Return value:
+ * 	pointer to buffer with description string
+ **/
+static const char * ipr_ioa_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	struct ipr_ioa_cfg *ioa_cfg;
+	unsigned long lock_flags = 0;
+
+	ioa_cfg = (struct ipr_ioa_cfg *) host->hostdata;
+
+	spin_lock_irqsave(host->host_lock, lock_flags);
+	sprintf(buffer, "IBM %X Storage Adapter", ioa_cfg->type);
+	spin_unlock_irqrestore(host->host_lock, lock_flags);
+
+	return buffer;
+}
+
+static struct scsi_host_template driver_template = {
+	.module = THIS_MODULE,
+	.name = "IPR",
+	.info = ipr_ioa_info,
+	.queuecommand = ipr_queuecommand,
+	.eh_abort_handler = ipr_eh_abort,
+	.eh_device_reset_handler = ipr_eh_dev_reset,
+	.eh_host_reset_handler = ipr_eh_host_reset,
+	.slave_alloc = ipr_slave_alloc,
+	.slave_configure = ipr_slave_configure,
+	.slave_destroy = ipr_slave_destroy,
+	.change_queue_depth = ipr_change_queue_depth,
+	.change_queue_type = ipr_change_queue_type,
+	.bios_param = ipr_biosparam,
+	.can_queue = IPR_MAX_COMMANDS,
+	.this_id = -1,
+	.sg_tablesize = IPR_MAX_SGLIST,
+	.max_sectors = IPR_IOA_MAX_SECTORS,
+	.cmd_per_lun = IPR_MAX_CMD_PER_LUN,
+	.use_clustering = ENABLE_CLUSTERING,
+	.shost_attrs = ipr_ioa_attrs,
+	.sdev_attrs = ipr_dev_attrs,
+	.proc_name = IPR_NAME
+};
+
+#ifdef CONFIG_PPC_PSERIES
+static const u16 ipr_blocked_processors[] = {
+	PV_NORTHSTAR,
+	PV_PULSAR,
+	PV_POWER4,
+	PV_ICESTAR,
+	PV_SSTAR,
+	PV_POWER4p,
+	PV_630,
+	PV_630p
+};
+
+/**
+ * ipr_invalid_adapter - Determine if this adapter is supported on this hardware
+ * @ioa_cfg:	ioa cfg struct
+ *
+ * Adapters that use Gemstone revision < 3.1 do not work reliably on
+ * certain pSeries hardware. This function determines if the given
+ * adapter is in one of these confgurations or not.
+ *
+ * Return value:
+ * 	1 if adapter is not supported / 0 if adapter is supported
+ **/
+static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg)
+{
+	u8 rev_id;
+	int i;
+
+	if (ioa_cfg->type == 0x5702) {
+		if (pci_read_config_byte(ioa_cfg->pdev, PCI_REVISION_ID,
+					 &rev_id) == PCIBIOS_SUCCESSFUL) {
+			if (rev_id < 4) {
+				for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++){
+					if (__is_processor(ipr_blocked_processors[i]))
+						return 1;
+				}
+			}
+		}
+	}
+	return 0;
+}
+#else
+#define ipr_invalid_adapter(ioa_cfg) 0
+#endif
+
+/**
+ * ipr_ioa_bringdown_done - IOA bring down completion.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function processes the completion of an adapter bring down.
+ * It wakes any reset sleepers.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioa_bringdown_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	ioa_cfg->in_reset_reload = 0;
+	ioa_cfg->reset_retries = 0;
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	wake_up_all(&ioa_cfg->reset_wait_q);
+
+	spin_unlock_irq(ioa_cfg->host->host_lock);
+	scsi_unblock_requests(ioa_cfg->host);
+	spin_lock_irq(ioa_cfg->host->host_lock);
+	LEAVE;
+
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_ioa_reset_done - IOA reset completion.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function processes the completion of an adapter reset.
+ * It schedules any necessary mid-layer add/removes and
+ * wakes any reset sleepers.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioa_reset_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_resource_entry *res;
+	struct ipr_hostrcb *hostrcb, *temp;
+	int i = 0;
+
+	ENTER;
+	ioa_cfg->in_reset_reload = 0;
+	ioa_cfg->allow_cmds = 1;
+	ioa_cfg->reset_cmd = NULL;
+
+	list_for_each_entry(res, &ioa_cfg->used_res_q, queue) {
+		if (ioa_cfg->allow_ml_add_del && (res->add_to_ml || res->del_from_ml)) {
+			ipr_trace;
+			break;
+		}
+	}
+	schedule_work(&ioa_cfg->work_q);
+
+	list_for_each_entry_safe(hostrcb, temp, &ioa_cfg->hostrcb_free_q, queue) {
+		list_del(&hostrcb->queue);
+		if (i++ < IPR_NUM_LOG_HCAMS)
+			ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_LOG_DATA, hostrcb);
+		else
+			ipr_send_hcam(ioa_cfg, IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE, hostrcb);
+	}
+
+	dev_info(&ioa_cfg->pdev->dev, "IOA initialized.\n");
+
+	ioa_cfg->reset_retries = 0;
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	wake_up_all(&ioa_cfg->reset_wait_q);
+
+	spin_unlock_irq(ioa_cfg->host->host_lock);
+	scsi_unblock_requests(ioa_cfg->host);
+	spin_lock_irq(ioa_cfg->host->host_lock);
+
+	if (!ioa_cfg->allow_cmds)
+		scsi_block_requests(ioa_cfg->host);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_set_sup_dev_dflt - Initialize a Set Supported Device buffer
+ * @supported_dev:	supported device struct
+ * @vpids:			vendor product id struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_set_sup_dev_dflt(struct ipr_supported_device *supported_dev,
+				 struct ipr_std_inq_vpids *vpids)
+{
+	memset(supported_dev, 0, sizeof(struct ipr_supported_device));
+	memcpy(&supported_dev->vpids, vpids, sizeof(struct ipr_std_inq_vpids));
+	supported_dev->num_records = 1;
+	supported_dev->data_length =
+		cpu_to_be16(sizeof(struct ipr_supported_device));
+	supported_dev->reserved = 0;
+}
+
+/**
+ * ipr_set_supported_devs - Send Set Supported Devices for a device
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function send a Set Supported Devices to the adapter
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_set_supported_devs(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_supported_device *supp_dev = &ioa_cfg->vpd_cbs->supp_dev;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_resource_entry *res = ipr_cmd->u.res;
+
+	ipr_cmd->job_step = ipr_ioa_reset_done;
+
+	list_for_each_entry_continue(res, &ioa_cfg->used_res_q, queue) {
+		if (!ipr_is_af_dasd_device(res))
+			continue;
+
+		ipr_cmd->u.res = res;
+		ipr_set_sup_dev_dflt(supp_dev, &res->cfgte.std_inq_data.vpids);
+
+		ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+		ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+		ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+
+		ioarcb->cmd_pkt.cdb[0] = IPR_SET_SUPPORTED_DEVICES;
+		ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_supported_device) >> 8) & 0xff;
+		ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_supported_device) & 0xff;
+
+		ioadl->flags_and_data_len = cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST |
+							sizeof(struct ipr_supported_device));
+		ioadl->address = cpu_to_be32(ioa_cfg->vpd_cbs_dma +
+					     offsetof(struct ipr_misc_cbs, supp_dev));
+		ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+		ioarcb->write_data_transfer_length =
+			cpu_to_be32(sizeof(struct ipr_supported_device));
+
+		ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
+			   IPR_SET_SUP_DEVICE_TIMEOUT);
+
+		ipr_cmd->job_step = ipr_set_supported_devs;
+		return IPR_RC_JOB_RETURN;
+	}
+
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
+ * ipr_get_mode_page - Locate specified mode page
+ * @mode_pages:	mode page buffer
+ * @page_code:	page code to find
+ * @len:		minimum required length for mode page
+ *
+ * Return value:
+ * 	pointer to mode page / NULL on failure
+ **/
+static void *ipr_get_mode_page(struct ipr_mode_pages *mode_pages,
+			       u32 page_code, u32 len)
+{
+	struct ipr_mode_page_hdr *mode_hdr;
+	u32 page_length;
+	u32 length;
+
+	if (!mode_pages || (mode_pages->hdr.length == 0))
+		return NULL;
+
+	length = (mode_pages->hdr.length + 1) - 4 - mode_pages->hdr.block_desc_len;
+	mode_hdr = (struct ipr_mode_page_hdr *)
+		(mode_pages->data + mode_pages->hdr.block_desc_len);
+
+	while (length) {
+		if (IPR_GET_MODE_PAGE_CODE(mode_hdr) == page_code) {
+			if (mode_hdr->page_length >= (len - sizeof(struct ipr_mode_page_hdr)))
+				return mode_hdr;
+			break;
+		} else {
+			page_length = (sizeof(struct ipr_mode_page_hdr) +
+				       mode_hdr->page_length);
+			length -= page_length;
+			mode_hdr = (struct ipr_mode_page_hdr *)
+				((unsigned long)mode_hdr + page_length);
+		}
+	}
+	return NULL;
+}
+
+/**
+ * ipr_check_term_power - Check for term power errors
+ * @ioa_cfg:	ioa config struct
+ * @mode_pages:	IOAFP mode pages buffer
+ *
+ * Check the IOAFP's mode page 28 for term power errors
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_check_term_power(struct ipr_ioa_cfg *ioa_cfg,
+				 struct ipr_mode_pages *mode_pages)
+{
+	int i;
+	int entry_length;
+	struct ipr_dev_bus_entry *bus;
+	struct ipr_mode_page28 *mode_page;
+
+	mode_page = ipr_get_mode_page(mode_pages, 0x28,
+				      sizeof(struct ipr_mode_page28));
+
+	entry_length = mode_page->entry_length;
+
+	bus = mode_page->bus;
+
+	for (i = 0; i < mode_page->num_entries; i++) {
+		if (bus->flags & IPR_SCSI_ATTR_NO_TERM_PWR) {
+			dev_err(&ioa_cfg->pdev->dev,
+				"Term power is absent on scsi bus %d\n",
+				bus->res_addr.bus);
+		}
+
+		bus = (struct ipr_dev_bus_entry *)((char *)bus + entry_length);
+	}
+}
+
+/**
+ * ipr_scsi_bus_speed_limit - Limit the SCSI speed based on SES table
+ * @ioa_cfg:	ioa config struct
+ *
+ * Looks through the config table checking for SES devices. If
+ * the SES device is in the SES table indicating a maximum SCSI
+ * bus speed, the speed is limited for the bus.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_scsi_bus_speed_limit(struct ipr_ioa_cfg *ioa_cfg)
+{
+	u32 max_xfer_rate;
+	int i;
+
+	for (i = 0; i < IPR_MAX_NUM_BUSES; i++) {
+		max_xfer_rate = ipr_get_max_scsi_speed(ioa_cfg, i,
+						       ioa_cfg->bus_attr[i].bus_width);
+
+		if (max_xfer_rate < ioa_cfg->bus_attr[i].max_xfer_rate)
+			ioa_cfg->bus_attr[i].max_xfer_rate = max_xfer_rate;
+	}
+}
+
+/**
+ * ipr_modify_ioafp_mode_page_28 - Modify IOAFP Mode Page 28
+ * @ioa_cfg:	ioa config struct
+ * @mode_pages:	mode page 28 buffer
+ *
+ * Updates mode page 28 based on driver configuration
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_modify_ioafp_mode_page_28(struct ipr_ioa_cfg *ioa_cfg,
+					  	struct ipr_mode_pages *mode_pages)
+{
+	int i, entry_length;
+	struct ipr_dev_bus_entry *bus;
+	struct ipr_bus_attributes *bus_attr;
+	struct ipr_mode_page28 *mode_page;
+
+	mode_page = ipr_get_mode_page(mode_pages, 0x28,
+				      sizeof(struct ipr_mode_page28));
+
+	entry_length = mode_page->entry_length;
+
+	/* Loop for each device bus entry */
+	for (i = 0, bus = mode_page->bus;
+	     i < mode_page->num_entries;
+	     i++, bus = (struct ipr_dev_bus_entry *)((u8 *)bus + entry_length)) {
+		if (bus->res_addr.bus > IPR_MAX_NUM_BUSES) {
+			dev_err(&ioa_cfg->pdev->dev,
+				"Invalid resource address reported: 0x%08X\n",
+				IPR_GET_PHYS_LOC(bus->res_addr));
+			continue;
+		}
+
+		bus_attr = &ioa_cfg->bus_attr[i];
+		bus->extended_reset_delay = IPR_EXTENDED_RESET_DELAY;
+		bus->bus_width = bus_attr->bus_width;
+		bus->max_xfer_rate = cpu_to_be32(bus_attr->max_xfer_rate);
+		bus->flags &= ~IPR_SCSI_ATTR_QAS_MASK;
+		if (bus_attr->qas_enabled)
+			bus->flags |= IPR_SCSI_ATTR_ENABLE_QAS;
+		else
+			bus->flags |= IPR_SCSI_ATTR_DISABLE_QAS;
+	}
+}
+
+/**
+ * ipr_build_mode_select - Build a mode select command
+ * @ipr_cmd:	ipr command struct
+ * @res_handle:	resource handle to send command to
+ * @parm:		Byte 2 of Mode Sense command
+ * @dma_addr:	DMA buffer address
+ * @xfer_len:	data transfer length
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_build_mode_select(struct ipr_cmnd *ipr_cmd,
+				  __be32 res_handle, u8 parm, u32 dma_addr,
+				  u8 xfer_len)
+{
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+
+	ioarcb->res_handle = res_handle;
+	ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
+	ioarcb->cmd_pkt.flags_hi |= IPR_FLAGS_HI_WRITE_NOT_READ;
+	ioarcb->cmd_pkt.cdb[0] = MODE_SELECT;
+	ioarcb->cmd_pkt.cdb[1] = parm;
+	ioarcb->cmd_pkt.cdb[4] = xfer_len;
+
+	ioadl->flags_and_data_len =
+		cpu_to_be32(IPR_IOADL_FLAGS_WRITE_LAST | xfer_len);
+	ioadl->address = cpu_to_be32(dma_addr);
+	ioarcb->write_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+	ioarcb->write_data_transfer_length = cpu_to_be32(xfer_len);
+}
+
+/**
+ * ipr_ioafp_mode_select_page28 - Issue Mode Select Page 28 to IOA
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sets up the SCSI bus attributes and sends
+ * a Mode Select for Page 28 to activate them.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_select_page28(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_mode_pages *mode_pages = &ioa_cfg->vpd_cbs->mode_pages;
+	int length;
+
+	ENTER;
+	if (ioa_cfg->saved_mode_pages) {
+		memcpy(mode_pages, ioa_cfg->saved_mode_pages,
+		       ioa_cfg->saved_mode_page_len);
+		length = ioa_cfg->saved_mode_page_len;
+	} else {
+		ipr_scsi_bus_speed_limit(ioa_cfg);
+		ipr_check_term_power(ioa_cfg, mode_pages);
+		ipr_modify_ioafp_mode_page_28(ioa_cfg, mode_pages);
+		length = mode_pages->hdr.length + 1;
+		mode_pages->hdr.length = 0;
+	}
+
+	ipr_build_mode_select(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE), 0x11,
+			      ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, mode_pages),
+			      length);
+
+	ipr_cmd->job_step = ipr_set_supported_devs;
+	ipr_cmd->u.res = list_entry(ioa_cfg->used_res_q.next,
+				    struct ipr_resource_entry, queue);
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_build_mode_sense - Builds a mode sense command
+ * @ipr_cmd:	ipr command struct
+ * @res:		resource entry struct
+ * @parm:		Byte 2 of mode sense command
+ * @dma_addr:	DMA address of mode sense buffer
+ * @xfer_len:	Size of DMA buffer
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_build_mode_sense(struct ipr_cmnd *ipr_cmd,
+				 __be32 res_handle,
+				 u8 parm, u32 dma_addr, u8 xfer_len)
+{
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+
+	ioarcb->res_handle = res_handle;
+	ioarcb->cmd_pkt.cdb[0] = MODE_SENSE;
+	ioarcb->cmd_pkt.cdb[2] = parm;
+	ioarcb->cmd_pkt.cdb[4] = xfer_len;
+	ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
+
+	ioadl->flags_and_data_len =
+		cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len);
+	ioadl->address = cpu_to_be32(dma_addr);
+	ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+	ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len);
+}
+
+/**
+ * ipr_ioafp_mode_sense_page28 - Issue Mode Sense Page 28 to IOA
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function send a Page 28 mode sense to the IOA to
+ * retrieve SCSI bus attributes.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_mode_sense_page28(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	ipr_build_mode_sense(ipr_cmd, cpu_to_be32(IPR_IOA_RES_HANDLE),
+			     0x28, ioa_cfg->vpd_cbs_dma +
+			     offsetof(struct ipr_misc_cbs, mode_pages),
+			     sizeof(struct ipr_mode_pages));
+
+	ipr_cmd->job_step = ipr_ioafp_mode_select_page28;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_init_res_table - Initialize the resource table
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function looks through the existing resource table, comparing
+ * it with the config table. This function will take care of old/new
+ * devices and schedule adding/removing them from the mid-layer
+ * as appropriate.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE
+ **/
+static int ipr_init_res_table(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_resource_entry *res, *temp;
+	struct ipr_config_table_entry *cfgte;
+	int found, i;
+	LIST_HEAD(old_res);
+
+	ENTER;
+	if (ioa_cfg->cfg_table->hdr.flags & IPR_UCODE_DOWNLOAD_REQ)
+		dev_err(&ioa_cfg->pdev->dev, "Microcode download required\n");
+
+	list_for_each_entry_safe(res, temp, &ioa_cfg->used_res_q, queue)
+		list_move_tail(&res->queue, &old_res);
+
+	for (i = 0; i < ioa_cfg->cfg_table->hdr.num_entries; i++) {
+		cfgte = &ioa_cfg->cfg_table->dev[i];
+		found = 0;
+
+		list_for_each_entry_safe(res, temp, &old_res, queue) {
+			if (!memcmp(&res->cfgte.res_addr,
+				    &cfgte->res_addr, sizeof(cfgte->res_addr))) {
+				list_move_tail(&res->queue, &ioa_cfg->used_res_q);
+				found = 1;
+				break;
+			}
+		}
+
+		if (!found) {
+			if (list_empty(&ioa_cfg->free_res_q)) {
+				dev_err(&ioa_cfg->pdev->dev, "Too many devices attached\n");
+				break;
+			}
+
+			found = 1;
+			res = list_entry(ioa_cfg->free_res_q.next,
+					 struct ipr_resource_entry, queue);
+			list_move_tail(&res->queue, &ioa_cfg->used_res_q);
+			ipr_init_res_entry(res);
+			res->add_to_ml = 1;
+		}
+
+		if (found)
+			memcpy(&res->cfgte, cfgte, sizeof(struct ipr_config_table_entry));
+	}
+
+	list_for_each_entry_safe(res, temp, &old_res, queue) {
+		if (res->sdev) {
+			res->del_from_ml = 1;
+			res->sdev->hostdata = NULL;
+			list_move_tail(&res->queue, &ioa_cfg->used_res_q);
+		} else {
+			list_move_tail(&res->queue, &ioa_cfg->free_res_q);
+		}
+	}
+
+	ipr_cmd->job_step = ipr_ioafp_mode_sense_page28;
+
+	LEAVE;
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
+ * ipr_ioafp_query_ioa_cfg - Send a Query IOA Config to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a Query IOA Configuration command
+ * to the adapter to retrieve the IOA configuration table.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_query_ioa_cfg(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+	struct ipr_inquiry_page3 *ucode_vpd = &ioa_cfg->vpd_cbs->page3_data;
+
+	ENTER;
+	dev_info(&ioa_cfg->pdev->dev, "Adapter firmware version: %02X%02X%02X%02X\n",
+		 ucode_vpd->major_release, ucode_vpd->card_type,
+		 ucode_vpd->minor_release[0], ucode_vpd->minor_release[1]);
+	ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+	ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+
+	ioarcb->cmd_pkt.cdb[0] = IPR_QUERY_IOA_CONFIG;
+	ioarcb->cmd_pkt.cdb[7] = (sizeof(struct ipr_config_table) >> 8) & 0xff;
+	ioarcb->cmd_pkt.cdb[8] = sizeof(struct ipr_config_table) & 0xff;
+
+	ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+	ioarcb->read_data_transfer_length =
+		cpu_to_be32(sizeof(struct ipr_config_table));
+
+	ioadl->address = cpu_to_be32(ioa_cfg->cfg_table_dma);
+	ioadl->flags_and_data_len =
+		cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | sizeof(struct ipr_config_table));
+
+	ipr_cmd->job_step = ipr_init_res_table;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_ioafp_inquiry - Send an Inquiry to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This utility function sends an inquiry to the adapter.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_ioafp_inquiry(struct ipr_cmnd *ipr_cmd, u8 flags, u8 page,
+			      u32 dma_addr, u8 xfer_len)
+{
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+	struct ipr_ioadl_desc *ioadl = ipr_cmd->ioadl;
+
+	ENTER;
+	ioarcb->cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
+	ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+
+	ioarcb->cmd_pkt.cdb[0] = INQUIRY;
+	ioarcb->cmd_pkt.cdb[1] = flags;
+	ioarcb->cmd_pkt.cdb[2] = page;
+	ioarcb->cmd_pkt.cdb[4] = xfer_len;
+
+	ioarcb->read_ioadl_len = cpu_to_be32(sizeof(struct ipr_ioadl_desc));
+	ioarcb->read_data_transfer_length = cpu_to_be32(xfer_len);
+
+	ioadl->address = cpu_to_be32(dma_addr);
+	ioadl->flags_and_data_len =
+		cpu_to_be32(IPR_IOADL_FLAGS_READ_LAST | xfer_len);
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+	LEAVE;
+}
+
+/**
+ * ipr_ioafp_page3_inquiry - Send a Page 3 Inquiry to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a Page 3 inquiry to the adapter
+ * to retrieve software VPD information.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_page3_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	char type[5];
+
+	ENTER;
+
+	/* Grab the type out of the VPD and store it away */
+	memcpy(type, ioa_cfg->vpd_cbs->ioa_vpd.std_inq_data.vpids.product_id, 4);
+	type[4] = '\0';
+	ioa_cfg->type = simple_strtoul((char *)type, NULL, 16);
+
+	ipr_cmd->job_step = ipr_ioafp_query_ioa_cfg;
+
+	ipr_ioafp_inquiry(ipr_cmd, 1, 3,
+			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, page3_data),
+			  sizeof(struct ipr_inquiry_page3));
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_ioafp_std_inquiry - Send a Standard Inquiry to the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function sends a standard inquiry to the adapter.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_std_inquiry(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	ENTER;
+	ipr_cmd->job_step = ipr_ioafp_page3_inquiry;
+
+	ipr_ioafp_inquiry(ipr_cmd, 0, 0,
+			  ioa_cfg->vpd_cbs_dma + offsetof(struct ipr_misc_cbs, ioa_vpd),
+			  sizeof(struct ipr_ioa_vpd));
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_ioafp_indentify_hrrq - Send Identify Host RRQ.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function send an Identify Host Request Response Queue
+ * command to establish the HRRQ with the adapter.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_ioafp_indentify_hrrq(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_ioarcb *ioarcb = &ipr_cmd->ioarcb;
+
+	ENTER;
+	dev_info(&ioa_cfg->pdev->dev, "Starting IOA initialization sequence.\n");
+
+	ioarcb->cmd_pkt.cdb[0] = IPR_ID_HOST_RR_Q;
+	ioarcb->res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+
+	ioarcb->cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+	ioarcb->cmd_pkt.cdb[2] =
+		((u32) ioa_cfg->host_rrq_dma >> 24) & 0xff;
+	ioarcb->cmd_pkt.cdb[3] =
+		((u32) ioa_cfg->host_rrq_dma >> 16) & 0xff;
+	ioarcb->cmd_pkt.cdb[4] =
+		((u32) ioa_cfg->host_rrq_dma >> 8) & 0xff;
+	ioarcb->cmd_pkt.cdb[5] =
+		((u32) ioa_cfg->host_rrq_dma) & 0xff;
+	ioarcb->cmd_pkt.cdb[7] =
+		((sizeof(u32) * IPR_NUM_CMD_BLKS) >> 8) & 0xff;
+	ioarcb->cmd_pkt.cdb[8] =
+		(sizeof(u32) * IPR_NUM_CMD_BLKS) & 0xff;
+
+	ipr_cmd->job_step = ipr_ioafp_std_inquiry;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, IPR_INTERNAL_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_timer_done - Adapter reset timer function
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function is used in adapter reset processing
+ * for timing events. If the reset_cmd pointer in the IOA
+ * config struct is not this adapter's we are doing nested
+ * resets and fail_all_ops will take care of freeing the
+ * command block.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_reset_timer_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+
+	if (ioa_cfg->reset_cmd == ipr_cmd) {
+		list_del(&ipr_cmd->queue);
+		ipr_cmd->done(ipr_cmd);
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+}
+
+/**
+ * ipr_reset_start_timer - Start a timer for adapter reset job
+ * @ipr_cmd:	ipr command struct
+ * @timeout:	timeout value
+ *
+ * Description: This function is used in adapter reset processing
+ * for timing events. If the reset_cmd pointer in the IOA
+ * config struct is not this adapter's we are doing nested
+ * resets and fail_all_ops will take care of freeing the
+ * command block.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_reset_start_timer(struct ipr_cmnd *ipr_cmd,
+				  unsigned long timeout)
+{
+	list_add_tail(&ipr_cmd->queue, &ipr_cmd->ioa_cfg->pending_q);
+	ipr_cmd->done = ipr_reset_ioa_job;
+
+	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
+	ipr_cmd->timer.expires = jiffies + timeout;
+	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_reset_timer_done;
+	add_timer(&ipr_cmd->timer);
+}
+
+/**
+ * ipr_init_ioa_mem - Initialize ioa_cfg control block
+ * @ioa_cfg:	ioa cfg struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_init_ioa_mem(struct ipr_ioa_cfg *ioa_cfg)
+{
+	memset(ioa_cfg->host_rrq, 0, sizeof(u32) * IPR_NUM_CMD_BLKS);
+
+	/* Initialize Host RRQ pointers */
+	ioa_cfg->hrrq_start = ioa_cfg->host_rrq;
+	ioa_cfg->hrrq_end = &ioa_cfg->host_rrq[IPR_NUM_CMD_BLKS - 1];
+	ioa_cfg->hrrq_curr = ioa_cfg->hrrq_start;
+	ioa_cfg->toggle_bit = 1;
+
+	/* Zero out config table */
+	memset(ioa_cfg->cfg_table, 0, sizeof(struct ipr_config_table));
+}
+
+/**
+ * ipr_reset_enable_ioa - Enable the IOA following a reset.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function reinitializes some control blocks and
+ * enables destructive diagnostics on the adapter.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_enable_ioa(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	volatile u32 int_reg;
+
+	ENTER;
+	ipr_cmd->job_step = ipr_ioafp_indentify_hrrq;
+	ipr_init_ioa_mem(ioa_cfg);
+
+	ioa_cfg->allow_interrupts = 1;
+	int_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+
+	if (int_reg & IPR_PCII_IOA_TRANS_TO_OPER) {
+		writel((IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED),
+		       ioa_cfg->regs.clr_interrupt_mask_reg);
+		int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	/* Enable destructive diagnostics on IOA */
+	writel(IPR_DOORBELL, ioa_cfg->regs.set_uproc_interrupt_reg);
+
+	writel(IPR_PCII_OPER_INTERRUPTS, ioa_cfg->regs.clr_interrupt_mask_reg);
+	int_reg = readl(ioa_cfg->regs.sense_interrupt_mask_reg);
+
+	dev_info(&ioa_cfg->pdev->dev, "Initializing IOA.\n");
+
+	ipr_cmd->timer.data = (unsigned long) ipr_cmd;
+	ipr_cmd->timer.expires = jiffies + (ipr_transop_timeout * HZ);
+	ipr_cmd->timer.function = (void (*)(unsigned long))ipr_oper_timeout;
+	ipr_cmd->done = ipr_reset_ioa_job;
+	add_timer(&ipr_cmd->timer);
+	list_add_tail(&ipr_cmd->queue, &ioa_cfg->pending_q);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_wait_for_dump - Wait for a dump to timeout.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function is invoked when an adapter dump has run out
+ * of processing time.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE
+ **/
+static int ipr_reset_wait_for_dump(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	if (ioa_cfg->sdt_state == GET_DUMP)
+		ioa_cfg->sdt_state = ABORT_DUMP;
+
+	ipr_cmd->job_step = ipr_reset_alert;
+
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
+ * ipr_unit_check_no_data - Log a unit check/no data error log
+ * @ioa_cfg:		ioa config struct
+ *
+ * Logs an error indicating the adapter unit checked, but for some
+ * reason, we were unable to fetch the unit check buffer.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_unit_check_no_data(struct ipr_ioa_cfg *ioa_cfg)
+{
+	ioa_cfg->errors_logged++;
+	dev_err(&ioa_cfg->pdev->dev, "IOA unit check with no data\n");
+}
+
+/**
+ * ipr_get_unit_check_buffer - Get the unit check buffer from the IOA
+ * @ioa_cfg:		ioa config struct
+ *
+ * Fetches the unit check buffer from the adapter by clocking the data
+ * through the mailbox register.
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_get_unit_check_buffer(struct ipr_ioa_cfg *ioa_cfg)
+{
+	unsigned long mailbox;
+	struct ipr_hostrcb *hostrcb;
+	struct ipr_uc_sdt sdt;
+	int rc, length;
+
+	mailbox = readl(ioa_cfg->ioa_mailbox);
+
+	if (!ipr_sdt_is_fmt2(mailbox)) {
+		ipr_unit_check_no_data(ioa_cfg);
+		return;
+	}
+
+	memset(&sdt, 0, sizeof(struct ipr_uc_sdt));
+	rc = ipr_get_ldump_data_section(ioa_cfg, mailbox, (__be32 *) &sdt,
+					(sizeof(struct ipr_uc_sdt)) / sizeof(__be32));
+
+	if (rc || (be32_to_cpu(sdt.hdr.state) != IPR_FMT2_SDT_READY_TO_USE) ||
+	    !(sdt.entry[0].flags & IPR_SDT_VALID_ENTRY)) {
+		ipr_unit_check_no_data(ioa_cfg);
+		return;
+	}
+
+	/* Find length of the first sdt entry (UC buffer) */
+	length = (be32_to_cpu(sdt.entry[0].end_offset) -
+		  be32_to_cpu(sdt.entry[0].bar_str_offset)) & IPR_FMT2_MBX_ADDR_MASK;
+
+	hostrcb = list_entry(ioa_cfg->hostrcb_free_q.next,
+			     struct ipr_hostrcb, queue);
+	list_del(&hostrcb->queue);
+	memset(&hostrcb->hcam, 0, sizeof(hostrcb->hcam));
+
+	rc = ipr_get_ldump_data_section(ioa_cfg,
+					be32_to_cpu(sdt.entry[0].bar_str_offset),
+					(__be32 *)&hostrcb->hcam,
+					min(length, (int)sizeof(hostrcb->hcam)) / sizeof(__be32));
+
+	if (!rc)
+		ipr_handle_log_data(ioa_cfg, hostrcb);
+	else
+		ipr_unit_check_no_data(ioa_cfg);
+
+	list_add_tail(&hostrcb->queue, &ioa_cfg->hostrcb_free_q);
+}
+
+/**
+ * ipr_reset_restore_cfg_space - Restore PCI config space.
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function restores the saved PCI config space of
+ * the adapter, fails all outstanding ops back to the callers, and
+ * fetches the dump/unit check if applicable to this reset.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_restore_cfg_space(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	int rc;
+
+	ENTER;
+	rc = pci_restore_state(ioa_cfg->pdev);
+
+	if (rc != PCIBIOS_SUCCESSFUL) {
+		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	if (ipr_set_pcix_cmd_reg(ioa_cfg)) {
+		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	ipr_fail_all_ops(ioa_cfg);
+
+	if (ioa_cfg->ioa_unit_checked) {
+		ioa_cfg->ioa_unit_checked = 0;
+		ipr_get_unit_check_buffer(ioa_cfg);
+		ipr_cmd->job_step = ipr_reset_alert;
+		ipr_reset_start_timer(ipr_cmd, 0);
+		return IPR_RC_JOB_RETURN;
+	}
+
+	if (ioa_cfg->in_ioa_bringdown) {
+		ipr_cmd->job_step = ipr_ioa_bringdown_done;
+	} else {
+		ipr_cmd->job_step = ipr_reset_enable_ioa;
+
+		if (GET_DUMP == ioa_cfg->sdt_state) {
+			ipr_reset_start_timer(ipr_cmd, IPR_DUMP_TIMEOUT);
+			ipr_cmd->job_step = ipr_reset_wait_for_dump;
+			schedule_work(&ioa_cfg->work_q);
+			return IPR_RC_JOB_RETURN;
+		}
+	}
+
+	ENTER;
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
+ * ipr_reset_start_bist - Run BIST on the adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function runs BIST on the adapter, then delays 2 seconds.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_start_bist(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	int rc;
+
+	ENTER;
+	rc = pci_write_config_byte(ioa_cfg->pdev, PCI_BIST, PCI_BIST_START);
+
+	if (rc != PCIBIOS_SUCCESSFUL) {
+		ipr_cmd->ioasa.ioasc = cpu_to_be32(IPR_IOASC_PCI_ACCESS_ERROR);
+		rc = IPR_RC_JOB_CONTINUE;
+	} else {
+		ipr_cmd->job_step = ipr_reset_restore_cfg_space;
+		ipr_reset_start_timer(ipr_cmd, IPR_WAIT_FOR_BIST_TIMEOUT);
+		rc = IPR_RC_JOB_RETURN;
+	}
+
+	LEAVE;
+	return rc;
+}
+
+/**
+ * ipr_reset_allowed - Query whether or not IOA can be reset
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	0 if reset not allowed / non-zero if reset is allowed
+ **/
+static int ipr_reset_allowed(struct ipr_ioa_cfg *ioa_cfg)
+{
+	volatile u32 temp_reg;
+
+	temp_reg = readl(ioa_cfg->regs.sense_interrupt_reg);
+	return ((temp_reg & IPR_PCII_CRITICAL_OPERATION) == 0);
+}
+
+/**
+ * ipr_reset_wait_to_start_bist - Wait for permission to reset IOA.
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function waits for adapter permission to run BIST,
+ * then runs BIST. If the adapter does not give permission after a
+ * reasonable time, we will reset the adapter anyway. The impact of
+ * resetting the adapter without warning the adapter is the risk of
+ * losing the persistent error log on the adapter. If the adapter is
+ * reset while it is writing to the flash on the adapter, the flash
+ * segment will have bad ECC and be zeroed.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_wait_to_start_bist(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	int rc = IPR_RC_JOB_RETURN;
+
+	if (!ipr_reset_allowed(ioa_cfg) && ipr_cmd->u.time_left) {
+		ipr_cmd->u.time_left -= IPR_CHECK_FOR_RESET_TIMEOUT;
+		ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
+	} else {
+		ipr_cmd->job_step = ipr_reset_start_bist;
+		rc = IPR_RC_JOB_CONTINUE;
+	}
+
+	return rc;
+}
+
+/**
+ * ipr_reset_alert_part2 - Alert the adapter of a pending reset
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function alerts the adapter that it will be reset.
+ * If memory space is not currently enabled, proceed directly
+ * to running BIST on the adapter. The timer must always be started
+ * so we guarantee we do not run BIST from ipr_isr.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_alert(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	u16 cmd_reg;
+	int rc;
+
+	ENTER;
+	rc = pci_read_config_word(ioa_cfg->pdev, PCI_COMMAND, &cmd_reg);
+
+	if ((rc == PCIBIOS_SUCCESSFUL) && (cmd_reg & PCI_COMMAND_MEMORY)) {
+		ipr_mask_and_clear_interrupts(ioa_cfg, ~0);
+		writel(IPR_UPROCI_RESET_ALERT, ioa_cfg->regs.set_uproc_interrupt_reg);
+		ipr_cmd->job_step = ipr_reset_wait_to_start_bist;
+	} else {
+		ipr_cmd->job_step = ipr_reset_start_bist;
+	}
+
+	ipr_cmd->u.time_left = IPR_WAIT_FOR_RESET_TIMEOUT;
+	ipr_reset_start_timer(ipr_cmd, IPR_CHECK_FOR_RESET_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_ucode_download_done - Microcode download completion
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function unmaps the microcode download buffer.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE
+ **/
+static int ipr_reset_ucode_download_done(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_sglist *sglist = ioa_cfg->ucode_sglist;
+
+	pci_unmap_sg(ioa_cfg->pdev, sglist->scatterlist,
+		     sglist->num_sg, DMA_TO_DEVICE);
+
+	ipr_cmd->job_step = ipr_reset_alert;
+	return IPR_RC_JOB_CONTINUE;
+}
+
+/**
+ * ipr_reset_ucode_download - Download microcode to the adapter
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function checks to see if it there is microcode
+ * to download to the adapter. If there is, a download is performed.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_ucode_download(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	struct ipr_sglist *sglist = ioa_cfg->ucode_sglist;
+
+	ENTER;
+	ipr_cmd->job_step = ipr_reset_alert;
+
+	if (!sglist)
+		return IPR_RC_JOB_CONTINUE;
+
+	ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+	ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_SCSICDB;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[0] = WRITE_BUFFER;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[1] = IPR_WR_BUF_DOWNLOAD_AND_SAVE;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[6] = (sglist->buffer_len & 0xff0000) >> 16;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[7] = (sglist->buffer_len & 0x00ff00) >> 8;
+	ipr_cmd->ioarcb.cmd_pkt.cdb[8] = sglist->buffer_len & 0x0000ff;
+
+	if (ipr_map_ucode_buffer(ipr_cmd, sglist, sglist->buffer_len)) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"Failed to map microcode download buffer\n");
+		return IPR_RC_JOB_CONTINUE;
+	}
+
+	ipr_cmd->job_step = ipr_reset_ucode_download_done;
+
+	ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout,
+		   IPR_WRITE_BUFFER_TIMEOUT);
+
+	LEAVE;
+	return IPR_RC_JOB_RETURN;
+}
+
+/**
+ * ipr_reset_shutdown_ioa - Shutdown the adapter
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function issues an adapter shutdown of the
+ * specified type to the specified adapter as part of the
+ * adapter reset job.
+ *
+ * Return value:
+ * 	IPR_RC_JOB_CONTINUE / IPR_RC_JOB_RETURN
+ **/
+static int ipr_reset_shutdown_ioa(struct ipr_cmnd *ipr_cmd)
+{
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+	enum ipr_shutdown_type shutdown_type = ipr_cmd->u.shutdown_type;
+	unsigned long timeout;
+	int rc = IPR_RC_JOB_CONTINUE;
+
+	ENTER;
+	if (shutdown_type != IPR_SHUTDOWN_NONE && !ioa_cfg->ioa_is_dead) {
+		ipr_cmd->ioarcb.res_handle = cpu_to_be32(IPR_IOA_RES_HANDLE);
+		ipr_cmd->ioarcb.cmd_pkt.request_type = IPR_RQTYPE_IOACMD;
+		ipr_cmd->ioarcb.cmd_pkt.cdb[0] = IPR_IOA_SHUTDOWN;
+		ipr_cmd->ioarcb.cmd_pkt.cdb[1] = shutdown_type;
+
+		if (shutdown_type == IPR_SHUTDOWN_ABBREV)
+			timeout = IPR_ABBREV_SHUTDOWN_TIMEOUT;
+		else if (shutdown_type == IPR_SHUTDOWN_PREPARE_FOR_NORMAL)
+			timeout = IPR_INTERNAL_TIMEOUT;
+		else
+			timeout = IPR_SHUTDOWN_TIMEOUT;
+
+		ipr_do_req(ipr_cmd, ipr_reset_ioa_job, ipr_timeout, timeout);
+
+		rc = IPR_RC_JOB_RETURN;
+		ipr_cmd->job_step = ipr_reset_ucode_download;
+	} else
+		ipr_cmd->job_step = ipr_reset_alert;
+
+	LEAVE;
+	return rc;
+}
+
+/**
+ * ipr_reset_ioa_job - Adapter reset job
+ * @ipr_cmd:	ipr command struct
+ *
+ * Description: This function is the job router for the adapter reset job.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_reset_ioa_job(struct ipr_cmnd *ipr_cmd)
+{
+	u32 rc, ioasc;
+	unsigned long scratch = ipr_cmd->u.scratch;
+	struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
+
+	do {
+		ioasc = be32_to_cpu(ipr_cmd->ioasa.ioasc);
+
+		if (ioa_cfg->reset_cmd != ipr_cmd) {
+			/*
+			 * We are doing nested adapter resets and this is
+			 * not the current reset job.
+			 */
+			list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+			return;
+		}
+
+		if (IPR_IOASC_SENSE_KEY(ioasc)) {
+			dev_err(&ioa_cfg->pdev->dev,
+				"0x%02X failed with IOASC: 0x%08X\n",
+				ipr_cmd->ioarcb.cmd_pkt.cdb[0], ioasc);
+
+			ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE);
+			list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+			return;
+		}
+
+		ipr_reinit_ipr_cmnd(ipr_cmd);
+		ipr_cmd->u.scratch = scratch;
+		rc = ipr_cmd->job_step(ipr_cmd);
+	} while(rc == IPR_RC_JOB_CONTINUE);
+}
+
+/**
+ * _ipr_initiate_ioa_reset - Initiate an adapter reset
+ * @ioa_cfg:		ioa config struct
+ * @job_step:		first job step of reset job
+ * @shutdown_type:	shutdown type
+ *
+ * Description: This function will initiate the reset of the given adapter
+ * starting at the selected job step.
+ * If the caller needs to wait on the completion of the reset,
+ * the caller must sleep on the reset_wait_q.
+ *
+ * Return value:
+ * 	none
+ **/
+static void _ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg,
+				    int (*job_step) (struct ipr_cmnd *),
+				    enum ipr_shutdown_type shutdown_type)
+{
+	struct ipr_cmnd *ipr_cmd;
+
+	ioa_cfg->in_reset_reload = 1;
+	ioa_cfg->allow_cmds = 0;
+	scsi_block_requests(ioa_cfg->host);
+
+	ipr_cmd = ipr_get_free_ipr_cmnd(ioa_cfg);
+	ioa_cfg->reset_cmd = ipr_cmd;
+	ipr_cmd->job_step = job_step;
+	ipr_cmd->u.shutdown_type = shutdown_type;
+
+	ipr_reset_ioa_job(ipr_cmd);
+}
+
+/**
+ * ipr_initiate_ioa_reset - Initiate an adapter reset
+ * @ioa_cfg:		ioa config struct
+ * @shutdown_type:	shutdown type
+ *
+ * Description: This function will initiate the reset of the given adapter.
+ * If the caller needs to wait on the completion of the reset,
+ * the caller must sleep on the reset_wait_q.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_initiate_ioa_reset(struct ipr_ioa_cfg *ioa_cfg,
+				   enum ipr_shutdown_type shutdown_type)
+{
+	if (ioa_cfg->ioa_is_dead)
+		return;
+
+	if (ioa_cfg->in_reset_reload && ioa_cfg->sdt_state == GET_DUMP)
+		ioa_cfg->sdt_state = ABORT_DUMP;
+
+	if (ioa_cfg->reset_retries++ >= IPR_NUM_RESET_RELOAD_RETRIES) {
+		dev_err(&ioa_cfg->pdev->dev,
+			"IOA taken offline - error recovery failed\n");
+
+		ioa_cfg->reset_retries = 0;
+		ioa_cfg->ioa_is_dead = 1;
+
+		if (ioa_cfg->in_ioa_bringdown) {
+			ioa_cfg->reset_cmd = NULL;
+			ioa_cfg->in_reset_reload = 0;
+			ipr_fail_all_ops(ioa_cfg);
+			wake_up_all(&ioa_cfg->reset_wait_q);
+
+			spin_unlock_irq(ioa_cfg->host->host_lock);
+			scsi_unblock_requests(ioa_cfg->host);
+			spin_lock_irq(ioa_cfg->host->host_lock);
+			return;
+		} else {
+			ioa_cfg->in_ioa_bringdown = 1;
+			shutdown_type = IPR_SHUTDOWN_NONE;
+		}
+	}
+
+	_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_shutdown_ioa,
+				shutdown_type);
+}
+
+/**
+ * ipr_probe_ioa_part2 - Initializes IOAs found in ipr_probe_ioa(..)
+ * @ioa_cfg:	ioa cfg struct
+ *
+ * Description: This is the second phase of adapter intialization
+ * This function takes care of initilizing the adapter to the point
+ * where it can accept new commands.
+
+ * Return value:
+ * 	0 on sucess / -EIO on failure
+ **/
+static int __devinit ipr_probe_ioa_part2(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int rc = 0;
+	unsigned long host_lock_flags = 0;
+
+	ENTER;
+	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+	dev_dbg(&ioa_cfg->pdev->dev, "ioa_cfg adx: 0x%p\n", ioa_cfg);
+	_ipr_initiate_ioa_reset(ioa_cfg, ipr_reset_enable_ioa, IPR_SHUTDOWN_NONE);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+
+	if (ioa_cfg->ioa_is_dead) {
+		rc = -EIO;
+	} else if (ipr_invalid_adapter(ioa_cfg)) {
+		if (!ipr_testmode)
+			rc = -EIO;
+
+		dev_err(&ioa_cfg->pdev->dev,
+			"Adapter not supported in this hardware configuration.\n");
+	}
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+
+	LEAVE;
+	return rc;
+}
+
+/**
+ * ipr_free_cmd_blks - Frees command blocks allocated for an adapter
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int i;
+
+	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
+		if (ioa_cfg->ipr_cmnd_list[i])
+			pci_pool_free(ioa_cfg->ipr_cmd_pool,
+				      ioa_cfg->ipr_cmnd_list[i],
+				      ioa_cfg->ipr_cmnd_list_dma[i]);
+
+		ioa_cfg->ipr_cmnd_list[i] = NULL;
+	}
+
+	if (ioa_cfg->ipr_cmd_pool)
+		pci_pool_destroy (ioa_cfg->ipr_cmd_pool);
+
+	ioa_cfg->ipr_cmd_pool = NULL;
+}
+
+/**
+ * ipr_free_mem - Frees memory allocated for an adapter
+ * @ioa_cfg:	ioa cfg struct
+ *
+ * Return value:
+ * 	nothing
+ **/
+static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int i;
+
+	kfree(ioa_cfg->res_entries);
+	pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_misc_cbs),
+			    ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
+	ipr_free_cmd_blks(ioa_cfg);
+	pci_free_consistent(ioa_cfg->pdev, sizeof(u32) * IPR_NUM_CMD_BLKS,
+			    ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma);
+	pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_config_table),
+			    ioa_cfg->cfg_table,
+			    ioa_cfg->cfg_table_dma);
+
+	for (i = 0; i < IPR_NUM_HCAMS; i++) {
+		pci_free_consistent(ioa_cfg->pdev,
+				    sizeof(struct ipr_hostrcb),
+				    ioa_cfg->hostrcb[i],
+				    ioa_cfg->hostrcb_dma[i]);
+	}
+
+	ipr_free_dump(ioa_cfg);
+	kfree(ioa_cfg->saved_mode_pages);
+	kfree(ioa_cfg->trace);
+}
+
+/**
+ * ipr_free_all_resources - Free all allocated resources for an adapter.
+ * @ipr_cmd:	ipr command struct
+ *
+ * This function frees all allocated resources for the
+ * specified adapter.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_free_all_resources(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct pci_dev *pdev = ioa_cfg->pdev;
+
+	ENTER;
+	free_irq(pdev->irq, ioa_cfg);
+	iounmap(ioa_cfg->hdw_dma_regs);
+	pci_release_regions(pdev);
+	ipr_free_mem(ioa_cfg);
+	scsi_host_put(ioa_cfg->host);
+	pci_disable_device(pdev);
+	LEAVE;
+}
+
+/**
+ * ipr_alloc_cmd_blks - Allocate command blocks for an adapter
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	0 on success / -ENOMEM on allocation failure
+ **/
+static int __devinit ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct ipr_cmnd *ipr_cmd;
+	struct ipr_ioarcb *ioarcb;
+	dma_addr_t dma_addr;
+	int i;
+
+	ioa_cfg->ipr_cmd_pool = pci_pool_create (IPR_NAME, ioa_cfg->pdev,
+						 sizeof(struct ipr_cmnd), 8, 0);
+
+	if (!ioa_cfg->ipr_cmd_pool)
+		return -ENOMEM;
+
+	for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
+		ipr_cmd = pci_pool_alloc (ioa_cfg->ipr_cmd_pool, SLAB_KERNEL, &dma_addr);
+
+		if (!ipr_cmd) {
+			ipr_free_cmd_blks(ioa_cfg);
+			return -ENOMEM;
+		}
+
+		memset(ipr_cmd, 0, sizeof(*ipr_cmd));
+		ioa_cfg->ipr_cmnd_list[i] = ipr_cmd;
+		ioa_cfg->ipr_cmnd_list_dma[i] = dma_addr;
+
+		ioarcb = &ipr_cmd->ioarcb;
+		ioarcb->ioarcb_host_pci_addr = cpu_to_be32(dma_addr);
+		ioarcb->host_response_handle = cpu_to_be32(i << 2);
+		ioarcb->write_ioadl_addr =
+			cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioadl));
+		ioarcb->read_ioadl_addr = ioarcb->write_ioadl_addr;
+		ioarcb->ioasa_host_pci_addr =
+			cpu_to_be32(dma_addr + offsetof(struct ipr_cmnd, ioasa));
+		ioarcb->ioasa_len = cpu_to_be16(sizeof(struct ipr_ioasa));
+		ipr_cmd->cmd_index = i;
+		ipr_cmd->ioa_cfg = ioa_cfg;
+		ipr_cmd->sense_buffer_dma = dma_addr +
+			offsetof(struct ipr_cmnd, sense_buffer);
+
+		list_add_tail(&ipr_cmd->queue, &ioa_cfg->free_q);
+	}
+
+	return 0;
+}
+
+/**
+ * ipr_alloc_mem - Allocate memory for an adapter
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	0 on success / non-zero for error
+ **/
+static int __devinit ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
+{
+	struct pci_dev *pdev = ioa_cfg->pdev;
+	int i, rc = -ENOMEM;
+
+	ENTER;
+	ioa_cfg->res_entries = kmalloc(sizeof(struct ipr_resource_entry) *
+				       IPR_MAX_PHYSICAL_DEVS, GFP_KERNEL);
+
+	if (!ioa_cfg->res_entries)
+		goto out;
+
+	memset(ioa_cfg->res_entries, 0,
+	       sizeof(struct ipr_resource_entry) * IPR_MAX_PHYSICAL_DEVS);
+
+	for (i = 0; i < IPR_MAX_PHYSICAL_DEVS; i++)
+		list_add_tail(&ioa_cfg->res_entries[i].queue, &ioa_cfg->free_res_q);
+
+	ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev,
+						sizeof(struct ipr_misc_cbs),
+						&ioa_cfg->vpd_cbs_dma);
+
+	if (!ioa_cfg->vpd_cbs)
+		goto out_free_res_entries;
+
+	if (ipr_alloc_cmd_blks(ioa_cfg))
+		goto out_free_vpd_cbs;
+
+	ioa_cfg->host_rrq = pci_alloc_consistent(ioa_cfg->pdev,
+						 sizeof(u32) * IPR_NUM_CMD_BLKS,
+						 &ioa_cfg->host_rrq_dma);
+
+	if (!ioa_cfg->host_rrq)
+		goto out_ipr_free_cmd_blocks;
+
+	ioa_cfg->cfg_table = pci_alloc_consistent(ioa_cfg->pdev,
+						  sizeof(struct ipr_config_table),
+						  &ioa_cfg->cfg_table_dma);
+
+	if (!ioa_cfg->cfg_table)
+		goto out_free_host_rrq;
+
+	for (i = 0; i < IPR_NUM_HCAMS; i++) {
+		ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev,
+							   sizeof(struct ipr_hostrcb),
+							   &ioa_cfg->hostrcb_dma[i]);
+
+		if (!ioa_cfg->hostrcb[i])
+			goto out_free_hostrcb_dma;
+
+		ioa_cfg->hostrcb[i]->hostrcb_dma =
+			ioa_cfg->hostrcb_dma[i] + offsetof(struct ipr_hostrcb, hcam);
+		list_add_tail(&ioa_cfg->hostrcb[i]->queue, &ioa_cfg->hostrcb_free_q);
+	}
+
+	ioa_cfg->trace = kmalloc(sizeof(struct ipr_trace_entry) *
+				 IPR_NUM_TRACE_ENTRIES, GFP_KERNEL);
+
+	if (!ioa_cfg->trace)
+		goto out_free_hostrcb_dma;
+
+	memset(ioa_cfg->trace, 0,
+	       sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES);
+
+	rc = 0;
+out:
+	LEAVE;
+	return rc;
+
+out_free_hostrcb_dma:
+	while (i-- > 0) {
+		pci_free_consistent(pdev, sizeof(struct ipr_hostrcb),
+				    ioa_cfg->hostrcb[i],
+				    ioa_cfg->hostrcb_dma[i]);
+	}
+	pci_free_consistent(pdev, sizeof(struct ipr_config_table),
+			    ioa_cfg->cfg_table, ioa_cfg->cfg_table_dma);
+out_free_host_rrq:
+	pci_free_consistent(pdev, sizeof(u32) * IPR_NUM_CMD_BLKS,
+			    ioa_cfg->host_rrq, ioa_cfg->host_rrq_dma);
+out_ipr_free_cmd_blocks:
+	ipr_free_cmd_blks(ioa_cfg);
+out_free_vpd_cbs:
+	pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs),
+			    ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
+out_free_res_entries:
+	kfree(ioa_cfg->res_entries);
+	goto out;
+}
+
+/**
+ * ipr_initialize_bus_attr - Initialize SCSI bus attributes to default values
+ * @ioa_cfg:	ioa config struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void __devinit ipr_initialize_bus_attr(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int i;
+
+	for (i = 0; i < IPR_MAX_NUM_BUSES; i++) {
+		ioa_cfg->bus_attr[i].bus = i;
+		ioa_cfg->bus_attr[i].qas_enabled = 0;
+		ioa_cfg->bus_attr[i].bus_width = IPR_DEFAULT_BUS_WIDTH;
+		if (ipr_max_speed < ARRAY_SIZE(ipr_max_bus_speeds))
+			ioa_cfg->bus_attr[i].max_xfer_rate = ipr_max_bus_speeds[ipr_max_speed];
+		else
+			ioa_cfg->bus_attr[i].max_xfer_rate = IPR_U160_SCSI_RATE;
+	}
+}
+
+/**
+ * ipr_init_ioa_cfg - Initialize IOA config struct
+ * @ioa_cfg:	ioa config struct
+ * @host:		scsi host struct
+ * @pdev:		PCI dev struct
+ *
+ * Return value:
+ * 	none
+ **/
+static void __devinit ipr_init_ioa_cfg(struct ipr_ioa_cfg *ioa_cfg,
+				       struct Scsi_Host *host, struct pci_dev *pdev)
+{
+	const struct ipr_interrupt_offsets *p;
+	struct ipr_interrupts *t;
+	void __iomem *base;
+
+	ioa_cfg->host = host;
+	ioa_cfg->pdev = pdev;
+	ioa_cfg->log_level = ipr_log_level;
+	sprintf(ioa_cfg->eye_catcher, IPR_EYECATCHER);
+	sprintf(ioa_cfg->trace_start, IPR_TRACE_START_LABEL);
+	sprintf(ioa_cfg->ipr_free_label, IPR_FREEQ_LABEL);
+	sprintf(ioa_cfg->ipr_pending_label, IPR_PENDQ_LABEL);
+	sprintf(ioa_cfg->cfg_table_start, IPR_CFG_TBL_START);
+	sprintf(ioa_cfg->resource_table_label, IPR_RES_TABLE_LABEL);
+	sprintf(ioa_cfg->ipr_hcam_label, IPR_HCAM_LABEL);
+	sprintf(ioa_cfg->ipr_cmd_label, IPR_CMD_LABEL);
+
+	INIT_LIST_HEAD(&ioa_cfg->free_q);
+	INIT_LIST_HEAD(&ioa_cfg->pending_q);
+	INIT_LIST_HEAD(&ioa_cfg->hostrcb_free_q);
+	INIT_LIST_HEAD(&ioa_cfg->hostrcb_pending_q);
+	INIT_LIST_HEAD(&ioa_cfg->free_res_q);
+	INIT_LIST_HEAD(&ioa_cfg->used_res_q);
+	INIT_WORK(&ioa_cfg->work_q, ipr_worker_thread, ioa_cfg);
+	init_waitqueue_head(&ioa_cfg->reset_wait_q);
+	ioa_cfg->sdt_state = INACTIVE;
+
+	ipr_initialize_bus_attr(ioa_cfg);
+
+	host->max_id = IPR_MAX_NUM_TARGETS_PER_BUS;
+	host->max_lun = IPR_MAX_NUM_LUNS_PER_TARGET;
+	host->max_channel = IPR_MAX_BUS_TO_SCAN;
+	host->unique_id = host->host_no;
+	host->max_cmd_len = IPR_MAX_CDB_LEN;
+	pci_set_drvdata(pdev, ioa_cfg);
+
+	p = &ioa_cfg->chip_cfg->regs;
+	t = &ioa_cfg->regs;
+	base = ioa_cfg->hdw_dma_regs;
+
+	t->set_interrupt_mask_reg = base + p->set_interrupt_mask_reg;
+	t->clr_interrupt_mask_reg = base + p->clr_interrupt_mask_reg;
+	t->sense_interrupt_mask_reg = base + p->sense_interrupt_mask_reg;
+	t->clr_interrupt_reg = base + p->clr_interrupt_reg;
+	t->sense_interrupt_reg = base + p->sense_interrupt_reg;
+	t->ioarrin_reg = base + p->ioarrin_reg;
+	t->sense_uproc_interrupt_reg = base + p->sense_uproc_interrupt_reg;
+	t->set_uproc_interrupt_reg = base + p->set_uproc_interrupt_reg;
+	t->clr_uproc_interrupt_reg = base + p->clr_uproc_interrupt_reg;
+}
+
+/**
+ * ipr_get_chip_cfg - Find adapter chip configuration
+ * @dev_id:		PCI device id struct
+ *
+ * Return value:
+ * 	ptr to chip config on success / NULL on failure
+ **/
+static const struct ipr_chip_cfg_t * __devinit
+ipr_get_chip_cfg(const struct pci_device_id *dev_id)
+{
+	int i;
+
+	if (dev_id->driver_data)
+		return (const struct ipr_chip_cfg_t *)dev_id->driver_data;
+
+	for (i = 0; i < ARRAY_SIZE(ipr_chip); i++)
+		if (ipr_chip[i].vendor == dev_id->vendor &&
+		    ipr_chip[i].device == dev_id->device)
+			return ipr_chip[i].cfg;
+	return NULL;
+}
+
+/**
+ * ipr_probe_ioa - Allocates memory and does first stage of initialization
+ * @pdev:		PCI device struct
+ * @dev_id:		PCI device id struct
+ *
+ * Return value:
+ * 	0 on success / non-zero on failure
+ **/
+static int __devinit ipr_probe_ioa(struct pci_dev *pdev,
+				   const struct pci_device_id *dev_id)
+{
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct Scsi_Host *host;
+	unsigned long ipr_regs_pci;
+	void __iomem *ipr_regs;
+	u32 rc = PCIBIOS_SUCCESSFUL;
+
+	ENTER;
+
+	if ((rc = pci_enable_device(pdev))) {
+		dev_err(&pdev->dev, "Cannot enable adapter\n");
+		goto out;
+	}
+
+	dev_info(&pdev->dev, "Found IOA with IRQ: %d\n", pdev->irq);
+
+	host = scsi_host_alloc(&driver_template, sizeof(*ioa_cfg));
+
+	if (!host) {
+		dev_err(&pdev->dev, "call to scsi_host_alloc failed!\n");
+		rc = -ENOMEM;
+		goto out_disable;
+	}
+
+	ioa_cfg = (struct ipr_ioa_cfg *)host->hostdata;
+	memset(ioa_cfg, 0, sizeof(struct ipr_ioa_cfg));
+
+	ioa_cfg->chip_cfg = ipr_get_chip_cfg(dev_id);
+
+	if (!ioa_cfg->chip_cfg) {
+		dev_err(&pdev->dev, "Unknown adapter chipset 0x%04X 0x%04X\n",
+			dev_id->vendor, dev_id->device);
+		goto out_scsi_host_put;
+	}
+
+	ipr_regs_pci = pci_resource_start(pdev, 0);
+
+	rc = pci_request_regions(pdev, IPR_NAME);
+	if (rc < 0) {
+		dev_err(&pdev->dev,
+			"Couldn't register memory range of registers\n");
+		goto out_scsi_host_put;
+	}
+
+	ipr_regs = ioremap(ipr_regs_pci, pci_resource_len(pdev, 0));
+
+	if (!ipr_regs) {
+		dev_err(&pdev->dev,
+			"Couldn't map memory range of registers\n");
+		rc = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	ioa_cfg->hdw_dma_regs = ipr_regs;
+	ioa_cfg->hdw_dma_regs_pci = ipr_regs_pci;
+	ioa_cfg->ioa_mailbox = ioa_cfg->chip_cfg->mailbox + ipr_regs;
+
+	ipr_init_ioa_cfg(ioa_cfg, host, pdev);
+
+	pci_set_master(pdev);
+
+	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (rc < 0) {
+		dev_err(&pdev->dev, "Failed to set PCI DMA mask\n");
+		goto cleanup_nomem;
+	}
+
+	rc = pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE,
+				   ioa_cfg->chip_cfg->cache_line_size);
+
+	if (rc != PCIBIOS_SUCCESSFUL) {
+		dev_err(&pdev->dev, "Write of cache line size failed\n");
+		rc = -EIO;
+		goto cleanup_nomem;
+	}
+
+	/* Save away PCI config space for use following IOA reset */
+	rc = pci_save_state(pdev);
+
+	if (rc != PCIBIOS_SUCCESSFUL) {
+		dev_err(&pdev->dev, "Failed to save PCI config space\n");
+		rc = -EIO;
+		goto cleanup_nomem;
+	}
+
+	if ((rc = ipr_save_pcix_cmd_reg(ioa_cfg)))
+		goto cleanup_nomem;
+
+	if ((rc = ipr_set_pcix_cmd_reg(ioa_cfg)))
+		goto cleanup_nomem;
+
+	rc = ipr_alloc_mem(ioa_cfg);
+	if (rc < 0) {
+		dev_err(&pdev->dev,
+			"Couldn't allocate enough memory for device driver!\n");
+		goto cleanup_nomem;
+	}
+
+	ipr_mask_and_clear_interrupts(ioa_cfg, ~IPR_PCII_IOA_TRANS_TO_OPER);
+	rc = request_irq(pdev->irq, ipr_isr, SA_SHIRQ, IPR_NAME, ioa_cfg);
+
+	if (rc) {
+		dev_err(&pdev->dev, "Couldn't register IRQ %d! rc=%d\n",
+			pdev->irq, rc);
+		goto cleanup_nolog;
+	}
+
+	spin_lock(&ipr_driver_lock);
+	list_add_tail(&ioa_cfg->queue, &ipr_ioa_head);
+	spin_unlock(&ipr_driver_lock);
+
+	LEAVE;
+out:
+	return rc;
+
+cleanup_nolog:
+	ipr_free_mem(ioa_cfg);
+cleanup_nomem:
+	iounmap(ipr_regs);
+out_release_regions:
+	pci_release_regions(pdev);
+out_scsi_host_put:
+	scsi_host_put(host);
+out_disable:
+	pci_disable_device(pdev);
+	goto out;
+}
+
+/**
+ * ipr_scan_vsets - Scans for VSET devices
+ * @ioa_cfg:	ioa config struct
+ *
+ * Description: Since the VSET resources do not follow SAM in that we can have
+ * sparse LUNs with no LUN 0, we have to scan for these ourselves.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_scan_vsets(struct ipr_ioa_cfg *ioa_cfg)
+{
+	int target, lun;
+
+	for (target = 0; target < IPR_MAX_NUM_TARGETS_PER_BUS; target++)
+		for (lun = 0; lun < IPR_MAX_NUM_VSET_LUNS_PER_TARGET; lun++ )
+			scsi_add_device(ioa_cfg->host, IPR_VSET_BUS, target, lun);
+}
+
+/**
+ * ipr_initiate_ioa_bringdown - Bring down an adapter
+ * @ioa_cfg:		ioa config struct
+ * @shutdown_type:	shutdown type
+ *
+ * Description: This function will initiate bringing down the adapter.
+ * This consists of issuing an IOA shutdown to the adapter
+ * to flush the cache, and running BIST.
+ * If the caller needs to wait on the completion of the reset,
+ * the caller must sleep on the reset_wait_q.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_initiate_ioa_bringdown(struct ipr_ioa_cfg *ioa_cfg,
+				       enum ipr_shutdown_type shutdown_type)
+{
+	ENTER;
+	if (ioa_cfg->sdt_state == WAIT_FOR_DUMP)
+		ioa_cfg->sdt_state = ABORT_DUMP;
+	ioa_cfg->reset_retries = 0;
+	ioa_cfg->in_ioa_bringdown = 1;
+	ipr_initiate_ioa_reset(ioa_cfg, shutdown_type);
+	LEAVE;
+}
+
+/**
+ * __ipr_remove - Remove a single adapter
+ * @pdev:	pci device struct
+ *
+ * Adapter hot plug remove entry point.
+ *
+ * Return value:
+ * 	none
+ **/
+static void __ipr_remove(struct pci_dev *pdev)
+{
+	unsigned long host_lock_flags = 0;
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+	ENTER;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+	spin_lock_irqsave(ioa_cfg->host->host_lock, host_lock_flags);
+
+	spin_lock(&ipr_driver_lock);
+	list_del(&ioa_cfg->queue);
+	spin_unlock(&ipr_driver_lock);
+
+	if (ioa_cfg->sdt_state == ABORT_DUMP)
+		ioa_cfg->sdt_state = WAIT_FOR_DUMP;
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, host_lock_flags);
+
+	ipr_free_all_resources(ioa_cfg);
+
+	LEAVE;
+}
+
+/**
+ * ipr_remove - IOA hot plug remove entry point
+ * @pdev:	pci device struct
+ *
+ * Adapter hot plug remove entry point.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_remove(struct pci_dev *pdev)
+{
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(pdev);
+
+	ENTER;
+
+	ioa_cfg->allow_cmds = 0;
+	flush_scheduled_work();
+	ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj,
+			      &ipr_trace_attr);
+	ipr_remove_dump_file(&ioa_cfg->host->shost_classdev.kobj,
+			     &ipr_dump_attr);
+	scsi_remove_host(ioa_cfg->host);
+
+	__ipr_remove(pdev);
+
+	LEAVE;
+}
+
+/**
+ * ipr_probe - Adapter hot plug add entry point
+ *
+ * Return value:
+ * 	0 on success / non-zero on failure
+ **/
+static int __devinit ipr_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *dev_id)
+{
+	struct ipr_ioa_cfg *ioa_cfg;
+	int rc;
+
+	rc = ipr_probe_ioa(pdev, dev_id);
+
+	if (rc)
+		return rc;
+
+	ioa_cfg = pci_get_drvdata(pdev);
+	rc = ipr_probe_ioa_part2(ioa_cfg);
+
+	if (rc) {
+		__ipr_remove(pdev);
+		return rc;
+	}
+
+	rc = scsi_add_host(ioa_cfg->host, &pdev->dev);
+
+	if (rc) {
+		__ipr_remove(pdev);
+		return rc;
+	}
+
+	rc = ipr_create_trace_file(&ioa_cfg->host->shost_classdev.kobj,
+				   &ipr_trace_attr);
+
+	if (rc) {
+		scsi_remove_host(ioa_cfg->host);
+		__ipr_remove(pdev);
+		return rc;
+	}
+
+	rc = ipr_create_dump_file(&ioa_cfg->host->shost_classdev.kobj,
+				   &ipr_dump_attr);
+
+	if (rc) {
+		ipr_remove_trace_file(&ioa_cfg->host->shost_classdev.kobj,
+				      &ipr_trace_attr);
+		scsi_remove_host(ioa_cfg->host);
+		__ipr_remove(pdev);
+		return rc;
+	}
+
+	scsi_scan_host(ioa_cfg->host);
+	ipr_scan_vsets(ioa_cfg);
+	scsi_add_device(ioa_cfg->host, IPR_IOA_BUS, IPR_IOA_TARGET, IPR_IOA_LUN);
+	ioa_cfg->allow_ml_add_del = 1;
+	schedule_work(&ioa_cfg->work_q);
+	return 0;
+}
+
+/**
+ * ipr_shutdown - Shutdown handler.
+ * @dev:	device struct
+ *
+ * This function is invoked upon system shutdown/reboot. It will issue
+ * an adapter shutdown to the adapter to flush the write cache.
+ *
+ * Return value:
+ * 	none
+ **/
+static void ipr_shutdown(struct device *dev)
+{
+	struct ipr_ioa_cfg *ioa_cfg = pci_get_drvdata(to_pci_dev(dev));
+	unsigned long lock_flags = 0;
+
+	spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
+	ipr_initiate_ioa_bringdown(ioa_cfg, IPR_SHUTDOWN_NORMAL);
+	spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
+	wait_event(ioa_cfg->reset_wait_q, !ioa_cfg->in_reset_reload);
+}
+
+static struct pci_device_id ipr_pci_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5702,
+		0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_5703,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573D,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_MYLEX, PCI_DEVICE_ID_IBM_GEMSTONE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_573E,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571B,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_572E,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CITRINE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571A,
+	      0, 0, (kernel_ulong_t)&ipr_chip_cfg[0] },
+	{ PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_SNIPE,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_2780,
+		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+	{ PCI_VENDOR_ID_ADAPTEC2, PCI_DEVICE_ID_ADAPTEC2_SCAMP,
+		PCI_VENDOR_ID_IBM, IPR_SUBS_DEV_ID_571E,
+		0, 0, (kernel_ulong_t)&ipr_chip_cfg[1] },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, ipr_pci_table);
+
+static struct pci_driver ipr_driver = {
+	.name = IPR_NAME,
+	.id_table = ipr_pci_table,
+	.probe = ipr_probe,
+	.remove = ipr_remove,
+	.driver = {
+		.shutdown = ipr_shutdown,
+	},
+};
+
+/**
+ * ipr_init - Module entry point
+ *
+ * Return value:
+ * 	0 on success / negative value on failure
+ **/
+static int __init ipr_init(void)
+{
+	ipr_info("IBM Power RAID SCSI Device Driver version: %s %s\n",
+		 IPR_DRIVER_VERSION, IPR_DRIVER_DATE);
+
+	return pci_module_init(&ipr_driver);
+}
+
+/**
+ * ipr_exit - Module unload
+ *
+ * Module unload entry point.
+ *
+ * Return value:
+ * 	none
+ **/
+static void __exit ipr_exit(void)
+{
+	pci_unregister_driver(&ipr_driver);
+}
+
+module_init(ipr_init);
+module_exit(ipr_exit);
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
new file mode 100644
index 0000000..446f425
--- /dev/null
+++ b/drivers/scsi/ipr.h
@@ -0,0 +1,1261 @@
+/*
+ * ipr.h -- driver for IBM Power Linux RAID adapters
+ *
+ * Written By: Brian King <brking@us.ibm.com>, IBM Corporation
+ *
+ * Copyright (C) 2003, 2004 IBM Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * Alan Cox <alan@redhat.com> - Removed several careless u32/dma_addr_t errors
+ *				that broke 64bit platforms.
+ */
+
+#ifndef _IPR_H
+#define _IPR_H
+
+#include <linux/types.h>
+#include <linux/completion.h>
+#include <linux/list.h>
+#include <linux/kref.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+
+/*
+ * Literals
+ */
+#define IPR_DRIVER_VERSION "2.0.13"
+#define IPR_DRIVER_DATE "(February 21, 2005)"
+
+/*
+ * IPR_DBG_TRACE: Setting this to 1 will turn on some general function tracing
+ *			resulting in a bunch of extra debugging printks to the console
+ *
+ * IPR_DEBUG:	Setting this to 1 will turn on some error path tracing.
+ *			Enables the ipr_trace macro.
+ */
+#ifdef IPR_DEBUG_ALL
+#define IPR_DEBUG				1
+#define IPR_DBG_TRACE			1
+#else
+#define IPR_DEBUG				0
+#define IPR_DBG_TRACE			0
+#endif
+
+/*
+ * IPR_MAX_CMD_PER_LUN: This defines the maximum number of outstanding
+ *	ops per device for devices not running tagged command queuing.
+ *	This can be adjusted at runtime through sysfs device attributes.
+ */
+#define IPR_MAX_CMD_PER_LUN				6
+
+/*
+ * IPR_NUM_BASE_CMD_BLKS: This defines the maximum number of
+ *	ops the mid-layer can send to the adapter.
+ */
+#define IPR_NUM_BASE_CMD_BLKS				100
+
+#define IPR_SUBS_DEV_ID_2780	0x0264
+#define IPR_SUBS_DEV_ID_5702	0x0266
+#define IPR_SUBS_DEV_ID_5703	0x0278
+#define IPR_SUBS_DEV_ID_572E  0x028D
+#define IPR_SUBS_DEV_ID_573E  0x02D3
+#define IPR_SUBS_DEV_ID_573D  0x02D4
+#define IPR_SUBS_DEV_ID_571A	0x02C0
+#define IPR_SUBS_DEV_ID_571B	0x02BE
+#define IPR_SUBS_DEV_ID_571E  0x02BF
+
+#define IPR_NAME				"ipr"
+
+/*
+ * Return codes
+ */
+#define IPR_RC_JOB_CONTINUE		1
+#define IPR_RC_JOB_RETURN		2
+
+/*
+ * IOASCs
+ */
+#define IPR_IOASC_NR_INIT_CMD_REQUIRED		0x02040200
+#define IPR_IOASC_SYNC_REQUIRED			0x023f0000
+#define IPR_IOASC_MED_DO_NOT_REALLOC		0x03110C00
+#define IPR_IOASC_HW_SEL_TIMEOUT			0x04050000
+#define IPR_IOASC_HW_DEV_BUS_STATUS			0x04448500
+#define	IPR_IOASC_IOASC_MASK			0xFFFFFF00
+#define	IPR_IOASC_SCSI_STATUS_MASK		0x000000FF
+#define IPR_IOASC_IR_RESOURCE_HANDLE		0x05250000
+#define IPR_IOASC_BUS_WAS_RESET			0x06290000
+#define IPR_IOASC_BUS_WAS_RESET_BY_OTHER		0x06298000
+#define IPR_IOASC_ABORTED_CMD_TERM_BY_HOST	0x0B5A0000
+
+#define IPR_FIRST_DRIVER_IOASC			0x10000000
+#define IPR_IOASC_IOA_WAS_RESET			0x10000001
+#define IPR_IOASC_PCI_ACCESS_ERROR			0x10000002
+
+#define IPR_NUM_LOG_HCAMS				2
+#define IPR_NUM_CFG_CHG_HCAMS				2
+#define IPR_NUM_HCAMS	(IPR_NUM_LOG_HCAMS + IPR_NUM_CFG_CHG_HCAMS)
+#define IPR_MAX_NUM_TARGETS_PER_BUS			0x10
+#define IPR_MAX_NUM_LUNS_PER_TARGET			256
+#define IPR_MAX_NUM_VSET_LUNS_PER_TARGET	8
+#define IPR_VSET_BUS					0xff
+#define IPR_IOA_BUS						0xff
+#define IPR_IOA_TARGET					0xff
+#define IPR_IOA_LUN						0xff
+#define IPR_MAX_NUM_BUSES				4
+#define IPR_MAX_BUS_TO_SCAN				IPR_MAX_NUM_BUSES
+
+#define IPR_NUM_RESET_RELOAD_RETRIES		3
+
+/* We need resources for HCAMS, IOA reset, IOA bringdown, and ERP */
+#define IPR_NUM_INTERNAL_CMD_BLKS	(IPR_NUM_HCAMS + \
+                                     ((IPR_NUM_RESET_RELOAD_RETRIES + 1) * 2) + 3)
+
+#define IPR_MAX_COMMANDS		IPR_NUM_BASE_CMD_BLKS
+#define IPR_NUM_CMD_BLKS		(IPR_NUM_BASE_CMD_BLKS + \
+						IPR_NUM_INTERNAL_CMD_BLKS)
+
+#define IPR_MAX_PHYSICAL_DEVS				192
+
+#define IPR_MAX_SGLIST					64
+#define IPR_IOA_MAX_SECTORS				32767
+#define IPR_VSET_MAX_SECTORS				512
+#define IPR_MAX_CDB_LEN					16
+
+#define IPR_DEFAULT_BUS_WIDTH				16
+#define IPR_80MBs_SCSI_RATE		((80 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
+#define IPR_U160_SCSI_RATE	((160 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
+#define IPR_U320_SCSI_RATE	((320 * 10) / (IPR_DEFAULT_BUS_WIDTH / 8))
+#define IPR_MAX_SCSI_RATE(width) ((320 * 10) / ((width) / 8))
+
+#define IPR_IOA_RES_HANDLE				0xffffffff
+#define IPR_IOA_RES_ADDR				0x00ffffff
+
+/*
+ * Adapter Commands
+ */
+#define IPR_QUERY_RSRC_STATE				0xC2
+#define IPR_RESET_DEVICE				0xC3
+#define	IPR_RESET_TYPE_SELECT				0x80
+#define	IPR_LUN_RESET					0x40
+#define	IPR_TARGET_RESET					0x20
+#define	IPR_BUS_RESET					0x10
+#define IPR_ID_HOST_RR_Q				0xC4
+#define IPR_QUERY_IOA_CONFIG				0xC5
+#define IPR_CANCEL_ALL_REQUESTS			0xCE
+#define IPR_HOST_CONTROLLED_ASYNC			0xCF
+#define	IPR_HCAM_CDB_OP_CODE_CONFIG_CHANGE	0x01
+#define	IPR_HCAM_CDB_OP_CODE_LOG_DATA		0x02
+#define IPR_SET_SUPPORTED_DEVICES			0xFB
+#define IPR_IOA_SHUTDOWN				0xF7
+#define	IPR_WR_BUF_DOWNLOAD_AND_SAVE			0x05
+
+/*
+ * Timeouts
+ */
+#define IPR_SHUTDOWN_TIMEOUT			(ipr_fastfail ? 60 * HZ : 10 * 60 * HZ)
+#define IPR_VSET_RW_TIMEOUT			(ipr_fastfail ? 30 * HZ : 2 * 60 * HZ)
+#define IPR_ABBREV_SHUTDOWN_TIMEOUT		(10 * HZ)
+#define IPR_DEVICE_RESET_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_CANCEL_ALL_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_ABORT_TASK_TIMEOUT		(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_INTERNAL_TIMEOUT			(ipr_fastfail ? 10 * HZ : 30 * HZ)
+#define IPR_WRITE_BUFFER_TIMEOUT		(10 * 60 * HZ)
+#define IPR_SET_SUP_DEVICE_TIMEOUT		(2 * 60 * HZ)
+#define IPR_REQUEST_SENSE_TIMEOUT		(10 * HZ)
+#define IPR_OPERATIONAL_TIMEOUT		(5 * 60)
+#define IPR_WAIT_FOR_RESET_TIMEOUT		(2 * HZ)
+#define IPR_CHECK_FOR_RESET_TIMEOUT		(HZ / 10)
+#define IPR_WAIT_FOR_BIST_TIMEOUT		(2 * HZ)
+#define IPR_DUMP_TIMEOUT			(15 * HZ)
+
+/*
+ * SCSI Literals
+ */
+#define IPR_VENDOR_ID_LEN			8
+#define IPR_PROD_ID_LEN				16
+#define IPR_SERIAL_NUM_LEN			8
+
+/*
+ * Hardware literals
+ */
+#define IPR_FMT2_MBX_ADDR_MASK				0x0fffffff
+#define IPR_FMT2_MBX_BAR_SEL_MASK			0xf0000000
+#define IPR_FMT2_MKR_BAR_SEL_SHIFT			28
+#define IPR_GET_FMT2_BAR_SEL(mbx) \
+(((mbx) & IPR_FMT2_MBX_BAR_SEL_MASK) >> IPR_FMT2_MKR_BAR_SEL_SHIFT)
+#define IPR_SDT_FMT2_BAR0_SEL				0x0
+#define IPR_SDT_FMT2_BAR1_SEL				0x1
+#define IPR_SDT_FMT2_BAR2_SEL				0x2
+#define IPR_SDT_FMT2_BAR3_SEL				0x3
+#define IPR_SDT_FMT2_BAR4_SEL				0x4
+#define IPR_SDT_FMT2_BAR5_SEL				0x5
+#define IPR_SDT_FMT2_EXP_ROM_SEL			0x8
+#define IPR_FMT2_SDT_READY_TO_USE			0xC4D4E3F2
+#define IPR_DOORBELL					0x82800000
+
+#define IPR_PCII_IOA_TRANS_TO_OPER			(0x80000000 >> 0)
+#define IPR_PCII_IOARCB_XFER_FAILED			(0x80000000 >> 3)
+#define IPR_PCII_IOA_UNIT_CHECKED			(0x80000000 >> 4)
+#define IPR_PCII_NO_HOST_RRQ				(0x80000000 >> 5)
+#define IPR_PCII_CRITICAL_OPERATION			(0x80000000 >> 6)
+#define IPR_PCII_IO_DEBUG_ACKNOWLEDGE		(0x80000000 >> 7)
+#define IPR_PCII_IOARRIN_LOST				(0x80000000 >> 27)
+#define IPR_PCII_MMIO_ERROR				(0x80000000 >> 28)
+#define IPR_PCII_PROC_ERR_STATE			(0x80000000 >> 29)
+#define IPR_PCII_HRRQ_UPDATED				(0x80000000 >> 30)
+#define IPR_PCII_CORE_ISSUED_RST_REQ		(0x80000000 >> 31)
+
+#define IPR_PCII_ERROR_INTERRUPTS \
+(IPR_PCII_IOARCB_XFER_FAILED | IPR_PCII_IOA_UNIT_CHECKED | \
+IPR_PCII_NO_HOST_RRQ | IPR_PCII_IOARRIN_LOST | IPR_PCII_MMIO_ERROR)
+
+#define IPR_PCII_OPER_INTERRUPTS \
+(IPR_PCII_ERROR_INTERRUPTS | IPR_PCII_HRRQ_UPDATED | IPR_PCII_IOA_TRANS_TO_OPER)
+
+#define IPR_UPROCI_RESET_ALERT			(0x80000000 >> 7)
+#define IPR_UPROCI_IO_DEBUG_ALERT			(0x80000000 >> 9)
+
+#define IPR_LDUMP_MAX_LONG_ACK_DELAY_IN_USEC		200000	/* 200 ms */
+#define IPR_LDUMP_MAX_SHORT_ACK_DELAY_IN_USEC		200000	/* 200 ms */
+
+/*
+ * Dump literals
+ */
+#define IPR_MAX_IOA_DUMP_SIZE				(4 * 1024 * 1024)
+#define IPR_NUM_SDT_ENTRIES				511
+#define IPR_MAX_NUM_DUMP_PAGES	((IPR_MAX_IOA_DUMP_SIZE / PAGE_SIZE) + 1)
+
+/*
+ * Misc literals
+ */
+#define IPR_NUM_IOADL_ENTRIES			IPR_MAX_SGLIST
+
+/*
+ * Adapter interface types
+ */
+
+struct ipr_res_addr {
+	u8 reserved;
+	u8 bus;
+	u8 target;
+	u8 lun;
+#define IPR_GET_PHYS_LOC(res_addr) \
+	(((res_addr).bus << 16) | ((res_addr).target << 8) | (res_addr).lun)
+}__attribute__((packed, aligned (4)));
+
+struct ipr_std_inq_vpids {
+	u8 vendor_id[IPR_VENDOR_ID_LEN];
+	u8 product_id[IPR_PROD_ID_LEN];
+}__attribute__((packed));
+
+struct ipr_std_inq_data {
+	u8 peri_qual_dev_type;
+#define IPR_STD_INQ_PERI_QUAL(peri) ((peri) >> 5)
+#define IPR_STD_INQ_PERI_DEV_TYPE(peri) ((peri) & 0x1F)
+
+	u8 removeable_medium_rsvd;
+#define IPR_STD_INQ_REMOVEABLE_MEDIUM 0x80
+
+#define IPR_IS_DASD_DEVICE(std_inq) \
+((IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_DISK) && \
+!(((std_inq).removeable_medium_rsvd) & IPR_STD_INQ_REMOVEABLE_MEDIUM))
+
+#define IPR_IS_SES_DEVICE(std_inq) \
+(IPR_STD_INQ_PERI_DEV_TYPE((std_inq).peri_qual_dev_type) == TYPE_ENCLOSURE)
+
+	u8 version;
+	u8 aen_naca_fmt;
+	u8 additional_len;
+	u8 sccs_rsvd;
+	u8 bq_enc_multi;
+	u8 sync_cmdq_flags;
+
+	struct ipr_std_inq_vpids vpids;
+
+	u8 ros_rsvd_ram_rsvd[4];
+
+	u8 serial_num[IPR_SERIAL_NUM_LEN];
+}__attribute__ ((packed));
+
+struct ipr_config_table_entry {
+	u8 service_level;
+	u8 array_id;
+	u8 flags;
+#define IPR_IS_IOA_RESOURCE	0x80
+#define IPR_IS_ARRAY_MEMBER 0x20
+#define IPR_IS_HOT_SPARE	0x10
+
+	u8 rsvd_subtype;
+#define IPR_RES_SUBTYPE(res) (((res)->cfgte.rsvd_subtype) & 0x0f)
+#define IPR_SUBTYPE_AF_DASD			0
+#define IPR_SUBTYPE_GENERIC_SCSI	1
+#define IPR_SUBTYPE_VOLUME_SET		2
+
+	struct ipr_res_addr res_addr;
+	__be32 res_handle;
+	__be32 reserved4[2];
+	struct ipr_std_inq_data std_inq_data;
+}__attribute__ ((packed, aligned (4)));
+
+struct ipr_config_table_hdr {
+	u8 num_entries;
+	u8 flags;
+#define IPR_UCODE_DOWNLOAD_REQ	0x10
+	__be16 reserved;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_config_table {
+	struct ipr_config_table_hdr hdr;
+	struct ipr_config_table_entry dev[IPR_MAX_PHYSICAL_DEVS];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_cfg_ch_not {
+	struct ipr_config_table_entry cfgte;
+	u8 reserved[936];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_supported_device {
+	__be16 data_length;
+	u8 reserved;
+	u8 num_records;
+	struct ipr_std_inq_vpids vpids;
+	u8 reserved2[16];
+}__attribute__((packed, aligned (4)));
+
+/* Command packet structure */
+struct ipr_cmd_pkt {
+	__be16 reserved;		/* Reserved by IOA */
+	u8 request_type;
+#define IPR_RQTYPE_SCSICDB		0x00
+#define IPR_RQTYPE_IOACMD		0x01
+#define IPR_RQTYPE_HCAM			0x02
+
+	u8 luntar_luntrn;
+
+	u8 flags_hi;
+#define IPR_FLAGS_HI_WRITE_NOT_READ		0x80
+#define IPR_FLAGS_HI_NO_ULEN_CHK		0x20
+#define IPR_FLAGS_HI_SYNC_OVERRIDE		0x10
+#define IPR_FLAGS_HI_SYNC_COMPLETE		0x08
+#define IPR_FLAGS_HI_NO_LINK_DESC		0x04
+
+	u8 flags_lo;
+#define IPR_FLAGS_LO_ALIGNED_BFR		0x20
+#define IPR_FLAGS_LO_DELAY_AFTER_RST	0x10
+#define IPR_FLAGS_LO_UNTAGGED_TASK		0x00
+#define IPR_FLAGS_LO_SIMPLE_TASK		0x02
+#define IPR_FLAGS_LO_ORDERED_TASK		0x04
+#define IPR_FLAGS_LO_HEAD_OF_Q_TASK		0x06
+#define IPR_FLAGS_LO_ACA_TASK			0x08
+
+	u8 cdb[16];
+	__be16 timeout;
+}__attribute__ ((packed, aligned(4)));
+
+/* IOA Request Control Block    128 bytes  */
+struct ipr_ioarcb {
+	__be32 ioarcb_host_pci_addr;
+	__be32 reserved;
+	__be32 res_handle;
+	__be32 host_response_handle;
+	__be32 reserved1;
+	__be32 reserved2;
+	__be32 reserved3;
+
+	__be32 write_data_transfer_length;
+	__be32 read_data_transfer_length;
+	__be32 write_ioadl_addr;
+	__be32 write_ioadl_len;
+	__be32 read_ioadl_addr;
+	__be32 read_ioadl_len;
+
+	__be32 ioasa_host_pci_addr;
+	__be16 ioasa_len;
+	__be16 reserved4;
+
+	struct ipr_cmd_pkt cmd_pkt;
+
+	__be32 add_cmd_parms_len;
+	__be32 add_cmd_parms[10];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioadl_desc {
+	__be32 flags_and_data_len;
+#define IPR_IOADL_FLAGS_MASK		0xff000000
+#define IPR_IOADL_GET_FLAGS(x) (be32_to_cpu(x) & IPR_IOADL_FLAGS_MASK)
+#define IPR_IOADL_DATA_LEN_MASK		0x00ffffff
+#define IPR_IOADL_GET_DATA_LEN(x) (be32_to_cpu(x) & IPR_IOADL_DATA_LEN_MASK)
+#define IPR_IOADL_FLAGS_READ		0x48000000
+#define IPR_IOADL_FLAGS_READ_LAST	0x49000000
+#define IPR_IOADL_FLAGS_WRITE		0x68000000
+#define IPR_IOADL_FLAGS_WRITE_LAST	0x69000000
+#define IPR_IOADL_FLAGS_LAST		0x01000000
+
+	__be32 address;
+}__attribute__((packed, aligned (8)));
+
+struct ipr_ioasa_vset {
+	__be32 failing_lba_hi;
+	__be32 failing_lba_lo;
+	__be32 ioa_data[22];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa_af_dasd {
+	__be32 failing_lba;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa_gpdd {
+	u8 end_state;
+	u8 bus_phase;
+	__be16 reserved;
+	__be32 ioa_data[23];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa_raw {
+	__be32 ioa_data[24];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ioasa {
+	__be32 ioasc;
+#define IPR_IOASC_SENSE_KEY(ioasc) ((ioasc) >> 24)
+#define IPR_IOASC_SENSE_CODE(ioasc) (((ioasc) & 0x00ff0000) >> 16)
+#define IPR_IOASC_SENSE_QUAL(ioasc) (((ioasc) & 0x0000ff00) >> 8)
+#define IPR_IOASC_SENSE_STATUS(ioasc) ((ioasc) & 0x000000ff)
+
+	__be16 ret_stat_len;	/* Length of the returned IOASA */
+
+	__be16 avail_stat_len;	/* Total Length of status available. */
+
+	__be32 residual_data_len;	/* number of bytes in the host data */
+	/* buffers that were not used by the IOARCB command. */
+
+	__be32 ilid;
+#define IPR_NO_ILID			0
+#define IPR_DRIVER_ILID		0xffffffff
+
+	__be32 fd_ioasc;
+
+	__be32 fd_phys_locator;
+
+	__be32 fd_res_handle;
+
+	__be32 ioasc_specific;	/* status code specific field */
+#define IPR_IOASC_SPECIFIC_MASK		0x00ffffff
+#define IPR_FIELD_POINTER_VALID		(0x80000000 >> 8)
+#define IPR_FIELD_POINTER_MASK		0x0000ffff
+
+	union {
+		struct ipr_ioasa_vset vset;
+		struct ipr_ioasa_af_dasd dasd;
+		struct ipr_ioasa_gpdd gpdd;
+		struct ipr_ioasa_raw raw;
+	} u;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_mode_parm_hdr {
+	u8 length;
+	u8 medium_type;
+	u8 device_spec_parms;
+	u8 block_desc_len;
+}__attribute__((packed));
+
+struct ipr_mode_pages {
+	struct ipr_mode_parm_hdr hdr;
+	u8 data[255 - sizeof(struct ipr_mode_parm_hdr)];
+}__attribute__((packed));
+
+struct ipr_mode_page_hdr {
+	u8 ps_page_code;
+#define IPR_MODE_PAGE_PS	0x80
+#define IPR_GET_MODE_PAGE_CODE(hdr) ((hdr)->ps_page_code & 0x3F)
+	u8 page_length;
+}__attribute__ ((packed));
+
+struct ipr_dev_bus_entry {
+	struct ipr_res_addr res_addr;
+	u8 flags;
+#define IPR_SCSI_ATTR_ENABLE_QAS			0x80
+#define IPR_SCSI_ATTR_DISABLE_QAS			0x40
+#define IPR_SCSI_ATTR_QAS_MASK				0xC0
+#define IPR_SCSI_ATTR_ENABLE_TM				0x20
+#define IPR_SCSI_ATTR_NO_TERM_PWR			0x10
+#define IPR_SCSI_ATTR_TM_SUPPORTED			0x08
+#define IPR_SCSI_ATTR_LVD_TO_SE_NOT_ALLOWED	0x04
+
+	u8 scsi_id;
+	u8 bus_width;
+	u8 extended_reset_delay;
+#define IPR_EXTENDED_RESET_DELAY	7
+
+	__be32 max_xfer_rate;
+
+	u8 spinup_delay;
+	u8 reserved3;
+	__be16 reserved4;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_mode_page28 {
+	struct ipr_mode_page_hdr hdr;
+	u8 num_entries;
+	u8 entry_length;
+	struct ipr_dev_bus_entry bus[0];
+}__attribute__((packed));
+
+struct ipr_ioa_vpd {
+	struct ipr_std_inq_data std_inq_data;
+	u8 ascii_part_num[12];
+	u8 reserved[40];
+	u8 ascii_plant_code[4];
+}__attribute__((packed));
+
+struct ipr_inquiry_page3 {
+	u8 peri_qual_dev_type;
+	u8 page_code;
+	u8 reserved1;
+	u8 page_length;
+	u8 ascii_len;
+	u8 reserved2[3];
+	u8 load_id[4];
+	u8 major_release;
+	u8 card_type;
+	u8 minor_release[2];
+	u8 ptf_number[4];
+	u8 patch_number[4];
+}__attribute__((packed));
+
+struct ipr_hostrcb_device_data_entry {
+	struct ipr_std_inq_vpids dev_vpids;
+	u8 dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_res_addr dev_res_addr;
+	struct ipr_std_inq_vpids new_dev_vpids;
+	u8 new_dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids ioa_last_with_dev_vpids;
+	u8 ioa_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids cfc_last_with_dev_vpids;
+	u8 cfc_last_with_dev_sn[IPR_SERIAL_NUM_LEN];
+	__be32 ioa_data[5];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_array_data_entry {
+	struct ipr_std_inq_vpids vpids;
+	u8 serial_num[IPR_SERIAL_NUM_LEN];
+	struct ipr_res_addr expected_dev_res_addr;
+	struct ipr_res_addr dev_res_addr;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_ff_error {
+	__be32 ioa_data[246];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_01_error {
+	__be32 seek_counter;
+	__be32 read_counter;
+	u8 sense_data[32];
+	__be32 ioa_data[236];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_02_error {
+	struct ipr_std_inq_vpids ioa_vpids;
+	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids cfc_vpids;
+	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids ioa_last_attached_to_cfc_vpids;
+	u8 ioa_last_attached_to_cfc_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids cfc_last_attached_to_ioa_vpids;
+	u8 cfc_last_attached_to_ioa_sn[IPR_SERIAL_NUM_LEN];
+	__be32 ioa_data[3];
+	u8 reserved[844];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_03_error {
+	struct ipr_std_inq_vpids ioa_vpids;
+	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids cfc_vpids;
+	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
+	__be32 errors_detected;
+	__be32 errors_logged;
+	u8 ioa_data[12];
+	struct ipr_hostrcb_device_data_entry dev_entry[3];
+	u8 reserved[444];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_type_04_error {
+	struct ipr_std_inq_vpids ioa_vpids;
+	u8 ioa_sn[IPR_SERIAL_NUM_LEN];
+	struct ipr_std_inq_vpids cfc_vpids;
+	u8 cfc_sn[IPR_SERIAL_NUM_LEN];
+	u8 ioa_data[12];
+	struct ipr_hostrcb_array_data_entry array_member[10];
+	__be32 exposed_mode_adn;
+	__be32 array_id;
+	struct ipr_std_inq_vpids incomp_dev_vpids;
+	u8 incomp_dev_sn[IPR_SERIAL_NUM_LEN];
+	__be32 ioa_data2;
+	struct ipr_hostrcb_array_data_entry array_member2[8];
+	struct ipr_res_addr last_func_vset_res_addr;
+	u8 vset_serial_num[IPR_SERIAL_NUM_LEN];
+	u8 protection_level[8];
+	u8 reserved[124];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_error {
+	__be32 failing_dev_ioasc;
+	struct ipr_res_addr failing_dev_res_addr;
+	__be32 failing_dev_res_handle;
+	__be32 prc;
+	union {
+		struct ipr_hostrcb_type_ff_error type_ff_error;
+		struct ipr_hostrcb_type_01_error type_01_error;
+		struct ipr_hostrcb_type_02_error type_02_error;
+		struct ipr_hostrcb_type_03_error type_03_error;
+		struct ipr_hostrcb_type_04_error type_04_error;
+	} u;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb_raw {
+	__be32 data[sizeof(struct ipr_hostrcb_error)/sizeof(__be32)];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hcam {
+	u8 op_code;
+#define IPR_HOST_RCB_OP_CODE_CONFIG_CHANGE			0xE1
+#define IPR_HOST_RCB_OP_CODE_LOG_DATA				0xE2
+
+	u8 notify_type;
+#define IPR_HOST_RCB_NOTIF_TYPE_EXISTING_CHANGED	0x00
+#define IPR_HOST_RCB_NOTIF_TYPE_NEW_ENTRY			0x01
+#define IPR_HOST_RCB_NOTIF_TYPE_REM_ENTRY			0x02
+#define IPR_HOST_RCB_NOTIF_TYPE_ERROR_LOG_ENTRY		0x10
+#define IPR_HOST_RCB_NOTIF_TYPE_INFORMATION_ENTRY	0x11
+
+	u8 notifications_lost;
+#define IPR_HOST_RCB_NO_NOTIFICATIONS_LOST			0
+#define IPR_HOST_RCB_NOTIFICATIONS_LOST				0x80
+
+	u8 flags;
+#define IPR_HOSTRCB_INTERNAL_OPER	0x80
+#define IPR_HOSTRCB_ERR_RESP_SENT	0x40
+
+	u8 overlay_id;
+#define IPR_HOST_RCB_OVERLAY_ID_1				0x01
+#define IPR_HOST_RCB_OVERLAY_ID_2				0x02
+#define IPR_HOST_RCB_OVERLAY_ID_3				0x03
+#define IPR_HOST_RCB_OVERLAY_ID_4				0x04
+#define IPR_HOST_RCB_OVERLAY_ID_6				0x06
+#define IPR_HOST_RCB_OVERLAY_ID_DEFAULT			0xFF
+
+	u8 reserved1[3];
+	__be32 ilid;
+	__be32 time_since_last_ioa_reset;
+	__be32 reserved2;
+	__be32 length;
+
+	union {
+		struct ipr_hostrcb_error error;
+		struct ipr_hostrcb_cfg_ch_not ccn;
+		struct ipr_hostrcb_raw raw;
+	} u;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_hostrcb {
+	struct ipr_hcam hcam;
+	dma_addr_t hostrcb_dma;
+	struct list_head queue;
+};
+
+/* IPR smart dump table structures */
+struct ipr_sdt_entry {
+	__be32 bar_str_offset;
+	__be32 end_offset;
+	u8 entry_byte;
+	u8 reserved[3];
+
+	u8 flags;
+#define IPR_SDT_ENDIAN		0x80
+#define IPR_SDT_VALID_ENTRY	0x20
+
+	u8 resv;
+	__be16 priority;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_sdt_header {
+	__be32 state;
+	__be32 num_entries;
+	__be32 num_entries_used;
+	__be32 dump_size;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_sdt {
+	struct ipr_sdt_header hdr;
+	struct ipr_sdt_entry entry[IPR_NUM_SDT_ENTRIES];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_uc_sdt {
+	struct ipr_sdt_header hdr;
+	struct ipr_sdt_entry entry[1];
+}__attribute__((packed, aligned (4)));
+
+/*
+ * Driver types
+ */
+struct ipr_bus_attributes {
+	u8 bus;
+	u8 qas_enabled;
+	u8 bus_width;
+	u8 reserved;
+	u32 max_xfer_rate;
+};
+
+struct ipr_resource_entry {
+	struct ipr_config_table_entry cfgte;
+	u8 needs_sync_complete:1;
+	u8 in_erp:1;
+	u8 add_to_ml:1;
+	u8 del_from_ml:1;
+	u8 resetting_device:1;
+
+	struct scsi_device *sdev;
+	struct list_head queue;
+};
+
+struct ipr_resource_hdr {
+	u16 num_entries;
+	u16 reserved;
+};
+
+struct ipr_resource_table {
+	struct ipr_resource_hdr hdr;
+	struct ipr_resource_entry dev[IPR_MAX_PHYSICAL_DEVS];
+};
+
+struct ipr_misc_cbs {
+	struct ipr_ioa_vpd ioa_vpd;
+	struct ipr_inquiry_page3 page3_data;
+	struct ipr_mode_pages mode_pages;
+	struct ipr_supported_device supp_dev;
+};
+
+struct ipr_interrupt_offsets {
+	unsigned long set_interrupt_mask_reg;
+	unsigned long clr_interrupt_mask_reg;
+	unsigned long sense_interrupt_mask_reg;
+	unsigned long clr_interrupt_reg;
+
+	unsigned long sense_interrupt_reg;
+	unsigned long ioarrin_reg;
+	unsigned long sense_uproc_interrupt_reg;
+	unsigned long set_uproc_interrupt_reg;
+	unsigned long clr_uproc_interrupt_reg;
+};
+
+struct ipr_interrupts {
+	void __iomem *set_interrupt_mask_reg;
+	void __iomem *clr_interrupt_mask_reg;
+	void __iomem *sense_interrupt_mask_reg;
+	void __iomem *clr_interrupt_reg;
+
+	void __iomem *sense_interrupt_reg;
+	void __iomem *ioarrin_reg;
+	void __iomem *sense_uproc_interrupt_reg;
+	void __iomem *set_uproc_interrupt_reg;
+	void __iomem *clr_uproc_interrupt_reg;
+};
+
+struct ipr_chip_cfg_t {
+	u32 mailbox;
+	u8 cache_line_size;
+	struct ipr_interrupt_offsets regs;
+};
+
+struct ipr_chip_t {
+	u16 vendor;
+	u16 device;
+	const struct ipr_chip_cfg_t *cfg;
+};
+
+enum ipr_shutdown_type {
+	IPR_SHUTDOWN_NORMAL = 0x00,
+	IPR_SHUTDOWN_PREPARE_FOR_NORMAL = 0x40,
+	IPR_SHUTDOWN_ABBREV = 0x80,
+	IPR_SHUTDOWN_NONE = 0x100
+};
+
+struct ipr_trace_entry {
+	u32 time;
+
+	u8 op_code;
+	u8 type;
+#define IPR_TRACE_START			0x00
+#define IPR_TRACE_FINISH		0xff
+	u16 cmd_index;
+
+	__be32 res_handle;
+	union {
+		u32 ioasc;
+		u32 add_data;
+		u32 res_addr;
+	} u;
+};
+
+struct ipr_sglist {
+	u32 order;
+	u32 num_sg;
+	u32 buffer_len;
+	struct scatterlist scatterlist[1];
+};
+
+enum ipr_sdt_state {
+	INACTIVE,
+	WAIT_FOR_DUMP,
+	GET_DUMP,
+	ABORT_DUMP,
+	DUMP_OBTAINED
+};
+
+/* Per-controller data */
+struct ipr_ioa_cfg {
+	char eye_catcher[8];
+#define IPR_EYECATCHER			"iprcfg"
+
+	struct list_head queue;
+
+	u8 allow_interrupts:1;
+	u8 in_reset_reload:1;
+	u8 in_ioa_bringdown:1;
+	u8 ioa_unit_checked:1;
+	u8 ioa_is_dead:1;
+	u8 dump_taken:1;
+	u8 allow_cmds:1;
+	u8 allow_ml_add_del:1;
+
+	u16 type; /* CCIN of the card */
+
+	u8 log_level;
+#define IPR_MAX_LOG_LEVEL			4
+#define IPR_DEFAULT_LOG_LEVEL		2
+
+#define IPR_NUM_TRACE_INDEX_BITS	8
+#define IPR_NUM_TRACE_ENTRIES		(1 << IPR_NUM_TRACE_INDEX_BITS)
+#define IPR_TRACE_SIZE	(sizeof(struct ipr_trace_entry) * IPR_NUM_TRACE_ENTRIES)
+	char trace_start[8];
+#define IPR_TRACE_START_LABEL			"trace"
+	struct ipr_trace_entry *trace;
+	u32 trace_index:IPR_NUM_TRACE_INDEX_BITS;
+
+	/*
+	 * Queue for free command blocks
+	 */
+	char ipr_free_label[8];
+#define IPR_FREEQ_LABEL			"free-q"
+	struct list_head free_q;
+
+	/*
+	 * Queue for command blocks outstanding to the adapter
+	 */
+	char ipr_pending_label[8];
+#define IPR_PENDQ_LABEL			"pend-q"
+	struct list_head pending_q;
+
+	char cfg_table_start[8];
+#define IPR_CFG_TBL_START		"cfg"
+	struct ipr_config_table *cfg_table;
+	dma_addr_t cfg_table_dma;
+
+	char resource_table_label[8];
+#define IPR_RES_TABLE_LABEL		"res_tbl"
+	struct ipr_resource_entry *res_entries;
+	struct list_head free_res_q;
+	struct list_head used_res_q;
+
+	char ipr_hcam_label[8];
+#define IPR_HCAM_LABEL			"hcams"
+	struct ipr_hostrcb *hostrcb[IPR_NUM_HCAMS];
+	dma_addr_t hostrcb_dma[IPR_NUM_HCAMS];
+	struct list_head hostrcb_free_q;
+	struct list_head hostrcb_pending_q;
+
+	__be32 *host_rrq;
+	dma_addr_t host_rrq_dma;
+#define IPR_HRRQ_REQ_RESP_HANDLE_MASK	0xfffffffc
+#define IPR_HRRQ_RESP_BIT_SET			0x00000002
+#define IPR_HRRQ_TOGGLE_BIT				0x00000001
+#define IPR_HRRQ_REQ_RESP_HANDLE_SHIFT	2
+	volatile __be32 *hrrq_start;
+	volatile __be32 *hrrq_end;
+	volatile __be32 *hrrq_curr;
+	volatile u32 toggle_bit;
+
+	struct ipr_bus_attributes bus_attr[IPR_MAX_NUM_BUSES];
+
+	const struct ipr_chip_cfg_t *chip_cfg;
+
+	void __iomem *hdw_dma_regs;	/* iomapped PCI memory space */
+	unsigned long hdw_dma_regs_pci;	/* raw PCI memory space */
+	void __iomem *ioa_mailbox;
+	struct ipr_interrupts regs;
+
+	u16 saved_pcix_cmd_reg;
+	u16 reset_retries;
+
+	u32 errors_logged;
+
+	struct Scsi_Host *host;
+	struct pci_dev *pdev;
+	struct ipr_sglist *ucode_sglist;
+	struct ipr_mode_pages *saved_mode_pages;
+	u8 saved_mode_page_len;
+
+	struct work_struct work_q;
+
+	wait_queue_head_t reset_wait_q;
+
+	struct ipr_dump *dump;
+	enum ipr_sdt_state sdt_state;
+
+	struct ipr_misc_cbs *vpd_cbs;
+	dma_addr_t vpd_cbs_dma;
+
+	struct pci_pool *ipr_cmd_pool;
+
+	struct ipr_cmnd *reset_cmd;
+
+	char ipr_cmd_label[8];
+#define IPR_CMD_LABEL		"ipr_cmnd"
+	struct ipr_cmnd *ipr_cmnd_list[IPR_NUM_CMD_BLKS];
+	u32 ipr_cmnd_list_dma[IPR_NUM_CMD_BLKS];
+};
+
+struct ipr_cmnd {
+	struct ipr_ioarcb ioarcb;
+	struct ipr_ioasa ioasa;
+	struct ipr_ioadl_desc ioadl[IPR_NUM_IOADL_ENTRIES];
+	struct list_head queue;
+	struct scsi_cmnd *scsi_cmd;
+	struct completion completion;
+	struct timer_list timer;
+	void (*done) (struct ipr_cmnd *);
+	int (*job_step) (struct ipr_cmnd *);
+	u16 cmd_index;
+	u8 sense_buffer[SCSI_SENSE_BUFFERSIZE];
+	dma_addr_t sense_buffer_dma;
+	unsigned short dma_use_sg;
+	dma_addr_t dma_handle;
+	struct ipr_cmnd *sibling;
+	union {
+		enum ipr_shutdown_type shutdown_type;
+		struct ipr_hostrcb *hostrcb;
+		unsigned long time_left;
+		unsigned long scratch;
+		struct ipr_resource_entry *res;
+		struct scsi_device *sdev;
+	} u;
+
+	struct ipr_ioa_cfg *ioa_cfg;
+};
+
+struct ipr_ses_table_entry {
+	char product_id[17];
+	char compare_product_id_byte[17];
+	u32 max_bus_speed_limit;	/* MB/sec limit for this backplane */
+};
+
+struct ipr_dump_header {
+	u32 eye_catcher;
+#define IPR_DUMP_EYE_CATCHER		0xC5D4E3F2
+	u32 len;
+	u32 num_entries;
+	u32 first_entry_offset;
+	u32 status;
+#define IPR_DUMP_STATUS_SUCCESS			0
+#define IPR_DUMP_STATUS_QUAL_SUCCESS		2
+#define IPR_DUMP_STATUS_FAILED			0xffffffff
+	u32 os;
+#define IPR_DUMP_OS_LINUX	0x4C4E5558
+	u32 driver_name;
+#define IPR_DUMP_DRIVER_NAME	0x49505232
+}__attribute__((packed, aligned (4)));
+
+struct ipr_dump_entry_header {
+	u32 eye_catcher;
+#define IPR_DUMP_EYE_CATCHER		0xC5D4E3F2
+	u32 len;
+	u32 num_elems;
+	u32 offset;
+	u32 data_type;
+#define IPR_DUMP_DATA_TYPE_ASCII	0x41534349
+#define IPR_DUMP_DATA_TYPE_BINARY	0x42494E41
+	u32 id;
+#define IPR_DUMP_IOA_DUMP_ID		0x494F4131
+#define IPR_DUMP_LOCATION_ID		0x4C4F4341
+#define IPR_DUMP_TRACE_ID		0x54524143
+#define IPR_DUMP_DRIVER_VERSION_ID	0x44525652
+#define IPR_DUMP_DRIVER_TYPE_ID	0x54595045
+#define IPR_DUMP_IOA_CTRL_BLK		0x494F4342
+#define IPR_DUMP_PEND_OPS		0x414F5053
+	u32 status;
+}__attribute__((packed, aligned (4)));
+
+struct ipr_dump_location_entry {
+	struct ipr_dump_entry_header hdr;
+	u8 location[BUS_ID_SIZE];
+}__attribute__((packed));
+
+struct ipr_dump_trace_entry {
+	struct ipr_dump_entry_header hdr;
+	u32 trace[IPR_TRACE_SIZE / sizeof(u32)];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_dump_version_entry {
+	struct ipr_dump_entry_header hdr;
+	u8 version[sizeof(IPR_DRIVER_VERSION)];
+};
+
+struct ipr_dump_ioa_type_entry {
+	struct ipr_dump_entry_header hdr;
+	u32 type;
+	u32 fw_version;
+};
+
+struct ipr_driver_dump {
+	struct ipr_dump_header hdr;
+	struct ipr_dump_version_entry version_entry;
+	struct ipr_dump_location_entry location_entry;
+	struct ipr_dump_ioa_type_entry ioa_type_entry;
+	struct ipr_dump_trace_entry trace_entry;
+}__attribute__((packed));
+
+struct ipr_ioa_dump {
+	struct ipr_dump_entry_header hdr;
+	struct ipr_sdt sdt;
+	__be32 *ioa_data[IPR_MAX_NUM_DUMP_PAGES];
+	u32 reserved;
+	u32 next_page_index;
+	u32 page_offset;
+	u32 format;
+#define IPR_SDT_FMT2		2
+#define IPR_SDT_UNKNOWN		3
+}__attribute__((packed, aligned (4)));
+
+struct ipr_dump {
+	struct kref kref;
+	struct ipr_ioa_cfg *ioa_cfg;
+	struct ipr_driver_dump driver_dump;
+	struct ipr_ioa_dump ioa_dump;
+};
+
+struct ipr_error_table_t {
+	u32 ioasc;
+	int log_ioasa;
+	int log_hcam;
+	char *error;
+};
+
+struct ipr_software_inq_lid_info {
+	__be32 load_id;
+	__be32 timestamp[3];
+}__attribute__((packed, aligned (4)));
+
+struct ipr_ucode_image_header {
+	__be32 header_length;
+	__be32 lid_table_offset;
+	u8 major_release;
+	u8 card_type;
+	u8 minor_release[2];
+	u8 reserved[20];
+	char eyecatcher[16];
+	__be32 num_lids;
+	struct ipr_software_inq_lid_info lid[1];
+}__attribute__((packed, aligned (4)));
+
+/*
+ * Macros
+ */
+#if IPR_DEBUG
+#define IPR_DBG_CMD(CMD) do { CMD; } while (0)
+#else
+#define IPR_DBG_CMD(CMD)
+#endif
+
+#ifdef CONFIG_SCSI_IPR_TRACE
+#define ipr_create_trace_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
+#define ipr_remove_trace_file(kobj, attr) sysfs_remove_bin_file(kobj, attr)
+#else
+#define ipr_create_trace_file(kobj, attr) 0
+#define ipr_remove_trace_file(kobj, attr) do { } while(0)
+#endif
+
+#ifdef CONFIG_SCSI_IPR_DUMP
+#define ipr_create_dump_file(kobj, attr) sysfs_create_bin_file(kobj, attr)
+#define ipr_remove_dump_file(kobj, attr) sysfs_remove_bin_file(kobj, attr)
+#else
+#define ipr_create_dump_file(kobj, attr) 0
+#define ipr_remove_dump_file(kobj, attr) do { } while(0)
+#endif
+
+/*
+ * Error logging macros
+ */
+#define ipr_err(...) printk(KERN_ERR IPR_NAME ": "__VA_ARGS__)
+#define ipr_info(...) printk(KERN_INFO IPR_NAME ": "__VA_ARGS__)
+#define ipr_crit(...) printk(KERN_CRIT IPR_NAME ": "__VA_ARGS__)
+#define ipr_warn(...) printk(KERN_WARNING IPR_NAME": "__VA_ARGS__)
+#define ipr_dbg(...) IPR_DBG_CMD(printk(KERN_INFO IPR_NAME ": "__VA_ARGS__))
+
+#define ipr_sdev_printk(level, sdev, fmt, ...) \
+	printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, sdev->host->host_no, \
+		sdev->channel, sdev->id, sdev->lun, ##__VA_ARGS__)
+
+#define ipr_sdev_err(sdev, fmt, ...) \
+	ipr_sdev_printk(KERN_ERR, sdev, fmt, ##__VA_ARGS__)
+
+#define ipr_sdev_info(sdev, fmt, ...) \
+	ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__)
+
+#define ipr_sdev_dbg(sdev, fmt, ...) \
+	IPR_DBG_CMD(ipr_sdev_printk(KERN_INFO, sdev, fmt, ##__VA_ARGS__))
+
+#define ipr_res_printk(level, ioa_cfg, res, fmt, ...) \
+	printk(level IPR_NAME ": %d:%d:%d:%d: " fmt, ioa_cfg->host->host_no, \
+		res.bus, res.target, res.lun, ##__VA_ARGS__)
+
+#define ipr_res_err(ioa_cfg, res, fmt, ...) \
+	ipr_res_printk(KERN_ERR, ioa_cfg, res, fmt, ##__VA_ARGS__)
+#define ipr_res_dbg(ioa_cfg, res, fmt, ...) \
+	IPR_DBG_CMD(ipr_res_printk(KERN_INFO, ioa_cfg, res, fmt, ##__VA_ARGS__))
+
+#define ipr_trace ipr_dbg("%s: %s: Line: %d\n",\
+	__FILE__, __FUNCTION__, __LINE__)
+
+#if IPR_DBG_TRACE
+#define ENTER printk(KERN_INFO IPR_NAME": Entering %s\n", __FUNCTION__)
+#define LEAVE printk(KERN_INFO IPR_NAME": Leaving %s\n", __FUNCTION__)
+#else
+#define ENTER
+#define LEAVE
+#endif
+
+#define ipr_err_separator \
+ipr_err("----------------------------------------------------------\n")
+
+
+/*
+ * Inlines
+ */
+
+/**
+ * ipr_is_ioa_resource - Determine if a resource is the IOA
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if IOA / 0 if not IOA
+ **/
+static inline int ipr_is_ioa_resource(struct ipr_resource_entry *res)
+{
+	return (res->cfgte.flags & IPR_IS_IOA_RESOURCE) ? 1 : 0;
+}
+
+/**
+ * ipr_is_af_dasd_device - Determine if a resource is an AF DASD
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if AF DASD / 0 if not AF DASD
+ **/
+static inline int ipr_is_af_dasd_device(struct ipr_resource_entry *res)
+{
+	if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) &&
+	    !ipr_is_ioa_resource(res) &&
+	    IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_AF_DASD)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * ipr_is_vset_device - Determine if a resource is a VSET
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if VSET / 0 if not VSET
+ **/
+static inline int ipr_is_vset_device(struct ipr_resource_entry *res)
+{
+	if (IPR_IS_DASD_DEVICE(res->cfgte.std_inq_data) &&
+	    !ipr_is_ioa_resource(res) &&
+	    IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_VOLUME_SET)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * ipr_is_gscsi - Determine if a resource is a generic scsi resource
+ * @res:	resource entry struct
+ *
+ * Return value:
+ * 	1 if GSCSI / 0 if not GSCSI
+ **/
+static inline int ipr_is_gscsi(struct ipr_resource_entry *res)
+{
+	if (!ipr_is_ioa_resource(res) &&
+	    IPR_RES_SUBTYPE(res) == IPR_SUBTYPE_GENERIC_SCSI)
+		return 1;
+	else
+		return 0;
+}
+
+/**
+ * ipr_is_device - Determine if resource address is that of a device
+ * @res_addr:	resource address struct
+ *
+ * Return value:
+ * 	1 if AF / 0 if not AF
+ **/
+static inline int ipr_is_device(struct ipr_res_addr *res_addr)
+{
+	if ((res_addr->bus < IPR_MAX_NUM_BUSES) &&
+	    (res_addr->target < IPR_MAX_NUM_TARGETS_PER_BUS))
+		return 1;
+
+	return 0;
+}
+
+/**
+ * ipr_sdt_is_fmt2 - Determine if a SDT address is in format 2
+ * @sdt_word:	SDT address
+ *
+ * Return value:
+ * 	1 if format 2 / 0 if not
+ **/
+static inline int ipr_sdt_is_fmt2(u32 sdt_word)
+{
+	u32 bar_sel = IPR_GET_FMT2_BAR_SEL(sdt_word);
+
+	switch (bar_sel) {
+	case IPR_SDT_FMT2_BAR0_SEL:
+	case IPR_SDT_FMT2_BAR1_SEL:
+	case IPR_SDT_FMT2_BAR2_SEL:
+	case IPR_SDT_FMT2_BAR3_SEL:
+	case IPR_SDT_FMT2_BAR4_SEL:
+	case IPR_SDT_FMT2_BAR5_SEL:
+	case IPR_SDT_FMT2_EXP_ROM_SEL:
+		return 1;
+	};
+
+	return 0;
+}
+
+#endif
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
new file mode 100644
index 0000000..e46096d
--- /dev/null
+++ b/drivers/scsi/ips.c
@@ -0,0 +1,7491 @@
+/*****************************************************************************/
+/* ips.c -- driver for the Adaptec / IBM ServeRAID controller                */
+/*                                                                           */
+/* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
+/*                                                                           */
+/* Copyright (C) 2000 IBM Corporation                                        */
+/* Copyright (C) 2002,2003 Adaptec, Inc.                                     */
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* NO WARRANTY                                                               */
+/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        */
+/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      */
+/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      */
+/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    */
+/* solely responsible for determining the appropriateness of using and       */
+/* distributing the Program and assumes all risks associated with its        */
+/* exercise of rights under this Agreement, including but not limited to     */
+/* the risks and costs of program errors, damage to or loss of data,         */
+/* programs or equipment, and unavailability or interruption of operations.  */
+/*                                                                           */
+/* DISCLAIMER OF LIABILITY                                                   */
+/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   */
+/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
+/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     */
+/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    */
+/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  */
+/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/* Bugs/Comments/Suggestions about this driver should be mailed to:          */
+/*      ipslinux@adaptec.com        	                                     */
+/*                                                                           */
+/* For system support issues, contact your local IBM Customer support.       */
+/* Directions to find IBM Customer Support for each country can be found at: */
+/*      http://www.ibm.com/planetwide/                                       */
+/*                                                                           */
+/*****************************************************************************/
+
+/*****************************************************************************/
+/* Change Log                                                                */
+/*                                                                           */
+/* 0.99.02  - Breakup commands that are bigger than 8 * the stripe size      */
+/* 0.99.03  - Make interrupt routine handle all completed request on the     */
+/*            adapter not just the first one                                 */
+/*          - Make sure passthru commands get woken up if we run out of      */
+/*            SCBs                                                           */
+/*          - Send all of the commands on the queue at once rather than      */
+/*            one at a time since the card will support it.                  */
+/* 0.99.04  - Fix race condition in the passthru mechanism -- this required  */
+/*            the interface to the utilities to change                       */
+/*          - Fix error recovery code                                        */
+/* 0.99.05  - Fix an oops when we get certain passthru commands              */
+/* 1.00.00  - Initial Public Release                                         */
+/*            Functionally equivalent to 0.99.05                             */
+/* 3.60.00  - Bump max commands to 128 for use with firmware 3.60            */
+/*          - Change version to 3.60 to coincide with release numbering.     */
+/* 3.60.01  - Remove bogus error check in passthru routine                   */
+/* 3.60.02  - Make DCDB direction based on lookup table                      */
+/*          - Only allow one DCDB command to a SCSI ID at a time             */
+/* 4.00.00  - Add support for ServeRAID 4                                    */
+/* 4.00.01  - Add support for First Failure Data Capture                     */
+/* 4.00.02  - Fix problem with PT DCDB with no buffer                        */
+/* 4.00.03  - Add alternative passthru interface                             */
+/*          - Add ability to flash BIOS                                      */
+/* 4.00.04  - Rename structures/constants to be prefixed with IPS_           */
+/* 4.00.05  - Remove wish_block from init routine                            */
+/*          - Use linux/spinlock.h instead of asm/spinlock.h for kernels     */
+/*            2.3.18 and later                                               */
+/*          - Sync with other changes from the 2.3 kernels                   */
+/* 4.00.06  - Fix timeout with initial FFDC command                          */
+/* 4.00.06a - Port to 2.4 (trivial) -- Christoph Hellwig <hch@infradead.org> */
+/* 4.10.00  - Add support for ServeRAID 4M/4L                                */
+/* 4.10.13  - Fix for dynamic unload and proc file system                    */
+/* 4.20.03  - Rename version to coincide with new release schedules          */
+/*            Performance fixes                                              */
+/*            Fix truncation of /proc files with cat                         */
+/*            Merge in changes through kernel 2.4.0test1ac21                 */
+/* 4.20.13  - Fix some failure cases / reset code                            */
+/*          - Hook into the reboot_notifier to flush the controller cache    */
+/* 4.50.01  - Fix problem when there is a hole in logical drive numbering    */
+/* 4.70.09  - Use a Common ( Large Buffer ) for Flashing from the JCRM CD    */
+/*          - Add IPSSEND Flash Support                                      */
+/*          - Set Sense Data for Unknown SCSI Command                        */
+/*          - Use Slot Number from NVRAM Page 5                              */
+/*          - Restore caller's DCDB Structure                                */
+/* 4.70.12  - Corrective actions for bad controller ( during initialization )*/
+/* 4.70.13  - Don't Send CDB's if we already know the device is not present  */
+/*          - Don't release HA Lock in ips_next() until SC taken off queue   */
+/*          - Unregister SCSI device in ips_release()                        */
+/* 4.70.15  - Fix Breakup for very large ( non-SG ) requests in ips_done()   */
+/* 4.71.00  - Change all memory allocations to not use GFP_DMA flag          */
+/*            Code Clean-Up for 2.4.x kernel                                 */
+/* 4.72.00  - Allow for a Scatter-Gather Element to exceed MAX_XFER Size     */
+/* 4.72.01  - I/O Mapped Memory release ( so "insmod ips" does not Fail )    */
+/*          - Don't Issue Internal FFDC Command if there are Active Commands */
+/*          - Close Window for getting too many IOCTL's active               */
+/* 4.80.00  - Make ia64 Safe                                                 */
+/* 4.80.04  - Eliminate calls to strtok() if 2.4.x or greater                */
+/*          - Adjustments to Device Queue Depth                              */
+/* 4.80.14  - Take all semaphores off stack                                  */
+/*          - Clean Up New_IOCTL path                                        */
+/* 4.80.20  - Set max_sectors in Scsi_Host structure ( if >= 2.4.7 kernel )  */
+/*          - 5 second delay needed after resetting an i960 adapter          */
+/* 4.80.26  - Clean up potential code problems ( Arjan's recommendations )   */
+/* 4.90.01  - Version Matching for FirmWare, BIOS, and Driver                */
+/* 4.90.05  - Use New PCI Architecture to facilitate Hot Plug Development    */
+/* 4.90.08  - Increase Delays in Flashing ( Trombone Only - 4H )             */
+/* 4.90.08  - Data Corruption if First Scatter Gather Element is > 64K       */
+/* 4.90.11  - Don't actually RESET unless it's physically required           */
+/*          - Remove unused compile options                                  */
+/* 5.00.01  - Sarasota ( 5i ) adapters must always be scanned first          */
+/*          - Get rid on IOCTL_NEW_COMMAND code                              */
+/*          - Add Extended DCDB Commands for Tape Support in 5I              */
+/* 5.10.12  - use pci_dma interfaces, update for 2.5 kernel changes          */
+/* 5.10.15  - remove unused code (sem, macros, etc.)                         */
+/* 5.30.00  - use __devexit_p()                                              */
+/* 6.00.00  - Add 6x Adapters and Battery Flash                              */
+/* 6.10.00  - Remove 1G Addressing Limitations                               */
+/* 6.11.xx  - Get VersionInfo buffer off the stack !              DDTS 60401 */
+/* 6.11.xx  - Make Logical Drive Info structure safe for DMA      DDTS 60639 */
+/* 7.10.xx  - Add highmem_io flag in SCSI Templete for 2.4 kernels           */
+/*          - Fix path/name for scsi_hosts.h include for 2.6 kernels         */
+/*          - Fix sort order of 7k                                           */
+/*          - Remove 3 unused "inline" functions                             */
+/*****************************************************************************/
+
+/*
+ * Conditional Compilation directives for this driver:
+ *
+ * IPS_DEBUG            - Turn on debugging info
+ *
+ * Parameters:
+ *
+ * debug:<number>       - Set debug level to <number>
+ *                        NOTE: only works when IPS_DEBUG compile directive is used.
+ *       1              - Normal debug messages
+ *       2              - Verbose debug messages
+ *       11             - Method trace (non interrupt)
+ *       12             - Method trace (includes interrupt)
+ *
+ * noi2o                - Don't use I2O Queues (ServeRAID 4 only)
+ * nommap               - Don't use memory mapped I/O
+ * ioctlsize            - Initial size of the IOCTL buffer
+ */
+
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/page.h>
+#include <linux/stddef.h>
+#include <linux/version.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/reboot.h>
+#include <linux/interrupt.h>
+
+#include <linux/blkdev.h>
+#include <linux/types.h>
+
+#include <scsi/sg.h>
+
+#include "scsi.h"
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#include "hosts.h"
+#else
+#include <scsi/scsi_host.h>
+#endif
+
+#include "ips.h"
+
+#include <linux/module.h>
+
+#include <linux/stat.h>
+#include <linux/config.h>
+
+#include <linux/spinlock.h>
+#include <linux/init.h>
+
+#include <linux/smp.h>
+
+#ifdef MODULE
+static char *ips = NULL;
+module_param(ips, charp, 0);
+#endif
+
+/*
+ * DRIVER_VER
+ */
+#define IPS_VERSION_HIGH        "7.10"
+#define IPS_VERSION_LOW         ".18 "
+
+#if !defined(__i386__) && !defined(__ia64__) && !defined(__x86_64__)
+#warning "This driver has only been tested on the x86/ia64/x86_64 platforms"
+#endif
+
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,5,0)
+#include <linux/blk.h>
+#include "sd.h"
+#define IPS_SG_ADDRESS(sg)       ((sg)->address)
+#define IPS_LOCK_SAVE(lock,flags) spin_lock_irqsave(&io_request_lock,flags)
+#define IPS_UNLOCK_RESTORE(lock,flags) spin_unlock_irqrestore(&io_request_lock,flags)
+#ifndef __devexit_p
+#define __devexit_p(x) x
+#endif
+#else
+#define IPS_SG_ADDRESS(sg)      (page_address((sg)->page) ? \
+                                   page_address((sg)->page)+(sg)->offset : NULL)
+#define IPS_LOCK_SAVE(lock,flags) do{spin_lock(lock);(void)flags;}while(0)
+#define IPS_UNLOCK_RESTORE(lock,flags) do{spin_unlock(lock);(void)flags;}while(0)
+#endif
+
+#define IPS_DMA_DIR(scb) ((!scb->scsi_cmd || ips_is_passthru(scb->scsi_cmd) || \
+                         SCSI_DATA_NONE == scb->scsi_cmd->sc_data_direction) ? \
+                         PCI_DMA_BIDIRECTIONAL : \
+                         scsi_to_pci_dma_dir(scb->scsi_cmd->sc_data_direction))
+
+#ifdef IPS_DEBUG
+#define METHOD_TRACE(s, i)    if (ips_debug >= (i+10)) printk(KERN_NOTICE s "\n");
+#define DEBUG(i, s)           if (ips_debug >= i) printk(KERN_NOTICE s "\n");
+#define DEBUG_VAR(i, s, v...) if (ips_debug >= i) printk(KERN_NOTICE s "\n", v);
+#else
+#define METHOD_TRACE(s, i)
+#define DEBUG(i, s)
+#define DEBUG_VAR(i, s, v...)
+#endif
+
+/*
+ * Function prototypes
+ */
+static int ips_detect(Scsi_Host_Template *);
+static int ips_release(struct Scsi_Host *);
+static int ips_eh_abort(Scsi_Cmnd *);
+static int ips_eh_reset(Scsi_Cmnd *);
+static int ips_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static const char *ips_info(struct Scsi_Host *);
+static irqreturn_t do_ipsintr(int, void *, struct pt_regs *);
+static int ips_hainit(ips_ha_t *);
+static int ips_map_status(ips_ha_t *, ips_scb_t *, ips_stat_t *);
+static int ips_send_wait(ips_ha_t *, ips_scb_t *, int, int);
+static int ips_send_cmd(ips_ha_t *, ips_scb_t *);
+static int ips_online(ips_ha_t *, ips_scb_t *);
+static int ips_inquiry(ips_ha_t *, ips_scb_t *);
+static int ips_rdcap(ips_ha_t *, ips_scb_t *);
+static int ips_msense(ips_ha_t *, ips_scb_t *);
+static int ips_reqsen(ips_ha_t *, ips_scb_t *);
+static int ips_deallocatescbs(ips_ha_t *, int);
+static int ips_allocatescbs(ips_ha_t *);
+static int ips_reset_copperhead(ips_ha_t *);
+static int ips_reset_copperhead_memio(ips_ha_t *);
+static int ips_reset_morpheus(ips_ha_t *);
+static int ips_issue_copperhead(ips_ha_t *, ips_scb_t *);
+static int ips_issue_copperhead_memio(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o(ips_ha_t *, ips_scb_t *);
+static int ips_issue_i2o_memio(ips_ha_t *, ips_scb_t *);
+static int ips_isintr_copperhead(ips_ha_t *);
+static int ips_isintr_copperhead_memio(ips_ha_t *);
+static int ips_isintr_morpheus(ips_ha_t *);
+static int ips_wait(ips_ha_t *, int, int);
+static int ips_write_driver_status(ips_ha_t *, int);
+static int ips_read_adapter_status(ips_ha_t *, int);
+static int ips_read_subsystem_parameters(ips_ha_t *, int);
+static int ips_read_config(ips_ha_t *, int);
+static int ips_clear_adapter(ips_ha_t *, int);
+static int ips_readwrite_page5(ips_ha_t *, int, int);
+static int ips_init_copperhead(ips_ha_t *);
+static int ips_init_copperhead_memio(ips_ha_t *);
+static int ips_init_morpheus(ips_ha_t *);
+static int ips_isinit_copperhead(ips_ha_t *);
+static int ips_isinit_copperhead_memio(ips_ha_t *);
+static int ips_isinit_morpheus(ips_ha_t *);
+static int ips_erase_bios(ips_ha_t *);
+static int ips_program_bios(ips_ha_t *, char *, uint32_t, uint32_t);
+static int ips_verify_bios(ips_ha_t *, char *, uint32_t, uint32_t);
+static int ips_erase_bios_memio(ips_ha_t *);
+static int ips_program_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
+static int ips_verify_bios_memio(ips_ha_t *, char *, uint32_t, uint32_t);
+static int ips_flash_copperhead(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
+static int ips_flash_bios(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
+static int ips_flash_firmware(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
+static void ips_free_flash_copperhead(ips_ha_t * ha);
+static void ips_get_bios_version(ips_ha_t *, int);
+static void ips_identify_controller(ips_ha_t *);
+static void ips_chkstatus(ips_ha_t *, IPS_STATUS *);
+static void ips_enable_int_copperhead(ips_ha_t *);
+static void ips_enable_int_copperhead_memio(ips_ha_t *);
+static void ips_enable_int_morpheus(ips_ha_t *);
+static int ips_intr_copperhead(ips_ha_t *);
+static int ips_intr_morpheus(ips_ha_t *);
+static void ips_next(ips_ha_t *, int);
+static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
+static void ipsintr_done(ips_ha_t *, struct ips_scb *);
+static void ips_done(ips_ha_t *, ips_scb_t *);
+static void ips_free(ips_ha_t *);
+static void ips_init_scb(ips_ha_t *, ips_scb_t *);
+static void ips_freescb(ips_ha_t *, ips_scb_t *);
+static void ips_setup_funclist(ips_ha_t *);
+static void ips_statinit(ips_ha_t *);
+static void ips_statinit_memio(ips_ha_t *);
+static void ips_fix_ffdc_time(ips_ha_t *, ips_scb_t *, time_t);
+static void ips_ffdc_reset(ips_ha_t *, int);
+static void ips_ffdc_time(ips_ha_t *);
+static uint32_t ips_statupd_copperhead(ips_ha_t *);
+static uint32_t ips_statupd_copperhead_memio(ips_ha_t *);
+static uint32_t ips_statupd_morpheus(ips_ha_t *);
+static ips_scb_t *ips_getscb(ips_ha_t *);
+static void ips_putq_scb_head(ips_scb_queue_t *, ips_scb_t *);
+static void ips_putq_wait_tail(ips_wait_queue_t *, Scsi_Cmnd *);
+static void ips_putq_copp_tail(ips_copp_queue_t *,
+				      ips_copp_wait_item_t *);
+static ips_scb_t *ips_removeq_scb_head(ips_scb_queue_t *);
+static ips_scb_t *ips_removeq_scb(ips_scb_queue_t *, ips_scb_t *);
+static Scsi_Cmnd *ips_removeq_wait_head(ips_wait_queue_t *);
+static Scsi_Cmnd *ips_removeq_wait(ips_wait_queue_t *, Scsi_Cmnd *);
+static ips_copp_wait_item_t *ips_removeq_copp(ips_copp_queue_t *,
+						     ips_copp_wait_item_t *);
+static ips_copp_wait_item_t *ips_removeq_copp_head(ips_copp_queue_t *);
+
+static int ips_is_passthru(Scsi_Cmnd *);
+static int ips_make_passthru(ips_ha_t *, Scsi_Cmnd *, ips_scb_t *, int);
+static int ips_usrcmd(ips_ha_t *, ips_passthru_t *, ips_scb_t *);
+static void ips_cleanup_passthru(ips_ha_t *, ips_scb_t *);
+static void ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data,
+			       unsigned int count);
+static void ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned int count);
+
+static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+static int ips_host_info(ips_ha_t *, char *, off_t, int);
+static void copy_mem_info(IPS_INFOSTR *, char *, int);
+static int copy_info(IPS_INFOSTR *, char *, ...);
+static int ips_get_version_info(ips_ha_t * ha, dma_addr_t, int intr);
+static void ips_version_check(ips_ha_t * ha, int intr);
+static int ips_abort_init(ips_ha_t * ha, int index);
+static int ips_init_phase2(int index);
+
+static int ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr);
+static int ips_register_scsi(int index);
+
+/*
+ * global variables
+ */
+static const char ips_name[] = "ips";
+static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];	/* Array of host controller structures */
+static ips_ha_t *ips_ha[IPS_MAX_ADAPTERS];	/* Array of HA structures */
+static unsigned int ips_next_controller;
+static unsigned int ips_num_controllers;
+static unsigned int ips_released_controllers;
+static int ips_hotplug;
+static int ips_cmd_timeout = 60;
+static int ips_reset_timeout = 60 * 5;
+static int ips_force_memio = 1;		/* Always use Memory Mapped I/O    */
+static int ips_force_i2o = 1;	/* Always use I2O command delivery */
+static int ips_ioctlsize = IPS_IOCTL_SIZE;	/* Size of the ioctl buffer        */
+static int ips_cd_boot;			/* Booting from Manager CD         */
+static char *ips_FlashData = NULL;	/* CD Boot - Flash Data Buffer      */
+static dma_addr_t ips_flashbusaddr;
+static long ips_FlashDataInUse;		/* CD Boot - Flash Data In Use Flag */
+static uint32_t MaxLiteCmds = 32;	/* Max Active Cmds for a Lite Adapter */
+static Scsi_Host_Template ips_driver_template = {
+	.detect			= ips_detect,
+	.release		= ips_release,
+	.info			= ips_info,
+	.queuecommand		= ips_queue,
+	.eh_abort_handler	= ips_eh_abort,
+	.eh_host_reset_handler	= ips_eh_reset,
+	.proc_name		= "ips",
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.proc_info		= ips_proc_info,
+	.slave_configure	= ips_slave_configure,
+#else
+	.proc_info		= ips_proc24_info,
+	.select_queue_depths	= ips_select_queue_depth,
+#endif
+	.bios_param		= ips_biosparam,
+	.this_id		= -1,
+	.sg_tablesize		= IPS_MAX_SG,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	.use_new_eh_code	= 1,
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20)  &&  LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+    .highmem_io          = 1,   
+#endif
+};
+
+static IPS_DEFINE_COMPAT_TABLE( Compatable );	/* Version Compatability Table      */
+
+
+/* This table describes all ServeRAID Adapters */
+static struct  pci_device_id  ips_pci_table[] = {
+	{ 0x1014, 0x002E, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+	{ 0x1014, 0x01BD, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+	{ 0x9005, 0x0250, PCI_ANY_ID, PCI_ANY_ID, 0, 0 },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE( pci, ips_pci_table );
+
+static char ips_hot_plug_name[] = "ips";
+   
+static int __devinit  ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent);
+static void __devexit ips_remove_device(struct pci_dev *pci_dev);
+   
+static struct pci_driver ips_pci_driver = {
+	.name		= ips_hot_plug_name,
+	.id_table	= ips_pci_table,
+	.probe		= ips_insert_device,
+	.remove		= __devexit_p(ips_remove_device),
+};
+           
+
+/*
+ * Necessary forward function protoypes
+ */
+static int ips_halt(struct notifier_block *nb, ulong event, void *buf);
+
+#define MAX_ADAPTER_NAME 15
+
+static char ips_adapter_name[][30] = {
+	"ServeRAID",
+	"ServeRAID II",
+	"ServeRAID on motherboard",
+	"ServeRAID on motherboard",
+	"ServeRAID 3H",
+	"ServeRAID 3L",
+	"ServeRAID 4H",
+	"ServeRAID 4M",
+	"ServeRAID 4L",
+	"ServeRAID 4Mx",
+	"ServeRAID 4Lx",
+	"ServeRAID 5i",
+	"ServeRAID 5i",
+	"ServeRAID 6M",
+	"ServeRAID 6i",
+	"ServeRAID 7t",
+	"ServeRAID 7k",
+	"ServeRAID 7M"
+};
+
+static struct notifier_block ips_notifier = {
+	ips_halt, NULL, 0
+};
+
+/*
+ * Direction table
+ */
+static char ips_command_direction[] = {
+	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK,
+	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_OUT,
+	IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_OUT,
+	IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_IN,
+	IPS_DATA_UNK, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_NONE, IPS_DATA_IN, IPS_DATA_NONE, IPS_DATA_NONE,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_IN, IPS_DATA_NONE,
+	IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK,
+	IPS_DATA_NONE, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_IN, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_NONE, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_NONE,
+	IPS_DATA_OUT, IPS_DATA_UNK, IPS_DATA_NONE, IPS_DATA_UNK, IPS_DATA_OUT,
+	IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_OUT, IPS_DATA_NONE,
+	IPS_DATA_UNK, IPS_DATA_IN, IPS_DATA_OUT, IPS_DATA_IN, IPS_DATA_IN,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_OUT,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK,
+	IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK, IPS_DATA_UNK
+};
+
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_setup                                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   setup parameters to the driver                                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_setup(char *ips_str)
+{
+
+	int i;
+	char *key;
+	char *value;
+	IPS_OPTION options[] = {
+		{"noi2o", &ips_force_i2o, 0},
+		{"nommap", &ips_force_memio, 0},
+		{"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE},
+		{"cdboot", &ips_cd_boot, 0},
+		{"maxcmds", &MaxLiteCmds, 32},
+	};
+
+	/* Don't use strtok() anymore ( if 2.4 Kernel or beyond ) */
+	/* Search for value */
+	while ((key = strsep(&ips_str, ",."))) {
+		if (!*key)
+			continue;
+		value = strchr(key, ':');
+		if (value)
+			*value++ = '\0';
+		/*
+		 * We now have key/value pairs.
+		 * Update the variables
+		 */
+		for (i = 0; i < (sizeof (options) / sizeof (options[0])); i++) {
+			if (strnicmp
+			    (key, options[i].option_name,
+			     strlen(options[i].option_name)) == 0) {
+				if (value)
+					*options[i].option_flag =
+					    simple_strtoul(value, NULL, 0);
+				else
+					*options[i].option_flag =
+					    options[i].option_value;
+				break;
+			}
+		}
+	}
+
+	return (1);
+}
+
+__setup("ips=", ips_setup);
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_detect                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Detect and initialize the driver                                       */
+/*                                                                          */
+/* NOTE: this routine is called under the io_request_lock spinlock          */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_detect(Scsi_Host_Template * SHT)
+{
+	int i;
+
+	METHOD_TRACE("ips_detect", 1);
+
+#ifdef MODULE
+	if (ips)
+		ips_setup(ips);
+#endif
+
+	for (i = 0; i < ips_num_controllers; i++) {
+		if (ips_register_scsi(i))
+			ips_free(ips_ha[i]);
+		ips_released_controllers++;
+	}
+	ips_hotplug = 1;
+	return (ips_num_controllers);
+}
+
+/****************************************************************************/
+/*   configure the function pointers to use the functions that will work    */
+/*   with the found version of the adapter                                  */
+/****************************************************************************/
+static void
+ips_setup_funclist(ips_ha_t * ha)
+{
+
+	/*                                
+	 * Setup Functions
+	 */
+	if (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha)) {
+		/* morpheus / marco / sebring */
+		ha->func.isintr = ips_isintr_morpheus;
+		ha->func.isinit = ips_isinit_morpheus;
+		ha->func.issue = ips_issue_i2o_memio;
+		ha->func.init = ips_init_morpheus;
+		ha->func.statupd = ips_statupd_morpheus;
+		ha->func.reset = ips_reset_morpheus;
+		ha->func.intr = ips_intr_morpheus;
+		ha->func.enableint = ips_enable_int_morpheus;
+	} else if (IPS_USE_MEMIO(ha)) {
+		/* copperhead w/MEMIO */
+		ha->func.isintr = ips_isintr_copperhead_memio;
+		ha->func.isinit = ips_isinit_copperhead_memio;
+		ha->func.init = ips_init_copperhead_memio;
+		ha->func.statupd = ips_statupd_copperhead_memio;
+		ha->func.statinit = ips_statinit_memio;
+		ha->func.reset = ips_reset_copperhead_memio;
+		ha->func.intr = ips_intr_copperhead;
+		ha->func.erasebios = ips_erase_bios_memio;
+		ha->func.programbios = ips_program_bios_memio;
+		ha->func.verifybios = ips_verify_bios_memio;
+		ha->func.enableint = ips_enable_int_copperhead_memio;
+		if (IPS_USE_I2O_DELIVER(ha))
+			ha->func.issue = ips_issue_i2o_memio;
+		else
+			ha->func.issue = ips_issue_copperhead_memio;
+	} else {
+		/* copperhead */
+		ha->func.isintr = ips_isintr_copperhead;
+		ha->func.isinit = ips_isinit_copperhead;
+		ha->func.init = ips_init_copperhead;
+		ha->func.statupd = ips_statupd_copperhead;
+		ha->func.statinit = ips_statinit;
+		ha->func.reset = ips_reset_copperhead;
+		ha->func.intr = ips_intr_copperhead;
+		ha->func.erasebios = ips_erase_bios;
+		ha->func.programbios = ips_program_bios;
+		ha->func.verifybios = ips_verify_bios;
+		ha->func.enableint = ips_enable_int_copperhead;
+
+		if (IPS_USE_I2O_DELIVER(ha))
+			ha->func.issue = ips_issue_i2o;
+		else
+			ha->func.issue = ips_issue_copperhead;
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_release                                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove a driver                                                        */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_release(struct Scsi_Host *sh)
+{
+	ips_scb_t *scb;
+	ips_ha_t *ha;
+	int i;
+
+	METHOD_TRACE("ips_release", 1);
+
+	for (i = 0; i < IPS_MAX_ADAPTERS && ips_sh[i] != sh; i++) ;
+
+	if (i == IPS_MAX_ADAPTERS) {
+		printk(KERN_WARNING
+		       "(%s) release, invalid Scsi_Host pointer.\n", ips_name);
+		BUG();
+		return (FALSE);
+	}
+
+	ha = IPS_HA(sh);
+
+	if (!ha)
+		return (FALSE);
+
+	/* flush the cache on the controller */
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FLUSH;
+
+	scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+	scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.flush_cache.state = IPS_NORM_STATE;
+	scb->cmd.flush_cache.reserved = 0;
+	scb->cmd.flush_cache.reserved2 = 0;
+	scb->cmd.flush_cache.reserved3 = 0;
+	scb->cmd.flush_cache.reserved4 = 0;
+
+	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
+
+	/* send command */
+	if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
+		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
+
+	IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
+
+	ips_sh[i] = NULL;
+	ips_ha[i] = NULL;
+
+	/* free extra memory */
+	ips_free(ha);
+
+	/* Free I/O Region */
+	if (ha->io_addr)
+		release_region(ha->io_addr, ha->io_len);
+
+	/* free IRQ */
+	free_irq(ha->irq, ha);
+
+	IPS_REMOVE_HOST(sh);
+	scsi_host_put(sh);
+
+	ips_released_controllers++;
+
+	return (FALSE);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_halt                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Perform cleanup when the system reboots                                */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_halt(struct notifier_block *nb, ulong event, void *buf)
+{
+	ips_scb_t *scb;
+	ips_ha_t *ha;
+	int i;
+
+	if ((event != SYS_RESTART) && (event != SYS_HALT) &&
+	    (event != SYS_POWER_OFF))
+		return (NOTIFY_DONE);
+
+	for (i = 0; i < ips_next_controller; i++) {
+		ha = (ips_ha_t *) ips_ha[i];
+
+		if (!ha)
+			continue;
+
+		if (!ha->active)
+			continue;
+
+		/* flush the cache on the controller */
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_FLUSH;
+
+		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flush_cache.state = IPS_NORM_STATE;
+		scb->cmd.flush_cache.reserved = 0;
+		scb->cmd.flush_cache.reserved2 = 0;
+		scb->cmd.flush_cache.reserved3 = 0;
+		scb->cmd.flush_cache.reserved4 = 0;
+
+		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
+
+		/* send command */
+		if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) ==
+		    IPS_FAILURE)
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Incomplete Flush.\n");
+		else
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Flushing Complete.\n");
+	}
+
+	return (NOTIFY_OK);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_eh_abort                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Abort a command (using the new error code stuff)                       */
+/* Note: this routine is called under the io_request_lock                   */
+/****************************************************************************/
+int
+ips_eh_abort(Scsi_Cmnd * SC)
+{
+	ips_ha_t *ha;
+	ips_copp_wait_item_t *item;
+	int ret;
+
+	METHOD_TRACE("ips_eh_abort", 1);
+
+	if (!SC)
+		return (FAILED);
+
+	ha = (ips_ha_t *) SC->device->host->hostdata;
+
+	if (!ha)
+		return (FAILED);
+
+	if (!ha->active)
+		return (FAILED);
+
+	if (SC->serial_number != SC->serial_number_at_timeout) {
+		/* HMM, looks like a bogus command */
+		DEBUG(1, "Abort called with bogus scsi command");
+
+		return (FAILED);
+	}
+
+	/* See if the command is on the copp queue */
+	item = ha->copp_waitlist.head;
+	while ((item) && (item->scsi_cmd != SC))
+		item = item->next;
+
+	if (item) {
+		/* Found it */
+		ips_removeq_copp(&ha->copp_waitlist, item);
+		ret = (SUCCESS);
+
+		/* See if the command is on the wait queue */
+	} else if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+		/* command not sent yet */
+		ret = (SUCCESS);
+	} else {
+		/* command must have already been sent */
+		ret = (FAILED);
+	}
+	return ret;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_eh_reset                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller (with new eh error code)                          */
+/*                                                                          */
+/* NOTE: this routine is called under the io_request_lock spinlock          */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_eh_reset(Scsi_Cmnd * SC)
+{
+	int ret;
+	int i;
+	ips_ha_t *ha;
+	ips_scb_t *scb;
+	ips_copp_wait_item_t *item;
+
+	METHOD_TRACE("ips_eh_reset", 1);
+
+#ifdef NO_IPS_RESET
+	return (FAILED);
+#else
+
+	if (!SC) {
+		DEBUG(1, "Reset called with NULL scsi command");
+
+		return (FAILED);
+	}
+
+	ha = (ips_ha_t *) SC->device->host->hostdata;
+
+	if (!ha) {
+		DEBUG(1, "Reset called with NULL ha struct");
+
+		return (FAILED);
+	}
+
+	if (!ha->active)
+		return (FAILED);
+
+	/* See if the command is on the copp queue */
+	item = ha->copp_waitlist.head;
+	while ((item) && (item->scsi_cmd != SC))
+		item = item->next;
+
+	if (item) {
+		/* Found it */
+		ips_removeq_copp(&ha->copp_waitlist, item);
+		return (SUCCESS);
+	}
+
+	/* See if the command is on the wait queue */
+	if (ips_removeq_wait(&ha->scb_waitlist, SC)) {
+		/* command not sent yet */
+		return (SUCCESS);
+	}
+
+	/* An explanation for the casual observer:                              */
+	/* Part of the function of a RAID controller is automatic error         */
+	/* detection and recovery.  As such, the only problem that physically   */
+	/* resetting an adapter will ever fix is when, for some reason,         */
+	/* the driver is not successfully communicating with the adapter.       */
+	/* Therefore, we will attempt to flush this adapter.  If that succeeds, */
+	/* then there's no real purpose in a physical reset. This will complete */
+	/* much faster and avoids any problems that might be caused by a        */
+	/* physical reset ( such as having to fail all the outstanding I/O's ). */
+
+	if (ha->ioctl_reset == 0) {	/* IF Not an IOCTL Requested Reset */
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_FLUSH;
+
+		scb->cmd.flush_cache.op_code = IPS_CMD_FLUSH;
+		scb->cmd.flush_cache.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flush_cache.state = IPS_NORM_STATE;
+		scb->cmd.flush_cache.reserved = 0;
+		scb->cmd.flush_cache.reserved2 = 0;
+		scb->cmd.flush_cache.reserved3 = 0;
+		scb->cmd.flush_cache.reserved4 = 0;
+
+		/* Attempt the flush command */
+		ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
+		if (ret == IPS_SUCCESS) {
+			IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+				   "Reset Request - Flushed Cache\n");
+			return (SUCCESS);
+		}
+	}
+
+	/* Either we can't communicate with the adapter or it's an IOCTL request */
+	/* from a utility.  A physical reset is needed at this point.            */
+
+	ha->ioctl_reset = 0;	/* Reset the IOCTL Requested Reset Flag */
+
+	/*
+	 * command must have already been sent
+	 * reset the controller
+	 */
+	IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
+	ret = (*ha->func.reset) (ha);
+
+	if (!ret) {
+		Scsi_Cmnd *scsi_cmd;
+
+		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+			   "Controller reset failed - controller now offline.\n");
+
+		/* Now fail all of the active commands */
+		DEBUG_VAR(1, "(%s%d) Failing active commands",
+			  ips_name, ha->host_num);
+
+		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			ips_freescb(ha, scb);
+		}
+
+		/* Now fail all of the pending commands */
+		DEBUG_VAR(1, "(%s%d) Failing pending commands",
+			  ips_name, ha->host_num);
+
+		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+			scsi_cmd->result = DID_ERROR;
+			scsi_cmd->scsi_done(scsi_cmd);
+		}
+
+		ha->active = FALSE;
+		return (FAILED);
+	}
+
+	if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
+		Scsi_Cmnd *scsi_cmd;
+
+		IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+			   "Controller reset failed - controller now offline.\n");
+
+		/* Now fail all of the active commands */
+		DEBUG_VAR(1, "(%s%d) Failing active commands",
+			  ips_name, ha->host_num);
+
+		while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			ips_freescb(ha, scb);
+		}
+
+		/* Now fail all of the pending commands */
+		DEBUG_VAR(1, "(%s%d) Failing pending commands",
+			  ips_name, ha->host_num);
+
+		while ((scsi_cmd = ips_removeq_wait_head(&ha->scb_waitlist))) {
+			scsi_cmd->result = DID_ERROR << 16;
+			scsi_cmd->scsi_done(scsi_cmd);
+		}
+
+		ha->active = FALSE;
+		return (FAILED);
+	}
+
+	/* FFDC */
+	if (le32_to_cpu(ha->subsys->param[3]) & 0x300000) {
+		struct timeval tv;
+
+		do_gettimeofday(&tv);
+		ha->last_ffdc = tv.tv_sec;
+		ha->reset_count++;
+		ips_ffdc_reset(ha, IPS_INTR_IORL);
+	}
+
+	/* Now fail all of the active commands */
+	DEBUG_VAR(1, "(%s%d) Failing active commands", ips_name, ha->host_num);
+
+	while ((scb = ips_removeq_scb_head(&ha->scb_activelist))) {
+		scb->scsi_cmd->result =
+		    (DID_RESET << 16) | (SUGGEST_RETRY << 24);
+		scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+		ips_freescb(ha, scb);
+	}
+
+	/* Reset DCDB active command bits */
+	for (i = 1; i < ha->nbus; i++)
+		ha->dcdb_active[i - 1] = 0;
+
+	/* Reset the number of active IOCTLs */
+	ha->num_ioctl = 0;
+
+	ips_next(ha, IPS_INTR_IORL);
+
+	return (SUCCESS);
+#endif				/* NO_IPS_RESET */
+
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_queue                                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command to the controller                                       */
+/*                                                                          */
+/* NOTE:                                                                    */
+/*    Linux obtains io_request_lock before calling this function            */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_queue(Scsi_Cmnd * SC, void (*done) (Scsi_Cmnd *))
+{
+	ips_ha_t *ha;
+	ips_passthru_t *pt;
+
+	METHOD_TRACE("ips_queue", 1);
+
+	ha = (ips_ha_t *) SC->device->host->hostdata;
+
+	if (!ha)
+		return (1);
+
+	if (!ha->active)
+		return (DID_ERROR);
+
+	if (ips_is_passthru(SC)) {
+		if (ha->copp_waitlist.count == IPS_MAX_IOCTL_QUEUE) {
+			SC->result = DID_BUS_BUSY << 16;
+			done(SC);
+
+			return (0);
+		}
+	} else if (ha->scb_waitlist.count == IPS_MAX_QUEUE) {
+		SC->result = DID_BUS_BUSY << 16;
+		done(SC);
+
+		return (0);
+	}
+
+	SC->scsi_done = done;
+
+	DEBUG_VAR(2, "(%s%d): ips_queue: cmd 0x%X (%d %d %d)",
+		  ips_name,
+		  ha->host_num,
+		  SC->cmnd[0],
+		  SC->device->channel, SC->device->id, SC->device->lun);
+
+	/* Check for command to initiator IDs */
+	if ((SC->device->channel > 0)
+	    && (SC->device->id == ha->ha_id[SC->device->channel])) {
+		SC->result = DID_NO_CONNECT << 16;
+		done(SC);
+
+		return (0);
+	}
+
+	if (ips_is_passthru(SC)) {
+
+		ips_copp_wait_item_t *scratch;
+
+		/* A Reset IOCTL is only sent by the boot CD in extreme cases.           */
+		/* There can never be any system activity ( network or disk ), but check */
+		/* anyway just as a good practice.                                       */
+		pt = (ips_passthru_t *) SC->request_buffer;
+		if ((pt->CoppCP.cmd.reset.op_code == IPS_CMD_RESET_CHANNEL) &&
+		    (pt->CoppCP.cmd.reset.adapter_flag == 1)) {
+			if (ha->scb_activelist.count != 0) {
+				SC->result = DID_BUS_BUSY << 16;
+				done(SC);
+				return (0);
+			}
+			ha->ioctl_reset = 1;	/* This reset request is from an IOCTL */
+			ips_eh_reset(SC);
+			SC->result = DID_OK << 16;
+			SC->scsi_done(SC);
+			return (0);
+		}
+
+		/* allocate space for the scribble */
+		scratch = kmalloc(sizeof (ips_copp_wait_item_t), GFP_ATOMIC);
+
+		if (!scratch) {
+			SC->result = DID_ERROR << 16;
+			done(SC);
+
+			return (0);
+		}
+
+		scratch->scsi_cmd = SC;
+		scratch->next = NULL;
+
+		ips_putq_copp_tail(&ha->copp_waitlist, scratch);
+	} else {
+		ips_putq_wait_tail(&ha->scb_waitlist, SC);
+	}
+
+	ips_next(ha, IPS_INTR_IORL);
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_biosparam                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Set bios geometry for the controller                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+ips_biosparam(Disk * disk, kdev_t dev, int geom[])
+{
+	ips_ha_t *ha = (ips_ha_t *) disk->device->host->hostdata;
+	unsigned long capacity = disk->capacity;
+#else
+ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+	      sector_t capacity, int geom[])
+{
+	ips_ha_t *ha = (ips_ha_t *) sdev->host->hostdata;
+#endif
+	int heads;
+	int sectors;
+	int cylinders;
+
+	METHOD_TRACE("ips_biosparam", 1);
+
+	if (!ha)
+		/* ?!?! host adater info invalid */
+		return (0);
+
+	if (!ha->active)
+		return (0);
+
+	if (!ips_read_adapter_status(ha, IPS_INTR_ON))
+		/* ?!?! Enquiry command failed */
+		return (0);
+
+	if ((capacity > 0x400000) && ((ha->enq->ucMiscFlag & 0x8) == 0)) {
+		heads = IPS_NORM_HEADS;
+		sectors = IPS_NORM_SECTORS;
+	} else {
+		heads = IPS_COMP_HEADS;
+		sectors = IPS_COMP_SECTORS;
+	}
+
+	cylinders = (unsigned long) capacity / (heads * sectors);
+
+	DEBUG_VAR(2, "Geometry: heads: %d, sectors: %d, cylinders: %d",
+		  heads, sectors, cylinders);
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return (0);
+}
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+
+/* ips_proc24_info is a wrapper around ips_proc_info *
+ * for compatibility with the 2.4 scsi parameters    */
+static int
+ips_proc24_info(char *buffer, char **start, off_t offset, int length,
+		              int hostno, int func)
+{
+	int i;
+
+	for (i = 0; i < ips_next_controller; i++) {
+		if (ips_sh[i] && ips_sh[i]->host_no == hostno) {
+			return ips_proc_info(ips_sh[i], buffer, start,
+					     offset, length, func);
+		}
+	}
+	return -EINVAL;	
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_select_queue_depth                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Select queue depths for the devices on the contoller                   */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_select_queue_depth(struct Scsi_Host *host, Scsi_Device * scsi_devs)
+{
+	Scsi_Device *device;
+	ips_ha_t *ha;
+	int count = 0;
+	int min;
+
+	ha = IPS_HA(host);
+	min = ha->max_cmds / 4;
+
+	for (device = scsi_devs; device; device = device->next) {
+		if (device->host == host) {
+			if ((device->channel == 0) && (device->type == 0))
+				count++;
+		}
+	}
+
+	for (device = scsi_devs; device; device = device->next) {
+		if (device->host == host) {
+			if ((device->channel == 0) && (device->type == 0)) {
+				device->queue_depth =
+				    (ha->max_cmds - 1) / count;
+				if (device->queue_depth < min)
+					device->queue_depth = min;
+			} else {
+				device->queue_depth = 2;
+			}
+
+			if (device->queue_depth < 2)
+				device->queue_depth = 2;
+		}
+	}
+}
+
+#else
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_slave_configure                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Set queue depths on devices once scan is complete                      */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_slave_configure(Scsi_Device * SDptr)
+{
+	ips_ha_t *ha;
+	int min;
+
+	ha = IPS_HA(SDptr->host);
+	if (SDptr->tagged_supported && SDptr->type == TYPE_DISK) {
+		min = ha->max_cmds / 2;
+		if (ha->enq->ucLogDriveCount <= 2)
+			min = ha->max_cmds - 1;
+		scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+	}
+	return 0;
+}
+#endif
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: do_ipsintr                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Wrapper for the interrupt handler                                      */
+/*                                                                          */
+/****************************************************************************/
+static irqreturn_t
+do_ipsintr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	ips_ha_t *ha;
+	unsigned long cpu_flags;
+	struct Scsi_Host *host;
+	int irqstatus;
+
+	METHOD_TRACE("do_ipsintr", 2);
+
+	ha = (ips_ha_t *) dev_id;
+	if (!ha)
+		return IRQ_NONE;
+	host = ips_sh[ha->host_num];
+	/* interrupt during initialization */
+	if (!host) {
+		(*ha->func.intr) (ha);
+		return IRQ_HANDLED;
+	}
+
+	IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+	if (!ha->active) {
+		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+		return IRQ_HANDLED;
+	}
+
+	irqstatus = (*ha->func.intr) (ha);
+
+	IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+
+	/* start the next command */
+	ips_next(ha, IPS_INTR_ON);
+	return IRQ_RETVAL(irqstatus);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_intr_copperhead                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Polling interrupt handler                                              */
+/*                                                                          */
+/*   ASSUMES interrupts are disabled                                        */
+/*                                                                          */
+/****************************************************************************/
+int
+ips_intr_copperhead(ips_ha_t * ha)
+{
+	ips_stat_t *sp;
+	ips_scb_t *scb;
+	IPS_STATUS cstatus;
+	int intrstatus;
+
+	METHOD_TRACE("ips_intr", 2);
+
+	if (!ha)
+		return 0;
+
+	if (!ha->active)
+		return 0;
+
+	intrstatus = (*ha->func.isintr) (ha);
+
+	if (!intrstatus) {
+		/*
+		 * Unexpected/Shared interrupt
+		 */
+
+		return 0;
+	}
+
+	while (TRUE) {
+		sp = &ha->sp;
+
+		intrstatus = (*ha->func.isintr) (ha);
+
+		if (!intrstatus)
+			break;
+		else
+			cstatus.value = (*ha->func.statupd) (ha);
+
+		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
+			/* Spurious Interupt ? */
+			continue;
+		}
+
+		ips_chkstatus(ha, &cstatus);
+		scb = (ips_scb_t *) sp->scb_addr;
+
+		/*
+		 * use the callback function to finish things up
+		 * NOTE: interrupts are OFF for this
+		 */
+		(*scb->callback) (ha, scb);
+	}			/* end while */
+	return 1;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_intr_morpheus                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Polling interrupt handler                                              */
+/*                                                                          */
+/*   ASSUMES interrupts are disabled                                        */
+/*                                                                          */
+/****************************************************************************/
+int
+ips_intr_morpheus(ips_ha_t * ha)
+{
+	ips_stat_t *sp;
+	ips_scb_t *scb;
+	IPS_STATUS cstatus;
+	int intrstatus;
+
+	METHOD_TRACE("ips_intr_morpheus", 2);
+
+	if (!ha)
+		return 0;
+
+	if (!ha->active)
+		return 0;
+
+	intrstatus = (*ha->func.isintr) (ha);
+
+	if (!intrstatus) {
+		/*
+		 * Unexpected/Shared interrupt
+		 */
+
+		return 0;
+	}
+
+	while (TRUE) {
+		sp = &ha->sp;
+
+		intrstatus = (*ha->func.isintr) (ha);
+
+		if (!intrstatus)
+			break;
+		else
+			cstatus.value = (*ha->func.statupd) (ha);
+
+		if (cstatus.value == 0xffffffff)
+			/* No more to process */
+			break;
+
+		if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Spurious interrupt; no ccb.\n");
+
+			continue;
+		}
+
+		ips_chkstatus(ha, &cstatus);
+		scb = (ips_scb_t *) sp->scb_addr;
+
+		/*
+		 * use the callback function to finish things up
+		 * NOTE: interrupts are OFF for this
+		 */
+		(*scb->callback) (ha, scb);
+	}			/* end while */
+	return 1;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_info                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Return info about the driver                                           */
+/*                                                                          */
+/****************************************************************************/
+static const char *
+ips_info(struct Scsi_Host *SH)
+{
+	static char buffer[256];
+	char *bp;
+	ips_ha_t *ha;
+
+	METHOD_TRACE("ips_info", 1);
+
+	ha = IPS_HA(SH);
+
+	if (!ha)
+		return (NULL);
+
+	bp = &buffer[0];
+	memset(bp, 0, sizeof (buffer));
+
+	sprintf(bp, "%s%s%s Build %d", "IBM PCI ServeRAID ",
+		IPS_VERSION_HIGH, IPS_VERSION_LOW, IPS_BUILD_IDENT);
+
+	if (ha->ad_type > 0 && ha->ad_type <= MAX_ADAPTER_NAME) {
+		strcat(bp, " <");
+		strcat(bp, ips_adapter_name[ha->ad_type - 1]);
+		strcat(bp, ">");
+	}
+
+	return (bp);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_proc_info                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   The passthru interface for the driver                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+	      int length, int func)
+{
+	int i;
+	int ret;
+	ips_ha_t *ha = NULL;
+
+	METHOD_TRACE("ips_proc_info", 1);
+
+	/* Find our host structure */
+	for (i = 0; i < ips_next_controller; i++) {
+		if (ips_sh[i]) {
+			if (ips_sh[i] == host) {
+				ha = (ips_ha_t *) ips_sh[i]->hostdata;
+				break;
+			}
+		}
+	}
+
+	if (!ha)
+		return (-EINVAL);
+
+	if (func) {
+		/* write */
+		return (0);
+	} else {
+		/* read */
+		if (start)
+			*start = buffer;
+
+		ret = ips_host_info(ha, buffer, offset, length);
+
+		return (ret);
+	}
+}
+
+/*--------------------------------------------------------------------------*/
+/* Helper Functions                                                         */
+/*--------------------------------------------------------------------------*/
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_is_passthru                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Determine if the specified SCSI command is really a passthru command   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_is_passthru(Scsi_Cmnd * SC)
+{
+	METHOD_TRACE("ips_is_passthru", 1);
+
+	if (!SC)
+		return (0);
+
+	if ((SC->cmnd[0] == IPS_IOCTL_COMMAND) &&
+	    (SC->device->channel == 0) &&
+	    (SC->device->id == IPS_ADAPTER_ID) &&
+	    (SC->device->lun == 0) && SC->request_buffer) {
+		if ((!SC->use_sg) && SC->request_bufflen &&
+		    (((char *) SC->request_buffer)[0] == 'C') &&
+		    (((char *) SC->request_buffer)[1] == 'O') &&
+		    (((char *) SC->request_buffer)[2] == 'P') &&
+		    (((char *) SC->request_buffer)[3] == 'P'))
+			return 1;
+		else if (SC->use_sg) {
+			struct scatterlist *sg = SC->request_buffer;
+			char *buffer = IPS_SG_ADDRESS(sg);
+			if (buffer && buffer[0] == 'C' && buffer[1] == 'O' &&
+			    buffer[2] == 'P' && buffer[3] == 'P')
+				return 1;
+		}
+	}
+	return 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_alloc_passthru_buffer                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   allocate a buffer large enough for the ioctl data if the ioctl buffer  */
+/*   is too small or doesn't exist                                          */
+/****************************************************************************/
+static int
+ips_alloc_passthru_buffer(ips_ha_t * ha, int length)
+{
+	void *bigger_buf;
+	dma_addr_t dma_busaddr;
+
+	if (ha->ioctl_data && length <= ha->ioctl_len)
+		return 0;
+	/* there is no buffer or it's not big enough, allocate a new one */
+	bigger_buf = pci_alloc_consistent(ha->pcidev, length, &dma_busaddr);
+	if (bigger_buf) {
+		/* free the old memory */
+		pci_free_consistent(ha->pcidev, ha->ioctl_len, ha->ioctl_data,
+				    ha->ioctl_busaddr);
+		/* use the new memory */
+		ha->ioctl_data = (char *) bigger_buf;
+		ha->ioctl_len = length;
+		ha->ioctl_busaddr = dma_busaddr;
+	} else {
+		return -1;
+	}
+	return 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_make_passthru                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Make a passthru command out of the info in the Scsi block              */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_make_passthru(ips_ha_t * ha, Scsi_Cmnd * SC, ips_scb_t * scb, int intr)
+{
+	ips_passthru_t *pt;
+	int length = 0;
+	int ret;
+
+	METHOD_TRACE("ips_make_passthru", 1);
+
+	if (!SC->use_sg) {
+		length = SC->request_bufflen;
+	} else {
+		struct scatterlist *sg = SC->request_buffer;
+		int i;
+		for (i = 0; i < SC->use_sg; i++)
+			length += sg[i].length;
+	}
+	if (length < sizeof (ips_passthru_t)) {
+		/* wrong size */
+		DEBUG_VAR(1, "(%s%d) Passthru structure wrong size",
+			  ips_name, ha->host_num);
+		return (IPS_FAILURE);
+	}
+	if (ips_alloc_passthru_buffer(ha, length)) {
+		/* allocation failure!  If ha->ioctl_data exists, use it to return
+		   some error codes.  Return a failed command to the scsi layer. */
+		if (ha->ioctl_data) {
+			pt = (ips_passthru_t *) ha->ioctl_data;
+			ips_scmd_buf_read(SC, pt, sizeof (ips_passthru_t));
+			pt->BasicStatus = 0x0B;
+			pt->ExtendedStatus = 0x00;
+			ips_scmd_buf_write(SC, pt, sizeof (ips_passthru_t));
+		}
+		return IPS_FAILURE;
+	}
+	ha->ioctl_datasize = length;
+
+	ips_scmd_buf_read(SC, ha->ioctl_data, ha->ioctl_datasize);
+	pt = (ips_passthru_t *) ha->ioctl_data;
+
+	/*
+	 * Some notes about the passthru interface used
+	 *
+	 * IF the scsi op_code == 0x0d then we assume
+	 * that the data came along with/goes with the
+	 * packet we received from the sg driver. In this
+	 * case the CmdBSize field of the pt structure is
+	 * used for the size of the buffer.
+	 */
+
+	switch (pt->CoppCmd) {
+	case IPS_NUMCTRLS:
+		memcpy(ha->ioctl_data + sizeof (ips_passthru_t),
+		       &ips_num_controllers, sizeof (int));
+		ips_scmd_buf_write(SC, ha->ioctl_data,
+				   sizeof (ips_passthru_t) + sizeof (int));
+		SC->result = DID_OK << 16;
+
+		return (IPS_SUCCESS_IMM);
+
+	case IPS_COPPUSRCMD:
+	case IPS_COPPIOCCMD:
+		if (SC->cmnd[0] == IPS_IOCTL_COMMAND) {
+			if (length < (sizeof (ips_passthru_t) + pt->CmdBSize)) {
+				/* wrong size */
+				DEBUG_VAR(1,
+					  "(%s%d) Passthru structure wrong size",
+					  ips_name, ha->host_num);
+
+				return (IPS_FAILURE);
+			}
+
+			if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+			    pt->CoppCP.cmd.flashfw.op_code ==
+			    IPS_CMD_RW_BIOSFW) {
+				ret = ips_flash_copperhead(ha, pt, scb);
+				ips_scmd_buf_write(SC, ha->ioctl_data,
+						   sizeof (ips_passthru_t));
+				return ret;
+			}
+			if (ips_usrcmd(ha, pt, scb))
+				return (IPS_SUCCESS);
+			else
+				return (IPS_FAILURE);
+		}
+
+		break;
+
+	}			/* end switch */
+
+	return (IPS_FAILURE);
+}
+
+/****************************************************************************/
+/* Routine Name: ips_flash_copperhead                                       */
+/* Routine Description:                                                     */
+/*   Flash the BIOS/FW on a Copperhead style controller                     */
+/****************************************************************************/
+static int
+ips_flash_copperhead(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	int datasize;
+
+	/* Trombone is the only copperhead that can do packet flash, but only
+	 * for firmware. No one said it had to make sence. */
+	if (IPS_IS_TROMBONE(ha) && pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE) {
+		if (ips_usrcmd(ha, pt, scb))
+			return IPS_SUCCESS;
+		else
+			return IPS_FAILURE;
+	}
+	pt->BasicStatus = 0x0B;
+	pt->ExtendedStatus = 0;
+	scb->scsi_cmd->result = DID_OK << 16;
+	/* IF it's OK to Use the "CD BOOT" Flash Buffer, then you can     */
+	/* avoid allocating a huge buffer per adapter ( which can fail ). */
+	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
+		pt->BasicStatus = 0;
+		return ips_flash_bios(ha, pt, scb);
+	} else if (pt->CoppCP.cmd.flashfw.packet_num == 0) {
+		if (ips_FlashData && !test_and_set_bit(0, &ips_FlashDataInUse)){
+			ha->flash_data = ips_FlashData;
+			ha->flash_busaddr = ips_flashbusaddr;
+			ha->flash_len = PAGE_SIZE << 7;
+			ha->flash_datasize = 0;
+		} else if (!ha->flash_data) {
+			datasize = pt->CoppCP.cmd.flashfw.total_packets *
+			    pt->CoppCP.cmd.flashfw.count;
+			ha->flash_data = pci_alloc_consistent(ha->pcidev,
+					                      datasize,
+							      &ha->flash_busaddr);
+			if (!ha->flash_data){
+				printk(KERN_WARNING "Unable to allocate a flash buffer\n");
+				return IPS_FAILURE;
+			}
+			ha->flash_datasize = 0;
+			ha->flash_len = datasize;
+		} else
+			return IPS_FAILURE;
+	} else {
+		if (pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
+		    ha->flash_len) {
+			ips_free_flash_copperhead(ha);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "failed size sanity check\n");
+			return IPS_FAILURE;
+		}
+	}
+	if (!ha->flash_data)
+		return IPS_FAILURE;
+	pt->BasicStatus = 0;
+	memcpy(&ha->flash_data[ha->flash_datasize], pt + 1,
+	       pt->CoppCP.cmd.flashfw.count);
+	ha->flash_datasize += pt->CoppCP.cmd.flashfw.count;
+	if (pt->CoppCP.cmd.flashfw.packet_num ==
+	    pt->CoppCP.cmd.flashfw.total_packets - 1) {
+		if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE)
+			return ips_flash_bios(ha, pt, scb);
+		else if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE)
+			return ips_flash_firmware(ha, pt, scb);
+	}
+	return IPS_SUCCESS_IMM;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_flash_bios                                             */
+/* Routine Description:                                                     */
+/*   flashes the bios of a copperhead adapter                               */
+/****************************************************************************/
+static int
+ips_flash_bios(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+
+	if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_BIOS) {
+		if ((!ha->func.programbios) || (!ha->func.erasebios) ||
+		    (!ha->func.verifybios))
+			goto error;
+		if ((*ha->func.erasebios) (ha)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to erase flash",
+				  ips_name, ha->host_num);
+			goto error;
+		} else
+		    if ((*ha->func.programbios) (ha,
+						 ha->flash_data +
+						 IPS_BIOS_HEADER,
+						 ha->flash_datasize -
+						 IPS_BIOS_HEADER, 0)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to flash",
+				  ips_name, ha->host_num);
+			goto error;
+		} else
+		    if ((*ha->func.verifybios) (ha,
+						ha->flash_data +
+						IPS_BIOS_HEADER,
+						ha->flash_datasize -
+						IPS_BIOS_HEADER, 0)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to verify flash",
+				  ips_name, ha->host_num);
+			goto error;
+		}
+		ips_free_flash_copperhead(ha);
+		return IPS_SUCCESS_IMM;
+	} else if (pt->CoppCP.cmd.flashfw.type == IPS_BIOS_IMAGE &&
+		   pt->CoppCP.cmd.flashfw.direction == IPS_ERASE_BIOS) {
+		if (!ha->func.erasebios)
+			goto error;
+		if ((*ha->func.erasebios) (ha)) {
+			DEBUG_VAR(1,
+				  "(%s%d) flash bios failed - unable to erase flash",
+				  ips_name, ha->host_num);
+			goto error;
+		}
+		return IPS_SUCCESS_IMM;
+	}
+      error:
+	pt->BasicStatus = 0x0B;
+	pt->ExtendedStatus = 0x00;
+	ips_free_flash_copperhead(ha);
+	return IPS_FAILURE;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_fill_scb_sg_single                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Fill in a single scb sg_list element from an address                   */
+/*   return a -1 if a breakup occurred                                      */
+/****************************************************************************/
+static int
+ips_fill_scb_sg_single(ips_ha_t * ha, dma_addr_t busaddr,
+		       ips_scb_t * scb, int indx, unsigned int e_len)
+{
+
+	int ret_val = 0;
+
+	if ((scb->data_len + e_len) > ha->max_xfer) {
+		e_len = ha->max_xfer - scb->data_len;
+		scb->breakup = indx;
+		++scb->sg_break;
+		ret_val = -1;
+	} else {
+		scb->breakup = 0;
+		scb->sg_break = 0;
+	}
+	if (IPS_USE_ENH_SGLIST(ha)) {
+		scb->sg_list.enh_list[indx].address_lo =
+		    cpu_to_le32(pci_dma_lo32(busaddr));
+		scb->sg_list.enh_list[indx].address_hi =
+		    cpu_to_le32(pci_dma_hi32(busaddr));
+		scb->sg_list.enh_list[indx].length = cpu_to_le32(e_len);
+	} else {
+		scb->sg_list.std_list[indx].address =
+		    cpu_to_le32(pci_dma_lo32(busaddr));
+		scb->sg_list.std_list[indx].length = cpu_to_le32(e_len);
+	}
+
+	++scb->sg_len;
+	scb->data_len += e_len;
+	return ret_val;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_flash_firmware                                         */
+/* Routine Description:                                                     */
+/*   flashes the firmware of a copperhead adapter                           */
+/****************************************************************************/
+static int
+ips_flash_firmware(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr;
+
+	if (pt->CoppCP.cmd.flashfw.type == IPS_FW_IMAGE &&
+	    pt->CoppCP.cmd.flashfw.direction == IPS_WRITE_FW) {
+		memset(&pt->CoppCP.cmd, 0, sizeof (IPS_HOST_COMMAND));
+		pt->CoppCP.cmd.flashfw.op_code = IPS_CMD_DOWNLOAD;
+		pt->CoppCP.cmd.flashfw.count = cpu_to_le32(ha->flash_datasize);
+	} else {
+		pt->BasicStatus = 0x0B;
+		pt->ExtendedStatus = 0x00;
+		ips_free_flash_copperhead(ha);
+		return IPS_FAILURE;
+	}
+	/* Save the S/G list pointer so it doesn't get clobbered */
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	/* copy in the CP */
+	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
+	/* FIX stuff that might be wrong */
+	scb->sg_list.list = sg_list.list;
+	scb->scb_busaddr = cmd_busaddr;
+	scb->bus = scb->scsi_cmd->device->channel;
+	scb->target_id = scb->scsi_cmd->device->id;
+	scb->lun = scb->scsi_cmd->device->lun;
+	scb->sg_len = 0;
+	scb->data_len = 0;
+	scb->flags = 0;
+	scb->op_code = 0;
+	scb->callback = ipsintr_done;
+	scb->timeout = ips_cmd_timeout;
+
+	scb->data_len = ha->flash_datasize;
+	scb->data_busaddr =
+	    pci_map_single(ha->pcidev, ha->flash_data, scb->data_len,
+			   IPS_DMA_DIR(scb));
+	scb->flags |= IPS_SCB_MAP_SINGLE;
+	scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.flashfw.buffer_addr = cpu_to_le32(scb->data_busaddr);
+	if (pt->TimeOut)
+		scb->timeout = pt->TimeOut;
+	scb->scsi_cmd->result = DID_OK << 16;
+	return IPS_SUCCESS;
+}
+
+/****************************************************************************/
+/* Routine Name: ips_free_flash_copperhead                                  */
+/* Routine Description:                                                     */
+/*   release the memory resources used to hold the flash image              */
+/****************************************************************************/
+static void
+ips_free_flash_copperhead(ips_ha_t * ha)
+{
+	if (ha->flash_data == ips_FlashData)
+		test_and_clear_bit(0, &ips_FlashDataInUse);
+	else if (ha->flash_data)
+		pci_free_consistent(ha->pcidev, ha->flash_len, ha->flash_data,
+				    ha->flash_busaddr);
+	ha->flash_data = NULL;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_usrcmd                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Process a user command and make it ready to send                       */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_usrcmd(ips_ha_t * ha, ips_passthru_t * pt, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr;
+
+	METHOD_TRACE("ips_usrcmd", 1);
+
+	if ((!scb) || (!pt) || (!ha))
+		return (0);
+
+	/* Save the S/G list pointer so it doesn't get clobbered */
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	/* copy in the CP */
+	memcpy(&scb->cmd, &pt->CoppCP.cmd, sizeof (IPS_IOCTL_CMD));
+	memcpy(&scb->dcdb, &pt->CoppCP.dcdb, sizeof (IPS_DCDB_TABLE));
+
+	/* FIX stuff that might be wrong */
+	scb->sg_list.list = sg_list.list;
+	scb->scb_busaddr = cmd_busaddr;
+	scb->bus = scb->scsi_cmd->device->channel;
+	scb->target_id = scb->scsi_cmd->device->id;
+	scb->lun = scb->scsi_cmd->device->lun;
+	scb->sg_len = 0;
+	scb->data_len = 0;
+	scb->flags = 0;
+	scb->op_code = 0;
+	scb->callback = ipsintr_done;
+	scb->timeout = ips_cmd_timeout;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+
+	/* we don't support DCDB/READ/WRITE Scatter Gather */
+	if ((scb->cmd.basic_io.op_code == IPS_CMD_READ_SG) ||
+	    (scb->cmd.basic_io.op_code == IPS_CMD_WRITE_SG) ||
+	    (scb->cmd.basic_io.op_code == IPS_CMD_DCDB_SG))
+		return (0);
+
+	if (pt->CmdBSize) {
+		scb->data_len = pt->CmdBSize;
+		scb->data_busaddr = ha->ioctl_busaddr + sizeof (ips_passthru_t);
+	} else {
+		scb->data_busaddr = 0L;
+	}
+
+	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
+		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+							 (unsigned long) &scb->
+							 dcdb -
+							 (unsigned long) scb);
+
+	if (pt->CmdBSize) {
+		if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)
+			scb->dcdb.buffer_pointer =
+			    cpu_to_le32(scb->data_busaddr);
+		else
+			scb->cmd.basic_io.sg_addr =
+			    cpu_to_le32(scb->data_busaddr);
+	}
+
+	/* set timeouts */
+	if (pt->TimeOut) {
+		scb->timeout = pt->TimeOut;
+
+		if (pt->TimeOut <= 10)
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;
+		else if (pt->TimeOut <= 60)
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;
+		else
+			scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;
+	}
+
+	/* assume success */
+	scb->scsi_cmd->result = DID_OK << 16;
+
+	/* success */
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_cleanup_passthru                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Cleanup after a passthru command                                       */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_cleanup_passthru(ips_ha_t * ha, ips_scb_t * scb)
+{
+	ips_passthru_t *pt;
+
+	METHOD_TRACE("ips_cleanup_passthru", 1);
+
+	if ((!scb) || (!scb->scsi_cmd) || (!scb->scsi_cmd->request_buffer)) {
+		DEBUG_VAR(1, "(%s%d) couldn't cleanup after passthru",
+			  ips_name, ha->host_num);
+
+		return;
+	}
+	pt = (ips_passthru_t *) ha->ioctl_data;
+
+	/* Copy data back to the user */
+	if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB)	/* Copy DCDB Back to Caller's Area */
+		memcpy(&pt->CoppCP.dcdb, &scb->dcdb, sizeof (IPS_DCDB_TABLE));
+
+	pt->BasicStatus = scb->basic_status;
+	pt->ExtendedStatus = scb->extended_status;
+	pt->AdapterType = ha->ad_type;
+
+	if (ha->device_id == IPS_DEVICEID_COPPERHEAD &&
+	    (scb->cmd.flashfw.op_code == IPS_CMD_DOWNLOAD ||
+	     scb->cmd.flashfw.op_code == IPS_CMD_RW_BIOSFW))
+		ips_free_flash_copperhead(ha);
+
+	ips_scmd_buf_write(scb->scsi_cmd, ha->ioctl_data, ha->ioctl_datasize);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_host_info                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   The passthru interface for the driver                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_host_info(ips_ha_t * ha, char *ptr, off_t offset, int len)
+{
+	IPS_INFOSTR info;
+
+	METHOD_TRACE("ips_host_info", 1);
+
+	info.buffer = ptr;
+	info.length = len;
+	info.offset = offset;
+	info.pos = 0;
+	info.localpos = 0;
+
+	copy_info(&info, "\nIBM ServeRAID General Information:\n\n");
+
+	if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
+	    (le16_to_cpu(ha->nvram->adapter_type) != 0))
+		copy_info(&info, "\tController Type                   : %s\n",
+			  ips_adapter_name[ha->ad_type - 1]);
+	else
+		copy_info(&info,
+			  "\tController Type                   : Unknown\n");
+
+	if (ha->io_addr)
+		copy_info(&info,
+			  "\tIO region                         : 0x%lx (%d bytes)\n",
+			  ha->io_addr, ha->io_len);
+
+	if (ha->mem_addr) {
+		copy_info(&info,
+			  "\tMemory region                     : 0x%lx (%d bytes)\n",
+			  ha->mem_addr, ha->mem_len);
+		copy_info(&info,
+			  "\tShared memory address             : 0x%lx\n",
+			  ha->mem_ptr);
+	}
+
+	copy_info(&info, "\tIRQ number                        : %d\n", ha->irq);
+
+    /* For the Next 3 lines Check for Binary 0 at the end and don't include it if it's there. */
+    /* That keeps everything happy for "text" operations on the proc file.                    */
+
+	if (le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) {
+        if (ha->nvram->bios_low[3] == 0) { 
+            copy_info(&info,
+			          "\tBIOS Version                      : %c%c%c%c%c%c%c\n",
+			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+			          ha->nvram->bios_low[2]);
+
+        } else {
+		    copy_info(&info,
+			          "\tBIOS Version                      : %c%c%c%c%c%c%c%c\n",
+			          ha->nvram->bios_high[0], ha->nvram->bios_high[1],
+			          ha->nvram->bios_high[2], ha->nvram->bios_high[3],
+			          ha->nvram->bios_low[0], ha->nvram->bios_low[1],
+			          ha->nvram->bios_low[2], ha->nvram->bios_low[3]);
+        }
+
+    }
+
+    if (ha->enq->CodeBlkVersion[7] == 0) {
+        copy_info(&info,
+		          "\tFirmware Version                  : %c%c%c%c%c%c%c\n",
+		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
+		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
+		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
+		          ha->enq->CodeBlkVersion[6]);
+    } else {
+        copy_info(&info,
+		          "\tFirmware Version                  : %c%c%c%c%c%c%c%c\n",
+		          ha->enq->CodeBlkVersion[0], ha->enq->CodeBlkVersion[1],
+		          ha->enq->CodeBlkVersion[2], ha->enq->CodeBlkVersion[3],
+		          ha->enq->CodeBlkVersion[4], ha->enq->CodeBlkVersion[5],
+		          ha->enq->CodeBlkVersion[6], ha->enq->CodeBlkVersion[7]);
+    }
+
+    if (ha->enq->BootBlkVersion[7] == 0) {
+        copy_info(&info,
+		          "\tBoot Block Version                : %c%c%c%c%c%c%c\n",
+		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
+		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
+		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
+		          ha->enq->BootBlkVersion[6]);
+    } else {
+        copy_info(&info,
+		          "\tBoot Block Version                : %c%c%c%c%c%c%c%c\n",
+		          ha->enq->BootBlkVersion[0], ha->enq->BootBlkVersion[1],
+		          ha->enq->BootBlkVersion[2], ha->enq->BootBlkVersion[3],
+		          ha->enq->BootBlkVersion[4], ha->enq->BootBlkVersion[5],
+		          ha->enq->BootBlkVersion[6], ha->enq->BootBlkVersion[7]);
+    }
+
+	copy_info(&info, "\tDriver Version                    : %s%s\n",
+		  IPS_VERSION_HIGH, IPS_VERSION_LOW);
+
+	copy_info(&info, "\tDriver Build                      : %d\n",
+		  IPS_BUILD_IDENT);
+
+	copy_info(&info, "\tMax Physical Devices              : %d\n",
+		  ha->enq->ucMaxPhysicalDevices);
+	copy_info(&info, "\tMax Active Commands               : %d\n",
+		  ha->max_cmds);
+	copy_info(&info, "\tCurrent Queued Commands           : %d\n",
+		  ha->scb_waitlist.count);
+	copy_info(&info, "\tCurrent Active Commands           : %d\n",
+		  ha->scb_activelist.count - ha->num_ioctl);
+	copy_info(&info, "\tCurrent Queued PT Commands        : %d\n",
+		  ha->copp_waitlist.count);
+	copy_info(&info, "\tCurrent Active PT Commands        : %d\n",
+		  ha->num_ioctl);
+
+	copy_info(&info, "\n");
+
+	return (info.localpos);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: copy_mem_info                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Copy data into an IPS_INFOSTR structure                                */
+/*                                                                          */
+/****************************************************************************/
+static void
+copy_mem_info(IPS_INFOSTR * info, char *data, int len)
+{
+	METHOD_TRACE("copy_mem_info", 1);
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len -= (info->offset - info->pos);
+		info->pos += (info->offset - info->pos);
+	}
+
+	if (info->localpos + len > info->length)
+		len = info->length - info->localpos;
+
+	if (len > 0) {
+		memcpy(info->buffer + info->localpos, data, len);
+		info->pos += len;
+		info->localpos += len;
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: copy_info                                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   printf style wrapper for an info structure                             */
+/*                                                                          */
+/****************************************************************************/
+static int
+copy_info(IPS_INFOSTR * info, char *fmt, ...)
+{
+	va_list args;
+	char buf[128];
+	int len;
+
+	METHOD_TRACE("copy_info", 1);
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+
+	return (len);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_identify_controller                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Identify this controller                                               */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_identify_controller(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_identify_controller", 1);
+
+	switch (ha->device_id) {
+	case IPS_DEVICEID_COPPERHEAD:
+		if (ha->revision_id <= IPS_REVID_SERVERAID) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID;
+		} else if (ha->revision_id == IPS_REVID_SERVERAID2) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID2;
+		} else if (ha->revision_id == IPS_REVID_NAVAJO) {
+			ha->ad_type = IPS_ADTYPE_NAVAJO;
+		} else if ((ha->revision_id == IPS_REVID_SERVERAID2)
+			   && (ha->slot_num == 0)) {
+			ha->ad_type = IPS_ADTYPE_KIOWA;
+		} else if ((ha->revision_id >= IPS_REVID_CLARINETP1) &&
+			   (ha->revision_id <= IPS_REVID_CLARINETP3)) {
+			if (ha->enq->ucMaxPhysicalDevices == 15)
+				ha->ad_type = IPS_ADTYPE_SERVERAID3L;
+			else
+				ha->ad_type = IPS_ADTYPE_SERVERAID3;
+		} else if ((ha->revision_id >= IPS_REVID_TROMBONE32) &&
+			   (ha->revision_id <= IPS_REVID_TROMBONE64)) {
+			ha->ad_type = IPS_ADTYPE_SERVERAID4H;
+		}
+		break;
+
+	case IPS_DEVICEID_MORPHEUS:
+		switch (ha->subdevice_id) {
+		case IPS_SUBDEVICEID_4L:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4L;
+			break;
+
+		case IPS_SUBDEVICEID_4M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4M;
+			break;
+
+		case IPS_SUBDEVICEID_4MX:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4MX;
+			break;
+
+		case IPS_SUBDEVICEID_4LX:
+			ha->ad_type = IPS_ADTYPE_SERVERAID4LX;
+			break;
+
+		case IPS_SUBDEVICEID_5I2:
+			ha->ad_type = IPS_ADTYPE_SERVERAID5I2;
+			break;
+
+		case IPS_SUBDEVICEID_5I1:
+			ha->ad_type = IPS_ADTYPE_SERVERAID5I1;
+			break;
+		}
+
+		break;
+
+	case IPS_DEVICEID_MARCO:
+		switch (ha->subdevice_id) {
+		case IPS_SUBDEVICEID_6M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID6M;
+			break;
+		case IPS_SUBDEVICEID_6I:
+			ha->ad_type = IPS_ADTYPE_SERVERAID6I;
+			break;
+		case IPS_SUBDEVICEID_7k:
+			ha->ad_type = IPS_ADTYPE_SERVERAID7k;
+			break;
+		case IPS_SUBDEVICEID_7M:
+			ha->ad_type = IPS_ADTYPE_SERVERAID7M;
+			break;
+		}
+		break;
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_get_bios_version                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Get the BIOS revision number                                           */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_get_bios_version(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+	uint8_t major;
+	uint8_t minor;
+	uint8_t subminor;
+	uint8_t *buffer;
+	char hexDigits[] =
+	    { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C',
+     'D', 'E', 'F' };
+
+	METHOD_TRACE("ips_get_bios_version", 1);
+
+	major = 0;
+	minor = 0;
+
+	strncpy(ha->bios_version, "       ?", 8);
+
+	if (ha->device_id == IPS_DEVICEID_COPPERHEAD) {
+		if (IPS_USE_MEMIO(ha)) {
+			/* Memory Mapped I/O */
+
+			/* test 1st byte */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+				return;
+
+			writel(1, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+				return;
+
+			/* Get Major version */
+			writel(0x1FF, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			major = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			/* Get Minor version */
+			writel(0x1FE, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+			minor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			/* Get SubMinor version */
+			writel(0x1FD, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+			subminor = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+		} else {
+			/* Programmed I/O */
+
+			/* test 1st byte */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+				return;
+
+			outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+				return;
+
+			/* Get Major version */
+			outl(cpu_to_le32(0x1FF), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			major = inb(ha->io_addr + IPS_REG_FLDP);
+
+			/* Get Minor version */
+			outl(cpu_to_le32(0x1FE), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			minor = inb(ha->io_addr + IPS_REG_FLDP);
+
+			/* Get SubMinor version */
+			outl(cpu_to_le32(0x1FD), ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			subminor = inb(ha->io_addr + IPS_REG_FLDP);
+
+		}
+	} else {
+		/* Morpheus Family - Send Command to the card */
+
+		buffer = ha->ioctl_data;
+
+		memset(buffer, 0, 0x1000);
+
+		scb = &ha->scbs[ha->max_cmds - 1];
+
+		ips_init_scb(ha, scb);
+
+		scb->timeout = ips_cmd_timeout;
+		scb->cdb[0] = IPS_CMD_RW_BIOSFW;
+
+		scb->cmd.flashfw.op_code = IPS_CMD_RW_BIOSFW;
+		scb->cmd.flashfw.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.flashfw.type = 1;
+		scb->cmd.flashfw.direction = 0;
+		scb->cmd.flashfw.count = cpu_to_le32(0x800);
+		scb->cmd.flashfw.total_packets = 1;
+		scb->cmd.flashfw.packet_num = 0;
+		scb->data_len = 0x1000;
+		scb->cmd.flashfw.buffer_addr = ha->ioctl_busaddr;
+
+		/* issue the command */
+		if (((ret =
+		      ips_send_wait(ha, scb, ips_cmd_timeout,
+				    intr)) == IPS_FAILURE)
+		    || (ret == IPS_SUCCESS_IMM)
+		    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+			/* Error occurred */
+
+			return;
+		}
+
+		if ((buffer[0xC0] == 0x55) && (buffer[0xC1] == 0xAA)) {
+			major = buffer[0x1ff + 0xC0];	/* Offset 0x1ff after the header (0xc0) */
+			minor = buffer[0x1fe + 0xC0];	/* Offset 0x1fe after the header (0xc0) */
+			subminor = buffer[0x1fd + 0xC0];	/* Offset 0x1fd after the header (0xc0) */
+		} else {
+			return;
+		}
+	}
+
+	ha->bios_version[0] = hexDigits[(major & 0xF0) >> 4];
+	ha->bios_version[1] = '.';
+	ha->bios_version[2] = hexDigits[major & 0x0F];
+	ha->bios_version[3] = hexDigits[subminor];
+	ha->bios_version[4] = '.';
+	ha->bios_version[5] = hexDigits[(minor & 0xF0) >> 4];
+	ha->bios_version[6] = hexDigits[minor & 0x0F];
+	ha->bios_version[7] = 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_hainit                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize the controller                                              */
+/*                                                                          */
+/* NOTE: Assumes to be called from with a lock                              */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_hainit(ips_ha_t * ha)
+{
+	int i;
+	struct timeval tv;
+
+	METHOD_TRACE("ips_hainit", 1);
+
+	if (!ha)
+		return (0);
+
+	if (ha->func.statinit)
+		(*ha->func.statinit) (ha);
+
+	if (ha->func.enableint)
+		(*ha->func.enableint) (ha);
+
+	/* Send FFDC */
+	ha->reset_count = 1;
+	do_gettimeofday(&tv);
+	ha->last_ffdc = tv.tv_sec;
+	ips_ffdc_reset(ha, IPS_INTR_IORL);
+
+	if (!ips_read_config(ha, IPS_INTR_IORL)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read config from controller.\n");
+
+		return (0);
+	}
+	/* end if */
+	if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read controller status.\n");
+
+		return (0);
+	}
+
+	/* Identify this controller */
+	ips_identify_controller(ha);
+
+	if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read subsystem parameters.\n");
+
+		return (0);
+	}
+
+	/* write nvram user page 5 */
+	if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to write driver info to controller.\n");
+
+		return (0);
+	}
+
+	/* If there are Logical Drives and a Reset Occurred, then an EraseStripeLock is Needed */
+	if ((ha->conf->ucLogDriveCount > 0) && (ha->requires_esl == 1))
+		ips_clear_adapter(ha, IPS_INTR_IORL);
+
+	/* set limits on SID, LUN, BUS */
+	ha->ntargets = IPS_MAX_TARGETS + 1;
+	ha->nlun = 1;
+	ha->nbus = (ha->enq->ucMaxPhysicalDevices / IPS_MAX_TARGETS) + 1;
+
+	switch (ha->conf->logical_drive[0].ucStripeSize) {
+	case 4:
+		ha->max_xfer = 0x10000;
+		break;
+
+	case 5:
+		ha->max_xfer = 0x20000;
+		break;
+
+	case 6:
+		ha->max_xfer = 0x40000;
+		break;
+
+	case 7:
+	default:
+		ha->max_xfer = 0x80000;
+		break;
+	}
+
+	/* setup max concurrent commands */
+	if (le32_to_cpu(ha->subsys->param[4]) & 0x1) {
+		/* Use the new method */
+		ha->max_cmds = ha->enq->ucConcurrentCmdCount;
+	} else {
+		/* use the old method */
+		switch (ha->conf->logical_drive[0].ucStripeSize) {
+		case 4:
+			ha->max_cmds = 32;
+			break;
+
+		case 5:
+			ha->max_cmds = 16;
+			break;
+
+		case 6:
+			ha->max_cmds = 8;
+			break;
+
+		case 7:
+		default:
+			ha->max_cmds = 4;
+			break;
+		}
+	}
+
+	/* Limit the Active Commands on a Lite Adapter */
+	if ((ha->ad_type == IPS_ADTYPE_SERVERAID3L) ||
+	    (ha->ad_type == IPS_ADTYPE_SERVERAID4L) ||
+	    (ha->ad_type == IPS_ADTYPE_SERVERAID4LX)) {
+		if ((ha->max_cmds > MaxLiteCmds) && (MaxLiteCmds))
+			ha->max_cmds = MaxLiteCmds;
+	}
+
+	/* set controller IDs */
+	ha->ha_id[0] = IPS_ADAPTER_ID;
+	for (i = 1; i < ha->nbus; i++) {
+		ha->ha_id[i] = ha->conf->init_id[i - 1] & 0x1f;
+		ha->dcdb_active[i - 1] = 0;
+	}
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_next                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Take the next command off the queue and send it to the controller      */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_next(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	Scsi_Cmnd *SC;
+	Scsi_Cmnd *p;
+	Scsi_Cmnd *q;
+	ips_copp_wait_item_t *item;
+	int ret;
+	unsigned long cpu_flags = 0;
+	struct Scsi_Host *host;
+	METHOD_TRACE("ips_next", 1);
+
+	if (!ha)
+		return;
+	host = ips_sh[ha->host_num];
+	/*
+	 * Block access to the queue function so
+	 * this command won't time out
+	 */
+	if (intr == IPS_INTR_ON)
+		IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+	if ((ha->subsys->param[3] & 0x300000)
+	    && (ha->scb_activelist.count == 0)) {
+		struct timeval tv;
+
+		do_gettimeofday(&tv);
+
+		if (tv.tv_sec - ha->last_ffdc > IPS_SECS_8HOURS) {
+			ha->last_ffdc = tv.tv_sec;
+			ips_ffdc_time(ha);
+		}
+	}
+
+	/*
+	 * Send passthru commands
+	 * These have priority over normal I/O
+	 * but shouldn't affect performance too much
+	 * since we limit the number that can be active
+	 * on the card at any one time
+	 */
+	while ((ha->num_ioctl < IPS_MAX_IOCTL) &&
+	       (ha->copp_waitlist.head) && (scb = ips_getscb(ha))) {
+
+		item = ips_removeq_copp_head(&ha->copp_waitlist);
+		ha->num_ioctl++;
+		if (intr == IPS_INTR_ON)
+			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+		scb->scsi_cmd = item->scsi_cmd;
+		kfree(item);
+
+		ret = ips_make_passthru(ha, scb->scsi_cmd, scb, intr);
+
+		if (intr == IPS_INTR_ON)
+			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+		switch (ret) {
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_OK << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
+
+		if (ret != IPS_SUCCESS) {
+			ha->num_ioctl--;
+			continue;
+		}
+
+		ret = ips_send_cmd(ha, scb);
+
+		if (ret == IPS_SUCCESS)
+			ips_putq_scb_head(&ha->scb_activelist, scb);
+		else
+			ha->num_ioctl--;
+
+		switch (ret) {
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+			}
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
+
+	}
+
+	/*
+	 * Send "Normal" I/O commands
+	 */
+
+	p = ha->scb_waitlist.head;
+	while ((p) && (scb = ips_getscb(ha))) {
+		if ((p->device->channel > 0)
+		    && (ha->
+			dcdb_active[p->device->channel -
+				    1] & (1 << p->device->id))) {
+			ips_freescb(ha, scb);
+			p = (Scsi_Cmnd *) p->host_scribble;
+			continue;
+		}
+
+		q = p;
+		SC = ips_removeq_wait(&ha->scb_waitlist, q);
+
+		if (intr == IPS_INTR_ON)
+			IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);	/* Unlock HA after command is taken off queue */
+
+		SC->result = DID_OK;
+		SC->host_scribble = NULL;
+
+		memset(SC->sense_buffer, 0, sizeof (SC->sense_buffer));
+
+		scb->target_id = SC->device->id;
+		scb->lun = SC->device->lun;
+		scb->bus = SC->device->channel;
+		scb->scsi_cmd = SC;
+		scb->breakup = 0;
+		scb->data_len = 0;
+		scb->callback = ipsintr_done;
+		scb->timeout = ips_cmd_timeout;
+		memset(&scb->cmd, 0, 16);
+
+		/* copy in the CDB */
+		memcpy(scb->cdb, SC->cmnd, SC->cmd_len);
+
+		/* Now handle the data buffer */
+		if (SC->use_sg) {
+			struct scatterlist *sg;
+			int i;
+
+			sg = SC->request_buffer;
+			scb->sg_count = pci_map_sg(ha->pcidev, sg, SC->use_sg,
+						   scsi_to_pci_dma_dir(SC->
+								       sc_data_direction));
+			scb->flags |= IPS_SCB_MAP_SG;
+			for (i = 0; i < scb->sg_count; i++) {
+				if (ips_fill_scb_sg_single
+				    (ha, sg_dma_address(&sg[i]), scb, i,
+				     sg_dma_len(&sg[i])) < 0)
+					break;
+			}
+			scb->dcdb.transfer_length = scb->data_len;
+		} else {
+			if (SC->request_bufflen) {
+				scb->data_busaddr =
+				    pci_map_single(ha->pcidev,
+						   SC->request_buffer,
+						   SC->request_bufflen,
+						   scsi_to_pci_dma_dir(SC->
+								       sc_data_direction));
+				scb->flags |= IPS_SCB_MAP_SINGLE;
+				ips_fill_scb_sg_single(ha, scb->data_busaddr,
+						       scb, 0,
+						       SC->request_bufflen);
+				scb->dcdb.transfer_length = scb->data_len;
+			} else {
+				scb->data_busaddr = 0L;
+				scb->sg_len = 0;
+				scb->data_len = 0;
+				scb->dcdb.transfer_length = 0;
+			}
+
+		}
+
+		scb->dcdb.cmd_attribute =
+		    ips_command_direction[scb->scsi_cmd->cmnd[0]];
+
+        /* Allow a WRITE BUFFER Command to Have no Data */
+        /* This is Used by Tape Flash Utilites          */
+        if ((scb->scsi_cmd->cmnd[0] == WRITE_BUFFER) && (scb->data_len == 0)) 
+            scb->dcdb.cmd_attribute = 0;                  
+
+		if (!(scb->dcdb.cmd_attribute & 0x3))
+			scb->dcdb.transfer_length = 0;
+
+		if (scb->data_len >= IPS_MAX_XFER) {
+			scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
+			scb->dcdb.transfer_length = 0;
+		}
+		if (intr == IPS_INTR_ON)
+			IPS_LOCK_SAVE(host->host_lock, cpu_flags);
+
+		ret = ips_send_cmd(ha, scb);
+
+		switch (ret) {
+		case IPS_SUCCESS:
+			ips_putq_scb_head(&ha->scb_activelist, scb);
+			break;
+		case IPS_FAILURE:
+			if (scb->scsi_cmd) {
+				scb->scsi_cmd->result = DID_ERROR << 16;
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+			}
+
+			if (scb->bus)
+				ha->dcdb_active[scb->bus - 1] &=
+				    ~(1 << scb->target_id);
+
+			ips_freescb(ha, scb);
+			break;
+		case IPS_SUCCESS_IMM:
+			if (scb->scsi_cmd)
+				scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+
+			if (scb->bus)
+				ha->dcdb_active[scb->bus - 1] &=
+				    ~(1 << scb->target_id);
+
+			ips_freescb(ha, scb);
+			break;
+		default:
+			break;
+		}		/* end case */
+
+		p = (Scsi_Cmnd *) p->host_scribble;
+
+	}			/* end while */
+
+	if (intr == IPS_INTR_ON)
+		IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_putq_scb_head                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Add an item to the head of the queue                                   */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_putq_scb_head(ips_scb_queue_t * queue, ips_scb_t * item)
+{
+	METHOD_TRACE("ips_putq_scb_head", 1);
+
+	if (!item)
+		return;
+
+	item->q_next = queue->head;
+	queue->head = item;
+
+	if (!queue->tail)
+		queue->tail = item;
+
+	queue->count++;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_scb_head                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove the head of the queue                                           */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static ips_scb_t *
+ips_removeq_scb_head(ips_scb_queue_t * queue)
+{
+	ips_scb_t *item;
+
+	METHOD_TRACE("ips_removeq_scb_head", 1);
+
+	item = queue->head;
+
+	if (!item) {
+		return (NULL);
+	}
+
+	queue->head = item->q_next;
+	item->q_next = NULL;
+
+	if (queue->tail == item)
+		queue->tail = NULL;
+
+	queue->count--;
+
+	return (item);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_scb                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an item from a queue                                            */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static ips_scb_t *
+ips_removeq_scb(ips_scb_queue_t * queue, ips_scb_t * item)
+{
+	ips_scb_t *p;
+
+	METHOD_TRACE("ips_removeq_scb", 1);
+
+	if (!item)
+		return (NULL);
+
+	if (item == queue->head) {
+		return (ips_removeq_scb_head(queue));
+	}
+
+	p = queue->head;
+
+	while ((p) && (item != p->q_next))
+		p = p->q_next;
+
+	if (p) {
+		/* found a match */
+		p->q_next = item->q_next;
+
+		if (!item->q_next)
+			queue->tail = p;
+
+		item->q_next = NULL;
+		queue->count--;
+
+		return (item);
+	}
+
+	return (NULL);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_putq_wait_tail                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Add an item to the tail of the queue                                   */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_putq_wait_tail(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+{
+	METHOD_TRACE("ips_putq_wait_tail", 1);
+
+	if (!item)
+		return;
+
+	item->host_scribble = NULL;
+
+	if (queue->tail)
+		queue->tail->host_scribble = (char *) item;
+
+	queue->tail = item;
+
+	if (!queue->head)
+		queue->head = item;
+
+	queue->count++;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_wait_head                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove the head of the queue                                           */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static Scsi_Cmnd *
+ips_removeq_wait_head(ips_wait_queue_t * queue)
+{
+	Scsi_Cmnd *item;
+
+	METHOD_TRACE("ips_removeq_wait_head", 1);
+
+	item = queue->head;
+
+	if (!item) {
+		return (NULL);
+	}
+
+	queue->head = (Scsi_Cmnd *) item->host_scribble;
+	item->host_scribble = NULL;
+
+	if (queue->tail == item)
+		queue->tail = NULL;
+
+	queue->count--;
+
+	return (item);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_wait                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an item from a queue                                            */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static Scsi_Cmnd *
+ips_removeq_wait(ips_wait_queue_t * queue, Scsi_Cmnd * item)
+{
+	Scsi_Cmnd *p;
+
+	METHOD_TRACE("ips_removeq_wait", 1);
+
+	if (!item)
+		return (NULL);
+
+	if (item == queue->head) {
+		return (ips_removeq_wait_head(queue));
+	}
+
+	p = queue->head;
+
+	while ((p) && (item != (Scsi_Cmnd *) p->host_scribble))
+		p = (Scsi_Cmnd *) p->host_scribble;
+
+	if (p) {
+		/* found a match */
+		p->host_scribble = item->host_scribble;
+
+		if (!item->host_scribble)
+			queue->tail = p;
+
+		item->host_scribble = NULL;
+		queue->count--;
+
+		return (item);
+	}
+
+	return (NULL);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_putq_copp_tail                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Add an item to the tail of the queue                                   */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_putq_copp_tail(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
+{
+	METHOD_TRACE("ips_putq_copp_tail", 1);
+
+	if (!item)
+		return;
+
+	item->next = NULL;
+
+	if (queue->tail)
+		queue->tail->next = item;
+
+	queue->tail = item;
+
+	if (!queue->head)
+		queue->head = item;
+
+	queue->count++;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_copp_head                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove the head of the queue                                           */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static ips_copp_wait_item_t *
+ips_removeq_copp_head(ips_copp_queue_t * queue)
+{
+	ips_copp_wait_item_t *item;
+
+	METHOD_TRACE("ips_removeq_copp_head", 1);
+
+	item = queue->head;
+
+	if (!item) {
+		return (NULL);
+	}
+
+	queue->head = item->next;
+	item->next = NULL;
+
+	if (queue->tail == item)
+		queue->tail = NULL;
+
+	queue->count--;
+
+	return (item);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_removeq_copp                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an item from a queue                                            */
+/*                                                                          */
+/* ASSUMED to be called from within the HA lock                             */
+/*                                                                          */
+/****************************************************************************/
+static ips_copp_wait_item_t *
+ips_removeq_copp(ips_copp_queue_t * queue, ips_copp_wait_item_t * item)
+{
+	ips_copp_wait_item_t *p;
+
+	METHOD_TRACE("ips_removeq_copp", 1);
+
+	if (!item)
+		return (NULL);
+
+	if (item == queue->head) {
+		return (ips_removeq_copp_head(queue));
+	}
+
+	p = queue->head;
+
+	while ((p) && (item != p->next))
+		p = p->next;
+
+	if (p) {
+		/* found a match */
+		p->next = item->next;
+
+		if (!item->next)
+			queue->tail = p;
+
+		item->next = NULL;
+		queue->count--;
+
+		return (item);
+	}
+
+	return (NULL);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ipsintr_blocking                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Finalize an interrupt for internal commands                            */
+/*                                                                          */
+/****************************************************************************/
+static void
+ipsintr_blocking(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ipsintr_blocking", 2);
+
+	ips_freescb(ha, scb);
+	if ((ha->waitflag == TRUE) && (ha->cmd_in_progress == scb->cdb[0])) {
+		ha->waitflag = FALSE;
+
+		return;
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ipsintr_done                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Finalize an interrupt for non-internal commands                        */
+/*                                                                          */
+/****************************************************************************/
+static void
+ipsintr_done(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ipsintr_done", 2);
+
+	if (!scb) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Spurious interrupt; scb NULL.\n");
+
+		return;
+	}
+
+	if (scb->scsi_cmd == NULL) {
+		/* unexpected interrupt */
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Spurious interrupt; scsi_cmd not set.\n");
+
+		return;
+	}
+
+	ips_done(ha, scb);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_done                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Do housekeeping on completed commands                                  */
+/*  ASSUMED to be called form within the request lock                       */
+/****************************************************************************/
+static void
+ips_done(ips_ha_t * ha, ips_scb_t * scb)
+{
+	int ret;
+
+	METHOD_TRACE("ips_done", 1);
+
+	if (!scb)
+		return;
+
+	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd))) {
+		ips_cleanup_passthru(ha, scb);
+		ha->num_ioctl--;
+	} else {
+		/*
+		 * Check to see if this command had too much
+		 * data and had to be broke up.  If so, queue
+		 * the rest of the data and continue.
+		 */
+		if ((scb->breakup) || (scb->sg_break)) {
+			/* we had a data breakup */
+			scb->data_len = 0;
+
+			if (scb->sg_count) {
+				/* S/G request */
+				struct scatterlist *sg;
+				int ips_sg_index = 0;
+				int sg_dma_index;
+
+				sg = scb->scsi_cmd->request_buffer;
+
+				/* Spin forward to last dma chunk */
+				sg_dma_index = scb->breakup;
+
+				/* Take care of possible partial on last chunk */
+				ips_fill_scb_sg_single(ha,
+						       sg_dma_address(&sg
+								      [sg_dma_index]),
+						       scb, ips_sg_index++,
+						       sg_dma_len(&sg
+								  [sg_dma_index]));
+
+				for (; sg_dma_index < scb->sg_count;
+				     sg_dma_index++) {
+					if (ips_fill_scb_sg_single
+					    (ha,
+					     sg_dma_address(&sg[sg_dma_index]),
+					     scb, ips_sg_index++,
+					     sg_dma_len(&sg[sg_dma_index])) < 0)
+						break;
+
+				}
+
+			} else {
+				/* Non S/G Request */
+				(void) ips_fill_scb_sg_single(ha,
+							      scb->
+							      data_busaddr +
+							      (scb->sg_break *
+							       ha->max_xfer),
+							      scb, 0,
+							      scb->scsi_cmd->
+							      request_bufflen -
+							      (scb->sg_break *
+							       ha->max_xfer));
+			}
+
+			scb->dcdb.transfer_length = scb->data_len;
+			scb->dcdb.cmd_attribute |=
+			    ips_command_direction[scb->scsi_cmd->cmnd[0]];
+
+			if (!(scb->dcdb.cmd_attribute & 0x3))
+				scb->dcdb.transfer_length = 0;
+
+			if (scb->data_len >= IPS_MAX_XFER) {
+				scb->dcdb.cmd_attribute |= IPS_TRANSFER64K;
+				scb->dcdb.transfer_length = 0;
+			}
+
+			ret = ips_send_cmd(ha, scb);
+
+			switch (ret) {
+			case IPS_FAILURE:
+				if (scb->scsi_cmd) {
+					scb->scsi_cmd->result = DID_ERROR << 16;
+					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+				}
+
+				ips_freescb(ha, scb);
+				break;
+			case IPS_SUCCESS_IMM:
+				if (scb->scsi_cmd) {
+					scb->scsi_cmd->result = DID_ERROR << 16;
+					scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+				}
+
+				ips_freescb(ha, scb);
+				break;
+			default:
+				break;
+			}	/* end case */
+
+			return;
+		}
+	}			/* end if passthru */
+
+	if (scb->bus) {
+		ha->dcdb_active[scb->bus - 1] &= ~(1 << scb->target_id);
+	}
+
+	scb->scsi_cmd->scsi_done(scb->scsi_cmd);
+
+	ips_freescb(ha, scb);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_map_status                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Map Controller Error codes to Linux Error Codes                        */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_map_status(ips_ha_t * ha, ips_scb_t * scb, ips_stat_t * sp)
+{
+	int errcode;
+	int device_error;
+	uint32_t transfer_len;
+	IPS_DCDB_TABLE_TAPE *tapeDCDB;
+
+	METHOD_TRACE("ips_map_status", 1);
+
+	if (scb->bus) {
+		DEBUG_VAR(2,
+			  "(%s%d) Physical device error (%d %d %d): %x %x, Sense Key: %x, ASC: %x, ASCQ: %x",
+			  ips_name, ha->host_num,
+			  scb->scsi_cmd->device->channel,
+			  scb->scsi_cmd->device->id, scb->scsi_cmd->device->lun,
+			  scb->basic_status, scb->extended_status,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[2] & 0xf : 0,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[12] : 0,
+			  scb->extended_status ==
+			  IPS_ERR_CKCOND ? scb->dcdb.sense_info[13] : 0);
+	}
+
+	/* default driver error */
+	errcode = DID_ERROR;
+	device_error = 0;
+
+	switch (scb->basic_status & IPS_GSC_STATUS_MASK) {
+	case IPS_CMD_TIMEOUT:
+		errcode = DID_TIME_OUT;
+		break;
+
+	case IPS_INVAL_OPCO:
+	case IPS_INVAL_CMD_BLK:
+	case IPS_INVAL_PARM_BLK:
+	case IPS_LD_ERROR:
+	case IPS_CMD_CMPLT_WERROR:
+		break;
+
+	case IPS_PHYS_DRV_ERROR:
+		switch (scb->extended_status) {
+		case IPS_ERR_SEL_TO:
+			if (scb->bus)
+				errcode = DID_NO_CONNECT;
+
+			break;
+
+		case IPS_ERR_OU_RUN:
+			if ((scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB) ||
+			    (scb->cmd.dcdb.op_code ==
+			     IPS_CMD_EXTENDED_DCDB_SG)) {
+				tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
+				transfer_len = tapeDCDB->transfer_length;
+			} else {
+				transfer_len =
+				    (uint32_t) scb->dcdb.transfer_length;
+			}
+
+			if ((scb->bus) && (transfer_len < scb->data_len)) {
+				/* Underrun - set default to no error */
+				errcode = DID_OK;
+
+				/* Restrict access to physical DASD */
+				if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
+				    ((((char *) scb->scsi_cmd->
+				       buffer)[0] & 0x1f) == TYPE_DISK)) {
+					/* underflow -- no error               */
+					/* restrict access to physical DASD    */
+					errcode = DID_TIME_OUT;
+					break;
+				}
+			} else
+				errcode = DID_ERROR;
+
+			break;
+
+		case IPS_ERR_RECOVERY:
+			/* don't fail recovered errors */
+			if (scb->bus)
+				errcode = DID_OK;
+
+			break;
+
+		case IPS_ERR_HOST_RESET:
+		case IPS_ERR_DEV_RESET:
+			errcode = DID_RESET;
+			break;
+
+		case IPS_ERR_CKCOND:
+			if (scb->bus) {
+				if ((scb->cmd.dcdb.op_code ==
+				     IPS_CMD_EXTENDED_DCDB)
+				    || (scb->cmd.dcdb.op_code ==
+					IPS_CMD_EXTENDED_DCDB_SG)) {
+					tapeDCDB =
+					    (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;
+					memcpy(scb->scsi_cmd->sense_buffer,
+					       tapeDCDB->sense_info,
+					       sizeof (scb->scsi_cmd->
+						       sense_buffer));
+				} else {
+					memcpy(scb->scsi_cmd->sense_buffer,
+					       scb->dcdb.sense_info,
+					       sizeof (scb->scsi_cmd->
+						       sense_buffer));
+				}
+				device_error = 2;	/* check condition */
+			}
+
+			errcode = DID_OK;
+
+			break;
+
+		default:
+			errcode = DID_ERROR;
+			break;
+
+		}		/* end switch */
+	}			/* end switch */
+
+	scb->scsi_cmd->result = device_error | (errcode << 16);
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_send_wait                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command to the controller and wait for it to return             */
+/*                                                                          */
+/*   The FFDC Time Stamp use this function for the callback, but doesn't    */
+/*   actually need to wait.                                                 */
+/****************************************************************************/
+static int
+ips_send_wait(ips_ha_t * ha, ips_scb_t * scb, int timeout, int intr)
+{
+	int ret;
+
+	METHOD_TRACE("ips_send_wait", 1);
+
+	if (intr != IPS_FFDC) {	/* Won't be Waiting if this is a Time Stamp */
+		ha->waitflag = TRUE;
+		ha->cmd_in_progress = scb->cdb[0];
+	}
+	scb->callback = ipsintr_blocking;
+	ret = ips_send_cmd(ha, scb);
+
+	if ((ret == IPS_FAILURE) || (ret == IPS_SUCCESS_IMM))
+		return (ret);
+
+	if (intr != IPS_FFDC)	/* Don't Wait around if this is a Time Stamp */
+		ret = ips_wait(ha, timeout, intr);
+
+	return (ret);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_scmd_buf_write                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*  Write data to Scsi_Cmnd request_buffer at proper offsets                */
+/****************************************************************************/
+static void
+ips_scmd_buf_write(Scsi_Cmnd * scmd, void *data, unsigned
+		   int count)
+{
+	if (scmd->use_sg) {
+		int i;
+		unsigned int min_cnt, xfer_cnt;
+		char *cdata = (char *) data;
+		struct scatterlist *sg = scmd->request_buffer;
+		for (i = 0, xfer_cnt = 0;
+		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
+			if (!IPS_SG_ADDRESS(&sg[i]))
+				return;
+			min_cnt = min(count - xfer_cnt, sg[i].length);
+			memcpy(IPS_SG_ADDRESS(&sg[i]), &cdata[xfer_cnt],
+			       min_cnt);
+			xfer_cnt += min_cnt;
+		}
+
+	} else {
+		unsigned int min_cnt = min(count, scmd->request_bufflen);
+		memcpy(scmd->request_buffer, data, min_cnt);
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_scmd_buf_read                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*  Copy data from a Scsi_Cmnd to a new, linear buffer                      */
+/****************************************************************************/
+static void
+ips_scmd_buf_read(Scsi_Cmnd * scmd, void *data, unsigned
+		  int count)
+{
+	if (scmd->use_sg) {
+		int i;
+		unsigned int min_cnt, xfer_cnt;
+		char *cdata = (char *) data;
+		struct scatterlist *sg = scmd->request_buffer;
+		for (i = 0, xfer_cnt = 0;
+		     (i < scmd->use_sg) && (xfer_cnt < count); i++) {
+			if (!IPS_SG_ADDRESS(&sg[i]))
+				return;
+			min_cnt = min(count - xfer_cnt, sg[i].length);
+			memcpy(&cdata[xfer_cnt], IPS_SG_ADDRESS(&sg[i]),
+			       min_cnt);
+			xfer_cnt += min_cnt;
+		}
+
+	} else {
+		unsigned int min_cnt = min(count, scmd->request_bufflen);
+		memcpy(data, scmd->request_buffer, min_cnt);
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_send_cmd                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Map SCSI commands to ServeRAID commands for logical drives             */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_send_cmd(ips_ha_t * ha, ips_scb_t * scb)
+{
+	int ret;
+	char *sp;
+	int device_error;
+	IPS_DCDB_TABLE_TAPE *tapeDCDB;
+	int TimeOut;
+
+	METHOD_TRACE("ips_send_cmd", 1);
+
+	ret = IPS_SUCCESS;
+
+	if (!scb->scsi_cmd) {
+		/* internal command */
+
+		if (scb->bus > 0) {
+			/* Controller commands can't be issued */
+			/* to real devices -- fail them        */
+			if ((ha->waitflag == TRUE) &&
+			    (ha->cmd_in_progress == scb->cdb[0])) {
+				ha->waitflag = FALSE;
+			}
+
+			return (1);
+		}
+	} else if ((scb->bus == 0) && (!ips_is_passthru(scb->scsi_cmd))) {
+		/* command to logical bus -- interpret */
+		ret = IPS_SUCCESS_IMM;
+
+		switch (scb->scsi_cmd->cmnd[0]) {
+		case ALLOW_MEDIUM_REMOVAL:
+		case REZERO_UNIT:
+		case ERASE:
+		case WRITE_FILEMARKS:
+		case SPACE:
+			scb->scsi_cmd->result = DID_ERROR << 16;
+			break;
+
+		case START_STOP:
+			scb->scsi_cmd->result = DID_OK << 16;
+
+		case TEST_UNIT_READY:
+		case INQUIRY:
+			if (scb->target_id == IPS_ADAPTER_ID) {
+				/*
+				 * Either we have a TUR
+				 * or we have a SCSI inquiry
+				 */
+				if (scb->scsi_cmd->cmnd[0] == TEST_UNIT_READY)
+					scb->scsi_cmd->result = DID_OK << 16;
+
+				if (scb->scsi_cmd->cmnd[0] == INQUIRY) {
+					IPS_SCSI_INQ_DATA inquiry;
+
+					memset(&inquiry, 0,
+					       sizeof (IPS_SCSI_INQ_DATA));
+
+					inquiry.DeviceType =
+					    IPS_SCSI_INQ_TYPE_PROCESSOR;
+					inquiry.DeviceTypeQualifier =
+					    IPS_SCSI_INQ_LU_CONNECTED;
+					inquiry.Version = IPS_SCSI_INQ_REV2;
+					inquiry.ResponseDataFormat =
+					    IPS_SCSI_INQ_RD_REV2;
+					inquiry.AdditionalLength = 31;
+					inquiry.Flags[0] =
+					    IPS_SCSI_INQ_Address16;
+					inquiry.Flags[1] =
+					    IPS_SCSI_INQ_WBus16 |
+					    IPS_SCSI_INQ_Sync;
+					strncpy(inquiry.VendorId, "IBM     ",
+						8);
+					strncpy(inquiry.ProductId,
+						"SERVERAID       ", 16);
+					strncpy(inquiry.ProductRevisionLevel,
+						"1.00", 4);
+
+					ips_scmd_buf_write(scb->scsi_cmd,
+							   &inquiry,
+							   sizeof (inquiry));
+
+					scb->scsi_cmd->result = DID_OK << 16;
+				}
+			} else {
+				scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
+				scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
+				scb->cmd.logical_info.reserved = 0;
+				scb->cmd.logical_info.reserved2 = 0;
+				scb->data_len = sizeof (IPS_LD_INFO);
+				scb->data_busaddr = ha->logical_drive_info_dma_addr;
+				scb->flags = 0;
+				scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
+				ret = IPS_SUCCESS;
+			}
+
+			break;
+
+		case REQUEST_SENSE:
+			ips_reqsen(ha, scb);
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		case READ_6:
+		case WRITE_6:
+			if (!scb->sg_len) {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_6) ? IPS_CMD_READ : IPS_CMD_WRITE;
+				scb->cmd.basic_io.enhanced_sg = 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->data_busaddr);
+			} else {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_6) ? IPS_CMD_READ_SG :
+				    IPS_CMD_WRITE_SG;
+				scb->cmd.basic_io.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->sg_busaddr);
+			}
+
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.log_drv = scb->target_id;
+			scb->cmd.basic_io.sg_count = scb->sg_len;
+
+			if (scb->cmd.basic_io.lba)
+				scb->cmd.basic_io.lba =
+				    cpu_to_le32(le32_to_cpu
+						(scb->cmd.basic_io.lba) +
+						le16_to_cpu(scb->cmd.basic_io.
+							    sector_count));
+			else
+				scb->cmd.basic_io.lba =
+				    (((scb->scsi_cmd->
+				       cmnd[1] & 0x1f) << 16) | (scb->scsi_cmd->
+								 cmnd[2] << 8) |
+				     (scb->scsi_cmd->cmnd[3]));
+
+			scb->cmd.basic_io.sector_count =
+			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
+
+			if (le16_to_cpu(scb->cmd.basic_io.sector_count) == 0)
+				scb->cmd.basic_io.sector_count =
+				    cpu_to_le16(256);
+
+			ret = IPS_SUCCESS;
+			break;
+
+		case READ_10:
+		case WRITE_10:
+			if (!scb->sg_len) {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_10) ? IPS_CMD_READ : IPS_CMD_WRITE;
+				scb->cmd.basic_io.enhanced_sg = 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->data_busaddr);
+			} else {
+				scb->cmd.basic_io.op_code =
+				    (scb->scsi_cmd->cmnd[0] ==
+				     READ_10) ? IPS_CMD_READ_SG :
+				    IPS_CMD_WRITE_SG;
+				scb->cmd.basic_io.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+				scb->cmd.basic_io.sg_addr =
+				    cpu_to_le32(scb->sg_busaddr);
+			}
+
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.log_drv = scb->target_id;
+			scb->cmd.basic_io.sg_count = scb->sg_len;
+
+			if (scb->cmd.basic_io.lba)
+				scb->cmd.basic_io.lba =
+				    cpu_to_le32(le32_to_cpu
+						(scb->cmd.basic_io.lba) +
+						le16_to_cpu(scb->cmd.basic_io.
+							    sector_count));
+			else
+				scb->cmd.basic_io.lba =
+				    ((scb->scsi_cmd->cmnd[2] << 24) | (scb->
+								       scsi_cmd->
+								       cmnd[3]
+								       << 16) |
+				     (scb->scsi_cmd->cmnd[4] << 8) | scb->
+				     scsi_cmd->cmnd[5]);
+
+			scb->cmd.basic_io.sector_count =
+			    cpu_to_le16(scb->data_len / IPS_BLKSIZE);
+
+			if (cpu_to_le16(scb->cmd.basic_io.sector_count) == 0) {
+				/*
+				 * This is a null condition
+				 * we don't have to do anything
+				 * so just return
+				 */
+				scb->scsi_cmd->result = DID_OK << 16;
+			} else
+				ret = IPS_SUCCESS;
+
+			break;
+
+		case RESERVE:
+		case RELEASE:
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		case MODE_SENSE:
+			scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
+			scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.basic_io.segment_4G = 0;
+			scb->cmd.basic_io.enhanced_sg = 0;
+			scb->data_len = sizeof (*ha->enq);
+			scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
+			ret = IPS_SUCCESS;
+			break;
+
+		case READ_CAPACITY:
+			scb->cmd.logical_info.op_code = IPS_CMD_GET_LD_INFO;
+			scb->cmd.logical_info.command_id = IPS_COMMAND_ID(ha, scb);
+			scb->cmd.logical_info.reserved = 0;
+			scb->cmd.logical_info.reserved2 = 0;
+			scb->cmd.logical_info.reserved3 = 0;
+			scb->data_len = sizeof (IPS_LD_INFO);
+			scb->data_busaddr = ha->logical_drive_info_dma_addr;
+			scb->flags = 0;
+			scb->cmd.logical_info.buffer_addr = scb->data_busaddr;
+			ret = IPS_SUCCESS;
+			break;
+
+		case SEND_DIAGNOSTIC:
+		case REASSIGN_BLOCKS:
+		case FORMAT_UNIT:
+		case SEEK_10:
+		case VERIFY:
+		case READ_DEFECT_DATA:
+		case READ_BUFFER:
+		case WRITE_BUFFER:
+			scb->scsi_cmd->result = DID_OK << 16;
+			break;
+
+		default:
+			/* Set the Return Info to appear like the Command was */
+			/* attempted, a Check Condition occurred, and Sense   */
+			/* Data indicating an Invalid CDB OpCode is returned. */
+			sp = (char *) scb->scsi_cmd->sense_buffer;
+			memset(sp, 0, sizeof (scb->scsi_cmd->sense_buffer));
+
+			sp[0] = 0x70;	/* Error Code               */
+			sp[2] = ILLEGAL_REQUEST;	/* Sense Key 5 Illegal Req. */
+			sp[7] = 0x0A;	/* Additional Sense Length  */
+			sp[12] = 0x20;	/* ASC = Invalid OpCode     */
+			sp[13] = 0x00;	/* ASCQ                     */
+
+			device_error = 2;	/* Indicate Check Condition */
+			scb->scsi_cmd->result = device_error | (DID_OK << 16);
+			break;
+		}		/* end switch */
+	}
+	/* end if */
+	if (ret == IPS_SUCCESS_IMM)
+		return (ret);
+
+	/* setup DCDB */
+	if (scb->bus > 0) {
+
+		/* If we already know the Device is Not there, no need to attempt a Command   */
+		/* This also protects an NT FailOver Controller from getting CDB's sent to it */
+		if (ha->conf->dev[scb->bus - 1][scb->target_id].ucState == 0) {
+			scb->scsi_cmd->result = DID_NO_CONNECT << 16;
+			return (IPS_SUCCESS_IMM);
+		}
+
+		ha->dcdb_active[scb->bus - 1] |= (1 << scb->target_id);
+		scb->cmd.dcdb.command_id = IPS_COMMAND_ID(ha, scb);
+		scb->cmd.dcdb.dcdb_address = cpu_to_le32(scb->scb_busaddr +
+							 (unsigned long) &scb->
+							 dcdb -
+							 (unsigned long) scb);
+		scb->cmd.dcdb.reserved = 0;
+		scb->cmd.dcdb.reserved2 = 0;
+		scb->cmd.dcdb.reserved3 = 0;
+		scb->cmd.dcdb.segment_4G = 0;
+		scb->cmd.dcdb.enhanced_sg = 0;
+
+		TimeOut = scb->scsi_cmd->timeout_per_command;
+
+		if (ha->subsys->param[4] & 0x00100000) {	/* If NEW Tape DCDB is Supported */
+			if (!scb->sg_len) {
+				scb->cmd.dcdb.op_code = IPS_CMD_EXTENDED_DCDB;
+			} else {
+				scb->cmd.dcdb.op_code =
+				    IPS_CMD_EXTENDED_DCDB_SG;
+				scb->cmd.dcdb.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+			}
+
+			tapeDCDB = (IPS_DCDB_TABLE_TAPE *) & scb->dcdb;	/* Use Same Data Area as Old DCDB Struct */
+			tapeDCDB->device_address =
+			    ((scb->bus - 1) << 4) | scb->target_id;
+			tapeDCDB->cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+			tapeDCDB->cmd_attribute &= ~IPS_TRANSFER64K;	/* Always Turn OFF 64K Size Flag */
+
+			if (TimeOut) {
+				if (TimeOut < (10 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
+				else if (TimeOut < (60 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
+				else if (TimeOut < (1200 * HZ))
+					tapeDCDB->cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
+			}
+
+			tapeDCDB->cdb_length = scb->scsi_cmd->cmd_len;
+			tapeDCDB->reserved_for_LUN = 0;
+			tapeDCDB->transfer_length = scb->data_len;
+			if (scb->cmd.dcdb.op_code == IPS_CMD_EXTENDED_DCDB_SG)
+				tapeDCDB->buffer_pointer =
+				    cpu_to_le32(scb->sg_busaddr);
+			else
+				tapeDCDB->buffer_pointer =
+				    cpu_to_le32(scb->data_busaddr);
+			tapeDCDB->sg_count = scb->sg_len;
+			tapeDCDB->sense_length = sizeof (tapeDCDB->sense_info);
+			tapeDCDB->scsi_status = 0;
+			tapeDCDB->reserved = 0;
+			memcpy(tapeDCDB->scsi_cdb, scb->scsi_cmd->cmnd,
+			       scb->scsi_cmd->cmd_len);
+		} else {
+			if (!scb->sg_len) {
+				scb->cmd.dcdb.op_code = IPS_CMD_DCDB;
+			} else {
+				scb->cmd.dcdb.op_code = IPS_CMD_DCDB_SG;
+				scb->cmd.dcdb.enhanced_sg =
+				    IPS_USE_ENH_SGLIST(ha) ? 0xFF : 0;
+			}
+
+			scb->dcdb.device_address =
+			    ((scb->bus - 1) << 4) | scb->target_id;
+			scb->dcdb.cmd_attribute |= IPS_DISCONNECT_ALLOWED;
+
+			if (TimeOut) {
+				if (TimeOut < (10 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT10;	/* TimeOut is 10 Seconds */
+				else if (TimeOut < (60 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT60;	/* TimeOut is 60 Seconds */
+				else if (TimeOut < (1200 * HZ))
+					scb->dcdb.cmd_attribute |= IPS_TIMEOUT20M;	/* TimeOut is 20 Minutes */
+			}
+
+			scb->dcdb.transfer_length = scb->data_len;
+			if (scb->dcdb.cmd_attribute & IPS_TRANSFER64K)
+				scb->dcdb.transfer_length = 0;
+			if (scb->cmd.dcdb.op_code == IPS_CMD_DCDB_SG)
+				scb->dcdb.buffer_pointer =
+				    cpu_to_le32(scb->sg_busaddr);
+			else
+				scb->dcdb.buffer_pointer =
+				    cpu_to_le32(scb->data_busaddr);
+			scb->dcdb.cdb_length = scb->scsi_cmd->cmd_len;
+			scb->dcdb.sense_length = sizeof (scb->dcdb.sense_info);
+			scb->dcdb.sg_count = scb->sg_len;
+			scb->dcdb.reserved = 0;
+			memcpy(scb->dcdb.scsi_cdb, scb->scsi_cmd->cmnd,
+			       scb->scsi_cmd->cmd_len);
+			scb->dcdb.scsi_status = 0;
+			scb->dcdb.reserved2[0] = 0;
+			scb->dcdb.reserved2[1] = 0;
+			scb->dcdb.reserved2[2] = 0;
+		}
+	}
+
+	return ((*ha->func.issue) (ha, scb));
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_chk_status                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Check the status of commands to logical drives                         */
+/*   Assumed to be called with the HA lock                                  */
+/****************************************************************************/
+static void
+ips_chkstatus(ips_ha_t * ha, IPS_STATUS * pstatus)
+{
+	ips_scb_t *scb;
+	ips_stat_t *sp;
+	uint8_t basic_status;
+	uint8_t ext_status;
+	int errcode;
+
+	METHOD_TRACE("ips_chkstatus", 1);
+
+	scb = &ha->scbs[pstatus->fields.command_id];
+	scb->basic_status = basic_status =
+	    pstatus->fields.basic_status & IPS_BASIC_STATUS_MASK;
+	scb->extended_status = ext_status = pstatus->fields.extended_status;
+
+	sp = &ha->sp;
+	sp->residue_len = 0;
+	sp->scb_addr = (void *) scb;
+
+	/* Remove the item from the active queue */
+	ips_removeq_scb(&ha->scb_activelist, scb);
+
+	if (!scb->scsi_cmd)
+		/* internal commands are handled in do_ipsintr */
+		return;
+
+	DEBUG_VAR(2, "(%s%d) ips_chkstatus: cmd 0x%X id %d (%d %d %d)",
+		  ips_name,
+		  ha->host_num,
+		  scb->cdb[0],
+		  scb->cmd.basic_io.command_id,
+		  scb->bus, scb->target_id, scb->lun);
+
+	if ((scb->scsi_cmd) && (ips_is_passthru(scb->scsi_cmd)))
+		/* passthru - just returns the raw result */
+		return;
+
+	errcode = DID_OK;
+
+	if (((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_SUCCESS) ||
+	    ((basic_status & IPS_GSC_STATUS_MASK) == IPS_CMD_RECOVERED_ERROR)) {
+
+		if (scb->bus == 0) {
+			if ((basic_status & IPS_GSC_STATUS_MASK) ==
+			    IPS_CMD_RECOVERED_ERROR) {
+				DEBUG_VAR(1,
+					  "(%s%d) Recovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+					  ips_name, ha->host_num,
+					  scb->cmd.basic_io.op_code,
+					  basic_status, ext_status);
+			}
+
+			switch (scb->scsi_cmd->cmnd[0]) {
+			case ALLOW_MEDIUM_REMOVAL:
+			case REZERO_UNIT:
+			case ERASE:
+			case WRITE_FILEMARKS:
+			case SPACE:
+				errcode = DID_ERROR;
+				break;
+
+			case START_STOP:
+				break;
+
+			case TEST_UNIT_READY:
+				if (!ips_online(ha, scb)) {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case INQUIRY:
+				if (ips_online(ha, scb)) {
+					ips_inquiry(ha, scb);
+				} else {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case REQUEST_SENSE:
+				ips_reqsen(ha, scb);
+				break;
+
+			case READ_6:
+			case WRITE_6:
+			case READ_10:
+			case WRITE_10:
+			case RESERVE:
+			case RELEASE:
+				break;
+
+			case MODE_SENSE:
+				if (!ips_online(ha, scb)
+				    || !ips_msense(ha, scb)) {
+					errcode = DID_ERROR;
+				}
+				break;
+
+			case READ_CAPACITY:
+				if (ips_online(ha, scb))
+					ips_rdcap(ha, scb);
+				else {
+					errcode = DID_TIME_OUT;
+				}
+				break;
+
+			case SEND_DIAGNOSTIC:
+			case REASSIGN_BLOCKS:
+				break;
+
+			case FORMAT_UNIT:
+				errcode = DID_ERROR;
+				break;
+
+			case SEEK_10:
+			case VERIFY:
+			case READ_DEFECT_DATA:
+			case READ_BUFFER:
+			case WRITE_BUFFER:
+				break;
+
+			default:
+				errcode = DID_ERROR;
+			}	/* end switch */
+
+			scb->scsi_cmd->result = errcode << 16;
+		} else {	/* bus == 0 */
+			/* restrict access to physical drives */
+			if ((scb->scsi_cmd->cmnd[0] == INQUIRY) &&
+			    ((((char *) scb->scsi_cmd->buffer)[0] & 0x1f) ==
+			     TYPE_DISK)) {
+
+				scb->scsi_cmd->result = DID_TIME_OUT << 16;
+			}
+		}		/* else */
+	} else {		/* recovered error / success */
+		if (scb->bus == 0) {
+			DEBUG_VAR(1,
+				  "(%s%d) Unrecovered Logical Drive Error OpCode: %x, BSB: %x, ESB: %x",
+				  ips_name, ha->host_num,
+				  scb->cmd.basic_io.op_code, basic_status,
+				  ext_status);
+		}
+
+		ips_map_status(ha, scb, sp);
+	}			/* else */
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_online                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Determine if a logical drive is online                                 */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_online(ips_ha_t * ha, ips_scb_t * scb)
+{
+	METHOD_TRACE("ips_online", 1);
+
+	if (scb->target_id >= IPS_MAX_LD)
+		return (0);
+
+	if ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1) {
+		memset(ha->logical_drive_info, 0, sizeof (IPS_LD_INFO));
+		return (0);
+	}
+
+	if (ha->logical_drive_info->drive_info[scb->target_id].state !=
+	    IPS_LD_OFFLINE
+	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
+	    IPS_LD_FREE
+	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
+	    IPS_LD_CRS
+	    && ha->logical_drive_info->drive_info[scb->target_id].state !=
+	    IPS_LD_SYS)
+		return (1);
+	else
+		return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_inquiry                                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Simulate an inquiry command to a logical drive                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_inquiry(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_INQ_DATA inquiry;
+
+	METHOD_TRACE("ips_inquiry", 1);
+
+	memset(&inquiry, 0, sizeof (IPS_SCSI_INQ_DATA));
+
+	inquiry.DeviceType = IPS_SCSI_INQ_TYPE_DASD;
+	inquiry.DeviceTypeQualifier = IPS_SCSI_INQ_LU_CONNECTED;
+	inquiry.Version = IPS_SCSI_INQ_REV2;
+	inquiry.ResponseDataFormat = IPS_SCSI_INQ_RD_REV2;
+	inquiry.AdditionalLength = 31;
+	inquiry.Flags[0] = IPS_SCSI_INQ_Address16;
+	inquiry.Flags[1] =
+	    IPS_SCSI_INQ_WBus16 | IPS_SCSI_INQ_Sync | IPS_SCSI_INQ_CmdQue;
+	strncpy(inquiry.VendorId, "IBM     ", 8);
+	strncpy(inquiry.ProductId, "SERVERAID       ", 16);
+	strncpy(inquiry.ProductRevisionLevel, "1.00", 4);
+
+	ips_scmd_buf_write(scb->scsi_cmd, &inquiry, sizeof (inquiry));
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_rdcap                                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Simulate a read capacity command to a logical drive                    */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_rdcap(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_CAPACITY cap;
+
+	METHOD_TRACE("ips_rdcap", 1);
+
+	if (scb->scsi_cmd->bufflen < 8)
+		return (0);
+
+	cap.lba =
+	    cpu_to_be32(le32_to_cpu
+			(ha->logical_drive_info->
+			 drive_info[scb->target_id].sector_count) - 1);
+	cap.len = cpu_to_be32((uint32_t) IPS_BLKSIZE);
+
+	ips_scmd_buf_write(scb->scsi_cmd, &cap, sizeof (cap));
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_msense                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Simulate a mode sense command to a logical drive                       */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_msense(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint16_t heads;
+	uint16_t sectors;
+	uint32_t cylinders;
+	IPS_SCSI_MODE_PAGE_DATA mdata;
+
+	METHOD_TRACE("ips_msense", 1);
+
+	if (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) > 0x400000 &&
+	    (ha->enq->ucMiscFlag & 0x8) == 0) {
+		heads = IPS_NORM_HEADS;
+		sectors = IPS_NORM_SECTORS;
+	} else {
+		heads = IPS_COMP_HEADS;
+		sectors = IPS_COMP_SECTORS;
+	}
+
+	cylinders =
+	    (le32_to_cpu(ha->enq->ulDriveSize[scb->target_id]) -
+	     1) / (heads * sectors);
+
+	memset(&mdata, 0, sizeof (IPS_SCSI_MODE_PAGE_DATA));
+
+	mdata.hdr.BlockDescLength = 8;
+
+	switch (scb->scsi_cmd->cmnd[2] & 0x3f) {
+	case 0x03:		/* page 3 */
+		mdata.pdata.pg3.PageCode = 3;
+		mdata.pdata.pg3.PageLength = sizeof (IPS_SCSI_MODE_PAGE3);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg3.PageLength;
+		mdata.pdata.pg3.TracksPerZone = 0;
+		mdata.pdata.pg3.AltSectorsPerZone = 0;
+		mdata.pdata.pg3.AltTracksPerZone = 0;
+		mdata.pdata.pg3.AltTracksPerVolume = 0;
+		mdata.pdata.pg3.SectorsPerTrack = cpu_to_be16(sectors);
+		mdata.pdata.pg3.BytesPerSector = cpu_to_be16(IPS_BLKSIZE);
+		mdata.pdata.pg3.Interleave = cpu_to_be16(1);
+		mdata.pdata.pg3.TrackSkew = 0;
+		mdata.pdata.pg3.CylinderSkew = 0;
+		mdata.pdata.pg3.flags = IPS_SCSI_MP3_SoftSector;
+		break;
+
+	case 0x4:
+		mdata.pdata.pg4.PageCode = 4;
+		mdata.pdata.pg4.PageLength = sizeof (IPS_SCSI_MODE_PAGE4);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg4.PageLength;
+		mdata.pdata.pg4.CylindersHigh =
+		    cpu_to_be16((cylinders >> 8) & 0xFFFF);
+		mdata.pdata.pg4.CylindersLow = (cylinders & 0xFF);
+		mdata.pdata.pg4.Heads = heads;
+		mdata.pdata.pg4.WritePrecompHigh = 0;
+		mdata.pdata.pg4.WritePrecompLow = 0;
+		mdata.pdata.pg4.ReducedWriteCurrentHigh = 0;
+		mdata.pdata.pg4.ReducedWriteCurrentLow = 0;
+		mdata.pdata.pg4.StepRate = cpu_to_be16(1);
+		mdata.pdata.pg4.LandingZoneHigh = 0;
+		mdata.pdata.pg4.LandingZoneLow = 0;
+		mdata.pdata.pg4.flags = 0;
+		mdata.pdata.pg4.RotationalOffset = 0;
+		mdata.pdata.pg4.MediumRotationRate = 0;
+		break;
+	case 0x8:
+		mdata.pdata.pg8.PageCode = 8;
+		mdata.pdata.pg8.PageLength = sizeof (IPS_SCSI_MODE_PAGE8);
+		mdata.hdr.DataLength =
+		    3 + mdata.hdr.BlockDescLength + mdata.pdata.pg8.PageLength;
+		/* everything else is left set to 0 */
+		break;
+
+	default:
+		return (0);
+	}			/* end switch */
+
+	ips_scmd_buf_write(scb->scsi_cmd, &mdata, sizeof (mdata));
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reqsen                                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Simulate a request sense command to a logical drive                    */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reqsen(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SCSI_REQSEN reqsen;
+
+	METHOD_TRACE("ips_reqsen", 1);
+
+	memset(&reqsen, 0, sizeof (IPS_SCSI_REQSEN));
+
+	reqsen.ResponseCode =
+	    IPS_SCSI_REQSEN_VALID | IPS_SCSI_REQSEN_CURRENT_ERR;
+	reqsen.AdditionalLength = 10;
+	reqsen.AdditionalSenseCode = IPS_SCSI_REQSEN_NO_SENSE;
+	reqsen.AdditionalSenseCodeQual = IPS_SCSI_REQSEN_NO_SENSE;
+
+	ips_scmd_buf_write(scb->scsi_cmd, &reqsen, sizeof (reqsen));
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_free                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Free any allocated space for this controller                           */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_free(ips_ha_t * ha)
+{
+
+	METHOD_TRACE("ips_free", 1);
+
+	if (ha) {
+		if (ha->enq) {
+			pci_free_consistent(ha->pcidev, sizeof(IPS_ENQ),
+					    ha->enq, ha->enq_busaddr);
+			ha->enq = NULL;
+		}
+
+		if (ha->conf) {
+			kfree(ha->conf);
+			ha->conf = NULL;
+		}
+
+		if (ha->adapt) {
+			pci_free_consistent(ha->pcidev,
+					    sizeof (IPS_ADAPTER) +
+					    sizeof (IPS_IO_CMD), ha->adapt,
+					    ha->adapt->hw_status_start);
+			ha->adapt = NULL;
+		}
+
+		if (ha->logical_drive_info) {
+			pci_free_consistent(ha->pcidev,
+					    sizeof (IPS_LD_INFO),
+					    ha->logical_drive_info,
+					    ha->logical_drive_info_dma_addr);
+			ha->logical_drive_info = NULL;
+		}
+
+		if (ha->nvram) {
+			kfree(ha->nvram);
+			ha->nvram = NULL;
+		}
+
+		if (ha->subsys) {
+			kfree(ha->subsys);
+			ha->subsys = NULL;
+		}
+
+		if (ha->ioctl_data) {
+			pci_free_consistent(ha->pcidev, ha->ioctl_len,
+					    ha->ioctl_data, ha->ioctl_busaddr);
+			ha->ioctl_data = NULL;
+			ha->ioctl_datasize = 0;
+			ha->ioctl_len = 0;
+		}
+		ips_deallocatescbs(ha, ha->max_cmds);
+
+		/* free memory mapped (if applicable) */
+		if (ha->mem_ptr) {
+			iounmap(ha->ioremap_ptr);
+			ha->ioremap_ptr = NULL;
+			ha->mem_ptr = NULL;
+		}
+
+		if (ha->mem_addr)
+			release_mem_region(ha->mem_addr, ha->mem_len);
+		ha->mem_addr = 0;
+
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_deallocatescbs                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Free the command blocks                                                */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_deallocatescbs(ips_ha_t * ha, int cmds)
+{
+	if (ha->scbs) {
+		pci_free_consistent(ha->pcidev,
+				    IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * cmds,
+				    ha->scbs->sg_list.list,
+				    ha->scbs->sg_busaddr);
+		pci_free_consistent(ha->pcidev, sizeof (ips_scb_t) * cmds,
+				    ha->scbs, ha->scbs->scb_busaddr);
+		ha->scbs = NULL;
+	}			/* end if */
+	return 1;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_allocatescbs                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Allocate the command blocks                                            */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_allocatescbs(ips_ha_t * ha)
+{
+	ips_scb_t *scb_p;
+	IPS_SG_LIST ips_sg;
+	int i;
+	dma_addr_t command_dma, sg_dma;
+
+	METHOD_TRACE("ips_allocatescbs", 1);
+
+	/* Allocate memory for the SCBs */
+	ha->scbs =
+	    pci_alloc_consistent(ha->pcidev, ha->max_cmds * sizeof (ips_scb_t),
+				 &command_dma);
+	if (ha->scbs == NULL)
+		return 0;
+	ips_sg.list =
+	    pci_alloc_consistent(ha->pcidev,
+				 IPS_SGLIST_SIZE(ha) * IPS_MAX_SG *
+				 ha->max_cmds, &sg_dma);
+	if (ips_sg.list == NULL) {
+		pci_free_consistent(ha->pcidev,
+				    ha->max_cmds * sizeof (ips_scb_t), ha->scbs,
+				    command_dma);
+		return 0;
+	}
+
+	memset(ha->scbs, 0, ha->max_cmds * sizeof (ips_scb_t));
+
+	for (i = 0; i < ha->max_cmds; i++) {
+		scb_p = &ha->scbs[i];
+		scb_p->scb_busaddr = command_dma + sizeof (ips_scb_t) * i;
+		/* set up S/G list */
+		if (IPS_USE_ENH_SGLIST(ha)) {
+			scb_p->sg_list.enh_list =
+			    ips_sg.enh_list + i * IPS_MAX_SG;
+			scb_p->sg_busaddr =
+			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
+		} else {
+			scb_p->sg_list.std_list =
+			    ips_sg.std_list + i * IPS_MAX_SG;
+			scb_p->sg_busaddr =
+			    sg_dma + IPS_SGLIST_SIZE(ha) * IPS_MAX_SG * i;
+		}
+
+		/* add to the free list */
+		if (i < ha->max_cmds - 1) {
+			scb_p->q_next = ha->scb_freelist;
+			ha->scb_freelist = scb_p;
+		}
+	}
+
+	/* success */
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_scb                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a CCB to default values                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_init_scb(ips_ha_t * ha, ips_scb_t * scb)
+{
+	IPS_SG_LIST sg_list;
+	uint32_t cmd_busaddr, sg_busaddr;
+	METHOD_TRACE("ips_init_scb", 1);
+
+	if (scb == NULL)
+		return;
+
+	sg_list.list = scb->sg_list.list;
+	cmd_busaddr = scb->scb_busaddr;
+	sg_busaddr = scb->sg_busaddr;
+	/* zero fill */
+	memset(scb, 0, sizeof (ips_scb_t));
+	memset(ha->dummy, 0, sizeof (IPS_IO_CMD));
+
+	/* Initialize dummy command bucket */
+	ha->dummy->op_code = 0xFF;
+	ha->dummy->ccsar = cpu_to_le32(ha->adapt->hw_status_start
+				       + sizeof (IPS_ADAPTER));
+	ha->dummy->command_id = IPS_MAX_CMDS;
+
+	/* set bus address of scb */
+	scb->scb_busaddr = cmd_busaddr;
+	scb->sg_busaddr = sg_busaddr;
+	scb->sg_list.list = sg_list.list;
+
+	/* Neptune Fix */
+	scb->cmd.basic_io.cccr = cpu_to_le32((uint32_t) IPS_BIT_ILE);
+	scb->cmd.basic_io.ccsar = cpu_to_le32(ha->adapt->hw_status_start
+					      + sizeof (IPS_ADAPTER));
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_get_scb                                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a CCB to default values                                     */
+/*                                                                          */
+/* ASSUMED to be callled from within a lock                                 */
+/*                                                                          */
+/****************************************************************************/
+static ips_scb_t *
+ips_getscb(ips_ha_t * ha)
+{
+	ips_scb_t *scb;
+
+	METHOD_TRACE("ips_getscb", 1);
+
+	if ((scb = ha->scb_freelist) == NULL) {
+
+		return (NULL);
+	}
+
+	ha->scb_freelist = scb->q_next;
+	scb->flags = 0;
+	scb->q_next = NULL;
+
+	ips_init_scb(ha, scb);
+
+	return (scb);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_free_scb                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Return an unused CCB back to the free list                             */
+/*                                                                          */
+/* ASSUMED to be called from within a lock                                  */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_freescb(ips_ha_t * ha, ips_scb_t * scb)
+{
+
+	METHOD_TRACE("ips_freescb", 1);
+	if (scb->flags & IPS_SCB_MAP_SG)
+		pci_unmap_sg(ha->pcidev, scb->scsi_cmd->request_buffer,
+			     scb->scsi_cmd->use_sg, IPS_DMA_DIR(scb));
+	else if (scb->flags & IPS_SCB_MAP_SINGLE)
+		pci_unmap_single(ha->pcidev, scb->data_busaddr, scb->data_len,
+				 IPS_DMA_DIR(scb));
+
+	/* check to make sure this is not our "special" scb */
+	if (IPS_COMMAND_ID(ha, scb) < (ha->max_cmds - 1)) {
+		scb->q_next = ha->scb_freelist;
+		ha->scb_freelist = scb;
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isinit_copperhead                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Is controller initialized ?                                            */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isinit_copperhead(ips_ha_t * ha)
+{
+	uint8_t scpr;
+	uint8_t isr;
+
+	METHOD_TRACE("ips_isinit_copperhead", 1);
+
+	isr = inb(ha->io_addr + IPS_REG_HISR);
+	scpr = inb(ha->io_addr + IPS_REG_SCPR);
+
+	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+		return (0);
+	else
+		return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isinit_copperhead_memio                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Is controller initialized ?                                            */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isinit_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t isr = 0;
+	uint8_t scpr;
+
+	METHOD_TRACE("ips_is_init_copperhead_memio", 1);
+
+	isr = readb(ha->mem_ptr + IPS_REG_HISR);
+	scpr = readb(ha->mem_ptr + IPS_REG_SCPR);
+
+	if (((isr & IPS_BIT_EI) == 0) && ((scpr & IPS_BIT_EBM) == 0))
+		return (0);
+	else
+		return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isinit_morpheus                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Is controller initialized ?                                            */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isinit_morpheus(ips_ha_t * ha)
+{
+	uint32_t post;
+	uint32_t bits;
+
+	METHOD_TRACE("ips_is_init_morpheus", 1);
+
+	post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+	bits = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	if (post == 0)
+		return (0);
+	else if (bits & 0x3)
+		return (0);
+	else
+		return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_copperhead                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_copperhead(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_enable_int_copperhead", 1);
+
+	outb(ha->io_addr + IPS_REG_HISR, IPS_BIT_EI);
+	inb(ha->io_addr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_copperhead_memio                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_copperhead_memio(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_enable_int_copperhead_memio", 1);
+
+	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+	readb(ha->mem_ptr + IPS_REG_HISR);	/*Ensure PCI Posting Completes*/
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_enable_int_morpheus                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Turn on interrupts                                                     */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_enable_int_morpheus(ips_ha_t * ha)
+{
+	uint32_t Oimr;
+
+	METHOD_TRACE("ips_enable_int_morpheus", 1);
+
+	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+	Oimr &= ~0x08;
+	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+	readl(ha->mem_ptr + IPS_REG_I960_OIMR);	/*Ensure PCI Posting Completes*/
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_copperhead                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a copperhead controller                                     */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_copperhead(ips_ha_t * ha)
+{
+	uint8_t Isr;
+	uint8_t Cbsp;
+	uint8_t PostByte[IPS_MAX_POST_BYTES];
+	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+	int i, j;
+
+	METHOD_TRACE("ips_init_copperhead", 1);
+
+	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+		for (j = 0; j < 45; j++) {
+			Isr = inb(ha->io_addr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 45)
+			/* error occurred */
+			return (0);
+
+		PostByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
+
+	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x %x).\n",
+			   PostByte[0], PostByte[1]);
+
+		return (0);
+	}
+
+	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+		for (j = 0; j < 240; j++) {
+			Isr = inb(ha->io_addr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 240)
+			/* error occurred */
+			return (0);
+
+		ConfigByte[i] = inb(ha->io_addr + IPS_REG_ISPR);
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
+
+	for (i = 0; i < 240; i++) {
+		Cbsp = inb(ha->io_addr + IPS_REG_CBSP);
+
+		if ((Cbsp & IPS_BIT_OP) == 0)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240)
+		/* reset failed */
+		return (0);
+
+	/* setup CCCR */
+	outl(cpu_to_le32(0x1010), ha->io_addr + IPS_REG_CCCR);
+
+	/* Enable busmastering */
+	outb(IPS_BIT_EBM, ha->io_addr + IPS_REG_SCPR);
+
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		/* fix for anaconda64 */
+		outl(0, ha->io_addr + IPS_REG_NDAE);
+
+	/* Enable interrupts */
+	outb(IPS_BIT_EI, ha->io_addr + IPS_REG_HISR);
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_copperhead_memio                                  */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a copperhead controller with memory mapped I/O              */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t Isr = 0;
+	uint8_t Cbsp;
+	uint8_t PostByte[IPS_MAX_POST_BYTES];
+	uint8_t ConfigByte[IPS_MAX_CONFIG_BYTES];
+	int i, j;
+
+	METHOD_TRACE("ips_init_copperhead_memio", 1);
+
+	for (i = 0; i < IPS_MAX_POST_BYTES; i++) {
+		for (j = 0; j < 45; j++) {
+			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 45)
+			/* error occurred */
+			return (0);
+
+		PostByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	if (PostByte[0] < IPS_GOOD_POST_STATUS) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x %x).\n",
+			   PostByte[0], PostByte[1]);
+
+		return (0);
+	}
+
+	for (i = 0; i < IPS_MAX_CONFIG_BYTES; i++) {
+		for (j = 0; j < 240; j++) {
+			Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+			if (Isr & IPS_BIT_GHI)
+				break;
+
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (j >= 240)
+			/* error occurred */
+			return (0);
+
+		ConfigByte[i] = readb(ha->mem_ptr + IPS_REG_ISPR);
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	for (i = 0; i < 240; i++) {
+		Cbsp = readb(ha->mem_ptr + IPS_REG_CBSP);
+
+		if ((Cbsp & IPS_BIT_OP) == 0)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240)
+		/* error occurred */
+		return (0);
+
+	/* setup CCCR */
+	writel(0x1010, ha->mem_ptr + IPS_REG_CCCR);
+
+	/* Enable busmastering */
+	writeb(IPS_BIT_EBM, ha->mem_ptr + IPS_REG_SCPR);
+
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		/* fix for anaconda64 */
+		writel(0, ha->mem_ptr + IPS_REG_NDAE);
+
+	/* Enable interrupts */
+	writeb(IPS_BIT_EI, ha->mem_ptr + IPS_REG_HISR);
+
+	/* if we get here then everything went OK */
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_init_morpheus                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize a morpheus controller                                       */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_init_morpheus(ips_ha_t * ha)
+{
+	uint32_t Post;
+	uint32_t Config;
+	uint32_t Isr;
+	uint32_t Oimr;
+	int i;
+
+	METHOD_TRACE("ips_init_morpheus", 1);
+
+	/* Wait up to 45 secs for Post */
+	for (i = 0; i < 45; i++) {
+		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		if (Isr & IPS_BIT_I960_MSG0I)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 45) {
+		/* error occurred */
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "timeout waiting for post.\n");
+
+		return (0);
+	}
+
+	Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+
+	if (Post == 0x4F00) {	/* If Flashing the Battery PIC         */
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Flashing Battery PIC, Please wait ...\n");
+
+		/* Clear the interrupt bit */
+		Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+		writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		for (i = 0; i < 120; i++) {	/*    Wait Up to 2 Min. for Completion */
+			Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
+			if (Post != 0x4F00)
+				break;
+			/* Delay for 1 Second */
+			MDELAY(IPS_ONE_SEC);
+		}
+
+		if (i >= 120) {
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "timeout waiting for Battery PIC Flash\n");
+			return (0);
+		}
+
+	}
+
+	/* Clear the interrupt bit */
+	Isr = (uint32_t) IPS_BIT_I960_MSG0I;
+	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	if (Post < (IPS_GOOD_POST_STATUS << 8)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "reset controller fails (post status %x).\n", Post);
+
+		return (0);
+	}
+
+	/* Wait up to 240 secs for config bytes */
+	for (i = 0; i < 240; i++) {
+		Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+		if (Isr & IPS_BIT_I960_MSG1I)
+			break;
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+	}
+
+	if (i >= 240) {
+		/* error occurred */
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "timeout waiting for config.\n");
+
+		return (0);
+	}
+
+	Config = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
+
+	/* Clear interrupt bit */
+	Isr = (uint32_t) IPS_BIT_I960_MSG1I;
+	writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	/* Turn on the interrupts */
+	Oimr = readl(ha->mem_ptr + IPS_REG_I960_OIMR);
+	Oimr &= ~0x8;
+	writel(Oimr, ha->mem_ptr + IPS_REG_I960_OIMR);
+
+	/* if we get here then everything went OK */
+
+	/* Since we did a RESET, an EraseStripeLock may be needed */
+	if (Post == 0xEF10) {
+		if ((Config == 0x000F) || (Config == 0x0009))
+			ha->requires_esl = 1;
+	}
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_copperhead                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_copperhead(ips_ha_t * ha)
+{
+	int reset_counter;
+
+	METHOD_TRACE("ips_reset_copperhead", 1);
+
+	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead: io addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->io_addr, ha->irq);
+
+	reset_counter = 0;
+
+	while (reset_counter < 2) {
+		reset_counter++;
+
+		outb(IPS_BIT_RST, ha->io_addr + IPS_REG_SCPR);
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+
+		outb(0, ha->io_addr + IPS_REG_SCPR);
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
+
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_copperhead_memio                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_copperhead_memio(ips_ha_t * ha)
+{
+	int reset_counter;
+
+	METHOD_TRACE("ips_reset_copperhead_memio", 1);
+
+	DEBUG_VAR(1, "(%s%d) ips_reset_copperhead_memio: mem addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
+
+	reset_counter = 0;
+
+	while (reset_counter < 2) {
+		reset_counter++;
+
+		writeb(IPS_BIT_RST, ha->mem_ptr + IPS_REG_SCPR);
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+
+		writeb(0, ha->mem_ptr + IPS_REG_SCPR);
+
+		/* Delay for 1 Second */
+		MDELAY(IPS_ONE_SEC);
+
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
+
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_reset_morpheus                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Reset the controller                                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_reset_morpheus(ips_ha_t * ha)
+{
+	int reset_counter;
+	uint8_t junk;
+
+	METHOD_TRACE("ips_reset_morpheus", 1);
+
+	DEBUG_VAR(1, "(%s%d) ips_reset_morpheus: mem addr: %x, irq: %d",
+		  ips_name, ha->host_num, ha->mem_addr, ha->irq);
+
+	reset_counter = 0;
+
+	while (reset_counter < 2) {
+		reset_counter++;
+
+		writel(0x80000000, ha->mem_ptr + IPS_REG_I960_IDR);
+
+		/* Delay for 5 Seconds */
+		MDELAY(5 * IPS_ONE_SEC);
+
+		/* Do a PCI config read to wait for adapter */
+		pci_read_config_byte(ha->pcidev, 4, &junk);
+
+		if ((*ha->func.init) (ha))
+			break;
+		else if (reset_counter >= 2) {
+
+			return (0);
+		}
+	}
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statinit                                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize the status queues on the controller                         */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_statinit(ips_ha_t * ha)
+{
+	uint32_t phys_status_start;
+
+	METHOD_TRACE("ips_statinit", 1);
+
+	ha->adapt->p_status_start = ha->adapt->status;
+	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
+	ha->adapt->p_status_tail = ha->adapt->status;
+
+	phys_status_start = ha->adapt->hw_status_start;
+	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQSR);
+	outl(cpu_to_le32(phys_status_start + IPS_STATUS_Q_SIZE),
+	     ha->io_addr + IPS_REG_SQER);
+	outl(cpu_to_le32(phys_status_start + IPS_STATUS_SIZE),
+	     ha->io_addr + IPS_REG_SQHR);
+	outl(cpu_to_le32(phys_status_start), ha->io_addr + IPS_REG_SQTR);
+
+	ha->adapt->hw_status_tail = phys_status_start;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statinit_memio                                         */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Initialize the status queues on the controller                         */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_statinit_memio(ips_ha_t * ha)
+{
+	uint32_t phys_status_start;
+
+	METHOD_TRACE("ips_statinit_memio", 1);
+
+	ha->adapt->p_status_start = ha->adapt->status;
+	ha->adapt->p_status_end = ha->adapt->status + IPS_MAX_CMDS;
+	ha->adapt->p_status_tail = ha->adapt->status;
+
+	phys_status_start = ha->adapt->hw_status_start;
+	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQSR);
+	writel(phys_status_start + IPS_STATUS_Q_SIZE,
+	       ha->mem_ptr + IPS_REG_SQER);
+	writel(phys_status_start + IPS_STATUS_SIZE, ha->mem_ptr + IPS_REG_SQHR);
+	writel(phys_status_start, ha->mem_ptr + IPS_REG_SQTR);
+
+	ha->adapt->hw_status_tail = phys_status_start;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statupd_copperhead                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an element from the status queue                                */
+/*                                                                          */
+/****************************************************************************/
+static uint32_t
+ips_statupd_copperhead(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_statupd_copperhead", 1);
+
+	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
+		ha->adapt->p_status_tail++;
+		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
+	} else {
+		ha->adapt->p_status_tail = ha->adapt->p_status_start;
+		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
+	}
+
+	outl(cpu_to_le32(ha->adapt->hw_status_tail),
+	     ha->io_addr + IPS_REG_SQTR);
+
+	return (ha->adapt->p_status_tail->value);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statupd_copperhead_memio                               */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an element from the status queue                                */
+/*                                                                          */
+/****************************************************************************/
+static uint32_t
+ips_statupd_copperhead_memio(ips_ha_t * ha)
+{
+	METHOD_TRACE("ips_statupd_copperhead_memio", 1);
+
+	if (ha->adapt->p_status_tail != ha->adapt->p_status_end) {
+		ha->adapt->p_status_tail++;
+		ha->adapt->hw_status_tail += sizeof (IPS_STATUS);
+	} else {
+		ha->adapt->p_status_tail = ha->adapt->p_status_start;
+		ha->adapt->hw_status_tail = ha->adapt->hw_status_start;
+	}
+
+	writel(ha->adapt->hw_status_tail, ha->mem_ptr + IPS_REG_SQTR);
+
+	return (ha->adapt->p_status_tail->value);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_statupd_morpheus                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Remove an element from the status queue                                */
+/*                                                                          */
+/****************************************************************************/
+static uint32_t
+ips_statupd_morpheus(ips_ha_t * ha)
+{
+	uint32_t val;
+
+	METHOD_TRACE("ips_statupd_morpheus", 1);
+
+	val = readl(ha->mem_ptr + IPS_REG_I2O_OUTMSGQ);
+
+	return (val);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_copperhead                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_copperhead(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint32_t TimeOut;
+	uint32_t val;
+
+	METHOD_TRACE("ips_issue_copperhead", 1);
+
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, KERN_NOTICE "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	TimeOut = 0;
+
+	while ((val =
+		le32_to_cpu(inl(ha->io_addr + IPS_REG_CCCR))) & IPS_BIT_SEM) {
+		udelay(1000);
+
+		if (++TimeOut >= IPS_SEM_TIMEOUT) {
+			if (!(val & IPS_BIT_START_STOP))
+				break;
+
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue val [0x%x].\n", val);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue semaphore chk timeout.\n");
+
+			return (IPS_FAILURE);
+		}		/* end if */
+	}			/* end while */
+
+	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_CCSAR);
+	outw(cpu_to_le32(IPS_BIT_START_CMD), ha->io_addr + IPS_REG_CCCR);
+
+	return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_copperhead_memio                                 */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_copperhead_memio(ips_ha_t * ha, ips_scb_t * scb)
+{
+	uint32_t TimeOut;
+	uint32_t val;
+
+	METHOD_TRACE("ips_issue_copperhead_memio", 1);
+
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	TimeOut = 0;
+
+	while ((val = readl(ha->mem_ptr + IPS_REG_CCCR)) & IPS_BIT_SEM) {
+		udelay(1000);
+
+		if (++TimeOut >= IPS_SEM_TIMEOUT) {
+			if (!(val & IPS_BIT_START_STOP))
+				break;
+
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue val [0x%x].\n", val);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "ips_issue semaphore chk timeout.\n");
+
+			return (IPS_FAILURE);
+		}		/* end if */
+	}			/* end while */
+
+	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_CCSAR);
+	writel(IPS_BIT_START_CMD, ha->mem_ptr + IPS_REG_CCCR);
+
+	return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_i2o                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_i2o(ips_ha_t * ha, ips_scb_t * scb)
+{
+
+	METHOD_TRACE("ips_issue_i2o", 1);
+
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	outl(cpu_to_le32(scb->scb_busaddr), ha->io_addr + IPS_REG_I2O_INMSGQ);
+
+	return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_issue_i2o_memio                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Send a command down to the controller                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_issue_i2o_memio(ips_ha_t * ha, ips_scb_t * scb)
+{
+
+	METHOD_TRACE("ips_issue_i2o_memio", 1);
+
+	if (scb->scsi_cmd) {
+		DEBUG_VAR(2, "(%s%d) ips_issue: cmd 0x%X id %d (%d %d %d)",
+			  ips_name,
+			  ha->host_num,
+			  scb->cdb[0],
+			  scb->cmd.basic_io.command_id,
+			  scb->bus, scb->target_id, scb->lun);
+	} else {
+		DEBUG_VAR(2, "(%s%d) ips_issue: logical cmd id %d",
+			  ips_name, ha->host_num, scb->cmd.basic_io.command_id);
+	}
+
+	writel(scb->scb_busaddr, ha->mem_ptr + IPS_REG_I2O_INMSGQ);
+
+	return (IPS_SUCCESS);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isintr_copperhead                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Test to see if an interrupt is for us                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isintr_copperhead(ips_ha_t * ha)
+{
+	uint8_t Isr;
+
+	METHOD_TRACE("ips_isintr_copperhead", 2);
+
+	Isr = inb(ha->io_addr + IPS_REG_HISR);
+
+	if (Isr == 0xFF)
+		/* ?!?! Nothing really there */
+		return (0);
+
+	if (Isr & IPS_BIT_SCE)
+		return (1);
+	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
+		/* status queue overflow or GHI */
+		/* just clear the interrupt */
+		outb(Isr, ha->io_addr + IPS_REG_HISR);
+	}
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isintr_copperhead_memio                                */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Test to see if an interrupt is for us                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isintr_copperhead_memio(ips_ha_t * ha)
+{
+	uint8_t Isr;
+
+	METHOD_TRACE("ips_isintr_memio", 2);
+
+	Isr = readb(ha->mem_ptr + IPS_REG_HISR);
+
+	if (Isr == 0xFF)
+		/* ?!?! Nothing really there */
+		return (0);
+
+	if (Isr & IPS_BIT_SCE)
+		return (1);
+	else if (Isr & (IPS_BIT_SQO | IPS_BIT_GHI)) {
+		/* status queue overflow or GHI */
+		/* just clear the interrupt */
+		writeb(Isr, ha->mem_ptr + IPS_REG_HISR);
+	}
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_isintr_morpheus                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Test to see if an interrupt is for us                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_isintr_morpheus(ips_ha_t * ha)
+{
+	uint32_t Isr;
+
+	METHOD_TRACE("ips_isintr_morpheus", 2);
+
+	Isr = readl(ha->mem_ptr + IPS_REG_I2O_HIR);
+
+	if (Isr & IPS_BIT_I2O_OPQI)
+		return (1);
+	else
+		return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_wait                                                   */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Wait for a command to complete                                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_wait(ips_ha_t * ha, int time, int intr)
+{
+	int ret;
+	int done;
+
+	METHOD_TRACE("ips_wait", 1);
+
+	ret = IPS_FAILURE;
+	done = FALSE;
+
+	time *= IPS_ONE_SEC;	/* convert seconds */
+
+	while ((time > 0) && (!done)) {
+		if (intr == IPS_INTR_ON) {
+			if (ha->waitflag == FALSE) {
+				ret = IPS_SUCCESS;
+				done = TRUE;
+				break;
+			}
+		} else if (intr == IPS_INTR_IORL) {
+			if (ha->waitflag == FALSE) {
+				/*
+				 * controller generated an interrupt to
+				 * acknowledge completion of the command
+				 * and ips_intr() has serviced the interrupt.
+				 */
+				ret = IPS_SUCCESS;
+				done = TRUE;
+				break;
+			}
+
+			/*
+			 * NOTE: we already have the io_request_lock so
+			 * even if we get an interrupt it won't get serviced
+			 * until after we finish.
+			 */
+
+			(*ha->func.intr) (ha);
+		}
+
+		/* This looks like a very evil loop, but it only does this during start-up */
+		udelay(1000);
+		time--;
+	}
+
+	return (ret);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_write_driver_status                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Write OS/Driver version to Page 5 of the nvram on the controller       */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_write_driver_status(ips_ha_t * ha, int intr)
+{
+	METHOD_TRACE("ips_write_driver_status", 1);
+
+	if (!ips_readwrite_page5(ha, FALSE, intr)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to read NVRAM page 5.\n");
+
+		return (0);
+	}
+
+	/* check to make sure the page has a valid */
+	/* signature */
+	if (le32_to_cpu(ha->nvram->signature) != IPS_NVRAM_P5_SIG) {
+		DEBUG_VAR(1,
+			  "(%s%d) NVRAM page 5 has an invalid signature: %X.",
+			  ips_name, ha->host_num, ha->nvram->signature);
+		ha->nvram->signature = IPS_NVRAM_P5_SIG;
+	}
+
+	DEBUG_VAR(2,
+		  "(%s%d) Ad Type: %d, Ad Slot: %d, BIOS: %c%c%c%c %c%c%c%c.",
+		  ips_name, ha->host_num, le16_to_cpu(ha->nvram->adapter_type),
+		  ha->nvram->adapter_slot, ha->nvram->bios_high[0],
+		  ha->nvram->bios_high[1], ha->nvram->bios_high[2],
+		  ha->nvram->bios_high[3], ha->nvram->bios_low[0],
+		  ha->nvram->bios_low[1], ha->nvram->bios_low[2],
+		  ha->nvram->bios_low[3]);
+
+	ips_get_bios_version(ha, intr);
+
+	/* change values (as needed) */
+	ha->nvram->operating_system = IPS_OS_LINUX;
+	ha->nvram->adapter_type = ha->ad_type;
+	strncpy((char *) ha->nvram->driver_high, IPS_VERSION_HIGH, 4);
+	strncpy((char *) ha->nvram->driver_low, IPS_VERSION_LOW, 4);
+	strncpy((char *) ha->nvram->bios_high, ha->bios_version, 4);
+	strncpy((char *) ha->nvram->bios_low, ha->bios_version + 4, 4);
+
+	ips_version_check(ha, intr);	/* Check BIOS/FW/Driver Versions */
+
+	/* now update the page */
+	if (!ips_readwrite_page5(ha, TRUE, intr)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "unable to write NVRAM page 5.\n");
+
+		return (0);
+	}
+
+	/* IF NVRAM Page 5 is OK, Use it for Slot Number Info Because Linux Doesn't Do Slots */
+	ha->slot_num = ha->nvram->adapter_slot;
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_read_adapter_status                                    */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Do an Inquiry command to the adapter                                   */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_read_adapter_status(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_read_adapter_status", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_ENQUIRY;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_ENQUIRY;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.basic_io.sg_count = 0;
+	scb->cmd.basic_io.lba = 0;
+	scb->cmd.basic_io.sector_count = 0;
+	scb->cmd.basic_io.log_drv = 0;
+	scb->data_len = sizeof (*ha->enq);
+	scb->cmd.basic_io.sg_addr = ha->enq_busaddr;
+
+	/* send command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_read_subsystem_parameters                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Read subsystem parameters from the adapter                             */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_read_subsystem_parameters(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_read_subsystem_parameters", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_GET_SUBSYS;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_GET_SUBSYS;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.basic_io.sg_count = 0;
+	scb->cmd.basic_io.lba = 0;
+	scb->cmd.basic_io.sector_count = 0;
+	scb->cmd.basic_io.log_drv = 0;
+	scb->data_len = sizeof (*ha->subsys);
+	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
+
+	/* send command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	memcpy(ha->subsys, ha->ioctl_data, sizeof(*ha->subsys));
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_read_config                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Read the configuration on the adapter                                  */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_read_config(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int i;
+	int ret;
+
+	METHOD_TRACE("ips_read_config", 1);
+
+	/* set defaults for initiator IDs */
+	for (i = 0; i < 4; i++)
+		ha->conf->init_id[i] = 7;
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_READ_CONF;
+
+	scb->cmd.basic_io.op_code = IPS_CMD_READ_CONF;
+	scb->cmd.basic_io.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->data_len = sizeof (*ha->conf);
+	scb->cmd.basic_io.sg_addr = ha->ioctl_busaddr;
+
+	/* send command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+
+		memset(ha->conf, 0, sizeof (IPS_CONF));
+
+		/* reset initiator IDs */
+		for (i = 0; i < 4; i++)
+			ha->conf->init_id[i] = 7;
+
+		/* Allow Completed with Errors, so JCRM can access the Adapter to fix the problems */
+		if ((scb->basic_status & IPS_GSC_STATUS_MASK) ==
+		    IPS_CMD_CMPLT_WERROR)
+			return (1);
+
+		return (0);
+	}
+	
+	memcpy(ha->conf, ha->ioctl_data, sizeof(*ha->conf));
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_readwrite_page5                                        */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Read nvram page 5 from the adapter                                     */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_readwrite_page5(ips_ha_t * ha, int write, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_readwrite_page5", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_RW_NVRAM_PAGE;
+
+	scb->cmd.nvram.op_code = IPS_CMD_RW_NVRAM_PAGE;
+	scb->cmd.nvram.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.nvram.page = 5;
+	scb->cmd.nvram.write = write;
+	scb->cmd.nvram.reserved = 0;
+	scb->cmd.nvram.reserved2 = 0;
+	scb->data_len = sizeof (*ha->nvram);
+	scb->cmd.nvram.buffer_addr = ha->ioctl_busaddr;
+	if (write)
+		memcpy(ha->ioctl_data, ha->nvram, sizeof(*ha->nvram));
+	
+	/* issue the command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1)) {
+
+		memset(ha->nvram, 0, sizeof (IPS_NVRAM_P5));
+
+		return (0);
+	}
+	if (!write)
+		memcpy(ha->nvram, ha->ioctl_data, sizeof(*ha->nvram));
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_clear_adapter                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   Clear the stripe lock tables                                           */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_clear_adapter(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+	int ret;
+
+	METHOD_TRACE("ips_clear_adapter", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_reset_timeout;
+	scb->cdb[0] = IPS_CMD_CONFIG_SYNC;
+
+	scb->cmd.config_sync.op_code = IPS_CMD_CONFIG_SYNC;
+	scb->cmd.config_sync.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.config_sync.channel = 0;
+	scb->cmd.config_sync.source_target = IPS_POCL;
+	scb->cmd.config_sync.reserved = 0;
+	scb->cmd.config_sync.reserved2 = 0;
+	scb->cmd.config_sync.reserved3 = 0;
+
+	/* issue command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_reset_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	/* send unlock stripe command */
+	ips_init_scb(ha, scb);
+
+	scb->cdb[0] = IPS_CMD_ERROR_TABLE;
+	scb->timeout = ips_reset_timeout;
+
+	scb->cmd.unlock_stripe.op_code = IPS_CMD_ERROR_TABLE;
+	scb->cmd.unlock_stripe.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.unlock_stripe.log_drv = 0;
+	scb->cmd.unlock_stripe.control = IPS_CSL;
+	scb->cmd.unlock_stripe.reserved = 0;
+	scb->cmd.unlock_stripe.reserved2 = 0;
+	scb->cmd.unlock_stripe.reserved3 = 0;
+
+	/* issue command */
+	if (((ret =
+	      ips_send_wait(ha, scb, ips_cmd_timeout, intr)) == IPS_FAILURE)
+	    || (ret == IPS_SUCCESS_IMM)
+	    || ((scb->basic_status & IPS_GSC_STATUS_MASK) > 1))
+		return (0);
+
+	return (1);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_ffdc_reset                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   FFDC: write reset info                                                 */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_ffdc_reset(ips_ha_t * ha, int intr)
+{
+	ips_scb_t *scb;
+
+	METHOD_TRACE("ips_ffdc_reset", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FFDC;
+	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
+	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.ffdc.reset_count = ha->reset_count;
+	scb->cmd.ffdc.reset_type = 0x80;
+
+	/* convert time to what the card wants */
+	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
+
+	/* issue command */
+	ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_ffdc_time                                              */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*                                                                          */
+/*   FFDC: write time info                                                  */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_ffdc_time(ips_ha_t * ha)
+{
+	ips_scb_t *scb;
+
+	METHOD_TRACE("ips_ffdc_time", 1);
+
+	DEBUG_VAR(1, "(%s%d) Sending time update.", ips_name, ha->host_num);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_FFDC;
+	scb->cmd.ffdc.op_code = IPS_CMD_FFDC;
+	scb->cmd.ffdc.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.ffdc.reset_count = 0;
+	scb->cmd.ffdc.reset_type = 0;
+
+	/* convert time to what the card wants */
+	ips_fix_ffdc_time(ha, scb, ha->last_ffdc);
+
+	/* issue command */
+	ips_send_wait(ha, scb, ips_cmd_timeout, IPS_FFDC);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_fix_ffdc_time                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Adjust time_t to what the card wants                                   */
+/*                                                                          */
+/****************************************************************************/
+static void
+ips_fix_ffdc_time(ips_ha_t * ha, ips_scb_t * scb, time_t current_time)
+{
+	long days;
+	long rem;
+	int i;
+	int year;
+	int yleap;
+	int year_lengths[2] = { IPS_DAYS_NORMAL_YEAR, IPS_DAYS_LEAP_YEAR };
+	int month_lengths[12][2] = { {31, 31},
+	{28, 29},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{31, 31},
+	{30, 30},
+	{31, 31},
+	{30, 30},
+	{31, 31}
+	};
+
+	METHOD_TRACE("ips_fix_ffdc_time", 1);
+
+	days = current_time / IPS_SECS_DAY;
+	rem = current_time % IPS_SECS_DAY;
+
+	scb->cmd.ffdc.hour = (rem / IPS_SECS_HOUR);
+	rem = rem % IPS_SECS_HOUR;
+	scb->cmd.ffdc.minute = (rem / IPS_SECS_MIN);
+	scb->cmd.ffdc.second = (rem % IPS_SECS_MIN);
+
+	year = IPS_EPOCH_YEAR;
+	while (days < 0 || days >= year_lengths[yleap = IPS_IS_LEAP_YEAR(year)]) {
+		int newy;
+
+		newy = year + (days / IPS_DAYS_NORMAL_YEAR);
+		if (days < 0)
+			--newy;
+		days -= (newy - year) * IPS_DAYS_NORMAL_YEAR +
+		    IPS_NUM_LEAP_YEARS_THROUGH(newy - 1) -
+		    IPS_NUM_LEAP_YEARS_THROUGH(year - 1);
+		year = newy;
+	}
+
+	scb->cmd.ffdc.yearH = year / 100;
+	scb->cmd.ffdc.yearL = year % 100;
+
+	for (i = 0; days >= month_lengths[i][yleap]; ++i)
+		days -= month_lengths[i][yleap];
+
+	scb->cmd.ffdc.month = i + 1;
+	scb->cmd.ffdc.day = days + 1;
+}
+
+/****************************************************************************
+ * BIOS Flash Routines                                                      *
+ ****************************************************************************/
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_erase_bios                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Erase the BIOS on the adapter                                          */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_erase_bios(ips_ha_t * ha)
+{
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_erase_bios", 1);
+
+	status = 0;
+
+	/* Clear the status register */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Setup */
+	outb(0x20, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Confirm */
+	outb(0xD0, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Status */
+	outb(0x70, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	timeout = 80000;	/* 80 seconds */
+
+	while (timeout > 0) {
+		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			udelay(25);	/* 25 us */
+		}
+
+		status = inb(ha->io_addr + IPS_REG_FLDP);
+
+		if (status & 0x80)
+			break;
+
+		MDELAY(1);
+		timeout--;
+	}
+
+	/* check for timeout */
+	if (timeout <= 0) {
+		/* timeout */
+
+		/* try to suspend the erase */
+		outb(0xB0, ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait for 10 seconds */
+		timeout = 10000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				outl(0, ha->io_addr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = inb(ha->io_addr + IPS_REG_FLDP);
+
+			if (status & 0xC0)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		return (1);
+	}
+
+	/* check for valid VPP */
+	if (status & 0x08)
+		/* VPP failure */
+		return (1);
+
+	/* check for succesful flash */
+	if (status & 0x30)
+		/* sequence error */
+		return (1);
+
+	/* Otherwise, we were successful */
+	/* clear status */
+	outb(0x50, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* enable reads */
+	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_erase_bios_memio                                       */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Erase the BIOS on the adapter                                          */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_erase_bios_memio(ips_ha_t * ha)
+{
+	int timeout;
+	uint8_t status;
+
+	METHOD_TRACE("ips_erase_bios_memio", 1);
+
+	status = 0;
+
+	/* Clear the status register */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Setup */
+	writeb(0x20, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Confirm */
+	writeb(0xD0, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* Erase Status */
+	writeb(0x70, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	timeout = 80000;	/* 80 seconds */
+
+	while (timeout > 0) {
+		if (ha->revision_id == IPS_REVID_TROMBONE64) {
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			udelay(25);	/* 25 us */
+		}
+
+		status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+		if (status & 0x80)
+			break;
+
+		MDELAY(1);
+		timeout--;
+	}
+
+	/* check for timeout */
+	if (timeout <= 0) {
+		/* timeout */
+
+		/* try to suspend the erase */
+		writeb(0xB0, ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait for 10 seconds */
+		timeout = 10000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			if (status & 0xC0)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		return (1);
+	}
+
+	/* check for valid VPP */
+	if (status & 0x08)
+		/* VPP failure */
+		return (1);
+
+	/* check for succesful flash */
+	if (status & 0x30)
+		/* sequence error */
+		return (1);
+
+	/* Otherwise, we were successful */
+	/* clear status */
+	writeb(0x50, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	/* enable reads */
+	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_program_bios                                           */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Program the BIOS on the adapter                                        */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_program_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		 uint32_t offset)
+{
+	int i;
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_program_bios", 1);
+
+	status = 0;
+
+	for (i = 0; i < buffersize; i++) {
+		/* write a byte */
+		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		outb(0x40, ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		outb(buffer[i], ha->io_addr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait up to one second */
+		timeout = 1000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				outl(0, ha->io_addr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = inb(ha->io_addr + IPS_REG_FLDP);
+
+			if (status & 0x80)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		if (timeout == 0) {
+			/* timeout error */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+
+		/* check the status */
+		if (status & 0x18) {
+			/* programming error */
+			outl(0, ha->io_addr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+	}			/* end for */
+
+	/* Enable reading */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	outb(0xFF, ha->io_addr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_program_bios_memio                                     */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Program the BIOS on the adapter                                        */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_program_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		       uint32_t offset)
+{
+	int i;
+	int timeout;
+	uint8_t status = 0;
+
+	METHOD_TRACE("ips_program_bios_memio", 1);
+
+	status = 0;
+
+	for (i = 0; i < buffersize; i++) {
+		/* write a byte */
+		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		writeb(0x40, ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		writeb(buffer[i], ha->mem_ptr + IPS_REG_FLDP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		/* wait up to one second */
+		timeout = 1000;
+		while (timeout > 0) {
+			if (ha->revision_id == IPS_REVID_TROMBONE64) {
+				writel(0, ha->mem_ptr + IPS_REG_FLAP);
+				udelay(25);	/* 25 us */
+			}
+
+			status = readb(ha->mem_ptr + IPS_REG_FLDP);
+
+			if (status & 0x80)
+				break;
+
+			MDELAY(1);
+			timeout--;
+		}
+
+		if (timeout == 0) {
+			/* timeout error */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+
+		/* check the status */
+		if (status & 0x18) {
+			/* programming error */
+			writel(0, ha->mem_ptr + IPS_REG_FLAP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+			if (ha->revision_id == IPS_REVID_TROMBONE64)
+				udelay(25);	/* 25 us */
+
+			return (1);
+		}
+	}			/* end for */
+
+	/* Enable reading */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	writeb(0xFF, ha->mem_ptr + IPS_REG_FLDP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_verify_bios                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Verify the BIOS on the adapter                                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_verify_bios(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		uint32_t offset)
+{
+	uint8_t checksum;
+	int i;
+
+	METHOD_TRACE("ips_verify_bios", 1);
+
+	/* test 1st byte */
+	outl(0, ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	if (inb(ha->io_addr + IPS_REG_FLDP) != 0x55)
+		return (1);
+
+	outl(cpu_to_le32(1), ha->io_addr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+	if (inb(ha->io_addr + IPS_REG_FLDP) != 0xAA)
+		return (1);
+
+	checksum = 0xff;
+	for (i = 2; i < buffersize; i++) {
+
+		outl(cpu_to_le32(i + offset), ha->io_addr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		checksum = (uint8_t) checksum + inb(ha->io_addr + IPS_REG_FLDP);
+	}
+
+	if (checksum != 0)
+		/* failure */
+		return (1);
+	else
+		/* success */
+		return (0);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_verify_bios_memio                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   Verify the BIOS on the adapter                                         */
+/*                                                                          */
+/****************************************************************************/
+static int
+ips_verify_bios_memio(ips_ha_t * ha, char *buffer, uint32_t buffersize,
+		      uint32_t offset)
+{
+	uint8_t checksum;
+	int i;
+
+	METHOD_TRACE("ips_verify_bios_memio", 1);
+
+	/* test 1st byte */
+	writel(0, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+
+	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0x55)
+		return (1);
+
+	writel(1, ha->mem_ptr + IPS_REG_FLAP);
+	if (ha->revision_id == IPS_REVID_TROMBONE64)
+		udelay(25);	/* 25 us */
+	if (readb(ha->mem_ptr + IPS_REG_FLDP) != 0xAA)
+		return (1);
+
+	checksum = 0xff;
+	for (i = 2; i < buffersize; i++) {
+
+		writel(i + offset, ha->mem_ptr + IPS_REG_FLAP);
+		if (ha->revision_id == IPS_REVID_TROMBONE64)
+			udelay(25);	/* 25 us */
+
+		checksum =
+		    (uint8_t) checksum + readb(ha->mem_ptr + IPS_REG_FLDP);
+	}
+
+	if (checksum != 0)
+		/* failure */
+		return (1);
+	else
+		/* success */
+		return (0);
+}
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_version_check                                         */
+/*                                                                           */
+/*   Dependencies:                                                           */
+/*     Assumes that ips_read_adapter_status() is called first filling in     */
+/*     the data for SubSystem Parameters.                                    */
+/*     Called from ips_write_driver_status() so it also assumes NVRAM Page 5 */
+/*     Data is available.                                                    */
+/*                                                                           */
+/*---------------------------------------------------------------------------*/
+static void
+ips_version_check(ips_ha_t * ha, int intr)
+{
+	IPS_VERSION_DATA *VersionInfo;
+	uint8_t FirmwareVersion[IPS_COMPAT_ID_LENGTH + 1];
+	uint8_t BiosVersion[IPS_COMPAT_ID_LENGTH + 1];
+	int MatchError;
+	int rc;
+	char BiosString[10];
+	char FirmwareString[10];
+
+	METHOD_TRACE("ips_version_check", 1);
+
+	VersionInfo = ( IPS_VERSION_DATA * ) ha->ioctl_data;
+
+	memset(FirmwareVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
+	memset(BiosVersion, 0, IPS_COMPAT_ID_LENGTH + 1);
+
+	/* Get the Compatible BIOS Version from NVRAM Page 5 */
+	memcpy(BiosVersion, ha->nvram->BiosCompatibilityID,
+	       IPS_COMPAT_ID_LENGTH);
+
+	rc = IPS_FAILURE;
+	if (ha->subsys->param[4] & IPS_GET_VERSION_SUPPORT) {	/* If Versioning is Supported */
+		/* Get the Version Info with a Get Version Command */
+		memset( VersionInfo, 0, sizeof (IPS_VERSION_DATA));
+		rc = ips_get_version_info(ha, ha->ioctl_busaddr, intr);
+		if (rc == IPS_SUCCESS)
+			memcpy(FirmwareVersion, VersionInfo->compatibilityId,
+			       IPS_COMPAT_ID_LENGTH);
+	}
+
+	if (rc != IPS_SUCCESS) {	/* If Data Not Obtainable from a GetVersion Command */
+		/* Get the Firmware Version from Enquiry Data */
+		memcpy(FirmwareVersion, ha->enq->CodeBlkVersion,
+		       IPS_COMPAT_ID_LENGTH);
+	}
+
+	/* printk(KERN_WARNING "Adapter's BIOS Version  = %s\n", BiosVersion);          */
+	/* printk(KERN_WARNING "BIOS Compatible Version = %s\n", IPS_COMPAT_BIOS);      */
+	/* printk(KERN_WARNING "Adapter's Firmware Version  = %s\n", FirmwareVersion);  */
+	/* printk(KERN_WARNING "Firmware Compatible Version = %s \n", Compatable[ ha->nvram->adapter_type ]); */
+
+	MatchError = 0;
+
+	if (strncmp
+	    (FirmwareVersion, Compatable[ha->nvram->adapter_type],
+	     IPS_COMPAT_ID_LENGTH) != 0)
+		MatchError = 1;
+
+	if (strncmp(BiosVersion, IPS_COMPAT_BIOS, IPS_COMPAT_ID_LENGTH) != 0)
+		MatchError = 1;
+
+	ha->nvram->versioning = 1;	/* Indicate the Driver Supports Versioning */
+
+	if (MatchError) {
+		ha->nvram->version_mismatch = 1;
+		if (ips_cd_boot == 0) {
+			strncpy(&BiosString[0], ha->nvram->bios_high, 4);
+			strncpy(&BiosString[4], ha->nvram->bios_low, 4);
+			BiosString[8] = 0;
+
+			strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
+			FirmwareString[8] = 0;
+
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Warning ! ! ! ServeRAID Version Mismatch\n");
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
+				   BiosString, FirmwareString, IPS_VERSION_HIGH,
+				   IPS_VERSION_LOW);
+			IPS_PRINTK(KERN_WARNING, ha->pcidev,
+				   "These levels should match to avoid possible compatibility problems.\n");
+		}
+	} else {
+		ha->nvram->version_mismatch = 0;
+	}
+
+	return;
+}
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_get_version_info                                      */
+/*                                                                           */
+/*   Routine Description:                                                    */
+/*     Issue an internal GETVERSION Command                                  */
+/*                                                                           */
+/*   Return Value:                                                           */
+/*     0 if Successful, else non-zero                                        */
+/*---------------------------------------------------------------------------*/
+static int
+ips_get_version_info(ips_ha_t * ha, dma_addr_t Buffer, int intr)
+{
+	ips_scb_t *scb;
+	int rc;
+
+	METHOD_TRACE("ips_get_version_info", 1);
+
+	scb = &ha->scbs[ha->max_cmds - 1];
+
+	ips_init_scb(ha, scb);
+
+	scb->timeout = ips_cmd_timeout;
+	scb->cdb[0] = IPS_CMD_GET_VERSION_INFO;
+	scb->cmd.version_info.op_code = IPS_CMD_GET_VERSION_INFO;
+	scb->cmd.version_info.command_id = IPS_COMMAND_ID(ha, scb);
+	scb->cmd.version_info.reserved = 0;
+	scb->cmd.version_info.count = sizeof (IPS_VERSION_DATA);
+	scb->cmd.version_info.reserved2 = 0;
+	scb->data_len = sizeof (IPS_VERSION_DATA);
+	scb->data_busaddr = Buffer;
+	scb->cmd.version_info.buffer_addr = Buffer;
+	scb->flags = 0;
+
+	/* issue command */
+	rc = ips_send_wait(ha, scb, ips_cmd_timeout, intr);
+	return (rc);
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_abort_init                                             */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   cleanup routine for a failed adapter initialization                    */
+/****************************************************************************/
+static int
+ips_abort_init(ips_ha_t * ha, int index)
+{
+	ha->active = 0;
+	ips_free(ha);
+	ips_ha[index] = NULL;
+	ips_sh[index] = NULL;
+	return -1;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_shift_controllers                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   helper function for ordering adapters                                  */
+/****************************************************************************/
+static void
+ips_shift_controllers(int lowindex, int highindex)
+{
+	ips_ha_t *ha_sav = ips_ha[highindex];
+	struct Scsi_Host *sh_sav = ips_sh[highindex];
+	int i;
+
+	for (i = highindex; i > lowindex; i--) {
+		ips_ha[i] = ips_ha[i - 1];
+		ips_sh[i] = ips_sh[i - 1];
+		ips_ha[i]->host_num = i;
+	}
+	ha_sav->host_num = lowindex;
+	ips_ha[lowindex] = ha_sav;
+	ips_sh[lowindex] = sh_sav;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_order_controllers                                      */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   place controllers is the "proper" boot order                           */
+/****************************************************************************/
+static void
+ips_order_controllers(void)
+{
+	int i, j, tmp, position = 0;
+	IPS_NVRAM_P5 *nvram;
+	if (!ips_ha[0])
+		return;
+	nvram = ips_ha[0]->nvram;
+
+	if (nvram->adapter_order[0]) {
+		for (i = 1; i <= nvram->adapter_order[0]; i++) {
+			for (j = position; j < ips_num_controllers; j++) {
+				switch (ips_ha[j]->ad_type) {
+				case IPS_ADTYPE_SERVERAID6M:
+				case IPS_ADTYPE_SERVERAID7M:
+					if (nvram->adapter_order[i] == 'M') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID4L:
+				case IPS_ADTYPE_SERVERAID4M:
+				case IPS_ADTYPE_SERVERAID4MX:
+				case IPS_ADTYPE_SERVERAID4LX:
+					if (nvram->adapter_order[i] == 'N') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID6I:
+				case IPS_ADTYPE_SERVERAID5I2:
+				case IPS_ADTYPE_SERVERAID5I1:
+				case IPS_ADTYPE_SERVERAID7k:
+					if (nvram->adapter_order[i] == 'S') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				case IPS_ADTYPE_SERVERAID:
+				case IPS_ADTYPE_SERVERAID2:
+				case IPS_ADTYPE_NAVAJO:
+				case IPS_ADTYPE_KIOWA:
+				case IPS_ADTYPE_SERVERAID3L:
+				case IPS_ADTYPE_SERVERAID3:
+				case IPS_ADTYPE_SERVERAID4H:
+					if (nvram->adapter_order[i] == 'A') {
+						ips_shift_controllers(position,
+								      j);
+						position++;
+					}
+					break;
+				default:
+					break;
+				}
+			}
+		}
+		/* if adapter_order[0], then ordering is complete */
+		return;
+	}
+	/* old bios, use older ordering */
+	tmp = 0;
+	for (i = position; i < ips_num_controllers; i++) {
+		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I2 ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID5I1) {
+			ips_shift_controllers(position, i);
+			position++;
+			tmp = 1;
+		}
+	}
+	/* if there were no 5I cards, then don't do any extra ordering */
+	if (!tmp)
+		return;
+	for (i = position; i < ips_num_controllers; i++) {
+		if (ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4L ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4M ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4LX ||
+		    ips_ha[i]->ad_type == IPS_ADTYPE_SERVERAID4MX) {
+			ips_shift_controllers(position, i);
+			position++;
+		}
+	}
+
+	return;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_register_scsi                                          */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   perform any registration and setup with the scsi layer                 */
+/****************************************************************************/
+static int
+ips_register_scsi(int index)
+{
+	struct Scsi_Host *sh;
+	ips_ha_t *ha, *oldha = ips_ha[index];
+	sh = scsi_host_alloc(&ips_driver_template, sizeof (ips_ha_t));
+	if (!sh) {
+		IPS_PRINTK(KERN_WARNING, oldha->pcidev,
+			   "Unable to register controller with SCSI subsystem\n");
+		return -1;
+	}
+	ha = IPS_HA(sh);
+	memcpy(ha, oldha, sizeof (ips_ha_t));
+	free_irq(oldha->irq, oldha);
+	/* Install the interrupt handler with the new ha */
+	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to install interrupt handler\n");
+		scsi_host_put(sh);
+		return -1;
+	}
+
+	kfree(oldha);
+	ips_sh[index] = sh;
+	ips_ha[index] = ha;
+	IPS_SCSI_SET_DEVICE(sh, ha);
+
+	/* Store away needed values for later use */
+	sh->io_port = ha->io_addr;
+	sh->n_io_port = ha->io_addr ? 255 : 0;
+	sh->unique_id = (ha->io_addr) ? ha->io_addr : ha->mem_addr;
+	sh->irq = ha->irq;
+	sh->sg_tablesize = sh->hostt->sg_tablesize;
+	sh->can_queue = sh->hostt->can_queue;
+	sh->cmd_per_lun = sh->hostt->cmd_per_lun;
+	sh->unchecked_isa_dma = sh->hostt->unchecked_isa_dma;
+	sh->use_clustering = sh->hostt->use_clustering;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
+	sh->max_sectors = 128;
+#endif
+
+	sh->max_id = ha->ntargets;
+	sh->max_lun = ha->nlun;
+	sh->max_channel = ha->nbus - 1;
+	sh->can_queue = ha->max_cmds - 1;
+
+	IPS_ADD_HOST(sh, NULL);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_remove_device                                         */
+/*                                                                           */
+/*   Routine Description:                                                    */
+/*     Remove one Adapter ( Hot Plugging )                                   */
+/*---------------------------------------------------------------------------*/
+static void __devexit
+ips_remove_device(struct pci_dev *pci_dev)
+{
+	int i;
+	struct Scsi_Host *sh;
+	ips_ha_t *ha;
+
+	for (i = 0; i < IPS_MAX_ADAPTERS; i++) {
+		ha = ips_ha[i];
+		if (ha) {
+			if ((pci_dev->bus->number == ha->pcidev->bus->number) &&
+			    (pci_dev->devfn == ha->pcidev->devfn)) {
+				sh = ips_sh[i];
+				ips_release(sh);
+			}
+		}
+	}
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_module_init                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   function called on module load                                         */
+/****************************************************************************/
+static int __init
+ips_module_init(void)
+{
+	if (pci_module_init(&ips_pci_driver) < 0)
+		return -ENODEV;
+	ips_driver_template.module = THIS_MODULE;
+	ips_order_controllers();
+	if (IPS_REGISTER_HOSTS(&ips_driver_template)) {
+		pci_unregister_driver(&ips_pci_driver);
+		return -ENODEV;
+	}
+	register_reboot_notifier(&ips_notifier);
+	return 0;
+}
+
+/****************************************************************************/
+/*                                                                          */
+/* Routine Name: ips_module_exit                                            */
+/*                                                                          */
+/* Routine Description:                                                     */
+/*   function called on module unload                                       */
+/****************************************************************************/
+static void __exit
+ips_module_exit(void)
+{
+	IPS_UNREGISTER_HOSTS(&ips_driver_template);
+	pci_unregister_driver(&ips_pci_driver);
+	unregister_reboot_notifier(&ips_notifier);
+}
+
+module_init(ips_module_init);
+module_exit(ips_module_exit);
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_insert_device                                         */
+/*                                                                           */
+/*   Routine Description:                                                    */
+/*     Add One Adapter ( Hot Plug )                                          */
+/*                                                                           */
+/*   Return Value:                                                           */
+/*     0 if Successful, else non-zero                                        */
+/*---------------------------------------------------------------------------*/
+static int __devinit
+ips_insert_device(struct pci_dev *pci_dev, const struct pci_device_id *ent)
+{
+	int index;
+	int rc;
+
+	METHOD_TRACE("ips_insert_device", 1);
+	if (pci_enable_device(pci_dev))
+		return -1;
+
+	rc = ips_init_phase1(pci_dev, &index);
+	if (rc == SUCCESS)
+		rc = ips_init_phase2(index);
+
+	if (ips_hotplug)
+		if (ips_register_scsi(index)) {
+			ips_free(ips_ha[index]);
+			rc = -1;
+		}
+
+	if (rc == SUCCESS)
+		ips_num_controllers++;
+
+	ips_next_controller = ips_num_controllers;
+	return rc;
+}
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_init_phase1                                           */
+/*                                                                           */
+/*   Routine Description:                                                    */
+/*     Adapter Initialization                                                */
+/*                                                                           */
+/*   Return Value:                                                           */
+/*     0 if Successful, else non-zero                                        */
+/*---------------------------------------------------------------------------*/
+static int
+ips_init_phase1(struct pci_dev *pci_dev, int *indexPtr)
+{
+	ips_ha_t *ha;
+	uint32_t io_addr;
+	uint32_t mem_addr;
+	uint32_t io_len;
+	uint32_t mem_len;
+	uint8_t revision_id;
+	uint8_t bus;
+	uint8_t func;
+	uint8_t irq;
+	uint16_t subdevice_id;
+	int j;
+	int index;
+	dma_addr_t dma_address;
+	char __iomem *ioremap_ptr;
+	char __iomem *mem_ptr;
+	uint32_t IsDead;
+
+	METHOD_TRACE("ips_init_phase1", 1);
+	index = IPS_MAX_ADAPTERS;
+	for (j = 0; j < IPS_MAX_ADAPTERS; j++) {
+		if (ips_ha[j] == 0) {
+			index = j;
+			break;
+		}
+	}
+
+	if (index >= IPS_MAX_ADAPTERS)
+		return -1;
+
+	/* stuff that we get in dev */
+	irq = pci_dev->irq;
+	bus = pci_dev->bus->number;
+	func = pci_dev->devfn;
+
+	/* Init MEM/IO addresses to 0 */
+	mem_addr = 0;
+	io_addr = 0;
+	mem_len = 0;
+	io_len = 0;
+
+	for (j = 0; j < 2; j++) {
+		if (!pci_resource_start(pci_dev, j))
+			break;
+
+		if (pci_resource_flags(pci_dev, j) & IORESOURCE_IO) {
+			io_addr = pci_resource_start(pci_dev, j);
+			io_len = pci_resource_len(pci_dev, j);
+		} else {
+			mem_addr = pci_resource_start(pci_dev, j);
+			mem_len = pci_resource_len(pci_dev, j);
+		}
+	}
+
+	/* setup memory mapped area (if applicable) */
+	if (mem_addr) {
+		uint32_t base;
+		uint32_t offs;
+
+		if (!request_mem_region(mem_addr, mem_len, "ips")) {
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "Couldn't allocate IO Memory space %x len %d.\n",
+				   mem_addr, mem_len);
+			return -1;
+		}
+
+		base = mem_addr & PAGE_MASK;
+		offs = mem_addr - base;
+		ioremap_ptr = ioremap(base, PAGE_SIZE);
+		mem_ptr = ioremap_ptr + offs;
+	} else {
+		ioremap_ptr = NULL;
+		mem_ptr = NULL;
+	}
+
+	/* setup I/O mapped area (if applicable) */
+	if (io_addr) {
+		if (!request_region(io_addr, io_len, "ips")) {
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "Couldn't allocate IO space %x len %d.\n",
+				   io_addr, io_len);
+			return -1;
+		}
+	}
+
+	/* get the revision ID */
+	if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
+		IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
+		return -1;
+	}
+
+	subdevice_id = pci_dev->subsystem_device;
+
+	/* found a controller */
+	ha = kmalloc(sizeof (ips_ha_t), GFP_KERNEL);
+	if (ha == NULL) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate temporary ha struct\n");
+		return -1;
+	}
+
+	memset(ha, 0, sizeof (ips_ha_t));
+
+	ips_sh[index] = NULL;
+	ips_ha[index] = ha;
+	ha->active = 1;
+
+	/* Store info in HA structure */
+	ha->irq = irq;
+	ha->io_addr = io_addr;
+	ha->io_len = io_len;
+	ha->mem_addr = mem_addr;
+	ha->mem_len = mem_len;
+	ha->mem_ptr = mem_ptr;
+	ha->ioremap_ptr = ioremap_ptr;
+	ha->host_num = (uint32_t) index;
+	ha->revision_id = revision_id;
+	ha->slot_num = PCI_SLOT(pci_dev->devfn);
+	ha->device_id = pci_dev->device;
+	ha->subdevice_id = subdevice_id;
+	ha->pcidev = pci_dev;
+
+	/*
+	 * Set the pci_dev's dma_mask.  Not all adapters support 64bit
+	 * addressing so don't enable it if the adapter can't support
+	 * it!  Also, don't use 64bit addressing if dma addresses
+	 * are guaranteed to be < 4G.
+	 */
+	if (IPS_ENABLE_DMA64 && IPS_HAS_ENH_SGLIST(ha) &&
+	    !pci_set_dma_mask(ha->pcidev, 0xffffffffffffffffULL)) {
+		(ha)->flags |= IPS_HA_ENH_SG;
+	} else {
+		if (pci_set_dma_mask(ha->pcidev, 0xffffffffULL) != 0) {
+			printk(KERN_WARNING "Unable to set DMA Mask\n");
+			return ips_abort_init(ha, index);
+		}
+	}
+	if(ips_cd_boot && !ips_FlashData){
+		ips_FlashData = pci_alloc_consistent(pci_dev, PAGE_SIZE << 7,
+						     &ips_flashbusaddr);
+	}
+
+	ha->enq = pci_alloc_consistent(pci_dev, sizeof (IPS_ENQ),
+				       &ha->enq_busaddr);
+	if (!ha->enq) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host inquiry structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->adapt = pci_alloc_consistent(pci_dev, sizeof (IPS_ADAPTER) +
+					 sizeof (IPS_IO_CMD), &dma_address);
+	if (!ha->adapt) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host adapt & dummy structures\n");
+		return ips_abort_init(ha, index);
+	}
+	ha->adapt->hw_status_start = dma_address;
+	ha->dummy = (void *) (ha->adapt + 1);
+
+
+
+	ha->logical_drive_info = pci_alloc_consistent(pci_dev, sizeof (IPS_LD_INFO), &dma_address);
+	if (!ha->logical_drive_info) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate logical drive info structure\n");
+		return ips_abort_init(ha, index);
+	}
+	ha->logical_drive_info_dma_addr = dma_address;
+
+
+	ha->conf = kmalloc(sizeof (IPS_CONF), GFP_KERNEL);
+
+	if (!ha->conf) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host conf structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->nvram = kmalloc(sizeof (IPS_NVRAM_P5), GFP_KERNEL);
+
+	if (!ha->nvram) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host NVRAM structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	ha->subsys = kmalloc(sizeof (IPS_SUBSYS), GFP_KERNEL);
+
+	if (!ha->subsys) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate host subsystem structure\n");
+		return ips_abort_init(ha, index);
+	}
+
+	/* the ioctl buffer is now used during adapter initialization, so its
+	 * successful allocation is now required */
+	if (ips_ioctlsize < PAGE_SIZE)
+		ips_ioctlsize = PAGE_SIZE;
+
+	ha->ioctl_data = pci_alloc_consistent(pci_dev, ips_ioctlsize,
+					      &ha->ioctl_busaddr);
+	ha->ioctl_len = ips_ioctlsize;
+	if (!ha->ioctl_data) {
+		IPS_PRINTK(KERN_WARNING, pci_dev,
+			   "Unable to allocate IOCTL data\n");
+		return ips_abort_init(ha, index);
+	}
+
+	/*
+	 * Setup Functions
+	 */
+	ips_setup_funclist(ha);
+
+	if ((IPS_IS_MORPHEUS(ha)) || (IPS_IS_MARCO(ha))) {
+		/* If Morpheus appears dead, reset it */
+		IsDead = readl(ha->mem_ptr + IPS_REG_I960_MSG1);
+		if (IsDead == 0xDEADBEEF) {
+			ips_reset_morpheus(ha);
+		}
+	}
+
+	/*
+	 * Initialize the card if it isn't already
+	 */
+
+	if (!(*ha->func.isinit) (ha)) {
+		if (!(*ha->func.init) (ha)) {
+			/*
+			 * Initialization failed
+			 */
+			IPS_PRINTK(KERN_WARNING, pci_dev,
+				   "Unable to initialize controller\n");
+			return ips_abort_init(ha, index);
+		}
+	}
+
+	*indexPtr = index;
+	return SUCCESS;
+}
+
+/*---------------------------------------------------------------------------*/
+/*   Routine Name: ips_init_phase2                                           */
+/*                                                                           */
+/*   Routine Description:                                                    */
+/*     Adapter Initialization Phase 2                                        */
+/*                                                                           */
+/*   Return Value:                                                           */
+/*     0 if Successful, else non-zero                                        */
+/*---------------------------------------------------------------------------*/
+static int
+ips_init_phase2(int index)
+{
+	ips_ha_t *ha;
+
+	ha = ips_ha[index];
+
+	METHOD_TRACE("ips_init_phase2", 1);
+	if (!ha->active) {
+		ips_ha[index] = NULL;
+		return -1;
+	}
+
+	/* Install the interrupt handler */
+	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to install interrupt handler\n");
+		return ips_abort_init(ha, index);
+	}
+
+	/*
+	 * Allocate a temporary SCB for initialization
+	 */
+	ha->max_cmds = 1;
+	if (!ips_allocatescbs(ha)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to allocate a CCB\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
+
+	if (!ips_hainit(ha)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to initialize controller\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
+	/* Free the temporary SCB */
+	ips_deallocatescbs(ha, 1);
+
+	/* allocate CCBs */
+	if (!ips_allocatescbs(ha)) {
+		IPS_PRINTK(KERN_WARNING, ha->pcidev,
+			   "Unable to allocate CCBs\n");
+		free_irq(ha->irq, ha);
+		return ips_abort_init(ha, index);
+	}
+
+	return SUCCESS;
+}
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,9)
+MODULE_LICENSE("GPL");
+#endif
+
+MODULE_DESCRIPTION("IBM ServeRAID Adapter Driver " IPS_VER_STRING);
+
+#ifdef MODULE_VERSION
+MODULE_VERSION(IPS_VER_STRING);
+#endif
+
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/ips.h b/drivers/scsi/ips.h
new file mode 100644
index 0000000..906a761
--- /dev/null
+++ b/drivers/scsi/ips.h
@@ -0,0 +1,1297 @@
+/*****************************************************************************/
+/* ips.h -- driver for the Adaptec / IBM ServeRAID controller                */
+/*                                                                           */
+/* Written By: Keith Mitchell, IBM Corporation                               */
+/*             Jack Hammer, Adaptec, Inc.                                    */
+/*             David Jeffery, Adaptec, Inc.                                  */
+/*                                                                           */
+/* Copyright (C) 1999 IBM Corporation                                        */
+/* Copyright (C) 2003 Adaptec, Inc.                                          */ 
+/*                                                                           */
+/* This program is free software; you can redistribute it and/or modify      */
+/* it under the terms of the GNU General Public License as published by      */
+/* the Free Software Foundation; either version 2 of the License, or         */
+/* (at your option) any later version.                                       */
+/*                                                                           */
+/* This program is distributed in the hope that it will be useful,           */
+/* but WITHOUT ANY WARRANTY; without even the implied warranty of            */
+/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             */
+/* GNU General Public License for more details.                              */
+/*                                                                           */
+/* NO WARRANTY                                                               */
+/* THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        */
+/* CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      */
+/* LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      */
+/* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    */
+/* solely responsible for determining the appropriateness of using and       */
+/* distributing the Program and assumes all risks associated with its        */
+/* exercise of rights under this Agreement, including but not limited to     */
+/* the risks and costs of program errors, damage to or loss of data,         */
+/* programs or equipment, and unavailability or interruption of operations.  */
+/*                                                                           */
+/* DISCLAIMER OF LIABILITY                                                   */
+/* NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   */
+/* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
+/* DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   */
+/* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     */
+/* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    */
+/* USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  */
+/* HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             */
+/*                                                                           */
+/* You should have received a copy of the GNU General Public License         */
+/* along with this program; if not, write to the Free Software               */
+/* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
+/*                                                                           */
+/* Bugs/Comments/Suggestions should be mailed to:                            */
+/*      ipslinux@adaptec.com                                                 */
+/*                                                                           */
+/*****************************************************************************/
+
+#ifndef _IPS_H_
+   #define _IPS_H_
+
+   #include <asm/uaccess.h>
+   #include <asm/io.h>
+
+   /*
+    * Some handy macros
+    */
+   #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
+      #define IPS_HIGHIO
+   #endif
+
+   #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
+   #define IPS_COMMAND_ID(ha, scb)     (int) (scb - ha->scbs)
+   #define IPS_IS_TROMBONE(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->revision_id >= IPS_REVID_TROMBONE32) && \
+                                         (ha->revision_id <= IPS_REVID_TROMBONE64)) ? 1 : 0)
+   #define IPS_IS_CLARINET(ha)         (((ha->device_id == IPS_DEVICEID_COPPERHEAD) && \
+                                         (ha->revision_id >= IPS_REVID_CLARINETP1) && \
+                                         (ha->revision_id <= IPS_REVID_CLARINETP3)) ? 1 : 0)
+   #define IPS_IS_MORPHEUS(ha)         (ha->device_id == IPS_DEVICEID_MORPHEUS)
+   #define IPS_IS_MARCO(ha)            (ha->device_id == IPS_DEVICEID_MARCO)
+   #define IPS_USE_I2O_DELIVER(ha)     ((IPS_IS_MORPHEUS(ha) || \
+                                         (IPS_IS_TROMBONE(ha) && \
+                                          (ips_force_i2o))) ? 1 : 0)
+   #define IPS_USE_MEMIO(ha)           ((IPS_IS_MORPHEUS(ha) || \
+                                         ((IPS_IS_TROMBONE(ha) || IPS_IS_CLARINET(ha)) && \
+                                          (ips_force_memio))) ? 1 : 0)
+
+    #define IPS_HAS_ENH_SGLIST(ha)    (IPS_IS_MORPHEUS(ha) || IPS_IS_MARCO(ha))
+    #define IPS_USE_ENH_SGLIST(ha)    ((ha)->flags & IPS_HA_ENH_SG)
+    #define IPS_SGLIST_SIZE(ha)       (IPS_USE_ENH_SGLIST(ha) ? \
+                                         sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST))
+
+   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
+      #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
+      #define scsi_set_pci_device(sh,dev) (0)
+   #endif
+
+   #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+   
+      #ifndef irqreturn_t
+         typedef void irqreturn_t;
+      #endif 
+      
+      #define IRQ_NONE
+      #define IRQ_HANDLED
+      #define IRQ_RETVAL(x)
+      #define IPS_REGISTER_HOSTS(SHT)      scsi_register_module(MODULE_SCSI_HA,SHT)
+      #define IPS_UNREGISTER_HOSTS(SHT)    scsi_unregister_module(MODULE_SCSI_HA,SHT)
+      #define IPS_ADD_HOST(shost,device)
+      #define IPS_REMOVE_HOST(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_pci_device(sh, (ha)->pcidev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            printk(level "%s %s:" format , "ips" ,     \
+            (pcidev)->slot_name , ## arg)
+      #define scsi_host_alloc(sh,size)         scsi_register(sh,size)
+      #define scsi_host_put(sh)             scsi_unregister(sh)
+   #else
+      #define IPS_REGISTER_HOSTS(SHT)      (!ips_detect(SHT))
+      #define IPS_UNREGISTER_HOSTS(SHT)
+      #define IPS_ADD_HOST(shost,device)   do { scsi_add_host(shost,device); scsi_scan_host(shost); } while (0)
+      #define IPS_REMOVE_HOST(shost)       scsi_remove_host(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_device(sh, &(ha)->pcidev->dev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            dev_printk(level , &((pcidev)->dev) , format , ## arg)
+   #endif
+
+   #ifndef MDELAY
+      #define MDELAY mdelay
+   #endif
+
+   #ifndef min
+      #define min(x,y) ((x) < (y) ? x : y)
+   #endif
+
+   #define pci_dma_hi32(a)         ((a >> 16) >> 16)
+   #define pci_dma_lo32(a)         (a & 0xffffffff)
+
+   #if (BITS_PER_LONG > 32) || (defined CONFIG_HIGHMEM64G && defined IPS_HIGHIO)
+      #define IPS_ENABLE_DMA64        (1)
+   #else
+      #define IPS_ENABLE_DMA64        (0)
+   #endif
+
+   /*
+    * Adapter address map equates
+    */
+   #define IPS_REG_HISR                 0x08    /* Host Interrupt Status Reg   */
+   #define IPS_REG_CCSAR                0x10    /* Cmd Channel System Addr Reg */
+   #define IPS_REG_CCCR                 0x14    /* Cmd Channel Control Reg     */
+   #define IPS_REG_SQHR                 0x20    /* Status Q Head Reg           */
+   #define IPS_REG_SQTR                 0x24    /* Status Q Tail Reg           */
+   #define IPS_REG_SQER                 0x28    /* Status Q End Reg            */
+   #define IPS_REG_SQSR                 0x2C    /* Status Q Start Reg          */
+   #define IPS_REG_SCPR                 0x05    /* Subsystem control port reg  */
+   #define IPS_REG_ISPR                 0x06    /* interrupt status port reg   */
+   #define IPS_REG_CBSP                 0x07    /* CBSP register               */
+   #define IPS_REG_FLAP                 0x18    /* Flash address port          */
+   #define IPS_REG_FLDP                 0x1C    /* Flash data port             */
+   #define IPS_REG_NDAE                 0x38    /* Anaconda 64 NDAE Register   */
+   #define IPS_REG_I2O_INMSGQ           0x40    /* I2O Inbound Message Queue   */
+   #define IPS_REG_I2O_OUTMSGQ          0x44    /* I2O Outbound Message Queue  */
+   #define IPS_REG_I2O_HIR              0x30    /* I2O Interrupt Status        */
+   #define IPS_REG_I960_IDR             0x20    /* i960 Inbound Doorbell       */
+   #define IPS_REG_I960_MSG0            0x18    /* i960 Outbound Reg 0         */
+   #define IPS_REG_I960_MSG1            0x1C    /* i960 Outbound Reg 1         */
+   #define IPS_REG_I960_OIMR            0x34    /* i960 Oubound Int Mask Reg   */
+
+   /*
+    * Adapter register bit equates
+    */
+   #define IPS_BIT_GHI                  0x04    /* HISR General Host Interrupt */
+   #define IPS_BIT_SQO                  0x02    /* HISR Status Q Overflow      */
+   #define IPS_BIT_SCE                  0x01    /* HISR Status Channel Enqueue */
+   #define IPS_BIT_SEM                  0x08    /* CCCR Semaphore Bit          */
+   #define IPS_BIT_ILE                  0x10    /* CCCR ILE Bit                */
+   #define IPS_BIT_START_CMD            0x101A  /* CCCR Start Command Channel  */
+   #define IPS_BIT_START_STOP           0x0002  /* CCCR Start/Stop Bit         */
+   #define IPS_BIT_RST                  0x80    /* SCPR Reset Bit              */
+   #define IPS_BIT_EBM                  0x02    /* SCPR Enable Bus Master      */
+   #define IPS_BIT_EI                   0x80    /* HISR Enable Interrupts      */
+   #define IPS_BIT_OP                   0x01    /* OP bit in CBSP              */
+   #define IPS_BIT_I2O_OPQI             0x08    /* General Host Interrupt      */
+   #define IPS_BIT_I960_MSG0I           0x01    /* Message Register 0 Interrupt*/
+   #define IPS_BIT_I960_MSG1I           0x02    /* Message Register 1 Interrupt*/
+
+   /*
+    * Adapter Command ID Equates
+    */
+   #define IPS_CMD_GET_LD_INFO          0x19
+   #define IPS_CMD_GET_SUBSYS           0x40
+   #define IPS_CMD_READ_CONF            0x38
+   #define IPS_CMD_RW_NVRAM_PAGE        0xBC
+   #define IPS_CMD_READ                 0x02
+   #define IPS_CMD_WRITE                0x03
+   #define IPS_CMD_FFDC                 0xD7
+   #define IPS_CMD_ENQUIRY              0x05
+   #define IPS_CMD_FLUSH                0x0A
+   #define IPS_CMD_READ_SG              0x82
+   #define IPS_CMD_WRITE_SG             0x83
+   #define IPS_CMD_DCDB                 0x04
+   #define IPS_CMD_DCDB_SG              0x84
+   #define IPS_CMD_EXTENDED_DCDB 	    0x95
+   #define IPS_CMD_EXTENDED_DCDB_SG	    0x96
+   #define IPS_CMD_CONFIG_SYNC          0x58
+   #define IPS_CMD_ERROR_TABLE          0x17
+   #define IPS_CMD_DOWNLOAD             0x20
+   #define IPS_CMD_RW_BIOSFW            0x22
+   #define IPS_CMD_GET_VERSION_INFO     0xC6
+   #define IPS_CMD_RESET_CHANNEL        0x1A  
+
+   /*
+    * Adapter Equates
+    */
+   #define IPS_CSL                      0xFF
+   #define IPS_POCL                     0x30
+   #define IPS_NORM_STATE               0x00
+   #define IPS_MAX_ADAPTER_TYPES        3
+   #define IPS_MAX_ADAPTERS             16
+   #define IPS_MAX_IOCTL                1
+   #define IPS_MAX_IOCTL_QUEUE          8
+   #define IPS_MAX_QUEUE                128
+   #define IPS_BLKSIZE                  512
+   #define IPS_MAX_SG                   17
+   #define IPS_MAX_LD                   8
+   #define IPS_MAX_CHANNELS             4
+   #define IPS_MAX_TARGETS              15
+   #define IPS_MAX_CHUNKS               16
+   #define IPS_MAX_CMDS                 128
+   #define IPS_MAX_XFER                 0x10000
+   #define IPS_NVRAM_P5_SIG             0xFFDDBB99
+   #define IPS_MAX_POST_BYTES           0x02
+   #define IPS_MAX_CONFIG_BYTES         0x02
+   #define IPS_GOOD_POST_STATUS         0x80
+   #define IPS_SEM_TIMEOUT              2000
+   #define IPS_IOCTL_COMMAND            0x0D
+   #define IPS_INTR_ON                  0
+   #define IPS_INTR_IORL                1
+   #define IPS_FFDC                     99
+   #define IPS_ADAPTER_ID               0xF
+   #define IPS_VENDORID_IBM             0x1014
+   #define IPS_VENDORID_ADAPTEC         0x9005
+   #define IPS_DEVICEID_COPPERHEAD      0x002E
+   #define IPS_DEVICEID_MORPHEUS        0x01BD
+   #define IPS_DEVICEID_MARCO           0x0250
+   #define IPS_SUBDEVICEID_4M           0x01BE
+   #define IPS_SUBDEVICEID_4L           0x01BF
+   #define IPS_SUBDEVICEID_4MX          0x0208
+   #define IPS_SUBDEVICEID_4LX          0x020E
+   #define IPS_SUBDEVICEID_5I2          0x0259
+   #define IPS_SUBDEVICEID_5I1          0x0258
+   #define IPS_SUBDEVICEID_6M           0x0279
+   #define IPS_SUBDEVICEID_6I           0x028C
+   #define IPS_SUBDEVICEID_7k           0x028E
+   #define IPS_SUBDEVICEID_7M           0x028F
+   #define IPS_IOCTL_SIZE               8192
+   #define IPS_STATUS_SIZE              4
+   #define IPS_STATUS_Q_SIZE            (IPS_MAX_CMDS+1) * IPS_STATUS_SIZE
+   #define IPS_IMAGE_SIZE               500 * 1024
+   #define IPS_MEMMAP_SIZE              128
+   #define IPS_ONE_MSEC                 1
+   #define IPS_ONE_SEC                  1000
+
+   /*
+    * Geometry Settings
+    */
+   #define IPS_COMP_HEADS               128
+   #define IPS_COMP_SECTORS             32
+   #define IPS_NORM_HEADS               254
+   #define IPS_NORM_SECTORS             63
+
+   /*
+    * Adapter Basic Status Codes
+    */
+   #define IPS_BASIC_STATUS_MASK        0xFF
+   #define IPS_GSC_STATUS_MASK          0x0F
+   #define IPS_CMD_SUCCESS              0x00
+   #define IPS_CMD_RECOVERED_ERROR      0x01
+   #define IPS_INVAL_OPCO               0x03
+   #define IPS_INVAL_CMD_BLK            0x04
+   #define IPS_INVAL_PARM_BLK           0x05
+   #define IPS_BUSY                     0x08
+   #define IPS_CMD_CMPLT_WERROR         0x0C
+   #define IPS_LD_ERROR                 0x0D
+   #define IPS_CMD_TIMEOUT              0x0E
+   #define IPS_PHYS_DRV_ERROR           0x0F
+
+   /*
+    * Adapter Extended Status Equates
+    */
+   #define IPS_ERR_SEL_TO               0xF0
+   #define IPS_ERR_OU_RUN               0xF2
+   #define IPS_ERR_HOST_RESET           0xF7
+   #define IPS_ERR_DEV_RESET            0xF8
+   #define IPS_ERR_RECOVERY             0xFC
+   #define IPS_ERR_CKCOND               0xFF
+
+   /*
+    * Operating System Defines
+    */
+   #define IPS_OS_WINDOWS_NT            0x01
+   #define IPS_OS_NETWARE               0x02
+   #define IPS_OS_OPENSERVER            0x03
+   #define IPS_OS_UNIXWARE              0x04
+   #define IPS_OS_SOLARIS               0x05
+   #define IPS_OS_OS2                   0x06
+   #define IPS_OS_LINUX                 0x07
+   #define IPS_OS_FREEBSD               0x08
+
+   /*
+    * Adapter Revision ID's
+    */
+   #define IPS_REVID_SERVERAID          0x02
+   #define IPS_REVID_NAVAJO             0x03
+   #define IPS_REVID_SERVERAID2         0x04
+   #define IPS_REVID_CLARINETP1         0x05
+   #define IPS_REVID_CLARINETP2         0x07
+   #define IPS_REVID_CLARINETP3         0x0D
+   #define IPS_REVID_TROMBONE32         0x0F
+   #define IPS_REVID_TROMBONE64         0x10
+
+   /*
+    * NVRAM Page 5 Adapter Defines
+    */
+   #define IPS_ADTYPE_SERVERAID         0x01
+   #define IPS_ADTYPE_SERVERAID2        0x02
+   #define IPS_ADTYPE_NAVAJO            0x03
+   #define IPS_ADTYPE_KIOWA             0x04
+   #define IPS_ADTYPE_SERVERAID3        0x05
+   #define IPS_ADTYPE_SERVERAID3L       0x06
+   #define IPS_ADTYPE_SERVERAID4H       0x07
+   #define IPS_ADTYPE_SERVERAID4M       0x08
+   #define IPS_ADTYPE_SERVERAID4L       0x09
+   #define IPS_ADTYPE_SERVERAID4MX      0x0A
+   #define IPS_ADTYPE_SERVERAID4LX      0x0B
+   #define IPS_ADTYPE_SERVERAID5I2      0x0C
+   #define IPS_ADTYPE_SERVERAID5I1      0x0D
+   #define IPS_ADTYPE_SERVERAID6M       0x0E
+   #define IPS_ADTYPE_SERVERAID6I       0x0F
+   #define IPS_ADTYPE_SERVERAID7t       0x10
+   #define IPS_ADTYPE_SERVERAID7k       0x11
+   #define IPS_ADTYPE_SERVERAID7M       0x12
+
+   /*
+    * Adapter Command/Status Packet Definitions
+    */
+   #define IPS_SUCCESS                  0x01 /* Successfully completed       */
+   #define IPS_SUCCESS_IMM              0x02 /* Success - Immediately        */
+   #define IPS_FAILURE                  0x04 /* Completed with Error         */
+
+   /*
+    * Logical Drive Equates
+    */
+   #define IPS_LD_OFFLINE               0x02
+   #define IPS_LD_OKAY                  0x03
+   #define IPS_LD_FREE                  0x00
+   #define IPS_LD_SYS                   0x06
+   #define IPS_LD_CRS                   0x24
+
+   /*
+    * DCDB Table Equates
+    */
+   #define IPS_NO_DISCONNECT            0x00
+   #define IPS_DISCONNECT_ALLOWED       0x80
+   #define IPS_NO_AUTO_REQSEN           0x40
+   #define IPS_DATA_NONE                0x00
+   #define IPS_DATA_UNK                 0x00
+   #define IPS_DATA_IN                  0x01
+   #define IPS_DATA_OUT                 0x02
+   #define IPS_TRANSFER64K              0x08
+   #define IPS_NOTIMEOUT                0x00
+   #define IPS_TIMEOUT10                0x10
+   #define IPS_TIMEOUT60                0x20
+   #define IPS_TIMEOUT20M               0x30
+
+   /*
+    * SCSI Inquiry Data Flags
+    */
+   #define IPS_SCSI_INQ_TYPE_DASD       0x00
+   #define IPS_SCSI_INQ_TYPE_PROCESSOR  0x03
+   #define IPS_SCSI_INQ_LU_CONNECTED    0x00
+   #define IPS_SCSI_INQ_RD_REV2         0x02
+   #define IPS_SCSI_INQ_REV2            0x02
+   #define IPS_SCSI_INQ_REV3            0x03
+   #define IPS_SCSI_INQ_Address16       0x01
+   #define IPS_SCSI_INQ_Address32       0x02
+   #define IPS_SCSI_INQ_MedChanger      0x08
+   #define IPS_SCSI_INQ_MultiPort       0x10
+   #define IPS_SCSI_INQ_EncServ         0x40
+   #define IPS_SCSI_INQ_SoftReset       0x01
+   #define IPS_SCSI_INQ_CmdQue          0x02
+   #define IPS_SCSI_INQ_Linked          0x08
+   #define IPS_SCSI_INQ_Sync            0x10
+   #define IPS_SCSI_INQ_WBus16          0x20
+   #define IPS_SCSI_INQ_WBus32          0x40
+   #define IPS_SCSI_INQ_RelAdr          0x80
+
+   /*
+    * SCSI Request Sense Data Flags
+    */
+   #define IPS_SCSI_REQSEN_VALID        0x80
+   #define IPS_SCSI_REQSEN_CURRENT_ERR  0x70
+   #define IPS_SCSI_REQSEN_NO_SENSE     0x00
+
+   /*
+    * SCSI Mode Page Equates
+    */
+   #define IPS_SCSI_MP3_SoftSector      0x01
+   #define IPS_SCSI_MP3_HardSector      0x02
+   #define IPS_SCSI_MP3_Removeable      0x04
+   #define IPS_SCSI_MP3_AllocateSurface 0x08
+
+   /*
+    * HA Flags
+    */
+
+   #define IPS_HA_ENH_SG                0x1
+
+   /*
+    * SCB Flags
+    */
+   #define IPS_SCB_MAP_SG               0x00008
+   #define IPS_SCB_MAP_SINGLE           0X00010
+
+   /*
+    * Passthru stuff
+    */
+   #define IPS_COPPUSRCMD              (('C'<<8) | 65)
+   #define IPS_COPPIOCCMD              (('C'<<8) | 66)
+   #define IPS_NUMCTRLS                (('C'<<8) | 68)
+   #define IPS_CTRLINFO                (('C'<<8) | 69)
+
+   /* flashing defines */
+   #define IPS_FW_IMAGE                0x00
+   #define IPS_BIOS_IMAGE              0x01
+   #define IPS_WRITE_FW                0x01
+   #define IPS_WRITE_BIOS              0x02
+   #define IPS_ERASE_BIOS              0x03
+   #define IPS_BIOS_HEADER             0xC0
+
+   /* time oriented stuff */
+   #define IPS_IS_LEAP_YEAR(y)           (((y % 4 == 0) && ((y % 100 != 0) || (y % 400 == 0))) ? 1 : 0)
+   #define IPS_NUM_LEAP_YEARS_THROUGH(y) ((y) / 4 - (y) / 100 + (y) / 400)
+
+   #define IPS_SECS_MIN                 60
+   #define IPS_SECS_HOUR                3600
+   #define IPS_SECS_8HOURS              28800
+   #define IPS_SECS_DAY                 86400
+   #define IPS_DAYS_NORMAL_YEAR         365
+   #define IPS_DAYS_LEAP_YEAR           366
+   #define IPS_EPOCH_YEAR               1970
+
+   /*
+    * Scsi_Host Template
+    */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+   static int ips_proc24_info(char *, char **, off_t, int, int, int);
+   static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
+   static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
+#else
+   static int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+   static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int geom[]);
+   static int ips_slave_configure(Scsi_Device *SDptr);
+#endif
+
+/*
+ * Raid Command Formats
+ */
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  log_drv;
+   uint8_t  sg_count;
+   uint32_t lba;
+   uint32_t sg_addr;
+   uint16_t sector_count;
+   uint8_t  segment_4G;
+   uint8_t  enhanced_sg;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_IO_CMD, *PIPS_IO_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint16_t reserved;
+   uint32_t reserved2;
+   uint32_t buffer_addr;
+   uint32_t reserved3;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_LD_CMD, *PIPS_LD_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  reserved;
+   uint8_t  reserved2;
+   uint32_t reserved3;
+   uint32_t buffer_addr;
+   uint32_t reserved4;
+} IPS_IOCTL_CMD, *PIPS_IOCTL_CMD; 
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  channel;
+   uint8_t  reserved3;
+   uint8_t  reserved4;
+   uint8_t  reserved5;
+   uint8_t  reserved6;
+   uint8_t  reserved7;
+   uint8_t  reserved8;
+   uint8_t  reserved9;
+   uint8_t  reserved10;
+   uint8_t  reserved11;
+   uint8_t  reserved12;
+   uint8_t  reserved13;
+   uint8_t  reserved14;
+   uint8_t  adapter_flag;
+} IPS_RESET_CMD, *PIPS_RESET_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint16_t reserved;
+   uint32_t reserved2;
+   uint32_t dcdb_address;
+   uint16_t reserved3;
+   uint8_t  segment_4G;
+   uint8_t  enhanced_sg;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_DCDB_CMD, *PIPS_DCDB_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  channel;
+   uint8_t  source_target;
+   uint32_t reserved;
+   uint32_t reserved2;
+   uint32_t reserved3;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_CS_CMD, *PIPS_CS_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  log_drv;
+   uint8_t  control;
+   uint32_t reserved;
+   uint32_t reserved2;
+   uint32_t reserved3;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_US_CMD, *PIPS_US_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  reserved;
+   uint8_t  state;
+   uint32_t reserved2;
+   uint32_t reserved3;
+   uint32_t reserved4;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_FC_CMD, *PIPS_FC_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  reserved;
+   uint8_t  desc;
+   uint32_t reserved2;
+   uint32_t buffer_addr;
+   uint32_t reserved3;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_STATUS_CMD, *PIPS_STATUS_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  page;
+   uint8_t  write;
+   uint32_t reserved;
+   uint32_t buffer_addr;
+   uint32_t reserved2;
+   uint32_t ccsar;
+   uint32_t cccr;
+} IPS_NVRAM_CMD, *PIPS_NVRAM_CMD;
+
+typedef struct 
+{
+    uint8_t  op_code;
+    uint8_t  command_id;
+    uint16_t reserved;
+    uint32_t count;
+    uint32_t buffer_addr;
+    uint32_t reserved2;
+} IPS_VERSION_INFO, *PIPS_VERSION_INFO;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  reset_count;
+   uint8_t  reset_type;
+   uint8_t  second;
+   uint8_t  minute;
+   uint8_t  hour;
+   uint8_t  day;
+   uint8_t  reserved1[4];
+   uint8_t  month;
+   uint8_t  yearH;
+   uint8_t  yearL;
+   uint8_t  reserved2;
+} IPS_FFDC_CMD, *PIPS_FFDC_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  type;
+   uint8_t  direction;
+   uint32_t count;
+   uint32_t buffer_addr;
+   uint8_t  total_packets;
+   uint8_t  packet_num;
+   uint16_t reserved;
+} IPS_FLASHFW_CMD, *PIPS_FLASHFW_CMD;
+
+typedef struct {
+   uint8_t  op_code;
+   uint8_t  command_id;
+   uint8_t  type;
+   uint8_t  direction;
+   uint32_t count;
+   uint32_t buffer_addr;
+   uint32_t offset;
+} IPS_FLASHBIOS_CMD, *PIPS_FLASHBIOS_CMD;
+
+typedef union {
+   IPS_IO_CMD         basic_io;
+   IPS_LD_CMD         logical_info;
+   IPS_IOCTL_CMD      ioctl_info;
+   IPS_DCDB_CMD       dcdb;
+   IPS_CS_CMD         config_sync;
+   IPS_US_CMD         unlock_stripe;
+   IPS_FC_CMD         flush_cache;
+   IPS_STATUS_CMD     status;
+   IPS_NVRAM_CMD      nvram;
+   IPS_FFDC_CMD       ffdc;
+   IPS_FLASHFW_CMD    flashfw;
+   IPS_FLASHBIOS_CMD  flashbios;
+   IPS_VERSION_INFO   version_info;
+   IPS_RESET_CMD      reset;
+} IPS_HOST_COMMAND, *PIPS_HOST_COMMAND;
+
+typedef struct {
+   uint8_t  logical_id;
+   uint8_t  reserved;
+   uint8_t  raid_level;
+   uint8_t  state;
+   uint32_t sector_count;
+} IPS_DRIVE_INFO, *PIPS_DRIVE_INFO;
+
+typedef struct {
+   uint8_t       no_of_log_drive;
+   uint8_t       reserved[3];
+   IPS_DRIVE_INFO drive_info[IPS_MAX_LD];
+} IPS_LD_INFO, *PIPS_LD_INFO;
+
+typedef struct {
+   uint8_t   device_address;
+   uint8_t   cmd_attribute;
+   uint16_t  transfer_length;
+   uint32_t  buffer_pointer;
+   uint8_t   cdb_length;
+   uint8_t   sense_length;
+   uint8_t   sg_count;
+   uint8_t   reserved;
+   uint8_t   scsi_cdb[12];
+   uint8_t   sense_info[64];
+   uint8_t   scsi_status;
+   uint8_t   reserved2[3];
+} IPS_DCDB_TABLE, *PIPS_DCDB_TABLE;
+
+typedef struct {
+   uint8_t   device_address;
+   uint8_t   cmd_attribute;
+   uint8_t   cdb_length;
+   uint8_t   reserved_for_LUN; 	 
+   uint32_t  transfer_length;
+   uint32_t  buffer_pointer;
+   uint16_t  sg_count;
+   uint8_t   sense_length;
+   uint8_t   scsi_status;
+   uint32_t  reserved;
+   uint8_t   scsi_cdb[16];
+   uint8_t   sense_info[56];
+} IPS_DCDB_TABLE_TAPE, *PIPS_DCDB_TABLE_TAPE;
+
+typedef union {
+   struct {
+      volatile uint8_t  reserved;
+      volatile uint8_t  command_id;
+      volatile uint8_t  basic_status;
+      volatile uint8_t  extended_status;
+   } fields;
+
+   volatile uint32_t    value;
+} IPS_STATUS, *PIPS_STATUS;
+
+typedef struct {
+   IPS_STATUS           status[IPS_MAX_CMDS + 1];
+   volatile PIPS_STATUS p_status_start;
+   volatile PIPS_STATUS p_status_end;
+   volatile PIPS_STATUS p_status_tail;
+   volatile uint32_t    hw_status_start;
+   volatile uint32_t    hw_status_tail;
+} IPS_ADAPTER, *PIPS_ADAPTER;
+
+typedef struct {
+   uint8_t  ucLogDriveCount;
+   uint8_t  ucMiscFlag;
+   uint8_t  ucSLTFlag;
+   uint8_t  ucBSTFlag;
+   uint8_t  ucPwrChgCnt;
+   uint8_t  ucWrongAdrCnt;
+   uint8_t  ucUnidentCnt;
+   uint8_t  ucNVramDevChgCnt;
+   uint8_t  CodeBlkVersion[8];
+   uint8_t  BootBlkVersion[8];
+   uint32_t ulDriveSize[IPS_MAX_LD];
+   uint8_t  ucConcurrentCmdCount;
+   uint8_t  ucMaxPhysicalDevices;
+   uint16_t usFlashRepgmCount;
+   uint8_t  ucDefunctDiskCount;
+   uint8_t  ucRebuildFlag;
+   uint8_t  ucOfflineLogDrvCount;
+   uint8_t  ucCriticalDrvCount;
+   uint16_t usConfigUpdateCount;
+   uint8_t  ucBlkFlag;
+   uint8_t  reserved;
+   uint16_t usAddrDeadDisk[IPS_MAX_CHANNELS * (IPS_MAX_TARGETS + 1)];
+} IPS_ENQ, *PIPS_ENQ;
+
+typedef struct {
+   uint8_t  ucInitiator;
+   uint8_t  ucParameters;
+   uint8_t  ucMiscFlag;
+   uint8_t  ucState;
+   uint32_t ulBlockCount;
+   uint8_t  ucDeviceId[28];
+} IPS_DEVSTATE, *PIPS_DEVSTATE;
+
+typedef struct {
+   uint8_t  ucChn;
+   uint8_t  ucTgt;
+   uint16_t ucReserved;
+   uint32_t ulStartSect;
+   uint32_t ulNoOfSects;
+} IPS_CHUNK, *PIPS_CHUNK;
+
+typedef struct {
+   uint16_t ucUserField;
+   uint8_t  ucState;
+   uint8_t  ucRaidCacheParam;
+   uint8_t  ucNoOfChunkUnits;
+   uint8_t  ucStripeSize;
+   uint8_t  ucParams;
+   uint8_t  ucReserved;
+   uint32_t ulLogDrvSize;
+   IPS_CHUNK chunk[IPS_MAX_CHUNKS];
+} IPS_LD, *PIPS_LD;
+
+typedef struct {
+   uint8_t  board_disc[8];
+   uint8_t  processor[8];
+   uint8_t  ucNoChanType;
+   uint8_t  ucNoHostIntType;
+   uint8_t  ucCompression;
+   uint8_t  ucNvramType;
+   uint32_t ulNvramSize;
+} IPS_HARDWARE, *PIPS_HARDWARE;
+
+typedef struct {
+   uint8_t        ucLogDriveCount;
+   uint8_t        ucDateD;
+   uint8_t        ucDateM;
+   uint8_t        ucDateY;
+   uint8_t        init_id[4];
+   uint8_t        host_id[12];
+   uint8_t        time_sign[8];
+   uint32_t       UserOpt;
+   uint16_t       user_field;
+   uint8_t        ucRebuildRate;
+   uint8_t        ucReserve;
+   IPS_HARDWARE   hardware_disc;
+   IPS_LD         logical_drive[IPS_MAX_LD];
+   IPS_DEVSTATE   dev[IPS_MAX_CHANNELS][IPS_MAX_TARGETS+1];
+   uint8_t        reserved[512];
+} IPS_CONF, *PIPS_CONF;
+
+typedef struct {
+   uint32_t  signature;
+   uint8_t   reserved1;
+   uint8_t   adapter_slot;
+   uint16_t  adapter_type;
+   uint8_t   ctrl_bios[8];
+   uint8_t   versioning;                   /* 1 = Versioning Supported, else 0 */
+   uint8_t   version_mismatch;             /* 1 = Versioning MisMatch,  else 0 */
+   uint8_t   reserved2;
+   uint8_t   operating_system;
+   uint8_t   driver_high[4];
+   uint8_t   driver_low[4];
+   uint8_t   BiosCompatibilityID[8];
+   uint8_t   ReservedForOS2[8];
+   uint8_t   bios_high[4];                 /* Adapter's Flashed BIOS Version   */
+   uint8_t   bios_low[4];
+   uint8_t   adapter_order[16];            /* BIOS Telling us the Sort Order   */
+   uint8_t   Filler[60];
+} IPS_NVRAM_P5, *PIPS_NVRAM_P5;
+
+/*--------------------------------------------------------------------------*/
+/* Data returned from a GetVersion Command                                  */
+/*--------------------------------------------------------------------------*/
+
+                                             /* SubSystem Parameter[4]      */
+#define  IPS_GET_VERSION_SUPPORT 0x00018000  /* Mask for Versioning Support */
+
+typedef struct 
+{
+   uint32_t  revision;
+   uint8_t   bootBlkVersion[32];
+   uint8_t   bootBlkAttributes[4];
+   uint8_t   codeBlkVersion[32];
+   uint8_t   biosVersion[32];
+   uint8_t   biosAttributes[4];
+   uint8_t   compatibilityId[32];
+   uint8_t   reserved[4];
+} IPS_VERSION_DATA;
+
+
+typedef struct _IPS_SUBSYS {
+   uint32_t  param[128];
+} IPS_SUBSYS, *PIPS_SUBSYS;
+
+/**
+ ** SCSI Structures
+ **/
+
+/*
+ * Inquiry Data Format
+ */
+typedef struct {
+   uint8_t   DeviceType;
+   uint8_t   DeviceTypeQualifier;
+   uint8_t   Version;
+   uint8_t   ResponseDataFormat;
+   uint8_t   AdditionalLength;
+   uint8_t   Reserved;
+   uint8_t   Flags[2];
+   uint8_t   VendorId[8];
+   uint8_t   ProductId[16];
+   uint8_t   ProductRevisionLevel[4];
+   uint8_t   Reserved2;                                  /* Provides NULL terminator to name */
+} IPS_SCSI_INQ_DATA, *PIPS_SCSI_INQ_DATA;
+
+/*
+ * Read Capacity Data Format
+ */
+typedef struct {
+   uint32_t lba;
+   uint32_t len;
+} IPS_SCSI_CAPACITY;
+
+/*
+ * Request Sense Data Format
+ */
+typedef struct {
+   uint8_t  ResponseCode;
+   uint8_t  SegmentNumber;
+   uint8_t  Flags;
+   uint8_t  Information[4];
+   uint8_t  AdditionalLength;
+   uint8_t  CommandSpecific[4];
+   uint8_t  AdditionalSenseCode;
+   uint8_t  AdditionalSenseCodeQual;
+   uint8_t  FRUCode;
+   uint8_t  SenseKeySpecific[3];
+} IPS_SCSI_REQSEN;
+
+/*
+ * Sense Data Format - Page 3
+ */
+typedef struct {
+   uint8_t  PageCode;
+   uint8_t  PageLength;
+   uint16_t TracksPerZone;
+   uint16_t AltSectorsPerZone;
+   uint16_t AltTracksPerZone;
+   uint16_t AltTracksPerVolume;
+   uint16_t SectorsPerTrack;
+   uint16_t BytesPerSector;
+   uint16_t Interleave;
+   uint16_t TrackSkew;
+   uint16_t CylinderSkew;
+   uint8_t  flags;
+   uint8_t  reserved[3];
+} IPS_SCSI_MODE_PAGE3;
+
+/*
+ * Sense Data Format - Page 4
+ */
+typedef struct {
+   uint8_t  PageCode;
+   uint8_t  PageLength;
+   uint16_t CylindersHigh;
+   uint8_t  CylindersLow;
+   uint8_t  Heads;
+   uint16_t WritePrecompHigh;
+   uint8_t  WritePrecompLow;
+   uint16_t ReducedWriteCurrentHigh;
+   uint8_t  ReducedWriteCurrentLow;
+   uint16_t StepRate;
+   uint16_t LandingZoneHigh;
+   uint8_t  LandingZoneLow;
+   uint8_t  flags;
+   uint8_t  RotationalOffset;
+   uint8_t  Reserved;
+   uint16_t MediumRotationRate;
+   uint8_t  Reserved2[2];
+} IPS_SCSI_MODE_PAGE4;
+
+/*
+ * Sense Data Format - Page 8
+ */
+typedef struct {
+   uint8_t  PageCode;
+   uint8_t  PageLength;
+   uint8_t  flags;
+   uint8_t  RetentPrio;
+   uint16_t DisPrefetchLen;
+   uint16_t MinPrefetchLen;
+   uint16_t MaxPrefetchLen;
+   uint16_t MaxPrefetchCeiling;
+} IPS_SCSI_MODE_PAGE8;
+
+/*
+ * Sense Data Format - Block Descriptor (DASD)
+ */
+typedef struct {
+   uint32_t NumberOfBlocks;
+   uint8_t  DensityCode;
+   uint16_t BlockLengthHigh;
+   uint8_t  BlockLengthLow;
+} IPS_SCSI_MODE_PAGE_BLKDESC;
+
+/*
+ * Sense Data Format - Mode Page Header
+ */
+typedef struct {
+   uint8_t  DataLength;
+   uint8_t  MediumType;
+   uint8_t  Reserved;
+   uint8_t  BlockDescLength;
+} IPS_SCSI_MODE_PAGE_HEADER;
+
+typedef struct {
+   IPS_SCSI_MODE_PAGE_HEADER  hdr;
+   IPS_SCSI_MODE_PAGE_BLKDESC blkdesc;
+
+   union {
+      IPS_SCSI_MODE_PAGE3 pg3;
+      IPS_SCSI_MODE_PAGE4 pg4;
+      IPS_SCSI_MODE_PAGE8 pg8;
+   } pdata;
+} IPS_SCSI_MODE_PAGE_DATA;
+
+/*
+ * Scatter Gather list format
+ */
+typedef struct ips_sglist {
+   uint32_t address;
+   uint32_t length;
+} IPS_STD_SG_LIST;
+
+typedef struct ips_enh_sglist {
+   uint32_t address_lo;
+   uint32_t address_hi;
+   uint32_t length;
+   uint32_t reserved;
+} IPS_ENH_SG_LIST;
+
+typedef union {
+   void             *list;
+   IPS_STD_SG_LIST  *std_list;
+   IPS_ENH_SG_LIST  *enh_list;
+} IPS_SG_LIST;
+
+typedef struct _IPS_INFOSTR {
+   char *buffer;
+   int   length;
+   int   offset;
+   int   pos;
+   int   localpos;
+} IPS_INFOSTR;
+
+typedef struct {
+   char *option_name;
+   int  *option_flag;
+   int   option_value;
+} IPS_OPTION;
+
+/*
+ * Status Info
+ */
+typedef struct ips_stat {
+   uint32_t residue_len;
+   void     *scb_addr;
+   uint8_t  padding[12 - sizeof(void *)];
+} ips_stat_t;
+
+/*
+ * SCB Queue Format
+ */
+typedef struct ips_scb_queue {
+   struct ips_scb *head;
+   struct ips_scb *tail;
+   int             count;
+} ips_scb_queue_t;
+
+/*
+ * Wait queue_format
+ */
+typedef struct ips_wait_queue {
+   Scsi_Cmnd      *head;
+   Scsi_Cmnd      *tail;
+   int             count;
+} ips_wait_queue_t;
+
+typedef struct ips_copp_wait_item {
+   Scsi_Cmnd                 *scsi_cmd;
+   struct ips_copp_wait_item *next;
+} ips_copp_wait_item_t;
+
+typedef struct ips_copp_queue {
+   struct ips_copp_wait_item *head;
+   struct ips_copp_wait_item *tail;
+   int                        count;
+} ips_copp_queue_t;
+
+/* forward decl for host structure */
+struct ips_ha;
+
+typedef struct {
+   int       (*reset)(struct ips_ha *);
+   int       (*issue)(struct ips_ha *, struct ips_scb *);
+   int       (*isinit)(struct ips_ha *);
+   int       (*isintr)(struct ips_ha *);
+   int       (*init)(struct ips_ha *);
+   int       (*erasebios)(struct ips_ha *);
+   int       (*programbios)(struct ips_ha *, char *, uint32_t, uint32_t);
+   int       (*verifybios)(struct ips_ha *, char *, uint32_t, uint32_t);
+   void      (*statinit)(struct ips_ha *);
+   int       (*intr)(struct ips_ha *);
+   void      (*enableint)(struct ips_ha *);
+   uint32_t (*statupd)(struct ips_ha *);
+} ips_hw_func_t;
+
+typedef struct ips_ha {
+   uint8_t            ha_id[IPS_MAX_CHANNELS+1];
+   uint32_t           dcdb_active[IPS_MAX_CHANNELS];
+   uint32_t           io_addr;            /* Base I/O address           */
+   uint8_t            irq;                /* IRQ for adapter            */
+   uint8_t            ntargets;           /* Number of targets          */
+   uint8_t            nbus;               /* Number of buses            */
+   uint8_t            nlun;               /* Number of Luns             */
+   uint16_t           ad_type;            /* Adapter type               */
+   uint16_t           host_num;           /* Adapter number             */
+   uint32_t           max_xfer;           /* Maximum Xfer size          */
+   uint32_t           max_cmds;           /* Max concurrent commands    */
+   uint32_t           num_ioctl;          /* Number of Ioctls           */
+   ips_stat_t         sp;                 /* Status packer pointer      */
+   struct ips_scb    *scbs;               /* Array of all CCBS          */
+   struct ips_scb    *scb_freelist;       /* SCB free list              */
+   ips_wait_queue_t   scb_waitlist;       /* Pending SCB list           */
+   ips_copp_queue_t   copp_waitlist;      /* Pending PT list            */
+   ips_scb_queue_t    scb_activelist;     /* Active SCB list            */
+   IPS_IO_CMD        *dummy;              /* dummy command              */
+   IPS_ADAPTER       *adapt;              /* Adapter status area        */
+   IPS_LD_INFO       *logical_drive_info; /* Adapter Logical Drive Info */
+   dma_addr_t         logical_drive_info_dma_addr; /* Logical Drive Info DMA Address */
+   IPS_ENQ           *enq;                /* Adapter Enquiry data       */
+   IPS_CONF          *conf;               /* Adapter config data        */
+   IPS_NVRAM_P5      *nvram;              /* NVRAM page 5 data          */
+   IPS_SUBSYS        *subsys;             /* Subsystem parameters       */
+   char              *ioctl_data;         /* IOCTL data area            */
+   uint32_t           ioctl_datasize;     /* IOCTL data size            */
+   uint32_t           cmd_in_progress;    /* Current command in progress*/
+   int                flags;              /*                            */
+   uint8_t            waitflag;           /* are we waiting for cmd     */
+   uint8_t            active;
+   int                ioctl_reset;        /* IOCTL Requested Reset Flag */
+   uint16_t           reset_count;        /* number of resets           */
+   time_t             last_ffdc;          /* last time we sent ffdc info*/
+   uint8_t            revision_id;        /* Revision level             */
+   uint16_t           device_id;          /* PCI device ID              */
+   uint8_t            slot_num;           /* PCI Slot Number            */
+   uint16_t           subdevice_id;       /* Subsystem device ID        */
+   int                ioctl_len;          /* size of ioctl buffer       */
+   dma_addr_t         ioctl_busaddr;      /* dma address of ioctl buffer*/
+   uint8_t            bios_version[8];    /* BIOS Revision              */
+   uint32_t           mem_addr;           /* Memory mapped address      */
+   uint32_t           io_len;             /* Size of IO Address         */
+   uint32_t           mem_len;            /* Size of memory address     */
+   char              __iomem *mem_ptr;    /* Memory mapped Ptr          */
+   char              __iomem *ioremap_ptr;/* ioremapped memory pointer  */
+   ips_hw_func_t      func;               /* hw function pointers       */
+   struct pci_dev    *pcidev;             /* PCI device handle          */
+   char              *flash_data;         /* Save Area for flash data   */
+   int                flash_len;          /* length of flash buffer     */
+   u32                flash_datasize;     /* Save Area for flash data size */
+   dma_addr_t         flash_busaddr;      /* dma address of flash buffer*/
+   dma_addr_t         enq_busaddr;        /* dma address of enq struct  */
+   uint8_t            requires_esl;       /* Requires an EraseStripeLock */
+} ips_ha_t;
+
+typedef void (*ips_scb_callback) (ips_ha_t *, struct ips_scb *);
+
+/*
+ * SCB Format
+ */
+typedef struct ips_scb {
+   IPS_HOST_COMMAND  cmd;
+   IPS_DCDB_TABLE    dcdb;
+   uint8_t           target_id;
+   uint8_t           bus;
+   uint8_t           lun;
+   uint8_t           cdb[12];
+   uint32_t          scb_busaddr;
+   uint32_t          old_data_busaddr;  // Obsolete, but kept for old utility compatibility
+   uint32_t          timeout;
+   uint8_t           basic_status;
+   uint8_t           extended_status;
+   uint8_t           breakup;
+   uint8_t           sg_break;
+   uint32_t          data_len;
+   uint32_t          sg_len;
+   uint32_t          flags;
+   uint32_t          op_code;
+   IPS_SG_LIST       sg_list;
+   Scsi_Cmnd        *scsi_cmd;
+   struct ips_scb   *q_next;
+   ips_scb_callback  callback;
+   uint32_t          sg_busaddr;
+   int               sg_count;
+   dma_addr_t        data_busaddr;
+} ips_scb_t;
+
+typedef struct ips_scb_pt {
+   IPS_HOST_COMMAND  cmd;
+   IPS_DCDB_TABLE    dcdb;
+   uint8_t           target_id;
+   uint8_t           bus;
+   uint8_t           lun;
+   uint8_t           cdb[12];
+   uint32_t          scb_busaddr;
+   uint32_t          data_busaddr;
+   uint32_t          timeout;
+   uint8_t           basic_status;
+   uint8_t           extended_status;
+   uint16_t          breakup;
+   uint32_t          data_len;
+   uint32_t          sg_len;
+   uint32_t          flags;
+   uint32_t          op_code;
+   IPS_SG_LIST      *sg_list;
+   Scsi_Cmnd        *scsi_cmd;
+   struct ips_scb   *q_next;
+   ips_scb_callback  callback;
+} ips_scb_pt_t;
+
+/*
+ * Passthru Command Format
+ */
+typedef struct {
+   uint8_t       CoppID[4];
+   uint32_t      CoppCmd;
+   uint32_t      PtBuffer;
+   uint8_t      *CmdBuffer;
+   uint32_t      CmdBSize;
+   ips_scb_pt_t  CoppCP;
+   uint32_t      TimeOut;
+   uint8_t       BasicStatus;
+   uint8_t       ExtendedStatus;
+   uint8_t       AdapterType;
+   uint8_t       reserved;
+} ips_passthru_t;
+
+#endif
+
+/* The Version Information below gets created by SED during the build process. */
+/* Do not modify the next line; it's what SED is looking for to do the insert. */
+/* Version Info                                                                */
+/*************************************************************************
+*
+* VERSION.H -- version numbers and copyright notices in various formats
+*
+*************************************************************************/
+
+#define IPS_VER_MAJOR 7
+#define IPS_VER_MAJOR_STRING "7"
+#define IPS_VER_MINOR 10
+#define IPS_VER_MINOR_STRING "10"
+#define IPS_VER_BUILD 18
+#define IPS_VER_BUILD_STRING "18"
+#define IPS_VER_STRING "7.10.18"
+#define IPS_RELEASE_ID 0x00020000
+#define IPS_BUILD_IDENT 731
+#define IPS_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002. All Rights Reserved."
+#define IPS_ADAPTECCOPYRIGHT_STRING "(c) Copyright Adaptec, Inc. 2002 to 2004. All Rights Reserved."
+#define IPS_DELLCOPYRIGHT_STRING "(c) Copyright Dell 2004. All Rights Reserved."
+#define IPS_NT_LEGALCOPYRIGHT_STRING "(C) Copyright IBM Corp. 1994, 2002."
+
+/* Version numbers for various adapters */
+#define IPS_VER_SERVERAID1 "2.25.01"
+#define IPS_VER_SERVERAID2 "2.88.13"
+#define IPS_VER_NAVAJO "2.88.13"
+#define IPS_VER_SERVERAID3 "6.10.24"
+#define IPS_VER_SERVERAID4H "7.10.11"
+#define IPS_VER_SERVERAID4MLx "7.10.18"
+#define IPS_VER_SARASOTA "7.10.18"
+#define IPS_VER_MARCO "7.10.18"
+#define IPS_VER_SEBRING "7.10.18"
+#define IPS_VER_KEYWEST "7.10.18"
+
+/* Compatability IDs for various adapters */
+#define IPS_COMPAT_UNKNOWN ""
+#define IPS_COMPAT_CURRENT "KW710"
+#define IPS_COMPAT_SERVERAID1 "2.25.01"
+#define IPS_COMPAT_SERVERAID2 "2.88.13"
+#define IPS_COMPAT_NAVAJO  "2.88.13"
+#define IPS_COMPAT_KIOWA "2.88.13"
+#define IPS_COMPAT_SERVERAID3H  "SB610"
+#define IPS_COMPAT_SERVERAID3L  "SB610"
+#define IPS_COMPAT_SERVERAID4H  "KW710"
+#define IPS_COMPAT_SERVERAID4M  "KW710"
+#define IPS_COMPAT_SERVERAID4L  "KW710"
+#define IPS_COMPAT_SERVERAID4Mx "KW710"
+#define IPS_COMPAT_SERVERAID4Lx "KW710"
+#define IPS_COMPAT_SARASOTA     "KW710"
+#define IPS_COMPAT_MARCO        "KW710"
+#define IPS_COMPAT_SEBRING      "KW710"
+#define IPS_COMPAT_TAMPA        "KW710"
+#define IPS_COMPAT_KEYWEST      "KW710"
+#define IPS_COMPAT_BIOS "KW710"
+
+#define IPS_COMPAT_MAX_ADAPTER_TYPE 18
+#define IPS_COMPAT_ID_LENGTH 8
+
+#define IPS_DEFINE_COMPAT_TABLE(tablename) \
+   char tablename[IPS_COMPAT_MAX_ADAPTER_TYPE] [IPS_COMPAT_ID_LENGTH] = { \
+      IPS_COMPAT_UNKNOWN, \
+      IPS_COMPAT_SERVERAID1, \
+      IPS_COMPAT_SERVERAID2, \
+      IPS_COMPAT_NAVAJO, \
+      IPS_COMPAT_KIOWA, \
+      IPS_COMPAT_SERVERAID3H, \
+      IPS_COMPAT_SERVERAID3L, \
+      IPS_COMPAT_SERVERAID4H, \
+      IPS_COMPAT_SERVERAID4M, \
+      IPS_COMPAT_SERVERAID4L, \
+      IPS_COMPAT_SERVERAID4Mx, \
+      IPS_COMPAT_SERVERAID4Lx, \
+      IPS_COMPAT_SARASOTA,         /* one-channel variety of SARASOTA */  \
+      IPS_COMPAT_SARASOTA,         /* two-channel variety of SARASOTA */  \
+      IPS_COMPAT_MARCO, \
+      IPS_COMPAT_SEBRING, \
+      IPS_COMPAT_TAMPA, \
+      IPS_COMPAT_KEYWEST \
+   }
+
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 2
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -2
+ * c-argdecl-indent: 2
+ * c-label-offset: -2
+ * c-continued-statement-offset: 2
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c
new file mode 100644
index 0000000..a642f73
--- /dev/null
+++ b/drivers/scsi/jazz_esp.c
@@ -0,0 +1,329 @@
+/*
+ * jazz_esp.c: Driver for SCSI chip on Mips Magnum Boards (JAZZ architecture)
+ *
+ * Copyright (C) 1997 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * jazz_esp is based on David S. Miller's ESP driver and cyber_esp
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <asm/irq.h>
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+#include <asm/dma.h>
+
+#include <asm/pgtable.h>
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp);
+static void dma_advance_sg (struct scsi_cmnd *sp);
+static void dma_led_off(struct NCR_ESP *);
+static void dma_led_on(struct NCR_ESP *);
+
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are trasfered to the ESP chip
+				 * via PIO.
+				 */
+
+int jazz_esp_detect(Scsi_Host_Template *tpnt);
+static int jazz_esp_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "jazz_esp",
+	.proc_info		= &esp_proc_info,
+	.name			= "ESP 100/100a/200",
+	.detect			= jazz_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= jazz_esp_release,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+#include "scsi_module.c"
+
+/***************************************************************** Detection */
+static int jazz_esp_detect(struct scsi_host_template *tpnt)
+{
+    struct NCR_ESP *esp;
+    struct ConfigDev *esp_dev;
+
+    /*
+     * first assumption it is there:-)
+     */
+    if (1) {
+	esp_dev = 0;
+	esp = esp_allocate(tpnt, (void *) esp_dev);
+	
+	/* Do command transfer with programmed I/O */
+	esp->do_pio_cmds = 1;
+	
+	/* Required functions */
+	esp->dma_bytes_sent = &dma_bytes_sent;
+	esp->dma_can_transfer = &dma_can_transfer;
+	esp->dma_dump_state = &dma_dump_state;
+	esp->dma_init_read = &dma_init_read;
+	esp->dma_init_write = &dma_init_write;
+	esp->dma_ints_off = &dma_ints_off;
+	esp->dma_ints_on = &dma_ints_on;
+	esp->dma_irq_p = &dma_irq_p;
+	esp->dma_ports_p = &dma_ports_p;
+	esp->dma_setup = &dma_setup;
+
+	/* Optional functions */
+	esp->dma_barrier = 0;
+	esp->dma_drain = 0;
+	esp->dma_invalidate = 0;
+	esp->dma_irq_entry = 0;
+	esp->dma_irq_exit = 0;
+	esp->dma_poll = 0;
+	esp->dma_reset = 0;
+	esp->dma_led_off = &dma_led_off;
+	esp->dma_led_on = &dma_led_on;
+	
+	/* virtual DMA functions */
+	esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+	esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+	esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
+	esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
+	esp->dma_advance_sg = &dma_advance_sg;
+
+
+	/* SCSI chip speed */
+	esp->cfreq = 40000000;
+
+	/* 
+	 * we don't give the address of DMA channel, but the number
+	 * of DMA channel, so we can use the jazz DMA functions
+	 * 
+	 */
+	esp->dregs = JAZZ_SCSI_DMA;
+	
+	/* ESP register base */
+	esp->eregs = (struct ESP_regs *)(JAZZ_SCSI_BASE);
+	
+	/* Set the command buffer */
+	esp->esp_command = (volatile unsigned char *)cmd_buffer;
+	
+	/* get virtual dma address for command buffer */
+	esp->esp_command_dvma = vdma_alloc(CPHYSADDR(cmd_buffer), sizeof (cmd_buffer));
+	
+	esp->irq = JAZZ_SCSI_IRQ;
+	request_irq(JAZZ_SCSI_IRQ, esp_intr, SA_INTERRUPT, "JAZZ SCSI",
+	            esp->ehost);
+
+	/*
+	 * FIXME, look if the scsi id is available from NVRAM
+	 */
+	esp->scsi_id = 7;
+		
+	/* Check for differential SCSI-bus */
+	/* What is this stuff? */
+	esp->diff = 0;
+
+	esp_initialize(esp);
+	
+	printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use);
+	esps_running = esps_in_use;
+	return esps_in_use;
+    }
+    return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+    return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, struct scsi_cmnd *sp)
+{
+    /*
+     * maximum DMA size is 1MB
+     */
+    unsigned long sz = sp->SCp.this_residual;
+    if(sz > 0x100000)
+	sz = 0x100000;
+    return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+    
+    ESPLOG(("esp%d: dma -- enable <%08x> residue <%08x\n",
+	    esp->esp_id, vdma_get_enable((int)esp->dregs), vdma_get_residue((int)esp->dregs)));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+    dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length);
+    vdma_disable ((int)esp->dregs);
+    vdma_set_mode ((int)esp->dregs, DMA_MODE_READ);
+    vdma_set_addr ((int)esp->dregs, vaddress);
+    vdma_set_count ((int)esp->dregs, length);
+    vdma_enable ((int)esp->dregs);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+    dma_cache_wback_inv ((unsigned long)phys_to_virt(vdma_log2phys(vaddress)), length);    
+    vdma_disable ((int)esp->dregs);    
+    vdma_set_mode ((int)esp->dregs, DMA_MODE_WRITE);
+    vdma_set_addr ((int)esp->dregs, vaddress);
+    vdma_set_count ((int)esp->dregs, length);
+    vdma_enable ((int)esp->dregs);    
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+    disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+    enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+    return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+    int enable = vdma_get_enable((int)esp->dregs);
+    
+    return (enable & R4030_CHNL_ENABLE);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+    /* 
+     * On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+     * so when (write) is true, it actually means READ!
+     */
+    if(write){
+	dma_init_read(esp, addr, count);
+    } else {
+	dma_init_write(esp, addr, count);
+    }
+}
+
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp)
+{
+    sp->SCp.have_data_in = vdma_alloc(CPHYSADDR(sp->SCp.buffer), sp->SCp.this_residual);
+    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in);
+}
+
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp)
+{
+    int sz = sp->SCp.buffers_residual;
+    struct scatterlist *sg = (struct scatterlist *) sp->SCp.buffer;
+    
+    while (sz >= 0) {
+	sg[sz].dma_address = vdma_alloc(CPHYSADDR(page_address(sg[sz].page) + sg[sz].offset), sg[sz].length);
+	sz--;
+    }
+    sp->SCp.ptr=(char *)(sp->SCp.buffer->dma_address);
+}    
+
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, struct scsi_cmnd *sp)
+{
+    vdma_free(sp->SCp.have_data_in);
+}
+
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, struct scsi_cmnd *sp)
+{
+    int sz = sp->use_sg - 1;
+    struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+			
+    while(sz >= 0) {
+	vdma_free(sg[sz].dma_address);
+	sz--;
+    }
+}
+
+static void dma_advance_sg (struct scsi_cmnd *sp)
+{
+    sp->SCp.ptr = (char *)(sp->SCp.buffer->dma_address);
+}
+
+#define JAZZ_HDC_LED   0xe000d100 /* FIXME, find correct address */
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+#if 0    
+    *(unsigned char *)JAZZ_HDC_LED = 0;
+#endif    
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{    
+#if 0    
+    *(unsigned char *)JAZZ_HDC_LED = 1;
+#endif    
+}
+
+static struct scsi_host_template driver_template = {
+	.proc_name		= "jazz_esp",
+	.proc_info		= esp_proc_info,
+	.name			= "ESP 100/100a/200",
+	.detect			= jazz_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= jazz_esp_release,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
new file mode 100644
index 0000000..29f250c
--- /dev/null
+++ b/drivers/scsi/lasi700.c
@@ -0,0 +1,189 @@
+/* -*- mode: c; c-basic-offset: 8 -*- */
+
+/* PARISC LASI driver for the 53c700 chip
+ *
+ * Copyright (C) 2001 by James.Bottomley@HansenPartnership.com
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+ */
+
+/*
+ * Many thanks to Richard Hirst <rhirst@linuxcare.com> for patiently
+ * debugging this driver on the parisc architecture and suggesting
+ * many improvements and bug fixes.
+ *
+ * Thanks also go to Linuxcare Inc. for providing several PARISC
+ * machines for me to debug the driver on.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/stat.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/irq.h>
+#include <asm/hardware.h>
+#include <asm/parisc-device.h>
+#include <asm/delay.h>
+
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+MODULE_AUTHOR("James Bottomley");
+MODULE_DESCRIPTION("lasi700 SCSI Driver");
+MODULE_LICENSE("GPL");
+
+#define LASI_700_SVERSION 0x00071
+#define LASI_710_SVERSION 0x00082
+
+#define LASI700_ID_TABLE {			\
+	.hw_type	= HPHW_FIO,		\
+	.sversion	= LASI_700_SVERSION,	\
+	.hversion	= HVERSION_ANY_ID,	\
+	.hversion_rev	= HVERSION_REV_ANY_ID,	\
+}
+
+#define LASI710_ID_TABLE {			\
+	.hw_type	= HPHW_FIO,		\
+	.sversion	= LASI_710_SVERSION,	\
+	.hversion	= HVERSION_ANY_ID,	\
+	.hversion_rev	= HVERSION_REV_ANY_ID,	\
+}
+
+#define LASI700_CLOCK	25
+#define LASI710_CLOCK	40
+#define LASI_SCSI_CORE_OFFSET 0x100
+
+static struct parisc_device_id lasi700_ids[] = {
+	LASI700_ID_TABLE,
+	LASI710_ID_TABLE,
+	{ 0 }
+};
+
+static struct scsi_host_template lasi700_template = {
+	.name		= "LASI SCSI 53c700",
+	.proc_name	= "lasi700",
+	.this_id	= 7,
+	.module		= THIS_MODULE,
+};
+MODULE_DEVICE_TABLE(parisc, lasi700_ids);
+
+static int __init
+lasi700_probe(struct parisc_device *dev)
+{
+	unsigned long base = dev->hpa + LASI_SCSI_CORE_OFFSET;
+	struct NCR_700_Host_Parameters *hostdata;
+	struct Scsi_Host *host;
+
+	hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+	if (!hostdata) {
+		printk(KERN_ERR "%s: Failed to allocate host data\n",
+		       dev->dev.bus_id);
+		return -ENOMEM;
+	}
+	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+	hostdata->dev = &dev->dev;
+	dma_set_mask(&dev->dev, DMA_32BIT_MASK);
+	hostdata->base = ioremap(base, 0x100);
+	hostdata->differential = 0;
+
+	if (dev->id.sversion == LASI_700_SVERSION) {
+		hostdata->clock = LASI700_CLOCK;
+		hostdata->force_le_on_be = 1;
+	} else {
+		hostdata->clock = LASI710_CLOCK;
+		hostdata->force_le_on_be = 0;
+		hostdata->chip710 = 1;
+		hostdata->dmode_extra = DMODE_FC2;
+	}
+
+	NCR_700_set_mem_mapped(hostdata);
+
+	host = NCR_700_detect(&lasi700_template, hostdata, &dev->dev);
+	if (!host)
+		goto out_kfree;
+	host->this_id = 7;
+	host->irq = dev->irq;
+	if(request_irq(dev->irq, NCR_700_intr, SA_SHIRQ, "lasi700", host)) {
+		printk(KERN_ERR "lasi700: request_irq failed!\n");
+		goto out_put_host;
+	}
+
+	dev_set_drvdata(&dev->dev, host);
+	scsi_scan_host(host);
+
+	return 0;
+
+ out_put_host:
+	scsi_host_put(host);
+ out_kfree:
+	iounmap(hostdata->base);
+	kfree(hostdata);
+	return -ENODEV;
+}
+
+static int __exit
+lasi700_driver_remove(struct parisc_device *dev)
+{
+	struct Scsi_Host *host = dev_get_drvdata(&dev->dev);
+	struct NCR_700_Host_Parameters *hostdata = 
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	scsi_remove_host(host);
+	NCR_700_release(host);
+	free_irq(host->irq, host);
+	iounmap(hostdata->base);
+	kfree(hostdata);
+
+	return 0;
+}
+
+static struct parisc_driver lasi700_driver = {
+	.name =		"Lasi SCSI",
+	.id_table =	lasi700_ids,
+	.probe =	lasi700_probe,
+	.remove =	__devexit_p(lasi700_driver_remove),
+};
+
+static int __init
+lasi700_init(void)
+{
+	return register_parisc_driver(&lasi700_driver);
+}
+
+static void __exit
+lasi700_exit(void)
+{
+	unregister_parisc_driver(&lasi700_driver);
+}
+
+module_init(lasi700_init);
+module_exit(lasi700_exit);
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
new file mode 100644
index 0000000..0b5d3a5
--- /dev/null
+++ b/drivers/scsi/libata-core.c
@@ -0,0 +1,4024 @@
+/*
+   libata-core.c - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/completion.h>
+#include <linux/suspend.h>
+#include <linux/workqueue.h>
+#include <scsi/scsi.h>
+#include "scsi.h"
+#include "scsi_priv.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+#include <asm/byteorder.h>
+
+#include "libata.h"
+
+static unsigned int ata_busy_sleep (struct ata_port *ap,
+				    unsigned long tmout_pat,
+			    	    unsigned long tmout);
+static void ata_set_mode(struct ata_port *ap);
+static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev);
+static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift);
+static int fgb(u32 bitmap);
+static int ata_choose_xfer_mode(struct ata_port *ap,
+				u8 *xfer_mode_out,
+				unsigned int *xfer_shift_out);
+static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat);
+static void __ata_qc_complete(struct ata_queued_cmd *qc);
+
+static unsigned int ata_unique_id = 1;
+static struct workqueue_struct *ata_wq;
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Library module for ATA devices");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+/**
+ *	ata_tf_load - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		outb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		outb(tf->hob_feature, ioaddr->feature_addr);
+		outb(tf->hob_nsect, ioaddr->nsect_addr);
+		outb(tf->hob_lbal, ioaddr->lbal_addr);
+		outb(tf->hob_lbam, ioaddr->lbam_addr);
+		outb(tf->hob_lbah, ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		outb(tf->feature, ioaddr->feature_addr);
+		outb(tf->nsect, ioaddr->nsect_addr);
+		outb(tf->lbal, ioaddr->lbal_addr);
+		outb(tf->lbam, ioaddr->lbam_addr);
+		outb(tf->lbah, ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		outb(tf->device, ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+/**
+ *	ata_tf_load_mmio - send taskfile registers to host controller
+ *	@ap: Port to which output is sent
+ *	@tf: ATA taskfile register set
+ *
+ *	Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, (void __iomem *) ap->ioaddr.ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writeb(tf->hob_feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->hob_nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->hob_lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->hob_lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->hob_lbah, (void __iomem *) ioaddr->lbah_addr);
+		VPRINTK("hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X\n",
+			tf->hob_feature,
+			tf->hob_nsect,
+			tf->hob_lbal,
+			tf->hob_lbam,
+			tf->hob_lbah);
+	}
+
+	if (is_addr) {
+		writeb(tf->feature, (void __iomem *) ioaddr->feature_addr);
+		writeb(tf->nsect, (void __iomem *) ioaddr->nsect_addr);
+		writeb(tf->lbal, (void __iomem *) ioaddr->lbal_addr);
+		writeb(tf->lbam, (void __iomem *) ioaddr->lbam_addr);
+		writeb(tf->lbah, (void __iomem *) ioaddr->lbah_addr);
+		VPRINTK("feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X\n",
+			tf->feature,
+			tf->nsect,
+			tf->lbal,
+			tf->lbam,
+			tf->lbah);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		writeb(tf->device, (void __iomem *) ioaddr->device_addr);
+		VPRINTK("device 0x%X\n", tf->device);
+	}
+
+	ata_wait_idle(ap);
+}
+
+void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_load_mmio(ap, tf);
+	else
+		ata_tf_load_pio(ap, tf);
+}
+
+/**
+ *	ata_exec_command - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO/MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	outb(tf->command, ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+
+/**
+ *	ata_exec_command_mmio - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+
+       	writeb(tf->command, (void __iomem *) ap->ioaddr.command_addr);
+	ata_pause(ap);
+}
+
+void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_exec_command_mmio(ap, tf);
+	else
+		ata_exec_command_pio(ap, tf);
+}
+
+/**
+ *	ata_exec - issue ATA command to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues PIO/MMIO write to ATA command register, with proper
+ *	synchronization with interrupt handler / other threads.
+ *
+ *	LOCKING:
+ *	Obtains host_set lock.
+ */
+
+static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	unsigned long flags;
+
+	DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command);
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	ap->ops->exec_command(ap, tf);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+}
+
+/**
+ *	ata_tf_to_host - issue ATA taskfile to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues ATA taskfile register set to ATA host controller,
+ *	with proper synchronization with interrupt handler and
+ *	other threads.
+ *
+ *	LOCKING:
+ *	Obtains host_set lock.
+ */
+
+static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	ap->ops->tf_load(ap, tf);
+
+	ata_exec(ap, tf);
+}
+
+/**
+ *	ata_tf_to_host_nolock - issue ATA taskfile to host controller
+ *	@ap: port to which command is being issued
+ *	@tf: ATA taskfile register set
+ *
+ *	Issues ATA taskfile register set to ATA host controller,
+ *	with proper synchronization with interrupt handler and
+ *	other threads.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	ap->ops->tf_load(ap, tf);
+	ap->ops->exec_command(ap, tf);
+}
+
+/**
+ *	ata_tf_read - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_read_pio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->nsect = inb(ioaddr->nsect_addr);
+	tf->lbal = inb(ioaddr->lbal_addr);
+	tf->lbam = inb(ioaddr->lbam_addr);
+	tf->lbah = inb(ioaddr->lbah_addr);
+	tf->device = inb(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		outb(tf->ctl | ATA_HOB, ioaddr->ctl_addr);
+		tf->hob_feature = inb(ioaddr->error_addr);
+		tf->hob_nsect = inb(ioaddr->nsect_addr);
+		tf->hob_lbal = inb(ioaddr->lbal_addr);
+		tf->hob_lbam = inb(ioaddr->lbam_addr);
+		tf->hob_lbah = inb(ioaddr->lbah_addr);
+	}
+}
+
+/**
+ *	ata_tf_read_mmio - input device's ATA taskfile shadow registers
+ *	@ap: Port from which input is read
+ *	@tf: ATA taskfile register set for storing input
+ *
+ *	Reads ATA taskfile registers for currently-selected device
+ *	into @tf via MMIO.
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+static void ata_tf_read_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	tf->nsect = readb((void __iomem *)ioaddr->nsect_addr);
+	tf->lbal = readb((void __iomem *)ioaddr->lbal_addr);
+	tf->lbam = readb((void __iomem *)ioaddr->lbam_addr);
+	tf->lbah = readb((void __iomem *)ioaddr->lbah_addr);
+	tf->device = readb((void __iomem *)ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		writeb(tf->ctl | ATA_HOB, (void __iomem *) ap->ioaddr.ctl_addr);
+		tf->hob_feature = readb((void __iomem *)ioaddr->error_addr);
+		tf->hob_nsect = readb((void __iomem *)ioaddr->nsect_addr);
+		tf->hob_lbal = readb((void __iomem *)ioaddr->lbal_addr);
+		tf->hob_lbam = readb((void __iomem *)ioaddr->lbam_addr);
+		tf->hob_lbah = readb((void __iomem *)ioaddr->lbah_addr);
+	}
+}
+
+void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_tf_read_mmio(ap, tf);
+	else
+		ata_tf_read_pio(ap, tf);
+}
+
+/**
+ *	ata_check_status_pio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	and return it's value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+static u8 ata_check_status_pio(struct ata_port *ap)
+{
+	return inb(ap->ioaddr.status_addr);
+}
+
+/**
+ *	ata_check_status_mmio - Read device status reg & clear interrupt
+ *	@ap: port where the device is
+ *
+ *	Reads ATA taskfile status register for currently-selected device
+ *	via MMIO and return it's value. This also clears pending interrupts
+ *      from this device
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+static u8 ata_check_status_mmio(struct ata_port *ap)
+{
+       	return readb((void __iomem *) ap->ioaddr.status_addr);
+}
+
+u8 ata_check_status(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return ata_check_status_mmio(ap);
+	return ata_check_status_pio(ap);
+}
+
+u8 ata_altstatus(struct ata_port *ap)
+{
+	if (ap->ops->check_altstatus)
+		return ap->ops->check_altstatus(ap);
+
+	if (ap->flags & ATA_FLAG_MMIO)
+		return readb((void __iomem *)ap->ioaddr.altstatus_addr);
+	return inb(ap->ioaddr.altstatus_addr);
+}
+
+u8 ata_chk_err(struct ata_port *ap)
+{
+	if (ap->ops->check_err)
+		return ap->ops->check_err(ap);
+
+	if (ap->flags & ATA_FLAG_MMIO) {
+		return readb((void __iomem *) ap->ioaddr.error_addr);
+	}
+	return inb(ap->ioaddr.error_addr);
+}
+
+/**
+ *	ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
+ *	@tf: Taskfile to convert
+ *	@fis: Buffer into which data will output
+ *	@pmp: Port multiplier port
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp)
+{
+	fis[0] = 0x27;	/* Register - Host to Device FIS */
+	fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number,
+					    bit 7 indicates Command FIS */
+	fis[2] = tf->command;
+	fis[3] = tf->feature;
+
+	fis[4] = tf->lbal;
+	fis[5] = tf->lbam;
+	fis[6] = tf->lbah;
+	fis[7] = tf->device;
+
+	fis[8] = tf->hob_lbal;
+	fis[9] = tf->hob_lbam;
+	fis[10] = tf->hob_lbah;
+	fis[11] = tf->hob_feature;
+
+	fis[12] = tf->nsect;
+	fis[13] = tf->hob_nsect;
+	fis[14] = 0;
+	fis[15] = tf->ctl;
+
+	fis[16] = 0;
+	fis[17] = 0;
+	fis[18] = 0;
+	fis[19] = 0;
+}
+
+/**
+ *	ata_tf_from_fis - Convert SATA FIS to ATA taskfile
+ *	@fis: Buffer from which data will be input
+ *	@tf: Taskfile to output
+ *
+ *	Converts a standard ATA taskfile to a Serial ATA
+ *	FIS structure (Register - Host to Device).
+ *
+ *	LOCKING:
+ *	Inherited from caller.
+ */
+
+void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf)
+{
+	tf->command	= fis[2];	/* status */
+	tf->feature	= fis[3];	/* error */
+
+	tf->lbal	= fis[4];
+	tf->lbam	= fis[5];
+	tf->lbah	= fis[6];
+	tf->device	= fis[7];
+
+	tf->hob_lbal	= fis[8];
+	tf->hob_lbam	= fis[9];
+	tf->hob_lbah	= fis[10];
+
+	tf->nsect	= fis[12];
+	tf->hob_nsect	= fis[13];
+}
+
+/**
+ *	ata_prot_to_cmd - determine which read/write opcodes to use
+ *	@protocol: ATA_PROT_xxx taskfile protocol
+ *	@lba48: true is lba48 is present
+ *
+ *	Given necessary input, determine which read/write commands
+ *	to use to transfer data.
+ *
+ *	LOCKING:
+ *	None.
+ */
+static int ata_prot_to_cmd(int protocol, int lba48)
+{
+	int rcmd = 0, wcmd = 0;
+
+	switch (protocol) {
+	case ATA_PROT_PIO:
+		if (lba48) {
+			rcmd = ATA_CMD_PIO_READ_EXT;
+			wcmd = ATA_CMD_PIO_WRITE_EXT;
+		} else {
+			rcmd = ATA_CMD_PIO_READ;
+			wcmd = ATA_CMD_PIO_WRITE;
+		}
+		break;
+
+	case ATA_PROT_DMA:
+		if (lba48) {
+			rcmd = ATA_CMD_READ_EXT;
+			wcmd = ATA_CMD_WRITE_EXT;
+		} else {
+			rcmd = ATA_CMD_READ;
+			wcmd = ATA_CMD_WRITE;
+		}
+		break;
+
+	default:
+		return -1;
+	}
+
+	return rcmd | (wcmd << 8);
+}
+
+/**
+ *	ata_dev_set_protocol - set taskfile protocol and r/w commands
+ *	@dev: device to examine and configure
+ *
+ *	Examine the device configuration, after we have
+ *	read the identify-device page and configured the
+ *	data transfer mode.  Set internal state related to
+ *	the ATA taskfile protocol (pio, pio mult, dma, etc.)
+ *	and calculate the proper read/write commands to use.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+static void ata_dev_set_protocol(struct ata_device *dev)
+{
+	int pio = (dev->flags & ATA_DFLAG_PIO);
+	int lba48 = (dev->flags & ATA_DFLAG_LBA48);
+	int proto, cmd;
+
+	if (pio)
+		proto = dev->xfer_protocol = ATA_PROT_PIO;
+	else
+		proto = dev->xfer_protocol = ATA_PROT_DMA;
+
+	cmd = ata_prot_to_cmd(proto, lba48);
+	if (cmd < 0)
+		BUG();
+
+	dev->read_cmd = cmd & 0xff;
+	dev->write_cmd = (cmd >> 8) & 0xff;
+}
+
+static const char * xfer_mode_str[] = {
+	"UDMA/16",
+	"UDMA/25",
+	"UDMA/33",
+	"UDMA/44",
+	"UDMA/66",
+	"UDMA/100",
+	"UDMA/133",
+	"UDMA7",
+	"MWDMA0",
+	"MWDMA1",
+	"MWDMA2",
+	"PIO0",
+	"PIO1",
+	"PIO2",
+	"PIO3",
+	"PIO4",
+};
+
+/**
+ *	ata_udma_string - convert UDMA bit offset to string
+ *	@mask: mask of bits supported; only highest bit counts.
+ *
+ *	Determine string which represents the highest speed
+ *	(highest bit in @udma_mask).
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Constant C string representing highest speed listed in
+ *	@udma_mask, or the constant C string "<n/a>".
+ */
+
+static const char *ata_mode_string(unsigned int mask)
+{
+	int i;
+
+	for (i = 7; i >= 0; i--)
+		if (mask & (1 << i))
+			goto out;
+	for (i = ATA_SHIFT_MWDMA + 2; i >= ATA_SHIFT_MWDMA; i--)
+		if (mask & (1 << i))
+			goto out;
+	for (i = ATA_SHIFT_PIO + 4; i >= ATA_SHIFT_PIO; i--)
+		if (mask & (1 << i))
+			goto out;
+
+	return "<n/a>";
+
+out:
+	return xfer_mode_str[i];
+}
+
+/**
+ *	ata_pio_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	This technique was originally described in
+ *	Hale Landis's ATADRVR (www.ata-atapi.com), and
+ *	later found its way into the ATA/ATAPI spec.
+ *
+ *	Write a pattern to the ATA shadow registers,
+ *	and if a device is present, it will respond by
+ *	correctly storing and echoing back the
+ *	ATA shadow register contents.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_pio_devchk(struct ata_port *ap,
+				   unsigned int device)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u8 nsect, lbal;
+
+	ap->ops->dev_select(ap, device);
+
+	outb(0x55, ioaddr->nsect_addr);
+	outb(0xaa, ioaddr->lbal_addr);
+
+	outb(0xaa, ioaddr->nsect_addr);
+	outb(0x55, ioaddr->lbal_addr);
+
+	outb(0x55, ioaddr->nsect_addr);
+	outb(0xaa, ioaddr->lbal_addr);
+
+	nsect = inb(ioaddr->nsect_addr);
+	lbal = inb(ioaddr->lbal_addr);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+
+	return 0;		/* nothing found */
+}
+
+/**
+ *	ata_mmio_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	This technique was originally described in
+ *	Hale Landis's ATADRVR (www.ata-atapi.com), and
+ *	later found its way into the ATA/ATAPI spec.
+ *
+ *	Write a pattern to the ATA shadow registers,
+ *	and if a device is present, it will respond by
+ *	correctly storing and echoing back the
+ *	ATA shadow register contents.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_mmio_devchk(struct ata_port *ap,
+				    unsigned int device)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u8 nsect, lbal;
+
+	ap->ops->dev_select(ap, device);
+
+	writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+
+	writeb(0xaa, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0x55, (void __iomem *) ioaddr->lbal_addr);
+
+	writeb(0x55, (void __iomem *) ioaddr->nsect_addr);
+	writeb(0xaa, (void __iomem *) ioaddr->lbal_addr);
+
+	nsect = readb((void __iomem *) ioaddr->nsect_addr);
+	lbal = readb((void __iomem *) ioaddr->lbal_addr);
+
+	if ((nsect == 0x55) && (lbal == 0xaa))
+		return 1;	/* we found a device */
+
+	return 0;		/* nothing found */
+}
+
+/**
+ *	ata_devchk - PATA device presence detection
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	Dispatch ATA device presence detection, depending
+ *	on whether we are using PIO or MMIO to talk to the
+ *	ATA shadow registers.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static unsigned int ata_devchk(struct ata_port *ap,
+				    unsigned int device)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		return ata_mmio_devchk(ap, device);
+	return ata_pio_devchk(ap, device);
+}
+
+/**
+ *	ata_dev_classify - determine device type based on ATA-spec signature
+ *	@tf: ATA taskfile register set for device to be identified
+ *
+ *	Determine from taskfile register contents whether a device is
+ *	ATA or ATAPI, as per "Signature and persistence" section
+ *	of ATA/PI spec (volume 1, sect 5.14).
+ *
+ *	LOCKING:
+ *	None.
+ *
+ *	RETURNS:
+ *	Device type, %ATA_DEV_ATA, %ATA_DEV_ATAPI, or %ATA_DEV_UNKNOWN
+ *	the event of failure.
+ */
+
+unsigned int ata_dev_classify(struct ata_taskfile *tf)
+{
+	/* Apple's open source Darwin code hints that some devices only
+	 * put a proper signature into the LBA mid/high registers,
+	 * So, we only check those.  It's sufficient for uniqueness.
+	 */
+
+	if (((tf->lbam == 0) && (tf->lbah == 0)) ||
+	    ((tf->lbam == 0x3c) && (tf->lbah == 0xc3))) {
+		DPRINTK("found ATA device by sig\n");
+		return ATA_DEV_ATA;
+	}
+
+	if (((tf->lbam == 0x14) && (tf->lbah == 0xeb)) ||
+	    ((tf->lbam == 0x69) && (tf->lbah == 0x96))) {
+		DPRINTK("found ATAPI device by sig\n");
+		return ATA_DEV_ATAPI;
+	}
+
+	DPRINTK("unknown device\n");
+	return ATA_DEV_UNKNOWN;
+}
+
+/**
+ *	ata_dev_try_classify - Parse returned ATA device signature
+ *	@ap: ATA channel to examine
+ *	@device: Device to examine (starting at zero)
+ *
+ *	After an event -- SRST, E.D.D., or SATA COMRESET -- occurs,
+ *	an ATA/ATAPI-defined set of values is placed in the ATA
+ *	shadow registers, indicating the results of device detection
+ *	and diagnostics.
+ *
+ *	Select the ATA device, and read the values from the ATA shadow
+ *	registers.  Then parse according to the Error register value,
+ *	and the spec-defined values examined by ata_dev_classify().
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static u8 ata_dev_try_classify(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+	struct ata_taskfile tf;
+	unsigned int class;
+	u8 err;
+
+	ap->ops->dev_select(ap, device);
+
+	memset(&tf, 0, sizeof(tf));
+
+	err = ata_chk_err(ap);
+	ap->ops->tf_read(ap, &tf);
+
+	dev->class = ATA_DEV_NONE;
+
+	/* see if device passed diags */
+	if (err == 1)
+		/* do nothing */ ;
+	else if ((device == 0) && (err == 0x81))
+		/* do nothing */ ;
+	else
+		return err;
+
+	/* determine if device if ATA or ATAPI */
+	class = ata_dev_classify(&tf);
+	if (class == ATA_DEV_UNKNOWN)
+		return err;
+	if ((class == ATA_DEV_ATA) && (ata_chk_status(ap) == 0))
+		return err;
+
+	dev->class = class;
+
+	return err;
+}
+
+/**
+ *	ata_dev_id_string - Convert IDENTIFY DEVICE page into string
+ *	@id: IDENTIFY DEVICE results we will examine
+ *	@s: string into which data is output
+ *	@ofs: offset into identify device page
+ *	@len: length of string to return. must be an even number.
+ *
+ *	The strings in the IDENTIFY DEVICE page are broken up into
+ *	16-bit chunks.  Run through the string, and output each
+ *	8-bit chunk linearly, regardless of platform.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+void ata_dev_id_string(u16 *id, unsigned char *s,
+		       unsigned int ofs, unsigned int len)
+{
+	unsigned int c;
+
+	while (len > 0) {
+		c = id[ofs] >> 8;
+		*s = c;
+		s++;
+
+		c = id[ofs] & 0xff;
+		*s = c;
+		s++;
+
+		ofs++;
+		len -= 2;
+	}
+}
+
+void ata_noop_dev_select (struct ata_port *ap, unsigned int device)
+{
+}
+
+/**
+ *	ata_std_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *
+ *	Use the method defined in the ATA specification to
+ *	make either device 0, or device 1, active on the
+ *	ATA channel.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+void ata_std_dev_select (struct ata_port *ap, unsigned int device)
+{
+	u8 tmp;
+
+	if (device == 0)
+		tmp = ATA_DEVICE_OBS;
+	else
+		tmp = ATA_DEVICE_OBS | ATA_DEV1;
+
+	if (ap->flags & ATA_FLAG_MMIO) {
+		writeb(tmp, (void __iomem *) ap->ioaddr.device_addr);
+	} else {
+		outb(tmp, ap->ioaddr.device_addr);
+	}
+	ata_pause(ap);		/* needed; also flushes, for mmio */
+}
+
+/**
+ *	ata_dev_select - Select device 0/1 on ATA bus
+ *	@ap: ATA channel to manipulate
+ *	@device: ATA device (numbered from zero) to select
+ *	@wait: non-zero to wait for Status register BSY bit to clear
+ *	@can_sleep: non-zero if context allows sleeping
+ *
+ *	Use the method defined in the ATA specification to
+ *	make either device 0, or device 1, active on the
+ *	ATA channel.
+ *
+ *	This is a high-level version of ata_std_dev_select(),
+ *	which additionally provides the services of inserting
+ *	the proper pauses and status polling, where needed.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+void ata_dev_select(struct ata_port *ap, unsigned int device,
+			   unsigned int wait, unsigned int can_sleep)
+{
+	VPRINTK("ENTER, ata%u: device %u, wait %u\n",
+		ap->id, device, wait);
+
+	if (wait)
+		ata_wait_idle(ap);
+
+	ap->ops->dev_select(ap, device);
+
+	if (wait) {
+		if (can_sleep && ap->device[device].class == ATA_DEV_ATAPI)
+			msleep(150);
+		ata_wait_idle(ap);
+	}
+}
+
+/**
+ *	ata_dump_id - IDENTIFY DEVICE info debugging output
+ *	@dev: Device whose IDENTIFY DEVICE page we will dump
+ *
+ *	Dump selected 16-bit words from a detected device's
+ *	IDENTIFY PAGE page.
+ *
+ *	LOCKING:
+ *	caller.
+ */
+
+static inline void ata_dump_id(struct ata_device *dev)
+{
+	DPRINTK("49==0x%04x  "
+		"53==0x%04x  "
+		"63==0x%04x  "
+		"64==0x%04x  "
+		"75==0x%04x  \n",
+		dev->id[49],
+		dev->id[53],
+		dev->id[63],
+		dev->id[64],
+		dev->id[75]);
+	DPRINTK("80==0x%04x  "
+		"81==0x%04x  "
+		"82==0x%04x  "
+		"83==0x%04x  "
+		"84==0x%04x  \n",
+		dev->id[80],
+		dev->id[81],
+		dev->id[82],
+		dev->id[83],
+		dev->id[84]);
+	DPRINTK("88==0x%04x  "
+		"93==0x%04x\n",
+		dev->id[88],
+		dev->id[93]);
+}
+
+/**
+ *	ata_dev_identify - obtain IDENTIFY x DEVICE page
+ *	@ap: port on which device we wish to probe resides
+ *	@device: device bus address, starting at zero
+ *
+ *	Following bus reset, we issue the IDENTIFY [PACKET] DEVICE
+ *	command, and read back the 512-byte device information page.
+ *	The device information page is fed to us via the standard
+ *	PIO-IN protocol, but we hand-code it here. (TODO: investigate
+ *	using standard PIO-IN paths)
+ *
+ *	After reading the device information page, we use several
+ *	bits of information from it to initialize data structures
+ *	that will be used during the lifetime of the ata_device.
+ *	Other data from the info page is used to disqualify certain
+ *	older ATA devices we do not wish to support.
+ *
+ *	LOCKING:
+ *	Inherited from caller.  Some functions called by this function
+ *	obtain the host_set lock.
+ */
+
+static void ata_dev_identify(struct ata_port *ap, unsigned int device)
+{
+	struct ata_device *dev = &ap->device[device];
+	unsigned int i;
+	u16 tmp;
+	unsigned long xfer_modes;
+	u8 status;
+	unsigned int using_edd;
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	unsigned long flags;
+	int rc;
+
+	if (!ata_dev_present(dev)) {
+		DPRINTK("ENTER/EXIT (host %u, dev %u) -- nodev\n",
+			ap->id, device);
+		return;
+	}
+
+	if (ap->flags & (ATA_FLAG_SRST | ATA_FLAG_SATA_RESET))
+		using_edd = 0;
+	else
+		using_edd = 1;
+
+	DPRINTK("ENTER, host %u, dev %u\n", ap->id, device);
+
+	assert (dev->class == ATA_DEV_ATA || dev->class == ATA_DEV_ATAPI ||
+		dev->class == ATA_DEV_NONE);
+
+	ata_dev_select(ap, device, 1, 1); /* select device 0/1 */
+
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
+
+	ata_sg_init_one(qc, dev->id, sizeof(dev->id));
+	qc->dma_dir = DMA_FROM_DEVICE;
+	qc->tf.protocol = ATA_PROT_PIO;
+	qc->nsect = 1;
+
+retry:
+	if (dev->class == ATA_DEV_ATA) {
+		qc->tf.command = ATA_CMD_ID_ATA;
+		DPRINTK("do ATA identify\n");
+	} else {
+		qc->tf.command = ATA_CMD_ID_ATAPI;
+		DPRINTK("do ATAPI identify\n");
+	}
+
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	if (rc)
+		goto err_out;
+	else
+		wait_for_completion(&wait);
+
+	status = ata_chk_status(ap);
+	if (status & ATA_ERR) {
+		/*
+		 * arg!  EDD works for all test cases, but seems to return
+		 * the ATA signature for some ATAPI devices.  Until the
+		 * reason for this is found and fixed, we fix up the mess
+		 * here.  If IDENTIFY DEVICE returns command aborted
+		 * (as ATAPI devices do), then we issue an
+		 * IDENTIFY PACKET DEVICE.
+		 *
+		 * ATA software reset (SRST, the default) does not appear
+		 * to have this problem.
+		 */
+		if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) {
+			u8 err = ata_chk_err(ap);
+			if (err & ATA_ABORTED) {
+				dev->class = ATA_DEV_ATAPI;
+				qc->cursg = 0;
+				qc->cursg_ofs = 0;
+				qc->cursect = 0;
+				qc->nsect = 1;
+				goto retry;
+			}
+		}
+		goto err_out;
+	}
+
+	swap_buf_le16(dev->id, ATA_ID_WORDS);
+
+	/* print device capabilities */
+	printk(KERN_DEBUG "ata%u: dev %u cfg "
+	       "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n",
+	       ap->id, device, dev->id[49],
+	       dev->id[82], dev->id[83], dev->id[84],
+	       dev->id[85], dev->id[86], dev->id[87],
+	       dev->id[88]);
+
+	/*
+	 * common ATA, ATAPI feature tests
+	 */
+
+	/* we require LBA and DMA support (bits 8 & 9 of word 49) */
+	if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) {
+		printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id);
+		goto err_out_nosup;
+	}
+
+	/* quick-n-dirty find max transfer mode; for printk only */
+	xfer_modes = dev->id[ATA_ID_UDMA_MODES];
+	if (!xfer_modes)
+		xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA;
+	if (!xfer_modes) {
+		xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3);
+		xfer_modes |= (0x7 << ATA_SHIFT_PIO);
+	}
+
+	ata_dump_id(dev);
+
+	/* ATA-specific feature tests */
+	if (dev->class == ATA_DEV_ATA) {
+		if (!ata_id_is_ata(dev->id))	/* sanity check */
+			goto err_out_nosup;
+
+		tmp = dev->id[ATA_ID_MAJOR_VER];
+		for (i = 14; i >= 1; i--)
+			if (tmp & (1 << i))
+				break;
+
+		/* we require at least ATA-3 */
+		if (i < 3) {
+			printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id);
+			goto err_out_nosup;
+		}
+
+		if (ata_id_has_lba48(dev->id)) {
+			dev->flags |= ATA_DFLAG_LBA48;
+			dev->n_sectors = ata_id_u64(dev->id, 100);
+		} else {
+			dev->n_sectors = ata_id_u32(dev->id, 60);
+		}
+
+		ap->host->max_cmd_len = 16;
+
+		/* print device info to dmesg */
+		printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n",
+		       ap->id, device,
+		       ata_mode_string(xfer_modes),
+		       (unsigned long long)dev->n_sectors,
+		       dev->flags & ATA_DFLAG_LBA48 ? " lba48" : "");
+	}
+
+	/* ATAPI-specific feature tests */
+	else {
+		if (ata_id_is_ata(dev->id))		/* sanity check */
+			goto err_out_nosup;
+
+		rc = atapi_cdb_len(dev->id);
+		if ((rc < 12) || (rc > ATAPI_CDB_LEN)) {
+			printk(KERN_WARNING "ata%u: unsupported CDB len\n", ap->id);
+			goto err_out_nosup;
+		}
+		ap->cdb_len = (unsigned int) rc;
+		ap->host->max_cmd_len = (unsigned char) ap->cdb_len;
+
+		/* print device info to dmesg */
+		printk(KERN_INFO "ata%u: dev %u ATAPI, max %s\n",
+		       ap->id, device,
+		       ata_mode_string(xfer_modes));
+	}
+
+	DPRINTK("EXIT, drv_stat = 0x%x\n", ata_chk_status(ap));
+	return;
+
+err_out_nosup:
+	printk(KERN_WARNING "ata%u: dev %u not supported, ignoring\n",
+	       ap->id, device);
+err_out:
+	dev->class++;	/* converts ATA_DEV_xxx into ATA_DEV_xxx_UNSUP */
+	DPRINTK("EXIT, err\n");
+}
+
+/**
+ *	ata_bus_probe - Reset and probe ATA bus
+ *	@ap: Bus to probe
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static int ata_bus_probe(struct ata_port *ap)
+{
+	unsigned int i, found = 0;
+
+	ap->ops->phy_reset(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		goto err_out;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		ata_dev_identify(ap, i);
+		if (ata_dev_present(&ap->device[i])) {
+			found = 1;
+			if (ap->ops->dev_config)
+				ap->ops->dev_config(ap, &ap->device[i]);
+		}
+	}
+
+	if ((!found) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		goto err_out_disable;
+
+	ata_set_mode(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		goto err_out_disable;
+
+	return 0;
+
+err_out_disable:
+	ap->ops->port_disable(ap);
+err_out:
+	return -1;
+}
+
+/**
+ *	ata_port_probe -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+void ata_port_probe(struct ata_port *ap)
+{
+	ap->flags &= ~ATA_FLAG_PORT_DISABLED;
+}
+
+/**
+ *	__sata_phy_reset -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ */
+void __sata_phy_reset(struct ata_port *ap)
+{
+	u32 sstatus;
+	unsigned long timeout = jiffies + (HZ * 5);
+
+	if (ap->flags & ATA_FLAG_SATA_RESET) {
+		scr_write(ap, SCR_CONTROL, 0x301); /* issue phy wake/reset */
+		scr_read(ap, SCR_STATUS);	/* dummy read; flush */
+		udelay(400);			/* FIXME: a guess */
+	}
+	scr_write(ap, SCR_CONTROL, 0x300);	/* issue phy wake/clear reset */
+
+	/* wait for phy to become ready, if necessary */
+	do {
+		msleep(200);
+		sstatus = scr_read(ap, SCR_STATUS);
+		if ((sstatus & 0xf) != 1)
+			break;
+	} while (time_before(jiffies, timeout));
+
+	/* TODO: phy layer with polling, timeouts, etc. */
+	if (sata_dev_present(ap))
+		ata_port_probe(ap);
+	else {
+		sstatus = scr_read(ap, SCR_STATUS);
+		printk(KERN_INFO "ata%u: no device found (phy stat %08x)\n",
+		       ap->id, sstatus);
+		ata_port_disable(ap);
+	}
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) {
+		ata_port_disable(ap);
+		return;
+	}
+
+	ap->cbl = ATA_CBL_SATA;
+}
+
+/**
+ *	__sata_phy_reset -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ */
+void sata_phy_reset(struct ata_port *ap)
+{
+	__sata_phy_reset(ap);
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+	ata_bus_reset(ap);
+}
+
+/**
+ *	ata_port_disable -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+void ata_port_disable(struct ata_port *ap)
+{
+	ap->device[0].class = ATA_DEV_NONE;
+	ap->device[1].class = ATA_DEV_NONE;
+	ap->flags |= ATA_FLAG_PORT_DISABLED;
+}
+
+static struct {
+	unsigned int shift;
+	u8 base;
+} xfer_mode_classes[] = {
+	{ ATA_SHIFT_UDMA,	XFER_UDMA_0 },
+	{ ATA_SHIFT_MWDMA,	XFER_MW_DMA_0 },
+	{ ATA_SHIFT_PIO,	XFER_PIO_0 },
+};
+
+static inline u8 base_from_shift(unsigned int shift)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++)
+		if (xfer_mode_classes[i].shift == shift)
+			return xfer_mode_classes[i].base;
+
+	return 0xff;
+}
+
+static void ata_dev_set_mode(struct ata_port *ap, struct ata_device *dev)
+{
+	int ofs, idx;
+	u8 base;
+
+	if (!ata_dev_present(dev) || (ap->flags & ATA_FLAG_PORT_DISABLED))
+		return;
+
+	if (dev->xfer_shift == ATA_SHIFT_PIO)
+		dev->flags |= ATA_DFLAG_PIO;
+
+	ata_dev_set_xfermode(ap, dev);
+
+	base = base_from_shift(dev->xfer_shift);
+	ofs = dev->xfer_mode - base;
+	idx = ofs + dev->xfer_shift;
+	WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
+
+	DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
+		idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
+
+	printk(KERN_INFO "ata%u: dev %u configured for %s\n",
+		ap->id, dev->devno, xfer_mode_str[idx]);
+}
+
+static int ata_host_set_pio(struct ata_port *ap)
+{
+	unsigned int mask;
+	int x, i;
+	u8 base, xfer_mode;
+
+	mask = ata_get_mode_mask(ap, ATA_SHIFT_PIO);
+	x = fgb(mask);
+	if (x < 0) {
+		printk(KERN_WARNING "ata%u: no PIO support\n", ap->id);
+		return -1;
+	}
+
+	base = base_from_shift(ATA_SHIFT_PIO);
+	xfer_mode = base + x;
+
+	DPRINTK("base 0x%x xfer_mode 0x%x mask 0x%x x %d\n",
+		(int)base, (int)xfer_mode, mask, x);
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		if (ata_dev_present(dev)) {
+			dev->pio_mode = xfer_mode;
+			dev->xfer_mode = xfer_mode;
+			dev->xfer_shift = ATA_SHIFT_PIO;
+			if (ap->ops->set_piomode)
+				ap->ops->set_piomode(ap, dev);
+		}
+	}
+
+	return 0;
+}
+
+static void ata_host_set_dma(struct ata_port *ap, u8 xfer_mode,
+			    unsigned int xfer_shift)
+{
+	int i;
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++) {
+		struct ata_device *dev = &ap->device[i];
+		if (ata_dev_present(dev)) {
+			dev->dma_mode = xfer_mode;
+			dev->xfer_mode = xfer_mode;
+			dev->xfer_shift = xfer_shift;
+			if (ap->ops->set_dmamode)
+				ap->ops->set_dmamode(ap, dev);
+		}
+	}
+}
+
+/**
+ *	ata_set_mode - Program timings and issue SET FEATURES - XFER
+ *	@ap: port on which timings will be programmed
+ *
+ *	LOCKING:
+ *
+ */
+static void ata_set_mode(struct ata_port *ap)
+{
+	unsigned int i, xfer_shift;
+	u8 xfer_mode;
+	int rc;
+
+	/* step 1: always set host PIO timings */
+	rc = ata_host_set_pio(ap);
+	if (rc)
+		goto err_out;
+
+	/* step 2: choose the best data xfer mode */
+	xfer_mode = xfer_shift = 0;
+	rc = ata_choose_xfer_mode(ap, &xfer_mode, &xfer_shift);
+	if (rc)
+		goto err_out;
+
+	/* step 3: if that xfer mode isn't PIO, set host DMA timings */
+	if (xfer_shift != ATA_SHIFT_PIO)
+		ata_host_set_dma(ap, xfer_mode, xfer_shift);
+
+	/* step 4: update devices' xfer mode */
+	ata_dev_set_mode(ap, &ap->device[0]);
+	ata_dev_set_mode(ap, &ap->device[1]);
+
+	if (ap->flags & ATA_FLAG_PORT_DISABLED)
+		return;
+
+	if (ap->ops->post_set_mode)
+		ap->ops->post_set_mode(ap);
+
+	for (i = 0; i < 2; i++) {
+		struct ata_device *dev = &ap->device[i];
+		ata_dev_set_protocol(dev);
+	}
+
+	return;
+
+err_out:
+	ata_port_disable(ap);
+}
+
+/**
+ *	ata_busy_sleep - sleep until BSY clears, or timeout
+ *	@ap: port containing status register to be polled
+ *	@tmout_pat: impatience timeout
+ *	@tmout: overall timeout
+ *
+ *	LOCKING:
+ *
+ */
+
+static unsigned int ata_busy_sleep (struct ata_port *ap,
+				    unsigned long tmout_pat,
+			    	    unsigned long tmout)
+{
+	unsigned long timer_start, timeout;
+	u8 status;
+
+	status = ata_busy_wait(ap, ATA_BUSY, 300);
+	timer_start = jiffies;
+	timeout = timer_start + tmout_pat;
+	while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+		msleep(50);
+		status = ata_busy_wait(ap, ATA_BUSY, 3);
+	}
+
+	if (status & ATA_BUSY)
+		printk(KERN_WARNING "ata%u is slow to respond, "
+		       "please be patient\n", ap->id);
+
+	timeout = timer_start + tmout;
+	while ((status & ATA_BUSY) && (time_before(jiffies, timeout))) {
+		msleep(50);
+		status = ata_chk_status(ap);
+	}
+
+	if (status & ATA_BUSY) {
+		printk(KERN_ERR "ata%u failed to respond (%lu secs)\n",
+		       ap->id, tmout / HZ);
+		return 1;
+	}
+
+	return 0;
+}
+
+static void ata_bus_post_reset(struct ata_port *ap, unsigned int devmask)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int dev0 = devmask & (1 << 0);
+	unsigned int dev1 = devmask & (1 << 1);
+	unsigned long timeout;
+
+	/* if device 0 was found in ata_devchk, wait for its
+	 * BSY bit to clear
+	 */
+	if (dev0)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* if device 1 was found in ata_devchk, wait for
+	 * register access, then wait for BSY to clear
+	 */
+	timeout = jiffies + ATA_TMOUT_BOOT;
+	while (dev1) {
+		u8 nsect, lbal;
+
+		ap->ops->dev_select(ap, 1);
+		if (ap->flags & ATA_FLAG_MMIO) {
+			nsect = readb((void __iomem *) ioaddr->nsect_addr);
+			lbal = readb((void __iomem *) ioaddr->lbal_addr);
+		} else {
+			nsect = inb(ioaddr->nsect_addr);
+			lbal = inb(ioaddr->lbal_addr);
+		}
+		if ((nsect == 1) && (lbal == 1))
+			break;
+		if (time_after(jiffies, timeout)) {
+			dev1 = 0;
+			break;
+		}
+		msleep(50);	/* give drive a breather */
+	}
+	if (dev1)
+		ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+
+	/* is all this really necessary? */
+	ap->ops->dev_select(ap, 0);
+	if (dev1)
+		ap->ops->dev_select(ap, 1);
+	if (dev0)
+		ap->ops->dev_select(ap, 0);
+}
+
+/**
+ *	ata_bus_edd -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ */
+
+static unsigned int ata_bus_edd(struct ata_port *ap)
+{
+	struct ata_taskfile tf;
+
+	/* set up execute-device-diag (bus reset) taskfile */
+	/* also, take interrupts to a known state (disabled) */
+	DPRINTK("execute-device-diag\n");
+	ata_tf_init(ap, &tf, 0);
+	tf.ctl |= ATA_NIEN;
+	tf.command = ATA_CMD_EDD;
+	tf.protocol = ATA_PROT_NODATA;
+
+	/* do bus reset */
+	ata_tf_to_host(ap, &tf);
+
+	/* spec says at least 2ms.  but who knows with those
+	 * crazy ATAPI devices...
+	 */
+	msleep(150);
+
+	return ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT);
+}
+
+static unsigned int ata_bus_softreset(struct ata_port *ap,
+				      unsigned int devmask)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+
+	DPRINTK("ata%u: bus reset via SRST\n", ap->id);
+
+	/* software reset.  causes dev0 to be selected */
+	if (ap->flags & ATA_FLAG_MMIO) {
+		writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+		udelay(20);	/* FIXME: flush */
+		writeb(ap->ctl | ATA_SRST, (void __iomem *) ioaddr->ctl_addr);
+		udelay(20);	/* FIXME: flush */
+		writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+	} else {
+		outb(ap->ctl, ioaddr->ctl_addr);
+		udelay(10);
+		outb(ap->ctl | ATA_SRST, ioaddr->ctl_addr);
+		udelay(10);
+		outb(ap->ctl, ioaddr->ctl_addr);
+	}
+
+	/* spec mandates ">= 2ms" before checking status.
+	 * We wait 150ms, because that was the magic delay used for
+	 * ATAPI devices in Hale Landis's ATADRVR, for the period of time
+	 * between when the ATA command register is written, and then
+	 * status is checked.  Because waiting for "a while" before
+	 * checking status is fine, post SRST, we perform this magic
+	 * delay here as well.
+	 */
+	msleep(150);
+
+	ata_bus_post_reset(ap, devmask);
+
+	return 0;
+}
+
+/**
+ *	ata_bus_reset - reset host port and associated ATA channel
+ *	@ap: port to reset
+ *
+ *	This is typically the first time we actually start issuing
+ *	commands to the ATA channel.  We wait for BSY to clear, then
+ *	issue EXECUTE DEVICE DIAGNOSTIC command, polling for its
+ *	result.  Determine what devices, if any, are on the channel
+ *	by looking at the device 0/1 error register.  Look at the signature
+ *	stored in each device's taskfile registers, to determine if
+ *	the device is ATA or ATAPI.
+ *
+ *	LOCKING:
+ *	Inherited from caller.  Some functions called by this function
+ *	obtain the host_set lock.
+ *
+ *	SIDE EFFECTS:
+ *	Sets ATA_FLAG_PORT_DISABLED if bus reset fails.
+ */
+
+void ata_bus_reset(struct ata_port *ap)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int slave_possible = ap->flags & ATA_FLAG_SLAVE_POSS;
+	u8 err;
+	unsigned int dev0, dev1 = 0, rc = 0, devmask = 0;
+
+	DPRINTK("ENTER, host %u, port %u\n", ap->id, ap->port_no);
+
+	/* determine if device 0/1 are present */
+	if (ap->flags & ATA_FLAG_SATA_RESET)
+		dev0 = 1;
+	else {
+		dev0 = ata_devchk(ap, 0);
+		if (slave_possible)
+			dev1 = ata_devchk(ap, 1);
+	}
+
+	if (dev0)
+		devmask |= (1 << 0);
+	if (dev1)
+		devmask |= (1 << 1);
+
+	/* select device 0 again */
+	ap->ops->dev_select(ap, 0);
+
+	/* issue bus reset */
+	if (ap->flags & ATA_FLAG_SRST)
+		rc = ata_bus_softreset(ap, devmask);
+	else if ((ap->flags & ATA_FLAG_SATA_RESET) == 0) {
+		/* set up device control */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
+		rc = ata_bus_edd(ap);
+	}
+
+	if (rc)
+		goto err_out;
+
+	/*
+	 * determine by signature whether we have ATA or ATAPI devices
+	 */
+	err = ata_dev_try_classify(ap, 0);
+	if ((slave_possible) && (err != 0x81))
+		ata_dev_try_classify(ap, 1);
+
+	/* re-enable interrupts */
+	if (ap->ioaddr.ctl_addr)	/* FIXME: hack. create a hook instead */
+		ata_irq_on(ap);
+
+	/* is double-select really necessary? */
+	if (ap->device[1].class != ATA_DEV_NONE)
+		ap->ops->dev_select(ap, 1);
+	if (ap->device[0].class != ATA_DEV_NONE)
+		ap->ops->dev_select(ap, 0);
+
+	/* if no devices were detected, disable this port */
+	if ((ap->device[0].class == ATA_DEV_NONE) &&
+	    (ap->device[1].class == ATA_DEV_NONE))
+		goto err_out;
+
+	if (ap->flags & (ATA_FLAG_SATA_RESET | ATA_FLAG_SRST)) {
+		/* set up device control for ATA_FLAG_SATA_RESET */
+		if (ap->flags & ATA_FLAG_MMIO)
+			writeb(ap->ctl, (void __iomem *) ioaddr->ctl_addr);
+		else
+			outb(ap->ctl, ioaddr->ctl_addr);
+	}
+
+	DPRINTK("EXIT\n");
+	return;
+
+err_out:
+	printk(KERN_ERR "ata%u: disabling port\n", ap->id);
+	ap->ops->port_disable(ap);
+
+	DPRINTK("EXIT\n");
+}
+
+static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev)
+{
+	printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n",
+		ap->id, dev->devno);
+}
+
+static const char * ata_dma_blacklist [] = {
+	"WDC AC11000H",
+	"WDC AC22100H",
+	"WDC AC32500H",
+	"WDC AC33100H",
+	"WDC AC31600H",
+	"WDC AC32100H",
+	"WDC AC23200L",
+	"Compaq CRD-8241B",
+	"CRD-8400B",
+	"CRD-8480B",
+	"CRD-8482B",
+ 	"CRD-84",
+	"SanDisk SDP3B",
+	"SanDisk SDP3B-64",
+	"SANYO CD-ROM CRD",
+	"HITACHI CDR-8",
+	"HITACHI CDR-8335",
+	"HITACHI CDR-8435",
+	"Toshiba CD-ROM XM-6202B",
+	"CD-532E-A",
+	"E-IDE CD-ROM CR-840",
+	"CD-ROM Drive/F5A",
+	"WPI CDD-820",
+	"SAMSUNG CD-ROM SC-148C",
+	"SAMSUNG CD-ROM SC",
+	"SanDisk SDP3B-64",
+	"SAMSUNG CD-ROM SN-124",
+	"ATAPI CD-ROM DRIVE 40X MAXIMUM",
+	"_NEC DV5800A",
+};
+
+static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev)
+{
+	unsigned char model_num[40];
+	char *s;
+	unsigned int len;
+	int i;
+
+	ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+			  sizeof(model_num));
+	s = &model_num[0];
+	len = strnlen(s, sizeof(model_num));
+
+	/* ATAPI specifies that empty space is blank-filled; remove blanks */
+	while ((len > 0) && (s[len - 1] == ' ')) {
+		len--;
+		s[len] = 0;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(ata_dma_blacklist); i++)
+		if (!strncmp(ata_dma_blacklist[i], s, len))
+			return 1;
+
+	return 0;
+}
+
+static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift)
+{
+	struct ata_device *master, *slave;
+	unsigned int mask;
+
+	master = &ap->device[0];
+	slave = &ap->device[1];
+
+	assert (ata_dev_present(master) || ata_dev_present(slave));
+
+	if (shift == ATA_SHIFT_UDMA) {
+		mask = ap->udma_mask;
+		if (ata_dev_present(master)) {
+			mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff);
+			if (ata_dma_blacklisted(ap, master)) {
+				mask = 0;
+				ata_pr_blacklisted(ap, master);
+			}
+		}
+		if (ata_dev_present(slave)) {
+			mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff);
+			if (ata_dma_blacklisted(ap, slave)) {
+				mask = 0;
+				ata_pr_blacklisted(ap, slave);
+			}
+		}
+	}
+	else if (shift == ATA_SHIFT_MWDMA) {
+		mask = ap->mwdma_mask;
+		if (ata_dev_present(master)) {
+			mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07);
+			if (ata_dma_blacklisted(ap, master)) {
+				mask = 0;
+				ata_pr_blacklisted(ap, master);
+			}
+		}
+		if (ata_dev_present(slave)) {
+			mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07);
+			if (ata_dma_blacklisted(ap, slave)) {
+				mask = 0;
+				ata_pr_blacklisted(ap, slave);
+			}
+		}
+	}
+	else if (shift == ATA_SHIFT_PIO) {
+		mask = ap->pio_mask;
+		if (ata_dev_present(master)) {
+			/* spec doesn't return explicit support for
+			 * PIO0-2, so we fake it
+			 */
+			u16 tmp_mode = master->id[ATA_ID_PIO_MODES] & 0x03;
+			tmp_mode <<= 3;
+			tmp_mode |= 0x7;
+			mask &= tmp_mode;
+		}
+		if (ata_dev_present(slave)) {
+			/* spec doesn't return explicit support for
+			 * PIO0-2, so we fake it
+			 */
+			u16 tmp_mode = slave->id[ATA_ID_PIO_MODES] & 0x03;
+			tmp_mode <<= 3;
+			tmp_mode |= 0x7;
+			mask &= tmp_mode;
+		}
+	}
+	else {
+		mask = 0xffffffff; /* shut up compiler warning */
+		BUG();
+	}
+
+	return mask;
+}
+
+/* find greatest bit */
+static int fgb(u32 bitmap)
+{
+	unsigned int i;
+	int x = -1;
+
+	for (i = 0; i < 32; i++)
+		if (bitmap & (1 << i))
+			x = i;
+
+	return x;
+}
+
+/**
+ *	ata_choose_xfer_mode - attempt to find best transfer mode
+ *	@ap: Port for which an xfer mode will be selected
+ *	@xfer_mode_out: (output) SET FEATURES - XFER MODE code
+ *	@xfer_shift_out: (output) bit shift that selects this mode
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+static int ata_choose_xfer_mode(struct ata_port *ap,
+				u8 *xfer_mode_out,
+				unsigned int *xfer_shift_out)
+{
+	unsigned int mask, shift;
+	int x, i;
+
+	for (i = 0; i < ARRAY_SIZE(xfer_mode_classes); i++) {
+		shift = xfer_mode_classes[i].shift;
+		mask = ata_get_mode_mask(ap, shift);
+
+		x = fgb(mask);
+		if (x >= 0) {
+			*xfer_mode_out = xfer_mode_classes[i].base + x;
+			*xfer_shift_out = shift;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+/**
+ *	ata_dev_set_xfermode - Issue SET FEATURES - XFER MODE command
+ *	@ap: Port associated with device @dev
+ *	@dev: Device to which command will be sent
+ *
+ *	LOCKING:
+ */
+
+static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev)
+{
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	int rc;
+	unsigned long flags;
+
+	/* set up set-features taskfile */
+	DPRINTK("set features - xfer mode\n");
+
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
+
+	qc->tf.command = ATA_CMD_SET_FEATURES;
+	qc->tf.feature = SETFEATURES_XFER;
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	qc->tf.protocol = ATA_PROT_NODATA;
+	qc->tf.nsect = dev->xfer_mode;
+
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	if (rc)
+		ata_port_disable(ap);
+	else
+		wait_for_completion(&wait);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_sg_clean -
+ *	@qc:
+ *
+ *	LOCKING:
+ */
+
+static void ata_sg_clean(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scatterlist *sg = qc->sg;
+	int dir = qc->dma_dir;
+
+	assert(qc->flags & ATA_QCFLAG_DMAMAP);
+	assert(sg != NULL);
+
+	if (qc->flags & ATA_QCFLAG_SINGLE)
+		assert(qc->n_elem == 1);
+
+	DPRINTK("unmapping %u sg elements\n", qc->n_elem);
+
+	if (qc->flags & ATA_QCFLAG_SG)
+		dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir);
+	else
+		dma_unmap_single(ap->host_set->dev, sg_dma_address(&sg[0]),
+				 sg_dma_len(&sg[0]), dir);
+
+	qc->flags &= ~ATA_QCFLAG_DMAMAP;
+	qc->sg = NULL;
+}
+
+/**
+ *	ata_fill_sg - Fill PCI IDE PRD table
+ *	@qc: Metadata associated with taskfile to be transferred
+ *
+ *	LOCKING:
+ *
+ */
+static void ata_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	unsigned int idx, nelem;
+
+	assert(sg != NULL);
+	assert(qc->n_elem > 0);
+
+	idx = 0;
+	for (nelem = qc->n_elem; nelem; nelem--,sg++) {
+		u32 addr, offset;
+		u32 sg_len, len;
+
+		/* determine if physical DMA addr spans 64K boundary.
+		 * Note h/w doesn't support 64-bit, so we unconditionally
+		 * truncate dma_addr_t to u32.
+		 */
+		addr = (u32) sg_dma_address(sg);
+		sg_len = sg_dma_len(sg);
+
+		while (sg_len) {
+			offset = addr & 0xffff;
+			len = sg_len;
+			if ((offset + sg_len) > 0x10000)
+				len = 0x10000 - offset;
+
+			ap->prd[idx].addr = cpu_to_le32(addr);
+			ap->prd[idx].flags_len = cpu_to_le32(len & 0xffff);
+			VPRINTK("PRD[%u] = (0x%X, 0x%X)\n", idx, addr, len);
+
+			idx++;
+			sg_len -= len;
+			addr += len;
+		}
+	}
+
+	if (idx)
+		ap->prd[idx - 1].flags_len |= cpu_to_le32(ATA_PRD_EOT);
+}
+/**
+ *	ata_check_atapi_dma - Check whether ATAPI DMA can be supported
+ *	@qc: Metadata associated with taskfile to check
+ *
+ *	LOCKING:
+ *	RETURNS: 0 when ATAPI DMA can be used
+ *               nonzero otherwise
+ */
+int ata_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	int rc = 0; /* Assume ATAPI DMA is OK by default */
+
+	if (ap->ops->check_atapi_dma)
+		rc = ap->ops->check_atapi_dma(qc);
+
+	return rc;
+}
+/**
+ *	ata_qc_prep - Prepare taskfile for submission
+ *	@qc: Metadata associated with taskfile to be prepared
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+void ata_qc_prep(struct ata_queued_cmd *qc)
+{
+	if (!(qc->flags & ATA_QCFLAG_DMAMAP))
+		return;
+
+	ata_fill_sg(qc);
+}
+
+void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen)
+{
+	struct scatterlist *sg;
+
+	qc->flags |= ATA_QCFLAG_SINGLE;
+
+	memset(&qc->sgent, 0, sizeof(qc->sgent));
+	qc->sg = &qc->sgent;
+	qc->n_elem = 1;
+	qc->buf_virt = buf;
+
+	sg = qc->sg;
+	sg->page = virt_to_page(buf);
+	sg->offset = (unsigned long) buf & ~PAGE_MASK;
+	sg_dma_len(sg) = buflen;
+}
+
+void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg,
+		 unsigned int n_elem)
+{
+	qc->flags |= ATA_QCFLAG_SG;
+	qc->sg = sg;
+	qc->n_elem = n_elem;
+}
+
+/**
+ *	ata_sg_setup_one -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *
+ */
+
+static int ata_sg_setup_one(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	int dir = qc->dma_dir;
+	struct scatterlist *sg = qc->sg;
+	dma_addr_t dma_address;
+
+	dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt,
+				     sg_dma_len(sg), dir);
+	if (dma_mapping_error(dma_address))
+		return -1;
+
+	sg_dma_address(sg) = dma_address;
+
+	DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg),
+		qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+	return 0;
+}
+
+/**
+ *	ata_sg_setup -
+ *	@qc:
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *
+ */
+
+static int ata_sg_setup(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct scatterlist *sg = qc->sg;
+	int n_elem, dir;
+
+	VPRINTK("ENTER, ata%u\n", ap->id);
+	assert(qc->flags & ATA_QCFLAG_SG);
+
+	dir = qc->dma_dir;
+	n_elem = dma_map_sg(ap->host_set->dev, sg, qc->n_elem, dir);
+	if (n_elem < 1)
+		return -1;
+
+	DPRINTK("%d sg elements mapped\n", n_elem);
+
+	qc->n_elem = n_elem;
+
+	return 0;
+}
+
+/**
+ *	ata_pio_poll -
+ *	@ap:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static unsigned long ata_pio_poll(struct ata_port *ap)
+{
+	u8 status;
+	unsigned int poll_state = PIO_ST_UNKNOWN;
+	unsigned int reg_state = PIO_ST_UNKNOWN;
+	const unsigned int tmout_state = PIO_ST_TMOUT;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST:
+	case PIO_ST_POLL:
+		poll_state = PIO_ST_POLL;
+		reg_state = PIO_ST;
+		break;
+	case PIO_ST_LAST:
+	case PIO_ST_LAST_POLL:
+		poll_state = PIO_ST_LAST_POLL;
+		reg_state = PIO_ST_LAST;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	status = ata_chk_status(ap);
+	if (status & ATA_BUSY) {
+		if (time_after(jiffies, ap->pio_task_timeout)) {
+			ap->pio_task_state = tmout_state;
+			return 0;
+		}
+		ap->pio_task_state = poll_state;
+		return ATA_SHORT_PAUSE;
+	}
+
+	ap->pio_task_state = reg_state;
+	return 0;
+}
+
+/**
+ *	ata_pio_complete -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_pio_complete (struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	u8 drv_stat;
+
+	/*
+	 * This is purely hueristic.  This is a fast path.
+	 * Sometimes when we enter, BSY will be cleared in
+	 * a chk-status or two.  If not, the drive is probably seeking
+	 * or something.  Snooze for a couple msecs, then
+	 * chk-status again.  If still busy, fall back to
+	 * PIO_ST_POLL state.
+	 */
+	drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
+	if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+		msleep(2);
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10);
+		if (drv_stat & (ATA_BUSY | ATA_DRQ)) {
+			ap->pio_task_state = PIO_ST_LAST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
+			return;
+		}
+	}
+
+	drv_stat = ata_wait_idle(ap);
+	if (!ata_ok(drv_stat)) {
+		ap->pio_task_state = PIO_ST_ERR;
+		return;
+	}
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	ap->pio_task_state = PIO_ST_IDLE;
+
+	ata_irq_on(ap);
+
+	ata_qc_complete(qc, drv_stat);
+}
+
+void swap_buf_le16(u16 *buf, unsigned int buf_words)
+{
+#ifdef __BIG_ENDIAN
+	unsigned int i;
+
+	for (i = 0; i < buf_words; i++)
+		buf[i] = le16_to_cpu(buf[i]);
+#endif /* __BIG_ENDIAN */
+}
+
+static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf,
+			       unsigned int buflen, int write_data)
+{
+	unsigned int i;
+	unsigned int words = buflen >> 1;
+	u16 *buf16 = (u16 *) buf;
+	void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr;
+
+	if (write_data) {
+		for (i = 0; i < words; i++)
+			writew(le16_to_cpu(buf16[i]), mmio);
+	} else {
+		for (i = 0; i < words; i++)
+			buf16[i] = cpu_to_le16(readw(mmio));
+	}
+}
+
+static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf,
+			      unsigned int buflen, int write_data)
+{
+	unsigned int dwords = buflen >> 1;
+
+	if (write_data)
+		outsw(ap->ioaddr.data_addr, buf, dwords);
+	else
+		insw(ap->ioaddr.data_addr, buf, dwords);
+}
+
+static void ata_data_xfer(struct ata_port *ap, unsigned char *buf,
+			  unsigned int buflen, int do_write)
+{
+	if (ap->flags & ATA_FLAG_MMIO)
+		ata_mmio_data_xfer(ap, buf, buflen, do_write);
+	else
+		ata_pio_data_xfer(ap, buf, buflen, do_write);
+}
+
+static void ata_pio_sector(struct ata_queued_cmd *qc)
+{
+	int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct page *page;
+	unsigned int offset;
+	unsigned char *buf;
+
+	if (qc->cursect == (qc->nsect - 1))
+		ap->pio_task_state = PIO_ST_LAST;
+
+	page = sg[qc->cursg].page;
+	offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE;
+
+	/* get the current page and offset */
+	page = nth_page(page, (offset >> PAGE_SHIFT));
+	offset %= PAGE_SIZE;
+
+	buf = kmap(page) + offset;
+
+	qc->cursect++;
+	qc->cursg_ofs++;
+
+	if ((qc->cursg_ofs * ATA_SECT_SIZE) == sg_dma_len(&sg[qc->cursg])) {
+		qc->cursg++;
+		qc->cursg_ofs = 0;
+	}
+
+	DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+	/* do the actual data transfer */
+	do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+	ata_data_xfer(ap, buf, ATA_SECT_SIZE, do_write);
+
+	kunmap(page);
+}
+
+static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes)
+{
+	int do_write = (qc->tf.flags & ATA_TFLAG_WRITE);
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct page *page;
+	unsigned char *buf;
+	unsigned int offset, count;
+
+	if (qc->curbytes == qc->nbytes - bytes)
+		ap->pio_task_state = PIO_ST_LAST;
+
+next_sg:
+	sg = &qc->sg[qc->cursg];
+
+next_page:
+	page = sg->page;
+	offset = sg->offset + qc->cursg_ofs;
+
+	/* get the current page and offset */
+	page = nth_page(page, (offset >> PAGE_SHIFT));
+	offset %= PAGE_SIZE;
+
+	count = min(sg_dma_len(sg) - qc->cursg_ofs, bytes);
+
+	/* don't cross page boundaries */
+	count = min(count, (unsigned int)PAGE_SIZE - offset);
+
+	buf = kmap(page) + offset;
+
+	bytes -= count;
+	qc->curbytes += count;
+	qc->cursg_ofs += count;
+
+	if (qc->cursg_ofs == sg_dma_len(sg)) {
+		qc->cursg++;
+		qc->cursg_ofs = 0;
+	}
+
+	DPRINTK("data %s\n", qc->tf.flags & ATA_TFLAG_WRITE ? "write" : "read");
+
+	/* do the actual data transfer */
+	ata_data_xfer(ap, buf, count, do_write);
+
+	kunmap(page);
+
+	if (bytes) {
+		if (qc->cursg_ofs < sg_dma_len(sg))
+			goto next_page;
+		goto next_sg;
+	}
+}
+
+static void atapi_pio_bytes(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_device *dev = qc->dev;
+	unsigned int ireason, bc_lo, bc_hi, bytes;
+	int i_write, do_write = (qc->tf.flags & ATA_TFLAG_WRITE) ? 1 : 0;
+
+	ap->ops->tf_read(ap, &qc->tf);
+	ireason = qc->tf.nsect;
+	bc_lo = qc->tf.lbam;
+	bc_hi = qc->tf.lbah;
+	bytes = (bc_hi << 8) | bc_lo;
+
+	/* shall be cleared to zero, indicating xfer of data */
+	if (ireason & (1 << 0))
+		goto err_out;
+
+	/* make sure transfer direction matches expected */
+	i_write = ((ireason & (1 << 1)) == 0) ? 1 : 0;
+	if (do_write != i_write)
+		goto err_out;
+
+	__atapi_pio_bytes(qc, bytes);
+
+	return;
+
+err_out:
+	printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n",
+	      ap->id, dev->devno);
+	ap->pio_task_state = PIO_ST_ERR;
+}
+
+/**
+ *	ata_pio_sector -
+ *	@ap:
+ *
+ *	LOCKING:
+ */
+
+static void ata_pio_block(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	u8 status;
+
+	/*
+	 * This is purely hueristic.  This is a fast path.
+	 * Sometimes when we enter, BSY will be cleared in
+	 * a chk-status or two.  If not, the drive is probably seeking
+	 * or something.  Snooze for a couple msecs, then
+	 * chk-status again.  If still busy, fall back to
+	 * PIO_ST_POLL state.
+	 */
+	status = ata_busy_wait(ap, ATA_BUSY, 5);
+	if (status & ATA_BUSY) {
+		msleep(2);
+		status = ata_busy_wait(ap, ATA_BUSY, 10);
+		if (status & ATA_BUSY) {
+			ap->pio_task_state = PIO_ST_POLL;
+			ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO;
+			return;
+		}
+	}
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	if (is_atapi_taskfile(&qc->tf)) {
+		/* no more data to transfer or unsupported ATAPI command */
+		if ((status & ATA_DRQ) == 0) {
+			ap->pio_task_state = PIO_ST_IDLE;
+
+			ata_irq_on(ap);
+
+			ata_qc_complete(qc, status);
+			return;
+		}
+
+		atapi_pio_bytes(qc);
+	} else {
+		/* handle BSY=0, DRQ=0 as error */
+		if ((status & ATA_DRQ) == 0) {
+			ap->pio_task_state = PIO_ST_ERR;
+			return;
+		}
+
+		ata_pio_sector(qc);
+	}
+}
+
+static void ata_pio_error(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+	u8 drv_stat;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+
+	drv_stat = ata_chk_status(ap);
+	printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n",
+	       ap->id, drv_stat);
+
+	ap->pio_task_state = PIO_ST_IDLE;
+
+	ata_irq_on(ap);
+
+	ata_qc_complete(qc, drv_stat | ATA_ERR);
+}
+
+static void ata_pio_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	unsigned long timeout = 0;
+
+	switch (ap->pio_task_state) {
+	case PIO_ST_IDLE:
+		return;
+
+	case PIO_ST:
+		ata_pio_block(ap);
+		break;
+
+	case PIO_ST_LAST:
+		ata_pio_complete(ap);
+		break;
+
+	case PIO_ST_POLL:
+	case PIO_ST_LAST_POLL:
+		timeout = ata_pio_poll(ap);
+		break;
+
+	case PIO_ST_TMOUT:
+	case PIO_ST_ERR:
+		ata_pio_error(ap);
+		return;
+	}
+
+	if (timeout)
+		queue_delayed_work(ata_wq, &ap->pio_task,
+				   timeout);
+	else
+		queue_work(ata_wq, &ap->pio_task);
+}
+
+static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev,
+				struct scsi_cmnd *cmd)
+{
+	DECLARE_COMPLETION(wait);
+	struct ata_queued_cmd *qc;
+	unsigned long flags;
+	int rc;
+
+	DPRINTK("ATAPI request sense\n");
+
+	qc = ata_qc_new_init(ap, dev);
+	BUG_ON(qc == NULL);
+
+	/* FIXME: is this needed? */
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer));
+	qc->dma_dir = DMA_FROM_DEVICE;
+
+	memset(&qc->cdb, 0, sizeof(ap->cdb_len));
+	qc->cdb[0] = REQUEST_SENSE;
+	qc->cdb[4] = SCSI_SENSE_BUFFERSIZE;
+
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	qc->tf.command = ATA_CMD_PACKET;
+
+	qc->tf.protocol = ATA_PROT_ATAPI;
+	qc->tf.lbam = (8 * 1024) & 0xff;
+	qc->tf.lbah = (8 * 1024) >> 8;
+	qc->nbytes = SCSI_SENSE_BUFFERSIZE;
+
+	qc->waiting = &wait;
+	qc->complete_fn = ata_qc_complete_noop;
+
+	spin_lock_irqsave(&ap->host_set->lock, flags);
+	rc = ata_qc_issue(qc);
+	spin_unlock_irqrestore(&ap->host_set->lock, flags);
+
+	if (rc)
+		ata_port_disable(ap);
+	else
+		wait_for_completion(&wait);
+
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_qc_timeout - Handle timeout of queued command
+ *	@qc: Command that timed out
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ */
+
+static void ata_qc_timeout(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_device *dev = qc->dev;
+	u8 host_stat = 0, drv_stat;
+
+	DPRINTK("ENTER\n");
+
+	/* FIXME: doesn't this conflict with timeout handling? */
+	if (qc->dev->class == ATA_DEV_ATAPI && qc->scsicmd) {
+		struct scsi_cmnd *cmd = qc->scsicmd;
+
+		if (!scsi_eh_eflags_chk(cmd, SCSI_EH_CANCEL_CMD)) {
+
+			/* finish completing original command */
+			__ata_qc_complete(qc);
+
+			atapi_request_sense(ap, dev, cmd);
+
+			cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
+			scsi_finish_command(cmd);
+
+			goto out;
+		}
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+
+	case ATA_PROT_DMA:
+	case ATA_PROT_ATAPI_DMA:
+		host_stat = ap->ops->bmdma_status(ap);
+
+		/* before we do anything else, clear DMA-Start bit */
+		ap->ops->bmdma_stop(ap);
+
+		/* fall through */
+
+	default:
+		ata_altstatus(ap);
+		drv_stat = ata_chk_status(ap);
+
+		/* ack bmdma irq events */
+		ap->ops->irq_clear(ap);
+
+		printk(KERN_ERR "ata%u: command 0x%x timeout, stat 0x%x host_stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat, host_stat);
+
+		/* complete taskfile transaction */
+		ata_qc_complete(qc, drv_stat);
+		break;
+	}
+out:
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_eng_timeout - Handle timeout of queued command
+ *	@ap: Port on which timed-out command is active
+ *
+ *	Some part of the kernel (currently, only the SCSI layer)
+ *	has noticed that the active command on port @ap has not
+ *	completed after a specified length of time.  Handle this
+ *	condition by disabling DMA (if necessary) and completing
+ *	transactions, with error if necessary.
+ *
+ *	This also handles the case of the "lost interrupt", where
+ *	for some reason (possibly hardware bug, possibly driver bug)
+ *	an interrupt was not delivered to the driver, even though the
+ *	transaction completed successfully.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ */
+
+void ata_eng_timeout(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	ata_qc_timeout(qc);
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+/**
+ *	ata_qc_new - Request an available ATA command, for queueing
+ *	@ap: Port associated with device @dev
+ *	@dev: Device from whom we request an available command structure
+ *
+ *	LOCKING:
+ */
+
+static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+{
+	struct ata_queued_cmd *qc = NULL;
+	unsigned int i;
+
+	for (i = 0; i < ATA_MAX_QUEUE; i++)
+		if (!test_and_set_bit(i, &ap->qactive)) {
+			qc = ata_qc_from_tag(ap, i);
+			break;
+		}
+
+	if (qc)
+		qc->tag = i;
+
+	return qc;
+}
+
+/**
+ *	ata_qc_new_init - Request an available ATA command, and initialize it
+ *	@ap: Port associated with device @dev
+ *	@dev: Device from whom we request an available command structure
+ *
+ *	LOCKING:
+ */
+
+struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
+				      struct ata_device *dev)
+{
+	struct ata_queued_cmd *qc;
+
+	qc = ata_qc_new(ap);
+	if (qc) {
+		qc->sg = NULL;
+		qc->flags = 0;
+		qc->scsicmd = NULL;
+		qc->ap = ap;
+		qc->dev = dev;
+		qc->cursect = qc->cursg = qc->cursg_ofs = 0;
+		qc->nsect = 0;
+		qc->nbytes = qc->curbytes = 0;
+
+		ata_tf_init(ap, &qc->tf, dev->devno);
+
+		if (dev->flags & ATA_DFLAG_LBA48)
+			qc->tf.flags |= ATA_TFLAG_LBA48;
+	}
+
+	return qc;
+}
+
+static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	return 0;
+}
+
+static void __ata_qc_complete(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int tag, do_clear = 0;
+
+	qc->flags = 0;
+	tag = qc->tag;
+	if (likely(ata_tag_valid(tag))) {
+		if (tag == ap->active_tag)
+			ap->active_tag = ATA_TAG_POISON;
+		qc->tag = ATA_TAG_POISON;
+		do_clear = 1;
+	}
+
+	if (qc->waiting) {
+		struct completion *waiting = qc->waiting;
+		qc->waiting = NULL;
+		complete(waiting);
+	}
+
+	if (likely(do_clear))
+		clear_bit(tag, &ap->qactive);
+}
+
+/**
+ *	ata_qc_free - free unused ata_queued_cmd
+ *	@qc: Command to complete
+ *
+ *	Designed to free unused ata_queued_cmd object
+ *	in case something prevents using it.
+ *
+ *	LOCKING:
+ *
+ */
+void ata_qc_free(struct ata_queued_cmd *qc)
+{
+	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
+	assert(qc->waiting == NULL);	/* nothing should be waiting */
+
+	__ata_qc_complete(qc);
+}
+
+/**
+ *	ata_qc_complete - Complete an active ATA command
+ *	@qc: Command to complete
+ *	@drv_stat: ATA status register contents
+ *
+ *	LOCKING:
+ *
+ */
+
+void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	int rc;
+
+	assert(qc != NULL);	/* ata_qc_from_tag _might_ return NULL */
+	assert(qc->flags & ATA_QCFLAG_ACTIVE);
+
+	if (likely(qc->flags & ATA_QCFLAG_DMAMAP))
+		ata_sg_clean(qc);
+
+	/* call completion callback */
+	rc = qc->complete_fn(qc, drv_stat);
+
+	/* if callback indicates not to complete command (non-zero),
+	 * return immediately
+	 */
+	if (rc != 0)
+		return;
+
+	__ata_qc_complete(qc);
+
+	VPRINTK("EXIT\n");
+}
+
+static inline int ata_should_dma_map(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_ATAPI_DMA:
+		return 1;
+
+	case ATA_PROT_ATAPI:
+	case ATA_PROT_PIO:
+	case ATA_PROT_PIO_MULT:
+		if (ap->flags & ATA_FLAG_PIO_DMA)
+			return 1;
+
+		/* fall through */
+
+	default:
+		return 0;
+	}
+
+	/* never reached */
+}
+
+/**
+ *	ata_qc_issue - issue taskfile to device
+ *	@qc: command to issue to device
+ *
+ *	Prepare an ATA command to submission to device.
+ *	This includes mapping the data into a DMA-able
+ *	area, filling in the S/G table, and finally
+ *	writing the taskfile to hardware, starting the command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+int ata_qc_issue(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	if (ata_should_dma_map(qc)) {
+		if (qc->flags & ATA_QCFLAG_SG) {
+			if (ata_sg_setup(qc))
+				goto err_out;
+		} else if (qc->flags & ATA_QCFLAG_SINGLE) {
+			if (ata_sg_setup_one(qc))
+				goto err_out;
+		}
+	} else {
+		qc->flags &= ~ATA_QCFLAG_DMAMAP;
+	}
+
+	ap->ops->qc_prep(qc);
+
+	qc->ap->active_tag = qc->tag;
+	qc->flags |= ATA_QCFLAG_ACTIVE;
+
+	return ap->ops->qc_issue(qc);
+
+err_out:
+	return -1;
+}
+
+/**
+ *	ata_qc_issue_prot - issue taskfile to device in proto-dependent manner
+ *	@qc: command to issue to device
+ *
+ *	Using various libata functions and hooks, this function
+ *	starts an ATA command.  ATA commands are grouped into
+ *	classes called "protocols", and issuing each type of protocol
+ *	is slightly different.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, negative on error.
+ */
+
+int ata_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+
+	ata_dev_select(ap, qc->dev->devno, 1, 0);
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_NODATA:
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		break;
+
+	case ATA_PROT_DMA:
+		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
+		ap->ops->bmdma_setup(qc);	    /* set up bmdma */
+		ap->ops->bmdma_start(qc);	    /* initiate bmdma */
+		break;
+
+	case ATA_PROT_PIO: /* load tf registers, initiate polling pio */
+		ata_qc_set_polling(qc);
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		ap->pio_task_state = PIO_ST;
+		queue_work(ata_wq, &ap->pio_task);
+		break;
+
+	case ATA_PROT_ATAPI:
+		ata_qc_set_polling(qc);
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		queue_work(ata_wq, &ap->packet_task);
+		break;
+
+	case ATA_PROT_ATAPI_NODATA:
+		ata_tf_to_host_nolock(ap, &qc->tf);
+		queue_work(ata_wq, &ap->packet_task);
+		break;
+
+	case ATA_PROT_ATAPI_DMA:
+		ap->ops->tf_load(ap, &qc->tf);	 /* load tf registers */
+		ap->ops->bmdma_setup(qc);	    /* set up bmdma */
+		queue_work(ata_wq, &ap->packet_task);
+		break;
+
+	default:
+		WARN_ON(1);
+		return -1;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_bmdma_setup - Set up PCI IDE BMDMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dmactl;
+	void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+
+	/* load PRD table addr. */
+	mb();	/* make sure PRD table writes are visible to controller */
+	writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	writeb(dmactl, mmio + ATA_DMA_CMD);
+
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *	ata_bmdma_start - Start a PCI IDE BMDMA transaction
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+	u8 dmactl;
+
+	/* start host DMA transaction */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+
+	/* Strictly, one may wish to issue a readb() here, to
+	 * flush the mmio write.  However, control also passes
+	 * to the hardware at this point, and it will interrupt
+	 * us when we are to resume control.  So, in effect,
+	 * we don't care when the mmio write flushes.
+	 * Further, a read of the DMA status register _immediately_
+	 * following the write may not be what certain flaky hardware
+	 * is expected, so I think it is best to not add a readb()
+	 * without first all the MMIO ATA cards/mobos.
+	 * Or maybe I'm just being paranoid.
+	 */
+}
+
+/**
+ *	ata_bmdma_setup_pio - Set up PCI IDE BMDMA transaction (PIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_bmdma_setup_pio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dmactl;
+
+	/* load PRD table addr. */
+	outl(ap->prd_dma, ap->ioaddr.bmdma_addr + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	outb(dmactl, ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+
+	/* issue r/w command */
+	ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *	ata_bmdma_start_pio - Start a PCI IDE BMDMA transaction (PIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_bmdma_start_pio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	u8 dmactl;
+
+	/* start host DMA transaction */
+	dmactl = inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	outb(dmactl | ATA_DMA_START,
+	     ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+}
+
+void ata_bmdma_start(struct ata_queued_cmd *qc)
+{
+	if (qc->ap->flags & ATA_FLAG_MMIO)
+		ata_bmdma_start_mmio(qc);
+	else
+		ata_bmdma_start_pio(qc);
+}
+
+void ata_bmdma_setup(struct ata_queued_cmd *qc)
+{
+	if (qc->ap->flags & ATA_FLAG_MMIO)
+		ata_bmdma_setup_mmio(qc);
+	else
+		ata_bmdma_setup_pio(qc);
+}
+
+void ata_bmdma_irq_clear(struct ata_port *ap)
+{
+    if (ap->flags & ATA_FLAG_MMIO) {
+        void __iomem *mmio = ((void __iomem *) ap->ioaddr.bmdma_addr) + ATA_DMA_STATUS;
+        writeb(readb(mmio), mmio);
+    } else {
+        unsigned long addr = ap->ioaddr.bmdma_addr + ATA_DMA_STATUS;
+        outb(inb(addr), addr);
+    }
+
+}
+
+u8 ata_bmdma_status(struct ata_port *ap)
+{
+	u8 host_stat;
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+		host_stat = readb(mmio + ATA_DMA_STATUS);
+	} else
+	host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS);
+	return host_stat;
+}
+
+void ata_bmdma_stop(struct ata_port *ap)
+{
+	if (ap->flags & ATA_FLAG_MMIO) {
+		void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr;
+
+		/* clear start/stop bit */
+		writeb(readb(mmio + ATA_DMA_CMD) & ~ATA_DMA_START,
+			mmio + ATA_DMA_CMD);
+	} else {
+		/* clear start/stop bit */
+		outb(inb(ap->ioaddr.bmdma_addr + ATA_DMA_CMD) & ~ATA_DMA_START,
+			ap->ioaddr.bmdma_addr + ATA_DMA_CMD);
+	}
+
+	/* one-PIO-cycle guaranteed wait, per spec, for HDMA1:0 transition */
+	ata_altstatus(ap);        /* dummy read */
+}
+
+/**
+ *	ata_host_intr - Handle host interrupt for given (port, task)
+ *	@ap: Port on which interrupt arrived (possibly...)
+ *	@qc: Taskfile currently active in engine
+ *
+ *	Handle host interrupt for given queued command.  Currently,
+ *	only DMA interrupts are handled.  All other commands are
+ *	handled via polling with interrupts disabled (nIEN bit).
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	One if interrupt was handled, zero if not (shared irq).
+ */
+
+inline unsigned int ata_host_intr (struct ata_port *ap,
+				   struct ata_queued_cmd *qc)
+{
+	u8 status, host_stat;
+
+	switch (qc->tf.protocol) {
+
+	case ATA_PROT_DMA:
+	case ATA_PROT_ATAPI_DMA:
+	case ATA_PROT_ATAPI:
+		/* check status of DMA engine */
+		host_stat = ap->ops->bmdma_status(ap);
+		VPRINTK("ata%u: host_stat 0x%X\n", ap->id, host_stat);
+
+		/* if it's not our irq... */
+		if (!(host_stat & ATA_DMA_INTR))
+			goto idle_irq;
+
+		/* before we do anything else, clear DMA-Start bit */
+		ap->ops->bmdma_stop(ap);
+
+		/* fall through */
+
+	case ATA_PROT_ATAPI_NODATA:
+	case ATA_PROT_NODATA:
+		/* check altstatus */
+		status = ata_altstatus(ap);
+		if (status & ATA_BUSY)
+			goto idle_irq;
+
+		/* check main status, clearing INTRQ */
+		status = ata_chk_status(ap);
+		if (unlikely(status & ATA_BUSY))
+			goto idle_irq;
+		DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+			ap->id, qc->tf.protocol, status);
+
+		/* ack bmdma irq events */
+		ap->ops->irq_clear(ap);
+
+		/* complete taskfile transaction */
+		ata_qc_complete(qc, status);
+		break;
+
+	default:
+		goto idle_irq;
+	}
+
+	return 1;	/* irq handled */
+
+idle_irq:
+	ap->stats.idle_irq++;
+
+#ifdef ATA_IRQ_TRAP
+	if ((ap->stats.idle_irq % 1000) == 0) {
+		handled = 1;
+		ata_irq_ack(ap, 0); /* debug trap */
+		printk(KERN_WARNING "ata%d: irq trap\n", ap->id);
+	}
+#endif
+	return 0;	/* irq not handled */
+}
+
+/**
+ *	ata_interrupt - Default ATA host interrupt handler
+ *	@irq: irq line
+ *	@dev_instance: pointer to our host information structure
+ *	@regs: unused
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	unsigned long flags;
+
+	/* TODO: make _irqsave conditional on x86 PCI IDE legacy mode */
+	spin_lock_irqsave(&host_set->lock, flags);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+		if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+				handled |= ata_host_intr(ap, qc);
+		}
+	}
+
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+/**
+ *	atapi_packet_task - Write CDB bytes to hardware
+ *	@_data: Port to which ATAPI device is attached.
+ *
+ *	When device has indicated its readiness to accept
+ *	a CDB, this function is called.  Send the CDB.
+ *	If DMA is to be performed, exit immediately.
+ *	Otherwise, we are in polling mode, so poll
+ *	status under operation succeeds or fails.
+ *
+ *	LOCKING:
+ *	Kernel thread context (may sleep)
+ */
+
+static void atapi_packet_task(void *_data)
+{
+	struct ata_port *ap = _data;
+	struct ata_queued_cmd *qc;
+	u8 status;
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	assert(qc != NULL);
+	assert(qc->flags & ATA_QCFLAG_ACTIVE);
+
+	/* sleep-wait for BSY to clear */
+	DPRINTK("busy wait\n");
+	if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB))
+		goto err_out;
+
+	/* make sure DRQ is set */
+	status = ata_chk_status(ap);
+	if ((status & (ATA_BUSY | ATA_DRQ)) != ATA_DRQ)
+		goto err_out;
+
+	/* send SCSI cdb */
+	DPRINTK("send cdb\n");
+	assert(ap->cdb_len >= 12);
+	ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1);
+
+	/* if we are DMA'ing, irq handler takes over from here */
+	if (qc->tf.protocol == ATA_PROT_ATAPI_DMA)
+		ap->ops->bmdma_start(qc);	    /* initiate bmdma */
+
+	/* non-data commands are also handled via irq */
+	else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) {
+		/* do nothing */
+	}
+
+	/* PIO commands are handled by polling */
+	else {
+		ap->pio_task_state = PIO_ST;
+		queue_work(ata_wq, &ap->pio_task);
+	}
+
+	return;
+
+err_out:
+	ata_qc_complete(qc, ATA_ERR);
+}
+
+int ata_port_start (struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+
+	ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL);
+	if (!ap->prd)
+		return -ENOMEM;
+
+	DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma);
+
+	return 0;
+}
+
+void ata_port_stop (struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+
+	dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma);
+}
+
+/**
+ *	ata_host_remove - Unregister SCSI host structure with upper layers
+ *	@ap: Port to unregister
+ *	@do_unregister: 1 if we fully unregister, 0 to just stop the port
+ *
+ *	LOCKING:
+ */
+
+static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister)
+{
+	struct Scsi_Host *sh = ap->host;
+
+	DPRINTK("ENTER\n");
+
+	if (do_unregister)
+		scsi_remove_host(sh);
+
+	ap->ops->port_stop(ap);
+}
+
+/**
+ *	ata_host_init - Initialize an ata_port structure
+ *	@ap: Structure to initialize
+ *	@host: associated SCSI mid-layer structure
+ *	@host_set: Collection of hosts to which @ap belongs
+ *	@ent: Probe information provided by low-level driver
+ *	@port_no: Port number associated with this ata_port
+ *
+ *	LOCKING:
+ *
+ */
+
+static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host,
+			  struct ata_host_set *host_set,
+			  struct ata_probe_ent *ent, unsigned int port_no)
+{
+	unsigned int i;
+
+	host->max_id = 16;
+	host->max_lun = 1;
+	host->max_channel = 1;
+	host->unique_id = ata_unique_id++;
+	host->max_cmd_len = 12;
+	scsi_set_device(host, ent->dev);
+	scsi_assign_lock(host, &host_set->lock);
+
+	ap->flags = ATA_FLAG_PORT_DISABLED;
+	ap->id = host->unique_id;
+	ap->host = host;
+	ap->ctl = ATA_DEVCTL_OBS;
+	ap->host_set = host_set;
+	ap->port_no = port_no;
+	ap->hard_port_no =
+		ent->legacy_mode ? ent->hard_port_no : port_no;
+	ap->pio_mask = ent->pio_mask;
+	ap->mwdma_mask = ent->mwdma_mask;
+	ap->udma_mask = ent->udma_mask;
+	ap->flags |= ent->host_flags;
+	ap->ops = ent->port_ops;
+	ap->cbl = ATA_CBL_NONE;
+	ap->active_tag = ATA_TAG_POISON;
+	ap->last_ctl = 0xFF;
+
+	INIT_WORK(&ap->packet_task, atapi_packet_task, ap);
+	INIT_WORK(&ap->pio_task, ata_pio_task, ap);
+
+	for (i = 0; i < ATA_MAX_DEVICES; i++)
+		ap->device[i].devno = i;
+
+#ifdef ATA_IRQ_TRAP
+	ap->stats.unhandled_irq = 1;
+	ap->stats.idle_irq = 1;
+#endif
+
+	memcpy(&ap->ioaddr, &ent->port[port_no], sizeof(struct ata_ioports));
+}
+
+/**
+ *	ata_host_add - Attach low-level ATA driver to system
+ *	@ent: Information provided by low-level driver
+ *	@host_set: Collections of ports to which we add
+ *	@port_no: Port number associated with this host
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static struct ata_port * ata_host_add(struct ata_probe_ent *ent,
+				      struct ata_host_set *host_set,
+				      unsigned int port_no)
+{
+	struct Scsi_Host *host;
+	struct ata_port *ap;
+	int rc;
+
+	DPRINTK("ENTER\n");
+	host = scsi_host_alloc(ent->sht, sizeof(struct ata_port));
+	if (!host)
+		return NULL;
+
+	ap = (struct ata_port *) &host->hostdata[0];
+
+	ata_host_init(ap, host, host_set, ent, port_no);
+
+	rc = ap->ops->port_start(ap);
+	if (rc)
+		goto err_out;
+
+	return ap;
+
+err_out:
+	scsi_host_put(host);
+	return NULL;
+}
+
+/**
+ *	ata_device_add -
+ *	@ent:
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+int ata_device_add(struct ata_probe_ent *ent)
+{
+	unsigned int count = 0, i;
+	struct device *dev = ent->dev;
+	struct ata_host_set *host_set;
+
+	DPRINTK("ENTER\n");
+	/* alloc a container for our list of ATA ports (buses) */
+	host_set = kmalloc(sizeof(struct ata_host_set) +
+			   (ent->n_ports * sizeof(void *)), GFP_KERNEL);
+	if (!host_set)
+		return 0;
+	memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *)));
+	spin_lock_init(&host_set->lock);
+
+	host_set->dev = dev;
+	host_set->n_ports = ent->n_ports;
+	host_set->irq = ent->irq;
+	host_set->mmio_base = ent->mmio_base;
+	host_set->private_data = ent->private_data;
+	host_set->ops = ent->port_ops;
+
+	/* register each port bound to this device */
+	for (i = 0; i < ent->n_ports; i++) {
+		struct ata_port *ap;
+		unsigned long xfer_mode_mask;
+
+		ap = ata_host_add(ent, host_set, i);
+		if (!ap)
+			goto err_out;
+
+		host_set->ports[i] = ap;
+		xfer_mode_mask =(ap->udma_mask << ATA_SHIFT_UDMA) |
+				(ap->mwdma_mask << ATA_SHIFT_MWDMA) |
+				(ap->pio_mask << ATA_SHIFT_PIO);
+
+		/* print per-port info to dmesg */
+		printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX "
+				 "bmdma 0x%lX irq %lu\n",
+			ap->id,
+			ap->flags & ATA_FLAG_SATA ? 'S' : 'P',
+			ata_mode_string(xfer_mode_mask),
+	       		ap->ioaddr.cmd_addr,
+	       		ap->ioaddr.ctl_addr,
+	       		ap->ioaddr.bmdma_addr,
+	       		ent->irq);
+
+		ata_chk_status(ap);
+		host_set->ops->irq_clear(ap);
+		count++;
+	}
+
+	if (!count) {
+		kfree(host_set);
+		return 0;
+	}
+
+	/* obtain irq, that is shared between channels */
+	if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags,
+			DRV_NAME, host_set))
+		goto err_out;
+
+	/* perform each probe synchronously */
+	DPRINTK("probe begin\n");
+	for (i = 0; i < count; i++) {
+		struct ata_port *ap;
+		int rc;
+
+		ap = host_set->ports[i];
+
+		DPRINTK("ata%u: probe begin\n", ap->id);
+		rc = ata_bus_probe(ap);
+		DPRINTK("ata%u: probe end\n", ap->id);
+
+		if (rc) {
+			/* FIXME: do something useful here?
+			 * Current libata behavior will
+			 * tear down everything when
+			 * the module is removed
+			 * or the h/w is unplugged.
+			 */
+		}
+
+		rc = scsi_add_host(ap->host, dev);
+		if (rc) {
+			printk(KERN_ERR "ata%u: scsi_add_host failed\n",
+			       ap->id);
+			/* FIXME: do something useful here */
+			/* FIXME: handle unconditional calls to
+			 * scsi_scan_host and ata_host_remove, below,
+			 * at the very least
+			 */
+		}
+	}
+
+	/* probes are done, now scan each port's disk(s) */
+	DPRINTK("probe begin\n");
+	for (i = 0; i < count; i++) {
+		struct ata_port *ap = host_set->ports[i];
+
+		scsi_scan_host(ap->host);
+	}
+
+	dev_set_drvdata(dev, host_set);
+
+	VPRINTK("EXIT, returning %u\n", ent->n_ports);
+	return ent->n_ports; /* success */
+
+err_out:
+	for (i = 0; i < count; i++) {
+		ata_host_remove(host_set->ports[i], 1);
+		scsi_host_put(host_set->ports[i]->host);
+	}
+	kfree(host_set);
+	VPRINTK("EXIT, returning 0\n");
+	return 0;
+}
+
+/**
+ *	ata_scsi_release - SCSI layer callback hook for host unload
+ *	@host: libata host to be unloaded
+ *
+ *	Performs all duties necessary to shut down a libata port...
+ *	Kill port kthread, disable port, and release resources.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer.
+ *
+ *	RETURNS:
+ *	One.
+ */
+
+int ata_scsi_release(struct Scsi_Host *host)
+{
+	struct ata_port *ap = (struct ata_port *) &host->hostdata[0];
+
+	DPRINTK("ENTER\n");
+
+	ap->ops->port_disable(ap);
+	ata_host_remove(ap, 0);
+
+	DPRINTK("EXIT\n");
+	return 1;
+}
+
+/**
+ *	ata_std_ports - initialize ioaddr with standard port offsets.
+ *	@ioaddr: IO address structure to be initialized
+ */
+void ata_std_ports(struct ata_ioports *ioaddr)
+{
+	ioaddr->data_addr = ioaddr->cmd_addr + ATA_REG_DATA;
+	ioaddr->error_addr = ioaddr->cmd_addr + ATA_REG_ERR;
+	ioaddr->feature_addr = ioaddr->cmd_addr + ATA_REG_FEATURE;
+	ioaddr->nsect_addr = ioaddr->cmd_addr + ATA_REG_NSECT;
+	ioaddr->lbal_addr = ioaddr->cmd_addr + ATA_REG_LBAL;
+	ioaddr->lbam_addr = ioaddr->cmd_addr + ATA_REG_LBAM;
+	ioaddr->lbah_addr = ioaddr->cmd_addr + ATA_REG_LBAH;
+	ioaddr->device_addr = ioaddr->cmd_addr + ATA_REG_DEVICE;
+	ioaddr->status_addr = ioaddr->cmd_addr + ATA_REG_STATUS;
+	ioaddr->command_addr = ioaddr->cmd_addr + ATA_REG_CMD;
+}
+
+static struct ata_probe_ent *
+ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port)
+{
+	struct ata_probe_ent *probe_ent;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       kobject_name(&(dev->kobj)));
+		return NULL;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->dev = dev;
+
+	probe_ent->sht = port->sht;
+	probe_ent->host_flags = port->host_flags;
+	probe_ent->pio_mask = port->pio_mask;
+	probe_ent->mwdma_mask = port->mwdma_mask;
+	probe_ent->udma_mask = port->udma_mask;
+	probe_ent->port_ops = port->port_ops;
+
+	return probe_ent;
+}
+
+#ifdef CONFIG_PCI
+struct ata_probe_ent *
+ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port)
+{
+	struct ata_probe_ent *probe_ent =
+		ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent->n_ports = 2;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+
+	probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0);
+	probe_ent->port[0].altstatus_addr =
+	probe_ent->port[0].ctl_addr =
+		pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS;
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+
+	probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2);
+	probe_ent->port[1].altstatus_addr =
+	probe_ent->port[1].ctl_addr =
+		pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS;
+	probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8;
+
+	ata_std_ports(&probe_ent->port[0]);
+	ata_std_ports(&probe_ent->port[1]);
+
+	return probe_ent;
+}
+
+static struct ata_probe_ent *
+ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port,
+    struct ata_probe_ent **ppe2)
+{
+	struct ata_probe_ent *probe_ent, *probe_ent2;
+
+	probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]);
+	if (!probe_ent)
+		return NULL;
+	probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]);
+	if (!probe_ent2) {
+		kfree(probe_ent);
+		return NULL;
+	}
+
+	probe_ent->n_ports = 1;
+	probe_ent->irq = 14;
+
+	probe_ent->hard_port_no = 0;
+	probe_ent->legacy_mode = 1;
+
+	probe_ent2->n_ports = 1;
+	probe_ent2->irq = 15;
+
+	probe_ent2->hard_port_no = 1;
+	probe_ent2->legacy_mode = 1;
+
+	probe_ent->port[0].cmd_addr = 0x1f0;
+	probe_ent->port[0].altstatus_addr =
+	probe_ent->port[0].ctl_addr = 0x3f6;
+	probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4);
+
+	probe_ent2->port[0].cmd_addr = 0x170;
+	probe_ent2->port[0].altstatus_addr =
+	probe_ent2->port[0].ctl_addr = 0x376;
+	probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8;
+
+	ata_std_ports(&probe_ent->port[0]);
+	ata_std_ports(&probe_ent2->port[0]);
+
+	*ppe2 = probe_ent2;
+	return probe_ent;
+}
+
+/**
+ *	ata_pci_init_one - Initialize/register PCI IDE host controller
+ *	@pdev: Controller to be initialized
+ *	@port_info: Information from low-level host driver
+ *	@n_ports: Number of ports attached to host controller
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ *
+ *	RETURNS:
+ *
+ */
+
+int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info,
+		      unsigned int n_ports)
+{
+	struct ata_probe_ent *probe_ent, *probe_ent2 = NULL;
+	struct ata_port_info *port[2];
+	u8 tmp8, mask;
+	unsigned int legacy_mode = 0;
+	int disable_dev_on_err = 1;
+	int rc;
+
+	DPRINTK("ENTER\n");
+
+	port[0] = port_info[0];
+	if (n_ports > 1)
+		port[1] = port_info[1];
+	else
+		port[1] = port[0];
+
+	if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0
+	    && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) {
+		/* TODO: support transitioning to native mode? */
+		pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8);
+		mask = (1 << 2) | (1 << 0);
+		if ((tmp8 & mask) != mask)
+			legacy_mode = (1 << 3);
+	}
+
+	/* FIXME... */
+	if ((!legacy_mode) && (n_ports > 1)) {
+		printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n");
+		return -EINVAL;
+	}
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		disable_dev_on_err = 0;
+		goto err_out;
+	}
+
+	if (legacy_mode) {
+		if (!request_region(0x1f0, 8, "libata")) {
+			struct resource *conflict, res;
+			res.start = 0x1f0;
+			res.end = 0x1f0 + 8 - 1;
+			conflict = ____request_resource(&ioport_resource, &res);
+			if (!strcmp(conflict->name, "libata"))
+				legacy_mode |= (1 << 0);
+			else {
+				disable_dev_on_err = 0;
+				printk(KERN_WARNING "ata: 0x1f0 IDE port busy\n");
+			}
+		} else
+			legacy_mode |= (1 << 0);
+
+		if (!request_region(0x170, 8, "libata")) {
+			struct resource *conflict, res;
+			res.start = 0x170;
+			res.end = 0x170 + 8 - 1;
+			conflict = ____request_resource(&ioport_resource, &res);
+			if (!strcmp(conflict->name, "libata"))
+				legacy_mode |= (1 << 1);
+			else {
+				disable_dev_on_err = 0;
+				printk(KERN_WARNING "ata: 0x170 IDE port busy\n");
+			}
+		} else
+			legacy_mode |= (1 << 1);
+	}
+
+	/* we have legacy mode, but all ports are unavailable */
+	if (legacy_mode == (1 << 3)) {
+		rc = -EBUSY;
+		goto err_out_regions;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	if (legacy_mode) {
+		probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2);
+	} else
+		probe_ent = ata_pci_init_native_mode(pdev, port);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return */
+	if (legacy_mode) {
+		if (legacy_mode & (1 << 0))
+			ata_device_add(probe_ent);
+		if (legacy_mode & (1 << 1))
+			ata_device_add(probe_ent2);
+	} else
+		ata_device_add(probe_ent);
+
+	kfree(probe_ent);
+	kfree(probe_ent2);
+
+	return 0;
+
+err_out_regions:
+	if (legacy_mode & (1 << 0))
+		release_region(0x1f0, 8);
+	if (legacy_mode & (1 << 1))
+		release_region(0x170, 8);
+	pci_release_regions(pdev);
+err_out:
+	if (disable_dev_on_err)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+/**
+ *	ata_pci_remove_one - PCI layer callback for device removal
+ *	@pdev: PCI device that was removed
+ *
+ *	PCI layer indicates to libata via this hook that
+ *	hot-unplug or module unload event has occured.
+ *	Handle this by unregistering all objects associated
+ *	with this PCI device.  Free those objects.  Then finally
+ *	release PCI resources and disable device.
+ *
+ *	LOCKING:
+ *	Inherited from PCI layer (may sleep).
+ */
+
+void ata_pci_remove_one (struct pci_dev *pdev)
+{
+	struct device *dev = pci_dev_to_dev(pdev);
+	struct ata_host_set *host_set = dev_get_drvdata(dev);
+	struct ata_port *ap;
+	unsigned int i;
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		ap = host_set->ports[i];
+
+		scsi_remove_host(ap->host);
+	}
+
+	free_irq(host_set->irq, host_set);
+	if (host_set->ops->host_stop)
+		host_set->ops->host_stop(host_set);
+	if (host_set->mmio_base)
+		iounmap(host_set->mmio_base);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		ap = host_set->ports[i];
+
+		ata_scsi_release(ap->host);
+
+		if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) {
+			struct ata_ioports *ioaddr = &ap->ioaddr;
+
+			if (ioaddr->cmd_addr == 0x1f0)
+				release_region(0x1f0, 8);
+			else if (ioaddr->cmd_addr == 0x170)
+				release_region(0x170, 8);
+		}
+
+		scsi_host_put(ap->host);
+	}
+
+	kfree(host_set);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+	dev_set_drvdata(dev, NULL);
+}
+
+/* move to PCI subsystem */
+int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits)
+{
+	unsigned long tmp = 0;
+
+	switch (bits->width) {
+	case 1: {
+		u8 tmp8 = 0;
+		pci_read_config_byte(pdev, bits->reg, &tmp8);
+		tmp = tmp8;
+		break;
+	}
+	case 2: {
+		u16 tmp16 = 0;
+		pci_read_config_word(pdev, bits->reg, &tmp16);
+		tmp = tmp16;
+		break;
+	}
+	case 4: {
+		u32 tmp32 = 0;
+		pci_read_config_dword(pdev, bits->reg, &tmp32);
+		tmp = tmp32;
+		break;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+	tmp &= bits->mask;
+
+	return (tmp == bits->val) ? 1 : 0;
+}
+#endif /* CONFIG_PCI */
+
+
+/**
+ *	ata_init -
+ *
+ *	LOCKING:
+ *
+ *	RETURNS:
+ *
+ */
+
+static int __init ata_init(void)
+{
+	ata_wq = create_workqueue("ata");
+	if (!ata_wq)
+		return -ENOMEM;
+
+	printk(KERN_DEBUG "libata version " DRV_VERSION " loaded.\n");
+	return 0;
+}
+
+static void __exit ata_exit(void)
+{
+	destroy_workqueue(ata_wq);
+}
+
+module_init(ata_init);
+module_exit(ata_exit);
+
+/*
+ * libata is essentially a library of internal helper functions for
+ * low-level ATA host controller drivers.  As such, the API/ABI is
+ * likely to change as new drivers are added and updated.
+ * Do not depend on ABI/API stability.
+ */
+
+EXPORT_SYMBOL_GPL(ata_std_bios_param);
+EXPORT_SYMBOL_GPL(ata_std_ports);
+EXPORT_SYMBOL_GPL(ata_device_add);
+EXPORT_SYMBOL_GPL(ata_sg_init);
+EXPORT_SYMBOL_GPL(ata_sg_init_one);
+EXPORT_SYMBOL_GPL(ata_qc_complete);
+EXPORT_SYMBOL_GPL(ata_qc_issue_prot);
+EXPORT_SYMBOL_GPL(ata_eng_timeout);
+EXPORT_SYMBOL_GPL(ata_tf_load);
+EXPORT_SYMBOL_GPL(ata_tf_read);
+EXPORT_SYMBOL_GPL(ata_noop_dev_select);
+EXPORT_SYMBOL_GPL(ata_std_dev_select);
+EXPORT_SYMBOL_GPL(ata_tf_to_fis);
+EXPORT_SYMBOL_GPL(ata_tf_from_fis);
+EXPORT_SYMBOL_GPL(ata_check_status);
+EXPORT_SYMBOL_GPL(ata_altstatus);
+EXPORT_SYMBOL_GPL(ata_chk_err);
+EXPORT_SYMBOL_GPL(ata_exec_command);
+EXPORT_SYMBOL_GPL(ata_port_start);
+EXPORT_SYMBOL_GPL(ata_port_stop);
+EXPORT_SYMBOL_GPL(ata_interrupt);
+EXPORT_SYMBOL_GPL(ata_qc_prep);
+EXPORT_SYMBOL_GPL(ata_bmdma_setup);
+EXPORT_SYMBOL_GPL(ata_bmdma_start);
+EXPORT_SYMBOL_GPL(ata_bmdma_irq_clear);
+EXPORT_SYMBOL_GPL(ata_bmdma_status);
+EXPORT_SYMBOL_GPL(ata_bmdma_stop);
+EXPORT_SYMBOL_GPL(ata_port_probe);
+EXPORT_SYMBOL_GPL(sata_phy_reset);
+EXPORT_SYMBOL_GPL(__sata_phy_reset);
+EXPORT_SYMBOL_GPL(ata_bus_reset);
+EXPORT_SYMBOL_GPL(ata_port_disable);
+EXPORT_SYMBOL_GPL(ata_scsi_ioctl);
+EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
+EXPORT_SYMBOL_GPL(ata_scsi_error);
+EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
+EXPORT_SYMBOL_GPL(ata_scsi_release);
+EXPORT_SYMBOL_GPL(ata_host_intr);
+EXPORT_SYMBOL_GPL(ata_dev_classify);
+EXPORT_SYMBOL_GPL(ata_dev_id_string);
+EXPORT_SYMBOL_GPL(ata_scsi_simulate);
+
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL_GPL(pci_test_config_bits);
+EXPORT_SYMBOL_GPL(ata_pci_init_native_mode);
+EXPORT_SYMBOL_GPL(ata_pci_init_one);
+EXPORT_SYMBOL_GPL(ata_pci_remove_one);
+#endif /* CONFIG_PCI */
diff --git a/drivers/scsi/libata-scsi.c b/drivers/scsi/libata-scsi.c
new file mode 100644
index 0000000..4e5e54a
--- /dev/null
+++ b/drivers/scsi/libata-scsi.c
@@ -0,0 +1,1593 @@
+/*
+   libata-scsi.c - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/uaccess.h>
+
+#include "libata.h"
+
+typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd);
+static struct ata_device *
+ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev);
+
+
+/**
+ *	ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd.
+ *	@sdev: SCSI device for which BIOS geometry is to be determined
+ *	@bdev: block device associated with @sdev
+ *	@capacity: capacity of SCSI device
+ *	@geom: location to which geometry will be output
+ *
+ *	Generic bios head/sector/cylinder calculator
+ *	used by sd. Most BIOSes nowadays expect a XXX/255/16  (CHS)
+ *	mapping. Some situations may arise where the disk is not
+ *	bootable if this is not used.
+ *
+ *	LOCKING:
+ *	Defined by the SCSI layer.  We don't really care.
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+int ata_std_bios_param(struct scsi_device *sdev, struct block_device *bdev,
+		       sector_t capacity, int geom[])
+{
+	geom[0] = 255;
+	geom[1] = 63;
+	sector_div(capacity, 255*63);
+	geom[2] = capacity;
+
+	return 0;
+}
+
+int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg)
+{
+	struct ata_port *ap;
+	struct ata_device *dev;
+	int val = -EINVAL, rc = -EINVAL;
+
+	ap = (struct ata_port *) &scsidev->host->hostdata[0];
+	if (!ap)
+		goto out;
+
+	dev = ata_scsi_find_dev(ap, scsidev);
+	if (!dev) {
+		rc = -ENODEV;
+		goto out;
+	}
+
+	switch (cmd) {
+	case ATA_IOC_GET_IO32:
+		val = 0;
+		if (copy_to_user(arg, &val, 1))
+			return -EFAULT;
+		return 0;
+
+	case ATA_IOC_SET_IO32:
+		val = (unsigned long) arg;
+		if (val != 0)
+			return -EINVAL;
+		return 0;
+
+	default:
+		rc = -ENOTTY;
+		break;
+	}
+
+out:
+	return rc;
+}
+
+/**
+ *	ata_scsi_qc_new - acquire new ata_queued_cmd reference
+ *	@ap: ATA port to which the new command is attached
+ *	@dev: ATA device to which the new command is attached
+ *	@cmd: SCSI command that originated this ATA command
+ *	@done: SCSI command completion function
+ *
+ *	Obtain a reference to an unused ata_queued_cmd structure,
+ *	which is the basic libata structure representing a single
+ *	ATA command sent to the hardware.
+ *
+ *	If a command was available, fill in the SCSI-specific
+ *	portions of the structure with information on the
+ *	current command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Command allocated, or %NULL if none available.
+ */
+struct ata_queued_cmd *ata_scsi_qc_new(struct ata_port *ap,
+				       struct ata_device *dev,
+				       struct scsi_cmnd *cmd,
+				       void (*done)(struct scsi_cmnd *))
+{
+	struct ata_queued_cmd *qc;
+
+	qc = ata_qc_new_init(ap, dev);
+	if (qc) {
+		qc->scsicmd = cmd;
+		qc->scsidone = done;
+
+		if (cmd->use_sg) {
+			qc->sg = (struct scatterlist *) cmd->request_buffer;
+			qc->n_elem = cmd->use_sg;
+		} else {
+			qc->sg = &qc->sgent;
+			qc->n_elem = 1;
+		}
+	} else {
+		cmd->result = (DID_OK << 16) | (QUEUE_FULL << 1);
+		done(cmd);
+	}
+
+	return qc;
+}
+
+/**
+ *	ata_to_sense_error - convert ATA error to SCSI error
+ *	@qc: Command that we are erroring out
+ *	@drv_stat: value contained in ATA status register
+ *
+ *	Converts an ATA error into a SCSI error. While we are at it
+ *	we decode and dump the ATA error for the user so that they
+ *	have some idea what really happened at the non make-believe
+ *	layer.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	u8 err = 0;
+	unsigned char *sb = cmd->sense_buffer;
+	/* Based on the 3ware driver translation table */
+	static unsigned char sense_table[][4] = {
+		/* BBD|ECC|ID|MAR */
+		{0xd1, 		ABORTED_COMMAND, 0x00, 0x00}, 	// Device busy                  Aborted command
+		/* BBD|ECC|ID */
+		{0xd0,  	ABORTED_COMMAND, 0x00, 0x00}, 	// Device busy                  Aborted command
+		/* ECC|MC|MARK */
+		{0x61, 		HARDWARE_ERROR, 0x00, 0x00}, 	// Device fault                 Hardware error
+		/* ICRC|ABRT */		/* NB: ICRC & !ABRT is BBD */
+		{0x84, 		ABORTED_COMMAND, 0x47, 0x00}, 	// Data CRC error               SCSI parity error
+		/* MC|ID|ABRT|TRK0|MARK */
+		{0x37, 		NOT_READY, 0x04, 0x00}, 	// Unit offline                 Not ready
+		/* MCR|MARK */
+		{0x09, 		NOT_READY, 0x04, 0x00}, 	// Unrecovered disk error       Not ready
+		/*  Bad address mark */
+		{0x01, 		MEDIUM_ERROR, 0x13, 0x00}, 	// Address mark not found       Address mark not found for data field
+		/* TRK0 */
+		{0x02, 		HARDWARE_ERROR, 0x00, 0x00}, 	// Track 0 not found		  Hardware error
+		/* Abort & !ICRC */
+		{0x04, 		ABORTED_COMMAND, 0x00, 0x00}, 	// Aborted command              Aborted command
+		/* Media change request */
+		{0x08, 		NOT_READY, 0x04, 0x00}, 	// Media change request	  FIXME: faking offline
+		/* SRV */
+		{0x10, 		ABORTED_COMMAND, 0x14, 0x00}, 	// ID not found                 Recorded entity not found
+		/* Media change */
+		{0x08,  	NOT_READY, 0x04, 0x00}, 	// Media change		  FIXME: faking offline
+		/* ECC */
+		{0x40, 		MEDIUM_ERROR, 0x11, 0x04}, 	// Uncorrectable ECC error      Unrecovered read error
+		/* BBD - block marked bad */
+		{0x80, 		MEDIUM_ERROR, 0x11, 0x04}, 	// Block marked bad		  Medium error, unrecovered read error
+		{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+	};
+	static unsigned char stat_table[][4] = {
+		/* Must be first because BUSY means no other bits valid */
+		{0x80, 		ABORTED_COMMAND, 0x47, 0x00},	// Busy, fake parity for now
+		{0x20, 		HARDWARE_ERROR,  0x00, 0x00}, 	// Device fault
+		{0x08, 		ABORTED_COMMAND, 0x47, 0x00},	// Timed out in xfer, fake parity for now
+		{0x04, 		RECOVERED_ERROR, 0x11, 0x00},	// Recovered ECC error	  Medium error, recovered
+		{0xFF, 0xFF, 0xFF, 0xFF}, // END mark
+	};
+	int i = 0;
+
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+	/*
+	 *	Is this an error we can process/parse
+	 */
+
+	if(drv_stat & ATA_ERR)
+		/* Read the err bits */
+		err = ata_chk_err(qc->ap);
+
+	/* Display the ATA level error info */
+
+	printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat);
+	if(drv_stat & 0x80)
+	{
+		printk("Busy ");
+		err = 0;	/* Data is not valid in this case */
+	}
+	else {
+		if(drv_stat & 0x40)	printk("DriveReady ");
+		if(drv_stat & 0x20)	printk("DeviceFault ");
+		if(drv_stat & 0x10)	printk("SeekComplete ");
+		if(drv_stat & 0x08)	printk("DataRequest ");
+		if(drv_stat & 0x04)	printk("CorrectedError ");
+		if(drv_stat & 0x02)	printk("Index ");
+		if(drv_stat & 0x01)	printk("Error ");
+	}
+	printk("}\n");
+
+	if(err)
+	{
+		printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err);
+		if(err & 0x04)		printk("DriveStatusError ");
+		if(err & 0x80)
+		{
+			if(err & 0x04)
+				printk("BadCRC ");
+			else
+				printk("Sector ");
+		}
+		if(err & 0x40)		printk("UncorrectableError ");
+		if(err & 0x10)		printk("SectorIdNotFound ");
+		if(err & 0x02)		printk("TrackZeroNotFound ");
+		if(err & 0x01)		printk("AddrMarkNotFound ");
+		printk("}\n");
+
+		/* Should we dump sector info here too ?? */
+	}
+
+
+	/* Look for err */
+	while(sense_table[i][0] != 0xFF)
+	{
+		/* Look for best matches first */
+		if((sense_table[i][0] & err) == sense_table[i][0])
+		{
+			sb[0] = 0x70;
+			sb[2] = sense_table[i][1];
+			sb[7] = 0x0a;
+			sb[12] = sense_table[i][2];
+			sb[13] = sense_table[i][3];
+			return;
+		}
+		i++;
+	}
+	/* No immediate match */
+	if(err)
+		printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err);
+
+	i = 0;
+	/* Fall back to interpreting status bits */
+	while(stat_table[i][0] != 0xFF)
+	{
+		if(stat_table[i][0] & drv_stat)
+		{
+			sb[0] = 0x70;
+			sb[2] = stat_table[i][1];
+			sb[7] = 0x0a;
+			sb[12] = stat_table[i][2];
+			sb[13] = stat_table[i][3];
+			return;
+		}
+		i++;
+	}
+	/* No error ?? */
+	printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat);
+	/* additional-sense-code[-qualifier] */
+
+	sb[0] = 0x70;
+	sb[2] = MEDIUM_ERROR;
+	sb[7] = 0x0A;
+	if (cmd->sc_data_direction == SCSI_DATA_READ) {
+		sb[12] = 0x11; /* "unrecovered read error" */
+		sb[13] = 0x04;
+	} else {
+		sb[12] = 0x0C; /* "write error -             */
+		sb[13] = 0x02; /*  auto-reallocation failed" */
+	}
+}
+
+/**
+ *	ata_scsi_slave_config - Set SCSI device attributes
+ *	@sdev: SCSI device to examine
+ *
+ *	This is called before we actually start reading
+ *	and writing to the device, to configure certain
+ *	SCSI mid-layer behaviors.
+ *
+ *	LOCKING:
+ *	Defined by SCSI layer.  We don't really care.
+ */
+
+int ata_scsi_slave_config(struct scsi_device *sdev)
+{
+	sdev->use_10_for_rw = 1;
+	sdev->use_10_for_ms = 1;
+
+	blk_queue_max_phys_segments(sdev->request_queue, LIBATA_MAX_PRD);
+
+	if (sdev->id < ATA_MAX_DEVICES) {
+		struct ata_port *ap;
+		struct ata_device *dev;
+
+		ap = (struct ata_port *) &sdev->host->hostdata[0];
+		dev = &ap->device[sdev->id];
+
+		/* TODO: 1024 is an arbitrary number, not the
+		 * hardware maximum.  This should be increased to
+		 * 65534 when Jens Axboe's patch for dynamically
+		 * determining max_sectors is merged.
+		 */
+		if ((dev->flags & ATA_DFLAG_LBA48) &&
+		    ((dev->flags & ATA_DFLAG_LOCK_SECTORS) == 0)) {
+			sdev->host->max_sectors = 2048;
+			blk_queue_max_sectors(sdev->request_queue, 2048);
+		}
+	}
+
+	return 0;	/* scsi layer doesn't check return value, sigh */
+}
+
+/**
+ *	ata_scsi_error - SCSI layer error handler callback
+ *	@host: SCSI host on which error occurred
+ *
+ *	Handles SCSI-layer-thrown error events.
+ *
+ *	LOCKING:
+ *	Inherited from SCSI layer (none, can sleep)
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+
+int ata_scsi_error(struct Scsi_Host *host)
+{
+	struct ata_port *ap;
+
+	DPRINTK("ENTER\n");
+
+	ap = (struct ata_port *) &host->hostdata[0];
+	ap->ops->eng_timeout(ap);
+
+	/* TODO: this is per-command; when queueing is supported
+	 * this code will either change or move to a more
+	 * appropriate place
+	 */
+	host->host_failed--;
+
+	DPRINTK("EXIT\n");
+	return 0;
+}
+
+/**
+ *	ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate (ignored)
+ *
+ *	Sets up an ATA taskfile to issue FLUSH CACHE or
+ *	FLUSH CACHE EXT.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+
+	tf->flags |= ATA_TFLAG_DEVICE;
+	tf->protocol = ATA_PROT_NODATA;
+
+	if ((tf->flags & ATA_TFLAG_LBA48) &&
+	    (ata_id_has_flush_ext(qc->dev->id)))
+		tf->command = ATA_CMD_FLUSH_EXT;
+	else
+		tf->command = ATA_CMD_FLUSH;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Converts SCSI VERIFY command to an ATA READ VERIFY command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+	u64 dev_sectors = qc->dev->n_sectors;
+	u64 sect = 0;
+	u32 n_sect = 0;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->protocol = ATA_PROT_NODATA;
+	tf->device |= ATA_LBA;
+
+	if (scsicmd[0] == VERIFY) {
+		sect |= ((u64)scsicmd[2]) << 24;
+		sect |= ((u64)scsicmd[3]) << 16;
+		sect |= ((u64)scsicmd[4]) << 8;
+		sect |= ((u64)scsicmd[5]);
+
+		n_sect |= ((u32)scsicmd[7]) << 8;
+		n_sect |= ((u32)scsicmd[8]);
+	}
+
+	else if (scsicmd[0] == VERIFY_16) {
+		sect |= ((u64)scsicmd[2]) << 56;
+		sect |= ((u64)scsicmd[3]) << 48;
+		sect |= ((u64)scsicmd[4]) << 40;
+		sect |= ((u64)scsicmd[5]) << 32;
+		sect |= ((u64)scsicmd[6]) << 24;
+		sect |= ((u64)scsicmd[7]) << 16;
+		sect |= ((u64)scsicmd[8]) << 8;
+		sect |= ((u64)scsicmd[9]);
+
+		n_sect |= ((u32)scsicmd[10]) << 24;
+		n_sect |= ((u32)scsicmd[11]) << 16;
+		n_sect |= ((u32)scsicmd[12]) << 8;
+		n_sect |= ((u32)scsicmd[13]);
+	}
+
+	else
+		return 1;
+
+	if (!n_sect)
+		return 1;
+	if (sect >= dev_sectors)
+		return 1;
+	if ((sect + n_sect) > dev_sectors)
+		return 1;
+	if (lba48) {
+		if (n_sect > (64 * 1024))
+			return 1;
+	} else {
+		if (n_sect > 256)
+			return 1;
+	}
+
+	if (lba48) {
+		tf->command = ATA_CMD_VERIFY_EXT;
+
+		tf->hob_nsect = (n_sect >> 8) & 0xff;
+
+		tf->hob_lbah = (sect >> 40) & 0xff;
+		tf->hob_lbam = (sect >> 32) & 0xff;
+		tf->hob_lbal = (sect >> 24) & 0xff;
+	} else {
+		tf->command = ATA_CMD_VERIFY;
+
+		tf->device |= (sect >> 24) & 0xf;
+	}
+
+	tf->nsect = n_sect & 0xff;
+
+	tf->lbah = (sect >> 16) & 0xff;
+	tf->lbam = (sect >> 8) & 0xff;
+	tf->lbal = sect & 0xff;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_rw_xlat - Translate SCSI r/w command into an ATA one
+ *	@qc: Storage for translated ATA taskfile
+ *	@scsicmd: SCSI command to translate
+ *
+ *	Converts any of six SCSI read/write commands into the
+ *	ATA counterpart, including starting sector (LBA),
+ *	sector count, and taking into account the device's LBA48
+ *	support.
+ *
+ *	Commands %READ_6, %READ_10, %READ_16, %WRITE_6, %WRITE_10, and
+ *	%WRITE_16 are currently supported.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on error.
+ */
+
+static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct ata_taskfile *tf = &qc->tf;
+	unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48;
+
+	tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	tf->protocol = qc->dev->xfer_protocol;
+	tf->device |= ATA_LBA;
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 ||
+	    scsicmd[0] == READ_16) {
+		tf->command = qc->dev->read_cmd;
+	} else {
+		tf->command = qc->dev->write_cmd;
+		tf->flags |= ATA_TFLAG_WRITE;
+	}
+
+	if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) {
+		if (lba48) {
+			tf->hob_nsect = scsicmd[7];
+			tf->hob_lbal = scsicmd[2];
+
+			qc->nsect = ((unsigned int)scsicmd[7] << 8) |
+					scsicmd[8];
+		} else {
+			/* if we don't support LBA48 addressing, the request
+			 * -may- be too large. */
+			if ((scsicmd[2] & 0xf0) || scsicmd[7])
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[2];
+
+			qc->nsect = scsicmd[8];
+		}
+
+		tf->nsect = scsicmd[8];
+		tf->lbal = scsicmd[5];
+		tf->lbam = scsicmd[4];
+		tf->lbah = scsicmd[3];
+
+		VPRINTK("ten-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) {
+		qc->nsect = tf->nsect = scsicmd[4];
+		tf->lbal = scsicmd[3];
+		tf->lbam = scsicmd[2];
+		tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */
+
+		VPRINTK("six-byte command\n");
+		return 0;
+	}
+
+	if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) {
+		/* rule out impossible LBAs and sector counts */
+		if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11])
+			return 1;
+
+		if (lba48) {
+			tf->hob_nsect = scsicmd[12];
+			tf->hob_lbal = scsicmd[6];
+			tf->hob_lbam = scsicmd[5];
+			tf->hob_lbah = scsicmd[4];
+
+			qc->nsect = ((unsigned int)scsicmd[12] << 8) |
+					scsicmd[13];
+		} else {
+			/* once again, filter out impossible non-zero values */
+			if (scsicmd[4] || scsicmd[5] || scsicmd[12] ||
+			    (scsicmd[6] & 0xf0))
+				return 1;
+
+			/* stores LBA27:24 in lower 4 bits of device reg */
+			tf->device |= scsicmd[6];
+
+			qc->nsect = scsicmd[13];
+		}
+
+		tf->nsect = scsicmd[13];
+		tf->lbal = scsicmd[9];
+		tf->lbam = scsicmd[8];
+		tf->lbah = scsicmd[7];
+
+		VPRINTK("sixteen-byte command\n");
+		return 0;
+	}
+
+	DPRINTK("no-byte command\n");
+	return 1;
+}
+
+static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ)))
+		ata_to_sense_error(qc, drv_stat);
+	else
+		cmd->result = SAM_STAT_GOOD;
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_translate - Translate then issue SCSI command to ATA device
+ *	@ap: ATA port to which the command is addressed
+ *	@dev: ATA device to which the command is addressed
+ *	@cmd: SCSI command to execute
+ *	@done: SCSI command completion function
+ *	@xlat_func: Actor which translates @cmd to an ATA taskfile
+ *
+ *	Our ->queuecommand() function has decided that the SCSI
+ *	command issued can be directly translated into an ATA
+ *	command, rather than handled internally.
+ *
+ *	This function sets up an ata_queued_cmd structure for the
+ *	SCSI command, and sends that ata_queued_cmd to the hardware.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void ata_scsi_translate(struct ata_port *ap, struct ata_device *dev,
+			      struct scsi_cmnd *cmd,
+			      void (*done)(struct scsi_cmnd *),
+			      ata_xlat_func_t xlat_func)
+{
+	struct ata_queued_cmd *qc;
+	u8 *scsicmd = cmd->cmnd;
+
+	VPRINTK("ENTER\n");
+
+	qc = ata_scsi_qc_new(ap, dev, cmd, done);
+	if (!qc)
+		return;
+
+	/* data is present; dma-map it */
+	if (cmd->sc_data_direction == SCSI_DATA_READ ||
+	    cmd->sc_data_direction == SCSI_DATA_WRITE) {
+		if (unlikely(cmd->request_bufflen < 1)) {
+			printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n",
+			       ap->id, dev->devno);
+			goto err_out;
+		}
+
+		if (cmd->use_sg)
+			ata_sg_init(qc, cmd->request_buffer, cmd->use_sg);
+		else
+			ata_sg_init_one(qc, cmd->request_buffer,
+					cmd->request_bufflen);
+
+		qc->dma_dir = cmd->sc_data_direction;
+	}
+
+	qc->complete_fn = ata_scsi_qc_complete;
+
+	if (xlat_func(qc, scsicmd))
+		goto err_out;
+
+	/* select device, send command to hardware */
+	if (ata_qc_issue(qc))
+		goto err_out;
+
+	VPRINTK("EXIT\n");
+	return;
+
+err_out:
+	ata_qc_free(qc);
+	ata_bad_cdb(cmd, done);
+	DPRINTK("EXIT - badcmd\n");
+}
+
+/**
+ *	ata_scsi_rbuf_get - Map response buffer.
+ *	@cmd: SCSI command containing buffer to be mapped.
+ *	@buf_out: Pointer to mapped area.
+ *
+ *	Maps buffer contained within SCSI command @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Length of response buffer.
+ */
+
+static unsigned int ata_scsi_rbuf_get(struct scsi_cmnd *cmd, u8 **buf_out)
+{
+	u8 *buf;
+	unsigned int buflen;
+
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		buf = kmap_atomic(sg->page, KM_USER0) + sg->offset;
+		buflen = sg->length;
+	} else {
+		buf = cmd->request_buffer;
+		buflen = cmd->request_bufflen;
+	}
+
+	*buf_out = buf;
+	return buflen;
+}
+
+/**
+ *	ata_scsi_rbuf_put - Unmap response buffer.
+ *	@cmd: SCSI command containing buffer to be unmapped.
+ *	@buf: buffer to unmap
+ *
+ *	Unmaps response buffer contained within @cmd.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static inline void ata_scsi_rbuf_put(struct scsi_cmnd *cmd, u8 *buf)
+{
+	if (cmd->use_sg) {
+		struct scatterlist *sg;
+
+		sg = (struct scatterlist *) cmd->request_buffer;
+		kunmap_atomic(buf - sg->offset, KM_USER0);
+	}
+}
+
+/**
+ *	ata_scsi_rbuf_fill - wrapper for SCSI command simulators
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@actor: Callback hook for desired SCSI command simulator
+ *
+ *	Takes care of the hard work of simulating a SCSI command...
+ *	Mapping the response buffer, calling the command's handler,
+ *	and handling the handler's return value.  This return value
+ *	indicates whether the handler wishes the SCSI command to be
+ *	completed successfully, or not.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_scsi_rbuf_fill(struct ata_scsi_args *args,
+		        unsigned int (*actor) (struct ata_scsi_args *args,
+			     		   u8 *rbuf, unsigned int buflen))
+{
+	u8 *rbuf;
+	unsigned int buflen, rc;
+	struct scsi_cmnd *cmd = args->cmd;
+
+	buflen = ata_scsi_rbuf_get(cmd, &rbuf);
+	memset(rbuf, 0, buflen);
+	rc = actor(args, rbuf, buflen);
+	ata_scsi_rbuf_put(cmd, rbuf);
+
+	if (rc)
+		ata_bad_cdb(cmd, args->done);
+	else {
+		cmd->result = SAM_STAT_GOOD;
+		args->done(cmd);
+	}
+}
+
+/**
+ *	ata_scsiop_inq_std - Simulate INQUIRY command
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns standard device identification data associated
+ *	with non-EVPD INQUIRY command output.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+			       unsigned int buflen)
+{
+	u8 hdr[] = {
+		TYPE_DISK,
+		0,
+		0x5,	/* claim SPC-3 version compatibility */
+		2,
+		95 - 4
+	};
+
+	/* set scsi removeable (RMB) bit per ata bit */
+	if (ata_id_removeable(args->id))
+		hdr[1] |= (1 << 7);
+
+	VPRINTK("ENTER\n");
+
+	memcpy(rbuf, hdr, sizeof(hdr));
+
+	if (buflen > 35) {
+		memcpy(&rbuf[8], "ATA     ", 8);
+		ata_dev_id_string(args->id, &rbuf[16], ATA_ID_PROD_OFS, 16);
+		ata_dev_id_string(args->id, &rbuf[32], ATA_ID_FW_REV_OFS, 4);
+		if (rbuf[32] == 0 || rbuf[32] == ' ')
+			memcpy(&rbuf[32], "n/a ", 4);
+	}
+
+	if (buflen > 63) {
+		const u8 versions[] = {
+			0x60,	/* SAM-3 (no version claimed) */
+
+			0x03,
+			0x20,	/* SBC-2 (no version claimed) */
+
+			0x02,
+			0x60	/* SPC-3 (no version claimed) */
+		};
+
+		memcpy(rbuf + 59, versions, sizeof(versions));
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_inq_00 - Simulate INQUIRY EVPD page 0, list of pages
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns list of inquiry EVPD pages available.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	const u8 pages[] = {
+		0x00,	/* page 0x00, this page */
+		0x80,	/* page 0x80, unit serial no page */
+		0x83	/* page 0x83, device ident page */
+	};
+	rbuf[3] = sizeof(pages);	/* number of supported EVPD pages */
+
+	if (buflen > 6)
+		memcpy(rbuf + 4, pages, sizeof(pages));
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_inq_80 - Simulate INQUIRY EVPD page 80, device serial number
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns ATA device serial number.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	const u8 hdr[] = {
+		0,
+		0x80,			/* this page code */
+		0,
+		ATA_SERNO_LEN,		/* page len */
+	};
+	memcpy(rbuf, hdr, sizeof(hdr));
+
+	if (buflen > (ATA_SERNO_LEN + 4 - 1))
+		ata_dev_id_string(args->id, (unsigned char *) &rbuf[4],
+				  ATA_ID_SERNO_OFS, ATA_SERNO_LEN);
+
+	return 0;
+}
+
+static const char *inq_83_str = "Linux ATA-SCSI simulator";
+
+/**
+ *	ata_scsiop_inq_83 - Simulate INQUIRY EVPD page 83, device identity
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Returns device identification.  Currently hardcoded to
+ *	return "Linux ATA-SCSI simulator".
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen)
+{
+	rbuf[1] = 0x83;			/* this page code */
+	rbuf[3] = 4 + strlen(inq_83_str);	/* page len */
+
+	/* our one and only identification descriptor (vendor-specific) */
+	if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) {
+		rbuf[4 + 0] = 2;	/* code set: ASCII */
+		rbuf[4 + 3] = strlen(inq_83_str);
+		memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str));
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_noop -
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	No operation.  Simply returns success to caller, to indicate
+ *	that the caller should successfully complete this SCSI command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+			    unsigned int buflen)
+{
+	VPRINTK("ENTER\n");
+	return 0;
+}
+
+/**
+ *	ata_msense_push - Push data onto MODE SENSE data output buffer
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *	@buf: Pointer to BLOB being added to output buffer
+ *	@buflen: Length of BLOB
+ *
+ *	Store MODE SENSE data on an output buffer.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static void ata_msense_push(u8 **ptr_io, const u8 *last,
+			    const u8 *buf, unsigned int buflen)
+{
+	u8 *ptr = *ptr_io;
+
+	if ((ptr + buflen - 1) > last)
+		return;
+
+	memcpy(ptr, buf, buflen);
+
+	ptr += buflen;
+
+	*ptr_io = ptr;
+}
+
+/**
+ *	ata_msense_caching - Simulate MODE SENSE caching info page
+ *	@id: device IDENTIFY data
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *
+ *	Generate a caching info page, which conditionally indicates
+ *	write caching to the SCSI layer, depending on device
+ *	capabilities.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io,
+				       const u8 *last)
+{
+	u8 page[] = {
+		0x8,				/* page code */
+		0x12,				/* page length */
+		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,	/* 10 zeroes */
+		0, 0, 0, 0, 0, 0, 0, 0		/* 8 zeroes */
+	};
+
+	if (ata_id_wcache_enabled(id))
+		page[2] |= (1 << 2);	/* write cache enable */
+	if (!ata_id_rahead_enabled(id))
+		page[12] |= (1 << 5);	/* disable read ahead */
+
+	ata_msense_push(ptr_io, last, page, sizeof(page));
+	return sizeof(page);
+}
+
+/**
+ *	ata_msense_ctl_mode - Simulate MODE SENSE control mode page
+ *	@dev: Device associated with this MODE SENSE command
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *
+ *	Generate a generic MODE SENSE control mode page.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last)
+{
+	const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30};
+
+	/* byte 2: set the descriptor format sense data bit (bit 2)
+	 * since we need to support returning this format for SAT
+	 * commands and any SCSI commands against a 48b LBA device.
+	 */
+
+	ata_msense_push(ptr_io, last, page, sizeof(page));
+	return sizeof(page);
+}
+
+/**
+ *	ata_msense_rw_recovery - Simulate MODE SENSE r/w error recovery page
+ *	@dev: Device associated with this MODE SENSE command
+ *	@ptr_io: (input/output) Location to store more output data
+ *	@last: End of output data buffer
+ *
+ *	Generate a generic MODE SENSE r/w error recovery page.
+ *
+ *	LOCKING:
+ *	None.
+ */
+
+static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last)
+{
+	const u8 page[] = {
+		0x1,			  /* page code */
+		0xa,			  /* page length */
+		(1 << 7) | (1 << 6),	  /* note auto r/w reallocation */
+		0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */
+	};
+
+	ata_msense_push(ptr_io, last, page, sizeof(page));
+	return sizeof(page);
+}
+
+/**
+ *	ata_scsiop_mode_sense - Simulate MODE SENSE 6, 10 commands
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate MODE SENSE commands.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen)
+{
+	u8 *scsicmd = args->cmd->cmnd, *p, *last;
+	unsigned int page_control, six_byte, output_len;
+
+	VPRINTK("ENTER\n");
+
+	six_byte = (scsicmd[0] == MODE_SENSE);
+
+	/* we only support saved and current values (which we treat
+	 * in the same manner)
+	 */
+	page_control = scsicmd[2] >> 6;
+	if ((page_control != 0) && (page_control != 3))
+		return 1;
+
+	if (six_byte)
+		output_len = 4;
+	else
+		output_len = 8;
+
+	p = rbuf + output_len;
+	last = rbuf + buflen - 1;
+
+	switch(scsicmd[2] & 0x3f) {
+	case 0x01:		/* r/w error recovery */
+		output_len += ata_msense_rw_recovery(&p, last);
+		break;
+
+	case 0x08:		/* caching */
+		output_len += ata_msense_caching(args->id, &p, last);
+		break;
+
+	case 0x0a: {		/* control mode */
+		output_len += ata_msense_ctl_mode(&p, last);
+		break;
+		}
+
+	case 0x3f:		/* all pages */
+		output_len += ata_msense_rw_recovery(&p, last);
+		output_len += ata_msense_caching(args->id, &p, last);
+		output_len += ata_msense_ctl_mode(&p, last);
+		break;
+
+	default:		/* invalid page code */
+		return 1;
+	}
+
+	if (six_byte) {
+		output_len--;
+		rbuf[0] = output_len;
+	} else {
+		output_len -= 2;
+		rbuf[0] = output_len >> 8;
+		rbuf[1] = output_len;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_read_cap - Simulate READ CAPACITY[ 16] commands
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate READ CAPACITY commands.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+			        unsigned int buflen)
+{
+	u64 n_sectors;
+	u32 tmp;
+
+	VPRINTK("ENTER\n");
+
+	if (ata_id_has_lba48(args->id))
+		n_sectors = ata_id_u64(args->id, 100);
+	else
+		n_sectors = ata_id_u32(args->id, 60);
+	n_sectors--;		/* ATA TotalUserSectors - 1 */
+
+	tmp = n_sectors;	/* note: truncates, if lba48 */
+	if (args->cmd->cmnd[0] == READ_CAPACITY) {
+		/* sector count, 32-bit */
+		rbuf[0] = tmp >> (8 * 3);
+		rbuf[1] = tmp >> (8 * 2);
+		rbuf[2] = tmp >> (8 * 1);
+		rbuf[3] = tmp;
+
+		/* sector size */
+		tmp = ATA_SECT_SIZE;
+		rbuf[6] = tmp >> 8;
+		rbuf[7] = tmp;
+
+	} else {
+		/* sector count, 64-bit */
+		rbuf[2] = n_sectors >> (8 * 7);
+		rbuf[3] = n_sectors >> (8 * 6);
+		rbuf[4] = n_sectors >> (8 * 5);
+		rbuf[5] = n_sectors >> (8 * 4);
+		rbuf[6] = tmp >> (8 * 3);
+		rbuf[7] = tmp >> (8 * 2);
+		rbuf[8] = tmp >> (8 * 1);
+		rbuf[9] = tmp;
+
+		/* sector size */
+		tmp = ATA_SECT_SIZE;
+		rbuf[12] = tmp >> 8;
+		rbuf[13] = tmp;
+	}
+
+	return 0;
+}
+
+/**
+ *	ata_scsiop_report_luns - Simulate REPORT LUNS command
+ *	@args: device IDENTIFY data / SCSI command of interest.
+ *	@rbuf: Response buffer, to which simulated SCSI cmd output is sent.
+ *	@buflen: Response buffer length.
+ *
+ *	Simulate REPORT LUNS command.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+				   unsigned int buflen)
+{
+	VPRINTK("ENTER\n");
+	rbuf[3] = 8;	/* just one lun, LUN 0, size 8 bytes */
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_badcmd - End a SCSI request with an error
+ *	@cmd: SCSI request to be handled
+ *	@done: SCSI command completion function
+ *	@asc: SCSI-defined additional sense code
+ *	@ascq: SCSI-defined additional sense code qualifier
+ *
+ *	Helper function that completes a SCSI command with
+ *	%SAM_STAT_CHECK_CONDITION, with a sense key %ILLEGAL_REQUEST
+ *	and the specified additional sense codes.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq)
+{
+	DPRINTK("ENTER\n");
+	cmd->result = SAM_STAT_CHECK_CONDITION;
+
+	cmd->sense_buffer[0] = 0x70;
+	cmd->sense_buffer[2] = ILLEGAL_REQUEST;
+	cmd->sense_buffer[7] = 14 - 8;	/* addnl. sense len. FIXME: correct? */
+	cmd->sense_buffer[12] = asc;
+	cmd->sense_buffer[13] = ascq;
+
+	done(cmd);
+}
+
+static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+
+	if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) {
+		DPRINTK("request check condition\n");
+
+		cmd->result = SAM_STAT_CHECK_CONDITION;
+
+		qc->scsidone(cmd);
+
+		return 1;
+	} else {
+		u8 *scsicmd = cmd->cmnd;
+
+		if (scsicmd[0] == INQUIRY) {
+			u8 *buf = NULL;
+			unsigned int buflen;
+
+			buflen = ata_scsi_rbuf_get(cmd, &buf);
+			buf[2] = 0x5;
+			buf[3] = (buf[3] & 0xf0) | 2;
+			ata_scsi_rbuf_put(cmd, buf);
+		}
+		cmd->result = SAM_STAT_GOOD;
+	}
+
+	qc->scsidone(cmd);
+
+	return 0;
+}
+/**
+ *	atapi_xlat - Initialize PACKET taskfile
+ *	@qc: command structure to be initialized
+ *	@scsicmd: SCSI CDB associated with this PACKET command
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Zero on success, non-zero on failure.
+ */
+
+static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
+{
+	struct scsi_cmnd *cmd = qc->scsicmd;
+	struct ata_device *dev = qc->dev;
+	int using_pio = (dev->flags & ATA_DFLAG_PIO);
+	int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE);
+
+	if (!using_pio)
+		/* Check whether ATAPI DMA is safe */
+		if (ata_check_atapi_dma(qc))
+			using_pio = 1;
+
+	memcpy(&qc->cdb, scsicmd, qc->ap->cdb_len);
+
+	qc->complete_fn = atapi_qc_complete;
+
+	qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
+	if (cmd->sc_data_direction == SCSI_DATA_WRITE) {
+		qc->tf.flags |= ATA_TFLAG_WRITE;
+		DPRINTK("direction: write\n");
+	}
+
+	qc->tf.command = ATA_CMD_PACKET;
+
+	/* no data, or PIO data xfer */
+	if (using_pio || nodata) {
+		if (nodata)
+			qc->tf.protocol = ATA_PROT_ATAPI_NODATA;
+		else
+			qc->tf.protocol = ATA_PROT_ATAPI;
+		qc->tf.lbam = (8 * 1024) & 0xff;
+		qc->tf.lbah = (8 * 1024) >> 8;
+	}
+
+	/* DMA data xfer */
+	else {
+		qc->tf.protocol = ATA_PROT_ATAPI_DMA;
+		qc->tf.feature |= ATAPI_PKT_DMA;
+
+#ifdef ATAPI_ENABLE_DMADIR
+		/* some SATA bridges need us to indicate data xfer direction */
+		if (cmd->sc_data_direction != SCSI_DATA_WRITE)
+			qc->tf.feature |= ATAPI_DMADIR;
+#endif
+	}
+
+	qc->nbytes = cmd->bufflen;
+
+	return 0;
+}
+
+/**
+ *	ata_scsi_find_dev - lookup ata_device from scsi_cmnd
+ *	@ap: ATA port to which the device is attached
+ *	@scsidev: SCSI device from which we derive the ATA device
+ *
+ *	Given various information provided in struct scsi_cmnd,
+ *	map that onto an ATA bus, and using that mapping
+ *	determine which ata_device is associated with the
+ *	SCSI command to be sent.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ *
+ *	RETURNS:
+ *	Associated ATA device, or %NULL if not found.
+ */
+
+static struct ata_device *
+ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev)
+{
+	struct ata_device *dev;
+
+	/* skip commands not addressed to targets we simulate */
+	if (likely(scsidev->id < ATA_MAX_DEVICES))
+		dev = &ap->device[scsidev->id];
+	else
+		return NULL;
+
+	if (unlikely((scsidev->channel != 0) ||
+		     (scsidev->lun != 0)))
+		return NULL;
+
+	if (unlikely(!ata_dev_present(dev)))
+		return NULL;
+
+#ifndef ATA_ENABLE_ATAPI
+	if (unlikely(dev->class == ATA_DEV_ATAPI))
+		return NULL;
+#endif
+
+	return dev;
+}
+
+/**
+ *	ata_get_xlat_func - check if SCSI to ATA translation is possible
+ *	@dev: ATA device
+ *	@cmd: SCSI command opcode to consider
+ *
+ *	Look up the SCSI command given, and determine whether the
+ *	SCSI command is to be translated or simulated.
+ *
+ *	RETURNS:
+ *	Pointer to translation function if possible, %NULL if not.
+ */
+
+static inline ata_xlat_func_t ata_get_xlat_func(struct ata_device *dev, u8 cmd)
+{
+	switch (cmd) {
+	case READ_6:
+	case READ_10:
+	case READ_16:
+
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_16:
+		return ata_scsi_rw_xlat;
+
+	case SYNCHRONIZE_CACHE:
+		if (ata_try_flush_cache(dev))
+			return ata_scsi_flush_xlat;
+		break;
+
+	case VERIFY:
+	case VERIFY_16:
+		return ata_scsi_verify_xlat;
+	}
+
+	return NULL;
+}
+
+/**
+ *	ata_scsi_dump_cdb - dump SCSI command contents to dmesg
+ *	@ap: ATA port to which the command was being sent
+ *	@cmd: SCSI command to dump
+ *
+ *	Prints the contents of a SCSI command via printk().
+ */
+
+static inline void ata_scsi_dump_cdb(struct ata_port *ap,
+				     struct scsi_cmnd *cmd)
+{
+#ifdef ATA_DEBUG
+	struct scsi_device *scsidev = cmd->device;
+	u8 *scsicmd = cmd->cmnd;
+
+	DPRINTK("CDB (%u:%d,%d,%d) %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
+		ap->id,
+		scsidev->channel, scsidev->id, scsidev->lun,
+		scsicmd[0], scsicmd[1], scsicmd[2], scsicmd[3],
+		scsicmd[4], scsicmd[5], scsicmd[6], scsicmd[7],
+		scsicmd[8]);
+#endif
+}
+
+/**
+ *	ata_scsi_queuecmd - Issue SCSI cdb to libata-managed device
+ *	@cmd: SCSI command to be sent
+ *	@done: Completion function, called when command is complete
+ *
+ *	In some cases, this function translates SCSI commands into
+ *	ATA taskfiles, and queues the taskfiles to be sent to
+ *	hardware.  In other cases, this function simulates a
+ *	SCSI device by evaluating and responding to certain
+ *	SCSI commands.  This creates the overall effect of
+ *	ATA and ATAPI devices appearing as SCSI devices.
+ *
+ *	LOCKING:
+ *	Releases scsi-layer-held lock, and obtains host_set lock.
+ *
+ *	RETURNS:
+ *	Zero.
+ */
+
+int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct ata_port *ap;
+	struct ata_device *dev;
+	struct scsi_device *scsidev = cmd->device;
+
+	ap = (struct ata_port *) &scsidev->host->hostdata[0];
+
+	ata_scsi_dump_cdb(ap, cmd);
+
+	dev = ata_scsi_find_dev(ap, scsidev);
+	if (unlikely(!dev)) {
+		cmd->result = (DID_BAD_TARGET << 16);
+		done(cmd);
+		goto out_unlock;
+	}
+
+	if (dev->class == ATA_DEV_ATA) {
+		ata_xlat_func_t xlat_func = ata_get_xlat_func(dev,
+							      cmd->cmnd[0]);
+
+		if (xlat_func)
+			ata_scsi_translate(ap, dev, cmd, done, xlat_func);
+		else
+			ata_scsi_simulate(dev->id, cmd, done);
+	} else
+		ata_scsi_translate(ap, dev, cmd, done, atapi_xlat);
+
+out_unlock:
+	return 0;
+}
+
+/**
+ *	ata_scsi_simulate - simulate SCSI command on ATA device
+ *	@id: current IDENTIFY data for target device.
+ *	@cmd: SCSI command being sent to device.
+ *	@done: SCSI command completion function.
+ *
+ *	Interprets and directly executes a select list of SCSI commands
+ *	that can be handled internally.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+void ata_scsi_simulate(u16 *id,
+		      struct scsi_cmnd *cmd,
+		      void (*done)(struct scsi_cmnd *))
+{
+	struct ata_scsi_args args;
+	u8 *scsicmd = cmd->cmnd;
+
+	args.id = id;
+	args.cmd = cmd;
+	args.done = done;
+
+	switch(scsicmd[0]) {
+		/* no-op's, complete with success */
+		case SYNCHRONIZE_CACHE:
+		case REZERO_UNIT:
+		case SEEK_6:
+		case SEEK_10:
+		case TEST_UNIT_READY:
+		case FORMAT_UNIT:		/* FIXME: correct? */
+		case SEND_DIAGNOSTIC:		/* FIXME: correct? */
+			ata_scsi_rbuf_fill(&args, ata_scsiop_noop);
+			break;
+
+		case INQUIRY:
+			if (scsicmd[1] & 2)	           /* is CmdDt set?  */
+				ata_bad_cdb(cmd, done);
+			else if ((scsicmd[1] & 1) == 0)    /* is EVPD clear? */
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std);
+			else if (scsicmd[2] == 0x00)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_00);
+			else if (scsicmd[2] == 0x80)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_80);
+			else if (scsicmd[2] == 0x83)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case MODE_SENSE:
+		case MODE_SENSE_10:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_mode_sense);
+			break;
+
+		case MODE_SELECT:	/* unconditionally return */
+		case MODE_SELECT_10:	/* bad-field-in-cdb */
+			ata_bad_cdb(cmd, done);
+			break;
+
+		case READ_CAPACITY:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			break;
+
+		case SERVICE_ACTION_IN:
+			if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
+				ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
+			else
+				ata_bad_cdb(cmd, done);
+			break;
+
+		case REPORT_LUNS:
+			ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns);
+			break;
+
+		/* mandantory commands we haven't implemented yet */
+		case REQUEST_SENSE:
+
+		/* all other commands */
+		default:
+			ata_bad_scsiop(cmd, done);
+			break;
+	}
+}
+
diff --git a/drivers/scsi/libata.h b/drivers/scsi/libata.h
new file mode 100644
index 0000000..6518226
--- /dev/null
+++ b/drivers/scsi/libata.h
@@ -0,0 +1,89 @@
+/*
+   libata.h - helper library for ATA
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+ */
+
+#ifndef __LIBATA_H__
+#define __LIBATA_H__
+
+#define DRV_NAME	"libata"
+#define DRV_VERSION	"1.10"	/* must be exactly four chars */
+
+struct ata_scsi_args {
+	u16			*id;
+	struct scsi_cmnd	*cmd;
+	void			(*done)(struct scsi_cmnd *);
+};
+
+/* libata-core.c */
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
+				      struct ata_device *dev);
+extern void ata_qc_free(struct ata_queued_cmd *qc);
+extern int ata_qc_issue(struct ata_queued_cmd *qc);
+extern int ata_check_atapi_dma(struct ata_queued_cmd *qc);
+extern void ata_dev_select(struct ata_port *ap, unsigned int device,
+                           unsigned int wait, unsigned int can_sleep);
+extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf);
+extern void swap_buf_le16(u16 *buf, unsigned int buf_words);
+
+
+/* libata-scsi.c */
+extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat);
+extern int ata_scsi_error(struct Scsi_Host *host);
+extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf,
+			       unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_00(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+
+extern unsigned int ata_scsiop_inq_80(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+extern unsigned int ata_scsiop_inq_83(struct ata_scsi_args *args, u8 *rbuf,
+			      unsigned int buflen);
+extern unsigned int ata_scsiop_noop(struct ata_scsi_args *args, u8 *rbuf,
+			    unsigned int buflen);
+extern unsigned int ata_scsiop_sync_cache(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen);
+extern unsigned int ata_scsiop_mode_sense(struct ata_scsi_args *args, u8 *rbuf,
+				  unsigned int buflen);
+extern unsigned int ata_scsiop_read_cap(struct ata_scsi_args *args, u8 *rbuf,
+			        unsigned int buflen);
+extern unsigned int ata_scsiop_report_luns(struct ata_scsi_args *args, u8 *rbuf,
+				   unsigned int buflen);
+extern void ata_scsi_badcmd(struct scsi_cmnd *cmd,
+			    void (*done)(struct scsi_cmnd *),
+			    u8 asc, u8 ascq);
+extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, 
+                        unsigned int (*actor) (struct ata_scsi_args *args,
+                                           u8 *rbuf, unsigned int buflen));
+
+static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	ata_scsi_badcmd(cmd, done, 0x20, 0x00);
+}
+
+static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	ata_scsi_badcmd(cmd, done, 0x24, 0x00);
+}
+
+#endif /* __LIBATA_H__ */
diff --git a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
new file mode 100644
index 0000000..3ef2a14
--- /dev/null
+++ b/drivers/scsi/mac53c94.c
@@ -0,0 +1,582 @@
+/*
+ * SCSI low-level driver for the 53c94 SCSI bus adaptor found
+ * on Power Macintosh computers, controlling the external SCSI chain.
+ * We assume the 53c94 is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/pci-bridge.h>
+#include <asm/macio.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "mac53c94.h"
+
+enum fsc_phase {
+	idle,
+	selecting,
+	dataing,
+	completing,
+	busfreeing,
+};
+
+struct fsc_state {
+	struct	mac53c94_regs __iomem *regs;
+	int	intr;
+	struct	dbdma_regs __iomem *dma;
+	int	dmaintr;
+	int	clk_freq;
+	struct	Scsi_Host *host;
+	struct scsi_cmnd *request_q;
+	struct scsi_cmnd *request_qtail;
+	struct scsi_cmnd *current_req;		/* req we're currently working on */
+	enum fsc_phase phase;		/* what we're currently trying to do */
+	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
+	void	*dma_cmd_space;
+	struct	pci_dev *pdev;
+	dma_addr_t dma_addr;
+	struct macio_dev *mdev;
+};
+
+static void mac53c94_init(struct fsc_state *);
+static void mac53c94_start(struct fsc_state *);
+static void mac53c94_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
+static void cmd_done(struct fsc_state *, int result);
+static void set_dma_cmds(struct fsc_state *, struct scsi_cmnd *);
+
+
+static int mac53c94_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct fsc_state *state;
+
+#if 0
+	if (cmd->sc_data_direction == DMA_TO_DEVICE) {
+		int i;
+		printk(KERN_DEBUG "mac53c94_queue %p: command is", cmd);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			printk(" %.2x", cmd->cmnd[i]);
+		printk("\n" KERN_DEBUG "use_sg=%d request_bufflen=%d request_buffer=%p\n",
+		       cmd->use_sg, cmd->request_bufflen, cmd->request_buffer);
+	}
+#endif
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+
+	state = (struct fsc_state *) cmd->device->host->hostdata;
+
+	if (state->request_q == NULL)
+		state->request_q = cmd;
+	else
+		state->request_qtail->host_scribble = (void *) cmd;
+	state->request_qtail = cmd;
+
+	if (state->phase == idle)
+		mac53c94_start(state);
+
+	return 0;
+}
+
+static int mac53c94_abort(struct scsi_cmnd *cmd)
+{
+	return FAILED;
+}
+
+static int mac53c94_host_reset(struct scsi_cmnd *cmd)
+{
+	struct fsc_state *state = (struct fsc_state *) cmd->device->host->hostdata;
+	struct mac53c94_regs __iomem *regs = state->regs;
+	struct dbdma_regs __iomem *dma = state->dma;
+
+	writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
+	writeb(CMD_SCSI_RESET, &regs->command);	/* assert RST */
+	udelay(100);			/* leave it on for a while (>= 25us) */
+	writeb(CMD_RESET, &regs->command);
+	udelay(20);
+	mac53c94_init(state);
+	writeb(CMD_NOP, &regs->command);
+	return SUCCESS;
+}
+
+static void mac53c94_init(struct fsc_state *state)
+{
+	struct mac53c94_regs __iomem *regs = state->regs;
+	struct dbdma_regs __iomem *dma = state->dma;
+	int x;
+
+	writeb(state->host->this_id | CF1_PAR_ENABLE, &regs->config1);
+	writeb(TIMO_VAL(250), &regs->sel_timeout);	/* 250ms */
+	writeb(CLKF_VAL(state->clk_freq), &regs->clk_factor);
+	writeb(CF2_FEATURE_EN, &regs->config2);
+	writeb(0, &regs->config3);
+	writeb(0, &regs->sync_period);
+	writeb(0, &regs->sync_offset);
+	x = readb(&regs->interrupt);
+	writel((RUN|PAUSE|FLUSH|WAKE) << 16, &dma->control);
+}
+
+/*
+ * Start the next command for a 53C94.
+ * Should be called with interrupts disabled.
+ */
+static void mac53c94_start(struct fsc_state *state)
+{
+	struct scsi_cmnd *cmd;
+	struct mac53c94_regs __iomem *regs = state->regs;
+	int i;
+
+	if (state->phase != idle || state->current_req != NULL)
+		panic("inappropriate mac53c94_start (state=%p)", state);
+	if (state->request_q == NULL)
+		return;
+	state->current_req = cmd = state->request_q;
+	state->request_q = (struct scsi_cmnd *) cmd->host_scribble;
+
+	/* Off we go */
+	writeb(0, &regs->count_lo);
+	writeb(0, &regs->count_mid);
+	writeb(0, &regs->count_hi);
+	writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
+	udelay(1);
+	writeb(CMD_FLUSH, &regs->command);
+	udelay(1);
+	writeb(cmd->device->id, &regs->dest_id);
+	writeb(0, &regs->sync_period);
+	writeb(0, &regs->sync_offset);
+
+	/* load the command into the FIFO */
+	for (i = 0; i < cmd->cmd_len; ++i)
+		writeb(cmd->cmnd[i], &regs->fifo);
+
+	/* do select without ATN XXX */
+	writeb(CMD_SELECT, &regs->command);
+	state->phase = selecting;
+
+	if (cmd->use_sg > 0 || cmd->request_bufflen != 0)
+		set_dma_cmds(state, cmd);
+}
+
+static irqreturn_t do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = ((struct fsc_state *) dev_id)->current_req->device->host;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
+	mac53c94_interrupt(irq, dev_id, ptregs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct fsc_state *state = (struct fsc_state *) dev_id;
+	struct mac53c94_regs __iomem *regs = state->regs;
+	struct dbdma_regs __iomem *dma = state->dma;
+	struct scsi_cmnd *cmd = state->current_req;
+	int nb, stat, seq, intr;
+	static int mac53c94_errors;
+
+	/*
+	 * Apparently, reading the interrupt register unlatches
+	 * the status and sequence step registers.
+	 */
+	seq = readb(&regs->seqstep);
+	stat = readb(&regs->status);
+	intr = readb(&regs->interrupt);
+
+#if 0
+	printk(KERN_DEBUG "mac53c94_intr, intr=%x stat=%x seq=%x phase=%d\n",
+	       intr, stat, seq, state->phase);
+#endif
+
+	if (intr & INTR_RESET) {
+		/* SCSI bus was reset */
+		printk(KERN_INFO "external SCSI bus reset detected\n");
+		writeb(CMD_NOP, &regs->command);
+		writel(RUN << 16, &dma->control);	/* stop dma */
+		cmd_done(state, DID_RESET << 16);
+		return;
+	}
+	if (intr & INTR_ILL_CMD) {
+		printk(KERN_ERR "53c94: invalid cmd, intr=%x stat=%x seq=%x phase=%d\n",
+		       intr, stat, seq, state->phase);
+		cmd_done(state, DID_ERROR << 16);
+		return;
+	}
+	if (stat & STAT_ERROR) {
+#if 0
+		/* XXX these seem to be harmless? */
+		printk("53c94: bad error, intr=%x stat=%x seq=%x phase=%d\n",
+		       intr, stat, seq, state->phase);
+#endif
+		++mac53c94_errors;
+		writeb(CMD_NOP + CMD_DMA_MODE, &regs->command);
+	}
+	if (cmd == 0) {
+		printk(KERN_DEBUG "53c94: interrupt with no command active?\n");
+		return;
+	}
+	if (stat & STAT_PARITY) {
+		printk(KERN_ERR "mac53c94: parity error\n");
+		cmd_done(state, DID_PARITY << 16);
+		return;
+	}
+	switch (state->phase) {
+	case selecting:
+		if (intr & INTR_DISCONNECT) {
+			/* selection timed out */
+			cmd_done(state, DID_BAD_TARGET << 16);
+			return;
+		}
+		if (intr != INTR_BUS_SERV + INTR_DONE) {
+			printk(KERN_DEBUG "got intr %x during selection\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		if ((seq & SS_MASK) != SS_DONE) {
+			printk(KERN_DEBUG "seq step %x after command\n", seq);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		writeb(CMD_NOP, &regs->command);
+		/* set DMA controller going if any data to transfer */
+		if ((stat & (STAT_MSG|STAT_CD)) == 0
+		    && (cmd->use_sg > 0 || cmd->request_bufflen != 0)) {
+			nb = cmd->SCp.this_residual;
+			if (nb > 0xfff0)
+				nb = 0xfff0;
+			cmd->SCp.this_residual -= nb;
+			writeb(nb, &regs->count_lo);
+			writeb(nb >> 8, &regs->count_mid);
+			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
+			writel(virt_to_phys(state->dma_cmds), &dma->cmdptr);
+			writel((RUN << 16) | RUN, &dma->control);
+			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
+			state->phase = dataing;
+			break;
+		} else if ((stat & STAT_PHASE) == STAT_CD + STAT_IO) {
+			/* up to status phase already */
+			writeb(CMD_I_COMPLETE, &regs->command);
+			state->phase = completing;
+		} else {
+			printk(KERN_DEBUG "in unexpected phase %x after cmd\n",
+			       stat & STAT_PHASE);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		break;
+
+	case dataing:
+		if (intr != INTR_BUS_SERV) {
+			printk(KERN_DEBUG "got intr %x before status\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		if (cmd->SCp.this_residual != 0
+		    && (stat & (STAT_MSG|STAT_CD)) == 0) {
+			/* Set up the count regs to transfer more */
+			nb = cmd->SCp.this_residual;
+			if (nb > 0xfff0)
+				nb = 0xfff0;
+			cmd->SCp.this_residual -= nb;
+			writeb(nb, &regs->count_lo);
+			writeb(nb >> 8, &regs->count_mid);
+			writeb(CMD_DMA_MODE + CMD_NOP, &regs->command);
+			writeb(CMD_DMA_MODE + CMD_XFER_DATA, &regs->command);
+			break;
+		}
+		if ((stat & STAT_PHASE) != STAT_CD + STAT_IO) {
+			printk(KERN_DEBUG "intr %x before data xfer complete\n", intr);
+		}
+		writel(RUN << 16, &dma->control);	/* stop dma */
+		if (cmd->use_sg != 0) {
+			pci_unmap_sg(state->pdev,
+				(struct scatterlist *)cmd->request_buffer,
+				cmd->use_sg, cmd->sc_data_direction);
+		} else {
+			pci_unmap_single(state->pdev, state->dma_addr,
+				cmd->request_bufflen, cmd->sc_data_direction);
+		}
+		/* should check dma status */
+		writeb(CMD_I_COMPLETE, &regs->command);
+		state->phase = completing;
+		break;
+	case completing:
+		if (intr != INTR_DONE) {
+			printk(KERN_DEBUG "got intr %x on completion\n", intr);
+			cmd_done(state, DID_ERROR << 16);
+			return;
+		}
+		cmd->SCp.Status = readb(&regs->fifo);
+		cmd->SCp.Message = readb(&regs->fifo);
+		cmd->result = CMD_ACCEPT_MSG;
+		writeb(CMD_ACCEPT_MSG, &regs->command);
+		state->phase = busfreeing;
+		break;
+	case busfreeing:
+		if (intr != INTR_DISCONNECT) {
+			printk(KERN_DEBUG "got intr %x when expected disconnect\n", intr);
+		}
+		cmd_done(state, (DID_OK << 16) + (cmd->SCp.Message << 8)
+			 + cmd->SCp.Status);
+		break;
+	default:
+		printk(KERN_DEBUG "don't know about phase %d\n", state->phase);
+	}
+}
+
+static void cmd_done(struct fsc_state *state, int result)
+{
+	struct scsi_cmnd *cmd;
+
+	cmd = state->current_req;
+	if (cmd != 0) {
+		cmd->result = result;
+		(*cmd->scsi_done)(cmd);
+		state->current_req = NULL;
+	}
+	state->phase = idle;
+	mac53c94_start(state);
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void set_dma_cmds(struct fsc_state *state, struct scsi_cmnd *cmd)
+{
+	int i, dma_cmd, total;
+	struct scatterlist *scl;
+	struct dbdma_cmd *dcmds;
+	dma_addr_t dma_addr;
+	u32 dma_len;
+
+	dma_cmd = cmd->sc_data_direction == DMA_TO_DEVICE ?
+			OUTPUT_MORE : INPUT_MORE;
+	dcmds = state->dma_cmds;
+	if (cmd->use_sg > 0) {
+		int nseg;
+
+		total = 0;
+		scl = (struct scatterlist *) cmd->buffer;
+		nseg = pci_map_sg(state->pdev, scl, cmd->use_sg,
+				cmd->sc_data_direction);
+		for (i = 0; i < nseg; ++i) {
+			dma_addr = sg_dma_address(scl);
+			dma_len = sg_dma_len(scl);
+			if (dma_len > 0xffff)
+				panic("mac53c94: scatterlist element >= 64k");
+			total += dma_len;
+			st_le16(&dcmds->req_count, dma_len);
+			st_le16(&dcmds->command, dma_cmd);
+			st_le32(&dcmds->phy_addr, dma_addr);
+			dcmds->xfer_status = 0;
+			++scl;
+			++dcmds;
+		}
+	} else {
+		total = cmd->request_bufflen;
+		if (total > 0xffff)
+			panic("mac53c94: transfer size >= 64k");
+		dma_addr = pci_map_single(state->pdev, cmd->request_buffer,
+					  total, cmd->sc_data_direction);
+		state->dma_addr = dma_addr;
+		st_le16(&dcmds->req_count, total);
+		st_le32(&dcmds->phy_addr, dma_addr);
+		dcmds->xfer_status = 0;
+		++dcmds;
+	}
+	dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+	st_le16(&dcmds[-1].command, dma_cmd);
+	st_le16(&dcmds->command, DBDMA_STOP);
+	cmd->SCp.this_residual = total;
+}
+
+static struct scsi_host_template mac53c94_template = {
+	.proc_name	= "53c94",
+	.name		= "53C94",
+	.queuecommand	= mac53c94_queue,
+	.eh_abort_handler = mac53c94_abort,
+	.eh_host_reset_handler = mac53c94_host_reset,
+	.can_queue	= 1,
+	.this_id	= 7,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun	= 1,
+	.use_clustering	= DISABLE_CLUSTERING,
+};
+
+static int mac53c94_probe(struct macio_dev *mdev, const struct of_match *match)
+{
+	struct device_node *node = macio_get_of_node(mdev);
+	struct pci_dev *pdev = macio_get_pci_dev(mdev);
+	struct fsc_state *state;
+	struct Scsi_Host *host;
+	void *dma_cmd_space;
+	unsigned char *clkprop;
+	int proplen;
+
+	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
+		printk(KERN_ERR "mac53c94: expected 2 addrs and intrs (got %d/%d)\n",
+		       node->n_addrs, node->n_intrs);
+		return -ENODEV;
+	}
+
+	if (macio_request_resources(mdev, "mac53c94") != 0) {
+       		printk(KERN_ERR "mac53c94: unable to request memory resources");
+		return -EBUSY;
+	}
+
+       	host = scsi_host_alloc(&mac53c94_template, sizeof(struct fsc_state));
+	if (host == NULL) {
+		printk(KERN_ERR "mac53c94: couldn't register host");
+		goto out_release;
+	}
+
+	state = (struct fsc_state *) host->hostdata;
+	macio_set_drvdata(mdev, state);
+	state->host = host;
+	state->pdev = pdev;
+	state->mdev = mdev;
+
+	state->regs = (struct mac53c94_regs __iomem *)
+		ioremap(macio_resource_start(mdev, 0), 0x1000);
+	state->intr = macio_irq(mdev, 0);
+	state->dma = (struct dbdma_regs __iomem *)
+		ioremap(macio_resource_start(mdev, 1), 0x1000);
+	state->dmaintr = macio_irq(mdev, 1);
+	if (state->regs == NULL || state->dma == NULL) {
+		printk(KERN_ERR "mac53c94: ioremap failed for %s\n",
+		       node->full_name);
+		goto out_free;
+	}
+
+       	clkprop = get_property(node, "clock-frequency", &proplen);
+       	if (clkprop == NULL || proplen != sizeof(int)) {
+       		printk(KERN_ERR "%s: can't get clock frequency, "
+       		       "assuming 25MHz\n", node->full_name);
+       		state->clk_freq = 25000000;
+       	} else
+       		state->clk_freq = *(int *)clkprop;
+
+       	/* Space for dma command list: +1 for stop command,
+       	 * +1 to allow for aligning.
+	 * XXX FIXME: Use DMA consistent routines
+	 */
+       	dma_cmd_space = kmalloc((host->sg_tablesize + 2) *
+       				sizeof(struct dbdma_cmd), GFP_KERNEL);
+       	if (dma_cmd_space == 0) {
+       		printk(KERN_ERR "mac53c94: couldn't allocate dma "
+       		       "command space for %s\n", node->full_name);
+       		goto out_free;
+       	}
+	state->dma_cmds = (struct dbdma_cmd *)DBDMA_ALIGN(dma_cmd_space);
+	memset(state->dma_cmds, 0, (host->sg_tablesize + 1)
+	       * sizeof(struct dbdma_cmd));
+	state->dma_cmd_space = dma_cmd_space;
+
+	mac53c94_init(state);
+
+	if (request_irq(state->intr, do_mac53c94_interrupt, 0, "53C94", state)) {
+		printk(KERN_ERR "mac53C94: can't get irq %d for %s\n",
+		       state->intr, node->full_name);
+		goto out_free_dma;
+	}
+
+	/* XXX FIXME: handle failure */
+	scsi_add_host(host, &mdev->ofdev.dev);
+	scsi_scan_host(host);
+
+	return 0;
+
+ out_free_dma:
+	kfree(state->dma_cmd_space);
+ out_free:
+	if (state->dma != NULL)
+		iounmap(state->dma);
+	if (state->regs != NULL)
+		iounmap(state->regs);
+	scsi_host_put(host);
+ out_release:
+	macio_release_resources(mdev);
+
+	return  -ENODEV;
+}
+
+static int mac53c94_remove(struct macio_dev *mdev)
+{
+	struct fsc_state *fp = (struct fsc_state *)macio_get_drvdata(mdev);
+	struct Scsi_Host *host = fp->host;
+
+	scsi_remove_host(host);
+
+	free_irq(fp->intr, fp);
+
+	if (fp->regs)
+		iounmap((void *) fp->regs);
+	if (fp->dma)
+		iounmap((void *) fp->dma);
+	kfree(fp->dma_cmd_space);
+
+	scsi_host_put(host);
+
+	macio_release_resources(mdev);
+
+	return 0;
+}
+
+
+static struct of_match mac53c94_match[] = 
+{
+	{
+	.name 		= "53c94",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH
+	},
+	{},
+};
+
+static struct macio_driver mac53c94_driver = 
+{
+	.name 		= "mac53c94",
+	.match_table	= mac53c94_match,
+	.probe		= mac53c94_probe,
+	.remove		= mac53c94_remove,
+};
+
+
+static int __init init_mac53c94(void)
+{
+	return macio_register_driver(&mac53c94_driver);
+}
+
+static void __exit exit_mac53c94(void)
+{
+	return macio_unregister_driver(&mac53c94_driver);
+}
+
+module_init(init_mac53c94);
+module_exit(exit_mac53c94);
+
+MODULE_DESCRIPTION("PowerMac 53c94 SCSI driver");
+MODULE_AUTHOR("Paul Mackerras <paulus@samba.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/mac53c94.h b/drivers/scsi/mac53c94.h
new file mode 100644
index 0000000..1ad24e4
--- /dev/null
+++ b/drivers/scsi/mac53c94.h
@@ -0,0 +1,214 @@
+/*
+ * mac53c94.h: definitions for the driver for the 53c94 SCSI bus adaptor
+ * found on Power Macintosh computers, controlling the external SCSI chain.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MAC53C94_H
+#define _MAC53C94_H
+
+/*
+ * Registers in the 53C94 controller.
+ */
+
+struct mac53c94_regs {
+	unsigned char	count_lo;
+	char pad0[15];
+	unsigned char	count_mid;
+	char pad1[15];
+	unsigned char	fifo;
+	char pad2[15];
+	unsigned char	command;
+	char pad3[15];
+	unsigned char	status;
+	char pad4[15];
+	unsigned char	interrupt;
+	char pad5[15];
+	unsigned char	seqstep;
+	char pad6[15];
+	unsigned char	flags;
+	char pad7[15];
+	unsigned char	config1;
+	char pad8[15];
+	unsigned char	clk_factor;
+	char pad9[15];
+	unsigned char	test;
+	char pad10[15];
+	unsigned char	config2;
+	char pad11[15];
+	unsigned char	config3;
+	char pad12[15];
+	unsigned char	config4;
+	char pad13[15];
+	unsigned char	count_hi;
+	char pad14[15];
+	unsigned char	fifo_res;
+	char pad15[15];
+};
+
+/*
+ * Alternate functions for some registers.
+ */
+#define dest_id		status
+#define sel_timeout	interrupt
+#define sync_period	seqstep
+#define sync_offset	flags
+
+/*
+ * Bits in command register.
+ */
+#define CMD_DMA_MODE	0x80
+#define CMD_MODE_MASK	0x70
+#define CMD_MODE_INIT	0x10
+#define CMD_MODE_TARG	0x20
+#define CMD_MODE_DISC	0x40
+
+#define CMD_NOP		0
+#define CMD_FLUSH	1
+#define CMD_RESET	2
+#define CMD_SCSI_RESET	3
+
+#define CMD_XFER_DATA	0x10
+#define CMD_I_COMPLETE	0x11
+#define CMD_ACCEPT_MSG	0x12
+#define CMD_XFER_PAD	0x18
+#define CMD_SET_ATN	0x1a
+#define CMD_CLR_ATN	0x1b
+
+#define CMD_SEND_MSG	0x20
+#define CMD_SEND_STATUS	0x21
+#define CMD_SEND_DATA	0x22
+#define CMD_DISC_SEQ	0x23
+#define CMD_TERMINATE	0x24
+#define CMD_T_COMPLETE	0x25
+#define CMD_DISCONNECT	0x27
+#define CMD_RECV_MSG	0x28
+#define CMD_RECV_CDB	0x29
+#define CMD_RECV_DATA	0x2a
+#define CMD_RECV_CMD	0x2b
+#define CMD_ABORT_DMA	0x04
+
+#define CMD_RESELECT	0x40
+#define CMD_SELECT	0x41
+#define CMD_SELECT_ATN	0x42
+#define CMD_SELATN_STOP	0x43
+#define CMD_ENABLE_SEL	0x44
+#define CMD_DISABLE_SEL	0x45
+#define CMD_SEL_ATN3	0x46
+#define CMD_RESEL_ATN3	0x47
+
+/*
+ * Bits in status register.
+ */
+#define STAT_IRQ	0x80
+#define STAT_ERROR	0x40
+#define STAT_PARITY	0x20
+#define STAT_TC_ZERO	0x10
+#define STAT_DONE	0x08
+#define STAT_PHASE	0x07
+#define STAT_MSG	0x04
+#define STAT_CD		0x02
+#define STAT_IO		0x01
+
+/*
+ * Bits in interrupt register.
+ */
+#define INTR_RESET	0x80	/* SCSI bus was reset */
+#define INTR_ILL_CMD	0x40	/* illegal command */
+#define INTR_DISCONNECT	0x20	/* we got disconnected */
+#define INTR_BUS_SERV	0x10	/* bus service requested */
+#define INTR_DONE	0x08	/* function completed */
+#define INTR_RESELECTED	0x04	/* we were reselected */
+#define INTR_SEL_ATN	0x02	/* we were selected, ATN asserted */
+#define INTR_SELECT	0x01	/* we were selected, ATN negated */
+
+/*
+ * Encoding for the select timeout.
+ */
+#define TIMO_VAL(x)	((x) * 5000 / 7682)
+
+/*
+ * Bits in sequence step register.
+ */
+#define SS_MASK		7
+#define SS_ARB_SEL	0	/* Selection & arbitration complete */
+#define SS_MSG_SENT	1	/* One message byte sent */
+#define SS_NOT_CMD	2	/* Not in command phase */
+#define SS_PHASE_CHG	3	/* Early phase change, cmd bytes lost */
+#define SS_DONE		4	/* Command was sent OK */
+
+/*
+ * Encoding for sync transfer period.
+ */
+#define SYNCP_MASK	0x1f
+#define SYNCP_MIN	4
+#define SYNCP_MAX	31
+
+/*
+ * Bits in flags register.
+ */
+#define FLAGS_FIFO_LEV	0x1f
+#define FLAGS_SEQ_STEP	0xe0
+
+/*
+ * Encoding for sync offset.
+ */
+#define SYNCO_MASK	0x0f
+#define SYNCO_ASS_CTRL	0x30	/* REQ/ACK assertion control */
+#define SYNCO_NEG_CTRL	0xc0	/* REQ/ACK negation control */
+
+/*
+ * Bits in config1 register.
+ */
+#define CF1_SLOW_CABLE	0x80	/* Slow cable mode */
+#define CF1_NO_RES_REP	0x40	/* Disable SCSI reset reports */
+#define CF1_PAR_TEST	0x20	/* Parity test mode enable */
+#define CF1_PAR_ENABLE	0x10	/* Enable parity checks */
+#define CF1_TEST	0x08	/* Chip tests */
+#define CF1_MY_ID	0x07	/* Controller's address on bus */
+
+/*
+ * Encoding for clk_factor register.
+ */
+#define CLKF_MASK	7
+#define CLKF_VAL(freq)	((((freq) + 4999999) / 5000000) & CLKF_MASK)
+
+/*
+ * Bits in test mode register.
+ */
+#define TEST_TARGET	1	/* target test mode */
+#define TEST_INITIATOR	2	/* initiator test mode */
+#define TEST_TRISTATE	4	/* tristate (hi-z) test mode */
+
+/*
+ * Bits in config2 register.
+ */
+#define CF2_RFB		0x80
+#define CF2_FEATURE_EN	0x40	/* enable features / phase latch */
+#define CF2_BYTECTRL	0x20
+#define CF2_DREQ_HIZ	0x10
+#define CF2_SCSI2	0x08
+#define CF2_PAR_ABORT	0x04	/* bad parity target abort */
+#define CF2_REG_PARERR	0x02	/* register parity error */
+#define CF2_DMA_PARERR	0x01	/* DMA parity error */
+
+/*
+ * Bits in the config3 register.
+ */
+#define CF3_ID_MSG_CHK	0x80
+#define CF3_3B_MSGS	0x40
+#define CF3_CDB10	0x20
+#define CF3_FASTSCSI	0x10	/* enable fast SCSI support */
+#define CF3_FASTCLOCK	0x08
+#define CF3_SAVERESID	0x04
+#define CF3_ALT_DMA	0x02
+#define CF3_THRESH_8	0x01
+
+/*
+ * Bits in the config4 register.
+ */
+#define CF4_EAN		0x04
+#define CF4_TEST	0x02
+#define CF4_BBTE	0x01
+
+#endif /* _MAC53C94_H */
diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c
new file mode 100644
index 0000000..c94c8db
--- /dev/null
+++ b/drivers/scsi/mac_esp.c
@@ -0,0 +1,754 @@
+/*
+ * 68k mac 53c9[46] scsi driver
+ *
+ * copyright (c) 1998, David Weis weisd3458@uni.edu
+ *
+ * debugging on Quadra 800 and 660AV Michael Schmitz, Dave Kilzer 7/98
+ *
+ * based loosely on cyber_esp.c
+ */
+
+/* these are unused for now */
+#define myreadl(addr) (*(volatile unsigned int *) (addr))
+#define mywritel(b, addr) ((*(volatile unsigned int *) (addr)) = (b))
+
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/ctype.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <asm/io.h>
+
+#include <asm/setup.h>
+#include <asm/irq.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+#include <asm/pgtable.h>
+
+#include <asm/macintosh.h>
+
+/* #define DEBUG_MAC_ESP */
+
+#define mac_turnon_irq(x)	mac_enable_irq(x)
+#define mac_turnoff_irq(x)	mac_disable_irq(x)
+
+extern void esp_handle(struct NCR_ESP *esp);
+extern void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs);
+
+static int  dma_bytes_sent(struct NCR_ESP * esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP * esp);
+static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length);
+static void dma_ints_off(struct NCR_ESP * esp);
+static void dma_ints_on(struct NCR_ESP * esp);
+static int  dma_irq_p(struct NCR_ESP * esp);
+static int  dma_irq_p_quick(struct NCR_ESP * esp);
+static void dma_led_off(struct NCR_ESP * esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write);
+static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write);
+
+static int esp_dafb_dma_irq_p(struct NCR_ESP * espdev);
+static int esp_iosb_dma_irq_p(struct NCR_ESP * espdev);
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are transferred to the ESP chip
+				 * via PIO.
+				 */
+
+static int esp_initialized = 0;
+
+static int setup_num_esps = -1;
+static int setup_disconnect = -1;
+static int setup_nosync = -1;
+static int setup_can_queue = -1;
+static int setup_cmd_per_lun = -1;
+static int setup_sg_tablesize = -1;
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+#endif
+static int setup_hostid = -1;
+
+/*
+ * Experimental ESP inthandler; check macints.c to make sure dev_id is 
+ * set up properly!
+ */
+
+void mac_esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *) dev_id;
+	int irq_p = 0;
+
+	/* Handle the one ESP interrupt showing at this IRQ level. */
+	if(((esp)->irq & 0xff) == irq) {
+	/*
+	 * Debug ..
+	 */
+		irq_p = esp->dma_irq_p(esp);
+	 	printk("mac_esp: irq_p %x current %p disconnected %p\n",
+	 		irq_p, esp->current_SC, esp->disconnected_SC);
+	 		
+		/*
+		 * Mac: if we're here, it's an ESP interrupt for sure!
+		 */
+		if((esp->current_SC || esp->disconnected_SC)) {
+			esp->dma_ints_off(esp);
+
+			ESPIRQ(("I%d(", esp->esp_id));
+			esp_handle(esp);
+			ESPIRQ((")"));
+
+			esp->dma_ints_on(esp);
+		}
+	}
+}
+
+/*
+ * Debug hooks; use for playing with the interrupt flag testing and interrupt
+ * acknowledge on the various machines
+ */
+
+void scsi_esp_polled(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	if (esp_initialized == 0)
+		return;
+
+	mac_esp_intr(irq, dev_id, pregs);
+}
+
+void fake_intr(int irq, void *dev_id, struct pt_regs *pregs)
+{
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: got irq\n");
+#endif
+
+	mac_esp_intr(irq, dev_id, pregs);
+}
+
+irqreturn_t fake_drq(int irq, void *dev_id, struct pt_regs *pregs)
+{
+	printk("mac_esp: got drq\n");
+	return IRQ_HANDLED;
+}
+
+#define DRIVER_SETUP
+
+/*
+ * Function : mac_esp_setup(char *str)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - parameters, separated by commas.
+ *
+ * Currently unused in the new driver; need to add settable parameters to the 
+ * detect function.
+ *
+ */
+
+static int __init mac_esp_setup(char *str) {
+#ifdef DRIVER_SETUP
+	/* Format of mac53c9x parameter is:
+	 *   mac53c9x=<num_esps>,<disconnect>,<nosync>,<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
+	 * Negative values mean don't change.
+	 */
+	
+	char *this_opt;
+	long opt;
+
+	this_opt = strsep (&str, ",");
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		if (opt >= 0 && opt <= 2)
+			setup_num_esps = opt;
+		else if (opt > 2)
+			printk( "mac_esp_setup: invalid number of hosts %ld !\n", opt );
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+	
+		if (opt > 0)
+			setup_disconnect = opt;
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		if (opt >= 0)
+			setup_nosync = opt;
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		if (opt > 0)
+			setup_can_queue = opt;
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		if (opt > 0)
+			setup_cmd_per_lun = opt;
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		if (opt >= 0) {
+			setup_sg_tablesize = opt;
+			/* Must be <= SG_ALL (255) */
+			if (setup_sg_tablesize > SG_ALL)
+				setup_sg_tablesize = SG_ALL;
+		}
+
+		this_opt = strsep (&str, ",");
+	}
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+
+		/* Must be between 0 and 7 */
+		if (opt >= 0 && opt <= 7)
+			setup_hostid = opt;
+		else if (opt > 7)
+			printk( "mac_esp_setup: invalid host ID %ld !\n", opt);
+
+		this_opt = strsep (&str, ",");
+	}
+#ifdef SUPPORT_TAGS
+	if(this_opt) {
+		opt = simple_strtol( this_opt, NULL, 0 );
+		if (opt >= 0)
+			setup_use_tagged_queuing = !!opt;
+	}
+#endif
+#endif
+	return 1; 
+}
+
+__setup("mac53c9x=", mac_esp_setup);
+
+
+/*
+ * ESP address 'detection'
+ */
+
+unsigned long get_base(int chip_num)
+{
+	/*
+	 * using the chip_num and mac model, figure out where the
+	 * chips are mapped
+	 */
+
+	unsigned long io_base = 0x50f00000;
+	unsigned int second_offset = 0x402;
+	unsigned long scsi_loc = 0;
+
+	switch (macintosh_config->scsi_type) {
+
+	/* 950, 900, 700 */
+	case MAC_SCSI_QUADRA2:
+		scsi_loc =  io_base + 0xf000 + ((chip_num == 0) ? 0 : second_offset);
+		break;
+
+	/* av's */
+	case MAC_SCSI_QUADRA3:
+		scsi_loc = io_base + 0x18000 + ((chip_num == 0) ? 0 : second_offset);
+		break;
+
+	/* most quadra/centris models are like this */	
+	case MAC_SCSI_QUADRA:
+		scsi_loc = io_base + 0x10000;
+		break;
+
+	default:
+		printk("mac_esp: get_base: hit default!\n");
+		scsi_loc = io_base + 0x10000;
+		break;
+
+	} /* switch */
+
+	printk("mac_esp: io base at 0x%lx\n", scsi_loc);
+
+	return scsi_loc;
+}
+
+/*
+ * Model dependent ESP setup
+ */
+
+int mac_esp_detect(Scsi_Host_Template * tpnt)
+{
+	int quick = 0;
+	int chipnum, chipspresent = 0;
+#if 0
+	unsigned long timeout;
+#endif
+
+	if (esp_initialized > 0)
+		return -ENODEV;
+
+	/* what do we have in this machine... */
+	if (MACHW_PRESENT(MAC_SCSI_96)) {
+		chipspresent ++;
+	}
+
+	if (MACHW_PRESENT(MAC_SCSI_96_2)) {
+		chipspresent ++;
+	}
+
+	/* number of ESPs present ? */
+	if (setup_num_esps >= 0) {
+	  if (chipspresent >= setup_num_esps)
+	    chipspresent = setup_num_esps;
+	  else
+	    printk("mac_esp_detect: num_hosts detected %d setup %d \n",
+		   chipspresent, setup_num_esps);
+	}
+
+	/* TODO: add disconnect / nosync flags */
+
+	/* setup variables */
+	tpnt->can_queue =
+	  (setup_can_queue > 0) ? setup_can_queue : 7;
+	tpnt->cmd_per_lun =
+	  (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : 1;
+	tpnt->sg_tablesize = 
+	  (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_ALL;
+
+	if (setup_hostid >= 0)
+	  tpnt->this_id = setup_hostid;
+	else {
+	  /* use 7 as default */
+	  tpnt->this_id = 7;
+	}
+
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
+#endif
+
+	for (chipnum = 0; chipnum < chipspresent; chipnum ++) {
+		struct NCR_ESP * esp;
+
+		esp = esp_allocate(tpnt, (void *) NULL);
+		esp->eregs = (struct ESP_regs *) get_base(chipnum);
+
+		esp->dma_irq_p = &esp_dafb_dma_irq_p;
+		if (chipnum == 0) {
+
+			if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
+				/* most machines except those below :-) */
+				quick = 1;
+				esp->dma_irq_p = &esp_iosb_dma_irq_p;
+			} else if (macintosh_config->scsi_type == MAC_SCSI_QUADRA3) {
+				/* mostly av's */
+				quick = 0;
+			} else {
+				/* q950, 900, 700 */
+				quick = 1;
+				out_be32(0xf9800024, 0x1d1);
+				esp->dregs = (void *) 0xf9800024;
+			}
+
+		} else { /* chipnum */
+
+			quick = 1;
+			out_be32(0xf9800028, 0x1d1);
+			esp->dregs = (void *) 0xf9800028;
+
+		} /* chipnum == 0 */
+
+		/* use pio for command bytes; pio for message/data: TBI */
+		esp->do_pio_cmds = 1;
+
+		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
+		esp->esp_command_dvma = (__u32) cmd_buffer;
+
+		/* various functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = NULL;
+		esp->dma_init_write = NULL;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+
+		esp->dma_ports_p = &dma_ports_p;
+
+
+		/* Optional functions */
+		esp->dma_barrier = NULL;
+		esp->dma_drain = NULL;
+		esp->dma_invalidate = NULL;
+		esp->dma_irq_entry = NULL;
+		esp->dma_irq_exit = NULL;
+		esp->dma_led_on = NULL;
+		esp->dma_led_off = NULL;
+		esp->dma_poll = NULL;
+		esp->dma_reset = NULL;
+
+		/* SCSI chip speed */
+		/* below esp->cfreq = 40000000; */
+
+
+		if (quick) {
+			/* 'quick' means there's handshake glue logic like in the 5380 case */
+			esp->dma_setup = &dma_setup_quick;
+		} else {
+			esp->dma_setup = &dma_setup;
+		}
+
+		if (chipnum == 0) {
+
+			esp->irq = IRQ_MAC_SCSI;
+
+			request_irq(IRQ_MAC_SCSI, esp_intr, 0, "Mac ESP SCSI", esp->ehost);
+#if 0	/* conflicts with IOP ADB */
+			request_irq(IRQ_MAC_SCSIDRQ, fake_drq, 0, "Mac ESP DRQ", esp->ehost);
+#endif
+
+			if (macintosh_config->scsi_type == MAC_SCSI_QUADRA) {
+				esp->cfreq = 16500000;
+			} else {
+				esp->cfreq = 25000000;
+			}
+
+
+		} else { /* chipnum == 1 */
+
+			esp->irq = IRQ_MAC_SCSIDRQ;
+#if 0	/* conflicts with IOP ADB */
+			request_irq(IRQ_MAC_SCSIDRQ, esp_intr, 0, "Mac ESP SCSI 2", esp->ehost);
+#endif
+
+			esp->cfreq = 25000000;
+
+		}
+
+		if (quick) {
+			printk("esp: using quick version\n");
+		}
+
+		printk("esp: addr at 0x%p\n", esp->eregs);
+
+		esp->scsi_id = 7;
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+	} /* for chipnum */
+
+	if (chipspresent)
+		printk("\nmac_esp: %d esp controllers found\n", chipspresent);
+
+	esp_initialized = chipspresent;
+
+	return chipspresent;
+}
+
+static int mac_esp_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+/*
+ * I've been wondering what this is supposed to do, for some time. Talking 
+ * to Allen Briggs: These machines have an extra register someplace where the
+ * DRQ pin of the ESP can be monitored. That isn't useful for determining 
+ * anything else (such as reselect interrupt or other magic) though. 
+ * Maybe make the semantics should be changed like 
+ * if (esp->current_SC)
+ *	... check DRQ flag ...
+ * else 
+ *	... disconnected, check pending VIA interrupt ...
+ *
+ * There's a problem with using the dabf flag or mac_irq_pending() here: both
+ * seem to return 1 even though no interrupt is currently pending, resulting
+ * in esp_exec_cmd() holding off the next command, and possibly infinite loops
+ * in esp_intr(). 
+ * Short term fix: just use esp_status & ESP_STAT_INTR here, as long as we
+ * use simple PIO. The DRQ status will be important when implementing pseudo
+ * DMA mode (set up ESP transfer count, return, do a batch of bytes in PIO or 
+ * 'hardware handshake' mode upon DRQ).
+ * If you plan on changing this (i.e. to save the esp_status register access in 
+ * favor of a VIA register access or a shadow register for the IFR), make sure
+ * to try a debug version of this first to monitor what registers would be a good
+ * indicator of the ESP interrupt.
+ */
+
+static int esp_dafb_dma_irq_p(struct NCR_ESP * esp)
+{
+	unsigned int ret;
+	int sreg = esp_read(esp->eregs->esp_status);
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: esp_dafb_dma_irq_p dafb %d irq %d\n", 
+		readl(esp->dregs), mac_irq_pending(IRQ_MAC_SCSI));
+#endif
+
+	sreg &= ESP_STAT_INTR;
+
+	/*
+	 * maybe working; this is essentially what's used for iosb_dma_irq_p
+	 */
+	if (sreg)
+		return 1;
+	else
+		return 0;
+
+	/*
+	 * didn't work ...
+	 */
+#if 0
+	if (esp->current_SC)
+		ret = readl(esp->dregs) & 0x200;
+	else if (esp->disconnected_SC)
+		ret = 1; /* sreg ?? */
+	else
+		ret = mac_irq_pending(IRQ_MAC_SCSI);
+
+	return(ret);
+#endif
+
+}
+
+/*
+ * See above: testing mac_irq_pending always returned 8 (SCSI IRQ) regardless 
+ * of the actual ESP status.
+ */
+
+static int esp_iosb_dma_irq_p(struct NCR_ESP * esp)
+{
+	int ret  = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
+	int sreg = esp_read(esp->eregs->esp_status);
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", 
+		mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), 
+		sreg, esp->current_SC, esp->disconnected_SC);
+#endif
+
+	sreg &= ESP_STAT_INTR;
+
+	if (sreg)
+		return (sreg);
+	else
+		return 0;
+}
+
+/*
+ * This seems to be OK for PIO at least ... usually 0 after PIO.
+ */
+
+static int dma_bytes_sent(struct NCR_ESP * esp, int fifo_count)
+{
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma bytes sent = %x\n", fifo_count);
+#endif
+
+	return fifo_count;
+}
+
+/*
+ * dma_can_transfer is used to switch between DMA and PIO, if DMA (pseudo)
+ * is ever implemented. Returning 0 here will use PIO.
+ */
+
+static int dma_can_transfer(struct NCR_ESP * esp, Scsi_Cmnd * sp)
+{
+	unsigned long sz = sp->SCp.this_residual;
+#if 0	/* no DMA yet; make conditional */
+	if (sz > 0x10000000) {
+		sz = 0x10000000;
+	}
+	printk("mac_esp: dma can transfer = 0lx%x\n", sz);
+#else
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: pio to transfer = %ld\n", sz);
+#endif
+
+	sz = 0;
+#endif
+	return sz;
+}
+
+/*
+ * Not yet ...
+ */
+
+static void dma_dump_state(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_dump_state: called\n");
+#endif
+#if 0
+	ESPLOG(("esp%d: dma -- cond_reg<%02x>\n",
+		esp->esp_id, ((struct mac_dma_registers *)
+		(esp->dregs))->cond_reg));
+#endif
+}
+
+/*
+ * DMA setup: should be used to set up the ESP transfer count for pseudo
+ * DMA transfers; need a DRQ transfer function to do the actual transfer
+ */
+
+static void dma_init_read(struct NCR_ESP * esp, char * vaddress, int length)
+{
+	printk("mac_esp: dma_init_read\n");
+}
+
+
+static void dma_init_write(struct NCR_ESP * esp, char * vaddress, int length)
+{
+	printk("mac_esp: dma_init_write\n");
+}
+
+
+static void dma_ints_off(struct NCR_ESP * esp)
+{
+	mac_turnoff_irq(esp->irq);
+}
+
+
+static void dma_ints_on(struct NCR_ESP * esp)
+{
+	mac_turnon_irq(esp->irq);
+}
+
+/*
+ * generic dma_irq_p(), unused
+ */
+
+static int dma_irq_p(struct NCR_ESP * esp)
+{
+	int i = esp_read(esp->eregs->esp_status);
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_irq_p status %d\n", i);
+#endif
+
+	return (i & ESP_STAT_INTR);
+}
+
+static int dma_irq_p_quick(struct NCR_ESP * esp)
+{
+	/*
+	 * Copied from iosb_dma_irq_p()
+	 */
+	int ret  = mac_irq_pending(IRQ_MAC_SCSI) || mac_irq_pending(IRQ_MAC_SCSIDRQ);
+	int sreg = esp_read(esp->eregs->esp_status);
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_irq_p drq %d irq %d sreg %x curr %p disc %p\n", 
+		mac_irq_pending(IRQ_MAC_SCSIDRQ), mac_irq_pending(IRQ_MAC_SCSI), 
+		sreg, esp->current_SC, esp->disconnected_SC);
+#endif
+
+	sreg &= ESP_STAT_INTR;
+
+	if (sreg)
+		return (sreg);
+	else
+		return 0;
+
+}
+
+static void dma_led_off(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_led_off: called\n");
+#endif
+}
+
+
+static void dma_led_on(struct NCR_ESP * esp)
+{
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_led_on: called\n");
+#endif
+}
+
+
+static int dma_ports_p(struct NCR_ESP * esp)
+{
+	return 0;
+}
+
+
+static void dma_setup(struct NCR_ESP * esp, __u32 addr, int count, int write)
+{
+
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_setup\n");
+#endif
+
+	if (write) {
+		dma_init_read(esp, (char *) addr, count);
+	} else {
+		dma_init_write(esp, (char *) addr, count);
+	}
+}
+
+
+static void dma_setup_quick(struct NCR_ESP * esp, __u32 addr, int count, int write)
+{
+#ifdef DEBUG_MAC_ESP
+	printk("mac_esp: dma_setup_quick\n");
+#endif
+}
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "mac_esp",
+	.name			= "Mac 53C9x SCSI",
+	.detect			= mac_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= mac_esp_release,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
new file mode 100644
index 0000000..d5fd17e
--- /dev/null
+++ b/drivers/scsi/mac_scsi.c
@@ -0,0 +1,605 @@
+/*
+ * Generic Macintosh NCR5380 driver
+ *
+ * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
+ *
+ * derived in part from:
+ */
+/*
+ * Generic Generic NCR5380 driver
+ *
+ * Copyright 1995, Russell King
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: mac_NCR5380.c,v $
+ */
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include <asm/macintosh.h>
+#include <asm/macints.h>
+#include <asm/machw.h>
+#include <asm/mac_via.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "mac_scsi.h"
+#include "NCR5380.h"
+
+#if 0
+#define NDEBUG (NDEBUG_INTR | NDEBUG_PSEUDO_DMA | NDEBUG_ARBITRATION | NDEBUG_SELECTION | NDEBUG_RESELECTION)
+#else
+#define NDEBUG (NDEBUG_ABORT)
+#endif
+
+#define RESET_BOOT
+#define DRIVER_SETUP
+
+#define	ENABLE_IRQ()	mac_enable_irq( IRQ_MAC_SCSI ); 
+#define	DISABLE_IRQ()	mac_disable_irq( IRQ_MAC_SCSI );
+
+extern void via_scsi_clear(void);
+
+#ifdef RESET_BOOT
+static void mac_scsi_reset_boot(struct Scsi_Host *instance);
+#endif
+
+static int setup_called = 0;
+static int setup_can_queue = -1;
+static int setup_cmd_per_lun = -1;
+static int setup_sg_tablesize = -1;
+static int setup_use_pdma = -1;
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+#endif
+static int setup_hostid = -1;
+
+/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
+ * we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
+ * need ten times the standard value... */
+#define TOSHIBA_DELAY
+
+#ifdef TOSHIBA_DELAY
+#define	AFTER_RESET_DELAY	(5*HZ/2)
+#else
+#define	AFTER_RESET_DELAY	(HZ/2)
+#endif
+
+static volatile unsigned char *mac_scsi_regp = NULL;
+static volatile unsigned char *mac_scsi_drq  = NULL;
+static volatile unsigned char *mac_scsi_nodrq = NULL;
+
+
+/*
+ * NCR 5380 register access functions
+ */
+
+#if 0
+/* Debug versions */
+#define CTRL(p,v) (*ctrl = (v))
+
+static char macscsi_read(struct Scsi_Host *instance, int reg)
+{
+  int iobase = instance->io_port;
+  int i;
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+  CTRL(iobase, 0);
+  i = in_8(iobase + (reg<<4));
+  CTRL(iobase, 0x40);
+
+  return i;
+}
+
+static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  int iobase = instance->io_port;
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+  CTRL(iobase, 0);
+  out_8(iobase + (reg<<4), value);
+  CTRL(iobase, 0x40);
+}
+#else
+
+/* Fast versions */
+static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg)
+{
+  return in_8(instance->io_port + (reg<<4));
+}
+
+static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  out_8(instance->io_port + (reg<<4), value);
+}
+#endif
+
+
+/*
+ * Function : mac_scsi_setup(char *str)
+ *
+ * Purpose : booter command line initialization of the overrides array,
+ *
+ * Inputs : str - comma delimited list of options
+ *
+ */
+
+static int __init mac_scsi_setup(char *str) {
+#ifdef DRIVER_SETUP	
+	int ints[7];
+	
+	(void)get_options( str, ARRAY_SIZE(ints), ints);
+	
+	if (setup_called++ || ints[0] < 1 || ints[0] > 6) {
+	    printk(KERN_WARNING "scsi: <mac5380>"
+		" Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n");
+	    printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n");
+	    return 0;
+	}
+	    
+	if (ints[0] >= 1) {
+		if (ints[1] > 0)
+			/* no limits on this, just > 0 */
+			setup_can_queue = ints[1];
+	}
+	if (ints[0] >= 2) {
+		if (ints[2] > 0)
+			setup_cmd_per_lun = ints[2];
+	}
+	if (ints[0] >= 3) {
+		if (ints[3] >= 0) {
+			setup_sg_tablesize = ints[3];
+			/* Must be <= SG_ALL (255) */
+			if (setup_sg_tablesize > SG_ALL)
+				setup_sg_tablesize = SG_ALL;
+		}
+	}
+	if (ints[0] >= 4) {
+		/* Must be between 0 and 7 */
+		if (ints[4] >= 0 && ints[4] <= 7)
+			setup_hostid = ints[4];
+		else if (ints[4] > 7)
+			printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
+	}
+#ifdef SUPPORT_TAGS	
+	if (ints[0] >= 5) {
+		if (ints[5] >= 0)
+			setup_use_tagged_queuing = !!ints[5];
+	}
+	
+	if (ints[0] == 6) {
+	    if (ints[6] >= 0)
+		setup_use_pdma = ints[6];
+	}
+#else
+	if (ints[0] == 5) {
+	    if (ints[5] >= 0)
+		setup_use_pdma = ints[5];
+	}
+#endif /* SUPPORT_TAGS */
+	
+#endif /* DRIVER_SETUP */
+	return 1;
+}
+
+__setup("mac5380=", mac_scsi_setup);
+
+/*
+ * If you want to find the instance with (k)gdb ...
+ */
+#if NDEBUG
+static struct Scsi_Host *default_instance;
+#endif
+
+/*
+ * Function : int macscsi_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : initializes mac NCR5380 driver based on the
+ *	command line / compile time port and irq definitions.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+ 
+int macscsi_detect(Scsi_Host_Template * tpnt)
+{
+    static int called = 0;
+    int flags = 0;
+    struct Scsi_Host *instance;
+
+    if (!MACH_IS_MAC || called)
+	return( 0 );
+
+    if (macintosh_config->scsi_type != MAC_SCSI_OLD)
+	return( 0 );
+
+    /* setup variables */
+    tpnt->can_queue =
+	(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+    tpnt->cmd_per_lun =
+	(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+    tpnt->sg_tablesize = 
+	(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+
+    if (setup_hostid >= 0)
+	tpnt->this_id = setup_hostid;
+    else {
+	/* use 7 as default */
+	tpnt->this_id = 7;
+    }
+
+#ifdef SUPPORT_TAGS
+    if (setup_use_tagged_queuing < 0)
+	setup_use_tagged_queuing = USE_TAGGED_QUEUING;
+#endif
+
+    /* Once we support multiple 5380s (e.g. DuoDock) we'll do
+       something different here */
+    instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+#if NDEBUG
+    default_instance = instance;
+#endif
+    
+    if (macintosh_config->ident == MAC_MODEL_IIFX) {
+	mac_scsi_regp  = via1+0x8000;
+	mac_scsi_drq   = via1+0xE000;
+	mac_scsi_nodrq = via1+0xC000;
+	/* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */
+	flags = FLAG_NO_PSEUDO_DMA;
+    } else {
+	mac_scsi_regp  = via1+0x10000;
+	mac_scsi_drq   = via1+0x6000;
+	mac_scsi_nodrq = via1+0x12000;
+    }
+
+    if (! setup_use_pdma)
+	flags = FLAG_NO_PSEUDO_DMA;
+	
+    instance->io_port = (unsigned long) mac_scsi_regp;
+    instance->irq = IRQ_MAC_SCSI;
+
+#ifdef RESET_BOOT   
+    mac_scsi_reset_boot(instance);
+#endif
+    
+    NCR5380_init(instance, flags);
+
+    instance->n_io_port = 255;
+
+    ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+
+    if (instance->irq != SCSI_IRQ_NONE)
+	if (request_irq(instance->irq, NCR5380_intr, IRQ_FLG_SLOW, 
+		"ncr5380", instance)) {
+	    printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
+		   instance->host_no, instance->irq);
+	    instance->irq = SCSI_IRQ_NONE;
+	}
+
+    printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
+    if (instance->irq == SCSI_IRQ_NONE)
+	printk (KERN_INFO "s disabled");
+    else
+	printk (KERN_INFO " %d", instance->irq);
+    printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	   instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
+    printk(KERN_INFO "\nscsi%d:", instance->host_no);
+    NCR5380_print_options(instance);
+    printk("\n");
+    called = 1;
+    return 1;
+}
+
+int macscsi_release (struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq != SCSI_IRQ_NONE)
+		free_irq (shpnt->irq, NCR5380_intr);
+	NCR5380_exit(shpnt);
+
+	return 0;
+}
+
+#ifdef RESET_BOOT
+/*
+ * Our 'bus reset on boot' function
+ */
+
+static void mac_scsi_reset_boot(struct Scsi_Host *instance)
+{
+	unsigned long end;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No messing
+	 * with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk(KERN_INFO "Macintosh SCSI: resetting the SCSI bus..." );
+
+	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
+	mac_disable_irq(IRQ_MAC_SCSI);
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
+		barrier();
+
+	/* switch on SCSI IRQ again */
+	mac_enable_irq(IRQ_MAC_SCSI);
+
+	printk(KERN_INFO " done\n" );
+}
+#endif
+
+const char * macscsi_info (struct Scsi_Host *spnt) {
+	return "";
+}
+
+/* 
+   Pseudo-DMA: (Ove Edlund)
+   The code attempts to catch bus errors that occur if one for example
+   "trips over the cable".
+   XXX: Since bus errors in the PDMA routines never happen on my 
+   computer, the bus error code is untested. 
+   If the code works as intended, a bus error results in Pseudo-DMA 
+   beeing disabled, meaning that the driver switches to slow handshake. 
+   If bus errors are NOT extremely rare, this has to be changed. 
+*/
+
+#define CP_IO_TO_MEM(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %1,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0),(%1)+\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0),(%1)+\n"				\
+     "31: move.l (%0),(%1)+\n"				\
+     "32: move.l (%0),(%1)+\n"				\
+     "33: move.l (%0),(%1)+\n"				\
+     "34: move.l (%0),(%1)+\n"				\
+     "35: move.l (%0),(%1)+\n"				\
+     "36: move.l (%0),(%1)+\n"				\
+     "37: move.l (%0),(%1)+\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0),(%1)+\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0),(%1)+\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+
+static int macscsi_pread (struct Scsi_Host *instance,
+			  unsigned char *dst, int len)
+{
+   unsigned char *d;
+   volatile unsigned char *s;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = mac_scsi_drq+0x60;
+   d = dst;
+
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && !(NCR5380_read(STATUS_REG) & SR_REQ))
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
+      printk(KERN_ERR "Error in macscsi_pread\n");
+      return -1;
+   }
+
+   CP_IO_TO_MEM(s, d, len);
+   
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pread\n");
+      return -1;
+   }
+   
+   return 0;
+}
+
+
+#define CP_MEM_TO_IO(s,d,len)				\
+__asm__ __volatile__					\
+    ("    cmp.w  #4,%2\n"				\
+     "    bls    8f\n"					\
+     "    move.w %0,%%d0\n"				\
+     "    neg.b  %%d0\n"				\
+     "    and.w  #3,%%d0\n"				\
+     "    sub.w  %%d0,%2\n"				\
+     "    bra    2f\n"					\
+     " 1: move.b (%0)+,(%1)\n"				\
+     " 2: dbf    %%d0,1b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #5,%%d0\n"				\
+     "    bra    4f\n"					\
+     " 3: move.l (%0)+,(%1)\n"				\
+     "31: move.l (%0)+,(%1)\n"				\
+     "32: move.l (%0)+,(%1)\n"				\
+     "33: move.l (%0)+,(%1)\n"				\
+     "34: move.l (%0)+,(%1)\n"				\
+     "35: move.l (%0)+,(%1)\n"				\
+     "36: move.l (%0)+,(%1)\n"				\
+     "37: move.l (%0)+,(%1)\n"				\
+     " 4: dbf    %%d0,3b\n"				\
+     "    move.w %2,%%d0\n"				\
+     "    lsr.w  #2,%%d0\n"				\
+     "    and.w  #7,%%d0\n"				\
+     "    bra    6f\n"					\
+     " 5: move.l (%0)+,(%1)\n"				\
+     " 6: dbf    %%d0,5b\n"				\
+     "    and.w  #3,%2\n"				\
+     "    bra    8f\n"					\
+     " 7: move.b (%0)+,(%1)\n"				\
+     " 8: dbf    %2,7b\n"				\
+     "    moveq.l #0, %2\n"				\
+     " 9: \n"						\
+     ".section .fixup,\"ax\"\n"				\
+     "    .even\n"					\
+     "90: moveq.l #1, %2\n"				\
+     "    jra 9b\n"					\
+     ".previous\n"					\
+     ".section __ex_table,\"a\"\n"			\
+     "   .align 4\n"					\
+     "   .long  1b,90b\n"				\
+     "   .long  3b,90b\n"				\
+     "   .long 31b,90b\n"				\
+     "   .long 32b,90b\n"				\
+     "   .long 33b,90b\n"				\
+     "   .long 34b,90b\n"				\
+     "   .long 35b,90b\n"				\
+     "   .long 36b,90b\n"				\
+     "   .long 37b,90b\n"				\
+     "   .long  5b,90b\n"				\
+     "   .long  7b,90b\n"				\
+     ".previous"					\
+     : "=a"(s), "=a"(d), "=d"(len)			\
+     : "0"(s), "1"(d), "2"(len)				\
+     : "d0")
+
+static int macscsi_pwrite (struct Scsi_Host *instance,
+				  unsigned char *src, int len)
+{
+   unsigned char *s;
+   volatile unsigned char *d;
+
+   NCR5380_local_declare();
+   NCR5380_setup(instance);
+
+   s = src;
+   d = mac_scsi_drq;
+   
+/* These conditions are derived from MacOS */
+
+   while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) 
+         && (!(NCR5380_read(STATUS_REG) & SR_REQ) 
+            || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH))) 
+      ;
+   if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
+      printk(KERN_ERR "Error in macscsi_pwrite\n");
+      return -1;
+   }
+
+   CP_MEM_TO_IO(s, d, len);   
+
+   if (len != 0) {
+      printk(KERN_NOTICE "Bus error in macscsi_pwrite\n");
+      return -1;
+   }
+   
+   return 0;
+}
+
+
+/* These control the behaviour of the generic 5380 core */
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+#include "NCR5380.c"
+
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "Mac5380",
+	.proc_info			= macscsi_proc_info,
+	.name				= "Macintosh NCR5380 SCSI",
+	.detect				= macscsi_detect,
+	.release			= macscsi_release,
+	.info				= macscsi_info,
+	.queuecommand			= macscsi_queue_command,
+	.eh_abort_handler		= macscsi_abort,
+	.eh_bus_reset_handler		= macscsi_bus_reset,
+	.eh_device_reset_handler	= macscsi_device_reset,
+	.eh_host_reset_handler		= macscsi_host_reset,
+	.can_queue			= CAN_QUEUE,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= CMD_PER_LUN,
+	.unchecked_isa_dma		= 0,
+	.use_clustering			= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/mac_scsi.h b/drivers/scsi/mac_scsi.h
new file mode 100644
index 0000000..23ab2c18
--- /dev/null
+++ b/drivers/scsi/mac_scsi.h
@@ -0,0 +1,85 @@
+/*
+ * Cumana Generic NCR5380 driver defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: cumana_NCR5380.h,v $
+ */
+
+#ifndef MAC_NCR5380_H
+#define MAC_NCR5380_H
+
+#define MACSCSI_PUBLIC_RELEASE 2
+
+#ifndef ASM
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifndef SG_TABLESIZE
+#define SG_TABLESIZE SG_NONE
+#endif
+
+#ifndef USE_TAGGED_QUEUING
+#define	USE_TAGGED_QUEUING 0
+#endif
+
+#include <scsi/scsicam.h>
+
+#ifndef HOSTS_C
+
+#define NCR5380_implementation_fields \
+    int port, ctrl
+
+#define NCR5380_local_declare() \
+        struct Scsi_Host *_instance
+
+#define NCR5380_setup(instance) \
+        _instance = instance
+
+#define NCR5380_read(reg) macscsi_read(_instance, reg)
+#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
+
+#define NCR5380_pread 	macscsi_pread
+#define NCR5380_pwrite 	macscsi_pwrite
+	
+#define NCR5380_intr macscsi_intr
+#define NCR5380_queue_command macscsi_queue_command
+#define NCR5380_abort macscsi_abort
+#define NCR5380_bus_reset macscsi_bus_reset
+#define NCR5380_device_reset macscsi_device_reset
+#define NCR5380_host_reset macscsi_host_reset
+#define NCR5380_proc_info macscsi_proc_info
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#endif /* ndef HOSTS_C */
+#endif /* ndef ASM */
+#endif /* MAC_NCR5380_H */
+
diff --git a/drivers/scsi/mca_53c9x.c b/drivers/scsi/mca_53c9x.c
new file mode 100644
index 0000000..194c754
--- /dev/null
+++ b/drivers/scsi/mca_53c9x.c
@@ -0,0 +1,520 @@
+/* mca_53c9x.c: Driver for the SCSI adapter found on NCR 35xx
+ *  (and maybe some other) Microchannel machines
+ *
+ * Code taken mostly from Cyberstorm SCSI drivers
+ *   Copyright (C) 1996 Jesper Skov (jskov@cygnus.co.uk)
+ *
+ * Hacked to work with the NCR MCA stuff by Tymm Twillman (tymm@computer.org)
+ *
+ * The CyberStorm SCSI driver (and this driver) is based on David S. Miller's
+ *   ESP driver  * for the Sparc computers. 
+ * 
+ * Special thanks to Ken Stewart at Symbios (LSI) for helping with info on
+ *  the 86C01.  I was on the brink of going ga-ga...
+ *
+ * Also thanks to Jesper Skov for helping me with info on how the Amiga
+ *  does things...
+ */
+
+/*
+ * This is currently only set up to use one 53c9x card at a time; it could be 
+ *  changed fairly easily to detect/use more than one, but I'm not too sure how
+ *  many cards that use the 53c9x on MCA systems there are (if, in fact, there
+ *  are cards that use them, other than the one built into some NCR systems)...
+ *  If anyone requests this, I'll throw it in, otherwise it's not worth the
+ *  effort.
+ */
+
+/*
+ * Info on the 86C01 MCA interface chip at the bottom, if you care enough to
+ *  look.
+ */
+
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mca.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/mca-legacy.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/mca_dma.h>
+#include <asm/pgtable.h>
+
+/*
+ * From ibmmca.c (IBM scsi controller card driver) -- used for turning PS2 disk
+ *  activity LED on and off
+ */
+
+#define PS2_SYS_CTR	0x92
+
+/* Ports the ncr's 53c94 can be put at; indexed by pos register value */
+
+#define MCA_53C9X_IO_PORTS {                             \
+                         0x0000, 0x0240, 0x0340, 0x0400, \
+	                 0x0420, 0x3240, 0x8240, 0xA240, \
+	                }
+			
+/*
+ * Supposedly there were some cards put together with the 'c9x and 86c01.  If
+ *   they have different ID's from the ones on the 3500 series machines, 
+ *   you can add them here and hopefully things will work out.
+ */
+			
+#define MCA_53C9X_IDS {          \
+                         0x7F4C, \
+			 0x0000, \
+                        }
+
+static int  dma_bytes_sent(struct NCR_ESP *, int);
+static int  dma_can_transfer(struct NCR_ESP *, Scsi_Cmnd *);
+static void dma_dump_state(struct NCR_ESP *);
+static void dma_init_read(struct NCR_ESP *, __u32, int);
+static void dma_init_write(struct NCR_ESP *, __u32, int);
+static void dma_ints_off(struct NCR_ESP *);
+static void dma_ints_on(struct NCR_ESP *);
+static int  dma_irq_p(struct NCR_ESP *);
+static int  dma_ports_p(struct NCR_ESP *);
+static void dma_setup(struct NCR_ESP *, __u32, int, int);
+static void dma_led_on(struct NCR_ESP *);
+static void dma_led_off(struct NCR_ESP *);
+
+/* This is where all commands are put before they are trasfered to the 
+ *  53c9x via PIO.
+ */
+
+static volatile unsigned char cmd_buffer[16];
+
+/*
+ * We keep the structure that is used to access the registers on the 53c9x
+ *  here.
+ */
+
+static struct ESP_regs eregs;
+
+/***************************************************************** Detection */
+static int mca_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	static int io_port_by_pos[] = MCA_53C9X_IO_PORTS;
+	int mca_53c9x_ids[] = MCA_53C9X_IDS;
+	int *id_to_check = mca_53c9x_ids;
+	int slot;
+	int pos[3];
+	unsigned int tmp_io_addr;
+	unsigned char tmp_byte;
+
+
+	if (!MCA_bus)
+		return 0;
+
+	while (*id_to_check) { 
+		if ((slot = mca_find_adapter(*id_to_check, 0)) !=
+		  MCA_NOTFOUND) 
+		{
+			esp = esp_allocate(tpnt, (void *) NULL);
+
+			pos[0] = mca_read_stored_pos(slot, 2);
+			pos[1] = mca_read_stored_pos(slot, 3);
+			pos[2] = mca_read_stored_pos(slot, 4);
+
+			esp->eregs = &eregs;
+
+			/*
+			 * IO port base is given in the first (non-ID) pos
+			 *  register, like so:
+			 *
+			 *  Bits 3  2  1       IO base
+			 * ----------------------------
+			 *       0  0  0       <disabled>
+			 *       0  0  1       0x0240
+			 *       0  1  0       0x0340
+			 *       0  1  1       0x0400
+			 *       1  0  0       0x0420
+			 *       1  0  1       0x3240
+			 *       1  1  0       0x8240
+			 *       1  1  1       0xA240
+			 */
+
+			tmp_io_addr =
+			  io_port_by_pos[(pos[0] & 0x0E) >> 1];
+
+			esp->eregs->io_addr = tmp_io_addr + 0x10;
+
+      			if (esp->eregs->io_addr == 0x0000) { 
+        			printk("Adapter is disabled.\n");
+				break;
+			}
+
+			/*
+			 * IRQ is specified in bits 4 and 5:
+			 *
+			 *  Bits  4  5        IRQ
+			 * -----------------------
+			 *        0  0         3
+			 *        0  1         5
+			 *        1  0         7
+			 *        1  1         9
+			 */
+
+      			esp->irq = ((pos[0] & 0x30) >> 3) + 3;
+
+			/*
+			 * DMA channel is in the low 3 bits of the second
+			 *  POS register
+			 */
+
+			esp->dma = pos[1] & 7;
+			esp->slot = slot;
+
+			if (request_irq(esp->irq, esp_intr, 0,
+			 "NCR 53c9x SCSI", esp->ehost))
+			{
+				printk("Unable to request IRQ %d.\n", esp->irq);
+				esp_deallocate(esp);
+				scsi_unregister(esp->ehost);
+				return 0;
+			}
+
+ 			if (request_dma(esp->dma, "NCR 53c9x SCSI")) {
+				printk("Unable to request DMA channel %d.\n",
+				 esp->dma);
+				free_irq(esp->irq, esp_intr);
+				esp_deallocate(esp);
+				scsi_unregister(esp->ehost);
+				return 0;
+			}
+
+			request_region(tmp_io_addr, 32, "NCR 53c9x SCSI");
+
+			/*
+			 * 86C01 handles DMA, IO mode, from address
+			 *  (base + 0x0a)
+			 */
+
+			mca_disable_dma(esp->dma);
+			mca_set_dma_io(esp->dma, tmp_io_addr + 0x0a);
+			mca_enable_dma(esp->dma);
+ 
+			/* Tell the 86C01 to give us interrupts */
+
+			tmp_byte = inb(tmp_io_addr + 0x02) | 0x40;
+			outb(tmp_byte, tmp_io_addr + 0x02); 
+
+			/*
+			 * Scsi ID -- general purpose register, hi
+			 *  2 bits; add 4 to this number to get the
+			 *  ID
+			 */
+
+			esp->scsi_id = ((pos[2] & 0xC0) >> 6) + 4;
+
+			/* Do command transfer with programmed I/O */
+
+			esp->do_pio_cmds = 1;
+
+			/* Required functions */
+
+			esp->dma_bytes_sent = &dma_bytes_sent;
+			esp->dma_can_transfer = &dma_can_transfer;
+			esp->dma_dump_state = &dma_dump_state;
+			esp->dma_init_read = &dma_init_read;
+			esp->dma_init_write = &dma_init_write;
+			esp->dma_ints_off = &dma_ints_off;
+			esp->dma_ints_on = &dma_ints_on;
+			esp->dma_irq_p = &dma_irq_p;
+			esp->dma_ports_p = &dma_ports_p;
+			esp->dma_setup = &dma_setup;
+
+			/* Optional functions */
+
+			esp->dma_barrier = NULL;
+			esp->dma_drain = NULL;
+			esp->dma_invalidate = NULL;
+			esp->dma_irq_entry = NULL;
+			esp->dma_irq_exit = NULL;
+			esp->dma_led_on = dma_led_on;
+			esp->dma_led_off = dma_led_off;
+			esp->dma_poll = NULL;
+			esp->dma_reset = NULL;
+
+			/* Set the command buffer */
+
+			esp->esp_command = (volatile unsigned char*)
+			  cmd_buffer;
+	 		esp->esp_command_dvma = isa_virt_to_bus(cmd_buffer);
+
+			/* SCSI chip speed */
+
+			esp->cfreq = 25000000;
+
+			/* Differential SCSI? I think not. */
+
+			esp->diff = 0;
+
+			esp_initialize(esp);
+
+      			printk(" Adapter found in slot %2d: io port 0x%x "
+			  "irq %d dma channel %d\n", slot + 1, tmp_io_addr,
+			   esp->irq, esp->dma);
+
+			mca_set_adapter_name(slot, "NCR 53C9X SCSI Adapter");
+			mca_mark_as_used(slot);
+
+			break;
+		}
+    
+		id_to_check++;
+	}
+
+	return esps_in_use;
+}
+
+
+/******************************************************************* Release */
+
+static int mca_esp_release(struct Scsi_Host *host)
+{
+	struct NCR_ESP *esp = (struct NCR_ESP *)host->hostdata;
+	unsigned char tmp_byte;
+
+	esp_deallocate(esp);
+	/*
+	 * Tell the 86C01 to stop sending interrupts
+	 */
+
+	tmp_byte = inb(esp->eregs->io_addr - 0x0E);
+	tmp_byte &= ~0x40;
+	outb(tmp_byte, esp->eregs->io_addr - 0x0E);
+
+	free_irq(esp->irq, esp_intr);
+	free_dma(esp->dma);
+
+	mca_mark_as_unused(esp->slot);
+
+	return 0;
+}
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Ask the 53c9x.  It knows. */
+
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	/* 
+	 * The MCA dma channels can only do up to 128K bytes at a time.
+         *  (16 bit mode)
+	 */
+
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > 0x20000)
+		sz = 0x20000;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	/*
+	 * Doesn't quite match up to the other drivers, but we do what we
+	 *  can.
+	 */
+
+	ESPLOG(("esp%d: dma channel <%d>\n", esp->esp_id, esp->dma));
+	ESPLOG(("bytes left to dma: %d\n", mca_get_dma_residue(esp->dma)));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	unsigned long flags;
+
+
+	save_flags(flags);
+	cli();
+
+	mca_disable_dma(esp->dma);
+	mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_16 |
+	  MCA_DMA_MODE_IO);
+	mca_set_dma_addr(esp->dma, addr);
+	mca_set_dma_count(esp->dma, length / 2); /* !!! */
+	mca_enable_dma(esp->dma);
+
+	restore_flags(flags);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 addr, int length)
+{
+	unsigned long flags;
+
+
+	save_flags(flags);
+	cli();
+
+	mca_disable_dma(esp->dma);
+	mca_set_dma_mode(esp->dma, MCA_DMA_MODE_XFER | MCA_DMA_MODE_WRITE |
+	  MCA_DMA_MODE_16 | MCA_DMA_MODE_IO);
+	mca_set_dma_addr(esp->dma, addr);
+	mca_set_dma_count(esp->dma, length / 2); /* !!! */
+	mca_enable_dma(esp->dma);
+
+	restore_flags(flags);
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	/*
+	 * Tell the 'C01 to shut up.  All interrupts are routed through it.
+	 */
+
+	outb(inb(esp->eregs->io_addr - 0x0E) & ~0x40,
+	 esp->eregs->io_addr - 0x0E);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	/*
+	 * Ok.  You can speak again.
+	 */
+
+	outb(inb(esp->eregs->io_addr - 0x0E) | 0x40,
+	 esp->eregs->io_addr - 0x0E);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	/*
+	 * DaveM says that this should return a "yes" if there is an interrupt
+	 *  or a DMA error occurred.  I copied the Amiga driver's semantics,
+	 *  though, because it seems to work and we can't really tell if
+	 *  a DMA error happened.  This gives the "yes" if the scsi chip
+	 *  is sending an interrupt and no DMA activity is taking place
+	 */
+
+	return (!(inb(esp->eregs->io_addr - 0x04) & 1) &&
+	 !(inb(esp->eregs->io_addr - 0x04) & 2) ); 
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	/*
+	 * Check to see if interrupts are enabled on the 'C01 (in case abort
+	 *  is entered multiple times, so we only do the abort once)
+	 */
+
+	return (inb(esp->eregs->io_addr - 0x0E) & 0x40) ? 1:0;
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	if(write){
+		dma_init_write(esp, addr, count);
+	} else {
+		dma_init_read(esp, addr, count);
+	}
+}
+
+/*
+ * These will not play nicely with other disk controllers that try to use the
+ *  disk active LED... but what can you do?  Don't answer that.
+ *
+ * Stolen shamelessly from ibmmca.c -- IBM Microchannel SCSI adapter driver
+ *
+ */
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+	outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+	outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR);
+}
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "mca_53c9x",
+	.name			= "NCR 53c9x SCSI",
+	.detect			= mca_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= mca_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.unchecked_isa_dma	= 1,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+/*
+ * OK, here's the goods I promised.  The NCR 86C01 is an MCA interface chip 
+ *  that handles enabling/diabling IRQ, dma interfacing, IO port selection
+ *  and other fun stuff.  It takes up 16 addresses, and the chip it is
+ *  connnected to gets the following 16.  Registers are as follows:
+ *
+ * Offsets 0-1 : Card ID
+ *
+ * Offset    2 : Mode enable register --
+ *                Bit    7 : Data Word width (1 = 16, 0 = 8)
+ *		  Bit    6 : IRQ enable (1 = enabled)
+ *                Bits 5,4 : IRQ select
+ *                              0  0 : IRQ 3
+ *			        0  1 : IRQ 5
+ * 				1  0 : IRQ 7
+ *  				1  1 : IRQ 9
+ *                Bits 3-1 : Base Address
+ *                           0  0  0 : <disabled>
+ * 			     0  0  1 : 0x0240
+ *    			     0  1  0 : 0x0340
+ *     			     0  1  1 : 0x0400
+ * 			     1  0  0 : 0x0420
+ * 			     1  0  1 : 0x3240
+ * 			     1  1  0 : 0x8240
+ * 			     1  1  1 : 0xA240
+ *		  Bit    0 : Card enable (1 = enabled)
+ *
+ * Offset    3 : DMA control register --
+ *                Bit    7 : DMA enable (1 = enabled)
+ *                Bits 6,5 : Preemt Count Select (transfers to complete after
+ *                            'C01 has been preempted on MCA bus)
+ *                              0  0 : 0
+ *                              0  1 : 1
+ *                              1  0 : 3
+ *                              1  1 : 7
+ *  (all these wacky numbers; I'm sure there's a reason somewhere)
+ *                Bit    4 : Fairness enable (1 = fair bus priority)
+ *                Bits 3-0 : Arbitration level (0-15 consecutive)
+ * 
+ * Offset    4 : General purpose register
+ *                Bits 7-3 : User definable (here, 7,6 are SCSI ID)
+ *                Bits 2-0 : reserved
+ *
+ * Offset   10 : DMA decode register (used for IO based DMA; also can do
+ *                PIO through this port)
+ *
+ * Offset   12 : Status
+ *                Bits 7-2 : reserved
+ *                Bit    1 : DMA pending (1 = pending)
+ *                Bit    0 : IRQ pending (0 = pending)
+ *
+ * Exciting, huh?  
+ *
+ */                
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
new file mode 100644
index 0000000..8d707b2
--- /dev/null
+++ b/drivers/scsi/megaraid.c
@@ -0,0 +1,5122 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright © 2002  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * Copyright (c) 2002  Red Hat, Inc. All rights reserved.
+ *	  - fixes
+ *	  - speed-ups (list handling fixes, issued_list, optimizations.)
+ *	  - lots of cleanups.
+ *
+ * Copyright (c) 2003  Christoph Hellwig  <hch@lst.de>
+ *	  - new-style, hotplug-aware pci probing and scsi registration
+ *
+ * Version : v2.00.3 (Feb 19, 2003) - Atul Mukker <Atul.Mukker@lsil.com>
+ *
+ * Description: Linux device driver for LSI Logic MegaRAID controller
+ *
+ * Supported controllers: MegaRAID 418, 428, 438, 466, 762, 467, 471, 490, 493
+ *					518, 520, 531, 532
+ *
+ * This driver is supported by LSI Logic, with assistance from Red Hat, Dell,
+ * and others. Please send updates to the mailing list
+ * linux-scsi@vger.kernel.org .
+ *
+ */
+
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/blkdev.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/reboot.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <scsi/scsicam.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#include "megaraid.h"
+
+#define MEGARAID_MODULE_VERSION "2.00.3"
+
+MODULE_AUTHOR ("LSI Logic Corporation");
+MODULE_DESCRIPTION ("LSI Logic MegaRAID driver");
+MODULE_LICENSE ("GPL");
+MODULE_VERSION(MEGARAID_MODULE_VERSION);
+
+static unsigned int max_cmd_per_lun = DEF_CMD_PER_LUN;
+module_param(max_cmd_per_lun, uint, 0);
+MODULE_PARM_DESC(max_cmd_per_lun, "Maximum number of commands which can be issued to a single LUN (default=DEF_CMD_PER_LUN=63)");
+
+static unsigned short int max_sectors_per_io = MAX_SECTORS_PER_IO;
+module_param(max_sectors_per_io, ushort, 0);
+MODULE_PARM_DESC(max_sectors_per_io, "Maximum number of sectors per I/O request (default=MAX_SECTORS_PER_IO=128)");
+
+
+static unsigned short int max_mbox_busy_wait = MBOX_BUSY_WAIT;
+module_param(max_mbox_busy_wait, ushort, 0);
+MODULE_PARM_DESC(max_mbox_busy_wait, "Maximum wait for mailbox in microseconds if busy (default=MBOX_BUSY_WAIT=10)");
+
+#define RDINDOOR(adapter)		readl((adapter)->base + 0x20)
+#define RDOUTDOOR(adapter)		readl((adapter)->base + 0x2C)
+#define WRINDOOR(adapter,value)		writel(value, (adapter)->base + 0x20)
+#define WROUTDOOR(adapter,value)	writel(value, (adapter)->base + 0x2C)
+
+/*
+ * Global variables
+ */
+
+static int hba_count;
+static adapter_t *hba_soft_state[MAX_CONTROLLERS];
+static struct proc_dir_entry *mega_proc_dir_entry;
+
+/* For controller re-ordering */
+static struct mega_hbas mega_hbas[MAX_CONTROLLERS];
+
+/*
+ * The File Operations structure for the serial/ioctl interface of the driver
+ */
+static struct file_operations megadev_fops = {
+	.owner		= THIS_MODULE,
+	.ioctl		= megadev_ioctl,
+	.open		= megadev_open,
+};
+
+/*
+ * Array to structures for storing the information about the controllers. This
+ * information is sent to the user level applications, when they do an ioctl
+ * for this information.
+ */
+static struct mcontroller mcontroller[MAX_CONTROLLERS];
+
+/* The current driver version */
+static u32 driver_ver = 0x02000000;
+
+/* major number used by the device for character interface */
+static int major;
+
+#define IS_RAID_CH(hba, ch)	(((hba)->mega_ch_class >> (ch)) & 0x01)
+
+
+/*
+ * Debug variable to print some diagnostic messages
+ */
+static int trace_level;
+
+/**
+ * mega_setup_mailbox()
+ * @adapter - pointer to our soft state
+ *
+ * Allocates a 8 byte aligned memory for the handshake mailbox.
+ */
+static int
+mega_setup_mailbox(adapter_t *adapter)
+{
+	unsigned long	align;
+
+	adapter->una_mbox64 = pci_alloc_consistent(adapter->dev,
+			sizeof(mbox64_t), &adapter->una_mbox64_dma);
+
+	if( !adapter->una_mbox64 ) return -1;
+		
+	adapter->mbox = &adapter->una_mbox64->mbox;
+
+	adapter->mbox = (mbox_t *)((((unsigned long) adapter->mbox) + 15) &
+			(~0UL ^ 0xFUL));
+
+	adapter->mbox64 = (mbox64_t *)(((unsigned long)adapter->mbox) - 8);
+
+	align = ((void *)adapter->mbox) - ((void *)&adapter->una_mbox64->mbox);
+
+	adapter->mbox_dma = adapter->una_mbox64_dma + 8 + align;
+
+	/*
+	 * Register the mailbox if the controller is an io-mapped controller
+	 */
+	if( adapter->flag & BOARD_IOMAP ) {
+
+		outb_p(adapter->mbox_dma & 0xFF,
+				adapter->host->io_port + MBOX_PORT0);
+
+		outb_p((adapter->mbox_dma >> 8) & 0xFF,
+				adapter->host->io_port + MBOX_PORT1);
+
+		outb_p((adapter->mbox_dma >> 16) & 0xFF,
+				adapter->host->io_port + MBOX_PORT2);
+
+		outb_p((adapter->mbox_dma >> 24) & 0xFF,
+				adapter->host->io_port + MBOX_PORT3);
+
+		outb_p(ENABLE_MBOX_BYTE,
+				adapter->host->io_port + ENABLE_MBOX_REGION);
+
+		irq_ack(adapter);
+
+		irq_enable(adapter);
+	}
+
+	return 0;
+}
+
+
+/*
+ * mega_query_adapter()
+ * @adapter - pointer to our soft state
+ *
+ * Issue the adapter inquiry commands to the controller and find out
+ * information and parameter about the devices attached
+ */
+static int
+mega_query_adapter(adapter_t *adapter)
+{
+	dma_addr_t	prod_info_dma_handle;
+	mega_inquiry3	*inquiry3;
+	u8	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox;
+	int	retval;
+
+	/* Initialize adapter inquiry mailbox */
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+
+	/*
+	 * Try to issue Inquiry3 command
+	 * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+	 * update enquiry3 structure
+	 */
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	inquiry3 = (mega_inquiry3 *)adapter->mega_buffer;
+
+	raw_mbox[0] = FC_NEW_CONFIG;		/* i.e. mbox->cmd=0xA1 */
+	raw_mbox[2] = NC_SUBOP_ENQUIRY3;	/* i.e. 0x0F */
+	raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;	/* i.e. 0x02 */
+
+	/* Issue a blocking command to the card */
+	if ((retval = issue_scb_block(adapter, raw_mbox))) {
+		/* the adapter does not support 40ld */
+
+		mraid_ext_inquiry	*ext_inq;
+		mraid_inquiry		*inq;
+		dma_addr_t		dma_handle;
+
+		ext_inq = pci_alloc_consistent(adapter->dev,
+				sizeof(mraid_ext_inquiry), &dma_handle);
+
+		if( ext_inq == NULL ) return -1;
+
+		inq = &ext_inq->raid_inq;
+
+		mbox->m_out.xferaddr = (u32)dma_handle;
+
+		/*issue old 0x04 command to adapter */
+		mbox->m_out.cmd = MEGA_MBOXCMD_ADPEXTINQ;
+
+		issue_scb_block(adapter, raw_mbox);
+
+		/*
+		 * update Enquiry3 and ProductInfo structures with
+		 * mraid_inquiry structure
+		 */
+		mega_8_to_40ld(inq, inquiry3,
+				(mega_product_info *)&adapter->product_info);
+
+		pci_free_consistent(adapter->dev, sizeof(mraid_ext_inquiry),
+				ext_inq, dma_handle);
+
+	} else {		/*adapter supports 40ld */
+		adapter->flag |= BOARD_40LD;
+
+		/*
+		 * get product_info, which is static information and will be
+		 * unchanged
+		 */
+		prod_info_dma_handle = pci_map_single(adapter->dev, (void *)
+				&adapter->product_info,
+				sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
+
+		mbox->m_out.xferaddr = prod_info_dma_handle;
+
+		raw_mbox[0] = FC_NEW_CONFIG;	/* i.e. mbox->cmd=0xA1 */
+		raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;	/* i.e. 0x0E */
+
+		if ((retval = issue_scb_block(adapter, raw_mbox)))
+			printk(KERN_WARNING
+			"megaraid: Product_info cmd failed with error: %d\n",
+				retval);
+
+		pci_unmap_single(adapter->dev, prod_info_dma_handle,
+				sizeof(mega_product_info), PCI_DMA_FROMDEVICE);
+	}
+
+
+	/*
+	 * kernel scans the channels from 0 to <= max_channel
+	 */
+	adapter->host->max_channel =
+		adapter->product_info.nchannels + NVIRT_CHAN -1;
+
+	adapter->host->max_id = 16;	/* max targets per channel */
+
+	adapter->host->max_lun = 7;	/* Upto 7 luns for non disk devices */
+
+	adapter->host->cmd_per_lun = max_cmd_per_lun;
+
+	adapter->numldrv = inquiry3->num_ldrv;
+
+	adapter->max_cmds = adapter->product_info.max_commands;
+
+	if(adapter->max_cmds > MAX_COMMANDS)
+		adapter->max_cmds = MAX_COMMANDS;
+
+	adapter->host->can_queue = adapter->max_cmds - 1;
+
+	/*
+	 * Get the maximum number of scatter-gather elements supported by this
+	 * firmware
+	 */
+	mega_get_max_sgl(adapter);
+
+	adapter->host->sg_tablesize = adapter->sglen;
+
+
+	/* use HP firmware and bios version encoding */
+	if (adapter->product_info.subsysvid == HP_SUBSYS_VID) {
+		sprintf (adapter->fw_version, "%c%d%d.%d%d",
+			 adapter->product_info.fw_version[2],
+			 adapter->product_info.fw_version[1] >> 8,
+			 adapter->product_info.fw_version[1] & 0x0f,
+			 adapter->product_info.fw_version[0] >> 8,
+			 adapter->product_info.fw_version[0] & 0x0f);
+		sprintf (adapter->bios_version, "%c%d%d.%d%d",
+			 adapter->product_info.bios_version[2],
+			 adapter->product_info.bios_version[1] >> 8,
+			 adapter->product_info.bios_version[1] & 0x0f,
+			 adapter->product_info.bios_version[0] >> 8,
+			 adapter->product_info.bios_version[0] & 0x0f);
+	} else {
+		memcpy(adapter->fw_version,
+				(char *)adapter->product_info.fw_version, 4);
+		adapter->fw_version[4] = 0;
+
+		memcpy(adapter->bios_version,
+				(char *)adapter->product_info.bios_version, 4);
+
+		adapter->bios_version[4] = 0;
+	}
+
+	printk(KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives.\n",
+		adapter->fw_version, adapter->bios_version, adapter->numldrv);
+
+	/*
+	 * Do we support extended (>10 bytes) cdbs
+	 */
+	adapter->support_ext_cdb = mega_support_ext_cdb(adapter);
+	if (adapter->support_ext_cdb)
+		printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
+
+
+	return 0;
+}
+
+/**
+ * mega_runpendq()
+ * @adapter - pointer to our soft state
+ *
+ * Runs through the list of pending requests.
+ */
+static inline void
+mega_runpendq(adapter_t *adapter)
+{
+	if(!list_empty(&adapter->pending_list))
+		__mega_runpendq(adapter);
+}
+
+/*
+ * megaraid_queue()
+ * @scmd - Issue this scsi command
+ * @done - the callback hook into the scsi mid-layer
+ *
+ * The command queuing entry point for the mid-layer.
+ */
+static int
+megaraid_queue(Scsi_Cmnd *scmd, void (*done)(Scsi_Cmnd *))
+{
+	adapter_t	*adapter;
+	scb_t	*scb;
+	int	busy=0;
+
+	adapter = (adapter_t *)scmd->device->host->hostdata;
+
+	scmd->scsi_done = done;
+
+
+	/*
+	 * Allocate and build a SCB request
+	 * busy flag will be set if mega_build_cmd() command could not
+	 * allocate scb. We will return non-zero status in that case.
+	 * NOTE: scb can be null even though certain commands completed
+	 * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, we would
+	 * return 0 in that case.
+	 */
+
+	scb = mega_build_cmd(adapter, scmd, &busy);
+
+	if(scb) {
+		scb->state |= SCB_PENDQ;
+		list_add_tail(&scb->list, &adapter->pending_list);
+
+		/*
+		 * Check if the HBA is in quiescent state, e.g., during a
+		 * delete logical drive opertion. If it is, don't run
+		 * the pending_list.
+		 */
+		if(atomic_read(&adapter->quiescent) == 0) {
+			mega_runpendq(adapter);
+		}
+		return 0;
+	}
+
+	return busy;
+}
+
+/**
+ * mega_allocate_scb()
+ * @adapter - pointer to our soft state
+ * @cmd - scsi command from the mid-layer
+ *
+ * Allocate a SCB structure. This is the central structure for controller
+ * commands.
+ */
+static inline scb_t *
+mega_allocate_scb(adapter_t *adapter, Scsi_Cmnd *cmd)
+{
+	struct list_head *head = &adapter->free_list;
+	scb_t	*scb;
+
+	/* Unlink command from Free List */
+	if( !list_empty(head) ) {
+
+		scb = list_entry(head->next, scb_t, list);
+
+		list_del_init(head->next);
+
+		scb->state = SCB_ACTIVE;
+		scb->cmd = cmd;
+		scb->dma_type = MEGA_DMA_TYPE_NONE;
+
+		return scb;
+	}
+
+	return NULL;
+}
+
+/**
+ * mega_get_ldrv_num()
+ * @adapter - pointer to our soft state
+ * @cmd - scsi mid layer command
+ * @channel - channel on the controller
+ *
+ * Calculate the logical drive number based on the information in scsi command
+ * and the channel number.
+ */
+static inline int
+mega_get_ldrv_num(adapter_t *adapter, Scsi_Cmnd *cmd, int channel)
+{
+	int		tgt;
+	int		ldrv_num;
+
+	tgt = cmd->device->id;
+	
+	if ( tgt > adapter->this_id )
+		tgt--;	/* we do not get inquires for initiator id */
+
+	ldrv_num = (channel * 15) + tgt;
+
+
+	/*
+	 * If we have a logical drive with boot enabled, project it first
+	 */
+	if( adapter->boot_ldrv_enabled ) {
+		if( ldrv_num == 0 ) {
+			ldrv_num = adapter->boot_ldrv;
+		}
+		else {
+			if( ldrv_num <= adapter->boot_ldrv ) {
+				ldrv_num--;
+			}
+		}
+	}
+
+	/*
+	 * If "delete logical drive" feature is enabled on this controller.
+	 * Do only if at least one delete logical drive operation was done.
+	 *
+	 * Also, after logical drive deletion, instead of logical drive number,
+	 * the value returned should be 0x80+logical drive id.
+	 *
+	 * These is valid only for IO commands.
+	 */
+
+	if (adapter->support_random_del && adapter->read_ldidmap )
+		switch (cmd->cmnd[0]) {
+		case READ_6:	/* fall through */
+		case WRITE_6:	/* fall through */
+		case READ_10:	/* fall through */
+		case WRITE_10:
+			ldrv_num += 0x80;
+		}
+
+	return ldrv_num;
+}
+
+/**
+ * mega_build_cmd()
+ * @adapter - pointer to our soft state
+ * @cmd - Prepare using this scsi command
+ * @busy - busy flag if no resources
+ *
+ * Prepares a command and scatter gather list for the controller. This routine
+ * also finds out if the commands is intended for a logical drive or a
+ * physical device and prepares the controller command accordingly.
+ *
+ * We also re-order the logical drives and physical devices based on their
+ * boot settings.
+ */
+static scb_t *
+mega_build_cmd(adapter_t *adapter, Scsi_Cmnd *cmd, int *busy)
+{
+	mega_ext_passthru	*epthru;
+	mega_passthru	*pthru;
+	scb_t	*scb;
+	mbox_t	*mbox;
+	long	seg;
+	char	islogical;
+	int	max_ldrv_num;
+	int	channel = 0;
+	int	target = 0;
+	int	ldrv_num = 0;   /* logical drive number */
+
+
+	/*
+	 * filter the internal and ioctl commands
+	 */
+	if((cmd->cmnd[0] == MEGA_INTERNAL_CMD)) {
+		return cmd->buffer;
+	}
+
+
+	/*
+	 * We know what channels our logical drives are on - mega_find_card()
+	 */
+	islogical = adapter->logdrv_chan[cmd->device->channel];
+
+	/*
+	 * The theory: If physical drive is chosen for boot, all the physical
+	 * devices are exported before the logical drives, otherwise physical
+	 * devices are pushed after logical drives, in which case - Kernel sees
+	 * the physical devices on virtual channel which is obviously converted
+	 * to actual channel on the HBA.
+	 */
+	if( adapter->boot_pdrv_enabled ) {
+		if( islogical ) {
+			/* logical channel */
+			channel = cmd->device->channel -
+				adapter->product_info.nchannels;
+		}
+		else {
+			/* this is physical channel */
+			channel = cmd->device->channel; 
+			target = cmd->device->id;
+
+			/*
+			 * boot from a physical disk, that disk needs to be
+			 * exposed first IF both the channels are SCSI, then
+			 * booting from the second channel is not allowed.
+			 */
+			if( target == 0 ) {
+				target = adapter->boot_pdrv_tgt;
+			}
+			else if( target == adapter->boot_pdrv_tgt ) {
+				target = 0;
+			}
+		}
+	}
+	else {
+		if( islogical ) {
+			/* this is the logical channel */
+			channel = cmd->device->channel;	
+		}
+		else {
+			/* physical channel */
+			channel = cmd->device->channel - NVIRT_CHAN;	
+			target = cmd->device->id;
+		}
+	}
+
+
+	if(islogical) {
+
+		/* have just LUN 0 for each target on virtual channels */
+		if (cmd->device->lun) {
+			cmd->result = (DID_BAD_TARGET << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+		}
+
+		ldrv_num = mega_get_ldrv_num(adapter, cmd, channel);
+
+
+		max_ldrv_num = (adapter->flag & BOARD_40LD) ?
+			MAX_LOGICAL_DRIVES_40LD : MAX_LOGICAL_DRIVES_8LD;
+
+		/*
+		 * max_ldrv_num increases by 0x80 if some logical drive was
+		 * deleted.
+		 */
+		if(adapter->read_ldidmap)
+			max_ldrv_num += 0x80;
+
+		if(ldrv_num > max_ldrv_num ) {
+			cmd->result = (DID_BAD_TARGET << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+		}
+
+	}
+	else {
+		if( cmd->device->lun > 7) {
+			/*
+			 * Do not support lun >7 for physically accessed
+			 * devices
+			 */
+			cmd->result = (DID_BAD_TARGET << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+		}
+	}
+
+	/*
+	 *
+	 * Logical drive commands
+	 *
+	 */
+	if(islogical) {
+		switch (cmd->cmnd[0]) {
+		case TEST_UNIT_READY:
+			memset(cmd->request_buffer, 0, cmd->request_bufflen);
+
+#if MEGA_HAVE_CLUSTERING
+			/*
+			 * Do we support clustering and is the support enabled
+			 * If no, return success always
+			 */
+			if( !adapter->has_cluster ) {
+				cmd->result = (DID_OK << 16);
+				cmd->scsi_done(cmd);
+				return NULL;
+			}
+
+			if(!(scb = mega_allocate_scb(adapter, cmd))) {
+				*busy = 1;
+				return NULL;
+			}
+
+			scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
+			scb->raw_mbox[2] = MEGA_RESERVATION_STATUS;
+			scb->raw_mbox[3] = ldrv_num;
+
+			scb->dma_direction = PCI_DMA_NONE;
+
+			return scb;
+#else
+			cmd->result = (DID_OK << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+#endif
+
+		case MODE_SENSE:
+			memset(cmd->request_buffer, 0, cmd->cmnd[4]);
+			cmd->result = (DID_OK << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+
+		case READ_CAPACITY:
+		case INQUIRY:
+
+			if(!(adapter->flag & (1L << cmd->device->channel))) {
+
+				printk(KERN_NOTICE
+					"scsi%d: scanning scsi channel %d ",
+						adapter->host->host_no,
+						cmd->device->channel);
+				printk("for logical drives.\n");
+
+				adapter->flag |= (1L << cmd->device->channel);
+			}
+
+			/* Allocate a SCB and initialize passthru */
+			if(!(scb = mega_allocate_scb(adapter, cmd))) {
+				*busy = 1;
+				return NULL;
+			}
+			pthru = scb->pthru;
+
+			mbox = (mbox_t *)scb->raw_mbox;
+			memset(mbox, 0, sizeof(scb->raw_mbox));
+			memset(pthru, 0, sizeof(mega_passthru));
+
+			pthru->timeout = 0;
+			pthru->ars = 1;
+			pthru->reqsenselen = 14;
+			pthru->islogical = 1;
+			pthru->logdrv = ldrv_num;
+			pthru->cdblen = cmd->cmd_len;
+			memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len);
+
+			if( adapter->has_64bit_addr ) {
+				mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64;
+			}
+			else {
+				mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU;
+			}
+
+			scb->dma_direction = PCI_DMA_FROMDEVICE;
+
+			pthru->numsgelements = mega_build_sglist(adapter, scb,
+				&pthru->dataxferaddr, &pthru->dataxferlen);
+
+			mbox->m_out.xferaddr = scb->pthru_dma_addr;
+
+			return scb;
+
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+		case READ_12:
+		case WRITE_12:
+
+			/* Allocate a SCB and initialize mailbox */
+			if(!(scb = mega_allocate_scb(adapter, cmd))) {
+				*busy = 1;
+				return NULL;
+			}
+			mbox = (mbox_t *)scb->raw_mbox;
+
+			memset(mbox, 0, sizeof(scb->raw_mbox));
+			mbox->m_out.logdrv = ldrv_num;
+
+			/*
+			 * A little hack: 2nd bit is zero for all scsi read
+			 * commands and is set for all scsi write commands
+			 */
+			if( adapter->has_64bit_addr ) {
+				mbox->m_out.cmd = (*cmd->cmnd & 0x02) ?
+					MEGA_MBOXCMD_LWRITE64:
+					MEGA_MBOXCMD_LREAD64 ;
+			}
+			else {
+				mbox->m_out.cmd = (*cmd->cmnd & 0x02) ?
+					MEGA_MBOXCMD_LWRITE:
+					MEGA_MBOXCMD_LREAD ;
+			}
+
+			/*
+			 * 6-byte READ(0x08) or WRITE(0x0A) cdb
+			 */
+			if( cmd->cmd_len == 6 ) {
+				mbox->m_out.numsectors = (u32) cmd->cmnd[4];
+				mbox->m_out.lba =
+					((u32)cmd->cmnd[1] << 16) |
+					((u32)cmd->cmnd[2] << 8) |
+					(u32)cmd->cmnd[3];
+
+				mbox->m_out.lba &= 0x1FFFFF;
+
+#if MEGA_HAVE_STATS
+				/*
+				 * Take modulo 0x80, since the logical drive
+				 * number increases by 0x80 when a logical
+				 * drive was deleted
+				 */
+				if (*cmd->cmnd == READ_6) {
+					adapter->nreads[ldrv_num%0x80]++;
+					adapter->nreadblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				} else {
+					adapter->nwrites[ldrv_num%0x80]++;
+					adapter->nwriteblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				}
+#endif
+			}
+
+			/*
+			 * 10-byte READ(0x28) or WRITE(0x2A) cdb
+			 */
+			if( cmd->cmd_len == 10 ) {
+				mbox->m_out.numsectors =
+					(u32)cmd->cmnd[8] |
+					((u32)cmd->cmnd[7] << 8);
+				mbox->m_out.lba =
+					((u32)cmd->cmnd[2] << 24) |
+					((u32)cmd->cmnd[3] << 16) |
+					((u32)cmd->cmnd[4] << 8) |
+					(u32)cmd->cmnd[5];
+
+#if MEGA_HAVE_STATS
+				if (*cmd->cmnd == READ_10) {
+					adapter->nreads[ldrv_num%0x80]++;
+					adapter->nreadblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				} else {
+					adapter->nwrites[ldrv_num%0x80]++;
+					adapter->nwriteblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				}
+#endif
+			}
+
+			/*
+			 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+			 */
+			if( cmd->cmd_len == 12 ) {
+				mbox->m_out.lba =
+					((u32)cmd->cmnd[2] << 24) |
+					((u32)cmd->cmnd[3] << 16) |
+					((u32)cmd->cmnd[4] << 8) |
+					(u32)cmd->cmnd[5];
+
+				mbox->m_out.numsectors =
+					((u32)cmd->cmnd[6] << 24) |
+					((u32)cmd->cmnd[7] << 16) |
+					((u32)cmd->cmnd[8] << 8) |
+					(u32)cmd->cmnd[9];
+
+#if MEGA_HAVE_STATS
+				if (*cmd->cmnd == READ_12) {
+					adapter->nreads[ldrv_num%0x80]++;
+					adapter->nreadblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				} else {
+					adapter->nwrites[ldrv_num%0x80]++;
+					adapter->nwriteblocks[ldrv_num%0x80] +=
+						mbox->m_out.numsectors;
+				}
+#endif
+			}
+
+			/*
+			 * If it is a read command
+			 */
+			if( (*cmd->cmnd & 0x0F) == 0x08 ) {
+				scb->dma_direction = PCI_DMA_FROMDEVICE;
+			}
+			else {
+				scb->dma_direction = PCI_DMA_TODEVICE;
+			}
+
+			/* Calculate Scatter-Gather info */
+			mbox->m_out.numsgelements = mega_build_sglist(adapter, scb,
+					(u32 *)&mbox->m_out.xferaddr, (u32 *)&seg);
+
+			return scb;
+
+#if MEGA_HAVE_CLUSTERING
+		case RESERVE:	/* Fall through */
+		case RELEASE:
+
+			/*
+			 * Do we support clustering and is the support enabled
+			 */
+			if( ! adapter->has_cluster ) {
+
+				cmd->result = (DID_BAD_TARGET << 16);
+				cmd->scsi_done(cmd);
+				return NULL;
+			}
+
+			/* Allocate a SCB and initialize mailbox */
+			if(!(scb = mega_allocate_scb(adapter, cmd))) {
+				*busy = 1;
+				return NULL;
+			}
+
+			scb->raw_mbox[0] = MEGA_CLUSTER_CMD;
+			scb->raw_mbox[2] = ( *cmd->cmnd == RESERVE ) ?
+				MEGA_RESERVE_LD : MEGA_RELEASE_LD;
+
+			scb->raw_mbox[3] = ldrv_num;
+
+			scb->dma_direction = PCI_DMA_NONE;
+
+			return scb;
+#endif
+
+		default:
+			cmd->result = (DID_BAD_TARGET << 16);
+			cmd->scsi_done(cmd);
+			return NULL;
+		}
+	}
+
+	/*
+	 * Passthru drive commands
+	 */
+	else {
+		/* Allocate a SCB and initialize passthru */
+		if(!(scb = mega_allocate_scb(adapter, cmd))) {
+			*busy = 1;
+			return NULL;
+		}
+
+		mbox = (mbox_t *)scb->raw_mbox;
+		memset(mbox, 0, sizeof(scb->raw_mbox));
+
+		if( adapter->support_ext_cdb ) {
+
+			epthru = mega_prepare_extpassthru(adapter, scb, cmd,
+					channel, target);
+
+			mbox->m_out.cmd = MEGA_MBOXCMD_EXTPTHRU;
+
+			mbox->m_out.xferaddr = scb->epthru_dma_addr;
+
+		}
+		else {
+
+			pthru = mega_prepare_passthru(adapter, scb, cmd,
+					channel, target);
+
+			/* Initialize mailbox */
+			if( adapter->has_64bit_addr ) {
+				mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU64;
+			}
+			else {
+				mbox->m_out.cmd = MEGA_MBOXCMD_PASSTHRU;
+			}
+
+			mbox->m_out.xferaddr = scb->pthru_dma_addr;
+
+		}
+		return scb;
+	}
+	return NULL;
+}
+
+
+/**
+ * mega_prepare_passthru()
+ * @adapter - pointer to our soft state
+ * @scb - our scsi control block
+ * @cmd - scsi command from the mid-layer
+ * @channel - actual channel on the controller
+ * @target - actual id on the controller.
+ *
+ * prepare a command for the scsi physical devices.
+ */
+static mega_passthru *
+mega_prepare_passthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd,
+		int channel, int target)
+{
+	mega_passthru *pthru;
+
+	pthru = scb->pthru;
+	memset(pthru, 0, sizeof (mega_passthru));
+
+	/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	pthru->timeout = 2;
+
+	pthru->ars = 1;
+	pthru->reqsenselen = 14;
+	pthru->islogical = 0;
+
+	pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel;
+
+	pthru->target = (adapter->flag & BOARD_40LD) ?
+		(channel << 4) | target : target;
+
+	pthru->cdblen = cmd->cmd_len;
+	pthru->logdrv = cmd->device->lun;
+
+	memcpy(pthru->cdb, cmd->cmnd, cmd->cmd_len);
+
+	/* Not sure about the direction */
+	scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+	/* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+	switch (cmd->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		if(!(adapter->flag & (1L << cmd->device->channel))) {
+
+			printk(KERN_NOTICE
+				"scsi%d: scanning scsi channel %d [P%d] ",
+					adapter->host->host_no,
+					cmd->device->channel, channel);
+			printk("for physical devices.\n");
+
+			adapter->flag |= (1L << cmd->device->channel);
+		}
+		/* Fall through */
+	default:
+		pthru->numsgelements = mega_build_sglist(adapter, scb,
+				&pthru->dataxferaddr, &pthru->dataxferlen);
+		break;
+	}
+	return pthru;
+}
+
+
+/**
+ * mega_prepare_extpassthru()
+ * @adapter - pointer to our soft state
+ * @scb - our scsi control block
+ * @cmd - scsi command from the mid-layer
+ * @channel - actual channel on the controller
+ * @target - actual id on the controller.
+ *
+ * prepare a command for the scsi physical devices. This rountine prepares
+ * commands for devices which can take extended CDBs (>10 bytes)
+ */
+static mega_ext_passthru *
+mega_prepare_extpassthru(adapter_t *adapter, scb_t *scb, Scsi_Cmnd *cmd,
+		int channel, int target)
+{
+	mega_ext_passthru	*epthru;
+
+	epthru = scb->epthru;
+	memset(epthru, 0, sizeof(mega_ext_passthru));
+
+	/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	epthru->timeout = 2;
+
+	epthru->ars = 1;
+	epthru->reqsenselen = 14;
+	epthru->islogical = 0;
+
+	epthru->channel = (adapter->flag & BOARD_40LD) ? 0 : channel;
+	epthru->target = (adapter->flag & BOARD_40LD) ?
+		(channel << 4) | target : target;
+
+	epthru->cdblen = cmd->cmd_len;
+	epthru->logdrv = cmd->device->lun;
+
+	memcpy(epthru->cdb, cmd->cmnd, cmd->cmd_len);
+
+	/* Not sure about the direction */
+	scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+	switch(cmd->cmnd[0]) {
+	case INQUIRY:
+	case READ_CAPACITY:
+		if(!(adapter->flag & (1L << cmd->device->channel))) {
+
+			printk(KERN_NOTICE
+				"scsi%d: scanning scsi channel %d [P%d] ",
+					adapter->host->host_no,
+					cmd->device->channel, channel);
+			printk("for physical devices.\n");
+
+			adapter->flag |= (1L << cmd->device->channel);
+		}
+		/* Fall through */
+	default:
+		epthru->numsgelements = mega_build_sglist(adapter, scb,
+				&epthru->dataxferaddr, &epthru->dataxferlen);
+		break;
+	}
+
+	return epthru;
+}
+
+static void
+__mega_runpendq(adapter_t *adapter)
+{
+	scb_t *scb;
+	struct list_head *pos, *next;
+
+	/* Issue any pending commands to the card */
+	list_for_each_safe(pos, next, &adapter->pending_list) {
+
+		scb = list_entry(pos, scb_t, list);
+
+		if( !(scb->state & SCB_ISSUED) ) {
+
+			if( issue_scb(adapter, scb) != 0 )
+				return;
+		}
+	}
+
+	return;
+}
+
+
+/**
+ * issue_scb()
+ * @adapter - pointer to our soft state
+ * @scb - scsi control block
+ *
+ * Post a command to the card if the mailbox is available, otherwise return
+ * busy. We also take the scb from the pending list if the mailbox is
+ * available.
+ */
+static int
+issue_scb(adapter_t *adapter, scb_t *scb)
+{
+	volatile mbox64_t	*mbox64 = adapter->mbox64;
+	volatile mbox_t		*mbox = adapter->mbox;
+	unsigned int	i = 0;
+
+	if(unlikely(mbox->m_in.busy)) {
+		do {
+			udelay(1);
+			i++;
+		} while( mbox->m_in.busy && (i < max_mbox_busy_wait) );
+
+		if(mbox->m_in.busy) return -1;
+	}
+
+	/* Copy mailbox data into host structure */
+	memcpy((char *)&mbox->m_out, (char *)scb->raw_mbox, 
+			sizeof(struct mbox_out));
+
+	mbox->m_out.cmdid = scb->idx;	/* Set cmdid */
+	mbox->m_in.busy = 1;		/* Set busy */
+
+
+	/*
+	 * Increment the pending queue counter
+	 */
+	atomic_inc(&adapter->pend_cmds);
+
+	switch (mbox->m_out.cmd) {
+	case MEGA_MBOXCMD_LREAD64:
+	case MEGA_MBOXCMD_LWRITE64:
+	case MEGA_MBOXCMD_PASSTHRU64:
+	case MEGA_MBOXCMD_EXTPTHRU:
+		mbox64->xfer_segment_lo = mbox->m_out.xferaddr;
+		mbox64->xfer_segment_hi = 0;
+		mbox->m_out.xferaddr = 0xFFFFFFFF;
+		break;
+	default:
+		mbox64->xfer_segment_lo = 0;
+		mbox64->xfer_segment_hi = 0;
+	}
+
+	/*
+	 * post the command
+	 */
+	scb->state |= SCB_ISSUED;
+
+	if( likely(adapter->flag & BOARD_MEMMAP) ) {
+		mbox->m_in.poll = 0;
+		mbox->m_in.ack = 0;
+		WRINDOOR(adapter, adapter->mbox_dma | 0x1);
+	}
+	else {
+		irq_enable(adapter);
+		issue_command(adapter);
+	}
+
+	return 0;
+}
+
+/*
+ * Wait until the controller's mailbox is available
+ */
+static inline int
+mega_busywait_mbox (adapter_t *adapter)
+{
+	if (adapter->mbox->m_in.busy)
+		return __mega_busywait_mbox(adapter);
+	return 0;
+}
+
+/**
+ * issue_scb_block()
+ * @adapter - pointer to our soft state
+ * @raw_mbox - the mailbox
+ *
+ * Issue a scb in synchronous and non-interrupt mode
+ */
+static int
+issue_scb_block(adapter_t *adapter, u_char *raw_mbox)
+{
+	volatile mbox64_t *mbox64 = adapter->mbox64;
+	volatile mbox_t *mbox = adapter->mbox;
+	u8	byte;
+
+	/* Wait until mailbox is free */
+	if(mega_busywait_mbox (adapter))
+		goto bug_blocked_mailbox;
+
+	/* Copy mailbox data into host structure */
+	memcpy((char *) mbox, raw_mbox, sizeof(struct mbox_out));
+	mbox->m_out.cmdid = 0xFE;
+	mbox->m_in.busy = 1;
+
+	switch (raw_mbox[0]) {
+	case MEGA_MBOXCMD_LREAD64:
+	case MEGA_MBOXCMD_LWRITE64:
+	case MEGA_MBOXCMD_PASSTHRU64:
+	case MEGA_MBOXCMD_EXTPTHRU:
+		mbox64->xfer_segment_lo = mbox->m_out.xferaddr;
+		mbox64->xfer_segment_hi = 0;
+		mbox->m_out.xferaddr = 0xFFFFFFFF;
+		break;
+	default:
+		mbox64->xfer_segment_lo = 0;
+		mbox64->xfer_segment_hi = 0;
+	}
+
+	if( likely(adapter->flag & BOARD_MEMMAP) ) {
+		mbox->m_in.poll = 0;
+		mbox->m_in.ack = 0;
+		mbox->m_in.numstatus = 0xFF;
+		mbox->m_in.status = 0xFF;
+		WRINDOOR(adapter, adapter->mbox_dma | 0x1);
+
+		while((volatile u8)mbox->m_in.numstatus == 0xFF)
+			cpu_relax();
+
+		mbox->m_in.numstatus = 0xFF;
+
+		while( (volatile u8)mbox->m_in.poll != 0x77 )
+			cpu_relax();
+
+		mbox->m_in.poll = 0;
+		mbox->m_in.ack = 0x77;
+
+		WRINDOOR(adapter, adapter->mbox_dma | 0x2);
+
+		while(RDINDOOR(adapter) & 0x2)
+			cpu_relax();
+	}
+	else {
+		irq_disable(adapter);
+		issue_command(adapter);
+
+		while (!((byte = irq_state(adapter)) & INTR_VALID))
+			cpu_relax();
+
+		set_irq_state(adapter, byte);
+		irq_enable(adapter);
+		irq_ack(adapter);
+	}
+
+	return mbox->m_in.status;
+
+bug_blocked_mailbox:
+	printk(KERN_WARNING "megaraid: Blocked mailbox......!!\n");
+	udelay (1000);
+	return -1;
+}
+
+
+/**
+ * megaraid_isr_iomapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+ * @regs - unused
+ *
+ * Interrupt service routine for io-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+static irqreturn_t
+megaraid_isr_iomapped(int irq, void *devp, struct pt_regs *regs)
+{
+	adapter_t	*adapter = devp;
+	unsigned long	flags;
+	u8	status;
+	u8	nstatus;
+	u8	completed[MAX_FIRMWARE_STATUS];
+	u8	byte;
+	int	handled = 0;
+
+
+	/*
+	 * loop till F/W has more commands for us to complete.
+	 */
+	spin_lock_irqsave(&adapter->lock, flags);
+
+	do {
+		/* Check if a valid interrupt is pending */
+		byte = irq_state(adapter);
+		if( (byte & VALID_INTR_BYTE) == 0 ) {
+			/*
+			 * No more pending commands
+			 */
+			goto out_unlock;
+		}
+		set_irq_state(adapter, byte);
+
+		while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus)
+				== 0xFF)
+			cpu_relax();
+		adapter->mbox->m_in.numstatus = 0xFF;
+
+		status = adapter->mbox->m_in.status;
+
+		/*
+		 * decrement the pending queue counter
+		 */
+		atomic_sub(nstatus, &adapter->pend_cmds);
+
+		memcpy(completed, (void *)adapter->mbox->m_in.completed, 
+				nstatus);
+
+		/* Acknowledge interrupt */
+		irq_ack(adapter);
+
+		mega_cmd_done(adapter, completed, nstatus, status);
+
+		mega_rundoneq(adapter);
+
+		handled = 1;
+
+		/* Loop through any pending requests */
+		if(atomic_read(&adapter->quiescent) == 0) {
+			mega_runpendq(adapter);
+		}
+
+	} while(1);
+
+ out_unlock:
+
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+/**
+ * megaraid_isr_memmapped()
+ * @irq - irq
+ * @devp - pointer to our soft state
+ * @regs - unused
+ *
+ * Interrupt service routine for memory-mapped controllers.
+ * Find out if our device is interrupting. If yes, acknowledge the interrupt
+ * and service the completed commands.
+ */
+static irqreturn_t
+megaraid_isr_memmapped(int irq, void *devp, struct pt_regs *regs)
+{
+	adapter_t	*adapter = devp;
+	unsigned long	flags;
+	u8	status;
+	u32	dword = 0;
+	u8	nstatus;
+	u8	completed[MAX_FIRMWARE_STATUS];
+	int	handled = 0;
+
+
+	/*
+	 * loop till F/W has more commands for us to complete.
+	 */
+	spin_lock_irqsave(&adapter->lock, flags);
+
+	do {
+		/* Check if a valid interrupt is pending */
+		dword = RDOUTDOOR(adapter);
+		if(dword != 0x10001234) {
+			/*
+			 * No more pending commands
+			 */
+			goto out_unlock;
+		}
+		WROUTDOOR(adapter, 0x10001234);
+
+		while((nstatus = (volatile u8)adapter->mbox->m_in.numstatus)
+				== 0xFF) {
+			cpu_relax();
+		}
+		adapter->mbox->m_in.numstatus = 0xFF;
+
+		status = adapter->mbox->m_in.status;
+
+		/*
+		 * decrement the pending queue counter
+		 */
+		atomic_sub(nstatus, &adapter->pend_cmds);
+
+		memcpy(completed, (void *)adapter->mbox->m_in.completed, 
+				nstatus);
+
+		/* Acknowledge interrupt */
+		WRINDOOR(adapter, 0x2);
+
+		handled = 1;
+
+		while( RDINDOOR(adapter) & 0x02 ) cpu_relax();
+
+		mega_cmd_done(adapter, completed, nstatus, status);
+
+		mega_rundoneq(adapter);
+
+		/* Loop through any pending requests */
+		if(atomic_read(&adapter->quiescent) == 0) {
+			mega_runpendq(adapter);
+		}
+
+	} while(1);
+
+ out_unlock:
+
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+/**
+ * mega_cmd_done()
+ * @adapter - pointer to our soft state
+ * @completed - array of ids of completed commands
+ * @nstatus - number of completed commands
+ * @status - status of the last command completed
+ *
+ * Complete the comamnds and call the scsi mid-layer callback hooks.
+ */
+static void
+mega_cmd_done(adapter_t *adapter, u8 completed[], int nstatus, int status)
+{
+	mega_ext_passthru	*epthru = NULL;
+	struct scatterlist	*sgl;
+	Scsi_Cmnd	*cmd = NULL;
+	mega_passthru	*pthru = NULL;
+	mbox_t	*mbox = NULL;
+	u8	c;
+	scb_t	*scb;
+	int	islogical;
+	int	cmdid;
+	int	i;
+
+	/*
+	 * for all the commands completed, call the mid-layer callback routine
+	 * and free the scb.
+	 */
+	for( i = 0; i < nstatus; i++ ) {
+
+		cmdid = completed[i];
+
+		if( cmdid == CMDID_INT_CMDS ) { /* internal command */
+			scb = &adapter->int_scb;
+			cmd = scb->cmd;
+			mbox = (mbox_t *)scb->raw_mbox;
+
+			/*
+			 * Internal command interface do not fire the extended
+			 * passthru or 64-bit passthru
+			 */
+			pthru = scb->pthru;
+
+		}
+		else {
+			scb = &adapter->scb_list[cmdid];
+
+			/*
+			 * Make sure f/w has completed a valid command
+			 */
+			if( !(scb->state & SCB_ISSUED) || scb->cmd == NULL ) {
+				printk(KERN_CRIT
+					"megaraid: invalid command ");
+				printk("Id %d, scb->state:%x, scsi cmd:%p\n",
+					cmdid, scb->state, scb->cmd);
+
+				continue;
+			}
+
+			/*
+			 * Was a abort issued for this command
+			 */
+			if( scb->state & SCB_ABORT ) {
+
+				printk(KERN_WARNING
+				"megaraid: aborted cmd %lx[%x] complete.\n",
+					scb->cmd->serial_number, scb->idx);
+
+				scb->cmd->result = (DID_ABORT << 16);
+
+				list_add_tail(SCSI_LIST(scb->cmd),
+						&adapter->completed_list);
+
+				mega_free_scb(adapter, scb);
+
+				continue;
+			}
+
+			/*
+			 * Was a reset issued for this command
+			 */
+			if( scb->state & SCB_RESET ) {
+
+				printk(KERN_WARNING
+				"megaraid: reset cmd %lx[%x] complete.\n",
+					scb->cmd->serial_number, scb->idx);
+
+				scb->cmd->result = (DID_RESET << 16);
+
+				list_add_tail(SCSI_LIST(scb->cmd),
+						&adapter->completed_list);
+
+				mega_free_scb (adapter, scb);
+
+				continue;
+			}
+
+			cmd = scb->cmd;
+			pthru = scb->pthru;
+			epthru = scb->epthru;
+			mbox = (mbox_t *)scb->raw_mbox;
+
+#if MEGA_HAVE_STATS
+			{
+
+			int	logdrv = mbox->m_out.logdrv;
+
+			islogical = adapter->logdrv_chan[cmd->channel];
+			/*
+			 * Maintain an error counter for the logical drive.
+			 * Some application like SNMP agent need such
+			 * statistics
+			 */
+			if( status && islogical && (cmd->cmnd[0] == READ_6 ||
+						cmd->cmnd[0] == READ_10 ||
+						cmd->cmnd[0] == READ_12)) {
+				/*
+				 * Logical drive number increases by 0x80 when
+				 * a logical drive is deleted
+				 */
+				adapter->rd_errors[logdrv%0x80]++;
+			}
+
+			if( status && islogical && (cmd->cmnd[0] == WRITE_6 ||
+						cmd->cmnd[0] == WRITE_10 ||
+						cmd->cmnd[0] == WRITE_12)) {
+				/*
+				 * Logical drive number increases by 0x80 when
+				 * a logical drive is deleted
+				 */
+				adapter->wr_errors[logdrv%0x80]++;
+			}
+
+			}
+#endif
+		}
+
+		/*
+		 * Do not return the presence of hard disk on the channel so,
+		 * inquiry sent, and returned data==hard disk or removable
+		 * hard disk and not logical, request should return failure! -
+		 * PJ
+		 */
+		islogical = adapter->logdrv_chan[cmd->device->channel];
+		if( cmd->cmnd[0] == INQUIRY && !islogical ) {
+
+			if( cmd->use_sg ) {
+				sgl = (struct scatterlist *)
+					cmd->request_buffer;
+
+				if( sgl->page ) {
+					c = *(unsigned char *)
+					page_address((&sgl[0])->page) +
+					(&sgl[0])->offset; 
+				}
+				else {
+					printk(KERN_WARNING
+						"megaraid: invalid sg.\n");
+					c = 0;
+				}
+			}
+			else {
+				c = *(u8 *)cmd->request_buffer;
+			}
+
+			if(IS_RAID_CH(adapter, cmd->device->channel) &&
+					((c & 0x1F ) == TYPE_DISK)) {
+				status = 0xF0;
+			}
+		}
+
+		/* clear result; otherwise, success returns corrupt value */
+		cmd->result = 0;
+
+		/* Convert MegaRAID status to Linux error code */
+		switch (status) {
+		case 0x00:	/* SUCCESS , i.e. SCSI_STATUS_GOOD */
+			cmd->result |= (DID_OK << 16);
+			break;
+
+		case 0x02:	/* ERROR_ABORTED, i.e.
+				   SCSI_STATUS_CHECK_CONDITION */
+
+			/* set sense_buffer and result fields */
+			if( mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU ||
+				mbox->m_out.cmd == MEGA_MBOXCMD_PASSTHRU64 ) {
+
+				memcpy(cmd->sense_buffer, pthru->reqsensearea,
+						14);
+
+				cmd->result = (DRIVER_SENSE << 24) |
+					(DID_OK << 16) |
+					(CHECK_CONDITION << 1);
+			}
+			else {
+				if (mbox->m_out.cmd == MEGA_MBOXCMD_EXTPTHRU) {
+
+					memcpy(cmd->sense_buffer,
+						epthru->reqsensearea, 14);
+
+					cmd->result = (DRIVER_SENSE << 24) |
+						(DID_OK << 16) |
+						(CHECK_CONDITION << 1);
+				} else {
+					cmd->sense_buffer[0] = 0x70;
+					cmd->sense_buffer[2] = ABORTED_COMMAND;
+					cmd->result |= (CHECK_CONDITION << 1);
+				}
+			}
+			break;
+
+		case 0x08:	/* ERR_DEST_DRIVE_FAILED, i.e.
+				   SCSI_STATUS_BUSY */
+			cmd->result |= (DID_BUS_BUSY << 16) | status;
+			break;
+
+		default:
+#if MEGA_HAVE_CLUSTERING
+			/*
+			 * If TEST_UNIT_READY fails, we know
+			 * MEGA_RESERVATION_STATUS failed
+			 */
+			if( cmd->cmnd[0] == TEST_UNIT_READY ) {
+				cmd->result |= (DID_ERROR << 16) |
+					(RESERVATION_CONFLICT << 1);
+			}
+			else
+			/*
+			 * Error code returned is 1 if Reserve or Release
+			 * failed or the input parameter is invalid
+			 */
+			if( status == 1 &&
+				(cmd->cmnd[0] == RESERVE ||
+					 cmd->cmnd[0] == RELEASE) ) {
+
+				cmd->result |= (DID_ERROR << 16) |
+					(RESERVATION_CONFLICT << 1);
+			}
+			else
+#endif
+				cmd->result |= (DID_BAD_TARGET << 16)|status;
+		}
+
+		/*
+		 * Only free SCBs for the commands coming down from the
+		 * mid-layer, not for which were issued internally
+		 *
+		 * For internal command, restore the status returned by the
+		 * firmware so that user can interpret it.
+		 */
+		if( cmdid == CMDID_INT_CMDS ) { /* internal command */
+			cmd->result = status;
+
+			/*
+			 * Remove the internal command from the pending list
+			 */
+			list_del_init(&scb->list);
+			scb->state = SCB_FREE;
+		}
+		else {
+			mega_free_scb(adapter, scb);
+		}
+
+		/* Add Scsi_Command to end of completed queue */
+		list_add_tail(SCSI_LIST(cmd), &adapter->completed_list);
+	}
+}
+
+
+/*
+ * mega_runpendq()
+ *
+ * Run through the list of completed requests and finish it
+ */
+static void
+mega_rundoneq (adapter_t *adapter)
+{
+	Scsi_Cmnd *cmd;
+	struct list_head *pos;
+
+	list_for_each(pos, &adapter->completed_list) {
+
+		Scsi_Pointer* spos = (Scsi_Pointer *)pos;
+
+		cmd = list_entry(spos, Scsi_Cmnd, SCp);
+		cmd->scsi_done(cmd);
+	}
+
+	INIT_LIST_HEAD(&adapter->completed_list);
+}
+
+
+/*
+ * Free a SCB structure
+ * Note: We assume the scsi commands associated with this scb is not free yet.
+ */
+static void
+mega_free_scb(adapter_t *adapter, scb_t *scb)
+{
+	switch( scb->dma_type ) {
+
+	case MEGA_DMA_TYPE_NONE:
+		break;
+
+	case MEGA_BULK_DATA:
+		pci_unmap_page(adapter->dev, scb->dma_h_bulkdata,
+			scb->cmd->request_bufflen, scb->dma_direction);
+		break;
+
+	case MEGA_SGLIST:
+		pci_unmap_sg(adapter->dev, scb->cmd->request_buffer,
+			scb->cmd->use_sg, scb->dma_direction);
+		break;
+
+	default:
+		break;
+	}
+
+	/*
+	 * Remove from the pending list
+	 */
+	list_del_init(&scb->list);
+
+	/* Link the scb back into free list */
+	scb->state = SCB_FREE;
+	scb->cmd = NULL;
+
+	list_add(&scb->list, &adapter->free_list);
+}
+
+
+static int
+__mega_busywait_mbox (adapter_t *adapter)
+{
+	volatile mbox_t *mbox = adapter->mbox;
+	long counter;
+
+	for (counter = 0; counter < 10000; counter++) {
+		if (!mbox->m_in.busy)
+			return 0;
+		udelay(100); yield();
+	}
+	return -1;		/* give up after 1 second */
+}
+
+/*
+ * Copies data to SGLIST
+ * Note: For 64 bit cards, we need a minimum of one SG element for read/write
+ */
+static int
+mega_build_sglist(adapter_t *adapter, scb_t *scb, u32 *buf, u32 *len)
+{
+	struct scatterlist	*sgl;
+	struct page	*page;
+	unsigned long	offset;
+	Scsi_Cmnd	*cmd;
+	int	sgcnt;
+	int	idx;
+
+	cmd = scb->cmd;
+
+	/* Scatter-gather not used */
+	if( !cmd->use_sg ) {
+
+		page = virt_to_page(cmd->request_buffer);
+		offset = offset_in_page(cmd->request_buffer);
+
+		scb->dma_h_bulkdata = pci_map_page(adapter->dev,
+						  page, offset,
+						  cmd->request_bufflen,
+						  scb->dma_direction);
+		scb->dma_type = MEGA_BULK_DATA;
+
+		/*
+		 * We need to handle special 64-bit commands that need a
+		 * minimum of 1 SG
+		 */
+		if( adapter->has_64bit_addr ) {
+			scb->sgl64[0].address = scb->dma_h_bulkdata;
+			scb->sgl64[0].length = cmd->request_bufflen;
+			*buf = (u32)scb->sgl_dma_addr;
+			*len = (u32)cmd->request_bufflen;
+			return 1;
+		}
+		else {
+			*buf = (u32)scb->dma_h_bulkdata;
+			*len = (u32)cmd->request_bufflen;
+		}
+		return 0;
+	}
+
+	sgl = (struct scatterlist *)cmd->request_buffer;
+
+	/*
+	 * Copy Scatter-Gather list info into controller structure.
+	 *
+	 * The number of sg elements returned must not exceed our limit
+	 */
+	sgcnt = pci_map_sg(adapter->dev, sgl, cmd->use_sg,
+			scb->dma_direction);
+
+	scb->dma_type = MEGA_SGLIST;
+
+	if( sgcnt > adapter->sglen ) BUG();
+
+	for( idx = 0; idx < sgcnt; idx++, sgl++ ) {
+
+		if( adapter->has_64bit_addr ) {
+			scb->sgl64[idx].address = sg_dma_address(sgl);
+			scb->sgl64[idx].length = sg_dma_len(sgl);
+		}
+		else {
+			scb->sgl[idx].address = sg_dma_address(sgl);
+			scb->sgl[idx].length = sg_dma_len(sgl);
+		}
+	}
+
+	/* Reset pointer and length fields */
+	*buf = scb->sgl_dma_addr;
+
+	/*
+	 * For passthru command, dataxferlen must be set, even for commands
+	 * with a sg list
+	 */
+	*len = (u32)cmd->request_bufflen;
+
+	/* Return count of SG requests */
+	return sgcnt;
+}
+
+
+/*
+ * mega_8_to_40ld()
+ *
+ * takes all info in AdapterInquiry structure and puts it into ProductInfo and
+ * Enquiry3 structures for later use
+ */
+static void
+mega_8_to_40ld(mraid_inquiry *inquiry, mega_inquiry3 *enquiry3,
+		mega_product_info *product_info)
+{
+	int i;
+
+	product_info->max_commands = inquiry->adapter_info.max_commands;
+	enquiry3->rebuild_rate = inquiry->adapter_info.rebuild_rate;
+	product_info->nchannels = inquiry->adapter_info.nchannels;
+
+	for (i = 0; i < 4; i++) {
+		product_info->fw_version[i] =
+			inquiry->adapter_info.fw_version[i];
+
+		product_info->bios_version[i] =
+			inquiry->adapter_info.bios_version[i];
+	}
+	enquiry3->cache_flush_interval =
+		inquiry->adapter_info.cache_flush_interval;
+
+	product_info->dram_size = inquiry->adapter_info.dram_size;
+
+	enquiry3->num_ldrv = inquiry->logdrv_info.num_ldrv;
+
+	for (i = 0; i < MAX_LOGICAL_DRIVES_8LD; i++) {
+		enquiry3->ldrv_size[i] = inquiry->logdrv_info.ldrv_size[i];
+		enquiry3->ldrv_prop[i] = inquiry->logdrv_info.ldrv_prop[i];
+		enquiry3->ldrv_state[i] = inquiry->logdrv_info.ldrv_state[i];
+	}
+
+	for (i = 0; i < (MAX_PHYSICAL_DRIVES); i++)
+		enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i];
+}
+
+static inline void
+mega_free_sgl(adapter_t *adapter)
+{
+	scb_t	*scb;
+	int	i;
+
+	for(i = 0; i < adapter->max_cmds; i++) {
+
+		scb = &adapter->scb_list[i];
+
+		if( scb->sgl64 ) {
+			pci_free_consistent(adapter->dev,
+				sizeof(mega_sgl64) * adapter->sglen,
+				scb->sgl64,
+				scb->sgl_dma_addr);
+
+			scb->sgl64 = NULL;
+		}
+
+		if( scb->pthru ) {
+			pci_free_consistent(adapter->dev, sizeof(mega_passthru),
+				scb->pthru, scb->pthru_dma_addr);
+
+			scb->pthru = NULL;
+		}
+
+		if( scb->epthru ) {
+			pci_free_consistent(adapter->dev,
+				sizeof(mega_ext_passthru),
+				scb->epthru, scb->epthru_dma_addr);
+
+			scb->epthru = NULL;
+		}
+
+	}
+}
+
+
+/*
+ * Get information about the card/driver
+ */
+const char *
+megaraid_info(struct Scsi_Host *host)
+{
+	static char buffer[512];
+	adapter_t *adapter;
+
+	adapter = (adapter_t *)host->hostdata;
+
+	sprintf (buffer,
+		 "LSI Logic MegaRAID %s %d commands %d targs %d chans %d luns",
+		 adapter->fw_version, adapter->product_info.max_commands,
+		 adapter->host->max_id, adapter->host->max_channel,
+		 adapter->host->max_lun);
+	return buffer;
+}
+
+/*
+ * Abort a previous SCSI request. Only commands on the pending list can be
+ * aborted. All the commands issued to the F/W must complete.
+ */
+static int
+megaraid_abort(Scsi_Cmnd *cmd)
+{
+	adapter_t	*adapter;
+	int		rval;
+
+	adapter = (adapter_t *)cmd->device->host->hostdata;
+
+	rval =  megaraid_abort_and_reset(adapter, cmd, SCB_ABORT);
+
+	/*
+	 * This is required here to complete any completed requests
+	 * to be communicated over to the mid layer.
+	 */
+	mega_rundoneq(adapter);
+
+	return rval;
+}
+
+
+static int
+megaraid_reset(Scsi_Cmnd *cmd)
+{
+	adapter_t	*adapter;
+	megacmd_t	mc;
+	int		rval;
+
+	adapter = (adapter_t *)cmd->device->host->hostdata;
+
+#if MEGA_HAVE_CLUSTERING
+	mc.cmd = MEGA_CLUSTER_CMD;
+	mc.opcode = MEGA_RESET_RESERVATIONS;
+
+	spin_unlock_irq(&adapter->lock);
+	if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+		printk(KERN_WARNING
+				"megaraid: reservation reset failed.\n");
+	}
+	else {
+		printk(KERN_INFO "megaraid: reservation reset.\n");
+	}
+	spin_lock_irq(&adapter->lock);
+#endif
+
+	rval =  megaraid_abort_and_reset(adapter, cmd, SCB_RESET);
+
+	/*
+	 * This is required here to complete any completed requests
+	 * to be communicated over to the mid layer.
+	 */
+	mega_rundoneq(adapter);
+
+	return rval;
+}
+
+
+
+/**
+ * megaraid_abort_and_reset()
+ * @adapter - megaraid soft state
+ * @cmd - scsi command to be aborted or reset
+ * @aor - abort or reset flag
+ *
+ * Try to locate the scsi command in the pending queue. If found and is not
+ * issued to the controller, abort/reset it. Otherwise return failure
+ */
+static int
+megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
+{
+	struct list_head	*pos, *next;
+	scb_t			*scb;
+
+	printk(KERN_WARNING "megaraid: %s-%lx cmd=%x <c=%d t=%d l=%d>\n",
+	     (aor == SCB_ABORT)? "ABORTING":"RESET", cmd->serial_number,
+	     cmd->cmnd[0], cmd->device->channel, 
+	     cmd->device->id, cmd->device->lun);
+
+	if(list_empty(&adapter->pending_list))
+		return FALSE;
+
+	list_for_each_safe(pos, next, &adapter->pending_list) {
+
+		scb = list_entry(pos, scb_t, list);
+
+		if (scb->cmd == cmd) { /* Found command */
+
+			scb->state |= aor;
+
+			/*
+			 * Check if this command has firmare owenership. If
+			 * yes, we cannot reset this command. Whenever, f/w
+			 * completes this command, we will return appropriate
+			 * status from ISR.
+			 */
+			if( scb->state & SCB_ISSUED ) {
+
+				printk(KERN_WARNING
+					"megaraid: %s-%lx[%x], fw owner.\n",
+					(aor==SCB_ABORT) ? "ABORTING":"RESET",
+					cmd->serial_number, scb->idx);
+
+				return FALSE;
+			}
+			else {
+
+				/*
+				 * Not yet issued! Remove from the pending
+				 * list
+				 */
+				printk(KERN_WARNING
+					"megaraid: %s-%lx[%x], driver owner.\n",
+					(aor==SCB_ABORT) ? "ABORTING":"RESET",
+					cmd->serial_number, scb->idx);
+
+				mega_free_scb(adapter, scb);
+
+				if( aor == SCB_ABORT ) {
+					cmd->result = (DID_ABORT << 16);
+				}
+				else {
+					cmd->result = (DID_RESET << 16);
+				}
+
+				list_add_tail(SCSI_LIST(cmd),
+						&adapter->completed_list);
+
+				return TRUE;
+			}
+		}
+	}
+
+	return FALSE;
+}
+
+static inline int
+make_local_pdev(adapter_t *adapter, struct pci_dev **pdev)
+{
+	*pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+
+	if( *pdev == NULL ) return -1;
+
+	memcpy(*pdev, adapter->dev, sizeof(struct pci_dev));
+
+	if( pci_set_dma_mask(*pdev, 0xffffffff) != 0 ) {
+		kfree(*pdev);
+		return -1;
+	}
+
+	return 0;
+}
+
+static inline void
+free_local_pdev(struct pci_dev *pdev)
+{
+	kfree(pdev);
+}
+
+/**
+ * mega_allocate_inquiry()
+ * @dma_handle - handle returned for dma address
+ * @pdev - handle to pci device
+ *
+ * allocates memory for inquiry structure
+ */
+static inline void *
+mega_allocate_inquiry(dma_addr_t *dma_handle, struct pci_dev *pdev)
+{
+	return pci_alloc_consistent(pdev, sizeof(mega_inquiry3), dma_handle);
+}
+
+
+static inline void
+mega_free_inquiry(void *inquiry, dma_addr_t dma_handle, struct pci_dev *pdev)
+{
+	pci_free_consistent(pdev, sizeof(mega_inquiry3), inquiry, dma_handle);
+}
+
+
+#ifdef CONFIG_PROC_FS
+/* Following code handles /proc fs  */
+
+#define CREATE_READ_PROC(string, func)	create_proc_read_entry(string,	\
+					S_IRUSR | S_IFREG,		\
+					controller_proc_dir_entry,	\
+					func, adapter)
+
+/**
+ * mega_create_proc_entry()
+ * @index - index in soft state array
+ * @parent - parent node for this /proc entry
+ *
+ * Creates /proc entries for our controllers.
+ */
+static void
+mega_create_proc_entry(int index, struct proc_dir_entry *parent)
+{
+	struct proc_dir_entry	*controller_proc_dir_entry = NULL;
+	u8		string[64] = { 0 };
+	adapter_t	*adapter = hba_soft_state[index];
+
+	sprintf(string, "hba%d", adapter->host->host_no);
+
+	controller_proc_dir_entry =
+		adapter->controller_proc_dir_entry = proc_mkdir(string, parent);
+
+	if(!controller_proc_dir_entry) {
+		printk(KERN_WARNING "\nmegaraid: proc_mkdir failed\n");
+		return;
+	}
+	adapter->proc_read = CREATE_READ_PROC("config", proc_read_config);
+	adapter->proc_stat = CREATE_READ_PROC("stat", proc_read_stat);
+	adapter->proc_mbox = CREATE_READ_PROC("mailbox", proc_read_mbox);
+#if MEGA_HAVE_ENH_PROC
+	adapter->proc_rr = CREATE_READ_PROC("rebuild-rate", proc_rebuild_rate);
+	adapter->proc_battery = CREATE_READ_PROC("battery-status",
+			proc_battery);
+
+	/*
+	 * Display each physical drive on its channel
+	 */
+	adapter->proc_pdrvstat[0] = CREATE_READ_PROC("diskdrives-ch0",
+					proc_pdrv_ch0);
+	adapter->proc_pdrvstat[1] = CREATE_READ_PROC("diskdrives-ch1",
+					proc_pdrv_ch1);
+	adapter->proc_pdrvstat[2] = CREATE_READ_PROC("diskdrives-ch2",
+					proc_pdrv_ch2);
+	adapter->proc_pdrvstat[3] = CREATE_READ_PROC("diskdrives-ch3",
+					proc_pdrv_ch3);
+
+	/*
+	 * Display a set of up to 10 logical drive through each of following
+	 * /proc entries
+	 */
+	adapter->proc_rdrvstat[0] = CREATE_READ_PROC("raiddrives-0-9",
+					proc_rdrv_10);
+	adapter->proc_rdrvstat[1] = CREATE_READ_PROC("raiddrives-10-19",
+					proc_rdrv_20);
+	adapter->proc_rdrvstat[2] = CREATE_READ_PROC("raiddrives-20-29",
+					proc_rdrv_30);
+	adapter->proc_rdrvstat[3] = CREATE_READ_PROC("raiddrives-30-39",
+					proc_rdrv_40);
+#endif
+}
+
+
+/**
+ * proc_read_config()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display configuration information about the controller.
+ */
+static int
+proc_read_config(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+
+	adapter_t *adapter = (adapter_t *)data;
+	int len = 0;
+
+	len += sprintf(page+len, "%s", MEGARAID_VERSION);
+
+	if(adapter->product_info.product_name[0])
+		len += sprintf(page+len, "%s\n",
+				adapter->product_info.product_name);
+
+	len += sprintf(page+len, "Controller Type: ");
+
+	if( adapter->flag & BOARD_MEMMAP ) {
+		len += sprintf(page+len,
+			"438/466/467/471/493/518/520/531/532\n");
+	}
+	else {
+		len += sprintf(page+len,
+			"418/428/434\n");
+	}
+
+	if(adapter->flag & BOARD_40LD) {
+		len += sprintf(page+len,
+				"Controller Supports 40 Logical Drives\n");
+	}
+
+	if(adapter->flag & BOARD_64BIT) {
+		len += sprintf(page+len,
+		"Controller capable of 64-bit memory addressing\n");
+	}
+	if( adapter->has_64bit_addr ) {
+		len += sprintf(page+len,
+			"Controller using 64-bit memory addressing\n");
+	}
+	else {
+		len += sprintf(page+len,
+			"Controller is not using 64-bit memory addressing\n");
+	}
+
+	len += sprintf(page+len, "Base = %08lx, Irq = %d, ", adapter->base,
+			adapter->host->irq);
+
+	len += sprintf(page+len, "Logical Drives = %d, Channels = %d\n",
+			adapter->numldrv, adapter->product_info.nchannels);
+
+	len += sprintf(page+len, "Version =%s:%s, DRAM = %dMb\n",
+			adapter->fw_version, adapter->bios_version,
+			adapter->product_info.dram_size);
+
+	len += sprintf(page+len,
+		"Controller Queue Depth = %d, Driver Queue Depth = %d\n",
+		adapter->product_info.max_commands, adapter->max_cmds);
+
+	len += sprintf(page+len, "support_ext_cdb    = %d\n",
+			adapter->support_ext_cdb);
+	len += sprintf(page+len, "support_random_del = %d\n",
+			adapter->support_random_del);
+	len += sprintf(page+len, "boot_ldrv_enabled  = %d\n",
+			adapter->boot_ldrv_enabled);
+	len += sprintf(page+len, "boot_ldrv          = %d\n",
+			adapter->boot_ldrv);
+	len += sprintf(page+len, "boot_pdrv_enabled  = %d\n",
+			adapter->boot_pdrv_enabled);
+	len += sprintf(page+len, "boot_pdrv_ch       = %d\n",
+			adapter->boot_pdrv_ch);
+	len += sprintf(page+len, "boot_pdrv_tgt      = %d\n",
+			adapter->boot_pdrv_tgt);
+	len += sprintf(page+len, "quiescent          = %d\n",
+			atomic_read(&adapter->quiescent));
+	len += sprintf(page+len, "has_cluster        = %d\n",
+			adapter->has_cluster);
+
+	len += sprintf(page+len, "\nModule Parameters:\n");
+	len += sprintf(page+len, "max_cmd_per_lun    = %d\n",
+			max_cmd_per_lun);
+	len += sprintf(page+len, "max_sectors_per_io = %d\n",
+			max_sectors_per_io);
+
+	*eof = 1;
+
+	return len;
+}
+
+
+
+/**
+ * proc_read_stat()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Diaplay statistical information about the I/O activity.
+ */
+static int
+proc_read_stat(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t	*adapter;
+	int	len;
+	int	i;
+
+	i = 0;	/* avoid compilation warnings */
+	len = 0;
+	adapter = (adapter_t *)data;
+
+	len = sprintf(page, "Statistical Information for this controller\n");
+	len += sprintf(page+len, "pend_cmds = %d\n",
+			atomic_read(&adapter->pend_cmds));
+#if MEGA_HAVE_STATS
+	for(i = 0; i < adapter->numldrv; i++) {
+		len += sprintf(page+len, "Logical Drive %d:\n", i);
+
+		len += sprintf(page+len,
+			"\tReads Issued = %lu, Writes Issued = %lu\n",
+			adapter->nreads[i], adapter->nwrites[i]);
+
+		len += sprintf(page+len,
+			"\tSectors Read = %lu, Sectors Written = %lu\n",
+			adapter->nreadblocks[i], adapter->nwriteblocks[i]);
+
+		len += sprintf(page+len,
+			"\tRead errors = %lu, Write errors = %lu\n\n",
+			adapter->rd_errors[i], adapter->wr_errors[i]);
+	}
+#else
+	len += sprintf(page+len,
+			"IO and error counters not compiled in driver.\n");
+#endif
+
+	*eof = 1;
+
+	return len;
+}
+
+
+/**
+ * proc_read_mbox()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display mailbox information for the last command issued. This information
+ * is good for debugging.
+ */
+static int
+proc_read_mbox(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+
+	adapter_t	*adapter = (adapter_t *)data;
+	volatile mbox_t	*mbox = adapter->mbox;
+	int	len = 0;
+
+	len = sprintf(page, "Contents of Mail Box Structure\n");
+	len += sprintf(page+len, "  Fw Command   = 0x%02x\n", 
+			mbox->m_out.cmd);
+	len += sprintf(page+len, "  Cmd Sequence = 0x%02x\n", 
+			mbox->m_out.cmdid);
+	len += sprintf(page+len, "  No of Sectors= %04d\n", 
+			mbox->m_out.numsectors);
+	len += sprintf(page+len, "  LBA          = 0x%02x\n", 
+			mbox->m_out.lba);
+	len += sprintf(page+len, "  DTA          = 0x%08x\n", 
+			mbox->m_out.xferaddr);
+	len += sprintf(page+len, "  Logical Drive= 0x%02x\n", 
+			mbox->m_out.logdrv);
+	len += sprintf(page+len, "  No of SG Elmt= 0x%02x\n",
+			mbox->m_out.numsgelements);
+	len += sprintf(page+len, "  Busy         = %01x\n", 
+			mbox->m_in.busy);
+	len += sprintf(page+len, "  Status       = 0x%02x\n", 
+			mbox->m_in.status);
+
+	*eof = 1;
+
+	return len;
+}
+
+
+/**
+ * proc_rebuild_rate()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display current rebuild rate
+ */
+static int
+proc_rebuild_rate(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t	*adapter = (adapter_t *)data;
+	dma_addr_t	dma_handle;
+	caddr_t		inquiry;
+	struct pci_dev	*pdev;
+	int	len = 0;
+
+	if( make_local_pdev(adapter, &pdev) != 0 ) {
+		*eof = 1;
+		return len;
+	}
+
+	if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
+		free_local_pdev(pdev);
+		*eof = 1;
+		return len;
+	}
+
+	if( mega_adapinq(adapter, dma_handle) != 0 ) {
+
+		len = sprintf(page, "Adapter inquiry failed.\n");
+
+		printk(KERN_WARNING "megaraid: inquiry failed.\n");
+
+		mega_free_inquiry(inquiry, dma_handle, pdev);
+
+		free_local_pdev(pdev);
+
+		*eof = 1;
+
+		return len;
+	}
+
+	if( adapter->flag & BOARD_40LD ) {
+		len = sprintf(page, "Rebuild Rate: [%d%%]\n",
+			((mega_inquiry3 *)inquiry)->rebuild_rate);
+	}
+	else {
+		len = sprintf(page, "Rebuild Rate: [%d%%]\n",
+			((mraid_ext_inquiry *)
+			inquiry)->raid_inq.adapter_info.rebuild_rate);
+	}
+
+
+	mega_free_inquiry(inquiry, dma_handle, pdev);
+
+	free_local_pdev(pdev);
+
+	*eof = 1;
+
+	return len;
+}
+
+
+/**
+ * proc_battery()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display information about the battery module on the controller.
+ */
+static int
+proc_battery(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t	*adapter = (adapter_t *)data;
+	dma_addr_t	dma_handle;
+	caddr_t		inquiry;
+	struct pci_dev	*pdev;
+	u8	battery_status = 0;
+	char	str[256];
+	int	len = 0;
+
+	if( make_local_pdev(adapter, &pdev) != 0 ) {
+		*eof = 1;
+		return len;
+	}
+
+	if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
+		free_local_pdev(pdev);
+		*eof = 1;
+		return len;
+	}
+
+	if( mega_adapinq(adapter, dma_handle) != 0 ) {
+
+		len = sprintf(page, "Adapter inquiry failed.\n");
+
+		printk(KERN_WARNING "megaraid: inquiry failed.\n");
+
+		mega_free_inquiry(inquiry, dma_handle, pdev);
+
+		free_local_pdev(pdev);
+
+		*eof = 1;
+
+		return len;
+	}
+
+	if( adapter->flag & BOARD_40LD ) {
+		battery_status = ((mega_inquiry3 *)inquiry)->battery_status;
+	}
+	else {
+		battery_status = ((mraid_ext_inquiry *)inquiry)->
+			raid_inq.adapter_info.battery_status;
+	}
+
+	/*
+	 * Decode the battery status
+	 */
+	sprintf(str, "Battery Status:[%d]", battery_status);
+
+	if(battery_status == MEGA_BATT_CHARGE_DONE)
+		strcat(str, " Charge Done");
+
+	if(battery_status & MEGA_BATT_MODULE_MISSING)
+		strcat(str, " Module Missing");
+	
+	if(battery_status & MEGA_BATT_LOW_VOLTAGE)
+		strcat(str, " Low Voltage");
+	
+	if(battery_status & MEGA_BATT_TEMP_HIGH)
+		strcat(str, " Temperature High");
+	
+	if(battery_status & MEGA_BATT_PACK_MISSING)
+		strcat(str, " Pack Missing");
+	
+	if(battery_status & MEGA_BATT_CHARGE_INPROG)
+		strcat(str, " Charge In-progress");
+	
+	if(battery_status & MEGA_BATT_CHARGE_FAIL)
+		strcat(str, " Charge Fail");
+	
+	if(battery_status & MEGA_BATT_CYCLES_EXCEEDED)
+		strcat(str, " Cycles Exceeded");
+
+	len = sprintf(page, "%s\n", str);
+
+
+	mega_free_inquiry(inquiry, dma_handle, pdev);
+
+	free_local_pdev(pdev);
+
+	*eof = 1;
+
+	return len;
+}
+
+
+/**
+ * proc_pdrv_ch0()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display information about the physical drives on physical channel 0.
+ */
+static int
+proc_pdrv_ch0(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_pdrv(adapter, page, 0));
+}
+
+
+/**
+ * proc_pdrv_ch1()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display information about the physical drives on physical channel 1.
+ */
+static int
+proc_pdrv_ch1(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_pdrv(adapter, page, 1));
+}
+
+
+/**
+ * proc_pdrv_ch2()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display information about the physical drives on physical channel 2.
+ */
+static int
+proc_pdrv_ch2(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_pdrv(adapter, page, 2));
+}
+
+
+/**
+ * proc_pdrv_ch3()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display information about the physical drives on physical channel 3.
+ */
+static int
+proc_pdrv_ch3(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_pdrv(adapter, page, 3));
+}
+
+
+/**
+ * proc_pdrv()
+ * @page - buffer to write the data in
+ * @adapter - pointer to our soft state
+ *
+ * Display information about the physical drives.
+ */
+static int
+proc_pdrv(adapter_t *adapter, char *page, int channel)
+{
+	dma_addr_t	dma_handle;
+	char		*scsi_inq;
+	dma_addr_t	scsi_inq_dma_handle;
+	caddr_t		inquiry;
+	struct pci_dev	*pdev;
+	u8	*pdrv_state;
+	u8	state;
+	int	tgt;
+	int	max_channels;
+	int	len = 0;
+	char	str[80];
+	int	i;
+
+	if( make_local_pdev(adapter, &pdev) != 0 ) {
+		return len;
+	}
+
+	if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
+		goto free_pdev;
+	}
+
+	if( mega_adapinq(adapter, dma_handle) != 0 ) {
+		len = sprintf(page, "Adapter inquiry failed.\n");
+
+		printk(KERN_WARNING "megaraid: inquiry failed.\n");
+
+		goto free_inquiry;
+	}
+
+
+	scsi_inq = pci_alloc_consistent(pdev, 256, &scsi_inq_dma_handle);
+
+	if( scsi_inq == NULL ) {
+		len = sprintf(page, "memory not available for scsi inq.\n");
+
+		goto free_inquiry;
+	}
+
+	if( adapter->flag & BOARD_40LD ) {
+		pdrv_state = ((mega_inquiry3 *)inquiry)->pdrv_state;
+	}
+	else {
+		pdrv_state = ((mraid_ext_inquiry *)inquiry)->
+			raid_inq.pdrv_info.pdrv_state;
+	}
+
+	max_channels = adapter->product_info.nchannels;
+
+	if( channel >= max_channels ) {
+		goto free_pci;
+	}
+
+	for( tgt = 0; tgt <= MAX_TARGET; tgt++ ) {
+
+		i = channel*16 + tgt;
+
+		state = *(pdrv_state + i);
+
+		switch( state & 0x0F ) {
+
+		case PDRV_ONLINE:
+			sprintf(str,
+			"Channel:%2d Id:%2d State: Online",
+				channel, tgt);
+			break;
+
+		case PDRV_FAILED:
+			sprintf(str,
+			"Channel:%2d Id:%2d State: Failed",
+				channel, tgt);
+			break;
+
+		case PDRV_RBLD:
+			sprintf(str,
+			"Channel:%2d Id:%2d State: Rebuild",
+				channel, tgt);
+			break;
+
+		case PDRV_HOTSPARE:
+			sprintf(str,
+			"Channel:%2d Id:%2d State: Hot spare",
+				channel, tgt);
+			break;
+
+		default:
+			sprintf(str,
+			"Channel:%2d Id:%2d State: Un-configured",
+				channel, tgt);
+			break;
+
+		}
+
+		/*
+		 * This interface displays inquiries for disk drives
+		 * only. Inquries for logical drives and non-disk
+		 * devices are available through /proc/scsi/scsi
+		 */
+		memset(scsi_inq, 0, 256);
+		if( mega_internal_dev_inquiry(adapter, channel, tgt,
+				scsi_inq_dma_handle) ||
+				(scsi_inq[0] & 0x1F) != TYPE_DISK ) {
+			continue;
+		}
+
+		/*
+		 * Check for overflow. We print less than 240
+		 * characters for inquiry
+		 */
+		if( (len + 240) >= PAGE_SIZE ) break;
+
+		len += sprintf(page+len, "%s.\n", str);
+
+		len += mega_print_inquiry(page+len, scsi_inq);
+	}
+
+free_pci:
+	pci_free_consistent(pdev, 256, scsi_inq, scsi_inq_dma_handle);
+free_inquiry:
+	mega_free_inquiry(inquiry, dma_handle, pdev);
+free_pdev:
+	free_local_pdev(pdev);
+
+	return len;
+}
+
+
+/*
+ * Display scsi inquiry
+ */
+static int
+mega_print_inquiry(char *page, char *scsi_inq)
+{
+	int	len = 0;
+	int	i;
+
+	len = sprintf(page, "  Vendor: ");
+	for( i = 8; i < 16; i++ ) {
+		len += sprintf(page+len, "%c", scsi_inq[i]);
+	}
+
+	len += sprintf(page+len, "  Model: ");
+
+	for( i = 16; i < 32; i++ ) {
+		len += sprintf(page+len, "%c", scsi_inq[i]);
+	}
+
+	len += sprintf(page+len, "  Rev: ");
+
+	for( i = 32; i < 36; i++ ) {
+		len += sprintf(page+len, "%c", scsi_inq[i]);
+	}
+
+	len += sprintf(page+len, "\n");
+
+	i = scsi_inq[0] & 0x1f;
+
+	len += sprintf(page+len, "  Type:   %s ",
+		i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
+		   "Unknown          ");
+
+	len += sprintf(page+len,
+	"                 ANSI SCSI revision: %02x", scsi_inq[2] & 0x07);
+
+	if( (scsi_inq[2] & 0x07) == 1 && (scsi_inq[3] & 0x0f) == 1 )
+		len += sprintf(page+len, " CCS\n");
+	else
+		len += sprintf(page+len, "\n");
+
+	return len;
+}
+
+
+/**
+ * proc_rdrv_10()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_rdrv_10(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_rdrv(adapter, page, 0, 9));
+}
+
+
+/**
+ * proc_rdrv_20()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_rdrv_20(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_rdrv(adapter, page, 10, 19));
+}
+
+
+/**
+ * proc_rdrv_30()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_rdrv_30(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_rdrv(adapter, page, 20, 29));
+}
+
+
+/**
+ * proc_rdrv_40()
+ * @page - buffer to write the data in
+ * @start - where the actual data has been written in page
+ * @offset - same meaning as the read system call
+ * @count - same meaning as the read system call
+ * @eof - set if no more data needs to be returned
+ * @data - pointer to our soft state
+ *
+ * Display real time information about the logical drives 0 through 9.
+ */
+static int
+proc_rdrv_40(char *page, char **start, off_t offset, int count, int *eof,
+		void *data)
+{
+	adapter_t *adapter = (adapter_t *)data;
+
+	*eof = 1;
+
+	return (proc_rdrv(adapter, page, 30, 39));
+}
+
+
+/**
+ * proc_rdrv()
+ * @page - buffer to write the data in
+ * @adapter - pointer to our soft state
+ * @start - starting logical drive to display
+ * @end - ending logical drive to display
+ *
+ * We do not print the inquiry information since its already available through
+ * /proc/scsi/scsi interface
+ */
+static int
+proc_rdrv(adapter_t *adapter, char *page, int start, int end )
+{
+	dma_addr_t	dma_handle;
+	logdrv_param	*lparam;
+	megacmd_t	mc;
+	char		*disk_array;
+	dma_addr_t	disk_array_dma_handle;
+	caddr_t		inquiry;
+	struct pci_dev	*pdev;
+	u8	*rdrv_state;
+	int	num_ldrv;
+	u32	array_sz;
+	int	len = 0;
+	int	i;
+
+	if( make_local_pdev(adapter, &pdev) != 0 ) {
+		return len;
+	}
+
+	if( (inquiry = mega_allocate_inquiry(&dma_handle, pdev)) == NULL ) {
+		free_local_pdev(pdev);
+		return len;
+	}
+
+	if( mega_adapinq(adapter, dma_handle) != 0 ) {
+
+		len = sprintf(page, "Adapter inquiry failed.\n");
+
+		printk(KERN_WARNING "megaraid: inquiry failed.\n");
+
+		mega_free_inquiry(inquiry, dma_handle, pdev);
+
+		free_local_pdev(pdev);
+
+		return len;
+	}
+
+	memset(&mc, 0, sizeof(megacmd_t));
+
+	if( adapter->flag & BOARD_40LD ) {
+		array_sz = sizeof(disk_array_40ld);
+
+		rdrv_state = ((mega_inquiry3 *)inquiry)->ldrv_state;
+
+		num_ldrv = ((mega_inquiry3 *)inquiry)->num_ldrv;
+	}
+	else {
+		array_sz = sizeof(disk_array_8ld);
+
+		rdrv_state = ((mraid_ext_inquiry *)inquiry)->
+			raid_inq.logdrv_info.ldrv_state;
+
+		num_ldrv = ((mraid_ext_inquiry *)inquiry)->
+			raid_inq.logdrv_info.num_ldrv;
+	}
+
+	disk_array = pci_alloc_consistent(pdev, array_sz,
+			&disk_array_dma_handle);
+
+	if( disk_array == NULL ) {
+		len = sprintf(page, "memory not available.\n");
+
+		mega_free_inquiry(inquiry, dma_handle, pdev);
+
+		free_local_pdev(pdev);
+
+		return len;
+	}
+
+	mc.xferaddr = (u32)disk_array_dma_handle;
+
+	if( adapter->flag & BOARD_40LD ) {
+		mc.cmd = FC_NEW_CONFIG;
+		mc.opcode = OP_DCMD_READ_CONFIG;
+
+		if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+
+			len = sprintf(page, "40LD read config failed.\n");
+
+			mega_free_inquiry(inquiry, dma_handle, pdev);
+
+			pci_free_consistent(pdev, array_sz, disk_array,
+					disk_array_dma_handle);
+
+			free_local_pdev(pdev);
+
+			return len;
+		}
+
+	}
+	else {
+		mc.cmd = NEW_READ_CONFIG_8LD;
+
+		if( mega_internal_command(adapter, LOCK_INT, &mc, NULL) ) {
+
+			mc.cmd = READ_CONFIG_8LD;
+
+			if( mega_internal_command(adapter, LOCK_INT, &mc,
+						NULL) ){
+
+				len = sprintf(page,
+					"8LD read config failed.\n");
+
+				mega_free_inquiry(inquiry, dma_handle, pdev);
+
+				pci_free_consistent(pdev, array_sz,
+						disk_array,
+						disk_array_dma_handle);
+
+				free_local_pdev(pdev);
+
+				return len;
+			}
+		}
+	}
+
+	for( i = start; i < ( (end+1 < num_ldrv) ? end+1 : num_ldrv ); i++ ) {
+
+		if( adapter->flag & BOARD_40LD ) {
+			lparam =
+			&((disk_array_40ld *)disk_array)->ldrv[i].lparam;
+		}
+		else {
+			lparam =
+			&((disk_array_8ld *)disk_array)->ldrv[i].lparam;
+		}
+
+		/*
+		 * Check for overflow. We print less than 240 characters for
+		 * information about each logical drive.
+		 */
+		if( (len + 240) >= PAGE_SIZE ) break;
+
+		len += sprintf(page+len, "Logical drive:%2d:, ", i);
+
+		switch( rdrv_state[i] & 0x0F ) {
+		case RDRV_OFFLINE:
+			len += sprintf(page+len, "state: offline");
+			break;
+
+		case RDRV_DEGRADED:
+			len += sprintf(page+len, "state: degraded");
+			break;
+
+		case RDRV_OPTIMAL:
+			len += sprintf(page+len, "state: optimal");
+			break;
+
+		case RDRV_DELETED:
+			len += sprintf(page+len, "state: deleted");
+			break;
+
+		default:
+			len += sprintf(page+len, "state: unknown");
+			break;
+		}
+
+		/*
+		 * Check if check consistency or initialization is going on
+		 * for this logical drive.
+		 */
+		if( (rdrv_state[i] & 0xF0) == 0x20 ) {
+			len += sprintf(page+len,
+					", check-consistency in progress");
+		}
+		else if( (rdrv_state[i] & 0xF0) == 0x10 ) {
+			len += sprintf(page+len,
+					", initialization in progress");
+		}
+		
+		len += sprintf(page+len, "\n");
+
+		len += sprintf(page+len, "Span depth:%3d, ",
+				lparam->span_depth);
+
+		len += sprintf(page+len, "RAID level:%3d, ",
+				lparam->level);
+
+		len += sprintf(page+len, "Stripe size:%3d, ",
+				lparam->stripe_sz ? lparam->stripe_sz/2: 128);
+
+		len += sprintf(page+len, "Row size:%3d\n",
+				lparam->row_size);
+
+
+		len += sprintf(page+len, "Read Policy: ");
+
+		switch(lparam->read_ahead) {
+
+		case NO_READ_AHEAD:
+			len += sprintf(page+len, "No read ahead, ");
+			break;
+
+		case READ_AHEAD:
+			len += sprintf(page+len, "Read ahead, ");
+			break;
+
+		case ADAP_READ_AHEAD:
+			len += sprintf(page+len, "Adaptive, ");
+			break;
+
+		}
+
+		len += sprintf(page+len, "Write Policy: ");
+
+		switch(lparam->write_mode) {
+
+		case WRMODE_WRITE_THRU:
+			len += sprintf(page+len, "Write thru, ");
+			break;
+
+		case WRMODE_WRITE_BACK:
+			len += sprintf(page+len, "Write back, ");
+			break;
+		}
+
+		len += sprintf(page+len, "Cache Policy: ");
+
+		switch(lparam->direct_io) {
+
+		case CACHED_IO:
+			len += sprintf(page+len, "Cached IO\n\n");
+			break;
+
+		case DIRECT_IO:
+			len += sprintf(page+len, "Direct IO\n\n");
+			break;
+		}
+	}
+
+	mega_free_inquiry(inquiry, dma_handle, pdev);
+
+	pci_free_consistent(pdev, array_sz, disk_array,
+			disk_array_dma_handle);
+
+	free_local_pdev(pdev);
+
+	return len;
+}
+
+#endif
+
+
+/**
+ * megaraid_biosparam()
+ *
+ * Return the disk geometry for a particular disk
+ */
+static int
+megaraid_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		    sector_t capacity, int geom[])
+{
+	adapter_t	*adapter;
+	unsigned char	*bh;
+	int	heads;
+	int	sectors;
+	int	cylinders;
+	int	rval;
+
+	/* Get pointer to host config structure */
+	adapter = (adapter_t *)sdev->host->hostdata;
+
+	if (IS_RAID_CH(adapter, sdev->channel)) {
+			/* Default heads (64) & sectors (32) */
+			heads = 64;
+			sectors = 32;
+			cylinders = (ulong)capacity / (heads * sectors);
+
+			/*
+			 * Handle extended translation size for logical drives
+			 * > 1Gb
+			 */
+			if ((ulong)capacity >= 0x200000) {
+				heads = 255;
+				sectors = 63;
+				cylinders = (ulong)capacity / (heads * sectors);
+			}
+
+			/* return result */
+			geom[0] = heads;
+			geom[1] = sectors;
+			geom[2] = cylinders;
+	}
+	else {
+		bh = scsi_bios_ptable(bdev);
+
+		if( bh ) {
+			rval = scsi_partsize(bh, capacity,
+					    &geom[2], &geom[0], &geom[1]);
+			kfree(bh);
+			if( rval != -1 )
+				return rval;
+		}
+
+		printk(KERN_INFO
+		"megaraid: invalid partition on this disk on channel %d\n",
+				sdev->channel);
+
+		/* Default heads (64) & sectors (32) */
+		heads = 64;
+		sectors = 32;
+		cylinders = (ulong)capacity / (heads * sectors);
+
+		/* Handle extended translation size for logical drives > 1Gb */
+		if ((ulong)capacity >= 0x200000) {
+			heads = 255;
+			sectors = 63;
+			cylinders = (ulong)capacity / (heads * sectors);
+		}
+
+		/* return result */
+		geom[0] = heads;
+		geom[1] = sectors;
+		geom[2] = cylinders;
+	}
+
+	return 0;
+}
+
+/**
+ * mega_init_scb()
+ * @adapter - pointer to our soft state
+ *
+ * Allocate memory for the various pointers in the scb structures:
+ * scatter-gather list pointer, passthru and extended passthru structure
+ * pointers.
+ */
+static int
+mega_init_scb(adapter_t *adapter)
+{
+	scb_t	*scb;
+	int	i;
+
+	for( i = 0; i < adapter->max_cmds; i++ ) {
+
+		scb = &adapter->scb_list[i];
+
+		scb->sgl64 = NULL;
+		scb->sgl = NULL;
+		scb->pthru = NULL;
+		scb->epthru = NULL;
+	}
+
+	for( i = 0; i < adapter->max_cmds; i++ ) {
+
+		scb = &adapter->scb_list[i];
+
+		scb->idx = i;
+
+		scb->sgl64 = pci_alloc_consistent(adapter->dev,
+				sizeof(mega_sgl64) * adapter->sglen,
+				&scb->sgl_dma_addr);
+
+		scb->sgl = (mega_sglist *)scb->sgl64;
+
+		if( !scb->sgl ) {
+			printk(KERN_WARNING "RAID: Can't allocate sglist.\n");
+			mega_free_sgl(adapter);
+			return -1;
+		}
+
+		scb->pthru = pci_alloc_consistent(adapter->dev,
+				sizeof(mega_passthru),
+				&scb->pthru_dma_addr);
+
+		if( !scb->pthru ) {
+			printk(KERN_WARNING "RAID: Can't allocate passthru.\n");
+			mega_free_sgl(adapter);
+			return -1;
+		}
+
+		scb->epthru = pci_alloc_consistent(adapter->dev,
+				sizeof(mega_ext_passthru),
+				&scb->epthru_dma_addr);
+
+		if( !scb->epthru ) {
+			printk(KERN_WARNING
+				"Can't allocate extended passthru.\n");
+			mega_free_sgl(adapter);
+			return -1;
+		}
+
+
+		scb->dma_type = MEGA_DMA_TYPE_NONE;
+
+		/*
+		 * Link to free list
+		 * lock not required since we are loading the driver, so no
+		 * commands possible right now.
+		 */
+		scb->state = SCB_FREE;
+		scb->cmd = NULL;
+		list_add(&scb->list, &adapter->free_list);
+	}
+
+	return 0;
+}
+
+
+/**
+ * megadev_open()
+ * @inode - unused
+ * @filep - unused
+ *
+ * Routines for the character/ioctl interface to the driver. Find out if this
+ * is a valid open. If yes, increment the module use count so that it cannot
+ * be unloaded.
+ */
+static int
+megadev_open (struct inode *inode, struct file *filep)
+{
+	/*
+	 * Only allow superuser to access private ioctl interface
+	 */
+	if( !capable(CAP_SYS_ADMIN) ) return -EACCES;
+
+	return 0;
+}
+
+
+/**
+ * megadev_ioctl()
+ * @inode - Our device inode
+ * @filep - unused
+ * @cmd - ioctl command
+ * @arg - user buffer
+ *
+ * ioctl entry point for our private ioctl interface. We move the data in from
+ * the user space, prepare the command (if necessary, convert the old MIMD
+ * ioctl to new ioctl command), and issue a synchronous command to the
+ * controller.
+ */
+static int
+megadev_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
+		unsigned long arg)
+{
+	adapter_t	*adapter;
+	nitioctl_t	uioc;
+	int		adapno;
+	int		rval;
+	mega_passthru	__user *upthru;	/* user address for passthru */
+	mega_passthru	*pthru;		/* copy user passthru here */
+	dma_addr_t	pthru_dma_hndl;
+	void		*data = NULL;	/* data to be transferred */
+	dma_addr_t	data_dma_hndl;	/* dma handle for data xfer area */
+	megacmd_t	mc;
+	megastat_t	__user *ustats;
+	int		num_ldrv;
+	u32		uxferaddr = 0;
+	struct pci_dev	*pdev;
+
+	ustats = NULL; /* avoid compilation warnings */
+	num_ldrv = 0;
+
+	/*
+	 * Make sure only USCSICMD are issued through this interface.
+	 * MIMD application would still fire different command.
+	 */
+	if( (_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD) ) {
+		return -EINVAL;
+	}
+
+	/*
+	 * Check and convert a possible MIMD command to NIT command.
+	 * mega_m_to_n() copies the data from the user space, so we do not
+	 * have to do it here.
+	 * NOTE: We will need some user address to copyout the data, therefore
+	 * the inteface layer will also provide us with the required user
+	 * addresses.
+	 */
+	memset(&uioc, 0, sizeof(nitioctl_t));
+	if( (rval = mega_m_to_n( (void __user *)arg, &uioc)) != 0 )
+		return rval;
+
+
+	switch( uioc.opcode ) {
+
+	case GET_DRIVER_VER:
+		if( put_user(driver_ver, (u32 __user *)uioc.uioc_uaddr) )
+			return (-EFAULT);
+
+		break;
+
+	case GET_N_ADAP:
+		if( put_user(hba_count, (u32 __user *)uioc.uioc_uaddr) )
+			return (-EFAULT);
+
+		/*
+		 * Shucks. MIMD interface returns a positive value for number
+		 * of adapters. TODO: Change it to return 0 when there is no
+		 * applicatio using mimd interface.
+		 */
+		return hba_count;
+
+	case GET_ADAP_INFO:
+
+		/*
+		 * Which adapter
+		 */
+		if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
+			return (-ENODEV);
+
+		if( copy_to_user(uioc.uioc_uaddr, mcontroller+adapno,
+				sizeof(struct mcontroller)) )
+			return (-EFAULT);
+		break;
+
+#if MEGA_HAVE_STATS
+
+	case GET_STATS:
+		/*
+		 * Which adapter
+		 */
+		if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
+			return (-ENODEV);
+
+		adapter = hba_soft_state[adapno];
+
+		ustats = uioc.uioc_uaddr;
+
+		if( copy_from_user(&num_ldrv, &ustats->num_ldrv, sizeof(int)) )
+			return (-EFAULT);
+
+		/*
+		 * Check for the validity of the logical drive number
+		 */
+		if( num_ldrv >= MAX_LOGICAL_DRIVES_40LD ) return -EINVAL;
+
+		if( copy_to_user(ustats->nreads, adapter->nreads,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		if( copy_to_user(ustats->nreadblocks, adapter->nreadblocks,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		if( copy_to_user(ustats->nwrites, adapter->nwrites,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		if( copy_to_user(ustats->nwriteblocks, adapter->nwriteblocks,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		if( copy_to_user(ustats->rd_errors, adapter->rd_errors,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		if( copy_to_user(ustats->wr_errors, adapter->wr_errors,
+					num_ldrv*sizeof(u32)) )
+			return -EFAULT;
+
+		return 0;
+
+#endif
+	case MBOX_CMD:
+
+		/*
+		 * Which adapter
+		 */
+		if( (adapno = GETADAP(uioc.adapno)) >= hba_count )
+			return (-ENODEV);
+
+		adapter = hba_soft_state[adapno];
+
+		/*
+		 * Deletion of logical drive is a special case. The adapter
+		 * should be quiescent before this command is issued.
+		 */
+		if( uioc.uioc_rmbox[0] == FC_DEL_LOGDRV &&
+				uioc.uioc_rmbox[2] == OP_DEL_LOGDRV ) {
+
+			/*
+			 * Do we support this feature
+			 */
+			if( !adapter->support_random_del ) {
+				printk(KERN_WARNING "megaraid: logdrv ");
+				printk("delete on non-supporting F/W.\n");
+
+				return (-EINVAL);
+			}
+
+			rval = mega_del_logdrv( adapter, uioc.uioc_rmbox[3] );
+
+			if( rval == 0 ) {
+				memset(&mc, 0, sizeof(megacmd_t));
+
+				mc.status = rval;
+
+				rval = mega_n_to_m((void __user *)arg, &mc);
+			}
+
+			return rval;
+		}
+		/*
+		 * This interface only support the regular passthru commands.
+		 * Reject extended passthru and 64-bit passthru
+		 */
+		if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU64 ||
+			uioc.uioc_rmbox[0] == MEGA_MBOXCMD_EXTPTHRU ) {
+
+			printk(KERN_WARNING "megaraid: rejected passthru.\n");
+
+			return (-EINVAL);
+		}
+
+		/*
+		 * For all internal commands, the buffer must be allocated in
+		 * <4GB address range
+		 */
+		if( make_local_pdev(adapter, &pdev) != 0 )
+			return -EIO;
+
+		/* Is it a passthru command or a DCMD */
+		if( uioc.uioc_rmbox[0] == MEGA_MBOXCMD_PASSTHRU ) {
+			/* Passthru commands */
+
+			pthru = pci_alloc_consistent(pdev,
+					sizeof(mega_passthru),
+					&pthru_dma_hndl);
+
+			if( pthru == NULL ) {
+				free_local_pdev(pdev);
+				return (-ENOMEM);
+			}
+
+			/*
+			 * The user passthru structure
+			 */
+			upthru = (mega_passthru __user *)MBOX(uioc)->xferaddr;
+
+			/*
+			 * Copy in the user passthru here.
+			 */
+			if( copy_from_user(pthru, upthru,
+						sizeof(mega_passthru)) ) {
+
+				pci_free_consistent(pdev,
+						sizeof(mega_passthru), pthru,
+						pthru_dma_hndl);
+
+				free_local_pdev(pdev);
+
+				return (-EFAULT);
+			}
+
+			/*
+			 * Is there a data transfer
+			 */
+			if( pthru->dataxferlen ) {
+				data = pci_alloc_consistent(pdev,
+						pthru->dataxferlen,
+						&data_dma_hndl);
+
+				if( data == NULL ) {
+					pci_free_consistent(pdev,
+							sizeof(mega_passthru),
+							pthru,
+							pthru_dma_hndl);
+
+					free_local_pdev(pdev);
+
+					return (-ENOMEM);
+				}
+
+				/*
+				 * Save the user address and point the kernel
+				 * address at just allocated memory
+				 */
+				uxferaddr = pthru->dataxferaddr;
+				pthru->dataxferaddr = data_dma_hndl;
+			}
+
+
+			/*
+			 * Is data coming down-stream
+			 */
+			if( pthru->dataxferlen && (uioc.flags & UIOC_WR) ) {
+				/*
+				 * Get the user data
+				 */
+				if( copy_from_user(data, (char __user *)uxferaddr,
+							pthru->dataxferlen) ) {
+					rval = (-EFAULT);
+					goto freemem_and_return;
+				}
+			}
+
+			memset(&mc, 0, sizeof(megacmd_t));
+
+			mc.cmd = MEGA_MBOXCMD_PASSTHRU;
+			mc.xferaddr = (u32)pthru_dma_hndl;
+
+			/*
+			 * Issue the command
+			 */
+			mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+
+			rval = mega_n_to_m((void __user *)arg, &mc);
+
+			if( rval ) goto freemem_and_return;
+
+
+			/*
+			 * Is data going up-stream
+			 */
+			if( pthru->dataxferlen && (uioc.flags & UIOC_RD) ) {
+				if( copy_to_user((char __user *)uxferaddr, data,
+							pthru->dataxferlen) ) {
+					rval = (-EFAULT);
+				}
+			}
+
+			/*
+			 * Send the request sense data also, irrespective of
+			 * whether the user has asked for it or not.
+			 */
+			copy_to_user(upthru->reqsensearea,
+					pthru->reqsensearea, 14);
+
+freemem_and_return:
+			if( pthru->dataxferlen ) {
+				pci_free_consistent(pdev,
+						pthru->dataxferlen, data,
+						data_dma_hndl);
+			}
+
+			pci_free_consistent(pdev, sizeof(mega_passthru),
+					pthru, pthru_dma_hndl);
+
+			free_local_pdev(pdev);
+
+			return rval;
+		}
+		else {
+			/* DCMD commands */
+
+			/*
+			 * Is there a data transfer
+			 */
+			if( uioc.xferlen ) {
+				data = pci_alloc_consistent(pdev,
+						uioc.xferlen, &data_dma_hndl);
+
+				if( data == NULL ) {
+					free_local_pdev(pdev);
+					return (-ENOMEM);
+				}
+
+				uxferaddr = MBOX(uioc)->xferaddr;
+			}
+
+			/*
+			 * Is data coming down-stream
+			 */
+			if( uioc.xferlen && (uioc.flags & UIOC_WR) ) {
+				/*
+				 * Get the user data
+				 */
+				if( copy_from_user(data, (char __user *)uxferaddr,
+							uioc.xferlen) ) {
+
+					pci_free_consistent(pdev,
+							uioc.xferlen,
+							data, data_dma_hndl);
+
+					free_local_pdev(pdev);
+
+					return (-EFAULT);
+				}
+			}
+
+			memcpy(&mc, MBOX(uioc), sizeof(megacmd_t));
+
+			mc.xferaddr = (u32)data_dma_hndl;
+
+			/*
+			 * Issue the command
+			 */
+			mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+
+			rval = mega_n_to_m((void __user *)arg, &mc);
+
+			if( rval ) {
+				if( uioc.xferlen ) {
+					pci_free_consistent(pdev,
+							uioc.xferlen, data,
+							data_dma_hndl);
+				}
+
+				free_local_pdev(pdev);
+
+				return rval;
+			}
+
+			/*
+			 * Is data going up-stream
+			 */
+			if( uioc.xferlen && (uioc.flags & UIOC_RD) ) {
+				if( copy_to_user((char __user *)uxferaddr, data,
+							uioc.xferlen) ) {
+
+					rval = (-EFAULT);
+				}
+			}
+
+			if( uioc.xferlen ) {
+				pci_free_consistent(pdev,
+						uioc.xferlen, data,
+						data_dma_hndl);
+			}
+
+			free_local_pdev(pdev);
+
+			return rval;
+		}
+
+	default:
+		return (-EINVAL);
+	}
+
+	return 0;
+}
+
+/**
+ * mega_m_to_n()
+ * @arg - user address
+ * @uioc - new ioctl structure
+ *
+ * A thin layer to convert older mimd interface ioctl structure to NIT ioctl
+ * structure
+ *
+ * Converts the older mimd ioctl structure to newer NIT structure
+ */
+static int
+mega_m_to_n(void __user *arg, nitioctl_t *uioc)
+{
+	struct uioctl_t	uioc_mimd;
+	char	signature[8] = {0};
+	u8	opcode;
+	u8	subopcode;
+
+
+	/*
+	 * check is the application conforms to NIT. We do not have to do much
+	 * in that case.
+	 * We exploit the fact that the signature is stored in the very
+	 * begining of the structure.
+	 */
+
+	if( copy_from_user(signature, arg, 7) )
+		return (-EFAULT);
+
+	if( memcmp(signature, "MEGANIT", 7) == 0 ) {
+
+		/*
+		 * NOTE NOTE: The nit ioctl is still under flux because of
+		 * change of mailbox definition, in HPE. No applications yet
+		 * use this interface and let's not have applications use this
+		 * interface till the new specifitions are in place.
+		 */
+		return -EINVAL;
+#if 0
+		if( copy_from_user(uioc, arg, sizeof(nitioctl_t)) )
+			return (-EFAULT);
+		return 0;
+#endif
+	}
+
+	/*
+	 * Else assume we have mimd uioctl_t as arg. Convert to nitioctl_t
+	 *
+	 * Get the user ioctl structure
+	 */
+	if( copy_from_user(&uioc_mimd, arg, sizeof(struct uioctl_t)) )
+		return (-EFAULT);
+
+
+	/*
+	 * Get the opcode and subopcode for the commands
+	 */
+	opcode = uioc_mimd.ui.fcs.opcode;
+	subopcode = uioc_mimd.ui.fcs.subopcode;
+
+	switch (opcode) {
+	case 0x82:
+
+		switch (subopcode) {
+
+		case MEGAIOC_QDRVRVER:	/* Query driver version */
+			uioc->opcode = GET_DRIVER_VER;
+			uioc->uioc_uaddr = uioc_mimd.data;
+			break;
+
+		case MEGAIOC_QNADAP:	/* Get # of adapters */
+			uioc->opcode = GET_N_ADAP;
+			uioc->uioc_uaddr = uioc_mimd.data;
+			break;
+
+		case MEGAIOC_QADAPINFO:	/* Get adapter information */
+			uioc->opcode = GET_ADAP_INFO;
+			uioc->adapno = uioc_mimd.ui.fcs.adapno;
+			uioc->uioc_uaddr = uioc_mimd.data;
+			break;
+
+		default:
+			return(-EINVAL);
+		}
+
+		break;
+
+
+	case 0x81:
+
+		uioc->opcode = MBOX_CMD;
+		uioc->adapno = uioc_mimd.ui.fcs.adapno;
+
+		memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18);
+
+		uioc->xferlen = uioc_mimd.ui.fcs.length;
+
+		if( uioc_mimd.outlen ) uioc->flags = UIOC_RD;
+		if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR;
+
+		break;
+
+	case 0x80:
+
+		uioc->opcode = MBOX_CMD;
+		uioc->adapno = uioc_mimd.ui.fcs.adapno;
+
+		memcpy(uioc->uioc_rmbox, uioc_mimd.mbox, 18);
+
+		/*
+		 * Choose the xferlen bigger of input and output data
+		 */
+		uioc->xferlen = uioc_mimd.outlen > uioc_mimd.inlen ?
+			uioc_mimd.outlen : uioc_mimd.inlen;
+
+		if( uioc_mimd.outlen ) uioc->flags = UIOC_RD;
+		if( uioc_mimd.inlen ) uioc->flags |= UIOC_WR;
+
+		break;
+
+	default:
+		return (-EINVAL);
+
+	}
+
+	return 0;
+}
+
+/*
+ * mega_n_to_m()
+ * @arg - user address
+ * @mc - mailbox command
+ *
+ * Updates the status information to the application, depending on application
+ * conforms to older mimd ioctl interface or newer NIT ioctl interface
+ */
+static int
+mega_n_to_m(void __user *arg, megacmd_t *mc)
+{
+	nitioctl_t	__user *uiocp;
+	megacmd_t	__user *umc;
+	mega_passthru	__user *upthru;
+	struct uioctl_t	__user *uioc_mimd;
+	char	signature[8] = {0};
+
+	/*
+	 * check is the application conforms to NIT.
+	 */
+	if( copy_from_user(signature, arg, 7) )
+		return -EFAULT;
+
+	if( memcmp(signature, "MEGANIT", 7) == 0 ) {
+
+		uiocp = arg;
+
+		if( put_user(mc->status, (u8 __user *)&MBOX_P(uiocp)->status) )
+			return (-EFAULT);
+
+		if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
+
+			umc = MBOX_P(uiocp);
+
+			if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr))
+				return -EFAULT;
+
+			if( put_user(mc->status, (u8 __user *)&upthru->scsistatus))
+				return (-EFAULT);
+		}
+	}
+	else {
+		uioc_mimd = arg;
+
+		if( put_user(mc->status, (u8 __user *)&uioc_mimd->mbox[17]) )
+			return (-EFAULT);
+
+		if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
+
+			umc = (megacmd_t __user *)uioc_mimd->mbox;
+
+			if (get_user(upthru, (mega_passthru __user * __user *)&umc->xferaddr))
+				return (-EFAULT);
+
+			if( put_user(mc->status, (u8 __user *)&upthru->scsistatus) )
+				return (-EFAULT);
+		}
+	}
+
+	return 0;
+}
+
+
+/*
+ * MEGARAID 'FW' commands.
+ */
+
+/**
+ * mega_is_bios_enabled()
+ * @adapter - pointer to our soft state
+ *
+ * issue command to find out if the BIOS is enabled for this controller
+ */
+static int
+mega_is_bios_enabled(adapter_t *adapter)
+{
+	unsigned char	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox;
+	int	ret;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	raw_mbox[0] = IS_BIOS_ENABLED;
+	raw_mbox[2] = GET_BIOS;
+
+
+	ret = issue_scb_block(adapter, raw_mbox);
+
+	return *(char *)adapter->mega_buffer;
+}
+
+
+/**
+ * mega_enum_raid_scsi()
+ * @adapter - pointer to our soft state
+ *
+ * Find out what channels are RAID/SCSI. This information is used to
+ * differentiate the virtual channels and physical channels and to support
+ * ROMB feature and non-disk devices.
+ */
+static void
+mega_enum_raid_scsi(adapter_t *adapter)
+{
+	unsigned char raw_mbox[sizeof(struct mbox_out)];
+	mbox_t *mbox;
+	int i;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+
+	/*
+	 * issue command to find out what channels are raid/scsi
+	 */
+	raw_mbox[0] = CHNL_CLASS;
+	raw_mbox[2] = GET_CHNL_CLASS;
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	/*
+	 * Non-ROMB firmware fail this command, so all channels
+	 * must be shown RAID
+	 */
+	adapter->mega_ch_class = 0xFF;
+
+	if(!issue_scb_block(adapter, raw_mbox)) {
+		adapter->mega_ch_class = *((char *)adapter->mega_buffer);
+
+	}
+
+	for( i = 0; i < adapter->product_info.nchannels; i++ ) { 
+		if( (adapter->mega_ch_class >> i) & 0x01 ) {
+			printk(KERN_INFO "megaraid: channel[%d] is raid.\n",
+					i);
+		}
+		else {
+			printk(KERN_INFO "megaraid: channel[%d] is scsi.\n",
+					i);
+		}
+	}
+
+	return;
+}
+
+
+/**
+ * mega_get_boot_drv()
+ * @adapter - pointer to our soft state
+ *
+ * Find out which device is the boot device. Note, any logical drive or any
+ * phyical device (e.g., a CDROM) can be designated as a boot device.
+ */
+static void
+mega_get_boot_drv(adapter_t *adapter)
+{
+	struct private_bios_data	*prv_bios_data;
+	unsigned char	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox;
+	u16	cksum = 0;
+	u8	*cksum_p;
+	u8	boot_pdrv;
+	int	i;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+
+	raw_mbox[0] = BIOS_PVT_DATA;
+	raw_mbox[2] = GET_BIOS_PVT_DATA;
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	adapter->boot_ldrv_enabled = 0;
+	adapter->boot_ldrv = 0;
+
+	adapter->boot_pdrv_enabled = 0;
+	adapter->boot_pdrv_ch = 0;
+	adapter->boot_pdrv_tgt = 0;
+
+	if(issue_scb_block(adapter, raw_mbox) == 0) {
+		prv_bios_data =
+			(struct private_bios_data *)adapter->mega_buffer;
+
+		cksum = 0;
+		cksum_p = (char *)prv_bios_data;
+		for (i = 0; i < 14; i++ ) {
+			cksum += (u16)(*cksum_p++);
+		}
+
+		if (prv_bios_data->cksum == (u16)(0-cksum) ) {
+
+			/*
+			 * If MSB is set, a physical drive is set as boot
+			 * device
+			 */
+			if( prv_bios_data->boot_drv & 0x80 ) {
+				adapter->boot_pdrv_enabled = 1;
+				boot_pdrv = prv_bios_data->boot_drv & 0x7F;
+				adapter->boot_pdrv_ch = boot_pdrv / 16;
+				adapter->boot_pdrv_tgt = boot_pdrv % 16;
+			}
+			else {
+				adapter->boot_ldrv_enabled = 1;
+				adapter->boot_ldrv = prv_bios_data->boot_drv;
+			}
+		}
+	}
+
+}
+
+/**
+ * mega_support_random_del()
+ * @adapter - pointer to our soft state
+ *
+ * Find out if this controller supports random deletion and addition of
+ * logical drives
+ */
+static int
+mega_support_random_del(adapter_t *adapter)
+{
+	unsigned char raw_mbox[sizeof(struct mbox_out)];
+	mbox_t *mbox;
+	int rval;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+
+	/*
+	 * issue command
+	 */
+	raw_mbox[0] = FC_DEL_LOGDRV;
+	raw_mbox[2] = OP_SUP_DEL_LOGDRV;
+
+	rval = issue_scb_block(adapter, raw_mbox);
+
+	return !rval;
+}
+
+
+/**
+ * mega_support_ext_cdb()
+ * @adapter - pointer to our soft state
+ *
+ * Find out if this firmware support cdblen > 10
+ */
+static int
+mega_support_ext_cdb(adapter_t *adapter)
+{
+	unsigned char raw_mbox[sizeof(struct mbox_out)];
+	mbox_t *mbox;
+	int rval;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+	/*
+	 * issue command to find out if controller supports extended CDBs.
+	 */
+	raw_mbox[0] = 0xA4;
+	raw_mbox[2] = 0x16;
+
+	rval = issue_scb_block(adapter, raw_mbox);
+
+	return !rval;
+}
+
+
+/**
+ * mega_del_logdrv()
+ * @adapter - pointer to our soft state
+ * @logdrv - logical drive to be deleted
+ *
+ * Delete the specified logical drive. It is the responsibility of the user
+ * app to let the OS know about this operation.
+ */
+static int
+mega_del_logdrv(adapter_t *adapter, int logdrv)
+{
+	unsigned long flags;
+	scb_t *scb;
+	int rval;
+
+	/*
+	 * Stop sending commands to the controller, queue them internally.
+	 * When deletion is complete, ISR will flush the queue.
+	 */
+	atomic_set(&adapter->quiescent, 1);
+
+	/*
+	 * Wait till all the issued commands are complete and there are no
+	 * commands in the pending queue
+	 */
+	while (atomic_read(&adapter->pend_cmds) > 0 ||
+	       !list_empty(&adapter->pending_list))
+		msleep(1000);	/* sleep for 1s */
+
+	rval = mega_do_del_logdrv(adapter, logdrv);
+
+	spin_lock_irqsave(&adapter->lock, flags);
+
+	/*
+	 * If delete operation was successful, add 0x80 to the logical drive
+	 * ids for commands in the pending queue.
+	 */
+	if (adapter->read_ldidmap) {
+		struct list_head *pos;
+		list_for_each(pos, &adapter->pending_list) {
+			scb = list_entry(pos, scb_t, list);
+			if (scb->pthru->logdrv < 0x80 )
+				scb->pthru->logdrv += 0x80;
+		}
+	}
+
+	atomic_set(&adapter->quiescent, 0);
+
+	mega_runpendq(adapter);
+
+	spin_unlock_irqrestore(&adapter->lock, flags);
+
+	return rval;
+}
+
+
+static int
+mega_do_del_logdrv(adapter_t *adapter, int logdrv)
+{
+	megacmd_t	mc;
+	int	rval;
+
+	memset( &mc, 0, sizeof(megacmd_t));
+
+	mc.cmd = FC_DEL_LOGDRV;
+	mc.opcode = OP_DEL_LOGDRV;
+	mc.subopcode = logdrv;
+
+	rval = mega_internal_command(adapter, LOCK_INT, &mc, NULL);
+
+	/* log this event */
+	if(rval) {
+		printk(KERN_WARNING "megaraid: Delete LD-%d failed.", logdrv);
+		return rval;
+	}
+
+	/*
+	 * After deleting first logical drive, the logical drives must be
+	 * addressed by adding 0x80 to the logical drive id.
+	 */
+	adapter->read_ldidmap = 1;
+
+	return rval;
+}
+
+
+/**
+ * mega_get_max_sgl()
+ * @adapter - pointer to our soft state
+ *
+ * Find out the maximum number of scatter-gather elements supported by this
+ * version of the firmware
+ */
+static void
+mega_get_max_sgl(adapter_t *adapter)
+{
+	unsigned char	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(mbox, 0, sizeof(raw_mbox));
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	raw_mbox[0] = MAIN_MISC_OPCODE;
+	raw_mbox[2] = GET_MAX_SG_SUPPORT;
+
+
+	if( issue_scb_block(adapter, raw_mbox) ) {
+		/*
+		 * f/w does not support this command. Choose the default value
+		 */
+		adapter->sglen = MIN_SGLIST;
+	}
+	else {
+		adapter->sglen = *((char *)adapter->mega_buffer);
+		
+		/*
+		 * Make sure this is not more than the resources we are
+		 * planning to allocate
+		 */
+		if ( adapter->sglen > MAX_SGLIST )
+			adapter->sglen = MAX_SGLIST;
+	}
+
+	return;
+}
+
+
+/**
+ * mega_support_cluster()
+ * @adapter - pointer to our soft state
+ *
+ * Find out if this firmware support cluster calls.
+ */
+static int
+mega_support_cluster(adapter_t *adapter)
+{
+	unsigned char	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset(mbox, 0, sizeof(raw_mbox));
+
+	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
+
+	mbox->m_out.xferaddr = (u32)adapter->buf_dma_handle;
+
+	/*
+	 * Try to get the initiator id. This command will succeed iff the
+	 * clustering is available on this HBA.
+	 */
+	raw_mbox[0] = MEGA_GET_TARGET_ID;
+
+	if( issue_scb_block(adapter, raw_mbox) == 0 ) {
+
+		/*
+		 * Cluster support available. Get the initiator target id.
+		 * Tell our id to mid-layer too.
+		 */
+		adapter->this_id = *(u32 *)adapter->mega_buffer;
+		adapter->host->this_id = adapter->this_id;
+
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * mega_adapinq()
+ * @adapter - pointer to our soft state
+ * @dma_handle - DMA address of the buffer
+ *
+ * Issue internal comamnds while interrupts are available.
+ * We only issue direct mailbox commands from within the driver. ioctl()
+ * interface using these routines can issue passthru commands.
+ */
+static int
+mega_adapinq(adapter_t *adapter, dma_addr_t dma_handle)
+{
+	megacmd_t	mc;
+
+	memset(&mc, 0, sizeof(megacmd_t));
+
+	if( adapter->flag & BOARD_40LD ) {
+		mc.cmd = FC_NEW_CONFIG;
+		mc.opcode = NC_SUBOP_ENQUIRY3;
+		mc.subopcode = ENQ3_GET_SOLICITED_FULL;
+	}
+	else {
+		mc.cmd = MEGA_MBOXCMD_ADPEXTINQ;
+	}
+
+	mc.xferaddr = (u32)dma_handle;
+
+	if ( mega_internal_command(adapter, LOCK_INT, &mc, NULL) != 0 ) {
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/** mega_internal_dev_inquiry()
+ * @adapter - pointer to our soft state
+ * @ch - channel for this device
+ * @tgt - ID of this device
+ * @buf_dma_handle - DMA address of the buffer
+ *
+ * Issue the scsi inquiry for the specified device.
+ */
+static int
+mega_internal_dev_inquiry(adapter_t *adapter, u8 ch, u8 tgt,
+		dma_addr_t buf_dma_handle)
+{
+	mega_passthru	*pthru;
+	dma_addr_t	pthru_dma_handle;
+	megacmd_t	mc;
+	int		rval;
+	struct pci_dev	*pdev;
+
+
+	/*
+	 * For all internal commands, the buffer must be allocated in <4GB
+	 * address range
+	 */
+	if( make_local_pdev(adapter, &pdev) != 0 ) return -1;
+
+	pthru = pci_alloc_consistent(pdev, sizeof(mega_passthru),
+			&pthru_dma_handle);
+
+	if( pthru == NULL ) {
+		free_local_pdev(pdev);
+		return -1;
+	}
+
+	pthru->timeout = 2;
+	pthru->ars = 1;
+	pthru->reqsenselen = 14;
+	pthru->islogical = 0;
+
+	pthru->channel = (adapter->flag & BOARD_40LD) ? 0 : ch;
+
+	pthru->target = (adapter->flag & BOARD_40LD) ? (ch << 4)|tgt : tgt;
+
+	pthru->cdblen = 6;
+
+	pthru->cdb[0] = INQUIRY;
+	pthru->cdb[1] = 0;
+	pthru->cdb[2] = 0;
+	pthru->cdb[3] = 0;
+	pthru->cdb[4] = 255;
+	pthru->cdb[5] = 0;
+
+
+	pthru->dataxferaddr = (u32)buf_dma_handle;
+	pthru->dataxferlen = 256;
+
+	memset(&mc, 0, sizeof(megacmd_t));
+
+	mc.cmd = MEGA_MBOXCMD_PASSTHRU;
+	mc.xferaddr = (u32)pthru_dma_handle;
+
+	rval = mega_internal_command(adapter, LOCK_INT, &mc, pthru);
+
+	pci_free_consistent(pdev, sizeof(mega_passthru), pthru,
+			pthru_dma_handle);
+
+	free_local_pdev(pdev);
+
+	return rval;
+}
+
+
+/**
+ * mega_internal_command()
+ * @adapter - pointer to our soft state
+ * @ls - the scope of the exclusion lock.
+ * @mc - the mailbox command
+ * @pthru - Passthru structure for DCDB commands
+ *
+ * Issue the internal commands in interrupt mode.
+ * The last argument is the address of the passthru structure if the command
+ * to be fired is a passthru command
+ *
+ * lockscope specifies whether the caller has already acquired the lock. Of
+ * course, the caller must know which lock we are talking about.
+ *
+ * Note: parameter 'pthru' is null for non-passthru commands.
+ */
+static int
+mega_internal_command(adapter_t *adapter, lockscope_t ls, megacmd_t *mc,
+		mega_passthru *pthru )
+{
+	Scsi_Cmnd	*scmd;
+	struct	scsi_device *sdev;
+	unsigned long	flags = 0;
+	scb_t	*scb;
+	int	rval;
+
+	/*
+	 * The internal commands share one command id and hence are
+	 * serialized. This is so because we want to reserve maximum number of
+	 * available command ids for the I/O commands.
+	 */
+	down(&adapter->int_mtx);
+
+	scb = &adapter->int_scb;
+	memset(scb, 0, sizeof(scb_t));
+
+	scmd = &adapter->int_scmd;
+	memset(scmd, 0, sizeof(Scsi_Cmnd));
+
+	sdev = kmalloc(sizeof(struct scsi_device), GFP_KERNEL);
+	memset(sdev, 0, sizeof(struct scsi_device));
+	scmd->device = sdev;
+
+	scmd->device->host = adapter->host;
+	scmd->buffer = (void *)scb;
+	scmd->cmnd[0] = MEGA_INTERNAL_CMD;
+
+	scb->state |= SCB_ACTIVE;
+	scb->cmd = scmd;
+
+	memcpy(scb->raw_mbox, mc, sizeof(megacmd_t));
+
+	/*
+	 * Is it a passthru command
+	 */
+	if( mc->cmd == MEGA_MBOXCMD_PASSTHRU ) {
+
+		scb->pthru = pthru;
+	}
+
+	scb->idx = CMDID_INT_CMDS;
+
+	scmd->state = 0;
+
+	/*
+	 * Get the lock only if the caller has not acquired it already
+	 */
+	if( ls == LOCK_INT ) spin_lock_irqsave(&adapter->lock, flags);
+
+	megaraid_queue(scmd, mega_internal_done);
+
+	if( ls == LOCK_INT ) spin_unlock_irqrestore(&adapter->lock, flags);
+
+	/*
+	 * Wait till this command finishes. Do not use
+	 * wait_event_interruptible(). It causes panic if CTRL-C is hit when
+	 * dumping e.g., physical disk information through /proc interface.
+	 */
+#if 0
+	wait_event_interruptible(adapter->int_waitq, scmd->state);
+#endif
+	wait_event(adapter->int_waitq, scmd->state);
+
+	rval = scmd->result;
+	mc->status = scmd->result;
+	kfree(sdev);
+
+	/*
+	 * Print a debug message for all failed commands. Applications can use
+	 * this information.
+	 */
+	if( scmd->result && trace_level ) {
+		printk("megaraid: cmd [%x, %x, %x] status:[%x]\n",
+			mc->cmd, mc->opcode, mc->subopcode, scmd->result);
+	}
+
+	up(&adapter->int_mtx);
+
+	return rval;
+}
+
+
+/**
+ * mega_internal_done()
+ * @scmd - internal scsi command
+ *
+ * Callback routine for internal commands.
+ */
+static void
+mega_internal_done(Scsi_Cmnd *scmd)
+{
+	adapter_t	*adapter;
+
+	adapter = (adapter_t *)scmd->device->host->hostdata;
+
+	scmd->state = 1; /* thread waiting for its command to complete */
+
+	/*
+	 * See comment in mega_internal_command() routine for
+	 * wait_event_interruptible()
+	 */
+#if 0
+	wake_up_interruptible(&adapter->int_waitq);
+#endif
+	wake_up(&adapter->int_waitq);
+
+}
+
+
+static struct scsi_host_template megaraid_template = {
+	.module				= THIS_MODULE,
+	.name				= "MegaRAID",
+	.proc_name			= "megaraid",
+	.info				= megaraid_info,
+	.queuecommand			= megaraid_queue,	
+	.bios_param			= megaraid_biosparam,
+	.max_sectors			= MAX_SECTORS_PER_IO,
+	.can_queue			= MAX_COMMANDS,
+	.this_id			= DEFAULT_INITIATOR_ID,
+	.sg_tablesize			= MAX_SGLIST,
+	.cmd_per_lun			= DEF_CMD_PER_LUN,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.eh_abort_handler		= megaraid_abort,
+	.eh_device_reset_handler	= megaraid_reset,
+	.eh_bus_reset_handler		= megaraid_reset,
+	.eh_host_reset_handler		= megaraid_reset,
+};
+
+static int __devinit
+megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct Scsi_Host *host;
+	adapter_t *adapter;
+	unsigned long mega_baseport, tbase, flag = 0;
+	u16 subsysid, subsysvid;
+	u8 pci_bus, pci_dev_func;
+	int irq, i, j;
+	int error = -ENODEV;
+
+	if (pci_enable_device(pdev))
+		goto out;
+	pci_set_master(pdev);
+
+	pci_bus = pdev->bus->number;
+	pci_dev_func = pdev->devfn;
+
+	/*
+	 * The megaraid3 stuff reports the ID of the Intel part which is not
+	 * remotely specific to the megaraid
+	 */
+	if (pdev->vendor == PCI_VENDOR_ID_INTEL) {
+		u16 magic;
+		/*
+		 * Don't fall over the Compaq management cards using the same
+		 * PCI identifier
+		 */
+		if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ &&
+		    pdev->subsystem_device == 0xC000)
+		   	return -ENODEV;
+		/* Now check the magic signature byte */
+		pci_read_config_word(pdev, PCI_CONF_AMISIG, &magic);
+		if (magic != HBA_SIGNATURE_471 && magic != HBA_SIGNATURE)
+			return -ENODEV;
+		/* Ok it is probably a megaraid */
+	}
+
+	/*
+	 * For these vendor and device ids, signature offsets are not
+	 * valid and 64 bit is implicit
+	 */
+	if (id->driver_data & BOARD_64BIT)
+		flag |= BOARD_64BIT;
+	else {
+		u32 magic64;
+
+		pci_read_config_dword(pdev, PCI_CONF_AMISIG64, &magic64);
+		if (magic64 == HBA_SIGNATURE_64BIT)
+			flag |= BOARD_64BIT;
+	}
+
+	subsysvid = pdev->subsystem_vendor;
+	subsysid = pdev->subsystem_device;
+
+	printk(KERN_NOTICE "megaraid: found 0x%4.04x:0x%4.04x:bus %d:",
+		id->vendor, id->device, pci_bus);
+
+	printk("slot %d:func %d\n",
+		PCI_SLOT(pci_dev_func), PCI_FUNC(pci_dev_func));
+
+	/* Read the base port and IRQ from PCI */
+	mega_baseport = pci_resource_start(pdev, 0);
+	irq = pdev->irq;
+
+	tbase = mega_baseport;
+	if (pci_resource_flags(pdev, 0) & IORESOURCE_MEM) {
+		flag |= BOARD_MEMMAP;
+
+		if (!request_mem_region(mega_baseport, 128, "megaraid")) {
+			printk(KERN_WARNING "megaraid: mem region busy!\n");
+			goto out_disable_device;
+		}
+
+		mega_baseport = (unsigned long)ioremap(mega_baseport, 128);
+		if (!mega_baseport) {
+			printk(KERN_WARNING
+			       "megaraid: could not map hba memory\n");
+			goto out_release_region;
+		}
+	} else {
+		flag |= BOARD_IOMAP;
+		mega_baseport += 0x10;
+
+		if (!request_region(mega_baseport, 16, "megaraid"))
+			goto out_disable_device;
+	}
+
+	/* Initialize SCSI Host structure */
+	host = scsi_host_alloc(&megaraid_template, sizeof(adapter_t));
+	if (!host)
+		goto out_iounmap;
+
+	adapter = (adapter_t *)host->hostdata;
+	memset(adapter, 0, sizeof(adapter_t));
+
+	printk(KERN_NOTICE
+		"scsi%d:Found MegaRAID controller at 0x%lx, IRQ:%d\n",
+		host->host_no, mega_baseport, irq);
+
+	adapter->base = mega_baseport;
+
+	INIT_LIST_HEAD(&adapter->free_list);
+	INIT_LIST_HEAD(&adapter->pending_list);
+	INIT_LIST_HEAD(&adapter->completed_list);
+
+	adapter->flag = flag;
+	spin_lock_init(&adapter->lock);
+	scsi_assign_lock(host, &adapter->lock);
+
+	host->cmd_per_lun = max_cmd_per_lun;
+	host->max_sectors = max_sectors_per_io;
+
+	adapter->dev = pdev;
+	adapter->host = host;
+
+	adapter->host->irq = irq;
+
+	if (flag & BOARD_MEMMAP)
+		adapter->host->base = tbase;
+	else {
+		adapter->host->io_port = tbase;
+		adapter->host->n_io_port = 16;
+	}
+
+	adapter->host->unique_id = (pci_bus << 8) | pci_dev_func;
+
+	/*
+	 * Allocate buffer to issue internal commands.
+	 */
+	adapter->mega_buffer = pci_alloc_consistent(adapter->dev,
+		MEGA_BUFFER_SIZE, &adapter->buf_dma_handle);
+	if (!adapter->mega_buffer) {
+		printk(KERN_WARNING "megaraid: out of RAM.\n");
+		goto out_host_put;
+	}
+
+	adapter->scb_list = kmalloc(sizeof(scb_t) * MAX_COMMANDS, GFP_KERNEL);
+	if (!adapter->scb_list) {
+		printk(KERN_WARNING "megaraid: out of RAM.\n");
+		goto out_free_cmd_buffer;
+	}
+
+	if (request_irq(irq, (adapter->flag & BOARD_MEMMAP) ?
+				megaraid_isr_memmapped : megaraid_isr_iomapped,
+					SA_SHIRQ, "megaraid", adapter)) {
+		printk(KERN_WARNING
+			"megaraid: Couldn't register IRQ %d!\n", irq);
+		goto out_free_scb_list;
+	}
+
+	if (mega_setup_mailbox(adapter))
+		goto out_free_irq;
+
+	if (mega_query_adapter(adapter))
+		goto out_free_mbox;
+
+	/*
+	 * Have checks for some buggy f/w
+	 */
+	if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
+		/*
+		 * Which firmware
+		 */
+		if (!strcmp(adapter->fw_version, "3.00") ||
+				!strcmp(adapter->fw_version, "3.01")) {
+
+			printk( KERN_WARNING
+				"megaraid: Your  card is a Dell PERC "
+				"2/SC RAID controller with  "
+				"firmware\nmegaraid: 3.00 or 3.01.  "
+				"This driver is known to have "
+				"corruption issues\nmegaraid: with "
+				"those firmware versions on this "
+				"specific card.  In order\nmegaraid: "
+				"to protect your data, please upgrade "
+				"your firmware to version\nmegaraid: "
+				"3.10 or later, available from the "
+				"Dell Technical Support web\n"
+				"megaraid: site at\nhttp://support."
+				"dell.com/us/en/filelib/download/"
+				"index.asp?fileid=2940\n"
+			);
+		}
+	}
+
+	/*
+	 * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
+	 * firmware H.01.07, H.01.08, and H.01.09 disable 64 bit
+	 * support, since this firmware cannot handle 64 bit
+	 * addressing
+	 */
+	if ((subsysvid == HP_SUBSYS_VID) &&
+	    ((subsysid == 0x60E7) || (subsysid == 0x60E8))) {
+		/*
+		 * which firmware
+		 */
+		if (!strcmp(adapter->fw_version, "H01.07") ||
+		    !strcmp(adapter->fw_version, "H01.08") ||
+		    !strcmp(adapter->fw_version, "H01.09") ) {
+			printk(KERN_WARNING
+				"megaraid: Firmware H.01.07, "
+				"H.01.08, and H.01.09 on 1M/2M "
+				"controllers\n"
+				"megaraid: do not support 64 bit "
+				"addressing.\nmegaraid: DISABLING "
+				"64 bit support.\n");
+			adapter->flag &= ~BOARD_64BIT;
+		}
+	}
+
+	if (mega_is_bios_enabled(adapter))
+		mega_hbas[hba_count].is_bios_enabled = 1;
+	mega_hbas[hba_count].hostdata_addr = adapter;
+
+	/*
+	 * Find out which channel is raid and which is scsi. This is
+	 * for ROMB support.
+	 */
+	mega_enum_raid_scsi(adapter);
+
+	/*
+	 * Find out if a logical drive is set as the boot drive. If
+	 * there is one, will make that as the first logical drive.
+	 * ROMB: Do we have to boot from a physical drive. Then all
+	 * the physical drives would appear before the logical disks.
+	 * Else, all the physical drives would be exported to the mid
+	 * layer after logical drives.
+	 */
+	mega_get_boot_drv(adapter);
+
+	if (adapter->boot_pdrv_enabled) {
+		j = adapter->product_info.nchannels;
+		for( i = 0; i < j; i++ )
+			adapter->logdrv_chan[i] = 0;
+		for( i = j; i < NVIRT_CHAN + j; i++ )
+			adapter->logdrv_chan[i] = 1;
+	} else {
+		for (i = 0; i < NVIRT_CHAN; i++)
+			adapter->logdrv_chan[i] = 1;
+		for (i = NVIRT_CHAN; i < MAX_CHANNELS+NVIRT_CHAN; i++)
+			adapter->logdrv_chan[i] = 0;
+		adapter->mega_ch_class <<= NVIRT_CHAN;
+	}
+
+	/*
+	 * Do we support random deletion and addition of logical
+	 * drives
+	 */
+	adapter->read_ldidmap = 0;	/* set it after first logdrv
+						   delete cmd */
+	adapter->support_random_del = mega_support_random_del(adapter);
+
+	/* Initialize SCBs */
+	if (mega_init_scb(adapter))
+		goto out_free_mbox;
+
+	/*
+	 * Reset the pending commands counter
+	 */
+	atomic_set(&adapter->pend_cmds, 0);
+
+	/*
+	 * Reset the adapter quiescent flag
+	 */
+	atomic_set(&adapter->quiescent, 0);
+
+	hba_soft_state[hba_count] = adapter;
+
+	/*
+	 * Fill in the structure which needs to be passed back to the
+	 * application when it does an ioctl() for controller related
+	 * information.
+	 */
+	i = hba_count;
+
+	mcontroller[i].base = mega_baseport;
+	mcontroller[i].irq = irq;
+	mcontroller[i].numldrv = adapter->numldrv;
+	mcontroller[i].pcibus = pci_bus;
+	mcontroller[i].pcidev = id->device;
+	mcontroller[i].pcifun = PCI_FUNC (pci_dev_func);
+	mcontroller[i].pciid = -1;
+	mcontroller[i].pcivendor = id->vendor;
+	mcontroller[i].pcislot = PCI_SLOT(pci_dev_func);
+	mcontroller[i].uid = (pci_bus << 8) | pci_dev_func;
+
+
+	/* Set the Mode of addressing to 64 bit if we can */
+	if ((adapter->flag & BOARD_64BIT) && (sizeof(dma_addr_t) == 8)) {
+		pci_set_dma_mask(pdev, 0xffffffffffffffffULL);
+		adapter->has_64bit_addr = 1;
+	} else  {
+		pci_set_dma_mask(pdev, 0xffffffff);
+		adapter->has_64bit_addr = 0;
+	}
+		
+	init_MUTEX(&adapter->int_mtx);
+	init_waitqueue_head(&adapter->int_waitq);
+
+	adapter->this_id = DEFAULT_INITIATOR_ID;
+	adapter->host->this_id = DEFAULT_INITIATOR_ID;
+
+#if MEGA_HAVE_CLUSTERING
+	/*
+	 * Is cluster support enabled on this controller
+	 * Note: In a cluster the HBAs ( the initiators ) will have
+	 * different target IDs and we cannot assume it to be 7. Call
+	 * to mega_support_cluster() will get the target ids also if
+	 * the cluster support is available
+	 */
+	adapter->has_cluster = mega_support_cluster(adapter);
+	if (adapter->has_cluster) {
+		printk(KERN_NOTICE
+			"megaraid: Cluster driver, initiator id:%d\n",
+			adapter->this_id);
+	}
+#endif
+
+	pci_set_drvdata(pdev, host);
+
+	mega_create_proc_entry(hba_count, mega_proc_dir_entry);
+
+	error = scsi_add_host(host, &pdev->dev);
+	if (error)
+		goto out_free_mbox;
+
+	scsi_scan_host(host);
+	hba_count++;
+	return 0;
+
+ out_free_mbox:
+	pci_free_consistent(adapter->dev, sizeof(mbox64_t),
+			adapter->una_mbox64, adapter->una_mbox64_dma);
+ out_free_irq:
+	free_irq(adapter->host->irq, adapter);
+ out_free_scb_list:
+	kfree(adapter->scb_list);
+ out_free_cmd_buffer:
+	pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
+			adapter->mega_buffer, adapter->buf_dma_handle);
+ out_host_put:
+	scsi_host_put(host);
+ out_iounmap:
+	if (flag & BOARD_MEMMAP)
+		iounmap((void *)mega_baseport);
+ out_release_region:
+	if (flag & BOARD_MEMMAP)
+		release_mem_region(tbase, 128);
+	else
+		release_region(mega_baseport, 16);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+static void
+__megaraid_shutdown(adapter_t *adapter)
+{
+	u_char	raw_mbox[sizeof(struct mbox_out)];
+	mbox_t	*mbox = (mbox_t *)raw_mbox;
+	int	i;
+
+	/* Flush adapter cache */
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+	raw_mbox[0] = FLUSH_ADAPTER;
+
+	free_irq(adapter->host->irq, adapter);
+
+	/* Issue a blocking (interrupts disabled) command to the card */
+	issue_scb_block(adapter, raw_mbox);
+
+	/* Flush disks cache */
+	memset(&mbox->m_out, 0, sizeof(raw_mbox));
+	raw_mbox[0] = FLUSH_SYSTEM;
+
+	/* Issue a blocking (interrupts disabled) command to the card */
+	issue_scb_block(adapter, raw_mbox);
+	
+	if (atomic_read(&adapter->pend_cmds) > 0)
+		printk(KERN_WARNING "megaraid: pending commands!!\n");
+
+	/*
+	 * Have a delibrate delay to make sure all the caches are
+	 * actually flushed.
+	 */
+	for (i = 0; i <= 10; i++)
+		mdelay(1000);
+}
+
+static void
+megaraid_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	adapter_t *adapter = (adapter_t *)host->hostdata;
+	char	buf[12] = { 0 };
+
+	scsi_remove_host(host);
+
+	__megaraid_shutdown(adapter);
+
+	/* Free our resources */
+	if (adapter->flag & BOARD_MEMMAP) {
+		iounmap((void *)adapter->base);
+		release_mem_region(adapter->host->base, 128);
+	} else
+		release_region(adapter->base, 16);
+
+	mega_free_sgl(adapter);
+
+#ifdef CONFIG_PROC_FS
+	if (adapter->controller_proc_dir_entry) {
+		remove_proc_entry("stat", adapter->controller_proc_dir_entry);
+		remove_proc_entry("config",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("mailbox",
+				adapter->controller_proc_dir_entry);
+#if MEGA_HAVE_ENH_PROC
+		remove_proc_entry("rebuild-rate",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("battery-status",
+				adapter->controller_proc_dir_entry);
+
+		remove_proc_entry("diskdrives-ch0",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("diskdrives-ch1",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("diskdrives-ch2",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("diskdrives-ch3",
+				adapter->controller_proc_dir_entry);
+
+		remove_proc_entry("raiddrives-0-9",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("raiddrives-10-19",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("raiddrives-20-29",
+				adapter->controller_proc_dir_entry);
+		remove_proc_entry("raiddrives-30-39",
+				adapter->controller_proc_dir_entry);
+#endif
+		sprintf(buf, "hba%d", adapter->host->host_no);
+		remove_proc_entry(buf, mega_proc_dir_entry);
+	}
+#endif
+
+	pci_free_consistent(adapter->dev, MEGA_BUFFER_SIZE,
+			adapter->mega_buffer, adapter->buf_dma_handle);
+	kfree(adapter->scb_list);
+	pci_free_consistent(adapter->dev, sizeof(mbox64_t),
+			adapter->una_mbox64, adapter->una_mbox64_dma);
+
+	scsi_host_put(host);
+	pci_disable_device(pdev);
+
+	hba_count--;
+}
+
+static void
+megaraid_shutdown(struct device *dev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(to_pci_dev(dev));
+	adapter_t *adapter = (adapter_t *)host->hostdata;
+
+	__megaraid_shutdown(adapter);
+}
+
+static struct pci_device_id megaraid_pci_tbl[] = {
+	{PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_DISCOVERY,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_DELL, PCI_DEVICE_ID_PERC4_DI,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, BOARD_64BIT},
+	{PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_PERC4_QC_VERDE,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, BOARD_64BIT},
+	{PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_AMI, PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, megaraid_pci_tbl);
+
+static struct pci_driver megaraid_pci_driver = {
+	.name		= "megaraid",
+	.id_table	= megaraid_pci_tbl,
+	.probe		= megaraid_probe_one,
+	.remove		= __devexit_p(megaraid_remove_one),
+	.driver		= {
+		.shutdown = megaraid_shutdown,
+	},
+};
+
+static int __init megaraid_init(void)
+{
+	int error;
+
+	if ((max_cmd_per_lun <= 0) || (max_cmd_per_lun > MAX_CMD_PER_LUN))
+		max_cmd_per_lun = MAX_CMD_PER_LUN;
+	if (max_mbox_busy_wait > MBOX_BUSY_WAIT)
+		max_mbox_busy_wait = MBOX_BUSY_WAIT;
+
+#ifdef CONFIG_PROC_FS
+	mega_proc_dir_entry = proc_mkdir("megaraid", &proc_root);
+	if (!mega_proc_dir_entry) {
+		printk(KERN_WARNING
+				"megaraid: failed to create megaraid root\n");
+	}
+#endif
+	error = pci_module_init(&megaraid_pci_driver);
+	if (error) {
+#ifdef CONFIG_PROC_FS
+		remove_proc_entry("megaraid", &proc_root);
+#endif
+		return error;
+	}
+
+	/*
+	 * Register the driver as a character device, for applications
+	 * to access it for ioctls.
+	 * First argument (major) to register_chrdev implies a dynamic
+	 * major number allocation.
+	 */
+	major = register_chrdev(0, "megadev", &megadev_fops);
+	if (!major) {
+		printk(KERN_WARNING
+				"megaraid: failed to register char device\n");
+	}
+
+	return 0;
+}
+
+static void __exit megaraid_exit(void)
+{
+	/*
+	 * Unregister the character device interface to the driver.
+	 */
+	unregister_chrdev(major, "megadev");
+
+	pci_unregister_driver(&megaraid_pci_driver);
+
+#ifdef CONFIG_PROC_FS
+	remove_proc_entry("megaraid", &proc_root);
+#endif
+}
+
+module_init(megaraid_init);
+module_exit(megaraid_exit);
+
+/* vi: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
new file mode 100644
index 0000000..e25c4de
--- /dev/null
+++ b/drivers/scsi/megaraid.h
@@ -0,0 +1,1071 @@
+#ifndef __MEGARAID_H__
+#define __MEGARAID_H__
+
+#include <linux/spinlock.h>
+
+
+#define MEGARAID_VERSION	\
+	"v2.00.3 (Release Date: Wed Feb 19 08:51:30 EST 2003)\n"
+
+/*
+ * Driver features - change the values to enable or disable features in the
+ * driver.
+ */
+
+/*
+ * Comand coalescing - This feature allows the driver to be able to combine
+ * two or more commands and issue as one command in order to boost I/O
+ * performance. Useful if the nature of the I/O is sequential. It is not very
+ * useful for random natured I/Os.
+ */
+#define MEGA_HAVE_COALESCING	0
+
+/*
+ * Clustering support - Set this flag if you are planning to use the
+ * clustering services provided by the megaraid controllers and planning to
+ * setup a cluster
+ */
+#define MEGA_HAVE_CLUSTERING	1
+
+/*
+ * Driver statistics - Set this flag if you are interested in statics about
+ * number of I/O completed on each logical drive and how many interrupts
+ * generated. If enabled, this information is available through /proc
+ * interface and through the private ioctl. Setting this flag has a
+ * performance penalty.
+ */
+#define MEGA_HAVE_STATS		0
+
+/*
+ * Enhanced /proc interface - This feature will allow you to have a more
+ * detailed /proc interface for megaraid driver. E.g., a real time update of
+ * the status of the logical drives, battery status, physical drives etc.
+ */
+#define MEGA_HAVE_ENH_PROC	1
+
+#define MAX_DEV_TYPE	32
+
+#ifndef PCI_VENDOR_ID_LSI_LOGIC
+#define PCI_VENDOR_ID_LSI_LOGIC		0x1000
+#endif
+
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI		0x101E
+#endif
+
+#ifndef PCI_VENDOR_ID_DELL
+#define PCI_VENDOR_ID_DELL		0x1028
+#endif
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL		0x8086
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID
+#define PCI_DEVICE_ID_AMI_MEGARAID	0x9010
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID2
+#define PCI_DEVICE_ID_AMI_MEGARAID2	0x9060
+#endif
+
+#ifndef PCI_DEVICE_ID_AMI_MEGARAID3
+#define PCI_DEVICE_ID_AMI_MEGARAID3	0x1960
+#endif
+
+#define PCI_DEVICE_ID_DISCOVERY		0x000E
+#define PCI_DEVICE_ID_PERC4_DI		0x000F
+#define PCI_DEVICE_ID_PERC4_QC_VERDE	0x0407
+
+/* Sub-System Vendor IDs */
+#define	AMI_SUBSYS_VID			0x101E
+#define DELL_SUBSYS_VID			0x1028
+#define	HP_SUBSYS_VID			0x103C
+#define LSI_SUBSYS_VID			0x1000
+#define INTEL_SUBSYS_VID		0x8086
+
+#define HBA_SIGNATURE	      		0x3344
+#define HBA_SIGNATURE_471	  	0xCCCC
+#define HBA_SIGNATURE_64BIT		0x0299
+
+#define MBOX_BUSY_WAIT			10	/* wait for up to 10 usec for
+						   mailbox to be free */
+#define DEFAULT_INITIATOR_ID	7
+
+#define MAX_SGLIST		64	/* max supported in f/w */
+#define MIN_SGLIST		26	/* guaranteed to support these many */
+#define MAX_COMMANDS		126
+#define CMDID_INT_CMDS		MAX_COMMANDS+1	/* make sure CMDID_INT_CMDS
+					 	is less than max commands
+						supported by any f/w */
+
+#define MAX_CDB_LEN	     	10
+#define MAX_EXT_CDB_LEN		16	/* we support cdb length up to 16 */
+
+#define DEF_CMD_PER_LUN		63
+#define MAX_CMD_PER_LUN		MAX_COMMANDS
+#define MAX_FIRMWARE_STATUS	46
+#define MAX_XFER_PER_CMD	(64*1024)
+#define MAX_SECTORS_PER_IO	128
+
+#define MAX_LOGICAL_DRIVES_40LD		40
+#define FC_MAX_PHYSICAL_DEVICES		256
+#define MAX_LOGICAL_DRIVES_8LD		8
+#define MAX_CHANNELS			5
+#define MAX_TARGET			15
+#define MAX_PHYSICAL_DRIVES		MAX_CHANNELS*MAX_TARGET
+#define MAX_ROW_SIZE_40LD		32
+#define MAX_ROW_SIZE_8LD		8
+#define MAX_SPAN_DEPTH			8
+
+#define NVIRT_CHAN		4	/* # of virtual channels to represent
+					   up to 60 logical drives */
+struct mbox_out {
+	/* 0x0 */ u8 cmd;
+	/* 0x1 */ u8 cmdid;
+	/* 0x2 */ u16 numsectors;
+	/* 0x4 */ u32 lba;
+	/* 0x8 */ u32 xferaddr;
+	/* 0xC */ u8 logdrv;
+	/* 0xD */ u8 numsgelements;
+	/* 0xE */ u8 resvd;
+} __attribute__ ((packed));
+
+struct mbox_in {
+	/* 0xF */ volatile u8 busy;
+	/* 0x10 */ volatile u8 numstatus;
+	/* 0x11 */ volatile u8 status;
+	/* 0x12 */ volatile u8 completed[MAX_FIRMWARE_STATUS];
+	volatile u8 poll;
+	volatile u8 ack;
+} __attribute__ ((packed));
+
+typedef struct {
+	struct mbox_out	m_out;
+	struct mbox_in	m_in;
+} __attribute__ ((packed)) mbox_t;
+
+typedef struct {
+	u32 xfer_segment_lo;
+	u32 xfer_segment_hi;
+	mbox_t mbox;
+} __attribute__ ((packed)) mbox64_t;
+
+
+/*
+ * Passthru definitions
+ */
+#define MAX_REQ_SENSE_LEN       0x20
+
+typedef struct {
+	u8 timeout:3;		/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	u8 ars:1;
+	u8 reserved:3;
+	u8 islogical:1;
+	u8 logdrv;		/* if islogical == 1 */
+	u8 channel;		/* if islogical == 0 */
+	u8 target;		/* if islogical == 0 */
+	u8 queuetag;		/* unused */
+	u8 queueaction;		/* unused */
+	u8 cdb[MAX_CDB_LEN];
+	u8 cdblen;
+	u8 reqsenselen;
+	u8 reqsensearea[MAX_REQ_SENSE_LEN];
+	u8 numsgelements;
+	u8 scsistatus;
+	u32 dataxferaddr;
+	u32 dataxferlen;
+} __attribute__ ((packed)) mega_passthru;
+
+
+/*
+ * Extended passthru: support CDB > 10 bytes
+ */
+typedef struct {
+	u8 timeout:3;		/* 0=6sec/1=60sec/2=10min/3=3hrs */
+	u8 ars:1;
+	u8 rsvd1:1;
+	u8 cd_rom:1;
+	u8 rsvd2:1;
+	u8 islogical:1;
+	u8 logdrv;		/* if islogical == 1 */
+	u8 channel;		/* if islogical == 0 */
+	u8 target;		/* if islogical == 0 */
+	u8 queuetag;		/* unused */
+	u8 queueaction;		/* unused */
+	u8 cdblen;
+	u8 rsvd3;
+	u8 cdb[MAX_EXT_CDB_LEN];
+	u8 numsgelements;
+	u8 status;
+	u8 reqsenselen;
+	u8 reqsensearea[MAX_REQ_SENSE_LEN];
+	u8 rsvd4;
+	u32 dataxferaddr;
+	u32 dataxferlen;
+} __attribute__ ((packed)) mega_ext_passthru;
+
+typedef struct {
+	u64 address;
+	u32 length;
+} __attribute__ ((packed)) mega_sgl64;
+
+typedef struct {
+	u32 address;
+	u32 length;
+} __attribute__ ((packed)) mega_sglist;
+
+
+/* Queued command data */
+typedef struct {
+	int	idx;
+	u32	state;
+	struct list_head	list;
+	u8	raw_mbox[66];
+	u32	dma_type;
+	u32	dma_direction;
+
+	Scsi_Cmnd	*cmd;
+	dma_addr_t	dma_h_bulkdata;
+	dma_addr_t	dma_h_sgdata;
+
+	mega_sglist	*sgl;
+	mega_sgl64	*sgl64;
+	dma_addr_t	sgl_dma_addr;
+
+	mega_passthru		*pthru;
+	dma_addr_t		pthru_dma_addr;
+	mega_ext_passthru	*epthru;
+	dma_addr_t		epthru_dma_addr;
+} scb_t;
+
+/*
+ * Flags to follow the scb as it transitions between various stages
+ */
+#define SCB_FREE	0x0000	/* on the free list */
+#define SCB_ACTIVE	0x0001	/* off the free list */
+#define SCB_PENDQ	0x0002	/* on the pending queue */
+#define SCB_ISSUED	0x0004	/* issued - owner f/w */
+#define SCB_ABORT	0x0008	/* Got an abort for this one */
+#define SCB_RESET	0x0010	/* Got a reset for this one */
+
+/*
+ * Utilities declare this strcture size as 1024 bytes. So more fields can
+ * be added in future.
+ */
+typedef struct {
+	u32	data_size; /* current size in bytes (not including resvd) */
+
+	u32	config_signature;
+		/* Current value is 0x00282008
+		 * 0x28=MAX_LOGICAL_DRIVES,
+		 * 0x20=Number of stripes and
+		 * 0x08=Number of spans */
+
+	u8	fw_version[16];		/* printable ASCI string */
+	u8	bios_version[16];	/* printable ASCI string */
+	u8	product_name[80];	/* printable ASCI string */
+
+	u8	max_commands;		/* Max. concurrent commands supported */
+	u8	nchannels;		/* Number of SCSI Channels detected */
+	u8	fc_loop_present;	/* Number of Fibre Loops detected */
+	u8	mem_type;		/* EDO, FPM, SDRAM etc */
+
+	u32	signature;
+	u16	dram_size;		/* In terms of MB */
+	u16	subsysid;
+
+	u16	subsysvid;
+	u8	notify_counters;
+	u8	pad1k[889];		/* 135 + 889 resvd = 1024 total size */
+} __attribute__ ((packed)) mega_product_info;
+
+struct notify {
+	u32 global_counter;	/* Any change increments this counter */
+
+	u8 param_counter;	/* Indicates any params changed  */
+	u8 param_id;		/* Param modified - defined below */
+	u16 param_val;		/* New val of last param modified */
+
+	u8 write_config_counter;	/* write config occurred */
+	u8 write_config_rsvd[3];
+
+	u8 ldrv_op_counter;	/* Indicates ldrv op started/completed */
+	u8 ldrv_opid;		/* ldrv num */
+	u8 ldrv_opcmd;		/* ldrv operation - defined below */
+	u8 ldrv_opstatus;	/* status of the operation */
+
+	u8 ldrv_state_counter;	/* Indicates change of ldrv state */
+	u8 ldrv_state_id;		/* ldrv num */
+	u8 ldrv_state_new;	/* New state */
+	u8 ldrv_state_old;	/* old state */
+
+	u8 pdrv_state_counter;	/* Indicates change of ldrv state */
+	u8 pdrv_state_id;		/* pdrv id */
+	u8 pdrv_state_new;	/* New state */
+	u8 pdrv_state_old;	/* old state */
+
+	u8 pdrv_fmt_counter;	/* Indicates pdrv format started/over */
+	u8 pdrv_fmt_id;		/* pdrv id */
+	u8 pdrv_fmt_val;		/* format started/over */
+	u8 pdrv_fmt_rsvd;
+
+	u8 targ_xfer_counter;	/* Indicates SCSI-2 Xfer rate change */
+	u8 targ_xfer_id;	/* pdrv Id  */
+	u8 targ_xfer_val;		/* new Xfer params of last pdrv */
+	u8 targ_xfer_rsvd;
+
+	u8 fcloop_id_chg_counter;	/* Indicates loopid changed */
+	u8 fcloopid_pdrvid;		/* pdrv id */
+	u8 fcloop_id0;			/* loopid on fc loop 0 */
+	u8 fcloop_id1;			/* loopid on fc loop 1 */
+
+	u8 fcloop_state_counter;	/* Indicates loop state changed */
+	u8 fcloop_state0;		/* state of fc loop 0 */
+	u8 fcloop_state1;		/* state of fc loop 1 */
+	u8 fcloop_state_rsvd;
+} __attribute__ ((packed));
+
+#define MAX_NOTIFY_SIZE     0x80
+#define CUR_NOTIFY_SIZE     sizeof(struct notify)
+
+typedef struct {
+	u32	data_size; /* current size in bytes (not including resvd) */
+
+	struct notify notify;
+
+	u8	notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
+
+	u8	rebuild_rate;		/* Rebuild rate (0% - 100%) */
+	u8	cache_flush_interval;	/* In terms of Seconds */
+	u8	sense_alert;
+	u8	drive_insert_count;	/* drive insertion count */
+
+	u8	battery_status;
+	u8	num_ldrv;		/* No. of Log Drives configured */
+	u8	recon_state[MAX_LOGICAL_DRIVES_40LD / 8];	/* State of
+							   reconstruct */
+	u16	ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8]; /* logdrv
+								 Status */
+
+	u32	ldrv_size[MAX_LOGICAL_DRIVES_40LD];/* Size of each log drv */
+	u8	ldrv_prop[MAX_LOGICAL_DRIVES_40LD];
+	u8	ldrv_state[MAX_LOGICAL_DRIVES_40LD];/* State of log drives */
+	u8	pdrv_state[FC_MAX_PHYSICAL_DEVICES];/* State of phys drvs. */
+	u16	pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16];
+
+	u8	targ_xfer[80];	/* phys device transfer rate */
+	u8	pad1k[263];	/* 761 + 263reserved = 1024 bytes total size */
+} __attribute__ ((packed)) mega_inquiry3;
+
+
+/* Structures */
+typedef struct {
+	u8	max_commands;	/* Max concurrent commands supported */
+	u8	rebuild_rate;	/* Rebuild rate - 0% thru 100% */
+	u8	max_targ_per_chan;	/* Max targ per channel */
+	u8	nchannels;	/* Number of channels on HBA */
+	u8	fw_version[4];	/* Firmware version */
+	u16	age_of_flash;	/* Number of times FW has been flashed */
+	u8	chip_set_value;	/* Contents of 0xC0000832 */
+	u8	dram_size;	/* In MB */
+	u8	cache_flush_interval;	/* in seconds */
+	u8	bios_version[4];
+	u8	board_type;
+	u8	sense_alert;
+	u8	write_config_count;	/* Increase with every configuration
+					   change */
+	u8	drive_inserted_count;	/* Increase with every drive inserted
+					 */
+	u8	inserted_drive;	/* Channel:Id of inserted drive */
+	u8	battery_status;	/*
+				 * BIT 0: battery module missing
+				 * BIT 1: VBAD
+				 * BIT 2: temprature high
+				 * BIT 3: battery pack missing
+				 * BIT 4,5:
+				 *   00 - charge complete
+				 *   01 - fast charge in progress
+				 *   10 - fast charge fail
+				 *   11 - undefined
+				 * Bit 6: counter > 1000
+				 * Bit 7: Undefined
+				 */
+	u8	dec_fault_bus_info;
+} __attribute__ ((packed)) mega_adp_info;
+
+
+typedef struct {
+	u8	num_ldrv;	/* Number of logical drives configured */
+	u8	rsvd[3];
+	u32	ldrv_size[MAX_LOGICAL_DRIVES_8LD];
+	u8	ldrv_prop[MAX_LOGICAL_DRIVES_8LD];
+	u8	ldrv_state[MAX_LOGICAL_DRIVES_8LD];
+} __attribute__ ((packed)) mega_ldrv_info;
+
+typedef struct {
+	u8	pdrv_state[MAX_PHYSICAL_DRIVES];
+	u8	rsvd;
+} __attribute__ ((packed)) mega_pdrv_info;
+
+/* RAID inquiry: Mailbox command 0x05*/
+typedef struct {
+	mega_adp_info	adapter_info;
+	mega_ldrv_info	logdrv_info;
+	mega_pdrv_info	pdrv_info;
+} __attribute__ ((packed)) mraid_inquiry;
+
+
+/* RAID extended inquiry: Mailbox command 0x04*/
+typedef struct {
+	mraid_inquiry	raid_inq;
+	u16	phys_drv_format[MAX_CHANNELS];
+	u8	stack_attn;
+	u8	modem_status;
+	u8	rsvd[2];
+} __attribute__ ((packed)) mraid_ext_inquiry;
+
+
+typedef struct {
+	u8	channel;
+	u8	target;
+}__attribute__ ((packed)) adp_device;
+
+typedef struct {
+	u32		start_blk;	/* starting block */
+	u32		num_blks;	/* # of blocks */
+	adp_device	device[MAX_ROW_SIZE_40LD];
+}__attribute__ ((packed)) adp_span_40ld;
+
+typedef struct {
+	u32		start_blk;	/* starting block */
+	u32		num_blks;	/* # of blocks */
+	adp_device	device[MAX_ROW_SIZE_8LD];
+}__attribute__ ((packed)) adp_span_8ld;
+
+typedef struct {
+	u8	span_depth;	/* Total # of spans */
+	u8	level;		/* RAID level */
+	u8	read_ahead;	/* read ahead, no read ahead, adaptive read
+				   ahead */
+	u8	stripe_sz;	/* Encoded stripe size */
+	u8	status;		/* Status of the logical drive */
+	u8	write_mode;	/* write mode, write_through/write_back */
+	u8	direct_io;	/* direct io or through cache */
+	u8	row_size;	/* Number of stripes in a row */
+} __attribute__ ((packed)) logdrv_param;
+
+typedef struct {
+	logdrv_param	lparam;
+	adp_span_40ld	span[MAX_SPAN_DEPTH];
+}__attribute__ ((packed)) logdrv_40ld;
+
+typedef struct {
+	logdrv_param	lparam;
+	adp_span_8ld	span[MAX_SPAN_DEPTH];
+}__attribute__ ((packed)) logdrv_8ld;
+
+typedef struct {
+	u8	type;		/* Type of the device */
+	u8	cur_status;	/* current status of the device */
+	u8	tag_depth;	/* Level of tagging */
+	u8	sync_neg;	/* sync negotiation - ENABLE or DISBALE */
+	u32	size;		/* configurable size in terms of 512 byte
+				   blocks */
+}__attribute__ ((packed)) phys_drv;
+
+typedef struct {
+	u8		nlog_drives;		/* number of logical drives */
+	u8		resvd[3];
+	logdrv_40ld	ldrv[MAX_LOGICAL_DRIVES_40LD];
+	phys_drv	pdrv[MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_40ld;
+
+typedef struct {
+	u8		nlog_drives;	/* number of logical drives */
+	u8		resvd[3];
+	logdrv_8ld	ldrv[MAX_LOGICAL_DRIVES_8LD];
+	phys_drv	pdrv[MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_8ld;
+
+
+/*
+ * User ioctl structure.
+ * This structure will be used for Traditional Method ioctl interface
+ * commands (0x80),Alternate Buffer Method (0x81) ioctl commands and the
+ * Driver ioctls.
+ * The Driver ioctl interface handles the commands at the driver level,
+ * without being sent to the card.
+ */
+/* system call imposed limit. Change accordingly */
+#define IOCTL_MAX_DATALEN       4096
+
+struct uioctl_t {
+	u32 inlen;
+	u32 outlen;
+	union {
+		u8 fca[16];
+		struct {
+			u8 opcode;
+			u8 subopcode;
+			u16 adapno;
+#if BITS_PER_LONG == 32
+			u8 *buffer;
+			u8 pad[4];
+#endif
+#if BITS_PER_LONG == 64
+			u8 *buffer;
+#endif
+			u32 length;
+		} __attribute__ ((packed)) fcs;
+	} __attribute__ ((packed)) ui;
+	u8 mbox[18];		/* 16 bytes + 2 status bytes */
+	mega_passthru pthru;
+#if BITS_PER_LONG == 32
+	char __user *data;		/* buffer <= 4096 for 0x80 commands */
+	char pad[4];
+#endif
+#if BITS_PER_LONG == 64
+	char __user *data;
+#endif
+} __attribute__ ((packed));
+
+/*
+ * struct mcontroller is used to pass information about the controllers in the
+ * system. Its upto the application how to use the information. We are passing
+ * as much info about the cards as possible and useful. Before issuing the
+ * call to find information about the cards, the applicaiton needs to issue a
+ * ioctl first to find out the number of controllers in the system.
+ */
+#define MAX_CONTROLLERS 32
+
+struct mcontroller {
+	u64 base;
+	u8 irq;
+	u8 numldrv;
+	u8 pcibus;
+	u16 pcidev;
+	u8 pcifun;
+	u16 pciid;
+	u16 pcivendor;
+	u8 pcislot;
+	u32 uid;
+};
+
+/*
+ * mailbox structure used for internal commands
+ */
+typedef struct {
+	u8	cmd;
+	u8	cmdid;
+	u8	opcode;
+	u8	subopcode;
+	u32	lba;
+	u32	xferaddr;
+	u8	logdrv;
+	u8	rsvd[3];
+	u8	numstatus;
+	u8	status;
+} __attribute__ ((packed)) megacmd_t;
+
+/*
+ * Defines for Driver IOCTL interface
+ */
+#define MEGAIOC_MAGIC  	'm'
+
+#define MEGAIOC_QNADAP		'm'	/* Query # of adapters */
+#define MEGAIOC_QDRVRVER	'e'	/* Query driver version */
+#define MEGAIOC_QADAPINFO   	'g'	/* Query adapter information */
+#define MKADAP(adapno)	  	(MEGAIOC_MAGIC << 8 | (adapno) )
+#define GETADAP(mkadap)	 	( (mkadap) ^ MEGAIOC_MAGIC << 8 )
+
+/*
+ * Definition for the new ioctl interface (NIT)
+ */
+
+/*
+ * Vendor specific Group-7 commands
+ */
+#define VENDOR_SPECIFIC_COMMANDS	0xE0
+#define MEGA_INTERNAL_CMD		VENDOR_SPECIFIC_COMMANDS + 0x01
+
+/*
+ * The ioctl command. No other command shall be used for this interface
+ */
+#define USCSICMD	VENDOR_SPECIFIC_COMMANDS
+
+/*
+ * Data direction flags
+ */
+#define UIOC_RD		0x00001
+#define UIOC_WR		0x00002
+
+/*
+ * ioctl opcodes
+ */
+#define MBOX_CMD	0x00000	/* DCMD or passthru command */
+#define GET_DRIVER_VER	0x10000	/* Get driver version */
+#define GET_N_ADAP	0x20000	/* Get number of adapters */
+#define GET_ADAP_INFO	0x30000	/* Get information about a adapter */
+#define GET_CAP		0x40000	/* Get ioctl capabilities */
+#define GET_STATS	0x50000	/* Get statistics, including error info */
+
+
+/*
+ * The ioctl structure.
+ * MBOX macro converts a nitioctl_t structure to megacmd_t pointer and
+ * MBOX_P macro converts a nitioctl_t pointer to megacmd_t pointer.
+ */
+typedef struct {
+	char		signature[8];	/* Must contain "MEGANIT" */
+	u32		opcode;		/* opcode for the command */
+	u32		adapno;		/* adapter number */
+	union {
+		u8	__raw_mbox[18];
+		void __user *__uaddr; /* xferaddr for non-mbox cmds */
+	}__ua;
+
+#define uioc_rmbox	__ua.__raw_mbox
+#define MBOX(uioc)	((megacmd_t *)&((uioc).__ua.__raw_mbox[0]))
+#define MBOX_P(uioc)	((megacmd_t __user *)&((uioc)->__ua.__raw_mbox[0]))
+#define uioc_uaddr	__ua.__uaddr
+
+	u32		xferlen;	/* xferlen for DCMD and non-mbox
+					   commands */
+	u32		flags;		/* data direction flags */
+}nitioctl_t;
+
+
+/*
+ * I/O statistics for some applications like SNMP agent. The caller must
+ * provide the number of logical drives for which status should be reported.
+ */
+typedef struct {
+	int	num_ldrv;	/* Number for logical drives for which the
+				   status should be reported. */
+	u32	nreads[MAX_LOGICAL_DRIVES_40LD];	/* number of reads for
+							each logical drive */
+	u32	nreadblocks[MAX_LOGICAL_DRIVES_40LD];	/* number of blocks
+							read for each logical
+							drive */
+	u32	nwrites[MAX_LOGICAL_DRIVES_40LD];	/* number of writes
+							for each logical
+							drive */
+	u32	nwriteblocks[MAX_LOGICAL_DRIVES_40LD];	/* number of blocks
+							writes for each
+							logical drive */
+	u32	rd_errors[MAX_LOGICAL_DRIVES_40LD];	/* number of read
+							   errors for each
+							   logical drive */
+	u32	wr_errors[MAX_LOGICAL_DRIVES_40LD];	/* number of write
+							   errors for each
+							   logical drive */
+}megastat_t;
+
+
+struct private_bios_data {
+	u8	geometry:4;	/*
+				 * bits 0-3 - BIOS geometry
+				 * 0x0001 - 1GB
+				 * 0x0010 - 2GB
+				 * 0x1000 - 8GB
+				 * Others values are invalid
+							 */
+	u8	unused:4;	/* bits 4-7 are unused */
+	u8	boot_drv;	/*
+				 * logical drive set as boot drive
+				 * 0..7 - for 8LD cards
+				 * 0..39 - for 40LD cards
+				 */
+	u8	rsvd[12];
+	u16	cksum;	/* 0-(sum of first 13 bytes of this structure) */
+} __attribute__ ((packed));
+
+
+
+
+/*
+ * Mailbox and firmware commands and subopcodes used in this driver.
+ */
+
+#define MEGA_MBOXCMD_LREAD	0x01
+#define MEGA_MBOXCMD_LWRITE	0x02
+#define MEGA_MBOXCMD_PASSTHRU	0x03
+#define MEGA_MBOXCMD_ADPEXTINQ	0x04
+#define MEGA_MBOXCMD_ADAPTERINQ	0x05
+#define MEGA_MBOXCMD_LREAD64	0xA7
+#define MEGA_MBOXCMD_LWRITE64	0xA8
+#define MEGA_MBOXCMD_PASSTHRU64	0xC3
+#define MEGA_MBOXCMD_EXTPTHRU	0xE3
+
+#define MAIN_MISC_OPCODE	0xA4	/* f/w misc opcode */
+#define GET_MAX_SG_SUPPORT	0x01	/* get max sg len supported by f/w */
+
+#define FC_NEW_CONFIG		0xA1
+#define NC_SUBOP_PRODUCT_INFO	0x0E
+#define NC_SUBOP_ENQUIRY3	0x0F
+#define ENQ3_GET_SOLICITED_FULL	0x02
+#define OP_DCMD_READ_CONFIG	0x04
+#define NEW_READ_CONFIG_8LD	0x67
+#define READ_CONFIG_8LD		0x07
+#define FLUSH_ADAPTER		0x0A
+#define FLUSH_SYSTEM		0xFE
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define	FC_DEL_LOGDRV		0xA4	/* f/w command */
+#define	OP_SUP_DEL_LOGDRV	0x2A	/* is feature supported */
+#define OP_GET_LDID_MAP		0x18	/* get ldid and logdrv number map */
+#define OP_DEL_LOGDRV		0x1C	/* delete logical drive */
+
+/*
+ * BIOS commands
+ */
+#define IS_BIOS_ENABLED		0x62
+#define GET_BIOS		0x01
+#define CHNL_CLASS		0xA9
+#define GET_CHNL_CLASS		0x00
+#define SET_CHNL_CLASS		0x01
+#define CH_RAID			0x01
+#define CH_SCSI			0x00
+#define BIOS_PVT_DATA		0x40
+#define GET_BIOS_PVT_DATA	0x00
+
+
+/*
+ * Commands to support clustering
+ */
+#define MEGA_GET_TARGET_ID	0x7D
+#define MEGA_CLUSTER_OP		0x70
+#define MEGA_GET_CLUSTER_MODE	0x02
+#define MEGA_CLUSTER_CMD	0x6E
+#define MEGA_RESERVE_LD		0x01
+#define MEGA_RELEASE_LD		0x02
+#define MEGA_RESET_RESERVATIONS	0x03
+#define MEGA_RESERVATION_STATUS	0x04
+#define MEGA_RESERVE_PD		0x05
+#define MEGA_RELEASE_PD		0x06
+
+
+/*
+ * Module battery status
+ */
+#define MEGA_BATT_MODULE_MISSING	0x01
+#define MEGA_BATT_LOW_VOLTAGE		0x02
+#define MEGA_BATT_TEMP_HIGH		0x04
+#define MEGA_BATT_PACK_MISSING		0x08
+#define MEGA_BATT_CHARGE_MASK		0x30
+#define MEGA_BATT_CHARGE_DONE		0x00
+#define MEGA_BATT_CHARGE_INPROG		0x10
+#define MEGA_BATT_CHARGE_FAIL		0x20
+#define MEGA_BATT_CYCLES_EXCEEDED	0x40
+
+/*
+ * Physical drive states.
+ */
+#define PDRV_UNCNF	0
+#define PDRV_ONLINE	3
+#define PDRV_FAILED	4
+#define PDRV_RBLD	5
+#define PDRV_HOTSPARE	6
+
+
+/*
+ * Raid logical drive states.
+ */
+#define RDRV_OFFLINE	0
+#define RDRV_DEGRADED	1
+#define RDRV_OPTIMAL	2
+#define RDRV_DELETED	3
+
+/*
+ * Read, write and cache policies
+ */
+#define NO_READ_AHEAD		0
+#define READ_AHEAD		1
+#define ADAP_READ_AHEAD		2
+#define WRMODE_WRITE_THRU	0
+#define WRMODE_WRITE_BACK	1
+#define CACHED_IO		0
+#define DIRECT_IO		1
+
+
+#define SCSI_LIST(scp) ((struct list_head *)(&(scp)->SCp))
+
+/*
+ * Each controller's soft state
+ */
+typedef struct {
+	int	this_id;	/* our id, may set to different than 7 if
+				   clustering is available */
+	u32	flag;
+
+	unsigned long	base;
+
+	/* mbox64 with mbox not aligned on 16-byte boundry */
+	mbox64_t	*una_mbox64;
+	dma_addr_t	una_mbox64_dma;
+
+	volatile mbox64_t	*mbox64;/* ptr to 64-bit mailbox */
+	volatile mbox_t		*mbox;	/* ptr to standard mailbox */
+	dma_addr_t		mbox_dma;
+
+	struct pci_dev	*dev;
+
+	struct list_head	free_list;
+	struct list_head	pending_list;
+	struct list_head	completed_list;
+
+	struct Scsi_Host	*host;
+
+#define MEGA_BUFFER_SIZE (2*1024)
+	u8		*mega_buffer;
+	dma_addr_t	buf_dma_handle;
+
+	mega_product_info	product_info;
+
+	u8		max_cmds;
+	scb_t		*scb_list;
+
+	atomic_t	pend_cmds;	/* maintain a counter for pending
+					   commands in firmware */
+
+#if MEGA_HAVE_STATS
+	u32	nreads[MAX_LOGICAL_DRIVES_40LD];
+	u32	nreadblocks[MAX_LOGICAL_DRIVES_40LD];
+	u32	nwrites[MAX_LOGICAL_DRIVES_40LD];
+	u32	nwriteblocks[MAX_LOGICAL_DRIVES_40LD];
+	u32	rd_errors[MAX_LOGICAL_DRIVES_40LD];
+	u32	wr_errors[MAX_LOGICAL_DRIVES_40LD];
+#endif
+
+	/* Host adapter parameters */
+	u8	numldrv;
+	u8	fw_version[7];
+	u8	bios_version[7];
+
+#ifdef CONFIG_PROC_FS
+	struct proc_dir_entry	*controller_proc_dir_entry;
+	struct proc_dir_entry	*proc_read;
+	struct proc_dir_entry	*proc_stat;
+	struct proc_dir_entry	*proc_mbox;
+
+#if MEGA_HAVE_ENH_PROC
+	struct proc_dir_entry	*proc_rr;
+	struct proc_dir_entry	*proc_battery;
+#define MAX_PROC_CHANNELS	4
+	struct proc_dir_entry	*proc_pdrvstat[MAX_PROC_CHANNELS];
+	struct proc_dir_entry	*proc_rdrvstat[MAX_PROC_CHANNELS];
+#endif
+
+#endif
+
+	int	has_64bit_addr;		/* are we using 64-bit addressing */
+	int	support_ext_cdb;
+	int	boot_ldrv_enabled;
+	int	boot_ldrv;
+	int	boot_pdrv_enabled;	/* boot from physical drive */
+	int	boot_pdrv_ch;		/* boot physical drive channel */
+	int	boot_pdrv_tgt;		/* boot physical drive target */
+
+
+	int	support_random_del;	/* Do we support random deletion of
+					   logdrvs */
+	int	read_ldidmap;	/* set after logical drive deltion. The
+				   logical drive number must be read from the
+				   map */
+	atomic_t	quiescent;	/* a stage reached when delete logical
+					   drive needs to be done. Stop
+					   sending requests to the hba till
+					   delete operation is completed */
+	spinlock_t	lock;
+
+	u8	logdrv_chan[MAX_CHANNELS+NVIRT_CHAN]; /* logical drive are on
+							what channels. */
+	int	mega_ch_class;
+
+	u8	sglen;	/* f/w supported scatter-gather list length */
+
+	scb_t			int_scb;
+	Scsi_Cmnd		int_scmd;
+	struct semaphore	int_mtx;	/* To synchronize the internal
+						commands */
+	wait_queue_head_t	int_waitq;	/* wait queue for internal
+						 cmds */
+
+	int	has_cluster;	/* cluster support on this HBA */
+}adapter_t;
+
+
+struct mega_hbas {
+	int is_bios_enabled;
+	adapter_t *hostdata_addr;
+};
+
+
+/*
+ * For state flag. Do not use LSB(8 bits) which are
+ * reserved for storing info about channels.
+ */
+#define IN_ABORT	0x80000000L
+#define IN_RESET	0x40000000L
+#define BOARD_MEMMAP	0x20000000L
+#define BOARD_IOMAP	0x10000000L
+#define BOARD_40LD   	0x08000000L
+#define BOARD_64BIT	0x04000000L
+
+#define INTR_VALID			0x40
+
+#define PCI_CONF_AMISIG			0xa0
+#define PCI_CONF_AMISIG64		0xa4
+
+
+#define MEGA_DMA_TYPE_NONE		0xFFFF
+#define MEGA_BULK_DATA			0x0001
+#define MEGA_SGLIST			0x0002
+
+/*
+ * lockscope definitions, callers can specify the lock scope with this data
+ * type. LOCK_INT would mean the caller has not acquired the lock before
+ * making the call and LOCK_EXT would mean otherwise.
+ */
+typedef enum { LOCK_INT, LOCK_EXT } lockscope_t;
+
+/*
+ * Parameters for the io-mapped controllers
+ */
+
+/* I/O Port offsets */
+#define CMD_PORT	 	0x00
+#define ACK_PORT	 	0x00
+#define TOGGLE_PORT		0x01
+#define INTR_PORT	  	0x0a
+
+#define MBOX_BUSY_PORT     	0x00
+#define MBOX_PORT0	 	0x04
+#define MBOX_PORT1	 	0x05
+#define MBOX_PORT2	 	0x06
+#define MBOX_PORT3	 	0x07
+#define ENABLE_MBOX_REGION 	0x0B
+
+/* I/O Port Values */
+#define ISSUE_BYTE	 	0x10
+#define ACK_BYTE	   	0x08
+#define ENABLE_INTR_BYTE   	0xc0
+#define DISABLE_INTR_BYTE  	0x00
+#define VALID_INTR_BYTE    	0x40
+#define MBOX_BUSY_BYTE     	0x10
+#define ENABLE_MBOX_BYTE   	0x00
+
+
+/* Setup some port macros here */
+#define issue_command(adapter)	\
+		outb_p(ISSUE_BYTE, (adapter)->base + CMD_PORT)
+
+#define irq_state(adapter)	inb_p((adapter)->base + INTR_PORT)
+
+#define set_irq_state(adapter, value)	\
+		outb_p((value), (adapter)->base + INTR_PORT)
+
+#define irq_ack(adapter)	\
+		outb_p(ACK_BYTE, (adapter)->base + ACK_PORT)
+
+#define irq_enable(adapter)	\
+	outb_p(ENABLE_INTR_BYTE, (adapter)->base + TOGGLE_PORT)
+
+#define irq_disable(adapter)	\
+	outb_p(DISABLE_INTR_BYTE, (adapter)->base + TOGGLE_PORT)
+
+
+/*
+ * This is our SYSDEP area. All kernel specific detail should be placed here -
+ * as much as possible
+ */
+
+/*
+ * End of SYSDEP area
+ */
+
+const char *megaraid_info (struct Scsi_Host *);
+
+static int mega_query_adapter(adapter_t *);
+static int issue_scb(adapter_t *, scb_t *);
+static int mega_setup_mailbox(adapter_t *);
+
+static int megaraid_queue (Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
+static scb_t * mega_build_cmd(adapter_t *, Scsi_Cmnd *, int *);
+static void __mega_runpendq(adapter_t *);
+static int issue_scb_block(adapter_t *, u_char *);
+
+static irqreturn_t megaraid_isr_memmapped(int, void *, struct pt_regs *);
+static irqreturn_t megaraid_isr_iomapped(int, void *, struct pt_regs *);
+
+static void mega_free_scb(adapter_t *, scb_t *);
+
+static int megaraid_abort(Scsi_Cmnd *);
+static int megaraid_reset(Scsi_Cmnd *);
+static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int);
+static int megaraid_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int []);
+static int mega_print_inquiry(char *, char *);
+
+static int mega_build_sglist (adapter_t *adapter, scb_t *scb,
+			      u32 *buffer, u32 *length);
+static int __mega_busywait_mbox (adapter_t *);
+static void mega_rundoneq (adapter_t *);
+static void mega_cmd_done(adapter_t *, u8 [], int, int);
+static inline void mega_free_sgl (adapter_t *adapter);
+static void mega_8_to_40ld (mraid_inquiry *inquiry,
+		mega_inquiry3 *enquiry3, mega_product_info *);
+
+static int megadev_open (struct inode *, struct file *);
+static int megadev_ioctl (struct inode *, struct file *, unsigned int,
+		unsigned long);
+static int mega_m_to_n(void __user *, nitioctl_t *);
+static int mega_n_to_m(void __user *, megacmd_t *);
+
+static int mega_init_scb (adapter_t *);
+
+static int mega_is_bios_enabled (adapter_t *);
+
+#ifdef CONFIG_PROC_FS
+static void mega_create_proc_entry(int, struct proc_dir_entry *);
+static int proc_read_config(char *, char **, off_t, int, int *, void *);
+static int proc_read_stat(char *, char **, off_t, int, int *, void *);
+static int proc_read_mbox(char *, char **, off_t, int, int *, void *);
+static int proc_rebuild_rate(char *, char **, off_t, int, int *, void *);
+static int proc_battery(char *, char **, off_t, int, int *, void *);
+static int proc_pdrv_ch0(char *, char **, off_t, int, int *, void *);
+static int proc_pdrv_ch1(char *, char **, off_t, int, int *, void *);
+static int proc_pdrv_ch2(char *, char **, off_t, int, int *, void *);
+static int proc_pdrv_ch3(char *, char **, off_t, int, int *, void *);
+static int proc_pdrv(adapter_t *, char *, int);
+static int proc_rdrv_10(char *, char **, off_t, int, int *, void *);
+static int proc_rdrv_20(char *, char **, off_t, int, int *, void *);
+static int proc_rdrv_30(char *, char **, off_t, int, int *, void *);
+static int proc_rdrv_40(char *, char **, off_t, int, int *, void *);
+static int proc_rdrv(adapter_t *, char *, int, int);
+#endif
+
+static int mega_adapinq(adapter_t *, dma_addr_t);
+static int mega_internal_dev_inquiry(adapter_t *, u8, u8, dma_addr_t);
+
+static int mega_support_ext_cdb(adapter_t *);
+static mega_passthru* mega_prepare_passthru(adapter_t *, scb_t *,
+		Scsi_Cmnd *, int, int);
+static mega_ext_passthru* mega_prepare_extpassthru(adapter_t *,
+		scb_t *, Scsi_Cmnd *, int, int);
+static void mega_enum_raid_scsi(adapter_t *);
+static void mega_get_boot_drv(adapter_t *);
+static int mega_support_random_del(adapter_t *);
+static int mega_del_logdrv(adapter_t *, int);
+static int mega_do_del_logdrv(adapter_t *, int);
+static void mega_get_max_sgl(adapter_t *);
+static int mega_internal_command(adapter_t *, lockscope_t, megacmd_t *,
+		mega_passthru *);
+static void mega_internal_done(Scsi_Cmnd *);
+static int mega_support_cluster(adapter_t *);
+#endif
+
+/* vi: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid/Kconfig.megaraid b/drivers/scsi/megaraid/Kconfig.megaraid
new file mode 100644
index 0000000..917d591
--- /dev/null
+++ b/drivers/scsi/megaraid/Kconfig.megaraid
@@ -0,0 +1,78 @@
+config MEGARAID_NEWGEN
+	bool "LSI Logic New Generation RAID Device Drivers"
+	depends on PCI && SCSI
+	help
+	LSI Logic RAID Device Drivers
+
+config MEGARAID_MM
+	tristate "LSI Logic Management Module (New Driver)"
+	depends on PCI && SCSI && MEGARAID_NEWGEN
+	help
+	Management Module provides ioctl, sysfs support for LSI Logic
+	RAID controllers.
+	To compile this driver as a module, choose M here: the
+	module will be called megaraid_mm
+
+
+config MEGARAID_MAILBOX
+	tristate "LSI Logic MegaRAID Driver (New Driver)"
+	depends on PCI && SCSI && MEGARAID_MM
+	help
+	List of supported controllers
+
+	OEM	Product Name		VID :DID :SVID:SSID
+	---	------------		---- ---- ---- ----
+	Dell PERC3/QC			101E:1960:1028:0471
+	Dell PERC3/DC			101E:1960:1028:0493
+	Dell PERC3/SC			101E:1960:1028:0475
+	Dell PERC3/Di			1028:000E:1028:0123
+	Dell PERC4/SC			1000:1960:1028:0520
+	Dell PERC4/DC			1000:1960:1028:0518
+	Dell PERC4/QC			1000:0407:1028:0531
+	Dell PERC4/Di			1028:000F:1028:014A
+	Dell PERC 4e/Si			1028:0013:1028:016c
+	Dell PERC 4e/Di			1028:0013:1028:016d
+	Dell PERC 4e/Di			1028:0013:1028:016e
+	Dell PERC 4e/Di			1028:0013:1028:016f
+	Dell PERC 4e/Di			1028:0013:1028:0170
+	Dell PERC 4e/DC			1000:0408:1028:0002
+	Dell PERC 4e/SC			1000:0408:1028:0001
+	LSI MegaRAID SCSI 320-0		1000:1960:1000:A520
+	LSI MegaRAID SCSI 320-1		1000:1960:1000:0520
+	LSI MegaRAID SCSI 320-2		1000:1960:1000:0518
+	LSI MegaRAID SCSI 320-0X	1000:0407:1000:0530
+	LSI MegaRAID SCSI 320-2X	1000:0407:1000:0532
+	LSI MegaRAID SCSI 320-4X	1000:0407:1000:0531
+	LSI MegaRAID SCSI 320-1E	1000:0408:1000:0001
+	LSI MegaRAID SCSI 320-2E	1000:0408:1000:0002
+	LSI MegaRAID SATA 150-4		1000:1960:1000:4523
+	LSI MegaRAID SATA 150-6		1000:1960:1000:0523
+	LSI MegaRAID SATA 300-4X	1000:0409:1000:3004
+	LSI MegaRAID SATA 300-8X	1000:0409:1000:3008
+	INTEL RAID Controller SRCU42X	1000:0407:8086:0532
+	INTEL RAID Controller SRCS16	1000:1960:8086:0523
+	INTEL RAID Controller SRCU42E	1000:0408:8086:0002
+	INTEL RAID Controller SRCZCRX	1000:0407:8086:0530
+	INTEL RAID Controller SRCS28X	1000:0409:8086:3008
+	INTEL RAID Controller SROMBU42E	1000:0408:8086:3431
+	INTEL RAID Controller SROMBU42E	1000:0408:8086:3499
+	INTEL RAID Controller SRCU51L	1000:1960:8086:0520
+	FSC MegaRAID PCI Express ROMB	1000:0408:1734:1065
+	ACER MegaRAID ROMB-2E		1000:0408:1025:004D
+	NEC MegaRAID PCI Express ROMB	1000:0408:1033:8287
+
+	To compile this driver as a module, choose M here: the
+	module will be called megaraid_mbox
+
+if MEGARAID_NEWGEN=n
+config MEGARAID_LEGACY
+	tristate "LSI Logic Legacy MegaRAID Driver"
+	depends on PCI && SCSI
+	help
+	This driver supports the LSI MegaRAID 418, 428, 438, 466, 762, 490
+	and 467 SCSI host adapters. This driver also support the all U320
+	RAID controllers
+
+	To compile this driver as a module, choose M here: the
+	module will be called megaraid
+endif
diff --git a/drivers/scsi/megaraid/Makefile b/drivers/scsi/megaraid/Makefile
new file mode 100644
index 0000000..6dd99f2
--- /dev/null
+++ b/drivers/scsi/megaraid/Makefile
@@ -0,0 +1,2 @@
+obj-$(CONFIG_MEGARAID_MM)	+= megaraid_mm.o
+obj-$(CONFIG_MEGARAID_MAILBOX)	+= megaraid_mbox.o
diff --git a/drivers/scsi/megaraid/mbox_defs.h b/drivers/scsi/megaraid/mbox_defs.h
new file mode 100644
index 0000000..3052869
--- /dev/null
+++ b/drivers/scsi/megaraid/mbox_defs.h
@@ -0,0 +1,790 @@
+/*
+ *
+ *			Linux MegaRAID Unified device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: mbox_defs.h
+ *
+ */
+#ifndef _MRAID_MBOX_DEFS_H_
+#define _MRAID_MBOX_DEFS_H_
+
+#include <linux/types.h>
+
+/*
+ * Commands and states for mailbox based controllers
+ */
+
+#define MBOXCMD_LREAD		0x01
+#define MBOXCMD_LWRITE		0x02
+#define MBOXCMD_PASSTHRU	0x03
+#define MBOXCMD_ADPEXTINQ	0x04
+#define MBOXCMD_ADAPTERINQ	0x05
+#define MBOXCMD_LREAD64		0xA7
+#define MBOXCMD_LWRITE64	0xA8
+#define MBOXCMD_PASSTHRU64	0xC3
+#define MBOXCMD_EXTPTHRU	0xE3
+
+#define MAIN_MISC_OPCODE	0xA4
+#define GET_MAX_SG_SUPPORT	0x01
+#define SUPPORT_EXT_CDB		0x16
+
+#define FC_NEW_CONFIG		0xA1
+#define NC_SUBOP_PRODUCT_INFO	0x0E
+#define NC_SUBOP_ENQUIRY3	0x0F
+#define ENQ3_GET_SOLICITED_FULL	0x02
+#define OP_DCMD_READ_CONFIG	0x04
+#define NEW_READ_CONFIG_8LD	0x67
+#define READ_CONFIG_8LD		0x07
+#define FLUSH_ADAPTER		0x0A
+#define FLUSH_SYSTEM		0xFE
+
+/*
+ * Command for random deletion of logical drives
+ */
+#define	FC_DEL_LOGDRV		0xA4
+#define	OP_SUP_DEL_LOGDRV	0x2A
+#define OP_GET_LDID_MAP		0x18
+#define OP_DEL_LOGDRV		0x1C
+
+/*
+ * BIOS commands
+ */
+#define IS_BIOS_ENABLED		0x62
+#define GET_BIOS		0x01
+#define CHNL_CLASS		0xA9
+#define GET_CHNL_CLASS		0x00
+#define SET_CHNL_CLASS		0x01
+#define CH_RAID			0x01
+#define CH_SCSI			0x00
+#define BIOS_PVT_DATA		0x40
+#define GET_BIOS_PVT_DATA	0x00
+
+
+/*
+ * Commands to support clustering
+ */
+#define GET_TARGET_ID		0x7D
+#define CLUSTER_OP		0x70
+#define GET_CLUSTER_MODE	0x02
+#define CLUSTER_CMD		0x6E
+#define RESERVE_LD		0x01
+#define RELEASE_LD		0x02
+#define RESET_RESERVATIONS	0x03
+#define RESERVATION_STATUS	0x04
+#define RESERVE_PD		0x05
+#define RELEASE_PD		0x06
+
+
+/*
+ * Module battery status
+ */
+#define BATTERY_MODULE_MISSING		0x01
+#define BATTERY_LOW_VOLTAGE		0x02
+#define BATTERY_TEMP_HIGH		0x04
+#define BATTERY_PACK_MISSING		0x08
+#define BATTERY_CHARGE_MASK		0x30
+#define BATTERY_CHARGE_DONE		0x00
+#define BATTERY_CHARGE_INPROG		0x10
+#define BATTERY_CHARGE_FAIL		0x20
+#define BATTERY_CYCLES_EXCEEDED		0x40
+
+/*
+ * Physical drive states.
+ */
+#define PDRV_UNCNF	0
+#define PDRV_ONLINE	3
+#define PDRV_FAILED	4
+#define PDRV_RBLD	5
+#define PDRV_HOTSPARE	6
+
+
+/*
+ * Raid logical drive states.
+ */
+#define RDRV_OFFLINE	0
+#define RDRV_DEGRADED	1
+#define RDRV_OPTIMAL	2
+#define RDRV_DELETED	3
+
+/*
+ * Read, write and cache policies
+ */
+#define NO_READ_AHEAD		0
+#define READ_AHEAD		1
+#define ADAP_READ_AHEAD		2
+#define WRMODE_WRITE_THRU	0
+#define WRMODE_WRITE_BACK	1
+#define CACHED_IO		0
+#define DIRECT_IO		1
+
+#define MAX_LOGICAL_DRIVES_8LD		8
+#define MAX_LOGICAL_DRIVES_40LD		40
+#define FC_MAX_PHYSICAL_DEVICES		256
+#define MAX_MBOX_CHANNELS		5
+#define MAX_MBOX_TARGET			15
+#define MBOX_MAX_PHYSICAL_DRIVES	MAX_MBOX_CHANNELS*MAX_MBOX_TARGET
+#define MAX_ROW_SIZE_40LD		32
+#define MAX_ROW_SIZE_8LD		8
+#define SPAN_DEPTH_8_SPANS		8
+#define SPAN_DEPTH_4_SPANS		4
+#define MAX_REQ_SENSE_LEN		0x20
+
+
+
+/**
+ * struct mbox_t - Driver and f/w handshake structure.
+ * @cmd		: firmware command
+ * @cmdid	: command id
+ * @numsectors	: number of sectors to be transferred
+ * @lba		: Logical Block Address on LD
+ * @xferaddr	: DMA address for data transfer
+ * @logdrv	: logical drive number
+ * @numsge	: number of scatter gather elements in sg list
+ * @resvd	: reserved
+ * @busy	: f/w busy, must wait to issue more commands.
+ * @numstatus	: number of commands completed.
+ * @status	: status of the commands completed
+ * @completed	: array of completed command ids.
+ * @poll	: poll and ack sequence
+ * @ack		: poll and ack sequence
+ *
+ * The central handshake structure between the driver and the firmware. This
+ * structure must be allocated by the driver and aligned at 8-byte boundary.
+ */
+#define MBOX_MAX_FIRMWARE_STATUS	46
+typedef struct {
+	uint8_t		cmd;
+	uint8_t		cmdid;
+	uint16_t	numsectors;
+	uint32_t	lba;
+	uint32_t	xferaddr;
+	uint8_t		logdrv;
+	uint8_t		numsge;
+	uint8_t		resvd;
+	uint8_t		busy;
+	uint8_t		numstatus;
+	uint8_t		status;
+	uint8_t		completed[MBOX_MAX_FIRMWARE_STATUS];
+	uint8_t		poll;
+	uint8_t		ack;
+} __attribute__ ((packed)) mbox_t;
+
+
+/**
+ * mbox64_t - 64-bit extension for the mailbox
+ * @segment_lo	: the low 32-bits of the address of the scatter-gather list
+ * @segment_hi	: the upper 32-bits of the address of the scatter-gather list
+ * @mbox	: 32-bit mailbox, whose xferadder field must be set to
+ *		0xFFFFFFFF
+ *
+ * This is the extension of the 32-bit mailbox to be able to perform DMA
+ * beyond 4GB address range.
+ */
+typedef struct {
+	uint32_t	xferaddr_lo;
+	uint32_t	xferaddr_hi;
+	mbox_t		mbox32;
+} __attribute__ ((packed)) mbox64_t;
+
+/*
+ * mailbox structure used for internal commands
+ */
+typedef struct {
+	u8	cmd;
+	u8	cmdid;
+	u8	opcode;
+	u8	subopcode;
+	u32	lba;
+	u32	xferaddr;
+	u8	logdrv;
+	u8	rsvd[3];
+	u8	numstatus;
+	u8	status;
+} __attribute__ ((packed)) int_mbox_t;
+
+/**
+ * mraid_passthru_t - passthru structure to issue commands to physical devices
+ * @timeout		: command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
+ * @ars			: set if ARS required after check condition
+ * @islogical		: set if command meant for logical devices
+ * @logdrv		: logical drive number if command for LD
+ * @channel		: Channel on which physical device is located
+ * @target		: SCSI target of the device
+ * @queuetag		: unused
+ * @queueaction		: unused
+ * @cdb			: SCSI CDB
+ * @cdblen		: length of the CDB
+ * @reqsenselen		: amount of request sense data to be returned
+ * @reqsensearea	: Sense information buffer
+ * @numsge		: number of scatter-gather elements in the sg list
+ * @scsistatus		: SCSI status of the command completed.
+ * @dataxferaddr	: DMA data transfer address
+ * @dataxferlen		: amount of the data to be transferred.
+ */
+typedef struct {
+	uint8_t		timeout		:3;
+	uint8_t		ars		:1;
+	uint8_t		reserved	:3;
+	uint8_t		islogical	:1;
+	uint8_t		logdrv;
+	uint8_t		channel;
+	uint8_t		target;
+	uint8_t		queuetag;
+	uint8_t		queueaction;
+	uint8_t		cdb[10];
+	uint8_t		cdblen;
+	uint8_t		reqsenselen;
+	uint8_t		reqsensearea[MAX_REQ_SENSE_LEN];
+	uint8_t		numsge;
+	uint8_t		scsistatus;
+	uint32_t	dataxferaddr;
+	uint32_t	dataxferlen;
+} __attribute__ ((packed)) mraid_passthru_t;
+
+typedef struct {
+
+	uint32_t		dataxferaddr_lo;
+	uint32_t		dataxferaddr_hi;
+	mraid_passthru_t	pthru32;
+
+} __attribute__ ((packed)) mega_passthru64_t;
+
+/**
+ * mraid_epassthru_t - passthru structure to issue commands to physical devices
+ * @timeout		: command timeout, 0=6sec, 1=60sec, 2=10min, 3=3hr
+ * @ars			: set if ARS required after check condition
+ * @rsvd1		: reserved field
+ * @cd_rom		: (?)
+ * @rsvd2		: reserved field
+ * @islogical		: set if command meant for logical devices
+ * @logdrv		: logical drive number if command for LD
+ * @channel		: Channel on which physical device is located
+ * @target		: SCSI target of the device
+ * @queuetag		: unused
+ * @queueaction		: unused
+ * @cdblen		: length of the CDB
+ * @rsvd3		: reserved field
+ * @cdb			: SCSI CDB
+ * @numsge		: number of scatter-gather elements in the sg list
+ * @status		: SCSI status of the command completed.
+ * @reqsenselen		: amount of request sense data to be returned
+ * @reqsensearea	: Sense information buffer
+ * @rsvd4		: reserved field
+ * @dataxferaddr	: DMA data transfer address
+ * @dataxferlen		: amount of the data to be transferred.
+ */
+typedef struct {
+	uint8_t		timeout		:3;
+	uint8_t		ars		:1;
+	uint8_t		rsvd1		:1;
+	uint8_t		cd_rom		:1;
+	uint8_t		rsvd2		:1;
+	uint8_t		islogical	:1;
+	uint8_t		logdrv;
+	uint8_t		channel;
+	uint8_t		target;
+	uint8_t		queuetag;
+	uint8_t		queueaction;
+	uint8_t		cdblen;
+	uint8_t		rsvd3;
+	uint8_t		cdb[16];
+	uint8_t		numsge;
+	uint8_t		status;
+	uint8_t		reqsenselen;
+	uint8_t		reqsensearea[MAX_REQ_SENSE_LEN];
+	uint8_t		rsvd4;
+	uint32_t	dataxferaddr;
+	uint32_t	dataxferlen;
+} __attribute__ ((packed)) mraid_epassthru_t;
+
+
+/**
+ * mraid_pinfo_t - product info, static information about the controller
+ * @data_size		: current size in bytes (not including resvd)
+ * @config_signature	: Current value is 0x00282008
+ * @fw_version		: Firmware version
+ * @bios_version	: version of the BIOS
+ * @product_name	: Name given to the controller
+ * @max_commands	: Maximum concurrent commands supported
+ * @nchannels		: Number of SCSI Channels detected
+ * @fc_loop_present	: Number of Fibre Loops detected
+ * @mem_type		: EDO, FPM, SDRAM etc
+ * @signature		:
+ * @dram_size		: In terms of MB
+ * @subsysid		: device PCI subsystem ID
+ * @subsysvid		: device PCI subsystem vendor ID
+ * @notify_counters	:
+ * @pad1k		: 135 + 889 resvd = 1024 total size
+ *
+ * This structures holds the information about the controller which is not
+ * expected to change dynamically.
+ *
+ * The current value of config signature is 0x00282008:
+ * 0x28 = MAX_LOGICAL_DRIVES,
+ * 0x20 = Number of stripes and
+ * 0x08 = Number of spans
+ */
+typedef struct {
+	uint32_t	data_size;
+	uint32_t	config_signature;
+	uint8_t		fw_version[16];
+	uint8_t		bios_version[16];
+	uint8_t		product_name[80];
+	uint8_t		max_commands;
+	uint8_t		nchannels;
+	uint8_t		fc_loop_present;
+	uint8_t		mem_type;
+	uint32_t	signature;
+	uint16_t	dram_size;
+	uint16_t	subsysid;
+	uint16_t	subsysvid;
+	uint8_t		notify_counters;
+	uint8_t		pad1k[889];
+} __attribute__ ((packed)) mraid_pinfo_t;
+
+
+/**
+ * mraid_notify_t - the notification structure
+ * @global_counter		: Any change increments this counter
+ * @param_counter		: Indicates any params changed
+ * @param_id			: Param modified - defined below
+ * @param_val			: New val of last param modified
+ * @write_config_counter	: write config occurred
+ * @write_config_rsvd		:
+ * @ldrv_op_counter		: Indicates ldrv op started/completed
+ * @ldrv_opid			: ldrv num
+ * @ldrv_opcmd			: ldrv operation - defined below
+ * @ldrv_opstatus		: status of the operation
+ * @ldrv_state_counter		: Indicates change of ldrv state
+ * @ldrv_state_id		: ldrv num
+ * @ldrv_state_new		: New state
+ * @ldrv_state_old		: old state
+ * @pdrv_state_counter		: Indicates change of ldrv state
+ * @pdrv_state_id		: pdrv id
+ * @pdrv_state_new		: New state
+ * @pdrv_state_old		: old state
+ * @pdrv_fmt_counter		: Indicates pdrv format started/over
+ * @pdrv_fmt_id			: pdrv id
+ * @pdrv_fmt_val		: format started/over
+ * @pdrv_fmt_rsvd		:
+ * @targ_xfer_counter		: Indicates SCSI-2 Xfer rate change
+ * @targ_xfer_id		: pdrv Id
+ * @targ_xfer_val		: new Xfer params of last pdrv
+ * @targ_xfer_rsvd		:
+ * @fcloop_id_chg_counter	: Indicates loopid changed
+ * @fcloopid_pdrvid		: pdrv id
+ * @fcloop_id0			: loopid on fc loop 0
+ * @fcloop_id1			: loopid on fc loop 1
+ * @fcloop_state_counter	: Indicates loop state changed
+ * @fcloop_state0		: state of fc loop 0
+ * @fcloop_state1		: state of fc loop 1
+ * @fcloop_state_rsvd		:
+ */
+typedef struct {
+	uint32_t	global_counter;
+	uint8_t		param_counter;
+	uint8_t		param_id;
+	uint16_t	param_val;
+	uint8_t		write_config_counter;
+	uint8_t		write_config_rsvd[3];
+	uint8_t		ldrv_op_counter;
+	uint8_t		ldrv_opid;
+	uint8_t		ldrv_opcmd;
+	uint8_t		ldrv_opstatus;
+	uint8_t		ldrv_state_counter;
+	uint8_t		ldrv_state_id;
+	uint8_t		ldrv_state_new;
+	uint8_t		ldrv_state_old;
+	uint8_t		pdrv_state_counter;
+	uint8_t		pdrv_state_id;
+	uint8_t		pdrv_state_new;
+	uint8_t		pdrv_state_old;
+	uint8_t		pdrv_fmt_counter;
+	uint8_t		pdrv_fmt_id;
+	uint8_t		pdrv_fmt_val;
+	uint8_t		pdrv_fmt_rsvd;
+	uint8_t		targ_xfer_counter;
+	uint8_t		targ_xfer_id;
+	uint8_t		targ_xfer_val;
+	uint8_t		targ_xfer_rsvd;
+	uint8_t		fcloop_id_chg_counter;
+	uint8_t		fcloopid_pdrvid;
+	uint8_t		fcloop_id0;
+	uint8_t		fcloop_id1;
+	uint8_t		fcloop_state_counter;
+	uint8_t		fcloop_state0;
+	uint8_t		fcloop_state1;
+	uint8_t		fcloop_state_rsvd;
+} __attribute__ ((packed)) mraid_notify_t;
+
+
+/**
+ * mraid_inquiry3_t - enquiry for device information
+ *
+ * @data_size		: current size in bytes (not including resvd)
+ * @notify		:
+ * @notify_rsvd		:
+ * @rebuild_rate	: rebuild rate (0% - 100%)
+ * @cache_flush_int	: cache flush interval in seconds
+ * @sense_alert		:
+ * @drive_insert_count	: drive insertion count
+ * @battery_status	:
+ * @num_ldrv		: no. of Log Drives configured
+ * @recon_state		: state of reconstruct
+ * @ldrv_op_status	: logdrv Status
+ * @ldrv_size		: size of each log drv
+ * @ldrv_prop		:
+ * @ldrv_state		: state of log drives
+ * @pdrv_state		: state of phys drvs.
+ * @pdrv_format		:
+ * @targ_xfer		: phys device transfer rate
+ * @pad1k		: 761 + 263reserved = 1024 bytes total size
+ */
+#define MAX_NOTIFY_SIZE		0x80
+#define CUR_NOTIFY_SIZE		sizeof(mraid_notify_t)
+
+typedef struct {
+	uint32_t	data_size;
+
+	mraid_notify_t	notify;
+
+	uint8_t		notify_rsvd[MAX_NOTIFY_SIZE - CUR_NOTIFY_SIZE];
+
+	uint8_t		rebuild_rate;
+	uint8_t		cache_flush_int;
+	uint8_t		sense_alert;
+	uint8_t		drive_insert_count;
+
+	uint8_t		battery_status;
+	uint8_t		num_ldrv;
+	uint8_t		recon_state[MAX_LOGICAL_DRIVES_40LD / 8];
+	uint16_t	ldrv_op_status[MAX_LOGICAL_DRIVES_40LD / 8];
+
+	uint32_t	ldrv_size[MAX_LOGICAL_DRIVES_40LD];
+	uint8_t		ldrv_prop[MAX_LOGICAL_DRIVES_40LD];
+	uint8_t		ldrv_state[MAX_LOGICAL_DRIVES_40LD];
+	uint8_t		pdrv_state[FC_MAX_PHYSICAL_DEVICES];
+	uint16_t	pdrv_format[FC_MAX_PHYSICAL_DEVICES / 16];
+
+	uint8_t		targ_xfer[80];
+	uint8_t		pad1k[263];
+} __attribute__ ((packed)) mraid_inquiry3_t;
+
+
+/**
+ * mraid_adapinfo_t - information about the adapter
+ * @max_commands		: max concurrent commands supported
+ * @rebuild_rate		: rebuild rate - 0% thru 100%
+ * @max_targ_per_chan		: max targ per channel
+ * @nchannels			: number of channels on HBA
+ * @fw_version			: firmware version
+ * @age_of_flash		: number of times FW has been flashed
+ * @chip_set_value		: contents of 0xC0000832
+ * @dram_size			: in MB
+ * @cache_flush_interval	: in seconds
+ * @bios_version		:
+ * @board_type			:
+ * @sense_alert			:
+ * @write_config_count		: increase with every configuration change
+ * @drive_inserted_count	: increase with every drive inserted
+ * @inserted_drive		: channel:Id of inserted drive
+ * @battery_status		: bit 0: battery module missing
+ *				bit 1: VBAD
+ *				bit 2: temprature high
+ *				bit 3: battery pack missing
+ *				bit 4,5:
+ *					00 - charge complete
+ *					01 - fast charge in progress
+ *					10 - fast charge fail
+ *					11 - undefined
+ *				bit 6: counter > 1000
+ *				bit 7: Undefined
+ * @dec_fault_bus_info		:
+ */
+typedef struct {
+	uint8_t		max_commands;
+	uint8_t		rebuild_rate;
+	uint8_t		max_targ_per_chan;
+	uint8_t		nchannels;
+	uint8_t		fw_version[4];
+	uint16_t	age_of_flash;
+	uint8_t		chip_set_value;
+	uint8_t		dram_size;
+	uint8_t		cache_flush_interval;
+	uint8_t		bios_version[4];
+	uint8_t		board_type;
+	uint8_t		sense_alert;
+	uint8_t		write_config_count;
+	uint8_t		battery_status;
+	uint8_t		dec_fault_bus_info;
+} __attribute__ ((packed)) mraid_adapinfo_t;
+
+
+/**
+ * mraid_ldrv_info_t - information about the logical drives
+ * @nldrv	: Number of logical drives configured
+ * @rsvd	:
+ * @size	: size of each logical drive
+ * @prop	:
+ * @state	: state of each logical drive
+ */
+typedef struct {
+	uint8_t		nldrv;
+	uint8_t		rsvd[3];
+	uint32_t	size[MAX_LOGICAL_DRIVES_8LD];
+	uint8_t		prop[MAX_LOGICAL_DRIVES_8LD];
+	uint8_t		state[MAX_LOGICAL_DRIVES_8LD];
+} __attribute__ ((packed)) mraid_ldrv_info_t;
+
+
+/**
+ * mraid_pdrv_info_t - information about the physical drives
+ * @pdrv_state	: state of each physical drive
+ */
+typedef struct {
+	uint8_t		pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
+	uint8_t		rsvd;
+} __attribute__ ((packed)) mraid_pdrv_info_t;
+
+
+/**
+ * mraid_inquiry_t - RAID inquiry, mailbox command 0x05
+ * @mraid_adapinfo_t	: adapter information
+ * @mraid_ldrv_info_t	: logical drives information
+ * @mraid_pdrv_info_t	: physical drives information
+ */
+typedef struct {
+	mraid_adapinfo_t	adapter_info;
+	mraid_ldrv_info_t	logdrv_info;
+	mraid_pdrv_info_t	pdrv_info;
+} __attribute__ ((packed)) mraid_inquiry_t;
+
+
+/**
+ * mraid_extinq_t - RAID extended inquiry, mailbox command 0x04
+ *
+ * @raid_inq		: raid inquiry
+ * @phys_drv_format	:
+ * @stack_attn		:
+ * @modem_status	:
+ * @rsvd		:
+ */
+typedef struct {
+	mraid_inquiry_t	raid_inq;
+	uint16_t	phys_drv_format[MAX_MBOX_CHANNELS];
+	uint8_t		stack_attn;
+	uint8_t		modem_status;
+	uint8_t		rsvd[2];
+} __attribute__ ((packed)) mraid_extinq_t;
+
+
+/**
+ * adap_device_t - device information
+ * @channel	: channel fpor the device
+ * @target	: target ID of the device
+ */
+typedef struct {
+	uint8_t		channel;
+	uint8_t		target;
+}__attribute__ ((packed)) adap_device_t;
+
+
+/**
+ * adap_span_40ld_t - 40LD span
+ * @start_blk	: starting block
+ * @num_blks	: number of blocks
+ */
+typedef struct {
+	uint32_t	start_blk;
+	uint32_t	num_blks;
+	adap_device_t	device[MAX_ROW_SIZE_40LD];
+}__attribute__ ((packed)) adap_span_40ld_t;
+
+
+/**
+ * adap_span_8ld_t - 8LD span
+ * @start_blk	: starting block
+ * @num_blks	: number of blocks
+ */
+typedef struct {
+	uint32_t	start_blk;
+	uint32_t	num_blks;
+	adap_device_t	device[MAX_ROW_SIZE_8LD];
+}__attribute__ ((packed)) adap_span_8ld_t;
+
+
+/**
+ * logdrv_param_t - logical drives parameters
+ *
+ * @span_depth	: total number of spans
+ * @level	: RAID level
+ * @read_ahead	: read ahead, no read ahead, adaptive read ahead
+ * @stripe_sz	: encoded stripe size
+ * @status	: status of the logical drive
+ * @write_mode	: write mode, write_through/write_back
+ * @direct_io	: direct io or through cache
+ * @row_size	: number of stripes in a row
+ */
+typedef struct {
+	uint8_t		span_depth;
+	uint8_t		level;
+	uint8_t		read_ahead;
+	uint8_t		stripe_sz;
+	uint8_t		status;
+	uint8_t		write_mode;
+	uint8_t		direct_io;
+	uint8_t		row_size;
+} __attribute__ ((packed)) logdrv_param_t;
+
+
+/**
+ * logdrv_40ld_t - logical drive definition for 40LD controllers
+ * @lparam	: logical drives parameters
+ * @span	: span
+ */
+typedef struct {
+	logdrv_param_t		lparam;
+	adap_span_40ld_t	span[SPAN_DEPTH_8_SPANS];
+}__attribute__ ((packed)) logdrv_40ld_t;
+
+
+/**
+ * logdrv_8ld_span8_t - logical drive definition for 8LD controllers
+ * @lparam	: logical drives parameters
+ * @span	: span
+ *
+ * 8-LD logical drive with upto 8 spans
+ */
+typedef struct {
+	logdrv_param_t	lparam;
+	adap_span_8ld_t	span[SPAN_DEPTH_8_SPANS];
+}__attribute__ ((packed)) logdrv_8ld_span8_t;
+
+
+/**
+ * logdrv_8ld_span4_t - logical drive definition for 8LD controllers
+ * @lparam	: logical drives parameters
+ * @span	: span
+ *
+ * 8-LD logical drive with upto 4 spans
+ */
+typedef struct {
+	logdrv_param_t	lparam;
+	adap_span_8ld_t	span[SPAN_DEPTH_4_SPANS];
+}__attribute__ ((packed)) logdrv_8ld_span4_t;
+
+
+/**
+ * phys_drive_t - physical device information
+ * @type	: Type of the device
+ * @cur_status	: current status of the device
+ * @tag_depth	: Level of tagging
+ * @sync_neg	: sync negotiation - ENABLE or DISBALE
+ * @size	: configurable size in terms of 512 byte
+ */
+typedef struct {
+	uint8_t		type;
+	uint8_t		cur_status;
+	uint8_t		tag_depth;
+	uint8_t		sync_neg;
+	uint32_t	size;
+}__attribute__ ((packed)) phys_drive_t;
+
+
+/**
+ * disk_array_40ld_t - disk array for 40LD controllers
+ * @numldrv	: number of logical drives
+ * @resvd	:
+ * @ldrv	: logical drives information
+ * @pdrv	: physical drives information
+ */
+typedef struct {
+	uint8_t		numldrv;
+	uint8_t		resvd[3];
+	logdrv_40ld_t	ldrv[MAX_LOGICAL_DRIVES_40LD];
+	phys_drive_t	pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_40ld_t;
+
+
+/**
+ * disk_array_8ld_span8_t - disk array for 8LD controllers
+ * @numldrv	: number of logical drives
+ * @resvd	:
+ * @ldrv	: logical drives information
+ * @pdrv	: physical drives information
+ *
+ * Disk array for 8LD logical drives with upto 8 spans
+ */
+typedef struct {
+	uint8_t			numldrv;
+	uint8_t			resvd[3];
+	logdrv_8ld_span8_t	ldrv[MAX_LOGICAL_DRIVES_8LD];
+	phys_drive_t		pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_8ld_span8_t;
+
+
+/**
+ * disk_array_8ld_span4_t - disk array for 8LD controllers
+ * @numldrv	: number of logical drives
+ * @resvd	:
+ * @ldrv	: logical drives information
+ * @pdrv	: physical drives information
+ *
+ * Disk array for 8LD logical drives with upto 4 spans
+ */
+typedef struct {
+	uint8_t			numldrv;
+	uint8_t			resvd[3];
+	logdrv_8ld_span4_t	ldrv[MAX_LOGICAL_DRIVES_8LD];
+	phys_drive_t		pdrv[MBOX_MAX_PHYSICAL_DRIVES];
+}__attribute__ ((packed)) disk_array_8ld_span4_t;
+
+
+/**
+ * private_bios_data - bios private data for boot devices
+ * @geometry	: bits 0-3 - BIOS geometry, 0x0001 - 1GB, 0x0010 - 2GB,
+ *		0x1000 - 8GB, Others values are invalid
+ * @unused	: bits 4-7 are unused
+ * @boot_drv	: logical drive set as boot drive, 0..7 - for 8LD cards,
+ * 		0..39 - for 40LD cards
+ * @cksum	: 0-(sum of first 13 bytes of this structure)
+ */
+struct private_bios_data {
+	uint8_t		geometry	:4;
+	uint8_t		unused		:4;
+	uint8_t		boot_drv;
+	uint8_t		rsvd[12];
+	uint16_t	cksum;
+} __attribute__ ((packed));
+
+
+/**
+ * mbox_sgl64 - 64-bit scatter list for mailbox based controllers
+ * @address	: address of the buffer
+ * @length	: data transfer length
+ */
+typedef struct {
+	uint64_t	address;
+	uint32_t	length;
+} __attribute__ ((packed)) mbox_sgl64;
+
+/**
+ * mbox_sgl32 - 32-bit scatter list for mailbox based controllers
+ * @address	: address of the buffer
+ * @length	: data transfer length
+ */
+typedef struct {
+	uint32_t	address;
+	uint32_t	length;
+} __attribute__ ((packed)) mbox_sgl32;
+
+#endif		// _MRAID_MBOX_DEFS_H_
+
+/* vim: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid/mega_common.h b/drivers/scsi/megaraid/mega_common.h
new file mode 100644
index 0000000..18969a4
--- /dev/null
+++ b/drivers/scsi/megaraid/mega_common.h
@@ -0,0 +1,286 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: mega_common.h
+ *
+ * Libaray of common routine used by all low-level megaraid drivers
+ */
+
+#ifndef _MEGA_COMMON_H_
+#define _MEGA_COMMON_H_
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/list.h>
+#include <linux/version.h>
+#include <linux/moduleparam.h>
+#include <asm/semaphore.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+
+#define LSI_MAX_CHANNELS		16
+#define LSI_MAX_LOGICAL_DRIVES_64LD	(64+1)
+
+
+/**
+ * scb_t - scsi command control block
+ * @param ccb		: command control block for individual driver
+ * @param list		: list of control blocks
+ * @param gp		: general purpose field for LLDs
+ * @param sno		: all SCBs have a serial number
+ * @param scp		: associated scsi command
+ * @param state		: current state of scb
+ * @param dma_dir	: direction of data transfer
+ * @param dma_type	: transfer with sg list, buffer, or no data transfer
+ * @param dev_channel	: actual channel on the device
+ * @param dev_target	: actual target on the device
+ * @param status	: completion status
+ *
+ * This is our central data structure to issue commands the each driver.
+ * Driver specific data structures are maintained in the ccb field.
+ * scb provides a field 'gp', which can be used by LLD for its own purposes
+ *
+ * dev_channel and dev_target must be initialized with the actual channel and
+ * target on the controller.
+ */
+typedef struct {
+	caddr_t			ccb;
+	struct list_head	list;
+	unsigned long		gp;
+	unsigned int		sno;
+	struct scsi_cmnd	*scp;
+	uint32_t		state;
+	uint32_t		dma_direction;
+	uint32_t		dma_type;
+	uint16_t		dev_channel;
+	uint16_t		dev_target;
+	uint32_t		status;
+} scb_t;
+
+/*
+ * SCB states as it transitions from one state to another
+ */
+#define SCB_FREE	0x0000	/* on the free list */
+#define SCB_ACTIVE	0x0001	/* off the free list */
+#define SCB_PENDQ	0x0002	/* on the pending queue */
+#define SCB_ISSUED	0x0004	/* issued - owner f/w */
+#define SCB_ABORT	0x0008	/* Got an abort for this one */
+#define SCB_RESET	0x0010	/* Got a reset for this one */
+
+/*
+ * DMA types for scb
+ */
+#define MRAID_DMA_NONE	0x0000	/* no data transfer for this command */
+#define MRAID_DMA_WSG	0x0001	/* data transfer using a sg list */
+#define MRAID_DMA_WBUF	0x0002	/* data transfer using a contiguous buffer */
+
+
+/**
+ * struct adapter_t - driver's initialization structure
+ * @param dpc_h			: tasklet handle
+ * @param pdev			: pci configuration pointer for kernel
+ * @param host			: pointer to host structure of mid-layer
+ * @param host_lock		: pointer to appropriate lock
+ * @param lock			: synchronization lock for mid-layer and driver
+ * @param quiescent		: driver is quiescent for now.
+ * @param outstanding_cmds	: number of commands pending in the driver
+ * @param kscb_list		: pointer to the bulk of SCBs pointers for IO
+ * @param kscb_pool		: pool of free scbs for IO
+ * @param kscb_pool_lock	: lock for pool of free scbs
+ * @param pend_list		: pending commands list
+ * @param pend_list_lock	: exlusion lock for pending commands list
+ * @param completed_list	: list of completed commands
+ * @param completed_list_lock	: exclusion lock for list of completed commands
+ * @param sglen			: max sg elements supported
+ * @param device_ids		: to convert kernel device addr to our devices.
+ * @param raid_device		: raid adapter specific pointer
+ * @param max_channel		: maximum channel number supported - inclusive
+ * @param max_target		: max target supported - inclusive
+ * @param max_lun		: max lun supported - inclusive
+ * @param unique_id		: unique identifier for each adapter
+ * @param irq			: IRQ for this adapter
+ * @param ito			: internal timeout value, (-1) means no timeout
+ * @param ibuf			: buffer to issue internal commands
+ * @param ibuf_dma_h		: dma handle for the above buffer
+ * @param uscb_list		: SCB pointers for user cmds, common mgmt module
+ * @param uscb_pool		: pool of SCBs for user commands
+ * @param uscb_pool_lock	: exclusion lock for these SCBs
+ * @param max_cmds		: max outstanding commands
+ * @param fw_version		: firmware version
+ * @param bios_version		: bios version
+ * @param max_cdb_sz		: biggest CDB size supported.
+ * @param ha			: is high availability present - clustering
+ * @param init_id		: initiator ID, the default value should be 7
+ * @param max_sectors		: max sectors per request
+ * @param cmd_per_lun		: max outstanding commands per LUN
+ * @param being_detached	: set when unloading, no more mgmt calls
+ *
+ *
+ * mraid_setup_device_map() can be called anytime after the device map is
+ * available and MRAID_GET_DEVICE_MAP() can be called whenever the mapping is
+ * required, usually from LLD's queue entry point. The formar API sets up the
+ * MRAID_IS_LOGICAL(adapter_t *, struct scsi_cmnd *) to find out if the
+ * device in question is a logical drive.
+ *
+ * quiescent flag should be set by the driver if it is not accepting more
+ * commands
+ *
+ * NOTE: The fields of this structures are placed to minimize cache misses
+ */
+
+// amount of space required to store the bios and firmware version strings
+#define VERSION_SIZE	16
+
+typedef struct {
+	struct tasklet_struct	dpc_h;
+	struct pci_dev		*pdev;
+	struct Scsi_Host	*host;
+	spinlock_t		*host_lock;
+	spinlock_t		lock;
+	uint8_t			quiescent;
+	int			outstanding_cmds;
+	scb_t			*kscb_list;
+	struct list_head	kscb_pool;
+	spinlock_t		kscb_pool_lock;
+	struct list_head	pend_list;
+	spinlock_t		pend_list_lock;
+	struct list_head	completed_list;
+	spinlock_t		completed_list_lock;
+	uint16_t		sglen;
+	int			device_ids[LSI_MAX_CHANNELS]
+					[LSI_MAX_LOGICAL_DRIVES_64LD];
+	caddr_t			raid_device;
+	uint8_t			max_channel;
+	uint16_t		max_target;
+	uint8_t			max_lun;
+
+	uint32_t		unique_id;
+	uint8_t			irq;
+	uint8_t			ito;
+	caddr_t			ibuf;
+	dma_addr_t		ibuf_dma_h;
+	scb_t			*uscb_list;
+	struct list_head	uscb_pool;
+	spinlock_t		uscb_pool_lock;
+	int			max_cmds;
+	uint8_t			fw_version[VERSION_SIZE];
+	uint8_t			bios_version[VERSION_SIZE];
+	uint8_t			max_cdb_sz;
+	uint8_t			ha;
+	uint16_t		init_id;
+	uint16_t		max_sectors;
+	uint16_t		cmd_per_lun;
+	atomic_t		being_detached;
+} adapter_t;
+
+#define SCSI_FREE_LIST_LOCK(adapter)	(&adapter->kscb_pool_lock)
+#define USER_FREE_LIST_LOCK(adapter)	(&adapter->uscb_pool_lock)
+#define PENDING_LIST_LOCK(adapter)	(&adapter->pend_list_lock)
+#define COMPLETED_LIST_LOCK(adapter)	(&adapter->completed_list_lock)
+
+
+// conversion from scsi command
+#define SCP2HOST(scp)			(scp)->device->host	// to host
+#define SCP2HOSTDATA(scp)		SCP2HOST(scp)->hostdata	// to soft state
+#define SCP2CHANNEL(scp)		(scp)->device->channel	// to channel
+#define SCP2TARGET(scp)			(scp)->device->id	// to target
+#define SCP2LUN(scp)			(scp)->device->lun	// to LUN
+
+// generic macro to convert scsi command and host to controller's soft state
+#define SCSIHOST2ADAP(host)	(((caddr_t *)(host->hostdata))[0])
+#define SCP2ADAPTER(scp)	(adapter_t *)SCSIHOST2ADAP(SCP2HOST(scp))
+
+
+/**
+ * MRAID_GET_DEVICE_MAP - device ids
+ * @param adp		- Adapter's soft state
+ * @param scp		- mid-layer scsi command pointer
+ * @param p_chan	- physical channel on the controller
+ * @param target	- target id of the device or logical drive number
+ * @param islogical	- set if the command is for the logical drive
+ *
+ * Macro to retrieve information about device class, logical or physical and
+ * the corresponding physical channel and target or logical drive number
+ **/
+#define MRAID_IS_LOGICAL(adp, scp)	\
+	(SCP2CHANNEL(scp) == (adp)->max_channel) ? 1 : 0
+
+#define MRAID_IS_LOGICAL_SDEV(adp, sdev)	\
+	(sdev->channel == (adp)->max_channel) ? 1 : 0
+
+#define MRAID_GET_DEVICE_MAP(adp, scp, p_chan, target, islogical)	\
+	/*								\
+	 * Is the request coming for the virtual channel		\
+	 */								\
+	islogical = MRAID_IS_LOGICAL(adp, scp);				\
+									\
+	/*								\
+	 * Get an index into our table of drive ids mapping		\
+	 */								\
+	if (islogical) {						\
+		p_chan = 0xFF;						\
+		target =						\
+		(adp)->device_ids[(adp)->max_channel][SCP2TARGET(scp)];	\
+	}								\
+	else {								\
+		p_chan = ((adp)->device_ids[SCP2CHANNEL(scp)]		\
+					[SCP2TARGET(scp)] >> 8) & 0xFF;	\
+		target = ((adp)->device_ids[SCP2CHANNEL(scp)]		\
+					[SCP2TARGET(scp)] & 0xFF);	\
+	}
+
+/*
+ * ### Helper routines ###
+ */
+#define LSI_DBGLVL mraid_debug_level	// each LLD must define a global
+ 					// mraid_debug_level
+
+#ifdef DEBUG
+#if defined (_ASSERT_PANIC)
+#define ASSERT_ACTION	panic
+#else
+#define ASSERT_ACTION	printk
+#endif
+
+#define ASSERT(expression)						\
+	if (!(expression)) {						\
+	ASSERT_ACTION("assertion failed:(%s), file: %s, line: %d:%s\n",	\
+			#expression, __FILE__, __LINE__, __FUNCTION__);	\
+	}
+#else
+#define ASSERT(expression)
+#endif
+
+/*
+ * struct mraid_pci_blk - structure holds DMA memory block info
+ * @param vaddr		: virtual address to a memory block
+ * @param dma_addr	: DMA handle to a memory block
+ *
+ * This structure is filled up for the caller. It is the responsibilty of the
+ * caller to allocate this array big enough to store addresses for all
+ * requested elements
+ */
+struct mraid_pci_blk {
+	caddr_t		vaddr;
+	dma_addr_t	dma_addr;
+};
+
+#endif // _MEGA_COMMON_H_
+
+// vim: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/megaraid/megaraid_ioctl.h b/drivers/scsi/megaraid/megaraid_ioctl.h
new file mode 100644
index 0000000..bdaee14
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_ioctl.h
@@ -0,0 +1,296 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_ioctl.h
+ *
+ * Definitions to interface with user level applications
+ */
+
+#ifndef _MEGARAID_IOCTL_H_
+#define _MEGARAID_IOCTL_H_
+
+#include <linux/types.h>
+#include <asm/semaphore.h>
+
+#include "mbox_defs.h"
+
+/**
+ * con_log() - console log routine
+ * @param level		: indicates the severity of the message.
+ * @fparam mt		: format string
+ *
+ * con_log displays the error messages on the console based on the current
+ * debug level. Also it attaches the appropriate kernel severity level with
+ * the message.
+ *
+ *
+ * consolge messages debug levels
+ */
+#define	CL_ANN		0	/* print unconditionally, announcements */
+#define CL_DLEVEL1	1	/* debug level 1, informative */
+#define CL_DLEVEL2	2	/* debug level 2, verbose */
+#define CL_DLEVEL3	3	/* debug level 3, very verbose */
+
+#define	con_log(level, fmt) if (LSI_DBGLVL >= level) printk fmt;
+
+/*
+ * Definitions & Declarations needed to use common management module
+ */
+
+#define MEGAIOC_MAGIC		'm'
+#define MEGAIOCCMD		_IOWR(MEGAIOC_MAGIC, 0, mimd_t)
+
+#define MEGAIOC_QNADAP		'm'	/* Query # of adapters		*/
+#define MEGAIOC_QDRVRVER	'e'	/* Query driver version		*/
+#define MEGAIOC_QADAPINFO   	'g'	/* Query adapter information	*/
+
+#define USCSICMD		0x80
+#define UIOC_RD			0x00001
+#define UIOC_WR			0x00002
+
+#define MBOX_CMD		0x00000
+#define GET_DRIVER_VER		0x10000
+#define GET_N_ADAP		0x20000
+#define GET_ADAP_INFO		0x30000
+#define GET_CAP			0x40000
+#define GET_STATS		0x50000
+#define GET_IOCTL_VERSION	0x01
+
+#define EXT_IOCTL_SIGN_SZ	16
+#define EXT_IOCTL_SIGN		"$$_EXTD_IOCTL_$$"
+
+#define	MBOX_LEGACY		0x00		/* ioctl has legacy mbox*/
+#define MBOX_HPE		0x01		/* ioctl has hpe mbox	*/
+
+#define	APPTYPE_MIMD		0x00		/* old existing apps	*/
+#define APPTYPE_UIOC		0x01		/* new apps using uioc	*/
+
+#define IOCTL_ISSUE		0x00000001	/* Issue ioctl		*/
+#define IOCTL_ABORT		0x00000002	/* Abort previous ioctl	*/
+
+#define DRVRTYPE_MBOX		0x00000001	/* regular mbox driver	*/
+#define DRVRTYPE_HPE		0x00000002	/* new hpe driver	*/
+
+#define MKADAP(adapno)	(MEGAIOC_MAGIC << 8 | (adapno) )
+#define GETADAP(mkadap)	((mkadap) ^ MEGAIOC_MAGIC << 8)
+
+#define MAX_DMA_POOLS		5		/* 4k, 8k, 16k, 32k, 64k*/
+
+
+/**
+ * struct uioc_t - the common ioctl packet structure
+ *
+ * @signature	: Must be "$$_EXTD_IOCTL_$$"
+ * @mb_type	: Type of the mail box (MB_LEGACY or MB_HPE)
+ * @app_type	: Type of the issuing application (existing or new)
+ * @opcode	: Opcode of the command
+ * @adapno	: Adapter number
+ * @cmdbuf	: Pointer to buffer - can point to mbox or plain data buffer
+ * @xferlen	: xferlen for DCMD and non mailbox commands
+ * @data_dir	: Direction of the data transfer
+ * @status	: Status from the driver
+ * @reserved	: reserved bytes for future expansion
+ *
+ * @user_data	: user data transfer address is saved in this
+ * @user_data_len: length of the data buffer sent by user app
+ * @user_pthru	: user passthru address is saves in this (null if DCMD)
+ * @pthru32	: kernel address passthru (allocated per kioc)
+ * @pthru32_h	: physicall address of @pthru32
+ * @list	: for kioc free pool list maintenance
+ * @done	: call back routine for llds to call when kioc is completed
+ * @buf_vaddr	: dma pool buffer attached to kioc for data transfer
+ * @buf_paddr	: physical address of the dma pool buffer
+ * @pool_index	: index of the dma pool that @buf_vaddr is taken from
+ * @free_buf	: indicates if buffer needs to be freed after kioc completes
+ *
+ * Note		: All LSI drivers understand only this packet. Any other
+ *		: format sent by applications would be converted to this.
+ */
+typedef struct uioc {
+
+/* User Apps: */
+
+	uint8_t			signature[EXT_IOCTL_SIGN_SZ];
+	uint16_t		mb_type;
+	uint16_t		app_type;
+	uint32_t		opcode;
+	uint32_t		adapno;
+	uint64_t		cmdbuf;
+	uint32_t		xferlen;
+	uint32_t		data_dir;
+	int32_t			status;
+	uint8_t			reserved[128];
+
+/* Driver Data: */
+	void __user *		user_data;
+	uint32_t		user_data_len;
+	mraid_passthru_t	__user *user_pthru;
+
+	mraid_passthru_t	*pthru32;
+	dma_addr_t		pthru32_h;
+
+	struct list_head	list;
+	void			(*done)(struct uioc*);
+
+	caddr_t			buf_vaddr;
+	dma_addr_t		buf_paddr;
+	int8_t			pool_index;
+	uint8_t			free_buf;
+
+	uint8_t			timedout;
+
+} __attribute__ ((aligned(1024),packed)) uioc_t;
+
+
+/**
+ * struct mraid_hba_info - information about the controller
+ *
+ * @param pci_vendor_id		: PCI vendor id
+ * @param pci_device_id		: PCI device id
+ * @param subsystem_vendor_id	: PCI subsystem vendor id
+ * @param subsystem_device_id	: PCI subsystem device id
+ * @param baseport		: base port of hba memory
+ * @param pci_bus		: PCI bus
+ * @param pci_dev_fn		: PCI device/function values
+ * @param irq			: interrupt vector for the device
+ *
+ * Extended information of 256 bytes about the controller. Align on the single
+ * byte boundary so that 32-bit applications can be run on 64-bit platform
+ * drivers withoug re-compilation.
+ * NOTE: reduce the number of reserved bytes whenever new field are added, so
+ * that total size of the structure remains 256 bytes.
+ */
+typedef struct mraid_hba_info {
+
+	uint16_t	pci_vendor_id;
+	uint16_t	pci_device_id;
+	uint16_t	subsys_vendor_id;
+	uint16_t	subsys_device_id;
+
+	uint64_t	baseport;
+	uint8_t		pci_bus;
+	uint8_t		pci_dev_fn;
+	uint8_t		pci_slot;
+	uint8_t		irq;
+
+	uint32_t	unique_id;
+	uint32_t	host_no;
+
+	uint8_t		num_ldrv;
+} __attribute__ ((aligned(256), packed)) mraid_hba_info_t;
+
+
+/**
+ * mcontroller	: adapter info structure for old mimd_t apps
+ *
+ * @base	: base address
+ * @irq		: irq number
+ * @numldrv	: number of logical drives
+ * @pcibus	: pci bus
+ * @pcidev	: pci device
+ * @pcifun	: pci function
+ * @pciid	: pci id
+ * @pcivendor	: vendor id
+ * @pcislot	: slot number
+ * @uid		: unique id
+ */
+typedef struct mcontroller {
+
+	uint64_t	base;
+	uint8_t		irq;
+	uint8_t		numldrv;
+	uint8_t		pcibus;
+	uint16_t	pcidev;
+	uint8_t		pcifun;
+	uint16_t	pciid;
+	uint16_t	pcivendor;
+	uint8_t		pcislot;
+	uint32_t	uid;
+
+} __attribute__ ((packed)) mcontroller_t;
+
+
+/**
+ * mm_dmapool_t	: Represents one dma pool with just one buffer
+ *
+ * @vaddr	: Virtual address
+ * @paddr	: DMA physicall address
+ * @bufsize	: In KB - 4 = 4k, 8 = 8k etc.
+ * @handle	: Handle to the dma pool
+ * @lock	: lock to synchronize access to the pool
+ * @in_use	: If pool already in use, attach new block
+ */
+typedef struct mm_dmapool {
+	caddr_t		vaddr;
+	dma_addr_t	paddr;
+	uint32_t	buf_size;
+	struct dma_pool	*handle;
+	spinlock_t	lock;
+	uint8_t		in_use;
+} mm_dmapool_t;
+
+
+/**
+ * mraid_mmadp_t: Structure that drivers pass during (un)registration
+ *
+ * @unique_id		: Any unique id (usually PCI bus+dev+fn)
+ * @drvr_type		: megaraid or hpe (DRVRTYPE_MBOX or DRVRTYPE_HPE)
+ * @drv_data		: Driver specific; not touched by the common module
+ * @timeout		: timeout for issued kiocs
+ * @max_kioc		: Maximum ioctl packets acceptable by the lld
+ * @pdev		: pci dev; used for allocating dma'ble memory
+ * @issue_uioc		: Driver supplied routine to issue uioc_t commands
+ *			: issue_uioc(drvr_data, kioc, ISSUE/ABORT, uioc_done)
+ * @quiescent		: flag to indicate if ioctl can be issued to this adp
+ * @list		: attach with the global list of adapters
+ * @kioc_list		: block of mem for @max_kioc number of kiocs
+ * @kioc_pool		: pool of free kiocs
+ * @kioc_pool_lock	: protection for free pool
+ * @kioc_semaphore	: so as not to exceed @max_kioc parallel ioctls
+ * @mbox_list		: block of mem for @max_kioc number of mboxes
+ * @pthru_dma_pool	: DMA pool to allocate passthru packets
+ * @dma_pool_list	: array of dma pools
+ */
+
+typedef struct mraid_mmadp {
+
+/* Filled by driver */
+
+	uint32_t		unique_id;
+	uint32_t		drvr_type;
+	unsigned long		drvr_data;
+	uint16_t		timeout;
+	uint8_t			max_kioc;
+
+	struct pci_dev		*pdev;
+
+	int(*issue_uioc)(unsigned long, uioc_t *, uint32_t);
+
+/* Maintained by common module */
+	uint32_t		quiescent;
+
+	struct list_head	list;
+	uioc_t			*kioc_list;
+	struct list_head	kioc_pool;
+	spinlock_t		kioc_pool_lock;
+	struct semaphore	kioc_semaphore;
+
+	mbox64_t		*mbox_list;
+	struct dma_pool		*pthru_dma_pool;
+	mm_dmapool_t		dma_pool_list[MAX_DMA_POOLS];
+
+} mraid_mmadp_t;
+
+int mraid_mm_register_adp(mraid_mmadp_t *);
+int mraid_mm_unregister_adp(uint32_t);
+uint32_t mraid_mm_adapter_app_handle(uint32_t);
+
+#endif /* _MEGARAID_IOCTL_H_ */
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
new file mode 100644
index 0000000..138fa48
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -0,0 +1,4276 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_mbox.c
+ * Version	: v2.20.4.5 (Feb 03 2005)
+ *
+ * Authors:
+ * 	Atul Mukker		<Atul.Mukker@lsil.com>
+ * 	Sreenivas Bagalkote	<Sreenivas.Bagalkote@lsil.com>
+ * 	Manoj Jose		<Manoj.Jose@lsil.com>
+ *
+ * List of supported controllers
+ *
+ * OEM	Product Name			VID	DID	SSVID	SSID
+ * ---	------------			---	---	----	----
+ * Dell PERC3/QC			101E	1960	1028	0471
+ * Dell PERC3/DC			101E	1960	1028	0493
+ * Dell PERC3/SC			101E	1960	1028	0475
+ * Dell PERC3/Di			1028	1960	1028	0123
+ * Dell PERC4/SC			1000	1960	1028	0520
+ * Dell PERC4/DC			1000	1960	1028	0518
+ * Dell PERC4/QC			1000	0407	1028	0531
+ * Dell PERC4/Di			1028	000F	1028	014A
+ * Dell PERC 4e/Si			1028	0013	1028	016c
+ * Dell PERC 4e/Di			1028	0013	1028	016d
+ * Dell PERC 4e/Di			1028	0013	1028	016e
+ * Dell PERC 4e/Di			1028	0013	1028	016f
+ * Dell PERC 4e/Di			1028	0013	1028	0170
+ * Dell PERC 4e/DC			1000	0408	1028	0002
+ * Dell PERC 4e/SC			1000	0408	1028	0001
+ *
+ *
+ * LSI MegaRAID SCSI 320-0		1000	1960	1000	A520
+ * LSI MegaRAID SCSI 320-1		1000	1960	1000	0520
+ * LSI MegaRAID SCSI 320-2		1000	1960	1000	0518
+ * LSI MegaRAID SCSI 320-0X		1000	0407	1000	0530
+ * LSI MegaRAID SCSI 320-2X		1000	0407	1000	0532
+ * LSI MegaRAID SCSI 320-4X		1000	0407	1000	0531
+ * LSI MegaRAID SCSI 320-1E		1000	0408	1000	0001
+ * LSI MegaRAID SCSI 320-2E		1000	0408	1000	0002
+ * LSI MegaRAID SATA 150-4		1000	1960	1000	4523
+ * LSI MegaRAID SATA 150-6		1000	1960	1000	0523
+ * LSI MegaRAID SATA 300-4X		1000	0409	1000	3004
+ * LSI MegaRAID SATA 300-8X		1000	0409	1000	3008
+ *
+ * INTEL RAID Controller SRCU42X	1000	0407	8086	0532
+ * INTEL RAID Controller SRCS16		1000	1960	8086	0523
+ * INTEL RAID Controller SRCU42E	1000	0408	8086	0002
+ * INTEL RAID Controller SRCZCRX	1000	0407	8086	0530
+ * INTEL RAID Controller SRCS28X	1000	0409	8086	3008
+ * INTEL RAID Controller SROMBU42E	1000	0408	8086	3431
+ * INTEL RAID Controller SROMBU42E	1000	0408	8086	3499
+ * INTEL RAID Controller SRCU51L	1000	1960	8086	0520
+ *
+ * FSC	MegaRAID PCI Express ROMB	1000	0408	1734	1065
+ *
+ * ACER	MegaRAID ROMB-2E		1000	0408	1025	004D
+ *
+ * NEC	MegaRAID PCI Express ROMB	1000	0408	1033	8287
+ *
+ * For history of changes, see Documentation/ChangeLog.megaraid
+ */
+
+#include "megaraid_mbox.h"
+
+static int megaraid_init(void);
+static void megaraid_exit(void);
+
+static int megaraid_probe_one(struct pci_dev*, const struct pci_device_id *);
+static void megaraid_detach_one(struct pci_dev *);
+static void megaraid_mbox_shutdown(struct device *);
+
+static int megaraid_io_attach(adapter_t *);
+static void megaraid_io_detach(adapter_t *);
+
+static int megaraid_init_mbox(adapter_t *);
+static void megaraid_fini_mbox(adapter_t *);
+
+static int megaraid_alloc_cmd_packets(adapter_t *);
+static void megaraid_free_cmd_packets(adapter_t *);
+
+static int megaraid_mbox_setup_dma_pools(adapter_t *);
+static void megaraid_mbox_teardown_dma_pools(adapter_t *);
+
+static int megaraid_sysfs_alloc_resources(adapter_t *);
+static void megaraid_sysfs_free_resources(adapter_t *);
+
+static int megaraid_abort_handler(struct scsi_cmnd *);
+static int megaraid_reset_handler(struct scsi_cmnd *);
+
+static int mbox_post_sync_cmd(adapter_t *, uint8_t []);
+static int mbox_post_sync_cmd_fast(adapter_t *, uint8_t []);
+static int megaraid_busywait_mbox(mraid_device_t *);
+static int megaraid_mbox_product_info(adapter_t *);
+static int megaraid_mbox_extended_cdb(adapter_t *);
+static int megaraid_mbox_support_ha(adapter_t *, uint16_t *);
+static int megaraid_mbox_support_random_del(adapter_t *);
+static int megaraid_mbox_get_max_sg(adapter_t *);
+static void megaraid_mbox_enum_raid_scsi(adapter_t *);
+static void megaraid_mbox_flush_cache(adapter_t *);
+
+static void megaraid_mbox_display_scb(adapter_t *, scb_t *);
+static void megaraid_mbox_setup_device_map(adapter_t *);
+
+static int megaraid_queue_command(struct scsi_cmnd *,
+		void (*)(struct scsi_cmnd *));
+static scb_t *megaraid_mbox_build_cmd(adapter_t *, struct scsi_cmnd *, int *);
+static void megaraid_mbox_runpendq(adapter_t *, scb_t *);
+static void megaraid_mbox_prepare_pthru(adapter_t *, scb_t *,
+		struct scsi_cmnd *);
+static void megaraid_mbox_prepare_epthru(adapter_t *, scb_t *,
+		struct scsi_cmnd *);
+
+static irqreturn_t megaraid_isr(int, void *, struct pt_regs *);
+
+static void megaraid_mbox_dpc(unsigned long);
+
+static ssize_t megaraid_sysfs_show_app_hndl(struct class_device *, char *);
+static ssize_t megaraid_sysfs_show_ldnum(struct device *, char *);
+
+static int megaraid_cmm_register(adapter_t *);
+static int megaraid_cmm_unregister(adapter_t *);
+static int megaraid_mbox_mm_handler(unsigned long, uioc_t *, uint32_t);
+static int megaraid_mbox_mm_command(adapter_t *, uioc_t *);
+static void megaraid_mbox_mm_done(adapter_t *, scb_t *);
+static int gather_hbainfo(adapter_t *, mraid_hba_info_t *);
+static int wait_till_fw_empty(adapter_t *);
+
+
+
+MODULE_AUTHOR("LSI Logic Corporation");
+MODULE_DESCRIPTION("LSI Logic MegaRAID Mailbox Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(MEGARAID_VERSION);
+
+/*
+ * ### modules parameters for driver ###
+ */
+
+/**
+ * Set to enable driver to expose unconfigured disk to kernel
+ */
+static int megaraid_expose_unconf_disks = 0;
+module_param_named(unconf_disks, megaraid_expose_unconf_disks, int, 0);
+MODULE_PARM_DESC(unconf_disks,
+	"Set to expose unconfigured disks to kernel (default=0)");
+
+/**
+ * driver wait time if the adapter's mailbox is busy
+ */
+static unsigned int max_mbox_busy_wait = MBOX_BUSY_WAIT;
+module_param_named(busy_wait, max_mbox_busy_wait, int, 0);
+MODULE_PARM_DESC(busy_wait,
+	"Max wait for mailbox in microseconds if busy (default=10)");
+
+/**
+ * number of sectors per IO command
+ */
+static unsigned int megaraid_max_sectors = MBOX_MAX_SECTORS;
+module_param_named(max_sectors, megaraid_max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+	"Maximum number of sectors per IO command (default=128)");
+
+/**
+ * number of commands per logical unit
+ */
+static unsigned int megaraid_cmd_per_lun = MBOX_DEF_CMD_PER_LUN;
+module_param_named(cmd_per_lun, megaraid_cmd_per_lun, int, 0);
+MODULE_PARM_DESC(cmd_per_lun,
+	"Maximum number of commands per logical unit (default=64)");
+
+
+/**
+ * Fast driver load option, skip scanning for physical devices during load.
+ * This would result in non-disk devices being skipped during driver load
+ * time. These can be later added though, using /proc/scsi/scsi
+ */
+static unsigned int megaraid_fast_load = 0;
+module_param_named(fast_load, megaraid_fast_load, int, 0);
+MODULE_PARM_DESC(fast_load,
+	"Faster loading of the driver, skips physical devices! (default=0)");
+
+
+/**
+ * mraid_debug level - threshold for amount of information to be displayed by
+ * the driver. This level can be changed through modules parameters, ioctl or
+ * sysfs/proc interface. By default, print the announcement messages only.
+ */
+int mraid_debug_level = CL_ANN;
+module_param_named(debug_level, mraid_debug_level, int, 0);
+MODULE_PARM_DESC(debug_level, "Debug level for driver (default=0)");
+
+/*
+ * ### global data ###
+ */
+static uint8_t megaraid_mbox_version[8] =
+	{ 0x02, 0x20, 0x04, 0x05, 2, 3, 20, 5 };
+
+
+/*
+ * PCI table for all supported controllers.
+ */
+static struct pci_device_id pci_id_table_g[] =  {
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4_DI_DISCOVERY,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4_DI_DISCOVERY,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_PERC4_SC,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4_SC,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_PERC4_DC,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4_DC,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_PERC4_QC,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4_QC,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4_DI_EVERGLADES,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4_DI_EVERGLADES,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4E_SI_BIGBEND,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_SI_BIGBEND,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4E_DI_KOBUK,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_DI_KOBUK,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4E_DI_CORVETTE,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_DI_CORVETTE,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4E_DI_EXPEDITION,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION,
+	},
+	{
+		PCI_VENDOR_ID_DELL,
+		PCI_DEVICE_ID_PERC4E_DI_GUADALUPE,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_PERC4E_DC_320_2E,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_DC_320_2E,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_PERC4E_SC_320_1E,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC4E_SC_320_1E,
+	},
+	{
+		PCI_VENDOR_ID_AMI,
+		PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC3_QC,
+	},
+	{
+		PCI_VENDOR_ID_AMI,
+		PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC3_DC,
+	},
+	{
+		PCI_VENDOR_ID_AMI,
+		PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_VENDOR_ID_DELL,
+		PCI_SUBSYS_ID_PERC3_SC,
+	},
+	{
+		PCI_VENDOR_ID_AMI,
+		PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_VENDOR_ID_AMI,
+		PCI_SUBSYS_ID_PERC3_SC,
+	},
+	{
+		PCI_VENDOR_ID_AMI,
+		PCI_DEVICE_ID_AMI_MEGARAID3,
+		PCI_VENDOR_ID_AMI,
+		PCI_SUBSYS_ID_PERC3_DC,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_0,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_0,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_1,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_1,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_2,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_2,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_0x,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_2x,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_4x,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_1E,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SCSI_320_2E,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_I4_133_RAID,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_I4_133_RAID,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SATA_150_4,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SATA_150_4,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SATA_150_6,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SATA_150_6,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SATA_300_4x,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SATA_300_4x,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_SATA_300_8x,
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_SUBSYS_ID_MEGARAID_SATA_300_8x,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCU42X,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCU42X,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCS16,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCS16,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCU42E,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCU42E,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCZCRX,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCS28X,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCS28X,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
+		PCI_VENDOR_ID_INTEL,
+		PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
+		PCI_SUBSYS_ID_FSC,
+		PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E,
+		PCI_VENDOR_ID_AI,
+		PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E,
+	},
+	{
+		PCI_VENDOR_ID_LSI_LOGIC,
+		PCI_DEVICE_ID_MEGARAID_NEC_ROMB_2E,
+		PCI_VENDOR_ID_NEC,
+		PCI_SUBSYS_ID_MEGARAID_NEC_ROMB_2E,
+	},
+	{0}	/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(pci, pci_id_table_g);
+
+
+static struct pci_driver megaraid_pci_driver_g = {
+	.name		= "megaraid",
+	.id_table	= pci_id_table_g,
+	.probe		= megaraid_probe_one,
+	.remove		= __devexit_p(megaraid_detach_one),
+	.driver		= {
+		.shutdown	= megaraid_mbox_shutdown,
+	}
+};
+
+
+
+// definitions for the device attributes for exporting logical drive number
+// for a scsi address (Host, Channel, Id, Lun)
+
+CLASS_DEVICE_ATTR(megaraid_mbox_app_hndl, S_IRUSR, megaraid_sysfs_show_app_hndl,
+		NULL);
+
+// Host template initializer for megaraid mbox sysfs device attributes
+static struct class_device_attribute *megaraid_shost_attrs[] = {
+	&class_device_attr_megaraid_mbox_app_hndl,
+	NULL,
+};
+
+
+DEVICE_ATTR(megaraid_mbox_ld, S_IRUSR, megaraid_sysfs_show_ldnum, NULL);
+
+// Host template initializer for megaraid mbox sysfs device attributes
+static struct device_attribute *megaraid_sdev_attrs[] = {
+	&dev_attr_megaraid_mbox_ld,
+	NULL,
+};
+
+
+/*
+ * Scsi host template for megaraid unified driver
+ */
+static struct scsi_host_template megaraid_template_g = {
+	.module				= THIS_MODULE,
+	.name				= "LSI Logic MegaRAID driver",
+	.proc_name			= "megaraid",
+	.queuecommand			= megaraid_queue_command,
+	.eh_abort_handler		= megaraid_abort_handler,
+	.eh_device_reset_handler	= megaraid_reset_handler,
+	.eh_bus_reset_handler		= megaraid_reset_handler,
+	.eh_host_reset_handler		= megaraid_reset_handler,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.sdev_attrs			= megaraid_sdev_attrs,
+	.shost_attrs			= megaraid_shost_attrs,
+};
+
+
+/**
+ * megaraid_init - module load hook
+ *
+ * We register ourselves as hotplug enabled module and let PCI subsystem
+ * discover our adaters
+ **/
+static int __init
+megaraid_init(void)
+{
+	int	rval;
+
+	// Announce the driver version
+	con_log(CL_ANN, (KERN_INFO "megaraid: %s %s\n", MEGARAID_VERSION,
+		MEGARAID_EXT_VERSION));
+
+	// check validity of module parameters
+	if (megaraid_cmd_per_lun > MBOX_MAX_SCSI_CMDS) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mailbox: max commands per lun reset to %d\n",
+			MBOX_MAX_SCSI_CMDS));
+
+		megaraid_cmd_per_lun = MBOX_MAX_SCSI_CMDS;
+	}
+
+
+	// register as a PCI hot-plug driver module
+	if ((rval = pci_module_init(&megaraid_pci_driver_g))) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: could not register hotplug support.\n"));
+	}
+
+	return rval;
+}
+
+
+/**
+ * megaraid_exit - driver unload entry point
+ *
+ * We simply unwrap the megaraid_init routine here
+ */
+static void __exit
+megaraid_exit(void)
+{
+	con_log(CL_DLEVEL1, (KERN_NOTICE "megaraid: unloading framework\n"));
+
+	// unregister as PCI hotplug driver
+	pci_unregister_driver(&megaraid_pci_driver_g);
+
+	return;
+}
+
+
+/**
+ * megaraid_probe_one - PCI hotplug entry point
+ * @param pdev	: handle to this controller's PCI configuration space
+ * @param id	: pci device id of the class of controllers
+ *
+ * This routine should be called whenever a new adapter is detected by the
+ * PCI hotplug susbsytem.
+ **/
+static int __devinit
+megaraid_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	adapter_t	*adapter;
+
+
+	// detected a new controller
+	con_log(CL_ANN, (KERN_INFO
+		"megaraid: probe new device %#4.04x:%#4.04x:%#4.04x:%#4.04x: ",
+		pdev->vendor, pdev->device, pdev->subsystem_vendor,
+		pdev->subsystem_device));
+
+	con_log(CL_ANN, ("bus %d:slot %d:func %d\n", pdev->bus->number,
+		PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)));
+
+	if (pci_enable_device(pdev)) {
+		con_log(CL_ANN, (KERN_WARNING
+				"megaraid: pci_enable_device failed\n"));
+
+		return -ENODEV;
+	}
+
+	// Enable bus-mastering on this controller
+	pci_set_master(pdev);
+
+	// Allocate the per driver initialization structure
+	adapter = kmalloc(sizeof(adapter_t), GFP_KERNEL);
+
+	if (adapter == NULL) {
+		con_log(CL_ANN, (KERN_WARNING
+		"megaraid: out of memory, %s %d.\n", __FUNCTION__, __LINE__));
+
+		goto out_probe_one;
+	}
+	memset(adapter, 0, sizeof(adapter_t));
+
+
+	// set up PCI related soft state and other pre-known parameters
+	adapter->unique_id	= pdev->bus->number << 8 | pdev->devfn;
+	adapter->irq		= pdev->irq;
+	adapter->pdev		= pdev;
+
+	atomic_set(&adapter->being_detached, 0);
+
+	// Setup the default DMA mask. This would be changed later on
+	// depending on hardware capabilities
+	if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFF) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: pci_set_dma_mask failed:%d\n", __LINE__));
+
+		goto out_free_adapter;
+	}
+
+
+	// Initialize the synchronization lock for kernel and LLD
+	spin_lock_init(&adapter->lock);
+	adapter->host_lock = &adapter->lock;
+
+
+	// Initialize the command queues: the list of free SCBs and the list
+	// of pending SCBs.
+	INIT_LIST_HEAD(&adapter->kscb_pool);
+	spin_lock_init(SCSI_FREE_LIST_LOCK(adapter));
+
+	INIT_LIST_HEAD(&adapter->pend_list);
+	spin_lock_init(PENDING_LIST_LOCK(adapter));
+
+	INIT_LIST_HEAD(&adapter->completed_list);
+	spin_lock_init(COMPLETED_LIST_LOCK(adapter));
+
+
+	// Start the mailbox based controller
+	if (megaraid_init_mbox(adapter) != 0) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: maibox adapter did not initialize\n"));
+
+		goto out_free_adapter;
+	}
+
+	// Register with LSI Common Management Module
+	if (megaraid_cmm_register(adapter) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+		"megaraid: could not register with management module\n"));
+
+		goto out_fini_mbox;
+	}
+
+	// setup adapter handle in PCI soft state
+	pci_set_drvdata(pdev, adapter);
+
+	// attach with scsi mid-layer
+	if (megaraid_io_attach(adapter) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING "megaraid: io attach failed\n"));
+
+		goto out_cmm_unreg;
+	}
+
+	return 0;
+
+out_cmm_unreg:
+	pci_set_drvdata(pdev, NULL);
+	megaraid_cmm_unregister(adapter);
+out_fini_mbox:
+	megaraid_fini_mbox(adapter);
+out_free_adapter:
+	kfree(adapter);
+out_probe_one:
+	pci_disable_device(pdev);
+
+	return -ENODEV;
+}
+
+
+/**
+ * megaraid_detach_one - release the framework resources and call LLD release
+ * routine
+ * @param pdev	: handle for our PCI cofiguration space
+ *
+ * This routine is called during driver unload. We free all the allocated
+ * resources and call the corresponding LLD so that it can also release all
+ * its resources.
+ *
+ * This routine is also called from the PCI hotplug system
+ **/
+static void
+megaraid_detach_one(struct pci_dev *pdev)
+{
+	adapter_t		*adapter;
+	struct Scsi_Host	*host;
+
+
+	// Start a rollback on this adapter
+	adapter = pci_get_drvdata(pdev);
+
+	if (!adapter) {
+		con_log(CL_ANN, (KERN_CRIT
+		"megaraid: Invalid detach on %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
+			pdev->vendor, pdev->device, pdev->subsystem_vendor,
+			pdev->subsystem_device));
+
+		return;
+	}
+	else {
+		con_log(CL_ANN, (KERN_NOTICE
+		"megaraid: detaching device %#4.04x:%#4.04x:%#4.04x:%#4.04x\n",
+			pdev->vendor, pdev->device, pdev->subsystem_vendor,
+			pdev->subsystem_device));
+	}
+
+
+	host = adapter->host;
+
+	// do not allow any more requests from the management module for this
+	// adapter.
+	// FIXME: How do we account for the request which might still be
+	// pending with us?
+	atomic_set(&adapter->being_detached, 1);
+
+	// detach from the IO sub-system
+	megaraid_io_detach(adapter);
+
+	// reset the device state in the PCI structure. We check this
+	// condition when we enter here. If the device state is NULL,
+	// that would mean the device has already been removed
+	pci_set_drvdata(pdev, NULL);
+
+	// Unregister from common management module
+	//
+	// FIXME: this must return success or failure for conditions if there
+	// is a command pending with LLD or not.
+	megaraid_cmm_unregister(adapter);
+
+	// finalize the mailbox based controller and release all resources
+	megaraid_fini_mbox(adapter);
+
+	kfree(adapter);
+
+	scsi_host_put(host);
+
+	pci_disable_device(pdev);
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_shutdown - PCI shutdown for megaraid HBA
+ * @param device	: generice driver model device
+ *
+ * Shutdown notification, perform flush cache
+ */
+static void
+megaraid_mbox_shutdown(struct device *device)
+{
+	adapter_t		*adapter = pci_get_drvdata(to_pci_dev(device));
+	static int		counter;
+
+	if (!adapter) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: null device in shutdown\n"));
+		return;
+	}
+
+	// flush caches now
+	con_log(CL_ANN, (KERN_INFO "megaraid: flushing adapter %d...",
+		counter++));
+
+	megaraid_mbox_flush_cache(adapter);
+
+	con_log(CL_ANN, ("done\n"));
+}
+
+
+/**
+ * megaraid_io_attach - attach a device with the IO subsystem
+ * @param adapter	: controller's soft state
+ *
+ * Attach this device with the IO subsystem
+ **/
+static int
+megaraid_io_attach(adapter_t *adapter)
+{
+	struct Scsi_Host	*host;
+
+	// Initialize SCSI Host structure
+	host = scsi_host_alloc(&megaraid_template_g, 8);
+	if (!host) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mbox: scsi_register failed\n"));
+
+		return -1;
+	}
+
+	SCSIHOST2ADAP(host)	= (caddr_t)adapter;
+	adapter->host		= host;
+
+	// export the parameters required by the mid-layer
+	scsi_assign_lock(host, adapter->host_lock);
+	scsi_set_device(host, &adapter->pdev->dev);
+
+	host->irq		= adapter->irq;
+	host->unique_id		= adapter->unique_id;
+	host->can_queue		= adapter->max_cmds;
+	host->this_id		= adapter->init_id;
+	host->sg_tablesize	= adapter->sglen;
+	host->max_sectors	= adapter->max_sectors;
+	host->cmd_per_lun	= adapter->cmd_per_lun;
+	host->max_channel	= adapter->max_channel;
+	host->max_id		= adapter->max_target;
+	host->max_lun		= adapter->max_lun;
+
+
+	// notify mid-layer about the new controller
+	if (scsi_add_host(host, &adapter->pdev->dev)) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mbox: scsi_add_host failed\n"));
+
+		scsi_host_put(host);
+
+		return -1;
+	}
+
+	scsi_scan_host(host);
+
+	return 0;
+}
+
+
+/**
+ * megaraid_io_detach - detach a device from the IO subsystem
+ * @param adapter	: controller's soft state
+ *
+ * Detach this device from the IO subsystem
+ **/
+static void
+megaraid_io_detach(adapter_t *adapter)
+{
+	struct Scsi_Host	*host;
+
+	con_log(CL_DLEVEL1, (KERN_INFO "megaraid: io detach\n"));
+
+	host = adapter->host;
+
+	scsi_remove_host(host);
+
+	return;
+}
+
+
+/*
+ * START: Mailbox Low Level Driver
+ *
+ * This is section specific to the single mailbox based controllers
+ */
+
+/**
+ * megaraid_init_mbox - initialize controller
+ * @param adapter	- our soft state
+ *
+ * . Allocate 16-byte aligned mailbox memory for firmware handshake
+ * . Allocate controller's memory resources
+ * . Find out all initialization data
+ * . Allocate memory required for all the commands
+ * . Use internal library of FW routines, build up complete soft state
+ */
+static int __init
+megaraid_init_mbox(adapter_t *adapter)
+{
+	struct pci_dev		*pdev;
+	mraid_device_t		*raid_dev;
+	int			i;
+
+
+	adapter->ito	= MBOX_TIMEOUT;
+	pdev		= adapter->pdev;
+
+	/*
+	 * Allocate and initialize the init data structure for mailbox
+	 * controllers
+	 */
+	raid_dev = kmalloc(sizeof(mraid_device_t), GFP_KERNEL);
+	if (raid_dev == NULL) return -1;
+
+	memset(raid_dev, 0, sizeof(mraid_device_t));
+
+	/*
+	 * Attach the adapter soft state to raid device soft state
+	 */
+	adapter->raid_device	= (caddr_t)raid_dev;
+	raid_dev->fast_load	= megaraid_fast_load;
+
+
+	// our baseport
+	raid_dev->baseport = pci_resource_start(pdev, 0);
+
+	if (pci_request_regions(pdev, "MegaRAID: LSI Logic Corporation") != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+				"megaraid: mem region busy\n"));
+
+		goto out_free_raid_dev;
+	}
+
+	raid_dev->baseaddr = ioremap_nocache(raid_dev->baseport, 128);
+
+	if (!raid_dev->baseaddr) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: could not map hba memory\n") );
+
+		goto out_release_regions;
+	}
+
+	//
+	// Setup the rest of the soft state using the library of FW routines
+	//
+
+	// request IRQ and register the interrupt service routine
+	if (request_irq(adapter->irq, megaraid_isr, SA_SHIRQ, "megaraid",
+		adapter)) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: Couldn't register IRQ %d!\n", adapter->irq));
+
+		goto out_iounmap;
+	}
+
+
+	// initialize the mutual exclusion lock for the mailbox
+	spin_lock_init(&raid_dev->mailbox_lock);
+
+	// allocate memory required for commands
+	if (megaraid_alloc_cmd_packets(adapter) != 0) {
+		goto out_free_irq;
+	}
+
+	// Product info
+	if (megaraid_mbox_product_info(adapter) != 0) {
+		goto out_alloc_cmds;
+	}
+
+	// Do we support extended CDBs
+	adapter->max_cdb_sz = 10;
+	if (megaraid_mbox_extended_cdb(adapter) == 0) {
+		adapter->max_cdb_sz = 16;
+	}
+
+	/*
+	 * Do we support cluster environment, if we do, what is the initiator
+	 * id.
+	 * NOTE: In a non-cluster aware firmware environment, the LLD should
+	 * return 7 as initiator id.
+	 */
+	adapter->ha		= 0;
+	adapter->init_id	= -1;
+	if (megaraid_mbox_support_ha(adapter, &adapter->init_id) == 0) {
+		adapter->ha = 1;
+	}
+
+	/*
+	 * Prepare the device ids array to have the mapping between the kernel
+	 * device address and megaraid device address.
+	 * We export the physical devices on their actual addresses. The
+	 * logical drives are exported on a virtual SCSI channel
+	 */
+	megaraid_mbox_setup_device_map(adapter);
+
+	// If the firmware supports random deletion, update the device id map
+	if (megaraid_mbox_support_random_del(adapter)) {
+
+		// Change the logical drives numbers in device_ids array one
+		// slot in device_ids is reserved for target id, that's why
+		// "<=" below
+		for (i = 0; i <= MAX_LOGICAL_DRIVES_40LD; i++) {
+			adapter->device_ids[adapter->max_channel][i] += 0x80;
+		}
+		adapter->device_ids[adapter->max_channel][adapter->init_id] =
+			0xFF;
+
+		raid_dev->random_del_supported = 1;
+	}
+
+	/*
+	 * find out the maximum number of scatter-gather elements supported by
+	 * this firmware
+	 */
+	adapter->sglen = megaraid_mbox_get_max_sg(adapter);
+
+	// enumerate RAID and SCSI channels so that all devices on SCSI
+	// channels can later be exported, including disk devices
+	megaraid_mbox_enum_raid_scsi(adapter);
+
+	/*
+	 * Other parameters required by upper layer
+	 *
+	 * maximum number of sectors per IO command
+	 */
+	adapter->max_sectors = megaraid_max_sectors;
+
+	/*
+	 * number of queued commands per LUN.
+	 */
+	adapter->cmd_per_lun = megaraid_cmd_per_lun;
+
+	/*
+	 * Allocate resources required to issue FW calls, when sysfs is
+	 * accessed
+	 */
+	if (megaraid_sysfs_alloc_resources(adapter) != 0) {
+		goto out_alloc_cmds;
+	}
+
+	// Set the DMA mask to 64-bit. All supported controllers as capable of
+	// DMA in this range
+	if (pci_set_dma_mask(adapter->pdev, 0xFFFFFFFFFFFFFFFFULL) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: could not set DMA mask for 64-bit.\n"));
+
+		goto out_free_sysfs_res;
+	}
+
+	// setup tasklet for DPC
+	tasklet_init(&adapter->dpc_h, megaraid_mbox_dpc,
+			(unsigned long)adapter);
+
+	con_log(CL_DLEVEL1, (KERN_INFO
+		"megaraid mbox hba successfully initialized\n"));
+
+	return 0;
+
+out_free_sysfs_res:
+	megaraid_sysfs_free_resources(adapter);
+out_alloc_cmds:
+	megaraid_free_cmd_packets(adapter);
+out_free_irq:
+	free_irq(adapter->irq, adapter);
+out_iounmap:
+	iounmap(raid_dev->baseaddr);
+out_release_regions:
+	pci_release_regions(pdev);
+out_free_raid_dev:
+	kfree(raid_dev);
+
+	return -1;
+}
+
+
+/**
+ * megaraid_fini_mbox - undo controller initialization
+ * @param adapter	: our soft state
+ */
+static void
+megaraid_fini_mbox(adapter_t *adapter)
+{
+	mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
+
+	// flush all caches
+	megaraid_mbox_flush_cache(adapter);
+
+	tasklet_kill(&adapter->dpc_h);
+
+	megaraid_sysfs_free_resources(adapter);
+
+	megaraid_free_cmd_packets(adapter);
+
+	free_irq(adapter->irq, adapter);
+
+	iounmap(raid_dev->baseaddr);
+
+	pci_release_regions(adapter->pdev);
+
+	kfree(raid_dev);
+
+	return;
+}
+
+
+/**
+ * megaraid_alloc_cmd_packets - allocate shared mailbox
+ * @param adapter	: soft state of the raid controller
+ *
+ * Allocate and align the shared mailbox. This maibox is used to issue
+ * all the commands. For IO based controllers, the mailbox is also regsitered
+ * with the FW. Allocate memory for all commands as well.
+ * This is our big allocator
+ */
+static int
+megaraid_alloc_cmd_packets(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	struct pci_dev		*pdev;
+	unsigned long		align;
+	scb_t			*scb;
+	mbox_ccb_t		*ccb;
+	struct mraid_pci_blk	*epthru_pci_blk;
+	struct mraid_pci_blk	*sg_pci_blk;
+	struct mraid_pci_blk	*mbox_pci_blk;
+	int			i;
+
+	pdev = adapter->pdev;
+
+	/*
+	 * Setup the mailbox
+	 * Allocate the common 16-byte aligned memory for the handshake
+	 * mailbox.
+	 */
+	raid_dev->una_mbox64 = pci_alloc_consistent(adapter->pdev,
+			sizeof(mbox64_t), &raid_dev->una_mbox64_dma);
+
+	if (!raid_dev->una_mbox64) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+		return -1;
+	}
+	memset(raid_dev->una_mbox64, 0, sizeof(mbox64_t));
+
+	/*
+	 * Align the mailbox at 16-byte boundary
+	 */
+	raid_dev->mbox	= &raid_dev->una_mbox64->mbox32;
+
+	raid_dev->mbox	= (mbox_t *)((((unsigned long)raid_dev->mbox) + 15) &
+				(~0UL ^ 0xFUL));
+
+	raid_dev->mbox64 = (mbox64_t *)(((unsigned long)raid_dev->mbox) - 8);
+
+	align = ((void *)raid_dev->mbox -
+			((void *)&raid_dev->una_mbox64->mbox32));
+
+	raid_dev->mbox_dma = (unsigned long)raid_dev->una_mbox64_dma + 8 +
+			align;
+
+	// Allocate memory for commands issued internally
+	adapter->ibuf = pci_alloc_consistent(pdev, MBOX_IBUF_SIZE,
+				&adapter->ibuf_dma_h);
+	if (!adapter->ibuf) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+
+		goto out_free_common_mbox;
+	}
+	memset(adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	// Allocate memory for our SCSI Command Blocks and their associated
+	// memory
+
+	/*
+	 * Allocate memory for the base list of scb. Later allocate memory for
+	 * CCBs and embedded components of each CCB and point the pointers in
+	 * scb to the allocated components
+	 * NOTE: The code to allocate SCB will be duplicated in all the LLD
+	 * since the calling routine does not yet know the number of available
+	 * commands.
+	 */
+	adapter->kscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_SCSI_CMDS,
+			GFP_KERNEL);
+
+	if (adapter->kscb_list == NULL) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+		goto out_free_ibuf;
+	}
+	memset(adapter->kscb_list, 0, sizeof(scb_t) * MBOX_MAX_SCSI_CMDS);
+
+	// memory allocation for our command packets
+	if (megaraid_mbox_setup_dma_pools(adapter) != 0) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+		goto out_free_scb_list;
+	}
+
+	// Adjust the scb pointers and link in the free pool
+	epthru_pci_blk	= raid_dev->epthru_pool;
+	sg_pci_blk	= raid_dev->sg_pool;
+	mbox_pci_blk	= raid_dev->mbox_pool;
+
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+		scb			= adapter->kscb_list + i;
+		ccb			= raid_dev->ccb_list + i;
+
+		ccb->mbox	= (mbox_t *)(mbox_pci_blk[i].vaddr + 16);
+		ccb->raw_mbox	= (uint8_t *)ccb->mbox;
+		ccb->mbox64	= (mbox64_t *)(mbox_pci_blk[i].vaddr + 8);
+		ccb->mbox_dma_h	= (unsigned long)mbox_pci_blk[i].dma_addr + 16;
+
+		// make sure the mailbox is aligned properly
+		if (ccb->mbox_dma_h & 0x0F) {
+			con_log(CL_ANN, (KERN_CRIT
+				"megaraid mbox: not aligned on 16-bytes\n"));
+
+			goto out_teardown_dma_pools;
+		}
+
+		ccb->epthru		= (mraid_epassthru_t *)
+						epthru_pci_blk[i].vaddr;
+		ccb->epthru_dma_h	= epthru_pci_blk[i].dma_addr;
+		ccb->pthru		= (mraid_passthru_t *)ccb->epthru;
+		ccb->pthru_dma_h	= ccb->epthru_dma_h;
+
+
+		ccb->sgl64		= (mbox_sgl64 *)sg_pci_blk[i].vaddr;
+		ccb->sgl_dma_h		= sg_pci_blk[i].dma_addr;
+		ccb->sgl32		= (mbox_sgl32 *)ccb->sgl64;
+
+		scb->ccb		= (caddr_t)ccb;
+		scb->gp			= 0;
+
+		scb->sno		= i;	// command index
+
+		scb->scp		= NULL;
+		scb->state		= SCB_FREE;
+		scb->dma_direction	= PCI_DMA_NONE;
+		scb->dma_type		= MRAID_DMA_NONE;
+		scb->dev_channel	= -1;
+		scb->dev_target		= -1;
+
+		// put scb in the free pool
+		list_add_tail(&scb->list, &adapter->kscb_pool);
+	}
+
+	return 0;
+
+out_teardown_dma_pools:
+	megaraid_mbox_teardown_dma_pools(adapter);
+out_free_scb_list:
+	kfree(adapter->kscb_list);
+out_free_ibuf:
+	pci_free_consistent(pdev, MBOX_IBUF_SIZE, (void *)adapter->ibuf,
+		adapter->ibuf_dma_h);
+out_free_common_mbox:
+	pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+		(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
+
+	return -1;
+}
+
+
+/**
+ * megaraid_free_cmd_packets - free memory
+ * @param adapter	: soft state of the raid controller
+ *
+ * Release memory resources allocated for commands
+ */
+static void
+megaraid_free_cmd_packets(adapter_t *adapter)
+{
+	mraid_device_t *raid_dev = ADAP2RAIDDEV(adapter);
+
+	megaraid_mbox_teardown_dma_pools(adapter);
+
+	kfree(adapter->kscb_list);
+
+	pci_free_consistent(adapter->pdev, MBOX_IBUF_SIZE,
+		(void *)adapter->ibuf, adapter->ibuf_dma_h);
+
+	pci_free_consistent(adapter->pdev, sizeof(mbox64_t),
+		(caddr_t)raid_dev->una_mbox64, raid_dev->una_mbox64_dma);
+	return;
+}
+
+
+/**
+ * megaraid_mbox_setup_dma_pools - setup dma pool for command packets
+ * @param adapter	: HBA soft state
+ *
+ * setup the dma pools for mailbox, passthru and extended passthru structures,
+ * and scatter-gather lists
+ */
+static int
+megaraid_mbox_setup_dma_pools(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	struct mraid_pci_blk	*epthru_pci_blk;
+	struct mraid_pci_blk	*sg_pci_blk;
+	struct mraid_pci_blk	*mbox_pci_blk;
+	int			i;
+
+
+
+	// Allocate memory for 16-bytes aligned mailboxes
+	raid_dev->mbox_pool_handle = pci_pool_create("megaraid mbox pool",
+						adapter->pdev,
+						sizeof(mbox64_t) + 16,
+						16, 0);
+
+	if (raid_dev->mbox_pool_handle == NULL) {
+		goto fail_setup_dma_pool;
+	}
+
+	mbox_pci_blk = raid_dev->mbox_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+		mbox_pci_blk[i].vaddr = pci_pool_alloc(
+						raid_dev->mbox_pool_handle,
+						GFP_KERNEL,
+						&mbox_pci_blk[i].dma_addr);
+		if (!mbox_pci_blk[i].vaddr) {
+			goto fail_setup_dma_pool;
+		}
+	}
+
+	/*
+	 * Allocate memory for each embedded passthru strucuture pointer
+	 * Request for a 128 bytes aligned structure for each passthru command
+	 * structure
+	 * Since passthru and extended passthru commands are exclusive, they
+	 * share common memory pool. Passthru structures piggyback on memory
+	 * allocted to extended passthru since passthru is smaller of the two
+	 */
+	raid_dev->epthru_pool_handle = pci_pool_create("megaraid mbox pthru",
+			adapter->pdev, sizeof(mraid_epassthru_t), 128, 0);
+
+	if (raid_dev->epthru_pool_handle == NULL) {
+		goto fail_setup_dma_pool;
+	}
+
+	epthru_pci_blk = raid_dev->epthru_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+		epthru_pci_blk[i].vaddr = pci_pool_alloc(
+						raid_dev->epthru_pool_handle,
+						GFP_KERNEL,
+						&epthru_pci_blk[i].dma_addr);
+		if (!epthru_pci_blk[i].vaddr) {
+			goto fail_setup_dma_pool;
+		}
+	}
+
+
+	// Allocate memory for each scatter-gather list. Request for 512 bytes
+	// alignment for each sg list
+	raid_dev->sg_pool_handle = pci_pool_create("megaraid mbox sg",
+					adapter->pdev,
+					sizeof(mbox_sgl64) * MBOX_MAX_SG_SIZE,
+					512, 0);
+
+	if (raid_dev->sg_pool_handle == NULL) {
+		goto fail_setup_dma_pool;
+	}
+
+	sg_pci_blk = raid_dev->sg_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+		sg_pci_blk[i].vaddr = pci_pool_alloc(
+						raid_dev->sg_pool_handle,
+						GFP_KERNEL,
+						&sg_pci_blk[i].dma_addr);
+		if (!sg_pci_blk[i].vaddr) {
+			goto fail_setup_dma_pool;
+		}
+	}
+
+	return 0;
+
+fail_setup_dma_pool:
+	megaraid_mbox_teardown_dma_pools(adapter);
+	return -1;
+}
+
+
+/**
+ * megaraid_mbox_teardown_dma_pools - teardown dma pools for command packets
+ * @param adapter	: HBA soft state
+ *
+ * teardown the dma pool for mailbox, passthru and extended passthru
+ * structures, and scatter-gather lists
+ */
+static void
+megaraid_mbox_teardown_dma_pools(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	struct mraid_pci_blk	*epthru_pci_blk;
+	struct mraid_pci_blk	*sg_pci_blk;
+	struct mraid_pci_blk	*mbox_pci_blk;
+	int			i;
+
+
+	sg_pci_blk = raid_dev->sg_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS && sg_pci_blk[i].vaddr; i++) {
+		pci_pool_free(raid_dev->sg_pool_handle, sg_pci_blk[i].vaddr,
+			sg_pci_blk[i].dma_addr);
+	}
+	if (raid_dev->sg_pool_handle)
+		pci_pool_destroy(raid_dev->sg_pool_handle);
+
+
+	epthru_pci_blk = raid_dev->epthru_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS && epthru_pci_blk[i].vaddr; i++) {
+		pci_pool_free(raid_dev->epthru_pool_handle,
+			epthru_pci_blk[i].vaddr, epthru_pci_blk[i].dma_addr);
+	}
+	if (raid_dev->epthru_pool_handle)
+		pci_pool_destroy(raid_dev->epthru_pool_handle);
+
+
+	mbox_pci_blk = raid_dev->mbox_pool;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS && mbox_pci_blk[i].vaddr; i++) {
+		pci_pool_free(raid_dev->mbox_pool_handle,
+			mbox_pci_blk[i].vaddr, mbox_pci_blk[i].dma_addr);
+	}
+	if (raid_dev->mbox_pool_handle)
+		pci_pool_destroy(raid_dev->mbox_pool_handle);
+
+	return;
+}
+
+
+/**
+ * megaraid_alloc_scb - detach and return a scb from the free list
+ * @adapter	: controller's soft state
+ *
+ * return the scb from the head of the free list. NULL if there are none
+ * available
+ **/
+static inline scb_t *
+megaraid_alloc_scb(adapter_t *adapter, struct scsi_cmnd *scp)
+{
+	struct list_head	*head = &adapter->kscb_pool;
+	scb_t			*scb = NULL;
+	unsigned long		flags;
+
+	// detach scb from free pool
+	spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+	if (list_empty(head)) {
+		spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+		return NULL;
+	}
+
+	scb = list_entry(head->next, scb_t, list);
+	list_del_init(&scb->list);
+
+	spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+	scb->state	= SCB_ACTIVE;
+	scb->scp	= scp;
+	scb->dma_type	= MRAID_DMA_NONE;
+
+	return scb;
+}
+
+
+/**
+ * megaraid_dealloc_scb - return the scb to the free pool
+ * @adapter	: controller's soft state
+ * @scb		: scb to be freed
+ *
+ * return the scb back to the free list of scbs. The caller must 'flush' the
+ * SCB before calling us. E.g., performing pci_unamp and/or pci_sync etc.
+ * NOTE NOTE: Make sure the scb is not on any list before calling this
+ * routine.
+ **/
+static inline void
+megaraid_dealloc_scb(adapter_t *adapter, scb_t *scb)
+{
+	unsigned long		flags;
+
+	// put scb in the free pool
+	scb->state	= SCB_FREE;
+	scb->scp	= NULL;
+	spin_lock_irqsave(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+	list_add(&scb->list, &adapter->kscb_pool);
+
+	spin_unlock_irqrestore(SCSI_FREE_LIST_LOCK(adapter), flags);
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_mksgl - make the scatter-gather list
+ * @adapter	- controller's soft state
+ * @scb		- scsi control block
+ *
+ * prepare the scatter-gather list
+ */
+static inline int
+megaraid_mbox_mksgl(adapter_t *adapter, scb_t *scb)
+{
+	struct scatterlist	*sgl;
+	mbox_ccb_t		*ccb;
+	struct page		*page;
+	unsigned long		offset;
+	struct scsi_cmnd	*scp;
+	int			sgcnt;
+	int			i;
+
+
+	scp	= scb->scp;
+	ccb	= (mbox_ccb_t *)scb->ccb;
+
+	// no mapping required if no data to be transferred
+	if (!scp->request_buffer || !scp->request_bufflen)
+		return 0;
+
+	if (!scp->use_sg) {	/* scatter-gather list not used */
+
+		page = virt_to_page(scp->request_buffer);
+
+		offset = ((unsigned long)scp->request_buffer & ~PAGE_MASK);
+
+		ccb->buf_dma_h = pci_map_page(adapter->pdev, page, offset,
+						  scp->request_bufflen,
+						  scb->dma_direction);
+		scb->dma_type = MRAID_DMA_WBUF;
+
+		/*
+		 * We need to handle special 64-bit commands that need a
+		 * minimum of 1 SG
+		 */
+		sgcnt = 1;
+		ccb->sgl64[0].address	= ccb->buf_dma_h;
+		ccb->sgl64[0].length	= scp->request_bufflen;
+
+		return sgcnt;
+	}
+
+	sgl = (struct scatterlist *)scp->request_buffer;
+
+	// The number of sg elements returned must not exceed our limit
+	sgcnt = pci_map_sg(adapter->pdev, sgl, scp->use_sg,
+			scb->dma_direction);
+
+	if (sgcnt > adapter->sglen) {
+		con_log(CL_ANN, (KERN_CRIT
+			"megaraid critical: too many sg elements:%d\n",
+			sgcnt));
+		BUG();
+	}
+
+	scb->dma_type = MRAID_DMA_WSG;
+
+	for (i = 0; i < sgcnt; i++, sgl++) {
+		ccb->sgl64[i].address	= sg_dma_address(sgl);
+		ccb->sgl64[i].length	= sg_dma_len(sgl);
+	}
+
+	// Return count of SG nodes
+	return sgcnt;
+}
+
+
+/**
+ * mbox_post_cmd - issue a mailbox command
+ * @adapter	- controller's soft state
+ * @scb		- command to be issued
+ *
+ * post the command to the controller if mailbox is availble.
+ */
+static inline int
+mbox_post_cmd(adapter_t *adapter, scb_t *scb)
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox64_t	*mbox64;
+	mbox_t		*mbox;
+	mbox_ccb_t	*ccb;
+	unsigned long	flags;
+	unsigned int	i = 0;
+
+
+	ccb	= (mbox_ccb_t *)scb->ccb;
+	mbox	= raid_dev->mbox;
+	mbox64	= raid_dev->mbox64;
+
+	/*
+	 * Check for busy mailbox. If it is, return failure - the caller
+	 * should retry later.
+	 */
+	spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
+
+	if (unlikely(mbox->busy)) {
+		do {
+			udelay(1);
+			i++;
+			rmb();
+		} while(mbox->busy && (i < max_mbox_busy_wait));
+
+		if (mbox->busy) {
+
+			spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+			return -1;
+		}
+	}
+
+
+	// Copy this command's mailbox data into "adapter's" mailbox
+	memcpy((caddr_t)mbox64, (caddr_t)ccb->mbox64, 22);
+	mbox->cmdid = scb->sno;
+
+	adapter->outstanding_cmds++;
+
+	if (scb->dma_direction == PCI_DMA_TODEVICE) {
+		if (!scb->scp->use_sg) {	// sg list not used
+			pci_dma_sync_single_for_device(adapter->pdev,
+					ccb->buf_dma_h,
+					scb->scp->request_bufflen,
+					PCI_DMA_TODEVICE);
+		}
+		else {
+			pci_dma_sync_sg_for_device(adapter->pdev,
+				scb->scp->request_buffer,
+				scb->scp->use_sg, PCI_DMA_TODEVICE);
+		}
+	}
+
+	mbox->busy	= 1;	// Set busy
+	mbox->poll	= 0;
+	mbox->ack	= 0;
+	wmb();
+
+	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+	spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+	return 0;
+}
+
+
+/**
+ * megaraid_queue_command - generic queue entry point for all LLDs
+ * @scp		: pointer to the scsi command to be executed
+ * @done	: callback routine to be called after the cmd has be completed
+ *
+ * Queue entry point for mailbox based controllers.
+ */
+static int
+megaraid_queue_command(struct scsi_cmnd *scp, void (* done)(struct scsi_cmnd *))
+{
+	adapter_t	*adapter;
+	scb_t		*scb;
+	int		if_busy;
+
+	adapter		= SCP2ADAPTER(scp);
+	scp->scsi_done	= done;
+	scp->result	= 0;
+
+	assert_spin_locked(adapter->host_lock);
+
+	spin_unlock(adapter->host_lock);
+
+	/*
+	 * Allocate and build a SCB request
+	 * if_busy flag will be set if megaraid_mbox_build_cmd() command could
+	 * not allocate scb. We will return non-zero status in that case.
+	 * NOTE: scb can be null even though certain commands completed
+	 * successfully, e.g., MODE_SENSE and TEST_UNIT_READY, it would
+	 * return 0 in that case, and we would do the callback right away.
+	 */
+	if_busy	= 0;
+	scb	= megaraid_mbox_build_cmd(adapter, scp, &if_busy);
+
+	if (scb) {
+		megaraid_mbox_runpendq(adapter, scb);
+	}
+
+	spin_lock(adapter->host_lock);
+
+	if (!scb) {	// command already completed
+		done(scp);
+		return 0;
+	}
+
+	return if_busy;
+}
+
+
+/**
+ * megaraid_mbox_build_cmd - transform the mid-layer scsi command to megaraid
+ * firmware lingua
+ * @adapter	- controller's soft state
+ * @scp		- mid-layer scsi command pointer
+ * @busy	- set if request could not be completed because of lack of
+ *		resources
+ *
+ * convert the command issued by mid-layer to format understood by megaraid
+ * firmware. We also complete certain command without sending them to firmware
+ */
+static scb_t *
+megaraid_mbox_build_cmd(adapter_t *adapter, struct scsi_cmnd *scp, int *busy)
+{
+	mraid_device_t		*rdev = ADAP2RAIDDEV(adapter);
+	int			channel;
+	int			target;
+	int			islogical;
+	mbox_ccb_t		*ccb;
+	mraid_passthru_t	*pthru;
+	mbox64_t		*mbox64;
+	mbox_t			*mbox;
+	scb_t			*scb;
+	char			skip[] = "skipping";
+	char			scan[] = "scanning";
+	char			*ss;
+
+
+	/*
+	 * Get the appropriate device map for the device this command is
+	 * intended for
+	 */
+	MRAID_GET_DEVICE_MAP(adapter, scp, channel, target, islogical);
+
+	/*
+	 * Logical drive commands
+	 */
+	if (islogical) {
+		switch (scp->cmnd[0]) {
+		case TEST_UNIT_READY:
+			/*
+			 * Do we support clustering and is the support enabled
+			 * If no, return success always
+			 */
+			if (!adapter->ha) {
+				scp->result = (DID_OK << 16);
+				return NULL;
+			}
+
+			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+				scp->result = (DID_ERROR << 16);
+				*busy = 1;
+				return NULL;
+			}
+
+			scb->dma_direction	= scp->sc_data_direction;
+			scb->dev_channel	= 0xFF;
+			scb->dev_target		= target;
+			ccb			= (mbox_ccb_t *)scb->ccb;
+
+			/*
+			 * The command id will be provided by the command
+			 * issuance routine
+			 */
+			ccb->raw_mbox[0]	= CLUSTER_CMD;
+			ccb->raw_mbox[2]	= RESERVATION_STATUS;
+			ccb->raw_mbox[3]	= target;
+
+			return scb;
+
+		case MODE_SENSE:
+			if (scp->use_sg) {
+				struct scatterlist	*sgl;
+				caddr_t			vaddr;
+
+				sgl = (struct scatterlist *)scp->request_buffer;
+				if (sgl->page) {
+					vaddr = (caddr_t)
+						(page_address((&sgl[0])->page)
+						+ (&sgl[0])->offset);
+
+					memset(vaddr, 0, scp->cmnd[4]);
+				}
+				else {
+					con_log(CL_ANN, (KERN_WARNING
+					"megaraid mailbox: invalid sg:%d\n",
+					__LINE__));
+				}
+			}
+			else {
+				memset(scp->request_buffer, 0, scp->cmnd[4]);
+			}
+			scp->result = (DID_OK << 16);
+			return NULL;
+
+		case INQUIRY:
+			/*
+			 * Display the channel scan for logical drives
+			 * Do not display scan for a channel if already done.
+			 */
+			if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
+
+				con_log(CL_ANN, (KERN_INFO
+					"scsi[%d]: scanning scsi channel %d",
+					adapter->host->host_no,
+					SCP2CHANNEL(scp)));
+
+				con_log(CL_ANN, (
+					" [virtual] for logical drives\n"));
+
+				rdev->last_disp |= (1L << SCP2CHANNEL(scp));
+			}
+
+			/* Fall through */
+
+		case READ_CAPACITY:
+			/*
+			 * Do not allow LUN > 0 for logical drives and
+			 * requests for more than 40 logical drives
+			 */
+			if (SCP2LUN(scp)) {
+				scp->result = (DID_BAD_TARGET << 16);
+				return NULL;
+			}
+			if ((target % 0x80) >= MAX_LOGICAL_DRIVES_40LD) {
+				scp->result = (DID_BAD_TARGET << 16);
+				return NULL;
+			}
+
+
+			/* Allocate a SCB and initialize passthru */
+			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+				scp->result = (DID_ERROR << 16);
+				*busy = 1;
+				return NULL;
+			}
+
+			ccb			= (mbox_ccb_t *)scb->ccb;
+			scb->dev_channel	= 0xFF;
+			scb->dev_target		= target;
+			pthru			= ccb->pthru;
+			mbox			= ccb->mbox;
+			mbox64			= ccb->mbox64;
+
+			pthru->timeout		= 0;
+			pthru->ars		= 1;
+			pthru->reqsenselen	= 14;
+			pthru->islogical	= 1;
+			pthru->logdrv		= target;
+			pthru->cdblen		= scp->cmd_len;
+			memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+			mbox->cmd		= MBOXCMD_PASSTHRU64;
+			scb->dma_direction	= scp->sc_data_direction;
+
+			pthru->dataxferlen	= scp->request_bufflen;
+			pthru->dataxferaddr	= ccb->sgl_dma_h;
+			pthru->numsge		= megaraid_mbox_mksgl(adapter,
+							scb);
+
+			mbox->xferaddr		= 0xFFFFFFFF;
+			mbox64->xferaddr_lo	= (uint32_t )ccb->pthru_dma_h;
+			mbox64->xferaddr_hi	= 0;
+
+			return scb;
+
+		case READ_6:
+		case WRITE_6:
+		case READ_10:
+		case WRITE_10:
+		case READ_12:
+		case WRITE_12:
+
+			/*
+			 * Allocate a SCB and initialize mailbox
+			 */
+			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+				scp->result = (DID_ERROR << 16);
+				*busy = 1;
+				return NULL;
+			}
+			ccb			= (mbox_ccb_t *)scb->ccb;
+			scb->dev_channel	= 0xFF;
+			scb->dev_target		= target;
+			mbox			= ccb->mbox;
+			mbox64			= ccb->mbox64;
+			mbox->logdrv		= target;
+
+			/*
+			 * A little HACK: 2nd bit is zero for all scsi read
+			 * commands and is set for all scsi write commands
+			 */
+			mbox->cmd = (scp->cmnd[0] & 0x02) ?  MBOXCMD_LWRITE64:
+					MBOXCMD_LREAD64 ;
+
+			/*
+			 * 6-byte READ(0x08) or WRITE(0x0A) cdb
+			 */
+			if (scp->cmd_len == 6) {
+				mbox->numsectors = (uint32_t)scp->cmnd[4];
+				mbox->lba =
+					((uint32_t)scp->cmnd[1] << 16)	|
+					((uint32_t)scp->cmnd[2] << 8)	|
+					(uint32_t)scp->cmnd[3];
+
+				mbox->lba &= 0x1FFFFF;
+			}
+
+			/*
+			 * 10-byte READ(0x28) or WRITE(0x2A) cdb
+			 */
+			else if (scp->cmd_len == 10) {
+				mbox->numsectors =
+					(uint32_t)scp->cmnd[8] |
+					((uint32_t)scp->cmnd[7] << 8);
+				mbox->lba =
+					((uint32_t)scp->cmnd[2] << 24) |
+					((uint32_t)scp->cmnd[3] << 16) |
+					((uint32_t)scp->cmnd[4] << 8) |
+					(uint32_t)scp->cmnd[5];
+			}
+
+			/*
+			 * 12-byte READ(0xA8) or WRITE(0xAA) cdb
+			 */
+			else if (scp->cmd_len == 12) {
+				mbox->lba =
+					((uint32_t)scp->cmnd[2] << 24) |
+					((uint32_t)scp->cmnd[3] << 16) |
+					((uint32_t)scp->cmnd[4] << 8) |
+					(uint32_t)scp->cmnd[5];
+
+				mbox->numsectors =
+					((uint32_t)scp->cmnd[6] << 24) |
+					((uint32_t)scp->cmnd[7] << 16) |
+					((uint32_t)scp->cmnd[8] << 8) |
+					(uint32_t)scp->cmnd[9];
+			}
+			else {
+				con_log(CL_ANN, (KERN_WARNING
+					"megaraid: unsupported CDB length\n"));
+
+				megaraid_dealloc_scb(adapter, scb);
+
+				scp->result = (DID_ERROR << 16);
+				return NULL;
+			}
+
+			scb->dma_direction = scp->sc_data_direction;
+
+			// Calculate Scatter-Gather info
+			mbox64->xferaddr_lo	= (uint32_t )ccb->sgl_dma_h;
+			mbox->numsge		= megaraid_mbox_mksgl(adapter,
+							scb);
+			mbox->xferaddr		= 0xFFFFFFFF;
+			mbox64->xferaddr_hi	= 0;
+
+			return scb;
+
+		case RESERVE:
+		case RELEASE:
+			/*
+			 * Do we support clustering and is the support enabled
+			 */
+			if (!adapter->ha) {
+				scp->result = (DID_BAD_TARGET << 16);
+				return NULL;
+			}
+
+			/*
+			 * Allocate a SCB and initialize mailbox
+			 */
+			if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+				scp->result = (DID_ERROR << 16);
+				*busy = 1;
+				return NULL;
+			}
+
+			ccb			= (mbox_ccb_t *)scb->ccb;
+			scb->dev_channel	= 0xFF;
+			scb->dev_target		= target;
+			ccb->raw_mbox[0]	= CLUSTER_CMD;
+			ccb->raw_mbox[2]	=  (scp->cmnd[0] == RESERVE) ?
+						RESERVE_LD : RELEASE_LD;
+
+			ccb->raw_mbox[3]	= target;
+			scb->dma_direction	= scp->sc_data_direction;
+
+			return scb;
+
+		default:
+			scp->result = (DID_BAD_TARGET << 16);
+			return NULL;
+		}
+	}
+	else { // Passthru device commands
+
+		// Do not allow access to target id > 15 or LUN > 7
+		if (target > 15 || SCP2LUN(scp) > 7) {
+			scp->result = (DID_BAD_TARGET << 16);
+			return NULL;
+		}
+
+		// if fast load option was set and scan for last device is
+		// over, reset the fast_load flag so that during a possible
+		// next scan, devices can be made available
+		if (rdev->fast_load && (target == 15) &&
+			(SCP2CHANNEL(scp) == adapter->max_channel -1)) {
+
+			con_log(CL_ANN, (KERN_INFO
+			"megaraid[%d]: physical device scan re-enabled\n",
+				adapter->host->host_no));
+			rdev->fast_load = 0;
+		}
+
+		/*
+		 * Display the channel scan for physical devices
+		 */
+		if (!(rdev->last_disp & (1L << SCP2CHANNEL(scp)))) {
+
+			ss = rdev->fast_load ? skip : scan;
+
+			con_log(CL_ANN, (KERN_INFO
+				"scsi[%d]: %s scsi channel %d [Phy %d]",
+				adapter->host->host_no, ss, SCP2CHANNEL(scp),
+				channel));
+
+			con_log(CL_ANN, (
+				" for non-raid devices\n"));
+
+			rdev->last_disp |= (1L << SCP2CHANNEL(scp));
+		}
+
+		// disable channel sweep if fast load option given
+		if (rdev->fast_load) {
+			scp->result = (DID_BAD_TARGET << 16);
+			return NULL;
+		}
+
+		// Allocate a SCB and initialize passthru
+		if (!(scb = megaraid_alloc_scb(adapter, scp))) {
+			scp->result = (DID_ERROR << 16);
+			*busy = 1;
+			return NULL;
+		}
+
+		ccb			= (mbox_ccb_t *)scb->ccb;
+		scb->dev_channel	= channel;
+		scb->dev_target		= target;
+		scb->dma_direction	= scp->sc_data_direction;
+		mbox			= ccb->mbox;
+		mbox64			= ccb->mbox64;
+
+		// Does this firmware support extended CDBs
+		if (adapter->max_cdb_sz == 16) {
+			mbox->cmd		= MBOXCMD_EXTPTHRU;
+
+			megaraid_mbox_prepare_epthru(adapter, scb, scp);
+
+			mbox64->xferaddr_lo	= (uint32_t)ccb->epthru_dma_h;
+			mbox64->xferaddr_hi	= 0;
+			mbox->xferaddr		= 0xFFFFFFFF;
+		}
+		else {
+			mbox->cmd = MBOXCMD_PASSTHRU64;
+
+			megaraid_mbox_prepare_pthru(adapter, scb, scp);
+
+			mbox64->xferaddr_lo	= (uint32_t)ccb->pthru_dma_h;
+			mbox64->xferaddr_hi	= 0;
+			mbox->xferaddr		= 0xFFFFFFFF;
+		}
+		return scb;
+	}
+
+	// NOT REACHED
+}
+
+
+/**
+ * megaraid_mbox_runpendq - execute commands queued in the pending queue
+ * @adapter	: controller's soft state
+ * @scb		: SCB to be queued in the pending list
+ *
+ * scan the pending list for commands which are not yet issued and try to
+ * post to the controller. The SCB can be a null pointer, which would indicate
+ * no SCB to be queue, just try to execute the ones in the pending list.
+ *
+ * NOTE: We do not actually traverse the pending list. The SCBs are plucked
+ * out from the head of the pending list. If it is successfully issued, the
+ * next SCB is at the head now.
+ */
+static void
+megaraid_mbox_runpendq(adapter_t *adapter, scb_t *scb_q)
+{
+	scb_t			*scb;
+	unsigned long		flags;
+
+	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+
+	if (scb_q) {
+		scb_q->state = SCB_PENDQ;
+		list_add_tail(&scb_q->list, &adapter->pend_list);
+	}
+
+	// if the adapter in not in quiescent mode, post the commands to FW
+	if (adapter->quiescent) {
+		spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+		return;
+	}
+
+	while (!list_empty(&adapter->pend_list)) {
+
+		assert_spin_locked(PENDING_LIST_LOCK(adapter));
+
+		scb = list_entry(adapter->pend_list.next, scb_t, list);
+
+		// remove the scb from the pending list and try to
+		// issue. If we are unable to issue it, put back in
+		// the pending list and return
+
+		list_del_init(&scb->list);
+
+		spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+		// if mailbox was busy, return SCB back to pending
+		// list. Make sure to add at the head, since that's
+		// where it would have been removed from
+
+		scb->state = SCB_ISSUED;
+
+		if (mbox_post_cmd(adapter, scb) != 0) {
+
+			spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+
+			scb->state = SCB_PENDQ;
+
+			list_add(&scb->list, &adapter->pend_list);
+
+			spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
+				flags);
+
+			return;
+		}
+
+		spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+	}
+
+	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_prepare_pthru - prepare a command for physical devices
+ * @adapter	- pointer to controller's soft state
+ * @scb		- scsi control block
+ * @scp		- scsi command from the mid-layer
+ *
+ * prepare a command for the scsi physical devices
+ */
+static void
+megaraid_mbox_prepare_pthru(adapter_t *adapter, scb_t *scb,
+		struct scsi_cmnd *scp)
+{
+	mbox_ccb_t		*ccb;
+	mraid_passthru_t	*pthru;
+	uint8_t			channel;
+	uint8_t			target;
+
+	ccb	= (mbox_ccb_t *)scb->ccb;
+	pthru	= ccb->pthru;
+	channel	= scb->dev_channel;
+	target	= scb->dev_target;
+
+	// 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout
+	pthru->timeout		= 4;	
+	pthru->ars		= 1;
+	pthru->islogical	= 0;
+	pthru->channel		= 0;
+	pthru->target		= (channel << 4) | target;
+	pthru->logdrv		= SCP2LUN(scp);
+	pthru->reqsenselen	= 14;
+	pthru->cdblen		= scp->cmd_len;
+
+	memcpy(pthru->cdb, scp->cmnd, scp->cmd_len);
+
+	if (scp->request_bufflen) {
+		pthru->dataxferlen	= scp->request_bufflen;
+		pthru->dataxferaddr	= ccb->sgl_dma_h;
+		pthru->numsge		= megaraid_mbox_mksgl(adapter, scb);
+	}
+	else {
+		pthru->dataxferaddr	= 0;
+		pthru->dataxferlen	= 0;
+		pthru->numsge		= 0;
+	}
+	return;
+}
+
+
+/**
+ * megaraid_mbox_prepare_epthru - prepare a command for physical devices
+ * @adapter	- pointer to controller's soft state
+ * @scb		- scsi control block
+ * @scp		- scsi command from the mid-layer
+ *
+ * prepare a command for the scsi physical devices. This rountine prepares
+ * commands for devices which can take extended CDBs (>10 bytes)
+ */
+static void
+megaraid_mbox_prepare_epthru(adapter_t *adapter, scb_t *scb,
+		struct scsi_cmnd *scp)
+{
+	mbox_ccb_t		*ccb;
+	mraid_epassthru_t	*epthru;
+	uint8_t			channel;
+	uint8_t			target;
+
+	ccb	= (mbox_ccb_t *)scb->ccb;
+	epthru	= ccb->epthru;
+	channel	= scb->dev_channel;
+	target	= scb->dev_target;
+
+	// 0=6sec, 1=60sec, 2=10min, 3=3hrs, 4=NO timeout
+	epthru->timeout		= 4;	
+	epthru->ars		= 1;
+	epthru->islogical	= 0;
+	epthru->channel		= 0;
+	epthru->target		= (channel << 4) | target;
+	epthru->logdrv		= SCP2LUN(scp);
+	epthru->reqsenselen	= 14;
+	epthru->cdblen		= scp->cmd_len;
+
+	memcpy(epthru->cdb, scp->cmnd, scp->cmd_len);
+
+	if (scp->request_bufflen) {
+		epthru->dataxferlen	= scp->request_bufflen;
+		epthru->dataxferaddr	= ccb->sgl_dma_h;
+		epthru->numsge		= megaraid_mbox_mksgl(adapter, scb);
+	}
+	else {
+		epthru->dataxferaddr	= 0;
+		epthru->dataxferlen	= 0;
+		epthru->numsge		= 0;
+	}
+	return;
+}
+
+
+/**
+ * megaraid_ack_sequence - interrupt ack sequence for memory mapped HBAs
+ * @adapter	- controller's soft state
+ *
+ * Interrupt ackrowledgement sequence for memory mapped HBAs. Find out the
+ * completed command and put them on the completed list for later processing.
+ *
+ * Returns:	1 if the interrupt is valid, 0 otherwise
+ */
+static inline int
+megaraid_ack_sequence(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox_t			*mbox;
+	scb_t			*scb;
+	uint8_t			nstatus;
+	uint8_t			completed[MBOX_MAX_FIRMWARE_STATUS];
+	struct list_head	clist;
+	int			handled;
+	uint32_t		dword;
+	unsigned long		flags;
+	int			i, j;
+
+
+	mbox	= raid_dev->mbox;
+
+	// move the SCBs from the firmware completed array to our local list
+	INIT_LIST_HEAD(&clist);
+
+	// loop till F/W has more commands for us to complete
+	handled = 0;
+	spin_lock_irqsave(MAILBOX_LOCK(raid_dev), flags);
+	do {
+		/*
+		 * Check if a valid interrupt is pending. If found, force the
+		 * interrupt line low.
+		 */
+		dword = RDOUTDOOR(raid_dev);
+		if (dword != 0x10001234) break;
+
+		handled = 1;
+
+		WROUTDOOR(raid_dev, 0x10001234);
+
+		nstatus = 0;
+		// wait for valid numstatus to post
+		for (i = 0; i < 0xFFFFF; i++) {
+			if (mbox->numstatus != 0xFF) {
+				nstatus = mbox->numstatus;
+				break;
+			}
+			rmb();
+		}
+		mbox->numstatus = 0xFF;
+
+		adapter->outstanding_cmds -= nstatus;
+
+		for (i = 0; i < nstatus; i++) {
+
+			// wait for valid command index to post
+			for (j = 0; j < 0xFFFFF; j++) {
+				if (mbox->completed[i] != 0xFF) break;
+				rmb();
+			}
+			completed[i]		= mbox->completed[i];
+			mbox->completed[i]	= 0xFF;
+
+			if (completed[i] == 0xFF) {
+				con_log(CL_ANN, (KERN_CRIT
+				"megaraid: command posting timed out\n"));
+
+				BUG();
+				continue;
+			}
+
+			// Get SCB associated with this command id
+			if (completed[i] >= MBOX_MAX_SCSI_CMDS) {
+				// a cmm command
+				scb = adapter->uscb_list + (completed[i] -
+						MBOX_MAX_SCSI_CMDS);
+			}
+			else {
+				// an os command
+				scb = adapter->kscb_list + completed[i];
+			}
+
+			scb->status = mbox->status;
+			list_add_tail(&scb->list, &clist);
+		}
+
+		// Acknowledge interrupt
+		WRINDOOR(raid_dev, 0x02);
+
+	} while(1);
+
+	spin_unlock_irqrestore(MAILBOX_LOCK(raid_dev), flags);
+
+
+	// put the completed commands in the completed list. DPC would
+	// complete these commands later
+	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+
+	list_splice(&clist, &adapter->completed_list);
+
+	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+	// schedule the DPC if there is some work for it
+	if (handled)
+		tasklet_schedule(&adapter->dpc_h);
+
+	return handled;
+}
+
+
+/**
+ * megaraid_isr - isr for memory based mailbox based controllers
+ * @irq		- irq
+ * @devp	- pointer to our soft state
+ * @regs	- unused
+ *
+ * Interrupt service routine for memory-mapped mailbox controllers.
+ */
+static irqreturn_t
+megaraid_isr(int irq, void *devp, struct pt_regs *regs)
+{
+	adapter_t	*adapter = devp;
+	int		handled;
+
+	handled = megaraid_ack_sequence(adapter);
+
+	/* Loop through any pending requests */
+	if (!adapter->quiescent) {
+		megaraid_mbox_runpendq(adapter, NULL);
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+
+/**
+ * megaraid_mbox_sync_scb - sync kernel buffers
+ * @adapter	: controller's soft state
+ * @scb		: pointer to the resource packet
+ *
+ * DMA sync if required.
+ */
+static inline void
+megaraid_mbox_sync_scb(adapter_t *adapter, scb_t *scb)
+{
+	mbox_ccb_t	*ccb;
+
+	ccb	= (mbox_ccb_t *)scb->ccb;
+
+	switch (scb->dma_type) {
+
+	case MRAID_DMA_WBUF:
+		if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
+			pci_dma_sync_single_for_cpu(adapter->pdev,
+					ccb->buf_dma_h,
+					scb->scp->request_bufflen,
+					PCI_DMA_FROMDEVICE);
+		}
+
+		pci_unmap_page(adapter->pdev, ccb->buf_dma_h,
+			scb->scp->request_bufflen, scb->dma_direction);
+
+		break;
+
+	case MRAID_DMA_WSG:
+		if (scb->dma_direction == PCI_DMA_FROMDEVICE) {
+			pci_dma_sync_sg_for_cpu(adapter->pdev,
+					scb->scp->request_buffer,
+					scb->scp->use_sg, PCI_DMA_FROMDEVICE);
+		}
+
+		pci_unmap_sg(adapter->pdev, scb->scp->request_buffer,
+			scb->scp->use_sg, scb->dma_direction);
+
+		break;
+
+	default:
+		break;
+	}
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_dpc - the tasklet to complete the commands from completed list
+ * @devp	: pointer to HBA soft state
+ *
+ * Pick up the commands from the completed list and send back to the owners.
+ * This is a reentrant function and does not assume any locks are held while
+ * it is being called.
+ */
+static void
+megaraid_mbox_dpc(unsigned long devp)
+{
+	adapter_t		*adapter = (adapter_t *)devp;
+	mraid_device_t		*raid_dev;
+	struct list_head	clist;
+	struct scatterlist	*sgl;
+	scb_t			*scb;
+	scb_t			*tmp;
+	struct scsi_cmnd	*scp;
+	mraid_passthru_t	*pthru;
+	mraid_epassthru_t	*epthru;
+	mbox_ccb_t		*ccb;
+	int			islogical;
+	int			pdev_index;
+	int			pdev_state;
+	mbox_t			*mbox;
+	unsigned long		flags;
+	uint8_t			c;
+	int			status;
+
+
+	if (!adapter) return;
+
+	raid_dev = ADAP2RAIDDEV(adapter);
+
+	// move the SCBs from the completed list to our local list
+	INIT_LIST_HEAD(&clist);
+
+	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+
+	list_splice_init(&adapter->completed_list, &clist);
+
+	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+	list_for_each_entry_safe(scb, tmp, &clist, list) {
+
+		status		= scb->status;
+		scp		= scb->scp;
+		ccb		= (mbox_ccb_t *)scb->ccb;
+		pthru		= ccb->pthru;
+		epthru		= ccb->epthru;
+		mbox		= ccb->mbox;
+
+		// Make sure f/w has completed a valid command
+		if (scb->state != SCB_ISSUED) {
+			con_log(CL_ANN, (KERN_CRIT
+			"megaraid critical err: invalid command %d:%d:%p\n",
+				scb->sno, scb->state, scp));
+			BUG();
+			continue;	// Must never happen!
+		}
+
+		// check for the management command and complete it right away
+		if (scb->sno >= MBOX_MAX_SCSI_CMDS) {
+			scb->state	= SCB_FREE;
+			scb->status	= status;
+
+			// remove from local clist
+			list_del_init(&scb->list);
+
+			megaraid_mbox_mm_done(adapter, scb);
+
+			continue;
+		}
+
+		// Was an abort issued for this command earlier
+		if (scb->state & SCB_ABORT) {
+			con_log(CL_ANN, (KERN_NOTICE
+			"megaraid: aborted cmd %lx[%x] completed\n",
+				scp->serial_number, scb->sno));
+		}
+
+		/*
+		 * If the inquiry came of a disk drive which is not part of
+		 * any RAID array, expose it to the kernel. For this to be
+		 * enabled, user must set the "megaraid_expose_unconf_disks"
+		 * flag to 1 by specifying it on module parameter list.
+		 * This would enable data migration off drives from other
+		 * configurations.
+		 */
+		islogical = MRAID_IS_LOGICAL(adapter, scp);
+		if (scp->cmnd[0] == INQUIRY && status == 0 && islogical == 0
+				&& IS_RAID_CH(raid_dev, scb->dev_channel)) {
+
+			if (scp->use_sg) {
+				sgl = (struct scatterlist *)
+					scp->request_buffer;
+
+				if (sgl->page) {
+					c = *(unsigned char *)
+					(page_address((&sgl[0])->page) +
+						(&sgl[0])->offset);
+				}
+				else {
+					con_log(CL_ANN, (KERN_WARNING
+					"megaraid mailbox: invalid sg:%d\n",
+					__LINE__));
+					c = 0;
+				}
+			}
+			else {
+				c = *(uint8_t *)scp->request_buffer;
+			}
+
+			if ((c & 0x1F ) == TYPE_DISK) {
+				pdev_index = (scb->dev_channel * 16) +
+					scb->dev_target;
+				pdev_state =
+					raid_dev->pdrv_state[pdev_index] & 0x0F;
+
+				if (pdev_state == PDRV_ONLINE		||
+					pdev_state == PDRV_FAILED	||
+					pdev_state == PDRV_RBLD		||
+					pdev_state == PDRV_HOTSPARE	||
+					megaraid_expose_unconf_disks == 0) {
+
+					status = 0xF0;
+				}
+			}
+		}
+
+		// Convert MegaRAID status to Linux error code
+		switch (status) {
+
+		case 0x00:
+
+			scp->result = (DID_OK << 16);
+			break;
+
+		case 0x02:
+
+			/* set sense_buffer and result fields */
+			if (mbox->cmd == MBOXCMD_PASSTHRU ||
+				mbox->cmd == MBOXCMD_PASSTHRU64) {
+
+				memcpy(scp->sense_buffer, pthru->reqsensearea,
+						14);
+
+				scp->result = DRIVER_SENSE << 24 |
+					DID_OK << 16 | CHECK_CONDITION << 1;
+			}
+			else {
+				if (mbox->cmd == MBOXCMD_EXTPTHRU) {
+
+					memcpy(scp->sense_buffer,
+						epthru->reqsensearea, 14);
+
+					scp->result = DRIVER_SENSE << 24 |
+						DID_OK << 16 |
+						CHECK_CONDITION << 1;
+				} else {
+					scp->sense_buffer[0] = 0x70;
+					scp->sense_buffer[2] = ABORTED_COMMAND;
+					scp->result = CHECK_CONDITION << 1;
+				}
+			}
+			break;
+
+		case 0x08:
+
+			scp->result = DID_BUS_BUSY << 16 | status;
+			break;
+
+		default:
+
+			/*
+			 * If TEST_UNIT_READY fails, we know RESERVATION_STATUS
+			 * failed
+			 */
+			if (scp->cmnd[0] == TEST_UNIT_READY) {
+				scp->result = DID_ERROR << 16 |
+					RESERVATION_CONFLICT << 1;
+			}
+			else
+			/*
+			 * Error code returned is 1 if Reserve or Release
+			 * failed or the input parameter is invalid
+			 */
+			if (status == 1 && (scp->cmnd[0] == RESERVE ||
+					 scp->cmnd[0] == RELEASE)) {
+
+				scp->result = DID_ERROR << 16 |
+					RESERVATION_CONFLICT << 1;
+			}
+			else {
+				scp->result = DID_BAD_TARGET << 16 | status;
+			}
+		}
+
+		// print a debug message for all failed commands
+		if (status) {
+			megaraid_mbox_display_scb(adapter, scb);
+		}
+
+		// Free our internal resources and call the mid-layer callback
+		// routine
+		megaraid_mbox_sync_scb(adapter, scb);
+
+		// remove from local clist
+		list_del_init(&scb->list);
+
+		// put back in free list
+		megaraid_dealloc_scb(adapter, scb);
+
+		// send the scsi packet back to kernel
+		spin_lock(adapter->host_lock);
+		scp->scsi_done(scp);
+		spin_unlock(adapter->host_lock);
+	}
+
+	return;
+}
+
+
+/**
+ * megaraid_abort_handler - abort the scsi command
+ * @scp		: command to be aborted
+ *
+ * Abort a previous SCSI request. Only commands on the pending list can be
+ * aborted. All the commands issued to the F/W must complete.
+ **/
+static int
+megaraid_abort_handler(struct scsi_cmnd *scp)
+{
+	adapter_t		*adapter;
+	mraid_device_t		*raid_dev;
+	scb_t			*scb;
+	scb_t			*tmp;
+	int			found;
+	unsigned long		flags;
+	int			i;
+
+
+	adapter		= SCP2ADAPTER(scp);
+	raid_dev	= ADAP2RAIDDEV(adapter);
+
+	assert_spin_locked(adapter->host_lock);
+
+	con_log(CL_ANN, (KERN_WARNING
+		"megaraid: aborting-%ld cmd=%x <c=%d t=%d l=%d>\n",
+		scp->serial_number, scp->cmnd[0], SCP2CHANNEL(scp),
+		SCP2TARGET(scp), SCP2LUN(scp)));
+
+	// If FW has stopped responding, simply return failure
+	if (raid_dev->hw_error) {
+		con_log(CL_ANN, (KERN_NOTICE
+			"megaraid: hw error, not aborting\n"));
+		return FAILED;
+	}
+
+	// There might a race here, where the command was completed by the
+	// firmware and now it is on the completed list. Before we could
+	// complete the command to the kernel in dpc, the abort came.
+	// Find out if this is the case to avoid the race.
+	scb = NULL;
+	spin_lock_irqsave(COMPLETED_LIST_LOCK(adapter), flags);
+	list_for_each_entry_safe(scb, tmp, &adapter->completed_list, list) {
+
+		if (scb->scp == scp) {	// Found command
+
+			list_del_init(&scb->list);	// from completed list
+
+			con_log(CL_ANN, (KERN_WARNING
+			"megaraid: %ld:%d[%d:%d], abort from completed list\n",
+				scp->serial_number, scb->sno,
+				scb->dev_channel, scb->dev_target));
+
+			scp->result = (DID_ABORT << 16);
+			scp->scsi_done(scp);
+
+			megaraid_dealloc_scb(adapter, scb);
+
+			spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter),
+				flags);
+
+			return SUCCESS;
+		}
+	}
+	spin_unlock_irqrestore(COMPLETED_LIST_LOCK(adapter), flags);
+
+
+	// Find out if this command is still on the pending list. If it is and
+	// was never issued, abort and return success. If the command is owned
+	// by the firmware, we must wait for it to complete by the FW.
+	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+	list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
+
+		if (scb->scp == scp) {	// Found command
+
+			list_del_init(&scb->list);	// from pending list
+
+			ASSERT(!(scb->state & SCB_ISSUED));
+
+			con_log(CL_ANN, (KERN_WARNING
+				"megaraid abort: %ld[%d:%d], driver owner\n",
+				scp->serial_number, scb->dev_channel,
+				scb->dev_target));
+
+			scp->result = (DID_ABORT << 16);
+			scp->scsi_done(scp);
+
+			megaraid_dealloc_scb(adapter, scb);
+
+			spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter),
+				flags);
+
+			return SUCCESS;
+		}
+	}
+	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+
+	// Check do we even own this command, in which case this would be
+	// owned by the firmware. The only way to locate the FW scb is to
+	// traverse through the list of all SCB, since driver does not
+	// maintain these SCBs on any list
+	found = 0;
+	for (i = 0; i < MBOX_MAX_SCSI_CMDS; i++) {
+		scb = adapter->kscb_list + i;
+
+		if (scb->scp == scp) {
+
+			found = 1;
+
+			if (!(scb->state & SCB_ISSUED)) {
+				con_log(CL_ANN, (KERN_WARNING
+				"megaraid abort: %ld%d[%d:%d], invalid state\n",
+				scp->serial_number, scb->sno, scb->dev_channel,
+				scb->dev_target));
+				BUG();
+			}
+			else {
+				con_log(CL_ANN, (KERN_WARNING
+				"megaraid abort: %ld:%d[%d:%d], fw owner\n",
+				scp->serial_number, scb->sno, scb->dev_channel,
+				scb->dev_target));
+			}
+		}
+	}
+
+	if (!found) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid abort: scsi cmd:%ld, do now own\n",
+			scp->serial_number));
+
+		// FIXME: Should there be a callback for this command?
+		return SUCCESS;
+	}
+
+	// We cannot actually abort a command owned by firmware, return
+	// failure and wait for reset. In host reset handler, we will find out
+	// if the HBA is still live
+	return FAILED;
+}
+
+
+/**
+ * megaraid_reset_handler - device reset hadler for mailbox based driver
+ * @scp		: reference command
+ *
+ * Reset handler for the mailbox based controller. First try to find out if
+ * the FW is still live, in which case the outstanding commands counter mut go
+ * down to 0. If that happens, also issue the reservation reset command to
+ * relinquish (possible) reservations on the logical drives connected to this
+ * host
+ **/
+static int
+megaraid_reset_handler(struct scsi_cmnd *scp)
+{
+	adapter_t	*adapter;
+	scb_t		*scb;
+	scb_t		*tmp;
+	mraid_device_t	*raid_dev;
+	unsigned long	flags;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+	int		rval;
+	int		recovery_window;
+	int		recovering;
+	int		i;
+
+	adapter		= SCP2ADAPTER(scp);
+	raid_dev	= ADAP2RAIDDEV(adapter);
+
+	assert_spin_locked(adapter->host_lock);
+
+	con_log(CL_ANN, (KERN_WARNING "megaraid: reseting the host...\n"));
+
+	// return failure if adapter is not responding
+	if (raid_dev->hw_error) {
+		con_log(CL_ANN, (KERN_NOTICE
+			"megaraid: hw error, cannot reset\n"));
+		return FAILED;
+	}
+
+
+	// Under exceptional conditions, FW can take up to 3 minutes to
+	// complete command processing. Wait for additional 2 minutes for the
+	// pending commands counter to go down to 0. If it doesn't, let the
+	// controller be marked offline
+	// Also, reset all the commands currently owned by the driver
+	spin_lock_irqsave(PENDING_LIST_LOCK(adapter), flags);
+	list_for_each_entry_safe(scb, tmp, &adapter->pend_list, list) {
+
+		list_del_init(&scb->list);	// from pending list
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: %ld:%d[%d:%d], reset from pending list\n",
+				scp->serial_number, scb->sno,
+				scb->dev_channel, scb->dev_target));
+
+		scp->result = (DID_RESET << 16);
+		scp->scsi_done(scp);
+
+		megaraid_dealloc_scb(adapter, scb);
+	}
+	spin_unlock_irqrestore(PENDING_LIST_LOCK(adapter), flags);
+
+	if (adapter->outstanding_cmds) {
+		con_log(CL_ANN, (KERN_NOTICE
+			"megaraid: %d outstanding commands. Max wait %d sec\n",
+			adapter->outstanding_cmds, MBOX_RESET_WAIT));
+	}
+
+	spin_unlock(adapter->host_lock);
+
+	recovery_window = MBOX_RESET_WAIT + MBOX_RESET_EXT_WAIT;
+
+	recovering = adapter->outstanding_cmds;
+
+	for (i = 0; i < recovery_window && adapter->outstanding_cmds; i++) {
+
+		megaraid_ack_sequence(adapter);
+
+		// print a message once every 5 seconds only
+		if (!(i % 5)) {
+			con_log(CL_ANN, (
+			"megaraid mbox: Wait for %d commands to complete:%d\n",
+				adapter->outstanding_cmds,
+				MBOX_RESET_WAIT - i));
+		}
+
+		// bailout if no recovery happended in reset time
+		if ((i == MBOX_RESET_WAIT) &&
+			(recovering == adapter->outstanding_cmds)) {
+			break;
+		}
+
+		msleep(1000);
+	}
+
+	spin_lock(adapter->host_lock);
+
+	// If still outstanding commands, bail out
+	if (adapter->outstanding_cmds) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mbox: critical hardware error!\n"));
+
+		raid_dev->hw_error = 1;
+
+		return FAILED;
+	}
+	else {
+		con_log(CL_ANN, (KERN_NOTICE
+		"megaraid mbox: reset sequence completed sucessfully\n"));
+	}
+
+
+	// If the controller supports clustering, reset reservations
+	if (!adapter->ha) return SUCCESS;
+
+	// clear reservations if any
+	raw_mbox[0] = CLUSTER_CMD;
+	raw_mbox[2] = RESET_RESERVATIONS;
+
+	rval = SUCCESS;
+	if (mbox_post_sync_cmd_fast(adapter, raw_mbox) == 0) {
+		con_log(CL_ANN,
+			(KERN_INFO "megaraid: reservation reset\n"));
+	}
+	else {
+		rval = FAILED;
+		con_log(CL_ANN, (KERN_WARNING
+				"megaraid: reservation reset failed\n"));
+	}
+
+	return rval;
+}
+
+
+/*
+ * START: internal commands library
+ *
+ * This section of the driver has the common routine used by the driver and
+ * also has all the FW routines
+ */
+
+/**
+ * mbox_post_sync_cmd() - blocking command to the mailbox based controllers
+ * @adapter	- controller's soft state
+ * @raw_mbox	- the mailbox
+ *
+ * Issue a scb in synchronous and non-interrupt mode for mailbox based
+ * controllers
+ */
+static int
+mbox_post_sync_cmd(adapter_t *adapter, uint8_t raw_mbox[])
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox64_t	*mbox64;
+	mbox_t		*mbox;
+	uint8_t		status;
+	int		i;
+
+
+	mbox64	= raid_dev->mbox64;
+	mbox	= raid_dev->mbox;
+
+	/*
+	 * Wait until mailbox is free
+	 */
+	if (megaraid_busywait_mbox(raid_dev) != 0)
+		goto blocked_mailbox;
+
+	/*
+	 * Copy mailbox data into host structure
+	 */
+	memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 16);
+	mbox->cmdid		= 0xFE;
+	mbox->busy		= 1;
+	mbox->poll		= 0;
+	mbox->ack		= 0;
+	mbox->numstatus		= 0xFF;
+	mbox->status		= 0xFF;
+
+	wmb();
+	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+	// wait for maximum 1 second for status to post. If the status is not
+	// available within 1 second, assume FW is initializing and wait
+	// for an extended amount of time
+	if (mbox->numstatus == 0xFF) {	// status not yet available
+		udelay(25);;
+
+		for (i = 0; mbox->numstatus == 0xFF && i < 1000; i++) {
+			rmb();
+			msleep(1);
+		}
+
+
+		if (i == 1000) {
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid mailbox: wait for FW to boot      "));
+
+			for (i = 0; (mbox->numstatus == 0xFF) &&
+					(i < MBOX_RESET_WAIT); i++) {
+				rmb();
+				con_log(CL_ANN, ("\b\b\b\b\b[%03d]",
+							MBOX_RESET_WAIT - i));
+				msleep(1000);
+			}
+
+			if (i == MBOX_RESET_WAIT) {
+
+				con_log(CL_ANN, (
+				"\nmegaraid mailbox: status not available\n"));
+
+				return -1;
+			}
+			con_log(CL_ANN, ("\b\b\b\b\b[ok] \n"));
+		}
+	}
+
+	// wait for maximum 1 second for poll semaphore
+	if (mbox->poll != 0x77) {
+		udelay(25);
+
+		for (i = 0; (mbox->poll != 0x77) && (i < 1000); i++) {
+			rmb();
+			msleep(1);
+		}
+
+		if (i == 1000) {
+			con_log(CL_ANN, (KERN_WARNING
+			"megaraid mailbox: could not get poll semaphore\n"));
+			return -1;
+		}
+	}
+
+	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
+	wmb();
+
+	// wait for maximum 1 second for acknowledgement
+	if (RDINDOOR(raid_dev) & 0x2) {
+		udelay(25);
+
+		for (i = 0; (RDINDOOR(raid_dev) & 0x2) && (i < 1000); i++) {
+			rmb();
+			msleep(1);
+		}
+
+		if (i == 1000) {
+			con_log(CL_ANN, (KERN_WARNING
+				"megaraid mailbox: could not acknowledge\n"));
+			return -1;
+		}
+	}
+	mbox->poll	= 0;
+	mbox->ack	= 0x77;
+
+	status = mbox->status;
+
+	// invalidate the completed command id array. After command
+	// completion, firmware would write the valid id.
+	mbox->numstatus	= 0xFF;
+	mbox->status	= 0xFF;
+	for (i = 0; i < MBOX_MAX_FIRMWARE_STATUS; i++) {
+		mbox->completed[i] = 0xFF;
+	}
+
+	return status;
+
+blocked_mailbox:
+
+	con_log(CL_ANN, (KERN_WARNING "megaraid: blocked mailbox\n") );
+	return -1;
+}
+
+
+/**
+ * mbox_post_sync_cmd_fast - blocking command to the mailbox based controllers
+ * @adapter	- controller's soft state
+ * @raw_mbox	- the mailbox
+ *
+ * Issue a scb in synchronous and non-interrupt mode for mailbox based
+ * controllers. This is a faster version of the synchronous command and
+ * therefore can be called in interrupt-context as well
+ */
+static int
+mbox_post_sync_cmd_fast(adapter_t *adapter, uint8_t raw_mbox[])
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox_t		*mbox;
+	long		i;
+
+
+	mbox	= raid_dev->mbox;
+
+	// return immediately if the mailbox is busy
+	if (mbox->busy) return -1;
+
+	// Copy mailbox data into host structure
+	memcpy((caddr_t)mbox, (caddr_t)raw_mbox, 14);
+	mbox->cmdid		= 0xFE;
+	mbox->busy		= 1;
+	mbox->poll		= 0;
+	mbox->ack		= 0;
+	mbox->numstatus		= 0xFF;
+	mbox->status		= 0xFF;
+
+	wmb();
+	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x1);
+
+	for (i = 0; i < 0xFFFFF; i++) {
+		if (mbox->numstatus != 0xFF) break;
+	}
+
+	if (i == 0xFFFFF) {
+		// We may need to re-calibrate the counter
+		con_log(CL_ANN, (KERN_CRIT
+			"megaraid: fast sync command timed out\n"));
+	}
+
+	WRINDOOR(raid_dev, raid_dev->mbox_dma | 0x2);
+	wmb();
+
+	return mbox->status;
+}
+
+
+/**
+ * megaraid_busywait_mbox() - Wait until the controller's mailbox is available
+ * @raid_dev	- RAID device (HBA) soft state
+ *
+ * wait until the controller's mailbox is available to accept more commands.
+ * wait for at most 1 second
+ */
+static int
+megaraid_busywait_mbox(mraid_device_t *raid_dev)
+{
+	mbox_t	*mbox = raid_dev->mbox;
+	int	i = 0;
+
+	if (mbox->busy) {
+		udelay(25);
+		for (i = 0; mbox->busy && i < 1000; i++)
+			msleep(1);
+	}
+
+	if (i < 1000) return 0;
+	else return -1;
+}
+
+
+/**
+ * megaraid_mbox_product_info - some static information about the controller
+ * @adapter	- our soft state
+ *
+ * issue commands to the controller to grab some parameters required by our
+ * caller.
+ */
+static int
+megaraid_mbox_product_info(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox_t			*mbox;
+	uint8_t			raw_mbox[sizeof(mbox_t)];
+	mraid_pinfo_t		*pinfo;
+	dma_addr_t		pinfo_dma_h;
+	mraid_inquiry3_t	*mraid_inq3;
+	int			i;
+
+
+	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+	mbox = (mbox_t *)raw_mbox;
+
+	/*
+	 * Issue an ENQUIRY3 command to find out certain adapter parameters,
+	 * e.g., max channels, max commands etc.
+	 */
+	pinfo = pci_alloc_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+			&pinfo_dma_h);
+
+	if (pinfo == NULL) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+
+		return -1;
+	}
+	memset(pinfo, 0, sizeof(mraid_pinfo_t));
+
+	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	raw_mbox[0] = FC_NEW_CONFIG;
+	raw_mbox[2] = NC_SUBOP_ENQUIRY3;
+	raw_mbox[3] = ENQ3_GET_SOLICITED_FULL;
+
+	// Issue the command
+	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING "megaraid: Inquiry3 failed\n"));
+
+		pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+			pinfo, pinfo_dma_h);
+
+		return -1;
+	}
+
+	/*
+	 * Collect information about state of each physical drive
+	 * attached to the controller. We will expose all the disks
+	 * which are not part of RAID
+	 */
+	mraid_inq3 = (mraid_inquiry3_t *)adapter->ibuf;
+	for (i = 0; i < MBOX_MAX_PHYSICAL_DRIVES; i++) {
+		raid_dev->pdrv_state[i] = mraid_inq3->pdrv_state[i];
+	}
+
+	/*
+	 * Get product info for information like number of channels,
+	 * maximum commands supported.
+	 */
+	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+	mbox->xferaddr = (uint32_t)pinfo_dma_h;
+
+	raw_mbox[0] = FC_NEW_CONFIG;
+	raw_mbox[2] = NC_SUBOP_PRODUCT_INFO;
+
+	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: product info failed\n"));
+
+		pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t),
+			pinfo, pinfo_dma_h);
+
+		return -1;
+	}
+
+	/*
+	 * Setup some parameters for host, as required by our caller
+	 */
+	adapter->max_channel = pinfo->nchannels;
+
+	/*
+	 * we will export all the logical drives on a single channel.
+	 * Add 1 since inquires do not come for inititor ID
+	 */
+	adapter->max_target	= MAX_LOGICAL_DRIVES_40LD + 1;
+	adapter->max_lun	= 8;	// up to 8 LUNs for non-disk devices
+
+	/*
+	 * These are the maximum outstanding commands for the scsi-layer
+	 */
+	adapter->max_cmds	= MBOX_MAX_SCSI_CMDS;
+
+	memset(adapter->fw_version, 0, VERSION_SIZE);
+	memset(adapter->bios_version, 0, VERSION_SIZE);
+
+	memcpy(adapter->fw_version, pinfo->fw_version, 4);
+	adapter->fw_version[4] = 0;
+
+	memcpy(adapter->bios_version, pinfo->bios_version, 4);
+	adapter->bios_version[4] = 0;
+
+	con_log(CL_ANN, (KERN_NOTICE
+		"megaraid: fw version:[%s] bios version:[%s]\n",
+		adapter->fw_version, adapter->bios_version));
+
+	pci_free_consistent(adapter->pdev, sizeof(mraid_pinfo_t), pinfo,
+			pinfo_dma_h);
+
+	return 0;
+}
+
+
+
+/**
+ * megaraid_mbox_extended_cdb - check for support for extended CDBs
+ * @adapter	- soft state for the controller
+ *
+ * this routine check whether the controller in question supports extended
+ * ( > 10 bytes ) CDBs
+ */
+static int
+megaraid_mbox_extended_cdb(adapter_t *adapter)
+{
+	mbox_t		*mbox;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+	int		rval;
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+	mbox->xferaddr	= (uint32_t)adapter->ibuf_dma_h;
+
+	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	raw_mbox[0] = MAIN_MISC_OPCODE;
+	raw_mbox[2] = SUPPORT_EXT_CDB;
+
+	/*
+	 * Issue the command
+	 */
+	rval = 0;
+	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+		rval = -1;
+	}
+
+	return rval;
+}
+
+
+/**
+ * megaraid_mbox_support_ha - Do we support clustering
+ * @adapter	- soft state for the controller
+ * @init_id	- ID of the initiator
+ *
+ * Determine if the firmware supports clustering and the ID of the initiator.
+ */
+static int
+megaraid_mbox_support_ha(adapter_t *adapter, uint16_t *init_id)
+{
+	mbox_t		*mbox;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+	int		rval;
+
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(raw_mbox));
+
+	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	raw_mbox[0] = GET_TARGET_ID;
+
+	// Issue the command
+	*init_id = 7;
+	rval =  -1;
+	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+
+		*init_id = *(uint8_t *)adapter->ibuf;
+
+		con_log(CL_ANN, (KERN_INFO
+			"megaraid: cluster firmware, initiator ID: %d\n",
+			*init_id));
+
+		rval =  0;
+	}
+
+	return rval;
+}
+
+
+/**
+ * megaraid_mbox_support_random_del - Do we support random deletion
+ * @adapter	- soft state for the controller
+ *
+ * Determine if the firmware supports random deletion
+ * Return:	1 is operation supported, 0 otherwise
+ */
+static int
+megaraid_mbox_support_random_del(adapter_t *adapter)
+{
+	mbox_t		*mbox;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+	int		rval;
+
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+	raw_mbox[0] = FC_DEL_LOGDRV;
+	raw_mbox[2] = OP_SUP_DEL_LOGDRV;
+
+	// Issue the command
+	rval = 0;
+	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+
+		con_log(CL_DLEVEL1, ("megaraid: supports random deletion\n"));
+
+		rval =  1;
+	}
+
+	return rval;
+}
+
+
+/**
+ * megaraid_mbox_get_max_sg - maximum sg elements supported by the firmware
+ * @adapter	- soft state for the controller
+ *
+ * Find out the maximum number of scatter-gather elements supported by the
+ * firmware
+ */
+static int
+megaraid_mbox_get_max_sg(adapter_t *adapter)
+{
+	mbox_t		*mbox;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+	int		nsg;
+
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	raw_mbox[0] = MAIN_MISC_OPCODE;
+	raw_mbox[2] = GET_MAX_SG_SUPPORT;
+
+	// Issue the command
+	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+		nsg =  *(uint8_t *)adapter->ibuf;
+	}
+	else {
+		nsg =  MBOX_DEFAULT_SG_SIZE;
+	}
+
+	if (nsg > MBOX_MAX_SG_SIZE) nsg = MBOX_MAX_SG_SIZE;
+
+	return nsg;
+}
+
+
+/**
+ * megaraid_mbox_enum_raid_scsi - enumerate the RAID and SCSI channels
+ * @adapter	- soft state for the controller
+ *
+ * Enumerate the RAID and SCSI channels for ROMB platoforms so that channels
+ * can be exported as regular SCSI channels
+ */
+static void
+megaraid_mbox_enum_raid_scsi(adapter_t *adapter)
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	mbox_t		*mbox;
+	uint8_t		raw_mbox[sizeof(mbox_t)];
+
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+	mbox->xferaddr = (uint32_t)adapter->ibuf_dma_h;
+
+	memset((void *)adapter->ibuf, 0, MBOX_IBUF_SIZE);
+
+	raw_mbox[0] = CHNL_CLASS;
+	raw_mbox[2] = GET_CHNL_CLASS;
+
+	// Issue the command. If the command fails, all channels are RAID
+	// channels
+	raid_dev->channel_class = 0xFF;
+	if (mbox_post_sync_cmd(adapter, raw_mbox) == 0) {
+		raid_dev->channel_class =  *(uint8_t *)adapter->ibuf;
+	}
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_flush_cache - flush adapter and disks cache
+ * @param adapter	: soft state for the controller
+ *
+ * Flush adapter cache followed by disks cache
+ */
+static void
+megaraid_mbox_flush_cache(adapter_t *adapter)
+{
+	mbox_t	*mbox;
+	uint8_t	raw_mbox[sizeof(mbox_t)];
+
+
+	mbox = (mbox_t *)raw_mbox;
+
+	memset((caddr_t)raw_mbox, 0, sizeof(mbox_t));
+
+	raw_mbox[0] = FLUSH_ADAPTER;
+
+	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+		con_log(CL_ANN, ("megaraid: flush adapter failed\n"));
+	}
+
+	raw_mbox[0] = FLUSH_SYSTEM;
+
+	if (mbox_post_sync_cmd(adapter, raw_mbox) != 0) {
+		con_log(CL_ANN, ("megaraid: flush disks cache failed\n"));
+	}
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_display_scb - display SCB information, mostly debug purposes
+ * @param adapter	: controllers' soft state
+ * @param scb		: SCB to be displayed
+ * @param level	: debug level for console print
+ *
+ * Diplay information about the given SCB iff the current debug level is
+ * verbose
+ */
+static void
+megaraid_mbox_display_scb(adapter_t *adapter, scb_t *scb)
+{
+	mbox_ccb_t		*ccb;
+	struct scsi_cmnd	*scp;
+	mbox_t			*mbox;
+	int			level;
+	int			i;
+
+
+	ccb	= (mbox_ccb_t *)scb->ccb;
+	scp	= scb->scp;
+	mbox	= ccb->mbox;
+
+	level = CL_DLEVEL3;
+
+	con_log(level, (KERN_NOTICE
+		"megaraid mailbox: status:%#x cmd:%#x id:%#x ", scb->status,
+		mbox->cmd, scb->sno));
+
+	con_log(level, ("sec:%#x lba:%#x addr:%#x ld:%d sg:%d\n",
+		mbox->numsectors, mbox->lba, mbox->xferaddr, mbox->logdrv,
+		mbox->numsge));
+
+	if (!scp) return;
+
+	con_log(level, (KERN_NOTICE "scsi cmnd: "));
+
+	for (i = 0; i < scp->cmd_len; i++) {
+		con_log(level, ("%#2.02x ", scp->cmnd[i]));
+	}
+
+	con_log(level, ("\n"));
+
+	return;
+}
+
+
+/**
+ * megaraid_mbox_setup_device_map - manage device ids
+ * @adapter	: Driver's soft state
+ *
+ * Manange the device ids to have an appropraite mapping between the kernel
+ * scsi addresses and megaraid scsi and logical drive addresses. We export
+ * scsi devices on their actual addresses, whereas the logical drives are
+ * exported on a virtual scsi channel.
+ **/
+static void
+megaraid_mbox_setup_device_map(adapter_t *adapter)
+{
+	uint8_t		c;
+	uint8_t		t;
+
+	/*
+	 * First fill the values on the logical drive channel
+	 */
+	for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
+		adapter->device_ids[adapter->max_channel][t] =
+			(t < adapter->init_id) ?  t : t - 1;
+
+	adapter->device_ids[adapter->max_channel][adapter->init_id] = 0xFF;
+
+	/*
+	 * Fill the values on the physical devices channels
+	 */
+	for (c = 0; c < adapter->max_channel; c++)
+		for (t = 0; t < LSI_MAX_LOGICAL_DRIVES_64LD; t++)
+			adapter->device_ids[c][t] = (c << 8) | t;
+}
+
+
+/*
+ * END: internal commands library
+ */
+
+/*
+ * START: Interface for the common management module
+ *
+ * This is the module, which interfaces with the common mangement module to
+ * provide support for ioctl and sysfs
+ */
+
+/**
+ * megaraid_cmm_register - register with the mangement module
+ * @param adapter	: HBA soft state
+ *
+ * Register with the management module, which allows applications to issue
+ * ioctl calls to the drivers. This interface is used by the management module
+ * to setup sysfs support as well.
+ */
+static int
+megaraid_cmm_register(adapter_t *adapter)
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	mraid_mmadp_t	adp;
+	scb_t		*scb;
+	mbox_ccb_t	*ccb;
+	int		rval;
+	int		i;
+
+	// Allocate memory for the base list of scb for management module.
+	adapter->uscb_list = kmalloc(sizeof(scb_t) * MBOX_MAX_USER_CMDS,
+			GFP_KERNEL);
+
+	if (adapter->uscb_list == NULL) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+		return -1;
+	}
+	memset(adapter->uscb_list, 0, sizeof(scb_t) * MBOX_MAX_USER_CMDS);
+
+
+	// Initialize the synchronization parameters for resources for
+	// commands for management module
+	INIT_LIST_HEAD(&adapter->uscb_pool);
+
+	spin_lock_init(USER_FREE_LIST_LOCK(adapter));
+
+
+
+	// link all the packets. Note, CCB for commands, coming from the
+	// commom management module, mailbox physical address are already
+	// setup by it. We just need placeholder for that in our local command
+	// control blocks
+	for (i = 0; i < MBOX_MAX_USER_CMDS; i++) {
+
+		scb			= adapter->uscb_list + i;
+		ccb			= raid_dev->uccb_list + i;
+
+		scb->ccb		= (caddr_t)ccb;
+		ccb->mbox64		= raid_dev->umbox64 + i;
+		ccb->mbox		= &ccb->mbox64->mbox32;
+		ccb->raw_mbox		= (uint8_t *)ccb->mbox;
+
+		scb->gp			= 0;
+
+		// COMMAND ID 0 - (MBOX_MAX_SCSI_CMDS-1) ARE RESERVED FOR
+		// COMMANDS COMING FROM IO SUBSYSTEM (MID-LAYER)
+		scb->sno		= i + MBOX_MAX_SCSI_CMDS;
+
+		scb->scp		= NULL;
+		scb->state		= SCB_FREE;
+		scb->dma_direction	= PCI_DMA_NONE;
+		scb->dma_type		= MRAID_DMA_NONE;
+		scb->dev_channel	= -1;
+		scb->dev_target		= -1;
+
+		// put scb in the free pool
+		list_add_tail(&scb->list, &adapter->uscb_pool);
+	}
+
+	adp.unique_id		= adapter->unique_id;
+	adp.drvr_type		= DRVRTYPE_MBOX;
+	adp.drvr_data		= (unsigned long)adapter;
+	adp.pdev		= adapter->pdev;
+	adp.issue_uioc		= megaraid_mbox_mm_handler;
+	adp.timeout		= 300;
+	adp.max_kioc		= MBOX_MAX_USER_CMDS;
+
+	if ((rval = mraid_mm_register_adp(&adp)) != 0) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mbox: did not register with CMM\n"));
+
+		kfree(adapter->uscb_list);
+	}
+
+	return rval;
+}
+
+
+/**
+ * megaraid_cmm_unregister - un-register with the mangement module
+ * @param adapter	: HBA soft state
+ *
+ * Un-register with the management module.
+ * FIXME: mgmt module must return failure for unregister if it has pending
+ * commands in LLD
+ */
+static int
+megaraid_cmm_unregister(adapter_t *adapter)
+{
+	kfree(adapter->uscb_list);
+	mraid_mm_unregister_adp(adapter->unique_id);
+	return 0;
+}
+
+
+/**
+ * megaraid_mbox_mm_handler - interface for CMM to issue commands to LLD
+ * @param drvr_data	: LLD specific data
+ * @param kioc		: CMM interface packet
+ * @param action	: command action
+ *
+ * This routine is invoked whenever the Common Mangement Module (CMM) has a
+ * command for us. The 'action' parameter specifies if this is a new command
+ * or otherwise.
+ */
+static int
+megaraid_mbox_mm_handler(unsigned long drvr_data, uioc_t *kioc, uint32_t action)
+{
+	adapter_t *adapter;
+
+	if (action != IOCTL_ISSUE) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: unsupported management action:%#2x\n",
+			action));
+		return (-ENOTSUPP);
+	}
+
+	adapter = (adapter_t *)drvr_data;
+
+	// make sure this adapter is not being detached right now.
+	if (atomic_read(&adapter->being_detached)) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: reject management request, detaching\n"));
+		return (-ENODEV);
+	}
+
+	switch (kioc->opcode) {
+
+	case GET_ADAP_INFO:
+
+		kioc->status =  gather_hbainfo(adapter, (mraid_hba_info_t *)
+					(unsigned long)kioc->buf_vaddr);
+
+		kioc->done(kioc);
+
+		return kioc->status;
+
+	case MBOX_CMD:
+
+		return megaraid_mbox_mm_command(adapter, kioc);
+
+	default:
+		kioc->status = (-EINVAL);
+		kioc->done(kioc);
+		return (-EINVAL);
+	}
+
+	return 0;	// not reached
+}
+
+/**
+ * megaraid_mbox_mm_command - issues commands routed through CMM
+ * @param adapter	: HBA soft state
+ * @param kioc		: management command packet
+ *
+ * Issues commands, which are routed through the management module.
+ */
+static int
+megaraid_mbox_mm_command(adapter_t *adapter, uioc_t *kioc)
+{
+	struct list_head	*head = &adapter->uscb_pool;
+	mbox64_t		*mbox64;
+	uint8_t			*raw_mbox;
+	scb_t			*scb;
+	mbox_ccb_t		*ccb;
+	unsigned long		flags;
+
+	// detach one scb from free pool
+	spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
+
+	if (list_empty(head)) {	// should never happen because of CMM
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid mbox: bug in cmm handler, lost resources\n"));
+
+		spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+		return (-EINVAL);
+	}
+
+	scb = list_entry(head->next, scb_t, list);
+	list_del_init(&scb->list);
+
+	spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+	scb->state		= SCB_ACTIVE;
+	scb->dma_type		= MRAID_DMA_NONE;
+	scb->dma_direction	= PCI_DMA_NONE;
+
+	ccb		= (mbox_ccb_t *)scb->ccb;
+	mbox64		= (mbox64_t *)(unsigned long)kioc->cmdbuf;
+	raw_mbox	= (uint8_t *)&mbox64->mbox32;
+
+	memcpy(ccb->mbox64, mbox64, sizeof(mbox64_t));
+
+	scb->gp		= (unsigned long)kioc;
+
+	/*
+	 * If it is a logdrv random delete operation, we have to wait till
+	 * there are no outstanding cmds at the fw and then issue it directly
+	 */
+	if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
+
+		if (wait_till_fw_empty(adapter)) {
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid mbox: LD delete, timed out\n"));
+
+			kioc->status = -ETIME;
+
+			scb->status = -1;
+
+			megaraid_mbox_mm_done(adapter, scb);
+
+			return (-ETIME);
+		}
+
+		INIT_LIST_HEAD(&scb->list);
+
+		scb->state = SCB_ISSUED;
+		if (mbox_post_cmd(adapter, scb) != 0) {
+
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid mbox: LD delete, mailbox busy\n"));
+
+			kioc->status = -EBUSY;
+
+			scb->status = -1;
+
+			megaraid_mbox_mm_done(adapter, scb);
+
+			return (-EBUSY);
+		}
+
+		return 0;
+	}
+
+	// put the command on the pending list and execute
+	megaraid_mbox_runpendq(adapter, scb);
+
+	return 0;
+}
+
+
+static int
+wait_till_fw_empty(adapter_t *adapter)
+{
+	unsigned long	flags = 0;
+	int		i;
+
+
+	/*
+	 * Set the quiescent flag to stop issuing cmds to FW.
+	 */
+	spin_lock_irqsave(adapter->host_lock, flags);
+	adapter->quiescent++;
+	spin_unlock_irqrestore(adapter->host_lock, flags);
+
+	/*
+	 * Wait till there are no more cmds outstanding at FW. Try for at most
+	 * 60 seconds
+	 */
+	for (i = 0; i < 60 && adapter->outstanding_cmds; i++) {
+		con_log(CL_DLEVEL1, (KERN_INFO
+			"megaraid: FW has %d pending commands\n",
+			adapter->outstanding_cmds));
+
+		msleep(1000);
+	}
+
+	return adapter->outstanding_cmds;
+}
+
+
+/**
+ * megaraid_mbox_mm_done - callback for CMM commands
+ * @adapter	: HBA soft state
+ * @scb		: completed command
+ *
+ * Callback routine for internal commands originated from the management
+ * module.
+ */
+static void
+megaraid_mbox_mm_done(adapter_t *adapter, scb_t *scb)
+{
+	uioc_t			*kioc;
+	mbox64_t		*mbox64;
+	uint8_t			*raw_mbox;
+	unsigned long		flags;
+
+	kioc			= (uioc_t *)scb->gp;
+	kioc->status		= 0;
+	mbox64			= (mbox64_t *)(unsigned long)kioc->cmdbuf;
+	mbox64->mbox32.status	= scb->status;
+	raw_mbox		= (uint8_t *)&mbox64->mbox32;
+
+
+	// put scb in the free pool
+	scb->state	= SCB_FREE;
+	scb->scp	= NULL;
+
+	spin_lock_irqsave(USER_FREE_LIST_LOCK(adapter), flags);
+
+	list_add(&scb->list, &adapter->uscb_pool);
+
+	spin_unlock_irqrestore(USER_FREE_LIST_LOCK(adapter), flags);
+
+	// if a delete logical drive operation succeeded, restart the
+	// controller
+	if (raw_mbox[0] == FC_DEL_LOGDRV && raw_mbox[2] == OP_DEL_LOGDRV) {
+
+		adapter->quiescent--;
+
+		megaraid_mbox_runpendq(adapter, NULL);
+	}
+
+	kioc->done(kioc);
+
+	return;
+}
+
+
+/**
+ * gather_hbainfo - HBA characteristics for the applications
+ * @param adapter	: HBA soft state
+ * @param hinfo		: pointer to the caller's host info strucuture
+ */
+static int
+gather_hbainfo(adapter_t *adapter, mraid_hba_info_t *hinfo)
+{
+	uint8_t	dmajor;
+
+	dmajor			= megaraid_mbox_version[0];
+
+	hinfo->pci_vendor_id	= adapter->pdev->vendor;
+	hinfo->pci_device_id	= adapter->pdev->device;
+	hinfo->subsys_vendor_id	= adapter->pdev->subsystem_vendor;
+	hinfo->subsys_device_id	= adapter->pdev->subsystem_device;
+
+	hinfo->pci_bus		= adapter->pdev->bus->number;
+	hinfo->pci_dev_fn	= adapter->pdev->devfn;
+	hinfo->pci_slot		= PCI_SLOT(adapter->pdev->devfn);
+	hinfo->irq		= adapter->host->irq;
+	hinfo->baseport		= ADAP2RAIDDEV(adapter)->baseport;
+
+	hinfo->unique_id	= (hinfo->pci_bus << 8) | adapter->pdev->devfn;
+	hinfo->host_no		= adapter->host->host_no;
+
+	return 0;
+}
+
+/*
+ * END: Interface for the common management module
+ */
+
+
+
+/**
+ * megaraid_sysfs_alloc_resources - allocate sysfs related resources
+ *
+ * Allocate packets required to issue FW calls whenever the sysfs attributes
+ * are read. These attributes would require up-to-date information from the
+ * FW. Also set up resources for mutual exclusion to share these resources and
+ * the wait queue.
+ *
+ * @param adapter : controller's soft state
+ *
+ * @return 0 on success
+ * @return -ERROR_CODE on failure
+ */
+static int
+megaraid_sysfs_alloc_resources(adapter_t *adapter)
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	int		rval = 0;
+
+	raid_dev->sysfs_uioc = kmalloc(sizeof(uioc_t), GFP_KERNEL);
+
+	raid_dev->sysfs_mbox64 = kmalloc(sizeof(mbox64_t), GFP_KERNEL);
+
+	raid_dev->sysfs_buffer = pci_alloc_consistent(adapter->pdev,
+			PAGE_SIZE, &raid_dev->sysfs_buffer_dma);
+
+	if (!raid_dev->sysfs_uioc || !raid_dev->sysfs_mbox64 ||
+		!raid_dev->sysfs_buffer) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+
+		rval = -ENOMEM;
+
+		megaraid_sysfs_free_resources(adapter);
+	}
+
+	sema_init(&raid_dev->sysfs_sem, 1);
+
+	init_waitqueue_head(&raid_dev->sysfs_wait_q);
+
+	return rval;
+}
+
+
+/**
+ * megaraid_sysfs_free_resources - free sysfs related resources
+ *
+ * Free packets allocated for sysfs FW commands
+ *
+ * @param adapter : controller's soft state
+ */
+static void
+megaraid_sysfs_free_resources(adapter_t *adapter)
+{
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+
+	if (raid_dev->sysfs_uioc) kfree(raid_dev->sysfs_uioc);
+
+	if (raid_dev->sysfs_mbox64) kfree(raid_dev->sysfs_mbox64);
+
+	if (raid_dev->sysfs_buffer) {
+		pci_free_consistent(adapter->pdev, PAGE_SIZE,
+			raid_dev->sysfs_buffer, raid_dev->sysfs_buffer_dma);
+	}
+}
+
+
+/**
+ * megaraid_sysfs_get_ldmap_done - callback for get ldmap
+ *
+ * Callback routine called in the ISR/tasklet context for get ldmap call
+ *
+ * @param uioc : completed packet
+ */
+static void
+megaraid_sysfs_get_ldmap_done(uioc_t *uioc)
+{
+	adapter_t	*adapter = (adapter_t *)uioc->buf_vaddr;
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+
+	uioc->status = 0;
+
+	wake_up(&raid_dev->sysfs_wait_q);
+}
+
+
+/**
+ * megaraid_sysfs_get_ldmap_timeout - timeout handling for get ldmap
+ *
+ * Timeout routine to recover and return to application, in case the adapter
+ * has stopped responding. A timeout of 60 seconds for this command seem like
+ * a good value
+ *
+ * @param uioc : timed out packet
+ */
+static void
+megaraid_sysfs_get_ldmap_timeout(unsigned long data)
+{
+	uioc_t		*uioc = (uioc_t *)data;
+	adapter_t	*adapter = (adapter_t *)uioc->buf_vaddr;
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+
+	uioc->status = -ETIME;
+
+	wake_up(&raid_dev->sysfs_wait_q);
+}
+
+
+/**
+ * megaraid_sysfs_get_ldmap - get update logical drive map
+ *
+ * This routine will be called whenever user reads the logical drive
+ * attributes, go get the current logical drive mapping table from the
+ * firmware. We use the managment API's to issue commands to the controller.
+ *
+ * NOTE: The commands issuance functionality is not generalized and
+ * implemented in context of "get ld map" command only. If required, the
+ * command issuance logical can be trivially pulled out and implemented as a
+ * standalone libary. For now, this should suffice since there is no other
+ * user of this interface.
+ *
+ * @param adapter : controller's soft state
+ *
+ * @return 0 on success
+ * @return -1 on failure
+ */
+static int
+megaraid_sysfs_get_ldmap(adapter_t *adapter)
+{
+	mraid_device_t		*raid_dev = ADAP2RAIDDEV(adapter);
+	uioc_t			*uioc;
+	mbox64_t		*mbox64;
+	mbox_t			*mbox;
+	char			*raw_mbox;
+	struct timer_list	sysfs_timer;
+	struct timer_list	*timerp;
+	caddr_t			ldmap;
+	int			rval = 0;
+
+	/*
+	 * Allow only one read at a time to go through the sysfs attributes
+	 */
+	down(&raid_dev->sysfs_sem);
+
+	uioc	= raid_dev->sysfs_uioc;
+	mbox64	= raid_dev->sysfs_mbox64;
+	ldmap	= raid_dev->sysfs_buffer;
+
+	memset(uioc, 0, sizeof(uioc_t));
+	memset(mbox64, 0, sizeof(mbox64_t));
+	memset(ldmap, 0, sizeof(raid_dev->curr_ldmap));
+
+	mbox		= &mbox64->mbox32;
+	raw_mbox	= (char *)mbox;
+	uioc->cmdbuf    = (uint64_t)(unsigned long)mbox64;
+	uioc->buf_vaddr	= (caddr_t)adapter;
+	uioc->status	= -ENODATA;
+	uioc->done	= megaraid_sysfs_get_ldmap_done;
+
+	/*
+	 * Prepare the mailbox packet to get the current logical drive mapping
+	 * table
+	 */
+	mbox->xferaddr = (uint32_t)raid_dev->sysfs_buffer_dma;
+
+	raw_mbox[0] = FC_DEL_LOGDRV;
+	raw_mbox[2] = OP_GET_LDID_MAP;
+
+	/*
+	 * Setup a timer to recover from a non-responding controller
+	 */
+	timerp	= &sysfs_timer;
+	init_timer(timerp);
+
+	timerp->function	= megaraid_sysfs_get_ldmap_timeout;
+	timerp->data		= (unsigned long)uioc;
+	timerp->expires		= jiffies + 60 * HZ;
+
+	add_timer(timerp);
+
+	/*
+	 * Send the command to the firmware
+	 */
+	rval = megaraid_mbox_mm_command(adapter, uioc);
+
+	if (rval == 0) {	// command successfully issued
+		wait_event(raid_dev->sysfs_wait_q, (uioc->status != -ENODATA));
+
+		/*
+		 * Check if the command timed out
+		 */
+		if (uioc->status == -ETIME) {
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid: sysfs get ld map timed out\n"));
+
+			rval = -ETIME;
+		}
+		else {
+			rval = mbox->status;
+		}
+
+		if (rval == 0) {
+			memcpy(raid_dev->curr_ldmap, ldmap,
+				sizeof(raid_dev->curr_ldmap));
+		}
+		else {
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid: get ld map failed with %x\n", rval));
+		}
+	}
+	else {
+		con_log(CL_ANN, (KERN_NOTICE
+			"megaraid: could not issue ldmap command:%x\n", rval));
+	}
+
+
+	del_timer_sync(timerp);
+
+	up(&raid_dev->sysfs_sem);
+
+	return rval;
+}
+
+
+/**
+ * megaraid_sysfs_show_app_hndl - display application handle for this adapter
+ *
+ * Display the handle used by the applications while executing management
+ * tasks on the adapter. We invoke a management module API to get the adapter
+ * handle, since we do not interface with applications directly.
+ *
+ * @param cdev	: class device object representation for the host
+ * @param buf	: buffer to send data to
+ */
+static ssize_t
+megaraid_sysfs_show_app_hndl(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = class_to_shost(cdev);
+	adapter_t	*adapter = (adapter_t *)SCSIHOST2ADAP(shost);
+	uint32_t	app_hndl;
+
+	app_hndl = mraid_mm_adapter_app_handle(adapter->unique_id);
+
+	return snprintf(buf, 8, "%u\n", app_hndl);
+}
+
+
+/**
+ * megaraid_sysfs_show_ldnum - display the logical drive number for this device
+ *
+ * Display the logical drive number for the device in question, if it a valid
+ * logical drive. For physical devices, "-1" is returned
+ * The logical drive number is displayed in following format
+ *
+ * <SCSI ID> <LD NUM> <LD STICKY ID> <APP ADAPTER HANDLE>
+ *   <int>     <int>       <int>            <int>
+ *
+ * @param dev	: device object representation for the scsi device
+ * @param buf	: buffer to send data to
+ */
+static ssize_t
+megaraid_sysfs_show_ldnum(struct device *dev, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	adapter_t	*adapter = (adapter_t *)SCSIHOST2ADAP(sdev->host);
+	mraid_device_t	*raid_dev = ADAP2RAIDDEV(adapter);
+	int		scsi_id = -1;
+	int		logical_drv = -1;
+	int		ldid_map = -1;
+	uint32_t	app_hndl = 0;
+	int		mapped_sdev_id;
+	int		rval;
+	int		i;
+
+	if (raid_dev->random_del_supported &&
+			MRAID_IS_LOGICAL_SDEV(adapter, sdev)) {
+
+		rval = megaraid_sysfs_get_ldmap(adapter);
+		if (rval == 0) {
+
+			for (i = 0; i < MAX_LOGICAL_DRIVES_40LD; i++) {
+
+				mapped_sdev_id = sdev->id;
+
+				if (sdev->id > adapter->init_id) {
+					mapped_sdev_id -= 1;
+				}
+
+				if (raid_dev->curr_ldmap[i] == mapped_sdev_id) {
+
+					scsi_id = sdev->id;
+
+					logical_drv = i;
+
+					ldid_map = raid_dev->curr_ldmap[i];
+
+					app_hndl = mraid_mm_adapter_app_handle(
+							adapter->unique_id);
+
+					break;
+				}
+			}
+		}
+		else {
+			con_log(CL_ANN, (KERN_NOTICE
+				"megaraid: sysfs get ld map failed: %x\n",
+				rval));
+		}
+	}
+
+	return snprintf(buf, 36, "%d %d %d %d\n", scsi_id, logical_drv,
+			ldid_map, app_hndl);
+}
+
+
+/*
+ * END: Mailbox Low Level Driver
+ */
+module_init(megaraid_init);
+module_exit(megaraid_exit);
+
+/* vim: set ts=8 sw=8 tw=78 ai si: */
diff --git a/drivers/scsi/megaraid/megaraid_mbox.h b/drivers/scsi/megaraid/megaraid_mbox.h
new file mode 100644
index 0000000..0751000
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_mbox.h
@@ -0,0 +1,288 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_mbox.h
+ */
+
+#ifndef _MEGARAID_H_
+#define _MEGARAID_H_
+
+
+#include "mega_common.h"
+#include "mbox_defs.h"
+#include "megaraid_ioctl.h"
+
+
+#define MEGARAID_VERSION	"2.20.4.5"
+#define MEGARAID_EXT_VERSION	"(Release Date: Thu Feb 03 12:27:22 EST 2005)"
+
+
+/*
+ * Define some PCI values here until they are put in the kernel
+ */
+#define PCI_DEVICE_ID_PERC4_DI_DISCOVERY		0x000E
+#define PCI_SUBSYS_ID_PERC4_DI_DISCOVERY		0x0123
+
+#define PCI_DEVICE_ID_PERC4_SC				0x1960
+#define PCI_SUBSYS_ID_PERC4_SC				0x0520
+
+#define PCI_DEVICE_ID_PERC4_DC				0x1960
+#define PCI_SUBSYS_ID_PERC4_DC				0x0518
+
+#define PCI_DEVICE_ID_PERC4_QC				0x0407
+#define PCI_SUBSYS_ID_PERC4_QC				0x0531
+
+#define PCI_DEVICE_ID_PERC4_DI_EVERGLADES		0x000F
+#define PCI_SUBSYS_ID_PERC4_DI_EVERGLADES		0x014A
+
+#define PCI_DEVICE_ID_PERC4E_SI_BIGBEND			0x0013
+#define PCI_SUBSYS_ID_PERC4E_SI_BIGBEND			0x016c
+
+#define PCI_DEVICE_ID_PERC4E_DI_KOBUK			0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_KOBUK			0x016d
+
+#define PCI_DEVICE_ID_PERC4E_DI_CORVETTE		0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_CORVETTE		0x016e
+
+#define PCI_DEVICE_ID_PERC4E_DI_EXPEDITION		0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_EXPEDITION		0x016f
+
+#define PCI_DEVICE_ID_PERC4E_DI_GUADALUPE		0x0013
+#define PCI_SUBSYS_ID_PERC4E_DI_GUADALUPE		0x0170
+
+#define PCI_DEVICE_ID_PERC4E_DC_320_2E			0x0408
+#define PCI_SUBSYS_ID_PERC4E_DC_320_2E			0x0002
+
+#define PCI_DEVICE_ID_PERC4E_SC_320_1E			0x0408
+#define PCI_SUBSYS_ID_PERC4E_SC_320_1E			0x0001
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0		0xA520
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1		0x0520
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2		0x0518
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_0x		0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_0x		0x0530
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2x		0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2x		0x0532
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_4x		0x0407
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_4x		0x0531
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_1E		0x0408
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_1E		0x0001
+
+#define PCI_DEVICE_ID_MEGARAID_SCSI_320_2E		0x0408
+#define PCI_SUBSYS_ID_MEGARAID_SCSI_320_2E		0x0002
+
+#define PCI_DEVICE_ID_MEGARAID_I4_133_RAID		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_I4_133_RAID		0x0522
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_150_4		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SATA_150_4		0x4523
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_150_6		0x1960
+#define PCI_SUBSYS_ID_MEGARAID_SATA_150_6		0x0523
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_300_4x		0x0409
+#define PCI_SUBSYS_ID_MEGARAID_SATA_300_4x		0x3004
+
+#define PCI_DEVICE_ID_MEGARAID_SATA_300_8x		0x0409
+#define PCI_SUBSYS_ID_MEGARAID_SATA_300_8x		0x3008
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU42X		0x0407
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42X		0x0532
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCS16			0x1960
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCS16			0x0523
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU42E		0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU42E		0x0002
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCZCRX		0x0407
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCZCRX		0x0530
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCS28X		0x0409
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCS28X		0x3008
+
+#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_ALIEF	0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_ALIEF	0x3431
+
+#define PCI_DEVICE_ID_INTEL_RAID_SROMBU42E_HARWICH	0x0408
+#define PCI_SUBSYS_ID_INTEL_RAID_SROMBU42E_HARWICH	0x3499
+
+#define PCI_DEVICE_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK	0x1960
+#define PCI_SUBSYS_ID_INTEL_RAID_SRCU41L_LAKE_SHETEK	0x0520
+
+#define PCI_DEVICE_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB	0x0408
+#define PCI_SUBSYS_ID_FSC_MEGARAID_PCI_EXPRESS_ROMB	0x1065
+
+#define PCI_DEVICE_ID_MEGARAID_ACER_ROMB_2E		0x0408
+#define PCI_SUBSYS_ID_MEGARAID_ACER_ROMB_2E		0x004D
+
+#define PCI_SUBSYS_ID_PERC3_QC				0x0471
+#define PCI_SUBSYS_ID_PERC3_DC				0x0493
+#define PCI_SUBSYS_ID_PERC3_SC				0x0475
+
+#define PCI_DEVICE_ID_MEGARAID_NEC_ROMB_2E		0x0408
+#define PCI_SUBSYS_ID_MEGARAID_NEC_ROMB_2E		0x8287
+
+#ifndef PCI_SUBSYS_ID_FSC
+#define PCI_SUBSYS_ID_FSC				0x1734
+#endif
+
+#define MBOX_MAX_SCSI_CMDS	128	// number of cmds reserved for kernel
+#define MBOX_MAX_USER_CMDS	32	// number of cmds for applications
+#define MBOX_DEF_CMD_PER_LUN	64	// default commands per lun
+#define MBOX_DEFAULT_SG_SIZE	26	// default sg size supported by all fw
+#define MBOX_MAX_SG_SIZE	32	// maximum scatter-gather list size
+#define MBOX_MAX_SECTORS	128	// maximum sectors per IO
+#define MBOX_TIMEOUT		30	// timeout value for internal cmds
+#define MBOX_BUSY_WAIT		10	// max usec to wait for busy mailbox
+#define MBOX_RESET_WAIT		180	// wait these many seconds in reset
+#define MBOX_RESET_EXT_WAIT	120	// extended wait reset
+
+/*
+ * maximum transfer that can happen through the firmware commands issued
+ * internnaly from the driver.
+ */
+#define MBOX_IBUF_SIZE		4096
+
+
+/**
+ * mbox_ccb_t - command control block specific to mailbox based controllers
+ * @raw_mbox		: raw mailbox pointer
+ * @mbox		: mailbox
+ * @mbox64		: extended mailbox
+ * @mbox_dma_h		: maibox dma address
+ * @sgl64		: 64-bit scatter-gather list
+ * @sgl32		: 32-bit scatter-gather list
+ * @sgl_dma_h		: dma handle for the scatter-gather list
+ * @pthru		: passthru structure
+ * @pthru_dma_h		: dma handle for the passthru structure
+ * @epthru		: extended passthru structure
+ * @epthru_dma_h	: dma handle for extended passthru structure
+ * @buf_dma_h		: dma handle for buffers w/o sg list
+ *
+ * command control block specific to the mailbox based controllers
+ */
+typedef struct {
+	uint8_t			*raw_mbox;
+	mbox_t			*mbox;
+	mbox64_t		*mbox64;
+	dma_addr_t		mbox_dma_h;
+	mbox_sgl64		*sgl64;
+	mbox_sgl32		*sgl32;
+	dma_addr_t		sgl_dma_h;
+	mraid_passthru_t	*pthru;
+	dma_addr_t		pthru_dma_h;
+	mraid_epassthru_t	*epthru;
+	dma_addr_t		epthru_dma_h;
+	dma_addr_t		buf_dma_h;
+} mbox_ccb_t;
+
+
+/**
+ * mraid_device_t - adapter soft state structure for mailbox controllers
+ * @param una_mbox64		: 64-bit mbox - unaligned
+ * @param una_mbox64_dma	: mbox dma addr - unaligned
+ * @param mbox			: 32-bit mbox - aligned
+ * @param mbox64		: 64-bit mbox - aligned
+ * @param mbox_dma		: mbox dma addr - aligned
+ * @param mailbox_lock		: exclusion lock for the mailbox
+ * @param baseport		: base port of hba memory
+ * @param baseaddr		: mapped addr of hba memory
+ * @param mbox_pool		: pool of mailboxes
+ * @param mbox_pool_handle	: handle for the mailbox pool memory
+ * @param epthru_pool		: a pool for extended passthru commands
+ * @param epthru_pool_handle	: handle to the pool above
+ * @param sg_pool		: pool of scatter-gather lists for this driver
+ * @param sg_pool_handle	: handle to the pool above
+ * @param ccb_list		: list of our command control blocks
+ * @param uccb_list		: list of cmd control blocks for mgmt module
+ * @param umbox64		: array of mailbox for user commands (cmm)
+ * @param pdrv_state		: array for state of each physical drive.
+ * @param last_disp		: flag used to show device scanning
+ * @param hw_error		: set if FW not responding
+ * @param fast_load		: If set, skip physical device scanning
+ * @channel_class		: channel class, RAID or SCSI
+ * @sysfs_sem			: semaphore to serialize access to sysfs res.
+ * @sysfs_uioc			: management packet to issue FW calls from sysfs
+ * @sysfs_mbox64		: mailbox packet to issue FW calls from sysfs
+ * @sysfs_buffer		: data buffer for FW commands issued from sysfs
+ * @sysfs_buffer_dma		: DMA buffer for FW commands issued from sysfs
+ * @sysfs_wait_q		: wait queue for sysfs operations
+ * @random_del_supported	: set if the random deletion is supported
+ * @curr_ldmap			: current LDID map
+ *
+ * Initialization structure for mailbox controllers: memory based and IO based
+ * All the fields in this structure are LLD specific and may be discovered at
+ * init() or start() time.
+ *
+ * NOTE: The fields of this structures are placed to minimize cache misses
+ */
+#define MAX_LD_EXTENDED64	64
+typedef struct {
+	mbox64_t			*una_mbox64;
+	dma_addr_t			una_mbox64_dma;
+	mbox_t				*mbox;
+	mbox64_t			*mbox64;
+	dma_addr_t			mbox_dma;
+	spinlock_t			mailbox_lock;
+	unsigned long			baseport;
+	void __iomem *			baseaddr;
+	struct mraid_pci_blk		mbox_pool[MBOX_MAX_SCSI_CMDS];
+	struct dma_pool			*mbox_pool_handle;
+	struct mraid_pci_blk		epthru_pool[MBOX_MAX_SCSI_CMDS];
+	struct dma_pool			*epthru_pool_handle;
+	struct mraid_pci_blk		sg_pool[MBOX_MAX_SCSI_CMDS];
+	struct dma_pool			*sg_pool_handle;
+	mbox_ccb_t			ccb_list[MBOX_MAX_SCSI_CMDS];
+	mbox_ccb_t			uccb_list[MBOX_MAX_USER_CMDS];
+	mbox64_t			umbox64[MBOX_MAX_USER_CMDS];
+
+	uint8_t				pdrv_state[MBOX_MAX_PHYSICAL_DRIVES];
+	uint32_t			last_disp;
+	int				hw_error;
+	int				fast_load;
+	uint8_t				channel_class;
+	struct semaphore		sysfs_sem;
+	uioc_t				*sysfs_uioc;
+	mbox64_t			*sysfs_mbox64;
+	caddr_t				sysfs_buffer;
+	dma_addr_t			sysfs_buffer_dma;
+	wait_queue_head_t		sysfs_wait_q;
+	int				random_del_supported;
+	uint16_t			curr_ldmap[MAX_LD_EXTENDED64];
+} mraid_device_t;
+
+// route to raid device from adapter
+#define ADAP2RAIDDEV(adp)	((mraid_device_t *)((adp)->raid_device))
+
+#define MAILBOX_LOCK(rdev)	(&(rdev)->mailbox_lock)
+
+// Find out if this channel is a RAID or SCSI
+#define IS_RAID_CH(rdev, ch)	(((rdev)->channel_class >> (ch)) & 0x01)
+
+
+#define RDINDOOR(rdev)		readl((rdev)->baseaddr + 0x20)
+#define RDOUTDOOR(rdev)		readl((rdev)->baseaddr + 0x2C)
+#define WRINDOOR(rdev, value)	writel(value, (rdev)->baseaddr + 0x20)
+#define WROUTDOOR(rdev, value)	writel(value, (rdev)->baseaddr + 0x2C)
+
+#endif // _MEGARAID_H_
+
+// vim: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/megaraid/megaraid_mm.c b/drivers/scsi/megaraid/megaraid_mm.c
new file mode 100644
index 0000000..9f1b550
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_mm.c
@@ -0,0 +1,1255 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_mm.c
+ * Version	: v2.20.2.5 (Jan 21 2005)
+ *
+ * Common management module
+ */
+
+#include "megaraid_mm.h"
+#include <linux/smp_lock.h>
+
+
+// Entry points for char node driver
+static int mraid_mm_open(struct inode *, struct file *);
+static int mraid_mm_ioctl(struct inode *, struct file *, uint, unsigned long);
+
+
+// routines to convert to and from the old the format
+static int mimd_to_kioc(mimd_t __user *, mraid_mmadp_t *, uioc_t *);
+static int kioc_to_mimd(uioc_t *, mimd_t __user *);
+
+
+// Helper functions
+static int handle_drvrcmd(void __user *, uint8_t, int *);
+static int lld_ioctl(mraid_mmadp_t *, uioc_t *);
+static void ioctl_done(uioc_t *);
+static void lld_timedout(unsigned long);
+static void hinfo_to_cinfo(mraid_hba_info_t *, mcontroller_t *);
+static mraid_mmadp_t *mraid_mm_get_adapter(mimd_t __user *, int *);
+static uioc_t *mraid_mm_alloc_kioc(mraid_mmadp_t *);
+static void mraid_mm_dealloc_kioc(mraid_mmadp_t *, uioc_t *);
+static int mraid_mm_attach_buf(mraid_mmadp_t *, uioc_t *, int);
+static int mraid_mm_setup_dma_pools(mraid_mmadp_t *);
+static void mraid_mm_free_adp_resources(mraid_mmadp_t *);
+static void mraid_mm_teardown_dma_pools(mraid_mmadp_t *);
+
+#ifdef CONFIG_COMPAT
+static long mraid_mm_compat_ioctl(struct file *, unsigned int, unsigned long);
+#endif
+
+MODULE_AUTHOR("LSI Logic Corporation");
+MODULE_DESCRIPTION("LSI Logic Management Module");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(LSI_COMMON_MOD_VERSION);
+
+static int dbglevel = CL_ANN;
+module_param_named(dlevel, dbglevel, int, 0);
+MODULE_PARM_DESC(dlevel, "Debug level (default=0)");
+
+EXPORT_SYMBOL(mraid_mm_register_adp);
+EXPORT_SYMBOL(mraid_mm_unregister_adp);
+EXPORT_SYMBOL(mraid_mm_adapter_app_handle);
+
+static int majorno;
+static uint32_t drvr_ver	= 0x02200201;
+
+static int adapters_count_g;
+static struct list_head adapters_list_g;
+
+static wait_queue_head_t wait_q;
+
+static struct file_operations lsi_fops = {
+	.open	= mraid_mm_open,
+	.ioctl	= mraid_mm_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = mraid_mm_compat_ioctl,
+#endif
+	.owner	= THIS_MODULE,
+};
+
+/**
+ * mraid_mm_open - open routine for char node interface
+ * @inod	: unused
+ * @filep	: unused
+ *
+ * allow ioctl operations by apps only if they superuser privilege
+ */
+static int
+mraid_mm_open(struct inode *inode, struct file *filep)
+{
+	/*
+	 * Only allow superuser to access private ioctl interface
+	 */
+	if (!capable(CAP_SYS_ADMIN)) return (-EACCES);
+
+	return 0;
+}
+
+/**
+ * mraid_mm_ioctl - module entry-point for ioctls
+ * @inode	: inode (ignored)
+ * @filep	: file operations pointer (ignored)
+ * @cmd		: ioctl command
+ * @arg		: user ioctl packet
+ */
+static int
+mraid_mm_ioctl(struct inode *inode, struct file *filep, unsigned int cmd,
+							unsigned long arg)
+{
+	uioc_t		*kioc;
+	char		signature[EXT_IOCTL_SIGN_SZ]	= {0};
+	int		rval;
+	mraid_mmadp_t	*adp;
+	uint8_t		old_ioctl;
+	int		drvrcmd_rval;
+	void __user *argp = (void __user *)arg;
+
+	/*
+	 * Make sure only USCSICMD are issued through this interface.
+	 * MIMD application would still fire different command.
+	 */
+
+	if ((_IOC_TYPE(cmd) != MEGAIOC_MAGIC) && (cmd != USCSICMD)) {
+		return (-EINVAL);
+	}
+
+	/*
+	 * Look for signature to see if this is the new or old ioctl format.
+	 */
+	if (copy_from_user(signature, argp, EXT_IOCTL_SIGN_SZ)) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid cmm: copy from usr addr failed\n"));
+		return (-EFAULT);
+	}
+
+	if (memcmp(signature, EXT_IOCTL_SIGN, EXT_IOCTL_SIGN_SZ) == 0)
+		old_ioctl = 0;
+	else
+		old_ioctl = 1;
+
+	/*
+	 * At present, we don't support the new ioctl packet
+	 */
+	if (!old_ioctl )
+		return (-EINVAL);
+
+	/*
+	 * If it is a driver ioctl (as opposed to fw ioctls), then we can
+	 * handle the command locally. rval > 0 means it is not a drvr cmd
+	 */
+	rval = handle_drvrcmd(argp, old_ioctl, &drvrcmd_rval);
+
+	if (rval < 0)
+		return rval;
+	else if (rval == 0)
+		return drvrcmd_rval;
+
+	rval = 0;
+	if ((adp = mraid_mm_get_adapter(argp, &rval)) == NULL) {
+		return rval;
+	}
+
+	/*
+	 * Check if adapter can accept ioctl. We may have marked it offline
+	 * if any previous kioc had timedout on this controller.
+	 */
+	if (!adp->quiescent) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid cmm: controller cannot accept cmds due to "
+			"earlier errors\n" ));
+		return -EFAULT;
+	}
+
+	/*
+	 * The following call will block till a kioc is available
+	 */
+	kioc = mraid_mm_alloc_kioc(adp);
+
+	/*
+	 * User sent the old mimd_t ioctl packet. Convert it to uioc_t.
+	 */
+	if ((rval = mimd_to_kioc(argp, adp, kioc))) {
+		mraid_mm_dealloc_kioc(adp, kioc);
+		return rval;
+	}
+
+	kioc->done = ioctl_done;
+
+	/*
+	 * Issue the IOCTL to the low level driver. After the IOCTL completes
+	 * release the kioc if and only if it was _not_ timedout. If it was
+	 * timedout, that means that resources are still with low level driver.
+	 */
+	if ((rval = lld_ioctl(adp, kioc))) {
+
+		if (!kioc->timedout)
+			mraid_mm_dealloc_kioc(adp, kioc);
+
+		return rval;
+	}
+
+	/*
+	 * Convert the kioc back to user space
+	 */
+	rval = kioc_to_mimd(kioc, argp);
+
+	/*
+	 * Return the kioc to free pool
+	 */
+	mraid_mm_dealloc_kioc(adp, kioc);
+
+	return rval;
+}
+
+
+/**
+ * mraid_mm_get_adapter - Returns corresponding adapters for the mimd packet
+ * @umimd	: User space mimd_t ioctl packet
+ * @adapter	: pointer to the adapter (OUT)
+ */
+static mraid_mmadp_t *
+mraid_mm_get_adapter(mimd_t __user *umimd, int *rval)
+{
+	mraid_mmadp_t	*adapter;
+	mimd_t		mimd;
+	uint32_t	adapno;
+	int		iterator;
+
+
+	if (copy_from_user(&mimd, umimd, sizeof(mimd_t))) {
+		*rval = -EFAULT;
+		return NULL;
+	}
+
+	adapno = GETADAP(mimd.ui.fcs.adapno);
+
+	if (adapno >= adapters_count_g) {
+		*rval = -ENODEV;
+		return NULL;
+	}
+
+	adapter = NULL;
+	iterator = 0;
+
+	list_for_each_entry(adapter, &adapters_list_g, list) {
+		if (iterator++ == adapno) break;
+	}
+
+	if (!adapter) {
+		*rval = -ENODEV;
+		return NULL;
+	}
+
+	return adapter;
+}
+
+/*
+ * handle_drvrcmd - This routine checks if the opcode is a driver
+ * 			  cmd and if it is, handles it.
+ * @arg		: packet sent by the user app
+ * @old_ioctl	: mimd if 1; uioc otherwise
+ */
+static int
+handle_drvrcmd(void __user *arg, uint8_t old_ioctl, int *rval)
+{
+	mimd_t		__user *umimd;
+	mimd_t		kmimd;
+	uint8_t		opcode;
+	uint8_t		subopcode;
+
+	if (old_ioctl)
+		goto old_packet;
+	else
+		goto new_packet;
+
+new_packet:
+	return (-ENOTSUPP);
+
+old_packet:
+	*rval = 0;
+	umimd = arg;
+
+	if (copy_from_user(&kmimd, umimd, sizeof(mimd_t)))
+		return (-EFAULT);
+
+	opcode		= kmimd.ui.fcs.opcode;
+	subopcode	= kmimd.ui.fcs.subopcode;
+
+	/*
+	 * If the opcode is 0x82 and the subopcode is either GET_DRVRVER or
+	 * GET_NUMADP, then we can handle. Otherwise we should return 1 to
+	 * indicate that we cannot handle this.
+	 */
+	if (opcode != 0x82)
+		return 1;
+
+	switch (subopcode) {
+
+	case MEGAIOC_QDRVRVER:
+
+		if (copy_to_user(kmimd.data, &drvr_ver, sizeof(uint32_t)))
+			return (-EFAULT);
+
+		return 0;
+
+	case MEGAIOC_QNADAP:
+
+		*rval = adapters_count_g;
+
+		if (copy_to_user(kmimd.data, &adapters_count_g,
+				sizeof(uint32_t)))
+			return (-EFAULT);
+
+		return 0;
+
+	default:
+		/* cannot handle */
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * mimd_to_kioc	- Converter from old to new ioctl format
+ *
+ * @umimd	: user space old MIMD IOCTL
+ * @kioc	: kernel space new format IOCTL
+ *
+ * Routine to convert MIMD interface IOCTL to new interface IOCTL packet. The
+ * new packet is in kernel space so that driver can perform operations on it
+ * freely.
+ */
+
+static int
+mimd_to_kioc(mimd_t __user *umimd, mraid_mmadp_t *adp, uioc_t *kioc)
+{
+	mbox64_t		*mbox64;
+	mbox_t			*mbox;
+	mraid_passthru_t	*pthru32;
+	uint32_t		adapno;
+	uint8_t			opcode;
+	uint8_t			subopcode;
+	mimd_t			mimd;
+
+	if (copy_from_user(&mimd, umimd, sizeof(mimd_t)))
+		return (-EFAULT);
+
+	/*
+	 * Applications are not allowed to send extd pthru
+	 */
+	if ((mimd.mbox[0] == MBOXCMD_PASSTHRU64) ||
+			(mimd.mbox[0] == MBOXCMD_EXTPTHRU))
+		return (-EINVAL);
+
+	opcode		= mimd.ui.fcs.opcode;
+	subopcode	= mimd.ui.fcs.subopcode;
+	adapno		= GETADAP(mimd.ui.fcs.adapno);
+
+	if (adapno >= adapters_count_g)
+		return (-ENODEV);
+
+	kioc->adapno	= adapno;
+	kioc->mb_type	= MBOX_LEGACY;
+	kioc->app_type	= APPTYPE_MIMD;
+
+	switch (opcode) {
+
+	case 0x82:
+
+		if (subopcode == MEGAIOC_QADAPINFO) {
+
+			kioc->opcode	= GET_ADAP_INFO;
+			kioc->data_dir	= UIOC_RD;
+			kioc->xferlen	= sizeof(mraid_hba_info_t);
+
+			if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+				return (-ENOMEM);
+		}
+		else {
+			con_log(CL_ANN, (KERN_WARNING
+					"megaraid cmm: Invalid subop\n"));
+			return (-EINVAL);
+		}
+
+		break;
+
+	case 0x81:
+
+		kioc->opcode		= MBOX_CMD;
+		kioc->xferlen		= mimd.ui.fcs.length;
+		kioc->user_data_len	= kioc->xferlen;
+		kioc->user_data		= mimd.ui.fcs.buffer;
+
+		if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+			return (-ENOMEM);
+
+		if (mimd.outlen) kioc->data_dir  = UIOC_RD;
+		if (mimd.inlen) kioc->data_dir |= UIOC_WR;
+
+		break;
+
+	case 0x80:
+
+		kioc->opcode		= MBOX_CMD;
+		kioc->xferlen		= (mimd.outlen > mimd.inlen) ?
+						mimd.outlen : mimd.inlen;
+		kioc->user_data_len	= kioc->xferlen;
+		kioc->user_data		= mimd.data;
+
+		if (mraid_mm_attach_buf(adp, kioc, kioc->xferlen))
+			return (-ENOMEM);
+
+		if (mimd.outlen) kioc->data_dir  = UIOC_RD;
+		if (mimd.inlen) kioc->data_dir |= UIOC_WR;
+
+		break;
+
+	default:
+		return (-EINVAL);
+	}
+
+	/*
+	 * If driver command, nothing else to do
+	 */
+	if (opcode == 0x82)
+		return 0;
+
+	/*
+	 * This is a mailbox cmd; copy the mailbox from mimd
+	 */
+	mbox64	= (mbox64_t *)((unsigned long)kioc->cmdbuf);
+	mbox	= &mbox64->mbox32;
+	memcpy(mbox, mimd.mbox, 14);
+
+	if (mbox->cmd != MBOXCMD_PASSTHRU) {	// regular DCMD
+
+		mbox->xferaddr	= (uint32_t)kioc->buf_paddr;
+
+		if (kioc->data_dir & UIOC_WR) {
+			if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
+							kioc->xferlen)) {
+				return (-EFAULT);
+			}
+		}
+
+		return 0;
+	}
+
+	/*
+	 * This is a regular 32-bit pthru cmd; mbox points to pthru struct.
+	 * Just like in above case, the beginning for memblk is treated as
+	 * a mailbox. The passthru will begin at next 1K boundary. And the
+	 * data will start 1K after that.
+	 */
+	pthru32			= kioc->pthru32;
+	kioc->user_pthru	= &umimd->pthru;
+	mbox->xferaddr		= (uint32_t)kioc->pthru32_h;
+
+	if (copy_from_user(pthru32, kioc->user_pthru,
+			sizeof(mraid_passthru_t))) {
+		return (-EFAULT);
+	}
+
+	pthru32->dataxferaddr	= kioc->buf_paddr;
+	if (kioc->data_dir & UIOC_WR) {
+		if (copy_from_user(kioc->buf_vaddr, kioc->user_data,
+						pthru32->dataxferlen)) {
+			return (-EFAULT);
+		}
+	}
+
+	return 0;
+}
+
+/**
+ * mraid_mm_attch_buf - Attach a free dma buffer for required size
+ *
+ * @adp		: Adapter softstate
+ * @kioc	: kioc that the buffer needs to be attached to
+ * @xferlen	: required length for buffer
+ *
+ * First we search for a pool with smallest buffer that is >= @xferlen. If
+ * that pool has no free buffer, we will try for the next bigger size. If none
+ * is available, we will try to allocate the smallest buffer that is >=
+ * @xferlen and attach it the pool.
+ */
+static int
+mraid_mm_attach_buf(mraid_mmadp_t *adp, uioc_t *kioc, int xferlen)
+{
+	mm_dmapool_t	*pool;
+	int		right_pool = -1;
+	unsigned long	flags;
+	int		i;
+
+	kioc->pool_index	= -1;
+	kioc->buf_vaddr		= NULL;
+	kioc->buf_paddr		= 0;
+	kioc->free_buf		= 0;
+
+	/*
+	 * We need xferlen amount of memory. See if we can get it from our
+	 * dma pools. If we don't get exact size, we will try bigger buffer
+	 */
+
+	for (i = 0; i < MAX_DMA_POOLS; i++) {
+
+		pool = &adp->dma_pool_list[i];
+
+		if (xferlen > pool->buf_size)
+			continue;
+
+		if (right_pool == -1)
+			right_pool = i;
+
+		spin_lock_irqsave(&pool->lock, flags);
+
+		if (!pool->in_use) {
+
+			pool->in_use		= 1;
+			kioc->pool_index	= i;
+			kioc->buf_vaddr		= pool->vaddr;
+			kioc->buf_paddr		= pool->paddr;
+
+			spin_unlock_irqrestore(&pool->lock, flags);
+			return 0;
+		}
+		else {
+			spin_unlock_irqrestore(&pool->lock, flags);
+			continue;
+		}
+	}
+
+	/*
+	 * If xferlen doesn't match any of our pools, return error
+	 */
+	if (right_pool == -1)
+		return -EINVAL;
+
+	/*
+	 * We did not get any buffer from the preallocated pool. Let us try
+	 * to allocate one new buffer. NOTE: This is a blocking call.
+	 */
+	pool = &adp->dma_pool_list[right_pool];
+
+	spin_lock_irqsave(&pool->lock, flags);
+
+	kioc->pool_index	= right_pool;
+	kioc->free_buf		= 1;
+	kioc->buf_vaddr 	= pci_pool_alloc(pool->handle, GFP_KERNEL,
+							&kioc->buf_paddr);
+	spin_unlock_irqrestore(&pool->lock, flags);
+
+	if (!kioc->buf_vaddr)
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * mraid_mm_alloc_kioc - Returns a uioc_t from free list
+ * @adp	: Adapter softstate for this module
+ *
+ * The kioc_semaphore is initialized with number of kioc nodes in the
+ * free kioc pool. If the kioc pool is empty, this function blocks till
+ * a kioc becomes free.
+ */
+static uioc_t *
+mraid_mm_alloc_kioc(mraid_mmadp_t *adp)
+{
+	uioc_t			*kioc;
+	struct list_head*	head;
+	unsigned long		flags;
+
+	down(&adp->kioc_semaphore);
+
+	spin_lock_irqsave(&adp->kioc_pool_lock, flags);
+
+	head = &adp->kioc_pool;
+
+	if (list_empty(head)) {
+		up(&adp->kioc_semaphore);
+		spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+		con_log(CL_ANN, ("megaraid cmm: kioc list empty!\n"));
+		return NULL;
+	}
+
+	kioc = list_entry(head->next, uioc_t, list);
+	list_del_init(&kioc->list);
+
+	spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+	memset((caddr_t)(unsigned long)kioc->cmdbuf, 0, sizeof(mbox64_t));
+	memset((caddr_t) kioc->pthru32, 0, sizeof(mraid_passthru_t));
+
+	kioc->buf_vaddr		= NULL;
+	kioc->buf_paddr		= 0;
+	kioc->pool_index	=-1;
+	kioc->free_buf		= 0;
+	kioc->user_data		= NULL;
+	kioc->user_data_len	= 0;
+	kioc->user_pthru	= NULL;
+	kioc->timedout		= 0;
+
+	return kioc;
+}
+
+/**
+ * mraid_mm_dealloc_kioc - Return kioc to free pool
+ *
+ * @adp		: Adapter softstate
+ * @kioc	: uioc_t node to be returned to free pool
+ */
+static void
+mraid_mm_dealloc_kioc(mraid_mmadp_t *adp, uioc_t *kioc)
+{
+	mm_dmapool_t	*pool;
+	unsigned long	flags;
+
+	if (kioc->pool_index != -1) {
+		pool = &adp->dma_pool_list[kioc->pool_index];
+
+		/* This routine may be called in non-isr context also */
+		spin_lock_irqsave(&pool->lock, flags);
+
+		/*
+		 * While attaching the dma buffer, if we didn't get the 
+		 * required buffer from the pool, we would have allocated 
+		 * it at the run time and set the free_buf flag. We must 
+		 * free that buffer. Otherwise, just mark that the buffer is 
+		 * not in use
+		 */
+		if (kioc->free_buf == 1)
+			pci_pool_free(pool->handle, kioc->buf_vaddr, 
+							kioc->buf_paddr);
+		else
+			pool->in_use = 0;
+
+		spin_unlock_irqrestore(&pool->lock, flags);
+	}
+
+	/* Return the kioc to the free pool */
+	spin_lock_irqsave(&adp->kioc_pool_lock, flags);
+	list_add(&kioc->list, &adp->kioc_pool);
+	spin_unlock_irqrestore(&adp->kioc_pool_lock, flags);
+
+	/* increment the free kioc count */
+	up(&adp->kioc_semaphore);
+
+	return;
+}
+
+/**
+ * lld_ioctl - Routine to issue ioctl to low level drvr
+ *
+ * @adp		: The adapter handle
+ * @kioc	: The ioctl packet with kernel addresses
+ */
+static int
+lld_ioctl(mraid_mmadp_t *adp, uioc_t *kioc)
+{
+	int			rval;
+	struct timer_list	timer;
+	struct timer_list	*tp = NULL;
+
+	kioc->status	= -ENODATA;
+	rval		= adp->issue_uioc(adp->drvr_data, kioc, IOCTL_ISSUE);
+
+	if (rval) return rval;
+
+	/*
+	 * Start the timer
+	 */
+	if (adp->timeout > 0) {
+		tp		= &timer;
+		init_timer(tp);
+
+		tp->function	= lld_timedout;
+		tp->data	= (unsigned long)kioc;
+		tp->expires	= jiffies + adp->timeout * HZ;
+
+		add_timer(tp);
+	}
+
+	/*
+	 * Wait till the low level driver completes the ioctl. After this
+	 * call, the ioctl either completed successfully or timedout.
+	 */
+	wait_event(wait_q, (kioc->status != -ENODATA));
+	if (tp) {
+		del_timer_sync(tp);
+	}
+
+	/*
+	 * If the command had timedout, we mark the controller offline
+	 * before returning
+	 */
+	if (kioc->timedout) {
+		adp->quiescent = 0;
+	}
+
+	return kioc->status;
+}
+
+
+/**
+ * ioctl_done - callback from the low level driver
+ *
+ * @kioc	: completed ioctl packet
+ */
+static void
+ioctl_done(uioc_t *kioc)
+{
+	uint32_t	adapno;
+	int		iterator;
+	mraid_mmadp_t*	adapter;
+
+	/*
+	 * When the kioc returns from driver, make sure it still doesn't
+	 * have ENODATA in status. Otherwise, driver will hang on wait_event
+	 * forever
+	 */
+	if (kioc->status == -ENODATA) {
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid cmm: lld didn't change status!\n"));
+
+		kioc->status = -EINVAL;
+	}
+
+	/*
+	 * Check if this kioc was timedout before. If so, nobody is waiting
+	 * on this kioc. We don't have to wake up anybody. Instead, we just
+	 * have to free the kioc
+	 */
+	if (kioc->timedout) {
+		iterator	= 0;
+		adapter		= NULL;
+		adapno		= kioc->adapno;
+
+		con_log(CL_ANN, ( KERN_WARNING "megaraid cmm: completed "
+					"ioctl that was timedout before\n"));
+
+		list_for_each_entry(adapter, &adapters_list_g, list) {
+			if (iterator++ == adapno) break;
+		}
+
+		kioc->timedout = 0;
+
+		if (adapter) {
+			mraid_mm_dealloc_kioc( adapter, kioc );
+		}
+	}
+	else {
+		wake_up(&wait_q);
+	}
+}
+
+
+/*
+ * lld_timedout	: callback from the expired timer
+ *
+ * @ptr		: ioctl packet that timed out
+ */
+static void
+lld_timedout(unsigned long ptr)
+{
+	uioc_t *kioc	= (uioc_t *)ptr;
+
+	kioc->status 	= -ETIME;
+	kioc->timedout	= 1;
+
+	con_log(CL_ANN, (KERN_WARNING "megaraid cmm: ioctl timed out\n"));
+
+	wake_up(&wait_q);
+}
+
+
+/**
+ * kioc_to_mimd	: Converter from new back to old format
+ *
+ * @kioc	: Kernel space IOCTL packet (successfully issued)
+ * @mimd	: User space MIMD packet
+ */
+static int
+kioc_to_mimd(uioc_t *kioc, mimd_t __user *mimd)
+{
+	mimd_t			kmimd;
+	uint8_t			opcode;
+	uint8_t			subopcode;
+
+	mbox64_t		*mbox64;
+	mraid_passthru_t	__user *upthru32;
+	mraid_passthru_t	*kpthru32;
+	mcontroller_t		cinfo;
+	mraid_hba_info_t	*hinfo;
+
+
+	if (copy_from_user(&kmimd, mimd, sizeof(mimd_t)))
+		return (-EFAULT);
+
+	opcode		= kmimd.ui.fcs.opcode;
+	subopcode	= kmimd.ui.fcs.subopcode;
+
+	if (opcode == 0x82) {
+		switch (subopcode) {
+
+		case MEGAIOC_QADAPINFO:
+
+			hinfo = (mraid_hba_info_t *)(unsigned long)
+					kioc->buf_vaddr;
+
+			hinfo_to_cinfo(hinfo, &cinfo);
+
+			if (copy_to_user(kmimd.data, &cinfo, sizeof(cinfo)))
+				return (-EFAULT);
+
+			return 0;
+
+		default:
+			return (-EINVAL);
+		}
+
+		return 0;
+	}
+
+	mbox64 = (mbox64_t *)(unsigned long)kioc->cmdbuf;
+
+	if (kioc->user_pthru) {
+
+		upthru32 = kioc->user_pthru;
+		kpthru32 = kioc->pthru32;
+
+		if (copy_to_user(&upthru32->scsistatus,
+					&kpthru32->scsistatus,
+					sizeof(uint8_t))) {
+			return (-EFAULT);
+		}
+	}
+
+	if (kioc->user_data) {
+		if (copy_to_user(kioc->user_data, kioc->buf_vaddr,
+					kioc->user_data_len)) {
+			return (-EFAULT);
+		}
+	}
+
+	if (copy_to_user(&mimd->mbox[17],
+			&mbox64->mbox32.status, sizeof(uint8_t))) {
+		return (-EFAULT);
+	}
+
+	return 0;
+}
+
+
+/**
+ * hinfo_to_cinfo - Convert new format hba info into old format
+ *
+ * @hinfo	: New format, more comprehensive adapter info
+ * @cinfo	: Old format adapter info to support mimd_t apps
+ */
+static void
+hinfo_to_cinfo(mraid_hba_info_t *hinfo, mcontroller_t *cinfo)
+{
+	if (!hinfo || !cinfo)
+		return;
+
+	cinfo->base		= hinfo->baseport;
+	cinfo->irq		= hinfo->irq;
+	cinfo->numldrv		= hinfo->num_ldrv;
+	cinfo->pcibus		= hinfo->pci_bus;
+	cinfo->pcidev		= hinfo->pci_slot;
+	cinfo->pcifun		= PCI_FUNC(hinfo->pci_dev_fn);
+	cinfo->pciid		= hinfo->pci_device_id;
+	cinfo->pcivendor	= hinfo->pci_vendor_id;
+	cinfo->pcislot		= hinfo->pci_slot;
+	cinfo->uid		= hinfo->unique_id;
+}
+
+
+/*
+ * mraid_mm_register_adp - Registration routine for low level drvrs
+ *
+ * @adp	: Adapter objejct
+ */
+int
+mraid_mm_register_adp(mraid_mmadp_t *lld_adp)
+{
+	mraid_mmadp_t	*adapter;
+	mbox64_t	*mbox_list;
+	uioc_t		*kioc;
+	uint32_t	rval;
+	int		i;
+
+
+	if (lld_adp->drvr_type != DRVRTYPE_MBOX)
+		return (-EINVAL);
+
+	adapter = kmalloc(sizeof(mraid_mmadp_t), GFP_KERNEL);
+
+	if (!adapter) {
+		rval = -ENOMEM;
+		goto memalloc_error;
+	}
+
+	memset(adapter, 0, sizeof(mraid_mmadp_t));
+
+	adapter->unique_id	= lld_adp->unique_id;
+	adapter->drvr_type	= lld_adp->drvr_type;
+	adapter->drvr_data	= lld_adp->drvr_data;
+	adapter->pdev		= lld_adp->pdev;
+	adapter->issue_uioc	= lld_adp->issue_uioc;
+	adapter->timeout	= lld_adp->timeout;
+	adapter->max_kioc	= lld_adp->max_kioc;
+	adapter->quiescent	= 1;
+
+	/*
+	 * Allocate single blocks of memory for all required kiocs,
+	 * mailboxes and passthru structures.
+	 */
+	adapter->kioc_list	= kmalloc(sizeof(uioc_t) * lld_adp->max_kioc,
+						GFP_KERNEL);
+	adapter->mbox_list	= kmalloc(sizeof(mbox64_t) * lld_adp->max_kioc,
+						GFP_KERNEL);
+	adapter->pthru_dma_pool = pci_pool_create("megaraid mm pthru pool",
+						adapter->pdev,
+						sizeof(mraid_passthru_t),
+						16, 0);
+
+	if (!adapter->kioc_list || !adapter->mbox_list ||
+			!adapter->pthru_dma_pool) {
+
+		con_log(CL_ANN, (KERN_WARNING
+			"megaraid cmm: out of memory, %s %d\n", __FUNCTION__,
+			__LINE__));
+
+		rval = (-ENOMEM);
+
+		goto memalloc_error;
+	}
+
+	/*
+	 * Slice kioc_list and make a kioc_pool with the individiual kiocs
+	 */
+	INIT_LIST_HEAD(&adapter->kioc_pool);
+	spin_lock_init(&adapter->kioc_pool_lock);
+	sema_init(&adapter->kioc_semaphore, lld_adp->max_kioc);
+
+	mbox_list	= (mbox64_t *)adapter->mbox_list;
+
+	for (i = 0; i < lld_adp->max_kioc; i++) {
+
+		kioc		= adapter->kioc_list + i;
+		kioc->cmdbuf	= (uint64_t)(unsigned long)(mbox_list + i);
+		kioc->pthru32	= pci_pool_alloc(adapter->pthru_dma_pool,
+						GFP_KERNEL, &kioc->pthru32_h);
+
+		if (!kioc->pthru32) {
+
+			con_log(CL_ANN, (KERN_WARNING
+				"megaraid cmm: out of memory, %s %d\n",
+					__FUNCTION__, __LINE__));
+
+			rval = (-ENOMEM);
+
+			goto pthru_dma_pool_error;
+		}
+
+		list_add_tail(&kioc->list, &adapter->kioc_pool);
+	}
+
+	// Setup the dma pools for data buffers
+	if ((rval = mraid_mm_setup_dma_pools(adapter)) != 0) {
+		goto dma_pool_error;
+	}
+
+	list_add_tail(&adapter->list, &adapters_list_g);
+
+	adapters_count_g++;
+
+	return 0;
+
+dma_pool_error:
+	/* Do nothing */
+
+pthru_dma_pool_error:
+
+	for (i = 0; i < lld_adp->max_kioc; i++) {
+		kioc = adapter->kioc_list + i;
+		if (kioc->pthru32) {
+			pci_pool_free(adapter->pthru_dma_pool, kioc->pthru32,
+				kioc->pthru32_h);
+		}
+	}
+
+memalloc_error:
+
+	if (adapter->kioc_list)
+		kfree(adapter->kioc_list);
+
+	if (adapter->mbox_list)
+		kfree(adapter->mbox_list);
+
+	if (adapter->pthru_dma_pool)
+		pci_pool_destroy(adapter->pthru_dma_pool);
+
+	if (adapter)
+		kfree(adapter);
+
+	return rval;
+}
+
+
+/**
+ * mraid_mm_adapter_app_handle - return the application handle for this adapter
+ *
+ * For the given driver data, locate the adadpter in our global list and
+ * return the corresponding handle, which is also used by applications to
+ * uniquely identify an adapter.
+ *
+ * @param unique_id : adapter unique identifier
+ *
+ * @return adapter handle if found in the list
+ * @return 0 if adapter could not be located, should never happen though
+ */
+uint32_t
+mraid_mm_adapter_app_handle(uint32_t unique_id)
+{
+	mraid_mmadp_t	*adapter;
+	mraid_mmadp_t	*tmp;
+	int		index = 0;
+
+	list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {
+
+		if (adapter->unique_id == unique_id) {
+
+			return MKADAP(index);
+		}
+
+		index++;
+	}
+
+	return 0;
+}
+
+
+/**
+ * mraid_mm_setup_dma_pools - Set up dma buffer pools per adapter
+ *
+ * @adp	: Adapter softstate
+ *
+ * We maintain a pool of dma buffers per each adapter. Each pool has one
+ * buffer. E.g, we may have 5 dma pools - one each for 4k, 8k ... 64k buffers.
+ * We have just one 4k buffer in 4k pool, one 8k buffer in 8k pool etc. We
+ * dont' want to waste too much memory by allocating more buffers per each
+ * pool.
+ */
+static int
+mraid_mm_setup_dma_pools(mraid_mmadp_t *adp)
+{
+	mm_dmapool_t	*pool;
+	int		bufsize;
+	int		i;
+
+	/*
+	 * Create MAX_DMA_POOLS number of pools
+	 */
+	bufsize = MRAID_MM_INIT_BUFF_SIZE;
+
+	for (i = 0; i < MAX_DMA_POOLS; i++){
+
+		pool = &adp->dma_pool_list[i];
+
+		pool->buf_size = bufsize;
+		spin_lock_init(&pool->lock);
+
+		pool->handle = pci_pool_create("megaraid mm data buffer",
+						adp->pdev, bufsize, 16, 0);
+
+		if (!pool->handle) {
+			goto dma_pool_setup_error;
+		}
+
+		pool->vaddr = pci_pool_alloc(pool->handle, GFP_KERNEL,
+							&pool->paddr);
+
+		if (!pool->vaddr)
+			goto dma_pool_setup_error;
+
+		bufsize = bufsize * 2;
+	}
+
+	return 0;
+
+dma_pool_setup_error:
+
+	mraid_mm_teardown_dma_pools(adp);
+	return (-ENOMEM);
+}
+
+
+/*
+ * mraid_mm_unregister_adp - Unregister routine for low level drivers
+ *				  Assume no outstanding ioctls to llds.
+ *
+ * @unique_id	: UID of the adpater
+ */
+int
+mraid_mm_unregister_adp(uint32_t unique_id)
+{
+	mraid_mmadp_t	*adapter;
+	mraid_mmadp_t	*tmp;
+
+	list_for_each_entry_safe(adapter, tmp, &adapters_list_g, list) {
+
+
+		if (adapter->unique_id == unique_id) {
+
+			adapters_count_g--;
+
+			list_del_init(&adapter->list);
+
+			mraid_mm_free_adp_resources(adapter);
+
+			kfree(adapter);
+
+			con_log(CL_ANN, (
+				"megaraid cmm: Unregistered one adapter:%#x\n",
+				unique_id));
+
+			return 0;
+		}
+	}
+
+	return (-ENODEV);
+}
+
+/**
+ * mraid_mm_free_adp_resources - Free adapter softstate
+ *
+ * @adp	: Adapter softstate
+ */
+static void
+mraid_mm_free_adp_resources(mraid_mmadp_t *adp)
+{
+	uioc_t	*kioc;
+	int	i;
+
+	mraid_mm_teardown_dma_pools(adp);
+
+	for (i = 0; i < adp->max_kioc; i++) {
+
+		kioc = adp->kioc_list + i;
+
+		pci_pool_free(adp->pthru_dma_pool, kioc->pthru32,
+				kioc->pthru32_h);
+	}
+
+	kfree(adp->kioc_list);
+
+	kfree(adp->mbox_list);
+
+	pci_pool_destroy(adp->pthru_dma_pool);
+
+
+	return;
+}
+
+
+/**
+ * mraid_mm_teardown_dma_pools - Free all per adapter dma buffers
+ *
+ * @adp	: Adapter softstate
+ */
+static void
+mraid_mm_teardown_dma_pools(mraid_mmadp_t *adp)
+{
+	int		i;
+	mm_dmapool_t	*pool;
+
+	for (i = 0; i < MAX_DMA_POOLS; i++) {
+
+		pool = &adp->dma_pool_list[i];
+
+		if (pool->handle) {
+
+			if (pool->vaddr)
+				pci_pool_free(pool->handle, pool->vaddr,
+							pool->paddr);
+
+			pci_pool_destroy(pool->handle);
+			pool->handle = NULL;
+		}
+	}
+
+	return;
+}
+
+/**
+ * mraid_mm_init	: Module entry point
+ */
+static int __init
+mraid_mm_init(void)
+{
+	// Announce the driver version
+	con_log(CL_ANN, (KERN_INFO "megaraid cmm: %s %s\n",
+		LSI_COMMON_MOD_VERSION, LSI_COMMON_MOD_EXT_VERSION));
+
+	majorno = register_chrdev(0, "megadev", &lsi_fops);
+
+	if (majorno < 0) {
+		con_log(CL_ANN, ("megaraid cmm: cannot get major\n"));
+		return majorno;
+	}
+
+	init_waitqueue_head(&wait_q);
+
+	INIT_LIST_HEAD(&adapters_list_g);
+
+	return 0;
+}
+
+
+/**
+ * mraid_mm_compat_ioctl	: 32bit to 64bit ioctl conversion routine
+ */
+#ifdef CONFIG_COMPAT
+static long
+mraid_mm_compat_ioctl(struct file *filep, unsigned int cmd,
+		      unsigned long arg)
+{
+	int err;
+	lock_kernel();
+	err = mraid_mm_ioctl(NULL, filep, cmd, arg);
+	unlock_kernel();
+	return err;
+}
+#endif
+
+/**
+ * mraid_mm_exit	: Module exit point
+ */
+static void __exit
+mraid_mm_exit(void)
+{
+	con_log(CL_DLEVEL1 , ("exiting common mod\n"));
+
+	unregister_chrdev(majorno, "megadev");
+}
+
+module_init(mraid_mm_init);
+module_exit(mraid_mm_exit);
+
+/* vi: set ts=8 sw=8 tw=78: */
diff --git a/drivers/scsi/megaraid/megaraid_mm.h b/drivers/scsi/megaraid/megaraid_mm.h
new file mode 100644
index 0000000..948a001
--- /dev/null
+++ b/drivers/scsi/megaraid/megaraid_mm.h
@@ -0,0 +1,102 @@
+/*
+ *
+ *			Linux MegaRAID device driver
+ *
+ * Copyright (c) 2003-2004  LSI Logic Corporation.
+ *
+ *	   This program is free software; you can redistribute it and/or
+ *	   modify it under the terms of the GNU General Public License
+ *	   as published by the Free Software Foundation; either version
+ *	   2 of the License, or (at your option) any later version.
+ *
+ * FILE		: megaraid_mm.h
+ */
+
+#ifndef MEGARAID_MM_H
+#define MEGARAID_MM_H
+
+#include <linux/spinlock.h>
+#include <linux/fs.h>
+#include <asm/uaccess.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/list.h>
+#include <linux/ioctl32.h>
+
+#include "mbox_defs.h"
+#include "megaraid_ioctl.h"
+
+
+#define LSI_COMMON_MOD_VERSION	"2.20.2.5"
+#define LSI_COMMON_MOD_EXT_VERSION	\
+		"(Release Date: Fri Jan 21 00:01:03 EST 2005)"
+
+
+#define LSI_DBGLVL			dbglevel
+
+// The smallest dma pool
+#define MRAID_MM_INIT_BUFF_SIZE		4096
+
+/**
+ * mimd_t	: Old style ioctl packet structure (deprecated)
+ *
+ * @inlen	:
+ * @outlen	:
+ * @fca		:
+ * @opcode	:
+ * @subopcode	:
+ * @adapno	:
+ * @buffer	:
+ * @pad		:
+ * @length	:
+ * @mbox	:
+ * @pthru	:
+ * @data	:
+ * @pad		:
+ *
+ * Note		: This structure is DEPRECATED. New applications must use
+ *		: uioc_t structure instead. All new hba drivers use the new
+ *		: format. If we get this mimd packet, we will convert it into
+ *		: new uioc_t format and send it to the hba drivers.
+ */
+
+typedef struct mimd {
+
+	uint32_t inlen;
+	uint32_t outlen;
+
+	union {
+		uint8_t fca[16];
+		struct {
+			uint8_t opcode;
+			uint8_t subopcode;
+			uint16_t adapno;
+#if BITS_PER_LONG == 32
+			uint8_t __user *buffer;
+			uint8_t pad[4];
+#endif
+#if BITS_PER_LONG == 64
+			uint8_t __user *buffer;
+#endif
+			uint32_t length;
+		} __attribute__ ((packed)) fcs;
+	} __attribute__ ((packed)) ui;
+
+	uint8_t mbox[18];		/* 16 bytes + 2 status bytes */
+	mraid_passthru_t pthru;
+
+#if BITS_PER_LONG == 32
+	char __user *data;		/* buffer <= 4096 for 0x80 commands */
+	char pad[4];
+#endif
+#if BITS_PER_LONG == 64
+	char __user *data;
+#endif
+
+} __attribute__ ((packed))mimd_t;
+
+#endif // MEGARAID_MM_H
+
+// vi: set ts=8 sw=8 tw=78:
diff --git a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
new file mode 100644
index 0000000..85f3a74
--- /dev/null
+++ b/drivers/scsi/mesh.c
@@ -0,0 +1,2062 @@
+/*
+ * SCSI low-level driver for the MESH (Macintosh Enhanced SCSI Hardware)
+ * bus adaptor found on Power Macintosh computers.
+ * We assume the MESH is connected to a DBDMA (descriptor-based DMA)
+ * controller.
+ *
+ * Paul Mackerras, August 1996.
+ * Copyright (C) 1996 Paul Mackerras.
+ *
+ * Apr. 21 2002  - BenH		Rework bus reset code for new error handler
+ *                              Add delay after initial bus reset
+ *                              Add module parameters
+ *
+ * Sep. 27 2003  - BenH		Move to new driver model, fix some write posting
+ *				issues
+ * To do:
+ * - handle aborts correctly
+ * - retry arbitration if lost (unless higher levels do this for us)
+ * - power down the chip when no device is detected
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/interrupt.h>
+#include <linux/reboot.h>
+#include <linux/spinlock.h>
+#include <asm/dbdma.h>
+#include <asm/io.h>
+#include <asm/pgtable.h>
+#include <asm/prom.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/hydra.h>
+#include <asm/processor.h>
+#include <asm/machdep.h>
+#include <asm/pmac_feature.h>
+#include <asm/pci-bridge.h>
+#include <asm/macio.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "mesh.h"
+
+#if 1
+#undef KERN_DEBUG
+#define KERN_DEBUG KERN_WARNING
+#endif
+
+MODULE_AUTHOR("Paul Mackerras (paulus@samba.org)");
+MODULE_DESCRIPTION("PowerMac MESH SCSI driver");
+MODULE_LICENSE("GPL");
+
+static int sync_rate = CONFIG_SCSI_MESH_SYNC_RATE;
+static int sync_targets = 0xff;
+static int resel_targets = 0xff;
+static int debug_targets = 0;	/* print debug for these targets */
+static int init_reset_delay = CONFIG_SCSI_MESH_RESET_DELAY_MS;
+
+module_param(sync_rate, int, 0);
+MODULE_PARM_DESC(sync_rate, "Synchronous rate (0..10, 0=async)");
+module_param(sync_targets, int, 0);
+MODULE_PARM_DESC(sync_targets, "Bitmask of targets allowed to set synchronous");
+module_param(resel_targets, int, 0);
+MODULE_PARM_DESC(resel_targets, "Bitmask of targets allowed to set disconnect");
+module_param(debug_targets, int, 0644);
+MODULE_PARM_DESC(debug_targets, "Bitmask of debugged targets");
+module_param(init_reset_delay, int, 0);
+MODULE_PARM_DESC(init_reset_delay, "Initial bus reset delay (0=no reset)");
+
+static int mesh_sync_period = 100;
+static int mesh_sync_offset = 0;
+static unsigned char use_active_neg = 0;  /* bit mask for SEQ_ACTIVE_NEG if used */
+
+#define ALLOW_SYNC(tgt)		((sync_targets >> (tgt)) & 1)
+#define ALLOW_RESEL(tgt)	((resel_targets >> (tgt)) & 1)
+#define ALLOW_DEBUG(tgt)	((debug_targets >> (tgt)) & 1)
+#define DEBUG_TARGET(cmd)	((cmd) && ALLOW_DEBUG((cmd)->device->id))
+
+#undef MESH_DBG
+#define N_DBG_LOG	50
+#define N_DBG_SLOG	20
+#define NUM_DBG_EVENTS	13
+#undef	DBG_USE_TB		/* bombs on 601 */
+
+struct dbglog {
+	char	*fmt;
+	u32	tb;
+	u8	phase;
+	u8	bs0;
+	u8	bs1;
+	u8	tgt;
+	int	d;
+};
+
+enum mesh_phase {
+	idle,
+	arbitrating,
+	selecting,
+	commanding,
+	dataing,
+	statusing,
+	busfreeing,
+	disconnecting,
+	reselecting,
+	sleeping
+};
+
+enum msg_phase {
+	msg_none,
+	msg_out,
+	msg_out_xxx,
+	msg_out_last,
+	msg_in,
+	msg_in_bad,
+};
+
+enum sdtr_phase {
+	do_sdtr,
+	sdtr_sent,
+	sdtr_done
+};
+
+struct mesh_target {
+	enum sdtr_phase sdtr_state;
+	int	sync_params;
+	int	data_goes_out;		/* guess as to data direction */
+	struct scsi_cmnd *current_req;
+	u32	saved_ptr;
+#ifdef MESH_DBG
+	int	log_ix;
+	int	n_log;
+	struct dbglog log[N_DBG_LOG];
+#endif
+};
+
+struct mesh_state {
+	volatile struct	mesh_regs __iomem *mesh;
+	int	meshintr;
+	volatile struct	dbdma_regs __iomem *dma;
+	int	dmaintr;
+	struct	Scsi_Host *host;
+	struct	mesh_state *next;
+	struct scsi_cmnd *request_q;
+	struct scsi_cmnd *request_qtail;
+	enum mesh_phase phase;		/* what we're currently trying to do */
+	enum msg_phase msgphase;
+	int	conn_tgt;		/* target we're connected to */
+	struct scsi_cmnd *current_req;		/* req we're currently working on */
+	int	data_ptr;
+	int	dma_started;
+	int	dma_count;
+	int	stat;
+	int	aborting;
+	int	expect_reply;
+	int	n_msgin;
+	u8	msgin[16];
+	int	n_msgout;
+	int	last_n_msgout;
+	u8	msgout[16];
+	struct dbdma_cmd *dma_cmds;	/* space for dbdma commands, aligned */
+	dma_addr_t dma_cmd_bus;
+	void	*dma_cmd_space;
+	int	dma_cmd_size;
+	int	clk_freq;
+	struct mesh_target tgts[8];
+	struct macio_dev *mdev;
+	struct pci_dev* pdev;
+#ifdef MESH_DBG
+	int	log_ix;
+	int	n_log;
+	struct dbglog log[N_DBG_SLOG];
+#endif
+};
+
+/*
+ * Driver is too messy, we need a few prototypes...
+ */
+static void mesh_done(struct mesh_state *ms, int start_next);
+static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs);
+static void cmd_complete(struct mesh_state *ms);
+static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd);
+static void halt_dma(struct mesh_state *ms);
+static void phase_mismatch(struct mesh_state *ms);
+
+
+/*
+ * Some debugging & logging routines
+ */
+
+#ifdef MESH_DBG
+
+static inline u32 readtb(void)
+{
+	u32 tb;
+
+#ifdef DBG_USE_TB
+	/* Beware: if you enable this, it will crash on 601s. */
+	asm ("mftb %0" : "=r" (tb) : );
+#else
+	tb = 0;
+#endif
+	return tb;
+}
+
+static void dlog(struct mesh_state *ms, char *fmt, int a)
+{
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	struct dbglog *tlp, *slp;
+
+	tlp = &tp->log[tp->log_ix];
+	slp = &ms->log[ms->log_ix];
+	tlp->fmt = fmt;
+	tlp->tb = readtb();
+	tlp->phase = (ms->msgphase << 4) + ms->phase;
+	tlp->bs0 = ms->mesh->bus_status0;
+	tlp->bs1 = ms->mesh->bus_status1;
+	tlp->tgt = ms->conn_tgt;
+	tlp->d = a;
+	*slp = *tlp;
+	if (++tp->log_ix >= N_DBG_LOG)
+		tp->log_ix = 0;
+	if (tp->n_log < N_DBG_LOG)
+		++tp->n_log;
+	if (++ms->log_ix >= N_DBG_SLOG)
+		ms->log_ix = 0;
+	if (ms->n_log < N_DBG_SLOG)
+		++ms->n_log;
+}
+
+static void dumplog(struct mesh_state *ms, int t)
+{
+	struct mesh_target *tp = &ms->tgts[t];
+	struct dbglog *lp;
+	int i;
+
+	if (tp->n_log == 0)
+		return;
+	i = tp->log_ix - tp->n_log;
+	if (i < 0)
+		i += N_DBG_LOG;
+	tp->n_log = 0;
+	do {
+		lp = &tp->log[i];
+		printk(KERN_DEBUG "mesh log %d: bs=%.2x%.2x ph=%.2x ",
+		       t, lp->bs1, lp->bs0, lp->phase);
+#ifdef DBG_USE_TB
+		printk("tb=%10u ", lp->tb);
+#endif
+		printk(lp->fmt, lp->d);
+		printk("\n");
+		if (++i >= N_DBG_LOG)
+			i = 0;
+	} while (i != tp->log_ix);
+}
+
+static void dumpslog(struct mesh_state *ms)
+{
+	struct dbglog *lp;
+	int i;
+
+	if (ms->n_log == 0)
+		return;
+	i = ms->log_ix - ms->n_log;
+	if (i < 0)
+		i += N_DBG_SLOG;
+	ms->n_log = 0;
+	do {
+		lp = &ms->log[i];
+		printk(KERN_DEBUG "mesh log: bs=%.2x%.2x ph=%.2x t%d ",
+		       lp->bs1, lp->bs0, lp->phase, lp->tgt);
+#ifdef DBG_USE_TB
+		printk("tb=%10u ", lp->tb);
+#endif
+		printk(lp->fmt, lp->d);
+		printk("\n");
+		if (++i >= N_DBG_SLOG)
+			i = 0;
+	} while (i != ms->log_ix);
+}
+
+#else
+
+static inline void dlog(struct mesh_state *ms, char *fmt, int a)
+{}
+static inline void dumplog(struct mesh_state *ms, int tgt)
+{}
+static inline void dumpslog(struct mesh_state *ms)
+{}
+
+#endif /* MESH_DBG */
+
+#define MKWORD(a, b, c, d)	(((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static void
+mesh_dump_regs(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	volatile struct dbdma_regs __iomem *md = ms->dma;
+	int t;
+	struct mesh_target *tp;
+
+	printk(KERN_DEBUG "mesh: state at %p, regs at %p, dma at %p\n",
+	       ms, mr, md);
+	printk(KERN_DEBUG "    ct=%4x seq=%2x bs=%4x fc=%2x "
+	       "exc=%2x err=%2x im=%2x int=%2x sp=%2x\n",
+	       (mr->count_hi << 8) + mr->count_lo, mr->sequence,
+	       (mr->bus_status1 << 8) + mr->bus_status0, mr->fifo_count,
+	       mr->exception, mr->error, mr->intr_mask, mr->interrupt,
+	       mr->sync_params);
+	while(in_8(&mr->fifo_count))
+		printk(KERN_DEBUG " fifo data=%.2x\n",in_8(&mr->fifo));
+	printk(KERN_DEBUG "    dma stat=%x cmdptr=%x\n",
+	       in_le32(&md->status), in_le32(&md->cmdptr));
+	printk(KERN_DEBUG "    phase=%d msgphase=%d conn_tgt=%d data_ptr=%d\n",
+	       ms->phase, ms->msgphase, ms->conn_tgt, ms->data_ptr);
+	printk(KERN_DEBUG "    dma_st=%d dma_ct=%d n_msgout=%d\n",
+	       ms->dma_started, ms->dma_count, ms->n_msgout);
+	for (t = 0; t < 8; ++t) {
+		tp = &ms->tgts[t];
+		if (tp->current_req == NULL)
+			continue;
+		printk(KERN_DEBUG "    target %d: req=%p goes_out=%d saved_ptr=%d\n",
+		       t, tp->current_req, tp->data_goes_out, tp->saved_ptr);
+	}
+}
+
+
+/*
+ * Flush write buffers on the bus path to the mesh
+ */
+static inline void mesh_flush_io(volatile struct mesh_regs __iomem *mr)
+{
+	(void)in_8(&mr->mesh_id);
+}
+
+
+/*
+ * Complete a SCSI command
+ */
+static void mesh_completed(struct mesh_state *ms, struct scsi_cmnd *cmd)
+{
+	(*cmd->scsi_done)(cmd);
+}
+
+
+/* Called with  meshinterrupt disabled, initialize the chipset
+ * and eventually do the initial bus reset. The lock must not be
+ * held since we can schedule.
+ */
+static void mesh_init(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	volatile struct dbdma_regs __iomem *md = ms->dma;
+
+	mesh_flush_io(mr);
+	udelay(100);
+
+	/* Reset controller */
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
+	out_8(&mr->exception, 0xff);	/* clear all exception bits */
+	out_8(&mr->error, 0xff);	/* clear all error bits */
+	out_8(&mr->sequence, SEQ_RESETMESH);
+	mesh_flush_io(mr);
+	udelay(10);
+	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->source_id, ms->host->this_id);
+	out_8(&mr->sel_timeout, 25);	/* 250ms */
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	if (init_reset_delay) {
+		printk(KERN_INFO "mesh: performing initial bus reset...\n");
+		
+		/* Reset bus */
+		out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+		mesh_flush_io(mr);
+		udelay(30);			/* leave it on for >= 25us */
+		out_8(&mr->bus_status1, 0);	/* negate RST */
+		mesh_flush_io(mr);
+
+		/* Wait for bus to come back */
+		msleep(init_reset_delay);
+	}
+	
+	/* Reconfigure controller */
+	out_8(&mr->interrupt, 0xff);	/* clear all interrupt bits */
+	out_8(&mr->sequence, SEQ_FLUSHFIFO);
+	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+
+	ms->phase = idle;
+	ms->msgphase = msg_none;
+}
+
+
+static void mesh_start_cmd(struct mesh_state *ms, struct scsi_cmnd *cmd)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	int t, id;
+
+	id = cmd->device->id;
+	ms->current_req = cmd;
+	ms->tgts[id].data_goes_out = cmd->sc_data_direction == DMA_TO_DEVICE;
+	ms->tgts[id].current_req = cmd;
+
+#if 1
+	if (DEBUG_TARGET(cmd)) {
+		int i;
+		printk(KERN_DEBUG "mesh_start: %p ser=%lu tgt=%d cmd=",
+		       cmd, cmd->serial_number, id);
+		for (i = 0; i < cmd->cmd_len; ++i)
+			printk(" %x", cmd->cmnd[i]);
+		printk(" use_sg=%d buffer=%p bufflen=%u\n",
+		       cmd->use_sg, cmd->request_buffer, cmd->request_bufflen);
+	}
+#endif
+	if (ms->dma_started)
+		panic("mesh: double DMA start !\n");
+
+	ms->phase = arbitrating;
+	ms->msgphase = msg_none;
+	ms->data_ptr = 0;
+	ms->dma_started = 0;
+	ms->n_msgout = 0;
+	ms->last_n_msgout = 0;
+	ms->expect_reply = 0;
+	ms->conn_tgt = id;
+	ms->tgts[id].saved_ptr = 0;
+	ms->stat = DID_OK;
+	ms->aborting = 0;
+#ifdef MESH_DBG
+	ms->tgts[id].n_log = 0;
+	dlog(ms, "start cmd=%x", (int) cmd);
+#endif
+
+	/* Off we go */
+	dlog(ms, "about to arb, intr/exc/err/fc=%.8x",
+	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
+	out_8(&mr->interrupt, INT_CMDDONE);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+	mesh_flush_io(mr);
+	udelay(1);
+
+	if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
+		/*
+		 * Some other device has the bus or is arbitrating for it -
+		 * probably a target which is about to reselect us.
+		 */
+		dlog(ms, "busy b4 arb, intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception,
+			    mr->error, mr->fifo_count));
+		for (t = 100; t > 0; --t) {
+			if ((in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) == 0)
+				break;
+			if (in_8(&mr->interrupt) != 0) {
+				dlog(ms, "intr b4 arb, intr/exc/err/fc=%.8x",
+				     MKWORD(mr->interrupt, mr->exception,
+					    mr->error, mr->fifo_count));
+				mesh_interrupt(0, (void *)ms, NULL);
+				if (ms->phase != arbitrating)
+					return;
+			}
+			udelay(1);
+		}
+		if (in_8(&mr->bus_status1) & (BS1_BSY | BS1_SEL)) {
+			/* XXX should try again in a little while */
+			ms->stat = DID_BUS_BUSY;
+			ms->phase = idle;
+			mesh_done(ms, 0);
+			return;
+		}
+	}
+
+	/*
+	 * Apparently the mesh has a bug where it will assert both its
+	 * own bit and the target's bit on the bus during arbitration.
+	 */
+	out_8(&mr->dest_id, mr->source_id);
+
+	/*
+	 * There appears to be a race with reselection sometimes,
+	 * where a target reselects us just as we issue the
+	 * arbitrate command.  It seems that then the arbitrate
+	 * command just hangs waiting for the bus to be free
+	 * without giving us a reselection exception.
+	 * The only way I have found to get it to respond correctly
+	 * is this: disable reselection before issuing the arbitrate
+	 * command, then after issuing it, if it looks like a target
+	 * is trying to reselect us, reset the mesh and then enable
+	 * reselection.
+	 */
+	out_8(&mr->sequence, SEQ_DISRESEL);
+	if (in_8(&mr->interrupt) != 0) {
+		dlog(ms, "intr after disresel, intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception,
+			    mr->error, mr->fifo_count));
+		mesh_interrupt(0, (void *)ms, NULL);
+		if (ms->phase != arbitrating)
+			return;
+		dlog(ms, "after intr after disresel, intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception,
+			    mr->error, mr->fifo_count));
+	}
+
+	out_8(&mr->sequence, SEQ_ARBITRATE);
+
+	for (t = 230; t > 0; --t) {
+		if (in_8(&mr->interrupt) != 0)
+			break;
+		udelay(1);
+	}
+	dlog(ms, "after arb, intr/exc/err/fc=%.8x",
+	     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
+	if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
+	    && (in_8(&mr->bus_status0) & BS0_IO)) {
+		/* looks like a reselection - try resetting the mesh */
+		dlog(ms, "resel? after arb, intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
+		out_8(&mr->sequence, SEQ_RESETMESH);
+		mesh_flush_io(mr);
+		udelay(10);
+		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+		out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+		out_8(&mr->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(mr);
+		for (t = 10; t > 0 && in_8(&mr->interrupt) == 0; --t)
+			udelay(1);
+		dlog(ms, "tried reset after arb, intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception, mr->error, mr->fifo_count));
+#ifndef MESH_MULTIPLE_HOSTS
+		if (in_8(&mr->interrupt) == 0 && (in_8(&mr->bus_status1) & BS1_SEL)
+		    && (in_8(&mr->bus_status0) & BS0_IO)) {
+			printk(KERN_ERR "mesh: controller not responding"
+			       " to reselection!\n");
+			/*
+			 * If this is a target reselecting us, and the
+			 * mesh isn't responding, the higher levels of
+			 * the scsi code will eventually time out and
+			 * reset the bus.
+			 */
+		}
+#endif
+	}
+}
+
+/*
+ * Start the next command for a MESH.
+ * Should be called with interrupts disabled.
+ */
+static void mesh_start(struct mesh_state *ms)
+{
+	struct scsi_cmnd *cmd, *prev, *next;
+
+	if (ms->phase != idle || ms->current_req != NULL) {
+		printk(KERN_ERR "inappropriate mesh_start (phase=%d, ms=%p)",
+		       ms->phase, ms);
+		return;
+	}
+
+	while (ms->phase == idle) {
+		prev = NULL;
+		for (cmd = ms->request_q; ; cmd = (struct scsi_cmnd *) cmd->host_scribble) {
+			if (cmd == NULL)
+				return;
+			if (ms->tgts[cmd->device->id].current_req == NULL)
+				break;
+			prev = cmd;
+		}
+		next = (struct scsi_cmnd *) cmd->host_scribble;
+		if (prev == NULL)
+			ms->request_q = next;
+		else
+			prev->host_scribble = (void *) next;
+		if (next == NULL)
+			ms->request_qtail = prev;
+
+		mesh_start_cmd(ms, cmd);
+	}
+}
+
+static void mesh_done(struct mesh_state *ms, int start_next)
+{
+	struct scsi_cmnd *cmd;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	cmd = ms->current_req;
+	ms->current_req = NULL;
+	tp->current_req = NULL;
+	if (cmd) {
+		cmd->result = (ms->stat << 16) + cmd->SCp.Status;
+		if (ms->stat == DID_OK)
+			cmd->result += (cmd->SCp.Message << 8);
+		if (DEBUG_TARGET(cmd)) {
+			printk(KERN_DEBUG "mesh_done: result = %x, data_ptr=%d, buflen=%d\n",
+			       cmd->result, ms->data_ptr, cmd->request_bufflen);
+			if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 3)
+			    && cmd->request_buffer != 0) {
+				unsigned char *b = cmd->request_buffer;
+				printk(KERN_DEBUG "buffer = %x %x %x %x %x %x %x %x\n",
+				       b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]);
+			}
+		}
+		cmd->SCp.this_residual -= ms->data_ptr;
+		mesh_completed(ms, cmd);
+	}
+	if (start_next) {
+		out_8(&ms->mesh->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(ms->mesh);
+		udelay(1);
+		ms->phase = idle;
+		mesh_start(ms);
+	}
+}
+
+static inline void add_sdtr_msg(struct mesh_state *ms)
+{
+	int i = ms->n_msgout;
+
+	ms->msgout[i] = EXTENDED_MESSAGE;
+	ms->msgout[i+1] = 3;
+	ms->msgout[i+2] = EXTENDED_SDTR;
+	ms->msgout[i+3] = mesh_sync_period/4;
+	ms->msgout[i+4] = (ALLOW_SYNC(ms->conn_tgt)? mesh_sync_offset: 0);
+	ms->n_msgout = i + 5;
+}
+
+static void set_sdtr(struct mesh_state *ms, int period, int offset)
+{
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	int v, tr;
+
+	tp->sdtr_state = sdtr_done;
+	if (offset == 0) {
+		/* asynchronous */
+		if (SYNC_OFF(tp->sync_params))
+			printk(KERN_INFO "mesh: target %d now asynchronous\n",
+			       ms->conn_tgt);
+		tp->sync_params = ASYNC_PARAMS;
+		out_8(&mr->sync_params, ASYNC_PARAMS);
+		return;
+	}
+	/*
+	 * We need to compute ceil(clk_freq * period / 500e6) - 2
+	 * without incurring overflow.
+	 */
+	v = (ms->clk_freq / 5000) * period;
+	if (v <= 250000) {
+		/* special case: sync_period == 5 * clk_period */
+		v = 0;
+		/* units of tr are 100kB/s */
+		tr = (ms->clk_freq + 250000) / 500000;
+	} else {
+		/* sync_period == (v + 2) * 2 * clk_period */
+		v = (v + 99999) / 100000 - 2;
+		if (v > 15)
+			v = 15;	/* oops */
+		tr = ((ms->clk_freq / (v + 2)) + 199999) / 200000;
+	}
+	if (offset > 15)
+		offset = 15;	/* can't happen */
+	tp->sync_params = SYNC_PARAMS(offset, v);
+	out_8(&mr->sync_params, tp->sync_params);
+	printk(KERN_INFO "mesh: target %d synchronous at %d.%d MB/s\n",
+	       ms->conn_tgt, tr/10, tr%10);
+}
+
+static void start_phase(struct mesh_state *ms)
+{
+	int i, seq, nb;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	volatile struct dbdma_regs __iomem *md = ms->dma;
+	struct scsi_cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	dlog(ms, "start_phase nmo/exc/fc/seq = %.8x",
+	     MKWORD(ms->n_msgout, mr->exception, mr->fifo_count, mr->sequence));
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
+	switch (ms->msgphase) {
+	case msg_none:
+		break;
+
+	case msg_in:
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGIN + seq);
+		ms->n_msgin = 0;
+		return;
+
+	case msg_out:
+		/*
+		 * To make sure ATN drops before we assert ACK for
+		 * the last byte of the message, we have to do the
+		 * last byte specially.
+		 */
+		if (ms->n_msgout <= 0) {
+			printk(KERN_ERR "mesh: msg_out but n_msgout=%d\n",
+			       ms->n_msgout);
+			mesh_dump_regs(ms);
+			ms->msgphase = msg_none;
+			break;
+		}
+		if (ALLOW_DEBUG(ms->conn_tgt)) {
+			printk(KERN_DEBUG "mesh: sending %d msg bytes:",
+			       ms->n_msgout);
+			for (i = 0; i < ms->n_msgout; ++i)
+				printk(" %x", ms->msgout[i]);
+			printk("\n");
+		}
+		dlog(ms, "msgout msg=%.8x", MKWORD(ms->n_msgout, ms->msgout[0],
+						ms->msgout[1], ms->msgout[2]));
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
+		udelay(1);
+		/*
+		 * If ATN is not already asserted, we assert it, then
+		 * issue a SEQ_MSGOUT to get the mesh to drop ACK.
+		 */
+		if ((in_8(&mr->bus_status0) & BS0_ATN) == 0) {
+			dlog(ms, "bus0 was %.2x explictly asserting ATN", mr->bus_status0);
+			out_8(&mr->bus_status0, BS0_ATN); /* explicit ATN */
+			mesh_flush_io(mr);
+			udelay(1);
+			out_8(&mr->count_lo, 1);
+			out_8(&mr->sequence, SEQ_MSGOUT + seq);
+			out_8(&mr->bus_status0, 0); /* release explicit ATN */
+			dlog(ms,"hace: after explicit ATN bus0=%.2x",mr->bus_status0);
+		}
+		if (ms->n_msgout == 1) {
+			/*
+			 * We can't issue the SEQ_MSGOUT without ATN
+			 * until the target has asserted REQ.  The logic
+			 * in cmd_complete handles both situations:
+			 * REQ already asserted or not.
+			 */
+			cmd_complete(ms);
+		} else {
+			out_8(&mr->count_lo, ms->n_msgout - 1);
+			out_8(&mr->sequence, SEQ_MSGOUT + seq);
+			for (i = 0; i < ms->n_msgout - 1; ++i)
+				out_8(&mr->fifo, ms->msgout[i]);
+		}
+		return;
+
+	default:
+		printk(KERN_ERR "mesh bug: start_phase msgphase=%d\n",
+		       ms->msgphase);
+	}
+
+	switch (ms->phase) {
+	case selecting:
+		out_8(&mr->dest_id, ms->conn_tgt);
+		out_8(&mr->sequence, SEQ_SELECT + SEQ_ATN);
+		break;
+	case commanding:
+		out_8(&mr->sync_params, tp->sync_params);
+		out_8(&mr->count_hi, 0);
+		if (cmd) {
+			out_8(&mr->count_lo, cmd->cmd_len);
+			out_8(&mr->sequence, SEQ_COMMAND + seq);
+			for (i = 0; i < cmd->cmd_len; ++i)
+				out_8(&mr->fifo, cmd->cmnd[i]);
+		} else {
+			out_8(&mr->count_lo, 6);
+			out_8(&mr->sequence, SEQ_COMMAND + seq);
+			for (i = 0; i < 6; ++i)
+				out_8(&mr->fifo, 0);
+		}
+		break;
+	case dataing:
+		/* transfer data, if any */
+		if (!ms->dma_started) {
+			set_dma_cmds(ms, cmd);
+			out_le32(&md->cmdptr, virt_to_phys(ms->dma_cmds));
+			out_le32(&md->control, (RUN << 16) | RUN);
+			ms->dma_started = 1;
+		}
+		nb = ms->dma_count;
+		if (nb > 0xfff0)
+			nb = 0xfff0;
+		ms->dma_count -= nb;
+		ms->data_ptr += nb;
+		out_8(&mr->count_lo, nb);
+		out_8(&mr->count_hi, nb >> 8);
+		out_8(&mr->sequence, (tp->data_goes_out?
+				SEQ_DATAOUT: SEQ_DATAIN) + SEQ_DMA_MODE + seq);
+		break;
+	case statusing:
+		out_8(&mr->count_hi, 0);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_STATUS + seq);
+		break;
+	case busfreeing:
+	case disconnecting:
+		out_8(&mr->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(mr);
+		udelay(1);
+		dlog(ms, "enbresel intr/exc/err/fc=%.8x",
+		     MKWORD(mr->interrupt, mr->exception, mr->error,
+			    mr->fifo_count));
+		out_8(&mr->sequence, SEQ_BUSFREE);
+		break;
+	default:
+		printk(KERN_ERR "mesh: start_phase called with phase=%d\n",
+		       ms->phase);
+		dumpslog(ms);
+	}
+
+}
+
+static inline void get_msgin(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	int i, n;
+
+	n = mr->fifo_count;
+	if (n != 0) {
+		i = ms->n_msgin;
+		ms->n_msgin = i + n;
+		for (; n > 0; --n)
+			ms->msgin[i++] = in_8(&mr->fifo);
+	}
+}
+
+static inline int msgin_length(struct mesh_state *ms)
+{
+	int b, n;
+
+	n = 1;
+	if (ms->n_msgin > 0) {
+		b = ms->msgin[0];
+		if (b == 1) {
+			/* extended message */
+			n = ms->n_msgin < 2? 2: ms->msgin[1] + 2;
+		} else if (0x20 <= b && b <= 0x2f) {
+			/* 2-byte message */
+			n = 2;
+		}
+	}
+	return n;
+}
+
+static void reselected(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	struct scsi_cmnd *cmd;
+	struct mesh_target *tp;
+	int b, t, prev;
+
+	switch (ms->phase) {
+	case idle:
+		break;
+	case arbitrating:
+		if ((cmd = ms->current_req) != NULL) {
+			/* put the command back on the queue */
+			cmd->host_scribble = (void *) ms->request_q;
+			if (ms->request_q == NULL)
+				ms->request_qtail = cmd;
+			ms->request_q = cmd;
+			tp = &ms->tgts[cmd->device->id];
+			tp->current_req = NULL;
+		}
+		break;
+	case busfreeing:
+		ms->phase = reselecting;
+		mesh_done(ms, 0);
+		break;
+	case disconnecting:
+		break;
+	default:
+		printk(KERN_ERR "mesh: reselected in phase %d/%d tgt %d\n",
+		       ms->msgphase, ms->phase, ms->conn_tgt);
+		dumplog(ms, ms->conn_tgt);
+		dumpslog(ms);
+	}
+
+	if (ms->dma_started) {
+		printk(KERN_ERR "mesh: reselected with DMA started !\n");
+		halt_dma(ms);
+	}
+	ms->current_req = NULL;
+	ms->phase = dataing;
+	ms->msgphase = msg_in;
+	ms->n_msgout = 0;
+	ms->last_n_msgout = 0;
+	prev = ms->conn_tgt;
+
+	/*
+	 * We seem to get abortive reselections sometimes.
+	 */
+	while ((in_8(&mr->bus_status1) & BS1_BSY) == 0) {
+		static int mesh_aborted_resels;
+		mesh_aborted_resels++;
+		out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+		mesh_flush_io(mr);
+		udelay(1);
+		out_8(&mr->sequence, SEQ_ENBRESEL);
+		mesh_flush_io(mr);
+		udelay(5);
+		dlog(ms, "extra resel err/exc/fc = %.6x",
+		     MKWORD(0, mr->error, mr->exception, mr->fifo_count));
+	}
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	/*
+	 * Find out who reselected us.
+	 */
+	if (in_8(&mr->fifo_count) == 0) {
+		printk(KERN_ERR "mesh: reselection but nothing in fifo?\n");
+		ms->conn_tgt = ms->host->this_id;
+		goto bogus;
+	}
+	/* get the last byte in the fifo */
+	do {
+		b = in_8(&mr->fifo);
+		dlog(ms, "reseldata %x", b);
+	} while (in_8(&mr->fifo_count));
+	for (t = 0; t < 8; ++t)
+		if ((b & (1 << t)) != 0 && t != ms->host->this_id)
+			break;
+	if (b != (1 << t) + (1 << ms->host->this_id)) {
+		printk(KERN_ERR "mesh: bad reselection data %x\n", b);
+		ms->conn_tgt = ms->host->this_id;
+		goto bogus;
+	}
+
+
+	/*
+	 * Set up to continue with that target's transfer.
+	 */
+	ms->conn_tgt = t;
+	tp = &ms->tgts[t];
+	out_8(&mr->sync_params, tp->sync_params);
+	if (ALLOW_DEBUG(t)) {
+		printk(KERN_DEBUG "mesh: reselected by target %d\n", t);
+		printk(KERN_DEBUG "mesh: saved_ptr=%x goes_out=%d cmd=%p\n",
+		       tp->saved_ptr, tp->data_goes_out, tp->current_req);
+	}
+	ms->current_req = tp->current_req;
+	if (tp->current_req == NULL) {
+		printk(KERN_ERR "mesh: reselected by tgt %d but no cmd!\n", t);
+		goto bogus;
+	}
+	ms->data_ptr = tp->saved_ptr;
+	dlog(ms, "resel prev tgt=%d", prev);
+	dlog(ms, "resel err/exc=%.4x", MKWORD(0, 0, mr->error, mr->exception));
+	start_phase(ms);
+	return;
+
+bogus:
+	dumplog(ms, ms->conn_tgt);
+	dumpslog(ms);
+	ms->data_ptr = 0;
+	ms->aborting = 1;
+	start_phase(ms);
+}
+
+static void do_abort(struct mesh_state *ms)
+{
+	ms->msgout[0] = ABORT;
+	ms->n_msgout = 1;
+	ms->aborting = 1;
+	ms->stat = DID_ABORT;
+	dlog(ms, "abort", 0);
+}
+
+static void handle_reset(struct mesh_state *ms)
+{
+	int tgt;
+	struct mesh_target *tp;
+	struct scsi_cmnd *cmd;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+
+	for (tgt = 0; tgt < 8; ++tgt) {
+		tp = &ms->tgts[tgt];
+		if ((cmd = tp->current_req) != NULL) {
+			cmd->result = DID_RESET << 16;
+			tp->current_req = NULL;
+			mesh_completed(ms, cmd);
+		}
+		ms->tgts[tgt].sdtr_state = do_sdtr;
+		ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+	}
+	ms->current_req = NULL;
+	while ((cmd = ms->request_q) != NULL) {
+		ms->request_q = (struct scsi_cmnd *) cmd->host_scribble;
+		cmd->result = DID_RESET << 16;
+		mesh_completed(ms, cmd);
+	}
+	ms->phase = idle;
+	ms->msgphase = msg_none;
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->sequence, SEQ_FLUSHFIFO);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+	out_8(&mr->sequence, SEQ_ENBRESEL);
+}
+
+static irqreturn_t do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = ((struct mesh_state *)dev_id)->host;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
+	mesh_interrupt(irq, dev_id, ptregs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void handle_error(struct mesh_state *ms)
+{
+	int err, exc, count;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+
+	err = in_8(&mr->error);
+	exc = in_8(&mr->exception);
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	dlog(ms, "error err/exc/fc/cl=%.8x",
+	     MKWORD(err, exc, mr->fifo_count, mr->count_lo));
+	if (err & ERR_SCSIRESET) {
+		/* SCSI bus was reset */
+		printk(KERN_INFO "mesh: SCSI bus reset detected: "
+		       "waiting for end...");
+		while ((in_8(&mr->bus_status1) & BS1_RST) != 0)
+			udelay(1);
+		printk("done\n");
+		handle_reset(ms);
+		/* request_q is empty, no point in mesh_start() */
+		return;
+	}
+	if (err & ERR_UNEXPDISC) {
+		/* Unexpected disconnect */
+		if (exc & EXC_RESELECTED) {
+			reselected(ms);
+			return;
+		}
+		if (!ms->aborting) {
+			printk(KERN_WARNING "mesh: target %d aborted\n",
+			       ms->conn_tgt);
+			dumplog(ms, ms->conn_tgt);
+			dumpslog(ms);
+		}
+		out_8(&mr->interrupt, INT_CMDDONE);
+		ms->stat = DID_ABORT;
+		mesh_done(ms, 1);
+		return;
+	}
+	if (err & ERR_PARITY) {
+		if (ms->msgphase == msg_in) {
+			printk(KERN_ERR "mesh: msg parity error, target %d\n",
+			       ms->conn_tgt);
+			ms->msgout[0] = MSG_PARITY_ERROR;
+			ms->n_msgout = 1;
+			ms->msgphase = msg_in_bad;
+			cmd_complete(ms);
+			return;
+		}
+		if (ms->stat == DID_OK) {
+			printk(KERN_ERR "mesh: parity error, target %d\n",
+			       ms->conn_tgt);
+			ms->stat = DID_PARITY;
+		}
+		count = (mr->count_hi << 8) + mr->count_lo;
+		if (count == 0) {
+			cmd_complete(ms);
+		} else {
+			/* reissue the data transfer command */
+			out_8(&mr->sequence, mr->sequence);
+		}
+		return;
+	}
+	if (err & ERR_SEQERR) {
+		if (exc & EXC_RESELECTED) {
+			/* This can happen if we issue a command to
+			   get the bus just after the target reselects us. */
+			static int mesh_resel_seqerr;
+			mesh_resel_seqerr++;
+			reselected(ms);
+			return;
+		}
+		if (exc == EXC_PHASEMM) {
+			static int mesh_phasemm_seqerr;
+			mesh_phasemm_seqerr++;
+			phase_mismatch(ms);
+			return;
+		}
+		printk(KERN_ERR "mesh: sequence error (err=%x exc=%x)\n",
+		       err, exc);
+	} else {
+		printk(KERN_ERR "mesh: unknown error %x (exc=%x)\n", err, exc);
+	}
+	mesh_dump_regs(ms);
+	dumplog(ms, ms->conn_tgt);
+	if (ms->phase > selecting && (in_8(&mr->bus_status1) & BS1_BSY)) {
+		/* try to do what the target wants */
+		do_abort(ms);
+		phase_mismatch(ms);
+		return;
+	}
+	ms->stat = DID_ERROR;
+	mesh_done(ms, 1);
+}
+
+static void handle_exception(struct mesh_state *ms)
+{
+	int exc;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+
+	exc = in_8(&mr->exception);
+	out_8(&mr->interrupt, INT_EXCEPTION | INT_CMDDONE);
+	if (exc & EXC_RESELECTED) {
+		static int mesh_resel_exc;
+		mesh_resel_exc++;
+		reselected(ms);
+	} else if (exc == EXC_ARBLOST) {
+		printk(KERN_DEBUG "mesh: lost arbitration\n");
+		ms->stat = DID_BUS_BUSY;
+		mesh_done(ms, 1);
+	} else if (exc == EXC_SELTO) {
+		/* selection timed out */
+		ms->stat = DID_BAD_TARGET;
+		mesh_done(ms, 1);
+	} else if (exc == EXC_PHASEMM) {
+		/* target wants to do something different:
+		   find out what it wants and do it. */
+		phase_mismatch(ms);
+	} else {
+		printk(KERN_ERR "mesh: can't cope with exception %x\n", exc);
+		mesh_dump_regs(ms);
+		dumplog(ms, ms->conn_tgt);
+		do_abort(ms);
+		phase_mismatch(ms);
+	}
+}
+
+static void handle_msgin(struct mesh_state *ms)
+{
+	int i, code;
+	struct scsi_cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+
+	if (ms->n_msgin == 0)
+		return;
+	code = ms->msgin[0];
+	if (ALLOW_DEBUG(ms->conn_tgt)) {
+		printk(KERN_DEBUG "got %d message bytes:", ms->n_msgin);
+		for (i = 0; i < ms->n_msgin; ++i)
+			printk(" %x", ms->msgin[i]);
+		printk("\n");
+	}
+	dlog(ms, "msgin msg=%.8x",
+	     MKWORD(ms->n_msgin, code, ms->msgin[1], ms->msgin[2]));
+
+	ms->expect_reply = 0;
+	ms->n_msgout = 0;
+	if (ms->n_msgin < msgin_length(ms))
+		goto reject;
+	if (cmd)
+		cmd->SCp.Message = code;
+	switch (code) {
+	case COMMAND_COMPLETE:
+		break;
+	case EXTENDED_MESSAGE:
+		switch (ms->msgin[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			ms->data_ptr += (ms->msgin[3] << 24) + ms->msgin[6]
+				+ (ms->msgin[4] << 16) + (ms->msgin[5] << 8);
+			break;
+		case EXTENDED_SDTR:
+			if (tp->sdtr_state != sdtr_sent) {
+				/* reply with an SDTR */
+				add_sdtr_msg(ms);
+				/* limit period to at least his value,
+				   offset to no more than his */
+				if (ms->msgout[3] < ms->msgin[3])
+					ms->msgout[3] = ms->msgin[3];
+				if (ms->msgout[4] > ms->msgin[4])
+					ms->msgout[4] = ms->msgin[4];
+				set_sdtr(ms, ms->msgout[3], ms->msgout[4]);
+				ms->msgphase = msg_out;
+			} else {
+				set_sdtr(ms, ms->msgin[3], ms->msgin[4]);
+			}
+			break;
+		default:
+			goto reject;
+		}
+		break;
+	case SAVE_POINTERS:
+		tp->saved_ptr = ms->data_ptr;
+		break;
+	case RESTORE_POINTERS:
+		ms->data_ptr = tp->saved_ptr;
+		break;
+	case DISCONNECT:
+		ms->phase = disconnecting;
+		break;
+	case ABORT:
+		break;
+	case MESSAGE_REJECT:
+		if (tp->sdtr_state == sdtr_sent)
+			set_sdtr(ms, 0, 0);
+		break;
+	case NOP:
+		break;
+	default:
+		if (IDENTIFY_BASE <= code && code <= IDENTIFY_BASE + 7) {
+			if (cmd == NULL) {
+				do_abort(ms);
+				ms->msgphase = msg_out;
+			} else if (code != cmd->device->lun + IDENTIFY_BASE) {
+				printk(KERN_WARNING "mesh: lun mismatch "
+				       "(%d != %d) on reselection from "
+				       "target %d\n", code - IDENTIFY_BASE,
+				       cmd->device->lun, ms->conn_tgt);
+			}
+			break;
+		}
+		goto reject;
+	}
+	return;
+
+ reject:
+	printk(KERN_WARNING "mesh: rejecting message from target %d:",
+	       ms->conn_tgt);
+	for (i = 0; i < ms->n_msgin; ++i)
+		printk(" %x", ms->msgin[i]);
+	printk("\n");
+	ms->msgout[0] = MESSAGE_REJECT;
+	ms->n_msgout = 1;
+	ms->msgphase = msg_out;
+}
+
+/*
+ * Set up DMA commands for transferring data.
+ */
+static void set_dma_cmds(struct mesh_state *ms, struct scsi_cmnd *cmd)
+{
+	int i, dma_cmd, total, off, dtot;
+	struct scatterlist *scl;
+	struct dbdma_cmd *dcmds;
+
+	dma_cmd = ms->tgts[ms->conn_tgt].data_goes_out?
+		OUTPUT_MORE: INPUT_MORE;
+	dcmds = ms->dma_cmds;
+	dtot = 0;
+	if (cmd) {
+		cmd->SCp.this_residual = cmd->request_bufflen;
+		if (cmd->use_sg > 0) {
+			int nseg;
+			total = 0;
+			scl = (struct scatterlist *) cmd->buffer;
+			off = ms->data_ptr;
+			nseg = pci_map_sg(ms->pdev, scl, cmd->use_sg,
+					  cmd->sc_data_direction);
+			for (i = 0; i <nseg; ++i, ++scl) {
+				u32 dma_addr = sg_dma_address(scl);
+				u32 dma_len = sg_dma_len(scl);
+				
+				total += scl->length;
+				if (off >= dma_len) {
+					off -= dma_len;
+					continue;
+				}
+				if (dma_len > 0xffff)
+					panic("mesh: scatterlist element >= 64k");
+				st_le16(&dcmds->req_count, dma_len - off);
+				st_le16(&dcmds->command, dma_cmd);
+				st_le32(&dcmds->phy_addr, dma_addr + off);
+				dcmds->xfer_status = 0;
+				++dcmds;
+				dtot += dma_len - off;
+				off = 0;
+			}
+		} else if (ms->data_ptr < cmd->request_bufflen) {
+			dtot = cmd->request_bufflen - ms->data_ptr;
+			if (dtot > 0xffff)
+				panic("mesh: transfer size >= 64k");
+			st_le16(&dcmds->req_count, dtot);
+			/* XXX Use pci DMA API here ... */
+			st_le32(&dcmds->phy_addr,
+				virt_to_phys(cmd->request_buffer) + ms->data_ptr);
+			dcmds->xfer_status = 0;
+			++dcmds;
+		}
+	}
+	if (dtot == 0) {
+		/* Either the target has overrun our buffer,
+		   or the caller didn't provide a buffer. */
+		static char mesh_extra_buf[64];
+
+		dtot = sizeof(mesh_extra_buf);
+		st_le16(&dcmds->req_count, dtot);
+		st_le32(&dcmds->phy_addr, virt_to_phys(mesh_extra_buf));
+		dcmds->xfer_status = 0;
+		++dcmds;
+	}
+	dma_cmd += OUTPUT_LAST - OUTPUT_MORE;
+	st_le16(&dcmds[-1].command, dma_cmd);
+	memset(dcmds, 0, sizeof(*dcmds));
+	st_le16(&dcmds->command, DBDMA_STOP);
+	ms->dma_count = dtot;
+}
+
+static void halt_dma(struct mesh_state *ms)
+{
+	volatile struct dbdma_regs __iomem *md = ms->dma;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	struct scsi_cmnd *cmd = ms->current_req;
+	int t, nb;
+
+	if (!ms->tgts[ms->conn_tgt].data_goes_out) {
+		/* wait a little while until the fifo drains */
+		t = 50;
+		while (t > 0 && in_8(&mr->fifo_count) != 0
+		       && (in_le32(&md->status) & ACTIVE) != 0) {
+			--t;
+			udelay(1);
+		}
+	}
+	out_le32(&md->control, RUN << 16);	/* turn off RUN bit */
+	nb = (mr->count_hi << 8) + mr->count_lo;
+	dlog(ms, "halt_dma fc/count=%.6x",
+	     MKWORD(0, mr->fifo_count, 0, nb));
+	if (ms->tgts[ms->conn_tgt].data_goes_out)
+		nb += mr->fifo_count;
+	/* nb is the number of bytes not yet transferred
+	   to/from the target. */
+	ms->data_ptr -= nb;
+	dlog(ms, "data_ptr %x", ms->data_ptr);
+	if (ms->data_ptr < 0) {
+		printk(KERN_ERR "mesh: halt_dma: data_ptr=%d (nb=%d, ms=%p)\n",
+		       ms->data_ptr, nb, ms);
+		ms->data_ptr = 0;
+#ifdef MESH_DBG
+		dumplog(ms, ms->conn_tgt);
+		dumpslog(ms);
+#endif /* MESH_DBG */
+	} else if (cmd && cmd->request_bufflen != 0 &&
+		   ms->data_ptr > cmd->request_bufflen) {
+		printk(KERN_DEBUG "mesh: target %d overrun, "
+		       "data_ptr=%x total=%x goes_out=%d\n",
+		       ms->conn_tgt, ms->data_ptr, cmd->request_bufflen,
+		       ms->tgts[ms->conn_tgt].data_goes_out);
+	}
+	if (cmd->use_sg != 0) {
+		struct scatterlist *sg;
+		sg = (struct scatterlist *)cmd->request_buffer;
+		pci_unmap_sg(ms->pdev, sg, cmd->use_sg, cmd->sc_data_direction);
+	}
+	ms->dma_started = 0;
+}
+
+static void phase_mismatch(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	int phase;
+
+	dlog(ms, "phasemm ch/cl/seq/fc=%.8x",
+	     MKWORD(mr->count_hi, mr->count_lo, mr->sequence, mr->fifo_count));
+	phase = in_8(&mr->bus_status0) & BS0_PHASE;
+	if (ms->msgphase == msg_out_xxx && phase == BP_MSGOUT) {
+		/* output the last byte of the message, without ATN */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
+		mesh_flush_io(mr);
+		udelay(1);
+		out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+		ms->msgphase = msg_out_last;
+		return;
+	}
+
+	if (ms->msgphase == msg_in) {
+		get_msgin(ms);
+		if (ms->n_msgin)
+			handle_msgin(ms);
+	}
+
+	if (ms->dma_started)
+		halt_dma(ms);
+	if (mr->fifo_count) {
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
+		udelay(1);
+	}
+
+	ms->msgphase = msg_none;
+	switch (phase) {
+	case BP_DATAIN:
+		ms->tgts[ms->conn_tgt].data_goes_out = 0;
+		ms->phase = dataing;
+		break;
+	case BP_DATAOUT:
+		ms->tgts[ms->conn_tgt].data_goes_out = 1;
+		ms->phase = dataing;
+		break;
+	case BP_COMMAND:
+		ms->phase = commanding;
+		break;
+	case BP_STATUS:
+		ms->phase = statusing;
+		break;
+	case BP_MSGIN:
+		ms->msgphase = msg_in;
+		ms->n_msgin = 0;
+		break;
+	case BP_MSGOUT:
+		ms->msgphase = msg_out;
+		if (ms->n_msgout == 0) {
+			if (ms->aborting) {
+				do_abort(ms);
+			} else {
+				if (ms->last_n_msgout == 0) {
+					printk(KERN_DEBUG
+					       "mesh: no msg to repeat\n");
+					ms->msgout[0] = NOP;
+					ms->last_n_msgout = 1;
+				}
+				ms->n_msgout = ms->last_n_msgout;
+			}
+		}
+		break;
+	default:
+		printk(KERN_DEBUG "mesh: unknown scsi phase %x\n", phase);
+		ms->stat = DID_ERROR;
+		mesh_done(ms, 1);
+		return;
+	}
+
+	start_phase(ms);
+}
+
+static void cmd_complete(struct mesh_state *ms)
+{
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	struct scsi_cmnd *cmd = ms->current_req;
+	struct mesh_target *tp = &ms->tgts[ms->conn_tgt];
+	int seq, n, t;
+
+	dlog(ms, "cmd_complete fc=%x", mr->fifo_count);
+	seq = use_active_neg + (ms->n_msgout? SEQ_ATN: 0);
+	switch (ms->msgphase) {
+	case msg_out_xxx:
+		/* huh?  we expected a phase mismatch */
+		ms->n_msgin = 0;
+		ms->msgphase = msg_in;
+		/* fall through */
+
+	case msg_in:
+		/* should have some message bytes in fifo */
+		get_msgin(ms);
+		n = msgin_length(ms);
+		if (ms->n_msgin < n) {
+			out_8(&mr->count_lo, n - ms->n_msgin);
+			out_8(&mr->sequence, SEQ_MSGIN + seq);
+		} else {
+			ms->msgphase = msg_none;
+			handle_msgin(ms);
+			start_phase(ms);
+		}
+		break;
+
+	case msg_in_bad:
+		out_8(&mr->sequence, SEQ_FLUSHFIFO);
+		mesh_flush_io(mr);
+		udelay(1);
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGIN + SEQ_ATN + use_active_neg);
+		break;
+
+	case msg_out:
+		/*
+		 * To get the right timing on ATN wrt ACK, we have
+		 * to get the MESH to drop ACK, wait until REQ gets
+		 * asserted, then drop ATN.  To do this we first
+		 * issue a SEQ_MSGOUT with ATN and wait for REQ,
+		 * then change the command to a SEQ_MSGOUT w/o ATN.
+		 * If we don't see REQ in a reasonable time, we
+		 * change the command to SEQ_MSGIN with ATN,
+		 * wait for the phase mismatch interrupt, then
+		 * issue the SEQ_MSGOUT without ATN.
+		 */
+		out_8(&mr->count_lo, 1);
+		out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg + SEQ_ATN);
+		t = 30;		/* wait up to 30us */
+		while ((in_8(&mr->bus_status0) & BS0_REQ) == 0 && --t >= 0)
+			udelay(1);
+		dlog(ms, "last_mbyte err/exc/fc/cl=%.8x",
+		     MKWORD(mr->error, mr->exception,
+			    mr->fifo_count, mr->count_lo));
+		if (in_8(&mr->interrupt) & (INT_ERROR | INT_EXCEPTION)) {
+			/* whoops, target didn't do what we expected */
+			ms->last_n_msgout = ms->n_msgout;
+			ms->n_msgout = 0;
+			if (in_8(&mr->interrupt) & INT_ERROR) {
+				printk(KERN_ERR "mesh: error %x in msg_out\n",
+				       in_8(&mr->error));
+				handle_error(ms);
+				return;
+			}
+			if (in_8(&mr->exception) != EXC_PHASEMM)
+				printk(KERN_ERR "mesh: exc %x in msg_out\n",
+				       in_8(&mr->exception));
+			else
+				printk(KERN_DEBUG "mesh: bs0=%x in msg_out\n",
+				       in_8(&mr->bus_status0));
+			handle_exception(ms);
+			return;
+		}
+		if (in_8(&mr->bus_status0) & BS0_REQ) {
+			out_8(&mr->sequence, SEQ_MSGOUT + use_active_neg);
+			mesh_flush_io(mr);
+			udelay(1);
+			out_8(&mr->fifo, ms->msgout[ms->n_msgout-1]);
+			ms->msgphase = msg_out_last;
+		} else {
+			out_8(&mr->sequence, SEQ_MSGIN + use_active_neg + SEQ_ATN);
+			ms->msgphase = msg_out_xxx;
+		}
+		break;
+
+	case msg_out_last:
+		ms->last_n_msgout = ms->n_msgout;
+		ms->n_msgout = 0;
+		ms->msgphase = ms->expect_reply? msg_in: msg_none;
+		start_phase(ms);
+		break;
+
+	case msg_none:
+		switch (ms->phase) {
+		case idle:
+			printk(KERN_ERR "mesh: interrupt in idle phase?\n");
+			dumpslog(ms);
+			return;
+		case selecting:
+			dlog(ms, "Selecting phase at command completion",0);
+			ms->msgout[0] = IDENTIFY(ALLOW_RESEL(ms->conn_tgt),
+						 (cmd? cmd->device->lun: 0));
+			ms->n_msgout = 1;
+			ms->expect_reply = 0;
+			if (ms->aborting) {
+				ms->msgout[0] = ABORT;
+				ms->n_msgout++;
+			} else if (tp->sdtr_state == do_sdtr) {
+				/* add SDTR message */
+				add_sdtr_msg(ms);
+				ms->expect_reply = 1;
+				tp->sdtr_state = sdtr_sent;
+			}
+			ms->msgphase = msg_out;
+			/*
+			 * We need to wait for REQ before dropping ATN.
+			 * We wait for at most 30us, then fall back to
+			 * a scheme where we issue a SEQ_COMMAND with ATN,
+			 * which will give us a phase mismatch interrupt
+			 * when REQ does come, and then we send the message.
+			 */
+			t = 230;		/* wait up to 230us */
+			while ((in_8(&mr->bus_status0) & BS0_REQ) == 0) {
+				if (--t < 0) {
+					dlog(ms, "impatient for req", ms->n_msgout);
+					ms->msgphase = msg_none;
+					break;
+				}
+				udelay(1);
+			}
+			break;
+		case dataing:
+			if (ms->dma_count != 0) {
+				start_phase(ms);
+				return;
+			}
+			/*
+			 * We can get a phase mismatch here if the target
+			 * changes to the status phase, even though we have
+			 * had a command complete interrupt.  Then, if we
+			 * issue the SEQ_STATUS command, we'll get a sequence
+			 * error interrupt.  Which isn't so bad except that
+			 * occasionally the mesh actually executes the
+			 * SEQ_STATUS *as well as* giving us the sequence
+			 * error and phase mismatch exception.
+			 */
+			out_8(&mr->sequence, 0);
+			out_8(&mr->interrupt,
+			      INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+			halt_dma(ms);
+			break;
+		case statusing:
+			if (cmd) {
+				cmd->SCp.Status = mr->fifo;
+				if (DEBUG_TARGET(cmd))
+					printk(KERN_DEBUG "mesh: status is %x\n",
+					       cmd->SCp.Status);
+			}
+			ms->msgphase = msg_in;
+			break;
+		case busfreeing:
+			mesh_done(ms, 1);
+			return;
+		case disconnecting:
+			ms->current_req = NULL;
+			ms->phase = idle;
+			mesh_start(ms);
+			return;
+		default:
+			break;
+		}
+		++ms->phase;
+		start_phase(ms);
+		break;
+	}
+}
+
+
+/*
+ * Called by midlayer with host locked to queue a new
+ * request
+ */
+static int mesh_queue(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
+{
+	struct mesh_state *ms;
+
+	cmd->scsi_done = done;
+	cmd->host_scribble = NULL;
+
+	ms = (struct mesh_state *) cmd->device->host->hostdata;
+
+	if (ms->request_q == NULL)
+		ms->request_q = cmd;
+	else
+		ms->request_qtail->host_scribble = (void *) cmd;
+	ms->request_qtail = cmd;
+
+	if (ms->phase == idle)
+		mesh_start(ms);
+
+	return 0;
+}
+
+/*
+ * Called to handle interrupts, either call by the interrupt
+ * handler (do_mesh_interrupt) or by other functions in
+ * exceptional circumstances
+ */
+static void mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+{
+	struct mesh_state *ms = (struct mesh_state *) dev_id;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	int intr;
+
+#if 0
+	if (ALLOW_DEBUG(ms->conn_tgt))
+		printk(KERN_DEBUG "mesh_intr, bs0=%x int=%x exc=%x err=%x "
+		       "phase=%d msgphase=%d\n", mr->bus_status0,
+		       mr->interrupt, mr->exception, mr->error,
+		       ms->phase, ms->msgphase);
+#endif
+	while ((intr = in_8(&mr->interrupt)) != 0) {
+		dlog(ms, "interrupt intr/err/exc/seq=%.8x", 
+		     MKWORD(intr, mr->error, mr->exception, mr->sequence));
+		if (intr & INT_ERROR) {
+			handle_error(ms);
+		} else if (intr & INT_EXCEPTION) {
+			handle_exception(ms);
+		} else if (intr & INT_CMDDONE) {
+			out_8(&mr->interrupt, INT_CMDDONE);
+			cmd_complete(ms);
+		}
+	}
+}
+
+/* Todo: here we can at least try to remove the command from the
+ * queue if it isn't connected yet, and for pending command, assert
+ * ATN until the bus gets freed.
+ */
+static int mesh_abort(struct scsi_cmnd *cmd)
+{
+	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
+
+	printk(KERN_DEBUG "mesh_abort(%p)\n", cmd);
+	mesh_dump_regs(ms);
+	dumplog(ms, cmd->device->id);
+	dumpslog(ms);
+	return FAILED;
+}
+
+/*
+ * Called by the midlayer with the lock held to reset the
+ * SCSI host and bus.
+ * The midlayer will wait for devices to come back, we don't need
+ * to do that ourselves
+ */
+static int mesh_host_reset(struct scsi_cmnd *cmd)
+{
+	struct mesh_state *ms = (struct mesh_state *) cmd->device->host->hostdata;
+	volatile struct mesh_regs __iomem *mr = ms->mesh;
+	volatile struct dbdma_regs __iomem *md = ms->dma;
+
+	printk(KERN_DEBUG "mesh_host_reset\n");
+
+	/* Reset the controller & dbdma channel */
+	out_le32(&md->control, (RUN|PAUSE|FLUSH|WAKE) << 16);	/* stop dma */
+	out_8(&mr->exception, 0xff);	/* clear all exception bits */
+	out_8(&mr->error, 0xff);	/* clear all error bits */
+	out_8(&mr->sequence, SEQ_RESETMESH);
+       	mesh_flush_io(mr);
+	udelay(1);
+	out_8(&mr->intr_mask, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->source_id, ms->host->this_id);
+	out_8(&mr->sel_timeout, 25);	/* 250ms */
+	out_8(&mr->sync_params, ASYNC_PARAMS);
+
+	/* Reset the bus */
+	out_8(&mr->bus_status1, BS1_RST);	/* assert RST */
+       	mesh_flush_io(mr);
+	udelay(30);			/* leave it on for >= 25us */
+	out_8(&mr->bus_status1, 0);	/* negate RST */
+
+	/* Complete pending commands */
+	handle_reset(ms);
+	
+	return SUCCESS;
+}
+
+static void set_mesh_power(struct mesh_state *ms, int state)
+{
+	if (_machine != _MACH_Pmac)
+		return;
+	if (state) {
+		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 1);
+		msleep(200);
+	} else {
+		pmac_call_feature(PMAC_FTR_MESH_ENABLE, macio_get_of_node(ms->mdev), 0, 0);
+		msleep(10);
+	}
+}			
+
+
+#ifdef CONFIG_PM
+static int mesh_suspend(struct macio_dev *mdev, u32 state)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	unsigned long flags;
+
+	if (state == mdev->ofdev.dev.power.power_state || state < 2)
+		return 0;
+
+	scsi_block_requests(ms->host);
+	spin_lock_irqsave(ms->host->host_lock, flags);
+	while(ms->phase != idle) {
+		spin_unlock_irqrestore(ms->host->host_lock, flags);
+		msleep(10);
+		spin_lock_irqsave(ms->host->host_lock, flags);
+	}
+	ms->phase = sleeping;
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+	disable_irq(ms->meshintr);
+	set_mesh_power(ms, 0);
+
+	mdev->ofdev.dev.power.power_state = state;
+
+	return 0;
+}
+
+static int mesh_resume(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	unsigned long flags;
+
+	if (mdev->ofdev.dev.power.power_state == 0)
+		return 0;
+
+	set_mesh_power(ms, 1);
+	mesh_init(ms);
+	spin_lock_irqsave(ms->host->host_lock, flags);
+	mesh_start(ms);
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+	enable_irq(ms->meshintr);
+	scsi_unblock_requests(ms->host);
+
+	mdev->ofdev.dev.power.power_state = 0;
+
+	return 0;
+}
+
+#endif /* CONFIG_PM */
+
+/*
+ * If we leave drives set for synchronous transfers (especially
+ * CDROMs), and reboot to MacOS, it gets confused, poor thing.
+ * So, on reboot we reset the SCSI bus.
+ */
+static int mesh_shutdown(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	volatile struct mesh_regs __iomem *mr;
+	unsigned long flags;
+
+       	printk(KERN_INFO "resetting MESH scsi bus(es)\n");
+	spin_lock_irqsave(ms->host->host_lock, flags);
+       	mr = ms->mesh;
+	out_8(&mr->intr_mask, 0);
+	out_8(&mr->interrupt, INT_ERROR | INT_EXCEPTION | INT_CMDDONE);
+	out_8(&mr->bus_status1, BS1_RST);
+	mesh_flush_io(mr);
+	udelay(30);
+	out_8(&mr->bus_status1, 0);
+	spin_unlock_irqrestore(ms->host->host_lock, flags);
+
+	return 0;
+}
+
+static struct scsi_host_template mesh_template = {
+	.proc_name			= "mesh",
+	.name				= "MESH",
+	.queuecommand			= mesh_queue,
+	.eh_abort_handler		= mesh_abort,
+	.eh_host_reset_handler		= mesh_host_reset,
+	.can_queue			= 20,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 2,
+	.use_clustering			= DISABLE_CLUSTERING,
+};
+
+static int mesh_probe(struct macio_dev *mdev, const struct of_match *match)
+{
+	struct device_node *mesh = macio_get_of_node(mdev);
+	struct pci_dev* pdev = macio_get_pci_dev(mdev);
+	int tgt, *cfp, minper;
+	struct mesh_state *ms;
+	struct Scsi_Host *mesh_host;
+	void *dma_cmd_space;
+	dma_addr_t dma_cmd_bus;
+
+	switch (mdev->bus->chip->type) {
+	case macio_heathrow:
+	case macio_gatwick:
+	case macio_paddington:
+		use_active_neg = 0;
+		break;
+	default:
+		use_active_neg = SEQ_ACTIVE_NEG;
+	}
+
+	if (macio_resource_count(mdev) != 2 || macio_irq_count(mdev) != 2) {
+       		printk(KERN_ERR "mesh: expected 2 addrs and 2 intrs"
+	       	       " (got %d,%d)\n", mesh->n_addrs, mesh->n_intrs);
+		return -ENODEV;
+	}
+
+	if (macio_request_resources(mdev, "mesh") != 0) {
+       		printk(KERN_ERR "mesh: unable to request memory resources");
+		return -EBUSY;
+	}
+       	mesh_host = scsi_host_alloc(&mesh_template, sizeof(struct mesh_state));
+	if (mesh_host == NULL) {
+		printk(KERN_ERR "mesh: couldn't register host");
+		goto out_release;
+	}
+	
+	/* Old junk for root discovery, that will die ultimately */
+#if !defined(MODULE)
+       	note_scsi_host(mesh, mesh_host);
+#endif
+
+	mesh_host->base = macio_resource_start(mdev, 0);
+	mesh_host->irq = macio_irq(mdev, 0);
+       	ms = (struct mesh_state *) mesh_host->hostdata;
+	macio_set_drvdata(mdev, ms);
+	ms->host = mesh_host;
+	ms->mdev = mdev;
+	ms->pdev = pdev;
+	
+	ms->mesh = ioremap(macio_resource_start(mdev, 0), 0x1000);
+	if (ms->mesh == NULL) {
+		printk(KERN_ERR "mesh: can't map registers\n");
+		goto out_free;
+	}		
+	ms->dma = ioremap(macio_resource_start(mdev, 1), 0x1000);
+	if (ms->dma == NULL) {
+		printk(KERN_ERR "mesh: can't map registers\n");
+		iounmap(ms->mesh);
+		goto out_free;
+	}
+
+       	ms->meshintr = macio_irq(mdev, 0);
+       	ms->dmaintr = macio_irq(mdev, 1);
+
+       	/* Space for dma command list: +1 for stop command,
+       	 * +1 to allow for aligning.
+	 */
+	ms->dma_cmd_size = (mesh_host->sg_tablesize + 2) * sizeof(struct dbdma_cmd);
+
+	/* We use the PCI APIs for now until the generic one gets fixed
+	 * enough or until we get some macio-specific versions
+	 */
+	dma_cmd_space = pci_alloc_consistent(macio_get_pci_dev(mdev),
+					     ms->dma_cmd_size,
+					     &dma_cmd_bus);
+	if (dma_cmd_space == NULL) {
+		printk(KERN_ERR "mesh: can't allocate DMA table\n");
+		goto out_unmap;
+	}
+	memset(dma_cmd_space, 0, ms->dma_cmd_size);
+
+	ms->dma_cmds = (struct dbdma_cmd *) DBDMA_ALIGN(dma_cmd_space);
+       	ms->dma_cmd_space = dma_cmd_space;
+	ms->dma_cmd_bus = dma_cmd_bus + ((unsigned long)ms->dma_cmds)
+		- (unsigned long)dma_cmd_space;
+	ms->current_req = NULL;
+       	for (tgt = 0; tgt < 8; ++tgt) {
+	       	ms->tgts[tgt].sdtr_state = do_sdtr;
+	       	ms->tgts[tgt].sync_params = ASYNC_PARAMS;
+	       	ms->tgts[tgt].current_req = NULL;
+       	}
+
+	if ((cfp = (int *) get_property(mesh, "clock-frequency", NULL)))
+       		ms->clk_freq = *cfp;
+	else {
+       		printk(KERN_INFO "mesh: assuming 50MHz clock frequency\n");
+	       	ms->clk_freq = 50000000;
+       	}
+
+       	/* The maximum sync rate is clock / 5; increase
+       	 * mesh_sync_period if necessary.
+	 */
+	minper = 1000000000 / (ms->clk_freq / 5); /* ns */
+	if (mesh_sync_period < minper)
+		mesh_sync_period = minper;
+
+	/* Power up the chip */
+	set_mesh_power(ms, 1);
+
+	/* Set it up */
+       	mesh_init(ms);
+
+	/* XXX FIXME: error should be fatal */
+       	if (request_irq(ms->meshintr, do_mesh_interrupt, 0, "MESH", ms))
+	       	printk(KERN_ERR "MESH: can't get irq %d\n", ms->meshintr);
+
+	/* XXX FIXME: handle failure */
+	scsi_add_host(mesh_host, &mdev->ofdev.dev);
+	scsi_scan_host(mesh_host);
+
+	return 0;
+
+out_unmap:
+	iounmap(ms->dma);
+	iounmap(ms->mesh);
+out_free:
+	scsi_host_put(mesh_host);
+out_release:
+	macio_release_resources(mdev);
+
+	return -ENODEV;
+}
+
+static int mesh_remove(struct macio_dev *mdev)
+{
+	struct mesh_state *ms = (struct mesh_state *)macio_get_drvdata(mdev);
+	struct Scsi_Host *mesh_host = ms->host;
+
+	scsi_remove_host(mesh_host);
+
+	free_irq(ms->meshintr, ms);
+
+	/* Reset scsi bus */
+	mesh_shutdown(mdev);
+
+	/* Shut down chip & termination */
+	set_mesh_power(ms, 0);
+
+	/* Unmap registers & dma controller */
+	iounmap(ms->mesh);
+       	iounmap(ms->dma);
+
+	/* Free DMA commands memory */
+	pci_free_consistent(macio_get_pci_dev(mdev), ms->dma_cmd_size,
+			  ms->dma_cmd_space, ms->dma_cmd_bus);
+
+	/* Release memory resources */
+	macio_release_resources(mdev);
+
+	scsi_host_put(mesh_host);
+
+	return 0;
+}
+
+
+static struct of_match mesh_match[] = 
+{
+	{
+	.name 		= "mesh",
+	.type		= OF_ANY_MATCH,
+	.compatible	= OF_ANY_MATCH
+	},
+	{
+	.name 		= OF_ANY_MATCH,
+	.type		= "scsi",
+	.compatible	= "chrp,mesh0"
+	},
+	{},
+};
+
+static struct macio_driver mesh_driver = 
+{
+	.name 		= "mesh",
+	.match_table	= mesh_match,
+	.probe		= mesh_probe,
+	.remove		= mesh_remove,
+	.shutdown	= mesh_shutdown,
+#ifdef CONFIG_PM
+	.suspend	= mesh_suspend,
+	.resume		= mesh_resume,
+#endif
+};
+
+
+static int __init init_mesh(void)
+{
+
+	/* Calculate sync rate from module parameters */
+	if (sync_rate > 10)
+		sync_rate = 10;
+	if (sync_rate > 0) {
+		printk(KERN_INFO "mesh: configured for synchronous %d MB/s\n", sync_rate);
+		mesh_sync_period = 1000 / sync_rate;	/* ns */
+		mesh_sync_offset = 15;
+	} else
+		printk(KERN_INFO "mesh: configured for asynchronous\n");
+
+	return macio_register_driver(&mesh_driver);
+}
+
+static void __exit exit_mesh(void)
+{
+	return macio_unregister_driver(&mesh_driver);
+}
+
+module_init(init_mesh);
+module_exit(exit_mesh);
diff --git a/drivers/scsi/mesh.h b/drivers/scsi/mesh.h
new file mode 100644
index 0000000..4fdb81f
--- /dev/null
+++ b/drivers/scsi/mesh.h
@@ -0,0 +1,127 @@
+/*
+ * mesh.h: definitions for the driver for the MESH SCSI bus adaptor
+ * (Macintosh Enhanced SCSI Hardware) found on Power Macintosh computers.
+ *
+ * Copyright (C) 1996 Paul Mackerras.
+ */
+#ifndef _MESH_H
+#define _MESH_H
+
+/*
+ * Registers in the MESH controller.
+ */
+
+struct mesh_regs {
+	unsigned char	count_lo;
+	char pad0[15];
+	unsigned char	count_hi;
+	char pad1[15];
+	unsigned char	fifo;
+	char pad2[15];
+	unsigned char	sequence;
+	char pad3[15];
+	unsigned char	bus_status0;
+	char pad4[15];
+	unsigned char	bus_status1;
+	char pad5[15];
+	unsigned char	fifo_count;
+	char pad6[15];
+	unsigned char	exception;
+	char pad7[15];
+	unsigned char	error;
+	char pad8[15];
+	unsigned char	intr_mask;
+	char pad9[15];
+	unsigned char	interrupt;
+	char pad10[15];
+	unsigned char	source_id;
+	char pad11[15];
+	unsigned char	dest_id;
+	char pad12[15];
+	unsigned char	sync_params;
+	char pad13[15];
+	unsigned char	mesh_id;
+	char pad14[15];
+	unsigned char	sel_timeout;
+	char pad15[15];
+};
+
+/* Bits in the sequence register. */
+#define SEQ_DMA_MODE	0x80	/* use DMA for data transfer */
+#define SEQ_TARGET	0x40	/* put the controller into target mode */
+#define SEQ_ATN		0x20	/* assert ATN signal */
+#define SEQ_ACTIVE_NEG	0x10	/* use active negation on REQ/ACK */
+#define SEQ_CMD		0x0f	/* command bits: */
+#define SEQ_ARBITRATE	1	/*  get the bus */
+#define SEQ_SELECT	2	/*  select a target */
+#define SEQ_COMMAND	3	/*  send a command */
+#define SEQ_STATUS	4	/*  receive status */
+#define SEQ_DATAOUT	5	/*  send data */
+#define SEQ_DATAIN	6	/*  receive data */
+#define SEQ_MSGOUT	7	/*  send a message */
+#define SEQ_MSGIN	8	/*  receive a message */
+#define SEQ_BUSFREE	9	/*  look for bus free */
+#define SEQ_ENBPARITY	0x0a	/*  enable parity checking */
+#define SEQ_DISPARITY	0x0b	/*  disable parity checking */
+#define SEQ_ENBRESEL	0x0c	/*  enable reselection */
+#define SEQ_DISRESEL	0x0d	/*  disable reselection */
+#define SEQ_RESETMESH	0x0e	/*  reset the controller */
+#define SEQ_FLUSHFIFO	0x0f	/*  clear out the FIFO */
+
+/* Bits in the bus_status0 and bus_status1 registers:
+   these correspond directly to the SCSI bus control signals. */
+#define BS0_REQ		0x20
+#define BS0_ACK		0x10
+#define BS0_ATN		0x08
+#define BS0_MSG		0x04
+#define BS0_CD		0x02
+#define BS0_IO		0x01
+#define BS1_RST		0x80
+#define BS1_BSY		0x40
+#define BS1_SEL		0x20
+
+/* Bus phases defined by the bits in bus_status0 */
+#define BS0_PHASE	(BS0_MSG+BS0_CD+BS0_IO)
+#define BP_DATAOUT	0
+#define BP_DATAIN	BS0_IO
+#define BP_COMMAND	BS0_CD
+#define BP_STATUS	(BS0_CD+BS0_IO)
+#define BP_MSGOUT	(BS0_MSG+BS0_CD)
+#define BP_MSGIN	(BS0_MSG+BS0_CD+BS0_IO)
+
+/* Bits in the exception register. */
+#define EXC_SELWATN	0x20	/* (as target) we were selected with ATN */
+#define EXC_SELECTED	0x10	/* (as target) we were selected w/o ATN */
+#define EXC_RESELECTED	0x08	/* (as initiator) we were reselected */
+#define EXC_ARBLOST	0x04	/* we lost arbitration */
+#define EXC_PHASEMM	0x02	/* SCSI phase mismatch */
+#define EXC_SELTO	0x01	/* selection timeout */
+
+/* Bits in the error register */
+#define ERR_UNEXPDISC	0x40	/* target unexpectedly disconnected */
+#define ERR_SCSIRESET	0x20	/* SCSI bus got reset on us */
+#define ERR_SEQERR	0x10	/* we did something the chip didn't like */
+#define ERR_PARITY	0x01	/* parity error was detected */
+
+/* Bits in the interrupt and intr_mask registers */
+#define INT_ERROR	0x04	/* error interrupt */
+#define INT_EXCEPTION	0x02	/* exception interrupt */
+#define INT_CMDDONE	0x01	/* command done interrupt */
+
+/* Fields in the sync_params register */
+#define SYNC_OFF(x)	((x) >> 4)	/* offset field */
+#define SYNC_PER(x)	((x) & 0xf)	/* period field */
+#define SYNC_PARAMS(o, p)	(((o) << 4) | (p))
+#define ASYNC_PARAMS	2	/* sync_params value for async xfers */
+
+/*
+ * Assuming a clock frequency of 50MHz:
+ *
+ * The transfer period with SYNC_PER(sync_params) == x
+ * is (x + 2) * 40ns, except that x == 0 gives 100ns.
+ *
+ * The units of the sel_timeout register are 10ms.
+ */
+
+
+#endif /* _MESH_H */
diff --git a/drivers/scsi/mvme147.c b/drivers/scsi/mvme147.c
new file mode 100644
index 0000000..e73b33f
--- /dev/null
+++ b/drivers/scsi/mvme147.c
@@ -0,0 +1,155 @@
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mvme147hw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "wd33c93.h"
+#include "mvme147.h"
+
+#include<linux/stat.h>
+
+#define HDATA(ptr) ((struct WD33C93_hostdata *)((ptr)->hostdata))
+
+static struct Scsi_Host *mvme147_host = NULL;
+
+static irqreturn_t mvme147_intr (int irq, void *dummy, struct pt_regs *fp)
+{
+    if (irq == MVME147_IRQ_SCSI_PORT)
+	wd33c93_intr (mvme147_host);
+    else
+	m147_pcc->dma_intr = 0x89;	/* Ack and enable ints */
+    return IRQ_HANDLED;
+}
+
+static int dma_setup (Scsi_Cmnd *cmd, int dir_in)
+{
+    unsigned char flags = 0x01;
+    unsigned long addr = virt_to_bus(cmd->SCp.ptr);
+
+    /* setup dma direction */
+    if (!dir_in)
+	flags |= 0x04;
+
+    /* remember direction */
+    HDATA(mvme147_host)->dma_dir = dir_in;
+
+    if (dir_in)
+  	/* invalidate any cache */
+	cache_clear (addr, cmd->SCp.this_residual);
+    else
+	/* push any dirty cache */
+	cache_push (addr, cmd->SCp.this_residual);
+
+    /* start DMA */
+    m147_pcc->dma_bcr   = cmd->SCp.this_residual | (1<<24);
+    m147_pcc->dma_dadr  = addr;
+    m147_pcc->dma_cntrl = flags;
+
+    /* return success */
+    return 0;
+}
+
+static void dma_stop (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		      int status)
+{
+    m147_pcc->dma_cntrl = 0;
+}
+
+int mvme147_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    wd33c93_regs regs;
+
+    if (!MACH_IS_MVME147 || called)
+	return 0;
+    called++;
+
+    tpnt->proc_name = "MVME147";
+    tpnt->proc_info = &wd33c93_proc_info;
+
+    mvme147_host = scsi_register (tpnt, sizeof(struct WD33C93_hostdata));
+    if (!mvme147_host)
+	    goto err_out;
+
+    mvme147_host->base = 0xfffe4000;
+    mvme147_host->irq = MVME147_IRQ_SCSI_PORT;
+    regs.SASR = (volatile unsigned char *)0xfffe4000;
+    regs.SCMD = (volatile unsigned char *)0xfffe4001;
+    wd33c93_init(mvme147_host, regs, dma_setup, dma_stop, WD33C93_FS_8_10);
+
+    if (request_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr, 0, "MVME147 SCSI PORT", mvme147_intr))
+	    goto err_unregister;
+    if (request_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr, 0, "MVME147 SCSI DMA", mvme147_intr))
+	    goto err_free_irq;
+#if 0	/* Disabled; causes problems booting */
+    m147_pcc->scsi_interrupt = 0x10;	/* Assert SCSI bus reset */
+    udelay(100);
+    m147_pcc->scsi_interrupt = 0x00;	/* Negate SCSI bus reset */
+    udelay(2000);
+    m147_pcc->scsi_interrupt = 0x40;	/* Clear bus reset interrupt */
+#endif
+    m147_pcc->scsi_interrupt = 0x09;	/* Enable interrupt */
+
+    m147_pcc->dma_cntrl = 0x00;		/* ensure DMA is stopped */
+    m147_pcc->dma_intr = 0x89;		/* Ack and enable ints */
+
+    return 1;
+
+ err_free_irq:
+    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+ err_unregister:
+    wd33c93_release();
+    scsi_unregister(mvme147_host);
+ err_out:
+    return 0;
+}
+
+static int mvme147_bus_reset(Scsi_Cmnd *cmd)
+{
+	/* FIXME perform bus-specific reset */
+	wd33c93_host_reset(cmd);
+	return SUCCESS;
+}
+
+#define HOSTS_C
+
+#include "mvme147.h"
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "MVME147",
+	.name			= "MVME147 built-in SCSI",
+	.detect			= mvme147_detect,
+	.release		= mvme147_release,
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_bus_reset_handler	= mvme147_bus_reset,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+int mvme147_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+    /* XXX Make sure DMA is stopped! */
+    wd33c93_release();
+    free_irq(MVME147_IRQ_SCSI_PORT, mvme147_intr);
+    free_irq(MVME147_IRQ_SCSI_DMA, mvme147_intr);
+#endif
+    return 1;
+}
diff --git a/drivers/scsi/mvme147.h b/drivers/scsi/mvme147.h
new file mode 100644
index 0000000..d8903f0
--- /dev/null
+++ b/drivers/scsi/mvme147.h
@@ -0,0 +1,28 @@
+#ifndef MVME147_H
+
+/* $Id: mvme147.h,v 1.4 1997/01/19 23:07:10 davem Exp $
+ *
+ * Header file for the MVME147 built-in SCSI controller for Linux
+ *
+ * Written and (C) 1993, Hamish Macdonald, see mvme147.c for more info
+ *
+ */
+
+#include <linux/types.h>
+
+int mvme147_detect(Scsi_Host_Template *);
+int mvme147_release(struct Scsi_Host *);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_reset(Scsi_Cmnd *, unsigned int);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#endif /* MVME147_H */
diff --git a/drivers/scsi/mvme16x.c b/drivers/scsi/mvme16x.c
new file mode 100644
index 0000000..b2d8d8e
--- /dev/null
+++ b/drivers/scsi/mvme16x.c
@@ -0,0 +1,80 @@
+/*
+ * Detection routine for the NCR53c710 based MVME16x SCSI Controllers for Linux.
+ *
+ * Based on work by Alan Hourihane
+ */
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/mvme16xhw.h>
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "53c7xx.h"
+#include "mvme16x.h"
+
+#include<linux/stat.h>
+
+
+int mvme16x_scsi_detect(Scsi_Host_Template *tpnt)
+{
+    static unsigned char called = 0;
+    int clock;
+    long long options;
+
+    if (!MACH_IS_MVME16x)
+		return 0;
+    if (mvme16x_config & MVME16x_CONFIG_NO_SCSICHIP) {
+	printk ("SCSI detection disabled, SCSI chip not present\n");
+	return 0;
+    }
+    if (called)
+	return 0;
+
+    tpnt->proc_name = "MVME16x";
+
+    options = OPTION_MEMORY_MAPPED|OPTION_DEBUG_TEST1|OPTION_INTFLY|OPTION_SYNCHRONOUS|OPTION_ALWAYS_SYNCHRONOUS|OPTION_DISCONNECT;
+
+    clock = 66000000;	/* 66MHz SCSI Clock */
+
+    ncr53c7xx_init(tpnt, 0, 710, (unsigned long)0xfff47000,
+			0, MVME16x_IRQ_SCSI, DMA_NONE,
+			options, clock);
+    called = 1;
+    return 1;
+}
+
+static int mvme16x_scsi_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name			= "MVME16x NCR53c710 SCSI",
+	.detect			= mvme16x_scsi_detect,
+	.release		= mvme16x_scsi_release,
+	.queuecommand		= NCR53c7xx_queue_command,
+	.abort			= NCR53c7xx_abort,
+	.reset			= NCR53c7xx_reset,
+	.can_queue		= 24,
+	.this_id		= 7,
+	.sg_tablesize		= 63,
+	.cmd_per_lun		= 3,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/mvme16x.h b/drivers/scsi/mvme16x.h
new file mode 100644
index 0000000..25173c8
--- /dev/null
+++ b/drivers/scsi/mvme16x.h
@@ -0,0 +1,24 @@
+#ifndef MVME16x_SCSI_H
+#define MVME16x_SCSI_H
+
+#include <linux/types.h>
+
+int mvme16x_scsi_detect(Scsi_Host_Template *);
+const char *NCR53c7x0_info(void);
+int NCR53c7xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int NCR53c7xx_abort(Scsi_Cmnd *);
+int NCR53c7x0_release (struct Scsi_Host *);
+int NCR53c7xx_reset(Scsi_Cmnd *, unsigned int);
+void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 3
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 24
+#endif
+
+#include <scsi/scsicam.h>
+
+#endif /* MVME16x_SCSI_H */
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
new file mode 100644
index 0000000..7ae1323
--- /dev/null
+++ b/drivers/scsi/ncr53c8xx.c
@@ -0,0 +1,7986 @@
+/******************************************************************************
+**  Device driver for the PCI-SCSI NCR538XX controller family.
+**
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
+**  and is currently maintained by
+**
+**          Gerard Roudier              <groudier@free.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**  And has been ported to NetBSD by
+**          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>
+**
+**-----------------------------------------------------------------------------
+**
+**                     Brief history
+**
+**  December 10 1995 by Gerard Roudier:
+**     Initial port to Linux.
+**
+**  June 23 1996 by Gerard Roudier:
+**     Support for 64 bits architectures (Alpha).
+**
+**  November 30 1996 by Gerard Roudier:
+**     Support for Fast-20 scsi.
+**     Support for large DMA fifo and 128 dwords bursting.
+**
+**  February 27 1997 by Gerard Roudier:
+**     Support for Fast-40 scsi.
+**     Support for on-Board RAM.
+**
+**  May 3 1997 by Gerard Roudier:
+**     Full support for scsi scripts instructions pre-fetching.
+**
+**  May 19 1997 by Richard Waltham <dormouse@farsrobt.demon.co.uk>:
+**     Support for NvRAM detection and reading.
+**
+**  August 18 1997 by Cort <cort@cs.nmt.edu>:
+**     Support for Power/PC (Big Endian).
+**
+**  June 20 1998 by Gerard Roudier
+**     Support for up to 64 tags per lun.
+**     O(1) everywhere (C and SCRIPTS) for normal cases.
+**     Low PCI traffic for command handling when on-chip RAM is present.
+**     Aggressive SCSI SCRIPTS optimizations.
+**
+*******************************************************************************
+*/
+
+/*
+**	Supported SCSI-II features:
+**	    Synchronous negotiation
+**	    Wide negotiation        (depends on the NCR Chip)
+**	    Enable disconnection
+**	    Tagged command queuing
+**	    Parity checking
+**	    Etc...
+**
+**	Supported NCR/SYMBIOS chips:
+**		53C720		(Wide,   Fast SCSI-2, intfly problems)
+*/
+
+/* Name and version of the driver */
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx-3.4.3g"
+
+#define SCSI_NCR_DEBUG_FLAGS	(0)
+
+/*==========================================================
+**
+**      Include files
+**
+**==========================================================
+*/
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/time.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "ncr53c8xx.h"
+
+#define NAME53C			"ncr53c"
+#define NAME53C8XX		"ncr53c8xx"
+
+#include "sym53c8xx_comm.h"
+
+
+/*==========================================================
+**
+**	The CCB done queue uses an array of CCB virtual 
+**	addresses. Empty entries are flagged using the bogus 
+**	virtual address 0xffffffff.
+**
+**	Since PCI ensures that only aligned DWORDs are accessed 
+**	atomically, 64 bit little-endian architecture requires 
+**	to test the high order DWORD of the entry to determine 
+**	if it is empty or valid.
+**
+**	BTW, I will make things differently as soon as I will 
+**	have a better idea, but this is simple and should work.
+**
+**==========================================================
+*/
+ 
+#define SCSI_NCR_CCB_DONE_SUPPORT
+#ifdef  SCSI_NCR_CCB_DONE_SUPPORT
+
+#define MAX_DONE 24
+#define CCB_DONE_EMPTY 0xffffffffUL
+
+/* All 32 bit architectures */
+#if BITS_PER_LONG == 32
+#define CCB_DONE_VALID(cp)  (((u_long) cp) != CCB_DONE_EMPTY)
+
+/* All > 32 bit (64 bit) architectures regardless endian-ness */
+#else
+#define CCB_DONE_VALID(cp)  \
+	((((u_long) cp) & 0xffffffff00000000ul) && 	\
+	 (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY)
+#endif
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+
+/*==========================================================
+**
+**	Configuration and Debugging
+**
+**==========================================================
+*/
+
+/*
+**    SCSI address of this device.
+**    The boot routines should have set it.
+**    If not, use this.
+*/
+
+#ifndef SCSI_NCR_MYADDR
+#define SCSI_NCR_MYADDR      (7)
+#endif
+
+/*
+**    The maximum number of tags per logic unit.
+**    Used only for disk devices that support tags.
+*/
+
+#ifndef SCSI_NCR_MAX_TAGS
+#define SCSI_NCR_MAX_TAGS    (8)
+#endif
+
+/*
+**    TAGS are actually limited to 64 tags/lun.
+**    We need to deal with power of 2, for alignment constraints.
+*/
+#if	SCSI_NCR_MAX_TAGS > 64
+#define	MAX_TAGS (64)
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
+#endif
+
+#define NO_TAG	(255)
+
+/*
+**	Choose appropriate type for tag bitmap.
+*/
+#if	MAX_TAGS > 32
+typedef u64 tagmap_t;
+#else
+typedef u32 tagmap_t;
+#endif
+
+/*
+**    Number of targets supported by the driver.
+**    n permits target numbers 0..n-1.
+**    Default is 16, meaning targets #0..#15.
+**    #7 .. is myself.
+*/
+
+#ifdef SCSI_NCR_MAX_TARGET
+#define MAX_TARGET  (SCSI_NCR_MAX_TARGET)
+#else
+#define MAX_TARGET  (16)
+#endif
+
+/*
+**    Number of logic units supported by the driver.
+**    n enables logic unit numbers 0..n-1.
+**    The common SCSI devices require only
+**    one lun, so take 1 as the default.
+*/
+
+#ifdef SCSI_NCR_MAX_LUN
+#define MAX_LUN    SCSI_NCR_MAX_LUN
+#else
+#define MAX_LUN    (1)
+#endif
+
+/*
+**    Asynchronous pre-scaler (ns). Shall be 40
+*/
+ 
+#ifndef SCSI_NCR_MIN_ASYNC
+#define SCSI_NCR_MIN_ASYNC (40)
+#endif
+
+/*
+**    The maximum number of jobs scheduled for starting.
+**    There should be one slot per target, and one slot
+**    for each tag of each target in use.
+**    The calculation below is actually quite silly ...
+*/
+
+#ifdef SCSI_NCR_CAN_QUEUE
+#define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
+#else
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+**   We limit the max number of pending IO to 250.
+**   since we donnot want to allocate more than 1 
+**   PAGE for 'scripth'.
+*/
+#if	MAX_START > 250
+#undef	MAX_START
+#define	MAX_START 250
+#endif
+
+/*
+**    The maximum number of segments a transfer is split into.
+**    We support up to 127 segments for both read and write.
+**    The data scripts are broken into 2 sub-scripts.
+**    80 (MAX_SCATTERL) segments are moved from a sub-script
+**    in on-chip RAM. This makes data transfers shorter than 
+**    80k (assuming 1k fs) as fast as possible.
+*/
+
+#define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
+
+#if (MAX_SCATTER > 80)
+#define MAX_SCATTERL	80
+#define	MAX_SCATTERH	(MAX_SCATTER - MAX_SCATTERL)
+#else
+#define MAX_SCATTERL	(MAX_SCATTER-1)
+#define	MAX_SCATTERH	1
+#endif
+
+/*
+**	other
+*/
+
+#define NCR_SNOOP_TIMEOUT (1000000)
+
+/*
+**	Other definitions
+*/
+
+#define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f))
+
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+/*==========================================================
+**
+**	Command control block states.
+**
+**==========================================================
+*/
+
+#define HS_IDLE		(0)
+#define HS_BUSY		(1)
+#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
+#define HS_DISCONNECT	(3)	/* Disconnected by target */
+
+#define HS_DONEMASK	(0x80)
+#define HS_COMPLETE	(4|HS_DONEMASK)
+#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
+#define HS_RESET	(6|HS_DONEMASK)	/* SCSI reset	          */
+#define HS_ABORTED	(7|HS_DONEMASK)	/* Transfer aborted       */
+#define HS_TIMEOUT	(8|HS_DONEMASK)	/* Software timeout       */
+#define HS_FAIL		(9|HS_DONEMASK)	/* SCSI or PCI bus errors */
+#define HS_UNEXPECTED	(10|HS_DONEMASK)/* Unexpected disconnect  */
+
+/*
+**	Invalid host status values used by the SCRIPTS processor 
+**	when the nexus is not fully identified.
+**	Shall never appear in a CCB.
+*/
+
+#define HS_INVALMASK	(0x40)
+#define	HS_SELECTING	(0|HS_INVALMASK)
+#define	HS_IN_RESELECT	(1|HS_INVALMASK)
+#define	HS_STARTING	(2|HS_INVALMASK)
+
+/*
+**	Flags set by the SCRIPT processor for commands 
+**	that have been skipped.
+*/
+#define HS_SKIPMASK	(0x20)
+
+/*==========================================================
+**
+**	Software Interrupt Codes
+**
+**==========================================================
+*/
+
+#define	SIR_BAD_STATUS		(1)
+#define	SIR_XXXXXXXXXX		(2)
+#define	SIR_NEGO_SYNC		(3)
+#define	SIR_NEGO_WIDE		(4)
+#define	SIR_NEGO_FAILED		(5)
+#define	SIR_NEGO_PROTO		(6)
+#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_REJECT_SENT		(8)
+#define	SIR_IGN_RESIDUE		(9)
+#define	SIR_MISSING_SAVE	(10)
+#define	SIR_RESEL_NO_MSG_IN	(11)
+#define	SIR_RESEL_NO_IDENTIFY	(12)
+#define	SIR_RESEL_BAD_LUN	(13)
+#define	SIR_RESEL_BAD_TARGET	(14)
+#define	SIR_RESEL_BAD_I_T_L	(15)
+#define	SIR_RESEL_BAD_I_T_L_Q	(16)
+#define	SIR_DONE_OVERFLOW	(17)
+#define	SIR_INTFLY		(18)
+#define	SIR_MAX			(18)
+
+/*==========================================================
+**
+**	Extended error codes.
+**	xerr_status field of struct ccb.
+**
+**==========================================================
+*/
+
+#define	XE_OK		(0)
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
+
+/*==========================================================
+**
+**	Negotiation status.
+**	nego_status field	of struct ccb.
+**
+**==========================================================
+*/
+
+#define NS_NOCHANGE	(0)
+#define NS_SYNC		(1)
+#define NS_WIDE		(2)
+#define NS_PPR		(4)
+
+/*==========================================================
+**
+**	Misc.
+**
+**==========================================================
+*/
+
+#define CCB_MAGIC	(0xf2691ad2)
+
+/*==========================================================
+**
+**	Declaration of structs.
+**
+**==========================================================
+*/
+
+static struct scsi_transport_template *ncr53c8xx_transport_template = NULL;
+
+struct tcb;
+struct lcb;
+struct ccb;
+struct ncb;
+struct script;
+
+struct link {
+	ncrcmd	l_cmd;
+	ncrcmd	l_paddr;
+};
+
+struct	usrcmd {
+	u_long	target;
+	u_long	lun;
+	u_long	data;
+	u_long	cmd;
+};
+
+#define UC_SETSYNC      10
+#define UC_SETTAGS	11
+#define UC_SETDEBUG	12
+#define UC_SETORDER	13
+#define UC_SETWIDE	14
+#define UC_SETFLAG	15
+#define UC_SETVERBOSE	17
+
+#define	UF_TRACE	(0x01)
+#define	UF_NODISC	(0x02)
+#define	UF_NOSCAN	(0x04)
+
+/*========================================================================
+**
+**	Declaration of structs:		target control block
+**
+**========================================================================
+*/
+struct tcb {
+	/*----------------------------------------------------------------
+	**	During reselection the ncr jumps to this point with SFBR 
+	**	set to the encoded target number with bit 7 set.
+	**	if it's not this target, jump to the next.
+	**
+	**	JUMP  IF (SFBR != #target#), @(next tcb)
+	**----------------------------------------------------------------
+	*/
+	struct link   jump_tcb;
+
+	/*----------------------------------------------------------------
+	**	Load the actual values for the sxfer and the scntl3
+	**	register (sync/wide mode).
+	**
+	**	SCR_COPY (1), @(sval field of this tcb), @(sxfer  register)
+	**	SCR_COPY (1), @(wval field of this tcb), @(scntl3 register)
+	**----------------------------------------------------------------
+	*/
+	ncrcmd	getscr[6];
+
+	/*----------------------------------------------------------------
+	**	Get the IDENTIFY message and load the LUN to SFBR.
+	**
+	**	CALL, <RESEL_LUN>
+	**----------------------------------------------------------------
+	*/
+	struct link   call_lun;
+
+	/*----------------------------------------------------------------
+	**	Now look for the right lun.
+	**
+	**	For i = 0 to 3
+	**		SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i)
+	**
+	**	Recent chips will prefetch the 4 JUMPS using only 1 burst.
+	**	It is kind of hashcoding.
+	**----------------------------------------------------------------
+	*/
+	struct link     jump_lcb[4];	/* JUMPs for reselection	*/
+	struct lcb *	lp[MAX_LUN];	/* The lcb's of this tcb	*/
+
+	/*----------------------------------------------------------------
+	**	Pointer to the ccb used for negotiation.
+	**	Prevent from starting a negotiation for all queued commands 
+	**	when tagged command queuing is enabled.
+	**----------------------------------------------------------------
+	*/
+	struct ccb *   nego_cp;
+
+	/*----------------------------------------------------------------
+	**	statistical data
+	**----------------------------------------------------------------
+	*/
+	u_long	transfers;
+	u_long	bytes;
+
+	/*----------------------------------------------------------------
+	**	negotiation of wide and synch transfer and device quirks.
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_BIG_ENDIAN
+/*0*/	u16	period;
+/*2*/	u_char	sval;
+/*3*/	u_char	minsync;
+/*0*/	u_char	wval;
+/*1*/	u_char	widedone;
+/*2*/	u_char	quirks;
+/*3*/	u_char	maxoffs;
+#else
+/*0*/	u_char	minsync;
+/*1*/	u_char	sval;
+/*2*/	u16	period;
+/*0*/	u_char	maxoffs;
+/*1*/	u_char	quirks;
+/*2*/	u_char	widedone;
+/*3*/	u_char	wval;
+#endif
+
+	/* User settable limits and options.  */
+	u_char	usrsync;
+	u_char	usrwide;
+	u_char	usrtags;
+	u_char	usrflag;
+	struct scsi_target *starget;
+};
+
+/*========================================================================
+**
+**	Declaration of structs:		lun control block
+**
+**========================================================================
+*/
+struct lcb {
+	/*----------------------------------------------------------------
+	**	During reselection the ncr jumps to this point
+	**	with SFBR set to the "Identify" message.
+	**	if it's not this lun, jump to the next.
+	**
+	**	JUMP  IF (SFBR != #lun#), @(next lcb of this target)
+	**
+	**	It is this lun. Load TEMP with the nexus jumps table 
+	**	address and jump to RESEL_TAG (or RESEL_NOTAG).
+	**
+	**		SCR_COPY (4), p_jump_ccb, TEMP,
+	**		SCR_JUMP, <RESEL_TAG>
+	**----------------------------------------------------------------
+	*/
+	struct link	jump_lcb;
+	ncrcmd		load_jump_ccb[3];
+	struct link	jump_tag;
+	ncrcmd		p_jump_ccb;	/* Jump table bus address	*/
+
+	/*----------------------------------------------------------------
+	**	Jump table used by the script processor to directly jump 
+	**	to the CCB corresponding to the reselected nexus.
+	**	Address is allocated on 256 bytes boundary in order to 
+	**	allow 8 bit calculation of the tag jump entry for up to 
+	**	64 possible tags.
+	**----------------------------------------------------------------
+	*/
+	u32		jump_ccb_0;	/* Default table if no tags	*/
+	u32		*jump_ccb;	/* Virtual address		*/
+
+	/*----------------------------------------------------------------
+	**	CCB queue management.
+	**----------------------------------------------------------------
+	*/
+	struct list_head free_ccbq;	/* Queue of available CCBs	*/
+	struct list_head busy_ccbq;	/* Queue of busy CCBs		*/
+	struct list_head wait_ccbq;	/* Queue of waiting for IO CCBs	*/
+	struct list_head skip_ccbq;	/* Queue of skipped CCBs	*/
+	u_char		actccbs;	/* Number of allocated CCBs	*/
+	u_char		busyccbs;	/* CCBs busy for this lun	*/
+	u_char		queuedccbs;	/* CCBs queued to the controller*/
+	u_char		queuedepth;	/* Queue depth for this lun	*/
+	u_char		scdev_depth;	/* SCSI device queue depth	*/
+	u_char		maxnxs;		/* Max possible nexuses		*/
+
+	/*----------------------------------------------------------------
+	**	Control of tagged command queuing.
+	**	Tags allocation is performed using a circular buffer.
+	**	This avoids using a loop for tag allocation.
+	**----------------------------------------------------------------
+	*/
+	u_char		ia_tag;		/* Allocation index		*/
+	u_char		if_tag;		/* Freeing index		*/
+	u_char cb_tags[MAX_TAGS];	/* Circular tags buffer	*/
+	u_char		usetags;	/* Command queuing is active	*/
+	u_char		maxtags;	/* Max nr of tags asked by user	*/
+	u_char		numtags;	/* Current number of tags	*/
+
+	/*----------------------------------------------------------------
+	**	QUEUE FULL control and ORDERED tag control.
+	**----------------------------------------------------------------
+	*/
+	/*----------------------------------------------------------------
+	**	QUEUE FULL and ORDERED tag control.
+	**----------------------------------------------------------------
+	*/
+	u16		num_good;	/* Nr of GOOD since QUEUE FULL	*/
+	tagmap_t	tags_umap;	/* Used tags bitmap		*/
+	tagmap_t	tags_smap;	/* Tags in use at 'tag_stime'	*/
+	u_long		tags_stime;	/* Last time we set smap=umap	*/
+	struct ccb *	held_ccb;	/* CCB held for QUEUE FULL	*/
+};
+
+/*========================================================================
+**
+**      Declaration of structs:     the launch script.
+**
+**========================================================================
+**
+**	It is part of the CCB and is called by the scripts processor to 
+**	start or restart the data structure (nexus).
+**	This 6 DWORDs mini script makes use of prefetching.
+**
+**------------------------------------------------------------------------
+*/
+struct launch {
+	/*----------------------------------------------------------------
+	**	SCR_COPY(4),	@(p_phys), @(dsa register)
+	**	SCR_JUMP,	@(scheduler_point)
+	**----------------------------------------------------------------
+	*/
+	ncrcmd		setup_dsa[3];	/* Copy 'phys' address to dsa	*/
+	struct link	schedule;	/* Jump to scheduler point	*/
+	ncrcmd		p_phys;		/* 'phys' header bus address	*/
+};
+
+/*========================================================================
+**
+**      Declaration of structs:     global HEADER.
+**
+**========================================================================
+**
+**	This substructure is copied from the ccb to a global address after 
+**	selection (or reselection) and copied back before disconnect.
+**
+**	These fields are accessible to the script processor.
+**
+**------------------------------------------------------------------------
+*/
+
+struct head {
+	/*----------------------------------------------------------------
+	**	Saved data pointer.
+	**	Points to the position in the script responsible for the
+	**	actual transfer transfer of data.
+	**	It's written after reception of a SAVE_DATA_POINTER message.
+	**	The goalpointer points after the last transfer command.
+	**----------------------------------------------------------------
+	*/
+	u32		savep;
+	u32		lastp;
+	u32		goalp;
+
+	/*----------------------------------------------------------------
+	**	Alternate data pointer.
+	**	They are copied back to savep/lastp/goalp by the SCRIPTS 
+	**	when the direction is unknown and the device claims data out.
+	**----------------------------------------------------------------
+	*/
+	u32		wlastp;
+	u32		wgoalp;
+
+	/*----------------------------------------------------------------
+	**	The virtual address of the ccb containing this header.
+	**----------------------------------------------------------------
+	*/
+	struct ccb *	cp;
+
+	/*----------------------------------------------------------------
+	**	Status fields.
+	**----------------------------------------------------------------
+	*/
+	u_char		scr_st[4];	/* script status		*/
+	u_char		status[4];	/* host status. must be the 	*/
+					/*  last DWORD of the header.	*/
+};
+
+/*
+**	The status bytes are used by the host and the script processor.
+**
+**	The byte corresponding to the host_status must be stored in the 
+**	last DWORD of the CCB header since it is used for command 
+**	completion (ncr_wakeup()). Doing so, we are sure that the header 
+**	has been entirely copied back to the CCB when the host_status is 
+**	seen complete by the CPU.
+**
+**	The last four bytes (status[4]) are copied to the scratchb register
+**	(declared as scr0..scr3 in ncr_reg.h) just after the select/reselect,
+**	and copied back just after disconnecting.
+**	Inside the script the XX_REG are used.
+**
+**	The first four bytes (scr_st[4]) are used inside the script by 
+**	"COPY" commands.
+**	Because source and destination must have the same alignment
+**	in a DWORD, the fields HAVE to be at the choosen offsets.
+**		xerr_st		0	(0x34)	scratcha
+**		sync_st		1	(0x05)	sxfer
+**		wide_st		3	(0x03)	scntl3
+*/
+
+/*
+**	Last four bytes (script)
+*/
+#define  QU_REG	scr0
+#define  HS_REG	scr1
+#define  HS_PRT	nc_scr1
+#define  SS_REG	scr2
+#define  SS_PRT	nc_scr2
+#define  PS_REG	scr3
+
+/*
+**	Last four bytes (host)
+*/
+#ifdef SCSI_NCR_BIG_ENDIAN
+#define  actualquirks  phys.header.status[3]
+#define  host_status   phys.header.status[2]
+#define  scsi_status   phys.header.status[1]
+#define  parity_status phys.header.status[0]
+#else
+#define  actualquirks  phys.header.status[0]
+#define  host_status   phys.header.status[1]
+#define  scsi_status   phys.header.status[2]
+#define  parity_status phys.header.status[3]
+#endif
+
+/*
+**	First four bytes (script)
+*/
+#define  xerr_st       header.scr_st[0]
+#define  sync_st       header.scr_st[1]
+#define  nego_st       header.scr_st[2]
+#define  wide_st       header.scr_st[3]
+
+/*
+**	First four bytes (host)
+*/
+#define  xerr_status   phys.xerr_st
+#define  nego_status   phys.nego_st
+
+#if 0
+#define  sync_status   phys.sync_st
+#define  wide_status   phys.wide_st
+#endif
+
+/*==========================================================
+**
+**      Declaration of structs:     Data structure block
+**
+**==========================================================
+**
+**	During execution of a ccb by the script processor,
+**	the DSA (data structure address) register points
+**	to this substructure of the ccb.
+**	This substructure contains the header with
+**	the script-processor-changable data and
+**	data blocks for the indirect move commands.
+**
+**----------------------------------------------------------
+*/
+
+struct dsb {
+
+	/*
+	**	Header.
+	*/
+
+	struct head	header;
+
+	/*
+	**	Table data for Script
+	*/
+
+	struct scr_tblsel  select;
+	struct scr_tblmove smsg  ;
+	struct scr_tblmove cmd   ;
+	struct scr_tblmove sense ;
+	struct scr_tblmove data[MAX_SCATTER];
+};
+
+
+/*========================================================================
+**
+**      Declaration of structs:     Command control block.
+**
+**========================================================================
+*/
+struct ccb {
+	/*----------------------------------------------------------------
+	**	This is the data structure which is pointed by the DSA 
+	**	register when it is executed by the script processor.
+	**	It must be the first entry because it contains the header 
+	**	as first entry that must be cache line aligned.
+	**----------------------------------------------------------------
+	*/
+	struct dsb	phys;
+
+	/*----------------------------------------------------------------
+	**	Mini-script used at CCB execution start-up.
+	**	Load the DSA with the data structure address (phys) and 
+	**	jump to SELECT. Jump to CANCEL if CCB is to be canceled.
+	**----------------------------------------------------------------
+	*/
+	struct launch	start;
+
+	/*----------------------------------------------------------------
+	**	Mini-script used at CCB relection to restart the nexus.
+	**	Load the DSA with the data structure address (phys) and 
+	**	jump to RESEL_DSA. Jump to ABORT if CCB is to be aborted.
+	**----------------------------------------------------------------
+	*/
+	struct launch	restart;
+
+	/*----------------------------------------------------------------
+	**	If a data transfer phase is terminated too early
+	**	(after reception of a message (i.e. DISCONNECT)),
+	**	we have to prepare a mini script to transfer
+	**	the rest of the data.
+	**----------------------------------------------------------------
+	*/
+	ncrcmd		patch[8];
+
+	/*----------------------------------------------------------------
+	**	The general SCSI driver provides a
+	**	pointer to a control block.
+	**----------------------------------------------------------------
+	*/
+	struct scsi_cmnd	*cmd;		/* SCSI command 		*/
+	u_char		cdb_buf[16];	/* Copy of CDB			*/
+	u_char		sense_buf[64];
+	int		data_len;	/* Total data length		*/
+
+	/*----------------------------------------------------------------
+	**	Message areas.
+	**	We prepare a message to be sent after selection.
+	**	We may use a second one if the command is rescheduled 
+	**	due to GETCC or QFULL.
+	**      Contents are IDENTIFY and SIMPLE_TAG.
+	**	While negotiating sync or wide transfer,
+	**	a SDTR or WDTR message is appended.
+	**----------------------------------------------------------------
+	*/
+	u_char		scsi_smsg [8];
+	u_char		scsi_smsg2[8];
+
+	/*----------------------------------------------------------------
+	**	Other fields.
+	**----------------------------------------------------------------
+	*/
+	u_long		p_ccb;		/* BUS address of this CCB	*/
+	u_char		sensecmd[6];	/* Sense command		*/
+	u_char		tag;		/* Tag for this transfer	*/
+					/*  255 means no tag		*/
+	u_char		target;
+	u_char		lun;
+	u_char		queued;
+	u_char		auto_sense;
+	struct ccb *	link_ccb;	/* Host adapter CCB chain	*/
+	struct list_head link_ccbq;	/* Link to unit CCB queue	*/
+	u32		startp;		/* Initial data pointer		*/
+	u_long		magic;		/* Free / busy  CCB flag	*/
+};
+
+#define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
+
+
+/*========================================================================
+**
+**      Declaration of structs:     NCR device descriptor
+**
+**========================================================================
+*/
+struct ncb {
+	/*----------------------------------------------------------------
+	**	The global header.
+	**	It is accessible to both the host and the script processor.
+	**	Must be cache line size aligned (32 for x86) in order to 
+	**	allow cache line bursting when it is copied to/from CCB.
+	**----------------------------------------------------------------
+	*/
+	struct head     header;
+
+	/*----------------------------------------------------------------
+	**	CCBs management queues.
+	**----------------------------------------------------------------
+	*/
+	struct scsi_cmnd	*waiting_list;	/* Commands waiting for a CCB	*/
+					/*  when lcb is not allocated.	*/
+	struct scsi_cmnd	*done_list;	/* Commands waiting for done()  */
+					/* callback to be invoked.      */ 
+	spinlock_t	smp_lock;	/* Lock for SMP threading       */
+
+	/*----------------------------------------------------------------
+	**	Chip and controller indentification.
+	**----------------------------------------------------------------
+	*/
+	int		unit;		/* Unit number			*/
+	char		inst_name[16];	/* ncb instance name		*/
+
+	/*----------------------------------------------------------------
+	**	Initial value of some IO register bits.
+	**	These values are assumed to have been set by BIOS, and may 
+	**	be used for probing adapter implementation differences.
+	**----------------------------------------------------------------
+	*/
+	u_char	sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest0, sv_ctest3,
+		sv_ctest4, sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4;
+
+	/*----------------------------------------------------------------
+	**	Actual initial value of IO register bits used by the 
+	**	driver. They are loaded at initialisation according to  
+	**	features that are to be enabled.
+	**----------------------------------------------------------------
+	*/
+	u_char	rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest0, rv_ctest3,
+		rv_ctest4, rv_ctest5, rv_stest2;
+
+	/*----------------------------------------------------------------
+	**	Targets management.
+	**	During reselection the ncr jumps to jump_tcb.
+	**	The SFBR register is loaded with the encoded target id.
+	**	For i = 0 to 3
+	**		SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(next tcb mod. i)
+	**
+	**	Recent chips will prefetch the 4 JUMPS using only 1 burst.
+	**	It is kind of hashcoding.
+	**----------------------------------------------------------------
+	*/
+	struct link     jump_tcb[4];	/* JUMPs for reselection	*/
+	struct tcb  target[MAX_TARGET];	/* Target data			*/
+
+	/*----------------------------------------------------------------
+	**	Virtual and physical bus addresses of the chip.
+	**----------------------------------------------------------------
+	*/
+	void __iomem *vaddr;		/* Virtual and bus address of	*/
+	unsigned long	paddr;		/*  chip's IO registers.	*/
+	unsigned long	paddr2;		/* On-chip RAM bus address.	*/
+	volatile			/* Pointer to volatile for 	*/
+	struct ncr_reg	__iomem *reg;	/*  memory mapped IO.		*/
+
+	/*----------------------------------------------------------------
+	**	SCRIPTS virtual and physical bus addresses.
+	**	'script'  is loaded in the on-chip RAM if present.
+	**	'scripth' stays in main memory.
+	**----------------------------------------------------------------
+	*/
+	struct script	*script0;	/* Copies of script and scripth	*/
+	struct scripth	*scripth0;	/*  relocated for this ncb.	*/
+	struct scripth	*scripth;	/* Actual scripth virt. address	*/
+	u_long		p_script;	/* Actual script and scripth	*/
+	u_long		p_scripth;	/*  bus addresses.		*/
+
+	/*----------------------------------------------------------------
+	**	General controller parameters and configuration.
+	**----------------------------------------------------------------
+	*/
+	struct device	*dev;
+	u_char		revision_id;	/* PCI device revision id	*/
+	u32		irq;		/* IRQ level			*/
+	u32		features;	/* Chip features map		*/
+	u_char		myaddr;		/* SCSI id of the adapter	*/
+	u_char		maxburst;	/* log base 2 of dwords burst	*/
+	u_char		maxwide;	/* Maximum transfer width	*/
+	u_char		minsync;	/* Minimum sync period factor	*/
+	u_char		maxsync;	/* Maximum sync period factor	*/
+	u_char		maxoffs;	/* Max scsi offset		*/
+	u_char		multiplier;	/* Clock multiplier (1,2,4)	*/
+	u_char		clock_divn;	/* Number of clock divisors	*/
+	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
+
+	/*----------------------------------------------------------------
+	**	Start queue management.
+	**	It is filled up by the host processor and accessed by the 
+	**	SCRIPTS processor in order to start SCSI commands.
+	**----------------------------------------------------------------
+	*/
+	u16		squeueput;	/* Next free slot of the queue	*/
+	u16		actccbs;	/* Number of allocated CCBs	*/
+	u16		queuedccbs;	/* Number of CCBs in start queue*/
+	u16		queuedepth;	/* Start queue depth		*/
+
+	/*----------------------------------------------------------------
+	**	Timeout handler.
+	**----------------------------------------------------------------
+	*/
+	struct timer_list timer;	/* Timer handler link header	*/
+	u_long		lasttime;
+	u_long		settle_time;	/* Resetting the SCSI BUS	*/
+
+	/*----------------------------------------------------------------
+	**	Debugging and profiling.
+	**----------------------------------------------------------------
+	*/
+	struct ncr_reg	regdump;	/* Register dump		*/
+	u_long		regtime;	/* Time it has been done	*/
+
+	/*----------------------------------------------------------------
+	**	Miscellaneous buffers accessed by the scripts-processor.
+	**	They shall be DWORD aligned, because they may be read or 
+	**	written with a SCR_COPY script command.
+	**----------------------------------------------------------------
+	*/
+	u_char		msgout[8];	/* Buffer for MESSAGE OUT 	*/
+	u_char		msgin [8];	/* Buffer for MESSAGE IN	*/
+	u32		lastmsg;	/* Last SCSI message sent	*/
+	u_char		scratch;	/* Scratch for SCSI receive	*/
+
+	/*----------------------------------------------------------------
+	**	Miscellaneous configuration and status parameters.
+	**----------------------------------------------------------------
+	*/
+	u_char		disc;		/* Diconnection allowed		*/
+	u_char		scsi_mode;	/* Current SCSI BUS mode	*/
+	u_char		order;		/* Tag order to use		*/
+	u_char		verbose;	/* Verbosity for this controller*/
+	int		ncr_cache;	/* Used for cache test at init.	*/
+	u_long		p_ncb;		/* BUS address of this NCB	*/
+
+	/*----------------------------------------------------------------
+	**	Command completion handling.
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	struct ccb	*(ccb_done[MAX_DONE]);
+	int		ccb_done_ic;
+#endif
+	/*----------------------------------------------------------------
+	**	Fields that should be removed or changed.
+	**----------------------------------------------------------------
+	*/
+	struct ccb	*ccb;		/* Global CCB			*/
+	struct usrcmd	user;		/* Command from user		*/
+	volatile u_char	release_stage;	/* Synchronisation stage on release  */
+};
+
+#define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
+#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl))
+
+/*==========================================================
+**
+**
+**      Script for NCR-Processor.
+**
+**	Use ncr_script_fill() to create the variable parts.
+**	Use ncr_script_copy_and_bind() to make a copy and
+**	bind to physical addresses.
+**
+**
+**==========================================================
+**
+**	We have to know the offsets of all labels before
+**	we reach them (for forward jumps).
+**	Therefore we declare a struct here.
+**	If you make changes inside the script,
+**	DONT FORGET TO CHANGE THE LENGTHS HERE!
+**
+**----------------------------------------------------------
+*/
+
+/*
+**	For HP Zalon/53c720 systems, the Zalon interface
+**	between CPU and 53c720 does prefetches, which causes
+**	problems with self modifying scripts.  The problem
+**	is overcome by calling a dummy subroutine after each
+**	modification, to force a refetch of the script on
+**	return from the subroutine.
+*/
+
+#ifdef CONFIG_NCR53C8XX_PREFETCH
+#define PREFETCH_FLUSH_CNT	2
+#define PREFETCH_FLUSH		SCR_CALL, PADDRH (wait_dma),
+#else
+#define PREFETCH_FLUSH_CNT	0
+#define PREFETCH_FLUSH
+#endif
+
+/*
+**	Script fragments which are loaded into the on-chip RAM 
+**	of 825A, 875 and 895 chips.
+*/
+struct script {
+	ncrcmd	start		[  5];
+	ncrcmd  startpos	[  1];
+	ncrcmd	select		[  6];
+	ncrcmd	select2		[  9 + PREFETCH_FLUSH_CNT];
+	ncrcmd	loadpos		[  4];
+	ncrcmd	send_ident	[  9];
+	ncrcmd	prepare		[  6];
+	ncrcmd	prepare2	[  7];
+	ncrcmd  command		[  6];
+	ncrcmd  dispatch	[ 32];
+	ncrcmd  clrack		[  4];
+	ncrcmd	no_data		[ 17];
+	ncrcmd  status		[  8];
+	ncrcmd  msg_in		[  2];
+	ncrcmd  msg_in2		[ 16];
+	ncrcmd  msg_bad		[  4];
+	ncrcmd	setmsg		[  7];
+	ncrcmd	cleanup		[  6];
+	ncrcmd  complete	[  9];
+	ncrcmd	cleanup_ok	[  8 + PREFETCH_FLUSH_CNT];
+	ncrcmd	cleanup0	[  1];
+#ifndef SCSI_NCR_CCB_DONE_SUPPORT
+	ncrcmd	signal		[ 12];
+#else
+	ncrcmd	signal		[  9];
+	ncrcmd	done_pos	[  1];
+	ncrcmd	done_plug	[  2];
+	ncrcmd	done_end	[  7];
+#endif
+	ncrcmd  save_dp		[  7];
+	ncrcmd  restore_dp	[  5];
+	ncrcmd  disconnect	[ 10];
+	ncrcmd	msg_out		[  9];
+	ncrcmd	msg_out_done	[  7];
+	ncrcmd  idle		[  2];
+	ncrcmd	reselect	[  8];
+	ncrcmd	reselected	[  8];
+	ncrcmd	resel_dsa	[  6 + PREFETCH_FLUSH_CNT];
+	ncrcmd	loadpos1	[  4];
+	ncrcmd  resel_lun	[  6];
+	ncrcmd	resel_tag	[  6];
+	ncrcmd	jump_to_nexus	[  4 + PREFETCH_FLUSH_CNT];
+	ncrcmd	nexus_indirect	[  4];
+	ncrcmd	resel_notag	[  4];
+	ncrcmd  data_in		[MAX_SCATTERL * 4];
+	ncrcmd  data_in2	[  4];
+	ncrcmd  data_out	[MAX_SCATTERL * 4];
+	ncrcmd  data_out2	[  4];
+};
+
+/*
+**	Script fragments which stay in main memory for all chips.
+*/
+struct scripth {
+	ncrcmd  tryloop		[MAX_START*2];
+	ncrcmd  tryloop2	[  2];
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	ncrcmd  done_queue	[MAX_DONE*5];
+	ncrcmd  done_queue2	[  2];
+#endif
+	ncrcmd	select_no_atn	[  8];
+	ncrcmd	cancel		[  4];
+	ncrcmd	skip		[  9 + PREFETCH_FLUSH_CNT];
+	ncrcmd	skip2		[ 19];
+	ncrcmd	par_err_data_in	[  6];
+	ncrcmd	par_err_other	[  4];
+	ncrcmd	msg_reject	[  8];
+	ncrcmd	msg_ign_residue	[ 24];
+	ncrcmd  msg_extended	[ 10];
+	ncrcmd  msg_ext_2	[ 10];
+	ncrcmd	msg_wdtr	[ 14];
+	ncrcmd	send_wdtr	[  7];
+	ncrcmd  msg_ext_3	[ 10];
+	ncrcmd	msg_sdtr	[ 14];
+	ncrcmd	send_sdtr	[  7];
+	ncrcmd	nego_bad_phase	[  4];
+	ncrcmd	msg_out_abort	[ 10];
+	ncrcmd  hdata_in	[MAX_SCATTERH * 4];
+	ncrcmd  hdata_in2	[  2];
+	ncrcmd  hdata_out	[MAX_SCATTERH * 4];
+	ncrcmd  hdata_out2	[  2];
+	ncrcmd	reset		[  4];
+	ncrcmd	aborttag	[  4];
+	ncrcmd	abort		[  2];
+	ncrcmd	abort_resel	[ 20];
+	ncrcmd	resend_ident	[  4];
+	ncrcmd	clratn_go_on	[  3];
+	ncrcmd	nxtdsp_go_on	[  1];
+	ncrcmd	sdata_in	[  8];
+	ncrcmd  data_io		[ 18];
+	ncrcmd	bad_identify	[ 12];
+	ncrcmd	bad_i_t_l	[  4];
+	ncrcmd	bad_i_t_l_q	[  4];
+	ncrcmd	bad_target	[  8];
+	ncrcmd	bad_status	[  8];
+	ncrcmd	start_ram	[  4 + PREFETCH_FLUSH_CNT];
+	ncrcmd	start_ram0	[  4];
+	ncrcmd	sto_restart	[  5];
+	ncrcmd	wait_dma	[  2];
+	ncrcmd	snooptest	[  9];
+	ncrcmd	snoopend	[  2];
+};
+
+/*==========================================================
+**
+**
+**      Function headers.
+**
+**
+**==========================================================
+*/
+
+static	void	ncr_alloc_ccb	(struct ncb *np, u_char tn, u_char ln);
+static	void	ncr_complete	(struct ncb *np, struct ccb *cp);
+static	void	ncr_exception	(struct ncb *np);
+static	void	ncr_free_ccb	(struct ncb *np, struct ccb *cp);
+static	void	ncr_init_ccb	(struct ncb *np, struct ccb *cp);
+static	void	ncr_init_tcb	(struct ncb *np, u_char tn);
+static	struct lcb *	ncr_alloc_lcb	(struct ncb *np, u_char tn, u_char ln);
+static	struct lcb *	ncr_setup_lcb	(struct ncb *np, struct scsi_device *sdev);
+static	void	ncr_getclock	(struct ncb *np, int mult);
+static	void	ncr_selectclock	(struct ncb *np, u_char scntl3);
+static	struct ccb *ncr_get_ccb	(struct ncb *np, struct scsi_cmnd *cmd);
+static	void	ncr_chip_reset	(struct ncb *np, int delay);
+static	void	ncr_init	(struct ncb *np, int reset, char * msg, u_long code);
+static	int	ncr_int_sbmc	(struct ncb *np);
+static	int	ncr_int_par	(struct ncb *np);
+static	void	ncr_int_ma	(struct ncb *np);
+static	void	ncr_int_sir	(struct ncb *np);
+static  void    ncr_int_sto     (struct ncb *np);
+static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	int	ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr);
+
+static	void	ncr_script_copy_and_bind
+				(struct ncb *np, ncrcmd *src, ncrcmd *dst, int len);
+static  void    ncr_script_fill (struct script * scr, struct scripth * scripth);
+static	int	ncr_scatter	(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd);
+static	void	ncr_getsync	(struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p);
+static	void	ncr_setsync	(struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer);
+static	void	ncr_setup_tags	(struct ncb *np, struct scsi_device *sdev);
+static	void	ncr_setwide	(struct ncb *np, struct ccb *cp, u_char wide, u_char ack);
+static	int	ncr_snooptest	(struct ncb *np);
+static	void	ncr_timeout	(struct ncb *np);
+static  void    ncr_wakeup      (struct ncb *np, u_long code);
+static  void    ncr_wakeup_done (struct ncb *np);
+static	void	ncr_start_next_ccb (struct ncb *np, struct lcb * lp, int maxn);
+static	void	ncr_put_start_queue(struct ncb *np, struct ccb *cp);
+
+static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd);
+static struct scsi_cmnd *retrieve_from_waiting_list(int to_remove, struct ncb *np, struct scsi_cmnd *cmd);
+static void process_waiting_list(struct ncb *np, int sts);
+
+#define remove_from_waiting_list(np, cmd) \
+		retrieve_from_waiting_list(1, (np), (cmd))
+#define requeue_waiting_list(np) process_waiting_list((np), DID_OK)
+#define reset_waiting_list(np) process_waiting_list((np), DID_RESET)
+
+static inline char *ncr_name (struct ncb *np)
+{
+	return np->inst_name;
+}
+
+
+/*==========================================================
+**
+**
+**      Scripts for NCR-Processor.
+**
+**      Use ncr_script_bind for binding to physical addresses.
+**
+**
+**==========================================================
+**
+**	NADDR generates a reference to a field of the controller data.
+**	PADDR generates a reference to another part of the script.
+**	RADDR generates a reference to a script processor register.
+**	FADDR generates a reference to a script processor register
+**		with offset.
+**
+**----------------------------------------------------------
+*/
+
+#define	RELOC_SOFTC	0x40000000
+#define	RELOC_LABEL	0x50000000
+#define	RELOC_REGISTER	0x60000000
+#if 0
+#define	RELOC_KVAR	0x70000000
+#endif
+#define	RELOC_LABELH	0x80000000
+#define	RELOC_MASK	0xf0000000
+
+#define	NADDR(label)	(RELOC_SOFTC | offsetof(struct ncb, label))
+#define PADDR(label)    (RELOC_LABEL | offsetof(struct script, label))
+#define PADDRH(label)   (RELOC_LABELH | offsetof(struct scripth, label))
+#define	RADDR(label)	(RELOC_REGISTER | REG(label))
+#define	FADDR(label,ofs)(RELOC_REGISTER | ((REG(label))+(ofs)))
+#if 0
+#define	KVAR(which)	(RELOC_KVAR | (which))
+#endif
+
+#if 0
+#define	SCRIPT_KVAR_JIFFIES	(0)
+#define	SCRIPT_KVAR_FIRST		SCRIPT_KVAR_JIFFIES
+#define	SCRIPT_KVAR_LAST		SCRIPT_KVAR_JIFFIES
+/*
+ * Kernel variables referenced in the scripts.
+ * THESE MUST ALL BE ALIGNED TO A 4-BYTE BOUNDARY.
+ */
+static void *script_kvars[] __initdata =
+	{ (void *)&jiffies };
+#endif
+
+static	struct script script0 __initdata = {
+/*--------------------------< START >-----------------------*/ {
+	/*
+	**	This NOP will be patched with LED ON
+	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+	*/
+	SCR_NO_OP,
+		0,
+	/*
+	**      Clear SIGP.
+	*/
+	SCR_FROM_REG (ctest2),
+		0,
+	/*
+	**	Then jump to a certain point in tryloop.
+	**	Due to the lack of indirect addressing the code
+	**	is self modifying here.
+	*/
+	SCR_JUMP,
+}/*-------------------------< STARTPOS >--------------------*/,{
+		PADDRH(tryloop),
+
+}/*-------------------------< SELECT >----------------------*/,{
+	/*
+	**	DSA	contains the address of a scheduled
+	**		data structure.
+	**
+	**	SCRATCHA contains the address of the script,
+	**		which starts the next entry.
+	**
+	**	Set Initiator mode.
+	**
+	**	(Target mode is left as an exercise for the reader)
+	*/
+
+	SCR_CLR (SCR_TRG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_SELECTING),
+		0,
+
+	/*
+	**      And try to select this target.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select),
+		PADDR (reselect),
+
+}/*-------------------------< SELECT2 >----------------------*/,{
+	/*
+	**	Now there are 4 possibilities:
+	**
+	**	(1) The ncr loses arbitration.
+	**	This is ok, because it will try again,
+	**	when the bus becomes idle.
+	**	(But beware of the timeout function!)
+	**
+	**	(2) The ncr is reselected.
+	**	Then the script processor takes the jump
+	**	to the RESELECT label.
+	**
+	**	(3) The ncr wins arbitration.
+	**	Then it will execute SCRIPTS instruction until 
+	**	the next instruction that checks SCSI phase.
+	**	Then will stop and wait for selection to be 
+	**	complete or selection time-out to occur.
+	**	As a result the SCRIPTS instructions until 
+	**	LOADPOS + 2 should be executed in parallel with 
+	**	the SCSI core performing selection.
+	*/
+
+	/*
+	**	The M_REJECT problem seems to be due to a selection 
+	**	timing problem.
+	**	Wait immediately for the selection to complete. 
+	**	(2.5x behaves so)
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		0,
+
+	/*
+	**	Next time use the next slot.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (startpos),
+	/*
+	**      The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDR (loadpos),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
+	*/
+}/*-------------------------< LOADPOS >---------------------*/,{
+		0,
+		NADDR (header),
+	/*
+	**	Wait for the next phase or the selection
+	**	to complete or time-out.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR (prepare),
+
+}/*-------------------------< SEND_IDENT >----------------------*/,{
+	/*
+	**	Selection complete.
+	**	Send the IDENTIFY and SIMPLE_TAG messages
+	**	(and the M_X_SYNC_REQ message)
+	*/
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct dsb, smsg),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDRH (resend_ident),
+	SCR_LOAD_REG (scratcha, 0x80),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (lastmsg),
+}/*-------------------------< PREPARE >----------------------*/,{
+	/*
+	**      load the savep (saved pointer) into
+	**      the TEMP register (actual pointer)
+	*/
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_COPY (4),
+		NADDR (header.status),
+		RADDR (scr0),
+}/*-------------------------< PREPARE2 >---------------------*/,{
+	/*
+	**	Initialize the msgout buffer with a NOOP message.
+	*/
+	SCR_LOAD_REG (scratcha, M_NOOP),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+#if 0
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgin),
+#endif
+	/*
+	**	Anticipate the COMMAND phase.
+	**	This is the normal case for initial selection.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
+		PADDR (dispatch),
+
+}/*-------------------------< COMMAND >--------------------*/,{
+	/*
+	**	... and send the command
+	*/
+	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct dsb, cmd),
+	/*
+	**	If status is still HS_NEGOTIATE, negotiation failed.
+	**	We check this here, since we want to do that 
+	**	only once.
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+
+}/*-----------------------< DISPATCH >----------------------*/,{
+	/*
+	**	MSG_IN is the only phase that shall be 
+	**	entered at least once for each (re)selection.
+	**	So we test it first.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
+
+	SCR_RETURN ^ IFTRUE (IF (SCR_DATA_OUT)),
+		0,
+	/*
+	**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4.
+	**	Possible data corruption during Memory Write and Invalidate.
+	**	This work-around resets the addressing logic prior to the 
+	**	start of the first MOVE of a DATA IN phase.
+	**	(See Documentation/scsi/ncr53c8xx.txt for more information)
+	*/
+	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+		20,
+	SCR_COPY (4),
+		RADDR (scratcha),
+		RADDR (scratcha),
+	SCR_RETURN,
+ 		0,
+	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+		PADDR (status),
+	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+		PADDR (command),
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+		PADDR (msg_out),
+	/*
+	**      Discard one illegal phase byte, if required.
+	*/
+	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (xerr_st),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+		NADDR (scratch),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+		NADDR (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< CLRACK >----------------------*/,{
+	/*
+	**	Terminate possible pending message phase.
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< NO_DATA >--------------------*/,{
+	/*
+	**	The target wants to tranfer too much data
+	**	or in the wrong direction.
+	**      Remember that in extended error.
+	*/
+	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+		0,
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (xerr_st),
+	/*
+	**      Discard one data byte, if required.
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
+		NADDR (scratch),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+		NADDR (scratch),
+	/*
+	**      .. and repeat as required.
+	*/
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+
+}/*-------------------------< STATUS >--------------------*/,{
+	/*
+	**	get the status
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+	/*
+	**	save status to scsi_status.
+	**	mark as complete.
+	*/
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*-------------------------< MSG_IN >--------------------*/,{
+	/*
+	**	Get the first byte of the message
+	**	and save it to SCRATCHA.
+	**
+	**	The script processor doesn't negate the
+	**	ACK signal after this transfer.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------*/,{
+	/*
+	**	Handle this message.
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+		PADDR (complete),
+	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+		PADDR (disconnect),
+	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+		PADDR (save_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+		PADDR (restore_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDRH (msg_extended),
+	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
+		PADDR (clrack),
+	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
+		PADDRH (msg_reject),
+	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
+		PADDRH (msg_ign_residue),
+	/*
+	**	Rest of the messages left as
+	**	an exercise ...
+	**
+	**	Unimplemented messages:
+	**	fall through to MSG_BAD.
+	*/
+}/*-------------------------< MSG_BAD >------------------*/,{
+	/*
+	**	unimplemented message - reject it.
+	*/
+	SCR_INT,
+		SIR_REJECT_SENT,
+	SCR_LOAD_REG (scratcha, M_REJECT),
+		0,
+}/*-------------------------< SETMSG >----------------------*/,{
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR (clrack),
+}/*-------------------------< CLEANUP >-------------------*/,{
+	/*
+	**      dsa:    Pointer to ccb
+	**	      or xxxxxxFF (no ccb)
+	**
+	**      HS_REG:   Host-Status (<>0!)
+	*/
+	SCR_FROM_REG (dsa),
+		0,
+	SCR_JUMP ^ IFTRUE (DATA (0xff)),
+		PADDR (start),
+	/*
+	**      dsa is valid.
+	**	complete the cleanup.
+	*/
+	SCR_JUMP,
+		PADDR (cleanup_ok),
+
+}/*-------------------------< COMPLETE >-----------------*/,{
+	/*
+	**	Complete message.
+	**
+	**	Copy TEMP register to LASTP in header.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.lastp),
+	/*
+	**	When we terminate the cycle by clearing ACK,
+	**	the target may disconnect immediately.
+	**
+	**	We don't want to be told of an
+	**	"unexpected disconnect",
+	**	so we disable this feature.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	/*
+	**	Terminate cycle ...
+	*/
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	**	... and wait for the disconnect.
+	*/
+	SCR_WAIT_DISC,
+		0,
+}/*-------------------------< CLEANUP_OK >----------------*/,{
+	/*
+	**	Save host status to header.
+	*/
+	SCR_COPY (4),
+		RADDR (scr0),
+		NADDR (header.status),
+	/*
+	**	and copy back the header to the ccb.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDR (cleanup0),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	SCR_COPY (sizeof (struct head)),
+		NADDR (header),
+}/*-------------------------< CLEANUP0 >--------------------*/,{
+		0,
+}/*-------------------------< SIGNAL >----------------------*/,{
+	/*
+	**	if job not completed ...
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+	/*
+	**	... start the next command.
+	*/
+	SCR_JUMP ^ IFTRUE (MASK (0, (HS_DONEMASK|HS_SKIPMASK))),
+		PADDR(start),
+	/*
+	**	If command resulted in not GOOD status,
+	**	call the C code if needed.
+	*/
+	SCR_FROM_REG (SS_REG),
+		0,
+	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+		PADDRH (bad_status),
+
+#ifndef	SCSI_NCR_CCB_DONE_SUPPORT
+
+	/*
+	**	... signal completion to the host
+	*/
+	SCR_INT,
+		SIR_INTFLY,
+	/*
+	**	Auf zu neuen Schandtaten!
+	*/
+	SCR_JUMP,
+		PADDR(start),
+
+#else	/* defined SCSI_NCR_CCB_DONE_SUPPORT */
+
+	/*
+	**	... signal completion to the host
+	*/
+	SCR_JUMP,
+}/*------------------------< DONE_POS >---------------------*/,{
+		PADDRH (done_queue),
+}/*------------------------< DONE_PLUG >--------------------*/,{
+	SCR_INT,
+		SIR_DONE_OVERFLOW,
+}/*------------------------< DONE_END >---------------------*/,{
+	SCR_INT,
+		SIR_INTFLY,
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (done_pos),
+	SCR_JUMP,
+		PADDR (start),
+
+#endif	/* SCSI_NCR_CCB_DONE_SUPPORT */
+
+}/*-------------------------< SAVE_DP >------------------*/,{
+	/*
+	**	SAVE_DP message:
+	**	Copy TEMP register to SAVEP in header.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR (header.savep),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*-------------------------< RESTORE_DP >---------------*/,{
+	/*
+	**	RESTORE_DP message:
+	**	Copy SAVEP in header to TEMP register.
+	*/
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< DISCONNECT >---------------*/,{
+	/*
+	**	DISCONNECTing  ...
+	**
+	**	disable the "unexpected disconnect" feature,
+	**	and remove the ACK signal.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	**	Wait for the disconnect.
+	*/
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	Status is: DISCONNECTED.
+	*/
+	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup_ok),
+
+}/*-------------------------< MSG_OUT >-------------------*/,{
+	/*
+	**	The target requests a message.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		NADDR (msgout),
+		NADDR (lastmsg),
+	/*
+	**	If it was no ABORT message ...
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (M_ABORT)),
+		PADDRH (msg_out_abort),
+	/*
+	**	... wait for the next phase
+	**	if it's a message out, send it again, ...
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR (msg_out),
+}/*-------------------------< MSG_OUT_DONE >--------------*/,{
+	/*
+	**	... else clear the message ...
+	*/
+	SCR_LOAD_REG (scratcha, M_NOOP),
+		0,
+	SCR_COPY (4),
+		RADDR (scratcha),
+		NADDR (msgout),
+	/*
+	**	... and process the next phase
+	*/
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*-------------------------< IDLE >------------------------*/,{
+	/*
+	**	Nothing to do?
+	**	Wait for reselect.
+	**	This NOP will be patched with LED OFF
+	**	SCR_REG_REG (gpreg, SCR_OR, 0x01)
+	*/
+	SCR_NO_OP,
+		0,
+}/*-------------------------< RESELECT >--------------------*/,{
+	/*
+	**	make the DSA invalid.
+	*/
+	SCR_LOAD_REG (dsa, 0xff),
+		0,
+	SCR_CLR (SCR_TRG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_IN_RESELECT),
+		0,
+	/*
+	**	Sleep waiting for a reselection.
+	**	If SIGP is set, special treatment.
+	**
+	**	Zu allem bereit ..
+	*/
+	SCR_WAIT_RESEL,
+		PADDR(start),
+}/*-------------------------< RESELECTED >------------------*/,{
+	/*
+	**	This NOP will be patched with LED ON
+	**	SCR_REG_REG (gpreg, SCR_AND, 0xfe)
+	*/
+	SCR_NO_OP,
+		0,
+	/*
+	**	... zu nichts zu gebrauchen ?
+	**
+	**      load the target id into the SFBR
+	**	and jump to the control block.
+	**
+	**	Look at the declarations of
+	**	- struct ncb
+	**	- struct tcb
+	**	- struct lcb
+	**	- struct ccb
+	**	to understand what's going on.
+	*/
+	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+		0,
+	SCR_TO_REG (sdid),
+		0,
+	SCR_JUMP,
+		NADDR (jump_tcb),
+
+}/*-------------------------< RESEL_DSA >-------------------*/,{
+	/*
+	**	Ack the IDENTIFY or TAG previously received.
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**      The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDR (loadpos1),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
+	*/
+
+}/*-------------------------< LOADPOS1 >-------------------*/,{
+		0,
+		NADDR (header),
+	/*
+	**	The DSA contains the data structure address.
+	*/
+	SCR_JUMP,
+		PADDR (prepare),
+
+}/*-------------------------< RESEL_LUN >-------------------*/,{
+	/*
+	**	come back to this point
+	**	to get an IDENTIFY message
+	**	Wait for a msg_in phase.
+	*/
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_RESEL_NO_MSG_IN,
+	/*
+	**	message phase.
+	**	Read the data directly from the BUS DATA lines.
+	**	This helps to support very old SCSI devices that 
+	**	may reselect without sending an IDENTIFY.
+	*/
+	SCR_FROM_REG (sbdl),
+		0,
+	/*
+	**	It should be an Identify message.
+	*/
+	SCR_RETURN,
+		0,
+}/*-------------------------< RESEL_TAG >-------------------*/,{
+	/*
+	**	Read IDENTIFY + SIMPLE + TAG using a single MOVE.
+	**	Agressive optimization, is'nt it?
+	**	No need to test the SIMPLE TAG message, since the 
+	**	driver only supports conformant devices for tags. ;-)
+	*/
+	SCR_MOVE_ABS (3) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	/*
+	**	Read the TAG from the SIDL.
+	**	Still an aggressive optimization. ;-)
+	**	Compute the CCB indirect jump address which 
+	**	is (#TAG*2 & 0xfc) due to tag numbering using 
+	**	1,3,5..MAXTAGS*2+1 actual values.
+	*/
+	SCR_REG_SFBR (sidl, SCR_SHL, 0),
+		0,
+	SCR_SFBR_REG (temp, SCR_AND, 0xfc),
+		0,
+}/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{
+	SCR_COPY_F (4),
+		RADDR (temp),
+		PADDR (nexus_indirect),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	SCR_COPY (4),
+}/*-------------------------< NEXUS_INDIRECT >-------------------*/,{
+		0,
+		RADDR (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< RESEL_NOTAG >-------------------*/,{
+	/*
+	**	No tag expected.
+	**	Read an throw away the IDENTIFY.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_JUMP,
+		PADDR (jump_to_nexus),
+}/*-------------------------< DATA_IN >--------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTERL parameter,
+**	it is filled in at runtime.
+**
+**  ##===========< i=0; i<MAX_SCATTERL >=========
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##==========================================
+**
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< DATA_IN2 >-------------------*/,{
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+}/*-------------------------< DATA_OUT >--------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTERL parameter,
+**	it is filled in at runtime.
+**
+**  ##===========< i=0; i<MAX_SCATTERL >=========
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##==========================================
+**
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< DATA_OUT2 >-------------------*/,{
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+}/*--------------------------------------------------------*/
+};
+
+static	struct scripth scripth0 __initdata = {
+/*-------------------------< TRYLOOP >---------------------*/{
+/*
+**	Start the next entry.
+**	Called addresses point to the launch script in the CCB.
+**	They are patched by the main processor.
+**
+**	Because the size depends on the
+**	#define MAX_START parameter, it is filled
+**	in at runtime.
+**
+**-----------------------------------------------------------
+**
+**  ##===========< I=0; i<MAX_START >===========
+**  ||	SCR_CALL,
+**  ||		PADDR (idle),
+**  ##==========================================
+**
+**-----------------------------------------------------------
+*/
+0
+}/*------------------------< TRYLOOP2 >---------------------*/,{
+	SCR_JUMP,
+		PADDRH(tryloop),
+
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+
+}/*------------------------< DONE_QUEUE >-------------------*/,{
+/*
+**	Copy the CCB address to the next done entry.
+**	Because the size depends on the
+**	#define MAX_DONE parameter, it is filled
+**	in at runtime.
+**
+**-----------------------------------------------------------
+**
+**  ##===========< I=0; i<MAX_DONE >===========
+**  ||	SCR_COPY (sizeof(struct ccb *),
+**  ||		NADDR (header.cp),
+**  ||		NADDR (ccb_done[i]),
+**  ||	SCR_CALL,
+**  ||		PADDR (done_end),
+**  ##==========================================
+**
+**-----------------------------------------------------------
+*/
+0
+}/*------------------------< DONE_QUEUE2 >------------------*/,{
+	SCR_JUMP,
+		PADDRH (done_queue),
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+}/*------------------------< SELECT_NO_ATN >-----------------*/,{
+	/*
+	**	Set Initiator mode.
+	**      And try to select this target without ATN.
+	*/
+
+	SCR_CLR (SCR_TRG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_SELECTING),
+		0,
+	SCR_SEL_TBL ^ offsetof (struct dsb, select),
+		PADDR (reselect),
+	SCR_JUMP,
+		PADDR (select2),
+
+}/*-------------------------< CANCEL >------------------------*/,{
+
+	SCR_LOAD_REG (scratcha, HS_ABORTED),
+		0,
+	SCR_JUMPR,
+		8,
+}/*-------------------------< SKIP >------------------------*/,{
+	SCR_LOAD_REG (scratcha, 0),
+		0,
+	/*
+	**	This entry has been canceled.
+	**	Next time use the next slot.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (startpos),
+	/*
+	**      The ncr doesn't have an indirect load
+	**	or store command. So we have to
+	**	copy part of the control block to a
+	**	fixed place, where we can access it.
+	**
+	**	We patch the address part of a
+	**	COPY command with the DSA-register.
+	*/
+	SCR_COPY_F (4),
+		RADDR (dsa),
+		PADDRH (skip2),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	/*
+	**	then we do the actual copy.
+	*/
+	SCR_COPY (sizeof (struct head)),
+	/*
+	**	continued after the next label ...
+	*/
+}/*-------------------------< SKIP2 >---------------------*/,{
+		0,
+		NADDR (header),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_COPY (4),
+		NADDR (header.status),
+		RADDR (scr0),
+	/*
+	**	Force host status.
+	*/
+	SCR_FROM_REG (scratcha),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)),
+		16,
+	SCR_REG_REG (HS_REG, SCR_OR, HS_SKIPMASK),
+		0,
+	SCR_JUMPR,
+		8,
+	SCR_TO_REG (HS_REG),
+		0,
+	SCR_LOAD_REG (SS_REG, S_GOOD),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup_ok),
+
+},/*-------------------------< PAR_ERR_DATA_IN >---------------*/{
+	/*
+	**	Ignore all data in byte, until next phase
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDRH (par_err_other),
+	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
+		NADDR (scratch),
+	SCR_JUMPR,
+		-24,
+},/*-------------------------< PAR_ERR_OTHER >------------------*/{
+	/*
+	**	count it.
+	*/
+	SCR_REG_REG (PS_REG, SCR_ADD, 0x01),
+		0,
+	/*
+	**	jump to dispatcher.
+	*/
+	SCR_JUMP,
+		PADDR (dispatch),
+}/*-------------------------< MSG_REJECT >---------------*/,{
+	/*
+	**	If a negotiation was in progress,
+	**	negotiation failed.
+	**	Otherwise, let the C code print 
+	**	some message.
+	*/
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
+		SIR_REJECT_RECEIVED,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+	/*
+	**	Terminate cycle
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get residue size.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
+	/*
+	**	Size is 0 .. ignore message.
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (0)),
+		PADDR (clrack),
+	/*
+	**	Size is not 1 .. have to interrupt.
+	*/
+	SCR_JUMPR ^ IFFALSE (DATA (1)),
+		40,
+	/*
+	**	Check for residue byte in swide register
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+		16,
+	/*
+	**	There IS data in the swide register.
+	**	Discard it.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	SCR_JUMP,
+		PADDR (clrack),
+	/*
+	**	Load again the size to the sfbr register.
+	*/
+	SCR_FROM_REG (scratcha),
+		0,
+	SCR_INT,
+		SIR_IGN_RESIDUE,
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< MSG_EXTENDED >-------------*/,{
+	/*
+	**	Terminate cycle
+	*/
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get length.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
+	/*
+	*/
+	SCR_JUMP ^ IFTRUE (DATA (3)),
+		PADDRH (msg_ext_3),
+	SCR_JUMP ^ IFFALSE (DATA (2)),
+		PADDR (msg_bad),
+}/*-------------------------< MSG_EXT_2 >----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get extended message code.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[2]),
+	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
+		PADDRH (msg_wdtr),
+	/*
+	**	unknown extended message
+	*/
+	SCR_JUMP,
+		PADDR (msg_bad)
+}/*-------------------------< MSG_WDTR >-----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get data bus width
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[3]),
+	/*
+	**	let the host do the real work.
+	*/
+	SCR_INT,
+		SIR_NEGO_WIDE,
+	/*
+	**	let the target fetch our answer.
+	*/
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDRH (nego_bad_phase),
+
+}/*-------------------------< SEND_WDTR >----------------*/,{
+	/*
+	**	Send the M_X_WIDE_REQ
+	*/
+	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		NADDR (msgout),
+		NADDR (lastmsg),
+	SCR_JUMP,
+		PADDR (msg_out_done),
+
+}/*-------------------------< MSG_EXT_3 >----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get extended message code.
+	*/
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[2]),
+	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
+		PADDRH (msg_sdtr),
+	/*
+	**	unknown extended message
+	*/
+	SCR_JUMP,
+		PADDR (msg_bad)
+
+}/*-------------------------< MSG_SDTR >-----------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (dispatch),
+	/*
+	**	get period and offset
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (msgin[3]),
+	/*
+	**	let the host do the real work.
+	*/
+	SCR_INT,
+		SIR_NEGO_SYNC,
+	/*
+	**	let the target fetch our answer.
+	*/
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDRH (nego_bad_phase),
+
+}/*-------------------------< SEND_SDTR >-------------*/,{
+	/*
+	**	Send the M_X_SYNC_REQ
+	*/
+	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		NADDR (msgout),
+		NADDR (lastmsg),
+	SCR_JUMP,
+		PADDR (msg_out_done),
+
+}/*-------------------------< NEGO_BAD_PHASE >------------*/,{
+	SCR_INT,
+		SIR_NEGO_PROTO,
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< MSG_OUT_ABORT >-------------*/,{
+	/*
+	**	After ABORT message,
+	**
+	**	expect an immediate disconnect, ...
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	... and set the status to "ABORTED"
+	*/
+	SCR_LOAD_REG (HS_REG, HS_ABORTED),
+		0,
+	SCR_JUMP,
+		PADDR (cleanup),
+
+}/*-------------------------< HDATA_IN >-------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTERH parameter,
+**	it is filled in at runtime.
+**
+**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##===================================================
+**
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< HDATA_IN2 >------------------*/,{
+	SCR_JUMP,
+		PADDR (data_in),
+
+}/*-------------------------< HDATA_OUT >-------------------*/,{
+/*
+**	Because the size depends on the
+**	#define MAX_SCATTERH parameter,
+**	it is filled in at runtime.
+**
+**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
+**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+**  ||		PADDR (dispatch),
+**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ||		offsetof (struct dsb, data[ i]),
+**  ##===================================================
+**
+**---------------------------------------------------------
+*/
+0
+}/*-------------------------< HDATA_OUT2 >------------------*/,{
+	SCR_JUMP,
+		PADDR (data_out),
+
+}/*-------------------------< RESET >----------------------*/,{
+	/*
+	**      Send a M_RESET message if bad IDENTIFY 
+	**	received on reselection.
+	*/
+	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+		0,
+	SCR_JUMP,
+		PADDRH (abort_resel),
+}/*-------------------------< ABORTTAG >-------------------*/,{
+	/*
+	**      Abort a wrong tag received on reselection.
+	*/
+	SCR_LOAD_REG (scratcha, M_ABORT_TAG),
+		0,
+	SCR_JUMP,
+		PADDRH (abort_resel),
+}/*-------------------------< ABORT >----------------------*/,{
+	/*
+	**      Abort a reselection when no active CCB.
+	*/
+	SCR_LOAD_REG (scratcha, M_ABORT),
+		0,
+}/*-------------------------< ABORT_RESEL >----------------*/,{
+	SCR_COPY (1),
+		RADDR (scratcha),
+		NADDR (msgout),
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	and send it.
+	**	we expect an immediate disconnect
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_COPY (1),
+		NADDR (msgout),
+		NADDR (lastmsg),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< RESEND_IDENT >-------------------*/,{
+	/*
+	**	The target stays in MSG OUT phase after having acked 
+	**	Identify [+ Tag [+ Extended message ]]. Targets shall
+	**	behave this way on parity error.
+	**	We must send it again all the messages.
+	*/
+	SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the  */
+		0,         /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */
+	SCR_JUMP,
+		PADDR (send_ident),
+}/*-------------------------< CLRATN_GO_ON >-------------------*/,{
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_JUMP,
+}/*-------------------------< NXTDSP_GO_ON >-------------------*/,{
+		0,
+}/*-------------------------< SDATA_IN >-------------------*/,{
+	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR (dispatch),
+	SCR_MOVE_TBL ^ SCR_DATA_IN,
+		offsetof (struct dsb, sense),
+	SCR_CALL,
+		PADDR (dispatch),
+	SCR_JUMP,
+		PADDR (no_data),
+}/*-------------------------< DATA_IO >--------------------*/,{
+	/*
+	**	We jump here if the data direction was unknown at the 
+	**	time we had to queue the command to the scripts processor.
+	**	Pointers had been set as follow in this situation:
+	**	  savep   -->   DATA_IO
+	**	  lastp   -->   start pointer when DATA_IN
+	**	  goalp   -->   goal  pointer when DATA_IN
+	**	  wlastp  -->   start pointer when DATA_OUT
+	**	  wgoalp  -->   goal  pointer when DATA_OUT
+	**	This script sets savep/lastp/goalp according to the 
+	**	direction chosen by the target.
+	*/
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		32,
+	/*
+	**	Direction is DATA IN.
+	**	Warning: we jump here, even when phase is DATA OUT.
+	*/
+	SCR_COPY (4),
+		NADDR (header.lastp),
+		NADDR (header.savep),
+
+	/*
+	**	Jump to the SCRIPTS according to actual direction.
+	*/
+	SCR_COPY (4),
+		NADDR (header.savep),
+		RADDR (temp),
+	SCR_RETURN,
+		0,
+	/*
+	**	Direction is DATA OUT.
+	*/
+	SCR_COPY (4),
+		NADDR (header.wlastp),
+		NADDR (header.lastp),
+	SCR_COPY (4),
+		NADDR (header.wgoalp),
+		NADDR (header.goalp),
+	SCR_JUMPR,
+		-64,
+}/*-------------------------< BAD_IDENTIFY >---------------*/,{
+	/*
+	**	If message phase but not an IDENTIFY,
+	**	get some help from the C code.
+	**	Old SCSI device may behave so.
+	*/
+	SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)),
+		16,
+	SCR_INT,
+		SIR_RESEL_NO_IDENTIFY,
+	SCR_JUMP,
+		PADDRH (reset),
+	/*
+	**	Message is an IDENTIFY, but lun is unknown.
+	**	Read the message, since we got it directly 
+	**	from the SCSI BUS data lines.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORT to clear all pending tasks.
+	*/
+	SCR_INT,
+		SIR_RESEL_BAD_LUN,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_JUMP,
+		PADDRH (abort),
+}/*-------------------------< BAD_I_T_L >------------------*/,{
+	/*
+	**	We donnot have a task for that I_T_L.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORT message.
+	*/
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L,
+	SCR_JUMP,
+		PADDRH (abort),
+}/*-------------------------< BAD_I_T_L_Q >----------------*/,{
+	/*
+	**	We donnot have a task that matches the tag.
+	**	Signal problem to C code for logging the event.
+	**	Send a M_ABORTTAG message.
+	*/
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L_Q,
+	SCR_JUMP,
+		PADDRH (aborttag),
+}/*-------------------------< BAD_TARGET >-----------------*/,{
+	/*
+	**	We donnot know the target that reselected us.
+	**	Grab the first message if any (IDENTIFY).
+	**	Signal problem to C code for logging the event.
+	**	M_RESET message.
+	*/
+	SCR_INT,
+		SIR_RESEL_BAD_TARGET,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		8,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin),
+	SCR_JUMP,
+		PADDRH (reset),
+}/*-------------------------< BAD_STATUS >-----------------*/,{
+	/*
+	**	If command resulted in either QUEUE FULL,
+	**	CHECK CONDITION or COMMAND TERMINATED,
+	**	call the C code.
+	*/
+	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
+		SIR_BAD_STATUS,
+	SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
+		SIR_BAD_STATUS,
+	SCR_INT ^ IFTRUE (DATA (S_TERMINATED)),
+		SIR_BAD_STATUS,
+	SCR_RETURN,
+		0,
+}/*-------------------------< START_RAM >-------------------*/,{
+	/*
+	**	Load the script into on-chip RAM, 
+	**	and jump to start point.
+	*/
+	SCR_COPY_F (4),
+		RADDR (scratcha),
+		PADDRH (start_ram0),
+	/*
+	**	Flush script prefetch if required
+	*/
+	PREFETCH_FLUSH
+	SCR_COPY (sizeof (struct script)),
+}/*-------------------------< START_RAM0 >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< STO_RESTART >-------------------*/,{
+	/*
+	**
+	**	Repair start queue (e.g. next time use the next slot) 
+	**	and jump to start point.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		PADDR (startpos),
+	SCR_JUMP,
+		PADDR (start),
+}/*-------------------------< WAIT_DMA >-------------------*/,{
+	/*
+	**	For HP Zalon/53c720 systems, the Zalon interface
+	**	between CPU and 53c720 does prefetches, which causes
+	**	problems with self modifying scripts.  The problem
+	**	is overcome by calling a dummy subroutine after each
+	**	modification, to force a refetch of the script on
+	**	return from the subroutine.
+	*/
+	SCR_RETURN,
+		0,
+}/*-------------------------< SNOOPTEST >-------------------*/,{
+	/*
+	**	Read the variable.
+	*/
+	SCR_COPY (4),
+		NADDR(ncr_cache),
+		RADDR (scratcha),
+	/*
+	**	Write the variable.
+	*/
+	SCR_COPY (4),
+		RADDR (temp),
+		NADDR(ncr_cache),
+	/*
+	**	Read back the variable.
+	*/
+	SCR_COPY (4),
+		NADDR(ncr_cache),
+		RADDR (temp),
+}/*-------------------------< SNOOPEND >-------------------*/,{
+	/*
+	**	And stop.
+	*/
+	SCR_INT,
+		99,
+}/*--------------------------------------------------------*/
+};
+
+/*==========================================================
+**
+**
+**	Fill in #define dependent parts of the script
+**
+**
+**==========================================================
+*/
+
+void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
+{
+	int	i;
+	ncrcmd	*p;
+
+	p = scrh->tryloop;
+	for (i=0; i<MAX_START; i++) {
+		*p++ =SCR_CALL;
+		*p++ =PADDR (idle);
+	}
+
+	BUG_ON((u_long)p != (u_long)&scrh->tryloop + sizeof (scrh->tryloop));
+
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+
+	p = scrh->done_queue;
+	for (i = 0; i<MAX_DONE; i++) {
+		*p++ =SCR_COPY (sizeof(struct ccb *));
+		*p++ =NADDR (header.cp);
+		*p++ =NADDR (ccb_done[i]);
+		*p++ =SCR_CALL;
+		*p++ =PADDR (done_end);
+	}
+
+	BUG_ON((u_long)p != (u_long)&scrh->done_queue+sizeof(scrh->done_queue));
+
+#endif /* SCSI_NCR_CCB_DONE_SUPPORT */
+
+	p = scrh->hdata_in;
+	for (i=0; i<MAX_SCATTERH; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+		*p++ =offsetof (struct dsb, data[i]);
+	}
+
+	BUG_ON((u_long)p != (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
+
+	p = scr->data_in;
+	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+		*p++ =offsetof (struct dsb, data[i]);
+	}
+
+	BUG_ON((u_long)p != (u_long)&scr->data_in + sizeof (scr->data_in));
+
+	p = scrh->hdata_out;
+	for (i=0; i<MAX_SCATTERH; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+		*p++ =offsetof (struct dsb, data[i]);
+	}
+
+	BUG_ON((u_long)p != (u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
+
+	p = scr->data_out;
+	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
+		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
+		*p++ =PADDR (dispatch);
+		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+		*p++ =offsetof (struct dsb, data[i]);
+	}
+
+	BUG_ON((u_long) p != (u_long)&scr->data_out + sizeof (scr->data_out));
+}
+
+/*==========================================================
+**
+**
+**	Copy and rebind a script.
+**
+**
+**==========================================================
+*/
+
+static void __init 
+ncr_script_copy_and_bind (struct ncb *np, ncrcmd *src, ncrcmd *dst, int len)
+{
+	ncrcmd  opcode, new, old, tmp1, tmp2;
+	ncrcmd	*start, *end;
+	int relocs;
+	int opchanged = 0;
+
+	start = src;
+	end = src + len/4;
+
+	while (src < end) {
+
+		opcode = *src++;
+		*dst++ = cpu_to_scr(opcode);
+
+		/*
+		**	If we forget to change the length
+		**	in struct script, a field will be
+		**	padded with 0. This is an illegal
+		**	command.
+		*/
+
+		if (opcode == 0) {
+			printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n",
+				ncr_name(np), (int) (src-start-1));
+			mdelay(1000);
+		}
+
+		if (DEBUG_FLAGS & DEBUG_SCRIPT)
+			printk (KERN_DEBUG "%p:  <%x>\n",
+				(src-1), (unsigned)opcode);
+
+		/*
+		**	We don't have to decode ALL commands
+		*/
+		switch (opcode >> 28) {
+
+		case 0xc:
+			/*
+			**	COPY has TWO arguments.
+			*/
+			relocs = 2;
+			tmp1 = src[0];
+#ifdef	RELOC_KVAR
+			if ((tmp1 & RELOC_MASK) == RELOC_KVAR)
+				tmp1 = 0;
+#endif
+			tmp2 = src[1];
+#ifdef	RELOC_KVAR
+			if ((tmp2 & RELOC_MASK) == RELOC_KVAR)
+				tmp2 = 0;
+#endif
+			if ((tmp1 ^ tmp2) & 3) {
+				printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n",
+					ncr_name(np), (int) (src-start-1));
+				mdelay(1000);
+			}
+			/*
+			**	If PREFETCH feature not enabled, remove 
+			**	the NO FLUSH bit if present.
+			*/
+			if ((opcode & SCR_NO_FLUSH) && !(np->features & FE_PFEN)) {
+				dst[-1] = cpu_to_scr(opcode & ~SCR_NO_FLUSH);
+				++opchanged;
+			}
+			break;
+
+		case 0x0:
+			/*
+			**	MOVE (absolute address)
+			*/
+			relocs = 1;
+			break;
+
+		case 0x8:
+			/*
+			**	JUMP / CALL
+			**	don't relocate if relative :-)
+			*/
+			if (opcode & 0x00800000)
+				relocs = 0;
+			else
+				relocs = 1;
+			break;
+
+		case 0x4:
+		case 0x5:
+		case 0x6:
+		case 0x7:
+			relocs = 1;
+			break;
+
+		default:
+			relocs = 0;
+			break;
+		}
+
+		if (relocs) {
+			while (relocs--) {
+				old = *src++;
+
+				switch (old & RELOC_MASK) {
+				case RELOC_REGISTER:
+					new = (old & ~RELOC_MASK) + np->paddr;
+					break;
+				case RELOC_LABEL:
+					new = (old & ~RELOC_MASK) + np->p_script;
+					break;
+				case RELOC_LABELH:
+					new = (old & ~RELOC_MASK) + np->p_scripth;
+					break;
+				case RELOC_SOFTC:
+					new = (old & ~RELOC_MASK) + np->p_ncb;
+					break;
+#ifdef	RELOC_KVAR
+				case RELOC_KVAR:
+					if (((old & ~RELOC_MASK) <
+					     SCRIPT_KVAR_FIRST) ||
+					    ((old & ~RELOC_MASK) >
+					     SCRIPT_KVAR_LAST))
+						panic("ncr KVAR out of range");
+					new = vtophys(script_kvars[old &
+					    ~RELOC_MASK]);
+					break;
+#endif
+				case 0:
+					/* Don't relocate a 0 address. */
+					if (old == 0) {
+						new = old;
+						break;
+					}
+					/* fall through */
+				default:
+					panic("ncr_script_copy_and_bind: weird relocation %x\n", old);
+					break;
+				}
+
+				*dst++ = cpu_to_scr(new);
+			}
+		} else
+			*dst++ = cpu_to_scr(*src++);
+
+	}
+}
+
+/*
+**	Linux host data structure
+*/
+
+struct host_data {
+     struct ncb *ncb;
+};
+
+#define PRINT_ADDR(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
+
+static void ncr_print_msg(struct ccb *cp, char *label, u_char *msg)
+{
+	int i;
+	PRINT_ADDR(cp->cmd, "%s: ", label);
+
+	printk ("%x",*msg);
+	if (*msg == M_EXTENDED) {
+		for (i = 1; i < 8; i++) {
+			if (i - 1 > msg[1])
+				break;
+			printk ("-%x",msg[i]);
+		}
+	} else if ((*msg & 0xf0) == 0x20) {
+		printk ("-%x",msg[1]);
+	}
+
+	printk(".\n");
+}
+
+/*==========================================================
+**
+**	NCR chip clock divisor table.
+**	Divisors are multiplied by 10,000,000 in order to make 
+**	calculations more simple.
+**
+**==========================================================
+*/
+
+#define _5M 5000000
+static u_long div_10M[] =
+	{2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
+
+
+/*===============================================================
+**
+**	Prepare io register values used by ncr_init() according 
+**	to selected and supported features.
+**
+**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
+**	transfers. 32,64,128 are only supported by 875 and 895 chips.
+**	We use log base 2 (burst length) as internal code, with 
+**	value 0 meaning "burst disabled".
+**
+**===============================================================
+*/
+
+/*
+ *	Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *	Burst code from io register bits.  Burst enable is ctest0 for c720
+ */
+#define burst_code(dmode, ctest0) \
+	(ctest0) & 0x80 ? 0 : (((dmode) & 0xc0) >> 6) + 1
+
+/*
+ *	Set initial io register bits from burst code.
+ */
+static inline void ncr_init_burst(struct ncb *np, u_char bc)
+{
+	u_char *be = &np->rv_ctest0;
+	*be		&= ~0x80;
+	np->rv_dmode	&= ~(0x3 << 6);
+	np->rv_ctest5	&= ~0x4;
+
+	if (!bc) {
+		*be		|= 0x80;
+	} else {
+		--bc;
+		np->rv_dmode	|= ((bc & 0x3) << 6);
+		np->rv_ctest5	|= (bc & 0x4);
+	}
+}
+
+static void __init ncr_prepare_setting(struct ncb *np)
+{
+	u_char	burst_max;
+	u_long	period;
+	int i;
+
+	/*
+	**	Save assumed BIOS setting
+	*/
+
+	np->sv_scntl0	= INB(nc_scntl0) & 0x0a;
+	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
+	np->sv_dmode	= INB(nc_dmode)  & 0xce;
+	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
+	np->sv_ctest0	= INB(nc_ctest0) & 0x84;
+	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
+	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
+	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
+	np->sv_gpcntl	= INB(nc_gpcntl);
+	np->sv_stest2	= INB(nc_stest2) & 0x20;
+	np->sv_stest4	= INB(nc_stest4);
+
+	/*
+	**	Wide ?
+	*/
+
+	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
+
+ 	/*
+	 *  Guess the frequency of the chip's clock.
+	 */
+	if (np->features & FE_ULTRA)
+		np->clock_khz = 80000;
+	else
+		np->clock_khz = 40000;
+
+	/*
+	 *  Get the clock multiplier factor.
+ 	 */
+	if	(np->features & FE_QUAD)
+		np->multiplier	= 4;
+	else if	(np->features & FE_DBLR)
+		np->multiplier	= 2;
+	else
+		np->multiplier	= 1;
+
+	/*
+	 *  Measure SCSI clock frequency for chips 
+	 *  it may vary from assumed one.
+	 */
+	if (np->features & FE_VARCLK)
+		ncr_getclock(np, np->multiplier);
+
+	/*
+	 * Divisor to be used for async (timer pre-scaler).
+	 */
+	i = np->clock_divn - 1;
+	while (--i >= 0) {
+		if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
+			++i;
+			break;
+		}
+	}
+	np->rv_scntl3 = i+1;
+
+	/*
+	 * Minimum synchronous period factor supported by the chip.
+	 * Btw, 'period' is in tenths of nanoseconds.
+	 */
+
+	period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
+	if	(period <= 250)		np->minsync = 10;
+	else if	(period <= 303)		np->minsync = 11;
+	else if	(period <= 500)		np->minsync = 12;
+	else				np->minsync = (period + 40 - 1) / 40;
+
+	/*
+	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+	 */
+
+	if	(np->minsync < 25 && !(np->features & FE_ULTRA))
+		np->minsync = 25;
+
+	/*
+	 * Maximum synchronous period factor supported by the chip.
+	 */
+
+	period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
+	np->maxsync = period > 2540 ? 254 : period / 10;
+
+	/*
+	**	Prepare initial value of other IO registers
+	*/
+#if defined SCSI_NCR_TRUST_BIOS_SETTING
+	np->rv_scntl0	= np->sv_scntl0;
+	np->rv_dmode	= np->sv_dmode;
+	np->rv_dcntl	= np->sv_dcntl;
+	np->rv_ctest0	= np->sv_ctest0;
+	np->rv_ctest3	= np->sv_ctest3;
+	np->rv_ctest4	= np->sv_ctest4;
+	np->rv_ctest5	= np->sv_ctest5;
+	burst_max	= burst_code(np->sv_dmode, np->sv_ctest0);
+#else
+
+	/*
+	**	Select burst length (dwords)
+	*/
+	burst_max	= driver_setup.burst_max;
+	if (burst_max == 255)
+		burst_max = burst_code(np->sv_dmode, np->sv_ctest0);
+	if (burst_max > 7)
+		burst_max = 7;
+	if (burst_max > np->maxburst)
+		burst_max = np->maxburst;
+
+	/*
+	**	Select all supported special features
+	*/
+	if (np->features & FE_ERL)
+		np->rv_dmode	|= ERL;		/* Enable Read Line */
+	if (np->features & FE_BOF)
+		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
+	if (np->features & FE_ERMP)
+		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
+	if (np->features & FE_PFEN)
+		np->rv_dcntl	|= PFEN;	/* Prefetch Enable */
+	if (np->features & FE_CLSE)
+		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
+	if (np->features & FE_WRIE)
+		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
+	if (np->features & FE_DFS)
+		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+	if (np->features & FE_MUX)
+		np->rv_ctest4	|= MUX;		/* Host bus multiplex mode */
+	if (np->features & FE_EA)
+		np->rv_dcntl	|= EA;		/* Enable ACK */
+	if (np->features & FE_EHP)
+		np->rv_ctest0	|= EHP;		/* Even host parity */
+
+	/*
+	**	Select some other
+	*/
+	if (driver_setup.master_parity)
+		np->rv_ctest4	|= MPEE;	/* Master parity checking */
+	if (driver_setup.scsi_parity)
+		np->rv_scntl0	|= 0x0a;	/*  full arb., ena parity, par->ATN  */
+
+	/*
+	**  Get SCSI addr of host adapter (set by bios?).
+	*/
+	if (np->myaddr == 255) {
+		np->myaddr = INB(nc_scid) & 0x07;
+		if (!np->myaddr)
+			np->myaddr = SCSI_NCR_MYADDR;
+	}
+
+#endif /* SCSI_NCR_TRUST_BIOS_SETTING */
+
+	/*
+	 *	Prepare initial io register bits for burst length
+	 */
+	ncr_init_burst(np, burst_max);
+
+	/*
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if (np->features & FE_DIFF) {
+		switch(driver_setup.diff_support) {
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (INB(nc_gpreg) & 0x08)
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
+			break;
+		default:/* Don't care about HVD */	
+			break;
+		}
+	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
+	if ((driver_setup.led_pin) &&
+	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
+		np->features |= FE_LED0;
+
+	/*
+	**	Set irq mode.
+	*/
+	switch(driver_setup.irqm & 3) {
+	case 2:
+		np->rv_dcntl	|= IRQM;
+		break;
+	case 1:
+		np->rv_dcntl	|= (np->sv_dcntl & IRQM);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	**	Configure targets according to driver setup.
+	**	Allow to override sync, wide and NOSCAN from 
+	**	boot command line.
+	*/
+	for (i = 0 ; i < MAX_TARGET ; i++) {
+		struct tcb *tp = &np->target[i];
+
+		tp->usrsync = driver_setup.default_sync;
+		tp->usrwide = driver_setup.max_wide;
+		tp->usrtags = MAX_TAGS;
+		tp->period = 0xffff;
+		if (!driver_setup.disconnection)
+			np->target[i].usrflag = UF_NODISC;
+	}
+
+	/*
+	**	Announce all that stuff to user.
+	*/
+
+	printk(KERN_INFO "%s: ID %d, Fast-%d%s%s\n", ncr_name(np),
+		np->myaddr,
+		np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10),
+		(np->rv_scntl0 & 0xa)	? ", Parity Checking"	: ", NO Parity",
+		(np->rv_stest2 & 0x20)	? ", Differential"	: "");
+
+	if (bootverbose > 1) {
+		printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
+			np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+
+		printk (KERN_INFO "%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
+			np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+	}
+
+	if (bootverbose && np->paddr2)
+		printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n",
+			ncr_name(np), np->paddr2);
+}
+
+/*==========================================================
+**
+**
+**	Done SCSI commands list management.
+**
+**	We donnot enter the scsi_done() callback immediately 
+**	after a command has been seen as completed but we 
+**	insert it into a list which is flushed outside any kind 
+**	of driver critical section.
+**	This allows to do minimal stuff under interrupt and 
+**	inside critical sections and to also avoid locking up 
+**	on recursive calls to driver entry points under SMP.
+**	In fact, the only kernel point which is entered by the 
+**	driver with a driver lock set is kmalloc(GFP_ATOMIC) 
+**	that shall not reenter the driver under any circumstances,
+**	AFAIK.
+**
+**==========================================================
+*/
+static inline void ncr_queue_done_cmd(struct ncb *np, struct scsi_cmnd *cmd)
+{
+	unmap_scsi_data(np, cmd);
+	cmd->host_scribble = (char *) np->done_list;
+	np->done_list = cmd;
+}
+
+static inline void ncr_flush_done_cmds(struct scsi_cmnd *lcmd)
+{
+	struct scsi_cmnd *cmd;
+
+	while (lcmd) {
+		cmd = lcmd;
+		lcmd = (struct scsi_cmnd *) cmd->host_scribble;
+		cmd->scsi_done(cmd);
+	}
+}
+
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+
+static int ncr_prepare_nego(struct ncb *np, struct ccb *cp, u_char *msgptr)
+{
+	struct tcb *tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+	struct scsi_target *starget = tp->starget;
+
+	/* negotiate wide transfers ?  */
+	if (!tp->widedone) {
+		if (spi_support_wide(starget)) {
+			nego = NS_WIDE;
+		} else
+			tp->widedone=1;
+	}
+
+	/* negotiate synchronous transfers?  */
+	if (!nego && !tp->period) {
+		if (spi_support_sync(starget)) {
+			nego = NS_SYNC;
+		} else {
+			tp->period  =0xffff;
+			dev_info(&starget->dev, "target did not report SYNC.\n");
+		}
+	}
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+		msgptr[msglen++] = tp->maxoffs;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = tp->usrwide;
+		break;
+	}
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+					  "wide msgout":"sync_msgout", msgptr);
+		}
+	}
+
+	return msglen;
+}
+
+
+
+/*==========================================================
+**
+**
+**	Start execution of a SCSI command.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+static int ncr_queue_command (struct ncb *np, struct scsi_cmnd *cmd)
+{
+	struct scsi_device *sdev = cmd->device;
+	struct tcb *tp = &np->target[sdev->id];
+	struct lcb *lp = tp->lp[sdev->lun];
+	struct ccb *cp;
+
+	int	segments;
+	u_char	idmsg, *msgptr;
+	u32	msglen;
+	int	direction;
+	u32	lastp, goalp;
+
+	/*---------------------------------------------
+	**
+	**      Some shortcuts ...
+	**
+	**---------------------------------------------
+	*/
+	if ((sdev->id == np->myaddr	  ) ||
+		(sdev->id >= MAX_TARGET) ||
+		(sdev->lun    >= MAX_LUN   )) {
+		return(DID_BAD_TARGET);
+	}
+
+	/*---------------------------------------------
+	**
+	**	Complete the 1st TEST UNIT READY command
+	**	with error condition if the device is 
+	**	flagged NOSCAN, in order to speed up 
+	**	the boot.
+	**
+	**---------------------------------------------
+	*/
+	if ((cmd->cmnd[0] == 0 || cmd->cmnd[0] == 0x12) && 
+	    (tp->usrflag & UF_NOSCAN)) {
+		tp->usrflag &= ~UF_NOSCAN;
+		return DID_BAD_TARGET;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_TINY) {
+		PRINT_ADDR(cmd, "CMD=%x ", cmd->cmnd[0]);
+	}
+
+	/*---------------------------------------------------
+	**
+	**	Assign a ccb / bind cmd.
+	**	If resetting, shorten settle_time if necessary
+	**	in order to avoid spurious timeouts.
+	**	If resetting or no free ccb,
+	**	insert cmd into the waiting list.
+	**
+	**----------------------------------------------------
+	*/
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
+	}
+
+	if (np->settle_time || !(cp=ncr_get_ccb (np, cmd))) {
+		insert_into_waiting_list(np, cmd);
+		return(DID_OK);
+	}
+	cp->cmd = cmd;
+
+	/*----------------------------------------------------
+	**
+	**	Build the identify / tag / sdtr message
+	**
+	**----------------------------------------------------
+	*/
+
+	idmsg = M_IDENTIFY | sdev->lun;
+
+	if (cp ->tag != NO_TAG ||
+		(cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC)))
+		idmsg |= 0x40;
+
+	msgptr = cp->scsi_smsg;
+	msglen = 0;
+	msgptr[msglen++] = idmsg;
+
+	if (cp->tag != NO_TAG) {
+		char order = np->order;
+
+		/*
+		**	Force ordered tag if necessary to avoid timeouts 
+		**	and to preserve interactivity.
+		*/
+		if (lp && ktime_exp(lp->tags_stime)) {
+			if (lp->tags_smap) {
+				order = M_ORDERED_TAG;
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
+					PRINT_ADDR(cmd,
+						"ordered tag forced.\n");
+				}
+			}
+			lp->tags_stime = ktime_get(3*HZ);
+			lp->tags_smap = lp->tags_umap;
+		}
+
+		if (order == 0) {
+			/*
+			**	Ordered write ops, unordered read ops.
+			*/
+			switch (cmd->cmnd[0]) {
+			case 0x08:  /* READ_SMALL (6) */
+			case 0x28:  /* READ_BIG  (10) */
+			case 0xa8:  /* READ_HUGE (12) */
+				order = M_SIMPLE_TAG;
+				break;
+			default:
+				order = M_ORDERED_TAG;
+			}
+		}
+		msgptr[msglen++] = order;
+		/*
+		**	Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
+		**	since we may have to deal with devices that have 
+		**	problems with #TAG 0 or too great #TAG numbers.
+		*/
+		msgptr[msglen++] = (cp->tag << 1) + 1;
+	}
+
+	/*----------------------------------------------------
+	**
+	**	Build the data descriptors
+	**
+	**----------------------------------------------------
+	*/
+
+	direction = cmd->sc_data_direction;
+	if (direction != DMA_NONE) {
+		segments = ncr_scatter(np, cp, cp->cmd);
+		if (segments < 0) {
+			ncr_free_ccb(np, cp);
+			return(DID_ERROR);
+		}
+	}
+	else {
+		cp->data_len = 0;
+		segments = 0;
+	}
+
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
+	*/
+
+	cp->nego_status = 0;
+
+	if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+		msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
+	}
+
+	/*----------------------------------------------------
+	**
+	**	Determine xfer direction.
+	**
+	**----------------------------------------------------
+	*/
+	if (!cp->data_len)
+		direction = DMA_NONE;
+
+	/*
+	**	If data direction is BIDIRECTIONAL, speculate FROM_DEVICE
+	**	but prepare alternate pointers for TO_DEVICE in case 
+	**	of our speculation will be just wrong.
+	**	SCRIPTS will swap values if needed.
+	*/
+	switch(direction) {
+	case DMA_BIDIRECTIONAL:
+	case DMA_TO_DEVICE:
+		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
+		if (segments <= MAX_SCATTERL)
+			lastp = goalp - 8 - (segments * 16);
+		else {
+			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
+			lastp -= (segments - MAX_SCATTERL) * 16;
+		}
+		if (direction != DMA_BIDIRECTIONAL)
+			break;
+		cp->phys.header.wgoalp	= cpu_to_scr(goalp);
+		cp->phys.header.wlastp	= cpu_to_scr(lastp);
+		/* fall through */
+	case DMA_FROM_DEVICE:
+		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
+		if (segments <= MAX_SCATTERL)
+			lastp = goalp - 8 - (segments * 16);
+		else {
+			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
+			lastp -= (segments - MAX_SCATTERL) * 16;
+		}
+		break;
+	default:
+	case DMA_NONE:
+		lastp = goalp = NCB_SCRIPT_PHYS (np, no_data);
+		break;
+	}
+
+	/*
+	**	Set all pointers values needed by SCRIPTS.
+	**	If direction is unknown, start at data_io.
+	*/
+	cp->phys.header.lastp = cpu_to_scr(lastp);
+	cp->phys.header.goalp = cpu_to_scr(goalp);
+
+	if (direction == DMA_BIDIRECTIONAL)
+		cp->phys.header.savep = 
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io));
+	else
+		cp->phys.header.savep= cpu_to_scr(lastp);
+
+	/*
+	**	Save the initial data pointer in order to be able 
+	**	to redo the command.
+	*/
+	cp->startp = cp->phys.header.savep;
+
+	/*----------------------------------------------------
+	**
+	**	fill in ccb
+	**
+	**----------------------------------------------------
+	**
+	**
+	**	physical -> virtual backlink
+	**	Generic SCSI command
+	*/
+
+	/*
+	**	Startqueue
+	*/
+	cp->start.schedule.l_paddr   = cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+	cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_dsa));
+	/*
+	**	select
+	*/
+	cp->phys.select.sel_id		= sdev->id;
+	cp->phys.select.sel_scntl3	= tp->wval;
+	cp->phys.select.sel_sxfer	= tp->sval;
+	/*
+	**	message
+	*/
+	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size		= cpu_to_scr(msglen);
+
+	/*
+	**	command
+	*/
+	memcpy(cp->cdb_buf, cmd->cmnd, min_t(int, cmd->cmd_len, sizeof(cp->cdb_buf)));
+	cp->phys.cmd.addr		= cpu_to_scr(CCB_PHYS (cp, cdb_buf[0]));
+	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
+
+	/*
+	**	status
+	*/
+	cp->actualquirks		= 0;
+	cp->host_status			= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+	cp->scsi_status			= S_ILLEGAL;
+	cp->parity_status		= 0;
+
+	cp->xerr_status			= XE_OK;
+#if 0
+	cp->sync_status			= tp->sval;
+	cp->wide_status			= tp->wval;
+#endif
+
+	/*----------------------------------------------------
+	**
+	**	Critical region: start this job.
+	**
+	**----------------------------------------------------
+	*/
+
+	/* activate this job.  */
+	cp->magic		= CCB_MAGIC;
+
+	/*
+	**	insert next CCBs into start queue.
+	**	2 max at a time is enough to flush the CCB wait queue.
+	*/
+	cp->auto_sense = 0;
+	if (lp)
+		ncr_start_next_ccb(np, lp, 2);
+	else
+		ncr_put_start_queue(np, cp);
+
+	/* Command is successfully queued.  */
+
+	return DID_OK;
+}
+
+
+/*==========================================================
+**
+**
+**	Insert a CCB into the start queue and wake up the 
+**	SCRIPTS processor.
+**
+**
+**==========================================================
+*/
+
+static void ncr_start_next_ccb(struct ncb *np, struct lcb *lp, int maxn)
+{
+	struct list_head *qp;
+	struct ccb *cp;
+
+	if (lp->held_ccb)
+		return;
+
+	while (maxn-- && lp->queuedccbs < lp->queuedepth) {
+		qp = ncr_list_pop(&lp->wait_ccbq);
+		if (!qp)
+			break;
+		++lp->queuedccbs;
+		cp = list_entry(qp, struct ccb, link_ccbq);
+		list_add_tail(qp, &lp->busy_ccbq);
+		lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag] =
+			cpu_to_scr(CCB_PHYS (cp, restart));
+		ncr_put_start_queue(np, cp);
+	}
+}
+
+static void ncr_put_start_queue(struct ncb *np, struct ccb *cp)
+{
+	u16	qidx;
+
+	/*
+	**	insert into start queue.
+	*/
+	if (!np->squeueput) np->squeueput = 1;
+	qidx = np->squeueput + 2;
+	if (qidx >= MAX_START + MAX_START) qidx = 1;
+
+	np->scripth->tryloop [qidx] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	MEMORY_BARRIER();
+	np->scripth->tryloop [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, start));
+
+	np->squeueput = qidx;
+	++np->queuedccbs;
+	cp->queued = 1;
+
+	if (DEBUG_FLAGS & DEBUG_QUEUE)
+		printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput);
+
+	/*
+	**	Script processor may be waiting for reselect.
+	**	Wake it up.
+	*/
+	MEMORY_BARRIER();
+	OUTB (nc_istat, SIGP);
+}
+
+
+static int ncr_reset_scsi_bus(struct ncb *np, int enab_int, int settle_delay)
+{
+	u32 term;
+	int retv = 0;
+
+	np->settle_time	= ktime_get(settle_delay * HZ);
+
+	if (bootverbose > 1)
+		printk("%s: resetting, "
+			"command processing suspended for %d seconds\n",
+			ncr_name(np), settle_delay);
+
+	ncr_chip_reset(np, 100);
+	udelay(2000);	/* The 895 needs time for the bus mode to settle */
+	if (enab_int)
+		OUTW (nc_sien, RST);
+	/*
+	**	Enable Tolerant, reset IRQD if present and 
+	**	properly set IRQ mode, prior to resetting the bus.
+	*/
+	OUTB (nc_stest3, TE);
+	OUTB (nc_scntl1, CRST);
+	udelay(200);
+
+	if (!driver_setup.bus_check)
+		goto out;
+	/*
+	**	Check for no terminators or SCSI bus shorts to ground.
+	**	Read SCSI data bus, data parity bits and control signals.
+	**	We are expecting RESET to be TRUE and other signals to be 
+	**	FALSE.
+	*/
+
+	term =	INB(nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(nc_sbcl);	/* req ack bsy sel atn msg cd io    */
+
+	if (!(np->features & FE_WIDE))
+		term &= 0x3ffff;
+
+	if (term != (2<<7)) {
+		printk("%s: suspicious SCSI data while resetting the BUS.\n",
+			ncr_name(np));
+		printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+			"0x%lx, expecting 0x%lx\n",
+			ncr_name(np),
+			(np->features & FE_WIDE) ? "dp1,d15-8," : "",
+			(u_long)term, (u_long)(2<<7));
+		if (driver_setup.bus_check == 1)
+			retv = 1;
+	}
+out:
+	OUTB (nc_scntl1, 0);
+	return retv;
+}
+
+/*
+ * Start reset process.
+ * If reset in progress do nothing.
+ * The interrupt handler will reinitialize the chip.
+ * The timeout handler will wait for settle_time before 
+ * clearing it and so resuming command processing.
+ */
+static void ncr_start_reset(struct ncb *np)
+{
+	if (!np->settle_time) {
+		ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+ 	}
+}
+ 
+/*==========================================================
+**
+**
+**	Reset the SCSI BUS.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+static int ncr_reset_bus (struct ncb *np, struct scsi_cmnd *cmd, int sync_reset)
+{
+/*	struct scsi_device        *device    = cmd->device; */
+	struct ccb *cp;
+	int found;
+
+/*
+ * Return immediately if reset is in progress.
+ */
+	if (np->settle_time) {
+		return FAILED;
+	}
+/*
+ * Start the reset process.
+ * The script processor is then assumed to be stopped.
+ * Commands will now be queued in the waiting list until a settle 
+ * delay of 2 seconds will be completed.
+ */
+	ncr_start_reset(np);
+/*
+ * First, look in the wakeup list
+ */
+	for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
+		/*
+		**	look for the ccb of this command.
+		*/
+		if (cp->host_status == HS_IDLE) continue;
+		if (cp->cmd == cmd) {
+			found = 1;
+			break;
+		}
+	}
+/*
+ * Then, look in the waiting list
+ */
+	if (!found && retrieve_from_waiting_list(0, np, cmd))
+		found = 1;
+/*
+ * Wake-up all awaiting commands with DID_RESET.
+ */
+	reset_waiting_list(np);
+/*
+ * Wake-up all pending commands with HS_RESET -> DID_RESET.
+ */
+	ncr_wakeup(np, HS_RESET);
+/*
+ * If the involved command was not in a driver queue, and the 
+ * scsi driver told us reset is synchronous, and the command is not 
+ * currently in the waiting list, complete it with DID_RESET status,
+ * in order to keep it alive.
+ */
+	if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) {
+		cmd->result = ScsiResult(DID_RESET, 0);
+		ncr_queue_done_cmd(np, cmd);
+	}
+
+	return SUCCESS;
+}
+
+#if 0 /* unused and broken.. */
+/*==========================================================
+**
+**
+**	Abort an SCSI command.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+static int ncr_abort_command (struct ncb *np, struct scsi_cmnd *cmd)
+{
+/*	struct scsi_device        *device    = cmd->device; */
+	struct ccb *cp;
+	int found;
+	int retv;
+
+/*
+ * First, look for the scsi command in the waiting list
+ */
+	if (remove_from_waiting_list(np, cmd)) {
+		cmd->result = ScsiResult(DID_ABORT, 0);
+		ncr_queue_done_cmd(np, cmd);
+		return SCSI_ABORT_SUCCESS;
+	}
+
+/*
+ * Then, look in the wakeup list
+ */
+	for (found=0, cp=np->ccb; cp; cp=cp->link_ccb) {
+		/*
+		**	look for the ccb of this command.
+		*/
+		if (cp->host_status == HS_IDLE) continue;
+		if (cp->cmd == cmd) {
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found) {
+		return SCSI_ABORT_NOT_RUNNING;
+	}
+
+	if (np->settle_time) {
+		return SCSI_ABORT_SNOOZE;
+	}
+
+	/*
+	**	If the CCB is active, patch schedule jumps for the 
+	**	script to abort the command.
+	*/
+
+	switch(cp->host_status) {
+	case HS_BUSY:
+	case HS_NEGOTIATE:
+		printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
+			cp->start.schedule.l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
+		retv = SCSI_ABORT_PENDING;
+		break;
+	case HS_DISCONNECT:
+		cp->restart.schedule.l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+		retv = SCSI_ABORT_PENDING;
+		break;
+	default:
+		retv = SCSI_ABORT_NOT_RUNNING;
+		break;
+
+	}
+
+	/*
+	**      If there are no requests, the script
+	**      processor will sleep on SEL_WAIT_RESEL.
+	**      Let's wake it up, since it may have to work.
+	*/
+	OUTB (nc_istat, SIGP);
+
+	return retv;
+}
+#endif
+
+static void ncr_detach(struct ncb *np)
+{
+	struct ccb *cp;
+	struct tcb *tp;
+	struct lcb *lp;
+	int target, lun;
+	int i;
+	char inst_name[16];
+
+	/* Local copy so we don't access np after freeing it! */
+	strlcpy(inst_name, ncr_name(np), sizeof(inst_name));
+
+	printk("%s: releasing host resources\n", ncr_name(np));
+
+/*
+**	Stop the ncr_timeout process
+**	Set release_stage to 1 and wait that ncr_timeout() set it to 2.
+*/
+
+#ifdef DEBUG_NCR53C8XX
+	printk("%s: stopping the timer\n", ncr_name(np));
+#endif
+	np->release_stage = 1;
+	for (i = 50 ; i && np->release_stage != 2 ; i--)
+		mdelay(100);
+	if (np->release_stage != 2)
+		printk("%s: the timer seems to be already stopped\n", ncr_name(np));
+	else np->release_stage = 2;
+
+/*
+**	Disable chip interrupts
+*/
+
+#ifdef DEBUG_NCR53C8XX
+	printk("%s: disabling chip interrupts\n", ncr_name(np));
+#endif
+	OUTW (nc_sien , 0);
+	OUTB (nc_dien , 0);
+
+	/*
+	**	Reset NCR chip
+	**	Restore bios setting for automatic clock detection.
+	*/
+
+	printk("%s: resetting chip\n", ncr_name(np));
+	ncr_chip_reset(np, 100);
+
+	OUTB(nc_dmode,	np->sv_dmode);
+	OUTB(nc_dcntl,	np->sv_dcntl);
+	OUTB(nc_ctest0,	np->sv_ctest0);
+	OUTB(nc_ctest3,	np->sv_ctest3);
+	OUTB(nc_ctest4,	np->sv_ctest4);
+	OUTB(nc_ctest5,	np->sv_ctest5);
+	OUTB(nc_gpcntl,	np->sv_gpcntl);
+	OUTB(nc_stest2,	np->sv_stest2);
+
+	ncr_selectclock(np, np->sv_scntl3);
+
+	/*
+	**	Free allocated ccb(s)
+	*/
+
+	while ((cp=np->ccb->link_ccb) != NULL) {
+		np->ccb->link_ccb = cp->link_ccb;
+		if (cp->host_status) {
+		printk("%s: shall free an active ccb (host_status=%d)\n",
+			ncr_name(np), cp->host_status);
+		}
+#ifdef DEBUG_NCR53C8XX
+	printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp);
+#endif
+		m_free_dma(cp, sizeof(*cp), "CCB");
+	}
+
+	/* Free allocated tp(s) */
+
+	for (target = 0; target < MAX_TARGET ; target++) {
+		tp=&np->target[target];
+		for (lun = 0 ; lun < MAX_LUN ; lun++) {
+			lp = tp->lp[lun];
+			if (lp) {
+#ifdef DEBUG_NCR53C8XX
+	printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp);
+#endif
+				if (lp->jump_ccb != &lp->jump_ccb_0)
+					m_free_dma(lp->jump_ccb,256,"JUMP_CCB");
+				m_free_dma(lp, sizeof(*lp), "LCB");
+			}
+		}
+	}
+
+	if (np->scripth0)
+		m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+	if (np->script0)
+		m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+	if (np->ccb)
+		m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+	m_free_dma(np, sizeof(struct ncb), "NCB");
+
+	printk("%s: host resources successfully released\n", inst_name);
+}
+
+/*==========================================================
+**
+**
+**	Complete execution of a SCSI command.
+**	Signal completion to the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+
+void ncr_complete (struct ncb *np, struct ccb *cp)
+{
+	struct scsi_cmnd *cmd;
+	struct tcb *tp;
+	struct lcb *lp;
+
+	/*
+	**	Sanity check
+	*/
+
+	if (!cp || cp->magic != CCB_MAGIC || !cp->cmd)
+		return;
+
+	/*
+	**	Print minimal debug information.
+	*/
+
+	if (DEBUG_FLAGS & DEBUG_TINY)
+		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
+			cp->host_status,cp->scsi_status);
+
+	/*
+	**	Get command, target and lun pointers.
+	*/
+
+	cmd = cp->cmd;
+	cp->cmd = NULL;
+	tp = &np->target[cmd->device->id];
+	lp = tp->lp[cmd->device->lun];
+
+	/*
+	**	We donnot queue more than 1 ccb per target 
+	**	with negotiation at any time. If this ccb was 
+	**	used for negotiation, clear this info in the tcb.
+	*/
+
+	if (cp == tp->nego_cp)
+		tp->nego_cp = NULL;
+
+	/*
+	**	If auto-sense performed, change scsi status.
+	*/
+	if (cp->auto_sense) {
+		cp->scsi_status = cp->auto_sense;
+	}
+
+	/*
+	**	If we were recovering from queue full or performing 
+	**	auto-sense, requeue skipped CCBs to the wait queue.
+	*/
+
+	if (lp && lp->held_ccb) {
+		if (cp == lp->held_ccb) {
+			list_splice_init(&lp->skip_ccbq, &lp->wait_ccbq);
+			lp->held_ccb = NULL;
+		}
+	}
+
+	/*
+	**	Check for parity errors.
+	*/
+
+	if (cp->parity_status > 1) {
+		PRINT_ADDR(cmd, "%d parity error(s).\n",cp->parity_status);
+	}
+
+	/*
+	**	Check for extended errors.
+	*/
+
+	if (cp->xerr_status != XE_OK) {
+		switch (cp->xerr_status) {
+		case XE_EXTRA_DATA:
+			PRINT_ADDR(cmd, "extraneous data discarded.\n");
+			break;
+		case XE_BAD_PHASE:
+			PRINT_ADDR(cmd, "invalid scsi phase (4/5).\n");
+			break;
+		default:
+			PRINT_ADDR(cmd, "extended error %d.\n",
+					cp->xerr_status);
+			break;
+		}
+		if (cp->host_status==HS_COMPLETE)
+			cp->host_status = HS_FAIL;
+	}
+
+	/*
+	**	Print out any error for debugging purpose.
+	*/
+	if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
+		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+			PRINT_ADDR(cmd, "ERROR: cmd=%x host_status=%x "
+					"scsi_status=%x\n", cmd->cmnd[0],
+					cp->host_status, cp->scsi_status);
+		}
+	}
+
+	/*
+	**	Check the status.
+	*/
+	if (   (cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_GOOD ||
+		    cp->scsi_status == S_COND_MET)) {
+		/*
+		 *	All went well (GOOD status).
+		 *	CONDITION MET status is returned on 
+		 *	`Pre-Fetch' or `Search data' success.
+		 */
+		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
+
+		/*
+		**	@RESID@
+		**	Could dig out the correct value for resid,
+		**	but it would be quite complicated.
+		*/
+		/* if (cp->phys.header.lastp != cp->phys.header.goalp) */
+
+		/*
+		**	Allocate the lcb if not yet.
+		*/
+		if (!lp)
+			ncr_alloc_lcb (np, cmd->device->id, cmd->device->lun);
+
+		tp->bytes     += cp->data_len;
+		tp->transfers ++;
+
+		/*
+		**	If tags was reduced due to queue full,
+		**	increase tags if 1000 good status received.
+		*/
+		if (lp && lp->usetags && lp->numtags < lp->maxtags) {
+			++lp->num_good;
+			if (lp->num_good >= 1000) {
+				lp->num_good = 0;
+				++lp->numtags;
+				ncr_setup_tags (np, cmd->device);
+			}
+		}
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_CHECK_COND)) {
+		/*
+		**   Check condition code
+		*/
+		cmd->result = ScsiResult(DID_OK, S_CHECK_COND);
+
+		/*
+		**	Copy back sense data to caller's buffer.
+		*/
+		memcpy(cmd->sense_buffer, cp->sense_buf,
+		       min(sizeof(cmd->sense_buffer), sizeof(cp->sense_buf)));
+
+		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
+			u_char * p = (u_char*) & cmd->sense_buffer;
+			int i;
+			PRINT_ADDR(cmd, "sense data:");
+			for (i=0; i<14; i++) printk (" %x", *p++);
+			printk (".\n");
+		}
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_CONFLICT)) {
+		/*
+		**   Reservation Conflict condition code
+		*/
+		cmd->result = ScsiResult(DID_OK, S_CONFLICT);
+	
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_BUSY ||
+		    cp->scsi_status == S_QUEUE_FULL)) {
+
+		/*
+		**   Target is busy.
+		*/
+		cmd->result = ScsiResult(DID_OK, cp->scsi_status);
+
+	} else if ((cp->host_status == HS_SEL_TIMEOUT)
+		|| (cp->host_status == HS_TIMEOUT)) {
+
+		/*
+		**   No response
+		*/
+		cmd->result = ScsiResult(DID_TIME_OUT, cp->scsi_status);
+
+	} else if (cp->host_status == HS_RESET) {
+
+		/*
+		**   SCSI bus reset
+		*/
+		cmd->result = ScsiResult(DID_RESET, cp->scsi_status);
+
+	} else if (cp->host_status == HS_ABORTED) {
+
+		/*
+		**   Transfer aborted
+		*/
+		cmd->result = ScsiResult(DID_ABORT, cp->scsi_status);
+
+	} else {
+
+		/*
+		**  Other protocol messes
+		*/
+		PRINT_ADDR(cmd, "COMMAND FAILED (%x %x) @%p.\n",
+			cp->host_status, cp->scsi_status, cp);
+
+		cmd->result = ScsiResult(DID_ERROR, cp->scsi_status);
+	}
+
+	/*
+	**	trace output
+	*/
+
+	if (tp->usrflag & UF_TRACE) {
+		u_char * p;
+		int i;
+		PRINT_ADDR(cmd, " CMD:");
+		p = (u_char*) &cmd->cmnd[0];
+		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
+
+		if (cp->host_status==HS_COMPLETE) {
+			switch (cp->scsi_status) {
+			case S_GOOD:
+				printk ("  GOOD");
+				break;
+			case S_CHECK_COND:
+				printk ("  SENSE:");
+				p = (u_char*) &cmd->sense_buffer;
+				for (i=0; i<14; i++)
+					printk (" %x", *p++);
+				break;
+			default:
+				printk ("  STAT: %x\n", cp->scsi_status);
+				break;
+			}
+		} else printk ("  HOSTERROR: %x", cp->host_status);
+		printk ("\n");
+	}
+
+	/*
+	**	Free this ccb
+	*/
+	ncr_free_ccb (np, cp);
+
+	/*
+	**	requeue awaiting scsi commands for this lun.
+	*/
+	if (lp && lp->queuedccbs < lp->queuedepth &&
+	    !list_empty(&lp->wait_ccbq))
+		ncr_start_next_ccb(np, lp, 2);
+
+	/*
+	**	requeue awaiting scsi commands for this controller.
+	*/
+	if (np->waiting_list)
+		requeue_waiting_list(np);
+
+	/*
+	**	signal completion to generic driver.
+	*/
+	ncr_queue_done_cmd(np, cmd);
+}
+
+/*==========================================================
+**
+**
+**	Signal all (or one) control block done.
+**
+**
+**==========================================================
+*/
+
+/*
+**	This CCB has been skipped by the NCR.
+**	Queue it in the correponding unit queue.
+*/
+static void ncr_ccb_skipped(struct ncb *np, struct ccb *cp)
+{
+	struct tcb *tp = &np->target[cp->target];
+	struct lcb *lp = tp->lp[cp->lun];
+
+	if (lp && cp != np->ccb) {
+		cp->host_status &= ~HS_SKIPMASK;
+		cp->start.schedule.l_paddr = 
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+		list_del(&cp->link_ccbq);
+		list_add_tail(&cp->link_ccbq, &lp->skip_ccbq);
+		if (cp->queued) {
+			--lp->queuedccbs;
+		}
+	}
+	if (cp->queued) {
+		--np->queuedccbs;
+		cp->queued = 0;
+	}
+}
+
+/*
+**	The NCR has completed CCBs.
+**	Look at the DONE QUEUE if enabled, otherwise scan all CCBs
+*/
+void ncr_wakeup_done (struct ncb *np)
+{
+	struct ccb *cp;
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	int i, j;
+
+	i = np->ccb_done_ic;
+	while (1) {
+		j = i+1;
+		if (j >= MAX_DONE)
+			j = 0;
+
+		cp = np->ccb_done[j];
+		if (!CCB_DONE_VALID(cp))
+			break;
+
+		np->ccb_done[j] = (struct ccb *)CCB_DONE_EMPTY;
+		np->scripth->done_queue[5*j + 4] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
+		MEMORY_BARRIER();
+		np->scripth->done_queue[5*i + 4] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
+
+		if (cp->host_status & HS_DONEMASK)
+			ncr_complete (np, cp);
+		else if (cp->host_status & HS_SKIPMASK)
+			ncr_ccb_skipped (np, cp);
+
+		i = j;
+	}
+	np->ccb_done_ic = i;
+#else
+	cp = np->ccb;
+	while (cp) {
+		if (cp->host_status & HS_DONEMASK)
+			ncr_complete (np, cp);
+		else if (cp->host_status & HS_SKIPMASK)
+			ncr_ccb_skipped (np, cp);
+		cp = cp->link_ccb;
+	}
+#endif
+}
+
+/*
+**	Complete all active CCBs.
+*/
+void ncr_wakeup (struct ncb *np, u_long code)
+{
+	struct ccb *cp = np->ccb;
+
+	while (cp) {
+		if (cp->host_status != HS_IDLE) {
+			cp->host_status = code;
+			ncr_complete (np, cp);
+		}
+		cp = cp->link_ccb;
+	}
+}
+
+/*
+** Reset ncr chip.
+*/
+
+/* Some initialisation must be done immediately following reset, for 53c720,
+ * at least.  EA (dcntl bit 5) isn't set here as it is set once only in
+ * the _detect function.
+ */
+static void ncr_chip_reset(struct ncb *np, int delay)
+{
+	OUTB (nc_istat,  SRST);
+	udelay(delay);
+	OUTB (nc_istat,  0   );
+
+	if (np->features & FE_EHP)
+		OUTB (nc_ctest0, EHP);
+	if (np->features & FE_MUX)
+		OUTB (nc_ctest4, MUX);
+}
+
+
+/*==========================================================
+**
+**
+**	Start NCR chip.
+**
+**
+**==========================================================
+*/
+
+void ncr_init (struct ncb *np, int reset, char * msg, u_long code)
+{
+ 	int	i;
+
+ 	/*
+	**	Reset chip if asked, otherwise just clear fifos.
+ 	*/
+
+	if (reset) {
+		OUTB (nc_istat,  SRST);
+		udelay(100);
+	}
+	else {
+		OUTB (nc_stest3, TE|CSF);
+		OUTONB (nc_ctest3, CLF);
+	}
+ 
+	/*
+	**	Message.
+	*/
+
+	if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg);
+
+	/*
+	**	Clear Start Queue
+	*/
+	np->queuedepth = MAX_START - 1;	/* 1 entry needed as end marker */
+	for (i = 1; i < MAX_START + MAX_START; i += 2)
+		np->scripth0->tryloop[i] =
+				cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+
+	/*
+	**	Start at first entry.
+	*/
+	np->squeueput = 0;
+	np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop));
+
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+	/*
+	**	Clear Done Queue
+	*/
+	for (i = 0; i < MAX_DONE; i++) {
+		np->ccb_done[i] = (struct ccb *)CCB_DONE_EMPTY;
+		np->scripth0->done_queue[5*i + 4] =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end));
+	}
+#endif
+
+	/*
+	**	Start at first entry.
+	*/
+	np->script0->done_pos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np,done_queue));
+	np->ccb_done_ic = MAX_DONE-1;
+	np->scripth0->done_queue[5*(MAX_DONE-1) + 4] =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug));
+
+	/*
+	**	Wakeup all pending jobs.
+	*/
+	ncr_wakeup (np, code);
+
+	/*
+	**	Init chip.
+	*/
+
+	/*
+	** Remove reset; big delay because the 895 needs time for the
+	** bus mode to settle
+	*/
+	ncr_chip_reset(np, 2000);
+
+	OUTB (nc_scntl0, np->rv_scntl0 | 0xc0);
+					/*  full arb., ena parity, par->ATN  */
+	OUTB (nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
+
+	ncr_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
+
+	OUTB (nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
+	OUTW (nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
+	OUTB (nc_istat , SIGP	);		/*  Signal Process */
+	OUTB (nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
+	OUTB (nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
+
+	OUTB (nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
+	OUTB (nc_ctest0, np->rv_ctest0);	/* 720: CDIS and EHP */
+	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
+	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
+
+	OUTB (nc_stest2, EXT|np->rv_stest2);	/* Extended Sreq/Sack filtering */
+	OUTB (nc_stest3, TE);			/* TolerANT enable */
+	OUTB (nc_stime0, 0x0c	);		/* HTH disabled  STO 0.25 sec */
+
+	/*
+	**	Disable disconnects.
+	*/
+
+	np->disc = 0;
+
+	/*
+	**    Enable GPIO0 pin for writing if LED support.
+	*/
+
+	if (np->features & FE_LED0) {
+		OUTOFFB (nc_gpcntl, 0x01);
+	}
+
+	/*
+	**      enable ints
+	*/
+
+	OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
+	OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID);
+
+	/*
+	**	Fill in target structure.
+	**	Reinitialize usrsync.
+	**	Reinitialize usrwide.
+	**	Prepare sync negotiation according to actual SCSI bus mode.
+	*/
+
+	for (i=0;i<MAX_TARGET;i++) {
+		struct tcb *tp = &np->target[i];
+
+		tp->sval    = 0;
+		tp->wval    = np->rv_scntl3;
+
+		if (tp->usrsync != 255) {
+			if (tp->usrsync <= np->maxsync) {
+				if (tp->usrsync < np->minsync) {
+					tp->usrsync = np->minsync;
+				}
+			}
+			else
+				tp->usrsync = 255;
+		}
+
+		if (tp->usrwide > np->maxwide)
+			tp->usrwide = np->maxwide;
+
+	}
+
+	/*
+	**    Start script processor.
+	*/
+	if (np->paddr2) {
+		if (bootverbose)
+			printk ("%s: Downloading SCSI SCRIPTS.\n",
+				ncr_name(np));
+		OUTL (nc_scratcha, vtobus(np->script0));
+		OUTL_DSP (NCB_SCRIPTH_PHYS (np, start_ram));
+	}
+	else
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
+}
+
+/*==========================================================
+**
+**	Prepare the negotiation values for wide and
+**	synchronous transfers.
+**
+**==========================================================
+*/
+
+static void ncr_negotiate (struct ncb* np, struct tcb* tp)
+{
+	/*
+	**	minsync unit is 4ns !
+	*/
+
+	u_long minsync = tp->usrsync;
+
+	/*
+	**	SCSI bus mode limit
+	*/
+
+	if (np->scsi_mode && np->scsi_mode == SMODE_SE) {
+		if (minsync < 12) minsync = 12;
+	}
+
+	/*
+	**	our limit ..
+	*/
+
+	if (minsync < np->minsync)
+		minsync = np->minsync;
+
+	/*
+	**	divider limit
+	*/
+
+	if (minsync > np->maxsync)
+		minsync = 255;
+
+	if (tp->maxoffs > np->maxoffs)
+		tp->maxoffs = np->maxoffs;
+
+	tp->minsync = minsync;
+	tp->maxoffs = (minsync<255 ? tp->maxoffs : 0);
+
+	/*
+	**	period=0: has to negotiate sync transfer
+	*/
+
+	tp->period=0;
+
+	/*
+	**	widedone=0: has to negotiate wide transfer
+	*/
+	tp->widedone=0;
+}
+
+/*==========================================================
+**
+**	Get clock factor and sync divisor for a given 
+**	synchronous factor period.
+**	Returns the clock factor (in sxfer) and scntl3 
+**	synchronous divisor field.
+**
+**==========================================================
+*/
+
+static void ncr_getsync(struct ncb *np, u_char sfac, u_char *fakp, u_char *scntl3p)
+{
+	u_long	clk = np->clock_khz;	/* SCSI clock frequency in kHz	*/
+	int	div = np->clock_divn;	/* Number of divisors supported	*/
+	u_long	fak;			/* Sync factor in sxfer		*/
+	u_long	per;			/* Period in tenths of ns	*/
+	u_long	kpc;			/* (per * clk)			*/
+
+	/*
+	**	Compute the synchronous period in tenths of nano-seconds
+	*/
+	if	(sfac <= 10)	per = 250;
+	else if	(sfac == 11)	per = 303;
+	else if	(sfac == 12)	per = 500;
+	else			per = 40 * sfac;
+
+	/*
+	**	Look for the greatest clock divisor that allows an 
+	**	input speed faster than the period.
+	*/
+	kpc = per * clk;
+	while (--div >= 0)
+		if (kpc >= (div_10M[div] << 2)) break;
+
+	/*
+	**	Calculate the lowest clock factor that allows an output 
+	**	speed not faster than the period.
+	*/
+	fak = (kpc - 1) / div_10M[div] + 1;
+
+#if 0	/* This optimization does not seem very useful */
+
+	per = (fak * div_10M[div]) / clk;
+
+	/*
+	**	Why not to try the immediate lower divisor and to choose 
+	**	the one that allows the fastest output speed ?
+	**	We don't want input speed too much greater than output speed.
+	*/
+	if (div >= 1 && fak < 8) {
+		u_long fak2, per2;
+		fak2 = (kpc - 1) / div_10M[div-1] + 1;
+		per2 = (fak2 * div_10M[div-1]) / clk;
+		if (per2 < per && fak2 <= 8) {
+			fak = fak2;
+			per = per2;
+			--div;
+		}
+	}
+#endif
+
+	if (fak < 4) fak = 4;	/* Should never happen, too bad ... */
+
+	/*
+	**	Compute and return sync parameters for the ncr
+	*/
+	*fakp		= fak - 4;
+	*scntl3p	= ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+}
+
+
+/*==========================================================
+**
+**	Set actual values, sync status and patch all ccbs of 
+**	a target according to new sync/wide agreement.
+**
+**==========================================================
+*/
+
+static void ncr_set_sync_wide_status (struct ncb *np, u_char target)
+{
+	struct ccb *cp;
+	struct tcb *tp = &np->target[target];
+
+	/*
+	**	set actual value and sync_status
+	*/
+	OUTB (nc_sxfer, tp->sval);
+	np->sync_st = tp->sval;
+	OUTB (nc_scntl3, tp->wval);
+	np->wide_st = tp->wval;
+
+	/*
+	**	patch ALL ccbs of this target.
+	*/
+	for (cp = np->ccb; cp; cp = cp->link_ccb) {
+		if (!cp->cmd) continue;
+		if (cp->cmd->device->id != target) continue;
+#if 0
+		cp->sync_status = tp->sval;
+		cp->wide_status = tp->wval;
+#endif
+		cp->phys.select.sel_scntl3 = tp->wval;
+		cp->phys.select.sel_sxfer  = tp->sval;
+	}
+}
+
+/*==========================================================
+**
+**	Switch sync mode for current job and it's target
+**
+**==========================================================
+*/
+
+static void ncr_setsync (struct ncb *np, struct ccb *cp, u_char scntl3, u_char sxfer)
+{
+	struct scsi_cmnd *cmd = cp->cmd;
+	struct tcb *tp;
+	u_char target = INB (nc_sdid) & 0x0f;
+	u_char idiv;
+
+	BUG_ON(target != (cmd->device->id & 0xf));
+
+	tp = &np->target[target];
+
+	if (!scntl3 || !(sxfer & 0x1f))
+		scntl3 = np->rv_scntl3;
+	scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07);
+
+	/*
+	**	Deduce the value of controller sync period from scntl3.
+	**	period is in tenths of nano-seconds.
+	*/
+
+	idiv = ((scntl3 >> 4) & 0x7);
+	if ((sxfer & 0x1f) && idiv)
+		tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	else
+		tp->period = 0xffff;
+
+	/* Stop there if sync parameters are unchanged */
+	if (tp->sval == sxfer && tp->wval == scntl3)
+		return;
+	tp->sval = sxfer;
+	tp->wval = scntl3;
+
+	if (sxfer & 0x01f) {
+		/* Disable extended Sreq/Sack filtering */
+		if (tp->period <= 2000)
+			OUTOFFB(nc_stest2, EXT);
+	}
+ 
+	spi_display_xfer_agreement(tp->starget);
+
+	/*
+	**	set actual value and sync_status
+	**	patch ALL ccbs of this target.
+	*/
+	ncr_set_sync_wide_status(np, target);
+}
+
+/*==========================================================
+**
+**	Switch wide mode for current job and it's target
+**	SCSI specs say: a SCSI device that accepts a WDTR 
+**	message shall reset the synchronous agreement to 
+**	asynchronous mode.
+**
+**==========================================================
+*/
+
+static void ncr_setwide (struct ncb *np, struct ccb *cp, u_char wide, u_char ack)
+{
+	struct scsi_cmnd *cmd = cp->cmd;
+	u16 target = INB (nc_sdid) & 0x0f;
+	struct tcb *tp;
+	u_char	scntl3;
+	u_char	sxfer;
+
+	BUG_ON(target != (cmd->device->id & 0xf));
+
+	tp = &np->target[target];
+	tp->widedone  =  wide+1;
+	scntl3 = (tp->wval & (~EWS)) | (wide ? EWS : 0);
+
+	sxfer = ack ? 0 : tp->sval;
+
+	/*
+	**	 Stop there if sync/wide parameters are unchanged
+	*/
+	if (tp->sval == sxfer && tp->wval == scntl3) return;
+	tp->sval = sxfer;
+	tp->wval = scntl3;
+
+	/*
+	**	Bells and whistles   ;-)
+	*/
+	if (bootverbose >= 2) {
+		dev_info(&cmd->device->sdev_target->dev, "WIDE SCSI %sabled.\n",
+				(scntl3 & EWS) ? "en" : "dis");
+	}
+
+	/*
+	**	set actual value and sync_status
+	**	patch ALL ccbs of this target.
+	*/
+	ncr_set_sync_wide_status(np, target);
+}
+
+/*==========================================================
+**
+**	Switch tagged mode for a target.
+**
+**==========================================================
+*/
+
+static void ncr_setup_tags (struct ncb *np, struct scsi_device *sdev)
+{
+	unsigned char tn = sdev->id, ln = sdev->lun;
+	struct tcb *tp = &np->target[tn];
+	struct lcb *lp = tp->lp[ln];
+	u_char   reqtags, maxdepth;
+
+	/*
+	**	Just in case ...
+	*/
+	if ((!tp) || (!lp) || !sdev)
+		return;
+
+	/*
+	**	If SCSI device queue depth is not yet set, leave here.
+	*/
+	if (!lp->scdev_depth)
+		return;
+
+	/*
+	**	Donnot allow more tags than the SCSI driver can queue 
+	**	for this device.
+	**	Donnot allow more tags than we can handle.
+	*/
+	maxdepth = lp->scdev_depth;
+	if (maxdepth > lp->maxnxs)	maxdepth    = lp->maxnxs;
+	if (lp->maxtags > maxdepth)	lp->maxtags = maxdepth;
+	if (lp->numtags > maxdepth)	lp->numtags = maxdepth;
+
+	/*
+	**	only devices conformant to ANSI Version >= 2
+	**	only devices capable of tagged commands
+	**	only if enabled by user ..
+	*/
+	if (sdev->tagged_supported && lp->numtags > 1) {
+		reqtags = lp->numtags;
+	} else {
+		reqtags = 1;
+	}
+
+	/*
+	**	Update max number of tags
+	*/
+	lp->numtags = reqtags;
+	if (lp->numtags > lp->maxtags)
+		lp->maxtags = lp->numtags;
+
+	/*
+	**	If we want to switch tag mode, we must wait 
+	**	for no CCB to be active.
+	*/
+	if	(reqtags > 1 && lp->usetags) {	 /* Stay in tagged mode    */
+		if (lp->queuedepth == reqtags)	 /* Already announced	   */
+			return;
+		lp->queuedepth	= reqtags;
+	}
+	else if	(reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode  */
+		lp->queuedepth	= reqtags;
+		return;
+	}
+	else {					 /* Want to switch tag mode */
+		if (lp->busyccbs)		 /* If not yet safe, return */
+			return;
+		lp->queuedepth	= reqtags;
+		lp->usetags	= reqtags > 1 ? 1 : 0;
+	}
+
+	/*
+	**	Patch the lun mini-script, according to tag mode.
+	*/
+	lp->jump_tag.l_paddr = lp->usetags?
+			cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) :
+			cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag));
+
+	/*
+	**	Announce change to user.
+	*/
+	if (bootverbose) {
+		if (lp->usetags) {
+			dev_info(&sdev->sdev_gendev,
+				"tagged command queue depth set to %d\n",
+				reqtags);
+		} else {
+			dev_info(&sdev->sdev_gendev,
+					"tagged command queueing disabled\n");
+		}
+	}
+}
+
+/*==========================================================
+**
+**
+**	ncr timeout handler.
+**
+**
+**==========================================================
+**
+**	Misused to keep the driver running when
+**	interrupts are not configured correctly.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_timeout (struct ncb *np)
+{
+	u_long	thistime = ktime_get(0);
+
+	/*
+	**	If release process in progress, let's go
+	**	Set the release stage from 1 to 2 to synchronize
+	**	with the release process.
+	*/
+
+	if (np->release_stage) {
+		if (np->release_stage == 1) np->release_stage = 2;
+		return;
+	}
+
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+	add_timer(&np->timer);
+
+	/*
+	**	If we are resetting the ncr, wait for settle_time before 
+	**	clearing it. Then command processing will be resumed.
+	*/
+	if (np->settle_time) {
+		if (np->settle_time <= thistime) {
+			if (bootverbose > 1)
+				printk("%s: command processing resumed\n", ncr_name(np));
+			np->settle_time	= 0;
+			np->disc	= 1;
+			requeue_waiting_list(np);
+		}
+		return;
+	}
+
+	/*
+	**	Since the generic scsi driver only allows us 0.5 second 
+	**	to perform abort of a command, we must look at ccbs about 
+	**	every 0.25 second.
+	*/
+	if (np->lasttime + 4*HZ < thistime) {
+		/*
+		**	block ncr interrupts
+		*/
+		np->lasttime = thistime;
+	}
+
+#ifdef SCSI_NCR_BROKEN_INTR
+	if (INB(nc_istat) & (INTF|SIP|DIP)) {
+
+		/*
+		**	Process pending interrupts.
+		*/
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("{");
+		ncr_exception (np);
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
+	}
+#endif /* SCSI_NCR_BROKEN_INTR */
+}
+
+/*==========================================================
+**
+**	log message for real hard errors
+**
+**	"ncr0 targ 0?: ERROR (ds:si) (so-si-sd) (sxfer/scntl3) @ name (dsp:dbc)."
+**	"	      reg: r0 r1 r2 r3 r4 r5 r6 ..... rf."
+**
+**	exception register:
+**		ds:	dstat
+**		si:	sist
+**
+**	SCSI bus lines:
+**		so:	control lines as driver by NCR.
+**		si:	control lines as seen by NCR.
+**		sd:	scsi data lines as seen by NCR.
+**
+**	wide/fastmode:
+**		sxfer:	(see the manual)
+**		scntl3:	(see the manual)
+**
+**	current script command:
+**		dsp:	script address (relative to start of script).
+**		dbc:	first word of script command.
+**
+**	First 16 register of the chip:
+**		r0..rf
+**
+**==========================================================
+*/
+
+static void ncr_log_hard_error(struct ncb *np, u16 sist, u_char dstat)
+{
+	u32	dsp;
+	int	script_ofs;
+	int	script_size;
+	char	*script_name;
+	u_char	*script_base;
+	int	i;
+
+	dsp	= INL (nc_dsp);
+
+	if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) {
+		script_ofs	= dsp - np->p_script;
+		script_size	= sizeof(struct script);
+		script_base	= (u_char *) np->script0;
+		script_name	= "script";
+	}
+	else if (np->p_scripth < dsp && 
+		 dsp <= np->p_scripth + sizeof(struct scripth)) {
+		script_ofs	= dsp - np->p_scripth;
+		script_size	= sizeof(struct scripth);
+		script_base	= (u_char *) np->scripth0;
+		script_name	= "scripth";
+	} else {
+		script_ofs	= dsp;
+		script_size	= 0;
+		script_base	= NULL;
+		script_name	= "mem";
+	}
+
+	printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n",
+		ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist,
+		(unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl),
+		(unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs,
+		(unsigned)INL (nc_dbc));
+
+	if (((script_ofs & 3) == 0) &&
+	    (unsigned)script_ofs < script_size) {
+		printk ("%s: script cmd = %08x\n", ncr_name(np),
+			scr_to_cpu((int) *(ncrcmd *)(script_base + script_ofs)));
+	}
+
+	printk ("%s: regdump:", ncr_name(np));
+	for (i=0; i<16;i++)
+            printk (" %02x", (unsigned)INB_OFF(i));
+	printk (".\n");
+}
+
+/*============================================================
+**
+**	ncr chip exception handler.
+**
+**============================================================
+**
+**	In normal cases, interrupt conditions occur one at a 
+**	time. The ncr is able to stack in some extra registers 
+**	other interrupts that will occurs after the first one.
+**	But severall interrupts may occur at the same time.
+**
+**	We probably should only try to deal with the normal 
+**	case, but it seems that multiple interrupts occur in 
+**	some cases that are not abnormal at all.
+**
+**	The most frequent interrupt condition is Phase Mismatch.
+**	We should want to service this interrupt quickly.
+**	A SCSI parity error may be delivered at the same time.
+**	The SIR interrupt is not very frequent in this driver, 
+**	since the INTFLY is likely used for command completion 
+**	signaling.
+**	The Selection Timeout interrupt may be triggered with 
+**	IID and/or UDC.
+**	The SBMC interrupt (SCSI Bus Mode Change) may probably 
+**	occur at any time.
+**
+**	This handler try to deal as cleverly as possible with all
+**	the above.
+**
+**============================================================
+*/
+
+void ncr_exception (struct ncb *np)
+{
+	u_char	istat, dstat;
+	u16	sist;
+	int	i;
+
+	/*
+	**	interrupt on the fly ?
+	**	Since the global header may be copied back to a CCB 
+	**	using a posted PCI memory write, the last operation on 
+	**	the istat register is a READ in order to flush posted 
+	**	PCI write commands.
+	*/
+	istat = INB (nc_istat);
+	if (istat & INTF) {
+		OUTB (nc_istat, (istat & SIGP) | INTF);
+		istat = INB (nc_istat);
+		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
+		ncr_wakeup_done (np);
+	}
+
+	if (!(istat & (SIP|DIP)))
+		return;
+
+	if (istat & CABRT)
+		OUTB (nc_istat, CABRT);
+
+	/*
+	**	Steinbach's Guideline for Systems Programming:
+	**	Never test for an error condition you don't know how to handle.
+	*/
+
+	sist  = (istat & SIP) ? INW (nc_sist)  : 0;
+	dstat = (istat & DIP) ? INB (nc_dstat) : 0;
+
+	if (DEBUG_FLAGS & DEBUG_TINY)
+		printk ("<%d|%x:%x|%x:%x>",
+			(int)INB(nc_scr0),
+			dstat,sist,
+			(unsigned)INL(nc_dsp),
+			(unsigned)INL(nc_dbc));
+
+	/*========================================================
+	**	First, interrupts we want to service cleanly.
+	**
+	**	Phase mismatch is the most frequent interrupt, and 
+	**	so we have to service it as quickly and as cleanly 
+	**	as possible.
+	**	Programmed interrupts are rarely used in this driver,
+	**	but we must handle them cleanly anyway.
+	**	We try to deal with PAR and SBMC combined with 
+	**	some other interrupt(s).
+	**=========================================================
+	*/
+
+	if (!(sist  & (STO|GEN|HTH|SGE|UDC|RST)) &&
+	    !(dstat & (MDPE|BF|ABRT|IID))) {
+		if ((sist & SBMC) && ncr_int_sbmc (np))
+			return;
+		if ((sist & PAR)  && ncr_int_par  (np))
+			return;
+		if (sist & MA) {
+			ncr_int_ma (np);
+			return;
+		}
+		if (dstat & SIR) {
+			ncr_int_sir (np);
+			return;
+		}
+		/*
+		**  DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2.
+		*/
+		if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) {
+			printk(	"%s: unknown interrupt(s) ignored, "
+				"ISTAT=%x DSTAT=%x SIST=%x\n",
+				ncr_name(np), istat, dstat, sist);
+			return;
+		}
+		OUTONB_STD ();
+		return;
+	}
+
+	/*========================================================
+	**	Now, interrupts that need some fixing up.
+	**	Order and multiple interrupts is so less important.
+	**
+	**	If SRST has been asserted, we just reset the chip.
+	**
+	**	Selection is intirely handled by the chip. If the 
+	**	chip says STO, we trust it. Seems some other 
+	**	interrupts may occur at the same time (UDC, IID), so 
+	**	we ignore them. In any case we do enough fix-up 
+	**	in the service routine.
+	**	We just exclude some fatal dma errors.
+	**=========================================================
+	*/
+
+	if (sist & RST) {
+		ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET);
+		return;
+	}
+
+	if ((sist & STO) &&
+		!(dstat & (MDPE|BF|ABRT))) {
+	/*
+	**	DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 1.
+	*/
+		OUTONB (nc_ctest3, CLF);
+
+		ncr_int_sto (np);
+		return;
+	}
+
+	/*=========================================================
+	**	Now, interrupts we are not able to recover cleanly.
+	**	(At least for the moment).
+	**
+	**	Do the register dump.
+	**	Log message for real hard errors.
+	**	Clear all fifos.
+	**	For MDPE, BF, ABORT, IID, SGE and HTH we reset the 
+	**	BUS and the chip.
+	**	We are more soft for UDC.
+	**=========================================================
+	*/
+
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
+		for (i = 0; i<sizeof(np->regdump); i++)
+			((char*)&np->regdump)[i] = INB_OFF(i);
+		np->regdump.nc_dstat = dstat;
+		np->regdump.nc_sist  = sist;
+	}
+
+	ncr_log_hard_error(np, sist, dstat);
+
+	printk ("%s: have to clear fifos.\n", ncr_name (np));
+	OUTB (nc_stest3, TE|CSF);
+	OUTONB (nc_ctest3, CLF);
+
+	if ((sist & (SGE)) ||
+		(dstat & (MDPE|BF|ABRT|IID))) {
+		ncr_start_reset(np);
+		return;
+	}
+
+	if (sist & HTH) {
+		printk ("%s: handshake timeout\n", ncr_name(np));
+		ncr_start_reset(np);
+		return;
+	}
+
+	if (sist & UDC) {
+		printk ("%s: unexpected disconnect\n", ncr_name(np));
+		OUTB (HS_PRT, HS_UNEXPECTED);
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, cleanup));
+		return;
+	}
+
+	/*=========================================================
+	**	We just miss the cause of the interrupt. :(
+	**	Print a message. The timeout will do the real work.
+	**=========================================================
+	*/
+	printk ("%s: unknown interrupt\n", ncr_name(np));
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for selection timeout
+**
+**==========================================================
+**
+**	There seems to be a bug in the 53c810.
+**	Although a STO-Interrupt is pending,
+**	it continues executing script commands.
+**	But it will fail and interrupt (IID) on
+**	the next instruction where it's looking
+**	for a valid phase.
+**
+**----------------------------------------------------------
+*/
+
+void ncr_int_sto (struct ncb *np)
+{
+	u_long dsa;
+	struct ccb *cp;
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
+
+	/*
+	**	look for ccb and set the status.
+	*/
+
+	dsa = INL (nc_dsa);
+	cp = np->ccb;
+	while (cp && (CCB_PHYS (cp, phys) != dsa))
+		cp = cp->link_ccb;
+
+	if (cp) {
+		cp-> host_status = HS_SEL_TIMEOUT;
+		ncr_complete (np, cp);
+	}
+
+	/*
+	**	repair start queue and jump to start point.
+	*/
+
+	OUTL_DSP (NCB_SCRIPTH_PHYS (np, sto_restart));
+	return;
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for SCSI bus mode change
+**
+**==========================================================
+**
+**	spi2-r12 11.2.3 says a transceiver mode change must 
+**	generate a reset event and a device that detects a reset 
+**	event shall initiate a hard reset. It says also that a
+**	device that detects a mode change shall set data transfer 
+**	mode to eight bit asynchronous, etc...
+**	So, just resetting should be enough.
+**	 
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_sbmc (struct ncb *np)
+{
+	u_char scsi_mode = INB (nc_stest4) & SMODE;
+
+	if (scsi_mode != np->scsi_mode) {
+		printk("%s: SCSI bus mode change from %x to %x.\n",
+			ncr_name(np), np->scsi_mode, scsi_mode);
+
+		np->scsi_mode = scsi_mode;
+
+
+		/*
+		**	Suspend command processing for 1 second and 
+		**	reinitialize all except the chip.
+		*/
+		np->settle_time	= ktime_get(1*HZ);
+		ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
+		return 1;
+	}
+	return 0;
+}
+
+/*==========================================================
+**
+**	ncr chip exception handler for SCSI parity error.
+**
+**==========================================================
+**
+**
+**----------------------------------------------------------
+*/
+
+static int ncr_int_par (struct ncb *np)
+{
+	u_char	hsts	= INB (HS_PRT);
+	u32	dbc	= INL (nc_dbc);
+	u_char	sstat1	= INB (nc_sstat1);
+	int phase	= -1;
+	int msg		= -1;
+	u32 jmp;
+
+	printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SSTAT1=%x\n",
+		ncr_name(np), hsts, dbc, sstat1);
+
+	/*
+	 *	Ignore the interrupt if the NCR is not connected 
+	 *	to the SCSI bus, since the right work should have  
+	 *	been done on unexpected disconnection handling.
+	 */
+	if (!(INB (nc_scntl1) & ISCON))
+		return 0;
+
+	/*
+	 *	If the nexus is not clearly identified, reset the bus.
+	 *	We will try to do better later.
+	 */
+	if (hsts & HS_INVALMASK)
+		goto reset_all;
+
+	/*
+	 *	If the SCSI parity error occurs in MSG IN phase, prepare a 
+	 *	MSG PARITY message. Otherwise, prepare a INITIATOR DETECTED 
+	 *	ERROR message and let the device decide to retry the command 
+	 *	or to terminate with check condition. If we were in MSG IN 
+	 *	phase waiting for the response of a negotiation, we will 
+	 *	get SIR_NEGO_FAILED at dispatch.
+	 */
+	if (!(dbc & 0xc0000000))
+		phase = (dbc >> 24) & 7;
+	if (phase == 7)
+		msg = M_PARITY;
+	else
+		msg = M_ID_ERROR;
+
+
+	/*
+	 *	If the NCR stopped on a MOVE ^ DATA_IN, we jump to a 
+	 *	script that will ignore all data in bytes until phase 
+	 *	change, since we are not sure the chip will wait the phase 
+	 *	change prior to delivering the interrupt.
+	 */
+	if (phase == 1)
+		jmp = NCB_SCRIPTH_PHYS (np, par_err_data_in);
+	else
+		jmp = NCB_SCRIPTH_PHYS (np, par_err_other);
+
+	OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
+	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
+
+	np->msgout[0] = msg;
+	OUTL_DSP (jmp);
+	return 1;
+
+reset_all:
+	ncr_start_reset(np);
+	return 1;
+}
+
+/*==========================================================
+**
+**
+**	ncr chip exception handler for phase errors.
+**
+**
+**==========================================================
+**
+**	We have to construct a new transfer descriptor,
+**	to transfer the rest of the current block.
+**
+**----------------------------------------------------------
+*/
+
+static void ncr_int_ma (struct ncb *np)
+{
+	u32	dbc;
+	u32	rest;
+	u32	dsp;
+	u32	dsa;
+	u32	nxtdsp;
+	u32	newtmp;
+	u32	*vdsp;
+	u32	oadr, olen;
+	u32	*tblp;
+	ncrcmd *newcmd;
+	u_char	cmd, sbcl;
+	struct ccb *cp;
+
+	dsp	= INL (nc_dsp);
+	dbc	= INL (nc_dbc);
+	sbcl	= INB (nc_sbcl);
+
+	cmd	= dbc >> 24;
+	rest	= dbc & 0xffffff;
+
+	/*
+	**	Take into account dma fifo and various buffers and latches,
+	**	only if the interrupted phase is an OUTPUT phase.
+	*/
+
+	if ((cmd & 1) == 0) {
+		u_char	ctest5, ss0, ss2;
+		u16	delta;
+
+		ctest5 = (np->rv_ctest5 & DFS) ? INB (nc_ctest5) : 0;
+		if (ctest5 & DFS)
+			delta=(((ctest5 << 8) | (INB (nc_dfifo) & 0xff)) - rest) & 0x3ff;
+		else
+			delta=(INB (nc_dfifo) - rest) & 0x7f;
+
+		/*
+		**	The data in the dma fifo has not been transferred to
+		**	the target -> add the amount to the rest
+		**	and clear the data.
+		**	Check the sstat2 register in case of wide transfer.
+		*/
+
+		rest += delta;
+		ss0  = INB (nc_sstat0);
+		if (ss0 & OLF) rest++;
+		if (ss0 & ORF) rest++;
+		if (INB(nc_scntl3) & EWS) {
+			ss2 = INB (nc_sstat2);
+			if (ss2 & OLF1) rest++;
+			if (ss2 & ORF1) rest++;
+		}
+
+		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+			printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7,
+				(unsigned) rest, (unsigned) delta, ss0);
+
+	} else	{
+		if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+			printk ("P%x%x RL=%d ", cmd&7, sbcl&7, rest);
+	}
+
+	/*
+	**	Clear fifos.
+	*/
+	OUTONB (nc_ctest3, CLF );	/* clear dma fifo  */
+	OUTB (nc_stest3, TE|CSF);	/* clear scsi fifo */
+
+	/*
+	**	locate matching cp.
+	**	if the interrupted phase is DATA IN or DATA OUT,
+	**	trust the global header.
+	*/
+	dsa = INL (nc_dsa);
+	if (!(cmd & 6)) {
+		cp = np->header.cp;
+		if (CCB_PHYS(cp, phys) != dsa)
+			cp = NULL;
+	} else {
+		cp  = np->ccb;
+		while (cp && (CCB_PHYS (cp, phys) != dsa))
+			cp = cp->link_ccb;
+	}
+
+	/*
+	**	try to find the interrupted script command,
+	**	and the address at which to continue.
+	*/
+	vdsp	= NULL;
+	nxtdsp	= 0;
+	if	(dsp >  np->p_script &&
+		 dsp <= np->p_script + sizeof(struct script)) {
+		vdsp = (u32 *)((char*)np->script0 + (dsp-np->p_script-8));
+		nxtdsp = dsp;
+	}
+	else if	(dsp >  np->p_scripth &&
+		 dsp <= np->p_scripth + sizeof(struct scripth)) {
+		vdsp = (u32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8));
+		nxtdsp = dsp;
+	}
+	else if (cp) {
+		if	(dsp == CCB_PHYS (cp, patch[2])) {
+			vdsp = &cp->patch[0];
+			nxtdsp = scr_to_cpu(vdsp[3]);
+		}
+		else if (dsp == CCB_PHYS (cp, patch[6])) {
+			vdsp = &cp->patch[4];
+			nxtdsp = scr_to_cpu(vdsp[3]);
+		}
+	}
+
+	/*
+	**	log the information
+	*/
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		printk ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
+			cp, np->header.cp,
+			(unsigned)dsp,
+			(unsigned)nxtdsp, vdsp, cmd);
+	}
+
+	/*
+	**	cp=0 means that the DSA does not point to a valid control 
+	**	block. This should not happen since we donnot use multi-byte 
+	**	move while we are being reselected ot after command complete.
+	**	We are not able to recover from such a phase error.
+	*/
+	if (!cp) {
+		printk ("%s: SCSI phase error fixup: "
+			"CCB already dequeued (0x%08lx)\n", 
+			ncr_name (np), (u_long) np->header.cp);
+		goto reset_all;
+	}
+
+	/*
+	**	get old startaddress and old length.
+	*/
+
+	oadr = scr_to_cpu(vdsp[1]);
+
+	if (cmd & 0x10) {	/* Table indirect */
+		tblp = (u32 *) ((char*) &cp->phys + oadr);
+		olen = scr_to_cpu(tblp[0]);
+		oadr = scr_to_cpu(tblp[1]);
+	} else {
+		tblp = (u32 *) 0;
+		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
+			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
+			tblp,
+			(unsigned) olen,
+			(unsigned) oadr);
+	}
+
+	/*
+	**	check cmd against assumed interrupted script command.
+	*/
+
+	if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) {
+		PRINT_ADDR(cp->cmd, "internal error: cmd=%02x != %02x=(vdsp[0] "
+				">> 24)\n", cmd, scr_to_cpu(vdsp[0]) >> 24);
+
+		goto reset_all;
+	}
+
+	/*
+	**	cp != np->header.cp means that the header of the CCB 
+	**	currently being processed has not yet been copied to 
+	**	the global header area. That may happen if the device did 
+	**	not accept all our messages after having been selected.
+	*/
+	if (cp != np->header.cp) {
+		printk ("%s: SCSI phase error fixup: "
+			"CCB address mismatch (0x%08lx != 0x%08lx)\n", 
+			ncr_name (np), (u_long) cp, (u_long) np->header.cp);
+	}
+
+	/*
+	**	if old phase not dataphase, leave here.
+	*/
+
+	if (cmd & 0x06) {
+		PRINT_ADDR(cp->cmd, "phase change %x-%x %d@%08x resid=%d.\n",
+			cmd&7, sbcl&7, (unsigned)olen,
+			(unsigned)oadr, (unsigned)rest);
+		goto unexpected_phase;
+	}
+
+	/*
+	**	choose the correct patch area.
+	**	if savep points to one, choose the other.
+	*/
+
+	newcmd = cp->patch;
+	newtmp = CCB_PHYS (cp, patch);
+	if (newtmp == scr_to_cpu(cp->phys.header.savep)) {
+		newcmd = &cp->patch[4];
+		newtmp = CCB_PHYS (cp, patch[4]);
+	}
+
+	/*
+	**	fillin the commands
+	*/
+
+	newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest);
+	newcmd[1] = cpu_to_scr(oadr + olen - rest);
+	newcmd[2] = cpu_to_scr(SCR_JUMP);
+	newcmd[3] = cpu_to_scr(nxtdsp);
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		PRINT_ADDR(cp->cmd, "newcmd[%d] %x %x %x %x.\n",
+			(int) (newcmd - cp->patch),
+			(unsigned)scr_to_cpu(newcmd[0]),
+			(unsigned)scr_to_cpu(newcmd[1]),
+			(unsigned)scr_to_cpu(newcmd[2]),
+			(unsigned)scr_to_cpu(newcmd[3]));
+	}
+	/*
+	**	fake the return address (to the patch).
+	**	and restart script processor at dispatcher.
+	*/
+	OUTL (nc_temp, newtmp);
+	OUTL_DSP (NCB_SCRIPT_PHYS (np, dispatch));
+	return;
+
+	/*
+	**	Unexpected phase changes that occurs when the current phase 
+	**	is not a DATA IN or DATA OUT phase are due to error conditions.
+	**	Such event may only happen when the SCRIPTS is using a 
+	**	multibyte SCSI MOVE.
+	**
+	**	Phase change		Some possible cause
+	**
+	**	COMMAND  --> MSG IN	SCSI parity error detected by target.
+	**	COMMAND  --> STATUS	Bad command or refused by target.
+	**	MSG OUT  --> MSG IN     Message rejected by target.
+	**	MSG OUT  --> COMMAND    Bogus target that discards extended
+	**				negotiation messages.
+	**
+	**	The code below does not care of the new phase and so 
+	**	trusts the target. Why to annoy it ?
+	**	If the interrupted phase is COMMAND phase, we restart at
+	**	dispatcher.
+	**	If a target does not get all the messages after selection, 
+	**	the code assumes blindly that the target discards extended 
+	**	messages and clears the negotiation status.
+	**	If the target does not want all our response to negotiation,
+	**	we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 
+	**	bloat for such a should_not_happen situation).
+	**	In all other situation, we reset the BUS.
+	**	Are these assumptions reasonnable ? (Wait and see ...)
+	*/
+unexpected_phase:
+	dsp -= 8;
+	nxtdsp = 0;
+
+	switch (cmd & 7) {
+	case 2:	/* COMMAND phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+		break;
+#if 0
+	case 3:	/* STATUS  phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+		break;
+#endif
+	case 6:	/* MSG OUT phase */
+		np->scripth->nxtdsp_go_on[0] = cpu_to_scr(dsp + 8);
+		if	(dsp == NCB_SCRIPT_PHYS (np, send_ident)) {
+			cp->host_status = HS_BUSY;
+			nxtdsp = NCB_SCRIPTH_PHYS (np, clratn_go_on);
+		}
+		else if	(dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) ||
+			 dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) {
+			nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase);
+		}
+		break;
+#if 0
+	case 7:	/* MSG IN  phase */
+		nxtdsp = NCB_SCRIPT_PHYS (np, clrack);
+		break;
+#endif
+	}
+
+	if (nxtdsp) {
+		OUTL_DSP (nxtdsp);
+		return;
+	}
+
+reset_all:
+	ncr_start_reset(np);
+}
+
+
+static void ncr_sir_to_redo(struct ncb *np, int num, struct ccb *cp)
+{
+	struct scsi_cmnd *cmd	= cp->cmd;
+	struct tcb *tp	= &np->target[cmd->device->id];
+	struct lcb *lp	= tp->lp[cmd->device->lun];
+	struct list_head *qp;
+	struct ccb *	cp2;
+	int		disc_cnt = 0;
+	int		busy_cnt = 0;
+	u32		startp;
+	u_char		s_status = INB (SS_PRT);
+
+	/*
+	**	Let the SCRIPTS processor skip all not yet started CCBs,
+	**	and count disconnected CCBs. Since the busy queue is in 
+	**	the same order as the chip start queue, disconnected CCBs 
+	**	are before cp and busy ones after.
+	*/
+	if (lp) {
+		qp = lp->busy_ccbq.prev;
+		while (qp != &lp->busy_ccbq) {
+			cp2 = list_entry(qp, struct ccb, link_ccbq);
+			qp  = qp->prev;
+			++busy_cnt;
+			if (cp2 == cp)
+				break;
+			cp2->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, skip));
+		}
+		lp->held_ccb = cp;	/* Requeue when this one completes */
+		disc_cnt = lp->queuedccbs - busy_cnt;
+	}
+
+	switch(s_status) {
+	default:	/* Just for safety, should never happen */
+	case S_QUEUE_FULL:
+		/*
+		**	Decrease number of tags to the number of 
+		**	disconnected commands.
+		*/
+		if (!lp)
+			goto out;
+		if (bootverbose >= 1) {
+			PRINT_ADDR(cmd, "QUEUE FULL! %d busy, %d disconnected "
+					"CCBs\n", busy_cnt, disc_cnt);
+		}
+		if (disc_cnt < lp->numtags) {
+			lp->numtags	= disc_cnt > 2 ? disc_cnt : 2;
+			lp->num_good	= 0;
+			ncr_setup_tags (np, cmd->device);
+		}
+		/*
+		**	Requeue the command to the start queue.
+		**	If any disconnected commands,
+		**		Clear SIGP.
+		**		Jump to reselect.
+		*/
+		cp->phys.header.savep = cp->startp;
+		cp->host_status = HS_BUSY;
+		cp->scsi_status = S_ILLEGAL;
+
+		ncr_put_start_queue(np, cp);
+		if (disc_cnt)
+			INB (nc_ctest2);		/* Clear SIGP */
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, reselect));
+		return;
+	case S_TERMINATED:
+	case S_CHECK_COND:
+		/*
+		**	If we were requesting sense, give up.
+		*/
+		if (cp->auto_sense)
+			goto out;
+
+		/*
+		**	Device returned CHECK CONDITION status.
+		**	Prepare all needed data strutures for getting 
+		**	sense data.
+		**
+		**	identify message
+		*/
+		cp->scsi_smsg2[0]	= IDENTIFY(0, cmd->device->lun);
+		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
+		cp->phys.smsg.size	= cpu_to_scr(1);
+
+		/*
+		**	sense command
+		*/
+		cp->phys.cmd.addr	= cpu_to_scr(CCB_PHYS (cp, sensecmd));
+		cp->phys.cmd.size	= cpu_to_scr(6);
+
+		/*
+		**	patch requested size into sense command
+		*/
+		cp->sensecmd[0]		= 0x03;
+		cp->sensecmd[1]		= cmd->device->lun << 5;
+		cp->sensecmd[4]		= sizeof(cp->sense_buf);
+
+		/*
+		**	sense data
+		*/
+		memset(cp->sense_buf, 0, sizeof(cp->sense_buf));
+		cp->phys.sense.addr	= cpu_to_scr(CCB_PHYS(cp,sense_buf[0]));
+		cp->phys.sense.size	= cpu_to_scr(sizeof(cp->sense_buf));
+
+		/*
+		**	requeue the command.
+		*/
+		startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
+
+		cp->phys.header.savep	= startp;
+		cp->phys.header.goalp	= startp + 24;
+		cp->phys.header.lastp	= startp;
+		cp->phys.header.wgoalp	= startp + 24;
+		cp->phys.header.wlastp	= startp;
+
+		cp->host_status = HS_BUSY;
+		cp->scsi_status = S_ILLEGAL;
+		cp->auto_sense	= s_status;
+
+		cp->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
+
+		/*
+		**	Select without ATN for quirky devices.
+		*/
+		if (cmd->device->select_no_atn)
+			cp->start.schedule.l_paddr =
+			cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
+
+		ncr_put_start_queue(np, cp);
+
+		OUTL_DSP (NCB_SCRIPT_PHYS (np, start));
+		return;
+	}
+
+out:
+	OUTONB_STD ();
+	return;
+}
+
+
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
+**
+**
+**==========================================================
+*/
+
+void ncr_int_sir (struct ncb *np)
+{
+	u_char scntl3;
+	u_char chg, ofs, per, fak, wide;
+	u_char num = INB (nc_dsps);
+	struct ccb *cp=NULL;
+	u_long	dsa    = INL (nc_dsa);
+	u_char	target = INB (nc_sdid) & 0x0f;
+	struct tcb *tp     = &np->target[target];
+	struct scsi_target *starget = tp->starget;
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+
+	switch (num) {
+	case SIR_INTFLY:
+		/*
+		**	This is used for HP Zalon/53c720 where INTFLY
+		**	operation is currently broken.
+		*/
+		ncr_wakeup_done(np);
+#ifdef SCSI_NCR_CCB_DONE_SUPPORT
+		OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, done_end) + 8);
+#else
+		OUTL(nc_dsp, NCB_SCRIPT_PHYS (np, start));
+#endif
+		return;
+	case SIR_RESEL_NO_MSG_IN:
+	case SIR_RESEL_NO_IDENTIFY:
+		/*
+		**	If devices reselecting without sending an IDENTIFY 
+		**	message still exist, this should help.
+		**	We just assume lun=0, 1 CCB, no tag.
+		*/
+		if (tp->lp[0]) { 
+			OUTL_DSP (scr_to_cpu(tp->lp[0]->jump_ccb[0]));
+			return;
+		}
+	case SIR_RESEL_BAD_TARGET:	/* Will send a TARGET RESET message */
+	case SIR_RESEL_BAD_LUN:		/* Will send a TARGET RESET message */
+	case SIR_RESEL_BAD_I_T_L_Q:	/* Will send an ABORT TAG message   */
+	case SIR_RESEL_BAD_I_T_L:	/* Will send an ABORT message	    */
+		printk ("%s:%d: SIR %d, "
+			"incorrect nexus identification on reselection\n",
+			ncr_name (np), target, num);
+		goto out;
+	case SIR_DONE_OVERFLOW:
+		printk ("%s:%d: SIR %d, "
+			"CCB done queue overflow\n",
+			ncr_name (np), target, num);
+		goto out;
+	case SIR_BAD_STATUS:
+		cp = np->header.cp;
+		if (!cp || CCB_PHYS (cp, phys) != dsa)
+			goto out;
+		ncr_sir_to_redo(np, num, cp);
+		return;
+	default:
+		/*
+		**	lookup the ccb
+		*/
+		cp = np->ccb;
+		while (cp && (CCB_PHYS (cp, phys) != dsa))
+			cp = cp->link_ccb;
+
+		BUG_ON(!cp);
+		BUG_ON(cp != np->header.cp);
+
+		if (!cp || cp != np->header.cp)
+			goto out;
+	}
+
+	switch (num) {
+/*-----------------------------------------------------------------------------
+**
+**	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
+**
+**	We try to negotiate sync and wide transfer only after
+**	a successful inquire command. We look at byte 7 of the
+**	inquire data to determine the capabilities of the target.
+**
+**	When we try to negotiate, we append the negotiation message
+**	to the identify and (maybe) simple tag message.
+**	The host status field is set to HS_NEGOTIATE to mark this
+**	situation.
+**
+**	If the target doesn't answer this message immidiately
+**	(as required by the standard), the SIR_NEGO_FAIL interrupt
+**	will be raised eventually.
+**	The handler removes the HS_NEGOTIATE status, and sets the
+**	negotiated value to the default (async / nowide).
+**
+**	If we receive a matching answer immediately, we check it
+**	for validity, and set the values.
+**
+**	If we receive a Reject message immediately, we assume the
+**	negotiation has failed, and fall back to standard values.
+**
+**	If we receive a negotiation message while not in HS_NEGOTIATE
+**	state, it's a target initiated negotiation. We prepare a
+**	(hopefully) valid answer, set our parameters, and send back 
+**	this answer to the target.
+**
+**	If the target doesn't fetch the answer (no message out phase),
+**	we assume the negotiation has failed, and fall back to default
+**	settings.
+**
+**	When we set the values, we adjust them in all ccbs belonging 
+**	to this target, in the controller's register, and in the "phys"
+**	field of the controller's struct ncb.
+**
+**	Possible cases:		   hs  sir   msg_in value  send   goto
+**	We try to negotiate:
+**	-> target doesn't msgin    NEG FAIL  noop   defa.  -      dispatch
+**	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
+**	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
+**	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
+**	-> target answered  (ok)   NEG WIDE  wdtr   set    -      clrack
+**	-> target answered (!ok)   NEG WIDE  wdtr   defa.  REJ--->msg_bad
+**	-> any other msgin	   NEG FAIL  noop   defa.  -      dispatch
+**
+**	Target tries to negotiate:
+**	-> incoming message	   --- SYNC  sdtr   set    SDTR   -
+**	-> incoming message	   --- WIDE  wdtr   set    WDTR   -
+**      We sent our answer:
+**	-> target doesn't msgout   --- PROTO ?      defa.  -      dispatch
+**
+**-----------------------------------------------------------------------------
+*/
+
+	case SIR_NEGO_FAILED:
+		/*-------------------------------------------------------
+		**
+		**	Negotiation failed.
+		**	Target doesn't send an answer message,
+		**	or target rejected our message.
+		**
+		**      Remove negotiation request.
+		**
+		**-------------------------------------------------------
+		*/
+		OUTB (HS_PRT, HS_BUSY);
+
+		/* fall through */
+
+	case SIR_NEGO_PROTO:
+		/*-------------------------------------------------------
+		**
+		**	Negotiation failed.
+		**	Target doesn't fetch the answer message.
+		**
+		**-------------------------------------------------------
+		*/
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd, "negotiation failed sir=%x "
+					"status=%x.\n", num, cp->nego_status);
+		}
+
+		/*
+		**	any error in negotiation:
+		**	fall back to default mode.
+		*/
+		switch (cp->nego_status) {
+
+		case NS_SYNC:
+			spi_period(starget) = 0;
+			spi_offset(starget) = 0;
+			ncr_setsync (np, cp, 0, 0xe0);
+			break;
+
+		case NS_WIDE:
+			spi_width(starget) = 0;
+			ncr_setwide (np, cp, 0, 0);
+			break;
+
+		}
+		np->msgin [0] = M_NOOP;
+		np->msgout[0] = M_NOOP;
+		cp->nego_status = 0;
+		break;
+
+	case SIR_NEGO_SYNC:
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, "sync msgin", np->msgin);
+		}
+
+		chg = 0;
+		per = np->msgin[3];
+		ofs = np->msgin[4];
+		if (ofs==0) per=255;
+
+		/*
+		**      if target sends SDTR message,
+		**	      it CAN transfer synch.
+		*/
+
+		if (ofs && starget)
+			spi_support_sync(starget) = 1;
+
+		/*
+		**	check values against driver limits.
+		*/
+
+		if (per < np->minsync)
+			{chg = 1; per = np->minsync;}
+		if (per < tp->minsync)
+			{chg = 1; per = tp->minsync;}
+		if (ofs > tp->maxoffs)
+			{chg = 1; ofs = tp->maxoffs;}
+
+		/*
+		**	Check against controller limits.
+		*/
+		fak	= 7;
+		scntl3	= 0;
+		if (ofs != 0) {
+			ncr_getsync(np, per, &fak, &scntl3);
+			if (fak > 7) {
+				chg = 1;
+				ofs = 0;
+			}
+		}
+		if (ofs == 0) {
+			fak	= 7;
+			per	= 0;
+			scntl3	= 0;
+			tp->minsync = 0;
+		}
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd, "sync: per=%d scntl3=0x%x ofs=%d "
+				"fak=%d chg=%d.\n", per, scntl3, ofs, fak, chg);
+		}
+
+		if (INB (HS_PRT) == HS_NEGOTIATE) {
+			OUTB (HS_PRT, HS_BUSY);
+			switch (cp->nego_status) {
+
+			case NS_SYNC:
+				/* This was an answer message */
+				if (chg) {
+					/* Answer wasn't acceptable.  */
+					spi_period(starget) = 0;
+					spi_offset(starget) = 0;
+					ncr_setsync(np, cp, 0, 0xe0);
+					OUTL_DSP(NCB_SCRIPT_PHYS (np, msg_bad));
+				} else {
+					/* Answer is ok.  */
+					spi_period(starget) = per;
+					spi_offset(starget) = ofs;
+					ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
+					OUTL_DSP(NCB_SCRIPT_PHYS (np, clrack));
+				}
+				return;
+
+			case NS_WIDE:
+				spi_width(starget) = 0;
+				ncr_setwide(np, cp, 0, 0);
+				break;
+			}
+		}
+
+		/*
+		**	It was a request. Set value and
+		**      prepare an answer message
+		*/
+
+		spi_period(starget) = per;
+		spi_offset(starget) = ofs;
+		ncr_setsync(np, cp, scntl3, (fak<<5)|ofs);
+
+		np->msgout[0] = M_EXTENDED;
+		np->msgout[1] = 3;
+		np->msgout[2] = M_X_SYNC_REQ;
+		np->msgout[3] = per;
+		np->msgout[4] = ofs;
+
+		cp->nego_status = NS_SYNC;
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, "sync msgout", np->msgout);
+		}
+
+		if (!ofs) {
+			OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
+			return;
+		}
+		np->msgin [0] = M_NOOP;
+
+		break;
+
+	case SIR_NEGO_WIDE:
+		/*
+		**	Wide request message received.
+		*/
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, "wide msgin", np->msgin);
+		}
+
+		/*
+		**	get requested values.
+		*/
+
+		chg  = 0;
+		wide = np->msgin[3];
+
+		/*
+		**      if target sends WDTR message,
+		**	      it CAN transfer wide.
+		*/
+
+		if (wide && starget)
+			spi_support_wide(starget) = 1;
+
+		/*
+		**	check values against driver limits.
+		*/
+
+		if (wide > tp->usrwide)
+			{chg = 1; wide = tp->usrwide;}
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			PRINT_ADDR(cp->cmd, "wide: wide=%d chg=%d.\n", wide,
+					chg);
+		}
+
+		if (INB (HS_PRT) == HS_NEGOTIATE) {
+			OUTB (HS_PRT, HS_BUSY);
+			switch (cp->nego_status) {
+
+			case NS_WIDE:
+				/*
+				**      This was an answer message
+				*/
+				if (chg) {
+					/* Answer wasn't acceptable.  */
+					spi_width(starget) = 0;
+					ncr_setwide(np, cp, 0, 1);
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, msg_bad));
+				} else {
+					/* Answer is ok.  */
+					spi_width(starget) = wide;
+					ncr_setwide(np, cp, wide, 1);
+					OUTL_DSP (NCB_SCRIPT_PHYS (np, clrack));
+				}
+				return;
+
+			case NS_SYNC:
+				spi_period(starget) = 0;
+				spi_offset(starget) = 0;
+				ncr_setsync(np, cp, 0, 0xe0);
+				break;
+			}
+		}
+
+		/*
+		**	It was a request, set value and
+		**      prepare an answer message
+		*/
+
+		spi_width(starget) = wide;
+		ncr_setwide(np, cp, wide, 1);
+
+		np->msgout[0] = M_EXTENDED;
+		np->msgout[1] = 2;
+		np->msgout[2] = M_X_WIDE_REQ;
+		np->msgout[3] = wide;
+
+		np->msgin [0] = M_NOOP;
+
+		cp->nego_status = NS_WIDE;
+
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, "wide msgout", np->msgin);
+		}
+		break;
+
+/*--------------------------------------------------------------------
+**
+**	Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+	case SIR_REJECT_RECEIVED:
+		/*-----------------------------------------------
+		**
+		**	We received a M_REJECT message.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd, "M_REJECT received (%x:%x).\n",
+			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
+		break;
+
+	case SIR_REJECT_SENT:
+		/*-----------------------------------------------
+		**
+		**	We received an unknown message
+		**
+		**-----------------------------------------------
+		*/
+
+		ncr_print_msg(cp, "M_REJECT sent for", np->msgin);
+		break;
+
+/*--------------------------------------------------------------------
+**
+**	Processing of special messages
+**
+**--------------------------------------------------------------------
+*/
+
+	case SIR_IGN_RESIDUE:
+		/*-----------------------------------------------
+		**
+		**	We received an IGNORE RESIDUE message,
+		**	which couldn't be handled by the script.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd, "M_IGN_RESIDUE received, but not yet "
+				"implemented.\n");
+		break;
+#if 0
+	case SIR_MISSING_SAVE:
+		/*-----------------------------------------------
+		**
+		**	We received an DISCONNECT message,
+		**	but the datapointer wasn't saved before.
+		**
+		**-----------------------------------------------
+		*/
+
+		PRINT_ADDR(cp->cmd, "M_DISCONNECT received, but datapointer "
+				"not saved: data=%x save=%x goal=%x.\n",
+			(unsigned) INL (nc_temp),
+			(unsigned) scr_to_cpu(np->header.savep),
+			(unsigned) scr_to_cpu(np->header.goalp));
+		break;
+#endif
+	}
+
+out:
+	OUTONB_STD ();
+}
+
+/*==========================================================
+**
+**
+**	Acquire a control block
+**
+**
+**==========================================================
+*/
+
+static struct ccb *ncr_get_ccb(struct ncb *np, struct scsi_cmnd *cmd)
+{
+	u_char tn = cmd->device->id;
+	u_char ln = cmd->device->lun;
+	struct tcb *tp = &np->target[tn];
+	struct lcb *lp = tp->lp[ln];
+	u_char tag = NO_TAG;
+	struct ccb *cp = NULL;
+
+	/*
+	**	Lun structure available ?
+	*/
+	if (lp) {
+		struct list_head *qp;
+		/*
+		**	Keep from using more tags than we can handle.
+		*/
+		if (lp->usetags && lp->busyccbs >= lp->maxnxs)
+			return NULL;
+
+		/*
+		**	Allocate a new CCB if needed.
+		*/
+		if (list_empty(&lp->free_ccbq))
+			ncr_alloc_ccb(np, tn, ln);
+
+		/*
+		**	Look for free CCB
+		*/
+		qp = ncr_list_pop(&lp->free_ccbq);
+		if (qp) {
+			cp = list_entry(qp, struct ccb, link_ccbq);
+			if (cp->magic) {
+				PRINT_ADDR(cmd, "ccb free list corrupted "
+						"(@%p)\n", cp);
+				cp = NULL;
+			} else {
+				list_add_tail(qp, &lp->wait_ccbq);
+				++lp->busyccbs;
+			}
+		}
+
+		/*
+		**	If a CCB is available,
+		**	Get a tag for this nexus if required.
+		*/
+		if (cp) {
+			if (lp->usetags)
+				tag = lp->cb_tags[lp->ia_tag];
+		}
+		else if (lp->actccbs > 0)
+			return NULL;
+	}
+
+	/*
+	**	if nothing available, take the default.
+	*/
+	if (!cp)
+		cp = np->ccb;
+
+	/*
+	**	Wait until available.
+	*/
+#if 0
+	while (cp->magic) {
+		if (flags & SCSI_NOSLEEP) break;
+		if (tsleep ((caddr_t)cp, PRIBIO|PCATCH, "ncr", 0))
+			break;
+	}
+#endif
+
+	if (cp->magic)
+		return NULL;
+
+	cp->magic = 1;
+
+	/*
+	**	Move to next available tag if tag used.
+	*/
+	if (lp) {
+		if (tag != NO_TAG) {
+			++lp->ia_tag;
+			if (lp->ia_tag == MAX_TAGS)
+				lp->ia_tag = 0;
+			lp->tags_umap |= (((tagmap_t) 1) << tag);
+		}
+	}
+
+	/*
+	**	Remember all informations needed to free this CCB.
+	*/
+	cp->tag	   = tag;
+	cp->target = tn;
+	cp->lun    = ln;
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		PRINT_ADDR(cmd, "ccb @%p using tag %d.\n", cp, tag);
+	}
+
+	return cp;
+}
+
+/*==========================================================
+**
+**
+**	Release one control block
+**
+**
+**==========================================================
+*/
+
+static void ncr_free_ccb (struct ncb *np, struct ccb *cp)
+{
+	struct tcb *tp = &np->target[cp->target];
+	struct lcb *lp = tp->lp[cp->lun];
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		PRINT_ADDR(cp->cmd, "ccb @%p freeing tag %d.\n", cp, cp->tag);
+	}
+
+	/*
+	**	If lun control block available,
+	**	decrement active commands and increment credit, 
+	**	free the tag if any and remove the JUMP for reselect.
+	*/
+	if (lp) {
+		if (cp->tag != NO_TAG) {
+			lp->cb_tags[lp->if_tag++] = cp->tag;
+			if (lp->if_tag == MAX_TAGS)
+				lp->if_tag = 0;
+			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
+			lp->tags_smap &= lp->tags_umap;
+			lp->jump_ccb[cp->tag] =
+				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q));
+		} else {
+			lp->jump_ccb[0] =
+				cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l));
+		}
+	}
+
+	/*
+	**	Make this CCB available.
+	*/
+
+	if (lp) {
+		if (cp != np->ccb)
+			list_move(&cp->link_ccbq, &lp->free_ccbq);
+		--lp->busyccbs;
+		if (cp->queued) {
+			--lp->queuedccbs;
+		}
+	}
+	cp -> host_status = HS_IDLE;
+	cp -> magic = 0;
+	if (cp->queued) {
+		--np->queuedccbs;
+		cp->queued = 0;
+	}
+
+#if 0
+	if (cp == np->ccb)
+		wakeup ((caddr_t) cp);
+#endif
+}
+
+
+#define ncr_reg_bus_addr(r) (np->paddr + offsetof (struct ncr_reg, r))
+
+/*------------------------------------------------------------------------
+**	Initialize the fixed part of a CCB structure.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_init_ccb(struct ncb *np, struct ccb *cp)
+{
+	ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
+
+	/*
+	**	Remember virtual and bus address of this ccb.
+	*/
+	cp->p_ccb 	   = vtobus(cp);
+	cp->phys.header.cp = cp;
+
+	/*
+	**	This allows list_del to work for the default ccb.
+	*/
+	INIT_LIST_HEAD(&cp->link_ccbq);
+
+	/*
+	**	Initialyze the start and restart launch script.
+	**
+	**	COPY(4) @(...p_phys), @(dsa)
+	**	JUMP @(sched_point)
+	*/
+	cp->start.setup_dsa[0]	 = cpu_to_scr(copy_4);
+	cp->start.setup_dsa[1]	 = cpu_to_scr(CCB_PHYS(cp, start.p_phys));
+	cp->start.setup_dsa[2]	 = cpu_to_scr(ncr_reg_bus_addr(nc_dsa));
+	cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP);
+	cp->start.p_phys	 = cpu_to_scr(CCB_PHYS(cp, phys));
+
+	memcpy(&cp->restart, &cp->start, sizeof(cp->restart));
+
+	cp->start.schedule.l_paddr   = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle));
+	cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort));
+}
+
+
+/*------------------------------------------------------------------------
+**	Allocate a CCB and initialize its fixed part.
+**------------------------------------------------------------------------
+**------------------------------------------------------------------------
+*/
+static void ncr_alloc_ccb(struct ncb *np, u_char tn, u_char ln)
+{
+	struct tcb *tp = &np->target[tn];
+	struct lcb *lp = tp->lp[ln];
+	struct ccb *cp = NULL;
+
+	/*
+	**	Allocate memory for this CCB.
+	*/
+	cp = m_calloc_dma(sizeof(struct ccb), "CCB");
+	if (!cp)
+		return;
+
+	/*
+	**	Count it and initialyze it.
+	*/
+	lp->actccbs++;
+	np->actccbs++;
+	memset(cp, 0, sizeof (*cp));
+	ncr_init_ccb(np, cp);
+
+	/*
+	**	Chain into wakeup list and free ccb queue and take it 
+	**	into account for tagged commands.
+	*/
+	cp->link_ccb      = np->ccb->link_ccb;
+	np->ccb->link_ccb = cp;
+
+	list_add(&cp->link_ccbq, &lp->free_ccbq);
+}
+
+/*==========================================================
+**
+**
+**      Allocation of resources for Targets/Luns/Tags.
+**
+**
+**==========================================================
+*/
+
+
+/*------------------------------------------------------------------------
+**	Target control block initialisation.
+**------------------------------------------------------------------------
+**	This data structure is fully initialized after a SCSI command 
+**	has been successfully completed for this target.
+**	It contains a SCRIPT that is called on target reselection.
+**------------------------------------------------------------------------
+*/
+static void ncr_init_tcb (struct ncb *np, u_char tn)
+{
+	struct tcb *tp = &np->target[tn];
+	ncrcmd copy_1 = np->features & FE_PFEN ? SCR_COPY(1) : SCR_COPY_F(1);
+	int th = tn & 3;
+	int i;
+
+	/*
+	**	Jump to next tcb if SFBR does not match this target.
+	**	JUMP  IF (SFBR != #target#), @(next tcb)
+	*/
+	tp->jump_tcb.l_cmd   =
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (0x80 + tn))));
+	tp->jump_tcb.l_paddr = np->jump_tcb[th].l_paddr;
+
+	/*
+	**	Load the synchronous transfer register.
+	**	COPY @(tp->sval), @(sxfer)
+	*/
+	tp->getscr[0] =	cpu_to_scr(copy_1);
+	tp->getscr[1] = cpu_to_scr(vtobus (&tp->sval));
+#ifdef SCSI_NCR_BIG_ENDIAN
+	tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer) ^ 3);
+#else
+	tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer));
+#endif
+
+	/*
+	**	Load the timing register.
+	**	COPY @(tp->wval), @(scntl3)
+	*/
+	tp->getscr[3] =	cpu_to_scr(copy_1);
+	tp->getscr[4] = cpu_to_scr(vtobus (&tp->wval));
+#ifdef SCSI_NCR_BIG_ENDIAN
+	tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3) ^ 3);
+#else
+	tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3));
+#endif
+
+	/*
+	**	Get the IDENTIFY message and the lun.
+	**	CALL @script(resel_lun)
+	*/
+	tp->call_lun.l_cmd   = cpu_to_scr(SCR_CALL);
+	tp->call_lun.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun));
+
+	/*
+	**	Look for the lun control block of this nexus.
+	**	For i = 0 to 3
+	**		JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
+	*/
+	for (i = 0 ; i < 4 ; i++) {
+		tp->jump_lcb[i].l_cmd   =
+				cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
+		tp->jump_lcb[i].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_identify));
+	}
+
+	/*
+	**	Link this target control block to the JUMP chain.
+	*/
+	np->jump_tcb[th].l_paddr = cpu_to_scr(vtobus (&tp->jump_tcb));
+
+	/*
+	**	These assert's should be moved at driver initialisations.
+	*/
+#ifdef SCSI_NCR_BIG_ENDIAN
+	BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^
+		 offsetof(struct tcb    , sval    )) &3) != 3);
+	BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^
+		 offsetof(struct tcb    , wval    )) &3) != 3);
+#else
+	BUG_ON(((offsetof(struct ncr_reg, nc_sxfer) ^
+		 offsetof(struct tcb    , sval    )) &3) != 0);
+	BUG_ON(((offsetof(struct ncr_reg, nc_scntl3) ^
+		 offsetof(struct tcb    , wval    )) &3) != 0);
+#endif
+}
+
+
+/*------------------------------------------------------------------------
+**	Lun control block allocation and initialization.
+**------------------------------------------------------------------------
+**	This data structure is allocated and initialized after a SCSI 
+**	command has been successfully completed for this target/lun.
+**------------------------------------------------------------------------
+*/
+static struct lcb *ncr_alloc_lcb (struct ncb *np, u_char tn, u_char ln)
+{
+	struct tcb *tp = &np->target[tn];
+	struct lcb *lp = tp->lp[ln];
+	ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4);
+	int lh = ln & 3;
+
+	/*
+	**	Already done, return.
+	*/
+	if (lp)
+		return lp;
+
+	/*
+	**	Allocate the lcb.
+	*/
+	lp = m_calloc_dma(sizeof(struct lcb), "LCB");
+	if (!lp)
+		goto fail;
+	memset(lp, 0, sizeof(*lp));
+	tp->lp[ln] = lp;
+
+	/*
+	**	Initialize the target control block if not yet.
+	*/
+	if (!tp->jump_tcb.l_cmd)
+		ncr_init_tcb(np, tn);
+
+	/*
+	**	Initialize the CCB queue headers.
+	*/
+	INIT_LIST_HEAD(&lp->free_ccbq);
+	INIT_LIST_HEAD(&lp->busy_ccbq);
+	INIT_LIST_HEAD(&lp->wait_ccbq);
+	INIT_LIST_HEAD(&lp->skip_ccbq);
+
+	/*
+	**	Set max CCBs to 1 and use the default 1 entry 
+	**	jump table by default.
+	*/
+	lp->maxnxs	= 1;
+	lp->jump_ccb	= &lp->jump_ccb_0;
+	lp->p_jump_ccb	= cpu_to_scr(vtobus(lp->jump_ccb));
+
+	/*
+	**	Initilialyze the reselect script:
+	**
+	**	Jump to next lcb if SFBR does not match this lun.
+	**	Load TEMP with the CCB direct jump table bus address.
+	**	Get the SIMPLE TAG message and the tag.
+	**
+	**	JUMP  IF (SFBR != #lun#), @(next lcb)
+	**	COPY @(lp->p_jump_ccb),	  @(temp)
+	**	JUMP @script(resel_notag)
+	*/
+	lp->jump_lcb.l_cmd   =
+		cpu_to_scr((SCR_JUMP ^ IFFALSE (MASK (0x80+ln, 0xff))));
+	lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr;
+
+	lp->load_jump_ccb[0] = cpu_to_scr(copy_4);
+	lp->load_jump_ccb[1] = cpu_to_scr(vtobus (&lp->p_jump_ccb));
+	lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp));
+
+	lp->jump_tag.l_cmd   = cpu_to_scr(SCR_JUMP);
+	lp->jump_tag.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_notag));
+
+	/*
+	**	Link this lun control block to the JUMP chain.
+	*/
+	tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtobus (&lp->jump_lcb));
+
+	/*
+	**	Initialize command queuing control.
+	*/
+	lp->busyccbs	= 1;
+	lp->queuedccbs	= 1;
+	lp->queuedepth	= 1;
+fail:
+	return lp;
+}
+
+
+/*------------------------------------------------------------------------
+**	Lun control block setup on INQUIRY data received.
+**------------------------------------------------------------------------
+**	We only support WIDE, SYNC for targets and CMDQ for logical units.
+**	This setup is done on each INQUIRY since we are expecting user 
+**	will play with CHANGE DEFINITION commands. :-)
+**------------------------------------------------------------------------
+*/
+static struct lcb *ncr_setup_lcb (struct ncb *np, struct scsi_device *sdev)
+{
+	unsigned char tn = sdev->id, ln = sdev->lun;
+	struct tcb *tp = &np->target[tn];
+	struct lcb *lp = tp->lp[ln];
+
+	/* If no lcb, try to allocate it.  */
+	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
+		goto fail;
+
+	/*
+	**	If unit supports tagged commands, allocate the 
+	**	CCB JUMP table if not yet.
+	*/
+	if (sdev->tagged_supported && lp->jump_ccb == &lp->jump_ccb_0) {
+		int i;
+		lp->jump_ccb = m_calloc_dma(256, "JUMP_CCB");
+		if (!lp->jump_ccb) {
+			lp->jump_ccb = &lp->jump_ccb_0;
+			goto fail;
+		}
+		lp->p_jump_ccb = cpu_to_scr(vtobus(lp->jump_ccb));
+		for (i = 0 ; i < 64 ; i++)
+			lp->jump_ccb[i] =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
+		for (i = 0 ; i < MAX_TAGS ; i++)
+			lp->cb_tags[i] = i;
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
+		ncr_setup_tags (np, sdev);
+	}
+
+
+fail:
+	return lp;
+}
+
+/*==========================================================
+**
+**
+**	Build Scatter Gather Block
+**
+**
+**==========================================================
+**
+**	The transfer area may be scattered among
+**	several non adjacent physical pages.
+**
+**	We may use MAX_SCATTER blocks.
+**
+**----------------------------------------------------------
+*/
+
+/*
+**	We try to reduce the number of interrupts caused
+**	by unexpected phase changes due to disconnects.
+**	A typical harddisk may disconnect before ANY block.
+**	If we wanted to avoid unexpected phase changes at all
+**	we had to use a break point every 512 bytes.
+**	Of course the number of scatter/gather blocks is
+**	limited.
+**	Under Linux, the scatter/gatter blocks are provided by 
+**	the generic driver. We just have to copy addresses and 
+**	sizes to the data segment array.
+*/
+
+static int ncr_scatter_no_sglist(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
+{
+	struct scr_tblmove *data = &cp->phys.data[MAX_SCATTER - 1];
+	int segment;
+
+	cp->data_len = cmd->request_bufflen;
+
+	if (cmd->request_bufflen) {
+		dma_addr_t baddr = map_scsi_single_data(np, cmd);
+		if (baddr) {
+			ncr_build_sge(np, data, baddr, cmd->request_bufflen);
+			segment = 1;
+		} else {
+			segment = -2;
+		}
+	} else {
+		segment = 0;
+	}
+
+	return segment;
+}
+
+static int ncr_scatter(struct ncb *np, struct ccb *cp, struct scsi_cmnd *cmd)
+{
+	int segment	= 0;
+	int use_sg	= (int) cmd->use_sg;
+
+	cp->data_len	= 0;
+
+	if (!use_sg)
+		segment = ncr_scatter_no_sglist(np, cp, cmd);
+	else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
+		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+		struct scr_tblmove *data;
+
+		if (use_sg > MAX_SCATTER) {
+			unmap_scsi_data(np, cmd);
+			return -1;
+		}
+
+		data = &cp->phys.data[MAX_SCATTER - use_sg];
+
+		for (segment = 0; segment < use_sg; segment++) {
+			dma_addr_t baddr = sg_dma_address(&scatter[segment]);
+			unsigned int len = sg_dma_len(&scatter[segment]);
+
+			ncr_build_sge(np, &data[segment], baddr, len);
+			cp->data_len += len;
+		}
+	} else {
+		segment = -2;
+	}
+
+	return segment;
+}
+
+/*==========================================================
+**
+**
+**	Test the bus snoop logic :-(
+**
+**	Has to be called with interrupts disabled.
+**
+**
+**==========================================================
+*/
+
+static int __init ncr_regtest (struct ncb* np)
+{
+	register volatile u32 data;
+	/*
+	**	ncr registers may NOT be cached.
+	**	write 0xffffffff to a read only register area,
+	**	and try to read it back.
+	*/
+	data = 0xffffffff;
+	OUTL_OFF(offsetof(struct ncr_reg, nc_dstat), data);
+	data = INL_OFF(offsetof(struct ncr_reg, nc_dstat));
+#if 1
+	if (data == 0xffffffff) {
+#else
+	if ((data & 0xe2f0fffd) != 0x02000080) {
+#endif
+		printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+			(unsigned) data);
+		return (0x10);
+	}
+	return (0);
+}
+
+static int __init ncr_snooptest (struct ncb* np)
+{
+	u32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
+	int	i, err=0;
+	if (np->reg) {
+		err |= ncr_regtest (np);
+		if (err)
+			return (err);
+	}
+
+	/* init */
+	pc  = NCB_SCRIPTH_PHYS (np, snooptest);
+	host_wr = 1;
+	ncr_wr  = 2;
+	/*
+	**	Set memory and register.
+	*/
+	np->ncr_cache = cpu_to_scr(host_wr);
+	OUTL (nc_temp, ncr_wr);
+	/*
+	**	Start script (exchange values)
+	*/
+	OUTL_DSP (pc);
+	/*
+	**	Wait 'til done (with timeout)
+	*/
+	for (i=0; i<NCR_SNOOP_TIMEOUT; i++)
+		if (INB(nc_istat) & (INTF|SIP|DIP))
+			break;
+	/*
+	**	Save termination position.
+	*/
+	pc = INL (nc_dsp);
+	/*
+	**	Read memory and register.
+	*/
+	host_rd = scr_to_cpu(np->ncr_cache);
+	ncr_rd  = INL (nc_scratcha);
+	ncr_bk  = INL (nc_temp);
+	/*
+	**	Reset ncr chip
+	*/
+	ncr_chip_reset(np, 100);
+	/*
+	**	check for timeout
+	*/
+	if (i>=NCR_SNOOP_TIMEOUT) {
+		printk ("CACHE TEST FAILED: timeout.\n");
+		return (0x20);
+	}
+	/*
+	**	Check termination position.
+	*/
+	if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) {
+		printk ("CACHE TEST FAILED: script execution failed.\n");
+		printk ("start=%08lx, pc=%08lx, end=%08lx\n", 
+			(u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc,
+			(u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8);
+		return (0x40);
+	}
+	/*
+	**	Show results.
+	*/
+	if (host_wr != ncr_rd) {
+		printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n",
+			(int) host_wr, (int) ncr_rd);
+		err |= 1;
+	}
+	if (host_rd != ncr_wr) {
+		printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n",
+			(int) ncr_wr, (int) host_rd);
+		err |= 2;
+	}
+	if (ncr_bk != ncr_wr) {
+		printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n",
+			(int) ncr_wr, (int) ncr_bk);
+		err |= 4;
+	}
+	return (err);
+}
+
+/*==========================================================
+**
+**	Determine the ncr's clock frequency.
+**	This is essential for the negotiation
+**	of the synchronous transfer rate.
+**
+**==========================================================
+**
+**	Note: we have to return the correct value.
+**	THERE IS NO SAVE DEFAULT VALUE.
+**
+**	Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+**	53C860 and 53C875 rev. 1 support fast20 transfers but 
+**	do not have a clock doubler and so are provided with a 
+**	80 MHz clock. All other fast20 boards incorporate a doubler 
+**	and so should be delivered with a 40 MHz clock.
+**	The future fast40 chips (895/895) use a 40 Mhz base clock 
+**	and provide a clock quadrupler (160 Mhz). The code below 
+**	tries to deal as cleverly as possible with all this stuff.
+**
+**----------------------------------------------------------
+*/
+
+/*
+ *	Select NCR SCSI clock frequency
+ */
+static void ncr_selectclock(struct ncb *np, u_char scntl3)
+{
+	if (np->multiplier < 2) {
+		OUTB(nc_scntl3,	scntl3);
+		return;
+	}
+
+	if (bootverbose >= 2)
+		printk ("%s: enabling clock multiplier\n", ncr_name(np));
+
+	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
+	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
+		int i = 20;
+		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
+			udelay(20);
+		if (!i)
+			printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
+	} else			/* Wait 20 micro-seconds for doubler	*/
+		udelay(20);
+	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
+	OUTB(nc_scntl3,	scntl3);
+	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
+	OUTB(nc_stest3, 0x00);		/* Restart scsi clock 		*/
+}
+
+
+/*
+ *	calculate NCR SCSI clock frequency (in KHz)
+ */
+static unsigned __init ncrgetfreq (struct ncb *np, int gen)
+{
+	unsigned ms = 0;
+	char count = 0;
+
+	/*
+	 * Measure GEN timer delay in order 
+	 * to calculate SCSI clock frequency
+	 *
+	 * This code will never execute too
+	 * many loop iterations (if DELAY is 
+	 * reasonably correct). It could get
+	 * too low a delay (too high a freq.)
+	 * if the CPU is slow executing the 
+	 * loop for some reason (an NMI, for
+	 * example). For this reason we will
+	 * if multiple measurements are to be 
+	 * performed trust the higher delay 
+	 * (lower frequency returned).
+	 */
+	OUTB (nc_stest1, 0);	/* make sure clock doubler is OFF */
+	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
+	(void) INW (nc_sist);	/* clear pending scsi interrupt */
+	OUTB (nc_dien , 0);	/* mask all dma interrupts */
+	(void) INW (nc_sist);	/* another one, just to be sure :) */
+	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
+	OUTB (nc_stime1, 0);	/* disable general purpose timer */
+	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
+	while (!(INW(nc_sist) & GEN) && ms++ < 100000) {
+		for (count = 0; count < 10; count ++)
+			udelay(100);	/* count ms */
+	}
+	OUTB (nc_stime1, 0);	/* disable general purpose timer */
+ 	/*
+ 	 * set prescaler to divide by whatever 0 means
+ 	 * 0 ought to choose divide by 2, but appears
+ 	 * to set divide by 3.5 mode in my 53c810 ...
+ 	 */
+ 	OUTB (nc_scntl3, 0);
+
+	if (bootverbose >= 2)
+		printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
+  	/*
+ 	 * adjust for prescaler, and convert into KHz 
+  	 */
+	return ms ? ((1 << gen) * 4340) / ms : 0;
+}
+
+/*
+ *	Get/probe NCR SCSI clock frequency
+ */
+static void __init ncr_getclock (struct ncb *np, int mult)
+{
+	unsigned char scntl3 = INB(nc_scntl3);
+	unsigned char stest1 = INB(nc_stest1);
+	unsigned f1;
+
+	np->multiplier = 1;
+	f1 = 40000;
+
+	/*
+	**	True with 875 or 895 with clock multiplier selected
+	*/
+	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
+		if (bootverbose >= 2)
+			printk ("%s: clock multiplier found\n", ncr_name(np));
+		np->multiplier = mult;
+	}
+
+	/*
+	**	If multiplier not found or scntl3 not 7,5,3,
+	**	reset chip and get frequency from general purpose timer.
+	**	Otherwise trust scntl3 BIOS setting.
+	*/
+	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+		unsigned f2;
+
+		ncr_chip_reset(np, 5);
+
+		(void) ncrgetfreq (np, 11);	/* throw away first result */
+		f1 = ncrgetfreq (np, 11);
+		f2 = ncrgetfreq (np, 11);
+
+		if(bootverbose)
+			printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+
+		if (f1 > f2) f1 = f2;		/* trust lower result	*/
+
+		if	(f1 <	45000)		f1 =  40000;
+		else if (f1 <	55000)		f1 =  50000;
+		else				f1 =  80000;
+
+		if (f1 < 80000 && mult > 1) {
+			if (bootverbose >= 2)
+				printk ("%s: clock multiplier assumed\n", ncr_name(np));
+			np->multiplier	= mult;
+		}
+	} else {
+		if	((scntl3 & 7) == 3)	f1 =  40000;
+		else if	((scntl3 & 7) == 5)	f1 =  80000;
+		else 				f1 = 160000;
+
+		f1 /= np->multiplier;
+	}
+
+	/*
+	**	Compute controller synchronous parameters.
+	*/
+	f1		*= np->multiplier;
+	np->clock_khz	= f1;
+}
+
+/*===================== LINUX ENTRY POINTS SECTION ==========================*/
+
+static int ncr53c8xx_slave_alloc(struct scsi_device *device)
+{
+	struct Scsi_Host *host = device->host;
+	struct ncb *np = ((struct host_data *) host->hostdata)->ncb;
+	struct tcb *tp = &np->target[device->id];
+	tp->starget = device->sdev_target;
+
+	return 0;
+}
+
+static int ncr53c8xx_slave_configure(struct scsi_device *device)
+{
+	struct Scsi_Host *host = device->host;
+	struct ncb *np = ((struct host_data *) host->hostdata)->ncb;
+	struct tcb *tp = &np->target[device->id];
+	struct lcb *lp = tp->lp[device->lun];
+	int numtags, depth_to_use;
+
+	ncr_setup_lcb(np, device);
+
+	/*
+	**	Select queue depth from driver setup.
+	**	Donnot use more than configured by user.
+	**	Use at least 2.
+	**	Donnot use more than our maximum.
+	*/
+	numtags = device_queue_depth(np->unit, device->id, device->lun);
+	if (numtags > tp->usrtags)
+		numtags = tp->usrtags;
+	if (!device->tagged_supported)
+		numtags = 1;
+	depth_to_use = numtags;
+	if (depth_to_use < 2)
+		depth_to_use = 2;
+	if (depth_to_use > MAX_TAGS)
+		depth_to_use = MAX_TAGS;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	/*
+	**	Since the queue depth is not tunable under Linux,
+	**	we need to know this value in order not to 
+	**	announce stupid things to user.
+	**
+	**	XXX(hch): As of Linux 2.6 it certainly _is_ tunable..
+	**		  In fact we just tuned it, or did I miss
+	**		  something important? :)
+	*/
+	if (lp) {
+		lp->numtags = lp->maxtags = numtags;
+		lp->scdev_depth = depth_to_use;
+	}
+	ncr_setup_tags (np, device);
+
+#ifdef DEBUG_NCR53C8XX
+	printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n",
+	       np->unit, device->id, device->lun, depth_to_use);
+#endif
+
+	if (spi_support_sync(device->sdev_target) &&
+	    !spi_initial_dv(device->sdev_target))
+		spi_dv_device(device);
+	return 0;
+}
+
+static int ncr53c8xx_queue_command (struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *))
+{
+     struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
+     unsigned long flags;
+     int sts;
+
+#ifdef DEBUG_NCR53C8XX
+printk("ncr53c8xx_queue_command\n");
+#endif
+
+     cmd->scsi_done     = done;
+     cmd->host_scribble = NULL;
+     cmd->__data_mapped = 0;
+     cmd->__data_mapping = 0;
+
+     spin_lock_irqsave(&np->smp_lock, flags);
+
+     if ((sts = ncr_queue_command(np, cmd)) != DID_OK) {
+	  cmd->result = ScsiResult(sts, 0);
+#ifdef DEBUG_NCR53C8XX
+printk("ncr53c8xx : command not queued - result=%d\n", sts);
+#endif
+     }
+#ifdef DEBUG_NCR53C8XX
+     else
+printk("ncr53c8xx : command successfully queued\n");
+#endif
+
+     spin_unlock_irqrestore(&np->smp_lock, flags);
+
+     if (sts != DID_OK) {
+          unmap_scsi_data(np, cmd);
+          done(cmd);
+	  sts = 0;
+     }
+
+     return sts;
+}
+
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+{
+     unsigned long flags;
+     struct Scsi_Host *shost = (struct Scsi_Host *)dev_id;
+     struct host_data *host_data = (struct host_data *)shost->hostdata;
+     struct ncb *np = host_data->ncb;
+     struct scsi_cmnd *done_list;
+
+#ifdef DEBUG_NCR53C8XX
+     printk("ncr53c8xx : interrupt received\n");
+#endif
+
+     if (DEBUG_FLAGS & DEBUG_TINY) printk ("[");
+
+     spin_lock_irqsave(&np->smp_lock, flags);
+     ncr_exception(np);
+     done_list     = np->done_list;
+     np->done_list = NULL;
+     spin_unlock_irqrestore(&np->smp_lock, flags);
+
+     if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n");
+
+     if (done_list)
+	     ncr_flush_done_cmds(done_list);
+     return IRQ_HANDLED;
+}
+
+static void ncr53c8xx_timeout(unsigned long npref)
+{
+	struct ncb *np = (struct ncb *) npref;
+	unsigned long flags;
+	struct scsi_cmnd *done_list;
+
+	spin_lock_irqsave(&np->smp_lock, flags);
+	ncr_timeout(np);
+	done_list     = np->done_list;
+	np->done_list = NULL;
+	spin_unlock_irqrestore(&np->smp_lock, flags);
+
+	if (done_list)
+		ncr_flush_done_cmds(done_list);
+}
+
+static int ncr53c8xx_bus_reset(struct scsi_cmnd *cmd)
+{
+	struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
+	int sts;
+	unsigned long flags;
+	struct scsi_cmnd *done_list;
+
+	/*
+	 * If the mid-level driver told us reset is synchronous, it seems 
+	 * that we must call the done() callback for the involved command, 
+	 * even if this command was not queued to the low-level driver, 
+	 * before returning SUCCESS.
+	 */
+
+	spin_lock_irqsave(&np->smp_lock, flags);
+	sts = ncr_reset_bus(np, cmd, 1);
+
+	done_list     = np->done_list;
+	np->done_list = NULL;
+	spin_unlock_irqrestore(&np->smp_lock, flags);
+
+	ncr_flush_done_cmds(done_list);
+
+	return sts;
+}
+
+#if 0 /* unused and broken */
+static int ncr53c8xx_abort(struct scsi_cmnd *cmd)
+{
+	struct ncb *np = ((struct host_data *) cmd->device->host->hostdata)->ncb;
+	int sts;
+	unsigned long flags;
+	struct scsi_cmnd *done_list;
+
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+	printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n",
+		cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout);
+#else
+	printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid);
+#endif
+
+	NCR_LOCK_NCB(np, flags);
+
+#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS
+	/*
+	 * We have to just ignore abort requests in some situations.
+	 */
+	if (cmd->serial_number != cmd->serial_number_at_timeout) {
+		sts = SCSI_ABORT_NOT_RUNNING;
+		goto out;
+	}
+#endif
+
+	sts = ncr_abort_command(np, cmd);
+out:
+	done_list     = np->done_list;
+	np->done_list = NULL;
+	NCR_UNLOCK_NCB(np, flags);
+
+	ncr_flush_done_cmds(done_list);
+
+	return sts;
+}
+#endif
+
+
+/*
+**	Scsi command waiting list management.
+**
+**	It may happen that we cannot insert a scsi command into the start queue,
+**	in the following circumstances.
+** 		Too few preallocated ccb(s), 
+**		maxtags < cmd_per_lun of the Linux host control block,
+**		etc...
+**	Such scsi commands are inserted into a waiting list.
+**	When a scsi command complete, we try to requeue the commands of the
+**	waiting list.
+*/
+
+#define next_wcmd host_scribble
+
+static void insert_into_waiting_list(struct ncb *np, struct scsi_cmnd *cmd)
+{
+	struct scsi_cmnd *wcmd;
+
+#ifdef DEBUG_WAITING_LIST
+	printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd);
+#endif
+	cmd->next_wcmd = NULL;
+	if (!(wcmd = np->waiting_list)) np->waiting_list = cmd;
+	else {
+		while ((wcmd->next_wcmd) != 0)
+			wcmd = (struct scsi_cmnd *) wcmd->next_wcmd;
+		wcmd->next_wcmd = (char *) cmd;
+	}
+}
+
+static struct scsi_cmnd *retrieve_from_waiting_list(int to_remove, struct ncb *np, struct scsi_cmnd *cmd)
+{
+	struct scsi_cmnd **pcmd = &np->waiting_list;
+
+	while (*pcmd) {
+		if (cmd == *pcmd) {
+			if (to_remove) {
+				*pcmd = (struct scsi_cmnd *) cmd->next_wcmd;
+				cmd->next_wcmd = NULL;
+			}
+#ifdef DEBUG_WAITING_LIST
+	printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd);
+#endif
+			return cmd;
+		}
+		pcmd = (struct scsi_cmnd **) &(*pcmd)->next_wcmd;
+	}
+	return NULL;
+}
+
+static void process_waiting_list(struct ncb *np, int sts)
+{
+	struct scsi_cmnd *waiting_list, *wcmd;
+
+	waiting_list = np->waiting_list;
+	np->waiting_list = NULL;
+
+#ifdef DEBUG_WAITING_LIST
+	if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts);
+#endif
+	while ((wcmd = waiting_list) != 0) {
+		waiting_list = (struct scsi_cmnd *) wcmd->next_wcmd;
+		wcmd->next_wcmd = NULL;
+		if (sts == DID_OK) {
+#ifdef DEBUG_WAITING_LIST
+	printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd);
+#endif
+			sts = ncr_queue_command(np, wcmd);
+		}
+		if (sts != DID_OK) {
+#ifdef DEBUG_WAITING_LIST
+	printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts);
+#endif
+			wcmd->result = ScsiResult(sts, 0);
+			ncr_queue_done_cmd(np, wcmd);
+		}
+	}
+}
+
+#undef next_wcmd
+
+static ssize_t show_ncr53c8xx_revision(struct class_device *dev, char *buf)
+{
+	struct Scsi_Host *host = class_to_shost(dev);
+	struct host_data *host_data = (struct host_data *)host->hostdata;
+  
+	return snprintf(buf, 20, "0x%x\n", host_data->ncb->revision_id);
+}
+  
+static struct class_device_attribute ncr53c8xx_revision_attr = {
+	.attr	= { .name = "revision", .mode = S_IRUGO, },
+	.show	= show_ncr53c8xx_revision,
+};
+  
+static struct class_device_attribute *ncr53c8xx_host_attrs[] = {
+	&ncr53c8xx_revision_attr,
+	NULL
+};
+
+/*==========================================================
+**
+**	Boot command line.
+**
+**==========================================================
+*/
+#ifdef	MODULE
+char *ncr53c8xx;	/* command line passed by insmod */
+module_param(ncr53c8xx, charp, 0);
+#endif
+
+static int __init ncr53c8xx_setup(char *str)
+{
+	return sym53c8xx__setup(str);
+}
+
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+
+
+/*
+ *	Host attach and initialisations.
+ *
+ *	Allocate host data and ncb structure.
+ *	Request IO region and remap MMIO region.
+ *	Do chip initialization.
+ *	If all is OK, install interrupt handling and
+ *	start the timer daemon.
+ */
+struct Scsi_Host * __init ncr_attach(struct scsi_host_template *tpnt,
+					int unit, struct ncr_device *device)
+{
+	struct host_data *host_data;
+	struct ncb *np = NULL;
+	struct Scsi_Host *instance = NULL;
+	u_long flags = 0;
+	int i;
+
+	if (!tpnt->name)
+		tpnt->name	= SCSI_NCR_DRIVER_NAME;
+	if (!tpnt->shost_attrs)
+		tpnt->shost_attrs = ncr53c8xx_host_attrs;
+
+	tpnt->queuecommand	= ncr53c8xx_queue_command;
+	tpnt->slave_configure	= ncr53c8xx_slave_configure;
+	tpnt->slave_alloc	= ncr53c8xx_slave_alloc;
+	tpnt->eh_bus_reset_handler = ncr53c8xx_bus_reset;
+	tpnt->can_queue		= SCSI_NCR_CAN_QUEUE;
+	tpnt->this_id		= 7;
+	tpnt->sg_tablesize	= SCSI_NCR_SG_TABLESIZE;
+	tpnt->cmd_per_lun	= SCSI_NCR_CMD_PER_LUN;
+	tpnt->use_clustering	= ENABLE_CLUSTERING;
+
+	if (device->differential)
+		driver_setup.diff_support = device->differential;
+
+	printk(KERN_INFO "ncr53c720-%d: rev 0x%x irq %d\n",
+		unit, device->chip.revision_id, device->slot.irq);
+
+	instance = scsi_host_alloc(tpnt, sizeof(*host_data));
+	if (!instance)
+	        goto attach_error;
+	host_data = (struct host_data *) instance->hostdata;
+
+	np = __m_calloc_dma(device->dev, sizeof(struct ncb), "NCB");
+	if (!np)
+		goto attach_error;
+	spin_lock_init(&np->smp_lock);
+	np->dev = device->dev;
+	np->p_ncb = vtobus(np);
+	host_data->ncb = np;
+
+	np->ccb = m_calloc_dma(sizeof(struct ccb), "CCB");
+	if (!np->ccb)
+		goto attach_error;
+
+	/* Store input information in the host data structure.  */
+	np->unit	= unit;
+	np->verbose	= driver_setup.verbose;
+	sprintf(np->inst_name, "ncr53c720-%d", np->unit);
+	np->revision_id	= device->chip.revision_id;
+	np->features	= device->chip.features;
+	np->clock_divn	= device->chip.nr_divisor;
+	np->maxoffs	= device->chip.offset_max;
+	np->maxburst	= device->chip.burst_max;
+	np->myaddr	= device->host_id;
+
+	/* Allocate SCRIPTS areas.  */
+	np->script0 = m_calloc_dma(sizeof(struct script), "SCRIPT");
+	if (!np->script0)
+		goto attach_error;
+	np->scripth0 = m_calloc_dma(sizeof(struct scripth), "SCRIPTH");
+	if (!np->scripth0)
+		goto attach_error;
+
+	init_timer(&np->timer);
+	np->timer.data     = (unsigned long) np;
+	np->timer.function = ncr53c8xx_timeout;
+
+	/* Try to map the controller chip to virtual and physical memory. */
+
+	np->paddr	= device->slot.base;
+	np->paddr2	= (np->features & FE_RAM) ? device->slot.base_2 : 0;
+
+	if (device->slot.base_v)
+		np->vaddr = device->slot.base_v;
+	else
+		np->vaddr = ioremap(device->slot.base_c, 128);
+
+	if (!np->vaddr) {
+		printk(KERN_ERR
+			"%s: can't map memory mapped IO region\n",ncr_name(np));
+		goto attach_error;
+	} else {
+		if (bootverbose > 1)
+			printk(KERN_INFO
+				"%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr);
+	}
+
+	/* Make the controller's registers available.  Now the INB INW INL
+	 * OUTB OUTW OUTL macros can be used safely.
+	 */
+
+	np->reg = (struct ncr_reg __iomem *)np->vaddr;
+
+	/* Do chip dependent initialization.  */
+	ncr_prepare_setting(np);
+
+	if (np->paddr2 && sizeof(struct script) > 4096) {
+		np->paddr2 = 0;
+		printk(KERN_WARNING "%s: script too large, NOT using on chip RAM.\n",
+			ncr_name(np));
+	}
+
+	instance->max_channel	= 0;
+	instance->this_id       = np->myaddr;
+	instance->max_id	= np->maxwide ? 16 : 8;
+	instance->max_lun	= SCSI_NCR_MAX_LUN;
+	instance->base		= (unsigned long) np->reg;
+	instance->irq		= device->slot.irq;
+	instance->unique_id	= device->slot.base;
+	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
+	/* This can happen if you forget to call ncr53c8xx_init from
+	 * your module_init */
+	BUG_ON(!ncr53c8xx_transport_template);
+	instance->transportt	= ncr53c8xx_transport_template;
+	scsi_set_device(instance, device->dev);
+
+	/* Patch script to physical addresses */
+	ncr_script_fill(&script0, &scripth0);
+
+	np->scripth	= np->scripth0;
+	np->p_scripth	= vtobus(np->scripth);
+	np->p_script	= (np->paddr2) ?  np->paddr2 : vtobus(np->script0);
+
+	ncr_script_copy_and_bind(np, (ncrcmd *) &script0,
+			(ncrcmd *) np->script0, sizeof(struct script));
+	ncr_script_copy_and_bind(np, (ncrcmd *) &scripth0,
+			(ncrcmd *) np->scripth0, sizeof(struct scripth));
+	np->ccb->p_ccb	= vtobus (np->ccb);
+
+	/* Patch the script for LED support.  */
+
+	if (np->features & FE_LED0) {
+		np->script0->idle[0]  =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR,  0x01));
+		np->script0->reselected[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+		np->script0->start[0] =
+				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
+	}
+
+	/*
+	 * Look for the target control block of this nexus.
+	 * For i = 0 to 3
+	 *   JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb)
+	 */
+	for (i = 0 ; i < 4 ; i++) {
+		np->jump_tcb[i].l_cmd   =
+				cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3))));
+		np->jump_tcb[i].l_paddr =
+				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_target));
+	}
+
+	ncr_chip_reset(np, 100);
+
+	/* Now check the cache handling of the chipset.  */
+
+	if (ncr_snooptest(np)) {
+		printk(KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n");
+		goto attach_error;
+	}
+
+	/* Install the interrupt handler.  */
+	np->irq = device->slot.irq;
+
+	/* Initialize the fixed part of the default ccb.  */
+	ncr_init_ccb(np, np->ccb);
+
+	/*
+	 * After SCSI devices have been opened, we cannot reset the bus
+	 * safely, so we do it here.  Interrupt handler does the real work.
+	 * Process the reset exception if interrupts are not enabled yet.
+	 * Then enable disconnects.
+	 */
+	spin_lock_irqsave(&np->smp_lock, flags);
+	if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
+		printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
+
+		spin_unlock_irqrestore(&np->smp_lock, flags);
+		goto attach_error;
+	}
+	ncr_exception(np);
+
+	np->disc = 1;
+
+	/*
+	 * The middle-level SCSI driver does not wait for devices to settle.
+	 * Wait synchronously if more than 2 seconds.
+	 */
+	if (driver_setup.settle_delay > 2) {
+		printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n",
+			ncr_name(np), driver_setup.settle_delay);
+		mdelay(1000 * driver_setup.settle_delay);
+	}
+
+	/* start the timeout daemon */
+	np->lasttime=0;
+	ncr_timeout (np);
+
+	/* use SIMPLE TAG messages by default */
+#ifdef SCSI_NCR_ALWAYS_SIMPLE_TAG
+	np->order = M_SIMPLE_TAG;
+#endif
+
+	spin_unlock_irqrestore(&np->smp_lock, flags);
+
+	return instance;
+
+ attach_error:
+	if (!instance)
+		return NULL;
+	printk(KERN_INFO "%s: detaching...\n", ncr_name(np));
+	if (!np)
+		goto unregister;
+	if (np->scripth0)
+		m_free_dma(np->scripth0, sizeof(struct scripth), "SCRIPTH");
+	if (np->script0)
+		m_free_dma(np->script0, sizeof(struct script), "SCRIPT");
+	if (np->ccb)
+		m_free_dma(np->ccb, sizeof(struct ccb), "CCB");
+	m_free_dma(np, sizeof(struct ncb), "NCB");
+	host_data->ncb = NULL;
+
+ unregister:
+	scsi_host_put(instance);
+
+	return NULL;
+}
+
+
+int ncr53c8xx_release(struct Scsi_Host *host)
+{
+	struct host_data *host_data;
+#ifdef DEBUG_NCR53C8XX
+	printk("ncr53c8xx: release\n");
+#endif
+	if (!host)
+		return 1;
+	host_data = (struct host_data *)host->hostdata;
+	if (host_data && host_data->ncb)
+		ncr_detach(host_data->ncb);
+	return 1;
+}
+
+static void ncr53c8xx_set_period(struct scsi_target *starget, int period)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (period > np->maxsync)
+		period = np->maxsync;
+	else if (period < np->minsync)
+		period = np->minsync;
+
+	tp->usrsync = period;
+
+	ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_offset(struct scsi_target *starget, int offset)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (offset > np->maxoffs)
+		offset = np->maxoffs;
+	else if (offset < 0)
+		offset = 0;
+
+	tp->maxoffs = offset;
+
+	ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_set_width(struct scsi_target *starget, int width)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	struct tcb *tp = &np->target[starget->id];
+
+	if (width > np->maxwide)
+		width = np->maxwide;
+	else if (width < 0)
+		width = 0;
+
+	tp->usrwide = width;
+
+	ncr_negotiate(np, tp);
+}
+
+static void ncr53c8xx_get_signalling(struct Scsi_Host *shost)
+{
+	struct ncb *np = ((struct host_data *)shost->hostdata)->ncb;
+	enum spi_signal_type type;
+
+	switch (np->scsi_mode) {
+	case SMODE_SE:
+		type = SPI_SIGNAL_SE;
+		break;
+	case SMODE_HVD:
+		type = SPI_SIGNAL_HVD;
+		break;
+	default:
+		type = SPI_SIGNAL_UNKNOWN;
+		break;
+	}
+	spi_signalling(shost) = type;
+}
+
+static struct spi_function_template ncr53c8xx_transport_functions =  {
+	.set_period	= ncr53c8xx_set_period,
+	.show_period	= 1,
+	.set_offset	= ncr53c8xx_set_offset,
+	.show_offset	= 1,
+	.set_width	= ncr53c8xx_set_width,
+	.show_width	= 1,
+	.get_signalling	= ncr53c8xx_get_signalling,
+};
+
+int __init ncr53c8xx_init(void)
+{
+	ncr53c8xx_transport_template = spi_attach_transport(&ncr53c8xx_transport_functions);
+	if (!ncr53c8xx_transport_template)
+		return -ENODEV;
+	return 0;
+}
+
+void ncr53c8xx_exit(void)
+{
+	spi_release_transport(ncr53c8xx_transport_template);
+}
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
new file mode 100644
index 0000000..05c7b83
--- /dev/null
+++ b/drivers/scsi/ncr53c8xx.h
@@ -0,0 +1,101 @@
+/******************************************************************************
+**  Device driver for the PCI-SCSI NCR538XX controller family.
+**
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  This driver has been ported to Linux from the FreeBSD NCR53C8XX driver
+**  and is currently maintained by
+**
+**          Gerard Roudier              <groudier@free.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**  And has been ported to NetBSD by
+**          Charles M. Hannum           <mycroft@gnu.ai.mit.edu>
+**
+*******************************************************************************
+*/
+
+#ifndef NCR53C8XX_H
+#define NCR53C8XX_H
+
+#include <scsi/scsi_host.h>
+
+#include "sym53c8xx_defs.h"
+
+/*
+	Build a scatter/gather entry.
+	see sym53c8xx_2/sym_hipd.h for more detailed sym_build_sge()
+	implementation ;)
+ */
+
+#define ncr_build_sge(np, data, badd, len)	\
+do {						\
+	(data)->addr = cpu_to_scr(badd);	\
+	(data)->size = cpu_to_scr(len);		\
+} while (0)
+
+/*==========================================================
+**
+**	Structures used by the detection routine to transmit 
+**	device configuration to the attach function.
+**
+**==========================================================
+*/
+struct ncr_slot {
+	u_long	base;
+	u_long	base_2;
+	u_long	base_c;
+	u_long	base_2_c;
+	void __iomem *base_v;
+	void __iomem *base_2_v;
+	int	irq;
+/* port and reg fields to use INB, OUTB macros */
+	volatile struct ncr_reg	__iomem *reg;
+};
+
+/*==========================================================
+**
+**	Structure used by detection routine to save data on 
+**	each detected board for attach.
+**
+**==========================================================
+*/
+struct ncr_device {
+	struct device  *dev;
+	struct ncr_slot  slot;
+	struct ncr_chip  chip;
+	u_char host_id;
+	u8 differential;
+};
+
+extern struct Scsi_Host *ncr_attach(struct scsi_host_template *tpnt, int unit, struct ncr_device *device);
+extern int ncr53c8xx_release(struct Scsi_Host *host);
+irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs);
+extern int ncr53c8xx_init(void);
+extern void ncr53c8xx_exit(void);
+
+#endif /* NCR53C8XX_H */
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
new file mode 100644
index 0000000..acfead1
--- /dev/null
+++ b/drivers/scsi/nsp32.c
@@ -0,0 +1,3585 @@
+/*
+ * NinjaSCSI-32Bi Cardbus, NinjaSCSI-32UDE PCI/CardBus SCSI driver
+ * Copyright (C) 2001, 2002, 2003
+ *      YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ *      GOTO Masanori <gotom@debian.or.jp>, <gotom@debian.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ *
+ * Revision History:
+ *   1.0: Initial Release.
+ *   1.1: Add /proc SDTR status.
+ *        Remove obsolete error handler nsp32_reset.
+ *        Some clean up.
+ *   1.2: PowerPC (big endian) support.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/ctype.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+# include <linux/blk.h>
+#endif
+
+#include "nsp32.h"
+
+
+/***********************************************************************
+ * Module parameters
+ */
+static int       trans_mode = 0;	/* default: BIOS */
+module_param     (trans_mode, int, 0);
+MODULE_PARM_DESC(trans_mode, "transfer mode (0: BIOS(default) 1: Async 2: Ultra20M");
+#define ASYNC_MODE    1
+#define ULTRA20M_MODE 2
+
+static int       auto_param = 0;	/* default: ON */
+module_param     (auto_param, bool, 0);
+MODULE_PARM_DESC(auto_param, "AutoParameter mode (0: ON(default) 1: OFF)");
+
+static int       disc_priv  = 1;	/* default: OFF */
+module_param     (disc_priv, bool, 0);
+MODULE_PARM_DESC(disc_priv,  "disconnection privilege mode (0: ON 1: OFF(default))");
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>, GOTO Masanori <gotom@debian.or.jp>");
+MODULE_DESCRIPTION("Workbit NinjaSCSI-32Bi/UDE CardBus/PCI SCSI host bus adapter module");
+MODULE_LICENSE("GPL");
+
+static const char *nsp32_release_version = "1.2";
+
+
+/****************************************************************************
+ * Supported hardware
+ */
+static struct pci_device_id nsp32_pci_table[] __devinitdata = {
+	{
+		.vendor      = PCI_VENDOR_ID_IODATA,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_IODATA,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_KME,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_KME,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_WBT,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_WORKBIT,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_WORKBIT_STANDARD,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_PCI_WORKBIT,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_LOGITEC,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_PCI_LOGITEC,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_PCI_MELCO,
+	},
+	{
+		.vendor      = PCI_VENDOR_ID_WORKBIT,
+		.device      = PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+		.driver_data = MODEL_PCI_MELCO,
+	},
+	{0,0,},
+};
+MODULE_DEVICE_TABLE(pci, nsp32_pci_table);
+
+static nsp32_hw_data nsp32_data_base;  /* probe <-> detect glue */
+
+
+/*
+ * Period/AckWidth speed conversion table
+ *
+ * Note: This period/ackwidth speed table must be in descending order.
+ */
+static nsp32_sync_table nsp32_sync_table_40M[] = {
+     /* {PNo, AW,   SP,   EP, SREQ smpl}  Speed(MB/s) Period AckWidth */
+	{0x1,  0, 0x0c, 0x0c, SMPL_40M},  /*  20.0 :  50ns,  25ns */
+	{0x2,  0, 0x0d, 0x18, SMPL_40M},  /*  13.3 :  75ns,  25ns */
+	{0x3,  1, 0x19, 0x19, SMPL_40M},  /*  10.0 : 100ns,  50ns */
+	{0x4,  1, 0x1a, 0x1f, SMPL_20M},  /*   8.0 : 125ns,  50ns */
+	{0x5,  2, 0x20, 0x25, SMPL_20M},  /*   6.7 : 150ns,  75ns */
+	{0x6,  2, 0x26, 0x31, SMPL_20M},  /*   5.7 : 175ns,  75ns */
+	{0x7,  3, 0x32, 0x32, SMPL_20M},  /*   5.0 : 200ns, 100ns */
+	{0x8,  3, 0x33, 0x38, SMPL_10M},  /*   4.4 : 225ns, 100ns */
+	{0x9,  3, 0x39, 0x3e, SMPL_10M},  /*   4.0 : 250ns, 100ns */
+};
+
+static nsp32_sync_table nsp32_sync_table_20M[] = {
+	{0x1,  0, 0x19, 0x19, SMPL_40M},  /* 10.0 : 100ns,  50ns */
+	{0x2,  0, 0x1a, 0x25, SMPL_20M},  /*  6.7 : 150ns,  50ns */
+	{0x3,  1, 0x26, 0x32, SMPL_20M},  /*  5.0 : 200ns, 100ns */
+	{0x4,  1, 0x33, 0x3e, SMPL_10M},  /*  4.0 : 250ns, 100ns */
+	{0x5,  2, 0x3f, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 150ns */
+	{0x6,  2, 0x4c, 0x57, SMPL_10M},  /*  2.8 : 350ns, 150ns */
+	{0x7,  3, 0x58, 0x64, SMPL_10M},  /*  2.5 : 400ns, 200ns */
+	{0x8,  3, 0x65, 0x70, SMPL_10M},  /*  2.2 : 450ns, 200ns */
+	{0x9,  3, 0x71, 0x7d, SMPL_10M},  /*  2.0 : 500ns, 200ns */
+};
+
+static nsp32_sync_table nsp32_sync_table_pci[] = {
+	{0x1,  0, 0x0c, 0x0f, SMPL_40M},  /* 16.6 :  60ns,  30ns */
+	{0x2,  0, 0x10, 0x16, SMPL_40M},  /* 11.1 :  90ns,  30ns */
+	{0x3,  1, 0x17, 0x1e, SMPL_20M},  /*  8.3 : 120ns,  60ns */
+	{0x4,  1, 0x1f, 0x25, SMPL_20M},  /*  6.7 : 150ns,  60ns */
+	{0x5,  2, 0x26, 0x2d, SMPL_20M},  /*  5.6 : 180ns,  90ns */
+	{0x6,  2, 0x2e, 0x34, SMPL_10M},  /*  4.8 : 210ns,  90ns */
+	{0x7,  3, 0x35, 0x3c, SMPL_10M},  /*  4.2 : 240ns, 120ns */
+	{0x8,  3, 0x3d, 0x43, SMPL_10M},  /*  3.7 : 270ns, 120ns */
+	{0x9,  3, 0x44, 0x4b, SMPL_10M},  /*  3.3 : 300ns, 120ns */
+};
+
+/*
+ * function declaration
+ */
+/* module entry point */
+static int  __devinit nsp32_probe (struct pci_dev *, const struct pci_device_id *);
+static void __devexit nsp32_remove(struct pci_dev *);
+static int  __init    init_nsp32  (void);
+static void __exit    exit_nsp32  (void);
+
+/* struct Scsi_Host_Template */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+static int         nsp32_proc_info   (struct Scsi_Host *, char *, char **, off_t, int, int);
+#else
+static int         nsp32_proc_info   (char *, char **, off_t, int, int, int);
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+static int         nsp32_detect      (struct pci_dev *pdev);
+#else
+static int         nsp32_detect      (Scsi_Host_Template *);
+#endif
+static int         nsp32_queuecommand(struct scsi_cmnd *,
+		void (*done)(struct scsi_cmnd *));
+static const char *nsp32_info        (struct Scsi_Host *);
+static int         nsp32_release     (struct Scsi_Host *);
+
+/* SCSI error handler */
+static int         nsp32_eh_abort     (struct scsi_cmnd *);
+static int         nsp32_eh_bus_reset (struct scsi_cmnd *);
+static int         nsp32_eh_host_reset(struct scsi_cmnd *);
+
+/* generate SCSI message */
+static void nsp32_build_identify(struct scsi_cmnd *);
+static void nsp32_build_nop     (struct scsi_cmnd *);
+static void nsp32_build_reject  (struct scsi_cmnd *);
+static void nsp32_build_sdtr    (struct scsi_cmnd *, unsigned char, unsigned char);
+
+/* SCSI message handler */
+static int  nsp32_busfree_occur(struct scsi_cmnd *, unsigned short);
+static void nsp32_msgout_occur (struct scsi_cmnd *);
+static void nsp32_msgin_occur  (struct scsi_cmnd *, unsigned long, unsigned short);
+
+static int  nsp32_setup_sg_table    (struct scsi_cmnd *);
+static int  nsp32_selection_autopara(struct scsi_cmnd *);
+static int  nsp32_selection_autoscsi(struct scsi_cmnd *);
+static void nsp32_scsi_done         (struct scsi_cmnd *);
+static int  nsp32_arbitration       (struct scsi_cmnd *, unsigned int);
+static int  nsp32_reselection       (struct scsi_cmnd *, unsigned char);
+static void nsp32_adjust_busfree    (struct scsi_cmnd *, unsigned int);
+static void nsp32_restart_autoscsi  (struct scsi_cmnd *, unsigned short);
+
+/* SCSI SDTR */
+static void nsp32_analyze_sdtr       (struct scsi_cmnd *);
+static int  nsp32_search_period_entry(nsp32_hw_data *, nsp32_target *, unsigned char);
+static void nsp32_set_async          (nsp32_hw_data *, nsp32_target *);
+static void nsp32_set_max_sync       (nsp32_hw_data *, nsp32_target *, unsigned char *, unsigned char *);
+static void nsp32_set_sync_entry     (nsp32_hw_data *, nsp32_target *, int, unsigned char);
+
+/* SCSI bus status handler */
+static void nsp32_wait_req    (nsp32_hw_data *, int);
+static void nsp32_wait_sack   (nsp32_hw_data *, int);
+static void nsp32_sack_assert (nsp32_hw_data *);
+static void nsp32_sack_negate (nsp32_hw_data *);
+static void nsp32_do_bus_reset(nsp32_hw_data *);
+
+/* hardware interrupt handler */
+static irqreturn_t do_nsp32_isr(int, void *, struct pt_regs *);
+
+/* initialize hardware */
+static int  nsp32hw_init(nsp32_hw_data *);
+
+/* EEPROM handler */
+static        int  nsp32_getprom_param (nsp32_hw_data *);
+static        int  nsp32_getprom_at24  (nsp32_hw_data *);
+static        int  nsp32_getprom_c16   (nsp32_hw_data *);
+static        void nsp32_prom_start    (nsp32_hw_data *);
+static        void nsp32_prom_stop     (nsp32_hw_data *);
+static        int  nsp32_prom_read     (nsp32_hw_data *, int);
+static        int  nsp32_prom_read_bit (nsp32_hw_data *);
+static        void nsp32_prom_write_bit(nsp32_hw_data *, int);
+static        void nsp32_prom_set      (nsp32_hw_data *, int, int);
+static        int  nsp32_prom_get      (nsp32_hw_data *, int);
+
+/* debug/warning/info message */
+static void nsp32_message (const char *, int, char *, char *, ...);
+#ifdef NSP32_DEBUG
+static void nsp32_dmessage(const char *, int, int,    char *, ...);
+#endif
+
+/*
+ * max_sectors is currently limited up to 128.
+ */
+static struct scsi_host_template nsp32_template = {
+	.proc_name			= "nsp32",
+	.name				= "Workbit NinjaSCSI-32Bi/UDE",
+	.proc_info			= nsp32_proc_info,
+	.info				= nsp32_info,
+	.queuecommand			= nsp32_queuecommand,
+	.can_queue			= 1,
+	.sg_tablesize			= NSP32_SG_SIZE,
+	.max_sectors			= 128,
+	.cmd_per_lun			= 1,
+	.this_id			= NSP32_HOST_SCSIID,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.eh_abort_handler       	= nsp32_eh_abort,
+/*	.eh_device_reset_handler	= NULL, */
+	.eh_bus_reset_handler		= nsp32_eh_bus_reset,
+	.eh_host_reset_handler		= nsp32_eh_host_reset,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,74))
+	.detect				= nsp32_detect,
+	.release			= nsp32_release,
+#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+	.use_new_eh_code        	= 1,
+#else
+/*	.highmem_io			= 1, */
+#endif
+};
+
+#include "nsp32_io.h"
+
+/***********************************************************************
+ * debug, error print
+ */
+#ifndef NSP32_DEBUG
+# define NSP32_DEBUG_MASK	      0x000000
+# define nsp32_msg(type, args...)     nsp32_message ("", 0, (type), args)
+# define nsp32_dbg(mask, args...)     /* */
+#else
+# define NSP32_DEBUG_MASK	      0xffffff
+# define nsp32_msg(type, args...) \
+	nsp32_message (__FUNCTION__, __LINE__, (type), args)
+# define nsp32_dbg(mask, args...) \
+	nsp32_dmessage(__FUNCTION__, __LINE__, (mask), args)
+#endif
+
+#define NSP32_DEBUG_QUEUECOMMAND	BIT(0)
+#define NSP32_DEBUG_REGISTER		BIT(1)
+#define NSP32_DEBUG_AUTOSCSI		BIT(2)
+#define NSP32_DEBUG_INTR		BIT(3)
+#define NSP32_DEBUG_SGLIST		BIT(4)
+#define NSP32_DEBUG_BUSFREE		BIT(5)
+#define NSP32_DEBUG_CDB_CONTENTS	BIT(6)
+#define NSP32_DEBUG_RESELECTION		BIT(7)
+#define NSP32_DEBUG_MSGINOCCUR		BIT(8)
+#define NSP32_DEBUG_EEPROM		BIT(9)
+#define NSP32_DEBUG_MSGOUTOCCUR		BIT(10)
+#define NSP32_DEBUG_BUSRESET		BIT(11)
+#define NSP32_DEBUG_RESTART		BIT(12)
+#define NSP32_DEBUG_SYNC		BIT(13)
+#define NSP32_DEBUG_WAIT		BIT(14)
+#define NSP32_DEBUG_TARGETFLAG		BIT(15)
+#define NSP32_DEBUG_PROC		BIT(16)
+#define NSP32_DEBUG_INIT		BIT(17)
+#define NSP32_SPECIAL_PRINT_REGISTER	BIT(20)
+
+#define NSP32_DEBUG_BUF_LEN		100
+
+static void nsp32_message(const char *func, int line, char *type, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+#ifndef NSP32_DEBUG
+	printk("%snsp32: %s\n", type, buf);
+#else
+	printk("%snsp32: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+#ifdef NSP32_DEBUG
+static void nsp32_dmessage(const char *func, int line, int mask, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP32_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	if (mask & NSP32_DEBUG_MASK) {
+		printk("nsp32-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
+	}
+}
+#endif
+
+#ifdef NSP32_DEBUG
+# include "nsp32_debug.c"
+#else
+# define show_command(arg)   /* */
+# define show_busphase(arg)  /* */
+# define show_autophase(arg) /* */
+#endif
+
+/*
+ * IDENTIFY Message
+ */
+static void nsp32_build_identify(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	int pos             = data->msgout_len;
+	int mode            = FALSE;
+
+	/* XXX: Auto DiscPriv detection is progressing... */
+	if (disc_priv == 0) {
+		/* mode = TRUE; */
+	}
+
+	data->msgoutbuf[pos] = IDENTIFY(mode, SCpnt->device->lun); pos++;
+
+	data->msgout_len = pos;
+}
+
+/*
+ * SDTR Message Routine
+ */
+static void nsp32_build_sdtr(struct scsi_cmnd    *SCpnt,
+			     unsigned char period,
+			     unsigned char offset)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	int pos             = data->msgout_len;
+
+	data->msgoutbuf[pos] = EXTENDED_MESSAGE;  pos++;
+	data->msgoutbuf[pos] = EXTENDED_SDTR_LEN; pos++;
+	data->msgoutbuf[pos] = EXTENDED_SDTR;     pos++;
+	data->msgoutbuf[pos] = period;            pos++;
+	data->msgoutbuf[pos] = offset;            pos++;
+
+	data->msgout_len = pos;
+}
+
+/*
+ * No Operation Message
+ */
+static void nsp32_build_nop(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	int            pos  = data->msgout_len;
+
+	if (pos != 0) {
+		nsp32_msg(KERN_WARNING,
+			  "Some messages are already contained!");
+		return;
+	}
+
+	data->msgoutbuf[pos] = NOP; pos++;
+	data->msgout_len = pos;
+}
+
+/*
+ * Reject Message
+ */
+static void nsp32_build_reject(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	int            pos  = data->msgout_len;
+
+	data->msgoutbuf[pos] = MESSAGE_REJECT; pos++;
+	data->msgout_len = pos;
+}
+	
+/*
+ * timer
+ */
+#if 0
+static void nsp32_start_timer(struct scsi_cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->host->io_port;
+
+	nsp32_dbg(NSP32_DEBUG_INTR, "timer=%d", time);
+
+	if (time & (~TIMER_CNT_MASK)) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "timer set overflow");
+	}
+
+	nsp32_write2(base, TIMER_SET, time & TIMER_CNT_MASK);
+}
+#endif
+
+
+/*
+ * set SCSI command and other parameter to asic, and start selection phase
+ */
+static int nsp32_selection_autopara(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int	base    = SCpnt->device->host->io_port;
+	unsigned int	host_id = SCpnt->device->host->this_id;
+	unsigned char	target  = SCpnt->device->id;
+	nsp32_autoparam *param  = data->autoparam;
+	unsigned char	phase;
+	int		i, ret;
+	unsigned int	msgout;
+	u16_le	        s;
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
+
+	/*
+	 * check bus free
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if (phase != BUSMON_BUS_FREE) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		show_busphase(phase & BUSMON_PHASE_MASK);
+		SCpnt->result = DID_BUS_BUSY << 16;
+		return FALSE;
+	}
+
+	/*
+	 * message out
+	 *
+	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgout_len == 0) {
+		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		return FALSE;
+	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
+		msgout = 0;
+		for (i = 0; i < data->msgout_len; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgout_len; /* len */
+	} else {
+		/* data->msgout_len > 3 */
+		msgout = 0;
+	}
+
+	// nsp_dbg(NSP32_DEBUG_AUTOSCSI, "sel time out=0x%x\n", nsp32_read2(base, SEL_TIME_OUT));
+	// nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
+
+	/*
+	 * setup asic parameter
+	 */
+	memset(param, 0, sizeof(nsp32_autoparam));
+
+	/* cdb */
+	for (i = 0; i < SCpnt->cmd_len; i++) {
+		param->cdb[4 * i] = SCpnt->cmnd[i];
+	}
+
+	/* outgoing messages */
+	param->msgout = cpu_to_le32(msgout);
+
+	/* syncreg, ackwidth, target id, SREQ sampling rate */
+	param->syncreg    = data->cur_target->syncreg;
+	param->ackwidth   = data->cur_target->ackwidth;
+	param->target_id  = BIT(host_id) | BIT(target);
+	param->sample_reg = data->cur_target->sample_reg;
+
+	// nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "sample rate=0x%x\n", data->cur_target->sample_reg);
+
+	/* command control */
+	param->command_control = cpu_to_le16(CLEAR_CDB_FIFO_POINTER |
+					     AUTOSCSI_START         |
+					     AUTO_MSGIN_00_OR_04    |
+					     AUTO_MSGIN_02          |
+					     AUTO_ATN               );
+
+
+	/* transfer control */
+	s = 0;
+	switch (data->trans_method) {
+	case NSP32_TRANSFER_BUSMASTER:
+		s |= BM_START;
+		break;
+	case NSP32_TRANSFER_MMIO:
+		s |= CB_MMIO_MODE;
+		break;
+	case NSP32_TRANSFER_PIO:
+		s |= CB_IO_MODE;
+		break;
+	default:
+		nsp32_msg(KERN_ERR, "unknown trans_method");
+		break;
+	}
+	/*
+	 * OR-ed BLIEND_MODE, FIFO intr is decreased, instead of PCI bus waits.
+	 * For bus master transfer, it's taken off.
+	 */
+	s |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	param->transfer_control = cpu_to_le16(s);
+
+	/* sg table addr */
+	param->sgt_pointer = cpu_to_le32(data->cur_lunt->sglun_paddr);
+
+	/*
+	 * transfer parameter to ASIC
+	 */
+	nsp32_write4(base, SGT_ADR,         data->auto_paddr);
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER |
+		                            AUTO_PARAMETER         );
+
+	/*
+	 * Check arbitration
+	 */
+	ret = nsp32_arbitration(SCpnt, base);
+
+	return ret;
+}
+
+
+/*
+ * Selection with AUTO SCSI (without AUTO PARAMETER)
+ */
+static int nsp32_selection_autoscsi(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data  *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int	base    = SCpnt->device->host->io_port;
+	unsigned int	host_id = SCpnt->device->host->this_id;
+	unsigned char	target  = SCpnt->device->id;
+	unsigned char	phase;
+	int		status;
+	unsigned short	command	= 0;
+	unsigned int	msgout  = 0;
+	unsigned short	execph;
+	int		i;
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "in");
+
+	/*
+	 * IRQ disable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	/*
+	 * check bus line
+	 */
+	phase = nsp32_read1(base, SCSI_BUS_MONITOR);
+	if(((phase & BUSMON_BSY) == 1) || (phase & BUSMON_SEL) == 1) {
+		nsp32_msg(KERN_WARNING, "bus busy");
+		SCpnt->result = DID_BUS_BUSY << 16;
+		status = 1;
+		goto out;
+        }
+
+	/*
+	 * clear execph
+	 */
+	execph = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+
+	/*
+	 * clear FIFO counter to set CDBs
+	 */
+	nsp32_write2(base, COMMAND_CONTROL, CLEAR_CDB_FIFO_POINTER);
+
+	/*
+	 * set CDB0 - CDB15
+	 */
+	for (i = 0; i < SCpnt->cmd_len; i++) {
+		nsp32_write1(base, COMMAND_DATA, SCpnt->cmnd[i]);
+        }
+	nsp32_dbg(NSP32_DEBUG_CDB_CONTENTS, "CDB[0]=[0x%x]", SCpnt->cmnd[0]);
+
+	/*
+	 * set SCSIOUT LATCH(initiator)/TARGET(target) (OR-ed) ID
+	 */
+	nsp32_write1(base, SCSI_OUT_LATCH_TARGET_ID, BIT(host_id) | BIT(target));
+
+	/*
+	 * set SCSI MSGOUT REG
+	 *
+	 * Note: If the range of msgout_len is 1 - 3, fill scsi_msgout.
+	 *       over 3 messages needs another routine.
+	 */
+	if (data->msgout_len == 0) {
+		nsp32_msg(KERN_ERR, "SCSI MsgOut without any message!");
+		SCpnt->result = DID_ERROR << 16;
+		status = 1;
+		goto out;
+	} else if (data->msgout_len > 0 && data->msgout_len <= 3) {
+		msgout = 0;
+		for (i = 0; i < data->msgout_len; i++) {
+			/*
+			 * the sending order of the message is:
+			 *  MCNT 3: MSG#0 -> MSG#1 -> MSG#2
+			 *  MCNT 2:          MSG#1 -> MSG#2
+			 *  MCNT 1:                   MSG#2    
+			 */
+			msgout >>= 8;
+			msgout |= ((unsigned int)(data->msgoutbuf[i]) << 24);
+		}
+		msgout |= MV_VALID;	/* MV valid */
+		msgout |= (unsigned int)data->msgout_len; /* len */
+		nsp32_write4(base, SCSI_MSG_OUT, msgout);
+	} else {
+		/* data->msgout_len > 3 */
+		nsp32_write4(base, SCSI_MSG_OUT, 0);
+	}
+
+	/*
+	 * set selection timeout(= 250ms)
+	 */
+	nsp32_write2(base, SEL_TIME_OUT,   SEL_TIMEOUT_TIME);
+
+	/*
+	 * set SREQ hazard killer sampling rate
+	 * 
+	 * TODO: sample_rate (BASE+0F) is 0 when internal clock = 40MHz.
+	 *      check other internal clock!
+	 */
+	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT,      ARBIT_CLEAR);
+
+	/*
+	 * set SYNCREG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG,  data->cur_target->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "syncreg=0x%x, ackwidth=0x%x, sgtpaddr=0x%x, id=0x%x",
+		  nsp32_read1(base, SYNC_REG), nsp32_read1(base, ACK_WIDTH),
+		  nsp32_read4(base, SGT_ADR), nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "msgout_len=%d, msgout=0x%x",
+		  data->msgout_len, msgout);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	command = 0;
+	command |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			command |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		command |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		command |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, command);
+
+	/*
+	 * start AUTO SCSI, kick off arbitration
+	 */
+	command = (CLEAR_CDB_FIFO_POINTER |
+		   AUTOSCSI_START         |
+		   AUTO_MSGIN_00_OR_04    |
+		   AUTO_MSGIN_02          |
+		   AUTO_ATN                );
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	/*
+	 * Check arbitration
+	 */
+	status = nsp32_arbitration(SCpnt, base);
+
+ out:
+	/*
+	 * IRQ enable
+	 */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return status;
+}
+
+
+/*
+ * Arbitration Status Check
+ *	
+ * Note: Arbitration counter is waited during ARBIT_GO is not lifting.
+ *	 Using udelay(1) consumes CPU time and system time, but 
+ *	 arbitration delay time is defined minimal 2.4us in SCSI
+ *	 specification, thus udelay works as coarse grained wait timer.
+ */
+static int nsp32_arbitration(struct scsi_cmnd *SCpnt, unsigned int base)
+{
+	unsigned char arbit;
+	int	      status = TRUE;
+	int	      time   = 0;
+
+	do {
+		arbit = nsp32_read1(base, ARBIT_STATUS);
+		time++;
+	} while ((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		 (time <= ARBIT_TIMEOUT_TIME));
+
+	nsp32_dbg(NSP32_DEBUG_AUTOSCSI,
+		  "arbit: 0x%x, delay time: %d", arbit, time);
+
+	if (arbit & ARBIT_WIN) {
+		/* Arbitration succeeded */
+		SCpnt->result = DID_OK << 16;
+		nsp32_index_write1(base, EXT_PORT, LED_ON); /* PCI LED on */
+	} else if (arbit & ARBIT_FAIL) {
+		/* Arbitration failed */
+		SCpnt->result = DID_BUS_BUSY << 16;
+		status = FALSE;
+	} else {
+		/*
+		 * unknown error or ARBIT_GO timeout,
+		 * something lock up! guess no connection.
+		 */
+		nsp32_dbg(NSP32_DEBUG_AUTOSCSI, "arbit timeout");
+		SCpnt->result = DID_NO_CONNECT << 16;
+		status = FALSE;
+        }
+
+	/*
+	 * clear Arbit
+	 */
+	nsp32_write1(base, SET_ARBIT, ARBIT_CLEAR);
+
+	return status;
+}
+
+
+/*
+ * reselection
+ *
+ * Note: This reselection routine is called from msgin_occur,
+ *	 reselection target id&lun must be already set.
+ *	 SCSI-2 says IDENTIFY implies RESTORE_POINTER operation.
+ */
+static int nsp32_reselection(struct scsi_cmnd *SCpnt, unsigned char newlun)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   host_id = SCpnt->device->host->this_id;
+	unsigned int   base    = SCpnt->device->host->io_port;
+	unsigned char  tmpid, newid;
+
+	nsp32_dbg(NSP32_DEBUG_RESELECTION, "enter");
+
+	/*
+	 * calculate reselected SCSI ID
+	 */
+	tmpid = nsp32_read1(base, RESELECT_ID);
+	tmpid &= (~BIT(host_id));
+	newid = 0;
+	while (tmpid) {
+		if (tmpid & 1) {
+			break;
+		}
+		tmpid >>= 1;
+		newid++;
+	}
+
+	/*
+	 * If reselected New ID:LUN is not existed
+	 * or current nexus is not existed, unexpected
+	 * reselection is occurred. Send reject message.
+	 */
+	if (newid >= ARRAY_SIZE(data->lunt) || newlun >= ARRAY_SIZE(data->lunt[0])) {
+		nsp32_msg(KERN_WARNING, "unknown id/lun");
+		return FALSE;
+	} else if(data->lunt[newid][newlun].SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "no SCSI command is processing");
+		return FALSE;
+	}
+
+	data->cur_id    = newid;
+	data->cur_lun   = newlun;
+	data->cur_target = &(data->target[newid]);
+	data->cur_lunt   = &(data->lunt[newid][newlun]);
+
+	/* reset SACK/SavedACK counter (or ALL clear?) */
+	nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+	return TRUE;
+}
+
+
+/*
+ * nsp32_setup_sg_table - build scatter gather list for transfer data
+ *			    with bus master.
+ *
+ * Note: NinjaSCSI-32Bi/UDE bus master can not transfer over 64KB at a time.
+ */
+static int nsp32_setup_sg_table(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	struct scatterlist   *sgl;
+	nsp32_sgtable *sgt = data->cur_lunt->sglun->sgt;
+	int num, i;
+	u32_le l;
+
+	if (SCpnt->request_bufflen == 0) {
+		return TRUE;
+	}
+
+	if (sgt == NULL) {
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "SGT == null");
+		return FALSE;
+	}
+
+	if (SCpnt->use_sg) {
+		sgl = (struct scatterlist *)SCpnt->request_buffer;
+		num = pci_map_sg(data->Pci, sgl, SCpnt->use_sg,
+				 SCpnt->sc_data_direction);
+		for (i = 0; i < num; i++) {
+			/*
+			 * Build nsp32_sglist, substitute sg dma addresses.
+			 */
+			sgt[i].addr = cpu_to_le32(sg_dma_address(sgl));
+			sgt[i].len  = cpu_to_le32(sg_dma_len(sgl));
+			sgl++;
+
+			if (le32_to_cpu(sgt[i].len) > 0x10000) {
+				nsp32_msg(KERN_ERR,
+					"can't transfer over 64KB at a time, size=0x%lx", le32_to_cpu(sgt[i].len));
+				return FALSE;
+			}
+			nsp32_dbg(NSP32_DEBUG_SGLIST,
+				  "num 0x%x : addr 0x%lx len 0x%lx",
+				  i,
+				  le32_to_cpu(sgt[i].addr),
+				  le32_to_cpu(sgt[i].len ));
+		}
+
+		/* set end mark */
+		l = le32_to_cpu(sgt[num-1].len);
+		sgt[num-1].len = cpu_to_le32(l | SGTEND);
+
+	} else {
+		SCpnt->SCp.have_data_in	= pci_map_single(data->Pci,
+			SCpnt->request_buffer, SCpnt->request_bufflen,
+			SCpnt->sc_data_direction);
+
+		sgt[0].addr = cpu_to_le32(SCpnt->SCp.have_data_in);
+		sgt[0].len  = cpu_to_le32(SCpnt->request_bufflen | SGTEND); /* set end mark */
+
+		if (SCpnt->request_bufflen > 0x10000) {
+			nsp32_msg(KERN_ERR,
+				  "can't transfer over 64KB at a time, size=0x%lx", SCpnt->request_bufflen);
+			return FALSE;
+		}
+		nsp32_dbg(NSP32_DEBUG_SGLIST, "single : addr 0x%lx len=0x%lx",
+			  le32_to_cpu(sgt[0].addr),
+			  le32_to_cpu(sgt[0].len ));
+	}
+
+	return TRUE;
+}
+
+static int nsp32_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	nsp32_target *target;
+	nsp32_lunt   *cur_lunt;
+	int ret;
+
+	nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+		  "enter. target: 0x%x LUN: 0x%x cmnd: 0x%x cmndlen: 0x%x "
+		  "use_sg: 0x%x reqbuf: 0x%lx reqlen: 0x%x",
+		  SCpnt->device->id, SCpnt->device->lun, SCpnt->cmnd[0], SCpnt->cmd_len,
+		  SCpnt->use_sg, SCpnt->request_buffer, SCpnt->request_bufflen);
+
+	if (data->CurrentSC != NULL) {
+		nsp32_msg(KERN_ERR, "Currentsc != NULL. Cancel this command request");
+		data->CurrentSC = NULL;
+		SCpnt->result   = DID_NO_CONNECT << 16;
+		done(SCpnt);
+		return 0;
+	}
+
+	/* check target ID is not same as this initiator ID */
+	if (SCpnt->device->id == SCpnt->device->host->this_id) {
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "terget==host???");
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 0;
+	}
+
+	/* check target LUN is allowable value */
+	if (SCpnt->device->lun >= MAX_LUN) {
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "no more lun");
+		SCpnt->result = DID_BAD_TARGET << 16;
+		done(SCpnt);
+		return 0;
+	}
+
+	show_command(SCpnt);
+
+	SCpnt->scsi_done     = done;
+	data->CurrentSC      = SCpnt;
+	SCpnt->SCp.Status    = CHECK_CONDITION;
+	SCpnt->SCp.Message   = 0;
+	SCpnt->resid         = SCpnt->request_bufflen;
+
+	SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+	SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+	SCpnt->SCp.buffer	    = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+
+	/* initialize data */
+	data->msgout_len	= 0;
+	data->msgin_len		= 0;
+	cur_lunt		= &(data->lunt[SCpnt->device->id][SCpnt->device->lun]);
+	cur_lunt->SCpnt		= SCpnt;
+	cur_lunt->save_datp	= 0;
+	cur_lunt->msgin03	= FALSE;
+	data->cur_lunt		= cur_lunt;
+	data->cur_id		= SCpnt->device->id;
+	data->cur_lun		= SCpnt->device->lun;
+
+	ret = nsp32_setup_sg_table(SCpnt);
+	if (ret == FALSE) {
+		nsp32_msg(KERN_ERR, "SGT fail");
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(SCpnt);
+		return 0;
+	}
+
+	/* Build IDENTIFY */
+	nsp32_build_identify(SCpnt);
+
+	/* 
+	 * If target is the first time to transfer after the reset
+	 * (target don't have SDTR_DONE and SDTR_INITIATOR), sync
+	 * message SDTR is needed to do synchronous transfer.
+	 */
+	target = &data->target[SCpnt->device->id];
+	data->cur_target = target;
+
+	if (!(target->sync_flag & (SDTR_DONE | SDTR_INITIATOR | SDTR_TARGET))) {
+		unsigned char period, offset;
+
+		if (trans_mode != ASYNC_MODE) {
+			nsp32_set_max_sync(data, target, &period, &offset);
+			nsp32_build_sdtr(SCpnt, period, offset);
+			target->sync_flag |= SDTR_INITIATOR;
+		} else {
+			nsp32_set_async(data, target);
+			target->sync_flag |= SDTR_DONE;
+		}
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR: entry: %d start_period: 0x%x offset: 0x%x\n",
+			  target->limit_entry, period, offset);
+	} else if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * It was negotiating SDTR with target, sending from the
+		 * initiator, but there are no chance to remove this flag.
+		 * Set async because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "SDTR_INITIATOR: fall back to async");
+	} else if (target->sync_flag & SDTR_TARGET) {
+		/*
+		 * It was negotiating SDTR with target, sending from target,
+		 * but there are no chance to remove this flag.  Set async
+		 * because we don't get proper negotiation.
+		 */
+		nsp32_set_async(data, target);
+		target->sync_flag &= ~SDTR_TARGET;
+		target->sync_flag |= SDTR_DONE;
+
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND,
+			  "Unknown SDTR from target is reached, fall back to async.");
+	}
+
+	nsp32_dbg(NSP32_DEBUG_TARGETFLAG,
+		  "target: %d sync_flag: 0x%x syncreg: 0x%x ackwidth: 0x%x",
+		  SCpnt->device->id, target->sync_flag, target->syncreg,
+		  target->ackwidth);
+
+	/* Selection */
+	if (auto_param == 0) {
+		ret = nsp32_selection_autopara(SCpnt);
+	} else {
+		ret = nsp32_selection_autoscsi(SCpnt);
+	}
+
+	if (ret != TRUE) {
+		nsp32_dbg(NSP32_DEBUG_QUEUECOMMAND, "selection fail");
+		nsp32_scsi_done(SCpnt);
+	}
+
+	return 0;
+}
+
+/* initialize asic */
+static int nsp32hw_init(nsp32_hw_data *data)
+{
+	unsigned int   base = data->BaseAddress;
+	unsigned short irq_stat;
+	unsigned long  lc_reg;
+	unsigned char  power;
+
+	lc_reg = nsp32_index_read4(base, CFG_LATE_CACHE);
+	if ((lc_reg & 0xff00) == 0) {
+		lc_reg |= (0x20 << 8);
+		nsp32_index_write2(base, CFG_LATE_CACHE, lc_reg & 0xffff);
+	}
+
+	nsp32_write2(base, IRQ_CONTROL,        IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_write2(base, TRANSFER_CONTROL,   0);
+	nsp32_write4(base, BM_CNT,             0);
+	nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+	do {
+		irq_stat = nsp32_read2(base, IRQ_STATUS);
+		nsp32_dbg(NSP32_DEBUG_INIT, "irq_stat 0x%x", irq_stat);
+	} while (irq_stat & IRQSTATUS_ANY_IRQ);
+
+	/*
+	 * Fill FIFO_FULL_SHLD, FIFO_EMPTY_SHLD. Below parameter is
+	 *  designated by specification.
+	 */
+	if ((data->trans_method & NSP32_TRANSFER_PIO) ||
+	    (data->trans_method & NSP32_TRANSFER_MMIO)) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x40);
+		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x40);
+	} else if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		nsp32_index_write1(base, FIFO_FULL_SHLD_COUNT,  0x10);
+		nsp32_index_write1(base, FIFO_EMPTY_SHLD_COUNT, 0x60);
+	} else {
+		nsp32_dbg(NSP32_DEBUG_INIT, "unknown transfer mode");
+	}
+
+	nsp32_dbg(NSP32_DEBUG_INIT, "full 0x%x emp 0x%x",
+		  nsp32_index_read1(base, FIFO_FULL_SHLD_COUNT),
+		  nsp32_index_read1(base, FIFO_EMPTY_SHLD_COUNT));
+
+	nsp32_index_write1(base, CLOCK_DIV, data->clock);
+	nsp32_index_write1(base, BM_CYCLE,  MEMRD_CMD1 | SGT_AUTO_PARA_MEMED_CMD);
+	nsp32_write1(base, PARITY_CONTROL, 0);	/* parity check is disable */
+
+	/*
+	 * initialize MISC_WRRD register
+	 * 
+	 * Note: Designated parameters is obeyed as following:
+	 *	MISC_SCSI_DIRECTION_DETECTOR_SELECT: It must be set.
+	 *	MISC_MASTER_TERMINATION_SELECT:      It must be set.
+	 *	MISC_BMREQ_NEGATE_TIMING_SEL:	     It should be set.
+	 *	MISC_AUTOSEL_TIMING_SEL:	     It should be set.
+	 *	MISC_BMSTOP_CHANGE2_NONDATA_PHASE:   It should be set.
+	 *	MISC_DELAYED_BMSTART:		     It's selected for safety.
+	 *
+	 * Note: If MISC_BMSTOP_CHANGE2_NONDATA_PHASE is set, then
+	 *	we have to set TRANSFERCONTROL_BM_START as 0 and set
+	 *	appropriate value before restarting bus master transfer.
+	 */
+	nsp32_index_write2(base, MISC_WR,
+			   (SCSI_DIRECTION_DETECTOR_SELECT |
+			    DELAYED_BMSTART                |
+			    MASTER_TERMINATION_SELECT      |
+			    BMREQ_NEGATE_TIMING_SEL        |
+			    AUTOSEL_TIMING_SEL             |
+			    BMSTOP_CHANGE2_NONDATA_PHASE));
+
+	nsp32_index_write1(base, TERM_PWR_CONTROL, 0);
+	power = nsp32_index_read1(base, TERM_PWR_CONTROL);
+	if (!(power & SENSE)) {
+		nsp32_msg(KERN_INFO, "term power on");
+		nsp32_index_write1(base, TERM_PWR_CONTROL, BPWR);
+	}
+
+	nsp32_write2(base, TIMER_SET, TIMER_STOP);
+	nsp32_write2(base, TIMER_SET, TIMER_STOP); /* Required 2 times */
+
+	nsp32_write1(base, SYNC_REG,     0);
+	nsp32_write1(base, ACK_WIDTH,    0);
+	nsp32_write2(base, SEL_TIME_OUT, SEL_TIMEOUT_TIME);
+
+	/*
+	 * enable to select designated IRQ (except for
+	 * IRQSELECT_SERR, IRQSELECT_PERR, IRQSELECT_BMCNTERR)
+	 */
+	nsp32_index_write2(base, IRQ_SELECT, IRQSELECT_TIMER_IRQ         |
+			                     IRQSELECT_SCSIRESET_IRQ     |
+			                     IRQSELECT_FIFO_SHLD_IRQ     |
+			                     IRQSELECT_RESELECT_IRQ      |
+			                     IRQSELECT_PHASE_CHANGE_IRQ  |
+			                     IRQSELECT_AUTO_SCSI_SEQ_IRQ |
+			                  //   IRQSELECT_BMCNTERR_IRQ      |
+			                     IRQSELECT_TARGET_ABORT_IRQ  |
+			                     IRQSELECT_MASTER_ABORT_IRQ );
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	/* PCI LED off */
+	nsp32_index_write1(base, EXT_PORT_DDR, LED_OFF);
+	nsp32_index_write1(base, EXT_PORT,     LED_OFF);
+
+	return TRUE;
+}
+
+
+/* interrupt routine */
+static irqreturn_t do_nsp32_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	nsp32_hw_data *data = dev_id;
+	unsigned int base = data->BaseAddress;
+	struct scsi_cmnd *SCpnt = data->CurrentSC;
+	unsigned short auto_stat, irq_stat, trans_stat;
+	unsigned char busmon, busphase;
+	unsigned long flags;
+	int ret;
+	int handled = 0;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+	struct Scsi_Host *host = data->Host;
+	spin_lock_irqsave(host->host_lock, flags);
+#else
+	spin_lock_irqsave(&io_request_lock, flags);
+#endif
+
+	/*
+	 * IRQ check, then enable IRQ mask
+	 */
+	irq_stat = nsp32_read2(base, IRQ_STATUS);
+	nsp32_dbg(NSP32_DEBUG_INTR, 
+		  "enter IRQ: %d, IRQstatus: 0x%x", irq, irq_stat);
+	/* is this interrupt comes from Ninja asic? */
+	if ((irq_stat & IRQSTATUS_ANY_IRQ) == 0) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "shared interrupt: irq other 0x%x", irq_stat);
+		goto out2;
+	}
+	handled = 1;
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+
+	busmon = nsp32_read1(base, SCSI_BUS_MONITOR);
+	busphase = busmon & BUSMON_PHASE_MASK;
+
+	trans_stat = nsp32_read2(base, TRANSFER_STATUS);
+	if ((irq_stat == 0xffff) && (trans_stat == 0xffff)) {
+		nsp32_msg(KERN_INFO, "card disconnect");
+		if (data->CurrentSC != NULL) {
+			nsp32_msg(KERN_INFO, "clean up current SCSI command");
+			SCpnt->result = DID_BAD_TARGET << 16;
+			nsp32_scsi_done(SCpnt);
+		}
+		goto out;
+	}
+
+	/* Timer IRQ */
+	if (irq_stat & IRQSTATUS_TIMER_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "timer stop");
+		nsp32_write2(base, TIMER_SET, TIMER_STOP);
+		goto out;
+	}
+
+	/* SCSI reset */
+	if (irq_stat & IRQSTATUS_SCSIRESET_IRQ) {
+		nsp32_msg(KERN_INFO, "detected someone do bus reset");
+		nsp32_do_bus_reset(data);
+		if (SCpnt != NULL) {
+			SCpnt->result = DID_RESET << 16;
+			nsp32_scsi_done(SCpnt);
+		}
+		goto out;
+	}
+
+	if (SCpnt == NULL) {
+		nsp32_msg(KERN_WARNING, "SCpnt==NULL this can't be happened");
+		nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
+		goto out;
+	}
+
+	/*
+	 * AutoSCSI Interrupt.
+	 * Note: This interrupt is occurred when AutoSCSI is finished.  Then
+	 * check SCSIEXECUTEPHASE, and do appropriate action.  Each phases are
+	 * recorded when AutoSCSI sequencer has been processed.
+	 */
+	if(irq_stat & IRQSTATUS_AUTOSCSI_IRQ) {
+		/* getting SCSI executed phase */
+		auto_stat = nsp32_read2(base, SCSI_EXECUTE_PHASE);
+		nsp32_write2(base, SCSI_EXECUTE_PHASE, 0);
+
+		/* Selection Timeout, go busfree phase. */
+		if (auto_stat & SELECTION_TIMEOUT) {
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "selection timeout occurred");
+
+			SCpnt->result = DID_TIME_OUT << 16;
+			nsp32_scsi_done(SCpnt);
+			goto out;
+		}
+
+		if (auto_stat & MSGOUT_PHASE) {
+			/*
+			 * MsgOut phase was processed.
+			 * If MSG_IN_OCCUER is not set, then MsgOut phase is
+			 * completed. Thus, msgout_len must reset.  Otherwise,
+			 * nothing to do here. If MSG_OUT_OCCUER is occurred,
+			 * then we will encounter the condition and check.
+			 */
+			if (!(auto_stat & MSG_IN_OCCUER) &&
+			     (data->msgout_len <= 3)) {
+				/*
+				 * !MSG_IN_OCCUER && msgout_len <=3
+				 *   ---> AutoSCSI with MSGOUTreg is processed.
+				 */
+				data->msgout_len = 0;
+			};
+
+			nsp32_dbg(NSP32_DEBUG_INTR, "MsgOut phase processed");
+		}
+
+		if ((auto_stat & DATA_IN_PHASE) &&
+		    (SCpnt->resid > 0) &&
+		    ((nsp32_read2(base, FIFO_REST_CNT) & FIFO_REST_MASK) != 0)) {
+			printk( "auto+fifo\n");
+			//nsp32_pio_read(SCpnt);
+		}
+
+		if (auto_stat & (DATA_IN_PHASE | DATA_OUT_PHASE)) {
+			/* DATA_IN_PHASE/DATA_OUT_PHASE was processed. */
+			nsp32_dbg(NSP32_DEBUG_INTR,
+				  "Data in/out phase processed");
+
+			/* read BMCNT, SGT pointer addr */
+			nsp32_dbg(NSP32_DEBUG_INTR, "BMCNT=0x%lx", 
+				    nsp32_read4(base, BM_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "addr=0x%lx", 
+				    nsp32_read4(base, SGT_ADR));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SACK=0x%lx", 
+				    nsp32_read4(base, SACK_CNT));
+			nsp32_dbg(NSP32_DEBUG_INTR, "SSACK=0x%lx", 
+				    nsp32_read4(base, SAVED_SACK_CNT));
+
+			SCpnt->resid = 0; /* all data transfered! */
+		}
+
+		/*
+		 * MsgIn Occur
+		 */
+		if (auto_stat & MSG_IN_OCCUER) {
+			nsp32_msgin_occur(SCpnt, irq_stat, auto_stat);
+		}
+
+		/*
+		 * MsgOut Occur
+		 */
+		if (auto_stat & MSG_OUT_OCCUER) {
+			nsp32_msgout_occur(SCpnt);
+		}
+
+		/*
+		 * Bus Free Occur
+		 */
+		if (auto_stat & BUS_FREE_OCCUER) {
+			ret = nsp32_busfree_occur(SCpnt, auto_stat);
+			if (ret == TRUE) {
+				goto out;
+			}
+		}
+
+		if (auto_stat & STATUS_PHASE) {
+			/*
+			 * Read CSB and substitute CSB for SCpnt->result
+			 * to save status phase stutas byte.
+			 * scsi error handler checks host_byte (DID_*:
+			 * low level driver to indicate status), then checks 
+			 * status_byte (SCSI status byte).
+			 */
+			SCpnt->result =	(int)nsp32_read1(base, SCSI_CSB_IN);
+		}
+
+		if (auto_stat & ILLEGAL_PHASE) {
+			/* Illegal phase is detected. SACK is not back. */
+			nsp32_msg(KERN_WARNING, 
+				  "AUTO SCSI ILLEGAL PHASE OCCUR!!!!");
+
+			/* TODO: currently we don't have any action... bus reset? */
+
+			/*
+			 * To send back SACK, assert, wait, and negate.
+			 */
+			nsp32_sack_assert(data);
+			nsp32_wait_req(data, NEGATE);
+			nsp32_sack_negate(data);
+
+		}
+
+		if (auto_stat & COMMAND_PHASE) {
+			/* nothing to do */
+			nsp32_dbg(NSP32_DEBUG_INTR, "Command phase processed");
+		}
+
+		if (auto_stat & AUTOSCSI_BUSY) {
+			/* AutoSCSI is running */
+		}
+
+		show_autophase(auto_stat);
+	}
+
+	/* FIFO_SHLD_IRQ */
+	if (irq_stat & IRQSTATUS_FIFO_SHLD_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "FIFO IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_DATA_OUT:
+			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/write");
+
+			//nsp32_pio_write(SCpnt);
+
+			break;
+
+		case BUSPHASE_DATA_IN:
+			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/read");
+
+			//nsp32_pio_read(SCpnt);
+
+			break;
+
+		case BUSPHASE_STATUS:
+			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/status");
+
+			SCpnt->SCp.Status = nsp32_read1(base, SCSI_CSB_IN);
+
+			break;
+		default:
+			nsp32_dbg(NSP32_DEBUG_INTR, "fifo/other phase");
+			nsp32_dbg(NSP32_DEBUG_INTR, "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+
+		goto out;
+	}
+
+	/* Phase Change IRQ */
+	if (irq_stat & IRQSTATUS_PHASE_CHANGE_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "phase change IRQ");
+
+		switch(busphase) {
+		case BUSPHASE_MESSAGE_IN:
+			nsp32_dbg(NSP32_DEBUG_INTR, "phase chg/msg in");
+			nsp32_msgin_occur(SCpnt, irq_stat, 0);
+			break;
+		default:
+			nsp32_msg(KERN_WARNING, "phase chg/other phase?");
+			nsp32_msg(KERN_WARNING, "irq_stat=0x%x trans_stat=0x%x\n",
+				  irq_stat, trans_stat);
+			show_busphase(busphase);
+			break;
+		}
+		goto out;
+	}
+
+	/* PCI_IRQ */
+	if (irq_stat & IRQSTATUS_PCI_IRQ) {
+		nsp32_dbg(NSP32_DEBUG_INTR, "PCI IRQ occurred");
+		/* Do nothing */
+	}
+
+	/* BMCNTERR_IRQ */
+	if (irq_stat & IRQSTATUS_BMCNTERR_IRQ) {
+		nsp32_msg(KERN_ERR, "Received unexpected BMCNTERR IRQ! ");
+		/*
+		 * TODO: To be implemented improving bus master
+		 * transfer reliablity when BMCNTERR is occurred in
+		 * AutoSCSI phase described in specification.
+		 */
+	}
+
+#if 0
+	nsp32_dbg(NSP32_DEBUG_INTR,
+		  "irq_stat=0x%x trans_stat=0x%x", irq_stat, trans_stat);
+	show_busphase(busphase);
+#endif
+
+ out:
+	/* disable IRQ mask */
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+ out2:
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
+	spin_unlock_irqrestore(host->host_lock, flags);
+#else
+	spin_unlock_irqrestore(&io_request_lock, flags);
+#endif
+
+	nsp32_dbg(NSP32_DEBUG_INTR, "exit");
+
+	return IRQ_RETVAL(handled);
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+	do { \
+		if(length > (pos - buffer)) { \
+			pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
+			nsp32_dbg(NSP32_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length,  length - (pos - buffer));\
+		} \
+	} while(0)
+static int nsp32_proc_info(
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 
+	struct Scsi_Host *host,
+#endif
+	char             *buffer,
+	char            **start,
+	off_t             offset,
+	int               length,
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 
+	int               hostno,
+#endif
+	int               inout)
+{
+	char             *pos = buffer;
+	int               thislength;
+	unsigned long     flags;
+	nsp32_hw_data    *data;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 
+	int               hostno;
+#else
+	struct Scsi_Host *host;
+#endif
+	unsigned int      base;
+	unsigned char     mode_reg;
+	int               id, speed;
+	long              model;
+
+	/* Write is not supported, just return. */
+	if (inout == TRUE) {
+		return -EINVAL;
+	}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73)) 
+	hostno = host->host_no;
+#else
+	/* search this HBA host */
+	host = scsi_host_hn_get(hostno);
+	if (host == NULL) {
+		return -ESRCH;
+	}
+#endif
+	data = (nsp32_hw_data *)host->hostdata;
+	base = host->io_port;
+
+	SPRINTF("NinjaSCSI-32 status\n\n");
+	SPRINTF("Driver version:        %s, $Revision: 1.33 $\n", nsp32_release_version);
+	SPRINTF("SCSI host No.:         %d\n",		hostno);
+	SPRINTF("IRQ:                   %d\n",		host->irq);
+	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+	SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n",	host->base, host->base + data->MmioLength - 1);
+	SPRINTF("sg_tablesize:          %d\n",		host->sg_tablesize);
+	SPRINTF("Chip revision:         0x%x\n",       	(nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
+
+	mode_reg = nsp32_index_read1(base, CHIP_MODE);
+	model    = data->pci_devid->driver_data;
+
+#ifdef CONFIG_PM
+	SPRINTF("Power Management:      %s\n",          (mode_reg & OPTF) ? "yes" : "no");
+#endif
+	SPRINTF("OEM:                   %ld, %s\n",     (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
+
+	spin_lock_irqsave(&(data->Lock), flags);
+	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);
+	spin_unlock_irqrestore(&(data->Lock), flags);
+
+
+	SPRINTF("SDTR status\n");
+	for (id = 0; id < ARRAY_SIZE(data->target); id++) {
+
+                SPRINTF("id %d: ", id);
+
+		if (id == host->this_id) {
+			SPRINTF("----- NinjaSCSI-32 host adapter\n");
+			continue;
+		}
+
+		if (data->target[id].sync_flag == SDTR_DONE) {
+			if (data->target[id].period == 0            &&
+			    data->target[id].offset == ASYNC_OFFSET ) {
+				SPRINTF("async");
+			} else {
+				SPRINTF(" sync");
+			}
+		} else {
+			SPRINTF(" none");
+		}
+
+		if (data->target[id].period != 0) {
+
+			speed = 1000000 / (data->target[id].period * 4);
+
+			SPRINTF(" transfer %d.%dMB/s, offset %d",
+				speed / 1000,
+				speed % 1000,
+				data->target[id].offset
+				);
+		}
+		SPRINTF("\n");
+	}
+
+
+	thislength = pos - (buffer + offset);
+
+	if(thislength < 0) {
+		*start = NULL;
+                return 0;
+        }
+
+
+	thislength = min(thislength, length);
+	*start = buffer + offset;
+
+	return thislength;
+}
+#undef SPRINTF
+
+
+
+/*
+ * Reset parameters and call scsi_done for data->cur_lunt.
+ * Be careful setting SCpnt->result = DID_* before calling this function.
+ */
+static void nsp32_scsi_done(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   base = SCpnt->device->host->io_port;
+
+	/*
+	 * unmap pci
+	 */
+	if (SCpnt->request_bufflen == 0) {
+		goto skip;
+	}
+
+	if (SCpnt->use_sg) {
+		pci_unmap_sg(data->Pci,
+			     (struct scatterlist *)SCpnt->buffer,
+			     SCpnt->use_sg, SCpnt->sc_data_direction);
+	} else {
+		pci_unmap_single(data->Pci,
+				 (u32)SCpnt->SCp.have_data_in,
+				 SCpnt->request_bufflen,
+				 SCpnt->sc_data_direction);
+	}
+
+ skip:
+	/*
+	 * clear TRANSFERCONTROL_BM_START
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+
+	/*
+	 * call scsi_done
+	 */
+	(*SCpnt->scsi_done)(SCpnt);
+
+	/*
+	 * reset parameters
+	 */
+	data->cur_lunt->SCpnt = NULL;
+	data->cur_lunt        = NULL;
+	data->cur_target      = NULL;
+	data->CurrentSC      = NULL;
+}
+
+
+/*
+ * Bus Free Occur
+ *
+ * Current Phase is BUSFREE. AutoSCSI is automatically execute BUSFREE phase
+ * with ACK reply when below condition is matched:
+ *	MsgIn 00: Command Complete.
+ *	MsgIn 02: Save Data Pointer.
+ *	MsgIn 04: Diconnect.
+ * In other case, unexpected BUSFREE is detected.
+ */
+static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int base   = SCpnt->device->host->io_port;
+
+	nsp32_dbg(NSP32_DEBUG_BUSFREE, "enter execph=0x%x", execph);
+	show_autophase(execph);
+
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+
+	/*
+	 * MsgIn 02: Save Data Pointer
+	 *
+	 * VALID:
+	 *   Save Data Pointer is received. Adjust pointer.
+	 *   
+	 * NO-VALID:
+	 *   SCSI-3 says if Save Data Pointer is not received, then we restart
+	 *   processing and we can't adjust any SCSI data pointer in next data
+	 *   phase.
+	 */
+	if (execph & MSGIN_02_VALID) {
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "MsgIn02_Valid");
+
+		/*
+		 * Check sack_cnt/saved_sack_cnt, then adjust sg table if
+		 * needed.
+		 */
+		if (!(execph & MSGIN_00_VALID) && 
+		    ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE))) {
+			unsigned int sacklen, s_sacklen;
+
+			/*
+			 * Read SACK count and SAVEDSACK count, then compare.
+			 */
+			sacklen   = nsp32_read4(base, SACK_CNT      );
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+
+			/*
+			 * If SAVEDSACKCNT == 0, it means SavedDataPointer is
+			 * come after data transfering.
+			 */
+			if (s_sacklen > 0) {
+				/*
+				 * Comparing between sack and savedsack to
+				 * check the condition of AutoMsgIn03.
+				 *
+				 * If they are same, set msgin03 == TRUE,
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is enabled at
+				 * reselection.  On the other hand, if they
+				 * aren't same, set msgin03 == FALSE, and
+				 * COMMANDCONTROL_AUTO_MSGIN_03 is disabled at
+				 * reselection.
+				 */
+				if (sacklen != s_sacklen) {
+					data->cur_lunt->msgin03 = FALSE;
+				} else {
+					data->cur_lunt->msgin03 = TRUE;
+				}
+
+				nsp32_adjust_busfree(SCpnt, s_sacklen);
+			}
+		}
+
+		/* This value has not substitude with valid value yet... */
+		//data->cur_lunt->save_datp = data->cur_datp;
+	} else {
+		/*
+		 * no processing.
+		 */
+	}
+	
+	if (execph & MSGIN_03_VALID) {
+		/* MsgIn03 was valid to be processed. No need processing. */
+	}
+
+	/*
+	 * target SDTR check
+	 */
+	if (data->cur_target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * SDTR negotiation pulled by the initiator has not
+		 * finished yet. Fall back to ASYNC mode.
+		 */
+		nsp32_set_async(data, data->cur_target);
+		data->cur_target->sync_flag &= ~SDTR_INITIATOR;
+		data->cur_target->sync_flag |= SDTR_DONE;
+	} else if (data->cur_target->sync_flag & SDTR_TARGET) {
+		/*
+		 * SDTR negotiation pulled by the target has been
+		 * negotiating.
+		 */
+		if (execph & (MSGIN_00_VALID | MSGIN_04_VALID)) {
+			/* 
+			 * If valid message is received, then
+			 * negotiation is succeeded.
+			 */
+		} else {
+			/*
+			 * On the contrary, if unexpected bus free is
+			 * occurred, then negotiation is failed. Fall
+			 * back to ASYNC mode.
+			 */
+			nsp32_set_async(data, data->cur_target);
+		}
+		data->cur_target->sync_flag &= ~SDTR_TARGET;
+		data->cur_target->sync_flag |= SDTR_DONE;
+	}
+
+	/*
+	 * It is always ensured by SCSI standard that initiator
+	 * switches into Bus Free Phase after
+	 * receiving message 00 (Command Complete), 04 (Disconnect).
+	 * It's the reason that processing here is valid.
+	 */
+	if (execph & MSGIN_00_VALID) {
+		/* MsgIn 00: Command Complete */
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "command complete");
+
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 0;
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, 
+			  "normal end stat=0x%x resid=0x%x\n",
+			  SCpnt->SCp.Status, SCpnt->resid);
+		SCpnt->result = (DID_OK             << 16) |
+			        (SCpnt->SCp.Message <<  8) |
+			        (SCpnt->SCp.Status  <<  0);
+		nsp32_scsi_done(SCpnt);
+		/* All operation is done */
+		return TRUE;
+	} else if (execph & MSGIN_04_VALID) {
+		/* MsgIn 04: Disconnect */
+		SCpnt->SCp.Status  = nsp32_read1(base, SCSI_CSB_IN);
+		SCpnt->SCp.Message = 4;
+		
+		nsp32_dbg(NSP32_DEBUG_BUSFREE, "disconnect");
+		return TRUE;
+	} else {
+		/* Unexpected bus free */
+		nsp32_msg(KERN_WARNING, "unexpected bus free occurred");
+
+		/* DID_ERROR? */
+		//SCpnt->result   = (DID_OK << 16) | (SCpnt->SCp.Message << 8) | (SCpnt->SCp.Status << 0);
+		SCpnt->result = DID_ERROR << 16;
+		nsp32_scsi_done(SCpnt);
+		return TRUE;
+	}
+	return FALSE;
+}
+
+
+/*
+ * nsp32_adjust_busfree - adjusting SG table
+ *
+ * Note: This driver adjust the SG table using SCSI ACK
+ *       counter instead of BMCNT counter!
+ */
+static void nsp32_adjust_busfree(struct scsi_cmnd *SCpnt, unsigned int s_sacklen)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	int                   old_entry = data->cur_entry;
+	int                   new_entry;
+	int                   sg_num = data->cur_lunt->sg_num;
+	nsp32_sgtable *sgt    = data->cur_lunt->sglun->sgt;
+	unsigned int          restlen, sentlen;
+	u32_le                len, addr;
+
+	nsp32_dbg(NSP32_DEBUG_SGLIST, "old resid=0x%x", SCpnt->resid);
+
+	/* adjust saved SACK count with 4 byte start address boundary */
+	s_sacklen -= le32_to_cpu(sgt[old_entry].addr) & 3;
+
+	/*
+	 * calculate new_entry from sack count and each sgt[].len 
+	 * calculate the byte which is intent to send
+	 */
+	sentlen = 0;
+	for (new_entry = old_entry; new_entry < sg_num; new_entry++) {
+		sentlen += (le32_to_cpu(sgt[new_entry].len) & ~SGTEND);
+		if (sentlen > s_sacklen) {
+			break;
+		}
+	}
+
+	/* all sgt is processed */
+	if (new_entry == sg_num) {
+		goto last;
+	}
+
+	if (sentlen == s_sacklen) {
+		/* XXX: confirm it's ok or not */
+		/* In this case, it's ok because we are at 
+		   the head element of the sg. restlen is correctly calculated. */
+	}
+
+	/* calculate the rest length for transfering */
+	restlen = sentlen - s_sacklen;
+
+	/* update adjusting current SG table entry */
+	len  = le32_to_cpu(sgt[new_entry].len);
+	addr = le32_to_cpu(sgt[new_entry].addr);
+	addr += (len - restlen);
+	sgt[new_entry].addr = cpu_to_le32(addr);
+	sgt[new_entry].len  = cpu_to_le32(restlen);
+
+	/* set cur_entry with new_entry */
+	data->cur_entry = new_entry;
+ 
+	return;
+
+ last:
+	if (SCpnt->resid < sentlen) {
+		nsp32_msg(KERN_ERR, "resid underflow");
+	}
+
+	SCpnt->resid -= sentlen;
+	nsp32_dbg(NSP32_DEBUG_SGLIST, "new resid=0x%x", SCpnt->resid);
+
+	/* update hostdata and lun */
+
+	return;
+}
+
+
+/*
+ * It's called MsgOut phase occur.
+ * NinjaSCSI-32Bi/UDE automatically processes up to 3 messages in
+ * message out phase. It, however, has more than 3 messages,
+ * HBA creates the interrupt and we have to process by hand.
+ */
+static void nsp32_msgout_occur(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int base   = SCpnt->device->host->io_port;
+	//unsigned short command;
+	long new_sgtp;
+	int i;
+	
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+		  "enter: msgout_len: 0x%x", data->msgout_len);
+
+	/*
+	 * If MsgOut phase is occurred without having any
+	 * message, then No_Operation is sent (SCSI-2).
+	 */
+	if (data->msgout_len == 0) {
+		nsp32_build_nop(SCpnt);
+	}
+
+	/*
+	 * Set SGTP ADDR current entry for restarting AUTOSCSI, 
+	 * because SGTP is incremented next point.
+	 * There is few statement in the specification...
+	 */
+ 	new_sgtp = data->cur_lunt->sglun_paddr + 
+		   (data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
+
+	/*
+	 * send messages
+	 */
+	for (i = 0; i < data->msgout_len; i++) {
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR,
+			  "%d : 0x%x", i, data->msgoutbuf[i]);
+
+		/*
+		 * Check REQ is asserted.
+		 */
+		nsp32_wait_req(data, ASSERT);
+
+		if (i == (data->msgout_len - 1)) {
+			/*
+			 * If the last message, set the AutoSCSI restart
+			 * before send back the ack message. AutoSCSI
+			 * restart automatically negate ATN signal.
+			 */
+			//command = (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+			//nsp32_restart_autoscsi(SCpnt, command);
+			nsp32_write2(base, COMMAND_CONTROL,
+					 (CLEAR_CDB_FIFO_POINTER |
+					  AUTO_COMMAND_PHASE     |
+					  AUTOSCSI_RESTART       |
+					  AUTO_MSGIN_00_OR_04    |
+					  AUTO_MSGIN_02          ));
+		}
+		/*
+		 * Write data with SACK, then wait sack is
+		 * automatically negated.
+		 */
+		nsp32_write1(base, SCSI_DATA_WITH_ACK, data->msgoutbuf[i]);
+		nsp32_wait_sack(data, NEGATE);
+
+		nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "bus: 0x%x\n",
+			  nsp32_read1(base, SCSI_BUS_MONITOR));
+	};
+
+	data->msgout_len = 0;
+
+	nsp32_dbg(NSP32_DEBUG_MSGOUTOCCUR, "exit");
+}
+
+/*
+ * Restart AutoSCSI
+ *
+ * Note: Restarting AutoSCSI needs set:
+ *		SYNC_REG, ACK_WIDTH, SGT_ADR, TRANSFER_CONTROL
+ */
+static void nsp32_restart_autoscsi(struct scsi_cmnd *SCpnt, unsigned short command)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   base = data->BaseAddress;
+	unsigned short transfer = 0;
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "enter");
+
+	if (data->cur_target == NULL || data->cur_lunt == NULL) {
+		nsp32_msg(KERN_ERR, "Target or Lun is invalid");
+	}
+
+	/*
+	 * set SYNC_REG
+	 * Don't set BM_START_ADR before setting this register.
+	 */
+	nsp32_write1(base, SYNC_REG, data->cur_target->syncreg);
+
+	/*
+	 * set ACKWIDTH
+	 */
+	nsp32_write1(base, ACK_WIDTH, data->cur_target->ackwidth);
+
+	/*
+	 * set SREQ hazard killer sampling rate
+	 */
+	nsp32_write1(base, SREQ_SMPL_RATE, data->cur_target->sample_reg);
+
+	/*
+	 * set SGT ADDR (physical address)
+	 */
+	nsp32_write4(base, SGT_ADR, data->cur_lunt->sglun_paddr);
+
+	/*
+	 * set TRANSFER CONTROL REG
+	 */
+	transfer = 0;
+	transfer |= (TRANSFER_GO | ALL_COUNTER_CLR);
+	if (data->trans_method & NSP32_TRANSFER_BUSMASTER) {
+		if (SCpnt->request_bufflen > 0) {
+			transfer |= BM_START;
+		}
+	} else if (data->trans_method & NSP32_TRANSFER_MMIO) {
+		transfer |= CB_MMIO_MODE;
+	} else if (data->trans_method & NSP32_TRANSFER_PIO) {
+		transfer |= CB_IO_MODE;
+	}
+	nsp32_write2(base, TRANSFER_CONTROL, transfer);
+
+	/*
+	 * restart AutoSCSI
+	 *
+	 * TODO: COMMANDCONTROL_AUTO_COMMAND_PHASE is needed ?
+	 */
+	command |= (CLEAR_CDB_FIFO_POINTER |
+		    AUTO_COMMAND_PHASE     |
+		    AUTOSCSI_RESTART       );
+	nsp32_write2(base, COMMAND_CONTROL, command);
+
+	nsp32_dbg(NSP32_DEBUG_RESTART, "exit");
+}
+
+
+/*
+ * cannot run automatically message in occur
+ */
+static void nsp32_msgin_occur(struct scsi_cmnd     *SCpnt,
+			      unsigned long  irq_status,
+			      unsigned short execph)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   base = SCpnt->device->host->io_port;
+	unsigned char  msg;
+	unsigned char  msgtype;
+	unsigned char  newlun;
+	unsigned short command  = 0;
+	int            msgclear = TRUE;
+	long           new_sgtp;
+	int            ret;
+
+	/*
+	 * read first message
+	 *    Use SCSIDATA_W_ACK instead of SCSIDATAIN, because the procedure
+	 *    of Message-In have to be processed before sending back SCSI ACK.
+	 */
+	msg = nsp32_read1(base, SCSI_DATA_IN);
+	data->msginbuf[(unsigned char)data->msgin_len] = msg;
+	msgtype = data->msginbuf[0];
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR,
+		  "enter: msglen: 0x%x msgin: 0x%x msgtype: 0x%x",
+		  data->msgin_len, msg, msgtype);
+
+	/*
+	 * TODO: We need checking whether bus phase is message in?
+	 */
+
+	/*
+	 * assert SCSI ACK
+	 */
+	nsp32_sack_assert(data);
+
+	/*
+	 * processing IDENTIFY
+	 */
+	if (msgtype & 0x80) {
+		if (!(irq_status & IRQSTATUS_RESELECT_OCCUER)) {
+			/* Invalid (non reselect) phase */
+			goto reject;
+		}
+
+		newlun = msgtype & 0x1f; /* TODO: SPI-3 compliant? */
+		ret = nsp32_reselection(SCpnt, newlun);
+		if (ret == TRUE) {
+			goto restart;
+		} else {
+			goto reject;
+		}
+	}
+	
+	/*
+	 * processing messages except for IDENTIFY
+	 *
+	 * TODO: Messages are all SCSI-2 terminology. SCSI-3 compliance is TODO.
+	 */
+	switch (msgtype) {
+	/*
+	 * 1-byte message
+	 */
+	case COMMAND_COMPLETE:
+	case DISCONNECT:
+		/*
+		 * These messages should not be occurred.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg(KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: 0x%x", msg);
+		break;
+		
+	case RESTORE_POINTERS:
+		/*
+		 * AutoMsgIn03 is disabled, and HBA gets this message.
+		 */
+
+		if ((execph & DATA_IN_PHASE) || (execph & DATA_OUT_PHASE)) {
+			unsigned int s_sacklen;
+
+			s_sacklen = nsp32_read4(base, SAVED_SACK_CNT);
+			if ((execph & MSGIN_02_VALID) && (s_sacklen > 0)) {
+				nsp32_adjust_busfree(SCpnt, s_sacklen);
+			} else {
+				/* No need to rewrite SGT */
+			}
+		}
+		data->cur_lunt->msgin03 = FALSE;
+
+		/* Update with the new value */
+
+		/* reset SACK/SavedACK counter (or ALL clear?) */
+		nsp32_write4(base, CLR_COUNTER, CLRCOUNTER_ALLMASK);
+
+		/*
+		 * set new sg pointer
+		 */
+		new_sgtp = data->cur_lunt->sglun_paddr + 
+			(data->cur_lunt->cur_entry * sizeof(nsp32_sgtable));
+		nsp32_write4(base, SGT_ADR, new_sgtp);
+
+		break;
+
+	case SAVE_POINTERS:
+		/*
+		 * These messages should not be occurred.
+		 * They should be processed on AutoSCSI sequencer.
+		 */
+		nsp32_msg (KERN_WARNING, 
+			   "unexpected message of AutoSCSI MsgIn: SAVE_POINTERS");
+		
+		break;
+		
+	case MESSAGE_REJECT:
+		/* If previous message_out is sending SDTR, and get 
+		   message_reject from target, SDTR negotiation is failed */
+		if (data->cur_target->sync_flag &
+				(SDTR_INITIATOR | SDTR_TARGET)) {
+			/*
+			 * Current target is negotiating SDTR, but it's
+			 * failed.  Fall back to async transfer mode, and set
+			 * SDTR_DONE.
+			 */
+			nsp32_set_async(data, data->cur_target);
+			data->cur_target->sync_flag &= ~SDTR_INITIATOR;
+			data->cur_target->sync_flag |= SDTR_DONE;
+
+		}
+		break;
+
+	case LINKED_CMD_COMPLETE:
+	case LINKED_FLG_CMD_COMPLETE:
+		/* queue tag is not supported currently */
+		nsp32_msg (KERN_WARNING, 
+			   "unsupported message: 0x%x", msgtype);
+		break;
+
+	case INITIATE_RECOVERY:
+		/* staring ECA (Extended Contingent Allegiance) state. */
+		/* This message is declined in SPI2 or later. */
+
+		goto reject;
+
+	/*
+	 * 2-byte message
+	 */
+	case SIMPLE_QUEUE_TAG:
+	case 0x23:
+		/*
+		 * 0x23: Ignore_Wide_Residue is not declared in scsi.h.
+		 * No support is needed.
+		 */
+		if (data->msgin_len >= 1) {
+			goto reject;
+		}
+
+		/* current position is 1-byte of 2 byte */
+		msgclear = FALSE;
+
+		break;
+
+	/*
+	 * extended message
+	 */
+	case EXTENDED_MESSAGE:
+		if (data->msgin_len < 1) {
+			/*
+			 * Current position does not reach 2-byte
+			 * (2-byte is extended message length).
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		if ((data->msginbuf[1] + 1) > data->msgin_len) {
+			/*
+			 * Current extended message has msginbuf[1] + 2
+			 * (msgin_len starts counting from 0, so buf[1] + 1).
+			 * If current message position is not finished,
+			 * continue receiving message.
+			 */
+			msgclear = FALSE;
+			break;
+		}
+
+		/*
+		 * Reach here means regular length of each type of 
+		 * extended messages.
+		 */
+		switch (data->msginbuf[2]) {
+		case EXTENDED_MODIFY_DATA_POINTER:
+			/* TODO */
+			goto reject; /* not implemented yet */
+			break;
+
+		case EXTENDED_SDTR:
+			/*
+			 * Exchange this message between initiator and target.
+			 */
+			if (data->msgin_len != EXTENDED_SDTR_LEN + 1) {
+				/*
+				 * received inappropriate message.
+				 */
+				goto reject;
+				break;
+			}
+
+			nsp32_analyze_sdtr(SCpnt);
+
+			break;
+
+		case EXTENDED_EXTENDED_IDENTIFY:
+			/* SCSI-I only, not supported. */
+			goto reject; /* not implemented yet */
+
+			break;
+
+		case EXTENDED_WDTR:
+			goto reject; /* not implemented yet */
+
+			break;
+			
+		default:
+			goto reject;
+		}
+		break;
+		
+	default:
+		goto reject;
+	}
+
+ restart:
+	if (msgclear == TRUE) {
+		data->msgin_len = 0;
+
+		/*
+		 * If restarting AutoSCSI, but there are some message to out
+		 * (msgout_len > 0), set AutoATN, and set SCSIMSGOUT as 0
+		 * (MV_VALID = 0). When commandcontrol is written with
+		 * AutoSCSI restart, at the same time MsgOutOccur should be
+		 * happened (however, such situation is really possible...?).
+		 */
+		if (data->msgout_len > 0) {	
+			nsp32_write4(base, SCSI_MSG_OUT, 0);
+			command |= AUTO_ATN;
+		}
+
+		/*
+		 * restart AutoSCSI
+		 * If it's failed, COMMANDCONTROL_AUTO_COMMAND_PHASE is needed.
+		 */
+		command |= (AUTO_MSGIN_00_OR_04 | AUTO_MSGIN_02);
+
+		/*
+		 * If current msgin03 is TRUE, then flag on.
+		 */
+		if (data->cur_lunt->msgin03 == TRUE) {
+			command |= AUTO_MSGIN_03;
+		}
+		data->cur_lunt->msgin03 = FALSE;
+	} else {
+		data->msgin_len++;
+	}
+
+	/*
+	 * restart AutoSCSI
+	 */
+	nsp32_restart_autoscsi(SCpnt, command);
+
+	/*
+	 * wait SCSI REQ negate for REQ-ACK handshake
+	 */
+	nsp32_wait_req(data, NEGATE);
+
+	/*
+	 * negate SCSI ACK
+	 */
+	nsp32_sack_negate(data);
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+
+	return;
+
+ reject:
+	nsp32_msg(KERN_WARNING, 
+		  "invalid or unsupported MessageIn, rejected. "
+		  "current msg: 0x%x (len: 0x%x), processing msg: 0x%x",
+		  msg, data->msgin_len, msgtype);
+	nsp32_build_reject(SCpnt);
+	data->msgin_len = 0;
+
+	goto restart;
+}
+
+/*
+ * 
+ */
+static void nsp32_analyze_sdtr(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data   *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	nsp32_target     *target     = data->cur_target;
+	nsp32_sync_table *synct;
+	unsigned char     get_period = data->msginbuf[3];
+	unsigned char     get_offset = data->msginbuf[4];
+	int               entry;
+	int               syncnum;
+
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "enter");
+
+	synct   = data->synct;
+	syncnum = data->syncnum;
+
+	/*
+	 * If this inititor sent the SDTR message, then target responds SDTR,
+	 * initiator SYNCREG, ACKWIDTH from SDTR parameter.
+	 * Messages are not appropriate, then send back reject message.
+	 * If initiator did not send the SDTR, but target sends SDTR, 
+	 * initiator calculator the appropriate parameter and send back SDTR.
+	 */	
+	if (target->sync_flag & SDTR_INITIATOR) {
+		/*
+		 * Initiator sent SDTR, the target responds and
+		 * send back negotiation SDTR.
+		 */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target responds SDTR");
+	
+		target->sync_flag &= ~SDTR_INITIATOR;
+		target->sync_flag |= SDTR_DONE;
+
+		/*
+		 * offset:
+		 */
+		if (get_offset > SYNC_OFFSET) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected offset value.
+			 */
+			goto reject;
+		}
+		
+		if (get_offset == ASYNC_OFFSET) {
+			/*
+			 * Negotiation is succeeded, the target want
+			 * to fall back into asynchronous transfer mode.
+			 */
+			goto async;
+		}
+
+		/*
+		 * period:
+		 *    Check whether sync period is too short. If too short,
+		 *    fall back to async mode. If it's ok, then investigate
+		 *    the received sync period. If sync period is acceptable
+		 *    between sync table start_period and end_period, then
+		 *    set this I_T nexus as sent offset and period.
+		 *    If it's not acceptable, send back reject and fall back
+		 *    to async mode.
+		 */
+		if (get_period < data->synct[0].period_num) {
+			/*
+			 * Negotiation is failed, the target send back
+			 * unexpected period value.
+			 */
+			goto reject;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (entry < 0) {
+			/*
+			 * Target want to use long period which is not 
+			 * acceptable NinjaSCSI-32Bi/UDE.
+			 */
+			goto reject;
+		}
+
+		/*
+		 * Set new sync table and offset in this I_T nexus.
+		 */
+		nsp32_set_sync_entry(data, target, entry, get_offset);
+	} else {
+		/* Target send SDTR to initiator. */
+		nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "target send SDTR");
+	
+		target->sync_flag |= SDTR_INITIATOR;
+
+		/* offset: */
+		if (get_offset > SYNC_OFFSET) {
+			/* send back as SYNC_OFFSET */
+			get_offset = SYNC_OFFSET;
+		}
+
+		/* period: */
+		if (get_period < data->synct[0].period_num) {
+			get_period = data->synct[0].period_num;
+		}
+
+		entry = nsp32_search_period_entry(data, target, get_period);
+
+		if (get_offset == ASYNC_OFFSET || entry < 0) {
+			nsp32_set_async(data, target);
+			nsp32_build_sdtr(SCpnt, 0, ASYNC_OFFSET);
+		} else {
+			nsp32_set_sync_entry(data, target, entry, get_offset);
+			nsp32_build_sdtr(SCpnt, get_period, get_offset);
+		}
+	}
+
+	target->period = get_period;
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit");
+	return;
+
+ reject:
+	/*
+	 * If the current message is unacceptable, send back to the target
+	 * with reject message.
+	 */
+	nsp32_build_reject(SCpnt);
+
+ async:
+	nsp32_set_async(data, target);	/* set as ASYNC transfer mode */
+
+	target->period = 0;
+	nsp32_dbg(NSP32_DEBUG_MSGINOCCUR, "exit: set async");
+	return;
+}
+
+
+/*
+ * Search config entry number matched in sync_table from given
+ * target and speed period value. If failed to search, return negative value.
+ */
+static int nsp32_search_period_entry(nsp32_hw_data *data,
+				     nsp32_target  *target,
+				     unsigned char  period)
+{
+	int i;
+
+	if (target->limit_entry >= data->syncnum) {
+		nsp32_msg(KERN_ERR, "limit_entry exceeds syncnum!");
+		target->limit_entry = 0;
+	}
+
+	for (i = target->limit_entry; i < data->syncnum; i++) {
+		if (period >= data->synct[i].start_period &&
+		    period <= data->synct[i].end_period) {
+				break;
+		}
+	}
+
+	/*
+	 * Check given period value is over the sync_table value.
+	 * If so, return max value.
+	 */
+	if (i == data->syncnum) {
+		i = -1;
+	}
+
+	return i;
+}
+
+
+/*
+ * target <-> initiator use ASYNC transfer
+ */
+static void nsp32_set_async(nsp32_hw_data *data, nsp32_target *target)
+{
+	unsigned char period = data->synct[target->limit_entry].period_num;
+
+	target->offset     = ASYNC_OFFSET;
+	target->period     = 0;
+	target->syncreg    = TO_SYNCREG(period, ASYNC_OFFSET);
+	target->ackwidth   = 0;
+	target->sample_reg = 0;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set async");
+}
+
+
+/*
+ * target <-> initiator use maximum SYNC transfer
+ */
+static void nsp32_set_max_sync(nsp32_hw_data *data,
+			       nsp32_target  *target,
+			       unsigned char *period,
+			       unsigned char *offset)
+{
+	unsigned char period_num, ackwidth;
+
+	period_num = data->synct[target->limit_entry].period_num;
+	*period    = data->synct[target->limit_entry].start_period;
+	ackwidth   = data->synct[target->limit_entry].ackwidth;
+	*offset    = SYNC_OFFSET;
+
+	target->syncreg    = TO_SYNCREG(period_num, *offset);
+	target->ackwidth   = ackwidth;
+	target->offset     = *offset;
+	target->sample_reg = 0;       /* disable SREQ sampling */
+}
+
+
+/*
+ * target <-> initiator use entry number speed
+ */
+static void nsp32_set_sync_entry(nsp32_hw_data *data,
+				 nsp32_target  *target,
+				 int            entry,
+				 unsigned char  offset)
+{
+	unsigned char period, ackwidth, sample_rate;
+
+	period      = data->synct[entry].period_num;
+	ackwidth    = data->synct[entry].ackwidth;
+	offset      = offset;
+	sample_rate = data->synct[entry].sample_rate;
+
+	target->syncreg    = TO_SYNCREG(period, offset);
+	target->ackwidth   = ackwidth;
+	target->offset     = offset;
+	target->sample_reg = sample_rate | SAMPLING_ENABLE;
+
+	nsp32_dbg(NSP32_DEBUG_SYNC, "set sync");
+}
+
+
+/*
+ * It waits until SCSI REQ becomes assertion or negation state.
+ *
+ * Note: If nsp32_msgin_occur is called, we asserts SCSI ACK. Then
+ *     connected target responds SCSI REQ negation.  We have to wait
+ *     SCSI REQ becomes negation in order to negate SCSI ACK signal for
+ *     REQ-ACK handshake.
+ */
+static void nsp32_wait_req(nsp32_hw_data *data, int state)
+{
+	unsigned int  base      = data->BaseAddress;
+	int           wait_time = 0;
+	unsigned char bus, req_bit;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	/* REQ is BIT(5) */
+	req_bit = (state == ASSERT ? BUSMON_REQ : 0);
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_REQ) == req_bit) {
+			nsp32_dbg(NSP32_DEBUG_WAIT, 
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait REQ timeout, req_bit: 0x%x", req_bit);
+}
+
+/*
+ * It waits until SCSI SACK becomes assertion or negation state.
+ */
+static void nsp32_wait_sack(nsp32_hw_data *data, int state)
+{
+	unsigned int  base      = data->BaseAddress;
+	int           wait_time = 0;
+	unsigned char bus, ack_bit;
+
+	if (!((state == ASSERT) || (state == NEGATE))) {
+		nsp32_msg(KERN_ERR, "unknown state designation");
+	}
+	/* ACK is BIT(4) */
+	ack_bit = (state == ASSERT ? BUSMON_ACK : 0);
+
+	do {
+		bus = nsp32_read1(base, SCSI_BUS_MONITOR);
+		if ((bus & BUSMON_ACK) == ack_bit) {
+			nsp32_dbg(NSP32_DEBUG_WAIT,
+				  "wait_time: %d", wait_time);
+			return;
+		}
+		udelay(1);
+		wait_time++;
+	} while (wait_time < REQSACK_TIMEOUT_TIME);
+
+	nsp32_msg(KERN_WARNING, "wait SACK timeout, ack_bit: 0x%x", ack_bit);
+}
+
+/*
+ * assert SCSI ACK
+ *
+ * Note: SCSI ACK assertion needs with ACKENB=1, AUTODIRECTION=1.
+ */
+static void nsp32_sack_assert(nsp32_hw_data *data)
+{
+	unsigned int  base = data->BaseAddress;
+	unsigned char busctrl;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	|= (BUSCTL_ACK | AUTODIRECTION | ACKENB);
+	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
+}
+
+/*
+ * negate SCSI ACK
+ */
+static void nsp32_sack_negate(nsp32_hw_data *data)
+{
+	unsigned int  base = data->BaseAddress;
+	unsigned char busctrl;
+
+	busctrl  = nsp32_read1(base, SCSI_BUS_CONTROL);
+	busctrl	&= ~BUSCTL_ACK;
+	nsp32_write1(base, SCSI_BUS_CONTROL, busctrl);
+}
+
+
+
+/*
+ * Note: n_io_port is defined as 0x7f because I/O register port is
+ *	 assigned as:
+ *	0x800-0x8ff: memory mapped I/O port
+ *	0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly)
+ *	0xc00-0xfff: CardBus status registers
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+#define DETECT_OK 0
+#define DETECT_NG 1
+#define PCIDEV    pdev
+static int nsp32_detect(struct pci_dev *pdev)
+#else
+#define DETECT_OK 1
+#define DETECT_NG 0
+#define PCIDEV    (data->Pci)
+static int nsp32_detect(Scsi_Host_Template *sht)
+#endif
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	struct resource  *res;
+	nsp32_hw_data    *data;
+	int               ret;
+	int               i, j;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+	/*
+	 * register this HBA as SCSI device
+	 */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	host = scsi_host_alloc(&nsp32_template, sizeof(nsp32_hw_data));
+#else
+	host = scsi_register(sht, sizeof(nsp32_hw_data));
+#endif
+	if (host == NULL) {
+		nsp32_msg (KERN_ERR, "failed to scsi register");
+		goto err;
+	}
+
+	/*
+	 * set nsp32_hw_data
+	 */
+	data = (nsp32_hw_data *)host->hostdata;
+
+	memcpy(data, &nsp32_data_base, sizeof(nsp32_hw_data));
+
+	host->irq       = data->IrqNumber;
+	host->io_port   = data->BaseAddress;
+	host->unique_id = data->BaseAddress;
+	host->n_io_port	= data->NumAddress;
+	host->base      = (unsigned long)data->MmioAddress;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,63))
+	scsi_set_device(host, &PCIDEV->dev);
+#else
+	scsi_set_pci_device(host, PCIDEV);
+#endif
+
+	data->Host      = host;
+	spin_lock_init(&(data->Lock));
+
+	data->cur_lunt   = NULL;
+	data->cur_target = NULL;
+
+	/*
+	 * Bus master transfer mode is supported currently.
+	 */
+	data->trans_method = NSP32_TRANSFER_BUSMASTER;
+
+	/*
+	 * Set clock div, CLOCK_4 (HBA has own external clock, and
+	 * dividing * 100ns/4).
+	 * Currently CLOCK_4 has only tested, not for CLOCK_2/PCICLK yet.
+	 */
+	data->clock = CLOCK_4;
+
+	/*
+	 * Select appropriate nsp32_sync_table and set I_CLOCKDIV.
+	 */
+	switch (data->clock) {
+	case CLOCK_4:
+		/* If data->clock is CLOCK_4, then select 40M sync table. */
+		data->synct   = nsp32_sync_table_40M;
+		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
+		break;
+	case CLOCK_2:
+		/* If data->clock is CLOCK_2, then select 20M sync table. */
+		data->synct   = nsp32_sync_table_20M;
+		data->syncnum = ARRAY_SIZE(nsp32_sync_table_20M);
+		break;
+	case PCICLK:
+		/* If data->clock is PCICLK, then select pci sync table. */
+		data->synct   = nsp32_sync_table_pci;
+		data->syncnum = ARRAY_SIZE(nsp32_sync_table_pci);
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Invalid clock div is selected, set CLOCK_4.");
+		/* Use default value CLOCK_4 */
+		data->clock   = CLOCK_4;
+		data->synct   = nsp32_sync_table_40M;
+		data->syncnum = ARRAY_SIZE(nsp32_sync_table_40M);
+	}
+
+	/*
+	 * setup nsp32_lunt
+	 */
+
+	/*
+	 * setup DMA 
+	 */
+	if (pci_set_dma_mask(PCIDEV, 0xffffffffUL) != 0) {
+		nsp32_msg (KERN_ERR, "failed to set PCI DMA mask");
+		goto scsi_unregister;
+	}
+
+	/*
+	 * allocate autoparam DMA resource.
+	 */
+	data->autoparam = pci_alloc_consistent(PCIDEV, sizeof(nsp32_autoparam), &(data->auto_paddr));
+	if (data->autoparam == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto scsi_unregister;
+	}
+
+	/*
+	 * allocate scatter-gather DMA resource.
+	 */
+	data->sg_list = pci_alloc_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+					     &(data->sg_paddr));
+	if (data->sg_list == NULL) {
+		nsp32_msg(KERN_ERR, "failed to allocate DMA memory");
+		goto free_autoparam;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(data->lunt); i++) {
+		for (j = 0; j < ARRAY_SIZE(data->lunt[0]); j++) {
+			int offset = i * ARRAY_SIZE(data->lunt[0]) + j;
+			nsp32_lunt tmp = {
+				.SCpnt       = NULL,
+				.save_datp   = 0,
+				.msgin03     = FALSE,
+				.sg_num      = 0,
+				.cur_entry   = 0,
+				.sglun       = &(data->sg_list[offset]),
+				.sglun_paddr = data->sg_paddr + (offset * sizeof(nsp32_sglun)),
+			};
+
+			data->lunt[i][j] = tmp;
+		}
+	}
+
+	/*
+	 * setup target
+	 */
+	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
+		nsp32_target *target = &(data->target[i]);
+
+		target->limit_entry  = 0;
+		target->sync_flag    = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * EEPROM check
+	 */
+	ret = nsp32_getprom_param(data);
+	if (ret == FALSE) {
+		data->resettime = 3;	/* default 3 */
+	}
+
+	/*
+	 * setup HBA
+	 */
+	nsp32hw_init(data);
+
+	snprintf(data->info_str, sizeof(data->info_str),
+		 "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x",
+		 host->irq, host->io_port, host->n_io_port);
+
+	/*
+	 * SCSI bus reset
+	 *
+	 * Note: It's important to reset SCSI bus in initialization phase.
+	 *     NinjaSCSI-32Bi/UDE HBA EEPROM seems to exchange SDTR when
+	 *     system is coming up, so SCSI devices connected to HBA is set as
+	 *     un-asynchronous mode.  It brings the merit that this HBA is
+	 *     ready to start synchronous transfer without any preparation,
+	 *     but we are difficult to control transfer speed.  In addition,
+	 *     it prevents device transfer speed from effecting EEPROM start-up
+	 *     SDTR.  NinjaSCSI-32Bi/UDE has the feature if EEPROM is set as
+	 *     Auto Mode, then FAST-10M is selected when SCSI devices are
+	 *     connected same or more than 4 devices.  It should be avoided
+	 *     depending on this specification. Thus, resetting the SCSI bus
+	 *     restores all connected SCSI devices to asynchronous mode, then
+	 *     this driver set SDTR safely later, and we can control all SCSI
+	 *     device transfer mode.
+	 */
+	nsp32_do_bus_reset(data);
+
+	ret = request_irq(host->irq, do_nsp32_isr,
+			  SA_SHIRQ | SA_SAMPLE_RANDOM, "nsp32", data);
+	if (ret < 0) {
+		nsp32_msg(KERN_ERR, "Unable to allocate IRQ for NinjaSCSI32 "
+			  "SCSI PCI controller. Interrupt: %d", host->irq);
+		goto free_sg_list;
+	}
+
+        /*
+         * PCI IO register
+         */
+	res = request_region(host->io_port, host->n_io_port, "nsp32");
+	if (res == NULL) {
+		nsp32_msg(KERN_ERR, 
+			  "I/O region 0x%lx+0x%lx is already used",
+			  data->BaseAddress, data->NumAddress);
+		goto free_irq;
+        }
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	scsi_add_host (host, &PCIDEV->dev);
+	scsi_scan_host(host);
+#endif
+	pci_set_drvdata(PCIDEV, host);
+	return DETECT_OK;
+
+ free_irq:
+	free_irq(host->irq, data);
+
+ free_sg_list:
+	pci_free_consistent(PCIDEV, NSP32_SG_TABLE_SIZE,
+			    data->sg_list, data->sg_paddr);
+
+ free_autoparam:
+	pci_free_consistent(PCIDEV, sizeof(nsp32_autoparam),
+			    data->autoparam, data->auto_paddr);
+	
+ scsi_unregister:
+	scsi_host_put(host);
+
+ err:
+	return DETECT_NG;
+}
+#undef DETECT_OK
+#undef DETECT_NG
+#undef PCIDEV
+
+static int nsp32_release(struct Scsi_Host *host)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)host->hostdata;
+
+	if (data->autoparam) {
+		pci_free_consistent(data->Pci, sizeof(nsp32_autoparam),
+				    data->autoparam, data->auto_paddr);
+	}
+
+	if (data->sg_list) {
+		pci_free_consistent(data->Pci, NSP32_SG_TABLE_SIZE,
+				    data->sg_list, data->sg_paddr);
+	}
+
+	if (host->irq) {
+		free_irq(host->irq, data);
+	}
+
+	if (host->io_port && host->n_io_port) {
+		release_region(host->io_port, host->n_io_port);
+	}
+
+	if (data->MmioAddress) {
+		iounmap(data->MmioAddress);
+	}
+
+	return 0;
+}
+
+static const char *nsp32_info(struct Scsi_Host *shpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata;
+
+	return data->info_str;
+}
+
+
+/****************************************************************************
+ * error handler
+ */
+static int nsp32_eh_abort(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   base = SCpnt->device->host->io_port;
+
+	nsp32_msg(KERN_WARNING, "abort");
+
+	if (data->cur_lunt->SCpnt == NULL) {
+		nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort failed");
+		return FAILED;
+	}
+
+	if (data->cur_target->sync_flag & (SDTR_INITIATOR | SDTR_TARGET)) {
+		/* reset SDTR negotiation */
+		data->cur_target->sync_flag = 0;
+		nsp32_set_async(data, data->cur_target);
+	}
+
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write2(base, BM_CNT,           0);
+
+	SCpnt->result = DID_ABORT << 16;
+	nsp32_scsi_done(SCpnt);
+
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "abort success");
+	return SUCCESS;
+}
+
+static int nsp32_eh_bus_reset(struct scsi_cmnd *SCpnt)
+{
+	nsp32_hw_data *data = (nsp32_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int   base = SCpnt->device->host->io_port;
+
+	nsp32_msg(KERN_INFO, "Bus Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* SCSI bus reset is succeeded at any time. */
+}
+
+static void nsp32_do_bus_reset(nsp32_hw_data *data)
+{
+	unsigned int   base = data->BaseAddress;
+	unsigned short intrdat;
+	int i;
+
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "in");
+
+	/*
+	 * stop all transfer
+	 * clear TRANSFERCONTROL_BM_START
+	 * clear counter
+	 */
+	nsp32_write2(base, TRANSFER_CONTROL, 0);
+	nsp32_write4(base, BM_CNT,           0);
+	nsp32_write4(base, CLR_COUNTER,      CLRCOUNTER_ALLMASK);
+
+	/*
+	 * fall back to asynchronous transfer mode
+	 * initialize SDTR negotiation flag
+	 */
+	for (i = 0; i < ARRAY_SIZE(data->target); i++) {
+		nsp32_target *target = &data->target[i];
+
+		target->sync_flag = 0;
+		nsp32_set_async(data, target);
+	}
+
+	/*
+	 * reset SCSI bus
+	 */
+	nsp32_write1(base, SCSI_BUS_CONTROL, BUSCTL_RST);
+	udelay(RESET_HOLD_TIME);
+	nsp32_write1(base, SCSI_BUS_CONTROL, 0);
+	for(i = 0; i < 5; i++) {
+		intrdat = nsp32_read2(base, IRQ_STATUS); /* dummy read */
+		nsp32_dbg(NSP32_DEBUG_BUSRESET, "irq:1: 0x%x", intrdat);
+        }
+
+	data->CurrentSC = NULL;
+}
+
+static int nsp32_eh_host_reset(struct scsi_cmnd *SCpnt)
+{
+	struct Scsi_Host *host = SCpnt->device->host;
+	unsigned int      base = SCpnt->device->host->io_port;
+	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
+
+	nsp32_msg(KERN_INFO, "Host Reset");	
+	nsp32_dbg(NSP32_DEBUG_BUSRESET, "SCpnt=0x%x", SCpnt);
+
+	nsp32hw_init(data);
+	nsp32_write2(base, IRQ_CONTROL, IRQ_CONTROL_ALL_IRQ_MASK);
+	nsp32_do_bus_reset(data);
+	nsp32_write2(base, IRQ_CONTROL, 0);
+
+	return SUCCESS;	/* Host reset is succeeded at any time. */
+}
+
+
+/**************************************************************************
+ * EEPROM handler
+ */
+
+/*
+ * getting EEPROM parameter
+ */
+static int nsp32_getprom_param(nsp32_hw_data *data)
+{
+	int vendor = data->pci_devid->vendor;
+	int device = data->pci_devid->device;
+	int ret, val, i;
+
+	/*
+	 * EEPROM checking.
+	 */
+	ret = nsp32_prom_read(data, 0x7e);
+	if (ret != 0x55) {
+		nsp32_msg(KERN_INFO, "No EEPROM detected: 0x%x", ret);
+		return FALSE;
+	}
+	ret = nsp32_prom_read(data, 0x7f);
+	if (ret != 0xaa) {
+		nsp32_msg(KERN_INFO, "Invalid number: 0x%x", ret);
+		return FALSE;
+	}
+
+	/*
+	 * check EEPROM type
+	 */
+	if (vendor == PCI_VENDOR_ID_WORKBIT &&
+	    device == PCI_DEVICE_ID_WORKBIT_STANDARD) {
+		ret = nsp32_getprom_c16(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC) {
+		ret = nsp32_getprom_at24(data);
+	} else if (vendor == PCI_VENDOR_ID_WORKBIT &&
+		   device == PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO ) {
+		ret = nsp32_getprom_at24(data);
+	} else {
+		nsp32_msg(KERN_WARNING, "Unknown EEPROM");
+		ret = FALSE;
+	}
+
+	/* for debug : SPROM data full checking */
+	for (i = 0; i <= 0x1f; i++) {
+		val = nsp32_prom_read(data, i);
+		nsp32_dbg(NSP32_DEBUG_EEPROM,
+			  "rom address 0x%x : 0x%x", i, val);
+	}
+
+	return ret;
+}
+
+
+/*
+ * AT24C01A (Logitec: LHA-600S), AT24C02 (Melco Buffalo: IFC-USLP) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: ASYNC, 0x0c: Ultra-20M, 0x19: Fast-10M
+ *   0x07        :  HBA Synchronous Transfer Period
+ *			Value 0: AutoSync, 1: Manual Setting
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Bus Termination
+ * 			Value 0: Auto[ON], 1: ON, 2: OFF
+ *   0x11        :  Not Used? (0)
+ *   0x12        :  Bus Reset Delay Time (0x03)
+ *   0x13        :  Bootable CD Support
+ *			Value 0: Disable, 1: Enable
+ *   0x14        :  Device Scan
+ *			Bit   7  6  5  4  3  2  1  0
+ *			      |  <----------------->
+ * 			      |    SCSI ID: Value 0: Skip, 1: YES
+ *			      |->  Value 0: ALL scan,  Value 1: Manual
+ *   0x15 - 0x1b :  Not Used? (0)
+ *   0x1c        :  Constant? (0x01) (clock div?)
+ *   0x1d - 0x7c :  Not Used (0xff)
+ *   0x7d	 :  Not Used? (0xff)
+ *   0x7e        :  Constant (0x55), Validity signature
+ *   0x7f        :  Constant (0xaa), Validity signature
+ */
+static int nsp32_getprom_at24(nsp32_hw_data *data)
+{
+	int           ret, i;
+	int           auto_sync;
+	nsp32_target *target;
+	int           entry;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x12);
+
+	/*
+	 * HBA Synchronous Transfer Period
+	 *
+	 * Note: auto_sync = 0: auto, 1: manual.  Ninja SCSI HBA spec says
+	 *	that if auto_sync is 0 (auto), and connected SCSI devices are
+	 *	same or lower than 3, then transfer speed is set as ULTRA-20M.
+	 *	On the contrary if connected SCSI devices are same or higher
+	 *	than 4, then transfer speed is set as FAST-10M.
+	 *
+	 *	I break this rule. The number of connected SCSI devices are
+	 *	only ignored. If auto_sync is 0 (auto), then transfer speed is
+	 *	forced as ULTRA-20M.
+	 */
+	ret = nsp32_prom_read(data, 0x07);
+	switch (ret) {
+	case 0:
+		auto_sync = TRUE;
+		break;
+	case 1:
+		auto_sync = FALSE;
+		break;
+	default:
+		nsp32_msg(KERN_WARNING,
+			  "Unsupported Auto Sync mode. Fall back to manual mode.");
+		auto_sync = TRUE;
+	}
+
+	if (trans_mode == ULTRA20M_MODE) {
+		auto_sync = TRUE;
+	}
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		if (auto_sync == TRUE) {
+			target->limit_entry = 0;   /* set as ULTRA20M */
+		} else {
+			ret   = nsp32_prom_read(data, i);
+			entry = nsp32_search_period_entry(data, target, ret);
+			if (entry < 0) {
+				/* search failed... set maximum speed */
+				entry = 0;
+			}
+			target->limit_entry = entry;
+		}
+	}
+
+	return TRUE;
+}
+
+
+/*
+ * C16 110 (I-O Data: SC-NBD) data map:
+ *
+ *   ROMADDR
+ *   0x00 - 0x06 :  Device Synchronous Transfer Period (SCSI ID 0 - 6) 
+ *			Value 0x0: 20MB/S, 0x1: 10MB/S, 0x2: 5MB/S, 0x3: ASYNC
+ *   0x07        :  0 (HBA Synchronous Transfer Period: Auto Sync)
+ *   0x08 - 0x0f :  Not Used? (0x0)
+ *   0x10        :  Transfer Mode
+ *			Value 0: PIO, 1: Busmater
+ *   0x11        :  Bus Reset Delay Time (0x00-0x20)
+ *   0x12        :  Bus Termination
+ * 			Value 0: Disable, 1: Enable
+ *   0x13 - 0x19 :  Disconnection
+ *			Value 0: Disable, 1: Enable
+ *   0x1a - 0x7c :  Not Used? (0)
+ *   0x7d	 :  Not Used? (0xf8)
+ *   0x7e        :  Constant (0x55), Validity signature
+ *   0x7f        :  Constant (0xaa), Validity signature
+ */
+static int nsp32_getprom_c16(nsp32_hw_data *data)
+{
+	int           ret, i;
+	nsp32_target *target;
+	int           entry, val;
+
+	/*
+	 * Reset time which is designated by EEPROM.
+	 *
+	 * TODO: Not used yet.
+	 */
+	data->resettime = nsp32_prom_read(data, 0x11);
+
+	/*
+	 * each device Synchronous Transfer Period
+	 */
+	for (i = 0; i < NSP32_HOST_SCSIID; i++) {
+		target = &data->target[i];
+		ret = nsp32_prom_read(data, i);
+		switch (ret) {
+		case 0:		/* 20MB/s */
+			val = 0x0c;
+			break;
+		case 1:		/* 10MB/s */
+			val = 0x19;
+			break;
+		case 2:		/* 5MB/s */
+			val = 0x32;
+			break;
+		case 3:		/* ASYNC */
+			val = 0x00;
+			break;
+		default:	/* default 20MB/s */
+			val = 0x0c;
+			break;
+		}
+		entry = nsp32_search_period_entry(data, target, val);
+		if (entry < 0 || trans_mode == ULTRA20M_MODE) {
+			/* search failed... set maximum speed */
+			entry = 0;
+		}
+		target->limit_entry = entry;
+	}
+
+	return TRUE;
+}
+
+
+/*
+ * Atmel AT24C01A (drived in 5V) serial EEPROM routines
+ */
+static int nsp32_prom_read(nsp32_hw_data *data, int romaddr)
+{
+	int i, val;
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write_bit(data, 1);	/* 1 */
+	nsp32_prom_write_bit(data, 0);	/* 0 */
+	nsp32_prom_write_bit(data, 1);	/* 1 */
+	nsp32_prom_write_bit(data, 0);	/* 0 */
+	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: W for dummy write */
+	nsp32_prom_write_bit(data, 0);
+
+	/* ack */
+	nsp32_prom_write_bit(data, 0);
+
+	/* word address */
+	for (i = 7; i >= 0; i--) {
+		nsp32_prom_write_bit(data, ((romaddr >> i) & 1));
+	}
+
+	/* ack */
+	nsp32_prom_write_bit(data, 0);
+
+	/* start condition */
+	nsp32_prom_start(data);
+
+	/* device address */
+	nsp32_prom_write_bit(data, 1);	/* 1 */
+	nsp32_prom_write_bit(data, 0);	/* 0 */
+	nsp32_prom_write_bit(data, 1);	/* 1 */
+	nsp32_prom_write_bit(data, 0);	/* 0 */
+	nsp32_prom_write_bit(data, 0);	/* A2: 0 (GND) */
+	nsp32_prom_write_bit(data, 0);	/* A1: 0 (GND) */
+	nsp32_prom_write_bit(data, 0);	/* A0: 0 (GND) */
+
+	/* R/W: R */
+	nsp32_prom_write_bit(data, 1);
+
+	/* ack */
+	nsp32_prom_write_bit(data, 0);
+
+	/* data... */
+	val = 0;
+	for (i = 7; i >= 0; i--) {
+		val += (nsp32_prom_read_bit(data) << i);
+	}
+	
+	/* no ack */
+	nsp32_prom_write_bit(data, 1);
+
+	/* stop condition */
+	nsp32_prom_stop(data);
+
+	return val;
+}
+
+static void nsp32_prom_set(nsp32_hw_data *data, int bit, int val)
+{
+	int base = data->BaseAddress;
+	int tmp;
+
+	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL);
+
+	if (val == 0) {
+		tmp &= ~bit;
+	} else {
+		tmp |=  bit;
+	}
+
+	nsp32_index_write1(base, SERIAL_ROM_CTL, tmp);
+
+	udelay(10);
+}
+
+static int nsp32_prom_get(nsp32_hw_data *data, int bit)
+{
+	int base = data->BaseAddress;
+	int tmp, ret;
+
+	if (bit != SDA) {
+		nsp32_msg(KERN_ERR, "return value is not appropriate");
+		return 0;
+	}
+
+
+	tmp = nsp32_index_read1(base, SERIAL_ROM_CTL) & bit;
+
+	if (tmp == 0) {
+		ret = 0;
+	} else {
+		ret = 1;
+	}
+
+	udelay(10);
+
+	return ret;
+}
+
+static void nsp32_prom_start (nsp32_hw_data *data)
+{
+	/* start condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 0);	/* keeping SCL=1 and transiting
+					 * SDA 1->0 is start condition */
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_stop (nsp32_hw_data *data)
+{
+	/* stop condition */
+	nsp32_prom_set(data, SCL, 1);
+	nsp32_prom_set(data, SDA, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+	nsp32_prom_set(data, SDA, 1);
+	nsp32_prom_set(data, SCL, 0);
+}
+
+static void nsp32_prom_write_bit(nsp32_hw_data *data, int val)
+{
+	/* write */
+	nsp32_prom_set(data, SDA, val);
+	nsp32_prom_set(data, SCL, 1  );
+	nsp32_prom_set(data, SCL, 0  );
+}
+
+static int nsp32_prom_read_bit(nsp32_hw_data *data)
+{
+	int val;
+
+	/* read */
+	nsp32_prom_set(data, ENA, 0);	/* input mode */
+	nsp32_prom_set(data, SCL, 1);
+
+	val = nsp32_prom_get(data, SDA);
+
+	nsp32_prom_set(data, SCL, 0);
+	nsp32_prom_set(data, ENA, 1);	/* output mode */
+
+	return val;
+}
+
+
+/**************************************************************************
+ * Power Management
+ */
+#ifdef CONFIG_PM
+
+/* Device suspended */
+static int nsp32_suspend(struct pci_dev *pdev, u32 state)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+
+	nsp32_msg(KERN_INFO, "pci-suspend: pdev=0x%p, state=%ld, slot=%s, host=0x%p", pdev, state, pci_name(pdev), host);
+
+	pci_save_state     (pdev);
+	pci_disable_device (pdev);
+	pci_set_power_state(pdev, state);
+
+	return 0;
+}
+
+/* Device woken up */
+static int nsp32_resume(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	nsp32_hw_data    *data = (nsp32_hw_data *)host->hostdata;
+	unsigned short    reg;
+
+	nsp32_msg(KERN_INFO, "pci-resume: pdev=0x%p, slot=%s, host=0x%p", pdev, pci_name(pdev), host);
+
+	pci_set_power_state(pdev, 0);
+	pci_enable_wake    (pdev, 0, 0);
+	pci_restore_state  (pdev);
+
+	reg = nsp32_read2(data->BaseAddress, INDEX_REG);
+
+	nsp32_msg(KERN_INFO, "io=0x%x reg=0x%x", data->BaseAddress, reg);
+
+	if (reg == 0xffff) {
+		nsp32_msg(KERN_INFO, "missing device. abort resume.");
+		return 0;
+	}
+
+	nsp32hw_init      (data);
+	nsp32_do_bus_reset(data);
+
+	nsp32_msg(KERN_INFO, "resume success");
+
+	return 0;
+}
+
+/* Enable wake event */
+static int nsp32_enable_wake(struct pci_dev *pdev, u32 state, int enable)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+
+	nsp32_msg(KERN_INFO, "pci-enable_wake: stub, pdev=0x%p, enable=%d, slot=%s, host=0x%p", pdev, enable, pci_name(pdev), host);
+
+	return 0;
+}
+#endif
+
+/************************************************************************
+ * PCI/Cardbus probe/remove routine
+ */
+static int __devinit nsp32_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int ret;
+	nsp32_hw_data *data = &nsp32_data_base;
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+        ret = pci_enable_device(pdev);
+	if (ret) {
+		nsp32_msg(KERN_ERR, "failed to enable pci device");
+		return ret;
+	}
+
+	data->Pci         = pdev;
+	data->pci_devid   = id;
+	data->IrqNumber   = pdev->irq;
+	data->BaseAddress = pci_resource_start(pdev, 0);
+	data->NumAddress  = pci_resource_len  (pdev, 0);
+	data->MmioAddress = ioremap_nocache(pci_resource_start(pdev, 1),
+					       pci_resource_len  (pdev, 1));
+	data->MmioLength  = pci_resource_len  (pdev, 1);
+
+	pci_set_master(pdev);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	ret = nsp32_detect(pdev);
+#else
+	ret = scsi_register_host(&nsp32_template);
+#endif
+
+	nsp32_msg(KERN_INFO, "irq: %i mmio: %p+0x%lx slot: %s model: %s",
+		  pdev->irq,
+		  data->MmioAddress, data->MmioLength,
+		  pci_name(pdev),
+		  nsp32_model[id->driver_data]);
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "exit %d", ret);
+
+	return ret;
+}
+
+static void __devexit nsp32_remove(struct pci_dev *pdev)
+{
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+#endif
+
+	nsp32_dbg(NSP32_DEBUG_REGISTER, "enter");
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+        scsi_remove_host(host);
+
+	nsp32_release(host);
+
+	scsi_host_put(host);
+#else
+	scsi_unregister_host(&nsp32_template);	
+#endif
+}
+
+
+
+static struct pci_driver nsp32_driver = {
+	.name		= "nsp32",
+	.id_table	= nsp32_pci_table,
+	.probe		= nsp32_probe,
+	.remove		= __devexit_p(nsp32_remove),
+#ifdef CONFIG_PM
+	.suspend	= nsp32_suspend, 
+	.resume		= nsp32_resume, 
+	.enable_wake    = nsp32_enable_wake,
+#endif
+};
+
+/*********************************************************************
+ * Moule entry point
+ */
+static int __init init_nsp32(void) {
+	nsp32_msg(KERN_INFO, "loading...");
+	return pci_module_init(&nsp32_driver);
+}
+
+static void __exit exit_nsp32(void) {
+	nsp32_msg(KERN_INFO, "unloading...");
+	pci_unregister_driver(&nsp32_driver);
+}
+
+module_init(init_nsp32);
+module_exit(exit_nsp32);
+
+/* end */
diff --git a/drivers/scsi/nsp32.h b/drivers/scsi/nsp32.h
new file mode 100644
index 0000000..5664398
--- /dev/null
+++ b/drivers/scsi/nsp32.h
@@ -0,0 +1,664 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver
+ * Basic data header
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+*/
+
+#ifndef _NSP32_H
+#define _NSP32_H
+
+//#define NSP32_DEBUG 9
+
+/*
+ * VENDOR/DEVICE ID
+ */
+#define PCI_VENDOR_ID_IODATA  0x10fc
+#define PCI_VENDOR_ID_WORKBIT 0x1145
+
+#define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II   0x0005
+#define PCI_DEVICE_ID_NINJASCSI_32BI_KME       0xf007
+#define PCI_DEVICE_ID_NINJASCSI_32BI_WBT       0x8007
+#define PCI_DEVICE_ID_WORKBIT_STANDARD         0xf010
+#define PCI_DEVICE_ID_WORKBIT_DUALEDGE         0xf011
+#define PCI_DEVICE_ID_NINJASCSI_32BI_LOGITEC   0xf012
+#define PCI_DEVICE_ID_NINJASCSI_32BIB_LOGITEC  0xf013
+#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO    0xf015
+#define PCI_DEVICE_ID_NINJASCSI_32UDE_MELCO_II 0x8009
+
+/*
+ * MODEL
+ */
+enum {
+	MODEL_IODATA        = 0,
+	MODEL_KME           = 1,
+	MODEL_WORKBIT       = 2,
+	MODEL_LOGITEC       = 3,
+	MODEL_PCI_WORKBIT   = 4,
+	MODEL_PCI_LOGITEC   = 5,
+	MODEL_PCI_MELCO     = 6,
+};
+
+static char * nsp32_model[] = {
+	"I-O DATA CBSC-II CardBus card",
+	"KME SCSI CardBus card",
+	"Workbit duo SCSI CardBus card",
+	"Logitec CardBus card with external ROM",
+	"Workbit / I-O DATA PCI card",
+	"Logitec PCI card with external ROM",
+	"Melco CardBus/PCI card with external ROM",
+};
+
+
+/*
+ * SCSI Generic Definitions
+ */
+#define EXTENDED_SDTR_LEN	0x03
+
+/* Little Endian */
+typedef u32 u32_le;
+typedef u16 u16_le;
+
+/*
+ * MACRO
+ */
+#define BIT(x)      (1UL << (x))
+
+/*
+ * BASIC Definitions
+ */
+#ifndef TRUE
+# define TRUE  1
+#endif
+#ifndef FALSE
+# define FALSE 0
+#endif
+#define ASSERT 1
+#define NEGATE 0
+
+
+/*******************/
+/* normal register */
+/*******************/
+/*
+ * Don't access below register with Double Word:
+ * +00, +04, +08, +0c, +64, +80, +84, +88, +90, +c4, +c8, +cc, +d0.
+ */
+#define IRQ_CONTROL 0x00	/* BASE+00, W, W */
+#define IRQ_STATUS  0x00	/* BASE+00, W, R */
+# define IRQSTATUS_LATCHED_MSG      BIT(0)
+# define IRQSTATUS_LATCHED_IO       BIT(1)
+# define IRQSTATUS_LATCHED_CD       BIT(2)
+# define IRQSTATUS_LATCHED_BUS_FREE BIT(3)
+# define IRQSTATUS_RESELECT_OCCUER  BIT(4)
+# define IRQSTATUS_PHASE_CHANGE_IRQ BIT(5)
+# define IRQSTATUS_SCSIRESET_IRQ    BIT(6)
+# define IRQSTATUS_TIMER_IRQ        BIT(7)
+# define IRQSTATUS_FIFO_SHLD_IRQ    BIT(8)
+# define IRQSTATUS_PCI_IRQ	    BIT(9)
+# define IRQSTATUS_BMCNTERR_IRQ     BIT(10)
+# define IRQSTATUS_AUTOSCSI_IRQ     BIT(11)
+# define PCI_IRQ_MASK               BIT(12)
+# define TIMER_IRQ_MASK             BIT(13)
+# define FIFO_IRQ_MASK              BIT(14)
+# define SCSI_IRQ_MASK              BIT(15)
+# define IRQ_CONTROL_ALL_IRQ_MASK   (PCI_IRQ_MASK   | \
+                                     TIMER_IRQ_MASK | \
+                                     FIFO_IRQ_MASK  | \
+                                     SCSI_IRQ_MASK  )
+# define IRQSTATUS_ANY_IRQ          (IRQSTATUS_RESELECT_OCCUER	| \
+				     IRQSTATUS_PHASE_CHANGE_IRQ	| \
+				     IRQSTATUS_SCSIRESET_IRQ	| \
+				     IRQSTATUS_TIMER_IRQ	| \
+				     IRQSTATUS_FIFO_SHLD_IRQ	| \
+				     IRQSTATUS_PCI_IRQ		| \
+				     IRQSTATUS_BMCNTERR_IRQ	| \
+				     IRQSTATUS_AUTOSCSI_IRQ	)
+
+#define TRANSFER_CONTROL	0x02	/* BASE+02, W, W */
+#define TRANSFER_STATUS		0x02	/* BASE+02, W, R */
+# define CB_MMIO_MODE        BIT(0)
+# define CB_IO_MODE          BIT(1)
+# define BM_TEST             BIT(2)
+# define BM_TEST_DIR         BIT(3)
+# define DUAL_EDGE_ENABLE    BIT(4)
+# define NO_TRANSFER_TO_HOST BIT(5)
+# define TRANSFER_GO         BIT(7)
+# define BLIEND_MODE         BIT(8)
+# define BM_START            BIT(9)
+# define ADVANCED_BM_WRITE   BIT(10)
+# define BM_SINGLE_MODE      BIT(11)
+# define FIFO_TRUE_FULL      BIT(12)
+# define FIFO_TRUE_EMPTY     BIT(13)
+# define ALL_COUNTER_CLR     BIT(14)
+# define FIFOTEST            BIT(15)
+
+#define INDEX_REG		0x04	/* BASE+04, Byte(R/W), Word(R) */
+
+#define TIMER_SET		0x06	/* BASE+06, W, R/W */
+# define TIMER_CNT_MASK (0xff)
+# define TIMER_STOP     BIT(8)
+
+#define DATA_REG_LOW		0x08	/* BASE+08, LowW, R/W */
+#define DATA_REG_HI		0x0a	/* BASE+0a, Hi-W, R/W */
+
+#define FIFO_REST_CNT		0x0c	/* BASE+0c, W, R/W */
+# define FIFO_REST_MASK       0x1ff
+# define FIFO_EMPTY_SHLD_FLAG BIT(14)
+# define FIFO_FULL_SHLD_FLAG  BIT(15)
+
+#define SREQ_SMPL_RATE		0x0f	/* BASE+0f, B, R/W */
+# define SREQSMPLRATE_RATE0 BIT(0)
+# define SREQSMPLRATE_RATE1 BIT(1)
+# define SAMPLING_ENABLE    BIT(2)
+#  define SMPL_40M (0)                   /* 40MHz:   0-100ns/period */
+#  define SMPL_20M (SREQSMPLRATE_RATE0)  /* 20MHz: 100-200ns/period */
+#  define SMPL_10M (SREQSMPLRATE_RATE1)  /* 10Mhz: 200-   ns/period */
+
+#define SCSI_BUS_CONTROL	0x10	/* BASE+10, B, R/W */
+# define BUSCTL_SEL         BIT(0)
+# define BUSCTL_RST         BIT(1)
+# define BUSCTL_DATAOUT_ENB BIT(2)
+# define BUSCTL_ATN         BIT(3)
+# define BUSCTL_ACK         BIT(4)
+# define BUSCTL_BSY         BIT(5)
+# define AUTODIRECTION      BIT(6)
+# define ACKENB             BIT(7)
+
+#define CLR_COUNTER		0x12	/* BASE+12, B, W */
+# define ACK_COUNTER_CLR       BIT(0)
+# define SREQ_COUNTER_CLR      BIT(1)
+# define FIFO_HOST_POINTER_CLR BIT(2)
+# define FIFO_REST_COUNT_CLR   BIT(3)
+# define BM_COUNTER_CLR        BIT(4)
+# define SAVED_ACK_CLR         BIT(5)
+# define CLRCOUNTER_ALLMASK    (ACK_COUNTER_CLR       | \
+                                SREQ_COUNTER_CLR      | \
+                                FIFO_HOST_POINTER_CLR | \
+                                FIFO_REST_COUNT_CLR   | \
+                                BM_COUNTER_CLR        | \
+                                SAVED_ACK_CLR         )
+
+#define SCSI_BUS_MONITOR	0x12	/* BASE+12, B, R */
+# define BUSMON_MSG BIT(0)
+# define BUSMON_IO  BIT(1)
+# define BUSMON_CD  BIT(2)
+# define BUSMON_BSY BIT(3)
+# define BUSMON_ACK BIT(4)
+# define BUSMON_REQ BIT(5)
+# define BUSMON_SEL BIT(6)
+# define BUSMON_ATN BIT(7)
+
+#define COMMAND_DATA		0x14	/* BASE+14, B, R/W */
+
+#define PARITY_CONTROL		0x16	/* BASE+16, B, W */
+# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_CLEAR  BIT(1)
+#define PARITY_STATUS		0x16	/* BASE+16, B, R */
+//# define PARITY_CHECK_ENABLE BIT(0)
+# define PARITY_ERROR_NORMAL BIT(1)
+# define PARITY_ERROR_LSB    BIT(1)
+# define PARITY_ERROR_MSB    BIT(2)
+
+#define RESELECT_ID		0x18	/* BASE+18, B, R */
+
+#define COMMAND_CONTROL		0x18	/* BASE+18, W, W */
+# define CLEAR_CDB_FIFO_POINTER BIT(0)
+# define AUTO_COMMAND_PHASE     BIT(1)
+# define AUTOSCSI_START         BIT(2)
+# define AUTOSCSI_RESTART       BIT(3)
+# define AUTO_PARAMETER         BIT(4)
+# define AUTO_ATN               BIT(5)
+# define AUTO_MSGIN_00_OR_04    BIT(6)
+# define AUTO_MSGIN_02          BIT(7)
+# define AUTO_MSGIN_03          BIT(8)
+
+#define SET_ARBIT		0x1a	/* BASE+1a, B, W */
+# define ARBIT_GO    BIT(0)
+# define ARBIT_CLEAR BIT(1)
+
+#define ARBIT_STATUS		0x1a	/* BASE+1a, B, R */
+//# define ARBIT_GO             BIT(0)
+# define ARBIT_WIN            BIT(1)
+# define ARBIT_FAIL           BIT(2)
+# define AUTO_PARAMETER_VALID BIT(3)
+# define SGT_VALID            BIT(4)
+
+#define SYNC_REG		0x1c	/* BASE+1c, B, R/W */
+
+#define ACK_WIDTH		0x1d	/* BASE+1d, B, R/W */
+
+#define SCSI_DATA_WITH_ACK	0x20	/* BASE+20, B, R/W */
+#define SCSI_OUT_LATCH_TARGET_ID 0x22	/* BASE+22, B, W */
+#define SCSI_DATA_IN		0x22	/* BASE+22, B, R */
+
+#define SCAM_CONTROL		0x24	/* BASE+24, B, W */
+#define SCAM_STATUS		0x24	/* BASE+24, B, R */
+# define SCAM_MSG    BIT(0)
+# define SCAM_IO     BIT(1)
+# define SCAM_CD     BIT(2)
+# define SCAM_BSY    BIT(3)
+# define SCAM_SEL    BIT(4)
+# define SCAM_XFEROK BIT(5)
+
+#define SCAM_DATA		0x26	/* BASE+26, B, R/W */
+# define SD0	BIT(0)
+# define SD1	BIT(1)
+# define SD2	BIT(2)
+# define SD3	BIT(3)
+# define SD4	BIT(4)
+# define SD5	BIT(5)
+# define SD6	BIT(6)
+# define SD7	BIT(7)
+
+#define SACK_CNT		0x28	/* BASE+28, DW, R/W */
+#define SREQ_CNT		0x2c	/* BASE+2c, DW, R/W */
+
+#define FIFO_DATA_LOW		0x30	/* BASE+30, B/W/DW, R/W */
+#define FIFO_DATA_HIGH		0x32	/* BASE+32, B/W, R/W */
+#define BM_START_ADR		0x34	/* BASE+34, DW, R/W */
+
+#define BM_CNT			0x38	/* BASE+38, DW, R/W */
+# define BM_COUNT_MASK 0x0001ffffUL
+# define SGTEND        BIT(31)      /* Last SGT marker */
+
+#define SGT_ADR			0x3c	/* BASE+3c, DW, R/W */
+#define WAIT_REG		0x40	/* Bi only */
+
+#define SCSI_EXECUTE_PHASE	0x40	/* BASE+40, W, R */
+# define COMMAND_PHASE     BIT(0)
+# define DATA_IN_PHASE     BIT(1)
+# define DATA_OUT_PHASE    BIT(2)
+# define MSGOUT_PHASE      BIT(3)
+# define STATUS_PHASE      BIT(4)
+# define ILLEGAL_PHASE     BIT(5)
+# define BUS_FREE_OCCUER   BIT(6)
+# define MSG_IN_OCCUER     BIT(7)
+# define MSG_OUT_OCCUER    BIT(8)
+# define SELECTION_TIMEOUT BIT(9)
+# define MSGIN_00_VALID    BIT(10)
+# define MSGIN_02_VALID    BIT(11)
+# define MSGIN_03_VALID    BIT(12)
+# define MSGIN_04_VALID    BIT(13)
+# define AUTOSCSI_BUSY     BIT(15)
+
+#define SCSI_CSB_IN		0x42	/* BASE+42, B, R */
+
+#define SCSI_MSG_OUT		0x44	/* BASE+44, DW, R/W */
+# define MSGOUT_COUNT_MASK (BIT(0)|BIT(1))
+# define MV_VALID	    BIT(7)
+
+#define SEL_TIME_OUT		0x48	/* BASE+48, W, R/W */
+#define SAVED_SACK_CNT		0x4c	/* BASE+4c, DW, R */
+
+#define HTOSDATADELAY		0x50	/* BASE+50, B, R/W */
+#define STOHDATADELAY		0x54	/* BASE+54, B, R/W */
+#define ACKSUMCHECKRD		0x58	/* BASE+58, W, R */
+#define REQSUMCHECKRD		0x5c	/* BASE+5c, W, R */
+
+
+/********************/
+/* indexed register */
+/********************/
+
+#define CLOCK_DIV		0x00	/* BASE+08, IDX+00, B, R/W */
+# define CLOCK_2  BIT(0)	/* MCLK/2 */
+# define CLOCK_4  BIT(1)	/* MCLK/4 */
+# define PCICLK	  BIT(7)	/* PCICLK (33MHz) */
+
+#define TERM_PWR_CONTROL	0x01	/* BASE+08, IDX+01, B, R/W */
+# define BPWR  BIT(0)
+# define SENSE BIT(1)	/* Read Only */
+
+#define EXT_PORT_DDR		0x02	/* BASE+08, IDX+02, B, R/W */
+#define EXT_PORT		0x03	/* BASE+08, IDX+03, B, R/W */
+# define LED_ON	 (0)
+# define LED_OFF BIT(0)
+
+#define IRQ_SELECT		0x04	/* BASE+08, IDX+04, W, R/W */
+# define IRQSELECT_RESELECT_IRQ      BIT(0)
+# define IRQSELECT_PHASE_CHANGE_IRQ  BIT(1)
+# define IRQSELECT_SCSIRESET_IRQ     BIT(2)
+# define IRQSELECT_TIMER_IRQ         BIT(3)
+# define IRQSELECT_FIFO_SHLD_IRQ     BIT(4)
+# define IRQSELECT_TARGET_ABORT_IRQ  BIT(5)
+# define IRQSELECT_MASTER_ABORT_IRQ  BIT(6)
+# define IRQSELECT_SERR_IRQ          BIT(7)
+# define IRQSELECT_PERR_IRQ          BIT(8)
+# define IRQSELECT_BMCNTERR_IRQ      BIT(9)
+# define IRQSELECT_AUTO_SCSI_SEQ_IRQ BIT(10)
+
+#define OLD_SCSI_PHASE		0x05	/* BASE+08, IDX+05, B, R */
+# define OLD_MSG  BIT(0)
+# define OLD_IO   BIT(1)
+# define OLD_CD   BIT(2)
+# define OLD_BUSY BIT(3)
+
+#define FIFO_FULL_SHLD_COUNT	0x06	/* BASE+08, IDX+06, B, R/W */
+#define FIFO_EMPTY_SHLD_COUNT	0x07	/* BASE+08, IDX+07, B, R/W */
+
+#define EXP_ROM_CONTROL		0x08	/* BASE+08, IDX+08, B, R/W */ /* external ROM control */
+# define ROM_WRITE_ENB BIT(0)
+# define IO_ACCESS_ENB BIT(1)
+# define ROM_ADR_CLEAR BIT(2)
+
+#define EXP_ROM_ADR		0x09	/* BASE+08, IDX+09, W, R/W */
+
+#define EXP_ROM_DATA		0x0a	/* BASE+08, IDX+0a, B, R/W */
+
+#define CHIP_MODE		0x0b	/* BASE+08, IDX+0b, B, R   */ /* NinjaSCSI-32Bi only */
+# define OEM0 BIT(1)  /* OEM select */ /* 00=I-O DATA, 01=KME, 10=Workbit, 11=Ext ROM */
+# define OEM1 BIT(2)  /* OEM select */
+# define OPTB BIT(3)  /* KME mode select */
+# define OPTC BIT(4)  /* KME mode select */
+# define OPTD BIT(5)  /* KME mode select */
+# define OPTE BIT(6)  /* KME mode select */
+# define OPTF BIT(7)  /* Power management */
+
+#define MISC_WR			0x0c	/* BASE+08, IDX+0c, W, R/W */
+#define MISC_RD			0x0c
+# define SCSI_DIRECTION_DETECTOR_SELECT BIT(0)
+# define SCSI2_HOST_DIRECTION_VALID	BIT(1)	/* Read only */
+# define HOST2_SCSI_DIRECTION_VALID	BIT(2)	/* Read only */
+# define DELAYED_BMSTART                BIT(3)
+# define MASTER_TERMINATION_SELECT      BIT(4)
+# define BMREQ_NEGATE_TIMING_SEL        BIT(5)
+# define AUTOSEL_TIMING_SEL             BIT(6)
+# define MISC_MABORT_MASK		BIT(7)
+# define BMSTOP_CHANGE2_NONDATA_PHASE	BIT(8)
+
+#define BM_CYCLE		0x0d	/* BASE+08, IDX+0d, B, R/W */
+# define BM_CYCLE0		 BIT(0)
+# define BM_CYCLE1		 BIT(1)
+# define BM_FRAME_ASSERT_TIMING	 BIT(2)
+# define BM_IRDY_ASSERT_TIMING	 BIT(3)
+# define BM_SINGLE_BUS_MASTER	 BIT(4)
+# define MEMRD_CMD0              BIT(5)
+# define SGT_AUTO_PARA_MEMED_CMD BIT(6)
+# define MEMRD_CMD1              BIT(7)
+
+
+#define SREQ_EDGH		0x0e	/* BASE+08, IDX+0e, B, W */
+# define SREQ_EDGH_SELECT BIT(0)
+
+#define UP_CNT			0x0f	/* BASE+08, IDX+0f, B, W */
+# define REQCNT_UP  BIT(0)
+# define ACKCNT_UP  BIT(1)
+# define BMADR_UP   BIT(4)
+# define BMCNT_UP   BIT(5)
+# define SGT_CNT_UP BIT(7)
+
+#define CFG_CMD_STR		0x10	/* BASE+08, IDX+10, W, R */
+#define CFG_LATE_CACHE		0x11	/* BASE+08, IDX+11, W, R/W */
+#define CFG_BASE_ADR_1		0x12	/* BASE+08, IDX+12, W, R */
+#define CFG_BASE_ADR_2		0x13	/* BASE+08, IDX+13, W, R */
+#define CFG_INLINE		0x14	/* BASE+08, IDX+14, W, R */
+
+#define SERIAL_ROM_CTL		0x15	/* BASE+08, IDX+15, B, R */
+# define SCL BIT(0)
+# define ENA BIT(1)
+# define SDA BIT(2)
+
+#define FIFO_HST_POINTER	0x16	/* BASE+08, IDX+16, B, R/W */
+#define SREQ_DELAY		0x17	/* BASE+08, IDX+17, B, R/W */
+#define SACK_DELAY		0x18	/* BASE+08, IDX+18, B, R/W */
+#define SREQ_NOISE_CANCEL	0x19	/* BASE+08, IDX+19, B, R/W */
+#define SDP_NOISE_CANCEL	0x1a	/* BASE+08, IDX+1a, B, R/W */
+#define DELAY_TEST		0x1b	/* BASE+08, IDX+1b, B, R/W */
+#define SD0_NOISE_CANCEL	0x20	/* BASE+08, IDX+20, B, R/W */
+#define SD1_NOISE_CANCEL	0x21	/* BASE+08, IDX+21, B, R/W */
+#define SD2_NOISE_CANCEL	0x22	/* BASE+08, IDX+22, B, R/W */
+#define SD3_NOISE_CANCEL	0x23	/* BASE+08, IDX+23, B, R/W */
+#define SD4_NOISE_CANCEL	0x24	/* BASE+08, IDX+24, B, R/W */
+#define SD5_NOISE_CANCEL	0x25	/* BASE+08, IDX+25, B, R/W */
+#define SD6_NOISE_CANCEL	0x26	/* BASE+08, IDX+26, B, R/W */
+#define SD7_NOISE_CANCEL	0x27	/* BASE+08, IDX+27, B, R/W */
+
+
+/*
+ * Useful Bus Monitor status combinations.
+ */
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( BUSMON_BSY |                          BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_IN  ( BUSMON_BSY | BUSMON_MSG | BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_MESSAGE_OUT ( BUSMON_BSY | BUSMON_MSG |             BUSMON_CD | BUSMON_REQ )
+#define BUSMON_DATA_IN     ( BUSMON_BSY |              BUSMON_IO |             BUSMON_REQ )
+#define BUSMON_DATA_OUT    ( BUSMON_BSY |                                      BUSMON_REQ )
+#define BUSMON_STATUS      ( BUSMON_BSY |              BUSMON_IO | BUSMON_CD | BUSMON_REQ )
+#define BUSMON_RESELECT    (                           BUSMON_IO                          | BUSMON_SEL)
+#define BUSMON_PHASE_MASK  (              BUSMON_MSG | BUSMON_IO | BUSMON_CD              | BUSMON_SEL)
+
+#define BUSPHASE_COMMAND     ( BUSMON_COMMAND     & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_IN  ( BUSMON_MESSAGE_IN  & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_IN     ( BUSMON_DATA_IN     & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_OUT    ( BUSMON_DATA_OUT    & BUSMON_PHASE_MASK )
+#define BUSPHASE_STATUS      ( BUSMON_STATUS      & BUSMON_PHASE_MASK )
+#define BUSPHASE_SELECT      ( BUSMON_SEL | BUSMON_IO )
+
+
+/************************************************************************
+ * structure for DMA/Scatter Gather list
+ */
+#define NSP32_SG_SIZE		SG_ALL
+
+typedef struct _nsp32_sgtable {
+	/* values must be little endian */
+	u32_le addr; /* transfer address */
+	u32_le len;  /* transfer length. BIT(31) is for SGT_END mark */
+} __attribute__ ((packed)) nsp32_sgtable;
+
+typedef struct _nsp32_sglun {
+	nsp32_sgtable sgt[NSP32_SG_SIZE+1];	/* SG table */
+} __attribute__ ((packed)) nsp32_sglun;
+#define NSP32_SG_TABLE_SIZE (sizeof(nsp32_sgtable) * NSP32_SG_SIZE * MAX_TARGET * MAX_LUN)
+
+/* Auto parameter mode memory map.   */
+/* All values must be little endian. */
+typedef struct _nsp32_autoparam {
+	u8     cdb[4 * 0x10];    /* SCSI Command                      */
+	u32_le msgout;           /* outgoing messages                 */
+	u8     syncreg;          /* sync register value               */
+	u8     ackwidth;         /* ack width register value          */
+	u8     target_id;        /* target/host device id             */
+	u8     sample_reg;       /* hazard killer sampling rate       */
+	u16_le command_control;  /* command control register          */
+	u16_le transfer_control; /* transfer control register         */
+	u32_le sgt_pointer;      /* SG table physical address for DMA */
+	u32_le dummy[2];
+} __attribute__ ((packed)) nsp32_autoparam;  /* must be packed struct */
+
+/*
+ * host data structure
+ */
+/* message in/out buffer */
+#define MSGOUTBUF_MAX		20
+#define MSGINBUF_MAX		20
+
+/* flag for trans_method */
+#define NSP32_TRANSFER_BUSMASTER	BIT(0)
+#define NSP32_TRANSFER_MMIO		BIT(1)	/* Not supported yet */
+#define NSP32_TRANSFER_PIO		BIT(2)	/* Not supported yet */
+
+
+/*
+ * structure for connected LUN dynamic data
+ *
+ * Note: Currently tagged queuing is disabled, each nsp32_lunt holds
+ *       one SCSI command and one state.
+ */
+#define DISCPRIV_OK		BIT(0)		/* DISCPRIV Enable mode */
+#define MSGIN03			BIT(1)		/* Auto Msg In 03 Flag  */
+
+typedef struct _nsp32_lunt {
+	struct scsi_cmnd	*SCpnt;	    /* Current Handling struct scsi_cmnd */
+	unsigned long	 save_datp;  /* Save Data Pointer - saved position from initial address */
+	int		 msgin03;	/* auto msg in 03 flag     */
+	unsigned int	 sg_num;	/* Total number of SG entries */
+	int		 cur_entry;	/* Current SG entry number */
+	nsp32_sglun     *sglun;		/* sg table per lun        */
+	dma_addr_t       sglun_paddr;   /* sglun physical address  */
+} nsp32_lunt;
+
+
+/*
+ * SCSI TARGET/LUN definition
+ */
+#define NSP32_HOST_SCSIID    7  /* SCSI initiator is everytime defined as 7 */
+#define MAX_TARGET	     8
+#define MAX_LUN		     8	/* XXX: In SPI3, max number of LUN is 64. */
+
+
+typedef struct _nsp32_sync_table {
+	unsigned char	period_num;	/* period number                  */
+	unsigned char	ackwidth;	/* ack width designated by period */
+	unsigned char	start_period;	/* search range - start period    */
+	unsigned char	end_period;	/* search range - end period      */
+	unsigned char   sample_rate;    /* hazard killer parameter        */
+} nsp32_sync_table;
+
+
+/*
+ * structure for target device static data
+ */
+/* flag for nsp32_target.sync_flag */
+#define SDTR_INITIATOR	  BIT(0)    /* sending SDTR from initiator        */
+#define SDTR_TARGET	  BIT(1)    /* sending SDTR from target           */
+#define SDTR_DONE	  BIT(2)    /* exchanging SDTR has been processed */
+
+/* syncronous period value for nsp32_target.config_max */
+#define FAST5M			0x32
+#define FAST10M			0x19
+#define ULTRA20M		0x0c
+
+/* flag for nsp32_target.{sync_offset}, period */
+#define ASYNC_OFFSET		0	/* asynchronous transfer           */
+#define SYNC_OFFSET		0xf	/* synchronous transfer max offset */
+
+/* syncreg:
+  bit:07 06 05 04 03 02 01 00
+      ---PERIOD-- ---OFFSET--   */
+#define TO_SYNCREG(period, offset) (((period) & 0x0f) << 4 | ((offset) & 0x0f))
+
+typedef struct _nsp32_target {
+	unsigned char	syncreg;	/* value for SYNCREG   */
+	unsigned char	ackwidth;	/* value for ACKWIDTH  */
+	unsigned char   period;         /* sync period (0-255) */
+	unsigned char	offset;		/* sync offset (0-15)  */
+	int		sync_flag;	/* SDTR_*, 0           */
+	int		limit_entry;	/* max speed limit entry designated
+					   by EEPROM configuration */
+	unsigned char   sample_reg;     /* SREQ hazard killer register */
+} nsp32_target;
+
+typedef struct _nsp32_hw_data {
+	int           IrqNumber;
+	int           BaseAddress;
+	int           NumAddress;
+	void __iomem *MmioAddress;
+#define NSP32_MMIO_OFFSET 0x0800
+	unsigned long MmioLength;
+
+	struct scsi_cmnd *CurrentSC;
+
+	struct pci_dev             *Pci;
+	const struct pci_device_id *pci_devid;
+	struct Scsi_Host           *Host;
+	spinlock_t                  Lock;
+
+	char info_str[100];
+
+	/* allocated memory region */
+	nsp32_sglun      *sg_list;	/* sglist virtuxal address         */
+	dma_addr_t	  sg_paddr;     /* physical address of hw_sg_table */
+	nsp32_autoparam  *autoparam;	/* auto parameter transfer region  */
+	dma_addr_t	  auto_paddr;	/* physical address of autoparam   */
+	int 		  cur_entry;	/* current sgt entry               */
+
+	/* target/LUN */
+	nsp32_lunt       *cur_lunt;	/* Current connected LUN table */
+	nsp32_lunt        lunt[MAX_TARGET][MAX_LUN];  /* All LUN table */
+
+	nsp32_target     *cur_target;	/* Current connected SCSI ID    */
+	nsp32_target	  target[MAX_TARGET];	     /* SCSI ID */
+	int		  cur_id;	/* Current connected target ID  */
+	int		  cur_lun;	/* Current connected target LUN */
+
+	/* behavior setting parameters */
+	int		  trans_method;	/* transfer method flag            */
+	int		  resettime;	/* Reset time                      */
+	int 		  clock;       	/* clock dividing flag             */
+	nsp32_sync_table *synct;	/* sync_table determined by clock  */
+	int		  syncnum;	/* the max number of synct element */
+
+	/* message buffer */
+	unsigned char msgoutbuf[MSGOUTBUF_MAX]; /* msgout buffer    */
+	char	      msgout_len;		/* msgoutbuf length */
+	unsigned char msginbuf [MSGINBUF_MAX];	/* megin buffer     */
+	char	      msgin_len;		/* msginbuf length  */
+
+} nsp32_hw_data;
+
+/*
+ * TIME definition
+ */
+#define RESET_HOLD_TIME		10000	/* reset time in us (SCSI-2 says the
+					   minimum is 25us) */
+#define SEL_TIMEOUT_TIME	10000	/* 250ms defined in SCSI specification
+					   (25.6us/1unit) */
+#define ARBIT_TIMEOUT_TIME	100	/* 100us */
+#define REQSACK_TIMEOUT_TIME	10000	/* max wait time for REQ/SACK assertion
+					   or negation, 10000us == 10ms */
+
+/**************************************************************************
+ * Compatibility functions
+ */
+
+/* for Kernel 2.4 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+# define scsi_register_host(template) 	scsi_register_module(MODULE_SCSI_HA, template)
+# define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
+# define scsi_host_put(host)            scsi_unregister(host)
+# define pci_name(pci_dev)              ((pci_dev)->slot_name)
+
+typedef void irqreturn_t;
+# define IRQ_NONE      /* */
+# define IRQ_HANDLED   /* */
+# define IRQ_RETVAL(x) /* */
+
+/* This is ad-hoc version of scsi_host_get_next() */
+static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
+{
+	if (host == NULL) {
+		return scsi_hostlist;
+	} else {
+		return host->next;
+	}
+}
+
+/* This is ad-hoc version of scsi_host_hn_get() */
+static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
+{
+	struct Scsi_Host *host;
+
+	for (host = scsi_host_get_next(NULL); host != NULL;
+	     host = scsi_host_get_next(host)) {
+		if (host->host_no == hostno) {
+			break;
+		}
+	}
+
+	return host;
+}
+#endif
+
+#endif /* _NSP32_H */
+/* end */
diff --git a/drivers/scsi/nsp32_debug.c b/drivers/scsi/nsp32_debug.c
new file mode 100644
index 0000000..ef3c59c
--- /dev/null
+++ b/drivers/scsi/nsp32_debug.c
@@ -0,0 +1,263 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver
+ * Debug routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+/*
+ * Show the command data of a command
+ */
+static const char unknown[] = "UNKNOWN";
+
+static const char * group_0_commands[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
+/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
+/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
+/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
+/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
+};
+
+
+static const char *group_1_commands[] = {
+/* 20-22 */  unknown, unknown, unknown,
+/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)",
+/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown,
+/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
+/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
+};
+
+
+static const char *group_2_commands[] = {
+/* 40-41 */ "Change Definition", "Write Same", 
+/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", 
+/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown,
+/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
+/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
+/* 5c-5f */ unknown, unknown, unknown,
+};
+
+#define group(opcode) (((opcode) >> 5) & 7)
+
+#define RESERVED_GROUP  0
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
+
+static const char **commands[] = {
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
+
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
+
+static void print_opcodek(unsigned char opcode)
+{
+	const char **table = commands[ group(opcode) ];
+
+	switch ((unsigned long) table) {
+	case RESERVED_GROUP:
+		printk("%s[%02x] ", reserved, opcode); 
+		break;
+	case NOTEXT_GROUP:
+		printk("%s(notext)[%02x] ", unknown, opcode); 
+		break;
+	case VENDOR_GROUP:
+		printk("%s[%02x] ", vendor, opcode); 
+		break;
+	default:
+		if (table[opcode & 0x1f] != unknown)
+			printk("%s[%02x] ", table[opcode & 0x1f], opcode);
+		else
+			printk("%s[%02x] ", unknown, opcode);
+		break;
+	}
+}
+
+static void print_commandk (unsigned char *command)
+{
+	int i,s;
+//	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	if ((command[0] >> 5) == 6 ||
+	    (command[0] >> 5) == 7 ) {
+		s = 12; /* vender specific */
+	} else {
+		s = COMMAND_SIZE(command[0]);
+	}
+
+	for ( i = 1; i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+
+	switch (s) {
+	case 6:
+		printk("LBA=%d len=%d",
+		       (((unsigned int)command[1] & 0x0f) << 16) |
+		       ( (unsigned int)command[2]         <<  8) |
+		       ( (unsigned int)command[3]              ),
+		       (unsigned int)command[4]
+			);
+		break;
+	case 10:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[7] <<  8) |
+		       ((unsigned int)command[8]      )
+		       );
+		break;
+	case 12:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[6] << 24) |
+		       ((unsigned int)command[7] << 16) |
+		       ((unsigned int)command[8] <<  8) |
+		       ((unsigned int)command[9]      )
+		       );
+		break;
+	default:
+		break;
+	}
+	printk("\n");
+}
+
+static void show_command(Scsi_Cmnd *SCpnt)
+{
+	print_commandk(SCpnt->cmnd);
+}
+
+static void show_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk( "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk( "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk( "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk( "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk( "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk( "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk( "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk( "BUSPHASE_other: 0x%x\n", stat);
+		break;
+	}
+}
+
+static void show_autophase(unsigned short i)
+{
+	printk("auto: 0x%x,", i);
+
+	if(i & COMMAND_PHASE) {
+		printk(" cmd");
+	}
+	if(i & DATA_IN_PHASE) {
+		printk(" din");
+	}
+	if(i & DATA_OUT_PHASE) {
+		printk(" dout");
+	}
+	if(i & MSGOUT_PHASE) {
+		printk(" mout");
+	}
+	if(i & STATUS_PHASE) {
+		printk(" stat");
+	}
+	if(i & ILLEGAL_PHASE) {
+		printk(" ill");
+	}
+	if(i & BUS_FREE_OCCUER) {
+		printk(" bfree-o");
+	}
+	if(i & MSG_IN_OCCUER) {
+		printk(" min-o");
+	}
+	if(i & MSG_OUT_OCCUER) {
+		printk(" mout-o");
+	}
+	if(i & SELECTION_TIMEOUT) {
+		printk(" sel");
+	}
+	if(i & MSGIN_00_VALID) {
+		printk(" m0");
+	}
+	if(i & MSGIN_02_VALID) {
+		printk(" m2");
+	}
+	if(i & MSGIN_03_VALID) {
+		printk(" m3");
+	}
+	if(i & MSGIN_04_VALID) {
+		printk(" m4");
+	}
+	if(i & AUTOSCSI_BUSY) {
+		printk(" busy");
+	}
+
+	printk("\n");
+}
+
+static void nsp32_print_register(int base)
+{
+	if (!(NSP32_DEBUG_MASK & NSP32_SPECIAL_PRINT_REGISTER))
+		return;
+
+	printk("Phase=0x%x, ", nsp32_read1(base, SCSI_BUS_MONITOR));
+	printk("OldPhase=0x%x, ", nsp32_index_read1(base, OLD_SCSI_PHASE));
+	printk("syncreg=0x%x, ", nsp32_read1(base, SYNC_REG));
+	printk("ackwidth=0x%x, ", nsp32_read1(base, ACK_WIDTH));
+	printk("sgtpaddr=0x%lx, ", nsp32_read4(base, SGT_ADR));
+	printk("scsioutlatch=0x%x, ", nsp32_read1(base, SCSI_OUT_LATCH_TARGET_ID));
+	printk("msgout=0x%lx, ", nsp32_read4(base, SCSI_MSG_OUT));
+	printk("miscrd=0x%x, ", nsp32_index_read2(base, MISC_WR));
+	printk("seltimeout=0x%x, ", nsp32_read2(base, SEL_TIME_OUT));
+	printk("sreqrate=0x%x, ", nsp32_read1(base, SREQ_SMPL_RATE));
+	printk("transStatus=0x%x, ", nsp32_read2(base, TRANSFER_STATUS));
+	printk("reselectid=0x%x, ", nsp32_read2(base, COMMAND_CONTROL));
+	printk("arbit=0x%x, ", nsp32_read1(base, ARBIT_STATUS));
+	printk("BmStart=0x%lx, ", nsp32_read4(base, BM_START_ADR));
+	printk("BmCount=0x%lx, ", nsp32_read4(base, BM_CNT));
+	printk("SackCnt=0x%lx, ", nsp32_read4(base, SACK_CNT));
+	printk("SReqCnt=0x%lx, ", nsp32_read4(base, SREQ_CNT));
+	printk("SavedSackCnt=0x%lx, ", nsp32_read4(base, SAVED_SACK_CNT));
+	printk("ScsiBusControl=0x%x, ", nsp32_read1(base, SCSI_BUS_CONTROL));
+	printk("FifoRestCnt=0x%x, ", nsp32_read2(base, FIFO_REST_CNT));
+	printk("CdbIn=0x%x, ", nsp32_read1(base, SCSI_CSB_IN));
+	printk("\n");
+
+	if (0) {
+		printk("execph=0x%x, ", nsp32_read2(base, SCSI_EXECUTE_PHASE));
+		printk("IrqStatus=0x%x, ", nsp32_read2(base, IRQ_STATUS));
+		printk("\n");
+	}
+}
+
+/* end */
diff --git a/drivers/scsi/nsp32_io.h b/drivers/scsi/nsp32_io.h
new file mode 100644
index 0000000..e3f3c27
--- /dev/null
+++ b/drivers/scsi/nsp32_io.h
@@ -0,0 +1,259 @@
+/*
+ * Workbit NinjaSCSI-32Bi/UDE PCI/CardBus SCSI Host Bus Adapter driver
+ * I/O routine
+ *
+ * This software may be used and distributed according to the terms of
+ * the GNU General Public License.
+ */
+
+#ifndef _NSP32_IO_H
+#define _NSP32_IO_H
+
+static inline void nsp32_write1(unsigned int  base,
+				unsigned int  index,
+				unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp32_read1(unsigned int base,
+					unsigned int index)
+{
+	return inb(base + index);
+}
+
+static inline void nsp32_write2(unsigned int   base,
+				unsigned int   index,
+				unsigned short val)
+{
+	outw(val, (base + index));
+}
+
+static inline unsigned short nsp32_read2(unsigned int base,
+					 unsigned int index)
+{
+	return inw(base + index);
+}
+
+static inline void nsp32_write4(unsigned int  base,
+				unsigned int  index,
+				unsigned long val)
+{
+	outl(val, (base + index));
+}
+
+static inline unsigned long nsp32_read4(unsigned int base,
+					unsigned int index)
+{
+	return inl(base + index);
+}
+
+/*==============================================*/
+
+static inline void nsp32_mmio_write1(unsigned long base,
+				     unsigned int  index,
+				     unsigned char val)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	writeb(val, ptr);
+}
+
+static inline unsigned char nsp32_mmio_read1(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned char *ptr;
+
+	ptr = (unsigned char *)(base + NSP32_MMIO_OFFSET + index);
+
+	return readb(ptr);
+}
+
+static inline void nsp32_mmio_write2(unsigned long  base,
+				     unsigned int   index,
+				     unsigned short val)
+{
+	volatile unsigned short *ptr;
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	writew(cpu_to_le16(val), ptr);
+}
+
+static inline unsigned short nsp32_mmio_read2(unsigned long base,
+					      unsigned int  index)
+{
+	volatile unsigned short *ptr;
+
+	ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le16_to_cpu(readw(ptr));
+}
+
+static inline void nsp32_mmio_write4(unsigned long base,
+				     unsigned int  index,
+				     unsigned long val)
+{
+	volatile unsigned long *ptr;
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	writel(cpu_to_le32(val), ptr);
+}
+
+static inline unsigned long nsp32_mmio_read4(unsigned long base,
+					     unsigned int  index)
+{
+	volatile unsigned long *ptr;
+
+	ptr = (unsigned long *)(base + NSP32_MMIO_OFFSET + index);
+
+	return le32_to_cpu(readl(ptr));
+}
+
+/*==============================================*/
+
+static inline unsigned char nsp32_index_read1(unsigned int base,
+					      unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return inb(base + DATA_REG_LOW);
+}
+
+static inline void nsp32_index_write1(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned char val)
+{
+	outb(reg, base + INDEX_REG   );
+	outb(val, base + DATA_REG_LOW);
+}
+
+static inline unsigned short nsp32_index_read2(unsigned int base,
+					       unsigned int reg)
+{
+	outb(reg, base + INDEX_REG);
+	return inw(base + DATA_REG_LOW);
+}
+
+static inline void nsp32_index_write2(unsigned int   base,
+				      unsigned int   reg,
+				      unsigned short val)
+{
+	outb(reg, base + INDEX_REG   );
+	outw(val, base + DATA_REG_LOW);
+}
+
+static inline unsigned long nsp32_index_read4(unsigned int base,
+					      unsigned int reg)
+{
+	unsigned long h,l;
+
+	outb(reg, base + INDEX_REG);
+	l = inw(base + DATA_REG_LOW);
+	h = inw(base + DATA_REG_HI );
+
+	return ((h << 16) | l);
+}
+
+static inline void nsp32_index_write4(unsigned int  base,
+				      unsigned int  reg,
+				      unsigned long val)
+{
+	unsigned long h,l;
+
+	h = (val & 0xffff0000) >> 16;
+	l = (val & 0x0000ffff) >>  0;
+
+	outb(reg, base + INDEX_REG   );
+	outw(l,   base + DATA_REG_LOW);
+	outw(h,   base + DATA_REG_HI );
+}
+
+/*==============================================*/
+
+static inline unsigned char nsp32_mmio_index_read1(unsigned long base,
+						   unsigned int reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	writeb(reg, index_ptr);
+	return readb(data_ptr);
+}
+
+static inline void nsp32_mmio_index_write1(unsigned long base,
+					   unsigned int  reg,
+					   unsigned char val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	writeb(reg, index_ptr);
+	writeb(val, data_ptr );
+}
+
+static inline unsigned short nsp32_mmio_index_read2(unsigned long base,
+						    unsigned int  reg)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	writeb(reg, index_ptr);
+	return le16_to_cpu(readw(data_ptr));
+}
+
+static inline void nsp32_mmio_index_write2(unsigned long  base,
+					   unsigned int   reg,
+					   unsigned short val)
+{
+	volatile unsigned short *index_ptr, *data_ptr;
+
+	index_ptr = (unsigned short *)(base + NSP32_MMIO_OFFSET + INDEX_REG);
+	data_ptr  = (unsigned short *)(base + NSP32_MMIO_OFFSET + DATA_REG_LOW);
+
+	writeb(reg,              index_ptr);
+	writew(cpu_to_le16(val), data_ptr );
+}
+
+/*==============================================*/
+
+static inline void nsp32_multi_read4(unsigned int   base,
+				     unsigned int   reg,
+				     void          *buf,
+				     unsigned long  count)
+{
+	insl(base + reg, buf, count);
+}
+
+static inline void nsp32_fifo_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	nsp32_multi_read4(base, FIFO_DATA_LOW, buf, count);
+}
+
+static inline void nsp32_multi_write4(unsigned int   base,
+				      unsigned int   reg,
+				      void          *buf,
+				      unsigned long  count)
+{
+	outsl(base + reg, buf, count);
+}
+
+static inline void nsp32_fifo_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp32_multi_write4(base, FIFO_DATA_LOW, buf, count);
+}
+
+#endif /* _NSP32_IO_H */
+/* end */
diff --git a/drivers/scsi/oktagon_esp.c b/drivers/scsi/oktagon_esp.c
new file mode 100644
index 0000000..573d7ef
--- /dev/null
+++ b/drivers/scsi/oktagon_esp.c
@@ -0,0 +1,609 @@
+/*
+ * Oktagon_esp.c -- Driver for bsc Oktagon
+ *
+ * Written by Carsten Pluntke 1998
+ *
+ * Based on cyber_esp.c
+ */
+
+#include <linux/config.h>
+
+#if defined(CONFIG_AMIGA) || defined(CONFIG_APUS)
+#define USE_BOTTOM_HALF
+#endif
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/reboot.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <linux/zorro.h>
+#include <asm/irq.h>
+#include <asm/amigaints.h>
+#include <asm/amigahw.h>
+
+#ifdef USE_BOTTOM_HALF
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#endif
+
+/* The controller registers can be found in the Z2 config area at these
+ * offsets:
+ */
+#define OKTAGON_ESP_ADDR 0x03000
+#define OKTAGON_DMA_ADDR 0x01000
+
+
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_led_off(struct NCR_ESP *esp);
+static void dma_led_on(struct NCR_ESP *esp);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+
+static void dma_irq_exit(struct NCR_ESP *esp);
+static void dma_invalidate(struct NCR_ESP *esp);
+
+static void dma_mmu_get_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_get_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_release_scsi_one(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_mmu_release_scsi_sgl(struct NCR_ESP *,Scsi_Cmnd *);
+static void dma_advance_sg(Scsi_Cmnd *);
+static int  oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x);
+
+#ifdef USE_BOTTOM_HALF
+static void dma_commit(void *opaque);
+
+long oktag_to_io(long *paddr, long *addr, long len);
+long oktag_from_io(long *addr, long *paddr, long len);
+
+static DECLARE_WORK(tq_fake_dma, dma_commit, NULL);
+
+#define DMA_MAXTRANSFER 0x8000
+
+#else
+
+/*
+ * No bottom half. Use transfer directly from IRQ. Find a narrow path
+ * between too much IRQ overhead and clogging the IRQ for too long.
+ */
+
+#define DMA_MAXTRANSFER 0x1000
+
+#endif
+
+static struct notifier_block oktagon_notifier = { 
+	oktagon_notify_reboot,
+	NULL,
+	0
+};
+
+static long *paddress;
+static long *address;
+static long len;
+static long dma_on;
+static int direction;
+static struct NCR_ESP *current_esp;
+
+
+static volatile unsigned char cmd_buffer[16];
+				/* This is where all commands are put
+				 * before they are trasfered to the ESP chip
+				 * via PIO.
+				 */
+
+/***************************************************************** Detection */
+int oktagon_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct zorro_dev *z = NULL;
+	unsigned long address;
+	struct ESP_regs *eregs;
+
+	while ((z = zorro_find_device(ZORRO_PROD_BSC_OKTAGON_2008, z))) {
+	    unsigned long board = z->resource.start;
+	    if (request_mem_region(board+OKTAGON_ESP_ADDR,
+				   sizeof(struct ESP_regs), "NCR53C9x")) {
+		/*
+		 * It is a SCSI controller.
+		 * Hardwire Host adapter to SCSI ID 7
+		 */
+		
+		address = (unsigned long)ZTWO_VADDR(board);
+		eregs = (struct ESP_regs *)(address + OKTAGON_ESP_ADDR);
+
+		/* This line was 5 lines lower */
+		esp = esp_allocate(tpnt, (void *)board+OKTAGON_ESP_ADDR);
+
+		/* we have to shift the registers only one bit for oktagon */
+		esp->shift = 1;
+
+		esp_write(eregs->esp_cfg1, (ESP_CONFIG1_PENABLE | 7));
+		udelay(5);
+		if (esp_read(eregs->esp_cfg1) != (ESP_CONFIG1_PENABLE | 7))
+			return 0; /* Bail out if address did not hold data */
+
+		/* Do command transfer with programmed I/O */
+		esp->do_pio_cmds = 1;
+
+		/* Required functions */
+		esp->dma_bytes_sent = &dma_bytes_sent;
+		esp->dma_can_transfer = &dma_can_transfer;
+		esp->dma_dump_state = &dma_dump_state;
+		esp->dma_init_read = &dma_init_read;
+		esp->dma_init_write = &dma_init_write;
+		esp->dma_ints_off = &dma_ints_off;
+		esp->dma_ints_on = &dma_ints_on;
+		esp->dma_irq_p = &dma_irq_p;
+		esp->dma_ports_p = &dma_ports_p;
+		esp->dma_setup = &dma_setup;
+
+		/* Optional functions */
+		esp->dma_barrier = 0;
+		esp->dma_drain = 0;
+		esp->dma_invalidate = &dma_invalidate;
+		esp->dma_irq_entry = 0;
+		esp->dma_irq_exit = &dma_irq_exit;
+		esp->dma_led_on = &dma_led_on;
+		esp->dma_led_off = &dma_led_off;
+		esp->dma_poll = 0;
+		esp->dma_reset = 0;
+
+		esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+		esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+		esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
+		esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
+		esp->dma_advance_sg = &dma_advance_sg;
+
+		/* SCSI chip speed */
+		/* Looking at the quartz of the SCSI board... */
+		esp->cfreq = 25000000;
+
+		/* The DMA registers on the CyberStorm are mapped
+		 * relative to the device (i.e. in the same Zorro
+		 * I/O block).
+		 */
+		esp->dregs = (void *)(address + OKTAGON_DMA_ADDR);
+
+		paddress = (long *) esp->dregs;
+
+		/* ESP register base */
+		esp->eregs = eregs;
+		
+		/* Set the command buffer */
+		esp->esp_command = (volatile unsigned char*) cmd_buffer;
+
+		/* Yes, the virtual address. See below. */
+		esp->esp_command_dvma = (__u32) cmd_buffer;
+
+		esp->irq = IRQ_AMIGA_PORTS;
+		request_irq(IRQ_AMIGA_PORTS, esp_intr, SA_SHIRQ,
+			    "BSC Oktagon SCSI", esp->ehost);
+
+		/* Figure out our scsi ID on the bus */
+		esp->scsi_id = 7;
+		
+		/* We don't have a differential SCSI-bus. */
+		esp->diff = 0;
+
+		esp_initialize(esp);
+
+		printk("ESP_Oktagon Driver 1.1"
+#ifdef USE_BOTTOM_HALF
+		       " [BOTTOM_HALF]"
+#else
+		       " [IRQ]"
+#endif
+		       " registered.\n");
+		printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,esps_in_use);
+		esps_running = esps_in_use;
+		current_esp = esp;
+		register_reboot_notifier(&oktagon_notifier);
+		return esps_in_use;
+	    }
+	}
+	return 0;
+}
+
+
+/*
+ * On certain configurations the SCSI equipment gets confused on reboot,
+ * so we have to reset it then.
+ */
+
+static int
+oktagon_notify_reboot(struct notifier_block *this, unsigned long code, void *x)
+{
+  struct NCR_ESP *esp;
+  
+  if((code == SYS_DOWN || code == SYS_HALT) && (esp = current_esp))
+   {
+    esp_bootup_reset(esp,esp->eregs);
+    udelay(500); /* Settle time. Maybe unnecessary. */
+   }
+  return NOTIFY_DONE;
+}
+    
+
+	
+#ifdef USE_BOTTOM_HALF
+
+
+/*
+ * The bsc Oktagon controller has no real DMA, so we have to do the 'DMA
+ * transfer' in the interrupt (Yikes!) or use a bottom half to not to clutter
+ * IRQ's for longer-than-good.
+ *
+ * FIXME
+ * BIG PROBLEM: 'len' is usually the buffer length, not the expected length
+ * of the data. So DMA may finish prematurely, further reads lead to
+ * 'machine check' on APUS systems (don't know about m68k systems, AmigaOS
+ * deliberately ignores the bus faults) and a normal copy-loop can't
+ * be exited prematurely just at the right moment by the dma_invalidate IRQ.
+ * So do it the hard way, write an own copier in assembler and
+ * catch the exception.
+ *                                     -- Carsten
+ */
+ 
+ 
+static void dma_commit(void *opaque)
+{
+    long wait,len2,pos;
+    struct NCR_ESP *esp;
+
+    ESPDATA(("Transfer: %ld bytes, Address 0x%08lX, Direction: %d\n",
+         len,(long) address,direction));
+    dma_ints_off(current_esp);
+
+    pos = 0;
+    wait = 1;
+    if(direction) /* write? (memory to device) */
+     {
+      while(len > 0)
+       {
+        len2 = oktag_to_io(paddress, address+pos, len);
+	if(!len2)
+	 {
+	  if(wait > 1000)
+	   {
+	    printk("Expedited DMA exit (writing) %ld\n",len);
+	    break;
+	   }
+	  mdelay(wait);
+	  wait *= 2;
+	 }
+	pos += len2;
+	len -= len2*sizeof(long);
+       }
+     } else {
+      while(len > 0)
+       {
+        len2 = oktag_from_io(address+pos, paddress, len);
+	if(!len2)
+	 {
+	  if(wait > 1000)
+	   {
+	    printk("Expedited DMA exit (reading) %ld\n",len);
+	    break;
+	   }
+	  mdelay(wait);
+	  wait *= 2;
+	 }
+	pos += len2;
+	len -= len2*sizeof(long);
+       }
+     }
+
+    /* to make esp->shift work */
+    esp=current_esp;
+
+#if 0
+    len2 = (esp_read(current_esp->eregs->esp_tclow) & 0xff) |
+           ((esp_read(current_esp->eregs->esp_tcmed) & 0xff) << 8);
+
+    /*
+     * Uh uh. If you see this, len and transfer count registers were out of
+     * sync. That means really serious trouble.
+     */
+
+    if(len2)
+      printk("Eeeek!! Transfer count still %ld!\n",len2);
+#endif
+
+    /*
+     * Normally we just need to exit and wait for the interrupt to come.
+     * But at least one device (my Microtek ScanMaker 630) regularly mis-
+     * calculates the bytes it should send which is really ugly because
+     * it locks up the SCSI bus if not accounted for.
+     */
+
+    if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+     {
+      long len = 100;
+      long trash[10];
+
+      /*
+       * Interrupt bit was not set. Either the device is just plain lazy
+       * so we give it a 10 ms chance or...
+       */
+      while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
+        udelay(100);
+
+
+      if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+       {
+        /*
+	 * So we think that the transfer count is out of sync. Since we
+	 * have all we want we are happy and can ditch the trash.
+	 */
+	 
+        len = DMA_MAXTRANSFER;
+
+        while(len-- && (!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR)))
+          oktag_from_io(trash,paddress,2);
+
+        if(!(esp_read(current_esp->eregs->esp_status) & ESP_STAT_INTR))
+         {
+          /*
+           * Things really have gone wrong. If we leave the system in that
+           * state, the SCSI bus is locked forever. I hope that this will
+           * turn the system in a more or less running state.
+           */
+          printk("Device is bolixed, trying bus reset...\n");
+	  esp_bootup_reset(current_esp,current_esp->eregs);
+         }
+       }
+     }
+
+    ESPDATA(("Transfer_finale: do_data_finale should come\n"));
+
+    len = 0;
+    dma_on = 0;
+    dma_ints_on(current_esp);
+}
+
+#endif
+
+/************************************************************* DMA Functions */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	/* Since the CyberStorm DMA is fully dedicated to the ESP chip,
+	 * the number of bytes sent (to the ESP chip) equals the number
+	 * of bytes in the FIFO - there is no buffering in the DMA controller.
+	 * XXXX Do I read this right? It is from host to ESP, right?
+	 */
+	return fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	unsigned long sz = sp->SCp.this_residual;
+	if(sz > DMA_MAXTRANSFER)
+		sz = DMA_MAXTRANSFER;
+	return sz;
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+}
+
+/*
+ * What the f$@& is this?
+ *
+ * Some SCSI devices (like my Microtek ScanMaker 630 scanner) want to transfer
+ * more data than requested. How much? Dunno. So ditch the bogus data into
+ * the sink, hoping the device will advance to the next phase sooner or later.
+ *
+ *                         -- Carsten
+ */
+
+static long oktag_eva_buffer[16]; /* The data sink */
+
+static void oktag_check_dma(void)
+{
+  struct NCR_ESP *esp;
+
+  esp=current_esp;
+  if(!len)
+   {
+    address = oktag_eva_buffer;
+    len = 2;
+    /* esp_do_data sets them to zero like len */
+    esp_write(current_esp->eregs->esp_tclow,2);
+    esp_write(current_esp->eregs->esp_tcmed,0);
+   }
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	/* Zorro is noncached, everything else done using processor. */
+	/* cache_clear(addr, length); */
+	
+	if(dma_on)
+	  panic("dma_init_read while dma process is initialized/running!\n");
+	direction = 0;
+	address = (long *) vaddress;
+	current_esp = esp;
+	len = length;
+	oktag_check_dma();
+        dma_on = 1;
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	/* cache_push(addr, length); */
+
+	if(dma_on)
+	  panic("dma_init_write while dma process is initialized/running!\n");
+	direction = 1;
+	address = (long *) vaddress;
+	current_esp = esp;
+	len = length;
+	oktag_check_dma();
+	dma_on = 1;
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	disable_irq(esp->irq);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	enable_irq(esp->irq);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	/* It's important to check the DMA IRQ bit in the correct way! */
+	return (esp_read(esp->eregs->esp_status) & ESP_STAT_INTR);
+}
+
+static void dma_led_off(struct NCR_ESP *esp)
+{
+}
+
+static void dma_led_on(struct NCR_ESP *esp)
+{
+}
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return ((custom.intenar) & IF_PORTS);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	/* On the Sparc, DMA_ST_WRITE means "move data from device to memory"
+	 * so when (write) is true, it actually means READ!
+	 */
+	if(write){
+		dma_init_read(esp, addr, count);
+	} else {
+		dma_init_write(esp, addr, count);
+	}
+}
+
+/*
+ * IRQ entry when DMA transfer is ready to be started
+ */
+
+static void dma_irq_exit(struct NCR_ESP *esp)
+{
+#ifdef USE_BOTTOM_HALF
+	if(dma_on)
+	 {
+	  schedule_work(&tq_fake_dma);
+	 }
+#else
+	while(len && !dma_irq_p(esp))
+	 {
+	  if(direction)
+	    *paddress = *address++;
+	   else
+	    *address++ = *paddress;
+	  len -= (sizeof(long));
+	 }
+	len = 0;
+        dma_on = 0;
+#endif
+}
+
+/*
+ * IRQ entry when DMA has just finished
+ */
+
+static void dma_invalidate(struct NCR_ESP *esp)
+{
+}
+
+/*
+ * Since the processor does the data transfer we have to use the custom
+ * mmu interface to pass the virtual address, not the physical.
+ */
+
+void dma_mmu_get_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+        sp->SCp.ptr =
+                sp->request_buffer;
+}
+
+void dma_mmu_get_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+        sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
+		      sp->SCp.buffer->offset;
+}
+
+void dma_mmu_release_scsi_one(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+}
+
+void dma_mmu_release_scsi_sgl(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+}
+
+void dma_advance_sg(Scsi_Cmnd *sp)
+{
+	sp->SCp.ptr = page_address(sp->SCp.buffer->page)+
+		      sp->SCp.buffer->offset;
+}
+
+
+#define HOSTS_C
+
+int oktagon_esp_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+	unsigned long address = (unsigned long)((struct NCR_ESP *)instance->hostdata)->edev;
+	esp_release();
+	release_mem_region(address, sizeof(struct ESP_regs));
+	free_irq(IRQ_AMIGA_PORTS, esp_intr);
+	unregister_reboot_notifier(&oktagon_notifier);
+#endif
+	return 1;
+}
+
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "esp-oktagon",
+	.proc_info		= &esp_proc_info,
+	.name			= "BSC Oktagon SCSI",
+	.detect			= oktagon_esp_detect,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.release		= oktagon_esp_release,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/oktagon_io.S b/drivers/scsi/oktagon_io.S
new file mode 100644
index 0000000..08ce8d8
--- /dev/null
+++ b/drivers/scsi/oktagon_io.S
@@ -0,0 +1,195 @@
+/* -*- mode: asm -*-
+ * Due to problems while transferring data I've put these routines as assembly
+ * code.
+ * Since I'm no PPC assembler guru, the code is just the assembler version of
+
+int oktag_to_io(long *paddr,long *addr,long len)
+{
+  long *addr2 = addr;
+  for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
+    *paddr = *addr2++;
+  return addr2 - addr;
+}
+
+int oktag_from_io(long *addr,long *paddr,long len)
+{
+  long *addr2 = addr;
+  for(len=(len+sizeof(long)-1)/sizeof(long);len--;)
+    *addr2++ = *paddr;
+  return addr2 - addr;
+}
+
+ * assembled using gcc -O2 -S, with two exception catch points where data
+ * is moved to/from the IO register.
+ */
+
+#include <linux/config.h>
+
+#ifdef CONFIG_APUS
+
+	.file	"oktagon_io.c"
+
+gcc2_compiled.:
+/*
+	.section ".text"
+*/
+	.align 2
+	.globl oktag_to_io
+	.type	 oktag_to_io,@function
+oktag_to_io:
+	addi 5,5,3
+	srwi 5,5,2
+	cmpwi 1,5,0
+	mr 9,3
+	mr 3,4
+	addi 5,5,-1
+	bc 12,6,.L3
+.L5:
+	cmpwi 1,5,0
+	lwz 0,0(3)
+	addi 3,3,4
+	addi 5,5,-1
+exp1:	stw 0,0(9)
+	bc 4,6,.L5
+.L3:
+ret1:	subf 3,4,3
+	srawi 3,3,2
+	blr
+.Lfe1:
+	.size	 oktag_to_io,.Lfe1-oktag_to_io
+	.align 2
+	.globl oktag_from_io
+	.type	 oktag_from_io,@function
+oktag_from_io:
+	addi 5,5,3
+	srwi 5,5,2
+	cmpwi 1,5,0
+	mr 9,3
+	addi 5,5,-1
+	bc 12,6,.L9
+.L11:
+	cmpwi 1,5,0
+exp2:	lwz 0,0(4)
+	addi 5,5,-1
+	stw 0,0(3)
+	addi 3,3,4
+	bc 4,6,.L11
+.L9:
+ret2:	subf 3,9,3
+	srawi 3,3,2
+	blr
+.Lfe2:
+	.size	 oktag_from_io,.Lfe2-oktag_from_io
+	.ident	"GCC: (GNU) egcs-2.90.29 980515 (egcs-1.0.3 release)"
+
+/*
+ * Exception table.
+ * Second longword shows where to jump when an exception at the addr the first
+ * longword is pointing to is caught.
+ */
+
+.section __ex_table,"a"
+	.align	2
+oktagon_except:
+	.long	exp1,ret1
+	.long	exp2,ret2
+
+#else
+
+/*
+The code which follows is for 680x0 based assembler and is meant for
+Linux/m68k. It was created by cross compiling the code using the
+instructions given above. I then added the four labels used in the
+exception handler table at the bottom of this file.
+- Kevin <kcozens@interlog.com>
+*/
+
+#ifdef CONFIG_AMIGA
+
+	.file	"oktagon_io.c"
+	.version	"01.01"
+gcc2_compiled.:
+.text
+	.align 	2
+.globl oktag_to_io
+	.type	 oktag_to_io,@function
+oktag_to_io:
+	link.w %a6,#0
+	move.l %d2,-(%sp)
+	move.l 8(%a6),%a1
+	move.l 12(%a6),%d1
+	move.l %d1,%a0
+	move.l 16(%a6),%d0
+	addq.l #3,%d0
+	lsr.l #2,%d0
+	subq.l #1,%d0
+	moveq.l #-1,%d2
+	cmp.l %d0,%d2
+	jbeq .L3
+.L5:
+exp1:
+	move.l (%a0)+,(%a1)
+	dbra %d0,.L5
+	clr.w %d0
+	subq.l #1,%d0
+	jbcc .L5
+.L3:
+ret1:
+	move.l %a0,%d0
+	sub.l %d1,%d0
+	asr.l #2,%d0
+	move.l -4(%a6),%d2
+	unlk %a6
+	rts
+
+.Lfe1:
+	.size	 oktag_to_io,.Lfe1-oktag_to_io
+	.align 	2
+.globl oktag_from_io
+	.type	 oktag_from_io,@function
+oktag_from_io:
+	link.w %a6,#0
+	move.l %d2,-(%sp)
+	move.l 8(%a6),%d1
+	move.l 12(%a6),%a1
+	move.l %d1,%a0
+	move.l 16(%a6),%d0
+	addq.l #3,%d0
+	lsr.l #2,%d0
+	subq.l #1,%d0
+	moveq.l #-1,%d2
+	cmp.l %d0,%d2
+	jbeq .L9
+.L11:
+exp2:
+	move.l (%a1),(%a0)+
+	dbra %d0,.L11
+	clr.w %d0
+	subq.l #1,%d0
+	jbcc .L11
+.L9:
+ret2:
+	move.l %a0,%d0
+	sub.l %d1,%d0
+	asr.l #2,%d0
+	move.l -4(%a6),%d2
+	unlk %a6
+	rts
+.Lfe2:
+	.size	 oktag_from_io,.Lfe2-oktag_from_io
+	.ident	"GCC: (GNU) 2.7.2.1"
+
+/*
+ * Exception table.
+ * Second longword shows where to jump when an exception at the addr the first
+ * longword is pointing to is caught.
+ */
+
+.section __ex_table,"a"
+	.align	2
+oktagon_except:
+	.long	exp1,ret1
+	.long	exp2,ret2
+
+#endif
+#endif
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
new file mode 100644
index 0000000..c585c7b
--- /dev/null
+++ b/drivers/scsi/osst.c
@@ -0,0 +1,5914 @@
+/*
+  SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
+  file Documentation/scsi/st.txt for more information.
+
+  History:
+
+  OnStream SCSI Tape support (osst) cloned from st.c by
+  Willem Riede (osst@riede.org) Feb 2000
+  Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000
+
+  Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
+  Contribution and ideas from several people including (in alphabetical
+  order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
+  Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
+
+  Copyright 1992 - 2002 Kai Makisara / 2000 - 2004 Willem Riede
+	 email osst@riede.org
+
+  $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $
+
+  Microscopic alterations - Rik Ling, 2000/12/21
+  Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
+  Some small formal changes - aeb, 950809
+*/
+
+static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $";
+static const char * osst_version = "0.99.3";
+
+/* The "failure to reconnect" firmware bug */
+#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
+#define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/
+#define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7)
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+#include <linux/vmalloc.h>
+#include <linux/blkdev.h>
+#include <linux/moduleparam.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+
+/* The driver prints some debugging information on the console if DEBUG
+   is defined and non-zero. */
+#define DEBUG 0
+
+/* The message level for the debug messages is currently set to KERN_NOTICE
+   so that people can easily see the messages. Later when the debugging messages
+   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
+#define OSST_DEB_MSG  KERN_NOTICE
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+
+#define ST_KILOBYTE 1024
+
+#include "st.h"
+#include "osst.h"
+#include "osst_options.h"
+#include "osst_detect.h"
+
+static int max_dev = 0;
+static int write_threshold_kbs = 0;
+static int max_sg_segs = 0;
+
+#ifdef MODULE
+MODULE_AUTHOR("Willem Riede");
+MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
+MODULE_LICENSE("GPL");
+
+module_param(max_dev, int, 0444);
+MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
+
+module_param(write_threshold_kbs, int, 0644);
+MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)");
+
+module_param(max_sg_segs, int, 0644);
+MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
+#else
+static struct osst_dev_parm {
+       char   *name;
+       int    *val;
+} parms[] __initdata = {
+       { "max_dev",             &max_dev             },
+       { "write_threshold_kbs", &write_threshold_kbs },
+       { "max_sg_segs",         &max_sg_segs         }
+};
+#endif
+
+static char *osst_formats[ST_NBR_MODES] ={"", "l", "m", "a"};
+
+/* Some default definitions have been moved to osst_options.h */
+#define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE)
+#define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE)
+
+/* The buffer size should fit into the 24 bits for length in the
+   6-byte SCSI read and write commands. */
+#if OSST_BUFFER_SIZE >= (2 << 24 - 1)
+#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
+#endif
+
+#if DEBUG
+static int debugging = 1;
+/* uncomment define below to test error recovery */
+// #define OSST_INJECT_ERRORS 1 
+#endif
+
+/* Do not retry! The drive firmware already retries when appropriate,
+   and when it tries to tell us something, we had better listen... */
+#define MAX_RETRIES 0
+
+#define NO_TAPE  NOT_READY
+
+#define OSST_WAIT_POSITION_COMPLETE   (HZ > 200 ? HZ / 200 : 1)
+#define OSST_WAIT_WRITE_COMPLETE      (HZ / 12)
+#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
+	
+#define OSST_TIMEOUT (200 * HZ)
+#define OSST_LONG_TIMEOUT (1800 * HZ)
+
+#define TAPE_NR(x) (iminor(x) & ~(-1 << ST_MODE_SHIFT))
+#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
+#define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0)
+#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
+
+/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
+   24 bits) */
+#define SET_DENS_AND_BLK 0x10001
+
+static int osst_buffer_size       = OSST_BUFFER_SIZE;
+static int osst_write_threshold   = OSST_WRITE_THRESHOLD;
+static int osst_max_sg_segs       = OSST_MAX_SG;
+static int osst_max_dev           = OSST_MAX_TAPES;
+static int osst_nr_dev;
+
+static struct osst_tape **os_scsi_tapes = NULL;
+static DEFINE_RWLOCK(os_scsi_tapes_lock);
+
+static int modes_defined = 0;
+
+static struct osst_buffer *new_tape_buffer(int, int, int);
+static int enlarge_buffer(struct osst_buffer *, int);
+static void normalize_buffer(struct osst_buffer *);
+static int append_to_buffer(const char __user *, struct osst_buffer *, int);
+static int from_buffer(struct osst_buffer *, char __user *, int);
+static int osst_zero_buffer_tail(struct osst_buffer *);
+static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *);
+static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *);
+
+static int osst_probe(struct device *);
+static int osst_remove(struct device *);
+
+static struct scsi_driver osst_template = {
+	.owner			= THIS_MODULE,
+	.gendrv = {
+		.name		=  "osst",
+		.probe		= osst_probe,
+		.remove		= osst_remove,
+	}
+};
+
+static int osst_int_ioctl(struct osst_tape *STp, struct scsi_request ** aSRpnt,
+			    unsigned int cmd_in, unsigned long arg);
+
+static int osst_set_frame_position(struct osst_tape *STp, struct scsi_request ** aSRpnt, int frame, int skip);
+
+static int osst_get_frame_position(struct osst_tape *STp, struct scsi_request ** aSRpnt);
+
+static int osst_flush_write_buffer(struct osst_tape *STp, struct scsi_request ** aSRpnt);
+
+static int osst_write_error_recovery(struct osst_tape * STp, struct scsi_request ** aSRpnt, int pending);
+
+static inline char *tape_name(struct osst_tape *tape)
+{
+	return tape->drive->disk_name;
+}
+
+/* Routines that handle the interaction with mid-layer SCSI routines */
+
+/* Convert the result to success code */
+static int osst_chk_result(struct osst_tape * STp, struct scsi_request * SRpnt)
+{
+	char *name = tape_name(STp);
+	int result = SRpnt->sr_result;
+	unsigned char * sense = SRpnt->sr_sense_buffer, scode;
+#if DEBUG
+	const char *stp;
+#endif
+
+	if (!result) {
+		sense[0] = 0;    /* We don't have sense data if this byte is zero */
+		return 0;
+	}
+	if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
+		scode = sense[2] & 0x0f;
+	else {
+		sense[0] = 0;    /* We don't have sense data if this byte is zero */
+		scode = 0;
+	}
+#if DEBUG
+	if (debugging) {
+		printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+		   name, result,
+		   SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
+		   SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
+		   SRpnt->sr_bufflen);
+		if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
+			       	name, scode, sense[12], sense[13]);
+		if (driver_byte(result) & DRIVER_SENSE)
+			scsi_print_req_sense("osst ", SRpnt);
+	}
+	else
+#endif
+	if (!(driver_byte(result) & DRIVER_SENSE) ||
+		((sense[0] & 0x70) == 0x70 &&
+		 scode != NO_SENSE &&
+		 scode != RECOVERED_ERROR &&
+/*      	 scode != UNIT_ATTENTION && */
+		 scode != BLANK_CHECK &&
+		 scode != VOLUME_OVERFLOW &&
+		 SRpnt->sr_cmnd[0] != MODE_SENSE &&
+		 SRpnt->sr_cmnd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
+		if (driver_byte(result) & DRIVER_SENSE) {
+			printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
+			scsi_print_req_sense("osst:", SRpnt);
+		}
+		else {
+			static	int	notyetprinted = 1;
+
+			printk(KERN_WARNING
+			     "%s:W: Warning %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			     name, result, suggestion(result), driver_byte(result) & DRIVER_MASK,
+			     host_byte(result));
+			if (notyetprinted) {
+				notyetprinted = 0;
+				printk(KERN_INFO
+					"%s:I: This warning may be caused by your scsi controller,\n", name);
+				printk(KERN_INFO
+					"%s:I: it has been reported with some Buslogic cards.\n", name);
+			}
+		}
+	}
+	STp->pos_unknown |= STp->device->was_reset;
+
+	if ((sense[0] & 0x70) == 0x70 &&
+	     scode == RECOVERED_ERROR) {
+		STp->recover_count++;
+		STp->recover_erreg++;
+#if DEBUG
+		if (debugging) {
+			if (SRpnt->sr_cmnd[0] == READ_6)
+				stp = "read";
+			else if (SRpnt->sr_cmnd[0] == WRITE_6)
+				stp = "write";
+			else
+				stp = "ioctl";
+			printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp,
+					     STp->recover_count);
+		}
+#endif
+		if ((sense[2] & 0xe0) == 0)
+			return 0;
+	}
+	return (-EIO);
+}
+
+
+/* Wakeup from interrupt */
+static void osst_sleep_done (struct scsi_cmnd * SCpnt)
+{
+	struct osst_tape * STp = container_of(SCpnt->request->rq_disk->private_data, struct osst_tape, driver);
+
+	if ((STp->buffer)->writing &&
+	    (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
+	    (SCpnt->sense_buffer[2] & 0x40)) {
+		/* EOM at write-behind, has all been written? */
+		if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
+			STp->buffer->midlevel_result = SCpnt->result; /* Error */
+		else
+			STp->buffer->midlevel_result = INT_MAX;       /* OK */
+	}
+	else
+		STp->buffer->midlevel_result = SCpnt->result;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
+	STp->buffer->last_SRpnt = SCpnt->sc_request;
+
+#if DEBUG
+	STp->write_pending = 0;
+#endif
+	complete(SCpnt->request->waiting);
+}
+
+
+/* Do the scsi command. Waits until command performed if do_wait is true.
+   Otherwise osst_write_behind_check() is used to check that the command
+   has finished. */
+static	struct scsi_request * osst_do_scsi(struct scsi_request *SRpnt, struct osst_tape *STp, 
+	unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait)
+{
+	unsigned char *bp;
+#ifdef OSST_INJECT_ERRORS
+	static   int   inject = 0;
+	static   int   repeat = 0;
+#endif
+	if (SRpnt == NULL) {
+		if ((SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC)) == NULL) {
+			printk(KERN_ERR "%s:E: Can't get SCSI request.\n", tape_name(STp));
+			if (signal_pending(current))
+				(STp->buffer)->syscall_result = (-EINTR);
+			else
+				(STp->buffer)->syscall_result = (-EBUSY);
+			return NULL;
+		}
+	}
+
+        init_completion(&STp->wait);
+	SRpnt->sr_use_sg = (bytes > (STp->buffer)->sg[0].length) ?
+				    (STp->buffer)->use_sg : 0;
+	if (SRpnt->sr_use_sg) {
+		bp = (char *)&(STp->buffer->sg[0]);
+		if (STp->buffer->sg_segs < SRpnt->sr_use_sg)
+			SRpnt->sr_use_sg = STp->buffer->sg_segs;
+	}
+	else
+		bp = (STp->buffer)->b_data;
+	SRpnt->sr_data_direction = direction;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_request->waiting = &(STp->wait);
+	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request->rq_disk = STp->drive;
+
+	scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
+
+	if (do_wait) {
+		wait_for_completion(SRpnt->sr_request->waiting);
+		SRpnt->sr_request->waiting = NULL;
+		STp->buffer->syscall_result = osst_chk_result(STp, SRpnt);
+#ifdef OSST_INJECT_ERRORS
+		if (STp->buffer->syscall_result == 0 &&
+		    cmd[0] == READ_6 &&
+		    cmd[4] && 
+		    ( (++ inject % 83) == 29  ||
+		      (STp->first_frame_position == 240 
+			         /* or STp->read_error_frame to fail again on the block calculated above */ &&
+				 ++repeat < 3))) {
+			printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp));
+			STp->buffer->last_result_fatal = 1;
+		}
+#endif
+	}
+	return SRpnt;
+}
+
+
+/* Handle the write-behind checking (downs the semaphore) */
+static void osst_write_behind_check(struct osst_tape *STp)
+{
+	struct osst_buffer * STbuffer;
+
+	STbuffer = STp->buffer;
+
+#if DEBUG
+	if (STp->write_pending)
+		STp->nbr_waits++;
+	else
+		STp->nbr_finished++;
+#endif
+	wait_for_completion(&(STp->wait));
+	(STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
+
+	STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt);
+
+	if ((STp->buffer)->syscall_result)
+		(STp->buffer)->syscall_result =
+			osst_write_error_recovery(STp, &((STp->buffer)->last_SRpnt), 1);
+	else
+		STp->first_frame_position++;
+
+	scsi_release_request((STp->buffer)->last_SRpnt);
+
+	if (STbuffer->writing < STbuffer->buffer_bytes)
+		printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
+
+	STbuffer->buffer_bytes -= STbuffer->writing;
+	STbuffer->writing = 0;
+
+	return;
+}
+
+
+
+/* Onstream specific Routines */
+/*
+ * Initialize the OnStream AUX
+ */
+static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number,
+					 int logical_blk_num, int blk_sz, int blk_cnt)
+{
+	os_aux_t       *aux = STp->buffer->aux;
+	os_partition_t *par = &aux->partition;
+	os_dat_t       *dat = &aux->dat;
+
+	if (STp->raw) return;
+
+	memset(aux, 0, sizeof(*aux));
+	aux->format_id = htonl(0);
+	memcpy(aux->application_sig, "LIN4", 4);
+	aux->hdwr = htonl(0);
+	aux->frame_type = frame_type;
+
+	switch (frame_type) {
+	  case	OS_FRAME_TYPE_HEADER:
+		aux->update_frame_cntr    = htonl(STp->update_frame_cntr);
+		par->partition_num        = OS_CONFIG_PARTITION;
+		par->par_desc_ver         = OS_PARTITION_VERSION;
+		par->wrt_pass_cntr        = htons(0xffff);
+		/* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */
+		par->first_frame_ppos     = htonl(0);
+		par->last_frame_ppos      = htonl(0xbb7);
+		aux->frame_seq_num        = htonl(0);
+		aux->logical_blk_num_high = htonl(0);
+		aux->logical_blk_num      = htonl(0);
+		aux->next_mark_ppos       = htonl(STp->first_mark_ppos);
+		break;
+	  case	OS_FRAME_TYPE_DATA:
+	  case	OS_FRAME_TYPE_MARKER:
+		dat->dat_sz = 8;
+		dat->reserved1 = 0;
+		dat->entry_cnt = 1;
+		dat->reserved3 = 0;
+		dat->dat_list[0].blk_sz   = htonl(blk_sz);
+		dat->dat_list[0].blk_cnt  = htons(blk_cnt);
+		dat->dat_list[0].flags    = frame_type==OS_FRAME_TYPE_MARKER?
+							OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA;
+		dat->dat_list[0].reserved = 0;
+	  case	OS_FRAME_TYPE_EOD:
+		aux->update_frame_cntr    = htonl(0);
+		par->partition_num        = OS_DATA_PARTITION;
+		par->par_desc_ver         = OS_PARTITION_VERSION;
+		par->wrt_pass_cntr        = htons(STp->wrt_pass_cntr);
+		par->first_frame_ppos     = htonl(STp->first_data_ppos);
+		par->last_frame_ppos      = htonl(STp->capacity);
+		aux->frame_seq_num        = htonl(frame_seq_number);
+		aux->logical_blk_num_high = htonl(0);
+		aux->logical_blk_num      = htonl(logical_blk_num);
+		break;
+	  default: ; /* probably FILL */
+	}
+	aux->filemark_cnt = ntohl(STp->filemark_cnt);
+	aux->phys_fm = ntohl(0xffffffff);
+	aux->last_mark_ppos = ntohl(STp->last_mark_ppos);
+	aux->last_mark_lbn  = ntohl(STp->last_mark_lbn);
+}
+
+/*
+ * Verify that we have the correct tape frame
+ */
+static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet)
+{
+	char               * name = tape_name(STp);
+	os_aux_t           * aux  = STp->buffer->aux;
+	os_partition_t     * par  = &(aux->partition);
+	struct st_partstat * STps = &(STp->ps[STp->partition]);
+	int		     blk_cnt, blk_sz, i;
+
+	if (STp->raw) {
+		if (STp->buffer->syscall_result) {
+			for (i=0; i < STp->buffer->sg_segs; i++)
+				memset(page_address(STp->buffer->sg[i].page),
+				       0, STp->buffer->sg[i].length);
+			strcpy(STp->buffer->b_data, "READ ERROR ON FRAME");
+                } else
+			STp->buffer->buffer_bytes = OS_FRAME_SIZE;
+		return 1;
+	}
+	if (STp->buffer->syscall_result) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name);
+#endif
+		return 0;
+	}
+	if (ntohl(aux->format_id) != 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id));
+#endif
+		goto err_out;
+	}
+	if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 &&
+	    (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name);
+#endif
+		goto err_out;
+	}
+	if (par->partition_num != OS_DATA_PARTITION) {
+		if (!STp->linux_media || STp->linux_media_version != 2) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n",
+					    name, par->partition_num);
+#endif
+			goto err_out;
+		}
+	}
+	if (par->par_desc_ver != OS_PARTITION_VERSION) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver);
+#endif
+		goto err_out;
+	}
+	if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", 
+				    name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr);
+#endif
+		goto err_out;
+	}
+	if (aux->frame_type != OS_FRAME_TYPE_DATA &&
+	    aux->frame_type != OS_FRAME_TYPE_EOD &&
+	    aux->frame_type != OS_FRAME_TYPE_MARKER) {
+		if (!quiet)
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type);
+#endif
+		goto err_out;
+	}
+	if (aux->frame_type == OS_FRAME_TYPE_EOD &&
+	    STp->first_frame_position < STp->eod_frame_ppos) {
+		printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name,
+				 STp->first_frame_position);
+		goto err_out;
+	}
+        if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
+		if (!quiet)
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", 
+					    name, ntohl(aux->frame_seq_num), frame_seq_number);
+#endif
+		goto err_out;
+	}
+	if (aux->frame_type == OS_FRAME_TYPE_MARKER) {
+		STps->eof = ST_FM_HIT;
+
+		i = ntohl(aux->filemark_cnt);
+		if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt ||
+		    STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name,
+				  STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected",
+				  i, STp->first_frame_position - 1);
+#endif
+			STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1);
+			if (i >= STp->filemark_cnt)
+				 STp->filemark_cnt = i+1;
+		}
+	}
+	if (aux->frame_type == OS_FRAME_TYPE_EOD) {
+		STps->eof = ST_EOD_1;
+		STp->frame_in_buffer = 1;
+	}
+	if (aux->frame_type == OS_FRAME_TYPE_DATA) {
+                blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
+		blk_sz  = ntohl(aux->dat.dat_list[0].blk_sz);
+		STp->buffer->buffer_bytes = blk_cnt * blk_sz;
+		STp->buffer->read_pointer = 0;
+		STp->frame_in_buffer = 1;
+
+		/* See what block size was used to write file */
+		if (STp->block_size != blk_sz && blk_sz > 0) {
+			printk(KERN_INFO
+	    	"%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n",
+       				name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k',
+				STp->block_size<1024?STp->block_size:STp->block_size/1024,
+				STp->block_size<1024?'b':'k');
+			STp->block_size            = blk_sz;
+			STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz;
+		}
+		STps->eof = ST_NOEOF;
+	}
+        STp->frame_seq_number = ntohl(aux->frame_seq_num);
+	STp->logical_blk_num  = ntohl(aux->logical_blk_num);
+	return 1;
+
+err_out:
+	if (STp->read_error_frame == 0)
+		STp->read_error_frame = STp->first_frame_position - 1;
+	return 0;
+}
+
+/*
+ * Wait for the unit to become Ready
+ */
+static int osst_wait_ready(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+				 unsigned timeout, int initial_delay)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	unsigned long		startwait = jiffies;
+#if DEBUG
+	int			dbg  = debugging;
+	char    	      * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
+#endif
+
+	if (initial_delay > 0)
+		msleep(jiffies_to_msecs(initial_delay));
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+
+	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
+	       (( SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 4    &&
+		 (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)    ) ||
+		( SRpnt->sr_sense_buffer[2]  == 6 && SRpnt->sr_sense_buffer[12] == 0x28 &&
+		  SRpnt->sr_sense_buffer[13] == 0                                        )  )) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name);
+		printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
+		debugging = 0;
+	    }
+#endif
+	    msleep(100);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	}
+	*aSRpnt = SRpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( STp->buffer->syscall_result &&
+	     osst_write_error_recovery(STp, aSRpnt, 0) ) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name);
+	    printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+	    return (-EIO);
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name);
+#endif
+	return 0;
+}
+
+/*
+ * Wait for a tape to be inserted in the unit
+ */
+static int osst_wait_for_medium(struct osst_tape * STp, struct scsi_request ** aSRpnt, unsigned timeout)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	unsigned long		startwait = jiffies;
+#if DEBUG
+	int			dbg = debugging;
+	char    	      * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+
+	while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) &&
+		SRpnt->sr_sense_buffer[2]  == 2 && SRpnt->sr_sense_buffer[12] == 0x3a       &&
+	        SRpnt->sr_sense_buffer[13] == 0                                             ) {
+#if DEBUG
+	    if (debugging) {
+		printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name);
+		printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
+		debugging = 0;
+	    }
+#endif
+	    msleep(100);
+
+	    memset(cmd, 0, MAX_COMMAND_SIZE);
+	    cmd[0] = TEST_UNIT_READY;
+
+	    SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	}
+	*aSRpnt = SRpnt;
+#if DEBUG
+	debugging = dbg;
+#endif
+	if ( STp->buffer->syscall_result     && SRpnt->sr_sense_buffer[2]  != 2 &&
+	     SRpnt->sr_sense_buffer[12] != 4 && SRpnt->sr_sense_buffer[13] == 1) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name);
+	    printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name,
+			STp->buffer->syscall_result, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+			SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+	    return 0;
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name);
+#endif
+	return 1;
+}
+
+static int osst_position_tape_and_confirm(struct osst_tape * STp, struct scsi_request ** aSRpnt, int frame)
+{
+	int	retval;
+
+	osst_wait_ready(STp, aSRpnt, 15 * 60, 0);			/* TODO - can this catch a write error? */
+	retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
+	if (retval) return (retval);
+	osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
+	return (osst_get_frame_position(STp, aSRpnt));
+}
+
+/*
+ * Wait for write(s) to complete
+ */
+static int osst_flush_drive_buffer(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	int			result = 0;
+	int			delay  = OSST_WAIT_WRITE_COMPLETE;
+#if DEBUG
+	char		      * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name);
+#endif
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = WRITE_FILEMARKS;
+	cmd[1] = 1;
+
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	*aSRpnt = SRpnt;
+	if (!SRpnt) return (-EBUSY);
+	if (STp->buffer->syscall_result) {
+		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == 2 && SRpnt->sr_sense_buffer[12] == 4) {
+			if (SRpnt->sr_sense_buffer[13] == 8) {
+				delay = OSST_WAIT_LONG_WRITE_COMPLETE;
+			}
+		} else
+			result = osst_write_error_recovery(STp, aSRpnt, 0);
+	}
+	result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
+	STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
+
+	return (result);
+}
+
+#define OSST_POLL_PER_SEC 10
+static int osst_wait_frame(struct osst_tape * STp, struct scsi_request ** aSRpnt, int curr, int minlast, int to)
+{
+	unsigned long	startwait = jiffies;
+	char	      * name      = tape_name(STp);
+#if DEBUG
+	char	   notyetprinted  = 1;
+#endif
+	if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING)
+		printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name);
+
+	while (time_before (jiffies, startwait + to*HZ))
+	{ 
+		int result;
+		result = osst_get_frame_position(STp, aSRpnt);
+		if (result == -EIO)
+			if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0)
+				return 0;	/* successful recovery leaves drive ready for frame */
+		if (result < 0) break;
+		if (STp->first_frame_position == curr &&
+		    ((minlast < 0 &&
+		      (signed)STp->last_frame_position > (signed)curr + minlast) ||
+		     (minlast >= 0 && STp->cur_frames > minlast)
+		    ) && result >= 0)
+		{
+#if DEBUG			
+			if (debugging || jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC)
+				printk (OSST_DEB_MSG
+					"%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n",
+					name, curr, curr+minlast, STp->first_frame_position,
+					STp->last_frame_position, STp->cur_frames,
+					result, (jiffies-startwait)/HZ, 
+					(((jiffies-startwait)%HZ)*10)/HZ);
+#endif
+			return 0;
+		}
+#if DEBUG
+		if (jiffies - startwait >= 2*HZ/OSST_POLL_PER_SEC && notyetprinted)
+		{
+			printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n",
+				name, curr, curr+minlast, STp->first_frame_position,
+				STp->last_frame_position, STp->cur_frames, result);
+			notyetprinted--;
+		}
+#endif
+		msleep(1000 / OSST_POLL_PER_SEC);
+	}
+#if DEBUG
+	printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n",
+		name, curr, curr+minlast, STp->first_frame_position,
+		STp->last_frame_position, STp->cur_frames,
+		(jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ);
+#endif	
+	return -EBUSY;
+}
+
+static int osst_recover_wait_frame(struct osst_tape * STp, struct scsi_request ** aSRpnt, int writing)
+{
+	struct scsi_request   * SRpnt;
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	unsigned long   	startwait = jiffies;
+	int			retval    = 1;
+        char		      * name      = tape_name(STp);
+                                                                                                                                
+	if (writing) {
+		char	mybuf[24];
+		char  * olddata = STp->buffer->b_data;
+		int	oldsize = STp->buffer->buffer_size;
+
+		/* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_FILEMARKS;
+		cmd[1] = 1;
+		SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
+								MAX_RETRIES, 1);
+
+		while (retval && time_before (jiffies, startwait + 5*60*HZ)) {
+
+			if (STp->buffer->syscall_result && (SRpnt->sr_sense_buffer[2] & 0x0f) != 2) {
+
+				/* some failure - not just not-ready */
+				retval = osst_write_error_recovery(STp, aSRpnt, 0);
+				break;
+			}
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout (HZ / OSST_POLL_PER_SEC);
+
+			STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
+			memset(cmd, 0, MAX_COMMAND_SIZE);
+			cmd[0] = READ_POSITION;
+
+			SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout,
+										MAX_RETRIES, 1);
+
+			retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 );
+			STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
+		}
+		if (retval)
+			printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name);
+	} else
+		/* TODO - figure out which error conditions can be handled */
+		if (STp->buffer->syscall_result)
+			printk(KERN_WARNING
+				"%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name,
+					(*aSRpnt)->sr_sense_buffer[ 2] & 0x0f,
+					(*aSRpnt)->sr_sense_buffer[12],
+					(*aSRpnt)->sr_sense_buffer[13]);
+
+	return retval;
+}
+
+/*
+ * Read the next OnStream tape frame at the current location
+ */
+static int osst_read_frame(struct osst_tape * STp, struct scsi_request ** aSRpnt, int timeout)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	int			retval = 0;
+#if DEBUG
+	os_aux_t	      * aux    = STp->buffer->aux;
+	char		      * name   = tape_name(STp);
+#endif
+
+	if (STp->poll)
+		if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout))
+			retval = osst_recover_wait_frame(STp, aSRpnt, 0);
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = READ_6;
+	cmd[1] = 1;
+	cmd[4] = 1;
+
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
+#endif
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
+				      STp->timeout, MAX_RETRIES, 1);
+	*aSRpnt = SRpnt;
+	if (!SRpnt)
+		return (-EBUSY);
+
+	if ((STp->buffer)->syscall_result) {
+	    retval = 1;
+	    if (STp->read_error_frame == 0) {
+		STp->read_error_frame = STp->first_frame_position;
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame);
+#endif
+	    }
+#if DEBUG
+	    if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+		   name,
+		   SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
+		   SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
+		   SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
+		   SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]);
+#endif
+	}
+	else
+	    STp->first_frame_position++;
+#if DEBUG
+	if (debugging) {
+	   char sig[8]; int i;
+	   for (i=0;i<4;i++)
+		   sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i];
+	   sig[4] = '\0';
+	   printk(OSST_DEB_MSG 
+		"%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig,
+			ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr),
+			aux->frame_type==1?"EOD":aux->frame_type==2?"MARK":
+			aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", 
+			ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
+			ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) );
+	   if (aux->frame_type==2)
+		printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name,
+			ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn));
+	   printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval);
+	}
+#endif
+	return (retval);
+}
+
+static int osst_initiate_read(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	struct st_partstat    * STps   = &(STp->ps[STp->partition]);
+	struct scsi_request   * SRpnt  ;
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	int			retval = 0;
+	char		      * name   = tape_name(STp);
+
+	if (STps->rw != ST_READING) {         /* Initialize read operation */
+		if (STps->rw == ST_WRITING || STp->dirty) {
+			STp->write_type = OS_WRITE_DATA;
+                        osst_flush_write_buffer(STp, aSRpnt);
+			osst_flush_drive_buffer(STp, aSRpnt);
+		}
+		STps->rw = ST_READING;
+		STp->frame_in_buffer = 0;
+
+		/*
+		 *      Issue a read 0 command to get the OnStream drive
+                 *      read frames into its buffer.
+		 */
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = READ_6;
+		cmd[1] = 1;
+
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
+#endif
+		SRpnt   = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+		*aSRpnt = SRpnt;
+		if ((retval = STp->buffer->syscall_result))
+			printk(KERN_WARNING "%s:W: Error starting read ahead\n", name);
+	}
+
+	return retval;
+}
+
+static int osst_get_logical_frame(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+						int frame_seq_number, int quiet)
+{
+	struct st_partstat * STps  = &(STp->ps[STp->partition]);
+	char		   * name  = tape_name(STp);
+	int		     cnt   = 0,
+			     bad   = 0,
+			     past  = 0,
+			     x,
+			     position;
+
+	/*
+	 * If we want just any frame (-1) and there is a frame in the buffer, return it
+	 */
+	if (frame_seq_number == -1 && STp->frame_in_buffer) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
+#endif
+		return (STps->eof);
+	}
+	/*
+         * Search and wait for the next logical tape frame
+	 */
+	while (1) {
+		if (cnt++ > 400) {
+                        printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n",
+					    name, frame_seq_number);
+			if (STp->read_error_frame) {
+				osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0);
+#if DEBUG
+                        	printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n",
+						    name, STp->read_error_frame);
+#endif
+				STp->read_error_frame = 0;
+				STp->abort_count++;
+			}
+			return (-EIO);
+		}
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n",
+					  name, frame_seq_number, cnt);
+#endif
+		if ( osst_initiate_read(STp, aSRpnt)
+                || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) {
+			if (STp->raw)
+				return (-EIO);
+			position = osst_get_frame_position(STp, aSRpnt);
+			if (position >= 0xbae && position < 0xbb8)
+				position = 0xbb8;
+			else if (position > STp->eod_frame_ppos || ++bad == 10) {
+				position = STp->read_error_frame - 1;
+				bad = 0;
+			}
+			else {
+				position += 29;
+				cnt      += 19;
+			}
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n",
+					 name, position);
+#endif
+			osst_set_frame_position(STp, aSRpnt, position, 0);
+			continue;
+		}
+		if (osst_verify_frame(STp, frame_seq_number, quiet))
+			break;
+		if (osst_verify_frame(STp, -1, quiet)) {
+			x = ntohl(STp->buffer->aux->frame_seq_num);
+			if (STp->fast_open) {
+				printk(KERN_WARNING
+				       "%s:W: Found logical frame %d instead of %d after fast open\n",
+				       name, x, frame_seq_number);
+				STp->header_ok = 0;
+				STp->read_error_frame = 0;
+				return (-EIO);
+			}
+			if (x > frame_seq_number) {
+				if (++past > 3) {
+					/* positioning backwards did not bring us to the desired frame */
+					position = STp->read_error_frame - 1;
+				}
+				else {
+			        	position = osst_get_frame_position(STp, aSRpnt)
+					         + frame_seq_number - x - 1;
+
+					if (STp->first_frame_position >= 3000 && position < 3000)
+						position -= 10;
+				}
+#if DEBUG
+                                printk(OSST_DEB_MSG
+				       "%s:D: Found logical frame %d while looking for %d: back up %d\n",
+						name, x, frame_seq_number,
+					       	STp->first_frame_position - position);
+#endif
+                        	osst_set_frame_position(STp, aSRpnt, position, 0);
+				cnt += 10;
+			}
+			else
+				past = 0;
+		}
+		if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name);
+#endif
+			osst_set_frame_position(STp, aSRpnt, 0xbb8, 0);
+			cnt--;
+		}
+		STp->frame_in_buffer = 0;
+	}
+	if (cnt > 1) {
+		STp->recover_count++;
+		STp->recover_erreg++;
+		printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", 
+					name, STp->read_error_frame);
+ 	}
+	STp->read_count++;
+
+#if DEBUG
+	if (debugging || STps->eof)
+		printk(OSST_DEB_MSG
+			"%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n",
+			name, frame_seq_number, STp->frame_seq_number, STps->eof);
+#endif
+	STp->fast_open = 0;
+	STp->read_error_frame = 0;
+	return (STps->eof);
+}
+
+static int osst_seek_logical_blk(struct osst_tape * STp, struct scsi_request ** aSRpnt, int logical_blk_num)
+{
+        struct st_partstat * STps = &(STp->ps[STp->partition]);
+	char		   * name = tape_name(STp);
+	int	retries    = 0;
+	int	frame_seq_estimate, ppos_estimate, move;
+	
+	if (logical_blk_num < 0) logical_blk_num = 0;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n",
+				name, logical_blk_num, STp->logical_blk_num, 
+				STp->block_size<1024?STp->block_size:STp->block_size/1024,
+				STp->block_size<1024?'b':'k');
+#endif
+	/* Do we know where we are? */
+	if (STps->drv_block >= 0) {
+		move                = logical_blk_num - STp->logical_blk_num;
+		if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
+		move               /= (OS_DATA_SIZE / STp->block_size);
+		frame_seq_estimate  = STp->frame_seq_number + move;
+	} else
+		frame_seq_estimate  = logical_blk_num * STp->block_size / OS_DATA_SIZE;
+
+	if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10;
+	else			       ppos_estimate = frame_seq_estimate + 20;
+	while (++retries < 10) {
+	   if (ppos_estimate > STp->eod_frame_ppos-2) {
+	       frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate;
+	       ppos_estimate       = STp->eod_frame_ppos - 2;
+	   }
+	   if (frame_seq_estimate < 0) {
+	       frame_seq_estimate = 0;
+	       ppos_estimate      = 10;
+	   }
+	   osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0);
+	   if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) {
+	      /* we've located the estimated frame, now does it have our block? */
+	      if (logical_blk_num <  STp->logical_blk_num ||
+	          logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) {
+		 if (STps->eof == ST_FM_HIT)
+		    move = logical_blk_num < STp->logical_blk_num? -2 : 1;
+		 else {
+		    move                = logical_blk_num - STp->logical_blk_num;
+		    if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
+		    move               /= (OS_DATA_SIZE / STp->block_size);
+		 }
+		 if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
+#if DEBUG
+		 printk(OSST_DEB_MSG
+			"%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
+				name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
+				STp->logical_blk_num, logical_blk_num, move);
+#endif
+		 frame_seq_estimate += move;
+		 ppos_estimate      += move;
+		 continue;
+	      } else {
+		 STp->buffer->read_pointer  = (logical_blk_num - STp->logical_blk_num) * STp->block_size;
+		 STp->buffer->buffer_bytes -= STp->buffer->read_pointer;
+		 STp->logical_blk_num       =  logical_blk_num;
+#if DEBUG
+		 printk(OSST_DEB_MSG 
+			"%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n",
+				name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, 
+				STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, 
+				STp->block_size);
+#endif
+		 STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
+		 if (STps->eof == ST_FM_HIT) {
+		     STps->drv_file++;
+		     STps->drv_block = 0;
+		 } else {
+		     STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
+					  STp->logical_blk_num -
+					     (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
+					-1;
+		 }
+		 STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
+		 return 0;
+	      }
+	   }
+	   if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0)
+	      goto error;
+	   /* we are not yet at the estimated frame, adjust our estimate of its physical position */
+#if DEBUG
+	   printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", 
+			   name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, 
+			   STp->logical_blk_num, logical_blk_num);
+#endif
+	   if (frame_seq_estimate != STp->frame_seq_number)
+	      ppos_estimate += frame_seq_estimate - STp->frame_seq_number;
+	   else
+	      break;
+	}
+error:
+	printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", 
+			    name, logical_blk_num, STp->logical_blk_num, retries);
+	return (-EIO);
+}
+
+/* The values below are based on the OnStream frame payload size of 32K == 2**15,
+ * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block
+ * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions
+ * inside each frame. Finaly, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1.
+ */
+#define OSST_FRAME_SHIFT  6
+#define OSST_SECTOR_SHIFT 9
+#define OSST_SECTOR_MASK  0x03F
+
+static int osst_get_sector(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	int	sector;
+#if DEBUG
+	char  * name = tape_name(STp);
+	
+	printk(OSST_DEB_MSG 
+		"%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n",
+		name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
+		STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, 
+		STp->ps[STp->partition].rw == ST_WRITING?'w':'r',
+		STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes:
+		STp->buffer->read_pointer, STp->ps[STp->partition].eof);
+#endif
+	/* do we know where we are inside a file? */
+	if (STp->ps[STp->partition].drv_block >= 0) {
+		sector = (STp->frame_in_buffer ? STp->first_frame_position-1 :
+				STp->first_frame_position) << OSST_FRAME_SHIFT;
+		if (STp->ps[STp->partition].rw == ST_WRITING)
+		       	sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
+		else
+	       		sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK;
+	} else {
+		sector = osst_get_frame_position(STp, aSRpnt);
+		if (sector > 0)
+			sector <<= OSST_FRAME_SHIFT;
+	}
+	return sector;
+}
+
+static int osst_seek_sector(struct osst_tape * STp, struct scsi_request ** aSRpnt, int sector)
+{
+        struct st_partstat * STps   = &(STp->ps[STp->partition]);
+	int		     frame  = sector >> OSST_FRAME_SHIFT,
+			     offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, 
+			     r;
+#if DEBUG
+	char          * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n",
+				name, sector, frame, offset);
+#endif
+	if (frame < 0 || frame >= STp->capacity) return (-ENXIO);
+
+	if (frame <= STp->first_data_ppos) {
+		STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0;
+		return (osst_set_frame_position(STp, aSRpnt, frame, 0));
+	}
+	r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0);
+	if (r < 0) return r;
+
+	r = osst_get_logical_frame(STp, aSRpnt, -1, 1);
+	if (r < 0) return r;
+
+	if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO);
+
+	if (offset) {
+		STp->logical_blk_num      += offset / STp->block_size;
+		STp->buffer->read_pointer  = offset;
+		STp->buffer->buffer_bytes -= offset;
+	} else {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer       = 0;
+		STp->logical_blk_num      += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+		STp->buffer->buffer_bytes  = STp->buffer->read_pointer = 0;
+	}
+	STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt);
+	if (STps->eof == ST_FM_HIT) {
+		STps->drv_file++;
+		STps->drv_block = 0;
+	} else {
+		STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)?
+				    STp->logical_blk_num -
+					(STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0):
+				  -1;
+	}
+	STps->eof       = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF;
+#if DEBUG
+	printk(OSST_DEB_MSG 
+		"%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n",
+		name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num,
+		STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof);
+#endif
+	return 0;
+}
+
+/*
+ * Read back the drive's internal buffer contents, as a part
+ * of the write error recovery mechanism for old OnStream
+ * firmware revisions.
+ * Precondition for this function to work: all frames in the
+ * drive's buffer must be of one type (DATA, MARK or EOD)!
+ */
+static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+						unsigned int frame, unsigned int skip, int pending)
+{
+	struct scsi_request   * SRpnt = * aSRpnt;
+	unsigned char	      * buffer, * p;
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	int			flag, new_frame, i;
+	int			nframes          = STp->cur_frames;
+	int			blks_per_frame   = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	int			frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num)
+						- (nframes + pending - 1);
+	int			logical_blk_num  = ntohl(STp->buffer->aux->logical_blk_num) 
+						- (nframes + pending - 1) * blks_per_frame;
+	char		      * name             = tape_name(STp);
+	unsigned long		startwait        = jiffies;
+#if DEBUG
+	int			dbg              = debugging;
+#endif
+
+	if ((buffer = (unsigned char *)vmalloc((nframes + 1) * OS_DATA_SIZE)) == NULL)
+		return (-EIO);
+
+	printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n",
+			 name, nframes, pending?" and one that was pending":"");
+
+	osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE]));
+#if DEBUG
+	if (pending && debugging)
+		printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n",
+				name, frame_seq_number + nframes,
+			       	logical_blk_num + nframes * blks_per_frame,
+			       	p[0], p[1], p[2], p[3]);
+#endif
+	for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) {
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = 0x3C;		/* Buffer Read           */
+		cmd[1] = 6;		/* Retrieve Faulty Block */
+		cmd[7] = 32768 >> 8;
+		cmd[8] = 32768 & 0xff;
+
+		SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE,
+					    STp->timeout, MAX_RETRIES, 1);
+	
+		if ((STp->buffer)->syscall_result || !SRpnt) {
+			printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
+			vfree((void *)buffer);
+			*aSRpnt = SRpnt;
+			return (-EIO);
+		}
+		osst_copy_from_buffer(STp->buffer, p);
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n",
+					  name, frame_seq_number + i, p[0], p[1], p[2], p[3]);
+#endif
+	}
+	*aSRpnt = SRpnt;
+	osst_get_frame_position(STp, aSRpnt);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames);
+#endif
+	/* Write synchronously so we can be sure we're OK again and don't have to recover recursively */
+	/* In the header we don't actually re-write the frames that fail, just the ones after them */
+
+	for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) {
+
+		if (flag) {
+			if (STp->write_type == OS_WRITE_HEADER) {
+				i += skip;
+				p += skip * OS_DATA_SIZE;
+			}
+			else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990)
+				new_frame = 3000-i;
+			else
+				new_frame += skip;
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n",
+						name, new_frame+i, frame_seq_number+i);
+#endif
+			osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
+			osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
+			osst_get_frame_position(STp, aSRpnt);
+			SRpnt = * aSRpnt;
+
+			if (new_frame > frame + 1000) {
+				printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name);
+				vfree((void *)buffer);
+				return (-EIO);
+			}
+			if ( i >= nframes + pending ) break;
+			flag = 0;
+		}
+		osst_copy_to_buffer(STp->buffer, p);
+		/*
+		 * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type!
+		 */
+		osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i,
+			       	logical_blk_num + i*blks_per_frame,
+			       	ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame);
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_6;
+		cmd[1] = 1;
+		cmd[4] = 1;
+
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG
+				"%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n",
+				name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame,
+				p[0], p[1], p[2], p[3]);
+#endif
+		SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
+					    STp->timeout, MAX_RETRIES, 1);
+
+		if (STp->buffer->syscall_result)
+			flag = 1;
+		else {
+			p += OS_DATA_SIZE; i++;
+
+			/* if we just sent the last frame, wait till all successfully written */
+			if ( i == nframes + pending ) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name);
+#endif
+				memset(cmd, 0, MAX_COMMAND_SIZE);
+				cmd[0] = WRITE_FILEMARKS;
+				cmd[1] = 1;
+				SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+							    STp->timeout, MAX_RETRIES, 1);
+#if DEBUG
+				if (debugging) {
+					printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
+					printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
+					debugging = 0;
+				}
+#endif
+				flag = STp->buffer->syscall_result;
+				while ( !flag && time_before(jiffies, startwait + 60*HZ) ) {
+
+					memset(cmd, 0, MAX_COMMAND_SIZE);
+					cmd[0] = TEST_UNIT_READY;
+
+					SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout,
+												MAX_RETRIES, 1);
+
+					if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
+					    (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
+						/* in the process of becoming ready */
+						msleep(100);
+						continue;
+					}
+					if (STp->buffer->syscall_result)
+						flag = 1;
+					break;
+				}
+#if DEBUG
+				debugging = dbg;
+				printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
+#endif
+			}
+		}
+		*aSRpnt = SRpnt;
+		if (flag) {
+			if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
+			     SRpnt->sr_sense_buffer[12]         ==  0 &&
+			     SRpnt->sr_sense_buffer[13]         ==  2) {
+				printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name);
+				vfree((void *)buffer);
+				return (-EIO);			/* hit end of tape = fail */
+			}
+			i = ((SRpnt->sr_sense_buffer[3] << 24) |
+			     (SRpnt->sr_sense_buffer[4] << 16) |
+			     (SRpnt->sr_sense_buffer[5] <<  8) |
+			      SRpnt->sr_sense_buffer[6]        ) - new_frame;
+			p = &buffer[i * OS_DATA_SIZE];
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i);
+#endif
+			osst_get_frame_position(STp, aSRpnt);
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n",
+					  name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
+#endif
+		}
+	}
+	if (flag) {
+		/* error recovery did not successfully complete */
+		printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name,
+				STp->write_type == OS_WRITE_HEADER?"header":"body");
+	}
+	if (!pending)
+		osst_copy_to_buffer(STp->buffer, p);	/* so buffer content == at entry in all cases */
+	vfree((void *)buffer);
+	return 0;
+}
+
+static int osst_reposition_and_retry(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+					unsigned int frame, unsigned int skip, int pending)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	char		      * name      = tape_name(STp);
+	int			expected  = 0;
+	int			attempts  = 1000 / skip;
+	int			flag      = 1;
+	unsigned long		startwait = jiffies;
+#if DEBUG
+	int			dbg       = debugging;
+#endif
+
+	while (attempts && time_before(jiffies, startwait + 60*HZ)) {
+		if (flag) {
+#if DEBUG
+			debugging = dbg;
+#endif
+			if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990)
+				frame = 3000-skip;
+			expected = frame+skip+STp->cur_frames+pending;
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n",
+					  name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending);
+#endif
+			osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
+			flag = 0;
+			attempts--;
+			set_current_state(TASK_INTERRUPTIBLE);
+			schedule_timeout(HZ / 10);
+		}
+		if (osst_get_frame_position(STp, aSRpnt) < 0) {		/* additional write error */
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n",
+					  name, STp->first_frame_position,
+					  STp->last_frame_position, STp->cur_frames);
+#endif
+			frame = STp->last_frame_position;
+			flag = 1;
+			continue;
+		}
+		if (pending && STp->cur_frames < 50) {
+
+			memset(cmd, 0, MAX_COMMAND_SIZE);
+			cmd[0] = WRITE_6;
+			cmd[1] = 1;
+			cmd[4] = 1;
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n",
+					  name, STp->frame_seq_number-1, STp->first_frame_position);
+#endif
+			SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE,
+						      STp->timeout, MAX_RETRIES, 1);
+			*aSRpnt = SRpnt;
+
+			if (STp->buffer->syscall_result) {		/* additional write error */
+				if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) == 13 &&
+				     SRpnt->sr_sense_buffer[12]         ==  0 &&
+				     SRpnt->sr_sense_buffer[13]         ==  2) {
+					printk(KERN_ERR
+					       "%s:E: Volume overflow in write error recovery\n",
+					       name);
+					break;				/* hit end of tape = fail */
+				}
+				flag = 1;
+			}
+			else
+				pending = 0;
+
+			continue;
+		}
+		if (STp->cur_frames == 0) {
+#if DEBUG
+			debugging = dbg;
+			printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name);
+#endif
+			if (STp->first_frame_position != expected) {
+				printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", 
+						name, STp->first_frame_position, expected);
+				return (-EIO);
+			}
+			return 0;
+		}
+#if DEBUG
+		if (debugging) {
+			printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name);
+			printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name);
+			debugging = 0;
+		}
+#endif
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(HZ / 10);
+	}
+	printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name);
+#if DEBUG
+	debugging = dbg;
+#endif
+	return (-EIO);
+}
+
+/*
+ * Error recovery algorithm for the OnStream tape.
+ */
+
+static int osst_write_error_recovery(struct osst_tape * STp, struct scsi_request ** aSRpnt, int pending)
+{
+	struct scsi_request * SRpnt  = * aSRpnt;
+	struct st_partstat  * STps   = & STp->ps[STp->partition];
+	char		    * name   = tape_name(STp);
+	int		      retval = 0;
+	int		      rw_state;
+	unsigned int	      frame, skip;
+
+	rw_state = STps->rw;
+
+	if ((SRpnt->sr_sense_buffer[ 2] & 0x0f) != 3
+	  || SRpnt->sr_sense_buffer[12]         != 12
+	  || SRpnt->sr_sense_buffer[13]         != 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name,
+			SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+		return (-EIO);
+	}
+	frame =	(SRpnt->sr_sense_buffer[3] << 24) |
+		(SRpnt->sr_sense_buffer[4] << 16) |
+		(SRpnt->sr_sense_buffer[5] <<  8) |
+		 SRpnt->sr_sense_buffer[6];
+	skip  =  SRpnt->sr_sense_buffer[9];
+ 
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip);
+#endif
+	osst_get_frame_position(STp, aSRpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n",
+			name, STp->first_frame_position, STp->last_frame_position);
+#endif
+	switch (STp->write_type) {
+	   case OS_WRITE_DATA:
+	   case OS_WRITE_EOD:
+	   case OS_WRITE_NEW_MARK:
+		printk(KERN_WARNING 
+			"%s:I: Relocating %d buffered logical frames from position %u to %u\n",
+			name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip);
+		if (STp->os_fw_rev >= 10600)
+			retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending);
+		else
+			retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending);
+		printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name,
+			       	retval?"E"    :"I",
+			       	retval?""     :"Don't worry, ",
+			       	retval?" not ":" ");
+		break;
+	   case OS_WRITE_LAST_MARK:
+		printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name);
+		osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
+		retval = -EIO;
+		break;
+	   case OS_WRITE_HEADER:
+		printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name);
+		retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending);
+		break;
+	   default:
+		printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name);
+		osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0);
+	}
+	osst_get_frame_position(STp, aSRpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", 
+			name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position);
+	printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num);
+#endif
+	if (retval == 0) {
+		STp->recover_count++;
+		STp->recover_erreg++;
+	} else
+		STp->abort_count++;
+
+	STps->rw = rw_state;
+	return retval;
+}
+
+static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+								 int mt_op, int mt_count)
+{
+	char  * name = tape_name(STp);
+	int     cnt;
+	int     last_mark_ppos = -1;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name);
+#endif
+		return -EIO;
+	}
+	if (STp->linux_media_version >= 4) {
+		/*
+		 * direct lookup in header filemark list
+		 */
+		cnt = ntohl(STp->buffer->aux->filemark_cnt);
+		if (STp->header_ok                         && 
+		    STp->header_cache != NULL              &&
+		    (cnt - mt_count)  >= 0                 &&
+		    (cnt - mt_count)   < OS_FM_TAB_MAX     &&
+		    (cnt - mt_count)   < STp->filemark_cnt &&
+		    STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos)
+
+			last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]);
+#if DEBUG
+		if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX)
+			printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
+			       STp->header_cache == NULL?"lack of header cache":"count out of range");
+		else
+			printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
+				name, cnt,
+				((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+				 (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] ==
+					 STp->buffer->aux->last_mark_ppos))?"match":"error",
+			       mt_count, last_mark_ppos);
+#endif
+		if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) {
+			osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG 
+					"%s:D: Couldn't get logical blk num in space_filemarks\n", name);
+#endif
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
+						 name, last_mark_ppos);
+				return (-EIO);
+			}
+			goto found;
+		}
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name);
+#endif
+	}
+	cnt = 0;
+	while (cnt != mt_count) {
+		last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos);
+		if (last_mark_ppos == -1)
+			return (-EIO);
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos);
+#endif
+		osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos);
+		cnt++;
+		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
+#endif
+			return (-EIO);
+		}
+		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+			printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
+					 name, last_mark_ppos);
+			return (-EIO);
+		}
+	}
+found:
+	if (mt_op == MTBSFM) {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer      = 0;
+		STp->buffer->buffer_bytes = 0;
+		STp->buffer->read_pointer = 0;
+		STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	}
+	return 0;
+}
+
+/*
+ * ADRL 1.1 compatible "slow" space filemarks fwd version
+ *
+ * Just scans for the filemark sequentially.
+ */
+static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+								     int mt_op, int mt_count)
+{
+	int	cnt = 0;
+#if DEBUG
+	char  * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
+#endif
+		return (-EIO);
+	}
+	while (1) {
+		if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name);
+#endif
+			return (-EIO);
+		}
+		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
+			cnt++;
+		if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
+#endif
+			if (STp->first_frame_position > STp->eod_frame_ppos+1) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n",
+					       	name, STp->eod_frame_ppos, STp->first_frame_position-1);
+#endif
+				STp->eod_frame_ppos = STp->first_frame_position-1;
+			}
+			return (-EIO);
+		}
+		if (cnt == mt_count)
+			break;
+		STp->frame_in_buffer = 0;
+	}
+	if (mt_op == MTFSF) {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer      = 0;
+		STp->buffer->buffer_bytes = 0;
+		STp->buffer->read_pointer = 0;
+		STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	}
+	return 0;
+}
+
+/*
+ * Fast linux specific version of OnStream FSF
+ */
+static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+								     int mt_op, int mt_count)
+{
+	char  * name = tape_name(STp);
+	int	cnt  = 0,
+		next_mark_ppos = -1;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count);
+#endif
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name);
+#endif
+		return (-EIO);
+	}
+
+	if (STp->linux_media_version >= 4) {
+		/*
+		 * direct lookup in header filemark list
+		 */
+		cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1;
+		if (STp->header_ok                         && 
+		    STp->header_cache != NULL              &&
+		    (cnt + mt_count)   < OS_FM_TAB_MAX     &&
+		    (cnt + mt_count)   < STp->filemark_cnt &&
+		    ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+		     (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos)))
+
+			next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]);
+#if DEBUG
+		if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX)
+			printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name,
+			       STp->header_cache == NULL?"lack of header cache":"count out of range");
+		else
+			printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n",
+			       name, cnt,
+			       ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) ||
+				(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] ==
+					 STp->buffer->aux->last_mark_ppos))?"match":"error",
+			       mt_count, next_mark_ppos);
+#endif
+		if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
+#endif
+			return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
+		} else {
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
+						 name);
+#endif
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
+						 name, next_mark_ppos);
+				return (-EIO);
+			}
+			if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) {
+				printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n",
+						 name, cnt+mt_count, next_mark_ppos,
+						 ntohl(STp->buffer->aux->filemark_cnt));
+       				return (-EIO);
+			}
+		}
+	} else {
+		/*
+		 * Find nearest (usually previous) marker, then jump from marker to marker
+		 */
+		while (1) {
+			if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER)
+				break;
+			if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name);
+#endif
+				return (-EIO);
+			}
+			if (ntohl(STp->buffer->aux->filemark_cnt) == 0) {
+				if (STp->first_mark_ppos == -1) {
+#if DEBUG
+					printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
+#endif
+					return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count);
+				}
+				osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos);
+				if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+					printk(OSST_DEB_MSG
+					       "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n",
+					       name);
+#endif
+					return (-EIO);
+				}
+				if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+					printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n",
+							 name, STp->first_mark_ppos);
+					return (-EIO);
+				}
+			} else {
+				if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0)
+					return (-EIO);
+				mt_count++;
+			}
+		}
+		cnt++;
+		while (cnt != mt_count) {
+			next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos);
+			if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name);
+#endif
+				return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt);
+			}
+#if DEBUG
+			else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos);
+#endif
+			osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos);
+			cnt++;
+			if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+				printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n",
+						 name);
+#endif
+				return (-EIO);
+			}
+			if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) {
+				printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n",
+						 name, next_mark_ppos);
+				return (-EIO);
+			}
+		}
+	}
+	if (mt_op == MTFSF) {
+		STp->frame_seq_number++;
+		STp->frame_in_buffer      = 0;
+		STp->buffer->buffer_bytes = 0;
+		STp->buffer->read_pointer = 0;
+		STp->logical_blk_num     += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
+	}
+	return 0;
+}
+
+/*
+ * In debug mode, we want to see as many errors as possible
+ * to test the error recovery mechanism.
+ */
+#if DEBUG
+static void osst_set_retries(struct osst_tape * STp, struct scsi_request ** aSRpnt, int retries)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt  = * aSRpnt;
+	char		      * name   = tape_name(STp);
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	(STp->buffer)->b_data[0] = cmd[4] - 1;
+	(STp->buffer)->b_data[1] = 0;			/* Medium Type - ignoring */
+	(STp->buffer)->b_data[2] = 0;			/* Reserved */
+	(STp->buffer)->b_data[3] = 0;			/* Block Descriptor Length */
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7);
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries;
+
+	if (debugging)
+	    printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries);
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
+	*aSRpnt = SRpnt;
+
+	if ((STp->buffer)->syscall_result)
+	    printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries);
+}
+#endif
+
+
+static int osst_write_filemark(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	int	result;
+	int	this_mark_ppos = STp->first_frame_position;
+	int	this_mark_lbn  = STp->logical_blk_num;
+#if DEBUG
+	char  * name = tape_name(STp);
+#endif
+
+	if (STp->raw) return 0;
+
+	STp->write_type = OS_WRITE_NEW_MARK;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", 
+	       name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn);
+#endif
+	STp->dirty = 1;
+	result  = osst_flush_write_buffer(STp, aSRpnt);
+	result |= osst_flush_drive_buffer(STp, aSRpnt);
+	STp->last_mark_ppos = this_mark_ppos;
+	STp->last_mark_lbn  = this_mark_lbn;
+	if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX)
+		STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos);
+	if (STp->filemark_cnt++ == 0)
+		STp->first_mark_ppos = this_mark_ppos;
+	return result;
+}
+
+static int osst_write_eod(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	int	result;
+#if DEBUG
+	char  * name = tape_name(STp);
+#endif
+
+	if (STp->raw) return 0;
+
+	STp->write_type = OS_WRITE_EOD;
+	STp->eod_frame_ppos = STp->first_frame_position;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name,
+			STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num);
+#endif
+	STp->dirty = 1;
+
+	result  = osst_flush_write_buffer(STp, aSRpnt);	
+	result |= osst_flush_drive_buffer(STp, aSRpnt);
+	STp->eod_frame_lfa = --(STp->frame_seq_number);
+	return result;
+}
+
+static int osst_write_filler(struct osst_tape * STp, struct scsi_request ** aSRpnt, int where, int count)
+{
+	char * name = tape_name(STp);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
+#endif
+	osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
+	osst_set_frame_position(STp, aSRpnt, where, 0);
+	STp->write_type = OS_WRITE_FILLER;
+	while (count--) {
+		memcpy(STp->buffer->b_data, "Filler", 6);
+		STp->buffer->buffer_bytes = 6;
+		STp->dirty = 1;
+		if (osst_flush_write_buffer(STp, aSRpnt)) {
+			printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name);
+			return (-EIO);
+		}
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name);
+#endif
+	return osst_flush_drive_buffer(STp, aSRpnt);
+}
+
+static int __osst_write_header(struct osst_tape * STp, struct scsi_request ** aSRpnt, int where, int count)
+{
+	char * name = tape_name(STp);
+	int     result;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
+#endif
+	osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
+	osst_set_frame_position(STp, aSRpnt, where, 0);
+	STp->write_type = OS_WRITE_HEADER;
+	while (count--) {
+		osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache);
+		STp->buffer->buffer_bytes = sizeof(os_header_t);
+		STp->dirty = 1;
+		if (osst_flush_write_buffer(STp, aSRpnt)) {
+			printk(KERN_INFO "%s:I: Couldn't write header frame\n", name);
+			return (-EIO);
+		}
+	}
+	result = osst_flush_drive_buffer(STp, aSRpnt);
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done");
+#endif
+	return result;
+}
+
+static int osst_write_header(struct osst_tape * STp, struct scsi_request ** aSRpnt, int locate_eod)
+{
+	os_header_t * header;
+	int	      result;
+	char        * name = tape_name(STp);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name);
+#endif
+	if (STp->raw) return 0;
+
+	if (STp->header_cache == NULL) {
+		if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+			printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
+			return (-ENOMEM);
+		}
+		memset(STp->header_cache, 0, sizeof(os_header_t));
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name);
+#endif
+	}
+	if (STp->header_ok) STp->update_frame_cntr++;
+	else                STp->update_frame_cntr = 0;
+
+	header = STp->header_cache;
+	strcpy(header->ident_str, "ADR_SEQ");
+	header->major_rev      = 1;
+	header->minor_rev      = 4;
+	header->ext_trk_tb_off = htons(17192);
+	header->pt_par_num     = 1;
+	header->partition[0].partition_num              = OS_DATA_PARTITION;
+	header->partition[0].par_desc_ver               = OS_PARTITION_VERSION;
+	header->partition[0].wrt_pass_cntr              = htons(STp->wrt_pass_cntr);
+	header->partition[0].first_frame_ppos           = htonl(STp->first_data_ppos);
+	header->partition[0].last_frame_ppos            = htonl(STp->capacity);
+	header->partition[0].eod_frame_ppos             = htonl(STp->eod_frame_ppos);
+	header->cfg_col_width                           = htonl(20);
+	header->dat_col_width                           = htonl(1500);
+	header->qfa_col_width                           = htonl(0);
+	header->ext_track_tb.nr_stream_part             = 1;
+	header->ext_track_tb.et_ent_sz                  = 32;
+	header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0;
+	header->ext_track_tb.dat_ext_trk_ey.fmt         = 1;
+	header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  = htons(17736);
+	header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0;
+	header->ext_track_tb.dat_ext_trk_ey.last_hlb    = htonl(STp->eod_frame_lfa);
+	header->ext_track_tb.dat_ext_trk_ey.last_pp	= htonl(STp->eod_frame_ppos);
+	header->dat_fm_tab.fm_part_num                  = 0;
+	header->dat_fm_tab.fm_tab_ent_sz                = 4;
+	header->dat_fm_tab.fm_tab_ent_cnt               = htons(STp->filemark_cnt<OS_FM_TAB_MAX?
+								STp->filemark_cnt:OS_FM_TAB_MAX);
+
+	result  = __osst_write_header(STp, aSRpnt, 0xbae, 5);
+	if (STp->update_frame_cntr == 0)
+		    osst_write_filler(STp, aSRpnt, 0xbb3, 5);
+	result &= __osst_write_header(STp, aSRpnt,     5, 5);
+
+	if (locate_eod) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos);
+#endif
+		osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0);
+	}
+	if (result)
+		printk(KERN_ERR "%s:E: Write header failed\n", name);
+	else {
+		memcpy(STp->application_sig, "LIN4", 4);
+		STp->linux_media         = 1;
+		STp->linux_media_version = 4;
+		STp->header_ok           = 1;
+	}
+	return result;
+}
+
+static int osst_reset_header(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	if (STp->header_cache != NULL)
+		memset(STp->header_cache, 0, sizeof(os_header_t));
+
+	STp->logical_blk_num = STp->frame_seq_number = 0;
+	STp->frame_in_buffer = 0;
+	STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A;
+	STp->filemark_cnt = 0;
+	STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
+	return osst_write_header(STp, aSRpnt, 1);
+}
+
+static int __osst_analyze_headers(struct osst_tape * STp, struct scsi_request ** aSRpnt, int ppos)
+{
+	char        * name = tape_name(STp);
+	os_header_t * header;
+	os_aux_t    * aux;
+	char          id_string[8];
+	int	      linux_media_version,
+		      update_frame_cntr;
+
+	if (STp->raw)
+		return 1;
+
+	if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) {
+		if (osst_set_frame_position(STp, aSRpnt, ppos, 0))
+			printk(KERN_WARNING "%s:W: Couldn't position tape\n", name);
+		osst_wait_ready(STp, aSRpnt, 60 * 15, 0);
+		if (osst_initiate_read (STp, aSRpnt)) {
+			printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name);
+			return 0;
+		}
+	}
+	if (osst_read_frame(STp, aSRpnt, 180)) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name);
+#endif
+		return 0;
+	}
+	header = (os_header_t *) STp->buffer->b_data;	/* warning: only first segment addressable */
+	aux = STp->buffer->aux;
+	if (aux->frame_type != OS_FRAME_TYPE_HEADER) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos);
+#endif
+		return 0;
+	}
+	if (ntohl(aux->frame_seq_num)              != 0                   ||
+	    ntohl(aux->logical_blk_num)            != 0                   ||
+	          aux->partition.partition_num     != OS_CONFIG_PARTITION ||
+	    ntohl(aux->partition.first_frame_ppos) != 0                   ||
+	    ntohl(aux->partition.last_frame_ppos)  != 0xbb7               ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name,
+				ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num),
+			       	aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos),
+			       	ntohl(aux->partition.last_frame_ppos));
+#endif
+		return 0;
+	}
+	if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 &&
+	    strncmp(header->ident_str, "ADR-SEQ", 7) != 0) {
+		strlcpy(id_string, header->ident_str, 8);
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string);
+#endif
+		return 0;
+	}
+	update_frame_cntr = ntohl(aux->update_frame_cntr);
+	if (update_frame_cntr < STp->update_frame_cntr) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n",
+				   name, ppos, update_frame_cntr, STp->update_frame_cntr);
+#endif
+		return 0;
+	}
+	if (header->major_rev != 1 || header->minor_rev != 4 ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", 
+				 name, (header->major_rev != 1 || header->minor_rev < 2 || 
+				       header->minor_rev  > 4 )? "Invalid" : "Warning:",
+				 header->major_rev, header->minor_rev);
+#endif
+		if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4)
+			return 0;
+	}
+#if DEBUG
+	if (header->pt_par_num != 1)
+		printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", 
+				 name, header->pt_par_num);
+#endif
+	memcpy(id_string, aux->application_sig, 4);
+	id_string[4] = 0;
+	if (memcmp(id_string, "LIN", 3) == 0) {
+		STp->linux_media = 1;
+		linux_media_version = id_string[3] - '0';
+		if (linux_media_version != 4)
+			printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n",
+					 name, linux_media_version);
+	} else {
+		printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string);
+		return 0;
+	}
+	if (linux_media_version < STp->linux_media_version) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n",
+				  name, ppos, linux_media_version);
+#endif
+		return 0;
+	}
+	if (linux_media_version > STp->linux_media_version) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n",
+				   name, ppos, linux_media_version);
+#endif
+		memcpy(STp->application_sig, id_string, 5);
+		STp->linux_media_version = linux_media_version;
+		STp->update_frame_cntr = -1;
+	}
+	if (update_frame_cntr > STp->update_frame_cntr) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n",
+				   name, ppos, update_frame_cntr);
+#endif
+		if (STp->header_cache == NULL) {
+			if ((STp->header_cache = (os_header_t *)vmalloc(sizeof(os_header_t))) == NULL) {
+				printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name);
+				return 0;
+			}
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name);
+#endif
+		}
+		osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache);
+		header = STp->header_cache;	/* further accesses from cached (full) copy */
+
+		STp->wrt_pass_cntr     = ntohs(header->partition[0].wrt_pass_cntr);
+		STp->first_data_ppos   = ntohl(header->partition[0].first_frame_ppos);
+		STp->eod_frame_ppos    = ntohl(header->partition[0].eod_frame_ppos);
+		STp->eod_frame_lfa     = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb);
+		STp->filemark_cnt      = ntohl(aux->filemark_cnt);
+		STp->first_mark_ppos   = ntohl(aux->next_mark_ppos);
+		STp->last_mark_ppos    = ntohl(aux->last_mark_ppos);
+		STp->last_mark_lbn     = ntohl(aux->last_mark_lbn);
+		STp->update_frame_cntr = update_frame_cntr;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n",
+			  name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt);
+	printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name,
+			  STp->first_data_ppos,
+			  ntohl(header->partition[0].last_frame_ppos),
+			  ntohl(header->partition[0].eod_frame_ppos));
+	printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", 
+			  name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos);
+#endif
+		if (header->minor_rev < 4 && STp->linux_media_version == 4) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name);
+#endif
+			memcpy((void *)header->dat_fm_tab.fm_tab_ent, 
+			       (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent));
+			memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list));
+		}
+		if (header->minor_rev == 4   &&
+		    (header->ext_trk_tb_off                          != htons(17192)               ||
+		     header->partition[0].partition_num              != OS_DATA_PARTITION          ||
+		     header->partition[0].par_desc_ver               != OS_PARTITION_VERSION       ||
+		     header->partition[0].last_frame_ppos            != htonl(STp->capacity)       ||
+		     header->cfg_col_width                           != htonl(20)                  ||
+		     header->dat_col_width                           != htonl(1500)                ||
+		     header->qfa_col_width                           != htonl(0)                   ||
+		     header->ext_track_tb.nr_stream_part             != 1                          ||
+		     header->ext_track_tb.et_ent_sz                  != 32                         ||
+		     header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION          ||
+		     header->ext_track_tb.dat_ext_trk_ey.fmt         != 1                          ||
+		     header->ext_track_tb.dat_ext_trk_ey.fm_tab_off  != htons(17736)               ||
+		     header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0                          ||
+		     header->ext_track_tb.dat_ext_trk_ey.last_pp     != htonl(STp->eod_frame_ppos) ||
+		     header->dat_fm_tab.fm_part_num                  != OS_DATA_PARTITION          ||
+		     header->dat_fm_tab.fm_tab_ent_sz                != 4                          ||
+		     header->dat_fm_tab.fm_tab_ent_cnt               !=
+			     htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX)))
+			printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name);
+
+	}
+
+	return 1;
+}
+
+static int osst_analyze_headers(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	int	position, ppos;
+	int	first, last;
+	int	valid = 0;
+	char  * name  = tape_name(STp);
+
+	position = osst_get_frame_position(STp, aSRpnt);
+
+	if (STp->raw) {
+		STp->header_ok = STp->linux_media = 1;
+		STp->linux_media_version = 0;
+		return 1;
+	}
+	STp->header_ok = STp->linux_media = STp->linux_media_version = 0;
+	STp->wrt_pass_cntr = STp->update_frame_cntr = -1;
+	STp->eod_frame_ppos = STp->first_data_ppos = -1;
+	STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reading header\n", name);
+#endif
+
+	/* optimization for speed - if we are positioned at ppos 10, read second group first  */	
+	/* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */
+
+	first = position==10?0xbae: 5;
+	last  = position==10?0xbb3:10;
+
+	for (ppos = first; ppos < last; ppos++)
+		if (__osst_analyze_headers(STp, aSRpnt, ppos))
+			valid = 1;
+
+	first = position==10? 5:0xbae;
+	last  = position==10?10:0xbb3;
+
+	for (ppos = first; ppos < last; ppos++)
+		if (__osst_analyze_headers(STp, aSRpnt, ppos))
+			valid = 1;
+
+	if (!valid) {
+		printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name);
+		STp->eod_frame_ppos = STp->first_data_ppos = 0;
+		osst_set_frame_position(STp, aSRpnt, 10, 0);
+		return 0;
+	}
+	if (position <= STp->first_data_ppos) {
+		position = STp->first_data_ppos;
+		STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
+	}
+	osst_set_frame_position(STp, aSRpnt, position, 0);
+	STp->header_ok = 1;
+
+	return 1;
+}
+
+static int osst_verify_position(struct osst_tape * STp, struct scsi_request ** aSRpnt)
+{
+	int	frame_position  = STp->first_frame_position;
+	int	frame_seq_numbr = STp->frame_seq_number;
+	int	logical_blk_num = STp->logical_blk_num;
+       	int	halfway_frame   = STp->frame_in_buffer;
+	int	read_pointer    = STp->buffer->read_pointer;
+	int	prev_mark_ppos  = -1;
+	int	actual_mark_ppos, i, n;
+#if DEBUG
+	char  * name = tape_name(STp);
+
+	printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name);
+#endif
+	osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
+	if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name);
+#endif
+		return (-EIO);
+	}
+	if (STp->linux_media_version >= 4) {
+		for (i=0; i<STp->filemark_cnt; i++)
+			if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position)
+				prev_mark_ppos = n;
+	} else
+		prev_mark_ppos = frame_position - 1;  /* usually - we don't really know */
+	actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ?
+				frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos);
+	if (frame_position  != STp->first_frame_position                   ||
+	    frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) ||
+	    prev_mark_ppos  != actual_mark_ppos                            ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name,
+				  STp->first_frame_position, frame_position, 
+				  STp->frame_seq_number + (halfway_frame?0:1),
+				  frame_seq_numbr, actual_mark_ppos, prev_mark_ppos);
+#endif
+		return (-EIO);
+	}
+	if (halfway_frame) {
+		/* prepare buffer for append and rewrite on top of original */
+		osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0);
+		STp->buffer->buffer_bytes  = read_pointer;
+		STp->ps[STp->partition].rw = ST_WRITING;
+		STp->dirty                 = 1;
+	}
+	STp->frame_in_buffer  = halfway_frame;
+	STp->frame_seq_number = frame_seq_numbr;
+	STp->logical_blk_num  = logical_blk_num;
+	return 0;
+}
+
+/* Acc. to OnStream, the vers. numbering is the following:
+ * X.XX for released versions (X=digit), 
+ * XXXY for unreleased versions (Y=letter)
+ * Ordering 1.05 < 106A < 106B < ...  < 106a < ... < 1.06
+ * This fn makes monoton numbers out of this scheme ...
+ */
+static unsigned int osst_parse_firmware_rev (const char * str)
+{
+	if (str[1] == '.') {
+		return (str[0]-'0')*10000
+			+(str[2]-'0')*1000
+			+(str[3]-'0')*100;
+	} else {
+		return (str[0]-'0')*10000
+			+(str[1]-'0')*1000
+			+(str[2]-'0')*100 - 100
+			+(str[3]-'@');
+	}
+}
+
+/*
+ * Configure the OnStream SCII tape drive for default operation
+ */
+static int osst_configure_onstream(struct osst_tape *STp, struct scsi_request ** aSRpnt)
+{
+	unsigned char                  cmd[MAX_COMMAND_SIZE];
+	char                         * name = tape_name(STp);
+	struct scsi_request                 * SRpnt = * aSRpnt;
+	osst_mode_parameter_header_t * header;
+	osst_block_size_page_t       * bs;
+	osst_capabilities_page_t     * cp;
+	osst_tape_paramtr_page_t     * prm;
+	int                            drive_buffer_size;
+
+	if (STp->ready != ST_READY) {
+#if DEBUG
+	    printk(OSST_DEB_MSG "%s:D: Not Ready\n", name);
+#endif
+	    return (-EIO);
+	}
+	
+	if (STp->os_fw_rev < 10600) {
+	    printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev);
+	    printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name);
+	}
+
+	/*
+	 * Configure 32.5KB (data+aux) frame size.
+         * Get the current frame size from the block size mode page
+	 */
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = BLOCK_SIZE_PAGE;
+	cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
+	if (SRpnt == NULL) {
+#if DEBUG
+ 	    printk(OSST_DEB_MSG "osst :D: Busy\n");
+#endif
+	    return (-EBUSY);
+	}
+	*aSRpnt = SRpnt;
+	if ((STp->buffer)->syscall_result != 0) {
+	    printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name);
+	    return (-EIO);
+	}
+
+	header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+	bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n",   name, bs->play32     ? "Yes" : "No");
+	printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5   ? "Yes" : "No");
+	printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n",      name, bs->record32   ? "Yes" : "No");
+	printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n",    name, bs->record32_5 ? "Yes" : "No");
+#endif
+
+	/*
+	 * Configure default auto columns mode, 32.5KB transfer mode
+	 */ 
+	bs->one = 1;
+	bs->play32 = 0;
+	bs->play32_5 = 1;
+	bs->record32 = 0;
+	bs->record32_5 = 1;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
+	*aSRpnt = SRpnt;
+	if ((STp->buffer)->syscall_result != 0) {
+	    printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name);
+	    return (-EIO);
+	}
+
+#if DEBUG
+	printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name);
+	 /*
+	 * In debug mode, we want to see as many errors as possible
+	 * to test the error recovery mechanism.
+	 */
+	osst_set_retries(STp, aSRpnt, 0);
+	SRpnt = * aSRpnt;
+#endif
+
+	/*
+	 * Set vendor name to 'LIN4' for "Linux support version 4".
+	 */
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = 0x10;
+	cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1;
+	header->medium_type      = 0;	/* Medium Type - ignoring */
+	header->dsp              = 0;	/* Reserved */
+	header->bdl              = 0;	/* Block Descriptor Length */
+	
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7);
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4';
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0;
+	(STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0;
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
+	*aSRpnt = SRpnt;
+
+	if ((STp->buffer)->syscall_result != 0) {
+	    printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, 
+			(char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2));
+	    return (-EIO);
+	}
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = CAPABILITIES_PAGE;
+	cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
+	*aSRpnt = SRpnt;
+
+	if ((STp->buffer)->syscall_result != 0) {
+	    printk (KERN_ERR "%s:E: Can't get capabilities page\n", name);
+	    return (-EIO);
+	}
+
+	header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+	cp     = (osst_capabilities_page_t    *) ((STp->buffer)->b_data +
+		 sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+	drive_buffer_size = ntohs(cp->buffer_size) / 2;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[1] = 8;
+	cmd[2] = TAPE_PARAMTR_PAGE;
+	cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
+	*aSRpnt = SRpnt;
+
+	if ((STp->buffer)->syscall_result != 0) {
+	    printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name);
+	    return (-EIO);
+	}
+
+	header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data;
+	prm    = (osst_tape_paramtr_page_t    *) ((STp->buffer)->b_data +
+		 sizeof(osst_mode_parameter_header_t) + header->bdl);
+
+	STp->density  = prm->density;
+	STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks);
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n",
+			  name, STp->density, STp->capacity / 32, drive_buffer_size);
+#endif
+
+	return 0;
+	
+}
+
+
+/* Step over EOF if it has been inadvertently crossed (ioctl not used because
+   it messes up the block number). */
+static int cross_eof(struct osst_tape *STp, struct scsi_request ** aSRpnt, int forward)
+{
+	int	result;
+	char  * name = tape_name(STp);
+
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n",
+	   			  name, forward ? "forward" : "backward");
+#endif
+
+	if (forward) {
+	   /* assumes that the filemark is already read by the drive, so this is low cost */
+	   result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1);
+	}
+	else
+	   /* assumes this is only called if we just read the filemark! */
+	   result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1);
+
+	if (result < 0)
+	   printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n",
+				name, forward ? "forward" : "backward");
+
+	return result;
+}
+
+
+/* Get the tape position. */
+
+static int osst_get_frame_position(struct osst_tape *STp, struct scsi_request ** aSRpnt)
+{
+	unsigned char		scmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	int			result = 0;
+	char    	      * name   = tape_name(STp);
+
+	/* KG: We want to be able to use it for checking Write Buffer availability
+	 *  and thus don't want to risk to overwrite anything. Exchange buffers ... */
+	char		mybuf[24];
+	char	      * olddata = STp->buffer->b_data;
+	int		oldsize = STp->buffer->buffer_size;
+
+	if (STp->ready != ST_READY) return (-EIO);
+
+	memset (scmd, 0, MAX_COMMAND_SIZE);
+	scmd[0] = READ_POSITION;
+
+	STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
+	SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
+				      STp->timeout, MAX_RETRIES, 1);
+	if (!SRpnt) {
+		STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
+		return (-EBUSY);
+	}
+	*aSRpnt = SRpnt;
+
+	if (STp->buffer->syscall_result)
+		result = ((SRpnt->sr_sense_buffer[2] & 0x0f) == 3) ? -EIO : -EINVAL;	/* 3: Write Error */
+
+	if (result == -EINVAL)
+		printk(KERN_ERR "%s:E: Can't read tape position.\n", name);
+	else {
+		if (result == -EIO) {	/* re-read position - this needs to preserve media errors */
+			unsigned char mysense[16];
+			memcpy (mysense, SRpnt->sr_sense_buffer, 16);
+			memset (scmd, 0, MAX_COMMAND_SIZE);
+			scmd[0] = READ_POSITION;
+			STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
+			SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE,
+						    STp->timeout, MAX_RETRIES, 1);
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n",
+					name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:",
+					SRpnt->sr_sense_buffer[2],SRpnt->sr_sense_buffer[12],SRpnt->sr_sense_buffer[13]);
+#endif
+			if (!STp->buffer->syscall_result)
+				memcpy (SRpnt->sr_sense_buffer, mysense, 16);
+			else
+				printk(KERN_WARNING "%s:W: Double error in get position\n", name);
+		}
+		STp->first_frame_position = ((STp->buffer)->b_data[4] << 24)
+					  + ((STp->buffer)->b_data[5] << 16)
+					  + ((STp->buffer)->b_data[6] << 8)
+					  +  (STp->buffer)->b_data[7];
+		STp->last_frame_position  = ((STp->buffer)->b_data[ 8] << 24)
+					  + ((STp->buffer)->b_data[ 9] << 16)
+					  + ((STp->buffer)->b_data[10] <<  8)
+					  +  (STp->buffer)->b_data[11];
+		STp->cur_frames           =  (STp->buffer)->b_data[15];
+#if DEBUG
+		if (debugging) {
+			printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name,
+					    STp->first_frame_position, STp->last_frame_position,
+					    ((STp->buffer)->b_data[0]&0x80)?" (BOP)":
+					    ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"",
+					    STp->cur_frames);
+		}
+#endif
+		if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name,
+					STp->first_frame_position, STp->last_frame_position, STp->cur_frames);
+#endif
+			STp->first_frame_position = STp->last_frame_position;
+		}
+	}
+	STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
+
+	return (result == 0 ? STp->first_frame_position : result);
+}
+
+
+/* Set the tape block */
+static int osst_set_frame_position(struct osst_tape *STp, struct scsi_request ** aSRpnt, int ppos, int skip)
+{
+	unsigned char		scmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	struct st_partstat    * STps;
+	int			result = 0;
+	int			pp     = (ppos == 3000 && !skip)? 0 : ppos;
+	char		      * name   = tape_name(STp);
+
+	if (STp->ready != ST_READY) return (-EIO);
+
+	STps = &(STp->ps[STp->partition]);
+
+	if (ppos < 0 || ppos > STp->capacity) {
+		printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos);
+		pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1);
+		result = (-EINVAL);
+	}
+
+	do {
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp);
+#endif
+		memset (scmd, 0, MAX_COMMAND_SIZE);
+		scmd[0] = SEEK_10;
+		scmd[1] = 1;
+		scmd[3] = (pp >> 24);
+		scmd[4] = (pp >> 16);
+		scmd[5] = (pp >> 8);
+		scmd[6] =  pp;
+		if (skip)
+			scmd[9] = 0x80;
+
+		SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout,
+								MAX_RETRIES, 1);
+		if (!SRpnt)
+			return (-EBUSY);
+		*aSRpnt  = SRpnt;
+
+		if ((STp->buffer)->syscall_result != 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n",
+					name, STp->first_frame_position, pp);
+#endif
+			result = (-EIO);
+		}
+		if (pp != ppos)
+			osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
+	} while ((pp != ppos) && (pp = ppos));
+	STp->first_frame_position = STp->last_frame_position = ppos;
+	STps->eof = ST_NOEOF;
+	STps->at_sm = 0;
+	STps->rw = ST_IDLE;
+	STp->frame_in_buffer = 0;
+	return result;
+}
+
+static int osst_write_trailer(struct osst_tape *STp, struct scsi_request ** aSRpnt, int leave_at_EOT)
+{
+	struct st_partstat * STps = &(STp->ps[STp->partition]);
+	int result = 0;
+
+	if (STp->write_type != OS_WRITE_NEW_MARK) {
+		/* true unless the user wrote the filemark for us */
+		result = osst_flush_drive_buffer(STp, aSRpnt);
+		if (result < 0) goto out;
+		result = osst_write_filemark(STp, aSRpnt);
+		if (result < 0) goto out;
+
+		if (STps->drv_file >= 0)
+			STps->drv_file++ ;
+		STps->drv_block = 0;
+	}
+	result = osst_write_eod(STp, aSRpnt);
+	osst_write_header(STp, aSRpnt, leave_at_EOT);
+
+	STps->eof = ST_FM;
+out:
+	return result;
+}
+
+/* osst versions of st functions - augmented and stripped to suit OnStream only */
+
+/* Flush the write buffer (never need to write if variable blocksize). */
+static int osst_flush_write_buffer(struct osst_tape *STp, struct scsi_request ** aSRpnt)
+{
+	int			offset, transfer, blks = 0;
+	int			result = 0;
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt = *aSRpnt;
+	struct st_partstat    * STps;
+	char		      * name = tape_name(STp);
+
+	if ((STp->buffer)->writing) {
+		if (SRpnt == (STp->buffer)->last_SRpnt)
+#if DEBUG
+			{ printk(OSST_DEB_MSG
+	 "%s:D: aSRpnt points to scsi_request that write_behind_check will release -- cleared\n", name);
+#endif
+			*aSRpnt = SRpnt = NULL;
+#if DEBUG
+			} else if (SRpnt)
+				printk(OSST_DEB_MSG
+	 "%s:D: aSRpnt does not point to scsi_request that write_behind_check will release -- strange\n", name);
+#endif	
+		osst_write_behind_check(STp);
+		if ((STp->buffer)->syscall_result) {
+#if DEBUG
+			if (debugging)
+				printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n",
+				       name, (STp->buffer)->midlevel_result);
+#endif
+			if ((STp->buffer)->midlevel_result == INT_MAX)
+				return (-ENOSPC);
+			return (-EIO);
+		}
+	}
+
+	result = 0;
+	if (STp->dirty == 1) {
+
+		STp->write_count++;
+		STps     = &(STp->ps[STp->partition]);
+		STps->rw = ST_WRITING;
+		offset   = STp->buffer->buffer_bytes;
+		blks     = (offset + STp->block_size - 1) / STp->block_size;
+		transfer = OS_FRAME_SIZE;
+		
+		if (offset < OS_DATA_SIZE)
+			osst_zero_buffer_tail(STp->buffer);
+
+		if (STp->poll)
+			if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120))
+				result = osst_recover_wait_frame(STp, aSRpnt, 1);
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_6;
+		cmd[1] = 1;
+		cmd[4] = 1;
+
+		switch	(STp->write_type) {
+		   case OS_WRITE_DATA:
+#if DEBUG
+   			if (debugging)
+				printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n",
+					name, blks, STp->frame_seq_number, 
+					STp->logical_blk_num - blks, STp->logical_blk_num - 1);
+#endif
+			osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
+				      STp->logical_blk_num - blks, STp->block_size, blks);
+			break;
+		   case OS_WRITE_EOD:
+			osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++,
+				      STp->logical_blk_num, 0, 0);
+			break;
+		   case OS_WRITE_NEW_MARK:
+			osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++,
+				      STp->logical_blk_num++, 0, blks=1);
+			break;
+		   case OS_WRITE_HEADER:
+			osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0);
+			break;
+		default: /* probably FILLER */
+			osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0);
+		}
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transfering %d bytes in %d lblocks.\n",
+			  			 name, offset, transfer, blks);
+#endif
+
+		SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
+					      STp->timeout, MAX_RETRIES, 1);
+		*aSRpnt = SRpnt;
+		if (!SRpnt)
+			return (-EBUSY);
+
+		if ((STp->buffer)->syscall_result != 0) {
+#if DEBUG
+			printk(OSST_DEB_MSG
+				"%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n",
+				name, SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[2],
+				SRpnt->sr_sense_buffer[12], SRpnt->sr_sense_buffer[13]);
+#endif
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+			    (SRpnt->sr_sense_buffer[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */
+			    (SRpnt->sr_sense_buffer[2] & 0x0f) == NO_SENSE) {
+				STp->dirty = 0;
+				(STp->buffer)->buffer_bytes = 0;
+				result = (-ENOSPC);
+			}
+			else {
+				if (osst_write_error_recovery(STp, aSRpnt, 1)) {
+					printk(KERN_ERR "%s:E: Error on flush write.\n", name);
+					result = (-EIO);
+				}
+			}
+			STps->drv_block = (-1);		/* FIXME - even if write recovery succeeds? */
+		}
+		else {
+			STp->first_frame_position++;
+			STp->dirty = 0;
+			(STp->buffer)->buffer_bytes = 0;
+		}
+	}
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result);
+#endif
+	return result;
+}
+
+
+/* Flush the tape buffer. The tape will be positioned correctly unless
+   seek_next is true. */
+static int osst_flush_buffer(struct osst_tape * STp, struct scsi_request ** aSRpnt, int seek_next)
+{
+	struct st_partstat * STps;
+	int    backspace = 0, result = 0;
+#if DEBUG
+	char * name = tape_name(STp);
+#endif
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if( STp->pos_unknown)
+		return (-EIO);
+
+	if (STp->ready != ST_READY)
+		return 0;
+
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING || STp->dirty) {	/* Writing */
+		STp->write_type = OS_WRITE_DATA;
+		return osst_flush_write_buffer(STp, aSRpnt);
+	}
+	if (STp->block_size == 0)
+		return 0;
+
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name);
+#endif
+
+	if (!STp->can_bsr) {
+		backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size -
+			    ((STp->buffer)->read_pointer + STp->block_size - 1        ) / STp->block_size ;
+		(STp->buffer)->buffer_bytes = 0;
+		(STp->buffer)->read_pointer = 0;
+		STp->frame_in_buffer = 0;		/* FIXME is this relevant w. OSST? */
+	}
+
+	if (!seek_next) {
+		if (STps->eof == ST_FM_HIT) {
+			result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */
+			if (!result)
+				STps->eof = ST_NOEOF;
+			else {
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+			}
+		}
+		if (!result && backspace > 0)	/* TODO -- design and run a test case for this */
+			result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace);
+	}
+	else if (STps->eof == ST_FM_HIT) {
+		if (STps->drv_file >= 0)
+			STps->drv_file++;
+		STps->drv_block = 0;
+		STps->eof = ST_NOEOF;
+	}
+
+	return result;
+}
+
+static int osst_write_frame(struct osst_tape * STp, struct scsi_request ** aSRpnt, int synchronous)
+{
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt;
+	int			blks;
+#if DEBUG
+	char		      * name = tape_name(STp);
+#endif
+
+	if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name);
+#endif
+		if (osst_flush_drive_buffer(STp, aSRpnt) < 0) {
+			return (-EIO);
+		}
+		/* error recovery may have bumped us past the header partition */
+		if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name);
+#endif
+		osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8);
+		}
+	}
+
+	if (STp->poll)
+		if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120))
+			if (osst_recover_wait_frame(STp, aSRpnt, 1))
+				return (-EIO);
+
+//	osst_build_stats(STp, &SRpnt);
+
+	STp->ps[STp->partition].rw = ST_WRITING;
+	STp->write_type            = OS_WRITE_DATA;
+			
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0]   = WRITE_6;
+	cmd[1]   = 1;
+	cmd[4]   = 1;						/* one frame at a time... */
+	blks     = STp->buffer->buffer_bytes / STp->block_size;
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, 
+			STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1);
+#endif
+	osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++,
+		      STp->logical_blk_num - blks, STp->block_size, blks);
+
+#if DEBUG
+	if (!synchronous)
+		STp->write_pending = 1;
+#endif
+	SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout,
+									MAX_RETRIES, synchronous);
+	if (!SRpnt)
+		return (-EBUSY);
+	*aSRpnt = SRpnt;
+
+	if (synchronous) {
+		if (STp->buffer->syscall_result != 0) {
+#if DEBUG
+			if (debugging)
+				printk(OSST_DEB_MSG "%s:D: Error on write:\n", name);
+#endif
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+			    (SRpnt->sr_sense_buffer[2] & 0x40)) {
+				if ((SRpnt->sr_sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
+					return (-ENOSPC);
+			}
+			else {
+				if (osst_write_error_recovery(STp, aSRpnt, 1))
+					return (-EIO);
+			}
+		}
+		else
+			STp->first_frame_position++;
+	}
+
+	STp->write_count++;
+
+	return 0;
+}
+
+/* Lock or unlock the drive door. Don't use when struct scsi_request allocated. */
+static int do_door_lock(struct osst_tape * STp, int do_lock)
+{
+	int retval, cmd;
+
+	cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
+#endif
+	retval = scsi_ioctl(STp->device, cmd, NULL);
+	if (!retval) {
+		STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
+	}
+	else {
+		STp->door_locked = ST_LOCK_FAILS;
+	}
+	return retval;
+}
+
+/* Set the internal state after reset */
+static void reset_state(struct osst_tape *STp)
+{
+	int i;
+	struct st_partstat *STps;
+
+	STp->pos_unknown = 0;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = 0;
+		STps->drv_block = -1;
+		STps->drv_file = -1;
+	}
+}
+				
+
+/* Entry points to osst */
+
+/* Write command */
+static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos)
+{
+	ssize_t		      total, retval = 0;
+	ssize_t		      i, do_count, blks, transfer;
+	int		      write_threshold;
+	int		      doing_write = 0;
+	const char   __user * b_point;
+	struct scsi_request * SRpnt = NULL;
+	struct st_modedef   * STm;
+	struct st_partstat  * STps;
+	struct osst_tape    * STp  = filp->private_data;
+	char		    * name = tape_name(STp);
+
+
+	if (down_interruptible(&STp->lock))
+		return (-ERESTARTSYS);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if( !scsi_block_when_processing_errors(STp->device) ) {
+		retval = (-ENXIO);
+		goto out;
+	}
+	
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			retval = (-ENOMEDIUM);
+		else
+			retval = (-EIO);
+		goto out;
+	}
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
+	if (count == 0)
+		goto out;
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if (STp->pos_unknown) {
+		retval = (-EIO);
+		goto out;
+	}
+
+#if DEBUG
+	if (!STp->in_use) {
+		printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
+		retval = (-EIO);
+		goto out;
+	}
+#endif
+
+	if (STp->write_prot) {
+		retval = (-EACCES);
+		goto out;
+	}
+
+	/* Write must be integral number of blocks */
+	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+		printk(KERN_ERR "%s:E: Write (%Zd bytes) not multiple of tape block size (%d%c).\n",
+				       name, count, STp->block_size<1024?
+				       STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
+		retval = (-EINVAL);
+		goto out;
+	}
+
+	if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) {
+		printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n",
+				       name, STp->first_frame_position);
+		retval = (-ENOSPC);
+		goto out;
+	}
+
+	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
+		STp->door_locked = ST_LOCKED_AUTO;
+
+	STps = &(STp->ps[STp->partition]);
+
+	if (STps->rw == ST_READING) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, 
+					STps->drv_file, STps->drv_block);
+#endif
+		retval = osst_flush_buffer(STp, &SRpnt, 0);
+		if (retval)
+			goto out;
+		STps->rw = ST_IDLE;
+	}
+	if (STps->rw != ST_WRITING) {
+		/* Are we totally rewriting this tape? */
+		if (!STp->header_ok ||
+		    (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
+		    (STps->drv_file == 0 && STps->drv_block == 0)) {
+			STp->wrt_pass_cntr++;
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n",
+						  name, STp->wrt_pass_cntr);
+#endif
+			osst_reset_header(STp, &SRpnt);
+			STps->drv_file = STps->drv_block = 0;
+		}
+		/* Do we know where we'll be writing on the tape? */
+		else {
+			if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) ||
+			  		STps->drv_file < 0 || STps->drv_block < 0) {
+				if (STp->first_frame_position == STp->eod_frame_ppos) {	/* at EOD */
+			  		STps->drv_file = STp->filemark_cnt;
+			  		STps->drv_block = 0;
+				}
+				else {
+					/* We have no idea where the tape is positioned - give up */
+#if DEBUG
+					printk(OSST_DEB_MSG
+						"%s:D: Cannot write at indeterminate position.\n", name);
+#endif
+					retval = (-EIO);
+					goto out;
+				}
+      			}	  
+			if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) {
+				STp->filemark_cnt = STps->drv_file;
+				STp->last_mark_ppos =
+				       	ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]);
+				printk(KERN_WARNING
+					"%s:W: Overwriting file %d with old write pass counter %d\n",
+						name, STps->drv_file, STp->wrt_pass_cntr);
+				printk(KERN_WARNING
+					"%s:W: may lead to stale data being accepted on reading back!\n",
+						name);
+#if DEBUG
+				printk(OSST_DEB_MSG
+				  "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n",
+					name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn);
+#endif
+			}
+		}
+		STp->fast_open = 0;
+	}
+	if (!STp->header_ok) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name);
+#endif
+		retval = (-EIO);
+		goto out;
+	}
+
+	if ((STp->buffer)->writing) {
+if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__);
+		osst_write_behind_check(STp);
+		if ((STp->buffer)->syscall_result) {
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name,
+						 (STp->buffer)->midlevel_result);
+#endif
+		if ((STp->buffer)->midlevel_result == INT_MAX)
+			STps->eof = ST_EOM_OK;
+		else
+			STps->eof = ST_EOM_ERROR;
+		}
+	}
+	if (STps->eof == ST_EOM_OK) {
+		retval = (-ENOSPC);
+		goto out;
+	}
+	else if (STps->eof == ST_EOM_ERROR) {
+		retval = (-EIO);
+		goto out;
+	}
+
+	/* Check the buffer readability in cases where copy_user might catch
+		 the problems after some tape movement. */
+	if ((copy_from_user(&i, buf, 1) != 0 ||
+	     copy_from_user(&i, buf + count - 1, 1) != 0)) {
+		retval = (-EFAULT);
+		goto out;
+	}
+
+	if (!STm->do_buffer_writes) {
+		write_threshold = 1;
+	}
+	else
+		write_threshold = (STp->buffer)->buffer_blocks * STp->block_size;
+	if (!STm->do_async_writes)
+		write_threshold--;
+
+	total = count;
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n",
+				name, count, STps->drv_file, STps->drv_block,
+				STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position);
+#endif
+	b_point = buf;
+	while ((STp->buffer)->buffer_bytes + count > write_threshold)
+	{
+		doing_write = 1;
+		do_count = (STp->buffer)->buffer_blocks * STp->block_size -
+			   (STp->buffer)->buffer_bytes;
+		if (do_count > count)
+			do_count = count;
+
+		i = append_to_buffer(b_point, STp->buffer, do_count);
+		if (i) {
+			retval = i;
+			goto out;
+		}
+
+		blks = do_count / STp->block_size;
+		STp->logical_blk_num += blks;  /* logical_blk_num is incremented as data is moved from user */
+  
+		i = osst_write_frame(STp, &SRpnt, 1);
+
+		if (i == (-ENOSPC)) {
+			transfer = STp->buffer->writing;	/* FIXME -- check this logic */
+			if (transfer <= do_count) {
+				filp->f_pos += do_count - transfer;
+				count -= do_count - transfer;
+				if (STps->drv_block >= 0) {
+					STps->drv_block += (do_count - transfer) / STp->block_size;
+				}
+				STps->eof = ST_EOM_OK;
+				retval = (-ENOSPC);		/* EOM within current request */
+#if DEBUG
+				if (debugging)
+				      printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n",
+							     name, transfer);
+#endif
+			}
+			else {
+				STps->eof = ST_EOM_ERROR;
+				STps->drv_block = (-1);		/* Too cautious? */
+				retval = (-EIO);		/* EOM for old data */
+#if DEBUG
+				if (debugging)
+				      printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name);
+#endif
+			}
+		}
+		else
+			retval = i;
+			
+		if (retval < 0) {
+			if (SRpnt != NULL) {
+				scsi_release_request(SRpnt);
+				SRpnt = NULL;
+			}
+			STp->buffer->buffer_bytes = 0;
+			STp->dirty = 0;
+			if (count < total)
+				retval = total - count;
+			goto out;
+		}
+
+		filp->f_pos += do_count;
+		b_point += do_count;
+		count -= do_count;
+		if (STps->drv_block >= 0) {
+			STps->drv_block += blks;
+		}
+		STp->buffer->buffer_bytes = 0;
+		STp->dirty = 0;
+	}  /* end while write threshold exceeded */
+
+	if (count != 0) {
+		STp->dirty = 1;
+		i = append_to_buffer(b_point, STp->buffer, count);
+		if (i) {
+			retval = i;
+			goto out;
+		}
+		blks = count / STp->block_size;
+		STp->logical_blk_num += blks;
+		if (STps->drv_block >= 0) {
+			STps->drv_block += blks;
+		}
+		filp->f_pos += count;
+		count = 0;
+	}
+
+	if (doing_write && (STp->buffer)->syscall_result != 0) {
+		retval = (STp->buffer)->syscall_result;
+		goto out;
+	}
+
+	if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { 
+		/* Schedule an asynchronous write */
+		(STp->buffer)->writing = ((STp->buffer)->buffer_bytes /
+					   STp->block_size) * STp->block_size;
+		STp->dirty = !((STp->buffer)->writing ==
+				          (STp->buffer)->buffer_bytes);
+
+		i = osst_write_frame(STp, &SRpnt, 0);
+		if (i < 0) {
+			retval = (-EIO);
+			goto out;
+		}
+		SRpnt = NULL;			/* Prevent releasing this request! */
+	}
+	STps->at_sm &= (total == 0);
+	if (total > 0)
+		STps->eof = ST_NOEOF;
+
+	retval = total;
+
+out:
+	if (SRpnt != NULL) scsi_release_request(SRpnt);
+
+	up(&STp->lock);
+
+	return retval;
+}
+
+
+/* Read command */
+static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos)
+{
+	ssize_t		      total, retval = 0;
+	ssize_t		      i, transfer;
+	int		      special;
+	struct st_modedef   * STm;
+	struct st_partstat  * STps;
+	struct scsi_request * SRpnt = NULL;
+	struct osst_tape    * STp   = filp->private_data;
+	char		    * name  = tape_name(STp);
+
+
+	if (down_interruptible(&STp->lock))
+		return (-ERESTARTSYS);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if( !scsi_block_when_processing_errors(STp->device) ) {
+		retval = (-ENXIO);
+		goto out;
+	}
+	
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			retval = (-ENOMEDIUM);
+		else
+			retval = (-EIO);
+		goto out;
+	}
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
+#if DEBUG
+	if (!STp->in_use) {
+		printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
+		retval = (-EIO);
+		goto out;
+	}
+#endif
+	/* Must have initialized medium */
+	if (!STp->header_ok) {
+		retval = (-EIO);
+		goto out;
+	}
+
+	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
+		STp->door_locked = ST_LOCKED_AUTO;
+
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING) {
+		retval = osst_flush_buffer(STp, &SRpnt, 0);
+		if (retval)
+			goto out;
+		STps->rw = ST_IDLE;
+		/* FIXME -- this may leave the tape without EOD and up2date headers */
+	}
+
+	if ((count % STp->block_size) != 0) {
+		printk(KERN_WARNING
+		    "%s:W: Read (%Zd bytes) not multiple of tape block size (%d%c).\n", name, count,
+		    STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k');
+	}
+
+#if DEBUG
+	if (debugging && STps->eof != ST_NOEOF)
+		printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name,
+				     STps->eof, (STp->buffer)->buffer_bytes);
+#endif
+	if ((STp->buffer)->buffer_bytes == 0 &&
+	     STps->eof >= ST_EOD_1) {
+		if (STps->eof < ST_EOD) {
+			STps->eof += 1;
+			retval = 0;
+			goto out;
+		}
+		retval = (-EIO);  /* EOM or Blank Check */
+		goto out;
+	}
+
+	/* Check the buffer writability before any tape movement. Don't alter
+		 buffer data. */
+	if (copy_from_user(&i, buf, 1)             != 0 ||
+	    copy_to_user  (buf, &i, 1)             != 0 ||
+	    copy_from_user(&i, buf + count - 1, 1) != 0 ||
+	    copy_to_user  (buf + count - 1, &i, 1) != 0) {
+		retval = (-EFAULT);
+		goto out;
+	}
+
+	/* Loop until enough data in buffer or a special condition found */
+	for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) {
+
+		/* Get new data if the buffer is empty */
+		if ((STp->buffer)->buffer_bytes == 0) {
+			if (STps->eof == ST_FM_HIT)
+				break;
+			special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0);
+			if (special < 0) { 			/* No need to continue read */
+				STp->frame_in_buffer = 0;
+				retval = special;
+				goto out;
+			}
+		}
+
+		/* Move the data from driver buffer to user buffer */
+		if ((STp->buffer)->buffer_bytes > 0) {
+#if DEBUG
+			if (debugging && STps->eof != ST_NOEOF)
+			    printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
+						 STps->eof, (STp->buffer)->buffer_bytes, count - total);
+#endif
+		       	/* force multiple of block size, note block_size may have been adjusted */
+			transfer = (((STp->buffer)->buffer_bytes < count - total ?
+				     (STp->buffer)->buffer_bytes : count - total)/
+					STp->block_size) * STp->block_size;
+
+			if (transfer == 0) {
+				printk(KERN_WARNING
+				  "%s:W: Nothing can be transfered, requested %Zd, tape block size (%d%c).\n",
+			   		name, count, STp->block_size < 1024?
+					STp->block_size:STp->block_size/1024,
+				       	STp->block_size<1024?'b':'k');
+				break;
+			}
+			i = from_buffer(STp->buffer, buf, transfer);
+			if (i)  {
+				retval = i;
+				goto out;
+			}
+			STp->logical_blk_num += transfer / STp->block_size;
+			STps->drv_block      += transfer / STp->block_size;
+			filp->f_pos          += transfer;
+			buf                  += transfer;
+			total                += transfer;
+		}
+ 
+		if ((STp->buffer)->buffer_bytes == 0) {
+#if DEBUG
+			if (debugging)
+				printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n",
+					       	name, STp->frame_seq_number);
+#endif
+			STp->frame_in_buffer = 0;
+			STp->frame_seq_number++;              /* frame to look for next time */
+		}
+	} /* for (total = 0, special = 0; total < count && !special; ) */
+
+	/* Change the eof state if no data from tape or buffer */
+	if (total == 0) {
+		if (STps->eof == ST_FM_HIT) {
+			STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM;
+			STps->drv_block = 0;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+		}
+		else if (STps->eof == ST_EOD_1) {
+			STps->eof = ST_EOD_2;
+			if (STps->drv_block > 0 && STps->drv_file >= 0)
+				STps->drv_file++;
+			STps->drv_block = 0;
+		}
+		else if (STps->eof == ST_EOD_2)
+			STps->eof = ST_EOD;
+	}
+	else if (STps->eof == ST_FM)
+		STps->eof = ST_NOEOF;
+
+	retval = total;
+
+out:
+	if (SRpnt != NULL) scsi_release_request(SRpnt);
+
+	up(&STp->lock);
+
+	return retval;
+}
+
+
+/* Set the driver options */
+static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name)
+{
+  printk(KERN_INFO
+"%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+	 name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
+	 STm->do_read_ahead);
+  printk(KERN_INFO
+"%s:I:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+	 name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
+  printk(KERN_INFO
+"%s:I:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+	 name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
+	 STp->scsi2_logical);
+  printk(KERN_INFO
+"%s:I:    sysv: %d\n", name, STm->sysv);
+#if DEBUG
+  printk(KERN_INFO
+	 "%s:D:    debugging: %d\n",
+	 name, debugging);
+#endif
+}
+
+
+static int osst_set_options(struct osst_tape *STp, long options)
+{
+	int		    value;
+	long		    code;
+	struct st_modedef * STm;
+	char		  * name = tape_name(STp);
+
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined) {
+		memcpy(STm, &(STp->modes[0]), sizeof(*STm));
+		modes_defined = 1;
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n",
+					     name, STp->current_mode);
+#endif
+	}
+
+	code = options & MT_ST_OPTIONS;
+	if (code == MT_ST_BOOLEANS) {
+		STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
+		STm->do_async_writes  = (options & MT_ST_ASYNC_WRITES) != 0;
+		STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
+		STm->do_read_ahead    = (options & MT_ST_READ_AHEAD) != 0;
+		STp->two_fm	      = (options & MT_ST_TWO_FM) != 0;
+		STp->fast_mteom	      = (options & MT_ST_FAST_MTEOM) != 0;
+		STp->do_auto_lock     = (options & MT_ST_AUTO_LOCK) != 0;
+		STp->can_bsr          = (options & MT_ST_CAN_BSR) != 0;
+		STp->omit_blklims     = (options & MT_ST_NO_BLKLIMS) != 0;
+		if ((STp->device)->scsi_level >= SCSI_2)
+			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
+		STp->scsi2_logical    = (options & MT_ST_SCSI2LOGICAL) != 0;
+		STm->sysv	      = (options & MT_ST_SYSV) != 0;
+#if DEBUG
+		debugging = (options & MT_ST_DEBUGGING) != 0;
+#endif
+		osst_log_options(STp, STm, name);
+	}
+	else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
+		value = (code == MT_ST_SETBOOLEANS);
+		if ((options & MT_ST_BUFFER_WRITES) != 0)
+			STm->do_buffer_writes = value;
+		if ((options & MT_ST_ASYNC_WRITES) != 0)
+			STm->do_async_writes = value;
+		if ((options & MT_ST_DEF_WRITES) != 0)
+			STm->defaults_for_writes = value;
+		if ((options & MT_ST_READ_AHEAD) != 0)
+			STm->do_read_ahead = value;
+		if ((options & MT_ST_TWO_FM) != 0)
+			STp->two_fm = value;
+		if ((options & MT_ST_FAST_MTEOM) != 0)
+			STp->fast_mteom = value;
+		if ((options & MT_ST_AUTO_LOCK) != 0)
+			STp->do_auto_lock = value;
+		if ((options & MT_ST_CAN_BSR) != 0)
+			STp->can_bsr = value;
+		if ((options & MT_ST_NO_BLKLIMS) != 0)
+			STp->omit_blklims = value;
+		if ((STp->device)->scsi_level >= SCSI_2 &&
+		    (options & MT_ST_CAN_PARTITIONS) != 0)
+			STp->can_partitions = value;
+		if ((options & MT_ST_SCSI2LOGICAL) != 0)
+			STp->scsi2_logical = value;
+		if ((options & MT_ST_SYSV) != 0)
+			STm->sysv = value;
+#if DEBUG
+		if ((options & MT_ST_DEBUGGING) != 0)
+			debugging = value;
+#endif
+		osst_log_options(STp, STm, name);
+	}
+	else if (code == MT_ST_WRITE_THRESHOLD) {
+		value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE;
+		if (value < 1 || value > osst_buffer_size) {
+			printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n",
+					     name, value);
+			return (-EIO);
+		}
+		STp->write_threshold = value;
+		printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n",
+				  name, value);
+	}
+	else if (code == MT_ST_DEF_BLKSIZE) {
+		value = (options & ~MT_ST_OPTIONS);
+		if (value == ~MT_ST_OPTIONS) {
+			STm->default_blksize = (-1);
+			printk(KERN_INFO "%s:I: Default block size disabled.\n", name);
+		}
+		else {
+			if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) {
+				printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n",
+							 name, value);
+				return (-EINVAL);
+			}
+			STm->default_blksize = value;
+			printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n",
+					  name, STm->default_blksize);
+		}
+	}
+	else if (code == MT_ST_TIMEOUTS) {
+		value = (options & ~MT_ST_OPTIONS);
+		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
+			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
+			printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name,
+					     (value & ~MT_ST_SET_LONG_TIMEOUT));
+		}
+		else {
+			STp->timeout = value * HZ;
+			printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value);
+		}
+	}
+	else if (code == MT_ST_DEF_OPTIONS) {
+		code = (options & ~MT_ST_CLEAR_DEFAULT);
+		value = (options & MT_ST_CLEAR_DEFAULT);
+		if (code == MT_ST_DEF_DENSITY) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_density = (-1);
+				printk(KERN_INFO "%s:I: Density default disabled.\n", name);
+			}
+			else {
+				STm->default_density = value & 0xff;
+				printk(KERN_INFO "%s:I: Density default set to %x\n",
+						  name, STm->default_density);
+			}
+		}
+		else if (code == MT_ST_DEF_DRVBUFFER) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STp->default_drvbuffer = 0xff;
+				printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name);
+			}
+			else {
+				STp->default_drvbuffer = value & 7;
+				printk(KERN_INFO "%s:I: Drive buffer default set to %x\n",
+						  name, STp->default_drvbuffer);
+			}
+		}
+		else if (code == MT_ST_DEF_COMPRESSION) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_compression = ST_DONT_TOUCH;
+				printk(KERN_INFO "%s:I: Compression default disabled.\n", name);
+			}
+			else {
+				STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+				printk(KERN_INFO "%s:I: Compression default set to %x\n",
+						  name, (value & 1));
+			}
+		}
+	}
+	else
+		return (-EIO);
+
+	return 0;
+}
+
+
+/* Internal ioctl function */
+static int osst_int_ioctl(struct osst_tape * STp, struct scsi_request ** aSRpnt,
+			     unsigned int cmd_in, unsigned long arg)
+{
+	int			timeout;
+	long			ltmp;
+	int			i, ioctl_result;
+	int			chg_eof = 1;
+	unsigned char		cmd[MAX_COMMAND_SIZE];
+	struct scsi_request   * SRpnt = * aSRpnt;
+	struct st_partstat    * STps;
+	int			fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num;
+	int			datalen = 0, direction = DMA_NONE;
+	char		      * name = tape_name(STp);
+
+	if (STp->ready != ST_READY && cmd_in != MTLOAD) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+	timeout = STp->long_timeout;
+	STps = &(STp->ps[STp->partition]);
+	fileno = STps->drv_file;
+	blkno = STps->drv_block;
+	at_sm = STps->at_sm;
+	frame_seq_numbr = STp->frame_seq_number;
+	logical_blk_num = STp->logical_blk_num;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	switch (cmd_in) {
+	 case MTFSFM:
+		chg_eof = 0; /* Changed from the FSF after this */
+	 case MTFSF:
+		if (STp->raw)
+		   return (-EIO);
+		if (STp->linux_media)
+		   ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg);
+		else
+		   ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg);
+		if (fileno >= 0)
+		   fileno += arg;
+		blkno = 0;
+		at_sm &= (arg == 0);
+		goto os_bypass;
+
+	 case MTBSF:
+		chg_eof = 0; /* Changed from the FSF after this */
+	 case MTBSFM:
+		if (STp->raw)
+		   return (-EIO);
+		ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg);
+		if (fileno >= 0)
+		   fileno -= arg;
+		blkno = (-1);  /* We can't know the block number */
+		at_sm &= (arg == 0);
+		goto os_bypass;
+
+	 case MTFSR:
+	 case MTBSR:
+#if DEBUG
+		if (debugging)
+		   printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n",
+				name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num);
+#endif
+		if (cmd_in == MTFSR) {
+		   logical_blk_num += arg;
+		   if (blkno >= 0) blkno += arg;
+		}
+		else {
+		   logical_blk_num -= arg;
+		   if (blkno >= 0) blkno -= arg;
+		}
+		ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num);
+		fileno = STps->drv_file;
+		blkno  = STps->drv_block;
+		at_sm &= (arg == 0);
+		goto os_bypass;
+
+	 case MTFSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name,
+		cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+		if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		}
+		break;
+	 case MTBSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04; /* Space Setmarks */   /* FIXME -- OS can't do this? */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+#if DEBUG
+		if (debugging) {
+			if (cmd[2] & 0x80)
+			   ltmp = 0xff000000;
+			ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+			printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n",
+						name, (-ltmp));
+		 }
+#endif
+		 if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		 }
+		 break;
+	 case MTWEOF:
+		 if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
+			STp->write_type = OS_WRITE_DATA;
+			ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
+		 } else
+			ioctl_result = 0;
+#if DEBUG
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg);
+#endif
+		 for (i=0; i<arg; i++)
+			ioctl_result |= osst_write_filemark(STp, &SRpnt);
+		 if (fileno >= 0) fileno += arg;
+		 if (blkno  >= 0) blkno   = 0;
+		 goto os_bypass;
+
+	 case MTWSM:
+		 if (STp->write_prot)
+			return (-EACCES);
+		 if (!STp->raw)
+			return 0;
+		 cmd[0] = WRITE_FILEMARKS;   /* FIXME -- need OS version */
+		 if (cmd_in == MTWSM)
+			 cmd[1] = 2;
+		 cmd[2] = (arg >> 16);
+		 cmd[3] = (arg >> 8);
+		 cmd[4] = arg;
+		 timeout = STp->timeout;
+#if DEBUG
+		 if (debugging) 
+			   printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name,
+				  cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+#endif
+		 if (fileno >= 0)
+			fileno += arg;
+		 blkno = 0;
+		 at_sm = (cmd_in == MTWSM);
+		 break;
+	 case MTOFFL:
+	 case MTLOAD:
+	 case MTUNLOAD:
+	 case MTRETEN:
+		 cmd[0] = START_STOP;
+		 cmd[1] = 1;			/* Don't wait for completion */
+		 if (cmd_in == MTLOAD) {
+		     if (STp->ready == ST_NO_TAPE)
+			 cmd[4] = 4;		/* open tray */
+		      else
+			 cmd[4] = 1;		/* load */
+		 }
+		 if (cmd_in == MTRETEN)
+			 cmd[4] = 3;		/* retension then mount */
+		 if (cmd_in == MTOFFL)
+			 cmd[4] = 4;		/* rewind then eject */
+		 timeout = STp->timeout;
+#if DEBUG
+		 if (debugging) {
+			 switch (cmd_in) {
+				 case MTUNLOAD:
+					 printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name);
+					 break;
+				 case MTLOAD:
+					 printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name);
+					 break;
+				 case MTRETEN:
+					 printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name);
+					 break;
+				 case MTOFFL:
+					 printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name);
+					 break;
+			 }
+		 }
+#endif
+       fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
+		 break;
+	 case MTNOP:
+#if DEBUG
+		 if (debugging)
+			 printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name);
+#endif
+		 return 0;  /* Should do something ? */
+		 break;
+	 case MTEOM:
+#if DEBUG
+		if (debugging)
+		   printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name);
+#endif
+		if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) ||
+			    (osst_get_logical_frame(STp, &SRpnt, -1, 0)               < 0)) {
+		   ioctl_result = -EIO;
+		   goto os_bypass;
+		}
+		if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) {
+#if DEBUG
+		   printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name);
+#endif
+		   ioctl_result = -EIO;
+		   goto os_bypass;
+		}
+		ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0);
+		fileno = STp->filemark_cnt;
+		blkno  = at_sm = 0;
+		goto os_bypass;
+
+	 case MTERASE:
+		if (STp->write_prot)
+		   return (-EACCES);
+		ioctl_result = osst_reset_header(STp, &SRpnt);
+		i = osst_write_eod(STp, &SRpnt);
+		if (i < ioctl_result) ioctl_result = i;
+		i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos);
+		if (i < ioctl_result) ioctl_result = i;
+		fileno = blkno = at_sm = 0 ;
+		goto os_bypass;
+
+	 case MTREW:
+		cmd[0] = REZERO_UNIT; /* rewind */
+		cmd[1] = 1;
+#if DEBUG
+		if (debugging)
+		   printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]);
+#endif
+		fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
+		break;
+
+	 case MTSETBLK:           /* Set block length */
+		 if ((STps->drv_block == 0 )			  &&
+		     !STp->dirty				  &&
+		     ((STp->buffer)->buffer_bytes == 0)		  &&
+		     ((arg & MT_ST_BLKSIZE_MASK) >= 512 )	  && 
+		     ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) &&
+		     !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))  ) {
+			 /*
+			  * Only allowed to change the block size if you opened the
+			  * device at the beginning of a file before writing anything.
+			  * Note, that when reading, changing block_size is futile,
+			  * as the size used when writing overrides it.
+			  */
+			 STp->block_size = (arg & MT_ST_BLKSIZE_MASK);
+			 printk(KERN_INFO "%s:I: Block size set to %d bytes.\n",
+					   name, STp->block_size);
+			 return 0;
+		 }
+	 case MTSETDENSITY:       /* Set tape density */
+	 case MTSETDRVBUFFER:     /* Set drive buffering */
+	 case SET_DENS_AND_BLK:   /* Set density and block size */
+		 chg_eof = 0;
+		 if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
+			 return (-EIO);       /* Not allowed if data in buffer */
+		 if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
+		     (arg & MT_ST_BLKSIZE_MASK) != 0                    &&
+		     (arg & MT_ST_BLKSIZE_MASK) != STp->block_size       ) {
+			 printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n",
+						name, (int)(arg & MT_ST_BLKSIZE_MASK),
+						(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now");
+			 return (-EINVAL);
+		 }
+		 return 0;  /* FIXME silently ignore if block size didn't change */
+
+	 default:
+		return (-ENOSYS);
+	}
+
+	SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1);
+
+	ioctl_result = (STp->buffer)->syscall_result;
+
+	if (!SRpnt) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name);
+#endif
+		return ioctl_result;
+	}
+
+	if (!ioctl_result) {  /* SCSI command successful */
+		STp->frame_seq_number = frame_seq_numbr;
+		STp->logical_blk_num  = logical_blk_num;
+	}
+
+os_bypass:
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result);
+#endif
+
+	if (!ioctl_result) {				/* success */
+
+		if (cmd_in == MTFSFM) {
+			 fileno--;
+			 blkno--;
+		}
+		if (cmd_in == MTBSFM) {
+			 fileno++;
+			 blkno++;
+		}
+		STps->drv_block = blkno;
+		STps->drv_file = fileno;
+		STps->at_sm = at_sm;
+
+		if (cmd_in == MTEOM)
+			STps->eof = ST_EOD;
+		else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) {
+			ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1);
+			STps->drv_block++;
+			STp->logical_blk_num++;
+			STp->frame_seq_number++;
+			STp->frame_in_buffer = 0;
+			STp->buffer->read_pointer = 0;
+		}
+		else if (cmd_in == MTFSF)
+			STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
+		else if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+		if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
+			STp->rew_at_close = 0;
+		else if (cmd_in == MTLOAD) {
+			for (i=0; i < ST_NBR_PARTITIONS; i++) {
+			    STp->ps[i].rw = ST_IDLE;
+			    STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */
+			}
+			STp->partition = 0;
+		}
+
+		if (cmd_in == MTREW) {
+			ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); 
+			if (ioctl_result > 0)
+				ioctl_result = 0;
+		}
+
+	} else if (cmd_in == MTBSF || cmd_in == MTBSFM ) {
+		if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0)
+			STps->drv_file = STps->drv_block = -1;
+		else
+			STps->drv_file = STps->drv_block = 0;
+		STps->eof = ST_NOEOF;
+	} else if (cmd_in == MTFSF || cmd_in == MTFSFM) {
+		if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0)
+			STps->drv_file = STps->drv_block = -1;
+		else {
+			STps->drv_file  = STp->filemark_cnt;
+			STps->drv_block = 0;
+		}
+		STps->eof = ST_EOD;
+	} else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) {
+		STps->drv_file = STps->drv_block = (-1);
+		STps->eof = ST_NOEOF;
+		STp->header_ok = 0;
+	} else if (cmd_in == MTERASE) {
+		STp->header_ok = 0;
+	} else if (SRpnt) {  /* SCSI command was not completely successful. */
+		if (SRpnt->sr_sense_buffer[2] & 0x40) {
+			STps->eof = ST_EOM_OK;
+			STps->drv_block = 0;
+		}
+		if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+		if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
+			STps->eof = ST_EOD;
+
+		if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
+			ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
+	}
+	*aSRpnt = SRpnt;
+
+	return ioctl_result;
+}
+
+
+/* Open the device */
+static int os_scsi_tape_open(struct inode * inode, struct file * filp)
+{
+	unsigned short	      flags;
+	int		      i, b_size, new_session = 0, retval = 0;
+	unsigned char	      cmd[MAX_COMMAND_SIZE];
+	struct scsi_request * SRpnt = NULL;
+	struct osst_tape    * STp;
+	struct st_modedef   * STm;
+	struct st_partstat  * STps;
+	char		    * name;
+	int		      dev  = TAPE_NR(inode);
+	int		      mode = TAPE_MODE(inode);
+
+	/*
+	 * We really want to do nonseekable_open(inode, filp); here, but some
+	 * versions of tar incorrectly call lseek on tapes and bail out if that
+	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+	 */
+	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
+	write_lock(&os_scsi_tapes_lock);
+	if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
+	    (STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
+		write_unlock(&os_scsi_tapes_lock);
+		return (-ENXIO);
+	}
+
+	name = tape_name(STp);
+
+	if (STp->in_use) {
+		write_unlock(&os_scsi_tapes_lock);
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
+#endif
+		return (-EBUSY);
+	}
+	if (scsi_device_get(STp->device)) {
+		write_unlock(&os_scsi_tapes_lock);
+#if DEBUG
+                printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name);
+#endif
+		return (-ENXIO);
+	}
+	filp->private_data = STp;
+	STp->in_use = 1;
+	write_unlock(&os_scsi_tapes_lock);
+	STp->rew_at_close = TAPE_REWIND(inode);
+
+	if( !scsi_block_when_processing_errors(STp->device) ) {
+		return -ENXIO;
+	}
+
+	if (mode != STp->current_mode) {
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n",
+					       name, STp->current_mode, mode);
+#endif
+		new_session = 1;
+		STp->current_mode = mode;
+	}
+	STm = &(STp->modes[STp->current_mode]);
+
+	flags = filp->f_flags;
+	STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
+
+	STp->raw = TAPE_IS_RAW(inode);
+	if (STp->raw)
+		STp->header_ok = 0;
+
+	/* Allocate data segments for this device's tape buffer */
+	if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
+		printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
+		retval = (-EOVERFLOW);
+		goto err_out;
+	}
+	if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
+		for (i = 0, b_size = 0; 
+		     (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); 
+		     b_size += STp->buffer->sg[i++].length);
+		STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name,
+			STp->buffer->b_data, page_address(STp->buffer->sg[0].page));
+		printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
+			 STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
+#endif
+	} else {
+		STp->buffer->aux = NULL; /* this had better never happen! */
+		printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
+		retval = (-EIO);
+		goto err_out;
+	}
+	STp->buffer->writing = 0;
+	STp->buffer->syscall_result = 0;
+	STp->dirty = 0;
+	for (i=0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+	}
+	STp->ready = ST_READY;
+#if DEBUG
+	STp->nbr_waits = STp->nbr_finished = 0;
+#endif
+
+	memset (cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = TEST_UNIT_READY;
+
+	SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;		/* FIXME - valid? */
+		goto err_out;
+	}
+	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70      &&
+	    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
+	     SRpnt->sr_sense_buffer[12]        == 4         ) {
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]);
+#endif
+		if (filp->f_flags & O_NONBLOCK) {
+			retval = -EAGAIN;
+			goto err_out;
+		}
+		if (SRpnt->sr_sense_buffer[13] == 2) {	/* initialize command required (LOAD) */
+			memset (cmd, 0, MAX_COMMAND_SIZE);
+        		cmd[0] = START_STOP;
+			cmd[1] = 1;
+			cmd[4] = 1;
+			SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+					     STp->timeout, MAX_RETRIES, 1);
+		}
+		osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60, 0);
+	}
+	if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+	    (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name);
+#endif
+		STp->header_ok = 0;
+
+		for (i=0; i < 10; i++) {
+
+			memset (cmd, 0, MAX_COMMAND_SIZE);
+			cmd[0] = TEST_UNIT_READY;
+
+			SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+					     STp->timeout, MAX_RETRIES, 1);
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+			    (SRpnt->sr_sense_buffer[2] & 0x0f) != UNIT_ATTENTION)
+				break;
+		}
+
+		STp->pos_unknown = 0;
+		STp->partition = STp->new_partition = 0;
+		if (STp->can_partitions)
+			STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
+		for (i=0; i < ST_NBR_PARTITIONS; i++) {
+			STps = &(STp->ps[i]);
+			STps->rw = ST_IDLE;		/* FIXME - seems to be redundant... */
+			STps->eof = ST_NOEOF;
+			STps->at_sm = 0;
+			STps->last_block_valid = 0;
+			STps->drv_block = 0;
+			STps->drv_file = 0 ;
+		}
+		new_session = 1;
+		STp->recover_count = 0;
+		STp->abort_count = 0;
+	}
+	/*
+	 * if we have valid headers from before, and the drive/tape seem untouched,
+	 * open without reconfiguring and re-reading the headers
+	 */
+	if (!STp->buffer->syscall_result && STp->header_ok &&
+	    !SRpnt->sr_result && SRpnt->sr_sense_buffer[0] == 0) {
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = MODE_SENSE;
+		cmd[1] = 8;
+		cmd[2] = VENDOR_IDENT_PAGE;
+		cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH;
+
+		SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1);
+
+		if (STp->buffer->syscall_result                     ||
+		    STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' ||
+		    STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' ||
+		    STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' ||
+		    STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4'  ) {
+#if DEBUG
+			printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name,
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 2],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 3],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 4],
+			  STp->buffer->b_data[MODE_HEADER_LENGTH + 5]);
+#endif
+			STp->header_ok = 0;
+		}
+		i = STp->first_frame_position;
+		if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) {
+			if (STp->door_locked == ST_UNLOCKED) {
+				if (do_door_lock(STp, 1))
+					printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
+				else
+					STp->door_locked = ST_LOCKED_AUTO;
+			}
+			if (!STp->frame_in_buffer) {
+				STp->block_size = (STm->default_blksize > 0) ?
+							STm->default_blksize : OS_DATA_SIZE;
+				STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0;
+			}
+			STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size;
+			STp->fast_open = 1;
+			scsi_release_request(SRpnt);
+			return 0;
+		}
+#if DEBUG
+		if (i != STp->first_frame_position)
+			printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n",
+						name, i, STp->first_frame_position);
+#endif
+		STp->header_ok = 0;
+	}
+	STp->fast_open = 0;
+
+	if ((STp->buffer)->syscall_result != 0 &&   /* in all error conditions except no medium */ 
+	    (SRpnt->sr_sense_buffer[2] != 2 || SRpnt->sr_sense_buffer[12] != 0x3A) ) {
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = MODE_SELECT;
+		cmd[1] = 0x10;
+		cmd[4] = 4 + MODE_HEADER_LENGTH;
+
+		(STp->buffer)->b_data[0] = cmd[4] - 1;
+		(STp->buffer)->b_data[1] = 0;			/* Medium Type - ignoring */
+		(STp->buffer)->b_data[2] = 0;			/* Reserved */
+		(STp->buffer)->b_data[3] = 0;			/* Block Descriptor Length */
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f;
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1;
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2;
+		(STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3;
+
+#if DEBUG
+		printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name);
+#endif
+		SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1);
+
+		STp->header_ok = 0;
+
+		for (i=0; i < 10; i++) {
+
+			memset (cmd, 0, MAX_COMMAND_SIZE);
+			cmd[0] = TEST_UNIT_READY;
+
+			SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+						    STp->timeout, MAX_RETRIES, 1);
+			if ((SRpnt->sr_sense_buffer[0] & 0x70) != 0x70 ||
+			    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY)
+			break;
+
+			if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
+				STp->pos_unknown = 0;
+				STp->partition = STp->new_partition = 0;
+				if (STp->can_partitions)
+					STp->nbr_partitions = 1;  /* This guess will be updated later if necessary */
+				for (i=0; i < ST_NBR_PARTITIONS; i++) {
+					STps = &(STp->ps[i]);
+					STps->rw = ST_IDLE;
+					STps->eof = ST_NOEOF;
+					STps->at_sm = 0;
+					STps->last_block_valid = 0;
+					STps->drv_block = 0;
+					STps->drv_file = 0 ;
+				}
+				new_session = 1;
+			}
+		}
+	}
+
+	if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0))		/* FIXME - not allowed with NOBLOCK */
+		 printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
+
+	if ((STp->buffer)->syscall_result != 0) {
+		if ((STp->device)->scsi_level >= SCSI_2 &&
+		    (SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
+		    (SRpnt->sr_sense_buffer[2] & 0x0f) == NOT_READY &&
+		     SRpnt->sr_sense_buffer[12] == 0x3a) { /* Check ASC */
+			STp->ready = ST_NO_TAPE;
+		} else
+			STp->ready = ST_NOT_READY;
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+		STp->density = 0;   	/* Clear the erroneous "residue" */
+		STp->write_prot = 0;
+		STp->block_size = 0;
+		STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+		STp->partition = STp->new_partition = 0;
+		STp->door_locked = ST_UNLOCKED;
+		return 0;
+	}
+
+	osst_configure_onstream(STp, &SRpnt);
+
+	STp->block_size = STp->raw ? OS_FRAME_SIZE : (
+			     (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
+	STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size;
+	STp->buffer->buffer_bytes  =
+	STp->buffer->read_pointer  =
+	STp->frame_in_buffer       = 0;
+
+#if DEBUG
+	if (debugging)
+		printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n",
+		     name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size,
+		     (STp->buffer)->buffer_blocks);
+#endif
+
+	if (STp->drv_write_prot) {
+		STp->write_prot = 1;
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Write protected\n", name);
+#endif
+		if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) {
+			retval = (-EROFS);
+			goto err_out;
+		}
+	}
+
+	if (new_session) {  /* Change the drive parameters for the new mode */
+#if DEBUG
+		if (debugging)
+	printk(OSST_DEB_MSG "%s:D: New Session\n", name);
+#endif
+		STp->density_changed = STp->blksize_changed = 0;
+		STp->compression_changed = 0;
+	}
+
+	/*
+	 * properly position the tape and check the ADR headers
+	 */
+	if (STp->door_locked == ST_UNLOCKED) {
+		 if (do_door_lock(STp, 1))
+			printk(KERN_INFO "%s:I: Can't lock drive door\n", name);
+		 else
+			STp->door_locked = ST_LOCKED_AUTO;
+	}
+
+	osst_analyze_headers(STp, &SRpnt);
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+
+	return 0;
+
+err_out:
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	normalize_buffer(STp->buffer);
+	STp->header_ok = 0;
+	STp->in_use = 0;
+	scsi_device_put(STp->device);
+
+	return retval;
+}
+
+
+/* Flush the tape buffer before close */
+static int os_scsi_tape_flush(struct file * filp)
+{
+	int		      result = 0, result2;
+	struct osst_tape    * STp    = filp->private_data;
+	struct st_modedef   * STm    = &(STp->modes[STp->current_mode]);
+	struct st_partstat  * STps   = &(STp->ps[STp->partition]);
+	struct scsi_request * SRpnt  = NULL;
+	char		    * name   = tape_name(STp);
+
+	if (file_count(filp) > 1)
+		return 0;
+
+	if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
+		STp->write_type = OS_WRITE_DATA;
+		result = osst_flush_write_buffer(STp, &SRpnt);
+		if (result != 0 && result != (-ENOSPC))
+			goto out;
+	}
+	if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
+
+#if DEBUG
+		if (debugging) {
+			printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n",
+					       name, (long)(filp->f_pos));
+			printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n",
+					       name, STp->nbr_waits, STp->nbr_finished);
+		}
+#endif
+		result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close));
+#if DEBUG
+		if (debugging)
+			printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n",
+					       name, 1+STp->two_fm);
+#endif
+	}
+	else if (!STp->rew_at_close) {
+		STps = &(STp->ps[STp->partition]);
+		if (!STm->sysv || STps->rw != ST_READING) {
+			if (STp->can_bsr)
+				result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */
+			else if (STps->eof == ST_FM_HIT) {
+				result = cross_eof(STp, &SRpnt, 0);
+					if (result) {
+						if (STps->drv_file >= 0)
+							STps->drv_file++;
+						STps->drv_block = 0;
+						STps->eof = ST_FM;
+					}
+					else
+						STps->eof = ST_NOEOF;
+			}
+		}
+		else if ((STps->eof == ST_NOEOF &&
+			  !(result = cross_eof(STp, &SRpnt, 1))) ||
+			 STps->eof == ST_FM_HIT) {
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+			STps->drv_block = 0;
+			STps->eof = ST_FM;
+		}
+	}
+
+out:
+	if (STp->rew_at_close) {
+		result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos);
+		STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0;
+		if (result == 0 && result2 < 0)
+			result = result2;
+	}
+	if (SRpnt) scsi_release_request(SRpnt);
+
+	if (STp->abort_count || STp->recover_count) {
+		printk(KERN_INFO "%s:I:", name);
+		if (STp->abort_count)
+			printk(" %d unrecovered errors", STp->abort_count);
+		if (STp->recover_count)
+			printk(" %d recovered errors", STp->recover_count);
+		if (STp->write_count)
+			printk(" in %d frames written", STp->write_count);
+		if (STp->read_count)
+			printk(" in %d frames read", STp->read_count);
+		printk("\n");
+		STp->recover_count = 0;
+		STp->abort_count   = 0;
+	}
+	STp->write_count = 0;
+	STp->read_count  = 0;
+
+	return result;
+}
+
+
+/* Close the device and release it */
+static int os_scsi_tape_close(struct inode * inode, struct file * filp)
+{
+	int		      result = 0;
+	struct osst_tape    * STp    = filp->private_data;
+
+	if (STp->door_locked == ST_LOCKED_AUTO)
+		do_door_lock(STp, 0);
+
+	if (STp->raw)
+		STp->header_ok = 0;
+	
+	normalize_buffer(STp->buffer);
+	write_lock(&os_scsi_tapes_lock);
+	STp->in_use = 0;
+	write_unlock(&os_scsi_tapes_lock);
+
+	scsi_device_put(STp->device);
+
+	return result;
+}
+
+
+/* The ioctl command */
+static int osst_ioctl(struct inode * inode,struct file * file,
+	 unsigned int cmd_in, unsigned long arg)
+{
+	int		      i, cmd_nr, cmd_type, retval = 0;
+	unsigned int	      blk;
+	struct st_modedef   * STm;
+	struct st_partstat  * STps;
+	struct scsi_request * SRpnt = NULL;
+	struct osst_tape    * STp   = file->private_data;
+	char		    * name  = tape_name(STp);
+	void	    __user  * p     = (void __user *)arg;
+
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
+#if DEBUG
+	if (debugging && !STp->in_use) {
+		printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name);
+		retval = (-EIO);
+		goto out;
+	}
+#endif
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if( !scsi_block_when_processing_errors(STp->device) ) {
+		retval = (-ENXIO);
+		goto out;
+	}
+
+	cmd_type = _IOC_TYPE(cmd_in);
+	cmd_nr   = _IOC_NR(cmd_in);
+#if DEBUG
+	printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name,
+			    cmd_type, cmd_nr, STp->raw?"raw":"normal");
+#endif
+	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+		struct mtop mtc;
+		int    auto_weof = 0;
+
+		if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
+			retval = (-EINVAL);
+			goto out;
+		}
+
+		i = copy_from_user((char *) &mtc, p, sizeof(struct mtop));
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
+
+		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
+			printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name);
+			retval = (-EPERM);
+			goto out;
+		}
+
+		if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
+			retval = (-ENXIO);
+			goto out;
+		}
+
+		if (!STp->pos_unknown) {
+
+			if (STps->eof == ST_FM_HIT) {
+				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
+					mtc.mt_count -= 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				}
+				else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
+					mtc.mt_count += 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				}
+			}
+
+			if (mtc.mt_op == MTSEEK) {
+				/* Old position must be restored if partition will be changed */
+				i = !STp->can_partitions || (STp->new_partition != STp->partition);
+			}
+			else {
+				i = mtc.mt_op == MTREW   || mtc.mt_op == MTOFFL ||
+				    mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM  ||
+				    mtc.mt_op == MTLOCK  || mtc.mt_op == MTLOAD ||
+				    mtc.mt_op == MTFSF   || mtc.mt_op == MTFSFM ||
+				    mtc.mt_op == MTBSF   || mtc.mt_op == MTBSFM ||
+				    mtc.mt_op == MTCOMPRESSION;
+			}
+			i = osst_flush_buffer(STp, &SRpnt, i);
+			if (i < 0) {
+				retval = i;
+				goto out;
+			}
+		}
+		else {
+			/*
+			 * If there was a bus reset, block further access
+			 * to this device.  If the user wants to rewind the tape,
+			 * then reset the flag and allow access again.
+			 */
+			if(mtc.mt_op != MTREW   &&
+			   mtc.mt_op != MTOFFL  &&
+			   mtc.mt_op != MTRETEN &&
+			   mtc.mt_op != MTERASE &&
+			   mtc.mt_op != MTSEEK  &&
+			   mtc.mt_op != MTEOM)   {
+				retval = (-EIO);
+				goto out;
+			}
+			reset_state(STp);
+			/* remove this when the midlevel properly clears was_reset */
+			STp->device->was_reset = 0;
+		}
+
+		if (mtc.mt_op != MTCOMPRESSION  && mtc.mt_op != MTLOCK         &&
+		    mtc.mt_op != MTNOP          && mtc.mt_op != MTSETBLK       &&
+		    mtc.mt_op != MTSETDENSITY   && mtc.mt_op != MTSETDRVBUFFER && 
+		    mtc.mt_op != MTMKPART       && mtc.mt_op != MTSETPART      &&
+		    mtc.mt_op != MTWEOF         && mtc.mt_op != MTWSM           ) {
+
+			/*
+			 * The user tells us to move to another position on the tape.
+			 * If we were appending to the tape content, that would leave
+			 * the tape without proper end, in that case write EOD and
+			 * update the header to reflect its position.
+			 */
+#if DEBUG
+			printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name,
+					STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle",
+					STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number,
+					STp->logical_blk_num, STps->drv_file, STps->drv_block );
+#endif
+			if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) {
+				auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) &&
+							!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
+				i = osst_write_trailer(STp, &SRpnt,
+							!(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL));
+#if DEBUG
+				printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n",
+						name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos,
+						STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block );
+#endif
+				if (i < 0) {
+					retval = i;
+					goto out;
+				}
+			}
+			STps->rw = ST_IDLE;
+		}
+
+		if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
+			do_door_lock(STp, 0);  /* Ignore result! */
+
+		if (mtc.mt_op == MTSETDRVBUFFER &&
+		   (mtc.mt_count & MT_ST_OPTIONS) != 0) {
+			retval = osst_set_options(STp, mtc.mt_count);
+			goto out;
+		}
+
+		if (mtc.mt_op == MTSETPART) {
+			if (mtc.mt_count >= STp->nbr_partitions)
+				retval = -EINVAL;
+			else {
+				STp->new_partition = mtc.mt_count;
+				retval = 0;
+			}
+			goto out;
+		}
+
+		if (mtc.mt_op == MTMKPART) {
+			if (!STp->can_partitions) {
+				retval = (-EINVAL);
+				goto out;
+			}
+			if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*||
+			    (i = partition_tape(inode, mtc.mt_count)) < 0*/) {
+				retval = i;
+				goto out;
+			}
+			for (i=0; i < ST_NBR_PARTITIONS; i++) {
+				STp->ps[i].rw = ST_IDLE;
+				STp->ps[i].at_sm = 0;
+				STp->ps[i].last_block_valid = 0;
+			}
+			STp->partition = STp->new_partition = 0;
+			STp->nbr_partitions = 1;  /* Bad guess ?-) */
+			STps->drv_block = STps->drv_file = 0;
+			retval = 0;
+			goto out;
+	 	}
+
+		if (mtc.mt_op == MTSEEK) {
+			if (STp->raw)
+				i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0);
+			else
+				i = osst_seek_sector(STp, &SRpnt, mtc.mt_count);
+			if (!STp->can_partitions)
+				STp->ps[0].rw = ST_IDLE;
+			retval = i;
+			goto out;
+		}
+ 
+		if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
+			retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
+			goto out;
+		}
+
+		if (auto_weof)
+			cross_eof(STp, &SRpnt, 0);
+
+		if (mtc.mt_op == MTCOMPRESSION)
+			retval = -EINVAL;       /* OnStream drives don't have compression hardware */
+		else
+			/* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS
+			 * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */
+			retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count);
+		goto out;
+	}
+
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
+
+	if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) {
+		retval = i;
+		goto out;
+	}
+
+	if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+		struct mtget mt_status;
+
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
+			 retval = (-EINVAL);
+			 goto out;
+		}
+
+		mt_status.mt_type = MT_ISONSTREAM_SC;
+		mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT;
+		mt_status.mt_dsreg =
+			((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
+			((STp->density    << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
+		mt_status.mt_blkno = STps->drv_block;
+		mt_status.mt_fileno = STps->drv_file;
+		if (STp->block_size != 0) {
+			if (STps->rw == ST_WRITING)
+				mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size;
+			else if (STps->rw == ST_READING)
+				mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes +
+							STp->block_size - 1) / STp->block_size;
+		}
+
+		mt_status.mt_gstat = 0;
+		if (STp->drv_write_prot)
+			mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
+		if (mt_status.mt_blkno == 0) {
+			if (mt_status.mt_fileno == 0)
+				mt_status.mt_gstat |= GMT_BOT(0xffffffff);
+			else
+				mt_status.mt_gstat |= GMT_EOF(0xffffffff);
+		}
+		mt_status.mt_resid = STp->partition;
+		if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
+			mt_status.mt_gstat |= GMT_EOT(0xffffffff);
+		else if (STps->eof >= ST_EOM_OK)
+			mt_status.mt_gstat |= GMT_EOD(0xffffffff);
+		if (STp->density == 1)
+			mt_status.mt_gstat |= GMT_D_800(0xffffffff);
+		else if (STp->density == 2)
+			mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
+		else if (STp->density == 3)
+			mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
+		if (STp->ready == ST_READY)
+			mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
+		if (STp->ready == ST_NO_TAPE)
+			mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
+		if (STps->at_sm)
+			mt_status.mt_gstat |= GMT_SM(0xffffffff);
+		if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) ||
+		    STp->drv_buffer != 0)
+			mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+
+		i = copy_to_user(p, &mt_status, sizeof(struct mtget));
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
+
+		STp->recover_erreg = 0;  /* Clear after read */
+		retval = 0;
+		goto out;
+	} /* End of MTIOCGET */
+
+	if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+		struct mtpos mt_pos;
+
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
+			retval = (-EINVAL);
+			goto out;
+		}
+		if (STp->raw)
+			blk = osst_get_frame_position(STp, &SRpnt);
+		else
+			blk = osst_get_sector(STp, &SRpnt);
+		if (blk < 0) {
+			retval = blk;
+			goto out;
+		}
+		mt_pos.mt_blkno = blk;
+		i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
+		if (i)
+			retval = -EFAULT;
+		goto out;
+	}
+	if (SRpnt) scsi_release_request(SRpnt);
+
+	up(&STp->lock);
+
+	return scsi_ioctl(STp->device, cmd_in, p);
+
+out:
+	if (SRpnt) scsi_release_request(SRpnt);
+
+	up(&STp->lock);
+
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg)
+{
+	struct osst_tape *STp = file->private_data;
+	struct scsi_device *sdev = STp->device;
+	int ret = -ENOIOCTLCMD;
+	if (sdev->host->hostt->compat_ioctl) {
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
+
+	}
+	return ret;
+}
+#endif
+
+
+
+/* Memory handling routines */
+
+/* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
+static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
+{
+	int i, priority;
+	struct osst_buffer *tb;
+
+	if (from_initialization)
+		priority = GFP_ATOMIC;
+	else
+		priority = GFP_KERNEL;
+
+	i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
+	tb = (struct osst_buffer *)kmalloc(i, priority);
+	if (!tb) {
+		printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
+		return NULL;
+	}
+	memset(tb, 0, i);
+	tb->sg_segs = tb->orig_sg_segs = 0;
+	tb->use_sg = max_sg;
+	tb->in_use = 1;
+	tb->dma = need_dma;
+	tb->buffer_size = 0;
+#if DEBUG
+	if (debugging) 
+		printk(OSST_DEB_MSG
+			"osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
+			   i, max_sg, need_dma);
+#endif
+	return tb;
+}
+
+/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
+static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma)
+{
+	int segs, nbr, max_segs, b_size, priority, order, got;
+
+	if (STbuffer->buffer_size >= OS_FRAME_SIZE)
+		return 1;
+
+	if (STbuffer->sg_segs) {
+		printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
+		normalize_buffer(STbuffer);
+	}
+	/* See how many segments we can use -- need at least two */
+	nbr = max_segs = STbuffer->use_sg;
+	if (nbr <= 2)
+		return 0;
+
+	priority = GFP_KERNEL /* | __GFP_NOWARN */;
+	if (need_dma)
+		priority |= GFP_DMA;
+
+	/* Try to allocate the first segment up to OS_DATA_SIZE and the others
+	   big enough to reach the goal (code assumes no segments in place) */
+	for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
+		STbuffer->sg[0].page = alloc_pages(priority, order);
+		STbuffer->sg[0].offset = 0;
+		if (STbuffer->sg[0].page != NULL) {
+		    STbuffer->sg[0].length = b_size;
+		    STbuffer->b_data = page_address(STbuffer->sg[0].page);
+		    break;
+		}
+	}
+	if (STbuffer->sg[0].page == NULL) {
+		printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
+		return 0;
+	}
+	/* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
+	for (segs=STbuffer->sg_segs=1, got=b_size;
+	     segs < max_segs && got < OS_FRAME_SIZE; ) {
+		STbuffer->sg[segs].page =
+				alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order);
+		STbuffer->sg[segs].offset = 0;
+		if (STbuffer->sg[segs].page == NULL) {
+			if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
+				b_size /= 2;  /* Large enough for the rest of the buffers */
+				order--;
+				continue;
+			}
+			printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
+						OS_FRAME_SIZE);
+#if DEBUG
+			STbuffer->buffer_size = got;
+#endif
+			normalize_buffer(STbuffer);
+			return 0;
+		}
+		STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
+		got += STbuffer->sg[segs].length;
+		STbuffer->buffer_size = got;
+		STbuffer->sg_segs = ++segs;
+	}
+#if DEBUG
+	if (debugging) {
+		printk(OSST_DEB_MSG
+			   "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
+			   got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
+		printk(OSST_DEB_MSG
+			   "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n",
+			   STbuffer->sg[0].length, page_address(STbuffer->sg[0].page),
+			   STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page));
+	}
+#endif
+
+	return 1;
+}
+
+
+/* Release the segments */
+static void normalize_buffer(struct osst_buffer *STbuffer)
+{
+  int i, order, b_size;
+
+	for (i=0; i < STbuffer->sg_segs; i++) {
+
+		for (b_size = PAGE_SIZE, order = 0;
+		     b_size < STbuffer->sg[i].length;
+		     b_size *= 2, order++);
+
+		__free_pages(STbuffer->sg[i].page, order);
+		STbuffer->buffer_size -= STbuffer->sg[i].length;
+	}
+#if DEBUG
+	if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs)
+		printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
+			     STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
+#endif
+	STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
+}
+
+
+/* Move data from the user buffer to the tape buffer. Returns zero (success) or
+   negative error code. */
+static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count)
+{
+	int i, cnt, res, offset;
+
+	for (i=0, offset=st_bp->buffer_bytes;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+	offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		      st_bp->sg[i].length - offset : do_count;
+		res = copy_from_user(page_address(st_bp->sg[i].page) + offset, ubp, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n",
+		       do_count);
+		return (-EIO);
+	}
+	return 0;
+}
+
+
+/* Move data from the tape buffer to the user buffer. Returns zero (success) or
+   negative error code. */
+static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count)
+{
+	int i, cnt, res, offset;
+
+	for (i=0, offset=st_bp->read_pointer;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+		offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for ( ; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		      st_bp->sg[i].length - offset : do_count;
+		res = copy_to_user(ubp, page_address(st_bp->sg[i].page) + offset, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes -= cnt;
+		st_bp->read_pointer += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count);
+		return (-EIO);
+	}
+	return 0;
+}
+
+/* Sets the tail of the buffer after fill point to zero.
+   Returns zero (success) or negative error code.        */
+static int osst_zero_buffer_tail(struct osst_buffer *st_bp)
+{
+	int	i, offset, do_count, cnt;
+
+	for (i = 0, offset = st_bp->buffer_bytes;
+	     i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++)
+		offset -= st_bp->sg[i].length;
+	if (i == st_bp->sg_segs) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes;
+	     i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length - offset < do_count ?
+		      st_bp->sg[i].length - offset : do_count ;
+		memset(page_address(st_bp->sg[i].page) + offset, 0, cnt);
+		do_count -= cnt;
+		offset = 0;
+	}
+	if (do_count) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count);
+		return (-EIO);
+	}
+	return 0;
+}
+
+/* Copy a osst 32K chunk of memory into the buffer.
+   Returns zero (success) or negative error code.  */
+static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
+{
+	int	i, cnt, do_count = OS_DATA_SIZE;
+
+	for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length < do_count ?
+		      st_bp->sg[i].length : do_count ;
+		memcpy(page_address(st_bp->sg[i].page), ptr, cnt);
+		do_count -= cnt;
+		ptr      += cnt;
+	}
+	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n",
+					 do_count, i);
+		return (-EIO);
+	}
+	return 0;
+}
+
+/* Copy a osst 32K chunk of memory from the buffer.
+   Returns zero (success) or negative error code.  */
+static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr)
+{
+	int	i, cnt, do_count = OS_DATA_SIZE;
+
+	for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) {
+		cnt = st_bp->sg[i].length < do_count ?
+		      st_bp->sg[i].length : do_count ;
+		memcpy(ptr, page_address(st_bp->sg[i].page), cnt);
+		do_count -= cnt;
+		ptr      += cnt;
+	}
+	if (do_count || i != st_bp->sg_segs-1) {  /* Should never happen */
+		printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n",
+					 do_count, i);
+		return (-EIO);
+	}
+	return 0;
+}
+
+
+/* Module housekeeping */
+
+static void validate_options (void)
+{
+  if (max_dev > 0)
+		osst_max_dev = max_dev;  
+  if (write_threshold_kbs > 0)
+		osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
+  if (osst_write_threshold > osst_buffer_size)
+		osst_write_threshold = osst_buffer_size;
+  if (max_sg_segs >= OSST_FIRST_SG)
+		osst_max_sg_segs = max_sg_segs;
+#if DEBUG
+  printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n",
+			   osst_max_dev, osst_write_threshold, osst_max_sg_segs);
+#endif
+}
+	
+#ifndef MODULE
+/* Set the boot options. Syntax: osst=xxx,yyy,...
+   where xxx is write threshold in 1024 byte blocks,
+   and   yyy is number of s/g segments to use. */
+static int __init osst_setup (char *str)
+{
+  int i, ints[5];
+  char *stp;
+
+  stp = get_options(str, ARRAY_SIZE(ints), ints);
+	
+  if (ints[0] > 0) {
+	for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
+		  *parms[i].val = ints[i + 1];
+  } else {
+	while (stp != NULL) {
+		for (i = 0; i < ARRAY_SIZE(parms); i++) {
+			int len = strlen(parms[i].name);
+			if (!strncmp(stp, parms[i].name, len) &&
+			    (*(stp + len) == ':' || *(stp + len) == '=')) {
+				*parms[i].val =
+					simple_strtoul(stp + len + 1, NULL, 0);
+				break;
+			}
+		}
+		if (i >= sizeof(parms) / sizeof(struct osst_dev_parm))
+			printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n",
+			       stp);
+		stp = strchr(stp, ',');
+		if (stp)
+			stp++;
+	}
+  }
+
+  return 1;
+}
+
+__setup("osst=", osst_setup);
+
+#endif
+
+static struct file_operations osst_fops = {
+	.owner =        THIS_MODULE,
+	.read =         osst_read,
+	.write =        osst_write,
+	.ioctl =        osst_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = osst_compat_ioctl,
+#endif
+	.open =         os_scsi_tape_open,
+	.flush =        os_scsi_tape_flush,
+	.release =      os_scsi_tape_close,
+};
+
+static int osst_supports(struct scsi_device * SDp)
+{
+	struct	osst_support_data {
+		char *vendor;
+		char *model;
+		char *rev;
+		char *driver_hint; /* Name of the correct driver, NULL if unknown */
+	};
+
+static	struct	osst_support_data support_list[] = {
+		/* {"XXX", "Yy-", "", NULL},  example */
+		SIGS_FROM_OSST,
+		{NULL, }};
+
+	struct	osst_support_data *rp;
+
+	/* We are willing to drive OnStream SC-x0 as well as the
+	 * 	 * IDE, ParPort, FireWire, USB variants, if accessible by
+	 * 	 	 * emulation layer (ide-scsi, usb-storage, ...) */
+
+	for (rp=&(support_list[0]); rp->vendor != NULL; rp++)
+		if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
+		    !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
+		    !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) 
+			return 1;
+	return 0;
+}
+
+/*
+ * sysfs support for osst driver parameter information
+ */
+
+static ssize_t osst_version_show(struct device_driver *ddd, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%s\n", osst_version);
+}
+
+static DRIVER_ATTR(version, S_IRUGO, osst_version_show, NULL);
+
+static void osst_create_driverfs_files(struct device_driver *driverfs)
+{
+	driver_create_file(driverfs, &driver_attr_version);
+}
+
+static void osst_remove_driverfs_files(struct device_driver *driverfs)
+{
+	driver_remove_file(driverfs, &driver_attr_version);
+}
+
+/*
+ * sysfs support for accessing ADR header information
+ */
+
+static ssize_t osst_adr_rev_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL);
+
+static ssize_t osst_linux_media_version_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL);
+
+static ssize_t osst_capacity_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL);
+
+static ssize_t osst_first_data_ppos_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL);
+
+static ssize_t osst_eod_frame_ppos_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL);
+
+static ssize_t osst_filemark_cnt_show(struct class_device *class_dev, char *buf)
+{
+	struct osst_tape * STp = (struct osst_tape *) class_get_devdata (class_dev);
+	ssize_t l = 0;
+
+	if (STp && STp->header_ok && STp->linux_media)
+		l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL);
+
+static struct class_simple * osst_sysfs_class;
+
+static int osst_sysfs_valid = 0;
+
+static void osst_sysfs_init(void)
+{
+	osst_sysfs_class = class_simple_create(THIS_MODULE, "onstream_tape");
+	if ( IS_ERR(osst_sysfs_class) )
+		printk(KERN_WARNING "osst :W: Unable to register sysfs class\n");
+	else
+		osst_sysfs_valid = 1;
+}
+
+static void osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name)
+{
+	struct class_device *osst_class_member;
+
+	if (!osst_sysfs_valid) return;
+
+	osst_class_member = class_simple_device_add(osst_sysfs_class, dev, device, "%s", name);
+	if (IS_ERR(osst_class_member)) {
+		printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name);
+		return;
+	}
+	class_set_devdata(osst_class_member, STp);
+	class_device_create_file(osst_class_member, &class_device_attr_ADR_rev);
+	class_device_create_file(osst_class_member, &class_device_attr_media_version);
+	class_device_create_file(osst_class_member, &class_device_attr_capacity);
+	class_device_create_file(osst_class_member, &class_device_attr_BOT_frame);
+	class_device_create_file(osst_class_member, &class_device_attr_EOD_frame);
+	class_device_create_file(osst_class_member, &class_device_attr_file_count);
+}
+
+static void osst_sysfs_destroy(dev_t dev)
+{
+	if (!osst_sysfs_valid) return; 
+
+	class_simple_device_remove(dev);
+}
+
+static void osst_sysfs_cleanup(void)
+{
+	if (osst_sysfs_valid) {
+		class_simple_destroy(osst_sysfs_class);
+		osst_sysfs_valid = 0;
+	}
+}
+
+/*
+ * osst startup / cleanup code
+ */
+
+static int osst_probe(struct device *dev)
+{
+	struct scsi_device * SDp = to_scsi_device(dev);
+	struct osst_tape   * tpnt;
+	struct st_modedef  * STm;
+	struct st_partstat * STps;
+	struct osst_buffer * buffer;
+	struct gendisk	   * drive;
+	int		     i, mode, dev_num;
+
+	if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
+		return -ENODEV;
+
+	drive = alloc_disk(1);
+	if (!drive) {
+		printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
+		return -ENODEV;
+	}
+
+	/* if this is the first attach, build the infrastructure */
+	write_lock(&os_scsi_tapes_lock);
+	if (os_scsi_tapes == NULL) {
+		os_scsi_tapes =
+			(struct osst_tape **)kmalloc(osst_max_dev * sizeof(struct osst_tape *),
+				   GFP_ATOMIC);
+		if (os_scsi_tapes == NULL) {
+			write_unlock(&os_scsi_tapes_lock);
+			printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
+			goto out_put_disk;
+		}
+		for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
+	}
+	
+	if (osst_nr_dev >= osst_max_dev) {
+		write_unlock(&os_scsi_tapes_lock);
+		printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
+		goto out_put_disk;
+	}
+
+	/* find a free minor number */
+	for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
+	if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
+	dev_num = i;
+
+	/* allocate a struct osst_tape for this device */
+	tpnt = (struct osst_tape *)kmalloc(sizeof(struct osst_tape), GFP_ATOMIC);
+	if (tpnt == NULL) {
+		write_unlock(&os_scsi_tapes_lock);
+		printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
+		goto out_put_disk;
+	}
+	memset(tpnt, 0, sizeof(struct osst_tape));
+
+	/* allocate a buffer for this device */
+	i = SDp->host->sg_tablesize;
+	if (osst_max_sg_segs < i)
+		i = osst_max_sg_segs;
+	buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i);
+	if (buffer == NULL) {
+		write_unlock(&os_scsi_tapes_lock);
+		printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
+		kfree(tpnt);
+		goto out_put_disk;
+	}
+	os_scsi_tapes[dev_num] = tpnt;
+	tpnt->buffer = buffer;
+	tpnt->device = SDp;
+	drive->private_data = &tpnt->driver;
+	sprintf(drive->disk_name, "osst%d", dev_num);
+	tpnt->driver = &osst_template;
+	tpnt->drive = drive;
+	tpnt->in_use = 0;
+	tpnt->capacity = 0xfffff;
+	tpnt->dirty = 0;
+	tpnt->drv_buffer = 1;  /* Try buffering if no mode sense */
+	tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
+	tpnt->density = 0;
+	tpnt->do_auto_lock = OSST_AUTO_LOCK;
+	tpnt->can_bsr = OSST_IN_FILE_POS;
+	tpnt->can_partitions = 0;
+	tpnt->two_fm = OSST_TWO_FM;
+	tpnt->fast_mteom = OSST_FAST_MTEOM;
+	tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */
+	tpnt->write_threshold = osst_write_threshold;
+	tpnt->default_drvbuffer = 0xff; /* No forced buffering */
+	tpnt->partition = 0;
+	tpnt->new_partition = 0;
+	tpnt->nbr_partitions = 0;
+	tpnt->min_block = 512;
+	tpnt->max_block = OS_DATA_SIZE;
+	tpnt->timeout = OSST_TIMEOUT;
+	tpnt->long_timeout = OSST_LONG_TIMEOUT;
+
+	/* Recognize OnStream tapes */
+	/* We don't need to test for OnStream, as this has been done in detect () */
+	tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
+	tpnt->omit_blklims = 1;
+
+	tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || 
+		     (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
+	tpnt->frame_in_buffer = 0;
+	tpnt->header_ok = 0;
+	tpnt->linux_media = 0;
+	tpnt->header_cache = NULL;
+
+	for (i=0; i < ST_NBR_MODES; i++) {
+		STm = &(tpnt->modes[i]);
+		STm->defined = 0;
+		STm->sysv = OSST_SYSV;
+		STm->defaults_for_writes = 0;
+		STm->do_async_writes = OSST_ASYNC_WRITES;
+		STm->do_buffer_writes = OSST_BUFFER_WRITES;
+		STm->do_read_ahead = OSST_READ_AHEAD;
+		STm->default_compression = ST_DONT_TOUCH;
+		STm->default_blksize = 512;
+		STm->default_density = (-1);  /* No forced density */
+	}
+
+	for (i=0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(tpnt->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = 0;
+		STps->drv_block = (-1);
+		STps->drv_file = (-1);
+	}
+
+	tpnt->current_mode = 0;
+	tpnt->modes[0].defined = 1;
+	tpnt->modes[2].defined = 1;
+	tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0;
+
+	init_MUTEX(&tpnt->lock);
+	osst_nr_dev++;
+	write_unlock(&os_scsi_tapes_lock);
+	{
+		char name[8];
+		/*  Rewind entry  */
+		osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt));
+		/*  No-rewind entry  */
+		snprintf(name, 8, "%s%s", "n", tape_name(tpnt));
+		osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name);
+	}
+	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+		/*  Rewind entry  */
+		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				"%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+
+		/*  No-rewind entry  */
+		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				"%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
+	}
+	drive->number = devfs_register_tape(SDp->devfs_name);
+
+	printk(KERN_INFO
+		"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
+		SDp->model, SDp->host->host_no, SDp->channel, SDp->id, SDp->lun, tape_name(tpnt));
+
+	return 0;
+
+out_put_disk:
+        put_disk(drive);
+        return -ENODEV;
+};
+
+static int osst_remove(struct device *dev)
+{
+	struct scsi_device * SDp = to_scsi_device(dev);
+	struct osst_tape * tpnt;
+	int i, mode;
+
+	if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0))
+		return 0;
+
+	write_lock(&os_scsi_tapes_lock);
+	for(i=0; i < osst_max_dev; i++) {
+		if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) {
+			osst_sysfs_destroy(MKDEV(OSST_MAJOR, i));
+			osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128));
+			tpnt->device = NULL;
+			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+				devfs_remove("%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+				devfs_remove("%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
+			}
+			devfs_unregister_tape(tpnt->drive->number);
+			put_disk(tpnt->drive);
+			os_scsi_tapes[i] = NULL;
+			osst_nr_dev--;
+			write_unlock(&os_scsi_tapes_lock);
+			if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
+			if (tpnt->buffer) {
+				normalize_buffer(tpnt->buffer);
+				kfree(tpnt->buffer);
+			}
+			kfree(tpnt);
+			return 0;
+		}
+	}
+	write_unlock(&os_scsi_tapes_lock);
+	return 0;
+}
+
+static int __init init_osst(void) 
+{
+	printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
+
+	validate_options();
+	osst_sysfs_init();
+
+	if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) {
+		printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR);
+		osst_sysfs_cleanup();
+		return 1;
+	}
+	osst_create_driverfs_files(&osst_template.gendrv);
+
+	return 0;
+}
+
+static void __exit exit_osst (void)
+{
+	int i;
+	struct osst_tape * STp;
+
+	osst_remove_driverfs_files(&osst_template.gendrv);
+	scsi_unregister_driver(&osst_template.gendrv);
+	unregister_chrdev(OSST_MAJOR, "osst");
+	osst_sysfs_cleanup();
+
+	if (os_scsi_tapes) {
+		for (i=0; i < osst_max_dev; ++i) {
+			if (!(STp = os_scsi_tapes[i])) continue;
+			/* This is defensive, supposed to happen during detach */
+			if (STp->header_cache)
+				vfree(STp->header_cache);
+			if (STp->buffer) {
+				normalize_buffer(STp->buffer);
+				kfree(STp->buffer);
+			}
+			put_disk(STp->drive);
+			kfree(STp);
+		}
+		kfree(os_scsi_tapes);
+	}
+	printk(KERN_INFO "osst :I: Unloaded.\n");
+}
+
+module_init(init_osst);
+module_exit(exit_osst);
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h
new file mode 100644
index 0000000..b72e1c7
--- /dev/null
+++ b/drivers/scsi/osst.h
@@ -0,0 +1,638 @@
+/*
+ *	$Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $
+ */
+
+#include <asm/byteorder.h>
+#include <linux/config.h>
+#include <linux/completion.h>
+
+/*	FIXME - rename and use the following two types or delete them!
+ *              and the types really should go to st.h anyway...
+ *	INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C)
+ */
+typedef struct {
+	unsigned	device_type	:5;	/* Peripheral Device Type */
+	unsigned	reserved0_765	:3;	/* Peripheral Qualifier - Reserved */
+	unsigned	reserved1_6t0	:7;	/* Reserved */
+	unsigned	rmb		:1;	/* Removable Medium Bit */
+	unsigned	ansi_version	:3;	/* ANSI Version */
+	unsigned	ecma_version	:3;	/* ECMA Version */
+	unsigned	iso_version	:2;	/* ISO Version */
+	unsigned	response_format :4;	/* Response Data Format */
+	unsigned	reserved3_45	:2;	/* Reserved */
+	unsigned	reserved3_6	:1;	/* TrmIOP - Reserved */
+	unsigned	reserved3_7	:1;	/* AENC - Reserved */
+	u8		additional_length;	/* Additional Length (total_length-4) */
+	u8		rsv5, rsv6, rsv7;	/* Reserved */
+	u8		vendor_id[8];		/* Vendor Identification */
+	u8		product_id[16];		/* Product Identification */
+	u8		revision_level[4];	/* Revision Level */
+	u8		vendor_specific[20];	/* Vendor Specific - Optional */
+	u8		reserved56t95[40];	/* Reserved - Optional */
+						/* Additional information may be returned */
+} idetape_inquiry_result_t;
+
+/*
+ *	READ POSITION packet command - Data Format (From Table 6-57)
+ */
+typedef struct {
+	unsigned	reserved0_10	:2;	/* Reserved */
+	unsigned	bpu		:1;	/* Block Position Unknown */	
+	unsigned	reserved0_543	:3;	/* Reserved */
+	unsigned	eop		:1;	/* End Of Partition */
+	unsigned	bop		:1;	/* Beginning Of Partition */
+	u8		partition;		/* Partition Number */
+	u8		reserved2, reserved3;	/* Reserved */
+	u32		first_block;		/* First Block Location */
+	u32		last_block;		/* Last Block Location (Optional) */
+	u8		reserved12;		/* Reserved */
+	u8		blocks_in_buffer[3];	/* Blocks In Buffer - (Optional) */
+	u32		bytes_in_buffer;	/* Bytes In Buffer (Optional) */
+} idetape_read_position_result_t;
+
+/*
+ *      Follows structures which are related to the SELECT SENSE / MODE SENSE
+ *      packet commands. 
+ */
+#define COMPRESSION_PAGE           0x0f
+#define COMPRESSION_PAGE_LENGTH    16
+
+#define CAPABILITIES_PAGE          0x2a
+#define CAPABILITIES_PAGE_LENGTH   20
+
+#define TAPE_PARAMTR_PAGE          0x2b
+#define TAPE_PARAMTR_PAGE_LENGTH   16
+
+#define NUMBER_RETRIES_PAGE        0x2f
+#define NUMBER_RETRIES_PAGE_LENGTH 4
+
+#define BLOCK_SIZE_PAGE            0x30
+#define BLOCK_SIZE_PAGE_LENGTH     4
+
+#define BUFFER_FILLING_PAGE        0x33
+#define BUFFER_FILLING_PAGE_LENGTH 4
+
+#define VENDOR_IDENT_PAGE          0x36
+#define VENDOR_IDENT_PAGE_LENGTH   8
+
+#define LOCATE_STATUS_PAGE         0x37
+#define LOCATE_STATUS_PAGE_LENGTH  0
+
+#define MODE_HEADER_LENGTH         4
+
+
+/*
+ *	REQUEST SENSE packet command result - Data Format.
+ */
+typedef struct {
+	unsigned	error_code	:7;	/* Current of deferred errors */
+	unsigned	valid		:1;	/* The information field conforms to QIC-157C */
+	u8		reserved1	:8;	/* Segment Number - Reserved */
+	unsigned	sense_key	:4;	/* Sense Key */
+	unsigned	reserved2_4	:1;	/* Reserved */
+	unsigned	ili		:1;	/* Incorrect Length Indicator */
+	unsigned	eom		:1;	/* End Of Medium */
+	unsigned	filemark 	:1;	/* Filemark */
+	u32		information __attribute__ ((packed));
+	u8		asl;			/* Additional sense length (n-7) */
+	u32		command_specific;	/* Additional command specific information */
+	u8		asc;			/* Additional Sense Code */
+	u8		ascq;			/* Additional Sense Code Qualifier */
+	u8		replaceable_unit_code;	/* Field Replaceable Unit Code */
+	unsigned	sk_specific1 	:7;	/* Sense Key Specific */
+	unsigned	sksv		:1;	/* Sense Key Specific information is valid */
+	u8		sk_specific2;		/* Sense Key Specific */
+	u8		sk_specific3;		/* Sense Key Specific */
+	u8		pad[2];			/* Padding to 20 bytes */
+} idetape_request_sense_result_t;
+
+/*
+ *      Mode Parameter Header for the MODE SENSE packet command
+ */
+typedef struct {
+        u8              mode_data_length;       /* Length of the following data transfer */
+        u8              medium_type;            /* Medium Type */
+        u8              dsp;                    /* Device Specific Parameter */
+        u8              bdl;                    /* Block Descriptor Length */
+} osst_mode_parameter_header_t;
+
+/*
+ *      Mode Parameter Block Descriptor the MODE SENSE packet command
+ *
+ *      Support for block descriptors is optional.
+ */
+typedef struct {
+        u8              density_code;           /* Medium density code */
+        u8              blocks[3];              /* Number of blocks */
+        u8              reserved4;              /* Reserved */
+        u8              length[3];              /* Block Length */
+} osst_parameter_block_descriptor_t;
+
+/*
+ *      The Data Compression Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        ps              :1;
+        unsigned        reserved0       :1;     /* Reserved */
+	unsigned        page_code       :6;     /* Page Code - Should be 0xf */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        page_code       :6;     /* Page Code - Should be 0xf */
+        unsigned        reserved0       :1;     /* Reserved */
+        unsigned        ps              :1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u8              page_length;            /* Page Length - Should be 14 */
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        dce             :1;     /* Data Compression Enable */
+        unsigned        dcc             :1;     /* Data Compression Capable */
+	unsigned        reserved2       :6;     /* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        reserved2       :6;     /* Reserved */
+        unsigned        dcc             :1;     /* Data Compression Capable */
+        unsigned        dce             :1;     /* Data Compression Enable */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        dde             :1;     /* Data Decompression Enable */
+        unsigned        red             :2;     /* Report Exception on Decompression */
+	unsigned        reserved3       :5;     /* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        reserved3       :5;     /* Reserved */
+        unsigned        red             :2;     /* Report Exception on Decompression */
+        unsigned        dde             :1;     /* Data Decompression Enable */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u32             ca;                     /* Compression Algorithm */
+        u32             da;                     /* Decompression Algorithm */
+        u8              reserved[4];            /* Reserved */
+} osst_data_compression_page_t;
+
+/*
+ *      The Medium Partition Page, as returned by the MODE SENSE packet command.
+ */
+typedef struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        ps              :1;
+        unsigned        reserved1_6     :1;     /* Reserved */
+	unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        page_code       :6;     /* Page Code - Should be 0x11 */
+        unsigned        reserved1_6     :1;     /* Reserved */
+        unsigned        ps              :1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u8              page_length;            /* Page Length - Should be 6 */
+        u8              map;                    /* Maximum Additional Partitions - Should be 0 */
+        u8              apd;                    /* Additional Partitions Defined - Should be 0 */
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        fdp             :1;     /* Fixed Data Partitions */
+        unsigned        sdp             :1;     /* Should be 0 */
+        unsigned        idp             :1;     /* Should be 0 */
+        unsigned        psum            :2;     /* Should be 0 */
+	unsigned        reserved4_012   :3;     /* Reserved */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        reserved4_012   :3;     /* Reserved */
+        unsigned        psum            :2;     /* Should be 0 */
+        unsigned        idp             :1;     /* Should be 0 */
+        unsigned        sdp             :1;     /* Should be 0 */
+        unsigned        fdp             :1;     /* Fixed Data Partitions */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u8              mfr;                    /* Medium Format Recognition */
+        u8              reserved[2];            /* Reserved */
+} osst_medium_partition_page_t;
+
+/*
+ *      Capabilities and Mechanical Status Page
+ */
+typedef struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        reserved1_67    :2;
+	unsigned        page_code       :6;     /* Page code - Should be 0x2a */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        page_code       :6;     /* Page code - Should be 0x2a */
+        unsigned        reserved1_67    :2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u8              page_length;            /* Page Length - Should be 0x12 */
+        u8              reserved2, reserved3;
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        reserved4_67    :2;
+        unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
+        unsigned        reserved4_1234  :4;
+	unsigned        ro              :1;     /* Read Only Mode */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        ro              :1;     /* Read Only Mode */
+        unsigned        reserved4_1234  :4;
+        unsigned        sprev           :1;     /* Supports SPACE in the reverse direction */
+        unsigned        reserved4_67    :2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        reserved5_67    :2;
+        unsigned        qfa             :1;     /* Supports the QFA two partition formats */
+        unsigned        reserved5_4     :1;
+        unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
+	unsigned        reserved5_012   :3;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        reserved5_012   :3;
+        unsigned        efmt            :1;     /* Supports ERASE command initiated formatting */
+        unsigned        reserved5_4     :1;
+        unsigned        qfa             :1;     /* Supports the QFA two partition formats */
+        unsigned        reserved5_67    :2;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        cmprs           :1;     /* Supports data compression */
+        unsigned        ecc             :1;     /* Supports error correction */
+	unsigned        reserved6_45    :2;     /* Reserved */  
+        unsigned        eject           :1;     /* The device can eject the volume */
+        unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */
+        unsigned        locked          :1;     /* The volume is locked */
+	unsigned        lock            :1;     /* Supports locking the volume */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        lock            :1;     /* Supports locking the volume */
+        unsigned        locked          :1;     /* The volume is locked */
+        unsigned        prevent         :1;     /* The device defaults in the prevent state after power up */
+        unsigned        eject           :1;     /* The device can eject the volume */
+	unsigned        reserved6_45    :2;     /* Reserved */  
+        unsigned        ecc             :1;     /* Supports error correction */
+        unsigned        cmprs           :1;     /* Supports data compression */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
+                                                /* transfers for slow buffer memory ??? */
+                                                /* Also 32768 block size in some cases */
+        unsigned        reserved7_3_6   :4;
+        unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
+        unsigned        blk512          :1;     /* Supports 512 bytes block size */
+	unsigned        reserved7_0     :1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        reserved7_0     :1;
+        unsigned        blk512          :1;     /* Supports 512 bytes block size */
+        unsigned        blk1024         :1;     /* Supports 1024 bytes block size */
+        unsigned        reserved7_3_6   :4;
+        unsigned        blk32768        :1;     /* slowb - the device restricts the byte count for PIO */
+                                                /* transfers for slow buffer memory ??? */
+                                                /* Also 32768 block size in some cases */
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u16             max_speed;              /* Maximum speed supported in KBps */
+        u8              reserved10, reserved11;
+        u16             ctl;                    /* Continuous Transfer Limit in blocks */
+        u16             speed;                  /* Current Speed, in KBps */
+        u16             buffer_size;            /* Buffer Size, in 512 bytes */
+        u8              reserved18, reserved19;
+} osst_capabilities_page_t;
+
+/*
+ *      Block Size Page
+ */
+typedef struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        ps              :1;
+        unsigned        reserved1_6     :1;
+	unsigned        page_code       :6;     /* Page code - Should be 0x30 */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        page_code       :6;     /* Page code - Should be 0x30 */
+        unsigned        reserved1_6     :1;
+        unsigned        ps              :1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+        u8              page_length;            /* Page Length - Should be 2 */
+        u8              reserved2;
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        one             :1;
+        unsigned        reserved2_6     :1;
+        unsigned        record32_5      :1;
+        unsigned        record32        :1;
+        unsigned        reserved2_23    :2;
+        unsigned        play32_5        :1;
+	unsigned        play32          :1;
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        play32          :1;
+        unsigned        play32_5        :1;
+        unsigned        reserved2_23    :2;
+        unsigned        record32        :1;
+        unsigned        record32_5      :1;
+        unsigned        reserved2_6     :1;
+        unsigned        one             :1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+} osst_block_size_page_t;
+
+/*
+ *	Tape Parameters Page
+ */
+typedef struct {
+#if   defined(__BIG_ENDIAN_BITFIELD)
+        unsigned        ps              :1;
+        unsigned        reserved1_6     :1;
+	unsigned        page_code       :6;     /* Page code - Should be 0x2b */
+#elif defined(__LITTLE_ENDIAN_BITFIELD)
+	unsigned        page_code       :6;     /* Page code - Should be 0x2b */
+        unsigned        reserved1_6     :1;
+        unsigned        ps              :1;
+#else
+#error "Please fix <asm/byteorder.h>"
+#endif
+	u8		reserved2;
+	u8		density;
+	u8		reserved3,reserved4;
+	u16		segtrk;
+	u16		trks;
+	u8		reserved5,reserved6,reserved7,reserved8,reserved9,reserved10;
+} osst_tape_paramtr_page_t;
+
+/* OnStream definitions */
+
+#define OS_CONFIG_PARTITION     (0xff)
+#define OS_DATA_PARTITION       (0)
+#define OS_PARTITION_VERSION    (1)
+
+/*
+ * partition
+ */
+typedef struct os_partition_s {
+        __u8    partition_num;
+        __u8    par_desc_ver;
+        __u16   wrt_pass_cntr;
+        __u32   first_frame_ppos;
+        __u32   last_frame_ppos;
+        __u32   eod_frame_ppos;
+} os_partition_t;
+
+/*
+ * DAT entry
+ */
+typedef struct os_dat_entry_s {
+        __u32   blk_sz;
+        __u16   blk_cnt;
+        __u8    flags;
+        __u8    reserved;
+} os_dat_entry_t;
+
+/*
+ * DAT
+ */
+#define OS_DAT_FLAGS_DATA       (0xc)
+#define OS_DAT_FLAGS_MARK       (0x1)
+
+typedef struct os_dat_s {
+        __u8            dat_sz;
+        __u8            reserved1;
+        __u8            entry_cnt;
+        __u8            reserved3;
+        os_dat_entry_t  dat_list[16];
+} os_dat_t;
+
+/*
+ * Frame types
+ */
+#define OS_FRAME_TYPE_FILL      (0)
+#define OS_FRAME_TYPE_EOD       (1 << 0)
+#define OS_FRAME_TYPE_MARKER    (1 << 1)
+#define OS_FRAME_TYPE_HEADER    (1 << 3)
+#define OS_FRAME_TYPE_DATA      (1 << 7)
+
+/*
+ * AUX
+ */
+typedef struct os_aux_s {
+        __u32           format_id;              /* hardware compability AUX is based on */
+        char            application_sig[4];     /* driver used to write this media */
+        __u32           hdwr;                   /* reserved */
+        __u32           update_frame_cntr;      /* for configuration frame */
+        __u8            frame_type;
+        __u8            frame_type_reserved;
+        __u8            reserved_18_19[2];
+        os_partition_t  partition;
+        __u8            reserved_36_43[8];
+        __u32           frame_seq_num;
+        __u32           logical_blk_num_high;
+        __u32           logical_blk_num;
+        os_dat_t        dat;
+        __u8            reserved188_191[4];
+        __u32           filemark_cnt;
+        __u32           phys_fm;
+        __u32           last_mark_ppos;
+        __u8            reserved204_223[20];
+
+        /*
+         * __u8         app_specific[32];
+         *
+         * Linux specific fields:
+         */
+         __u32          next_mark_ppos;         /* when known, points to next marker */
+	 __u32		last_mark_lbn;		/* storing log_blk_num of last mark is extends ADR spec */
+         __u8           linux_specific[24];
+
+        __u8            reserved_256_511[256];
+} os_aux_t;
+
+#define OS_FM_TAB_MAX 1024
+
+typedef struct os_fm_tab_s {
+	__u8		fm_part_num;
+	__u8		reserved_1;
+	__u8		fm_tab_ent_sz;
+	__u8		reserved_3;
+	__u16		fm_tab_ent_cnt;
+	__u8		reserved6_15[10];
+	__u32		fm_tab_ent[OS_FM_TAB_MAX];
+} os_fm_tab_t;
+
+typedef struct os_ext_trk_ey_s {
+	__u8		et_part_num;
+	__u8		fmt;
+	__u16		fm_tab_off;
+	__u8		reserved4_7[4];
+	__u32		last_hlb_hi;
+	__u32		last_hlb;
+	__u32		last_pp;
+	__u8		reserved20_31[12];
+} os_ext_trk_ey_t;
+
+typedef struct os_ext_trk_tb_s {
+	__u8		nr_stream_part;
+	__u8		reserved_1;
+	__u8		et_ent_sz;
+	__u8		reserved3_15[13];
+	os_ext_trk_ey_t	dat_ext_trk_ey;
+	os_ext_trk_ey_t	qfa_ext_trk_ey;
+} os_ext_trk_tb_t;
+
+typedef struct os_header_s {
+        char            ident_str[8];
+        __u8            major_rev;
+        __u8            minor_rev;
+	__u16		ext_trk_tb_off;
+        __u8            reserved12_15[4];
+        __u8            pt_par_num;
+        __u8            pt_reserved1_3[3];
+        os_partition_t  partition[16];
+	__u32		cfg_col_width;
+	__u32		dat_col_width;
+	__u32		qfa_col_width;
+	__u8		cartridge[16];
+	__u8		reserved304_511[208];
+	__u32		old_filemark_list[16680/4];		/* in ADR 1.4 __u8 track_table[16680] */
+	os_ext_trk_tb_t	ext_track_tb;
+	__u8		reserved17272_17735[464];
+	os_fm_tab_t	dat_fm_tab;
+	os_fm_tab_t	qfa_fm_tab;
+	__u8		reserved25960_32767[6808];
+} os_header_t;
+
+
+/*
+ * OnStream ADRL frame
+ */
+#define OS_FRAME_SIZE   (32 * 1024 + 512)
+#define OS_DATA_SIZE    (32 * 1024)
+#define OS_AUX_SIZE     (512)
+//#define OSST_MAX_SG      2
+
+/* The OnStream tape buffer descriptor. */
+struct osst_buffer {
+  unsigned char in_use;
+  unsigned char dma;	/* DMA-able buffer */
+  int buffer_size;
+  int buffer_blocks;
+  int buffer_bytes;
+  int read_pointer;
+  int writing;
+  int midlevel_result;
+  int syscall_result;
+  struct scsi_request *last_SRpnt;
+  unsigned char *b_data;
+  os_aux_t *aux;               /* onstream AUX structure at end of each block     */
+  unsigned short use_sg;       /* zero or number of s/g segments for this adapter */
+  unsigned short sg_segs;      /* number of segments in s/g list                  */
+  unsigned short orig_sg_segs; /* number of segments allocated at first try       */
+  struct scatterlist sg[1];    /* MUST BE last item                               */
+} ;
+
+/* The OnStream tape drive descriptor */
+struct osst_tape {
+  struct scsi_driver *driver;
+  unsigned capacity;
+  struct scsi_device *device;
+  struct semaphore lock;       /* for serialization */
+  struct completion wait;      /* for SCSI commands */
+  struct osst_buffer * buffer;
+
+  /* Drive characteristics */
+  unsigned char omit_blklims;
+  unsigned char do_auto_lock;
+  unsigned char can_bsr;
+  unsigned char can_partitions;
+  unsigned char two_fm;
+  unsigned char fast_mteom;
+  unsigned char restr_dma;
+  unsigned char scsi2_logical;
+  unsigned char default_drvbuffer;  /* 0xff = don't touch, value 3 bits */
+  unsigned char pos_unknown;        /* after reset position unknown */
+  int write_threshold;
+  int timeout;			/* timeout for normal commands */
+  int long_timeout;		/* timeout for commands known to take long time*/
+
+  /* Mode characteristics */
+  struct st_modedef modes[ST_NBR_MODES];
+  int current_mode;
+
+  /* Status variables */
+  int partition;
+  int new_partition;
+  int nbr_partitions;    /* zero until partition support enabled */
+  struct st_partstat ps[ST_NBR_PARTITIONS];
+  unsigned char dirty;
+  unsigned char ready;
+  unsigned char write_prot;
+  unsigned char drv_write_prot;
+  unsigned char in_use;
+  unsigned char blksize_changed;
+  unsigned char density_changed;
+  unsigned char compression_changed;
+  unsigned char drv_buffer;
+  unsigned char density;
+  unsigned char door_locked;
+  unsigned char rew_at_close;
+  unsigned char inited;
+  int block_size;
+  int min_block;
+  int max_block;
+  int recover_count;            /* from tape opening */
+  int abort_count;
+  int write_count;
+  int read_count;
+  int recover_erreg;            /* from last status call */
+  /*
+   * OnStream specific data
+   */
+  int	   os_fw_rev;			       /* the firmware revision * 10000 */
+  unsigned char  raw;                          /* flag OnStream raw access (32.5KB block size) */
+  unsigned char  poll;                         /* flag that this drive needs polling (IDE|firmware) */
+  unsigned char  frame_in_buffer;	       /* flag that the frame as per frame_seq_number
+						* has been read into STp->buffer and is valid */
+  int      frame_seq_number;                   /* logical frame number */
+  int      logical_blk_num;                    /* logical block number */
+  unsigned first_frame_position;               /* physical frame to be transferred to/from host */
+  unsigned last_frame_position;                /* physical frame to be transferd to/from tape */
+  int      cur_frames;                         /* current number of frames in internal buffer */
+  int      max_frames;                         /* max number of frames in internal buffer */
+  char     application_sig[5];                 /* application signature */
+  unsigned char  fast_open;                    /* flag that reminds us we didn't check headers at open */
+  unsigned short wrt_pass_cntr;                /* write pass counter */
+  int      update_frame_cntr;                  /* update frame counter */
+  int      onstream_write_error;               /* write error recovery active */
+  int      header_ok;                          /* header frame verified ok */
+  int      linux_media;                        /* reading linux-specifc media */
+  int      linux_media_version;
+  os_header_t * header_cache;		       /* cache is kept for filemark positions */
+  int      filemark_cnt;
+  int      first_mark_ppos;
+  int      last_mark_ppos;
+  int      last_mark_lbn;			/* storing log_blk_num of last mark is extends ADR spec */
+  int      first_data_ppos;
+  int      eod_frame_ppos;
+  int      eod_frame_lfa;
+  int      write_type;				/* used in write error recovery */
+  int      read_error_frame;			/* used in read error recovery */
+  unsigned long cmd_start_time;
+  unsigned long max_cmd_time;
+
+#if DEBUG
+  unsigned char write_pending;
+  int nbr_finished;
+  int nbr_waits;
+  unsigned char last_cmnd[6];
+  unsigned char last_sense[16];
+#endif
+  struct gendisk *drive;
+} ;
+
+/* Values of write_type */
+#define OS_WRITE_DATA      0
+#define OS_WRITE_EOD       1
+#define OS_WRITE_NEW_MARK  2
+#define OS_WRITE_LAST_MARK 3
+#define OS_WRITE_HEADER    4
+#define OS_WRITE_FILLER    5
+
+/* Additional rw state */
+#define OS_WRITING_COMPLETE 3
diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h
new file mode 100644
index 0000000..21717d0
--- /dev/null
+++ b/drivers/scsi/osst_detect.h
@@ -0,0 +1,6 @@
+#define SIGS_FROM_OSST \
+       {"OnStream", "SC-", "", "osst"}, \
+       {"OnStream", "DI-", "", "osst"}, \
+       {"OnStream", "DP-", "", "osst"}, \
+       {"OnStream", "FW-", "", "osst"}, \
+       {"OnStream", "USB", "", "osst"}
diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h
new file mode 100644
index 0000000..ff1e610
--- /dev/null
+++ b/drivers/scsi/osst_options.h
@@ -0,0 +1,106 @@
+/*
+   The compile-time configurable defaults for the Linux SCSI tape driver.
+
+   Copyright 1995 Kai Makisara.
+   
+   Last modified: Wed Sep  2 21:24:07 1998 by root@home
+   
+   Changed (and renamed) for OnStream SCSI drives garloff@suse.de
+   2000-06-21
+
+   $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $
+*/
+
+#ifndef _OSST_OPTIONS_H
+#define _OSST_OPTIONS_H
+
+/* The minimum limit for the number of SCSI tape devices is determined by
+   OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by
+   OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */
+#define OSST_MAX_TAPES 4
+
+/* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the
+   record been read by the user program even if the tape has moved further
+   because of buffered reads. Should be set to zero to support also drives
+   that can't space backwards over records. NOTE: The tape will be
+   spaced backwards over an "accidentally" crossed filemark in any case. */
+#define OSST_IN_FILE_POS 1
+
+/* The tape driver buffer size in kilobytes. */
+/* Don't change, as this is the HW blocksize */
+#define OSST_BUFFER_BLOCKS 32
+
+/* The number of kilobytes of data in the buffer that triggers an
+   asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES
+   below. */
+#define OSST_WRITE_THRESHOLD_BLOCKS 32
+
+/* OSST_EOM_RESERVE defines the number of frames are kept in reserve for
+ *  * write error recovery when writing near end of medium. ENOSPC is returned
+ *   * when write() is called and the tape write position is within this number
+ *    * of blocks from the tape capacity. */
+#define OSST_EOM_RESERVE 300
+
+/* The maximum number of tape buffers the driver allocates. The number
+   is also constrained by the number of drives detected. Determines the
+   maximum number of concurrently active tape drives. */
+#define OSST_MAX_BUFFERS OSST_MAX_TAPES 
+
+/* Maximum number of scatter/gather segments */
+/* Fit one buffer in pages and add one for the AUX header */
+#define OSST_MAX_SG      (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1)
+
+/* The number of scatter/gather segments to allocate at first try (must be
+   smaller or equal to the maximum). */
+#define OSST_FIRST_SG    ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE)
+
+/* The size of the first scatter/gather segments (determines the maximum block
+   size for SCSI adapters not supporting scatter/gather). The default is set
+   to try to allocate the buffer as one chunk. */
+#define OSST_FIRST_ORDER  (15-PAGE_SHIFT)
+
+
+/* The following lines define defaults for properties that can be set
+   separately for each drive using the MTSTOPTIONS ioctl. */
+
+/* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a
+   file being written. Some drives can't handle two filemarks at the
+   end of data. */
+#define OSST_TWO_FM 0
+
+/* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are
+   buffered until the driver buffer is full or asynchronous write is
+   triggered. */
+#define OSST_BUFFER_WRITES 1
+
+/* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started
+   without waiting for it to finish. May cause problems in multiple
+   tape backups. */
+#define OSST_ASYNC_WRITES 1
+
+/* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
+   mode. */
+#define OSST_READ_AHEAD 1
+
+/* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first
+   read or write command after the device is opened. The door is opened
+   when the device is closed. */
+#define OSST_AUTO_LOCK 0
+
+/* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
+   direct SCSI command. The file number status is lost but this method
+   is fast with some drives. Otherwise MTEOM is done by spacing over
+   files and the file number status is retained. */
+#define OSST_FAST_MTEOM 0
+
+/* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
+   MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL
+   is zero. */
+#define OSST_SCSI2LOGICAL 0
+
+/* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
+   The default is BSD semantics. */
+#define OSST_SYSV 0
+
+
+#endif
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
new file mode 100644
index 0000000..e70dedb
--- /dev/null
+++ b/drivers/scsi/pas16.c
@@ -0,0 +1,639 @@
+#define AUTOSENSE
+#define PSEUDO_DMA
+#define FOO
+#define UNSAFE  /* Not unsafe for PAS16 -- use it */
+
+/*
+ * This driver adapted from Drew Eckhardt's Trantor T128 driver
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 666-5836
+ *
+ *  ( Based on T128 - DISTRIBUTION RELEASE 3. ) 
+ *
+ * Modified to work with the Pro Audio Spectrum/Studio 16
+ * by John Weidman.
+ *
+ *
+ * For more information, please consult 
+ *
+ * Media Vision
+ * (510) 770-8600
+ * (800) 348-7116
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * Options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *      for commands that return with a CHECK CONDITION status. 
+ *
+ * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
+ *      bytes at a time.  Since interrupts are disabled by default during
+ *      these transfers, we might need this to give reasonable interrupt
+ *      service time if the transfer size gets too large.
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking.  Not supported.
+ * 
+ * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  This
+ *	    parameter comes from the NCR5380 code.  It is NOT unsafe with
+ *	    the PAS16 and you should use it.  If you don't you will have
+ *	    a problem with dropped characters during high speed
+ *	    communications during SCSI transfers.  If you really don't
+ *	    want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
+ *	    twiddle with the transfer size in the high level code.
+ *
+ * USLEEP - enable support for devices that don't disconnect.  Untested.
+ *
+ * The card is detected and initialized in one of several ways : 
+ * 1.  Autoprobe (default) - There are many different models of
+ *     the Pro Audio Spectrum/Studio 16, and I only have one of
+ *     them, so this may require a little tweaking.  An interrupt
+ *     is triggered to autoprobe for the interrupt line.  Note:
+ *     with the newer model boards, the interrupt is set via
+ *     software after reset using the default_irq for the
+ *     current board number.
+ *
+ * 2.  With command line overrides - pas16=port,irq may be 
+ *     used on the LILO command line to override the defaults.
+ *
+ * 3.  With the PAS16_OVERRIDE compile time define.  This is 
+ *     specified as an array of address, irq tuples.  Ie, for
+ *     one board at the default 0x388 address, IRQ10, I could say 
+ *     -DPAS16_OVERRIDE={{0x388, 10}}
+ *     NOTE:  Untested.
+ *	
+ * 4.  When included as a module, with arguments passed on the command line:
+ *         pas16_irq=xx		the interrupt
+ *         pas16_addr=xx	the port
+ *     e.g. "modprobe pas16 pas16_addr=0x388 pas16_irq=5"
+ *
+ *     Note that if the override methods are used, place holders must
+ *     be specified for other boards in the system.
+ *
+ *
+ * Configuration notes :
+ *   The current driver does not support interrupt sharing with the
+ *   sound portion of the card.  If you use the same irq for the
+ *   scsi port and sound you will have problems.  Either use
+ *   a different irq for the scsi port or don't use interrupts
+ *   for the scsi port.
+ *
+ *   If you have problems with your card not being recognized, use
+ *   the LILO command line override.  Try to get it recognized without
+ *   interrupts.  Ie, for a board at the default 0x388 base port,
+ *   boot: linux pas16=0x388,255
+ *
+ *   SCSI_IRQ_NONE (255) should be specified for no interrupt,
+ *   IRQ_AUTO (254) to autoprobe for an IRQ line if overridden
+ *   on the command line.
+ *
+ *   (IRQ_AUTO == 254, SCSI_IRQ_NONE == 255 in NCR5380.h)
+ */
+ 
+#include <linux/module.h>
+
+#include <asm/system.h>
+#include <linux/signal.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "pas16.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+
+
+static int pas_maxi = 0;
+static int pas_wmaxi = 0;
+static unsigned short pas16_addr = 0;
+static int pas16_irq = 0;
+ 
+
+int scsi_irq_translate[] =
+	{ 0,  0,  1,  2,  3,  4,  5,  6, 0,  0,  7,  8,  9,  0, 10, 11 };
+
+/* The default_irqs array contains values used to set the irq into the
+ * board via software (as must be done on newer model boards without
+ * irq jumpers on the board).  The first value in the array will be
+ * assigned to logical board 0, the next to board 1, etc.
+ */
+int default_irqs[] __initdata = 
+	{  PAS16_DEFAULT_BOARD_1_IRQ,
+	   PAS16_DEFAULT_BOARD_2_IRQ,
+	   PAS16_DEFAULT_BOARD_3_IRQ,
+	   PAS16_DEFAULT_BOARD_4_IRQ
+	};
+
+static struct override {
+    unsigned short io_port;
+    int  irq;
+} overrides 
+#ifdef PAS16_OVERRIDE
+    [] __initdata = PAS16_OVERRIDE;
+#else
+    [4] __initdata = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
+	{0,IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+    unsigned short io_port;
+    int noauto;
+} bases[] __initdata = 
+	{ {PAS16_DEFAULT_BASE_1, 0},
+	  {PAS16_DEFAULT_BASE_2, 0},
+	  {PAS16_DEFAULT_BASE_3, 0},
+	  {PAS16_DEFAULT_BASE_4, 0}
+	};
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+unsigned short  pas16_offset[ 8 ] =
+    {
+	0x1c00,    /* OUTPUT_DATA_REG */
+	0x1c01,    /* INITIATOR_COMMAND_REG */
+	0x1c02,    /* MODE_REG */
+	0x1c03,    /* TARGET_COMMAND_REG */
+	0x3c00,    /* STATUS_REG ro, SELECT_ENABLE_REG wo */
+	0x3c01,    /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
+	0x3c02,    /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
+		    * START_DMA_TARGET_RECEIVE_REG wo
+		    */
+	0x3c03,    /* RESET_PARITY_INTERRUPT_REG ro,
+		    * START_DMA_INITIATOR_RECEIVE_REG wo
+		    */
+    };
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+ where something crashed or gets stuck at */
+/* 1 = blue
+ 2 = green
+ 3 = cyan
+ 4 = red
+ 5 = magenta
+ 6 = yellow
+ 7 = white
+*/
+#if 1
+#define rtrc(i) {inb(0x3da); outb(0x31, 0x3c0); outb((i), 0x3c0);}
+#else
+#define rtrc(i) {}
+#endif
+
+
+/*
+ * Function : enable_board( int  board_num, unsigned short port )
+ *
+ * Purpose :  set address in new model board
+ *
+ * Inputs : board_num - logical board number 0-3, port - base address
+ *
+ */
+
+static void __init
+	enable_board( int  board_num,  unsigned short port )
+{
+    outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
+    outb( port >> 2, MASTER_ADDRESS_PTR );
+}
+
+
+
+/*
+ * Function : init_board( unsigned short port, int irq )
+ *
+ * Purpose :  Set the board up to handle the SCSI interface
+ *
+ * Inputs : port - base address of the board,
+ *	    irq - irq to assign to the SCSI port
+ *	    force_irq - set it even if it conflicts with sound driver
+ *
+ */
+
+static void __init 
+	init_board( unsigned short io_port, int irq, int force_irq )
+{
+	unsigned int	tmp;
+	unsigned int	pas_irq_code;
+
+	/* Initialize the SCSI part of the board */
+
+	outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG );  /* Timeout counter */
+	outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET );   /* Reset TC */
+	outb( 0x01, io_port + WAIT_STATE );   /* 1 Wait state */
+
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	/* Set the SCSI interrupt pointer without mucking up the sound
+	 * interrupt pointer in the same byte.
+	 */
+	pas_irq_code = ( irq < 16 ) ? scsi_irq_translate[irq] : 0;
+	tmp = inb( io_port + IO_CONFIG_3 );
+
+	if( (( tmp & 0x0f ) == pas_irq_code) && pas_irq_code > 0 
+	    && !force_irq )
+	{
+	    printk( "pas16: WARNING: Can't use same irq as sound "
+		    "driver -- interrupts disabled\n" );
+	    /* Set up the drive parameters, disable 5380 interrupts */
+	    outb( 0x4d, io_port + SYS_CONFIG_4 );
+	}
+	else
+	{
+	    tmp = (  tmp & 0x0f ) | ( pas_irq_code << 4 );
+	    outb( tmp, io_port + IO_CONFIG_3 );
+
+	    /* Set up the drive parameters and enable 5380 interrupts */
+	    outb( 0x6d, io_port + SYS_CONFIG_4 );
+	}
+}
+
+
+/*
+ * Function : pas16_hw_detect( unsigned short board_num )
+ *
+ * Purpose : determine if a pas16 board is present
+ * 
+ * Inputs : board_num - logical board number ( 0 - 3 )
+ *
+ * Returns : 0 if board not found, 1 if found.
+ */
+
+static int __init 
+     pas16_hw_detect( unsigned short  board_num )
+{
+    unsigned char	board_rev, tmp;
+    unsigned short	io_port = bases[ board_num ].io_port;
+
+    /* See if we can find a PAS16 board at the address associated
+     * with this logical board number.
+     */
+
+    /* First, attempt to take a newer model board out of reset and
+     * give it a base address.  This shouldn't affect older boards.
+     */
+    enable_board( board_num, io_port );
+
+    /* Now see if it looks like a PAS16 board */
+    board_rev = inb( io_port + PCB_CONFIG );
+
+    if( board_rev == 0xff )
+	return 0;
+
+    tmp = board_rev ^ 0xe0;
+
+    outb( tmp, io_port + PCB_CONFIG );
+    tmp = inb( io_port + PCB_CONFIG );
+    outb( board_rev, io_port + PCB_CONFIG );
+
+    if( board_rev != tmp ) 	/* Not a PAS-16 */
+	return 0;
+
+    if( ( inb( io_port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 ) 
+	return 0;  	/* return if no SCSI interface found */
+
+    /* Mediavision has some new model boards that return ID bits
+     * that indicate a SCSI interface, but they're not (LMS).  We'll
+     * put in an additional test to try to weed them out.
+     */
+
+    outb( 0x01, io_port + WAIT_STATE ); 	/* 1 Wait state */
+    NCR5380_write( MODE_REG, 0x20 );		/* Is it really SCSI? */
+    if( NCR5380_read( MODE_REG ) != 0x20 )	/* Write to a reg.    */
+	return 0;				/* and try to read    */
+    NCR5380_write( MODE_REG, 0x00 );		/* it back.	      */
+    if( NCR5380_read( MODE_REG ) != 0x00 )
+	return 0;
+
+    return 1;
+}
+
+
+/*
+ * Function : pas16_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ */
+
+void __init pas16_setup(char *str, int *ints)
+{
+    static int commandline_current = 0;
+    int i;
+    if (ints[0] != 2) 
+	printk("pas16_setup : usage pas16=io_port,irq\n");
+    else 
+	if (commandline_current < NO_OVERRIDES) {
+	    overrides[commandline_current].io_port = (unsigned short) ints[1];
+	    overrides[commandline_current].irq = ints[2];
+	    for (i = 0; i < NO_BASES; ++i)
+		if (bases[i].io_port == (unsigned short) ints[1]) {
+ 		    bases[i].noauto = 1;
+		    break;
+		}
+	    ++commandline_current;
+	}
+}
+
+/* 
+ * Function : int pas16_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : detects and initializes PAS16 controllers
+ *	that were autoprobed, overridden on the LILO command line, 
+ *	or specified at compile time.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ * 
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int __init pas16_detect(Scsi_Host_Template * tpnt)
+{
+    static int current_override = 0;
+    static unsigned short current_base = 0;
+    struct Scsi_Host *instance;
+    unsigned short io_port;
+    int  count;
+
+    tpnt->proc_name = "pas16";
+    tpnt->proc_info = &pas16_proc_info;
+
+    if (pas16_addr != 0) {
+	overrides[0].io_port = pas16_addr;
+	/*
+	*  This is how we avoid seeing more than
+	*  one host adapter at the same I/O port.
+	*  Cribbed shamelessly from pas16_setup().
+	*/
+	for (count = 0; count < NO_BASES; ++count)
+	    if (bases[count].io_port == pas16_addr) {
+ 		    bases[count].noauto = 1;
+		    break;
+	}
+    }
+    if (pas16_irq != 0)
+	overrides[0].irq = pas16_irq;
+
+    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+	io_port = 0;
+
+	if (overrides[current_override].io_port)
+	{
+	    io_port = overrides[current_override].io_port;
+	    enable_board( current_override, io_port );
+	    init_board( io_port, overrides[current_override].irq, 1 );
+	}
+	else
+	    for (; !io_port && (current_base < NO_BASES); ++current_base) {
+#if (PDEBUG & PDEBUG_INIT)
+    printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
+#endif
+		if ( !bases[current_base].noauto &&
+		     pas16_hw_detect( current_base ) ){
+			io_port = bases[current_base].io_port;
+			init_board( io_port, default_irqs[ current_base ], 0 ); 
+#if (PDEBUG & PDEBUG_INIT)
+			printk("scsi-pas16 : detected board.\n");
+#endif
+		}
+    }
+
+
+#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
+	printk("scsi-pas16 : io_port = %04x\n", (unsigned int) io_port);
+#endif
+
+	if (!io_port)
+	    break;
+
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if(instance == NULL)
+		break;
+		
+	instance->io_port = io_port;
+
+	NCR5380_init(instance, 0);
+
+	if (overrides[current_override].irq != IRQ_AUTO)
+	    instance->irq = overrides[current_override].irq;
+	else 
+	    instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
+
+	if (instance->irq != SCSI_IRQ_NONE) 
+	    if (request_irq(instance->irq, pas16_intr, SA_INTERRUPT, "pas16", instance)) {
+		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
+		    instance->host_no, instance->irq);
+		instance->irq = SCSI_IRQ_NONE;
+	    } 
+
+	if (instance->irq == SCSI_IRQ_NONE) {
+	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+	    /* Disable 5380 interrupts, leave drive params the same */
+	    outb( 0x4d, io_port + SYS_CONFIG_4 );
+	    outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
+	}
+
+#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
+	printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
+#endif
+
+	printk("scsi%d : at 0x%04x", instance->host_no, (int) 
+	    instance->io_port);
+	if (instance->irq == SCSI_IRQ_NONE)
+	    printk (" interrupts disabled");
+	else 
+	    printk (" irq %d", instance->irq);
+	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
+	    CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	++current_override;
+	++count;
+    }
+    return count;
+}
+
+/*
+ * Function : int pas16_biosparam(Disk *disk, struct block_device *dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *	the specified device / size.
+ * 
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ *	major / minor, ip[] = {heads, sectors, cylinders}  
+ *
+ * Returns : always 0 (success), initializes ip
+ *	
+ */
+
+/* 
+ * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+ */
+
+int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int * ip)
+{
+  int size = capacity;
+  ip[0] = 64;
+  ip[1] = 32;
+  ip[2] = size >> 11;		/* I think I have it as /(32*64) */
+  if( ip[2] > 1024 ) {		/* yes, >, not >= */
+	ip[0]=255;
+	ip[1]=63;
+	ip[2]=size/(63*255);
+	if( ip[2] > 1023 )	/* yes >1023... */
+		ip[2] = 1023;
+  }
+
+  return 0;
+}
+
+/*
+ * Function : int NCR5380_pread (struct Scsi_Host *instance, 
+ *	unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 
+ *	dst
+ * 
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+ */
+
+static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
+    int len) {
+    register unsigned char  *d = dst;
+    register unsigned short reg = (unsigned short) (instance->io_port + 
+	P_DATA_REG_OFFSET);
+    register int i = len;
+    int ii = 0;
+
+    while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
+	 ++ii;
+
+    insb( reg, d, i );
+
+    if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+	outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+	printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
+	    instance->host_no);
+	return -1;
+    }
+   if (ii > pas_maxi)
+      pas_maxi = ii;
+    return 0;
+}
+
+/*
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
+ *	unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ *	src
+ * 
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+ */
+
+static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
+    int len) {
+    register unsigned char *s = src;
+    register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
+    register int i = len;
+    int ii = 0;
+
+    while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
+	 ++ii;
+ 
+    outsb( reg, s, i );
+
+    if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+	outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+	printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
+	    instance->host_no);
+	return -1;
+    }
+    if (ii > pas_maxi)
+	 pas_wmaxi = ii;
+    return 0;
+}
+
+#include "NCR5380.c"
+
+static int pas16_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	NCR5380_exit(shost);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name           = "Pro Audio Spectrum-16 SCSI",
+	.detect         = pas16_detect,
+	.release        = pas16_release,
+	.queuecommand   = pas16_queue_command,
+	.eh_abort_handler = pas16_abort,
+	.eh_bus_reset_handler = pas16_bus_reset,
+	.eh_device_reset_handler = pas16_device_reset,
+	.eh_host_reset_handler = pas16_host_reset,
+	.bios_param     = pas16_biosparam, 
+	.can_queue      = CAN_QUEUE,
+	.this_id        = 7,
+	.sg_tablesize   = SG_ALL,
+	.cmd_per_lun    = CMD_PER_LUN,
+	.use_clustering = DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
+
+#ifdef MODULE
+module_param(pas16_addr, ushort, 0);
+module_param(pas16_irq, int, 0);
+#endif
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
new file mode 100644
index 0000000..58d4d67
--- /dev/null
+++ b/drivers/scsi/pas16.h
@@ -0,0 +1,179 @@
+/*
+ * This driver adapted from Drew Eckhardt's Trantor T128 driver
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 666-5836
+ *
+ *  ( Based on T128 - DISTRIBUTION RELEASE 3. ) 
+ *
+ * Modified to work with the Pro Audio Spectrum/Studio 16
+ * by John Weidman.
+ *
+ *
+ * For more information, please consult 
+ *
+ * Media Vision
+ * (510) 770-8600
+ * (800) 348-7116
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+
+#ifndef PAS16_H
+#define PAS16_H
+
+#define PAS16_PUBLIC_RELEASE 3
+
+#define PDEBUG_INIT	0x1
+#define PDEBUG_TRANSFER 0x2
+
+#define PAS16_DEFAULT_BASE_1  0x388
+#define PAS16_DEFAULT_BASE_2  0x384
+#define PAS16_DEFAULT_BASE_3  0x38c
+#define PAS16_DEFAULT_BASE_4  0x288
+
+#define PAS16_DEFAULT_BOARD_1_IRQ 10
+#define PAS16_DEFAULT_BOARD_2_IRQ 12
+#define PAS16_DEFAULT_BOARD_3_IRQ 14
+#define PAS16_DEFAULT_BOARD_4_IRQ 15
+
+
+/*
+ * The Pro Audio Spectrum boards are I/O mapped. They use a Zilog 5380
+ * SCSI controller, which is the equivalent of NCR's 5380.  "Pseudo-DMA"
+ * architecture is used, where a PAL drives the DMA signals on the 5380
+ * allowing fast, blind transfers with proper handshaking. 
+ */
+
+
+/* The Time-out Counter register is used to safe-guard against a stuck
+ * bus (in the case of RDY driven handshake) or a stuck byte (if 16-Bit
+ * DMA conversion is used).  The counter uses a 28.224MHz clock
+ * divided by 14 as its clock source.  In the case of a stuck byte in
+ * the holding register, an interrupt is generated (and mixed with the
+ * one with the drive) using the CD-ROM interrupt pointer.
+ */
+ 
+#define P_TIMEOUT_COUNTER_REG	0x4000
+#define P_TC_DISABLE	0x80	/* Set to 0 to enable timeout int. */
+				/* Bits D6-D0 contain timeout count */
+
+
+#define P_TIMEOUT_STATUS_REG_OFFSET	0x4001
+#define P_TS_TIM		0x80	/* check timeout status */
+					/* Bits D6-D4 N/U */
+#define P_TS_ARM_DRQ_INT	0x08	/* Arm DRQ Int.  When set high,
+					 * the next rising edge will
+					 * cause a CD-ROM interrupt.
+					 * When set low, the interrupt
+					 * will be cleared.  There is
+					 * no status available for
+					 * this interrupt.
+					 */
+#define P_TS_ENABLE_TO_ERR_INTERRUPT	/* Enable timeout error int. */
+#define P_TS_ENABLE_WAIT		/* Enable Wait */
+
+#define P_TS_CT			0x01	/* clear timeout. Note: writing
+					 * to this register clears the
+					 * timeout error int. or status
+					 */
+
+
+/*
+ * The data register reads/writes to/from the 5380 in pseudo-DMA mode
+ */ 
+
+#define P_DATA_REG_OFFSET	0x5c00	/* rw */
+
+#define P_STATUS_REG_OFFSET	0x5c01	/* ro */
+#define P_ST_RDY		0x80	/* 5380 DDRQ Status */
+
+#define P_IRQ_STATUS		0x5c03
+#define P_IS_IRQ		0x80	/* DIRQ status */
+
+#define PCB_CONFIG 0x803
+#define MASTER_ADDRESS_PTR 0x9a01  /* Fixed position - no relo */
+#define SYS_CONFIG_4 0x8003
+#define WAIT_STATE 0xbc00
+#define OPERATION_MODE_1 0xec03
+#define IO_CONFIG_3 0xf002
+
+
+#ifndef ASM
+static int pas16_abort(Scsi_Cmnd *);
+static int pas16_biosparam(struct scsi_device *, struct block_device *,
+			   sector_t, int*);
+static int pas16_detect(Scsi_Host_Template *);
+static int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int pas16_bus_reset(Scsi_Cmnd *);
+static int pas16_host_reset(Scsi_Cmnd *);
+static int pas16_device_reset(Scsi_Cmnd *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32 
+#endif
+
+#ifndef HOSTS_C
+
+#define NCR5380_implementation_fields \
+    volatile unsigned short io_port
+
+#define NCR5380_local_declare() \
+    volatile unsigned short io_port
+
+#define NCR5380_setup(instance) \
+    io_port = (instance)->io_port
+
+#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] )
+
+#if !(PDEBUG & PDEBUG_TRANSFER) 
+#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
+#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
+#else
+#define NCR5380_read(reg)						\
+    (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\
+    , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) )
+
+#define NCR5380_write(reg, value) 					\
+    (printk("scsi%d : write %02x to register %d at io_port %04x\n", 	\
+	    instance->hostno, (value), (reg), PAS16_io_port(reg)),	\
+    outb( (value),PAS16_io_port(reg) ) )
+
+#endif
+
+
+#define NCR5380_intr pas16_intr
+#define do_NCR5380_intr do_pas16_intr
+#define NCR5380_queue_command pas16_queue_command
+#define NCR5380_abort pas16_abort
+#define NCR5380_device_reset pas16_device_reset
+#define NCR5380_bus_reset pas16_bus_reset
+#define NCR5380_host_reset pas16_host_reset
+#define NCR5380_proc_info pas16_proc_info
+
+/* 15 14 12 10 7 5 3 
+   1101 0100 1010 1000 */
+   
+#define PAS16_IRQS 0xd4a8 
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* PAS16_H */
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
new file mode 100644
index 0000000..60ce1cc
--- /dev/null
+++ b/drivers/scsi/pci2000.c
@@ -0,0 +1,834 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
+ *
+ * pci2000.c - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ *
+ *	Revisions	1.10	Jan-21-1999
+ *		- Fixed sign on message to reflect proper controller name.
+ *		- Added support for RAID status monitoring and control.
+ *
+ *  Revisions	1.11	Mar-22-1999
+ *		- Fixed control timeout to not lock up the entire system if
+ *		  controller goes offline completely.
+ *
+ *	Revisions 1.12		Mar-26-1999
+ *		- Fixed spinlock and PCI configuration.
+ *
+ *	Revisions 1.20		Mar-27-2000
+ *		- Added support for dynamic DMA
+ *
+ ****************************************************************************/
+#define PCI2000_VERSION		"1.20"
+
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/spinlock.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "pci2000.h"
+#include "psi_roy.h"
+
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+#define DEB(x) x
+#define STOP_HERE	{int st;for(st=0;st<100;st++){st=1;}}
+#else
+#define DEB(x)
+#define STOP_HERE
+#endif
+
+typedef struct
+	{
+	unsigned int	address;
+	unsigned int	length;
+	}	SCATGATH, *PSCATGATH;
+
+typedef struct
+	{
+	Scsi_Cmnd		*SCpnt;
+	PSCATGATH		 scatGath;
+	dma_addr_t		 scatGathDma;
+	UCHAR			*cdb;
+	dma_addr_t		 cdbDma; 
+	UCHAR			 tag;
+	}	DEV2000, *PDEV2000;
+
+typedef struct
+	{
+	ULONG			 basePort;
+	ULONG			 mb0;
+	ULONG			 mb1;
+	ULONG			 mb2;
+	ULONG			 mb3;
+	ULONG			 mb4;
+	ULONG			 cmd;
+	ULONG			 tag;
+	ULONG			 irqOwned;
+	struct pci_dev	*pdev;
+	DEV2000	 		 dev[MAX_BUS][MAX_UNITS];
+	}	ADAPTER2000, *PADAPTER2000;
+
+#define HOSTDATA(host) ((PADAPTER2000)&host->hostdata)
+#define consistentLen (MAX_BUS * MAX_UNITS * (16 * sizeof (SCATGATH) + MAX_COMMAND_SIZE))
+
+
+static struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapter
+static			int				NumAdapters = 0;
+/****************************************************************
+ *	Name:			WaitReady	:LOCAL
+ *
+ *	Description:	Wait for controller ready.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReady (PADAPTER2000 padapter)
+	{
+	ULONG	z;
+
+	for ( z = 0;  z < (TIMEOUT_COMMAND * 4);  z++ )
+		{
+		if ( !inb_p (padapter->cmd) )
+			return FALSE;
+		udelay (250);
+		};								
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:			WaitReadyLong	:LOCAL
+ *
+ *	Description:	Wait for controller ready.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE on not ready.
+ *
+ ****************************************************************/
+static int WaitReadyLong (PADAPTER2000 padapter)
+	{
+	ULONG	z;
+
+	for ( z = 0;  z < (5000 * 4);  z++ )
+		{
+		if ( !inb_p (padapter->cmd) )
+			return FALSE;
+		udelay (250);
+		};								
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	OpDone	:LOCAL
+ *
+ *	Description:	Clean up operation and issue done to caller.
+ *
+ *	Parameters:		SCpnt	- Pointer to SCSI command structure.
+ *					status	- Caller status.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void OpDone (Scsi_Cmnd *SCpnt, ULONG status)
+	{
+	SCpnt->result = status;
+	SCpnt->scsi_done (SCpnt);
+	}
+/****************************************************************
+ *	Name:	Command		:LOCAL
+ *
+ *	Description:	Issue queued command to the PCI-2000.
+ *
+ *	Parameters:		padapter - Pointer to adapter information structure.
+ *					cmd		 - PCI-2000 command byte.
+ *
+ *	Returns:		Non-zero command tag if operation is accepted.
+ *
+ ****************************************************************/
+static UCHAR Command (PADAPTER2000 padapter, UCHAR cmd)
+	{
+	outb_p (cmd, padapter->cmd);
+	if ( WaitReady (padapter) )
+		return 0;
+
+	if ( inw_p (padapter->mb0) )
+		return 0;
+
+	return inb_p (padapter->mb1);
+	}
+/****************************************************************
+ *	Name:	BuildSgList		:LOCAL
+ *
+ *	Description:	Build the scatter gather list for controller.
+ *
+ *	Parameters:		SCpnt	 - Pointer to SCSI command structure.
+ *					padapter - Pointer to adapter information structure.
+ *					pdev	 - Pointer to adapter device structure.
+ *
+ *	Returns:		Non-zero in not scatter gather.
+ *
+ ****************************************************************/
+static int BuildSgList (Scsi_Cmnd *SCpnt, PADAPTER2000 padapter, PDEV2000 pdev)
+	{
+	int					 z;
+	int					 zc;
+	struct scatterlist	*sg;
+
+	if ( SCpnt->use_sg )
+		{
+		sg = (struct scatterlist *)SCpnt->request_buffer;
+		zc = pci_map_sg (padapter->pdev, sg, SCpnt->use_sg, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+		for ( z = 0;  z < zc;  z++ )
+			{
+			pdev->scatGath[z].address = cpu_to_le32 (sg_dma_address (sg));
+			pdev->scatGath[z].length = cpu_to_le32 (sg_dma_len (sg++));
+			}
+		outl (pdev->scatGathDma, padapter->mb2);
+		outl ((zc << 24) | SCpnt->request_bufflen, padapter->mb3);
+		return FALSE;
+		}
+	if ( !SCpnt->request_bufflen)
+		{
+		outl (0, padapter->mb2);
+		outl (0, padapter->mb3);
+		return TRUE;
+		}
+	SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen, scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+	outl (SCpnt->SCp.have_data_in, padapter->mb2);
+	outl (SCpnt->request_bufflen, padapter->mb3);
+	return TRUE;
+	}
+/*********************************************************************
+ *	Name:	PsiRaidCmd
+ *
+ *	Description:	Execute a simple command.
+ *
+ *	Parameters:		padapter - Pointer to adapter control structure.
+ *					cmd		 - Roy command byte.
+ *
+ *	Returns:		Return error status.
+ *
+ ********************************************************************/
+static int PsiRaidCmd (PADAPTER2000 padapter, char cmd)
+	{
+	if ( WaitReady (padapter) )						// test for command register ready
+		return DID_TIME_OUT;
+	outb_p (cmd, padapter->cmd);					// issue command
+	if ( WaitReadyLong (padapter) )					// wait for adapter ready
+		return DID_TIME_OUT;
+	return DID_OK;
+	}
+/****************************************************************
+ *	Name:	Irq_Handler	:LOCAL
+ *
+ *	Description:	Interrupt handler.
+ *
+ *	Parameters:		irq		- Hardware IRQ number.
+ *					dev_id	-
+ *					regs	-
+ *
+ *	Returns:		TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static irqreturn_t Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	struct Scsi_Host   *shost = NULL;	// Pointer to host data block
+	PADAPTER2000		padapter;		// Pointer to adapter control structure
+	PDEV2000			pdev;
+	Scsi_Cmnd		   *SCpnt;
+	UCHAR				tag = 0;
+	UCHAR				tag0;
+	ULONG				error;
+	int					pun;
+	int					bus;
+	int					z;
+    unsigned long		flags;
+    int handled = 0;
+
+	DEB(printk ("\npci2000 received interrupt "));
+	for ( z = 0; z < NumAdapters;  z++ )										// scan for interrupt to process
+		{
+		if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
+			{
+			tag = inb_p (HOSTDATA(PsiHost[z])->tag);
+			if (  tag )
+				{
+				shost = PsiHost[z];
+				break;
+				}
+			}
+		}
+
+	if ( !shost )
+		{
+		DEB (printk ("\npci2000: not my interrupt"));
+		goto out;
+		}
+
+    handled = 1;
+	spin_lock_irqsave(shost->host_lock, flags);
+	padapter = HOSTDATA(shost);
+
+	tag0 = tag & 0x7F;															// mask off the error bit
+	for ( bus = 0;  bus < MAX_BUS;  bus++ )										// scan the busses
+    	{
+		for ( pun = 0;  pun < MAX_UNITS;  pun++ )								// scan the targets
+    		{
+			pdev = &padapter->dev[bus][pun];
+			if ( !pdev->tag )
+    			continue;
+			if ( pdev->tag == tag0 )											// is this it?
+				{
+				pdev->tag = 0;
+				SCpnt = pdev->SCpnt;
+				goto unmapProceed;
+    			}
+			}
+    	}
+
+	outb_p (0xFF, padapter->tag);												// clear the op interrupt
+	outb_p (CMD_DONE, padapter->cmd);											// complete the op
+	goto irq_return;															// done, but, with what?
+
+unmapProceed:;
+	if ( !bus )
+		{
+		switch ( SCpnt->cmnd[0] )
+			{
+			case SCSIOP_TEST_UNIT_READY:
+				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE);
+				goto irqProceed;
+			case SCSIOP_READ_CAPACITY:
+				pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, 8, PCI_DMA_FROMDEVICE);
+				goto irqProceed;
+			case SCSIOP_VERIFY:
+			case SCSIOP_START_STOP_UNIT:
+			case SCSIOP_MEDIUM_REMOVAL:
+				goto irqProceed;
+			}
+		}
+	if ( SCpnt->SCp.have_data_in )
+		pci_unmap_single (padapter->pdev, SCpnt->SCp.have_data_in, SCpnt->request_bufflen, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+	else 
+		{
+		if ( SCpnt->use_sg )
+			pci_unmap_sg (padapter->pdev, (struct scatterlist *)SCpnt->request_buffer, SCpnt->use_sg, scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+		}
+
+irqProceed:;
+	if ( tag & ERR08_TAGGED )												// is there an error here?
+		{
+		if ( WaitReady (padapter) )
+			{
+			OpDone (SCpnt, DID_TIME_OUT << 16);
+			goto irq_return;
+			}
+
+		outb_p (tag0, padapter->mb0);										// get real error code
+		outb_p (CMD_ERROR, padapter->cmd);
+		if ( WaitReady (padapter) )											// wait for controller to suck up the op
+			{
+			OpDone (SCpnt, DID_TIME_OUT << 16);
+			goto irq_return;
+			}
+
+		error = inl (padapter->mb0);										// get error data
+		outb_p (0xFF, padapter->tag);										// clear the op interrupt
+		outb_p (CMD_DONE, padapter->cmd);									// complete the op
+
+		DEB (printk ("status: %lX ", error));
+		if ( error == 0x00020002 )											// is this error a check condition?
+			{
+			if ( bus )														// are we doint SCSI commands?
+				{
+				OpDone (SCpnt, (DID_OK << 16) | 2);
+				goto irq_return;
+				}
+			if ( *SCpnt->cmnd == SCSIOP_TEST_UNIT_READY )
+				OpDone (SCpnt, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);	// test caller we have sense data too
+			else
+				OpDone (SCpnt, DID_ERROR << 16);
+			goto irq_return;
+			}
+		OpDone (SCpnt, DID_ERROR << 16);
+		goto irq_return;
+		}
+
+	outb_p (0xFF, padapter->tag);											// clear the op interrupt
+	outb_p (CMD_DONE, padapter->cmd);										// complete the op
+	OpDone (SCpnt, DID_OK << 16);
+
+irq_return:
+    spin_unlock_irqrestore(shost->host_lock, flags);
+out:
+    return IRQ_RETVAL(handled);
+}
+/****************************************************************
+ *	Name:	Pci2000_QueueCommand
+ *
+ *	Description:	Process a queued command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *					done  - Pointer to done function to call.
+ *
+ *	Returns:		Status code.
+ *
+ ****************************************************************/
+int Pci2000_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+	{
+	UCHAR		   *cdb = (UCHAR *)SCpnt->cmnd;					// Pointer to SCSI CDB
+	PADAPTER2000	padapter = HOSTDATA(SCpnt->device->host);			// Pointer to adapter control structure
+	int				rc		 = -1;								// command return code
+	UCHAR			bus		 = SCpnt->device->channel;
+	UCHAR			pun		 = SCpnt->device->id;
+	UCHAR			lun		 = SCpnt->device->lun;
+	UCHAR			cmd;
+	PDEV2000		pdev	 = &padapter->dev[bus][pun];
+
+	if ( !done )
+		{
+		printk("pci2000_queuecommand: %02X: done can't be NULL\n", *cdb);
+		return 0;
+		}
+
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.have_data_in = 0;
+	pdev->SCpnt = SCpnt;  									// Save this command data
+
+	if ( WaitReady (padapter) )
+		{
+		rc = DID_ERROR;
+		goto finished;
+		}
+
+	outw_p (pun | (lun << 8), padapter->mb0);
+
+	if ( bus )
+		{
+		DEB (if(*cdb) printk ("\nCDB: %X-  %X %X %X %X %X %X %X %X %X %X ", SCpnt->cmd_len, cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9]));
+		DEB (if(*cdb) printk ("\ntimeout_per_command: %d, timeout_total: %d, timeout: %d, internal_timout: %d", SCpnt->timeout_per_command,
+							  SCpnt->timeout_total, SCpnt->timeout, SCpnt->internal_timeout));
+		outl (SCpnt->timeout_per_command, padapter->mb1);
+		outb_p (CMD_SCSI_TIMEOUT, padapter->cmd);
+		if ( WaitReady (padapter) )
+			{
+			rc = DID_ERROR;
+			goto finished;
+			}
+
+		outw_p (pun | (lun << 8), padapter->mb0);
+		outw_p (SCpnt->cmd_len << 8, padapter->mb0 + 2);
+		memcpy (pdev->cdb, cdb, MAX_COMMAND_SIZE);
+
+		outl (pdev->cdbDma, padapter->mb1);
+		if ( BuildSgList (SCpnt, padapter, pdev) )
+			cmd = CMD_SCSI_THRU;
+		else
+			cmd = CMD_SCSI_THRU_SG;
+		if ( (pdev->tag = Command (padapter, cmd)) == 0 )
+			rc = DID_TIME_OUT;
+		goto finished;
+		}
+	else
+		{
+		if ( lun )
+			{
+			rc = DID_BAD_TARGET;
+			goto finished;
+			}
+		}
+
+	switch ( *cdb )
+		{
+		case SCSIOP_INQUIRY:   					// inquiry CDB
+			if ( cdb[2] == SC_MY_RAID )
+				{
+				switch ( cdb[3] ) 
+					{
+					case MY_SCSI_REBUILD:
+						OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_REBUILD) << 16);
+						return 0;
+					case MY_SCSI_ALARMMUTE:
+						OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_MUTE) << 16);
+						return 0;
+					case MY_SCSI_DEMOFAIL:
+						OpDone (SCpnt, PsiRaidCmd (padapter, CMD_RAID_FAIL) << 16);
+						return 0;
+					default:
+						if ( SCpnt->use_sg )
+							{
+							rc = DID_ERROR;
+							goto finished;
+							}
+						else
+							{
+							SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, SCpnt->request_bufflen,
+													  scsi_to_pci_dma_dir(SCpnt->sc_data_direction));
+							outl (SCpnt->SCp.have_data_in, padapter->mb2);
+							}
+						outl (cdb[5], padapter->mb0);
+						outl (cdb[3], padapter->mb3);
+						cmd = CMD_DASD_RAID_RQ;
+						break;
+					}
+				break;
+				}
+			
+			if ( SCpnt->use_sg )
+				{
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev,
+									  ((struct scatterlist *)SCpnt->request_buffer)->address,
+									  SCpnt->request_bufflen,
+									  scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+				}
+			else
+				{
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer,
+									  SCpnt->request_bufflen,
+									  scsi_to_pci_dma_dir (SCpnt->sc_data_direction));
+				}
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
+			outl (SCpnt->request_bufflen, padapter->mb3);
+			cmd = CMD_DASD_SCSI_INQ;
+			break;
+
+		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
+			SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->sense_buffer, sizeof (SCpnt->sense_buffer), PCI_DMA_FROMDEVICE);
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
+			outl (sizeof (SCpnt->sense_buffer), padapter->mb3);
+			cmd = CMD_TEST_READY;
+			break;
+
+		case SCSIOP_READ_CAPACITY:			  	// read capacity CDB
+			if ( SCpnt->use_sg )
+				{
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, ((struct scatterlist *)(SCpnt->request_buffer))->address,
+										  8, PCI_DMA_FROMDEVICE);
+				}
+			else
+				SCpnt->SCp.have_data_in = pci_map_single (padapter->pdev, SCpnt->request_buffer, 8, PCI_DMA_FROMDEVICE);
+			outl (SCpnt->SCp.have_data_in, padapter->mb2);
+			outl (8, padapter->mb3);
+			cmd = CMD_DASD_CAP;
+			break;
+		case SCSIOP_VERIFY:						// verify CDB
+			outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+			outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+			cmd = CMD_READ_SG;
+			break;
+		case SCSIOP_READ:						// read10 CDB
+			outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+			outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+			if ( BuildSgList (SCpnt, padapter, pdev) )
+				cmd = CMD_READ;
+			else
+				cmd = CMD_READ_SG;
+			break;
+		case SCSIOP_READ6:						// read6  CDB
+			outw_p (cdb[4], padapter->mb0 + 2);
+			outl ((SCSI2LONG (&cdb[1])) & 0x001FFFFF, padapter->mb1);
+			if ( BuildSgList (SCpnt, padapter, pdev) )
+				cmd = CMD_READ;
+			else
+				cmd = CMD_READ_SG;
+			break;
+		case SCSIOP_WRITE:						// write10 CDB
+			outw_p ((USHORT)cdb[8] | ((USHORT)cdb[7] << 8), padapter->mb0 + 2);
+			outl (XSCSI2LONG (&cdb[2]), padapter->mb1);
+			if ( BuildSgList (SCpnt, padapter, pdev) )
+				cmd = CMD_WRITE;
+			else
+				cmd = CMD_WRITE_SG;
+			break;
+		case SCSIOP_WRITE6:						// write6  CDB
+			outw_p (cdb[4], padapter->mb0 + 2);
+			outl ((SCSI2LONG (&cdb[1])) & 0x001FFFFF, padapter->mb1);
+			if ( BuildSgList (SCpnt, padapter, pdev) )
+				cmd = CMD_WRITE;
+			else
+				cmd = CMD_WRITE_SG;
+			break;
+		case SCSIOP_START_STOP_UNIT:
+			cmd = CMD_EJECT_MEDIA;
+			break;
+		case SCSIOP_MEDIUM_REMOVAL:
+			switch ( cdb[4] )
+				{
+				case 0:
+					cmd = CMD_UNLOCK_DOOR;
+					break;
+				case 1:
+					cmd = CMD_LOCK_DOOR;
+					break;
+				default:
+					cmd = 0;
+					break;
+				}
+			if ( cmd )
+				break;
+		default:
+			DEB (printk ("pci2000_queuecommand: Unsupported command %02X\n", *cdb));
+			OpDone (SCpnt, DID_ERROR << 16);
+			return 0;
+		}
+
+	if ( (pdev->tag = Command (padapter, cmd)) == 0 )
+		rc = DID_TIME_OUT;
+finished:;
+	if ( rc != -1 )
+		OpDone (SCpnt, rc << 16);
+	return 0;
+	}
+/****************************************************************
+ *	Name:	Pci2000_Detect
+ *
+ *	Description:	Detect and initialize our boards.
+ *
+ *	Parameters:		tpnt - Pointer to SCSI host template structure.
+ *
+ *	Returns:		Number of adapters installed.
+ *
+ ****************************************************************/
+int Pci2000_Detect (Scsi_Host_Template *tpnt)
+	{
+	int					found = 0;
+	int					installed = 0;
+	struct Scsi_Host   *pshost;
+	PADAPTER2000	    padapter;
+	int					z, zz;
+	int					setirq;
+	struct pci_dev	   *pdev = NULL;
+	UCHAR			   *consistent;
+	dma_addr_t			consistentDma;
+
+	while ( (pdev = pci_find_device (VENDOR_PSI, DEVICE_ROY_1, pdev)) != NULL )
+		{
+		if (pci_enable_device(pdev))
+			continue;
+		pshost = scsi_register (tpnt, sizeof(ADAPTER2000));
+		if(pshost == NULL)
+			continue;
+		padapter = HOSTDATA(pshost);
+
+		padapter->basePort = pci_resource_start (pdev, 1);
+		DEB (printk ("\nBase Regs = %#04X", padapter->basePort));			// get the base I/O port address
+		padapter->mb0	= padapter->basePort + RTR_MAILBOX;		   			// get the 32 bit mail boxes
+		padapter->mb1	= padapter->basePort + RTR_MAILBOX + 4;
+		padapter->mb2	= padapter->basePort + RTR_MAILBOX + 8;
+		padapter->mb3	= padapter->basePort + RTR_MAILBOX + 12;
+		padapter->mb4	= padapter->basePort + RTR_MAILBOX + 16;
+		padapter->cmd	= padapter->basePort + RTR_LOCAL_DOORBELL;			// command register
+		padapter->tag	= padapter->basePort + RTR_PCI_DOORBELL;			// tag/response register
+		padapter->pdev = pdev;
+
+		if ( WaitReady (padapter) )
+			goto unregister;
+		outb_p (0x84, padapter->mb0);
+		outb_p (CMD_SPECIFY, padapter->cmd);
+		if ( WaitReady (padapter) )
+			goto unregister;
+
+		consistent = pci_alloc_consistent (pdev, consistentLen, &consistentDma);
+		if ( !consistent )
+			{
+			printk ("Unable to allocate DMA memory for PCI-2000 controller.\n");
+			goto unregister;
+			}
+		
+		scsi_set_device(pshost, &pdev->dev);
+		pshost->irq = pdev->irq;
+		setirq = 1;
+		padapter->irqOwned = 0;
+		for ( z = 0;  z < installed;  z++ )									// scan for shared interrupts
+			{
+			if ( PsiHost[z]->irq == pshost->irq )							// if shared then, don't posses
+				setirq = 0;
+			}
+		if ( setirq )												// if not shared, posses
+			{
+			if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2000", padapter) < 0 )
+				{
+				if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2000", padapter) < 0 )
+					{
+					printk ("Unable to allocate IRQ for PCI-2000 controller.\n");
+					pci_free_consistent (pdev, consistentLen, consistent, consistentDma);
+					goto unregister;
+					}
+				}
+			padapter->irqOwned = pshost->irq;						// set IRQ as owned
+			}
+		PsiHost[installed]	= pshost;										// save SCSI_HOST pointer
+
+		pshost->io_port		= padapter->basePort;
+		pshost->n_io_port	= 0xFF;
+		pshost->unique_id	= padapter->basePort;
+		pshost->max_id		= 16;
+		pshost->max_channel	= 1;
+
+		for ( zz = 0;  zz < MAX_BUS;  zz++ )
+			for ( z = 0; z < MAX_UNITS;  z++ )
+				{
+				padapter->dev[zz][z].tag = 0;
+				padapter->dev[zz][z].scatGath = (PSCATGATH)consistent;
+				padapter->dev[zz][z].scatGathDma = consistentDma;
+				consistent += 16 * sizeof (SCATGATH);
+				consistentDma += 16 * sizeof (SCATGATH);
+				padapter->dev[zz][z].cdb = (UCHAR *)consistent;
+				padapter->dev[zz][z].cdbDma = consistentDma;
+				consistent += MAX_COMMAND_SIZE;
+				consistentDma += MAX_COMMAND_SIZE;
+				}
+			
+		printk("\nPSI-2000 Intelligent Storage SCSI CONTROLLER: at I/O = %lX  IRQ = %d\n", padapter->basePort, pshost->irq);
+		printk("Version %s, Compiled %s %s\n\n", PCI2000_VERSION,  __DATE__, __TIME__);
+		found++;
+		if ( ++installed < MAXADAPTER )
+			continue;
+		break;
+unregister:;
+		scsi_unregister (pshost);
+		found++;
+		}
+	NumAdapters = installed;
+	return installed;
+	}
+/****************************************************************
+ *	Name:	Pci2000_Abort
+ *
+ *	Description:	Process the Abort command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *
+ *	Returns:		Allways snooze.
+ *
+ ****************************************************************/
+int Pci2000_Abort (Scsi_Cmnd *SCpnt)
+	{
+	DEB (printk ("pci2000_abort\n"));
+	return SCSI_ABORT_SNOOZE;
+	}
+/****************************************************************
+ *	Name:	Pci2000_Reset
+ *
+ *	Description:	Process the Reset command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *					flags - Flags about the reset command
+ *
+ *	Returns:		No active command at this time, so this means
+ *					that each time we got some kind of response the
+ *					last time through.  Tell the mid-level code to
+ *					request sense information in order to decide what
+ *					to do next.
+ *
+ ****************************************************************/
+int Pci2000_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+	{
+	return SCSI_RESET_PUNT;
+	}
+/****************************************************************
+ *	Name:	Pci2000_Release
+ *
+ *	Description:	Release resources allocated for a single each adapter.
+ *
+ *	Parameters:		pshost - Pointer to SCSI command structure.
+ *
+ *	Returns:		zero.
+ *
+ ****************************************************************/
+int Pci2000_Release (struct Scsi_Host *pshost)
+	{
+    PADAPTER2000	padapter = HOSTDATA (pshost);
+
+	if ( padapter->irqOwned )
+		free_irq (pshost->irq, padapter);
+	pci_free_consistent (padapter->pdev, consistentLen, padapter->dev[0][0].scatGath, padapter->dev[0][0].scatGathDma);
+	release_region (pshost->io_port, pshost->n_io_port);
+    scsi_unregister(pshost);
+    return 0;
+	}
+
+/****************************************************************
+ *	Name:	Pci2000_BiosParam
+ *
+ *	Description:	Process the biosparam request from the SCSI manager to
+ *					return C/H/S data.
+ *
+ *	Parameters:		disk - Pointer to SCSI disk structure.
+ *					dev	 - Major/minor number from kernel.
+ *					geom - Pointer to integer array to place geometry data.
+ *
+ *	Returns:		zero.
+ *
+ ****************************************************************/
+int Pci2000_BiosParam (struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int geom[])
+	{
+	PADAPTER2000	    padapter;
+
+	padapter = HOSTDATA(sdev->host);
+
+	if ( WaitReady (padapter) )
+		return 0;
+	outb_p (sdev->id, padapter->mb0);
+	outb_p (CMD_GET_PARMS, padapter->cmd);
+	if ( WaitReady (padapter) )
+		return 0;
+
+	geom[0] = inb_p (padapter->mb2 + 3);
+	geom[1] = inb_p (padapter->mb2 + 2);
+	geom[2] = inw_p (padapter->mb2);
+	return 0;
+	}
+
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+static Scsi_Host_Template driver_template = {
+	.proc_name	= "pci2000",
+	.name		= "PCI-2000 SCSI Intelligent Disk Controller",
+	.detect		= Pci2000_Detect,
+	.release	= Pci2000_Release,
+	.queuecommand	= Pci2000_QueueCommand,
+	.abort		= Pci2000_Abort,
+	.reset		= Pci2000_Reset,
+	.bios_param	= Pci2000_BiosParam,
+	.can_queue	= 16,
+	.this_id	= -1,
+	.sg_tablesize	= 16,
+	.cmd_per_lun	= 1,
+	.use_clustering	= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
new file mode 100644
index 0000000..c65afc9
--- /dev/null
+++ b/drivers/scsi/pci2000.h
@@ -0,0 +1,200 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
+ *
+ * pci2000.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ ****************************************************************************/
+#ifndef _PCI2000_H
+#define _PCI2000_H
+
+#include <linux/types.h>
+
+#ifndef	PSI_EIDE_SCSIOP
+#define	PSI_EIDE_SCSIOP	1
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif 
+#define	LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
+
+/************************************************/
+/*		definition of standard data types		*/
+/************************************************/
+#define	CHAR	char
+#define	UCHAR	unsigned char
+#define	SHORT	short
+#define	USHORT	unsigned short
+#define	BOOL	long
+#define	LONG	long
+#define	ULONG	unsigned long
+#define	VOID	void
+
+typedef	CHAR	*PCHAR;
+typedef	UCHAR	*PUCHAR;
+typedef	SHORT	*PSHORT;
+typedef	USHORT	*PUSHORT;
+typedef	BOOL	*PBOOL;
+typedef	LONG	*PLONG;
+typedef	ULONG	*PULONG;
+typedef	VOID	*PVOID;
+
+
+/************************************************/
+/*		Misc. macros			 				*/
+/************************************************/
+#define ANY2SCSI(up, p)					\
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up)					\
+( (((long)*(((UCHAR *)up))) << 16)		\
++ (((long)(((UCHAR *)up)[1])) << 8)		\
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p)				\
+((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
+((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
+((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up)					\
+( (((long)(((UCHAR *)up)[0])) << 24)	\
++ (((long)(((UCHAR *)up)[1])) << 16)	\
++ (((long)(((UCHAR *)up)[2])) <<  8)	\
++ ((long)(((UCHAR *)up)[3])) )
+
+/************************************************/
+/*		SCSI CDB operation codes 				*/
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY		0x00
+#define SCSIOP_REZERO_UNIT			0x01
+#define SCSIOP_REWIND				0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
+#define SCSIOP_REQUEST_SENSE		0x03
+#define SCSIOP_FORMAT_UNIT			0x04
+#define SCSIOP_READ_BLOCK_LIMITS	0x05
+#define SCSIOP_REASSIGN_BLOCKS		0x07
+#define SCSIOP_READ6				0x08
+#define SCSIOP_RECEIVE				0x08
+#define SCSIOP_WRITE6				0x0A
+#define SCSIOP_PRINT				0x0A
+#define SCSIOP_SEND					0x0A
+#define SCSIOP_SEEK6				0x0B
+#define SCSIOP_TRACK_SELECT			0x0B
+#define SCSIOP_SLEW_PRINT			0x0B
+#define SCSIOP_SEEK_BLOCK			0x0C
+#define SCSIOP_PARTITION			0x0D
+#define SCSIOP_READ_REVERSE			0x0F
+#define SCSIOP_WRITE_FILEMARKS		0x10
+#define SCSIOP_FLUSH_BUFFER			0x10
+#define SCSIOP_SPACE				0x11
+#define SCSIOP_INQUIRY				0x12
+#define SCSIOP_VERIFY6				0x13
+#define SCSIOP_RECOVER_BUF_DATA		0x14
+#define SCSIOP_MODE_SELECT			0x15
+#define SCSIOP_RESERVE_UNIT			0x16
+#define SCSIOP_RELEASE_UNIT			0x17
+#define SCSIOP_COPY					0x18
+#define SCSIOP_ERASE				0x19
+#define SCSIOP_MODE_SENSE			0x1A
+#define SCSIOP_START_STOP_UNIT		0x1B
+#define SCSIOP_STOP_PRINT			0x1B
+#define SCSIOP_LOAD_UNLOAD			0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
+#define SCSIOP_SEND_DIAGNOSTIC		0x1D
+#define SCSIOP_MEDIUM_REMOVAL		0x1E
+#define SCSIOP_READ_CAPACITY		0x25
+#define SCSIOP_READ					0x28
+#define SCSIOP_WRITE				0x2A
+#define SCSIOP_SEEK					0x2B
+#define SCSIOP_LOCATE				0x2B
+#define SCSIOP_WRITE_VERIFY			0x2E
+#define SCSIOP_VERIFY				0x2F
+#define SCSIOP_SEARCH_DATA_HIGH		0x30
+#define SCSIOP_SEARCH_DATA_EQUAL	0x31
+#define SCSIOP_SEARCH_DATA_LOW		0x32
+#define SCSIOP_SET_LIMITS			0x33
+#define SCSIOP_READ_POSITION		0x34
+#define SCSIOP_SYNCHRONIZE_CACHE	0x35
+#define SCSIOP_COMPARE				0x39
+#define SCSIOP_COPY_COMPARE			0x3A
+#define SCSIOP_WRITE_DATA_BUFF		0x3B
+#define SCSIOP_READ_DATA_BUFF		0x3C
+#define SCSIOP_CHANGE_DEFINITION	0x40
+#define SCSIOP_READ_SUB_CHANNEL		0x42
+#define SCSIOP_READ_TOC				0x43
+#define SCSIOP_READ_HEADER			0x44
+#define SCSIOP_PLAY_AUDIO			0x45
+#define SCSIOP_PLAY_AUDIO_MSF		0x47
+#define SCSIOP_PLAY_TRACK_INDEX		0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
+#define SCSIOP_PAUSE_RESUME			0x4B
+#define SCSIOP_LOG_SELECT			0x4C
+#define SCSIOP_LOG_SENSE			0x4D
+#define SCSIOP_MODE_SELECT10		0x55
+#define SCSIOP_MODE_SENSE10			0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
+#define SCSIOP_MECHANISM_STATUS		0xBD
+#define SCSIOP_READ_CD				0xBE
+
+// SCSI read capacity structure
+typedef	struct _READ_CAPACITY_DATA
+	{
+	ULONG blks;				/* total blocks (converted to little endian) */
+	ULONG blksiz;			/* size of each (converted to little endian) */
+	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+	{
+	UCHAR DeviceType			:5;
+	UCHAR DeviceTypeQualifier	:3;
+	UCHAR DeviceTypeModifier	:7;
+	UCHAR RemovableMedia		:1;
+    UCHAR Versions;
+    UCHAR ResponseDataFormat;
+    UCHAR AdditionalLength;
+    UCHAR Reserved[2];
+	UCHAR SoftReset				:1;
+	UCHAR CommandQueue			:1;
+	UCHAR Reserved2				:1;
+	UCHAR LinkedCommands		:1;
+	UCHAR Synchronous			:1;
+	UCHAR Wide16Bit				:1;
+	UCHAR Wide32Bit				:1;
+	UCHAR RelativeAddressing	:1;
+    UCHAR VendorId[8];
+    UCHAR ProductId[16];
+    UCHAR ProductRevisionLevel[4];
+    UCHAR VendorSpecific[20];
+    UCHAR Reserved3[40];
+	}	INQUIRYDATA, *PINQUIRYDATA;
+
+#endif
+
+// function prototypes
+int Pci2000_Detect			(Scsi_Host_Template *tpnt);
+int Pci2000_Command			(Scsi_Cmnd *SCpnt);
+int Pci2000_QueueCommand	(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+int Pci2000_Abort			(Scsi_Cmnd *SCpnt);
+int Pci2000_Reset			(Scsi_Cmnd *SCpnt, unsigned int flags);
+int Pci2000_Release			(struct Scsi_Host *pshost);
+int Pci2000_BiosParam		(struct scsi_device *sdev,
+					struct block_device *bdev,
+					sector_t capacity, int geom[]);
+
+#endif
diff --git a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
new file mode 100644
index 0000000..e395e42
--- /dev/null
+++ b/drivers/scsi/pci2220i.c
@@ -0,0 +1,2915 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2220I device driver for Linux.
+ *
+ * pci2220i.c - Linux Host Driver for PCI-2220I EIDE RAID Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ *
+ *	Revisions 1.10		Mar-26-1999
+ *		- Updated driver for RAID and hot reconstruct support.
+ *
+ *	Revisions 1.11		Mar-26-1999
+ *		- Fixed spinlock and PCI configuration.
+ *
+ *	Revision 2.00		December-1-1999
+ *		- Added code for the PCI-2240I controller
+ *		- Added code for ATAPI devices.
+ *		- Double buffer for scatter/gather support
+ *
+ *	Revision 2.10		March-27-2000
+ *		- Added support for dynamic DMA
+ *
+ ****************************************************************************/
+
+#error Convert me to understand page+offset based scatterlists
+
+//#define DEBUG 1
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/blkdev.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "pci2220i.h"
+#include "psi_dale.h"
+
+
+#define	PCI2220I_VERSION		"2.10"
+#define	READ_CMD				IDE_CMD_READ_MULTIPLE
+#define	WRITE_CMD				IDE_CMD_WRITE_MULTIPLE
+#define	MAX_BUS_MASTER_BLOCKS	SECTORSXFER		// This is the maximum we can bus master
+
+#ifdef DEBUG
+#define DEB(x) x
+#define STOP_HERE()	{int st;for(st=0;st<100;st++){st=1;}}
+#else
+#define DEB(x)
+#define STOP_HERE()
+#endif
+
+#define MAXADAPTER 4					// Increase this and the sizes of the arrays below, if you need more.
+
+
+typedef struct
+	{
+	UCHAR			byte6;				// device select register image
+	UCHAR			spigot;				// spigot number
+	UCHAR			spigots[2];			// RAID spigots
+	UCHAR			deviceID[2];		// device ID codes
+	USHORT			sectors;			// number of sectors per track
+	USHORT			heads;				// number of heads
+	USHORT			cylinders;			// number of cylinders for this device
+	USHORT			spareword;			// placeholder
+	ULONG			blocks;				// number of blocks on device
+	DISK_MIRROR		DiskMirror[2];		// RAID status and control
+	ULONG			lastsectorlba[2];	// last addressable sector on the drive
+	USHORT			raid;				// RAID active flag
+	USHORT			mirrorRecon;
+	UCHAR			reconOn;
+	USHORT			reconCount;
+	USHORT			reconIsStarting;	// indicate hot reconstruct is starting
+	UCHAR			cmdDrqInt;			// flag for command interrupt
+	UCHAR			packet;				// command packet size in bytes
+	}	OUR_DEVICE, *POUR_DEVICE;	
+
+typedef struct
+	{
+	USHORT		 bigD;					// identity is a PCI-2240I if true, otherwise a PCI-2220I
+	USHORT		 atapi;					// this interface is for ATAPI devices only
+	ULONG		 regDmaDesc;			// address of the DMA discriptor register for direction of transfer
+	ULONG		 regDmaCmdStat;			// Byte #1 of DMA command status register
+	ULONG		 regDmaAddrPci;			// 32 bit register for PCI address of DMA
+	ULONG		 regDmaAddrLoc;			// 32 bit register for local bus address of DMA
+	ULONG		 regDmaCount;			// 32 bit register for DMA transfer count
+	ULONG		 regDmaMode;			// 32 bit register for DMA mode control
+	ULONG		 regRemap;				// 32 bit local space remap
+	ULONG		 regDesc;				// 32 bit local region descriptor
+	ULONG		 regRange;				// 32 bit local range
+	ULONG		 regIrqControl;			// 16 bit Interrupt enable/disable and status
+	ULONG		 regScratchPad;			// scratch pad I/O base address
+	ULONG		 regBase;				// Base I/O register for data space
+	ULONG		 regData;				// data register I/O address
+	ULONG		 regError;				// error register I/O address
+	ULONG		 regSectCount;			// sector count register I/O address
+	ULONG		 regLba0;				// least significant byte of LBA
+	ULONG		 regLba8;				// next least significant byte of LBA
+	ULONG		 regLba16;				// next most significan byte of LBA
+	ULONG		 regLba24;				// head and most 4 significant bits of LBA
+	ULONG		 regStatCmd;			// status on read and command on write register
+	ULONG		 regStatSel;			// board status on read and spigot select on write register
+	ULONG		 regFail;				// fail bits control register
+	ULONG		 regAltStat;			// alternate status and drive control register
+	ULONG		 basePort;				// PLX base I/O port
+	USHORT		 timingMode;			// timing mode currently set for adapter
+	USHORT		 timingPIO;				// TRUE if PIO timing is active
+	struct pci_dev	*pcidev;
+	ULONG		 timingAddress;			// address to use on adapter for current timing mode
+	ULONG		 irqOwned;				// owned IRQ or zero if shared
+	UCHAR		 numberOfDrives;		// saved number of drives on this controller
+	UCHAR		 failRegister;			// current inverted data in fail register
+	OUR_DEVICE	 device[BIGD_MAXDRIVES];
+	DISK_MIRROR	*raidData[BIGD_MAXDRIVES];
+	ULONG		 startSector;
+	USHORT		 sectorCount;
+	ULONG		 readCount;
+	UCHAR		*currentSgBuffer;
+	ULONG		 currentSgCount;
+	USHORT		 nextSg;
+	UCHAR		 cmd;
+	Scsi_Cmnd	*SCpnt;
+	POUR_DEVICE	 pdev;					// current device opearating on
+	USHORT		 devInReconIndex;
+	USHORT		 expectingIRQ;
+	USHORT		 reconOn;				// Hot reconstruct is to be done.
+	USHORT		 reconPhase;			// Hot reconstruct operation is in progress.
+	ULONG		 reconSize;
+	USHORT		 demoFail;				// flag for RAID failure demonstration
+	USHORT		 survivor;
+	USHORT		 failinprog;
+	struct timer_list	reconTimer;	
+	struct timer_list	timer;
+	UCHAR		*kBuffer;
+	dma_addr_t	 kBufferDma;
+	UCHAR		 reqSense;
+	UCHAR		 atapiCdb[16];
+	UCHAR		 atapiSpecial;
+	}	ADAPTER2220I, *PADAPTER2220I;
+
+#define HOSTDATA(host) ((PADAPTER2220I)&host->hostdata)
+
+#define	RECON_PHASE_READY		0x01
+#define	RECON_PHASE_COPY		0x02
+#define	RECON_PHASE_UPDATE		0x03
+#define	RECON_PHASE_LAST		0x04
+#define	RECON_PHASE_END			0x07	
+#define	RECON_PHASE_MARKING		0x80
+#define	RECON_PHASE_FAILOVER	0xFF
+
+static struct	Scsi_Host 	   *PsiHost[MAXADAPTER] = {NULL,};  // One for each adapter
+static			int				NumAdapters = 0;
+static			int				Installed = 0;
+static			SETUP			DaleSetup;
+static			DISK_MIRROR		DiskMirror[BIGD_MAXDRIVES];
+static			ULONG			ModeArray[] = {DALE_DATA_MODE2, DALE_DATA_MODE3, DALE_DATA_MODE4, DALE_DATA_MODE5};
+static			ULONG			ModeArray2[] = {BIGD_DATA_MODE2, BIGD_DATA_MODE3, BIGD_DATA_MODE4, BIGD_DATA_MODE5};
+
+static void ReconTimerExpiry (unsigned long data);
+
+/*******************************************************************************************************
+ *	Name:			Alarm
+ *
+ *	Description:	Sound the for the given device
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					device	 - Device number.
+ *	
+ *	Returns:		Nothing.
+ *
+ ******************************************************************************************************/
+static void Alarm (PADAPTER2220I padapter, UCHAR device)
+	{
+	UCHAR	zc;
+
+	if ( padapter->bigD )
+		{
+		zc = device | (FAIL_ANY | FAIL_AUDIBLE);
+		if ( padapter->failRegister & FAIL_ANY ) 
+			zc |= FAIL_MULTIPLE;
+		
+		padapter->failRegister = zc;
+		outb_p (~zc, padapter->regFail);
+		}
+	else
+		outb_p (0x3C | (1 << device), padapter->regFail);			// sound alarm and set fail light		
+	}
+/****************************************************************
+ *	Name:	MuteAlarm	:LOCAL
+ *
+ *	Description:	Mute the audible alarm.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static void MuteAlarm (PADAPTER2220I padapter)
+	{
+	UCHAR	old;
+
+	if ( padapter->bigD )
+		{
+		padapter->failRegister &= ~FAIL_AUDIBLE;
+		outb_p (~padapter->failRegister, padapter->regFail);
+		}
+	else
+		{
+		old = (inb_p (padapter->regStatSel) >> 3) | (inb_p (padapter->regStatSel) & 0x83);
+		outb_p (old | 0x40, padapter->regFail);
+		}
+	}
+/****************************************************************
+ *	Name:	WaitReady	:LOCAL
+ *
+ *	Description:	Wait for device ready.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WaitReady (PADAPTER2220I padapter)
+	{
+	ULONG	z;
+	UCHAR	status;
+
+	for ( z = 0;  z < (TIMEOUT_READY * 4);  z++ )
+		{
+		status = inb_p (padapter->regStatCmd);
+		if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
+			return 0;
+		udelay (250);
+		}
+	return status;
+	}
+/****************************************************************
+ *	Name:	WaitReadyReset	:LOCAL
+ *
+ *	Description:	Wait for device ready.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WaitReadyReset (PADAPTER2220I padapter)
+	{
+	ULONG	z;
+	UCHAR	status;
+
+	for ( z = 0;  z < (125 * 16);  z++ )				// wait up to 1/4 second
+		{
+		status = inb_p (padapter->regStatCmd);
+		if ( (status & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY )
+			{
+			DEB (printk ("\nPCI2220I:  Reset took %ld mSec to be ready", z / 8));
+			return 0;
+			}
+		udelay (125);
+		}
+	DEB (printk ("\nPCI2220I:  Reset took more than 2 Seconds to come ready, Disk Failure"));
+	return status;
+	}
+/****************************************************************
+ *	Name:	WaitDrq	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WaitDrq (PADAPTER2220I padapter)
+	{
+	ULONG	z;
+	UCHAR	status;
+
+	for ( z = 0;  z < (TIMEOUT_DRQ * 4);  z++ )
+		{
+		status = inb_p (padapter->regStatCmd);
+		if ( status & IDE_STATUS_DRQ )
+			return 0;
+		udelay (250);
+		}
+	return status;
+	}
+/****************************************************************
+ *	Name:	AtapiWaitReady	:LOCAL
+ *
+ *	Description:	Wait for device busy and DRQ to be cleared.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					msec	 - Number of milliseconds to wait.
+ *
+ *	Returns:		TRUE if drive does not clear busy in time.
+ *
+ ****************************************************************/
+static int AtapiWaitReady (PADAPTER2220I padapter, int msec)
+	{
+	int z;
+
+	for ( z = 0;  z < (msec * 16);  z++ )
+		{
+		if ( !(inb_p (padapter->regStatCmd) & (IDE_STATUS_BUSY | IDE_STATUS_DRQ)) )
+			return FALSE;
+		udelay (125);
+		}
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	AtapiWaitDrq	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					msec	 - Number of milliseconds to wait.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int AtapiWaitDrq (PADAPTER2220I padapter, int msec)
+	{
+	ULONG	z;
+
+	for ( z = 0;  z < (msec * 16);  z++ )
+		{
+		if ( inb_p (padapter->regStatCmd) & IDE_STATUS_DRQ )
+			return 0;
+		udelay (128);
+		}
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	HardReset	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					spigot	 - Spigot number.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int HardReset (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot)
+	{
+	DEB (printk ("\npci2220i:RESET  spigot = %X  devices = %d, %d", spigot, pdev->deviceID[0], pdev->deviceID[1]));
+	mdelay (100);										// just wait 100 mSec to let drives flush	
+	SelectSpigot (padapter, spigot | SEL_IRQ_OFF);
+	
+	outb_p (0x0E, padapter->regAltStat);					// reset the suvivor
+	udelay (100);											// wait a little	
+	outb_p (0x08, padapter->regAltStat);					// clear the reset
+	udelay (100);
+
+	outb_p (0xA0, padapter->regLba24);						// select the master drive
+	if ( WaitReadyReset (padapter) )
+		{
+		DEB (printk ("\npci2220i: master not ready after reset"));
+		return TRUE;
+		}
+	outb_p (0xB0, padapter->regLba24);						// try the slave drive
+	if ( (inb_p (padapter->regStatCmd) & (IDE_STATUS_DRDY | IDE_STATUS_BUSY)) == IDE_STATUS_DRDY ) 
+		{
+		DEB (printk ("\nPCI2220I: initializing slave drive on spigot %X", spigot));
+		outb_p (SECTORSXFER, padapter->regSectCount);
+		WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);	
+		if ( WaitReady (padapter) )
+			{
+			DEB (printk ("\npci2220i: slave not ready after set multiple"));
+			return TRUE;
+			}
+		}
+	
+	outb_p (0xA0, padapter->regLba24);				// select the drive
+	outb_p (SECTORSXFER, padapter->regSectCount);
+	WriteCommand (padapter, IDE_CMD_SET_MULTIPLE);	
+	if ( WaitReady (padapter) )
+		{
+		DEB (printk ("\npci2220i: master not ready after set multiple"));
+		return TRUE;
+		}
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:	AtapiReset	:LOCAL
+ *
+ *	Description:	Wait for device ready for data transfer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *
+ *	Returns:		TRUE if drive does not come ready.
+ *
+ ****************************************************************/
+static int AtapiReset (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	SelectSpigot (padapter, pdev->spigot);
+	AtapiDevice (padapter, pdev->byte6);
+	AtapiCountLo (padapter, 0);
+	AtapiCountHi (padapter, 0);
+	WriteCommand (padapter, IDE_COMMAND_ATAPI_RESET);
+	udelay (125);
+	if ( AtapiWaitReady (padapter, 1000) )
+		return TRUE;
+	if ( inb_p (padapter->regStatCmd) || (inb_p (padapter->regLba8) != 0x14) || (inb_p (padapter->regLba16) != 0xEB) )
+		return TRUE;
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:	WalkScatGath	:LOCAL
+ *
+ *	Description:	Transfer data to/from scatter/gather buffers.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					datain   - TRUE if data read.
+ *					length   - Number of bytes to transfer.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void WalkScatGath (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+	{
+	ULONG	 count;
+	UCHAR	*buffer = padapter->kBuffer;
+
+	while ( length )
+		{
+		count = ( length > padapter->currentSgCount ) ? padapter->currentSgCount : length; 
+		
+		if ( datain )
+			memcpy (padapter->currentSgBuffer, buffer, count);
+		else
+			memcpy (buffer, padapter->currentSgBuffer, count);
+
+		padapter->currentSgCount -= count;
+		if ( !padapter->currentSgCount )
+			{
+			if ( padapter->nextSg < padapter->SCpnt->use_sg )
+				{
+				padapter->currentSgBuffer = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].address;
+				padapter->currentSgCount = ((struct scatterlist *)padapter->SCpnt->request_buffer)[padapter->nextSg].length;
+				padapter->nextSg++;
+				}
+			}
+		else
+			padapter->currentSgBuffer += count;
+
+		length -= count;
+		buffer += count;
+		}
+	}
+/****************************************************************
+ *	Name:	BusMaster	:LOCAL
+ *
+ *	Description:	Do a bus master I/O.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					datain	 - TRUE if data read.
+ *					irq		 - TRUE if bus master interrupt expected.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void BusMaster (PADAPTER2220I padapter, UCHAR datain, UCHAR irq)
+	{
+	ULONG zl;
+	
+	zl = ( padapter->sectorCount > MAX_BUS_MASTER_BLOCKS ) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+	padapter->sectorCount -= zl;
+	zl *= (ULONG)BYTES_PER_SECTOR;
+
+	if ( datain )
+		{
+		padapter->readCount = zl;
+		outb_p (8, padapter->regDmaDesc);							// read operation
+		if ( padapter->bigD )
+			{
+			if ( irq && !padapter->sectorCount )
+				outb_p (0x0C, padapter->regDmaMode);				// interrupt on
+			else
+				outb_p (0x08, padapter->regDmaMode);				// no interrupt
+			}
+		else 
+			{
+			if ( irq && !padapter->sectorCount )
+				outb_p (0x05, padapter->regDmaMode);				// interrupt on
+			else
+				outb_p (0x01, padapter->regDmaMode);				// no interrupt
+			}
+		}
+	else
+		{
+		outb_p (0x00, padapter->regDmaDesc);						// write operation
+		if ( padapter->bigD )
+			outb_p (0x08, padapter->regDmaMode);					// no interrupt						
+		else
+			outb_p (0x01, padapter->regDmaMode);					// no interrupt
+		WalkScatGath (padapter, FALSE, zl);	
+		}
+	
+	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+	outl (padapter->kBufferDma, padapter->regDmaAddrPci);
+	outl (zl, padapter->regDmaCount);
+	outb_p (0x03, padapter->regDmaCmdStat);							// kick the DMA engine in gear
+	}
+/****************************************************************
+ *	Name:	AtapiBusMaster	:LOCAL
+ *
+ *	Description:	Do a bus master I/O.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					datain	 - TRUE if data read.
+ *					length	 - Number of bytes to transfer.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void AtapiBusMaster (PADAPTER2220I padapter, UCHAR datain, ULONG length)
+	{
+	outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+	outl (padapter->kBufferDma, padapter->regDmaAddrPci);
+	outl (length, padapter->regDmaCount);
+	if ( datain )
+		{
+		if ( padapter->readCount )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
+		outb_p (0x08, padapter->regDmaDesc);						// read operation
+		outb_p (0x08, padapter->regDmaMode);						// no interrupt
+		padapter->readCount = length;
+		}
+	else
+		{
+		outb_p (0x00, padapter->regDmaDesc);						// write operation
+		outb_p (0x08, padapter->regDmaMode);						// no interrupt						
+		if ( !padapter->atapiSpecial )
+			WalkScatGath (padapter, FALSE, length);	
+		}
+	outb_p (0x03, padapter->regDmaCmdStat);							// kick the DMA engine in gear
+	}
+/****************************************************************
+ *	Name:	WriteData	:LOCAL
+ *
+ *	Description:	Write data to device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WriteData (PADAPTER2220I padapter)
+	{
+	ULONG	zl;
+	
+	if ( !WaitDrq (padapter) )
+		{
+		if ( padapter->timingPIO )
+			{
+			zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+			WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+			outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
+			padapter->sectorCount -= zl;
+			}
+		else
+			BusMaster (padapter, 0, 0);
+		return 0;
+		}
+	padapter->cmd = 0;												// null out the command byte
+	return 1;
+	}
+/****************************************************************
+ *	Name:	WriteDataBoth	:LOCAL
+ *
+ *	Description:	Write data to device.
+ *
+ *	Parameters:		padapter - Pointer to adapter structure.
+ *					pdev	 - Pointer to device structure
+ *
+ *	Returns:		Index + 1 of drive not failed or zero for OK.
+ *
+ ****************************************************************/
+static int WriteDataBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	ULONG	zl;
+	UCHAR	status0, status1;
+
+	SelectSpigot (padapter, pdev->spigots[0]);
+	status0 = WaitDrq (padapter);
+	if ( !status0 )
+		{
+		SelectSpigot (padapter, pdev->spigots[1]);
+		status1 = WaitDrq (padapter);
+		if ( !status1 )
+			{
+			SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
+			if ( padapter->timingPIO )
+				{
+				zl = (padapter->sectorCount > MAX_BUS_MASTER_BLOCKS) ? MAX_BUS_MASTER_BLOCKS : padapter->sectorCount;
+				WalkScatGath (padapter, FALSE, zl * BYTES_PER_SECTOR);
+				outsw (padapter->regData, padapter->kBuffer, zl * (BYTES_PER_SECTOR / 2));
+				padapter->sectorCount -= zl;
+				}
+			else
+				BusMaster (padapter, 0, 0);
+			return 0;
+			}
+		}
+	padapter->cmd = 0;												// null out the command byte
+	if ( status0 )
+		return 2;
+	return 1;
+	}
+/****************************************************************
+ *	Name:	IdeCmd	:LOCAL
+ *
+ *	Description:	Process an IDE command.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *
+ *	Returns:		Zero if no error or status register contents on error.
+ *
+ ****************************************************************/
+static UCHAR IdeCmd (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	UCHAR	status;
+
+	SelectSpigot (padapter, pdev->spigot | padapter->bigD);							// select the spigot
+	outb_p (pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);			// select the drive
+	status = WaitReady (padapter);
+	if ( !status )
+		{
+		outb_p (padapter->sectorCount, padapter->regSectCount);
+		outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
+		outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
+		outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16);
+		padapter->expectingIRQ = TRUE;
+		WriteCommand (padapter, padapter->cmd);
+		return 0;
+		}
+
+	padapter->cmd = 0;									// null out the command byte
+	return status;
+	}
+/****************************************************************
+ *	Name:	IdeCmdBoth	:LOCAL
+ *
+ *	Description:	Process an IDE command to both drivers.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device structure
+ *
+ *	Returns:		Index + 1 of drive not failed or zero for OK.
+ *
+ ****************************************************************/
+static UCHAR IdeCmdBoth (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	UCHAR	status0;
+	UCHAR	status1;
+
+	SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);								// select the spigots
+	outb_p (padapter->pdev->byte6 | ((UCHAR *)(&padapter->startSector))[3], padapter->regLba24);// select the drive
+	SelectSpigot (padapter, pdev->spigots[0]);
+	status0 = WaitReady (padapter);
+	if ( !status0 )
+		{
+		SelectSpigot (padapter, pdev->spigots[1]);
+		status1 = WaitReady (padapter);
+		if ( !status1 )
+			{
+			SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1] | padapter->bigD);
+			outb_p (padapter->sectorCount, padapter->regSectCount);
+			outb_p (((UCHAR *)(&padapter->startSector))[0], padapter->regLba0);
+			outb_p (((UCHAR *)(&padapter->startSector))[1], padapter->regLba8);
+			outb_p (((UCHAR *)(&padapter->startSector))[2], padapter->regLba16);
+			padapter->expectingIRQ = TRUE;
+			WriteCommand (padapter, padapter->cmd);
+			return 0;
+			}
+		}
+	padapter->cmd = 0;									// null out the command byte
+	if ( status0 )
+		return 2;
+	return 1;
+	}
+/****************************************************************
+ *	Name:	OpDone	:LOCAL
+ *
+ *	Description:	Complete an operatoin done sequence.
+ *
+ *	Parameters:		padapter - Pointer to host data block.
+ *					spigot	 - Spigot select code.
+ *					device	 - Device byte code.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void OpDone (PADAPTER2220I padapter, ULONG result)
+	{
+	Scsi_Cmnd	   *SCpnt = padapter->SCpnt;
+	
+	if ( padapter->reconPhase )
+		{
+		padapter->reconPhase = 0;
+		if ( padapter->SCpnt )
+			{
+			Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done);
+			}
+		else
+			{
+			if ( padapter->reconOn )
+				{
+				ReconTimerExpiry ((unsigned long)padapter);
+				}
+			}
+		}
+	else
+		{
+		padapter->cmd = 0;
+		padapter->SCpnt = NULL;	
+		padapter->pdev = NULL;
+		SCpnt->result = result;
+		SCpnt->scsi_done (SCpnt);
+		if ( padapter->reconOn && !padapter->reconTimer.data )
+			{
+			padapter->reconTimer.expires = jiffies + (HZ / 4);	// start in 1/4 second
+			padapter->reconTimer.data = (unsigned long)padapter;
+			add_timer (&padapter->reconTimer);
+			}
+		}
+	}
+/****************************************************************
+ *	Name:	InlineIdentify	:LOCAL
+ *
+ *	Description:	Do an intline inquiry on a drive.
+ *
+ *	Parameters:		padapter - Pointer to host data block.
+ *					spigot	 - Spigot select code.
+ *					device	 - Device byte code.
+ *
+ *	Returns:		Last addressable sector or zero if none.
+ *
+ ****************************************************************/
+static ULONG InlineIdentify (PADAPTER2220I padapter, UCHAR spigot, UCHAR device)
+	{
+	PIDENTIFY_DATA	pid = (PIDENTIFY_DATA)padapter->kBuffer;
+
+	SelectSpigot (padapter, spigot | SEL_IRQ_OFF);					// select the spigot
+	outb_p ((device << 4) | 0xA0, padapter->regLba24);				// select the drive
+	if ( WaitReady (padapter) )
+		return 0;
+	WriteCommand (padapter, IDE_COMMAND_IDENTIFY);	
+	if ( WaitDrq (padapter) )
+		return 0;
+	insw (padapter->regData, padapter->kBuffer, sizeof (IDENTIFY_DATA) >> 1);
+	return (pid->LBATotalSectors - 1);
+	}
+/****************************************************************
+ *	Name:	AtapiIdentify	:LOCAL
+ *
+ *	Description:	Do an intline inquiry on a drive.
+ *
+ *	Parameters:		padapter - Pointer to host data block.
+ *					pdev	 - Pointer to device table.
+ *
+ *	Returns:		TRUE on error.
+ *
+ ****************************************************************/
+static ULONG AtapiIdentify (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	ATAPI_GENERAL_0		ag0;
+	USHORT				zs;
+	int					z;
+
+	AtapiDevice (padapter, pdev->byte6);	
+	WriteCommand (padapter, IDE_COMMAND_ATAPI_IDENTIFY);	
+	if ( AtapiWaitDrq (padapter, 3000) )
+		return TRUE;
+
+	*(USHORT *)&ag0 = inw_p (padapter->regData);
+	for ( z = 0;  z < 255;  z++ )
+		zs = inw_p (padapter->regData);
+
+	if ( ag0.ProtocolType == 2 )
+		{
+		if ( ag0.CmdDrqType == 1 )
+			pdev->cmdDrqInt = TRUE;
+		switch ( ag0.CmdPacketSize )
+			{
+			case 0:
+				pdev->packet = 6;
+				break;
+			case 1:
+				pdev->packet = 8;
+				break;
+			default:
+				pdev->packet = 6;
+				break;
+			}
+		return FALSE;
+		}
+	return TRUE;
+	}
+/****************************************************************
+ *	Name:	Atapi2Scsi
+ *
+ *	Description:	Convert ATAPI data to SCSI data.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+void Atapi2Scsi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+	{
+	UCHAR	*buff = padapter->currentSgBuffer;
+ 
+	switch ( SCpnt->cmnd[0] )
+		{
+		case SCSIOP_MODE_SENSE:
+			buff[0] = padapter->kBuffer[1];
+			buff[1] = padapter->kBuffer[2];
+			buff[2] = padapter->kBuffer[3];
+			buff[3] = padapter->kBuffer[7];
+			memcpy (&buff[4], &padapter->kBuffer[8], padapter->atapiCdb[8] - 8);
+			break;
+		case SCSIOP_INQUIRY:
+			padapter->kBuffer[2] = 2;
+			memcpy (buff, padapter->kBuffer, padapter->currentSgCount);
+			break;		
+		default:
+			if ( padapter->readCount )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
+			break;
+		}
+	}
+/****************************************************************
+ *	Name:	Scsi2Atapi
+ *
+ *	Description:	Convert SCSI packet command to Atapi packet command.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void Scsi2Atapi (PADAPTER2220I padapter, Scsi_Cmnd *SCpnt)
+	{
+	UCHAR	*cdb = SCpnt->cmnd;
+	UCHAR	*buff = padapter->currentSgBuffer;
+
+	switch (cdb[0]) 
+		{
+		case SCSIOP_READ6:
+            padapter->atapiCdb[0] = SCSIOP_READ;
+			padapter->atapiCdb[1] = cdb[1] & 0xE0;
+            padapter->atapiCdb[3] = cdb[1] & 0x1F;
+			padapter->atapiCdb[4] = cdb[2];
+			padapter->atapiCdb[5] = cdb[3];
+			padapter->atapiCdb[8] = cdb[4];
+			padapter->atapiCdb[9] = cdb[5];
+			break;
+		case SCSIOP_WRITE6:
+            padapter->atapiCdb[0] = SCSIOP_WRITE;
+			padapter->atapiCdb[1] = cdb[1] & 0xE0;
+            padapter->atapiCdb[3] = cdb[1] & 0x1F;
+			padapter->atapiCdb[4] = cdb[2];
+			padapter->atapiCdb[5] = cdb[3];
+			padapter->atapiCdb[8] = cdb[4];
+			padapter->atapiCdb[9] = cdb[5];
+			break;
+        case SCSIOP_MODE_SENSE: 
+            padapter->atapiCdb[0] = SCSIOP_MODE_SENSE10;
+			padapter->atapiCdb[2] = cdb[2];
+			padapter->atapiCdb[8] = cdb[4] + 4;
+            break;
+
+        case SCSIOP_MODE_SELECT: 
+			padapter->atapiSpecial = TRUE;
+			padapter->atapiCdb[0] = SCSIOP_MODE_SELECT10;
+			padapter->atapiCdb[1] = cdb[1] | 0x10;
+			memcpy (padapter->kBuffer, buff, 4);
+			padapter->kBuffer[4] = padapter->kBuffer[5] = 0;
+			padapter->kBuffer[6] = padapter->kBuffer[7] = 0;
+			memcpy (&padapter->kBuffer[8], &buff[4], cdb[4] - 4);
+			padapter->atapiCdb[8] = cdb[4] + 4;
+			break;
+	    }
+	}
+/****************************************************************
+ *	Name:	AtapiSendCdb
+ *
+ *	Description:	Send the CDB packet to the device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					cdb		 - Pointer to 16 byte SCSI cdb.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void AtapiSendCdb (PADAPTER2220I padapter, POUR_DEVICE pdev, CHAR *cdb)
+	{
+	DEB (printk ("\nPCI2242I: CDB: %X %X %X %X %X %X %X %X %X %X %X %X", cdb[0], cdb[1], cdb[2], cdb[3], cdb[4], cdb[5], cdb[6], cdb[7], cdb[8], cdb[9], cdb[10], cdb[11]));
+	outsw (padapter->regData, cdb, pdev->packet);
+	}
+/****************************************************************
+ *	Name:	AtapiRequestSense
+ *
+ *	Description:	Send the CDB packet to the device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					SCpnt	 - Pointer to SCSI command structure.
+ *					pass	 - If true then this is the second pass to send cdb.
+ *
+ *	Returns:		TRUE on error.
+ *
+ ****************************************************************/
+static int AtapiRequestSense (PADAPTER2220I padapter, POUR_DEVICE pdev, Scsi_Cmnd *SCpnt, UCHAR pass)
+	{
+	UCHAR	cdb[16] = {SCSIOP_REQUEST_SENSE,0,0,0,16,0,0,0,0,0,0,0,0,0,0,0};		
+	
+	DEB (printk ("\nPCI2242I: AUTO REQUEST SENSE"));
+	cdb[4] = (UCHAR)(sizeof (SCpnt->sense_buffer));
+	if ( !pass )
+		{
+		padapter->reqSense = TRUE;
+	 	AtapiCountLo (padapter, cdb[4]);						
+		AtapiCountHi (padapter, 0);						
+		outb_p (0, padapter->regError);						
+		WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+		if ( pdev->cmdDrqInt )
+			return FALSE;
+
+		if ( AtapiWaitDrq (padapter, 500) )
+			return TRUE;
+		}
+	AtapiSendCdb (padapter, pdev, cdb);	
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:	InlineReadSignature	:LOCAL
+ *
+ *	Description:	Do an inline read RAID sigature.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to device.
+ *					index	 - index of data to read.
+ *
+ *	Returns:		Zero if no error or status register contents on error.
+ *
+ ****************************************************************/
+static UCHAR InlineReadSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, int index)
+	{
+	UCHAR	status;
+	ULONG	zl = pdev->lastsectorlba[index];
+
+	SelectSpigot (padapter, pdev->spigots[index] | SEL_IRQ_OFF);	// select the spigot without interrupts
+	outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);		
+	status = WaitReady (padapter);
+	if ( !status )
+		{
+		outb_p (((UCHAR *)&zl)[2], padapter->regLba16);
+		outb_p (((UCHAR *)&zl)[1], padapter->regLba8); 
+		outb_p (((UCHAR *)&zl)[0], padapter->regLba0);
+		outb_p (1, padapter->regSectCount);
+		WriteCommand (padapter, IDE_COMMAND_READ);
+		status = WaitDrq (padapter);
+		if ( !status )
+			{
+			insw (padapter->regData, padapter->kBuffer, BYTES_PER_SECTOR / 2);
+			((ULONG *)(&pdev->DiskMirror[index]))[0] = ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[0];
+			((ULONG *)(&pdev->DiskMirror[index]))[1] = ((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[1];
+			// some drives assert DRQ before IRQ so let's make sure we clear the IRQ
+			WaitReady (padapter);
+			return 0;			
+			}
+		}
+	return status;
+	}
+/****************************************************************
+ *	Name:	DecodeError	:LOCAL
+ *
+ *	Description:	Decode and process device errors.
+ *
+ *	Parameters:		padapter - Pointer to adapter data.
+ *					status - Status register code.
+ *
+ *	Returns:		The driver status code.
+ *
+ ****************************************************************/
+static ULONG DecodeError (PADAPTER2220I	padapter, UCHAR status)
+	{
+	UCHAR			error;
+
+	padapter->expectingIRQ = 0;
+	if ( status & IDE_STATUS_WRITE_FAULT )
+		{
+		return DID_PARITY << 16;
+		}
+	if ( status & IDE_STATUS_BUSY )
+		return DID_BUS_BUSY << 16;
+
+	error = inb_p (padapter->regError);
+	DEB(printk ("\npci2220i error register: %x", error));
+	switch ( error )
+		{
+		case IDE_ERROR_AMNF:
+		case IDE_ERROR_TKONF:
+		case IDE_ERROR_ABRT:
+		case IDE_ERROR_IDFN:
+		case IDE_ERROR_UNC:
+		case IDE_ERROR_BBK:
+		default:
+			return DID_ERROR << 16;
+		}
+	return DID_ERROR << 16;
+	}
+/****************************************************************
+ *	Name:	StartTimer	:LOCAL
+ *
+ *	Description:	Start the timer.
+ *
+ *	Parameters:		ipadapter - Pointer adapter data structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void StartTimer (PADAPTER2220I padapter)
+	{
+	padapter->timer.expires = jiffies + TIMEOUT_DATA;
+	add_timer (&padapter->timer);
+	}
+/****************************************************************
+ *	Name:	WriteSignature	:LOCAL
+ *
+ *	Description:	Start the timer.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to our device.
+ *					spigot	 - Selected spigot.
+ *					index	 - index of mirror signature on device.
+ *
+ *	Returns:		TRUE on any error.
+ *
+ ****************************************************************/
+static int WriteSignature (PADAPTER2220I padapter, POUR_DEVICE pdev, UCHAR spigot, int index)
+	{
+	ULONG	zl;
+
+	SelectSpigot (padapter, spigot);
+	zl = pdev->lastsectorlba[index];
+	outb_p (pdev->byte6 | ((UCHAR *)&zl)[3], padapter->regLba24);		
+	outb_p (((UCHAR *)&zl)[2], padapter->regLba16);
+	outb_p (((UCHAR *)&zl)[1], padapter->regLba8);
+	outb_p (((UCHAR *)&zl)[0], padapter->regLba0);
+	outb_p (1, padapter->regSectCount);
+
+	WriteCommand (padapter, IDE_COMMAND_WRITE);	
+	if ( WaitDrq (padapter) )
+		return TRUE;
+	StartTimer (padapter);	
+	padapter->expectingIRQ = TRUE;
+	
+	((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[0] = ((ULONG *)(&pdev->DiskMirror[index]))[0];
+	((ULONG *)(&padapter->kBuffer[DISK_MIRROR_POSITION]))[1] = ((ULONG *)(&pdev->DiskMirror[index]))[1];
+	outsw (padapter->regData, padapter->kBuffer, BYTES_PER_SECTOR / 2);
+	return FALSE;
+	}
+/*******************************************************************************************************
+ *	Name:			InitFailover
+ *
+ *	Description:	This is the beginning of the failover routine
+ *
+ *	Parameters:		SCpnt	 - Pointer to SCSI command structure.
+ *					padapter - Pointer adapter data structure.
+ *					pdev	 - Pointer to our device.
+ *	
+ *	Returns:		TRUE on error.
+ *
+ ******************************************************************************************************/
+static int InitFailover (PADAPTER2220I padapter, POUR_DEVICE pdev)
+	{
+	UCHAR	spigot;
+	
+	DEB (printk ("\npci2220i:  Initialize failover process - survivor = %d", pdev->deviceID[padapter->survivor]));
+	pdev->raid = FALSE;									//initializes system for non raid mode
+	pdev->reconOn = FALSE;
+	spigot = pdev->spigots[padapter->survivor];	
+
+	if ( pdev->DiskMirror[padapter->survivor].status & UCBF_REBUILD )
+		{
+		DEB (printk ("\n         failed, is survivor"));
+		return (TRUE); 
+		}
+
+	if ( HardReset (padapter, pdev, spigot) )
+		{
+		DEB (printk ("\n         failed, reset"));
+		return TRUE;
+		}
+
+	Alarm (padapter, pdev->deviceID[padapter->survivor ^ 1]);
+	pdev->DiskMirror[padapter->survivor].status = UCBF_MIRRORED | UCBF_SURVIVOR;	//clear present status
+	
+	if ( WriteSignature (padapter, pdev, spigot, padapter->survivor) )
+		{
+		DEB (printk ("\n         failed, write signature"));
+		return TRUE;
+		}
+	padapter->failinprog = TRUE;
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:	TimerExpiry	:LOCAL
+ *
+ *	Description:	Timer expiry routine.
+ *
+ *	Parameters:		data - Pointer adapter data structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void TimerExpiry (unsigned long data)
+	{
+	PADAPTER2220I	padapter = (PADAPTER2220I)data;
+	struct Scsi_Host *host = padapter->SCpnt->device->host;
+	POUR_DEVICE		pdev = padapter->pdev;
+	UCHAR			status = IDE_STATUS_BUSY;
+	UCHAR			temp, temp1;
+    unsigned long		flags;
+
+    /*
+     * Disable interrupts, if they aren't already disabled and acquire
+     * the I/O spinlock.
+     */
+    spin_lock_irqsave (host->host_lock, flags);
+	DEB (printk ("\nPCI2220I: Timeout expired "));
+
+	if ( padapter->failinprog )
+		{
+		DEB (printk ("in failover process"));
+		OpDone (padapter, DecodeError (padapter, inb_p (padapter->regStatCmd)));
+		goto timerExpiryDone;
+		}
+	
+	while ( padapter->reconPhase )
+		{
+		DEB (printk ("in recon phase %X", padapter->reconPhase));
+		switch ( padapter->reconPhase )
+			{
+			case RECON_PHASE_MARKING:
+			case RECON_PHASE_LAST:
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
+				DEB (printk ("\npci2220i: FAILURE 1"));
+				if ( InitFailover (padapter, pdev) )
+					OpDone (padapter, DID_ERROR << 16);
+				goto timerExpiryDone;
+			
+			case RECON_PHASE_READY:
+				OpDone (padapter, DID_ERROR << 16);
+				goto timerExpiryDone;
+
+			case RECON_PHASE_COPY:
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+				DEB (printk ("\npci2220i: FAILURE 2"));
+				DEB (printk ("\n       spig/stat = %X", inb_p (padapter->regStatSel));
+				if ( InitFailover (padapter, pdev) )
+					OpDone (padapter, DID_ERROR << 16);
+				goto timerExpiryDone;
+
+			case RECON_PHASE_UPDATE:
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+				DEB (printk ("\npci2220i: FAILURE 3")));
+				if ( InitFailover (padapter, pdev) )
+					OpDone (padapter, DID_ERROR << 16);
+				goto timerExpiryDone;
+
+			case RECON_PHASE_END:
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+				DEB (printk ("\npci2220i: FAILURE 4"));
+				if ( InitFailover (padapter, pdev) )
+					OpDone (padapter, DID_ERROR << 16);
+				goto timerExpiryDone;
+			
+			default:
+				goto timerExpiryDone;
+			}
+		}
+	
+	while ( padapter->cmd )
+		{
+		outb_p (0x08, padapter->regDmaCmdStat);					// cancel interrupt from DMA engine
+		if ( pdev->raid )
+			{
+			if ( padapter->cmd == WRITE_CMD )
+				{
+				DEB (printk ("in RAID write operation"));
+				temp = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_1 : SEL_3;
+				if ( inb_p (padapter->regStatSel) & temp )
+					{
+					DEB (printk ("\npci2220i: Determined A OK"));
+					SelectSpigot (padapter, temp | SEL_IRQ_OFF); // Masking the interrupt during spigot select
+					temp = inb_p (padapter->regStatCmd);
+					}
+				else
+					temp = IDE_STATUS_BUSY;
+
+				temp1 = ( pdev->spigot & (SEL_1 | SEL_2) ) ? SEL_2 : SEL_4;
+				if ( inb (padapter->regStatSel) & temp1 )
+					{
+					DEB (printk ("\npci2220i: Determined B OK"));
+					SelectSpigot (padapter, temp1 | SEL_IRQ_OFF); // Masking the interrupt during spigot select
+					temp1 = inb_p (padapter->regStatCmd);
+					}
+				else
+					temp1 = IDE_STATUS_BUSY;
+			
+				if ( (temp & IDE_STATUS_BUSY) || (temp1 & IDE_STATUS_BUSY) )
+					{
+					DEB (printk ("\npci2220i: Status A: %X   B: %X", temp & 0xFF, temp1 & 0xFF));
+	 				if ( (temp & IDE_STATUS_BUSY) && (temp1 & IDE_STATUS_BUSY) ) 
+						{
+						status = temp;
+						break;
+						}		
+					else	
+						{
+						if ( temp & IDE_STATUS_BUSY )
+							padapter->survivor = 1;
+						else
+							padapter->survivor = 0;
+						if ( InitFailover (padapter, pdev) )
+							{
+							status = inb_p (padapter->regStatCmd);
+							break;
+							}
+						goto timerExpiryDone;
+						}
+					}
+				}
+			else
+				{
+				DEB (printk ("in RAID read operation"));
+				padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+				DEB (printk ("\npci2220i: FAILURE 6"));
+				if ( InitFailover (padapter, pdev) )
+					{
+					status = inb_p (padapter->regStatCmd);
+					break;
+					}
+				goto timerExpiryDone;
+				}
+			}
+		else
+			{
+			DEB (printk ("in I/O operation"));
+			status = inb_p (padapter->regStatCmd);
+			}
+		break;
+		}
+	
+	OpDone (padapter, DecodeError (padapter, status));
+
+timerExpiryDone:;
+    /*
+     * Release the I/O spinlock and restore the original flags
+     * which will enable interrupts if and only if they were
+     * enabled on entry.
+     */
+    spin_unlock_irqrestore (host->host_lock, flags);
+	}
+/****************************************************************
+ *	Name:			SetReconstruct	:LOCAL
+ *
+ *	Description:	Set the reconstruct up.
+ *
+ *	Parameters:		pdev	- Pointer to device structure.
+ *					index	- Mirror index number.
+ *
+ *	Returns:		Number of sectors on new disk required.
+ *
+ ****************************************************************/
+static LONG SetReconstruct (POUR_DEVICE pdev, int index)
+	{
+	pdev->DiskMirror[index].status = UCBF_MIRRORED;							// setup the flags
+	pdev->DiskMirror[index ^ 1].status = UCBF_MIRRORED | UCBF_REBUILD;
+	pdev->DiskMirror[index ^ 1].reconstructPoint = 0;						// start the reconstruct
+	pdev->reconCount = 1990;												// mark target drive early
+	return pdev->DiskMirror[index].reconstructPoint;
+	}
+/****************************************************************
+ *	Name:	ReconTimerExpiry	:LOCAL
+ *
+ *	Description:	Reconstruct timer expiry routine.
+ *
+ *	Parameters:		data - Pointer adapter data structure.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static void ReconTimerExpiry (unsigned long data)
+	{
+	PADAPTER2220I	padapter = (PADAPTER2220I)data;
+	struct Scsi_Host *host = padapter->SCpnt->device->host;
+	POUR_DEVICE		pdev;
+	ULONG			testsize = 0;
+	PIDENTIFY_DATA	pid;
+	USHORT			minmode;
+	ULONG			zl;
+	UCHAR			zc;
+	USHORT			z;
+    unsigned long	flags;
+
+    /*
+     * Disable interrupts, if they aren't already disabled and acquire
+     * the I/O spinlock.
+     */
+    spin_lock_irqsave(host->host_lock, flags);
+
+	if ( padapter->SCpnt )
+		goto reconTimerExpiry;
+
+	padapter->reconTimer.data = 0;
+	for ( z = padapter->devInReconIndex + 1;  z < BIGD_MAXDRIVES;  z++ )
+		{
+		if ( padapter->device[z].reconOn )
+			break;
+		}
+	if ( z < BIGD_MAXDRIVES )
+		pdev = &padapter->device[z];
+	else
+		{
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			{
+			if ( padapter->device[z].reconOn )
+				break;
+			}
+		if ( z < BIGD_MAXDRIVES )
+			pdev = &padapter->device[z];
+		else
+			{
+			padapter->reconOn = FALSE;
+			goto reconTimerExpiry;
+			}
+		}
+
+	padapter->devInReconIndex = z;
+	pid = (PIDENTIFY_DATA)padapter->kBuffer;
+	padapter->pdev = pdev;
+	if ( pdev->reconIsStarting )
+		{
+		pdev->reconIsStarting = FALSE;
+		pdev->reconOn = FALSE;
+
+		while ( (pdev->DiskMirror[0].signature == SIGNATURE) && (pdev->DiskMirror[1].signature == SIGNATURE) &&
+			 (pdev->DiskMirror[0].pairIdentifier == (pdev->DiskMirror[1].pairIdentifier ^ 1)) )
+			{
+			if ( (pdev->DiskMirror[0].status & UCBF_MATCHED) && (pdev->DiskMirror[1].status & UCBF_MATCHED) )
+				break;
+
+			if ( pdev->DiskMirror[0].status & UCBF_SURVIVOR )				// is first drive survivor?
+				testsize = SetReconstruct (pdev, 0);
+			else
+				if ( pdev->DiskMirror[1].status & UCBF_SURVIVOR )			// is second drive survivor?
+					testsize = SetReconstruct (pdev, 1);
+
+			if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+				{
+				if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+					pdev->mirrorRecon = 0;
+				else
+					pdev->mirrorRecon = 1;
+				pdev->reconOn = TRUE;
+				}
+			break;
+			}
+
+		if ( !pdev->reconOn )
+			goto reconTimerExpiry;
+
+		if ( padapter->bigD )
+			{
+			padapter->failRegister = 0;
+			outb_p (~padapter->failRegister, padapter->regFail);
+			}
+		else
+			{
+			zc = ((inb_p (padapter->regStatSel) >> 3) | inb_p (padapter->regStatSel)) & 0x83;		// mute the alarm
+			outb_p (0xFF, padapter->regFail);
+			}
+
+		while ( 1 )
+			{
+			DEB (printk ("\npci2220i: hard reset issue"));
+			if ( HardReset (padapter, pdev, pdev->spigots[pdev->mirrorRecon]) )
+				{
+				DEB (printk ("\npci2220i: sub 1"));
+				break;
+				}
+
+			pdev->lastsectorlba[pdev->mirrorRecon] = InlineIdentify (padapter, pdev->spigots[pdev->mirrorRecon], pdev->deviceID[pdev->mirrorRecon] & 1);
+
+			if ( pdev->lastsectorlba[pdev->mirrorRecon] < testsize )
+				{
+				DEB (printk ("\npci2220i: sub 2 %ld %ld", pdev->lastsectorlba[pdev->mirrorRecon], testsize));
+				break;
+				}
+
+	        // test LBA and multiper sector transfer compatibility
+			if (!pid->SupportLBA || (pid->NumSectorsPerInt < SECTORSXFER) || !pid->Valid_64_70 )
+				{
+				DEB (printk ("\npci2220i: sub 3"));
+				break;
+				}
+
+	        // test PIO/bus matering mode compatibility
+			if ( (pid->MinPIOCycleWithoutFlow > 240) && !pid->SupportIORDYDisable && !padapter->timingPIO )
+				{
+				DEB (printk ("\npci2220i: sub 4"));
+				break;
+				}
+
+			if ( pid->MinPIOCycleWithoutFlow <= 120 )	// setup timing mode of drive
+				minmode = 5;
+			else
+				{
+				if ( pid->MinPIOCylceWithFlow <= 150 )
+					minmode = 4;
+				else
+					{
+					if ( pid->MinPIOCylceWithFlow <= 180 )
+						minmode = 3;
+					else
+						{
+						if ( pid->MinPIOCylceWithFlow <= 240 )
+							minmode = 2;
+						else
+							{
+							DEB (printk ("\npci2220i: sub 5"));
+							break;
+							}
+						}
+					}
+				}
+
+			if ( padapter->timingMode > minmode )									// set minimum timing mode
+				padapter->timingMode = minmode;
+			if ( padapter->timingMode >= 2 )
+				padapter->timingAddress	= ModeArray[padapter->timingMode - 2];
+			else
+				padapter->timingPIO = TRUE;
+
+			padapter->reconOn = TRUE;
+			break;
+			}
+
+		if ( !pdev->reconOn )
+			{		
+			padapter->survivor = pdev->mirrorRecon ^ 1;
+			padapter->reconPhase = RECON_PHASE_FAILOVER;
+			DEB (printk ("\npci2220i: FAILURE 7"));
+			InitFailover (padapter, pdev);
+			goto reconTimerExpiry;
+			}
+
+		pdev->raid = TRUE;
+	
+		if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) )
+			goto reconTimerExpiry;
+		padapter->reconPhase = RECON_PHASE_MARKING;
+		goto reconTimerExpiry;
+		}
+
+	//**********************************
+	// reconstruct copy starts here	
+	//**********************************
+	if ( pdev->reconCount++ > 2000 )
+		{
+		pdev->reconCount = 0;
+		if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
+			{
+			padapter->survivor = pdev->mirrorRecon ^ 1;
+			padapter->reconPhase = RECON_PHASE_FAILOVER;
+			DEB (printk ("\npci2220i: FAILURE 8"));
+			InitFailover (padapter, pdev);
+			goto reconTimerExpiry;
+			}
+		padapter->reconPhase = RECON_PHASE_UPDATE;
+		goto reconTimerExpiry;
+		}
+
+	zl = pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint;	
+	padapter->reconSize = pdev->DiskMirror[pdev->mirrorRecon ^ 1].reconstructPoint - zl;
+	if ( padapter->reconSize > MAX_BUS_MASTER_BLOCKS )
+		padapter->reconSize = MAX_BUS_MASTER_BLOCKS;
+
+	if ( padapter->reconSize )
+		{
+		SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);	// select the spigots
+		outb_p (pdev->byte6 | ((UCHAR *)(&zl))[3], padapter->regLba24);	// select the drive
+		SelectSpigot (padapter, pdev->spigot);
+		if ( WaitReady (padapter) )
+			goto reconTimerExpiry;
+
+		SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
+		if ( WaitReady (padapter) )
+			{
+			padapter->survivor = pdev->mirrorRecon ^ 1;
+			padapter->reconPhase = RECON_PHASE_FAILOVER;
+			DEB (printk ("\npci2220i: FAILURE 9"));
+			InitFailover (padapter, pdev);
+			goto reconTimerExpiry;
+			}
+	
+		SelectSpigot (padapter, pdev->spigots[0] | pdev->spigots[1]);
+		outb_p (padapter->reconSize & 0xFF, padapter->regSectCount);
+		outb_p (((UCHAR *)(&zl))[0], padapter->regLba0);
+		outb_p (((UCHAR *)(&zl))[1], padapter->regLba8);
+		outb_p (((UCHAR *)(&zl))[2], padapter->regLba16);
+		padapter->expectingIRQ = TRUE;
+		padapter->reconPhase = RECON_PHASE_READY;
+		SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
+		WriteCommand (padapter, WRITE_CMD);
+		StartTimer (padapter);
+		SelectSpigot (padapter, pdev->spigot);
+		WriteCommand (padapter, READ_CMD);
+		goto reconTimerExpiry;
+		}
+
+	pdev->DiskMirror[pdev->mirrorRecon].status = UCBF_MIRRORED | UCBF_MATCHED;
+	pdev->DiskMirror[pdev->mirrorRecon ^ 1].status = UCBF_MIRRORED | UCBF_MATCHED;
+	if ( WriteSignature (padapter, pdev, pdev->spigot, pdev->mirrorRecon ^ 1) )
+		goto reconTimerExpiry;
+	padapter->reconPhase = RECON_PHASE_LAST;
+
+reconTimerExpiry:;
+    /*
+     * Release the I/O spinlock and restore the original flags
+     * which will enable interrupts if and only if they were
+     * enabled on entry.
+     */
+    spin_unlock_irqrestore(host->host_lock, flags);
+	}
+/****************************************************************
+ *	Name:	Irq_Handler	:LOCAL
+ *
+ *	Description:	Interrupt handler.
+ *
+ *	Parameters:		irq		- Hardware IRQ number.
+ *					dev_id	-
+ *					regs	-
+ *
+ *	Returns:		TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static irqreturn_t Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	struct Scsi_Host   *shost = NULL;	// Pointer to host data block
+	PADAPTER2220I		padapter;		// Pointer to adapter control structure
+	POUR_DEVICE			pdev;
+	Scsi_Cmnd		   *SCpnt;
+	UCHAR				status;
+	UCHAR				status1;
+	ATAPI_STATUS		statusa;
+	ATAPI_REASON		reasona;
+	ATAPI_ERROR			errora;
+	int					z;
+	ULONG				zl;
+    unsigned long		flags;
+    int handled = 0;
+
+//	DEB (printk ("\npci2220i received interrupt\n"));
+
+	for ( z = 0; z < NumAdapters;  z++ )								// scan for interrupt to process
+		{
+		if ( PsiHost[z]->irq == (UCHAR)(irq & 0xFF) )
+			{
+			if ( inw_p (HOSTDATA(PsiHost[z])->regIrqControl) & 0x8000 )
+				{
+				shost = PsiHost[z];
+				break;
+				}
+			}
+		}
+
+	if ( !shost )
+		{
+		DEB (printk ("\npci2220i: not my interrupt"));
+		goto out;
+		}
+
+	handled = 1;
+	spin_lock_irqsave(shost->host_lock, flags);
+	padapter = HOSTDATA(shost);
+	pdev = padapter->pdev;
+	SCpnt = padapter->SCpnt;
+	outb_p (0x08, padapter->regDmaCmdStat);									// cancel interrupt from DMA engine
+
+	if ( padapter->atapi && SCpnt )
+		{
+		*(char *)&statusa = inb_p (padapter->regStatCmd);						// read the device status
+		*(char *)&reasona = inb_p (padapter->regSectCount);						// read the device interrupt reason
+	
+		if ( !statusa.bsy )
+			{
+			if ( statusa.drq )													// test for transfer phase
+				{
+				if ( !reasona.cod )												// test for data phase
+					{
+					z = (ULONG)inb_p (padapter->regLba8) | (ULONG)(inb_p (padapter->regLba16) << 8);
+					if ( padapter->reqSense )
+						insw (padapter->regData, SCpnt->sense_buffer, z / 2);
+					else
+						AtapiBusMaster (padapter, reasona.io, z);
+					goto irq_return;
+					}
+				if ( reasona.cod && !reasona.io )								// test for command packet phase
+					{
+					if ( padapter->reqSense )
+						AtapiRequestSense (padapter, pdev, SCpnt, TRUE);
+					else
+						AtapiSendCdb (padapter, pdev, padapter->atapiCdb);
+					goto irq_return;
+					}
+				}
+			else
+				{
+				if ( reasona.io && statusa.drdy )								// test for status phase
+					{
+					Atapi2Scsi (padapter, SCpnt);
+					if ( statusa.check )
+						{
+						*(UCHAR *)&errora = inb_p (padapter->regError);			// read the device error
+						if ( errora.senseKey )
+							{
+							if ( padapter->reqSense || AtapiRequestSense (padapter, pdev, SCpnt, FALSE) )
+								OpDone (padapter, DID_ERROR << 16);
+							}
+						else
+							{
+							if ( errora.ili || errora.abort )
+								OpDone (padapter, DID_ERROR << 16);
+							else
+								OpDone (padapter, DID_OK << 16);	
+							}
+						}
+					else
+						if ( padapter->reqSense )
+							{
+							DEB (printk ("PCI2242I: Sense codes - %X %X %X ", ((UCHAR *)SCpnt->sense_buffer)[0], ((UCHAR *)SCpnt->sense_buffer)[12], ((UCHAR *)SCpnt->sense_buffer)[13]));
+							OpDone (padapter, (DRIVER_SENSE << 24) | (DID_OK << 16) | 2);
+							}
+						else
+							OpDone (padapter, DID_OK << 16);	
+					}
+				}
+			}		
+		goto irq_return;
+		}
+	
+	if ( !padapter->expectingIRQ || !(SCpnt || padapter->reconPhase) )
+		{
+		DEB(printk ("\npci2220i Unsolicited interrupt\n"));
+		STOP_HERE ();
+		goto irq_return;
+		}
+	padapter->expectingIRQ = 0;
+
+	if ( padapter->failinprog )
+		{
+		DEB (printk ("\npci2220i interrupt failover complete"));
+		padapter->failinprog = FALSE;
+		status = inb_p (padapter->regStatCmd);								// read the device status
+		if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+			{
+			DEB (printk ("\npci2220i: interrupt failover error from drive %X", status));
+			padapter->cmd = 0;
+			}
+		else
+			{
+			DEB (printk ("\npci2220i: restarting failed opertation."));
+			pdev->spigot = (padapter->survivor) ? pdev->spigots[1] : pdev->spigots[0];
+			del_timer (&padapter->timer);
+			if ( padapter->reconPhase )
+				OpDone (padapter, DID_OK << 16);
+			else
+				Pci2220i_QueueCommand (SCpnt, SCpnt->scsi_done);
+			goto irq_return;		
+			}
+		}
+
+	if ( padapter->reconPhase )
+		{
+		switch ( padapter->reconPhase )
+			{
+			case RECON_PHASE_MARKING:
+			case RECON_PHASE_LAST:
+				status = inb_p (padapter->regStatCmd);						// read the device status
+				del_timer (&padapter->timer);
+				if ( padapter->reconPhase == RECON_PHASE_LAST )
+					{
+					if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+						{
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
+						DEB (printk ("\npci2220i: FAILURE 10"));
+						if ( InitFailover (padapter, pdev) )
+							OpDone (padapter, DecodeError (padapter, status));
+						goto irq_return;
+						}
+					if ( WriteSignature (padapter, pdev, pdev->spigots[pdev->mirrorRecon], pdev->mirrorRecon) )
+						{
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+						DEB (printk ("\npci2220i: FAILURE 11"));
+						if ( InitFailover (padapter, pdev) )
+							OpDone (padapter, DecodeError (padapter, status));
+						goto irq_return;
+						}
+					padapter->reconPhase = RECON_PHASE_END;	
+					goto irq_return;
+					}
+				OpDone (padapter, DID_OK << 16);
+				goto irq_return;
+
+			case RECON_PHASE_READY:
+				status = inb_p (padapter->regStatCmd);						// read the device status
+				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+					{
+					del_timer (&padapter->timer);
+					OpDone (padapter, DecodeError (padapter, status));
+					goto irq_return;
+					}
+				SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon]);
+				if ( WaitDrq (padapter) )
+					{
+					del_timer (&padapter->timer);
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+					DEB (printk ("\npci2220i: FAILURE 12"));
+					if ( InitFailover (padapter, pdev) )
+						OpDone (padapter, DecodeError (padapter, status));
+					goto irq_return;
+					}
+				SelectSpigot (padapter, pdev->spigot | SEL_COPY | padapter->bigD);
+				padapter->reconPhase = RECON_PHASE_COPY;
+				padapter->expectingIRQ = TRUE;
+				if ( padapter->timingPIO )
+					{
+					insw (padapter->regData, padapter->kBuffer, padapter->reconSize * (BYTES_PER_SECTOR / 2));
+					}
+				else
+					{
+					if ( (padapter->timingMode > 3) )
+						{
+						if ( padapter->bigD )
+							outl (BIGD_DATA_MODE3, padapter->regDmaAddrLoc);
+						else
+							outl (DALE_DATA_MODE3, padapter->regDmaAddrLoc);
+						}
+					else
+						outl (padapter->timingAddress, padapter->regDmaAddrLoc);
+					outl (padapter->kBufferDma, padapter->regDmaAddrPci);
+					outl (padapter->reconSize * BYTES_PER_SECTOR, padapter->regDmaCount);
+					outb_p (8, padapter->regDmaDesc);						// read operation
+					if ( padapter->bigD )
+						outb_p (8, padapter->regDmaMode);					// no interrupt
+					else
+						outb_p (1, padapter->regDmaMode);					// no interrupt
+					outb_p (0x03, padapter->regDmaCmdStat);					// kick the DMA engine in gear
+					}
+				goto irq_return;
+
+			case RECON_PHASE_COPY:
+				pdev->DiskMirror[pdev->mirrorRecon].reconstructPoint += padapter->reconSize;
+
+			case RECON_PHASE_UPDATE:
+				SelectSpigot (padapter, pdev->spigots[pdev->mirrorRecon] | SEL_IRQ_OFF);
+				status = inb_p (padapter->regStatCmd);						// read the device status
+				del_timer (&padapter->timer);
+				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+					{
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+					DEB (printk ("\npci2220i: FAILURE 13"));
+					DEB (printk ("\n  status register = %X   error = %X", status, inb_p (padapter->regError)));
+					if ( InitFailover (padapter, pdev) )
+						OpDone (padapter, DecodeError (padapter, status));
+					goto irq_return;
+					}
+				OpDone (padapter, DID_OK << 16);
+				goto irq_return;
+
+			case RECON_PHASE_END:
+				status = inb_p (padapter->regStatCmd);						// read the device status
+				del_timer (&padapter->timer);
+				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+					{
+					padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 0 : 1;
+					DEB (printk ("\npci2220i: FAILURE 14"));
+					if ( InitFailover (padapter, pdev) )
+						OpDone (padapter, DecodeError (padapter, status));
+					goto irq_return;
+					}
+				pdev->reconOn = 0;
+				if ( padapter->bigD )
+					{
+					for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+						{
+						if ( padapter->device[z].DiskMirror[0].status & UCBF_SURVIVOR )
+							{
+							Alarm (padapter, padapter->device[z].deviceID[0] ^ 2);
+							MuteAlarm (padapter);
+							}
+						if ( padapter->device[z].DiskMirror[1].status & UCBF_SURVIVOR )
+							{
+							Alarm (padapter, padapter->device[z].deviceID[1] ^ 2);
+							MuteAlarm (padapter);
+							}
+						}
+					}
+				OpDone (padapter, DID_OK << 16);
+				goto irq_return;
+
+			default:
+				goto irq_return;
+			}
+		}
+		
+	switch ( padapter->cmd )												// decide how to handle the interrupt
+		{
+		case READ_CMD:
+			if ( padapter->sectorCount )
+				{
+				status = inb_p (padapter->regStatCmd);						// read the device status
+				if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+					{
+					if ( pdev->raid )
+						{
+						padapter->survivor = ( pdev->spigot == pdev->spigots[0] ) ? 1 : 0;
+						del_timer (&padapter->timer);
+						DEB (printk ("\npci2220i: FAILURE 15"));
+						if ( !InitFailover (padapter, pdev) )
+							goto irq_return;
+						}
+					break;	
+					}
+				if ( padapter->timingPIO )
+					{
+					insw (padapter->regData, padapter->kBuffer, padapter->readCount / 2);
+					padapter->sectorCount -= padapter->readCount / BYTES_PER_SECTOR;
+					WalkScatGath (padapter, TRUE, padapter->readCount);
+					if ( !padapter->sectorCount )
+						{
+						status = 0;
+						break;
+						}
+					}
+				else
+					{
+					if ( padapter->readCount )
+						WalkScatGath (padapter, TRUE, padapter->readCount);
+					BusMaster (padapter, 1, 1);
+					}
+				padapter->expectingIRQ = TRUE;
+				goto irq_return;
+				}
+			if ( padapter->readCount && !padapter->timingPIO )
+				WalkScatGath (padapter, TRUE, padapter->readCount);
+			status = 0;
+			break;
+
+		case WRITE_CMD:
+			if ( pdev->raid )
+				{
+				SelectSpigot (padapter, pdev->spigots[0] | SEL_IRQ_OFF);				
+				status = inb_p (padapter->regStatCmd);								// read the device status
+				SelectSpigot (padapter, pdev->spigots[1] | SEL_IRQ_OFF);				
+				status1 = inb_p (padapter->regStatCmd);								// read the device status
+				}
+			else
+				SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);				
+				status = inb_p (padapter->regStatCmd);								// read the device status
+				status1 = 0;
+		
+			if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+				{	
+				if ( pdev->raid && !(status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT)) )
+					{
+					padapter->survivor = 1;
+					del_timer (&padapter->timer);
+					SelectSpigot (padapter, pdev->spigot | SEL_IRQ_OFF);
+					DEB (printk ("\npci2220i: FAILURE 16  status = %X  error = %X", status, inb_p (padapter->regError)));
+					if ( !InitFailover (padapter, pdev) )
+						goto irq_return;
+					}
+				break;
+				}
+			if ( pdev->raid )
+				{
+				if ( status1 & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+					{	
+					padapter->survivor = 0;
+					del_timer (&padapter->timer);
+					DEB (printk ("\npci2220i: FAILURE 17  status = %X  error = %X", status1, inb_p (padapter->regError)));
+					if ( !InitFailover (padapter, pdev) )
+						goto irq_return;
+					status = status1;
+					break;
+					}
+				if ( padapter->sectorCount )
+					{
+					status = WriteDataBoth (padapter, pdev);
+					if ( status )
+						{
+						padapter->survivor = status >> 1;
+						del_timer (&padapter->timer);
+						DEB (printk ("\npci2220i: FAILURE 18"));
+						if ( !InitFailover (padapter, pdev) )
+							goto irq_return;
+						SelectSpigot (padapter, pdev->spigots[status] | SEL_IRQ_OFF);				
+						status = inb_p (padapter->regStatCmd);								// read the device status
+						break;
+						}
+					padapter->expectingIRQ = TRUE;
+					goto irq_return;
+					}
+				status = 0;
+				break;
+				}
+			if ( padapter->sectorCount )	
+				{	
+				SelectSpigot (padapter, pdev->spigot | padapter->bigD);
+				status = WriteData (padapter);
+				if ( status )
+					break;
+				padapter->expectingIRQ = TRUE;
+				goto irq_return;
+				}
+			status = 0;
+			break;
+
+		case IDE_COMMAND_IDENTIFY:
+			{
+			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;
+			PIDENTIFY_DATA	pid = (PIDENTIFY_DATA)padapter->kBuffer;
+
+			status = inb_p (padapter->regStatCmd);
+			if ( status & IDE_STATUS_DRQ )
+				{
+				insw (padapter->regData, pid, sizeof (IDENTIFY_DATA) >> 1);
+
+				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.
+				pinquiryData->DeviceType = 0;
+				pinquiryData->Versions = 2;
+				pinquiryData->AdditionalLength = 35 - 4;
+
+				// Fill in vendor identification fields.
+				for ( z = 0;  z < 20;  z += 2 )
+					{
+					pinquiryData->VendorId[z]	  = ((UCHAR *)pid->ModelNumber)[z + 1];
+					pinquiryData->VendorId[z + 1] = ((UCHAR *)pid->ModelNumber)[z];
+					}
+
+				// Initialize unused portion of product id.
+				for ( z = 0;  z < 4;  z++ )
+					pinquiryData->ProductId[12 + z] = ' ';
+
+				// Move firmware revision from IDENTIFY data to
+				// product revision in INQUIRY data.
+				for ( z = 0;  z < 4;  z += 2 )
+					{
+					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)pid->FirmwareRevision)[z + 1];
+					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)pid->FirmwareRevision)[z];
+					}
+				if ( pdev == padapter->device )
+					*((USHORT *)(&pinquiryData->VendorSpecific)) = DEVICE_DALE_1;
+				
+				status = 0;
+				}
+			break;
+			}
+
+		default:
+			status = 0;
+			break;
+		}
+
+	del_timer (&padapter->timer);
+	if ( status )
+		{
+		DEB (printk ("\npci2220i Interrupt handler return error"));
+		zl = DecodeError (padapter, status);
+		}
+	else
+		zl = DID_OK << 16;
+
+	OpDone (padapter, zl);
+irq_return:
+    spin_unlock_irqrestore(shost->host_lock, flags);
+out:
+	return IRQ_RETVAL(handled);
+}
+
+/****************************************************************
+ *	Name:	Pci2220i_QueueCommand
+ *
+ *	Description:	Process a queued command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *					done  - Pointer to done function to call.
+ *
+ *	Returns:		Status code.
+ *
+ ****************************************************************/
+int Pci2220i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+	{
+	UCHAR		   *cdb = (UCHAR *)SCpnt->cmnd;					// Pointer to SCSI CDB
+	PADAPTER2220I	padapter = HOSTDATA(SCpnt->device->host);			// Pointer to adapter control structure
+	POUR_DEVICE		pdev	 = &padapter->device[SCpnt->device->id];// Pointer to device information
+	UCHAR			rc;											// command return code
+	int				z; 
+	PDEVICE_RAID1	pdr;
+
+	SCpnt->scsi_done = done;
+	padapter->SCpnt = SCpnt;  									// Save this command data
+	padapter->readCount = 0;
+
+	if ( SCpnt->use_sg )
+		{
+		padapter->currentSgBuffer = ((struct scatterlist *)SCpnt->request_buffer)[0].address;
+		padapter->currentSgCount = ((struct scatterlist *)SCpnt->request_buffer)[0].length;
+		}
+	else
+		{
+		padapter->currentSgBuffer = SCpnt->request_buffer;
+		padapter->currentSgCount = SCpnt->request_bufflen;
+		}
+	padapter->nextSg = 1;
+
+	if ( !done )
+		{
+		printk("pci2220i_queuecommand: %02X: done can't be NULL\n", *cdb);
+		return 0;
+		}
+	
+	if ( padapter->atapi )
+		{
+		UCHAR			zlo, zhi;
+
+		DEB (printk ("\nPCI2242I: ID %d, LUN %d opcode %X ", SCpnt->device->id, SCpnt->device->lun, *cdb));
+		padapter->pdev = pdev;
+		if ( !pdev->byte6 || SCpnt->device->lun )
+			{
+			OpDone (padapter, DID_BAD_TARGET << 16);
+			return 0;
+			}
+	
+		padapter->atapiSpecial = FALSE;
+		padapter->reqSense = FALSE;
+		memset (padapter->atapiCdb, 0, 16);
+		SelectSpigot (padapter, pdev->spigot);									// select the spigot
+		AtapiDevice (padapter, pdev->byte6);									// select the drive
+		if ( AtapiWaitReady (padapter, 100) )
+			{
+			OpDone (padapter, DID_NO_CONNECT << 16);
+			return 0;
+			}
+
+		switch ( cdb[0] ) 
+			{
+			case SCSIOP_MODE_SENSE:
+			case SCSIOP_MODE_SELECT:
+				Scsi2Atapi (padapter, SCpnt);
+				z = SCpnt->request_bufflen + 4;
+				break;
+			case SCSIOP_READ6:
+			case SCSIOP_WRITE6:
+				Scsi2Atapi (padapter, SCpnt);
+				z = SCpnt->request_bufflen;
+				break;
+			default:
+				memcpy (padapter->atapiCdb, cdb, SCpnt->cmd_len);
+				z = SCpnt->request_bufflen;
+				break;
+			}
+		if ( z > ATAPI_TRANSFER )
+			z = ATAPI_TRANSFER;
+	    zlo = (UCHAR)(z & 0xFF);
+	    zhi = (UCHAR)(z >> 8);
+
+	 	AtapiCountLo (padapter, zlo);						
+	   	AtapiCountHi (padapter, zhi);						
+	   	outb_p (0, padapter->regError);						
+		WriteCommand (padapter, IDE_COMMAND_ATAPI_PACKET);
+		if ( pdev->cmdDrqInt )
+			return 0;
+
+		if ( AtapiWaitDrq (padapter, 500) )
+			{
+			OpDone (padapter, DID_ERROR << 16);
+			return 0;
+			}
+		AtapiSendCdb (padapter, pdev, padapter->atapiCdb);	
+		return 0;
+		}
+	
+	if ( padapter->reconPhase )
+		return 0;
+	if ( padapter->reconTimer.data )
+		{
+		del_timer (&padapter->reconTimer);
+		padapter->reconTimer.data = 0;
+		}
+		
+	if ( (SCpnt->device->id >= padapter->numberOfDrives) || SCpnt->device->lun )
+		{
+		OpDone (padapter, DID_BAD_TARGET << 16);
+		return 0;
+		}
+	
+	switch ( *cdb )
+		{
+		case SCSIOP_INQUIRY:   					// inquiry CDB
+			{
+			if ( cdb[2] == SC_MY_RAID )
+				{
+				switch ( cdb[3] ) 
+					{
+					case MY_SCSI_REBUILD:
+						for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+							{
+							pdev = &padapter->device[z];
+							if ( ((pdev->DiskMirror[0].status & UCBF_SURVIVOR) && (pdev->DiskMirror[1].status & UCBF_MIRRORED)) ||
+								 ((pdev->DiskMirror[1].status & UCBF_SURVIVOR) && (pdev->DiskMirror[0].status & UCBF_MIRRORED)) )
+								{
+								padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+								}
+							}
+						OpDone (padapter, DID_OK << 16);
+						break;
+					case MY_SCSI_ALARMMUTE:
+						MuteAlarm (padapter);
+						OpDone (padapter, DID_OK << 16);
+						break;
+					case MY_SCSI_DEMOFAIL:
+						padapter->demoFail = TRUE;				
+						OpDone (padapter, DID_OK << 16);
+						break;
+					default:
+						z = cdb[5];				// get index
+						pdr = (PDEVICE_RAID1)SCpnt->request_buffer;
+						if ( padapter->raidData[z] )
+							{
+							memcpy (&pdr->DiskRaid1, padapter->raidData[z], sizeof (DISK_MIRROR));
+							if ( padapter->raidData[z]->reconstructPoint > padapter->raidData[z ^ 2]->reconstructPoint )
+								pdr->TotalSectors = padapter->raidData[z]->reconstructPoint;
+							else
+								pdr->TotalSectors = padapter->raidData[z ^ 2]->reconstructPoint;
+							}
+						else
+							memset (pdr, 0, sizeof (DEVICE_RAID1));
+						OpDone (padapter, DID_OK << 16);
+						break;
+					}	
+				return 0;
+				}
+			padapter->cmd = IDE_COMMAND_IDENTIFY;
+			break;
+			}
+
+		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
+			OpDone (padapter, DID_OK << 16);
+			return 0;
+		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
+			{
+			PREAD_CAPACITY_DATA	pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+
+			pdata->blksiz = 0x20000;
+			XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
+			OpDone (padapter, DID_OK << 16);
+			return 0;
+			}
+		case SCSIOP_VERIFY:						// verify CDB
+			padapter->startSector = XSCSI2LONG (&cdb[2]);
+			padapter->sectorCount = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
+			padapter->cmd = IDE_COMMAND_VERIFY;
+			break;
+		case SCSIOP_READ:						// read10 CDB
+			padapter->startSector = XSCSI2LONG (&cdb[2]);
+			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+			padapter->cmd = READ_CMD;
+			break;
+		case SCSIOP_READ6:						// read6  CDB
+			padapter->startSector = SCSI2LONG (&cdb[1]);
+			padapter->sectorCount = cdb[4];
+			padapter->cmd = READ_CMD;
+			break;
+		case SCSIOP_WRITE:						// write10 CDB
+			padapter->startSector = XSCSI2LONG (&cdb[2]);
+			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+			padapter->cmd = WRITE_CMD;
+			break;
+		case SCSIOP_WRITE6:						// write6  CDB
+			padapter->startSector = SCSI2LONG (&cdb[1]);
+			padapter->sectorCount = cdb[4];
+			padapter->cmd = WRITE_CMD;
+			break;
+		default:
+			DEB (printk ("pci2220i_queuecommand: Unsupported command %02X\n", *cdb));
+			OpDone (padapter, DID_ERROR << 16);
+			return 0;
+		}
+
+	if ( padapter->reconPhase )
+		return 0;
+	
+	padapter->pdev = pdev;
+
+	while ( padapter->demoFail )
+		{
+		pdev = padapter->pdev = &padapter->device[0];
+		padapter->demoFail = FALSE;
+		if ( !pdev->raid || 
+			 (pdev->DiskMirror[0].status & UCBF_SURVIVOR) || 
+			 (pdev->DiskMirror[1].status & UCBF_SURVIVOR) )
+			{
+			break;
+			}
+		if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+			padapter->survivor = 1;
+		else
+			padapter->survivor = 0;
+				DEB (printk ("\npci2220i: FAILURE 19"));
+		if ( InitFailover (padapter, pdev) )
+			break;
+		return 0;
+		}
+
+	StartTimer (padapter);
+	if ( pdev->raid && (padapter->cmd == WRITE_CMD) )
+		{
+		rc = IdeCmdBoth (padapter, pdev);
+		if ( !rc )
+			rc = WriteDataBoth (padapter, pdev);
+		if ( rc )
+			{
+			del_timer (&padapter->timer);
+			padapter->expectingIRQ = 0;
+			padapter->survivor = rc >> 1;
+				DEB (printk ("\npci2220i: FAILURE 20"));
+			if ( InitFailover (padapter, pdev) )
+				{
+				OpDone (padapter, DID_ERROR << 16);
+				return 0;
+				}
+			}
+		}
+	else
+		{
+		rc = IdeCmd (padapter, pdev);
+		if ( (padapter->cmd == WRITE_CMD) && !rc )
+			rc = WriteData (padapter);
+		if ( rc )
+			{
+			del_timer (&padapter->timer);
+			padapter->expectingIRQ = 0;
+			if ( pdev->raid )
+				{
+				padapter->survivor = (pdev->spigot ^ 3) >> 1;
+				DEB (printk ("\npci2220i: FAILURE 21"));
+				if ( !InitFailover (padapter, pdev) )
+					return 0;
+				}
+			OpDone (padapter, DID_ERROR << 16);
+			return 0;
+			}
+		}
+	return 0;
+	}
+/****************************************************************
+ *	Name:			ReadFlash
+ *
+ *	Description:	Read information from controller Flash memory.
+ *
+ *	Parameters:		padapter - Pointer to host interface data structure.
+ *					pdata	 - Pointer to data structures.
+ *					base	 - base address in Flash.
+ *					length	 - lenght of data space in bytes.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+static VOID ReadFlash (PADAPTER2220I padapter, VOID *pdata, ULONG base, ULONG length)
+	{
+	ULONG	 oldremap;
+	UCHAR	 olddesc;
+	ULONG	 z;
+	UCHAR	*pd = (UCHAR *)pdata;
+
+	oldremap = inl (padapter->regRemap);							// save values to restore later
+	olddesc  = inb_p (padapter->regDesc);
+
+	outl (base | 1, padapter->regRemap);							// remap to Flash space as specified
+	outb_p (0x40, padapter->regDesc);								// describe remap region as 8 bit
+	for ( z = 0;  z < length;  z++)									// get "length" data count
+		*pd++ = inb_p (padapter->regBase + z);						// read in the data
+
+	outl (oldremap, padapter->regRemap);							// restore remap register values
+	outb_p (olddesc, padapter->regDesc);
+	}
+/****************************************************************
+ *	Name:			GetRegs
+ *
+ *	Description:	Initialize the regester information.
+ *
+ *	Parameters:		pshost		  - Pointer to SCSI host data structure.
+ *					bigd		  - PCI-2240I identifier
+ *					pcidev		  - Pointer to device data structure.
+ *
+ *	Returns:		TRUE if failure to install.
+ *
+ ****************************************************************/
+static USHORT GetRegs (struct Scsi_Host *pshost, BOOL bigd, struct pci_dev *pcidev)
+	{
+	PADAPTER2220I	padapter;
+	int				setirq;
+	int				z;
+	USHORT			zr, zl;
+	UCHAR		   *consistent;
+	dma_addr_t		consistentDma;
+
+	padapter = HOSTDATA(pshost);
+	memset (padapter, 0, sizeof (ADAPTER2220I));
+	memset (&DaleSetup, 0, sizeof (DaleSetup));
+	memset (DiskMirror, 0, sizeof (DiskMirror));
+
+	zr = pci_resource_start (pcidev, 1);
+	zl = pci_resource_start (pcidev, 2);
+
+	padapter->basePort = zr;
+	padapter->regRemap		= zr + RTR_LOCAL_REMAP;					// 32 bit local space remap
+	padapter->regDesc		= zr + RTR_REGIONS;	  					// 32 bit local region descriptor
+	padapter->regRange		= zr + RTR_LOCAL_RANGE;					// 32 bit local range
+	padapter->regIrqControl	= zr + RTR_INT_CONTROL_STATUS;			// 16 bit interrupt control and status
+	padapter->regScratchPad	= zr + RTR_MAILBOX;	  					// 16 byte scratchpad I/O base address
+
+	padapter->regBase		= zl;
+	padapter->regData		= zl + REG_DATA;						// data register I/O address
+	padapter->regError		= zl + REG_ERROR;						// error register I/O address
+	padapter->regSectCount	= zl + REG_SECTOR_COUNT;				// sector count register I/O address
+	padapter->regLba0		= zl + REG_LBA_0;						// least significant byte of LBA
+	padapter->regLba8		= zl + REG_LBA_8;						// next least significant byte of LBA
+	padapter->regLba16		= zl + REG_LBA_16;						// next most significan byte of LBA
+	padapter->regLba24		= zl + REG_LBA_24;						// head and most 4 significant bits of LBA
+	padapter->regStatCmd	= zl + REG_STAT_CMD;					// status on read and command on write register
+	padapter->regStatSel	= zl + REG_STAT_SEL;					// board status on read and spigot select on write register
+	padapter->regFail		= zl + REG_FAIL;
+	padapter->regAltStat	= zl + REG_ALT_STAT;
+	padapter->pcidev		= pcidev;
+
+	if ( bigd )
+		{
+		padapter->regDmaDesc	= zr + RTR_DMA0_DESC_PTR;			// address of the DMA discriptor register for direction of transfer
+		padapter->regDmaCmdStat	= zr + RTR_DMA_COMMAND_STATUS;		// Byte #0 of DMA command status register
+		padapter->regDmaAddrPci	= zr + RTR_DMA0_PCI_ADDR;			// 32 bit register for PCI address of DMA
+		padapter->regDmaAddrLoc	= zr + RTR_DMA0_LOCAL_ADDR;			// 32 bit register for local bus address of DMA
+		padapter->regDmaCount	= zr + RTR_DMA0_COUNT;				// 32 bit register for DMA transfer count
+		padapter->regDmaMode	= zr + RTR_DMA0_MODE + 1;			// 32 bit register for DMA mode control
+		padapter->bigD			= SEL_NEW_SPEED_1;					// set spigot speed control bit
+		}
+	else
+		{
+		padapter->regDmaDesc	= zl + RTL_DMA1_DESC_PTR;			// address of the DMA discriptor register for direction of transfer
+		padapter->regDmaCmdStat	= zl + RTL_DMA_COMMAND_STATUS + 1;	// Byte #1 of DMA command status register
+		padapter->regDmaAddrPci	= zl + RTL_DMA1_PCI_ADDR;			// 32 bit register for PCI address of DMA
+		padapter->regDmaAddrLoc	= zl + RTL_DMA1_LOCAL_ADDR;			// 32 bit register for local bus address of DMA
+		padapter->regDmaCount	= zl + RTL_DMA1_COUNT;				// 32 bit register for DMA transfer count
+		padapter->regDmaMode	= zl + RTL_DMA1_MODE + 1;			// 32 bit register for DMA mode control
+		}
+
+	padapter->numberOfDrives = inb_p (padapter->regScratchPad + BIGD_NUM_DRIVES);
+	if ( !bigd && !padapter->numberOfDrives )						// if no devices on this board
+		return TRUE;
+
+	pshost->irq = pcidev->irq;
+	setirq = 1;
+	for ( z = 0;  z < Installed;  z++ )								// scan for shared interrupts
+		{
+		if ( PsiHost[z]->irq == pshost->irq )						// if shared then, don't posses
+			setirq = 0;
+		}
+	if ( setirq )													// if not shared, posses
+		{
+		if ( request_irq (pshost->irq, Irq_Handler, SA_SHIRQ, "pci2220i", padapter) < 0 )
+			{
+			if ( request_irq (pshost->irq, Irq_Handler, SA_INTERRUPT | SA_SHIRQ, "pci2220i", padapter) < 0 )
+				{
+				printk ("Unable to allocate IRQ for PCI-2220I controller.\n");
+				return TRUE;
+				}
+			}
+		padapter->irqOwned = pshost->irq;							// set IRQ as owned
+		}
+
+	if ( padapter->numberOfDrives )
+		consistent = pci_alloc_consistent (pcidev, SECTORSXFER * BYTES_PER_SECTOR, &consistentDma);
+	else
+		consistent = pci_alloc_consistent (pcidev, ATAPI_TRANSFER, &consistentDma);
+	if ( !consistent )
+		{
+		printk ("Unable to allocate DMA buffer for PCI-2220I controller.\n");
+		free_irq (pshost->irq, padapter);
+		return TRUE;
+		}
+	padapter->kBuffer = consistent;
+	padapter->kBufferDma = consistentDma;
+
+	PsiHost[Installed]	= pshost;									// save SCSI_HOST pointer
+	pshost->io_port		= padapter->basePort;
+	pshost->n_io_port	= 0xFF;
+	pshost->unique_id	= padapter->regBase;
+
+	outb_p (0x01, padapter->regRange);								// fix our range register because other drivers want to tromp on it
+
+	padapter->timingMode = inb_p (padapter->regScratchPad + DALE_TIMING_MODE);
+	if ( padapter->timingMode >= 2 )
+		{
+		if ( bigd )
+			padapter->timingAddress	= ModeArray2[padapter->timingMode - 2];
+		else
+			padapter->timingAddress	= ModeArray[padapter->timingMode - 2];
+		}
+	else
+		padapter->timingPIO = TRUE;
+
+	ReadFlash (padapter, &DaleSetup, DALE_FLASH_SETUP, sizeof (SETUP));
+	ReadFlash (padapter, &DiskMirror, DALE_FLASH_RAID, sizeof (DiskMirror));
+
+	return FALSE;
+	}
+/****************************************************************
+ *	Name:			SetupFinish
+ *
+ *	Description:	Complete the driver initialization process for a card
+ *
+ *	Parameters:		padapter  - Pointer to SCSI host data structure.
+ *					str		  - Pointer to board type string.
+ *
+ *	Returns:		Nothing.
+ *
+ ****************************************************************/
+VOID SetupFinish (PADAPTER2220I padapter, char *str, int irq)
+	{
+	init_timer (&padapter->timer);
+	padapter->timer.function = TimerExpiry;
+	padapter->timer.data = (unsigned long)padapter;
+	init_timer (&padapter->reconTimer);
+	padapter->reconTimer.function = ReconTimerExpiry;
+	padapter->reconTimer.data = (unsigned long)padapter;
+	printk("\nPCI-%sI EIDE CONTROLLER: at I/O = %lX/%lX  IRQ = %d\n", str, padapter->basePort, padapter->regBase, irq);
+	printk("Version %s, Compiled %s %s\n\n", PCI2220I_VERSION, __DATE__, __TIME__);
+	}	
+/****************************************************************
+ *	Name:	Pci2220i_Detect
+ *
+ *	Description:	Detect and initialize our boards.
+ *
+ *	Parameters:		tpnt - Pointer to SCSI host template structure.
+ *
+ *	Returns:		Number of adapters installed.
+ *
+ ****************************************************************/
+int Pci2220i_Detect (Scsi_Host_Template *tpnt)
+	{
+	struct Scsi_Host   *pshost;
+	PADAPTER2220I	    padapter;
+	POUR_DEVICE			pdev;
+	int					unit;
+	int					z;
+	USHORT				raidon;
+	UCHAR				spigot1, spigot2;
+	UCHAR				device;
+	struct pci_dev	   *pcidev = NULL;
+
+	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_DALE_1, pcidev)) != NULL )
+		{
+		if (pci_enable_device(pcidev))
+			continue;
+		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+		if(pshost==NULL)
+			continue;
+			
+		padapter = HOSTDATA(pshost);
+
+		if ( GetRegs (pshost, FALSE, pcidev) )
+			goto unregister;
+
+		scsi_set_device(pshost, &pcidev->dev);
+		pshost->max_id = padapter->numberOfDrives;
+		for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+			{
+			unit = inb_p (padapter->regScratchPad + DALE_CHANNEL_DEVICE_0 + z) & 0x0F;
+			pdev = &padapter->device[z];
+			pdev->byte6		= (UCHAR)(((unit & 1) << 4) | 0xE0);
+			pdev->spigot	= (UCHAR)(1 << (unit >> 1));
+			pdev->sectors	= DaleSetup.setupDevice[unit].sectors;
+			pdev->heads		= DaleSetup.setupDevice[unit].heads;
+			pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+			pdev->blocks	= DaleSetup.setupDevice[unit].blocks;
+
+			if ( !z )
+				{
+				DiskMirror[0].status = inb_p (padapter->regScratchPad + DALE_RAID_0_STATUS);		
+				DiskMirror[1].status = inb_p (padapter->regScratchPad + DALE_RAID_1_STATUS);		
+				if ( (DiskMirror[0].signature == SIGNATURE) && (DiskMirror[1].signature == SIGNATURE) &&
+				     (DiskMirror[0].pairIdentifier == (DiskMirror[1].pairIdentifier ^ 1)) )
+					{			 
+					raidon = TRUE;
+					if ( unit > (unit ^ 2) )
+						unit = unit ^ 2;
+					}	
+				else
+					raidon = FALSE;
+
+				memcpy (pdev->DiskMirror, DiskMirror, sizeof (DiskMirror));
+				padapter->raidData[0] = &pdev->DiskMirror[0];
+				padapter->raidData[2] = &pdev->DiskMirror[1];
+				
+				spigot1 = spigot2 = FALSE;
+				pdev->spigots[0] = 1;
+				pdev->spigots[1] = 2;
+				pdev->lastsectorlba[0] = InlineIdentify (padapter, 1, 0);
+				pdev->lastsectorlba[1] = InlineIdentify (padapter, 2, 0);
+						
+				if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+					spigot1 = TRUE;
+				if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+					spigot2 = TRUE;
+				if ( pdev->DiskMirror[0].status & DiskMirror[1].status & UCBF_SURVIVOR )
+					spigot1 = TRUE;
+
+				if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+					InlineReadSignature (padapter, pdev, 0);
+				if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+					InlineReadSignature (padapter, pdev, 1);
+
+				if ( spigot1 && spigot2 && raidon )
+					{
+					pdev->raid = 1;
+					if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+						pdev->spigot = 2;
+					else
+						pdev->spigot = 1;
+					if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+						padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+					}
+				else
+					{
+					if ( spigot1 )
+						{
+						if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+							goto unregister;
+						pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+						pdev->spigot = 1;
+						}
+					else
+						{
+						if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+							goto unregister;
+						pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+						pdev->spigot = 2;
+						}
+					if ( DaleSetup.rebootRebuild && raidon )
+						padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+					}
+			
+				if ( raidon )
+					break;
+				}
+			}
+
+		SetupFinish (padapter, "2220", pshost->irq);
+	
+		if ( ++Installed < MAXADAPTER )
+			continue;
+		break;
+unregister:;
+		scsi_unregister (pshost);
+		}
+
+	while ( (pcidev = pci_find_device (VENDOR_PSI, DEVICE_BIGD_1, pcidev)) != NULL )
+		{
+		pshost = scsi_register (tpnt, sizeof(ADAPTER2220I));
+		padapter = HOSTDATA(pshost);
+
+		if ( GetRegs (pshost, TRUE, pcidev) )
+			goto unregister1;
+
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			DiskMirror[z].status = inb_p (padapter->regScratchPad + BIGD_RAID_0_STATUS + z);		
+
+		scsi_set_pci_device(pshost, pcidev);
+		pshost->max_id = padapter->numberOfDrives;
+		padapter->failRegister = inb_p (padapter->regScratchPad + BIGD_ALARM_IMAGE);
+		for ( z = 0;  z < padapter->numberOfDrives;  z++ )
+			{
+			unit = inb_p (padapter->regScratchPad + BIGD_DEVICE_0 + z);
+			pdev = &padapter->device[z];
+			pdev->byte6		= (UCHAR)(((unit & 1) << 4) | 0xE0);
+			pdev->spigot	= (UCHAR)(1 << (unit >> 1));
+			pdev->sectors	= DaleSetup.setupDevice[unit].sectors;
+			pdev->heads		= DaleSetup.setupDevice[unit].heads;
+			pdev->cylinders = DaleSetup.setupDevice[unit].cylinders;
+			pdev->blocks	= DaleSetup.setupDevice[unit].blocks;
+			
+			if ( (DiskMirror[unit].signature == SIGNATURE) && (DiskMirror[unit ^ 2].signature == SIGNATURE) &&
+			     (DiskMirror[unit].pairIdentifier == (DiskMirror[unit ^ 2].pairIdentifier ^ 1)) )
+				{			 
+				raidon = TRUE;
+				if ( unit > (unit ^ 2) )
+					unit = unit ^ 2;
+				}	
+			else
+				raidon = FALSE;
+				
+			spigot1 = spigot2 = FALSE;
+			memcpy (&pdev->DiskMirror[0], &DiskMirror[unit], sizeof (DISK_MIRROR));
+			memcpy (&pdev->DiskMirror[1], &DiskMirror[unit ^ 2], sizeof (DISK_MIRROR));
+			padapter->raidData[unit]	 = &pdev->DiskMirror[0];
+			padapter->raidData[unit ^ 2] = &pdev->DiskMirror[1];
+			pdev->spigots[0] = 1 << (unit >> 1);
+			pdev->spigots[1] = 1 << ((unit ^ 2) >> 1);
+			pdev->deviceID[0] = unit;
+			pdev->deviceID[1] = unit ^ 2;
+			pdev->lastsectorlba[0] = InlineIdentify (padapter, pdev->spigots[0], unit & 1);
+			pdev->lastsectorlba[1] = InlineIdentify (padapter, pdev->spigots[1], unit & 1);
+
+			if ( !(pdev->DiskMirror[1].status & UCBF_SURVIVOR) && pdev->lastsectorlba[0] )
+				spigot1 = TRUE;
+			if ( !(pdev->DiskMirror[0].status & UCBF_SURVIVOR) && pdev->lastsectorlba[1] )
+				spigot2 = TRUE;
+			if ( pdev->DiskMirror[0].status & pdev->DiskMirror[1].status & UCBF_SURVIVOR )
+				spigot1 = TRUE;
+
+			if ( spigot1 && (pdev->DiskMirror[0].status & UCBF_REBUILD) )
+				InlineReadSignature (padapter, pdev, 0);
+			if ( spigot2 && (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+				InlineReadSignature (padapter, pdev, 1);
+
+			if ( spigot1 && spigot2 && raidon )
+				{
+				pdev->raid = 1;
+				if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+					pdev->spigot = pdev->spigots[1];
+				else
+					pdev->spigot = pdev->spigots[0];
+				if ( (pdev->DiskMirror[0].status & UCBF_REBUILD) || (pdev->DiskMirror[1].status & UCBF_REBUILD) )
+					padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+				}
+			else
+				{
+				if ( spigot1 )
+					{
+					if ( pdev->DiskMirror[0].status & UCBF_REBUILD )
+						goto unregister1;
+					pdev->DiskMirror[0].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+					pdev->spigot = pdev->spigots[0];
+					}
+				else
+					{
+					if ( pdev->DiskMirror[1].status & UCBF_REBUILD )
+						goto unregister;
+					pdev->DiskMirror[1].status = UCBF_MIRRORED | UCBF_SURVIVOR;
+					pdev->spigot = pdev->spigots[1];
+					}
+				if ( DaleSetup.rebootRebuild && raidon )
+					padapter->reconOn = pdev->reconOn = pdev->reconIsStarting = TRUE;
+				}
+			}
+		
+		if ( !padapter->numberOfDrives )									// If no ATA devices then scan ATAPI
+			{
+			unit = 0;
+			for ( spigot1 = 0;  spigot1 < 4;  spigot1++ )
+				{
+				for ( device = 0;  device < 2;  device++ )
+					{
+					DEB (printk ("\nPCI2242I: scanning for ID %d ", (spigot1 * 2) + device));
+					pdev = &(padapter->device[(spigot1 * 2) + device]);
+					pdev->byte6 = 0x0A | (device << 4);
+					pdev->spigot = 1 << spigot1;
+					if ( !AtapiReset (padapter, pdev) )
+						{
+						DEB (printk (" Device found "));
+						if ( !AtapiIdentify (padapter, pdev) )
+							{
+							DEB (printk (" Device verified"));
+							unit++;
+							continue;
+							}
+						}
+					pdev->spigot = pdev->byte6 = 0;
+					}
+				}
+
+			if ( unit )
+				{
+				padapter->atapi = TRUE;
+				padapter->timingAddress = DALE_DATA_MODE3;
+				outw_p (0x0900, padapter->regIrqControl);					// Turn our interrupts on
+				outw_p (0x0C41, padapter->regDmaMode - 1);					// setup for 16 bits, ready enabled, done IRQ enabled, no incriment
+				outb_p (0xFF, padapter->regFail);							// all fail lights and alarm off
+				pshost->max_id = 8;
+				}
+			}
+		SetupFinish (padapter, "2240", pshost->irq);
+		
+		if ( ++Installed < MAXADAPTER )
+			continue;
+		break;
+unregister1:;
+		scsi_unregister (pshost);
+		}
+
+	NumAdapters = Installed;
+	return Installed;
+	}
+/****************************************************************
+ *	Name:	Pci2220i_Abort
+ *
+ *	Description:	Process the Abort command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *
+ *	Returns:		Allways snooze.
+ *
+ ****************************************************************/
+int Pci2220i_Abort (Scsi_Cmnd *SCpnt)
+	{
+	PADAPTER2220I	padapter = HOSTDATA(SCpnt->device->host);			// Pointer to adapter control structure
+	POUR_DEVICE		pdev	 = &padapter->device[SCpnt->device->id];// Pointer to device information
+
+	if ( !padapter->SCpnt )
+		return SCSI_ABORT_NOT_RUNNING;
+	
+	if ( padapter->atapi )
+		{
+		if ( AtapiReset (padapter, pdev) )
+			return SCSI_ABORT_ERROR;
+		OpDone (padapter, DID_ABORT << 16);
+		return SCSI_ABORT_SUCCESS;
+		}
+	return SCSI_ABORT_SNOOZE;
+	}
+/****************************************************************
+ *	Name:	Pci2220i_Reset
+ *
+ *	Description:	Process the Reset command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *					flags - Flags about the reset command
+ *
+ *	Returns:		No active command at this time, so this means
+ *					that each time we got some kind of response the
+ *					last time through.  Tell the mid-level code to
+ *					request sense information in order to decide what
+ *					to do next.
+ *
+ ****************************************************************/
+int Pci2220i_Reset (Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+	{
+	PADAPTER2220I	padapter = HOSTDATA(SCpnt->device->host);			// Pointer to adapter control structure
+	POUR_DEVICE		pdev	 = &padapter->device[SCpnt->device->id];// Pointer to device information
+
+	if ( padapter->atapi )
+		{
+		if ( AtapiReset (padapter, pdev) )
+			return SCSI_RESET_ERROR;
+		return SCSI_RESET_SUCCESS;
+		}
+	return SCSI_RESET_PUNT;
+	}
+/****************************************************************
+ *	Name:	Pci2220i_Release
+ *
+ *	Description:	Release resources allocated for a single each adapter.
+ *
+ *	Parameters:		pshost - Pointer to SCSI command structure.
+ *
+ *	Returns:		zero.
+ *
+ ****************************************************************/
+int Pci2220i_Release (struct Scsi_Host *pshost)
+	{
+    PADAPTER2220I	padapter = HOSTDATA (pshost);
+	USHORT			z;
+
+	if ( padapter->reconOn )
+		{
+		padapter->reconOn = FALSE;						// shut down the hot reconstruct
+		if ( padapter->reconPhase )
+			mdelay (300);
+		if ( padapter->reconTimer.data )				// is the timer running?
+			{
+			del_timer (&padapter->reconTimer);
+			padapter->reconTimer.data = 0;
+			}
+		}
+
+	// save RAID status on the board
+	if ( padapter->bigD )
+		{
+		outb_p (padapter->failRegister, padapter->regScratchPad + BIGD_ALARM_IMAGE);
+		for ( z = 0;  z < BIGD_MAXDRIVES;  z++ )
+			{
+			if ( padapter->raidData )
+				outb_p (padapter->raidData[z]->status, padapter->regScratchPad + BIGD_RAID_0_STATUS + z);	
+			else
+				outb_p (0, padapter->regScratchPad + BIGD_RAID_0_STATUS);	
+			}
+		}
+	else
+		{
+		outb_p (padapter->device[0].DiskMirror[0].status, padapter->regScratchPad + DALE_RAID_0_STATUS);		
+		outb_p (padapter->device[0].DiskMirror[1].status, padapter->regScratchPad + DALE_RAID_1_STATUS);		
+		}
+
+	if ( padapter->irqOwned )
+		free_irq (pshost->irq, padapter);
+    release_region (pshost->io_port, pshost->n_io_port);
+	if ( padapter->numberOfDrives )
+		pci_free_consistent (padapter->pcidev, SECTORSXFER * BYTES_PER_SECTOR, padapter->kBuffer, padapter->kBufferDma);
+	else	
+		pci_free_consistent (padapter->pcidev, ATAPI_TRANSFER, padapter->kBuffer, padapter->kBufferDma);
+    scsi_unregister(pshost);
+    return 0;
+	}
+
+/****************************************************************
+ *	Name:	Pci2220i_BiosParam
+ *
+ *	Description:	Process the biosparam request from the SCSI manager to
+ *					return C/H/S data.
+ *
+ *	Parameters:		disk - Pointer to SCSI disk structure.
+ *					dev	 - Major/minor number from kernel.
+ *					geom - Pointer to integer array to place geometry data.
+ *
+ *	Returns:		zero.
+ *
+ ****************************************************************/
+int Pci2220i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int geom[])
+	{
+	POUR_DEVICE	pdev;
+
+	if ( !(HOSTDATA(sdev->host))->atapi )
+		{
+		pdev = &(HOSTDATA(sdev->host)->device[sdev->id]);
+
+		geom[0] = pdev->heads;
+		geom[1] = pdev->sectors;
+		geom[2] = pdev->cylinders;
+		}
+	return 0;
+	}
+
+MODULE_LICENSE("Dual BSD/GPL");
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "pci2220i",
+	.name			= "PCI-2220I/PCI-2240I",
+	.detect			= Pci2220i_Detect,
+	.release		= Pci2220i_Release,
+	.queuecommand		= Pci2220i_QueueCommand,
+	.abort			= Pci2220i_Abort,
+	.reset			= Pci2220i_Reset,
+	.bios_param		= Pci2220i_BiosParam,
+	.can_queue		= 1,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
new file mode 100644
index 0000000..6926056
--- /dev/null
+++ b/drivers/scsi/pci2220i.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2220I device driver for Linux.
+ *
+ * pci2220i.h - Linux Host Driver for PCI-2220i EIDE Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ ****************************************************************************/
+#ifndef _PCI2220I_H
+#define _PCI2220I_H
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif 
+#define	LINUXVERSION(v,p,s)    (((v)<<16) + ((p)<<8) + (s))
+
+// function prototypes
+int Pci2220i_Detect			(Scsi_Host_Template *tpnt);
+int Pci2220i_Command		(Scsi_Cmnd *SCpnt);
+int Pci2220i_QueueCommand	(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
+int Pci2220i_Abort			(Scsi_Cmnd *SCpnt);
+int Pci2220i_Reset			(Scsi_Cmnd *SCpnt, unsigned int flags);
+int Pci2220i_Release		(struct Scsi_Host *pshost);
+int Pci2220i_BiosParam		(struct scsi_device *sdev,
+					struct block_device *dev,
+					sector_t capacity, int geom[]);
+#endif
diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig
new file mode 100644
index 0000000..df52190
--- /dev/null
+++ b/drivers/scsi/pcmcia/Kconfig
@@ -0,0 +1,82 @@
+#
+# PCMCIA SCSI adapter configuration
+#
+
+menu "PCMCIA SCSI adapter support"
+	depends on SCSI!=n && PCMCIA!=n && MODULES
+
+config PCMCIA_AHA152X
+	tristate "Adaptec AHA152X PCMCIA support"
+	depends on m && !64BIT
+	help
+	  Say Y here if you intend to attach this type of PCMCIA SCSI host
+	  adapter to your computer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called aha152x_cs.
+
+config PCMCIA_FDOMAIN
+	tristate "Future Domain PCMCIA support"
+	depends on m
+	help
+	  Say Y here if you intend to attach this type of PCMCIA SCSI host
+	  adapter to your computer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called fdomain_cs.
+
+config PCMCIA_NINJA_SCSI
+	tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support"
+	depends on m && !64BIT
+	help
+	  If you intend to attach this type of PCMCIA SCSI host adapter to
+	  your computer, say Y here and read
+	  <file:Documentation/scsi/NinjaSCSI.txt>.
+
+	  Supported cards:
+
+	  NinjaSCSI-3: (version string: "WBT","NinjaSCSI-3","R1.0")
+	    IO-DATA     PCSC-FP
+	    ALPHA DATA  AD-PCS201
+	    CyQ've      SFC-201  
+	    LOGITECH    LPM-SCSI2E
+	    Pioneer PCR-PR24's card
+	    I-O DATA CDPS-PX24's card (PCSC-F)
+	    Panasonic KXL-RW10AN CD-RW's card
+	    etc.
+
+	  NinjaSCSI-32Bit (in 16bit mode):
+	    [Workbit (version string: "WORKBIT","UltraNinja-16","1")]
+	    Jazz SCP050
+	    [I-O DATA (OEM) (version string: "IO DATA","CBSC16       ","1")]
+	    I-O DATA CBSC-II
+	    [Kyusyu Matsushita Kotobuki (OEM)
+               (version string: "KME    ","SCSI-CARD-001","1")]
+	    KME KXL-820AN's card
+	    HP M820e CDRW's card
+	    etc.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nsp_cs.
+
+config PCMCIA_QLOGIC
+	tristate "Qlogic PCMCIA support"
+	depends on m
+	help
+	  Say Y here if you intend to attach this type of PCMCIA SCSI host
+	  adapter to your computer.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called qlogic_cs.
+
+config PCMCIA_SYM53C500
+	tristate "Symbios 53c500 PCMCIA support"
+	depends on m
+	help
+	  Say Y here if you have a New Media Bus Toaster or other PCMCIA
+	  SCSI adapter based on the Symbios 53c500 controller.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called sym53c500_cs.
+
+endmenu
diff --git a/drivers/scsi/pcmcia/Makefile b/drivers/scsi/pcmcia/Makefile
new file mode 100644
index 0000000..eca3790
--- /dev/null
+++ b/drivers/scsi/pcmcia/Makefile
@@ -0,0 +1,13 @@
+
+EXTRA_CFLAGS		+= -Idrivers/scsi
+
+# 16-bit client drivers
+obj-$(CONFIG_PCMCIA_QLOGIC)	+= qlogic_cs.o
+obj-$(CONFIG_PCMCIA_FDOMAIN)	+= fdomain_cs.o
+obj-$(CONFIG_PCMCIA_AHA152X)	+= aha152x_cs.o
+obj-$(CONFIG_PCMCIA_NINJA_SCSI)	+= nsp_cs.o
+obj-$(CONFIG_PCMCIA_SYM53C500)	+= sym53c500_cs.o
+
+aha152x_cs-objs	:= aha152x_stub.o aha152x_core.o
+fdomain_cs-objs	:= fdomain_stub.o fdomain_core.o
+qlogic_cs-objs	:= qlogic_stub.o
diff --git a/drivers/scsi/pcmcia/aha152x_core.c b/drivers/scsi/pcmcia/aha152x_core.c
new file mode 100644
index 0000000..dba3716
--- /dev/null
+++ b/drivers/scsi/pcmcia/aha152x_core.c
@@ -0,0 +1,3 @@
+#define PCMCIA	1
+#define AHA152X_STAT 1
+#include "aha152x.c"
diff --git a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
new file mode 100644
index 0000000..e60b4c0
--- /dev/null
+++ b/drivers/scsi/pcmcia/aha152x_stub.c
@@ -0,0 +1,343 @@
+/*======================================================================
+
+    A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
+
+    This driver supports the Adaptec AHA-1460, the New Media Bus
+    Toaster, and the New Media Toast & Jam.
+    
+    aha152x_cs.c 1.54 2000/06/12 21:27:25
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_ioctl.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "aha152x.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0644);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"aha152x_cs.c 1.54 2000/06/12 21:27:25 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* SCSI bus setup options */
+static int host_id = 7;
+static int reconnect = 1;
+static int parity = 1;
+static int synchronous = 1;
+static int reset_delay = 100;
+static int ext_trans = 0;
+
+module_param(host_id, int, 0);
+module_param(reconnect, int, 0);
+module_param(parity, int, 0);
+module_param(synchronous, int, 0);
+module_param(reset_delay, int, 0);
+module_param(ext_trans, int, 0);
+
+MODULE_LICENSE("Dual MPL/GPL");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+    dev_link_t		link;
+    dev_node_t		node;
+    struct Scsi_Host	*host;
+} scsi_info_t;
+
+static void aha152x_release_cs(dev_link_t *link);
+static int aha152x_event(event_t event, int priority,
+			 event_callback_args_t *args);
+
+static dev_link_t *aha152x_attach(void);
+static void aha152x_detach(dev_link_t *);
+
+static dev_link_t *dev_list;
+static dev_info_t dev_info = "aha152x_cs";
+
+static dev_link_t *aha152x_attach(void)
+{
+    scsi_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int ret;
+    
+    DEBUG(0, "aha152x_attach()\n");
+
+    /* Create new SCSI device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->io.NumPorts1 = 0x20;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 10;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.event_handler = &aha152x_event;
+    client_reg.EventMask =
+	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = pcmcia_register_client(&link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	aha152x_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* aha152x_attach */
+
+/*====================================================================*/
+
+static void aha152x_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "aha152x_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    if (link->state & DEV_CONFIG)
+	aha152x_release_cs(link);
+
+    if (link->handle)
+	pcmcia_deregister_client(link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* aha152x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void aha152x_config_cs(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    scsi_info_t *info = link->priv;
+    struct aha152x_setup s;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn;
+    u_char tuple_data[64];
+    struct Scsi_Host *host;
+    
+    DEBUG(0, "aha152x_config(0x%p)\n", link);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = tuple_data;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    link->conf.ConfigBase = parse.config.base;
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    while (1) {
+	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	    goto next_entry;
+	/* For New Media T&J, look for a SCSI window */
+	if (parse.cftable_entry.io.win[0].len >= 0x20)
+	    link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+	else if ((parse.cftable_entry.io.nwin > 1) &&
+		 (parse.cftable_entry.io.win[1].len >= 0x20))
+	    link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
+	if ((parse.cftable_entry.io.nwin > 0) &&
+	    (link->io.BasePort1 < 0xffff)) {
+	    link->conf.ConfigIndex = parse.cftable_entry.index;
+	    i = pcmcia_request_io(handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+    next_entry:
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+    }
+    
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    
+    /* Set configuration options for the aha152x driver */
+    memset(&s, 0, sizeof(s));
+    s.conf        = "PCMCIA setup";
+    s.io_port     = link->io.BasePort1;
+    s.irq         = link->irq.AssignedIRQ;
+    s.scsiid      = host_id;
+    s.reconnect   = reconnect;
+    s.parity      = parity;
+    s.synchronous = synchronous;
+    s.delay       = reset_delay;
+    if (ext_trans)
+        s.ext_trans = ext_trans;
+
+    host = aha152x_probe_one(&s);
+    if (host == NULL) {
+	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
+	goto cs_failed;
+    }
+
+    sprintf(info->node.dev_name, "scsi%d", host->host_no);
+    link->dev = &info->node;
+    info->host = host;
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    aha152x_release_cs(link);
+    return;
+}
+
+static void aha152x_release_cs(dev_link_t *link)
+{
+	scsi_info_t *info = link->priv;
+
+	aha152x_release(info->host);
+	link->dev = NULL;
+    
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+    
+	link->state &= ~DEV_CONFIG;
+}
+
+static int aha152x_event(event_t event, int priority,
+			 event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    scsi_info_t *info = link->priv;
+    
+    DEBUG(0, "aha152x_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    aha152x_release_cs(link);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	aha152x_config_cs(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    pcmcia_release_configuration(link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    Scsi_Cmnd tmp;
+	    pcmcia_request_configuration(link->handle, &link->conf);
+	    tmp.device->host = info->host;
+	    aha152x_host_reset(&tmp);
+	}
+	break;
+    }
+    return 0;
+}
+
+static struct pcmcia_driver aha152x_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "aha152x_cs",
+	},
+	.attach		= aha152x_attach,
+	.detach		= aha152x_detach,
+};
+
+static int __init init_aha152x_cs(void)
+{
+	return pcmcia_register_driver(&aha152x_cs_driver);
+}
+
+static void __exit exit_aha152x_cs(void)
+{
+	pcmcia_unregister_driver(&aha152x_cs_driver);
+	BUG_ON(dev_list != NULL);
+}
+
+module_init(init_aha152x_cs);
+module_exit(exit_aha152x_cs);
+ 
diff --git a/drivers/scsi/pcmcia/fdomain_core.c b/drivers/scsi/pcmcia/fdomain_core.c
new file mode 100644
index 0000000..a489137
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_core.c
@@ -0,0 +1,2 @@
+#define PCMCIA 1
+#include "fdomain.c"
diff --git a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
new file mode 100644
index 0000000..3df7bc7
--- /dev/null
+++ b/drivers/scsi/pcmcia/fdomain_stub.c
@@ -0,0 +1,323 @@
+/*======================================================================
+
+    A driver for Future Domain-compatible PCMCIA SCSI cards
+
+    fdomain_cs.c 1.47 2001/10/13 00:08:52
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_ioctl.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "fdomain.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+/*====================================================================*/
+
+/* Module parameters */
+
+MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>");
+MODULE_DESCRIPTION("Future Domain PCMCIA SCSI driver");
+MODULE_LICENSE("Dual MPL/GPL");
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"fdomain_cs.c 1.47 2001/10/13 00:08:52 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+    dev_link_t		link;
+    dev_node_t		node;
+    struct Scsi_Host	*host;
+} scsi_info_t;
+
+
+static void fdomain_release(dev_link_t *link);
+static int fdomain_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static dev_link_t *fdomain_attach(void);
+static void fdomain_detach(dev_link_t *);
+
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "fdomain_cs";
+
+static dev_link_t *fdomain_attach(void)
+{
+    scsi_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int ret;
+    
+    DEBUG(0, "fdomain_attach()\n");
+
+    /* Create new SCSI device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    link->io.NumPorts1 = 0x10;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 10;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.event_handler = &fdomain_event;
+    client_reg.EventMask =
+	CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = pcmcia_register_client(&link->handle, &client_reg);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterClient, ret);
+	fdomain_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* fdomain_attach */
+
+/*====================================================================*/
+
+static void fdomain_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "fdomain_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    if (link->state & DEV_CONFIG)
+	fdomain_release(link);
+
+    if (link->handle)
+	pcmcia_deregister_client(link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* fdomain_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void fdomain_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    scsi_info_t *info = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn;
+    u_char tuple_data[64];
+    char str[16];
+    struct Scsi_Host *host;
+
+    DEBUG(0, "fdomain_config(0x%p)\n", link);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = tuple_data;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+    CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+    link->conf.ConfigBase = parse.config.base;
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+    while (1) {
+	if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+		pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+	    goto next_entry;
+	link->conf.ConfigIndex = parse.cftable_entry.index;
+	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+	i = pcmcia_request_io(handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    next_entry:
+	CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+    }
+
+    CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+    
+    /* A bad hack... */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+
+    /* Set configuration options for the fdomain driver */
+    sprintf(str, "%d,%d", link->io.BasePort1, link->irq.AssignedIRQ);
+    fdomain_setup(str);
+    
+    host = __fdomain_16x0_detect(&fdomain_driver_template);
+    if (!host) {
+        printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
+	goto cs_failed;
+    }
+ 
+    scsi_add_host(host, NULL); /* XXX handle failure */
+    scsi_scan_host(host);
+
+    sprintf(info->node.dev_name, "scsi%d", host->host_no);
+    link->dev = &info->node;
+    info->host = host;
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    fdomain_release(link);
+    return;
+    
+} /* fdomain_config */
+
+/*====================================================================*/
+
+static void fdomain_release(dev_link_t *link)
+{
+    scsi_info_t *info = link->priv;
+
+    DEBUG(0, "fdomain_release(0x%p)\n", link);
+
+    scsi_remove_host(info->host);
+    link->dev = NULL;
+    
+    pcmcia_release_configuration(link->handle);
+    pcmcia_release_io(link->handle, &link->io);
+    pcmcia_release_irq(link->handle, &link->irq);
+
+    scsi_unregister(info->host);
+
+    link->state &= ~DEV_CONFIG;
+}
+
+/*====================================================================*/
+
+static int fdomain_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "fdomain_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    fdomain_release(link);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	fdomain_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    pcmcia_release_configuration(link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    pcmcia_request_configuration(link->handle, &link->conf);
+	    fdomain_16x0_bus_reset(NULL);
+	}
+	break;
+    }
+    return 0;
+} /* fdomain_event */
+
+static struct pcmcia_driver fdomain_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "fdomain_cs",
+	},
+	.attach		= fdomain_attach,
+	.detach		= fdomain_detach,
+};
+
+static int __init init_fdomain_cs(void)
+{
+	return pcmcia_register_driver(&fdomain_cs_driver);
+}
+
+static void __exit exit_fdomain_cs(void)
+{
+	pcmcia_unregister_driver(&fdomain_cs_driver);
+	BUG_ON(dev_list != NULL);
+}
+
+module_init(init_fdomain_cs);
+module_exit(exit_fdomain_cs);
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
new file mode 100644
index 0000000..496c412
--- /dev/null
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -0,0 +1,2198 @@
+/*======================================================================
+
+    NinjaSCSI-3 / NinjaSCSI-32Bi PCMCIA SCSI host adapter card driver
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    Ver.2.8   Support 32bit MMIO mode
+              Support Synchronous Data Transfer Request (SDTR) mode
+    Ver.2.0   Support 32bit PIO mode
+    Ver.1.1.2 Fix for scatter list buffer exceeds
+    Ver.1.1   Support scatter list
+    Ver.0.1   Initial version
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+
+======================================================================*/
+
+/***********************************************************************
+    This driver is for these PCcards.
+
+	I-O DATA PCSC-F	 (Workbit NinjaSCSI-3)
+			"WBT", "NinjaSCSI-3", "R1.0"
+	I-O DATA CBSC-II (Workbit NinjaSCSI-32Bi in 16bit mode)
+			"IO DATA", "CBSC16	 ", "1"
+
+***********************************************************************/
+
+/* $Id: nsp_cs.c,v 1.23 2003/08/18 11:09:19 elca Exp $ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include "nsp_cs.h"
+
+MODULE_AUTHOR("YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>");
+MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module $Revision: 1.23 $");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+#ifdef MODULE_LICENSE
+MODULE_LICENSE("GPL");
+#endif
+
+#include "nsp_io.h"
+
+/*====================================================================*/
+/* Parameters that can be set with 'insmod' */
+
+static int       nsp_burst_mode = BURST_MEM32;
+module_param(nsp_burst_mode, int, 0);
+MODULE_PARM_DESC(nsp_burst_mode, "Burst transfer mode (0=io8, 1=io32, 2=mem32(default))");
+
+/* Release IO ports after configuration? */
+static int       free_ports = 0;
+module_param(free_ports, bool, 0);
+MODULE_PARM_DESC(free_ports, "Release IO ports after configuration? (default: 0 (=no))");
+
+/* /usr/src/linux/drivers/scsi/hosts.h */
+static Scsi_Host_Template nsp_driver_template = {
+	.proc_name	         = "nsp_cs",
+	.proc_info		 = nsp_proc_info,
+	.name			 = "WorkBit NinjaSCSI-3/32Bi(16bit)",
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+	.detect			 = nsp_detect_old,
+	.release		 = nsp_release_old,
+#endif
+	.info			 = nsp_info,
+	.queuecommand		 = nsp_queuecommand,
+/*	.eh_strategy_handler	 = nsp_eh_strategy,*/
+/*	.eh_abort_handler	 = nsp_eh_abort,*/
+/*	.eh_device_reset_handler = nsp_eh_device_reset,*/
+	.eh_bus_reset_handler	 = nsp_eh_bus_reset,
+	.eh_host_reset_handler	 = nsp_eh_host_reset,
+	.can_queue		 = 1,
+	.this_id		 = NSP_INITIATOR_ID,
+	.sg_tablesize		 = SG_ALL,
+	.cmd_per_lun		 = 1,
+	.use_clustering		 = DISABLE_CLUSTERING,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2))
+	.use_new_eh_code	 = 1,
+#endif
+};
+
+static dev_link_t *dev_list = NULL;
+static dev_info_t dev_info  = {"nsp_cs"};
+
+static nsp_hw_data nsp_data_base; /* attach <-> detect glue */
+
+
+
+/*
+ * debug, error print
+ */
+#ifndef NSP_DEBUG
+# define NSP_DEBUG_MASK		0x000000
+# define nsp_msg(type, args...) nsp_cs_message("", 0, (type), args)
+# define nsp_dbg(mask, args...) /* */
+#else
+# define NSP_DEBUG_MASK		0xffffff
+# define nsp_msg(type, args...) \
+	nsp_cs_message (__FUNCTION__, __LINE__, (type), args)
+# define nsp_dbg(mask, args...) \
+	nsp_cs_dmessage(__FUNCTION__, __LINE__, (mask), args)
+#endif
+
+#define NSP_DEBUG_QUEUECOMMAND		BIT(0)
+#define NSP_DEBUG_REGISTER		BIT(1)
+#define NSP_DEBUG_AUTOSCSI		BIT(2)
+#define NSP_DEBUG_INTR			BIT(3)
+#define NSP_DEBUG_SGLIST		BIT(4)
+#define NSP_DEBUG_BUSFREE		BIT(5)
+#define NSP_DEBUG_CDB_CONTENTS		BIT(6)
+#define NSP_DEBUG_RESELECTION		BIT(7)
+#define NSP_DEBUG_MSGINOCCUR		BIT(8)
+#define NSP_DEBUG_EEPROM		BIT(9)
+#define NSP_DEBUG_MSGOUTOCCUR		BIT(10)
+#define NSP_DEBUG_BUSRESET		BIT(11)
+#define NSP_DEBUG_RESTART		BIT(12)
+#define NSP_DEBUG_SYNC			BIT(13)
+#define NSP_DEBUG_WAIT			BIT(14)
+#define NSP_DEBUG_TARGETFLAG		BIT(15)
+#define NSP_DEBUG_PROC			BIT(16)
+#define NSP_DEBUG_INIT			BIT(17)
+#define NSP_DEBUG_DATA_IO      		BIT(18)
+#define NSP_SPECIAL_PRINT_REGISTER	BIT(20)
+
+#define NSP_DEBUG_BUF_LEN		150
+
+static void nsp_cs_message(const char *func, int line, char *type, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+#ifndef NSP_DEBUG
+	printk("%snsp_cs: %s\n", type, buf);
+#else
+	printk("%snsp_cs: %s (%d): %s\n", type, func, line, buf);
+#endif
+}
+
+#ifdef NSP_DEBUG
+static void nsp_cs_dmessage(const char *func, int line, int mask, char *fmt, ...)
+{
+	va_list args;
+	char buf[NSP_DEBUG_BUF_LEN];
+
+	va_start(args, fmt);
+	vsnprintf(buf, sizeof(buf), fmt, args);
+	va_end(args);
+
+	if (mask & NSP_DEBUG_MASK) {
+		printk("nsp_cs-debug: 0x%x %s (%d): %s\n", mask, func, line, buf);
+	}
+}
+#endif
+
+/***********************************************************/
+
+/*====================================================
+ * Clenaup parameters and call done() functions.
+ * You must be set SCpnt->result before call this function.
+ */
+static void nsp_scsi_done(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+	data->CurrentSC = NULL;
+
+	SCpnt->scsi_done(SCpnt);
+}
+
+static int nsp_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+#ifdef NSP_DEBUG
+	/*unsigned int host_id = SCpnt->device->host->this_id;*/
+	/*unsigned int base    = SCpnt->device->host->io_port;*/
+	unsigned char target = SCpnt->device->id;
+#endif
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+	nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "SCpnt=0x%p target=%d lun=%d buff=0x%p bufflen=%d use_sg=%d",
+		   SCpnt, target, SCpnt->device->lun, SCpnt->request_buffer, SCpnt->request_bufflen, SCpnt->use_sg);
+	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "before CurrentSC=0x%p", data->CurrentSC);
+
+	SCpnt->scsi_done	= done;
+
+	if (data->CurrentSC != NULL) {
+		nsp_msg(KERN_DEBUG, "CurrentSC!=NULL this can't be happen");
+		SCpnt->result   = DID_BAD_TARGET << 16;
+		nsp_scsi_done(SCpnt);
+		return 0;
+	}
+
+#if 0
+	/* XXX: pcmcia-cs generates SCSI command with "scsi_info" utility.
+	        This makes kernel crash when suspending... */
+	if (data->ScsiInfo->stop != 0) {
+		nsp_msg(KERN_INFO, "suspending device. reject command.");
+		SCpnt->result  = DID_BAD_TARGET << 16;
+		nsp_scsi_done(SCpnt);
+		return SCSI_MLQUEUE_HOST_BUSY;
+	}
+#endif
+
+	show_command(SCpnt);
+
+	data->CurrentSC		= SCpnt;
+
+	SCpnt->SCp.Status	= CHECK_CONDITION;
+	SCpnt->SCp.Message	= 0;
+	SCpnt->SCp.have_data_in = IO_UNKNOWN;
+	SCpnt->SCp.sent_command = 0;
+	SCpnt->SCp.phase	= PH_UNDETERMINED;
+	SCpnt->resid	        = SCpnt->request_bufflen;
+
+	/* setup scratch area
+	   SCp.ptr		: buffer pointer
+	   SCp.this_residual	: buffer length
+	   SCp.buffer		: next buffer
+	   SCp.buffers_residual : left buffers in list
+	   SCp.phase		: current state of the command */
+	if (SCpnt->use_sg) {
+		SCpnt->SCp.buffer	    = (struct scatterlist *) SCpnt->request_buffer;
+		SCpnt->SCp.ptr		    = BUFFER_ADDR;
+		SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+	} else {
+		SCpnt->SCp.ptr		    = (char *) SCpnt->request_buffer;
+		SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+		SCpnt->SCp.buffer	    = NULL;
+		SCpnt->SCp.buffers_residual = 0;
+	}
+
+	if (nsphw_start_selection(SCpnt) == FALSE) {
+		nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "selection fail");
+		SCpnt->result   = DID_BUS_BUSY << 16;
+		nsp_scsi_done(SCpnt);
+		return 0;
+	}
+
+
+	//nsp_dbg(NSP_DEBUG_QUEUECOMMAND, "out");
+#ifdef NSP_DEBUG
+	data->CmdId++;
+#endif
+	return 0;
+}
+
+/*
+ * setup PIO FIFO transfer mode and enable/disable to data out
+ */
+static void nsp_setup_fifo(nsp_hw_data *data, int enabled)
+{
+	unsigned int  base = data->BaseAddress;
+	unsigned char transfer_mode_reg;
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "enabled=%d", enabled);
+
+	if (enabled != FALSE) {
+		transfer_mode_reg = TRANSFER_GO | BRAIND;
+	} else {
+		transfer_mode_reg = 0;
+	}
+
+	transfer_mode_reg |= data->TransferMode;
+
+	nsp_index_write(base, TRANSFERMODE, transfer_mode_reg);
+}
+
+static void nsphw_init_sync(nsp_hw_data *data)
+{
+	sync_data tmp_sync = { .SyncNegotiation = SYNC_NOT_YET,
+			       .SyncPeriod      = 0,
+			       .SyncOffset      = 0
+	};
+	int i;
+
+	/* setup sync data */
+	for ( i = 0; i < ARRAY_SIZE(data->Sync); i++ ) {
+		data->Sync[i] = tmp_sync;
+	}
+}
+
+/*
+ * Initialize Ninja hardware
+ */
+static int nsphw_init(nsp_hw_data *data)
+{
+	unsigned int base     = data->BaseAddress;
+
+	nsp_dbg(NSP_DEBUG_INIT, "in base=0x%x", base);
+
+	data->ScsiClockDiv = CLOCK_40M | FAST_20;
+	data->CurrentSC    = NULL;
+	data->FifoCount    = 0;
+	data->TransferMode = MODE_IO8;
+
+	nsphw_init_sync(data);
+
+	/* block all interrupts */
+	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLMASK);
+
+	/* setup SCSI interface */
+	nsp_write(base,	      IFSELECT,	    IF_IFSEL);
+
+	nsp_index_write(base, SCSIIRQMODE,  0);
+
+	nsp_index_write(base, TRANSFERMODE, MODE_IO8);
+	nsp_index_write(base, CLOCKDIV,	    data->ScsiClockDiv);
+
+	nsp_index_write(base, PARITYCTRL,   0);
+	nsp_index_write(base, POINTERCLR,   POINTER_CLEAR     |
+					    ACK_COUNTER_CLEAR |
+					    REQ_COUNTER_CLEAR |
+					    HOST_COUNTER_CLEAR);
+
+	/* setup fifo asic */
+	nsp_write(base,	      IFSELECT,	    IF_REGSEL);
+	nsp_index_write(base, TERMPWRCTRL,  0);
+	if ((nsp_index_read(base, OTHERCONTROL) & TPWR_SENSE) == 0) {
+		nsp_msg(KERN_INFO, "terminator power on");
+		nsp_index_write(base, TERMPWRCTRL, POWER_ON);
+	}
+
+	nsp_index_write(base, TIMERCOUNT,   0);
+	nsp_index_write(base, TIMERCOUNT,   0); /* requires 2 times!! */
+
+	nsp_index_write(base, SYNCREG,	    0);
+	nsp_index_write(base, ACKWIDTH,	    0);
+
+	/* enable interrupts and ack them */
+	nsp_index_write(base, SCSIIRQMODE,  SCSI_PHASE_CHANGE_EI |
+					    RESELECT_EI		 |
+					    SCSI_RESET_IRQ_EI	 );
+	nsp_write(base,	      IRQCONTROL,   IRQCONTROL_ALLCLEAR);
+
+	nsp_setup_fifo(data, FALSE);
+
+	return TRUE;
+}
+
+/*
+ * Start selection phase
+ */
+static int nsphw_start_selection(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  host_id	 = SCpnt->device->host->this_id;
+	unsigned int  base	 = SCpnt->device->host->io_port;
+	unsigned char target	 = SCpnt->device->id;
+	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	int	      time_out;
+	unsigned char phase, arbit;
+
+	//nsp_dbg(NSP_DEBUG_RESELECTION, "in");
+
+	phase = nsp_index_read(base, SCSIBUSMON);
+	if(phase != BUSMON_BUS_FREE) {
+		//nsp_dbg(NSP_DEBUG_RESELECTION, "bus busy");
+		return FALSE;
+	}
+
+	/* start arbitration */
+	//nsp_dbg(NSP_DEBUG_RESELECTION, "start arbit");
+	SCpnt->SCp.phase = PH_ARBSTART;
+	nsp_index_write(base, SETARBIT, ARBIT_GO);
+
+	time_out = 1000;
+	do {
+		/* XXX: what a stupid chip! */
+		arbit = nsp_index_read(base, ARBITSTATUS);
+		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit=%d, wait_count=%d", arbit, wait_count);
+		udelay(1); /* hold 1.2us */
+	} while((arbit & (ARBIT_WIN | ARBIT_FAIL)) == 0 &&
+		(time_out-- != 0));
+
+	if (!(arbit & ARBIT_WIN)) {
+		//nsp_dbg(NSP_DEBUG_RESELECTION, "arbit fail");
+		nsp_index_write(base, SETARBIT, ARBIT_FLAG_CLEAR);
+		return FALSE;
+	}
+
+	/* assert select line */
+	//nsp_dbg(NSP_DEBUG_RESELECTION, "assert SEL line");
+	SCpnt->SCp.phase = PH_SELSTART;
+	udelay(3); /* wait 2.4us */
+	nsp_index_write(base, SCSIDATALATCH, BIT(host_id) | BIT(target));
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY                    | SCSI_ATN);
+	udelay(2); /* wait >1.2us */
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL | SCSI_BSY | SCSI_DATAOUT_ENB | SCSI_ATN);
+	nsp_index_write(base, SETARBIT,	     ARBIT_FLAG_CLEAR);
+	/*udelay(1);*/ /* wait >90ns */
+	nsp_index_write(base, SCSIBUSCTRL,   SCSI_SEL            | SCSI_DATAOUT_ENB | SCSI_ATN);
+
+	/* check selection timeout */
+	nsp_start_timer(SCpnt, 1000/51);
+	data->SelectionTimeOut = 1;
+
+	return TRUE;
+}
+
+struct nsp_sync_table {
+	unsigned int min_period;
+	unsigned int max_period;
+	unsigned int chip_period;
+	unsigned int ack_width;
+};
+
+static struct nsp_sync_table nsp_sync_table_40M[] = {
+	{0x0c, 0x0c, 0x1, 0},	/* 20MB	  50ns*/
+	{0x19, 0x19, 0x3, 1},	/* 10MB	 100ns*/ 
+	{0x1a, 0x25, 0x5, 2},	/* 7.5MB 150ns*/ 
+	{0x26, 0x32, 0x7, 3},	/* 5MB	 200ns*/
+	{   0,    0,   0, 0},
+};
+
+static struct nsp_sync_table nsp_sync_table_20M[] = {
+	{0x19, 0x19, 0x1, 0},	/* 10MB	 100ns*/ 
+	{0x1a, 0x25, 0x2, 0},	/* 7.5MB 150ns*/ 
+	{0x26, 0x32, 0x3, 1},	/* 5MB	 200ns*/
+	{   0,    0,   0, 0},
+};
+
+/*
+ * setup synchronous data transfer mode
+ */
+static int nsp_analyze_sdtr(Scsi_Cmnd *SCpnt)
+{
+	unsigned char	       target = SCpnt->device->id;
+//	unsigned char	       lun    = SCpnt->device->lun;
+	nsp_hw_data           *data   = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	sync_data	      *sync   = &(data->Sync[target]);
+	struct nsp_sync_table *sync_table;
+	unsigned int	       period, offset;
+	int		       i;
+
+
+	nsp_dbg(NSP_DEBUG_SYNC, "in");
+
+	period = sync->SyncPeriod;
+	offset = sync->SyncOffset;
+
+	nsp_dbg(NSP_DEBUG_SYNC, "period=0x%x, offset=0x%x", period, offset);
+
+	if ((data->ScsiClockDiv & (BIT(0)|BIT(1))) == CLOCK_20M) {
+		sync_table = nsp_sync_table_20M;
+	} else {
+		sync_table = nsp_sync_table_40M;
+	}
+
+	for ( i = 0; sync_table->max_period != 0; i++, sync_table++) {
+		if ( period >= sync_table->min_period &&
+		     period <= sync_table->max_period	 ) {
+			break;
+		}
+	}
+
+	if (period != 0 && sync_table->max_period == 0) {
+		/*
+		 * No proper period/offset found
+		 */
+		nsp_dbg(NSP_DEBUG_SYNC, "no proper period/offset");
+
+		sync->SyncPeriod      = 0;
+		sync->SyncOffset      = 0;
+		sync->SyncRegister    = 0;
+		sync->AckWidth	      = 0;
+
+		return FALSE;
+	}
+
+	sync->SyncRegister    = (sync_table->chip_period << SYNCREG_PERIOD_SHIFT) |
+		                (offset & SYNCREG_OFFSET_MASK);
+	sync->AckWidth	      = sync_table->ack_width;
+
+	nsp_dbg(NSP_DEBUG_SYNC, "sync_reg=0x%x, ack_width=0x%x", sync->SyncRegister, sync->AckWidth);
+
+	return TRUE;
+}
+
+
+/*
+ * start ninja hardware timer
+ */
+static void nsp_start_timer(Scsi_Cmnd *SCpnt, int time)
+{
+	unsigned int base = SCpnt->device->host->io_port;
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+	//nsp_dbg(NSP_DEBUG_INTR, "in SCpnt=0x%p, time=%d", SCpnt, time);
+	data->TimerCount = time;
+	nsp_index_write(base, TIMERCOUNT, time);
+}
+
+/*
+ * wait for bus phase change
+ */
+static int nsp_negate_signal(Scsi_Cmnd *SCpnt, unsigned char mask, char *str)
+{
+	unsigned int  base = SCpnt->device->host->io_port;
+	unsigned char reg;
+	int	      time_out;
+
+	//nsp_dbg(NSP_DEBUG_INTR, "in");
+
+	time_out = 100;
+
+	do {
+		reg = nsp_index_read(base, SCSIBUSMON);
+		if (reg == 0xff) {
+			break;
+		}
+	} while ((time_out-- != 0) && (reg & mask) != 0);
+
+	if (time_out == 0) {
+		nsp_msg(KERN_DEBUG, " %s signal off timeut", str);
+	}
+
+	return 0;
+}
+
+/*
+ * expect Ninja Irq
+ */
+static int nsp_expect_signal(Scsi_Cmnd	   *SCpnt,
+			     unsigned char  current_phase,
+			     unsigned char  mask)
+{
+	unsigned int  base	 = SCpnt->device->host->io_port;
+	int	      time_out;
+	unsigned char phase, i_src;
+
+	//nsp_dbg(NSP_DEBUG_INTR, "current_phase=0x%x, mask=0x%x", current_phase, mask);
+
+	time_out = 100;
+	do {
+		phase = nsp_index_read(base, SCSIBUSMON);
+		if (phase == 0xff) {
+			//nsp_dbg(NSP_DEBUG_INTR, "ret -1");
+			return -1;
+		}
+		i_src = nsp_read(base, IRQSTATUS);
+		if (i_src & IRQSTATUS_SCSI) {
+			//nsp_dbg(NSP_DEBUG_INTR, "ret 0 found scsi signal");
+			return 0;
+		}
+		if ((phase & mask) != 0 && (phase & BUSMON_PHASE_MASK) == current_phase) {
+			//nsp_dbg(NSP_DEBUG_INTR, "ret 1 phase=0x%x", phase);
+			return 1;
+		}
+	} while(time_out-- != 0);
+
+	//nsp_dbg(NSP_DEBUG_INTR, "timeout");
+	return -1;
+}
+
+/*
+ * transfer SCSI message
+ */
+static int nsp_xfer(Scsi_Cmnd *SCpnt, int phase)
+{
+	unsigned int  base = SCpnt->device->host->io_port;
+	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	char	     *buf  = data->MsgBuffer;
+	int	      len  = min(MSGBUF_SIZE, data->MsgLen);
+	int	      ptr;
+	int	      ret;
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
+	for (ptr = 0; len > 0; len--, ptr++) {
+
+		ret = nsp_expect_signal(SCpnt, phase, BUSMON_REQ);
+		if (ret <= 0) {
+			nsp_dbg(NSP_DEBUG_DATA_IO, "xfer quit");
+			return 0;
+		}
+
+		/* if last byte, negate ATN */
+		if (len == 1 && SCpnt->SCp.phase == PH_MSG_OUT) {
+			nsp_index_write(base, SCSIBUSCTRL, AUTODIRECTION | ACKENB);
+		}
+
+		/* read & write message */
+		if (phase & BUSMON_IO) {
+			nsp_dbg(NSP_DEBUG_DATA_IO, "read msg");
+			buf[ptr] = nsp_index_read(base, SCSIDATAWITHACK);
+		} else {
+			nsp_dbg(NSP_DEBUG_DATA_IO, "write msg");
+			nsp_index_write(base, SCSIDATAWITHACK, buf[ptr]);
+		}
+		nsp_negate_signal(SCpnt, BUSMON_ACK, "xfer<ack>");
+
+	}
+	return len;
+}
+
+/*
+ * get extra SCSI data from fifo
+ */
+static int nsp_dataphase_bypass(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	unsigned int count;
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "in");
+
+	if (SCpnt->SCp.have_data_in != IO_IN) {
+		return 0;
+	}
+
+	count = nsp_fifo_count(SCpnt);
+	if (data->FifoCount == count) {
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "not use bypass quirk");
+		return 0;
+	}
+
+	/*
+	 * XXX: NSP_QUIRK
+	 * data phase skip only occures in case of SCSI_LOW_READ
+	 */
+	nsp_dbg(NSP_DEBUG_DATA_IO, "use bypass quirk");
+	SCpnt->SCp.phase = PH_DATA;
+	nsp_pio_read(SCpnt);
+	nsp_setup_fifo(data, FALSE);
+
+	return 0;
+}
+
+/*
+ * accept reselection
+ */
+static int nsp_reselected(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base    = SCpnt->device->host->io_port;
+	unsigned int  host_id = SCpnt->device->host->this_id;
+	//nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	unsigned char bus_reg;
+	unsigned char id_reg, tmp;
+	int target;
+
+	nsp_dbg(NSP_DEBUG_RESELECTION, "in");
+
+	id_reg = nsp_index_read(base, RESELECTID);
+	tmp    = id_reg & (~BIT(host_id));
+	target = 0;
+	while(tmp != 0) {
+		if (tmp & BIT(0)) {
+			break;
+		}
+		tmp >>= 1;
+		target++;
+	}
+
+	if (SCpnt->device->id != target) {
+		nsp_msg(KERN_ERR, "XXX: reselect ID must be %d in this implementation.", target);
+	}
+
+	nsp_negate_signal(SCpnt, BUSMON_SEL, "reselect<SEL>");
+
+	nsp_nexus(SCpnt);
+	bus_reg = nsp_index_read(base, SCSIBUSCTRL) & ~(SCSI_BSY | SCSI_ATN);
+	nsp_index_write(base, SCSIBUSCTRL, bus_reg);
+	nsp_index_write(base, SCSIBUSCTRL, bus_reg | AUTODIRECTION | ACKENB);
+
+	return TRUE;
+}
+
+/*
+ * count how many data transferd
+ */
+static int nsp_fifo_count(Scsi_Cmnd *SCpnt)
+{
+	unsigned int base = SCpnt->device->host->io_port;
+	unsigned int count;
+	unsigned int l, m, h, dummy;
+
+	nsp_index_write(base, POINTERCLR, POINTER_CLEAR | ACK_COUNTER);
+
+	l     = nsp_index_read(base, TRANSFERCOUNT);
+	m     = nsp_index_read(base, TRANSFERCOUNT);
+	h     = nsp_index_read(base, TRANSFERCOUNT);
+	dummy = nsp_index_read(base, TRANSFERCOUNT); /* required this! */
+
+	count = (h << 16) | (m << 8) | (l << 0);
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "count=0x%x", count);
+
+	return count;
+}
+
+/* fifo size */
+#define RFIFO_CRIT 64
+#define WFIFO_CRIT 64
+
+/*
+ * read data in DATA IN phase
+ */
+static void nsp_pio_read(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base      = SCpnt->device->host->io_port;
+	unsigned long mmio_base = SCpnt->device->host->base;
+	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	long	      time_out;
+	int	      ocount, res;
+	unsigned char stat, fifo_stat;
+
+	ocount = data->FifoCount;
+
+	nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p resid=%d ocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d",
+		SCpnt, SCpnt->resid, ocount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual);
+
+	time_out = 1000;
+
+	while ((time_out-- != 0) &&
+	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0 ) ) {
+
+		stat = nsp_index_read(base, SCSIBUSMON);
+		stat &= BUSMON_PHASE_MASK;
+
+
+		res = nsp_fifo_count(SCpnt) - ocount;
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x ocount=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount, res);
+		if (res == 0) { /* if some data avilable ? */
+			if (stat == BUSPHASE_DATA_IN) { /* phase changed? */
+				//nsp_dbg(NSP_DEBUG_DATA_IO, " wait for data this=%d", SCpnt->SCp.this_residual);
+				continue;
+			} else {
+				nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x", stat);
+				break;
+			}
+		}
+
+		fifo_stat = nsp_read(base, FIFOSTATUS);
+		if ((fifo_stat & FIFOSTATUS_FULL_EMPTY) == 0 &&
+		    stat                                == BUSPHASE_DATA_IN) {
+			continue;
+		}
+
+		res = min(res, SCpnt->SCp.this_residual);
+
+		switch (data->TransferMode) {
+		case MODE_IO32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_fifo32_read(base, SCpnt->SCp.ptr, res >> 2);
+			break;
+		case MODE_IO8:
+			nsp_fifo8_read (base, SCpnt->SCp.ptr, res     );
+			break;
+
+		case MODE_MEM32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_mmio_fifo32_read(mmio_base, SCpnt->SCp.ptr, res >> 2);
+			break;
+
+		default:
+			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown read mode");
+			return;
+		}
+
+		SCpnt->resid	       	 -= res;
+		SCpnt->SCp.ptr		 += res;
+		SCpnt->SCp.this_residual -= res;
+		ocount			 += res;
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this_residual=0x%x ocount=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, ocount);
+
+		/* go to next scatter list if available */
+		if (SCpnt->SCp.this_residual	== 0 &&
+		    SCpnt->SCp.buffers_residual != 0 ) {
+			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next timeout=%d", time_out);
+			SCpnt->SCp.buffers_residual--;
+			SCpnt->SCp.buffer++;
+			SCpnt->SCp.ptr		 = BUFFER_ADDR;
+			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+			time_out = 1000;
+
+			//nsp_dbg(NSP_DEBUG_DATA_IO, "page: 0x%p, off: 0x%x", SCpnt->SCp.buffer->page, SCpnt->SCp.buffer->offset);
+		}
+	}
+
+	data->FifoCount = ocount;
+
+	if (time_out == 0) {
+		nsp_msg(KERN_DEBUG, "pio read timeout resid=%d this_residual=%d buffers_residual=%d",
+			SCpnt->resid, SCpnt->SCp.this_residual, SCpnt->SCp.buffers_residual);
+	}
+	nsp_dbg(NSP_DEBUG_DATA_IO, "read ocount=0x%x", ocount);
+	nsp_dbg(NSP_DEBUG_DATA_IO, "r cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+}
+
+/*
+ * write data in DATA OUT phase
+ */
+static void nsp_pio_write(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base      = SCpnt->device->host->io_port;
+	unsigned long mmio_base = SCpnt->device->host->base;
+	nsp_hw_data  *data      = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	int	      time_out;
+	int           ocount, res;
+	unsigned char stat;
+
+	ocount	 = data->FifoCount;
+
+	nsp_dbg(NSP_DEBUG_DATA_IO, "in fifocount=%d ptr=0x%p this_residual=%d buffers=0x%p nbuf=%d resid=0x%x",
+		data->FifoCount, SCpnt->SCp.ptr, SCpnt->SCp.this_residual, SCpnt->SCp.buffer, SCpnt->SCp.buffers_residual, SCpnt->resid);
+
+	time_out = 1000;
+
+	while ((time_out-- != 0) &&
+	       (SCpnt->SCp.this_residual > 0 || SCpnt->SCp.buffers_residual > 0)) {
+		stat = nsp_index_read(base, SCSIBUSMON);
+		stat &= BUSMON_PHASE_MASK;
+
+		if (stat != BUSPHASE_DATA_OUT) {
+			res = ocount - nsp_fifo_count(SCpnt);
+
+			nsp_dbg(NSP_DEBUG_DATA_IO, "phase changed stat=0x%x, res=%d\n", stat, res);
+			/* Put back pointer */
+			SCpnt->resid	       	 += res;
+			SCpnt->SCp.ptr		 -= res;
+			SCpnt->SCp.this_residual += res;
+			ocount			 -= res;
+
+			break;
+		}
+
+		res = ocount - nsp_fifo_count(SCpnt);
+		if (res > 0) { /* write all data? */
+			nsp_dbg(NSP_DEBUG_DATA_IO, "wait for all data out. ocount=0x%x res=%d", ocount, res);
+			continue;
+		}
+
+		res = min(SCpnt->SCp.this_residual, WFIFO_CRIT);
+
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "ptr=0x%p this=0x%x res=0x%x", SCpnt->SCp.ptr, SCpnt->SCp.this_residual, res);
+		switch (data->TransferMode) {
+		case MODE_IO32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_fifo32_write(base, SCpnt->SCp.ptr, res >> 2);
+			break;
+		case MODE_IO8:
+			nsp_fifo8_write (base, SCpnt->SCp.ptr, res     );
+			break;
+
+		case MODE_MEM32:
+			res &= ~(BIT(1)|BIT(0)); /* align 4 */
+			nsp_mmio_fifo32_write(mmio_base, SCpnt->SCp.ptr, res >> 2);
+			break;
+
+		default:
+			nsp_dbg(NSP_DEBUG_DATA_IO, "unknown write mode");
+			break;
+		}
+
+		SCpnt->resid	       	 -= res;
+		SCpnt->SCp.ptr		 += res;
+		SCpnt->SCp.this_residual -= res;
+		ocount			 += res;
+
+		/* go to next scatter list if available */
+		if (SCpnt->SCp.this_residual	== 0 &&
+		    SCpnt->SCp.buffers_residual != 0 ) {
+			//nsp_dbg(NSP_DEBUG_DATA_IO, "scatterlist next");
+			SCpnt->SCp.buffers_residual--;
+			SCpnt->SCp.buffer++;
+			SCpnt->SCp.ptr		 = BUFFER_ADDR;
+			SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+			time_out = 1000;
+		}
+	}
+
+	data->FifoCount = ocount;
+
+	if (time_out == 0) {
+		nsp_msg(KERN_DEBUG, "pio write timeout resid=0x%x", SCpnt->resid);
+	}
+	nsp_dbg(NSP_DEBUG_DATA_IO, "write ocount=0x%x", ocount);
+	nsp_dbg(NSP_DEBUG_DATA_IO, "w cmd=%d resid=0x%x\n", data->CmdId, SCpnt->resid);
+}
+#undef RFIFO_CRIT
+#undef WFIFO_CRIT
+
+/*
+ * setup synchronous/asynchronous data transfer mode
+ */
+static int nsp_nexus(Scsi_Cmnd *SCpnt)
+{
+	unsigned int   base   = SCpnt->device->host->io_port;
+	unsigned char  target = SCpnt->device->id;
+//	unsigned char  lun    = SCpnt->device->lun;
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	sync_data     *sync   = &(data->Sync[target]);
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "in SCpnt=0x%p", SCpnt);
+
+	/* setup synch transfer registers */
+	nsp_index_write(base, SYNCREG,	sync->SyncRegister);
+	nsp_index_write(base, ACKWIDTH, sync->AckWidth);
+
+	if (SCpnt->use_sg    == 0        ||
+	    SCpnt->resid % 4 != 0        ||
+	    SCpnt->resid     <= PAGE_SIZE ) {
+		data->TransferMode = MODE_IO8;
+	} else if (nsp_burst_mode == BURST_MEM32) {
+		data->TransferMode = MODE_MEM32;
+	} else if (nsp_burst_mode == BURST_IO32) {
+		data->TransferMode = MODE_IO32;
+	} else {
+		data->TransferMode = MODE_IO8;
+	}
+
+	/* setup pdma fifo */
+	nsp_setup_fifo(data, TRUE);
+
+	/* clear ack counter */
+ 	data->FifoCount = 0;
+	nsp_index_write(base, POINTERCLR, POINTER_CLEAR	    |
+					  ACK_COUNTER_CLEAR |
+					  REQ_COUNTER_CLEAR |
+					  HOST_COUNTER_CLEAR);
+
+	return 0;
+}
+
+#include "nsp_message.c"
+/*
+ * interrupt handler
+ */
+static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned int   base;
+	unsigned char  irq_status, irq_phase, phase;
+	Scsi_Cmnd     *tmpSC;
+	unsigned char  target, lun;
+	unsigned int  *sync_neg;
+	int            i, tmp;
+	nsp_hw_data   *data;
+
+
+	//nsp_dbg(NSP_DEBUG_INTR, "dev_id=0x%p", dev_id);
+	//nsp_dbg(NSP_DEBUG_INTR, "host=0x%p", ((scsi_info_t *)dev_id)->host);
+
+	if (                dev_id        != NULL &&
+	    ((scsi_info_t *)dev_id)->host != NULL  ) {
+		scsi_info_t *info = (scsi_info_t *)dev_id;
+
+		data = (nsp_hw_data *)info->host->hostdata;
+	} else {
+		nsp_dbg(NSP_DEBUG_INTR, "host data wrong");
+		return IRQ_NONE;
+	}
+
+	//nsp_dbg(NSP_DEBUG_INTR, "&nsp_data_base=0x%p, dev_id=0x%p", &nsp_data_base, dev_id);
+
+	base = data->BaseAddress;
+	//nsp_dbg(NSP_DEBUG_INTR, "base=0x%x", base);
+
+	/*
+	 * interrupt check
+	 */
+	nsp_write(base, IRQCONTROL, IRQCONTROL_IRQDISABLE);
+	irq_status = nsp_read(base, IRQSTATUS);
+	//nsp_dbg(NSP_DEBUG_INTR, "irq_status=0x%x", irq_status);
+	if ((irq_status == 0xff) || ((irq_status & IRQSTATUS_MASK) == 0)) {
+		nsp_write(base, IRQCONTROL, 0);
+		//nsp_dbg(NSP_DEBUG_INTR, "no irq/shared irq");
+		return IRQ_NONE;
+	}
+
+	/* XXX: IMPORTANT
+	 * Do not read an irq_phase register if no scsi phase interrupt.
+	 * Unless, you should lose a scsi phase interrupt.
+	 */
+	phase = nsp_index_read(base, SCSIBUSMON);
+	if((irq_status & IRQSTATUS_SCSI) != 0) {
+		irq_phase = nsp_index_read(base, IRQPHASESENCE);
+	} else {
+		irq_phase = 0;
+	}
+
+	//nsp_dbg(NSP_DEBUG_INTR, "irq_phase=0x%x", irq_phase);
+
+	/*
+	 * timer interrupt handler (scsi vs timer interrupts)
+	 */
+	//nsp_dbg(NSP_DEBUG_INTR, "timercount=%d", data->TimerCount);
+	if (data->TimerCount != 0) {
+		//nsp_dbg(NSP_DEBUG_INTR, "stop timer");
+		nsp_index_write(base, TIMERCOUNT, 0);
+		nsp_index_write(base, TIMERCOUNT, 0);
+		data->TimerCount = 0;
+	}
+
+	if ((irq_status & IRQSTATUS_MASK) == IRQSTATUS_TIMER &&
+	    data->SelectionTimeOut == 0) {
+		//nsp_dbg(NSP_DEBUG_INTR, "timer start");
+		nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR);
+		return IRQ_HANDLED;
+	}
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_TIMER_CLEAR | IRQCONTROL_FIFO_CLEAR);
+
+	if ((irq_status & IRQSTATUS_SCSI) &&
+	    (irq_phase  & SCSI_RESET_IRQ)) {
+		nsp_msg(KERN_ERR, "bus reset (power off?)");
+
+		nsphw_init(data);
+		nsp_bus_reset(data);
+
+		if(data->CurrentSC != NULL) {
+			tmpSC = data->CurrentSC;
+			tmpSC->result  = (DID_RESET                   << 16) |
+				         ((tmpSC->SCp.Message & 0xff) <<  8) |
+				         ((tmpSC->SCp.Status  & 0xff) <<  0);
+			nsp_scsi_done(tmpSC);
+		}
+		return IRQ_HANDLED;
+	}
+
+	if (data->CurrentSC == NULL) {
+		nsp_msg(KERN_ERR, "CurrentSC==NULL irq_status=0x%x phase=0x%x irq_phase=0x%x this can't be happen. reset everything", irq_status, phase, irq_phase);
+		nsphw_init(data);
+		nsp_bus_reset(data);
+		return IRQ_HANDLED;
+	}
+
+	tmpSC    = data->CurrentSC;
+	target   = tmpSC->device->id;
+	lun      = tmpSC->device->lun;
+	sync_neg = &(data->Sync[target].SyncNegotiation);
+
+	/*
+	 * parse hardware SCSI irq reasons register
+	 */
+	if (irq_status & IRQSTATUS_SCSI) {
+		if (irq_phase & RESELECT_IRQ) {
+			nsp_dbg(NSP_DEBUG_INTR, "reselect");
+			nsp_write(base, IRQCONTROL, IRQCONTROL_RESELECT_CLEAR);
+			if (nsp_reselected(tmpSC) != FALSE) {
+				return IRQ_HANDLED;
+			}
+		}
+
+		if ((irq_phase & (PHASE_CHANGE_IRQ | LATCHED_BUS_FREE)) == 0) {
+			return IRQ_HANDLED;
+		}
+	}
+
+	//show_phase(tmpSC);
+
+	switch(tmpSC->SCp.phase) {
+	case PH_SELSTART:
+		// *sync_neg = SYNC_NOT_YET;
+		if ((phase & BUSMON_BSY) == 0) {
+			//nsp_dbg(NSP_DEBUG_INTR, "selection count=%d", data->SelectionTimeOut);
+			if (data->SelectionTimeOut >= NSP_SELTIMEOUT) {
+				nsp_dbg(NSP_DEBUG_INTR, "selection time out");
+				data->SelectionTimeOut = 0;
+				nsp_index_write(base, SCSIBUSCTRL, 0);
+
+				tmpSC->result   = DID_TIME_OUT << 16;
+				nsp_scsi_done(tmpSC);
+
+				return IRQ_HANDLED;
+			}
+			data->SelectionTimeOut += 1;
+			nsp_start_timer(tmpSC, 1000/51);
+			return IRQ_HANDLED;
+		}
+
+		/* attention assert */
+		//nsp_dbg(NSP_DEBUG_INTR, "attention assert");
+		data->SelectionTimeOut = 0;
+		tmpSC->SCp.phase       = PH_SELECTED;
+		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN);
+		udelay(1);
+		nsp_index_write(base, SCSIBUSCTRL, SCSI_ATN | AUTODIRECTION | ACKENB);
+		return IRQ_HANDLED;
+
+		break;
+
+	case PH_RESELECT:
+		//nsp_dbg(NSP_DEBUG_INTR, "phase reselect");
+		// *sync_neg = SYNC_NOT_YET;
+		if ((phase & BUSMON_PHASE_MASK) != BUSPHASE_MESSAGE_IN) {
+
+			tmpSC->result	= DID_ABORT << 16;
+			nsp_scsi_done(tmpSC);
+			return IRQ_HANDLED;
+		}
+		/* fall thru */
+	default:
+		if ((irq_status & (IRQSTATUS_SCSI | IRQSTATUS_FIFO)) == 0) {
+			return IRQ_HANDLED;
+		}
+		break;
+	}
+
+	/*
+	 * SCSI sequencer
+	 */
+	//nsp_dbg(NSP_DEBUG_INTR, "start scsi seq");
+
+	/* normal disconnect */
+	if (((tmpSC->SCp.phase == PH_MSG_IN) || (tmpSC->SCp.phase == PH_MSG_OUT)) &&
+	    (irq_phase & LATCHED_BUS_FREE) != 0 ) {
+		nsp_dbg(NSP_DEBUG_INTR, "normal disconnect irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
+
+		//*sync_neg       = SYNC_NOT_YET;
+
+		if ((tmpSC->SCp.Message == MSG_COMMAND_COMPLETE)) {     /* all command complete and return status */
+			tmpSC->result = (DID_OK		             << 16) |
+					((tmpSC->SCp.Message & 0xff) <<  8) |
+					((tmpSC->SCp.Status  & 0xff) <<  0);
+			nsp_dbg(NSP_DEBUG_INTR, "command complete result=0x%x", tmpSC->result);
+			nsp_scsi_done(tmpSC);
+
+			return IRQ_HANDLED;
+		}
+
+		return IRQ_HANDLED;
+	}
+
+
+	/* check unexpected bus free state */
+	if (phase == 0) {
+		nsp_msg(KERN_DEBUG, "unexpected bus free. irq_status=0x%x, phase=0x%x, irq_phase=0x%x", irq_status, phase, irq_phase);
+
+		*sync_neg       = SYNC_NG;
+		tmpSC->result   = DID_ERROR << 16;
+		nsp_scsi_done(tmpSC);
+		return IRQ_HANDLED;
+	}
+
+	switch (phase & BUSMON_PHASE_MASK) {
+	case BUSPHASE_COMMAND:
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_COMMAND");
+		if ((phase & BUSMON_REQ) == 0) {
+			nsp_dbg(NSP_DEBUG_INTR, "REQ == 0");
+			return IRQ_HANDLED;
+		}
+
+		tmpSC->SCp.phase = PH_COMMAND;
+
+		nsp_nexus(tmpSC);
+
+		/* write scsi command */
+		nsp_dbg(NSP_DEBUG_INTR, "cmd_len=%d", tmpSC->cmd_len);
+		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER);
+		for (i = 0; i < tmpSC->cmd_len; i++) {
+			nsp_index_write(base, COMMANDDATA, tmpSC->cmnd[i]);
+		}
+		nsp_index_write(base, COMMANDCTRL, CLEAR_COMMAND_POINTER | AUTO_COMMAND_GO);
+		break;
+
+	case BUSPHASE_DATA_OUT:
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_OUT");
+
+		tmpSC->SCp.phase        = PH_DATA;
+		tmpSC->SCp.have_data_in = IO_OUT;
+
+		nsp_pio_write(tmpSC);
+
+		break;
+
+	case BUSPHASE_DATA_IN:
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_DATA_IN");
+
+		tmpSC->SCp.phase        = PH_DATA;
+		tmpSC->SCp.have_data_in = IO_IN;
+
+		nsp_pio_read(tmpSC);
+
+		break;
+
+	case BUSPHASE_STATUS:
+		nsp_dataphase_bypass(tmpSC);
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_STATUS");
+
+		tmpSC->SCp.phase = PH_STATUS;
+
+		tmpSC->SCp.Status = nsp_index_read(base, SCSIDATAWITHACK);
+		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x status=0x%x", tmpSC->SCp.Message, tmpSC->SCp.Status);
+
+		break;
+
+	case BUSPHASE_MESSAGE_OUT:
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_OUT");
+		if ((phase & BUSMON_REQ) == 0) {
+			goto timer_out;
+		}
+
+		tmpSC->SCp.phase = PH_MSG_OUT;
+
+		//*sync_neg = SYNC_NOT_YET;
+
+		data->MsgLen = i = 0;
+		data->MsgBuffer[i] = IDENTIFY(TRUE, lun); i++;
+
+		if (*sync_neg == SYNC_NOT_YET) {
+			data->Sync[target].SyncPeriod = 0;
+			data->Sync[target].SyncOffset = 0;
+
+			/**/
+			data->MsgBuffer[i] = MSG_EXTENDED; i++;
+			data->MsgBuffer[i] = 3;            i++;
+			data->MsgBuffer[i] = MSG_EXT_SDTR; i++;
+			data->MsgBuffer[i] = 0x0c;         i++;
+			data->MsgBuffer[i] = 15;           i++;
+			/**/
+		}
+		data->MsgLen = i;
+
+		nsp_analyze_sdtr(tmpSC);
+		show_message(data);
+		nsp_message_out(tmpSC);
+		break;
+
+	case BUSPHASE_MESSAGE_IN:
+		nsp_dataphase_bypass(tmpSC);
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE_MESSAGE_IN");
+		if ((phase & BUSMON_REQ) == 0) {
+			goto timer_out;
+		}
+
+		tmpSC->SCp.phase = PH_MSG_IN;
+		nsp_message_in(tmpSC);
+
+		/**/
+		if (*sync_neg == SYNC_NOT_YET) {
+			//nsp_dbg(NSP_DEBUG_INTR, "sync target=%d,lun=%d",target,lun);
+
+			if (data->MsgLen       >= 5            &&
+			    data->MsgBuffer[0] == MSG_EXTENDED &&
+			    data->MsgBuffer[1] == 3            &&
+			    data->MsgBuffer[2] == MSG_EXT_SDTR ) {
+				data->Sync[target].SyncPeriod = data->MsgBuffer[3];
+				data->Sync[target].SyncOffset = data->MsgBuffer[4];
+				//nsp_dbg(NSP_DEBUG_INTR, "sync ok, %d %d", data->MsgBuffer[3], data->MsgBuffer[4]);
+				*sync_neg = SYNC_OK;
+			} else {
+				data->Sync[target].SyncPeriod = 0;
+				data->Sync[target].SyncOffset = 0;
+				*sync_neg = SYNC_NG;
+			}
+			nsp_analyze_sdtr(tmpSC);
+		}
+		/**/
+
+		/* search last messeage byte */
+		tmp = -1;
+		for (i = 0; i < data->MsgLen; i++) {
+			tmp = data->MsgBuffer[i];
+			if (data->MsgBuffer[i] == MSG_EXTENDED) {
+				i += (1 + data->MsgBuffer[i+1]);
+			}
+		}
+		tmpSC->SCp.Message = tmp;
+
+		nsp_dbg(NSP_DEBUG_INTR, "message=0x%x len=%d", tmpSC->SCp.Message, data->MsgLen);
+		show_message(data);
+
+		break;
+
+	case BUSPHASE_SELECT:
+	default:
+		nsp_dbg(NSP_DEBUG_INTR, "BUSPHASE other");
+
+		break;
+	}
+
+	//nsp_dbg(NSP_DEBUG_INTR, "out");
+	return IRQ_HANDLED; 	
+
+timer_out:
+	nsp_start_timer(tmpSC, 1000/102);
+	return IRQ_HANDLED;
+}
+
+#ifdef NSP_DEBUG
+#include "nsp_debug.c"
+#endif	/* NSP_DEBUG */
+
+/*----------------------------------------------------------------*/
+/* look for ninja3 card and init if found			  */
+/*----------------------------------------------------------------*/
+static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *host;	/* registered host structure */
+	nsp_hw_data *data_b = &nsp_data_base, *data;
+
+	nsp_dbg(NSP_DEBUG_INIT, "this_id=%d", sht->this_id);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	host = scsi_host_alloc(&nsp_driver_template, sizeof(nsp_hw_data));
+#else
+	host = scsi_register(sht, sizeof(nsp_hw_data));
+#endif
+	if (host == NULL) {
+		nsp_dbg(NSP_DEBUG_INIT, "host failed");
+		return NULL;
+	}
+
+	memcpy(host->hostdata, data_b, sizeof(nsp_hw_data));
+	data = (nsp_hw_data *)host->hostdata;
+	data->ScsiInfo->host = host;
+#ifdef NSP_DEBUG
+	data->CmdId = 0;
+#endif
+
+	nsp_dbg(NSP_DEBUG_INIT, "irq=%d,%d", data_b->IrqNumber, ((nsp_hw_data *)host->hostdata)->IrqNumber);
+
+	host->unique_id	  = data->BaseAddress;
+	host->io_port	  = data->BaseAddress;
+	host->n_io_port	  = data->NumAddress;
+	host->irq	  = data->IrqNumber;
+	host->base        = data->MmioAddress;
+
+	spin_lock_init(&(data->Lock));
+
+	snprintf(data->nspinfo,
+		 sizeof(data->nspinfo),
+		 "NinjaSCSI-3/32Bi Driver $Revision: 1.23 $ IO:0x%04lx-0x%04lx MMIO(virt addr):0x%04lx IRQ:%02d",
+		 host->io_port, host->io_port + host->n_io_port - 1,
+		 host->base,
+		 host->irq);
+	sht->name	  = data->nspinfo;
+
+	nsp_dbg(NSP_DEBUG_INIT, "end");
+
+
+	return host; /* detect done. */
+}
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static int nsp_detect_old(Scsi_Host_Template *sht)
+{
+	if (nsp_detect(sht) == NULL) {
+		return 0;
+	} else {
+		//MOD_INC_USE_COUNT;
+		return 1;
+	}
+}
+
+
+static int nsp_release_old(struct Scsi_Host *shpnt)
+{
+	//nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
+
+	/* PCMCIA Card Service dose same things below. */
+	/* So we do nothing.                           */
+	//if (shpnt->irq) {
+	//	free_irq(shpnt->irq, data->ScsiInfo);
+	//}
+	//if (shpnt->io_port) {
+	//	release_region(shpnt->io_port, shpnt->n_io_port);
+	//}
+
+	//MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+#endif
+
+/*----------------------------------------------------------------*/
+/* return info string						  */
+/*----------------------------------------------------------------*/
+static const char *nsp_info(struct Scsi_Host *shpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)shpnt->hostdata;
+
+	return data->nspinfo;
+}
+
+#undef SPRINTF
+#define SPRINTF(args...) \
+        do { \
+		if(length > (pos - buffer)) { \
+			pos += snprintf(pos, length - (pos - buffer) + 1, ## args); \
+			nsp_dbg(NSP_DEBUG_PROC, "buffer=0x%p pos=0x%p length=%d %d\n", buffer, pos, length,  length - (pos - buffer));\
+		} \
+	} while(0)
+static int
+nsp_proc_info(
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	struct Scsi_Host *host,
+#endif
+	char  *buffer,
+	char **start,
+	off_t  offset,
+	int    length,
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	int    hostno,
+#endif
+	int    inout)
+{
+	int id;
+	char *pos = buffer;
+	int thislength;
+	int speed;
+	unsigned long flags;
+	nsp_hw_data *data;
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	struct Scsi_Host *host;
+#else
+	int hostno;
+#endif
+	if (inout) {
+		return -EINVAL;
+	}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	hostno = host->host_no;
+#else
+	/* search this HBA host */
+	host = scsi_host_hn_get(hostno);
+	if (host == NULL) {
+		return -ESRCH;
+	}
+#endif
+	data = (nsp_hw_data *)host->hostdata;
+
+
+	SPRINTF("NinjaSCSI status\n\n");
+	SPRINTF("Driver version:        $Revision: 1.23 $\n");
+	SPRINTF("SCSI host No.:         %d\n",          hostno);
+	SPRINTF("IRQ:                   %d\n",          host->irq);
+	SPRINTF("IO:                    0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+	SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
+	SPRINTF("sg_tablesize:          %d\n",          host->sg_tablesize);
+
+	SPRINTF("burst transfer mode:   ");
+	switch (nsp_burst_mode) {
+	case BURST_IO8:
+		SPRINTF("io8");
+		break;
+	case BURST_IO32:
+		SPRINTF("io32");
+		break;
+	case BURST_MEM32:
+		SPRINTF("mem32");
+		break;
+	default:
+		SPRINTF("???");
+		break;
+	}
+	SPRINTF("\n");
+
+
+	spin_lock_irqsave(&(data->Lock), flags);
+	SPRINTF("CurrentSC:             0x%p\n\n",      data->CurrentSC);
+	spin_unlock_irqrestore(&(data->Lock), flags);
+
+	SPRINTF("SDTR status\n");
+	for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
+
+		SPRINTF("id %d: ", id);
+
+		if (id == host->this_id) {
+			SPRINTF("----- NinjaSCSI-3 host adapter\n");
+			continue;
+		}
+
+		switch(data->Sync[id].SyncNegotiation) {
+		case SYNC_OK:
+			SPRINTF(" sync");
+			break;
+		case SYNC_NG:
+			SPRINTF("async");
+			break;
+		case SYNC_NOT_YET:
+			SPRINTF(" none");
+			break;
+		default:
+			SPRINTF("?????");
+			break;
+		}
+
+		if (data->Sync[id].SyncPeriod != 0) {
+			speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
+
+			SPRINTF(" transfer %d.%dMB/s, offset %d",
+				speed / 1000,
+				speed % 1000,
+				data->Sync[id].SyncOffset
+				);
+		}
+		SPRINTF("\n");
+	}
+
+	thislength = pos - (buffer + offset);
+
+	if(thislength < 0) {
+		*start = NULL;
+                return 0;
+        }
+
+
+	thislength = min(thislength, length);
+	*start = buffer + offset;
+
+	return thislength;
+}
+#undef SPRINTF
+
+/*---------------------------------------------------------------*/
+/* error handler                                                 */
+/*---------------------------------------------------------------*/
+
+/*static int nsp_eh_strategy(struct Scsi_Host *Shost)
+{
+	return FAILED;
+}*/
+
+/*
+static int nsp_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
+
+	return nsp_eh_bus_reset(SCpnt);
+}*/
+
+/*
+static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp_dbg(NSP_DEBUG_BUSRESET, "%s: SCpnt=0x%p", SCpnt);
+
+	return FAILED;
+}*/
+
+static int nsp_bus_reset(nsp_hw_data *data)
+{
+	unsigned int base = data->BaseAddress;
+	int	     i;
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLMASK);
+
+	nsp_index_write(base, SCSIBUSCTRL, SCSI_RST);
+	mdelay(100); /* 100ms */
+	nsp_index_write(base, SCSIBUSCTRL, 0);
+	for(i = 0; i < 5; i++) {
+		nsp_index_read(base, IRQPHASESENCE); /* dummy read */
+	}
+
+	nsphw_init_sync(data);
+
+	nsp_write(base, IRQCONTROL, IRQCONTROL_ALLCLEAR);
+
+	return SUCCESS;
+}
+
+static int nsp_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+	nsp_dbg(NSP_DEBUG_BUSRESET, "SCpnt=0x%p", SCpnt);
+
+	return nsp_bus_reset(data);
+}
+
+static int nsp_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+
+	nsp_dbg(NSP_DEBUG_BUSRESET, "in");
+
+	nsphw_init(data);
+
+	return SUCCESS;
+}
+
+
+/**********************************************************************
+  PCMCIA functions
+**********************************************************************/
+
+/*======================================================================
+    nsp_cs_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+======================================================================*/
+static dev_link_t *nsp_cs_attach(void)
+{
+	scsi_info_t  *info;
+	client_reg_t  client_reg;
+	dev_link_t   *link;
+	int	      ret;
+	nsp_hw_data  *data = &nsp_data_base;
+
+	nsp_dbg(NSP_DEBUG_INIT, "in");
+
+	/* Create new SCSI device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (info == NULL) { return NULL; }
+	memset(info, 0, sizeof(*info));
+	link = &info->link;
+	link->priv = info;
+	data->ScsiInfo = info;
+
+	nsp_dbg(NSP_DEBUG_INIT, "info=0x%p", info);
+
+	/* The io structure describes IO port mapping */
+	link->io.NumPorts1	 = 0x10;
+	link->io.Attributes1	 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.IOAddrLines	 = 10;	/* not used */
+
+	/* Interrupt setup */
+	link->irq.Attributes	 = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1	 = IRQ_LEVEL_ID;
+
+	/* Interrupt handler */
+	link->irq.Handler	 = &nspintr;
+	link->irq.Instance       = info;
+	link->irq.Attributes     |= (SA_SHIRQ | SA_SAMPLE_RANDOM);
+
+	/* General socket configuration */
+	link->conf.Attributes	 = CONF_ENABLE_IRQ;
+	link->conf.Vcc		 = 50;
+	link->conf.IntType	 = INT_MEMORY_AND_IO;
+	link->conf.Present	 = PRESENT_OPTION;
+
+
+	/* Register with Card Services */
+	link->next               = dev_list;
+	dev_list                 = link;
+	client_reg.dev_info	 = &dev_info;
+	client_reg.EventMask	 =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET	|
+		CS_EVENT_PM_SUSPEND	| CS_EVENT_PM_RESUME	 ;
+	client_reg.event_handler = &nsp_cs_event;
+	client_reg.Version	 = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != CS_SUCCESS) {
+		cs_error(link->handle, RegisterClient, ret);
+		nsp_cs_detach(link);
+		return NULL;
+	}
+
+
+	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
+	return link;
+} /* nsp_cs_attach */
+
+
+/*======================================================================
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.	 If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+======================================================================*/
+static void nsp_cs_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+
+	nsp_dbg(NSP_DEBUG_INIT, "in, link=0x%p", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) {
+		if (*linkp == link) {
+			break;
+		}
+	}
+	if (*linkp == NULL) {
+		return;
+	}
+
+	if (link->state & DEV_CONFIG)
+		nsp_cs_release(link);
+
+	/* Break the link with Card Services */
+	if (link->handle) {
+		pcmcia_deregister_client(link->handle);
+	}
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+	kfree(link->priv);
+	link->priv = NULL;
+
+} /* nsp_cs_detach */
+
+
+/*======================================================================
+    nsp_cs_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+======================================================================*/
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+/*====================================================================*/
+static void nsp_cs_config(dev_link_t *link)
+{
+	client_handle_t	  handle = link->handle;
+	scsi_info_t	 *info	 = link->priv;
+	tuple_t		  tuple;
+	cisparse_t	  parse;
+	int		  last_ret, last_fn;
+	unsigned char	  tuple_data[64];
+	config_info_t	  conf;
+	win_req_t         req;
+	memreq_t          map;
+	cistpl_cftable_entry_t dflt = { 0 };
+	struct Scsi_Host *host;
+	nsp_hw_data      *data = &nsp_data_base;
+#if !(LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
+	Scsi_Device	 *dev;
+	dev_node_t	**tail, *node;
+#endif
+
+	nsp_dbg(NSP_DEBUG_INIT, "in");
+
+	tuple.DesiredTuple    = CISTPL_CONFIG;
+	tuple.Attributes      = 0;
+	tuple.TupleData	      = tuple_data;
+	tuple.TupleDataMax    = sizeof(tuple_data);
+	tuple.TupleOffset     = 0;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData,	pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple,	pcmcia_parse_tuple(handle, &tuple, &parse));
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present    = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state	      |= DEV_CONFIG;
+
+	/* Look up the current Vcc */
+	CS_CHECK(GetConfigurationInfo, pcmcia_get_configuration_info(handle, &conf));
+	link->conf.Vcc = conf.Vcc;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	while (1) {
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+
+		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+			goto next_entry;
+
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) { dflt = *cfg; }
+		if (cfg->index == 0) { goto next_entry; }
+		link->conf.ConfigIndex = cfg->index;
+
+		/* Does this card need audio output? */
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+			if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000) {
+				goto next_entry;
+			}
+		} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+			if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000) {
+				goto next_entry;
+			}
+		}
+
+		if (cfg->vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				cfg->vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		} else if (dflt.vpp1.present & (1 << CISTPL_POWER_VNOM)) {
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				dflt.vpp1.param[CISTPL_POWER_VNOM] / 10000;
+		}
+
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) {
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+		}
+
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+			link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 = link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+			/* This reserves IO space but doesn't actually enable it */
+			if (pcmcia_request_io(link->handle, &link->io) != 0)
+				goto next_entry;
+		}
+
+		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+			cistpl_mem_t *mem =
+				(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+			req.Attributes |= WIN_ENABLE;
+			req.Base = mem->win[0].host_addr;
+			req.Size = mem->win[0].len;
+			if (req.Size < 0x1000) {
+				req.Size = 0x1000;
+			}
+			req.AccessSpeed = 0;
+			if (pcmcia_request_window(&link->handle, &req, &link->win) != 0)
+				goto next_entry;
+			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+			if (pcmcia_map_mem_page(link->win, &map) != 0)
+				goto next_entry;
+
+			data->MmioAddress = (unsigned long)ioremap_nocache(req.Base, req.Size);
+			data->MmioLength  = req.Size;
+		}
+		/* If we got this far, we're cool! */
+		break;
+
+	next_entry:
+		nsp_dbg(NSP_DEBUG_INIT, "next");
+
+		if (link->io.NumPorts1) {
+			pcmcia_release_io(link->handle, &link->io);
+		}
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	}
+
+	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+		CS_CHECK(RequestIRQ, pcmcia_request_irq(link->handle, &link->irq));
+	}
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+
+	if (free_ports) {
+		if (link->io.BasePort1) {
+			release_region(link->io.BasePort1, link->io.NumPorts1);
+		}
+		if (link->io.BasePort2) {
+			release_region(link->io.BasePort2, link->io.NumPorts2);
+		}
+	}
+
+	/* Set port and IRQ */
+	data->BaseAddress = link->io.BasePort1;
+	data->NumAddress  = link->io.NumPorts1;
+	data->IrqNumber   = link->irq.AssignedIRQ;
+
+	nsp_dbg(NSP_DEBUG_INIT, "I/O[0x%x+0x%x] IRQ %d",
+		data->BaseAddress, data->NumAddress, data->IrqNumber);
+
+	if(nsphw_init(data) == FALSE) {
+		goto cs_failed;
+	}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
+	host = nsp_detect(&nsp_driver_template);
+#else
+	scsi_register_host(&nsp_driver_template);
+	for (host = scsi_host_get_next(NULL); host != NULL;
+	     host = scsi_host_get_next(host)) {
+		if (host->hostt == &nsp_driver_template) {
+			break;
+		}
+	}
+#endif
+
+	if (host == NULL) {
+		nsp_dbg(NSP_DEBUG_INIT, "detect failed");
+		goto cs_failed;
+	}
+
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
+	scsi_add_host (host, NULL);
+	scsi_scan_host(host);
+
+	snprintf(info->node.dev_name, sizeof(info->node.dev_name), "scsi%d", host->host_no);
+	link->dev  = &info->node;
+	info->host = host;
+
+#else
+	nsp_dbg(NSP_DEBUG_INIT, "GET_SCSI_INFO");
+	tail = &link->dev;
+	info->ndev = 0;
+
+	nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
+
+	for (dev = host->host_queue; dev != NULL; dev = dev->next) {
+		unsigned long id;
+		id = (dev->id & 0x0f) + ((dev->lun & 0x0f) << 4) +
+			((dev->channel & 0x0f) << 8) +
+			((dev->host->host_no & 0x0f) << 12);
+		node = &info->node[info->ndev];
+		node->minor = 0;
+		switch (dev->type) {
+		case TYPE_TAPE:
+			node->major = SCSI_TAPE_MAJOR;
+			snprintf(node->dev_name, sizeof(node->dev_name), "st#%04lx", id);
+			break;
+		case TYPE_DISK:
+		case TYPE_MOD:
+			node->major = SCSI_DISK0_MAJOR;
+			snprintf(node->dev_name, sizeof(node->dev_name), "sd#%04lx", id);
+			break;
+		case TYPE_ROM:
+		case TYPE_WORM:
+			node->major = SCSI_CDROM_MAJOR;
+			snprintf(node->dev_name, sizeof(node->dev_name), "sr#%04lx", id);
+			break;
+		default:
+			node->major = SCSI_GENERIC_MAJOR;
+			snprintf(node->dev_name, sizeof(node->dev_name), "sg#%04lx", id);
+			break;
+		}
+		*tail = node; tail = &node->next;
+		info->ndev++;
+		info->host = dev->host;
+	}
+
+	*tail = NULL;
+	if (info->ndev == 0) {
+		nsp_msg(KERN_INFO, "no SCSI devices found");
+	}
+	nsp_dbg(NSP_DEBUG_INIT, "host=0x%p", host);
+#endif
+
+	/* Finally, report what we've done */
+	printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d",
+	       link->conf.ConfigIndex,
+	       link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1) {
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	}
+	if (link->conf.Attributes & CONF_ENABLE_IRQ) {
+		printk(", irq %d", link->irq.AssignedIRQ);
+	}
+	if (link->io.NumPorts1) {
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1+link->io.NumPorts1-1);
+	}
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+		       link->io.BasePort2+link->io.NumPorts2-1);
+	if (link->win)
+		printk(", mem 0x%06lx-0x%06lx", req.Base,
+		       req.Base+req.Size-1);
+	printk("\n");
+
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+
+ cs_failed:
+	nsp_dbg(NSP_DEBUG_INIT, "config fail");
+	cs_error(link->handle, last_fn, last_ret);
+	nsp_cs_release(link);
+
+	return;
+} /* nsp_cs_config */
+#undef CS_CHECK
+
+
+/*======================================================================
+    After a card is removed, nsp_cs_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+======================================================================*/
+static void nsp_cs_release(dev_link_t *link)
+{
+	scsi_info_t *info = link->priv;
+	nsp_hw_data *data = NULL;
+
+	if (info->host == NULL) {
+		nsp_msg(KERN_DEBUG, "unexpected card release call.");
+	} else {
+		data = (nsp_hw_data *)info->host->hostdata;
+	}
+
+	nsp_dbg(NSP_DEBUG_INIT, "link=0x%p", link);
+
+	/* Unlink the device chain */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
+	if (info->host != NULL) {
+		scsi_remove_host(info->host);
+	}
+#else
+	scsi_unregister_host(&nsp_driver_template);
+#endif
+	link->dev = NULL;
+
+	if (link->win) {
+		if (data != NULL) {
+			iounmap((void *)(data->MmioAddress));
+		}
+		pcmcia_release_window(link->win);
+	}
+	pcmcia_release_configuration(link->handle);
+	if (link->io.NumPorts1) {
+		pcmcia_release_io(link->handle, &link->io);
+	}
+	if (link->irq.AssignedIRQ) {
+		pcmcia_release_irq(link->handle, &link->irq);
+	}
+	link->state &= ~DEV_CONFIG;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2))
+	if (info->host != NULL) {
+		scsi_host_put(info->host);
+	}
+#endif
+} /* nsp_cs_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+
+======================================================================*/
+static int nsp_cs_event(event_t		       event,
+			int		       priority,
+			event_callback_args_t *args)
+{
+	dev_link_t  *link = args->client_data;
+	scsi_info_t *info = link->priv;
+	nsp_hw_data *data;
+
+	nsp_dbg(NSP_DEBUG_INIT, "in, event=0x%08x", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		nsp_dbg(NSP_DEBUG_INIT, "event: remove");
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			((scsi_info_t *)link->priv)->stop = 1;
+			nsp_cs_release(link);
+		}
+		break;
+
+	case CS_EVENT_CARD_INSERTION:
+		nsp_dbg(NSP_DEBUG_INIT, "event: insert");
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,68))
+		info->bus    =  args->bus;
+#endif
+		nsp_cs_config(link);
+		break;
+
+	case CS_EVENT_PM_SUSPEND:
+		nsp_dbg(NSP_DEBUG_INIT, "event: suspend");
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		/* Mark the device as stopped, to block IO until later */
+		nsp_dbg(NSP_DEBUG_INIT, "event: reset physical");
+
+		if (info->host != NULL) {
+			nsp_msg(KERN_INFO, "clear SDTR status");
+
+			data = (nsp_hw_data *)info->host->hostdata;
+
+			nsphw_init_sync(data);
+		}
+
+		info->stop = 1;
+		if (link->state & DEV_CONFIG) {
+			pcmcia_release_configuration(link->handle);
+		}
+		break;
+
+	case CS_EVENT_PM_RESUME:
+		nsp_dbg(NSP_DEBUG_INIT, "event: resume");
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		nsp_dbg(NSP_DEBUG_INIT, "event: reset");
+		if (link->state & DEV_CONFIG) {
+			pcmcia_request_configuration(link->handle, &link->conf);
+		}
+		info->stop = 0;
+
+		if (info->host != NULL) {
+			nsp_msg(KERN_INFO, "reset host and bus");
+
+			data = (nsp_hw_data *)info->host->hostdata;
+
+			nsphw_init   (data);
+			nsp_bus_reset(data);
+		}
+
+		break;
+
+	default:
+		nsp_dbg(NSP_DEBUG_INIT, "event: unknown");
+		break;
+	}
+	nsp_dbg(NSP_DEBUG_INIT, "end");
+	return 0;
+} /* nsp_cs_event */
+
+/*======================================================================*
+ *	module entry point
+ *====================================================================*/
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+static struct pcmcia_driver nsp_driver = {
+	.owner          = THIS_MODULE,
+	.drv            = {
+		.name   = "nsp_cs",
+	},
+	.attach         = nsp_cs_attach,
+	.detach         = nsp_cs_detach,
+};
+#endif
+
+static int __init nsp_cs_init(void)
+{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+	nsp_msg(KERN_INFO, "loading...");
+
+	return pcmcia_register_driver(&nsp_driver);
+#else
+	servinfo_t serv;
+
+	nsp_msg(KERN_INFO, "loading...");
+	pcmcia_get_card_services_info(&serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		nsp_msg(KERN_DEBUG, "Card Services release does not match!");
+		return -EINVAL;
+	}
+	register_pcmcia_driver(&dev_info, &nsp_cs_attach, &nsp_cs_detach);
+
+	nsp_dbg(NSP_DEBUG_INIT, "out");
+	return 0;
+#endif
+}
+
+static void __exit nsp_cs_exit(void)
+{
+	nsp_msg(KERN_INFO, "unloading...");
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,68))
+	pcmcia_unregister_driver(&nsp_driver);
+	BUG_ON(dev_list != NULL);
+#else
+	unregister_pcmcia_driver(&dev_info);
+	/* XXX: this really needs to move into generic code.. */
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG) {
+			nsp_cs_release(dev_list);
+		}
+		nsp_cs_detach(dev_list);
+	}
+#endif
+}
+
+
+module_init(nsp_cs_init)
+module_exit(nsp_cs_exit)
+
+/* end */
diff --git a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h
new file mode 100644
index 0000000..c201b52
--- /dev/null
+++ b/drivers/scsi/pcmcia/nsp_cs.h
@@ -0,0 +1,472 @@
+/*=======================================================/
+  Header file for nsp_cs.c
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    Ver.1.0 : Cut unused lines.
+    Ver 0.1 : Initial version.
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+
+=========================================================*/
+
+/* $Id: nsp_cs.h,v 1.19 2003/08/18 11:09:19 elca Exp $ */
+
+#ifndef  __nsp_cs__
+#define  __nsp_cs__
+
+/* for debugging */
+//#define NSP_DEBUG 9
+
+/*
+#define static
+#define inline
+*/
+
+/************************************
+ * Some useful macros...
+ */
+#define BIT(x)      (1L << (x))
+
+/* SCSI initiator must be ID 7 */
+#define NSP_INITIATOR_ID  7
+
+#define NSP_SELTIMEOUT 200
+
+/***************************************************************************
+ * register definitions
+ ***************************************************************************/
+/*========================================================================
+ * base register
+ ========================================================================*/
+#define	IRQCONTROL	0x00  /* R */
+#  define IRQCONTROL_RESELECT_CLEAR     BIT(0)
+#  define IRQCONTROL_PHASE_CHANGE_CLEAR BIT(1)
+#  define IRQCONTROL_TIMER_CLEAR        BIT(2)
+#  define IRQCONTROL_FIFO_CLEAR         BIT(3)
+#  define IRQCONTROL_ALLMASK            0xff
+#  define IRQCONTROL_ALLCLEAR           (IRQCONTROL_RESELECT_CLEAR     | \
+					 IRQCONTROL_PHASE_CHANGE_CLEAR | \
+					 IRQCONTROL_TIMER_CLEAR        | \
+					 IRQCONTROL_FIFO_CLEAR          )
+#  define IRQCONTROL_IRQDISABLE         0xf0
+
+#define	IRQSTATUS	0x00  /* W */
+#  define IRQSTATUS_SCSI  BIT(0)
+#  define IRQSTATUS_TIMER BIT(2)
+#  define IRQSTATUS_FIFO  BIT(3)
+#  define IRQSTATUS_MASK  0x0f
+
+#define	IFSELECT	0x01 /* W */
+#  define IF_IFSEL    BIT(0)
+#  define IF_REGSEL   BIT(2)
+
+#define	FIFOSTATUS	0x01 /* R */
+#  define FIFOSTATUS_CHIP_REVISION_MASK 0x0f
+#  define FIFOSTATUS_CHIP_ID_MASK       0x70
+#  define FIFOSTATUS_FULL_EMPTY         BIT(7)
+
+#define	INDEXREG	0x02 /* R/W */
+#define	DATAREG		0x03 /* R/W */
+#define	FIFODATA	0x04 /* R/W */
+#define	FIFODATA1	0x05 /* R/W */
+#define	FIFODATA2	0x06 /* R/W */
+#define	FIFODATA3	0x07 /* R/W */
+
+/*====================================================================
+ * indexed register
+ ====================================================================*/
+#define EXTBUSCTRL	0x10 /* R/W,deleted */
+
+#define CLOCKDIV	0x11 /* R/W */
+#  define CLOCK_40M 0x02
+#  define CLOCK_20M 0x01
+#  define FAST_20   BIT(2)
+
+#define TERMPWRCTRL	0x13 /* R/W */
+#  define POWER_ON BIT(0)
+
+#define SCSIIRQMODE	0x15 /* R/W */
+#  define SCSI_PHASE_CHANGE_EI BIT(0)
+#  define RESELECT_EI          BIT(4)
+#  define FIFO_IRQ_EI          BIT(5)
+#  define SCSI_RESET_IRQ_EI    BIT(6)
+
+#define IRQPHASESENCE	0x16 /* R */
+#  define LATCHED_MSG      BIT(0)
+#  define LATCHED_IO       BIT(1)
+#  define LATCHED_CD       BIT(2)
+#  define LATCHED_BUS_FREE BIT(3)
+#  define PHASE_CHANGE_IRQ BIT(4)
+#  define RESELECT_IRQ     BIT(5)
+#  define FIFO_IRQ         BIT(6)
+#  define SCSI_RESET_IRQ   BIT(7)
+
+#define TIMERCOUNT	0x17 /* R/W */
+
+#define SCSIBUSCTRL	0x18 /* R/W */
+#  define SCSI_SEL         BIT(0)
+#  define SCSI_RST         BIT(1)
+#  define SCSI_DATAOUT_ENB BIT(2)
+#  define SCSI_ATN         BIT(3)
+#  define SCSI_ACK         BIT(4)
+#  define SCSI_BSY         BIT(5)
+#  define AUTODIRECTION    BIT(6)
+#  define ACKENB           BIT(7)
+
+#define SCSIBUSMON	0x19 /* R */
+
+#define SETARBIT	0x1A /* W */
+#  define ARBIT_GO         BIT(0)
+#  define ARBIT_FLAG_CLEAR BIT(1)
+
+#define ARBITSTATUS	0x1A /* R */
+/*#  define ARBIT_GO        BIT(0)*/
+#  define ARBIT_WIN        BIT(1)
+#  define ARBIT_FAIL       BIT(2)
+#  define RESELECT_FLAG    BIT(3)
+
+#define PARITYCTRL	0x1B  /* W */
+#define PARITYSTATUS	0x1B  /* R */
+
+#define COMMANDCTRL	0x1C  /* W */
+#  define CLEAR_COMMAND_POINTER BIT(0)
+#  define AUTO_COMMAND_GO       BIT(1)
+
+#define RESELECTID	0x1C  /* R   */
+#define COMMANDDATA	0x1D  /* R/W */
+
+#define POINTERCLR	0x1E  /*   W */
+#  define POINTER_CLEAR      BIT(0)
+#  define ACK_COUNTER_CLEAR  BIT(1)
+#  define REQ_COUNTER_CLEAR  BIT(2)
+#  define HOST_COUNTER_CLEAR BIT(3)
+#  define READ_SOURCE        (BIT(4) | BIT(5))
+#    define ACK_COUNTER        (0)
+#    define REQ_COUNTER        (BIT(4))
+#    define HOST_COUNTER       (BIT(5))
+
+#define TRANSFERCOUNT	0x1E  /* R   */
+
+#define TRANSFERMODE	0x20  /* R/W */
+#  define MODE_MEM8   BIT(0)
+#  define MODE_MEM32  BIT(1)
+#  define MODE_ADR24  BIT(2)
+#  define MODE_ADR32  BIT(3)
+#  define MODE_IO8    BIT(4)
+#  define MODE_IO32   BIT(5)
+#  define TRANSFER_GO BIT(6)
+#  define BRAIND      BIT(7)
+
+#define SYNCREG		0x21 /* R/W */
+#  define SYNCREG_OFFSET_MASK  0x0f
+#  define SYNCREG_PERIOD_MASK  0xf0
+#  define SYNCREG_PERIOD_SHIFT 4
+
+#define SCSIDATALATCH	0x22 /*   W */
+#define SCSIDATAIN	0x22 /* R   */
+#define SCSIDATAWITHACK	0x23 /* R/W */
+#define SCAMCONTROL	0x24 /*   W */
+#define SCAMSTATUS	0x24 /* R   */
+#define SCAMDATA	0x25 /* R/W */
+
+#define OTHERCONTROL	0x26 /* R/W */
+#  define TPL_ROM_WRITE_EN BIT(0)
+#  define TPWR_OUT         BIT(1)
+#  define TPWR_SENSE       BIT(2)
+#  define RA8_CONTROL      BIT(3)
+
+#define ACKWIDTH	0x27 /* R/W */
+#define CLRTESTPNT	0x28 /*   W */
+#define ACKCNTLD	0x29 /*   W */
+#define REQCNTLD	0x2A /*   W */
+#define HSTCNTLD	0x2B /*   W */
+#define CHECKSUM	0x2C /* R/W */
+
+/************************************************************************
+ * Input status bit definitions.
+ ************************************************************************/
+#define S_MESSAGE	BIT(0)    /* Message line from SCSI bus      */
+#define S_IO		BIT(1)    /* Input/Output line from SCSI bus */
+#define S_CD		BIT(2)    /* Command/Data line from SCSI bus */
+#define S_BUSY		BIT(3)    /* Busy line from SCSI bus         */
+#define S_ACK		BIT(4)    /* Acknowlege line from SCSI bus   */
+#define S_REQUEST	BIT(5)    /* Request line from SCSI bus      */
+#define S_SELECT	BIT(6)	  /*                                 */
+#define S_ATN		BIT(7)	  /*                                 */
+
+/***********************************************************************
+ * Useful Bus Monitor status combinations.
+ ***********************************************************************/
+#define BUSMON_SEL         S_SELECT
+#define BUSMON_BSY         S_BUSY
+#define BUSMON_REQ         S_REQUEST
+#define BUSMON_IO          S_IO
+#define BUSMON_ACK         S_ACK
+#define BUSMON_BUS_FREE    0
+#define BUSMON_COMMAND     ( S_BUSY | S_CD |                    S_REQUEST )
+#define BUSMON_MESSAGE_IN  ( S_BUSY | S_CD | S_IO | S_MESSAGE | S_REQUEST )
+#define BUSMON_MESSAGE_OUT ( S_BUSY | S_CD |        S_MESSAGE | S_REQUEST )
+#define BUSMON_DATA_IN     ( S_BUSY |        S_IO |             S_REQUEST )
+#define BUSMON_DATA_OUT    ( S_BUSY |                           S_REQUEST )
+#define BUSMON_STATUS      ( S_BUSY | S_CD | S_IO |             S_REQUEST )
+#define BUSMON_SELECT      (                 S_IO |                        S_SELECT )
+#define BUSMON_RESELECT    (                 S_IO |                        S_SELECT )
+#define BUSMON_PHASE_MASK  (          S_CD | S_IO | S_MESSAGE |            S_SELECT )
+
+#define BUSPHASE_SELECT      ( BUSMON_SELECT      & BUSMON_PHASE_MASK )
+#define BUSPHASE_COMMAND     ( BUSMON_COMMAND     & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_IN  ( BUSMON_MESSAGE_IN  & BUSMON_PHASE_MASK )
+#define BUSPHASE_MESSAGE_OUT ( BUSMON_MESSAGE_OUT & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_IN     ( BUSMON_DATA_IN     & BUSMON_PHASE_MASK )
+#define BUSPHASE_DATA_OUT    ( BUSMON_DATA_OUT    & BUSMON_PHASE_MASK )
+#define BUSPHASE_STATUS      ( BUSMON_STATUS      & BUSMON_PHASE_MASK )
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+	dev_link_t             link;
+	struct Scsi_Host      *host;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,74))
+	dev_node_t             node;
+#else
+	int	               ndev;
+	dev_node_t             node[8];
+	struct bus_operations *bus;
+#endif
+	int                    stop;
+} scsi_info_t;
+
+
+/* synchronous transfer negotiation data */
+typedef struct _sync_data {
+	unsigned int SyncNegotiation;
+#define SYNC_NOT_YET 0
+#define SYNC_OK      1
+#define SYNC_NG      2
+
+	unsigned int  SyncPeriod;
+	unsigned int  SyncOffset;
+	unsigned char SyncRegister;
+	unsigned char AckWidth;
+} sync_data;
+
+typedef struct _nsp_hw_data {
+	unsigned int  BaseAddress;
+	unsigned int  NumAddress;
+	unsigned int  IrqNumber;
+
+	unsigned long MmioAddress;
+#define NSP_MMIO_OFFSET 0x0800
+	unsigned long MmioLength;
+
+	unsigned char ScsiClockDiv;
+
+	unsigned char TransferMode;
+
+	int           TimerCount;
+	int           SelectionTimeOut;
+	Scsi_Cmnd    *CurrentSC;
+	//int           CurrnetTarget;
+
+	int           FifoCount;
+
+#define MSGBUF_SIZE 20
+	unsigned char MsgBuffer[MSGBUF_SIZE];
+	int MsgLen;
+
+#define N_TARGET 8
+	sync_data     Sync[N_TARGET];
+
+	char nspinfo[110];     /* description */
+	spinlock_t Lock;
+
+	scsi_info_t   *ScsiInfo; /* attach <-> detect glue */
+
+
+#ifdef NSP_DEBUG
+	int CmdId; /* Accepted command serial number.
+		      Used for debugging.             */
+#endif
+} nsp_hw_data;
+
+
+/****************************************************************************
+ *
+ */
+
+/* Card service functions */
+static dev_link_t *nsp_cs_attach (void);
+static void        nsp_cs_detach (dev_link_t *link);
+static void        nsp_cs_release(dev_link_t *link);
+static void        nsp_cs_config (dev_link_t *link);
+static int         nsp_cs_event  (event_t event, int priority, event_callback_args_t *args);
+
+/* Linux SCSI subsystem specific functions */
+static struct Scsi_Host *nsp_detect     (Scsi_Host_Template *sht);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
+static        int        nsp_detect_old (Scsi_Host_Template *sht);
+static        int        nsp_release_old(struct Scsi_Host *shpnt);
+#endif
+static const  char      *nsp_info       (struct Scsi_Host *shpnt);
+static        int        nsp_proc_info  (
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+	                                 struct Scsi_Host *host,
+#endif
+					 char   *buffer,
+					 char  **start,
+					 off_t   offset,
+					 int     length,
+#if !(LINUX_VERSION_CODE > KERNEL_VERSION(2,5,73))
+					 int     hostno,
+#endif
+					 int     inout);
+static        int        nsp_queuecommand(Scsi_Cmnd *SCpnt, void (* done)(Scsi_Cmnd *SCpnt));
+
+/* Error handler */
+/*static int nsp_eh_abort       (Scsi_Cmnd *SCpnt);*/
+/*static int nsp_eh_device_reset(Scsi_Cmnd *SCpnt);*/
+static int nsp_eh_bus_reset    (Scsi_Cmnd *SCpnt);
+static int nsp_eh_host_reset   (Scsi_Cmnd *SCpnt);
+static int nsp_bus_reset       (nsp_hw_data *data);
+
+/* */
+static int  nsphw_init           (nsp_hw_data *data);
+static int  nsphw_start_selection(Scsi_Cmnd *SCpnt);
+static void nsp_start_timer      (Scsi_Cmnd *SCpnt, int time);
+static int  nsp_fifo_count       (Scsi_Cmnd *SCpnt);
+static void nsp_pio_read         (Scsi_Cmnd *SCpnt);
+static void nsp_pio_write        (Scsi_Cmnd *SCpnt);
+static int  nsp_nexus            (Scsi_Cmnd *SCpnt);
+static void nsp_scsi_done        (Scsi_Cmnd *SCpnt);
+static int  nsp_analyze_sdtr     (Scsi_Cmnd *SCpnt);
+static int  nsp_negate_signal    (Scsi_Cmnd *SCpnt, unsigned char mask, char *str);
+static int  nsp_expect_signal    (Scsi_Cmnd *SCpnt, unsigned char current_phase, unsigned char  mask);
+static int  nsp_xfer             (Scsi_Cmnd *SCpnt, int phase);
+static int  nsp_dataphase_bypass (Scsi_Cmnd *SCpnt);
+static int  nsp_reselected       (Scsi_Cmnd *SCpnt);
+static struct Scsi_Host *nsp_detect(Scsi_Host_Template *sht);
+
+/* Interrupt handler */
+//static irqreturn_t nspintr(int irq, void *dev_id, struct pt_regs *regs);
+
+/* Module entry point*/
+static int  __init nsp_cs_init(void);
+static void __exit nsp_cs_exit(void);
+
+
+/* Debug */
+#ifdef NSP_DEBUG
+static void show_command (Scsi_Cmnd *SCpnt);
+static void show_phase   (Scsi_Cmnd *SCpnt);
+static void show_busphase(unsigned char stat);
+static void show_message (nsp_hw_data *data);
+#else
+# define show_command(ptr)   /* */
+# define show_phase(SCpnt)   /* */
+# define show_busphase(stat) /* */
+# define show_message(data)  /* */
+#endif
+
+/*
+ * SCSI phase
+ */
+enum _scsi_phase {
+	PH_UNDETERMINED ,
+	PH_ARBSTART     ,
+	PH_SELSTART     ,
+	PH_SELECTED     ,
+	PH_COMMAND      ,
+	PH_DATA         ,
+	PH_STATUS       ,
+	PH_MSG_IN       ,
+	PH_MSG_OUT      ,
+	PH_DISCONNECT   ,
+	PH_RESELECT     ,
+	PH_ABORT        ,
+	PH_RESET
+};
+
+enum _data_in_out {
+	IO_UNKNOWN,
+	IO_IN,
+	IO_OUT
+};
+
+enum _burst_mode {
+	BURST_IO8   = 0,
+	BURST_IO32  = 1,
+	BURST_MEM32 = 2,
+};
+
+
+/**************************************************************************
+ * SCSI messaage
+ */
+#define MSG_COMMAND_COMPLETE 0x00
+#define MSG_EXTENDED         0x01
+#define MSG_ABORT            0x06
+#define MSG_NO_OPERATION     0x08
+#define MSG_BUS_DEVICE_RESET 0x0c
+
+#define MSG_EXT_SDTR         0x01
+
+
+/**************************************************************************
+ * Compatibility functions
+ */
+
+/* for Kernel 2.4 */
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0))
+#  define scsi_register_host(template)   scsi_register_module(MODULE_SCSI_HA, template)
+#  define scsi_unregister_host(template) scsi_unregister_module(MODULE_SCSI_HA, template)
+#  define scsi_host_put(host)            scsi_unregister(host)
+
+typedef void irqreturn_t;
+#  define IRQ_NONE      /* */
+#  define IRQ_HANDLED   /* */
+#  define IRQ_RETVAL(x) /* */
+
+/* This is ad-hoc version of scsi_host_get_next() */
+static inline struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *host)
+{
+	if (host == NULL) {
+		return scsi_hostlist;
+	} else {
+		return host->next;
+	}
+}
+
+/* This is ad-hoc version of scsi_host_hn_get() */
+static inline struct Scsi_Host *scsi_host_hn_get(unsigned short hostno)
+{
+	struct Scsi_Host *host;
+
+	for (host = scsi_host_get_next(NULL); host != NULL;
+	     host = scsi_host_get_next(host)) {
+		if (host->host_no == hostno) {
+			break;
+		}
+	}
+
+	return host;
+}
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	pcmcia_report_error(handle, &err);
+}
+
+/* scatter-gather table */
+#  define BUFFER_ADDR (SCpnt->SCp.buffer->address)
+#endif
+
+/* for Kernel 2.6 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0))
+/* scatter-gather table */
+#  define BUFFER_ADDR ((char *)((unsigned int)(SCpnt->SCp.buffer->page) + SCpnt->SCp.buffer->offset))
+#endif
+
+#endif  /*__nsp_cs__*/
+/* end */
diff --git a/drivers/scsi/pcmcia/nsp_debug.c b/drivers/scsi/pcmcia/nsp_debug.c
new file mode 100644
index 0000000..62e5c60
--- /dev/null
+++ b/drivers/scsi/pcmcia/nsp_debug.c
@@ -0,0 +1,215 @@
+/*========================================================================
+    Debug routines for nsp_cs
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+    This software may be used and distributed according to the terms of
+    the GNU General Public License.
+=========================================================================*/
+
+/* $Id: nsp_debug.c,v 1.3 2003/07/26 14:21:09 elca Exp $ */
+
+/*
+ * Show the command data of a command
+ */
+static const char unknown[] = "UNKNOWN";
+
+static const char * group_0_commands[] = {
+/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense",
+/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks",
+/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown,
+/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry",  
+/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve",
+/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit",
+/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", 
+/* 1e-1f */ "Prevent/Allow Medium Removal", unknown,
+};
+
+
+static const char *group_1_commands[] = {
+/* 20-22 */  unknown, unknown, unknown,
+/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)",
+/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown,
+/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
+/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", 
+/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long",  "Write Long",
+};
+
+
+static const char *group_2_commands[] = {
+/* 40-41 */ "Change Definition", "Write Same", 
+/* 42-48 */ "Read Sub-Ch(cd)", "Read TOC", "Read Header(cd)", "Play Audio(cd)", unknown, "Play Audio MSF(cd)", "Play Audio Track/Index(cd)", 
+/* 49-4f */ "Play Track Relative(10)(cd)", unknown, "Pause/Resume(cd)", "Log Select", "Log Sense", unknown, unknown,
+/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
+/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
+/* 5c-5f */ unknown, unknown, unknown,
+};
+
+#define group(opcode) (((opcode) >> 5) & 7)
+
+#define RESERVED_GROUP  0
+#define VENDOR_GROUP    1
+#define NOTEXT_GROUP    2
+
+static const char **commands[] = {
+    group_0_commands, group_1_commands, group_2_commands, 
+    (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, 
+    (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP, 
+    (const char **) VENDOR_GROUP
+};
+
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
+
+static void print_opcodek(unsigned char opcode)
+{
+	const char **table = commands[ group(opcode) ];
+
+	switch ((unsigned long) table) {
+	case RESERVED_GROUP:
+		printk("%s[%02x] ", reserved, opcode); 
+		break;
+	case NOTEXT_GROUP:
+		printk("%s(notext)[%02x] ", unknown, opcode); 
+		break;
+	case VENDOR_GROUP:
+		printk("%s[%02x] ", vendor, opcode); 
+		break;
+	default:
+		if (table[opcode & 0x1f] != unknown)
+			printk("%s[%02x] ", table[opcode & 0x1f], opcode);
+		else
+			printk("%s[%02x] ", unknown, opcode);
+		break;
+	}
+}
+
+static void print_commandk (unsigned char *command)
+{
+	int i, s;
+	printk(KERN_DEBUG);
+	print_opcodek(command[0]);
+	/*printk(KERN_DEBUG "%s ", __FUNCTION__);*/
+	if ((command[0] >> 5) == 6 ||
+	    (command[0] >> 5) == 7 ) {
+		s = 12; /* vender specific */
+	} else {
+		s = COMMAND_SIZE(command[0]);
+	}
+	for ( i = 1; i < s; ++i) {
+		printk("%02x ", command[i]);
+	}
+
+	switch (s) {
+	case 6:
+		printk("LBA=%d len=%d",
+		       (((unsigned int)command[1] & 0x0f) << 16) |
+		       ( (unsigned int)command[2]         <<  8) |
+		       ( (unsigned int)command[3]              ),
+		       (unsigned int)command[4]
+			);
+		break;
+	case 10:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[7] <<  8) |
+		       ((unsigned int)command[8]      )
+		       );
+		break;
+	case 12:
+		printk("LBA=%d len=%d",
+		       ((unsigned int)command[2] << 24) |
+		       ((unsigned int)command[3] << 16) |
+		       ((unsigned int)command[4] <<  8) |
+		       ((unsigned int)command[5]      ),
+		       ((unsigned int)command[6] << 24) |
+		       ((unsigned int)command[7] << 16) |
+		       ((unsigned int)command[8] <<  8) |
+		       ((unsigned int)command[9]      )
+		       );
+		break;
+	default:
+		break;
+	}
+	printk("\n");
+}
+
+static void show_command(Scsi_Cmnd *SCpnt)
+{
+	print_commandk(SCpnt->cmnd);
+}
+
+static void show_phase(Scsi_Cmnd *SCpnt)
+{
+	int i = SCpnt->SCp.phase;
+
+	char *ph[] = {
+		"PH_UNDETERMINED",
+		"PH_ARBSTART",
+		"PH_SELSTART",
+		"PH_SELECTED",
+		"PH_COMMAND",
+		"PH_DATA",
+		"PH_STATUS",
+		"PH_MSG_IN",
+		"PH_MSG_OUT",
+		"PH_DISCONNECT",
+		"PH_RESELECT"
+	};
+
+	if ( i < PH_UNDETERMINED || i > PH_RESELECT ) {
+		printk(KERN_DEBUG "scsi phase: unknown(%d)\n", i);
+		return;
+	}
+
+	printk(KERN_DEBUG "scsi phase: %s\n", ph[i]);
+
+	return;
+}
+
+static void show_busphase(unsigned char stat)
+{
+	switch(stat) {
+	case BUSPHASE_COMMAND:
+		printk(KERN_DEBUG "BUSPHASE_COMMAND\n");
+		break;
+	case BUSPHASE_MESSAGE_IN:
+		printk(KERN_DEBUG "BUSPHASE_MESSAGE_IN\n");
+		break;
+	case BUSPHASE_MESSAGE_OUT:
+		printk(KERN_DEBUG "BUSPHASE_MESSAGE_OUT\n");
+		break;
+	case BUSPHASE_DATA_IN:
+		printk(KERN_DEBUG "BUSPHASE_DATA_IN\n");
+		break;
+	case BUSPHASE_DATA_OUT:
+		printk(KERN_DEBUG "BUSPHASE_DATA_OUT\n");
+		break;
+	case BUSPHASE_STATUS:
+		printk(KERN_DEBUG "BUSPHASE_STATUS\n");
+		break;
+	case BUSPHASE_SELECT:
+		printk(KERN_DEBUG "BUSPHASE_SELECT\n");
+		break;
+	default:
+		printk(KERN_DEBUG "BUSPHASE_other\n");
+		break;
+	}
+}
+
+static void show_message(nsp_hw_data *data)
+{
+	int i;
+
+	printk(KERN_DEBUG "msg:");
+	for(i=0; i < data->MsgLen; i++) {
+		printk(" %02x", data->MsgBuffer[i]);
+	}
+	printk("\n");
+}
+
+/* end */
diff --git a/drivers/scsi/pcmcia/nsp_io.h b/drivers/scsi/pcmcia/nsp_io.h
new file mode 100644
index 0000000..3b8746f
--- /dev/null
+++ b/drivers/scsi/pcmcia/nsp_io.h
@@ -0,0 +1,274 @@
+/*
+  NinjaSCSI I/O funtions 
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+ 
+  This software may be used and distributed according to the terms of
+  the GNU General Public License.
+
+  */
+
+/* $Id: nsp_io.h,v 1.3 2003/08/04 21:15:26 elca Exp $ */
+
+#ifndef __NSP_IO_H__
+#define __NSP_IO_H__
+
+static inline          void nsp_write(unsigned int base,
+				      unsigned int index,
+				      unsigned char val);
+static inline unsigned char nsp_read(unsigned int base,
+				     unsigned int index);
+static inline          void nsp_index_write(unsigned int BaseAddr,
+					    unsigned int Register,
+					    unsigned char Value);
+static inline unsigned char nsp_index_read(unsigned int BaseAddr,
+					   unsigned int Register);
+
+/*******************************************************************
+ * Basic IO
+ */
+
+static inline void nsp_write(unsigned int  base,
+			     unsigned int  index,
+			     unsigned char val)
+{
+	outb(val, (base + index));
+}
+
+static inline unsigned char nsp_read(unsigned int base,
+				     unsigned int index)
+{
+	return inb(base + index);
+}
+
+
+/**********************************************************************
+ * Indexed IO
+ */
+static inline unsigned char nsp_index_read(unsigned int BaseAddr,
+					   unsigned int Register)
+{
+	outb(Register, BaseAddr + INDEXREG);
+	return inb(BaseAddr + DATAREG);
+}
+
+static inline void nsp_index_write(unsigned int  BaseAddr,
+				   unsigned int  Register,
+				   unsigned char Value)
+{
+	outb(Register, BaseAddr + INDEXREG);
+	outb(Value, BaseAddr + DATAREG);
+}
+
+/*********************************************************************
+ * fifo func
+ */
+
+/* read 8 bit FIFO */
+static inline void nsp_multi_read_1(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insb(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo8_read(unsigned int   base,
+				  void          *buf,
+				  unsigned long  count)
+{
+	/*nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx", buf, count);*/
+	nsp_multi_read_1(base, FIFODATA, buf, count);
+}
+
+/*--------------------------------------------------------------*/
+
+/* read 16 bit FIFO */
+static inline void nsp_multi_read_2(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insw(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo16_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*2", buf, count);
+	nsp_multi_read_2(base, FIFODATA, buf, count);
+}
+
+/*--------------------------------------------------------------*/
+
+/* read 32bit FIFO */
+static inline void nsp_multi_read_4(unsigned int   BaseAddr,
+				    unsigned int   Register,
+				    void          *buf,
+				    unsigned long  count)
+{
+	insl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo32_read(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count);
+	nsp_multi_read_4(base, FIFODATA, buf, count);
+}
+
+/*----------------------------------------------------------*/
+
+/* write 8bit FIFO */
+static inline void nsp_multi_write_1(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsb(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo8_write(unsigned int   base,
+				   void          *buf,
+				   unsigned long  count)
+{
+	nsp_multi_write_1(base, FIFODATA, buf, count);
+}
+
+/*---------------------------------------------------------*/
+
+/* write 16bit FIFO */
+static inline void nsp_multi_write_2(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsw(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo16_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp_multi_write_2(base, FIFODATA, buf, count);
+}
+
+/*---------------------------------------------------------*/
+
+/* write 32bit FIFO */
+static inline void nsp_multi_write_4(unsigned int   BaseAddr,
+				     unsigned int   Register,
+				     void          *buf,
+				     unsigned long  count)
+{
+	outsl(BaseAddr + Register, buf, count);
+}
+
+static inline void nsp_fifo32_write(unsigned int   base,
+				    void          *buf,
+				    unsigned long  count)
+{
+	nsp_multi_write_4(base, FIFODATA, buf, count);
+}
+
+
+/*====================================================================*/
+
+static inline void nsp_mmio_write(unsigned long base,
+				  unsigned int  index,
+				  unsigned char val)
+{
+	unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index);
+
+	writeb(val, ptr);
+}
+
+static inline unsigned char nsp_mmio_read(unsigned long base,
+					  unsigned int  index)
+{
+	unsigned char *ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + index);
+
+	return readb(ptr);
+}
+
+/*-----------*/
+
+static inline unsigned char nsp_mmio_index_read(unsigned long base,
+						unsigned int  reg)
+{
+	unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG);
+	unsigned char *data_ptr  = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG);
+
+	writeb((unsigned char)reg, index_ptr);
+	return readb(data_ptr);
+}
+
+static inline void nsp_mmio_index_write(unsigned long base,
+					unsigned int  reg,
+					unsigned char val)
+{
+	unsigned char *index_ptr = (unsigned char *)(base + NSP_MMIO_OFFSET + INDEXREG);
+	unsigned char *data_ptr  = (unsigned char *)(base + NSP_MMIO_OFFSET + DATAREG);
+
+	writeb((unsigned char)reg, index_ptr);
+	writeb(val,                data_ptr);
+}
+
+/* read 32bit FIFO */
+static inline void nsp_mmio_multi_read_4(unsigned long  base,
+					 unsigned int   Register,
+					 void          *buf,
+					 unsigned long  count)
+{
+	unsigned long *ptr = (unsigned long *)(base + Register);
+	unsigned long *tmp = (unsigned long *)buf;
+	int i;
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr);
+
+	for (i = 0; i < count; i++) {
+		*tmp = readl(ptr);
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp);
+		tmp++;
+	}
+}
+
+static inline void nsp_mmio_fifo32_read(unsigned int   base,
+					void          *buf,
+					unsigned long  count)
+{
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count);
+	nsp_mmio_multi_read_4(base, FIFODATA, buf, count);
+}
+
+static inline void nsp_mmio_multi_write_4(unsigned long  base,
+					  unsigned int   Register,
+					  void          *buf,
+					  unsigned long  count)
+{
+	unsigned long *ptr = (unsigned long *)(base + Register);
+	unsigned long *tmp = (unsigned long *)buf;
+	int i;
+
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "base 0x%0lx ptr 0x%p",base,ptr);
+
+	for (i = 0; i < count; i++) {
+		writel(*tmp, ptr);
+		//nsp_dbg(NSP_DEBUG_DATA_IO, "<%d,%p,%p,%lx>", i, ptr, tmp, *tmp);
+		tmp++;
+	}
+}
+
+static inline void nsp_mmio_fifo32_write(unsigned int   base,
+					 void          *buf,
+					 unsigned long  count)
+{
+	//nsp_dbg(NSP_DEBUG_DATA_IO, "buf=0x%p, count=0x%lx*4", buf, count);
+	nsp_mmio_multi_write_4(base, FIFODATA, buf, count);
+}
+
+
+
+#endif
+/* end */
diff --git a/drivers/scsi/pcmcia/nsp_message.c b/drivers/scsi/pcmcia/nsp_message.c
new file mode 100644
index 0000000..d705773
--- /dev/null
+++ b/drivers/scsi/pcmcia/nsp_message.c
@@ -0,0 +1,78 @@
+/*==========================================================================
+  NinjaSCSI-3 message handler
+      By: YOKOTA Hiroshi <yokota@netlab.is.tsukuba.ac.jp>
+
+   This software may be used and distributed according to the terms of
+   the GNU General Public License.
+ */
+
+/* $Id: nsp_message.c,v 1.6 2003/07/26 14:21:09 elca Exp $ */
+
+static void nsp_message_in(Scsi_Cmnd *SCpnt)
+{
+	unsigned int  base = SCpnt->device->host->io_port;
+	nsp_hw_data  *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	unsigned char data_reg, control_reg;
+	int           ret, len;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg in" if exists (no scsi phase changes).
+	 */
+	ret = 16;
+	len = 0;
+
+	nsp_dbg(NSP_DEBUG_MSGINOCCUR, "msgin loop");
+	do {
+		/* read data */
+		data_reg = nsp_index_read(base, SCSIDATAIN);
+
+		/* assert ACK */
+		control_reg = nsp_index_read(base, SCSIBUSCTRL);
+		control_reg |= SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+		nsp_negate_signal(SCpnt, BUSMON_REQ, "msgin<REQ>");
+
+		data->MsgBuffer[len] = data_reg; len++;
+
+		/* deassert ACK */
+		control_reg =  nsp_index_read(base, SCSIBUSCTRL);
+		control_reg &= ~SCSI_ACK;
+		nsp_index_write(base, SCSIBUSCTRL, control_reg);
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_IN, BUSMON_REQ);
+	} while (ret > 0 && MSGBUF_SIZE > len);
+
+	data->MsgLen = len;
+
+}
+
+static void nsp_message_out(Scsi_Cmnd *SCpnt)
+{
+	nsp_hw_data *data = (nsp_hw_data *)SCpnt->device->host->hostdata;
+	int ret = 1;
+	int len = data->MsgLen;
+
+	/*
+	 * XXX: NSP QUIRK
+	 * NSP invoke interrupts only in the case of scsi phase changes,
+	 * therefore we should poll the scsi phase here to catch 
+	 * the next "msg out" if exists (no scsi phase changes).
+	 */
+
+	nsp_dbg(NSP_DEBUG_MSGOUTOCCUR, "msgout loop");
+	do {
+		if (nsp_xfer(SCpnt, BUSPHASE_MESSAGE_OUT)) {
+			nsp_msg(KERN_DEBUG, "msgout: xfer short");
+		}
+
+		/* catch a next signal */
+		ret = nsp_expect_signal(SCpnt, BUSPHASE_MESSAGE_OUT, BUSMON_REQ);
+	} while (ret > 0 && len-- > 0);
+
+}
+
+/* end */
diff --git a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
new file mode 100644
index 0000000..4766bcd
--- /dev/null
+++ b/drivers/scsi/pcmcia/qlogic_stub.c
@@ -0,0 +1,425 @@
+/*======================================================================
+
+    A driver for the Qlogic SCSI card
+
+    qlogic_cs.c 1.79 2000/06/12 21:27:26
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in which
+    case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blkdev.h>
+#include <scsi/scsi_ioctl.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "../qlogicfas408.h"
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+/* Set the following to 2 to use normal interrupt (active high/totempole-
+ * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
+ * drain
+ */
+#define INT_TYPE	0
+
+static char qlogic_name[] = "qlogic_cs";
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0644);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version = "qlogic_cs.c 1.79-ac 2002/10/26 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+static Scsi_Host_Template qlogicfas_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= qlogic_name,
+	.proc_name		= qlogic_name,
+	.info			= qlogicfas408_info,
+	.queuecommand		= qlogicfas408_queuecommand,
+	.eh_abort_handler	= qlogicfas408_abort,
+	.eh_bus_reset_handler	= qlogicfas408_bus_reset,
+	.eh_device_reset_handler= qlogicfas408_device_reset,
+	.eh_host_reset_handler	= qlogicfas408_host_reset,
+	.bios_param		= qlogicfas408_biosparam,
+	.can_queue		= 1,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+	dev_link_t link;
+	dev_node_t node;
+	struct Scsi_Host *host;
+	unsigned short manf_id;
+} scsi_info_t;
+
+static void qlogic_release(dev_link_t *link);
+static int qlogic_event(event_t event, int priority, event_callback_args_t * args);
+
+static dev_link_t *qlogic_attach(void);
+static void qlogic_detach(dev_link_t *);
+
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "qlogic_cs";
+
+static struct Scsi_Host *qlogic_detect(Scsi_Host_Template *host,
+				dev_link_t *link, int qbase, int qlirq)
+{
+	int qltyp;		/* type of chip */
+	int qinitid;
+	struct Scsi_Host *shost;	/* registered host structure */
+	struct qlogicfas408_priv *priv;
+
+	qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
+	qinitid = host->this_id;
+	if (qinitid < 0)
+		qinitid = 7;	/* if no ID, use 7 */
+
+	qlogicfas408_setup(qbase, qinitid, INT_TYPE);
+
+	host->name = qlogic_name;
+	shost = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
+	if (!shost)
+		goto err;
+	shost->io_port = qbase;
+	shost->n_io_port = 16;
+	shost->dma_channel = -1;
+	if (qlirq != -1)
+		shost->irq = qlirq;
+
+	priv = get_priv_by_host(shost);
+	priv->qlirq = qlirq;
+	priv->qbase = qbase;
+	priv->qinitid = qinitid;
+	priv->shost = shost;
+	priv->int_type = INT_TYPE;					
+
+	if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogic_name, shost))
+		goto free_scsi_host;
+
+	sprintf(priv->qinfo,
+		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
+		qltyp, qbase, qlirq, QL_TURBO_PDMA);
+
+	if (scsi_add_host(shost, NULL))
+		goto free_interrupt;
+
+	scsi_scan_host(shost);
+
+	return shost;
+
+free_interrupt:
+	free_irq(qlirq, shost);
+
+free_scsi_host:
+	scsi_host_put(shost);
+	
+err:
+	return NULL;
+}
+static dev_link_t *qlogic_attach(void)
+{
+	scsi_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int ret;
+
+	DEBUG(0, "qlogic_attach()\n");
+
+	/* Create new SCSI device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+	link = &info->link;
+	link->priv = info;
+	link->io.NumPorts1 = 16;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.IOAddrLines = 10;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.event_handler = &qlogic_event;
+	client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET | CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		qlogic_detach(link);
+		return NULL;
+	}
+
+	return link;
+}				/* qlogic_attach */
+
+/*====================================================================*/
+
+static void qlogic_detach(dev_link_t * link)
+{
+	dev_link_t **linkp;
+
+	DEBUG(0, "qlogic_detach(0x%p)\n", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+	if (*linkp == NULL)
+		return;
+
+	if (link->state & DEV_CONFIG)
+		qlogic_release(link);
+
+	if (link->handle)
+		pcmcia_deregister_client(link->handle);
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+	kfree(link->priv);
+
+}				/* qlogic_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void qlogic_config(dev_link_t * link)
+{
+	client_handle_t handle = link->handle;
+	scsi_info_t *info = link->priv;
+	tuple_t tuple;
+	cisparse_t parse;
+	int i, last_ret, last_fn;
+	unsigned short tuple_data[32];
+	struct Scsi_Host *host;
+
+	DEBUG(0, "qlogic_config(0x%p)\n", link);
+
+	tuple.TupleData = (cisdata_t *) tuple_data;
+	tuple.TupleDataMax = 64;
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	link->conf.ConfigBase = parse.config.base;
+
+	tuple.DesiredTuple = CISTPL_MANFID;
+	if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) && (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
+		info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	while (1) {
+		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+				pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+			goto next_entry;
+		link->conf.ConfigIndex = parse.cftable_entry.index;
+		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+		if (link->io.BasePort1 != 0) {
+			i = pcmcia_request_io(handle, &link->io);
+			if (i == CS_SUCCESS)
+				break;
+		}
+	      next_entry:
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	}
+
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+
+	if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
+		/* set ATAcmd */
+		outb(0xb4, link->io.BasePort1 + 0xd);
+		outb(0x24, link->io.BasePort1 + 0x9);
+		outb(0x04, link->io.BasePort1 + 0xd);
+	}
+
+	/* The KXL-810AN has a bigger IO port window */
+	if (link->io.NumPorts1 == 32)
+		host = qlogic_detect(&qlogicfas_driver_template, link,
+			link->io.BasePort1 + 16, link->irq.AssignedIRQ);
+	else
+		host = qlogic_detect(&qlogicfas_driver_template, link,
+			link->io.BasePort1, link->irq.AssignedIRQ);
+	
+	if (!host) {
+		printk(KERN_INFO "%s: no SCSI devices found\n", qlogic_name);
+		goto out;
+	}
+
+	sprintf(info->node.dev_name, "scsi%d", host->host_no);
+	link->dev = &info->node;
+	info->host = host;
+
+out:
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	link->dev = NULL;
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+	return;
+
+}				/* qlogic_config */
+
+/*====================================================================*/
+
+static void qlogic_release(dev_link_t *link)
+{
+	scsi_info_t *info = link->priv;
+
+	DEBUG(0, "qlogic_release(0x%p)\n", link);
+
+	scsi_remove_host(info->host);
+	link->dev = NULL;
+
+	free_irq(link->irq.AssignedIRQ, info->host);
+
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+
+	scsi_host_put(info->host);
+
+	link->state &= ~DEV_CONFIG;
+}
+
+/*====================================================================*/
+
+static int qlogic_event(event_t event, int priority, event_callback_args_t * args)
+{
+	dev_link_t *link = args->client_data;
+
+	DEBUG(1, "qlogic_event(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG)
+			qlogic_release(link);
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		qlogic_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			pcmcia_release_configuration(link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			scsi_info_t *info = link->priv;
+			pcmcia_request_configuration(link->handle, &link->conf);
+			if ((info->manf_id == MANFID_MACNICA) || (info->manf_id == MANFID_PIONEER) || (info->manf_id == 0x0098)) {
+				outb(0x80, link->io.BasePort1 + 0xd);
+				outb(0x24, link->io.BasePort1 + 0x9);
+				outb(0x04, link->io.BasePort1 + 0xd);
+			}
+			/* Ugggglllyyyy!!! */
+			qlogicfas408_bus_reset(NULL);
+		}
+		break;
+	}
+	return 0;
+}				/* qlogic_event */
+
+
+static struct pcmcia_driver qlogic_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+	.name		= "qlogic_cs",
+	},
+	.attach		= qlogic_attach,
+	.detach		= qlogic_detach,
+};
+
+static int __init init_qlogic_cs(void)
+{
+	return pcmcia_register_driver(&qlogic_cs_driver);
+}
+
+static void __exit exit_qlogic_cs(void)
+{
+	pcmcia_unregister_driver(&qlogic_cs_driver);
+	BUG_ON(dev_list != NULL);
+}
+
+MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
+MODULE_DESCRIPTION("Driver for the PCMCIA Qlogic FAS SCSI controllers");
+MODULE_LICENSE("GPL");
+module_init(init_qlogic_cs);
+module_exit(exit_qlogic_cs);
diff --git a/drivers/scsi/pcmcia/sym53c500_cs.c b/drivers/scsi/pcmcia/sym53c500_cs.c
new file mode 100644
index 0000000..8457d0d
--- /dev/null
+++ b/drivers/scsi/pcmcia/sym53c500_cs.c
@@ -0,0 +1,1022 @@
+/*
+*  sym53c500_cs.c	Bob Tracy (rct@frus.com)
+*
+*  A rewrite of the pcmcia-cs add-on driver for newer (circa 1997)
+*  New Media Bus Toaster PCMCIA SCSI cards using the Symbios Logic
+*  53c500 controller: intended for use with 2.6 and later kernels.
+*  The pcmcia-cs add-on version of this driver is not supported
+*  beyond 2.4.  It consisted of three files with history/copyright
+*  information as follows:
+*
+*  SYM53C500.h
+*	Bob Tracy (rct@frus.com)
+*	Original by Tom Corner (tcorner@via.at).
+*	Adapted from NCR53c406a.h which is Copyrighted (C) 1994
+*	Normunds Saumanis (normunds@rx.tech.swh.lv)
+*
+*  SYM53C500.c
+*	Bob Tracy (rct@frus.com)
+*	Original driver by Tom Corner (tcorner@via.at) was adapted
+*	from NCR53c406a.c which is Copyrighted (C) 1994, 1995, 1996 
+*	Normunds Saumanis (normunds@fi.ibm.com)
+*
+*  sym53c500.c
+*	Bob Tracy (rct@frus.com)
+*	Original by Tom Corner (tcorner@via.at) was adapted from a
+*	driver for the Qlogic SCSI card written by
+*	David Hinds (dhinds@allegro.stanford.edu).
+* 
+*  This program is free software; you can redistribute it and/or modify it
+*  under the terms of the GNU General Public License as published by the
+*  Free Software Foundation; either version 2, or (at your option) any
+*  later version.
+*
+*  This program is distributed in the hope that it will be useful, but
+*  WITHOUT ANY WARRANTY; without even the implied warranty of
+*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+*  General Public License for more details.
+*/
+
+#define SYM53C500_DEBUG 0
+#define VERBOSE_SYM53C500_DEBUG 0
+
+/*
+*  Set this to 0 if you encounter kernel lockups while transferring 
+*  data in PIO mode.  Note this can be changed via "sysfs".
+*/
+#define USE_FAST_PIO 1
+
+/* =============== End of user configurable parameters ============== */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/blkdev.h>
+#include <linux/spinlock.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+/* ================================================================== */
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+module_param(pc_debug, int, 0);
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"sym53c500_cs.c 0.9c 2004/10/27 (Bob Tracy)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* ================================================================== */
+
+#define SYNC_MODE 0 		/* Synchronous transfer mode */
+
+/* Default configuration */
+#define C1_IMG   0x07		/* ID=7 */
+#define C2_IMG   0x48		/* FE SCSI2 */
+#define C3_IMG   0x20		/* CDB */
+#define C4_IMG   0x04		/* ANE */
+#define C5_IMG   0xa4		/* ? changed from b6= AA PI SIE POL */
+#define C7_IMG   0x80		/* added for SYM53C500 t. corner */
+
+/* Hardware Registers: offsets from io_port (base) */
+
+/* Control Register Set 0 */
+#define TC_LSB		0x00		/* transfer counter lsb */
+#define TC_MSB		0x01		/* transfer counter msb */
+#define SCSI_FIFO	0x02		/* scsi fifo register */
+#define CMD_REG		0x03		/* command register */
+#define STAT_REG	0x04		/* status register */
+#define DEST_ID		0x04		/* selection/reselection bus id */
+#define INT_REG		0x05		/* interrupt status register */
+#define SRTIMOUT	0x05		/* select/reselect timeout reg */
+#define SEQ_REG		0x06		/* sequence step register */
+#define SYNCPRD		0x06		/* synchronous transfer period */
+#define FIFO_FLAGS	0x07		/* indicates # of bytes in fifo */
+#define SYNCOFF		0x07		/* synchronous offset register */
+#define CONFIG1		0x08		/* configuration register */
+#define CLKCONV		0x09		/* clock conversion register */
+/* #define TESTREG	0x0A */		/* test mode register */
+#define CONFIG2		0x0B		/* configuration 2 register */
+#define CONFIG3		0x0C		/* configuration 3 register */
+#define CONFIG4		0x0D		/* configuration 4 register */
+#define TC_HIGH		0x0E		/* transfer counter high */
+/* #define FIFO_BOTTOM	0x0F */		/* reserve FIFO byte register */
+
+/* Control Register Set 1 */
+/* #define JUMPER_SENSE	0x00 */		/* jumper sense port reg (r/w) */
+/* #define SRAM_PTR	0x01 */		/* SRAM address pointer reg (r/w) */
+/* #define SRAM_DATA	0x02 */		/* SRAM data register (r/w) */
+#define PIO_FIFO	0x04		/* PIO FIFO registers (r/w) */
+/* #define PIO_FIFO1	0x05 */		/*  */
+/* #define PIO_FIFO2	0x06 */		/*  */
+/* #define PIO_FIFO3	0x07 */		/*  */
+#define PIO_STATUS	0x08		/* PIO status (r/w) */
+/* #define ATA_CMD	0x09 */		/* ATA command/status reg (r/w) */
+/* #define ATA_ERR	0x0A */		/* ATA features/error reg (r/w) */
+#define PIO_FLAG	0x0B		/* PIO flag interrupt enable (r/w) */
+#define CONFIG5		0x09		/* configuration 5 register */
+/* #define SIGNATURE	0x0E */		/* signature register (r) */
+/* #define CONFIG6	0x0F */		/* configuration 6 register (r) */
+#define CONFIG7		0x0d
+
+/* select register set 0 */
+#define REG0(x)		(outb(C4_IMG, (x) + CONFIG4))
+/* select register set 1 */
+#define REG1(x)		outb(C7_IMG, (x) + CONFIG7); outb(C5_IMG, (x) + CONFIG5)
+
+#if SYM53C500_DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+#if VERBOSE_SYM53C500_DEBUG
+#define VDEB(x) x
+#else
+#define VDEB(x)
+#endif
+
+#define LOAD_DMA_COUNT(x, count) \
+  outb(count & 0xff, (x) + TC_LSB); \
+  outb((count >> 8) & 0xff, (x) + TC_MSB); \
+  outb((count >> 16) & 0xff, (x) + TC_HIGH);
+
+/* Chip commands */
+#define DMA_OP               0x80
+
+#define SCSI_NOP             0x00
+#define FLUSH_FIFO           0x01
+#define CHIP_RESET           0x02
+#define SCSI_RESET           0x03
+#define RESELECT             0x40
+#define SELECT_NO_ATN        0x41
+#define SELECT_ATN           0x42
+#define SELECT_ATN_STOP      0x43
+#define ENABLE_SEL           0x44
+#define DISABLE_SEL          0x45
+#define SELECT_ATN3          0x46
+#define RESELECT3            0x47
+#define TRANSFER_INFO        0x10
+#define INIT_CMD_COMPLETE    0x11
+#define MSG_ACCEPT           0x12
+#define TRANSFER_PAD         0x18
+#define SET_ATN              0x1a
+#define RESET_ATN            0x1b
+#define SEND_MSG             0x20
+#define SEND_STATUS          0x21
+#define SEND_DATA            0x22
+#define DISCONN_SEQ          0x23
+#define TERMINATE_SEQ        0x24
+#define TARG_CMD_COMPLETE    0x25
+#define DISCONN              0x27
+#define RECV_MSG             0x28
+#define RECV_CMD             0x29
+#define RECV_DATA            0x2a
+#define RECV_CMD_SEQ         0x2b
+#define TARGET_ABORT_DMA     0x04
+
+/* ================================================================== */
+
+struct scsi_info_t {
+	dev_link_t link;
+	dev_node_t node;
+	struct Scsi_Host *host;
+	unsigned short manf_id;
+};
+
+/*
+*  Repository for per-instance host data.
+*/
+struct sym53c500_data {
+	struct scsi_cmnd *current_SC;
+	int fast_pio;
+};
+
+enum Phase {
+    idle,
+    data_out,
+    data_in,
+    command_ph,
+    status_ph,
+    message_out,
+    message_in
+};
+
+/* ================================================================== */
+
+/*
+*  Global (within this module) variables other than
+*  sym53c500_driver_template (the scsi_host_template).
+*/
+static dev_link_t *dev_list;
+static dev_info_t dev_info = "sym53c500_cs";
+
+/* ================================================================== */
+
+static void
+chip_init(int io_port)
+{
+	REG1(io_port);
+	outb(0x01, io_port + PIO_STATUS);
+	outb(0x00, io_port + PIO_FLAG);
+
+	outb(C4_IMG, io_port + CONFIG4);	/* REG0(io_port); */
+	outb(C3_IMG, io_port + CONFIG3);
+	outb(C2_IMG, io_port + CONFIG2);
+	outb(C1_IMG, io_port + CONFIG1);
+
+	outb(0x05, io_port + CLKCONV);	/* clock conversion factor */
+	outb(0x9C, io_port + SRTIMOUT);	/* Selection timeout */
+	outb(0x05, io_port + SYNCPRD);	/* Synchronous transfer period */
+	outb(SYNC_MODE, io_port + SYNCOFF);	/* synchronous mode */  
+}
+
+static void
+SYM53C500_int_host_reset(int io_port)
+{
+	outb(C4_IMG, io_port + CONFIG4);	/* REG0(io_port); */
+	outb(CHIP_RESET, io_port + CMD_REG);
+	outb(SCSI_NOP, io_port + CMD_REG);	/* required after reset */
+	outb(SCSI_RESET, io_port + CMD_REG);
+	chip_init(io_port);
+}
+
+static __inline__ int
+SYM53C500_pio_read(int fast_pio, int base, unsigned char *request, unsigned int reqlen)
+{
+	int i;
+	int len;	/* current scsi fifo size */
+
+	REG1(base);
+	while (reqlen) {
+		i = inb(base + PIO_STATUS);
+		/* VDEB(printk("pio_status=%x\n", i)); */
+		if (i & 0x80) 
+			return 0;
+
+		switch (i & 0x1e) {
+		default:
+		case 0x10:	/* fifo empty */
+			len = 0;
+			break;
+		case 0x0:
+			len = 1;
+			break; 
+		case 0x8:	/* fifo 1/3 full */
+			len = 42;
+			break;
+		case 0xc:	/* fifo 2/3 full */
+			len = 84;
+			break;
+		case 0xe:	/* fifo full */
+			len = 128;
+			break;
+		}
+
+		if ((i & 0x40) && len == 0) { /* fifo empty and interrupt occurred */
+			return 0;
+		}
+
+		if (len) {
+			if (len > reqlen) 
+				len = reqlen;
+
+			if (fast_pio && len > 3) {
+				insl(base + PIO_FIFO, request, len >> 2);
+				request += len & 0xfc; 
+				reqlen -= len & 0xfc; 
+			} else {
+				while (len--) {
+					*request++ = inb(base + PIO_FIFO);
+					reqlen--;
+				}
+			} 
+		}
+	}
+	return 0;
+}
+
+static __inline__ int
+SYM53C500_pio_write(int fast_pio, int base, unsigned char *request, unsigned int reqlen)
+{
+	int i = 0;
+	int len;	/* current scsi fifo size */
+
+	REG1(base);
+	while (reqlen && !(i & 0x40)) {
+		i = inb(base + PIO_STATUS);
+		/* VDEB(printk("pio_status=%x\n", i)); */
+		if (i & 0x80)	/* error */
+			return 0;
+
+		switch (i & 0x1e) {
+		case 0x10:
+			len = 128;
+			break;
+		case 0x0:
+			len = 84;
+			break;
+		case 0x8:
+			len = 42;
+			break;
+		case 0xc:
+			len = 1;
+			break;
+		default:
+		case 0xe:
+			len = 0;
+			break;
+		}
+
+		if (len) {
+			if (len > reqlen)
+				len = reqlen;
+
+			if (fast_pio && len > 3) {
+				outsl(base + PIO_FIFO, request, len >> 2);
+				request += len & 0xfc;
+				reqlen -= len & 0xfc;
+			} else {
+				while (len--) {
+					outb(*request++, base + PIO_FIFO);
+					reqlen--;
+				}
+			}
+		}
+	}
+	return 0;
+}
+
+static irqreturn_t
+SYM53C500_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+	DEB(unsigned char fifo_size;)
+	DEB(unsigned char seq_reg;)
+	unsigned char status, int_reg;
+	unsigned char pio_status;
+	struct scatterlist *sglist;
+	unsigned int sgcount;
+	int port_base = dev->io_port;
+	struct sym53c500_data *data =
+	    (struct sym53c500_data *)dev->hostdata;
+	struct scsi_cmnd *curSC = data->current_SC;
+	int fast_pio = data->fast_pio;
+
+	spin_lock_irqsave(dev->host_lock, flags);
+
+	VDEB(printk("SYM53C500_intr called\n"));
+
+	REG1(port_base);
+	pio_status = inb(port_base + PIO_STATUS);
+	REG0(port_base);
+	status = inb(port_base + STAT_REG);
+	DEB(seq_reg = inb(port_base + SEQ_REG));
+	int_reg = inb(port_base + INT_REG);
+	DEB(fifo_size = inb(port_base + FIFO_FLAGS) & 0x1f);
+
+#if SYM53C500_DEBUG
+	printk("status=%02x, seq_reg=%02x, int_reg=%02x, fifo_size=%02x", 
+	    status, seq_reg, int_reg, fifo_size);
+	printk(", pio=%02x\n", pio_status);
+#endif /* SYM53C500_DEBUG */
+
+	if (int_reg & 0x80) {	/* SCSI reset intr */
+		DEB(printk("SYM53C500: reset intr received\n"));
+		curSC->result = DID_RESET << 16;
+		goto idle_out;
+	}
+
+	if (pio_status & 0x80) {
+		printk("SYM53C500: Warning: PIO error!\n");
+		curSC->result = DID_ERROR << 16;
+		goto idle_out;
+	}
+
+	if (status & 0x20) {		/* Parity error */
+		printk("SYM53C500: Warning: parity error!\n");
+		curSC->result = DID_PARITY << 16;
+		goto idle_out;
+	}
+
+	if (status & 0x40) {		/* Gross error */
+		printk("SYM53C500: Warning: gross error!\n");
+		curSC->result = DID_ERROR << 16;
+		goto idle_out;
+	}
+
+	if (int_reg & 0x20) {		/* Disconnect */
+		DEB(printk("SYM53C500: disconnect intr received\n"));
+		if (curSC->SCp.phase != message_in) {	/* Unexpected disconnect */
+			curSC->result = DID_NO_CONNECT << 16;
+		} else {	/* Command complete, return status and message */
+			curSC->result = (curSC->SCp.Status & 0xff)
+			    | ((curSC->SCp.Message & 0xff) << 8) | (DID_OK << 16);
+		}
+		goto idle_out;
+	}
+
+	switch (status & 0x07) {	/* scsi phase */
+	case 0x00:			/* DATA-OUT */
+		if (int_reg & 0x10) {	/* Target requesting info transfer */
+			curSC->SCp.phase = data_out;
+			VDEB(printk("SYM53C500: Data-Out phase\n"));
+			outb(FLUSH_FIFO, port_base + CMD_REG);
+			LOAD_DMA_COUNT(port_base, curSC->request_bufflen);	/* Max transfer size */
+			outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
+			if (!curSC->use_sg)	/* Don't use scatter-gather */
+				SYM53C500_pio_write(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
+			else {	/* use scatter-gather */
+				sgcount = curSC->use_sg;
+				sglist = curSC->request_buffer;
+				while (sgcount--) {
+					SYM53C500_pio_write(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
+					sglist++;
+				}
+			}
+			REG0(port_base);
+		}
+		break;
+
+	case 0x01:		/* DATA-IN */
+		if (int_reg & 0x10) {	/* Target requesting info transfer */
+			curSC->SCp.phase = data_in;
+			VDEB(printk("SYM53C500: Data-In phase\n"));
+			outb(FLUSH_FIFO, port_base + CMD_REG);
+			LOAD_DMA_COUNT(port_base, curSC->request_bufflen);	/* Max transfer size */
+			outb(TRANSFER_INFO | DMA_OP, port_base + CMD_REG);
+			if (!curSC->use_sg)	/* Don't use scatter-gather */
+				SYM53C500_pio_read(fast_pio, port_base, curSC->request_buffer, curSC->request_bufflen);
+			else {	/* Use scatter-gather */
+				sgcount = curSC->use_sg;
+				sglist = curSC->request_buffer;
+				while (sgcount--) {
+					SYM53C500_pio_read(fast_pio, port_base, page_address(sglist->page) + sglist->offset, sglist->length);
+					sglist++;
+				}
+			}
+			REG0(port_base);
+		}
+		break;
+
+	case 0x02:		/* COMMAND */
+		curSC->SCp.phase = command_ph;
+		printk("SYM53C500: Warning: Unknown interrupt occurred in command phase!\n");
+		break;
+
+	case 0x03:		/* STATUS */
+		curSC->SCp.phase = status_ph;
+		VDEB(printk("SYM53C500: Status phase\n"));
+		outb(FLUSH_FIFO, port_base + CMD_REG);
+		outb(INIT_CMD_COMPLETE, port_base + CMD_REG);
+		break;
+
+	case 0x04:		/* Reserved */
+	case 0x05:		/* Reserved */
+		printk("SYM53C500: WARNING: Reserved phase!!!\n");
+		break;
+
+	case 0x06:		/* MESSAGE-OUT */
+		DEB(printk("SYM53C500: Message-Out phase\n"));
+		curSC->SCp.phase = message_out;
+		outb(SET_ATN, port_base + CMD_REG);	/* Reject the message */
+		outb(MSG_ACCEPT, port_base + CMD_REG);
+		break;
+
+	case 0x07:		/* MESSAGE-IN */
+		VDEB(printk("SYM53C500: Message-In phase\n"));
+		curSC->SCp.phase = message_in;
+
+		curSC->SCp.Status = inb(port_base + SCSI_FIFO);
+		curSC->SCp.Message = inb(port_base + SCSI_FIFO);
+
+		VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f));
+		DEB(printk("Status = %02x  Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message));
+
+		if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) {
+			outb(SET_ATN, port_base + CMD_REG);	/* Reject message */
+			DEB(printk("Discarding SAVE_POINTERS message\n"));
+		}
+		outb(MSG_ACCEPT, port_base + CMD_REG);
+		break;
+	}
+out:
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+
+idle_out:
+	curSC->SCp.phase = idle;
+	curSC->scsi_done(curSC);
+	goto out;
+}
+
+static void
+SYM53C500_release(dev_link_t *link)
+{
+	struct scsi_info_t *info = link->priv;
+	struct Scsi_Host *shost = info->host;
+
+	DEBUG(0, "SYM53C500_release(0x%p)\n", link);
+
+	/*
+	*  Do this before releasing/freeing resources.
+	*/
+	scsi_remove_host(shost);
+
+	/*
+	*  Interrupts getting hosed on card removal.  Try
+	*  the following code, mostly from qlogicfas.c.
+	*/
+	if (shost->irq)
+		free_irq(shost->irq, shost);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+
+	link->dev = NULL;
+
+	pcmcia_release_configuration(link->handle);
+	pcmcia_release_io(link->handle, &link->io);
+	pcmcia_release_irq(link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+
+	scsi_host_put(shost);
+} /* SYM53C500_release */
+
+static const char*
+SYM53C500_info(struct Scsi_Host *SChost)
+{
+	static char info_msg[256];
+	struct sym53c500_data *data =
+	    (struct sym53c500_data *)SChost->hostdata;
+
+	DEB(printk("SYM53C500_info called\n"));
+	(void)snprintf(info_msg, sizeof(info_msg),
+	    "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", 
+	    SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow");
+	return (info_msg);
+}
+
+static int 
+SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
+{
+	int i;
+	int port_base = SCpnt->device->host->io_port;
+	struct sym53c500_data *data =
+	    (struct sym53c500_data *)SCpnt->device->host->hostdata;
+
+	VDEB(printk("SYM53C500_queue called\n"));
+
+	DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", 
+	    SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, 
+	    SCpnt->device->lun,  SCpnt->request_bufflen));
+
+	VDEB(for (i = 0; i < SCpnt->cmd_len; i++)
+	    printk("cmd[%d]=%02x  ", i, SCpnt->cmnd[i]));
+	VDEB(printk("\n"));
+
+	data->current_SC = SCpnt;
+	data->current_SC->scsi_done = done;
+	data->current_SC->SCp.phase = command_ph;
+	data->current_SC->SCp.Status = 0;
+	data->current_SC->SCp.Message = 0;
+
+	/* We are locked here already by the mid layer */
+	REG0(port_base);
+	outb(SCpnt->device->id, port_base + DEST_ID);	/* set destination */
+	outb(FLUSH_FIFO, port_base + CMD_REG);	/* reset the fifos */
+
+	for (i = 0; i < SCpnt->cmd_len; i++) {
+		outb(SCpnt->cmnd[i], port_base + SCSI_FIFO);
+	}
+	outb(SELECT_NO_ATN, port_base + CMD_REG);
+
+	return 0;
+}
+
+static int 
+SYM53C500_host_reset(struct scsi_cmnd *SCpnt)
+{
+	int port_base = SCpnt->device->host->io_port;
+
+	DEB(printk("SYM53C500_host_reset called\n"));
+	SYM53C500_int_host_reset(port_base);
+
+	return SUCCESS;
+}
+
+static int 
+SYM53C500_biosparm(struct scsi_device *disk,
+    struct block_device *dev,
+    sector_t capacity, int *info_array)
+{
+	int size;
+
+	DEB(printk("SYM53C500_biosparm called\n"));
+
+	size = capacity;
+	info_array[0] = 64;		/* heads */
+	info_array[1] = 32;		/* sectors */
+	info_array[2] = size >> 11;	/* cylinders */
+	if (info_array[2] > 1024) {	/* big disk */
+		info_array[0] = 255;
+		info_array[1] = 63;
+		info_array[2] = size / (255 * 63);
+	}
+	return 0;
+}
+
+static ssize_t
+SYM53C500_show_pio(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *SHp = class_to_shost(cdev);
+	struct sym53c500_data *data =
+	    (struct sym53c500_data *)SHp->hostdata;
+
+	return snprintf(buf, 4, "%d\n", data->fast_pio);
+}
+
+static ssize_t
+SYM53C500_store_pio(struct class_device *cdev, const char *buf, size_t count)
+{
+	int pio;
+	struct Scsi_Host *SHp = class_to_shost(cdev);
+	struct sym53c500_data *data =
+	    (struct sym53c500_data *)SHp->hostdata;
+
+	pio = simple_strtoul(buf, NULL, 0);
+	if (pio == 0 || pio == 1) {
+		data->fast_pio = pio;
+		return count;
+	}
+	else
+		return -EINVAL;
+}
+
+/*
+*  SCSI HBA device attributes we want to
+*  make available via sysfs.
+*/
+static struct class_device_attribute SYM53C500_pio_attr = {
+	.attr = {
+		.name = "fast_pio",
+		.mode = (S_IRUGO | S_IWUSR),
+	},
+	.show = SYM53C500_show_pio,
+	.store = SYM53C500_store_pio,
+};
+
+static struct class_device_attribute *SYM53C500_shost_attrs[] = {
+	&SYM53C500_pio_attr,
+	NULL,
+};
+
+/*
+*  scsi_host_template initializer
+*/
+static struct scsi_host_template sym53c500_driver_template = {
+     .module			= THIS_MODULE,
+     .name			= "SYM53C500",
+     .info			= SYM53C500_info,
+     .queuecommand		= SYM53C500_queue,
+     .eh_host_reset_handler	= SYM53C500_host_reset,
+     .bios_param		= SYM53C500_biosparm,
+     .proc_name			= "SYM53C500",
+     .can_queue			= 1,
+     .this_id			= 7,
+     .sg_tablesize		= 32,
+     .cmd_per_lun		= 1,
+     .use_clustering		= ENABLE_CLUSTERING,
+     .shost_attrs		= SYM53C500_shost_attrs
+};
+
+#define CS_CHECK(fn, ret) \
+do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
+
+static void
+SYM53C500_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	struct scsi_info_t *info = link->priv;
+	tuple_t tuple;
+	cisparse_t parse;
+	int i, last_ret, last_fn;
+	int irq_level, port_base;
+	unsigned short tuple_data[32];
+	struct Scsi_Host *host;
+	struct scsi_host_template *tpnt = &sym53c500_driver_template;
+	struct sym53c500_data *data;
+
+	DEBUG(0, "SYM53C500_config(0x%p)\n", link);
+
+	tuple.TupleData = (cisdata_t *)tuple_data;
+	tuple.TupleDataMax = 64;
+	tuple.TupleOffset = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));
+	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));
+	link->conf.ConfigBase = parse.config.base;
+
+	tuple.DesiredTuple = CISTPL_MANFID;
+	if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&
+	    (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))
+		info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));
+	while (1) {
+		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||
+		    pcmcia_parse_tuple(handle, &tuple, &parse) != 0)
+			goto next_entry;
+		link->conf.ConfigIndex = parse.cftable_entry.index;
+		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+
+		if (link->io.BasePort1 != 0) {
+			i = pcmcia_request_io(handle, &link->io);
+			if (i == CS_SUCCESS)
+				break;
+		}
+next_entry:
+		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));
+	}
+
+	CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));
+	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));
+
+	/*
+	*  That's the trouble with copying liberally from another driver.
+	*  Some things probably aren't relevant, and I suspect this entire
+	*  section dealing with manufacturer IDs can be scrapped.	--rct
+	*/
+	if ((info->manf_id == MANFID_MACNICA) ||
+	    (info->manf_id == MANFID_PIONEER) ||
+	    (info->manf_id == 0x0098)) {
+		/* set ATAcmd */
+		outb(0xb4, link->io.BasePort1 + 0xd);
+		outb(0x24, link->io.BasePort1 + 0x9);
+		outb(0x04, link->io.BasePort1 + 0xd);
+	}
+
+	/*
+	*  irq_level == 0 implies tpnt->can_queue == 0, which
+	*  is not supported in 2.6.  Thus, only irq_level > 0
+	*  will be allowed.
+	*
+	*  Possible port_base values are as follows:
+	*
+	*	0x130, 0x230, 0x280, 0x290,
+	*	0x320, 0x330, 0x340, 0x350
+	*/
+	port_base = link->io.BasePort1;
+	irq_level = link->irq.AssignedIRQ;
+
+	DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n",
+	    port_base, irq_level, USE_FAST_PIO);)
+
+	chip_init(port_base);
+
+	host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data));
+	if (!host) {
+		printk("SYM53C500: Unable to register host, giving up.\n");
+		goto err_release;
+	}
+
+	data = (struct sym53c500_data *)host->hostdata;
+
+	if (irq_level > 0) {
+		if (request_irq(irq_level, SYM53C500_intr, SA_SHIRQ, "SYM53C500", host)) {
+			printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);
+			goto err_free_scsi;
+		}
+		DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level));
+	} else if (irq_level == 0) {
+		DEB(printk("SYM53C500: No interrupts detected\n"));
+		goto err_free_scsi;
+	} else {
+		DEB(printk("SYM53C500: Shouldn't get here!\n"));
+		goto err_free_scsi;
+	}
+
+	host->unique_id = port_base;
+	host->irq = irq_level;
+	host->io_port = port_base;
+	host->n_io_port = 0x10;
+	host->dma_channel = -1;
+
+	/*
+	*  Note fast_pio is set to USE_FAST_PIO by
+	*  default, but can be changed via "sysfs".
+	*/
+	data->fast_pio = USE_FAST_PIO;
+
+	sprintf(info->node.dev_name, "scsi%d", host->host_no);
+	link->dev = &info->node;
+	info->host = host;
+
+	if (scsi_add_host(host, NULL))
+		goto err_free_irq;
+
+	scsi_scan_host(host);
+
+	goto out;	/* SUCCESS */
+
+err_free_irq:
+	free_irq(irq_level, host);
+err_free_scsi:
+	scsi_host_put(host);
+err_release:
+	release_region(port_base, 0x10);
+	printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n");
+
+out:
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	SYM53C500_release(link);
+	return;
+} /* SYM53C500_config */
+
+static int
+SYM53C500_event(event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	struct scsi_info_t *info = link->priv;
+
+	DEBUG(1, "SYM53C500_event(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG)
+			SYM53C500_release(link);
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		SYM53C500_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG)
+			pcmcia_release_configuration(link->handle);
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			pcmcia_request_configuration(link->handle, &link->conf);
+			/* See earlier comment about manufacturer IDs. */
+			if ((info->manf_id == MANFID_MACNICA) ||
+			    (info->manf_id == MANFID_PIONEER) ||
+			    (info->manf_id == 0x0098)) {
+				outb(0x80, link->io.BasePort1 + 0xd);
+				outb(0x24, link->io.BasePort1 + 0x9);
+				outb(0x04, link->io.BasePort1 + 0xd);
+			}
+			/*
+			*  If things don't work after a "resume",
+			*  this is a good place to start looking.
+			*/
+			SYM53C500_int_host_reset(link->io.BasePort1);
+		}
+		break;
+	}
+	return 0;
+} /* SYM53C500_event */
+
+static void
+SYM53C500_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+
+	DEBUG(0, "SYM53C500_detach(0x%p)\n", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link)
+			break;
+	if (*linkp == NULL)
+		return;
+
+	if (link->state & DEV_CONFIG)
+		SYM53C500_release(link);
+
+	if (link->handle)
+		pcmcia_deregister_client(link->handle);
+
+	/* Unlink device structure, free bits. */
+	*linkp = link->next;
+	kfree(link->priv);
+	link->priv = NULL;
+} /* SYM53C500_detach */
+
+static dev_link_t *
+SYM53C500_attach(void)
+{
+	struct scsi_info_t *info;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	int ret;
+
+	DEBUG(0, "SYM53C500_attach()\n");
+
+	/* Create new SCSI device */
+	info = kmalloc(sizeof(*info), GFP_KERNEL);
+	if (!info)
+		return NULL;
+	memset(info, 0, sizeof(*info));
+	link = &info->link;
+	link->priv = info;
+	link->io.NumPorts1 = 16;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	link->io.IOAddrLines = 10;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_LEVEL_ID;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.event_handler = &SYM53C500_event;
+	client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |
+	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+	ret = pcmcia_register_client(&link->handle, &client_reg);
+	if (ret != 0) {
+		cs_error(link->handle, RegisterClient, ret);
+		SYM53C500_detach(link);
+		return NULL;
+	}
+
+	return link;
+} /* SYM53C500_attach */
+
+MODULE_AUTHOR("Bob Tracy <rct@frus.com>");
+MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");
+MODULE_LICENSE("GPL");
+
+static struct pcmcia_driver sym53c500_cs_driver = {
+	.owner		= THIS_MODULE,
+	.drv		= {
+		.name	= "sym53c500_cs",
+	},
+	.attach		= SYM53C500_attach,
+	.detach		= SYM53C500_detach,
+};
+
+static int __init
+init_sym53c500_cs(void)
+{
+	return pcmcia_register_driver(&sym53c500_cs_driver);
+}
+
+static void __exit
+exit_sym53c500_cs(void)
+{
+	pcmcia_unregister_driver(&sym53c500_cs_driver);
+}
+
+module_init(init_sym53c500_cs);
+module_exit(exit_sym53c500_cs);
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
new file mode 100644
index 0000000..7bb0a2e
--- /dev/null
+++ b/drivers/scsi/pluto.c
@@ -0,0 +1,364 @@
+/* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
+ *
+ * Copyright (C) 1997,1998,1999 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/config.h>
+#ifdef CONFIG_KMOD
+#include <linux/kmod.h>
+#endif
+
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "../fc4/fcp_impl.h"
+#include "pluto.h"
+
+#include <linux/module.h>
+
+/* #define PLUTO_DEBUG */
+
+#define pluto_printk printk ("PLUTO %s: ", fc->name); printk
+
+#ifdef PLUTO_DEBUG
+#define PLD(x)  pluto_printk x;
+#define PLND(x) printk ("PLUTO: "); printk x;
+#else
+#define PLD(x)
+#define PLND(x)
+#endif
+
+static struct ctrl_inquiry {
+	struct Scsi_Host host;
+	struct pluto pluto;
+	Scsi_Cmnd cmd;
+	char inquiry[256];
+	fc_channel *fc;
+} *fcs __initdata = { 0 };
+static int fcscount __initdata = 0;
+static atomic_t fcss __initdata = ATOMIC_INIT(0);
+DECLARE_MUTEX_LOCKED(fc_sem);
+
+static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd);
+
+static void __init pluto_detect_timeout(unsigned long data)
+{
+	PLND(("Timeout\n"))
+	up(&fc_sem);
+}
+
+static void __init pluto_detect_done(Scsi_Cmnd *SCpnt)
+{
+	/* Do nothing */
+}
+
+static void __init pluto_detect_scsi_done(Scsi_Cmnd *SCpnt)
+{
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
+	PLND(("Detect done %08lx\n", (long)SCpnt))
+	if (atomic_dec_and_test (&fcss))
+		up(&fc_sem);
+}
+
+int pluto_slave_configure(Scsi_Device *device)
+{
+	int depth_to_use;
+
+	if (device->tagged_supported)
+		depth_to_use = /* 254 */ 8;
+	else
+		depth_to_use = 2;
+
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+
+	return 0;
+}
+
+/* Detect all SSAs attached to the machine.
+   To be fast, do it on all online FC channels at the same time. */
+int __init pluto_detect(Scsi_Host_Template *tpnt)
+{
+	int i, retry, nplutos;
+	fc_channel *fc;
+	Scsi_Device dev;
+	struct timer_list fc_timer =
+		TIMER_INITIALIZER(pluto_detect_timeout, 0, 0);
+
+	tpnt->proc_name = "pluto";
+	fcscount = 0;
+	for_each_online_fc_channel(fc) {
+		if (!fc->posmap)
+			fcscount++;
+	}
+	PLND(("%d channels online\n", fcscount))
+	if (!fcscount) {
+#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD)
+		request_module("soc");
+		
+		for_each_online_fc_channel(fc) {
+			if (!fc->posmap)
+				fcscount++;
+		}
+		if (!fcscount)
+#endif
+			return 0;
+	}
+	fcs = (struct ctrl_inquiry *) kmalloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
+	if (!fcs) {
+		printk ("PLUTO: Not enough memory to probe\n");
+		return 0;
+	}
+	
+	memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
+	memset (&dev, 0, sizeof(dev));
+	atomic_set (&fcss, fcscount);
+	
+	i = 0;
+	for_each_online_fc_channel(fc) {
+		Scsi_Cmnd *SCpnt;
+		struct Scsi_Host *host;
+		struct pluto *pluto;
+
+		if (i == fcscount) break;
+		if (fc->posmap) continue;
+		
+		PLD(("trying to find SSA\n"))
+
+		/* If this is already registered to some other SCSI host, then it cannot be pluto */
+		if (fc->scsi_name[0]) continue;
+		memcpy (fc->scsi_name, "SSA", 4);
+		
+		fcs[i].fc = fc;
+		
+		fc->can_queue = PLUTO_CAN_QUEUE;
+		fc->rsp_size = 64;
+		fc->encode_addr = pluto_encode_addr;
+		
+		fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
+	
+		SCpnt = &(fcs[i].cmd);
+		host = &(fcs[i].host);
+		pluto = (struct pluto *)host->hostdata;
+		
+		pluto->fc = fc;
+	
+		SCpnt->cmnd[0] = INQUIRY;
+		SCpnt->cmnd[4] = 255;
+		
+		/* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */
+		SCpnt->device = &dev;
+		dev.host = host;
+		
+		SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
+	
+		SCpnt->request->rq_status = RQ_SCSI_BUSY;
+		
+		SCpnt->done = pluto_detect_done;
+		SCpnt->bufflen = 256;
+		SCpnt->buffer = fcs[i].inquiry;
+		SCpnt->request_bufflen = 256;
+		SCpnt->request_buffer = fcs[i].inquiry;
+		PLD(("set up %d %08lx\n", i, (long)SCpnt))
+		i++;
+	}
+	
+	for (retry = 0; retry < 5; retry++) {
+		for (i = 0; i < fcscount; i++) {
+			if (!fcs[i].fc) break;
+			if (fcs[i].cmd.request->rq_status != RQ_SCSI_DONE) {
+				disable_irq(fcs[i].fc->irq);
+				PLND(("queuecommand %d %d\n", retry, i))
+				fcp_scsi_queuecommand (&(fcs[i].cmd), 
+					pluto_detect_scsi_done);
+				enable_irq(fcs[i].fc->irq);
+			}
+		}
+	    
+		fc_timer.expires = jiffies + 10 * HZ;
+		add_timer(&fc_timer);
+		
+		down(&fc_sem);
+		PLND(("Woken up\n"))
+		if (!atomic_read(&fcss))
+			break; /* All fc channels have answered us */
+	}
+	del_timer_sync(&fc_timer);
+
+	PLND(("Finished search\n"))
+	for (i = 0, nplutos = 0; i < fcscount; i++) {
+		Scsi_Cmnd *SCpnt;
+		
+		if (!(fc = fcs[i].fc)) break;
+	
+		SCpnt = &(fcs[i].cmd);
+		
+		/* Let FC mid-level free allocated resources */
+		SCpnt->done (SCpnt);
+		
+		if (!SCpnt->result) {
+			struct pluto_inquiry *inq;
+			struct pluto *pluto;
+			struct Scsi_Host *host;
+			
+			inq = (struct pluto_inquiry *)fcs[i].inquiry;
+
+			if ((inq->dtype & 0x1f) == TYPE_PROCESSOR &&
+			    !strncmp (inq->vendor_id, "SUN", 3) &&
+			    !strncmp (inq->product_id, "SSA", 3)) {
+				char *p;
+				long *ages;
+				
+				ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
+				if (!ages) continue;
+				
+				host = scsi_register (tpnt, sizeof (struct pluto));
+				if(!host)
+				{
+					kfree(ages);
+					continue;
+				}
+				
+				if (!try_module_get(fc->module)) {
+					kfree(ages);
+					scsi_unregister(host);
+					continue;
+				}
+
+				nplutos++;
+				
+				pluto = (struct pluto *)host->hostdata;
+				
+				host->max_id = inq->targets;
+				host->max_channel = inq->channels;
+				host->irq = fc->irq;
+
+				fc->channels = inq->channels + 1;
+				fc->targets = inq->targets;
+				fc->ages = ages;
+				memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
+				
+				pluto->fc = fc;
+				memcpy (pluto->rev_str, inq->revision, 4);
+				pluto->rev_str[4] = 0;
+				p = strchr (pluto->rev_str, ' ');
+				if (p) *p = 0;
+				memcpy (pluto->fw_rev_str, inq->fw_revision, 4);
+				pluto->fw_rev_str[4] = 0;
+				p = strchr (pluto->fw_rev_str, ' ');
+				if (p) *p = 0;
+				memcpy (pluto->serial_str, inq->serial, 12);
+				pluto->serial_str[12] = 0;
+				p = strchr (pluto->serial_str, ' ');
+				if (p) *p = 0;
+				
+				PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id))
+			} else
+				fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+		} else
+			fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+	}
+	kfree((char *)fcs);
+	if (nplutos)
+		printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
+	return nplutos;
+}
+
+int pluto_release(struct Scsi_Host *host)
+{
+	struct pluto *pluto = (struct pluto *)host->hostdata;
+	fc_channel *fc = pluto->fc;
+
+	module_put(fc->module);
+	
+	fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+	PLND((" releasing pluto.\n"));
+	kfree (fc->ages);
+	PLND(("released pluto!\n"));
+	return 0;
+}
+
+const char *pluto_info(struct Scsi_Host *host)
+{
+	static char buf[128], *p;
+	struct pluto *pluto = (struct pluto *) host->hostdata;
+
+	sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s",
+		pluto->rev_str, pluto->fw_rev_str, pluto->serial_str,
+		host->max_channel, host->max_id, pluto->fc->name);
+#ifdef __sparc__
+	p = strchr(buf, 0);
+	sprintf(p, " PROM node %x", pluto->fc->dev->prom_node);
+#endif	
+	return buf;
+}
+
+/* SSA uses this FC4S addressing:
+   switch (addr[0])
+   {
+   case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0
+   case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0
+   case 2: DISK GROUP - ???
+   }
+   
+   So that SCSI mid-layer can access to these, we reserve
+   channel 0 id 0 lun 0 for CONTROLLER
+   and channels 1 .. max_channel are normal single disks.
+ */
+static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr, fc_channel *fc, fcp_cmnd *fcmd)
+{
+	PLND(("encode addr %d %d %d\n", SCpnt->device->channel, SCpnt->device->id, SCpnt->cmnd[1] & 0xe0))
+	/* We don't support LUNs - neither does SSA :) */
+	if (SCpnt->cmnd[1] & 0xe0)
+		return -EINVAL;
+	if (!SCpnt->device->channel) {
+		if (SCpnt->device->id)
+			return -EINVAL;
+		memset (addr, 0, 4 * sizeof(u16));
+	} else {
+		addr[0] = 1;
+		addr[1] = SCpnt->device->channel - 1;
+		addr[2] = SCpnt->device->id;
+		addr[3] = 0;
+	}
+	/* We're Point-to-Point, so target it to the default DID */
+	fcmd->did = fc->did;
+	PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3]))
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.name			= "Sparc Storage Array 100/200",
+	.detect			= pluto_detect,
+	.release		= pluto_release,
+	.info			= pluto_info,
+	.queuecommand		= fcp_scsi_queuecommand,
+	.slave_configure	= pluto_slave_configure,
+	.can_queue		= PLUTO_CAN_QUEUE,
+	.this_id		= -1,
+	.sg_tablesize		= 1,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.eh_abort_handler	= fcp_scsi_abort,
+	.eh_device_reset_handler = fcp_scsi_dev_reset,
+	.eh_bus_reset_handler	= fcp_scsi_bus_reset,
+	.eh_host_reset_handler	= fcp_scsi_host_reset,
+};
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
new file mode 100644
index 0000000..beb844a
--- /dev/null
+++ b/drivers/scsi/pluto.h
@@ -0,0 +1,47 @@
+/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef _PLUTO_H
+#define _PLUTO_H
+
+#include "../fc4/fcp_impl.h"
+
+struct pluto {
+	/* This must be first */
+	fc_channel	*fc;
+	char		rev_str[5];
+	char		fw_rev_str[5];
+	char		serial_str[13];
+};
+
+struct pluto_inquiry {
+	u8	dtype;
+	u8	removable:1, qualifier:7;
+	u8	iso:2, ecma:3, ansi:3;
+	u8	aenc:1, trmiop:1, :2, rdf:4;
+	u8	len;
+	u8	xxx1;
+	u8	xxx2;
+	u8	reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1;
+	u8	vendor_id[8];
+	u8	product_id[16];
+	u8	revision[4];
+	u8	fw_revision[4];
+	u8	serial[12];
+	u8	xxx3[2];
+	u8	channels;
+	u8	targets;
+};
+
+/* This is the max number of outstanding SCSI commands per pluto */
+#define PLUTO_CAN_QUEUE		254
+
+int pluto_detect(Scsi_Host_Template *);
+int pluto_release(struct Scsi_Host *);
+const char * pluto_info(struct Scsi_Host *);
+int pluto_slave_configure(Scsi_Device *);
+
+#endif /* !(_PLUTO_H) */
+
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
new file mode 100644
index 0000000..96b4522
--- /dev/null
+++ b/drivers/scsi/ppa.c
@@ -0,0 +1,1150 @@
+/* ppa.c   --  low level driver for the IOMEGA PPA3 
+ * parallel port SCSI host adapter.
+ * 
+ * (The PPA3 is the embedded controller in the ZIP drive.)
+ * 
+ * (c) 1995,1996 Grant R. Guenther, grant@torque.net,
+ * under the terms of the GNU General Public License.
+ * 
+ * Current Maintainer: David Campbell (Perth, Western Australia, GMT+0800)
+ *                     campbell@torque.net
+ */
+
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/parport.h>
+#include <linux/workqueue.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+
+static void ppa_reset_pulse(unsigned int base);
+
+typedef struct {
+	struct pardevice *dev;	/* Parport device entry         */
+	int base;		/* Actual port address          */
+	int mode;		/* Transfer mode                */
+	struct scsi_cmnd *cur_cmd;	/* Current queued command       */
+	struct work_struct ppa_tq;	/* Polling interrupt stuff       */
+	unsigned long jstart;	/* Jiffies at start             */
+	unsigned long recon_tmo;	/* How many usecs to wait for reconnection (6th bit) */
+	unsigned int failed:1;	/* Failure flag                 */
+	unsigned wanted:1;	/* Parport sharing busy flag    */
+	wait_queue_head_t *waiting;
+	struct Scsi_Host *host;
+	struct list_head list;
+} ppa_struct;
+
+#include  "ppa.h"
+
+static inline ppa_struct *ppa_dev(struct Scsi_Host *host)
+{
+	return *(ppa_struct **)&host->hostdata;
+}
+
+static DEFINE_SPINLOCK(arbitration_lock);
+
+static void got_it(ppa_struct *dev)
+{
+	dev->base = dev->dev->port->base;
+	if (dev->cur_cmd)
+		dev->cur_cmd->SCp.phase = 1;
+	else
+		wake_up(dev->waiting);
+}
+
+static void ppa_wakeup(void *ref)
+{
+	ppa_struct *dev = (ppa_struct *) ref;
+	unsigned long flags;
+
+	spin_lock_irqsave(&arbitration_lock, flags);
+	if (dev->wanted) {
+		parport_claim(dev->dev);
+		got_it(dev);
+		dev->wanted = 0;
+	}
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+	return;
+}
+
+static int ppa_pb_claim(ppa_struct *dev)
+{
+	unsigned long flags;
+	int res = 1;
+	spin_lock_irqsave(&arbitration_lock, flags);
+	if (parport_claim(dev->dev) == 0) {
+		got_it(dev);
+		res = 0;
+	}
+	dev->wanted = res;
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+	return res;
+}
+
+static void ppa_pb_dismiss(ppa_struct *dev)
+{
+	unsigned long flags;
+	int wanted;
+	spin_lock_irqsave(&arbitration_lock, flags);
+	wanted = dev->wanted;
+	dev->wanted = 0;
+	spin_unlock_irqrestore(&arbitration_lock, flags);
+	if (!wanted)
+		parport_release(dev->dev);
+}
+
+static inline void ppa_pb_release(ppa_struct *dev)
+{
+	parport_release(dev->dev);
+}
+
+/*
+ * Start of Chipset kludges
+ */
+
+/* This is to give the ppa driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/ppa/0 file.
+ * Very simple method really... (To simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+
+static inline int ppa_proc_write(ppa_struct *dev, char *buffer, int length)
+{
+	unsigned long x;
+
+	if ((length > 5) && (strncmp(buffer, "mode=", 5) == 0)) {
+		x = simple_strtoul(buffer + 5, NULL, 0);
+		dev->mode = x;
+		return length;
+	}
+	if ((length > 10) && (strncmp(buffer, "recon_tmo=", 10) == 0)) {
+		x = simple_strtoul(buffer + 10, NULL, 0);
+		dev->recon_tmo = x;
+		printk("ppa: recon_tmo set to %ld\n", x);
+		return length;
+	}
+	printk("ppa /proc: invalid variable\n");
+	return (-EINVAL);
+}
+
+static int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout)
+{
+	int len = 0;
+	ppa_struct *dev = ppa_dev(host);
+
+	if (inout)
+		return ppa_proc_write(dev, buffer, length);
+
+	len += sprintf(buffer + len, "Version : %s\n", PPA_VERSION);
+	len +=
+	    sprintf(buffer + len, "Parport : %s\n",
+		    dev->dev->port->name);
+	len +=
+	    sprintf(buffer + len, "Mode    : %s\n",
+		    PPA_MODE_STRING[dev->mode]);
+#if PPA_DEBUG > 0
+	len +=
+	    sprintf(buffer + len, "recon_tmo : %lu\n", dev->recon_tmo);
+#endif
+
+	/* Request for beyond end of buffer */
+	if (offset > length)
+		return 0;
+
+	*start = buffer + offset;
+	len -= offset;
+	if (len > length)
+		len = length;
+	return len;
+}
+
+static int device_check(ppa_struct *dev);
+
+#if PPA_DEBUG > 0
+#define ppa_fail(x,y) printk("ppa: ppa_fail(%i) from %s at line %d\n",\
+	   y, __FUNCTION__, __LINE__); ppa_fail_func(x,y);
+static inline void ppa_fail_func(ppa_struct *dev, int error_code)
+#else
+static inline void ppa_fail(ppa_struct *dev, int error_code)
+#endif
+{
+	/* If we fail a device then we trash status / message bytes */
+	if (dev->cur_cmd) {
+		dev->cur_cmd->result = error_code << 16;
+		dev->failed = 1;
+	}
+}
+
+/*
+ * Wait for the high bit to be set.
+ * 
+ * In principle, this could be tied to an interrupt, but the adapter
+ * doesn't appear to be designed to support interrupts.  We spin on
+ * the 0x80 ready bit. 
+ */
+static unsigned char ppa_wait(ppa_struct *dev)
+{
+	int k;
+	unsigned short ppb = dev->base;
+	unsigned char r;
+
+	k = PPA_SPIN_TMO;
+	/* Wait for bit 6 and 7 - PJC */
+	for (r = r_str(ppb); ((r & 0xc0) != 0xc0) && (k); k--) {
+		udelay(1);
+		r = r_str(ppb);
+	}
+
+	/*
+	 * return some status information.
+	 * Semantics: 0xc0 = ZIP wants more data
+	 *            0xd0 = ZIP wants to send more data
+	 *            0xe0 = ZIP is expecting SCSI command data
+	 *            0xf0 = end of transfer, ZIP is sending status
+	 */
+	if (k)
+		return (r & 0xf0);
+
+	/* Counter expired - Time out occurred */
+	ppa_fail(dev, DID_TIME_OUT);
+	printk("ppa timeout in ppa_wait\n");
+	return 0;		/* command timed out */
+}
+
+/*
+ * Clear EPP Timeout Bit 
+ */
+static inline void epp_reset(unsigned short ppb)
+{
+	int i;
+
+	i = r_str(ppb);
+	w_str(ppb, i);
+	w_str(ppb, i & 0xfe);
+}
+
+/* 
+ * Wait for empty ECP fifo (if we are in ECP fifo mode only)
+ */
+static inline void ecp_sync(ppa_struct *dev)
+{
+	int i, ppb_hi = dev->dev->port->base_hi;
+
+	if (ppb_hi == 0)
+		return;
+
+	if ((r_ecr(ppb_hi) & 0xe0) == 0x60) {	/* mode 011 == ECP fifo mode */
+		for (i = 0; i < 100; i++) {
+			if (r_ecr(ppb_hi) & 0x01)
+				return;
+			udelay(5);
+		}
+		printk("ppa: ECP sync failed as data still present in FIFO.\n");
+	}
+}
+
+static int ppa_byte_out(unsigned short base, const char *buffer, int len)
+{
+	int i;
+
+	for (i = len; i; i--) {
+		w_dtr(base, *buffer++);
+		w_ctr(base, 0xe);
+		w_ctr(base, 0xc);
+	}
+	return 1;		/* All went well - we hope! */
+}
+
+static int ppa_byte_in(unsigned short base, char *buffer, int len)
+{
+	int i;
+
+	for (i = len; i; i--) {
+		*buffer++ = r_dtr(base);
+		w_ctr(base, 0x27);
+		w_ctr(base, 0x25);
+	}
+	return 1;		/* All went well - we hope! */
+}
+
+static int ppa_nibble_in(unsigned short base, char *buffer, int len)
+{
+	for (; len; len--) {
+		unsigned char h;
+
+		w_ctr(base, 0x4);
+		h = r_str(base) & 0xf0;
+		w_ctr(base, 0x6);
+		*buffer++ = h | ((r_str(base) & 0xf0) >> 4);
+	}
+	return 1;		/* All went well - we hope! */
+}
+
+static int ppa_out(ppa_struct *dev, char *buffer, int len)
+{
+	int r;
+	unsigned short ppb = dev->base;
+
+	r = ppa_wait(dev);
+
+	if ((r & 0x50) != 0x40) {
+		ppa_fail(dev, DID_ERROR);
+		return 0;
+	}
+	switch (dev->mode) {
+	case PPA_NIBBLE:
+	case PPA_PS2:
+		/* 8 bit output, with a loop */
+		r = ppa_byte_out(ppb, buffer, len);
+		break;
+
+	case PPA_EPP_32:
+	case PPA_EPP_16:
+	case PPA_EPP_8:
+		epp_reset(ppb);
+		w_ctr(ppb, 0x4);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+		if (!(((long) buffer | len) & 0x01))
+			outsw(ppb + 4, buffer, len >> 1);
+#else
+		if (!(((long) buffer | len) & 0x03))
+			outsl(ppb + 4, buffer, len >> 2);
+#endif
+		else
+			outsb(ppb + 4, buffer, len);
+		w_ctr(ppb, 0xc);
+		r = !(r_str(ppb) & 0x01);
+		w_ctr(ppb, 0xc);
+		ecp_sync(dev);
+		break;
+
+	default:
+		printk("PPA: bug in ppa_out()\n");
+		r = 0;
+	}
+	return r;
+}
+
+static int ppa_in(ppa_struct *dev, char *buffer, int len)
+{
+	int r;
+	unsigned short ppb = dev->base;
+
+	r = ppa_wait(dev);
+
+	if ((r & 0x50) != 0x50) {
+		ppa_fail(dev, DID_ERROR);
+		return 0;
+	}
+	switch (dev->mode) {
+	case PPA_NIBBLE:
+		/* 4 bit input, with a loop */
+		r = ppa_nibble_in(ppb, buffer, len);
+		w_ctr(ppb, 0xc);
+		break;
+
+	case PPA_PS2:
+		/* 8 bit input, with a loop */
+		w_ctr(ppb, 0x25);
+		r = ppa_byte_in(ppb, buffer, len);
+		w_ctr(ppb, 0x4);
+		w_ctr(ppb, 0xc);
+		break;
+
+	case PPA_EPP_32:
+	case PPA_EPP_16:
+	case PPA_EPP_8:
+		epp_reset(ppb);
+		w_ctr(ppb, 0x24);
+#ifdef CONFIG_SCSI_IZIP_EPP16
+		if (!(((long) buffer | len) & 0x01))
+			insw(ppb + 4, buffer, len >> 1);
+#else
+		if (!(((long) buffer | len) & 0x03))
+			insl(ppb + 4, buffer, len >> 2);
+#endif
+		else
+			insb(ppb + 4, buffer, len);
+		w_ctr(ppb, 0x2c);
+		r = !(r_str(ppb) & 0x01);
+		w_ctr(ppb, 0x2c);
+		ecp_sync(dev);
+		break;
+
+	default:
+		printk("PPA: bug in ppa_ins()\n");
+		r = 0;
+		break;
+	}
+	return r;
+}
+
+/* end of ppa_io.h */
+static inline void ppa_d_pulse(unsigned short ppb, unsigned char b)
+{
+	w_dtr(ppb, b);
+	w_ctr(ppb, 0xc);
+	w_ctr(ppb, 0xe);
+	w_ctr(ppb, 0xc);
+	w_ctr(ppb, 0x4);
+	w_ctr(ppb, 0xc);
+}
+
+static void ppa_disconnect(ppa_struct *dev)
+{
+	unsigned short ppb = dev->base;
+
+	ppa_d_pulse(ppb, 0);
+	ppa_d_pulse(ppb, 0x3c);
+	ppa_d_pulse(ppb, 0x20);
+	ppa_d_pulse(ppb, 0xf);
+}
+
+static inline void ppa_c_pulse(unsigned short ppb, unsigned char b)
+{
+	w_dtr(ppb, b);
+	w_ctr(ppb, 0x4);
+	w_ctr(ppb, 0x6);
+	w_ctr(ppb, 0x4);
+	w_ctr(ppb, 0xc);
+}
+
+static inline void ppa_connect(ppa_struct *dev, int flag)
+{
+	unsigned short ppb = dev->base;
+
+	ppa_c_pulse(ppb, 0);
+	ppa_c_pulse(ppb, 0x3c);
+	ppa_c_pulse(ppb, 0x20);
+	if ((flag == CONNECT_EPP_MAYBE) && IN_EPP_MODE(dev->mode))
+		ppa_c_pulse(ppb, 0xcf);
+	else
+		ppa_c_pulse(ppb, 0x8f);
+}
+
+static int ppa_select(ppa_struct *dev, int target)
+{
+	int k;
+	unsigned short ppb = dev->base;
+
+	/*
+	 * Bit 6 (0x40) is the device selected bit.
+	 * First we must wait till the current device goes off line...
+	 */
+	k = PPA_SELECT_TMO;
+	do {
+		k--;
+		udelay(1);
+	} while ((r_str(ppb) & 0x40) && (k));
+	if (!k)
+		return 0;
+
+	w_dtr(ppb, (1 << target));
+	w_ctr(ppb, 0xe);
+	w_ctr(ppb, 0xc);
+	w_dtr(ppb, 0x80);	/* This is NOT the initator */
+	w_ctr(ppb, 0x8);
+
+	k = PPA_SELECT_TMO;
+	do {
+		k--;
+		udelay(1);
+	}
+	while (!(r_str(ppb) & 0x40) && (k));
+	if (!k)
+		return 0;
+
+	return 1;
+}
+
+/* 
+ * This is based on a trace of what the Iomega DOS 'guest' driver does.
+ * I've tried several different kinds of parallel ports with guest and
+ * coded this to react in the same ways that it does.
+ * 
+ * The return value from this function is just a hint about where the
+ * handshaking failed.
+ * 
+ */
+static int ppa_init(ppa_struct *dev)
+{
+	int retv;
+	unsigned short ppb = dev->base;
+
+	ppa_disconnect(dev);
+	ppa_connect(dev, CONNECT_NORMAL);
+
+	retv = 2;		/* Failed */
+
+	w_ctr(ppb, 0xe);
+	if ((r_str(ppb) & 0x08) == 0x08)
+		retv--;
+
+	w_ctr(ppb, 0xc);
+	if ((r_str(ppb) & 0x08) == 0x00)
+		retv--;
+
+	if (!retv)
+		ppa_reset_pulse(ppb);
+	udelay(1000);		/* Allow devices to settle down */
+	ppa_disconnect(dev);
+	udelay(1000);		/* Another delay to allow devices to settle */
+
+	if (retv)
+		return -EIO;
+
+	return device_check(dev);
+}
+
+static inline int ppa_send_command(struct scsi_cmnd *cmd)
+{
+	ppa_struct *dev = ppa_dev(cmd->device->host);
+	int k;
+
+	w_ctr(dev->base, 0x0c);
+
+	for (k = 0; k < cmd->cmd_len; k++)
+		if (!ppa_out(dev, &cmd->cmnd[k], 1))
+			return 0;
+	return 1;
+}
+
+/*
+ * The bulk flag enables some optimisations in the data transfer loops,
+ * it should be true for any command that transfers data in integral
+ * numbers of sectors.
+ * 
+ * The driver appears to remain stable if we speed up the parallel port
+ * i/o in this function, but not elsewhere.
+ */
+static int ppa_completion(struct scsi_cmnd *cmd)
+{
+	/* Return codes:
+	 * -1     Error
+	 *  0     Told to schedule
+	 *  1     Finished data transfer
+	 */
+	ppa_struct *dev = ppa_dev(cmd->device->host);
+	unsigned short ppb = dev->base;
+	unsigned long start_jiffies = jiffies;
+
+	unsigned char r, v;
+	int fast, bulk, status;
+
+	v = cmd->cmnd[0];
+	bulk = ((v == READ_6) ||
+		(v == READ_10) || (v == WRITE_6) || (v == WRITE_10));
+
+	/*
+	 * We only get here if the drive is ready to comunicate,
+	 * hence no need for a full ppa_wait.
+	 */
+	r = (r_str(ppb) & 0xf0);
+
+	while (r != (unsigned char) 0xf0) {
+		/*
+		 * If we have been running for more than a full timer tick
+		 * then take a rest.
+		 */
+		if (time_after(jiffies, start_jiffies + 1))
+			return 0;
+
+		if ((cmd->SCp.this_residual <= 0)) {
+			ppa_fail(dev, DID_ERROR);
+			return -1;	/* ERROR_RETURN */
+		}
+
+		/* On some hardware we have SCSI disconnected (6th bit low)
+		 * for about 100usecs. It is too expensive to wait a 
+		 * tick on every loop so we busy wait for no more than
+		 * 500usecs to give the drive a chance first. We do not 
+		 * change things for "normal" hardware since generally 
+		 * the 6th bit is always high.
+		 * This makes the CPU load higher on some hardware 
+		 * but otherwise we can not get more than 50K/secs 
+		 * on this problem hardware.
+		 */
+		if ((r & 0xc0) != 0xc0) {
+			/* Wait for reconnection should be no more than 
+			 * jiffy/2 = 5ms = 5000 loops
+			 */
+			unsigned long k = dev->recon_tmo;
+			for (; k && ((r = (r_str(ppb) & 0xf0)) & 0xc0) != 0xc0;
+			     k--)
+				udelay(1);
+
+			if (!k)
+				return 0;
+		}
+
+		/* determine if we should use burst I/O */
+		fast = (bulk && (cmd->SCp.this_residual >= PPA_BURST_SIZE))
+		    ? PPA_BURST_SIZE : 1;
+
+		if (r == (unsigned char) 0xc0)
+			status = ppa_out(dev, cmd->SCp.ptr, fast);
+		else
+			status = ppa_in(dev, cmd->SCp.ptr, fast);
+
+		cmd->SCp.ptr += fast;
+		cmd->SCp.this_residual -= fast;
+
+		if (!status) {
+			ppa_fail(dev, DID_BUS_BUSY);
+			return -1;	/* ERROR_RETURN */
+		}
+		if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+			/* if scatter/gather, advance to the next segment */
+			if (cmd->SCp.buffers_residual--) {
+				cmd->SCp.buffer++;
+				cmd->SCp.this_residual =
+				    cmd->SCp.buffer->length;
+				cmd->SCp.ptr =
+				    page_address(cmd->SCp.buffer->page) +
+				    cmd->SCp.buffer->offset;
+			}
+		}
+		/* Now check to see if the drive is ready to comunicate */
+		r = (r_str(ppb) & 0xf0);
+		/* If not, drop back down to the scheduler and wait a timer tick */
+		if (!(r & 0x80))
+			return 0;
+	}
+	return 1;		/* FINISH_RETURN */
+}
+
+/*
+ * Since the PPA itself doesn't generate interrupts, we use
+ * the scheduler's task queue to generate a stream of call-backs and
+ * complete the request when the drive is ready.
+ */
+static void ppa_interrupt(void *data)
+{
+	ppa_struct *dev = (ppa_struct *) data;
+	struct scsi_cmnd *cmd = dev->cur_cmd;
+
+	if (!cmd) {
+		printk("PPA: bug in ppa_interrupt\n");
+		return;
+	}
+	if (ppa_engine(dev, cmd)) {
+		dev->ppa_tq.data = (void *) dev;
+		schedule_delayed_work(&dev->ppa_tq, 1);
+		return;
+	}
+	/* Command must of completed hence it is safe to let go... */
+#if PPA_DEBUG > 0
+	switch ((cmd->result >> 16) & 0xff) {
+	case DID_OK:
+		break;
+	case DID_NO_CONNECT:
+		printk("ppa: no device at SCSI ID %i\n", cmd->device->target);
+		break;
+	case DID_BUS_BUSY:
+		printk("ppa: BUS BUSY - EPP timeout detected\n");
+		break;
+	case DID_TIME_OUT:
+		printk("ppa: unknown timeout\n");
+		break;
+	case DID_ABORT:
+		printk("ppa: told to abort\n");
+		break;
+	case DID_PARITY:
+		printk("ppa: parity error (???)\n");
+		break;
+	case DID_ERROR:
+		printk("ppa: internal driver error\n");
+		break;
+	case DID_RESET:
+		printk("ppa: told to reset device\n");
+		break;
+	case DID_BAD_INTR:
+		printk("ppa: bad interrupt (???)\n");
+		break;
+	default:
+		printk("ppa: bad return code (%02x)\n",
+		       (cmd->result >> 16) & 0xff);
+	}
+#endif
+
+	if (cmd->SCp.phase > 1)
+		ppa_disconnect(dev);
+
+	ppa_pb_dismiss(dev);
+
+	dev->cur_cmd = NULL;
+
+	cmd->scsi_done(cmd);
+}
+
+static int ppa_engine(ppa_struct *dev, struct scsi_cmnd *cmd)
+{
+	unsigned short ppb = dev->base;
+	unsigned char l = 0, h = 0;
+	int retv;
+
+	/* First check for any errors that may of occurred
+	 * Here we check for internal errors
+	 */
+	if (dev->failed)
+		return 0;
+
+	switch (cmd->SCp.phase) {
+	case 0:		/* Phase 0 - Waiting for parport */
+		if (time_after(jiffies, dev->jstart + HZ)) {
+			/*
+			 * We waited more than a second
+			 * for parport to call us
+			 */
+			ppa_fail(dev, DID_BUS_BUSY);
+			return 0;
+		}
+		return 1;	/* wait until ppa_wakeup claims parport */
+	case 1:		/* Phase 1 - Connected */
+		{		/* Perform a sanity check for cable unplugged */
+			int retv = 2;	/* Failed */
+
+			ppa_connect(dev, CONNECT_EPP_MAYBE);
+
+			w_ctr(ppb, 0xe);
+			if ((r_str(ppb) & 0x08) == 0x08)
+				retv--;
+
+			w_ctr(ppb, 0xc);
+			if ((r_str(ppb) & 0x08) == 0x00)
+				retv--;
+
+			if (retv) {
+				if ((jiffies - dev->jstart) > (1 * HZ)) {
+					printk
+					    ("ppa: Parallel port cable is unplugged!!\n");
+					ppa_fail(dev, DID_BUS_BUSY);
+					return 0;
+				} else {
+					ppa_disconnect(dev);
+					return 1;	/* Try again in a jiffy */
+				}
+			}
+			cmd->SCp.phase++;
+		}
+
+	case 2:		/* Phase 2 - We are now talking to the scsi bus */
+		if (!ppa_select(dev, cmd->device->id)) {
+			ppa_fail(dev, DID_NO_CONNECT);
+			return 0;
+		}
+		cmd->SCp.phase++;
+
+	case 3:		/* Phase 3 - Ready to accept a command */
+		w_ctr(ppb, 0x0c);
+		if (!(r_str(ppb) & 0x80))
+			return 1;
+
+		if (!ppa_send_command(cmd))
+			return 0;
+		cmd->SCp.phase++;
+
+	case 4:		/* Phase 4 - Setup scatter/gather buffers */
+		if (cmd->use_sg) {
+			/* if many buffers are available, start filling the first */
+			cmd->SCp.buffer =
+			    (struct scatterlist *) cmd->request_buffer;
+			cmd->SCp.this_residual = cmd->SCp.buffer->length;
+			cmd->SCp.ptr =
+			    page_address(cmd->SCp.buffer->page) +
+			    cmd->SCp.buffer->offset;
+		} else {
+			/* else fill the only available buffer */
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.this_residual = cmd->request_bufflen;
+			cmd->SCp.ptr = cmd->request_buffer;
+		}
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.phase++;
+
+	case 5:		/* Phase 5 - Data transfer stage */
+		w_ctr(ppb, 0x0c);
+		if (!(r_str(ppb) & 0x80))
+			return 1;
+
+		retv = ppa_completion(cmd);
+		if (retv == -1)
+			return 0;
+		if (retv == 0)
+			return 1;
+		cmd->SCp.phase++;
+
+	case 6:		/* Phase 6 - Read status/message */
+		cmd->result = DID_OK << 16;
+		/* Check for data overrun */
+		if (ppa_wait(dev) != (unsigned char) 0xf0) {
+			ppa_fail(dev, DID_ERROR);
+			return 0;
+		}
+		if (ppa_in(dev, &l, 1)) {	/* read status byte */
+			/* Check for optional message byte */
+			if (ppa_wait(dev) == (unsigned char) 0xf0)
+				ppa_in(dev, &h, 1);
+			cmd->result =
+			    (DID_OK << 16) + (h << 8) + (l & STATUS_MASK);
+		}
+		return 0;	/* Finished */
+		break;
+
+	default:
+		printk("ppa: Invalid scsi phase\n");
+	}
+	return 0;
+}
+
+static int ppa_queuecommand(struct scsi_cmnd *cmd,
+		void (*done) (struct scsi_cmnd *))
+{
+	ppa_struct *dev = ppa_dev(cmd->device->host);
+
+	if (dev->cur_cmd) {
+		printk("PPA: bug in ppa_queuecommand\n");
+		return 0;
+	}
+	dev->failed = 0;
+	dev->jstart = jiffies;
+	dev->cur_cmd = cmd;
+	cmd->scsi_done = done;
+	cmd->result = DID_ERROR << 16;	/* default return code */
+	cmd->SCp.phase = 0;	/* bus free */
+
+	dev->ppa_tq.data = dev;
+	schedule_work(&dev->ppa_tq);
+
+	ppa_pb_claim(dev);
+
+	return 0;
+}
+
+/*
+ * Apparently the disk->capacity attribute is off by 1 sector 
+ * for all disk drives.  We add the one here, but it should really
+ * be done in sd.c.  Even if it gets fixed there, this will still
+ * work.
+ */
+static int ppa_biosparam(struct scsi_device *sdev, struct block_device *dev,
+	      sector_t capacity, int ip[])
+{
+	ip[0] = 0x40;
+	ip[1] = 0x20;
+	ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]);
+	if (ip[2] > 1024) {
+		ip[0] = 0xff;
+		ip[1] = 0x3f;
+		ip[2] = ((unsigned long) capacity + 1) / (ip[0] * ip[1]);
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+	}
+	return 0;
+}
+
+static int ppa_abort(struct scsi_cmnd *cmd)
+{
+	ppa_struct *dev = ppa_dev(cmd->device->host);
+	/*
+	 * There is no method for aborting commands since Iomega
+	 * have tied the SCSI_MESSAGE line high in the interface
+	 */
+
+	switch (cmd->SCp.phase) {
+	case 0:		/* Do not have access to parport */
+	case 1:		/* Have not connected to interface */
+		dev->cur_cmd = NULL;	/* Forget the problem */
+		return SUCCESS;
+		break;
+	default:		/* SCSI command sent, can not abort */
+		return FAILED;
+		break;
+	}
+}
+
+static void ppa_reset_pulse(unsigned int base)
+{
+	w_dtr(base, 0x40);
+	w_ctr(base, 0x8);
+	udelay(30);
+	w_ctr(base, 0xc);
+}
+
+static int ppa_reset(struct scsi_cmnd *cmd)
+{
+	ppa_struct *dev = ppa_dev(cmd->device->host);
+
+	if (cmd->SCp.phase)
+		ppa_disconnect(dev);
+	dev->cur_cmd = NULL;	/* Forget the problem */
+
+	ppa_connect(dev, CONNECT_NORMAL);
+	ppa_reset_pulse(dev->base);
+	udelay(1000);		/* device settle delay */
+	ppa_disconnect(dev);
+	udelay(1000);		/* device settle delay */
+	return SUCCESS;
+}
+
+static int device_check(ppa_struct *dev)
+{
+	/* This routine looks for a device and then attempts to use EPP
+	   to send a command. If all goes as planned then EPP is available. */
+
+	static char cmd[6] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+	int loop, old_mode, status, k, ppb = dev->base;
+	unsigned char l;
+
+	old_mode = dev->mode;
+	for (loop = 0; loop < 8; loop++) {
+		/* Attempt to use EPP for Test Unit Ready */
+		if ((ppb & 0x0007) == 0x0000)
+			dev->mode = PPA_EPP_32;
+
+	      second_pass:
+		ppa_connect(dev, CONNECT_EPP_MAYBE);
+		/* Select SCSI device */
+		if (!ppa_select(dev, loop)) {
+			ppa_disconnect(dev);
+			continue;
+		}
+		printk("ppa: Found device at ID %i, Attempting to use %s\n",
+		       loop, PPA_MODE_STRING[dev->mode]);
+
+		/* Send SCSI command */
+		status = 1;
+		w_ctr(ppb, 0x0c);
+		for (l = 0; (l < 6) && (status); l++)
+			status = ppa_out(dev, cmd, 1);
+
+		if (!status) {
+			ppa_disconnect(dev);
+			ppa_connect(dev, CONNECT_EPP_MAYBE);
+			w_dtr(ppb, 0x40);
+			w_ctr(ppb, 0x08);
+			udelay(30);
+			w_ctr(ppb, 0x0c);
+			udelay(1000);
+			ppa_disconnect(dev);
+			udelay(1000);
+			if (dev->mode == PPA_EPP_32) {
+				dev->mode = old_mode;
+				goto second_pass;
+			}
+			return -EIO;
+		}
+		w_ctr(ppb, 0x0c);
+		k = 1000000;	/* 1 Second */
+		do {
+			l = r_str(ppb);
+			k--;
+			udelay(1);
+		} while (!(l & 0x80) && (k));
+
+		l &= 0xf0;
+
+		if (l != 0xf0) {
+			ppa_disconnect(dev);
+			ppa_connect(dev, CONNECT_EPP_MAYBE);
+			ppa_reset_pulse(ppb);
+			udelay(1000);
+			ppa_disconnect(dev);
+			udelay(1000);
+			if (dev->mode == PPA_EPP_32) {
+				dev->mode = old_mode;
+				goto second_pass;
+			}
+			return -EIO;
+		}
+		ppa_disconnect(dev);
+		printk("ppa: Communication established with ID %i using %s\n",
+		       loop, PPA_MODE_STRING[dev->mode]);
+		ppa_connect(dev, CONNECT_EPP_MAYBE);
+		ppa_reset_pulse(ppb);
+		udelay(1000);
+		ppa_disconnect(dev);
+		udelay(1000);
+		return 0;
+	}
+	return -ENODEV;
+}
+
+static struct scsi_host_template ppa_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "ppa",
+	.proc_info		= ppa_proc_info,
+	.name			= "Iomega VPI0 (ppa) interface",
+	.queuecommand		= ppa_queuecommand,
+	.eh_abort_handler	= ppa_abort,
+	.eh_bus_reset_handler	= ppa_reset,
+	.eh_host_reset_handler	= ppa_reset,
+	.bios_param		= ppa_biosparam,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.can_queue		= 1,
+};
+
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+
+static LIST_HEAD(ppa_hosts);
+
+static int __ppa_attach(struct parport *pb)
+{
+	struct Scsi_Host *host;
+	DECLARE_WAIT_QUEUE_HEAD(waiting);
+	DEFINE_WAIT(wait);
+	ppa_struct *dev;
+	int ports;
+	int modes, ppb, ppb_hi;
+	int err = -ENOMEM;
+
+	dev = kmalloc(sizeof(ppa_struct), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	memset(dev, 0, sizeof(ppa_struct));
+	dev->base = -1;
+	dev->mode = PPA_AUTODETECT;
+	dev->recon_tmo = PPA_RECON_TMO;
+	init_waitqueue_head(&waiting);
+	dev->dev = parport_register_device(pb, "ppa", NULL, ppa_wakeup,
+					    NULL, 0, dev);
+
+	if (!dev->dev)
+		goto out;
+
+	/* Claim the bus so it remembers what we do to the control
+	 * registers. [ CTR and ECP ]
+	 */
+	err = -EBUSY;
+	dev->waiting = &waiting;
+	prepare_to_wait(&waiting, &wait, TASK_UNINTERRUPTIBLE);
+	if (ppa_pb_claim(dev))
+		schedule_timeout(3 * HZ);
+	if (dev->wanted) {
+		printk(KERN_ERR "ppa%d: failed to claim parport because "
+				"a pardevice is owning the port for too long "
+				"time!\n", pb->number);
+		ppa_pb_dismiss(dev);
+		dev->waiting = NULL;
+		finish_wait(&waiting, &wait);
+		goto out1;
+	}
+	dev->waiting = NULL;
+	finish_wait(&waiting, &wait);
+	ppb = dev->base = dev->dev->port->base;
+	ppb_hi = dev->dev->port->base_hi;
+	w_ctr(ppb, 0x0c);
+	modes = dev->dev->port->modes;
+
+	/* Mode detection works up the chain of speed
+	 * This avoids a nasty if-then-else-if-... tree
+	 */
+	dev->mode = PPA_NIBBLE;
+
+	if (modes & PARPORT_MODE_TRISTATE)
+		dev->mode = PPA_PS2;
+
+	if (modes & PARPORT_MODE_ECP) {
+		w_ecr(ppb_hi, 0x20);
+		dev->mode = PPA_PS2;
+	}
+	if ((modes & PARPORT_MODE_EPP) && (modes & PARPORT_MODE_ECP))
+		w_ecr(ppb_hi, 0x80);
+
+	/* Done configuration */
+
+	err = ppa_init(dev);
+	ppa_pb_release(dev);
+
+	if (err)
+		goto out1;
+
+	/* now the glue ... */
+	if (dev->mode == PPA_NIBBLE || dev->mode == PPA_PS2)
+		ports = 3;
+	else
+		ports = 8;
+
+	INIT_WORK(&dev->ppa_tq, ppa_interrupt, dev);
+
+	err = -ENOMEM;
+	host = scsi_host_alloc(&ppa_template, sizeof(ppa_struct *));
+	if (!host)
+		goto out1;
+	host->io_port = pb->base;
+	host->n_io_port = ports;
+	host->dma_channel = -1;
+	host->unique_id = pb->number;
+	*(ppa_struct **)&host->hostdata = dev;
+	dev->host = host;
+	list_add_tail(&dev->list, &ppa_hosts);
+	err = scsi_add_host(host, NULL);
+	if (err)
+		goto out2;
+	scsi_scan_host(host);
+	return 0;
+out2:
+	list_del_init(&dev->list);
+	scsi_host_put(host);
+out1:
+	parport_unregister_device(dev->dev);
+out:
+	kfree(dev);
+	return err;
+}
+
+static void ppa_attach(struct parport *pb)
+{
+	__ppa_attach(pb);
+}
+
+static void ppa_detach(struct parport *pb)
+{
+	ppa_struct *dev;
+	list_for_each_entry(dev, &ppa_hosts, list) {
+		if (dev->dev->port == pb) {
+			list_del_init(&dev->list);
+			scsi_remove_host(dev->host);
+			scsi_host_put(dev->host);
+			parport_unregister_device(dev->dev);
+			kfree(dev);
+			break;
+		}
+	}
+}
+
+static struct parport_driver ppa_driver = {
+	.name	= "ppa",
+	.attach	= ppa_attach,
+	.detach	= ppa_detach,
+};
+
+static int __init ppa_driver_init(void)
+{
+	printk("ppa: Version %s\n", PPA_VERSION);
+	return parport_register_driver(&ppa_driver);
+}
+
+static void __exit ppa_driver_exit(void)
+{
+	parport_unregister_driver(&ppa_driver);
+}
+
+module_init(ppa_driver_init);
+module_exit(ppa_driver_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
new file mode 100644
index 0000000..f6e1a15
--- /dev/null
+++ b/drivers/scsi/ppa.h
@@ -0,0 +1,151 @@
+/*  Driver for the PPA3 parallel port SCSI HBA embedded in 
+ * the Iomega ZIP drive
+ * 
+ * (c) 1996     Grant R. Guenther  grant@torque.net
+ *              David Campbell     campbell@torque.net
+ *
+ *      All comments to David.
+ */
+
+#ifndef _PPA_H
+#define _PPA_H
+
+#define   PPA_VERSION   "2.07 (for Linux 2.4.x)"
+
+/* 
+ * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
+ * to support EPP and scatter-gather.                        [0.26-athena]
+ *
+ * additional hacks by David Campbell
+ * in response to this driver "mis-behaving" on his machine.
+ *      Fixed EPP to handle "software" changing of EPP port data direction.
+ *      Chased down EPP timeouts
+ *      Made this driver "kernel version friendly"           [0.28-athena]
+ *
+ * [ Stuff removed ]
+ *
+ * Corrected ppa.h for 2.1.x kernels (>=2.1.85)
+ * Modified "Nat Semi Kludge" for extended chipsets
+ *                                                      [1.41]
+ *
+ * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7)
+ *                                                      [1.42]
+ *
+ * Development solely for 2.1.x kernels from now on!
+ *                                                      [2.00]
+ *
+ * Hack and slash at the init code (EPP device check routine)
+ * Added INSANE option.
+ *                                                      [2.01]
+ *
+ * Patch applied to sync against the 2.1.x kernel code
+ * Included qboot_zip.sh
+ *                                                      [2.02]
+ *
+ * Cleaned up the mess left by someone else trying to fix the
+ * asm section to keep egcc happy. The asm section no longer
+ * exists, the nibble code is *almost* as fast as the asm code
+ * providing it is compiled with egcc.
+ *
+ * Other clean ups include the follow changes:
+ *    CONFIG_SCSI_PPA_HAVE_PEDANTIC => CONFIG_SCSI_IZIP_EPP16
+ *    added CONFIG_SCSI_IZIP_SLOW_CTR option
+ *                                                      [2.03]
+ *
+ * Use ppa_wait() to check for ready AND connected status bits
+ * Add ppa_wait() calls to ppa_completion()
+ *  by Peter Cherriman <pjc@ecs.soton.ac.uk> and
+ *     Tim Waugh <twaugh@redhat.com>
+ *							[2.04]
+ *
+ * Fix kernel panic on scsi timeout, 2000-08-18		[2.05]
+ *
+ * Avoid io_request_lock problems.
+ * John Cavan <johncavan@home.com>			[2.06]
+ *
+ * Busy wait for connected status bit in ppa_completion()
+ *  in order to cope with some hardware that has this bit low
+ *  for short periods of time.
+ * Add udelay() to ppa_select()
+ *  by Peter Cherriman <pjc@ecs.soton.ac.uk> and
+ *     Oleg Makarenko <omakarenko@cyberplat.ru>         
+ *                                                      [2.07]
+ */
+/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+#include  <linux/config.h>
+#include  <linux/stddef.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <linux/blkdev.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
+
+#include  <asm/io.h>
+#include  <scsi/scsi_host.h>
+/* batteries not included :-) */
+
+/*
+ * modes in which the driver can operate 
+ */
+#define   PPA_AUTODETECT        0	/* Autodetect mode                */
+#define   PPA_NIBBLE            1	/* work in standard 4 bit mode    */
+#define   PPA_PS2               2	/* PS/2 byte mode         */
+#define   PPA_EPP_8             3	/* EPP mode, 8 bit                */
+#define   PPA_EPP_16            4	/* EPP mode, 16 bit               */
+#define   PPA_EPP_32            5	/* EPP mode, 32 bit               */
+#define   PPA_UNKNOWN           6	/* Just in case...                */
+
+static char *PPA_MODE_STRING[] =
+{
+    "Autodetect",
+    "SPP",
+    "PS/2",
+    "EPP 8 bit",
+    "EPP 16 bit",
+#ifdef CONFIG_SCSI_IZIP_EPP16
+    "EPP 16 bit",
+#else
+    "EPP 32 bit",
+#endif
+    "Unknown"};
+
+/* other options */
+#define PPA_BURST_SIZE	512	/* data burst size */
+#define PPA_SELECT_TMO  5000	/* how long to wait for target ? */
+#define PPA_SPIN_TMO    50000	/* ppa_wait loop limiter */
+#define PPA_RECON_TMO   500	/* scsi reconnection loop limiter */
+#define PPA_DEBUG	0	/* debugging option */
+#define IN_EPP_MODE(x) (x == PPA_EPP_8 || x == PPA_EPP_16 || x == PPA_EPP_32)
+
+/* args to ppa_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define r_dtr(x)        (unsigned char)inb((x))
+#define r_str(x)        (unsigned char)inb((x)+1)
+#define r_ctr(x)        (unsigned char)inb((x)+2)
+#define r_epp(x)        (unsigned char)inb((x)+4)
+#define r_fifo(x)       (unsigned char)inb((x)) /* x must be base_hi */
+					/* On PCI is base+0x400 != base_hi */
+#define r_ecr(x)        (unsigned char)inb((x)+0x2) /* x must be base_hi */
+
+#define w_dtr(x,y)      outb(y, (x))
+#define w_str(x,y)      outb(y, (x)+1)
+#define w_epp(x,y)      outb(y, (x)+4)
+#define w_fifo(x,y)     outb(y, (x))	/* x must be base_hi */
+#define w_ecr(x,y)      outb(y, (x)+0x2)/* x must be base_hi */
+
+#ifdef CONFIG_SCSI_IZIP_SLOW_CTR
+#define w_ctr(x,y)      outb_p(y, (x)+2)
+#else
+#define w_ctr(x,y)      outb(y, (x)+2)
+#endif
+
+static int ppa_engine(ppa_struct *, struct scsi_cmnd *);
+
+#endif				/* _PPA_H */
diff --git a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
new file mode 100644
index 0000000..0f576d4
--- /dev/null
+++ b/drivers/scsi/psi240i.c
@@ -0,0 +1,685 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *	File Name:		psi240i.c
+ *
+ *	Description:	SCSI driver for the PSI240I EIDE interface card.
+ *
+ *-M*************************************************************************/
+
+#include <linux/module.h>
+
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#include "psi240i.h"
+#include "psi_chip.h"
+
+//#define DEBUG 1
+
+#ifdef DEBUG
+#define DEB(x) x
+#else
+#define DEB(x)
+#endif
+
+#define MAXBOARDS 6	/* Increase this and the sizes of the arrays below, if you need more. */
+
+#define	PORT_DATA				0
+#define	PORT_ERROR				1
+#define	PORT_SECTOR_COUNT		2
+#define	PORT_LBA_0				3
+#define	PORT_LBA_8				4
+#define	PORT_LBA_16				5
+#define	PORT_LBA_24				6
+#define	PORT_STAT_CMD			7
+#define	PORT_SEL_FAIL			8
+#define	PORT_IRQ_STATUS			9
+#define	PORT_ADDRESS			10
+#define	PORT_FAIL				11
+#define	PORT_ALT_STAT		   	12
+
+typedef struct
+	{
+	UCHAR		   	device;				// device code
+	UCHAR			byte6;				// device select register image
+	UCHAR			spigot;				// spigot number
+	UCHAR			expectingIRQ;		// flag for expecting and interrupt
+	USHORT			sectors;			// number of sectors per track
+	USHORT			heads;				// number of heads
+	USHORT			cylinders;			// number of cylinders for this device
+	USHORT			spareword;			// placeholder
+	ULONG			blocks;				// number of blocks on device
+	}	OUR_DEVICE, *POUR_DEVICE;
+
+typedef struct
+	{
+	USHORT		 ports[13];
+	OUR_DEVICE	 device[8];
+	Scsi_Cmnd	*pSCmnd;
+	IDE_STRUCT	 ide;
+	ULONG		 startSector;
+	USHORT		 sectorCount;
+	Scsi_Cmnd	*SCpnt;
+	VOID		*buffer;
+	USHORT		 expectingIRQ;
+	}	ADAPTER240I, *PADAPTER240I;
+
+#define HOSTDATA(host) ((PADAPTER240I)&host->hostdata)
+
+static struct	Scsi_Host *PsiHost[6] = {NULL,};  /* One for each IRQ level (10-15) */
+static			IDENTIFY_DATA	identifyData;
+static			SETUP			ChipSetup;
+
+static	USHORT	portAddr[6] = {CHIP_ADRS_0, CHIP_ADRS_1, CHIP_ADRS_2, CHIP_ADRS_3, CHIP_ADRS_4, CHIP_ADRS_5};
+
+/****************************************************************
+ *	Name:	WriteData	:LOCAL
+ *
+ *	Description:	Write data to device.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		TRUE if drive does not assert DRQ in time.
+ *
+ ****************************************************************/
+static int WriteData (PADAPTER240I padapter)
+	{
+	ULONG	timer;
+	USHORT *pports = padapter->ports;
+
+	timer = jiffies + TIMEOUT_DRQ;								// calculate the timeout value
+	do  {
+		if ( inb_p (pports[PORT_STAT_CMD]) & IDE_STATUS_DRQ )
+			{
+			outsw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ide[2] * 256);
+			return 0;
+			}
+		}	while ( time_after(timer, jiffies) );									// test for timeout
+
+	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
+	return 1;
+	}
+/****************************************************************
+ *	Name:	IdeCmd	:LOCAL
+ *
+ *	Description:	Process a queued command from the SCSI manager.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *
+ *	Returns:		Zero if no error or status register contents on error.
+ *
+ ****************************************************************/
+static UCHAR IdeCmd (PADAPTER240I padapter)
+	{
+	ULONG	timer;
+	USHORT *pports = padapter->ports;
+	UCHAR	status;
+
+	outb_p (padapter->ide.ide.ides.spigot, pports[PORT_SEL_FAIL]);	// select the spigot
+	outb_p (padapter->ide.ide.ide[6], pports[PORT_LBA_24]);			// select the drive
+	timer = jiffies + TIMEOUT_READY;							// calculate the timeout value
+	do  {
+		status = inb_p (padapter->ports[PORT_STAT_CMD]);
+		if ( status & IDE_STATUS_DRDY )
+			{
+			outb_p (padapter->ide.ide.ide[2], pports[PORT_SECTOR_COUNT]);
+			outb_p (padapter->ide.ide.ide[3], pports[PORT_LBA_0]);
+			outb_p (padapter->ide.ide.ide[4], pports[PORT_LBA_8]);
+			outb_p (padapter->ide.ide.ide[5], pports[PORT_LBA_16]);
+			padapter->expectingIRQ = 1;
+			outb_p (padapter->ide.ide.ide[7], pports[PORT_STAT_CMD]);
+
+			if ( padapter->ide.ide.ides.cmd == IDE_CMD_WRITE_MULTIPLE )
+				return (WriteData (padapter));
+
+			return 0;
+			}
+		}	while ( time_after(timer, jiffies) );									// test for timeout
+
+	padapter->ide.ide.ides.cmd = 0;									// null out the command byte
+	return status;
+	}
+/****************************************************************
+ *	Name:	SetupTransfer	:LOCAL
+ *
+ *	Description:	Setup a data transfer command.
+ *
+ *	Parameters:		padapter - Pointer adapter data structure.
+ *					drive	 - Drive/head register upper nibble only.
+ *
+ *	Returns:		TRUE if no data to transfer.
+ *
+ ****************************************************************/
+static int SetupTransfer (PADAPTER240I padapter, UCHAR drive)
+	{
+	if ( padapter->sectorCount )
+		{
+		*(ULONG *)padapter->ide.ide.ides.lba = padapter->startSector;
+		padapter->ide.ide.ide[6] |= drive;
+		padapter->ide.ide.ides.sectors = ( padapter->sectorCount > SECTORSXFER ) ? SECTORSXFER : padapter->sectorCount;
+		padapter->sectorCount -= padapter->ide.ide.ides.sectors;	// bump the start and count for next xfer
+		padapter->startSector += padapter->ide.ide.ides.sectors;
+		return 0;
+		}
+	else
+		{
+		padapter->ide.ide.ides.cmd = 0;								// null out the command byte
+		padapter->SCpnt = NULL;
+		return 1;
+		}
+	}
+/****************************************************************
+ *	Name:	DecodeError	:LOCAL
+ *
+ *	Description:	Decode and process device errors.
+ *
+ *	Parameters:		pshost - Pointer to host data block.
+ *					status - Status register code.
+ *
+ *	Returns:		The driver status code.
+ *
+ ****************************************************************/
+static ULONG DecodeError (struct Scsi_Host *pshost, UCHAR status)
+	{
+	PADAPTER240I	padapter = HOSTDATA(pshost);
+	UCHAR			error;
+
+	padapter->expectingIRQ = 0;
+	padapter->SCpnt = NULL;
+	if ( status & IDE_STATUS_WRITE_FAULT )
+		{
+		return DID_PARITY << 16;
+		}
+	if ( status & IDE_STATUS_BUSY )
+		return DID_BUS_BUSY << 16;
+
+	error = inb_p (padapter->ports[PORT_ERROR]);
+	DEB(printk ("\npsi240i error register: %x", error));
+	switch ( error )
+		{
+		case IDE_ERROR_AMNF:
+		case IDE_ERROR_TKONF:
+		case IDE_ERROR_ABRT:
+		case IDE_ERROR_IDFN:
+		case IDE_ERROR_UNC:
+		case IDE_ERROR_BBK:
+		default:
+			return DID_ERROR << 16;
+		}
+	return DID_ERROR << 16;
+	}
+/****************************************************************
+ *	Name:	Irq_Handler	:LOCAL
+ *
+ *	Description:	Interrupt handler.
+ *
+ *	Parameters:		irq		- Hardware IRQ number.
+ *					dev_id	-
+ *					regs	-
+ *
+ *	Returns:		TRUE if drive is not ready in time.
+ *
+ ****************************************************************/
+static void Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+	{
+	struct Scsi_Host   *shost;			// Pointer to host data block
+	PADAPTER240I		padapter;		// Pointer to adapter control structure
+	USHORT		 	   *pports;			// I/O port array
+	Scsi_Cmnd		   *SCpnt;
+	UCHAR				status;
+	int					z;
+
+	DEB(printk ("\npsi240i received interrupt\n"));
+
+	shost = PsiHost[irq - 10];
+	if ( !shost )
+		panic ("Splunge!");
+
+	padapter = HOSTDATA(shost);
+	pports = padapter->ports;
+	SCpnt = padapter->SCpnt;
+
+	if ( !padapter->expectingIRQ )
+		{
+		DEB(printk ("\npsi240i Unsolicited interrupt\n"));
+		return;
+		}
+	padapter->expectingIRQ = 0;
+
+	status = inb_p (padapter->ports[PORT_STAT_CMD]);			// read the device status
+	if ( status & (IDE_STATUS_ERROR | IDE_STATUS_WRITE_FAULT) )
+		goto irqerror;
+
+	DEB(printk ("\npsi240i processing interrupt"));
+	switch ( padapter->ide.ide.ides.cmd )							// decide how to handle the interrupt
+		{
+		case IDE_CMD_READ_MULTIPLE:
+			if ( status & IDE_STATUS_DRQ )
+				{
+				insw (pports[PORT_DATA], padapter->buffer, (USHORT)padapter->ide.ide.ides.sectors * 256);
+				padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+				if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+					{
+					SCpnt->result = DID_OK << 16;
+					padapter->SCpnt = NULL;
+					SCpnt->scsi_done (SCpnt);
+					return;
+					}
+				if ( !(status = IdeCmd (padapter)) )
+					return;
+				}
+			break;
+
+		case IDE_CMD_WRITE_MULTIPLE:
+			padapter->buffer += padapter->ide.ide.ides.sectors * 512;
+			if ( SetupTransfer (padapter, padapter->ide.ide.ide[6] & 0xF0) )
+				{
+				SCpnt->result = DID_OK << 16;
+				padapter->SCpnt = NULL;
+				SCpnt->scsi_done (SCpnt);
+				return;
+				}
+			if ( !(status = IdeCmd (padapter)) )
+				return;
+			break;
+
+		case IDE_COMMAND_IDENTIFY:
+			{
+			PINQUIRYDATA	pinquiryData  = SCpnt->request_buffer;
+
+			if ( status & IDE_STATUS_DRQ )
+				{
+				insw (pports[PORT_DATA], &identifyData, sizeof (identifyData) >> 1);
+
+				memset (pinquiryData, 0, SCpnt->request_bufflen);		// Zero INQUIRY data structure.
+				pinquiryData->DeviceType = 0;
+				pinquiryData->Versions = 2;
+				pinquiryData->AdditionalLength = 35 - 4;
+
+				// Fill in vendor identification fields.
+				for ( z = 0;  z < 20;  z += 2 )
+					{
+					pinquiryData->VendorId[z]	  = ((UCHAR *)identifyData.ModelNumber)[z + 1];
+					pinquiryData->VendorId[z + 1] = ((UCHAR *)identifyData.ModelNumber)[z];
+					}
+
+				// Initialize unused portion of product id.
+				for ( z = 0;  z < 4;  z++ )
+					pinquiryData->ProductId[12 + z] = ' ';
+
+				// Move firmware revision from IDENTIFY data to
+				// product revision in INQUIRY data.
+				for ( z = 0;  z < 4;  z += 2 )
+					{
+					pinquiryData->ProductRevisionLevel[z]	 = ((UCHAR *)identifyData.FirmwareRevision)[z + 1];
+					pinquiryData->ProductRevisionLevel[z + 1] = ((UCHAR *)identifyData.FirmwareRevision)[z];
+					}
+
+				SCpnt->result = DID_OK << 16;
+				padapter->SCpnt = NULL;
+				SCpnt->scsi_done (SCpnt);
+				return;
+				}
+			break;
+			}
+
+		default:
+			SCpnt->result = DID_OK << 16;
+			padapter->SCpnt = NULL;
+			SCpnt->scsi_done (SCpnt);
+			return;
+		}
+
+irqerror:;
+	DEB(printk ("\npsi240i error  Device Status: %X\n", status));
+	SCpnt->result = DecodeError (shost, status);
+	SCpnt->scsi_done (SCpnt);
+	}
+
+static irqreturn_t do_Irq_Handler (int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave(dev->host_lock, flags);
+	Irq_Handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/****************************************************************
+ *	Name:	Psi240i_QueueCommand
+ *
+ *	Description:	Process a queued command from the SCSI manager.
+ *
+ *	Parameters:		SCpnt - Pointer to SCSI command structure.
+ *					done  - Pointer to done function to call.
+ *
+ *	Returns:		Status code.
+ *
+ ****************************************************************/
+static int Psi240i_QueueCommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+	{
+	UCHAR		   *cdb = (UCHAR *)SCpnt->cmnd;					// Pointer to SCSI CDB
+	PADAPTER240I	padapter = HOSTDATA (SCpnt->device->host); 			// Pointer to adapter control structure
+	POUR_DEVICE 		pdev	 = &padapter->device [SCpnt->device->id];// Pointer to device information
+	UCHAR			rc;											// command return code
+
+	SCpnt->scsi_done = done;
+	padapter->ide.ide.ides.spigot = pdev->spigot;
+	padapter->buffer = SCpnt->request_buffer;
+	if (done)
+		{
+		if ( !pdev->device )
+			{
+			SCpnt->result = DID_BAD_TARGET << 16;
+			done (SCpnt);
+			return 0;
+			}
+		}
+	else
+		{
+		printk("psi240i_queuecommand: %02X: done can't be NULL\n", *cdb);
+		return 0;
+		}
+
+	switch ( *cdb )
+		{
+		case SCSIOP_INQUIRY:   					// inquiry CDB
+			{
+			padapter->ide.ide.ide[6] = pdev->byte6;
+			padapter->ide.ide.ides.cmd = IDE_COMMAND_IDENTIFY;
+			break;
+			}
+
+		case SCSIOP_TEST_UNIT_READY:			// test unit ready CDB
+			SCpnt->result = DID_OK << 16;
+			done (SCpnt);
+			return 0;
+
+		case SCSIOP_READ_CAPACITY:			  	// read capctiy CDB
+			{
+			PREAD_CAPACITY_DATA	pdata = (PREAD_CAPACITY_DATA)SCpnt->request_buffer;
+
+			pdata->blksiz = 0x20000;
+			XANY2SCSI ((UCHAR *)&pdata->blks, pdev->blocks);
+			SCpnt->result = DID_OK << 16;
+			done (SCpnt);
+			return 0;
+			}
+
+		case SCSIOP_VERIFY:						// verify CDB
+			*(ULONG *)padapter->ide.ide.ides.lba = XSCSI2LONG (&cdb[2]);
+			padapter->ide.ide.ide[6] |= pdev->byte6;
+			padapter->ide.ide.ide[2] = (UCHAR)((USHORT)cdb[8] | ((USHORT)cdb[7] << 8));
+			padapter->ide.ide.ides.cmd = IDE_COMMAND_VERIFY;
+			break;
+
+		case SCSIOP_READ:						// read10 CDB
+			padapter->startSector = XSCSI2LONG (&cdb[2]);
+			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+			SetupTransfer (padapter, pdev->byte6);
+			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+			break;
+
+		case SCSIOP_READ6:						// read6  CDB
+			padapter->startSector = SCSI2LONG (&cdb[1]);
+			padapter->sectorCount = cdb[4];
+			SetupTransfer (padapter, pdev->byte6);
+			padapter->ide.ide.ides.cmd = IDE_CMD_READ_MULTIPLE;
+			break;
+
+		case SCSIOP_WRITE:						// write10 CDB
+			padapter->startSector = XSCSI2LONG (&cdb[2]);
+			padapter->sectorCount = (USHORT)cdb[8] | ((USHORT)cdb[7] << 8);
+			SetupTransfer (padapter, pdev->byte6);
+			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+			break;
+		case SCSIOP_WRITE6:						// write6  CDB
+			padapter->startSector = SCSI2LONG (&cdb[1]);
+			padapter->sectorCount = cdb[4];
+			SetupTransfer (padapter, pdev->byte6);
+			padapter->ide.ide.ides.cmd = IDE_CMD_WRITE_MULTIPLE;
+			break;
+
+		default:
+			DEB (printk ("psi240i_queuecommand: Unsupported command %02X\n", *cdb));
+			SCpnt->result = DID_ERROR << 16;
+			done (SCpnt);
+			return 0;
+		}
+
+	padapter->SCpnt = SCpnt;  									// Save this command data
+
+	rc = IdeCmd (padapter);
+	if ( rc )
+		{
+		padapter->expectingIRQ = 0;
+		DEB (printk ("psi240i_queuecommand: %02X, %02X: Device failed to respond for command\n", *cdb, padapter->ide.ide.ides.cmd));
+		SCpnt->result = DID_ERROR << 16;
+		done (SCpnt);
+		return 0;
+		}
+	DEB (printk("psi240i_queuecommand: %02X, %02X now waiting for interrupt ", *cdb, padapter->ide.ide.ides.cmd));
+	return 0;
+	}
+
+/***************************************************************************
+ *	Name:			ReadChipMemory
+ *
+ *	Description:	Read information from controller memory.
+ *
+ *	Parameters:		psetup	- Pointer to memory image of setup information.
+ *					base	- base address of memory.
+ *					length	- lenght of data space in bytes.
+ *					port	- I/O address of data port.
+ *
+ *	Returns:		Nothing.
+ *
+ **************************************************************************/
+static void ReadChipMemory (void *pdata, USHORT base, USHORT length, USHORT port)
+	{
+	USHORT	z, zz;
+	UCHAR	*pd = (UCHAR *)pdata;
+	outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup data port
+	zz = 0;
+	while ( zz < length )
+		{
+		outw_p (base, port + REG_ADDRESS);				// setup address
+
+		for ( z = 0;  z < 8;  z++ )
+			{
+			if ( (zz + z) < length )
+			*pd++ = inb_p (port + z);	// read data byte
+			}
+		zz += 8;
+		base += 8;
+		}
+	}
+/****************************************************************
+ *	Name:	Psi240i_Detect
+ *
+ *	Description:	Detect and initialize our boards.
+ *
+ *	Parameters:		tpnt - Pointer to SCSI host template structure.
+ *
+ *	Returns:		Number of adapters found.
+ *
+ ****************************************************************/
+static int Psi240i_Detect (Scsi_Host_Template *tpnt)
+	{
+	int					board;
+	int					count = 0;
+	int					unit;
+	int					z;
+	USHORT				port, port_range = 16;
+	CHIP_CONFIG_N		chipConfig;
+	CHIP_DEVICE_N		chipDevice[8];
+	struct Scsi_Host   *pshost;
+
+	for ( board = 0;  board < MAXBOARDS;  board++ )					// scan for I/O ports
+		{
+		pshost = NULL;
+		port = portAddr[board];								// get base address to test
+		if ( !request_region (port, port_range, "psi240i") )
+			continue;
+		if ( inb_p (port + REG_FAIL) != CHIP_ID )			// do the first test for likley hood that it is us
+			goto host_init_failure;
+		outb_p (SEL_NONE, port + REG_SEL_FAIL);				// setup EEPROM/RAM access
+		outw (0, port + REG_ADDRESS);						// setup EEPROM address zero
+		if ( inb_p (port) != 0x55 )							// test 1st byte
+			goto host_init_failure;									//   nope
+		if ( inb_p (port + 1) != 0xAA )						// test 2nd byte
+			goto host_init_failure;								//   nope
+
+		// at this point our board is found and can be accessed.  Now we need to initialize
+		// our informatation and register with the kernel.
+
+
+		ReadChipMemory (&chipConfig, CHIP_CONFIG, sizeof (chipConfig), port);
+		ReadChipMemory (&chipDevice, CHIP_DEVICE, sizeof (chipDevice), port);
+		ReadChipMemory (&ChipSetup, CHIP_EEPROM_DATA, sizeof (ChipSetup), port);
+
+		if ( !chipConfig.numDrives )						// if no devices on this board
+			goto host_init_failure;
+
+		pshost = scsi_register (tpnt, sizeof(ADAPTER240I));
+		if(pshost == NULL)
+			goto host_init_failure;	
+
+		PsiHost[chipConfig.irq - 10] = pshost;
+		pshost->unique_id = port;
+		pshost->io_port = port;
+		pshost->n_io_port = 16;  /* Number of bytes of I/O space used */
+		pshost->irq = chipConfig.irq;
+
+		for ( z = 0;  z < 11;  z++ )						// build regester address array
+			HOSTDATA(pshost)->ports[z] = port + z;
+		HOSTDATA(pshost)->ports[11] = port + REG_FAIL;
+		HOSTDATA(pshost)->ports[12] = port + REG_ALT_STAT;
+		DEB (printk ("\nPorts ="));
+		DEB (for (z=0;z<13;z++) printk(" %#04X",HOSTDATA(pshost)->ports[z]););
+
+		for ( z = 0;  z < chipConfig.numDrives;  ++z )
+			{
+			unit = chipDevice[z].channel & 0x0F;
+			HOSTDATA(pshost)->device[unit].device	 = ChipSetup.setupDevice[unit].device;
+			HOSTDATA(pshost)->device[unit].byte6	 = (UCHAR)(((unit & 1) << 4) | 0xE0);
+			HOSTDATA(pshost)->device[unit].spigot	 = (UCHAR)(1 << (unit >> 1));
+			HOSTDATA(pshost)->device[unit].sectors	 = ChipSetup.setupDevice[unit].sectors;
+			HOSTDATA(pshost)->device[unit].heads	 = ChipSetup.setupDevice[unit].heads;
+			HOSTDATA(pshost)->device[unit].cylinders = ChipSetup.setupDevice[unit].cylinders;
+			HOSTDATA(pshost)->device[unit].blocks	 = ChipSetup.setupDevice[unit].blocks;
+			DEB (printk ("\nHOSTDATA->device    = %X", HOSTDATA(pshost)->device[unit].device));
+			DEB (printk ("\n          byte6     = %X", HOSTDATA(pshost)->device[unit].byte6));
+			DEB (printk ("\n          spigot    = %X", HOSTDATA(pshost)->device[unit].spigot));
+			DEB (printk ("\n          sectors   = %X", HOSTDATA(pshost)->device[unit].sectors));
+			DEB (printk ("\n          heads     = %X", HOSTDATA(pshost)->device[unit].heads));
+			DEB (printk ("\n          cylinders = %X", HOSTDATA(pshost)->device[unit].cylinders));
+			DEB (printk ("\n          blocks    = %lX", HOSTDATA(pshost)->device[unit].blocks));
+			}
+
+		if ( request_irq (chipConfig.irq, do_Irq_Handler, 0, "psi240i", pshost) == 0 ) 
+			{
+			printk("\nPSI-240I EIDE CONTROLLER: at I/O = %x  IRQ = %d\n", port, chipConfig.irq);
+		        printk("(C) 1997 Perceptive Solutions, Inc. All rights reserved\n\n");
+		        count++;
+		        continue;
+			}
+
+		printk ("Unable to allocate IRQ for PSI-240I controller.\n");
+           
+host_init_failure:
+		
+		release_region (port, port_range);
+		if (pshost)
+			scsi_unregister (pshost);
+
+		}
+	return count;
+	}
+
+static int Psi240i_Release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+/****************************************************************
+ *	Name:	Psi240i_BiosParam
+ *
+ *	Description:	Process the biosparam request from the SCSI manager to
+ *					return C/H/S data.
+ *
+ *	Parameters:		disk - Pointer to SCSI disk structure.
+ *					dev	 - Major/minor number from kernel.
+ *					geom - Pointer to integer array to place geometry data.
+ *
+ *	Returns:		zero.
+ *
+ ****************************************************************/
+static int Psi240i_BiosParam (struct scsi_device *sdev, struct block_device *dev,
+		sector_t capacity, int geom[])
+	{
+	POUR_DEVICE	pdev;
+
+	pdev = &(HOSTDATA(sdev->host)->device[sdev->id]);
+
+	geom[0] = pdev->heads;
+	geom[1] = pdev->sectors;
+	geom[2] = pdev->cylinders;
+	return 0;
+	}
+
+MODULE_LICENSE("GPL");
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "psi240i", 
+	.name			= "PSI-240I EIDE Disk Controller",
+	.detect			= Psi240i_Detect,
+	.release		= Psi240i_Release,
+	.queuecommand		= Psi240i_QueueCommand,
+	.bios_param	  	= Psi240i_BiosParam,
+	.can_queue	  	= 1,
+	.this_id	  	= -1,
+	.sg_tablesize	  	= SG_NONE,
+	.cmd_per_lun	  	= 1, 
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
new file mode 100644
index 0000000..6a59876
--- /dev/null
+++ b/drivers/scsi/psi240i.h
@@ -0,0 +1,315 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *	File Name:		psi240i.h
+ *
+ *	Description:	Header file for the SCSI driver for the PSI240I
+ *					EIDE interface card.
+ *
+ *-M*************************************************************************/
+#ifndef _PSI240I_H
+#define _PSI240I_H
+
+#include <linux/types.h>
+
+#ifndef	PSI_EIDE_SCSIOP
+#define	PSI_EIDE_SCSIOP	1
+
+/************************************************/
+/*		Some defines that we like 				*/
+/************************************************/
+#define	CHAR		char
+#define	UCHAR		unsigned char
+#define	SHORT		short
+#define	USHORT		unsigned short
+#define	BOOL		unsigned short
+#define	LONG		long
+#define	ULONG		unsigned long
+#define	VOID		void
+
+/************************************************/
+/*		Timeout konstants		 				*/
+/************************************************/
+#define	TIMEOUT_READY				10		// 100 mSec
+#define	TIMEOUT_DRQ					40		// 400 mSec
+
+/************************************************/
+/*		Misc. macros			 				*/
+/************************************************/
+#define ANY2SCSI(up, p)					\
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up)					\
+( (((long)*(((UCHAR *)up))) << 16)		\
++ (((long)(((UCHAR *)up)[1])) << 8)		\
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p)				\
+((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
+((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
+((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up)					\
+( (((long)(((UCHAR *)up)[0])) << 24)	\
++ (((long)(((UCHAR *)up)[1])) << 16)	\
++ (((long)(((UCHAR *)up)[2])) <<  8)	\
++ ((long)(((UCHAR *)up)[3])) )
+
+/************************************************/
+/*		SCSI CDB operation codes 				*/
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY		0x00
+#define SCSIOP_REZERO_UNIT			0x01
+#define SCSIOP_REWIND				0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
+#define SCSIOP_REQUEST_SENSE		0x03
+#define SCSIOP_FORMAT_UNIT			0x04
+#define SCSIOP_READ_BLOCK_LIMITS	0x05
+#define SCSIOP_REASSIGN_BLOCKS		0x07
+#define SCSIOP_READ6				0x08
+#define SCSIOP_RECEIVE				0x08
+#define SCSIOP_WRITE6				0x0A
+#define SCSIOP_PRINT				0x0A
+#define SCSIOP_SEND					0x0A
+#define SCSIOP_SEEK6				0x0B
+#define SCSIOP_TRACK_SELECT			0x0B
+#define SCSIOP_SLEW_PRINT			0x0B
+#define SCSIOP_SEEK_BLOCK			0x0C
+#define SCSIOP_PARTITION			0x0D
+#define SCSIOP_READ_REVERSE			0x0F
+#define SCSIOP_WRITE_FILEMARKS		0x10
+#define SCSIOP_FLUSH_BUFFER			0x10
+#define SCSIOP_SPACE				0x11
+#define SCSIOP_INQUIRY				0x12
+#define SCSIOP_VERIFY6				0x13
+#define SCSIOP_RECOVER_BUF_DATA		0x14
+#define SCSIOP_MODE_SELECT			0x15
+#define SCSIOP_RESERVE_UNIT			0x16
+#define SCSIOP_RELEASE_UNIT			0x17
+#define SCSIOP_COPY					0x18
+#define SCSIOP_ERASE				0x19
+#define SCSIOP_MODE_SENSE			0x1A
+#define SCSIOP_START_STOP_UNIT		0x1B
+#define SCSIOP_STOP_PRINT			0x1B
+#define SCSIOP_LOAD_UNLOAD			0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
+#define SCSIOP_SEND_DIAGNOSTIC		0x1D
+#define SCSIOP_MEDIUM_REMOVAL		0x1E
+#define SCSIOP_READ_CAPACITY		0x25
+#define SCSIOP_READ					0x28
+#define SCSIOP_WRITE				0x2A
+#define SCSIOP_SEEK					0x2B
+#define SCSIOP_LOCATE				0x2B
+#define SCSIOP_WRITE_VERIFY			0x2E
+#define SCSIOP_VERIFY				0x2F
+#define SCSIOP_SEARCH_DATA_HIGH		0x30
+#define SCSIOP_SEARCH_DATA_EQUAL	0x31
+#define SCSIOP_SEARCH_DATA_LOW		0x32
+#define SCSIOP_SET_LIMITS			0x33
+#define SCSIOP_READ_POSITION		0x34
+#define SCSIOP_SYNCHRONIZE_CACHE	0x35
+#define SCSIOP_COMPARE				0x39
+#define SCSIOP_COPY_COMPARE			0x3A
+#define SCSIOP_WRITE_DATA_BUFF		0x3B
+#define SCSIOP_READ_DATA_BUFF		0x3C
+#define SCSIOP_CHANGE_DEFINITION	0x40
+#define SCSIOP_READ_SUB_CHANNEL		0x42
+#define SCSIOP_READ_TOC				0x43
+#define SCSIOP_READ_HEADER			0x44
+#define SCSIOP_PLAY_AUDIO			0x45
+#define SCSIOP_PLAY_AUDIO_MSF		0x47
+#define SCSIOP_PLAY_TRACK_INDEX		0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
+#define SCSIOP_PAUSE_RESUME			0x4B
+#define SCSIOP_LOG_SELECT			0x4C
+#define SCSIOP_LOG_SENSE			0x4D
+#define SCSIOP_MODE_SELECT10		0x55
+#define SCSIOP_MODE_SENSE10			0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
+#define SCSIOP_MECHANISM_STATUS		0xBD
+#define SCSIOP_READ_CD				0xBE
+
+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET		0x08
+#define IDE_COMMAND_READ			0x20
+#define IDE_COMMAND_WRITE			0x30
+#define IDE_COMMAND_RECALIBRATE		0x10
+#define IDE_COMMAND_SEEK			0x70
+#define IDE_COMMAND_SET_PARAMETERS	0x91
+#define IDE_COMMAND_VERIFY			0x40
+#define IDE_COMMAND_ATAPI_PACKET	0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
+#define	IDE_CMD_READ_MULTIPLE		0xC4
+#define	IDE_CMD_WRITE_MULTIPLE		0xC5
+#define	IDE_CMD_SET_MULTIPLE		0xC6
+#define IDE_COMMAND_WRITE_DMA		0xCA
+#define IDE_COMMAND_READ_DMA		0xC8
+#define IDE_COMMAND_IDENTIFY		0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR			0x01
+#define IDE_STATUS_INDEX			0x02
+#define IDE_STATUS_CORRECTED_ERROR	0x04
+#define IDE_STATUS_DRQ				0x08
+#define IDE_STATUS_DSC				0x10
+#define	IDE_STATUS_WRITE_FAULT		0x20
+#define IDE_STATUS_DRDY				0x40
+#define IDE_STATUS_BUSY				0x80
+
+// IDE error definitions
+#define	IDE_ERROR_AMNF				0x01
+#define	IDE_ERROR_TKONF				0x02
+#define	IDE_ERROR_ABRT				0x04
+#define	IDE_ERROR_MCR				0x08
+#define	IDE_ERROR_IDFN				0x10
+#define	IDE_ERROR_MC				0x20
+#define	IDE_ERROR_UNC				0x40
+#define	IDE_ERROR_BBK				0x80
+
+//	IDE interface structure
+typedef struct _IDE_STRUCT
+	{
+	union
+		{
+		UCHAR	ide[9];
+		struct
+			{
+			USHORT	data;
+			UCHAR	sectors;
+			UCHAR	lba[4];
+			UCHAR	cmd;
+			UCHAR	spigot;
+			}	ides;
+		} ide;
+	}	IDE_STRUCT;
+
+// SCSI read capacity structure
+typedef	struct _READ_CAPACITY_DATA
+	{
+	ULONG blks;				/* total blocks (converted to little endian) */
+	ULONG blksiz;			/* size of each (converted to little endian) */
+	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+#ifndef HOSTS_C
+
+typedef struct _INQUIRYDATA
+	{
+	UCHAR DeviceType			:5;
+	UCHAR DeviceTypeQualifier	:3;
+	UCHAR DeviceTypeModifier	:7;
+	UCHAR RemovableMedia		:1;
+    UCHAR Versions;
+    UCHAR ResponseDataFormat;
+    UCHAR AdditionalLength;
+    UCHAR Reserved[2];
+	UCHAR SoftReset				:1;
+	UCHAR CommandQueue			:1;
+	UCHAR Reserved2				:1;
+	UCHAR LinkedCommands		:1;
+	UCHAR Synchronous			:1;
+	UCHAR Wide16Bit				:1;
+	UCHAR Wide32Bit				:1;
+	UCHAR RelativeAddressing	:1;
+    UCHAR VendorId[8];
+    UCHAR ProductId[16];
+    UCHAR ProductRevisionLevel[4];
+    UCHAR VendorSpecific[20];
+    UCHAR Reserved3[40];
+	}	INQUIRYDATA, *PINQUIRYDATA;
+#endif
+
+// IDE IDENTIFY data
+typedef struct _IDENTIFY_DATA
+	{
+    USHORT GeneralConfiguration;            // 00
+    USHORT NumberOfCylinders;               // 02
+    USHORT Reserved1;                       // 04
+    USHORT NumberOfHeads;                   // 06
+    USHORT UnformattedBytesPerTrack;        // 08
+    USHORT UnformattedBytesPerSector;       // 0A
+    USHORT SectorsPerTrack;                 // 0C
+    USHORT VendorUnique1[3];                // 0E
+    USHORT SerialNumber[10];                // 14
+    USHORT BufferType;                      // 28
+    USHORT BufferSectorSize;                // 2A
+    USHORT NumberOfEccBytes;                // 2C
+    USHORT FirmwareRevision[4];             // 2E
+    USHORT ModelNumber[20];                 // 36
+    UCHAR  MaximumBlockTransfer;            // 5E
+    UCHAR  VendorUnique2;                   // 5F
+    USHORT DoubleWordIo;                    // 60
+    USHORT Capabilities;                    // 62
+    USHORT Reserved2;                       // 64
+    UCHAR  VendorUnique3;                   // 66
+    UCHAR  PioCycleTimingMode;              // 67
+    UCHAR  VendorUnique4;                   // 68
+    UCHAR  DmaCycleTimingMode;              // 69
+    USHORT TranslationFieldsValid:1;        // 6A
+    USHORT Reserved3:15;
+    USHORT NumberOfCurrentCylinders;        // 6C
+    USHORT NumberOfCurrentHeads;            // 6E
+    USHORT CurrentSectorsPerTrack;          // 70
+    ULONG  CurrentSectorCapacity;           // 72
+    USHORT Reserved4[197];                  // 76
+	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// Identify data without the Reserved4.
+typedef struct _IDENTIFY_DATA2 {
+    USHORT GeneralConfiguration;            // 00
+    USHORT NumberOfCylinders;               // 02
+    USHORT Reserved1;                       // 04
+    USHORT NumberOfHeads;                   // 06
+    USHORT UnformattedBytesPerTrack;        // 08
+    USHORT UnformattedBytesPerSector;       // 0A
+    USHORT SectorsPerTrack;                 // 0C
+    USHORT VendorUnique1[3];                // 0E
+    USHORT SerialNumber[10];                // 14
+    USHORT BufferType;                      // 28
+    USHORT BufferSectorSize;                // 2A
+    USHORT NumberOfEccBytes;                // 2C
+    USHORT FirmwareRevision[4];             // 2E
+    USHORT ModelNumber[20];                 // 36
+    UCHAR  MaximumBlockTransfer;            // 5E
+    UCHAR  VendorUnique2;                   // 5F
+    USHORT DoubleWordIo;                    // 60
+    USHORT Capabilities;                    // 62
+    USHORT Reserved2;                       // 64
+    UCHAR  VendorUnique3;                   // 66
+    UCHAR  PioCycleTimingMode;              // 67
+    UCHAR  VendorUnique4;                   // 68
+    UCHAR  DmaCycleTimingMode;              // 69
+	USHORT TranslationFieldsValid:1;     	// 6A
+    USHORT Reserved3:15;
+    USHORT NumberOfCurrentCylinders;        // 6C
+    USHORT NumberOfCurrentHeads;            // 6E
+    USHORT CurrentSectorsPerTrack;          // 70
+    ULONG  CurrentSectorCapacity;           // 72
+	}	IDENTIFY_DATA2, *PIDENTIFY_DATA2;
+
+#endif	// PSI_EIDE_SCSIOP
+
+// function prototypes
+int Psi240i_Command			(Scsi_Cmnd *SCpnt);
+int Psi240i_Abort			(Scsi_Cmnd *SCpnt);
+int Psi240i_Reset			(Scsi_Cmnd *SCpnt, unsigned int flags);
+#endif
diff --git a/drivers/scsi/psi_chip.h b/drivers/scsi/psi_chip.h
new file mode 100644
index 0000000..224cf8f
--- /dev/null
+++ b/drivers/scsi/psi_chip.h
@@ -0,0 +1,195 @@
+/*+M*************************************************************************
+ * Perceptive Solutions, Inc. PSI-240I device driver proc support for Linux.
+ *
+ * Copyright (c) 1997 Perceptive Solutions, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ *	File Name:	psi_chip.h
+ *
+ *	Description:	This file contains the interface defines and
+ *					error codes.
+ *
+ *-M*************************************************************************/
+#ifndef PSI_CHIP
+#define PSI_CHIP
+
+/************************************************/
+/*		Misc konstants							*/
+/************************************************/
+#define	CHIP_MAXDRIVES			8
+
+/************************************************/
+/*		Chip I/O addresses						*/
+/************************************************/
+#define	CHIP_ADRS_0				0x0130
+#define	CHIP_ADRS_1				0x0150
+#define	CHIP_ADRS_2				0x0190
+#define	CHIP_ADRS_3				0x0210
+#define	CHIP_ADRS_4				0x0230
+#define	CHIP_ADRS_5				0x0250
+
+/************************************************/
+/*		EEPROM locations		*/
+/************************************************/
+#define	CHIP_EEPROM_BIOS		0x0000		// BIOS base address
+#define	CHIP_EEPROM_DATA		0x2000	   	// SETUP data base address
+#define	CHIP_EEPROM_FACTORY		0x2400	   	// FACTORY data base address
+#define	CHIP_EEPROM_SETUP		0x3000	   	// SETUP PROGRAM base address
+
+#define	CHIP_EEPROM_SIZE		32768U	   	// size of the entire EEPROM
+#define	CHIP_EEPROM_BIOS_SIZE	8192	   	// size of the BIOS in bytes
+#define	CHIP_EEPROM_DATA_SIZE	4096	   	// size of factory, setup, log data block in bytes
+#define	CHIP_EEPROM_SETUP_SIZE	20480U	   	// size of the setup program in bytes
+
+/************************************************/
+/*		Chip Interrupts							*/
+/************************************************/
+#define	CHIP_IRQ_10				0x72
+#define	CHIP_IRQ_11				0x73
+#define	CHIP_IRQ_12				0x74
+
+/************************************************/
+/*		Chip Setup addresses		*/
+/************************************************/
+#define	CHIP_SETUP_BASE			0x0000C000L
+
+/************************************************/
+/*		Chip Register address offsets	*/
+/************************************************/
+#define	REG_DATA				0x00
+#define	REG_ERROR				0x01
+#define	REG_SECTOR_COUNT		0x02
+#define	REG_LBA_0				0x03
+#define	REG_LBA_8				0x04
+#define	REG_LBA_16				0x05
+#define	REG_LBA_24				0x06
+#define	REG_STAT_CMD			0x07
+#define	REG_SEL_FAIL			0x08
+#define	REG_IRQ_STATUS			0x09
+#define	REG_ADDRESS				0x0A
+#define	REG_FAIL				0x0C
+#define	REG_ALT_STAT		   	0x0E
+#define	REG_DRIVE_ADRS			0x0F
+
+/************************************************/
+/*		Chip RAM locations		*/
+/************************************************/
+#define	CHIP_DEVICE				0x8000
+#define	CHIP_DEVICE_0			0x8000
+#define CHIP_DEVICE_1			0x8008
+#define	CHIP_DEVICE_2			0x8010
+#define	CHIP_DEVICE_3			0x8018
+#define	CHIP_DEVICE_4			0x8020
+#define	CHIP_DEVICE_5			0x8028
+#define	CHIP_DEVICE_6			0x8030
+#define	CHIP_DEVICE_7			0x8038
+typedef struct
+	{
+	UCHAR	channel;		// channel of this device (0-8).
+	UCHAR	spt;			// Sectors Per Track.
+	ULONG	spc;			// Sectors Per Cylinder.
+	}	CHIP_DEVICE_N;
+
+#define	CHIP_CONFIG				0x8100		// address of boards configuration.
+typedef struct
+	{
+	UCHAR		irq;			// interrupt request channel number
+	UCHAR		numDrives;		// Number of accessible drives
+	UCHAR		fastFormat;	 	// Boolean for fast format enable
+	}	CHIP_CONFIG_N;
+
+#define	CHIP_MAP				0x8108 		// eight byte device type map.
+
+
+#define	CHIP_RAID				0x8120 		// array of RAID signature structures and LBA
+#define	CHIP_RAID_1				0x8120
+#define CHIP_RAID_2				0x8130
+#define	CHIP_RAID_3				0x8140
+#define	CHIP_RAID_4				0x8150
+
+/************************************************/
+/*		Chip Register Masks		*/
+/************************************************/
+#define	CHIP_ID					0x7B
+#define	SEL_RAM					0x8000
+#define	MASK_FAIL				0x80
+
+/************************************************/
+/*		Chip cable select bits		*/
+/************************************************/
+#define	SECTORSXFER				8
+
+/************************************************/
+/*		Chip cable select bits		*/
+/************************************************/
+#define	SEL_NONE				0x00
+#define	SEL_1					0x01
+#define	SEL_2					0x02
+#define	SEL_3					0x04
+#define	SEL_4					0x08
+
+/************************************************/
+/*		Programmable Interrupt Controller*/
+/************************************************/
+#define	PIC1					0x20		// first 8259 base port address
+#define	PIC2					0xA0		// second 8259 base port address
+#define	INT_OCW1				1			// Operation Control Word 1: IRQ mask
+#define	EOI						0x20		// non-specific end-of-interrupt
+
+/************************************************/
+/*		Device/Geometry controls				*/
+/************************************************/
+#define GEOMETRY_NONE		 	0x0			// No device
+#define GEOMETRY_AUTO			0x1			// Geometry set automatically
+#define GEOMETRY_USER		 	0x2			// User supplied geometry
+
+#define	DEVICE_NONE				0x0			// No device present
+#define	DEVICE_INACTIVE			0x1			// device present but not registered active
+#define	DEVICE_ATAPI			0x2			// ATAPI device (CD_ROM, Tape, Etc...)
+#define	DEVICE_DASD_NONLBA		0x3			// Non LBA incompatible device
+#define	DEVICE_DASD_LBA			0x4			// LBA compatible device
+
+/************************************************/
+/*		Setup Structure Definitions	*/
+/************************************************/
+typedef struct							// device setup parameters
+	{
+	UCHAR			geometryControl;	// geometry control flags
+	UCHAR		   	device;				// device code
+	USHORT			sectors;			// number of sectors per track
+	USHORT			heads;				// number of heads
+	USHORT			cylinders;			// number of cylinders for this device
+	ULONG			blocks;				// number of blocks on device
+	USHORT			spare1;
+	USHORT			spare2;
+	} SETUP_DEVICE, *PSETUP_DEVICE;
+
+typedef struct		// master setup structure
+	{
+	USHORT 			startupDelay;
+	USHORT 			promptBIOS;
+	USHORT 			fastFormat;
+	USHORT			spare2;
+	USHORT			spare3;
+	USHORT			spare4;
+	USHORT			spare5;
+	USHORT			spare6;
+	SETUP_DEVICE	setupDevice[8];
+	}	SETUP, *PSETUP;
+
+#endif
+
diff --git a/drivers/scsi/psi_dale.h b/drivers/scsi/psi_dale.h
new file mode 100644
index 0000000..d672e3b
--- /dev/null
+++ b/drivers/scsi/psi_dale.h
@@ -0,0 +1,564 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2220I device driver for Linux.
+ *
+ * psi_dalei.h - Linux Host Driver for PCI-2220i EIDE Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ ****************************************************************************/
+
+/************************************************/
+/*		Some defines that we like 				*/
+/************************************************/
+#define	CHAR		char
+#define	UCHAR		unsigned char
+#define	SHORT		short
+#define	USHORT		unsigned short
+#define	BOOL		unsigned short
+#define	LONG		long
+#define	ULONG		unsigned long
+#define	VOID		void
+
+/************************************************/
+/*		Dale PCI setup							*/
+/************************************************/
+#define	VENDOR_PSI			0x1256
+#define	DEVICE_DALE_1		0x4401		/* 'D1' */
+#define	DEVICE_BIGD_1		0x4201		/* 'B1' */
+#define	DEVICE_BIGD_2		0x4202		/* 'B2' */
+
+/************************************************/
+/*		Misc konstants							*/
+/************************************************/
+#define	DALE_MAXDRIVES			4
+#define	BIGD_MAXDRIVES			8
+#define	SECTORSXFER				8
+#define	ATAPI_TRANSFER			8192
+#define	BYTES_PER_SECTOR		512
+#define	DEFAULT_TIMING_MODE		5
+
+/************************************************/
+/*		EEPROM locations						*/
+/************************************************/
+#define	DALE_FLASH_PAGE_SIZE	128				// number of bytes per page
+#define	DALE_FLASH_SIZE			65536L
+
+#define	DALE_FLASH_BIOS			0x00080000L		// BIOS base address
+#define	DALE_FLASH_SETUP		0x00088000L		// SETUP PROGRAM base address offset from BIOS
+#define	DALE_FLASH_RAID			0x00088400L		// RAID signature storage
+#define	DALE_FLASH_FACTORY		0x00089000L		// FACTORY data base address offset from BIOS
+
+#define	DALE_FLASH_BIOS_SIZE	32768U			// size of FLASH BIOS REGION
+
+/************************************************/
+/*		DALE Register address offsets			*/
+/************************************************/
+#define	REG_DATA					0x80
+#define	REG_ERROR					0x84
+#define	REG_SECTOR_COUNT			0x88
+#define	REG_LBA_0					0x8C
+#define	REG_LBA_8					0x90
+#define	REG_LBA_16					0x94
+#define	REG_LBA_24					0x98
+#define	REG_STAT_CMD				0x9C
+#define	REG_STAT_SEL				0xA0
+#define	REG_FAIL					0xB0
+#define	REG_ALT_STAT				0xB8
+#define	REG_DRIVE_ADRS				0xBC
+
+#define	DALE_DATA_SLOW				0x00040000L
+#define	DALE_DATA_MODE2				0x00040000L
+#define	DALE_DATA_MODE3				0x00050000L
+#define	DALE_DATA_MODE4				0x00060000L
+#define	DALE_DATA_MODE5				0x00070000L
+
+#define	BIGD_DATA_SLOW				0x00000000L
+#define	BIGD_DATA_MODE0				0x00000000L
+#define	BIGD_DATA_MODE2				0x00000000L
+#define	BIGD_DATA_MODE3				0x00000008L
+#define	BIGD_DATA_MODE4				0x00000010L
+#define	BIGD_DATA_MODE5				0x00000020L
+
+#define RTR_LOCAL_RANGE				0x000
+#define RTR_LOCAL_REMAP				0x004
+#define RTR_EXP_RANGE				0x010
+#define RTR_EXP_REMAP				0x014
+#define RTR_REGIONS					0x018
+#define RTR_DM_MASK					0x01C
+#define RTR_DM_LOCAL_BASE			0x020
+#define RTR_DM_IO_BASE				0x024
+#define RTR_DM_PCI_REMAP			0x028
+#define RTR_DM_IO_CONFIG			0x02C
+#define RTR_MAILBOX					0x040
+#define RTR_LOCAL_DOORBELL			0x060
+#define RTR_PCI_DOORBELL			0x064
+#define RTR_INT_CONTROL_STATUS 		0x068
+#define RTR_EEPROM_CONTROL_STATUS	0x06C
+
+#define RTR_DMA0_MODE				0x0080
+#define RTR_DMA0_PCI_ADDR			0x0084
+#define RTR_DMA0_LOCAL_ADDR			0x0088
+#define RTR_DMA0_COUNT				0x008C
+#define RTR_DMA0_DESC_PTR			0x0090
+#define RTR_DMA1_MODE				0x0094
+#define RTR_DMA1_PCI_ADDR			0x0098
+#define RTR_DMA1_LOCAL_ADDR			0x009C
+#define RTR_DMA1_COUNT				0x00A0
+#define RTR_DMA1_DESC_PTR			0x00A4
+#define RTR_DMA_COMMAND_STATUS		0x00A8
+#define RTR_DMA_ARB0				0x00AC
+#define RTR_DMA_ARB1				0x00B0
+
+#define RTL_DMA0_MODE				0x00
+#define RTL_DMA0_PCI_ADDR			0x04
+#define RTL_DMA0_LOCAL_ADDR			0x08
+#define RTL_DMA0_COUNT				0x0C
+#define RTL_DMA0_DESC_PTR			0x10
+#define RTL_DMA1_MODE				0x14
+#define RTL_DMA1_PCI_ADDR			0x18
+#define RTL_DMA1_LOCAL_ADDR			0x1C
+#define RTL_DMA1_COUNT				0x20
+#define RTL_DMA1_DESC_PTR			0x24
+#define RTL_DMA_COMMAND_STATUS		0x28
+#define RTL_DMA_ARB0				0x2C
+#define RTL_DMA_ARB1				0x30
+
+/************************************************/
+/*		Dale Scratchpad locations				*/
+/************************************************/
+#define	DALE_CHANNEL_DEVICE_0		0		// device channel locations
+#define	DALE_CHANNEL_DEVICE_1		1
+#define	DALE_CHANNEL_DEVICE_2		2
+#define	DALE_CHANNEL_DEVICE_3		3
+
+#define	DALE_SCRATCH_DEVICE_0		4		// device type codes
+#define	DALE_SCRATCH_DEVICE_1		5
+#define DALE_SCRATCH_DEVICE_2		6
+#define	DALE_SCRATCH_DEVICE_3		7
+
+#define	DALE_RAID_0_STATUS			8
+#define DALE_RAID_1_STATUS			9
+
+#define	DALE_TIMING_MODE			12		// bus master timing mode (2, 3, 4, 5)
+#define	DALE_NUM_DRIVES				13		// number of addressable drives on this board
+#define	DALE_RAID_ON				14 		// RAID status On
+#define	DALE_LAST_ERROR				15		// Last error code from BIOS
+
+/************************************************/
+/*		BigD Scratchpad locations				*/
+/************************************************/
+#define	BIGD_DEVICE_0			0		// device channel locations
+#define	BIGD_DEVICE_1			1
+#define	BIGD_DEVICE_2			2
+#define	BIGD_DEVICE_3			3
+
+#define	BIGD_DEVICE_4			4		// device type codes
+#define	BIGD_DEVICE_5			5
+#define BIGD_DEVICE_6			6
+#define	BIGD_DEVICE_7			7
+
+#define	BIGD_ALARM_IMAGE		11		// ~image of alarm fail register		
+#define	BIGD_TIMING_MODE		12		// bus master timing mode (2, 3, 4, 5)
+#define	BIGD_NUM_DRIVES			13		// number of addressable drives on this board
+#define	BIGD_RAID_ON			14 		// RAID status is on for the whole board
+#define	BIGD_LAST_ERROR			15		// Last error code from BIOS
+
+#define	BIGD_RAID_0_STATUS		16
+#define BIGD_RAID_1_STATUS		17
+#define	BIGD_RAID_2_STATUS		18
+#define	BIGD_RAID_3_STATUS		19
+#define	BIGD_RAID_4_STATUS		20
+#define BIGD_RAID_5_STATUS		21
+#define	BIGD_RAID_6_STATUS		22
+#define	BIGD_RAID_7_STATUS		23
+
+/************************************************/
+/*		Dale cable select bits					*/
+/************************************************/
+#define	SEL_NONE					0x00
+#define	SEL_1						0x01
+#define	SEL_2						0x02
+#define	SEL_3						0x04
+#define	SEL_4						0x08
+#define	SEL_NEW_SPEED_1				0x20
+#define	SEL_COPY					0x40
+#define	SEL_IRQ_OFF					0x80
+
+/************************************************/
+/*		Device/Geometry controls				*/
+/************************************************/
+#define GEOMETRY_NONE	 			0x0				// No device
+#define GEOMETRY_SET				0x1				// Geometry set
+#define	GEOMETRY_LBA				0x2				// Geometry set in default LBA mode
+#define	GEOMETRY_PHOENIX			0x3				// Geometry set in Pheonix BIOS compatibility mode
+
+#define	DEVICE_NONE					0x0				// No device present
+#define	DEVICE_INACTIVE				0x1				// device present but not registered active
+#define	DEVICE_ATAPI				0x2				// ATAPI device (CD_ROM, Tape, Etc...)
+#define	DEVICE_DASD_NONLBA			0x3				// Non LBA incompatible device
+#define	DEVICE_DASD_LBA				0x4				// LBA compatible device
+
+/************************************************/
+/*		BigD fail register bits					*/
+/************************************************/
+#define	FAIL_NONE				0x00
+#define	FAIL_0					0x01
+#define	FAIL_1					0x02
+#define	FAIL_2					0x04
+#define	FAIL_MULTIPLE			0x08
+#define	FAIL_GOOD				0x20
+#define	FAIL_AUDIBLE			0x40
+#define	FAIL_ANY				0x80
+
+/************************************************/
+/*		Setup Structure Definitions				*/
+/************************************************/
+typedef struct		// device setup parameters
+	{
+	UCHAR	geometryControl;	// geometry control flags
+	UCHAR	device;				// device code
+	USHORT	sectors;			// number of sectors per track
+	USHORT	heads;				// number of heads
+	USHORT	cylinders;			// number of cylinders for this device
+	ULONG	blocks;				// number of blocks on device
+	ULONG	realCapacity;		// number of real blocks on this device for drive changed testing
+	} SETUP_DEVICE, *PSETUP_DEVICE;
+
+typedef struct		// master setup structure
+	{
+	USHORT			startupDelay;
+	BOOL			promptBIOS;
+	BOOL			fastFormat;
+	BOOL			shareInterrupt;
+	BOOL			rebootRebuild;
+	USHORT			timingMode;
+	USHORT			spare5;
+	USHORT			spare6;
+	SETUP_DEVICE	setupDevice[BIGD_MAXDRIVES];
+	}	SETUP, *PSETUP;
+
+/************************************************/
+/*		RAID Structure Definitions				*/
+/************************************************/
+typedef	struct
+	{
+	UCHAR	signature;			// 0x55 our mirror signature
+	UCHAR	status;				// current status bits
+	UCHAR	pairIdentifier;		// unique identifier for pair
+	ULONG	reconstructPoint;	// recontruction point for hot reconstruct
+	}	DISK_MIRROR;
+
+typedef struct	DEVICE_RAID1
+	{
+	long		TotalSectors;
+	DISK_MIRROR DiskRaid1;
+	}	DEVICE_RAID1, *PDEVICE_RAID1;
+
+#define	DISK_MIRROR_POSITION	0x01A8
+#define	SIGNATURE				0x55
+
+#define	MASK_SERIAL_NUMBER	0x0FFE			// mask for serial number matching
+#define	MASK_SERIAL_UNIT	0x0001			// mask for unit portion of serial number
+
+// Status bits
+#define	UCBF_MIRRORED		0x0010								// drive has a pair
+#define	UCBF_MATCHED		0x0020								// drive pair is matched
+#define	UCBF_SURVIVOR		0x0040								// this unit is a survivor of a pair
+#define	UCBF_REBUILD		0x0080								// rebuild in progress on this device
+
+// SCSI controls for RAID
+#define	SC_MY_RAID			0xBF			// our special CDB command byte for Win95... interface
+#define	MY_SCSI_QUERY1		0x32			// byte 1 subcommand to query driver for RAID 1 informatation
+#define	MY_SCSI_REBUILD		0x40			// byte 1 subcommand to reconstruct a mirrored pair
+#define MY_SCSI_DEMOFAIL	0x54			// byte 1 subcommand for RAID failure demonstration
+#define	MY_SCSI_ALARMMUTE	0x60			// byte 1 subcommand to mute any alarm currently on
+
+/************************************************/
+/*		Timeout konstants		 				*/
+/************************************************/
+#define	TIMEOUT_READY				100			// 100 mSec
+#define	TIMEOUT_DRQ					300			// 300 mSec
+#define	TIMEOUT_DATA				(3 * HZ)	// 3 seconds
+
+/************************************************/
+/*		Misc. macros			 				*/
+/************************************************/
+#define ANY2SCSI(up, p)					\
+((UCHAR *)up)[0] = (((ULONG)(p)) >> 8);	\
+((UCHAR *)up)[1] = ((ULONG)(p));
+
+#define SCSI2LONG(up)					\
+( (((long)*(((UCHAR *)up))) << 16)		\
++ (((long)(((UCHAR *)up)[1])) << 8)		\
++ ((long)(((UCHAR *)up)[2])) )
+
+#define XANY2SCSI(up, p)				\
+((UCHAR *)up)[0] = ((long)(p)) >> 24;	\
+((UCHAR *)up)[1] = ((long)(p)) >> 16;	\
+((UCHAR *)up)[2] = ((long)(p)) >> 8;	\
+((UCHAR *)up)[3] = ((long)(p));
+
+#define XSCSI2LONG(up)					\
+( (((long)(((UCHAR *)up)[0])) << 24)	\
++ (((long)(((UCHAR *)up)[1])) << 16)	\
++ (((long)(((UCHAR *)up)[2])) <<  8)	\
++ ((long)(((UCHAR *)up)[3])) )
+
+#define	SelectSpigot(padapter,spigot)	outb_p (spigot, padapter->regStatSel)
+#define WriteCommand(padapter,cmd)		outb_p (cmd, padapter->regStatCmd)
+#define	AtapiDevice(padapter,b)			outb_p (b, padapter->regLba24);
+#define	AtapiCountLo(padapter,b)		outb_p (b, padapter->regLba8)
+#define	AtapiCountHi(padapter,b)		outb_p (b, padapter->regLba16)
+
+/************************************************/
+/*		SCSI CDB operation codes 				*/
+/************************************************/
+#define SCSIOP_TEST_UNIT_READY		0x00
+#define SCSIOP_REZERO_UNIT			0x01
+#define SCSIOP_REWIND				0x01
+#define SCSIOP_REQUEST_BLOCK_ADDR	0x02
+#define SCSIOP_REQUEST_SENSE		0x03
+#define SCSIOP_FORMAT_UNIT			0x04
+#define SCSIOP_READ_BLOCK_LIMITS	0x05
+#define SCSIOP_REASSIGN_BLOCKS		0x07
+#define SCSIOP_READ6				0x08
+#define SCSIOP_RECEIVE				0x08
+#define SCSIOP_WRITE6				0x0A
+#define SCSIOP_PRINT				0x0A
+#define SCSIOP_SEND					0x0A
+#define SCSIOP_SEEK6				0x0B
+#define SCSIOP_TRACK_SELECT			0x0B
+#define SCSIOP_SLEW_PRINT			0x0B
+#define SCSIOP_SEEK_BLOCK			0x0C
+#define SCSIOP_PARTITION			0x0D
+#define SCSIOP_READ_REVERSE			0x0F
+#define SCSIOP_WRITE_FILEMARKS		0x10
+#define SCSIOP_FLUSH_BUFFER			0x10
+#define SCSIOP_SPACE				0x11
+#define SCSIOP_INQUIRY				0x12
+#define SCSIOP_VERIFY6				0x13
+#define SCSIOP_RECOVER_BUF_DATA		0x14
+#define SCSIOP_MODE_SELECT			0x15
+#define SCSIOP_RESERVE_UNIT			0x16
+#define SCSIOP_RELEASE_UNIT			0x17
+#define SCSIOP_COPY					0x18
+#define SCSIOP_ERASE				0x19
+#define SCSIOP_MODE_SENSE			0x1A
+#define SCSIOP_START_STOP_UNIT		0x1B
+#define SCSIOP_STOP_PRINT			0x1B
+#define SCSIOP_LOAD_UNLOAD			0x1B
+#define SCSIOP_RECEIVE_DIAGNOSTIC	0x1C
+#define SCSIOP_SEND_DIAGNOSTIC		0x1D
+#define SCSIOP_MEDIUM_REMOVAL		0x1E
+#define SCSIOP_READ_CAPACITY		0x25
+#define SCSIOP_READ					0x28
+#define SCSIOP_WRITE				0x2A
+#define SCSIOP_SEEK					0x2B
+#define SCSIOP_LOCATE				0x2B
+#define SCSIOP_WRITE_VERIFY			0x2E
+#define SCSIOP_VERIFY				0x2F
+#define SCSIOP_SEARCH_DATA_HIGH		0x30
+#define SCSIOP_SEARCH_DATA_EQUAL	0x31
+#define SCSIOP_SEARCH_DATA_LOW		0x32
+#define SCSIOP_SET_LIMITS			0x33
+#define SCSIOP_READ_POSITION		0x34
+#define SCSIOP_SYNCHRONIZE_CACHE	0x35
+#define SCSIOP_COMPARE				0x39
+#define SCSIOP_COPY_COMPARE			0x3A
+#define SCSIOP_WRITE_DATA_BUFF		0x3B
+#define SCSIOP_READ_DATA_BUFF		0x3C
+#define SCSIOP_CHANGE_DEFINITION	0x40
+#define SCSIOP_READ_SUB_CHANNEL		0x42
+#define SCSIOP_READ_TOC				0x43
+#define SCSIOP_READ_HEADER			0x44
+#define SCSIOP_PLAY_AUDIO			0x45
+#define SCSIOP_PLAY_AUDIO_MSF		0x47
+#define SCSIOP_PLAY_TRACK_INDEX		0x48
+#define SCSIOP_PLAY_TRACK_RELATIVE	0x49
+#define SCSIOP_PAUSE_RESUME			0x4B
+#define SCSIOP_LOG_SELECT			0x4C
+#define SCSIOP_LOG_SENSE			0x4D
+#define SCSIOP_MODE_SELECT10		0x55
+#define SCSIOP_MODE_SENSE10			0x5A
+#define SCSIOP_LOAD_UNLOAD_SLOT		0xA6
+#define SCSIOP_MECHANISM_STATUS		0xBD
+#define SCSIOP_READ_CD				0xBE
+
+// IDE command definitions
+#define IDE_COMMAND_ATAPI_RESET		0x08
+#define IDE_COMMAND_READ			0x20
+#define IDE_COMMAND_WRITE			0x30
+#define IDE_COMMAND_RECALIBRATE		0x10
+#define IDE_COMMAND_SEEK			0x70
+#define IDE_COMMAND_SET_PARAMETERS	0x91
+#define IDE_COMMAND_VERIFY			0x40
+#define IDE_COMMAND_ATAPI_PACKET	0xA0
+#define IDE_COMMAND_ATAPI_IDENTIFY	0xA1
+#define	IDE_CMD_READ_MULTIPLE		0xC4
+#define	IDE_CMD_WRITE_MULTIPLE		0xC5
+#define	IDE_CMD_SET_MULTIPLE		0xC6
+#define IDE_COMMAND_IDENTIFY		0xEC
+
+// IDE status definitions
+#define IDE_STATUS_ERROR			0x01
+#define IDE_STATUS_INDEX			0x02
+#define IDE_STATUS_CORRECTED_ERROR	0x04
+#define IDE_STATUS_DRQ				0x08
+#define IDE_STATUS_DSC				0x10
+#define	IDE_STATUS_WRITE_FAULT		0x20
+#define IDE_STATUS_DRDY				0x40
+#define IDE_STATUS_BUSY				0x80
+
+typedef struct _ATAPI_STATUS
+	{
+	CHAR	check		:1;
+	CHAR	reserved1	:1;
+	CHAR	corr		:1;
+	CHAR	drq			:1;
+	CHAR	dsc			:1;
+	CHAR	reserved2	:1;
+	CHAR	drdy		:1;
+	CHAR	bsy			:1;
+	}	ATAPI_STATUS;
+
+typedef struct _ATAPI_REASON
+	{
+	CHAR	cod			:1;
+	CHAR	io			:1;
+	CHAR	reserved1	:6;
+	}	ATAPI_REASON;
+
+typedef struct _ATAPI_ERROR
+	{
+	CHAR	ili			:1;
+	CHAR	eom			:1;
+	CHAR	abort		:1;
+	CHAR	mcr			:1;
+	CHAR	senseKey	:4;
+	}	ATAPI_ERROR;
+
+// IDE error definitions
+#define	IDE_ERROR_AMNF				0x01
+#define	IDE_ERROR_TKONF				0x02
+#define	IDE_ERROR_ABRT				0x04
+#define	IDE_ERROR_MCR				0x08
+#define	IDE_ERROR_IDFN				0x10
+#define	IDE_ERROR_MC				0x20
+#define	IDE_ERROR_UNC				0x40
+#define	IDE_ERROR_BBK				0x80
+
+// SCSI read capacity structure
+typedef	struct _READ_CAPACITY_DATA
+	{
+	ULONG blks;				/* total blocks (converted to little endian) */
+	ULONG blksiz;			/* size of each (converted to little endian) */
+	}	READ_CAPACITY_DATA, *PREAD_CAPACITY_DATA;
+
+// SCSI inquiry data
+typedef struct _INQUIRYDATA
+	{
+	UCHAR DeviceType			:5;
+	UCHAR DeviceTypeQualifier	:3;
+	UCHAR DeviceTypeModifier	:7;
+	UCHAR RemovableMedia		:1;
+    UCHAR Versions;
+    UCHAR ResponseDataFormat;
+    UCHAR AdditionalLength;
+    UCHAR Reserved[2];
+	UCHAR SoftReset				:1;
+	UCHAR CommandQueue			:1;
+	UCHAR Reserved2				:1;
+	UCHAR LinkedCommands		:1;
+	UCHAR Synchronous			:1;
+	UCHAR Wide16Bit				:1;
+	UCHAR Wide32Bit				:1;
+	UCHAR RelativeAddressing	:1;
+    UCHAR VendorId[8];
+    UCHAR ProductId[16];
+    UCHAR ProductRevisionLevel[4];
+    UCHAR VendorSpecific[20];
+    UCHAR Reserved3[40];
+	}	INQUIRYDATA, *PINQUIRYDATA;
+
+// IDE IDENTIFY data
+#pragma pack (1)
+typedef struct _IDENTIFY_DATA
+	{
+    USHORT	GeneralConfiguration;		//  0
+    USHORT	NumberOfCylinders;			//  1
+    USHORT	Reserved1;					//  2
+    USHORT	NumberOfHeads;				//  3
+    USHORT	UnformattedBytesPerTrack;	//  4
+    USHORT	UnformattedBytesPerSector;	//  5
+    USHORT	SectorsPerTrack;			//  6
+	USHORT	NumBytesISG;				//  7 Byte Len - inter-sector gap
+	USHORT	NumBytesSync;				//  8          - sync field
+	USHORT	NumWordsVUS;				//  9 Len - Vendor Unique Info
+    USHORT	SerialNumber[10];			// 10
+    USHORT	BufferType;					// 20
+    USHORT	BufferSectorSize;			// 21
+    USHORT	NumberOfEccBytes;			// 22
+    USHORT	FirmwareRevision[4];		// 23
+    USHORT	ModelNumber[20];			// 27
+	USHORT	NumSectorsPerInt	:8;		// 47 Multiple Mode - Sec/Blk
+	USHORT	Reserved2			:8;		// 47
+	USHORT	DoubleWordMode;				// 48 flag for double word mode capable
+	USHORT	VendorUnique1		:8;		// 49
+	USHORT	SupportDMA			:1;		// 49 DMA supported
+	USHORT	SupportLBA			:1;		// 49 LBA supported
+	USHORT	SupportIORDYDisable	:1;		// 49 IORDY can be disabled
+	USHORT	SupportIORDY		:1;		// 49 IORDY supported
+	USHORT	ReservedPsuedoDMA	:1;		// 49 reserved for pseudo DMA mode support
+	USHORT	Reserved3			:3;		// 49
+	USHORT	Reserved4;					// 50
+	USHORT	Reserved5			:8;		// 51 Transfer Cycle Timing - PIO
+	USHORT	PIOCycleTime		:8;		// 51 Transfer Cycle Timing - PIO
+	USHORT	Reserved6			:8;		// 52                       - DMA
+	USHORT	DMACycleTime		:8;		// 52                       - DMA
+	USHORT	Valid_54_58			:1;		// 53 words 54 - 58 are valid
+	USHORT	Valid_64_70			:1;		// 53 words 64 - 70 are valid
+	USHORT	Reserved7			:14;	// 53
+	USHORT	LogNumCyl;					// 54 Current Translation - Num Cyl
+	USHORT	LogNumHeads;				// 55                       Num Heads
+	USHORT	LogSectorsPerTrack;			// 56                       Sec/Trk
+	ULONG	LogTotalSectors;			// 57                       Total Sec
+	USHORT	CurrentNumSecPerInt	:8;		// 59 current setting for number of sectors per interrupt
+	USHORT	ValidNumSecPerInt	:1;		// 59 Current setting is valid for number of sectors per interrupt
+	USHORT	Reserved8			:7;		// 59
+	ULONG	LBATotalSectors;			// 60 LBA Mode - Sectors
+	USHORT	DMASWordFlags;				// 62
+	USHORT	DMAMWordFlags;				// 63
+	USHORT	AdvancedPIOSupport  :8;		// 64 Flow control PIO transfer modes supported
+	USHORT	Reserved9			:8;		// 64
+	USHORT	MinMultiDMACycle;			// 65 minimum multiword DMA transfer cycle time per word
+	USHORT	RecomendDMACycle;			// 66 Manufacturer's recommende multiword DMA transfer cycle time
+	USHORT	MinPIOCycleWithoutFlow;		// 67 Minimum PIO transfer cycle time without flow control
+	USHORT	MinPIOCylceWithFlow;		// 68 Minimum PIO transfer cycle time with IORDY flow control
+	USHORT	ReservedSpace[256-69];		// 69
+	}	IDENTIFY_DATA, *PIDENTIFY_DATA;
+
+// ATAPI configuration bits
+typedef struct _ATAPI_GENERAL_0
+	{
+	USHORT	CmdPacketSize		:2;		// Command packet size
+	USHORT	Reserved1			:3;
+	USHORT	CmdDrqType			:2;
+	USHORT	Removable			:1;
+	USHORT	DeviceType			:5;
+	USHORT	Reserved2			:1;
+	USHORT	ProtocolType		:2;
+	}	ATAPI_GENERAL_0;
+
+#pragma pack ()
diff --git a/drivers/scsi/psi_roy.h b/drivers/scsi/psi_roy.h
new file mode 100644
index 0000000..c55b9c0
--- /dev/null
+++ b/drivers/scsi/psi_roy.h
@@ -0,0 +1,331 @@
+/****************************************************************************
+ * Perceptive Solutions, Inc. PCI-2000 device driver for Linux.
+ *
+ * psi_roy.h - Linux Host Driver for PCI-2000 IntelliCache SCSI Adapters
+ *
+ * Copyright (c) 1997-1999 Perceptive Solutions, Inc.
+ * All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
+ *
+ * Technical updates and product information at:
+ *  http://www.psidisk.com
+ *
+ * Please send questions, comments, bug reports to:
+ *  tech@psidisk.com Technical Support
+ *
+ ****************************************************************************/
+
+#ifndef	ROY_HOST
+#define	ROY_HOST
+
+/************************************************/
+/*		PCI setup								*/
+/************************************************/
+#define	VENDOR_PSI			0x1256
+#define	DEVICE_ROY_1		0x5201		/* 'R1' */
+
+/************************************************/
+/*		controller constants					*/
+/************************************************/
+#define MAXADAPTER			4			// Increase this and the sizes of the arrays below, if you need more.
+#define	MAX_BUS				2
+#define	MAX_UNITS			16
+#define	TIMEOUT_COMMAND		400			// number of milliSecondos for command busy timeout
+
+/************************************************/
+/*		I/O address offsets						*/
+/************************************************/
+#define RTR_MAILBOX						0x040
+#define RTR_LOCAL_DOORBELL				0x060
+#define RTR_PCI_DOORBELL				0x064
+
+/************************************************/
+/*												*/
+/*			Host command codes					*/
+/*												*/
+/************************************************/
+#define	CMD_READ_CHS		0x01		/* read sectors as specified (CHS mode) */
+#define	CMD_READ			0x02		/* read sectors as specified (RBA mode) */
+#define	CMD_READ_SG			0x03		/* read sectors using scatter/gather list */
+#define	CMD_WRITE_CHS		0x04		/* write sectors as specified (CHS mode) */
+#define	CMD_WRITE			0x05		/* write sectors as specified (RBA mode) */
+#define	CMD_WRITE_SG		0x06		/* write sectors using scatter/gather list (LBA mode) */
+#define	CMD_READ_CHS_SG		0x07		/* read sectors using scatter/gather list (CHS mode) */
+#define	CMD_WRITE_CHS_SG	0x08		/* write sectors using scatter/gather list (CHS mode) */
+#define	CMD_VERIFY_CHS		0x09		/* verify data on sectors as specified (CHS mode) */
+#define	CMD_VERIFY			0x0A		/* verify data on sectors as specified (RBA mode) */
+#define	CMD_DASD_CDB		0x0B		/* process CDB for a DASD device */
+#define	CMD_DASD_CDB_SG		0x0C		/* process CDB for a DASD device with scatter/gather */
+
+#define	CMD_READ_ABS		0x10		/* read absolute disk */
+#define	CMD_WRITE_ABS		0x11		/* write absolute disk */
+#define	CMD_VERIFY_ABS		0x12		/* verify absolute disk */
+#define	CMD_TEST_READY		0x13		/* test unit ready and return status code */
+#define	CMD_LOCK_DOOR		0x14		/* lock device door */
+#define	CMD_UNLOCK_DOOR		0x15		/* unlock device door */
+#define	CMD_EJECT_MEDIA		0x16		/* eject the media */
+#define	CMD_UPDATE_CAP		0x17		/* update capacity information */
+#define	CMD_TEST_PRIV		0x18		/* test and setup private format media */
+
+
+#define	CMD_SCSI_THRU		0x30		/* SCSI pass through CDB */
+#define	CMD_SCSI_THRU_SG	0x31		/* SCSI pass through CDB with scatter/gather */
+#define	CMD_SCSI_REQ_SENSE	0x32		/* SCSI pass through request sense after check condition */
+
+#define	CMD_DASD_RAID_RQ	0x35		/* request DASD RAID drive data */
+#define	CMD_DASD_RAID_RQ0	0x31			/* byte 1 subcommand to query for RAID 0 informatation */
+#define	CMD_DASD_RAID_RQ1	0x32			/* byte 1 subcommand to query for RAID 1 informatation */
+#define	CMD_DASD_RAID_RQ5	0x33			/* byte 1 subcommand to query for RAID 5 informatation */
+
+#define	CMD_DASD_SCSI_INQ	0x36		/* do DASD inquire and return in SCSI format */
+#define	CMD_DASD_CAP		0x37		/* read DASD capacity */
+#define	CMD_DASD_INQ		0x38		/* do DASD inquire for type data and return SCSI/EIDE inquiry */
+#define	CMD_SCSI_INQ		0x39		/* do SCSI inquire */
+#define	CMD_READ_SETUP		0x3A		/* Get setup structures from controller */
+#define	CMD_WRITE_SETUP		0x3B		/* Put setup structures in controller and burn in flash */
+#define	CMD_READ_CONFIG		0x3C		/* Get the entire configuration and setup structures */
+#define	CMD_WRITE_CONFIG	0x3D		/* Put the entire configuration and setup structures in flash */
+
+#define	CMD_TEXT_DEVICE		0x3E		/* obtain device text */
+#define	CMD_TEXT_SIGNON		0x3F		/* get sign on banner */
+
+#define	CMD_QUEUE			0x40		/* any command below this generates a queue tag interrupt to host*/
+
+#define	CMD_PREFETCH		0x40		/* prefetch sectors as specified */
+#define	CMD_TEST_WRITE		0x41		/* Test a device for write protect */
+#define	CMD_LAST_STATUS		0x42		/* get last command status and error data*/
+#define	CMD_ABORT			0x43		/* abort command as specified */
+#define	CMD_ERROR			0x44		/* fetch error code from a tagged op */
+#define	CMD_DONE			0x45		/* done with operation */
+#define	CMD_DIAGNOSTICS		0x46		/* execute controller diagnostics and wait for results */
+#define	CMD_FEATURE_MODE	0x47		/* feature mode control word */
+#define	CMD_DASD_INQUIRE	0x48		/* inquire as to DASD SCSI device (32 possible) */
+#define	CMD_FEATURE_QUERY	0x49		/* query the feature control word */
+#define	CMD_DASD_EJECT		0x4A		/* Eject removable media for DASD type */
+#define	CMD_DASD_LOCK		0x4B		/* Lock removable media for DASD type */
+#define	CMD_DASD_TYPE		0x4C		/* obtain DASD device type */
+#define	CMD_NUM_DEV			0x4D		/* obtain the number of devices connected to the controller */
+#define	CMD_GET_PARMS		0x4E		/* obtain device parameters */
+#define	CMD_SPECIFY			0x4F		/* specify operating system for scatter/gather operations */
+
+#define	CMD_RAID_GET_DEV	0x50		/* read RAID device geometry */
+#define CMD_RAID_READ		0x51		/* read RAID 1 parameter block */
+#define	CMD_RAID_WRITE		0x52		/* write RAID 1 parameter block */
+#define	CMD_RAID_LITEUP		0x53		/* Light up the drive light for identification */
+#define	CMD_RAID_REBUILD	0x54		/* issue a RAID 1 pair rebuild */
+#define	CMD_RAID_MUTE		0x55		/* mute RAID failure alarm */
+#define	CMD_RAID_FAIL		0x56		/* induce a RAID failure */
+#define	CMD_RAID_STATUS		0x57		/* get status of RAID pair */
+#define	CMD_RAID_STOP		0x58		/* stop any reconstruct in progress */
+#define CMD_RAID_START		0x59		/* start reconstruct */
+#define	CMD_RAID0_READ		0x5A		/* read RAID 0 parameter block */
+#define	CMD_RAID0_WRITE		0x5B		/* write RAID 0 parameter block */
+#define	CMD_RAID5_READ		0x5C		/* read RAID 5 parameter block */
+#define	CMD_RAID5_WRITE		0x5D		/* write RAID 5 parameter block */
+
+#define	CMD_ERASE_TABLES	0x5F		/* erase partition table and RAID signatutures */
+
+#define	CMD_SCSI_GET		0x60		/* get SCSI pass through devices */
+#define	CMD_SCSI_TIMEOUT	0x61		/* set SCSI pass through timeout */
+#define	CMD_SCSI_ERROR		0x62		/* get SCSI pass through request sense length and residual data count */
+#define	CMD_GET_SPARMS		0x63		/* get SCSI bus and user parms */
+#define	CMD_SCSI_ABORT		0x64		/* abort by setting time-out to zero */
+
+#define	CMD_CHIRP_CHIRP		0x77		/* make a chirp chirp sound */
+#define	CMD_GET_LAST_DONE	0x78		/* get tag of last done in progress */
+#define	CMD_GET_FEATURES	0x79		/* get feature code and ESN */
+#define CMD_CLEAR_CACHE		0x7A		/* Clear cache on specified device */
+#define	CMD_BIOS_TEST		0x7B		/* Test whether or not to load BIOS */
+#define	CMD_WAIT_FLUSH		0x7C		/* wait for cache flushed and invalidate read cache */
+#define	CMD_RESET_BUS		0x7D		/* reset the SCSI bus */
+#define	CMD_STARTUP_QRY		0x7E		/* startup in progress query */
+#define	CMD_RESET			0x7F		/* reset the controller */
+
+#define	CMD_RESTART_RESET	0x80		/* reload and restart the controller at any reset issued */
+#define	CMD_SOFT_RESET		0x81		/* do a soft reset NOW! */
+
+/************************************************/
+/*												*/
+/*				Host return errors				*/
+/*												*/
+/************************************************/
+#define	ERR08_TAGGED		0x80		/* doorbell error ored with tag */
+
+#define	ERR16_NONE			0x0000		/* no errors */
+#define	ERR16_SC_COND_MET	0x0004		/* SCSI status - Condition Met */
+#define	ERR16_CMD			0x0101		/* command error */
+#define	ERR16_SC_CHECK_COND	0x0002		/* SCSI status - Check Condition */
+#define	ERR16_CMD_NOT		0x0201		/* command not supported */
+#define ERR16_NO_DEVICE     0x0301		/* invalid device selection */
+#define	ERR16_SECTOR		0x0202		/* bad sector */
+#define	ERR16_PROTECT		0x0303		/* write protected */
+#define	ERR16_NOSECTOR		0x0404		/* sector not found */
+#define	ERR16_MEDIA			0x0C0C		/* invalid media */
+#define	ERR16_CONTROL		0x2020		/* controller error */
+#define	ERR16_CONTROL_DMA	0x2120		/* controller DMA engine error */
+#define	ERR16_NO_ALARM		0x2220		/* alarm is not active */
+#define	ERR16_OP_BUSY		0x2320		/* operation busy */
+#define	ERR16_SEEK			0x4040		/* seek failure */
+#define	ERR16_DEVICE_FAIL	0x4140		/* device has failed */
+#define ERR16_TIMEOUT		0x8080		/* timeout error */
+#define	ERR16_DEV_NOT_READY	0xAAAA		/* drive not ready */
+#define	ERR16_UNDEFINED		0xBBBB		/* undefined error */
+#define	ERR16_WRITE_FAULT	0xCCCC		/* write fault */
+#define ERR16_INVALID_DEV	0x4001		/* invalid device access */
+#define	ERR16_DEVICE_BUSY	0x4002		/* device is busy */
+#define	ERR16_MEMORY		0x4003		/* device pass thru requires too much memory */
+#define	ERR16_NO_FEATURE	0x40FA		/* feature no implemented */
+#define	ERR16_NOTAG			0x40FD		/* no tag space available */
+#define	ERR16_NOT_READY		0x40FE		/* controller not ready error */
+#define	ERR16_SETUP_FLASH	0x5050		/* error when writing setup to flash memory */
+#define	ERR16_SETUP_SIZE	0x5051		/* setup block size error */
+#define	ERR16_SENSE			0xFFFF		/* sense opereration failed */
+#define	ERR16_SC_BUSY		0x0008		/* SCSI status - Busy */
+#define	ERR16_SC_RES_CONFL	0x0018		/* SCSI status - Reservation Conflict */
+#define	ERR16_SC_CMD_TERM	0x0022		/* SCSI status - Command Terminated */
+#define	ERR16_SC_OTHER		0x00FF		/* SCSI status - not recognized (any value masked) */
+#define	ERR16_MEDIA_CHANGED	0x8001		/* devices media has been changed */
+
+#define	ERR32_NONE			0x00000000	/* no errors */
+#define	ERR32_SC_COND_MET	0x00000004	/* SCSI status - Condition Met */
+#define	ERR32_CMD			0x00010101	/* command error */
+#define	ERR32_SC_CHECK_COND	0x00020002	/* SCSI status - Check Condition */
+#define	ERR32_CMD_NOT		0x00030201	/* command not supported */
+#define ERR32_NO_DEVICE     0x00040301	/* invalid device selection */
+#define	ERR32_SECTOR		0x00050202	/* bad sector */
+#define	ERR32_PROTECT		0x00060303	/* write protected */
+#define	ERR32_NOSECTOR		0x00070404	/* sector not found */
+#define	ERR32_MEDIA			0x00080C0C	/* invalid media */
+#define	ERR32_CONTROL		0x00092020	/* controller error */
+#define	ERR32_CONTROL_DMA	0x000A2120	/* Controller DMA error */
+#define	ERR32_NO_ALARM		0x000B2220 	/* alarm is not active */
+#define	ERR32_OP_BUSY		0x000C2320	/* operation busy */
+#define	ERR32_SEEK			0x000D4040	/* seek failure */
+#define	ERR32_DEVICE_FAIL	0x000E4140	/* device has failed */
+#define ERR32_TIMEOUT		0x000F8080	/* timeout error */
+#define	ERR32_DEV_NOT_READY	0x0010AAAA	/* drive not ready */
+#define	ERR32_UNDEFINED		0x0011BBBB	/* undefined error */
+#define	ERR32_WRITE_FAULT	0x0012CCCC	/* write fault */
+#define ERR32_INVALID_DEV	0x00134001	/* invalid device access */
+#define	ERR32_DEVICE_BUSY	0x00144002	/* device is busy */
+#define	ERR32_MEMORY		0x00154003	/* device pass thru requires too much memory */
+#define	ERR32_NO_FEATURE	0x001640FA	/* feature no implemented */
+#define	ERR32_NOTAG			0x001740FD	/* no tag space available */
+#define	ERR32_NOT_READY		0x001840FE	/* controller not ready error */
+#define	ERR32_SETUP_FLASH	0x00195050	/* error when writing setup to flash memory */
+#define	ERR32_SETUP_SIZE	0x001A5051	/* setup block size error */
+#define	ERR32_SENSE			0x001BFFFF	/* sense opereration failed */
+#define	ERR32_SC_BUSY		0x001C0008	/* SCSI status - Busy */
+#define	ERR32_SC_RES_CONFL	0x001D0018	/* SCSI status - Reservation Conflict */
+#define	ERR32_SC_CMD_TERM	0x001E0022	/* SCSI status - Command Terminated */
+#define	ERR32_SC_OTHER		0x001F00FF	/* SCSI status - not recognized (any value masked) */
+#define	ERR32_MEDIA_CHANGED	0x00208001	/* devices media has been changed */
+
+/************************************************/
+/*												*/
+/*	Host Operating System specification codes	*/
+/*												*/
+/************************************************/
+#define	SPEC_INTERRUPT		0x80		/* specification requires host interrupt */
+#define	SPEC_BACKWARD_SG	0x40		/* specification requires scatter/gather items reversed */
+#define	SPEC_DOS_BLOCK		0x01		/* DOS DASD blocking on pass through */
+#define	SPEC_OS2_V3			0x02		/* OS/2 Warp */
+#define	SPCE_SCO_3242		0x04		/* SCO 3.4.2.2 */
+#define	SPEC_QNX_4X			0x05		/* QNX 4.XX */
+#define	SPEC_NOVELL_NWPA	0x08		/* Novell NWPA scatter/gather support */
+
+/************************************************/
+/*												*/
+/*	Inquire structures							*/
+/*												*/
+/************************************************/
+typedef	struct	_CNT_SCSI_INQ
+	{
+	UCHAR	devt;						/* 00: device type */
+	UCHAR	devtm;						/* 01: device type modifier */
+	UCHAR	svers;						/* 02: SCSI version */
+	UCHAR	rfmt;						/* 03: response data format */
+	UCHAR	adlen;						/* 04: additional length of data */
+	UCHAR	res1;						/* 05: */
+	UCHAR	res2;						/* 06: */
+	UCHAR	fncs;						/* 07: functional capabilities */
+	UCHAR	vid[8];						/* 08: vendor ID */
+	UCHAR	pid[16];					/* 10: product ID */
+	UCHAR	rev[4];						/* 20: product revision */
+	}	CNT_SCSI_INQ;
+
+typedef	struct	_CNT_IDE_INQ
+	{
+	USHORT	GeneralConfiguration;		/* 00 */
+	USHORT	NumberOfCylinders;			/* 02 */
+	USHORT	Reserved1;					/* 04 */
+	USHORT	NumberOfHeads;				/* 06 */
+	USHORT	UnformattedBytesPerTrack;	/* 08 */
+	USHORT	UnformattedBytesPerSector;	/* 0A */
+	USHORT	SectorsPerTrack;			/* 0C */
+	USHORT	VendorUnique1[3];			/* 0E */
+	USHORT	SerialNumber[10];			/* 14 */
+	USHORT	BufferType;					/* 28 */
+	USHORT	BufferSectorSize;			/* 2A */
+	USHORT	NumberOfEccBytes;			/* 2C */
+	USHORT	FirmwareRevision[4];		/* 2E */
+	USHORT	ModelNumber[20];			/* 36 */
+	UCHAR	MaximumBlockTransfer;		/* 5E */
+	UCHAR	VendorUnique2;				/* 5F */
+	USHORT	DoubleWordIo;				/* 60 */
+	USHORT	Capabilities;				/* 62 */
+	USHORT	Reserved2;					/* 64 */
+	UCHAR	VendorUnique3;				/* 66 */
+	UCHAR	PioCycleTimingMode;			/* 67 */
+	UCHAR	VendorUnique4;				/* 68 */
+	UCHAR	DmaCycleTimingMode;			/* 69 */
+	USHORT	TranslationFieldsValid;		/* 6A */
+	USHORT	NumberOfCurrentCylinders;	/* 6C */
+	USHORT	NumberOfCurrentHeads;		/* 6E */
+	USHORT	CurrentSectorsPerTrack;		/* 70 */
+	ULONG	CurrentSectorCapacity;		/* 72 */
+	}	CNT_IDE_INQ;
+
+typedef struct	_DASD_INQUIRE
+	{
+	ULONG	type;						/* 0 = SCSI, 1 = IDE */
+	union
+		{
+		CNT_SCSI_INQ	scsi;			/* SCSI inquire data */
+		CNT_IDE_INQ		ide;			/* IDE inquire data */
+		}	inq;
+	}	DASD_INQUIRE;
+
+/************************************************/
+/*												*/
+/*	Device Codes								*/
+/*												*/
+/************************************************/
+#define DEVC_DASD			0x00		/* Direct-access Storage Device */
+#define DEVC_SEQACESS		0x01		/* Sequential-access device */
+#define DEVC_PRINTER		0x02		/* Printer device */
+#define DEVC_PROCESSOR		0x03		/* Processor device */
+#define DEVC_WRITEONCE		0x04		/* Write-once device */
+#define DEVC_CDROM			0x05		/* CD-ROM device */
+#define DEVC_SCANNER		0x06		/* Scanner device */
+#define DEVC_OPTICAL		0x07		/* Optical memory device */
+#define DEVC_MEDCHGR		0x08		/* Medium changer device */
+#define	DEVC_DASD_REMOVABLE	0x80		/* Direct-access storage device, Removable */
+#define	DEVC_NONE			0xFF		/* no device */
+
+// SCSI controls for RAID
+#define	SC_MY_RAID			0xBF			// our special CDB command byte for Win95... interface
+#define	MY_SCSI_QUERY0		0x31			// byte 1 subcommand to query driver for RAID 0 informatation
+#define	MY_SCSI_QUERY1		0x32			// byte 1 subcommand to query driver for RAID 1 informatation
+#define	MY_SCSI_QUERY5		0x33			// byte 1 subcommand to query driver for RAID 5 informatation
+#define	MY_SCSI_REBUILD		0x40			// byte 1 subcommand to reconstruct a mirrored pair
+#define MY_SCSI_DEMOFAIL	0x54			// byte 1 subcommand for RAID failure demonstration
+#define	MY_SCSI_ALARMMUTE	0x60			// byte 1 subcommand to mute any alarm currently on
+
+
+#endif
+
diff --git a/drivers/scsi/ql1040_fw.h b/drivers/scsi/ql1040_fw.h
new file mode 100644
index 0000000..89d8e09
--- /dev/null
+++ b/drivers/scsi/ql1040_fw.h
@@ -0,0 +1,2099 @@
+/**************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * Copyright (C) 2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *************************************************************************/
+
+/************************************************************************
+ *									*
+ * 	        --- ISP1040 Initiator/Target Firmware ---               *
+ *			    32 LUN Support				*
+ *									*
+ ************************************************************************
+ */
+
+/*
+ *	Firmware Version 7.65.00 (14:17 Jul 20, 1999)
+ */
+
+static unsigned char firmware_version[] = {7,65,0};
+
+#define FW_VERSION_STRING "7.65.0"
+
+static unsigned short risc_code_addr01 = 0x1000 ;
+
+static unsigned short risc_code01[] = { 
+	0x0078, 0x103a, 0x0000, 0x4057, 0x0000, 0x2043, 0x4f50, 0x5952,
+	0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943,
+	0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350,
+	0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172,
+	0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3635,
+	0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20,
+	0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020,
+	0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048,
+	0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9,
+	0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071,
+	0x0010, 0x70c3, 0x0004, 0x20c9, 0x77ff, 0x2089, 0x1186, 0x70c7,
+	0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00,
+	0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100,
+	0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc,
+	0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040,
+	0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1,
+	0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1,
+	0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc,
+	0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040,
+	0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134,
+	0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078,
+	0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b,
+	0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a,
+	0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a,
+	0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5100, 0x8424,
+	0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7800, 0x2009,
+	0x0000, 0x2001, 0x0031, 0x1078, 0x1cba, 0x2218, 0x2079, 0x5100,
+	0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109,
+	0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883,
+	0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f,
+	0x0002, 0x784f, 0x0003, 0x2069, 0x5140, 0x2001, 0x04fd, 0x2004,
+	0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108,
+	0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c,
+	0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008,
+	0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008,
+	0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5380, 0x2011, 0x0020,
+	0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00,
+	0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
+	0x8109, 0x00c0, 0x1122, 0x2069, 0x5400, 0x2009, 0x0002, 0x20a9,
+	0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff,
+	0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c,
+	0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152,
+	0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x220a, 0x1078,
+	0x482c, 0x1078, 0x1963, 0x1078, 0x4d22, 0x3200, 0xa085, 0x000d,
+	0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002,
+	0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005,
+	0x00c0, 0x117a, 0x1078, 0x1ce3, 0x0010, 0x1180, 0x0068, 0x1180,
+	0x1078, 0x20e9, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1a48,
+	0x00e0, 0x116c, 0x1078, 0x4ba9, 0x0078, 0x116c, 0x118e, 0x1190,
+	0x240b, 0x240b, 0x48ad, 0x48ad, 0x240b, 0x240b, 0x0078, 0x118e,
+	0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201,
+	0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814,
+	0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009,
+	0x515b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5164, 0x200b,
+	0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009,
+	0x5162, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca,
+	0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce,
+	0x1078, 0x1948, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0,
+	0x11d3, 0x1078, 0x165a, 0x7817, 0x0000, 0x2009, 0x5162, 0x2104,
+	0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x19b3,
+	0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, 0x6007,
+	0x0103, 0x1078, 0x1924, 0x00c0, 0x11fb, 0x1078, 0x1948, 0x2009,
+	0x5162, 0x200b, 0x0000, 0x2009, 0x515c, 0x2104, 0x200b, 0x0000,
+	0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078,
+	0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000,
+	0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038,
+	0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313,
+	0x12a0, 0x1748, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3,
+	0x174d, 0x1298, 0x1329, 0x1360, 0x1672, 0x1742, 0x12b5, 0x1591,
+	0x15ad, 0x15c9, 0x15f4, 0x154a, 0x1558, 0x156c, 0x1580, 0x13df,
+	0x1298, 0x138d, 0x1393, 0x1398, 0x139d, 0x13a3, 0x13a8, 0x13ad,
+	0x13b2, 0x13b7, 0x13bb, 0x13d0, 0x13dc, 0x1298, 0x1298, 0x1298,
+	0x1298, 0x13eb, 0x13f4, 0x1403, 0x1429, 0x1433, 0x143a, 0x1480,
+	0x148f, 0x149e, 0x14b0, 0x152a, 0x153a, 0x1298, 0x1298, 0x1298,
+	0x1298, 0x153f, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084,
+	0x001f, 0x0079, 0x125b, 0x1786, 0x1789, 0x1799, 0x1298, 0x1298,
+	0x18df, 0x18fc, 0x1298, 0x1298, 0x1298, 0x1900, 0x1908, 0x1298,
+	0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x1356, 0x1668,
+	0x1764, 0x1778, 0x1298, 0x1829, 0x190e, 0x18bb, 0x18c5, 0x18c9,
+	0x18d7, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078,
+	0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068,
+	0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0,
+	0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c,
+	0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287,
+	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+	0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078,
+	0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3,
+	0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
+	0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
+	0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0078, 0x0455, 0x1078, 0x1b53, 0x00c0, 0x129c, 0x75d8,
+	0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520,
+	0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1a8d, 0x0040, 0x1284,
+	0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1b53, 0x00c0, 0x129c,
+	0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000,
+	0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1aed, 0x0040,
+	0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114,
+	0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7,
+	0x0007, 0x70cb, 0x0041, 0x70cf, 0x0000, 0x0078, 0x1284, 0x1078,
+	0x1b53, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078,
+	0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0,
+	0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1350, 0x8001,
+	0x7892, 0xa084, 0xfc00, 0x0040, 0x1345, 0x78cc, 0xa085, 0x0001,
+	0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2,
+	0x7ea6, 0x7c96, 0x78cc, 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1354,
+	0x78cc, 0xa085, 0x0001, 0x78ce, 0x0078, 0x1284, 0x1078, 0x1b53,
+	0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1363,
+	0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6,
+	0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1387, 0x8001, 0x78ae,
+	0xa084, 0xfc00, 0x0040, 0x137c, 0x78cc, 0xa085, 0x0100, 0x78ce,
+	0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, 0x7dbe, 0x7ec2,
+	0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, 0x138b, 0x78cc,
+	0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, 0x5161, 0x210c,
+	0x7aec, 0x0078, 0x1282, 0x2009, 0x5141, 0x210c, 0x0078, 0x1283,
+	0x2009, 0x5142, 0x210c, 0x0078, 0x1283, 0x2061, 0x5140, 0x610c,
+	0x6210, 0x0078, 0x1282, 0x2009, 0x5145, 0x210c, 0x0078, 0x1283,
+	0x2009, 0x5146, 0x210c, 0x0078, 0x1283, 0x2009, 0x5148, 0x210c,
+	0x0078, 0x1283, 0x2009, 0x5149, 0x210c, 0x0078, 0x1283, 0x7908,
+	0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa0e8, 0x5380, 0x6a00, 0x6804, 0xa084, 0x0008,
+	0x0040, 0x13cd, 0x6b08, 0x0078, 0x13ce, 0x6b0c, 0x0078, 0x1281,
+	0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091,
+	0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, 0x1283, 0x77c4,
+	0x1078, 0x1973, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091,
+	0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x127c,
+	0x1078, 0x22e2, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8,
+	0x127c, 0x2011, 0x5141, 0x2204, 0x007e, 0x2112, 0x1078, 0x229b,
+	0x017f, 0x0078, 0x1283, 0x71c4, 0x2011, 0x1421, 0x20a9, 0x0008,
+	0x2204, 0xa106, 0x0040, 0x1413, 0x8210, 0x0070, 0x1411, 0x0078,
+	0x1408, 0x0078, 0x127c, 0xa292, 0x1421, 0x027e, 0x2011, 0x5142,
+	0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x22a7, 0x017f, 0x0078,
+	0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032,
+	0x004b, 0x2061, 0x5140, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8,
+	0x6012, 0x0078, 0x1282, 0x2061, 0x5140, 0x6114, 0x70c4, 0x6016,
+	0x0078, 0x1283, 0x2061, 0x5140, 0x71c4, 0x2011, 0x0004, 0x601f,
+	0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x145b, 0x2011,
+	0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
+	0x145b, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186,
+	0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084,
+	0x0001, 0x00c0, 0x1476, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+	0x0048, 0x146e, 0x0038, 0x1472, 0x0078, 0x1476, 0x0028, 0x1472,
+	0x0078, 0x1476, 0x2019, 0x2222, 0x0078, 0x1478, 0x2019, 0x1212,
+	0x23b8, 0x1078, 0x22b8, 0x1078, 0x4d22, 0x017f, 0x0078, 0x1283,
+	0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5148, 0x2204,
+	0x2112, 0x007e, 0x1078, 0x22da, 0x017f, 0x0078, 0x1283, 0x71c4,
+	0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5149, 0x2204, 0x007e,
+	0x2112, 0x1078, 0x22c9, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8,
+	0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b,
+	0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282,
+	0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8,
+	0x5380, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, 0x14c6,
+	0x6c14, 0x84ff, 0x00c0, 0x14c6, 0x6817, 0x0040, 0xa284, 0x0040,
+	0x0040, 0x14d0, 0x6c10, 0x84ff, 0x00c0, 0x14d0, 0x6813, 0x0001,
+	0x6800, 0x007e, 0xa226, 0x0040, 0x14f3, 0x6a02, 0xa484, 0x2000,
+	0x0040, 0x14dc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14e2,
+	0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14f3, 0x810f, 0xa284,
+	0x4000, 0x0040, 0x14ef, 0x1078, 0x22fc, 0x0078, 0x14f3, 0x1078,
+	0x22ee, 0x0078, 0x14f3, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1522,
+	0xa2a4, 0x00ff, 0x2061, 0x5140, 0x6118, 0xa186, 0x0028, 0x0040,
+	0x1509, 0xa186, 0x0032, 0x0040, 0x150f, 0xa186, 0x003c, 0x0040,
+	0x1515, 0xa482, 0x0064, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482,
+	0x0050, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, 0x0043, 0x0048,
+	0x151f, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a,
+	0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4,
+	0x0078, 0x1281, 0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a14,
+	0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708,
+	0x0078, 0x1281, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4,
+	0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x230a,
+	0x0078, 0x1281, 0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a08,
+	0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+	0x77c4, 0x1078, 0x1973, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9,
+	0x6a0a, 0x6804, 0xa005, 0x0040, 0x1567, 0x1078, 0x21d2, 0x2091,
+	0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, 0x1973, 0x2091,
+	0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040,
+	0x157b, 0x1078, 0x21d2, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+	0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091,
+	0x8000, 0x1078, 0x1980, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078,
+	0x1282, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078,
+	0x19e1, 0x00c0, 0x15a9, 0x6818, 0xa005, 0x0040, 0x15a9, 0x2708,
+	0x1078, 0x231a, 0x00c0, 0x15a9, 0x7817, 0x0015, 0x2091, 0x8001,
+	0x007c, 0x2091, 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041,
+	0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
+	0x1980, 0x2061, 0x5140, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f,
+	0x6073, 0x0000, 0x7817, 0x0016, 0x1078, 0x21d2, 0x2091, 0x8001,
+	0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091,
+	0x8000, 0x2061, 0x5140, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782,
+	0x6093, 0x000f, 0x7817, 0x0017, 0x1078, 0x21d2, 0x2091, 0x8001,
+	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000,
+	0x1078, 0x1980, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0,
+	0x15e8, 0x2091, 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0,
+	0x1618, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
+	0x0008, 0x1078, 0x1973, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a,
+	0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1601, 0xa7bc,
+	0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1601,
+	0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040,
+	0x1641, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004,
+	0x0040, 0x162e, 0x0070, 0x162e, 0x0078, 0x1625, 0x684b, 0x0009,
+	0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x163b, 0x0070,
+	0x163b, 0x0078, 0x1632, 0x20a9, 0x00fa, 0x0070, 0x1641, 0x0078,
+	0x163d, 0x2079, 0x5100, 0x7817, 0x0018, 0x2061, 0x5140, 0x606f,
+	0x0001, 0x6073, 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002,
+	0x78ce, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091,
+	0x8001, 0x007c, 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001,
+	0x00c0, 0x1664, 0x1078, 0x1a2b, 0x71c4, 0x71c6, 0x794a, 0x007c,
+	0x1078, 0x1b53, 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de,
+	0x0078, 0x1675, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc,
+	0x71c6, 0x73ca, 0x72ce, 0x2079, 0x5100, 0x2091, 0x8000, 0x1078,
+	0x192e, 0x2091, 0x8001, 0x0040, 0x172c, 0x20a9, 0x0005, 0x20a1,
+	0x5118, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020,
+	0x1078, 0x1929, 0x0040, 0x1698, 0x1078, 0x1948, 0x0078, 0x172c,
+	0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16fb, 0x0c7e,
+	0x2c68, 0x2091, 0x8000, 0x1078, 0x192e, 0x2091, 0x8001, 0x0040,
+	0x16cc, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x16a0, 0x609f, 0x0000,
+	0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c,
+	0xa065, 0x0040, 0x16fa, 0x2009, 0x0020, 0x1078, 0x1929, 0x00c0,
+	0x16e3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16cc,
+	0x2d00, 0x6002, 0x0078, 0x16b2, 0x0c7f, 0x0c7e, 0x609c, 0x2060,
+	0x1078, 0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009,
+	0x000c, 0x6008, 0xa085, 0x0200, 0x600a, 0x1078, 0x1924, 0x1078,
+	0x1948, 0x0078, 0x172c, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078,
+	0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c,
+	0x6007, 0x0103, 0x601b, 0x0003, 0x1078, 0x1924, 0x1078, 0x1948,
+	0x0078, 0x172c, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091,
+	0x8000, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x5140, 0x706f, 0x0005,
+	0x7073, 0x0000, 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000,
+	0x2c00, 0x708a, 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2,
+	0xa184, 0x0060, 0x0040, 0x171e, 0x1078, 0x47c2, 0x0e7f, 0x6596,
+	0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078,
+	0x21d2, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287,
+	0x20a9, 0x0005, 0x2099, 0x5118, 0x2091, 0x8000, 0x530a, 0x2091,
+	0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+	0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284,
+	0x71c4, 0x71c6, 0x2168, 0x0078, 0x174f, 0x2069, 0x1000, 0x690c,
+	0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1751, 0xa285,
+	0x0000, 0x00c0, 0x175f, 0x70c3, 0x4000, 0x0078, 0x1761, 0x70c3,
+	0x4003, 0x70ca, 0x0078, 0x1287, 0x2011, 0x5167, 0x220c, 0x70c4,
+	0x8003, 0x0048, 0x1771, 0x1078, 0x3b7f, 0xa184, 0x7fff, 0x0078,
+	0x1775, 0x1078, 0x3b72, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283,
+	0x71c4, 0x1078, 0x3b69, 0x6100, 0x2001, 0x5167, 0x2004, 0xa084,
+	0x8000, 0xa10d, 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078,
+	0x1283, 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004,
+	0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078,
+	0x1284, 0x70c4, 0x2068, 0x2079, 0x5100, 0x2091, 0x8000, 0x1078,
+	0x192e, 0x2091, 0x8001, 0x0040, 0x1825, 0x6007, 0x0001, 0x600b,
+	0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f,
+	0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016,
+	0xa284, 0x0800, 0x0040, 0x17c0, 0x601b, 0x000a, 0x0078, 0x17c6,
+	0xa284, 0x1000, 0x0040, 0x17c6, 0x601b, 0x000c, 0xa284, 0x0300,
+	0x0040, 0x17cf, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085,
+	0x0001, 0x601e, 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400,
+	0x0040, 0x17dc, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b,
+	0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0,
+	0x17f1, 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078,
+	0x17fb, 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c,
+	0x6552, 0x6596, 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042,
+	0x2c08, 0x2061, 0x5140, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077,
+	0x0000, 0x607b, 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284,
+	0x0400, 0x608e, 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007,
+	0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000,
+	0x1078, 0x21d2, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078,
+	0x1287, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071,
+	0x5140, 0x2079, 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040,
+	0x18b1, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1844,
+	0xa286, 0x000f, 0x00c0, 0x18b1, 0x691c, 0xa184, 0x0080, 0x00c0,
+	0x18b1, 0x6824, 0xa18c, 0xff00, 0xa085, 0x0019, 0x6826, 0x71b0,
+	0x81ff, 0x0040, 0x1867, 0x0d7e, 0x2069, 0x0020, 0x6807, 0x0010,
+	0x6908, 0x6808, 0xa106, 0x00c0, 0x1858, 0x690c, 0x680c, 0xa106,
+	0x00c0, 0x185d, 0xa184, 0x00ff, 0x00c0, 0x185d, 0x0d7f, 0x78b8,
+	0xa084, 0x801f, 0x00c0, 0x1867, 0x7848, 0xa085, 0x000c, 0x784a,
+	0x71b0, 0x81ff, 0x0040, 0x188a, 0x70b3, 0x0000, 0x0d7e, 0x2069,
+	0x0020, 0x6807, 0x0018, 0x6804, 0xa084, 0x0008, 0x00c0, 0x187b,
+	0x6807, 0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x1882, 0x6807,
+	0x0002, 0x0d7f, 0x61c4, 0x62c8, 0x63cc, 0x61c6, 0x62ca, 0x63ce,
+	0x0e7e, 0x2071, 0x5100, 0x7266, 0x736a, 0xae80, 0x0019, 0x0e7f,
+	0x7848, 0xa084, 0x000c, 0x00c0, 0x1898, 0x1078, 0x46db, 0x78a3,
+	0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, 0xa080, 0x00df,
+	0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, 0x0078,
+	0x1284, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001, 0x2001,
+	0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, 0xa182, 0x0003,
+	0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, 0x71c6, 0x0078,
+	0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, 0x71ca, 0x71c8,
+	0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, 0x1284, 0x7974,
+	0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, 0x1284, 0x7900,
+	0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+	0x0048, 0x18ee, 0x0038, 0x18f0, 0x0078, 0x18fa, 0x00a8, 0x18fa,
+	0xa18c, 0x0001, 0x00c0, 0x18f8, 0x20b9, 0x2222, 0x0078, 0x18fa,
+	0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, 0x0078, 0x1284,
+	0x2009, 0x5174, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078, 0x1284,
+	0x2009, 0x5174, 0x2104, 0x70c6, 0x0078, 0x1284, 0x71c4, 0x8107,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x5380, 0x6a14,
+	0xd2b4, 0x0040, 0x191f, 0x2011, 0x0001, 0x0078, 0x1921, 0x2011,
+	0x0000, 0x6b0c, 0x0078, 0x1281, 0xac80, 0x0001, 0x1078, 0x1b0f,
+	0x007c, 0xac80, 0x0001, 0x1078, 0x1aaf, 0x007c, 0x7850, 0xa065,
+	0x0040, 0x1936, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c, 0x0f7e,
+	0x2079, 0x5100, 0x7850, 0xa06d, 0x0040, 0x1946, 0x2d04, 0x7852,
+	0x6803, 0x0000, 0x6807, 0x0000, 0x680b, 0x0000, 0x0f7f, 0x007c,
+	0x2091, 0x8000, 0x0f7e, 0x2079, 0x5100, 0x7850, 0x2062, 0x2c00,
+	0xa005, 0x00c0, 0x1955, 0x1078, 0x23eb, 0x7852, 0x0f7f, 0x2091,
+	0x8001, 0x007c, 0x0f7e, 0x2079, 0x5100, 0x7850, 0x206a, 0x2d00,
+	0x7852, 0x0f7f, 0x007c, 0x2011, 0x7800, 0x7a52, 0x7bec, 0x8319,
+	0x0040, 0x1970, 0xa280, 0x0031, 0x2012, 0x2010, 0x0078, 0x1967,
+	0x2013, 0x0000, 0x007c, 0xa784, 0x0f00, 0x800b, 0xa784, 0x001f,
+	0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x5400, 0x007c,
+	0x1078, 0x1973, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084,
+	0xffef, 0xa80d, 0x690a, 0x2009, 0x5152, 0x210c, 0x6804, 0xa005,
+	0x0040, 0x19b2, 0xa116, 0x00c0, 0x199d, 0x2060, 0x6000, 0x6806,
+	0x017e, 0x200b, 0x0000, 0x0078, 0x19a0, 0x2009, 0x0000, 0x017e,
+	0x6804, 0xa065, 0x0040, 0x19af, 0x6000, 0x6806, 0x1078, 0x19c0,
+	0x1078, 0x1c5f, 0x6810, 0x8001, 0x6812, 0x00c0, 0x19a0, 0x017f,
+	0x6902, 0x6906, 0x007c, 0xa065, 0x0040, 0x19bf, 0x609c, 0x609f,
+	0x0000, 0x2008, 0x1078, 0x1948, 0x2100, 0x0078, 0x19b3, 0x007c,
+	0x6007, 0x0103, 0x608f, 0x0000, 0x20a9, 0x001c, 0xac80, 0x0005,
+	0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828, 0x601a, 0x682c, 0x6022,
+	0x007c, 0x0e7e, 0x2071, 0x5140, 0x704c, 0xa08c, 0x0200, 0x00c0,
+	0x19df, 0xa088, 0x5180, 0x2d0a, 0x8000, 0x704e, 0xa006, 0x0e7f,
+	0x007c, 0x1078, 0x1973, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065,
+	0x0040, 0x1a2a, 0x0078, 0x19f2, 0x2c00, 0x781e, 0x6000, 0xa065,
+	0x0040, 0x1a2a, 0x600c, 0xa306, 0x00c0, 0x19ec, 0x6010, 0xa206,
+	0x00c0, 0x19ec, 0x2c28, 0x2001, 0x5152, 0x2004, 0xac06, 0x00c0,
+	0x1a03, 0x0078, 0x1a28, 0x6804, 0xac06, 0x00c0, 0x1a10, 0x6000,
+	0xa065, 0x6806, 0x00c0, 0x1a1a, 0x6803, 0x0000, 0x0078, 0x1a1a,
+	0x6400, 0x781c, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1a1a,
+	0x2c00, 0x6802, 0x2560, 0x1078, 0x19c0, 0x601b, 0x0005, 0x6023,
+	0x0020, 0x1078, 0x1c5f, 0x6810, 0x8001, 0x1050, 0x23eb, 0x6812,
+	0xa085, 0xffff, 0x007c, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049,
+	0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1980, 0x8738,
+	0xa784, 0x001f, 0x00c0, 0x1a35, 0xa7bc, 0xff00, 0x873f, 0x8738,
+	0x873f, 0xa784, 0x0f00, 0x00c0, 0x1a35, 0x2091, 0x8001, 0x007c,
+	0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1a59, 0x2091,
+	0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091, 0x8001, 0xa005, 0x00c0,
+	0x1a5a, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1a60, 0x1078, 0x23eb,
+	0x0079, 0x1a62, 0x1a72, 0x1a75, 0x1a7b, 0x1a7f, 0x1a73, 0x1a83,
+	0x1a89, 0x1a73, 0x1a73, 0x1c29, 0x1c4d, 0x1c51, 0x1a73, 0x1a73,
+	0x1a73, 0x1a73, 0x007c, 0x1078, 0x23eb, 0x1078, 0x1a2b, 0x2001,
+	0x8001, 0x0078, 0x1c57, 0x2001, 0x8003, 0x0078, 0x1c57, 0x2001,
+	0x8004, 0x0078, 0x1c57, 0x1078, 0x1a2b, 0x2001, 0x8006, 0x0078,
+	0x1c57, 0x2001, 0x8007, 0x0078, 0x1c57, 0x2030, 0x2138, 0xa782,
+	0x0021, 0x0048, 0x1a95, 0x2009, 0x0020, 0x2600, 0x1078, 0x1aaf,
+	0x00c0, 0x1aae, 0xa7ba, 0x0020, 0x0048, 0x1aad, 0x0040, 0x1aad,
+	0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1,
+	0x0000, 0xa5a9, 0x0000, 0x0078, 0x1a8f, 0xa006, 0x007c, 0x81ff,
+	0x0040, 0x1aea, 0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, 0x00ff,
+	0x0040, 0x1ac1, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+	0x1abc, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, 0x731e,
+	0x7422, 0x7526, 0x780c, 0xa085, 0x0001, 0x7002, 0x7007, 0x0001,
+	0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x1ade, 0x2009,
+	0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1ad0, 0x7008, 0x800b,
+	0x00c8, 0x1ad0, 0x7007, 0x0002, 0xa08c, 0x01e0, 0x00c0, 0x1aea,
+	0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x2030, 0x2138, 0xa782,
+	0x0021, 0x0048, 0x1af5, 0x2009, 0x0020, 0x2600, 0x1078, 0x1b0f,
+	0x00c0, 0x1b0e, 0xa7ba, 0x0020, 0x0048, 0x1b0d, 0x0040, 0x1b0d,
+	0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1,
+	0x0000, 0xa5a9, 0x0000, 0x0078, 0x1aef, 0xa006, 0x007c, 0x81ff,
+	0x0040, 0x1b50, 0x2098, 0x20a1, 0x0030, 0x700c, 0xa084, 0x00ff,
+	0x0040, 0x1b21, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0,
+	0x1b1c, 0x21a8, 0x7017, 0x0000, 0x810b, 0x7112, 0x721a, 0x731e,
+	0x7422, 0x7526, 0x780c, 0xa085, 0x0000, 0x7002, 0x53a6, 0x7007,
+	0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x1b3f,
+	0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0, 0x1b31, 0x7010,
+	0xa084, 0xf000, 0x0040, 0x1b48, 0x7007, 0x0008, 0x0078, 0x1b4c,
+	0x7108, 0x8103, 0x00c8, 0x1b31, 0x7007, 0x0002, 0xa184, 0x01e0,
+	0x7003, 0x0000, 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0004,
+	0x00c8, 0x1b5c, 0x0078, 0x1b5f, 0xa006, 0x0078, 0x1b61, 0xa085,
+	0x0001, 0x007c, 0x0e7e, 0x2071, 0x5100, 0x2d08, 0x7058, 0x6802,
+	0xa005, 0x00c0, 0x1b6c, 0x715e, 0x715a, 0x0e7f, 0x007c, 0x2c08,
+	0x7858, 0x6002, 0xa005, 0x00c0, 0x1b76, 0x795e, 0x795a, 0x007c,
+	0x2091, 0x8000, 0x6003, 0x0000, 0x2c08, 0x785c, 0xa065, 0x00c0,
+	0x1b84, 0x795a, 0x0078, 0x1b85, 0x6102, 0x795e, 0x2091, 0x8001,
+	0x1078, 0x21ef, 0x007c, 0x0e7e, 0x2071, 0x5100, 0x7058, 0xa06d,
+	0x0040, 0x1b99, 0x6800, 0x705a, 0xa005, 0x00c0, 0x1b98, 0x705e,
+	0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5100,
+	0xaf80, 0x0016, 0x2060, 0x6000, 0xa005, 0x0040, 0x1bc9, 0x2068,
+	0x6814, 0xa306, 0x00c0, 0x1bb2, 0x6828, 0xa084, 0x00ff, 0xa406,
+	0x0040, 0x1bb5, 0x2d60, 0x0078, 0x1ba3, 0x6800, 0xa005, 0x6002,
+	0x00c0, 0x1bc1, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1bc0, 0x2c00,
+	0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bc8, 0x1078, 0x19b3,
+	0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x0d7e, 0x0c7e,
+	0x0f7e, 0x2079, 0x5100, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005,
+	0x0040, 0x1bf8, 0x2068, 0x6814, 0xa084, 0x00ff, 0xa306, 0x0040,
+	0x1be4, 0x2d60, 0x0078, 0x1bd6, 0x6800, 0xa005, 0x6002, 0x00c0,
+	0x1bf0, 0xaf80, 0x0016, 0xac06, 0x0040, 0x1bef, 0x2c00, 0x785e,
+	0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bf7, 0x1078, 0x19b3, 0x007f,
+	0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x0d7e, 0x0c7e, 0x0f7e,
+	0x2079, 0x5100, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa06d, 0x0040,
+	0x1c24, 0x6814, 0xa306, 0x0040, 0x1c10, 0x2d60, 0x0078, 0x1c05,
+	0x6800, 0xa005, 0x6002, 0x00c0, 0x1c1c, 0xaf80, 0x0016, 0xac06,
+	0x0040, 0x1c1b, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040,
+	0x1c23, 0x1078, 0x19b3, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005,
+	0x007c, 0x2091, 0x8000, 0x2069, 0x5140, 0x6800, 0xa086, 0x0000,
+	0x0040, 0x1c37, 0x2091, 0x8001, 0x78e3, 0x0009, 0x007c, 0x6880,
+	0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010,
+	0x1078, 0x1980, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1c40, 0x2091,
+	0x8001, 0x2001, 0x800a, 0x0078, 0x1c57, 0x2001, 0x800c, 0x0078,
+	0x1c57, 0x1078, 0x1a2b, 0x2001, 0x800d, 0x0078, 0x1c57, 0x70c2,
+	0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080, 0x007c, 0x6004,
+	0x2c08, 0x2063, 0x0000, 0x7884, 0x8000, 0x7886, 0x7888, 0xa005,
+	0x798a, 0x0040, 0x1c6e, 0x2c02, 0x0078, 0x1c6f, 0x798e, 0x007c,
+	0x6807, 0x0103, 0x0c7e, 0x2061, 0x5100, 0x2d08, 0x206b, 0x0000,
+	0x6084, 0x8000, 0x6086, 0x6088, 0xa005, 0x618a, 0x0040, 0x1c83,
+	0x2d02, 0x0078, 0x1c84, 0x618e, 0x0c7f, 0x007c, 0x1078, 0x1c97,
+	0x0040, 0x1c96, 0x0c7e, 0x609c, 0xa065, 0x0040, 0x1c91, 0x1078,
+	0x19b3, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1948, 0x007c, 0x788c,
+	0xa065, 0x0040, 0x1ca9, 0x2091, 0x8000, 0x7884, 0x8001, 0x7886,
+	0x2c04, 0x788e, 0xa005, 0x00c0, 0x1ca7, 0x788a, 0x8000, 0x2091,
+	0x8001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e,
+	0x00c8, 0x1cb3, 0xa200, 0x0070, 0x1cb7, 0x0078, 0x1cae, 0x8086,
+	0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x1cdd,
+	0xa11a, 0x00c8, 0x1cdd, 0x8213, 0x818d, 0x0048, 0x1cce, 0xa11a,
+	0x00c8, 0x1ccf, 0x0070, 0x1cd5, 0x0078, 0x1cc3, 0xa11a, 0x2308,
+	0x8210, 0x0070, 0x1cd5, 0x0078, 0x1cc3, 0x007e, 0x3200, 0xa084,
+	0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085,
+	0x0800, 0x0078, 0x1cd9, 0x7994, 0x70d0, 0xa106, 0x0040, 0x1d51,
+	0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x1d51,
+	0x7008, 0x7208, 0xa206, 0x00c0, 0x1d51, 0xa286, 0x0008, 0x00c0,
+	0x1d51, 0x2071, 0x0010, 0x1078, 0x192e, 0x0040, 0x1d51, 0x7a9c,
+	0x7b98, 0x7ca4, 0x7da0, 0xa184, 0xff00, 0x0040, 0x1d1f, 0x2031,
+	0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b,
+	0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x2100, 0xa210, 0x2600,
+	0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1d29, 0x8107,
+	0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+	0x0000, 0x2009, 0x0020, 0x1078, 0x1929, 0x2091, 0x8001, 0x0040,
+	0x1d48, 0x1078, 0x1948, 0x78a8, 0x8000, 0x78aa, 0xa086, 0x0002,
+	0x00c0, 0x1d51, 0x2091, 0x8000, 0x78e3, 0x0002, 0x78ab, 0x0000,
+	0x78cc, 0xa085, 0x0003, 0x78ce, 0x2091, 0x8001, 0x0078, 0x1d51,
+	0x78ab, 0x0000, 0x1078, 0x20ac, 0x6004, 0xa084, 0x000f, 0x0079,
+	0x1d56, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x1d66, 0x1d88,
+	0x1dae, 0x1d66, 0x1dcb, 0x1d75, 0x1f2c, 0x1f47, 0x1d66, 0x1d82,
+	0x1da8, 0x1e13, 0x1e82, 0x1ed2, 0x1ee4, 0x1f43, 0x2039, 0x0400,
+	0x78dc, 0xa705, 0x78de, 0x6008, 0xa705, 0x600a, 0x1078, 0x1fc7,
+	0x609c, 0x78da, 0x1078, 0x2094, 0x007c, 0x78dc, 0xa084, 0x0100,
+	0x0040, 0x1d7c, 0x0078, 0x1d66, 0x601c, 0xa085, 0x0080, 0x601e,
+	0x0078, 0x1d8f, 0x1078, 0x1b53, 0x00c0, 0x1d66, 0x1078, 0x20c6,
+	0x78dc, 0xa084, 0x0100, 0x0040, 0x1d8f, 0x0078, 0x1d66, 0x78df,
+	0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f,
+	0x0000, 0x0040, 0x1da5, 0x1078, 0x1fc7, 0x0040, 0x1da5, 0x78dc,
+	0xa085, 0x0100, 0x78de, 0x0078, 0x1da7, 0x1078, 0x1feb, 0x007c,
+	0x1078, 0x1b53, 0x00c0, 0x1d66, 0x1078, 0x20c2, 0x78dc, 0xa08c,
+	0x0e00, 0x00c0, 0x1db7, 0xa084, 0x0100, 0x00c0, 0x1db9, 0x0078,
+	0x1d66, 0x1078, 0x1fc7, 0x00c0, 0x1dca, 0x6104, 0xa18c, 0x00ff,
+	0xa186, 0x0007, 0x0040, 0x1f84, 0xa186, 0x000f, 0x0040, 0x1f84,
+	0x1078, 0x1feb, 0x007c, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1dd2,
+	0x0078, 0x1d66, 0x78df, 0x0000, 0x6714, 0x2011, 0x0001, 0x20a9,
+	0x0001, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040, 0x1df5, 0x2011,
+	0x0001, 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040,
+	0x1df5, 0x2039, 0x0000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e,
+	0x0002, 0x0040, 0x1df5, 0x0078, 0x1e10, 0x1078, 0x1973, 0x2091,
+	0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde,
+	0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x0070, 0x1e09, 0x0078,
+	0x1df7, 0x8211, 0x0040, 0x1e10, 0x20a9, 0x0100, 0x0078, 0x1df7,
+	0x1078, 0x1948, 0x007c, 0x2001, 0x5167, 0x2004, 0xa084, 0x8000,
+	0x0040, 0x1fac, 0x6114, 0x1078, 0x20e3, 0x6900, 0xa184, 0x0001,
+	0x0040, 0x1e34, 0x6028, 0xa084, 0x00ff, 0x00c0, 0x1fa4, 0x6800,
+	0xa084, 0x0001, 0x0040, 0x1fac, 0x6803, 0x0000, 0x680b, 0x0000,
+	0x6807, 0x0000, 0x0078, 0x1fb4, 0x2011, 0x0001, 0x6020, 0xd0f4,
+	0x0040, 0x1e3c, 0xa295, 0x0002, 0xd0c4, 0x0040, 0x1e41, 0xa295,
+	0x0008, 0xd0cc, 0x0040, 0x1e46, 0xa295, 0x0400, 0x601c, 0xa084,
+	0x0002, 0x0040, 0x1e4d, 0xa295, 0x0004, 0x602c, 0xa08c, 0x00ff,
+	0xa182, 0x0002, 0x0048, 0x1fb0, 0xa182, 0x001b, 0x00c8, 0x1fb0,
+	0x0040, 0x1fb0, 0x690e, 0x602c, 0x8007, 0xa08c, 0x00ff, 0xa182,
+	0x0002, 0x0048, 0x1fb0, 0xa182, 0x001b, 0x00c8, 0x1fb0, 0x0040,
+	0x1fb0, 0x6912, 0x6030, 0xa005, 0x00c0, 0x1e70, 0x2001, 0x001e,
+	0x8000, 0x6816, 0x6028, 0xa084, 0x00ff, 0x0040, 0x1fac, 0x6806,
+	0x6028, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1fac, 0x680a, 0x6a02,
+	0x0078, 0x1fb4, 0x2001, 0x5167, 0x2004, 0xa084, 0x8000, 0x0040,
+	0x1fac, 0x6114, 0x1078, 0x20e3, 0x2091, 0x8000, 0x6a04, 0x6b08,
+	0x6418, 0xa484, 0x0003, 0x0040, 0x1ea8, 0x6128, 0xa18c, 0x00ff,
+	0x8001, 0x00c0, 0x1ea1, 0x2100, 0xa210, 0x0048, 0x1ece, 0x0078,
+	0x1ea8, 0x8001, 0x00c0, 0x1ece, 0x2100, 0xa212, 0x0048, 0x1ece,
+	0xa484, 0x000c, 0x0040, 0x1ec2, 0x6128, 0x810f, 0xa18c, 0x00ff,
+	0xa082, 0x0004, 0x00c0, 0x1eba, 0x2100, 0xa318, 0x0048, 0x1ece,
+	0x0078, 0x1ec2, 0xa082, 0x0004, 0x00c0, 0x1ece, 0x2100, 0xa31a,
+	0x0048, 0x1ece, 0x6030, 0xa005, 0x0040, 0x1ec8, 0x8000, 0x6816,
+	0x6a06, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1fb4, 0x2091, 0x8001,
+	0x0078, 0x1fb0, 0x6114, 0x1078, 0x20e3, 0x2091, 0x8000, 0x6b08,
+	0x8318, 0x0048, 0x1ee0, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1fc3,
+	0x2091, 0x8001, 0x0078, 0x1fb0, 0x6024, 0x8007, 0xa084, 0x00ff,
+	0x0040, 0x1f02, 0xa086, 0x0080, 0x00c0, 0x1f2a, 0x20a9, 0x0008,
+	0x2069, 0x7510, 0x2091, 0x8000, 0x6800, 0xa084, 0xfcff, 0x6802,
+	0xade8, 0x0008, 0x0070, 0x1efe, 0x0078, 0x1ef4, 0x2091, 0x8001,
+	0x0078, 0x1fb4, 0x6028, 0xa015, 0x0040, 0x1f2a, 0x6114, 0x1078,
+	0x20e3, 0x0d7e, 0xade8, 0x0007, 0x2091, 0x8000, 0x6800, 0xa00d,
+	0x0040, 0x1f27, 0xa206, 0x0040, 0x1f18, 0x2168, 0x0078, 0x1f0e,
+	0x0c7e, 0x2160, 0x6000, 0x6802, 0x1078, 0x1948, 0x0c7f, 0x0d7f,
+	0x6808, 0x8000, 0x680a, 0x2091, 0x8001, 0x0078, 0x1fc3, 0x2091,
+	0x8001, 0x0d7f, 0x0078, 0x1fac, 0x6114, 0x1078, 0x20e3, 0x6800,
+	0xa084, 0x0001, 0x0040, 0x1f9c, 0x2091, 0x8000, 0x6a04, 0x8210,
+	0x0048, 0x1f3f, 0x6a06, 0x2091, 0x8001, 0x0078, 0x1fc3, 0x2091,
+	0x8001, 0x0078, 0x1fb0, 0x1078, 0x1b53, 0x00c0, 0x1d66, 0x6114,
+	0x1078, 0x20e3, 0x60be, 0x60bb, 0x0000, 0x6900, 0xa184, 0x0008,
+	0x0040, 0x1f56, 0x6020, 0xa085, 0x0100, 0x6022, 0xa184, 0x0001,
+	0x0040, 0x1fac, 0xa184, 0x0100, 0x00c0, 0x1f98, 0xa184, 0x0200,
+	0x00c0, 0x1f94, 0x681c, 0xa005, 0x00c0, 0x1fa0, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x000f, 0x00c0, 0x1f6f, 0x1078, 0x20c6, 0x78df,
+	0x0000, 0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f,
+	0x0000, 0x0040, 0x1f84, 0x1078, 0x1fc7, 0x0040, 0x1f84, 0x78dc,
+	0xa085, 0x0100, 0x78de, 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000,
+	0x6024, 0xa084, 0xff00, 0x6026, 0x1078, 0x39de, 0x0040, 0x1ce3,
+	0x1078, 0x1b78, 0x0078, 0x1ce3, 0x2009, 0x0017, 0x0078, 0x1fb6,
+	0x2009, 0x000e, 0x0078, 0x1fb6, 0x2009, 0x0007, 0x0078, 0x1fb6,
+	0x2009, 0x0035, 0x0078, 0x1fb6, 0x2009, 0x003e, 0x0078, 0x1fb6,
+	0x2009, 0x0004, 0x0078, 0x1fb6, 0x2009, 0x0006, 0x0078, 0x1fb6,
+	0x2009, 0x0016, 0x0078, 0x1fb6, 0x2009, 0x0001, 0x6024, 0xa084,
+	0xff00, 0xa105, 0x6026, 0x2091, 0x8000, 0x1078, 0x1c5f, 0x2091,
+	0x8001, 0x0078, 0x1ce3, 0x1078, 0x1948, 0x0078, 0x1ce3, 0x78d4,
+	0xa06d, 0x00c0, 0x1fd2, 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000,
+	0x0078, 0x1fde, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00,
+	0x6002, 0x78d8, 0xad06, 0x00c0, 0x1fde, 0x6002, 0x78d0, 0x8001,
+	0x78d2, 0x00c0, 0x1fea, 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8,
+	0x2060, 0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184,
+	0xe1ff, 0x601e, 0xa184, 0x0060, 0x0040, 0x1ffa, 0x0e7e, 0x1078,
+	0x47c2, 0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000,
+	0x60b3, 0x0000, 0x6714, 0x1078, 0x1973, 0x2091, 0x8000, 0x60a0,
+	0xa084, 0x8000, 0x00c0, 0x2021, 0x6808, 0xa084, 0x0001, 0x0040,
+	0x2021, 0x2091, 0x8001, 0x1078, 0x19c0, 0x2091, 0x8000, 0x1078,
+	0x1c5f, 0x2091, 0x8001, 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078,
+	0x2093, 0x6024, 0xa096, 0x0001, 0x00c0, 0x2028, 0x8000, 0x6026,
+	0x6a10, 0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x2037, 0x0040,
+	0x2037, 0x2039, 0x0200, 0x1078, 0x2094, 0x0078, 0x2093, 0x2c08,
+	0x2091, 0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x2064, 0x6800,
+	0xa065, 0x0040, 0x2069, 0x6a04, 0x0e7e, 0x2071, 0x5140, 0x7000,
+	0xa084, 0x0001, 0x0040, 0x205e, 0x7048, 0xa206, 0x00c0, 0x205e,
+	0x6b04, 0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, 0x2059,
+	0x6902, 0x2260, 0x6102, 0x0e7f, 0x0078, 0x2070, 0x2160, 0x6202,
+	0x6906, 0x0e7f, 0x0078, 0x2070, 0x6800, 0xa065, 0x0040, 0x2069,
+	0x6102, 0x6902, 0x00c0, 0x206d, 0x6906, 0x2160, 0x6003, 0x0000,
+	0x2160, 0x60a0, 0xa084, 0x8000, 0x0040, 0x207a, 0x6808, 0xa084,
+	0xfffc, 0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808,
+	0xa08c, 0x0040, 0x0040, 0x2089, 0xa086, 0x0040, 0x680a, 0x1078,
+	0x19d1, 0x2091, 0x8000, 0x1078, 0x21d2, 0x2091, 0x8001, 0x78db,
+	0x0000, 0x78d7, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091,
+	0x8000, 0x1078, 0x1c5f, 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040,
+	0x20a7, 0x609c, 0x78da, 0x609f, 0x0000, 0x0078, 0x2097, 0x78d7,
+	0x0000, 0x78db, 0x0000, 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a,
+	0x00c8, 0x20b3, 0xa006, 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040,
+	0x20c1, 0x8001, 0x7806, 0x00c0, 0x20c1, 0x0068, 0x20c1, 0x2091,
+	0x4080, 0x007c, 0x2039, 0x20da, 0x0078, 0x20c8, 0x2039, 0x20e0,
+	0x2704, 0xa005, 0x0040, 0x20d9, 0xac00, 0x2068, 0x6b08, 0x6c0c,
+	0x6910, 0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078,
+	0x20c8, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000,
+	0x0015, 0x001b, 0x0000, 0x0c7e, 0x1078, 0x3b69, 0x2c68, 0x0c7f,
+	0x007c, 0x0010, 0x215a, 0x0068, 0x215a, 0x2029, 0x0000, 0x78cb,
+	0x0000, 0x788c, 0xa065, 0x0040, 0x2153, 0x2009, 0x5174, 0x2104,
+	0xa084, 0x0001, 0x0040, 0x2121, 0x6004, 0xa086, 0x0103, 0x00c0,
+	0x2121, 0x6018, 0xa005, 0x00c0, 0x2121, 0x6014, 0xa005, 0x00c0,
+	0x2121, 0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0,
+	0x2120, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b,
+	0x0001, 0x2091, 0x4080, 0x0d7f, 0x1078, 0x1c86, 0x0078, 0x2158,
+	0x0d7f, 0x1078, 0x215b, 0x0040, 0x2153, 0x6204, 0xa294, 0x00ff,
+	0xa296, 0x0003, 0x0040, 0x2133, 0x6204, 0xa296, 0x0110, 0x00c0,
+	0x2141, 0x78cb, 0x0001, 0x6204, 0xa294, 0xff00, 0x8217, 0x8211,
+	0x0040, 0x2141, 0x85ff, 0x00c0, 0x2153, 0x8210, 0xa202, 0x00c8,
+	0x2153, 0x057e, 0x1078, 0x216a, 0x057f, 0x0040, 0x214e, 0x78e0,
+	0xa086, 0x0003, 0x0040, 0x2153, 0x0078, 0x2141, 0x8528, 0x78c8,
+	0xa005, 0x0040, 0x20f1, 0x85ff, 0x0040, 0x215a, 0x2091, 0x4080,
+	0x78b0, 0x70d6, 0x007c, 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0,
+	0x2164, 0x2300, 0xa005, 0x007c, 0x0048, 0x2168, 0xa302, 0x007c,
+	0x8002, 0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8,
+	0x2184, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0,
+	0x21b9, 0x7008, 0x7208, 0xa206, 0x00c0, 0x21b9, 0xa286, 0x0008,
+	0x00c0, 0x21b9, 0x2071, 0x0010, 0x1078, 0x21be, 0x2009, 0x0020,
+	0x6004, 0xa086, 0x0103, 0x00c0, 0x2193, 0x6028, 0xa005, 0x00c0,
+	0x2193, 0x2009, 0x000c, 0x1078, 0x1924, 0x0040, 0x21ac, 0x78c4,
+	0x8000, 0x78c6, 0xa086, 0x0002, 0x00c0, 0x21b9, 0x2091, 0x8000,
+	0x78e3, 0x0003, 0x78c7, 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce,
+	0x2091, 0x8001, 0x0078, 0x21b9, 0x78c7, 0x0000, 0x1078, 0x1c86,
+	0x79ac, 0x78b0, 0x8000, 0xa10a, 0x00c8, 0x21b7, 0xa006, 0x78b2,
+	0xa006, 0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107, 0x8004,
+	0x8004, 0x7ab8, 0x7bb4, 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000,
+	0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x515b, 0x2091,
+	0x8000, 0x200a, 0x0f7e, 0x0e7e, 0x2071, 0x5140, 0x7000, 0xa086,
+	0x0000, 0x00c0, 0x21ec, 0x2009, 0x5112, 0x2104, 0xa005, 0x00c0,
+	0x21ec, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21ec,
+	0x0018, 0x21ec, 0x781b, 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e,
+	0x0e7e, 0x2071, 0x5140, 0x2091, 0x8000, 0x7000, 0xa086, 0x0000,
+	0x00c0, 0x2205, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0,
+	0x2205, 0x0018, 0x2205, 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f,
+	0x0f7f, 0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x5140, 0x2079,
+	0x0100, 0x784b, 0x000f, 0x0098, 0x2218, 0x7838, 0x0078, 0x2211,
+	0x20a9, 0x0040, 0x7800, 0xa082, 0x0004, 0x0048, 0x2221, 0x20a9,
+	0x0060, 0x789b, 0x0000, 0x78af, 0x0000, 0x78af, 0x0000, 0x0070,
+	0x222b, 0x0078, 0x2223, 0x7800, 0xa082, 0x0004, 0x0048, 0x223a,
+	0x70b7, 0x0096, 0x2019, 0x4ee7, 0x1078, 0x2276, 0x702f, 0x8001,
+	0x0078, 0x2246, 0x70b7, 0x0000, 0x2019, 0x4d5f, 0x1078, 0x2276,
+	0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x7003, 0x0000,
+	0x1078, 0x237f, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd,
+	0x210c, 0xa18a, 0x0005, 0x0048, 0x225b, 0x0038, 0x2261, 0xa085,
+	0x6280, 0x0078, 0x2263, 0x0028, 0x2261, 0xa085, 0x6280, 0x0078,
+	0x2263, 0xa085, 0x62c0, 0x017f, 0x7806, 0x780f, 0xb204, 0x7843,
+	0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x0008, 0x7053,
+	0x517f, 0x704f, 0x0000, 0x127f, 0x2000, 0x007c, 0x137e, 0x147e,
+	0x157e, 0x047e, 0x20a1, 0x012b, 0x2304, 0xa005, 0x789a, 0x0040,
+	0x2296, 0x8318, 0x2324, 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00,
+	0x0040, 0x228e, 0xa482, 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6,
+	0xa005, 0x00c0, 0x2285, 0x3318, 0x0078, 0x227c, 0x047f, 0x157f,
+	0x147f, 0x137f, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204,
+	0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x237f, 0x007c, 0x2011,
+	0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x22b0, 0x0078, 0x22ab,
+	0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c,
+	0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x22c1, 0x0078,
+	0x22bc, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a,
+	0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x22d2,
+	0x0078, 0x22cd, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105,
+	0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105,
+	0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061,
+	0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003,
+	0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084,
+	0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022,
+	0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae,
+	0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061,
+	0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018,
+	0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005,
+	0x0040, 0x235d, 0x2061, 0x7500, 0x1078, 0x2365, 0x0040, 0x2349,
+	0x20a9, 0x0000, 0x2061, 0x7400, 0x0c7e, 0x1078, 0x2365, 0x0040,
+	0x2339, 0x0c7f, 0x8c60, 0x0070, 0x2337, 0x0078, 0x232c, 0x0078,
+	0x235d, 0x007f, 0xa082, 0x7400, 0x2071, 0x5140, 0x7086, 0x7182,
+	0x2001, 0x0004, 0x706e, 0x7093, 0x000f, 0x1078, 0x21cd, 0x0078,
+	0x2359, 0x60c0, 0xa005, 0x00c0, 0x235d, 0x2071, 0x5140, 0x7182,
+	0x2c00, 0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x1078,
+	0x21cd, 0x2001, 0x0000, 0x0078, 0x235f, 0x2001, 0x0001, 0x2091,
+	0x8001, 0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040,
+	0x237c, 0x2060, 0x600c, 0xa306, 0x00c0, 0x2379, 0x6010, 0xa206,
+	0x00c0, 0x2379, 0x6014, 0xa106, 0x00c0, 0x2379, 0xa006, 0x0078,
+	0x237e, 0x6000, 0x0078, 0x2366, 0xa085, 0x0001, 0x007c, 0x2011,
+	0x5141, 0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084,
+	0x0100, 0x0040, 0x2395, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b,
+	0x810b, 0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4,
+	0xa08c, 0x0020, 0x0040, 0x23e9, 0xa084, 0x0006, 0x00c0, 0x23e9,
+	0x6014, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0,
+	0x5380, 0x7004, 0xa084, 0x000a, 0x00c0, 0x23e9, 0x7108, 0xa194,
+	0xff00, 0x0040, 0x23e9, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106,
+	0x0040, 0x23d0, 0x2001, 0x0012, 0xa106, 0x0040, 0x23d4, 0x2001,
+	0x0014, 0xa106, 0x0040, 0x23d8, 0x2001, 0x0019, 0xa106, 0x0040,
+	0x23dc, 0x2001, 0x0032, 0xa106, 0x0040, 0x23e0, 0x0078, 0x23e4,
+	0x2009, 0x0012, 0x0078, 0x23e6, 0x2009, 0x0014, 0x0078, 0x23e6,
+	0x2009, 0x0019, 0x0078, 0x23e6, 0x2009, 0x0020, 0x0078, 0x23e6,
+	0x2009, 0x003f, 0x0078, 0x23e6, 0x2011, 0x0000, 0x2100, 0xa205,
+	0x700a, 0x0e7f, 0x007c, 0x0068, 0x23eb, 0x2091, 0x8000, 0x2071,
+	0x0000, 0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x23f2, 0x007f,
+	0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db,
+	0x0741, 0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091,
+	0x4080, 0x0078, 0x2409, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300,
+	0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, 0x75ce,
+	0xa594, 0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, 0x2420,
+	0x2432, 0x2432, 0x2432, 0x276c, 0x393b, 0x2430, 0x2461, 0x246b,
+	0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430, 0x2430,
+	0x1078, 0x23eb, 0x8507, 0xa084, 0x001f, 0x0079, 0x2437, 0x2475,
+	0x276c, 0x2926, 0x2a23, 0x2a4b, 0x2ced, 0x2f98, 0x2fdb, 0x3026,
+	0x30ab, 0x3163, 0x320c, 0x2461, 0x2848, 0x2f6d, 0x2457, 0x3cc8,
+	0x3ce8, 0x3eae, 0x3eba, 0x3f8f, 0x2457, 0x2457, 0x4062, 0x4066,
+	0x3cc6, 0x2457, 0x3e19, 0x2457, 0x3b8c, 0x246b, 0x2457, 0x1078,
+	0x23eb, 0x0018, 0x2410, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f,
+	0x007c, 0x2019, 0x4e3b, 0x1078, 0x2276, 0x702f, 0x0001, 0x781b,
+	0x004f, 0x0078, 0x2459, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f,
+	0x8000, 0x781b, 0x00d0, 0x0078, 0x2459, 0x7242, 0x2009, 0x510f,
+	0x200b, 0x0000, 0xa584, 0x0001, 0x00c0, 0x3ba0, 0x0040, 0x2492,
+	0x1078, 0x23eb, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, 0x0000,
+	0x7037, 0x0000, 0x1078, 0x3912, 0x0018, 0x2410, 0x2009, 0x510f,
+	0x200b, 0x0000, 0x7068, 0xa005, 0x00c0, 0x255d, 0x706c, 0xa084,
+	0x0007, 0x0079, 0x249b, 0x2594, 0x24a3, 0x24af, 0x24cc, 0x24ee,
+	0x253b, 0x2514, 0x24a3, 0x1078, 0x38fa, 0x2009, 0x0048, 0x1078,
+	0x2e39, 0x00c0, 0x24ad, 0x7003, 0x0004, 0x0078, 0x2459, 0x1078,
+	0x38fa, 0x00c0, 0x24ca, 0x7080, 0x8007, 0x7882, 0x789b, 0x0010,
+	0x78ab, 0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004,
+	0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x24ca, 0x7003, 0x0004,
+	0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x24ec,
+	0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d,
+	0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002,
+	0x785b, 0x0004, 0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x24ec,
+	0x7003, 0x0004, 0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa,
+	0x00c0, 0x2512, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c,
+	0x001f, 0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, 0x79aa,
+	0x78ab, 0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004,
+	0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x2512, 0x7003, 0x0004,
+	0x7093, 0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x2539,
+	0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d,
+	0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002,
+	0x785b, 0x0004, 0x2009, 0x00e0, 0x1078, 0x2e2d, 0x00c0, 0x2539,
+	0x7088, 0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, 0x7093,
+	0x000f, 0x0078, 0x2459, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x7088,
+	0x2068, 0x6f14, 0x1078, 0x37ef, 0x2c50, 0x1078, 0x39ac, 0x789b,
+	0x0010, 0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x6e1c,
+	0x2041, 0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, 0x0040,
+	0x255b, 0x2001, 0x0006, 0x0078, 0x267c, 0x1078, 0x38fa, 0x00c0,
+	0x2459, 0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, 0x37ef,
+	0x2c50, 0x1078, 0x39ac, 0x6008, 0xa085, 0x0010, 0x600a, 0x6824,
+	0xa005, 0x0040, 0x257b, 0xa082, 0x0006, 0x0048, 0x2579, 0x0078,
+	0x257b, 0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0,
+	0x7058, 0xa084, 0x8000, 0x0040, 0x2589, 0xa684, 0x0001, 0x0040,
+	0x258b, 0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, 0x0001,
+	0x2001, 0x0003, 0x0078, 0x267c, 0x0018, 0x2410, 0x744c, 0xa485,
+	0x0000, 0x0040, 0x25ae, 0xa080, 0x5180, 0x2030, 0x7150, 0x8108,
+	0xa12a, 0x0048, 0x25a5, 0x2009, 0x5180, 0x2164, 0x6504, 0x85ff,
+	0x00c0, 0x25bf, 0x8421, 0x00c0, 0x259f, 0x7152, 0x7003, 0x0000,
+	0x704b, 0x0000, 0x7040, 0xa005, 0x0040, 0x3ba0, 0x0078, 0x2459,
+	0x764c, 0xa6b0, 0x5180, 0x7150, 0x2600, 0x0078, 0x25aa, 0x7152,
+	0x2568, 0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0,
+	0x25bc, 0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x25f5, 0xa784,
+	0x0021, 0x00c0, 0x25bc, 0xa784, 0x0002, 0x0040, 0x25de, 0xa784,
+	0x0004, 0x0040, 0x25bc, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008,
+	0x00c0, 0x25bc, 0xa784, 0x0010, 0x00c0, 0x25bc, 0xa784, 0x0200,
+	0x00c0, 0x25bc, 0xa784, 0x0100, 0x0040, 0x25f5, 0x6018, 0xa005,
+	0x00c0, 0x25bc, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c,
+	0xa684, 0x000e, 0x6118, 0x0040, 0x2605, 0x601c, 0xa102, 0x0048,
+	0x2608, 0x0040, 0x2608, 0x0078, 0x25b8, 0x81ff, 0x00c0, 0x25b8,
+	0x68c3, 0x0000, 0xa784, 0x0080, 0x00c0, 0x2610, 0x700c, 0x6022,
+	0xa7bc, 0xff7f, 0x670a, 0x1078, 0x39ac, 0x0018, 0x2410, 0x789b,
+	0x0010, 0xa046, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x6b14, 0xa39c,
+	0x001f, 0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x262c,
+	0xa684, 0x0001, 0x0040, 0x262e, 0xa39c, 0xffbf, 0xa684, 0x0010,
+	0x0040, 0x2634, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e,
+	0x00c0, 0x263f, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x267a, 0x7158,
+	0xa18c, 0x0800, 0x0040, 0x3401, 0x2011, 0x0020, 0xa684, 0x0008,
+	0x00c0, 0x2650, 0x8210, 0xa684, 0x0002, 0x00c0, 0x2650, 0x8210,
+	0x7aaa, 0x8840, 0x1078, 0x3912, 0x6a14, 0x610c, 0x8108, 0xa18c,
+	0x00ff, 0xa1e0, 0x7400, 0x2c64, 0x8cff, 0x0040, 0x2671, 0x6014,
+	0xa206, 0x00c0, 0x265b, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2656,
+	0x0c7e, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078,
+	0x2594, 0x1078, 0x38fa, 0x00c0, 0x2459, 0x2a60, 0x610e, 0x79aa,
+	0x8840, 0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, 0x0018,
+	0x0040, 0x2697, 0xa184, 0x0010, 0x0040, 0x268a, 0x1078, 0x3604,
+	0x00c0, 0x26ba, 0xa184, 0x0008, 0x0040, 0x2697, 0x69a0, 0xa184,
+	0x0600, 0x00c0, 0x2697, 0x1078, 0x34f1, 0x0078, 0x26ba, 0x69a0,
+	0xa184, 0x0800, 0x0040, 0x26ae, 0x0c7e, 0x027e, 0x2960, 0x6000,
+	0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f,
+	0x0c7f, 0x1078, 0x3604, 0x00c0, 0x26ba, 0x69a0, 0xa184, 0x0200,
+	0x0040, 0x26b6, 0x1078, 0x3540, 0x0078, 0x26ba, 0xa184, 0x0400,
+	0x00c0, 0x2693, 0x69a0, 0xa184, 0x1000, 0x0040, 0x26c5, 0x6914,
+	0xa18c, 0xff00, 0x810f, 0x1078, 0x22ee, 0x007f, 0x7002, 0xa68c,
+	0x00e0, 0xa684, 0x0060, 0x0040, 0x26d3, 0xa086, 0x0060, 0x00c0,
+	0x26d3, 0xa18d, 0x4000, 0x88ff, 0x0040, 0x26d8, 0xa18d, 0x0004,
+	0x795a, 0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061,
+	0x6818, 0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080,
+	0x0040, 0x26f7, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, 0x26f5,
+	0xa08a, 0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x78aa,
+	0x8008, 0x810c, 0x0040, 0x3407, 0xa18c, 0x00f8, 0x00c0, 0x3407,
+	0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000,
+	0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+	0x6814, 0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2,
+	0x7eda, 0x1078, 0x38fa, 0x00c0, 0x272e, 0x702c, 0x8003, 0x0048,
+	0x2727, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x272e, 0x0098, 0x2736, 0x6008, 0xa084,
+	0xffef, 0x600a, 0x1078, 0x3912, 0x0078, 0x2482, 0x7200, 0xa284,
+	0x0007, 0xa086, 0x0001, 0x00c0, 0x2743, 0x781b, 0x004f, 0x1078,
+	0x3912, 0x0078, 0x2754, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b,
+	0x004f, 0x1078, 0x3912, 0x7200, 0x2500, 0xa605, 0x0040, 0x2754,
+	0xa284, 0x0007, 0x1079, 0x2762, 0xad80, 0x0009, 0x7036, 0xa284,
+	0x0007, 0xa086, 0x0001, 0x00c0, 0x2459, 0x6018, 0x8000, 0x601a,
+	0x0078, 0x2459, 0x276a, 0x4a3a, 0x4a3a, 0x4a29, 0x4a3a, 0x276a,
+	0x4a29, 0x276a, 0x1078, 0x23eb, 0x1078, 0x38fa, 0x0f7e, 0x2079,
+	0x5100, 0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x2790, 0x706c,
+	0xa086, 0x0001, 0x00c0, 0x277f, 0x706e, 0x0078, 0x2823, 0x706c,
+	0xa086, 0x0005, 0x00c0, 0x278e, 0x7088, 0x2068, 0x681b, 0x0004,
+	0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, 0x0000,
+	0x2011, 0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x27b1, 0xa186,
+	0x0007, 0x00c0, 0x27a1, 0x2009, 0x5138, 0x200b, 0x0005, 0x0078,
+	0x27b1, 0x2009, 0x5113, 0x2104, 0x2009, 0x5112, 0x200a, 0x2009,
+	0x5138, 0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, 0x0078,
+	0x27b3, 0x706f, 0x0000, 0x1078, 0x4776, 0x157e, 0x20a9, 0x0010,
+	0x2039, 0x0000, 0x1078, 0x36e2, 0xa7b8, 0x0100, 0x0070, 0x27c2,
+	0x0078, 0x27ba, 0x157f, 0x7000, 0x0079, 0x27c6, 0x27f4, 0x27db,
+	0x27db, 0x27ce, 0x27f4, 0x27f4, 0x27f4, 0x27f4, 0x2021, 0x515a,
+	0x2404, 0xa005, 0x0040, 0x27f4, 0xad06, 0x00c0, 0x27db, 0x6800,
+	0x2022, 0x0078, 0x27eb, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27e7,
+	0x6f14, 0x1078, 0x37ef, 0x1078, 0x33d8, 0x0078, 0x27eb, 0x7060,
+	0x2060, 0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085,
+	0x0008, 0x6822, 0x1078, 0x1c70, 0x2021, 0x7500, 0x1078, 0x2830,
+	0x2021, 0x515a, 0x1078, 0x2830, 0x157e, 0x20a9, 0x0000, 0x2021,
+	0x7400, 0x1078, 0x2830, 0x8420, 0x0070, 0x2808, 0x0078, 0x2801,
+	0x2061, 0x5400, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, 0x6110,
+	0x81ff, 0x0040, 0x2817, 0xa102, 0x0050, 0x2817, 0x6012, 0x601b,
+	0x0000, 0xace0, 0x0010, 0x0070, 0x281f, 0x0078, 0x280e, 0x8421,
+	0x00c0, 0x280c, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, 0x282a,
+	0x1078, 0x3a00, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, 0x2459,
+	0x047e, 0x2404, 0xa005, 0x0040, 0x2844, 0x2068, 0x6800, 0x007e,
+	0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078,
+	0x1c70, 0x007f, 0x0078, 0x2832, 0x047f, 0x2023, 0x0000, 0x007c,
+	0xa282, 0x0003, 0x0050, 0x284e, 0x1078, 0x23eb, 0x2300, 0x0079,
+	0x2851, 0x2854, 0x28c7, 0x28e4, 0xa282, 0x0002, 0x0040, 0x285a,
+	0x1078, 0x23eb, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079,
+	0x2861, 0x2869, 0x2869, 0x286b, 0x289f, 0x340d, 0x2869, 0x289f,
+	0x2869, 0x1078, 0x23eb, 0x7780, 0x1078, 0x36e2, 0x7780, 0xa7bc,
+	0x0f00, 0x1078, 0x37ef, 0x6018, 0xa005, 0x0040, 0x2896, 0x2021,
+	0x7500, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x28ff, 0x0040,
+	0x2896, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7400, 0x047e, 0x2009,
+	0x0004, 0x2011, 0x0010, 0x1078, 0x28ff, 0x047f, 0x0040, 0x2895,
+	0x8420, 0x0070, 0x2895, 0x0078, 0x2886, 0x157f, 0x8738, 0xa784,
+	0x001f, 0x00c0, 0x2871, 0x0078, 0x2482, 0x0078, 0x2482, 0x7780,
+	0x1078, 0x37ef, 0x6018, 0xa005, 0x0040, 0x28c5, 0x2021, 0x7500,
+	0x2009, 0x0005, 0x2011, 0x0020, 0x1078, 0x28ff, 0x0040, 0x28c5,
+	0x157e, 0x20a9, 0x0000, 0x2021, 0x7400, 0x047e, 0x2009, 0x0005,
+	0x2011, 0x0020, 0x1078, 0x28ff, 0x047f, 0x0040, 0x28c4, 0x8420,
+	0x0070, 0x28c4, 0x0078, 0x28b5, 0x157f, 0x0078, 0x2482, 0x2200,
+	0x0079, 0x28ca, 0x28cd, 0x28cf, 0x28cf, 0x1078, 0x23eb, 0x2009,
+	0x0012, 0x706c, 0xa086, 0x0002, 0x0040, 0x28d8, 0x2009, 0x000e,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x28de, 0x691a, 0x706f, 0x0000,
+	0x7073, 0x0001, 0x0078, 0x3888, 0x2200, 0x0079, 0x28e7, 0x28ec,
+	0x28cf, 0x28ea, 0x1078, 0x23eb, 0x1078, 0x4776, 0x7000, 0xa086,
+	0x0001, 0x00c0, 0x339d, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x3390, 0x0040, 0x339d, 0x0078, 0x2594, 0x2404,
+	0xa005, 0x0040, 0x2922, 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706,
+	0x0040, 0x290e, 0x2d20, 0x007f, 0x0078, 0x2900, 0x007f, 0x2022,
+	0x691a, 0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, 0x1c70,
+	0x6010, 0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+	0x33ee, 0x007c, 0xa085, 0x0001, 0x0078, 0x2921, 0x2300, 0x0079,
+	0x2929, 0x292e, 0x292c, 0x29c7, 0x1078, 0x23eb, 0x78ec, 0xa084,
+	0x0001, 0x00c0, 0x2942, 0x7000, 0xa086, 0x0004, 0x00c0, 0x293a,
+	0x0078, 0x2965, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a,
+	0x0078, 0x339d, 0x78e4, 0xa005, 0x00d0, 0x2965, 0x0018, 0x2459,
+	0x2008, 0xa084, 0x0030, 0x00c0, 0x2951, 0x781b, 0x004f, 0x0078,
+	0x2459, 0x78ec, 0xa084, 0x0003, 0x0040, 0x294d, 0x2100, 0xa084,
+	0x0007, 0x0079, 0x295b, 0x299e, 0x29a9, 0x298f, 0x2963, 0x38ed,
+	0x38ed, 0x2963, 0x29b8, 0x1078, 0x23eb, 0x7000, 0xa086, 0x0004,
+	0x00c0, 0x297f, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2975, 0x2011,
+	0x0002, 0x2019, 0x0000, 0x0078, 0x2848, 0x706c, 0xa086, 0x0006,
+	0x0040, 0x296f, 0x706c, 0xa086, 0x0004, 0x0040, 0x296f, 0x79e4,
+	0xa184, 0x0030, 0x0040, 0x2989, 0x78ec, 0xa084, 0x0003, 0x00c0,
+	0x298b, 0x0078, 0x2f6d, 0x2001, 0x0003, 0x0078, 0x2d01, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x2996, 0x681b, 0x001d, 0x1078, 0x36c1,
+	0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x29a5, 0x681b, 0x001d, 0x1078, 0x36c1, 0x0078,
+	0x38b8, 0x6818, 0xa084, 0x8000, 0x0040, 0x29b0, 0x681b, 0x001d,
+	0x1078, 0x36c1, 0x782b, 0x3008, 0x781b, 0x00cd, 0x0078, 0x2459,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x29bf, 0x681b, 0x001d, 0x1078,
+	0x36c1, 0x782b, 0x3008, 0x781b, 0x008e, 0x0078, 0x2459, 0xa584,
+	0x000f, 0x00c0, 0x29e4, 0x7000, 0x0079, 0x29ce, 0x2482, 0x29d8,
+	0x29d6, 0x339d, 0x339d, 0x339d, 0x339d, 0x29d6, 0x1078, 0x23eb,
+	0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3390,
+	0x0040, 0x339d, 0x0078, 0x2594, 0x78e4, 0xa005, 0x00d0, 0x2965,
+	0x0018, 0x2965, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29f3, 0x781b,
+	0x004f, 0x0078, 0x2459, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ef,
+	0x2100, 0xa184, 0x0007, 0x0079, 0x29fd, 0x2a0f, 0x2a13, 0x2a07,
+	0x2a05, 0x38ed, 0x38ed, 0x2a05, 0x38e3, 0x1078, 0x23eb, 0x1078,
+	0x36c9, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x1078,
+	0x36c9, 0x0078, 0x38b8, 0x1078, 0x36c9, 0x782b, 0x3008, 0x781b,
+	0x00cd, 0x0078, 0x2459, 0x1078, 0x36c9, 0x782b, 0x3008, 0x781b,
+	0x008e, 0x0078, 0x2459, 0x2300, 0x0079, 0x2a26, 0x2a2b, 0x2a29,
+	0x2a2d, 0x1078, 0x23eb, 0x0078, 0x30ab, 0x681b, 0x0008, 0x78a3,
+	0x0000, 0x79e4, 0xa184, 0x0030, 0x0040, 0x30ab, 0x78ec, 0xa084,
+	0x0003, 0x0040, 0x30ab, 0xa184, 0x0007, 0x0079, 0x2a3f, 0x2a47,
+	0x2a13, 0x298f, 0x3888, 0x38ed, 0x38ed, 0x2a47, 0x38e3, 0x1078,
+	0x389c, 0x0078, 0x2459, 0xa282, 0x0005, 0x0050, 0x2a51, 0x1078,
+	0x23eb, 0x2300, 0x0079, 0x2a54, 0x2a57, 0x2cae, 0x2cbc, 0x2200,
+	0x0079, 0x2a5a, 0x2a74, 0x2a61, 0x2a74, 0x2a5f, 0x2c93, 0x1078,
+	0x23eb, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020,
+	0x0048, 0x369d, 0xa08a, 0x0004, 0x00c8, 0x369d, 0x0079, 0x2a70,
+	0x369d, 0x369d, 0x369d, 0x364b, 0x789b, 0x0018, 0x79a8, 0xa184,
+	0x0080, 0x0040, 0x2a85, 0x0078, 0x369d, 0x7000, 0xa005, 0x00c0,
+	0x2a7b, 0x2011, 0x0004, 0x0078, 0x321f, 0xa184, 0x00ff, 0xa08a,
+	0x0010, 0x00c8, 0x369d, 0x0079, 0x2a8d, 0x2a9f, 0x2a9d, 0x2ab7,
+	0x2abb, 0x2b78, 0x369d, 0x369d, 0x2b7a, 0x369d, 0x369d, 0x2c8f,
+	0x2c8f, 0x369d, 0x369d, 0x369d, 0x2c91, 0x1078, 0x23eb, 0xa684,
+	0x1000, 0x0040, 0x2aac, 0x2001, 0x0500, 0x8000, 0x8000, 0x783a,
+	0x781b, 0x008c, 0x0078, 0x2459, 0x6818, 0xa084, 0x8000, 0x0040,
+	0x2ab5, 0x681b, 0x001d, 0x0078, 0x2aa3, 0x0078, 0x3888, 0x681b,
+	0x001d, 0x0078, 0x36ad, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0,
+	0x2afc, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2b04, 0x6818, 0xa086,
+	0x0008, 0x00c0, 0x2acd, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040,
+	0x2b74, 0xa684, 0x0080, 0x0040, 0x2af8, 0x7097, 0x0000, 0x6818,
+	0xa084, 0x003f, 0xa08a, 0x000d, 0x0050, 0x2af8, 0xa08a, 0x000c,
+	0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, 0x78aa,
+	0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000,
+	0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f,
+	0x781b, 0x0058, 0x0078, 0x2459, 0xa684, 0x1000, 0x0040, 0x2b04,
+	0x781b, 0x0065, 0x0078, 0x2459, 0xa684, 0x0060, 0x0040, 0x2b70,
+	0xa684, 0x0800, 0x0040, 0x2b70, 0xa684, 0x8000, 0x00c0, 0x2b12,
+	0x0078, 0x2b2c, 0xa6b4, 0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0076,
+	0x7aac, 0x79ac, 0x78ac, 0x801b, 0x00c8, 0x2b1f, 0x8000, 0xa084,
+	0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2,
+	0x6b94, 0x2200, 0xa303, 0x68ae, 0xa684, 0x4000, 0x0040, 0x2b34,
+	0xa6b4, 0xbfff, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0,
+	0x2b41, 0x1078, 0x482c, 0x1078, 0x4a29, 0x781b, 0x0064, 0x0078,
+	0x2459, 0xa006, 0x1078, 0x4b30, 0x6ab0, 0x69ac, 0x6c98, 0x6b94,
+	0x2200, 0xa105, 0x0040, 0x2b50, 0x2200, 0xa422, 0x2100, 0xa31b,
+	0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405,
+	0x00c0, 0x2b62, 0xa6b5, 0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064,
+	0x0078, 0x2459, 0x781b, 0x0064, 0x2200, 0xa115, 0x00c0, 0x2b6c,
+	0x1078, 0x4a3a, 0x0078, 0x2459, 0x1078, 0x4a85, 0x0078, 0x2459,
+	0x781b, 0x0065, 0x0078, 0x2459, 0x781b, 0x0058, 0x0078, 0x2459,
+	0x1078, 0x23eb, 0x0078, 0x2bdb, 0x6920, 0xa184, 0x0100, 0x0040,
+	0x2b92, 0xa18c, 0xfeff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000,
+	0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f,
+	0x0078, 0x2bca, 0xa184, 0x0200, 0x0040, 0x2bca, 0xa18c, 0xfdff,
+	0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xdfff, 0x6002,
+	0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+	0x0008, 0x0040, 0x2bca, 0x1078, 0x37eb, 0x1078, 0x34f1, 0x88ff,
+	0x0040, 0x2bca, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5,
+	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2bc4, 0x782b, 0x3008,
+	0x781b, 0x0056, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x0065,
+	0x0078, 0x2459, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x2bd3, 0x781b,
+	0x0058, 0x0078, 0x2459, 0x781b, 0x0065, 0x0078, 0x2459, 0x0078,
+	0x36a5, 0x0078, 0x36a5, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007,
+	0x00c0, 0x2be9, 0x6820, 0xa084, 0x0100, 0x0040, 0x2bd9, 0x2009,
+	0x0008, 0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001,
+	0x00c0, 0x2c20, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040,
+	0x2c18, 0x0048, 0x2bfd, 0x0078, 0x2c1a, 0xa380, 0x0002, 0xa102,
+	0x00c8, 0x2c18, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054,
+	0x2060, 0x6000, 0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5,
+	0x6006, 0x0c7f, 0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2bcb,
+	0x0078, 0x2b7c, 0x24a8, 0x7aa8, 0x00f0, 0x2c1a, 0x0078, 0x2beb,
+	0xa284, 0x00f0, 0xa086, 0x0020, 0x00c0, 0x2c80, 0x8318, 0x8318,
+	0x2300, 0xa102, 0x0040, 0x2c30, 0x0048, 0x2c30, 0x0078, 0x2c7d,
+	0xa286, 0x0023, 0x0040, 0x2bd9, 0x681c, 0xa084, 0xfff1, 0x681e,
+	0x7e58, 0xa684, 0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008,
+	0xa085, 0x0010, 0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008,
+	0x2c48, 0x0c7f, 0xa184, 0x0010, 0x0040, 0x2c54, 0x1078, 0x37eb,
+	0x1078, 0x3604, 0x0078, 0x2c63, 0x0c7e, 0x7054, 0x2060, 0x6004,
+	0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2bca, 0x1078,
+	0x37eb, 0x1078, 0x34f1, 0x88ff, 0x0040, 0x2bca, 0x789b, 0x0060,
+	0x2800, 0x78aa, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0,
+	0x2c77, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x7aa8, 0x0078, 0x2beb,
+	0x8318, 0x2300, 0xa102, 0x0040, 0x2c89, 0x0048, 0x2c89, 0x0078,
+	0x2beb, 0xa284, 0x0080, 0x00c0, 0x36ad, 0x0078, 0x36a5, 0x0078,
+	0x36ad, 0x0078, 0x369d, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff,
+	0xa08e, 0x0001, 0x0040, 0x2c9e, 0x1078, 0x23eb, 0x7aa8, 0xa294,
+	0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x369d,
+	0x0079, 0x2caa, 0x369d, 0x343e, 0x369d, 0x3599, 0xa282, 0x0000,
+	0x00c0, 0x2cb4, 0x1078, 0x23eb, 0x1078, 0x36c1, 0x782b, 0x3008,
+	0x781b, 0x0065, 0x0078, 0x2459, 0xa282, 0x0003, 0x00c0, 0x2cc2,
+	0x1078, 0x23eb, 0xa484, 0x8000, 0x00c0, 0x2ce5, 0x706c, 0xa005,
+	0x0040, 0x2ccc, 0x1078, 0x23eb, 0x6f14, 0x7782, 0xa7bc, 0x0f00,
+	0x1078, 0x37ef, 0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784,
+	0x001f, 0x00c0, 0x2cd0, 0x1078, 0x36c5, 0x706f, 0x0002, 0x2009,
+	0x5138, 0x200b, 0x0009, 0x0078, 0x2ce7, 0x1078, 0x36d1, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0xa282, 0x0004, 0x0050,
+	0x2cf3, 0x1078, 0x23eb, 0x2300, 0x0079, 0x2cf6, 0x2cf9, 0x2de2,
+	0x2e15, 0xa286, 0x0003, 0x0040, 0x2cff, 0x1078, 0x23eb, 0x2001,
+	0x0000, 0x007e, 0x68c0, 0xa005, 0x0040, 0x2d08, 0x7003, 0x0003,
+	0x68a0, 0xa084, 0x2000, 0x0040, 0x2d11, 0x6008, 0xa085, 0x0002,
+	0x600a, 0x007f, 0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2d18,
+	0x2482, 0x2d22, 0x2d22, 0x2f17, 0x2f53, 0x2482, 0x2f53, 0x2d20,
+	0x1078, 0x23eb, 0xa684, 0x1000, 0x00c0, 0x2d2a, 0x1078, 0x4776,
+	0x0040, 0x2dbc, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2d72, 0xa186,
+	0x0008, 0x00c0, 0x2d41, 0x1078, 0x33ee, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x3390, 0x0040, 0x2d72, 0x1078, 0x4776, 0x0078,
+	0x2d59, 0xa186, 0x0028, 0x00c0, 0x2d72, 0x1078, 0x4776, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2d59, 0x8001,
+	0x601a, 0xa005, 0x0040, 0x2d59, 0x8001, 0xa005, 0x0040, 0x2d59,
+	0x601e, 0x6820, 0xa084, 0x0001, 0x0040, 0x2482, 0x6820, 0xa084,
+	0xfffe, 0x6822, 0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f,
+	0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2d6f, 0x6002, 0x6006,
+	0x0078, 0x2482, 0x017e, 0x1078, 0x2e46, 0x017f, 0xa684, 0xdf00,
+	0x681e, 0x682b, 0x0000, 0x6f14, 0x81ff, 0x0040, 0x2dbc, 0xa186,
+	0x0002, 0x00c0, 0x2dbc, 0xa684, 0x0800, 0x00c0, 0x2d8f, 0xa684,
+	0x0060, 0x0040, 0x2d8f, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820,
+	0xa084, 0x0800, 0x00c0, 0x2dbc, 0x8717, 0xa294, 0x000f, 0x8213,
+	0x8213, 0x8213, 0xa290, 0x5380, 0xa290, 0x0000, 0x221c, 0xa384,
+	0x0100, 0x00c0, 0x2da5, 0x0078, 0x2dab, 0x8210, 0x2204, 0xa085,
+	0x0018, 0x2012, 0x8211, 0xa384, 0x0400, 0x0040, 0x2db8, 0x68a0,
+	0xa084, 0x0100, 0x00c0, 0x2db8, 0x1078, 0x2eca, 0x0078, 0x2482,
+	0x6008, 0xa085, 0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x2dc4, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078,
+	0x33df, 0x1078, 0x33ee, 0x00c0, 0x2dd1, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2dda, 0x1078, 0x33d8,
+	0x0078, 0x2dde, 0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1c70,
+	0x0078, 0x2482, 0xa282, 0x0004, 0x0048, 0x2de8, 0x1078, 0x23eb,
+	0x2200, 0x0079, 0x2deb, 0x2de6, 0x2def, 0x2dfc, 0x2def, 0x7000,
+	0xa086, 0x0005, 0x0040, 0x2df8, 0x1078, 0x36c1, 0x782b, 0x3008,
+	0x781b, 0x0065, 0x0078, 0x2459, 0x7890, 0x8007, 0x8001, 0xa084,
+	0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186,
+	0x0003, 0x0040, 0x2e11, 0xa186, 0x0000, 0x0040, 0x2e11, 0x0078,
+	0x369d, 0x781b, 0x0065, 0x0078, 0x2459, 0x6820, 0xa085, 0x0004,
+	0x6822, 0x82ff, 0x00c0, 0x2e20, 0x1078, 0x36c1, 0x0078, 0x2e27,
+	0x8211, 0x0040, 0x2e25, 0x1078, 0x23eb, 0x1078, 0x36d1, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x702c, 0x8003, 0x0048,
+	0x2e37, 0x2019, 0x4d9e, 0x1078, 0x2276, 0x702f, 0x8000, 0x1078,
+	0x3912, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2e43, 0x0018, 0x2e43,
+	0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060,
+	0x00c0, 0x2e50, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2ec9,
+	0xa684, 0x0800, 0x00c0, 0x2e72, 0x68b4, 0xa084, 0x4800, 0xa635,
+	0xa684, 0x0800, 0x00c0, 0x2e72, 0x6998, 0x6a94, 0x692e, 0x6a32,
+	0x703c, 0xa005, 0x00c0, 0x2e6a, 0x2200, 0xa105, 0x0040, 0x2e71,
+	0x703f, 0x0015, 0x7000, 0xa086, 0x0006, 0x0040, 0x2e71, 0x1078,
+	0x4776, 0x007c, 0xa684, 0x0020, 0x0040, 0x2e94, 0xa684, 0x4000,
+	0x0040, 0x2e80, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e6a,
+	0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e7a,
+	0x703c, 0xa005, 0x00c0, 0x2e8e, 0x703f, 0x0015, 0x79d8, 0x7adc,
+	0x692e, 0x6a32, 0x0078, 0x2e6a, 0xa684, 0x4000, 0x0040, 0x2e9e,
+	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e6a, 0x68b4, 0xa084,
+	0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e98, 0x703c, 0xa005,
+	0x00c0, 0x2eac, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb,
+	0x00c8, 0x2eb3, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+	0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x2ec0, 0x0078, 0x2e6a,
+	0x7000, 0xa086, 0x0006, 0x0040, 0x2ec9, 0x1078, 0x4b30, 0x0078,
+	0x2e6a, 0x007c, 0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200,
+	0x0040, 0x2ed6, 0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006,
+	0x688f, 0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942,
+	0x682f, 0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000,
+	0x689b, 0x0020, 0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079,
+	0x2ef1, 0x2482, 0x2efb, 0x2f04, 0x2ef9, 0x2ef9, 0x2ef9, 0x2ef9,
+	0x2ef9, 0x1078, 0x23eb, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2f04,
+	0x1078, 0x33d8, 0x0078, 0x2f0a, 0x7060, 0x2c50, 0x2060, 0x6800,
+	0x6002, 0x2a60, 0x2021, 0x515a, 0x2404, 0xa005, 0x0040, 0x2f13,
+	0x2020, 0x0078, 0x2f0c, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078,
+	0x33df, 0x1078, 0x33ee, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b,
+	0x0000, 0x789b, 0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4b78,
+	0xa684, 0x0800, 0x0040, 0x2f30, 0x691c, 0xa18d, 0x2000, 0x691e,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x2f40, 0x7868, 0xa08c, 0x00ff,
+	0x0040, 0x2f3e, 0x681b, 0x001e, 0x0078, 0x2f40, 0x681b, 0x0000,
+	0x2021, 0x515a, 0x2404, 0xad06, 0x0040, 0x2f47, 0x7460, 0x6800,
+	0x2022, 0x68c3, 0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078,
+	0x1c70, 0x0078, 0x2482, 0x1078, 0x2e46, 0x682b, 0x0000, 0x2001,
+	0x000e, 0x6f14, 0x1078, 0x3918, 0xa08c, 0x00ff, 0x6916, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x2f66, 0x703c, 0x681a, 0xa68c, 0xdf00,
+	0x691e, 0x706f, 0x0000, 0x0078, 0x2482, 0x7000, 0xa005, 0x00c0,
+	0x2f73, 0x0078, 0x2482, 0xa006, 0x1078, 0x4776, 0x6817, 0x0000,
+	0x681b, 0x0014, 0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820,
+	0xa085, 0x00ff, 0x6822, 0x7000, 0x0079, 0x2f86, 0x2482, 0x2f90,
+	0x2f90, 0x2f92, 0x2f92, 0x2f92, 0x2f92, 0x2f8e, 0x1078, 0x23eb,
+	0x1078, 0x33ee, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x33a8,
+	0x2300, 0x0079, 0x2f9b, 0x2f9e, 0x2fa0, 0x2fd9, 0x1078, 0x23eb,
+	0x7000, 0x0079, 0x2fa3, 0x2482, 0x2fad, 0x2fad, 0x2fc8, 0x2fad,
+	0x2fd5, 0x2fc8, 0x2fab, 0x1078, 0x23eb, 0xa684, 0x0060, 0xa086,
+	0x0060, 0x00c0, 0x2fc4, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5,
+	0x2000, 0x7e5a, 0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x4776,
+	0x1078, 0x4a3a, 0x0078, 0x3888, 0xa684, 0x2000, 0x0040, 0x2fb7,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x2fd5, 0x681b, 0x0015, 0xa684,
+	0x4000, 0x0040, 0x2fd5, 0x681b, 0x0007, 0x1078, 0x389c, 0x0078,
+	0x2459, 0x1078, 0x23eb, 0x2300, 0x0079, 0x2fde, 0x2fe1, 0x2fe3,
+	0x3016, 0x1078, 0x23eb, 0x7000, 0x0079, 0x2fe6, 0x2482, 0x2ff0,
+	0x2ff0, 0x300b, 0x2ff0, 0x3012, 0x300b, 0x2fee, 0x1078, 0x23eb,
+	0xa684, 0x0060, 0xa086, 0x0060, 0x00c0, 0x3007, 0xa6b4, 0xffbf,
+	0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf,
+	0x681e, 0x1078, 0x4776, 0x1078, 0x4a3a, 0x0078, 0x3888, 0xa684,
+	0x2000, 0x0040, 0x2ffa, 0x6818, 0xa084, 0x8000, 0x0040, 0x3012,
+	0x681b, 0x0007, 0x781b, 0x00cd, 0x0078, 0x2459, 0x6820, 0xa085,
+	0x0004, 0x6822, 0x1078, 0x3853, 0xa6b5, 0x0800, 0x1078, 0x36c1,
+	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x2300, 0x0079,
+	0x3029, 0x302c, 0x302e, 0x3030, 0x1078, 0x23eb, 0x0078, 0x36ad,
+	0xa684, 0x0400, 0x00c0, 0x3059, 0x79e4, 0xa184, 0x0020, 0x0040,
+	0x3040, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3040, 0x782b, 0x3009,
+	0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4,
+	0xa184, 0x0020, 0x0040, 0x3051, 0x78ec, 0xa084, 0x0003, 0x00c0,
+	0x3055, 0x2001, 0x0014, 0x0078, 0x2d01, 0xa184, 0x0007, 0x0079,
+	0x3091, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff,
+	0x0040, 0x308f, 0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0,
+	0x3080, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0, 0x3073, 0x2009,
+	0xfff7, 0x0078, 0x3079, 0xa386, 0x0003, 0x00c0, 0x3080, 0x2009,
+	0xffef, 0x0c7e, 0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f,
+	0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b,
+	0x3009, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
+	0x3888, 0x299e, 0x29a9, 0x309b, 0x30a3, 0x3099, 0x3099, 0x3888,
+	0x3888, 0x1078, 0x23eb, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff,
+	0x6922, 0x0078, 0x3892, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff,
+	0x6922, 0x0078, 0x3888, 0x79e4, 0xa184, 0x0030, 0x0040, 0x30b5,
+	0x78ec, 0xa084, 0x0003, 0x00c0, 0x30dc, 0x7000, 0xa086, 0x0004,
+	0x00c0, 0x30cf, 0x706c, 0xa086, 0x0002, 0x00c0, 0x30c5, 0x2011,
+	0x0002, 0x2019, 0x0000, 0x0078, 0x2848, 0x706c, 0xa086, 0x0006,
+	0x0040, 0x30bf, 0x706c, 0xa086, 0x0004, 0x0040, 0x30bf, 0x7000,
+	0xa086, 0x0000, 0x0040, 0x2459, 0x6818, 0xa085, 0x8000, 0x681a,
+	0x2001, 0x0014, 0x0078, 0x2d01, 0xa184, 0x0007, 0x0079, 0x30e0,
+	0x3888, 0x3888, 0x30e8, 0x3888, 0x38ed, 0x38ed, 0x3888, 0x3888,
+	0xa684, 0x0080, 0x0040, 0x3117, 0x7194, 0x81ff, 0x0040, 0x3117,
+	0xa182, 0x000d, 0x00d0, 0x30f8, 0x7097, 0x0000, 0x0078, 0x30fd,
+	0xa182, 0x000c, 0x7096, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa,
+	0x157e, 0x137e, 0x147e, 0x7098, 0x8114, 0xa210, 0x729a, 0xa080,
+	0x000b, 0xad00, 0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108,
+	0x81ac, 0x53a6, 0x147f, 0x137f, 0x157f, 0x0078, 0x3892, 0xa684,
+	0x0400, 0x00c0, 0x3158, 0x6820, 0xa084, 0x0001, 0x0040, 0x3892,
+	0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x312c, 0xa086, 0x0060,
+	0x00c0, 0x312c, 0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6,
+	0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xa085,
+	0x8000, 0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3407, 0xa18c,
+	0x00f8, 0x00c0, 0x3407, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b,
+	0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6,
+	0x147f, 0x137f, 0x157f, 0x6814, 0x8007, 0x7882, 0x0078, 0x3892,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x315f, 0x681b, 0x0008, 0x781b,
+	0x00c3, 0x0078, 0x2459, 0x2300, 0x0079, 0x3166, 0x316b, 0x320a,
+	0x3169, 0x1078, 0x23eb, 0x7000, 0xa084, 0x0007, 0x0079, 0x3170,
+	0x2482, 0x317a, 0x31af, 0x3185, 0x3178, 0x2482, 0x3178, 0x3178,
+	0x1078, 0x23eb, 0x681c, 0xa084, 0x2000, 0x0040, 0x3193, 0x6008,
+	0xa085, 0x0002, 0x600a, 0x0078, 0x3193, 0x68c0, 0xa005, 0x00c0,
+	0x31af, 0x6920, 0xa18d, 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800,
+	0x706a, 0x0078, 0x31a9, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800,
+	0x6006, 0xa005, 0x00c0, 0x319d, 0x6002, 0x681c, 0xa084, 0x000e,
+	0x0040, 0x31a9, 0x7014, 0x68ba, 0x7130, 0xa188, 0x7400, 0x0078,
+	0x31ab, 0x2009, 0x7500, 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6,
+	0xa684, 0x0060, 0x0040, 0x3208, 0xa684, 0x0800, 0x00c0, 0x31c3,
+	0xa684, 0x7fff, 0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078,
+	0x4776, 0x0078, 0x3208, 0xa684, 0x0020, 0x0040, 0x31d8, 0x68c0,
+	0xa005, 0x0040, 0x31cf, 0x1078, 0x4b78, 0x0078, 0x31d2, 0xa006,
+	0x1078, 0x4b30, 0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x31de,
+	0x1078, 0x37fc, 0x69aa, 0x6aa6, 0x1078, 0x4b30, 0xa684, 0x8000,
+	0x0040, 0x3208, 0xa684, 0x7fff, 0x68b6, 0x2001, 0x0076, 0x1078,
+	0x3918, 0x2010, 0x2001, 0x0078, 0x1078, 0x3918, 0x2008, 0xa684,
+	0x0020, 0x00c0, 0x3200, 0x2001, 0x007a, 0x1078, 0x3918, 0x801b,
+	0x00c8, 0x31fb, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+	0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae,
+	0x0078, 0x2482, 0x0078, 0x36ad, 0x7037, 0x0000, 0xa282, 0x0006,
+	0x0050, 0x3214, 0x1078, 0x23eb, 0x7000, 0xa084, 0x0007, 0x10c0,
+	0x39be, 0x2300, 0x0079, 0x321c, 0x321f, 0x3248, 0x325c, 0x2200,
+	0x0079, 0x3222, 0x3246, 0x36ad, 0x3228, 0x3246, 0x3278, 0x32ba,
+	0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0x157e, 0x20a9,
+	0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x3238, 0x0078, 0x3231,
+	0x157f, 0xad80, 0x0009, 0x7036, 0x6817, 0x0000, 0x68b7, 0x0700,
+	0x6823, 0x0800, 0x6827, 0x0003, 0x0078, 0x369d, 0x1078, 0x23eb,
+	0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0xad80, 0x0009,
+	0x7036, 0x2200, 0x0079, 0x3254, 0x36ad, 0x325a, 0x325a, 0x3278,
+	0x325a, 0x36ad, 0x1078, 0x23eb, 0x7003, 0x0005, 0x2001, 0x7610,
+	0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x3268,
+	0x3270, 0x326e, 0x326e, 0x3270, 0x326e, 0x3270, 0x1078, 0x23eb,
+	0x1078, 0x36d1, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2459,
+	0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8,
+	0xa484, 0x001f, 0xa215, 0x2069, 0x7500, 0x2d04, 0x2d08, 0x7162,
+	0x2068, 0xa005, 0x0040, 0x3293, 0x6814, 0xa206, 0x0040, 0x32af,
+	0x6800, 0x0078, 0x3286, 0x7003, 0x0005, 0x2001, 0x7610, 0x2068,
+	0x704a, 0x7036, 0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000,
+	0x0070, 0x32a4, 0x0078, 0x329d, 0x157f, 0xad80, 0x0009, 0x7036,
+	0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4,
+	0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040, 0x3309, 0x1078, 0x36c9,
+	0x0078, 0x3309, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b,
+	0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x79a8, 0x79a8, 0xa18c,
+	0x00ff, 0xa1e8, 0x7400, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005,
+	0x0040, 0x32d9, 0x6814, 0xa206, 0x0040, 0x32f4, 0x6800, 0x0078,
+	0x32cc, 0x7003, 0x0005, 0x2001, 0x7610, 0x2068, 0x704a, 0x157e,
+	0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x32e9, 0x0078,
+	0x32e2, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700,
+	0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084,
+	0x0c00, 0x0040, 0x3309, 0xa084, 0x0800, 0x0040, 0x3303, 0x1078,
+	0x36cd, 0x0078, 0x3309, 0x1078, 0x36c9, 0x708b, 0x0000, 0x0078,
+	0x3309, 0x027e, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+	0xa080, 0x5380, 0x2060, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e,
+	0xa684, 0x0060, 0x0040, 0x3361, 0x6b98, 0x6c94, 0x69ac, 0x68b0,
+	0xa105, 0x00c0, 0x3343, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4,
+	0xb7ff, 0x7e5a, 0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x3361,
+	0x68c0, 0xa005, 0x0040, 0x333c, 0x7003, 0x0003, 0x682b, 0x0000,
+	0x1078, 0x4a29, 0x0078, 0x333e, 0x1078, 0x4a3a, 0xa6b5, 0x2000,
+	0x7e5a, 0x0078, 0x3361, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400,
+	0xa305, 0x0040, 0x3361, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0,
+	0xa6b4, 0xbfff, 0x7e5a, 0x007e, 0x68c0, 0xa005, 0x007f, 0x0040,
+	0x335f, 0x7003, 0x0003, 0x1078, 0x4a29, 0x0078, 0x3361, 0x1078,
+	0x4a85, 0x077f, 0x1078, 0x37ef, 0x2009, 0x0065, 0xa684, 0x0004,
+	0x0040, 0x3382, 0x78e4, 0xa084, 0x0030, 0x0040, 0x337a, 0x78ec,
+	0xa084, 0x0003, 0x0040, 0x337a, 0x782b, 0x3008, 0x2009, 0x0065,
+	0x0078, 0x3382, 0x0f7e, 0x2079, 0x5100, 0x1078, 0x4776, 0x0f7f,
+	0x0040, 0x2482, 0x791a, 0x2d00, 0x704a, 0x8207, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa080, 0x5380, 0x2048, 0x0078, 0x2459,
+	0x6020, 0xa005, 0x0040, 0x339c, 0x8001, 0x6022, 0x6008, 0xa085,
+	0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x4776,
+	0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100,
+	0x7000, 0xa084, 0x0007, 0x0079, 0x33ad, 0x2482, 0x33b7, 0x33b7,
+	0x33d4, 0x33bf, 0x33bd, 0x33bf, 0x33b5, 0x1078, 0x23eb, 0x1078,
+	0x33df, 0x1078, 0x33d8, 0x1078, 0x1c70, 0x0078, 0x2482, 0x706c,
+	0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x33c6, 0x33d0, 0x33d0,
+	0x33ce, 0x33ce, 0x33ce, 0x33d0, 0x33ce, 0x33d0, 0x0079, 0x2861,
+	0x706f, 0x0000, 0x0078, 0x2482, 0x681b, 0x0000, 0x0078, 0x2f17,
+	0x6800, 0xa005, 0x00c0, 0x33dd, 0x6002, 0x6006, 0x007c, 0x6010,
+	0xa005, 0x0040, 0x33e8, 0x8001, 0x00d0, 0x33e8, 0x1078, 0x23eb,
+	0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005,
+	0x0040, 0x33f4, 0x8001, 0x601a, 0x007c, 0x1078, 0x3912, 0x681b,
+	0x0018, 0x0078, 0x342b, 0x1078, 0x3912, 0x681b, 0x0019, 0x0078,
+	0x342b, 0x1078, 0x3912, 0x681b, 0x001a, 0x0078, 0x342b, 0x1078,
+	0x3912, 0x681b, 0x0003, 0x0078, 0x342b, 0x7780, 0x1078, 0x37ef,
+	0x7184, 0xa18c, 0x00ff, 0xa1e8, 0x7400, 0x2d04, 0x2d08, 0x2068,
+	0xa005, 0x00c0, 0x341d, 0x0078, 0x2482, 0x6814, 0x7280, 0xa206,
+	0x0040, 0x3425, 0x6800, 0x0078, 0x3416, 0x6800, 0x200a, 0x681b,
+	0x0005, 0x708b, 0x0000, 0x1078, 0x33df, 0x6820, 0xa084, 0x0001,
+	0x00c0, 0x3434, 0x1078, 0x33d8, 0x1078, 0x33ee, 0x681f, 0x0000,
+	0x6823, 0x0020, 0x1078, 0x1c70, 0x0078, 0x2482, 0xa282, 0x0003,
+	0x00c0, 0x369d, 0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff,
+	0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0100, 0x0040, 0x34a2,
+	0xa18c, 0xfeff, 0x6922, 0xa4a4, 0x00ff, 0x0040, 0x348c, 0xa482,
+	0x000c, 0x0048, 0x345f, 0x0040, 0x345f, 0x2021, 0x000c, 0x852b,
+	0x852b, 0x1078, 0x3760, 0x0040, 0x3469, 0x1078, 0x355b, 0x0078,
+	0x3495, 0x1078, 0x371b, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5,
+	0x6006, 0x1078, 0x3586, 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922,
+	0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x3486,
+	0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b, 0x3008,
+	0x781b, 0x0065, 0x0078, 0x2459, 0x0c7e, 0x2960, 0x6004, 0xa084,
+	0xfff5, 0x6006, 0x1078, 0x3586, 0x0c7f, 0x7e58, 0xa684, 0x0400,
+	0x00c0, 0x349e, 0x781b, 0x0058, 0x0078, 0x2459, 0x781b, 0x0065,
+	0x0078, 0x2459, 0x0c7e, 0x7054, 0x2060, 0x6100, 0xa18c, 0x1000,
+	0x0040, 0x34e2, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c,
+	0x0048, 0x34b6, 0x0040, 0x34b6, 0x2011, 0x000c, 0x2400, 0xa202,
+	0x00c8, 0x34bb, 0x2220, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086,
+	0x0028, 0x00c0, 0x34cb, 0xa282, 0x0019, 0x00c8, 0x34d1, 0x2011,
+	0x0019, 0x0078, 0x34d1, 0xa282, 0x000c, 0x00c8, 0x34d1, 0x2011,
+	0x000c, 0x2200, 0xa502, 0x00c8, 0x34d6, 0x2228, 0x1078, 0x371f,
+	0x852b, 0x852b, 0x1078, 0x3760, 0x0040, 0x34e2, 0x1078, 0x355b,
+	0x0078, 0x34e6, 0x1078, 0x371b, 0x1078, 0x3586, 0x7858, 0xa085,
+	0x0004, 0x785a, 0x0c7f, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078,
+	0x2459, 0x0c7e, 0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x3509,
+	0x6010, 0xa084, 0x000f, 0x00c0, 0x3503, 0x6104, 0xa18c, 0xfff5,
+	0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078,
+	0x3530, 0x68a0, 0xa084, 0x0200, 0x00c0, 0x3503, 0x6208, 0xa294,
+	0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0, 0x351e, 0xa282, 0x0019,
+	0x00c8, 0x3524, 0x2011, 0x0019, 0x0078, 0x3524, 0xa282, 0x000c,
+	0x00c8, 0x3524, 0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff,
+	0xa382, 0x000c, 0x0048, 0x3530, 0x0040, 0x3530, 0x2019, 0x000c,
+	0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa,
+	0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c,
+	0x0c7e, 0x2960, 0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019,
+	0x0000, 0x0078, 0x354b, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+	0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100,
+	0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x7154, 0x2160, 0x1078, 0x3562,
+	0x0c7f, 0x007c, 0x2008, 0xa084, 0xfff0, 0xa425, 0x7c86, 0x6018,
+	0x789a, 0x7cae, 0x6412, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007,
+	0xa105, 0x78a6, 0x6016, 0x788a, 0xa4a4, 0x000f, 0x8427, 0x8204,
+	0x8004, 0xa084, 0x00ff, 0xa405, 0x600e, 0x78ec, 0xd08c, 0x00c0,
+	0x3585, 0x6004, 0xa084, 0xfff5, 0x6006, 0x007c, 0x0c7e, 0x7054,
+	0x2060, 0x1078, 0x358d, 0x0c7f, 0x007c, 0x6018, 0x789a, 0x78a4,
+	0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084, 0xfff0, 0x7886,
+	0x007c, 0xa282, 0x0002, 0x00c0, 0x369d, 0x7aa8, 0x6920, 0xa18d,
+	0x0080, 0x6922, 0xa184, 0x0200, 0x0040, 0x35e2, 0xa18c, 0xfdff,
+	0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8, 0x369d, 0x1078,
+	0x362b, 0x1078, 0x3586, 0xa980, 0x0001, 0x200c, 0x1078, 0x37eb,
+	0x1078, 0x34f1, 0x88ff, 0x0040, 0x35d5, 0x789b, 0x0060, 0x2800,
+	0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0,
+	0x35cf, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2459, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x7e58, 0xa684, 0x0400,
+	0x00c0, 0x35de, 0x781b, 0x0058, 0x0078, 0x2459, 0x781b, 0x0065,
+	0x0078, 0x2459, 0xa282, 0x0002, 0x00c8, 0x35ea, 0xa284, 0x0001,
+	0x0040, 0x35f4, 0x7154, 0xa188, 0x0000, 0x210c, 0xa18c, 0x2000,
+	0x00c0, 0x35f4, 0x2011, 0x0000, 0x1078, 0x370d, 0x1078, 0x362b,
+	0x1078, 0x3586, 0x7858, 0xa085, 0x0004, 0x785a, 0x782b, 0x3008,
+	0x781b, 0x0065, 0x0078, 0x2459, 0x0c7e, 0x027e, 0x2960, 0x6000,
+	0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x361b, 0x6014, 0xa084,
+	0x0040, 0x00c0, 0x3619, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078,
+	0x3628, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+	0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085, 0x0200, 0x6822,
+	0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7054, 0x2060, 0x1078, 0x3632,
+	0x0c7f, 0x007c, 0x82ff, 0x0040, 0x3637, 0x2011, 0x0040, 0x6018,
+	0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf, 0xa205, 0x78a6,
+	0x788a, 0x6016, 0x78ec, 0xd08c, 0x00c0, 0x364a, 0x6004, 0xa084,
+	0xffef, 0x6006, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040,
+	0x3654, 0x007f, 0x0078, 0x3657, 0x007f, 0x0078, 0x3699, 0xa684,
+	0x0020, 0x0040, 0x3699, 0x7888, 0xa084, 0x0040, 0x0040, 0x3699,
+	0x7bb8, 0xa384, 0x003f, 0x831b, 0x00c8, 0x3667, 0x8000, 0xa005,
+	0x0040, 0x367d, 0x831b, 0x00c8, 0x3670, 0x8001, 0x0040, 0x3695,
+	0xa684, 0x4000, 0x0040, 0x367d, 0x78b8, 0x801b, 0x00c8, 0x3679,
+	0x8000, 0xa084, 0x003f, 0x00c0, 0x3695, 0xa6b4, 0xbfff, 0x7e5a,
+	0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108, 0x00c8, 0x3689, 0xa291,
+	0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x1078, 0x4b30, 0x781b,
+	0x0064, 0x1078, 0x49b5, 0x0078, 0x2459, 0x781b, 0x0064, 0x0078,
+	0x2459, 0x781b, 0x0065, 0x0078, 0x2459, 0x1078, 0x36d5, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x1078, 0x36c1, 0x782b,
+	0x3008, 0x781b, 0x0065, 0x0078, 0x2459, 0x6827, 0x0002, 0x1078,
+	0x36c9, 0x78e4, 0xa084, 0x0030, 0x0040, 0x2482, 0x78ec, 0xa084,
+	0x0003, 0x0040, 0x2482, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078,
+	0x2459, 0x2001, 0x0005, 0x0078, 0x36d7, 0x2001, 0x000c, 0x0078,
+	0x36d7, 0x2001, 0x0006, 0x0078, 0x36d7, 0x2001, 0x000d, 0x0078,
+	0x36d7, 0x2001, 0x0009, 0x0078, 0x36d7, 0x2001, 0x0007, 0x789b,
+	0x0010, 0x78aa, 0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004,
+	0x7e5a, 0x007c, 0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b,
+	0x8703, 0xa0e0, 0x5380, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184,
+	0x000f, 0x0040, 0x36fb, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004,
+	0xa085, 0x0008, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184,
+	0x0040, 0x0040, 0x370b, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004,
+	0xa085, 0x0010, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab,
+	0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060,
+	0x78ab, 0x0004, 0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b,
+	0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa,
+	0x7caa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007,
+	0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4,
+	0xa18c, 0xfff0, 0x2001, 0x5146, 0x2004, 0xa082, 0x0028, 0x0040,
+	0x3749, 0x2021, 0x37d2, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078,
+	0x374f, 0x2021, 0x37de, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011,
+	0x0064, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040, 0x375e, 0x8420,
+	0x2300, 0xa210, 0x0070, 0x375e, 0x0078, 0x3751, 0x157f, 0x007c,
+	0x157e, 0x2009, 0x5146, 0x210c, 0xa182, 0x0032, 0x0048, 0x3774,
+	0x0040, 0x3778, 0x2009, 0x37c4, 0x2019, 0x0011, 0x20a9, 0x000e,
+	0x2011, 0x0032, 0x0078, 0x378a, 0xa182, 0x0028, 0x0040, 0x3782,
+	0x2009, 0x37d2, 0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064,
+	0x0078, 0x378a, 0x2009, 0x37de, 0x2019, 0x0019, 0x20a9, 0x000d,
+	0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x379a, 0x0048, 0x379a,
+	0x8108, 0x2300, 0xa210, 0x0070, 0x3797, 0x0078, 0x378a, 0x157f,
+	0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8, 0x37a9, 0x7808,
+	0xa085, 0x0070, 0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078,
+	0x37a9, 0x78ec, 0xa084, 0x0300, 0x0040, 0x37b1, 0x2104, 0x0078,
+	0x37c2, 0x2104, 0xa09e, 0x1102, 0x00c0, 0x37c2, 0x2001, 0x04fd,
+	0x2004, 0xa082, 0x0005, 0x0048, 0x37c1, 0x2001, 0x1201, 0x0078,
+	0x37c2, 0x2104, 0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203,
+	0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07,
+	0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605,
+	0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202,
+	0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04,
+	0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784,
+	0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003,
+	0xa105, 0xa0e0, 0x5400, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b,
+	0x00c8, 0x3803, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+	0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x5140, 0x2091, 0x8000,
+	0x2104, 0x0079, 0x3813, 0x3849, 0x381d, 0x381d, 0x381d, 0x381d,
+	0x381d, 0x381d, 0x384d, 0x1078, 0x23eb, 0x784b, 0x0004, 0x7848,
+	0xa084, 0x0004, 0x00c0, 0x381f, 0x784b, 0x0008, 0x7848, 0xa084,
+	0x0008, 0x00c0, 0x3826, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858,
+	0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3849,
+	0x0018, 0x3849, 0x681c, 0xa084, 0x0020, 0x00c0, 0x3847, 0x0e7e,
+	0x2071, 0x5140, 0x1078, 0x389c, 0x0e7f, 0x0078, 0x3849, 0x781b,
+	0x00cd, 0x2091, 0x8001, 0x0f7f, 0x007c, 0x70b3, 0x0000, 0x1078,
+	0x3a76, 0x0078, 0x3849, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa0e0, 0x5380, 0x6004, 0xa084, 0x000a,
+	0x00c0, 0x3886, 0x6108, 0xa194, 0xff00, 0x0040, 0x3886, 0xa18c,
+	0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x3875, 0x2001, 0x0032,
+	0xa106, 0x0040, 0x3879, 0x0078, 0x387d, 0x2009, 0x0020, 0x0078,
+	0x387f, 0x2009, 0x003f, 0x0078, 0x387f, 0x2011, 0x0000, 0x2100,
+	0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c,
+	0x781b, 0x0065, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x0065,
+	0x0078, 0x2459, 0x781b, 0x0058, 0x0078, 0x2459, 0x782b, 0x3008,
+	0x781b, 0x0056, 0x0078, 0x2459, 0x2009, 0x5120, 0x210c, 0xa186,
+	0x0000, 0x0040, 0x38b0, 0xa186, 0x0001, 0x0040, 0x38b3, 0x2009,
+	0x5138, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x007c,
+	0x781b, 0x00c7, 0x007c, 0x2009, 0x5138, 0x200b, 0x000a, 0x007c,
+	0x2009, 0x5120, 0x210c, 0xa186, 0x0000, 0x0040, 0x38d3, 0xa186,
+	0x0001, 0x0040, 0x38cd, 0x2009, 0x5138, 0x200b, 0x000b, 0x706f,
+	0x0001, 0x781b, 0x0048, 0x0078, 0x2459, 0x2009, 0x5138, 0x200b,
+	0x000a, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b, 0x00c7, 0x0078,
+	0x2459, 0x781b, 0x00cd, 0x0078, 0x2459, 0x782b, 0x3008, 0x781b,
+	0x00cd, 0x0078, 0x2459, 0x781b, 0x008e, 0x0078, 0x2459, 0x782b,
+	0x3008, 0x781b, 0x008e, 0x0078, 0x2459, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x38f4, 0x681b, 0x001d, 0x706f, 0x0001, 0x781b, 0x0048,
+	0x0078, 0x2459, 0x007e, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3910,
+	0x7808, 0xa084, 0xfffc, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005,
+	0x78ec, 0xa084, 0x0021, 0x0040, 0x3910, 0x7044, 0x780a, 0xa005,
+	0x007f, 0x007c, 0x7044, 0xa085, 0x0002, 0x7046, 0x780a, 0x007c,
+	0x007e, 0x7830, 0xa084, 0x0040, 0x00c0, 0x3919, 0x0098, 0x3924,
+	0x007f, 0x789a, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+	0x3933, 0x0098, 0x3931, 0x007f, 0x789a, 0x78ac, 0x007e, 0x7044,
+	0x780a, 0x007f, 0x007c, 0x78ec, 0xa084, 0x0002, 0x00c0, 0x4760,
+	0xa784, 0x007d, 0x00c0, 0x3947, 0x2700, 0x1078, 0x23eb, 0xa784,
+	0x0001, 0x00c0, 0x2f6d, 0xa784, 0x0070, 0x0040, 0x3957, 0x0c7e,
+	0x2d60, 0x2f68, 0x1078, 0x2396, 0x2d78, 0x2c68, 0x0c7f, 0xa784,
+	0x0008, 0x0040, 0x3964, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x2482, 0x0078, 0x3888, 0xa784, 0x0004, 0x0040, 0x3997,
+	0x78b8, 0xa084, 0x4001, 0x0040, 0x3997, 0x784b, 0x0008, 0x78ec,
+	0xa084, 0x0003, 0x0040, 0x2482, 0x78e4, 0xa084, 0x0007, 0xa086,
+	0x0001, 0x00c0, 0x3997, 0x78c0, 0xa085, 0x4800, 0x2030, 0x7e5a,
+	0x781b, 0x00cd, 0x0078, 0x2459, 0x784b, 0x0008, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x3993, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
+	0x3993, 0x681b, 0x0007, 0x1078, 0x389c, 0x0078, 0x2459, 0x681b,
+	0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f, 0x0000, 0x6833,
+	0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2965,
+	0x0018, 0x2459, 0x0078, 0x36a5, 0x6b14, 0x8307, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa080, 0x5380, 0x2060, 0x2048, 0x7056,
+	0x6000, 0x705a, 0x6004, 0x705e, 0x2a60, 0x007c, 0x0079, 0x39c0,
+	0x39c8, 0x39c9, 0x39c8, 0x39cb, 0x39c8, 0x39c8, 0x39c8, 0x39d0,
+	0x007c, 0x1078, 0x33ee, 0x1078, 0x4776, 0x7038, 0x600a, 0x007c,
+	0x70a0, 0xa005, 0x0040, 0x39dd, 0x2068, 0x1078, 0x1b62, 0x1078,
+	0x46f8, 0x1078, 0x46ff, 0x70a3, 0x0000, 0x007c, 0x0e7e, 0x2091,
+	0x8000, 0x2071, 0x5140, 0x7000, 0xa086, 0x0007, 0x00c0, 0x39f4,
+	0x6110, 0x70bc, 0xa106, 0x00c0, 0x39f4, 0x0e7f, 0x1078, 0x1b6f,
+	0x1078, 0x39fa, 0xa006, 0x007c, 0x2091, 0x8001, 0x0e7f, 0xa085,
+	0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x2071, 0x5140, 0x0078, 0x21fa,
+	0x785b, 0x0000, 0x70af, 0x000e, 0x2009, 0x0100, 0x017e, 0x70a0,
+	0xa06d, 0x0040, 0x3a0f, 0x70a3, 0x0000, 0x0078, 0x3a15, 0x70b3,
+	0x0000, 0x1078, 0x1b8b, 0x0040, 0x3a1b, 0x70ac, 0x6826, 0x1078,
+	0x3af8, 0x0078, 0x3a0f, 0x017f, 0x157e, 0x0c7e, 0x0d7e, 0x20a9,
+	0x0008, 0x2061, 0x7510, 0x6000, 0xa105, 0x6002, 0x601c, 0xa06d,
+	0x0040, 0x3a33, 0x6800, 0x601e, 0x1078, 0x195a, 0x6008, 0x8000,
+	0x600a, 0x0078, 0x3a26, 0x6018, 0xa06d, 0x0040, 0x3a3d, 0x6800,
+	0x601a, 0x1078, 0x195a, 0x0078, 0x3a33, 0xace0, 0x0008, 0x0070,
+	0x3a43, 0x0078, 0x3a23, 0x709c, 0xa084, 0x8000, 0x0040, 0x3a4a,
+	0x1078, 0x3b72, 0x0d7f, 0x0c7f, 0x157f, 0x007c, 0x127e, 0x2091,
+	0x2300, 0x6804, 0xa084, 0x000f, 0x0079, 0x3a56, 0x3a66, 0x3a66,
+	0x3a66, 0x3a66, 0x3a66, 0x3a66, 0x3a68, 0x3a6e, 0x3a66, 0x3a66,
+	0x3a66, 0x3a66, 0x3a66, 0x3a70, 0x3a66, 0x3a68, 0x1078, 0x23eb,
+	0x1078, 0x44d0, 0x1078, 0x195a, 0x0078, 0x3a74, 0x6827, 0x000b,
+	0x1078, 0x44d0, 0x1078, 0x3af8, 0x127f, 0x007c, 0x127e, 0x2091,
+	0x2300, 0x0098, 0x3a92, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3a92,
+	0x0d7e, 0x1078, 0x4708, 0x2d00, 0x682e, 0x2009, 0x0004, 0x2001,
+	0x0000, 0x6827, 0x0084, 0x1078, 0x46c1, 0x1078, 0x3af8, 0x0d7f,
+	0x0078, 0x3ac6, 0x7948, 0xa185, 0x4000, 0x784a, 0x0098, 0x3a9b,
+	0x794a, 0x0078, 0x3a80, 0x7828, 0xa086, 0x1834, 0x00c0, 0x3aa4,
+	0xa185, 0x0004, 0x0078, 0x3aab, 0x7828, 0xa086, 0x1814, 0x00c0,
+	0x3a98, 0xa185, 0x000c, 0x784a, 0x789b, 0x000e, 0x78ab, 0x0002,
+	0x7858, 0xa084, 0x00ff, 0xa085, 0x0400, 0x785a, 0x70b4, 0xa080,
+	0x0091, 0x781a, 0x6827, 0x0284, 0x682c, 0x6836, 0x6830, 0x683a,
+	0x2009, 0x0004, 0x2001, 0x0000, 0x1078, 0x46c1, 0x127f, 0x007c,
+	0x0d7e, 0x6b14, 0x1078, 0x1bfd, 0x0040, 0x3ad5, 0x2068, 0x6827,
+	0x0002, 0x1078, 0x3af8, 0x0078, 0x3aca, 0x0d7f, 0x007c, 0x0d7e,
+	0x6b14, 0x6c28, 0xa4a4, 0x00ff, 0x1078, 0x1b9b, 0x0040, 0x3ae5,
+	0x2068, 0x6827, 0x0002, 0x1078, 0x3af8, 0x0d7f, 0x007c, 0x0d7e,
+	0x6b14, 0xa39c, 0x00ff, 0x1078, 0x1bce, 0x0040, 0x3af6, 0x2068,
+	0x6827, 0x0002, 0x1078, 0x3af8, 0x0078, 0x3aeb, 0x0d7f, 0x007c,
+	0x0c7e, 0x6914, 0x1078, 0x3b69, 0x6904, 0xa18c, 0x00ff, 0xa186,
+	0x0006, 0x0040, 0x3b13, 0xa186, 0x000d, 0x0040, 0x3b32, 0xa186,
+	0x0017, 0x00c0, 0x3b0f, 0x1078, 0x195a, 0x0078, 0x3b11, 0x1078,
+	0x1c72, 0x0c7f, 0x007c, 0x6004, 0x8001, 0x0048, 0x3b30, 0x6006,
+	0x2009, 0x0000, 0xa684, 0x0001, 0x00c0, 0x3b20, 0xa18d, 0x8000,
+	0xa684, 0x0004, 0x0040, 0x3b26, 0xa18d, 0x0002, 0x691e, 0x6823,
+	0x0000, 0x7104, 0x810f, 0x6818, 0xa105, 0x681a, 0x0078, 0x3b0f,
+	0x1078, 0x23eb, 0x6018, 0xa005, 0x00c0, 0x3b41, 0x6008, 0x8001,
+	0x0048, 0x3b41, 0x600a, 0x601c, 0x6802, 0x2d00, 0x601e, 0x0078,
+	0x3b57, 0xac88, 0x0006, 0x2104, 0xa005, 0x0040, 0x3b4a, 0x2008,
+	0x0078, 0x3b43, 0x6802, 0x2d0a, 0x6008, 0x8001, 0x0048, 0x3b11,
+	0x600a, 0x6018, 0x2068, 0x6800, 0x601a, 0x0078, 0x3b3b, 0x157e,
+	0x137e, 0x147e, 0x0c7e, 0x0d7e, 0x1078, 0x1937, 0x2da0, 0x137f,
+	0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x0078,
+	0x3b0f, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003, 0xa080, 0x7510,
+	0x2060, 0x007c, 0x2019, 0x5151, 0x2304, 0xa085, 0x0001, 0x201a,
+	0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a, 0x007c, 0x2019,
+	0x5151, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019, 0x0102, 0x2304,
+	0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c, 0xfff8, 0x7992,
+	0x70b4, 0xa080, 0x00dd, 0x781a, 0x0078, 0x2459, 0x70a3, 0x0000,
+	0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000, 0x0018, 0x2410,
+	0x1078, 0x1b8b, 0x0040, 0x3bc7, 0x2009, 0x510f, 0x200b, 0x0000,
+	0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040, 0x3bbb, 0x6827,
+	0x000e, 0xa084, 0x0200, 0x0040, 0x3bb7, 0x6827, 0x0017, 0x1078,
+	0x3af8, 0x0078, 0x3b96, 0x7000, 0xa086, 0x0007, 0x00c0, 0x3c29,
+	0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078, 0x3bce, 0x7040,
+	0xa086, 0x0001, 0x0040, 0x2492, 0x0078, 0x2459, 0x2031, 0x0000,
+	0x691c, 0xa184, 0x0002, 0x0040, 0x3bd7, 0xa6b5, 0x0004, 0xa184,
+	0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3cc2, 0x2004, 0xa635,
+	0x6820, 0xa084, 0x0400, 0x0040, 0x3bef, 0x789b, 0x0018, 0x78ab,
+	0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5, 0x1000, 0x6820,
+	0xa084, 0x8000, 0x00c0, 0x3bfd, 0x681c, 0xa084, 0x8000, 0x00c0,
+	0x3c04, 0xa6b5, 0x0800, 0x0078, 0x3c04, 0xa6b5, 0x0400, 0x789b,
+	0x000e, 0x6824, 0x8007, 0x78aa, 0x6820, 0xa084, 0x0100, 0x0040,
+	0x3c0b, 0xa6b5, 0x4000, 0xa684, 0x0200, 0x0040, 0x3c25, 0x682c,
+	0x78d2, 0x6830, 0x78d6, 0xa684, 0x0100, 0x0040, 0x3c23, 0x682c,
+	0xa084, 0x0001, 0x0040, 0x3c23, 0x7888, 0xa084, 0x0040, 0x0040,
+	0x3c23, 0xa6b5, 0x8000, 0x1078, 0x46f0, 0x7e5a, 0x6eb6, 0x0078,
+	0x4727, 0x1078, 0x38fa, 0x00c0, 0x3cbc, 0x702c, 0x8004, 0x0048,
+	0x3c37, 0x2019, 0x4e3b, 0x1078, 0x2276, 0x702f, 0x0001, 0x2041,
+	0x0001, 0x2031, 0x1000, 0x789b, 0x0018, 0x6814, 0xa084, 0x001f,
+	0xa085, 0x0080, 0x78aa, 0x691c, 0xa184, 0x0002, 0x0040, 0x3c50,
+	0xa6b5, 0x0004, 0x78ab, 0x0020, 0x6828, 0x78aa, 0xa8c0, 0x0002,
+	0x681c, 0xd0f4, 0x0040, 0x3c59, 0x2c50, 0x1078, 0x39ac, 0x1078,
+	0x45ff, 0x6820, 0xa084, 0x8000, 0x0040, 0x3c67, 0xa6b5, 0x0400,
+	0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3c6e, 0x681c,
+	0xa084, 0x8000, 0x00c0, 0x3c6e, 0xa6b5, 0x0800, 0x6820, 0xa084,
+	0x0100, 0x0040, 0x3c75, 0xa6b5, 0x4000, 0x681c, 0xa084, 0x00c0,
+	0x8003, 0x8003, 0x8007, 0xa080, 0x3cc2, 0x2004, 0xa635, 0xa684,
+	0x0100, 0x0040, 0x3c8f, 0x682c, 0xa084, 0x0001, 0x0040, 0x3c8f,
+	0x7888, 0xa084, 0x0040, 0x0040, 0x3c8f, 0xa6b5, 0x8000, 0x789b,
+	0x007e, 0x7eae, 0x6eb6, 0x6814, 0x8007, 0x78aa, 0x7882, 0x2810,
+	0x7aaa, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3cbc, 0x0018, 0x3cbc,
+	0x70b4, 0xa080, 0x00e2, 0x781a, 0x1078, 0x3912, 0xa684, 0x0200,
+	0x0040, 0x3cb0, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x46f0,
+	0x2d00, 0x70a2, 0x704a, 0x6810, 0x70be, 0x7003, 0x0007, 0xad80,
+	0x000f, 0x7036, 0x0078, 0x2459, 0x1078, 0x1b62, 0x1078, 0x3912,
+	0x0078, 0x2459, 0x0000, 0x0300, 0x0200, 0x0000, 0x1078, 0x23eb,
+	0x2300, 0x0079, 0x3ccb, 0x3cce, 0x3cce, 0x3cd0, 0x1078, 0x23eb,
+	0x1078, 0x46ff, 0x6924, 0xa184, 0x00ff, 0xa086, 0x000a, 0x0040,
+	0x3ce2, 0xa184, 0xff00, 0xa085, 0x000a, 0x6826, 0x1078, 0x1b62,
+	0x0078, 0x3b96, 0x2001, 0x000a, 0x1078, 0x4691, 0x0078, 0x3b96,
+	0xa282, 0x0005, 0x0050, 0x3cee, 0x1078, 0x23eb, 0x7000, 0xa084,
+	0x0007, 0x10c0, 0x39be, 0x1078, 0x1937, 0x00c0, 0x3d0d, 0xa684,
+	0x0004, 0x0040, 0x3cff, 0x2001, 0x2800, 0x0078, 0x3d01, 0x2001,
+	0x0800, 0x71b4, 0xa188, 0x0091, 0x789b, 0x000e, 0x78aa, 0x2031,
+	0x0400, 0x7e5a, 0x791a, 0x0078, 0x2459, 0x6807, 0x0106, 0x680b,
+	0x0000, 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0,
+	0x3d2e, 0xa286, 0x0002, 0x00c0, 0x3d2e, 0x78a0, 0xa005, 0x00c0,
+	0x3d2e, 0xa484, 0x8000, 0x00c0, 0x3d2e, 0x78e4, 0xa084, 0x0008,
+	0x0040, 0x3d2e, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x411e,
+	0x2d00, 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824,
+	0xa084, 0x0080, 0x0040, 0x3d40, 0x1078, 0x41d0, 0x0078, 0x2459,
+	0x2300, 0x0079, 0x3d43, 0x3d46, 0x3dc7, 0x3de6, 0x2200, 0x0079,
+	0x3d49, 0x3d4e, 0x3d5e, 0x3d84, 0x3d90, 0x3db3, 0x2029, 0x0001,
+	0xa026, 0x2011, 0x0000, 0x1078, 0x42f1, 0x0079, 0x3d57, 0x3d5c,
+	0x2459, 0x3b96, 0x3d5c, 0x3d5c, 0x1078, 0x23eb, 0x7990, 0xa18c,
+	0x0007, 0x00c0, 0x3d65, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684,
+	0x0004, 0x0040, 0x3d6d, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011,
+	0x0001, 0x1078, 0x42f1, 0x0079, 0x3d75, 0x3d7a, 0x2459, 0x3b96,
+	0x3d82, 0x3d7c, 0x0078, 0x472d, 0x70ab, 0x3d80, 0x0078, 0x2459,
+	0x0078, 0x3d7a, 0x1078, 0x23eb, 0xa684, 0x0010, 0x0040, 0x3d8e,
+	0x1078, 0x419f, 0x0040, 0x3d8e, 0x0078, 0x2459, 0x0078, 0x420c,
+	0x6000, 0xa084, 0x0002, 0x0040, 0x3dad, 0x70b4, 0xa080, 0x00d2,
+	0x781a, 0x0d7e, 0x1078, 0x4708, 0x2d00, 0x682e, 0x6827, 0x0000,
+	0x1078, 0x3af8, 0x0d7f, 0x1078, 0x195a, 0x7003, 0x0000, 0x7037,
+	0x0000, 0x704b, 0x0000, 0x0078, 0x3b96, 0xa684, 0x0004, 0x00c0,
+	0x3db3, 0x0078, 0x472d, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3dc5,
+	0x6000, 0xa084, 0x0001, 0x0040, 0x3dc5, 0x70ab, 0x3dc5, 0x2001,
+	0x0007, 0x1078, 0x4689, 0x0078, 0x4733, 0x0078, 0x472d, 0x2200,
+	0x0079, 0x3dca, 0x3dcf, 0x3dcf, 0x3dcf, 0x3dd1, 0x3dcf, 0x1078,
+	0x23eb, 0x70a7, 0x3dd5, 0x0078, 0x4739, 0x2011, 0x0018, 0x1078,
+	0x42eb, 0x0079, 0x3ddb, 0x3de0, 0x2459, 0x3b96, 0x3de2, 0x3de4,
+	0x1078, 0x23eb, 0x1078, 0x23eb, 0x1078, 0x23eb, 0x2200, 0x0079,
+	0x3de9, 0x3dee, 0x3df0, 0x3df0, 0x3dee, 0x3dee, 0x1078, 0x23eb,
+	0x78e4, 0xa084, 0x0008, 0x0040, 0x3e05, 0x70a7, 0x3df9, 0x0078,
+	0x4739, 0x2011, 0x0004, 0x1078, 0x42eb, 0x0079, 0x3dff, 0x3e05,
+	0x2459, 0x3b96, 0x3e05, 0x3e0f, 0x3e13, 0x70ab, 0x3e0d, 0x2001,
+	0x0003, 0x1078, 0x4689, 0x0078, 0x4733, 0x0078, 0x472d, 0x70ab,
+	0x3e05, 0x0078, 0x2459, 0x70ab, 0x3e17, 0x0078, 0x2459, 0x0078,
+	0x3e0d, 0xa282, 0x0003, 0x0050, 0x3e1f, 0x1078, 0x23eb, 0xa386,
+	0x0002, 0x00c0, 0x3e38, 0xa286, 0x0002, 0x00c0, 0x3e3e, 0x78a0,
+	0xa005, 0x00c0, 0x3e3e, 0xa484, 0x8000, 0x00c0, 0x3e3e, 0x78e4,
+	0xa084, 0x0008, 0x0040, 0x3e38, 0xa6b5, 0x0008, 0x2019, 0x0000,
+	0xa684, 0x0008, 0x0040, 0x3e3e, 0x1078, 0x417c, 0x6810, 0x70be,
+	0x7003, 0x0007, 0x2300, 0x0079, 0x3e45, 0x3e48, 0x3e75, 0x3e7d,
+	0x2200, 0x0079, 0x3e4b, 0x3e50, 0x3e4e, 0x3e69, 0x1078, 0x23eb,
+	0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, 0x42f1,
+	0x0079, 0x3e5a, 0x3e5f, 0x2459, 0x3b96, 0x3e67, 0x3e61, 0x0078,
+	0x472d, 0x70ab, 0x3e65, 0x0078, 0x2459, 0x0078, 0x3e5f, 0x1078,
+	0x23eb, 0xa684, 0x0010, 0x0040, 0x3e73, 0x1078, 0x419f, 0x0040,
+	0x3e73, 0x0078, 0x2459, 0x0078, 0x420c, 0x2200, 0x0079, 0x3e78,
+	0x3e7b, 0x3e7b, 0x3e7b, 0x1078, 0x23eb, 0x2200, 0x0079, 0x3e80,
+	0x3e83, 0x3e85, 0x3e85, 0x1078, 0x23eb, 0x78e4, 0xa084, 0x0008,
+	0x0040, 0x3e9a, 0x70a7, 0x3e8e, 0x0078, 0x4739, 0x2011, 0x0004,
+	0x1078, 0x42eb, 0x0079, 0x3e94, 0x3e9a, 0x2459, 0x3b96, 0x3e9a,
+	0x3ea4, 0x3ea8, 0x70ab, 0x3ea2, 0x2001, 0x0003, 0x1078, 0x4689,
+	0x0078, 0x4733, 0x0078, 0x472d, 0x70ab, 0x3e9a, 0x0078, 0x2459,
+	0x70ab, 0x3eac, 0x0078, 0x2459, 0x0078, 0x3ea2, 0x2300, 0x0079,
+	0x3eb1, 0x3eb6, 0x3eb8, 0x3eb4, 0x1078, 0x23eb, 0x70a4, 0x007a,
+	0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3ec0, 0x1078, 0x23eb,
+	0xa684, 0x0200, 0x0040, 0x3eca, 0x1078, 0x46f8, 0x1078, 0x42d3,
+	0x1078, 0x46ff, 0x2300, 0x0079, 0x3ecd, 0x3ed0, 0x3ef4, 0x3f5a,
+	0xa286, 0x0001, 0x0040, 0x3ed6, 0x1078, 0x23eb, 0xa684, 0x0200,
+	0x0040, 0x3ede, 0x1078, 0x46f8, 0x1078, 0x46ff, 0x2001, 0x0001,
+	0x1078, 0x4691, 0x78b8, 0xa084, 0xc001, 0x0040, 0x3ef0, 0x7848,
+	0xa085, 0x0008, 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3eeb,
+	0x7003, 0x0000, 0x0078, 0x3b96, 0x2200, 0x0079, 0x3ef7, 0x3ef9,
+	0x3f2a, 0x70a7, 0x3efd, 0x0078, 0x4739, 0x2011, 0x000d, 0x1078,
+	0x42eb, 0x0079, 0x3f03, 0x3f0a, 0x2459, 0x3b96, 0x3f12, 0x3f1a,
+	0x3f20, 0x3f22, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x0078, 0x4727, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x0078, 0x4727, 0x70ab, 0x3f1e, 0x0078, 0x2459, 0x0078, 0x3f0a,
+	0x1078, 0x23eb, 0x70ab, 0x3f26, 0x0078, 0x2459, 0x1078, 0x473f,
+	0x0078, 0x2459, 0x70a7, 0x3f2e, 0x0078, 0x4739, 0x2011, 0x0012,
+	0x1078, 0x42eb, 0x0079, 0x3f34, 0x3f3a, 0x2459, 0x3b96, 0x3f46,
+	0x3f4e, 0x3f54, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x70b4, 0xa080, 0x00a6, 0x781a, 0x0078, 0x2459, 0xa6b4, 0x00ff,
+	0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0x70ab, 0x3f52,
+	0x0078, 0x2459, 0x0078, 0x3f3a, 0x70ab, 0x3f58, 0x0078, 0x2459,
+	0x0078, 0x3f46, 0xa286, 0x0001, 0x0040, 0x3f60, 0x1078, 0x23eb,
+	0x70a7, 0x3f64, 0x0078, 0x4739, 0x2011, 0x0015, 0x1078, 0x42eb,
+	0x0079, 0x3f6a, 0x3f6f, 0x2459, 0x3b96, 0x3f7d, 0x3f89, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4,
+	0xa080, 0x00b4, 0x781a, 0x0078, 0x2459, 0xa6b4, 0x00ff, 0xa6b5,
+	0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00a6, 0x781a, 0x0078,
+	0x2459, 0x70ab, 0x3f8d, 0x0078, 0x2459, 0x0078, 0x3f6f, 0xa282,
+	0x0003, 0x0050, 0x3f95, 0x1078, 0x23eb, 0x2300, 0x0079, 0x3f98,
+	0x3f9b, 0x3fd2, 0x402d, 0xa286, 0x0001, 0x0040, 0x3fa1, 0x1078,
+	0x23eb, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3fae,
+	0x1078, 0x3af8, 0x7003, 0x0000, 0x0078, 0x3b96, 0x683b, 0x0000,
+	0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x3fbc, 0x1078, 0x46f8,
+	0x1078, 0x42d3, 0x1078, 0x46ff, 0x2001, 0x0001, 0x1078, 0x4691,
+	0x78b8, 0xa084, 0xc001, 0x0040, 0x3fce, 0x7848, 0xa085, 0x0008,
+	0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3fc9, 0x7003, 0x0000,
+	0x0078, 0x3b96, 0x2200, 0x0079, 0x3fd5, 0x3fd7, 0x4008, 0x70a7,
+	0x3fdb, 0x0078, 0x4739, 0x2011, 0x000d, 0x1078, 0x42eb, 0x0079,
+	0x3fe1, 0x3fe8, 0x2459, 0x3b96, 0x3ff0, 0x3ff8, 0x3ffe, 0x4000,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+	0x70ab, 0x3ffc, 0x0078, 0x2459, 0x0078, 0x3fe8, 0x1078, 0x23eb,
+	0x70ab, 0x4004, 0x0078, 0x2459, 0x1078, 0x473f, 0x0078, 0x2459,
+	0x70a7, 0x400c, 0x0078, 0x4739, 0x2011, 0x0005, 0x1078, 0x42eb,
+	0x0079, 0x4012, 0x4017, 0x2459, 0x3b96, 0x401f, 0x4027, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727, 0x70ab,
+	0x402b, 0x0078, 0x2459, 0x0078, 0x4017, 0xa286, 0x0001, 0x0040,
+	0x4033, 0x1078, 0x23eb, 0x70a7, 0x4037, 0x0078, 0x4739, 0x2011,
+	0x0006, 0x1078, 0x42eb, 0x0079, 0x403d, 0x4042, 0x2459, 0x3b96,
+	0x4048, 0x4052, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x4727,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a,
+	0x0078, 0x4727, 0x70ab, 0x4056, 0x0078, 0x2459, 0x0078, 0x4042,
+	0x2300, 0x0079, 0x405b, 0x4060, 0x405e, 0x405e, 0x1078, 0x23eb,
+	0x1078, 0x23eb, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be,
+	0xa282, 0x0003, 0x0050, 0x406e, 0x1078, 0x23eb, 0x2300, 0x0079,
+	0x4071, 0x4074, 0x4082, 0x40a4, 0xa684, 0x0200, 0x0040, 0x407c,
+	0x1078, 0x46f8, 0x1078, 0x46ff, 0x2001, 0x0001, 0x1078, 0x4691,
+	0x0078, 0x2459, 0xa296, 0x0002, 0x0040, 0x408b, 0x82ff, 0x0040,
+	0x408b, 0x1078, 0x23eb, 0x70a7, 0x408f, 0x0078, 0x4739, 0x2011,
+	0x0018, 0x1078, 0x42eb, 0x0079, 0x4095, 0x409a, 0x2459, 0x3b96,
+	0x409c, 0x409e, 0x0078, 0x4727, 0x0078, 0x4727, 0x70ab, 0x40a2,
+	0x0078, 0x2459, 0x0078, 0x409a, 0x2200, 0x0079, 0x40a7, 0x40a9,
+	0x40c2, 0x70a7, 0x40ad, 0x0078, 0x4739, 0x2011, 0x0017, 0x1078,
+	0x42eb, 0x0079, 0x40b3, 0x40b8, 0x2459, 0x3b96, 0x40ba, 0x40bc,
+	0x0078, 0x4727, 0x0078, 0x4727, 0x70ab, 0x40c0, 0x0078, 0x2459,
+	0x0078, 0x40b8, 0xa484, 0x8000, 0x00c0, 0x410c, 0xa684, 0x0100,
+	0x0040, 0x40d6, 0x1078, 0x46f8, 0x1078, 0x42d3, 0x1078, 0x46ff,
+	0x7848, 0xa085, 0x000c, 0x784a, 0x0078, 0x40da, 0x78d8, 0x78d2,
+	0x78dc, 0x78d6, 0xa6b4, 0xefff, 0x7e5a, 0x70a7, 0x40e1, 0x0078,
+	0x4739, 0x2011, 0x000d, 0x1078, 0x42eb, 0x0079, 0x40e7, 0x40ee,
+	0x2459, 0x3b96, 0x40ee, 0x40fc, 0x4102, 0x4104, 0xa684, 0x0100,
+	0x0040, 0x40fa, 0x1078, 0x46b6, 0x682c, 0x78d2, 0x6830, 0x78d6,
+	0x1078, 0x46f0, 0x0078, 0x4727, 0x70ab, 0x4100, 0x0078, 0x2459,
+	0x0078, 0x40ee, 0x1078, 0x23eb, 0x70ab, 0x4108, 0x0078, 0x2459,
+	0x1078, 0x473f, 0x0078, 0x2459, 0x1078, 0x46ff, 0x70ab, 0x4116,
+	0x2001, 0x0003, 0x1078, 0x4689, 0x0078, 0x4733, 0x1078, 0x46f0,
+	0x682c, 0x78d2, 0x6830, 0x78d6, 0x0078, 0x4727, 0x70b8, 0x6812,
+	0x70be, 0x8000, 0x70ba, 0x681b, 0x0000, 0xa684, 0x0008, 0x0040,
+	0x4141, 0x157e, 0x137e, 0x147e, 0x7890, 0x8004, 0x8004, 0x8004,
+	0x8004, 0xa084, 0x000f, 0x681a, 0x80ac, 0x789b, 0x0000, 0xaf80,
+	0x002b, 0x2098, 0xad80, 0x000b, 0x20a0, 0x53a5, 0x147f, 0x137f,
+	0x157f, 0xa6c4, 0x0f00, 0xa684, 0x0002, 0x00c0, 0x4150, 0x692c,
+	0x810d, 0x810d, 0x810d, 0xa184, 0x0007, 0x2008, 0x0078, 0x415f,
+	0x789b, 0x0010, 0x79ac, 0xa184, 0x0020, 0x0040, 0x415f, 0x017e,
+	0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x46c1, 0x017f, 0xa184,
+	0x001f, 0xa805, 0x6816, 0x1078, 0x3b69, 0x68be, 0xa684, 0x0004,
+	0x0040, 0x4170, 0xa18c, 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105,
+	0x682a, 0xa6b4, 0x00ff, 0x6000, 0xa084, 0x0008, 0x0040, 0x417a,
+	0xa6b5, 0x4000, 0x6eb6, 0x007c, 0x157e, 0x137e, 0x147e, 0x6918,
+	0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, 0x007e,
+	0xa100, 0x681a, 0x007f, 0x8000, 0x8004, 0x0040, 0x419b, 0x20a8,
+	0x8104, 0xa080, 0x000b, 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80,
+	0x002b, 0x2098, 0x53a5, 0x147f, 0x137f, 0x157f, 0x007c, 0x682c,
+	0xa084, 0x0020, 0x00c0, 0x41a7, 0x620c, 0x0078, 0x41a8, 0x6210,
+	0x6b18, 0x2300, 0xa202, 0x0040, 0x41c8, 0x2018, 0xa382, 0x000e,
+	0x0048, 0x41b8, 0x0040, 0x41b8, 0x2019, 0x000e, 0x0078, 0x41bc,
+	0x7858, 0xa084, 0xffef, 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000,
+	0x7ba2, 0x70b4, 0xa080, 0x008e, 0x781a, 0xa085, 0x0001, 0x007c,
+	0x7858, 0xa084, 0xffef, 0x785a, 0x7893, 0x0000, 0xa006, 0x007c,
+	0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x41dd, 0xa196,
+	0x000f, 0x0040, 0x41dd, 0x6807, 0x0117, 0x6914, 0x1078, 0x3b69,
+	0x6100, 0x8104, 0x00c8, 0x41f8, 0x601c, 0xa005, 0x0040, 0x41ec,
+	0x2001, 0x0800, 0x0078, 0x41fa, 0x0d7e, 0x6824, 0x007e, 0x1078,
+	0x4708, 0x007f, 0x6826, 0x2d00, 0x682e, 0x1078, 0x3af8, 0x0d7f,
+	0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
+	0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4,
+	0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, 0x0002,
+	0x00c0, 0x4220, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x0007,
+	0x2008, 0xa805, 0x6816, 0x1078, 0x3b69, 0x68be, 0x0078, 0x4223,
+	0x6914, 0x1078, 0x3b69, 0x6100, 0x8104, 0x00c8, 0x4280, 0xa184,
+	0x0300, 0x0040, 0x422f, 0x6807, 0x0117, 0x0078, 0x424d, 0x6004,
+	0xa005, 0x00c0, 0x4256, 0x6807, 0x0117, 0x601c, 0xa005, 0x00c0,
+	0x4243, 0x0d7e, 0x1078, 0x4708, 0x6827, 0x0034, 0x2d00, 0x682e,
+	0x1078, 0x3af8, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x424d, 0x2031,
+	0x0400, 0x2001, 0x2800, 0x0078, 0x4251, 0x2031, 0x0400, 0x2001,
+	0x0800, 0x71b4, 0xa188, 0x0091, 0x0078, 0x42ae, 0x6018, 0xa005,
+	0x00c0, 0x4243, 0x601c, 0xa005, 0x00c0, 0x4243, 0x689f, 0x0000,
+	0x6827, 0x003d, 0xa684, 0x0001, 0x0040, 0x42bc, 0xd694, 0x00c0,
+	0x4279, 0x6100, 0xd1d4, 0x0040, 0x4279, 0x692c, 0x81ff, 0x0040,
+	0x42bc, 0xa186, 0x0003, 0x0040, 0x42bc, 0xa186, 0x0012, 0x0040,
+	0x42bc, 0xa6b5, 0x0800, 0x71b4, 0xa188, 0x00af, 0x0078, 0x42b7,
+	0x6807, 0x0117, 0x2031, 0x0400, 0x692c, 0xa18c, 0x00ff, 0xa186,
+	0x0012, 0x00c0, 0x4291, 0x2001, 0x42c9, 0x2009, 0x0001, 0x0078,
+	0x42a2, 0xa186, 0x0003, 0x00c0, 0x429b, 0x2001, 0x42ca, 0x2009,
+	0x0012, 0x0078, 0x42a2, 0x2001, 0x0200, 0x71b4, 0xa188, 0x0091,
+	0x0078, 0x42ae, 0x1078, 0x46db, 0x78a3, 0x0000, 0x681c, 0xa085,
+	0x0040, 0x681e, 0x71b4, 0xa188, 0x00df, 0xa006, 0x6826, 0x8007,
+	0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, 0x6822, 0x6eb6,
+	0x7e5a, 0x791a, 0x0078, 0x2459, 0x6eb6, 0x1078, 0x3af8, 0x6810,
+	0x70be, 0x7003, 0x0007, 0x70a3, 0x0000, 0x704b, 0x0000, 0x0078,
+	0x2459, 0x0023, 0x0070, 0x0005, 0x0000, 0x0a00, 0x0000, 0x0000,
+	0x0025, 0x0000, 0x0000, 0x683b, 0x0000, 0x6837, 0x0000, 0xa684,
+	0x0200, 0x0040, 0x42ea, 0x78b8, 0xa08c, 0x001f, 0xa084, 0x8000,
+	0x0040, 0x42e3, 0x8108, 0x78d8, 0xa100, 0x6836, 0x78dc, 0xa081,
+	0x0000, 0x683a, 0x007c, 0x7990, 0x810f, 0xa5ac, 0x0007, 0x2021,
+	0x0000, 0xa480, 0x0010, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa184,
+	0x0080, 0x00c0, 0x4319, 0xa182, 0x0020, 0x00c8, 0x4337, 0xa182,
+	0x0012, 0x00c8, 0x467b, 0x2100, 0x1079, 0x4307, 0x007c, 0x467b,
+	0x44e8, 0x467b, 0x467b, 0x4344, 0x4347, 0x4381, 0x43b7, 0x43eb,
+	0x43ee, 0x467b, 0x467b, 0x43a2, 0x4412, 0x444c, 0x467b, 0x467b,
+	0x4473, 0xa184, 0x0020, 0x00c0, 0x44a7, 0xa18c, 0x001f, 0x6814,
+	0xa084, 0x001f, 0xa106, 0x0040, 0x4334, 0x70b4, 0xa080, 0x00d2,
+	0x781a, 0x2001, 0x0014, 0x1078, 0x4691, 0x1078, 0x46ff, 0x7003,
+	0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, 0x007c, 0xa182,
+	0x0024, 0x00c8, 0x467b, 0xa184, 0x0003, 0x1079, 0x4307, 0x007c,
+	0x467b, 0x467b, 0x467b, 0x467b, 0x1078, 0x467b, 0x007c, 0x2200,
+	0x0079, 0x434a, 0x4476, 0x4476, 0x436e, 0x436e, 0x436e, 0x436e,
+	0x436e, 0x436e, 0x436e, 0x436e, 0x436c, 0x436e, 0x4363, 0x436e,
+	0x436e, 0x436e, 0x436e, 0x436e, 0x4376, 0x4379, 0x4476, 0x4379,
+	0x436e, 0x436e, 0x436e, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x36e2,
+	0x077f, 0x0c7f, 0x0078, 0x436e, 0x1078, 0x458b, 0x6827, 0x02b3,
+	0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x44aa, 0x1078, 0x4670,
+	0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078,
+	0x4492, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+	0x438b, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x4708, 0x6827,
+	0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ac8, 0x1078,
+	0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078, 0x3af8, 0x2001,
+	0x0002, 0x007c, 0x1078, 0x44d0, 0x2001, 0x0017, 0x1078, 0x4691,
+	0x70a3, 0x0000, 0x2009, 0x5138, 0x200b, 0x0006, 0x70af, 0x0017,
+	0x2009, 0x0200, 0x1078, 0x3a06, 0x2001, 0x0001, 0x007c, 0x2200,
+	0x0079, 0x43ba, 0x4476, 0x44a7, 0x44a7, 0x44a7, 0x43db, 0x44b7,
+	0x43e3, 0x44b7, 0x44b7, 0x44ba, 0x44ba, 0x44bf, 0x44bf, 0x43d3,
+	0x43d3, 0x44a7, 0x44a7, 0x44b7, 0x44a7, 0x43e3, 0x4476, 0x43e3,
+	0x43e3, 0x43e3, 0x43e3, 0x6827, 0x0084, 0x2009, 0x000b, 0x2001,
+	0x4300, 0x0078, 0x44c9, 0x6827, 0x000d, 0x2009, 0x000b, 0x2001,
+	0x4300, 0x0078, 0x44aa, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001,
+	0x4300, 0x0078, 0x4492, 0x2001, 0x0000, 0x007c, 0x2200, 0x0079,
+	0x43f1, 0x4476, 0x440a, 0x440a, 0x440a, 0x440a, 0x44b7, 0x44b7,
+	0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x44b7, 0x440a, 0x440a,
+	0x440a, 0x440a, 0x44b7, 0x440a, 0x440a, 0x44b7, 0x44b7, 0x44b7,
+	0x44b7, 0x4476, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300,
+	0x0078, 0x4492, 0xa684, 0x0004, 0x00c0, 0x4426, 0x6804, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x00c0, 0x467b, 0x1078, 0x44d0, 0x6807,
+	0x0117, 0x1078, 0x3af8, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084,
+	0x0004, 0x0040, 0x467b, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x00c0, 0x4435, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078,
+	0x4708, 0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078,
+	0x3ad7, 0x1078, 0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078,
+	0x3af8, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040,
+	0x467b, 0x2d58, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, 0x00c0,
+	0x445b, 0x6807, 0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, 0x4708,
+	0x6827, 0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ae7,
+	0x1078, 0x44d0, 0x2b68, 0x1078, 0x3af8, 0x0d7f, 0x1078, 0x3af8,
+	0x2001, 0x0002, 0x007c, 0x1078, 0x467b, 0x007c, 0x70b4, 0xa080,
+	0x00d2, 0x781a, 0x2001, 0x0001, 0x1078, 0x4691, 0x1078, 0x46ff,
+	0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x46c1, 0x1078,
+	0x46f8, 0x1078, 0x42d3, 0x1078, 0x41d0, 0x1078, 0x46ff, 0x2001,
+	0x0001, 0x007c, 0x1078, 0x46c1, 0x1078, 0x46f8, 0x1078, 0x42d3,
+	0x70b4, 0xa080, 0x00d2, 0x781a, 0x2001, 0x0013, 0x1078, 0x4691,
+	0x1078, 0x46ff, 0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078,
+	0x467b, 0x007c, 0x1078, 0x46c1, 0x1078, 0x46f8, 0x1078, 0x42d3,
+	0x1078, 0x41d0, 0x1078, 0x46ff, 0x2001, 0x0001, 0x007c, 0x2001,
+	0x0003, 0x007c, 0x1078, 0x458b, 0x2001, 0x0000, 0x007c, 0x0c7e,
+	0x077e, 0x6f14, 0x1078, 0x36e2, 0x077f, 0x0c7f, 0x2001, 0x0000,
+	0x007c, 0x1078, 0x46c1, 0x1078, 0x467b, 0x2001, 0x0006, 0x007c,
+	0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x44db, 0xa186,
+	0x000f, 0x00c0, 0x44df, 0x1078, 0x46f8, 0x1078, 0x42d3, 0x70b4,
+	0xa080, 0x00d2, 0x781a, 0x1078, 0x46ff, 0x7003, 0x0000, 0x007c,
+	0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004,
+	0x00c8, 0x467b, 0x1079, 0x44f5, 0x007c, 0x467b, 0x44f9, 0x467b,
+	0x4592, 0xa282, 0x0003, 0x0040, 0x4500, 0x1078, 0x467b, 0x007c,
+	0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0x69b8, 0xa184,
+	0x0100, 0x0040, 0x453f, 0xa18c, 0xfeff, 0x69ba, 0x78a0, 0xa005,
+	0x00c0, 0x453f, 0xa4a4, 0x00ff, 0x0040, 0x4533, 0xa482, 0x000c,
+	0x0040, 0x451c, 0x00c8, 0x4526, 0x852b, 0x852b, 0x1078, 0x3760,
+	0x0040, 0x4526, 0x1078, 0x355b, 0x0078, 0x4535, 0x1078, 0x465d,
+	0x1078, 0x3586, 0x69b8, 0xa18d, 0x0100, 0x69ba, 0xa6b5, 0x1000,
+	0x7e5a, 0x0078, 0x4538, 0x1078, 0x3586, 0xa6b4, 0xefff, 0x7e5a,
+	0x70b4, 0xa080, 0x0091, 0x781a, 0x2001, 0x0001, 0x007c, 0x0c7e,
+	0x1078, 0x457f, 0x6200, 0xd2e4, 0x0040, 0x4570, 0x6208, 0x8217,
+	0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x4552, 0x0040, 0x4552,
+	0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, 0x4557, 0x2220, 0x6208,
+	0xa294, 0x00ff, 0x701c, 0xa202, 0x00c8, 0x455f, 0x721c, 0x2200,
+	0xa502, 0x00c8, 0x4564, 0x2228, 0x1078, 0x4661, 0x852b, 0x852b,
+	0x1078, 0x3760, 0x0040, 0x4570, 0x1078, 0x3562, 0x0078, 0x4574,
+	0x1078, 0x465d, 0x1078, 0x358d, 0xa6b5, 0x1000, 0x7e5a, 0x70b4,
+	0xa080, 0x00be, 0x781a, 0x2001, 0x0004, 0x0c7f, 0x007c, 0x007e,
+	0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0,
+	0x5380, 0x007f, 0x007c, 0x0c7e, 0x1078, 0x457f, 0x1078, 0x358d,
+	0x0c7f, 0x007c, 0xa282, 0x0002, 0x00c0, 0x467b, 0x7aa8, 0xa294,
+	0x00ff, 0x69b8, 0xa184, 0x0200, 0x0040, 0x45c9, 0xa18c, 0xfdff,
+	0x69ba, 0x78a0, 0xa005, 0x00c0, 0x45c9, 0xa282, 0x0002, 0x00c8,
+	0x369d, 0x1078, 0x4627, 0x1078, 0x362b, 0x1078, 0x3586, 0xa684,
+	0x0100, 0x0040, 0x45bf, 0x682c, 0xa084, 0x0001, 0x0040, 0x45bf,
+	0xc6fc, 0x7888, 0xa084, 0x0040, 0x0040, 0x45bf, 0xc6fd, 0xa6b5,
+	0x1000, 0x7e5a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x2001, 0x0001,
+	0x007c, 0x0c7e, 0x1078, 0x457f, 0xa284, 0xfffe, 0x0040, 0x45d4,
+	0x2011, 0x0001, 0x0078, 0x45d8, 0xa284, 0x0001, 0x0040, 0x45de,
+	0x6100, 0xd1ec, 0x00c0, 0x45de, 0x2011, 0x0000, 0x1078, 0x4619,
+	0x1078, 0x3632, 0x1078, 0x358d, 0xa684, 0x0100, 0x0040, 0x45f4,
+	0x682c, 0xa084, 0x0001, 0x0040, 0x45f4, 0xc6fc, 0x7888, 0xa084,
+	0x0040, 0x0040, 0x45f4, 0xc6fd, 0xa6b5, 0x1000, 0x7e5a, 0x70b4,
+	0xa080, 0x00be, 0x781a, 0x2001, 0x0004, 0x0c7f, 0x007c, 0x0c7e,
+	0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x460a,
+	0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003,
+	0x7aaa, 0xa8c0, 0x0004, 0x68b8, 0xa085, 0x0200, 0x68ba, 0x0c7f,
+	0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+	0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, 0x0004, 0x007c, 0x0c7e,
+	0x7054, 0x2060, 0x6000, 0xa084, 0x1000, 0x00c0, 0x4635, 0x2029,
+	0x0032, 0x2021, 0x0000, 0x0078, 0x4655, 0x6508, 0xa5ac, 0x00ff,
+	0x7018, 0xa086, 0x0028, 0x00c0, 0x4645, 0xa582, 0x0019, 0x00c8,
+	0x464b, 0x2029, 0x0019, 0x0078, 0x464b, 0xa582, 0x000c, 0x00c8,
+	0x464b, 0x2029, 0x000c, 0x6408, 0x8427, 0xa4a4, 0x00ff, 0xa482,
+	0x000c, 0x0048, 0x4655, 0x2021, 0x000c, 0x1078, 0x4661, 0x68b8,
+	0xa085, 0x0100, 0x68ba, 0x0c7f, 0x007c, 0x2021, 0x0000, 0x2029,
+	0x0032, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+	0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081, 0x78ab, 0x0005, 0x007c,
+	0x2001, 0x0003, 0x1078, 0x4689, 0x70b4, 0xa080, 0x00be, 0x781a,
+	0x2001, 0x0005, 0x007c, 0x2001, 0x0007, 0x1078, 0x4689, 0xa6b5,
+	0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00be, 0x781a, 0x2001, 0x0004,
+	0x007c, 0x789b, 0x0018, 0x78aa, 0x789b, 0x0081, 0x78ab, 0x0001,
+	0x007c, 0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x469f,
+	0xa196, 0x000f, 0x0040, 0x469f, 0x1078, 0x195a, 0x007c, 0x6924,
+	0xa194, 0x003f, 0x00c0, 0x46a8, 0xa18c, 0xffc0, 0xa105, 0x6826,
+	0x1078, 0x3af8, 0x691c, 0xa184, 0x0100, 0x0040, 0x46b5, 0x6914,
+	0x1078, 0x3b69, 0x6204, 0x8210, 0x6206, 0x007c, 0x692c, 0x6834,
+	0x682e, 0xa112, 0x6930, 0x6838, 0x6832, 0xa11b, 0xa200, 0xa301,
+	0x007c, 0x0c7e, 0xade0, 0x0018, 0x6003, 0x0070, 0x6106, 0x600b,
+	0x0000, 0x600f, 0x0a00, 0x6013, 0x0000, 0x6017, 0x0000, 0x8007,
+	0x601a, 0x601f, 0x0000, 0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085,
+	0x0080, 0x6826, 0x007c, 0x157e, 0x137e, 0x147e, 0x2098, 0xaf80,
+	0x002d, 0x20a0, 0x81ac, 0x0040, 0x46e6, 0x53a6, 0xa184, 0x0001,
+	0x0040, 0x46ec, 0x3304, 0x78be, 0x147f, 0x137f, 0x157f, 0x007c,
+	0x70b0, 0xa005, 0x10c0, 0x23eb, 0x70b3, 0x8000, 0x0078, 0x4a3a,
+	0x71b0, 0x81ff, 0x0040, 0x46fe, 0x1078, 0x4b30, 0x007c, 0x71b0,
+	0x81ff, 0x0040, 0x4707, 0x70b3, 0x0000, 0x1078, 0x4776, 0x007c,
+	0x0c7e, 0x0d7e, 0x1078, 0x1937, 0x0c7f, 0x157e, 0x137e, 0x147e,
+	0x2da0, 0x2c98, 0x20a9, 0x0031, 0x53a3, 0x147f, 0x137f, 0x157f,
+	0x6807, 0x010d, 0x680b, 0x0000, 0x7004, 0x8007, 0x681a, 0x6823,
+	0x0000, 0x681f, 0x0000, 0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4,
+	0xa080, 0x0091, 0x781a, 0x0078, 0x2459, 0x70b4, 0xa080, 0x0081,
+	0x781a, 0x0078, 0x2459, 0x70b4, 0xa080, 0x00be, 0x781a, 0x0078,
+	0x2459, 0x70b4, 0xa080, 0x00c8, 0x781a, 0x0078, 0x2459, 0x6904,
+	0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x474c, 0xa196, 0x000f,
+	0x0040, 0x474c, 0x6807, 0x0117, 0x2001, 0x0200, 0x6826, 0x8007,
+	0x789b, 0x000e, 0x78aa, 0x6820, 0xa085, 0x8000, 0x6822, 0x2031,
+	0x0400, 0x6eb6, 0x7e5a, 0x71b4, 0xa188, 0x0091, 0x791a, 0x007c,
+	0x1078, 0x46ff, 0x7848, 0xa085, 0x000c, 0x784a, 0x70b4, 0xa080,
+	0x00d2, 0x781a, 0x2009, 0x000b, 0x2001, 0x4400, 0x1078, 0x46c1,
+	0x2001, 0x0013, 0x1078, 0x4691, 0x0078, 0x3b96, 0x127e, 0x2091,
+	0x2200, 0x2049, 0x4776, 0x7000, 0x7204, 0xa205, 0x720c, 0xa215,
+	0x7008, 0xa084, 0xfff7, 0xa205, 0x0040, 0x4788, 0x0078, 0x478d,
+	0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x7000, 0xa084, 0x0001,
+	0x00c0, 0x47bb, 0x7108, 0x8103, 0x00c8, 0x479a, 0x1078, 0x48bd,
+	0x0078, 0x4792, 0x700c, 0xa08c, 0x00ff, 0x0040, 0x47bb, 0x7004,
+	0x8004, 0x00c8, 0x47b2, 0x7014, 0xa005, 0x00c0, 0x47ae, 0x7010,
+	0xa005, 0x0040, 0x47b2, 0xa102, 0x00c8, 0x4792, 0x7007, 0x0010,
+	0x0078, 0x47bb, 0x8aff, 0x0040, 0x47bb, 0x1078, 0x4b07, 0x00c0,
+	0x47b5, 0x0040, 0x4792, 0x1078, 0x4846, 0x7003, 0x0000, 0x127f,
+	0x2000, 0x007c, 0x017e, 0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007,
+	0x0040, 0x47ce, 0xa18e, 0x000f, 0x00c0, 0x47d1, 0x6040, 0x0078,
+	0x47d2, 0x6428, 0x017f, 0x84ff, 0x0040, 0x47fc, 0x2c70, 0x7004,
+	0xa0bc, 0x000f, 0xa7b8, 0x480c, 0x273c, 0x87fb, 0x00c0, 0x47ea,
+	0x0048, 0x47e4, 0x1078, 0x23eb, 0x609c, 0xa075, 0x0040, 0x47fc,
+	0x0078, 0x47d7, 0x2704, 0xae68, 0x6808, 0xa630, 0x680c, 0xa529,
+	0x8421, 0x0040, 0x47fc, 0x8738, 0x2704, 0xa005, 0x00c0, 0x47eb,
+	0x709c, 0xa075, 0x00c0, 0x47d7, 0x007c, 0x0000, 0x0005, 0x0009,
+	0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003, 0x0009,
+	0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x4801, 0x47fe, 0x0000,
+	0x0000, 0x8000, 0x0000, 0x4801, 0x0000, 0x4809, 0x4806, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x4809, 0x0000, 0x4804, 0x4804, 0x0000,
+	0x0000, 0x8000, 0x0000, 0x4804, 0x0000, 0x480a, 0x480a, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x480a, 0x127e, 0x2091, 0x2200, 0x2079,
+	0x5100, 0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+	0x0000, 0x2071, 0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+	0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, 0x4846,
+	0x2019, 0x0000, 0x7004, 0x8004, 0x00c8, 0x4899, 0x7007, 0x0012,
+	0x7108, 0x7008, 0xa106, 0x00c0, 0x4850, 0xa184, 0x01e0, 0x0040,
+	0x485b, 0x1078, 0x23eb, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+	0x00c8, 0x4866, 0xa184, 0x4000, 0x00c0, 0x4850, 0xa19c, 0x300c,
+	0xa386, 0x2004, 0x0040, 0x4874, 0xa386, 0x0008, 0x0040, 0x487f,
+	0xa386, 0x200c, 0x00c0, 0x4850, 0x7200, 0x8204, 0x0048, 0x487f,
+	0x730c, 0xa384, 0x00ff, 0x0040, 0x487f, 0x1078, 0x23eb, 0x7007,
+	0x0012, 0x7000, 0xa084, 0x0001, 0x00c0, 0x4899, 0x7008, 0xa084,
+	0x01e0, 0x00c0, 0x4899, 0x7310, 0x7014, 0xa305, 0x0040, 0x4899,
+	0x710c, 0xa184, 0x0300, 0x00c0, 0x4899, 0xa184, 0x00ff, 0x00c0,
+	0x4846, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008,
+	0x00c0, 0x489d, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x48a2,
+	0x7003, 0x0000, 0x2049, 0x0000, 0x007c, 0x107e, 0x007e, 0x127e,
+	0x157e, 0x2091, 0x2200, 0x7108, 0x1078, 0x48bd, 0x157f, 0x127f,
+	0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7204, 0x7500, 0x730c,
+	0xa384, 0x0300, 0x00c0, 0x48e4, 0xa184, 0x01e0, 0x00c0, 0x4908,
+	0x7108, 0xa184, 0x01e0, 0x00c0, 0x4908, 0x2001, 0x04fd, 0x2004,
+	0xa082, 0x0005, 0x00c8, 0x48d8, 0xa184, 0x4000, 0x00c0, 0x48c8,
+	0xa184, 0x0007, 0x0079, 0x48dc, 0x48e6, 0x48f8, 0x48e4, 0x48f8,
+	0x48e4, 0x4944, 0x48e4, 0x4942, 0x1078, 0x23eb, 0x7004, 0xa084,
+	0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x48f3, 0x2049,
+	0x0000, 0x0078, 0x48f7, 0x1078, 0x4b07, 0x00c0, 0x48f3, 0x007c,
+	0x7004, 0xa084, 0x0010, 0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0,
+	0x4903, 0x0078, 0x4907, 0x1078, 0x4b07, 0x00c0, 0x4903, 0x007c,
+	0x7007, 0x0012, 0x7108, 0x00e0, 0x490b, 0x2091, 0x6000, 0x00e0,
+	0x490f, 0x2091, 0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004,
+	0xa084, 0x0008, 0x00c0, 0x4917, 0x7007, 0x0012, 0x7108, 0x8103,
+	0x0048, 0x491c, 0x7003, 0x0000, 0x7000, 0xa005, 0x00c0, 0x4930,
+	0x7004, 0xa005, 0x00c0, 0x4930, 0x700c, 0xa005, 0x0040, 0x4932,
+	0x0078, 0x4913, 0x2049, 0x0000, 0x1078, 0x3809, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x493d, 0x681b, 0x0002, 0x007c, 0x1078, 0x23eb,
+	0x1078, 0x23eb, 0x1078, 0x49a0, 0x7210, 0x7114, 0x700c, 0xa09c,
+	0x00ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000, 0x1078, 0x49a0,
+	0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322, 0x630c, 0x2100,
+	0xa31b, 0x2400, 0xa305, 0x0040, 0x4967, 0x00c8, 0x4967, 0x8412,
+	0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078, 0x494e, 0x2b60,
+	0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040, 0x4973, 0xa7ba,
+	0x4806, 0x0078, 0x4975, 0xa7ba, 0x47fe, 0x007f, 0xa73d, 0x2c00,
+	0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7007, 0x0012, 0x1078, 0x4846,
+	0x007c, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4994, 0x609c, 0xa005,
+	0x0040, 0x499d, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080, 0x480c,
+	0x203c, 0x87fb, 0x1040, 0x23eb, 0x8a51, 0x0040, 0x499c, 0x7008,
+	0xa084, 0x0003, 0xa086, 0x0003, 0x007c, 0x2051, 0x0000, 0x007c,
+	0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x49b4, 0x6000, 0xa064,
+	0x00c0, 0x49ab, 0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x481c,
+	0x203c, 0x87fb, 0x1040, 0x23eb, 0x007c, 0x127e, 0x0d7e, 0x2091,
+	0x2200, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057,
+	0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084, 0x0008,
+	0x007f, 0x0040, 0x49cf, 0xa0b8, 0x4806, 0x0078, 0x49d1, 0xa0b8,
+	0x47fe, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186,
+	0x0007, 0x0040, 0x49df, 0xa18e, 0x000f, 0x00c0, 0x49e8, 0x681c,
+	0xa084, 0x0040, 0x0040, 0x49ef, 0xa6b5, 0x0001, 0x0078, 0x49ef,
+	0x681c, 0xa084, 0x0040, 0x0040, 0x49ef, 0xa6b5, 0x0001, 0x7007,
+	0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x49f1, 0x2400, 0xa305,
+	0x00c0, 0x49fc, 0x0078, 0x4a22, 0x2c58, 0x2704, 0x6104, 0xac60,
+	0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184, 0x0008,
+	0x0040, 0x4a12, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081,
+	0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300,
+	0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x4981,
+	0x0078, 0x4a24, 0x1078, 0x4b07, 0x00c0, 0x4a22, 0x127f, 0x2000,
+	0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004,
+	0x7004, 0xa084, 0x0004, 0x00c0, 0x4a30, 0x7003, 0x0008, 0x127f,
+	0x2000, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049,
+	0x4a3a, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4a43,
+	0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007,
+	0x0040, 0x4a56, 0xa18e, 0x000f, 0x00c0, 0x4a61, 0x681c, 0xa084,
+	0x0040, 0x0040, 0x4a5d, 0xa6b5, 0x0001, 0x6840, 0x2050, 0x0078,
+	0x4a6a, 0x681c, 0xa084, 0x0020, 0x00c0, 0x4a68, 0xa6b5, 0x0001,
+	0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x480c,
+	0x273c, 0x87fb, 0x00c0, 0x4a7e, 0x0048, 0x4a78, 0x1078, 0x23eb,
+	0x689c, 0xa065, 0x0040, 0x4a82, 0x0078, 0x4a6b, 0x1078, 0x4b07,
+	0x00c0, 0x4a7e, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e,
+	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5,
+	0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4a9c,
+	0xa18e, 0x000f, 0x00c0, 0x4aa5, 0x681c, 0xa084, 0x0040, 0x0040,
+	0x4aac, 0xa6b5, 0x0001, 0x0078, 0x4aac, 0x681c, 0xa084, 0x0040,
+	0x0040, 0x4aac, 0xa6b5, 0x0001, 0x2049, 0x4a85, 0x017e, 0x6904,
+	0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4aba, 0xa18e, 0x000f,
+	0x00c0, 0x4abd, 0x6840, 0x0078, 0x4abe, 0x6828, 0x017f, 0xa055,
+	0x0040, 0x4b04, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8,
+	0x480c, 0x273c, 0x87fb, 0x00c0, 0x4ad8, 0x0048, 0x4ad1, 0x1078,
+	0x23eb, 0x709c, 0xa075, 0x2060, 0x0040, 0x4b04, 0x0078, 0x4ac4,
+	0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048, 0x4af1,
+	0x8a51, 0x00c0, 0x4ae5, 0x1078, 0x23eb, 0x8738, 0x2704, 0xa005,
+	0x00c0, 0x4ad9, 0x709c, 0xa075, 0x2060, 0x0040, 0x4b04, 0x0078,
+	0x4ac4, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908, 0x2400,
+	0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x4b00, 0x1078, 0x23eb,
+	0x2071, 0x0020, 0x0078, 0x49ef, 0x127f, 0x2000, 0x007c, 0x7008,
+	0xa084, 0x0003, 0xa086, 0x0003, 0x0040, 0x4b2f, 0x2704, 0xac08,
+	0x2104, 0x701a, 0x8108, 0x2104, 0x701e, 0x8108, 0x2104, 0x7012,
+	0x8108, 0x2104, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x4b26,
+	0x8108, 0x2104, 0x7022, 0x8108, 0x2104, 0x7026, 0x7602, 0x7004,
+	0xa084, 0x0010, 0xa085, 0x0001, 0x7006, 0x1078, 0x4981, 0x007c,
+	0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x2049, 0x4b30, 0x0d7f,
+	0x087f, 0x7108, 0xa184, 0x0003, 0x00c0, 0x4b5a, 0x017e, 0x6904,
+	0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4b4a, 0xa18e, 0x000f,
+	0x00c0, 0x4b4d, 0x6840, 0x0078, 0x4b4e, 0x6828, 0x017f, 0xa005,
+	0x0040, 0x4b68, 0x0078, 0x478d, 0x0020, 0x4b5a, 0x1078, 0x4944,
+	0x0078, 0x4b68, 0x00a0, 0x4b61, 0x7108, 0x1078, 0x48bd, 0x0078,
+	0x4b39, 0x7007, 0x0010, 0x00a0, 0x4b63, 0x7108, 0x1078, 0x48bd,
+	0x7008, 0xa086, 0x0008, 0x00c0, 0x4b39, 0x7000, 0xa005, 0x00c0,
+	0x4b39, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c,
+	0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x2049, 0x4b78, 0xad80, 0x0011, 0x20a0, 0x2099, 0x0031,
+	0x700c, 0xa084, 0x00ff, 0x682a, 0x7007, 0x0008, 0x7007, 0x0002,
+	0x7003, 0x0001, 0x0040, 0x4b97, 0x8000, 0x80ac, 0x53a5, 0x7007,
+	0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4b99, 0x0c7f, 0x2049,
+	0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, 0x2000,
+	0x007c, 0x2091, 0x6000, 0x2091, 0x8000, 0x78cc, 0xa005, 0x0040,
+	0x4bc0, 0x7994, 0x70d0, 0xa106, 0x00c0, 0x4bc0, 0x7804, 0xa005,
+	0x0040, 0x4bc0, 0x7807, 0x0000, 0x0068, 0x4bc0, 0x2091, 0x4080,
+	0x7820, 0x8001, 0x7822, 0x00c0, 0x4c1b, 0x7824, 0x7822, 0x2069,
+	0x5140, 0x6800, 0xa084, 0x0007, 0x0040, 0x4bde, 0xa086, 0x0002,
+	0x0040, 0x4bde, 0x6834, 0xa00d, 0x0040, 0x4bde, 0x2104, 0xa005,
+	0x0040, 0x4bde, 0x8001, 0x200a, 0x0040, 0x4cc3, 0x7848, 0xa005,
+	0x0040, 0x4bec, 0x8001, 0x784a, 0x00c0, 0x4bec, 0x2009, 0x0102,
+	0x6844, 0x200a, 0x1078, 0x21d2, 0x6890, 0xa005, 0x0040, 0x4bf8,
+	0x8001, 0x6892, 0x00c0, 0x4bf8, 0x686f, 0x0000, 0x6873, 0x0001,
+	0x2061, 0x5400, 0x20a9, 0x0100, 0x2009, 0x0002, 0x6034, 0xa005,
+	0x0040, 0x4c0e, 0x8001, 0x6036, 0x00c0, 0x4c0e, 0x6010, 0xa005,
+	0x0040, 0x4c0e, 0x017e, 0x1078, 0x21d2, 0x017f, 0xace0, 0x0010,
+	0x0070, 0x4c14, 0x0078, 0x4bfe, 0x8109, 0x0040, 0x4c1b, 0x20a9,
+	0x0100, 0x0078, 0x4bfe, 0x1078, 0x4c28, 0x1078, 0x4c4d, 0x2009,
+	0x5151, 0x2104, 0x2009, 0x0102, 0x200a, 0x2091, 0x8001, 0x007c,
+	0x7834, 0x8001, 0x7836, 0x00c0, 0x4c4c, 0x7838, 0x7836, 0x2091,
+	0x8000, 0x7844, 0xa005, 0x00c0, 0x4c37, 0x2001, 0x0101, 0x8001,
+	0x7846, 0xa080, 0x7400, 0x2040, 0x2004, 0xa065, 0x0040, 0x4c4c,
+	0x6024, 0xa005, 0x0040, 0x4c48, 0x8001, 0x6026, 0x0040, 0x4c7c,
+	0x6000, 0x2c40, 0x0078, 0x4c3d, 0x007c, 0x7828, 0x8001, 0x782a,
+	0x00c0, 0x4c7b, 0x782c, 0x782a, 0x7830, 0xa005, 0x00c0, 0x4c5a,
+	0x2001, 0x0200, 0x8001, 0x7832, 0x8003, 0x8003, 0x8003, 0x8003,
+	0xa090, 0x5400, 0xa298, 0x0002, 0x2304, 0xa084, 0x0008, 0x0040,
+	0x4c7b, 0xa290, 0x0009, 0x2204, 0xa005, 0x0040, 0x4c73, 0x8001,
+	0x2012, 0x00c0, 0x4c7b, 0x2304, 0xa084, 0xfff7, 0xa085, 0x0080,
+	0x201a, 0x1078, 0x21d2, 0x007c, 0x2069, 0x5140, 0x6800, 0xa005,
+	0x0040, 0x4c86, 0x6848, 0xac06, 0x0040, 0x4cc3, 0x601b, 0x0006,
+	0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+	0x0060, 0x6022, 0x6000, 0x2042, 0x6714, 0x6f82, 0x1078, 0x1973,
+	0x6818, 0xa005, 0x0040, 0x4c9e, 0x8001, 0x681a, 0x6808, 0xa084,
+	0xffef, 0x680a, 0x6810, 0x8001, 0x00d0, 0x4ca8, 0x1078, 0x23eb,
+	0x6812, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x1078, 0x1c70,
+	0x2069, 0x5140, 0x7944, 0xa184, 0x0100, 0x2001, 0x0006, 0x686e,
+	0x00c0, 0x4cbe, 0x6986, 0x2001, 0x0004, 0x686e, 0x1078, 0x21cd,
+	0x2091, 0x8001, 0x007c, 0x2069, 0x0100, 0x2009, 0x5140, 0x2104,
+	0xa084, 0x0007, 0x0040, 0x4d1f, 0xa086, 0x0007, 0x00c0, 0x4cd9,
+	0x0d7e, 0x2009, 0x5152, 0x216c, 0x1078, 0x3a4e, 0x0d7f, 0x0078,
+	0x4d1f, 0x2009, 0x5152, 0x2164, 0x1078, 0x2396, 0x601b, 0x0006,
+	0x6858, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+	0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000, 0x6830, 0xa084,
+	0x0040, 0x0040, 0x4d13, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848,
+	0xa084, 0x0004, 0x0040, 0x4d00, 0x0070, 0x4d00, 0x0078, 0x4cf7,
+	0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040,
+	0x4d0d, 0x0070, 0x4d0d, 0x0078, 0x4d04, 0x20a9, 0x00fa, 0x0070,
+	0x4d13, 0x0078, 0x4d0f, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b,
+	0x0048, 0x2009, 0x515b, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091,
+	0x8001, 0x007c, 0x2079, 0x5100, 0x1078, 0x4d4d, 0x1078, 0x4d31,
+	0x1078, 0x4d3f, 0x7833, 0x0000, 0x7847, 0x0000, 0x784b, 0x0000,
+	0x007c, 0x2019, 0x0003, 0x2011, 0x5146, 0x2204, 0xa086, 0x003c,
+	0x0040, 0x4d3c, 0x2019, 0x0002, 0x7b2a, 0x7b2e, 0x007c, 0x2019,
+	0x0039, 0x2011, 0x5146, 0x2204, 0xa086, 0x003c, 0x0040, 0x4d4a,
+	0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011,
+	0x5146, 0x2204, 0xa086, 0x003c, 0x0040, 0x4d58, 0x2019, 0x2626,
+	0x7b22, 0x7b26, 0x783f, 0x0000, 0x7843, 0x000a, 0x007c, 0x0020,
+	0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, 0x0014,
+	0x0014, 0x0014, 0x0014, 0x0014, 0x0080, 0x000f, 0x0000, 0x0201,
+	0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, 0xa201,
+	0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0x0000, 0x006c, 0x0002,
+	0x0014, 0x98d0, 0x009e, 0x0096, 0xa202, 0x8838, 0x3806, 0x8839,
+	0x20c3, 0x0864, 0x9884, 0x28c1, 0x9cb1, 0xa203, 0x300c, 0x2846,
+	0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0x9865, 0x28f2, 0x9c90,
+	0x9858, 0x300c, 0x28e1, 0x9c90, 0x2802, 0xa206, 0x64c3, 0x282d,
+	0xa207, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7824, 0x68c1,
+	0x7864, 0x883e, 0x9878, 0x8576, 0x8677, 0x206b, 0x28c1, 0x9cb1,
+	0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209, 0x2901, 0x988c,
+	0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xc601,
+	0xa20a, 0x856e, 0x0704, 0x9c90, 0x0014, 0xa204, 0xa300, 0x3009,
+	0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e, 0x87a9, 0x883f,
+	0x08e6, 0x9890, 0xf881, 0x988b, 0xc801, 0x0014, 0xf8c1, 0x0016,
+	0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532, 0xf241,
+	0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208, 0x6043,
+	0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, 0xf041, 0x3008,
+	0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016,
+	0x8000, 0x2847, 0x1011, 0x98c3, 0x8000, 0xa000, 0x2802, 0x1011,
+	0x98c9, 0x9865, 0x283e, 0x1011, 0x98cd, 0xa20b, 0x0017, 0x300c,
+	0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0x98da, 0x0014, 0x26e0,
+	0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806, 0x0210,
+	0x9cb6, 0x0704, 0x0000, 0x006c, 0x0002, 0x984f, 0x0014, 0x009e,
+	0x00a5, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211, 0x9cd5, 0x8772,
+	0x8837, 0x2101, 0x987a, 0x10d2, 0x78e2, 0x9cd8, 0x9859, 0xd984,
+	0xf0e2, 0xf0a1, 0x98d2, 0x0014, 0x8831, 0xd166, 0x8830, 0x800f,
+	0x9401, 0xb520, 0xc802, 0x8820, 0x987a, 0x2301, 0x987a, 0x10d2,
+	0x78e4, 0x9cd8, 0x8821, 0x8820, 0x9859, 0xf123, 0xf142, 0xf101,
+	0x98cb, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c, 0xd99e, 0x6001,
+	0x0014, 0x6845, 0x0214, 0xa21b, 0x9cd5, 0x2001, 0x98ca, 0x8201,
+	0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0x988d, 0x3027, 0x84a8,
+	0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9cc1, 0x692a, 0x6902,
+	0x1834, 0x989d, 0x1a14, 0x8010, 0x8592, 0x8026, 0x84b9, 0x7021,
+	0x0014, 0xa300, 0x69e1, 0x9caa, 0x694c, 0xa213, 0x9cba, 0x1462,
+	0xa213, 0x8000, 0x16e1, 0x98b4, 0x8023, 0x16e1, 0x8001, 0x10f1,
+	0x0016, 0x6968, 0xa214, 0x9cba, 0x8004, 0x16e1, 0x0101, 0x300a,
+	0x8827, 0x0014, 0x9cba, 0x0014, 0x61c2, 0x8002, 0x14e1, 0x0016,
+	0xa217, 0x9cc1, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6,
+	0x882c, 0x0016, 0xa212, 0x9cd5, 0x10d2, 0x70e4, 0x0004, 0x8007,
+	0x9424, 0xcc1a, 0x9cd8, 0x98ca, 0x8827, 0x300a, 0x0013, 0x8000,
+	0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e,
+	0x0016, 0xa21c, 0x1035, 0x9891, 0xa210, 0xa000, 0x8010, 0x8592,
+	0x853b, 0xd044, 0x8022, 0x3807, 0x84bb, 0x98ef, 0x8021, 0x3807,
+	0x84b9, 0x300c, 0x817e, 0x872b, 0x8772, 0x9891, 0x0000, 0x0020,
+	0x002b, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0014, 0x0014, 0x9849, 0x0014, 0x0014, 0x98e5,
+	0x98d0, 0x0014, 0x0014, 0x0014, 0x0080, 0x013f, 0x0000, 0x0201,
+	0x0604, 0x0c08, 0x2120, 0x4022, 0xf880, 0x0018, 0x300b, 0xa201,
+	0x0014, 0xa200, 0x0014, 0xa200, 0x0214, 0xa202, 0x8838, 0x3806,
+	0x8839, 0x20c3, 0x0864, 0xa82e, 0x28c1, 0x9cb1, 0xa203, 0x300c,
+	0x2846, 0x8161, 0x846a, 0x8300, 0x1856, 0x883a, 0xa804, 0x28f2,
+	0x9c90, 0xa8f4, 0x300c, 0x28e1, 0x9c90, 0x2802, 0xa206, 0x64c3,
+	0x282d, 0xa207, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b, 0x7824,
+	0x68c1, 0x7864, 0x883e, 0xa802, 0x8576, 0x8677, 0x206b, 0x28c1,
+	0x9cb1, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e5, 0xa209, 0x2901,
+	0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c, 0x1fe2,
+	0xc601, 0xa20a, 0x856e, 0x0704, 0x9c90, 0x0014, 0xa204, 0xa300,
+	0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e, 0x87a9,
+	0x883f, 0x08e6, 0xa8f3, 0xf881, 0xa8ec, 0xc801, 0x0014, 0xf8c1,
+	0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014, 0x8532,
+	0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014, 0xa208,
+	0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a, 0xf041,
+	0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5, 0x8822,
+	0x0016, 0x8000, 0x2847, 0x1011, 0xa8fc, 0x8000, 0xa000, 0x2802,
+	0x1011, 0xa8fd, 0xa898, 0x283e, 0x1011, 0xa8fd, 0xa20b, 0x0017,
+	0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0xa801, 0x0014,
+	0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d, 0x3806,
+	0x0210, 0x9cb6, 0x0704, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211,
+	0x9d6b, 0x8772, 0x8837, 0x2101, 0xa821, 0x10d2, 0x78e2, 0x9d6e,
+	0xa8fc, 0xd984, 0xf0e2, 0xf0a1, 0xa871, 0x0014, 0x8831, 0xd166,
+	0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, 0xa80f, 0x2301,
+	0xa80d, 0x10d2, 0x78e4, 0x9d6e, 0x8821, 0x8820, 0xa8e6, 0xf123,
+	0xf142, 0xf101, 0xa854, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c,
+	0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, 0x9d6b, 0x2001,
+	0xa845, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0xa801,
+	0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9d57,
+	0x692a, 0x6902, 0x1834, 0xa805, 0x1a14, 0x8010, 0x8592, 0x8026,
+	0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9d40, 0x694c, 0xa213,
+	0x9d50, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa80a, 0x8023, 0x16e1,
+	0x8001, 0x10f1, 0x0016, 0x6968, 0xa214, 0x9d50, 0x8004, 0x16e1,
+	0x0101, 0x300a, 0x8827, 0x0014, 0x9d50, 0x0014, 0x61c2, 0x8002,
+	0x14e1, 0x0016, 0xa217, 0x9d57, 0x0014, 0xa300, 0x8181, 0x842a,
+	0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212, 0x9d6b, 0x10d2, 0x70e4,
+	0x0004, 0x8007, 0x9424, 0xcc1a, 0x9d6e, 0xa8f8, 0x8827, 0x300a,
+	0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d,
+	0x0014, 0x878e, 0x0016, 0xa21c, 0x1035, 0xa8af, 0xa210, 0x3807,
+	0x300c, 0x817e, 0x872b, 0x8772, 0xa8a8, 0x0000, 0xdf21
+};
+static unsigned short   risc_code_length01 = 0x4057;
+
diff --git a/drivers/scsi/ql12160_fw.h b/drivers/scsi/ql12160_fw.h
new file mode 100644
index 0000000..9db6a20
--- /dev/null
+++ b/drivers/scsi/ql12160_fw.h
@@ -0,0 +1,1781 @@
+/*****************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP12160 device driver for Linux 2.2.x and 2.4.x
+ * Copyright (C) 2002 Qlogic Corporation (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *****************************************************************************/
+
+/************************************************************************
+ * 	           --- ISP12160A Initiator Firmware ---                 *
+ *			      32 LUN Support                            *
+ ************************************************************************/
+
+/*
+ *	Firmware Version 10.04.32 (12:03 May 09, 2001)
+ */
+
+#ifdef UNIQUE_FW_NAME
+static unsigned char fw12160i_version_str[] = {10,4,32};
+#else
+static unsigned char firmware_version[] = {10,4,32};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw12160i_VERSION_STRING "10.04.32"
+#else
+#define FW_VERSION_STRING "10.04.32"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+static unsigned short fw12160i_addr01 = 0x1000;
+#else
+static unsigned short risc_code_addr01 = 0x1000;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+static unsigned short fw12160i_code01[] = {
+#else
+static unsigned short risc_code01[] = {
+#endif
+	0x0804, 0x1041, 0x0000, 0x35e6, 0x0000, 0x2043, 0x4f50, 0x5952,
+	0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
+	0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
+	0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350,
+	0x3132, 0x3136, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056,
+	0x6572, 0x7369, 0x6f6e, 0x2031, 0x302e, 0x3034, 0x2020, 0x2043,
+	0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050,
+	0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020,
+	0x2400, 0x20c9, 0x8fff, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2001,
+	0x01ff, 0x2004, 0xd0fc, 0x1120, 0x2071, 0x0100, 0x70a0, 0x70a2,
+	0x20c1, 0x0020, 0x2089, 0x1221, 0x2071, 0x0010, 0x70c3, 0x0004,
+	0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x000a,
+	0x2001, 0x04fd, 0x2004, 0x70d6, 0x2009, 0xfeff, 0x2130, 0x2128,
+	0xa1a2, 0x4600, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424,
+	0xa192, 0x9000, 0x2009, 0x0000, 0x2001, 0x0032, 0x080c, 0x1de8,
+	0x2218, 0x2079, 0x4600, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9,
+	0x0040, 0x42a4, 0x8109, 0x1dd8, 0x2009, 0xff00, 0x3400, 0xa102,
+	0x0218, 0x0110, 0x20a8, 0x42a4, 0x781b, 0x0064, 0x7814, 0xc0cd,
+	0xc0d5, 0x7816, 0x2071, 0x0200, 0x00d6, 0x2069, 0x4640, 0x080c,
+	0x459a, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1130, 0x2069, 0x4680,
+	0x2071, 0x0100, 0x080c, 0x459a, 0x7814, 0xc0d4, 0x7816, 0x00de,
+	0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800, 0xc08d, 0x7802,
+	0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002, 0x7827, 0x0002,
+	0x2009, 0x0002, 0x2069, 0x4640, 0x681b, 0x0003, 0x6823, 0x0007,
+	0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028, 0x6837, 0x0006,
+	0x6833, 0x0008, 0x683b, 0x0000, 0x8109, 0x0500, 0x68cf, 0x000a,
+	0x68bf, 0x46c0, 0x2079, 0x4600, 0x68d3, 0x762d, 0x68c3, 0x4bc0,
+	0x68c7, 0x4ac0, 0x68cb, 0x8bc0, 0x68a7, 0x8e44, 0x68ab, 0x8e49,
+	0x68af, 0x8e44, 0x68b3, 0x8e44, 0x68a3, 0x0001, 0x2001, 0x01ff,
+	0x2004, 0xd0fc, 0x11c8, 0x2069, 0x4680, 0x0870, 0x68cf, 0x000a,
+	0x68bf, 0x48c0, 0x68d3, 0x7839, 0x68c3, 0x6bc0, 0x68c7, 0x4b40,
+	0x68cb, 0x8cd0, 0x68a7, 0x8e49, 0x68ab, 0x8e4e, 0x68af, 0x8e49,
+	0x68b3, 0x8e49, 0x68a3, 0x0001, 0x00e6, 0x2069, 0x4ac0, 0x2071,
+	0x0200, 0x70ec, 0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120,
+	0x2019, 0x180c, 0x2021, 0x000c, 0x080c, 0x1d58, 0x2001, 0x01ff,
+	0x2004, 0xd0fc, 0x1188, 0x2069, 0x4b40, 0x2071, 0x0100, 0x70ec,
+	0xd0e4, 0x2019, 0x1809, 0x2021, 0x0009, 0x1120, 0x2019, 0x180c,
+	0x2021, 0x000c, 0x080c, 0x1d58, 0x00ee, 0x2011, 0x0002, 0x2069,
+	0x4bc0, 0x2009, 0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b,
+	0x0040, 0x7bc8, 0xa386, 0xfeff, 0x1128, 0x6817, 0x0100, 0x681f,
+	0x0064, 0x0020, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010,
+	0x1f04, 0x1135, 0x8109, 0x1d38, 0x2001, 0x01ff, 0x2004, 0xd0fc,
+	0x1128, 0x8211, 0x0118, 0x2069, 0x6bc0, 0x08d8, 0x080c, 0x22cf,
+	0x080c, 0x4015, 0x080c, 0x1b6d, 0x080c, 0x4553, 0x2091, 0x2200,
+	0x2079, 0x4600, 0x2071, 0x0050, 0x2091, 0x2400, 0x2079, 0x4600,
+	0x2071, 0x0020, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x4640,
+	0x2091, 0x2800, 0x2079, 0x0100, 0x2071, 0x4680, 0x2091, 0x2000,
+	0x2079, 0x4600, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090,
+	0x2071, 0x0010, 0x70c3, 0x0000, 0x1004, 0x118c, 0x70c0, 0xa086,
+	0x0002, 0x1110, 0x080c, 0x13ba, 0x2039, 0x0000, 0x080c, 0x12ab,
+	0x78ac, 0xa005, 0x1180, 0x0e04, 0x119a, 0x786c, 0xa065, 0x0110,
+	0x080c, 0x207a, 0x080c, 0x1e09, 0x0e04, 0x11af, 0x786c, 0xa065,
+	0x0110, 0x080c, 0x207a, 0x0e04, 0x11af, 0x2009, 0x4647, 0x2011,
+	0x4687, 0x2104, 0x220c, 0xa105, 0x0110, 0x080c, 0x1c7c, 0x2071,
+	0x4640, 0x70a0, 0xa005, 0x01e8, 0x744c, 0xa485, 0x0000, 0x01c8,
+	0x2079, 0x0200, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d, 0x2190,
+	0x080c, 0x2720, 0x2091, 0x8000, 0x2091, 0x303d, 0x0e04, 0x11d1,
+	0x2079, 0x4600, 0x786c, 0xa065, 0x0120, 0x2071, 0x0010, 0x080c,
+	0x207a, 0x1d04, 0x11d9, 0x2079, 0x4600, 0x2071, 0x0010, 0x080c,
+	0x4370, 0x2071, 0x4680, 0x70a0, 0xa005, 0x0188, 0x704c, 0xa025,
+	0x0170, 0x2079, 0x0100, 0x2091, 0x8000, 0x72d0, 0xa28c, 0x303d,
+	0x2190, 0x080c, 0x2720, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079,
+	0x4600, 0x2071, 0x0010, 0x0e04, 0x11fa, 0x786c, 0xa065, 0x0110,
+	0x080c, 0x207a, 0x1d04, 0x118e, 0x080c, 0x4370, 0x0804, 0x118e,
+	0x3c00, 0xa084, 0x0007, 0x0002, 0x120c, 0x120c, 0x120e, 0x120e,
+	0x1213, 0x1213, 0x1218, 0x1218, 0x080c, 0x254c, 0x2091, 0x2400,
+	0x080c, 0x40ad, 0x0005, 0x2091, 0x2200, 0x080c, 0x40ad, 0x0005,
+	0x2091, 0x2200, 0x080c, 0x40ad, 0x2091, 0x2400, 0x080c, 0x40ad,
+	0x0005, 0x1241, 0x1241, 0x1242, 0x1242, 0x124d, 0x124d, 0x124d,
+	0x124d, 0x1256, 0x1256, 0x1261, 0x1261, 0x124d, 0x124d, 0x124d,
+	0x124d, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270,
+	0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270, 0x1270,
+	0x1270, 0x0cf8, 0x0006, 0x0106, 0x0126, 0x2091, 0x2800, 0x080c,
+	0x2569, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106, 0x0126,
+	0x080c, 0x1200, 0x012e, 0x010e, 0x000e, 0x000d, 0x0006, 0x0106,
+	0x0126, 0x2091, 0x2600, 0x080c, 0x2569, 0x012e, 0x010e, 0x000e,
+	0x000d, 0x0006, 0x0106, 0x0126, 0x2091, 0x2600, 0x080c, 0x2569,
+	0x2091, 0x2800, 0x080c, 0x2569, 0x012e, 0x010e, 0x000e, 0x000d,
+	0x0006, 0x0106, 0x0126, 0x00d6, 0x00e6, 0x00f6, 0x2079, 0x4600,
+	0x2071, 0x0200, 0x2069, 0x4640, 0x3d00, 0xd08c, 0x0130, 0x70ec,
+	0xa084, 0x1c00, 0x78e2, 0x080c, 0x459a, 0x3d00, 0xd084, 0x0150,
+	0x2069, 0x4680, 0x2071, 0x0100, 0x70ec, 0xa084, 0x1c00, 0x78e6,
+	0x080c, 0x459a, 0x080c, 0x24fd, 0x00fe, 0x00ee, 0x00de, 0x012e,
+	0x010e, 0x000e, 0x000d, 0x7008, 0x800b, 0x1240, 0x7007, 0x0002,
+	0xa08c, 0x01e0, 0x1120, 0xd09c, 0x0108, 0x0887, 0x0897, 0x70c3,
+	0x4002, 0x0804, 0x13bd, 0x0e04, 0x131e, 0x2061, 0x0000, 0x6018,
+	0xd084, 0x1904, 0x131e, 0x7828, 0xa005, 0x1120, 0x0004, 0x131f,
+	0x0804, 0x131e, 0xd0fc, 0x0130, 0x0006, 0x080c, 0x1b0a, 0x000e,
+	0x0150, 0x0028, 0x0006, 0x080c, 0x1aff, 0x000e, 0x0120, 0x2001,
+	0x4007, 0x0804, 0x13bc, 0x7910, 0xd0fc, 0x1128, 0x2061, 0x4640,
+	0xc19c, 0xc7fc, 0x0020, 0x2061, 0x4680, 0xc19d, 0xc7fd, 0x6060,
+	0xa005, 0x1904, 0x131e, 0x7912, 0x607e, 0x7828, 0xc0fc, 0xa086,
+	0x0018, 0x1120, 0x00c6, 0x080c, 0x1916, 0x00ce, 0x782b, 0x0000,
+	0x6078, 0xa065, 0x01e0, 0x00c6, 0x609c, 0x080c, 0x1bd4, 0x00ce,
+	0x609f, 0x0000, 0x080c, 0x1a41, 0x2009, 0x0018, 0x6087, 0x0103,
+	0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812,
+	0x080c, 0x1b15, 0x000e, 0x7812, 0x1198, 0x080c, 0x1b60, 0x7810,
+	0xd09c, 0x1118, 0x2061, 0x4640, 0x0020, 0x2061, 0x4680, 0xc09c,
+	0x7812, 0x607b, 0x0000, 0x60d0, 0xd0c4, 0x0130, 0xc0c4, 0x60d2,
+	0x2001, 0x4005, 0x0804, 0x13bc, 0x0804, 0x13ba, 0x0005, 0xa006,
+	0x70c2, 0x70c6, 0x70ca, 0x70ce, 0x70da, 0x70c0, 0xa03d, 0xa08a,
+	0x0040, 0x1a04, 0x136c, 0x0002, 0x13ba, 0x1408, 0x13d6, 0x143c,
+	0x1470, 0x1470, 0x13ce, 0x1a59, 0x147a, 0x13c8, 0x13da, 0x13db,
+	0x13dc, 0x13dd, 0x1a5d, 0x13c8, 0x1487, 0x14db, 0x1931, 0x1a53,
+	0x13de, 0x17ba, 0x17f0, 0x1822, 0x1868, 0x1777, 0x1784, 0x1797,
+	0x17a9, 0x15b0, 0x13c8, 0x150d, 0x1518, 0x1526, 0x1534, 0x154b,
+	0x1559, 0x155c, 0x156a, 0x1578, 0x1582, 0x1596, 0x15a2, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x15bd, 0x15ce, 0x15e8, 0x161c, 0x1645,
+	0x1657, 0x165a, 0x1685, 0x16be, 0x16d0, 0x1745, 0x1755, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x1767, 0x2100, 0xa08a, 0x0040, 0x1a04,
+	0x13c8, 0x0002, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x1a7f,
+	0x1a85, 0x13c8, 0x13c8, 0x13c8, 0x1a89, 0x1ac9, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x1403, 0x146b, 0x1482, 0x14d6, 0x192c, 0x13c8,
+	0x13c8, 0x18fb, 0x13c8, 0x1acd, 0x1a71, 0x1a7b, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8, 0x13c8,
+	0x13c8, 0x13c8, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0028, 0x73ce,
+	0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0e04, 0x13bd, 0x2061,
+	0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x0005,
+	0x70c3, 0x4001, 0x0c90, 0x70c3, 0x4006, 0x0c78, 0x2099, 0x0041,
+	0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0c20, 0x70c4, 0x70c3,
+	0x0004, 0x0807, 0x08f8, 0x08f0, 0x08e8, 0x08e0, 0x2091, 0x8000,
+	0x70c3, 0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020,
+	0x70d3, 0x000a, 0x2001, 0x0004, 0x70d6, 0x2079, 0x0000, 0x781b,
+	0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051,
+	0x0445, 0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0804, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0018,
+	0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0,
+	0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e,
+	0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0904, 0x13ba, 0xa182,
+	0x0040, 0x1210, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x7007,
+	0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0de8, 0x7007, 0x0002,
+	0xa084, 0x01e0, 0x0120, 0x70c3, 0x4002, 0x0804, 0x13bd, 0x24a8,
+	0x53a5, 0x0c10, 0x0804, 0x13ba, 0x2029, 0x0000, 0x2520, 0x71d0,
+	0x72c8, 0x73cc, 0x70c4, 0x2098, 0x20a1, 0x0030, 0x7003, 0x0000,
+	0x7007, 0x0006, 0x731a, 0x721e, 0x7422, 0x7526, 0x2021, 0x0040,
+	0x7007, 0x0006, 0x81ff, 0x0904, 0x13ba, 0xa182, 0x0040, 0x1210,
+	0x2120, 0xa006, 0x2008, 0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007,
+	0x0001, 0x7008, 0xd0fc, 0x0de8, 0xa084, 0x01e0, 0x0d48, 0x70c3,
+	0x4002, 0x0804, 0x13bd, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0878,
+	0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x1108, 0x200a, 0x72ca,
+	0x0804, 0x13b9, 0x70c7, 0x000a, 0x70cb, 0x0004, 0x70cf, 0x0020,
+	0x0804, 0x13ba, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0018, 0x2029,
+	0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca,
+	0x73ce, 0x74d2, 0xa005, 0x05e8, 0xa40a, 0x0108, 0x1240, 0x8001,
+	0x7872, 0xa084, 0xfc00, 0x0138, 0x78ac, 0xc085, 0x78ae, 0x2001,
+	0x4005, 0x0804, 0x13bc, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76,
+	0xa48c, 0xff00, 0x0170, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c,
+	0x810f, 0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000,
+	0x0050, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1,
+	0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605,
+	0x0118, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc, 0x78ae,
+	0x0018, 0x78ac, 0xc085, 0x78ae, 0x0804, 0x13ba, 0x75d8, 0x76dc,
+	0x75da, 0x76de, 0x0018, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8,
+	0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0500,
+	0xa40a, 0x0110, 0x1a04, 0x13bc, 0x8001, 0x7892, 0xa084, 0xfc00,
+	0x0138, 0x78ac, 0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0804, 0x13bc,
+	0x7a9a, 0x7b9e, 0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0118, 0x7a10,
+	0xc2c5, 0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0018,
+	0x78ac, 0xc0c5, 0x78ae, 0x0804, 0x13ba, 0x2009, 0x0000, 0x786c,
+	0xa065, 0x0118, 0x8108, 0x6000, 0x0cd8, 0x7ac4, 0x0804, 0x13b8,
+	0x2009, 0x4648, 0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904,
+	0x13b9, 0x2011, 0x4688, 0x2214, 0x0804, 0x13b8, 0x2009, 0x4649,
+	0x210c, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011,
+	0x4689, 0x2214, 0x0804, 0x13b8, 0x2061, 0x4640, 0x6128, 0x622c,
+	0x8214, 0x8214, 0x8214, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1148,
+	0x2061, 0x4680, 0x6328, 0x73da, 0x632c, 0x831c, 0x831c, 0x831c,
+	0x73de, 0x0804, 0x13b8, 0x2009, 0x464c, 0x210c, 0x2001, 0x01ff,
+	0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, 0x468c, 0x2214, 0x0804,
+	0x13b8, 0x7918, 0x0804, 0x13b9, 0x2009, 0x0202, 0x210c, 0x2001,
+	0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x2011, 0x0102, 0x2214,
+	0x0804, 0x13b8, 0x2009, 0x464d, 0x210c, 0x2001, 0x01ff, 0x2004,
+	0xd0fc, 0x1904, 0x13b9, 0x2011, 0x468d, 0x2214, 0x0804, 0x13b8,
+	0x7920, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9, 0x7a24,
+	0x0804, 0x13b8, 0x2011, 0x4b40, 0x71c4, 0xd1fc, 0x1110, 0x2011,
+	0x4ac0, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268,
+	0x6a00, 0x6b08, 0x6c1c, 0x74da, 0x0804, 0x13b7, 0x77c4, 0x080c,
+	0x1b7b, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708,
+	0x0804, 0x13b7, 0x2061, 0x4640, 0x6118, 0x2001, 0x01ff, 0x2004,
+	0xd0fc, 0x1904, 0x13b9, 0x2061, 0x4680, 0x6218, 0x0804, 0x13b8,
+	0x77c4, 0x080c, 0x1b7b, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10,
+	0x77da, 0x2091, 0x8001, 0x0804, 0x13b7, 0x71c4, 0x2110, 0xa294,
+	0x000f, 0xa282, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x238b, 0xa384,
+	0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x71c4, 0x2100,
+	0xc0bc, 0xa082, 0x0010, 0x1a04, 0x13b3, 0xd1bc, 0x1120, 0x2011,
+	0x4648, 0x2204, 0x0020, 0x2011, 0x4688, 0x2204, 0xc0bd, 0x0006,
+	0x2100, 0xc0bc, 0x2012, 0x080c, 0x2331, 0x001e, 0x0804, 0x13b9,
+	0x71c4, 0x2021, 0x4649, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0030,
+	0x71c8, 0x2021, 0x4689, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1614,
+	0x20a9, 0x0008, 0x2204, 0xa106, 0x0138, 0x8210, 0x1f04, 0x15fa,
+	0x71c4, 0x72c8, 0x0804, 0x13b2, 0xa292, 0x1614, 0x0026, 0x2122,
+	0x001e, 0x080c, 0x2343, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1110,
+	0xd3fc, 0x09f0, 0x0804, 0x13ba, 0x03e8, 0x00fa, 0x01f4, 0x02ee,
+	0x0004, 0x0001, 0x0002, 0x0003, 0x2061, 0x4640, 0x6128, 0x622c,
+	0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003,
+	0x8003, 0x602e, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x11a0, 0x0026,
+	0x0016, 0x2061, 0x4680, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214,
+	0x70d8, 0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da,
+	0x72de, 0x001e, 0x002e, 0x0804, 0x13b8, 0x2061, 0x4640, 0x6130,
+	0x70c4, 0x6032, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9,
+	0x2061, 0x4680, 0x6230, 0x70c8, 0x6032, 0x0804, 0x13b8, 0x7918,
+	0x0804, 0x13b9, 0x71c4, 0xa184, 0xf0cf, 0x0148, 0x2001, 0x01ff,
+	0x2004, 0xd0fc, 0x1904, 0x13b3, 0x72c8, 0x0804, 0x13b2, 0x0006,
+	0x2019, 0x0000, 0x080c, 0x237f, 0x2001, 0x01ff, 0x2004, 0xd0fc,
+	0x0118, 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa184, 0xf0cf, 0x0128,
+	0x0006, 0x2110, 0x71c4, 0x0804, 0x13b2, 0x0006, 0xc3fd, 0x080c,
+	0x237f, 0x002e, 0x001e, 0x0804, 0x13b8, 0x71c4, 0xa182, 0x0010,
+	0x0248, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b3, 0x72c8,
+	0x0804, 0x13b2, 0x2011, 0x464d, 0x2204, 0x0006, 0x8104, 0x1208,
+	0x8108, 0x2112, 0x2019, 0x0000, 0x080c, 0x236c, 0x2001, 0x01ff,
+	0x2004, 0xd0fc, 0x0118, 0x001e, 0x0804, 0x13b9, 0x71c8, 0xa182,
+	0x0010, 0x0228, 0x0006, 0x2110, 0x71c4, 0x0804, 0x13b2, 0x2011,
+	0x468d, 0x2204, 0x0006, 0x8104, 0x1208, 0x8108, 0x2112, 0xc3fd,
+	0x080c, 0x236c, 0x002e, 0x001e, 0x0804, 0x13b8, 0x71c4, 0x72c8,
+	0xa184, 0xfffd, 0x1904, 0x13b2, 0xa284, 0xfffd, 0x1904, 0x13b2,
+	0x2100, 0x7920, 0x7822, 0x2200, 0x7a24, 0x7826, 0x0804, 0x13b8,
+	0x2011, 0x4b40, 0x71c4, 0xd1fc, 0x1110, 0x2011, 0x4ac0, 0x8107,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268, 0x72c8, 0x73cc,
+	0x74d8, 0x71c6, 0x6800, 0x70ca, 0x73ce, 0x74da, 0x2091, 0x8000,
+	0x6a02, 0xd2ac, 0x1118, 0x2021, 0x0000, 0x0090, 0xa484, 0x00ff,
+	0xa082, 0x0002, 0x1a04, 0x1741, 0x843f, 0xa7bc, 0x00ff, 0x0140,
+	0xa786, 0x0002, 0x1904, 0x1741, 0xa484, 0x00ff, 0x0904, 0x1741,
+	0x2061, 0x0200, 0xd1fc, 0x0110, 0x2061, 0x0100, 0x2029, 0x0009,
+	0x2031, 0x0062, 0x843f, 0xa7bc, 0x00ff, 0x0130, 0x8307, 0xa084,
+	0x00ff, 0x1110, 0xa73d, 0x1138, 0x2041, 0x0019, 0xa384, 0x00ff,
+	0xa082, 0x001a, 0x0210, 0xa4a4, 0x00ff, 0x8307, 0xa084, 0x00ff,
+	0x0188, 0xa842, 0x02f0, 0xa086, 0x0010, 0x1120, 0xa39c, 0x00ff,
+	0xa39d, 0x0f00, 0xa3bc, 0x00ff, 0x2500, 0xa702, 0x0290, 0x2600,
+	0xa702, 0x1278, 0x2039, 0x003a, 0x6804, 0xa705, 0x6806, 0x6b0a,
+	0x6b0c, 0x73ce, 0x681c, 0x70da, 0x6c1e, 0x2091, 0x8001, 0x0804,
+	0x13ba, 0x2091, 0x8001, 0x0804, 0x13b4, 0x77c4, 0x080c, 0x1b7b,
+	0x2091, 0x8000, 0x6a14, 0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816,
+	0x70cc, 0x681e, 0x2708, 0x0804, 0x13b7, 0x70c4, 0x2061, 0x4640,
+	0x6118, 0x601a, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904, 0x13b9,
+	0x70c8, 0x2061, 0x4680, 0x6218, 0x601a, 0x0804, 0x13b8, 0x71c4,
+	0x72c8, 0x73cc, 0xa182, 0x0010, 0x1a04, 0x13b3, 0x080c, 0x23af,
+	0xa384, 0x4000, 0x0110, 0xa295, 0x0020, 0x0804, 0x13b7, 0x77c4,
+	0x080c, 0x1b7b, 0x2091, 0x8000, 0x6a08, 0xc28d, 0x6a0a, 0x2091,
+	0x8001, 0x2708, 0x0804, 0x13b8, 0x77c4, 0x080c, 0x1b7b, 0x2091,
+	0x8000, 0x6a08, 0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0110,
+	0x080c, 0x22ae, 0x2091, 0x8001, 0x2708, 0x0804, 0x13b8, 0x77c4,
+	0x080c, 0x1b7b, 0x2091, 0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804,
+	0xa005, 0x0110, 0x080c, 0x22ae, 0x2091, 0x8001, 0x2708, 0x0804,
+	0x13b8, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020,
+	0x2091, 0x8000, 0x080c, 0x1b93, 0x2091, 0x8001, 0x2708, 0x6a08,
+	0x0804, 0x13b8, 0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1b0a, 0x0138,
+	0x0804, 0x13bc, 0x080c, 0x1aff, 0x0110, 0x0804, 0x13bc, 0x73c8,
+	0x72cc, 0x77c6, 0x73ca, 0x72ce, 0x080c, 0x1c0b, 0x11e8, 0x6818,
+	0xa005, 0x01a0, 0x2708, 0x0076, 0x080c, 0x23ce, 0x007e, 0x1170,
+	0x2001, 0x0015, 0xd7fc, 0x1118, 0x2061, 0x4640, 0x0018, 0xc0fd,
+	0x2061, 0x4680, 0x782a, 0x2091, 0x8001, 0x0005, 0x2091, 0x8001,
+	0x2001, 0x4005, 0x0804, 0x13bc, 0x2091, 0x8001, 0x0804, 0x13ba,
+	0x77c4, 0xd7fc, 0x0128, 0x080c, 0x1b0a, 0x0138, 0x0804, 0x13bc,
+	0x080c, 0x1aff, 0x0110, 0x0804, 0x13bc, 0x77c6, 0x2041, 0x0021,
+	0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x080c, 0x1b93,
+	0x2009, 0x0016, 0xd7fc, 0x1118, 0x2061, 0x4640, 0x0018, 0x2061,
+	0x4680, 0xc1fd, 0x6063, 0x0003, 0x607b, 0x0000, 0x6772, 0x607f,
+	0x000f, 0x792a, 0x61d0, 0xc1c4, 0x61d2, 0x080c, 0x22ae, 0x2091,
+	0x8001, 0x0005, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xd7fc, 0x0128,
+	0x080c, 0x1b0a, 0x0138, 0x0804, 0x13bc, 0x080c, 0x1aff, 0x0110,
+	0x0804, 0x13bc, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2009, 0x0017,
+	0xd7fc, 0x1118, 0x2061, 0x4640, 0x0018, 0x2061, 0x4680, 0xc1fd,
+	0x607b, 0x0000, 0x6063, 0x0002, 0x6772, 0x607f, 0x000f, 0x792a,
+	0x61d0, 0xc1c4, 0x61d2, 0x080c, 0x22ae, 0x2091, 0x8001, 0x2041,
+	0x0021, 0x2049, 0x0005, 0x2051, 0x0030, 0x2091, 0x8000, 0x70c8,
+	0xa005, 0x0118, 0x60d0, 0xc0fd, 0x60d2, 0x080c, 0x1b93, 0x70c8,
+	0x6836, 0x8738, 0xa784, 0x001f, 0x1dc0, 0x2091, 0x8001, 0x0005,
+	0x2019, 0x0000, 0x72c8, 0xd284, 0x0128, 0x080c, 0x1b0a, 0x0138,
+	0x0804, 0x13bc, 0x080c, 0x1aff, 0x0110, 0x0804, 0x13bc, 0x72c8,
+	0x72ca, 0x78ac, 0xa084, 0x0003, 0x1508, 0x2039, 0x0000, 0xd284,
+	0x0108, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008,
+	0x080c, 0x1b7b, 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, 0x690a,
+	0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x1d90, 0xa7bc, 0xff00,
+	0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d50, 0x2091, 0x8000,
+	0x72c8, 0x2069, 0x0100, 0xd284, 0x1110, 0x2069, 0x0200, 0x6808,
+	0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b, 0x0004,
+	0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x18b2, 0x684b,
+	0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04, 0x18bb,
+	0x20a9, 0x00fa, 0x1f04, 0x18c2, 0x2079, 0x4600, 0x2009, 0x0018,
+	0x72c8, 0xd284, 0x1118, 0x2061, 0x4640, 0x0018, 0x2061, 0x4680,
+	0xc1fd, 0x607b, 0x0000, 0x792a, 0x6063, 0x0001, 0x607f, 0x000f,
+	0x60a3, 0x0000, 0x60a4, 0x60ae, 0x60b2, 0x60d0, 0xd0b4, 0x0160,
+	0xc0b4, 0x60d2, 0x00c6, 0x60b4, 0xa065, 0x6008, 0xc0d4, 0x600a,
+	0x6018, 0x8001, 0x601a, 0x00ce, 0x60d0, 0xa084, 0x7eff, 0x60d2,
+	0x78ac, 0xc08d, 0x78ae, 0x83ff, 0x0108, 0x0005, 0x681b, 0x0054,
+	0x2091, 0x8001, 0x0005, 0x73cc, 0x080c, 0x186a, 0x69ec, 0x6a48,
+	0xa185, 0x1800, 0x684a, 0xa185, 0x0040, 0x68ee, 0x73cc, 0x2021,
+	0x0004, 0x20a9, 0x09ff, 0x1f04, 0x190b, 0x8421, 0x1dd0, 0x8319,
+	0x1db0, 0x69ee, 0x6a4a, 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118,
+	0x2069, 0x4640, 0x0010, 0x2069, 0x4680, 0x71c4, 0x71c6, 0x6916,
+	0x81ff, 0x1110, 0x68a3, 0x0001, 0x78ac, 0xc08c, 0x78ae, 0xd084,
+	0x1110, 0x080c, 0x1c5b, 0x0005, 0x75d8, 0x74dc, 0x75da, 0x74de,
+	0x0010, 0xa02e, 0x2520, 0x71c4, 0x73c8, 0x72cc, 0x71c6, 0x73ca,
+	0x72ce, 0x2079, 0x4600, 0x7dde, 0x7cda, 0x7bd6, 0x7ad2, 0x080c,
+	0x1b58, 0x0904, 0x1a3d, 0x20a9, 0x0005, 0x20a1, 0x4614, 0x2091,
+	0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0040, 0x080c, 0x1d24,
+	0x0120, 0x080c, 0x1b60, 0x0804, 0x1a3d, 0x6004, 0xa08c, 0x00ff,
+	0xa18e, 0x0009, 0x1120, 0x0006, 0x080c, 0x205f, 0x000e, 0xa084,
+	0xff00, 0x8007, 0x8009, 0x0904, 0x19e1, 0x00c6, 0x2c68, 0x080c,
+	0x1b58, 0x05a8, 0x2c00, 0x689e, 0x8109, 0x1dc0, 0x609f, 0x0000,
+	0x00ce, 0x00c6, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040,
+	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda,
+	0x7bd6, 0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0904, 0x19e0, 0x2009,
+	0x0040, 0x080c, 0x1d24, 0x15a0, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0002, 0x1168, 0x6004, 0xa084, 0x00ff, 0xa086, 0x000a, 0x1120,
+	0x0016, 0x080c, 0x205c, 0x001e, 0x2d00, 0x6002, 0x0898, 0x00ce,
+	0x00c6, 0x609c, 0x080c, 0x1bd4, 0x00ce, 0x609f, 0x0000, 0x080c,
+	0x1a41, 0x2009, 0x0018, 0x6008, 0xc0cd, 0x600a, 0x6004, 0x6086,
+	0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812,
+	0x080c, 0x1b15, 0x000e, 0x7812, 0x080c, 0x1b60, 0x0804, 0x1a3d,
+	0x00ce, 0x00c6, 0x609c, 0x080c, 0x1bd4, 0x00ce, 0x609f, 0x0000,
+	0x080c, 0x1a41, 0x2009, 0x0018, 0x6087, 0x0103, 0x601b, 0x0003,
+	0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff, 0x0110, 0xc0c5, 0x7812,
+	0x080c, 0x1b15, 0x000e, 0x7812, 0x080c, 0x1b60, 0x0804, 0x1a3d,
+	0x00ce, 0x6114, 0xd1fc, 0x0120, 0x080c, 0x1b0a, 0x01f0, 0x0018,
+	0x080c, 0x1aff, 0x01d0, 0x080c, 0x1a41, 0x2009, 0x0018, 0x6087,
+	0x0103, 0x601b, 0x0021, 0x7810, 0x0006, 0x84ff, 0x1110, 0x85ff,
+	0x0110, 0xc0c5, 0x7812, 0x080c, 0x1b15, 0x000e, 0x7812, 0x080c,
+	0x1b60, 0x2001, 0x4007, 0x0804, 0x13bc, 0x74c4, 0x73c8, 0x72cc,
+	0x6014, 0x2091, 0x8000, 0x00e6, 0x2009, 0x0012, 0xd0fc, 0x1118,
+	0x2071, 0x4640, 0x0018, 0x2071, 0x4680, 0xc1fd, 0x792a, 0x7063,
+	0x0005, 0x71d0, 0xc1c4, 0x71d2, 0x7366, 0x726a, 0x746e, 0x7072,
+	0x7077, 0x0000, 0x2c00, 0x707a, 0xa02e, 0x2530, 0x611c, 0xa184,
+	0x0060, 0x0110, 0x080c, 0x3fc1, 0x00ee, 0x6596, 0x65a6, 0x669a,
+	0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x6714, 0x6023, 0x0000,
+	0x080c, 0x22ae, 0x2091, 0x8001, 0x0005, 0x70c3, 0x4005, 0x0804,
+	0x13bd, 0x20a9, 0x0005, 0x2099, 0x4614, 0x2091, 0x8000, 0x530a,
+	0x2091, 0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000,
+	0xa5a9, 0x0000, 0x0005, 0x71c4, 0x70c7, 0x0000, 0x791e, 0x0804,
+	0x13ba, 0x71c4, 0x71c6, 0x2168, 0x0010, 0x2069, 0x1000, 0x690c,
+	0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x1dd8, 0xa285, 0x0000,
+	0x1118, 0x70c3, 0x4000, 0x0010, 0x70c3, 0x4003, 0x70ca, 0x0804,
+	0x13bd, 0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x1a04, 0x13b3,
+	0x7966, 0x0804, 0x13ba, 0x7964, 0x71c6, 0x0804, 0x13ba, 0x7900,
+	0x71c6, 0x71c4, 0x7902, 0x0804, 0x13ba, 0x7900, 0x71c6, 0x0804,
+	0x13ba, 0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0160, 0x810c,
+	0x0230, 0x8210, 0x810c, 0x810c, 0x0210, 0x8210, 0x810c, 0x81ff,
+	0x1904, 0x13b4, 0x8210, 0x7a0e, 0xd28c, 0x0538, 0x7910, 0xc1cd,
+	0x7912, 0x2009, 0x0021, 0x2019, 0x0003, 0xd284, 0x01c0, 0x8108,
+	0x2019, 0x0041, 0x2011, 0x8e4e, 0x2312, 0x2019, 0x0042, 0x8210,
+	0x2312, 0x2019, 0x0043, 0x8210, 0x2312, 0x2019, 0x0046, 0x8210,
+	0x2312, 0x2019, 0x0047, 0x8210, 0x2312, 0x2019, 0x0006, 0x2011,
+	0x8e53, 0x2112, 0x2011, 0x8e73, 0x2312, 0x7904, 0x7806, 0x0804,
+	0x13b9, 0x7804, 0x70c6, 0x0804, 0x13ba, 0x71c4, 0xd1fc, 0x1118,
+	0x2011, 0x4ac0, 0x0010, 0x2011, 0x4b40, 0x8107, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa268, 0x2011, 0x0000, 0x6814, 0xd0fc,
+	0x0110, 0xa295, 0x0200, 0xd0b4, 0x0110, 0xa295, 0x0001, 0x6b0c,
+	0x6800, 0x70da, 0x0804, 0x13b7, 0x7814, 0xd0f4, 0x0130, 0x2001,
+	0x4007, 0x70db, 0x0000, 0xa005, 0x0048, 0xd0fc, 0x0130, 0x2001,
+	0x4007, 0x70db, 0x0001, 0xa005, 0x0008, 0xa006, 0x0005, 0x7814,
+	0xd0f4, 0x0130, 0x2001, 0x4007, 0x70db, 0x0000, 0xa005, 0x0008,
+	0xa006, 0x0005, 0x7814, 0xd0fc, 0x0130, 0x2001, 0x4007, 0x70db,
+	0x0001, 0xa005, 0x0008, 0xa006, 0x0005, 0x7112, 0x721a, 0x731e,
+	0x7810, 0xd0c4, 0x0110, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108,
+	0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084,
+	0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0140,
+	0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018,
+	0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211,
+	0x7d10, 0xd5c4, 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008,
+	0xd0fc, 0x0de8, 0x7003, 0x0001, 0x7007, 0x0006, 0x711a, 0x721e,
+	0x7d10, 0xd5c4, 0x0110, 0x7322, 0x7426, 0xa084, 0x01e0, 0x0005,
+	0x7848, 0xa065, 0x0120, 0x2c04, 0x784a, 0x2063, 0x0000, 0x0005,
+	0x00f6, 0x2079, 0x4600, 0x7848, 0x2062, 0x2c00, 0xa005, 0x1110,
+	0x080c, 0x254c, 0x784a, 0x00fe, 0x0005, 0x2011, 0x9000, 0x7a4a,
+	0x7bc4, 0x8319, 0x0128, 0xa280, 0x0032, 0x2012, 0x2010, 0x0cc8,
+	0x2013, 0x0000, 0x0005, 0x0016, 0x0026, 0xd7fc, 0x1118, 0x2011,
+	0x4bc0, 0x0010, 0x2011, 0x6bc0, 0xa784, 0x0f00, 0x800b, 0xa784,
+	0x001f, 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa268,
+	0x002e, 0x001e, 0x0005, 0x0c39, 0x2900, 0x682a, 0x2a00, 0x682e,
+	0x6808, 0xa084, 0xf9ef, 0xa80d, 0x690a, 0x00e6, 0xd7fc, 0x1128,
+	0x2009, 0x4652, 0x2071, 0x4640, 0x0020, 0x2009, 0x4692, 0x2071,
+	0x4680, 0x210c, 0x6804, 0xa005, 0x0148, 0xa116, 0x1138, 0x2060,
+	0x6000, 0x6806, 0x0016, 0x200b, 0x0000, 0x0018, 0x2009, 0x0000,
+	0x0016, 0x6804, 0xa065, 0x0178, 0x6000, 0x6806, 0x0421, 0x080c,
+	0x1d95, 0x6810, 0x7908, 0x8109, 0x790a, 0x8001, 0x6812, 0x1d88,
+	0x7910, 0xc1a5, 0x7912, 0x001e, 0x6902, 0x6906, 0x2d00, 0x2060,
+	0x080c, 0x2693, 0x00ee, 0x0005, 0xa065, 0x0160, 0x2008, 0x609c,
+	0xa005, 0x0128, 0x2062, 0x609f, 0x0000, 0xa065, 0x0cc0, 0x7848,
+	0x794a, 0x2062, 0x0005, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9,
+	0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828,
+	0x601a, 0x682c, 0x6022, 0x0005, 0x00e6, 0xd7fc, 0x1128, 0x2071,
+	0x4640, 0x2031, 0x46c0, 0x0020, 0x2071, 0x4680, 0x2031, 0x48c0,
+	0x704c, 0xa08c, 0x0200, 0x1128, 0xa608, 0x2d0a, 0x8000, 0x704e,
+	0xa006, 0x00ee, 0x0005, 0x00f6, 0xd7fc, 0x1118, 0x2079, 0x4640,
+	0x0010, 0x2079, 0x4680, 0x080c, 0x1b7b, 0x2091, 0x8000, 0x6804,
+	0x780a, 0xa065, 0x05f0, 0x0030, 0x2c00, 0x780a, 0x2060, 0x6000,
+	0xa065, 0x05b8, 0x6010, 0xa306, 0x1db8, 0x600c, 0xa206, 0x1da0,
+	0x2c28, 0x7848, 0xac06, 0x1108, 0x0448, 0x6804, 0xac06, 0x1140,
+	0x6000, 0x2060, 0x6806, 0xa005, 0x1118, 0x6803, 0x0000, 0x0048,
+	0x6400, 0x7808, 0x2060, 0x6402, 0xa486, 0x0000, 0x1110, 0x2c00,
+	0x6802, 0x2560, 0x080c, 0x1be3, 0x601b, 0x0005, 0x6023, 0x0020,
+	0x00fe, 0x080c, 0x1d95, 0x00f6, 0x7908, 0x8109, 0x790a, 0x6810,
+	0x8001, 0x6812, 0x1118, 0x7810, 0xc0a5, 0x7812, 0x2001, 0xffff,
+	0xa005, 0x00fe, 0x0005, 0x0076, 0x2700, 0x2039, 0x0000, 0xd0fc,
+	0x0108, 0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008,
+	0x2091, 0x8000, 0x080c, 0x1b93, 0x8738, 0xa784, 0x001f, 0x1dd0,
+	0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x1d90,
+	0x2091, 0x8001, 0x007e, 0x0005, 0x786c, 0x2009, 0x8e74, 0x210c,
+	0xa10d, 0x0118, 0xa065, 0x0804, 0x207a, 0x2061, 0x0000, 0x6018,
+	0xd084, 0x11b8, 0x7810, 0xd08c, 0x0130, 0xc08c, 0x7812, 0xc7fc,
+	0x2069, 0x4640, 0x0028, 0xc08d, 0x7812, 0x2069, 0x4680, 0xc7fd,
+	0x2091, 0x8000, 0x681c, 0x681f, 0x0000, 0x2091, 0x8001, 0xa005,
+	0x1108, 0x0005, 0xa08c, 0xfff0, 0x0110, 0x080c, 0x254c, 0x0002,
+	0x1cb8, 0x1cbb, 0x1cc1, 0x1cc5, 0x1cb9, 0x1cc9, 0x1cb9, 0x1cb9,
+	0x1cb9, 0x1ccf, 0x1cfb, 0x1cfe, 0x1d03, 0x1d0c, 0x1cb9, 0x1cb9,
+	0x0005, 0x080c, 0x254c, 0x080c, 0x1c5b, 0x2001, 0x8001, 0x0804,
+	0x1d15, 0x2001, 0x8003, 0x0804, 0x1d15, 0x2001, 0x8004, 0x0804,
+	0x1d15, 0x080c, 0x1c5b, 0x2001, 0x8006, 0x0804, 0x1d15, 0x2091,
+	0x8000, 0x0076, 0xd7fc, 0x1128, 0x2069, 0x4640, 0x2039, 0x0009,
+	0x0020, 0x2069, 0x4680, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000,
+	0x0128, 0x000e, 0x6f1e, 0x2091, 0x8001, 0x0005, 0x6870, 0x007e,
+	0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010,
+	0x080c, 0x1b93, 0x8738, 0xa784, 0x001f, 0x1dd0, 0x2091, 0x8001,
+	0x2001, 0x800a, 0x00d0, 0x2001, 0x800c, 0x00b8, 0x080c, 0x1c5b,
+	0x2001, 0x800d, 0x0090, 0xd7fc, 0x0110, 0x78e4, 0x0008, 0x78e0,
+	0x70c6, 0x2001, 0x800e, 0x0048, 0xd7fc, 0x0110, 0x78ec, 0x0008,
+	0x78e8, 0x70c6, 0x2001, 0x800f, 0x0000, 0x70c2, 0xd7fc, 0x1118,
+	0x70db, 0x0000, 0x0010, 0x70db, 0x0001, 0x2061, 0x0000, 0x601b,
+	0x0001, 0x2091, 0x4080, 0x0005, 0xac80, 0x0001, 0x81ff, 0x0518,
+	0x2099, 0x0030, 0x20a0, 0x700c, 0xa084, 0x07ff, 0x0100, 0x7018,
+	0x0006, 0x701c, 0x0006, 0x7020, 0x0006, 0x7024, 0x0006, 0x7112,
+	0x81ac, 0x721a, 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007,
+	0x0001, 0x7008, 0x800b, 0x1ee8, 0x7007, 0x0002, 0xa08c, 0x01e0,
+	0x1110, 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004, 0x000e,
+	0x7026, 0x000e, 0x7022, 0x000e, 0x701e, 0x000e, 0x701a, 0x0005,
+	0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x681f, 0x0201,
+	0x6803, 0xfd20, 0x6807, 0x0038, 0x6a1a, 0x2d00, 0xa0e8, 0x0008,
+	0xa290, 0x0004, 0x8109, 0x1d80, 0x0005, 0x70ec, 0xd0dc, 0x1520,
+	0x2029, 0x0001, 0x7814, 0xd0cc, 0x1160, 0x70ec, 0xd0e4, 0x2019,
+	0x0c0a, 0x2021, 0x000a, 0x1120, 0x2019, 0x0c0c, 0x2021, 0x000c,
+	0x0070, 0x70ec, 0xd0e4, 0x1128, 0x2019, 0x180c, 0x2021, 0x000c,
+	0x0030, 0x2019, 0x1809, 0x2021, 0x0009, 0xa5ad, 0x0200, 0x6b0a,
+	0x6c0e, 0x6d1e, 0x6807, 0x0038, 0x0005, 0x6004, 0x6086, 0x2c08,
+	0x2063, 0x0000, 0x7868, 0xa005, 0x796a, 0x0110, 0x2c02, 0x0008,
+	0x796e, 0x0005, 0x00c6, 0x2061, 0x4600, 0x6887, 0x0103, 0x2d08,
+	0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008,
+	0x616e, 0x00ce, 0x0005, 0x2091, 0x8000, 0x2c04, 0x786e, 0xa005,
+	0x1108, 0x786a, 0x2091, 0x8001, 0x609c, 0xa005, 0x0188, 0x00c6,
+	0x2060, 0x2008, 0x609c, 0xa005, 0x0138, 0x2062, 0x609f, 0x0000,
+	0xa065, 0x609c, 0xa005, 0x1dc8, 0x7848, 0x794a, 0x2062, 0x00ce,
+	0x7848, 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x1110, 0x080c,
+	0x254c, 0x784a, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086,
+	0x818e, 0x1208, 0xa200, 0x1f04, 0x1ddf, 0x8086, 0x818e, 0x0005,
+	0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213,
+	0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, 0x1def, 0x0028, 0xa11a,
+	0x2308, 0x8210, 0x1f04, 0x1def, 0x0006, 0x3200, 0xa084, 0xefff,
+	0x2080, 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000,
+	0x0cb8, 0x7d74, 0x70d0, 0xa506, 0x0904, 0x1ebd, 0x7810, 0x2050,
+	0x080c, 0x1b58, 0x0904, 0x1ebd, 0xa046, 0x7970, 0x2500, 0x8000,
+	0xa112, 0x2009, 0x0040, 0x1208, 0x0030, 0x72d0, 0xa206, 0x0118,
+	0x8840, 0x2009, 0x0080, 0x00c6, 0x7112, 0x7007, 0x0001, 0x2099,
+	0x0030, 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000,
+	0x88ff, 0x0110, 0x080c, 0x1b58, 0x7008, 0xd0fc, 0x0de8, 0x7007,
+	0x0002, 0x2091, 0x8001, 0xa08c, 0x01e0, 0x1538, 0x53a5, 0x8cff,
+	0x1120, 0x88ff, 0x0904, 0x1eaa, 0x0050, 0x2c00, 0x788e, 0x20a9,
+	0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5, 0x0804, 0x1eaa, 0xa046,
+	0x7218, 0x731c, 0xdac4, 0x0110, 0x7420, 0x7524, 0xa292, 0x0040,
+	0xa39b, 0x0000, 0xa4a3, 0x0000, 0xa5ab, 0x0000, 0x721a, 0x731e,
+	0xdac4, 0x0118, 0x7422, 0x7526, 0xa006, 0x7007, 0x0004, 0x0904,
+	0x1eaa, 0x8cff, 0x0110, 0x080c, 0x1b60, 0x00ce, 0x080c, 0x1b60,
+	0xa046, 0x7888, 0x8000, 0x788a, 0xa086, 0x0002, 0x01c0, 0x7a7c,
+	0x7b78, 0xdac4, 0x0110, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004,
+	0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000,
+	0x721a, 0x731e, 0xdac4, 0x0588, 0x7422, 0x7526, 0x0470, 0x6014,
+	0xd0fc, 0x1118, 0x2069, 0x4640, 0x0010, 0x2069, 0x4680, 0x2091,
+	0x8000, 0x681f, 0x0002, 0x88ff, 0x0120, 0xa046, 0x788c, 0x2060,
+	0x0c70, 0x788b, 0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091,
+	0x8001, 0x0098, 0x00ce, 0x788b, 0x0000, 0x080c, 0x2035, 0x6004,
+	0xa084, 0x000f, 0x0059, 0x88ff, 0x0130, 0x788c, 0x2060, 0x6004,
+	0xa084, 0x000f, 0x0019, 0x0804, 0x1e09, 0x0005, 0x0002, 0x1ecf,
+	0x1eea, 0x1f03, 0x1ecf, 0x1f10, 0x1ee0, 0x1ecf, 0x1ecf, 0x1ecf,
+	0x1ee8, 0x1f01, 0x1ecf, 0x1ecf, 0x1ecf, 0x1ecf, 0x1ecf, 0x2039,
+	0x0400, 0x78bc, 0xa705, 0x78be, 0x6008, 0xa705, 0x600a, 0x080c,
+	0x1f4c, 0x609c, 0x78ba, 0x609f, 0x0000, 0x080c, 0x2021, 0x0005,
+	0x78bc, 0xd0c4, 0x0108, 0x0c58, 0x601c, 0xc0bd, 0x601e, 0x0030,
+	0x080c, 0x205f, 0x78bc, 0xd0c4, 0x0108, 0x0c08, 0x78bf, 0x0000,
+	0x6004, 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0138, 0x080c,
+	0x1f4c, 0x0120, 0x78bc, 0xc0c5, 0x78be, 0x0010, 0x0804, 0x1f67,
+	0x0005, 0x080c, 0x205c, 0x78bc, 0xa08c, 0x0e00, 0x1110, 0xd0c4,
+	0x1108, 0x0828, 0x080c, 0x1f4c, 0x1110, 0x0804, 0x1f67, 0x0005,
+	0x78bc, 0xd0c4, 0x0110, 0x0804, 0x1ecf, 0x78bf, 0x0000, 0x6714,
+	0x2011, 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0188,
+	0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0150, 0xa7bc,
+	0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e, 0x0002, 0x0108,
+	0x00c0, 0x080c, 0x1b7b, 0x2d00, 0x2091, 0x8000, 0x682b, 0x0000,
+	0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010,
+	0x2091, 0x8001, 0x1f04, 0x1f34, 0x8211, 0x0118, 0x20a9, 0x0100,
+	0x0c58, 0x080c, 0x1b60, 0x0005, 0x609f, 0x0000, 0x78b4, 0xa06d,
+	0x2c00, 0x78b6, 0x1110, 0x78ba, 0x0038, 0x689e, 0x2d00, 0x6002,
+	0x78b8, 0xad06, 0x1108, 0x6002, 0x78b0, 0x8001, 0x78b2, 0x1130,
+	0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006, 0x0005, 0x00e6,
+	0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2, 0x601c, 0x60a2,
+	0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060, 0x0110, 0x080c,
+	0x3fc1, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x6714, 0x2071, 0x4680,
+	0xd7fc, 0x1110, 0x2071, 0x4640, 0xa784, 0x0f00, 0x800b, 0xa784,
+	0x001f, 0x0120, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x71c0,
+	0xa168, 0x2700, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+	0x71c4, 0xa100, 0x60c2, 0x2091, 0x8000, 0x7814, 0xd0c4, 0x0138,
+	0xd7fc, 0x1118, 0xd0f4, 0x1140, 0x0010, 0xd0fc, 0x1128, 0x6e08,
+	0xd684, 0x01f0, 0xd9fc, 0x11e0, 0x2091, 0x8001, 0x080c, 0x1be3,
+	0x2091, 0x8000, 0x080c, 0x1d95, 0x2091, 0x8001, 0x7814, 0xd0c4,
+	0x0904, 0x201f, 0xd7fc, 0x1120, 0xd0f4, 0x1130, 0x0804, 0x201f,
+	0xd0fc, 0x1110, 0x0804, 0x201f, 0x601b, 0x0021, 0x0804, 0x201f,
+	0x6024, 0xa096, 0x0001, 0x1110, 0x8000, 0x6026, 0x6a10, 0x6814,
+	0xa202, 0x0268, 0x0160, 0x2091, 0x8001, 0x2039, 0x0200, 0x609c,
+	0x78ba, 0x609f, 0x0000, 0x080c, 0x2021, 0x0804, 0x201f, 0x2c08,
+	0xd9fc, 0x01f0, 0x6800, 0xa065, 0x01d8, 0x6a04, 0x7000, 0xa084,
+	0x0002, 0x0168, 0x7048, 0xa206, 0x1150, 0x6b04, 0x2160, 0x2304,
+	0x6002, 0xa005, 0x1108, 0x6902, 0x2260, 0x6102, 0x0098, 0x2d00,
+	0x2060, 0x080c, 0x2693, 0x6e08, 0x2160, 0x6202, 0x6906, 0x0050,
+	0x6800, 0x6902, 0xa065, 0x0110, 0x6102, 0x0008, 0x6906, 0x2160,
+	0x6003, 0x0000, 0x2160, 0xd9fc, 0x0118, 0xa6b4, 0xfffc, 0x6e0a,
+	0x6810, 0x7d08, 0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001,
+	0xd6b4, 0x0128, 0xa6b6, 0x0040, 0x6e0a, 0x080c, 0x1bf4, 0x00ee,
+	0x0005, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x080c, 0x1d95,
+	0x2091, 0x8001, 0x78b8, 0xa065, 0x0128, 0x609c, 0x78ba, 0x609f,
+	0x0000, 0x0c78, 0x78b6, 0x78ba, 0x0005, 0x7970, 0x7874, 0x2818,
+	0xd384, 0x0118, 0x8000, 0xa112, 0x0220, 0x8000, 0xa112, 0x1278,
+	0xc384, 0x7a7c, 0x721a, 0x7a78, 0x721e, 0xdac4, 0x0120, 0x7a84,
+	0x7222, 0x7a80, 0x7226, 0xa006, 0xd384, 0x0108, 0x8000, 0x7876,
+	0x70d2, 0x781c, 0xa005, 0x0138, 0x8001, 0x781e, 0x1120, 0x0e04,
+	0x205b, 0x2091, 0x4080, 0x0005, 0x2039, 0x2071, 0x0010, 0x2039,
+	0x2077, 0x2704, 0xa005, 0x0160, 0xac00, 0x2068, 0x6908, 0x6810,
+	0x6912, 0x680a, 0x690c, 0x6814, 0x6916, 0x680e, 0x8738, 0x0c88,
+	0x0005, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015,
+	0x001b, 0x0000, 0x2041, 0x0000, 0x780c, 0x0002, 0x2223, 0x21fe,
+	0x2082, 0x20f2, 0x2039, 0x8e74, 0x2734, 0x7d10, 0x00c0, 0x6084,
+	0xa086, 0x0103, 0x1904, 0x20dc, 0x6114, 0x6018, 0xa105, 0x0120,
+	0x86ff, 0x11d8, 0x0804, 0x20dc, 0x8603, 0xa080, 0x8e55, 0x620c,
+	0x2202, 0x8000, 0x6210, 0x2202, 0x080c, 0x1db3, 0x8630, 0xa68e,
+	0x000f, 0x0904, 0x215d, 0x786c, 0xa065, 0x1d08, 0x7808, 0xa602,
+	0x1220, 0xd5ac, 0x1110, 0x263a, 0x0005, 0xa682, 0x0003, 0x1a04,
+	0x215d, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x11f8,
+	0x2011, 0x8e55, 0x2204, 0x70c6, 0x8210, 0x2204, 0x70ca, 0xd684,
+	0x1130, 0x8210, 0x2204, 0x70da, 0x8210, 0x2204, 0x70de, 0xa685,
+	0x8020, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810, 0xa084,
+	0xffcf, 0x7812, 0x2091, 0x8001, 0x203b, 0x0000, 0x0005, 0x7810,
+	0xc0ad, 0x7812, 0x0804, 0x215d, 0x263a, 0x080c, 0x2229, 0x1904,
+	0x2245, 0x786c, 0xa065, 0x1904, 0x2087, 0x2091, 0x8000, 0x7810,
+	0xa084, 0xffcf, 0x86ff, 0x0108, 0xc0ad, 0x7812, 0x2091, 0x8001,
+	0x0804, 0x2245, 0x2039, 0x8e74, 0x2734, 0x7d10, 0x00a0, 0x6084,
+	0xa086, 0x0103, 0x1904, 0x2147, 0x6114, 0x6018, 0xa105, 0x0120,
+	0x86ff, 0x11b8, 0x0804, 0x2147, 0xa680, 0x8e55, 0x620c, 0x2202,
+	0x080c, 0x1db3, 0x8630, 0xa68e, 0x001e, 0x0904, 0x215d, 0x786c,
+	0xa065, 0x1d28, 0x7808, 0xa602, 0x1220, 0xd5ac, 0x1110, 0x263a,
+	0x0005, 0xa682, 0x0006, 0x1a04, 0x215d, 0x2091, 0x8000, 0x2069,
+	0x0000, 0x6818, 0xd084, 0x11f8, 0x2011, 0x8e55, 0x2009, 0x8e4e,
+	0x26a8, 0x211c, 0x2204, 0x201a, 0x8108, 0x8210, 0x1f04, 0x2129,
+	0xa685, 0x8030, 0x70c2, 0x681b, 0x0001, 0x2091, 0x4080, 0x7810,
+	0xa084, 0xffcf, 0x7812, 0x2091, 0x8001, 0xa006, 0x2009, 0x8e75,
+	0x200a, 0x203a, 0x0005, 0x7810, 0xc0ad, 0x7812, 0x00b0, 0x263a,
+	0x080c, 0x2229, 0x1904, 0x2245, 0x786c, 0xa065, 0x1904, 0x20f7,
+	0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0108, 0xc0ad,
+	0x7812, 0x2091, 0x8001, 0x0804, 0x2245, 0x2091, 0x8000, 0x7007,
+	0x0004, 0x7994, 0x70d4, 0xa102, 0x0228, 0x0168, 0x7b90, 0xa302,
+	0x1150, 0x0010, 0x8002, 0x1138, 0x263a, 0x7810, 0xc0ad, 0x7812,
+	0x2091, 0x8001, 0x0005, 0xa184, 0xff00, 0x0140, 0x810f, 0x810c,
+	0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018, 0x8107, 0x8004,
+	0x8004, 0x7a9c, 0xa210, 0x721a, 0x7a98, 0xa006, 0xa211, 0x721e,
+	0xd4c4, 0x0130, 0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226,
+	0x20a1, 0x0030, 0x7003, 0x0000, 0x2009, 0x8e54, 0x260a, 0x8109,
+	0x2198, 0x2104, 0xd084, 0x0108, 0x8633, 0xa6b0, 0x0002, 0x26a8,
+	0x53a6, 0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000,
+	0xa10a, 0x1208, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0140,
+	0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100, 0x0018,
+	0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78, 0xa006, 0xa211,
+	0xd4c4, 0x0120, 0x7b84, 0xa319, 0x7c80, 0xa421, 0x7008, 0xd0fc,
+	0x0de8, 0xa084, 0x01e0, 0x01d0, 0x7d10, 0x2031, 0x8e54, 0x2634,
+	0x78a8, 0x8000, 0x78aa, 0xd08c, 0x1138, 0x7007, 0x0006, 0x7004,
+	0xd094, 0x1de8, 0x0804, 0x215f, 0x2069, 0x4647, 0x206b, 0x0003,
+	0x78ac, 0xa085, 0x0300, 0x78ae, 0xa006, 0x0048, 0x2030, 0x75d6,
+	0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091,
+	0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a,
+	0x721e, 0xd5c4, 0x0110, 0x7322, 0x7426, 0x0005, 0x6084, 0xa086,
+	0x0103, 0x11d8, 0x6114, 0x6018, 0xa105, 0x11b8, 0x2069, 0x0000,
+	0x6818, 0xd084, 0x1190, 0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3,
+	0x8020, 0x681b, 0x0001, 0x2091, 0x4080, 0x080c, 0x1db3, 0x0e04,
+	0x221c, 0x786c, 0xa065, 0x1d10, 0x0005, 0x0059, 0x1530, 0x786c,
+	0xa065, 0x19e0, 0x0410, 0x0029, 0x1500, 0x786c, 0xa065, 0x1dd8,
+	0x00e0, 0x6084, 0xa086, 0x0103, 0x1168, 0x6018, 0xc0fc, 0x601a,
+	0xa086, 0x0004, 0x1138, 0x7804, 0xd0a4, 0x0120, 0x080c, 0x1db3,
+	0xa006, 0x0005, 0x0079, 0x1118, 0xa085, 0x0001, 0x0005, 0x00b9,
+	0x1110, 0x2041, 0x0001, 0x7d10, 0x0005, 0x88ff, 0x0110, 0x2091,
+	0x4080, 0x0005, 0x7b90, 0x7994, 0x70d4, 0xa102, 0x1118, 0xa385,
+	0x0000, 0x0005, 0x0210, 0xa302, 0x0005, 0x8002, 0x0005, 0xa184,
+	0xff00, 0x0140, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007,
+	0xa100, 0x0018, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98, 0x7ca4,
+	0x7da0, 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009, 0x0018,
+	0x6028, 0xa005, 0x0110, 0x2009, 0x0040, 0x080c, 0x1b15, 0x01d0,
+	0x78a8, 0x8000, 0x78aa, 0xd08c, 0x1510, 0x6014, 0xd0fc, 0x1118,
+	0x2069, 0x4640, 0x0010, 0x2069, 0x4680, 0x2091, 0x8000, 0x681f,
+	0x0003, 0x78ab, 0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091,
+	0x8001, 0x0068, 0x78ab, 0x0000, 0x080c, 0x1db3, 0x7990, 0x7894,
+	0x8000, 0xa10a, 0x1208, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071,
+	0x0010, 0x2091, 0x8001, 0x0005, 0xd7fc, 0x1118, 0x2009, 0x4658,
+	0x0010, 0x2009, 0x4698, 0x2091, 0x8000, 0x200a, 0x00f6, 0x2009,
+	0x4680, 0x2079, 0x0100, 0xd7fc, 0x1120, 0x2009, 0x4640, 0x2079,
+	0x0200, 0x2104, 0xa086, 0x0000, 0x1180, 0xd7fc, 0x1118, 0x2009,
+	0x4645, 0x0010, 0x2009, 0x4685, 0x2104, 0xa005, 0x1130, 0x7830,
+	0xa084, 0x00c0, 0x1110, 0x781b, 0x0052, 0x00fe, 0x0005, 0x2009,
+	0x0002, 0x2069, 0x4600, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1904,
+	0x2324, 0x2071, 0x4680, 0x2079, 0x0100, 0x2021, 0x48bf, 0x784b,
+	0x000f, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x0118, 0x2019, 0x3e0f,
+	0x0030, 0x20a1, 0x012b, 0x2019, 0x3e0f, 0xd184, 0x0110, 0x20a1,
+	0x022b, 0x2304, 0xa005, 0x0140, 0x789a, 0x8318, 0x23ac, 0x8318,
+	0x2398, 0x53a6, 0x3318, 0x0ca8, 0x789b, 0x0000, 0x789b, 0x0020,
+	0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x2020, 0x1f04, 0x2302,
+	0x7003, 0x0000, 0x0016, 0xd18c, 0x2009, 0x0000, 0x0108, 0xc1bd,
+	0x080c, 0x2443, 0x001e, 0x7020, 0xa084, 0x000f, 0xa085, 0x6300,
+	0x7806, 0x780f, 0x9000, 0x7843, 0x00d8, 0x7853, 0x0090, 0x780b,
+	0x2f08, 0x7452, 0x704f, 0x0000, 0x8109, 0x0140, 0x2071, 0x4640,
+	0x2079, 0x0200, 0x2021, 0x46bf, 0x0804, 0x22df, 0x080c, 0x24fd,
+	0x0005, 0x0016, 0x2011, 0x0101, 0xd1bc, 0x1110, 0x2011, 0x0201,
+	0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x001e,
+	0x080c, 0x2443, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110, 0x2011,
+	0x0201, 0x20a9, 0x0009, 0x810b, 0x1f04, 0x234b, 0xa18c, 0x0e00,
+	0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x0005, 0x2019, 0x0002,
+	0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x1f04, 0x235c, 0xa294,
+	0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x8319, 0x0118,
+	0x2009, 0x0201, 0x0c78, 0x0005, 0x2011, 0x0101, 0xd3fc, 0x1110,
+	0x2011, 0x0201, 0x20a9, 0x000c, 0x810b, 0x1f04, 0x2374, 0xa18c,
+	0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012, 0x0005, 0x2011,
+	0x0102, 0xd3fc, 0x1110, 0x2011, 0x0202, 0x2204, 0xa084, 0xf0cf,
+	0xa105, 0x2012, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc, 0x1110,
+	0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a,
+	0x62ac, 0x63ac, 0x00ce, 0x0005, 0x00c6, 0x2061, 0x0100, 0xd1bc,
+	0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0022,
+	0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x00ce, 0x0005, 0x00c6,
+	0x2061, 0x0100, 0xd1bc, 0x1110, 0x2061, 0x0200, 0xc1bc, 0x8103,
+	0x8003, 0xa080, 0x0020, 0x609a, 0x60a4, 0xa28c, 0x0020, 0x0118,
+	0xc2ac, 0xa39d, 0x4000, 0xc3ec, 0xd3b4, 0x1108, 0xc3ed, 0x62ae,
+	0x2010, 0x60a4, 0x63ae, 0x2018, 0x00ce, 0x0005, 0x2091, 0x8000,
+	0x00c6, 0x00e6, 0x6818, 0xa005, 0x0904, 0x2427, 0xd1fc, 0x0118,
+	0x2061, 0x8dd0, 0x0010, 0x2061, 0x8cc0, 0x080c, 0x242f, 0x0560,
+	0x20a9, 0x0101, 0xd1fc, 0x0118, 0x2061, 0x8cd0, 0x0010, 0x2061,
+	0x8bc0, 0x00c6, 0x080c, 0x242f, 0x0128, 0x00ce, 0x8c60, 0x1f04,
+	0x23e9, 0x04a8, 0x000e, 0xd1fc, 0x0128, 0xa082, 0x8cd0, 0x2071,
+	0x4680, 0x0020, 0xa082, 0x8bc0, 0x2071, 0x4640, 0x7076, 0x7172,
+	0x2138, 0x2001, 0x0004, 0x7062, 0x707f, 0x000f, 0x71d0, 0xc1c4,
+	0x71d2, 0x080c, 0x22a4, 0x00c0, 0xd1fc, 0x1118, 0x2071, 0x4640,
+	0x0010, 0x2071, 0x4680, 0x6020, 0xc0dd, 0x6022, 0x7172, 0x2138,
+	0x2c00, 0x707a, 0x2001, 0x0006, 0x7062, 0x707f, 0x000f, 0x71d0,
+	0xc1c4, 0x71d2, 0x080c, 0x22a4, 0x2001, 0x0000, 0x0010, 0x2001,
+	0x0001, 0x2091, 0x8001, 0xa005, 0x00ee, 0x00ce, 0x0005, 0x2c04,
+	0xa005, 0x0170, 0x2060, 0x6010, 0xa306, 0x1140, 0x600c, 0xa206,
+	0x1128, 0x6014, 0xa106, 0x1110, 0xa006, 0x0020, 0x6000, 0x0c80,
+	0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x2079, 0x4680,
+	0x2071, 0x0100, 0xd1bc, 0x1120, 0x2079, 0x4640, 0x2071, 0x0200,
+	0x7920, 0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x1110, 0x001e, 0x0060,
+	0x810b, 0x810b, 0x810b, 0x810b, 0x000e, 0xa18d, 0x0800, 0xd0bc,
+	0x1110, 0xa18d, 0x0f00, 0x2104, 0x00ee, 0x00fe, 0x0005, 0x2001,
+	0x4601, 0x2004, 0xd0ac, 0x1138, 0x68e4, 0xd0ac, 0x0120, 0xa084,
+	0x0006, 0x1108, 0x0009, 0x0005, 0x6014, 0x00e6, 0x0036, 0x2018,
+	0x2071, 0x4b40, 0xd0fc, 0x1110, 0x2071, 0x4ac0, 0x8007, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004, 0xa084, 0x000a,
+	0x1904, 0x24fa, 0x7108, 0xa194, 0xff00, 0x0904, 0x24fa, 0xa18c,
+	0x00ff, 0x701c, 0xa084, 0xff00, 0x01c0, 0x7004, 0xa085, 0x003a,
+	0x7006, 0x2001, 0x0009, 0xa102, 0x16d8, 0x2001, 0x000a, 0xa102,
+	0x16d0, 0x2001, 0x000c, 0xa102, 0x16c8, 0x701c, 0xa084, 0x00ff,
+	0x701e, 0x7004, 0xa084, 0xffdf, 0x7006, 0x2001, 0x000a, 0xa106,
+	0x01a8, 0x2001, 0x000c, 0xa106, 0x01a0, 0x2001, 0x0012, 0xa106,
+	0x0198, 0x2001, 0x0014, 0xa106, 0x0190, 0x2001, 0x0019, 0xa106,
+	0x0188, 0x2001, 0x0032, 0xa106, 0x0180, 0x00d8, 0x2009, 0x000c,
+	0x00d0, 0x2009, 0x0012, 0x00b8, 0x2009, 0x0014, 0x00a0, 0x2009,
+	0x0019, 0x0088, 0x2009, 0x0020, 0x0070, 0x2009, 0x003f, 0x0058,
+	0x2009, 0x000a, 0x0040, 0x2009, 0x000c, 0x0028, 0x2009, 0x0019,
+	0x0010, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a, 0x7004, 0xa085,
+	0x000a, 0x7006, 0x2071, 0x4600, 0x7004, 0xd0bc, 0x0158, 0xd3fc,
+	0x1120, 0x73ea, 0x2071, 0x4640, 0x0018, 0x73ee, 0x2071, 0x4680,
+	0x701f, 0x000d, 0x003e, 0x00ee, 0x0005, 0x2001, 0x01ff, 0x2004,
+	0xd0fc, 0x11d0, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x12a0,
+	0x2071, 0x0200, 0x71ec, 0xa18c, 0x1c00, 0x810f, 0x810c, 0x810c,
+	0x2079, 0x0100, 0x78ec, 0xa084, 0x1c00, 0x8007, 0x8004, 0x8004,
+	0xa105, 0xa08a, 0x0007, 0x0208, 0x0005, 0x0002, 0x254b, 0x2532,
+	0x254b, 0x2532, 0x2525, 0x253f, 0x2525, 0x7008, 0xa084, 0xc3ff,
+	0xa085, 0x3000, 0x700a, 0x7808, 0xa084, 0xc3ff, 0xa085, 0x3000,
+	0x780a, 0x0005, 0x7008, 0xa084, 0xc3ff, 0xa085, 0x2000, 0x700a,
+	0x7808, 0xa084, 0xc3ff, 0xa085, 0x2000, 0x780a, 0x0005, 0x7008,
+	0xa084, 0xc3ff, 0xa085, 0x0c00, 0x700a, 0x7808, 0xa084, 0xc3ff,
+	0xa085, 0x0c00, 0x780a, 0x0005, 0x0e04, 0x254c, 0x2091, 0x8000,
+	0x2071, 0x0000, 0x0006, 0x7018, 0xd084, 0x1de8, 0x000e, 0x2071,
+	0x0010, 0x70ca, 0x000e, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x0a04,
+	0x70df, 0x0020, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x0cf8, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708a, 0x758e,
+	0x7492, 0x7696, 0x779a, 0xa594, 0x003f, 0xd4f4, 0x0138, 0xd7bc,
+	0x1128, 0xa784, 0x007d, 0x1904, 0x3c74, 0x0871, 0xa49c, 0x000f,
+	0xa382, 0x0004, 0x0320, 0xa3a6, 0x0007, 0x1930, 0x2418, 0x8507,
+	0xa084, 0x000f, 0x0002, 0x2b49, 0x2c34, 0x2c72, 0x2ed8, 0x3256,
+	0x32ad, 0x3353, 0x33e2, 0x34b6, 0x3588, 0x259e, 0x259b, 0x2970,
+	0x2a56, 0x322a, 0x259b, 0x080c, 0x254c, 0x0005, 0xa006, 0x0038,
+	0x7808, 0xc08d, 0x780a, 0xa006, 0x7002, 0x704a, 0x7042, 0x70ce,
+	0x705c, 0xa005, 0x1904, 0x26ec, 0x7060, 0xa084, 0x0007, 0x0002,
+	0x25b8, 0x2626, 0x262e, 0x2637, 0x2640, 0x26d2, 0x2649, 0x2626,
+	0x7830, 0xd0bc, 0x1d10, 0x71d0, 0xd1bc, 0x19f8, 0xd1b4, 0x1904,
+	0x2603, 0x70a0, 0xa086, 0x0001, 0x09c0, 0x70b0, 0xa06d, 0x6800,
+	0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa, 0x6808, 0xa045,
+	0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0118, 0x69bc,
+	0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001, 0x0010, 0x0804,
+	0x281f, 0x705c, 0xa005, 0x1904, 0x259d, 0x00c6, 0x00d6, 0x70b0,
+	0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0080, 0x6b0c, 0x7baa,
+	0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001,
+	0x0118, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001,
+	0x0020, 0x0804, 0x281f, 0x080c, 0x3c33, 0x1904, 0x259d, 0x781b,
+	0x0068, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de,
+	0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a, 0x68bc, 0x703e,
+	0xc1b4, 0x71d2, 0x70b4, 0xa065, 0x68c0, 0x7056, 0x7003, 0x0002,
+	0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005, 0x080c, 0x3c33,
+	0x1120, 0x781b, 0x0054, 0x7003, 0x0004, 0x0005, 0x080c, 0x3c33,
+	0x1128, 0x2011, 0x000c, 0x0419, 0x7003, 0x0004, 0x0005, 0x080c,
+	0x3c33, 0x1128, 0x2011, 0x0006, 0x00d1, 0x7003, 0x0004, 0x0005,
+	0x080c, 0x3c33, 0x1128, 0x2011, 0x000d, 0x0089, 0x7003, 0x0004,
+	0x0005, 0x080c, 0x3c33, 0x1150, 0x2011, 0x0006, 0x0041, 0x7078,
+	0x707b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0004, 0x0005, 0x7170,
+	0xc1fc, 0x8107, 0x7882, 0x789b, 0x0080, 0xa286, 0x000c, 0x1120,
+	0x7aaa, 0x2001, 0x0001, 0x0098, 0xa18c, 0x001f, 0xa18d, 0x00c0,
+	0x79aa, 0xa286, 0x000d, 0x0120, 0x7aaa, 0x2001, 0x0002, 0x0038,
+	0x78ab, 0x0020, 0x7174, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b,
+	0x0060, 0x78aa, 0x785b, 0x0004, 0x781b, 0x0113, 0x080c, 0x3c46,
+	0x707f, 0x000f, 0x70d0, 0xd0b4, 0x0168, 0xc0b4, 0x70d2, 0x00c6,
+	0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001,
+	0x601a, 0x00ce, 0x0005, 0x7014, 0xa005, 0x1138, 0x70d0, 0xd0b4,
+	0x0128, 0x70b4, 0xac06, 0x1110, 0x0c29, 0x0005, 0x0016, 0x71a0,
+	0xa186, 0x0001, 0x0528, 0x00d6, 0x0026, 0x2100, 0x2011, 0x0001,
+	0xa212, 0x70b0, 0x2068, 0x6800, 0xac06, 0x0120, 0x8211, 0x01b0,
+	0x00c9, 0x0cc8, 0x00c6, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b0,
+	0x2068, 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef, 0x600a, 0x8211,
+	0x0110, 0x0041, 0x0cb0, 0x70a3, 0x0001, 0x00ce, 0x002e, 0x00de,
+	0x001e, 0x0005, 0xade8, 0x0005, 0x70a8, 0xad06, 0x1110, 0x70a4,
+	0x2068, 0x0005, 0x080c, 0x3c33, 0x1904, 0x259d, 0x7078, 0x2068,
+	0x7770, 0x080c, 0x3b6f, 0x2c50, 0x080c, 0x3cce, 0x789b, 0x0080,
+	0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001,
+	0x2001, 0x0004, 0x0804, 0x2824, 0x080c, 0x3c33, 0x1904, 0x259d,
+	0x789b, 0x0080, 0x705c, 0x2068, 0x6f14, 0x70d0, 0xd0b4, 0x0168,
+	0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef,
+	0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x080c, 0x3b6f, 0x2c50,
+	0x080c, 0x3cce, 0x6824, 0xa005, 0x0130, 0xa082, 0x0006, 0x0208,
+	0x0010, 0x6827, 0x0005, 0x6814, 0xa084, 0x001f, 0xc0bd, 0x78aa,
+	0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003, 0x0804, 0x2824,
+	0xc28d, 0x72d2, 0x72bc, 0xa200, 0xa015, 0x7150, 0x8108, 0xa12a,
+	0x0208, 0x71bc, 0x2164, 0x6504, 0x85ff, 0x1170, 0x7152, 0x8421,
+	0x1da8, 0x70d0, 0xd08c, 0x0128, 0x70cc, 0xa005, 0x1110, 0x70cf,
+	0x000a, 0x0005, 0x2200, 0x0c90, 0x70d0, 0xc08c, 0x70d2, 0x70cf,
+	0x0000, 0x6034, 0xa005, 0x1db0, 0x6708, 0xa784, 0x073f, 0x01d0,
+	0xd7d4, 0x1d80, 0xa784, 0x0021, 0x1d68, 0xa784, 0x0002, 0x0130,
+	0xa784, 0x0004, 0x0d38, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218,
+	0x1d08, 0xa784, 0x0100, 0x0130, 0x6018, 0xa005, 0x19d8, 0xa7bc,
+	0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684, 0x000e,
+	0x6318, 0x0128, 0x601c, 0xa302, 0x0220, 0x0118, 0x0858, 0x83ff,
+	0x1948, 0x2d58, 0x2c50, 0x7152, 0xd7bc, 0x1120, 0x7028, 0x6022,
+	0x603a, 0x0010, 0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100,
+	0x2a60, 0x2041, 0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0,
+	0xd1fc, 0x0110, 0xd684, 0x0110, 0xa39c, 0xffbf, 0xd6a4, 0x0110,
+	0xa39d, 0x0020, 0xa684, 0x000e, 0x1904, 0x27d6, 0xc7a5, 0x670a,
+	0x2c00, 0x68c6, 0x77a0, 0xa786, 0x0001, 0x1178, 0x70d0, 0xd0b4,
+	0x1160, 0x7000, 0xa082, 0x0002, 0x1240, 0x7830, 0xd0bc, 0x1128,
+	0x789b, 0x0080, 0x7baa, 0x0804, 0x281d, 0x8739, 0x77a2, 0x2750,
+	0x77ac, 0xa7b0, 0x0005, 0x70a8, 0xa606, 0x1108, 0x76a4, 0x76ae,
+	0x2c3a, 0x8738, 0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738,
+	0x253a, 0x7830, 0xd0bc, 0x0150, 0x2091, 0x8000, 0x2091, 0x303d,
+	0x70d0, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000,
+	0x0120, 0x8421, 0x2200, 0x1904, 0x2725, 0x0005, 0xd1dc, 0x0904,
+	0x37ce, 0x2029, 0x0020, 0xd69c, 0x1120, 0x8528, 0xd68c, 0x1108,
+	0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c, 0x00ff, 0x70c8,
+	0xa160, 0x2c64, 0x8cff, 0x0188, 0x6014, 0xa706, 0x1dd0, 0x60b8,
+	0x8001, 0x60ba, 0x1d88, 0x2a60, 0x6008, 0xa085, 0x0100, 0x600a,
+	0x2200, 0x8421, 0x1904, 0x2725, 0x0005, 0x2a60, 0x610e, 0x69be,
+	0x2c00, 0x68c6, 0x8840, 0x6008, 0xc0d5, 0x600a, 0x77a0, 0xa786,
+	0x0001, 0x1904, 0x27ad, 0x70d0, 0xd0b4, 0x1904, 0x27ad, 0x7000,
+	0xa082, 0x0002, 0x1a04, 0x27ad, 0x7830, 0xd0bc, 0x1904, 0x27ad,
+	0x789b, 0x0080, 0x7baa, 0x7daa, 0x79aa, 0x2001, 0x0002, 0x0006,
+	0x6018, 0x8000, 0x601a, 0x0008, 0x0006, 0x2960, 0x6104, 0x2a60,
+	0x080c, 0x3ce1, 0x1590, 0xa184, 0x0018, 0x0180, 0xa184, 0x0010,
+	0x0118, 0x080c, 0x3977, 0x1548, 0xa184, 0x0008, 0x0138, 0x69a0,
+	0xa184, 0x0600, 0x1118, 0x080c, 0x3895, 0x00f8, 0x69a0, 0xa184,
+	0x1e00, 0x0528, 0xa184, 0x0800, 0x0178, 0x00c6, 0x2960, 0x6000,
+	0xa085, 0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x00ce,
+	0x080c, 0x3977, 0x1150, 0x69a0, 0xa184, 0x0200, 0x0118, 0x080c,
+	0x38da, 0x0018, 0xa184, 0x0400, 0x19f0, 0x69a0, 0xa184, 0x1000,
+	0x0130, 0x6914, 0xa18c, 0xff00, 0x810f, 0x080c, 0x239c, 0x002e,
+	0xa68c, 0x00e0, 0xa684, 0x0060, 0x0128, 0xa086, 0x0060, 0x1110,
+	0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b, 0x0060, 0x2800,
+	0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0168, 0xc0fc, 0x7083,
+	0x0000, 0xa08a, 0x000d, 0x0328, 0xa08a, 0x000c, 0x7182, 0x2001,
+	0x000c, 0x800c, 0x7186, 0x78aa, 0x3518, 0x3340, 0x3428, 0x8000,
+	0x80ac, 0xaf80, 0x002b, 0x20a0, 0x789b, 0x0000, 0xad80, 0x000b,
+	0x2098, 0x53a6, 0x23a8, 0x2898, 0x25a0, 0xa286, 0x0020, 0x1508,
+	0x70d0, 0xc0b5, 0x70d2, 0x2c00, 0x70b6, 0x2d00, 0x70ba, 0x6814,
+	0xc0fc, 0x8007, 0x7882, 0xa286, 0x0002, 0x0904, 0x28f5, 0x70a0,
+	0x8000, 0x70a2, 0x74b0, 0xa498, 0x0005, 0x70a8, 0xa306, 0x1108,
+	0x73a4, 0x73b2, 0xa286, 0x0010, 0x0904, 0x259d, 0x00de, 0x00ce,
+	0x0005, 0x7000, 0xa005, 0x19e0, 0xa286, 0x0002, 0x1904, 0x290c,
+	0x080c, 0x3c33, 0x19a8, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091,
+	0x8000, 0x781b, 0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de,
+	0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a,
+	0x0126, 0x00d6, 0x00c6, 0x70d0, 0xa084, 0x2e00, 0x2090, 0x00ce,
+	0x00de, 0x012e, 0x2900, 0x7056, 0x68bc, 0x703e, 0x7003, 0x0002,
+	0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x7830, 0xd0bc, 0x0140,
+	0x2091, 0x303d, 0x70d0, 0xa084, 0x303d, 0x2091, 0x8000, 0x2090,
+	0x70a0, 0xa005, 0x1108, 0x0005, 0x8421, 0x0de8, 0x724c, 0x70bc,
+	0xa200, 0xa015, 0x0804, 0x2725, 0xa286, 0x0010, 0x1560, 0x080c,
+	0x3c33, 0x1904, 0x28a0, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x781b,
+	0x0068, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2,
+	0x78da, 0x7808, 0xc08d, 0x780a, 0x70a0, 0x8000, 0x70a2, 0x74b0,
+	0xa490, 0x0005, 0x70a8, 0xa206, 0x1108, 0x72a4, 0x72b2, 0x2900,
+	0x7056, 0x68bc, 0x703e, 0x7003, 0x0002, 0x2d00, 0x704a, 0xad80,
+	0x0009, 0x7042, 0x0005, 0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814,
+	0xc0fc, 0x8007, 0x7882, 0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2,
+	0x7eda, 0x781b, 0x0068, 0x2900, 0x7056, 0x7202, 0x7808, 0xc08d,
+	0x780a, 0x2300, 0xa605, 0x0170, 0x70d0, 0xa084, 0x2e00, 0xa086,
+	0x2600, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009, 0x0001, 0xa284,
+	0x000f, 0x0023, 0xad80, 0x0009, 0x7042, 0x0005, 0x296e, 0x41d9,
+	0x41d9, 0x41c7, 0x41d9, 0x296e, 0x296e, 0x296e, 0x080c, 0x254c,
+	0x7808, 0xa084, 0xfffd, 0x780a, 0x00f6, 0x2079, 0x4600, 0x78ac,
+	0x00fe, 0xd084, 0x01b0, 0x7060, 0xa086, 0x0001, 0x0904, 0x2a32,
+	0x7060, 0xa086, 0x0005, 0x1158, 0x7078, 0x2068, 0x681b, 0x0004,
+	0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7063,
+	0x0000, 0x70a3, 0x0000, 0x70a4, 0x70ae, 0x70b2, 0x080c, 0x2682,
+	0x0156, 0x2011, 0x0004, 0x7160, 0xa186, 0x0001, 0x0160, 0xa186,
+	0x0007, 0x1118, 0x701f, 0x0005, 0x0030, 0x701f, 0x0001, 0x70d0,
+	0xc0c5, 0x70d2, 0x0000, 0x2001, 0x460a, 0x2004, 0xa084, 0x00ff,
+	0xa086, 0x0018, 0x0130, 0x7018, 0x7016, 0xa005, 0x1110, 0x70a3,
+	0x0001, 0x0066, 0x080c, 0x3f26, 0x20a9, 0x0010, 0x2039, 0x0000,
+	0x080c, 0x3a66, 0xa7b8, 0x0100, 0x1f04, 0x29c0, 0x006e, 0x7000,
+	0x0002, 0x29fd, 0x29db, 0x29db, 0x29d3, 0x29fd, 0x29fd, 0x29fd,
+	0x29d1, 0x080c, 0x254c, 0x705c, 0xa005, 0x0538, 0xad06, 0x1118,
+	0x6800, 0x705e, 0x0080, 0x6820, 0xd084, 0x1148, 0x6f14, 0x080c,
+	0x3b6f, 0x6008, 0xc0d4, 0x600a, 0x080c, 0x37a4, 0x0020, 0x7058,
+	0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc,
+	0x0108, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820, 0xa084,
+	0x00ff, 0xc09d, 0x6822, 0x080c, 0x1da2, 0x2011, 0x0004, 0x74c8,
+	0xa4a0, 0x0100, 0x04b1, 0xaea0, 0x0017, 0x0499, 0x20a9, 0x0101,
+	0x74c8, 0x0479, 0x8420, 0x1f04, 0x2a09, 0x70c0, 0x2060, 0x2021,
+	0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0198, 0x6018, 0x0016,
+	0x0006, 0x2011, 0x4602, 0x220c, 0xa102, 0x2012, 0x000e, 0x001e,
+	0xa102, 0x0338, 0x6012, 0x1128, 0x2011, 0x4604, 0x2204, 0xc0a5,
+	0x2012, 0x601b, 0x0000, 0xace0, 0x0010, 0x1f04, 0x2a13, 0x8421,
+	0x1d00, 0x015e, 0x7063, 0x0000, 0x7003, 0x0000, 0x704b, 0x0000,
+	0x0005, 0x0046, 0x2404, 0xa005, 0x01a8, 0x2068, 0x6800, 0x0006,
+	0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00,
+	0x681e, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x080c, 0x1da2,
+	0x000e, 0x0c48, 0x004e, 0x2023, 0x0000, 0x0005, 0xa282, 0x0003,
+	0x0310, 0x080c, 0x254c, 0x2300, 0x0002, 0x2a60, 0x2add, 0x2af7,
+	0xa282, 0x0002, 0x0110, 0x080c, 0x254c, 0x7060, 0x7063, 0x0000,
+	0x707f, 0x0000, 0x0022, 0x77d0, 0xc7c5, 0x77d2, 0x0002, 0x2a77,
+	0x2a77, 0x2a79, 0x2ab1, 0x37d8, 0x2a77, 0x2ab1, 0x2a77, 0x080c,
+	0x254c, 0x7770, 0x080c, 0x3a66, 0x7770, 0xa7bc, 0x8f00, 0x080c,
+	0x3b6f, 0x6018, 0xa005, 0x0528, 0xd7fc, 0x1118, 0x2021, 0x8cc0,
+	0x0010, 0x2021, 0x8dd0, 0x2009, 0x0005, 0x2011, 0x0010, 0x080c,
+	0x2b11, 0x01b8, 0x0156, 0x20a9, 0x0101, 0xd7fc, 0x1118, 0x2021,
+	0x8bc0, 0x0010, 0x2021, 0x8cd0, 0x0046, 0x2009, 0x0005, 0x2011,
+	0x0010, 0x080c, 0x2b11, 0x004e, 0x0118, 0x8420, 0x1f04, 0x2a9c,
+	0x015e, 0x8738, 0xa784, 0x001f, 0x1990, 0x0804, 0x25a0, 0x0804,
+	0x25a0, 0x7770, 0x080c, 0x3b6f, 0x6018, 0xa005, 0x0520, 0xd7fc,
+	0x1118, 0x2021, 0x8cc0, 0x0010, 0x2021, 0x8dd0, 0x2009, 0x0005,
+	0x2011, 0x0020, 0x080c, 0x2b11, 0x01b0, 0x0156, 0x20a9, 0x0101,
+	0xd7fc, 0x1118, 0x2021, 0x8bc0, 0x0010, 0x2021, 0x8cd0, 0x0046,
+	0x2009, 0x0005, 0x2011, 0x0020, 0x04e1, 0x004e, 0x0118, 0x8420,
+	0x1f04, 0x2acf, 0x015e, 0x0804, 0x25a0, 0x2200, 0x0002, 0x2ae2,
+	0x2ae4, 0x2ae4, 0x080c, 0x254c, 0x2009, 0x0012, 0x7060, 0xa086,
+	0x0002, 0x0110, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0108, 0x691a,
+	0x7063, 0x0000, 0x70d0, 0xc0c5, 0x70d2, 0x0804, 0x3be5, 0x2200,
+	0x0002, 0x2afe, 0x2ae4, 0x2afc, 0x080c, 0x254c, 0x080c, 0x3f26,
+	0x7000, 0xa086, 0x0002, 0x1904, 0x375d, 0x080c, 0x37be, 0x6008,
+	0xa084, 0xfbef, 0x600a, 0x080c, 0x374f, 0x0904, 0x375d, 0x0804,
+	0x25a0, 0x2404, 0xa005, 0x0590, 0x2068, 0x2d04, 0x0006, 0x6814,
+	0xa706, 0x0118, 0x2d20, 0x000e, 0x0ca8, 0x000e, 0x2022, 0x691a,
+	0x6817, 0x0000, 0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e,
+	0x6820, 0xa084, 0x00ff, 0xa205, 0x6822, 0x080c, 0x1da2, 0x2021,
+	0x4602, 0x241c, 0x8319, 0x2322, 0x6010, 0x8001, 0x6012, 0x1128,
+	0x2021, 0x4604, 0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef,
+	0x600a, 0x080c, 0x269e, 0x080c, 0x37be, 0x0005, 0xa085, 0x0001,
+	0x0ce0, 0x2300, 0x0002, 0x2b50, 0x2b4e, 0x2bcb, 0x080c, 0x254c,
+	0x78e4, 0xa005, 0x17b0, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104,
+	0x259d, 0x0010, 0x0304, 0x259d, 0x2008, 0xa084, 0x0030, 0x1110,
+	0x0804, 0x322a, 0x78ec, 0xa084, 0x0003, 0x0dd0, 0x7884, 0xd0fc,
+	0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, 0x0004,
+	0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, 0x0005,
+	0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, 0x2bae,
+	0x2bb7, 0x2ba4, 0x2b87, 0x3c29, 0x3c29, 0x2b87, 0x2bc1, 0x080c,
+	0x254c, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, 0xa086, 0x0002,
+	0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x2a56, 0x7060,
+	0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, 0x0d90, 0x79e4,
+	0x2001, 0x0003, 0x0804, 0x2f18, 0x6818, 0xd0fc, 0x0110, 0x681b,
+	0x001d, 0x080c, 0x3a3c, 0x781b, 0x006e, 0x0005, 0x6818, 0xd0fc,
+	0x0110, 0x681b, 0x001d, 0x080c, 0x3a3c, 0x0804, 0x3c07, 0x6818,
+	0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a3c, 0x781b, 0x00fa,
+	0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x080c, 0x3a3c,
+	0x781b, 0x00cb, 0x0005, 0xa584, 0x000f, 0x11c0, 0x7000, 0x0002,
+	0x25a0, 0x2bd8, 0x2bda, 0x375d, 0x375d, 0x375d, 0x2bd8, 0x2bd8,
+	0x080c, 0x254c, 0x080c, 0x37be, 0x6008, 0xa084, 0xfbef, 0x600a,
+	0x080c, 0x374f, 0x0904, 0x375d, 0x0804, 0x25a0, 0x78e4, 0xa005,
+	0x1b04, 0x2b89, 0x3208, 0xa18c, 0x0800, 0x0118, 0x0104, 0x2b89,
+	0x0010, 0x0304, 0x2b89, 0x2008, 0xa084, 0x0030, 0x1118, 0x781b,
+	0x0068, 0x0005, 0x78ec, 0xa084, 0x0003, 0x0dc8, 0x7884, 0xd0fc,
+	0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, 0x0004,
+	0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, 0x0005,
+	0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, 0x2c26,
+	0x2c2a, 0x2c21, 0x2c1f, 0x3c29, 0x3c29, 0x2c1f, 0x3c23, 0x080c,
+	0x254c, 0x080c, 0x3a42, 0x781b, 0x006e, 0x0005, 0x080c, 0x3a42,
+	0x0804, 0x3c07, 0x080c, 0x3a42, 0x781b, 0x00fa, 0x0005, 0x080c,
+	0x3a42, 0x781b, 0x00cb, 0x0005, 0x2300, 0x0002, 0x2c3b, 0x2c39,
+	0x2c3d, 0x080c, 0x254c, 0x0804, 0x33e2, 0x681b, 0x0016, 0x78a3,
+	0x0000, 0x79e4, 0xa184, 0x0030, 0x0904, 0x33e2, 0x78ec, 0xa084,
+	0x0003, 0x0904, 0x33e2, 0xa184, 0x0100, 0x0d98, 0x7884, 0xd0fc,
+	0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007, 0xa086, 0x0004,
+	0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007, 0xa086, 0x0005,
+	0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001, 0x0002, 0x2c6f,
+	0x2c2a, 0x2ba4, 0x3be5, 0x3c29, 0x3c29, 0x3be5, 0x3c23, 0x080c,
+	0x3bf1, 0x0005, 0xa282, 0x0005, 0x0310, 0x080c, 0x254c, 0x7898,
+	0x2040, 0x2300, 0x0002, 0x2c7e, 0x2ea8, 0x2eb2, 0x2200, 0x0002,
+	0x2c9a, 0x2c87, 0x2c9a, 0x2c85, 0x2e8a, 0x080c, 0x254c, 0x789b,
+	0x0018, 0x78a8, 0x2010, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0a04,
+	0x3a0b, 0xa08a, 0x0004, 0x1a04, 0x3a0b, 0x0002, 0x3a0b, 0x3a0b,
+	0x3a0b, 0x39c1, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0148,
+	0x0804, 0x3a0b, 0x7000, 0xa005, 0x1dd8, 0x2011, 0x0004, 0x0804,
+	0x3594, 0xa184, 0x00ff, 0xa08a, 0x0010, 0x1a04, 0x3a0b, 0x0002,
+	0x2cc2, 0x2cc0, 0x2cd4, 0x2cd8, 0x2d86, 0x3a0b, 0x3a0b, 0x2d88,
+	0x3a0b, 0x3a0b, 0x2e86, 0x2e86, 0x3a0b, 0x3a0b, 0x3a0b, 0x2e88,
+	0x080c, 0x254c, 0xd6e4, 0x0140, 0x2001, 0x0300, 0x8000, 0x8000,
+	0x783a, 0x781b, 0x00c7, 0x0005, 0x6818, 0xd0fc, 0x0118, 0x681b,
+	0x001d, 0x0c90, 0x0804, 0x3be5, 0x681b, 0x001d, 0x0804, 0x3a36,
+	0x6920, 0x6922, 0xa684, 0x1800, 0x1904, 0x2d29, 0x6820, 0xd084,
+	0x1904, 0x2d31, 0x6818, 0xa086, 0x0008, 0x1110, 0x681b, 0x0000,
+	0xd6d4, 0x0568, 0xd6bc, 0x0558, 0x7083, 0x0000, 0x6818, 0xa084,
+	0x003f, 0xa08a, 0x000d, 0x0718, 0xa08a, 0x000c, 0x7182, 0x2001,
+	0x000c, 0x800c, 0x7186, 0x789b, 0x0061, 0x78aa, 0x0156, 0x0136,
+	0x0146, 0x0016, 0x3208, 0xa18c, 0x0600, 0x0118, 0x20a1, 0x022b,
+	0x0010, 0x20a1, 0x012b, 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac,
+	0xad80, 0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, 0x6038,
+	0xa005, 0x1150, 0x681c, 0xa084, 0x000e, 0x0904, 0x3a36, 0x080c,
+	0x3a48, 0x782b, 0x3008, 0x0010, 0x8001, 0x603a, 0x781b, 0x0071,
+	0x0005, 0xd6e4, 0x0130, 0x781b, 0x0083, 0x0005, 0x781b, 0x0083,
+	0x0005, 0xa684, 0x0060, 0x0dd0, 0xd6dc, 0x0dc0, 0xd6fc, 0x01a0,
+	0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x8007, 0xa084,
+	0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2,
+	0x6b94, 0x2200, 0xa303, 0x68ae, 0xd6f4, 0x0118, 0xc6f4, 0x7e5a,
+	0x6eb6, 0x7000, 0xa086, 0x0003, 0x1148, 0x0006, 0x080c, 0x3f26,
+	0x080c, 0x41d9, 0x000e, 0x781b, 0x0080, 0x0005, 0xa006, 0x080c,
+	0x42b5, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0120,
+	0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6,
+	0x7bd6, 0x7bde, 0x2300, 0xa405, 0x1130, 0xc6f5, 0x7e5a, 0x6eb6,
+	0x781b, 0x0080, 0x0005, 0x781b, 0x0080, 0x2200, 0xa115, 0x1118,
+	0x080c, 0x41d9, 0x0005, 0x080c, 0x4206, 0x0005, 0x080c, 0x254c,
+	0x0804, 0x2e1c, 0x00c6, 0x7054, 0x2060, 0x6920, 0xa18c, 0xecff,
+	0x6922, 0x6000, 0xa084, 0xcfdf, 0x6002, 0x080c, 0x38f4, 0xa006,
+	0x2040, 0x2038, 0x080c, 0x399c, 0x0804, 0x2e10, 0x00c6, 0x7054,
+	0x2060, 0x2c48, 0x7aa8, 0xa294, 0x00ff, 0xa286, 0x0004, 0x11d8,
+	0x6920, 0xd1e4, 0x1170, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031,
+	0x0000, 0xa006, 0x2010, 0x080c, 0x38f7, 0x080c, 0x399c, 0x0804,
+	0x2e10, 0xa18c, 0xecff, 0x6922, 0x6104, 0xa18c, 0xffdd, 0x6106,
+	0x6000, 0xc0ac, 0x6002, 0xa286, 0x0003, 0x01d0, 0x6104, 0xa184,
+	0x0010, 0x0548, 0x080c, 0x3b6b, 0x080c, 0x3977, 0x88ff, 0x0518,
+	0x00ce, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a,
+	0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005,
+	0x6920, 0xd1cc, 0x0130, 0xa18c, 0xfdff, 0x6922, 0x6000, 0xc0ec,
+	0x6002, 0x2039, 0x0000, 0x2041, 0x0000, 0x2031, 0x0000, 0xa006,
+	0x2010, 0x080c, 0x399c, 0xa286, 0x0001, 0x0158, 0x6104, 0xa184,
+	0x0008, 0x01b0, 0x080c, 0x3b6b, 0x080c, 0x3895, 0x88ff, 0x1980,
+	0x0078, 0x6920, 0xd1c4, 0x0130, 0xa18c, 0xfeff, 0x6922, 0x6000,
+	0xc0e4, 0x6002, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x38f7,
+	0x00ce, 0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b,
+	0x0083, 0x0005, 0x0804, 0x3a32, 0x2808, 0x789b, 0x0080, 0x2019,
+	0x0080, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x11b8, 0x2300,
+	0xa102, 0xa086, 0x0001, 0x0904, 0x2d8a, 0x7ca8, 0xa4a4, 0x00ff,
+	0xa480, 0x0002, 0xa300, 0x2018, 0xa102, 0x0a04, 0x2d9e, 0x0904,
+	0x2d9e, 0x24a8, 0x7aa8, 0x1f04, 0x2e3a, 0x0c18, 0xa284, 0x00f0,
+	0xa082, 0x0020, 0x06b8, 0x2200, 0xa082, 0x0021, 0x1698, 0x7aa8,
+	0x8318, 0x8318, 0x2100, 0xa302, 0x0aa0, 0xa286, 0x0023, 0x0950,
+	0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xc0a5,
+	0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x78a0, 0x8001, 0x0904,
+	0x2e10, 0x20a8, 0x7998, 0x789b, 0x0060, 0x78aa, 0x2011, 0x0080,
+	0x799a, 0x78a8, 0x7998, 0x7a9a, 0x78aa, 0x7a98, 0x1f04, 0x2e68,
+	0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b, 0x006e, 0x0005, 0x781b,
+	0x0082, 0x0005, 0x8318, 0x2100, 0xa302, 0x0a04, 0x2e21, 0xa284,
+	0x0080, 0x1904, 0x3a36, 0x78a0, 0xa005, 0x08c8, 0x0804, 0x3a36,
+	0x0804, 0x3a0b, 0x7054, 0xa04d, 0x789b, 0x0018, 0x78a8, 0xa084,
+	0x00ff, 0xa08e, 0x0001, 0x0110, 0x080c, 0x254c, 0x7aa8, 0xa294,
+	0x00ff, 0x784b, 0x0008, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0005,
+	0x1a04, 0x3a0b, 0x0002, 0x3a0b, 0x380c, 0x3a0b, 0x3927, 0x3d31,
+	0xa282, 0x0000, 0x1110, 0x080c, 0x254c, 0x080c, 0x3a3c, 0x781b,
+	0x0082, 0x0005, 0xa282, 0x0003, 0x1110, 0x080c, 0x254c, 0xd4fc,
+	0x11d0, 0x7060, 0xa005, 0x0110, 0x080c, 0x254c, 0x6f14, 0x7772,
+	0xa7bc, 0x8f00, 0x080c, 0x3b6f, 0x6008, 0xa085, 0x0021, 0x600a,
+	0x8738, 0xa784, 0x001f, 0x1db0, 0x080c, 0x3a3f, 0x7063, 0x0002,
+	0x701f, 0x0009, 0x0010, 0x080c, 0x3a4b, 0x781b, 0x0082, 0x0005,
+	0xa282, 0x0004, 0x0310, 0x080c, 0x254c, 0x2300, 0x0002, 0x2ee2,
+	0x3078, 0x30b4, 0xa286, 0x0003, 0x0598, 0x7200, 0x7cd8, 0x7ddc,
+	0x7fd0, 0x71d0, 0xd1b4, 0x0528, 0xd1bc, 0x1518, 0x2001, 0x4601,
+	0x2004, 0xd0c4, 0x11f0, 0x7868, 0xa084, 0x00ff, 0x11d0, 0xa282,
+	0x0002, 0x12b8, 0x00d6, 0x783b, 0x8300, 0x781b, 0x0059, 0x70b8,
+	0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2,
+	0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x00de, 0x2001, 0x0000,
+	0x0058, 0x783b, 0x1300, 0x781b, 0x0057, 0x2001, 0x0000, 0x0020,
+	0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x7046, 0x68a0, 0xd0ec, 0x0118,
+	0x6008, 0xc08d, 0x600a, 0xa284, 0x000f, 0x0002, 0x3059, 0x2f33,
+	0x2f30, 0x3184, 0x320f, 0x25a0, 0x2f2e, 0x2f2e, 0x080c, 0x254c,
+	0x6008, 0xc0d4, 0x600a, 0xd6e4, 0x0120, 0x7044, 0xa086, 0x0014,
+	0x11e8, 0x080c, 0x3f26, 0x2009, 0x0000, 0x6818, 0xd0fc, 0x0108,
+	0x7044, 0xa086, 0x0014, 0x0168, 0x6818, 0xa086, 0x0008, 0x1904,
+	0x301b, 0x7858, 0xd09c, 0x0904, 0x301b, 0x6820, 0xd0ac, 0x0904,
+	0x301b, 0x681b, 0x0014, 0x2009, 0x0002, 0x04a8, 0x7868, 0xa08c,
+	0x00ff, 0x0588, 0xa186, 0x0008, 0x1158, 0x6008, 0xc0a4, 0x600a,
+	0x080c, 0x374f, 0x0540, 0x080c, 0x37be, 0x080c, 0x3f26, 0x0060,
+	0xa186, 0x0028, 0x1500, 0x6018, 0xa005, 0x0d78, 0x8001, 0x0d68,
+	0x8001, 0x0d58, 0x601e, 0x0c48, 0x6820, 0xd084, 0x0904, 0x25a0,
+	0xc084, 0x6822, 0x080c, 0x2693, 0x7058, 0x00c6, 0x2060, 0x6800,
+	0x6002, 0x00ce, 0x6004, 0x6802, 0xa005, 0x2d00, 0x1108, 0x6002,
+	0x6006, 0x0804, 0x25a0, 0x0016, 0x81ff, 0x15f0, 0x7000, 0xa086,
+	0x0030, 0x05d0, 0x71d0, 0xd1bc, 0x15b8, 0xd1b4, 0x11e8, 0x705c,
+	0xa005, 0x1590, 0x70a0, 0xa086, 0x0001, 0x0570, 0x7003, 0x0000,
+	0x0046, 0x0056, 0x0076, 0x0066, 0x00c6, 0x00d6, 0x080c, 0x25c5,
+	0x00de, 0x00ce, 0x006e, 0x007e, 0x005e, 0x004e, 0x71d0, 0xd1b4,
+	0x11d8, 0x7003, 0x0040, 0x00c0, 0x080c, 0x3c33, 0x11a8, 0x781b,
+	0x0068, 0x00d6, 0x70b8, 0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6,
+	0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030,
+	0x7808, 0xc08d, 0x780a, 0x00de, 0x080c, 0x30dc, 0x001e, 0x81ff,
+	0x0904, 0x301b, 0xa684, 0xdf00, 0x681e, 0x682b, 0x0000, 0x6f14,
+	0xa186, 0x0002, 0x1904, 0x301c, 0x6818, 0xa086, 0x0014, 0x1130,
+	0x2008, 0xd6e4, 0x0118, 0x7868, 0xa08c, 0x00ff, 0x080c, 0x3a55,
+	0x080c, 0x269e, 0x6820, 0xd0dc, 0x1578, 0x8717, 0xa294, 0x000f,
+	0x8213, 0x8213, 0x8213, 0xb284, 0x0600, 0x0118, 0xa290, 0x4ac0,
+	0x0010, 0xa290, 0x4b40, 0xa290, 0x0000, 0x221c, 0xd3c4, 0x0170,
+	0x6820, 0xd0e4, 0x0128, 0xa084, 0xefff, 0x6822, 0xc3ac, 0x2312,
+	0x8210, 0x2204, 0xa085, 0x0038, 0x2012, 0x8211, 0xd3d4, 0x0138,
+	0x68a0, 0xd0c4, 0x1120, 0x080c, 0x3144, 0x0804, 0x25a0, 0x6008,
+	0xc08d, 0x600a, 0x0008, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0110,
+	0x7044, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, 0x0168,
+	0x2009, 0x4602, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412, 0x1128,
+	0x2021, 0x4604, 0x2404, 0xc0a5, 0x2022, 0x6018, 0xa005, 0x0118,
+	0x8001, 0x601a, 0x1118, 0x6008, 0xc0a4, 0x600a, 0x6820, 0xd084,
+	0x1130, 0x6800, 0xa005, 0x1108, 0x6002, 0x6006, 0x0020, 0x7058,
+	0x2060, 0x6800, 0x6002, 0x2061, 0x4600, 0x6887, 0x0103, 0x2d08,
+	0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0110, 0x2d02, 0x0008,
+	0x616e, 0x7200, 0xa286, 0x0030, 0x0158, 0xa286, 0x0040, 0x1904,
+	0x25a0, 0x7003, 0x0002, 0x7048, 0x2068, 0x68c4, 0x2060, 0x0005,
+	0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, 0x703e, 0x70b4, 0xa065,
+	0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, 0x0009, 0x7042, 0x0005,
+	0xa282, 0x0004, 0x0210, 0x080c, 0x254c, 0x2200, 0x0002, 0x3083,
+	0x3092, 0x309e, 0x3092, 0xa586, 0x1300, 0x0160, 0xa586, 0x8300,
+	0x1d90, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084,
+	0xfbef, 0x600a, 0x7000, 0xa086, 0x0005, 0x0128, 0x080c, 0x3a3c,
+	0x781b, 0x0082, 0x0005, 0x781b, 0x0083, 0x0005, 0x7890, 0x8007,
+	0x8001, 0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c,
+	0x00ff, 0xa186, 0x0003, 0x0128, 0xa186, 0x0000, 0x0110, 0x0804,
+	0x3a0b, 0x781b, 0x0083, 0x0005, 0x6820, 0xc095, 0x6822, 0x82ff,
+	0x1118, 0x080c, 0x3a3c, 0x0030, 0x8211, 0x0110, 0x080c, 0x254c,
+	0x080c, 0x3a4b, 0x781b, 0x0082, 0x0005, 0x080c, 0x3c46, 0x7830,
+	0xa084, 0x00c0, 0x1170, 0x0016, 0x3208, 0xa18c, 0x0800, 0x001e,
+	0x0118, 0x0104, 0x30d9, 0x0010, 0x0304, 0x30d9, 0x791a, 0xa006,
+	0x0005, 0xa085, 0x0001, 0x0005, 0xa684, 0x0060, 0x1130, 0x682f,
+	0x0000, 0x6833, 0x0000, 0x0804, 0x3143, 0xd6dc, 0x1198, 0x68b4,
+	0xd0dc, 0x1180, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x7044, 0xa005,
+	0x1130, 0x2200, 0xa105, 0x0904, 0x3f26, 0x7047, 0x0015, 0x0804,
+	0x3f26, 0x0005, 0xd6ac, 0x01f0, 0xd6f4, 0x0130, 0x682f, 0x0000,
+	0x6833, 0x0000, 0x0804, 0x3f26, 0x68b4, 0xa084, 0x4000, 0xa635,
+	0xd6f4, 0x1da0, 0x7044, 0xa005, 0x1110, 0x7047, 0x0015, 0xd6dc,
+	0x1128, 0x68b4, 0xd0dc, 0x0110, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32,
+	0x0804, 0x3f26, 0xd6f4, 0x0130, 0x682f, 0x0000, 0x6833, 0x0000,
+	0x0804, 0x3f26, 0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x1da0,
+	0x7044, 0xa005, 0x1110, 0x7047, 0x0015, 0x2408, 0x2510, 0x2700,
+	0x8007, 0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32,
+	0x2100, 0xa205, 0x1110, 0x0804, 0x3f26, 0x7000, 0xa086, 0x0006,
+	0x0110, 0x0804, 0x3f26, 0x0005, 0x6946, 0x6008, 0xc0cd, 0xd3cc,
+	0x0108, 0xc08d, 0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f,
+	0x0000, 0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f,
+	0x0003, 0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b,
+	0x0020, 0x7000, 0x0002, 0x25a0, 0x3173, 0x316d, 0x316b, 0x316b,
+	0x316b, 0x316b, 0x316b, 0x080c, 0x254c, 0x6820, 0xd084, 0x1118,
+	0x080c, 0x37a4, 0x0030, 0x7058, 0x2c50, 0x2060, 0x6800, 0x6002,
+	0x2a60, 0xaea0, 0x0017, 0x2404, 0xa005, 0x0110, 0x2020, 0x0cd8,
+	0x2d22, 0x206b, 0x0000, 0x0005, 0x080c, 0x37aa, 0x080c, 0x37be,
+	0x6008, 0xc0cc, 0x600a, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14,
+	0x6938, 0x691a, 0x6944, 0x6916, 0x2009, 0x0000, 0xae86, 0x4640,
+	0x0110, 0x2009, 0x0001, 0x080c, 0x42ec, 0xd6dc, 0x01c8, 0x691c,
+	0xc1ed, 0x691e, 0x6828, 0xa082, 0x000e, 0x0290, 0x6848, 0xa084,
+	0x000f, 0xa086, 0x000b, 0x1160, 0x685c, 0xa086, 0x0047, 0x1140,
+	0x2001, 0x4601, 0x2004, 0xd0ac, 0x1118, 0x2700, 0x080c, 0x2475,
+	0x6818, 0xd0fc, 0x0140, 0x681b, 0x0000, 0x7868, 0xa08c, 0x00ff,
+	0x0110, 0x681b, 0x001e, 0xaea0, 0x0017, 0x6800, 0x2022, 0x6a3c,
+	0x6940, 0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, 0x0580,
+	0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x00d6, 0x00f6,
+	0x0156, 0x0146, 0x2079, 0x4600, 0x080c, 0x1b93, 0x014e, 0x015e,
+	0x00fe, 0x70c8, 0x2010, 0x2009, 0x0101, 0x0026, 0x2204, 0xa06d,
+	0x0140, 0x6814, 0xa706, 0x0110, 0x6800, 0x0cc8, 0x6820, 0xc0d5,
+	0x6822, 0x002e, 0x8210, 0x8109, 0x1d80, 0x00de, 0x7063, 0x0003,
+	0x707b, 0x0000, 0x7772, 0x707f, 0x000f, 0x71d0, 0xc1c4, 0x71d2,
+	0x6818, 0xa086, 0x0002, 0x1138, 0x6817, 0x0000, 0x682b, 0x0000,
+	0x681c, 0xc0ec, 0x681e, 0x080c, 0x1da2, 0x0804, 0x25a0, 0x7cd8,
+	0x7ddc, 0x7fd0, 0x080c, 0x30dc, 0x682b, 0x0000, 0x789b, 0x000e,
+	0x6f14, 0x080c, 0x3c4a, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc,
+	0x0110, 0x7044, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x7063, 0x0000,
+	0x0804, 0x25a0, 0x7000, 0xa005, 0x1110, 0x0804, 0x25a0, 0xa006,
+	0x080c, 0x3f26, 0x6920, 0xd1ac, 0x1110, 0x681b, 0x0014, 0xa68c,
+	0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0x6822,
+	0x7000, 0x0002, 0x25a0, 0x324c, 0x324c, 0x324f, 0x324f, 0x324f,
+	0x324a, 0x324a, 0x080c, 0x254c, 0x6818, 0x0804, 0x2f18, 0x6008,
+	0xc0a4, 0x600a, 0x6817, 0x0000, 0x0804, 0x3772, 0x2300, 0x0002,
+	0x325b, 0x325d, 0x32ab, 0x080c, 0x254c, 0xd6fc, 0x1904, 0x2d38,
+	0x7000, 0xa00d, 0x0002, 0x25a0, 0x326d, 0x326d, 0x3297, 0x326d,
+	0x32a8, 0x326b, 0x326b, 0x080c, 0x254c, 0xa684, 0x0060, 0x0538,
+	0xa086, 0x0060, 0x1510, 0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x6eb6,
+	0x681c, 0xc0ac, 0x681e, 0xa186, 0x0002, 0x0148, 0x080c, 0x3f26,
+	0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x4206, 0x0010, 0x080c,
+	0x41d9, 0x781b, 0x0083, 0x71d0, 0xd1b4, 0x1904, 0x259d, 0x70a0,
+	0xa086, 0x0001, 0x1904, 0x25e1, 0x0005, 0xd6ec, 0x09f0, 0x6818,
+	0xd0fc, 0x0170, 0xd6f4, 0x1130, 0x681b, 0x0015, 0x781b, 0x0083,
+	0x0804, 0x259d, 0x681b, 0x0007, 0x682f, 0x0000, 0x6833, 0x0000,
+	0x080c, 0x3bf1, 0x0005, 0x080c, 0x254c, 0x2300, 0x0002, 0x32b4,
+	0x32d6, 0x332e, 0x080c, 0x254c, 0x7000, 0x0002, 0x32be, 0x32c0,
+	0x32c7, 0x32be, 0x32be, 0x32be, 0x32be, 0x32be, 0x080c, 0x254c,
+	0x69ac, 0x68b0, 0xa115, 0x0118, 0x080c, 0x4206, 0x0010, 0x080c,
+	0x41d9, 0x681c, 0xc0b4, 0x681e, 0x70d0, 0xd0b4, 0x1904, 0x259d,
+	0x70a0, 0xa086, 0x0001, 0x1904, 0x25e1, 0x0005, 0xd6fc, 0x1904,
+	0x331e, 0x7000, 0xa00d, 0x0002, 0x25a0, 0x32ec, 0x32e6, 0x3316,
+	0x32ec, 0x331b, 0x32e4, 0x32e4, 0x080c, 0x254c, 0x6894, 0x78d6,
+	0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0x0538, 0xa086,
+	0x0060, 0x1510, 0xa6b4, 0xbfbf, 0xc6ed, 0x7e5a, 0x6eb6, 0xa186,
+	0x0002, 0x0148, 0x080c, 0x3f26, 0x69ac, 0x68b0, 0xa115, 0x0118,
+	0x080c, 0x4206, 0x0010, 0x080c, 0x41d9, 0x781b, 0x0083, 0x681c,
+	0xc0b4, 0x681e, 0x71d0, 0xd1b4, 0x1904, 0x259d, 0x70a0, 0xa086,
+	0x0001, 0x1904, 0x25e1, 0x0005, 0xd6ec, 0x09f0, 0x6818, 0xd0fc,
+	0x0110, 0x681b, 0x0007, 0x781b, 0x00fb, 0x0005, 0xc6fc, 0x7e5a,
+	0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200,
+	0xa303, 0x68ae, 0x79d2, 0x781b, 0x0083, 0x0005, 0xd6dc, 0x0130,
+	0x782b, 0x3009, 0x781b, 0x0083, 0x0804, 0x259d, 0x7884, 0xc0ac,
+	0x7886, 0x78e4, 0xa084, 0x0008, 0x1150, 0xa484, 0x0200, 0x0108,
+	0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0083, 0x0804, 0x259d, 0x6820,
+	0xc095, 0x6822, 0x080c, 0x3bdc, 0xc6dd, 0x080c, 0x3a3c, 0x781b,
+	0x0082, 0x0804, 0x259d, 0x2300, 0x0002, 0x3358, 0x335a, 0x335c,
+	0x080c, 0x254c, 0x0804, 0x3a36, 0x7d98, 0xd6d4, 0x15a8, 0x79e4,
+	0xd1ac, 0x0130, 0x78ec, 0xa084, 0x0003, 0x0110, 0x782b, 0x3009,
+	0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x7d9a,
+	0x79e4, 0xd1ac, 0x0120, 0x78ec, 0xa084, 0x0003, 0x1120, 0x2001,
+	0x0014, 0x0804, 0x2f18, 0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007,
+	0x0090, 0xa184, 0x0007, 0xa086, 0x0004, 0x1118, 0x2001, 0x0000,
+	0x0050, 0xa184, 0x0007, 0xa086, 0x0005, 0x0118, 0xa184, 0x0007,
+	0x0010, 0x2001, 0x0001, 0x04c2, 0x7a90, 0xa294, 0x0007, 0x789b,
+	0x0060, 0x79a8, 0x81ff, 0x0568, 0x789b, 0x0080, 0x7ba8, 0xa384,
+	0x0001, 0x11d0, 0x7ba8, 0x7ba8, 0xa386, 0x0004, 0x1118, 0x2009,
+	0xffdf, 0x0058, 0xa386, 0x0001, 0x1118, 0x2009, 0xfff7, 0x0028,
+	0xa386, 0x0003, 0x1148, 0x2009, 0xffef, 0x00c6, 0x7054, 0x2060,
+	0x6004, 0xa104, 0x6006, 0x00ce, 0x789b, 0x0060, 0x78ab, 0x0000,
+	0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xecff,
+	0x6922, 0x7d9a, 0x0804, 0x3be5, 0x2bae, 0x2bb7, 0x33d6, 0x33dc,
+	0x33d4, 0x33d4, 0x3be5, 0x3be5, 0x080c, 0x254c, 0x6920, 0xa18c,
+	0xfcff, 0x6922, 0x0804, 0x3beb, 0x6920, 0xa18c, 0xfcff, 0x6922,
+	0x0804, 0x3be5, 0x79e4, 0xa184, 0x0030, 0x0120, 0x78ec, 0xa084,
+	0x0003, 0x1570, 0x7000, 0xa086, 0x0004, 0x1190, 0x7060, 0xa086,
+	0x0002, 0x1130, 0x2011, 0x0002, 0x2019, 0x0000, 0x0804, 0x2a56,
+	0x7060, 0xa086, 0x0006, 0x0db0, 0x7060, 0xa086, 0x0004, 0x0d90,
+	0x7000, 0xa086, 0x0000, 0x0904, 0x259d, 0x6920, 0xa184, 0x0420,
+	0x0128, 0xc1d4, 0x6922, 0x6818, 0x0804, 0x2f18, 0x6818, 0xa08e,
+	0x0002, 0x0120, 0xc0fd, 0x681a, 0x2001, 0x0014, 0x0804, 0x2f18,
+	0x7884, 0xd0fc, 0x1118, 0xa184, 0x0007, 0x0090, 0xa184, 0x0007,
+	0xa086, 0x0004, 0x1118, 0x2001, 0x0000, 0x0050, 0xa184, 0x0007,
+	0xa086, 0x0005, 0x0118, 0xa184, 0x0007, 0x0010, 0x2001, 0x0001,
+	0x0002, 0x3be5, 0x3be5, 0x3439, 0x3be5, 0x3c29, 0x3c29, 0x3be5,
+	0x3be5, 0xd6bc, 0x0570, 0x7180, 0x81ff, 0x0558, 0xa182, 0x000d,
+	0x1318, 0x7083, 0x0000, 0x0028, 0xa182, 0x000c, 0x7082, 0x2009,
+	0x000c, 0x789b, 0x0061, 0x79aa, 0x0156, 0x0136, 0x0146, 0x7084,
+	0x8114, 0xa210, 0x7286, 0xa080, 0x000b, 0xad00, 0x2098, 0xb284,
+	0x0600, 0x0118, 0x20a1, 0x022b, 0x0010, 0x20a1, 0x012b, 0x789b,
+	0x0000, 0x8108, 0x81ac, 0x53a6, 0x014e, 0x013e, 0x015e, 0x0804,
+	0x3beb, 0xd6d4, 0x1904, 0x34ac, 0x6820, 0xd084, 0x0904, 0x3beb,
+	0xa68c, 0x0060, 0xa684, 0x0060, 0x0120, 0xa086, 0x0060, 0x1108,
+	0xc1f5, 0xc194, 0x795a, 0x69b6, 0x789b, 0x0060, 0x78ab, 0x0000,
+	0x789b, 0x0061, 0x6818, 0xc0fd, 0x681a, 0x78aa, 0x8008, 0x810c,
+	0x0904, 0x37d3, 0xa18c, 0x00f8, 0x1904, 0x37d3, 0x0156, 0x0136,
+	0x0146, 0x0016, 0x20a1, 0x012b, 0x3208, 0xa18c, 0x0600, 0x0110,
+	0x20a1, 0x022b, 0x001e, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80,
+	0x000b, 0x2098, 0x53a6, 0x014e, 0x013e, 0x015e, 0x6814, 0xc0fc,
+	0x8007, 0x7882, 0x0804, 0x3beb, 0x6818, 0xd0fc, 0x0110, 0x681b,
+	0x0008, 0x080c, 0x3a3c, 0x781b, 0x00ed, 0x0005, 0x2300, 0x0002,
+	0x34bd, 0x357a, 0x34bb, 0x080c, 0x254c, 0x7cd8, 0x7ddc, 0x7fd0,
+	0x82ff, 0x1528, 0x7200, 0xa286, 0x0003, 0x0904, 0x2ee6, 0x71d0,
+	0xd1bc, 0x11f8, 0xd1b4, 0x01e8, 0x2001, 0x4601, 0x2004, 0xd0c4,
+	0x11c0, 0x00d6, 0x783b, 0x8800, 0x781b, 0x0059, 0x70b8, 0xa06d,
+	0x68b4, 0xc0a5, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2,
+	0x78da, 0xc1b4, 0x71d2, 0x7003, 0x0030, 0x00de, 0x0030, 0x7200,
+	0x0020, 0x783b, 0x1800, 0x781b, 0x0057, 0xa284, 0x000f, 0x0002,
+	0x3565, 0x3522, 0x34fa, 0x2f15, 0x34f8, 0x3565, 0x34f8, 0x34f8,
+	0x080c, 0x254c, 0x681c, 0xd0ec, 0x0118, 0x6008, 0xc08d, 0x600a,
+	0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005, 0x1108, 0x6002,
+	0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084, 0x000e, 0x1120, 0x71c8,
+	0xa188, 0x0100, 0x0028, 0x7030, 0x68ba, 0x713c, 0x70c8, 0xa108,
+	0x2104, 0x6802, 0x2d0a, 0x715a, 0xd6dc, 0x1120, 0xc6fc, 0x6eb6,
+	0x0804, 0x3565, 0x6eb6, 0xa684, 0x0060, 0x1120, 0xa684, 0x7fff,
+	0x68b6, 0x04d8, 0xd6dc, 0x1150, 0xa684, 0x7fff, 0x68b6, 0x6894,
+	0x68a6, 0x6898, 0x68aa, 0x080c, 0x3f26, 0x0478, 0xd6ac, 0x0140,
+	0xa006, 0x080c, 0x3f26, 0x2408, 0x2510, 0x69aa, 0x6aa6, 0x0068,
+	0x2408, 0x2510, 0x2700, 0x8007, 0xa084, 0x007f, 0xa108, 0xa291,
+	0x0000, 0x69aa, 0x6aa6, 0x080c, 0x3f26, 0xd6fc, 0x01b0, 0xa684,
+	0x7fff, 0x68b6, 0x2510, 0x2408, 0xd6ac, 0x1138, 0x2700, 0x8007,
+	0xa084, 0x007f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302,
+	0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x7000, 0xa086, 0x0030,
+	0x1904, 0x25a0, 0x7003, 0x0002, 0x70b8, 0xa06d, 0x68bc, 0x703e,
+	0x70b4, 0xa065, 0x68c0, 0x7056, 0x2d00, 0x704a, 0xad80, 0x0009,
+	0x7042, 0x0005, 0xa586, 0x8800, 0x1148, 0x7003, 0x0000, 0x6018,
+	0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a, 0x0804, 0x3a36,
+	0x7043, 0x0000, 0xa282, 0x0006, 0x0310, 0x080c, 0x254c, 0x2300,
+	0x0002, 0x3594, 0x35a5, 0x35af, 0x2200, 0x0002, 0x359c, 0x3a36,
+	0x359e, 0x359c, 0x35e0, 0x362e, 0x080c, 0x254c, 0x7a80, 0xa294,
+	0x0f00, 0x080c, 0x3682, 0x0804, 0x3a0b, 0x00c1, 0x0002, 0x3a36,
+	0x35ad, 0x35ad, 0x35e0, 0x35ad, 0x3a36, 0x080c, 0x254c, 0x0071,
+	0x0002, 0x35b9, 0x35b7, 0x35b7, 0x35b9, 0x35b7, 0x35b9, 0x080c,
+	0x254c, 0x080c, 0x3a4b, 0x781b, 0x0082, 0x0005, 0x7000, 0xa086,
+	0x0002, 0x1150, 0x080c, 0x37be, 0x0010, 0x080c, 0x3f26, 0x6008,
+	0xa084, 0xfbef, 0x600a, 0x0020, 0x7000, 0xa086, 0x0003, 0x0da8,
+	0x7003, 0x0005, 0x2001, 0x8de0, 0xae8e, 0x4640, 0x0110, 0x2001,
+	0x8e12, 0x2068, 0x704a, 0xad80, 0x0009, 0x7042, 0x2200, 0x0005,
+	0x7000, 0xa086, 0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, 0x2c00,
+	0x70b6, 0x2d00, 0x70ba, 0x0038, 0x080c, 0x3f26, 0x0020, 0x7000,
+	0xa086, 0x0003, 0x0dc8, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00,
+	0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x8cc0,
+	0xb284, 0x0600, 0x1118, 0xc2fd, 0x2069, 0x8dd0, 0x2d04, 0x2d08,
+	0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, 0x0120, 0x6800, 0x0cb8,
+	0x080c, 0x3682, 0x6eb4, 0x7e5a, 0x6920, 0xa184, 0x0c00, 0x0904,
+	0x36a8, 0x7060, 0xa086, 0x0006, 0x1128, 0x7070, 0xa206, 0x1110,
+	0x7062, 0x707a, 0x681b, 0x0005, 0xc1ad, 0x681b, 0x0005, 0xc1ad,
+	0xc1d4, 0x6922, 0x080c, 0x3a42, 0x0804, 0x36a8, 0x7200, 0xa286,
+	0x0002, 0x1158, 0x70d0, 0xc0b5, 0x70d2, 0x2c00, 0x70b6, 0x2d00,
+	0x70ba, 0x0030, 0x080c, 0x3f26, 0x0018, 0xa286, 0x0003, 0x0dd0,
+	0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8,
+	0xa484, 0x001f, 0xa215, 0xae86, 0x4640, 0x0108, 0xc2fd, 0x79a8,
+	0x79a8, 0xa18c, 0x00ff, 0x2118, 0x70c8, 0xa168, 0x2d04, 0x2d08,
+	0x715a, 0xa06d, 0x0128, 0x6814, 0xa206, 0x0118, 0x6800, 0x0cb8,
+	0x0409, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0904, 0x36a8, 0xd0dc,
+	0x0178, 0x7060, 0xa086, 0x0004, 0x1140, 0x7070, 0xa206, 0x1128,
+	0x7074, 0xa306, 0x1110, 0x7062, 0x707a, 0x080c, 0x3a48, 0x0480,
+	0x681b, 0x0005, 0xc1ad, 0xc1d4, 0x6922, 0x080c, 0x3a42, 0x707b,
+	0x0000, 0x0430, 0x7003, 0x0005, 0xb284, 0x0600, 0x0118, 0x2001,
+	0x8de0, 0x0010, 0x2001, 0x8e12, 0x2068, 0x704a, 0x0156, 0x20a9,
+	0x0032, 0x2003, 0x0000, 0x8000, 0x1f04, 0x3691, 0x015e, 0xb284,
+	0x0600, 0x0110, 0xc2fc, 0x0008, 0xc2fd, 0x6a16, 0xad80, 0x0009,
+	0x7042, 0x68b7, 0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x0005,
+	0xc6ec, 0xa6ac, 0x0060, 0x0904, 0x36ef, 0x6b98, 0x6c94, 0x69ac,
+	0x68b0, 0xa105, 0x11e0, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa586,
+	0x0060, 0x05c8, 0xd6f4, 0x1108, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a,
+	0x2009, 0x0083, 0xd69c, 0x0128, 0x2009, 0x0082, 0x2019, 0x0000,
+	0x2320, 0x791a, 0xd6ec, 0x0588, 0x080c, 0x41d9, 0x0470, 0x68b0,
+	0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x01f8, 0x7bd2, 0x7bda,
+	0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x1108, 0xc6ed, 0xc6f4, 0x7e5a,
+	0x2011, 0x0083, 0xd69c, 0x0128, 0x2011, 0x0082, 0x2019, 0x0000,
+	0x2320, 0x7a1a, 0xd6ec, 0x0188, 0x080c, 0x4206, 0x0070, 0x2019,
+	0x0000, 0x2320, 0x0010, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0083,
+	0xd69c, 0x0110, 0x2009, 0x0082, 0x791a, 0x68c0, 0x7056, 0x2d00,
+	0x704a, 0x68c4, 0x2060, 0x71d0, 0x2001, 0x4601, 0x2004, 0xd0c4,
+	0x15c8, 0x70d4, 0xa02d, 0x01b8, 0xd1bc, 0x0548, 0x7a80, 0xa294,
+	0x0f00, 0x70d8, 0xa206, 0x0118, 0x78e0, 0xa504, 0x1558, 0x70d6,
+	0xc1bc, 0x71d2, 0x0438, 0x2031, 0x0001, 0x852c, 0x0218, 0x8633,
+	0x8210, 0x0cd8, 0x0005, 0x7de0, 0xa594, 0xff00, 0x0130, 0x2011,
+	0x0008, 0x852f, 0x0c81, 0x8637, 0x0008, 0x0c69, 0x8217, 0x7880,
+	0xa084, 0x0f00, 0xa206, 0x0170, 0x72da, 0x76d6, 0x0058, 0x7a80,
+	0xa294, 0x0f00, 0x70d8, 0xa236, 0x0dc0, 0x78e0, 0xa534, 0x0da8,
+	0xc1bd, 0x71d2, 0xd1b4, 0x1904, 0x259d, 0x2300, 0xa405, 0x0904,
+	0x259d, 0x70a0, 0xa086, 0x0001, 0x1904, 0x25e1, 0x0005, 0x6020,
+	0xa005, 0x0150, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a,
+	0x700f, 0x0100, 0x702c, 0x6026, 0x0005, 0xa006, 0x080c, 0x3f26,
+	0x7000, 0xa086, 0x0002, 0x0120, 0x7060, 0xa086, 0x0005, 0x1150,
+	0x682b, 0x0000, 0x6817, 0x0000, 0x681b, 0x0001, 0x6823, 0x0040,
+	0x681f, 0x0100, 0x7000, 0xa084, 0x000f, 0x0002, 0x25a0, 0x3783,
+	0x3780, 0x37a0, 0x378c, 0x25a0, 0x377e, 0x377e, 0x080c, 0x254c,
+	0x0449, 0x0411, 0x0028, 0x0431, 0x7058, 0x2060, 0x6800, 0x6002,
+	0x080c, 0x1da2, 0x0804, 0x25a0, 0x7060, 0x7063, 0x0000, 0x707f,
+	0x0000, 0x0002, 0x379c, 0x379c, 0x379a, 0x379a, 0x379a, 0x379c,
+	0x379a, 0x379c, 0x0804, 0x2a6b, 0x7063, 0x0000, 0x0804, 0x25a0,
+	0x681b, 0x0000, 0x0804, 0x3184, 0x6800, 0xa005, 0x1108, 0x6002,
+	0x6006, 0x0005, 0x6410, 0x84ff, 0x0168, 0x2009, 0x4602, 0x2104,
+	0x8001, 0x200a, 0x8421, 0x6412, 0x1128, 0x2021, 0x4604, 0x2404,
+	0xc0a5, 0x2022, 0x6008, 0xc0a4, 0x600a, 0x0005, 0x6018, 0xa005,
+	0x0110, 0x8001, 0x601a, 0x0005, 0x080c, 0x3c46, 0x681b, 0x0018,
+	0x0490, 0x080c, 0x3c46, 0x681b, 0x0019, 0x0468, 0x080c, 0x3c46,
+	0x681b, 0x001a, 0x0440, 0x080c, 0x3c46, 0x681b, 0x0003, 0x0418,
+	0x7770, 0x080c, 0x3b6f, 0x7174, 0xa18c, 0x00ff, 0x3210, 0xa294,
+	0x0600, 0x0118, 0xa1e8, 0x8bc0, 0x0010, 0xa1e8, 0x8cd0, 0x2d04,
+	0x2d08, 0x2068, 0xa005, 0x1118, 0x707a, 0x0804, 0x25a0, 0x6814,
+	0x7270, 0xa206, 0x0110, 0x6800, 0x0c98, 0x6800, 0x200a, 0x681b,
+	0x0005, 0x707b, 0x0000, 0x080c, 0x37aa, 0x6820, 0xd084, 0x1110,
+	0x080c, 0x37a4, 0x080c, 0x37be, 0x681f, 0x0000, 0x6823, 0x0020,
+	0x080c, 0x1da2, 0x0804, 0x25a0, 0xa282, 0x0003, 0x1904, 0x3a10,
+	0x7da8, 0xa5ac, 0x00ff, 0x7ea8, 0xa6b4, 0x00ff, 0x6920, 0xc1bd,
+	0x6922, 0xd1c4, 0x05b0, 0xc1c4, 0x6922, 0xa6b4, 0x00ff, 0x0530,
+	0xa682, 0x0018, 0x0218, 0x0110, 0x2031, 0x0018, 0xa686, 0x0010,
+	0x1108, 0x8630, 0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x3ac9,
+	0x0118, 0x080c, 0x38f7, 0x00a0, 0x080c, 0x3a95, 0x080c, 0x38f4,
+	0x6920, 0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118,
+	0x781b, 0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x080c, 0x38f4,
+	0x7e58, 0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083,
+	0x0005, 0x00c6, 0x7054, 0x2060, 0x6100, 0xd1e4, 0x0598, 0x6208,
+	0x8217, 0xa294, 0x00ff, 0xa282, 0x0018, 0x0218, 0x0110, 0x2011,
+	0x0018, 0x2600, 0xa202, 0x1208, 0x2230, 0xa686, 0x0010, 0x1108,
+	0x8630, 0x6208, 0xa294, 0x00ff, 0x78ec, 0xd0e4, 0x0130, 0xa282,
+	0x000a, 0x1240, 0x2011, 0x000a, 0x0028, 0xa282, 0x000c, 0x1210,
+	0x2011, 0x000c, 0x2200, 0xa502, 0x1208, 0x2228, 0x080c, 0x3a99,
+	0x852b, 0x852b, 0x2041, 0x0000, 0x080c, 0x3ac9, 0x0118, 0x080c,
+	0x38f7, 0x0020, 0x080c, 0x3a95, 0x080c, 0x38f4, 0x7858, 0xc095,
+	0x785a, 0x00ce, 0x781b, 0x0082, 0x0005, 0x00c6, 0x2960, 0x6000,
+	0xd0e4, 0x1188, 0xd0b4, 0x1150, 0x6010, 0xa084, 0x000f, 0x1130,
+	0x6104, 0xa18c, 0xfff5, 0x6106, 0x00ce, 0x0005, 0x2011, 0x0032,
+	0x2019, 0x0000, 0x00f0, 0x68a0, 0xd0cc, 0x1dc0, 0x6208, 0xa294,
+	0x00ff, 0x78ec, 0xd0e4, 0x0130, 0xa282, 0x000b, 0x1218, 0x2011,
+	0x000a, 0x0028, 0xa282, 0x000c, 0x1210, 0x2011, 0x000c, 0x6308,
+	0x831f, 0xa39c, 0x00ff, 0xa382, 0x0018, 0x0218, 0x0110, 0x2019,
+	0x0018, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa,
+	0x7baa, 0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x080c, 0x3a55,
+	0x00ce, 0x0005, 0x00c6, 0x2960, 0x6104, 0xa18c, 0xfff5, 0x6106,
+	0x2011, 0x0032, 0x2019, 0x0000, 0x0000, 0x78ab, 0x0001, 0x78ab,
+	0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x6820,
+	0xc0c5, 0x6822, 0x00ce, 0x0005, 0xa006, 0x2030, 0x2010, 0x00c6,
+	0x7154, 0x2160, 0x2018, 0x2008, 0xa084, 0xffe0, 0xa635, 0x7e86,
+	0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4, 0xa084, 0x7770, 0xa18c,
+	0x000f, 0xa105, 0x2029, 0x4605, 0x252c, 0xd5cc, 0x0140, 0xd3a4,
+	0x0110, 0xa085, 0x0800, 0xd3fc, 0x0110, 0xa085, 0x8080, 0x78a6,
+	0x6016, 0x788a, 0xa6b4, 0x001f, 0x8637, 0x8204, 0x8004, 0xa605,
+	0x600e, 0x6004, 0xa084, 0xffd5, 0x6006, 0x00ce, 0x0005, 0xa282,
+	0x0002, 0x1904, 0x3a1a, 0x7aa8, 0x6920, 0xc1bd, 0x6922, 0xd1cc,
+	0x0568, 0xc1cc, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x1a04,
+	0x3a0b, 0x080c, 0x399e, 0x080c, 0x38f4, 0xa980, 0x0001, 0x200c,
+	0x080c, 0x3b6b, 0x080c, 0x3895, 0x88ff, 0x0178, 0x789b, 0x0060,
+	0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x1118, 0x781b,
+	0x006e, 0x0005, 0x781b, 0x0082, 0x0005, 0x7e58, 0xd6d4, 0x1118,
+	0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005, 0xa282, 0x0002,
+	0x1218, 0xa284, 0x0001, 0x0140, 0x7154, 0xa188, 0x0000, 0x210c,
+	0xd1ec, 0x1110, 0x2011, 0x0000, 0x080c, 0x3a87, 0x0479, 0x080c,
+	0x38f4, 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x00c6,
+	0x0026, 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec, 0x1158, 0xd0bc,
+	0x1138, 0x6014, 0xd0b4, 0x1120, 0xc1a4, 0x6106, 0xa006, 0x0088,
+	0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003,
+	0x7aaa, 0xa8c0, 0x0004, 0x080c, 0x3a55, 0x6820, 0xa085, 0x0200,
+	0x6822, 0x002e, 0x00ce, 0x0005, 0x8807, 0xa715, 0x00c6, 0x2009,
+	0x0000, 0x7054, 0x2060, 0x82ff, 0x0110, 0x2009, 0x0040, 0x6018,
+	0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xff9f, 0xa105, 0xc0ec,
+	0xd0b4, 0x1108, 0xc0ed, 0x6100, 0xd1f4, 0x0110, 0xa085, 0x0020,
+	0x78a6, 0x6016, 0x788a, 0x6004, 0xa084, 0xffef, 0x6006, 0x00ce,
+	0x0005, 0x0006, 0x7000, 0xa086, 0x0003, 0x0110, 0x000e, 0x0010,
+	0x000e, 0x0488, 0xd6ac, 0x0578, 0x7888, 0xa084, 0x0040, 0x0558,
+	0x7bb8, 0x8307, 0xa084, 0x007f, 0x1508, 0x8207, 0xa084, 0x00ff,
+	0xa09e, 0x0001, 0x1904, 0x3a32, 0xd6f4, 0x11d0, 0x79d8, 0x7adc,
+	0xa108, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade, 0x080c,
+	0x42b5, 0x781b, 0x0080, 0xb284, 0x0600, 0x0118, 0x2001, 0x0000,
+	0x0010, 0x2001, 0x0001, 0x080c, 0x4172, 0x0005, 0x080c, 0x254c,
+	0x781b, 0x0080, 0x0005, 0x781b, 0x0083, 0x0005, 0x2039, 0x0000,
+	0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x080c, 0x38f7,
+	0x080c, 0x399c, 0x7e58, 0x080c, 0x3a4e, 0x781b, 0x0082, 0x0005,
+	0x0cd1, 0x6820, 0xc0c4, 0x6822, 0x00c6, 0x7054, 0x2060, 0x080c,
+	0x3921, 0x00b0, 0x0c81, 0x6820, 0xc0cc, 0x6822, 0x00c6, 0x7054,
+	0x2060, 0x080c, 0x39bb, 0x0060, 0x0c31, 0x6820, 0xa084, 0xecff,
+	0x6822, 0x00c6, 0x7054, 0x2060, 0x6004, 0xa084, 0xffc5, 0x6006,
+	0x00ce, 0x0005, 0x0049, 0x781b, 0x0082, 0x0005, 0x6827, 0x0002,
+	0x0049, 0x781b, 0x0082, 0x0005, 0x2001, 0x0005, 0x0088, 0x2001,
+	0x000c, 0x0070, 0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0040,
+	0x2001, 0x000d, 0x0028, 0x2001, 0x0009, 0x0010, 0x2001, 0x0007,
+	0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d0, 0xd0b4, 0x0168,
+	0xc0b4, 0x70d2, 0x00c6, 0x70b4, 0xa065, 0x6008, 0xa084, 0xfbef,
+	0x600a, 0x6018, 0x8001, 0x601a, 0x00ce, 0x0005, 0x0076, 0x873f,
+	0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, 0x4ac0, 0xae8e,
+	0x4640, 0x0110, 0xa0e0, 0x4b40, 0xa7b8, 0x0020, 0x7f9a, 0x79a4,
+	0xa184, 0x7fe0, 0x78ae, 0x6012, 0x79a4, 0xa184, 0x773f, 0x78a6,
+	0x6016, 0x6004, 0xa085, 0x0038, 0x6006, 0x007e, 0x0005, 0x789b,
+	0x0080, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa,
+	0x789b, 0x0060, 0x78ab, 0x0004, 0x0800, 0x2031, 0x0000, 0x2029,
+	0x0032, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+	0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x0804,
+	0x3a55, 0x0156, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080,
+	0x0020, 0x789a, 0x79a4, 0xa18c, 0xffe0, 0x2021, 0x3b54, 0x2019,
+	0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x2404, 0xa084, 0xffe0,
+	0xa106, 0x0128, 0x8420, 0x2300, 0xa210, 0x1f04, 0x3abd, 0x015e,
+	0x0005, 0x0156, 0x04f8, 0x2021, 0x3b62, 0x20a9, 0x0009, 0x2011,
+	0x0029, 0xa582, 0x0028, 0x0550, 0x8420, 0x95a9, 0x2011, 0x0033,
+	0xa582, 0x0033, 0x0618, 0x8420, 0x95a9, 0x2019, 0x000a, 0x2011,
+	0x0065, 0x2200, 0xa502, 0x02d0, 0x8420, 0x2300, 0xa210, 0x1f04,
+	0x3ae1, 0x015e, 0x0088, 0x2021, 0x3b54, 0x2019, 0x0011, 0x20a9,
+	0x000e, 0x2011, 0x0033, 0x2200, 0xa502, 0x0240, 0x8420, 0x2300,
+	0xa210, 0x1f04, 0x3af3, 0x015e, 0xa006, 0x0005, 0x8211, 0x015e,
+	0xa582, 0x0064, 0x1220, 0x7808, 0xa085, 0x0070, 0x780a, 0x2404,
+	0xa005, 0x0005, 0xa886, 0x0002, 0x01e8, 0x2021, 0x3b40, 0x20a9,
+	0x000d, 0x2011, 0x0028, 0xa582, 0x0028, 0x0d48, 0x8420, 0x2019,
+	0x0019, 0x2011, 0x0033, 0x2200, 0xa502, 0x0e00, 0x8420, 0x2300,
+	0xa210, 0x1f04, 0x3b1b, 0x015e, 0x2011, 0x0184, 0xa582, 0x0185,
+	0x0ab0, 0x0890, 0x2021, 0x3b4f, 0x20a9, 0x0003, 0x2011, 0x0024,
+	0xa586, 0x0024, 0x0960, 0x8420, 0x2011, 0x0028, 0xa586, 0x0028,
+	0x0930, 0x8420, 0x2019, 0x0019, 0x2011, 0x0033, 0x0804, 0x3af3,
+	0x1021, 0x2202, 0x3403, 0x4604, 0x5805, 0x6a06, 0x7c07, 0x4610,
+	0x4612, 0x5812, 0x5a12, 0x6a14, 0x6c14, 0x6e14, 0x7e17, 0x9021,
+	0xb002, 0xe204, 0xe210, 0xe210, 0x1209, 0x3002, 0x3202, 0x4203,
+	0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07,
+	0x0c07, 0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06,
+	0x7c07, 0x7e07, 0x0e00, 0x789b, 0x0080, 0xa046, 0x0005, 0xa784,
+	0x0f00, 0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003,
+	0xa105, 0xd7fc, 0x0118, 0xa0e0, 0x6bc0, 0x0010, 0xa0e0, 0x4bc0,
+	0x0005, 0x00e6, 0x00f6, 0xd084, 0x0138, 0x2079, 0x0100, 0x2009,
+	0x4680, 0x2071, 0x4680, 0x0030, 0x2009, 0x4640, 0x2079, 0x0200,
+	0x2071, 0x4640, 0x2091, 0x8000, 0x2104, 0xa084, 0x000f, 0x0002,
+	0x3ba2, 0x3ba2, 0x3ba2, 0x3ba2, 0x3ba2, 0x3ba2, 0x3ba0, 0x3ba0,
+	0x080c, 0x254c, 0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005,
+	0x0580, 0x7858, 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828,
+	0xa086, 0x1814, 0x1530, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004,
+	0x1de0, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x1de0, 0x7830,
+	0xd0bc, 0x11b8, 0xb284, 0x0800, 0x0118, 0x0104, 0x3bd9, 0x0010,
+	0x0304, 0x3bd9, 0x79e4, 0xa184, 0x0030, 0x0158, 0x78ec, 0xa084,
+	0x0003, 0x0138, 0x681c, 0xd0ac, 0x1110, 0x00d9, 0x0010, 0x781b,
+	0x00fb, 0x00fe, 0x00ee, 0x0005, 0x2001, 0x4601, 0x2004, 0xd0ac,
+	0x1118, 0x6814, 0x080c, 0x2475, 0x0005, 0x781b, 0x0083, 0x0005,
+	0x781b, 0x0082, 0x0005, 0x781b, 0x0071, 0x0005, 0x781b, 0x006e,
+	0x0005, 0x2009, 0x4619, 0x210c, 0xa186, 0x0000, 0x0150, 0xa186,
+	0x0001, 0x0150, 0x701f, 0x000b, 0x7063, 0x0001, 0x781b, 0x0054,
+	0x0005, 0x781b, 0x00f3, 0x0005, 0x701f, 0x000a, 0x0005, 0x2009,
+	0x4619, 0x210c, 0xa186, 0x0000, 0x0168, 0xa186, 0x0001, 0x0138,
+	0x701f, 0x000b, 0x7063, 0x0001, 0x781b, 0x0054, 0x0005, 0x701f,
+	0x000a, 0x0005, 0x781b, 0x00f2, 0x0005, 0x781b, 0x00fb, 0x0005,
+	0x781b, 0x00fa, 0x0005, 0x781b, 0x00cc, 0x0005, 0x781b, 0x00cb,
+	0x0005, 0x6818, 0xd0fc, 0x0110, 0x681b, 0x001d, 0x7063, 0x0001,
+	0x781b, 0x0054, 0x0005, 0x7830, 0xa084, 0x00c0, 0x1170, 0x7808,
+	0xc08c, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000, 0x78ec, 0xa084,
+	0x0021, 0x0118, 0x7808, 0xc08d, 0x780a, 0x0005, 0x7808, 0xc08d,
+	0x780a, 0x0005, 0x7830, 0xa084, 0x0040, 0x1de0, 0xb284, 0x0800,
+	0x0118, 0x1104, 0x3c58, 0x0010, 0x1304, 0x3c58, 0x78ac, 0x0005,
+	0x7808, 0xa084, 0xfffd, 0x780a, 0xe000, 0xe000, 0xe000, 0xe000,
+	0x78ec, 0xa084, 0x0021, 0x0140, 0xb284, 0x0800, 0x0118, 0x1104,
+	0x3c67, 0x0010, 0x1304, 0x3c6a, 0x78ac, 0x0006, 0x7808, 0xa085,
+	0x0002, 0x780a, 0x000e, 0x0005, 0xa784, 0x0001, 0x1904, 0x322a,
+	0xa784, 0x0070, 0x0140, 0x00c6, 0x2d60, 0x2f68, 0x080c, 0x2467,
+	0x2d78, 0x2c68, 0x00ce, 0xa784, 0x0008, 0x0148, 0x784b, 0x0008,
+	0x78ec, 0xa084, 0x0003, 0x0904, 0x322a, 0x0804, 0x3be5, 0xa784,
+	0x0004, 0x01c8, 0x78b8, 0xa084, 0x8000, 0x01a8, 0x784b, 0x0008,
+	0x78ec, 0xa084, 0x0003, 0x0904, 0x322a, 0x78e4, 0xa084, 0x0007,
+	0xa086, 0x0001, 0x1140, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a,
+	0x781b, 0x00fb, 0x0005, 0xa784, 0x0080, 0x0140, 0x7884, 0xd0fc,
+	0x0128, 0x080c, 0x3a32, 0x681b, 0x0022, 0x0005, 0x681b, 0x0003,
+	0x7858, 0xa084, 0x5f00, 0x681e, 0x682f, 0x0000, 0x6833, 0x0000,
+	0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0904, 0x2b89, 0xb284,
+	0x0800, 0x0110, 0x0104, 0x259d, 0x0304, 0x259d, 0x6b14, 0x8307,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xd3fc, 0x0118, 0xa080,
+	0x4b40, 0x0010, 0xa080, 0x4ac0, 0x2060, 0x2048, 0x7056, 0x2a60,
+	0x0005, 0x00c6, 0x2960, 0x6000, 0xd0ac, 0x0904, 0x3d2f, 0x68a0,
+	0xd1ac, 0x1120, 0xa084, 0x0e00, 0x0904, 0x3d2d, 0x6108, 0x8117,
+	0xa18c, 0x00ff, 0x631c, 0x832f, 0xd0dc, 0x0110, 0xa39d, 0x0001,
+	0xd0cc, 0x11c8, 0xa584, 0x00ff, 0x0138, 0x78ec, 0xd0e4, 0x0110,
+	0x8213, 0x00b8, 0x2029, 0x0000, 0xa182, 0x000c, 0x1290, 0x78ec,
+	0xd0e4, 0x1118, 0x2009, 0x000c, 0x0060, 0xa182, 0x000b, 0x1248,
+	0x2009, 0x000a, 0x0030, 0x2009, 0x0032, 0x2011, 0x0000, 0x2029,
+	0x0000, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab, 0x0004, 0x79aa,
+	0x78ab, 0x0000, 0x7aaa, 0x7baa, 0x7daa, 0xa8c0, 0x0008, 0x6820,
+	0xa085, 0x1000, 0x6822, 0x080c, 0x3a55, 0xa085, 0x0001, 0x00ce,
+	0x0005, 0xa282, 0x0006, 0x1904, 0x3a24, 0x7da8, 0x7eac, 0x8637,
+	0xa5ac, 0x00ff, 0xa6b4, 0x00ff, 0x7fac, 0x8747, 0xa7bc, 0x00ff,
+	0xa8c4, 0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1e4, 0x0904, 0x3da3,
+	0xa18c, 0xecff, 0x6922, 0xa782, 0x0002, 0x1a04, 0x39fe, 0xa6b4,
+	0x00ff, 0x0904, 0x3da0, 0xa682, 0x0031, 0x1a04, 0x39fe, 0xa582,
+	0x0009, 0x0a04, 0x39fe, 0xa882, 0x0003, 0x1a04, 0x39fe, 0xa886,
+	0x0002, 0x01d0, 0xa886, 0x0000, 0x1904, 0x39fe, 0x2001, 0x000c,
+	0x79ec, 0xd1e4, 0x0110, 0x2001, 0x000a, 0xa502, 0x1290, 0x080c,
+	0x39fe, 0x00c6, 0x2960, 0x6004, 0xa085, 0x001a, 0x6006, 0x6000,
+	0xc0ac, 0x6002, 0x00ce, 0x0005, 0xa786, 0x0000, 0x0904, 0x39fe,
+	0x8634, 0xa682, 0x0018, 0x0228, 0x0120, 0x2031, 0x0018, 0x0804,
+	0x3df1, 0xa686, 0x0010, 0x1108, 0x8630, 0x852b, 0x852b, 0x080c,
+	0x3ac9, 0x0904, 0x39fe, 0x080c, 0x38f7, 0x080c, 0x399c, 0x7e58,
+	0xd6d4, 0x1118, 0x781b, 0x0071, 0x0005, 0x781b, 0x0083, 0x0005,
+	0x080c, 0x38f4, 0x0c90, 0xa886, 0x0002, 0x1108, 0x8634, 0x7154,
+	0xa188, 0x0000, 0x210c, 0xd1ac, 0x0904, 0x39fe, 0xd1ec, 0x1120,
+	0x2039, 0x0000, 0x2041, 0x0000, 0xd1e4, 0x1120, 0x2031, 0x0000,
+	0x2041, 0x0000, 0xa782, 0x0002, 0x12c8, 0x621c, 0xa284, 0x00ff,
+	0xa706, 0x0110, 0x2039, 0x0000, 0xa605, 0x0190, 0x6108, 0x811f,
+	0xa39c, 0x00ff, 0x0168, 0xa302, 0x1208, 0x2330, 0x8807, 0xa705,
+	0xa086, 0x0201, 0x0160, 0xa886, 0x0000, 0x0168, 0x2039, 0x0000,
+	0x2041, 0x0000, 0x2031, 0x0000, 0xa006, 0x2010, 0x0070, 0xa284,
+	0xff00, 0x1108, 0x2040, 0xa184, 0x00ff, 0xa502, 0x0108, 0x2128,
+	0x852b, 0x852b, 0x080c, 0x3ac9, 0x0d58, 0x080c, 0x38f7, 0x080c,
+	0x399c, 0x789b, 0x0080, 0x78ab, 0x0001, 0x78ab, 0x0006, 0x78ab,
+	0x0004, 0x7daa, 0x78ab, 0x0000, 0x7eaa, 0x7faa, 0x2800, 0x78aa,
+	0x789b, 0x0060, 0x78ab, 0x0008, 0x6820, 0xc0e5, 0x6822, 0x080c,
+	0x3a55, 0x7858, 0xc095, 0x785a, 0x781b, 0x0082, 0x0005, 0x0020,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9855, 0x984d, 0x0014,
+	0x9911, 0x98ff, 0x0014, 0x0014, 0x0090, 0x00e7, 0x0100, 0x0402,
+	0x2008, 0xf880, 0x0018, 0x0017, 0x840f, 0xd8c1, 0x0014, 0x0016,
+	0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014, 0x2500, 0x0013, 0x2500,
+	0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
+	0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0xa200, 0x3806,
+	0x8839, 0x20c4, 0x0864, 0xa850, 0x3008, 0x28c1, 0x9d18, 0xa201,
+	0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a,
+	0xa808, 0x28e2, 0x9cce, 0xa8f3, 0x0864, 0xa83e, 0x300c, 0xa801,
+	0x3008, 0x28e1, 0x9cce, 0x28a2, 0x7163, 0xa831, 0x2021, 0xa818,
+	0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0, 0x6fc0, 0x67a4, 0x6c80,
+	0x0212, 0xa205, 0x883d, 0x882b, 0x1814, 0x883b, 0x7027, 0x85f2,
+	0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa813, 0x883e, 0xa811,
+	0x2882, 0x7162, 0xa814, 0x280a, 0xa204, 0x64c0, 0x6de0, 0x67a0,
+	0x6fc0, 0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa802, 0x7861,
+	0x883e, 0x206a, 0x28c1, 0x9d18, 0x2042, 0x2101, 0xa8ca, 0x2902,
+	0xa20e, 0xa80b, 0xa207, 0x0014, 0xa203, 0x8000, 0x85a4, 0x1872,
+	0x879a, 0x883c, 0x1fe2, 0xf601, 0xa208, 0x856e, 0x7121, 0x0014,
+	0x0704, 0x3008, 0x9cce, 0x0014, 0xa202, 0x8000, 0x85a4, 0x3009,
+	0x84a8, 0x19e2, 0xf844, 0x856e, 0x883f, 0x08e6, 0xa8f5, 0xf861,
+	0xa8eb, 0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532,
+	0xfaa2, 0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8,
+	0xd6e0, 0x1fe6, 0x0014, 0x3008, 0x8000, 0x2849, 0x1011, 0xa8fc,
+	0x3008, 0x8000, 0xa000, 0x2081, 0x2802, 0x1011, 0xa8fc, 0xa889,
+	0x3008, 0x20a1, 0x283c, 0x1011, 0xa8fc, 0xa209, 0x0017, 0x300c,
+	0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x0210, 0xa801, 0x0014,
+	0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0, 0x18f2, 0x0014, 0xa20b,
+	0x0014, 0xa20d, 0x3806, 0x0210, 0x9d22, 0x0704, 0xa206, 0x6865,
+	0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016, 0x6042, 0x8008, 0xa8fa,
+	0x8160, 0x842a, 0x8180, 0xf021, 0x3008, 0x84a8, 0x11d7, 0x7042,
+	0x20dd, 0x0011, 0x20d5, 0x8822, 0x0016, 0x0000, 0x0126, 0x70d0,
+	0xa084, 0x4c00, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205,
+	0x11a0, 0x720c, 0x82ff, 0x0128, 0x8aff, 0x1178, 0x7200, 0xd284,
+	0x1160, 0x7804, 0xd0cc, 0x0110, 0x080c, 0x4328, 0x7007, 0x0008,
+	0x7003, 0x0008, 0x012e, 0x2000, 0x0005, 0x7000, 0xa084, 0x0003,
+	0x7002, 0xc69c, 0xd084, 0x0588, 0x7108, 0xe000, 0x7008, 0xa106,
+	0x1dd8, 0xa184, 0x0003, 0x0904, 0x3fa2, 0xa184, 0x01e0, 0x1904,
+	0x3fa2, 0xd1f4, 0x1d88, 0xa184, 0x3000, 0xa086, 0x1000, 0x0d60,
+	0x2011, 0x0180, 0x710c, 0x8211, 0x0130, 0x7008, 0xd0f4, 0x1d20,
+	0x700c, 0xa106, 0x0dc0, 0x7007, 0x0012, 0x7108, 0xe000, 0x7008,
+	0xa106, 0x1dd8, 0xa184, 0x0003, 0x0568, 0xd194, 0x0db0, 0xd1f4,
+	0x0548, 0x7007, 0x0002, 0x0880, 0x0428, 0x7108, 0xd1fc, 0x0130,
+	0x080c, 0x40ae, 0x8aff, 0x0904, 0x3f2c, 0x0cb8, 0x700c, 0xa08c,
+	0x07ff, 0x01e8, 0x7004, 0xd084, 0x0178, 0x7014, 0xa005, 0x1148,
+	0x7010, 0x7310, 0xa306, 0x1de0, 0x2300, 0xa005, 0x0128, 0xa102,
+	0x1e20, 0x7007, 0x0010, 0x0030, 0x8aff, 0x0148, 0x080c, 0x426b,
+	0x1de8, 0x09d8, 0x080c, 0x4034, 0x012e, 0x2000, 0x0005, 0x7204,
+	0x7108, 0xc19c, 0x8103, 0x1218, 0x7007, 0x0002, 0x0cc0, 0xa205,
+	0x1d88, 0x7007, 0x0008, 0x7003, 0x0008, 0x0006, 0x2001, 0x4601,
+	0x2004, 0xd0cc, 0x0110, 0x080c, 0x4328, 0x000e, 0x012e, 0x2000,
+	0x0005, 0x6428, 0x84ff, 0x0508, 0x2c70, 0x7004, 0xa0bc, 0x000f,
+	0xa7b8, 0x3ff5, 0x273c, 0x87fb, 0x1148, 0x0210, 0x080c, 0x254c,
+	0x609c, 0xa075, 0x0190, 0x0c88, 0x2039, 0x3fea, 0x2704, 0xae68,
+	0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0138, 0x8738, 0x2704,
+	0xa005, 0x1da8, 0x709c, 0xa075, 0x1d00, 0x0005, 0x0000, 0x0005,
+	0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000, 0x0003,
+	0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x3fea, 0x3fe7,
+	0x0000, 0x0000, 0x8000, 0x0000, 0x3fea, 0x0000, 0x3ff2, 0x3fef,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x3ff2, 0x0000, 0x3fed, 0x3fed,
+	0x0000, 0x0000, 0x8000, 0x0000, 0x3fed, 0x0000, 0x3ff3, 0x3ff3,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x3ff3, 0x2079, 0x4600, 0x2071,
+	0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001, 0x2009,
+	0x0002, 0x2071, 0x0050, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003,
+	0x0000, 0x2001, 0x01ff, 0x2004, 0xd0fc, 0x1128, 0x8109, 0x0118,
+	0x2071, 0x0020, 0x0c80, 0x0005, 0x7004, 0x8004, 0x1a04, 0x408a,
+	0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0120, 0x080c,
+	0x40e6, 0x0804, 0x40aa, 0x7007, 0x0012, 0x2019, 0x0000, 0x7108,
+	0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0120, 0x080c, 0x40e6,
+	0x0804, 0x40aa, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0190, 0xa386,
+	0x0008, 0x01c0, 0x7004, 0xd084, 0x1148, 0x7108, 0x7008, 0xa106,
+	0x1de0, 0xa184, 0x0003, 0x0110, 0x0804, 0x40e6, 0xa386, 0x200c,
+	0x19f0, 0x7200, 0x8204, 0x0230, 0x730c, 0xa384, 0x07ff, 0x0110,
+	0x080c, 0x254c, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0,
+	0x0118, 0x080c, 0x40e6, 0x0470, 0x7007, 0x0012, 0x7000, 0xd084,
+	0x1148, 0x7310, 0x7014, 0xa305, 0x0128, 0x710c, 0xa184, 0x07ff,
+	0x1904, 0x4034, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0,
+	0x0118, 0x080c, 0x40e6, 0x00b0, 0x7007, 0x0012, 0x7007, 0x0008,
+	0x7004, 0xd09c, 0x1de8, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184,
+	0x01e0, 0x0118, 0x080c, 0x40e6, 0x0028, 0x7007, 0x0012, 0x7108,
+	0x8103, 0x0e88, 0x7003, 0x0008, 0x0005, 0x7108, 0xa184, 0x01e0,
+	0x15a8, 0x7108, 0xa184, 0x01e0, 0x1588, 0xa184, 0x0007, 0x0002,
+	0x40c2, 0x40d0, 0x40c0, 0x40d0, 0x40c0, 0x4120, 0x40c0, 0x411e,
+	0x080c, 0x254c, 0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff,
+	0x1118, 0x2049, 0x0000, 0x0005, 0x080c, 0x426b, 0x1de8, 0x0005,
+	0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x7004, 0xd084, 0x1140,
+	0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x0003, 0x0108, 0x0030,
+	0x8aff, 0x0118, 0x080c, 0x426b, 0x1de8, 0x0005, 0x7007, 0x0012,
+	0x7108, 0x1d04, 0x40e9, 0x2091, 0x6000, 0x1d04, 0x40ed, 0x2091,
+	0x6000, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x1de8,
+	0x7007, 0x0012, 0x7108, 0xd1fc, 0x1dd8, 0x7003, 0x0000, 0x7000,
+	0xa005, 0x1130, 0x7004, 0xa005, 0x1118, 0x700c, 0xa005, 0x0108,
+	0x0c40, 0x2049, 0x0000, 0xb284, 0x0200, 0x0118, 0x2001, 0x0000,
+	0x0010, 0x2001, 0x0001, 0x080c, 0x3b81, 0x681b, 0x0002, 0x2051,
+	0x0000, 0x0005, 0x080c, 0x254c, 0x080c, 0x254c, 0x080c, 0x415f,
+	0x7210, 0x7114, 0x700c, 0xa09c, 0x07ff, 0x2800, 0xa300, 0xa211,
+	0xa189, 0x0000, 0x04a1, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200,
+	0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0140, 0x1238,
+	0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0c58, 0x2b60,
+	0x8a07, 0x0006, 0x6004, 0xd09c, 0x0118, 0xa7ba, 0x3fef, 0x0010,
+	0xa7ba, 0x3fe7, 0x000e, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92,
+	0x6b8e, 0x7108, 0x7008, 0xa106, 0x1de0, 0xa184, 0x01e0, 0x0110,
+	0x080c, 0x40e6, 0x7007, 0x0012, 0x080c, 0x4034, 0x0005, 0x8a50,
+	0x8739, 0x2704, 0xa004, 0x1168, 0x6000, 0xa064, 0x1108, 0x2d60,
+	0x6004, 0xa084, 0x000f, 0xa080, 0x4005, 0x203c, 0x87fb, 0x090c,
+	0x254c, 0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004,
+	0x2090, 0x00de, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057,
+	0xaad4, 0x00ff, 0xa084, 0x00ff, 0x0006, 0x6804, 0xa084, 0x0008,
+	0x000e, 0x0118, 0xa0b8, 0x3fef, 0x0010, 0xa0b8, 0x3fe7, 0xb284,
+	0x0200, 0x0110, 0x7e20, 0x0008, 0x7e24, 0xa6b5, 0x000c, 0x681c,
+	0xd0b4, 0x0108, 0xc685, 0x2400, 0xa305, 0x0518, 0x2c58, 0x2704,
+	0x6104, 0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e,
+	0xd19c, 0x0140, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014, 0xa081,
+	0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c, 0x2300,
+	0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x080c, 0x4292,
+	0x0010, 0x080c, 0x426b, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126,
+	0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x7007,
+	0x0004, 0x7004, 0xd094, 0x1de8, 0x7003, 0x0008, 0x012e, 0x2000,
+	0x0005, 0x0126, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090,
+	0x00de, 0x7e20, 0xb284, 0x0200, 0x1108, 0x7e24, 0xa6b5, 0x000c,
+	0x681c, 0xd0ac, 0x1118, 0xc685, 0x7003, 0x0000, 0x6828, 0x2050,
+	0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x3ff5, 0x273c, 0x87fb,
+	0x1138, 0x0210, 0x080c, 0x254c, 0x689c, 0xa065, 0x0120, 0x0c88,
+	0x080c, 0x426b, 0x1de8, 0x012e, 0x2000, 0x0005, 0x0126, 0x0006,
+	0x0016, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x7e20,
+	0xb284, 0x0200, 0x1108, 0x7e24, 0x00de, 0x003e, 0x004e, 0xa6b5,
+	0x000c, 0x681c, 0xd0b4, 0x0128, 0xc685, 0x7003, 0x0000, 0x7007,
+	0x0004, 0x2049, 0x4206, 0x6828, 0xa055, 0x00d6, 0x0904, 0x4267,
+	0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x3ff5, 0x273c,
+	0x87fb, 0x1140, 0x0210, 0x080c, 0x254c, 0x709c, 0xa075, 0x2060,
+	0x0570, 0x0c80, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b,
+	0x0268, 0x8a51, 0x1110, 0x080c, 0x254c, 0x8738, 0x2704, 0xa005,
+	0x1d90, 0x709c, 0xa075, 0x2060, 0x01d0, 0x08e0, 0x8422, 0x8420,
+	0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300,
+	0xa11b, 0x1210, 0x080c, 0x254c, 0xb284, 0x0200, 0x0118, 0x2071,
+	0x0050, 0x0010, 0x2071, 0x0020, 0x00de, 0x0804, 0x419b, 0x00de,
+	0x012e, 0x2000, 0x0005, 0x7008, 0x0006, 0xa084, 0x01e0, 0x000e,
+	0x0110, 0xa006, 0x0005, 0xa084, 0x0003, 0xa086, 0x0003, 0x1108,
+	0x0005, 0x2704, 0xac78, 0x7800, 0x701a, 0x7804, 0x701e, 0x7808,
+	0x7012, 0x780c, 0x7016, 0x6004, 0xd09c, 0x0120, 0x7810, 0x7022,
+	0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xc085, 0x7006,
+	0x2079, 0x4600, 0x8a51, 0x01e8, 0x8738, 0x2704, 0xa005, 0x1168,
+	0x609c, 0xa005, 0x01b8, 0x2060, 0x6004, 0xa084, 0x000f, 0xa080,
+	0x3ff5, 0x203c, 0x87fb, 0x090c, 0x254c, 0x7008, 0x0006, 0xa084,
+	0x01e0, 0x000e, 0x0110, 0xa006, 0x0028, 0xa084, 0x0003, 0xa086,
+	0x0003, 0x0005, 0x2051, 0x0000, 0x0005, 0x0126, 0x0006, 0x00d6,
+	0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de, 0x008e, 0x7108,
+	0xa184, 0x0003, 0x1128, 0x6828, 0xa005, 0x0178, 0x0804, 0x3f45,
+	0x7108, 0xd1fc, 0x0118, 0x080c, 0x40ae, 0x0c88, 0x7007, 0x0010,
+	0x7108, 0xd1fc, 0x0de8, 0x080c, 0x40ae, 0x7008, 0xa086, 0x0008,
+	0x1d30, 0x7000, 0xa005, 0x1d18, 0x7003, 0x0000, 0x2049, 0x0000,
+	0x0006, 0x2001, 0x4601, 0x2004, 0xd0cc, 0x0110, 0x080c, 0x4328,
+	0x000e, 0x012e, 0x2000, 0x0005, 0x0126, 0x0146, 0x0136, 0x0156,
+	0x00c6, 0x00d6, 0x70d0, 0xa084, 0x4c00, 0x8004, 0x2090, 0x00de,
+	0x2049, 0x42ec, 0xad80, 0x0011, 0x20a0, 0xb284, 0x0200, 0x0118,
+	0x2099, 0x0032, 0x0010, 0x2099, 0x0031, 0x700c, 0xa084, 0x07ff,
+	0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0118,
+	0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, 0x07ff, 0x0130, 0x7007,
+	0x0004, 0x7004, 0xa084, 0x0004, 0x1de0, 0x00ce, 0x2049, 0x0000,
+	0x7003, 0x0000, 0x015e, 0x013e, 0x014e, 0x012e, 0x2000, 0x0005,
+	0x6814, 0xd0fc, 0x0904, 0x436b, 0x7000, 0xd084, 0x05e0, 0x7e24,
+	0xa6b5, 0x0004, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x1de0,
+	0x7118, 0x0016, 0x711c, 0x0016, 0x7120, 0x0016, 0x7124, 0x0016,
+	0x701b, 0x0000, 0x701f, 0x3fff, 0x7023, 0x0000, 0x7027, 0x0000,
+	0x7013, 0x0004, 0x7017, 0x0000, 0x7602, 0x7007, 0x0001, 0x2001,
+	0xffff, 0x2009, 0x0031, 0x200a, 0x200a, 0x7108, 0x7008, 0xa106,
+	0x1de0, 0xd1fc, 0x0dd0, 0x002e, 0x7226, 0x002e, 0x7222, 0x002e,
+	0x721e, 0x002e, 0x721a, 0x7007, 0x0002, 0x7008, 0xa086, 0x0008,
+	0x0110, 0x0804, 0x40e6, 0x7007, 0x0004, 0x7003, 0x0000, 0x0005,
+	0x2091, 0x8000, 0x2091, 0x6000, 0x78ac, 0xa005, 0x1168, 0x7974,
+	0x70d0, 0xa106, 0x1148, 0x781c, 0xa005, 0x0130, 0x781f, 0x0000,
+	0x0e04, 0x4384, 0x2091, 0x4080, 0x2069, 0x4680, 0xd7fc, 0x1110,
+	0x2069, 0x4640, 0x6800, 0xa084, 0x000f, 0x1198, 0x68d0, 0xd0b4,
+	0x0180, 0xd0bc, 0x1170, 0x00f6, 0x2079, 0x0100, 0xd7fc, 0x1110,
+	0x2079, 0x0200, 0x7830, 0xa084, 0x00c0, 0x1110, 0x080c, 0x22ae,
+	0x00fe, 0x7830, 0x8001, 0x7832, 0x1904, 0x440b, 0x7834, 0x7832,
+	0x2061, 0x6bc0, 0x2069, 0x4680, 0xc7fd, 0x68cc, 0xa005, 0x0128,
+	0x8001, 0x68ce, 0x1110, 0x080c, 0x4577, 0x6800, 0xa084, 0x000f,
+	0x0168, 0xa086, 0x0001, 0x0150, 0x6840, 0xa00d, 0x0138, 0x2104,
+	0xa005, 0x0120, 0x8001, 0x200a, 0x0904, 0x4514, 0x6814, 0xa005,
+	0x01a8, 0x8001, 0x6816, 0x1190, 0x68a3, 0x0001, 0x00f6, 0xd7fc,
+	0x1118, 0x2079, 0x0200, 0x0010, 0x2079, 0x0100, 0x080c, 0x3c46,
+	0x00fe, 0x6860, 0xa005, 0x0110, 0x080c, 0x22ae, 0x687c, 0xa005,
+	0x0140, 0x8001, 0x687e, 0x1128, 0x6863, 0x0000, 0x68d0, 0xc0c5,
+	0x68d2, 0x68d0, 0xd0fc, 0x01b0, 0xc0fc, 0x68d2, 0x20a9, 0x0200,
+	0x6034, 0xa005, 0x0158, 0x8001, 0x6036, 0x68d0, 0xc0fd, 0x68d2,
+	0x1128, 0x6010, 0xa005, 0x0110, 0x080c, 0x22ae, 0xace0, 0x0010,
+	0x1f04, 0x43f0, 0xd7fc, 0x0138, 0x2061, 0x4bc0, 0x2069, 0x4640,
+	0xc7fc, 0x0804, 0x43ad, 0x0459, 0x7838, 0x8001, 0x783a, 0x11a0,
+	0x783c, 0x783a, 0x2061, 0x4bc0, 0x2069, 0x4640, 0xc7fc, 0x680c,
+	0xa005, 0x0110, 0x080c, 0x4487, 0xd7fc, 0x1130, 0x2061, 0x6bc0,
+	0x2069, 0x4680, 0xc7fd, 0x0c98, 0x7810, 0xd0cc, 0x0168, 0xd0ac,
+	0x1120, 0xd0a4, 0x0148, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0e04,
+	0x4433, 0x080c, 0x207a, 0x0005, 0x2091, 0x8001, 0x0005, 0x7840,
+	0x8001, 0x7842, 0x1904, 0x4486, 0x7844, 0x7842, 0x2069, 0x4640,
+	0xc7fc, 0x2079, 0x0200, 0x68d4, 0xa005, 0x0138, 0x7de0, 0xa504,
+	0x1120, 0x68d6, 0x68d0, 0xc0bc, 0x68d2, 0x2079, 0x4600, 0x6810,
+	0xa005, 0x1110, 0x2001, 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0118,
+	0xa080, 0x8cd0, 0x0010, 0xa080, 0x8bc0, 0x2040, 0x2004, 0xa065,
+	0x01e0, 0x6024, 0xa005, 0x01b0, 0x8001, 0x6026, 0x1198, 0x6800,
+	0xa005, 0x0130, 0x6848, 0xac06, 0x1118, 0x080c, 0x4514, 0x0068,
+	0x6860, 0xa005, 0x0118, 0x6027, 0x0001, 0x0020, 0x080c, 0x44c8,
+	0x2804, 0x0c28, 0x6000, 0x2c40, 0x0c10, 0xd7fc, 0x1138, 0x2069,
+	0x4680, 0xc7fd, 0x2079, 0x0100, 0x0804, 0x4443, 0x0005, 0x2009,
+	0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0558, 0x6024, 0xa005,
+	0x0118, 0x8001, 0x6026, 0x0418, 0x6008, 0xc09c, 0xd084, 0x1110,
+	0xd0ac, 0x01c0, 0x600a, 0x6004, 0xa005, 0x01d8, 0x00d6, 0x00c6,
+	0x0016, 0x2068, 0x6010, 0x8001, 0x6012, 0x080c, 0x37a4, 0x2d00,
+	0x2c68, 0x2060, 0x080c, 0x1be3, 0x080c, 0x1d95, 0x001e, 0x00ce,
+	0x00de, 0x0038, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0010, 0xa18d,
+	0x0100, 0xace0, 0x0010, 0x1f04, 0x448b, 0xa184, 0x0001, 0x0130,
+	0xa18c, 0xfffe, 0x690e, 0x080c, 0x22ae, 0x0008, 0x690e, 0x0005,
+	0x2c00, 0x687a, 0x6714, 0x6f72, 0x6017, 0x0000, 0x602b, 0x0000,
+	0x601b, 0x0006, 0x60b4, 0xa084, 0x5f00, 0x601e, 0x6020, 0xa084,
+	0x00ff, 0xa085, 0x0060, 0x6022, 0x6000, 0x2042, 0x6858, 0xac06,
+	0x1110, 0x2800, 0x685a, 0x080c, 0x1b7b, 0x6818, 0xa005, 0x0110,
+	0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810, 0x7908, 0x8109,
+	0x790a, 0x8001, 0x1310, 0x080c, 0x254c, 0x6812, 0x1118, 0x7910,
+	0xc1a5, 0x7912, 0x602f, 0x0000, 0x6033, 0x0000, 0x2c68, 0x080c,
+	0x1da2, 0xd7fc, 0x1118, 0x2069, 0x4640, 0x0010, 0x2069, 0x4680,
+	0x6910, 0xa184, 0x0100, 0x2001, 0x0006, 0x1118, 0x6976, 0x2001,
+	0x0004, 0x080c, 0x22a4, 0x0005, 0x00d6, 0x6948, 0x2160, 0xd7fc,
+	0x1118, 0x2069, 0x0200, 0x0010, 0x2069, 0x0100, 0x080c, 0x2467,
+	0x601b, 0x0006, 0x6858, 0xa084, 0x5f00, 0x601e, 0x6020, 0xa084,
+	0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033, 0x0000,
+	0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x01b0, 0x684b,
+	0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0110, 0x1f04, 0x453b,
+	0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xd084, 0x0110, 0x1f04,
+	0x4544, 0x20a9, 0x00fa, 0x1f04, 0x454b, 0x681b, 0x0054, 0x00de,
+	0x6863, 0x0007, 0x0005, 0x2079, 0x4600, 0x00e1, 0x0089, 0x00a9,
+	0x2009, 0x0002, 0x2069, 0x4680, 0x680f, 0x0000, 0x6813, 0x0000,
+	0x6817, 0x0000, 0x8109, 0x0118, 0x2069, 0x4640, 0x0ca8, 0x0005,
+	0x2019, 0x00a3, 0x7b3a, 0x7b3e, 0x0005, 0x2019, 0x0033, 0x7b42,
+	0x7b46, 0x0005, 0x2019, 0x32dd, 0x7b32, 0x7b36, 0x0005, 0x6a4c,
+	0xa285, 0x0000, 0x01f0, 0x6950, 0x6bbc, 0xa300, 0x00c6, 0x2164,
+	0x6304, 0x83ff, 0x1138, 0x8211, 0x0148, 0x8108, 0xa11a, 0x0eb8,
+	0x69bc, 0x0ca8, 0x68cf, 0x000a, 0x00ce, 0x0005, 0x694c, 0x6abc,
+	0x2264, 0x6008, 0xc0b5, 0x600a, 0x8210, 0x8109, 0x1dc8, 0x694e,
+	0x00ce, 0x0005, 0x1d04, 0x459a, 0x2091, 0x6000, 0x1d04, 0x459e,
+	0x2091, 0x6000, 0x70ec, 0xd0dc, 0x1118, 0xd0d4, 0x0190, 0x0098,
+	0xae8e, 0x0100, 0x0138, 0x7814, 0xc0f5, 0xc0c5, 0x7816, 0xd0d4,
+	0x1578, 0x0458, 0x7814, 0xc0fd, 0xc0c5, 0x7816, 0xd0d4, 0x1540,
+	0x0420, 0xd0e4, 0x0538, 0x1d04, 0x45bb, 0x2091, 0x6000, 0x2009,
+	0x000c, 0x1d04, 0x45c1, 0x2091, 0x6000, 0x8109, 0x1dd0, 0x70e4,
+	0xa084, 0x01ff, 0xa086, 0x01ff, 0x1110, 0x70ec, 0x08c8, 0xae8e,
+	0x0100, 0x0128, 0x7814, 0xc0f4, 0xd0fc, 0x1130, 0x0020, 0x7814,
+	0xc0fc, 0xd0f4, 0x1108, 0xc0c4, 0x7816, 0x7804, 0xd08c, 0x0110,
+	0x681f, 0x000c, 0x70a0, 0x70a2, 0x0005, 0x7c12
+};
+#ifdef UNIQUE_FW_NAME
+static unsigned short   fw12160i_length01 = 0x35e6;
+#else
+static unsigned short   risc_code_length01 = 0x35e6;
+#endif
diff --git a/drivers/scsi/ql1280_fw.h b/drivers/scsi/ql1280_fw.h
new file mode 100644
index 0000000..2621e99
--- /dev/null
+++ b/drivers/scsi/ql1280_fw.h
@@ -0,0 +1,2017 @@
+/*****************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP1280/ device driver for Linux 2.2.x and 2.4.x
+ * Copyright (C) 2001 Qlogic Corporation (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *****************************************************************************/
+
+/************************************************************************
+ * 	         --- ISP1240/1080/1280 Initiator Firmware ---           *
+ *			      32 LUN Support				*
+ ************************************************************************/
+
+
+/*
+ *	Firmware Version 8.15.00 (14:35 Aug 22, 2000)
+ */
+
+#ifdef UNIQUE_FW_NAME
+static unsigned char fw1280ei_version_str[] = {8,15,0};
+#else
+static unsigned char firmware_version[] = {8,15,0};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw1280ei_VERSION_STRING "8.15.00"
+#else
+#define FW_VERSION_STRING "8.15.00"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+static unsigned short fw1280ei_addr01 = 0x1000;
+#else
+static unsigned short risc_code_addr01 = 0x1000;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+static unsigned short fw1280ei_code01[] = {
+#else
+static unsigned short risc_code01[] = {
+#endif
+	0x0078, 0x1041, 0x0000, 0x3d3b, 0x0000, 0x2043, 0x4f50, 0x5952,
+	0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932, 0x2c31,
+	0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749, 0x4320,
+	0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049, 0x5350,
+	0x3132, 0x3430, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520, 0x2056,
+	0x6572, 0x7369, 0x6f6e, 0x2030, 0x382e, 0x3135, 0x2020, 0x2043,
+	0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20, 0x3030, 0x2050,
+	0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020, 0x3030, 0x2020,
+	0x2400, 0x20c9, 0x97ff, 0x2001, 0x04fc, 0x2004, 0xa086, 0x1080,
+	0x00c0, 0x1054, 0x2071, 0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010,
+	0x2089, 0x1374, 0x0078, 0x106d, 0x2001, 0x04fc, 0x2004, 0xa086,
+	0x1280, 0x00c0, 0x1069, 0x2071, 0x0200, 0x70a0, 0x70a2, 0x2071,
+	0x0100, 0x70a0, 0x70a2, 0x20c1, 0x0010, 0x2089, 0x13f8, 0x0078,
+	0x106d, 0x20c1, 0x0020, 0x2089, 0x131c, 0x2071, 0x0010, 0x70c3,
+	0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0008, 0x2001, 0x04fe, 0x70d6, 0x20c1, 0x0021, 0x2019, 0x0000,
+	0x2009, 0xfeff, 0x2100, 0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64,
+	0x206b, 0x0a0a, 0xaddc, 0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114,
+	0xa286, 0xa5a5, 0x0040, 0x10a4, 0xa386, 0x000f, 0x0040, 0x10a0,
+	0x2c6a, 0x2a5a, 0x20c1, 0x0020, 0x2019, 0x000f, 0x0078, 0x1080,
+	0x2c6a, 0x2a5a, 0x0078, 0x10a2, 0x2c6a, 0x2a5a, 0x2130, 0x2128,
+	0xa1a2, 0x4e00, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0x8424,
+	0xa192, 0x9800, 0x2009, 0x0000, 0x2001, 0x0032, 0x1078, 0x207a,
+	0x2218, 0x2079, 0x4e00, 0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9,
+	0x0040, 0x42a4, 0x8109, 0x00c0, 0x10bf, 0x2009, 0xff00, 0x3400,
+	0xa102, 0x0048, 0x10cf, 0x0040, 0x10cf, 0x20a8, 0x42a4, 0x2001,
+	0x04fc, 0x2004, 0xa086, 0x1080, 0x00c0, 0x10e5, 0x2071, 0x0100,
+	0x0d7e, 0x2069, 0x4e40, 0x1078, 0x4cdd, 0x0d7f, 0x7810, 0xc0ed,
+	0x7812, 0x781b, 0x0064, 0x0078, 0x110a, 0x2001, 0x04fc, 0x2004,
+	0xa086, 0x1280, 0x00c0, 0x1105, 0x7814, 0xc0ed, 0xc0d5, 0x7816,
+	0x781b, 0x0064, 0x2071, 0x0200, 0x0d7e, 0x2069, 0x4e40, 0x1078,
+	0x4cdd, 0x2069, 0x4e80, 0x2071, 0x0100, 0x1078, 0x4cdd, 0x7814,
+	0xc0d4, 0x7816, 0x0d7f, 0x0078, 0x110a, 0x7814, 0xc0e5, 0x7816,
+	0x781b, 0x003c, 0x7eca, 0x7cc2, 0x7bc6, 0x7867, 0x0000, 0x7800,
+	0xc08d, 0x7802, 0x2031, 0x0030, 0x78af, 0x0101, 0x7823, 0x0002,
+	0x7827, 0x0002, 0x2009, 0x0002, 0x2069, 0x4e40, 0x681b, 0x0003,
+	0x6823, 0x0007, 0x6827, 0x00fa, 0x682b, 0x0008, 0x682f, 0x0028,
+	0x6837, 0x0000, 0x683b, 0x0006, 0x6833, 0x0008, 0x683f, 0x0000,
+	0x8109, 0x0040, 0x115e, 0x68d3, 0x000a, 0x68c3, 0x4ec0, 0x2079,
+	0x4e00, 0x7814, 0xd0e4, 0x00c0, 0x1144, 0xd0ec, 0x00c0, 0x1148,
+	0x68d7, 0x7329, 0x0078, 0x114a, 0x68d7, 0x730d, 0x0078, 0x114a,
+	0x68d7, 0x732d, 0x68c7, 0x53c0, 0x68cb, 0x52c0, 0x68cf, 0x93c0,
+	0x68ab, 0x9644, 0x68af, 0x9649, 0x68b3, 0x9644, 0x68b7, 0x9644,
+	0x68a7, 0x0001, 0x2069, 0x4e80, 0x0078, 0x111e, 0x68d3, 0x000a,
+	0x68c3, 0x50c0, 0x7814, 0xd0e4, 0x00c0, 0x116a, 0x68d7, 0x7439,
+	0x0078, 0x116c, 0x68d7, 0x7419, 0x68c7, 0x73c0, 0x68cb, 0x5340,
+	0x68cf, 0x94d0, 0x68ab, 0x9649, 0x68af, 0x964e, 0x68b3, 0x9649,
+	0x68b7, 0x9649, 0x68a7, 0x0001, 0x7810, 0xd0ec, 0x00c0, 0x11c2,
+	0x7814, 0xd0e4, 0x00c0, 0x11b4, 0x0e7e, 0x2069, 0x52c0, 0x2071,
+	0x0200, 0x70ec, 0xd0e4, 0x00c0, 0x1195, 0x2019, 0x0c0c, 0x2021,
+	0x000c, 0x1078, 0x2009, 0x0078, 0x119b, 0x2019, 0x0c0a, 0x2021,
+	0x000a, 0x1078, 0x2009, 0x2069, 0x5340, 0x2071, 0x0100, 0x70ec,
+	0xd0e4, 0x00c0, 0x11ab, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078,
+	0x2009, 0x0078, 0x11b1, 0x2019, 0x0c0a, 0x2021, 0x000a, 0x1078,
+	0x2009, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0c, 0x2021, 0x000c,
+	0x2069, 0x52c0, 0x1078, 0x2009, 0x2069, 0x5340, 0x1078, 0x2009,
+	0x0078, 0x11db, 0x2069, 0x52c0, 0x0e7e, 0x2071, 0x0100, 0x70ec,
+	0xd0e4, 0x00c0, 0x11d4, 0x2019, 0x0c0c, 0x2021, 0x000c, 0x1078,
+	0x2009, 0x0e7f, 0x0078, 0x11db, 0x2019, 0x0c0a, 0x2021, 0x000a,
+	0x1078, 0x2009, 0x0e7f, 0x2011, 0x0002, 0x2069, 0x53c0, 0x2009,
+	0x0002, 0x20a9, 0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bc8,
+	0xa386, 0xfeff, 0x00c0, 0x11f2, 0x6817, 0x0100, 0x681f, 0x0064,
+	0x0078, 0x11f6, 0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010,
+	0x00f0, 0x11e3, 0x8109, 0x00c0, 0x11e1, 0x8211, 0x0040, 0x1204,
+	0x2069, 0x73c0, 0x0078, 0x11df, 0x1078, 0x265b, 0x1078, 0x468e,
+	0x1078, 0x1dd4, 0x1078, 0x4c6f, 0x2091, 0x2100, 0x2079, 0x4e00,
+	0x7810, 0xd0ec, 0x0040, 0x1218, 0x2071, 0x0020, 0x0078, 0x121a,
+	0x2071, 0x0050, 0x2091, 0x2200, 0x2079, 0x4e00, 0x2071, 0x0020,
+	0x2091, 0x2300, 0x2079, 0x4e00, 0x7810, 0xd0ec, 0x0040, 0x122c,
+	0x2079, 0x0100, 0x0078, 0x122e, 0x2079, 0x0200, 0x2071, 0x4e40,
+	0x2091, 0x2400, 0x2079, 0x0100, 0x2071, 0x4e80, 0x2091, 0x2000,
+	0x2079, 0x4e00, 0x2071, 0x0010, 0x3200, 0xa085, 0x303d, 0x2090,
+	0x2071, 0x0010, 0x70c3, 0x0000, 0x0090, 0x124d, 0x70c0, 0xa086,
+	0x0002, 0x00c0, 0x124d, 0x1078, 0x15ba, 0x2039, 0x0000, 0x7810,
+	0xd0ec, 0x00c0, 0x12cf, 0x1078, 0x148e, 0x78ac, 0xa005, 0x00c0,
+	0x126b, 0x0068, 0x1261, 0x786c, 0xa065, 0x0040, 0x1261, 0x1078,
+	0x2395, 0x1078, 0x20a1, 0x0068, 0x1278, 0x786c, 0xa065, 0x0040,
+	0x126b, 0x1078, 0x2395, 0x0068, 0x1278, 0x2009, 0x4e47, 0x2011,
+	0x4e87, 0x2104, 0x220c, 0xa105, 0x0040, 0x1278, 0x1078, 0x1f0a,
+	0x2071, 0x4e40, 0x70a4, 0xa005, 0x0040, 0x129d, 0x7450, 0xa485,
+	0x0000, 0x0040, 0x129d, 0x2079, 0x0200, 0x2091, 0x8000, 0x72d4,
+	0xa28c, 0x303d, 0x2190, 0x1078, 0x2b6a, 0x2091, 0x8000, 0x2091,
+	0x303d, 0x0068, 0x129d, 0x2079, 0x4e00, 0x786c, 0xa065, 0x0040,
+	0x129d, 0x2071, 0x0010, 0x1078, 0x2395, 0x00e0, 0x12a5, 0x2079,
+	0x4e00, 0x2071, 0x0010, 0x1078, 0x4a43, 0x2071, 0x4e80, 0x70a4,
+	0xa005, 0x0040, 0x12bd, 0x7050, 0xa025, 0x0040, 0x12bd, 0x2079,
+	0x0100, 0x2091, 0x8000, 0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078,
+	0x2b6a, 0x2091, 0x8000, 0x2091, 0x303d, 0x2079, 0x4e00, 0x2071,
+	0x0010, 0x0068, 0x12c9, 0x786c, 0xa065, 0x0040, 0x12c9, 0x1078,
+	0x2395, 0x00e0, 0x1253, 0x1078, 0x4a43, 0x0078, 0x1253, 0x1078,
+	0x148e, 0x78ac, 0xa005, 0x00c0, 0x12e7, 0x0068, 0x12dd, 0x786c,
+	0xa065, 0x0040, 0x12dd, 0x1078, 0x2395, 0x1078, 0x20a1, 0x0068,
+	0x12f1, 0x786c, 0xa065, 0x0040, 0x12e7, 0x1078, 0x2395, 0x0068,
+	0x12f1, 0x2009, 0x4e47, 0x2104, 0xa005, 0x0040, 0x12f1, 0x1078,
+	0x1f0a, 0x2071, 0x4e40, 0x70a4, 0xa005, 0x0040, 0x130c, 0x7450,
+	0xa485, 0x0000, 0x0040, 0x130c, 0x2079, 0x0100, 0x2091, 0x8000,
+	0x72d4, 0xa28c, 0x303d, 0x2190, 0x1078, 0x2b6a, 0x2091, 0x8000,
+	0x2091, 0x303d, 0x2079, 0x4e00, 0x2071, 0x0010, 0x0068, 0x1316,
+	0x786c, 0xa065, 0x0040, 0x1316, 0x1078, 0x2395, 0x00e0, 0x12cf,
+	0x1078, 0x4a43, 0x0078, 0x12cf, 0x133c, 0x133c, 0x133e, 0x133e,
+	0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363,
+	0x134b, 0x134b, 0x134b, 0x134b, 0x133c, 0x133c, 0x133e, 0x133e,
+	0x134b, 0x134b, 0x134b, 0x134b, 0x1356, 0x1356, 0x1363, 0x1363,
+	0x134b, 0x134b, 0x134b, 0x134b, 0x0078, 0x133c, 0x007e, 0x107e,
+	0x127e, 0x2091, 0x2400, 0x1078, 0x298a, 0x127f, 0x107f, 0x007f,
+	0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13c8,
+	0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e, 0x107e,
+	0x127e, 0x2091, 0x2300, 0x1078, 0x298a, 0x127f, 0x107f, 0x007f,
+	0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300,
+	0x1078, 0x298a, 0x2091, 0x2400, 0x1078, 0x298a, 0x127f, 0x107f,
+	0x007f, 0x2091, 0x8001, 0x007c, 0x1394, 0x1394, 0x1396, 0x1396,
+	0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13ae, 0x13ae, 0x1396, 0x1396,
+	0x13a3, 0x13a3, 0x13a3, 0x13a3, 0x13af, 0x13af, 0x13af, 0x13af,
+	0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af, 0x13af,
+	0x13af, 0x13af, 0x13af, 0x13af, 0x0078, 0x1394, 0x007e, 0x107e,
+	0x127e, 0x2091, 0x2300, 0x1078, 0x298a, 0x127f, 0x107f, 0x007f,
+	0x2091, 0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x1078, 0x13d5,
+	0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007c, 0x107e,
+	0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x007e, 0x2071, 0x0100, 0x2069,
+	0x4e40, 0x2079, 0x4e00, 0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078,
+	0x4cdd, 0x007f, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f, 0x107f, 0x007c,
+	0x3c00, 0xa084, 0x0007, 0x0079, 0x13cd, 0x13de, 0x13de, 0x13e0,
+	0x13e0, 0x13e5, 0x13e5, 0x13ea, 0x13ea, 0x3c00, 0xa084, 0x0003,
+	0x0079, 0x13da, 0x13de, 0x13de, 0x13f3, 0x13f3, 0x1078, 0x296b,
+	0x2091, 0x2200, 0x1078, 0x4768, 0x007c, 0x2091, 0x2100, 0x1078,
+	0x4768, 0x007c, 0x2091, 0x2100, 0x1078, 0x4768, 0x2091, 0x2200,
+	0x1078, 0x4768, 0x007c, 0x2091, 0x2100, 0x1078, 0x4768, 0x007c,
+	0x1418, 0x1418, 0x141a, 0x141a, 0x1427, 0x1427, 0x1427, 0x1427,
+	0x1432, 0x1432, 0x143f, 0x143f, 0x1427, 0x1427, 0x1427, 0x1427,
+	0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450,
+	0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450, 0x1450,
+	0x0078, 0x1418, 0x007e, 0x107e, 0x127e, 0x2091, 0x2400, 0x1078,
+	0x298a, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e,
+	0x107e, 0x127e, 0x1078, 0x13c8, 0x127f, 0x107f, 0x007f, 0x2091,
+	0x8001, 0x007c, 0x007e, 0x107e, 0x127e, 0x2091, 0x2300, 0x1078,
+	0x298a, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c, 0x007e,
+	0x107e, 0x127e, 0x2091, 0x2300, 0x1078, 0x298a, 0x2091, 0x2400,
+	0x1078, 0x298a, 0x127f, 0x107f, 0x007f, 0x2091, 0x8001, 0x007c,
+	0x007e, 0x107e, 0x127e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2079, 0x4e00,
+	0x2071, 0x0200, 0x2069, 0x4e40, 0x3d00, 0xd08c, 0x0040, 0x1466,
+	0x70ec, 0xa084, 0x1c00, 0x78e2, 0x1078, 0x4cdd, 0x3d00, 0xd084,
+	0x0040, 0x1474, 0x2069, 0x4e80, 0x2071, 0x0100, 0x70ec, 0xa084,
+	0x1c00, 0x78e6, 0x1078, 0x4cdd, 0x0f7f, 0x0e7f, 0x0d7f, 0x127f,
+	0x107f, 0x007f, 0x007c, 0x7008, 0x800b, 0x00c8, 0x1489, 0x7007,
+	0x0002, 0xa08c, 0x01e0, 0x00c0, 0x148a, 0xd09c, 0x0040, 0x1489,
+	0x087a, 0x097a, 0x70c3, 0x4002, 0x0078, 0x15bd, 0x0068, 0x1513,
+	0x2061, 0x0000, 0x6018, 0xd084, 0x00c0, 0x1513, 0x7828, 0xa005,
+	0x00c0, 0x149e, 0x0010, 0x1514, 0x0078, 0x1513, 0x7910, 0xd1f4,
+	0x0040, 0x14a6, 0x2001, 0x4007, 0x0078, 0x15bc, 0x7914, 0xd1ec,
+	0x0040, 0x14c1, 0xd0fc, 0x0040, 0x14b7, 0x007e, 0x1078, 0x1d64,
+	0x007f, 0x0040, 0x14c1, 0x2001, 0x4007, 0x0078, 0x15bc, 0x007e,
+	0x1078, 0x1d54, 0x007f, 0x0040, 0x14c1, 0x2001, 0x4007, 0x0078,
+	0x15bc, 0x7910, 0xd0fc, 0x00c0, 0x14cb, 0x2061, 0x4e40, 0xc19c,
+	0xc7fc, 0x0078, 0x14cf, 0x2061, 0x4e80, 0xc19d, 0xc7fd, 0x6064,
+	0xa005, 0x00c0, 0x1513, 0x7912, 0x6083, 0x0000, 0x7828, 0xc0fc,
+	0xa086, 0x0018, 0x00c0, 0x14e0, 0x0c7e, 0x1078, 0x1b5b, 0x0c7f,
+	0x782b, 0x0000, 0x607c, 0xa065, 0x0040, 0x14f9, 0x0c7e, 0x609c,
+	0x1078, 0x1e49, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1c84, 0x2009,
+	0x0018, 0x6087, 0x0103, 0x1078, 0x1d74, 0x00c0, 0x150d, 0x1078,
+	0x1dc6, 0x7810, 0xd09c, 0x00c0, 0x1501, 0x2061, 0x4e40, 0x0078,
+	0x1505, 0x2061, 0x4e80, 0xc09c, 0x7812, 0x607f, 0x0000, 0x60d4,
+	0xd0dc, 0x0040, 0x1511, 0xc0dc, 0x60d6, 0x2001, 0x4005, 0x0078,
+	0x15bc, 0x0078, 0x15ba, 0x007c, 0x7810, 0xd0f4, 0x0040, 0x151c,
+	0x2001, 0x4007, 0x0078, 0x15bc, 0xa006, 0x70c2, 0x70c6, 0x70ca,
+	0x70ce, 0x70da, 0x70c0, 0xa03d, 0xa08a, 0x0040, 0x00c8, 0x152a,
+	0x0079, 0x1531, 0x2100, 0xa08a, 0x0040, 0x00c8, 0x15c8, 0x0079,
+	0x1571, 0x15ba, 0x1610, 0x15d9, 0x1648, 0x1680, 0x1680, 0x15d0,
+	0x1c9c, 0x168b, 0x15c8, 0x15dd, 0x15df, 0x15e1, 0x15e3, 0x1ca1,
+	0x15c8, 0x1699, 0x16f6, 0x1b7b, 0x1c96, 0x15e5, 0x19c0, 0x1a02,
+	0x1a3d, 0x1a8e, 0x197b, 0x1988, 0x199c, 0x19af, 0x17cb, 0x15c8,
+	0x172d, 0x173a, 0x1746, 0x1752, 0x1768, 0x1774, 0x1777, 0x1783,
+	0x178f, 0x1797, 0x17b3, 0x17bf, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x17d8, 0x17ea, 0x1806, 0x183c, 0x1864, 0x1874, 0x1877, 0x18a8,
+	0x18d9, 0x18eb, 0x194a, 0x195a, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x196a, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x1cc6, 0x1ccc,
+	0x15c8, 0x15c8, 0x15c8, 0x1cd0, 0x1d15, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x160a, 0x167a, 0x1693, 0x16f0, 0x1b75, 0x15c8, 0x15c8,
+	0x1b3e, 0x15c8, 0x1d19, 0x1cb8, 0x1cc2, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8, 0x15c8,
+	0x15c8, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x15bc, 0x73ce,
+	0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068, 0x15bd, 0x2061,
+	0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c,
+	0x70c3, 0x4001, 0x0078, 0x15bd, 0x70c3, 0x4006, 0x0078, 0x15bd,
+	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+	0x15ba, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x15ba, 0x0078,
+	0x15ba, 0x0078, 0x15ba, 0x0078, 0x15ba, 0x2091, 0x8000, 0x70c3,
+	0x0004, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0008, 0x2001, 0x000f, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001,
+	0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x041a, 0x2051, 0x0445,
+	0x2061, 0x0447, 0x20c1, 0x0020, 0x2091, 0x5000, 0x2091, 0x4080,
+	0x0078, 0x0418, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1613,
+	0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x20a0,
+	0x2099, 0x0030, 0x7003, 0x0001, 0x7007, 0x0006, 0x731a, 0x721e,
+	0x7422, 0x7526, 0x2021, 0x0040, 0x81ff, 0x0040, 0x15ba, 0xa182,
+	0x0040, 0x00c8, 0x162d, 0x2120, 0xa006, 0x2008, 0x8403, 0x7012,
+	0x7007, 0x0004, 0x7007, 0x0001, 0x7008, 0xd0fc, 0x0040, 0x1634,
+	0x7007, 0x0002, 0xa084, 0x01e0, 0x0040, 0x1642, 0x70c3, 0x4002,
+	0x0078, 0x15bd, 0x24a8, 0x53a5, 0x0078, 0x1624, 0x0078, 0x15ba,
+	0x2029, 0x0000, 0x2520, 0x71d0, 0x72c8, 0x73cc, 0x70c4, 0x2098,
+	0x20a1, 0x0030, 0x7003, 0x0000, 0x7007, 0x0006, 0x731a, 0x721e,
+	0x7422, 0x7526, 0x2021, 0x0040, 0x7007, 0x0006, 0x81ff, 0x0040,
+	0x15ba, 0xa182, 0x0040, 0x00c8, 0x1667, 0x2120, 0xa006, 0x2008,
+	0x8403, 0x7012, 0x24a8, 0x53a6, 0x7007, 0x0001, 0x7008, 0xd0fc,
+	0x0040, 0x166e, 0xa084, 0x01e0, 0x0040, 0x165c, 0x70c3, 0x4002,
+	0x0078, 0x15bd, 0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x164b,
+	0x71c4, 0x70c8, 0x2114, 0xa79e, 0x0004, 0x00c0, 0x1688, 0x200a,
+	0x72ca, 0x0078, 0x15b9, 0x70c7, 0x0008, 0x70cb, 0x000f, 0x70cf,
+	0x0000, 0x0078, 0x15ba, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078,
+	0x169c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0,
+	0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x16eb, 0xa40a,
+	0x0040, 0x16ac, 0x00c8, 0x16b5, 0x8001, 0x7872, 0xa084, 0xfc00,
+	0x0040, 0x16b9, 0x78ac, 0xc085, 0x78ae, 0x2001, 0x4005, 0x0078,
+	0x15bc, 0x7b7e, 0x7a7a, 0x7e86, 0x7d82, 0x7c76, 0xa48c, 0xff00,
+	0x0040, 0x16d1, 0x8407, 0x8004, 0x8004, 0x810c, 0x810c, 0x810f,
+	0xa118, 0xa291, 0x0000, 0xa6b1, 0x0000, 0xa581, 0x0000, 0x0078,
+	0x16db, 0x8407, 0x8004, 0x8004, 0xa318, 0xa291, 0x0000, 0xa6b1,
+	0x0000, 0xa581, 0x0000, 0x731a, 0x721e, 0x7622, 0x7026, 0xa605,
+	0x0040, 0x16e5, 0x7a10, 0xc2c5, 0x7a12, 0x78ac, 0xa084, 0xfffc,
+	0x78ae, 0x0078, 0x16ee, 0x78ac, 0xc085, 0x78ae, 0x0078, 0x15ba,
+	0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x16f9, 0x2029, 0x0000,
+	0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6, 0x72ca, 0x73ce,
+	0x74d6, 0xa005, 0x0040, 0x1728, 0xa40a, 0x0040, 0x1709, 0x00c8,
+	0x15bc, 0x8001, 0x7892, 0xa084, 0xfc00, 0x0040, 0x1716, 0x78ac,
+	0xc0c5, 0x78ae, 0x2001, 0x4005, 0x0078, 0x15bc, 0x7a9a, 0x7b9e,
+	0x7da2, 0x7ea6, 0x2600, 0xa505, 0x0040, 0x1721, 0x7a10, 0xc2c5,
+	0x7a12, 0x7c96, 0x78ac, 0xa084, 0xfcff, 0x78ae, 0x0078, 0x172b,
+	0x78ac, 0xc0c5, 0x78ae, 0x0078, 0x15ba, 0x2009, 0x0000, 0x786c,
+	0xa065, 0x0040, 0x1737, 0x8108, 0x6000, 0x0078, 0x1730, 0x7ac4,
+	0x0078, 0x15b8, 0x2009, 0x4e48, 0x210c, 0x7810, 0xd0ec, 0x00c0,
+	0x15b9, 0x2011, 0x4e88, 0x2214, 0x0078, 0x15b8, 0x2009, 0x4e49,
+	0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011, 0x4e89, 0x2214,
+	0x0078, 0x15b8, 0x2061, 0x4e40, 0x6128, 0x622c, 0x8214, 0x8214,
+	0x8214, 0x7810, 0xd0ec, 0x00c0, 0x1766, 0x2061, 0x4e80, 0x6328,
+	0x73da, 0x632c, 0x831c, 0x831c, 0x831c, 0x73de, 0x0078, 0x15b8,
+	0x2009, 0x4e4c, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011,
+	0x4e8c, 0x2214, 0x0078, 0x15b8, 0x7918, 0x0078, 0x15b9, 0x2009,
+	0x4e4d, 0x210c, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2011, 0x4e8d,
+	0x2214, 0x0078, 0x15b8, 0x2009, 0x4e4e, 0x210c, 0x7810, 0xd0ec,
+	0x00c0, 0x15b9, 0x2011, 0x4e8e, 0x2214, 0x0078, 0x15b8, 0x7920,
+	0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x7a24, 0x0078, 0x15b8, 0x71c4,
+	0xd1fc, 0x00c0, 0x179f, 0x2011, 0x52c0, 0x0078, 0x17a1, 0x2011,
+	0x5340, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa268,
+	0x6a00, 0x6804, 0xd09c, 0x0040, 0x17b0, 0x6b08, 0x0078, 0x17b1,
+	0x6b0c, 0x0078, 0x15b7, 0x77c4, 0x1078, 0x1de4, 0x2091, 0x8000,
+	0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x15b7, 0x2061,
+	0x4e40, 0x6118, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2061, 0x4e80,
+	0x6218, 0x0078, 0x15b8, 0x77c4, 0x1078, 0x1de4, 0x2091, 0x8000,
+	0x6908, 0x6a18, 0x6b10, 0x77da, 0x2091, 0x8001, 0x0078, 0x15b7,
+	0x71c4, 0x2110, 0xa294, 0x000f, 0xa282, 0x0010, 0x00c8, 0x15b2,
+	0x1078, 0x277f, 0xa384, 0x4000, 0x0040, 0x17e8, 0xa295, 0x0020,
+	0x0078, 0x15b7, 0x71c4, 0x2100, 0xc0bc, 0xa082, 0x0010, 0x00c8,
+	0x15b2, 0xd1bc, 0x00c0, 0x17f9, 0x2011, 0x4e48, 0x2204, 0x0078,
+	0x17fd, 0x2011, 0x4e88, 0x2204, 0xc0bd, 0x007e, 0x2100, 0xc0bc,
+	0x2012, 0x1078, 0x26dc, 0x017f, 0x0078, 0x15b9, 0x71c4, 0x2021,
+	0x4e49, 0x2404, 0x70c6, 0x2019, 0x0000, 0x0078, 0x1815, 0x71c8,
+	0x2021, 0x4e89, 0x2404, 0x70ca, 0xc3fd, 0x2011, 0x1834, 0x20a9,
+	0x0008, 0x2204, 0xa106, 0x0040, 0x1824, 0x8210, 0x00f0, 0x1819,
+	0x71c4, 0x72c8, 0x0078, 0x15b1, 0xa292, 0x1834, 0x027e, 0x2122,
+	0x017f, 0x1078, 0x26fd, 0x7810, 0xd0ec, 0x00c0, 0x1832, 0xd3fc,
+	0x0040, 0x180f, 0x0078, 0x15ba, 0x03e8, 0x00fa, 0x01f4, 0x02ee,
+	0x0004, 0x0001, 0x0002, 0x0003, 0x2061, 0x4e40, 0x6128, 0x622c,
+	0x8214, 0x8214, 0x8214, 0x70c4, 0x602a, 0x70c8, 0x8003, 0x8003,
+	0x8003, 0x602e, 0x7810, 0xd0ec, 0x00c0, 0x1862, 0x027e, 0x017e,
+	0x2061, 0x4e80, 0x6128, 0x622c, 0x8214, 0x8214, 0x8214, 0x70d8,
+	0x602a, 0x70dc, 0x8003, 0x8003, 0x8003, 0x602e, 0x71da, 0x72de,
+	0x017f, 0x027f, 0x0078, 0x15b8, 0x2061, 0x4e40, 0x6130, 0x70c4,
+	0x6032, 0x7810, 0xd0ec, 0x00c0, 0x15b9, 0x2061, 0x4e80, 0x6230,
+	0x70c8, 0x6032, 0x0078, 0x15b8, 0x7918, 0x0078, 0x15b9, 0x71c4,
+	0xa184, 0xffcf, 0x0040, 0x1883, 0x7810, 0xd0ec, 0x00c0, 0x15b2,
+	0x72c8, 0x0078, 0x15b1, 0x2011, 0x4e4d, 0x2204, 0x2112, 0x007e,
+	0x2019, 0x0000, 0x1078, 0x2764, 0x7810, 0xd0ec, 0x0040, 0x1893,
+	0x017f, 0x0078, 0x15b9, 0x71c8, 0xa184, 0xffcf, 0x0040, 0x189c,
+	0x2110, 0x71c4, 0x0078, 0x15b1, 0x2011, 0x4e8d, 0x2204, 0x2112,
+	0x007e, 0xc3fd, 0x1078, 0x2764, 0x027f, 0x017f, 0x0078, 0x15b8,
+	0x71c4, 0xa182, 0x0010, 0x0048, 0x18b4, 0x7810, 0xd0ec, 0x00c0,
+	0x15b2, 0x72c8, 0x0078, 0x15b1, 0x2011, 0x4e4e, 0x2204, 0x007e,
+	0x2112, 0x2019, 0x0000, 0x1078, 0x2742, 0x7810, 0xd0ec, 0x0040,
+	0x18c4, 0x017f, 0x0078, 0x15b9, 0x71c8, 0xa182, 0x0010, 0x0048,
+	0x18cd, 0x2110, 0x71c4, 0x0078, 0x15b1, 0x2011, 0x4e8e, 0x2204,
+	0x007e, 0x2112, 0xc3fd, 0x1078, 0x2742, 0x027f, 0x017f, 0x0078,
+	0x15b8, 0x71c4, 0x72c8, 0xa184, 0xfffd, 0x00c0, 0x15b1, 0xa284,
+	0xfffd, 0x00c0, 0x15b1, 0x2100, 0x7920, 0x7822, 0x2200, 0x7a24,
+	0x7826, 0x0078, 0x15b8, 0x71c4, 0xd1fc, 0x00c0, 0x18f3, 0x2011,
+	0x52c0, 0x0078, 0x18f5, 0x2011, 0x5340, 0x8107, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa268, 0x2019, 0x0000, 0x72c8, 0x2091,
+	0x8000, 0x6800, 0x007e, 0xa226, 0x0040, 0x191e, 0x6a02, 0xd4ec,
+	0x0040, 0x190b, 0xc3a5, 0xd4e4, 0x0040, 0x190f, 0xc39d, 0xd4f4,
+	0x0040, 0x191e, 0x810f, 0xd2f4, 0x0040, 0x191a, 0x1078, 0x27c1,
+	0x0078, 0x191e, 0x1078, 0x279f, 0x0078, 0x191e, 0x72cc, 0x6808,
+	0xa206, 0x0040, 0x1940, 0xa2a4, 0x00ff, 0x7814, 0xd0e4, 0x00c0,
+	0x1931, 0xa482, 0x0028, 0x0048, 0x193d, 0x0040, 0x193d, 0x0078,
+	0x1935, 0xa482, 0x0043, 0x0048, 0x193d, 0x71c4, 0x71c6, 0x027f,
+	0x72ca, 0x2091, 0x8001, 0x0078, 0x15b3, 0x6a0a, 0xa39d, 0x000a,
+	0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x2091, 0x8001,
+	0x0078, 0x15b7, 0x77c4, 0x1078, 0x1de4, 0x2091, 0x8000, 0x6a14,
+	0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708,
+	0x0078, 0x15b7, 0x70c4, 0x2061, 0x4e40, 0x6118, 0x601a, 0x7810,
+	0xd0ec, 0x00c0, 0x15b9, 0x70c8, 0x2061, 0x4e80, 0x6218, 0x601a,
+	0x0078, 0x15b8, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8,
+	0x15b2, 0x1078, 0x27e3, 0xa384, 0x4000, 0x0040, 0x1979, 0xa295,
+	0x0020, 0x0078, 0x15b7, 0x77c4, 0x1078, 0x1de4, 0x2091, 0x8000,
+	0x6a08, 0xc28d, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x15b8,
+	0x77c4, 0x1078, 0x1de4, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9,
+	0x6a0a, 0x6804, 0xa005, 0x0040, 0x1997, 0x1078, 0x2628, 0x2091,
+	0x8001, 0x2708, 0x0078, 0x15b8, 0x77c4, 0x1078, 0x1de4, 0x2091,
+	0x8000, 0x6a08, 0xc295, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x19aa,
+	0x1078, 0x2628, 0x2091, 0x8001, 0x2708, 0x0078, 0x15b8, 0x77c4,
+	0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000,
+	0x1078, 0x1dff, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078, 0x15b8,
+	0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x19d4, 0xd7fc, 0x0040, 0x19ce,
+	0x1078, 0x1d64, 0x0040, 0x19d4, 0x0078, 0x15bc, 0x1078, 0x1d54,
+	0x0040, 0x19d4, 0x0078, 0x15bc, 0x73c8, 0x72cc, 0x77c6, 0x73ca,
+	0x72ce, 0x1078, 0x1e86, 0x00c0, 0x19fe, 0x6818, 0xa005, 0x0040,
+	0x19f8, 0x2708, 0x077e, 0x1078, 0x2813, 0x077f, 0x00c0, 0x19f8,
+	0x2001, 0x0015, 0xd7fc, 0x00c0, 0x19f1, 0x2061, 0x4e40, 0x0078,
+	0x19f4, 0xc0fd, 0x2061, 0x4e80, 0x782a, 0x2091, 0x8001, 0x007c,
+	0x2091, 0x8001, 0x2001, 0x4005, 0x0078, 0x15bc, 0x2091, 0x8001,
+	0x0078, 0x15ba, 0x77c4, 0x7814, 0xd0e4, 0x00c0, 0x1a16, 0xd7fc,
+	0x0040, 0x1a10, 0x1078, 0x1d64, 0x0040, 0x1a16, 0x0078, 0x15bc,
+	0x1078, 0x1d54, 0x0040, 0x1a16, 0x0078, 0x15bc, 0x77c6, 0x2041,
+	0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
+	0x1dff, 0x2009, 0x0016, 0xd7fc, 0x00c0, 0x1a2a, 0x2061, 0x4e40,
+	0x0078, 0x1a2d, 0x2061, 0x4e80, 0xc1fd, 0x6067, 0x0003, 0x607f,
+	0x0000, 0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, 0xc1dc, 0x61d6,
+	0x1078, 0x2628, 0x2091, 0x8001, 0x007c, 0x77c8, 0x77ca, 0x77c4,
+	0x77c6, 0x7814, 0xd0e4, 0x00c0, 0x1a54, 0xd7fc, 0x0040, 0x1a4e,
+	0x1078, 0x1d64, 0x0040, 0x1a54, 0x0078, 0x15bc, 0x1078, 0x1d54,
+	0x0040, 0x1a54, 0x0078, 0x15bc, 0xa7bc, 0xff00, 0x2091, 0x8000,
+	0x2009, 0x0017, 0xd7fc, 0x00c0, 0x1a61, 0x2061, 0x4e40, 0x0078,
+	0x1a64, 0x2061, 0x4e80, 0xc1fd, 0x607f, 0x0000, 0x6067, 0x0002,
+	0x6776, 0x6083, 0x000f, 0x792a, 0x61d4, 0xc1dc, 0x61d6, 0x1078,
+	0x2628, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0005, 0x2051,
+	0x0010, 0x2091, 0x8000, 0x70c8, 0xa005, 0x0040, 0x1a82, 0x60d4,
+	0xc0fd, 0x60d6, 0x1078, 0x1dff, 0x70c8, 0x6836, 0x8738, 0xa784,
+	0x001f, 0x00c0, 0x1a82, 0x2091, 0x8001, 0x007c, 0x2019, 0x0000,
+	0x7814, 0xd0e4, 0x00c0, 0x1aa4, 0x72c8, 0xd284, 0x0040, 0x1a9e,
+	0x1078, 0x1d64, 0x0040, 0x1aa4, 0x0078, 0x15bc, 0x1078, 0x1d54,
+	0x0040, 0x1aa4, 0x0078, 0x15bc, 0x72c8, 0x72ca, 0x78ac, 0xa084,
+	0x0003, 0x00c0, 0x1acf, 0x2039, 0x0000, 0xd284, 0x0040, 0x1ab1,
+	0xc7fd, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078,
+	0x1de4, 0x2091, 0x8000, 0x6808, 0xc0d4, 0xa80d, 0x690a, 0x2091,
+	0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1ab7, 0xa7bc, 0xff00,
+	0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1ab7, 0x2091,
+	0x8000, 0x72c8, 0xd284, 0x00c0, 0x1ae1, 0x7810, 0xd0ec, 0x0040,
+	0x1add, 0x2069, 0x0100, 0x0078, 0x1ae3, 0x2069, 0x0200, 0x0078,
+	0x1ae3, 0x2069, 0x0100, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830,
+	0xd0b4, 0x0040, 0x1b03, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848,
+	0xd094, 0x0040, 0x1af5, 0x00f0, 0x1aef, 0x684b, 0x0009, 0x20a9,
+	0x0014, 0x6848, 0xd084, 0x0040, 0x1aff, 0x00f0, 0x1af9, 0x20a9,
+	0x00fa, 0x00f0, 0x1b01, 0x2079, 0x4e00, 0x2009, 0x0018, 0x72c8,
+	0xd284, 0x00c0, 0x1b0f, 0x2061, 0x4e40, 0x0078, 0x1b12, 0x2061,
+	0x4e80, 0xc1fd, 0x607f, 0x0000, 0x792a, 0x6067, 0x0001, 0x6083,
+	0x000f, 0x60a7, 0x0000, 0x60a8, 0x60b2, 0x60b6, 0x60d4, 0xd0b4,
+	0x0040, 0x1b2e, 0xc0b4, 0x60d6, 0x0c7e, 0x60b8, 0xa065, 0x6008,
+	0xc0d4, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x60d4, 0xa084,
+	0x77ff, 0x60d6, 0x78ac, 0xc08d, 0x78ae, 0x83ff, 0x0040, 0x1b39,
+	0x007c, 0x681b, 0x0047, 0x2091, 0x8001, 0x007c, 0x73cc, 0x1078,
+	0x1a90, 0x69ec, 0x6a48, 0xa185, 0x1800, 0x684a, 0xa185, 0x0040,
+	0x68ee, 0x73cc, 0x2021, 0x0004, 0x20a9, 0x09ff, 0x00f0, 0x1b4e,
+	0x8421, 0x00c0, 0x1b4c, 0x8319, 0x00c0, 0x1b4a, 0x69ee, 0x6a4a,
+	0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x1b62, 0x2069, 0x4e40,
+	0x0078, 0x1b64, 0x2069, 0x4e80, 0x71c4, 0x71c6, 0x6916, 0x81ff,
+	0x00c0, 0x1b6c, 0x68a7, 0x0001, 0x78ac, 0xc08c, 0x78ae, 0xd084,
+	0x00c0, 0x1b74, 0x1078, 0x1ee6, 0x007c, 0x75d8, 0x74dc, 0x75da,
+	0x74de, 0x0078, 0x1b7e, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8,
+	0x72cc, 0x71c6, 0x73ca, 0x72ce, 0x2079, 0x4e00, 0x7dde, 0x7cda,
+	0x7bd6, 0x7ad2, 0x1078, 0x1dbd, 0x0040, 0x1c80, 0x20a9, 0x0005,
+	0x20a1, 0x4e14, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009,
+	0x0040, 0x1078, 0x1fd1, 0x0040, 0x1ba1, 0x1078, 0x1dc6, 0x0078,
+	0x1c80, 0x6004, 0xa08c, 0x00ff, 0xa18e, 0x0009, 0x00c0, 0x1bac,
+	0x007e, 0x1078, 0x2378, 0x007f, 0xa084, 0xff00, 0x8007, 0x8009,
+	0x0040, 0x1c20, 0x0c7e, 0x2c68, 0x1078, 0x1dbd, 0x0040, 0x1bf2,
+	0x2c00, 0x689e, 0x8109, 0x00c0, 0x1bb3, 0x609f, 0x0000, 0x0c7f,
+	0x0c7e, 0x7ddc, 0x7cd8, 0x7bd4, 0x7ad0, 0xa290, 0x0040, 0xa399,
+	0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x7dde, 0x7cda, 0x7bd6,
+	0x7ad2, 0x2c68, 0x689c, 0xa065, 0x0040, 0x1c1f, 0x2009, 0x0040,
+	0x1078, 0x1fd1, 0x00c0, 0x1c09, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0002, 0x00c0, 0x1bf2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x000a,
+	0x00c0, 0x1bee, 0x017e, 0x1078, 0x2374, 0x017f, 0x2d00, 0x6002,
+	0x0078, 0x1bc1, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e49, 0x0c7f,
+	0x609f, 0x0000, 0x1078, 0x1c84, 0x2009, 0x0018, 0x6008, 0xc0cd,
+	0x600a, 0x6004, 0x6086, 0x1078, 0x1d74, 0x1078, 0x1dc6, 0x0078,
+	0x1c80, 0x0c7f, 0x0c7e, 0x609c, 0x1078, 0x1e49, 0x0c7f, 0x609f,
+	0x0000, 0x1078, 0x1c84, 0x2009, 0x0018, 0x6087, 0x0103, 0x601b,
+	0x0003, 0x1078, 0x1d74, 0x1078, 0x1dc6, 0x0078, 0x1c80, 0x0c7f,
+	0x7814, 0xd0e4, 0x00c0, 0x1c45, 0x6114, 0xd1fc, 0x0040, 0x1c2e,
+	0x1078, 0x1d64, 0x0040, 0x1c45, 0x0078, 0x1c32, 0x1078, 0x1d54,
+	0x0040, 0x1c45, 0x2029, 0x0000, 0x2520, 0x2009, 0x0018, 0x73c8,
+	0x72cc, 0x6087, 0x0103, 0x601b, 0x0021, 0x1078, 0x1d74, 0x1078,
+	0x1dc6, 0x2001, 0x4007, 0x0078, 0x15bc, 0x74c4, 0x73c8, 0x72cc,
+	0x6014, 0x2091, 0x8000, 0x0e7e, 0x2009, 0x0012, 0xd0fc, 0x00c0,
+	0x1c55, 0x2071, 0x4e40, 0x0078, 0x1c58, 0x2071, 0x4e80, 0xc1fd,
+	0x792a, 0x7067, 0x0005, 0x71d4, 0xc1dc, 0x71d6, 0x736a, 0x726e,
+	0x7472, 0x7076, 0x707b, 0x0000, 0x2c00, 0x707e, 0xa02e, 0x2530,
+	0x611c, 0xa184, 0x0060, 0x0040, 0x1c6f, 0x1078, 0x4632, 0x0e7f,
+	0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000,
+	0x6714, 0x6023, 0x0000, 0x1078, 0x2628, 0x2091, 0x8001, 0x007c,
+	0x70c3, 0x4005, 0x0078, 0x15bd, 0x20a9, 0x0005, 0x2099, 0x4e14,
+	0x2091, 0x8000, 0x530a, 0x2091, 0x8001, 0x2100, 0xa210, 0xa399,
+	0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x007c, 0x71c4, 0x70c7,
+	0x0000, 0x791e, 0x0078, 0x15ba, 0x71c4, 0x71c6, 0x2168, 0x0078,
+	0x1ca3, 0x2069, 0x1000, 0x690c, 0xa016, 0x2d04, 0xa210, 0x8d68,
+	0x8109, 0x00c0, 0x1ca5, 0xa285, 0x0000, 0x00c0, 0x1cb3, 0x70c3,
+	0x4000, 0x0078, 0x1cb5, 0x70c3, 0x4003, 0x70ca, 0x0078, 0x15bd,
+	0x7964, 0x71c6, 0x71c4, 0xa182, 0x0003, 0x00c8, 0x15b2, 0x7966,
+	0x0078, 0x15ba, 0x7964, 0x71c6, 0x0078, 0x15ba, 0x7900, 0x71c6,
+	0x71c4, 0x7902, 0x0078, 0x15ba, 0x7900, 0x71c6, 0x0078, 0x15ba,
+	0x70c4, 0x2011, 0x0000, 0xa08c, 0x000d, 0x0040, 0x1ce5, 0x810c,
+	0x0048, 0x1ce1, 0x8210, 0x810c, 0x810c, 0x0048, 0x1ce1, 0x8210,
+	0x810c, 0x81ff, 0x00c0, 0x15b3, 0x8210, 0x7a0e, 0xd28c, 0x0040,
+	0x1d11, 0x7910, 0xc1cd, 0x7912, 0x2009, 0x0021, 0x2019, 0x0003,
+	0xd284, 0x0040, 0x1d0b, 0x8108, 0x2019, 0x0041, 0x2011, 0x964e,
+	0x2312, 0x2019, 0x0042, 0x8210, 0x2312, 0x2019, 0x0043, 0x8210,
+	0x2312, 0x2019, 0x0046, 0x8210, 0x2312, 0x2019, 0x0047, 0x8210,
+	0x2312, 0x2019, 0x0006, 0x2011, 0x9653, 0x2112, 0x2011, 0x9673,
+	0x2312, 0x7904, 0x7806, 0x0078, 0x15b9, 0x7804, 0x70c6, 0x0078,
+	0x15ba, 0x71c4, 0xd1fc, 0x00c0, 0x1d21, 0x2011, 0x52c0, 0x0078,
+	0x1d23, 0x2011, 0x5340, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa268, 0x6a14, 0xd2b4, 0x0040, 0x1d32, 0x2011, 0x0001,
+	0x0078, 0x1d34, 0x2011, 0x0000, 0x6b0c, 0x6800, 0x70da, 0x0078,
+	0x15b7, 0x017e, 0x7814, 0xd0f4, 0x0040, 0x1d46, 0x2001, 0x4007,
+	0x70db, 0x0000, 0xa18d, 0x0001, 0x0078, 0x1d52, 0xd0fc, 0x0040,
+	0x1d51, 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078,
+	0x1d52, 0xa006, 0x017f, 0x007c, 0x017e, 0x7814, 0xd0f4, 0x0040,
+	0x1d61, 0x2001, 0x4007, 0x70db, 0x0000, 0xa18d, 0x0001, 0x0078,
+	0x1d62, 0xa006, 0x017f, 0x007c, 0x017e, 0x7814, 0xd0fc, 0x0040,
+	0x1d71, 0x2001, 0x4007, 0x70db, 0x0001, 0xa18d, 0x0001, 0x0078,
+	0x1d72, 0xa006, 0x017f, 0x007c, 0x7112, 0x721a, 0x731e, 0x7810,
+	0xd0c4, 0x0040, 0x1d7d, 0x7422, 0x7526, 0xac80, 0x0001, 0x8108,
+	0x810c, 0x81a9, 0x8098, 0x20a1, 0x0030, 0x7003, 0x0000, 0x6084,
+	0x20a2, 0x53a6, 0x7007, 0x0001, 0x7974, 0xa184, 0xff00, 0x0040,
+	0x1d9a, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100,
+	0x0078, 0x1d9d, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78,
+	0xa006, 0xa211, 0x7d10, 0xd5c4, 0x0040, 0x1daa, 0x7b84, 0xa319,
+	0x7c80, 0xa421, 0x7008, 0xd0fc, 0x0040, 0x1daa, 0x7003, 0x0001,
+	0x7007, 0x0006, 0x711a, 0x721e, 0x7d10, 0xd5c4, 0x0040, 0x1dba,
+	0x7322, 0x7426, 0xa084, 0x01e0, 0x007c, 0x7848, 0xa065, 0x0040,
+	0x1dc5, 0x2c04, 0x784a, 0x2063, 0x0000, 0x007c, 0x0f7e, 0x2079,
+	0x4e00, 0x7848, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1dd1, 0x1078,
+	0x296b, 0x784a, 0x0f7f, 0x007c, 0x2011, 0x9800, 0x7a4a, 0x7bc4,
+	0x8319, 0x0040, 0x1de1, 0xa280, 0x0032, 0x2012, 0x2010, 0x0078,
+	0x1dd8, 0x2013, 0x0000, 0x007c, 0x017e, 0x027e, 0xd7fc, 0x00c0,
+	0x1ded, 0x2011, 0x53c0, 0x0078, 0x1def, 0x2011, 0x73c0, 0xa784,
+	0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x1dfa, 0x8003, 0x8003,
+	0x8003, 0x8003, 0xa105, 0xa268, 0x027f, 0x017f, 0x007c, 0x1078,
+	0x1de4, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xf9ef,
+	0xa80d, 0x690a, 0x0e7e, 0xd7fc, 0x00c0, 0x1e14, 0x2009, 0x4e53,
+	0x2071, 0x4e40, 0x0078, 0x1e18, 0x2009, 0x4e93, 0x2071, 0x4e80,
+	0x210c, 0x6804, 0xa005, 0x0040, 0x1e28, 0xa116, 0x00c0, 0x1e28,
+	0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1e2b,
+	0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1e40, 0x6000,
+	0x6806, 0x1078, 0x1e5b, 0x1078, 0x201d, 0x6810, 0x7908, 0x8109,
+	0x790a, 0x8001, 0x6812, 0x00c0, 0x1e2b, 0x7910, 0xc1a5, 0x7912,
+	0x017f, 0x6902, 0x6906, 0x2d00, 0x2060, 0x1078, 0x2acc, 0x0e7f,
+	0x007c, 0xa065, 0x0040, 0x1e5a, 0x2008, 0x609c, 0xa005, 0x0040,
+	0x1e57, 0x2062, 0x609f, 0x0000, 0xa065, 0x0078, 0x1e4d, 0x7848,
+	0x794a, 0x2062, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9,
+	0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828,
+	0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0xd7fc, 0x00c0, 0x1e76,
+	0x2071, 0x4e40, 0x2031, 0x4ec0, 0x0078, 0x1e7a, 0x2071, 0x4e80,
+	0x2031, 0x50c0, 0x7050, 0xa08c, 0x0200, 0x00c0, 0x1e84, 0xa608,
+	0x2d0a, 0x8000, 0x7052, 0xa006, 0x0e7f, 0x007c, 0x0f7e, 0xd7fc,
+	0x00c0, 0x1e8e, 0x2079, 0x4e40, 0x0078, 0x1e90, 0x2079, 0x4e80,
+	0x1078, 0x1de4, 0x2091, 0x8000, 0x6804, 0x780a, 0xa065, 0x0040,
+	0x1ee4, 0x0078, 0x1ea2, 0x2c00, 0x780a, 0x2060, 0x6000, 0xa065,
+	0x0040, 0x1ee4, 0x6010, 0xa306, 0x00c0, 0x1e9b, 0x600c, 0xa206,
+	0x00c0, 0x1e9b, 0x2c28, 0x784c, 0xac06, 0x00c0, 0x1eb1, 0x0078,
+	0x1ee1, 0x6804, 0xac06, 0x00c0, 0x1ebf, 0x6000, 0x2060, 0x6806,
+	0xa005, 0x00c0, 0x1ebf, 0x6803, 0x0000, 0x0078, 0x1ec9, 0x6400,
+	0x7808, 0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1ec9, 0x2c00,
+	0x6802, 0x2560, 0x0f7f, 0x1078, 0x1e5b, 0x0f7e, 0x601b, 0x0005,
+	0x6023, 0x0020, 0x0f7f, 0x1078, 0x201d, 0x0f7e, 0x7908, 0x8109,
+	0x790a, 0x6810, 0x8001, 0x6812, 0x00c0, 0x1ee1, 0x7810, 0xc0a5,
+	0x7812, 0x2001, 0xffff, 0xa005, 0x0f7f, 0x007c, 0x077e, 0x2700,
+	0x2039, 0x0000, 0xd0fc, 0x0040, 0x1eee, 0xc7fd, 0x2041, 0x0021,
+	0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000, 0x1078, 0x1dff,
+	0x8738, 0xa784, 0x001f, 0x00c0, 0x1ef6, 0xa7bc, 0xff00, 0x873f,
+	0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1ef6, 0x2091, 0x8001,
+	0x077f, 0x007c, 0x786c, 0x2009, 0x9674, 0x210c, 0xa10d, 0x0040,
+	0x1f14, 0xa065, 0x0078, 0x2395, 0x2061, 0x0000, 0x6018, 0xd084,
+	0x00c0, 0x1f34, 0x7810, 0xd08c, 0x0040, 0x1f25, 0xc08c, 0x7812,
+	0xc7fc, 0x2069, 0x4e40, 0x0078, 0x1f2a, 0xc08d, 0x7812, 0x2069,
+	0x4e80, 0xc7fd, 0x2091, 0x8000, 0x681c, 0x681f, 0x0000, 0x2091,
+	0x8001, 0xa005, 0x00c0, 0x1f35, 0x007c, 0xa08c, 0xfff0, 0x0040,
+	0x1f3b, 0x1078, 0x296b, 0x0079, 0x1f3d, 0x1f4d, 0x1f50, 0x1f56,
+	0x1f5a, 0x1f4e, 0x1f5e, 0x1f4e, 0x1f4e, 0x1f4e, 0x1f64, 0x1f95,
+	0x1f99, 0x1f9f, 0x1fb4, 0x1f4e, 0x1f4e, 0x007c, 0x1078, 0x296b,
+	0x1078, 0x1ee6, 0x2001, 0x8001, 0x0078, 0x1fc0, 0x2001, 0x8003,
+	0x0078, 0x1fc0, 0x2001, 0x8004, 0x0078, 0x1fc0, 0x1078, 0x1ee6,
+	0x2001, 0x8006, 0x0078, 0x1fc0, 0x2091, 0x8000, 0x077e, 0xd7fc,
+	0x00c0, 0x1f70, 0x2069, 0x4e40, 0x2039, 0x0009, 0x0078, 0x1f74,
+	0x2069, 0x4e80, 0x2039, 0x0009, 0x6800, 0xa086, 0x0000, 0x0040,
+	0x1f7e, 0x007f, 0x6f1e, 0x2091, 0x8001, 0x007c, 0x6874, 0x077f,
+	0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010,
+	0x1078, 0x1dff, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1f88, 0x2091,
+	0x8001, 0x2001, 0x800a, 0x0078, 0x1fc0, 0x2001, 0x800c, 0x0078,
+	0x1fc0, 0x1078, 0x1ee6, 0x2001, 0x800d, 0x0078, 0x1fc0, 0x7814,
+	0xd0e4, 0x00c0, 0x1fb2, 0xd0ec, 0x0040, 0x1fac, 0xd7fc, 0x0040,
+	0x1fac, 0x78e4, 0x0078, 0x1fad, 0x78e0, 0x70c6, 0x2001, 0x800e,
+	0x0078, 0x1fc0, 0x0078, 0x1f4e, 0xd7fc, 0x0040, 0x1fba, 0x78ec,
+	0x0078, 0x1fbb, 0x78e8, 0x70c6, 0x2001, 0x800f, 0x0078, 0x1fc0,
+	0x70c2, 0xd7fc, 0x00c0, 0x1fc8, 0x70db, 0x0000, 0x0078, 0x1fca,
+	0x70db, 0x0001, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x4080,
+	0x007c, 0xac80, 0x0001, 0x81ff, 0x0040, 0x1ffc, 0x2099, 0x0030,
+	0x20a0, 0x700c, 0xa084, 0x03ff, 0x0040, 0x1fde, 0x7018, 0x007e,
+	0x701c, 0x007e, 0x7020, 0x007e, 0x7024, 0x007e, 0x7112, 0x81ac,
+	0x721a, 0x731e, 0x7422, 0x7526, 0x7003, 0x0001, 0x7007, 0x0001,
+	0x7008, 0x800b, 0x00c8, 0x1ff0, 0x7007, 0x0002, 0xa08c, 0x01e0,
+	0x00c0, 0x1ffc, 0x53a5, 0xa006, 0x7003, 0x0000, 0x7007, 0x0004,
+	0x007f, 0x7026, 0x007f, 0x7022, 0x007f, 0x701e, 0x007f, 0x701a,
+	0x007c, 0x2011, 0x0020, 0x2009, 0x0010, 0x6b0a, 0x6c0e, 0x6803,
+	0xfd00, 0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290,
+	0x0004, 0x8109, 0x00c0, 0x200d, 0x007c, 0x6004, 0x6086, 0x2c08,
+	0x2063, 0x0000, 0x7868, 0xa005, 0x796a, 0x0040, 0x202a, 0x2c02,
+	0x0078, 0x202b, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x4e00, 0x6887,
+	0x0103, 0x2d08, 0x206b, 0x0000, 0x6068, 0xa005, 0x616a, 0x0040,
+	0x203c, 0x2d02, 0x0078, 0x203d, 0x616e, 0x0c7f, 0x007c, 0x2091,
+	0x8000, 0x2c04, 0x786e, 0xa005, 0x00c0, 0x2047, 0x786a, 0x2091,
+	0x8001, 0x609c, 0xa005, 0x0040, 0x2060, 0x0c7e, 0x2060, 0x2008,
+	0x609c, 0xa005, 0x0040, 0x205c, 0x2062, 0x609f, 0x0000, 0xa065,
+	0x609c, 0xa005, 0x00c0, 0x2054, 0x7848, 0x794a, 0x2062, 0x0c7f,
+	0x7848, 0x2062, 0x609f, 0x0000, 0xac85, 0x0000, 0x00c0, 0x206a,
+	0x1078, 0x296b, 0x784a, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004,
+	0x8086, 0x818e, 0x00c8, 0x2075, 0xa200, 0x00f0, 0x2070, 0x8086,
+	0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x209b,
+	0xa11a, 0x00c8, 0x209b, 0x8213, 0x818d, 0x0048, 0x208e, 0xa11a,
+	0x00c8, 0x208f, 0x00f0, 0x2083, 0x0078, 0x2093, 0xa11a, 0x2308,
+	0x8210, 0x00f0, 0x2083, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080,
+	0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078,
+	0x2097, 0x7d74, 0x70d0, 0xa506, 0x0040, 0x2187, 0x7810, 0x2050,
+	0x7800, 0xd08c, 0x0040, 0x20c3, 0xdaec, 0x0040, 0x20c3, 0x0e7e,
+	0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x20c0,
+	0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040, 0x20c3, 0x0078, 0x2187,
+	0x0e7f, 0x0078, 0x2187, 0x1078, 0x1dbd, 0x0040, 0x2187, 0xa046,
+	0x7970, 0x2500, 0x8000, 0xa112, 0x2009, 0x0040, 0x00c8, 0x20d2,
+	0x0078, 0x20d9, 0x72d0, 0xa206, 0x0040, 0x20d9, 0x8840, 0x2009,
+	0x0080, 0x0c7e, 0x7112, 0x7007, 0x0001, 0x2099, 0x0030, 0x20a9,
+	0x0020, 0xac80, 0x0001, 0x20a0, 0x2061, 0x0000, 0x88ff, 0x0040,
+	0x20eb, 0x1078, 0x1dbd, 0x7008, 0xd0fc, 0x0040, 0x20eb, 0x7007,
+	0x0002, 0x2091, 0x8001, 0xa08c, 0x01e0, 0x00c0, 0x2122, 0x53a5,
+	0x8cff, 0x00c0, 0x2100, 0x88ff, 0x0040, 0x2171, 0x0078, 0x210a,
+	0x2c00, 0x788e, 0x20a9, 0x0020, 0xac80, 0x0001, 0x20a0, 0x53a5,
+	0x0078, 0x2171, 0xa046, 0x7218, 0x731c, 0xdac4, 0x0040, 0x2112,
+	0x7420, 0x7524, 0xa292, 0x0040, 0xa39b, 0x0000, 0xa4a3, 0x0000,
+	0xa5ab, 0x0000, 0x721a, 0x731e, 0xdac4, 0x0040, 0x2122, 0x7422,
+	0x7526, 0xa006, 0x7007, 0x0004, 0x0040, 0x2171, 0x8cff, 0x0040,
+	0x212b, 0x1078, 0x1dc6, 0x0c7f, 0x1078, 0x1dc6, 0xa046, 0x7888,
+	0x8000, 0x788a, 0xa086, 0x0002, 0x0040, 0x2151, 0x7a7c, 0x7b78,
+	0xdac4, 0x0040, 0x213d, 0x7c84, 0x7d80, 0x7974, 0x8107, 0x8004,
+	0x8004, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000,
+	0x721a, 0x731e, 0xdac4, 0x0040, 0x2187, 0x7422, 0x7526, 0x0078,
+	0x2187, 0x6014, 0xd0fc, 0x00c0, 0x2159, 0x2069, 0x4e40, 0x0078,
+	0x215b, 0x2069, 0x4e80, 0x2091, 0x8000, 0x681f, 0x0002, 0x88ff,
+	0x0040, 0x2167, 0xa046, 0x788c, 0x2060, 0x0078, 0x2151, 0x788b,
+	0x0000, 0x78ac, 0xa085, 0x0003, 0x78ae, 0x2091, 0x8001, 0x0078,
+	0x2187, 0x0c7f, 0x788b, 0x0000, 0x1078, 0x2346, 0x6004, 0xa084,
+	0x000f, 0x1078, 0x2188, 0x88ff, 0x0040, 0x2185, 0x788c, 0x2060,
+	0x6004, 0xa084, 0x000f, 0x1078, 0x2188, 0x0078, 0x20a1, 0x007c,
+	0x0079, 0x218a, 0x219a, 0x21b8, 0x21d6, 0x219a, 0x21e7, 0x21ab,
+	0x219a, 0x219a, 0x219a, 0x21b6, 0x21d4, 0x219a, 0x219a, 0x219a,
+	0x219a, 0x219a, 0x2039, 0x0400, 0x78bc, 0xa705, 0x78be, 0x6008,
+	0xa705, 0x600a, 0x1078, 0x222a, 0x609c, 0x78ba, 0x609f, 0x0000,
+	0x1078, 0x2330, 0x007c, 0x78bc, 0xd0c4, 0x0040, 0x21b1, 0x0078,
+	0x219a, 0x601c, 0xc0bd, 0x601e, 0x0078, 0x21be, 0x1078, 0x2378,
+	0x78bc, 0xd0c4, 0x0040, 0x21be, 0x0078, 0x219a, 0x78bf, 0x0000,
+	0x6004, 0x8007, 0xa084, 0x00ff, 0x78b2, 0x8001, 0x0040, 0x21d1,
+	0x1078, 0x222a, 0x0040, 0x21d1, 0x78bc, 0xc0c5, 0x78be, 0x0078,
+	0x21d3, 0x0078, 0x2249, 0x007c, 0x1078, 0x2374, 0x78bc, 0xa08c,
+	0x0e00, 0x00c0, 0x21de, 0xd0c4, 0x00c0, 0x21e0, 0x0078, 0x219a,
+	0x1078, 0x222a, 0x00c0, 0x21e6, 0x0078, 0x2249, 0x007c, 0x78bc,
+	0xd0c4, 0x0040, 0x21ed, 0x0078, 0x219a, 0x78bf, 0x0000, 0x6714,
+	0x2011, 0x0001, 0x22a8, 0x6018, 0xa084, 0x00ff, 0xa005, 0x0040,
+	0x220d, 0xa7bc, 0xff00, 0x20a9, 0x0020, 0xa08e, 0x0001, 0x0040,
+	0x220d, 0xa7bc, 0x8000, 0x2011, 0x0002, 0x20a9, 0x0100, 0xa08e,
+	0x0002, 0x0040, 0x220d, 0x0078, 0x2227, 0x1078, 0x1de4, 0x2d00,
+	0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084,
+	0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001, 0x00f0, 0x2210,
+	0x8211, 0x0040, 0x2227, 0x20a9, 0x0100, 0x0078, 0x2210, 0x1078,
+	0x1dc6, 0x007c, 0x609f, 0x0000, 0x78b4, 0xa06d, 0x2c00, 0x78b6,
+	0x00c0, 0x2235, 0x78ba, 0x0078, 0x223d, 0x689e, 0x2d00, 0x6002,
+	0x78b8, 0xad06, 0x00c0, 0x223d, 0x6002, 0x78b0, 0x8001, 0x78b2,
+	0x00c0, 0x2248, 0x78bc, 0xc0c4, 0x78be, 0x78b8, 0x2060, 0xa006,
+	0x007c, 0x0e7e, 0xa02e, 0x2530, 0x7dba, 0x7db6, 0x65ae, 0x65b2,
+	0x601c, 0x60a2, 0x2048, 0xa984, 0xe1ff, 0x601e, 0xa984, 0x0060,
+	0x0040, 0x225c, 0x1078, 0x4632, 0x6596, 0x65a6, 0x669a, 0x66aa,
+	0x6714, 0x2071, 0x4e80, 0xd7fc, 0x00c0, 0x2268, 0x2071, 0x4e40,
+	0xa784, 0x0f00, 0x800b, 0xa784, 0x001f, 0x0040, 0x2273, 0x8003,
+	0x8003, 0x8003, 0x8003, 0xa105, 0x71c4, 0xa168, 0x2700, 0x8007,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0x71c8, 0xa100, 0x60c2,
+	0x2091, 0x8000, 0x7814, 0xd0c4, 0x0040, 0x2298, 0xd0ec, 0x0040,
+	0x2294, 0xd7fc, 0x00c0, 0x2291, 0xd0f4, 0x00c0, 0x229f, 0x0078,
+	0x2298, 0xd0fc, 0x00c0, 0x229f, 0x7810, 0xd0f4, 0x00c0, 0x229f,
+	0x6e08, 0xd684, 0x0040, 0x22c9, 0xd9fc, 0x00c0, 0x22c9, 0x2091,
+	0x8001, 0x1078, 0x1e5b, 0x2091, 0x8000, 0x1078, 0x201d, 0x2091,
+	0x8001, 0x7814, 0xd0e4, 0x00c0, 0x232e, 0x7814, 0xd0c4, 0x0040,
+	0x232e, 0xd0ec, 0x0040, 0x22c1, 0xd7fc, 0x00c0, 0x22bc, 0xd0f4,
+	0x00c0, 0x22c5, 0x0078, 0x232e, 0xd0fc, 0x00c0, 0x22c5, 0x0078,
+	0x232e, 0x7810, 0xd0f4, 0x0040, 0x232e, 0x601b, 0x0021, 0x0078,
+	0x232e, 0x6024, 0xa096, 0x0001, 0x00c0, 0x22d0, 0x8000, 0x6026,
+	0x6a10, 0x6814, 0xa202, 0x0048, 0x22e3, 0x0040, 0x22e3, 0x2091,
+	0x8001, 0x2039, 0x0200, 0x609c, 0x78ba, 0x609f, 0x0000, 0x1078,
+	0x2330, 0x0078, 0x232e, 0x2c08, 0xd9fc, 0x0040, 0x230b, 0x6800,
+	0xa065, 0x0040, 0x230b, 0x6a04, 0x7000, 0xa084, 0x0002, 0x0040,
+	0x2301, 0x704c, 0xa206, 0x00c0, 0x2301, 0x6b04, 0x2160, 0x2304,
+	0x6002, 0xa005, 0x00c0, 0x22fd, 0x6902, 0x2260, 0x6102, 0x0078,
+	0x2317, 0x2d00, 0x2060, 0x1078, 0x2acc, 0x6e08, 0x2160, 0x6202,
+	0x6906, 0x0078, 0x2317, 0x6800, 0x6902, 0xa065, 0x0040, 0x2313,
+	0x6102, 0x0078, 0x2314, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160,
+	0xd9fc, 0x0040, 0x231e, 0xa6b4, 0xfffc, 0x6e0a, 0x6810, 0x7d08,
+	0x8528, 0x7d0a, 0x8000, 0x6812, 0x2091, 0x8001, 0xd6b4, 0x0040,
+	0x232e, 0xa6b6, 0x0040, 0x6e0a, 0x1078, 0x1e6c, 0x0e7f, 0x007c,
+	0x6008, 0xa705, 0x600a, 0x2091, 0x8000, 0x1078, 0x201d, 0x2091,
+	0x8001, 0x78b8, 0xa065, 0x0040, 0x2343, 0x609c, 0x78ba, 0x609f,
+	0x0000, 0x0078, 0x2330, 0x78b6, 0x78ba, 0x007c, 0x7970, 0x7874,
+	0x2818, 0xd384, 0x0040, 0x2350, 0x8000, 0xa112, 0x0048, 0x2355,
+	0x8000, 0xa112, 0x00c8, 0x2365, 0xc384, 0x7a7c, 0x721a, 0x7a78,
+	0x721e, 0xdac4, 0x0040, 0x2360, 0x7a84, 0x7222, 0x7a80, 0x7226,
+	0xa006, 0xd384, 0x0040, 0x2365, 0x8000, 0x7876, 0x70d2, 0x781c,
+	0xa005, 0x0040, 0x2373, 0x8001, 0x781e, 0x00c0, 0x2373, 0x0068,
+	0x2373, 0x2091, 0x4080, 0x007c, 0x2039, 0x238c, 0x0078, 0x237a,
+	0x2039, 0x2392, 0x2704, 0xa005, 0x0040, 0x238b, 0xac00, 0x2068,
+	0x6908, 0x6810, 0x6912, 0x680a, 0x690c, 0x6814, 0x6916, 0x680e,
+	0x8738, 0x0078, 0x237a, 0x007c, 0x0003, 0x0009, 0x000f, 0x0015,
+	0x001b, 0x0000, 0x0015, 0x001b, 0x0000, 0x2041, 0x0000, 0x780c,
+	0x0079, 0x239a, 0x256c, 0x253f, 0x239e, 0x2417, 0x2039, 0x9674,
+	0x2734, 0x7d10, 0x0078, 0x23be, 0x6084, 0xa086, 0x0103, 0x00c0,
+	0x2400, 0x6114, 0x6018, 0xa105, 0x0040, 0x23b3, 0x86ff, 0x00c0,
+	0x23cf, 0x0078, 0x2400, 0x8603, 0xa080, 0x9655, 0x620c, 0x2202,
+	0x8000, 0x6210, 0x2202, 0x1078, 0x203f, 0x8630, 0xa68e, 0x000f,
+	0x0040, 0x248b, 0x786c, 0xa065, 0x00c0, 0x23a4, 0x7808, 0xa602,
+	0x00c8, 0x23cf, 0xd5ac, 0x00c0, 0x23cf, 0x263a, 0x007c, 0xa682,
+	0x0003, 0x00c8, 0x248b, 0x2091, 0x8000, 0x2069, 0x0000, 0x6818,
+	0xd084, 0x00c0, 0x23fb, 0x2011, 0x9655, 0x2204, 0x70c6, 0x8210,
+	0x2204, 0x70ca, 0xd684, 0x00c0, 0x23eb, 0x8210, 0x2204, 0x70da,
+	0x8210, 0x2204, 0x70de, 0xa685, 0x8020, 0x70c2, 0x681b, 0x0001,
+	0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091, 0x8001,
+	0x203b, 0x0000, 0x007c, 0x7810, 0xc0ad, 0x7812, 0x0078, 0x248b,
+	0x263a, 0x1078, 0x2576, 0x00c0, 0x2599, 0x786c, 0xa065, 0x00c0,
+	0x23a4, 0x2091, 0x8000, 0x7810, 0xa084, 0xffcf, 0x86ff, 0x0040,
+	0x2412, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0078, 0x2599, 0x2039,
+	0x9674, 0x2734, 0x7d10, 0x0078, 0x2433, 0x6084, 0xa086, 0x0103,
+	0x00c0, 0x2474, 0x6114, 0x6018, 0xa105, 0x0040, 0x242c, 0x86ff,
+	0x00c0, 0x2444, 0x0078, 0x2474, 0xa680, 0x9655, 0x620c, 0x2202,
+	0x1078, 0x203f, 0x8630, 0xa68e, 0x001e, 0x0040, 0x248b, 0x786c,
+	0xa065, 0x00c0, 0x241d, 0x7808, 0xa602, 0x00c8, 0x2444, 0xd5ac,
+	0x00c0, 0x2444, 0x263a, 0x007c, 0xa682, 0x0006, 0x00c8, 0x248b,
+	0x2091, 0x8000, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x246f,
+	0x2011, 0x9655, 0x2009, 0x964e, 0x26a8, 0x211c, 0x2204, 0x201a,
+	0x8108, 0x8210, 0x00f0, 0x2455, 0xa685, 0x8030, 0x70c2, 0x681b,
+	0x0001, 0x2091, 0x4080, 0x7810, 0xa084, 0xffcf, 0x7812, 0x2091,
+	0x8001, 0xa006, 0x2009, 0x9675, 0x200a, 0x203a, 0x007c, 0x7810,
+	0xc0ad, 0x7812, 0x0078, 0x248b, 0x263a, 0x1078, 0x2576, 0x00c0,
+	0x2599, 0x786c, 0xa065, 0x00c0, 0x241d, 0x2091, 0x8000, 0x7810,
+	0xa084, 0xffcf, 0x86ff, 0x0040, 0x2486, 0xc0ad, 0x7812, 0x2091,
+	0x8001, 0x0078, 0x2599, 0x2091, 0x8000, 0x7007, 0x0004, 0x7994,
+	0x70d4, 0xa102, 0x0048, 0x249c, 0x0040, 0x24a6, 0x7b90, 0xa302,
+	0x00c0, 0x24a6, 0x0078, 0x249f, 0x8002, 0x00c0, 0x24a6, 0x263a,
+	0x7810, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x007c, 0xa184, 0xff00,
+	0x0040, 0x24b3, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007,
+	0xa100, 0x0078, 0x24b6, 0x8107, 0x8004, 0x8004, 0x7a9c, 0xa210,
+	0x721a, 0x7a98, 0xa006, 0xa211, 0x721e, 0xd4c4, 0x0040, 0x24c6,
+	0x7aa4, 0xa211, 0x7222, 0x7aa0, 0xa211, 0x7226, 0x20a1, 0x0030,
+	0x7003, 0x0000, 0x2009, 0x9654, 0x260a, 0x8109, 0x2198, 0x2104,
+	0xd084, 0x0040, 0x24d4, 0x8633, 0xa6b0, 0x0002, 0x26a8, 0x53a6,
+	0x8603, 0x7012, 0x7007, 0x0001, 0x7990, 0x7894, 0x8000, 0xa10a,
+	0x00c8, 0x24e3, 0xa006, 0x2028, 0x7974, 0xa184, 0xff00, 0x0040,
+	0x24f2, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007, 0xa100,
+	0x0078, 0x24f5, 0x8107, 0x8004, 0x8004, 0x797c, 0xa108, 0x7a78,
+	0xa006, 0xa211, 0xd4c4, 0x0040, 0x2501, 0x7b84, 0xa319, 0x7c80,
+	0xa421, 0x7008, 0xd0fc, 0x0040, 0x2501, 0xa084, 0x01e0, 0x0040,
+	0x2526, 0x7d10, 0x2031, 0x9654, 0x2634, 0x78a8, 0x8000, 0x78aa,
+	0xd08c, 0x00c0, 0x251b, 0x7007, 0x0006, 0x7004, 0xd094, 0x00c0,
+	0x2515, 0x0078, 0x248d, 0x2069, 0x4e47, 0x206b, 0x0003, 0x78ac,
+	0xa085, 0x0300, 0x78ae, 0xa006, 0x0078, 0x252f, 0x2030, 0x75d6,
+	0x2091, 0x4080, 0x7d96, 0x7d10, 0xa5ac, 0xffcf, 0x7d12, 0x2091,
+	0x8001, 0x78aa, 0x7007, 0x0006, 0x263a, 0x7003, 0x0001, 0x711a,
+	0x721e, 0xd5c4, 0x0040, 0x253e, 0x7322, 0x7426, 0x007c, 0x6084,
+	0xa086, 0x0103, 0x00c0, 0x2562, 0x6114, 0x6018, 0xa105, 0x00c0,
+	0x2562, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0, 0x2562, 0x600c,
+	0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001, 0x2091,
+	0x4080, 0x1078, 0x203f, 0x0068, 0x2561, 0x786c, 0xa065, 0x00c0,
+	0x253f, 0x007c, 0x1078, 0x2576, 0x00c0, 0x2599, 0x786c, 0xa065,
+	0x00c0, 0x253f, 0x0078, 0x2599, 0x1078, 0x2576, 0x00c0, 0x2599,
+	0x786c, 0xa065, 0x00c0, 0x256c, 0x0078, 0x2599, 0x6084, 0xa086,
+	0x0103, 0x00c0, 0x258a, 0x6018, 0xc0fc, 0x601a, 0xa086, 0x0004,
+	0x00c0, 0x258a, 0x7804, 0xd0a4, 0x0040, 0x258a, 0x1078, 0x203f,
+	0xa006, 0x007c, 0x1078, 0x259f, 0x00c0, 0x2591, 0xa085, 0x0001,
+	0x007c, 0x1078, 0x25ae, 0x00c0, 0x2597, 0x2041, 0x0001, 0x7d10,
+	0x007c, 0x88ff, 0x0040, 0x259e, 0x2091, 0x4080, 0x007c, 0x7b90,
+	0x7994, 0x70d4, 0xa102, 0x00c0, 0x25a8, 0xa385, 0x0000, 0x007c,
+	0x0048, 0x25ac, 0xa302, 0x007c, 0x8002, 0x007c, 0x7810, 0xd0ec,
+	0x0040, 0x25c6, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004,
+	0xa005, 0x00c0, 0x25c3, 0x7008, 0x0e7f, 0xa086, 0x0008, 0x0040,
+	0x25c6, 0x0078, 0x2617, 0x0e7f, 0x0078, 0x2617, 0xa184, 0xff00,
+	0x0040, 0x25d3, 0x810f, 0x810c, 0x810c, 0x8004, 0x8004, 0x8007,
+	0xa100, 0x0078, 0x25d6, 0x8107, 0x8004, 0x8004, 0x7a9c, 0x7b98,
+	0x7ca4, 0x7da0, 0xa210, 0xa006, 0xa319, 0xa421, 0xa529, 0x2009,
+	0x0018, 0x6028, 0xa005, 0x0040, 0x25e7, 0x2009, 0x0040, 0x1078,
+	0x1d74, 0x0040, 0x2609, 0x78a8, 0x8000, 0x78aa, 0xd08c, 0x00c0,
+	0x2617, 0x6014, 0xd0fc, 0x00c0, 0x25f9, 0x2069, 0x4e40, 0x0078,
+	0x25fb, 0x2069, 0x4e80, 0x2091, 0x8000, 0x681f, 0x0003, 0x78ab,
+	0x0000, 0x78ac, 0xa085, 0x0300, 0x78ae, 0x2091, 0x8001, 0x0078,
+	0x2617, 0x78ab, 0x0000, 0x1078, 0x203f, 0x7990, 0x7894, 0x8000,
+	0xa10a, 0x00c8, 0x2614, 0xa006, 0x7896, 0x70d6, 0xa006, 0x2071,
+	0x0010, 0x2091, 0x8001, 0x007c, 0xd7fc, 0x00c0, 0x2623, 0x2009,
+	0x4e59, 0x0078, 0x2625, 0x2009, 0x4e99, 0x2091, 0x8000, 0x200a,
+	0x0f7e, 0xd7fc, 0x00c0, 0x263c, 0x2009, 0x4e40, 0x2001, 0x4e04,
+	0x2004, 0xd0ec, 0x0040, 0x2638, 0x2079, 0x0100, 0x0078, 0x2640,
+	0x2079, 0x0200, 0x0078, 0x2640, 0x2009, 0x4e80, 0x2079, 0x0100,
+	0x2104, 0xa086, 0x0000, 0x00c0, 0x2659, 0xd7fc, 0x00c0, 0x264c,
+	0x2009, 0x4e45, 0x0078, 0x264e, 0x2009, 0x4e85, 0x2104, 0xa005,
+	0x00c0, 0x2659, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x2659, 0x781b,
+	0x0045, 0x0f7f, 0x007c, 0x2009, 0x0002, 0x2069, 0x4e00, 0x6810,
+	0xd0ec, 0x00c0, 0x26c8, 0x2071, 0x4e80, 0x2079, 0x0100, 0x2021,
+	0x50bf, 0x784b, 0x000f, 0x2019, 0x4457, 0xd184, 0x0040, 0x267c,
+	0x6810, 0xd0ec, 0x0040, 0x2678, 0x20a1, 0x012b, 0x0078, 0x267e,
+	0x20a1, 0x022b, 0x0078, 0x267e, 0x20a1, 0x012b, 0x2304, 0xa005,
+	0x0040, 0x268b, 0x789a, 0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6,
+	0x3318, 0x0078, 0x267e, 0x789b, 0x0020, 0x20a9, 0x0010, 0x6814,
+	0xd0e4, 0x0040, 0x269b, 0x78af, 0x0000, 0x78af, 0x9020, 0x00f0,
+	0x2693, 0x0078, 0x26a1, 0x78af, 0x0000, 0x78af, 0x8020, 0x00f0,
+	0x269b, 0x7003, 0x0000, 0x017e, 0xd18c, 0x2009, 0x0000, 0x0040,
+	0x26aa, 0xc1bd, 0x1078, 0x289b, 0x017f, 0x7020, 0xa084, 0x000f,
+	0x007e, 0x6814, 0xd0e4, 0x007f, 0x00c0, 0x26ba, 0xa085, 0x6340,
+	0x0078, 0x26bc, 0xa085, 0x62c0, 0x7806, 0x780f, 0x9200, 0x7843,
+	0x00d8, 0x7853, 0x0080, 0x780b, 0x0008, 0x7456, 0x7053, 0x0000,
+	0x8109, 0x0040, 0x26db, 0x2071, 0x4e40, 0x6810, 0xd0ec, 0x0040,
+	0x26d5, 0x2079, 0x0100, 0x0078, 0x26d7, 0x2079, 0x0200, 0x2021,
+	0x4ebf, 0x0078, 0x2669, 0x007c, 0x017e, 0xd1bc, 0x00c0, 0x26f0,
+	0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x26ec,
+	0x2011, 0x0101, 0x0078, 0x26f2, 0x2011, 0x0201, 0x0078, 0x26f2,
+	0x2011, 0x0101, 0xa18c, 0x000f, 0x2204, 0xa084, 0xfff0, 0xa105,
+	0x2012, 0x017f, 0x1078, 0x289b, 0x007c, 0xd3fc, 0x00c0, 0x2710,
+	0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x270c,
+	0x2011, 0x0101, 0x0078, 0x2712, 0x2011, 0x0201, 0x0078, 0x2712,
+	0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x00f0, 0x2714, 0xa18c,
+	0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2019,
+	0x0002, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x0040, 0x272c, 0x8319,
+	0x2009, 0x0101, 0x0078, 0x272e, 0x2009, 0x0101, 0x20a9, 0x0005,
+	0x8213, 0x00f0, 0x2730, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f,
+	0xa205, 0x200a, 0x8319, 0x0040, 0x2741, 0x2009, 0x0201, 0x0078,
+	0x272e, 0x007c, 0xd3fc, 0x00c0, 0x2755, 0x007e, 0x2001, 0x4e04,
+	0x2004, 0xd0ec, 0x007f, 0x0040, 0x2751, 0x2011, 0x0101, 0x0078,
+	0x2757, 0x2011, 0x0201, 0x0078, 0x2757, 0x2011, 0x0101, 0x20a9,
+	0x000c, 0x810b, 0x00f0, 0x2759, 0xa18c, 0xf000, 0x2204, 0xa084,
+	0x0fff, 0xa105, 0x2012, 0x007c, 0xd3fc, 0x00c0, 0x2777, 0x007e,
+	0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x2773, 0x2011,
+	0x0102, 0x0078, 0x2779, 0x2011, 0x0202, 0x0078, 0x2779, 0x2011,
+	0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012, 0x007c, 0x0c7e,
+	0xd1bc, 0x00c0, 0x2793, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec,
+	0x007f, 0x0040, 0x278f, 0x2061, 0x0100, 0x0078, 0x2795, 0x2061,
+	0x0200, 0x0078, 0x2795, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003,
+	0xa080, 0x0020, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x0c7e,
+	0xd1bc, 0x00c0, 0x27b3, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec,
+	0x007f, 0x0040, 0x27af, 0x2061, 0x0100, 0x0078, 0x27b5, 0x2061,
+	0x0200, 0x0078, 0x27b5, 0x2061, 0x0100, 0xc1bc, 0x8103, 0x8003,
+	0xa080, 0x0022, 0x609a, 0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f,
+	0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x27d5, 0x007e, 0x2001, 0x4e04,
+	0x2004, 0xd0ec, 0x007f, 0x0040, 0x27d1, 0x2061, 0x0100, 0x0078,
+	0x27d7, 0x2061, 0x0200, 0x0078, 0x27d7, 0x2061, 0x0100, 0xc1bc,
+	0x8103, 0x8003, 0xa080, 0x0022, 0x609a, 0x60a4, 0xa085, 0x0020,
+	0x60ae, 0x0c7f, 0x007c, 0x0c7e, 0xd1bc, 0x00c0, 0x27f7, 0x007e,
+	0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x27f3, 0x2061,
+	0x0100, 0x0078, 0x27f9, 0x2061, 0x0200, 0x0078, 0x27f9, 0x2061,
+	0x0100, 0xc1bc, 0x8103, 0x8003, 0xa080, 0x0020, 0x609a, 0x60a4,
+	0xa28c, 0x0020, 0x0040, 0x2807, 0xc2ac, 0xa39d, 0x4000, 0xc3fc,
+	0xd3b4, 0x00c0, 0x280c, 0xc3fd, 0x62ae, 0x2010, 0x60a4, 0x63ae,
+	0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818,
+	0xa005, 0x0040, 0x2879, 0xd1fc, 0x0040, 0x2822, 0x2061, 0x95d0,
+	0x0078, 0x2824, 0x2061, 0x94c0, 0x1078, 0x2881, 0x0040, 0x285b,
+	0x20a9, 0x0101, 0xd1fc, 0x0040, 0x2831, 0x2061, 0x94d0, 0x0078,
+	0x2833, 0x2061, 0x93c0, 0x0c7e, 0x1078, 0x2881, 0x0040, 0x283e,
+	0x0c7f, 0x8c60, 0x00f0, 0x2833, 0x0078, 0x2879, 0x007f, 0xd1fc,
+	0x0040, 0x2848, 0xa082, 0x94d0, 0x2071, 0x4e80, 0x0078, 0x284c,
+	0xa082, 0x93c0, 0x2071, 0x4e40, 0x707a, 0x7176, 0x2138, 0x2001,
+	0x0004, 0x7066, 0x7083, 0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x1078,
+	0x261c, 0x0078, 0x2875, 0xd1fc, 0x00c0, 0x2862, 0x2071, 0x4e40,
+	0x0078, 0x2864, 0x2071, 0x4e80, 0x6020, 0xc0dd, 0x6022, 0x7176,
+	0x2138, 0x2c00, 0x707e, 0x2001, 0x0006, 0x7066, 0x7083, 0x000f,
+	0x71d4, 0xc1dc, 0x71d6, 0x1078, 0x261c, 0x2001, 0x0000, 0x0078,
+	0x287b, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f,
+	0x007c, 0x2c04, 0xa005, 0x0040, 0x2898, 0x2060, 0x6010, 0xa306,
+	0x00c0, 0x2895, 0x600c, 0xa206, 0x00c0, 0x2895, 0x6014, 0xa106,
+	0x00c0, 0x2895, 0xa006, 0x0078, 0x289a, 0x6000, 0x0078, 0x2882,
+	0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0xd1bc, 0x00c0,
+	0x28b3, 0x2079, 0x4e40, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec,
+	0x007f, 0x0040, 0x28af, 0x2071, 0x0100, 0x0078, 0x28b7, 0x2071,
+	0x0200, 0x0078, 0x28b7, 0x2079, 0x4e80, 0x2071, 0x0100, 0x7920,
+	0xa18c, 0x000f, 0x70ec, 0xd0c4, 0x00c0, 0x28c1, 0x017f, 0x0078,
+	0x28dc, 0x810b, 0x810b, 0x810b, 0x810b, 0x007f, 0xd0bc, 0x00c0,
+	0x28d9, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040,
+	0x28d5, 0xa18d, 0x0f00, 0x0078, 0x28db, 0xa18d, 0x0f00, 0x0078,
+	0x28db, 0xa18d, 0x0800, 0x2104, 0x0e7f, 0x0f7f, 0x007c, 0x0e7e,
+	0x2001, 0x4e01, 0x2004, 0xd0ac, 0x00c0, 0x295c, 0x68e4, 0xd0ac,
+	0x0040, 0x295c, 0xa084, 0x0006, 0x00c0, 0x295c, 0x6014, 0xd0fc,
+	0x00c0, 0x28f6, 0x2071, 0x52c0, 0x0078, 0x28f8, 0x2071, 0x5340,
+	0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xae70, 0x7004,
+	0xa084, 0x000a, 0x00c0, 0x295c, 0x7108, 0xa194, 0xff00, 0x0040,
+	0x295c, 0xa18c, 0x00ff, 0x2001, 0x000a, 0xa106, 0x0040, 0x292b,
+	0x2001, 0x000c, 0xa106, 0x0040, 0x292f, 0x2001, 0x0012, 0xa106,
+	0x0040, 0x2933, 0x2001, 0x0014, 0xa106, 0x0040, 0x2937, 0x2001,
+	0x0019, 0xa106, 0x0040, 0x293b, 0x2001, 0x0032, 0xa106, 0x0040,
+	0x293f, 0x0078, 0x2943, 0x2009, 0x000c, 0x0078, 0x2945, 0x2009,
+	0x0012, 0x0078, 0x2945, 0x2009, 0x0014, 0x0078, 0x2945, 0x2009,
+	0x0019, 0x0078, 0x2945, 0x2009, 0x0020, 0x0078, 0x2945, 0x2009,
+	0x003f, 0x0078, 0x2945, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a,
+	0x2071, 0x4e00, 0x7004, 0xd0bc, 0x0040, 0x295c, 0x6014, 0xd0fc,
+	0x00c0, 0x2957, 0x70ea, 0x2071, 0x4e40, 0x0078, 0x295a, 0x70ee,
+	0x2071, 0x4e80, 0x701f, 0x000d, 0x0e7f, 0x007c, 0x2001, 0x4e05,
+	0x2004, 0xd0e4, 0x00c0, 0x296a, 0x7804, 0xa084, 0xff1f, 0xa085,
+	0x6340, 0x7806, 0x007c, 0x0068, 0x296b, 0x2091, 0x8000, 0x2071,
+	0x0000, 0x007e, 0x7018, 0xd084, 0x00c0, 0x2972, 0x007f, 0x2071,
+	0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x080f,
+	0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x0078, 0x2988, 0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0x78a0, 0x708e,
+	0x7592, 0x7496, 0x769a, 0x779e, 0xa594, 0x003f, 0xd4f4, 0x0040,
+	0x299f, 0xa784, 0x007d, 0x00c0, 0x43cd, 0x1078, 0x296b, 0xa49c,
+	0x000f, 0xa382, 0x0004, 0x0050, 0x29aa, 0xa3a6, 0x0007, 0x00c0,
+	0x296b, 0x2418, 0x8507, 0xa084, 0x000f, 0x0079, 0x29af, 0x3028,
+	0x3119, 0x3144, 0x33b6, 0x379f, 0x3819, 0x38ce, 0x395f, 0x3a4d,
+	0x3b3c, 0x29c2, 0x29bf, 0x2df9, 0x2f1c, 0x3770, 0x29bf, 0x1078,
+	0x296b, 0x007c, 0xa006, 0x0078, 0x29cc, 0x7808, 0xc08d, 0x780a,
+	0xa006, 0x7002, 0x704e, 0x7046, 0x70d2, 0x7060, 0xa005, 0x00c0,
+	0x2b32, 0x7064, 0xa084, 0x0007, 0x0079, 0x29d6, 0x29de, 0x2a51,
+	0x2a5a, 0x2a65, 0x2a70, 0x2b18, 0x2a7b, 0x2a51, 0x7830, 0xd0bc,
+	0x00c0, 0x29c1, 0x71d4, 0xd1bc, 0x00c0, 0x29c1, 0xd1b4, 0x00c0,
+	0x2a2e, 0x70a4, 0xa086, 0x0001, 0x0040, 0x29c1, 0x70b4, 0xa06d,
+	0x6800, 0xa065, 0xa055, 0x789b, 0x0010, 0x6b0c, 0x7baa, 0x6808,
+	0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d, 0xa886, 0x0001, 0x0040,
+	0x2a04, 0x69bc, 0x7daa, 0x79aa, 0x68c0, 0xa04d, 0x6e1c, 0x2001,
+	0x0010, 0x0078, 0x2c8c, 0x7060, 0xa005, 0x00c0, 0x29c1, 0x0c7e,
+	0x0d7e, 0x70b4, 0xa06d, 0x6800, 0xa065, 0xa055, 0x789b, 0x0010,
+	0x6b0c, 0x7baa, 0x6808, 0xa045, 0x6d10, 0x6804, 0xa06d, 0xa05d,
+	0xa886, 0x0001, 0x0040, 0x2a27, 0x69bc, 0x7daa, 0x79aa, 0x68c0,
+	0xa04d, 0x6e1c, 0x2001, 0x0020, 0x0078, 0x2c8c, 0x1078, 0x4360,
+	0x00c0, 0x29c1, 0x781b, 0x005b, 0x70bc, 0xa06d, 0x68b4, 0x785a,
+	0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d,
+	0x780a, 0x68bc, 0x7042, 0xc1b4, 0x71d6, 0x70b8, 0xa065, 0x68c0,
+	0x705a, 0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046,
+	0x007c, 0x1078, 0x4360, 0x00c0, 0x2a59, 0x781b, 0x0047, 0x7003,
+	0x0004, 0x007c, 0x1078, 0x4360, 0x00c0, 0x2a64, 0x2011, 0x000c,
+	0x1078, 0x2a8b, 0x7003, 0x0004, 0x007c, 0x1078, 0x4360, 0x00c0,
+	0x2a6f, 0x2011, 0x0006, 0x1078, 0x2a8b, 0x7003, 0x0004, 0x007c,
+	0x1078, 0x4360, 0x00c0, 0x2a7a, 0x2011, 0x000d, 0x1078, 0x2a8b,
+	0x7003, 0x0004, 0x007c, 0x1078, 0x4360, 0x00c0, 0x2a8a, 0x2011,
+	0x0006, 0x1078, 0x2a8b, 0x707c, 0x707f, 0x0000, 0x2068, 0x704e,
+	0x7003, 0x0001, 0x007c, 0x7174, 0xc1fc, 0x8107, 0x7882, 0x789b,
+	0x0010, 0xa286, 0x000c, 0x00c0, 0x2a9a, 0x7aaa, 0x2001, 0x0001,
+	0x0078, 0x2aaf, 0xa18c, 0x001f, 0xa18d, 0x00c0, 0x79aa, 0xa286,
+	0x000d, 0x0040, 0x2aa8, 0x7aaa, 0x2001, 0x0002, 0x0078, 0x2aaf,
+	0x78ab, 0x0020, 0x7178, 0x79aa, 0x7aaa, 0x2001, 0x0004, 0x789b,
+	0x0060, 0x78aa, 0x785b, 0x0004, 0x781b, 0x0116, 0x1078, 0x4383,
+	0x7083, 0x000f, 0x70d4, 0xd0b4, 0x0040, 0x2acb, 0xc0b4, 0x70d6,
+	0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018,
+	0x8001, 0x601a, 0x0c7f, 0x007c, 0x7014, 0xa005, 0x00c0, 0x2ada,
+	0x70d4, 0xd0b4, 0x0040, 0x2adb, 0x70b8, 0xac06, 0x00c0, 0x2adb,
+	0x1078, 0x2aba, 0x007c, 0x017e, 0x71a4, 0xa186, 0x0001, 0x0040,
+	0x2b0d, 0x0d7e, 0x027e, 0x2100, 0x2011, 0x0001, 0xa212, 0x70b4,
+	0x2068, 0x6800, 0xac06, 0x0040, 0x2af4, 0x8211, 0x0040, 0x2b0b,
+	0x1078, 0x2b0f, 0x0078, 0x2ae9, 0x0c7e, 0x2100, 0x2011, 0x0001,
+	0xa212, 0x70b4, 0x2068, 0x6800, 0x2060, 0x6008, 0xa084, 0xfbef,
+	0x600a, 0x8211, 0x0040, 0x2b08, 0x1078, 0x2b0f, 0x0078, 0x2afb,
+	0x70a7, 0x0001, 0x0c7f, 0x027f, 0x0d7f, 0x017f, 0x007c, 0xade8,
+	0x0005, 0x70ac, 0xad06, 0x00c0, 0x2b17, 0x70a8, 0x2068, 0x007c,
+	0x1078, 0x4360, 0x00c0, 0x29c1, 0x707c, 0x2068, 0x7774, 0x1078,
+	0x41fe, 0x2c50, 0x1078, 0x4442, 0x789b, 0x0010, 0x6814, 0xa084,
+	0x001f, 0xc0bd, 0x78aa, 0x6e1c, 0x2041, 0x0001, 0x2001, 0x0004,
+	0x0078, 0x2c92, 0x1078, 0x4360, 0x00c0, 0x29c1, 0x789b, 0x0010,
+	0x7060, 0x2068, 0x6f14, 0x70d4, 0xd0b4, 0x0040, 0x2b4c, 0xc0b4,
+	0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a,
+	0x6018, 0x8001, 0x601a, 0x0c7f, 0x1078, 0x41fe, 0x2c50, 0x1078,
+	0x4442, 0x6824, 0xa005, 0x0040, 0x2b5d, 0xa082, 0x0006, 0x0048,
+	0x2b5b, 0x0078, 0x2b5d, 0x6827, 0x0005, 0x6814, 0xa084, 0x001f,
+	0xc0bd, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001, 0x0003,
+	0x0078, 0x2c92, 0xc28d, 0x72d6, 0x72c0, 0xa200, 0xa015, 0x7154,
+	0x8108, 0xa12a, 0x0048, 0x2b75, 0x71c0, 0x2164, 0x6504, 0x85ff,
+	0x00c0, 0x2b8c, 0x7156, 0x8421, 0x00c0, 0x2b70, 0x70d4, 0xd08c,
+	0x0040, 0x2b88, 0x70d0, 0xa005, 0x00c0, 0x2b88, 0x70d3, 0x000a,
+	0x007c, 0x2200, 0x0078, 0x2b7a, 0x70d4, 0xc08c, 0x70d6, 0x70d3,
+	0x0000, 0x6034, 0xa005, 0x00c0, 0x2b89, 0x6708, 0xa784, 0x073f,
+	0x0040, 0x2bbb, 0xd7d4, 0x00c0, 0x2b89, 0xa784, 0x0021, 0x00c0,
+	0x2b89, 0xa784, 0x0002, 0x0040, 0x2bac, 0xa784, 0x0004, 0x0040,
+	0x2b89, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0218, 0x00c0, 0x2b89,
+	0xa784, 0x0100, 0x0040, 0x2bbb, 0x6018, 0xa005, 0x00c0, 0x2b89,
+	0xa7bc, 0xfeff, 0x670a, 0x2568, 0x6823, 0x0000, 0x6e1c, 0xa684,
+	0x000e, 0x6318, 0x0040, 0x2bcc, 0x601c, 0xa302, 0x0048, 0x2bcf,
+	0x0040, 0x2bcf, 0x0078, 0x2b89, 0x83ff, 0x00c0, 0x2b89, 0x2d58,
+	0x2c50, 0x7156, 0xd7bc, 0x00c0, 0x2bd8, 0x7028, 0x6022, 0x603a,
+	0xc7bc, 0x670a, 0x68c0, 0xa065, 0xa04d, 0x6100, 0x2a60, 0x2041,
+	0x0001, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0xd1fc, 0x0040,
+	0x2bec, 0xd684, 0x0040, 0x2bee, 0xa39c, 0xffbf, 0xd6a4, 0x0040,
+	0x2bf3, 0xa39d, 0x0020, 0xa684, 0x000e, 0x00c0, 0x2c3e, 0xc7a5,
+	0x670a, 0x2c00, 0x68c6, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c12,
+	0x70d4, 0xd0b4, 0x00c0, 0x2c12, 0x7000, 0xa082, 0x0002, 0x00c8,
+	0x2c12, 0x7830, 0xd0bc, 0x00c0, 0x2c12, 0x789b, 0x0010, 0x7baa,
+	0x0078, 0x2c8a, 0x8739, 0x77a6, 0x2750, 0x77b0, 0xa7b0, 0x0005,
+	0x70ac, 0xa606, 0x00c0, 0x2c1d, 0x76a8, 0x76b2, 0x2c3a, 0x8738,
+	0x2d3a, 0x8738, 0x283a, 0x8738, 0x233a, 0x8738, 0x253a, 0x7830,
+	0xd0bc, 0x0040, 0x2c35, 0x2091, 0x8000, 0x2091, 0x303d, 0x70d4,
+	0xa084, 0x303d, 0x2091, 0x8000, 0x2090, 0xaad5, 0x0000, 0x0040,
+	0x2c3d, 0x8421, 0x2200, 0x00c0, 0x2b6f, 0x007c, 0xd1dc, 0x0040,
+	0x3e00, 0x2029, 0x0020, 0xd69c, 0x00c0, 0x2c4b, 0x8528, 0xd68c,
+	0x00c0, 0x2c4b, 0x8528, 0x8840, 0x6f14, 0x610c, 0x8108, 0xa18c,
+	0x00ff, 0x70cc, 0xa160, 0x2c64, 0x8cff, 0x0040, 0x2c6a, 0x6014,
+	0xa706, 0x00c0, 0x2c53, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2c4e,
+	0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x2200, 0x8421, 0x00c0,
+	0x2b6f, 0x007c, 0x2a60, 0x610e, 0x69be, 0x2c00, 0x68c6, 0x8840,
+	0x6008, 0xc0d5, 0x600a, 0x77a4, 0xa786, 0x0001, 0x00c0, 0x2c12,
+	0x70d4, 0xd0b4, 0x00c0, 0x2c12, 0x7000, 0xa082, 0x0002, 0x00c8,
+	0x2c12, 0x7830, 0xd0bc, 0x00c0, 0x2c12, 0x789b, 0x0010, 0x7baa,
+	0x7daa, 0x79aa, 0x2001, 0x0002, 0x007e, 0x6018, 0x8000, 0x601a,
+	0x0078, 0x2c93, 0x007e, 0x2960, 0x6104, 0x2a60, 0xa184, 0x0018,
+	0x0040, 0x2caf, 0xa184, 0x0010, 0x0040, 0x2ca2, 0x1078, 0x4011,
+	0x00c0, 0x2cd4, 0xa184, 0x0008, 0x0040, 0x2caf, 0x69a0, 0xa184,
+	0x0600, 0x00c0, 0x2caf, 0x1078, 0x3ef5, 0x0078, 0x2cd4, 0x69a0,
+	0xa184, 0x1e00, 0x0040, 0x2cdf, 0xa184, 0x0800, 0x0040, 0x2cc8,
+	0x0c7e, 0x2960, 0x6000, 0xa085, 0x2000, 0x6002, 0x6104, 0xa18d,
+	0x0010, 0x6106, 0x0c7f, 0x1078, 0x4011, 0x00c0, 0x2cd4, 0x69a0,
+	0xa184, 0x0200, 0x0040, 0x2cd0, 0x1078, 0x3f54, 0x0078, 0x2cd4,
+	0xa184, 0x0400, 0x00c0, 0x2cab, 0x69a0, 0xa184, 0x1000, 0x0040,
+	0x2cdf, 0x6914, 0xa18c, 0xff00, 0x810f, 0x1078, 0x279f, 0x027f,
+	0xa68c, 0x00e0, 0xa684, 0x0060, 0x0040, 0x2cec, 0xa086, 0x0060,
+	0x00c0, 0x2cec, 0xa18d, 0x4000, 0xa18d, 0x0104, 0x69b6, 0x789b,
+	0x0060, 0x2800, 0x78aa, 0x6818, 0xc0fd, 0x681a, 0xd6bc, 0x0040,
+	0x2d07, 0xc0fc, 0x7087, 0x0000, 0xa08a, 0x000d, 0x0050, 0x2d05,
+	0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a, 0x78aa,
+	0x3518, 0x3340, 0x3428, 0x8000, 0x80ac, 0xaf80, 0x002b, 0x20a0,
+	0x789b, 0x0000, 0xad80, 0x000b, 0x2098, 0x53a6, 0x23a8, 0x2898,
+	0x25a0, 0xa286, 0x0020, 0x00c0, 0x2d3f, 0x70d4, 0xc0b5, 0x70d6,
+	0x2c00, 0x70ba, 0x2d00, 0x70be, 0x6814, 0xc0fc, 0x8007, 0x7882,
+	0xa286, 0x0002, 0x0040, 0x2d75, 0x70a4, 0x8000, 0x70a6, 0x74b4,
+	0xa498, 0x0005, 0x70ac, 0xa306, 0x00c0, 0x2d37, 0x73a8, 0x73b6,
+	0xa286, 0x0010, 0x0040, 0x29c1, 0x0d7f, 0x0c7f, 0x007c, 0x7000,
+	0xa005, 0x00c0, 0x2d1d, 0xa286, 0x0002, 0x00c0, 0x2d8f, 0x1078,
+	0x4360, 0x00c0, 0x2d1d, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x2091,
+	0x8000, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de,
+	0x6898, 0x78d2, 0x78da, 0x2091, 0x8001, 0x7808, 0xc08d, 0x780a,
+	0x127e, 0x0d7e, 0x0c7e, 0x70d4, 0xa084, 0x2700, 0x2090, 0x0c7f,
+	0x0d7f, 0x127f, 0x2900, 0x705a, 0x68bc, 0x7042, 0x7003, 0x0002,
+	0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x7830, 0xd0bc, 0x0040,
+	0x2d81, 0x2091, 0x303d, 0x70d4, 0xa084, 0x303d, 0x2091, 0x8000,
+	0x2090, 0x70a4, 0xa005, 0x00c0, 0x2d86, 0x007c, 0x8421, 0x0040,
+	0x2d85, 0x7250, 0x70c0, 0xa200, 0xa015, 0x0078, 0x2b6f, 0xa286,
+	0x0010, 0x00c0, 0x2dc0, 0x1078, 0x4360, 0x00c0, 0x2d1d, 0x6814,
+	0xc0fc, 0x8007, 0x7882, 0x781b, 0x005b, 0x68b4, 0x785a, 0x6894,
+	0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0x7808, 0xc08d, 0x780a,
+	0x70a4, 0x8000, 0x70a6, 0x74b4, 0xa490, 0x0005, 0x70ac, 0xa206,
+	0x00c0, 0x2db3, 0x72a8, 0x72b6, 0x2900, 0x705a, 0x68bc, 0x7042,
+	0x7003, 0x0002, 0x2d00, 0x704e, 0xad80, 0x0009, 0x7046, 0x007c,
+	0x6bb4, 0xa39d, 0x2000, 0x7b5a, 0x6814, 0xc0fc, 0x8007, 0x7882,
+	0x6b94, 0x7bd6, 0x7bde, 0x6e98, 0x7ed2, 0x7eda, 0x781b, 0x005b,
+	0x2900, 0x705a, 0x7202, 0x7808, 0xc08d, 0x780a, 0x2300, 0xa605,
+	0x0040, 0x2deb, 0x70d4, 0xa084, 0x2700, 0xa086, 0x2300, 0x00c0,
+	0x2de5, 0x2009, 0x0000, 0x0078, 0x2de7, 0x2009, 0x0001, 0xa284,
+	0x000f, 0x1079, 0x2def, 0xad80, 0x0009, 0x7046, 0x007c, 0x2df7,
+	0x48bd, 0x48bd, 0x48aa, 0x48bd, 0x2df7, 0x2df7, 0x2df7, 0x1078,
+	0x296b, 0x7808, 0xa084, 0xfffd, 0x780a, 0x1078, 0x295e, 0x0f7e,
+	0x2079, 0x4e00, 0x78ac, 0x0f7f, 0xd084, 0x0040, 0x2e21, 0x7064,
+	0xa086, 0x0001, 0x00c0, 0x2e0f, 0x7066, 0x0078, 0x2ef8, 0x7064,
+	0xa086, 0x0005, 0x00c0, 0x2e1f, 0x707c, 0x2068, 0x681b, 0x0004,
+	0x6817, 0x0000, 0x6820, 0xa084, 0x00ff, 0xc09d, 0x6822, 0x7067,
+	0x0000, 0x70a7, 0x0000, 0x70a8, 0x70b2, 0x70b6, 0x1078, 0x2aba,
+	0x157e, 0x2011, 0x0004, 0x7164, 0xa186, 0x0001, 0x0040, 0x2e41,
+	0xa186, 0x0007, 0x00c0, 0x2e38, 0x701f, 0x0005, 0x0078, 0x2e41,
+	0x701f, 0x0001, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078,
+	0x2e43, 0x7067, 0x0000, 0x2001, 0x4e0a, 0x2004, 0xa084, 0x00ff,
+	0xa086, 0x0018, 0x0040, 0x2e53, 0x7018, 0x7016, 0xa005, 0x00c0,
+	0x2e53, 0x70a7, 0x0001, 0x067e, 0x1078, 0x4586, 0x20a9, 0x0010,
+	0x2039, 0x0000, 0x1078, 0x40f8, 0xa7b8, 0x0100, 0x00f0, 0x2e5a,
+	0x067f, 0x7000, 0x0079, 0x2e64, 0x2e9e, 0x2e79, 0x2e79, 0x2e6e,
+	0x2e9e, 0x2e9e, 0x2e9e, 0x2e6c, 0x1078, 0x296b, 0x7060, 0xa005,
+	0x0040, 0x2e9e, 0xad06, 0x00c0, 0x2e79, 0x6800, 0x7062, 0x0078,
+	0x2e8b, 0x6820, 0xd084, 0x00c0, 0x2e87, 0x6f14, 0x1078, 0x41fe,
+	0x6008, 0xc0d4, 0x600a, 0x1078, 0x3dd0, 0x0078, 0x2e8b, 0x705c,
+	0x2060, 0x6800, 0x6002, 0xa684, 0x5f00, 0x681e, 0x6818, 0xd0fc,
+	0x0040, 0x2e93, 0x6a1a, 0x6817, 0x0000, 0x682b, 0x0000, 0x6820,
+	0xa084, 0x00ff, 0xc09d, 0x6822, 0x1078, 0x202c, 0xb284, 0x0400,
+	0x0040, 0x2ea6, 0x2021, 0x95d0, 0x0078, 0x2ea8, 0x2021, 0x94c0,
+	0x1078, 0x2efd, 0xb284, 0x0400, 0x0040, 0x2eb2, 0x2021, 0x4e98,
+	0x0078, 0x2eb4, 0x2021, 0x4e58, 0x1078, 0x2efd, 0x20a9, 0x0101,
+	0xb284, 0x0400, 0x0040, 0x2ec0, 0x2021, 0x94d0, 0x0078, 0x2ec2,
+	0x2021, 0x93c0, 0x1078, 0x2efd, 0x8420, 0x00f0, 0x2ec2, 0xb284,
+	0x0300, 0x0040, 0x2ecf, 0x2061, 0x53c0, 0x0078, 0x2ed1, 0x2061,
+	0x73c0, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6110, 0x81ff, 0x0040,
+	0x2eee, 0x6018, 0x017e, 0x007e, 0x2011, 0x4e02, 0x220c, 0xa102,
+	0x2012, 0x007f, 0x017f, 0xa102, 0x0050, 0x2eee, 0x6012, 0x00c0,
+	0x2eee, 0x2011, 0x4e04, 0x2204, 0xc0a5, 0x2012, 0x601b, 0x0000,
+	0xace0, 0x0010, 0x00f0, 0x2ed5, 0x8421, 0x00c0, 0x2ed3, 0x157f,
+	0x7003, 0x0000, 0x704f, 0x0000, 0x007c, 0x047e, 0x2404, 0xa005,
+	0x0040, 0x2f18, 0x2068, 0x6800, 0x007e, 0x6a1a, 0x6817, 0x0000,
+	0x682b, 0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084,
+	0x00ff, 0xc09d, 0x6822, 0x1078, 0x202c, 0x007f, 0x0078, 0x2eff,
+	0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050, 0x2f22,
+	0x1078, 0x296b, 0x2300, 0x0079, 0x2f25, 0x2f28, 0x2fb3, 0x2fd0,
+	0xa282, 0x0002, 0x0040, 0x2f2e, 0x1078, 0x296b, 0x7064, 0x7067,
+	0x0000, 0x7083, 0x0000, 0x0079, 0x2f35, 0x2f3d, 0x2f3d, 0x2f3f,
+	0x2f7f, 0x3e0c, 0x2f3d, 0x2f7f, 0x2f3d, 0x1078, 0x296b, 0x7774,
+	0x1078, 0x40f8, 0x7774, 0xa7bc, 0x8f00, 0x1078, 0x41fe, 0x6018,
+	0xa005, 0x0040, 0x2f76, 0xd7fc, 0x00c0, 0x2f52, 0x2021, 0x94c0,
+	0x0078, 0x2f54, 0x2021, 0x95d0, 0x2009, 0x0005, 0x2011, 0x0010,
+	0x1078, 0x2feb, 0x0040, 0x2f76, 0x157e, 0x20a9, 0x0101, 0xd7fc,
+	0x00c0, 0x2f66, 0x2021, 0x93c0, 0x0078, 0x2f68, 0x2021, 0x94d0,
+	0x047e, 0x2009, 0x0005, 0x2011, 0x0010, 0x1078, 0x2feb, 0x047f,
+	0x0040, 0x2f75, 0x8420, 0x00f0, 0x2f68, 0x157f, 0x8738, 0xa784,
+	0x001f, 0x00c0, 0x2f45, 0x0078, 0x29c5, 0x0078, 0x29c5, 0x7774,
+	0x1078, 0x41fe, 0x6018, 0xa005, 0x0040, 0x2fb1, 0xd7fc, 0x00c0,
+	0x2f8d, 0x2021, 0x94c0, 0x0078, 0x2f8f, 0x2021, 0x95d0, 0x2009,
+	0x0005, 0x2011, 0x0020, 0x1078, 0x2feb, 0x0040, 0x2fb1, 0x157e,
+	0x20a9, 0x0101, 0xd7fc, 0x00c0, 0x2fa1, 0x2021, 0x93c0, 0x0078,
+	0x2fa3, 0x2021, 0x94d0, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020,
+	0x1078, 0x2feb, 0x047f, 0x0040, 0x2fb0, 0x8420, 0x00f0, 0x2fa3,
+	0x157f, 0x0078, 0x29c5, 0x2200, 0x0079, 0x2fb6, 0x2fb9, 0x2fbb,
+	0x2fbb, 0x1078, 0x296b, 0x2009, 0x0012, 0x7064, 0xa086, 0x0002,
+	0x0040, 0x2fc4, 0x2009, 0x000e, 0x6818, 0xd0fc, 0x0040, 0x2fc9,
+	0x691a, 0x7067, 0x0000, 0x70d4, 0xc0dd, 0x70d6, 0x0078, 0x430d,
+	0x2200, 0x0079, 0x2fd3, 0x2fd8, 0x2fbb, 0x2fd6, 0x1078, 0x296b,
+	0x1078, 0x4586, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3d7e, 0x1078,
+	0x3ded, 0x6008, 0xa084, 0xfbef, 0x600a, 0x1078, 0x3d6f, 0x0040,
+	0x3d7e, 0x0078, 0x29c5, 0x2404, 0xa005, 0x0040, 0x3024, 0x2068,
+	0x2d04, 0x007e, 0x6814, 0xa706, 0x0040, 0x2ffa, 0x2d20, 0x007f,
+	0x0078, 0x2fec, 0x007f, 0x2022, 0x691a, 0x6817, 0x0000, 0x682b,
+	0x0000, 0x68b4, 0xa084, 0x5f00, 0x681e, 0x6820, 0xa084, 0x00ff,
+	0xa205, 0x6822, 0x1078, 0x202c, 0x2021, 0x4e02, 0x241c, 0x8319,
+	0x2322, 0x6010, 0x8001, 0x6012, 0x00c0, 0x301b, 0x2021, 0x4e04,
+	0x2404, 0xc0a5, 0x2022, 0x6008, 0xa084, 0xf9ef, 0x600a, 0x1078,
+	0x2adb, 0x1078, 0x3ded, 0x007c, 0xa085, 0x0001, 0x0078, 0x3023,
+	0x2300, 0x0079, 0x302b, 0x3030, 0x302e, 0x30b0, 0x1078, 0x296b,
+	0x78e4, 0xa005, 0x00d0, 0x3066, 0x3208, 0x007e, 0x2001, 0x4e04,
+	0x2004, 0xd0ec, 0x007f, 0x0040, 0x3041, 0xa18c, 0x0300, 0x0078,
+	0x3043, 0xa18c, 0x0400, 0x0040, 0x3049, 0x0018, 0x29c1, 0x0078,
+	0x304b, 0x0028, 0x29c1, 0x2008, 0xa084, 0x0030, 0x00c0, 0x3052,
+	0x0078, 0x3770, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3050, 0x2100,
+	0xa084, 0x0007, 0x0079, 0x305c, 0x3090, 0x309a, 0x3085, 0x3064,
+	0x4355, 0x4355, 0x3064, 0x30a5, 0x1078, 0x296b, 0x7000, 0xa086,
+	0x0004, 0x00c0, 0x3080, 0x7064, 0xa086, 0x0002, 0x00c0, 0x3076,
+	0x2011, 0x0002, 0x2019, 0x0000, 0x0078, 0x2f1c, 0x7064, 0xa086,
+	0x0006, 0x0040, 0x3070, 0x7064, 0xa086, 0x0004, 0x0040, 0x3070,
+	0x79e4, 0x2001, 0x0003, 0x0078, 0x33fa, 0x6818, 0xd0fc, 0x0040,
+	0x308b, 0x681b, 0x001d, 0x1078, 0x40c8, 0x781b, 0x0064, 0x007c,
+	0x6818, 0xd0fc, 0x0040, 0x3096, 0x681b, 0x001d, 0x1078, 0x40c8,
+	0x0078, 0x4331, 0x6818, 0xd0fc, 0x0040, 0x30a0, 0x681b, 0x001d,
+	0x1078, 0x40c8, 0x781b, 0x00f8, 0x007c, 0x6818, 0xd0fc, 0x0040,
+	0x30ab, 0x681b, 0x001d, 0x1078, 0x40c8, 0x781b, 0x00c8, 0x007c,
+	0xa584, 0x000f, 0x00c0, 0x30cf, 0x1078, 0x295e, 0x7000, 0x0079,
+	0x30b9, 0x29c5, 0x30c1, 0x30c3, 0x3d7e, 0x3d7e, 0x3d7e, 0x30c1,
+	0x30c1, 0x1078, 0x296b, 0x1078, 0x3ded, 0x6008, 0xa084, 0xfbef,
+	0x600a, 0x1078, 0x3d6f, 0x0040, 0x3d7e, 0x0078, 0x29c5, 0x78e4,
+	0xa005, 0x00d0, 0x3066, 0x3208, 0x007e, 0x2001, 0x4e04, 0x2004,
+	0xd0ec, 0x007f, 0x0040, 0x30e0, 0xa18c, 0x0300, 0x0078, 0x30e2,
+	0xa18c, 0x0400, 0x0040, 0x30e8, 0x0018, 0x3066, 0x0078, 0x30ea,
+	0x0028, 0x3066, 0x2008, 0xa084, 0x0030, 0x00c0, 0x30f2, 0x781b,
+	0x005b, 0x007c, 0x78ec, 0xa084, 0x0003, 0x0040, 0x30ef, 0x2100,
+	0xa184, 0x0007, 0x0079, 0x30fc, 0x310b, 0x310f, 0x3106, 0x3104,
+	0x4355, 0x4355, 0x3104, 0x434f, 0x1078, 0x296b, 0x1078, 0x40d0,
+	0x781b, 0x0064, 0x007c, 0x1078, 0x40d0, 0x0078, 0x4331, 0x1078,
+	0x40d0, 0x781b, 0x00f8, 0x007c, 0x1078, 0x40d0, 0x781b, 0x00c8,
+	0x007c, 0x2300, 0x0079, 0x311c, 0x3121, 0x311f, 0x3123, 0x1078,
+	0x296b, 0x0078, 0x395f, 0x681b, 0x0016, 0x78a3, 0x0000, 0x79e4,
+	0xa184, 0x0030, 0x0040, 0x395f, 0x78ec, 0xa084, 0x0003, 0x0040,
+	0x395f, 0xa184, 0x0100, 0x0040, 0x3127, 0xa184, 0x0007, 0x0079,
+	0x3139, 0x3141, 0x310f, 0x3085, 0x430d, 0x4355, 0x4355, 0x430d,
+	0x434f, 0x1078, 0x4319, 0x007c, 0xa282, 0x0005, 0x0050, 0x314a,
+	0x1078, 0x296b, 0x2300, 0x0079, 0x314d, 0x3150, 0x3380, 0x338b,
+	0x2200, 0x0079, 0x3153, 0x316d, 0x315a, 0x316d, 0x3158, 0x3363,
+	0x1078, 0x296b, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082,
+	0x0020, 0x0048, 0x40b7, 0xa08a, 0x0004, 0x00c8, 0x40b7, 0x0079,
+	0x3169, 0x40b7, 0x40b7, 0x40b7, 0x4061, 0x789b, 0x0018, 0x79a8,
+	0xa184, 0x0080, 0x0040, 0x317e, 0x0078, 0x40b7, 0x7000, 0xa005,
+	0x00c0, 0x3174, 0x2011, 0x0004, 0x0078, 0x3b4a, 0xa184, 0x00ff,
+	0xa08a, 0x0010, 0x00c8, 0x40b7, 0x0079, 0x3186, 0x3198, 0x3196,
+	0x31ad, 0x31b1, 0x3284, 0x40b7, 0x40b7, 0x3286, 0x40b7, 0x40b7,
+	0x335f, 0x335f, 0x40b7, 0x40b7, 0x40b7, 0x3361, 0x1078, 0x296b,
+	0xd6e4, 0x0040, 0x31a3, 0x2001, 0x0300, 0x8000, 0x8000, 0x783a,
+	0x781b, 0x00c3, 0x007c, 0x6818, 0xd0fc, 0x0040, 0x31ab, 0x681b,
+	0x001d, 0x0078, 0x319b, 0x0078, 0x430d, 0x681b, 0x001d, 0x0078,
+	0x40c1, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x3216, 0x6820,
+	0xd084, 0x00c0, 0x321c, 0x6818, 0xa086, 0x0008, 0x00c0, 0x31c2,
+	0x681b, 0x0000, 0xd6d4, 0x0040, 0x3281, 0xd6bc, 0x0040, 0x3202,
+	0x7087, 0x0000, 0x6818, 0xa084, 0x003f, 0xa08a, 0x000d, 0x0050,
+	0x3202, 0xa08a, 0x000c, 0x7186, 0x2001, 0x000c, 0x800c, 0x718a,
+	0x789b, 0x0061, 0x78aa, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208,
+	0xa18c, 0x0300, 0x0040, 0x31f4, 0x007e, 0x2001, 0x4e04, 0x2004,
+	0xd0ec, 0x007f, 0x0040, 0x31f0, 0x20a1, 0x012b, 0x0078, 0x31f6,
+	0x20a1, 0x022b, 0x0078, 0x31f6, 0x20a1, 0x012b, 0x017f, 0x789b,
+	0x0000, 0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f,
+	0x137f, 0x157f, 0x6038, 0xa005, 0x00c0, 0x3211, 0x681c, 0xa084,
+	0x000e, 0x0040, 0x40c1, 0x1078, 0x40d7, 0x782b, 0x3008, 0x0078,
+	0x3213, 0x8001, 0x603a, 0x781b, 0x0067, 0x007c, 0xd6e4, 0x0040,
+	0x321c, 0x781b, 0x0079, 0x007c, 0xa684, 0x0060, 0x0040, 0x327e,
+	0xd6dc, 0x0040, 0x327e, 0xd6fc, 0x00c0, 0x3228, 0x0078, 0x323f,
+	0xc6fc, 0x7e5a, 0x6eb6, 0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8,
+	0x3232, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98,
+	0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0xd6f4,
+	0x0040, 0x3245, 0xc6f4, 0x7e5a, 0x6eb6, 0x7000, 0xa086, 0x0003,
+	0x00c0, 0x3253, 0x007e, 0x1078, 0x4586, 0x1078, 0x48bd, 0x007f,
+	0x781b, 0x0076, 0x007c, 0xa006, 0x1078, 0x49c3, 0x6ab0, 0x69ac,
+	0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040, 0x3262, 0x2200, 0xa422,
+	0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda, 0x6ba6, 0x7bd6, 0x7bde,
+	0x2300, 0xa405, 0x00c0, 0x3272, 0xc6f5, 0x7e5a, 0x6eb6, 0x781b,
+	0x0076, 0x007c, 0x781b, 0x0076, 0x2200, 0xa115, 0x00c0, 0x327b,
+	0x1078, 0x48bd, 0x007c, 0x1078, 0x48f5, 0x007c, 0x781b, 0x0079,
+	0x007c, 0x781b, 0x0067, 0x007c, 0x1078, 0x296b, 0x0078, 0x32d2,
+	0x6920, 0xd1c4, 0x0040, 0x329b, 0xc1c4, 0x6922, 0x0c7e, 0x7058,
+	0x2060, 0x6000, 0xc0e4, 0x6002, 0x6004, 0xa084, 0xfff5, 0x6006,
+	0x0c7f, 0x0078, 0x32c6, 0xd1cc, 0x0040, 0x32c6, 0xc1cc, 0x6922,
+	0x0c7e, 0x7058, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x6004, 0xc0a4,
+	0x6006, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x32c6, 0x1078,
+	0x41fa, 0x1078, 0x3ef5, 0x88ff, 0x0040, 0x32c6, 0x789b, 0x0060,
+	0x2800, 0x78aa, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x32c3,
+	0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7e58, 0xd6d4,
+	0x00c0, 0x32cd, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079, 0x007c,
+	0x0078, 0x40bc, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x00c0,
+	0x32e0, 0x6820, 0xa084, 0x0100, 0x0040, 0x32d0, 0x2009, 0x0008,
+	0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0,
+	0x32fc, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x32f4,
+	0x0048, 0x32f4, 0x0078, 0x32f6, 0x0078, 0x3288, 0x24a8, 0x7aa8,
+	0x00f0, 0x32f6, 0x0078, 0x32e2, 0xa284, 0x00f0, 0xa086, 0x0020,
+	0x00c0, 0x3350, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x330c,
+	0x0048, 0x330c, 0x0078, 0x334d, 0xa286, 0x0023, 0x0040, 0x32d0,
+	0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684, 0xfff1, 0xc0a5,
+	0x2030, 0x7e5a, 0x6008, 0xc0a5, 0x600a, 0x0c7e, 0x7058, 0x2060,
+	0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd1a4, 0x0040, 0x332d, 0x1078,
+	0x41fa, 0x1078, 0x4011, 0x0078, 0x333b, 0x0c7e, 0x7058, 0x2060,
+	0x6004, 0x2008, 0x2c48, 0x0c7f, 0xd19c, 0x0040, 0x32c6, 0x1078,
+	0x41fa, 0x1078, 0x3ef5, 0x88ff, 0x0040, 0x32c6, 0x789b, 0x0060,
+	0x2800, 0x78aa, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x334a, 0x781b,
+	0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x7aa8, 0x0078, 0x32e2,
+	0x8318, 0x2300, 0xa102, 0x0040, 0x3359, 0x0048, 0x3359, 0x0078,
+	0x32e2, 0xa284, 0x0080, 0x00c0, 0x40c1, 0x0078, 0x40bc, 0x0078,
+	0x40c1, 0x0078, 0x40b7, 0x7058, 0xa04d, 0x789b, 0x0018, 0x78a8,
+	0xa084, 0x00ff, 0xa08e, 0x0001, 0x0040, 0x3370, 0x1078, 0x296b,
+	0x7aa8, 0xa294, 0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004,
+	0x00c8, 0x40b7, 0x0079, 0x337c, 0x40b7, 0x3e46, 0x40b7, 0x3fb9,
+	0xa282, 0x0000, 0x00c0, 0x3386, 0x1078, 0x296b, 0x1078, 0x40c8,
+	0x781b, 0x0078, 0x007c, 0xa282, 0x0003, 0x00c0, 0x3391, 0x1078,
+	0x296b, 0xd4fc, 0x00c0, 0x33b1, 0x7064, 0xa005, 0x0040, 0x339a,
+	0x1078, 0x296b, 0x6f14, 0x7776, 0xa7bc, 0x8f00, 0x1078, 0x41fe,
+	0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x00c0,
+	0x339e, 0x1078, 0x40cc, 0x7067, 0x0002, 0x701f, 0x0009, 0x0078,
+	0x33b3, 0x1078, 0x40db, 0x781b, 0x0078, 0x007c, 0xa282, 0x0004,
+	0x0050, 0x33bc, 0x1078, 0x296b, 0x2300, 0x0079, 0x33bf, 0x33c2,
+	0x3582, 0x35c5, 0xa286, 0x0003, 0x0040, 0x33fa, 0x7200, 0x7cd8,
+	0x7ddc, 0x7fd0, 0x71d4, 0xd1bc, 0x00c0, 0x33f2, 0xd1b4, 0x0040,
+	0x33f2, 0x7868, 0xa084, 0x00ff, 0x00c0, 0x33f2, 0xa282, 0x0002,
+	0x00c8, 0x33f2, 0x0d7e, 0x783b, 0x8300, 0x781b, 0x004c, 0x70bc,
+	0xa06d, 0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2,
+	0x78da, 0xc1b4, 0x71d6, 0x7003, 0x0030, 0x0d7f, 0x2001, 0x0000,
+	0x0078, 0x33fe, 0x783b, 0x1300, 0x781b, 0x004a, 0x2001, 0x0000,
+	0x0078, 0x33fe, 0x7200, 0x7cd8, 0x7ddc, 0x7fd0, 0x704a, 0x68a0,
+	0xd0ec, 0x0040, 0x3406, 0x6008, 0xc08d, 0x600a, 0xa284, 0x000f,
+	0x0079, 0x340a, 0x3562, 0x3417, 0x3414, 0x36c8, 0x3754, 0x29c5,
+	0x3412, 0x3412, 0x1078, 0x296b, 0x6008, 0xc0d4, 0x600a, 0xd6e4,
+	0x0040, 0x341f, 0x7048, 0xa086, 0x0014, 0x00c0, 0x343f, 0x1078,
+	0x4586, 0x2009, 0x0000, 0x6818, 0xd0fc, 0x0040, 0x3428, 0x7048,
+	0xa086, 0x0014, 0x0040, 0x3439, 0x6818, 0xa086, 0x0008, 0x00c0,
+	0x351a, 0x7858, 0xd09c, 0x0040, 0x351a, 0x6820, 0xd0ac, 0x0040,
+	0x351a, 0x681b, 0x0014, 0x2009, 0x0002, 0x0078, 0x347e, 0x7868,
+	0xa08c, 0x00ff, 0x0040, 0x347e, 0xa186, 0x0008, 0x00c0, 0x3455,
+	0x6008, 0xc0a4, 0x600a, 0x1078, 0x3d6f, 0x0040, 0x347e, 0x1078,
+	0x3ded, 0x1078, 0x4586, 0x0078, 0x3466, 0xa186, 0x0028, 0x00c0,
+	0x347e, 0x6018, 0xa005, 0x0040, 0x3448, 0x8001, 0x0040, 0x3448,
+	0x8001, 0x0040, 0x3448, 0x601e, 0x0078, 0x3448, 0x6820, 0xd084,
+	0x0040, 0x29c5, 0xc084, 0x6822, 0x1078, 0x2acc, 0x705c, 0x0c7e,
+	0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802, 0xa005, 0x2d00,
+	0x00c0, 0x347b, 0x6002, 0x6006, 0x0078, 0x29c5, 0x017e, 0x81ff,
+	0x00c0, 0x34c8, 0x7000, 0xa086, 0x0030, 0x0040, 0x34c8, 0x71d4,
+	0xd1bc, 0x00c0, 0x34c8, 0xd1b4, 0x00c0, 0x34af, 0x7060, 0xa005,
+	0x00c0, 0x34c8, 0x70a4, 0xa086, 0x0001, 0x0040, 0x34c8, 0x7003,
+	0x0000, 0x047e, 0x057e, 0x077e, 0x067e, 0x0c7e, 0x0d7e, 0x1078,
+	0x29ee, 0x0d7f, 0x0c7f, 0x067f, 0x077f, 0x057f, 0x047f, 0x71d4,
+	0xd1b4, 0x00c0, 0x34c8, 0x7003, 0x0040, 0x0078, 0x34c8, 0x1078,
+	0x4360, 0x00c0, 0x34c8, 0x781b, 0x005b, 0x0d7e, 0x70bc, 0xa06d,
+	0x68b4, 0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da,
+	0xc1b4, 0x71d6, 0x7003, 0x0030, 0x7808, 0xc08d, 0x780a, 0x0d7f,
+	0x1078, 0x35ff, 0x017f, 0x81ff, 0x0040, 0x351a, 0xa684, 0xdf00,
+	0x681e, 0x682b, 0x0000, 0x6f14, 0xa186, 0x0002, 0x00c0, 0x351b,
+	0x6818, 0xa086, 0x0014, 0x00c0, 0x34e4, 0x2008, 0xd6e4, 0x0040,
+	0x34e4, 0x7868, 0xa08c, 0x00ff, 0x1078, 0x2aba, 0x1078, 0x2adb,
+	0x6820, 0xd0dc, 0x00c0, 0x351b, 0x8717, 0xa294, 0x000f, 0x8213,
+	0x8213, 0x8213, 0xb284, 0x0300, 0x0040, 0x34fa, 0xa290, 0x52c0,
+	0x0078, 0x34fc, 0xa290, 0x5340, 0xa290, 0x0000, 0x221c, 0xd3c4,
+	0x00c0, 0x3504, 0x0078, 0x350a, 0x8210, 0x2204, 0xa085, 0x0018,
+	0x2012, 0x8211, 0xd3d4, 0x0040, 0x3515, 0x68a0, 0xd0c4, 0x00c0,
+	0x3515, 0x1078, 0x3679, 0x0078, 0x29c5, 0x6008, 0xc08d, 0x600a,
+	0x0078, 0x351b, 0x692a, 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3522,
+	0x7048, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x6410, 0x84ff, 0x0040,
+	0x3537, 0x2009, 0x4e02, 0x2104, 0x8001, 0x200a, 0x8421, 0x6412,
+	0x00c0, 0x3537, 0x2021, 0x4e04, 0x2404, 0xc0a5, 0x2022, 0x6018,
+	0xa005, 0x0040, 0x353f, 0x8001, 0x601a, 0x00c0, 0x3542, 0x6008,
+	0xc0a4, 0x600a, 0x6820, 0xd084, 0x00c0, 0x354e, 0x6800, 0xa005,
+	0x00c0, 0x354b, 0x6002, 0x6006, 0x0078, 0x3552, 0x705c, 0x2060,
+	0x6800, 0x6002, 0x2061, 0x4e00, 0x6887, 0x0103, 0x2d08, 0x206b,
+	0x0000, 0x6068, 0xa005, 0x616a, 0x0040, 0x3561, 0x2d02, 0x0078,
+	0x3562, 0x616e, 0x7200, 0xa286, 0x0030, 0x0040, 0x3572, 0xa286,
+	0x0040, 0x00c0, 0x29c5, 0x7003, 0x0002, 0x704c, 0x2068, 0x68c4,
+	0x2060, 0x007c, 0x7003, 0x0002, 0x70bc, 0xa06d, 0x68bc, 0x7042,
+	0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00, 0x704e, 0xad80, 0x0009,
+	0x7046, 0x007c, 0xa282, 0x0004, 0x0048, 0x3588, 0x1078, 0x296b,
+	0x2200, 0x0079, 0x358b, 0x358f, 0x35a0, 0x35ad, 0x35a0, 0xa586,
+	0x1300, 0x0040, 0x35a0, 0xa586, 0x8300, 0x00c0, 0x3586, 0x7003,
+	0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084, 0xfbef, 0x600a,
+	0x7000, 0xa086, 0x0005, 0x0040, 0x35aa, 0x1078, 0x40c8, 0x781b,
+	0x0078, 0x007c, 0x781b, 0x0079, 0x007c, 0x7890, 0x8007, 0x8001,
+	0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff,
+	0xa186, 0x0003, 0x0040, 0x35c2, 0xa186, 0x0000, 0x0040, 0x35c2,
+	0x0078, 0x40b7, 0x781b, 0x0079, 0x007c, 0x6820, 0xc095, 0x6822,
+	0x82ff, 0x00c0, 0x35cf, 0x1078, 0x40c8, 0x0078, 0x35d6, 0x8211,
+	0x0040, 0x35d4, 0x1078, 0x296b, 0x1078, 0x40db, 0x781b, 0x0078,
+	0x007c, 0x1078, 0x4383, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x35fc,
+	0x017e, 0x3208, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f,
+	0x0040, 0x35ee, 0xa18c, 0x0300, 0x0078, 0x35f0, 0xa18c, 0x0400,
+	0x017f, 0x0040, 0x35f7, 0x0018, 0x35fc, 0x0078, 0x35f9, 0x0028,
+	0x35fc, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684,
+	0x0060, 0x00c0, 0x3609, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078,
+	0x3678, 0xd6dc, 0x00c0, 0x3621, 0x68b4, 0xd0dc, 0x00c0, 0x3621,
+	0x6998, 0x6a94, 0x692e, 0x6a32, 0x7048, 0xa005, 0x00c0, 0x361e,
+	0x2200, 0xa105, 0x0040, 0x4586, 0x704b, 0x0015, 0x0078, 0x4586,
+	0x007c, 0xd6ac, 0x0040, 0x3647, 0xd6f4, 0x0040, 0x362d, 0x682f,
+	0x0000, 0x6833, 0x0000, 0x0078, 0x4586, 0x68b4, 0xa084, 0x4000,
+	0xa635, 0xd6f4, 0x00c0, 0x3627, 0x7048, 0xa005, 0x00c0, 0x363a,
+	0x704b, 0x0015, 0xd6dc, 0x00c0, 0x3643, 0x68b4, 0xd0dc, 0x0040,
+	0x3643, 0x6ca8, 0x6da4, 0x6c2e, 0x6d32, 0x0078, 0x4586, 0xd6f4,
+	0x0040, 0x3650, 0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x4586,
+	0x68b4, 0xa084, 0x4800, 0xa635, 0xd6f4, 0x00c0, 0x364a, 0x7048,
+	0xa005, 0x00c0, 0x365d, 0x704b, 0x0015, 0x2408, 0x2510, 0x2700,
+	0x80fb, 0x00c8, 0x3664, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291,
+	0x0000, 0x692e, 0x6a32, 0x2100, 0xa205, 0x00c0, 0x3671, 0x0078,
+	0x4586, 0x7000, 0xa086, 0x0006, 0x0040, 0x3678, 0x0078, 0x4586,
+	0x007c, 0x6946, 0x6008, 0xc0cd, 0xd3cc, 0x0040, 0x3680, 0xc08d,
+	0x600a, 0x6818, 0x683a, 0x681b, 0x0006, 0x688f, 0x0000, 0x6893,
+	0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003, 0x6833,
+	0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020, 0x7000,
+	0x0079, 0x369a, 0x29c5, 0x36ac, 0x36a4, 0x36a2, 0x36a2, 0x36a2,
+	0x36a2, 0x36a2, 0x1078, 0x296b, 0x6820, 0xd084, 0x00c0, 0x36ac,
+	0x1078, 0x3dd0, 0x0078, 0x36b2, 0x705c, 0x2c50, 0x2060, 0x6800,
+	0x6002, 0x2a60, 0x3208, 0xa18c, 0x0300, 0x0040, 0x36bb, 0x2021,
+	0x4e58, 0x0078, 0x36bd, 0x2021, 0x4e98, 0x2404, 0xa005, 0x0040,
+	0x36c4, 0x2020, 0x0078, 0x36bd, 0x2d22, 0x206b, 0x0000, 0x007c,
+	0x1078, 0x3dd7, 0x1078, 0x3ded, 0x6008, 0xc0cc, 0x600a, 0x682b,
+	0x0000, 0x789b, 0x000e, 0x6f14, 0x6938, 0x691a, 0x6944, 0x6916,
+	0x3208, 0xa18c, 0x0300, 0x0040, 0x36e1, 0x2009, 0x0000, 0x0078,
+	0x36e3, 0x2009, 0x0001, 0x1078, 0x49f8, 0xd6dc, 0x0040, 0x36eb,
+	0x691c, 0xc1ed, 0x691e, 0x6818, 0xd0fc, 0x0040, 0x36fa, 0x7868,
+	0xa08c, 0x00ff, 0x0040, 0x36f8, 0x681b, 0x001e, 0x0078, 0x36fa,
+	0x681b, 0x0000, 0xb284, 0x0300, 0x00c0, 0x3702, 0x2021, 0x4e98,
+	0x0078, 0x3704, 0x2021, 0x4e58, 0x6800, 0x2022, 0x6a3c, 0x6940,
+	0x6a32, 0x692e, 0x68c0, 0x2060, 0x6000, 0xd0a4, 0x0040, 0x3744,
+	0x2041, 0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x0d7e, 0x0f7e,
+	0x157e, 0x147e, 0x2079, 0x4e00, 0x1078, 0x1dff, 0x147f, 0x157f,
+	0x0f7f, 0x70cc, 0x2010, 0x2009, 0x0101, 0x027e, 0x2204, 0xa06d,
+	0x0040, 0x3734, 0x6814, 0xa706, 0x0040, 0x3731, 0x6800, 0x0078,
+	0x3727, 0x6820, 0xc0d5, 0x6822, 0x027f, 0x8210, 0x8109, 0x00c0,
+	0x3725, 0x0d7f, 0x7067, 0x0003, 0x707f, 0x0000, 0x7776, 0x7083,
+	0x000f, 0x71d4, 0xc1dc, 0x71d6, 0x6818, 0xa086, 0x0002, 0x00c0,
+	0x3750, 0x6817, 0x0000, 0x682b, 0x0000, 0x681c, 0xc0ec, 0x681e,
+	0x1078, 0x202c, 0x0078, 0x29c5, 0x7cd8, 0x7ddc, 0x7fd0, 0x1078,
+	0x35ff, 0x682b, 0x0000, 0x789b, 0x000e, 0x6f14, 0x1078, 0x4387,
+	0xa08c, 0x00ff, 0x6916, 0x6818, 0xd0fc, 0x0040, 0x3769, 0x7048,
+	0x681a, 0xa68c, 0xdf00, 0x691e, 0x7067, 0x0000, 0x0078, 0x29c5,
+	0x7000, 0xa005, 0x00c0, 0x3776, 0x0078, 0x29c5, 0xa006, 0x1078,
+	0x4586, 0x6920, 0xd1ac, 0x00c0, 0x377f, 0x681b, 0x0014, 0xa68c,
+	0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa084, 0x00ff, 0x6822,
+	0x7000, 0x0079, 0x378b, 0x29c5, 0x3795, 0x3795, 0x3798, 0x3798,
+	0x3798, 0x3793, 0x3793, 0x1078, 0x296b, 0x6818, 0x0078, 0x33fa,
+	0x6008, 0xc0a4, 0x600a, 0x6817, 0x0000, 0x0078, 0x3d95, 0x2300,
+	0x0079, 0x37a2, 0x37a5, 0x37a7, 0x3817, 0x1078, 0x296b, 0xd6fc,
+	0x00c0, 0x37fe, 0x7000, 0xa00d, 0x0079, 0x37ae, 0x29c5, 0x37b8,
+	0x37b8, 0x37e8, 0x37b8, 0x37fb, 0x37b6, 0x37b6, 0x1078, 0x296b,
+	0xa684, 0x0060, 0x0040, 0x37e8, 0xa086, 0x0060, 0x00c0, 0x37e5,
+	0xc6ac, 0xc6f4, 0xc6ed, 0x7e5a, 0x6eb6, 0x681c, 0xc0ac, 0x681e,
+	0xa186, 0x0002, 0x0040, 0x37d7, 0x1078, 0x4586, 0x69ac, 0x68b0,
+	0xa115, 0x0040, 0x37d7, 0x1078, 0x48f5, 0x0078, 0x37d9, 0x1078,
+	0x48bd, 0x781b, 0x0079, 0x71d4, 0xd1b4, 0x00c0, 0x29c1, 0x70a4,
+	0xa086, 0x0001, 0x00c0, 0x2a0b, 0x007c, 0xd6ec, 0x0040, 0x37c2,
+	0x6818, 0xd0fc, 0x0040, 0x37fb, 0xd6f4, 0x00c0, 0x37f5, 0x681b,
+	0x0015, 0x781b, 0x0079, 0x0078, 0x29c1, 0x681b, 0x0007, 0x682f,
+	0x0000, 0x6833, 0x0000, 0x1078, 0x4319, 0x007c, 0xc6fc, 0x7e5a,
+	0x7adc, 0x79d8, 0x78d0, 0x801b, 0x00c8, 0x3807, 0x8000, 0xa084,
+	0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2,
+	0x6b94, 0x2200, 0xa303, 0x68ae, 0x781b, 0x0079, 0x007c, 0x1078,
+	0x296b, 0x2300, 0x0079, 0x381c, 0x3821, 0x3846, 0x38a6, 0x1078,
+	0x296b, 0x7000, 0x0079, 0x3824, 0x382c, 0x382e, 0x3837, 0x382c,
+	0x382c, 0x382c, 0x382c, 0x382c, 0x1078, 0x296b, 0x69ac, 0x68b0,
+	0xa115, 0x0040, 0x3837, 0x1078, 0x48f5, 0x0078, 0x3839, 0x1078,
+	0x48bd, 0x681c, 0xc0b4, 0x681e, 0x70d4, 0xd0b4, 0x00c0, 0x29c1,
+	0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a0b, 0x007c, 0xd6fc, 0x00c0,
+	0x3896, 0x7000, 0xa00d, 0x0079, 0x384d, 0x29c5, 0x385d, 0x3857,
+	0x388d, 0x385d, 0x3893, 0x3855, 0x3855, 0x1078, 0x296b, 0x6894,
+	0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xa684, 0x0060, 0x0040,
+	0x388d, 0xa086, 0x0060, 0x00c0, 0x388a, 0xa6b4, 0xbfbf, 0xc6ed,
+	0x7e5a, 0x6eb6, 0xa186, 0x0002, 0x0040, 0x3879, 0x1078, 0x4586,
+	0x69ac, 0x68b0, 0xa115, 0x0040, 0x3879, 0x1078, 0x48f5, 0x0078,
+	0x387b, 0x1078, 0x48bd, 0x781b, 0x0079, 0x681c, 0xc0b4, 0x681e,
+	0x71d4, 0xd1b4, 0x00c0, 0x29c1, 0x70a4, 0xa086, 0x0001, 0x00c0,
+	0x2a0b, 0x007c, 0xd6ec, 0x0040, 0x3867, 0x6818, 0xd0fc, 0x0040,
+	0x3893, 0x681b, 0x0007, 0x781b, 0x00f9, 0x007c, 0xc6fc, 0x7e5a,
+	0x7adc, 0x79d8, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200,
+	0xa303, 0x68ae, 0x79d2, 0x781b, 0x0079, 0x007c, 0xd6dc, 0x0040,
+	0x38af, 0x782b, 0x3009, 0x781b, 0x0079, 0x0078, 0x29c1, 0x7884,
+	0xc0ac, 0x7886, 0x78e4, 0xa084, 0x0008, 0x00c0, 0x38c2, 0xa484,
+	0x0200, 0x0040, 0x38bc, 0xc6f5, 0xc6dd, 0x7e5a, 0x781b, 0x0079,
+	0x0078, 0x29c1, 0x6820, 0xc095, 0x6822, 0x1078, 0x4292, 0xc6dd,
+	0x1078, 0x40c8, 0x781b, 0x0078, 0x0078, 0x29c1, 0x2300, 0x0079,
+	0x38d1, 0x38d4, 0x38d6, 0x38d8, 0x1078, 0x296b, 0x0078, 0x40c1,
+	0xd6d4, 0x00c0, 0x3913, 0x79e4, 0xd1ac, 0x0040, 0x38e6, 0x78ec,
+	0xa084, 0x0003, 0x0040, 0x38e6, 0x782b, 0x3009, 0x789b, 0x0060,
+	0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xd1ac, 0x0040,
+	0x38f6, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x390f, 0x2001, 0x4e04,
+	0x2004, 0xd0e4, 0x00c0, 0x390b, 0x6820, 0xd0c4, 0x0040, 0x390b,
+	0x0c7e, 0x7058, 0x2060, 0x6004, 0xc09d, 0x6006, 0x6008, 0xa084,
+	0x00ff, 0x600a, 0x0c7f, 0x2001, 0x0014, 0x0078, 0x33fa, 0xa184,
+	0x0007, 0x0079, 0x3949, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060,
+	0x79a8, 0x81ff, 0x0040, 0x3947, 0x789b, 0x0010, 0x7ba8, 0xa384,
+	0x0001, 0x00c0, 0x393a, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0,
+	0x392d, 0x2009, 0xfff7, 0x0078, 0x3933, 0xa386, 0x0003, 0x00c0,
+	0x393a, 0x2009, 0xffef, 0x0c7e, 0x7058, 0x2060, 0x6004, 0xa104,
+	0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb,
+	0x785a, 0x782b, 0x3009, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078,
+	0x430d, 0x3090, 0x309a, 0x3953, 0x3959, 0x3951, 0x3951, 0x430d,
+	0x430d, 0x1078, 0x296b, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078,
+	0x4313, 0x6920, 0xa18c, 0xfcff, 0x6922, 0x0078, 0x430d, 0x79e4,
+	0xa184, 0x0030, 0x0040, 0x3969, 0x78ec, 0xa084, 0x0003, 0x00c0,
+	0x399d, 0x7000, 0xa086, 0x0004, 0x00c0, 0x3983, 0x7064, 0xa086,
+	0x0002, 0x00c0, 0x3979, 0x2011, 0x0002, 0x2019, 0x0000, 0x0078,
+	0x2f1c, 0x7064, 0xa086, 0x0006, 0x0040, 0x3973, 0x7064, 0xa086,
+	0x0004, 0x0040, 0x3973, 0x7000, 0xa086, 0x0000, 0x0040, 0x29c1,
+	0x6920, 0xa184, 0x0420, 0x0040, 0x3992, 0xc1d4, 0x6922, 0x6818,
+	0x0078, 0x33fa, 0x6818, 0xa08e, 0x0002, 0x0040, 0x399b, 0xc0fd,
+	0x681a, 0x2001, 0x0014, 0x0078, 0x33fa, 0xa184, 0x0007, 0x0079,
+	0x39a1, 0x430d, 0x430d, 0x39a9, 0x430d, 0x4355, 0x4355, 0x430d,
+	0x430d, 0xd6bc, 0x0040, 0x39eb, 0x7184, 0x81ff, 0x0040, 0x39eb,
+	0xa182, 0x000d, 0x00d0, 0x39b8, 0x7087, 0x0000, 0x0078, 0x39bd,
+	0xa182, 0x000c, 0x7086, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa,
+	0x157e, 0x137e, 0x147e, 0x7088, 0x8114, 0xa210, 0x728a, 0xa080,
+	0x000b, 0xad00, 0x2098, 0xb284, 0x0300, 0x0040, 0x39df, 0x007e,
+	0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x39db, 0x20a1,
+	0x012b, 0x0078, 0x39e1, 0x20a1, 0x022b, 0x0078, 0x39e1, 0x20a1,
+	0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6, 0x147f, 0x137f,
+	0x157f, 0x0078, 0x4313, 0xd6d4, 0x00c0, 0x3a3f, 0x6820, 0xd084,
+	0x0040, 0x4313, 0xa68c, 0x0060, 0xa684, 0x0060, 0x0040, 0x39fd,
+	0xa086, 0x0060, 0x00c0, 0x39fd, 0xc1f5, 0xc194, 0x795a, 0x69b6,
+	0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xc0fd,
+	0x681a, 0x78aa, 0x8008, 0x810c, 0x0040, 0x3e06, 0xa18c, 0x00f8,
+	0x00c0, 0x3e06, 0x157e, 0x137e, 0x147e, 0x017e, 0x3208, 0xa18c,
+	0x0300, 0x0040, 0x3a2b, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec,
+	0x007f, 0x0040, 0x3a27, 0x20a1, 0x012b, 0x0078, 0x3a2d, 0x20a1,
+	0x022b, 0x0078, 0x3a2d, 0x20a1, 0x012b, 0x017f, 0x789b, 0x0000,
+	0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f,
+	0x157f, 0x6814, 0xc0fc, 0x8007, 0x7882, 0x0078, 0x4313, 0x6818,
+	0xd0fc, 0x0040, 0x3a45, 0x681b, 0x0008, 0x6820, 0xc0ad, 0x6822,
+	0x1078, 0x40d0, 0x781b, 0x00ea, 0x007c, 0x2300, 0x0079, 0x3a50,
+	0x3a55, 0x3b2d, 0x3a53, 0x1078, 0x296b, 0x7cd8, 0x7ddc, 0x7fd0,
+	0x82ff, 0x00c0, 0x3a7e, 0x7200, 0xa286, 0x0003, 0x0040, 0x33c7,
+	0x71d4, 0xd1bc, 0x00c0, 0x3a81, 0xd1b4, 0x0040, 0x3a81, 0x0d7e,
+	0x783b, 0x8800, 0x781b, 0x004c, 0x70bc, 0xa06d, 0x68b4, 0xc0a5,
+	0x785a, 0x6894, 0x78d6, 0x78de, 0x6898, 0x78d2, 0x78da, 0xc1b4,
+	0x71d6, 0x7003, 0x0030, 0x0d7f, 0x0078, 0x3a85, 0x7200, 0x0078,
+	0x3a85, 0x783b, 0x1800, 0x781b, 0x004a, 0xa284, 0x000f, 0x0079,
+	0x3a89, 0x3b18, 0x3ac7, 0x3a93, 0x33f6, 0x3a91, 0x3b18, 0x3a91,
+	0x3a91, 0x1078, 0x296b, 0x681c, 0xd0ec, 0x0040, 0x3a9a, 0x6008,
+	0xc08d, 0x600a, 0x6920, 0xc185, 0x6922, 0x6800, 0x6006, 0xa005,
+	0x00c0, 0x3aa3, 0x6002, 0x6008, 0xc0d4, 0x600a, 0x681c, 0xa084,
+	0x000e, 0x00c0, 0x3ab7, 0xb284, 0x0300, 0x0040, 0x3ab3, 0x2009,
+	0x94c0, 0x0078, 0x3abc, 0x2009, 0x95d0, 0x0078, 0x3abc, 0x7030,
+	0x68ba, 0x7140, 0x70cc, 0xa108, 0x2104, 0x6802, 0x2d0a, 0x715e,
+	0xd6dc, 0x00c0, 0x3ac7, 0xc6fc, 0x6eb6, 0x0078, 0x3b18, 0x6eb6,
+	0xa684, 0x0060, 0x00c0, 0x3ad1, 0xa684, 0x7fff, 0x68b6, 0x0078,
+	0x3b18, 0xd6dc, 0x00c0, 0x3adf, 0xa684, 0x7fff, 0x68b6, 0x6894,
+	0x68a6, 0x6898, 0x68aa, 0x1078, 0x4586, 0x0078, 0x3b18, 0xd6ac,
+	0x0040, 0x3aeb, 0xa006, 0x1078, 0x4586, 0x2408, 0x2510, 0x69aa,
+	0x6aa6, 0x0078, 0x3afb, 0x2408, 0x2510, 0x2700, 0x801b, 0x00c8,
+	0x3af2, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x69aa,
+	0x6aa6, 0x1078, 0x4586, 0xd6fc, 0x0040, 0x3b18, 0xa684, 0x7fff,
+	0x68b6, 0x2510, 0x2408, 0xd6ac, 0x00c0, 0x3b10, 0x2700, 0x801b,
+	0x00c8, 0x3b0b, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+	0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae,
+	0x7000, 0xa086, 0x0030, 0x00c0, 0x29c5, 0x7003, 0x0002, 0x70bc,
+	0xa06d, 0x68bc, 0x7042, 0x70b8, 0xa065, 0x68c0, 0x705a, 0x2d00,
+	0x704e, 0xad80, 0x0009, 0x7046, 0x007c, 0xa586, 0x8800, 0x00c0,
+	0x3b3a, 0x7003, 0x0000, 0x6018, 0x8001, 0x601a, 0x6008, 0xa084,
+	0xfbef, 0x600a, 0x0078, 0x40c1, 0x7047, 0x0000, 0xa282, 0x0006,
+	0x0050, 0x3b44, 0x1078, 0x296b, 0x2300, 0x0079, 0x3b47, 0x3b4a,
+	0x3b5c, 0x3b68, 0x2200, 0x0079, 0x3b4d, 0x3b53, 0x40c1, 0x3b55,
+	0x3b53, 0x3ba2, 0x3bf7, 0x1078, 0x296b, 0x7a80, 0xa294, 0x0f00,
+	0x1078, 0x3c81, 0x0078, 0x40b7, 0x1078, 0x3b79, 0x0079, 0x3b60,
+	0x40c1, 0x3b66, 0x3b66, 0x3ba2, 0x3b66, 0x40c1, 0x1078, 0x296b,
+	0x1078, 0x3b79, 0x0079, 0x3b6c, 0x3b74, 0x3b72, 0x3b72, 0x3b74,
+	0x3b72, 0x3b74, 0x1078, 0x296b, 0x1078, 0x40db, 0x781b, 0x0078,
+	0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3b8a, 0x1078, 0x3ded,
+	0x0078, 0x3b84, 0x1078, 0x4586, 0x6008, 0xa084, 0xfbef, 0x600a,
+	0x0078, 0x3b8f, 0x7000, 0xa086, 0x0003, 0x0040, 0x3b82, 0x7003,
+	0x0005, 0xb284, 0x0300, 0x0040, 0x3b99, 0x2001, 0x95e0, 0x0078,
+	0x3b9b, 0x2001, 0x9612, 0x2068, 0x704e, 0xad80, 0x0009, 0x7046,
+	0x2200, 0x007c, 0x7000, 0xa086, 0x0002, 0x00c0, 0x3bb4, 0x70d4,
+	0xc0b5, 0x70d6, 0x2c00, 0x70ba, 0x2d00, 0x70be, 0x0078, 0x3bb9,
+	0x1078, 0x4586, 0x0078, 0x3bb9, 0x7000, 0xa086, 0x0003, 0x0040,
+	0x3bb0, 0x7003, 0x0001, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018,
+	0x7ca8, 0xa484, 0x001f, 0xa215, 0x2069, 0x94c0, 0xb284, 0x0300,
+	0x00c0, 0x3bcd, 0xc2fd, 0x2069, 0x95d0, 0x2d04, 0x2d08, 0x715e,
+	0xa06d, 0x0040, 0x3bda, 0x6814, 0xa206, 0x0040, 0x3bdc, 0x6800,
+	0x0078, 0x3bce, 0x1078, 0x3c81, 0x6eb4, 0x7e5a, 0x6920, 0xa184,
+	0x0c00, 0x0040, 0x3cab, 0x7064, 0xa086, 0x0006, 0x00c0, 0x3bee,
+	0x7074, 0xa206, 0x00c0, 0x3bee, 0x7066, 0x707e, 0x681b, 0x0005,
+	0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x40d0, 0x0078, 0x3cab, 0x7200,
+	0xa286, 0x0002, 0x00c0, 0x3c09, 0x70d4, 0xc0b5, 0x70d6, 0x2c00,
+	0x70ba, 0x2d00, 0x70be, 0x0078, 0x3c0d, 0x1078, 0x4586, 0x0078,
+	0x3c0d, 0xa286, 0x0003, 0x0040, 0x3c05, 0x7003, 0x0001, 0x7a80,
+	0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f, 0xa215,
+	0xb284, 0x0300, 0x00c0, 0x3c1d, 0xc2fd, 0x79a8, 0x79a8, 0xa18c,
+	0x00ff, 0x2118, 0x70cc, 0xa168, 0x2d04, 0x2d08, 0x715e, 0xa06d,
+	0x0040, 0x3c31, 0x6814, 0xa206, 0x0040, 0x3c5a, 0x6800, 0x0078,
+	0x3c25, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3c3b, 0x2001,
+	0x95e0, 0x0078, 0x3c3d, 0x2001, 0x9612, 0x2068, 0x704e, 0x157e,
+	0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3c42, 0x157f,
+	0xb284, 0x0300, 0x0040, 0x3c4f, 0xc2fc, 0x0078, 0x3c50, 0xc2fd,
+	0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800,
+	0x6827, 0x0003, 0x6eb4, 0x6920, 0xa184, 0x0c00, 0x0040, 0x3cab,
+	0xd0dc, 0x0040, 0x3c76, 0x7064, 0xa086, 0x0004, 0x00c0, 0x3c72,
+	0x7074, 0xa206, 0x00c0, 0x3c72, 0x7078, 0xa306, 0x00c0, 0x3c72,
+	0x7066, 0x707e, 0x1078, 0x40d7, 0x0078, 0x3cab, 0x681b, 0x0005,
+	0xc1ad, 0xc1d4, 0x6922, 0x1078, 0x40d0, 0x707f, 0x0000, 0x0078,
+	0x3cab, 0x7003, 0x0005, 0xb284, 0x0300, 0x0040, 0x3c8b, 0x2001,
+	0x95e0, 0x0078, 0x3c8d, 0x2001, 0x9612, 0x2068, 0x704e, 0x157e,
+	0x20a9, 0x0032, 0x2003, 0x0000, 0x8000, 0x00f0, 0x3c92, 0x157f,
+	0xb284, 0x0300, 0x0040, 0x3c9f, 0xc2fc, 0x0078, 0x3ca0, 0xc2fd,
+	0x6a16, 0xad80, 0x0009, 0x7046, 0x68b7, 0x0700, 0x6823, 0x0800,
+	0x6827, 0x0003, 0x007c, 0xc6ec, 0xa6ac, 0x0060, 0x0040, 0x3cfd,
+	0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0, 0x3cd8, 0x7bd2,
+	0x7bda, 0x7cd6, 0x7cde, 0xa586, 0x0060, 0x0040, 0x3d02, 0xd6f4,
+	0x00c0, 0x3cc3, 0xc6ed, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0079,
+	0xd69c, 0x0040, 0x3cd0, 0x2009, 0x0078, 0x2019, 0x0000, 0x2320,
+	0x791a, 0xd6ec, 0x0040, 0x3d0d, 0x1078, 0x48bd, 0x0078, 0x3d0d,
+	0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040, 0x3d04,
+	0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xd6f4, 0x00c0, 0x3ce9,
+	0xc6ed, 0xc6f4, 0x7e5a, 0x2011, 0x0079, 0xd69c, 0x0040, 0x3cf5,
+	0x2011, 0x0078, 0x2019, 0x0000, 0x2320, 0x7a1a, 0xd6ec, 0x0040,
+	0x3d0d, 0x1078, 0x48f5, 0x0078, 0x3d0d, 0x2019, 0x0000, 0x2320,
+	0x0078, 0x3d04, 0xa6b4, 0xb7ff, 0x7e5a, 0x2009, 0x0079, 0xd69c,
+	0x0040, 0x3d0c, 0x2009, 0x0078, 0x791a, 0x68c0, 0x705a, 0x2d00,
+	0x704e, 0x68c4, 0x2060, 0x71d4, 0x2001, 0x4e01, 0x2004, 0xd0c4,
+	0x00c0, 0x3d62, 0x70d8, 0xa02d, 0x0040, 0x3d3b, 0xd1bc, 0x0040,
+	0x3d55, 0x7a80, 0xa294, 0x0f00, 0x70dc, 0xa206, 0x0040, 0x3d2c,
+	0x78e0, 0xa504, 0x00c0, 0x3d62, 0x70da, 0xc1bc, 0x71d6, 0x0078,
+	0x3d62, 0x2031, 0x0001, 0x852c, 0x0048, 0x3d3a, 0x8633, 0x8210,
+	0x0078, 0x3d33, 0x007c, 0x7de0, 0xa594, 0xff00, 0x0040, 0x3d48,
+	0x2011, 0x0008, 0x852f, 0x1078, 0x3d31, 0x8637, 0x0078, 0x3d4a,
+	0x1078, 0x3d31, 0x8217, 0x7880, 0xa084, 0x0f00, 0xa206, 0x0040,
+	0x3d62, 0x72de, 0x76da, 0x0078, 0x3d62, 0x7a80, 0xa294, 0x0f00,
+	0x70dc, 0xa236, 0x0040, 0x3d52, 0x78e0, 0xa534, 0x0040, 0x3d52,
+	0xc1bd, 0x71d6, 0xd1b4, 0x00c0, 0x29c1, 0x2300, 0xa405, 0x0040,
+	0x29c1, 0x70a4, 0xa086, 0x0001, 0x00c0, 0x2a0b, 0x007c, 0x6020,
+	0xa005, 0x0040, 0x3d7d, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008,
+	0x600a, 0x700f, 0x0100, 0x702c, 0x6026, 0x007c, 0xa006, 0x1078,
+	0x4586, 0x7000, 0xa086, 0x0002, 0x0040, 0x3d8b, 0x7064, 0xa086,
+	0x0005, 0x00c0, 0x3d95, 0x682b, 0x0000, 0x6817, 0x0000, 0x681b,
+	0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084, 0x000f,
+	0x0079, 0x3d9a, 0x29c5, 0x3daa, 0x3da4, 0x3dcc, 0x3db4, 0x29c5,
+	0x3da2, 0x3da2, 0x1078, 0x296b, 0x1078, 0x3dd7, 0x1078, 0x3dd0,
+	0x0078, 0x3db0, 0x1078, 0x3dd7, 0x705c, 0x2060, 0x6800, 0x6002,
+	0x1078, 0x202c, 0x0078, 0x29c5, 0x7064, 0x7067, 0x0000, 0x7083,
+	0x0000, 0x0079, 0x3dbb, 0x3dc8, 0x3dc8, 0x3dc3, 0x3dc3, 0x3dc3,
+	0x3dc8, 0x3dc3, 0x3dc8, 0x77d4, 0xc7dd, 0x77d6, 0x0079, 0x2f35,
+	0x7067, 0x0000, 0x0078, 0x29c5, 0x681b, 0x0000, 0x0078, 0x36c8,
+	0x6800, 0xa005, 0x00c0, 0x3dd5, 0x6002, 0x6006, 0x007c, 0x6410,
+	0x84ff, 0x0040, 0x3de9, 0x2009, 0x4e02, 0x2104, 0x8001, 0x200a,
+	0x8421, 0x6412, 0x00c0, 0x3de9, 0x2021, 0x4e04, 0x2404, 0xc0a5,
+	0x2022, 0x6008, 0xc0a4, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040,
+	0x3df3, 0x8001, 0x601a, 0x007c, 0x1078, 0x4383, 0x681b, 0x0018,
+	0x0078, 0x3e34, 0x1078, 0x4383, 0x681b, 0x0019, 0x0078, 0x3e34,
+	0x1078, 0x4383, 0x681b, 0x001a, 0x0078, 0x3e34, 0x1078, 0x4383,
+	0x681b, 0x0003, 0x0078, 0x3e34, 0x7774, 0x1078, 0x41fe, 0x7178,
+	0xa18c, 0x00ff, 0x3210, 0xa294, 0x0300, 0x0040, 0x3e1b, 0xa1e8,
+	0x93c0, 0x0078, 0x3e1d, 0xa1e8, 0x94d0, 0x2d04, 0x2d08, 0x2068,
+	0xa005, 0x00c0, 0x3e26, 0x707e, 0x0078, 0x29c5, 0x6814, 0x7274,
+	0xa206, 0x0040, 0x3e2e, 0x6800, 0x0078, 0x3e1e, 0x6800, 0x200a,
+	0x681b, 0x0005, 0x707f, 0x0000, 0x1078, 0x3dd7, 0x6820, 0xd084,
+	0x00c0, 0x3e3c, 0x1078, 0x3dd0, 0x1078, 0x3ded, 0x681f, 0x0000,
+	0x6823, 0x0020, 0x1078, 0x202c, 0x0078, 0x29c5, 0xa282, 0x0003,
+	0x00c0, 0x40b7, 0x7da8, 0xa5ac, 0x00ff, 0x7e5a, 0x7ea8, 0xa6b4,
+	0x00ff, 0x6920, 0xc1bd, 0x6922, 0xd1c4, 0x0040, 0x3ea1, 0xc1c4,
+	0x6922, 0xa6b4, 0x00ff, 0x0040, 0x3e8e, 0xa682, 0x000c, 0x0048,
+	0x3e65, 0x0040, 0x3e65, 0x2031, 0x000c, 0x2500, 0xa086, 0x000a,
+	0x0040, 0x3e6c, 0x852b, 0x852b, 0x1078, 0x4190, 0x0040, 0x3e74,
+	0x1078, 0x3f6f, 0x0078, 0x3e97, 0x1078, 0x414b, 0x0c7e, 0x2960,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3fa5, 0x0c7f, 0x6920,
+	0xc1c5, 0x6922, 0x7e58, 0xc695, 0x7e5a, 0xd6d4, 0x00c0, 0x3e8b,
+	0x781b, 0x0064, 0x007c, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x2960,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x3fa5, 0x0c7f, 0x7e58,
+	0xd6d4, 0x00c0, 0x3e9e, 0x781b, 0x0067, 0x007c, 0x781b, 0x0079,
+	0x007c, 0x0c7e, 0x7058, 0x2060, 0x6100, 0xd1e4, 0x0040, 0x3eea,
+	0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x3eb4,
+	0x0040, 0x3eb4, 0x2011, 0x000c, 0x2600, 0xa202, 0x00c8, 0x3eb9,
+	0x2230, 0x6208, 0xa294, 0x00ff, 0x2001, 0x4e05, 0x2004, 0xd0e4,
+	0x00c0, 0x3ece, 0x78ec, 0xd0e4, 0x0040, 0x3ece, 0xa282, 0x000a,
+	0x00c8, 0x3ed4, 0x2011, 0x000a, 0x0078, 0x3ed4, 0xa282, 0x000c,
+	0x00c8, 0x3ed4, 0x2011, 0x000c, 0x2200, 0xa502, 0x00c8, 0x3ed9,
+	0x2228, 0x1078, 0x414f, 0x2500, 0xa086, 0x000a, 0x0040, 0x3ee2,
+	0x852b, 0x852b, 0x1078, 0x4190, 0x0040, 0x3eea, 0x1078, 0x3f6f,
+	0x0078, 0x3eee, 0x1078, 0x414b, 0x1078, 0x3fa5, 0x7858, 0xc095,
+	0x785a, 0x0c7f, 0x781b, 0x0078, 0x007c, 0x0c7e, 0x2960, 0x6000,
+	0xd0e4, 0x00c0, 0x3f0b, 0xa084, 0x0040, 0x00c0, 0x3f05, 0x6104,
+	0xa18c, 0xfff5, 0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019,
+	0x0000, 0x0078, 0x3f36, 0x68a0, 0xd0cc, 0x00c0, 0x3f05, 0x6208,
+	0xa294, 0x00ff, 0x2001, 0x4e05, 0x2004, 0xd0e4, 0x00c0, 0x3f24,
+	0x78ec, 0xd0e4, 0x0040, 0x3f24, 0xa282, 0x000b, 0x00c8, 0x3f24,
+	0x2011, 0x000a, 0x0078, 0x3f2a, 0xa282, 0x000c, 0x00c8, 0x3f2a,
+	0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c,
+	0x0048, 0x3f36, 0x0040, 0x3f36, 0x2019, 0x000c, 0x78ab, 0x0001,
+	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005,
+	0x6820, 0xc0c5, 0x6822, 0x70d4, 0xd0b4, 0x0040, 0x3f52, 0xc0b4,
+	0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018,
+	0x8001, 0x601a, 0x0c7f, 0x007c, 0x0c7e, 0x2960, 0x6104, 0xa18c,
+	0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3f60,
+	0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa,
+	0xa8c0, 0x0005, 0x6820, 0xc0c5, 0x6822, 0x0c7f, 0x007c, 0x0c7e,
+	0x7158, 0x2160, 0x2018, 0xa08c, 0x0020, 0x0040, 0x3f78, 0xc0ac,
+	0x2008, 0xa084, 0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae,
+	0x6612, 0x78a4, 0xa084, 0xfff0, 0xa18c, 0x000f, 0xa105, 0xc0f4,
+	0xa39c, 0x0020, 0x0040, 0x3f8e, 0xa085, 0x4000, 0xc0fc, 0xd0b4,
+	0x00c0, 0x3f93, 0xc0fd, 0x78a6, 0x6016, 0x788a, 0xa6b4, 0x000f,
+	0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605, 0x600e, 0x6004,
+	0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060,
+	0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884,
+	0xa084, 0xfff0, 0x7886, 0x600c, 0xa084, 0x00ff, 0x600e, 0x0c7f,
+	0x007c, 0xa282, 0x0002, 0x00c0, 0x40b7, 0x7aa8, 0x6920, 0xc1bd,
+	0x6922, 0xd1cc, 0x0040, 0x3ff4, 0xc1cc, 0x6922, 0xa294, 0x00ff,
+	0xa282, 0x0002, 0x00c8, 0x40b7, 0x1078, 0x4044, 0x1078, 0x3fa5,
+	0xa980, 0x0001, 0x200c, 0x1078, 0x41fa, 0x1078, 0x3ef5, 0x88ff,
+	0x0040, 0x3fea, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58, 0xc695,
+	0x7e5a, 0xd6d4, 0x00c0, 0x3fe7, 0x781b, 0x0064, 0x007c, 0x781b,
+	0x0078, 0x007c, 0x7e58, 0xd6d4, 0x00c0, 0x3ff1, 0x781b, 0x0067,
+	0x007c, 0x781b, 0x0079, 0x007c, 0xa282, 0x0002, 0x00c8, 0x3ffc,
+	0xa284, 0x0001, 0x0040, 0x4005, 0x7158, 0xa188, 0x0000, 0x210c,
+	0xd1ec, 0x00c0, 0x4005, 0x2011, 0x0000, 0x1078, 0x412c, 0x1078,
+	0x4044, 0x1078, 0x3fa5, 0x7858, 0xc095, 0x785a, 0x781b, 0x0078,
+	0x007c, 0x0c7e, 0x027e, 0x2960, 0x6000, 0x2011, 0x0001, 0xd0ec,
+	0x00c0, 0x4025, 0xa084, 0x0080, 0x00c0, 0x4023, 0xc1a4, 0x6106,
+	0xa006, 0x0078, 0x4041, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab,
+	0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x70d4, 0xd0b4,
+	0x0040, 0x403d, 0xc0b4, 0x70d6, 0x70b8, 0xa065, 0x6008, 0xa084,
+	0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x6820, 0xa085, 0x0200,
+	0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7058, 0x2060, 0x82ff,
+	0x0040, 0x404c, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a,
+	0x78a4, 0xa084, 0xffbf, 0xa205, 0xc0fc, 0xd0b4, 0x00c0, 0x4059,
+	0xc0fd, 0x78a6, 0x6016, 0x788a, 0x6004, 0xc0a4, 0x6006, 0x0c7f,
+	0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x406a, 0x007f,
+	0x0078, 0x406d, 0x007f, 0x0078, 0x40b4, 0xd6ac, 0x0040, 0x40b4,
+	0x7888, 0xa084, 0x0040, 0x0040, 0x40b4, 0x7bb8, 0xa384, 0x003f,
+	0x831b, 0x00c8, 0x407c, 0x8000, 0xa005, 0x0040, 0x4091, 0x831b,
+	0x00c8, 0x4085, 0x8001, 0x0040, 0x40b1, 0xd6f4, 0x0040, 0x4091,
+	0x78b8, 0x801b, 0x00c8, 0x408d, 0x8000, 0xa084, 0x003f, 0x00c0,
+	0x40b1, 0xc6f4, 0x7e5a, 0x79d8, 0x7adc, 0x2001, 0x0001, 0xa108,
+	0x00c8, 0x409c, 0xa291, 0x0000, 0x79d2, 0x79da, 0x7ad6, 0x7ade,
+	0x1078, 0x49c3, 0x781b, 0x0076, 0xb284, 0x0300, 0x0040, 0x40ac,
+	0x2001, 0x0000, 0x0078, 0x40ae, 0x2001, 0x0001, 0x1078, 0x484b,
+	0x007c, 0x781b, 0x0076, 0x007c, 0x781b, 0x0079, 0x007c, 0x1078,
+	0x40df, 0x781b, 0x0078, 0x007c, 0x1078, 0x40c8, 0x781b, 0x0078,
+	0x007c, 0x6827, 0x0002, 0x1078, 0x40d0, 0x781b, 0x0078, 0x007c,
+	0x2001, 0x0005, 0x0078, 0x40e1, 0x2001, 0x000c, 0x0078, 0x40e1,
+	0x6820, 0xc0d5, 0x6822, 0x2001, 0x0006, 0x0078, 0x40e1, 0x2001,
+	0x000d, 0x0078, 0x40e1, 0x2001, 0x0009, 0x0078, 0x40e1, 0x2001,
+	0x0007, 0x789b, 0x007e, 0x78aa, 0xc69d, 0x7e5a, 0x70d4, 0xd0b4,
+	0x0040, 0x40f7, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008,
+	0xa084, 0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c,
+	0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0x017e,
+	0xb28c, 0x0300, 0x0040, 0x4108, 0xa0e0, 0x52c0, 0x0078, 0x410a,
+	0xa0e0, 0x5340, 0x017f, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184,
+	0x000f, 0x0040, 0x411a, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004,
+	0xc09d, 0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040,
+	0x0040, 0x412a, 0xa184, 0xffbf, 0xc0fd, 0x78a6, 0x6016, 0x6004,
+	0xc0a5, 0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001,
+	0x78ab, 0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab,
+	0x0004, 0x70d4, 0xd0b4, 0x0040, 0x414a, 0xc0b4, 0x70d6, 0x0c7e,
+	0x70b8, 0xa065, 0x6008, 0xa084, 0xfbef, 0x600a, 0x6018, 0x8001,
+	0x601a, 0x0c7f, 0x007c, 0x2031, 0x0000, 0x2029, 0x0032, 0x789b,
+	0x0010, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa,
+	0x7eaa, 0x789b, 0x0060, 0x78ab, 0x0005, 0x70d4, 0xd0b4, 0x0040,
+	0x416e, 0xc0b4, 0x70d6, 0x0c7e, 0x70b8, 0xa065, 0x6008, 0xa084,
+	0xfbef, 0x600a, 0x6018, 0x8001, 0x601a, 0x0c7f, 0x007c, 0x157e,
+	0x8007, 0xa084, 0x00ff, 0x8003, 0x8003, 0xa080, 0x0020, 0x789a,
+	0x79a4, 0xa18c, 0xfff0, 0x2021, 0x41e3, 0x2019, 0x0011, 0x20a9,
+	0x000e, 0x2011, 0x0032, 0x2404, 0xa084, 0xfff0, 0xa106, 0x0040,
+	0x418e, 0x8420, 0x2300, 0xa210, 0x00f0, 0x4183, 0x157f, 0x007c,
+	0x157e, 0x2001, 0x4e05, 0x2004, 0xd0e4, 0x00c0, 0x41c1, 0x2021,
+	0x41f1, 0x20a9, 0x0009, 0x2011, 0x0028, 0xa582, 0x0019, 0x0040,
+	0x41d7, 0x0048, 0x41d7, 0x8420, 0x95a9, 0x2011, 0x0032, 0xa582,
+	0x0032, 0x0040, 0x41d7, 0x0048, 0x41d7, 0x8420, 0x95a9, 0x2019,
+	0x000a, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x41d7, 0x0048,
+	0x41d7, 0x8420, 0x2300, 0xa210, 0x00f0, 0x41b3, 0x157f, 0x0078,
+	0x41d5, 0x2021, 0x41e3, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011,
+	0x0032, 0x2200, 0xa502, 0x0040, 0x41d7, 0x0048, 0x41d7, 0x8420,
+	0x2300, 0xa210, 0x00f0, 0x41c9, 0x157f, 0xa006, 0x007c, 0x157f,
+	0xa582, 0x0064, 0x00c8, 0x41e0, 0x7808, 0xa085, 0x0070, 0x780a,
+	0x2404, 0xa005, 0x007c, 0x1209, 0x3002, 0x3202, 0x4203, 0x4403,
+	0x5404, 0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07,
+	0x0e07, 0x10e1, 0x330a, 0x5805, 0x5a05, 0x6a06, 0x6c06, 0x7c07,
+	0x7e07, 0x0e00, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00,
+	0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105,
+	0xd7fc, 0x0040, 0x420f, 0xa0e0, 0x73c0, 0x0078, 0x4211, 0xa0e0,
+	0x53c0, 0x007c, 0x0e7e, 0x0f7e, 0xd084, 0x0040, 0x421f, 0x2079,
+	0x0100, 0x2009, 0x4e80, 0x2071, 0x4e80, 0x0078, 0x422f, 0x2009,
+	0x4e40, 0x2071, 0x4e40, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x0040,
+	0x422d, 0x2079, 0x0100, 0x0078, 0x422f, 0x2079, 0x0200, 0x2091,
+	0x8000, 0x2104, 0xa084, 0x000f, 0x0079, 0x4236, 0x4240, 0x4240,
+	0x4240, 0x4240, 0x4240, 0x4240, 0x423e, 0x423e, 0x1078, 0x296b,
+	0x69b4, 0xc1f5, 0xa18c, 0xff9f, 0x69b6, 0xa005, 0x0040, 0x428f,
+	0x7858, 0xa084, 0xff9f, 0xa085, 0x6000, 0x785a, 0x7828, 0xa086,
+	0x1814, 0x00c0, 0x428f, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004,
+	0x00c0, 0x4255, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0,
+	0x425c, 0x7830, 0xd0bc, 0x00c0, 0x428f, 0x007e, 0x2001, 0x4e04,
+	0x2004, 0xd0ec, 0x007f, 0x0040, 0x4271, 0xb284, 0x0300, 0x0078,
+	0x4273, 0xb284, 0x0400, 0x0040, 0x4279, 0x0018, 0x428f, 0x0078,
+	0x427b, 0x0028, 0x428f, 0x79e4, 0xa184, 0x0030, 0x0040, 0x428f,
+	0x78ec, 0xa084, 0x0003, 0x0040, 0x428f, 0x681c, 0xd0ac, 0x00c0,
+	0x428d, 0x1078, 0x4319, 0x0078, 0x428f, 0x781b, 0x00f9, 0x0f7f,
+	0x0e7f, 0x007c, 0x0c7e, 0x2001, 0x4e01, 0x2004, 0xd0ac, 0x00c0,
+	0x430b, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003,
+	0xb28c, 0x0300, 0x0040, 0x42a8, 0xa0e0, 0x52c0, 0x0078, 0x42aa,
+	0xa0e0, 0x5340, 0x6004, 0xa084, 0x000a, 0x00c0, 0x430b, 0x6108,
+	0xa194, 0xff00, 0x0040, 0x430b, 0xa18c, 0x00ff, 0x2001, 0x000a,
+	0xa106, 0x0040, 0x42d6, 0x2001, 0x000c, 0xa106, 0x0040, 0x42da,
+	0x2001, 0x0012, 0xa106, 0x0040, 0x42de, 0x2001, 0x0014, 0xa106,
+	0x0040, 0x42e2, 0x2001, 0x0019, 0xa106, 0x0040, 0x42e6, 0x2001,
+	0x0032, 0xa106, 0x0040, 0x42ea, 0x0078, 0x42ee, 0x2009, 0x000c,
+	0x0078, 0x42f0, 0x2009, 0x0012, 0x0078, 0x42f0, 0x2009, 0x0014,
+	0x0078, 0x42f0, 0x2009, 0x0019, 0x0078, 0x42f0, 0x2009, 0x0020,
+	0x0078, 0x42f0, 0x2009, 0x003f, 0x0078, 0x42f0, 0x2011, 0x0000,
+	0x2100, 0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x2061,
+	0x4e00, 0x6004, 0xd0bc, 0x0040, 0x430b, 0x6814, 0xd0fc, 0x00c0,
+	0x4306, 0x60ea, 0x2061, 0x4e40, 0x0078, 0x4309, 0x60ee, 0x2061,
+	0x4e80, 0x601f, 0x800f, 0x0c7f, 0x007c, 0x781b, 0x0079, 0x007c,
+	0x781b, 0x0078, 0x007c, 0x781b, 0x0067, 0x007c, 0x781b, 0x0064,
+	0x007c, 0x2009, 0x4e19, 0x210c, 0xa186, 0x0000, 0x0040, 0x432b,
+	0xa186, 0x0001, 0x0040, 0x432e, 0x701f, 0x000b, 0x7067, 0x0001,
+	0x781b, 0x0047, 0x007c, 0x781b, 0x00f0, 0x007c, 0x701f, 0x000a,
+	0x007c, 0x2009, 0x4e19, 0x210c, 0xa186, 0x0000, 0x0040, 0x4346,
+	0xa186, 0x0001, 0x0040, 0x4343, 0x701f, 0x000b, 0x7067, 0x0001,
+	0x781b, 0x0047, 0x007c, 0x701f, 0x000a, 0x007c, 0x781b, 0x00ef,
+	0x007c, 0x781b, 0x00f9, 0x007c, 0x781b, 0x00f8, 0x007c, 0x781b,
+	0x00c9, 0x007c, 0x781b, 0x00c8, 0x007c, 0x6818, 0xd0fc, 0x0040,
+	0x435b, 0x681b, 0x001d, 0x7067, 0x0001, 0x781b, 0x0047, 0x007c,
+	0x7830, 0xa084, 0x00c0, 0x00c0, 0x4382, 0x7808, 0xc08c, 0x780a,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x00c0,
+	0x437f, 0x2001, 0x4e05, 0x2004, 0xd0e4, 0x00c0, 0x437d, 0x7804,
+	0xa084, 0xff1f, 0xa085, 0x00e0, 0x7806, 0xa006, 0x007c, 0x7808,
+	0xc08d, 0x780a, 0x007c, 0x7808, 0xc08d, 0x780a, 0x007c, 0x7830,
+	0xa084, 0x0040, 0x00c0, 0x4387, 0x2001, 0x4e04, 0x2004, 0xd0ec,
+	0x0040, 0x4396, 0xb284, 0x0300, 0x0078, 0x4398, 0xb284, 0x0400,
+	0x0040, 0x439e, 0x0098, 0x43a2, 0x0078, 0x43a0, 0x00a8, 0x43a2,
+	0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005,
+	0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040, 0x43c5, 0x007e,
+	0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f, 0x0040, 0x43bb, 0xb284,
+	0x0300, 0x0078, 0x43bd, 0xb284, 0x0400, 0x0040, 0x43c3, 0x0098,
+	0x43bf, 0x0078, 0x43c5, 0x00a8, 0x43c3, 0x78ac, 0x007e, 0x7808,
+	0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0xa784, 0x0001, 0x00c0,
+	0x3770, 0xa784, 0x0070, 0x0040, 0x43dd, 0x0c7e, 0x2d60, 0x2f68,
+	0x1078, 0x28df, 0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040,
+	0x43ea, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x3770,
+	0x0078, 0x430d, 0xa784, 0x0004, 0x0040, 0x4419, 0x78b8, 0xa084,
+	0x4001, 0x0040, 0x4419, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x3770, 0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0,
+	0x4419, 0x78c0, 0xa685, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00f9,
+	0x007c, 0x784b, 0x0008, 0x6818, 0xd0fc, 0x0040, 0x4416, 0x681b,
+	0x0015, 0xd6f4, 0x0040, 0x4416, 0x681b, 0x0007, 0x1078, 0x4319,
+	0x007c, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681e, 0x682f,
+	0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x3066, 0x007e, 0x2001, 0x4e04, 0x2004, 0xd0ec, 0x007f,
+	0x0040, 0x4436, 0xb284, 0x0300, 0x0078, 0x4438, 0xb284, 0x0400,
+	0x0040, 0x443e, 0x0018, 0x29c1, 0x0078, 0x4440, 0x0028, 0x29c1,
+	0x0078, 0x40bc, 0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xd3fc, 0x0040, 0x4450, 0xa080, 0x5340, 0x0078, 0x4452,
+	0xa080, 0x52c0, 0x2060, 0x2048, 0x705a, 0x2a60, 0x007c, 0x0020,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000,
+	0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9848, 0x0014, 0x0014,
+	0x9914, 0x98fd, 0x0014, 0x0014, 0x0080, 0x00ff, 0x0100, 0x0402,
+	0x2008, 0xf880, 0x0018, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014,
+	0x2500, 0x0013, 0x2500, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
+	0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010, 0x0010,
+	0x0010, 0xa200, 0x3806, 0x7102, 0x805f, 0x9481, 0x8839, 0x20c4,
+	0x0864, 0xa856, 0x3008, 0x28c1, 0x9d1b, 0xa201, 0x300c, 0x2847,
+	0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a, 0xa808, 0x28e2,
+	0x9ccb, 0xa8f3, 0x0864, 0xa844, 0x300c, 0xa801, 0x3008, 0x28e1,
+	0x9ccb, 0x2021, 0xa81d, 0xa205, 0x870c, 0xd8de, 0x64a0, 0x6de0,
+	0x6fc0, 0x63a4, 0x6c80, 0x0212, 0xa205, 0x883d, 0x7942, 0x8020,
+	0xa4a1, 0x882b, 0x1814, 0x883b, 0x80df, 0x94a1, 0x7027, 0x85f2,
+	0xa737, 0xa532, 0xf003, 0x8576, 0x8677, 0xa816, 0x883e, 0xa814,
+	0x2001, 0xa812, 0xa204, 0x64c0, 0x6de0, 0x67a0, 0x6fc0, 0x7942,
+	0x8020, 0xa4a1, 0x1814, 0x80df, 0x94a1, 0x883b, 0x7023, 0x8576,
+	0x8677, 0xa802, 0x7861, 0x883e, 0x206b, 0x28c1, 0x9d1b, 0x2044,
+	0x2103, 0x20a2, 0x2081, 0xa8c3, 0xa207, 0x0904, 0xa20e, 0xa809,
+	0xa203, 0x8000, 0x85a4, 0x1872, 0x879a, 0x883c, 0x1fe2, 0xf601,
+	0xa208, 0x856e, 0x866f, 0x7161, 0x0014, 0x0704, 0x3008, 0x9ccb,
+	0x0014, 0xa202, 0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf844,
+	0x856e, 0x883f, 0x08e6, 0xa8f5, 0xf861, 0xa8ea, 0xf801, 0x0014,
+	0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2, 0x1de2, 0x0014,
+	0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0, 0x1fe6, 0x0014,
+	0x3008, 0x8000, 0x284a, 0x1011, 0xa8fc, 0x3008, 0x9d33, 0x8000,
+	0xa000, 0x2802, 0x1011, 0xa8fd, 0x9d39, 0xa8bd, 0x3008, 0x9d33,
+	0x283b, 0x1011, 0xa8fd, 0xa209, 0x7102, 0x805f, 0x9481, 0x0017,
+	0x300c, 0xa209, 0x8000, 0x85a4, 0x1de2, 0xa209, 0xdac1, 0x0014,
+	0x0210, 0xa801, 0x0014, 0x26e0, 0x873a, 0xfaa3, 0x19f2, 0x26e0,
+	0x18f2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x3806, 0x0210, 0x9d25,
+	0x0704, 0xa206, 0x6865, 0x817e, 0x842a, 0x1dc1, 0x8823, 0x0016,
+	0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a, 0xf021,
+	0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d4, 0x8822,
+	0x0016, 0x7944, 0x8421, 0xa020, 0xa532, 0x84a1, 0x0016, 0x7944,
+	0x8421, 0xa0df, 0x9532, 0x84a1, 0x0016, 0x0000, 0x127e, 0x70d4,
+	0xa084, 0x4600, 0x8004, 0x2090, 0x7204, 0x7008, 0xc09c, 0xa205,
+	0x00c0, 0x45a2, 0x720c, 0x82ff, 0x0040, 0x459d, 0x8aff, 0x00c0,
+	0x45a2, 0x7200, 0xd284, 0x00c0, 0x45a2, 0x7003, 0x0008, 0x127f,
+	0x2000, 0x007c, 0x7000, 0xa084, 0x0003, 0x7002, 0xc69c, 0xd084,
+	0x0040, 0x45e5, 0x7108, 0x0005, 0x7008, 0xa106, 0x00c0, 0x45aa,
+	0xa184, 0x0003, 0x0040, 0x4616, 0xa184, 0x01e0, 0x00c0, 0x4616,
+	0xd1f4, 0x00c0, 0x45aa, 0xa184, 0x3000, 0xa086, 0x1000, 0x0040,
+	0x45aa, 0x2011, 0x0180, 0x710c, 0x8211, 0x0040, 0x45cf, 0x7008,
+	0xd0f4, 0x00c0, 0x45aa, 0x700c, 0xa106, 0x0040, 0x45c4, 0x7007,
+	0x0012, 0x7108, 0x0005, 0x7008, 0xa106, 0x00c0, 0x45d1, 0xa184,
+	0x0003, 0x0040, 0x4616, 0xd194, 0x0040, 0x45d1, 0xd1f4, 0x0040,
+	0x4616, 0x7007, 0x0002, 0x0078, 0x45aa, 0x7108, 0xd1fc, 0x0040,
+	0x45f0, 0x1078, 0x4769, 0x8aff, 0x0040, 0x458c, 0x0078, 0x45e5,
+	0x700c, 0xa08c, 0x03ff, 0x0040, 0x461b, 0x7004, 0xd084, 0x0040,
+	0x460d, 0x7014, 0xa005, 0x00c0, 0x4609, 0x7010, 0x7310, 0xa306,
+	0x00c0, 0x45fd, 0x2300, 0xa005, 0x0040, 0x460d, 0xa102, 0x00c8,
+	0x45e5, 0x7007, 0x0010, 0x0078, 0x4616, 0x8aff, 0x0040, 0x461b,
+	0x1078, 0x4970, 0x00c0, 0x4610, 0x0040, 0x45e5, 0x1078, 0x46b4,
+	0x127f, 0x2000, 0x007c, 0x7204, 0x7108, 0xc19c, 0x8103, 0x00c8,
+	0x462a, 0x7007, 0x0002, 0x0078, 0x461b, 0x7003, 0x0008, 0x127f,
+	0x2000, 0x007c, 0xa205, 0x00c0, 0x4616, 0x7003, 0x0008, 0x127f,
+	0x2000, 0x007c, 0x6428, 0x84ff, 0x0040, 0x465e, 0x2c70, 0x7004,
+	0xa0bc, 0x000f, 0xa7b8, 0x466e, 0x273c, 0x87fb, 0x00c0, 0x464c,
+	0x0048, 0x4644, 0x1078, 0x296b, 0x609c, 0xa075, 0x0040, 0x465e,
+	0x0078, 0x4637, 0x2039, 0x4663, 0x2704, 0xae68, 0x6808, 0xa630,
+	0x680c, 0xa529, 0x8421, 0x0040, 0x465e, 0x8738, 0x2704, 0xa005,
+	0x00c0, 0x464d, 0x709c, 0xa075, 0x00c0, 0x4637, 0x007c, 0x0000,
+	0x0005, 0x0009, 0x000d, 0x0011, 0x0015, 0x0019, 0x001d, 0x0000,
+	0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0000, 0x4663,
+	0x4660, 0x0000, 0x0000, 0x8000, 0x0000, 0x4663, 0x0000, 0x466b,
+	0x4668, 0x0000, 0x0000, 0x0000, 0x0000, 0x466b, 0x0000, 0x4666,
+	0x4666, 0x0000, 0x0000, 0x8000, 0x0000, 0x4666, 0x0000, 0x466c,
+	0x466c, 0x0000, 0x0000, 0x0000, 0x0000, 0x466c, 0x2079, 0x4e00,
+	0x2071, 0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0001,
+	0x7810, 0xd0ec, 0x0040, 0x46a2, 0x2009, 0x0001, 0x2071, 0x0020,
+	0x0078, 0x46a6, 0x2009, 0x0002, 0x2071, 0x0050, 0x7007, 0x000a,
+	0x7007, 0x0002, 0x7003, 0x0000, 0x8109, 0x0040, 0x46b3, 0x2071,
+	0x0020, 0x0078, 0x46a6, 0x007c, 0x7004, 0x8004, 0x00c8, 0x473d,
+	0x7108, 0x7008, 0xa106, 0x00c0, 0x46b8, 0xa184, 0x01e0, 0x0040,
+	0x46c5, 0x1078, 0x47ac, 0x0078, 0x4765, 0x7007, 0x0012, 0x2019,
+	0x0000, 0x7108, 0x7008, 0xa106, 0x00c0, 0x46c9, 0xa184, 0x01e0,
+	0x0040, 0x46d6, 0x1078, 0x47ac, 0x0078, 0x4765, 0x7810, 0xd0ec,
+	0x0040, 0x46f0, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0003, 0x00c0,
+	0x46f4, 0xa184, 0x4000, 0x0040, 0x46f8, 0xa382, 0x0003, 0x00c8,
+	0x46f8, 0xa184, 0x0004, 0x0040, 0x46c9, 0x8318, 0x0078, 0x46c9,
+	0x7814, 0xd0ec, 0x00c0, 0x46f8, 0xa184, 0x4000, 0x00c0, 0x46c9,
+	0xa19c, 0x300c, 0xa386, 0x2004, 0x0040, 0x4715, 0xa386, 0x0008,
+	0x0040, 0x4720, 0x7004, 0xd084, 0x00c0, 0x4711, 0x7108, 0x7008,
+	0xa106, 0x00c0, 0x4706, 0xa184, 0x0003, 0x0040, 0x4711, 0x0078,
+	0x47ac, 0xa386, 0x200c, 0x00c0, 0x46c9, 0x7200, 0x8204, 0x0048,
+	0x4720, 0x730c, 0xa384, 0x03ff, 0x0040, 0x4720, 0x1078, 0x296b,
+	0x7108, 0x7008, 0xa106, 0x00c0, 0x4720, 0xa184, 0x01e0, 0x0040,
+	0x472d, 0x1078, 0x47ac, 0x0078, 0x4765, 0x7007, 0x0012, 0x7000,
+	0xd084, 0x00c0, 0x473d, 0x7310, 0x7014, 0xa305, 0x0040, 0x473d,
+	0x710c, 0xa184, 0x03ff, 0x00c0, 0x46b4, 0x7108, 0x7008, 0xa106,
+	0x00c0, 0x473d, 0xa184, 0x01e0, 0x0040, 0x474a, 0x1078, 0x47ac,
+	0x0078, 0x4765, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xd09c,
+	0x00c0, 0x474e, 0x7108, 0x7008, 0xa106, 0x00c0, 0x4752, 0xa184,
+	0x01e0, 0x0040, 0x475f, 0x1078, 0x47ac, 0x0078, 0x4765, 0x7007,
+	0x0012, 0x7108, 0x8103, 0x0048, 0x4752, 0x7003, 0x0008, 0x007c,
+	0x7108, 0xa184, 0x01e0, 0x00c0, 0x47ac, 0x7108, 0xa184, 0x01e0,
+	0x00c0, 0x47ac, 0xa184, 0x0007, 0x0079, 0x4776, 0x4780, 0x4790,
+	0x477e, 0x4790, 0x477e, 0x47ee, 0x477e, 0x47ec, 0x1078, 0x296b,
+	0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x8aff, 0x00c0, 0x478b,
+	0x2049, 0x0000, 0x007c, 0x1078, 0x4970, 0x00c0, 0x478b, 0x007c,
+	0x7004, 0xa084, 0x0010, 0xc08d, 0x7006, 0x7004, 0xd084, 0x00c0,
+	0x47a4, 0x7108, 0x7008, 0xa106, 0x00c0, 0x4799, 0xa184, 0x0003,
+	0x0040, 0x47a4, 0x0078, 0x47ac, 0x8aff, 0x0040, 0x47ab, 0x1078,
+	0x4970, 0x00c0, 0x47a7, 0x007c, 0x7007, 0x0012, 0x7108, 0x00e0,
+	0x47af, 0x2091, 0x6000, 0x00e0, 0x47b3, 0x2091, 0x6000, 0x7007,
+	0x0012, 0x7007, 0x0008, 0x7004, 0xd09c, 0x00c0, 0x47bb, 0x7007,
+	0x0012, 0x7108, 0xd1fc, 0x00c0, 0x47bf, 0x7003, 0x0000, 0x7000,
+	0xa005, 0x00c0, 0x47d3, 0x7004, 0xa005, 0x00c0, 0x47d3, 0x700c,
+	0xa005, 0x0040, 0x47d5, 0x0078, 0x47b7, 0x2049, 0x0000, 0xb284,
+	0x0100, 0x0040, 0x47df, 0x2001, 0x0000, 0x0078, 0x47e1, 0x2001,
+	0x0001, 0x1078, 0x4212, 0x681b, 0x0002, 0x2051, 0x0000, 0x007c,
+	0x1078, 0x296b, 0x1078, 0x296b, 0x1078, 0x4836, 0x7210, 0x7114,
+	0x700c, 0xa09c, 0x03ff, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000,
+	0x1078, 0x4836, 0x2704, 0x2c58, 0xac60, 0x6308, 0x2200, 0xa322,
+	0x630c, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x4811, 0x00c8,
+	0x4811, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078,
+	0x47f8, 0x2b60, 0x8a07, 0x007e, 0x6004, 0xa084, 0x0008, 0x0040,
+	0x481d, 0xa7ba, 0x4668, 0x0078, 0x481f, 0xa7ba, 0x4660, 0x007f,
+	0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92, 0x6b8e, 0x7108, 0x7008,
+	0xa106, 0x00c0, 0x4826, 0xa184, 0x01e0, 0x0040, 0x4831, 0x1078,
+	0x47ac, 0x7007, 0x0012, 0x1078, 0x46b4, 0x007c, 0x8a50, 0x8739,
+	0x2704, 0xa004, 0x00c0, 0x484a, 0x6000, 0xa064, 0x00c0, 0x4841,
+	0x2d60, 0x6004, 0xa084, 0x000f, 0xa080, 0x467e, 0x203c, 0x87fb,
+	0x1040, 0x296b, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, 0x4600,
+	0x8004, 0x2090, 0x0d7f, 0x6884, 0x2060, 0x6888, 0x6b8c, 0x6c90,
+	0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0x007e, 0x6804, 0xa084,
+	0x0008, 0x007f, 0x0040, 0x4868, 0xa0b8, 0x4668, 0x0078, 0x486a,
+	0xa0b8, 0x4660, 0xb284, 0x0100, 0x0040, 0x4871, 0x7e20, 0x0078,
+	0x4872, 0x7e24, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0040, 0x4879,
+	0xc685, 0x2400, 0xa305, 0x0040, 0x48a3, 0x2c58, 0x2704, 0x6104,
+	0xac60, 0x6000, 0xa400, 0x701a, 0x6004, 0xa301, 0x701e, 0xa184,
+	0x0008, 0x0040, 0x4893, 0x6010, 0xa081, 0x0000, 0x7022, 0x6014,
+	0xa081, 0x0000, 0x7026, 0x6208, 0x2400, 0xa202, 0x7012, 0x620c,
+	0x2300, 0xa203, 0x7016, 0x7602, 0x7007, 0x0001, 0x2b60, 0x1078,
+	0x499b, 0x0078, 0x48a5, 0x1078, 0x4970, 0x00c0, 0x48a3, 0x127f,
+	0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004,
+	0x2090, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xd094, 0x00c0, 0x48b4,
+	0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e, 0x70d4,
+	0xa084, 0x4600, 0x8004, 0x007e, 0x2090, 0x007f, 0x0d7f, 0x7e20,
+	0xb284, 0x0100, 0x00c0, 0x48cd, 0x7e24, 0xa6b5, 0x000c, 0x681c,
+	0xd0ac, 0x00c0, 0x48d8, 0xc685, 0x7003, 0x0000, 0x7007, 0x0004,
+	0x6828, 0x2050, 0x2d60, 0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x466e,
+	0x273c, 0x87fb, 0x00c0, 0x48ee, 0x0048, 0x48e8, 0x1078, 0x296b,
+	0x689c, 0xa065, 0x0040, 0x48f2, 0x0078, 0x48db, 0x1078, 0x4970,
+	0x00c0, 0x48ee, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e,
+	0x0d7e, 0x70d4, 0xa084, 0x4600, 0x8004, 0x007e, 0x2090, 0x007f,
+	0x7e20, 0xb284, 0x0100, 0x00c0, 0x4906, 0x7e24, 0x0d7f, 0x037f,
+	0x047f, 0xa6b5, 0x000c, 0x681c, 0xd0b4, 0x0040, 0x4914, 0xc685,
+	0x7003, 0x0000, 0x7007, 0x0004, 0x2049, 0x48f5, 0x6828, 0xa055,
+	0x0d7e, 0x0040, 0x496c, 0x2d70, 0x2e60, 0x7004, 0xa0bc, 0x000f,
+	0xa7b8, 0x466e, 0x273c, 0x87fb, 0x00c0, 0x4931, 0x0048, 0x492a,
+	0x1078, 0x296b, 0x709c, 0xa075, 0x2060, 0x0040, 0x496c, 0x0078,
+	0x491d, 0x2704, 0xae68, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0048,
+	0x494a, 0x8a51, 0x00c0, 0x493e, 0x1078, 0x296b, 0x8738, 0x2704,
+	0xa005, 0x00c0, 0x4932, 0x709c, 0xa075, 0x2060, 0x0040, 0x496c,
+	0x0078, 0x491d, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x6908,
+	0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x00c8, 0x4959, 0x1078,
+	0x296b, 0xb284, 0x0100, 0x0040, 0x4967, 0x2001, 0x4e04, 0x2004,
+	0xd0ec, 0x00c0, 0x4967, 0x2071, 0x0050, 0x0078, 0x4969, 0x2071,
+	0x0020, 0x0d7f, 0x0078, 0x4879, 0x0d7f, 0x127f, 0x2000, 0x007c,
+	0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, 0x4979, 0xa006,
+	0x007c, 0xa084, 0x0003, 0xa086, 0x0003, 0x00c0, 0x4980, 0x007c,
+	0x2704, 0xac78, 0x7800, 0x701a, 0x7804, 0x701e, 0x7808, 0x7012,
+	0x780c, 0x7016, 0x6004, 0xa084, 0x0008, 0x0040, 0x4993, 0x7810,
+	0x7022, 0x7814, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xc085,
+	0x7006, 0x2079, 0x4e00, 0x8a51, 0x0040, 0x49bf, 0x8738, 0x2704,
+	0xa005, 0x00c0, 0x49b1, 0x609c, 0xa005, 0x0040, 0x49c0, 0x2060,
+	0x6004, 0xa084, 0x000f, 0xa080, 0x466e, 0x203c, 0x87fb, 0x1040,
+	0x296b, 0x7008, 0x007e, 0xa084, 0x01e0, 0x007f, 0x0040, 0x49bb,
+	0xa006, 0x0078, 0x49c0, 0xa084, 0x0003, 0xa086, 0x0003, 0x007c,
+	0x2051, 0x0000, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x70d4, 0xa084,
+	0x4600, 0x8004, 0x2090, 0x0d7f, 0x087f, 0x7108, 0xa184, 0x0003,
+	0x00c0, 0x49d8, 0x6828, 0xa005, 0x0040, 0x49e8, 0x0078, 0x45a2,
+	0x7108, 0xd1fc, 0x0040, 0x49e0, 0x1078, 0x4769, 0x0078, 0x49cd,
+	0x7007, 0x0010, 0x7108, 0xd1fc, 0x0040, 0x49e2, 0x1078, 0x4769,
+	0x7008, 0xa086, 0x0008, 0x00c0, 0x49cd, 0x7000, 0xa005, 0x00c0,
+	0x49cd, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f, 0x2000, 0x007c,
+	0x127e, 0x147e, 0x137e, 0x157e, 0x0c7e, 0x0d7e, 0x70d4, 0xa084,
+	0x4600, 0x8004, 0x2090, 0x0d7f, 0x2049, 0x49f8, 0xad80, 0x0011,
+	0x20a0, 0xb284, 0x0100, 0x0040, 0x4a1b, 0x2001, 0x4e04, 0x2004,
+	0xd0ec, 0x0040, 0x4a17, 0x2099, 0x0031, 0x0078, 0x4a1d, 0x2099,
+	0x0032, 0x0078, 0x4a1d, 0x2099, 0x0031, 0x700c, 0xa084, 0x03ff,
+	0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040,
+	0x4a2c, 0x8000, 0x80ac, 0x53a5, 0x700c, 0xa084, 0x03ff, 0x0040,
+	0x4a38, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x4a33,
+	0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f,
+	0x127f, 0x2000, 0x007c, 0x2091, 0x8000, 0x2091, 0x6000, 0x78ac,
+	0xa005, 0x00c0, 0x4a5a, 0x7974, 0x70d0, 0xa106, 0x00c0, 0x4a5a,
+	0x781c, 0xa005, 0x0040, 0x4a5a, 0x781f, 0x0000, 0x0068, 0x4a5a,
+	0x2091, 0x4080, 0x7830, 0x8001, 0x7832, 0x00c0, 0x4ae2, 0x7834,
+	0x7832, 0x7810, 0xd0ec, 0x00c0, 0x4adb, 0x2061, 0x73c0, 0x2069,
+	0x4e80, 0xc7fd, 0x68d0, 0xa005, 0x0040, 0x4a74, 0x8001, 0x68d2,
+	0x00c0, 0x4a74, 0x1078, 0x4cb0, 0x6800, 0xa084, 0x000f, 0x0040,
+	0x4a89, 0xa086, 0x0001, 0x0040, 0x4a89, 0x6844, 0xa00d, 0x0040,
+	0x4a89, 0x2104, 0xa005, 0x0040, 0x4a89, 0x8001, 0x200a, 0x0040,
+	0x4c23, 0x6814, 0xa005, 0x0040, 0x4aae, 0x8001, 0x6816, 0x00c0,
+	0x4aae, 0x68a7, 0x0001, 0x0f7e, 0xd7fc, 0x00c0, 0x4aa3, 0x7810,
+	0xd0ec, 0x0040, 0x4a9f, 0x2079, 0x0100, 0x0078, 0x4aa5, 0x2079,
+	0x0200, 0x0078, 0x4aa5, 0x2079, 0x0100, 0x1078, 0x4383, 0x0f7f,
+	0x6864, 0xa005, 0x0040, 0x4aae, 0x1078, 0x2628, 0x6880, 0xa005,
+	0x0040, 0x4abb, 0x8001, 0x6882, 0x00c0, 0x4abb, 0x6867, 0x0000,
+	0x68d4, 0xc0dd, 0x68d6, 0x68d4, 0xd0fc, 0x0040, 0x4ad8, 0xc0fc,
+	0x68d6, 0x20a9, 0x0200, 0x6034, 0xa005, 0x0040, 0x4ad4, 0x8001,
+	0x6036, 0x68d4, 0xc0fd, 0x68d6, 0x00c0, 0x4ad4, 0x6010, 0xa005,
+	0x0040, 0x4ad4, 0x1078, 0x2628, 0xace0, 0x0010, 0x00f0, 0x4ac3,
+	0xd7fc, 0x0040, 0x4ae2, 0x2061, 0x53c0, 0x2069, 0x4e40, 0xc7fc,
+	0x0078, 0x4a6a, 0x1078, 0x4b1e, 0x7838, 0x8001, 0x783a, 0x00c0,
+	0x4b04, 0x783c, 0x783a, 0x2061, 0x53c0, 0x2069, 0x4e40, 0xc7fc,
+	0x680c, 0xa005, 0x0040, 0x4af6, 0x1078, 0x4b88, 0xd7fc, 0x00c0,
+	0x4b04, 0x7810, 0xd0ec, 0x00c0, 0x4b04, 0x2061, 0x73c0, 0x2069,
+	0x4e80, 0xc7fd, 0x0078, 0x4af0, 0x7814, 0xd0e4, 0x00c0, 0x4b08,
+	0x7810, 0xd0cc, 0x0040, 0x4b1b, 0xd0ac, 0x00c0, 0x4b14, 0xd0a4,
+	0x0040, 0x4b1b, 0xc0ad, 0x7812, 0x2091, 0x8001, 0x0068, 0x4b1a,
+	0x1078, 0x2395, 0x007c, 0x2091, 0x8001, 0x007c, 0x7840, 0x8001,
+	0x7842, 0x00c0, 0x4b87, 0x7844, 0x7842, 0x2069, 0x4e40, 0xc7fc,
+	0x7810, 0x2079, 0x0200, 0xd0ec, 0x0040, 0x4b30, 0x2079, 0x0100,
+	0x68d8, 0xa005, 0x0040, 0x4b3c, 0x7de0, 0xa504, 0x00c0, 0x4b3c,
+	0x68da, 0x68d4, 0xc0bc, 0x68d6, 0x2079, 0x4e00, 0x6810, 0xa005,
+	0x00c0, 0x4b44, 0x2001, 0x0101, 0x8001, 0x6812, 0xd7fc, 0x0040,
+	0x4b4d, 0xa080, 0x94d0, 0x0078, 0x4b4f, 0xa080, 0x93c0, 0x2040,
+	0x2004, 0xa065, 0x0040, 0x4b79, 0x6024, 0xa005, 0x0040, 0x4b75,
+	0x8001, 0x6026, 0x00c0, 0x4b75, 0x6800, 0xa005, 0x0040, 0x4b68,
+	0x684c, 0xac06, 0x00c0, 0x4b68, 0x1078, 0x4c23, 0x0078, 0x4b79,
+	0x6864, 0xa005, 0x0040, 0x4b70, 0x6027, 0x0001, 0x0078, 0x4b75,
+	0x1078, 0x4bd6, 0x2804, 0x0078, 0x4b51, 0x6000, 0x2c40, 0x0078,
+	0x4b51, 0xd7fc, 0x00c0, 0x4b87, 0x7810, 0xd0ec, 0x00c0, 0x4b87,
+	0x2069, 0x4e80, 0xc7fd, 0x2079, 0x0100, 0x0078, 0x4b30, 0x007c,
+	0x2009, 0x0000, 0x20a9, 0x0200, 0x6008, 0xd09c, 0x0040, 0x4bc2,
+	0x6024, 0xa005, 0x0040, 0x4b98, 0x8001, 0x6026, 0x0078, 0x4bc0,
+	0x6008, 0xc09c, 0xd084, 0x00c0, 0x4ba0, 0xd0ac, 0x0040, 0x4bba,
+	0x600a, 0x6004, 0xa005, 0x0040, 0x4bc2, 0x0d7e, 0x0c7e, 0x017e,
+	0x2068, 0x6010, 0x8001, 0x6012, 0x1078, 0x3dd0, 0x2d00, 0x2c68,
+	0x2060, 0x1078, 0x1e5b, 0x1078, 0x201d, 0x017f, 0x0c7f, 0x0d7f,
+	0x0078, 0x4bc2, 0xc0bd, 0x600a, 0xa18d, 0x0001, 0x0078, 0x4bc2,
+	0xa18d, 0x0100, 0xace0, 0x0010, 0x00f0, 0x4b8c, 0xa184, 0x0001,
+	0x0040, 0x4bd1, 0xa18c, 0xfffe, 0x690e, 0x1078, 0x2628, 0x0078,
+	0x4bd2, 0x690e, 0x007c, 0x00c0, 0x4bd2, 0x786c, 0x2c00, 0x687e,
+	0x6714, 0x6f76, 0x6017, 0x0000, 0x602b, 0x0000, 0x601b, 0x0006,
+	0x60b4, 0xa084, 0x3f00, 0x601e, 0x6020, 0xa084, 0x00ff, 0xa085,
+	0x0060, 0x6022, 0x6000, 0x2042, 0x1078, 0x1de4, 0x6818, 0xa005,
+	0x0040, 0x4bf4, 0x8001, 0x681a, 0x6808, 0xc0a4, 0x680a, 0x6810,
+	0x7908, 0x8109, 0x790a, 0x8001, 0x00d0, 0x4c00, 0x1078, 0x296b,
+	0x6812, 0x00c0, 0x4c06, 0x7910, 0xc1a5, 0x7912, 0x602f, 0x0000,
+	0x6033, 0x0000, 0x2c68, 0x1078, 0x202c, 0xd7fc, 0x00c0, 0x4c14,
+	0x2069, 0x4e40, 0x0078, 0x4c16, 0x2069, 0x4e80, 0x6910, 0xa184,
+	0x0100, 0x2001, 0x0006, 0x00c0, 0x4c20, 0x697a, 0x2001, 0x0004,
+	0x1078, 0x261c, 0x007c, 0x0d7e, 0x694c, 0x2160, 0xd7fc, 0x00c0,
+	0x4c35, 0x7810, 0xd0ec, 0x0040, 0x4c31, 0x2069, 0x0100, 0x0078,
+	0x4c37, 0x2069, 0x0200, 0x0078, 0x4c37, 0x2069, 0x0100, 0x1078,
+	0x28df, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00, 0x601e, 0x6020,
+	0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f, 0x0000, 0x6033,
+	0x0000, 0x6808, 0xa084, 0xfffd, 0x680a, 0x6830, 0xd0b4, 0x0040,
+	0x4c69, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xd094, 0x0040,
+	0x4c5b, 0x00f0, 0x4c55, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848,
+	0xd084, 0x0040, 0x4c65, 0x00f0, 0x4c5f, 0x20a9, 0x00fa, 0x00f0,
+	0x4c67, 0x681b, 0x0047, 0x0d7f, 0x6867, 0x0007, 0x007c, 0x2079,
+	0x4e00, 0x1078, 0x4ca3, 0x1078, 0x4c89, 0x1078, 0x4c96, 0x2009,
+	0x0002, 0x2069, 0x4e80, 0x680f, 0x0000, 0x6813, 0x0000, 0x6817,
+	0x0000, 0x8109, 0x0040, 0x4c88, 0x2069, 0x4e40, 0x0078, 0x4c7b,
+	0x007c, 0x7810, 0xd0ec, 0x0040, 0x4c91, 0x2019, 0x00cc, 0x0078,
+	0x4c93, 0x2019, 0x007b, 0x7b3a, 0x7b3e, 0x007c, 0x7814, 0xd0e4,
+	0x00c0, 0x4c9e, 0x2019, 0x0040, 0x0078, 0x4ca0, 0x2019, 0x0026,
+	0x7b42, 0x7b46, 0x007c, 0x7814, 0xd0e4, 0x00c0, 0x4cab, 0x2019,
+	0x3f94, 0x0078, 0x4cad, 0x2019, 0x2624, 0x7b32, 0x7b36, 0x007c,
+	0x6a50, 0xa285, 0x0000, 0x0040, 0x4cdc, 0x6954, 0x6bc0, 0xa300,
+	0x0c7e, 0x2164, 0x6304, 0x83ff, 0x00c0, 0x4cc8, 0x8211, 0x0040,
+	0x4ccc, 0x8108, 0xa11a, 0x0048, 0x4cb9, 0x69c0, 0x0078, 0x4cb9,
+	0x68d3, 0x000a, 0x0c7f, 0x007c, 0x6950, 0x6ac0, 0x2264, 0x602b,
+	0x0000, 0x602f, 0x0000, 0x6008, 0xc0b5, 0x600a, 0x8210, 0x8109,
+	0x00c0, 0x4cce, 0x6952, 0x0c7f, 0x007c, 0x00e0, 0x4cdd, 0x2091,
+	0x6000, 0x00e0, 0x4ce1, 0x2091, 0x6000, 0x70ec, 0xd0dc, 0x00c0,
+	0x4cee, 0xd0d4, 0x0040, 0x4d17, 0x0078, 0x4d1a, 0x2008, 0x7810,
+	0xd0ec, 0x0040, 0x4d01, 0xd1c4, 0x00c0, 0x4d39, 0x7814, 0xc0c5,
+	0x7816, 0x7810, 0xc0f5, 0x7812, 0xd0ec, 0x0040, 0x4d35, 0x0078,
+	0x4d31, 0xae8e, 0x0100, 0x0040, 0x4d0e, 0x7814, 0xc0f5, 0xc0c5,
+	0x7816, 0xd0d4, 0x00c0, 0x4d35, 0x0078, 0x4d31, 0x7814, 0xc0fd,
+	0xc0c5, 0x7816, 0xd0d4, 0x00c0, 0x4d35, 0x0078, 0x4d31, 0xd0e4,
+	0x0040, 0x4d37, 0x00e0, 0x4d1a, 0x2091, 0x6000, 0x2009, 0x000c,
+	0x00e0, 0x4d20, 0x2091, 0x6000, 0x8109, 0x00c0, 0x4d20, 0x70e4,
+	0xa084, 0x01ff, 0xa086, 0x01ff, 0x00c0, 0x4d31, 0x70ec, 0x0078,
+	0x4cee, 0x7804, 0xd08c, 0x0040, 0x4d37, 0x681f, 0x000c, 0x70a0,
+	0x70a2, 0x007c, 0x205b
+};
+#ifdef UNIQUE_FW_NAME
+static unsigned short   fw1280ei_length01 = 0x3d3b;
+#else
+static unsigned short   risc_code_length01 = 0x3d3b;
+#endif
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
new file mode 100644
index 0000000..4ad2808
--- /dev/null
+++ b/drivers/scsi/qla1280.c
@@ -0,0 +1,4863 @@
+/******************************************************************************
+*                  QLOGIC LINUX SOFTWARE
+*
+* QLogic  QLA1280 (Ultra2)  and  QLA12160 (Ultra3) SCSI driver
+* Copyright (C) 2000 Qlogic Corporation (www.qlogic.com)
+* Copyright (C) 2001-2004 Jes Sorensen, Wild Open Source Inc.
+* Copyright (C) 2003-2004 Christoph Hellwig
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+*
+******************************************************************************/
+#define QLA1280_VERSION      "3.25"
+/*****************************************************************************
+    Revision History:
+    Rev  3.25.1, February 10, 2005 Christoph Hellwig
+	- use pci_map_single to map non-S/G requests
+	- remove qla1280_proc_info
+    Rev  3.25, September 28, 2004, Christoph Hellwig
+	- add support for ISP1020/1040
+	- don't include "scsi.h" anymore for 2.6.x
+    Rev  3.24.4 June 7, 2004 Christoph Hellwig
+	- restructure firmware loading, cleanup initialization code
+	- prepare support for ISP1020/1040 chips
+    Rev  3.24.3 January 19, 2004, Jes Sorensen
+	- Handle PCI DMA mask settings correctly
+	- Correct order of error handling in probe_one, free_irq should not
+	  be called if request_irq failed
+    Rev  3.24.2 January 19, 2004, James Bottomley & Andrew Vasquez
+	- Big endian fixes (James)
+	- Remove bogus IOCB content on zero data transfer commands (Andrew)
+    Rev  3.24.1 January 5, 2004, Jes Sorensen
+	- Initialize completion queue to avoid OOPS on probe
+	- Handle interrupts during mailbox testing
+    Rev  3.24 November 17, 2003, Christoph Hellwig
+    	- use struct list_head for completion queue
+	- avoid old Scsi_FOO typedefs
+	- cleanup 2.4 compat glue a bit
+	- use <scsi/scsi_*.h> headers on 2.6 instead of "scsi.h"
+	- make initialization for memory mapped vs port I/O more similar
+	- remove broken pci config space manipulation
+	- kill more cruft
+	- this is an almost perfect 2.6 scsi driver now! ;)
+    Rev  3.23.39 December 17, 2003, Jes Sorensen
+	- Delete completion queue from srb if mailbox command failed to
+	  to avoid qla1280_done completeting qla1280_error_action's
+	  obsolete context
+	- Reduce arguments for qla1280_done
+    Rev  3.23.38 October 18, 2003, Christoph Hellwig
+	- Convert to new-style hotplugable driver for 2.6
+	- Fix missing scsi_unregister/scsi_host_put on HBA removal
+	- Kill some more cruft
+    Rev  3.23.37 October 1, 2003, Jes Sorensen
+	- Make MMIO depend on CONFIG_X86_VISWS instead of yet another
+	  random CONFIG option
+	- Clean up locking in probe path
+    Rev  3.23.36 October 1, 2003, Christoph Hellwig
+	- queuecommand only ever receives new commands - clear flags
+	- Reintegrate lost fixes from Linux 2.5
+    Rev  3.23.35 August 14, 2003, Jes Sorensen
+	- Build against 2.6
+    Rev  3.23.34 July 23, 2003, Jes Sorensen
+	- Remove pointless TRUE/FALSE macros
+	- Clean up vchan handling
+    Rev  3.23.33 July 3, 2003, Jes Sorensen
+	- Don't define register access macros before define determining MMIO.
+	  This just happend to work out on ia64 but not elsewhere.
+	- Don't try and read from the card while it is in reset as
+	  it won't respond and causes an MCA
+    Rev  3.23.32 June 23, 2003, Jes Sorensen
+	- Basic support for boot time arguments
+    Rev  3.23.31 June 8, 2003, Jes Sorensen
+	- Reduce boot time messages
+    Rev  3.23.30 June 6, 2003, Jes Sorensen
+	- Do not enable sync/wide/ppr before it has been determined
+	  that the target device actually supports it
+	- Enable DMA arbitration for multi channel controllers
+    Rev  3.23.29 June 3, 2003, Jes Sorensen
+	- Port to 2.5.69
+    Rev  3.23.28 June 3, 2003, Jes Sorensen
+	- Eliminate duplicate marker commands on bus resets
+	- Handle outstanding commands appropriately on bus/device resets
+    Rev  3.23.27 May 28, 2003, Jes Sorensen
+	- Remove bogus input queue code, let the Linux SCSI layer do the work
+	- Clean up NVRAM handling, only read it once from the card
+	- Add a number of missing default nvram parameters
+    Rev  3.23.26 Beta May 28, 2003, Jes Sorensen
+	- Use completion queue for mailbox commands instead of busy wait
+    Rev  3.23.25 Beta May 27, 2003, James Bottomley
+	- Migrate to use new error handling code
+    Rev  3.23.24 Beta May 21, 2003, James Bottomley
+	- Big endian support
+	- Cleanup data direction code
+    Rev  3.23.23 Beta May 12, 2003, Jes Sorensen
+	- Switch to using MMIO instead of PIO
+    Rev  3.23.22 Beta April 15, 2003, Jes Sorensen
+	- Fix PCI parity problem with 12160 during reset.
+    Rev  3.23.21 Beta April 14, 2003, Jes Sorensen
+	- Use pci_map_page()/pci_unmap_page() instead of map_single version.
+    Rev  3.23.20 Beta April 9, 2003, Jes Sorensen
+	- Remove < 2.4.x support
+	- Introduce HOST_LOCK to make the spin lock changes portable.
+	- Remove a bunch of idiotic and unnecessary typedef's
+	- Kill all leftovers of target-mode support which never worked anyway
+    Rev  3.23.19 Beta April 11, 2002, Linus Torvalds
+	- Do qla1280_pci_config() before calling request_irq() and
+	  request_region()
+	- Use pci_dma_hi32() to handle upper word of DMA addresses instead
+	  of large shifts
+	- Hand correct arguments to free_irq() in case of failure
+    Rev  3.23.18 Beta April 11, 2002, Jes Sorensen
+	- Run source through Lindent and clean up the output
+    Rev  3.23.17 Beta April 11, 2002, Jes Sorensen
+	- Update SCSI firmware to qla1280 v8.15.00 and qla12160 v10.04.32
+    Rev  3.23.16 Beta March 19, 2002, Jes Sorensen
+	- Rely on mailbox commands generating interrupts - do not
+	  run qla1280_isr() from ql1280_mailbox_command()
+	- Remove device_reg_t
+	- Integrate ql12160_set_target_parameters() with 1280 version
+	- Make qla1280_setup() non static
+	- Do not call qla1280_check_for_dead_scsi_bus() on every I/O request
+	  sent to the card - this command pauses the firmare!!!
+    Rev  3.23.15 Beta March 19, 2002, Jes Sorensen
+	- Clean up qla1280.h - remove obsolete QL_DEBUG_LEVEL_x definitions
+	- Remove a pile of pointless and confusing (srb_t **) and
+	  (scsi_lu_t *) typecasts
+	- Explicit mark that we do not use the new error handling (for now)
+	- Remove scsi_qla_host_t and use 'struct' instead
+	- Remove in_abort, watchdog_enabled, dpc, dpc_sched, bios_enabled,
+	  pci_64bit_slot flags which weren't used for anything anyway
+	- Grab host->host_lock while calling qla1280_isr() from abort()
+	- Use spin_lock()/spin_unlock() in qla1280_intr_handler() - we
+	  do not need to save/restore flags in the interrupt handler
+	- Enable interrupts early (before any mailbox access) in preparation
+	  for cleaning up the mailbox handling
+    Rev  3.23.14 Beta March 14, 2002, Jes Sorensen
+	- Further cleanups. Remove all trace of QL_DEBUG_LEVEL_x and replace
+	  it with proper use of dprintk().
+	- Make qla1280_print_scsi_cmd() and qla1280_dump_buffer() both take
+	  a debug level argument to determine if data is to be printed
+	- Add KERN_* info to printk()
+    Rev  3.23.13 Beta March 14, 2002, Jes Sorensen
+	- Significant cosmetic cleanups
+	- Change debug code to use dprintk() and remove #if mess
+    Rev  3.23.12 Beta March 13, 2002, Jes Sorensen
+	- More cosmetic cleanups, fix places treating return as function
+	- use cpu_relax() in qla1280_debounce_register()
+    Rev  3.23.11 Beta March 13, 2002, Jes Sorensen
+	- Make it compile under 2.5.5
+    Rev  3.23.10 Beta October 1, 2001, Jes Sorensen
+	- Do no typecast short * to long * in QL1280BoardTbl, this
+	  broke miserably on big endian boxes
+    Rev  3.23.9 Beta September 30, 2001, Jes Sorensen
+	- Remove pre 2.2 hack for checking for reentrance in interrupt handler
+	- Make data types used to receive from SCSI_{BUS,TCN,LUN}_32
+	  unsigned int to match the types from struct scsi_cmnd
+    Rev  3.23.8 Beta September 29, 2001, Jes Sorensen
+	- Remove bogus timer_t typedef from qla1280.h
+	- Remove obsolete pre 2.2 PCI setup code, use proper #define's
+	  for PCI_ values, call pci_set_master()
+	- Fix memleak of qla1280_buffer on module unload
+	- Only compile module parsing code #ifdef MODULE - should be
+	  changed to use individual MODULE_PARM's later
+	- Remove dummy_buffer that was never modified nor printed
+	- ENTER()/LEAVE() are noops unless QL_DEBUG_LEVEL_3, hence remove
+	  #ifdef QL_DEBUG_LEVEL_3/#endif around ENTER()/LEAVE() calls
+	- Remove \r from print statements, this is Linux, not DOS
+	- Remove obsolete QLA1280_{SCSILU,INTR,RING}_{LOCK,UNLOCK}
+	  dummy macros
+	- Remove C++ compile hack in header file as Linux driver are not
+	  supposed to be compiled as C++
+	- Kill MS_64BITS macro as it makes the code more readable
+	- Remove unnecessary flags.in_interrupts bit
+    Rev  3.23.7 Beta August 20, 2001, Jes Sorensen
+	- Dont' check for set flags on q->q_flag one by one in qla1280_next()
+        - Check whether the interrupt was generated by the QLA1280 before
+          doing any processing
+	- qla1280_status_entry(): Only zero out part of sense_buffer that
+	  is not being copied into
+	- Remove more superflouous typecasts
+	- qla1280_32bit_start_scsi() replace home-brew memcpy() with memcpy()
+    Rev  3.23.6 Beta August 20, 2001, Tony Luck, Intel
+        - Don't walk the entire list in qla1280_putq_t() just to directly
+	  grab the pointer to the last element afterwards
+    Rev  3.23.5 Beta August 9, 2001, Jes Sorensen
+	- Don't use SA_INTERRUPT, it's use is deprecated for this kinda driver
+    Rev  3.23.4 Beta August 8, 2001, Jes Sorensen
+	- Set dev->max_sectors to 1024
+    Rev  3.23.3 Beta August 6, 2001, Jes Sorensen
+	- Provide compat macros for pci_enable_device(), pci_find_subsys()
+	  and scsi_set_pci_device()
+	- Call scsi_set_pci_device() for all devices
+	- Reduce size of kernel version dependent device probe code
+	- Move duplicate probe/init code to separate function
+	- Handle error if qla1280_mem_alloc() fails
+	- Kill OFFSET() macro and use Linux's PCI definitions instead
+        - Kill private structure defining PCI config space (struct config_reg)
+	- Only allocate I/O port region if not in MMIO mode
+	- Remove duplicate (unused) sanity check of sife of srb_t
+    Rev  3.23.2 Beta August 6, 2001, Jes Sorensen
+	- Change home-brew memset() implementations to use memset()
+        - Remove all references to COMTRACE() - accessing a PC's COM2 serial
+          port directly is not legal under Linux.
+    Rev  3.23.1 Beta April 24, 2001, Jes Sorensen
+        - Remove pre 2.2 kernel support
+        - clean up 64 bit DMA setting to use 2.4 API (provide backwards compat)
+        - Fix MMIO access to use readl/writel instead of directly
+          dereferencing pointers
+        - Nuke MSDOS debugging code
+        - Change true/false data types to int from uint8_t
+        - Use int for counters instead of uint8_t etc.
+        - Clean up size & byte order conversion macro usage
+    Rev  3.23 Beta January 11, 2001 BN Qlogic
+        - Added check of device_id when handling non
+          QLA12160s during detect().
+    Rev  3.22 Beta January 5, 2001 BN Qlogic
+        - Changed queue_task() to schedule_task()
+          for kernels 2.4.0 and higher.
+          Note: 2.4.0-testxx kernels released prior to
+                the actual 2.4.0 kernel release on January 2001
+                will get compile/link errors with schedule_task().
+                Please update your kernel to released 2.4.0 level,
+                or comment lines in this file flagged with  3.22
+                to resolve compile/link error of schedule_task().
+        - Added -DCONFIG_SMP in addition to -D__SMP__
+          in Makefile for 2.4.0 builds of driver as module.
+    Rev  3.21 Beta January 4, 2001 BN Qlogic
+        - Changed criteria of 64/32 Bit mode of HBA
+          operation according to BITS_PER_LONG rather
+          than HBA's NVRAM setting of >4Gig memory bit;
+          so that the HBA auto-configures without the need
+          to setup each system individually.
+    Rev  3.20 Beta December 5, 2000 BN Qlogic
+        - Added priority handling to IA-64  onboard SCSI
+          ISP12160 chip for kernels greater than 2.3.18.
+        - Added irqrestore for qla1280_intr_handler.
+        - Enabled /proc/scsi/qla1280 interface.
+        - Clear /proc/scsi/qla1280 counters in detect().
+    Rev  3.19 Beta October 13, 2000 BN Qlogic
+        - Declare driver_template for new kernel
+          (2.4.0 and greater) scsi initialization scheme.
+        - Update /proc/scsi entry for 2.3.18 kernels and
+          above as qla1280
+    Rev  3.18 Beta October 10, 2000 BN Qlogic
+        - Changed scan order of adapters to map
+          the QLA12160 followed by the QLA1280.
+    Rev  3.17 Beta September 18, 2000 BN Qlogic
+        - Removed warnings for 32 bit 2.4.x compiles
+        - Corrected declared size for request and response
+          DMA addresses that are kept in each ha
+    Rev. 3.16 Beta  August 25, 2000   BN  Qlogic
+        - Corrected 64 bit addressing issue on IA-64
+          where the upper 32 bits were not properly
+          passed to the RISC engine.
+    Rev. 3.15 Beta  August 22, 2000   BN  Qlogic
+        - Modified qla1280_setup_chip to properly load
+          ISP firmware for greater that 4 Gig memory on IA-64
+    Rev. 3.14 Beta  August 16, 2000   BN  Qlogic
+        - Added setting of dma_mask to full 64 bit
+          if flags.enable_64bit_addressing is set in NVRAM
+    Rev. 3.13 Beta  August 16, 2000   BN  Qlogic
+        - Use new PCI DMA mapping APIs for 2.4.x kernel
+    Rev. 3.12       July 18, 2000    Redhat & BN Qlogic
+        - Added check of pci_enable_device to detect() for 2.3.x
+        - Use pci_resource_start() instead of
+          pdev->resource[0].start in detect() for 2.3.x
+        - Updated driver version
+    Rev. 3.11       July 14, 2000    BN  Qlogic
+	- Updated SCSI Firmware to following versions:
+	  qla1x80:   8.13.08
+	  qla1x160:  10.04.08
+	- Updated driver version to 3.11
+    Rev. 3.10    June 23, 2000   BN Qlogic
+        - Added filtering of AMI SubSys Vendor ID devices
+    Rev. 3.9
+        - DEBUG_QLA1280 undefined and  new version  BN Qlogic
+    Rev. 3.08b      May 9, 2000    MD Dell
+        - Added logic to check against AMI subsystem vendor ID
+	Rev. 3.08       May 4, 2000    DG  Qlogic
+        - Added logic to check for PCI subsystem ID.
+	Rev. 3.07       Apr 24, 2000    DG & BN  Qlogic
+	   - Updated SCSI Firmware to following versions:
+	     qla12160:   10.01.19
+		 qla1280:     8.09.00
+	Rev. 3.06       Apr 12, 2000    DG & BN  Qlogic
+	   - Internal revision; not released
+    Rev. 3.05       Mar 28, 2000    DG & BN  Qlogic
+       - Edit correction for virt_to_bus and PROC.
+    Rev. 3.04       Mar 28, 2000    DG & BN  Qlogic
+       - Merge changes from ia64 port.
+    Rev. 3.03       Mar 28, 2000    BN  Qlogic
+       - Increase version to reflect new code drop with compile fix
+         of issue with inclusion of linux/spinlock for 2.3 kernels
+    Rev. 3.02       Mar 15, 2000    BN  Qlogic
+       - Merge qla1280_proc_info from 2.10 code base
+    Rev. 3.01       Feb 10, 2000    BN  Qlogic
+       - Corrected code to compile on a 2.2.x kernel.
+    Rev. 3.00       Jan 17, 2000    DG  Qlogic
+	   - Added 64-bit support.
+    Rev. 2.07       Nov 9, 1999     DG  Qlogic
+	   - Added new routine to set target parameters for ISP12160.
+    Rev. 2.06       Sept 10, 1999     DG  Qlogic
+       - Added support for ISP12160 Ultra 3 chip.
+    Rev. 2.03       August 3, 1999    Fred Lewis, Intel DuPont
+	- Modified code to remove errors generated when compiling with
+	  Cygnus IA64 Compiler.
+        - Changed conversion of pointers to unsigned longs instead of integers.
+        - Changed type of I/O port variables from uint32_t to unsigned long.
+        - Modified OFFSET macro to work with 64-bit as well as 32-bit.
+        - Changed sprintf and printk format specifiers for pointers to %p.
+        - Changed some int to long type casts where needed in sprintf & printk.
+        - Added l modifiers to sprintf and printk format specifiers for longs.
+        - Removed unused local variables.
+    Rev. 1.20       June 8, 1999      DG,  Qlogic
+         Changes to support RedHat release 6.0 (kernel 2.2.5).
+       - Added SCSI exclusive access lock (io_request_lock) when accessing
+         the adapter.
+       - Added changes for the new LINUX interface template. Some new error
+         handling routines have been added to the template, but for now we
+         will use the old ones.
+    -   Initial Beta Release.
+*****************************************************************************/
+
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/slab.h>
+#include <linux/pci_ids.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include <asm/processor.h>
+#include <asm/types.h>
+#include <asm/system.h>
+
+#if LINUX_VERSION_CODE >= 0x020545
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#else
+#include <linux/blk.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "sd.h"
+#endif
+
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+#include <asm/sn/io.h>
+#endif
+
+#if LINUX_VERSION_CODE < 0x020407
+#error "Kernels older than 2.4.7 are no longer supported"
+#endif
+
+
+/*
+ * Compile time Options:
+ *            0 - Disable and 1 - Enable
+ */
+#define  DEBUG_QLA1280_INTR	0
+#define  DEBUG_PRINT_NVRAM	0
+#define  DEBUG_QLA1280		0
+
+/*
+ * The SGI VISWS is broken and doesn't support MMIO ;-(
+ */
+#ifdef CONFIG_X86_VISWS
+#define	MEMORY_MAPPED_IO	0
+#else
+#define	MEMORY_MAPPED_IO	1
+#endif
+
+#define UNIQUE_FW_NAME
+#include "qla1280.h"
+#include "ql12160_fw.h"		/* ISP RISC codes */
+#include "ql1280_fw.h"
+#include "ql1040_fw.h"
+
+
+/*
+ * Missing PCI ID's
+ */
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP1080
+#define PCI_DEVICE_ID_QLOGIC_ISP1080	0x1080
+#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP1240
+#define PCI_DEVICE_ID_QLOGIC_ISP1240	0x1240
+#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP1280
+#define PCI_DEVICE_ID_QLOGIC_ISP1280	0x1280
+#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP10160
+#define PCI_DEVICE_ID_QLOGIC_ISP10160	0x1016
+#endif
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP12160
+#define PCI_DEVICE_ID_QLOGIC_ISP12160	0x1216
+#endif
+
+#ifndef PCI_VENDOR_ID_AMI
+#define PCI_VENDOR_ID_AMI               0x101e
+#endif
+
+#ifndef BITS_PER_LONG
+#error "BITS_PER_LONG not defined!"
+#endif
+#if (BITS_PER_LONG == 64) || defined CONFIG_HIGHMEM
+#define QLA_64BIT_PTR	1
+#endif
+
+#ifdef QLA_64BIT_PTR
+#define pci_dma_hi32(a)			((a >> 16) >> 16)
+#else
+#define pci_dma_hi32(a)			0
+#endif
+#define pci_dma_lo32(a)			(a & 0xffffffff)
+
+#define NVRAM_DELAY()			udelay(500)	/* 2 microseconds */
+
+#if LINUX_VERSION_CODE < 0x020500
+#define HOST_LOCK			&io_request_lock
+#define irqreturn_t			void
+#define IRQ_RETVAL(foo)
+#define MSG_ORDERED_TAG			1
+
+#define DMA_BIDIRECTIONAL	SCSI_DATA_UNKNOWN
+#define DMA_TO_DEVICE		SCSI_DATA_WRITE
+#define DMA_FROM_DEVICE		SCSI_DATA_READ
+#define DMA_NONE		SCSI_DATA_NONE
+
+#ifndef HAVE_SECTOR_T
+typedef unsigned int sector_t;
+#endif
+
+static inline void
+scsi_adjust_queue_depth(struct scsi_device *device, int tag, int depth)
+{
+	if (tag) {
+		device->tagged_queue = tag;
+		device->current_tag = 0;
+	}
+	device->queue_depth = depth;
+}
+static inline struct Scsi_Host *scsi_host_alloc(Scsi_Host_Template *t, size_t s)
+{
+	return scsi_register(t, s);
+}
+static inline void scsi_host_put(struct Scsi_Host *h)
+{
+	scsi_unregister(h);
+}
+#else
+#define HOST_LOCK			ha->host->host_lock
+#endif
+#if LINUX_VERSION_CODE < 0x020600
+#define DEV_SIMPLE_TAGS(device)		device->tagged_queue
+/*
+ * Hack around that qla1280_remove_one is called from
+ * qla1280_release in 2.4
+ */
+#undef __devexit
+#define __devexit
+#else
+#define DEV_SIMPLE_TAGS(device)		device->simple_tags
+#endif
+#if defined(__ia64__) && !defined(ia64_platform_is)
+#define ia64_platform_is(foo)		(!strcmp(x, platform_name))
+#endif
+
+
+#define IS_ISP1040(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020)
+#define IS_ISP1x40(ha) (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1020 || \
+			ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP1240)
+#define IS_ISP1x160(ha)        (ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP10160 || \
+				ha->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP12160)
+
+
+static int qla1280_probe_one(struct pci_dev *, const struct pci_device_id *);
+static void qla1280_remove_one(struct pci_dev *);
+
+/*
+ *  QLogic Driver Support Function Prototypes.
+ */
+static void qla1280_done(struct scsi_qla_host *);
+#if LINUX_VERSION_CODE < 0x020545
+static void qla1280_get_target_options(struct scsi_cmnd *, struct scsi_qla_host *);
+#endif
+static int qla1280_get_token(char *);
+static int qla1280_setup(char *s) __init;
+
+/*
+ *  QLogic ISP1280 Hardware Support Function Prototypes.
+ */
+static int qla1280_load_firmware(struct scsi_qla_host *);
+static int qla1280_init_rings(struct scsi_qla_host *);
+static int qla1280_nvram_config(struct scsi_qla_host *);
+static int qla1280_mailbox_command(struct scsi_qla_host *,
+				   uint8_t, uint16_t *);
+static int qla1280_bus_reset(struct scsi_qla_host *, int);
+static int qla1280_device_reset(struct scsi_qla_host *, int, int);
+static int qla1280_abort_device(struct scsi_qla_host *, int, int, int);
+static int qla1280_abort_command(struct scsi_qla_host *, struct srb *, int);
+static int qla1280_abort_isp(struct scsi_qla_host *);
+#ifdef QLA_64BIT_PTR
+static int qla1280_64bit_start_scsi(struct scsi_qla_host *, struct srb *);
+#else
+static int qla1280_32bit_start_scsi(struct scsi_qla_host *, struct srb *);
+#endif
+static void qla1280_nv_write(struct scsi_qla_host *, uint16_t);
+static void qla1280_poll(struct scsi_qla_host *);
+static void qla1280_reset_adapter(struct scsi_qla_host *);
+static void qla1280_marker(struct scsi_qla_host *, int, int, int, u8);
+static void qla1280_isp_cmd(struct scsi_qla_host *);
+static void qla1280_isr(struct scsi_qla_host *, struct list_head *);
+static void qla1280_rst_aen(struct scsi_qla_host *);
+static void qla1280_status_entry(struct scsi_qla_host *, struct response *,
+				 struct list_head *);
+static void qla1280_error_entry(struct scsi_qla_host *, struct response *,
+				struct list_head *);
+static uint16_t qla1280_get_nvram_word(struct scsi_qla_host *, uint32_t);
+static uint16_t qla1280_nvram_request(struct scsi_qla_host *, uint32_t);
+static uint16_t qla1280_debounce_register(volatile uint16_t __iomem *);
+static request_t *qla1280_req_pkt(struct scsi_qla_host *);
+static int qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *,
+					   unsigned int);
+static void qla1280_get_target_parameters(struct scsi_qla_host *,
+					   struct scsi_device *);
+static int qla1280_set_target_parameters(struct scsi_qla_host *, int, int);
+
+
+static struct qla_driver_setup driver_setup;
+
+/*
+ * convert scsi data direction to request_t control flags
+ */
+static inline uint16_t
+qla1280_data_direction(struct scsi_cmnd *cmnd)
+{
+	switch(cmnd->sc_data_direction) {
+	case DMA_FROM_DEVICE:
+		return BIT_5;
+	case DMA_TO_DEVICE:
+		return BIT_6;
+	case DMA_BIDIRECTIONAL:
+		return BIT_5 | BIT_6;
+	/*
+	 * We could BUG() on default here if one of the four cases aren't
+	 * met, but then again if we receive something like that from the
+	 * SCSI layer we have more serious problems. This shuts up GCC.
+	 */
+	case DMA_NONE:
+	default:
+		return 0;
+	}
+}
+		
+#if DEBUG_QLA1280
+static void __qla1280_print_scsi_cmd(struct scsi_cmnd * cmd);
+static void __qla1280_dump_buffer(char *, int);
+#endif
+
+
+/*
+ * insmod needs to find the variable and make it point to something
+ */
+#ifdef MODULE
+static char *qla1280;
+
+/* insmod qla1280 options=verbose" */
+module_param(qla1280, charp, 0);
+#else
+__setup("qla1280=", qla1280_setup);
+#endif
+
+
+/*
+ * We use the scsi_pointer structure that's included with each scsi_command
+ * to overlay our struct srb over it. qla1280_init() checks that a srb is not
+ * bigger than a scsi_pointer.
+ */
+
+#define	CMD_SP(Cmnd)		&Cmnd->SCp
+#define	CMD_CDBLEN(Cmnd)	Cmnd->cmd_len
+#define	CMD_CDBP(Cmnd)		Cmnd->cmnd
+#define	CMD_SNSP(Cmnd)		Cmnd->sense_buffer
+#define	CMD_SNSLEN(Cmnd)	sizeof(Cmnd->sense_buffer)
+#define	CMD_RESULT(Cmnd)	Cmnd->result
+#define	CMD_HANDLE(Cmnd)	Cmnd->host_scribble
+#if LINUX_VERSION_CODE < 0x020545
+#define CMD_REQUEST(Cmnd)	Cmnd->request.cmd
+#else
+#define CMD_REQUEST(Cmnd)	Cmnd->request->cmd
+#endif
+
+#define CMD_HOST(Cmnd)		Cmnd->device->host
+#define SCSI_BUS_32(Cmnd)	Cmnd->device->channel
+#define SCSI_TCN_32(Cmnd)	Cmnd->device->id
+#define SCSI_LUN_32(Cmnd)	Cmnd->device->lun
+
+
+/*****************************************/
+/*   ISP Boards supported by this driver */
+/*****************************************/
+
+struct qla_boards {
+	unsigned char name[9];	/* Board ID String */
+	int numPorts;		/* Number of SCSI ports */
+	unsigned short *fwcode;	/* pointer to FW array         */
+	unsigned short *fwlen;	/* number of words in array    */
+	unsigned short *fwstart;	/* start address for F/W       */
+	unsigned char *fwver;	/* Ptr to F/W version array    */
+};
+
+/* NOTE: the last argument in each entry is used to index ql1280_board_tbl */
+static struct pci_device_id qla1280_pci_tbl[] = {
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP12160,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
+#ifdef CONFIG_SCSI_QLOGIC_1280_1040
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1},
+#endif
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1080,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2},
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1240,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3},
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1280,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4},
+	{PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP10160,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5},
+	{0,}
+};
+MODULE_DEVICE_TABLE(pci, qla1280_pci_tbl);
+
+static struct qla_boards ql1280_board_tbl[] = {
+	/* Name ,  Number of ports, FW details */
+	{"QLA12160", 2, &fw12160i_code01[0], &fw12160i_length01,
+	 &fw12160i_addr01, &fw12160i_version_str[0]},
+	{"QLA1040", 1, &risc_code01[0], &risc_code_length01,
+	 &risc_code_addr01, &firmware_version[0]},
+	{"QLA1080", 1, &fw1280ei_code01[0], &fw1280ei_length01,
+	 &fw1280ei_addr01, &fw1280ei_version_str[0]},
+	{"QLA1240", 2, &fw1280ei_code01[0], &fw1280ei_length01,
+	 &fw1280ei_addr01, &fw1280ei_version_str[0]},
+	{"QLA1280", 2, &fw1280ei_code01[0], &fw1280ei_length01,
+	 &fw1280ei_addr01, &fw1280ei_version_str[0]},
+	{"QLA10160", 1, &fw12160i_code01[0], &fw12160i_length01,
+	 &fw12160i_addr01, &fw12160i_version_str[0]},
+	{"        ", 0}
+};
+
+static int qla1280_verbose = 1;
+
+#if DEBUG_QLA1280
+static int ql_debug_level = 1;
+#define dprintk(level, format, a...)	\
+	do { if (ql_debug_level >= level) printk(KERN_ERR format, ##a); } while(0)
+#define qla1280_dump_buffer(level, buf, size)	\
+	if (ql_debug_level >= level) __qla1280_dump_buffer(buf, size)
+#define qla1280_print_scsi_cmd(level, cmd)	\
+	if (ql_debug_level >= level) __qla1280_print_scsi_cmd(cmd)
+#else
+#define ql_debug_level			0
+#define dprintk(level, format, a...)	do{}while(0)
+#define qla1280_dump_buffer(a, b, c)	do{}while(0)
+#define qla1280_print_scsi_cmd(a, b)	do{}while(0)
+#endif
+
+#define ENTER(x)		dprintk(3, "qla1280 : Entering %s()\n", x);
+#define LEAVE(x)		dprintk(3, "qla1280 : Leaving %s()\n", x);
+#define ENTER_INTR(x)		dprintk(4, "qla1280 : Entering %s()\n", x);
+#define LEAVE_INTR(x)		dprintk(4, "qla1280 : Leaving %s()\n", x);
+
+
+static int qla1280_read_nvram(struct scsi_qla_host *ha)
+{
+	uint16_t *wptr;
+	uint8_t chksum;
+	int cnt, i;
+	struct nvram *nv;
+
+	ENTER("qla1280_read_nvram");
+
+	if (driver_setup.no_nvram)
+		return 1;
+
+	printk(KERN_INFO "scsi(%ld): Reading NVRAM\n", ha->host_no);
+
+	wptr = (uint16_t *)&ha->nvram;
+	nv = &ha->nvram;
+	chksum = 0;
+	for (cnt = 0; cnt < 3; cnt++) {
+		*wptr = qla1280_get_nvram_word(ha, cnt);
+		chksum += *wptr & 0xff;
+		chksum += (*wptr >> 8) & 0xff;
+		wptr++;
+	}
+
+	if (nv->id0 != 'I' || nv->id1 != 'S' ||
+	    nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) {
+		dprintk(2, "Invalid nvram ID or version!\n");
+		chksum = 1;
+	} else {
+		for (; cnt < sizeof(struct nvram); cnt++) {
+			*wptr = qla1280_get_nvram_word(ha, cnt);
+			chksum += *wptr & 0xff;
+			chksum += (*wptr >> 8) & 0xff;
+			wptr++;
+		}
+	}
+
+	dprintk(3, "qla1280_read_nvram: NVRAM Magic ID= %c %c %c %02x"
+	       " version %i\n", nv->id0, nv->id1, nv->id2, nv->id3,
+	       nv->version);
+
+
+	if (chksum) {
+		if (!driver_setup.no_nvram)
+			printk(KERN_WARNING "scsi(%ld): Unable to identify or "
+			       "validate NVRAM checksum, using default "
+			       "settings\n", ha->host_no);
+		ha->nvram_valid = 0;
+	} else
+		ha->nvram_valid = 1;
+
+	/* The firmware interface is, um, interesting, in that the
+	 * actual firmware image on the chip is little endian, thus,
+	 * the process of taking that image to the CPU would end up
+	 * little endian.  However, the firmare interface requires it
+	 * to be read a word (two bytes) at a time.
+	 *
+	 * The net result of this would be that the word (and
+	 * doubleword) quantites in the firmware would be correct, but
+	 * the bytes would be pairwise reversed.  Since most of the
+	 * firmware quantites are, in fact, bytes, we do an extra
+	 * le16_to_cpu() in the firmware read routine.
+	 *
+	 * The upshot of all this is that the bytes in the firmware
+	 * are in the correct places, but the 16 and 32 bit quantites
+	 * are still in little endian format.  We fix that up below by
+	 * doing extra reverses on them */
+	nv->isp_parameter = cpu_to_le16(nv->isp_parameter);
+	nv->firmware_feature.w = cpu_to_le16(nv->firmware_feature.w);
+	for(i = 0; i < MAX_BUSES; i++) {
+		nv->bus[i].selection_timeout = cpu_to_le16(nv->bus[i].selection_timeout);
+		nv->bus[i].max_queue_depth = cpu_to_le16(nv->bus[i].max_queue_depth);
+	}
+	dprintk(1, "qla1280_read_nvram: Completed Reading NVRAM\n");
+	LEAVE("qla1280_read_nvram");
+
+	return chksum;
+}
+
+/**************************************************************************
+ *   qla1280_info
+ *     Return a string describing the driver.
+ **************************************************************************/
+static const char *
+qla1280_info(struct Scsi_Host *host)
+{
+	static char qla1280_scsi_name_buffer[125];
+	char *bp;
+	struct scsi_qla_host *ha;
+	struct qla_boards *bdp;
+
+	bp = &qla1280_scsi_name_buffer[0];
+	ha = (struct scsi_qla_host *)host->hostdata;
+	bdp = &ql1280_board_tbl[ha->devnum];
+	memset(bp, 0, sizeof(qla1280_scsi_name_buffer));
+
+	sprintf (bp,
+		 "QLogic %s PCI to SCSI Host Adapter\n"
+		 "       Firmware version: %2d.%02d.%02d, Driver version %s",
+		 &bdp->name[0], bdp->fwver[0], bdp->fwver[1], bdp->fwver[2],
+		 QLA1280_VERSION);
+	return bp;
+}
+
+/**************************************************************************
+ *   qla1200_queuecommand
+ *     Queue a command to the controller.
+ *
+ * Note:
+ * The mid-level driver tries to ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (although the
+ * interrupt handler may call this routine as part of request-completion
+ * handling).   Unfortunely, it sometimes calls the scheduler in interrupt
+ * context which is a big NO! NO!.
+ **************************************************************************/
+static int
+qla1280_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = cmd->device->host;
+	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
+	struct srb *sp = (struct srb *)&cmd->SCp;
+	int status;
+
+	cmd->scsi_done = fn;
+	sp->cmd = cmd;
+	sp->flags = 0;
+
+	qla1280_print_scsi_cmd(5, cmd);
+
+#ifdef QLA_64BIT_PTR
+	/*
+	 * Using 64 bit commands if the PCI bridge doesn't support it is a
+	 * bit wasteful, however this should really only happen if one's
+	 * PCI controller is completely broken, like the BCM1250. For
+	 * sane hardware this is not an issue.
+	 */
+	status = qla1280_64bit_start_scsi(ha, sp);
+#else
+	status = qla1280_32bit_start_scsi(ha, sp);
+#endif
+	return status;
+}
+
+enum action {
+	ABORT_COMMAND,
+	ABORT_DEVICE,
+	DEVICE_RESET,
+	BUS_RESET,
+	ADAPTER_RESET,
+	FAIL
+};
+
+/* timer action for error action processor */
+static void qla1280_error_wait_timeout(unsigned long __data)
+{
+	struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data;
+	struct srb *sp = (struct srb *)CMD_SP(cmd);
+
+	complete(sp->wait);
+}
+
+static void qla1280_mailbox_timeout(unsigned long __data)
+{
+	struct scsi_qla_host *ha = (struct scsi_qla_host *)__data;
+	struct device_reg __iomem *reg;
+	reg = ha->iobase;
+
+	ha->mailbox_out[0] = RD_REG_WORD(&reg->mailbox0);
+	printk(KERN_ERR "scsi(%ld): mailbox timed out, mailbox0 %04x, "
+	       "ictrl %04x, istatus %04x\n", ha->host_no, ha->mailbox_out[0],
+	       RD_REG_WORD(&reg->ictrl), RD_REG_WORD(&reg->istatus));
+	complete(ha->mailbox_wait);
+}
+
+/**************************************************************************
+ * qla1200_error_action
+ *    The function will attempt to perform a specified error action and
+ *    wait for the results (or time out).
+ *
+ * Input:
+ *      cmd = Linux SCSI command packet of the command that cause the
+ *            bus reset.
+ *      action = error action to take (see action_t)
+ *
+ * Returns:
+ *      SUCCESS or FAILED
+ *
+ * Note:
+ *      Resetting the bus always succeeds - is has to, otherwise the
+ *      kernel will panic! Try a surgical technique - sending a BUS
+ *      DEVICE RESET message - on the offending target before pulling
+ *      the SCSI bus reset line.
+ **************************************************************************/
+static int
+qla1280_error_action(struct scsi_cmnd *cmd, enum action action)
+{
+	struct scsi_qla_host *ha;
+	int bus, target, lun;
+	struct srb *sp;
+	uint16_t data;
+	unsigned char *handle;
+	int result, i;
+	DECLARE_COMPLETION(wait);
+	struct timer_list timer;
+
+	ha = (struct scsi_qla_host *)(CMD_HOST(cmd)->hostdata);
+
+	dprintk(4, "error_action %i, istatus 0x%04x\n", action,
+		RD_REG_WORD(&ha->iobase->istatus));
+
+	dprintk(4, "host_cmd 0x%04x, ictrl 0x%04x, jiffies %li\n",
+		RD_REG_WORD(&ha->iobase->host_cmd),
+		RD_REG_WORD(&ha->iobase->ictrl), jiffies);
+
+	ENTER("qla1280_error_action");
+	if (qla1280_verbose)
+		printk(KERN_INFO "scsi(%li): Resetting Cmnd=0x%p, "
+		       "Handle=0x%p, action=0x%x\n",
+		       ha->host_no, cmd, CMD_HANDLE(cmd), action);
+
+	if (cmd == NULL) {
+		printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL "
+		       "si_Cmnd pointer, failing.\n");
+		LEAVE("qla1280_error_action");
+		return FAILED;
+	}
+
+	ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
+	sp = (struct srb *)CMD_SP(cmd);
+	handle = CMD_HANDLE(cmd);
+
+	/* Check for pending interrupts. */
+	data = qla1280_debounce_register(&ha->iobase->istatus);
+	/*
+	 * The io_request_lock is held when the reset handler is called, hence
+	 * the interrupt handler cannot be running in parallel as it also
+	 * grabs the lock. /Jes
+	 */
+	if (data & RISC_INT)
+		qla1280_isr(ha, &ha->done_q);
+
+	/*
+	 * Determine the suggested action that the mid-level driver wants
+	 * us to perform.
+	 */
+	if (handle == (unsigned char *)INVALID_HANDLE || handle == NULL) {
+		if(action == ABORT_COMMAND) {
+			/* we never got this command */
+			printk(KERN_INFO "qla1280: Aborting a NULL handle\n");
+			return SUCCESS;	/* no action - we don't have command */
+		}
+	} else {
+		sp->wait = &wait;
+	}
+
+	bus = SCSI_BUS_32(cmd);
+	target = SCSI_TCN_32(cmd);
+	lun = SCSI_LUN_32(cmd);
+
+	/* Overloading result.  Here it means the success or fail of the
+	 * *issue* of the action.  When we return from the routine, it must
+	 * mean the actual success or fail of the action */
+	result = FAILED;
+	switch (action) {
+	case FAIL:
+		break;
+
+	case ABORT_COMMAND:
+		if ((sp->flags & SRB_ABORT_PENDING)) {
+			printk(KERN_WARNING
+			       "scsi(): Command has a pending abort "
+			       "message - ABORT_PENDING.\n");
+			/* This should technically be impossible since we
+			 * now wait for abort completion */
+			break;
+		}
+
+		for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
+			if (sp == ha->outstanding_cmds[i]) {
+				dprintk(1, "qla1280: RISC aborting command\n");
+				if (qla1280_abort_command(ha, sp, i) == 0)
+					result = SUCCESS;
+				else {
+					/*
+					 * Since we don't know what might
+					 * have happend to the command, it
+					 * is unsafe to remove it from the
+					 * device's queue at this point.
+					 * Wait and let the escalation
+					 * process take care of it.
+					 */
+					printk(KERN_WARNING
+					       "scsi(%li:%i:%i:%i): Unable"
+					       " to abort command!\n",
+					       ha->host_no, bus, target, lun);
+				}
+			}
+		}
+		break;
+
+	case ABORT_DEVICE:
+		ha->flags.in_reset = 1;
+		if (qla1280_verbose)
+			printk(KERN_INFO
+			       "scsi(%ld:%d:%d:%d): Queueing abort device "
+			       "command.\n", ha->host_no, bus, target, lun);
+		if (qla1280_abort_device(ha, bus, target, lun) == 0)
+			result = SUCCESS;
+		break;
+
+	case DEVICE_RESET:
+		if (qla1280_verbose)
+			printk(KERN_INFO
+			       "scsi(%ld:%d:%d:%d): Queueing device reset "
+			       "command.\n", ha->host_no, bus, target, lun);
+		ha->flags.in_reset = 1;
+		if (qla1280_device_reset(ha, bus, target) == 0)
+			result = SUCCESS;
+		break;
+
+	case BUS_RESET:
+		if (qla1280_verbose)
+			printk(KERN_INFO "qla1280(%ld:%d): Issuing BUS "
+			       "DEVICE RESET\n", ha->host_no, bus);
+		ha->flags.in_reset = 1;
+		if (qla1280_bus_reset(ha, bus == 0))
+			result = SUCCESS;
+
+		break;
+
+	case ADAPTER_RESET:
+	default:
+		if (qla1280_verbose) {
+			printk(KERN_INFO
+			       "scsi(%ld): Issued ADAPTER RESET\n",
+			       ha->host_no);
+			printk(KERN_INFO "scsi(%ld): I/O processing will "
+			       "continue automatically\n", ha->host_no);
+		}
+		ha->flags.reset_active = 1;
+		/*
+		 * We restarted all of the commands automatically, so the
+		 * mid-level code can expect completions momentitarily.
+		 */
+		if (qla1280_abort_isp(ha) == 0)
+			result = SUCCESS;
+
+		ha->flags.reset_active = 0;
+	}
+
+	if (!list_empty(&ha->done_q))
+		qla1280_done(ha);
+	ha->flags.in_reset = 0;
+
+	/* If we didn't manage to issue the action, or we have no
+	 * command to wait for, exit here */
+	if (result == FAILED || handle == NULL ||
+	    handle == (unsigned char *)INVALID_HANDLE) {
+		/*
+		 * Clear completion queue to avoid qla1280_done() trying
+		 * to complete the command at a later stage after we
+		 * have exited the current context
+		 */
+		sp->wait = NULL;
+		goto leave;
+	}
+
+	/* set up a timer just in case we're really jammed */
+	init_timer(&timer);
+	timer.expires = jiffies + 4*HZ;
+	timer.data = (unsigned long)cmd;
+	timer.function = qla1280_error_wait_timeout;
+	add_timer(&timer);
+
+	/* wait for the action to complete (or the timer to expire) */
+	spin_unlock_irq(HOST_LOCK);
+	wait_for_completion(&wait);
+	del_timer_sync(&timer);
+	spin_lock_irq(HOST_LOCK);
+	sp->wait = NULL;
+
+	/* the only action we might get a fail for is abort */
+	if (action == ABORT_COMMAND) {
+		if(sp->flags & SRB_ABORTED)
+			result = SUCCESS;
+		else
+			result = FAILED;
+	}
+
+ leave:
+	dprintk(1, "RESET returning %d\n", result);
+
+	LEAVE("qla1280_error_action");
+	return result;
+}
+
+/**************************************************************************
+ *   qla1280_abort
+ *     Abort the specified SCSI command(s).
+ **************************************************************************/
+static int
+qla1280_eh_abort(struct scsi_cmnd * cmd)
+{
+	return qla1280_error_action(cmd, ABORT_COMMAND);
+}
+
+/**************************************************************************
+ *   qla1280_device_reset
+ *     Reset the specified SCSI device
+ **************************************************************************/
+static int
+qla1280_eh_device_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, DEVICE_RESET);
+}
+
+/**************************************************************************
+ *   qla1280_bus_reset
+ *     Reset the specified bus.
+ **************************************************************************/
+static int
+qla1280_eh_bus_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, BUS_RESET);
+}
+
+/**************************************************************************
+ *   qla1280_adapter_reset
+ *     Reset the specified adapter (both channels)
+ **************************************************************************/
+static int
+qla1280_eh_adapter_reset(struct scsi_cmnd *cmd)
+{
+	return qla1280_error_action(cmd, ADAPTER_RESET);
+}
+
+static int
+qla1280_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		  sector_t capacity, int geom[])
+{
+	int heads, sectors, cylinders;
+
+	heads = 64;
+	sectors = 32;
+	cylinders = (unsigned long)capacity / (heads * sectors);
+	if (cylinders > 1024) {
+		heads = 255;
+		sectors = 63;
+		cylinders = (unsigned long)capacity / (heads * sectors);
+		/* if (cylinders > 1023)
+		   cylinders = 1023; */
+	}
+
+	geom[0] = heads;
+	geom[1] = sectors;
+	geom[2] = cylinders;
+
+	return 0;
+}
+
+#if LINUX_VERSION_CODE < 0x020600
+static int
+qla1280_detect(Scsi_Host_Template *template)
+{
+	struct pci_device_id *id = &qla1280_pci_tbl[0];
+	struct pci_dev *pdev = NULL;
+	int num_hosts = 0;
+
+	if (sizeof(struct srb) > sizeof(Scsi_Pointer)) {
+		printk(KERN_WARNING
+		       "qla1280: struct srb too big, aborting\n");
+		return 0;
+	}
+
+	if ((DMA_BIDIRECTIONAL != PCI_DMA_BIDIRECTIONAL) ||
+	    (DMA_TO_DEVICE != PCI_DMA_TODEVICE) ||
+	    (DMA_FROM_DEVICE != PCI_DMA_FROMDEVICE) ||
+	    (DMA_NONE != PCI_DMA_NONE)) {
+		printk(KERN_WARNING
+		       "qla1280: dma direction bits don't match\n");
+		return 0;
+	}
+
+#ifdef MODULE
+	/*
+	 * If we are called as a module, the qla1280 pointer may not be null
+	 * and it would point to our bootup string, just like on the lilo
+	 * command line.  IF not NULL, then process this config string with
+	 * qla1280_setup
+	 *
+	 * Boot time Options
+	 * To add options at boot time add a line to your lilo.conf file like:
+	 * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}"
+	 * which will result in the first four devices on the first two
+	 * controllers being set to a tagged queue depth of 32.
+	 */
+	if (qla1280)
+		qla1280_setup(qla1280);
+#endif
+
+	/* First Initialize QLA12160 on PCI Bus 1 Dev 2 */
+	while ((pdev = pci_find_device(id->vendor, id->device, pdev))) {
+		if (pdev->bus->number == 1 && PCI_SLOT(pdev->devfn) == 2) {
+			if (!qla1280_probe_one(pdev, id))
+				num_hosts++;
+		}
+	}
+
+	pdev = NULL;
+	/* Try and find each different type of adapter we support */
+	for (id = &qla1280_pci_tbl[0]; id->device; id++) {
+		while ((pdev = pci_find_device(id->vendor, id->device, pdev))) {
+			/*
+			 * skip QLA12160 already initialized on
+			 * PCI Bus 1 Dev 2 since we already initialized
+			 * and presented it
+			 */
+			if (id->device == PCI_DEVICE_ID_QLOGIC_ISP12160 &&
+			    pdev->bus->number == 1 &&
+			    PCI_SLOT(pdev->devfn) == 2)
+				continue;
+
+			if (!qla1280_probe_one(pdev, id))
+				num_hosts++;
+		}
+	}
+
+	return num_hosts;
+}
+
+/*
+ * This looks a bit ugly as we could just pass down host to
+ * qla1280_remove_one, but I want to keep qla1280_release purely a wrapper
+ * around pci_driver::remove as used from 2.6 onwards.
+ */
+static int
+qla1280_release(struct Scsi_Host *host)
+{
+	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
+
+	qla1280_remove_one(ha->pdev);
+	return 0;
+}
+
+static int
+qla1280_biosparam_old(Disk * disk, kdev_t dev, int geom[])
+{
+	return qla1280_biosparam(disk->device, NULL, disk->capacity, geom);
+}
+#endif
+
+/**************************************************************************
+ * qla1280_intr_handler
+ *   Handles the H/W interrupt
+ **************************************************************************/
+static irqreturn_t
+qla1280_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct scsi_qla_host *ha;
+	struct device_reg __iomem *reg;
+	u16 data;
+	int handled = 0;
+
+	ENTER_INTR ("qla1280_intr_handler");
+	ha = (struct scsi_qla_host *)dev_id;
+
+	spin_lock(HOST_LOCK);
+
+	ha->isr_count++;
+	reg = ha->iobase;
+
+	WRT_REG_WORD(&reg->ictrl, 0);	/* disable our interrupt. */
+
+	data = qla1280_debounce_register(&reg->istatus);
+	/* Check for pending interrupts. */
+	if (data & RISC_INT) {	
+		qla1280_isr(ha, &ha->done_q);
+		handled = 1;
+	}
+	if (!list_empty(&ha->done_q))
+		qla1280_done(ha);
+
+	spin_unlock(HOST_LOCK);
+
+	/* enable our interrupt. */
+	WRT_REG_WORD(&reg->ictrl, (ISP_EN_INT | ISP_EN_RISC));
+
+	LEAVE_INTR("qla1280_intr_handler");
+	return IRQ_RETVAL(handled);
+}
+
+
+static int
+qla1280_set_target_parameters(struct scsi_qla_host *ha, int bus, int target)
+{
+	uint8_t mr;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	struct nvram *nv;
+	int status;
+
+	nv = &ha->nvram;
+
+	mr = BIT_3 | BIT_2 | BIT_1 | BIT_0;
+
+	/* Set Target Parameters. */
+	mb[0] = MBC_SET_TARGET_PARAMETERS;
+	mb[1] = (uint16_t) (bus ? target | BIT_7 : target);
+	mb[1] <<= 8;
+
+	mb[2] = (nv->bus[bus].target[target].parameter.c << 8);
+
+	if (IS_ISP1x160(ha)) {
+		mb[2] |= nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr << 5;
+		mb[3] =	(nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8) |
+			 nv->bus[bus].target[target].sync_period;
+		mb[6] =	(nv->bus[bus].target[target].ppr_1x160.flags.ppr_options << 8) |
+			 nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width;
+		mr |= BIT_6;
+	} else {
+		mb[3] =	(nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8) |
+			 nv->bus[bus].target[target].sync_period;
+	}
+
+	status = qla1280_mailbox_command(ha, mr, &mb[0]);
+
+	if (status)
+		printk(KERN_WARNING "scsi(%ld:%i:%i): "
+		       "qla1280_set_target_parameters() failed\n",
+		       ha->host_no, bus, target);
+	return status;
+}
+
+
+/**************************************************************************
+ *   qla1280_slave_configure
+ *
+ * Description:
+ *   Determines the queue depth for a given device.  There are two ways
+ *   a queue depth can be obtained for a tagged queueing device.  One
+ *   way is the default queue depth which is determined by whether
+ *   If it is defined, then it is used
+ *   as the default queue depth.  Otherwise, we use either 4 or 8 as the
+ *   default queue depth (dependent on the number of hardware SCBs).
+ **************************************************************************/
+static int
+qla1280_slave_configure(struct scsi_device *device)
+{
+	struct scsi_qla_host *ha;
+	int default_depth = 3;
+	int bus = device->channel;
+	int target = device->id;
+	int status = 0;
+	struct nvram *nv;
+	unsigned long flags;
+
+	ha = (struct scsi_qla_host *)device->host->hostdata;
+	nv = &ha->nvram;
+
+	if (qla1280_check_for_dead_scsi_bus(ha, bus))
+		return 1;
+
+	if (device->tagged_supported &&
+	    (ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) {
+		scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
+					ha->bus_settings[bus].hiwat);
+	} else {
+		scsi_adjust_queue_depth(device, 0, default_depth);
+	}
+
+#if LINUX_VERSION_CODE > 0x020500
+	nv->bus[bus].target[target].parameter.f.enable_sync = device->sdtr;
+	nv->bus[bus].target[target].parameter.f.enable_wide = device->wdtr;
+	nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = device->ppr;
+#endif
+
+	if (driver_setup.no_sync ||
+	    (driver_setup.sync_mask &&
+	     (~driver_setup.sync_mask & (1 << target))))
+		nv->bus[bus].target[target].parameter.f.enable_sync = 0;
+	if (driver_setup.no_wide ||
+	    (driver_setup.wide_mask &&
+	     (~driver_setup.wide_mask & (1 << target))))
+		nv->bus[bus].target[target].parameter.f.enable_wide = 0;
+	if (IS_ISP1x160(ha)) {
+		if (driver_setup.no_ppr ||
+		    (driver_setup.ppr_mask &&
+		     (~driver_setup.ppr_mask & (1 << target))))
+			nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
+	}
+
+	spin_lock_irqsave(HOST_LOCK, flags);
+	if (nv->bus[bus].target[target].parameter.f.enable_sync)
+		status = qla1280_set_target_parameters(ha, bus, target);
+	qla1280_get_target_parameters(ha, device);
+	spin_unlock_irqrestore(HOST_LOCK, flags);
+	return status;
+}
+
+#if LINUX_VERSION_CODE < 0x020545
+/**************************************************************************
+ *   qla1280_select_queue_depth
+ *
+ *   Sets the queue depth for each SCSI device hanging off the input
+ *   host adapter.  We use a queue depth of 2 for devices that do not
+ *   support tagged queueing.
+ **************************************************************************/
+static void
+qla1280_select_queue_depth(struct Scsi_Host *host, struct scsi_device *sdev_q)
+{
+	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
+	struct scsi_device *sdev;
+
+	ENTER("qla1280_select_queue_depth");
+	for (sdev = sdev_q; sdev; sdev = sdev->next)
+		if (sdev->host == host)
+			qla1280_slave_configure(sdev);
+
+	if (sdev_q)
+		qla1280_check_for_dead_scsi_bus(ha, sdev_q->channel);
+	LEAVE("qla1280_select_queue_depth");
+}
+#endif
+
+/*
+ * qla1280_done
+ *      Process completed commands.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *      done_q       = done queue.
+ */
+static void
+qla1280_done(struct scsi_qla_host *ha)
+{
+	struct srb *sp;
+	struct list_head *done_q;
+	int bus, target, lun;
+	struct scsi_cmnd *cmd;
+
+	ENTER("qla1280_done");
+
+	done_q = &ha->done_q;
+
+	while (!list_empty(done_q)) {
+		sp = list_entry(done_q->next, struct srb, list);
+
+		list_del(&sp->list);
+	
+		cmd = sp->cmd;
+		bus = SCSI_BUS_32(cmd);
+		target = SCSI_TCN_32(cmd);
+		lun = SCSI_LUN_32(cmd);
+
+		switch ((CMD_RESULT(cmd) >> 16)) {
+		case DID_RESET:
+			/* Issue marker command. */
+			qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
+			break;
+		case DID_ABORT:
+			sp->flags &= ~SRB_ABORT_PENDING;
+			sp->flags |= SRB_ABORTED;
+			if (sp->flags & SRB_TIMEOUT)
+				CMD_RESULT(sp->cmd) = DID_TIME_OUT << 16;
+			break;
+		default:
+			break;
+		}
+
+		/* Release memory used for this I/O */
+		if (cmd->use_sg) {
+			pci_unmap_sg(ha->pdev, cmd->request_buffer,
+					cmd->use_sg, cmd->sc_data_direction);
+		} else if (cmd->request_bufflen) {
+			pci_unmap_single(ha->pdev, sp->saved_dma_handle,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
+		}
+
+		/* Call the mid-level driver interrupt handler */
+		CMD_HANDLE(sp->cmd) = (unsigned char *)INVALID_HANDLE;
+		ha->actthreads--;
+
+#if LINUX_VERSION_CODE < 0x020500
+		if (cmd->cmnd[0] == INQUIRY)
+			qla1280_get_target_options(cmd, ha);
+#endif
+		(*(cmd)->scsi_done)(cmd);
+
+		if(sp->wait != NULL)
+			complete(sp->wait);
+	}
+	LEAVE("qla1280_done");
+}
+
+/*
+ * Translates a ISP error to a Linux SCSI error
+ */
+static int
+qla1280_return_status(struct response * sts, struct scsi_cmnd *cp)
+{
+	int host_status = DID_ERROR;
+	uint16_t comp_status = le16_to_cpu(sts->comp_status);
+	uint16_t state_flags = le16_to_cpu(sts->state_flags);
+	uint16_t residual_length = le16_to_cpu(sts->residual_length);
+	uint16_t scsi_status = le16_to_cpu(sts->scsi_status);
+#if DEBUG_QLA1280_INTR
+	static char *reason[] = {
+		"DID_OK",
+		"DID_NO_CONNECT",
+		"DID_BUS_BUSY",
+		"DID_TIME_OUT",
+		"DID_BAD_TARGET",
+		"DID_ABORT",
+		"DID_PARITY",
+		"DID_ERROR",
+		"DID_RESET",
+		"DID_BAD_INTR"
+	};
+#endif				/* DEBUG_QLA1280_INTR */
+
+	ENTER("qla1280_return_status");
+
+#if DEBUG_QLA1280_INTR
+	/*
+	  dprintk(1, "qla1280_return_status: compl status = 0x%04x\n",
+	  comp_status);
+	*/
+#endif
+
+	switch (comp_status) {
+	case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+
+	case CS_INCOMPLETE:
+		if (!(state_flags & SF_GOT_BUS))
+			host_status = DID_NO_CONNECT;
+		else if (!(state_flags & SF_GOT_TARGET))
+			host_status = DID_BAD_TARGET;
+		else if (!(state_flags & SF_SENT_CDB))
+			host_status = DID_ERROR;
+		else if (!(state_flags & SF_TRANSFERRED_DATA))
+			host_status = DID_ERROR;
+		else if (!(state_flags & SF_GOT_STATUS))
+			host_status = DID_ERROR;
+		else if (!(state_flags & SF_GOT_SENSE))
+			host_status = DID_ERROR;
+		break;
+
+	case CS_RESET:
+		host_status = DID_RESET;
+		break;
+
+	case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+
+	case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+
+	case CS_DATA_OVERRUN:
+		dprintk(2, "Data overrun 0x%x\n", residual_length);
+		dprintk(2, "qla1280_isr: response packet data\n");
+		qla1280_dump_buffer(2, (char *)sts, RESPONSE_ENTRY_SIZE);
+		host_status = DID_ERROR;
+		break;
+
+	case CS_DATA_UNDERRUN:
+		if ((cp->request_bufflen - residual_length) <
+		    cp->underflow) {
+			printk(KERN_WARNING
+			       "scsi: Underflow detected - retrying "
+			       "command.\n");
+			host_status = DID_ERROR;
+		} else
+			host_status = DID_OK;
+		break;
+
+	default:
+		host_status = DID_ERROR;
+		break;
+	}
+
+#if DEBUG_QLA1280_INTR
+	dprintk(1, "qla1280 ISP status: host status (%s) scsi status %x\n",
+		reason[host_status], scsi_status);
+#endif
+
+	LEAVE("qla1280_return_status");
+
+	return (scsi_status & 0xff) | (host_status << 16);
+}
+
+/****************************************************************************/
+/*                QLogic ISP1280 Hardware Support Functions.                */
+/****************************************************************************/
+
+ /*
+  * qla2100_enable_intrs
+  * qla2100_disable_intrs
+  *
+  * Input:
+  *      ha = adapter block pointer.
+  *
+  * Returns:
+  *      None
+  */
+static inline void
+qla1280_enable_intrs(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg;
+
+	reg = ha->iobase;
+	/* enable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, (ISP_EN_INT | ISP_EN_RISC));
+	RD_REG_WORD(&reg->ictrl);	/* PCI Posted Write flush */
+	ha->flags.ints_enabled = 1;
+}
+
+static inline void
+qla1280_disable_intrs(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg;
+
+	reg = ha->iobase;
+	/* disable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, 0);
+	RD_REG_WORD(&reg->ictrl);	/* PCI Posted Write flush */
+	ha->flags.ints_enabled = 0;
+}
+
+/*
+ * qla1280_initialize_adapter
+ *      Initialize board.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int __devinit
+qla1280_initialize_adapter(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg;
+	int status;
+	int bus;
+#if LINUX_VERSION_CODE > 0x020500
+	unsigned long flags;
+#endif
+
+	ENTER("qla1280_initialize_adapter");
+
+	/* Clear adapter flags. */
+	ha->flags.online = 0;
+	ha->flags.disable_host_adapter = 0;
+	ha->flags.reset_active = 0;
+	ha->flags.abort_isp_active = 0;
+
+	ha->flags.ints_enabled = 0;
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+	if (ia64_platform_is("sn2")) {
+		printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
+		       "dual channel lockup workaround\n", ha->host_no);
+		ha->flags.use_pci_vchannel = 1;
+		driver_setup.no_nvram = 1;
+	}
+#endif
+
+	/* TODO: implement support for the 1040 nvram format */
+	if (IS_ISP1040(ha))
+		driver_setup.no_nvram = 1;
+
+	dprintk(1, "Configure PCI space for adapter...\n");
+
+	reg = ha->iobase;
+
+	/* Insure mailbox registers are free. */
+	WRT_REG_WORD(&reg->semaphore, 0);
+	WRT_REG_WORD(&reg->host_cmd, HC_CLR_RISC_INT);
+	WRT_REG_WORD(&reg->host_cmd, HC_CLR_HOST_INT);
+	RD_REG_WORD(&reg->host_cmd);
+
+	if (qla1280_read_nvram(ha)) {
+		dprintk(2, "qla1280_initialize_adapter: failed to read "
+			"NVRAM\n");
+	}
+
+#if LINUX_VERSION_CODE >= 0x020500
+	/*
+	 * It's necessary to grab the spin here as qla1280_mailbox_command
+	 * needs to be able to drop the lock unconditionally to wait
+	 * for completion.
+	 * In 2.4 ->detect is called with the io_request_lock held.
+	 */
+	spin_lock_irqsave(HOST_LOCK, flags);
+#endif
+
+	status = qla1280_load_firmware(ha);
+	if (status) {
+		printk(KERN_ERR "scsi(%li): initialize: pci probe failed!\n",
+		       ha->host_no);
+		goto out;
+	}
+
+	/* Setup adapter based on NVRAM parameters. */
+	dprintk(1, "scsi(%ld): Configure NVRAM parameters\n", ha->host_no);
+	qla1280_nvram_config(ha);
+
+	if (ha->flags.disable_host_adapter) {
+		status = 1;
+		goto out;
+	}
+
+	status = qla1280_init_rings(ha);
+	if (status)
+		goto out;
+
+	/* Issue SCSI reset, if we can't reset twice then bus is dead */
+	for (bus = 0; bus < ha->ports; bus++) {
+		if (!ha->bus_settings[bus].disable_scsi_reset &&
+		    qla1280_bus_reset(ha, bus) &&
+		    qla1280_bus_reset(ha, bus))
+			ha->bus_settings[bus].scsi_bus_dead = 1;
+	}
+
+	ha->flags.online = 1;
+ out:
+#if LINUX_VERSION_CODE >= 0x020500
+	spin_unlock_irqrestore(HOST_LOCK, flags);
+#endif
+	if (status)
+		dprintk(2, "qla1280_initialize_adapter: **** FAILED ****\n");
+
+	LEAVE("qla1280_initialize_adapter");
+	return status;
+}
+
+
+/*
+ * ISP Firmware Test
+ *      Checks if present version of RISC firmware is older than
+ *      driver firmware.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *
+ * Returns:
+ *      0 = firmware does not need to be loaded.
+ */
+static int
+qla1280_isp_firmware(struct scsi_qla_host *ha)
+{
+	struct nvram *nv = (struct nvram *) ha->response_ring;
+	int status = 0;		/* dg 2/27 always loads RISC */
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+	ENTER("qla1280_isp_firmware");
+
+	dprintk(1, "scsi(%li): Determining if RISC is loaded\n", ha->host_no);
+
+	/* Bad NVRAM data, load RISC code. */
+	if (!ha->nvram_valid) {
+		ha->flags.disable_risc_code_load = 0;
+	} else
+		ha->flags.disable_risc_code_load =
+			nv->cntr_flags_1.disable_loading_risc_code;
+
+	if (ha->flags.disable_risc_code_load) {
+		dprintk(3, "qla1280_isp_firmware: Telling RISC to verify "
+			"checksum of loaded BIOS code.\n");
+
+		/* Verify checksum of loaded RISC code. */
+		mb[0] = MBC_VERIFY_CHECKSUM;
+		/* mb[1] = ql12_risc_code_addr01; */
+		mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
+
+		if (!(status =
+		      qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]))) {
+			/* Start firmware execution. */
+			dprintk(3, "qla1280_isp_firmware: Startng F/W "
+				"execution.\n");
+
+			mb[0] = MBC_EXECUTE_FIRMWARE;
+			/* mb[1] = ql12_risc_code_addr01; */
+			mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
+			qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+		} else
+			printk(KERN_INFO "qla1280: RISC checksum failed.\n");
+	} else {
+		dprintk(1, "qla1280: NVRAM configured to load RISC load.\n");
+		status = 1;
+	}
+
+	if (status)
+		dprintk(2, "qla1280_isp_firmware: **** Load RISC code ****\n");
+
+	LEAVE("qla1280_isp_firmware");
+	return status;
+}
+
+/*
+ * Chip diagnostics
+ *      Test chip for proper operation.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success.
+ */
+static int
+qla1280_chip_diag(struct scsi_qla_host *ha)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	struct device_reg __iomem *reg = ha->iobase;
+	int status = 0;
+	int cnt;
+	uint16_t data;
+	dprintk(3, "qla1280_chip_diag: testing device at 0x%p \n", &reg->id_l);
+
+	dprintk(1, "scsi(%ld): Verifying chip\n", ha->host_no);
+
+	/* Soft reset chip and wait for it to finish. */
+	WRT_REG_WORD(&reg->ictrl, ISP_RESET);
+
+	/*
+	 * We can't do a traditional PCI write flush here by reading
+	 * back the register. The card will not respond once the reset
+	 * is in action and we end up with a machine check exception
+	 * instead. Nothing to do but wait and hope for the best.
+	 * A portable pci_write_flush(pdev) call would be very useful here.
+	 */
+	udelay(20);
+	data = qla1280_debounce_register(&reg->ictrl);
+	/*
+	 * Yet another QLogic gem ;-(
+	 */
+	for (cnt = 1000000; cnt && data & ISP_RESET; cnt--) {
+		udelay(5);
+		data = RD_REG_WORD(&reg->ictrl);
+	}
+
+	if (!cnt)
+		goto fail;
+
+	/* Reset register cleared by chip reset. */
+	dprintk(3, "qla1280_chip_diag: reset register cleared by chip reset\n");
+
+	WRT_REG_WORD(&reg->cfg_1, 0);
+
+	/* Reset RISC and disable BIOS which
+	   allows RISC to execute out of RAM. */
+	WRT_REG_WORD(&reg->host_cmd, HC_RESET_RISC |
+		     HC_RELEASE_RISC | HC_DISABLE_BIOS);
+
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+	data = qla1280_debounce_register(&reg->mailbox0);
+
+	/*
+	 * I *LOVE* this code!
+	 */
+	for (cnt = 1000000; cnt && data == MBS_BUSY; cnt--) {
+		udelay(5);
+		data = RD_REG_WORD(&reg->mailbox0);
+	}
+
+	if (!cnt)
+		goto fail;
+
+	/* Check product ID of chip */
+	dprintk(3, "qla1280_chip_diag: Checking product ID of chip\n");
+
+	if (RD_REG_WORD(&reg->mailbox1) != PROD_ID_1 ||
+	    (RD_REG_WORD(&reg->mailbox2) != PROD_ID_2 &&
+	     RD_REG_WORD(&reg->mailbox2) != PROD_ID_2a) ||
+	    RD_REG_WORD(&reg->mailbox3) != PROD_ID_3 ||
+	    RD_REG_WORD(&reg->mailbox4) != PROD_ID_4) {
+		printk(KERN_INFO "qla1280: Wrong product ID = "
+		       "0x%x,0x%x,0x%x,0x%x\n",
+		       RD_REG_WORD(&reg->mailbox1),
+		       RD_REG_WORD(&reg->mailbox2),
+		       RD_REG_WORD(&reg->mailbox3),
+		       RD_REG_WORD(&reg->mailbox4));
+		goto fail;
+	}
+
+	/*
+	 * Enable ints early!!!
+	 */
+	qla1280_enable_intrs(ha);
+
+	dprintk(1, "qla1280_chip_diag: Checking mailboxes of chip\n");
+	/* Wrap Incoming Mailboxes Test. */
+	mb[0] = MBC_MAILBOX_REGISTER_TEST;
+	mb[1] = 0xAAAA;
+	mb[2] = 0x5555;
+	mb[3] = 0xAA55;
+	mb[4] = 0x55AA;
+	mb[5] = 0xA5A5;
+	mb[6] = 0x5A5A;
+	mb[7] = 0x2525;
+
+	status = qla1280_mailbox_command(ha, 0xff, mb);
+	if (status)
+		goto fail;
+
+	if (mb[1] != 0xAAAA || mb[2] != 0x5555 || mb[3] != 0xAA55 ||
+	    mb[4] != 0x55AA || mb[5] != 0xA5A5 || mb[6] != 0x5A5A ||
+	    mb[7] != 0x2525) {
+		printk(KERN_INFO "qla1280: Failed mbox check\n");
+		goto fail;
+	}
+
+	dprintk(3, "qla1280_chip_diag: exiting normally\n");
+	return 0;
+ fail:
+	dprintk(2, "qla1280_chip_diag: **** FAILED ****\n");
+	return status;
+}
+
+static int
+qla1280_load_firmware_pio(struct scsi_qla_host *ha)
+{
+	uint16_t risc_address, *risc_code_address, risc_code_size;
+	uint16_t mb[MAILBOX_REGISTER_COUNT], i;
+	int err;
+
+	/* Load RISC code. */
+	risc_address = *ql1280_board_tbl[ha->devnum].fwstart;
+	risc_code_address = ql1280_board_tbl[ha->devnum].fwcode;
+	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
+
+	for (i = 0; i < risc_code_size; i++) {
+		mb[0] = MBC_WRITE_RAM_WORD;
+		mb[1] = risc_address + i;
+		mb[2] = risc_code_address[i];
+
+		err = qla1280_mailbox_command(ha, BIT_0 | BIT_1 | BIT_2, mb);
+		if (err) {
+			printk(KERN_ERR "scsi(%li): Failed to load firmware\n",
+					ha->host_no);
+			return err;
+		}
+	}
+
+	return 0;
+}
+
+#define DUMP_IT_BACK 0		/* for debug of RISC loading */
+static int
+qla1280_load_firmware_dma(struct scsi_qla_host *ha)
+{
+	uint16_t risc_address, *risc_code_address, risc_code_size;
+	uint16_t mb[MAILBOX_REGISTER_COUNT], cnt;
+	int err = 0, num, i;
+#if DUMP_IT_BACK
+	uint8_t *sp, *tbuf;
+	dma_addr_t p_tbuf;
+
+	tbuf = pci_alloc_consistent(ha->pdev, 8000, &p_tbuf);
+	if (!tbuf)
+		return -ENOMEM;
+#endif
+
+	/* Load RISC code. */
+	risc_address = *ql1280_board_tbl[ha->devnum].fwstart;
+	risc_code_address = ql1280_board_tbl[ha->devnum].fwcode;
+	risc_code_size = *ql1280_board_tbl[ha->devnum].fwlen;
+
+	dprintk(1, "%s: DMA RISC code (%i) words\n",
+			__FUNCTION__, risc_code_size);
+
+	num = 0;
+	while (risc_code_size > 0) {
+		int warn __attribute__((unused)) = 0;
+
+		cnt = 2000 >> 1;
+
+		if (cnt > risc_code_size)
+			cnt = risc_code_size;
+
+		dprintk(2, "qla1280_setup_chip:  loading risc @ =(0x%p),"
+			"%d,%d(0x%x)\n",
+			risc_code_address, cnt, num, risc_address);
+		for(i = 0; i < cnt; i++)
+			((uint16_t *)ha->request_ring)[i] =
+				cpu_to_le16(risc_code_address[i]);
+
+		mb[0] = MBC_LOAD_RAM;
+		mb[1] = risc_address;
+		mb[4] = cnt;
+		mb[3] = ha->request_dma & 0xffff;
+		mb[2] = (ha->request_dma >> 16) & 0xffff;
+		mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
+		mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
+		dprintk(2, "%s: op=%d  0x%p = 0x%4x,0x%4x,0x%4x,0x%4x\n",
+				__FUNCTION__, mb[0],
+				(void *)(long)ha->request_dma,
+				mb[6], mb[7], mb[2], mb[3]);
+		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
+				BIT_1 | BIT_0, mb);
+		if (err) {
+			printk(KERN_ERR "scsi(%li): Failed to load partial "
+			       "segment of f\n", ha->host_no);
+			goto out;
+		}
+
+#if DUMP_IT_BACK
+		mb[0] = MBC_DUMP_RAM;
+		mb[1] = risc_address;
+		mb[4] = cnt;
+		mb[3] = p_tbuf & 0xffff;
+		mb[2] = (p_tbuf >> 16) & 0xffff;
+		mb[7] = pci_dma_hi32(p_tbuf) & 0xffff;
+		mb[6] = pci_dma_hi32(p_tbuf) >> 16;
+
+		err = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 |
+				BIT_1 | BIT_0, mb);
+		if (err) {
+			printk(KERN_ERR
+			       "Failed to dump partial segment of f/w\n");
+			goto out;
+		}
+		sp = (uint8_t *)ha->request_ring;
+		for (i = 0; i < (cnt << 1); i++) {
+			if (tbuf[i] != sp[i] && warn++ < 10) {
+				printk(KERN_ERR "%s: FW compare error @ "
+						"byte(0x%x) loop#=%x\n",
+						__FUNCTION__, i, num);
+				printk(KERN_ERR "%s: FWbyte=%x  "
+						"FWfromChip=%x\n",
+						__FUNCTION__, sp[i], tbuf[i]);
+				/*break; */
+			}
+		}
+#endif
+		risc_address += cnt;
+		risc_code_size = risc_code_size - cnt;
+		risc_code_address = risc_code_address + cnt;
+		num++;
+	}
+
+ out:
+#if DUMP_IT_BACK
+	pci_free_consistent(ha->pdev, 8000, tbuf, p_tbuf);
+#endif
+	return err;
+}
+
+static int
+qla1280_start_firmware(struct scsi_qla_host *ha)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int err;
+
+	dprintk(1, "%s: Verifying checksum of loaded RISC code.\n",
+			__FUNCTION__);
+
+	/* Verify checksum of loaded RISC code. */
+	mb[0] = MBC_VERIFY_CHECKSUM;
+	/* mb[1] = ql12_risc_code_addr01; */
+	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
+	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
+	if (err) {
+		printk(KERN_ERR "scsi(%li): Failed checksum\n", ha->host_no);
+		return err;
+	}
+
+	/* Start firmware execution. */
+	dprintk(1, "%s: start firmware running.\n", __FUNCTION__);
+	mb[0] = MBC_EXECUTE_FIRMWARE;
+	mb[1] = *ql1280_board_tbl[ha->devnum].fwstart;
+	err = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+	if (err) {
+		printk(KERN_ERR "scsi(%li): Failed to start firmware\n",
+				ha->host_no);
+	}
+
+	return err;
+}
+
+static int
+qla1280_load_firmware(struct scsi_qla_host *ha)
+{
+	int err = -ENODEV;
+
+	/* If firmware needs to be loaded */
+	if (!qla1280_isp_firmware(ha)) {
+		printk(KERN_ERR "scsi(%li): isp_firmware() failed!\n",
+				ha->host_no);
+		goto out;
+	}
+
+	err = qla1280_chip_diag(ha);
+	if (err)
+		goto out;
+	if (IS_ISP1040(ha))
+		err = qla1280_load_firmware_pio(ha);
+	else
+		err = qla1280_load_firmware_dma(ha);
+	if (err)
+		goto out;
+	err = qla1280_start_firmware(ha);
+ out:
+	return err;
+}
+
+/*
+ * Initialize rings
+ *
+ * Input:
+ *      ha                = adapter block pointer.
+ *      ha->request_ring  = request ring virtual address
+ *      ha->response_ring = response ring virtual address
+ *      ha->request_dma   = request ring physical address
+ *      ha->response_dma  = response ring physical address
+ *
+ * Returns:
+ *      0 = success.
+ */
+static int
+qla1280_init_rings(struct scsi_qla_host *ha)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int status = 0;
+
+	ENTER("qla1280_init_rings");
+
+	/* Clear outstanding commands array. */
+	memset(ha->outstanding_cmds, 0,
+	       sizeof(struct srb *) * MAX_OUTSTANDING_COMMANDS);
+
+	/* Initialize request queue. */
+	ha->request_ring_ptr = ha->request_ring;
+	ha->req_ring_index = 0;
+	ha->req_q_cnt = REQUEST_ENTRY_CNT;
+	/* mb[0] = MBC_INIT_REQUEST_QUEUE; */
+	mb[0] = MBC_INIT_REQUEST_QUEUE_A64;
+	mb[1] = REQUEST_ENTRY_CNT;
+	mb[3] = ha->request_dma & 0xffff;
+	mb[2] = (ha->request_dma >> 16) & 0xffff;
+	mb[4] = 0;
+	mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff;
+	mb[6] = pci_dma_hi32(ha->request_dma) >> 16;
+	if (!(status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_4 |
+					       BIT_3 | BIT_2 | BIT_1 | BIT_0,
+					       &mb[0]))) {
+		/* Initialize response queue. */
+		ha->response_ring_ptr = ha->response_ring;
+		ha->rsp_ring_index = 0;
+		/* mb[0] = MBC_INIT_RESPONSE_QUEUE; */
+		mb[0] = MBC_INIT_RESPONSE_QUEUE_A64;
+		mb[1] = RESPONSE_ENTRY_CNT;
+		mb[3] = ha->response_dma & 0xffff;
+		mb[2] = (ha->response_dma >> 16) & 0xffff;
+		mb[5] = 0;
+		mb[7] = pci_dma_hi32(ha->response_dma) & 0xffff;
+		mb[6] = pci_dma_hi32(ha->response_dma) >> 16;
+		status = qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_5 |
+						 BIT_3 | BIT_2 | BIT_1 | BIT_0,
+						 &mb[0]);
+	}
+
+	if (status)
+		dprintk(2, "qla1280_init_rings: **** FAILED ****\n");
+
+	LEAVE("qla1280_init_rings");
+	return status;
+}
+
+static void
+qla1280_print_settings(struct nvram *nv)
+{
+	dprintk(1, "qla1280 : initiator scsi id bus[0]=%d\n",
+		nv->bus[0].config_1.initiator_id);
+	dprintk(1, "qla1280 : initiator scsi id bus[1]=%d\n",
+		nv->bus[1].config_1.initiator_id);
+
+	dprintk(1, "qla1280 : bus reset delay[0]=%d\n",
+		nv->bus[0].bus_reset_delay);
+	dprintk(1, "qla1280 : bus reset delay[1]=%d\n",
+		nv->bus[1].bus_reset_delay);
+
+	dprintk(1, "qla1280 : retry count[0]=%d\n", nv->bus[0].retry_count);
+	dprintk(1, "qla1280 : retry delay[0]=%d\n", nv->bus[0].retry_delay);
+	dprintk(1, "qla1280 : retry count[1]=%d\n", nv->bus[1].retry_count);
+	dprintk(1, "qla1280 : retry delay[1]=%d\n", nv->bus[1].retry_delay);
+
+	dprintk(1, "qla1280 : async data setup time[0]=%d\n",
+		nv->bus[0].config_2.async_data_setup_time);
+	dprintk(1, "qla1280 : async data setup time[1]=%d\n",
+		nv->bus[1].config_2.async_data_setup_time);
+
+	dprintk(1, "qla1280 : req/ack active negation[0]=%d\n",
+		nv->bus[0].config_2.req_ack_active_negation);
+	dprintk(1, "qla1280 : req/ack active negation[1]=%d\n",
+		nv->bus[1].config_2.req_ack_active_negation);
+
+	dprintk(1, "qla1280 : data line active negation[0]=%d\n",
+		nv->bus[0].config_2.data_line_active_negation);
+	dprintk(1, "qla1280 : data line active negation[1]=%d\n",
+		nv->bus[1].config_2.data_line_active_negation);
+
+	dprintk(1, "qla1280 : disable loading risc code=%d\n",
+		nv->cntr_flags_1.disable_loading_risc_code);
+
+	dprintk(1, "qla1280 : enable 64bit addressing=%d\n",
+		nv->cntr_flags_1.enable_64bit_addressing);
+
+	dprintk(1, "qla1280 : selection timeout limit[0]=%d\n",
+		nv->bus[0].selection_timeout);
+	dprintk(1, "qla1280 : selection timeout limit[1]=%d\n",
+		nv->bus[1].selection_timeout);
+
+	dprintk(1, "qla1280 : max queue depth[0]=%d\n",
+		nv->bus[0].max_queue_depth);
+	dprintk(1, "qla1280 : max queue depth[1]=%d\n",
+		nv->bus[1].max_queue_depth);
+}
+
+static void
+qla1280_set_target_defaults(struct scsi_qla_host *ha, int bus, int target)
+{
+	struct nvram *nv = &ha->nvram;
+
+	nv->bus[bus].target[target].parameter.f.renegotiate_on_error = 1;
+	nv->bus[bus].target[target].parameter.f.auto_request_sense = 1;
+	nv->bus[bus].target[target].parameter.f.tag_queuing = 1;
+	nv->bus[bus].target[target].parameter.f.enable_sync = 1;
+#if 1	/* Some SCSI Processors do not seem to like this */
+	nv->bus[bus].target[target].parameter.f.enable_wide = 1;
+#endif
+	nv->bus[bus].target[target].parameter.f.parity_checking = 1;
+	nv->bus[bus].target[target].parameter.f.disconnect_allowed = 1;
+	nv->bus[bus].target[target].execution_throttle =
+		nv->bus[bus].max_queue_depth - 1;
+
+	if (IS_ISP1x160(ha)) {
+		nv->bus[bus].target[target].flags.flags1x160.device_enable = 1;
+		nv->bus[bus].target[target].flags.flags1x160.sync_offset = 0x0e;
+		nv->bus[bus].target[target].sync_period = 9;
+		nv->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1;
+		nv->bus[bus].target[target].ppr_1x160.flags.ppr_options = 2;
+		nv->bus[bus].target[target].ppr_1x160.flags.ppr_bus_width = 1;
+	} else {
+		nv->bus[bus].target[target].flags.flags1x80.device_enable = 1;
+		nv->bus[bus].target[target].flags.flags1x80.sync_offset = 12;
+		nv->bus[bus].target[target].sync_period = 10;
+	}
+}
+
+static void
+qla1280_set_defaults(struct scsi_qla_host *ha)
+{
+	struct nvram *nv = &ha->nvram;
+	int bus, target;
+
+	dprintk(1, "Using defaults for NVRAM: \n");
+	memset(nv, 0, sizeof(struct nvram));
+
+	/* nv->cntr_flags_1.disable_loading_risc_code = 1; */
+	nv->firmware_feature.f.enable_fast_posting = 1;
+	nv->firmware_feature.f.disable_synchronous_backoff = 1;
+	nv->termination.f.scsi_bus_0_control = 3;
+	nv->termination.f.scsi_bus_1_control = 3;
+	nv->termination.f.auto_term_support = 1;
+
+	/*
+	 * Set default FIFO magic - What appropriate values would be here
+	 * is unknown. This is what I have found testing with 12160s.
+	 *
+	 * Now, I would love the magic decoder ring for this one, the
+	 * header file provided by QLogic seems to be bogus or incomplete
+	 * at best.
+	 */
+	nv->isp_config.c = ISP_CFG1_BENAB|ISP_CFG1_F128;
+	if (IS_ISP1x160(ha))
+		nv->isp_parameter = 0x01; /* fast memory enable */
+
+	for (bus = 0; bus < MAX_BUSES; bus++) {
+		nv->bus[bus].config_1.initiator_id = 7;
+		nv->bus[bus].config_2.req_ack_active_negation = 1;
+		nv->bus[bus].config_2.data_line_active_negation = 1;
+		nv->bus[bus].selection_timeout = 250;
+		nv->bus[bus].max_queue_depth = 256;
+
+		if (IS_ISP1040(ha)) {
+			nv->bus[bus].bus_reset_delay = 3;
+			nv->bus[bus].config_2.async_data_setup_time = 6;
+			nv->bus[bus].retry_delay = 1;
+		} else {
+			nv->bus[bus].bus_reset_delay = 5;
+			nv->bus[bus].config_2.async_data_setup_time = 8;
+		}
+
+		for (target = 0; target < MAX_TARGETS; target++)
+			qla1280_set_target_defaults(ha, bus, target);
+	}
+}
+
+static int
+qla1280_config_target(struct scsi_qla_host *ha, int bus, int target)
+{
+	struct nvram *nv = &ha->nvram;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int status, lun;
+
+	/* Set Target Parameters. */
+	mb[0] = MBC_SET_TARGET_PARAMETERS;
+	mb[1] = (uint16_t) (bus ? target | BIT_7 : target);
+	mb[1] <<= 8;
+
+	/*
+	 * Do not enable wide, sync, and ppr for the initial
+	 * INQUIRY run. We enable this later if we determine
+	 * the target actually supports it.
+	 */
+	nv->bus[bus].target[target].parameter.f.
+		auto_request_sense = 1;
+	nv->bus[bus].target[target].parameter.f.
+		stop_queue_on_check = 0;
+
+	if (IS_ISP1x160(ha))
+		nv->bus[bus].target[target].ppr_1x160.
+			flags.enable_ppr = 0;
+
+	/*
+	 * No sync, wide, etc. while probing
+	 */
+	mb[2] = (nv->bus[bus].target[target].parameter.c << 8) &
+		~(TP_SYNC /*| TP_WIDE | TP_PPR*/);
+
+	if (IS_ISP1x160(ha))
+		mb[3] =	nv->bus[bus].target[target].flags.flags1x160.sync_offset << 8;
+	else
+		mb[3] =	nv->bus[bus].target[target].flags.flags1x80.sync_offset << 8;
+	mb[3] |= nv->bus[bus].target[target].sync_period;
+
+	status = qla1280_mailbox_command(ha, BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	/* Save Tag queuing enable flag. */
+	mb[0] = BIT_0 << target;
+	if (nv->bus[bus].target[target].parameter.f.tag_queuing)
+		ha->bus_settings[bus].qtag_enables |= mb[0];
+
+	/* Save Device enable flag. */
+	if (IS_ISP1x160(ha)) {
+		if (nv->bus[bus].target[target].flags.flags1x160.device_enable)
+			ha->bus_settings[bus].device_enables |= mb[0];
+		ha->bus_settings[bus].lun_disables |= 0;
+	} else {
+		if (nv->bus[bus].target[target].flags.flags1x80.device_enable)
+			ha->bus_settings[bus].device_enables |= mb[0];
+		/* Save LUN disable flag. */
+		if (nv->bus[bus].target[target].flags.flags1x80.lun_disable)
+			ha->bus_settings[bus].lun_disables |= mb[0];
+	}
+
+	/* Set Device Queue Parameters. */
+	for (lun = 0; lun < MAX_LUNS; lun++) {
+		mb[0] = MBC_SET_DEVICE_QUEUE;
+		mb[1] = (uint16_t)(bus ? target | BIT_7 : target);
+		mb[1] = mb[1] << 8 | lun;
+		mb[2] = nv->bus[bus].max_queue_depth;
+		mb[3] = nv->bus[bus].target[target].execution_throttle;
+		status |= qla1280_mailbox_command(ha, 0x0f, &mb[0]);
+	}
+
+	return status;
+}
+
+static int
+qla1280_config_bus(struct scsi_qla_host *ha, int bus)
+{
+	struct nvram *nv = &ha->nvram;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int target, status;
+
+	/* SCSI Reset Disable. */
+	ha->bus_settings[bus].disable_scsi_reset =
+		nv->bus[bus].config_1.scsi_reset_disable;
+
+	/* Initiator ID. */
+	ha->bus_settings[bus].id = nv->bus[bus].config_1.initiator_id;
+	mb[0] = MBC_SET_INITIATOR_ID;
+	mb[1] = bus ? ha->bus_settings[bus].id | BIT_7 :
+		ha->bus_settings[bus].id;
+	status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+
+	/* Reset Delay. */
+	ha->bus_settings[bus].bus_reset_delay =
+		nv->bus[bus].bus_reset_delay;
+
+	/* Command queue depth per device. */
+	ha->bus_settings[bus].hiwat = nv->bus[bus].max_queue_depth - 1;
+
+	/* Set target parameters. */
+	for (target = 0; target < MAX_TARGETS; target++)
+		status |= qla1280_config_target(ha, bus, target);
+
+	return status;
+}
+
+static int
+qla1280_nvram_config(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	struct nvram *nv = &ha->nvram;
+	int bus, target, status = 0;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	uint16_t mask;
+
+	ENTER("qla1280_nvram_config");
+
+	if (ha->nvram_valid) {
+		/* Always force AUTO sense for LINUX SCSI */
+		for (bus = 0; bus < MAX_BUSES; bus++)
+			for (target = 0; target < MAX_TARGETS; target++) {
+				nv->bus[bus].target[target].parameter.f.
+					auto_request_sense = 1;
+			}
+	} else {
+		qla1280_set_defaults(ha);
+	}
+
+	qla1280_print_settings(nv);
+
+	/* Disable RISC load of firmware. */
+	ha->flags.disable_risc_code_load =
+		nv->cntr_flags_1.disable_loading_risc_code;
+
+	if (IS_ISP1040(ha)) {
+		uint16_t hwrev, cfg1, cdma_conf, ddma_conf;
+
+		hwrev = RD_REG_WORD(&reg->cfg_0) & ISP_CFG0_HWMSK;
+
+		cfg1 = RD_REG_WORD(&reg->cfg_1);
+		cdma_conf = RD_REG_WORD(&reg->cdma_cfg);
+		ddma_conf = RD_REG_WORD(&reg->ddma_cfg);
+
+		/* Busted fifo, says mjacob. */
+		if (hwrev == ISP_CFG0_1040A)
+			WRT_REG_WORD(&reg->cfg_1, cfg1 | ISP_CFG1_F64);
+		else
+			WRT_REG_WORD(&reg->cfg_1, cfg1 | ISP_CFG1_F64 | ISP_CFG1_BENAB);
+
+		WRT_REG_WORD(&reg->cdma_cfg, cdma_conf | CDMA_CONF_BENAB);
+		WRT_REG_WORD(&reg->ddma_cfg, cdma_conf | DDMA_CONF_BENAB);
+	} else {
+		/* Set ISP hardware DMA burst */
+		mb[0] = nv->isp_config.c;
+		/* Enable DMA arbitration on dual channel controllers */
+		if (ha->ports > 1)
+			mb[0] |= BIT_13;
+		WRT_REG_WORD(&reg->cfg_1, mb[0]);
+
+		/* Set SCSI termination. */
+		WRT_REG_WORD(&reg->gpio_enable, (BIT_3 + BIT_2 + BIT_1 + BIT_0));
+		mb[0] = nv->termination.c & (BIT_3 + BIT_2 + BIT_1 + BIT_0);
+		WRT_REG_WORD(&reg->gpio_data, mb[0]);
+	}
+
+	/* ISP parameter word. */
+	mb[0] = MBC_SET_SYSTEM_PARAMETER;
+	mb[1] = nv->isp_parameter;
+	status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+
+	if (IS_ISP1x40(ha)) {
+		/* clock rate - for qla1240 and older, only */
+		mb[0] = MBC_SET_CLOCK_RATE;
+		mb[1] = 40;
+	 	status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, mb);
+	}
+
+	/* Firmware feature word. */
+	mb[0] = MBC_SET_FIRMWARE_FEATURES;
+	mask = BIT_5 | BIT_1 | BIT_0;
+	mb[1] = le16_to_cpu(nv->firmware_feature.w) & (mask);
+#if defined(CONFIG_IA64_GENERIC) || defined (CONFIG_IA64_SGI_SN2)
+	if (ia64_platform_is("sn2")) {
+		printk(KERN_INFO "scsi(%li): Enabling SN2 PCI DMA "
+		       "workaround\n", ha->host_no);
+		mb[1] |= BIT_9;
+	}
+#endif
+	status |= qla1280_mailbox_command(ha, mask, &mb[0]);
+
+	/* Retry count and delay. */
+	mb[0] = MBC_SET_RETRY_COUNT;
+	mb[1] = nv->bus[0].retry_count;
+	mb[2] = nv->bus[0].retry_delay;
+	mb[6] = nv->bus[1].retry_count;
+	mb[7] = nv->bus[1].retry_delay;
+	status |= qla1280_mailbox_command(ha, BIT_7 | BIT_6 | BIT_2 |
+					  BIT_1 | BIT_0, &mb[0]);
+
+	/* ASYNC data setup time. */
+	mb[0] = MBC_SET_ASYNC_DATA_SETUP;
+	mb[1] = nv->bus[0].config_2.async_data_setup_time;
+	mb[2] = nv->bus[1].config_2.async_data_setup_time;
+	status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	/* Active negation states. */
+	mb[0] = MBC_SET_ACTIVE_NEGATION;
+	mb[1] = 0;
+	if (nv->bus[0].config_2.req_ack_active_negation)
+		mb[1] |= BIT_5;
+	if (nv->bus[0].config_2.data_line_active_negation)
+		mb[1] |= BIT_4;
+	mb[2] = 0;
+	if (nv->bus[1].config_2.req_ack_active_negation)
+		mb[2] |= BIT_5;
+	if (nv->bus[1].config_2.data_line_active_negation)
+		mb[2] |= BIT_4;
+	status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	mb[0] = MBC_SET_DATA_OVERRUN_RECOVERY;
+	mb[1] = 2;	/* Reset SCSI bus and return all outstanding IO */
+	status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+
+	/* thingy */
+	mb[0] = MBC_SET_PCI_CONTROL;
+	mb[1] = 2;	/* Data DMA Channel Burst Enable */
+	mb[2] = 2;	/* Command DMA Channel Burst Enable */
+	status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	mb[0] = MBC_SET_TAG_AGE_LIMIT;
+	mb[1] = 8;
+	status |= qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+
+	/* Selection timeout. */
+	mb[0] = MBC_SET_SELECTION_TIMEOUT;
+	mb[1] = nv->bus[0].selection_timeout;
+	mb[2] = nv->bus[1].selection_timeout;
+	status |= qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	for (bus = 0; bus < ha->ports; bus++)
+		status |= qla1280_config_bus(ha, bus);
+
+	if (status)
+		dprintk(2, "qla1280_nvram_config: **** FAILED ****\n");
+
+	LEAVE("qla1280_nvram_config");
+	return status;
+}
+
+/*
+ * Get NVRAM data word
+ *      Calculates word position in NVRAM and calls request routine to
+ *      get the word from NVRAM.
+ *
+ * Input:
+ *      ha      = adapter block pointer.
+ *      address = NVRAM word address.
+ *
+ * Returns:
+ *      data word.
+ */
+static uint16_t
+qla1280_get_nvram_word(struct scsi_qla_host *ha, uint32_t address)
+{
+	uint32_t nv_cmd;
+	uint16_t data;
+
+	nv_cmd = address << 16;
+	nv_cmd |= NV_READ_OP;
+
+	data = le16_to_cpu(qla1280_nvram_request(ha, nv_cmd));
+
+	dprintk(8, "qla1280_get_nvram_word: exiting normally NVRAM data = "
+		"0x%x", data);
+
+	return data;
+}
+
+/*
+ * NVRAM request
+ *      Sends read command to NVRAM and gets data from NVRAM.
+ *
+ * Input:
+ *      ha     = adapter block pointer.
+ *      nv_cmd = Bit 26     = start bit
+ *               Bit 25, 24 = opcode
+ *               Bit 23-16  = address
+ *               Bit 15-0   = write data
+ *
+ * Returns:
+ *      data word.
+ */
+static uint16_t
+qla1280_nvram_request(struct scsi_qla_host *ha, uint32_t nv_cmd)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	int cnt;
+	uint16_t data = 0;
+	uint16_t reg_data;
+
+	/* Send command to NVRAM. */
+
+	nv_cmd <<= 5;
+	for (cnt = 0; cnt < 11; cnt++) {
+		if (nv_cmd & BIT_31)
+			qla1280_nv_write(ha, NV_DATA_OUT);
+		else
+			qla1280_nv_write(ha, 0);
+		nv_cmd <<= 1;
+	}
+
+	/* Read data from NVRAM. */
+
+	for (cnt = 0; cnt < 16; cnt++) {
+		WRT_REG_WORD(&reg->nvram, (NV_SELECT | NV_CLOCK));
+		RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+		NVRAM_DELAY();
+		data <<= 1;
+		reg_data = RD_REG_WORD(&reg->nvram);
+		if (reg_data & NV_DATA_IN)
+			data |= BIT_0;
+		WRT_REG_WORD(&reg->nvram, NV_SELECT);
+		RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+		NVRAM_DELAY();
+	}
+
+	/* Deselect chip. */
+
+	WRT_REG_WORD(&reg->nvram, NV_DESELECT);
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+	NVRAM_DELAY();
+
+	return data;
+}
+
+static void
+qla1280_nv_write(struct scsi_qla_host *ha, uint16_t data)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+
+	WRT_REG_WORD(&reg->nvram, data | NV_SELECT);
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+	NVRAM_DELAY();
+	WRT_REG_WORD(&reg->nvram, data | NV_SELECT | NV_CLOCK);
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+	NVRAM_DELAY();
+	WRT_REG_WORD(&reg->nvram, data | NV_SELECT);
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+	NVRAM_DELAY();
+}
+
+/*
+ * Mailbox Command
+ *      Issue mailbox command and waits for completion.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *      mr = mailbox registers to load.
+ *      mb = data pointer for mailbox registers.
+ *
+ * Output:
+ *      mb[MAILBOX_REGISTER_COUNT] = returned mailbox data.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_mailbox_command(struct scsi_qla_host *ha, uint8_t mr, uint16_t *mb)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+#if 0
+	LIST_HEAD(done_q);
+#endif
+	int status = 0;
+	int cnt;
+	uint16_t *optr, *iptr;
+	uint16_t __iomem *mptr;
+	uint16_t data;
+	DECLARE_COMPLETION(wait);
+	struct timer_list timer;
+
+	ENTER("qla1280_mailbox_command");
+
+	if (ha->mailbox_wait) {
+		printk(KERN_ERR "Warning mailbox wait already in use!\n");
+	}
+	ha->mailbox_wait = &wait;
+
+	/*
+	 * We really should start out by verifying that the mailbox is
+	 * available before starting sending the command data
+	 */
+	/* Load mailbox registers. */
+	mptr = (uint16_t __iomem *) &reg->mailbox0;
+	iptr = mb;
+	for (cnt = 0; cnt < MAILBOX_REGISTER_COUNT; cnt++) {
+		if (mr & BIT_0) {
+			WRT_REG_WORD(mptr, (*iptr));
+		}
+
+		mr >>= 1;
+		mptr++;
+		iptr++;
+	}
+
+	/* Issue set host interrupt command. */
+
+	/* set up a timer just in case we're really jammed */
+	init_timer(&timer);
+	timer.expires = jiffies + 20*HZ;
+	timer.data = (unsigned long)ha;
+	timer.function = qla1280_mailbox_timeout;
+	add_timer(&timer);
+
+	spin_unlock_irq(HOST_LOCK);
+	WRT_REG_WORD(&reg->host_cmd, HC_SET_HOST_INT);
+	data = qla1280_debounce_register(&reg->istatus);
+
+	wait_for_completion(&wait);
+	del_timer_sync(&timer);
+
+	spin_lock_irq(HOST_LOCK);
+
+	ha->mailbox_wait = NULL;
+
+	/* Check for mailbox command timeout. */
+	if (ha->mailbox_out[0] != MBS_CMD_CMP) {
+		printk(KERN_WARNING "qla1280_mailbox_command: Command failed, "
+		       "mailbox0 = 0x%04x, mailbox_out0 = 0x%04x, istatus = "
+		       "0x%04x\n", 
+		       mb[0], ha->mailbox_out[0], RD_REG_WORD(&reg->istatus));
+		printk(KERN_WARNING "m0 %04x, m1 %04x, m2 %04x, m3 %04x\n",
+		       RD_REG_WORD(&reg->mailbox0), RD_REG_WORD(&reg->mailbox1),
+		       RD_REG_WORD(&reg->mailbox2), RD_REG_WORD(&reg->mailbox3));
+		printk(KERN_WARNING "m4 %04x, m5 %04x, m6 %04x, m7 %04x\n",
+		       RD_REG_WORD(&reg->mailbox4), RD_REG_WORD(&reg->mailbox5),
+		       RD_REG_WORD(&reg->mailbox6), RD_REG_WORD(&reg->mailbox7));
+		status = 1;
+	}
+
+	/* Load return mailbox registers. */
+	optr = mb;
+	iptr = (uint16_t *) &ha->mailbox_out[0];
+	mr = MAILBOX_REGISTER_COUNT;
+	memcpy(optr, iptr, MAILBOX_REGISTER_COUNT * sizeof(uint16_t));
+
+#if 0
+	/* Go check for any response interrupts pending. */
+	qla1280_isr(ha, &done_q);
+#endif
+
+	if (ha->flags.reset_marker)
+		qla1280_rst_aen(ha);
+
+#if 0
+	if (!list_empty(&done_q))
+		qla1280_done(ha, &done_q);
+#endif
+
+	if (status)
+		dprintk(2, "qla1280_mailbox_command: **** FAILED, mailbox0 = "
+			"0x%x ****\n", mb[0]);
+
+	LEAVE("qla1280_mailbox_command");
+	return status;
+}
+
+/*
+ * qla1280_poll
+ *      Polls ISP for interrupts.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ */
+static void
+qla1280_poll(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	uint16_t data;
+	LIST_HEAD(done_q);
+
+	/* ENTER("qla1280_poll"); */
+
+	/* Check for pending interrupts. */
+	data = RD_REG_WORD(&reg->istatus);
+	if (data & RISC_INT)
+		qla1280_isr(ha, &done_q);
+
+	if (!ha->mailbox_wait) {
+		if (ha->flags.reset_marker)
+			qla1280_rst_aen(ha);
+	}
+
+	if (!list_empty(&done_q))
+		qla1280_done(ha);
+
+	/* LEAVE("qla1280_poll"); */
+}
+
+/*
+ * qla1280_bus_reset
+ *      Issue SCSI bus reset.
+ *
+ * Input:
+ *      ha  = adapter block pointer.
+ *      bus = SCSI bus number.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_bus_reset(struct scsi_qla_host *ha, int bus)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	uint16_t reset_delay;
+	int status;
+
+	dprintk(3, "qla1280_bus_reset: entered\n");
+
+	if (qla1280_verbose)
+		printk(KERN_INFO "scsi(%li:%i): Resetting SCSI BUS\n",
+		       ha->host_no, bus);
+
+	reset_delay = ha->bus_settings[bus].bus_reset_delay;
+	mb[0] = MBC_BUS_RESET;
+	mb[1] = reset_delay;
+	mb[2] = (uint16_t) bus;
+	status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	if (status) {
+		if (ha->bus_settings[bus].failed_reset_count > 2)
+			ha->bus_settings[bus].scsi_bus_dead = 1;
+		ha->bus_settings[bus].failed_reset_count++;
+	} else {
+		spin_unlock_irq(HOST_LOCK);
+		schedule_timeout(reset_delay * HZ);
+		spin_lock_irq(HOST_LOCK);
+
+		ha->bus_settings[bus].scsi_bus_dead = 0;
+		ha->bus_settings[bus].failed_reset_count = 0;
+		ha->bus_settings[bus].reset_marker = 0;
+		/* Issue marker command. */
+		qla1280_marker(ha, bus, 0, 0, MK_SYNC_ALL);
+	}
+
+	/*
+	 * We should probably call qla1280_set_target_parameters()
+	 * here as well for all devices on the bus.
+	 */
+
+	if (status)
+		dprintk(2, "qla1280_bus_reset: **** FAILED ****\n");
+	else
+		dprintk(3, "qla1280_bus_reset: exiting normally\n");
+
+	return status;
+}
+
+/*
+ * qla1280_device_reset
+ *      Issue bus device reset message to the target.
+ *
+ * Input:
+ *      ha      = adapter block pointer.
+ *      bus     = SCSI BUS number.
+ *      target  = SCSI ID.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_device_reset(struct scsi_qla_host *ha, int bus, int target)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int status;
+
+	ENTER("qla1280_device_reset");
+
+	mb[0] = MBC_ABORT_TARGET;
+	mb[1] = (bus ? (target | BIT_7) : target) << 8;
+	mb[2] = 1;
+	status = qla1280_mailbox_command(ha, BIT_2 | BIT_1 | BIT_0, &mb[0]);
+
+	/* Issue marker command. */
+	qla1280_marker(ha, bus, target, 0, MK_SYNC_ID);
+
+	if (status)
+		dprintk(2, "qla1280_device_reset: **** FAILED ****\n");
+
+	LEAVE("qla1280_device_reset");
+	return status;
+}
+
+/*
+ * qla1280_abort_device
+ *      Issue an abort message to the device
+ *
+ * Input:
+ *      ha     = adapter block pointer.
+ *      bus    = SCSI BUS.
+ *      target = SCSI ID.
+ *      lun    = SCSI LUN.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_abort_device(struct scsi_qla_host *ha, int bus, int target, int lun)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int status;
+
+	ENTER("qla1280_abort_device");
+
+	mb[0] = MBC_ABORT_DEVICE;
+	mb[1] = (bus ? target | BIT_7 : target) << 8 | lun;
+	status = qla1280_mailbox_command(ha, BIT_1 | BIT_0, &mb[0]);
+
+	/* Issue marker command. */
+	qla1280_marker(ha, bus, target, lun, MK_SYNC_ID_LUN);
+
+	if (status)
+		dprintk(2, "qla1280_abort_device: **** FAILED ****\n");
+
+	LEAVE("qla1280_abort_device");
+	return status;
+}
+
+/*
+ * qla1280_abort_command
+ *      Abort command aborts a specified IOCB.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *      sp = SB structure pointer.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_abort_command(struct scsi_qla_host *ha, struct srb * sp, int handle)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	unsigned int bus, target, lun;
+	int status;
+
+	ENTER("qla1280_abort_command");
+
+	bus = SCSI_BUS_32(sp->cmd);
+	target = SCSI_TCN_32(sp->cmd);
+	lun = SCSI_LUN_32(sp->cmd);
+
+	sp->flags |= SRB_ABORT_PENDING;
+
+	mb[0] = MBC_ABORT_COMMAND;
+	mb[1] = (bus ? target | BIT_7 : target) << 8 | lun;
+	mb[2] = handle >> 16;
+	mb[3] = handle & 0xffff;
+	status = qla1280_mailbox_command(ha, 0x0f, &mb[0]);
+
+	if (status) {
+		dprintk(2, "qla1280_abort_command: **** FAILED ****\n");
+		sp->flags &= ~SRB_ABORT_PENDING;
+	}
+
+
+	LEAVE("qla1280_abort_command");
+	return status;
+}
+
+/*
+ * qla1280_reset_adapter
+ *      Reset adapter.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ */
+static void
+qla1280_reset_adapter(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+
+	ENTER("qla1280_reset_adapter");
+
+	/* Disable ISP chip */
+	ha->flags.online = 0;
+	WRT_REG_WORD(&reg->ictrl, ISP_RESET);
+	WRT_REG_WORD(&reg->host_cmd,
+		     HC_RESET_RISC | HC_RELEASE_RISC | HC_DISABLE_BIOS);
+	RD_REG_WORD(&reg->id_l);	/* Flush PCI write */
+
+	LEAVE("qla1280_reset_adapter");
+}
+
+/*
+ *  Issue marker command.
+ *      Function issues marker IOCB.
+ *
+ * Input:
+ *      ha   = adapter block pointer.
+ *      bus  = SCSI BUS number
+ *      id   = SCSI ID
+ *      lun  = SCSI LUN
+ *      type = marker modifier
+ */
+static void
+qla1280_marker(struct scsi_qla_host *ha, int bus, int id, int lun, u8 type)
+{
+	struct mrk_entry *pkt;
+
+	ENTER("qla1280_marker");
+
+	/* Get request packet. */
+	if ((pkt = (struct mrk_entry *) qla1280_req_pkt(ha))) {
+		pkt->entry_type = MARKER_TYPE;
+		pkt->lun = (uint8_t) lun;
+		pkt->target = (uint8_t) (bus ? (id | BIT_7) : id);
+		pkt->modifier = type;
+		pkt->entry_status = 0;
+
+		/* Issue command to ISP */
+		qla1280_isp_cmd(ha);
+	}
+
+	LEAVE("qla1280_marker");
+}
+
+
+/*
+ * qla1280_64bit_start_scsi
+ *      The start SCSI is responsible for building request packets on
+ *      request ring and modifying ISP input pointer.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *      sp = SB structure pointer.
+ *
+ * Returns:
+ *      0 = success, was able to issue command.
+ */
+#ifdef QLA_64BIT_PTR
+static int
+qla1280_64bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	struct scsi_cmnd *cmd = sp->cmd;
+	cmd_a64_entry_t *pkt;
+	struct scatterlist *sg = NULL;
+	u32 *dword_ptr;
+	dma_addr_t dma_handle;
+	int status = 0;
+	int cnt;
+	int req_cnt;
+	u16 seg_cnt;
+	u8 dir;
+
+	ENTER("qla1280_64bit_start_scsi:");
+
+	/* Calculate number of entries and segments required. */
+	req_cnt = 1;
+	if (cmd->use_sg) {
+		sg = (struct scatterlist *) cmd->request_buffer;
+		seg_cnt = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+				     cmd->sc_data_direction);
+
+		if (seg_cnt > 2) {
+			req_cnt += (seg_cnt - 2) / 5;
+			if ((seg_cnt - 2) % 5)
+				req_cnt++;
+		}
+	} else if (cmd->request_bufflen) {	/* If data transfer. */
+		seg_cnt = 1;
+	} else {
+		seg_cnt = 0;
+	}
+
+	if ((req_cnt + 2) >= ha->req_q_cnt) {
+		/* Calculate number of free request entries. */
+		cnt = RD_REG_WORD(&reg->mailbox4);
+		if (ha->req_ring_index < cnt)
+			ha->req_q_cnt = cnt - ha->req_ring_index;
+		else
+			ha->req_q_cnt =
+				REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt);
+	}
+
+	/* If room for request in request ring. */
+	if ((req_cnt + 2) >= ha->req_q_cnt) {
+		status = 1;
+		dprintk(2, "qla1280_64bit_start_scsi: in-ptr=0x%x  req_q_cnt="
+			"0x%xreq_cnt=0x%x", ha->req_ring_index, ha->req_q_cnt,
+			req_cnt);
+		goto out;
+	}
+
+	/* Check for room in outstanding command list. */
+	for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS &&
+		     ha->outstanding_cmds[cnt] != 0; cnt++);
+
+	if (cnt >= MAX_OUTSTANDING_COMMANDS) {
+		status = 1;
+		dprintk(2, "qla1280_64bit_start_scsi: NO ROOM IN "
+			"OUTSTANDING ARRAY, req_q_cnt=0x%x", ha->req_q_cnt);
+		goto out;
+	}
+
+	ha->outstanding_cmds[cnt] = sp;
+	ha->req_q_cnt -= req_cnt;
+	CMD_HANDLE(sp->cmd) = (unsigned char *)(unsigned long)(cnt + 1);
+
+	dprintk(2, "64bit_start: cmd=%p sp=%p CDB=%xm, handle %lx\n", cmd, sp,
+		cmd->cmnd[0], (long)CMD_HANDLE(sp->cmd));
+	dprintk(2, "             bus %i, target %i, lun %i\n",
+		SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd));
+	qla1280_dump_buffer(2, cmd->cmnd, MAX_COMMAND_SIZE);
+
+	/*
+	 * Build command packet.
+	 */
+	pkt = (cmd_a64_entry_t *) ha->request_ring_ptr;
+
+	pkt->entry_type = COMMAND_A64_TYPE;
+	pkt->entry_count = (uint8_t) req_cnt;
+	pkt->sys_define = (uint8_t) ha->req_ring_index;
+	pkt->entry_status = 0;
+	pkt->handle = cpu_to_le32(cnt);
+
+	/* Zero out remaining portion of packet. */
+	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
+
+	/* Set ISP command timeout. */
+	pkt->timeout = cpu_to_le16(30);
+
+	/* Set device target ID and LUN */
+	pkt->lun = SCSI_LUN_32(cmd);
+	pkt->target = SCSI_BUS_32(cmd) ?
+		(SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
+
+	/* Enable simple tag queuing if device supports it. */
+	if (DEV_SIMPLE_TAGS(cmd->device))
+		pkt->control_flags |= cpu_to_le16(BIT_3);
+
+	/* Load SCSI command packet. */
+	pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
+	memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+	/* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
+
+	/* Set transfer direction. */
+	dir = qla1280_data_direction(cmd);
+	pkt->control_flags |= cpu_to_le16(dir);
+
+	/* Set total data segment count. */
+	pkt->dseg_count = cpu_to_le16(seg_cnt);
+
+	/*
+	 * Load data segments.
+	 */
+	if (seg_cnt) {	/* If data transfer. */
+		/* Setup packet address segment pointer. */
+		dword_ptr = (u32 *)&pkt->dseg_0_address;
+
+		if (cmd->use_sg) {	/* If scatter gather */
+			/* Load command entry data segments. */
+			for (cnt = 0; cnt < 2 && seg_cnt; cnt++, seg_cnt--) {
+				dma_handle = sg_dma_address(sg);
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+				if (ha->flags.use_pci_vchannel)
+					sn_pci_set_vchan(ha->pdev,
+							(unsigned long *)&dma_handle,
+							 SCSI_BUS_32(cmd));
+#endif
+				*dword_ptr++ =
+					cpu_to_le32(pci_dma_lo32(dma_handle));
+				*dword_ptr++ =
+					cpu_to_le32(pci_dma_hi32(dma_handle));
+				*dword_ptr++ = cpu_to_le32(sg_dma_len(sg));
+				sg++;
+				dprintk(3, "S/G Segment phys_addr=%x %x, len=0x%x\n",
+					cpu_to_le32(pci_dma_hi32(dma_handle)),
+					cpu_to_le32(pci_dma_lo32(dma_handle)),
+					cpu_to_le32(sg_dma_len(sg)));
+			}
+			dprintk(5, "qla1280_64bit_start_scsi: Scatter/gather "
+				"command packet data - b %i, t %i, l %i \n",
+				SCSI_BUS_32(cmd), SCSI_TCN_32(cmd),
+				SCSI_LUN_32(cmd));
+			qla1280_dump_buffer(5, (char *)pkt,
+					    REQUEST_ENTRY_SIZE);
+
+			/*
+			 * Build continuation packets.
+			 */
+			dprintk(3, "S/G Building Continuation...seg_cnt=0x%x "
+				"remains\n", seg_cnt);
+
+			while (seg_cnt > 0) {
+				/* Adjust ring index. */
+				ha->req_ring_index++;
+				if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+					ha->req_ring_index = 0;
+					ha->request_ring_ptr =
+						ha->request_ring;
+				} else
+						ha->request_ring_ptr++;
+
+				pkt = (cmd_a64_entry_t *)ha->request_ring_ptr;
+
+				/* Zero out packet. */
+				memset(pkt, 0, REQUEST_ENTRY_SIZE);
+
+				/* Load packet defaults. */
+				((struct cont_a64_entry *) pkt)->entry_type =
+					CONTINUE_A64_TYPE;
+				((struct cont_a64_entry *) pkt)->entry_count = 1;
+				((struct cont_a64_entry *) pkt)->sys_define =
+					(uint8_t)ha->req_ring_index;
+				/* Setup packet address segment pointer. */
+				dword_ptr =
+					(u32 *)&((struct cont_a64_entry *) pkt)->dseg_0_address;
+
+				/* Load continuation entry data segments. */
+				for (cnt = 0; cnt < 5 && seg_cnt;
+				     cnt++, seg_cnt--) {
+					dma_handle = sg_dma_address(sg);
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+				if (ha->flags.use_pci_vchannel)
+					sn_pci_set_vchan(ha->pdev, 
+							(unsigned long *)&dma_handle,
+							 SCSI_BUS_32(cmd));
+#endif
+					*dword_ptr++ =
+						cpu_to_le32(pci_dma_lo32(dma_handle));
+					*dword_ptr++ =
+						cpu_to_le32(pci_dma_hi32(dma_handle));
+					*dword_ptr++ =
+						cpu_to_le32(sg_dma_len(sg));
+					dprintk(3, "S/G Segment Cont. phys_addr=%x %x, len=0x%x\n",
+						cpu_to_le32(pci_dma_hi32(dma_handle)),
+						cpu_to_le32(pci_dma_lo32(dma_handle)),
+						cpu_to_le32(sg_dma_len(sg)));
+					sg++;
+				}
+				dprintk(5, "qla1280_64bit_start_scsi: "
+					"continuation packet data - b %i, t "
+					"%i, l %i \n", SCSI_BUS_32(cmd),
+					SCSI_TCN_32(cmd), SCSI_LUN_32(cmd));
+				qla1280_dump_buffer(5, (char *)pkt,
+						    REQUEST_ENTRY_SIZE);
+			}
+		} else {	/* No scatter gather data transfer */
+			dma_handle = pci_map_single(ha->pdev,
+					cmd->request_buffer,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
+
+			sp->saved_dma_handle = dma_handle;
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+			if (ha->flags.use_pci_vchannel)
+				sn_pci_set_vchan(ha->pdev, 
+						(unsigned long *)&dma_handle,
+						 SCSI_BUS_32(cmd));
+#endif
+			*dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle));
+			*dword_ptr++ = cpu_to_le32(pci_dma_hi32(dma_handle));
+			*dword_ptr = cpu_to_le32(cmd->request_bufflen);
+
+			dprintk(5, "qla1280_64bit_start_scsi: No scatter/"
+				"gather command packet data - b %i, t %i, "
+				"l %i \n", SCSI_BUS_32(cmd), SCSI_TCN_32(cmd),
+				SCSI_LUN_32(cmd));
+			qla1280_dump_buffer(5, (char *)pkt,
+					    REQUEST_ENTRY_SIZE);
+		}
+	} else {	/* No data transfer */
+		dprintk(5, "qla1280_64bit_start_scsi: No data, command "
+			"packet data - b %i, t %i, l %i \n",
+			SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd));
+		qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE);
+	}
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else
+		ha->request_ring_ptr++;
+
+	/* Set chip new ring index. */
+	dprintk(2,
+		"qla1280_64bit_start_scsi: Wakeup RISC for pending command\n");
+	sp->flags |= SRB_SENT;
+	ha->actthreads++;
+	WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
+	/* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */
+	mmiowb();
+
+ out:
+	if (status)
+		dprintk(2, "qla1280_64bit_start_scsi: **** FAILED ****\n");
+	else
+		dprintk(3, "qla1280_64bit_start_scsi: exiting normally\n");
+
+	return status;
+}
+#else /* !QLA_64BIT_PTR */
+
+/*
+ * qla1280_32bit_start_scsi
+ *      The start SCSI is responsible for building request packets on
+ *      request ring and modifying ISP input pointer.
+ *
+ *      The Qlogic firmware interface allows every queue slot to have a SCSI
+ *      command and up to 4 scatter/gather (SG) entries.  If we need more
+ *      than 4 SG entries, then continuation entries are used that can
+ *      hold another 7 entries each.  The start routine determines if there
+ *      is eought empty slots then build the combination of requests to
+ *      fulfill the OS request.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *      sp = SCSI Request Block structure pointer.
+ *
+ * Returns:
+ *      0 = success, was able to issue command.
+ */
+static int
+qla1280_32bit_start_scsi(struct scsi_qla_host *ha, struct srb * sp)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	struct scsi_cmnd *cmd = sp->cmd;
+	struct cmd_entry *pkt;
+	struct scatterlist *sg = NULL;
+	uint32_t *dword_ptr;
+	int status = 0;
+	int cnt;
+	int req_cnt;
+	uint16_t seg_cnt;
+	dma_addr_t dma_handle;
+	u8 dir;
+
+	ENTER("qla1280_32bit_start_scsi");
+
+	dprintk(1, "32bit_start: cmd=%p sp=%p CDB=%x\n", cmd, sp,
+		cmd->cmnd[0]);
+
+	/* Calculate number of entries and segments required. */
+	req_cnt = 1;
+	if (cmd->use_sg) {
+		/*
+		 * We must build an SG list in adapter format, as the kernel's
+		 * SG list cannot be used directly because of data field size
+		 * (__alpha__) differences and the kernel SG list uses virtual
+		 * addresses where we need physical addresses.
+		 */
+		sg = (struct scatterlist *) cmd->request_buffer;
+		seg_cnt = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+				     cmd->sc_data_direction);
+
+		/*
+		 * if greater than four sg entries then we need to allocate
+		 * continuation entries
+		 */
+		if (seg_cnt > 4) {
+			req_cnt += (seg_cnt - 4) / 7;
+			if ((seg_cnt - 4) % 7)
+				req_cnt++;
+		}
+		dprintk(3, "S/G Transfer cmd=%p seg_cnt=0x%x, req_cnt=%x\n",
+			cmd, seg_cnt, req_cnt);
+	} else if (cmd->request_bufflen) {	/* If data transfer. */
+		dprintk(3, "No S/G transfer t=%x cmd=%p len=%x CDB=%x\n",
+			SCSI_TCN_32(cmd), cmd, cmd->request_bufflen,
+			cmd->cmnd[0]);
+		seg_cnt = 1;
+	} else {
+		/* dprintk(1, "No data transfer \n"); */
+		seg_cnt = 0;
+	}
+
+	if ((req_cnt + 2) >= ha->req_q_cnt) {
+		/* Calculate number of free request entries. */
+		cnt = RD_REG_WORD(&reg->mailbox4);
+		if (ha->req_ring_index < cnt)
+			ha->req_q_cnt = cnt - ha->req_ring_index;
+		else
+			ha->req_q_cnt =
+				REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt);
+	}
+
+	dprintk(3, "Number of free entries=(%d) seg_cnt=0x%x\n",
+		ha->req_q_cnt, seg_cnt);
+	/* If room for request in request ring. */
+	if ((req_cnt + 2) >= ha->req_q_cnt) {
+		status = 1;
+		dprintk(2, "qla1280_32bit_start_scsi: in-ptr=0x%x, "
+			"req_q_cnt=0x%x, req_cnt=0x%x", ha->req_ring_index,
+			ha->req_q_cnt, req_cnt);
+		goto out;
+	}
+
+	/* Check for empty slot in outstanding command list. */
+	for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS &&
+		     (ha->outstanding_cmds[cnt] != 0); cnt++) ;
+
+	if (cnt >= MAX_OUTSTANDING_COMMANDS) {
+		status = 1;
+		dprintk(2, "qla1280_32bit_start_scsi: NO ROOM IN OUTSTANDING "
+			"ARRAY, req_q_cnt=0x%x\n", ha->req_q_cnt);
+		goto out;
+	}
+
+	CMD_HANDLE(sp->cmd) = (unsigned char *) (unsigned long)(cnt + 1);
+	ha->outstanding_cmds[cnt] = sp;
+	ha->req_q_cnt -= req_cnt;
+
+	/*
+	 * Build command packet.
+	 */
+	pkt = (struct cmd_entry *) ha->request_ring_ptr;
+
+	pkt->entry_type = COMMAND_TYPE;
+	pkt->entry_count = (uint8_t) req_cnt;
+	pkt->sys_define = (uint8_t) ha->req_ring_index;
+	pkt->entry_status = 0;
+	pkt->handle = cpu_to_le32(cnt);
+
+	/* Zero out remaining portion of packet. */
+	memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8));
+
+	/* Set ISP command timeout. */
+	pkt->timeout = cpu_to_le16(30);
+
+	/* Set device target ID and LUN */
+	pkt->lun = SCSI_LUN_32(cmd);
+	pkt->target = SCSI_BUS_32(cmd) ?
+		(SCSI_TCN_32(cmd) | BIT_7) : SCSI_TCN_32(cmd);
+
+	/* Enable simple tag queuing if device supports it. */
+	if (DEV_SIMPLE_TAGS(cmd->device))
+		pkt->control_flags |= cpu_to_le16(BIT_3);
+
+	/* Load SCSI command packet. */
+	pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd));
+	memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd));
+
+	/*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */
+	/* Set transfer direction. */
+	dir = qla1280_data_direction(cmd);
+	pkt->control_flags |= cpu_to_le16(dir);
+
+	/* Set total data segment count. */
+	pkt->dseg_count = cpu_to_le16(seg_cnt);
+
+	/*
+	 * Load data segments.
+	 */
+	if (seg_cnt) {
+		/* Setup packet address segment pointer. */
+		dword_ptr = &pkt->dseg_0_address;
+
+		if (cmd->use_sg) {	/* If scatter gather */
+			dprintk(3, "Building S/G data segments..\n");
+			qla1280_dump_buffer(1, (char *)sg, 4 * 16);
+
+			/* Load command entry data segments. */
+			for (cnt = 0; cnt < 4 && seg_cnt; cnt++, seg_cnt--) {
+				*dword_ptr++ =
+					cpu_to_le32(pci_dma_lo32(sg_dma_address(sg)));
+				*dword_ptr++ =
+					cpu_to_le32(sg_dma_len(sg));
+				dprintk(3, "S/G Segment phys_addr=0x%lx, len=0x%x\n",
+					(pci_dma_lo32(sg_dma_address(sg))),
+					(sg_dma_len(sg)));
+				sg++;
+			}
+			/*
+			 * Build continuation packets.
+			 */
+			dprintk(3, "S/G Building Continuation"
+				"...seg_cnt=0x%x remains\n", seg_cnt);
+			while (seg_cnt > 0) {
+				/* Adjust ring index. */
+				ha->req_ring_index++;
+				if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+					ha->req_ring_index = 0;
+					ha->request_ring_ptr =
+						ha->request_ring;
+				} else
+					ha->request_ring_ptr++;
+
+				pkt = (struct cmd_entry *)ha->request_ring_ptr;
+
+				/* Zero out packet. */
+				memset(pkt, 0, REQUEST_ENTRY_SIZE);
+
+				/* Load packet defaults. */
+				((struct cont_entry *) pkt)->
+					entry_type = CONTINUE_TYPE;
+				((struct cont_entry *) pkt)->entry_count = 1;
+
+				((struct cont_entry *) pkt)->sys_define =
+					(uint8_t) ha->req_ring_index;
+
+				/* Setup packet address segment pointer. */
+				dword_ptr =
+					&((struct cont_entry *) pkt)->dseg_0_address;
+
+				/* Load continuation entry data segments. */
+				for (cnt = 0; cnt < 7 && seg_cnt;
+				     cnt++, seg_cnt--) {
+					*dword_ptr++ =
+						cpu_to_le32(pci_dma_lo32(sg_dma_address(sg)));
+					*dword_ptr++ =
+						cpu_to_le32(sg_dma_len(sg));
+					dprintk(1,
+						"S/G Segment Cont. phys_addr=0x%x, "
+						"len=0x%x\n",
+						cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))),
+						cpu_to_le32(sg_dma_len(sg)));
+					sg++;
+				}
+				dprintk(5, "qla1280_32bit_start_scsi: "
+					"continuation packet data - "
+					"scsi(%i:%i:%i)\n", SCSI_BUS_32(cmd),
+					SCSI_TCN_32(cmd), SCSI_LUN_32(cmd));
+				qla1280_dump_buffer(5, (char *)pkt,
+						    REQUEST_ENTRY_SIZE);
+			}
+		} else {	/* No S/G data transfer */
+			dma_handle = pci_map_single(ha->pdev,
+					cmd->request_buffer,
+					cmd->request_bufflen,
+					cmd->sc_data_direction);
+			sp->saved_dma_handle = dma_handle;
+
+			*dword_ptr++ = cpu_to_le32(pci_dma_lo32(dma_handle));
+			*dword_ptr = cpu_to_le32(cmd->request_bufflen);
+		}
+	} else {	/* No data transfer at all */
+		dprintk(5, "qla1280_32bit_start_scsi: No data, command "
+			"packet data - \n");
+		qla1280_dump_buffer(5, (char *)pkt, REQUEST_ENTRY_SIZE);
+	}
+	dprintk(5, "qla1280_32bit_start_scsi: First IOCB block:\n");
+	qla1280_dump_buffer(5, (char *)ha->request_ring_ptr,
+			    REQUEST_ENTRY_SIZE);
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else
+		ha->request_ring_ptr++;
+
+	/* Set chip new ring index. */
+	dprintk(2, "qla1280_32bit_start_scsi: Wakeup RISC "
+		"for pending command\n");
+	sp->flags |= SRB_SENT;
+	ha->actthreads++;
+	WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
+	/* Enforce mmio write ordering; see comment in qla1280_isp_cmd(). */
+	mmiowb();
+
+out:
+	if (status)
+		dprintk(2, "qla1280_32bit_start_scsi: **** FAILED ****\n");
+
+	LEAVE("qla1280_32bit_start_scsi");
+
+	return status;
+}
+#endif
+
+/*
+ * qla1280_req_pkt
+ *      Function is responsible for locking ring and
+ *      getting a zeroed out request packet.
+ *
+ * Input:
+ *      ha  = adapter block pointer.
+ *
+ * Returns:
+ *      0 = failed to get slot.
+ */
+static request_t *
+qla1280_req_pkt(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	request_t *pkt = NULL;
+	int cnt;
+	uint32_t timer;
+
+	ENTER("qla1280_req_pkt");
+
+	/*
+	 * This can be called from interrupt context, damn it!!!
+	 */
+	/* Wait for 30 seconds for slot. */
+	for (timer = 15000000; timer; timer--) {
+		if (ha->req_q_cnt > 0) {
+			/* Calculate number of free request entries. */
+			cnt = RD_REG_WORD(&reg->mailbox4);
+			if (ha->req_ring_index < cnt)
+				ha->req_q_cnt = cnt - ha->req_ring_index;
+			else
+				ha->req_q_cnt =
+					REQUEST_ENTRY_CNT - (ha->req_ring_index - cnt);
+		}
+
+		/* Found empty request ring slot? */
+		if (ha->req_q_cnt > 0) {
+			ha->req_q_cnt--;
+			pkt = ha->request_ring_ptr;
+
+			/* Zero out packet. */
+			memset(pkt, 0, REQUEST_ENTRY_SIZE);
+
+			/*
+			 * How can this be right when we have a ring
+			 * size of 512???
+			 */
+			/* Set system defined field. */
+			pkt->sys_define = (uint8_t) ha->req_ring_index;
+
+			/* Set entry count. */
+			pkt->entry_count = 1;
+
+			break;
+		}
+
+		udelay(2);	/* 10 */
+
+		/* Check for pending interrupts. */
+		qla1280_poll(ha);
+	}
+
+	if (!pkt)
+		dprintk(2, "qla1280_req_pkt: **** FAILED ****\n");
+	else
+		dprintk(3, "qla1280_req_pkt: exiting normally\n");
+
+	return pkt;
+}
+
+/*
+ * qla1280_isp_cmd
+ *      Function is responsible for modifying ISP input pointer.
+ *      Releases ring lock.
+ *
+ * Input:
+ *      ha  = adapter block pointer.
+ */
+static void
+qla1280_isp_cmd(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+
+	ENTER("qla1280_isp_cmd");
+
+	dprintk(5, "qla1280_isp_cmd: IOCB data:\n");
+	qla1280_dump_buffer(5, (char *)ha->request_ring_ptr,
+			    REQUEST_ENTRY_SIZE);
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == REQUEST_ENTRY_CNT) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else
+		ha->request_ring_ptr++;
+
+	/*
+	 * Update request index to mailbox4 (Request Queue In).
+	 * The mmiowb() ensures that this write is ordered with writes by other
+	 * CPUs.  Without the mmiowb(), it is possible for the following:
+	 *    CPUA posts write of index 5 to mailbox4
+	 *    CPUA releases host lock
+	 *    CPUB acquires host lock
+	 *    CPUB posts write of index 6 to mailbox4
+	 *    On PCI bus, order reverses and write of 6 posts, then index 5,
+	 *       causing chip to issue full queue of stale commands
+	 * The mmiowb() prevents future writes from crossing the barrier.
+	 * See Documentation/DocBook/deviceiobook.tmpl for more information.
+	 */
+	WRT_REG_WORD(&reg->mailbox4, ha->req_ring_index);
+	mmiowb();
+
+	LEAVE("qla1280_isp_cmd");
+}
+
+/****************************************************************************/
+/*                        Interrupt Service Routine.                        */
+/****************************************************************************/
+
+/****************************************************************************
+ *  qla1280_isr
+ *      Calls I/O done on command completion.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *      done_q       = done queue.
+ ****************************************************************************/
+static void
+qla1280_isr(struct scsi_qla_host *ha, struct list_head *done_q)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	struct response *pkt;
+	struct srb *sp = NULL;
+	uint16_t mailbox[MAILBOX_REGISTER_COUNT];
+	uint16_t *wptr;
+	uint32_t index;
+	u16 istatus;
+
+	ENTER("qla1280_isr");
+
+	istatus = RD_REG_WORD(&reg->istatus);
+	if (!(istatus & (RISC_INT | PCI_INT)))
+		return;
+
+	/* Save mailbox register 5 */
+	mailbox[5] = RD_REG_WORD(&reg->mailbox5);
+
+	/* Check for mailbox interrupt. */
+
+	mailbox[0] = RD_REG_WORD_dmasync(&reg->semaphore);
+
+	if (mailbox[0] & BIT_0) {
+		/* Get mailbox data. */
+		/* dprintk(1, "qla1280_isr: In Get mailbox data \n"); */
+
+		wptr = &mailbox[0];
+		*wptr++ = RD_REG_WORD(&reg->mailbox0);
+		*wptr++ = RD_REG_WORD(&reg->mailbox1);
+		*wptr = RD_REG_WORD(&reg->mailbox2);
+		if (mailbox[0] != MBA_SCSI_COMPLETION) {
+			wptr++;
+			*wptr++ = RD_REG_WORD(&reg->mailbox3);
+			*wptr++ = RD_REG_WORD(&reg->mailbox4);
+			wptr++;
+			*wptr++ = RD_REG_WORD(&reg->mailbox6);
+			*wptr = RD_REG_WORD(&reg->mailbox7);
+		}
+
+		/* Release mailbox registers. */
+
+		WRT_REG_WORD(&reg->semaphore, 0);
+		WRT_REG_WORD(&reg->host_cmd, HC_CLR_RISC_INT);
+
+		dprintk(5, "qla1280_isr: mailbox interrupt mailbox[0] = 0x%x",
+			mailbox[0]);
+
+		/* Handle asynchronous event */
+		switch (mailbox[0]) {
+		case MBA_SCSI_COMPLETION:	/* Response completion */
+			dprintk(5, "qla1280_isr: mailbox SCSI response "
+				"completion\n");
+
+			if (ha->flags.online) {
+				/* Get outstanding command index. */
+				index = mailbox[2] << 16 | mailbox[1];
+
+				/* Validate handle. */
+				if (index < MAX_OUTSTANDING_COMMANDS)
+					sp = ha->outstanding_cmds[index];
+				else
+					sp = NULL;
+
+				if (sp) {
+					/* Free outstanding command slot. */
+					ha->outstanding_cmds[index] = NULL;
+
+					/* Save ISP completion status */
+					CMD_RESULT(sp->cmd) = 0;
+
+					/* Place block on done queue */
+					list_add_tail(&sp->list, done_q);
+				} else {
+					/*
+					 * If we get here we have a real problem!
+					 */
+					printk(KERN_WARNING
+					       "qla1280: ISP invalid handle");
+				}
+			}
+			break;
+
+		case MBA_BUS_RESET:	/* SCSI Bus Reset */
+			ha->flags.reset_marker = 1;
+			index = mailbox[6] & BIT_0;
+			ha->bus_settings[index].reset_marker = 1;
+
+			printk(KERN_DEBUG "qla1280_isr(): index %i "
+			       "asynchronous BUS_RESET\n", index);
+			break;
+
+		case MBA_SYSTEM_ERR:	/* System Error */
+			printk(KERN_WARNING
+			       "qla1280: ISP System Error - mbx1=%xh, mbx2="
+			       "%xh, mbx3=%xh\n", mailbox[1], mailbox[2],
+			       mailbox[3]);
+			break;
+
+		case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
+			printk(KERN_WARNING
+			       "qla1280: ISP Request Transfer Error\n");
+			break;
+
+		case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
+			printk(KERN_WARNING
+			       "qla1280: ISP Response Transfer Error\n");
+			break;
+
+		case MBA_WAKEUP_THRES:	/* Request Queue Wake-up */
+			dprintk(2, "qla1280_isr: asynchronous WAKEUP_THRES\n");
+			break;
+
+		case MBA_TIMEOUT_RESET:	/* Execution Timeout Reset */
+			dprintk(2,
+				"qla1280_isr: asynchronous TIMEOUT_RESET\n");
+			break;
+
+		case MBA_DEVICE_RESET:	/* Bus Device Reset */
+			printk(KERN_INFO "qla1280_isr(): asynchronous "
+			       "BUS_DEVICE_RESET\n");
+
+			ha->flags.reset_marker = 1;
+			index = mailbox[6] & BIT_0;
+			ha->bus_settings[index].reset_marker = 1;
+			break;
+
+		case MBA_BUS_MODE_CHANGE:
+			dprintk(2,
+				"qla1280_isr: asynchronous BUS_MODE_CHANGE\n");
+			break;
+
+		default:
+			/* dprintk(1, "qla1280_isr: default case of switch MB \n"); */
+			if (mailbox[0] < MBA_ASYNC_EVENT) {
+				wptr = &mailbox[0];
+				memcpy((uint16_t *) ha->mailbox_out, wptr,
+				       MAILBOX_REGISTER_COUNT *
+				       sizeof(uint16_t));
+
+				if(ha->mailbox_wait != NULL)
+					complete(ha->mailbox_wait);
+			}
+			break;
+		}
+	} else {
+		WRT_REG_WORD(&reg->host_cmd, HC_CLR_RISC_INT);
+	}
+
+	/*
+	 * We will receive interrupts during mailbox testing prior to
+	 * the card being marked online, hence the double check.
+	 */
+	if (!(ha->flags.online && !ha->mailbox_wait)) {
+		dprintk(2, "qla1280_isr: Response pointer Error\n");
+		goto out;
+	}
+
+	if (mailbox[5] >= RESPONSE_ENTRY_CNT)
+		goto out;
+
+	while (ha->rsp_ring_index != mailbox[5]) {
+		pkt = ha->response_ring_ptr;
+
+		dprintk(5, "qla1280_isr: ha->rsp_ring_index = 0x%x, mailbox[5]"
+			" = 0x%x\n", ha->rsp_ring_index, mailbox[5]);
+		dprintk(5,"qla1280_isr: response packet data\n");
+		qla1280_dump_buffer(5, (char *)pkt, RESPONSE_ENTRY_SIZE);
+
+		if (pkt->entry_type == STATUS_TYPE) {
+			if ((le16_to_cpu(pkt->scsi_status) & 0xff)
+			    || pkt->comp_status || pkt->entry_status) {
+				dprintk(2, "qla1280_isr: ha->rsp_ring_index = "
+					"0x%x mailbox[5] = 0x%x, comp_status "
+					"= 0x%x, scsi_status = 0x%x\n",
+					ha->rsp_ring_index, mailbox[5],
+					le16_to_cpu(pkt->comp_status),
+					le16_to_cpu(pkt->scsi_status));
+			}
+		} else {
+			dprintk(2, "qla1280_isr: ha->rsp_ring_index = "
+				"0x%x, mailbox[5] = 0x%x\n",
+				ha->rsp_ring_index, mailbox[5]);
+			dprintk(2, "qla1280_isr: response packet data\n");
+			qla1280_dump_buffer(2, (char *)pkt,
+					    RESPONSE_ENTRY_SIZE);
+		}
+
+		if (pkt->entry_type == STATUS_TYPE || pkt->entry_status) {
+			dprintk(2, "status: Cmd %p, handle %i\n",
+				ha->outstanding_cmds[pkt->handle]->cmd,
+				pkt->handle);
+			if (pkt->entry_type == STATUS_TYPE)
+				qla1280_status_entry(ha, pkt, done_q);
+			else
+				qla1280_error_entry(ha, pkt, done_q);
+			/* Adjust ring index. */
+			ha->rsp_ring_index++;
+			if (ha->rsp_ring_index == RESPONSE_ENTRY_CNT) {
+				ha->rsp_ring_index = 0;
+				ha->response_ring_ptr =	ha->response_ring;
+			} else
+				ha->response_ring_ptr++;
+			WRT_REG_WORD(&reg->mailbox5, ha->rsp_ring_index);
+		}
+	}
+	
+ out:
+	LEAVE("qla1280_isr");
+}
+
+/*
+ *  qla1280_rst_aen
+ *      Processes asynchronous reset.
+ *
+ * Input:
+ *      ha  = adapter block pointer.
+ */
+static void
+qla1280_rst_aen(struct scsi_qla_host *ha)
+{
+	uint8_t bus;
+
+	ENTER("qla1280_rst_aen");
+
+	if (ha->flags.online && !ha->flags.reset_active &&
+	    !ha->flags.abort_isp_active) {
+		ha->flags.reset_active = 1;
+		while (ha->flags.reset_marker) {
+			/* Issue marker command. */
+			ha->flags.reset_marker = 0;
+			for (bus = 0; bus < ha->ports &&
+				     !ha->flags.reset_marker; bus++) {
+				if (ha->bus_settings[bus].reset_marker) {
+					ha->bus_settings[bus].reset_marker = 0;
+					qla1280_marker(ha, bus, 0, 0,
+						       MK_SYNC_ALL);
+				}
+			}
+		}
+	}
+
+	LEAVE("qla1280_rst_aen");
+}
+
+
+#if LINUX_VERSION_CODE < 0x020500
+/*
+ *
+ */
+static void
+qla1280_get_target_options(struct scsi_cmnd *cmd, struct scsi_qla_host *ha)
+{
+	unsigned char *result;
+	struct nvram *n;
+	int bus, target, lun;
+
+	bus = SCSI_BUS_32(cmd);
+	target = SCSI_TCN_32(cmd);
+	lun = SCSI_LUN_32(cmd);
+
+	/*
+	 * Make sure to not touch anything if someone is using the
+	 * sg interface.
+	 */
+	if (cmd->use_sg || (CMD_RESULT(cmd) >> 16) != DID_OK || lun)
+		return;
+
+	result = cmd->request_buffer;
+	n = &ha->nvram;
+
+	n->bus[bus].target[target].parameter.f.enable_wide = 0;
+	n->bus[bus].target[target].parameter.f.enable_sync = 0;
+	n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 0;
+
+        if (result[7] & 0x60)
+		n->bus[bus].target[target].parameter.f.enable_wide = 1;
+        if (result[7] & 0x10)
+		n->bus[bus].target[target].parameter.f.enable_sync = 1;
+	if ((result[2] >= 3) && (result[4] + 5 > 56) &&
+	    (result[56] & 0x4))
+		n->bus[bus].target[target].ppr_1x160.flags.enable_ppr = 1;
+
+	dprintk(2, "get_target_options(): wide %i, sync %i, ppr %i\n",
+		n->bus[bus].target[target].parameter.f.enable_wide,
+		n->bus[bus].target[target].parameter.f.enable_sync,
+		n->bus[bus].target[target].ppr_1x160.flags.enable_ppr);
+}
+#endif
+
+/*
+ *  qla1280_status_entry
+ *      Processes received ISP status entry.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *      pkt          = entry pointer.
+ *      done_q       = done queue.
+ */
+static void
+qla1280_status_entry(struct scsi_qla_host *ha, struct response *pkt,
+		     struct list_head *done_q)
+{
+	unsigned int bus, target, lun;
+	int sense_sz;
+	struct srb *sp;
+	struct scsi_cmnd *cmd;
+	uint32_t handle = le32_to_cpu(pkt->handle);
+	uint16_t scsi_status = le16_to_cpu(pkt->scsi_status);
+	uint16_t comp_status = le16_to_cpu(pkt->comp_status);
+
+	ENTER("qla1280_status_entry");
+
+	/* Validate handle. */
+	if (handle < MAX_OUTSTANDING_COMMANDS)
+		sp = ha->outstanding_cmds[handle];
+	else
+		sp = NULL;
+
+	if (!sp) {
+		printk(KERN_WARNING "qla1280: Status Entry invalid handle\n");
+		goto out;
+	}
+
+	/* Free outstanding command slot. */
+	ha->outstanding_cmds[handle] = NULL;
+
+	cmd = sp->cmd;
+
+	/* Generate LU queue on cntrl, target, LUN */
+	bus = SCSI_BUS_32(cmd);
+	target = SCSI_TCN_32(cmd);
+	lun = SCSI_LUN_32(cmd);
+
+	if (comp_status || scsi_status) {
+		dprintk(3, "scsi: comp_status = 0x%x, scsi_status = "
+			"0x%x, handle = 0x%x\n", comp_status,
+			scsi_status, handle);
+	}
+
+	/* Target busy */
+	if (scsi_status & SS_BUSY_CONDITION &&
+	    scsi_status != SS_RESERVE_CONFLICT) {
+		CMD_RESULT(cmd) =
+			DID_BUS_BUSY << 16 | (scsi_status & 0xff);
+	} else {
+
+		/* Save ISP completion status */
+		CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd);
+
+		if (scsi_status & SS_CHECK_CONDITION) {
+			if (comp_status != CS_ARS_FAILED) {
+				uint16_t req_sense_length =
+					le16_to_cpu(pkt->req_sense_length);
+				if (req_sense_length < CMD_SNSLEN(cmd))
+					sense_sz = req_sense_length;
+				else
+					/*
+					 * scsi_cmnd->sense_buffer is
+					 * 64 bytes, why only copy 63?
+					 * This looks wrong! /Jes
+					 */
+					sense_sz = CMD_SNSLEN(cmd) - 1;
+
+				memcpy(cmd->sense_buffer,
+				       &pkt->req_sense_data, sense_sz);
+			} else
+				sense_sz = 0;
+			memset(cmd->sense_buffer + sense_sz, 0,
+			       sizeof(cmd->sense_buffer) - sense_sz);
+
+			dprintk(2, "qla1280_status_entry: Check "
+				"condition Sense data, b %i, t %i, "
+				"l %i\n", bus, target, lun);
+			if (sense_sz)
+				qla1280_dump_buffer(2,
+						    (char *)cmd->sense_buffer,
+						    sense_sz);
+		}
+	}
+
+	/* Place command on done queue. */
+	list_add_tail(&sp->list, done_q);
+ out:
+	LEAVE("qla1280_status_entry");
+}
+
+/*
+ *  qla1280_error_entry
+ *      Processes error entry.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *      pkt          = entry pointer.
+ *      done_q       = done queue.
+ */
+static void
+qla1280_error_entry(struct scsi_qla_host *ha, struct response *pkt,
+		    struct list_head *done_q)
+{
+	struct srb *sp;
+	uint32_t handle = le32_to_cpu(pkt->handle);
+
+	ENTER("qla1280_error_entry");
+
+	if (pkt->entry_status & BIT_3)
+		dprintk(2, "qla1280_error_entry: BAD PAYLOAD flag error\n");
+	else if (pkt->entry_status & BIT_2)
+		dprintk(2, "qla1280_error_entry: BAD HEADER flag error\n");
+	else if (pkt->entry_status & BIT_1)
+		dprintk(2, "qla1280_error_entry: FULL flag error\n");
+	else
+		dprintk(2, "qla1280_error_entry: UNKNOWN flag error\n");
+
+	/* Validate handle. */
+	if (handle < MAX_OUTSTANDING_COMMANDS)
+		sp = ha->outstanding_cmds[handle];
+	else
+		sp = NULL;
+
+	if (sp) {
+		/* Free outstanding command slot. */
+		ha->outstanding_cmds[handle] = NULL;
+
+		/* Bad payload or header */
+		if (pkt->entry_status & (BIT_3 + BIT_2)) {
+			/* Bad payload or header, set error status. */
+			/* CMD_RESULT(sp->cmd) = CS_BAD_PAYLOAD; */
+			CMD_RESULT(sp->cmd) = DID_ERROR << 16;
+		} else if (pkt->entry_status & BIT_1) {	/* FULL flag */
+			CMD_RESULT(sp->cmd) = DID_BUS_BUSY << 16;
+		} else {
+			/* Set error status. */
+			CMD_RESULT(sp->cmd) = DID_ERROR << 16;
+		}
+
+		/* Place command on done queue. */
+		list_add_tail(&sp->list, done_q);
+	}
+#ifdef QLA_64BIT_PTR
+	else if (pkt->entry_type == COMMAND_A64_TYPE) {
+		printk(KERN_WARNING "!qla1280: Error Entry invalid handle");
+	}
+#endif
+
+	LEAVE("qla1280_error_entry");
+}
+
+/*
+ *  qla1280_abort_isp
+ *      Resets ISP and aborts all outstanding commands.
+ *
+ * Input:
+ *      ha           = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success
+ */
+static int
+qla1280_abort_isp(struct scsi_qla_host *ha)
+{
+	struct device_reg __iomem *reg = ha->iobase;
+	struct srb *sp;
+	int status = 0;
+	int cnt;
+	int bus;
+
+	ENTER("qla1280_abort_isp");
+
+	if (ha->flags.abort_isp_active || !ha->flags.online)
+		goto out;
+	
+	ha->flags.abort_isp_active = 1;
+
+	/* Disable ISP interrupts. */
+	qla1280_disable_intrs(ha);
+	WRT_REG_WORD(&reg->host_cmd, HC_PAUSE_RISC);
+	RD_REG_WORD(&reg->id_l);
+
+	printk(KERN_INFO "scsi(%li): dequeuing outstanding commands\n",
+	       ha->host_no);
+	/* Dequeue all commands in outstanding command list. */
+	for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		struct scsi_cmnd *cmd;
+		sp = ha->outstanding_cmds[cnt];
+		if (sp) {
+
+			cmd = sp->cmd;
+			CMD_RESULT(cmd) = DID_RESET << 16;
+
+			sp->cmd = NULL;
+			ha->outstanding_cmds[cnt] = NULL;
+
+			(*cmd->scsi_done)(cmd);
+
+			sp->flags = 0;
+		}
+	}
+
+	status = qla1280_load_firmware(ha);
+	if (status)
+		goto out;
+
+	/* Setup adapter based on NVRAM parameters. */
+	qla1280_nvram_config (ha);
+
+	status = qla1280_init_rings(ha);
+	if (status)
+		goto out;
+		
+	/* Issue SCSI reset. */
+	for (bus = 0; bus < ha->ports; bus++)
+		qla1280_bus_reset(ha, bus);
+		
+	ha->flags.abort_isp_active = 0;
+ out:
+	if (status) {
+		printk(KERN_WARNING
+		       "qla1280: ISP error recovery failed, board disabled");
+		qla1280_reset_adapter(ha);
+		dprintk(2, "qla1280_abort_isp: **** FAILED ****\n");
+	}
+
+	LEAVE("qla1280_abort_isp");
+	return status;
+}
+
+
+/*
+ * qla1280_debounce_register
+ *      Debounce register.
+ *
+ * Input:
+ *      port = register address.
+ *
+ * Returns:
+ *      register value.
+ */
+static u16
+qla1280_debounce_register(volatile u16 __iomem * addr)
+{
+	volatile u16 ret;
+	volatile u16 ret2;
+
+	ret = RD_REG_WORD(addr);
+	ret2 = RD_REG_WORD(addr);
+
+	if (ret == ret2)
+		return ret;
+
+	do {
+		cpu_relax();
+		ret = RD_REG_WORD(addr);
+		ret2 = RD_REG_WORD(addr);
+	} while (ret != ret2);
+
+	return ret;
+}
+
+
+/************************************************************************
+ * qla1280_check_for_dead_scsi_bus                                      *
+ *                                                                      *
+ *    This routine checks for a dead SCSI bus                           *
+ ************************************************************************/
+#define SET_SXP_BANK            0x0100
+#define SCSI_PHASE_INVALID      0x87FF
+static int
+qla1280_check_for_dead_scsi_bus(struct scsi_qla_host *ha, unsigned int bus)
+{
+	uint16_t config_reg, scsi_control;
+	struct device_reg __iomem *reg = ha->iobase;
+
+	if (ha->bus_settings[bus].scsi_bus_dead) {
+		WRT_REG_WORD(&reg->host_cmd, HC_PAUSE_RISC);
+		config_reg = RD_REG_WORD(&reg->cfg_1);
+		WRT_REG_WORD(&reg->cfg_1, SET_SXP_BANK);
+		scsi_control = RD_REG_WORD(&reg->scsiControlPins);
+		WRT_REG_WORD(&reg->cfg_1, config_reg);
+		WRT_REG_WORD(&reg->host_cmd, HC_RELEASE_RISC);
+
+		if (scsi_control == SCSI_PHASE_INVALID) {
+			ha->bus_settings[bus].scsi_bus_dead = 1;
+#if 0
+			CMD_RESULT(cp) = DID_NO_CONNECT << 16;
+			CMD_HANDLE(cp) = INVALID_HANDLE;
+			/* ha->actthreads--; */
+
+			(*(cp)->scsi_done)(cp);
+#endif
+			return 1;	/* bus is dead */
+		} else {
+			ha->bus_settings[bus].scsi_bus_dead = 0;
+			ha->bus_settings[bus].failed_reset_count = 0;
+		}
+	}
+	return 0;		/* bus is not dead */
+}
+
+static void
+qla1280_get_target_parameters(struct scsi_qla_host *ha,
+			      struct scsi_device *device)
+{
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+	int bus, target, lun;
+
+	bus = device->channel;
+	target = device->id;
+	lun = device->lun;
+
+
+	mb[0] = MBC_GET_TARGET_PARAMETERS;
+	mb[1] = (uint16_t) (bus ? target | BIT_7 : target);
+	mb[1] <<= 8;
+	qla1280_mailbox_command(ha, BIT_6 | BIT_3 | BIT_2 | BIT_1 | BIT_0,
+				&mb[0]);
+
+	printk(KERN_INFO "scsi(%li:%d:%d:%d):", ha->host_no, bus, target, lun);
+
+	if (mb[3] != 0) {
+		printk(" Sync: period %d, offset %d",
+		       (mb[3] & 0xff), (mb[3] >> 8));
+		if (mb[2] & BIT_13)
+			printk(", Wide");
+		if ((mb[2] & BIT_5) && ((mb[6] >> 8) & 0xff) >= 2)
+			printk(", DT");
+	} else
+		printk(" Async");
+
+	if (DEV_SIMPLE_TAGS(device))
+		printk(", Tagged queuing: depth %d", device->queue_depth);
+	printk("\n");
+}
+
+
+#if DEBUG_QLA1280
+static void
+__qla1280_dump_buffer(char *b, int size)
+{
+	int cnt;
+	u8 c;
+
+	printk(KERN_DEBUG " 0   1   2   3   4   5   6   7   8   9   Ah  "
+	       "Bh  Ch  Dh  Eh  Fh\n");
+	printk(KERN_DEBUG "---------------------------------------------"
+	       "------------------\n");
+
+	for (cnt = 0; cnt < size;) {
+		c = *b++;
+
+		printk("0x%02x", c);
+		cnt++;
+		if (!(cnt % 16))
+			printk("\n");
+		else
+			printk(" ");
+	}
+	if (cnt % 16)
+		printk("\n");
+}
+
+/**************************************************************************
+ *   ql1280_print_scsi_cmd
+ *
+ **************************************************************************/
+static void
+__qla1280_print_scsi_cmd(struct scsi_cmnd *cmd)
+{
+	struct scsi_qla_host *ha;
+	struct Scsi_Host *host = CMD_HOST(cmd);
+	struct srb *sp;
+	/* struct scatterlist *sg; */
+
+	int i;
+	ha = (struct scsi_qla_host *)host->hostdata;
+
+	sp = (struct srb *)CMD_SP(cmd);
+	printk("SCSI Command @= 0x%p, Handle=0x%p\n", cmd, CMD_HANDLE(cmd));
+	printk("  chan=%d, target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+	       SCSI_BUS_32(cmd), SCSI_TCN_32(cmd), SCSI_LUN_32(cmd),
+	       CMD_CDBLEN(cmd));
+	printk(" CDB = ");
+	for (i = 0; i < cmd->cmd_len; i++) {
+		printk("0x%02x ", cmd->cmnd[i]);
+	}
+	printk("  seg_cnt =%d\n", cmd->use_sg);
+	printk("  request buffer=0x%p, request buffer len=0x%x\n",
+	       cmd->request_buffer, cmd->request_bufflen);
+	/* if (cmd->use_sg)
+	   {
+	   sg = (struct scatterlist *) cmd->request_buffer;
+	   printk("  SG buffer: \n");
+	   qla1280_dump_buffer(1, (char *)sg, (cmd->use_sg*sizeof(struct scatterlist)));
+	   } */
+	printk("  tag=%d, transfersize=0x%x \n",
+	       cmd->tag, cmd->transfersize);
+	printk("  Pid=%li, SP=0x%p\n", cmd->pid, CMD_SP(cmd));
+	printk(" underflow size = 0x%x, direction=0x%x\n",
+	       cmd->underflow, cmd->sc_data_direction);
+}
+
+/**************************************************************************
+ *   ql1280_dump_device
+ *
+ **************************************************************************/
+static void
+ql1280_dump_device(struct scsi_qla_host *ha)
+{
+
+	struct scsi_cmnd *cp;
+	struct srb *sp;
+	int i;
+
+	printk(KERN_DEBUG "Outstanding Commands on controller:\n");
+
+	for (i = 0; i < MAX_OUTSTANDING_COMMANDS; i++) {
+		if ((sp = ha->outstanding_cmds[i]) == NULL)
+			continue;
+		if ((cp = sp->cmd) == NULL)
+			continue;
+		qla1280_print_scsi_cmd(1, cp);
+	}
+}
+#endif
+
+
+enum tokens {
+	TOKEN_NVRAM,
+	TOKEN_SYNC,
+	TOKEN_WIDE,
+	TOKEN_PPR,
+	TOKEN_VERBOSE,
+	TOKEN_DEBUG,
+};
+
+struct setup_tokens {
+	char *token;
+	int val;
+};
+
+static struct setup_tokens setup_token[] __initdata = 
+{
+	{ "nvram", TOKEN_NVRAM },
+	{ "sync", TOKEN_SYNC },
+	{ "wide", TOKEN_WIDE },
+	{ "ppr", TOKEN_PPR },
+	{ "verbose", TOKEN_VERBOSE },
+	{ "debug", TOKEN_DEBUG },
+};
+
+
+/**************************************************************************
+ *   qla1280_setup
+ *
+ *   Handle boot parameters. This really needs to be changed so one
+ *   can specify per adapter parameters.
+ **************************************************************************/
+static int __init
+qla1280_setup(char *s)
+{
+	char *cp, *ptr;
+	unsigned long val;
+	int toke;
+
+	cp = s;
+
+	while (cp && (ptr = strchr(cp, ':'))) {
+		ptr++;
+		if (!strcmp(ptr, "yes")) {
+			val = 0x10000;
+			ptr += 3;
+		} else if (!strcmp(ptr, "no")) {
+ 			val = 0;
+			ptr += 2;
+		} else
+			val = simple_strtoul(ptr, &ptr, 0);
+
+		switch ((toke = qla1280_get_token(cp))) {
+		case TOKEN_NVRAM:
+			if (!val)
+				driver_setup.no_nvram = 1;
+			break;
+		case TOKEN_SYNC:
+			if (!val)
+				driver_setup.no_sync = 1;
+			else if (val != 0x10000)
+				driver_setup.sync_mask = val;
+			break;
+		case TOKEN_WIDE:
+			if (!val)
+				driver_setup.no_wide = 1;
+			else if (val != 0x10000)
+				driver_setup.wide_mask = val;
+			break;
+		case TOKEN_PPR:
+			if (!val)
+				driver_setup.no_ppr = 1;
+			else if (val != 0x10000)
+				driver_setup.ppr_mask = val;
+			break;
+		case TOKEN_VERBOSE:
+			qla1280_verbose = val;
+			break;
+		default:
+			printk(KERN_INFO "qla1280: unknown boot option %s\n",
+			       cp);
+		}
+
+		cp = strchr(ptr, ';');
+		if (cp)
+			cp++;
+		else {
+			break;
+		}
+	}
+	return 1;
+}
+
+
+static int
+qla1280_get_token(char *str)
+{
+	char *sep;
+	long ret = -1;
+	int i, len;
+
+	len = sizeof(setup_token)/sizeof(struct setup_tokens);
+
+	sep = strchr(str, ':');
+
+	if (sep) {
+		for (i = 0; i < len; i++){
+
+			if (!strncmp(setup_token[i].token, str, (sep - str))) {
+				ret =  setup_token[i].val;
+				break;
+			}
+		}
+	}
+
+	return ret;
+}
+
+#if LINUX_VERSION_CODE >= 0x020600
+static struct scsi_host_template qla1280_driver_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "qla1280",
+	.name			= "Qlogic ISP 1280/12160",
+	.info			= qla1280_info,
+	.slave_configure	= qla1280_slave_configure,
+	.queuecommand		= qla1280_queuecommand,
+	.eh_abort_handler	= qla1280_eh_abort,
+	.eh_device_reset_handler= qla1280_eh_device_reset,
+	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
+	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
+	.bios_param		= qla1280_biosparam,
+	.can_queue		= 0xfffff,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+#else
+static Scsi_Host_Template qla1280_driver_template = {
+	.proc_name		= "qla1280",
+	.name			= "Qlogic ISP 1280/12160",
+	.detect			= qla1280_detect,
+	.release		= qla1280_release,
+	.info			= qla1280_info,
+	.queuecommand		= qla1280_queuecommand,
+	.eh_abort_handler	= qla1280_eh_abort,
+	.eh_device_reset_handler= qla1280_eh_device_reset,
+	.eh_bus_reset_handler	= qla1280_eh_bus_reset,
+	.eh_host_reset_handler	= qla1280_eh_adapter_reset,
+	.bios_param		= qla1280_biosparam_old,
+	.can_queue		= 0xfffff,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.use_new_eh_code	= 1,
+};
+#endif
+
+static int __devinit
+qla1280_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	int devnum = id->driver_data;
+	struct qla_boards *bdp = &ql1280_board_tbl[devnum];
+	struct Scsi_Host *host;
+	struct scsi_qla_host *ha;
+	int error = -ENODEV;
+
+	/* Bypass all AMI SUBSYS VENDOR IDs */
+	if (pdev->subsystem_vendor == PCI_VENDOR_ID_AMI) {
+		printk(KERN_INFO
+		       "qla1280: Skipping AMI SubSys Vendor ID Chip\n");
+		goto error;
+	}
+
+	printk(KERN_INFO "qla1280: %s found on PCI bus %i, dev %i\n",
+	       bdp->name, pdev->bus->number, PCI_SLOT(pdev->devfn));
+	
+	if (pci_enable_device(pdev)) {
+		printk(KERN_WARNING
+		       "qla1280: Failed to enabled pci device, aborting.\n");
+		goto error;
+	}
+
+	pci_set_master(pdev);
+
+	error = -ENOMEM;
+	host = scsi_host_alloc(&qla1280_driver_template, sizeof(*ha));
+	if (!host) {
+		printk(KERN_WARNING
+		       "qla1280: Failed to register host, aborting.\n");
+		goto error_disable_device;
+	}
+
+	ha = (struct scsi_qla_host *)host->hostdata;
+	memset(ha, 0, sizeof(struct scsi_qla_host));
+
+	ha->pdev = pdev;
+	ha->devnum = devnum;	/* specifies microcode load address */
+
+#ifdef QLA_64BIT_PTR
+	if (pci_set_dma_mask(ha->pdev, (dma_addr_t) ~ 0ULL)) {
+		if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
+			printk(KERN_WARNING "scsi(%li): Unable to set a "
+			       " suitable DMA mask - aboring\n", ha->host_no);
+			error = -ENODEV;
+			goto error_free_irq;
+		}
+	} else
+		dprintk(2, "scsi(%li): 64 Bit PCI Addressing Enabled\n",
+			ha->host_no);
+#else
+	if (pci_set_dma_mask(ha->pdev, 0xffffffff)) {
+		printk(KERN_WARNING "scsi(%li): Unable to set a "
+		       " suitable DMA mask - aboring\n", ha->host_no);
+		error = -ENODEV;
+		goto error_free_irq;
+	}
+#endif
+
+	ha->request_ring = pci_alloc_consistent(ha->pdev,
+			((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
+			&ha->request_dma);
+	if (!ha->request_ring) {
+		printk(KERN_INFO "qla1280: Failed to get request memory\n");
+		goto error_put_host;
+	}
+
+	ha->response_ring = pci_alloc_consistent(ha->pdev,
+			((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
+			&ha->response_dma);
+	if (!ha->response_ring) {
+		printk(KERN_INFO "qla1280: Failed to get response memory\n");
+		goto error_free_request_ring;
+	}
+
+	ha->ports = bdp->numPorts;
+
+	ha->host = host;
+	ha->host_no = host->host_no;
+
+	host->irq = pdev->irq;
+	host->max_channel = bdp->numPorts - 1;
+	host->max_lun = MAX_LUNS - 1;
+	host->max_id = MAX_TARGETS;
+	host->max_sectors = 1024;
+	host->unique_id = host->host_no;
+
+#if LINUX_VERSION_CODE < 0x020545
+	host->select_queue_depths = qla1280_select_queue_depth;
+#endif
+
+	error = -ENODEV;
+
+#if MEMORY_MAPPED_IO
+	ha->mmpbase = ioremap(pci_resource_start(ha->pdev, 1),
+			      pci_resource_len(ha->pdev, 1));
+	if (!ha->mmpbase) {
+		printk(KERN_INFO "qla1280: Unable to map I/O memory\n");
+		goto error_free_response_ring;
+	}
+
+	host->base = (unsigned long)ha->mmpbase;
+	ha->iobase = (struct device_reg __iomem *)ha->mmpbase;
+#else
+	host->io_port = pci_resource_start(ha->pdev, 0);
+	if (!request_region(host->io_port, 0xff, "qla1280")) {
+		printk(KERN_INFO "qla1280: Failed to reserve i/o region "
+				 "0x%04lx-0x%04lx - already in use\n",
+		       host->io_port, host->io_port + 0xff);
+		goto error_free_response_ring;
+	}
+
+	ha->iobase = (struct device_reg *)host->io_port;
+#endif
+
+	INIT_LIST_HEAD(&ha->done_q);
+
+	/* Disable ISP interrupts. */
+	qla1280_disable_intrs(ha);
+
+	if (request_irq(pdev->irq, qla1280_intr_handler, SA_SHIRQ,
+				"qla1280", ha)) {
+		printk("qla1280 : Failed to reserve interrupt %d already "
+		       "in use\n", pdev->irq);
+		goto error_release_region;
+	}
+
+	/* load the F/W, read paramaters, and init the H/W */
+	if (qla1280_initialize_adapter(ha)) {
+		printk(KERN_INFO "qla1x160: Failed to initialize adapter\n");
+		goto error_free_irq;
+	}
+
+	/* set our host ID  (need to do something about our two IDs) */
+	host->this_id = ha->bus_settings[0].id;
+
+	pci_set_drvdata(pdev, host);
+
+#if LINUX_VERSION_CODE >= 0x020600
+	error = scsi_add_host(host, &pdev->dev);
+	if (error)
+		goto error_disable_adapter;
+	scsi_scan_host(host);
+#else
+	scsi_set_pci_device(host, pdev);
+#endif
+
+	return 0;
+
+#if LINUX_VERSION_CODE >= 0x020600
+ error_disable_adapter:
+	WRT_REG_WORD(&ha->iobase->ictrl, 0);
+#endif
+ error_free_irq:
+	free_irq(pdev->irq, ha);
+ error_release_region:
+#if MEMORY_MAPPED_IO
+	iounmap(ha->mmpbase);
+#else
+	release_region(host->io_port, 0xff);
+#endif
+ error_free_response_ring:
+	pci_free_consistent(ha->pdev,
+			((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
+			ha->response_ring, ha->response_dma);
+ error_free_request_ring:
+	pci_free_consistent(ha->pdev,
+			((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
+			ha->request_ring, ha->request_dma);
+ error_put_host:
+	scsi_host_put(host);
+ error_disable_device:
+	pci_disable_device(pdev);
+ error:
+	return error;
+}
+
+
+static void __devexit
+qla1280_remove_one(struct pci_dev *pdev)
+{
+	struct Scsi_Host *host = pci_get_drvdata(pdev);
+	struct scsi_qla_host *ha = (struct scsi_qla_host *)host->hostdata;
+
+#if LINUX_VERSION_CODE >= 0x020600
+	scsi_remove_host(host);
+#endif
+
+	WRT_REG_WORD(&ha->iobase->ictrl, 0);
+
+	free_irq(pdev->irq, ha);
+
+#if MEMORY_MAPPED_IO
+	iounmap(ha->mmpbase);
+#else
+	release_region(host->io_port, 0xff);
+#endif
+
+	pci_free_consistent(ha->pdev,
+			((REQUEST_ENTRY_CNT + 1) * (sizeof(request_t))),
+			ha->request_ring, ha->request_dma);
+	pci_free_consistent(ha->pdev,
+			((RESPONSE_ENTRY_CNT + 1) * (sizeof(struct response))),
+			ha->response_ring, ha->response_dma);
+
+	pci_disable_device(pdev);
+
+	scsi_host_put(host);
+}
+
+#if LINUX_VERSION_CODE >= 0x020600
+static struct pci_driver qla1280_pci_driver = {
+	.name		= "qla1280",
+	.id_table	= qla1280_pci_tbl,
+	.probe		= qla1280_probe_one,
+	.remove		= __devexit_p(qla1280_remove_one),
+};
+
+static int __init
+qla1280_init(void)
+{
+	if (sizeof(struct srb) > sizeof(struct scsi_pointer)) {
+		printk(KERN_WARNING
+		       "qla1280: struct srb too big, aborting\n");
+		return -EINVAL;
+	}
+
+#ifdef MODULE
+	/*
+	 * If we are called as a module, the qla1280 pointer may not be null
+	 * and it would point to our bootup string, just like on the lilo
+	 * command line.  IF not NULL, then process this config string with
+	 * qla1280_setup
+	 *
+	 * Boot time Options
+	 * To add options at boot time add a line to your lilo.conf file like:
+	 * append="qla1280=verbose,max_tags:{{255,255,255,255},{255,255,255,255}}"
+	 * which will result in the first four devices on the first two
+	 * controllers being set to a tagged queue depth of 32.
+	 */
+	if (qla1280)
+		qla1280_setup(qla1280);
+#endif
+
+	return pci_module_init(&qla1280_pci_driver);
+}
+
+static void __exit
+qla1280_exit(void)
+{
+	pci_unregister_driver(&qla1280_pci_driver);
+}
+
+module_init(qla1280_init);
+module_exit(qla1280_exit);
+
+#else
+# define driver_template qla1280_driver_template
+# include "scsi_module.c"
+#endif
+
+MODULE_AUTHOR("Qlogic & Jes Sorensen");
+MODULE_DESCRIPTION("Qlogic ISP SCSI (qla1x80/qla1x160) driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA1280_VERSION);
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only.  This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-basic-offset: 8
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
new file mode 100644
index 0000000..d245ae0
--- /dev/null
+++ b/drivers/scsi/qla1280.h
@@ -0,0 +1,1098 @@
+/******************************************************************************
+*                  QLOGIC LINUX SOFTWARE
+*
+* QLogic ISP1280 (Ultra2) /12160 (Ultra3) SCSI driver
+* Copyright (C) 2000 Qlogic Corporation
+* (www.qlogic.com)
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+*
+******************************************************************************/
+
+#ifndef	_QLA1280_H
+#define	_QLA1280_H
+
+/*
+ * Data bit definitions.
+ */
+#define BIT_0	0x1
+#define BIT_1	0x2
+#define BIT_2	0x4
+#define BIT_3	0x8
+#define BIT_4	0x10
+#define BIT_5	0x20
+#define BIT_6	0x40
+#define BIT_7	0x80
+#define BIT_8	0x100
+#define BIT_9	0x200
+#define BIT_10	0x400
+#define BIT_11	0x800
+#define BIT_12	0x1000
+#define BIT_13	0x2000
+#define BIT_14	0x4000
+#define BIT_15	0x8000
+#define BIT_16	0x10000
+#define BIT_17	0x20000
+#define BIT_18	0x40000
+#define BIT_19	0x80000
+#define BIT_20	0x100000
+#define BIT_21	0x200000
+#define BIT_22	0x400000
+#define BIT_23	0x800000
+#define BIT_24	0x1000000
+#define BIT_25	0x2000000
+#define BIT_26	0x4000000
+#define BIT_27	0x8000000
+#define BIT_28	0x10000000
+#define BIT_29	0x20000000
+#define BIT_30	0x40000000
+#define BIT_31	0x80000000
+
+#if MEMORY_MAPPED_IO
+#define RD_REG_WORD(addr)		readw_relaxed(addr)
+#define RD_REG_WORD_dmasync(addr)	readw(addr)
+#define WRT_REG_WORD(addr, data)	writew(data, addr)
+#else				/* MEMORY_MAPPED_IO */
+#define RD_REG_WORD(addr)		inw((unsigned long)addr)
+#define RD_REG_WORD_dmasync(addr)	RD_REG_WORD(addr)
+#define WRT_REG_WORD(addr, data)	outw(data, (unsigned long)addr)
+#endif				/* MEMORY_MAPPED_IO */
+
+/*
+ * Host adapter default definitions.
+ */
+#define MAX_BUSES	2	/* 2 */
+#define MAX_B_BITS	1
+
+#define MAX_TARGETS	16	/* 16 */
+#define MAX_T_BITS	4	/* 4 */
+
+#define MAX_LUNS	8	/* 32 */
+#define MAX_L_BITS	3	/* 5 */
+
+/*
+ * Watchdog time quantum
+ */
+#define QLA1280_WDG_TIME_QUANTUM	5	/* In seconds */
+
+/* Command retry count (0-65535) */
+#define COMMAND_RETRY_COUNT		255
+
+/* Maximum outstanding commands in ISP queues */
+#define MAX_OUTSTANDING_COMMANDS	512
+#define INVALID_HANDLE			(MAX_OUTSTANDING_COMMANDS + 2)
+
+/* ISP request and response entry counts (37-65535) */
+#define REQUEST_ENTRY_CNT		256 /* Number of request entries. */
+#define RESPONSE_ENTRY_CNT		16  /* Number of response entries. */
+
+/* Number of segments 1 - 65535 */
+#define SG_SEGMENTS			32  /* Cmd entry + 6 continuations */
+
+/*
+ * SCSI Request Block structure  (sp)  that is placed
+ * on cmd->SCp location of every I/O
+ */
+struct srb {
+	struct list_head list;		/* (8/16) LU queue */
+	struct scsi_cmnd *cmd;	/* (4/8) SCSI command block */
+	/* NOTE: the sp->cmd will be NULL when this completion is
+	 * called, so you should know the scsi_cmnd when using this */
+	struct completion *wait;
+	dma_addr_t saved_dma_handle;	/* for unmap of single transfers */
+	uint8_t flags;		/* (1) Status flags. */
+	uint8_t dir;		/* direction of transfer */
+};
+
+/*
+ * SRB flag definitions
+ */
+#define SRB_TIMEOUT		(1 << 0)	/* Command timed out */
+#define SRB_SENT		(1 << 1)	/* Command sent to ISP */
+#define SRB_ABORT_PENDING	(1 << 2)	/* Command abort sent to device */
+#define SRB_ABORTED		(1 << 3)	/* Command aborted command already */
+
+/*
+ *  ISP I/O Register Set structure definitions.
+ */
+struct device_reg {
+	uint16_t id_l;		/* ID low */
+	uint16_t id_h;		/* ID high */
+	uint16_t cfg_0;		/* Configuration 0 */
+#define ISP_CFG0_HWMSK   0x000f	/* Hardware revision mask */
+#define ISP_CFG0_1020    BIT_0	/* ISP1020 */
+#define ISP_CFG0_1020A	 BIT_1	/* ISP1020A */
+#define ISP_CFG0_1040	 BIT_2	/* ISP1040 */
+#define ISP_CFG0_1040A	 BIT_3	/* ISP1040A */
+#define ISP_CFG0_1040B	 BIT_4	/* ISP1040B */
+#define ISP_CFG0_1040C	 BIT_5	/* ISP1040C */
+	uint16_t cfg_1;		/* Configuration 1 */
+#define ISP_CFG1_F128    BIT_6  /* 128-byte FIFO threshold */
+#define ISP_CFG1_F64     BIT_4|BIT_5 /* 128-byte FIFO threshold */
+#define ISP_CFG1_F32     BIT_5  /* 128-byte FIFO threshold */
+#define ISP_CFG1_F16     BIT_4  /* 128-byte FIFO threshold */
+#define ISP_CFG1_BENAB   BIT_2  /* Global Bus burst enable */
+#define ISP_CFG1_SXP     BIT_0  /* SXP register select */
+	uint16_t ictrl;		/* Interface control */
+#define ISP_RESET        BIT_0	/* ISP soft reset */
+#define ISP_EN_INT       BIT_1	/* ISP enable interrupts. */
+#define ISP_EN_RISC      BIT_2	/* ISP enable RISC interrupts. */
+#define ISP_FLASH_ENABLE BIT_8	/* Flash BIOS Read/Write enable */
+#define ISP_FLASH_UPPER  BIT_9	/* Flash upper bank select */
+	uint16_t istatus;	/* Interface status */
+#define PCI_64BIT_SLOT   BIT_14	/* PCI 64-bit slot indicator. */
+#define RISC_INT         BIT_2	/* RISC interrupt */
+#define PCI_INT          BIT_1	/* PCI interrupt */
+	uint16_t semaphore;	/* Semaphore */
+	uint16_t nvram;		/* NVRAM register. */
+#define NV_DESELECT     0
+#define NV_CLOCK        BIT_0
+#define NV_SELECT       BIT_1
+#define NV_DATA_OUT     BIT_2
+#define NV_DATA_IN      BIT_3
+	uint16_t flash_data;	/* Flash BIOS data */
+	uint16_t flash_address;	/* Flash BIOS address */
+
+	uint16_t unused_1[0x06];
+	
+	/* cdma_* and ddma_* are 1040 only */
+	uint16_t cdma_cfg;
+#define CDMA_CONF_SENAB  BIT_3	/* SXP to DMA Data enable */
+#define CDMA_CONF_RIRQ   BIT_2	/* RISC interrupt enable */
+#define CDMA_CONF_BENAB  BIT_1	/* Bus burst enable */
+#define CDMA_CONF_DIR    BIT_0	/* DMA direction (0=fifo->host 1=host->fifo) */
+	uint16_t cdma_ctrl; 
+	uint16_t cdma_status;   
+	uint16_t cdma_fifo_status;
+	uint16_t cdma_count;
+	uint16_t cdma_reserved;
+	uint16_t cdma_address_count_0;
+	uint16_t cdma_address_count_1;
+	uint16_t cdma_address_count_2;
+	uint16_t cdma_address_count_3;
+
+	uint16_t unused_2[0x06];
+
+	uint16_t ddma_cfg;
+#define DDMA_CONF_SENAB  BIT_3	/* SXP to DMA Data enable */
+#define DDMA_CONF_RIRQ   BIT_2	/* RISC interrupt enable */
+#define DDMA_CONF_BENAB  BIT_1	/* Bus burst enable */
+#define DDMA_CONF_DIR    BIT_0	/* DMA direction (0=fifo->host 1=host->fifo) */
+	uint16_t ddma_ctrl;
+	uint16_t ddma_status; 
+	uint16_t ddma_fifo_status;
+	uint16_t ddma_xfer_count_low;
+	uint16_t ddma_xfer_count_high;
+	uint16_t ddma_addr_count_0;
+	uint16_t ddma_addr_count_1;
+	uint16_t ddma_addr_count_2;
+	uint16_t ddma_addr_count_3; 
+
+	uint16_t unused_3[0x0e];
+
+	uint16_t mailbox0;	/* Mailbox 0 */
+	uint16_t mailbox1;	/* Mailbox 1 */
+	uint16_t mailbox2;	/* Mailbox 2 */
+	uint16_t mailbox3;	/* Mailbox 3 */
+	uint16_t mailbox4;	/* Mailbox 4 */
+	uint16_t mailbox5;	/* Mailbox 5 */
+	uint16_t mailbox6;	/* Mailbox 6 */
+	uint16_t mailbox7;	/* Mailbox 7 */
+
+	uint16_t unused_4[0x20];/* 0x80-0xbf Gap */
+
+	uint16_t host_cmd;	/* Host command and control */
+#define HOST_INT      BIT_7	/* host interrupt bit */
+#define BIOS_ENABLE   BIT_0
+
+	uint16_t unused_5[0x5];	/* 0xc2-0xcb Gap */
+
+	uint16_t gpio_data;
+	uint16_t gpio_enable;
+
+	uint16_t unused_6[0x11];	/* d0-f0 */
+	uint16_t scsiControlPins;	/* f2 */
+};
+
+#define MAILBOX_REGISTER_COUNT	8
+
+/*
+ *  ISP product identification definitions in mailboxes after reset.
+ */
+#define PROD_ID_1		0x4953
+#define PROD_ID_2		0x0000
+#define PROD_ID_2a		0x5020
+#define PROD_ID_3		0x2020
+#define PROD_ID_4		0x1
+
+/*
+ * ISP host command and control register command definitions
+ */
+#define HC_RESET_RISC		0x1000	/* Reset RISC */
+#define HC_PAUSE_RISC		0x2000	/* Pause RISC */
+#define HC_RELEASE_RISC		0x3000	/* Release RISC from reset. */
+#define HC_SET_HOST_INT		0x5000	/* Set host interrupt */
+#define HC_CLR_HOST_INT		0x6000	/* Clear HOST interrupt */
+#define HC_CLR_RISC_INT		0x7000	/* Clear RISC interrupt */
+#define HC_DISABLE_BIOS		0x9000	/* Disable BIOS. */
+
+/*
+ * ISP mailbox Self-Test status codes
+ */
+#define MBS_FRM_ALIVE		0	/* Firmware Alive. */
+#define MBS_CHKSUM_ERR		1	/* Checksum Error. */
+#define MBS_SHADOW_LD_ERR	2	/* Shadow Load Error. */
+#define MBS_BUSY		4	/* Busy. */
+
+/*
+ * ISP mailbox command complete status codes
+ */
+#define MBS_CMD_CMP		0x4000	/* Command Complete. */
+#define MBS_INV_CMD		0x4001	/* Invalid Command. */
+#define MBS_HOST_INF_ERR	0x4002	/* Host Interface Error. */
+#define MBS_TEST_FAILED		0x4003	/* Test Failed. */
+#define MBS_CMD_ERR		0x4005	/* Command Error. */
+#define MBS_CMD_PARAM_ERR	0x4006	/* Command Parameter Error. */
+
+/*
+ * ISP mailbox asynchronous event status codes
+ */
+#define MBA_ASYNC_EVENT		0x8000	/* Asynchronous event. */
+#define MBA_BUS_RESET		0x8001	/* SCSI Bus Reset. */
+#define MBA_SYSTEM_ERR		0x8002	/* System Error. */
+#define MBA_REQ_TRANSFER_ERR	0x8003	/* Request Transfer Error. */
+#define MBA_RSP_TRANSFER_ERR	0x8004	/* Response Transfer Error. */
+#define MBA_WAKEUP_THRES	0x8005	/* Request Queue Wake-up. */
+#define MBA_TIMEOUT_RESET	0x8006	/* Execution Timeout Reset. */
+#define MBA_DEVICE_RESET	0x8007	/* Bus Device Reset. */
+#define MBA_BUS_MODE_CHANGE	0x800E	/* SCSI bus mode transition. */
+#define MBA_SCSI_COMPLETION	0x8020	/* Completion response. */
+
+/*
+ * ISP mailbox commands
+ */
+#define MBC_NOP				0	/* No Operation */
+#define MBC_LOAD_RAM			1	/* Load RAM */
+#define MBC_EXECUTE_FIRMWARE		2	/* Execute firmware */
+#define MBC_DUMP_RAM			3	/* Dump RAM contents */
+#define MBC_WRITE_RAM_WORD		4	/* Write ram word */
+#define MBC_READ_RAM_WORD		5	/* Read ram word */
+#define MBC_MAILBOX_REGISTER_TEST	6	/* Wrap incoming mailboxes */
+#define MBC_VERIFY_CHECKSUM		7	/* Verify checksum */
+#define MBC_ABOUT_FIRMWARE		8	/* Get firmware revision */
+#define MBC_INIT_REQUEST_QUEUE		0x10	/* Initialize request queue */
+#define MBC_INIT_RESPONSE_QUEUE		0x11	/* Initialize response queue */
+#define MBC_EXECUTE_IOCB		0x12	/* Execute IOCB command */
+#define MBC_ABORT_COMMAND		0x15	/* Abort IOCB command */
+#define MBC_ABORT_DEVICE		0x16	/* Abort device (ID/LUN) */
+#define MBC_ABORT_TARGET		0x17	/* Abort target (ID) */
+#define MBC_BUS_RESET			0x18	/* SCSI bus reset */
+#define MBC_GET_RETRY_COUNT		0x22	/* Get retry count and delay */
+#define MBC_GET_TARGET_PARAMETERS	0x28	/* Get target parameters */
+#define MBC_SET_INITIATOR_ID		0x30	/* Set initiator SCSI ID */
+#define MBC_SET_SELECTION_TIMEOUT	0x31	/* Set selection timeout */
+#define MBC_SET_RETRY_COUNT		0x32	/* Set retry count and delay */
+#define MBC_SET_TAG_AGE_LIMIT		0x33	/* Set tag age limit */
+#define MBC_SET_CLOCK_RATE		0x34	/* Set clock rate */
+#define MBC_SET_ACTIVE_NEGATION		0x35	/* Set active negation state */
+#define MBC_SET_ASYNC_DATA_SETUP	0x36	/* Set async data setup time */
+#define MBC_SET_PCI_CONTROL		0x37	/* Set BUS control parameters */
+#define MBC_SET_TARGET_PARAMETERS	0x38	/* Set target parameters */
+#define MBC_SET_DEVICE_QUEUE		0x39	/* Set device queue parameters */
+#define MBC_SET_RESET_DELAY_PARAMETERS	0x3A	/* Set reset delay parameters */
+#define MBC_SET_SYSTEM_PARAMETER	0x45	/* Set system parameter word */
+#define MBC_SET_FIRMWARE_FEATURES	0x4A	/* Set firmware feature word */
+#define MBC_INIT_REQUEST_QUEUE_A64	0x52	/* Initialize request queue A64 */
+#define MBC_INIT_RESPONSE_QUEUE_A64	0x53	/* Initialize response q A64 */
+#define MBC_ENABLE_TARGET_MODE		0x55	/* Enable target mode */
+#define MBC_SET_DATA_OVERRUN_RECOVERY	0x5A	/* Set data overrun recovery mode */
+
+/*
+ * ISP Get/Set Target Parameters mailbox command control flags.
+ */
+#define TP_PPR			BIT_5	/* PPR */
+#define TP_RENEGOTIATE		BIT_8	/* Renegotiate on error. */
+#define TP_STOP_QUEUE           BIT_9	/* Stop que on check condition */
+#define TP_AUTO_REQUEST_SENSE   BIT_10	/* Automatic request sense. */
+#define TP_TAGGED_QUEUE         BIT_11	/* Tagged queuing. */
+#define TP_SYNC                 BIT_12	/* Synchronous data transfers. */
+#define TP_WIDE                 BIT_13	/* Wide data transfers. */
+#define TP_PARITY               BIT_14	/* Parity checking. */
+#define TP_DISCONNECT           BIT_15	/* Disconnect privilege. */
+
+/*
+ * NVRAM Command values.
+ */
+#define NV_START_BIT		BIT_2
+#define NV_WRITE_OP		(BIT_26 | BIT_24)
+#define NV_READ_OP		(BIT_26 | BIT_25)
+#define NV_ERASE_OP		(BIT_26 | BIT_25 | BIT_24)
+#define NV_MASK_OP		(BIT_26 | BIT_25 | BIT_24)
+#define NV_DELAY_COUNT		10
+
+/*
+ *  QLogic ISP1280/ISP12160 NVRAM structure definition.
+ */
+struct nvram {
+	uint8_t id0;		/* 0 */
+	uint8_t id1;		/* 1 */
+	uint8_t id2;		/* 2 */
+	uint8_t id3;		/* 3 */
+	uint8_t version;	/* 4 */
+
+	struct {
+		uint8_t bios_configuration_mode:2;
+		uint8_t bios_disable:1;
+		uint8_t selectable_scsi_boot_enable:1;
+		uint8_t cd_rom_boot_enable:1;
+		uint8_t disable_loading_risc_code:1;
+		uint8_t enable_64bit_addressing:1;
+		uint8_t unused_7:1;
+	} cntr_flags_1;		/* 5 */
+
+	struct {
+		uint8_t boot_lun_number:5;
+		uint8_t scsi_bus_number:1;
+		uint8_t unused_6:1;
+		uint8_t unused_7:1;
+	} cntr_flags_2l;	/* 7 */
+
+	struct {
+		uint8_t boot_target_number:4;
+		uint8_t unused_12:1;
+		uint8_t unused_13:1;
+		uint8_t unused_14:1;
+		uint8_t unused_15:1;
+	} cntr_flags_2h;	/* 8 */
+
+	uint16_t unused_8;	/* 8, 9 */
+	uint16_t unused_10;	/* 10, 11 */
+	uint16_t unused_12;	/* 12, 13 */
+	uint16_t unused_14;	/* 14, 15 */
+
+	union {
+		uint8_t c;
+		struct {
+			uint8_t reserved:2;
+			uint8_t burst_enable:1;
+			uint8_t reserved_1:1;
+			uint8_t fifo_threshold:4;
+		} f;
+	} isp_config;		/* 16 */
+
+	/* Termination
+	 * 0 = Disable, 1 = high only, 3 = Auto term
+	 */
+	union {
+		uint8_t c;
+		struct {
+			uint8_t scsi_bus_1_control:2;
+			uint8_t scsi_bus_0_control:2;
+			uint8_t unused_0:1;
+			uint8_t unused_1:1;
+			uint8_t unused_2:1;
+			uint8_t auto_term_support:1;
+		} f;
+	} termination;		/* 17 */
+
+	uint16_t isp_parameter;	/* 18, 19 */
+
+	union {
+		uint16_t w;
+		struct {
+			uint16_t enable_fast_posting:1;
+			uint16_t report_lvd_bus_transition:1;
+			uint16_t unused_2:1;
+			uint16_t unused_3:1;
+			uint16_t disable_iosbs_with_bus_reset_status:1;
+			uint16_t disable_synchronous_backoff:1;
+			uint16_t unused_6:1;
+			uint16_t synchronous_backoff_reporting:1;
+			uint16_t disable_reselection_fairness:1;
+			uint16_t unused_9:1;
+			uint16_t unused_10:1;
+			uint16_t unused_11:1;
+			uint16_t unused_12:1;
+			uint16_t unused_13:1;
+			uint16_t unused_14:1;
+			uint16_t unused_15:1;
+		} f;
+	} firmware_feature;	/* 20, 21 */
+
+	uint16_t unused_22;	/* 22, 23 */
+
+	struct {
+		struct {
+			uint8_t initiator_id:4;
+			uint8_t scsi_reset_disable:1;
+			uint8_t scsi_bus_size:1;
+			uint8_t scsi_bus_type:1;
+			uint8_t unused_7:1;
+		} config_1;	/* 24 */
+
+		uint8_t bus_reset_delay;	/* 25 */
+		uint8_t retry_count;	/* 26 */
+		uint8_t retry_delay;	/* 27 */
+
+		struct {
+			uint8_t async_data_setup_time:4;
+			uint8_t req_ack_active_negation:1;
+			uint8_t data_line_active_negation:1;
+			uint8_t unused_6:1;
+			uint8_t unused_7:1;
+		} config_2;	/* 28 */
+
+		uint8_t unused_29;	/* 29 */
+
+		uint16_t selection_timeout;	/* 30, 31 */
+		uint16_t max_queue_depth;	/* 32, 33 */
+
+		uint16_t unused_34;	/* 34, 35 */
+		uint16_t unused_36;	/* 36, 37 */
+		uint16_t unused_38;	/* 38, 39 */
+
+		struct {
+			union {
+				uint8_t c;
+				struct {
+					uint8_t renegotiate_on_error:1;
+					uint8_t stop_queue_on_check:1;
+					uint8_t auto_request_sense:1;
+					uint8_t tag_queuing:1;
+					uint8_t enable_sync:1;
+					uint8_t enable_wide:1;
+					uint8_t parity_checking:1;
+					uint8_t disconnect_allowed:1;
+				} f;
+			} parameter;	/* 40 */
+
+			uint8_t execution_throttle;	/* 41 */
+			uint8_t sync_period;	/* 42 */
+
+			union {		/* 43 */
+				uint8_t flags_43;
+				struct {
+					uint8_t sync_offset:4;
+					uint8_t device_enable:1;
+					uint8_t lun_disable:1;
+					uint8_t unused_6:1;
+					uint8_t unused_7:1;
+				} flags1x80;
+				struct {
+					uint8_t sync_offset:5;
+					uint8_t device_enable:1;
+					uint8_t unused_6:1;
+					uint8_t unused_7:1;
+				} flags1x160;
+			} flags;
+			union {	/* PPR flags for the 1x160 controllers */
+				uint8_t unused_44;
+				struct {
+					uint8_t ppr_options:4;
+					uint8_t ppr_bus_width:2;
+					uint8_t unused_8:1;
+					uint8_t enable_ppr:1;
+				} flags;	/* 44 */
+			} ppr_1x160;
+			uint8_t unused_45;	/* 45 */
+		} target[MAX_TARGETS];
+	} bus[MAX_BUSES];
+
+	uint16_t unused_248;	/* 248, 249 */
+
+	uint16_t subsystem_id[2];	/* 250, 251, 252, 253 */
+
+	union {				/* 254 */
+		uint8_t unused_254;
+		uint8_t system_id_pointer;
+	} sysid_1x160;
+
+	uint8_t chksum;		/* 255 */
+};
+
+/*
+ * ISP queue - command entry structure definition.
+ */
+#define MAX_CMDSZ	12		/* SCSI maximum CDB size. */
+struct cmd_entry {
+	uint8_t entry_type;		/* Entry type. */
+#define COMMAND_TYPE    1		/* Command entry */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	uint8_t lun;			/* SCSI LUN */
+	uint8_t target;			/* SCSI ID */
+	uint16_t cdb_len;		/* SCSI command length. */
+	uint16_t control_flags;		/* Control flags. */
+	uint16_t reserved;
+	uint16_t timeout;		/* Command timeout. */
+	uint16_t dseg_count;		/* Data segment count. */
+	uint8_t scsi_cdb[MAX_CMDSZ];	/* SCSI command words. */
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+	uint32_t dseg_2_address;	/* Data segment 2 address. */
+	uint32_t dseg_2_length;		/* Data segment 2 length. */
+	uint32_t dseg_3_address;	/* Data segment 3 address. */
+	uint32_t dseg_3_length;		/* Data segment 3 length. */
+};
+
+/*
+ * ISP queue - continuation entry structure definition.
+ */
+struct cont_entry {
+	uint8_t entry_type;		/* Entry type. */
+#define CONTINUE_TYPE   2		/* Continuation entry. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t reserved;		/* Reserved */
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+	uint32_t dseg_2_address;	/* Data segment 2 address. */
+	uint32_t dseg_2_length;		/* Data segment 2 length. */
+	uint32_t dseg_3_address;	/* Data segment 3 address. */
+	uint32_t dseg_3_length;		/* Data segment 3 length. */
+	uint32_t dseg_4_address;	/* Data segment 4 address. */
+	uint32_t dseg_4_length;		/* Data segment 4 length. */
+	uint32_t dseg_5_address;	/* Data segment 5 address. */
+	uint32_t dseg_5_length;		/* Data segment 5 length. */
+	uint32_t dseg_6_address;	/* Data segment 6 address. */
+	uint32_t dseg_6_length;		/* Data segment 6 length. */
+};
+
+/*
+ * ISP queue - status entry structure definition.
+ */
+struct response {
+	uint8_t entry_type;	/* Entry type. */
+#define STATUS_TYPE     3	/* Status entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t sys_define;	/* System defined. */
+	uint8_t entry_status;	/* Entry Status. */
+#define RF_CONT         BIT_0	/* Continuation. */
+#define RF_FULL         BIT_1	/* Full */
+#define RF_BAD_HEADER   BIT_2	/* Bad header. */
+#define RF_BAD_PAYLOAD  BIT_3	/* Bad payload. */
+	uint32_t handle;	/* System handle. */
+	uint16_t scsi_status;	/* SCSI status. */
+	uint16_t comp_status;	/* Completion status. */
+	uint16_t state_flags;	/* State flags. */
+#define SF_TRANSFER_CMPL BIT_14	/* Transfer Complete. */
+#define SF_GOT_SENSE    BIT_13	/* Got Sense */
+#define SF_GOT_STATUS    BIT_12	/* Got Status */
+#define SF_TRANSFERRED_DATA BIT_11	/* Transferred data */
+#define SF_SENT_CDB   BIT_10	/* Send CDB */
+#define SF_GOT_TARGET  BIT_9	/*  */
+#define SF_GOT_BUS     BIT_8	/*  */
+	uint16_t status_flags;	/* Status flags. */
+	uint16_t time;		/* Time. */
+	uint16_t req_sense_length;	/* Request sense data length. */
+	uint32_t residual_length;	/* Residual transfer length. */
+	uint16_t reserved[4];
+	uint8_t req_sense_data[32];	/* Request sense data. */
+};
+
+/*
+ * ISP queue - marker entry structure definition.
+ */
+struct mrk_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define MARKER_TYPE     4	/* Marker entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t sys_define;	/* System defined. */
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t target;		/* SCSI ID */
+	uint8_t modifier;	/* Modifier (7-0). */
+#define MK_SYNC_ID_LUN      0	/* Synchronize ID/LUN */
+#define MK_SYNC_ID          1	/* Synchronize ID */
+#define MK_SYNC_ALL         2	/* Synchronize all ID/LUN */
+	uint8_t reserved_1[53];
+};
+
+/*
+ * ISP queue - extended command entry structure definition.
+ *
+ * Unused by the driver!
+ */
+struct ecmd_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define EXTENDED_CMD_TYPE  5	/* Extended command entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t sys_define;	/* System defined. */
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t handle;	/* System handle. */
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t target;		/* SCSI ID */
+	uint16_t cdb_len;	/* SCSI command length. */
+	uint16_t control_flags;	/* Control flags. */
+	uint16_t reserved;
+	uint16_t timeout;	/* Command timeout. */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint8_t scsi_cdb[88];	/* SCSI command words. */
+};
+
+/*
+ * ISP queue - 64-Bit addressing, command entry structure definition.
+ */
+typedef struct {
+	uint8_t entry_type;	/* Entry type. */
+#define COMMAND_A64_TYPE 9	/* Command A64 entry */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t sys_define;	/* System defined. */
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t handle;	/* System handle. */
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t target;		/* SCSI ID */
+	uint16_t cdb_len;	/* SCSI command length. */
+	uint16_t control_flags;	/* Control flags. */
+	uint16_t reserved;
+	uint16_t timeout;	/* Command timeout. */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint8_t scsi_cdb[MAX_CMDSZ];	/* SCSI command words. */
+	uint32_t reserved_1[2];	/* unused */
+	uint32_t dseg_0_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_0_length;	/* Data segment 0 length. */
+	uint32_t dseg_1_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_1_length;	/* Data segment 1 length. */
+} cmd_a64_entry_t, request_t;
+
+/*
+ * ISP queue - 64-Bit addressing, continuation entry structure definition.
+ */
+struct cont_a64_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define CONTINUE_A64_TYPE 0xA	/* Continuation A64 entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t sys_define;	/* System defined. */
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t dseg_0_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_0_length;	/* Data segment 0 length. */
+	uint32_t dseg_1_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_1_length;	/* Data segment 1 length. */
+	uint32_t dseg_2_address[2];	/* Data segment 2 address. */
+	uint32_t dseg_2_length;	/* Data segment 2 length. */
+	uint32_t dseg_3_address[2];	/* Data segment 3 address. */
+	uint32_t dseg_3_length;	/* Data segment 3 length. */
+	uint32_t dseg_4_address[2];	/* Data segment 4 address. */
+	uint32_t dseg_4_length;	/* Data segment 4 length. */
+};
+
+/*
+ * ISP queue - enable LUN entry structure definition.
+ */
+struct elun_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define ENABLE_LUN_TYPE 0xB	/* Enable LUN entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status not used. */
+	uint32_t reserved_2;
+	uint16_t lun;		/* Bit 15 is bus number. */
+	uint16_t reserved_4;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t reserved_5;
+	uint8_t command_count;	/* Number of ATIOs allocated. */
+	uint8_t immed_notify_count;	/* Number of Immediate Notify */
+	/* entries allocated. */
+	uint8_t group_6_length;	/* SCSI CDB length for group 6 */
+	/* commands (2-26). */
+	uint8_t group_7_length;	/* SCSI CDB length for group 7 */
+	/* commands (2-26). */
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t reserved_6[20];
+};
+
+/*
+ * ISP queue - modify LUN entry structure definition.
+ *
+ * Unused by the driver!
+ */
+struct modify_lun_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define MODIFY_LUN_TYPE 0xC	/* Modify LUN entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t reserved_3;
+	uint8_t operators;
+	uint8_t reserved_4;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t reserved_5;
+	uint8_t command_count;	/* Number of ATIOs allocated. */
+	uint8_t immed_notify_count;	/* Number of Immediate Notify */
+	/* entries allocated. */
+	uint16_t reserved_6;
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t reserved_7[20];
+};
+
+/*
+ * ISP queue - immediate notify entry structure definition.
+ */
+struct notify_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define IMMED_NOTIFY_TYPE 0xD	/* Immediate notify entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t reserved_4;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	/* entries allocated. */
+	uint16_t seq_id;
+	uint8_t scsi_msg[8];	/* SCSI message not handled by ISP */
+	uint16_t reserved_5[8];
+	uint8_t sense_data[18];
+};
+
+/*
+ * ISP queue - notify acknowledge entry structure definition.
+ */
+struct nack_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define NOTIFY_ACK_TYPE 0xE	/* Notify acknowledge entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t event;
+	uint16_t seq_id;
+	uint16_t reserved_4[22];
+};
+
+/*
+ * ISP queue - Accept Target I/O (ATIO) entry structure definition.
+ */
+struct atio_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define ACCEPT_TGT_IO_TYPE 6	/* Accept target I/O entry. */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;
+	uint8_t initiator_id;
+	uint8_t cdb_len;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t scsi_status;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	uint8_t cdb[26];
+	uint8_t sense_data[18];
+};
+
+/*
+ * ISP queue - Continue Target I/O (CTIO) entry structure definition.
+ */
+struct ctio_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define CONTINUE_TGT_IO_TYPE 7	/* CTIO entry */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t scsi_status;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	uint32_t transfer_length;
+	uint32_t residual;
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;	/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint32_t dseg_1_length;	/* Data segment 1 length. */
+	uint32_t dseg_2_address;	/* Data segment 2 address. */
+	uint32_t dseg_2_length;	/* Data segment 2 length. */
+	uint32_t dseg_3_address;	/* Data segment 3 address. */
+	uint32_t dseg_3_length;	/* Data segment 3 length. */
+};
+
+/*
+ * ISP queue - CTIO returned entry structure definition.
+ */
+struct ctio_ret_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define CTIO_RET_TYPE   7	/* CTIO return entry */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t scsi_status;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	uint32_t transfer_length;
+	uint32_t residual;
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;	/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint16_t dseg_1_length;	/* Data segment 1 length. */
+	uint8_t sense_data[18];
+};
+
+/*
+ * ISP queue - CTIO A64 entry structure definition.
+ */
+struct ctio_a64_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define CTIO_A64_TYPE 0xF	/* CTIO A64 entry */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t scsi_status;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	uint32_t transfer_length;
+	uint32_t residual;
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint32_t reserved_4[2];
+	uint32_t dseg_0_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_0_length;	/* Data segment 0 length. */
+	uint32_t dseg_1_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_1_length;	/* Data segment 1 length. */
+};
+
+/*
+ * ISP queue - CTIO returned entry structure definition.
+ */
+struct ctio_a64_ret_entry {
+	uint8_t entry_type;	/* Entry type. */
+#define CTIO_A64_RET_TYPE 0xF	/* CTIO A64 returned entry */
+	uint8_t entry_count;	/* Entry count. */
+	uint8_t reserved_1;
+	uint8_t entry_status;	/* Entry Status. */
+	uint32_t reserved_2;
+	uint8_t lun;		/* SCSI LUN */
+	uint8_t initiator_id;
+	uint8_t reserved_3;
+	uint8_t target_id;
+	uint32_t option_flags;
+	uint8_t status;
+	uint8_t scsi_status;
+	uint8_t tag_value;	/* Received queue tag message value */
+	uint8_t tag_type;	/* Received queue tag message type */
+	uint32_t transfer_length;
+	uint32_t residual;
+	uint16_t timeout;	/* 0 = 30 seconds, 0xFFFF = disable */
+	uint16_t dseg_count;	/* Data segment count. */
+	uint16_t reserved_4[7];
+	uint8_t sense_data[18];
+};
+
+/*
+ * ISP request and response queue entry sizes
+ */
+#define RESPONSE_ENTRY_SIZE	(sizeof(struct response))
+#define REQUEST_ENTRY_SIZE	(sizeof(request_t))
+
+/*
+ * ISP status entry - completion status definitions.
+ */
+#define CS_COMPLETE         0x0	/* No errors */
+#define CS_INCOMPLETE       0x1	/* Incomplete transfer of cmd. */
+#define CS_DMA              0x2	/* A DMA direction error. */
+#define CS_TRANSPORT        0x3	/* Transport error. */
+#define CS_RESET            0x4	/* SCSI bus reset occurred */
+#define CS_ABORTED          0x5	/* System aborted command. */
+#define CS_TIMEOUT          0x6	/* Timeout error. */
+#define CS_DATA_OVERRUN     0x7	/* Data overrun. */
+#define CS_COMMAND_OVERRUN  0x8	/* Command Overrun. */
+#define CS_STATUS_OVERRUN   0x9	/* Status Overrun. */
+#define CS_BAD_MSG          0xA	/* Bad msg after status phase. */
+#define CS_NO_MSG_OUT       0xB	/* No msg out after selection. */
+#define CS_EXTENDED_ID      0xC	/* Extended ID failed. */
+#define CS_IDE_MSG          0xD	/* Target rejected IDE msg. */
+#define CS_ABORT_MSG        0xE	/* Target rejected abort msg. */
+#define CS_REJECT_MSG       0xF	/* Target rejected reject msg. */
+#define CS_NOP_MSG          0x10	/* Target rejected NOP msg. */
+#define CS_PARITY_MSG       0x11	/* Target rejected parity msg. */
+#define CS_DEV_RESET_MSG    0x12	/* Target rejected dev rst msg. */
+#define CS_ID_MSG           0x13	/* Target rejected ID msg. */
+#define CS_FREE             0x14	/* Unexpected bus free. */
+#define CS_DATA_UNDERRUN    0x15	/* Data Underrun. */
+#define CS_TRANACTION_1     0x18	/* Transaction error 1 */
+#define CS_TRANACTION_2     0x19	/* Transaction error 2 */
+#define CS_TRANACTION_3     0x1a	/* Transaction error 3 */
+#define CS_INV_ENTRY_TYPE   0x1b	/* Invalid entry type */
+#define CS_DEV_QUEUE_FULL   0x1c	/* Device queue full */
+#define CS_PHASED_SKIPPED   0x1d	/* SCSI phase skipped */
+#define CS_ARS_FAILED       0x1e	/* ARS failed */
+#define CS_LVD_BUS_ERROR    0x21	/* LVD bus error */
+#define CS_BAD_PAYLOAD      0x80	/* Driver defined */
+#define CS_UNKNOWN          0x81	/* Driver defined */
+#define CS_RETRY            0x82	/* Driver defined */
+
+/*
+ * ISP status entry - SCSI status byte bit definitions.
+ */
+#define SS_CHECK_CONDITION  BIT_1
+#define SS_CONDITION_MET    BIT_2
+#define SS_BUSY_CONDITION   BIT_3
+#define SS_RESERVE_CONFLICT (BIT_4 | BIT_3)
+
+/*
+ * ISP target entries - Option flags bit definitions.
+ */
+#define OF_ENABLE_TAG       BIT_1	/* Tagged queue action enable */
+#define OF_DATA_IN          BIT_6	/* Data in to initiator */
+					/*  (data from target to initiator) */
+#define OF_DATA_OUT         BIT_7	/* Data out from initiator */
+					/*  (data from initiator to target) */
+#define OF_NO_DATA          (BIT_7 | BIT_6)
+#define OF_DISC_DISABLED    BIT_15	/* Disconnects disabled */
+#define OF_DISABLE_SDP      BIT_24	/* Disable sending save data ptr */
+#define OF_SEND_RDP         BIT_26	/* Send restore data pointers msg */
+#define OF_FORCE_DISC       BIT_30	/* Disconnects mandatory */
+#define OF_SSTS             BIT_31	/* Send SCSI status */
+
+
+/*
+ * BUS parameters/settings structure - UNUSED
+ */
+struct bus_param {
+	uint8_t id;		/* Host adapter SCSI id */
+	uint8_t bus_reset_delay;	/* SCSI bus reset delay. */
+	uint8_t failed_reset_count;	/* number of time reset failed */
+	uint8_t unused;
+	uint16_t device_enables;	/* Device enable bits. */
+	uint16_t lun_disables;	/* LUN disable bits. */
+	uint16_t qtag_enables;	/* Tag queue enables. */
+	uint16_t hiwat;		/* High water mark per device. */
+	uint8_t reset_marker:1;
+	uint8_t disable_scsi_reset:1;
+	uint8_t scsi_bus_dead:1;	/* SCSI Bus is Dead, when 5 back to back resets failed */
+};
+
+
+struct qla_driver_setup {
+	uint32_t no_sync:1;
+	uint32_t no_wide:1;
+	uint32_t no_ppr:1;
+	uint32_t no_nvram:1;
+	uint16_t sync_mask;
+	uint16_t wide_mask;
+	uint16_t ppr_mask;
+};
+
+
+/*
+ * Linux Host Adapter structure
+ */
+struct scsi_qla_host {
+	/* Linux adapter configuration data */
+	struct Scsi_Host *host;	/* pointer to host data */
+	struct scsi_qla_host *next;
+	struct device_reg __iomem *iobase;	/* Base Memory-mapped I/O address */
+
+	unsigned char __iomem *mmpbase;	/* memory mapped address */
+	unsigned long host_no;
+	struct pci_dev *pdev;
+	uint8_t devnum;
+	uint8_t revision;
+	uint8_t ports;
+
+	unsigned long actthreads;
+	unsigned long isr_count;	/* Interrupt count */
+	unsigned long spurious_int;
+
+	/* Outstandings ISP commands. */
+	struct srb *outstanding_cmds[MAX_OUTSTANDING_COMMANDS];
+
+	/* BUS configuration data */
+	struct bus_param bus_settings[MAX_BUSES];
+
+	/* Received ISP mailbox data. */
+	volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+
+	dma_addr_t request_dma;		/* Physical Address */
+	request_t *request_ring;	/* Base virtual address */
+	request_t *request_ring_ptr;	/* Current address. */
+	uint16_t req_ring_index;	/* Current index. */
+	uint16_t req_q_cnt;		/* Number of available entries. */
+
+	dma_addr_t response_dma;	/* Physical address. */
+	struct response *response_ring;	/* Base virtual address */
+	struct response *response_ring_ptr;	/* Current address. */
+	uint16_t rsp_ring_index;	/* Current index. */
+
+	struct list_head done_q;	/* Done queue */
+
+	struct completion *mailbox_wait;
+
+	volatile struct {
+		uint32_t online:1;			/* 0 */
+		uint32_t reset_marker:1;		/* 1 */
+		uint32_t disable_host_adapter:1;	/* 2 */
+		uint32_t reset_active:1;		/* 3 */
+		uint32_t abort_isp_active:1;		/* 4 */
+		uint32_t disable_risc_code_load:1;	/* 5 */
+		uint32_t enable_64bit_addressing:1;	/* 6 */
+		uint32_t in_reset:1;			/* 7 */
+		uint32_t ints_enabled:1;
+		uint32_t ignore_nvram:1;
+#ifdef __ia64__
+		uint32_t use_pci_vchannel:1;
+#endif
+	} flags;
+
+	struct nvram nvram;
+	int nvram_valid;
+};
+
+#endif /* _QLA1280_H */
diff --git a/drivers/scsi/qla2xxx/Kconfig b/drivers/scsi/qla2xxx/Kconfig
new file mode 100644
index 0000000..6c73b84
--- /dev/null
+++ b/drivers/scsi/qla2xxx/Kconfig
@@ -0,0 +1,41 @@
+config SCSI_QLA2XXX
+	tristate
+	default (SCSI && PCI)
+	depends on SCSI && PCI
+
+config SCSI_QLA21XX
+	tristate "QLogic ISP2100 host adapter family support"
+	depends on SCSI_QLA2XXX
+        select SCSI_FC_ATTRS
+	---help---
+	This driver supports the QLogic 21xx (ISP2100) host adapter family.
+
+config SCSI_QLA22XX
+	tristate "QLogic ISP2200 host adapter family support"
+	depends on SCSI_QLA2XXX
+        select SCSI_FC_ATTRS
+	---help---
+	This driver supports the QLogic 22xx (ISP2200) host adapter family.
+
+config SCSI_QLA2300
+	tristate "QLogic ISP2300 host adapter family support"
+	depends on SCSI_QLA2XXX
+        select SCSI_FC_ATTRS
+	---help---
+	This driver supports the QLogic 2300 (ISP2300 and ISP2312) host
+	adapter family.
+
+config SCSI_QLA2322
+	tristate "QLogic ISP2322 host adapter family support"
+	depends on SCSI_QLA2XXX
+        select SCSI_FC_ATTRS
+	---help---
+	This driver supports the QLogic 2322 (ISP2322) host adapter family.
+
+config SCSI_QLA6312
+	tristate "QLogic ISP63xx host adapter family support"
+	depends on SCSI_QLA2XXX
+        select SCSI_FC_ATTRS
+	---help---
+	This driver supports the QLogic 63xx (ISP6312 and ISP6322) host
+	adapter family.
diff --git a/drivers/scsi/qla2xxx/Makefile b/drivers/scsi/qla2xxx/Makefile
new file mode 100644
index 0000000..f7a247d
--- /dev/null
+++ b/drivers/scsi/qla2xxx/Makefile
@@ -0,0 +1,16 @@
+EXTRA_CFLAGS += -DUNIQUE_FW_NAME
+
+qla2xxx-y := qla_os.o qla_init.o qla_mbx.o qla_iocb.o qla_isr.o qla_gs.o \
+		qla_dbg.o qla_sup.o qla_rscn.o
+
+qla2100-y := ql2100.o ql2100_fw.o
+qla2200-y := ql2200.o ql2200_fw.o
+qla2300-y := ql2300.o ql2300_fw.o
+qla2322-y := ql2322.o ql2322_fw.o
+qla6312-y := ql6312.o ql6312_fw.o
+
+obj-$(CONFIG_SCSI_QLA21XX) += qla2xxx.o qla2100.o
+obj-$(CONFIG_SCSI_QLA22XX) += qla2xxx.o qla2200.o
+obj-$(CONFIG_SCSI_QLA2300) += qla2xxx.o qla2300.o
+obj-$(CONFIG_SCSI_QLA2322) += qla2xxx.o qla2322.o
+obj-$(CONFIG_SCSI_QLA6312) += qla2xxx.o qla6312.o
diff --git a/drivers/scsi/qla2xxx/ql2100.c b/drivers/scsi/qla2xxx/ql2100.c
new file mode 100644
index 0000000..ea136a6
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2100.c
@@ -0,0 +1,92 @@
+/*
+ * QLogic ISP2100 device driver for Linux 2.6.x
+ * Copyright (C) 2003 Christoph Hellwig.
+ * Copyright (C) 2003-2004 QLogic Corporation (www.qlogic.com)
+ *
+ * Released under GPL v2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "qla_def.h"
+
+static char qla_driver_name[] = "qla2100";
+
+extern unsigned char  fw2100tp_version[];
+extern unsigned char  fw2100tp_version_str[];
+extern unsigned short fw2100tp_addr01;
+extern unsigned short fw2100tp_code01[];
+extern unsigned short fw2100tp_length01;
+
+static struct qla_fw_info qla_fw_tbl[] = {
+	{
+		.addressing	= FW_INFO_ADDR_NORMAL,
+		.fwcode		= &fw2100tp_code01[0],
+		.fwlen		= &fw2100tp_length01,
+		.fwstart	= &fw2100tp_addr01,
+	},
+
+	{ FW_INFO_ADDR_NOMORE, },
+};
+
+static struct qla_board_info qla_board_tbl = {
+	.drv_name	= qla_driver_name,
+
+	.isp_name	= "ISP2100",
+	.fw_info	= qla_fw_tbl,
+};
+
+static struct pci_device_id qla2100_pci_tbl[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP2100,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl,
+	},
+
+	{0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla2100_pci_tbl);
+
+static int __devinit
+qla2100_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return qla2x00_probe_one(pdev,
+	    (struct qla_board_info *)id->driver_data);
+}
+
+static void __devexit
+qla2100_remove_one(struct pci_dev *pdev)
+{
+	qla2x00_remove_one(pdev);
+}
+
+static struct pci_driver qla2100_pci_driver = {
+	.name		= "qla2100",
+	.id_table	= qla2100_pci_tbl,
+	.probe		= qla2100_probe_one,
+	.remove		= __devexit_p(qla2100_remove_one),
+};
+
+static int __init
+qla2100_init(void)
+{
+	return pci_module_init(&qla2100_pci_driver);
+}
+
+static void __exit
+qla2100_exit(void)
+{
+	pci_unregister_driver(&qla2100_pci_driver);
+}
+
+module_init(qla2100_init);
+module_exit(qla2100_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP21xx FC-SCSI Host Bus Adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/ql2100_fw.c b/drivers/scsi/qla2xxx/ql2100_fw.c
new file mode 100644
index 0000000..e72f9f1a
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2100_fw.c
@@ -0,0 +1,4858 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *************************************************************************/
+
+/*
+ *	Firmware Version 1.19.24 (14:02 Jul 16, 2002)
+ */
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2100tp_version = 1*1024+19;
+#else
+unsigned short risc_code_version = 1*1024+19;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned char fw2100tp_version_str[] = {1,19,24};
+#else
+unsigned char firmware_version[] = {1,19,24};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw2100tp_VERSION_STRING "1.19.24"
+#else
+#define FW_VERSION_STRING "1.19.24"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2100tp_addr01 = 0x1000 ;
+#else
+unsigned short risc_code_addr01 = 0x1000 ;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2100tp_code01[] = { 
+#else
+unsigned short risc_code01[] = { 
+#endif
+	0x0078, 0x102d, 0x0000, 0x95f1, 0x0000, 0x0001, 0x0013, 0x0018,
+	0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030,
+	0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1,
+	0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff,
+	0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04,
+	0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c,
+	0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020,
+	0x2039, 0x8fff, 0x20a1, 0xad00, 0x2708, 0x810d, 0x810d, 0x810d,
+	0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8,
+	0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102,
+	0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1,
+	0xa5f1, 0x2009, 0x0000, 0x20a9, 0x070f, 0x41a4, 0x3400, 0x20c9,
+	0xaaff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x25c7,
+	0x2051, 0xa600, 0x2a70, 0x7762, 0xa786, 0x8fff, 0x0040, 0x1092,
+	0x705f, 0xcd00, 0x705b, 0xccf1, 0x7067, 0x0200, 0x706b, 0x0200,
+	0x0078, 0x109a, 0x705b, 0xbd01, 0x7067, 0x0100, 0x706b, 0x0100,
+	0x705f, 0xbd00, 0x1078, 0x12df, 0x1078, 0x13ca, 0x1078, 0x1577,
+	0x1078, 0x1ce9, 0x1078, 0x42ec, 0x1078, 0x76bf, 0x1078, 0x1355,
+	0x1078, 0x2ac0, 0x1078, 0x4e93, 0x1078, 0x49a3, 0x1078, 0x594a,
+	0x1078, 0x2263, 0x1078, 0x5c43, 0x1078, 0x5485, 0x1078, 0x2162,
+	0x1078, 0x2240, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf,
+	0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068,
+	0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70,
+	0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000,
+	0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x365e, 0x1078, 0x2ae8,
+	0x1078, 0x4ee3, 0x1078, 0x4b66, 0x2009, 0x0100, 0x2104, 0xa082,
+	0x0002, 0x0048, 0x10f3, 0x1078, 0x5966, 0x0078, 0x10d6, 0x1079,
+	0x10f7, 0x0078, 0x10dc, 0x1078, 0x7197, 0x0078, 0x10eb, 0x1101,
+	0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078,
+	0x1332, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086,
+	0x0001, 0x00c0, 0x1198, 0x1078, 0x3aec, 0x2079, 0x0100, 0x7844,
+	0xa005, 0x00c0, 0x1198, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x1078,
+	0x1adf, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011,
+	0x8010, 0x73c4, 0x1078, 0x361b, 0x2001, 0xffff, 0x1078, 0x5ae6,
+	0x723c, 0xc284, 0x723e, 0x2001, 0xa60c, 0x2014, 0xc2ac, 0x2202,
+	0x1078, 0x6f9f, 0x2011, 0x0004, 0x1078, 0x8d1b, 0x1078, 0x489e,
+	0x1078, 0x42d4, 0x0040, 0x1144, 0x7087, 0x0001, 0x70bf, 0x0000,
+	0x1078, 0x3c9e, 0x0078, 0x1198, 0x1078, 0x4967, 0x0040, 0x114d,
+	0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x90a6, 0x70cc,
+	0xd09c, 0x00c0, 0x1159, 0x7098, 0xa005, 0x0040, 0x1159, 0x1078,
+	0x42b8, 0x70d7, 0x0000, 0x70d3, 0x0000, 0x72cc, 0x2079, 0xa652,
+	0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ce, 0xa296, 0x0004,
+	0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8d1b, 0x7093, 0x0000,
+	0x7097, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x2677, 0x2011,
+	0x0005, 0x1078, 0x70e0, 0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100,
+	0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x7093, 0x0000,
+	0x7097, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x70e0,
+	0x1078, 0x62d1, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f,
+	0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e,
+	0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078,
+	0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f, 0x027f, 0x017f, 0x1078,
+	0x298e, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706f, 0x0000, 0x7070,
+	0xa084, 0x00ff, 0x7072, 0x709b, 0x0000, 0x007c, 0x127e, 0x2091,
+	0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7094, 0xa086,
+	0xffff, 0x0040, 0x11d1, 0x1078, 0x2677, 0x1078, 0x62d1, 0x0078,
+	0x1244, 0x70cc, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd,
+	0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c,
+	0x0040, 0x11fd, 0x70d0, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078,
+	0x27f7, 0x1078, 0x62d1, 0x70cc, 0xd094, 0x00c0, 0x1244, 0x2011,
+	0x0001, 0x2019, 0x0000, 0x1078, 0x282f, 0x1078, 0x62d1, 0x0078,
+	0x1244, 0x70d4, 0xa005, 0x00c0, 0x1244, 0x7090, 0xa005, 0x00c0,
+	0x1244, 0x1078, 0x4967, 0x00c0, 0x1244, 0x2001, 0xa653, 0x2004,
+	0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009,
+	0x0000, 0x017e, 0x1078, 0x45c4, 0x00c0, 0x121a, 0x6000, 0xd0ec,
+	0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f,
+	0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003,
+	0x0003, 0x7097, 0xffff, 0x2001, 0x0000, 0x1078, 0x24e8, 0x1078,
+	0x3699, 0x2001, 0xa8b2, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c,
+	0x2011, 0x0000, 0x1078, 0x70e0, 0x2011, 0x0000, 0x1078, 0x70ea,
+	0x1078, 0x62d1, 0x1078, 0x639b, 0x127f, 0x007c, 0x017e, 0x0f7e,
+	0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078,
+	0x42a1, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040,
+	0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008,
+	0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5ae6, 0x7900, 0xa18a,
+	0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009,
+	0x00f8, 0x1078, 0x42a1, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9,
+	0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0,
+	0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x24e8, 0x0078,
+	0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0,
+	0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f,
+	0x0000, 0x2009, 0x00f8, 0x1078, 0x42a1, 0x20a9, 0x000e, 0x0005,
+	0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4,
+	0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009,
+	0xa632, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4,
+	0x200b, 0x0000, 0x1078, 0x2588, 0x2001, 0x0001, 0x1078, 0x24e8,
+	0x0078, 0x12d3, 0x2001, 0xa632, 0x2003, 0x0000, 0x7828, 0xc09d,
+	0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f,
+	0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70,
+	0x2061, 0xa8ad, 0x2063, 0x0001, 0x6007, 0x0013, 0x600b, 0x0018,
+	0x600f, 0x0017, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048,
+	0x12f5, 0x7053, 0xffff, 0x0078, 0x12f7, 0x7053, 0x0000, 0x7057,
+	0xffff, 0x706f, 0x0000, 0x7073, 0x0000, 0x1078, 0x90a6, 0x2061,
+	0xa88d, 0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f,
+	0x0200, 0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f,
+	0x07d0, 0x2061, 0xa895, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b,
+	0x0000, 0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b,
+	0x0001, 0x601f, 0x0000, 0x2061, 0xa8a5, 0x6003, 0x514c, 0x6007,
+	0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0xa626, 0x2003,
+	0x0000, 0x007c, 0x2091, 0x8000, 0x0068, 0x1334, 0x007e, 0x017e,
+	0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x133a, 0x017f, 0x792e,
+	0x007f, 0x782a, 0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002,
+	0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa600,
+	0x7803, 0x0005, 0x0078, 0x1352, 0x007c, 0x2071, 0xa600, 0x715c,
+	0x712e, 0x2021, 0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048,
+	0x136b, 0x7060, 0xa302, 0x00c8, 0x136b, 0x220a, 0x2208, 0x2310,
+	0x8420, 0x0078, 0x135d, 0x200b, 0x0000, 0x74aa, 0x74ae, 0x007c,
+	0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa600, 0x70ac, 0xa0ea,
+	0x0010, 0x00c8, 0x137e, 0xa06e, 0x0078, 0x1388, 0x8001, 0x70ae,
+	0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000,
+	0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa600, 0x127e, 0x2091,
+	0x8000, 0x70ac, 0x8001, 0x00c8, 0x1398, 0xa06e, 0x0078, 0x13a1,
+	0x70ae, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807,
+	0x0000, 0x127f, 0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000,
+	0x2071, 0xa600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000,
+	0x70ae, 0x127f, 0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13c0, 0x6804,
+	0x6807, 0x0000, 0x007e, 0x1078, 0x13a4, 0x0d7f, 0x0078, 0x13b4,
+	0x007c, 0x0e7e, 0x2071, 0xa600, 0x70ac, 0xa08a, 0x0010, 0xa00d,
+	0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa8d6, 0x7007, 0x0000, 0x701b,
+	0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004,
+	0x7012, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x0e7e, 0x2270,
+	0x700b, 0x0000, 0x2071, 0xa8d6, 0x7018, 0xa088, 0xa8df, 0x220a,
+	0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x00c0, 0x13f6,
+	0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x127f,
+	0x007c, 0x0e7e, 0x2071, 0xa8d6, 0x7004, 0xa005, 0x00c0, 0x1406,
+	0x0f7e, 0x2079, 0x0010, 0x1078, 0x1408, 0x0f7f, 0x0e7f, 0x007c,
+	0x7000, 0x0079, 0x140b, 0x140f, 0x1479, 0x1496, 0x1496, 0x7018,
+	0x711c, 0xa106, 0x00c0, 0x1417, 0x7007, 0x0000, 0x007c, 0x0d7e,
+	0xa180, 0xa8df, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007,
+	0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c,
+	0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804,
+	0x0d7f, 0xd084, 0x0040, 0x1439, 0x7007, 0x0001, 0x1078, 0x143e,
+	0x007c, 0x7007, 0x0002, 0x1078, 0x1454, 0x007c, 0x017e, 0x027e,
+	0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1449, 0x2110,
+	0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803,
+	0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e, 0x137e, 0x147e,
+	0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c,
+	0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x1468, 0x2110, 0xa006,
+	0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803, 0x0020, 0x3300,
+	0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f, 0x027f, 0x017f,
+	0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa6fa, 0x20a1, 0x0018,
+	0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000,
+	0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002, 0x700b,
+	0xa6f5, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x137e, 0x147e,
+	0x157e, 0x2001, 0xa729, 0x209c, 0x20a1, 0x0014, 0x7803, 0x0026,
+	0x2001, 0xa72a, 0x20ac, 0x53a6, 0x2099, 0xa72b, 0x20a1, 0x0018,
+	0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e, 0x2091, 0x8000,
+	0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c, 0x7002, 0x700b,
+	0xa726, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c, 0x017e, 0x0e7e,
+	0x2071, 0xa8d6, 0x0f7e, 0x2079, 0x0010, 0x7904, 0x7803, 0x0002,
+	0xd1fc, 0x0040, 0x14d0, 0xa18c, 0x0700, 0x7004, 0x1079, 0x14d4,
+	0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x1408, 0x14dc, 0x1509, 0x1531,
+	0x1564, 0x14da, 0x0078, 0x14da, 0xa18c, 0x0700, 0x00c0, 0x1502,
+	0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803,
+	0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x157f, 0x147f,
+	0x137f, 0x700c, 0xa005, 0x0040, 0x151e, 0x1078, 0x143e, 0x007c,
+	0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078,
+	0x1408, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x0078,
+	0x14fd, 0xa18c, 0x0700, 0x00c0, 0x1514, 0x700c, 0xa005, 0x0040,
+	0x151e, 0x1078, 0x1454, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003,
+	0x0200, 0x7007, 0x0000, 0x1078, 0x1408, 0x007c, 0x0d7e, 0x7008,
+	0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838, 0x682e, 0x783c,
+	0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000, 0x1078, 0x1408,
+	0x007c, 0xa18c, 0x0700, 0x00c0, 0x155e, 0x137e, 0x147e, 0x157e,
+	0x2001, 0xa6f8, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099, 0x0014,
+	0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, 0xa6fa, 0x2004,
+	0xd0bc, 0x0040, 0x1554, 0x2001, 0xa703, 0x2004, 0xa080, 0x000d,
+	0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f, 0x137f, 0x7007,
+	0x0000, 0x1078, 0x4f8c, 0x1078, 0x1408, 0x007c, 0x2011, 0x8003,
+	0x1078, 0x361b, 0x0078, 0x1562, 0xa18c, 0x0700, 0x00c0, 0x1571,
+	0x2001, 0xa728, 0x2003, 0x0100, 0x7007, 0x0000, 0x1078, 0x1408,
+	0x007c, 0x2011, 0x8004, 0x1078, 0x361b, 0x0078, 0x1575, 0x127e,
+	0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa8e7, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x700f, 0xa8ed, 0x7013, 0xa8ed, 0x780f, 0x0076,
+	0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184, 0x0007, 0x0079,
+	0x1591, 0x1599, 0x15df, 0x1599, 0x1599, 0x1599, 0x15c4, 0x15a8,
+	0x159d, 0xa085, 0x0001, 0x0078, 0x15f9, 0x684c, 0xd0bc, 0x0040,
+	0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x0078, 0x15e7,
+	0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x1599, 0x684c, 0xd0bc,
+	0x0040, 0x1599, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a,
+	0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004,
+	0x6832, 0x6858, 0x0078, 0x15ef, 0xa18c, 0x00ff, 0xa186, 0x0015,
+	0x00c0, 0x1599, 0x684c, 0xd0ac, 0x0040, 0x1599, 0x6804, 0x681a,
+	0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004,
+	0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078, 0x15ef, 0x684c,
+	0xd0ac, 0x0040, 0x1599, 0xa006, 0x682e, 0x682a, 0x6858, 0xa18c,
+	0x000f, 0xa188, 0x206a, 0x210c, 0x6932, 0x2d08, 0x691a, 0x6826,
+	0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c, 0x6912, 0x6980,
+	0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001, 0x020a,
+	0x2004, 0x82ff, 0x0040, 0x161c, 0xa280, 0x0004, 0x0d7e, 0x206c,
+	0x684c, 0xd0dc, 0x00c0, 0x1618, 0x1078, 0x158c, 0x0040, 0x1618,
+	0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0078, 0x161c,
+	0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e, 0x037e, 0x027e,
+	0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000, 0xa005, 0x00c0,
+	0x1630, 0x7206, 0x2001, 0x1651, 0x007e, 0x2260, 0x0078, 0x17e0,
+	0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182,
+	0xa908, 0x0048, 0x163d, 0x2009, 0xa8ed, 0x710e, 0x7010, 0xa102,
+	0xa082, 0x0009, 0x0040, 0x1648, 0xa080, 0x001b, 0x00c0, 0x164b,
+	0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0, 0x1651, 0x1078,
+	0x17c1, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e, 0x0c7e, 0x007e,
+	0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f, 0x0d7e, 0x0c7e,
+	0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0040, 0x16dd,
+	0x6808, 0xa005, 0x0040, 0x174a, 0x7000, 0xa005, 0x00c0, 0x1672,
+	0x0078, 0x16d2, 0x700c, 0x7110, 0xa106, 0x00c0, 0x1753, 0x7004,
+	0xa406, 0x00c0, 0x16d2, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040,
+	0x168f, 0x047e, 0x1078, 0x1913, 0x047f, 0x2460, 0x6010, 0xa080,
+	0x0002, 0x2004, 0xa005, 0x0040, 0x174a, 0x0078, 0x166c, 0x2001,
+	0x0207, 0x2004, 0xd09c, 0x00c0, 0x167b, 0x7804, 0xa084, 0x6000,
+	0x0040, 0x16a0, 0xa086, 0x6000, 0x0040, 0x16a0, 0x0078, 0x167b,
+	0x7100, 0xa186, 0x0002, 0x00c0, 0x16c0, 0x0e7e, 0x2b68, 0x6818,
+	0x2060, 0x1078, 0x203f, 0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0,
+	0x16b5, 0x7108, 0x720c, 0x0078, 0x16b7, 0x7110, 0x7214, 0x6810,
+	0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f, 0x0078, 0x16c4,
+	0xa186, 0x0001, 0x00c0, 0x16cc, 0x7820, 0x6910, 0xa100, 0x6812,
+	0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000,
+	0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009,
+	0x0048, 0x1078, 0x775c, 0x0078, 0x1753, 0x6808, 0xa005, 0x0040,
+	0x174a, 0x7000, 0xa005, 0x00c0, 0x16e7, 0x0078, 0x174a, 0x700c,
+	0x7110, 0xa106, 0x00c0, 0x16f0, 0x7004, 0xa406, 0x00c0, 0x174a,
+	0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x1704, 0x047e, 0x1078,
+	0x1913, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005,
+	0x0040, 0x174a, 0x0078, 0x16e1, 0x2001, 0x0207, 0x2004, 0xd09c,
+	0x00c0, 0x16f0, 0x2001, 0x0005, 0x2004, 0xd08c, 0x00c0, 0x16f6,
+	0x7804, 0xa084, 0x6000, 0x0040, 0x171b, 0xa086, 0x6000, 0x0040,
+	0x171b, 0x0078, 0x16f0, 0x7007, 0x0000, 0xa016, 0x2218, 0x7000,
+	0xa08e, 0x0001, 0x0040, 0x173c, 0xa08e, 0x0002, 0x00c0, 0x174a,
+	0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x203f, 0x2804, 0xac70,
+	0x6034, 0xd09c, 0x00c0, 0x1738, 0x7308, 0x720c, 0x0078, 0x173a,
+	0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318, 0x7824, 0xa211,
+	0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0, 0x1753, 0x2009,
+	0x0048, 0x1078, 0x775c, 0x0c7f, 0x0d7f, 0x127f, 0x007c, 0x0f7e,
+	0x0e7e, 0x027e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa8e7, 0x7000,
+	0xa086, 0x0000, 0x0040, 0x17ba, 0x7004, 0xac06, 0x00c0, 0x17ab,
+	0x2079, 0x0030, 0x7000, 0xa086, 0x0003, 0x0040, 0x17ab, 0x7804,
+	0xd0fc, 0x00c0, 0x17a7, 0x20e1, 0x6000, 0x2011, 0x0032, 0x2001,
+	0x0208, 0x200c, 0x2001, 0x0209, 0x2004, 0xa106, 0x00c0, 0x176f,
+	0x8211, 0x00c0, 0x1777, 0x7804, 0xd0fc, 0x00c0, 0x17a7, 0x1078,
+	0x1b22, 0x027e, 0x057e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0,
+	0x178d, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007,
+	0x0000, 0x057f, 0x027f, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001,
+	0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0078, 0x17ab, 0x1078,
+	0x1913, 0x0078, 0x175f, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa8ed,
+	0x2104, 0xac06, 0x00c0, 0x17b5, 0x200a, 0xa188, 0x0003, 0x00f0,
+	0x17b0, 0x157f, 0x057f, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f,
+	0x007c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x17c9, 0x7003, 0x0000,
+	0x007c, 0x2104, 0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124,
+	0x8108, 0xa182, 0xa908, 0x0048, 0x17d7, 0x2009, 0xa8ed, 0x7112,
+	0x700c, 0xa106, 0x00c0, 0x17e0, 0x2001, 0x0138, 0x2003, 0x0008,
+	0x8cff, 0x00c0, 0x17e7, 0x1078, 0x1b4d, 0x0078, 0x1854, 0x6010,
+	0x2068, 0x2d58, 0x6828, 0xa406, 0x00c0, 0x17f2, 0x682c, 0xa306,
+	0x0040, 0x182f, 0x601c, 0xa086, 0x0008, 0x0040, 0x182f, 0x6024,
+	0xd0f4, 0x00c0, 0x181c, 0xd0d4, 0x0040, 0x1818, 0x6038, 0xa402,
+	0x6034, 0xa303, 0x0040, 0x1806, 0x00c8, 0x1818, 0x643a, 0x6336,
+	0x6c2a, 0x6b2e, 0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812,
+	0x2300, 0x6b80, 0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x181c,
+	0x1078, 0x9053, 0x0040, 0x17e3, 0x2001, 0xa674, 0x2004, 0xd0b4,
+	0x00c0, 0x182b, 0x6018, 0x2004, 0xd0bc, 0x00c0, 0x182b, 0x6817,
+	0x7fff, 0x6813, 0xffff, 0x1078, 0x208a, 0x00c0, 0x17e3, 0x0c7e,
+	0x7004, 0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4,
+	0x0040, 0x1840, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17e3,
+	0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc,
+	0x000f, 0x2009, 0x0011, 0x1078, 0x1855, 0x0040, 0x1853, 0x2009,
+	0x0001, 0x1078, 0x1855, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18ec,
+	0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1877, 0xd0f4, 0x00c0,
+	0x1887, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1867, 0x18ce,
+	0x188e, 0x188e, 0x18ce, 0x18ce, 0x18c6, 0x18ce, 0x188e, 0x18ce,
+	0x1894, 0x1894, 0x18ce, 0x18ce, 0x18ce, 0x18bd, 0x1894, 0xc0fc,
+	0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040,
+	0x18d1, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0xc0f4,
+	0x6852, 0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18d8, 0x6b08, 0x6a0c,
+	0x6d00, 0x6c04, 0x0078, 0x18d1, 0x7b0c, 0xd3bc, 0x0040, 0x18b5,
+	0x7004, 0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0,
+	0x18b5, 0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14,
+	0x82ff, 0x00c0, 0x18b0, 0x6810, 0xa302, 0x0048, 0x18b0, 0x6b10,
+	0x2011, 0x0000, 0x2468, 0x0078, 0x18b7, 0x6b10, 0x6a14, 0x6d00,
+	0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x18d1, 0x0d7f, 0x0d7e, 0x6834,
+	0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x18ce, 0x0d7f, 0x1078,
+	0x2026, 0x00c0, 0x1855, 0xa00e, 0x0078, 0x18ec, 0x0d7f, 0x1078,
+	0x1332, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902,
+	0x7000, 0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c,
+	0xa201, 0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14,
+	0xa203, 0x6816, 0x1078, 0x2026, 0x007c, 0x1078, 0x1332, 0x1078,
+	0x1c97, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000,
+	0x1078, 0x1af4, 0x1078, 0x8d06, 0x0040, 0x190c, 0x6808, 0x8001,
+	0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f,
+	0xffff, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8a01, 0x0078,
+	0x1adb, 0x1078, 0x1332, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e,
+	0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700,
+	0x00c0, 0x18ef, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x1911,
+	0x7000, 0x0079, 0x192b, 0x1933, 0x1935, 0x1a34, 0x1ab2, 0x1ac9,
+	0x1933, 0x1933, 0x1933, 0x1078, 0x1332, 0x8001, 0x7002, 0xa184,
+	0x0880, 0x00c0, 0x194a, 0x8aff, 0x0040, 0x19d4, 0x2009, 0x0001,
+	0x1078, 0x1855, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078, 0x1855,
+	0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0,
+	0x19b2, 0x027e, 0x037e, 0x017e, 0x7808, 0xd0ec, 0x00c0, 0x1962,
+	0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004,
+	0x0078, 0x1964, 0x1078, 0x1bd7, 0x017f, 0xd194, 0x0040, 0x196b,
+	0x8aff, 0x0040, 0x19a1, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a,
+	0x2500, 0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060,
+	0x6024, 0xd0f4, 0x00c0, 0x197e, 0x633a, 0x6236, 0x0c7f, 0x2400,
+	0x6910, 0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f,
+	0x027f, 0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x203f, 0x2a00,
+	0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852,
+	0x6808, 0x8001, 0x680a, 0x00c0, 0x19a7, 0x684c, 0xd0e4, 0x0040,
+	0x19a7, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x7000,
+	0xa086, 0x0004, 0x0040, 0x1adb, 0x7003, 0x0000, 0x1078, 0x17c1,
+	0x0078, 0x1adb, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x19b9, 0x1078,
+	0xa57e, 0x057f, 0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078,
+	0x4963, 0x0040, 0x19c6, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b,
+	0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912,
+	0x6980, 0x6916, 0x0078, 0x1adb, 0x7004, 0x0c7e, 0x2060, 0x6024,
+	0x0c7f, 0xd0f4, 0x0040, 0x19e1, 0x6808, 0x8001, 0x680a, 0x0078,
+	0x19f5, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19f9,
+	0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19f5, 0x7004,
+	0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078,
+	0x1adb, 0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000,
+	0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, 0x00c8,
+	0x18ef, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104,
+	0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x1078, 0x1b5e,
+	0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc,
+	0x0040, 0x1a1e, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x0076,
+	0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x1078, 0x775c,
+	0x1078, 0x1b92, 0x0040, 0x19f5, 0x8001, 0x7002, 0xd194, 0x0040,
+	0x1a46, 0x7804, 0xd0fc, 0x00c0, 0x191b, 0x8aff, 0x0040, 0x1adb,
+	0x2009, 0x0001, 0x1078, 0x1855, 0x0078, 0x1adb, 0xa184, 0x0880,
+	0x00c0, 0x1a53, 0x8aff, 0x0040, 0x1adb, 0x2009, 0x0001, 0x1078,
+	0x1855, 0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc,
+	0x00c0, 0x1a93, 0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1a66,
+	0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a68, 0x1078, 0x1bd7,
+	0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x0f7e, 0x2d78, 0x2804,
+	0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a83, 0x6808, 0x2008, 0xa31a,
+	0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c, 0x7814, 0xa101,
+	0x7816, 0x0078, 0x1a8f, 0x6810, 0x2008, 0xa31a, 0x6814, 0xa213,
+	0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101, 0x7816, 0x0f7f,
+	0x0d7f, 0x0078, 0x196d, 0x057e, 0x7d0c, 0x1078, 0xa57e, 0x057f,
+	0x1078, 0x1af4, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4963, 0x0040,
+	0x1aa4, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff, 0x682f,
+	0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916,
+	0x0078, 0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d,
+	0x0040, 0x1ac5, 0x6808, 0x8001, 0x680a, 0x00c0, 0x1ac5, 0x7004,
+	0x2060, 0x2009, 0x0048, 0x1078, 0x775c, 0x1078, 0x17c1, 0x0078,
+	0x1adb, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6010,
+	0xa005, 0x0040, 0x1ac5, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28,
+	0x6b2c, 0x1078, 0x17e0, 0x017f, 0x007f, 0x127f, 0x007c, 0x127e,
+	0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0, 0x1af2, 0x700c,
+	0x7110, 0xa106, 0x0040, 0x1af2, 0x20e1, 0x9028, 0x700f, 0xa8ed,
+	0x7013, 0xa8ed, 0x127f, 0x007c, 0x0c7e, 0x1078, 0x1b22, 0x20e1,
+	0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1b19, 0x2104, 0xa005,
+	0x0040, 0x1b08, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, 0x600a,
+	0xa188, 0x0003, 0xa182, 0xa908, 0x0048, 0x1b10, 0x2009, 0xa8ed,
+	0x7112, 0x700c, 0xa106, 0x00c0, 0x1af9, 0x2011, 0x0008, 0x0078,
+	0x1af9, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, 0x0138, 0x2202,
+	0x0c7f, 0x007c, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2021,
+	0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x00c0, 0x1b3f, 0x2001,
+	0x0109, 0x201c, 0xa39c, 0x0048, 0x00c0, 0x1b3f, 0x2001, 0x0111,
+	0x201c, 0x83ff, 0x00c0, 0x1b3f, 0x8421, 0x00c0, 0x1b29, 0x007c,
+	0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005, 0x00c0, 0x1b4c,
+	0x8109, 0x00c0, 0x1b44, 0x007c, 0x007c, 0x1078, 0x1b40, 0x0040,
+	0x1b55, 0x780c, 0xd0a4, 0x0040, 0x1b5b, 0x1078, 0x1af4, 0xa085,
+	0x0001, 0x0078, 0x1b5d, 0x1078, 0x1b92, 0x007c, 0x0e7e, 0x2071,
+	0x0200, 0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1b22, 0x2019,
+	0x5000, 0x8319, 0x0040, 0x1b7c, 0x2001, 0xa908, 0x2004, 0xa086,
+	0x0000, 0x0040, 0x1b7c, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b69,
+	0x1078, 0x1eaa, 0x0078, 0x1b67, 0x20e1, 0x7000, 0x7324, 0x7420,
+	0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f,
+	0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202,
+	0x0e7f, 0x007c, 0x027e, 0x2001, 0x015d, 0x2001, 0x0000, 0x7908,
+	0xa18c, 0x0fff, 0xa182, 0x0ffd, 0x0048, 0x1ba0, 0x2009, 0x0000,
+	0xa190, 0x0007, 0xa294, 0x1ff8, 0x8214, 0x8214, 0x8214, 0x2001,
+	0x020a, 0x82ff, 0x0040, 0x1bb5, 0x20e1, 0x6000, 0x200c, 0x200c,
+	0x200c, 0x200c, 0x8211, 0x00c0, 0x1bae, 0x20e1, 0x7000, 0x200c,
+	0x200c, 0x7003, 0x0000, 0x20e1, 0x6000, 0x2001, 0x0208, 0x200c,
+	0x2001, 0x0209, 0x2004, 0xa106, 0x0040, 0x1bd4, 0x1078, 0x1b40,
+	0x0040, 0x1bd2, 0x7908, 0xd1ec, 0x00c0, 0x1bd4, 0x790c, 0xd1a4,
+	0x0040, 0x1b97, 0x1078, 0x1af4, 0xa006, 0x027f, 0x007c, 0x7c20,
+	0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c69,
+	0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c69, 0x0d7e,
+	0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c67, 0x681c, 0xa086,
+	0x0008, 0x0040, 0x1c67, 0x6824, 0xd0d4, 0x00c0, 0x1c67, 0x6810,
+	0x2068, 0x6850, 0xd0fc, 0x0040, 0x1c29, 0x8108, 0x2104, 0x6b2c,
+	0xa306, 0x00c0, 0x1c67, 0x8108, 0x2104, 0x6a28, 0xa206, 0x00c0,
+	0x1c67, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822, 0x6870,
+	0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060, 0x6034,
+	0xd09c, 0x0040, 0x1c24, 0x6830, 0x2004, 0xac68, 0x6808, 0x783a,
+	0x680c, 0x783e, 0x0078, 0x1c65, 0xa006, 0x783a, 0x783e, 0x0078,
+	0x1c65, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6b2c, 0xa306,
+	0x00c0, 0x1c67, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c67, 0x6a28,
+	0xa206, 0x00c0, 0x1c67, 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2004,
+	0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c, 0x00c0, 0x1c57,
+	0x6008, 0x7822, 0x686e, 0x600c, 0x7826, 0x6872, 0x6000, 0x7832,
+	0x6004, 0x7836, 0xa006, 0x783a, 0x783e, 0x0078, 0x1c65, 0x6010,
+	0x7822, 0x686e, 0x6014, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004,
+	0x7836, 0x6008, 0x783a, 0x600c, 0x783e, 0x7803, 0x0011, 0x0c7f,
+	0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e, 0x027e, 0x2071, 0xa8e7,
+	0x2079, 0x0030, 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x0040,
+	0x1c92, 0x8211, 0x0040, 0x1c90, 0x2001, 0x0005, 0x2004, 0xd08c,
+	0x0040, 0x1c79, 0x7904, 0xa18c, 0x0780, 0x017e, 0x1078, 0x1913,
+	0x017f, 0x81ff, 0x00c0, 0x1c90, 0x2011, 0x0050, 0x0078, 0x1c74,
+	0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f, 0x0f7f, 0x007c, 0x7803,
+	0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac, 0x0040, 0x1ce8, 0x8109,
+	0x00c0, 0x1c9b, 0x2009, 0x0100, 0x210c, 0xa18a, 0x0003, 0x1048,
+	0x1332, 0x1078, 0x1fca, 0x0e7e, 0x0f7e, 0x2071, 0xa8d6, 0x2079,
+	0x0010, 0x7004, 0xa086, 0x0000, 0x0040, 0x1ce0, 0x7800, 0x007e,
+	0x7820, 0x007e, 0x7830, 0x007e, 0x7834, 0x007e, 0x7838, 0x007e,
+	0x783c, 0x007e, 0x7803, 0x0004, 0x7823, 0x0000, 0x0005, 0x0005,
+	0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x2079, 0x0010,
+	0x007f, 0x783e, 0x007f, 0x783a, 0x007f, 0x7836, 0x007f, 0x7832,
+	0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f, 0x0e7f, 0x0078, 0x1ce6,
+	0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0, 0x1332, 0x1078, 0x639b,
+	0x007c, 0x0e7e, 0x2071, 0xa908, 0x7003, 0x0000, 0x0e7f, 0x007c,
+	0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x00c0, 0x1d6b,
+	0x6934, 0xa184, 0x0007, 0x0079, 0x1cfd, 0x1d05, 0x1d56, 0x1d05,
+	0x1d05, 0x1d05, 0x1d3b, 0x1d18, 0x1d07, 0x1078, 0x1332, 0x684c,
+	0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a,
+	0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0078, 0x1d5e,
+	0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1d05, 0x684c,
+	0xd0b4, 0x0040, 0x1e79, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a,
+	0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080,
+	0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832,
+	0x6958, 0x0078, 0x1d67, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x00c0,
+	0x1d6b, 0x684c, 0xd0b4, 0x0040, 0x1e79, 0x6804, 0x681a, 0xa080,
+	0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832,
+	0x6958, 0xa006, 0x682e, 0x682a, 0x0078, 0x1d67, 0x684c, 0xd0b4,
+	0x0040, 0x18ed, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00, 0x681a,
+	0x6834, 0xa084, 0x000f, 0xa080, 0x206a, 0x2004, 0x6832, 0x6926,
+	0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c, 0x0f7e, 0x2079, 0x0020,
+	0x7804, 0xd0fc, 0x10c0, 0x1eaa, 0x0e7e, 0x0d7e, 0x2071, 0xa908,
+	0x7000, 0xa005, 0x00c0, 0x1df0, 0x0c7e, 0x7206, 0xa280, 0x0004,
+	0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x0d7e, 0x2068,
+	0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1, 0x9040, 0x2079, 0x0200,
+	0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x0f7f, 0x0d7f, 0x2b68,
+	0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc,
+	0x000f, 0x6908, 0x2001, 0x04fd, 0x2004, 0xa086, 0x0007, 0x0040,
+	0x1db2, 0xa184, 0x0007, 0x0040, 0x1db2, 0x017e, 0x2009, 0x0008,
+	0xa102, 0x017f, 0xa108, 0x791a, 0x7116, 0x701e, 0x680c, 0xa081,
+	0x0000, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c,
+	0x6814, 0xa106, 0x00c0, 0x1dc9, 0x6928, 0x6810, 0xa106, 0x0040,
+	0x1dd6, 0x037e, 0x047e, 0x6b14, 0x6c10, 0x1078, 0x208a, 0x047f,
+	0x037f, 0x0040, 0x1dd6, 0x0c7f, 0x0078, 0x1df0, 0x8aff, 0x00c0,
+	0x1dde, 0x0c7f, 0xa085, 0x0001, 0x0078, 0x1df0, 0x127e, 0x2091,
+	0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0040,
+	0x1ded, 0x2009, 0x0001, 0x1078, 0x1df4, 0x127f, 0x0c7f, 0xa006,
+	0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e, 0x067e, 0x057e, 0x047e,
+	0x037e, 0x027e, 0x8aff, 0x0040, 0x1e72, 0x700c, 0x7214, 0xa23a,
+	0x7010, 0x7218, 0xa203, 0x0048, 0x1e71, 0xa705, 0x0040, 0x1e71,
+	0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1e24, 0x0d7e, 0x2804,
+	0xac68, 0x2900, 0x0079, 0x1e14, 0x1e53, 0x1e34, 0x1e34, 0x1e53,
+	0x1e53, 0x1e4b, 0x1e53, 0x1e34, 0x1e53, 0x1e3a, 0x1e3a, 0x1e53,
+	0x1e53, 0x1e53, 0x1e42, 0x1e3a, 0xc0fc, 0x6852, 0x6b6c, 0x6a70,
+	0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e57, 0x0d7e, 0x2804, 0xac68,
+	0x6f08, 0x6e0c, 0x0078, 0x1e56, 0x6b08, 0x6a0c, 0x6d00, 0x6c04,
+	0x0078, 0x1e56, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c,
+	0x0078, 0x1e56, 0x0d7f, 0x0d7e, 0x6834, 0xa084, 0x00ff, 0xa086,
+	0x001e, 0x00c0, 0x1e53, 0x0d7f, 0x1078, 0x2026, 0x00c0, 0x1dfa,
+	0xa00e, 0x0078, 0x1e72, 0x0d7f, 0x1078, 0x1332, 0x0d7f, 0x7b22,
+	0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000,
+	0x7002, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c,
+	0xa300, 0x700e, 0x7010, 0xa201, 0x7012, 0x1078, 0x2026, 0x0078,
+	0x1e72, 0xa006, 0x027f, 0x037f, 0x047f, 0x057f, 0x067f, 0x077f,
+	0x007c, 0x1078, 0x1332, 0x027e, 0x2001, 0x0105, 0x2003, 0x0010,
+	0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060,
+	0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x1e92, 0x6850,
+	0xc0bd, 0x6852, 0x0d7f, 0x0c7e, 0x1078, 0x8a01, 0x0c7f, 0x2001,
+	0xa8c0, 0x2004, 0xac06, 0x00c0, 0x1ea7, 0x20e1, 0x9040, 0x1078,
+	0x738a, 0x2011, 0x0000, 0x1078, 0x70ea, 0x1078, 0x639b, 0x027f,
+	0x0078, 0x1f76, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x0f7e,
+	0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020, 0x2071, 0xa908, 0x2b68,
+	0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0,
+	0x1e7b, 0x7000, 0x0079, 0x1ec4, 0x1f76, 0x1ec8, 0x1f43, 0x1f74,
+	0x8001, 0x7002, 0xd19c, 0x00c0, 0x1edc, 0x8aff, 0x0040, 0x1efb,
+	0x2009, 0x0001, 0x1078, 0x1df4, 0x0040, 0x1f76, 0x2009, 0x0001,
+	0x1078, 0x1df4, 0x0078, 0x1f76, 0x7803, 0x0004, 0xd194, 0x0040,
+	0x1eec, 0x6850, 0xc0fc, 0x6852, 0x8aff, 0x00c0, 0x1ef1, 0x684c,
+	0xc0f5, 0x684e, 0x0078, 0x1ef1, 0x1078, 0x203f, 0x6850, 0xc0fd,
+	0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x7003,
+	0x0000, 0x0078, 0x1f76, 0x711c, 0x81ff, 0x0040, 0x1f11, 0x7918,
+	0x7922, 0x7827, 0x0000, 0x7803, 0x0001, 0x7000, 0x8000, 0x7002,
+	0x700c, 0xa100, 0x700e, 0x7010, 0xa081, 0x0000, 0x7012, 0x0078,
+	0x1f76, 0x0f7e, 0x027e, 0x781c, 0x007e, 0x7818, 0x007e, 0x2079,
+	0x0100, 0x7a14, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x037e,
+	0x2019, 0x1000, 0x8319, 0x1040, 0x1332, 0x7820, 0xd0bc, 0x00c0,
+	0x1f22, 0x037f, 0x79c8, 0x007f, 0xa102, 0x017f, 0x007e, 0x017e,
+	0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f, 0x78ca, 0xa284, 0x0004,
+	0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f, 0x7803, 0x0008, 0x7003,
+	0x0000, 0x0078, 0x1f76, 0x8001, 0x7002, 0xd194, 0x0040, 0x1f58,
+	0x7804, 0xd0fc, 0x00c0, 0x1eba, 0xd19c, 0x00c0, 0x1f72, 0x8aff,
+	0x0040, 0x1f76, 0x2009, 0x0001, 0x1078, 0x1df4, 0x0078, 0x1f76,
+	0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078, 0x203f, 0x0d7e, 0x2804,
+	0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f6b, 0x6808, 0xa31a, 0x680c,
+	0xa213, 0x0078, 0x1f6f, 0x6810, 0xa31a, 0x6814, 0xa213, 0x0d7f,
+	0x0078, 0x1eec, 0x0078, 0x1eec, 0x1078, 0x1332, 0x0c7f, 0x0d7f,
+	0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f, 0x007c, 0x0f7e, 0x0e7e,
+	0x2071, 0xa908, 0x7000, 0xa086, 0x0000, 0x0040, 0x1fc7, 0x2079,
+	0x0020, 0x017e, 0x2009, 0x0207, 0x210c, 0xd194, 0x0040, 0x1fa4,
+	0x2009, 0x020c, 0x210c, 0xa184, 0x0003, 0x0040, 0x1fa4, 0x1078,
+	0xa5d2, 0x2001, 0x0133, 0x2004, 0xa005, 0x1040, 0x1332, 0x20e1,
+	0x9040, 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104, 0x2009,
+	0x0203, 0x210c, 0xa106, 0x00c0, 0x1faf, 0x20e1, 0x9040, 0x7804,
+	0xd0fc, 0x0040, 0x1f8a, 0x1078, 0x1eaa, 0x7000, 0xa086, 0x0000,
+	0x00c0, 0x1f8a, 0x017f, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x00c0,
+	0x1fbd, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x0e7f,
+	0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071,
+	0xa908, 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0040, 0x2003,
+	0x7004, 0x2060, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x1fed,
+	0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c, 0xa206, 0x00c0, 0x1fed,
+	0x6808, 0x7a18, 0xa206, 0x0040, 0x2009, 0x2001, 0x0105, 0x2003,
+	0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004,
+	0x2060, 0x1078, 0x8a01, 0x20e1, 0x9040, 0x1078, 0x738a, 0x2011,
+	0x0000, 0x1078, 0x70ea, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x027f,
+	0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0, 0x1fed, 0x684c, 0xc0dc,
+	0x684e, 0x2c10, 0x1078, 0x1cf0, 0x2001, 0x0105, 0x2003, 0x0010,
+	0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000, 0x2069, 0xa8b1,
+	0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x2003, 0x8840, 0x2804,
+	0xa005, 0x00c0, 0x203a, 0x6004, 0xa005, 0x0040, 0x203c, 0x681a,
+	0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x206a, 0x2044, 0x88ff,
+	0x1040, 0x1332, 0x8a51, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50,
+	0x8841, 0x2804, 0xa005, 0x00c0, 0x2059, 0x2c00, 0xad06, 0x0040,
+	0x204e, 0x6000, 0xa005, 0x00c0, 0x204e, 0x2d00, 0x2060, 0x681a,
+	0x6034, 0xa084, 0x000f, 0xa080, 0x207a, 0x2044, 0x88ff, 0x1040,
+	0x1332, 0x007c, 0x0000, 0x0011, 0x0015, 0x0019, 0x001d, 0x0021,
+	0x0025, 0x0029, 0x0000, 0x000f, 0x0015, 0x001b, 0x0021, 0x0027,
+	0x0000, 0x0000, 0x0000, 0x205f, 0x205b, 0x0000, 0x0000, 0x2069,
+	0x0000, 0x205f, 0x0000, 0x2066, 0x2063, 0x0000, 0x0000, 0x0000,
+	0x2069, 0x2066, 0x0000, 0x2061, 0x2061, 0x0000, 0x0000, 0x2069,
+	0x0000, 0x2061, 0x0000, 0x2067, 0x2067, 0x0000, 0x0000, 0x0000,
+	0x2069, 0x2067, 0x0a7e, 0x097e, 0x087e, 0x6b2e, 0x6c2a, 0x6858,
+	0xa055, 0x0040, 0x212d, 0x2d60, 0x6034, 0xa0cc, 0x000f, 0xa9c0,
+	0x206a, 0xa986, 0x0007, 0x0040, 0x20a5, 0xa986, 0x000e, 0x0040,
+	0x20a5, 0xa986, 0x000f, 0x00c0, 0x20a9, 0x605c, 0xa422, 0x6060,
+	0xa31a, 0x2804, 0xa045, 0x00c0, 0x20b7, 0x0050, 0x20b1, 0x0078,
+	0x212d, 0x6004, 0xa065, 0x0040, 0x212d, 0x0078, 0x2094, 0x2804,
+	0xa005, 0x0040, 0x20d5, 0xac68, 0xd99c, 0x00c0, 0x20c5, 0x6808,
+	0xa422, 0x680c, 0xa31b, 0x0078, 0x20c9, 0x6810, 0xa422, 0x6814,
+	0xa31b, 0x0048, 0x20f4, 0x2300, 0xa405, 0x0040, 0x20db, 0x8a51,
+	0x0040, 0x212d, 0x8840, 0x0078, 0x20b7, 0x6004, 0xa065, 0x0040,
+	0x212d, 0x0078, 0x2094, 0x8a51, 0x0040, 0x212d, 0x8840, 0x2804,
+	0xa005, 0x00c0, 0x20ee, 0x6004, 0xa065, 0x0040, 0x212d, 0x6034,
+	0xa0cc, 0x000f, 0xa9c0, 0x206a, 0x2804, 0x2040, 0x2b68, 0x6850,
+	0xc0fc, 0x6852, 0x0078, 0x2121, 0x8422, 0x8420, 0x831a, 0xa399,
+	0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72, 0x0d7f, 0xd99c, 0x00c0,
+	0x210f, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300, 0xa11b, 0x1048,
+	0x1332, 0x6800, 0xa420, 0x6804, 0xa319, 0x0078, 0x211b, 0x6910,
+	0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x1048, 0x1332, 0x6800,
+	0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22, 0x6850, 0xc0fd,
+	0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00, 0x6826, 0x007f,
+	0x007f, 0x007f, 0xa006, 0x0078, 0x2132, 0x087f, 0x097f, 0x0a7f,
+	0xa085, 0x0001, 0x007c, 0x2001, 0x0005, 0x2004, 0xa084, 0x0007,
+	0x0079, 0x213a, 0x2142, 0x2143, 0x2146, 0x2149, 0x214e, 0x2151,
+	0x2156, 0x215b, 0x007c, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x1913,
+	0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x007c, 0x1078, 0x14be,
+	0x007c, 0x1078, 0x1eaa, 0x1078, 0x14be, 0x007c, 0x1078, 0x1913,
+	0x1078, 0x14be, 0x007c, 0x1078, 0x1913, 0x1078, 0x1eaa, 0x1078,
+	0x14be, 0x007c, 0x127e, 0x2091, 0x2300, 0x2079, 0x0200, 0x2071,
+	0xab80, 0x2069, 0xa600, 0x2009, 0x0004, 0x7912, 0x7817, 0x0004,
+	0x1078, 0x251f, 0x781b, 0x0002, 0x20e1, 0x8700, 0x127f, 0x007c,
+	0x127e, 0x2091, 0x2300, 0x781c, 0xa084, 0x0007, 0x0079, 0x2180,
+	0x21a4, 0x2188, 0x218c, 0x2190, 0x2196, 0x219a, 0x219e, 0x21a2,
+	0x1078, 0x548e, 0x0078, 0x21a4, 0x1078, 0x54da, 0x0078, 0x21a4,
+	0x1078, 0x548e, 0x1078, 0x54da, 0x0078, 0x21a4, 0x1078, 0x21a6,
+	0x0078, 0x21a4, 0x1078, 0x21a6, 0x0078, 0x21a4, 0x1078, 0x21a6,
+	0x0078, 0x21a4, 0x1078, 0x21a6, 0x127f, 0x007c, 0x007e, 0x017e,
+	0x027e, 0x1078, 0xa5d2, 0x7930, 0xa184, 0x0003, 0x0040, 0x21c9,
+	0x2001, 0xa8c0, 0x2004, 0xa005, 0x0040, 0x21c5, 0x2001, 0x0133,
+	0x2004, 0xa005, 0x1040, 0x1332, 0x0c7e, 0x2001, 0xa8c0, 0x2064,
+	0x1078, 0x8a01, 0x0c7f, 0x0078, 0x21f2, 0x20e1, 0x9040, 0x0078,
+	0x21f2, 0xa184, 0x0030, 0x0040, 0x21da, 0x6a00, 0xa286, 0x0003,
+	0x00c0, 0x21d4, 0x0078, 0x21d6, 0x1078, 0x4224, 0x20e1, 0x9010,
+	0x0078, 0x21f2, 0xa184, 0x00c0, 0x0040, 0x21ec, 0x0e7e, 0x037e,
+	0x047e, 0x057e, 0x2071, 0xa8e7, 0x1078, 0x1af4, 0x057f, 0x047f,
+	0x037f, 0x0e7f, 0x0078, 0x21f2, 0xa184, 0x0300, 0x0040, 0x21f2,
+	0x20e1, 0x9020, 0x7932, 0x027f, 0x017f, 0x007f, 0x007c, 0x017e,
+	0x0e7e, 0x0f7e, 0x2071, 0xa600, 0x7128, 0x2001, 0xa890, 0x2102,
+	0x2001, 0xa898, 0x2102, 0xa182, 0x0211, 0x00c8, 0x220b, 0x2009,
+	0x0008, 0x0078, 0x2235, 0xa182, 0x0259, 0x00c8, 0x2213, 0x2009,
+	0x0007, 0x0078, 0x2235, 0xa182, 0x02c1, 0x00c8, 0x221b, 0x2009,
+	0x0006, 0x0078, 0x2235, 0xa182, 0x0349, 0x00c8, 0x2223, 0x2009,
+	0x0005, 0x0078, 0x2235, 0xa182, 0x0421, 0x00c8, 0x222b, 0x2009,
+	0x0004, 0x0078, 0x2235, 0xa182, 0x0581, 0x00c8, 0x2233, 0x2009,
+	0x0003, 0x0078, 0x2235, 0x2009, 0x0002, 0x2079, 0x0200, 0x7912,
+	0x7817, 0x0004, 0x1078, 0x251f, 0x0f7f, 0x0e7f, 0x017f, 0x007c,
+	0x127e, 0x2091, 0x2200, 0x2061, 0x0100, 0x2071, 0xa600, 0x6024,
+	0x6026, 0x6053, 0x0030, 0x6033, 0x00ef, 0x60e7, 0x0000, 0x60eb,
+	0x00ef, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f,
+	0x0080, 0x602f, 0x0000, 0x6007, 0x0eaf, 0x600f, 0x00ff, 0x602b,
+	0x002f, 0x127f, 0x007c, 0x2001, 0xa630, 0x2003, 0x0000, 0x2001,
+	0xa62f, 0x2003, 0x0001, 0x007c, 0x127e, 0x2091, 0x2200, 0x007e,
+	0x017e, 0x027e, 0x6124, 0xa184, 0x002c, 0x00c0, 0x227b, 0xa184,
+	0x0007, 0x0079, 0x2281, 0xa195, 0x0004, 0xa284, 0x0007, 0x0079,
+	0x2281, 0x22ad, 0x2289, 0x228d, 0x2291, 0x2297, 0x229b, 0x22a1,
+	0x22a7, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078, 0x5d45, 0x0078,
+	0x22ad, 0x1078, 0x5d45, 0x1078, 0x5c56, 0x0078, 0x22ad, 0x1078,
+	0x22b2, 0x0078, 0x22ad, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x0078,
+	0x22ad, 0x1078, 0x5d45, 0x1078, 0x22b2, 0x0078, 0x22ad, 0x1078,
+	0x5d45, 0x1078, 0x5c56, 0x1078, 0x22b2, 0x027f, 0x017f, 0x007f,
+	0x127f, 0x007c, 0x6124, 0xd1ac, 0x0040, 0x23ac, 0x017e, 0x047e,
+	0x0c7e, 0x644c, 0xa486, 0xf0f0, 0x00c0, 0x22c5, 0x2061, 0x0100,
+	0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74c6, 0xa48c, 0xff00,
+	0x7034, 0xd084, 0x0040, 0x22dd, 0xa186, 0xf800, 0x00c0, 0x22dd,
+	0x703c, 0xd084, 0x00c0, 0x22dd, 0xc085, 0x703e, 0x037e, 0x2418,
+	0x2011, 0x8016, 0x1078, 0x361b, 0x037f, 0xa196, 0xff00, 0x0040,
+	0x231f, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa116, 0x0040, 0x231f,
+	0x7130, 0xd184, 0x00c0, 0x231f, 0x2011, 0xa653, 0x2214, 0xd2ec,
+	0x0040, 0x22fa, 0xc18d, 0x7132, 0x2011, 0xa653, 0x2214, 0xd2ac,
+	0x00c0, 0x231f, 0x6240, 0xa294, 0x0010, 0x0040, 0x2306, 0x6248,
+	0xa294, 0xff00, 0xa296, 0xff00, 0x0040, 0x231f, 0x7030, 0xd08c,
+	0x0040, 0x2371, 0x7034, 0xd08c, 0x00c0, 0x2316, 0x2001, 0xa60c,
+	0x200c, 0xd1ac, 0x00c0, 0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4,
+	0x2011, 0x8013, 0x1078, 0x361b, 0x037f, 0x0078, 0x2371, 0x7034,
+	0xd08c, 0x00c0, 0x232b, 0x2001, 0xa60c, 0x200c, 0xd1ac, 0x00c0,
+	0x2371, 0xc1ad, 0x2102, 0x037e, 0x73c4, 0x2011, 0x8013, 0x1078,
+	0x361b, 0x037f, 0x7130, 0xc185, 0x7132, 0x2011, 0xa653, 0x220c,
+	0xd1a4, 0x0040, 0x2355, 0x017e, 0x2009, 0x0001, 0x2011, 0x0100,
+	0x1078, 0x5bf1, 0x2019, 0x000e, 0x1078, 0xa195, 0xa484, 0x00ff,
+	0xa080, 0x29c0, 0x200c, 0xa18c, 0xff00, 0x810f, 0x8127, 0xa006,
+	0x2009, 0x000e, 0x1078, 0xa21d, 0x017f, 0xd1ac, 0x00c0, 0x2362,
+	0x017e, 0x2009, 0x0000, 0x2019, 0x0004, 0x1078, 0x284f, 0x017f,
+	0x0078, 0x2371, 0x157e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x1078,
+	0x45c4, 0x00c0, 0x236d, 0x1078, 0x42f8, 0x8108, 0x00f0, 0x2367,
+	0x157f, 0x0c7f, 0x047f, 0x0f7e, 0x2079, 0xa8c4, 0x783c, 0xa086,
+	0x0000, 0x0040, 0x2383, 0x6027, 0x0004, 0x783f, 0x0000, 0x2079,
+	0x0140, 0x7803, 0x0000, 0x0f7f, 0x2011, 0x0003, 0x1078, 0x70e0,
+	0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, 0x2019,
+	0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001,
+	0xa600, 0x2014, 0xa296, 0x0004, 0x00c0, 0x23a4, 0xd19c, 0x00c0,
+	0x23ac, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa622,
+	0x2003, 0x0000, 0x6027, 0x0020, 0xd194, 0x0040, 0x2490, 0x0f7e,
+	0x2079, 0xa8c4, 0x783c, 0xa086, 0x0001, 0x00c0, 0x23d0, 0x017e,
+	0x6027, 0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000,
+	0x7803, 0x0000, 0x2079, 0xa8b1, 0x7807, 0x0000, 0x7833, 0x0000,
+	0x1078, 0x62d1, 0x1078, 0x639b, 0x017f, 0x0f7f, 0x0078, 0x2490,
+	0x0f7f, 0x017e, 0x3900, 0xa082, 0xa9e3, 0x00c8, 0x23db, 0x017e,
+	0x1078, 0x747a, 0x017f, 0x6220, 0xd2b4, 0x0040, 0x2446, 0x1078,
+	0x5acb, 0x1078, 0x6e0f, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa8ba,
+	0x2304, 0xa07d, 0x0040, 0x241c, 0x7804, 0xa086, 0x0032, 0x00c0,
+	0x241c, 0x0d7e, 0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288,
+	0x7818, 0x608e, 0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003,
+	0x8001, 0x00c0, 0x2400, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x618e, 0x628a, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x7810,
+	0x2070, 0x7037, 0x0103, 0x2f60, 0x1078, 0x772d, 0x0e7f, 0x0c7f,
+	0x0d7f, 0x0f7f, 0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140,
+	0x6804, 0xa084, 0x4000, 0x0040, 0x2429, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa8b1, 0x6028, 0xa09a, 0x00c8,
+	0x00c8, 0x2439, 0x8000, 0x602a, 0x0c7f, 0x1078, 0x6e01, 0x0078,
+	0x248f, 0x2019, 0xa8ba, 0x2304, 0xa065, 0x0040, 0x2443, 0x2009,
+	0x0027, 0x1078, 0x775c, 0x0c7f, 0x0078, 0x248f, 0xd2bc, 0x0040,
+	0x248f, 0x1078, 0x5ad8, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e,
+	0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x245b, 0x6803,
+	0x1000, 0x6803, 0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa8b1, 0x6044,
+	0xa09a, 0x00c8, 0x00c8, 0x247e, 0x8000, 0x6046, 0x603c, 0x0c7f,
+	0xa005, 0x0040, 0x248f, 0x2009, 0x07d0, 0x1078, 0x5ad0, 0xa080,
+	0x0007, 0x2004, 0xa086, 0x0006, 0x00c0, 0x247a, 0x6017, 0x0012,
+	0x0078, 0x248f, 0x6017, 0x0016, 0x0078, 0x248f, 0x037e, 0x2019,
+	0x0001, 0x1078, 0x7058, 0x037f, 0x2019, 0xa8c0, 0x2304, 0xa065,
+	0x0040, 0x248e, 0x2009, 0x004f, 0x1078, 0x775c, 0x0c7f, 0x017f,
+	0xd19c, 0x0040, 0x24e4, 0x7034, 0xd0ac, 0x00c0, 0x24c1, 0x017e,
+	0x157e, 0x6027, 0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0,
+	0x249f, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9,
+	0x0320, 0x00e0, 0x24a9, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0,
+	0x24b8, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x24e4,
+	0x1078, 0x2577, 0x00f0, 0x24a9, 0x157f, 0x6152, 0x017f, 0x6027,
+	0x0008, 0x017e, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078,
+	0x70e0, 0x2011, 0x0002, 0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e,
+	0x2019, 0x0000, 0x1078, 0x7058, 0x037f, 0x60e3, 0x0000, 0x1078,
+	0xa5ad, 0x1078, 0xa5cb, 0x2001, 0xa600, 0x2003, 0x0004, 0x6027,
+	0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c,
+	0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000,
+	0x2071, 0xa600, 0x71bc, 0x70be, 0xa116, 0x0040, 0x2518, 0x81ff,
+	0x0040, 0x2500, 0x2011, 0x8011, 0x1078, 0x361b, 0x0078, 0x2518,
+	0x2011, 0x8012, 0x1078, 0x361b, 0x2001, 0xa672, 0x2004, 0xd0fc,
+	0x00c0, 0x2518, 0x037e, 0x0c7e, 0x1078, 0x6f9f, 0x2061, 0x0100,
+	0x2019, 0x0028, 0x2009, 0x0000, 0x1078, 0x284f, 0x0c7f, 0x037f,
+	0x127f, 0x0f7f, 0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e,
+	0x0f7e, 0x007e, 0x027e, 0x2061, 0x0100, 0xa190, 0x253b, 0x2204,
+	0x60f2, 0x2011, 0x2548, 0x6000, 0xa082, 0x0003, 0x00c8, 0x2534,
+	0x2001, 0x00ff, 0x0078, 0x2535, 0x2204, 0x60ee, 0x027f, 0x007f,
+	0x0f7f, 0x0c7f, 0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420,
+	0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8,
+	0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff,
+	0x2130, 0xa094, 0xff00, 0x00c0, 0x2558, 0x81ff, 0x0040, 0x255c,
+	0x1078, 0x5761, 0x0078, 0x2563, 0xa080, 0x29c0, 0x200c, 0xa18c,
+	0xff00, 0x810f, 0xa006, 0x007c, 0xa080, 0x29c0, 0x200c, 0xa18c,
+	0x00ff, 0x007c, 0x0c7e, 0x2061, 0xa600, 0x6030, 0x0040, 0x2573,
+	0xc09d, 0x0078, 0x2574, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e,
+	0x157e, 0x0f7e, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c,
+	0x00c0, 0x2584, 0x00f0, 0x257e, 0x0f7f, 0x157f, 0x007f, 0x007c,
+	0x0c7e, 0x007e, 0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e,
+	0x60e4, 0x007e, 0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e,
+	0x60ec, 0x007e, 0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e,
+	0x60e0, 0x007e, 0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005,
+	0x0005, 0x0005, 0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2,
+	0x007f, 0x602a, 0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee,
+	0x007f, 0x60f2, 0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6,
+	0x007f, 0x604a, 0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x25e7,
+	0x25eb, 0x25ef, 0x25f5, 0x25fb, 0x2601, 0x2607, 0x260f, 0x2617,
+	0x261d, 0x2623, 0x262b, 0x2633, 0x263b, 0x2643, 0x264d, 0x2657,
+	0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657,
+	0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x2657, 0x107e,
+	0x007e, 0x0078, 0x2670, 0x107e, 0x007e, 0x0078, 0x2670, 0x107e,
+	0x007e, 0x1078, 0x226c, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078,
+	0x226c, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x0078,
+	0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e,
+	0x007e, 0x1078, 0x226c, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e,
+	0x007e, 0x1078, 0x226c, 0x1078, 0x2133, 0x0078, 0x2670, 0x107e,
+	0x007e, 0x1078, 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078,
+	0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078,
+	0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078,
+	0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x1078,
+	0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x2133, 0x1078,
+	0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078, 0x226c, 0x1078,
+	0x2133, 0x1078, 0x2178, 0x0078, 0x2670, 0x107e, 0x007e, 0x1078,
+	0x226c, 0x1078, 0x2133, 0x1078, 0x2178, 0x0078, 0x2670, 0x0005,
+	0x0078, 0x2657, 0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x2660,
+	0x2670, 0x25ed, 0x25f1, 0x25f7, 0x25fd, 0x2603, 0x2609, 0x2611,
+	0x2619, 0x261f, 0x2625, 0x262d, 0x2635, 0x263d, 0x2645, 0x264f,
+	0x0008, 0x265a, 0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e,
+	0x027e, 0x047e, 0x2021, 0x0000, 0x1078, 0x4967, 0x00c0, 0x2772,
+	0x70cc, 0xd09c, 0x0040, 0x268e, 0xd084, 0x00c0, 0x268e, 0xd0bc,
+	0x00c0, 0x2772, 0x1078, 0x2776, 0x0078, 0x2772, 0xd0cc, 0x00c0,
+	0x2772, 0xd094, 0x0040, 0x2698, 0x7097, 0xffff, 0x0078, 0x2772,
+	0x2001, 0x010c, 0x203c, 0x7284, 0xd284, 0x0040, 0x2701, 0xd28c,
+	0x00c0, 0x2701, 0x037e, 0x7394, 0xa38e, 0xffff, 0x0040, 0x26ab,
+	0x83ff, 0x00c0, 0x26ad, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xacc0,
+	0x2c04, 0xa38c, 0x0001, 0x0040, 0x26ba, 0xa084, 0xff00, 0x8007,
+	0x0078, 0x26bc, 0xa084, 0x00ff, 0xa70e, 0x0040, 0x26f6, 0xa08e,
+	0x0000, 0x0040, 0x26f6, 0xa08e, 0x00ff, 0x00c0, 0x26d3, 0x7230,
+	0xd284, 0x00c0, 0x26fc, 0x7284, 0xc28d, 0x7286, 0x7097, 0xffff,
+	0x037f, 0x0078, 0x2701, 0x2009, 0x0000, 0x1078, 0x254d, 0x1078,
+	0x455c, 0x00c0, 0x26f9, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006,
+	0x00c0, 0x26f0, 0x7030, 0xd08c, 0x0040, 0x26ea, 0x6000, 0xd0bc,
+	0x0040, 0x26f0, 0x1078, 0x278c, 0x0040, 0x26f9, 0x0078, 0x26f6,
+	0x1078, 0x28c4, 0x1078, 0x27b9, 0x0040, 0x26f9, 0x8318, 0x0078,
+	0x26ad, 0x7396, 0x0078, 0x26fe, 0x7097, 0xffff, 0x037f, 0x0078,
+	0x2772, 0xa780, 0x29c0, 0x203c, 0xa7bc, 0xff00, 0x873f, 0x2041,
+	0x007e, 0x7094, 0xa096, 0xffff, 0x00c0, 0x2713, 0x2009, 0x0000,
+	0x28a8, 0x0078, 0x271f, 0xa812, 0x0048, 0x271b, 0x2008, 0xa802,
+	0x20a8, 0x0078, 0x271f, 0x7097, 0xffff, 0x0078, 0x2772, 0x2700,
+	0x157e, 0x017e, 0xa106, 0x0040, 0x2766, 0xc484, 0x1078, 0x45c4,
+	0x0040, 0x2730, 0x1078, 0x455c, 0x00c0, 0x276f, 0x0078, 0x2731,
+	0xc485, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2740,
+	0x7030, 0xd08c, 0x0040, 0x275e, 0x6000, 0xd0bc, 0x00c0, 0x275e,
+	0x7284, 0xd28c, 0x0040, 0x2756, 0x6004, 0xa084, 0x00ff, 0xa082,
+	0x0006, 0x0048, 0x2766, 0xd484, 0x00c0, 0x2752, 0x1078, 0x457f,
+	0x0078, 0x2754, 0x1078, 0x298e, 0x0078, 0x2766, 0x1078, 0x28c4,
+	0x1078, 0x27b9, 0x0040, 0x276f, 0x0078, 0x2766, 0x1078, 0x2959,
+	0x0040, 0x2766, 0x1078, 0x278c, 0x0040, 0x276f, 0x017f, 0x8108,
+	0x157f, 0x00f0, 0x271f, 0x7097, 0xffff, 0x0078, 0x2772, 0x017f,
+	0x157f, 0x7196, 0x047f, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x017e,
+	0x7097, 0x0001, 0x2009, 0x007e, 0x1078, 0x455c, 0x00c0, 0x2789,
+	0x1078, 0x28c4, 0x1078, 0x27b9, 0x0040, 0x2789, 0x70cc, 0xc0bd,
+	0x70ce, 0x017f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e,
+	0x2c68, 0x2001, 0xa657, 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078,
+	0x76c7, 0x0040, 0x27b4, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001,
+	0x0000, 0x1078, 0x44ee, 0x2001, 0x0000, 0x1078, 0x4502, 0x127e,
+	0x2091, 0x8000, 0x7090, 0x8000, 0x7092, 0x127f, 0x2009, 0x0004,
+	0x1078, 0x775c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f,
+	0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x2001, 0xa657,
+	0x2004, 0xa084, 0x00ff, 0x6842, 0x1078, 0x9187, 0x0040, 0x27f2,
+	0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e,
+	0x0040, 0x27db, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+	0x27db, 0x1078, 0x2880, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078,
+	0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x127e, 0x2091, 0x8000,
+	0x7090, 0x8000, 0x7092, 0x127f, 0x2009, 0x0002, 0x1078, 0x775c,
+	0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e,
+	0x027e, 0x2009, 0x0080, 0x1078, 0x455c, 0x00c0, 0x2805, 0x1078,
+	0x2808, 0x0040, 0x2805, 0x70d3, 0xffff, 0x027f, 0x0c7f, 0x007c,
+	0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x1078, 0x76c7, 0x0040,
+	0x282a, 0x2d00, 0x601a, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078,
+	0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x127e, 0x2091, 0x8000,
+	0x70d4, 0x8000, 0x70d6, 0x127f, 0x2009, 0x0002, 0x1078, 0x775c,
+	0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f, 0x017f, 0x007c, 0x0c7e,
+	0x0d7e, 0x127e, 0x2091, 0x8000, 0x2009, 0x007f, 0x1078, 0x455c,
+	0x00c0, 0x284b, 0x2c68, 0x1078, 0x76c7, 0x0040, 0x284b, 0x2d00,
+	0x601a, 0x6312, 0x601f, 0x0001, 0x620a, 0x2009, 0x0022, 0x1078,
+	0x775c, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x0c7f, 0x007c, 0x0e7e,
+	0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078, 0x5f0e, 0x1078, 0x5eae,
+	0x1078, 0x8068, 0x2130, 0x81ff, 0x0040, 0x2864, 0x20a9, 0x007e,
+	0x2009, 0x0000, 0x0078, 0x2868, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x017e, 0x1078, 0x45c4, 0x00c0, 0x2871, 0x1078, 0x47e9, 0x1078,
+	0x42f8, 0x017f, 0x8108, 0x00f0, 0x2868, 0x86ff, 0x00c0, 0x287a,
+	0x1078, 0x119b, 0x027f, 0x037f, 0x067f, 0x0c7f, 0x0e7f, 0x007c,
+	0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270, 0x72a0,
+	0x027e, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000,
+	0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f, 0x017f, 0x2e60,
+	0x1078, 0x47e9, 0x6210, 0x6314, 0x1078, 0x42f8, 0x6212, 0x6316,
+	0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x007e,
+	0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x00c0, 0x28ba, 0x2071,
+	0xa600, 0x7090, 0xa005, 0x0040, 0x28b7, 0x8001, 0x7092, 0x007f,
+	0x0e7f, 0x007c, 0x2071, 0xa600, 0x70d4, 0xa005, 0x0040, 0x28b7,
+	0x8001, 0x70d6, 0x0078, 0x28b7, 0x6000, 0xc08c, 0x6002, 0x007c,
+	0x0f7e, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x157e, 0x2178,
+	0x81ff, 0x00c0, 0x28d7, 0x20a9, 0x0001, 0x0078, 0x28f2, 0x2001,
+	0xa653, 0x2004, 0xd0c4, 0x0040, 0x28ee, 0xd0a4, 0x0040, 0x28ee,
+	0x047e, 0x6018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427,
+	0xa006, 0x2009, 0x002d, 0x1078, 0xa21d, 0x047f, 0x20a9, 0x00ff,
+	0x2011, 0x0000, 0x027e, 0xa28e, 0x007e, 0x0040, 0x2936, 0xa28e,
+	0x007f, 0x0040, 0x2936, 0xa28e, 0x0080, 0x0040, 0x2936, 0xa288,
+	0xa735, 0x210c, 0x81ff, 0x0040, 0x2936, 0x8fff, 0x1040, 0x2942,
+	0x0c7e, 0x2160, 0x2001, 0x0001, 0x1078, 0x4972, 0x0c7f, 0x2019,
+	0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a,
+	0x0c7e, 0x027e, 0x2160, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006,
+	0x00c0, 0x2926, 0x6007, 0x0404, 0x0078, 0x292b, 0x2001, 0x0004,
+	0x8007, 0xa215, 0x6206, 0x027f, 0x0c7f, 0x017e, 0x2c08, 0x1078,
+	0x9f8b, 0x017f, 0x077f, 0x2160, 0x1078, 0x47e9, 0x027f, 0x8210,
+	0x00f0, 0x28f2, 0x157f, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f,
+	0x0f7f, 0x007c, 0x047e, 0x027e, 0x017e, 0x2001, 0xa653, 0x2004,
+	0xd0c4, 0x0040, 0x2955, 0xd0a4, 0x0040, 0x2955, 0xa006, 0x2220,
+	0x8427, 0x2009, 0x0029, 0x1078, 0xa21d, 0x017f, 0x027f, 0x047f,
+	0x007c, 0x017e, 0x027e, 0x037e, 0x0c7e, 0x7284, 0x82ff, 0x0040,
+	0x2987, 0xa290, 0xa653, 0x2214, 0xd2ac, 0x00c0, 0x2987, 0x2100,
+	0x1078, 0x2564, 0x81ff, 0x0040, 0x2989, 0x2019, 0x0001, 0x8314,
+	0xa2e0, 0xacc0, 0x2c04, 0xd384, 0x0040, 0x297b, 0xa084, 0xff00,
+	0x8007, 0x0078, 0x297d, 0xa084, 0x00ff, 0xa116, 0x0040, 0x2989,
+	0xa096, 0x00ff, 0x0040, 0x2987, 0x8318, 0x0078, 0x296f, 0xa085,
+	0x0001, 0x0c7f, 0x037f, 0x027f, 0x017f, 0x007c, 0x017e, 0x0c7e,
+	0x127e, 0x2091, 0x8000, 0x017e, 0x027e, 0x037e, 0x2110, 0x027e,
+	0x2019, 0x0029, 0x1078, 0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f,
+	0x027f, 0x017f, 0xa180, 0xa735, 0x2004, 0xa065, 0x0040, 0x29b7,
+	0x017e, 0x0c7e, 0x1078, 0x9187, 0x017f, 0x1040, 0x1332, 0x611a,
+	0x1078, 0x2880, 0x1078, 0x772d, 0x017f, 0x1078, 0x457f, 0x127f,
+	0x0c7f, 0x017f, 0x007c, 0x2001, 0xa633, 0x2004, 0xd0cc, 0x007c,
+	0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da,
+	0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce,
+	0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5,
+	0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3,
+	0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9,
+	0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b,
+	0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081,
+	0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073,
+	0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69,
+	0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056,
+	0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c,
+	0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c,
+	0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831,
+	0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026,
+	0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017,
+	0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000,
+	0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000,
+	0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300,
+	0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100,
+	0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00,
+	0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800,
+	0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000,
+	0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000,
+	0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500,
+	0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000,
+	0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000,
+	0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000,
+	0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000,
+	0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x2071, 0xa682, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a,
+	0x703e, 0x7033, 0xa692, 0x7037, 0xa692, 0x7007, 0x0001, 0x2061,
+	0xa6d2, 0x6003, 0x0002, 0x007c, 0x0090, 0x2ae7, 0x0068, 0x2ae7,
+	0x2071, 0xa682, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2ae7, 0x2a60,
+	0x7820, 0xa08e, 0x0069, 0x00c0, 0x2bd7, 0x0079, 0x2b6b, 0x007c,
+	0x2071, 0xa682, 0x7004, 0x0079, 0x2aed, 0x2af1, 0x2af2, 0x2afc,
+	0x2b0e, 0x007c, 0x0090, 0x2afb, 0x0068, 0x2afb, 0x2b78, 0x7818,
+	0xd084, 0x0040, 0x2b1a, 0x007c, 0x2b78, 0x2061, 0xa6d2, 0x6008,
+	0xa08e, 0x0100, 0x0040, 0x2b09, 0xa086, 0x0200, 0x0040, 0x2bcf,
+	0x007c, 0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068,
+	0x6834, 0xa086, 0x0103, 0x0040, 0x2b16, 0x007c, 0x2a60, 0x2b78,
+	0x7018, 0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2b23,
+	0x61bc, 0x0079, 0x2b2b, 0x2100, 0xa08a, 0x003f, 0x00c8, 0x2bcb,
+	0x61bc, 0x0079, 0x2b6b, 0x2bad, 0x2bdf, 0x2be7, 0x2beb, 0x2bf3,
+	0x2bf9, 0x2bfd, 0x2c09, 0x2c0d, 0x2c17, 0x2c1b, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2c1f, 0x2bcb, 0x2c2f, 0x2c46, 0x2c5d, 0x2cdd, 0x2ce2,
+	0x2d0f, 0x2d69, 0x2d7a, 0x2d98, 0x2dd9, 0x2de3, 0x2df0, 0x2e03,
+	0x2e22, 0x2e2b, 0x2e68, 0x2e6e, 0x2bcb, 0x2e8a, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x2e91, 0x2e9b, 0x2bcb, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2ea3, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x2eb5, 0x2ece, 0x2bcb, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x2ee0, 0x2f37, 0x2f95, 0x2fa9, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x398e, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x2c17, 0x2c1b, 0x2fc0, 0x2bcb, 0x2fcd,
+	0x3a26, 0x3a83, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb,
+	0x2bcb, 0x2bcb, 0x2bcb, 0x301a, 0x314f, 0x316b, 0x3177, 0x31da,
+	0x3233, 0x323e, 0x327d, 0x328c, 0x329b, 0x329e, 0x2fd1, 0x32c2,
+	0x331e, 0x332b, 0x343c, 0x356f, 0x3599, 0x36a6, 0x2bcb, 0x36b6,
+	0x36f0, 0x37bf, 0x2bcb, 0x2bcb, 0x2bcb, 0x2bcb, 0x3827, 0x3843,
+	0x38bd, 0x3977, 0x713c, 0x0078, 0x2bad, 0x2021, 0x4000, 0x1078,
+	0x35f5, 0x127e, 0x2091, 0x8000, 0x0068, 0x2bba, 0x7818, 0xd084,
+	0x0040, 0x2bbd, 0x127f, 0x0078, 0x2bb1, 0x7c22, 0x7926, 0x7a2a,
+	0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091,
+	0x5000, 0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x2baf, 0x2021,
+	0x4002, 0x0078, 0x2baf, 0x2021, 0x4003, 0x0078, 0x2baf, 0x2021,
+	0x4005, 0x0078, 0x2baf, 0x2021, 0x4006, 0x0078, 0x2baf, 0xa02e,
+	0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x3604, 0x7823,
+	0x0004, 0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824,
+	0x7930, 0x0078, 0x3608, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078,
+	0x2bad, 0x7924, 0x2114, 0x0078, 0x2bad, 0x2099, 0x0009, 0x20a1,
+	0x0009, 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0078,
+	0x2bad, 0x7824, 0x2060, 0x0078, 0x2c21, 0x2009, 0x0001, 0x2011,
+	0x0013, 0x2019, 0x0018, 0x783b, 0x0017, 0x0078, 0x2bad, 0x7d38,
+	0x7c3c, 0x0078, 0x2be1, 0x7d38, 0x7c3c, 0x0078, 0x2bed, 0x2061,
+	0x1000, 0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0,
+	0x2c23, 0x2010, 0xa005, 0x0040, 0x2bad, 0x0078, 0x2bd3, 0x2069,
+	0xa652, 0x7824, 0x7930, 0xa11a, 0x00c8, 0x2bdb, 0x8019, 0x0040,
+	0x2bdb, 0x684a, 0x6942, 0x782c, 0x6852, 0x7828, 0x6856, 0xa006,
+	0x685a, 0x685e, 0x1078, 0x4eae, 0x0078, 0x2bad, 0x2069, 0xa652,
+	0x7824, 0x7934, 0xa11a, 0x00c8, 0x2bdb, 0x8019, 0x0040, 0x2bdb,
+	0x684e, 0x6946, 0x782c, 0x6862, 0x7828, 0x6866, 0xa006, 0x686a,
+	0x686e, 0x1078, 0x4a3e, 0x0078, 0x2bad, 0xa02e, 0x2520, 0x81ff,
+	0x00c0, 0x2bd7, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1,
+	0xa689, 0x41a1, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x2009, 0x0020,
+	0x1078, 0x3604, 0x701b, 0x2c75, 0x007c, 0x6834, 0x2008, 0xa084,
+	0x00ff, 0xa096, 0x0011, 0x0040, 0x2c85, 0xa096, 0x0019, 0x0040,
+	0x2c85, 0xa096, 0x0015, 0x00c0, 0x2bd7, 0x810f, 0xa18c, 0x00ff,
+	0x0040, 0x2bd7, 0x710e, 0x700c, 0x8001, 0x0040, 0x2cb6, 0x700e,
+	0x1078, 0x35ba, 0x0040, 0x2bd7, 0x2009, 0x0020, 0x2061, 0xa6d2,
+	0x6224, 0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000,
+	0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x1078, 0x3604, 0x701b, 0x2ca9,
+	0x007c, 0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0040, 0x2cb4,
+	0xa096, 0x000a, 0x00c0, 0x2bd7, 0x0078, 0x2c8b, 0x7010, 0x2068,
+	0x6838, 0xc0fd, 0x683a, 0x1078, 0x4431, 0x00c0, 0x2cc4, 0x7007,
+	0x0003, 0x701b, 0x2cc6, 0x007c, 0x1078, 0x4b51, 0x127e, 0x2091,
+	0x8000, 0x20a9, 0x0005, 0x2099, 0xa689, 0x530a, 0x2100, 0xa210,
+	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0xad80, 0x000d,
+	0x2009, 0x0020, 0x127f, 0x0078, 0x3608, 0x61a4, 0x7824, 0x60a6,
+	0x0078, 0x2bad, 0x2091, 0x8000, 0x7823, 0x4000, 0x7827, 0x4953,
+	0x782b, 0x5020, 0x782f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7832,
+	0x3f00, 0x7836, 0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c,
+	0x8007, 0xa205, 0x783a, 0x2009, 0x04fd, 0x2104, 0x783e, 0x781b,
+	0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2071, 0x0010, 0x20c1,
+	0x00f0, 0xa08a, 0x0003, 0x00c8, 0x0427, 0x0078, 0x0423, 0x81ff,
+	0x00c0, 0x2bd7, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x45c4,
+	0x00c0, 0x2bdb, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048,
+	0x2d23, 0x0078, 0x2bdb, 0x7c28, 0x7d2c, 0x1078, 0x47a4, 0xd28c,
+	0x00c0, 0x2d2e, 0x1078, 0x4736, 0x0078, 0x2d30, 0x1078, 0x4772,
+	0x00c0, 0x2d5a, 0x2061, 0xad00, 0x127e, 0x2091, 0x8000, 0x6000,
+	0xa086, 0x0000, 0x0040, 0x2d48, 0x6010, 0xa06d, 0x0040, 0x2d48,
+	0x683c, 0xa406, 0x00c0, 0x2d48, 0x6840, 0xa506, 0x0040, 0x2d53,
+	0x127f, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02, 0x00c8,
+	0x2bd7, 0x0078, 0x2d34, 0x1078, 0x8a01, 0x127f, 0x0040, 0x2bd7,
+	0x0078, 0x2bad, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4b51, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x8f85, 0x1078, 0x4a73, 0x127f, 0x0078,
+	0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, 0x0040, 0x2bdb,
+	0x1078, 0x4673, 0x0040, 0x2bd7, 0x1078, 0x47b2, 0x0040, 0x2bd7,
+	0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040,
+	0x2bdb, 0x1078, 0x482f, 0x0040, 0x2bd7, 0x2019, 0x0005, 0x1078,
+	0x47d3, 0x0040, 0x2bd7, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb,
+	0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x5a52, 0x0078, 0x2bad,
+	0x127e, 0x2091, 0x8000, 0x81ff, 0x0040, 0x2da2, 0x2009, 0x0001,
+	0x0078, 0x2dd3, 0x2029, 0x00ff, 0x6450, 0x2400, 0xa506, 0x0040,
+	0x2dcd, 0x2508, 0x1078, 0x45c4, 0x00c0, 0x2dcd, 0x1078, 0x482f,
+	0x00c0, 0x2db8, 0x2009, 0x0002, 0x62ac, 0x2518, 0x0078, 0x2dd3,
+	0x2019, 0x0004, 0x1078, 0x47d3, 0x00c0, 0x2dc2, 0x2009, 0x0006,
+	0x0078, 0x2dd3, 0x7824, 0xa08a, 0x1000, 0x00c8, 0x2dd6, 0x8003,
+	0x800b, 0x810b, 0xa108, 0x1078, 0x5a52, 0x8529, 0x00c8, 0x2da5,
+	0x127f, 0x0078, 0x2bad, 0x127f, 0x0078, 0x2bd7, 0x127f, 0x0078,
+	0x2bdb, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x46e7, 0x1078,
+	0x47a4, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2,
+	0x0040, 0x2bdb, 0x1078, 0x46d6, 0x1078, 0x47a4, 0x0078, 0x2bad,
+	0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078,
+	0x4775, 0x0040, 0x2bd7, 0x1078, 0x4484, 0x1078, 0x472f, 0x1078,
+	0x47a4, 0x0078, 0x2bad, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078,
+	0x4673, 0x0040, 0x2bd7, 0x62a0, 0x2019, 0x0005, 0x0c7e, 0x1078,
+	0x47e9, 0x0c7f, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078,
+	0x5e0a, 0x2009, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x1078, 0x47a4,
+	0x0078, 0x2bad, 0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x47a4,
+	0x2208, 0x0078, 0x2bad, 0x157e, 0x0d7e, 0x0e7e, 0x2069, 0xa714,
+	0x6810, 0x6914, 0xa10a, 0x00c8, 0x2e37, 0x2009, 0x0000, 0x6816,
+	0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x00ff, 0x2069, 0xa735,
+	0x2d04, 0xa075, 0x0040, 0x2e4c, 0x704c, 0x1078, 0x2e56, 0xa210,
+	0x7080, 0x1078, 0x2e56, 0xa318, 0x8d68, 0x00f0, 0x2e40, 0x2300,
+	0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078, 0x2bad, 0x0f7e, 0x017e,
+	0xa07d, 0x0040, 0x2e65, 0x2001, 0x0000, 0x8000, 0x2f0c, 0x81ff,
+	0x0040, 0x2e65, 0x2178, 0x0078, 0x2e5d, 0x017f, 0x0f7f, 0x007c,
+	0x2069, 0xa714, 0x6910, 0x62a8, 0x0078, 0x2bad, 0x81ff, 0x00c0,
+	0x2bd7, 0x6150, 0xa190, 0x29c0, 0x2214, 0xa294, 0x00ff, 0x6070,
+	0xa084, 0xff00, 0xa215, 0x636c, 0x67cc, 0xd79c, 0x0040, 0x2e84,
+	0x2031, 0x0001, 0x0078, 0x2e86, 0x2031, 0x0000, 0x7e3a, 0x7f3e,
+	0x0078, 0x2bad, 0x6140, 0x6244, 0x2019, 0xa8a2, 0x231c, 0x0078,
+	0x2bad, 0x127e, 0x2091, 0x8000, 0x6134, 0x6338, 0xa006, 0x2010,
+	0x127f, 0x0078, 0x2bad, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x6244,
+	0x6338, 0x0078, 0x2bad, 0x6140, 0x6244, 0x7824, 0x6042, 0x7b28,
+	0x6346, 0x2069, 0xa652, 0x831f, 0xa305, 0x6816, 0x782c, 0x2069,
+	0xa8a2, 0x2d1c, 0x206a, 0x0078, 0x2bad, 0x017e, 0x127e, 0x2091,
+	0x8000, 0x7824, 0x6036, 0xd094, 0x0040, 0x2ec8, 0x7828, 0xa085,
+	0x0001, 0x2009, 0xa8ab, 0x200a, 0x2001, 0xffff, 0x1078, 0x5ae6,
+	0x782c, 0x603a, 0x127f, 0x017f, 0x0078, 0x2bad, 0x1078, 0x35e4,
+	0x0040, 0x2bdb, 0x7828, 0xa00d, 0x0040, 0x2bdb, 0x782c, 0xa005,
+	0x0040, 0x2bdb, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078, 0x2bad,
+	0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x0c7e,
+	0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff,
+	0x00c0, 0x2ef7, 0x6030, 0xa085, 0xff00, 0x0078, 0x2f06, 0xa182,
+	0x007f, 0x00c8, 0x2f30, 0xa188, 0x29c0, 0x210c, 0xa18c, 0x00ff,
+	0x6030, 0xa116, 0x0040, 0x2f30, 0x810f, 0xa105, 0x127e, 0x2091,
+	0x8000, 0x007e, 0x1078, 0x76c7, 0x007f, 0x0040, 0x2f2c, 0x601a,
+	0x600b, 0xbc09, 0x601f, 0x0001, 0x1078, 0x35ba, 0x0040, 0x2f33,
+	0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x701b, 0x2f8e, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078,
+	0x775c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2bd7,
+	0x0c7f, 0x0078, 0x2bdb, 0x1078, 0x772d, 0x0078, 0x2f2c, 0x2001,
+	0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x0c7e, 0x2061,
+	0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x00c0,
+	0x2f4e, 0x6030, 0xa085, 0xff00, 0x0078, 0x2f5d, 0xa182, 0x007f,
+	0x00c8, 0x2f87, 0xa188, 0x29c0, 0x210c, 0xa18c, 0x00ff, 0x6030,
+	0xa116, 0x0040, 0x2f87, 0x810f, 0xa105, 0x127e, 0x2091, 0x8000,
+	0x007e, 0x1078, 0x76c7, 0x007f, 0x0040, 0x2f83, 0x601a, 0x600b,
+	0xbc05, 0x601f, 0x0001, 0x1078, 0x35ba, 0x0040, 0x2f8a, 0x6837,
+	0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a,
+	0x701b, 0x2f8e, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078, 0x775c,
+	0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2bd7, 0x0c7f,
+	0x0078, 0x2bdb, 0x1078, 0x772d, 0x0078, 0x2f83, 0x6830, 0xa086,
+	0x0100, 0x0040, 0x2bd7, 0x0078, 0x2bad, 0x2061, 0xa933, 0x127e,
+	0x2091, 0x8000, 0x6000, 0xd084, 0x0040, 0x2fa6, 0x6104, 0x6208,
+	0x2019, 0xa612, 0x231c, 0x127f, 0x0078, 0x2bad, 0x127f, 0x0078,
+	0x2bdb, 0x81ff, 0x00c0, 0x2bd7, 0x127e, 0x2091, 0x8000, 0x6248,
+	0x6064, 0xa202, 0x0048, 0x2fbd, 0xa085, 0x0001, 0x1078, 0x256a,
+	0x1078, 0x3c9e, 0x127f, 0x0078, 0x2bad, 0x127f, 0x0078, 0x2bdb,
+	0x127e, 0x2091, 0x8000, 0x20a9, 0x0012, 0x2001, 0xa640, 0x20a0,
+	0xa006, 0x40a4, 0x127f, 0x0078, 0x2bad, 0x7d38, 0x7c3c, 0x0078,
+	0x2c5f, 0x7824, 0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x2bd7,
+	0x6250, 0xa084, 0xff00, 0x8007, 0xa206, 0x00c0, 0x2fe9, 0x2001,
+	0xa640, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078,
+	0x3608, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x2bd7, 0x0c7e,
+	0x1078, 0x35ba, 0x0c7f, 0x0040, 0x2bd7, 0x6837, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x1078, 0x8e4a, 0x0040, 0x2bd7, 0x7007, 0x0003,
+	0x701b, 0x300b, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7,
+	0xad80, 0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x0078, 0x3608, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x1078, 0x42dd,
+	0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604,
+	0x701b, 0x302b, 0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040,
+	0x2bdb, 0x6804, 0xd0ac, 0x0040, 0x3038, 0xd0a4, 0x0040, 0x2bdb,
+	0xd094, 0x0040, 0x3043, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c,
+	0xffdf, 0x6106, 0x0c7f, 0xd08c, 0x0040, 0x304e, 0x0c7e, 0x2061,
+	0x0100, 0x6104, 0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100,
+	0x210c, 0xa18a, 0x0002, 0x0048, 0x3063, 0xd084, 0x0040, 0x3063,
+	0x6a28, 0xa28a, 0x007f, 0x00c8, 0x2bdb, 0xa288, 0x29c0, 0x210c,
+	0xa18c, 0x00ff, 0x6156, 0xd0dc, 0x0040, 0x306c, 0x6828, 0xa08a,
+	0x007f, 0x00c8, 0x2bdb, 0x6052, 0x6808, 0xa08a, 0x0100, 0x0048,
+	0x2bdb, 0xa08a, 0x0841, 0x00c8, 0x2bdb, 0xa084, 0x0007, 0x00c0,
+	0x2bdb, 0x680c, 0xa005, 0x0040, 0x2bdb, 0x6810, 0xa005, 0x0040,
+	0x2bdb, 0x6848, 0x6940, 0xa10a, 0x00c8, 0x2bdb, 0x8001, 0x0040,
+	0x2bdb, 0x684c, 0x6944, 0xa10a, 0x00c8, 0x2bdb, 0x8001, 0x0040,
+	0x2bdb, 0x6804, 0xd0fc, 0x0040, 0x30c2, 0x1078, 0x35ba, 0x0040,
+	0x2bd7, 0x2009, 0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290,
+	0x0038, 0xa399, 0x0000, 0x1078, 0x3604, 0x701b, 0x30a8, 0x007c,
+	0xade8, 0x000d, 0x20a9, 0x0014, 0x2d98, 0x2069, 0xa66e, 0x2da0,
+	0x53a3, 0x7010, 0xa0e8, 0x000d, 0x2001, 0xa672, 0x200c, 0xd1e4,
+	0x0040, 0x30c2, 0x0c7e, 0x2061, 0x0100, 0x6004, 0xa085, 0x0b00,
+	0x6006, 0x0c7f, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xa652, 0x2da0,
+	0x53a3, 0x6814, 0xa08c, 0x00ff, 0x6142, 0x8007, 0xa084, 0x00ff,
+	0x6046, 0x1078, 0x4eae, 0x1078, 0x49ce, 0x1078, 0x4a3e, 0x6000,
+	0xa086, 0x0000, 0x00c0, 0x314d, 0x6808, 0x602a, 0x1078, 0x21f7,
+	0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f,
+	0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0040, 0x30fa,
+	0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f,
+	0x0078, 0x30fc, 0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312,
+	0x1078, 0x5b19, 0x6904, 0xd1fc, 0x0040, 0x312f, 0x0c7e, 0x2009,
+	0x0000, 0x20a9, 0x0001, 0x6b70, 0xd384, 0x0040, 0x312c, 0x0078,
+	0x3116, 0x839d, 0x00c8, 0x312c, 0x3508, 0x8109, 0x1078, 0x5480,
+	0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a,
+	0xa184, 0x00ff, 0x6006, 0x8108, 0x00c0, 0x312a, 0x6003, 0x0003,
+	0x0078, 0x312c, 0x6003, 0x0001, 0x00f0, 0x3111, 0x0c7f, 0x0c7e,
+	0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x1078,
+	0x3819, 0x0040, 0x313d, 0x1078, 0x256a, 0x60c0, 0xa005, 0x0040,
+	0x3149, 0x6003, 0x0001, 0x2091, 0x301d, 0x1078, 0x4224, 0x0078,
+	0x314d, 0x6003, 0x0004, 0x2091, 0x301d, 0x0078, 0x2bad, 0x6000,
+	0xa086, 0x0000, 0x0040, 0x2bd7, 0x2069, 0xa652, 0x7830, 0x6842,
+	0x7834, 0x6846, 0x6804, 0xd0fc, 0x0040, 0x3162, 0x2009, 0x0030,
+	0x0078, 0x3164, 0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, 0x7c3c,
+	0x7d38, 0x0078, 0x3608, 0xa006, 0x1078, 0x256a, 0x81ff, 0x00c0,
+	0x2bd7, 0x1078, 0x42dd, 0x1078, 0x4224, 0x0078, 0x2bad, 0x81ff,
+	0x00c0, 0x2bd7, 0x6184, 0x81ff, 0x0040, 0x3191, 0x703f, 0x0000,
+	0x2001, 0xacc0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x3608, 0x701b, 0x2baa, 0x127f,
+	0x007c, 0x703f, 0x0001, 0x0d7e, 0x2069, 0xacc0, 0x20a9, 0x0040,
+	0x20a1, 0xacc0, 0x2019, 0xffff, 0x43a4, 0x6550, 0xa588, 0x29c0,
+	0x210c, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100,
+	0xa506, 0x0040, 0x31c3, 0x1078, 0x45c4, 0x00c0, 0x31c3, 0x6014,
+	0x821c, 0x0048, 0x31bb, 0xa398, 0xacc0, 0xa085, 0xff00, 0x8007,
+	0x201a, 0x0078, 0x31c2, 0xa398, 0xacc0, 0x2324, 0xa4a4, 0xff00,
+	0xa405, 0x201a, 0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, 0x31ca,
+	0x0078, 0x31a7, 0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, 0x0d7f,
+	0x20a9, 0x0040, 0x20a1, 0xacc0, 0x2099, 0xacc0, 0x1078, 0x4281,
+	0x0078, 0x3180, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x0c7e, 0x1078,
+	0x35ba, 0x0c7f, 0x00c0, 0x31e8, 0x2009, 0x0002, 0x0078, 0x2bd7,
+	0x2001, 0xa653, 0x2004, 0xd0b4, 0x0040, 0x320f, 0x6000, 0xd08c,
+	0x00c0, 0x320f, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+	0x320f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8e9e,
+	0x00c0, 0x3206, 0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003,
+	0x701b, 0x320b, 0x007c, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x20a9,
+	0x002b, 0x2c98, 0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004,
+	0xac80, 0x0006, 0x2098, 0xad80, 0x0006, 0x20a0, 0x1078, 0x4281,
+	0x20a9, 0x0004, 0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0,
+	0x1078, 0x4281, 0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c,
+	0x7d38, 0x0078, 0x3608, 0x81ff, 0x00c0, 0x2bd7, 0x1078, 0x35d2,
+	0x0040, 0x2bdb, 0x1078, 0x47bd, 0x0078, 0x2bad, 0x81ff, 0x00c0,
+	0x2bd7, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb, 0x1078, 0x35e4,
+	0x0040, 0x2bdb, 0x1078, 0x482f, 0x0040, 0x2bd7, 0x2019, 0x0004,
+	0x1078, 0x47d3, 0x7924, 0x810f, 0x7a28, 0x1078, 0x3259, 0x0078,
+	0x2bad, 0xa186, 0x00ff, 0x0040, 0x3261, 0x1078, 0x3271, 0x0078,
+	0x3270, 0x2029, 0x007e, 0x2061, 0xa600, 0x6450, 0x2400, 0xa506,
+	0x0040, 0x326d, 0x2508, 0x1078, 0x3271, 0x8529, 0x00c8, 0x3266,
+	0x007c, 0x1078, 0x45c4, 0x00c0, 0x327c, 0x2200, 0x8003, 0x800b,
+	0x810b, 0xa108, 0x1078, 0x5a52, 0x007c, 0x81ff, 0x00c0, 0x2bd7,
+	0x1078, 0x35d2, 0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7,
+	0x1078, 0x47c8, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7, 0x1078,
+	0x35d2, 0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7, 0x1078,
+	0x47b2, 0x0078, 0x2bad, 0x6100, 0x0078, 0x2bad, 0x1078, 0x35e4,
+	0x0040, 0x2bdb, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0,
+	0x2bd7, 0x0d7e, 0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x32b2,
+	0xace8, 0x0006, 0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a,
+	0x6b04, 0x831f, 0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200,
+	0x0078, 0x2bad, 0xa006, 0x1078, 0x256a, 0x7824, 0xa084, 0x00ff,
+	0xa086, 0x00ff, 0x0040, 0x32cf, 0x81ff, 0x00c0, 0x2bd7, 0x1078,
+	0x42dd, 0x7828, 0xa08a, 0x1000, 0x00c8, 0x2bdb, 0x7924, 0xa18c,
+	0xff00, 0x810f, 0xa186, 0x00ff, 0x0040, 0x32e5, 0xa182, 0x007f,
+	0x00c8, 0x2bdb, 0x2100, 0x1078, 0x2564, 0x027e, 0x0c7e, 0x127e,
+	0x2091, 0x8000, 0x2061, 0xa8c4, 0x601b, 0x0000, 0x601f, 0x0000,
+	0x2011, 0x0003, 0x1078, 0x70e0, 0x2011, 0x0002, 0x1078, 0x70ea,
+	0x1078, 0x6fc4, 0x037e, 0x2019, 0x0000, 0x1078, 0x7058, 0x037f,
+	0x2061, 0x0100, 0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a,
+	0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4259,
+	0x1078, 0x5add, 0x7924, 0xa18c, 0xff00, 0x810f, 0x7a28, 0x1078,
+	0x3259, 0x127f, 0x0c7f, 0x027f, 0x0078, 0x2bad, 0x7924, 0xa18c,
+	0xff00, 0x810f, 0x0c7e, 0x1078, 0x455c, 0x2c08, 0x0c7f, 0x00c0,
+	0x2bdb, 0x0078, 0x2bad, 0x81ff, 0x0040, 0x3332, 0x2009, 0x0001,
+	0x0078, 0x2bd7, 0x60cc, 0xd09c, 0x00c0, 0x333a, 0x2009, 0x0005,
+	0x0078, 0x2bd7, 0x1078, 0x35ba, 0x00c0, 0x3342, 0x2009, 0x0002,
+	0x0078, 0x2bd7, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078,
+	0x3604, 0x701b, 0x334c, 0x007c, 0x2009, 0x0080, 0x1078, 0x45c4,
+	0x00c0, 0x3359, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040,
+	0x335d, 0x2021, 0x400a, 0x0078, 0x2baf, 0x0d7e, 0xade8, 0x000d,
+	0x6900, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be,
+	0x0100, 0x0040, 0x33d0, 0xa0be, 0x0112, 0x0040, 0x33d0, 0xa0be,
+	0x0113, 0x0040, 0x33d0, 0xa0be, 0x0114, 0x0040, 0x33d0, 0xa0be,
+	0x0117, 0x0040, 0x33d0, 0xa0be, 0x011a, 0x0040, 0x33d0, 0xa0be,
+	0x0121, 0x0040, 0x33c6, 0xa0be, 0x0131, 0x0040, 0x33c6, 0xa0be,
+	0x0171, 0x0040, 0x33d0, 0xa0be, 0x0173, 0x0040, 0x33d0, 0xa0be,
+	0x01a1, 0x00c0, 0x3398, 0x6830, 0x8007, 0x6832, 0x0078, 0x33d6,
+	0xa0be, 0x0212, 0x0040, 0x33cc, 0xa0be, 0x0213, 0x0040, 0x33cc,
+	0xa0be, 0x0214, 0x0040, 0x33be, 0xa0be, 0x0217, 0x0040, 0x33b8,
+	0xa0be, 0x021a, 0x00c0, 0x33b1, 0x6838, 0x8007, 0x683a, 0x0078,
+	0x33d0, 0xa0be, 0x0300, 0x0040, 0x33d0, 0x0d7f, 0x0078, 0x2bdb,
+	0xad80, 0x0010, 0x20a9, 0x0007, 0x1078, 0x3418, 0xad80, 0x000e,
+	0x20a9, 0x0001, 0x1078, 0x3418, 0x0078, 0x33d0, 0xad80, 0x000c,
+	0x1078, 0x3426, 0x0078, 0x33d6, 0xad80, 0x000e, 0x1078, 0x3426,
+	0xad80, 0x000c, 0x20a9, 0x0001, 0x1078, 0x3418, 0x0c7e, 0x1078,
+	0x35ba, 0x0040, 0x3409, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119,
+	0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e,
+	0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b,
+	0x0000, 0x0c7f, 0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a,
+	0x6823, 0x0000, 0x6804, 0x2068, 0x1078, 0x8e66, 0x00c0, 0x3404,
+	0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x340f,
+	0x007c, 0x0c7f, 0x0d7f, 0x2009, 0x0002, 0x0078, 0x2bd7, 0x6820,
+	0xa086, 0x8001, 0x00c0, 0x2bad, 0x2009, 0x0004, 0x0078, 0x2bd7,
+	0x017e, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108,
+	0x280a, 0x8108, 0x00f0, 0x341a, 0x017f, 0x007c, 0x017e, 0x0a7e,
+	0x0b7e, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000,
+	0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a,
+	0x0b7f, 0x0a7f, 0x017f, 0x007c, 0x81ff, 0x0040, 0x3443, 0x2009,
+	0x0001, 0x0078, 0x2bd7, 0x60cc, 0xd09c, 0x00c0, 0x344b, 0x2009,
+	0x0005, 0x0078, 0x2bd7, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f,
+	0xa182, 0x0080, 0x0048, 0x2bdb, 0xa182, 0x00ff, 0x00c8, 0x2bdb,
+	0x7a2c, 0x7b28, 0x606c, 0xa306, 0x00c0, 0x3466, 0x6070, 0xa24e,
+	0x0040, 0x2bdb, 0xa9cc, 0xff00, 0x0040, 0x2bdb, 0x0c7e, 0x1078,
+	0x350f, 0x2c68, 0x0c7f, 0x0040, 0x349e, 0xa0c6, 0x4000, 0x00c0,
+	0x3484, 0x0c7e, 0x007e, 0x2d60, 0x2009, 0x0000, 0x1078, 0x489b,
+	0x00c0, 0x347b, 0xc185, 0x6000, 0xd0bc, 0x0040, 0x3480, 0xc18d,
+	0x007f, 0x0c7f, 0x0078, 0x349b, 0xa0c6, 0x4007, 0x00c0, 0x348b,
+	0x2408, 0x0078, 0x349b, 0xa0c6, 0x4008, 0x00c0, 0x3493, 0x2708,
+	0x2610, 0x0078, 0x349b, 0xa0c6, 0x4009, 0x00c0, 0x3499, 0x0078,
+	0x349b, 0x2001, 0x4006, 0x2020, 0x0078, 0x2baf, 0x2d00, 0x7022,
+	0x017e, 0x0b7e, 0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x76c7, 0x0040,
+	0x34e4, 0x2d00, 0x601a, 0x2001, 0xa657, 0x2004, 0xa084, 0x00ff,
+	0x6842, 0x2e58, 0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x35ba, 0x0c7f,
+	0x2b70, 0x00c0, 0x34c5, 0x1078, 0x772d, 0x0e7f, 0x0c7f, 0x0b7f,
+	0x017f, 0x2009, 0x0002, 0x0078, 0x2bd7, 0x6837, 0x0000, 0x2d00,
+	0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x2880, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000,
+	0x1078, 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x2009, 0x0002,
+	0x1078, 0x775c, 0xa085, 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f,
+	0x00c0, 0x34ee, 0x2009, 0x0003, 0x0078, 0x2bd7, 0x7007, 0x0003,
+	0x701b, 0x34f3, 0x007c, 0x6830, 0xa086, 0x0100, 0x7020, 0x2060,
+	0x00c0, 0x3501, 0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, 0x0078,
+	0x2bd7, 0x2009, 0x0000, 0x1078, 0x489b, 0x00c0, 0x3508, 0xc185,
+	0x6000, 0xd0bc, 0x0040, 0x350d, 0xc18d, 0x0078, 0x2bad, 0x0e7e,
+	0x0d7e, 0x2029, 0x0000, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071,
+	0xa7b5, 0x2e04, 0xa005, 0x00c0, 0x3524, 0x2100, 0xa406, 0x00c0,
+	0x3555, 0x2428, 0x0078, 0x3555, 0x2068, 0x6f10, 0x2700, 0xa306,
+	0x00c0, 0x3546, 0x6e14, 0x2600, 0xa206, 0x00c0, 0x3546, 0x2400,
+	0xa106, 0x00c0, 0x3542, 0x2d60, 0xd884, 0x0040, 0x356a, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x356a, 0x2001, 0x4000,
+	0x0078, 0x356b, 0x2001, 0x4007, 0x0078, 0x356b, 0x2400, 0xa106,
+	0x00c0, 0x3555, 0x6e14, 0x87ff, 0x00c0, 0x3551, 0x86ff, 0x0040,
+	0x3521, 0x2001, 0x4008, 0x0078, 0x356b, 0x8420, 0x8e70, 0x00f0,
+	0x3519, 0x85ff, 0x00c0, 0x3564, 0x2001, 0x4009, 0x0078, 0x356b,
+	0x2001, 0x0001, 0x0078, 0x356b, 0x1078, 0x455c, 0x00c0, 0x3560,
+	0x6312, 0x6216, 0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff,
+	0x00c0, 0x2bd7, 0x1078, 0x35ba, 0x0040, 0x2bd7, 0x6837, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x7824, 0xa005, 0x0040, 0x2bdb, 0xa096,
+	0x00ff, 0x0040, 0x3587, 0xa092, 0x0004, 0x00c8, 0x2bdb, 0x2010,
+	0x2d18, 0x1078, 0x282f, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b,
+	0x3592, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7, 0x0078,
+	0x2bad, 0x7924, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048,
+	0x2bdb, 0xa182, 0x00ff, 0x00c8, 0x2bdb, 0x127e, 0x2091, 0x8000,
+	0x1078, 0x8d4b, 0x00c0, 0x35b7, 0xa190, 0xa735, 0x2204, 0xa065,
+	0x0040, 0x35b7, 0x1078, 0x42f8, 0x127f, 0x0078, 0x2bad, 0x127f,
+	0x0078, 0x2bd7, 0x1078, 0x138b, 0x0040, 0x35d1, 0xa006, 0x6802,
+	0x7010, 0xa005, 0x00c0, 0x35c9, 0x2d00, 0x7012, 0x7016, 0x0078,
+	0x35cf, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80,
+	0x000d, 0x007c, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x45c4,
+	0x00c0, 0x35e1, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048,
+	0x35e2, 0xa066, 0x8cff, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff,
+	0x1078, 0x45c4, 0x00c0, 0x35f2, 0xa6b4, 0x00ff, 0xa682, 0x4000,
+	0x0048, 0x35f3, 0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff,
+	0x0040, 0x3600, 0x2168, 0x6904, 0x1078, 0x13a4, 0x0078, 0x35f7,
+	0x7112, 0x7116, 0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x360a,
+	0x2031, 0x0000, 0x2061, 0xa6d2, 0x6606, 0x6112, 0x600e, 0x6226,
+	0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13db, 0x7007, 0x0002,
+	0x701b, 0x2bad, 0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079,
+	0x0000, 0x2001, 0xa690, 0x2004, 0xa005, 0x00c0, 0x3636, 0x0068,
+	0x3636, 0x7818, 0xd084, 0x00c0, 0x3636, 0x7a22, 0x7b26, 0x7c2a,
+	0x781b, 0x0001, 0x2091, 0x4080, 0x0078, 0x365b, 0x017e, 0x0c7e,
+	0x0e7e, 0x2071, 0xa682, 0x7138, 0xa182, 0x0008, 0x0048, 0x3644,
+	0x7030, 0x2060, 0x0078, 0x3655, 0x7030, 0xa0e0, 0x0008, 0xac82,
+	0xa6d2, 0x0048, 0x364d, 0x2061, 0xa692, 0x2c00, 0x7032, 0x81ff,
+	0x00c0, 0x3653, 0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a,
+	0x0e7f, 0x0c7f, 0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071,
+	0xa682, 0x7038, 0xa005, 0x0040, 0x3697, 0x127e, 0x2091, 0x8000,
+	0x0068, 0x3696, 0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0,
+	0x3695, 0x0c7e, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826,
+	0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001,
+	0x703a, 0xa005, 0x00c0, 0x368b, 0x7033, 0xa692, 0x7037, 0xa692,
+	0x0c7f, 0x0078, 0x3695, 0xac80, 0x0008, 0xa0fa, 0xa6d2, 0x0048,
+	0x3693, 0x2001, 0xa692, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f,
+	0x007c, 0x027e, 0x2001, 0xa653, 0x2004, 0xd0c4, 0x0040, 0x36a4,
+	0x2011, 0x8014, 0x1078, 0x361b, 0x027f, 0x007c, 0x81ff, 0x00c0,
+	0x2bd7, 0x127e, 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac,
+	0x6032, 0x1078, 0x4224, 0x127f, 0x0078, 0x2bad, 0x81ff, 0x00c0,
+	0x2bd7, 0x6000, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x2001, 0xa653,
+	0x2004, 0xd0ac, 0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x36d3, 0x7828,
+	0xa005, 0x0040, 0x2bad, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, 0x0040,
+	0x2bd7, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a,
+	0x1078, 0x8f12, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x36e9,
+	0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2bd7, 0x0078, 0x2bad,
+	0x2001, 0xa600, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2bd7, 0x7f24,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x35ba, 0x0040, 0x2bd7,
+	0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000,
+	0xad80, 0x0005, 0x7026, 0x20a0, 0x1078, 0x45c4, 0x00c0, 0x376d,
+	0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0040, 0x371d, 0xa0c4,
+	0xff00, 0xa8c6, 0x0600, 0x00c0, 0x376d, 0x2001, 0xa653, 0x2004,
+	0xd0ac, 0x00c0, 0x372a, 0x1078, 0x489b, 0x00c0, 0x372a, 0xd79c,
+	0x0040, 0x376d, 0xd794, 0x00c0, 0x3730, 0xd784, 0x0040, 0x373c,
+	0xac80, 0x0006, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078,
+	0x3426, 0xd794, 0x0040, 0x3745, 0xac80, 0x000a, 0x2098, 0x3400,
+	0x20a9, 0x0004, 0x53a3, 0x1078, 0x3426, 0x21a2, 0xd794, 0x0040,
+	0x3765, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002, 0x53a3,
+	0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098, 0x3400,
+	0x20a9, 0x0002, 0x53a3, 0x1078, 0x3418, 0xac80, 0x0026, 0x2098,
+	0x20a9, 0x0002, 0x53a3, 0x0078, 0x3766, 0x94a0, 0xd794, 0x0040,
+	0x376b, 0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0xd78c, 0x0040,
+	0x3777, 0xa186, 0x0100, 0x0040, 0x3788, 0x0078, 0x377b, 0xa186,
+	0x007e, 0x0040, 0x3788, 0xd794, 0x0040, 0x3782, 0xa686, 0x0020,
+	0x0078, 0x3784, 0xa686, 0x0028, 0x0040, 0x3791, 0x0078, 0x370c,
+	0x86ff, 0x00c0, 0x378f, 0x7120, 0x810b, 0x0078, 0x2bad, 0x702f,
+	0x0001, 0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xa6d2,
+	0x6007, 0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e,
+	0x6532, 0x2c10, 0x1078, 0x13db, 0x7007, 0x0002, 0x701b, 0x37a9,
+	0x007c, 0x702c, 0xa005, 0x00c0, 0x37bb, 0x711c, 0x7024, 0x20a0,
+	0x7728, 0x2031, 0x0000, 0x2061, 0xa6d2, 0x6224, 0x6328, 0x642c,
+	0x6530, 0x0078, 0x370c, 0x7120, 0x810b, 0x0078, 0x2bad, 0x2029,
+	0x007e, 0x7924, 0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007,
+	0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa184,
+	0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb,
+	0xa284, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502,
+	0x0048, 0x2bdb, 0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb,
+	0xa502, 0x0048, 0x2bdb, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020,
+	0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa384, 0x00ff, 0xa0e2,
+	0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb, 0xa484, 0xff00,
+	0x8007, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048, 0x2bdb,
+	0xa484, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2bdb, 0xa502, 0x0048,
+	0x2bdb, 0x2061, 0xa8a5, 0x6102, 0x6206, 0x630a, 0x640e, 0x0078,
+	0x2bad, 0x007e, 0x2001, 0xa653, 0x2004, 0xd0cc, 0x007f, 0x007c,
+	0x007e, 0x2001, 0xa672, 0x2004, 0xd0bc, 0x007f, 0x007c, 0x6164,
+	0x7a24, 0x6300, 0x82ff, 0x00c0, 0x3830, 0x7926, 0x0078, 0x2bad,
+	0x83ff, 0x00c0, 0x2bdb, 0x2001, 0xfff0, 0xa200, 0x00c8, 0x2bdb,
+	0x2019, 0xffff, 0x6068, 0xa302, 0xa200, 0x0048, 0x2bdb, 0x7926,
+	0x6266, 0x0078, 0x2bad, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003,
+	0x00c0, 0x2bd7, 0x7c28, 0x7d24, 0x7e38, 0x7f2c, 0x1078, 0x35ba,
+	0x0040, 0x2bd7, 0x2009, 0x0000, 0x2019, 0x0000, 0x7023, 0x0000,
+	0x702f, 0x0000, 0xad80, 0x0003, 0x7026, 0x20a0, 0xa1e0, 0xa735,
+	0x2c64, 0x8cff, 0x0040, 0x387d, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x0040, 0x3872, 0x6004, 0xa084, 0xff00, 0xa086, 0x0600,
+	0x00c0, 0x387d, 0x6014, 0x20a2, 0x94a0, 0x6010, 0x8007, 0xa105,
+	0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108, 0xa182, 0x00ff,
+	0x0040, 0x3888, 0xa386, 0x002a, 0x0040, 0x3891, 0x0078, 0x385e,
+	0x83ff, 0x00c0, 0x388f, 0x7120, 0x810c, 0x0078, 0x2bad, 0x702f,
+	0x0001, 0x711e, 0x7020, 0xa300, 0x7022, 0x2061, 0xa6d2, 0x6007,
+	0x0000, 0x6312, 0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732,
+	0x2c10, 0x1078, 0x13db, 0x7007, 0x0002, 0x701b, 0x38a8, 0x007c,
+	0x702c, 0xa005, 0x00c0, 0x38b9, 0x711c, 0x7024, 0x20a0, 0x2019,
+	0x0000, 0x2061, 0xa6d2, 0x6424, 0x6528, 0x662c, 0x6730, 0x0078,
+	0x385e, 0x7120, 0x810c, 0x0078, 0x2bad, 0x81ff, 0x00c0, 0x2bd7,
+	0x60cc, 0xd09c, 0x0040, 0x2bd7, 0x1078, 0x35ba, 0x0040, 0x2bd7,
+	0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604, 0x701b,
+	0x38d2, 0x007c, 0x0d7e, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000,
+	0x0040, 0x38e5, 0xa0be, 0x7100, 0x0040, 0x38e5, 0xa0be, 0x7200,
+	0x0040, 0x38e5, 0x0d7f, 0x0078, 0x2bdb, 0x6820, 0x6924, 0x1078,
+	0x254d, 0x00c0, 0x3910, 0x1078, 0x455c, 0x00c0, 0x3910, 0x7122,
+	0x6612, 0x6516, 0x6e18, 0x0c7e, 0x1078, 0x35ba, 0x0040, 0x3910,
+	0x1078, 0x35ba, 0x0040, 0x3910, 0x0c7f, 0x0d7f, 0x6837, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x1078,
+	0x8e82, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x3913, 0x007c,
+	0x0d7f, 0x0078, 0x2bd7, 0x7120, 0x1078, 0x298e, 0x6820, 0xa086,
+	0x8001, 0x0040, 0x2bd7, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002,
+	0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x1078, 0x4281, 0x007f,
+	0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xa6d2,
+	0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x00c0, 0x393a,
+	0x0078, 0x393e, 0xa7c6, 0x7100, 0x00c0, 0x3946, 0xa6c2, 0x0004,
+	0x0048, 0x2bdb, 0x2009, 0x0004, 0x0078, 0x3608, 0xa7c6, 0x7200,
+	0x00c0, 0x2bdb, 0xa6c2, 0x0054, 0x0048, 0x2bdb, 0x600e, 0x6013,
+	0x002a, 0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13db,
+	0x7007, 0x0002, 0x701b, 0x395d, 0x007c, 0x701c, 0x2068, 0x6804,
+	0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x007e, 0x20a9, 0x002a,
+	0x2098, 0x20a0, 0x1078, 0x4281, 0x007f, 0x2009, 0x002a, 0x2061,
+	0xa6d2, 0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x3608, 0x81ff,
+	0x00c0, 0x2bd7, 0x792c, 0x2001, 0xa89d, 0x2102, 0x1078, 0x35d2,
+	0x0040, 0x2bdb, 0x1078, 0x4673, 0x0040, 0x2bd7, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x47de, 0x127f, 0x0078, 0x2bad, 0x7824, 0xd08c,
+	0x00c0, 0x3995, 0xd084, 0x0040, 0x31da, 0x1078, 0x35e4, 0x0040,
+	0x2bdb, 0x0c7e, 0x1078, 0x35ba, 0x0c7f, 0x00c0, 0x39a3, 0x2009,
+	0x0002, 0x0078, 0x2bd7, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006,
+	0x0040, 0x39b0, 0xa08e, 0x0004, 0x0040, 0x39b0, 0xa08e, 0x0005,
+	0x00c0, 0x39dd, 0x7824, 0xd08c, 0x0040, 0x39bb, 0x6000, 0xc08c,
+	0x6002, 0x0078, 0x39c5, 0x2001, 0xa653, 0x2004, 0xd0b4, 0x0040,
+	0x320f, 0x6000, 0xd08c, 0x00c0, 0x320f, 0x6837, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x1078, 0x8e9e, 0x00c0, 0x39d2, 0x2009, 0x0003,
+	0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x39d7, 0x007c, 0x1078,
+	0x35e4, 0x0040, 0x2bdb, 0x0078, 0x320f, 0x2009, 0xa62f, 0x210c,
+	0x81ff, 0x0040, 0x39e7, 0x2009, 0x0001, 0x0078, 0x2bd7, 0x2001,
+	0xa600, 0x2004, 0xa086, 0x0003, 0x0040, 0x39f2, 0x2009, 0x0007,
+	0x0078, 0x2bd7, 0x2001, 0xa653, 0x2004, 0xd0ac, 0x0040, 0x39fc,
+	0x2009, 0x0008, 0x0078, 0x2bd7, 0x609c, 0xd0a4, 0x00c0, 0x3a03,
+	0xd0ac, 0x00c0, 0x320f, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x1078, 0x8f12, 0x00c0, 0x3a12, 0x2009, 0x0003,
+	0x0078, 0x2bd7, 0x7007, 0x0003, 0x701b, 0x3a17, 0x007c, 0x6830,
+	0xa086, 0x0100, 0x00c0, 0x3a20, 0x2009, 0x0004, 0x0078, 0x2bd7,
+	0x1078, 0x35e4, 0x0040, 0x2bdb, 0x0078, 0x39b2, 0x81ff, 0x2009,
+	0x0001, 0x00c0, 0x2bd7, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007,
+	0x00c0, 0x2bd7, 0x2001, 0xa653, 0x2004, 0xd0ac, 0x2009, 0x0008,
+	0x00c0, 0x2bd7, 0x1078, 0x35e4, 0x0040, 0x2bdb, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x00c0, 0x2bd7, 0x0c7e,
+	0x1078, 0x35ba, 0x0c7f, 0x2009, 0x0002, 0x0040, 0x2bd7, 0x6837,
+	0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194,
+	0xff00, 0xa18c, 0x00ff, 0xa006, 0x82ff, 0x00c0, 0x3a65, 0xc0ed,
+	0x6952, 0x792c, 0x6956, 0x0078, 0x3a6e, 0xa28e, 0x0100, 0x00c0,
+	0x2bdb, 0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x1078,
+	0x90bd, 0x2009, 0x0003, 0x0040, 0x2bd7, 0x7007, 0x0003, 0x701b,
+	0x3a7a, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040,
+	0x2bd7, 0x0078, 0x2bad, 0x81ff, 0x2009, 0x0001, 0x00c0, 0x2bd7,
+	0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, 0x2bd7, 0x1078,
+	0x35e4, 0x0040, 0x2bdb, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006,
+	0x2009, 0x0009, 0x00c0, 0x2bd7, 0x0c7e, 0x1078, 0x35ba, 0x0c7f,
+	0x2009, 0x0002, 0x0040, 0x2bd7, 0xad80, 0x000f, 0x2009, 0x0008,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3604, 0x701b, 0x3ab1,
+	0x007c, 0x0d7e, 0xade8, 0x000f, 0x6800, 0xa086, 0x0500, 0x00c0,
+	0x3ac4, 0x6804, 0xa005, 0x00c0, 0x3ac4, 0x6808, 0xa084, 0xff00,
+	0x00c0, 0x3ac4, 0x0078, 0x3ac7, 0x0d7f, 0x00c0, 0x2bdb, 0x0d7f,
+	0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x0c7e,
+	0x1078, 0x35e4, 0x00c0, 0x3ad7, 0x0c7f, 0x0078, 0x2bdb, 0x1078,
+	0x9119, 0x2009, 0x0003, 0x0c7f, 0x0040, 0x2bd7, 0x7007, 0x0003,
+	0x701b, 0x3ae3, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004,
+	0x0040, 0x2bd7, 0x0078, 0x2bad, 0x127e, 0x0c7e, 0x0e7e, 0x2061,
+	0x0100, 0x2071, 0xa600, 0x6044, 0xd0a4, 0x00c0, 0x3b15, 0xd084,
+	0x0040, 0x3afe, 0x1078, 0x3c75, 0x0078, 0x3b11, 0xd08c, 0x0040,
+	0x3b05, 0x1078, 0x3b8c, 0x0078, 0x3b11, 0xd094, 0x0040, 0x3b0c,
+	0x1078, 0x3b60, 0x0078, 0x3b11, 0xd09c, 0x0040, 0x3b11, 0x1078,
+	0x3b1f, 0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c,
+	0x00c0, 0x3b1c, 0xc19d, 0x612a, 0x017f, 0x0078, 0x3b11, 0x624c,
+	0xa286, 0xf0f0, 0x00c0, 0x3b30, 0x6048, 0xa086, 0xf0f0, 0x0040,
+	0x3b30, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x3b5f,
+	0xa294, 0xff00, 0xa296, 0xf700, 0x0040, 0x3b45, 0x7134, 0xd1a4,
+	0x00c0, 0x3b45, 0x6240, 0xa294, 0x0010, 0x0040, 0x3b45, 0x2009,
+	0x00f7, 0x1078, 0x42a1, 0x0078, 0x3b5f, 0x6043, 0x0040, 0x6043,
+	0x0000, 0x7077, 0x0000, 0x708f, 0x0001, 0x70b3, 0x0000, 0x70cf,
+	0x0000, 0x2009, 0xacc0, 0x200b, 0x0000, 0x7087, 0x0000, 0x707b,
+	0x000f, 0x2009, 0x000f, 0x2011, 0x41d5, 0x1078, 0x5add, 0x007c,
+	0x157e, 0x7078, 0xa005, 0x00c0, 0x3b8a, 0x2011, 0x41d5, 0x1078,
+	0x5a45, 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9,
+	0x00c8, 0x6044, 0xd08c, 0x00c0, 0x3b83, 0x00f0, 0x3b71, 0x6242,
+	0x708b, 0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042,
+	0x6242, 0x0078, 0x3b8a, 0x6242, 0x708b, 0x0000, 0x707f, 0x0000,
+	0x0078, 0x3b8a, 0x157f, 0x007c, 0x707c, 0xa08a, 0x0003, 0x00c8,
+	0x3b95, 0x1079, 0x3b98, 0x0078, 0x3b97, 0x1078, 0x1332, 0x007c,
+	0x3b9b, 0x3bea, 0x3c74, 0x0f7e, 0x707f, 0x0001, 0x20e1, 0xa000,
+	0x20e1, 0x8700, 0x1078, 0x21f7, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x2079, 0xab00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000,
+	0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000,
+	0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000,
+	0x782f, 0x0000, 0x2079, 0xab0c, 0x207b, 0x1101, 0x7807, 0x0000,
+	0x2099, 0xa605, 0x20a1, 0xab0e, 0x20a9, 0x0004, 0x53a3, 0x2079,
+	0xab12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xab00, 0x20a1,
+	0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000,
+	0x1078, 0x420b, 0x0f7f, 0x7083, 0x0000, 0x6043, 0x0008, 0x6043,
+	0x0000, 0x007c, 0x0d7e, 0x7080, 0x7083, 0x0000, 0xa025, 0x0040,
+	0x3c5e, 0x6020, 0xd0b4, 0x00c0, 0x3c5c, 0x718c, 0x81ff, 0x0040,
+	0x3c4b, 0xa486, 0x000c, 0x00c0, 0x3c56, 0xa480, 0x0018, 0x8004,
+	0x20a8, 0x2011, 0xab80, 0x2019, 0xab00, 0x220c, 0x2304, 0xa106,
+	0x00c0, 0x3c22, 0x8210, 0x8318, 0x00f0, 0x3c05, 0x6043, 0x0004,
+	0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707f, 0x0002,
+	0x708b, 0x0002, 0x2009, 0x07d0, 0x2011, 0x41dc, 0x1078, 0x5add,
+	0x0078, 0x3c5c, 0x2069, 0xab80, 0x6930, 0xa18e, 0x1101, 0x00c0,
+	0x3c56, 0x6834, 0xa005, 0x00c0, 0x3c56, 0x6900, 0xa18c, 0x00ff,
+	0x00c0, 0x3c36, 0x6804, 0xa005, 0x0040, 0x3c4b, 0x2011, 0xab8e,
+	0x2019, 0xa605, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0048,
+	0x3c49, 0x00c0, 0x3c56, 0x8210, 0x8318, 0x00f0, 0x3c3c, 0x0078,
+	0x3c56, 0x708f, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xab80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008,
+	0x6043, 0x0000, 0x0078, 0x3c5e, 0x0d7f, 0x007c, 0x6020, 0xd0b4,
+	0x00c0, 0x3c5c, 0x60c3, 0x000c, 0x2011, 0xa8bb, 0x2013, 0x0000,
+	0x7083, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575,
+	0x1078, 0x6e06, 0x0078, 0x3c5c, 0x007c, 0x7088, 0xa08a, 0x001d,
+	0x00c8, 0x3c7e, 0x1079, 0x3c81, 0x0078, 0x3c80, 0x1078, 0x1332,
+	0x007c, 0x3cab, 0x3cba, 0x3ce9, 0x3d02, 0x3d2e, 0x3d5a, 0x3d86,
+	0x3dbc, 0x3de8, 0x3e10, 0x3e53, 0x3e7d, 0x3e9f, 0x3eb5, 0x3edb,
+	0x3eee, 0x3ef7, 0x3f2b, 0x3f57, 0x3f83, 0x3faf, 0x3fe5, 0x4030,
+	0x405f, 0x4081, 0x40c3, 0x40e9, 0x4102, 0x4103, 0x0c7e, 0x2061,
+	0xa600, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9,
+	0x6006, 0x0c7f, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043,
+	0x0002, 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x41dc, 0x1078,
+	0x5add, 0x007c, 0x0f7e, 0x7080, 0xa086, 0x0014, 0x00c0, 0x3ce7,
+	0x6043, 0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3ce7, 0x2079, 0xab80,
+	0x7a30, 0xa296, 0x1102, 0x00c0, 0x3ce5, 0x7834, 0xa005, 0x00c0,
+	0x3ce5, 0x7a38, 0xd2fc, 0x0040, 0x3cdb, 0x70b0, 0xa005, 0x00c0,
+	0x3cdb, 0x70b3, 0x0001, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x708b,
+	0x0010, 0x1078, 0x3ef7, 0x0078, 0x3ce7, 0x1078, 0x4224, 0x0f7f,
+	0x007c, 0x708b, 0x0003, 0x6043, 0x0004, 0x2011, 0x41dc, 0x1078,
+	0x5a45, 0x1078, 0x4289, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9,
+	0x000a, 0x20a3, 0x0000, 0x00f0, 0x3cf9, 0x60c3, 0x0014, 0x1078,
+	0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3d2c, 0x2011,
+	0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3d2a, 0x2079,
+	0xab80, 0x7a30, 0xa296, 0x1102, 0x00c0, 0x3d2a, 0x7834, 0xa005,
+	0x00c0, 0x3d2a, 0x7a38, 0xd2fc, 0x0040, 0x3d24, 0x70b0, 0xa005,
+	0x00c0, 0x3d24, 0x70b3, 0x0001, 0x708b, 0x0004, 0x1078, 0x3d2e,
+	0x0078, 0x3d2c, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, 0x0005,
+	0x1078, 0x4289, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011,
+	0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3d4c, 0x7074, 0xa005, 0x00c0,
+	0x3d4c, 0x7150, 0xa186, 0xffff, 0x0040, 0x3d4c, 0x1078, 0x419d,
+	0x0040, 0x3d4c, 0x1078, 0x42b8, 0x20a9, 0x0008, 0x2298, 0x26a0,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078,
+	0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3d84, 0x2011,
+	0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3d82, 0x2079,
+	0xab80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3d82, 0x7834, 0xa005,
+	0x00c0, 0x3d82, 0x7a38, 0xd2fc, 0x0040, 0x3d7c, 0x70b0, 0xa005,
+	0x00c0, 0x3d7c, 0x70b3, 0x0001, 0x708b, 0x0006, 0x1078, 0x3d86,
+	0x0078, 0x3d84, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b, 0x0007,
+	0x1078, 0x4289, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011,
+	0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3dae, 0x7074, 0xa005, 0x00c0,
+	0x3dae, 0x7154, 0xa186, 0xffff, 0x0040, 0x3dae, 0xa180, 0x29c0,
+	0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x419d, 0x0040, 0x3dae,
+	0x1078, 0x3820, 0x0040, 0x3dae, 0x1078, 0x256a, 0x20a9, 0x0008,
+	0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040,
+	0x3de6, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0,
+	0x3de4, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3de4,
+	0x7834, 0xa005, 0x00c0, 0x3de4, 0x7a38, 0xd2fc, 0x0040, 0x3dde,
+	0x70b0, 0xa005, 0x00c0, 0x3dde, 0x70b3, 0x0001, 0x708b, 0x0008,
+	0x1078, 0x3de8, 0x0078, 0x3de6, 0x1078, 0x4224, 0x0f7f, 0x007c,
+	0x708b, 0x0009, 0x1078, 0x4289, 0x20a3, 0x1105, 0x20a3, 0x0100,
+	0x3430, 0x1078, 0x42d4, 0x00c0, 0x3e01, 0x7074, 0xa005, 0x00c0,
+	0x3e01, 0x1078, 0x4104, 0x00c0, 0x3e0b, 0xa085, 0x0001, 0x1078,
+	0x256a, 0x20a9, 0x0008, 0x2099, 0xab8e, 0x26a0, 0x53a6, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x420b, 0x007c,
+	0x0f7e, 0x7080, 0xa005, 0x0040, 0x3e51, 0x2011, 0x41dc, 0x1078,
+	0x5a45, 0xa086, 0x0014, 0x00c0, 0x3e4f, 0x2079, 0xab80, 0x7a30,
+	0xa296, 0x1105, 0x00c0, 0x3e4f, 0x7834, 0x2011, 0x0100, 0xa21e,
+	0x00c0, 0x3e3a, 0x7a38, 0xd2fc, 0x0040, 0x3e34, 0x70b0, 0xa005,
+	0x00c0, 0x3e34, 0x70b3, 0x0001, 0x708b, 0x000a, 0x1078, 0x3e53,
+	0x0078, 0x3e51, 0xa005, 0x00c0, 0x3e4f, 0x7a38, 0xd2fc, 0x0040,
+	0x3e47, 0x70b0, 0xa005, 0x00c0, 0x3e47, 0x70b3, 0x0001, 0x7087,
+	0x0000, 0x708b, 0x000e, 0x1078, 0x3edb, 0x0078, 0x3e51, 0x1078,
+	0x4224, 0x0f7f, 0x007c, 0x708b, 0x000b, 0x2011, 0xab0e, 0x22a0,
+	0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009,
+	0x0000, 0x41a4, 0x1078, 0x4289, 0x20a3, 0x1106, 0x20a3, 0x0000,
+	0x1078, 0x42d4, 0x0040, 0x3e70, 0x2013, 0x0000, 0x0078, 0x3e74,
+	0x6030, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6,
+	0x60c3, 0x0084, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005,
+	0x0040, 0x3e9d, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084,
+	0x00c0, 0x3e9b, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1106, 0x00c0,
+	0x3e9b, 0x7834, 0xa005, 0x00c0, 0x3e9b, 0x708b, 0x000c, 0x1078,
+	0x3e9f, 0x0078, 0x3e9d, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b,
+	0x000d, 0x1078, 0x4289, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099,
+	0xab8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0084, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005,
+	0x0040, 0x3ed9, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084,
+	0x00c0, 0x3ed7, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1107, 0x00c0,
+	0x3ed7, 0x7834, 0xa005, 0x00c0, 0x3ed7, 0x7087, 0x0001, 0x1078,
+	0x427b, 0x708b, 0x000e, 0x1078, 0x3edb, 0x0078, 0x3ed9, 0x1078,
+	0x4224, 0x0f7f, 0x007c, 0x708b, 0x000f, 0x7083, 0x0000, 0x608b,
+	0xbc85, 0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009,
+	0x07d0, 0x2011, 0x41dc, 0x1078, 0x5a38, 0x007c, 0x7080, 0xa005,
+	0x0040, 0x3ef6, 0x2011, 0x41dc, 0x1078, 0x5a45, 0x007c, 0x708b,
+	0x0011, 0x1078, 0x42d4, 0x00c0, 0x3f14, 0x716c, 0x81ff, 0x0040,
+	0x3f14, 0x2009, 0x0000, 0x7070, 0xa084, 0x00ff, 0x1078, 0x254d,
+	0xa186, 0x007e, 0x0040, 0x3f14, 0xa186, 0x0080, 0x0040, 0x3f14,
+	0x2011, 0xab8e, 0x1078, 0x419d, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x2099, 0xab80, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080,
+	0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014,
+	0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3f55,
+	0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3f53,
+	0x2079, 0xab80, 0x7a30, 0xa296, 0x1103, 0x00c0, 0x3f53, 0x7834,
+	0xa005, 0x00c0, 0x3f53, 0x7a38, 0xd2fc, 0x0040, 0x3f4d, 0x70b0,
+	0xa005, 0x00c0, 0x3f4d, 0x70b3, 0x0001, 0x708b, 0x0012, 0x1078,
+	0x3f57, 0x0078, 0x3f55, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b,
+	0x0013, 0x1078, 0x4295, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430,
+	0x2011, 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3f75, 0x7074, 0xa005,
+	0x00c0, 0x3f75, 0x7150, 0xa186, 0xffff, 0x0040, 0x3f75, 0x1078,
+	0x419d, 0x0040, 0x3f75, 0x1078, 0x42b8, 0x20a9, 0x0008, 0x2298,
+	0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x3fad,
+	0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014, 0x00c0, 0x3fab,
+	0x2079, 0xab80, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3fab, 0x7834,
+	0xa005, 0x00c0, 0x3fab, 0x7a38, 0xd2fc, 0x0040, 0x3fa5, 0x70b0,
+	0xa005, 0x00c0, 0x3fa5, 0x70b3, 0x0001, 0x708b, 0x0014, 0x1078,
+	0x3faf, 0x0078, 0x3fad, 0x1078, 0x4224, 0x0f7f, 0x007c, 0x708b,
+	0x0015, 0x1078, 0x4295, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430,
+	0x2011, 0xab8e, 0x1078, 0x42d4, 0x00c0, 0x3fd7, 0x7074, 0xa005,
+	0x00c0, 0x3fd7, 0x7154, 0xa186, 0xffff, 0x0040, 0x3fd7, 0xa180,
+	0x29c0, 0x200c, 0xa18c, 0xff00, 0x810f, 0x1078, 0x419d, 0x0040,
+	0x3fd7, 0x1078, 0x3820, 0x0040, 0x3fd7, 0x1078, 0x256a, 0x20a9,
+	0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005,
+	0x0040, 0x402e, 0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0014,
+	0x00c0, 0x402c, 0x2079, 0xab80, 0x7a30, 0xa296, 0x1105, 0x00c0,
+	0x402c, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0, 0x400b, 0x7a38,
+	0xd2fc, 0x0040, 0x4009, 0x70b0, 0xa005, 0x00c0, 0x4009, 0x70b3,
+	0x0001, 0x0078, 0x401a, 0xa005, 0x00c0, 0x402c, 0x7a38, 0xd2fc,
+	0x0040, 0x4018, 0x70b0, 0xa005, 0x00c0, 0x4018, 0x70b3, 0x0001,
+	0x7087, 0x0000, 0x7a38, 0xd2f4, 0x0040, 0x4026, 0x2001, 0xa674,
+	0x2004, 0xd0a4, 0x00c0, 0x4026, 0x70cf, 0x0008, 0x708b, 0x0016,
+	0x1078, 0x4030, 0x0078, 0x402e, 0x1078, 0x4224, 0x0f7f, 0x007c,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xab80, 0x20a1, 0x020b,
+	0x20a9, 0x000e, 0x53a6, 0x3430, 0x2011, 0xab8e, 0x708b, 0x0017,
+	0x1078, 0x42d4, 0x00c0, 0x4050, 0x7074, 0xa005, 0x00c0, 0x4050,
+	0x1078, 0x4104, 0x00c0, 0x405a, 0xa085, 0x0001, 0x1078, 0x256a,
+	0x20a9, 0x0008, 0x2099, 0xab8e, 0x26a0, 0x53a6, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x420b, 0x007c, 0x0f7e,
+	0x7080, 0xa005, 0x0040, 0x407f, 0x2011, 0x41dc, 0x1078, 0x5a45,
+	0xa086, 0x0084, 0x00c0, 0x407d, 0x2079, 0xab80, 0x7a30, 0xa296,
+	0x1106, 0x00c0, 0x407d, 0x7834, 0xa005, 0x00c0, 0x407d, 0x708b,
+	0x0018, 0x1078, 0x4081, 0x0078, 0x407f, 0x1078, 0x4224, 0x0f7f,
+	0x007c, 0x708b, 0x0019, 0x1078, 0x4295, 0x20a3, 0x1106, 0x20a3,
+	0x0000, 0x3430, 0x2099, 0xab8e, 0x2039, 0xab0e, 0x27a0, 0x20a9,
+	0x0040, 0x53a3, 0x1078, 0x42d4, 0x00c0, 0x40b5, 0x2728, 0x2514,
+	0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007,
+	0xa205, 0x202a, 0x6030, 0x2310, 0x8214, 0xa2a0, 0xab0e, 0x2414,
+	0xa38c, 0x0001, 0x0040, 0x40b0, 0xa294, 0xff00, 0x0078, 0x40b3,
+	0xa294, 0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9,
+	0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084,
+	0x1078, 0x420b, 0x007c, 0x0f7e, 0x7080, 0xa005, 0x0040, 0x40e7,
+	0x2011, 0x41dc, 0x1078, 0x5a45, 0xa086, 0x0084, 0x00c0, 0x40e5,
+	0x2079, 0xab80, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x40e5, 0x7834,
+	0xa005, 0x00c0, 0x40e5, 0x7087, 0x0001, 0x1078, 0x427b, 0x708b,
+	0x001a, 0x1078, 0x40e9, 0x0078, 0x40e7, 0x1078, 0x4224, 0x0f7f,
+	0x007c, 0x708b, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xab80, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007,
+	0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078,
+	0x420b, 0x007c, 0x007c, 0x007c, 0x087e, 0x097e, 0x2029, 0xa653,
+	0x252c, 0x20a9, 0x0008, 0x2041, 0xab0e, 0x28a0, 0x2099, 0xab8e,
+	0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0040, 0x411a,
+	0x2011, 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0,
+	0x412c, 0xd5d4, 0x0040, 0x4127, 0x8210, 0x0078, 0x4128, 0x8211,
+	0x00f0, 0x411a, 0x0078, 0x4194, 0x82ff, 0x00c0, 0x413e, 0xd5d4,
+	0x0040, 0x4138, 0xa1a6, 0x3fff, 0x0040, 0x4124, 0x0078, 0x413c,
+	0xa1a6, 0x3fff, 0x0040, 0x4194, 0xa18d, 0xc000, 0x20a9, 0x0010,
+	0x2019, 0x0001, 0xd5d4, 0x0040, 0x4147, 0x2019, 0x0010, 0x2120,
+	0xd5d4, 0x0040, 0x414e, 0x8423, 0x0078, 0x414f, 0x8424, 0x00c8,
+	0x415c, 0xd5d4, 0x0040, 0x4157, 0x8319, 0x0078, 0x4158, 0x8318,
+	0x00f0, 0x4148, 0x0078, 0x4194, 0x23a8, 0x2021, 0x0001, 0x8426,
+	0x8425, 0x00f0, 0x4160, 0x2328, 0x8529, 0xa2be, 0x0007, 0x0040,
+	0x4174, 0x007e, 0x2039, 0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8,
+	0xa5a8, 0x0010, 0x00f0, 0x4170, 0x7552, 0xa5c8, 0x29c0, 0x292c,
+	0xa5ac, 0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0000,
+	0x7572, 0x2018, 0x2304, 0xa405, 0x201a, 0x7077, 0x0001, 0x26a0,
+	0x2898, 0x20a9, 0x0008, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0xa085, 0x0001, 0x0078, 0x419a, 0xa006, 0x0078, 0x419a, 0xa006,
+	0x1078, 0x1332, 0x097f, 0x087f, 0x007c, 0x2118, 0x2021, 0x0000,
+	0x2001, 0x0007, 0xa39a, 0x0010, 0x0048, 0x41aa, 0x8420, 0x8001,
+	0x0078, 0x41a2, 0x2118, 0x84ff, 0x0040, 0x41b3, 0xa39a, 0x0010,
+	0x8421, 0x00c0, 0x41ae, 0x2021, 0x0001, 0x83ff, 0x0040, 0x41bc,
+	0x8423, 0x8319, 0x00c0, 0x41b8, 0xa238, 0x2704, 0xa42c, 0x00c0,
+	0x41d4, 0xa405, 0x203a, 0x7152, 0xa1a0, 0x29c0, 0x242c, 0xa5ac,
+	0x00ff, 0x6532, 0x60e7, 0x0000, 0x65ea, 0x706f, 0x0000, 0x7572,
+	0x7077, 0x0001, 0xa084, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa600,
+	0x707b, 0x0000, 0x0e7f, 0x007c, 0x0e7e, 0x0f7e, 0x2001, 0x0002,
+	0x1078, 0x5ae6, 0x2079, 0x0100, 0x2071, 0x0140, 0x1078, 0x6e0f,
+	0x7004, 0xa084, 0x4000, 0x0040, 0x41f1, 0x7003, 0x1000, 0x7003,
+	0x0000, 0x127e, 0x2091, 0x8000, 0x2071, 0xa622, 0x2073, 0x0000,
+	0x7840, 0x027e, 0x017e, 0x2009, 0x00f7, 0x1078, 0x42a1, 0x017f,
+	0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42, 0x027f, 0x127f,
+	0x0f7f, 0x0e7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x2011, 0xa8bb,
+	0x2013, 0x0000, 0x7083, 0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3,
+	0x0056, 0x60a7, 0x9575, 0x1078, 0x6e06, 0x2009, 0x07d0, 0x2011,
+	0x41dc, 0x1078, 0x5add, 0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e,
+	0x2091, 0x8000, 0x2011, 0x0003, 0x1078, 0x70e0, 0x2011, 0x0002,
+	0x1078, 0x70ea, 0x1078, 0x6fc4, 0x037e, 0x2019, 0x0000, 0x1078,
+	0x7058, 0x037f, 0x2009, 0x00f7, 0x1078, 0x42a1, 0x2061, 0xa8c4,
+	0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0xa600, 0x6003, 0x0001,
+	0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x002d,
+	0x2011, 0x4259, 0x1078, 0x5a38, 0x127f, 0x0c7f, 0x027f, 0x017f,
+	0x007c, 0x0e7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2001, 0x0001,
+	0x1078, 0x5ae6, 0x2071, 0x0100, 0x1078, 0x6e0f, 0x2071, 0x0140,
+	0x7004, 0xa084, 0x4000, 0x0040, 0x4271, 0x7003, 0x1000, 0x7003,
+	0x0000, 0x2001, 0x0001, 0x1078, 0x24e8, 0x1078, 0x4224, 0x127f,
+	0x007f, 0x0e7f, 0x007c, 0x20a9, 0x0040, 0x20a1, 0xacc0, 0x2099,
+	0xab8e, 0x3304, 0x8007, 0x20a2, 0x9398, 0x94a0, 0x00f0, 0x4281,
+	0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xab00, 0x20a1,
+	0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x2099, 0xab80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6,
+	0x007c, 0x0c7e, 0x007e, 0x2061, 0x0100, 0x810f, 0x2001, 0xa62f,
+	0x2004, 0xa005, 0x00c0, 0x42b2, 0x6030, 0xa084, 0x00ff, 0xa105,
+	0x0078, 0x42b4, 0xa185, 0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c,
+	0x017e, 0x047e, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x42cb,
+	0xa006, 0x2020, 0x2009, 0x002a, 0x1078, 0xa21d, 0x2001, 0xa60c,
+	0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0000, 0x1078,
+	0x284f, 0x047f, 0x017f, 0x007c, 0x007e, 0x2001, 0xa60c, 0x2004,
+	0xd09c, 0x0040, 0x42db, 0x007f, 0x007c, 0x007e, 0x017e, 0x127e,
+	0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d, 0x0006, 0x2102,
+	0x127f, 0x017f, 0x007f, 0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009,
+	0xa735, 0xa006, 0x200a, 0x8108, 0x00f0, 0x42f2, 0x157f, 0x007c,
+	0x0d7e, 0x037e, 0x157e, 0x137e, 0x147e, 0x2069, 0xa652, 0xa006,
+	0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012, 0xa198, 0x29c0,
+	0x231c, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004, 0xac98, 0x0006,
+	0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4,
+	0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a, 0x605e, 0x6062,
+	0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a, 0x607e, 0x6082,
+	0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a, 0x609e, 0x60ae,
+	0x61a2, 0x0d7e, 0x60a4, 0xa06d, 0x0040, 0x4338, 0x1078, 0x13a4,
+	0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0040, 0x4340, 0x1078, 0x13a4,
+	0x60ab, 0x0000, 0x0d7f, 0xa006, 0x604a, 0x6810, 0x603a, 0x680c,
+	0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x147f, 0x137f, 0x157f,
+	0x037f, 0x0d7f, 0x007c, 0x127e, 0x2091, 0x8000, 0x6944, 0x6e48,
+	0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, 0x4424, 0xa18c, 0xff00,
+	0x810f, 0xa182, 0x00ff, 0x00c8, 0x442a, 0x2001, 0xa60c, 0x2004,
+	0xa084, 0x0003, 0x0040, 0x4385, 0x2001, 0xa60c, 0x2004, 0xd084,
+	0x00c0, 0x4405, 0xa188, 0xa735, 0x2104, 0xa065, 0x0040, 0x4405,
+	0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x4405, 0x6000,
+	0xd0c4, 0x0040, 0x4405, 0x0078, 0x4392, 0xa188, 0xa735, 0x2104,
+	0xa065, 0x0040, 0x43e9, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006,
+	0x00c0, 0x43ef, 0x60a4, 0xa00d, 0x0040, 0x439a, 0x1078, 0x4817,
+	0x0040, 0x43e3, 0x60a8, 0xa00d, 0x0040, 0x43b4, 0x1078, 0x486a,
+	0x00c0, 0x43b4, 0x694c, 0xd1fc, 0x00c0, 0x43aa, 0x1078, 0x44df,
+	0x0078, 0x43de, 0x1078, 0x4484, 0x694c, 0xd1ec, 0x00c0, 0x43de,
+	0x1078, 0x46d6, 0x0078, 0x43de, 0x694c, 0xa184, 0xa000, 0x0040,
+	0x43ce, 0xd1ec, 0x0040, 0x43c7, 0xd1fc, 0x0040, 0x43c3, 0x1078,
+	0x46e7, 0x0078, 0x43ca, 0x1078, 0x46e7, 0x0078, 0x43ce, 0xd1fc,
+	0x0040, 0x43ce, 0x1078, 0x4484, 0x0078, 0x43de, 0x6050, 0xa00d,
+	0x0040, 0x43d9, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0078,
+	0x43de, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x1078, 0x5da9,
+	0xa006, 0x127f, 0x007c, 0x2001, 0x0005, 0x2009, 0x0000, 0x0078,
+	0x442e, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, 0x442e, 0xa082,
+	0x0006, 0x00c8, 0x4405, 0x60a0, 0xd0bc, 0x00c0, 0x4401, 0x6100,
+	0xd1fc, 0x0040, 0x4392, 0x2001, 0x0029, 0x2009, 0x1000, 0x0078,
+	0x442e, 0x2001, 0x0028, 0x0078, 0x4420, 0x2009, 0xa60c, 0x210c,
+	0xd18c, 0x0040, 0x440f, 0x2001, 0x0004, 0x0078, 0x4420, 0xd184,
+	0x0040, 0x4416, 0x2001, 0x0004, 0x0078, 0x4420, 0x2001, 0x0029,
+	0x6100, 0xd1fc, 0x0040, 0x4420, 0x2009, 0x1000, 0x0078, 0x442e,
+	0x2009, 0x0000, 0x0078, 0x442e, 0x2001, 0x0029, 0x2009, 0x0000,
+	0x0078, 0x442e, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x127f,
+	0x007c, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8,
+	0x447e, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x00c8, 0x4464,
+	0xa188, 0xa735, 0x2104, 0xa065, 0x0040, 0x4464, 0x6004, 0xa084,
+	0x00ff, 0xa08e, 0x0006, 0x00c0, 0x446a, 0x684c, 0xd0ec, 0x0040,
+	0x4457, 0x1078, 0x46e7, 0x1078, 0x4484, 0x0078, 0x445f, 0x1078,
+	0x4484, 0x684c, 0xd0fc, 0x0040, 0x445f, 0x1078, 0x46d6, 0x1078,
+	0x472f, 0xa006, 0x0078, 0x4482, 0x2001, 0x0028, 0x2009, 0x0000,
+	0x0078, 0x4482, 0xa082, 0x0006, 0x00c8, 0x4478, 0x6100, 0xd1fc,
+	0x0040, 0x444d, 0x2001, 0x0029, 0x2009, 0x1000, 0x0078, 0x4482,
+	0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x4482, 0x2001, 0x0029,
+	0x2009, 0x0000, 0xa005, 0x007c, 0x127e, 0x2091, 0x8000, 0x6050,
+	0xa00d, 0x0040, 0x4492, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052,
+	0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0078,
+	0x4490, 0x127e, 0x2091, 0x8000, 0x604c, 0xa005, 0x0040, 0x44af,
+	0x0e7e, 0x2071, 0xa8b1, 0x7004, 0xa086, 0x0002, 0x0040, 0x44b6,
+	0x0e7f, 0x604c, 0x6802, 0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00,
+	0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x44ad, 0x701c, 0xac06,
+	0x00c0, 0x44a8, 0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002,
+	0x0e7f, 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x604c, 0xa06d,
+	0x0040, 0x44d1, 0x6800, 0xa005, 0x00c0, 0x44cf, 0x6052, 0x604e,
+	0xad05, 0x127f, 0x007c, 0x604c, 0xa06d, 0x0040, 0x44de, 0x6800,
+	0xa005, 0x00c0, 0x44dc, 0x6052, 0x604e, 0xad05, 0x007c, 0x6803,
+	0x0000, 0x6084, 0xa00d, 0x0040, 0x44e9, 0x2d00, 0x200a, 0x6086,
+	0x007c, 0x2d00, 0x6086, 0x6082, 0x0078, 0x44e8, 0x127e, 0x0c7e,
+	0x027e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0040,
+	0x44fc, 0xc285, 0x0078, 0x44fd, 0xc284, 0x6202, 0x027f, 0x0c7f,
+	0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260,
+	0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, 0x4521, 0x609c, 0xd0ac,
+	0x0040, 0x4521, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x4521,
+	0xa284, 0xff00, 0x8007, 0xa086, 0x0007, 0x00c0, 0x4521, 0x2011,
+	0x0600, 0x007f, 0xa294, 0xff00, 0xa215, 0x6206, 0x007e, 0xa086,
+	0x0006, 0x00c0, 0x4531, 0x6290, 0x82ff, 0x00c0, 0x4531, 0x1078,
+	0x1332, 0x007f, 0x0c7f, 0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091,
+	0x8000, 0x6218, 0x2260, 0x6204, 0x007e, 0xa086, 0x0006, 0x00c0,
+	0x4553, 0x609c, 0xd0a4, 0x0040, 0x4553, 0x2001, 0xa653, 0x2004,
+	0xd0ac, 0x00c0, 0x4553, 0xa284, 0x00ff, 0xa086, 0x0007, 0x00c0,
+	0x4553, 0x2011, 0x0006, 0x007f, 0xa294, 0x00ff, 0x8007, 0xa215,
+	0x6206, 0x0c7f, 0x127f, 0x007c, 0x027e, 0xa182, 0x00ff, 0x0048,
+	0x4565, 0xa085, 0x0001, 0x0078, 0x457d, 0xa190, 0xa735, 0x2204,
+	0xa065, 0x00c0, 0x457c, 0x017e, 0x0d7e, 0x1078, 0x1370, 0x2d60,
+	0x0d7f, 0x017f, 0x0040, 0x4561, 0x2c00, 0x2012, 0x60a7, 0x0000,
+	0x60ab, 0x0000, 0x1078, 0x42f8, 0xa006, 0x027f, 0x007c, 0x127e,
+	0x2091, 0x8000, 0x027e, 0xa182, 0x00ff, 0x0048, 0x458b, 0xa085,
+	0x0001, 0x0078, 0x45c1, 0x0d7e, 0xa190, 0xa735, 0x2204, 0xa06d,
+	0x0040, 0x45bf, 0x2013, 0x0000, 0x0d7e, 0x0c7e, 0x2d60, 0x60a4,
+	0xa06d, 0x0040, 0x459d, 0x1078, 0x13a4, 0x60a8, 0xa06d, 0x0040,
+	0x45a3, 0x1078, 0x13a4, 0x0c7f, 0x0d7f, 0x0d7e, 0x0c7e, 0x68ac,
+	0x2060, 0x8cff, 0x0040, 0x45bb, 0x600c, 0x007e, 0x6010, 0x2068,
+	0x1078, 0x8d06, 0x0040, 0x45b6, 0x1078, 0x13b4, 0x1078, 0x772d,
+	0x0c7f, 0x0078, 0x45a9, 0x0c7f, 0x0d7f, 0x1078, 0x13a4, 0x0d7f,
+	0xa006, 0x027f, 0x127f, 0x007c, 0x017e, 0xa182, 0x00ff, 0x0048,
+	0x45cd, 0xa085, 0x0001, 0x0078, 0x45d4, 0xa188, 0xa735, 0x2104,
+	0xa065, 0x0040, 0x45c9, 0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e,
+	0x137e, 0x147e, 0x600b, 0x0000, 0x600f, 0x0000, 0x6000, 0xc08c,
+	0x6002, 0x2069, 0xab8e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138,
+	0xa10a, 0x0048, 0x45ec, 0x603a, 0x6814, 0x6066, 0x2099, 0xab96,
+	0xac88, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xab9a,
+	0xac88, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xabae,
+	0x6808, 0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076,
+	0x60a0, 0xa086, 0x007e, 0x00c0, 0x4611, 0x2069, 0xab8e, 0x690c,
+	0x616e, 0xa182, 0x0211, 0x00c8, 0x4619, 0x2009, 0x0008, 0x0078,
+	0x4643, 0xa182, 0x0259, 0x00c8, 0x4621, 0x2009, 0x0007, 0x0078,
+	0x4643, 0xa182, 0x02c1, 0x00c8, 0x4629, 0x2009, 0x0006, 0x0078,
+	0x4643, 0xa182, 0x0349, 0x00c8, 0x4631, 0x2009, 0x0005, 0x0078,
+	0x4643, 0xa182, 0x0421, 0x00c8, 0x4639, 0x2009, 0x0004, 0x0078,
+	0x4643, 0xa182, 0x0581, 0x00c8, 0x4641, 0x2009, 0x0003, 0x0078,
+	0x4643, 0x2009, 0x0002, 0x6192, 0x147f, 0x137f, 0x157f, 0x0d7f,
+	0x007c, 0x017e, 0x027e, 0x0e7e, 0x2071, 0xab8d, 0x2e04, 0x6896,
+	0x2071, 0xab8e, 0x7004, 0x689a, 0x701c, 0x689e, 0x6a00, 0x2009,
+	0xa672, 0x210c, 0xd0bc, 0x0040, 0x4663, 0xd1ec, 0x0040, 0x4663,
+	0xc2ad, 0x0078, 0x4664, 0xc2ac, 0xd0c4, 0x0040, 0x466d, 0xd1e4,
+	0x0040, 0x466d, 0xc2bd, 0x0078, 0x466e, 0xc2bc, 0x6a02, 0x0e7f,
+	0x027f, 0x017f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4,
+	0xa06d, 0x0040, 0x4697, 0x6900, 0x81ff, 0x00c0, 0x46ab, 0x6a04,
+	0xa282, 0x0010, 0x00c8, 0x46b0, 0xad88, 0x0004, 0x20a9, 0x0010,
+	0x2104, 0xa086, 0xffff, 0x0040, 0x4692, 0x8108, 0x00f0, 0x4688,
+	0x1078, 0x1332, 0x260a, 0x8210, 0x6a06, 0x0078, 0x46ab, 0x1078,
+	0x138b, 0x0040, 0x46b0, 0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88,
+	0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x00f0, 0x46a3,
+	0x6807, 0x0001, 0x6e12, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c,
+	0xa006, 0x0078, 0x46ad, 0x127e, 0x2091, 0x8000, 0x0d7e, 0x60a4,
+	0xa00d, 0x0040, 0x46d3, 0x2168, 0x6800, 0xa005, 0x00c0, 0x46cf,
+	0x1078, 0x4817, 0x00c0, 0x46d3, 0x200b, 0xffff, 0x6804, 0xa08a,
+	0x0002, 0x0048, 0x46cf, 0x8001, 0x6806, 0x0078, 0x46d3, 0x1078,
+	0x13a4, 0x60a7, 0x0000, 0x0d7f, 0x127f, 0x007c, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x487f, 0x0078, 0x46df, 0x1078, 0x4484, 0x1078,
+	0x4775, 0x00c0, 0x46dd, 0x1078, 0x472f, 0x127f, 0x007c, 0x0d7e,
+	0x127e, 0x2091, 0x8000, 0x60a8, 0xa06d, 0x0040, 0x470b, 0x6950,
+	0x81ff, 0x00c0, 0x471f, 0x6a54, 0xa282, 0x0010, 0x00c8, 0x472c,
+	0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0040,
+	0x4706, 0x8108, 0x00f0, 0x46fc, 0x1078, 0x1332, 0x260a, 0x8210,
+	0x6a56, 0x0078, 0x471f, 0x1078, 0x138b, 0x0040, 0x472c, 0x2d00,
+	0x60aa, 0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b,
+	0xffff, 0x8108, 0x00f0, 0x4717, 0x6857, 0x0001, 0x6e62, 0x0078,
+	0x4723, 0x1078, 0x44df, 0x1078, 0x4739, 0x00c0, 0x4721, 0xa085,
+	0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x4729, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x5da9, 0x127f, 0x007c, 0xa01e, 0x0078,
+	0x473b, 0x2019, 0x0001, 0xa00e, 0x127e, 0x2091, 0x8000, 0x604c,
+	0x2068, 0x6000, 0xd0dc, 0x00c0, 0x4759, 0x8dff, 0x0040, 0x4770,
+	0x83ff, 0x0040, 0x4751, 0x6848, 0xa606, 0x0040, 0x475e, 0x0078,
+	0x4759, 0x683c, 0xa406, 0x00c0, 0x4759, 0x6840, 0xa506, 0x0040,
+	0x475e, 0x2d08, 0x6800, 0x2068, 0x0078, 0x4745, 0x1078, 0x7233,
+	0x6a00, 0x604c, 0xad06, 0x00c0, 0x4768, 0x624e, 0x0078, 0x476b,
+	0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x4770, 0x6152, 0x8dff,
+	0x127f, 0x007c, 0xa01e, 0x0078, 0x4777, 0x2019, 0x0001, 0xa00e,
+	0x6080, 0x2068, 0x8dff, 0x0040, 0x47a3, 0x83ff, 0x0040, 0x4786,
+	0x6848, 0xa606, 0x0040, 0x4793, 0x0078, 0x478e, 0x683c, 0xa406,
+	0x00c0, 0x478e, 0x6840, 0xa506, 0x0040, 0x4793, 0x2d08, 0x6800,
+	0x2068, 0x0078, 0x477a, 0x6a00, 0x6080, 0xad06, 0x00c0, 0x479b,
+	0x6282, 0x0078, 0x479e, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0,
+	0x47a3, 0x6186, 0x8dff, 0x007c, 0xa016, 0x1078, 0x4810, 0x00c0,
+	0x47ab, 0x2011, 0x0001, 0x1078, 0x4863, 0x00c0, 0x47b1, 0xa295,
+	0x0002, 0x007c, 0x1078, 0x489b, 0x0040, 0x47ba, 0x1078, 0x8dca,
+	0x0078, 0x47bc, 0xa085, 0x0001, 0x007c, 0x1078, 0x489b, 0x0040,
+	0x47c5, 0x1078, 0x8d62, 0x0078, 0x47c7, 0xa085, 0x0001, 0x007c,
+	0x1078, 0x489b, 0x0040, 0x47d0, 0x1078, 0x8dac, 0x0078, 0x47d2,
+	0xa085, 0x0001, 0x007c, 0x1078, 0x489b, 0x0040, 0x47db, 0x1078,
+	0x8d7e, 0x0078, 0x47dd, 0xa085, 0x0001, 0x007c, 0x1078, 0x489b,
+	0x0040, 0x47e6, 0x1078, 0x8de8, 0x0078, 0x47e8, 0xa085, 0x0001,
+	0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x8000, 0x6080, 0xa06d,
+	0x0040, 0x4808, 0x6800, 0x007e, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x1078, 0x8f7d, 0x007e, 0x6000, 0xd0fc, 0x0040, 0x4802,
+	0x1078, 0xa4ed, 0x007f, 0x1078, 0x4a73, 0x007f, 0x0078, 0x47ef,
+	0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f, 0x127f, 0x007c,
+	0x60a4, 0xa00d, 0x00c0, 0x4817, 0xa085, 0x0001, 0x007c, 0x0e7e,
+	0x2170, 0x7000, 0xa005, 0x00c0, 0x482c, 0x20a9, 0x0010, 0xae88,
+	0x0004, 0x2104, 0xa606, 0x0040, 0x482c, 0x8108, 0x00f0, 0x4821,
+	0xa085, 0x0001, 0x0078, 0x482d, 0xa006, 0x0e7f, 0x007c, 0x0d7e,
+	0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x00c0, 0x483d, 0x1078,
+	0x138b, 0x0040, 0x484f, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807,
+	0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108,
+	0x00f0, 0x4845, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006,
+	0x0078, 0x484c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d,
+	0x0040, 0x4860, 0x60a7, 0x0000, 0x1078, 0x13a4, 0xa085, 0x0001,
+	0x127f, 0x0d7f, 0x007c, 0x60a8, 0xa00d, 0x00c0, 0x486a, 0xa085,
+	0x0001, 0x007c, 0x0e7e, 0x2170, 0x7050, 0xa005, 0x00c0, 0x487d,
+	0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0040, 0x487d,
+	0x8108, 0x00f0, 0x4874, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x4863, 0x00c0, 0x4899, 0x200b, 0xffff,
+	0x0d7e, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0048, 0x4894,
+	0x8001, 0x6856, 0x0078, 0x4898, 0x1078, 0x13a4, 0x60ab, 0x0000,
+	0x0d7f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, 0x71b0,
+	0x81ff, 0x00c0, 0x48b9, 0x71cc, 0xd19c, 0x0040, 0x48b9, 0x2001,
+	0x007e, 0xa080, 0xa735, 0x2004, 0xa07d, 0x0040, 0x48b9, 0x7804,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x48b9, 0x7800, 0xc0ed,
+	0x7802, 0x2079, 0xa652, 0x7804, 0xd0a4, 0x0040, 0x48df, 0x157e,
+	0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x45c4,
+	0x00c0, 0x48d9, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004,
+	0x0040, 0x48d6, 0xa086, 0x0006, 0x00c0, 0x48d9, 0x6000, 0xc0ed,
+	0x6002, 0x017f, 0x8108, 0x00f0, 0x48c5, 0x0c7f, 0x157f, 0x1078,
+	0x4967, 0x0040, 0x48e8, 0x2001, 0xa8a1, 0x200c, 0x0078, 0x48f0,
+	0x2079, 0xa652, 0x7804, 0xd0a4, 0x0040, 0x48f4, 0x2009, 0x07d0,
+	0x2011, 0x48f6, 0x1078, 0x5add, 0x0f7f, 0x007c, 0x2011, 0x48f6,
+	0x1078, 0x5a45, 0x1078, 0x4967, 0x0040, 0x491e, 0x2001, 0xa7b3,
+	0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xa653,
+	0x2004, 0xd0a4, 0x0040, 0x4912, 0x2009, 0x07d0, 0x2011, 0x48f6,
+	0x1078, 0x5add, 0x0e7e, 0x2071, 0xa600, 0x706f, 0x0000, 0x7073,
+	0x0000, 0x1078, 0x2677, 0x0e7f, 0x0078, 0x4956, 0x157e, 0x0c7e,
+	0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x45c4, 0x00c0,
+	0x4950, 0x6000, 0xd0ec, 0x0040, 0x4950, 0x047e, 0x62a0, 0xa294,
+	0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0xa21d, 0x6000,
+	0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700,
+	0x6006, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e, 0x2039, 0x0000,
+	0x1078, 0x5e0a, 0x2009, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x047f,
+	0x017f, 0x8108, 0x00f0, 0x4924, 0x0c7f, 0x157f, 0x007c, 0x0c7e,
+	0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x7818,
+	0x2004, 0xd0ac, 0x007c, 0x7818, 0x2004, 0xd0bc, 0x007c, 0x0f7e,
+	0x2001, 0xa7b3, 0x2004, 0xa07d, 0x0040, 0x4970, 0x7800, 0xd0ec,
+	0x0f7f, 0x007c, 0x127e, 0x027e, 0x2091, 0x8000, 0x007e, 0x62a0,
+	0xa290, 0xa735, 0x2204, 0xac06, 0x10c0, 0x1332, 0x007f, 0x6200,
+	0xa005, 0x0040, 0x4986, 0xc2fd, 0x0078, 0x4987, 0xc2fc, 0x6202,
+	0x027f, 0x127f, 0x007c, 0x2011, 0xa633, 0x2204, 0xd0cc, 0x0040,
+	0x4998, 0x2001, 0xa89f, 0x200c, 0x2011, 0x4999, 0x1078, 0x5add,
+	0x007c, 0x2011, 0x4999, 0x1078, 0x5a45, 0x2011, 0xa633, 0x2204,
+	0xc0cc, 0x2012, 0x007c, 0x2071, 0xa714, 0x7003, 0x0001, 0x7007,
+	0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f,
+	0x0000, 0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b,
+	0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xa87d, 0x7003,
+	0xa714, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xa85d, 0x7013,
+	0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x007c, 0x017e, 0x0e7e,
+	0x2071, 0xa835, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001,
+	0xa653, 0x2004, 0xd0fc, 0x00c0, 0x49e8, 0x2001, 0xa653, 0x2004,
+	0xa00e, 0xd09c, 0x0040, 0x49e5, 0x8108, 0x7102, 0x0078, 0x4a3b,
+	0x2001, 0xa672, 0x200c, 0xa184, 0x000f, 0x2009, 0xa673, 0x210c,
+	0x0079, 0x49f2, 0x49dd, 0x4a13, 0x4a1b, 0x4a26, 0x4a2c, 0x49dd,
+	0x49dd, 0x49dd, 0x4a02, 0x49dd, 0x49dd, 0x49dd, 0x49dd, 0x49dd,
+	0x49dd, 0x49dd, 0x7003, 0x0004, 0x137e, 0x147e, 0x157e, 0x2099,
+	0xa676, 0x20a1, 0xa886, 0x20a9, 0x0004, 0x53a3, 0x157f, 0x147f,
+	0x137f, 0x0078, 0x4a3b, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001,
+	0x0002, 0x0078, 0x4a21, 0x708f, 0x0002, 0x7007, 0x0121, 0x2001,
+	0x0003, 0x7002, 0x7097, 0x0001, 0x0078, 0x4a38, 0x7007, 0x0122,
+	0x2001, 0x0002, 0x0078, 0x4a30, 0x7007, 0x0121, 0x2001, 0x0003,
+	0x7002, 0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a,
+	0xa184, 0x00ff, 0x7092, 0x0e7f, 0x017f, 0x007c, 0x0e7e, 0x2071,
+	0xa714, 0x684c, 0xa005, 0x00c0, 0x4a4c, 0x7028, 0xc085, 0x702a,
+	0xa085, 0x0001, 0x0078, 0x4a71, 0x6a60, 0x7236, 0x6b64, 0x733a,
+	0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e,
+	0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007,
+	0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100,
+	0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001,
+	0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x027e, 0x6838, 0xd0fc, 0x00c0,
+	0x4ac9, 0x6804, 0xa00d, 0x0040, 0x4a8f, 0x0d7e, 0x2071, 0xa600,
+	0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff,
+	0x00c0, 0x4a82, 0x702e, 0x70ac, 0xa200, 0x70ae, 0x0d7f, 0x2071,
+	0xa714, 0x701c, 0xa005, 0x00c0, 0x4adb, 0x0068, 0x4ad9, 0x2071,
+	0xa835, 0x7200, 0x82ff, 0x0040, 0x4ad9, 0x6934, 0xa186, 0x0103,
+	0x00c0, 0x4aec, 0x6948, 0x6844, 0xa105, 0x00c0, 0x4acc, 0x2009,
+	0x8020, 0x2200, 0x0079, 0x4aac, 0x4ad9, 0x4ab1, 0x4b09, 0x4b17,
+	0x4ad9, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4ad9, 0x7122,
+	0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x2071, 0xa600, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70ac, 0x8000,
+	0x70ae, 0x027f, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0,
+	0x4ad9, 0x6868, 0xa005, 0x00c0, 0x4ad9, 0x2009, 0x8020, 0x0078,
+	0x4aa9, 0x2071, 0xa714, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000,
+	0x7012, 0x7018, 0xa06d, 0x711a, 0x0040, 0x4ae9, 0x6902, 0x0078,
+	0x4aea, 0x711e, 0x0078, 0x4ac9, 0xa18c, 0x00ff, 0xa186, 0x0017,
+	0x0040, 0x4afa, 0xa186, 0x001e, 0x0040, 0x4afa, 0xa18e, 0x001f,
+	0x00c0, 0x4ad9, 0x684c, 0xd0cc, 0x0040, 0x4ad9, 0x6850, 0xa084,
+	0x00ff, 0xa086, 0x0001, 0x00c0, 0x4ad9, 0x2009, 0x8021, 0x0078,
+	0x4aa9, 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4ad9, 0x7186,
+	0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x4b27, 0x7084,
+	0x8008, 0xa092, 0x000f, 0x00c8, 0x4ad9, 0x7186, 0xae90, 0x0003,
+	0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088,
+	0xa10a, 0x0048, 0x4ac0, 0x718c, 0x7084, 0xa10a, 0x0048, 0x4ac0,
+	0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4ac0, 0x2071, 0xa835,
+	0x7000, 0xa086, 0x0002, 0x00c0, 0x4b47, 0x1078, 0x4dc3, 0x2071,
+	0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4ac0, 0x1078,
+	0x4dee, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078,
+	0x4ac0, 0x007e, 0x684c, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c,
+	0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0xa084,
+	0x00ff, 0x684e, 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0xa714,
+	0x7004, 0x0079, 0x4b6b, 0x4b75, 0x4b86, 0x4d94, 0x4d95, 0x4dbc,
+	0x4dc2, 0x4b76, 0x4d82, 0x4d23, 0x4da5, 0x007c, 0x127e, 0x2091,
+	0x8000, 0x0068, 0x4b85, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091,
+	0x4080, 0x7007, 0x0001, 0x700b, 0x0000, 0x127f, 0x2069, 0xa8c4,
+	0x6844, 0xa005, 0x0050, 0x4bae, 0x00c0, 0x4bae, 0x127e, 0x2091,
+	0x8000, 0x2069, 0x0000, 0x6934, 0x2001, 0xa720, 0x2004, 0xa10a,
+	0x0040, 0x4ba9, 0x0068, 0x4bad, 0x2069, 0x0000, 0x6818, 0xd084,
+	0x00c0, 0x4bad, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091,
+	0x4080, 0x2069, 0xa8c4, 0x6847, 0xffff, 0x127f, 0x2069, 0xa600,
+	0x6848, 0x6964, 0xa102, 0x2069, 0xa835, 0x688a, 0x6984, 0x701c,
+	0xa06d, 0x0040, 0x4bc0, 0x81ff, 0x0040, 0x4c08, 0x0078, 0x4bd6,
+	0x81ff, 0x0040, 0x4cda, 0x2071, 0xa835, 0x7184, 0x7088, 0xa10a,
+	0x00c8, 0x4bd6, 0x7190, 0x2071, 0xa8c4, 0x7040, 0xa005, 0x0040,
+	0x4bd6, 0x00d0, 0x4cda, 0x7142, 0x0078, 0x4cda, 0x2071, 0xa835,
+	0x718c, 0x127e, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0048, 0x4cf7,
+	0x0068, 0x4c8c, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4c8c,
+	0x2001, 0xffff, 0x2071, 0xa8c4, 0x7042, 0x2071, 0xa835, 0x7000,
+	0xa086, 0x0002, 0x00c0, 0x4bfe, 0x1078, 0x4dc3, 0x2071, 0x0000,
+	0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4c8c, 0x1078, 0x4dee,
+	0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4c8c,
+	0x2071, 0xa835, 0x7000, 0xa005, 0x0040, 0x4cb9, 0x6934, 0xa186,
+	0x0103, 0x00c0, 0x4c8f, 0x684c, 0xd0bc, 0x00c0, 0x4cb9, 0x6948,
+	0x6844, 0xa105, 0x00c0, 0x4cac, 0x2009, 0x8020, 0x2071, 0xa835,
+	0x7000, 0x0079, 0x4c23, 0x4cb9, 0x4c71, 0x4c49, 0x4c5b, 0x4c28,
+	0x137e, 0x147e, 0x157e, 0x2099, 0xa676, 0x20a1, 0xa886, 0x20a9,
+	0x0004, 0x53a3, 0x157f, 0x147f, 0x137f, 0x2071, 0xa87d, 0xad80,
+	0x000f, 0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000,
+	0x2e10, 0x1078, 0x13db, 0x2071, 0xa714, 0x7007, 0x0009, 0x0078,
+	0x4cda, 0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4cda, 0xae90,
+	0x0003, 0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xa714, 0x1078,
+	0x4e4c, 0x0078, 0x4cda, 0x7084, 0x8008, 0xa092, 0x000f, 0x00c8,
+	0x4cda, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210,
+	0x6840, 0x2012, 0x7186, 0x2071, 0xa714, 0x1078, 0x4e4c, 0x0078,
+	0x4cda, 0x127e, 0x2091, 0x8000, 0x0068, 0x4c8c, 0x2071, 0x0000,
+	0x7018, 0xd084, 0x00c0, 0x4c8c, 0x7122, 0x683c, 0x7026, 0x6840,
+	0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x127f, 0x2071, 0xa714,
+	0x1078, 0x4e4c, 0x0078, 0x4cda, 0x127f, 0x0078, 0x4cda, 0xa18c,
+	0x00ff, 0xa186, 0x0017, 0x0040, 0x4c9d, 0xa186, 0x001e, 0x0040,
+	0x4c9d, 0xa18e, 0x001f, 0x00c0, 0x4cb9, 0x684c, 0xd0cc, 0x0040,
+	0x4cb9, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4cb9,
+	0x2009, 0x8021, 0x0078, 0x4c1e, 0x6844, 0xa086, 0x0100, 0x00c0,
+	0x4cb9, 0x6868, 0xa005, 0x00c0, 0x4cb9, 0x2009, 0x8020, 0x0078,
+	0x4c1e, 0x2071, 0xa714, 0x1078, 0x4e60, 0x0040, 0x4cda, 0x2071,
+	0xa714, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003,
+	0x00c0, 0x4cd1, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x4cd1,
+	0x710e, 0x7007, 0x0003, 0x1078, 0x4e80, 0x7050, 0xa086, 0x0100,
+	0x0040, 0x4d95, 0x127e, 0x2091, 0x8000, 0x2071, 0xa714, 0x7008,
+	0xa086, 0x0001, 0x00c0, 0x4cf5, 0x0068, 0x4cf5, 0x2009, 0x000d,
+	0x7030, 0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086,
+	0x0006, 0x00c0, 0x4cf5, 0x7007, 0x0001, 0x127f, 0x007c, 0x2071,
+	0xa714, 0x1078, 0x4e60, 0x0040, 0x4d20, 0x2071, 0xa835, 0x7084,
+	0x700a, 0x20a9, 0x0020, 0x2099, 0xa836, 0x20a1, 0xa85d, 0x53a3,
+	0x7087, 0x0000, 0x2071, 0xa714, 0x2069, 0xa87d, 0x706c, 0x6826,
+	0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x1078,
+	0x13db, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xa8c4, 0x7042,
+	0x127f, 0x0078, 0x4cda, 0x2069, 0xa87d, 0x6808, 0xa08e, 0x0000,
+	0x0040, 0x4d81, 0xa08e, 0x0200, 0x0040, 0x4d7f, 0xa08e, 0x0100,
+	0x00c0, 0x4d81, 0x127e, 0x2091, 0x8000, 0x0068, 0x4d7c, 0x2069,
+	0x0000, 0x6818, 0xd084, 0x00c0, 0x4d7c, 0x702c, 0x7130, 0x8108,
+	0xa102, 0x0048, 0x4d4a, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072,
+	0x0078, 0x4d54, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4d54,
+	0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000,
+	0x2001, 0xa85a, 0x2004, 0xa005, 0x00c0, 0x4d73, 0x6934, 0x2069,
+	0xa835, 0x689c, 0x699e, 0x2069, 0xa8c4, 0xa102, 0x00c0, 0x4d6c,
+	0x6844, 0xa005, 0x00d0, 0x4d7a, 0x2001, 0xa85b, 0x200c, 0x810d,
+	0x6946, 0x0078, 0x4d7a, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001,
+	0x2091, 0x4080, 0x7007, 0x0001, 0x127f, 0x0078, 0x4d81, 0x7007,
+	0x0005, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4d93, 0x1078, 0x4e60,
+	0x0040, 0x4d93, 0x7007, 0x0003, 0x1078, 0x4e80, 0x7050, 0xa086,
+	0x0100, 0x0040, 0x4d95, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100,
+	0x00c0, 0x4d9e, 0x7007, 0x0004, 0x0078, 0x4dbc, 0xa086, 0x0200,
+	0x00c0, 0x4da4, 0x7007, 0x0005, 0x007c, 0x2001, 0xa87f, 0x2004,
+	0xa08e, 0x0100, 0x00c0, 0x4db1, 0x7007, 0x0001, 0x1078, 0x4e4c,
+	0x007c, 0xa08e, 0x0000, 0x0040, 0x4db0, 0xa08e, 0x0200, 0x00c0,
+	0x4db0, 0x7007, 0x0005, 0x007c, 0x1078, 0x4e16, 0x7006, 0x1078,
+	0x4e4c, 0x007c, 0x007c, 0x0e7e, 0x157e, 0x2071, 0xa835, 0x7184,
+	0x81ff, 0x0040, 0x4deb, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071,
+	0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x0070, 0x4de8, 0x2014,
+	0x722a, 0x8000, 0x0070, 0x4de8, 0x2014, 0x722e, 0x8000, 0x0070,
+	0x4de8, 0x2014, 0x723a, 0x8000, 0x0070, 0x4de8, 0x2014, 0x723e,
+	0xa180, 0x8030, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x0e7e, 0x157e,
+	0x2071, 0xa835, 0x7184, 0x81ff, 0x0040, 0x4e13, 0xa006, 0x7086,
+	0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000,
+	0x2014, 0x722a, 0x8000, 0x0070, 0x4e0c, 0x2014, 0x723a, 0x8000,
+	0x2014, 0x723e, 0x0078, 0x4e10, 0x2001, 0x8020, 0x0078, 0x4e12,
+	0x2001, 0x8042, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x702c, 0x7130,
+	0x8108, 0xa102, 0x0048, 0x4e23, 0xa00e, 0x7034, 0x706e, 0x7038,
+	0x7072, 0x0078, 0x4e2d, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8,
+	0x4e2d, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001,
+	0x700e, 0x00c0, 0x4e43, 0x127e, 0x2091, 0x8000, 0x0068, 0x4e46,
+	0x2001, 0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b,
+	0x0000, 0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006,
+	0x700b, 0x0001, 0x127f, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4e5f,
+	0x127e, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e,
+	0xa005, 0x00c0, 0x4e5c, 0x701a, 0x127f, 0x1078, 0x13a4, 0x007c,
+	0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, 0x4e6f, 0x2304,
+	0x230c, 0xa10e, 0x0040, 0x4e6f, 0xa006, 0x0078, 0x4e7f, 0x732c,
+	0x8319, 0x7130, 0xa102, 0x00c0, 0x4e79, 0x2300, 0xa005, 0x0078,
+	0x4e7f, 0x0048, 0x4e7e, 0xa302, 0x0078, 0x4e7f, 0x8002, 0x007c,
+	0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e,
+	0x2091, 0x8000, 0x2009, 0xa8d6, 0x2104, 0xc08d, 0x200a, 0x127f,
+	0x1078, 0x13f9, 0x007c, 0x2071, 0xa6e2, 0x7003, 0x0000, 0x7007,
+	0x0000, 0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053,
+	0x0001, 0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b,
+	0x0000, 0x708f, 0x0001, 0x70bf, 0x0000, 0x007c, 0x0e7e, 0x2071,
+	0xa6e2, 0x6848, 0xa005, 0x00c0, 0x4ebc, 0x7028, 0xc085, 0x702a,
+	0xa085, 0x0001, 0x0078, 0x4ee1, 0x6a50, 0x7236, 0x6b54, 0x733a,
+	0x6858, 0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e,
+	0x6840, 0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006,
+	0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272,
+	0x7376, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000,
+	0xa006, 0x0e7f, 0x007c, 0x2b78, 0x2071, 0xa6e2, 0x7004, 0x1079,
+	0x4f41, 0x700c, 0x0079, 0x4eec, 0x4ef1, 0x4ee6, 0x4ee6, 0x4ee6,
+	0x4ee6, 0x007c, 0x700c, 0x0079, 0x4ef5, 0x4efa, 0x4f3f, 0x4f3f,
+	0x4f40, 0x4f40, 0x7830, 0x7930, 0xa106, 0x0040, 0x4f04, 0x7830,
+	0x7930, 0xa106, 0x00c0, 0x4f2a, 0x7030, 0xa10a, 0x0040, 0x4f2a,
+	0x00c8, 0x4f0c, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x00c8, 0x4f2b,
+	0x1078, 0x1370, 0x0040, 0x4f2a, 0x2d00, 0x705a, 0x7063, 0x0040,
+	0x2001, 0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000,
+	0x2009, 0xa8d6, 0x2104, 0xc085, 0x200a, 0x007f, 0x700e, 0x127f,
+	0x1078, 0x13f9, 0x007c, 0x1078, 0x1370, 0x0040, 0x4f2a, 0x2d00,
+	0x705a, 0x1078, 0x1370, 0x00c0, 0x4f37, 0x0078, 0x4f16, 0x2d00,
+	0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x0078, 0x4f1a, 0x007c,
+	0x007c, 0x4f52, 0x4f53, 0x4f8a, 0x4f8b, 0x4f3f, 0x4fc1, 0x4fc6,
+	0x4ffd, 0x4ffe, 0x5019, 0x501a, 0x501b, 0x501c, 0x501d, 0x501e,
+	0x509e, 0x50c8, 0x007c, 0x700c, 0x0079, 0x4f56, 0x4f5b, 0x4f5e,
+	0x4f6e, 0x4f89, 0x4f89, 0x1078, 0x4ef2, 0x007c, 0x127e, 0x8001,
+	0x700e, 0x7058, 0x007e, 0x1078, 0x5464, 0x0040, 0x4f6b, 0x2091,
+	0x8000, 0x1078, 0x4ef2, 0x0d7f, 0x0078, 0x4f77, 0x127e, 0x8001,
+	0x700e, 0x1078, 0x5464, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803,
+	0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020,
+	0x00c8, 0x4f86, 0x1079, 0x4fa1, 0x127f, 0x007c, 0x127f, 0x1078,
+	0x501f, 0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, 0xa6e2, 0x700c,
+	0x0079, 0x4f92, 0x4f97, 0x4f97, 0x4f97, 0x4f99, 0x4f9d, 0x0e7f,
+	0x007c, 0x700f, 0x0001, 0x0078, 0x4f9f, 0x700f, 0x0002, 0x0e7f,
+	0x007c, 0x501f, 0x501f, 0x503b, 0x501f, 0x5171, 0x501f, 0x501f,
+	0x501f, 0x501f, 0x501f, 0x503b, 0x51bb, 0x5208, 0x5261, 0x5277,
+	0x501f, 0x501f, 0x5057, 0x503b, 0x501f, 0x501f, 0x5078, 0x5338,
+	0x5356, 0x501f, 0x5057, 0x501f, 0x501f, 0x501f, 0x501f, 0x506d,
+	0x5356, 0x7020, 0x2068, 0x1078, 0x13a4, 0x007c, 0x700c, 0x0079,
+	0x4fc9, 0x4fce, 0x4fd1, 0x4fe1, 0x4ffc, 0x4ffc, 0x1078, 0x4ef2,
+	0x007c, 0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x5464,
+	0x0040, 0x4fde, 0x2091, 0x8000, 0x1078, 0x4ef2, 0x0d7f, 0x0078,
+	0x4fea, 0x127e, 0x8001, 0x700e, 0x1078, 0x5464, 0x7058, 0x2068,
+	0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084,
+	0x00ff, 0xa08a, 0x001a, 0x00c8, 0x4ff9, 0x1079, 0x4fff, 0x127f,
+	0x007c, 0x127f, 0x1078, 0x501f, 0x007c, 0x007c, 0x007c, 0x501f,
+	0x503b, 0x515b, 0x501f, 0x503b, 0x501f, 0x503b, 0x503b, 0x501f,
+	0x503b, 0x515b, 0x503b, 0x503b, 0x503b, 0x503b, 0x503b, 0x501f,
+	0x503b, 0x515b, 0x501f, 0x501f, 0x503b, 0x501f, 0x501f, 0x501f,
+	0x503b, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007,
+	0x0001, 0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x4a73, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838,
+	0xa084, 0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x4a73, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff,
+	0xc0ed, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4a73, 0x127f,
+	0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x4a73, 0x127f, 0x007c, 0x6834,
+	0x8007, 0xa084, 0x00ff, 0x0040, 0x502d, 0x8001, 0x00c0, 0x5064,
+	0x7007, 0x0001, 0x0078, 0x513a, 0x7007, 0x0006, 0x7012, 0x2d00,
+	0x7016, 0x701a, 0x704b, 0x513a, 0x007c, 0x684c, 0xa084, 0x00c0,
+	0xa086, 0x00c0, 0x00c0, 0x5078, 0x7007, 0x0001, 0x0078, 0x5373,
+	0x2d00, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098,
+	0x20a1, 0xa70d, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8,
+	0x5049, 0x6884, 0xa08a, 0x0002, 0x00c8, 0x5049, 0x82ff, 0x00c0,
+	0x509a, 0x6888, 0x698c, 0xa105, 0x0040, 0x509a, 0x2001, 0x510a,
+	0x0078, 0x509d, 0xa280, 0x5100, 0x2004, 0x70c6, 0x7010, 0xa015,
+	0x0040, 0x50e8, 0x1078, 0x1370, 0x00c0, 0x50a9, 0x7007, 0x000f,
+	0x007c, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004,
+	0xad00, 0x7096, 0x6008, 0xa20a, 0x00c8, 0x50b8, 0xa00e, 0x2200,
+	0x7112, 0x620c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0040, 0x50c1,
+	0xa108, 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x1078, 0x13db,
+	0x7090, 0xa08e, 0x0100, 0x0040, 0x50dc, 0xa086, 0x0200, 0x0040,
+	0x50d4, 0x7007, 0x0010, 0x007c, 0x7020, 0x2068, 0x1078, 0x13a4,
+	0x7014, 0x2068, 0x0078, 0x5049, 0x7020, 0x2068, 0x7018, 0x6802,
+	0x6807, 0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0078, 0x509e,
+	0x7014, 0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x00c0, 0x50f7,
+	0x6888, 0x698c, 0xa105, 0x0040, 0x50f7, 0x1078, 0x510e, 0x6834,
+	0xa084, 0x00ff, 0xa086, 0x001e, 0x0040, 0x5373, 0x0078, 0x513a,
+	0x5102, 0x5106, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f,
+	0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x0f7e, 0x0e7e,
+	0x0c7e, 0x077e, 0x067e, 0x6f88, 0x6e8c, 0x6804, 0x2060, 0xacf0,
+	0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, 0x7008,
+	0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, 0x8109,
+	0x0040, 0x5130, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0078, 0x511d,
+	0x6004, 0xa065, 0x00c0, 0x5117, 0x067f, 0x077f, 0x0c7f, 0x0e7f,
+	0x0f7f, 0x007c, 0x2009, 0xa62f, 0x210c, 0x81ff, 0x00c0, 0x5155,
+	0x6838, 0xa084, 0x00ff, 0x683a, 0x1078, 0x4353, 0x00c0, 0x5149,
+	0x007c, 0x1078, 0x4b51, 0x127e, 0x2091, 0x8000, 0x1078, 0x8f7d,
+	0x1078, 0x4a73, 0x127f, 0x0078, 0x5148, 0x2001, 0x0028, 0x2009,
+	0x0000, 0x0078, 0x5149, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906,
+	0x711a, 0x7010, 0x8001, 0x7012, 0x0040, 0x516a, 0x7007, 0x0006,
+	0x0078, 0x5170, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a,
+	0x007c, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848,
+	0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x519a,
+	0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0040, 0x519a,
+	0xa005, 0x00c0, 0x51ad, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078,
+	0x45c4, 0x00c0, 0x51ad, 0x067e, 0x6e50, 0x1078, 0x46b3, 0x067f,
+	0x0078, 0x51ad, 0x047e, 0x2011, 0xa60c, 0x2224, 0xc484, 0xc48c,
+	0x2412, 0x047f, 0x0c7e, 0x1078, 0x45c4, 0x00c0, 0x51a9, 0x1078,
+	0x4852, 0x8108, 0x00f0, 0x51a3, 0x0c7f, 0x684c, 0xd084, 0x00c0,
+	0x51b4, 0x1078, 0x13a4, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x4a73, 0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001,
+	0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x51ff, 0x2061, 0xa933,
+	0x6100, 0xd184, 0x0040, 0x51df, 0x6858, 0xa084, 0x00ff, 0x00c0,
+	0x5202, 0x6000, 0xd084, 0x0040, 0x51ff, 0x6004, 0xa005, 0x00c0,
+	0x5205, 0x6003, 0x0000, 0x600b, 0x0000, 0x0078, 0x51fc, 0x2011,
+	0x0001, 0x6860, 0xa005, 0x00c0, 0x51e7, 0x2001, 0x001e, 0x8000,
+	0x6016, 0x6858, 0xa084, 0x00ff, 0x0040, 0x51ff, 0x6006, 0x6858,
+	0x8007, 0xa084, 0x00ff, 0x0040, 0x51ff, 0x600a, 0x6858, 0x8000,
+	0x00c0, 0x51fb, 0xc28d, 0x6202, 0x127f, 0x0078, 0x5453, 0x127f,
+	0x0078, 0x544b, 0x127f, 0x0078, 0x5443, 0x127f, 0x0078, 0x5447,
+	0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xa653, 0x2004,
+	0xd0a4, 0x0040, 0x525e, 0x2061, 0xa933, 0x6000, 0xd084, 0x0040,
+	0x525e, 0x6204, 0x6308, 0xd08c, 0x00c0, 0x5250, 0x6c48, 0xa484,
+	0x0003, 0x0040, 0x5236, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0,
+	0x522f, 0x2100, 0xa210, 0x0048, 0x525b, 0x0078, 0x5236, 0x8001,
+	0x00c0, 0x525b, 0x2100, 0xa212, 0x0048, 0x525b, 0xa484, 0x000c,
+	0x0040, 0x5250, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004,
+	0x00c0, 0x5248, 0x2100, 0xa318, 0x0048, 0x525b, 0x0078, 0x5250,
+	0xa082, 0x0004, 0x00c0, 0x525b, 0x2100, 0xa31a, 0x0048, 0x525b,
+	0x6860, 0xa005, 0x0040, 0x5256, 0x8000, 0x6016, 0x6206, 0x630a,
+	0x127f, 0x0078, 0x5453, 0x127f, 0x0078, 0x544f, 0x127f, 0x0078,
+	0x544b, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xa933,
+	0x6300, 0xd38c, 0x00c0, 0x5271, 0x6308, 0x8318, 0x0048, 0x5274,
+	0x630a, 0x127f, 0x0078, 0x5461, 0x127f, 0x0078, 0x544f, 0x127e,
+	0x0c7e, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0040,
+	0x528b, 0x0c7e, 0x2061, 0xa933, 0x6000, 0xa084, 0xfcff, 0x6002,
+	0x0c7f, 0x0078, 0x52ba, 0x6858, 0xa005, 0x0040, 0x52d1, 0x685c,
+	0xa065, 0x0040, 0x52cd, 0x2001, 0xa62f, 0x2004, 0xa005, 0x0040,
+	0x529d, 0x1078, 0x8ec6, 0x0078, 0x52ab, 0x6013, 0x0400, 0x6037,
+	0x0000, 0x694c, 0xd1a4, 0x0040, 0x52a7, 0x6950, 0x6136, 0x2009,
+	0x0041, 0x1078, 0x775c, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000,
+	0x00c0, 0x52ba, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078,
+	0x5bf1, 0x027f, 0x684c, 0xd0c4, 0x0040, 0x52c9, 0x2061, 0xa933,
+	0x6000, 0xd08c, 0x00c0, 0x52c9, 0x6008, 0x8000, 0x0048, 0x52cd,
+	0x600a, 0x0c7f, 0x127f, 0x0078, 0x5453, 0x0c7f, 0x127f, 0x0078,
+	0x544b, 0x6954, 0xa186, 0x0045, 0x0040, 0x5306, 0xa186, 0x002a,
+	0x00c0, 0x52e1, 0x2001, 0xa60c, 0x200c, 0xc194, 0x2102, 0x0078,
+	0x52ba, 0xa186, 0x0020, 0x0040, 0x52fa, 0xa186, 0x0029, 0x0040,
+	0x52ed, 0xa186, 0x002d, 0x00c0, 0x52cd, 0x6944, 0xa18c, 0xff00,
+	0x810f, 0x1078, 0x45c4, 0x00c0, 0x52ba, 0x6000, 0xc0e4, 0x6002,
+	0x0078, 0x52ba, 0x685c, 0xa065, 0x0040, 0x52cd, 0x6007, 0x0024,
+	0x2001, 0xa8a3, 0x2004, 0x6016, 0x0078, 0x52ba, 0x685c, 0xa065,
+	0x0040, 0x52cd, 0x0e7e, 0x6860, 0xa075, 0x2001, 0xa62f, 0x2004,
+	0xa005, 0x0040, 0x531e, 0x1078, 0x8ec6, 0x8eff, 0x0040, 0x531b,
+	0x2e60, 0x1078, 0x8ec6, 0x0e7f, 0x0078, 0x52ba, 0x6024, 0xc0dc,
+	0xc0d5, 0x6026, 0x2e60, 0x6007, 0x003a, 0x6870, 0xa005, 0x0040,
+	0x532f, 0x6007, 0x003b, 0x6874, 0x602a, 0x6878, 0x6012, 0x6003,
+	0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0e7f, 0x0078, 0x52ba,
+	0x2061, 0xa933, 0x6000, 0xd084, 0x0040, 0x5352, 0xd08c, 0x00c0,
+	0x5461, 0x2091, 0x8000, 0x6204, 0x8210, 0x0048, 0x534c, 0x6206,
+	0x2091, 0x8001, 0x0078, 0x5461, 0x2091, 0x8001, 0x6853, 0x0016,
+	0x0078, 0x545a, 0x6853, 0x0007, 0x0078, 0x545a, 0x6834, 0x8007,
+	0xa084, 0x00ff, 0x00c0, 0x5360, 0x1078, 0x502d, 0x0078, 0x5372,
+	0x2030, 0x8001, 0x00c0, 0x536a, 0x7007, 0x0001, 0x1078, 0x5373,
+	0x0078, 0x5372, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016, 0x701a,
+	0x704b, 0x5373, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0xa03e,
+	0x2009, 0xa62f, 0x210c, 0x81ff, 0x00c0, 0x53ff, 0x2009, 0xa60c,
+	0x210c, 0xd194, 0x00c0, 0x5431, 0x6848, 0x2070, 0xae82, 0xad00,
+	0x0048, 0x53ef, 0x2001, 0xa616, 0x2004, 0xae02, 0x00c8, 0x53ef,
+	0x2061, 0xa933, 0x6100, 0xa184, 0x0301, 0xa086, 0x0001, 0x00c0,
+	0x53d2, 0x711c, 0xa186, 0x0006, 0x00c0, 0x53da, 0x7018, 0xa005,
+	0x0040, 0x53ff, 0x2004, 0xd0e4, 0x00c0, 0x542b, 0x7024, 0xd0dc,
+	0x00c0, 0x5435, 0x6853, 0x0000, 0x6803, 0x0000, 0x2d08, 0x7010,
+	0xa005, 0x00c0, 0x53be, 0x7112, 0x684c, 0xd0f4, 0x00c0, 0x5439,
+	0x2e60, 0x1078, 0x5b27, 0x127f, 0x0e7f, 0x007c, 0x2068, 0x6800,
+	0xa005, 0x00c0, 0x53be, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x00c0,
+	0x5439, 0x127f, 0x0e7f, 0x007c, 0x127f, 0x0e7f, 0x6853, 0x0006,
+	0x0078, 0x545a, 0xd184, 0x0040, 0x53cc, 0xd1c4, 0x00c0, 0x53f3,
+	0x0078, 0x53f7, 0x6944, 0xa18c, 0xff00, 0x810f, 0x1078, 0x45c4,
+	0x00c0, 0x542b, 0x6000, 0xd0e4, 0x00c0, 0x542b, 0x711c, 0xa186,
+	0x0007, 0x00c0, 0x53ef, 0x6853, 0x0002, 0x0078, 0x542d, 0x6853,
+	0x0008, 0x0078, 0x542d, 0x6853, 0x000e, 0x0078, 0x542d, 0x6853,
+	0x0017, 0x0078, 0x542d, 0x6853, 0x0035, 0x0078, 0x542d, 0x2001,
+	0xa672, 0x2004, 0xd0fc, 0x0040, 0x5427, 0x6848, 0x2070, 0xae82,
+	0xad00, 0x0048, 0x5427, 0x6058, 0xae02, 0x00c8, 0x5427, 0x711c,
+	0xa186, 0x0006, 0x00c0, 0x5427, 0x7018, 0xa005, 0x0040, 0x5427,
+	0x2004, 0xd0bc, 0x0040, 0x5427, 0x2039, 0x0001, 0x7000, 0xa086,
+	0x0007, 0x00c0, 0x537e, 0x7003, 0x0002, 0x0078, 0x537e, 0x6853,
+	0x0028, 0x0078, 0x542d, 0x6853, 0x0029, 0x127f, 0x0e7f, 0x0078,
+	0x545a, 0x6853, 0x002a, 0x0078, 0x542d, 0x6853, 0x0045, 0x0078,
+	0x542d, 0x2e60, 0x2019, 0x0002, 0x6017, 0x0014, 0x1078, 0x9dc7,
+	0x127f, 0x0e7f, 0x007c, 0x2009, 0x003e, 0x0078, 0x5455, 0x2009,
+	0x0004, 0x0078, 0x5455, 0x2009, 0x0006, 0x0078, 0x5455, 0x2009,
+	0x0016, 0x0078, 0x5455, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00,
+	0xa105, 0x6856, 0x2091, 0x8000, 0x1078, 0x4a73, 0x2091, 0x8001,
+	0x007c, 0x1078, 0x13a4, 0x007c, 0x702c, 0x7130, 0x8108, 0xa102,
+	0x0048, 0x5471, 0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0078,
+	0x547d, 0x7070, 0xa080, 0x0040, 0x7072, 0x00c8, 0x547d, 0x7074,
+	0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132, 0x007c,
+	0x0d7e, 0x1078, 0x5b1e, 0x0d7f, 0x007c, 0x0d7e, 0x2011, 0x0004,
+	0x2204, 0xa085, 0x8002, 0x2012, 0x0d7f, 0x007c, 0x20e1, 0x0002,
+	0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0040, 0x549c,
+	0xa086, 0x1000, 0x00c0, 0x54d3, 0x20e1, 0x0000, 0x3d00, 0xa094,
+	0xff00, 0x8217, 0xa084, 0xf000, 0xa086, 0x3000, 0x00c0, 0x54b7,
+	0xa184, 0xff00, 0x8007, 0xa086, 0x0008, 0x00c0, 0x54d3, 0x1078,
+	0x29bb, 0x00c0, 0x54d3, 0x1078, 0x56b2, 0x0078, 0x54ce, 0x20e1,
+	0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x54be, 0x3e60, 0xac84, 0x000f,
+	0x00c0, 0x54d3, 0xac82, 0xad00, 0x0048, 0x54d3, 0x6858, 0xac02,
+	0x00c8, 0x54d3, 0x2009, 0x0047, 0x1078, 0x775c, 0x7a1c, 0xd284,
+	0x00c0, 0x548e, 0x007c, 0xa016, 0x1078, 0x15fa, 0x0078, 0x54ce,
+	0x0078, 0x54d3, 0x781c, 0xd08c, 0x0040, 0x5502, 0x157e, 0x137e,
+	0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, 0x00c0,
+	0x5518, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, 0x5507, 0x1078,
+	0x554e, 0x0040, 0x5518, 0x20e1, 0x3000, 0x7828, 0x7828, 0x1078,
+	0x556c, 0x147f, 0x137f, 0x157f, 0x2009, 0xa8b9, 0x2104, 0xa005,
+	0x00c0, 0x5503, 0x007c, 0x1078, 0x62d1, 0x0078, 0x5502, 0xa484,
+	0x7000, 0x00c0, 0x5518, 0x1078, 0x554e, 0x0040, 0x552c, 0x7000,
+	0xa084, 0xff00, 0xa086, 0x8100, 0x0040, 0x54f3, 0x0078, 0x552c,
+	0x1078, 0xa54f, 0xd5a4, 0x0040, 0x5528, 0x047e, 0x1078, 0x1b22,
+	0x047f, 0x20e1, 0x9010, 0x2001, 0x0138, 0x2202, 0x0078, 0x5530,
+	0x1078, 0x554e, 0x6883, 0x0000, 0x20e1, 0x3000, 0x7828, 0x7828,
+	0x1078, 0x5537, 0x147f, 0x137f, 0x157f, 0x0078, 0x5502, 0x2001,
+	0xa60e, 0x2004, 0xd08c, 0x0040, 0x554d, 0x2001, 0xa600, 0x2004,
+	0xa086, 0x0003, 0x00c0, 0x554d, 0x027e, 0x037e, 0x2011, 0x8048,
+	0x2518, 0x1078, 0x361b, 0x037f, 0x027f, 0x007c, 0xa484, 0x01ff,
+	0x6882, 0xa005, 0x0040, 0x5560, 0xa080, 0x001f, 0xa084, 0x03f8,
+	0x80ac, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c,
+	0x20a9, 0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5,
+	0xa085, 0x0001, 0x0078, 0x555f, 0x7000, 0xa084, 0xff00, 0xa08c,
+	0xf000, 0x8007, 0xa196, 0x0000, 0x00c0, 0x5579, 0x0078, 0x57ba,
+	0x007c, 0xa196, 0x2000, 0x00c0, 0x558a, 0x6900, 0xa18e, 0x0001,
+	0x00c0, 0x5586, 0x1078, 0x3aec, 0x0078, 0x5578, 0x1078, 0x5592,
+	0x0078, 0x5578, 0xa196, 0x8000, 0x00c0, 0x5578, 0x1078, 0x5871,
+	0x0078, 0x5578, 0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196,
+	0x0001, 0x0040, 0x559f, 0xa196, 0x0023, 0x00c0, 0x56aa, 0xa08e,
+	0x0023, 0x00c0, 0x55d4, 0x1078, 0x591d, 0x0040, 0x56aa, 0x7124,
+	0x610a, 0x7030, 0xa08e, 0x0200, 0x00c0, 0x55b8, 0x7034, 0xa005,
+	0x00c0, 0x56aa, 0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x56aa,
+	0xa08e, 0x0214, 0x0040, 0x55c0, 0xa08e, 0x0210, 0x00c0, 0x55c6,
+	0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x56aa, 0xa08e, 0x0100,
+	0x00c0, 0x56aa, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x0016,
+	0x1078, 0x775c, 0x0078, 0x56aa, 0xa08e, 0x0022, 0x00c0, 0x56aa,
+	0x7030, 0xa08e, 0x0300, 0x00c0, 0x55e5, 0x7034, 0xa005, 0x00c0,
+	0x56aa, 0x2009, 0x0017, 0x0078, 0x5676, 0xa08e, 0x0500, 0x00c0,
+	0x55f1, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x0018, 0x0078,
+	0x5676, 0xa08e, 0x2010, 0x00c0, 0x55f9, 0x2009, 0x0019, 0x0078,
+	0x5676, 0xa08e, 0x2110, 0x00c0, 0x5601, 0x2009, 0x001a, 0x0078,
+	0x5676, 0xa08e, 0x5200, 0x00c0, 0x560d, 0x7034, 0xa005, 0x00c0,
+	0x56aa, 0x2009, 0x001b, 0x0078, 0x5676, 0xa08e, 0x5000, 0x00c0,
+	0x5619, 0x7034, 0xa005, 0x00c0, 0x56aa, 0x2009, 0x001c, 0x0078,
+	0x5676, 0xa08e, 0x1300, 0x00c0, 0x5621, 0x2009, 0x0034, 0x0078,
+	0x5676, 0xa08e, 0x1200, 0x00c0, 0x562d, 0x7034, 0xa005, 0x00c0,
+	0x56aa, 0x2009, 0x0024, 0x0078, 0x5676, 0xa08c, 0xff00, 0xa18e,
+	0x2400, 0x00c0, 0x5637, 0x2009, 0x002d, 0x0078, 0x5676, 0xa08c,
+	0xff00, 0xa18e, 0x5300, 0x00c0, 0x5641, 0x2009, 0x002a, 0x0078,
+	0x5676, 0xa08e, 0x0f00, 0x00c0, 0x5649, 0x2009, 0x0020, 0x0078,
+	0x5676, 0xa08e, 0x5300, 0x00c0, 0x564f, 0x0078, 0x566c, 0xa08e,
+	0x6104, 0x00c0, 0x566c, 0x2011, 0xab8d, 0x8208, 0x2204, 0xa082,
+	0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108,
+	0x047e, 0x2124, 0x1078, 0x361b, 0x047f, 0x8108, 0x00f0, 0x565c,
+	0x2009, 0x0023, 0x0078, 0x5676, 0xa08e, 0x6000, 0x00c0, 0x5674,
+	0x2009, 0x003f, 0x0078, 0x5676, 0x2009, 0x001d, 0x017e, 0x2011,
+	0xab83, 0x2204, 0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x56ac,
+	0x1078, 0x455c, 0x00c0, 0x56ac, 0x6612, 0x6516, 0x86ff, 0x0040,
+	0x569c, 0x017f, 0x017e, 0xa186, 0x0017, 0x00c0, 0x569c, 0x686c,
+	0xa606, 0x00c0, 0x569c, 0x6870, 0xa506, 0xa084, 0xff00, 0x00c0,
+	0x569c, 0x6000, 0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x76c7, 0x0040,
+	0x56af, 0x017f, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f,
+	0x1078, 0x775c, 0x0c7f, 0x007c, 0x017f, 0x0078, 0x56aa, 0x0c7f,
+	0x0078, 0x56ac, 0x0c7e, 0x1078, 0x570f, 0x00c0, 0x570d, 0xa28e,
+	0x0033, 0x00c0, 0x56de, 0x1078, 0x591d, 0x0040, 0x570d, 0x7124,
+	0x610a, 0x7030, 0xa08e, 0x0200, 0x00c0, 0x56d0, 0x7034, 0xa005,
+	0x00c0, 0x570d, 0x2009, 0x0015, 0x1078, 0x775c, 0x0078, 0x570d,
+	0xa08e, 0x0100, 0x00c0, 0x570d, 0x7034, 0xa005, 0x00c0, 0x570d,
+	0x2009, 0x0016, 0x1078, 0x775c, 0x0078, 0x570d, 0xa28e, 0x0032,
+	0x00c0, 0x570d, 0x7030, 0xa08e, 0x1400, 0x00c0, 0x570d, 0x2009,
+	0x0038, 0x017e, 0x2011, 0xab83, 0x2204, 0x8211, 0x220c, 0x1078,
+	0x254d, 0x00c0, 0x570c, 0x1078, 0x455c, 0x00c0, 0x570c, 0x6612,
+	0x6516, 0x0c7e, 0x1078, 0x76c7, 0x0040, 0x570b, 0x017f, 0x611a,
+	0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x775c, 0x1078,
+	0x62d1, 0x0078, 0x570d, 0x0c7f, 0x017f, 0x0c7f, 0x007c, 0x0f7e,
+	0x0d7e, 0x027e, 0x017e, 0x137e, 0x147e, 0x157e, 0x3c00, 0x007e,
+	0x2079, 0x0030, 0x2069, 0x0200, 0x1078, 0x1c6a, 0x00c0, 0x5750,
+	0x1078, 0x1b40, 0x0040, 0x575d, 0x7908, 0xa18c, 0x1fff, 0xa182,
+	0x0011, 0x00c8, 0x575a, 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0,
+	0x2099, 0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004,
+	0x7a0c, 0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0xa08a, 0x0140,
+	0x10c8, 0x1332, 0x80ac, 0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5,
+	0x20e1, 0x7000, 0x6828, 0x6828, 0x7803, 0x0004, 0xa294, 0x0070,
+	0x007f, 0x20e0, 0x157f, 0x147f, 0x137f, 0x017f, 0x027f, 0x0d7f,
+	0x0f7f, 0x007c, 0xa016, 0x1078, 0x15fa, 0xa085, 0x0001, 0x0078,
+	0x5750, 0x047e, 0x0e7e, 0x0d7e, 0x2028, 0x2130, 0xa696, 0x00ff,
+	0x00c0, 0x5782, 0xa596, 0xfffd, 0x00c0, 0x5772, 0x2009, 0x007f,
+	0x0078, 0x57b5, 0xa596, 0xfffe, 0x00c0, 0x577a, 0x2009, 0x007e,
+	0x0078, 0x57b5, 0xa596, 0xfffc, 0x00c0, 0x5782, 0x2009, 0x0080,
+	0x0078, 0x57b5, 0x2011, 0x0000, 0x2021, 0x0081, 0x20a9, 0x007e,
+	0x2071, 0xa7b6, 0x2e1c, 0x83ff, 0x00c0, 0x5794, 0x82ff, 0x00c0,
+	0x57a9, 0x2410, 0x0078, 0x57a9, 0x2368, 0x6f10, 0x007e, 0x2100,
+	0xa706, 0x007f, 0x6b14, 0x00c0, 0x57a3, 0xa346, 0x00c0, 0x57a3,
+	0x2408, 0x0078, 0x57b5, 0x87ff, 0x00c0, 0x57a9, 0x83ff, 0x0040,
+	0x578e, 0x8420, 0x8e70, 0x00f0, 0x578a, 0x82ff, 0x00c0, 0x57b4,
+	0xa085, 0x0001, 0x0078, 0x57b6, 0x2208, 0xa006, 0x0d7f, 0x0e7f,
+	0x047f, 0x007c, 0xa084, 0x0007, 0x0079, 0x57bf, 0x007c, 0x57c7,
+	0x57c7, 0x57c7, 0x5933, 0x57c7, 0x57c8, 0x57e1, 0x5858, 0x007c,
+	0x7110, 0xd1bc, 0x0040, 0x57e0, 0x7120, 0x2160, 0xac8c, 0x000f,
+	0x00c0, 0x57e0, 0xac8a, 0xad00, 0x0048, 0x57e0, 0x6858, 0xac02,
+	0x00c8, 0x57e0, 0x7124, 0x610a, 0x2009, 0x0046, 0x1078, 0x775c,
+	0x007c, 0x0c7e, 0xa484, 0x01ff, 0x0040, 0x5833, 0x7110, 0xd1bc,
+	0x00c0, 0x5833, 0x2011, 0xab83, 0x2204, 0x8211, 0x220c, 0x1078,
+	0x254d, 0x00c0, 0x5833, 0x1078, 0x455c, 0x00c0, 0x5833, 0x6612,
+	0x6516, 0x6000, 0xd0ec, 0x00c0, 0x5833, 0x6204, 0xa294, 0xff00,
+	0x8217, 0xa286, 0x0006, 0x00c0, 0x5818, 0x0c7e, 0x1078, 0x76c7,
+	0x017f, 0x0040, 0x5835, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a,
+	0x7130, 0x6122, 0x2009, 0x0044, 0x1078, 0x775c, 0x0078, 0x5833,
+	0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x5833, 0x611a, 0x601f,
+	0x0004, 0x7120, 0x610a, 0xa286, 0x0004, 0x00c0, 0x582b, 0x6007,
+	0x0005, 0x0078, 0x582d, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078,
+	0x5dd7, 0x1078, 0x62d1, 0x0c7f, 0x007c, 0x2001, 0xa60d, 0x2004,
+	0xd0ec, 0x0040, 0x583f, 0x2011, 0x8049, 0x1078, 0x361b, 0x0c7e,
+	0x1078, 0x9187, 0x017f, 0x0040, 0x5833, 0x611a, 0x601f, 0x0006,
+	0x7120, 0x610a, 0x7130, 0x6122, 0x6013, 0x0300, 0x6003, 0x0001,
+	0x6007, 0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x5833,
+	0x7110, 0xd1bc, 0x0040, 0x5870, 0x7020, 0x2060, 0xac84, 0x000f,
+	0x00c0, 0x5870, 0xac82, 0xad00, 0x0048, 0x5870, 0x6858, 0xac02,
+	0x00c8, 0x5870, 0x7124, 0x610a, 0x2009, 0x0045, 0x1078, 0x775c,
+	0x007c, 0x007e, 0x1078, 0x29bb, 0x007f, 0x00c0, 0x5887, 0x7110,
+	0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x00c0, 0x5887, 0xa084,
+	0x000f, 0xa08a, 0x0006, 0x00c8, 0x5887, 0x1079, 0x5888, 0x007c,
+	0x588e, 0x588f, 0x588e, 0x588e, 0x58ff, 0x590e, 0x007c, 0x7110,
+	0xd1bc, 0x0040, 0x5897, 0x702c, 0xd084, 0x0040, 0x58fe, 0x700c,
+	0x7108, 0x1078, 0x254d, 0x00c0, 0x58fe, 0x1078, 0x455c, 0x00c0,
+	0x58fe, 0x6612, 0x6516, 0x6204, 0x7110, 0xd1bc, 0x0040, 0x58c9,
+	0xa28c, 0x00ff, 0xa186, 0x0004, 0x0040, 0x58b2, 0xa186, 0x0006,
+	0x00c0, 0x58ef, 0x0c7e, 0x1078, 0x591d, 0x0c7f, 0x0040, 0x58fe,
+	0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f,
+	0x0002, 0x7120, 0x610a, 0x2009, 0x0088, 0x1078, 0x775c, 0x0078,
+	0x58fe, 0xa28c, 0x00ff, 0xa186, 0x0006, 0x0040, 0x58de, 0xa186,
+	0x0004, 0x0040, 0x58de, 0xa294, 0xff00, 0x8217, 0xa286, 0x0004,
+	0x0040, 0x58de, 0xa286, 0x0006, 0x00c0, 0x58ef, 0x0c7e, 0x1078,
+	0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f, 0x0005, 0x7120,
+	0x610a, 0x2009, 0x0088, 0x1078, 0x775c, 0x0078, 0x58fe, 0x0c7e,
+	0x1078, 0x76c7, 0x017f, 0x0040, 0x58fe, 0x611a, 0x601f, 0x0004,
+	0x7120, 0x610a, 0x2009, 0x0001, 0x1078, 0x775c, 0x007c, 0x7110,
+	0xd1bc, 0x0040, 0x590d, 0x1078, 0x591d, 0x0040, 0x590d, 0x7124,
+	0x610a, 0x2009, 0x0089, 0x1078, 0x775c, 0x007c, 0x7110, 0xd1bc,
+	0x0040, 0x591c, 0x1078, 0x591d, 0x0040, 0x591c, 0x7124, 0x610a,
+	0x2009, 0x008a, 0x1078, 0x775c, 0x007c, 0x7020, 0x2060, 0xac84,
+	0x000f, 0x00c0, 0x5930, 0xac82, 0xad00, 0x0048, 0x5930, 0x2001,
+	0xa616, 0x2004, 0xac02, 0x00c8, 0x5930, 0xa085, 0x0001, 0x007c,
+	0xa006, 0x0078, 0x592f, 0x7110, 0xd1bc, 0x00c0, 0x5949, 0x7024,
+	0x2060, 0xac84, 0x000f, 0x00c0, 0x5949, 0xac82, 0xad00, 0x0048,
+	0x5949, 0x6858, 0xac02, 0x00c8, 0x5949, 0x2009, 0x0051, 0x1078,
+	0x775c, 0x007c, 0x2071, 0xa8c4, 0x7003, 0x0003, 0x700f, 0x0361,
+	0xa006, 0x701a, 0x7012, 0x7017, 0xad00, 0x7007, 0x0000, 0x7026,
+	0x702b, 0x6e1c, 0x7032, 0x7037, 0x6e70, 0x703b, 0x0002, 0x703f,
+	0x0000, 0x7043, 0xffff, 0x7047, 0xffff, 0x007c, 0x2071, 0xa8c4,
+	0x00e0, 0x5a32, 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x00c0,
+	0x59de, 0x700f, 0x0361, 0x7007, 0x0001, 0x127e, 0x2091, 0x8000,
+	0x7138, 0x8109, 0x713a, 0x00c0, 0x59dc, 0x703b, 0x0002, 0x2009,
+	0x0100, 0x2104, 0xa082, 0x0003, 0x00c8, 0x59dc, 0x703c, 0xa086,
+	0x0001, 0x00c0, 0x59b9, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084,
+	0x4000, 0x0040, 0x5997, 0x6803, 0x1000, 0x0078, 0x599e, 0x6804,
+	0xa084, 0x1000, 0x0040, 0x599e, 0x6803, 0x0100, 0x6803, 0x0000,
+	0x703f, 0x0000, 0x2069, 0xa8b1, 0x6804, 0xa082, 0x0006, 0x00c0,
+	0x59ab, 0x6807, 0x0000, 0x6830, 0xa082, 0x0003, 0x00c0, 0x59b2,
+	0x6833, 0x0000, 0x1078, 0x62d1, 0x1078, 0x639b, 0x0d7f, 0x0078,
+	0x59dc, 0x0d7e, 0x2069, 0xa600, 0x6948, 0x6864, 0xa102, 0x00c8,
+	0x59db, 0x2069, 0xa8b1, 0x6804, 0xa086, 0x0000, 0x00c0, 0x59db,
+	0x6830, 0xa086, 0x0000, 0x00c0, 0x59db, 0x703f, 0x0001, 0x6807,
+	0x0006, 0x6833, 0x0003, 0x2069, 0x0100, 0x6830, 0x689e, 0x2069,
+	0x0140, 0x6803, 0x0600, 0x0d7f, 0x0078, 0x59e1, 0x127e, 0x2091,
+	0x8000, 0x7024, 0xa00d, 0x0040, 0x59f9, 0x7020, 0x8001, 0x7022,
+	0x00c0, 0x59f9, 0x7023, 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8,
+	0x00c0, 0x59f4, 0x7028, 0x107a, 0x81ff, 0x00c0, 0x59f9, 0x7028,
+	0x107a, 0x7030, 0xa00d, 0x0040, 0x5a10, 0x702c, 0x8001, 0x702e,
+	0x00c0, 0x5a10, 0x702f, 0x0009, 0x8109, 0x7132, 0x0040, 0x5a0e,
+	0xa184, 0x007f, 0x1040, 0x6ea2, 0x0078, 0x5a10, 0x7034, 0x107a,
+	0x7040, 0xa005, 0x0040, 0x5a18, 0x0050, 0x5a18, 0x8001, 0x7042,
+	0x7044, 0xa005, 0x0040, 0x5a20, 0x0050, 0x5a20, 0x8001, 0x7046,
+	0x7018, 0xa00d, 0x0040, 0x5a31, 0x7008, 0x8001, 0x700a, 0x00c0,
+	0x5a31, 0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x5a31, 0x701c,
+	0x107a, 0x127f, 0x7004, 0x0079, 0x5a35, 0x5a5c, 0x5a5d, 0x5a79,
+	0x0e7e, 0x2071, 0xa8c4, 0x7018, 0xa005, 0x00c0, 0x5a43, 0x711a,
+	0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x2071,
+	0xa8c4, 0x701c, 0xa206, 0x00c0, 0x5a4f, 0x701a, 0x701e, 0x007f,
+	0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa8c4, 0x6088, 0xa102, 0x0048,
+	0x5a5a, 0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, 0x45c4,
+	0x00c0, 0x5a6f, 0x6088, 0x8001, 0x0048, 0x5a6f, 0x608a, 0x00c0,
+	0x5a6f, 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x8108,
+	0xa182, 0x00ff, 0x0048, 0x5a77, 0xa00e, 0x7007, 0x0002, 0x7112,
+	0x007c, 0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x603c, 0xa005,
+	0x0040, 0x5a88, 0x8001, 0x603e, 0x00c0, 0x5a88, 0x1078, 0x8f9c,
+	0x6014, 0xa005, 0x0040, 0x5ab2, 0x8001, 0x6016, 0x00c0, 0x5ab2,
+	0x611c, 0xa186, 0x0003, 0x0040, 0x5a99, 0xa186, 0x0006, 0x00c0,
+	0x5ab0, 0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x5ab0,
+	0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x5aa9, 0x2001,
+	0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x5ab2,
+	0x1078, 0x8abe, 0x127f, 0xac88, 0x0010, 0x7116, 0x2001, 0xcd00,
+	0xa102, 0x0048, 0x5abf, 0x7017, 0xad00, 0x7007, 0x0000, 0x007c,
+	0x0e7e, 0x2071, 0xa8c4, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b,
+	0x0002, 0x0e7f, 0x007c, 0x2001, 0xa8cd, 0x2003, 0x0000, 0x007c,
+	0x0e7e, 0x2071, 0xa8c4, 0x7132, 0x702f, 0x0009, 0x0e7f, 0x007c,
+	0x2011, 0xa8d0, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa8c4,
+	0x711a, 0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x027e, 0x0e7e,
+	0x0f7e, 0x2079, 0xa600, 0x7a34, 0xd294, 0x0040, 0x5b15, 0x2071,
+	0xa8ac, 0x2e14, 0xa0fe, 0x0000, 0x0040, 0x5b02, 0xa0fe, 0x0001,
+	0x0040, 0x5b06, 0xa0fe, 0x0002, 0x00c0, 0x5b11, 0xa292, 0x0085,
+	0x0078, 0x5b08, 0xa292, 0x0005, 0x0078, 0x5b08, 0xa292, 0x0002,
+	0x2272, 0x0040, 0x5b0d, 0x00c8, 0x5b15, 0x2011, 0x8037, 0x1078,
+	0x361b, 0x2011, 0xa8ab, 0x2204, 0x2072, 0x0f7f, 0x0e7f, 0x027f,
+	0x007c, 0x0c7e, 0x2061, 0xa933, 0x0c7f, 0x007c, 0xa184, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa080, 0xa933, 0x2060, 0x007c, 0x6854,
+	0xa08a, 0x199a, 0x0048, 0x5b2e, 0x2001, 0x1999, 0xa005, 0x00c0,
+	0x5b3d, 0x0c7e, 0x2061, 0xa933, 0x6014, 0x0c7f, 0xa005, 0x00c0,
+	0x5b42, 0x2001, 0x001e, 0x0078, 0x5b42, 0xa08e, 0xffff, 0x00c0,
+	0x5b42, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c,
+	0xa08c, 0x00c0, 0xa18e, 0x00c0, 0x0040, 0x5b9e, 0xd0b4, 0x00c0,
+	0x5b59, 0xd0bc, 0x00c0, 0x5b8b, 0x2009, 0x0006, 0x1078, 0x5bc3,
+	0x007c, 0xd0fc, 0x0040, 0x5b64, 0xa084, 0x0003, 0x0040, 0x5b64,
+	0xa086, 0x0003, 0x00c0, 0x5bbc, 0x6024, 0xd0d4, 0x0040, 0x5b6e,
+	0xc0d4, 0x6026, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xa674,
+	0x2104, 0xd084, 0x0040, 0x5b83, 0x6118, 0xa188, 0x0027, 0x2104,
+	0xd08c, 0x00c0, 0x5b83, 0x87ff, 0x00c0, 0x5b82, 0x2009, 0x0042,
+	0x1078, 0x775c, 0x007c, 0x87ff, 0x00c0, 0x5b8a, 0x2009, 0x0043,
+	0x1078, 0x775c, 0x007c, 0xd0fc, 0x0040, 0x5b96, 0xa084, 0x0003,
+	0x0040, 0x5b96, 0xa086, 0x0003, 0x00c0, 0x5bbc, 0x87ff, 0x00c0,
+	0x5b9d, 0x2009, 0x0042, 0x1078, 0x775c, 0x007c, 0xd0fc, 0x0040,
+	0x5baf, 0xa084, 0x0003, 0xa08e, 0x0002, 0x0040, 0x5bb3, 0x87ff,
+	0x00c0, 0x5bae, 0x2009, 0x0041, 0x1078, 0x775c, 0x007c, 0x1078,
+	0x5bc1, 0x0078, 0x5bae, 0x87ff, 0x00c0, 0x5bae, 0x2009, 0x0043,
+	0x1078, 0x775c, 0x0078, 0x5bae, 0x2009, 0x0004, 0x1078, 0x5bc3,
+	0x007c, 0x2009, 0x0001, 0x0d7e, 0x6010, 0xa0ec, 0xf000, 0x0040,
+	0x5bef, 0x2068, 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x00c0,
+	0x5be5, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, 0x00c0, 0x5be5,
+	0x0c7e, 0x2061, 0xa933, 0x6200, 0xd28c, 0x00c0, 0x5be4, 0x6204,
+	0x8210, 0x0048, 0x5be4, 0x6206, 0x0c7f, 0x1078, 0x4a73, 0x6010,
+	0xa06d, 0x077e, 0x2039, 0x0000, 0x10c0, 0x5b27, 0x077f, 0x0d7f,
+	0x007c, 0x157e, 0x0c7e, 0x2061, 0xa933, 0x6000, 0x81ff, 0x0040,
+	0x5bfc, 0xa205, 0x0078, 0x5bfd, 0xa204, 0x6002, 0x0c7f, 0x157f,
+	0x007c, 0x6800, 0xd08c, 0x00c0, 0x5c0d, 0x6808, 0xa005, 0x0040,
+	0x5c0d, 0x8001, 0x680a, 0xa085, 0x0001, 0x007c, 0x20a9, 0x0010,
+	0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x5c17, 0xa200, 0x00f0,
+	0x5c12, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010, 0xa005,
+	0x0040, 0x5c3d, 0xa11a, 0x00c8, 0x5c3d, 0x8213, 0x818d, 0x0048,
+	0x5c30, 0xa11a, 0x00c8, 0x5c31, 0x00f0, 0x5c25, 0x0078, 0x5c35,
+	0xa11a, 0x2308, 0x8210, 0x00f0, 0x5c25, 0x007e, 0x3200, 0xa084,
+	0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e, 0x3200, 0xa085,
+	0x0800, 0x0078, 0x5c39, 0x127e, 0x2091, 0x2200, 0x2079, 0xa8b1,
+	0x127f, 0x0d7e, 0x2069, 0xa8b1, 0x6803, 0x0005, 0x2069, 0x0004,
+	0x2d04, 0xa085, 0x8001, 0x206a, 0x0d7f, 0x007c, 0x0c7e, 0x6027,
+	0x0001, 0x7804, 0xa084, 0x0007, 0x0079, 0x5c5e, 0x5c68, 0x5c8d,
+	0x5ce8, 0x5c6e, 0x5c8d, 0x5c68, 0x5c66, 0x5c66, 0x1078, 0x1332,
+	0x1078, 0x5acb, 0x1078, 0x62d1, 0x0c7f, 0x007c, 0x62c0, 0x82ff,
+	0x00c0, 0x5c74, 0x0c7f, 0x007c, 0x2011, 0x41dc, 0x1078, 0x5a45,
+	0x7828, 0xa092, 0x00c8, 0x00c8, 0x5c83, 0x8000, 0x782a, 0x1078,
+	0x421b, 0x0078, 0x5c72, 0x1078, 0x41dc, 0x7807, 0x0003, 0x7827,
+	0x0000, 0x782b, 0x0000, 0x0078, 0x5c72, 0x1078, 0x5acb, 0x3c00,
+	0x007e, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x007f, 0x20e0,
+	0x82ff, 0x0040, 0x5cab, 0x62c0, 0x82ff, 0x00c0, 0x5cab, 0x782b,
+	0x0000, 0x7824, 0xa065, 0x1040, 0x1332, 0x2009, 0x0013, 0x1078,
+	0x775c, 0x0c7f, 0x007c, 0x3900, 0xa082, 0xa9e3, 0x00c8, 0x5cb2,
+	0x1078, 0x747a, 0x0c7e, 0x7824, 0xa065, 0x1040, 0x1332, 0x7804,
+	0xa086, 0x0004, 0x0040, 0x5d2d, 0x7828, 0xa092, 0x2710, 0x00c8,
+	0x5cc8, 0x8000, 0x782a, 0x0c7f, 0x1078, 0x6e01, 0x0078, 0x5ca9,
+	0x6104, 0xa186, 0x0003, 0x00c0, 0x5cdf, 0x0e7e, 0x2071, 0xa600,
+	0x70d8, 0x0e7f, 0xd08c, 0x0040, 0x5cdf, 0x0c7e, 0x0e7e, 0x2061,
+	0x0100, 0x2071, 0xa600, 0x1078, 0x4224, 0x0e7f, 0x0c7f, 0x1078,
+	0xa5c4, 0x2009, 0x0014, 0x1078, 0x775c, 0x0c7f, 0x0078, 0x5ca9,
+	0x2001, 0xa8cd, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x00c0, 0x5cfc,
+	0x782b, 0x0000, 0x7824, 0xa065, 0x1040, 0x1332, 0x2009, 0x0013,
+	0x1078, 0x77b3, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x3900, 0xa082,
+	0xa9e3, 0x00c8, 0x5d05, 0x1078, 0x747a, 0x7824, 0xa005, 0x1040,
+	0x1332, 0x781c, 0xa06d, 0x1040, 0x1332, 0x6800, 0xc0dc, 0x6802,
+	0x7924, 0x2160, 0x1078, 0x772d, 0x693c, 0x81ff, 0x1040, 0x1332,
+	0x8109, 0x693e, 0x6854, 0xa015, 0x0040, 0x5d21, 0x7a1e, 0x0078,
+	0x5d23, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827, 0x0000, 0x0d7f,
+	0x0c7f, 0x1078, 0x62d1, 0x0078, 0x5cfa, 0x6104, 0xa186, 0x0002,
+	0x0040, 0x5d38, 0xa186, 0x0004, 0x0040, 0x5d38, 0x0078, 0x5cbc,
+	0x7808, 0xac06, 0x0040, 0x5cbc, 0x1078, 0x61cd, 0x1078, 0x5dd7,
+	0x0c7f, 0x1078, 0x62d1, 0x0078, 0x5ca9, 0x0c7e, 0x6027, 0x0002,
+	0x62c8, 0x82ff, 0x00c0, 0x5d61, 0x62c4, 0x82ff, 0x00c0, 0x5d61,
+	0x793c, 0xa1e5, 0x0000, 0x0040, 0x5d5b, 0x2009, 0x0049, 0x1078,
+	0x775c, 0x0c7f, 0x007c, 0x2011, 0xa8d0, 0x2013, 0x0000, 0x0078,
+	0x5d59, 0x3908, 0xa192, 0xa9e3, 0x00c8, 0x5d68, 0x1078, 0x747a,
+	0x6017, 0x0010, 0x793c, 0x81ff, 0x0040, 0x5d5b, 0x7944, 0xa192,
+	0x7530, 0x00c8, 0x5d85, 0x8108, 0x7946, 0x793c, 0xa188, 0x0007,
+	0x210c, 0xa18e, 0x0006, 0x00c0, 0x5d81, 0x6017, 0x0012, 0x0078,
+	0x5d59, 0x6017, 0x0016, 0x0078, 0x5d59, 0x7848, 0xc085, 0x784a,
+	0x0078, 0x5d59, 0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000,
+	0x600f, 0x0000, 0x2c08, 0x2061, 0xa8b1, 0x6020, 0x8000, 0x6022,
+	0x6010, 0xa005, 0x0040, 0x5da5, 0xa080, 0x0003, 0x2102, 0x6112,
+	0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c, 0x6116, 0x6112, 0x0078,
+	0x5da0, 0x0d7e, 0x2069, 0xa8b1, 0x6000, 0xd0d4, 0x0040, 0x5dbe,
+	0x6820, 0x8000, 0x6822, 0xa086, 0x0001, 0x00c0, 0x5db9, 0x2c00,
+	0x681e, 0x6804, 0xa084, 0x0007, 0x0079, 0x62d9, 0xc0d5, 0x6002,
+	0x6818, 0xa005, 0x0040, 0x5dd0, 0x6056, 0x605b, 0x0000, 0x007e,
+	0x2c00, 0x681a, 0x0d7f, 0x685a, 0x2069, 0xa8b1, 0x0078, 0x5db0,
+	0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x0078, 0x5db0, 0x007e,
+	0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08,
+	0x2061, 0xa8b1, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040,
+	0x5df2, 0xa080, 0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f,
+	0x007f, 0x007c, 0x610e, 0x610a, 0x0078, 0x5ded, 0x0c7e, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0xa8b1, 0x6034, 0xa005, 0x0040, 0x5e06,
+	0xa080, 0x0003, 0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136,
+	0x0078, 0x5e04, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e,
+	0x037e, 0x027e, 0x017e, 0x007e, 0x127e, 0xa02e, 0x2071, 0xa8b1,
+	0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x5e8c,
+	0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x5e87, 0x87ff,
+	0x0040, 0x5e2e, 0x6020, 0xa106, 0x00c0, 0x5e87, 0x703c, 0xac06,
+	0x00c0, 0x5e44, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x7033,
+	0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b,
+	0x0000, 0x037f, 0x2029, 0x0001, 0x7038, 0xac36, 0x00c0, 0x5e4a,
+	0x660c, 0x763a, 0x7034, 0xac36, 0x00c0, 0x5e58, 0x2c00, 0xaf36,
+	0x0040, 0x5e56, 0x2f00, 0x7036, 0x0078, 0x5e58, 0x7037, 0x0000,
+	0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5e61, 0x7e0e, 0x0078,
+	0x5e62, 0x2678, 0x600f, 0x0000, 0x1078, 0x8d06, 0x0040, 0x5e82,
+	0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5e9d, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x017e, 0x037e, 0x077e, 0x1078,
+	0x8f7d, 0x1078, 0xa4e2, 0x1078, 0x4a73, 0x077f, 0x037f, 0x017f,
+	0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x5e1d, 0x2c78,
+	0x600c, 0x2060, 0x0078, 0x5e1d, 0x85ff, 0x0040, 0x5e91, 0x1078,
+	0x639b, 0x127f, 0x007f, 0x017f, 0x027f, 0x037f, 0x057f, 0x067f,
+	0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006,
+	0x00c0, 0x5e6f, 0x017e, 0x037e, 0x077e, 0x1078, 0xa4e2, 0x1078,
+	0xa1ca, 0x077f, 0x037f, 0x017f, 0x0078, 0x5e82, 0x007e, 0x067e,
+	0x0c7e, 0x0d7e, 0x0f7e, 0x2031, 0x0000, 0x127e, 0x2091, 0x8000,
+	0x2079, 0xa8b1, 0x7838, 0xa065, 0x0040, 0x5eef, 0x600c, 0x007e,
+	0x600f, 0x0000, 0x783c, 0xac06, 0x00c0, 0x5ed6, 0x037e, 0x2019,
+	0x0001, 0x1078, 0x7058, 0x7833, 0x0000, 0x783f, 0x0000, 0x7843,
+	0x0000, 0x7847, 0x0000, 0x784b, 0x0000, 0x037f, 0x1078, 0x8d06,
+	0x0040, 0x5eea, 0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x00c0,
+	0x5ef8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73,
+	0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x007f, 0x0078, 0x5ebb, 0x7e3a,
+	0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c,
+	0x601c, 0xa086, 0x0006, 0x00c0, 0x5ee1, 0x1078, 0xa1ca, 0x0078,
+	0x5eea, 0x017e, 0x027e, 0x087e, 0x2041, 0x0000, 0x1078, 0x5f1b,
+	0x1078, 0x5fdb, 0x087f, 0x027f, 0x017f, 0x007c, 0x0f7e, 0x127e,
+	0x2079, 0xa8b1, 0x2091, 0x8000, 0x1078, 0x6076, 0x1078, 0x60ec,
+	0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e,
+	0x017e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x7614,
+	0x2660, 0x2678, 0x8cff, 0x0040, 0x5fb5, 0x6018, 0xa080, 0x0028,
+	0x2004, 0xa206, 0x00c0, 0x5fb0, 0x88ff, 0x0040, 0x5f3b, 0x6020,
+	0xa106, 0x00c0, 0x5fb0, 0x7024, 0xac06, 0x00c0, 0x5f6b, 0x2069,
+	0x0100, 0x68c0, 0xa005, 0x0040, 0x5f66, 0x1078, 0x5acb, 0x1078,
+	0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7027, 0x0000, 0x037e,
+	0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5f5b, 0x6803,
+	0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040,
+	0x5f63, 0x6827, 0x0001, 0x037f, 0x0078, 0x5f6b, 0x6003, 0x0009,
+	0x630a, 0x0078, 0x5fb0, 0x7014, 0xac36, 0x00c0, 0x5f71, 0x660c,
+	0x7616, 0x7010, 0xac36, 0x00c0, 0x5f7f, 0x2c00, 0xaf36, 0x0040,
+	0x5f7d, 0x2f00, 0x7012, 0x0078, 0x5f7f, 0x7013, 0x0000, 0x660c,
+	0x067e, 0x2c00, 0xaf06, 0x0040, 0x5f88, 0x7e0e, 0x0078, 0x5f89,
+	0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040,
+	0x5fa9, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5fbe, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x017e, 0x037e, 0x087e, 0x1078, 0x8f7d,
+	0x1078, 0xa4e2, 0x1078, 0x4a73, 0x087f, 0x037f, 0x017f, 0x1078,
+	0x8eb9, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x0c7f, 0x0078, 0x5f2a,
+	0x2c78, 0x600c, 0x2060, 0x0078, 0x5f2a, 0x127f, 0x007f, 0x017f,
+	0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c, 0xa086,
+	0x0006, 0x00c0, 0x5fcf, 0x017e, 0x037e, 0x087e, 0x1078, 0xa4e2,
+	0x1078, 0xa1ca, 0x087f, 0x037f, 0x017f, 0x0078, 0x5fa9, 0x601c,
+	0xa086, 0x0002, 0x00c0, 0x5fa9, 0x6004, 0xa086, 0x0085, 0x0040,
+	0x5f96, 0x0078, 0x5fa9, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000,
+	0xa280, 0xa735, 0x2004, 0xa065, 0x0040, 0x6072, 0x0f7e, 0x0e7e,
+	0x0d7e, 0x067e, 0x2071, 0xa8b1, 0x6654, 0x7018, 0xac06, 0x00c0,
+	0x5ff2, 0x761a, 0x701c, 0xac06, 0x00c0, 0x5ffe, 0x86ff, 0x00c0,
+	0x5ffd, 0x7018, 0x701e, 0x0078, 0x5ffe, 0x761e, 0x6058, 0xa07d,
+	0x0040, 0x6003, 0x7e56, 0xa6ed, 0x0000, 0x0040, 0x6009, 0x2f00,
+	0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc,
+	0x6002, 0x1078, 0x44d3, 0x0040, 0x606e, 0x7624, 0x86ff, 0x0040,
+	0x605c, 0xa680, 0x0004, 0x2004, 0xad06, 0x00c0, 0x605c, 0x0d7e,
+	0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x6053, 0x1078, 0x5acb,
+	0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7027, 0x0000,
+	0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x603c,
+	0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0040, 0x6044, 0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c,
+	0xa005, 0x0040, 0x604d, 0x8001, 0x603e, 0x2660, 0x1078, 0x8ec6,
+	0x0c7f, 0x0078, 0x605c, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009,
+	0x630a, 0x0c7f, 0x0078, 0x6011, 0x8dff, 0x0040, 0x606a, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8f7d, 0x1078, 0xa4e2,
+	0x1078, 0x4a73, 0x1078, 0x7233, 0x0078, 0x6011, 0x067f, 0x0d7f,
+	0x0e7f, 0x0f7f, 0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e,
+	0x0c7e, 0x0d7e, 0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x60d0,
+	0x600c, 0x007e, 0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x60b5,
+	0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x60af, 0x1078, 0x5acb,
+	0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378, 0x7827, 0x0000,
+	0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x60a4,
+	0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0040, 0x60ac, 0x6827, 0x0001, 0x037f, 0x0078, 0x60b5, 0x6003,
+	0x0009, 0x630a, 0x2c30, 0x0078, 0x60cd, 0x6010, 0x2068, 0x1078,
+	0x8d06, 0x0040, 0x60c9, 0x601c, 0xa086, 0x0003, 0x00c0, 0x60d7,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078,
+	0x8eb9, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x007f, 0x0078, 0x607d,
+	0x7e16, 0x7e12, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c,
+	0xa086, 0x0006, 0x00c0, 0x60e0, 0x1078, 0xa1ca, 0x0078, 0x60c9,
+	0x601c, 0xa086, 0x0002, 0x00c0, 0x60c9, 0x6004, 0xa086, 0x0085,
+	0x0040, 0x60c0, 0x0078, 0x60c9, 0x007e, 0x067e, 0x0c7e, 0x0d7e,
+	0x7818, 0xa065, 0x0040, 0x615a, 0x6054, 0x007e, 0x6057, 0x0000,
+	0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x44d3,
+	0x0040, 0x6157, 0x7e24, 0x86ff, 0x0040, 0x6149, 0xa680, 0x0004,
+	0x2004, 0xad06, 0x00c0, 0x6149, 0x0d7e, 0x2069, 0x0100, 0x68c0,
+	0xa005, 0x0040, 0x6140, 0x1078, 0x5acb, 0x1078, 0x6e0f, 0x68c3,
+	0x0000, 0x1078, 0x7378, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140,
+	0x6b04, 0xa384, 0x1000, 0x0040, 0x6129, 0x6803, 0x0100, 0x6803,
+	0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x6131, 0x6827,
+	0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x613a,
+	0x8001, 0x603e, 0x2660, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x6149,
+	0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078,
+	0x60fe, 0x8dff, 0x0040, 0x6153, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x1078, 0x4a73, 0x1078, 0x7233, 0x0078, 0x60fe, 0x007f,
+	0x0078, 0x60f1, 0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f,
+	0x007c, 0x0e7e, 0x0d7e, 0x067e, 0x6000, 0xd0dc, 0x0040, 0x6181,
+	0x604c, 0xa06d, 0x0040, 0x6181, 0x6848, 0xa606, 0x00c0, 0x6181,
+	0x2071, 0xa8b1, 0x7024, 0xa035, 0x0040, 0x6181, 0xa080, 0x0004,
+	0x2004, 0xad06, 0x00c0, 0x6181, 0x6000, 0xc0dc, 0x6002, 0x1078,
+	0x6185, 0x067f, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x2079, 0x0100,
+	0x78c0, 0xa005, 0x00c0, 0x6194, 0x0c7e, 0x2660, 0x6003, 0x0009,
+	0x630a, 0x0c7f, 0x0078, 0x61cb, 0x1078, 0x6e0f, 0x78c3, 0x0000,
+	0x1078, 0x7378, 0x7027, 0x0000, 0x037e, 0x2079, 0x0140, 0x7b04,
+	0xa384, 0x1000, 0x0040, 0x61a8, 0x7803, 0x0100, 0x7803, 0x0000,
+	0x2079, 0x0100, 0x7824, 0xd084, 0x0040, 0x61b0, 0x7827, 0x0001,
+	0x1078, 0x7378, 0x037f, 0x1078, 0x44d3, 0x0c7e, 0x603c, 0xa005,
+	0x0040, 0x61bc, 0x8001, 0x603e, 0x2660, 0x1078, 0x772d, 0x0c7f,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8f7d, 0x1078,
+	0x4a73, 0x1078, 0x7233, 0x0f7f, 0x007c, 0x0e7e, 0x0c7e, 0x2071,
+	0xa8b1, 0x7004, 0xa084, 0x0007, 0x0079, 0x61d6, 0x61e0, 0x61e3,
+	0x61fc, 0x6218, 0x6262, 0x61e0, 0x61e0, 0x61de, 0x1078, 0x1332,
+	0x0c7f, 0x0e7f, 0x007c, 0x7024, 0xa065, 0x0040, 0x61f1, 0x7020,
+	0x8001, 0x7022, 0x600c, 0xa015, 0x0040, 0x61f8, 0x7216, 0x600f,
+	0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c,
+	0x7216, 0x7212, 0x0078, 0x61f1, 0x6018, 0x2060, 0x1078, 0x44d3,
+	0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0040, 0x620d,
+	0x6054, 0xa015, 0x0040, 0x6214, 0x721e, 0x7007, 0x0000, 0x7027,
+	0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7218, 0x721e, 0x0078, 0x620d,
+	0x7024, 0xa065, 0x0040, 0x625f, 0x700c, 0xac06, 0x00c0, 0x622f,
+	0x1078, 0x7233, 0x600c, 0xa015, 0x0040, 0x622b, 0x720e, 0x600f,
+	0x0000, 0x0078, 0x625d, 0x720e, 0x720a, 0x0078, 0x625d, 0x7014,
+	0xac06, 0x00c0, 0x6242, 0x1078, 0x7233, 0x600c, 0xa015, 0x0040,
+	0x623e, 0x7216, 0x600f, 0x0000, 0x0078, 0x625d, 0x7216, 0x7212,
+	0x0078, 0x625d, 0x601c, 0xa086, 0x0003, 0x00c0, 0x625d, 0x6018,
+	0x2060, 0x1078, 0x44d3, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x7233,
+	0x701c, 0xa065, 0x0040, 0x625d, 0x6054, 0xa015, 0x0040, 0x625b,
+	0x721e, 0x0078, 0x625d, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f,
+	0x0e7f, 0x007c, 0x7024, 0xa065, 0x0040, 0x626f, 0x1078, 0x7233,
+	0x600c, 0xa015, 0x0040, 0x6276, 0x720e, 0x600f, 0x0000, 0x1078,
+	0x7378, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a,
+	0x0078, 0x626f, 0x0d7e, 0x2069, 0xa8b1, 0x6830, 0xa084, 0x0003,
+	0x0079, 0x6282, 0x6288, 0x628a, 0x62b4, 0x6288, 0x1078, 0x1332,
+	0x0d7f, 0x007c, 0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x62aa,
+	0x683c, 0xa065, 0x0040, 0x629b, 0x600c, 0xa015, 0x0040, 0x62a6,
+	0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011,
+	0xa8d0, 0x2013, 0x0000, 0x0c7f, 0x0d7f, 0x007c, 0x683a, 0x6836,
+	0x0078, 0x629b, 0x6843, 0x0000, 0x6838, 0xa065, 0x0040, 0x629b,
+	0x6003, 0x0003, 0x0078, 0x629b, 0x0c7e, 0x6843, 0x0000, 0x6847,
+	0x0000, 0x684b, 0x0000, 0x683c, 0xa065, 0x0040, 0x62ce, 0x600c,
+	0xa015, 0x0040, 0x62ca, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000,
+	0x0078, 0x62ce, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f,
+	0x007c, 0x0d7e, 0x2069, 0xa8b1, 0x6804, 0xa084, 0x0007, 0x0079,
+	0x62d9, 0x62e3, 0x638a, 0x638a, 0x638a, 0x638a, 0x638c, 0x638a,
+	0x62e1, 0x1078, 0x1332, 0x6820, 0xa005, 0x00c0, 0x62e9, 0x0d7f,
+	0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x62f8, 0x6807, 0x0004,
+	0x6826, 0x682b, 0x0000, 0x1078, 0x63d4, 0x0c7f, 0x0d7f, 0x007c,
+	0x6814, 0xa065, 0x0040, 0x6306, 0x6807, 0x0001, 0x6826, 0x682b,
+	0x0000, 0x1078, 0x63d4, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, 0x037e,
+	0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x6385, 0x704c, 0xa00d, 0x0040,
+	0x6315, 0x7088, 0xa005, 0x0040, 0x632d, 0x7054, 0xa075, 0x0040,
+	0x631e, 0xa20e, 0x0040, 0x6385, 0x0078, 0x6323, 0x6818, 0xa20e,
+	0x0040, 0x6385, 0x2070, 0x704c, 0xa00d, 0x0040, 0x6315, 0x7088,
+	0xa005, 0x00c0, 0x6315, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302,
+	0x00c8, 0x6315, 0x1078, 0x76fc, 0x0040, 0x6385, 0x8318, 0x733e,
+	0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff,
+	0x6032, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004,
+	0xa08a, 0x199a, 0x0048, 0x634e, 0x2001, 0x1999, 0x8003, 0x801b,
+	0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc,
+	0x0040, 0x6367, 0x7100, 0xd1f4, 0x0040, 0x6363, 0x7114, 0xa18c,
+	0x00ff, 0x0078, 0x636c, 0x2009, 0x0000, 0x0078, 0x636c, 0xa1e0,
+	0x29c0, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078,
+	0x6965, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26,
+	0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040,
+	0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f,
+	0x0078, 0x6383, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040,
+	0x6398, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x63d4,
+	0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0xa8b1, 0x6830,
+	0xa086, 0x0000, 0x00c0, 0x63bb, 0x6838, 0xa07d, 0x0040, 0x63bb,
+	0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x684b, 0x0000, 0x127e,
+	0x0f7e, 0x2091, 0x2200, 0x027f, 0x1078, 0x1d6d, 0x00c0, 0x63be,
+	0x127f, 0x1078, 0x6cb3, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843,
+	0x0000, 0x7803, 0x0002, 0x780c, 0xa015, 0x0040, 0x63d0, 0x6a3a,
+	0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x63bb,
+	0x683a, 0x6836, 0x0078, 0x63ca, 0x601c, 0xa084, 0x000f, 0x1079,
+	0x63da, 0x007c, 0x63e3, 0x63e8, 0x6809, 0x6922, 0x63e8, 0x6809,
+	0x6922, 0x63e3, 0x63e8, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x007c,
+	0x157e, 0x137e, 0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0044,
+	0x10c8, 0x1332, 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x6405,
+	0x7900, 0xd1f4, 0x0040, 0x6401, 0x7914, 0xa18c, 0x00ff, 0x0078,
+	0x640a, 0x2009, 0x0000, 0x0078, 0x640a, 0xa1f8, 0x29c0, 0x2f0c,
+	0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040,
+	0x00c8, 0x645c, 0x1079, 0x641a, 0x0f7f, 0x0c7f, 0x147f, 0x137f,
+	0x157f, 0x007c, 0x64c2, 0x650a, 0x6532, 0x65cd, 0x65fd, 0x6605,
+	0x662c, 0x663d, 0x664e, 0x6656, 0x666e, 0x6656, 0x66d9, 0x663d,
+	0x66fa, 0x6702, 0x664e, 0x6702, 0x6713, 0x645a, 0x645a, 0x645a,
+	0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a, 0x645a,
+	0x6eef, 0x6f14, 0x6f29, 0x6f4c, 0x6f6d, 0x662c, 0x645a, 0x662c,
+	0x6656, 0x645a, 0x6532, 0x65cd, 0x645a, 0x749c, 0x6656, 0x645a,
+	0x74bc, 0x6656, 0x645a, 0x645a, 0x64bd, 0x646b, 0x645a, 0x74e1,
+	0x7558, 0x7640, 0x645a, 0x7651, 0x6626, 0x766d, 0x645a, 0x6f82,
+	0x645a, 0x645a, 0x1078, 0x1332, 0x2100, 0x1079, 0x6465, 0x0f7f,
+	0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c, 0x6469, 0x6469, 0x6469,
+	0x649f, 0x1078, 0x1332, 0x0d7e, 0x20a1, 0x020b, 0x1078, 0x6731,
+	0x7810, 0x2068, 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800,
+	0x683c, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6dfb, 0x0d7f, 0x007c,
+	0x0d7e, 0x7818, 0x2068, 0x68a0, 0xa082, 0x007e, 0x0048, 0x649c,
+	0xa085, 0x0001, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x649a, 0x0d7e,
+	0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x0500, 0x20a3, 0x0000,
+	0x7810, 0xa0e8, 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810,
+	0x20a2, 0x6814, 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3,
+	0x0010, 0x1078, 0x6dfb, 0x0d7f, 0x007c, 0x6030, 0x609a, 0x1078,
+	0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x5200,
+	0x20a3, 0x0000, 0x0d7e, 0x2069, 0xa652, 0x6804, 0xd084, 0x0040,
+	0x64dc, 0x6828, 0x20a3, 0x0000, 0x017e, 0x1078, 0x2564, 0x21a2,
+	0x017f, 0x0d7f, 0x0078, 0x64e1, 0x0d7f, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x20a9, 0x0004,
+	0x2099, 0xa601, 0x53a6, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082,
+	0x007f, 0x0048, 0x64fb, 0x2001, 0xa61b, 0x20a6, 0x2001, 0xa61c,
+	0x20a6, 0x0078, 0x6501, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff,
+	0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078,
+	0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x0500,
+	0x20a3, 0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f,
+	0x0048, 0x6522, 0x2001, 0xa61b, 0x20a6, 0x2001, 0xa61c, 0x20a6,
+	0x0078, 0x6528, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2,
+	0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x60c3, 0x0010, 0x1078,
+	0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6731, 0x0c7e, 0x7818,
+	0x2060, 0x2001, 0x0000, 0x1078, 0x4972, 0x0c7f, 0x7818, 0xa080,
+	0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x654d, 0x20a3, 0x0400,
+	0x620c, 0xc2b4, 0x620e, 0x0078, 0x654f, 0x20a3, 0x0300, 0x20a3,
+	0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0,
+	0x659c, 0x2099, 0xa88d, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304,
+	0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099,
+	0xa605, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa601, 0x53a6, 0x20a9,
+	0x0010, 0x20a3, 0x0000, 0x00f0, 0x6579, 0x2099, 0xa895, 0x3304,
+	0xc0dd, 0x20a2, 0x2001, 0xa672, 0x2004, 0xd0e4, 0x0040, 0x6594,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6,
+	0x20a9, 0x0004, 0x0078, 0x6596, 0x20a9, 0x0007, 0x20a3, 0x0000,
+	0x00f0, 0x6596, 0x0078, 0x65bc, 0x2099, 0xa88d, 0x20a9, 0x0008,
+	0x53a6, 0x20a9, 0x0004, 0x2099, 0xa605, 0x53a6, 0x20a9, 0x0004,
+	0x2099, 0xa601, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0,
+	0x65ad, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x65b3, 0x2099,
+	0xa895, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000,
+	0x00f0, 0x65be, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x65c4,
+	0x60c3, 0x0074, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x6731, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3,
+	0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e,
+	0x2079, 0xa652, 0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x65e9, 0xa085,
+	0x0020, 0xd1a4, 0x0040, 0x65ee, 0xa085, 0x0010, 0xa085, 0x0002,
+	0x0d7e, 0x0078, 0x66b7, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0014, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x6731, 0x20a3, 0x5000, 0x0078, 0x654f, 0x20a1, 0x020b, 0x1078,
+	0x6731, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0014, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b,
+	0x1078, 0x67b9, 0x0078, 0x6630, 0x20a1, 0x020b, 0x1078, 0x67c2,
+	0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0004, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3,
+	0x2a00, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b,
+	0x1078, 0x67c2, 0x20a3, 0x0200, 0x0078, 0x654f, 0x20a1, 0x020b,
+	0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005,
+	0x0040, 0x6665, 0x20a2, 0x0078, 0x6667, 0x20a3, 0x0003, 0x7810,
+	0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x0d7e, 0x20a1,
+	0x020b, 0x1078, 0x67c2, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3,
+	0x0800, 0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x6694,
+	0x6998, 0xa184, 0xc000, 0x00c0, 0x6690, 0xd1ec, 0x0040, 0x668c,
+	0x20a3, 0x2100, 0x0078, 0x6696, 0x20a3, 0x0100, 0x0078, 0x6696,
+	0x20a3, 0x0400, 0x0078, 0x6696, 0x20a3, 0x0700, 0xa006, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa652, 0x7904,
+	0x0f7f, 0xd1ac, 0x00c0, 0x66a6, 0xa085, 0x0020, 0xd1a4, 0x0040,
+	0x66ab, 0xa085, 0x0010, 0x2009, 0xa674, 0x210c, 0xd184, 0x0040,
+	0x66b5, 0x699c, 0xd18c, 0x0040, 0x66b7, 0xa085, 0x0002, 0x027e,
+	0x2009, 0xa672, 0x210c, 0xd1e4, 0x0040, 0x66c5, 0xc0c5, 0xa094,
+	0x0030, 0xa296, 0x0010, 0x0040, 0x66cf, 0xd1ec, 0x0040, 0x66cf,
+	0xa094, 0x0030, 0xa296, 0x0010, 0x0040, 0x66cf, 0xc0bd, 0x027f,
+	0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x0014, 0x1078, 0x6dfb, 0x0d7f,
+	0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0210, 0x20a3,
+	0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078,
+	0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0200,
+	0x0078, 0x64c8, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100,
+	0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008,
+	0x1078, 0x6dfb, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1,
+	0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3,
+	0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c,
+	0x027e, 0x037e, 0x047e, 0x2019, 0x3200, 0x2021, 0x0800, 0x0078,
+	0x6738, 0x027e, 0x037e, 0x047e, 0x2019, 0x2200, 0x2021, 0x0100,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014,
+	0xa286, 0x007e, 0x00c0, 0x674b, 0xa385, 0x00ff, 0x20a2, 0x20a3,
+	0xfffe, 0x0078, 0x6780, 0xa286, 0x007f, 0x00c0, 0x6757, 0x0d7e,
+	0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd, 0x0078, 0x676e, 0xd2bc,
+	0x0040, 0x6776, 0xa286, 0x0080, 0x0d7e, 0x00c0, 0x6766, 0xa385,
+	0x00ff, 0x20a2, 0x20a3, 0xfffc, 0x0078, 0x676e, 0xa2e8, 0xa735,
+	0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6784, 0x0d7e, 0xa2e8,
+	0xa735, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f,
+	0x20a3, 0x0000, 0x6230, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x047f,
+	0x037f, 0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000,
+	0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f,
+	0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff,
+	0x2011, 0xfffc, 0x22a2, 0x0d7e, 0x2069, 0xa61b, 0x2da6, 0x8d68,
+	0x2da6, 0x0d7f, 0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, 0x678b,
+	0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000,
+	0x007c, 0x027e, 0x037e, 0x047e, 0x2019, 0x3300, 0x2021, 0x0800,
+	0x0078, 0x67c9, 0x027e, 0x037e, 0x047e, 0x2019, 0x2300, 0x2021,
+	0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa092, 0x007e, 0x0048, 0x67e6, 0x0d7e, 0xa0e8, 0xa735,
+	0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x67f4, 0x0d7e, 0xa0e8,
+	0xa735, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f,
+	0x20a3, 0x0000, 0x6230, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3,
+	0x0000, 0x047f, 0x037f, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000,
+	0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f,
+	0x007c, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1332,
+	0xa08a, 0x008c, 0x10c8, 0x1332, 0x6118, 0x2178, 0x79a0, 0xd1bc,
+	0x0040, 0x6827, 0x7900, 0xd1f4, 0x0040, 0x6823, 0x7914, 0xa18c,
+	0x00ff, 0x0078, 0x682c, 0x2009, 0x0000, 0x0078, 0x682c, 0xa1f8,
+	0x29c0, 0x2f0c, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a,
+	0xa082, 0x0085, 0x1079, 0x6837, 0x0f7f, 0x0c7f, 0x007c, 0x6840,
+	0x684b, 0x6866, 0x683e, 0x683e, 0x683e, 0x6840, 0x1078, 0x1332,
+	0x147e, 0x20a1, 0x020b, 0x1078, 0x6879, 0x60c3, 0x0000, 0x1078,
+	0x6dfb, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, 0x68ad,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2,
+	0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x000c, 0x1078, 0x6dfb, 0x147f, 0x007c, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x68ee, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x1078, 0x6dfb, 0x147f,
+	0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080,
+	0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x6898, 0x0d7e, 0xa0e8,
+	0xa735, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x68a7,
+	0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2,
+	0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3,
+	0x0009, 0x20a3, 0x0000, 0x0078, 0x678b, 0x027e, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e,
+	0x0048, 0x68cc, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085,
+	0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68,
+	0x2da6, 0x0d7f, 0x0078, 0x68db, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c,
+	0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3,
+	0x0000, 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x1078,
+	0x6dea, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7a10, 0x22a2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092,
+	0x007e, 0x0048, 0x690d, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810,
+	0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6,
+	0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x691c, 0x0d7e, 0xa0e8, 0xa735,
+	0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x0d7f,
+	0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000,
+	0x0078, 0x68df, 0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040,
+	0x1048, 0x1332, 0xa08a, 0x0053, 0x10c8, 0x1332, 0x7918, 0x2160,
+	0x61a0, 0xd1bc, 0x0040, 0x6941, 0x6100, 0xd1f4, 0x0040, 0x693d,
+	0x6114, 0xa18c, 0x00ff, 0x0078, 0x6946, 0x2009, 0x0000, 0x0078,
+	0x6946, 0xa1e0, 0x29c0, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100,
+	0x619a, 0xa082, 0x0040, 0x1079, 0x6950, 0x0f7f, 0x0c7f, 0x007c,
+	0x6965, 0x6a73, 0x6a14, 0x6c27, 0x6963, 0x6963, 0x6963, 0x6963,
+	0x6963, 0x6963, 0x6963, 0x714c, 0x715d, 0x716e, 0x717f, 0x6963,
+	0x767e, 0x6963, 0x713b, 0x1078, 0x1332, 0x0d7e, 0x157e, 0x147e,
+	0x780b, 0xffff, 0x20a1, 0x020b, 0x1078, 0x69d0, 0x7910, 0x2168,
+	0x6948, 0x7922, 0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c,
+	0xa184, 0x000f, 0x00c0, 0x6980, 0x2001, 0x0005, 0x0078, 0x698a,
+	0xd184, 0x0040, 0x6987, 0x2001, 0x0004, 0x0078, 0x698a, 0xa084,
+	0x0006, 0x8004, 0x017e, 0x2008, 0x7830, 0xa084, 0x00ff, 0x8007,
+	0xa105, 0x017f, 0x20a2, 0xd1ac, 0x0040, 0x699a, 0x20a3, 0x0002,
+	0x0078, 0x69a6, 0xd1b4, 0x0040, 0x69a1, 0x20a3, 0x0001, 0x0078,
+	0x69a6, 0x20a3, 0x0000, 0x2230, 0x0078, 0x69a8, 0x6a80, 0x6e7c,
+	0x20a9, 0x0008, 0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000,
+	0x00f0, 0x69ac, 0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080,
+	0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xa8cd,
+	0x2003, 0x07d0, 0x2001, 0xa8cc, 0x2003, 0x0009, 0x2001, 0xa8d2,
+	0x2003, 0x0002, 0x1078, 0x158c, 0x147f, 0x157f, 0x0d7f, 0x007c,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014,
+	0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xd0bc, 0x0040, 0x69f6, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c,
+	0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6a05, 0x0d7e, 0xa0e8,
+	0xa735, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2,
+	0x0d7f, 0x20a3, 0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3,
+	0x0000, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e,
+	0x20a1, 0x020b, 0x1078, 0x6a34, 0x7810, 0x2068, 0x6860, 0x20a2,
+	0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c, 0x1078, 0x6dfb, 0x147f,
+	0x137f, 0x157f, 0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6a52,
+	0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f,
+	0x0078, 0x6a61, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085,
+	0x0500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230,
+	0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2,
+	0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x027f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x7810,
+	0xa0ec, 0xf000, 0x0040, 0x6a8b, 0xa06d, 0x1078, 0x495f, 0x0040,
+	0x6a8b, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6a8b,
+	0x7824, 0xc0cd, 0x7826, 0x20a1, 0x020b, 0x1078, 0x6be0, 0xa016,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000,
+	0x00c0, 0x6aa2, 0x7810, 0xa084, 0x0700, 0x8007, 0x1079, 0x6aaa,
+	0x0078, 0x6aa5, 0xa006, 0x1079, 0x6aaa, 0x147f, 0x137f, 0x157f,
+	0x0d7f, 0x007c, 0x6ab4, 0x6b4c, 0x6b57, 0x6b81, 0x6b95, 0x6bb1,
+	0x6bbc, 0x6ab2, 0x1078, 0x1332, 0x017e, 0x037e, 0x694c, 0xa18c,
+	0x0003, 0x0040, 0x6abf, 0xa186, 0x0003, 0x00c0, 0x6ace, 0x6b78,
+	0x7824, 0xd0cc, 0x0040, 0x6ac5, 0xc3e5, 0x23a2, 0x6868, 0x20a2,
+	0x6864, 0x20a2, 0x037f, 0x017f, 0x0078, 0x6b8c, 0xa186, 0x0001,
+	0x10c0, 0x1332, 0x6b78, 0x7824, 0xd0cc, 0x0040, 0x6ad8, 0xc3e5,
+	0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2,
+	0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, 0x0040,
+	0x6b46, 0xd3c4, 0x0040, 0x6aee, 0x687c, 0xa108, 0xd3cc, 0x0040,
+	0x6af3, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d, 0xad80, 0x0020,
+	0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x6af8, 0x157f, 0x22a2,
+	0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x6b46, 0x20a1, 0x020b,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x007e, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xd0bc, 0x0040, 0x6b26, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c,
+	0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6b35, 0x0d7e, 0xa0e8,
+	0xa735, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x007f, 0x7b24, 0xd3cc,
+	0x0040, 0x6b3e, 0x20a3, 0x0889, 0x0078, 0x6b40, 0x20a3, 0x0898,
+	0x20a2, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x61c2, 0x037f,
+	0x017f, 0x1078, 0x6dfb, 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc,
+	0x0040, 0x6b53, 0xc2e5, 0x22a2, 0xa016, 0x0078, 0x6b8a, 0x2011,
+	0x0302, 0x7824, 0xd0cc, 0x0040, 0x6b5e, 0xc2e5, 0x22a2, 0xa016,
+	0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500,
+	0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x1078, 0x6dfb,
+	0x007c, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x0040, 0x6b88, 0xc2e5,
+	0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2,
+	0x60c3, 0x0018, 0x1078, 0x6dfb, 0x007c, 0x2011, 0x0100, 0x7824,
+	0xd0cc, 0x0040, 0x6b9c, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2,
+	0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x7834, 0xa084,
+	0x00ff, 0x20a2, 0x22a2, 0x22a2, 0x60c3, 0x0020, 0x1078, 0x6dfb,
+	0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0040, 0x6bb8, 0xc2e5,
+	0x22a2, 0xa016, 0x0078, 0x6b8a, 0x037e, 0x7b10, 0xa384, 0xff00,
+	0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x6bcf, 0x7824, 0xd0cc,
+	0x0040, 0x6bcb, 0xc2e5, 0x22a2, 0x037f, 0x0078, 0x6b8a, 0x047e,
+	0x2021, 0x0800, 0x007e, 0x7824, 0xd0cc, 0x007f, 0x0040, 0x6bd9,
+	0xc4e5, 0x24a2, 0x047f, 0x22a2, 0x20a2, 0x037f, 0x0078, 0x6b8c,
+	0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xd0bc, 0x0040, 0x6bfe, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c,
+	0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6c0d, 0x0d7e, 0xa0e8,
+	0xa735, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x7824, 0xd0cc, 0x0040,
+	0x6c15, 0x20a3, 0x0889, 0x0078, 0x6c17, 0x20a3, 0x0898, 0x20a3,
+	0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2,
+	0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0d7e,
+	0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810, 0xa084, 0x0700,
+	0x8007, 0x1079, 0x6c3a, 0x037f, 0x017f, 0x147f, 0x137f, 0x157f,
+	0x0d7f, 0x007c, 0x6c42, 0x6c42, 0x6c44, 0x6c42, 0x6c42, 0x6c42,
+	0x6c69, 0x6c42, 0x1078, 0x1332, 0x7910, 0xa18c, 0xf8ff, 0xa18d,
+	0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, 0x6c73,
+	0x0d7e, 0x2069, 0xa652, 0x6804, 0xd0bc, 0x0040, 0x6c5e, 0x682c,
+	0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x6c60, 0x20a3, 0x3f00,
+	0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x1078, 0x6dfb,
+	0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078, 0x6c73, 0x20a3,
+	0x7f00, 0x0078, 0x6c61, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6c91, 0x0d7e,
+	0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814,
+	0x20a2, 0x2069, 0xa61b, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078,
+	0x6ca0, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c, 0x6810, 0xa085, 0x0100,
+	0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2,
+	0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078, 0x6dea, 0x22a2,
+	0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e, 0x057e, 0x047e,
+	0x037e, 0x2061, 0x0100, 0x2071, 0xa600, 0x6130, 0x7818, 0x2068,
+	0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x6cca, 0x6910, 0x6a14, 0x6430,
+	0x0078, 0x6cce, 0x6910, 0x6a14, 0x736c, 0x7470, 0x781c, 0xa086,
+	0x0006, 0x0040, 0x6d2d, 0xd5bc, 0x0040, 0x6cde, 0xa185, 0x0100,
+	0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6ce5, 0xa185, 0x0100,
+	0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073, 0x0809, 0x6077,
+	0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a,
+	0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070,
+	0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca,
+	0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0xa582, 0x0080, 0x0048, 0x6d17, 0x6a00, 0xd2f4, 0x0040, 0x6d15,
+	0x6a14, 0xa294, 0x00ff, 0x0078, 0x6d17, 0x2011, 0x0000, 0x629e,
+	0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005,
+	0x0040, 0x6d24, 0x2009, 0x1b58, 0x1078, 0x5ad0, 0x037f, 0x047f,
+	0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810, 0x2070, 0x704c,
+	0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x6d85, 0xd5bc, 0x0040,
+	0x6d41, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078,
+	0x6d48, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e,
+	0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff,
+	0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808,
+	0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c,
+	0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, 0xa109,
+	0x792a, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7,
+	0x0000, 0xa582, 0x0080, 0x0048, 0x6d80, 0x6a00, 0xd2f4, 0x0040,
+	0x6d7e, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6d80, 0x2011, 0x0000,
+	0x629e, 0x6017, 0x0012, 0x0078, 0x6d1a, 0xd5bc, 0x0040, 0x6d90,
+	0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6d97,
+	0xa185, 0x0700, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x1078,
+	0x495f, 0x0040, 0x6dad, 0x0d7e, 0x7810, 0xa06d, 0x684c, 0x0d7f,
+	0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6dad, 0x7824, 0xc0cd,
+	0x7826, 0x6073, 0x0889, 0x0078, 0x6daf, 0x6073, 0x0898, 0x6077,
+	0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a,
+	0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0x7014, 0x608a,
+	0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce,
+	0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080,
+	0x0048, 0x6ddd, 0x6a00, 0xd2f4, 0x0040, 0x6ddb, 0x6a14, 0xa294,
+	0x00ff, 0x0078, 0x6ddd, 0x2011, 0x0000, 0x629e, 0x7824, 0xd0cc,
+	0x0040, 0x6de6, 0x6017, 0x0016, 0x0078, 0x6d1a, 0x6017, 0x0012,
+	0x0078, 0x6d1a, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294,
+	0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069, 0xa8b1, 0x6843,
+	0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7,
+	0x9575, 0x1078, 0x6e06, 0x1078, 0x5ac0, 0x007c, 0x007e, 0x6014,
+	0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f, 0x007c, 0x007e,
+	0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008,
+	0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, 0x0d7e, 0x017e, 0x027e,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194, 0x4000, 0x0040,
+	0x6e59, 0x1078, 0x6e0f, 0x6803, 0x1000, 0x6803, 0x0000, 0x0c7e,
+	0x2061, 0xa8b1, 0x6128, 0xa192, 0x00c8, 0x00c8, 0x6e44, 0x8108,
+	0x612a, 0x6124, 0x0c7f, 0x81ff, 0x0040, 0x6e54, 0x1078, 0x5ac0,
+	0x1078, 0x6e06, 0x0078, 0x6e54, 0x6124, 0xa1e5, 0x0000, 0x0040,
+	0x6e51, 0x1078, 0xa5c4, 0x1078, 0x5acb, 0x2009, 0x0014, 0x1078,
+	0x775c, 0x0c7f, 0x0078, 0x6e54, 0x027f, 0x017f, 0x0d7f, 0x0c7f,
+	0x007c, 0x2001, 0xa8cd, 0x2004, 0xa005, 0x00c0, 0x6e54, 0x0c7e,
+	0x2061, 0xa8b1, 0x6128, 0xa192, 0x0003, 0x00c8, 0x6e44, 0x8108,
+	0x612a, 0x0c7f, 0x1078, 0x5ac0, 0x1078, 0x4224, 0x0078, 0x6e54,
+	0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x5ad8, 0x2071,
+	0xa8b1, 0x713c, 0x81ff, 0x0040, 0x6e9a, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x6ea0, 0x6803, 0x1000,
+	0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x037f,
+	0x713c, 0x2160, 0x1078, 0xa5c4, 0x2009, 0x004a, 0x1078, 0x775c,
+	0x0078, 0x6e9a, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c,
+	0x0078, 0x6e8a, 0x0e7e, 0x2071, 0xa8b1, 0x7048, 0xd084, 0x0040,
+	0x6ebc, 0x713c, 0x81ff, 0x0040, 0x6ebc, 0x2071, 0x0100, 0xa188,
+	0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x6eba, 0x7017, 0x0012,
+	0x0078, 0x6ebc, 0x7017, 0x0016, 0x0e7f, 0x007c, 0x0e7e, 0x0d7e,
+	0x0c7e, 0x067e, 0x057e, 0x047e, 0x007e, 0x127e, 0x2091, 0x8000,
+	0x6018, 0x2068, 0x6ca0, 0x2071, 0xa8b1, 0x7018, 0x2068, 0x8dff,
+	0x0040, 0x6ee6, 0x68a0, 0xa406, 0x0040, 0x6eda, 0x6854, 0x2068,
+	0x0078, 0x6ecf, 0x6010, 0x2060, 0x643c, 0x6540, 0x6648, 0x2d60,
+	0x1078, 0x4736, 0x0040, 0x6ee6, 0xa085, 0x0001, 0x127f, 0x007f,
+	0x047f, 0x057f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x20a1,
+	0x020b, 0x1078, 0x6731, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x781c, 0xa086, 0x0004, 0x00c0, 0x6f01, 0x6098, 0x0078,
+	0x6f02, 0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9,
+	0x0010, 0xa006, 0x20a2, 0x00f0, 0x6f0a, 0x20a2, 0x20a2, 0x60c3,
+	0x002c, 0x1078, 0x6dfb, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b,
+	0x1078, 0x6731, 0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x147f, 0x157f,
+	0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3,
+	0x0200, 0x20a3, 0x0000, 0x20a9, 0x0006, 0x2011, 0xa640, 0x2019,
+	0xa641, 0x23a6, 0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x00f0,
+	0x6f39, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078,
+	0x6dfb, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e,
+	0x20a1, 0x020b, 0x1078, 0x6799, 0x1078, 0x67b0, 0x7810, 0xa080,
+	0x0000, 0x2004, 0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002,
+	0x21a8, 0x53a6, 0xa080, 0x0004, 0x8003, 0x60c2, 0x1078, 0x6dfb,
+	0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x6731, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x7808, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x147f,
+	0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b,
+	0x1078, 0x6731, 0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017,
+	0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2,
+	0x1078, 0x6dfb, 0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x0e7e,
+	0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x700c,
+	0x2060, 0x8cff, 0x0040, 0x6fbb, 0x1078, 0x8f00, 0x00c0, 0x6fb2,
+	0x1078, 0x7c83, 0x600c, 0x007e, 0x1078, 0x772d, 0x1078, 0x7233,
+	0x0c7f, 0x0078, 0x6fa9, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f,
+	0x007f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e,
+	0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069,
+	0x0100, 0x2079, 0x0140, 0x2071, 0xa8b1, 0x7024, 0x2060, 0x8cff,
+	0x0040, 0x7014, 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x5acb,
+	0x2009, 0x0013, 0x1078, 0x775c, 0x20a9, 0x01f4, 0x6824, 0xd094,
+	0x0040, 0x6ff7, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040,
+	0x7009, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x7009, 0xd084,
+	0x0040, 0x6ffe, 0x6827, 0x0001, 0x0078, 0x7000, 0x00f0, 0x6fe6,
+	0x7804, 0xa084, 0x1000, 0x0040, 0x7009, 0x7803, 0x0100, 0x7803,
+	0x0000, 0x6824, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f,
+	0x0f7f, 0x157f, 0x127f, 0x007c, 0x2001, 0xa600, 0x2004, 0xa096,
+	0x0001, 0x0040, 0x704e, 0xa096, 0x0004, 0x0040, 0x704e, 0x1078,
+	0x5acb, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x41dc, 0x1078,
+	0x5a45, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x703c, 0x6827,
+	0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x704e, 0x7803, 0x1000,
+	0x7803, 0x0000, 0x0078, 0x704e, 0xd084, 0x0040, 0x7043, 0x6827,
+	0x0001, 0x0078, 0x7045, 0x00f0, 0x702b, 0x7804, 0xa084, 0x1000,
+	0x0040, 0x704e, 0x7803, 0x0100, 0x7803, 0x0000, 0x007f, 0x017f,
+	0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c,
+	0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x027e, 0x017e,
+	0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071,
+	0xa8b1, 0x703c, 0x2060, 0x8cff, 0x0040, 0x70d6, 0x68af, 0x95f5,
+	0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x00c0, 0x7074, 0x68c7,
+	0x0000, 0x68cb, 0x0008, 0x1078, 0x5ad8, 0x1078, 0x1f7e, 0x047e,
+	0x057e, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5, 0x2021, 0x0169,
+	0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x70a5, 0x68c7,
+	0x0000, 0x68cb, 0x0008, 0x0e7e, 0x0f7e, 0x2079, 0x0020, 0x2071,
+	0xa908, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012, 0x6816, 0x7803,
+	0x0008, 0x7003, 0x0000, 0x0f7f, 0x0e7f, 0x250a, 0x057f, 0x047f,
+	0xa39d, 0x0000, 0x00c0, 0x70b0, 0x2009, 0x0049, 0x1078, 0x775c,
+	0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x70c3, 0x6827, 0x0004,
+	0x7804, 0xa084, 0x4000, 0x0040, 0x70d5, 0x7803, 0x1000, 0x7803,
+	0x0000, 0x0078, 0x70d5, 0xd08c, 0x0040, 0x70ca, 0x6827, 0x0002,
+	0x0078, 0x70cc, 0x00f0, 0x70b2, 0x7804, 0xa084, 0x1000, 0x0040,
+	0x70d5, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x007f, 0x017f,
+	0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f, 0x127f, 0x007c,
+	0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa8b1, 0x6a06, 0x127f,
+	0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa8b1,
+	0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e,
+	0x007e, 0x127e, 0x2071, 0xa8b1, 0x7614, 0x2660, 0x2678, 0x2091,
+	0x8000, 0x8cff, 0x0040, 0x7134, 0x601c, 0xa206, 0x00c0, 0x712f,
+	0x7014, 0xac36, 0x00c0, 0x710e, 0x660c, 0x7616, 0x7010, 0xac36,
+	0x00c0, 0x711c, 0x2c00, 0xaf36, 0x0040, 0x711a, 0x2f00, 0x7012,
+	0x0078, 0x711c, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06,
+	0x0040, 0x7125, 0x7e0e, 0x0078, 0x7126, 0x2678, 0x600f, 0x0000,
+	0x1078, 0x8ec6, 0x1078, 0x7233, 0x0c7f, 0x0078, 0x7101, 0x2c78,
+	0x600c, 0x2060, 0x0078, 0x7101, 0x127f, 0x007f, 0x067f, 0x0c7f,
+	0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078,
+	0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2,
+	0x20a3, 0x1000, 0x0078, 0x718e, 0x157e, 0x147e, 0x20a1, 0x020b,
+	0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2,
+	0x20a2, 0x20a3, 0x4000, 0x0078, 0x718e, 0x157e, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2,
+	0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x718e, 0x157e, 0x147e,
+	0x20a1, 0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x718e, 0x157e,
+	0x147e, 0x20a1, 0x020b, 0x1078, 0x69d0, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x1078, 0x723e,
+	0x60c3, 0x0020, 0x1078, 0x6dfb, 0x147f, 0x157f, 0x007c, 0x127e,
+	0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120, 0xd1b4, 0x00c0,
+	0x71a6, 0xd1bc, 0x00c0, 0x71f0, 0x0078, 0x7230, 0x2009, 0x017f,
+	0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069, 0x0140, 0x20a9,
+	0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000, 0x0040, 0x71e7,
+	0x6020, 0xd0b4, 0x0040, 0x71e7, 0x6024, 0xd094, 0x00c0, 0x71e7,
+	0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x71e7, 0x00f0,
+	0x71b3, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c,
+	0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b, 0xbc91, 0x6043,
+	0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024, 0xd094, 0x00c0,
+	0x71e6, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x71dd, 0x027f, 0x0d7f,
+	0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000, 0x0078, 0x7230,
+	0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069,
+	0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000,
+	0x0040, 0x7229, 0x6020, 0xd0bc, 0x0040, 0x7229, 0x2104, 0xa084,
+	0x000f, 0xa086, 0x0004, 0x00c0, 0x7229, 0x00f0, 0x71fd, 0x027e,
+	0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c, 0x00ff, 0xa10d,
+	0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043, 0x0001, 0x6043,
+	0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x7223,
+	0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000,
+	0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0xa8b1, 0x7020, 0xa005,
+	0x0040, 0x723c, 0x8001, 0x7022, 0x0e7f, 0x007c, 0x20a9, 0x0008,
+	0x20a2, 0x00f0, 0x7240, 0x20a2, 0x20a2, 0x007c, 0x0f7e, 0x0e7e,
+	0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e, 0x2091, 0x8000,
+	0x2071, 0xa8b1, 0x7614, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff,
+	0x0040, 0x72e2, 0x8cff, 0x0040, 0x72e2, 0x601c, 0xa086, 0x0006,
+	0x00c0, 0x72dd, 0x88ff, 0x0040, 0x726d, 0x2800, 0xac06, 0x00c0,
+	0x72dd, 0x2039, 0x0000, 0x0078, 0x7278, 0x6018, 0xa206, 0x00c0,
+	0x72dd, 0x85ff, 0x0040, 0x7278, 0x6020, 0xa106, 0x00c0, 0x72dd,
+	0x7024, 0xac06, 0x00c0, 0x72a8, 0x2069, 0x0100, 0x68c0, 0xa005,
+	0x0040, 0x72a3, 0x1078, 0x5acb, 0x6817, 0x0008, 0x68c3, 0x0000,
+	0x1078, 0x7378, 0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04,
+	0xa384, 0x1000, 0x0040, 0x7298, 0x6803, 0x0100, 0x6803, 0x0000,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x72a0, 0x6827, 0x0001,
+	0x037f, 0x0078, 0x72a8, 0x6003, 0x0009, 0x630a, 0x0078, 0x72dd,
+	0x7014, 0xac36, 0x00c0, 0x72ae, 0x660c, 0x7616, 0x7010, 0xac36,
+	0x00c0, 0x72bc, 0x2c00, 0xaf36, 0x0040, 0x72ba, 0x2f00, 0x7012,
+	0x0078, 0x72bc, 0x7013, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06,
+	0x0040, 0x72c5, 0x7e0e, 0x0078, 0x72c6, 0x2678, 0x89ff, 0x00c0,
+	0x72d5, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040,
+	0x72d3, 0x1078, 0xa1ca, 0x1078, 0x8ec6, 0x1078, 0x7233, 0x88ff,
+	0x00c0, 0x72ec, 0x0c7f, 0x0078, 0x7257, 0x2c78, 0x600c, 0x2060,
+	0x0078, 0x7257, 0xa006, 0x127f, 0x007f, 0x067f, 0x077f, 0x0c7f,
+	0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000, 0x0c7f, 0xa8c5,
+	0x0001, 0x0078, 0x72e3, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e,
+	0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x7638,
+	0x2660, 0x2678, 0x8cff, 0x0040, 0x7367, 0x601c, 0xa086, 0x0006,
+	0x00c0, 0x7362, 0x87ff, 0x0040, 0x7313, 0x2700, 0xac06, 0x00c0,
+	0x7362, 0x0078, 0x731e, 0x6018, 0xa206, 0x00c0, 0x7362, 0x85ff,
+	0x0040, 0x731e, 0x6020, 0xa106, 0x00c0, 0x7362, 0x703c, 0xac06,
+	0x00c0, 0x7332, 0x037e, 0x2019, 0x0001, 0x1078, 0x7058, 0x7033,
+	0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b,
+	0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x7338, 0x660c, 0x763a,
+	0x7034, 0xac36, 0x00c0, 0x7346, 0x2c00, 0xaf36, 0x0040, 0x7344,
+	0x2f00, 0x7036, 0x0078, 0x7346, 0x7037, 0x0000, 0x660c, 0x067e,
+	0x2c00, 0xaf06, 0x0040, 0x734f, 0x7e0e, 0x0078, 0x7350, 0x2678,
+	0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x735a,
+	0x1078, 0xa1ca, 0x1078, 0x8ec6, 0x87ff, 0x00c0, 0x7371, 0x0c7f,
+	0x0078, 0x7302, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7302, 0xa006,
+	0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x007c, 0x6017, 0x0000, 0x0c7f, 0xa7bd, 0x0001, 0x0078, 0x7368,
+	0x0e7e, 0x2071, 0xa8b1, 0x2001, 0xa600, 0x2004, 0xa086, 0x0002,
+	0x00c0, 0x7386, 0x7007, 0x0005, 0x0078, 0x7388, 0x7007, 0x0000,
+	0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e,
+	0x127e, 0x2091, 0x8000, 0x2071, 0xa8b1, 0x2c10, 0x7638, 0x2660,
+	0x2678, 0x8cff, 0x0040, 0x73c8, 0x2200, 0xac06, 0x00c0, 0x73c3,
+	0x7038, 0xac36, 0x00c0, 0x73a6, 0x660c, 0x763a, 0x7034, 0xac36,
+	0x00c0, 0x73b4, 0x2c00, 0xaf36, 0x0040, 0x73b2, 0x2f00, 0x7036,
+	0x0078, 0x73b4, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0040,
+	0x73bc, 0x7e0e, 0x0078, 0x73bd, 0x2678, 0x600f, 0x0000, 0xa085,
+	0x0001, 0x0078, 0x73c8, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7399,
+	0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c,
+	0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091,
+	0x8000, 0x2071, 0xa8b1, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0040,
+	0x7469, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x7464,
+	0x7024, 0xac06, 0x00c0, 0x740f, 0x2069, 0x0100, 0x68c0, 0xa005,
+	0x0040, 0x743d, 0x1078, 0x6e0f, 0x68c3, 0x0000, 0x1078, 0x7378,
+	0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000,
+	0x0040, 0x7406, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100,
+	0x6824, 0xd084, 0x0040, 0x740e, 0x6827, 0x0001, 0x037f, 0x700c,
+	0xac36, 0x00c0, 0x7415, 0x660c, 0x760e, 0x7008, 0xac36, 0x00c0,
+	0x7423, 0x2c00, 0xaf36, 0x0040, 0x7421, 0x2f00, 0x700a, 0x0078,
+	0x7423, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040,
+	0x742c, 0x7e0e, 0x0078, 0x742d, 0x2678, 0x600f, 0x0000, 0x1078,
+	0x8eec, 0x00c0, 0x7441, 0x1078, 0x28a6, 0x1078, 0x8f00, 0x00c0,
+	0x745d, 0x1078, 0x7c83, 0x0078, 0x745d, 0x1078, 0x7378, 0x0078,
+	0x740f, 0x1078, 0x8f00, 0x00c0, 0x7449, 0x1078, 0x7c83, 0x0078,
+	0x745d, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x745d, 0x601c,
+	0xa086, 0x0003, 0x00c0, 0x7471, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x1078, 0x8ec6, 0x1078,
+	0x7233, 0x0c7f, 0x0078, 0x73de, 0x2c78, 0x600c, 0x2060, 0x0078,
+	0x73de, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x745d, 0x1078, 0xa1ca,
+	0x0078, 0x745d, 0x037e, 0x157e, 0x137e, 0x147e, 0x3908, 0xa006,
+	0xa190, 0x0020, 0x221c, 0xa39e, 0x2676, 0x00c0, 0x748b, 0x8210,
+	0x8000, 0x0078, 0x7482, 0xa005, 0x0040, 0x7497, 0x20a9, 0x0020,
+	0x2198, 0x8211, 0xa282, 0x0020, 0x20c8, 0x20a0, 0x53a3, 0x147f,
+	0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078,
+	0x67c2, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x2099, 0xa8a5, 0x20a9, 0x0004, 0x53a6,
+	0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x1078, 0x6dfb, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, 0x67c2,
+	0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084,
+	0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6dfb,
+	0x007c, 0x0d7e, 0x017e, 0x2f68, 0x2009, 0x0035, 0x1078, 0x91bc,
+	0x00c0, 0x7551, 0x20a1, 0x020b, 0x1078, 0x6731, 0x20a3, 0x1300,
+	0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0040,
+	0x752d, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0,
+	0x7507, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0078, 0x7542, 0xa286,
+	0x007f, 0x00c0, 0x7511, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0078,
+	0x7542, 0xd2bc, 0x0040, 0x7527, 0xa286, 0x0080, 0x00c0, 0x751e,
+	0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0078, 0x7542, 0xa2e8, 0xa735,
+	0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x0078, 0x7542, 0x20a3,
+	0x0000, 0x6098, 0x20a2, 0x0078, 0x7542, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa082, 0x007e, 0x0048, 0x753e, 0x0d7e, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x7542, 0x20a3, 0x0000,
+	0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x6dfb, 0x017f, 0x0d7f,
+	0x007c, 0x7817, 0x0001, 0x7803, 0x0006, 0x017f, 0x0d7f, 0x007c,
+	0x0d7e, 0x027e, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x0040,
+	0x757a, 0xa186, 0x0003, 0x0040, 0x75d5, 0xa186, 0x0005, 0x0040,
+	0x75b8, 0xa186, 0x0004, 0x0040, 0x75a8, 0xa186, 0x0008, 0x0040,
+	0x75c2, 0x7807, 0x0037, 0x7813, 0x1700, 0x1078, 0x7640, 0x027f,
+	0x0d7f, 0x007c, 0x1078, 0x75fd, 0x2009, 0x4000, 0x6800, 0x0079,
+	0x7581, 0x7594, 0x75a2, 0x7596, 0x75a2, 0x759d, 0x7594, 0x7594,
+	0x75a2, 0x75a2, 0x75a2, 0x75a2, 0x7594, 0x7594, 0x7594, 0x7594,
+	0x7594, 0x75a2, 0x7594, 0x75a2, 0x1078, 0x1332, 0x6824, 0xd0e4,
+	0x0040, 0x759d, 0xd0cc, 0x0040, 0x75a0, 0xa00e, 0x0078, 0x75a2,
+	0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0078, 0x75f3,
+	0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0x6a00, 0xa286, 0x0002, 0x00c0, 0x75b6, 0xa00e, 0x0078, 0x75f3,
+	0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0x0078, 0x75f3, 0x1078, 0x75fd, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x2009, 0x4000, 0xa286, 0x0005, 0x0040, 0x75d2, 0xa286, 0x0002,
+	0x00c0, 0x75d3, 0xa00e, 0x0078, 0x75f3, 0x1078, 0x75fd, 0x6810,
+	0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2,
+	0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0040,
+	0x75f1, 0xa08e, 0x0004, 0x0040, 0x75f1, 0x2009, 0x4000, 0x0078,
+	0x75f3, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018,
+	0x1078, 0x6dfb, 0x027f, 0x0d7f, 0x007c, 0x037e, 0x047e, 0x057e,
+	0x067e, 0x20a1, 0x020b, 0x1078, 0x67c2, 0xa006, 0x20a3, 0x0200,
+	0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa092, 0x007e, 0x0048, 0x7623, 0x0d7e, 0x2069, 0xa61b,
+	0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xa735, 0x2d6c, 0x6b10, 0x6c14,
+	0x0d7f, 0x0078, 0x7629, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000,
+	0x6630, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x00c0,
+	0x7637, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0078, 0x763b, 0x23a2,
+	0x24a2, 0x25a2, 0x26a2, 0x067f, 0x057f, 0x047f, 0x037f, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x67c2, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb,
+	0x007c, 0x20a1, 0x020b, 0x1078, 0x6728, 0x20a3, 0x1400, 0x20a3,
+	0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c,
+	0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000,
+	0x60c3, 0x0010, 0x1078, 0x6dfb, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x67b9, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810,
+	0x20a2, 0x60c3, 0x0008, 0x1078, 0x6dfb, 0x007c, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x7689, 0x60c3, 0x0000, 0x1078, 0x6dfb, 0x147f,
+	0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xd0bc, 0x0040, 0x76a6, 0x0d7e, 0xa0e8, 0xa735, 0x2d6c,
+	0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa61b,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x76ae, 0x20a3, 0x0300,
+	0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0819,
+	0x20a3, 0x0000, 0x1078, 0x6dea, 0x22a2, 0x20a3, 0x0000, 0x2fa2,
+	0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x2061,
+	0xad00, 0x2a70, 0x7064, 0x704a, 0x704f, 0xad00, 0x007c, 0x0e7e,
+	0x127e, 0x2071, 0xa600, 0x2091, 0x8000, 0x7548, 0xa582, 0x0010,
+	0x0048, 0x76f9, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040,
+	0x76e5, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8, 0x76e1, 0x0078,
+	0x76d4, 0x2061, 0xad00, 0x0078, 0x76d4, 0x6003, 0x0008, 0x8529,
+	0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8, 0x76f5, 0x754e,
+	0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704f, 0xad00, 0x0078,
+	0x76f0, 0xa006, 0x0078, 0x76f2, 0x0e7e, 0x2071, 0xa600, 0x7548,
+	0xa582, 0x0010, 0x0048, 0x772a, 0x704c, 0x2060, 0x6000, 0xa086,
+	0x0000, 0x0040, 0x7717, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8,
+	0x7713, 0x0078, 0x7706, 0x2061, 0xad00, 0x0078, 0x7706, 0x6003,
+	0x0008, 0x8529, 0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8,
+	0x7726, 0x754e, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x704f, 0xad00,
+	0x0078, 0x7722, 0xa006, 0x0078, 0x7724, 0xac82, 0xad00, 0x1048,
+	0x1332, 0x2001, 0xa616, 0x2004, 0xac02, 0x10c8, 0x1332, 0xa006,
+	0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000,
+	0x6003, 0x0000, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036,
+	0x603a, 0x603e, 0x2061, 0xa600, 0x6048, 0x8000, 0x604a, 0xa086,
+	0x0001, 0x0040, 0x7754, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x62d1, 0x127f, 0x0078, 0x7753, 0x601c, 0xa084, 0x000f, 0x0079,
+	0x7761, 0x776a, 0x777b, 0x7797, 0x77b3, 0x920e, 0x922a, 0x9246,
+	0x776a, 0x777b, 0xa186, 0x0013, 0x00c0, 0x7773, 0x1078, 0x61cd,
+	0x1078, 0x62d1, 0x007c, 0xa18e, 0x0047, 0x00c0, 0x777a, 0xa016,
+	0x1078, 0x15fa, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8,
+	0x1332, 0x1079, 0x7785, 0x067f, 0x007c, 0x7795, 0x7b00, 0x7cb2,
+	0x7795, 0x7d36, 0x77cf, 0x7795, 0x7795, 0x7a92, 0x80f6, 0x7795,
+	0x7795, 0x7795, 0x7795, 0x7795, 0x7795, 0x1078, 0x1332, 0x067e,
+	0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x77a1, 0x067f,
+	0x007c, 0x77b1, 0x87c3, 0x77b1, 0x77b1, 0x77b1, 0x77b1, 0x77b1,
+	0x77b1, 0x8766, 0x8951, 0x77b1, 0x87f3, 0x8879, 0x87f3, 0x8879,
+	0x77b1, 0x1078, 0x1332, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8,
+	0x1332, 0x1079, 0x77bd, 0x067f, 0x007c, 0x77cd, 0x813d, 0x820e,
+	0x8368, 0x84e4, 0x77cd, 0x77cd, 0x77cd, 0x8116, 0x870e, 0x8712,
+	0x77cd, 0x77cd, 0x77cd, 0x77cd, 0x8742, 0x1078, 0x1332, 0xa1b6,
+	0x0015, 0x00c0, 0x77d7, 0x1078, 0x772d, 0x0078, 0x77dd, 0xa1b6,
+	0x0016, 0x10c0, 0x1332, 0x1078, 0x772d, 0x007c, 0x20a9, 0x000e,
+	0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420,
+	0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002,
+	0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x77ec,
+	0x0e7e, 0x1078, 0x8d06, 0x0040, 0x7803, 0x6010, 0x2070, 0x7007,
+	0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x772d, 0x007c, 0x0d7e,
+	0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x7814, 0x6018, 0x2068,
+	0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, 0x781e,
+	0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, 0x772d,
+	0x037f, 0x0d7f, 0x007c, 0x017e, 0x20a9, 0x002a, 0xae80, 0x000c,
+	0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a,
+	0x6010, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3,
+	0x0e7e, 0x6010, 0x2004, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078,
+	0x772d, 0x017f, 0x007c, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2c68,
+	0x017e, 0x2009, 0x0035, 0x1078, 0x91bc, 0x017f, 0x00c0, 0x785f,
+	0x027e, 0x6228, 0x2268, 0x027f, 0x2071, 0xab8c, 0x6b1c, 0xa386,
+	0x0003, 0x0040, 0x7863, 0xa386, 0x0006, 0x0040, 0x7867, 0x1078,
+	0x772d, 0x0078, 0x7869, 0x1078, 0x786c, 0x0078, 0x7869, 0x1078,
+	0x7938, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x6810, 0x2078, 0xa186,
+	0x0015, 0x0040, 0x791d, 0xa18e, 0x0016, 0x00c0, 0x7936, 0x700c,
+	0xa08c, 0xff00, 0xa186, 0x1700, 0x0040, 0x7882, 0xa186, 0x0300,
+	0x00c0, 0x78f8, 0x8fff, 0x00c0, 0x788c, 0x6800, 0xa086, 0x000f,
+	0x0040, 0x78db, 0x0078, 0x7934, 0x6808, 0xa086, 0xffff, 0x00c0,
+	0x7921, 0x784c, 0xa084, 0x0060, 0xa086, 0x0020, 0x00c0, 0x78a2,
+	0x797c, 0x7810, 0xa106, 0x00c0, 0x7921, 0x7980, 0x7814, 0xa106,
+	0x00c0, 0x7921, 0x1078, 0x8eb9, 0x6830, 0x7852, 0x784c, 0xc0dc,
+	0xc0f4, 0xc0d4, 0x784e, 0x027e, 0xa00e, 0x6a14, 0x2001, 0x000a,
+	0x1078, 0x5c1c, 0x7854, 0xa20a, 0x0048, 0x78b7, 0x8011, 0x7a56,
+	0x82ff, 0x027f, 0x00c0, 0x78c3, 0x0c7e, 0x2d60, 0x1078, 0x8ae0,
+	0x0c7f, 0x0078, 0x7934, 0x0c7e, 0x0d7e, 0x2f68, 0x6838, 0xd0fc,
+	0x00c0, 0x78ce, 0x1078, 0x4353, 0x0078, 0x78d0, 0x1078, 0x4431,
+	0x0d7f, 0x0c7f, 0x00c0, 0x7921, 0x0c7e, 0x2d60, 0x1078, 0x772d,
+	0x0c7f, 0x0078, 0x7934, 0x0c7e, 0x1078, 0x9187, 0x0040, 0x78f1,
+	0x6013, 0x0000, 0x6818, 0x601a, 0x601f, 0x0003, 0x6904, 0x0c7e,
+	0x2d60, 0x1078, 0x772d, 0x0c7f, 0x1078, 0x775c, 0x0c7f, 0x0078,
+	0x7934, 0x2001, 0xa8a4, 0x2004, 0x683e, 0x0c7f, 0x0078, 0x7934,
+	0x7008, 0xa086, 0x000b, 0x00c0, 0x7912, 0x6018, 0x200c, 0xc1bc,
+	0x2102, 0x0c7e, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x601f, 0x0002, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f,
+	0x0078, 0x7934, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x7921, 0x2001,
+	0xa8a4, 0x2004, 0x683e, 0x0078, 0x7934, 0x1078, 0x7953, 0x0078,
+	0x7936, 0x8fff, 0x1040, 0x1332, 0x0c7e, 0x0d7e, 0x2d60, 0x2f68,
+	0x6837, 0x0103, 0x684b, 0x0003, 0x1078, 0x89cf, 0x1078, 0x8eb9,
+	0x1078, 0x8ec6, 0x0d7f, 0x0c7f, 0x1078, 0x772d, 0x0f7f, 0x007c,
+	0xa186, 0x0015, 0x00c0, 0x7942, 0x2001, 0xa8a4, 0x2004, 0x683e,
+	0x0078, 0x7950, 0xa18e, 0x0016, 0x00c0, 0x7952, 0x0c7e, 0x2d00,
+	0x2060, 0x1078, 0xa495, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x0c7f,
+	0x1078, 0x772d, 0x007c, 0x027e, 0x037e, 0x047e, 0x7228, 0x7c80,
+	0x7b7c, 0xd2f4, 0x0040, 0x7962, 0x2001, 0xa8a4, 0x2004, 0x683e,
+	0x0078, 0x79c6, 0x0c7e, 0x2d60, 0x1078, 0x89f3, 0x0c7f, 0x6804,
+	0xa086, 0x0050, 0x00c0, 0x797a, 0x0c7e, 0x2d00, 0x2060, 0x6003,
+	0x0001, 0x6007, 0x0050, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f,
+	0x0078, 0x79c6, 0x6800, 0xa086, 0x000f, 0x0040, 0x799c, 0x8fff,
+	0x1040, 0x1332, 0x6824, 0xd0dc, 0x00c0, 0x799c, 0x6800, 0xa086,
+	0x0004, 0x00c0, 0x79a1, 0x784c, 0xd0ac, 0x0040, 0x79a1, 0x784c,
+	0xc0dc, 0xc0f4, 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001,
+	0x0001, 0x682e, 0x0078, 0x79c0, 0x2001, 0x0007, 0x682e, 0x0078,
+	0x79c0, 0x784c, 0xd0b4, 0x00c0, 0x79ae, 0xd0ac, 0x0040, 0x799c,
+	0x784c, 0xd0f4, 0x00c0, 0x799c, 0x0078, 0x798f, 0xd2ec, 0x00c0,
+	0x799c, 0x7024, 0xa306, 0x00c0, 0x79b9, 0x7020, 0xa406, 0x0040,
+	0x799c, 0x7020, 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e,
+	0x1078, 0x8ff0, 0x1078, 0x62d1, 0x0078, 0x79c8, 0x1078, 0x772d,
+	0x047f, 0x037f, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x027e, 0x6034,
+	0x2068, 0x6a1c, 0xa286, 0x0007, 0x0040, 0x7a35, 0xa286, 0x0002,
+	0x0040, 0x7a35, 0xa286, 0x0000, 0x0040, 0x7a35, 0x6808, 0x6338,
+	0xa306, 0x00c0, 0x7a35, 0x2071, 0xab8c, 0xa186, 0x0015, 0x0040,
+	0x7a2f, 0xa18e, 0x0016, 0x00c0, 0x7a02, 0x6030, 0xa084, 0x00ff,
+	0xa086, 0x0001, 0x00c0, 0x7a02, 0x700c, 0xa086, 0x2a00, 0x00c0,
+	0x7a02, 0x6034, 0xa080, 0x0009, 0x200c, 0xc1dd, 0xc1f5, 0x2102,
+	0x0078, 0x7a2f, 0x0c7e, 0x6034, 0x2060, 0x6104, 0xa186, 0x004b,
+	0x0040, 0x7a22, 0xa186, 0x004c, 0x0040, 0x7a22, 0xa186, 0x004d,
+	0x0040, 0x7a22, 0xa186, 0x004e, 0x0040, 0x7a22, 0xa186, 0x0052,
+	0x0040, 0x7a22, 0x6010, 0x2068, 0x1078, 0x8d06, 0x1040, 0x1332,
+	0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002,
+	0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7f, 0x0078, 0x7a35, 0x6034,
+	0x2068, 0x2001, 0xa8a4, 0x2004, 0x683e, 0x1078, 0x772d, 0x027f,
+	0x0d7f, 0x0e7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98, 0x6010,
+	0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x7a73, 0x6018, 0x2068,
+	0x157e, 0x037e, 0x027e, 0xae90, 0x000c, 0xa290, 0x0004, 0x20a9,
+	0x0004, 0xad98, 0x000a, 0x1078, 0x80de, 0x027f, 0x037f, 0x157f,
+	0x00c0, 0x7a76, 0x157e, 0x037e, 0x027e, 0xae90, 0x000c, 0xa290,
+	0x0008, 0x20a9, 0x0004, 0xad98, 0x0006, 0x1078, 0x80de, 0x027f,
+	0x037f, 0x157f, 0x00c0, 0x7a76, 0x7038, 0x680a, 0x703c, 0x680e,
+	0x6800, 0xc08d, 0x6802, 0x0d7f, 0x0078, 0x77f8, 0x1078, 0x2880,
+	0x0c7e, 0x1078, 0x76c7, 0x2f00, 0x601a, 0x6013, 0x0000, 0x601f,
+	0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x2001, 0x0007, 0x1078,
+	0x4502, 0x1078, 0x4535, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0c7f,
+	0x0078, 0x7a73, 0x2100, 0xa1b2, 0x0044, 0x10c8, 0x1332, 0xa1b2,
+	0x0040, 0x00c8, 0x7af7, 0x0079, 0x7a9d, 0x7aeb, 0x7adf, 0x7aeb,
+	0x7aeb, 0x7aeb, 0x7aeb, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add,
+	0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add,
+	0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add,
+	0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb, 0x7add, 0x7aeb, 0x7aeb,
+	0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb, 0x7add, 0x7add,
+	0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7aeb,
+	0x7aeb, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add, 0x7add,
+	0x7add, 0x7add, 0x7aeb, 0x7add, 0x7add, 0x1078, 0x1332, 0x6003,
+	0x0001, 0x6106, 0x1078, 0x5dd7, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x62d1, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5dd7,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x2600,
+	0x0079, 0x7afa, 0x7afe, 0x7afe, 0x7afe, 0x7aeb, 0x1078, 0x1332,
+	0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1332, 0xa1b6, 0x0013, 0x00c0,
+	0x7b10, 0xa0b2, 0x0040, 0x00c8, 0x7c79, 0x2008, 0x0079, 0x7bbf,
+	0xa1b6, 0x0027, 0x00c0, 0x7b7c, 0x1078, 0x61cd, 0x6004, 0x1078,
+	0x8eec, 0x0040, 0x7b2d, 0x1078, 0x8f00, 0x0040, 0x7b74, 0xa08e,
+	0x0021, 0x0040, 0x7b78, 0xa08e, 0x0022, 0x0040, 0x7b74, 0xa08e,
+	0x003d, 0x0040, 0x7b78, 0x0078, 0x7b6f, 0x1078, 0x28a6, 0x2001,
+	0x0007, 0x1078, 0x4502, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078,
+	0x7c83, 0xa186, 0x007e, 0x00c0, 0x7b42, 0x2001, 0xa633, 0x2014,
+	0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019,
+	0x0028, 0x1078, 0x73d0, 0x027f, 0x1078, 0xa4f1, 0x037f, 0x027f,
+	0x017f, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019, 0x0028, 0x1078,
+	0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x0c7e, 0x6018,
+	0xa065, 0x0040, 0x7b65, 0x1078, 0x47e9, 0x0c7f, 0x2c08, 0x1078,
+	0x9f8b, 0x077f, 0x037f, 0x027f, 0x017f, 0x1078, 0x457f, 0x1078,
+	0x772d, 0x1078, 0x62d1, 0x007c, 0x1078, 0x7c83, 0x0078, 0x7b6f,
+	0x1078, 0x7ca6, 0x0078, 0x7b6f, 0xa186, 0x0014, 0x00c0, 0x7b73,
+	0x1078, 0x61cd, 0x1078, 0x2880, 0x1078, 0x8eec, 0x00c0, 0x7b9b,
+	0x1078, 0x28a6, 0x6018, 0xa080, 0x0028, 0x200c, 0x1078, 0x7c83,
+	0xa186, 0x007e, 0x00c0, 0x7b99, 0x2001, 0xa633, 0x200c, 0xc185,
+	0x2102, 0x0078, 0x7b6f, 0x1078, 0x8f00, 0x00c0, 0x7ba3, 0x1078,
+	0x7c83, 0x0078, 0x7b6f, 0x6004, 0xa08e, 0x0032, 0x00c0, 0x7bb4,
+	0x0e7e, 0x0f7e, 0x2071, 0xa682, 0x2079, 0x0000, 0x1078, 0x2bd7,
+	0x0f7f, 0x0e7f, 0x0078, 0x7b6f, 0x6004, 0xa08e, 0x0021, 0x0040,
+	0x7b9f, 0xa08e, 0x0022, 0x1040, 0x7c83, 0x0078, 0x7b6f, 0x7c01,
+	0x7c03, 0x7c07, 0x7c0b, 0x7c0f, 0x7c13, 0x7bff, 0x7bff, 0x7bff,
+	0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
+	0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
+	0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7c17, 0x7c29, 0x7bff,
+	0x7c2b, 0x7c29, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7c29,
+	0x7c29, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff, 0x7bff,
+	0x7bff, 0x7c5c, 0x7c29, 0x7bff, 0x7c23, 0x7bff, 0x7bff, 0x7bff,
+	0x7c25, 0x7bff, 0x7bff, 0x7bff, 0x7c29, 0x7bff, 0x7bff, 0x1078,
+	0x1332, 0x0078, 0x7c29, 0x2001, 0x000b, 0x0078, 0x7c36, 0x2001,
+	0x0003, 0x0078, 0x7c36, 0x2001, 0x0005, 0x0078, 0x7c36, 0x2001,
+	0x0001, 0x0078, 0x7c36, 0x2001, 0x0009, 0x0078, 0x7c36, 0x1078,
+	0x61cd, 0x6003, 0x0005, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x1078,
+	0x62d1, 0x0078, 0x7c35, 0x0078, 0x7c29, 0x0078, 0x7c29, 0x1078,
+	0x4502, 0x0078, 0x7c6e, 0x1078, 0x61cd, 0x6003, 0x0004, 0x2001,
+	0xa8a2, 0x2004, 0x6016, 0x1078, 0x62d1, 0x007c, 0x1078, 0x4502,
+	0x1078, 0x61cd, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002,
+	0x037e, 0x2019, 0xa65d, 0x2304, 0xa084, 0xff00, 0x00c0, 0x7c4d,
+	0x2019, 0xa8a2, 0x231c, 0x0078, 0x7c56, 0x8007, 0xa09a, 0x0004,
+	0x0048, 0x7c48, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x037f,
+	0x1078, 0x62d1, 0x0078, 0x7c35, 0x0e7e, 0x0f7e, 0x2071, 0xa682,
+	0x2079, 0x0000, 0x1078, 0x2bd7, 0x0f7f, 0x0e7f, 0x1078, 0x61cd,
+	0x1078, 0x772d, 0x1078, 0x62d1, 0x0078, 0x7c35, 0x1078, 0x61cd,
+	0x6003, 0x0002, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x1078, 0x62d1,
+	0x007c, 0x2600, 0x2008, 0x0079, 0x7c7d, 0x7c81, 0x7c81, 0x7c81,
+	0x7c6e, 0x1078, 0x1332, 0x0e7e, 0x1078, 0x8d06, 0x0040, 0x7c9f,
+	0x6010, 0x2070, 0x7038, 0xd0fc, 0x0040, 0x7c9f, 0x7007, 0x0000,
+	0x017e, 0x6004, 0xa08e, 0x0021, 0x0040, 0x7ca1, 0xa08e, 0x003d,
+	0x0040, 0x7ca1, 0x017f, 0x7037, 0x0103, 0x7033, 0x0100, 0x0e7f,
+	0x007c, 0x017f, 0x1078, 0x7ca6, 0x0078, 0x7c9f, 0x0e7e, 0xacf0,
+	0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023, 0x8001,
+	0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084, 0x00ff,
+	0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1332, 0x6604, 0xa6b6, 0x0043,
+	0x00c0, 0x7cc6, 0x1078, 0x9134, 0x0078, 0x7d25, 0x6604, 0xa6b6,
+	0x0033, 0x00c0, 0x7ccf, 0x1078, 0x90d8, 0x0078, 0x7d25, 0x6604,
+	0xa6b6, 0x0028, 0x00c0, 0x7cd8, 0x1078, 0x8f2f, 0x0078, 0x7d25,
+	0x6604, 0xa6b6, 0x0029, 0x00c0, 0x7ce1, 0x1078, 0x8f49, 0x0078,
+	0x7d25, 0x6604, 0xa6b6, 0x001f, 0x00c0, 0x7cea, 0x1078, 0x77de,
+	0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0000, 0x00c0, 0x7cf3, 0x1078,
+	0x7a3b, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0022, 0x00c0, 0x7cfc,
+	0x1078, 0x7807, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0035, 0x00c0,
+	0x7d05, 0x1078, 0x7843, 0x0078, 0x7d25, 0x6604, 0xa6b6, 0x0039,
+	0x00c0, 0x7d0e, 0x1078, 0x79cc, 0x0078, 0x7d25, 0x6604, 0xa6b6,
+	0x003d, 0x00c0, 0x7d17, 0x1078, 0x7823, 0x0078, 0x7d25, 0xa1b6,
+	0x0015, 0x00c0, 0x7d1f, 0x1079, 0x7d2a, 0x0078, 0x7d25, 0xa1b6,
+	0x0016, 0x00c0, 0x7d26, 0x1079, 0x7e7f, 0x007c, 0x1078, 0x7773,
+	0x0078, 0x7d25, 0x7d4e, 0x7d51, 0x7d4e, 0x7d9c, 0x7d4e, 0x7e13,
+	0x7e8b, 0x7d4e, 0x7d4e, 0x7e57, 0x7d4e, 0x7e6d, 0xa1b6, 0x0048,
+	0x0040, 0x7d42, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078,
+	0x15fa, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070,
+	0x7037, 0x0103, 0x0e7f, 0x1078, 0x772d, 0x007c, 0x0005, 0x0005,
+	0x007c, 0x0e7e, 0x2071, 0xa600, 0x7080, 0xa086, 0x0074, 0x00c0,
+	0x7d85, 0x1078, 0x9f5f, 0x00c0, 0x7d77, 0x0d7e, 0x6018, 0x2068,
+	0x7030, 0xd08c, 0x0040, 0x7d6a, 0x6800, 0xd0bc, 0x0040, 0x7d6a,
+	0xc0c5, 0x6802, 0x1078, 0x7d89, 0x0d7f, 0x2001, 0x0006, 0x1078,
+	0x4502, 0x1078, 0x28a6, 0x1078, 0x772d, 0x0078, 0x7d87, 0x2001,
+	0x000a, 0x1078, 0x4502, 0x1078, 0x28a6, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x1078, 0x5dd7, 0x0078, 0x7d87, 0x1078, 0x7dff, 0x0e7f,
+	0x007c, 0x6800, 0xd084, 0x0040, 0x7d9b, 0x2001, 0x0000, 0x1078,
+	0x44ee, 0x2069, 0xa652, 0x6804, 0xd0a4, 0x0040, 0x7d9b, 0x2001,
+	0x0006, 0x1078, 0x4535, 0x007c, 0x0d7e, 0x2011, 0xa620, 0x2204,
+	0xa086, 0x0074, 0x00c0, 0x7dfb, 0x6018, 0x2068, 0x6aa0, 0xa286,
+	0x007e, 0x00c0, 0x7daf, 0x1078, 0x7f9b, 0x0078, 0x7dfd, 0x1078,
+	0x7f91, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x0080,
+	0x00c0, 0x7dd3, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005,
+	0x0040, 0x7dc9, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833,
+	0x0200, 0x2001, 0x0006, 0x1078, 0x4502, 0x1078, 0x28a6, 0x1078,
+	0x772d, 0x0078, 0x7dfd, 0x0e7e, 0x2071, 0xa633, 0x2e04, 0xd09c,
+	0x0040, 0x7dee, 0x2071, 0xab80, 0x7108, 0x720c, 0xa18c, 0x00ff,
+	0x00c0, 0x7de6, 0xa284, 0xff00, 0x0040, 0x7dee, 0x6018, 0x2070,
+	0x70a0, 0xd0bc, 0x00c0, 0x7dee, 0x7112, 0x7216, 0x0e7f, 0x2001,
+	0x0004, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0003, 0x1078,
+	0x5dd7, 0x0078, 0x7dfd, 0x1078, 0x7dff, 0x0d7f, 0x007c, 0x2001,
+	0x0007, 0x1078, 0x4502, 0x2001, 0xa600, 0x2004, 0xa086, 0x0003,
+	0x00c0, 0x7e0e, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078, 0x28a6,
+	0x1078, 0x772d, 0x007c, 0x0e7e, 0x2071, 0xa600, 0x7080, 0xa086,
+	0x0014, 0x00c0, 0x7e51, 0x7000, 0xa086, 0x0003, 0x00c0, 0x7e26,
+	0x6010, 0xa005, 0x00c0, 0x7e26, 0x1078, 0x3699, 0x0d7e, 0x6018,
+	0x2068, 0x1078, 0x4649, 0x1078, 0x7d89, 0x0d7f, 0x1078, 0x8043,
+	0x00c0, 0x7e51, 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005,
+	0x0040, 0x7e51, 0x2001, 0x0006, 0x1078, 0x4502, 0x0e7e, 0x6010,
+	0xa005, 0x0040, 0x7e4a, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103,
+	0x7033, 0x0200, 0x0e7f, 0x1078, 0x28a6, 0x1078, 0x772d, 0x0078,
+	0x7e55, 0x1078, 0x7c83, 0x1078, 0x7dff, 0x0e7f, 0x007c, 0x2011,
+	0xa620, 0x2204, 0xa086, 0x0014, 0x00c0, 0x7e6a, 0x2001, 0x0002,
+	0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5dd7,
+	0x0078, 0x7e6c, 0x1078, 0x7dff, 0x007c, 0x2011, 0xa620, 0x2204,
+	0xa086, 0x0004, 0x00c0, 0x7e7c, 0x2001, 0x0007, 0x1078, 0x4502,
+	0x1078, 0x772d, 0x0078, 0x7e7e, 0x1078, 0x7dff, 0x007c, 0x7d4e,
+	0x7e97, 0x7d4e, 0x7ed2, 0x7d4e, 0x7f44, 0x7e8b, 0x7d4e, 0x7d4e,
+	0x7f59, 0x7d4e, 0x7f6c, 0x6604, 0xa686, 0x0003, 0x0040, 0x7e13,
+	0xa6b6, 0x001e, 0x00c0, 0x7e96, 0x1078, 0x772d, 0x007c, 0x0d7e,
+	0x0c7e, 0x1078, 0x7f7f, 0x00c0, 0x7ead, 0x2001, 0x0000, 0x1078,
+	0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007,
+	0x0002, 0x1078, 0x5dd7, 0x0078, 0x7ecf, 0x2009, 0xab8e, 0x2104,
+	0xa086, 0x0009, 0x00c0, 0x7ec2, 0x6018, 0x2068, 0x6840, 0xa084,
+	0x00ff, 0xa005, 0x0040, 0x7ecd, 0x8001, 0x6842, 0x6017, 0x000a,
+	0x0078, 0x7ecf, 0x2009, 0xab8f, 0x2104, 0xa084, 0xff00, 0xa086,
+	0x1900, 0x00c0, 0x7ecd, 0x0078, 0x7ea1, 0x1078, 0x7dff, 0x0c7f,
+	0x0d7f, 0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7ee6, 0x2001, 0x0000,
+	0x1078, 0x44ee, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x1078, 0x5dd7, 0x0078, 0x7f12, 0x1078, 0x7c83,
+	0x2009, 0xab8e, 0x2134, 0xa6b4, 0x00ff, 0xa686, 0x0005, 0x0040,
+	0x7f13, 0xa686, 0x000b, 0x0040, 0x7f10, 0x2009, 0xab8f, 0x2104,
+	0xa084, 0xff00, 0x00c0, 0x7f00, 0xa686, 0x0009, 0x0040, 0x7f13,
+	0xa086, 0x1900, 0x00c0, 0x7f10, 0xa686, 0x0009, 0x0040, 0x7f13,
+	0x2001, 0x0004, 0x1078, 0x4502, 0x1078, 0x772d, 0x0078, 0x7f12,
+	0x1078, 0x7dff, 0x007c, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06,
+	0x0040, 0x7f21, 0x6838, 0xd0fc, 0x0040, 0x7f21, 0x0d7f, 0x0078,
+	0x7f10, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040,
+	0x7f32, 0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x0d7f,
+	0x0078, 0x7f12, 0x68a0, 0xa086, 0x007e, 0x00c0, 0x7f3f, 0x0e7e,
+	0x2071, 0xa600, 0x1078, 0x42b8, 0x0e7f, 0x0078, 0x7f41, 0x1078,
+	0x2880, 0x0d7f, 0x0078, 0x7f10, 0x1078, 0x7f8e, 0x00c0, 0x7f54,
+	0x2001, 0x0004, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0003,
+	0x1078, 0x5dd7, 0x0078, 0x7f58, 0x1078, 0x7c83, 0x1078, 0x7dff,
+	0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7f69, 0x2001, 0x0008, 0x1078,
+	0x4502, 0x6003, 0x0001, 0x6007, 0x0005, 0x1078, 0x5dd7, 0x0078,
+	0x7f6b, 0x1078, 0x7dff, 0x007c, 0x1078, 0x7f8e, 0x00c0, 0x7f7c,
+	0x2001, 0x000a, 0x1078, 0x4502, 0x6003, 0x0001, 0x6007, 0x0001,
+	0x1078, 0x5dd7, 0x0078, 0x7f7e, 0x1078, 0x7dff, 0x007c, 0x2009,
+	0xab8e, 0x2104, 0xa086, 0x0003, 0x00c0, 0x7f8d, 0x2009, 0xab8f,
+	0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x007c, 0xa085, 0x0001,
+	0x007c, 0x0c7e, 0x017e, 0xac88, 0x0006, 0x2164, 0x1078, 0x45d6,
+	0x017f, 0x0c7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e, 0x037e, 0x017e,
+	0x6018, 0x2068, 0x2071, 0xa633, 0x2e04, 0xa085, 0x0003, 0x2072,
+	0x1078, 0x8014, 0x0040, 0x7fd9, 0x2009, 0xa633, 0x2104, 0xc0cd,
+	0x200a, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040, 0x7fc2, 0xa006,
+	0x2020, 0x2009, 0x002a, 0x1078, 0xa21d, 0x2001, 0xa60c, 0x200c,
+	0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x1078, 0x284f,
+	0x2071, 0xa600, 0x1078, 0x2677, 0x0c7e, 0x157e, 0x20a9, 0x0081,
+	0x2009, 0x007f, 0x1078, 0x298e, 0x8108, 0x00f0, 0x7fd2, 0x157f,
+	0x0c7f, 0x1078, 0x7f91, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071,
+	0xab80, 0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0xa61b,
+	0x206a, 0x78e6, 0x007e, 0x8e70, 0x2e04, 0x2069, 0xa61c, 0x206a,
+	0x78ea, 0xa084, 0xff00, 0x017f, 0xa105, 0x2009, 0xa626, 0x200a,
+	0x2069, 0xab8e, 0x2071, 0xa89e, 0x6810, 0x2072, 0x6814, 0x7006,
+	0x6818, 0x700a, 0x681c, 0x700e, 0x1078, 0x906e, 0x2001, 0x0006,
+	0x1078, 0x4502, 0x1078, 0x28a6, 0x1078, 0x772d, 0x017f, 0x037f,
+	0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x037e, 0x0e7e, 0x157e,
+	0x2019, 0xa626, 0x231c, 0x83ff, 0x0040, 0x803e, 0x2071, 0xab80,
+	0x2e14, 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306,
+	0x00c0, 0x803e, 0x2011, 0xab96, 0xad98, 0x000a, 0x20a9, 0x0004,
+	0x1078, 0x80de, 0x00c0, 0x803e, 0x2011, 0xab9a, 0xad98, 0x0006,
+	0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x803e, 0x157f, 0x0e7f,
+	0x037f, 0x027f, 0x007c, 0x0e7e, 0x2071, 0xab8c, 0x7004, 0xa086,
+	0x0014, 0x00c0, 0x8066, 0x7008, 0xa086, 0x0800, 0x00c0, 0x8066,
+	0x700c, 0xd0ec, 0x0040, 0x8064, 0xa084, 0x0f00, 0xa086, 0x0100,
+	0x00c0, 0x8064, 0x7024, 0xd0a4, 0x00c0, 0x8061, 0xd0ac, 0x0040,
+	0x8064, 0xa006, 0x0078, 0x8066, 0xa085, 0x0001, 0x0e7f, 0x007c,
+	0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e,
+	0x127e, 0x2091, 0x8000, 0x2029, 0xa8ba, 0x252c, 0x2021, 0xa8c0,
+	0x2424, 0x2061, 0xad00, 0x2071, 0xa600, 0x7248, 0x7064, 0xa202,
+	0x00c8, 0x80cc, 0x1078, 0xa242, 0x0040, 0x80c4, 0x671c, 0xa786,
+	0x0001, 0x0040, 0x80c4, 0xa786, 0x0007, 0x0040, 0x80c4, 0x2500,
+	0xac06, 0x0040, 0x80c4, 0x2400, 0xac06, 0x0040, 0x80c4, 0x0c7e,
+	0x6000, 0xa086, 0x0004, 0x00c0, 0x809f, 0x1078, 0x1757, 0xa786,
+	0x0008, 0x00c0, 0x80ae, 0x1078, 0x8f00, 0x00c0, 0x80ae, 0x0c7f,
+	0x1078, 0x7c83, 0x1078, 0x8ec6, 0x0078, 0x80c4, 0x6010, 0x2068,
+	0x1078, 0x8d06, 0x0040, 0x80c1, 0xa786, 0x0003, 0x00c0, 0x80d6,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078,
+	0x8eb9, 0x1078, 0x8ec6, 0x0c7f, 0xace0, 0x0010, 0x7058, 0xac02,
+	0x00c8, 0x80cc, 0x0078, 0x807d, 0x127f, 0x007f, 0x027f, 0x047f,
+	0x057f, 0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006,
+	0x00c0, 0x80b8, 0x1078, 0xa1ca, 0x0078, 0x80c1, 0x220c, 0x2304,
+	0xa106, 0x00c0, 0x80e9, 0x8210, 0x8318, 0x00f0, 0x80de, 0xa006,
+	0x007c, 0x2304, 0xa102, 0x0048, 0x80f1, 0x2001, 0x0001, 0x0078,
+	0x80f3, 0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a,
+	0x0044, 0x10c8, 0x1332, 0x1078, 0x8eec, 0x0040, 0x8105, 0x1078,
+	0x8f00, 0x0040, 0x8112, 0x0078, 0x810b, 0x1078, 0x28a6, 0x1078,
+	0x8f00, 0x0040, 0x8112, 0x1078, 0x61cd, 0x1078, 0x772d, 0x1078,
+	0x62d1, 0x007c, 0x1078, 0x7c83, 0x0078, 0x810b, 0xa182, 0x0040,
+	0x0079, 0x811a, 0x812d, 0x812d, 0x812d, 0x812d, 0x812d, 0x812d,
+	0x812d, 0x812d, 0x812d, 0x812d, 0x812d, 0x812f, 0x812f, 0x812f,
+	0x812f, 0x812d, 0x812d, 0x812d, 0x812f, 0x1078, 0x1332, 0x600b,
+	0xffff, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0,
+	0x8146, 0x6004, 0xa082, 0x0040, 0x0079, 0x81d1, 0xa186, 0x0027,
+	0x00c0, 0x8168, 0x1078, 0x61cd, 0x1078, 0x2880, 0x0d7e, 0x6110,
+	0x2168, 0x1078, 0x8d06, 0x0040, 0x8162, 0x6837, 0x0103, 0x684b,
+	0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x1078, 0x4a73,
+	0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d, 0x1078, 0x62d1, 0x007c,
+	0xa186, 0x0014, 0x00c0, 0x8171, 0x6004, 0xa082, 0x0040, 0x0079,
+	0x8199, 0xa186, 0x0046, 0x0040, 0x817d, 0xa186, 0x0045, 0x0040,
+	0x817d, 0xa186, 0x0047, 0x10c0, 0x1332, 0x2001, 0x0109, 0x2004,
+	0xd084, 0x0040, 0x8196, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e,
+	0x027e, 0x1078, 0x5c56, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000,
+	0xa086, 0x0002, 0x00c0, 0x8196, 0x0078, 0x820e, 0x1078, 0x7773,
+	0x007c, 0x81ae, 0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ac,
+	0x81ac, 0x81ac, 0x81ac, 0x81ac, 0x81ca, 0x81ca, 0x81ca, 0x81ca,
+	0x81ac, 0x81ca, 0x81ac, 0x81ca, 0x1078, 0x1332, 0x1078, 0x61cd,
+	0x0d7e, 0x6110, 0x2168, 0x1078, 0x8d06, 0x0040, 0x81c4, 0x6837,
+	0x0103, 0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852,
+	0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d, 0x1078,
+	0x62d1, 0x007c, 0x1078, 0x61cd, 0x1078, 0x772d, 0x1078, 0x62d1,
+	0x007c, 0x81e6, 0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81e4,
+	0x81e4, 0x81e4, 0x81e4, 0x81e4, 0x81f8, 0x81f8, 0x81f8, 0x81f8,
+	0x81e4, 0x8207, 0x81e4, 0x81f8, 0x1078, 0x1332, 0x1078, 0x61cd,
+	0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x62d1,
+	0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c,
+	0x1078, 0x61cd, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x2001, 0xa8a4,
+	0x2004, 0x603e, 0x6003, 0x000f, 0x1078, 0x62d1, 0x007c, 0x1078,
+	0x61cd, 0x1078, 0x772d, 0x1078, 0x62d1, 0x007c, 0xa182, 0x0040,
+	0x0079, 0x8212, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x8227,
+	0x8327, 0x8359, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x8225,
+	0x8225, 0x8225, 0x8225, 0x8225, 0x8225, 0x1078, 0x1332, 0x0e7e,
+	0x0d7e, 0x603f, 0x0000, 0x2071, 0xab80, 0x7124, 0x610a, 0x2071,
+	0xab8c, 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff, 0x0040,
+	0x82e9, 0xa68c, 0x0c00, 0x0040, 0x825e, 0x0f7e, 0x2c78, 0x1078,
+	0x4963, 0x0f7f, 0x0040, 0x825a, 0x684c, 0xd0ac, 0x0040, 0x825a,
+	0x6024, 0xd0dc, 0x00c0, 0x825a, 0x6850, 0xd0bc, 0x00c0, 0x825a,
+	0x7318, 0x6814, 0xa306, 0x00c0, 0x8301, 0x731c, 0x6810, 0xa306,
+	0x00c0, 0x8301, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff,
+	0xa186, 0x0002, 0x0040, 0x8291, 0xa186, 0x0028, 0x00c0, 0x826e,
+	0x1078, 0x8eda, 0x684b, 0x001c, 0x0078, 0x8293, 0xd6dc, 0x0040,
+	0x828a, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0040, 0x8288, 0x6914,
+	0x6a10, 0x2100, 0xa205, 0x0040, 0x8288, 0x7018, 0xa106, 0x00c0,
+	0x8285, 0x701c, 0xa206, 0x0040, 0x8288, 0x6962, 0x6a5e, 0xc6dc,
+	0x0078, 0x8293, 0xd6d4, 0x0040, 0x8291, 0x684b, 0x0007, 0x0078,
+	0x8293, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e, 0xd6c4,
+	0x0040, 0x82bc, 0xa686, 0x0100, 0x00c0, 0x82a7, 0x2001, 0xab99,
+	0x2004, 0xa005, 0x00c0, 0x82a7, 0xc6c4, 0x0078, 0x8236, 0x7328,
+	0x732c, 0x6b56, 0x83ff, 0x0040, 0x82bc, 0xa38a, 0x0009, 0x0048,
+	0x82b3, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90,
+	0x0019, 0x1078, 0x89e2, 0x037f, 0xd6cc, 0x0040, 0x8317, 0x7124,
+	0x695a, 0x81ff, 0x0040, 0x8317, 0xa192, 0x0021, 0x00c8, 0x82d5,
+	0x2071, 0xab98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078,
+	0x89e2, 0x1078, 0x91f4, 0x0078, 0x8317, 0x6838, 0xd0fc, 0x0040,
+	0x82de, 0x2009, 0x0020, 0x695a, 0x0078, 0x82c8, 0x0f7e, 0x2d78,
+	0x1078, 0x897a, 0x0f7f, 0x1078, 0x91f4, 0x1078, 0x89cf, 0x0078,
+	0x8319, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x8307,
+	0x684c, 0xd0ac, 0x0040, 0x8307, 0x6024, 0xd0dc, 0x00c0, 0x8307,
+	0x6850, 0xd0bc, 0x00c0, 0x8307, 0x6810, 0x6914, 0xa105, 0x0040,
+	0x8307, 0x1078, 0x8fbf, 0x0d7f, 0x0e7f, 0x0078, 0x8326, 0x684b,
+	0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x8317,
+	0x6810, 0x6914, 0xa115, 0x0040, 0x8317, 0x1078, 0x84d5, 0x1078,
+	0x4a73, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x1078, 0x8f89,
+	0x0d7f, 0x0e7f, 0x00c0, 0x8326, 0x1078, 0x772d, 0x007c, 0x0f7e,
+	0x6003, 0x0003, 0x2079, 0xab8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08,
+	0x6010, 0x2078, 0x784c, 0xd0ac, 0x0040, 0x833e, 0x6003, 0x0002,
+	0x0f7f, 0x007c, 0x2130, 0x2228, 0x0078, 0x834a, 0x2400, 0x797c,
+	0xa10a, 0x2300, 0x7a80, 0xa213, 0x2600, 0xa102, 0x2500, 0xa203,
+	0x0048, 0x833a, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x603f,
+	0x0000, 0x2c10, 0x1078, 0x1cf0, 0x1078, 0x5df6, 0x1078, 0x639b,
+	0x007c, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110,
+	0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15fa, 0x007c,
+	0xa182, 0x0040, 0x0079, 0x836c, 0x837f, 0x837f, 0x837f, 0x837f,
+	0x837f, 0x8381, 0x8424, 0x837f, 0x837f, 0x843a, 0x84ab, 0x837f,
+	0x837f, 0x837f, 0x837f, 0x84ba, 0x837f, 0x837f, 0x837f, 0x1078,
+	0x1332, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0xab8c, 0x6110,
+	0x2178, 0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e,
+	0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x841f,
+	0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x83a2, 0x7018, 0x7862,
+	0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x841f, 0x1078, 0x138b,
+	0x1040, 0x1332, 0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837,
+	0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46,
+	0xa68c, 0x0c00, 0x0040, 0x83c0, 0x7318, 0x6b62, 0x731c, 0x6b5e,
+	0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x83dc, 0xa186, 0x0028,
+	0x00c0, 0x83ce, 0x684b, 0x001c, 0x0078, 0x83de, 0xd6dc, 0x0040,
+	0x83d5, 0x684b, 0x0015, 0x0078, 0x83de, 0xd6d4, 0x0040, 0x83dc,
+	0x684b, 0x0007, 0x0078, 0x83de, 0x684b, 0x0000, 0x6f4e, 0x7850,
+	0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x83fc, 0x7328,
+	0x732c, 0x6b56, 0x83ff, 0x0040, 0x83fc, 0xa38a, 0x0009, 0x0048,
+	0x83f3, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90,
+	0x0019, 0x1078, 0x89e2, 0x037f, 0xd6cc, 0x0040, 0x841f, 0x7124,
+	0x695a, 0x81ff, 0x0040, 0x841f, 0xa192, 0x0021, 0x00c8, 0x8413,
+	0x2071, 0xab98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078,
+	0x89e2, 0x0078, 0x841f, 0x7838, 0xd0fc, 0x0040, 0x841c, 0x2009,
+	0x0020, 0x695a, 0x0078, 0x8408, 0x2d78, 0x1078, 0x897a, 0x0d7f,
+	0x0e7f, 0x0f7f, 0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079,
+	0xab8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12,
+	0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x1cf0, 0x1078,
+	0x6df4, 0x007c, 0x0d7e, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f,
+	0x0040, 0x8446, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x6003, 0x0002,
+	0x1078, 0x627a, 0x1078, 0x639b, 0x6110, 0x2168, 0x694c, 0xd1e4,
+	0x0040, 0x84a9, 0xd1cc, 0x0040, 0x8480, 0x6948, 0x6838, 0xd0fc,
+	0x0040, 0x8478, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90,
+	0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304,
+	0x2012, 0x8318, 0x8210, 0x00f0, 0x8467, 0x157f, 0x007f, 0x6852,
+	0x007f, 0x684e, 0x017f, 0x2168, 0x1078, 0x13b4, 0x0078, 0x84a3,
+	0x017e, 0x1078, 0x13b4, 0x0d7f, 0x1078, 0x89cf, 0x0078, 0x84a3,
+	0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040,
+	0x849f, 0xa086, 0x0028, 0x00c0, 0x8491, 0x684b, 0x001c, 0x0078,
+	0x84a1, 0xd1dc, 0x0040, 0x8498, 0x684b, 0x0015, 0x0078, 0x84a1,
+	0xd1d4, 0x0040, 0x849f, 0x684b, 0x0007, 0x0078, 0x84a1, 0x684b,
+	0x0000, 0x1078, 0x4a73, 0x1078, 0x8f89, 0x00c0, 0x84a9, 0x1078,
+	0x772d, 0x0d7f, 0x007c, 0x2019, 0x0001, 0x1078, 0x7058, 0x6003,
+	0x0002, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x1078, 0x627a, 0x1078,
+	0x639b, 0x007c, 0x1078, 0x627a, 0x1078, 0x2880, 0x0d7e, 0x6110,
+	0x2168, 0x1078, 0x8d06, 0x0040, 0x84cf, 0x6837, 0x0103, 0x684b,
+	0x0029, 0x6847, 0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f,
+	0x1078, 0x772d, 0x1078, 0x639b, 0x007c, 0x684b, 0x0015, 0xd1fc,
+	0x0040, 0x84e1, 0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189,
+	0x0000, 0x6962, 0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x84e8,
+	0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fd, 0x84fb, 0x85d0,
+	0x85dc, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb, 0x84fb,
+	0x84fb, 0x84fb, 0x84fb, 0x1078, 0x1332, 0x077e, 0x0f7e, 0x0e7e,
+	0x0d7e, 0x2071, 0xab8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff,
+	0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x851b, 0xa684,
+	0x00ff, 0x00c0, 0x851b, 0x6024, 0xd0f4, 0x0040, 0x851b, 0x1078,
+	0x8fbf, 0x0078, 0x85cb, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218,
+	0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x85c0, 0xa694,
+	0xff00, 0xa284, 0x0c00, 0x0040, 0x8531, 0x7018, 0x7862, 0x701c,
+	0x785e, 0xa284, 0x0300, 0x0040, 0x85bd, 0xa686, 0x0100, 0x00c0,
+	0x8543, 0x2001, 0xab99, 0x2004, 0xa005, 0x00c0, 0x8543, 0xc6c4,
+	0x7e46, 0x0078, 0x8524, 0x1078, 0x138b, 0x1040, 0x1332, 0x2d00,
+	0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838,
+	0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00,
+	0x0040, 0x855e, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff,
+	0xa186, 0x0002, 0x0040, 0x857a, 0xa186, 0x0028, 0x00c0, 0x856c,
+	0x684b, 0x001c, 0x0078, 0x857c, 0xd6dc, 0x0040, 0x8573, 0x684b,
+	0x0015, 0x0078, 0x857c, 0xd6d4, 0x0040, 0x857a, 0x684b, 0x0007,
+	0x0078, 0x857c, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854,
+	0x6856, 0xa01e, 0xd6c4, 0x0040, 0x859a, 0x7328, 0x732c, 0x6b56,
+	0x83ff, 0x0040, 0x859a, 0xa38a, 0x0009, 0x0048, 0x8591, 0x2019,
+	0x0008, 0x037e, 0x2308, 0x2019, 0xab98, 0xad90, 0x0019, 0x1078,
+	0x89e2, 0x037f, 0xd6cc, 0x0040, 0x85bd, 0x7124, 0x695a, 0x81ff,
+	0x0040, 0x85bd, 0xa192, 0x0021, 0x00c8, 0x85b1, 0x2071, 0xab98,
+	0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x89e2, 0x0078,
+	0x85bd, 0x7838, 0xd0fc, 0x0040, 0x85ba, 0x2009, 0x0020, 0x695a,
+	0x0078, 0x85a6, 0x2d78, 0x1078, 0x897a, 0xd6dc, 0x00c0, 0x85c3,
+	0xa006, 0x0078, 0x85c9, 0x2001, 0x0001, 0x2071, 0xab8c, 0x7218,
+	0x731c, 0x1078, 0x1653, 0x0d7f, 0x0e7f, 0x0f7f, 0x077f, 0x007c,
+	0x2001, 0xa8a4, 0x2004, 0x603e, 0x20e1, 0x0005, 0x3d18, 0x3e20,
+	0x2c10, 0x1078, 0x15fa, 0x007c, 0x2001, 0xa8a4, 0x2004, 0x603e,
+	0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040,
+	0x870c, 0x603f, 0x0000, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x0f7f,
+	0x0040, 0x8622, 0x6814, 0x6910, 0xa115, 0x0040, 0x8622, 0x6a60,
+	0xa206, 0x00c0, 0x85ff, 0x685c, 0xa106, 0x0040, 0x8622, 0x684c,
+	0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000,
+	0x6024, 0xd0f4, 0x00c0, 0x8617, 0x697c, 0x6810, 0xa102, 0x603a,
+	0x6980, 0x6814, 0xa103, 0x6036, 0x6024, 0xc0f5, 0x6026, 0x0d7e,
+	0x6018, 0x2068, 0x683c, 0x8000, 0x683e, 0x0d7f, 0x1078, 0x8fbf,
+	0x0078, 0x870c, 0x694c, 0xd1cc, 0x0040, 0x86d1, 0x6948, 0x6838,
+	0xd0fc, 0x0040, 0x8689, 0x017e, 0x684c, 0x007e, 0x6850, 0x007e,
+	0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040,
+	0x865c, 0xa086, 0x0028, 0x00c0, 0x8643, 0x684b, 0x001c, 0x784b,
+	0x001c, 0x0078, 0x8667, 0xd1dc, 0x0040, 0x8653, 0x684b, 0x0015,
+	0x784b, 0x0015, 0x1078, 0x916c, 0x0040, 0x8651, 0x7944, 0xc1dc,
+	0x7946, 0x0078, 0x8667, 0xd1d4, 0x0040, 0x865c, 0x684b, 0x0007,
+	0x784b, 0x0007, 0x0078, 0x8667, 0x684c, 0xd0ac, 0x0040, 0x8667,
+	0x6810, 0x6914, 0xa115, 0x0040, 0x8667, 0x1078, 0x84d5, 0x6848,
+	0x784a, 0x6860, 0x7862, 0x685c, 0x785e, 0xad90, 0x000d, 0xaf98,
+	0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318,
+	0x8210, 0x00f0, 0x8675, 0x157f, 0x0f7f, 0x007f, 0x6852, 0x007f,
+	0x684e, 0x1078, 0x91f4, 0x017f, 0x2168, 0x1078, 0x13b4, 0x0078,
+	0x8706, 0x017e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6,
+	0x0002, 0x0040, 0x86b6, 0xa086, 0x0028, 0x00c0, 0x869d, 0x684b,
+	0x001c, 0x784b, 0x001c, 0x0078, 0x86c1, 0xd1dc, 0x0040, 0x86ad,
+	0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x916c, 0x0040, 0x86ab,
+	0x7944, 0xc1dc, 0x7946, 0x0078, 0x86c1, 0xd1d4, 0x0040, 0x86b6,
+	0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x86c1, 0x684c, 0xd0ac,
+	0x0040, 0x86c1, 0x6810, 0x6914, 0xa115, 0x0040, 0x86c1, 0x1078,
+	0x84d5, 0x6860, 0x7862, 0x685c, 0x785e, 0x684c, 0x784e, 0x0f7f,
+	0x1078, 0x13b4, 0x0d7f, 0x1078, 0x91f4, 0x1078, 0x89cf, 0x0078,
+	0x8706, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002,
+	0x0040, 0x86f7, 0xa086, 0x0028, 0x00c0, 0x86e2, 0x684b, 0x001c,
+	0x0078, 0x8704, 0xd1dc, 0x0040, 0x86f0, 0x684b, 0x0015, 0x1078,
+	0x916c, 0x0040, 0x86ee, 0x6944, 0xc1dc, 0x6946, 0x0078, 0x8704,
+	0xd1d4, 0x0040, 0x86f7, 0x684b, 0x0007, 0x0078, 0x8704, 0x684b,
+	0x0000, 0x684c, 0xd0ac, 0x0040, 0x8704, 0x6810, 0x6914, 0xa115,
+	0x0040, 0x8704, 0x1078, 0x84d5, 0x1078, 0x4a73, 0x1078, 0x8f89,
+	0x00c0, 0x870c, 0x1078, 0x772d, 0x0d7f, 0x007c, 0x1078, 0x61cd,
+	0x0078, 0x8714, 0x1078, 0x627a, 0x1078, 0x8d06, 0x0040, 0x8733,
+	0x0d7e, 0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0xa60c, 0x210c,
+	0xd18c, 0x00c0, 0x873e, 0xd184, 0x00c0, 0x873a, 0x6108, 0x694a,
+	0xa18e, 0x0029, 0x00c0, 0x872e, 0x1078, 0xa4e2, 0x6847, 0x0000,
+	0x1078, 0x4a73, 0x0d7f, 0x1078, 0x772d, 0x1078, 0x62d1, 0x1078,
+	0x639b, 0x007c, 0x684b, 0x0004, 0x0078, 0x872e, 0x684b, 0x0004,
+	0x0078, 0x872e, 0xa182, 0x0040, 0x0079, 0x8746, 0x8759, 0x8759,
+	0x8759, 0x8759, 0x8759, 0x875b, 0x8759, 0x875e, 0x8759, 0x8759,
+	0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759, 0x8759,
+	0x8759, 0x1078, 0x1332, 0x1078, 0x772d, 0x007c, 0x007e, 0x027e,
+	0xa016, 0x1078, 0x15fa, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085,
+	0x0079, 0x876a, 0x8773, 0x8771, 0x8771, 0x877f, 0x8771, 0x8771,
+	0x8771, 0x1078, 0x1332, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x027e,
+	0x057e, 0x0d7e, 0x0e7e, 0x2071, 0xab80, 0x7224, 0x6212, 0x7220,
+	0x1078, 0x8cf2, 0x0040, 0x87a4, 0x2268, 0x6800, 0xa086, 0x0000,
+	0x0040, 0x87a4, 0x6018, 0x6d18, 0xa52e, 0x00c0, 0x87a4, 0x0c7e,
+	0x2d60, 0x1078, 0x89f3, 0x0c7f, 0x0040, 0x87a4, 0x6803, 0x0002,
+	0x6007, 0x0086, 0x0078, 0x87a6, 0x6007, 0x0087, 0x6003, 0x0001,
+	0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0f7e, 0x2278, 0x1078, 0x4963,
+	0x0f7f, 0x0040, 0x87be, 0x6824, 0xd0ec, 0x0040, 0x87be, 0x0c7e,
+	0x2260, 0x603f, 0x0000, 0x1078, 0x8fbf, 0x0c7f, 0x0e7f, 0x0d7f,
+	0x057f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x87d4, 0x6004,
+	0xa08a, 0x0085, 0x1048, 0x1332, 0xa08a, 0x008c, 0x10c8, 0x1332,
+	0xa082, 0x0085, 0x0079, 0x87e3, 0xa186, 0x0027, 0x0040, 0x87dc,
+	0xa186, 0x0014, 0x10c0, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6,
+	0x1078, 0x62d1, 0x007c, 0x87ea, 0x87ec, 0x87ec, 0x87ea, 0x87ea,
+	0x87ea, 0x87ea, 0x1078, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6,
+	0x1078, 0x62d1, 0x007c, 0xa186, 0x0013, 0x00c0, 0x87fd, 0x6004,
+	0xa082, 0x0085, 0x2008, 0x0078, 0x8838, 0xa186, 0x0027, 0x00c0,
+	0x8820, 0x1078, 0x61cd, 0x1078, 0x2880, 0x0d7e, 0x6010, 0x2068,
+	0x1078, 0x8d06, 0x0040, 0x8816, 0x6837, 0x0103, 0x6847, 0x0000,
+	0x684b, 0x0029, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078,
+	0x772d, 0x1078, 0x62d1, 0x007c, 0x1078, 0x7773, 0x0078, 0x881b,
+	0xa186, 0x0014, 0x00c0, 0x881c, 0x1078, 0x61cd, 0x0d7e, 0x6010,
+	0x2068, 0x1078, 0x8d06, 0x0040, 0x8816, 0x6837, 0x0103, 0x6847,
+	0x0000, 0x684b, 0x0006, 0x6850, 0xc0ec, 0x6852, 0x0078, 0x8812,
+	0x0079, 0x883a, 0x8843, 0x8841, 0x8841, 0x8841, 0x8841, 0x8841,
+	0x885e, 0x1078, 0x1332, 0x1078, 0x61cd, 0x6030, 0xa08c, 0xff00,
+	0x810f, 0xa186, 0x0039, 0x0040, 0x8851, 0xa186, 0x0035, 0x00c0,
+	0x8855, 0x2001, 0xa8a2, 0x0078, 0x8857, 0x2001, 0xa8a3, 0x2004,
+	0x6016, 0x6003, 0x000c, 0x1078, 0x62d1, 0x007c, 0x1078, 0x61cd,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x886c,
+	0xa186, 0x0035, 0x00c0, 0x8870, 0x2001, 0xa8a2, 0x0078, 0x8872,
+	0x2001, 0xa8a3, 0x2004, 0x6016, 0x6003, 0x000e, 0x1078, 0x62d1,
+	0x007c, 0xa182, 0x008c, 0x00c8, 0x8883, 0xa182, 0x0085, 0x0048,
+	0x8883, 0x0079, 0x8886, 0x1078, 0x7773, 0x007c, 0x888d, 0x888d,
+	0x888d, 0x888d, 0x888f, 0x88ec, 0x888d, 0x1078, 0x1332, 0x0f7e,
+	0x2c78, 0x1078, 0x4963, 0x0f7f, 0x0040, 0x88a2, 0x6030, 0xa08c,
+	0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x8903, 0xa186, 0x0035,
+	0x0040, 0x8903, 0x0d7e, 0x1078, 0x8d06, 0x00c0, 0x88ab, 0x1078,
+	0x8eb9, 0x0078, 0x88ce, 0x6010, 0x2068, 0x684c, 0xd0e4, 0x00c0,
+	0x88b3, 0x1078, 0x8eb9, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040,
+	0x88bf, 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0078, 0x88ca, 0xd0bc,
+	0x0040, 0x88c6, 0x684b, 0x0002, 0x0078, 0x88ca, 0x684b, 0x0005,
+	0x1078, 0x8f85, 0x6847, 0x0000, 0x1078, 0x4a73, 0x2c68, 0x1078,
+	0x76c7, 0x0040, 0x88e7, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009,
+	0xab8e, 0x210c, 0x6136, 0x2009, 0xab8f, 0x210c, 0x613a, 0x6918,
+	0x611a, 0x6920, 0x6122, 0x601f, 0x0001, 0x1078, 0x5d8a, 0x2d60,
+	0x1078, 0x772d, 0x0d7f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4963,
+	0x0f7f, 0x0040, 0x8929, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186,
+	0x0035, 0x0040, 0x8903, 0xa186, 0x001e, 0x0040, 0x8903, 0xa186,
+	0x0039, 0x00c0, 0x8929, 0x0d7e, 0x2c68, 0x1078, 0x91bc, 0x00c0,
+	0x894d, 0x1078, 0x76c7, 0x0040, 0x8926, 0x6106, 0x6003, 0x0001,
+	0x601f, 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, 0x612e,
+	0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, 0x613a,
+	0x6920, 0x6122, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x2d60, 0x0078,
+	0x894d, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x894d,
+	0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x893c, 0xc0ec, 0x6852,
+	0x684b, 0x0006, 0x0078, 0x8947, 0xd0bc, 0x0040, 0x8943, 0x684b,
+	0x0002, 0x0078, 0x8947, 0x684b, 0x0005, 0x1078, 0x8f85, 0x6847,
+	0x0000, 0x1078, 0x4a73, 0x1078, 0x8eb9, 0x0d7f, 0x1078, 0x772d,
+	0x007c, 0x017e, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040,
+	0x8961, 0x6837, 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x1078,
+	0x4a73, 0x0d7f, 0x017f, 0xa186, 0x0013, 0x0040, 0x8973, 0xa186,
+	0x0014, 0x0040, 0x8973, 0xa186, 0x0027, 0x0040, 0x8973, 0x1078,
+	0x7773, 0x0078, 0x8979, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078,
+	0x62d1, 0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001,
+	0xa182, 0x0101, 0x00c8, 0x8986, 0x0078, 0x8988, 0x2009, 0x0100,
+	0x2130, 0x2069, 0xab98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020,
+	0xaf90, 0x001d, 0x1078, 0x89e2, 0xa6b2, 0x0020, 0x7804, 0xa06d,
+	0x0040, 0x899c, 0x1078, 0x13b4, 0x1078, 0x138b, 0x0040, 0x89c6,
+	0x8528, 0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a,
+	0x003d, 0x00c8, 0x89b2, 0x2608, 0xad90, 0x000f, 0x1078, 0x89e2,
+	0x0078, 0x89c6, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90,
+	0x000f, 0x1078, 0x89e2, 0x0078, 0x899c, 0x0f7f, 0x852f, 0xa5ad,
+	0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0078, 0x89cb, 0x0f7f, 0x852f,
+	0xa5ad, 0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e,
+	0x8dff, 0x0040, 0x89e0, 0x6804, 0xa07d, 0x0040, 0x89de, 0x6807,
+	0x0000, 0x1078, 0x4a73, 0x2f68, 0x0078, 0x89d3, 0x1078, 0x4a73,
+	0x0f7f, 0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x89e8, 0x8108,
+	0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0,
+	0x89ea, 0x157f, 0x007c, 0x067e, 0x127e, 0x2091, 0x8000, 0x2031,
+	0x0001, 0x601c, 0xa084, 0x000f, 0x1079, 0x8a0f, 0x127f, 0x067f,
+	0x007c, 0x127e, 0x2091, 0x8000, 0x067e, 0x2031, 0x0000, 0x601c,
+	0xa084, 0x000f, 0x1079, 0x8a0f, 0x067f, 0x127f, 0x007c, 0x8a29,
+	0x8a17, 0x8a24, 0x8a45, 0x8a17, 0x8a24, 0x8a45, 0x8a24, 0x1078,
+	0x1332, 0x037e, 0x2019, 0x0010, 0x1078, 0x9dc7, 0x601f, 0x0006,
+	0x6003, 0x0007, 0x037f, 0x007c, 0xa006, 0x007c, 0xa085, 0x0001,
+	0x007c, 0x0d7e, 0x86ff, 0x00c0, 0x8a40, 0x6010, 0x2068, 0x1078,
+	0x8d06, 0x0040, 0x8a42, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4b51,
+	0x1078, 0x8f85, 0x1078, 0x4a73, 0x1078, 0x772d, 0xa085, 0x0001,
+	0x0d7f, 0x007c, 0xa006, 0x0078, 0x8a40, 0x6000, 0xa08a, 0x0010,
+	0x10c8, 0x1332, 0x1079, 0x8a4d, 0x007c, 0x8a5d, 0x8a82, 0x8a5f,
+	0x8aa5, 0x8a7e, 0x8a5d, 0x8a24, 0x8a29, 0x8a29, 0x8a24, 0x8a24,
+	0x8a24, 0x8a24, 0x8a24, 0x8a24, 0x8a24, 0x1078, 0x1332, 0x86ff,
+	0x00c0, 0x8a7b, 0x601c, 0xa086, 0x0006, 0x0040, 0x8a7b, 0x0d7e,
+	0x6010, 0x2068, 0x1078, 0x8d06, 0x0040, 0x8a70, 0x1078, 0x8f85,
+	0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078,
+	0x5d8a, 0x1078, 0x62d1, 0xa085, 0x0001, 0x007c, 0x1078, 0x1757,
+	0x0078, 0x8a5f, 0x0e7e, 0x2071, 0xa8b1, 0x7024, 0xac06, 0x00c0,
+	0x8a8b, 0x1078, 0x6fc4, 0x601c, 0xa084, 0x000f, 0xa086, 0x0006,
+	0x00c0, 0x8a9d, 0x087e, 0x097e, 0x2049, 0x0001, 0x2c40, 0x1078,
+	0x7246, 0x097f, 0x087f, 0x0078, 0x8a9f, 0x1078, 0x6ebe, 0x0e7f,
+	0x00c0, 0x8a5f, 0x1078, 0x8a24, 0x007c, 0x037e, 0x0e7e, 0x2071,
+	0xa8b1, 0x703c, 0xac06, 0x00c0, 0x8ab5, 0x2019, 0x0000, 0x1078,
+	0x7058, 0x0e7f, 0x037f, 0x0078, 0x8a5f, 0x1078, 0x738a, 0x0e7f,
+	0x037f, 0x00c0, 0x8a5f, 0x1078, 0x8a24, 0x007c, 0x0c7e, 0x601c,
+	0xa084, 0x000f, 0x1079, 0x8ac6, 0x0c7f, 0x007c, 0x8ad5, 0x8b47,
+	0x8c7f, 0x8ae0, 0x8ec6, 0x8ad5, 0x9db8, 0x772d, 0x8b47, 0x1078,
+	0x8f00, 0x00c0, 0x8ad5, 0x1078, 0x7c83, 0x007c, 0x1078, 0x61cd,
+	0x1078, 0x62d1, 0x1078, 0x772d, 0x007c, 0x6017, 0x0001, 0x007c,
+	0x1078, 0x8d06, 0x0040, 0x8ae8, 0x6010, 0xa080, 0x0019, 0x2c02,
+	0x6000, 0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8af0, 0x007c,
+	0x8b00, 0x8b02, 0x8b24, 0x8b36, 0x8b43, 0x8b00, 0x8ad5, 0x8ad5,
+	0x8ad5, 0x8b36, 0x8b36, 0x8b00, 0x8b00, 0x8b00, 0x8b00, 0x8b40,
+	0x1078, 0x1332, 0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052,
+	0x2071, 0xa8b1, 0x7024, 0xac06, 0x0040, 0x8b20, 0x1078, 0x6ebe,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xa8a3,
+	0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0e7f, 0x007c,
+	0x6017, 0x0001, 0x0078, 0x8b1e, 0x0d7e, 0x6010, 0x2068, 0x6850,
+	0xc0b5, 0x6852, 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f,
+	0x0002, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x007c, 0x0d7e, 0x6017,
+	0x0001, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x007c,
+	0x1078, 0x772d, 0x007c, 0x1078, 0x1757, 0x0078, 0x8b24, 0x6000,
+	0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8b4f, 0x007c, 0x8b5f,
+	0x8add, 0x8b61, 0x8b5f, 0x8b61, 0x8b61, 0x8ad6, 0x8b5f, 0x8acf,
+	0x8acf, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x8b5f, 0x1078,
+	0x1332, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f,
+	0xa08a, 0x000c, 0x10c8, 0x1332, 0x1079, 0x8b6f, 0x007c, 0x8b7b,
+	0x8c23, 0x8b7d, 0x8bbd, 0x8b7d, 0x8bbd, 0x8b7d, 0x8b8a, 0x8b7b,
+	0x8bbd, 0x8b7b, 0x8ba7, 0x1078, 0x1332, 0x6004, 0xa08e, 0x0016,
+	0x0040, 0x8bb8, 0xa08e, 0x0004, 0x0040, 0x8bb8, 0xa08e, 0x0002,
+	0x0040, 0x8bb8, 0x6004, 0x1078, 0x8f00, 0x0040, 0x8c3e, 0xa08e,
+	0x0021, 0x0040, 0x8c42, 0xa08e, 0x0022, 0x0040, 0x8c3e, 0xa08e,
+	0x003d, 0x0040, 0x8c42, 0xa08e, 0x0039, 0x0040, 0x8c46, 0xa08e,
+	0x0035, 0x0040, 0x8c46, 0xa08e, 0x001e, 0x0040, 0x8bba, 0xa08e,
+	0x0001, 0x00c0, 0x8bb6, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084,
+	0x00ff, 0x0d7f, 0xa086, 0x0006, 0x0040, 0x8bb8, 0x1078, 0x2880,
+	0x1078, 0x7c83, 0x1078, 0x8ec6, 0x007c, 0x0c7e, 0x0d7e, 0x6104,
+	0xa186, 0x0016, 0x0040, 0x8c13, 0xa186, 0x0002, 0x00c0, 0x8be6,
+	0x6018, 0x2068, 0x68a0, 0xd0bc, 0x00c0, 0x8c6a, 0x6840, 0xa084,
+	0x00ff, 0xa005, 0x0040, 0x8be6, 0x8001, 0x6842, 0x6013, 0x0000,
+	0x601f, 0x0007, 0x6017, 0x0398, 0x1078, 0x76c7, 0x0040, 0x8be6,
+	0x2d00, 0x601a, 0x601f, 0x0001, 0x0078, 0x8c13, 0x0d7f, 0x0c7f,
+	0x6004, 0xa08e, 0x0002, 0x00c0, 0x8c04, 0x6018, 0xa080, 0x0028,
+	0x2004, 0xa086, 0x007e, 0x00c0, 0x8c04, 0x2009, 0xa633, 0x2104,
+	0xc085, 0x200a, 0x0e7e, 0x2071, 0xa600, 0x1078, 0x42b8, 0x0e7f,
+	0x1078, 0x7c83, 0x0078, 0x8c08, 0x1078, 0x7c83, 0x1078, 0x2880,
+	0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x28a6, 0x127f, 0x0e7f,
+	0x1078, 0x8ec6, 0x007c, 0x2001, 0x0002, 0x1078, 0x4502, 0x6003,
+	0x0001, 0x6007, 0x0002, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0d7f,
+	0x0c7f, 0x0078, 0x8c12, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016,
+	0x0040, 0x8c13, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005,
+	0x0040, 0x8be6, 0x8001, 0x6842, 0x6003, 0x0001, 0x1078, 0x5dd7,
+	0x1078, 0x62d1, 0x0d7f, 0x0c7f, 0x0078, 0x8c12, 0x1078, 0x7c83,
+	0x0078, 0x8bba, 0x1078, 0x7ca6, 0x0078, 0x8bba, 0x0d7e, 0x2c68,
+	0x6104, 0x1078, 0x91bc, 0x0d7f, 0x0040, 0x8c52, 0x1078, 0x772d,
+	0x0078, 0x8c69, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105,
+	0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038,
+	0x600a, 0x2001, 0xa8a3, 0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078,
+	0x62d1, 0x007c, 0x0d7f, 0x0c7f, 0x1078, 0x7c83, 0x1078, 0x2880,
+	0x0e7e, 0x127e, 0x2091, 0x8000, 0x1078, 0x28a6, 0x6013, 0x0000,
+	0x601f, 0x0007, 0x6017, 0x0398, 0x127f, 0x0e7f, 0x007c, 0x6000,
+	0xa08a, 0x0010, 0x10c8, 0x1332, 0x1079, 0x8c87, 0x007c, 0x8c97,
+	0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97, 0x8c97,
+	0x8ad5, 0x8c97, 0x8add, 0x8c99, 0x8add, 0x8ca7, 0x8c97, 0x1078,
+	0x1332, 0x6004, 0xa086, 0x008b, 0x0040, 0x8ca7, 0x6007, 0x008b,
+	0x6003, 0x000d, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x007c, 0x1078,
+	0x8eb9, 0x1078, 0x8d06, 0x0040, 0x8cdf, 0x1078, 0x2880, 0x0d7e,
+	0x1078, 0x8d06, 0x0040, 0x8cc1, 0x6010, 0x2068, 0x6837, 0x0103,
+	0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x1078,
+	0x4a73, 0x2c68, 0x1078, 0x76c7, 0x0040, 0x8ccf, 0x6818, 0x601a,
+	0x0c7e, 0x2d60, 0x1078, 0x8ec6, 0x0c7f, 0x0078, 0x8cd0, 0x2d60,
+	0x0d7f, 0x6013, 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003,
+	0x0001, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0078, 0x8cf1, 0x6030,
+	0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x8ceb, 0xa186,
+	0x0035, 0x00c0, 0x8cef, 0x1078, 0x2880, 0x0078, 0x8cc1, 0x1078,
+	0x8ec6, 0x007c, 0xa284, 0x000f, 0x00c0, 0x8d03, 0xa282, 0xad00,
+	0x0048, 0x8d03, 0x2001, 0xa616, 0x2004, 0xa202, 0x00c8, 0x8d03,
+	0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x8d02, 0x027e, 0x0e7e,
+	0x2071, 0xa600, 0x6210, 0x705c, 0xa202, 0x0048, 0x8d18, 0x7060,
+	0xa202, 0x00c8, 0x8d18, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c,
+	0xa006, 0x0078, 0x8d15, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e,
+	0x2091, 0x8000, 0x2061, 0xad00, 0x2071, 0xa600, 0x7348, 0x7064,
+	0xa302, 0x00c8, 0x8d45, 0x601c, 0xa206, 0x00c0, 0x8d3d, 0x1078,
+	0x902b, 0x0040, 0x8d3d, 0x1078, 0x8f00, 0x00c0, 0x8d39, 0x1078,
+	0x7c83, 0x0c7e, 0x1078, 0x772d, 0x0c7f, 0xace0, 0x0010, 0x7058,
+	0xac02, 0x00c8, 0x8d45, 0x0078, 0x8d26, 0x127f, 0x007f, 0x037f,
+	0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0xa735,
+	0x210c, 0x81ff, 0x0040, 0x8d59, 0x2061, 0xa9b3, 0x611a, 0x1078,
+	0x2880, 0xa006, 0x0078, 0x8d5e, 0xa085, 0x0001, 0x017f, 0x0c7f,
+	0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e,
+	0x1078, 0x76c7, 0x057f, 0x0040, 0x8d7b, 0x6612, 0x651a, 0x601f,
+	0x0003, 0x2009, 0x004b, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f,
+	0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8d77, 0x0c7e, 0x057e,
+	0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x76c7, 0x057f,
+	0x0040, 0x8da9, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e,
+	0x2560, 0x1078, 0x47e9, 0x0c7f, 0x1078, 0x5f01, 0x077e, 0x2039,
+	0x0000, 0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f, 0x2009,
+	0x004c, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f,
+	0x007c, 0xa006, 0x0078, 0x8da5, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e,
+	0x1078, 0x76c7, 0x2c78, 0x0c7f, 0x0040, 0x8dc6, 0x7e12, 0x2c00,
+	0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x1078, 0x8e11, 0x2f60,
+	0x2009, 0x004d, 0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f,
+	0x0f7f, 0x007c, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x76c7,
+	0x2c78, 0x0c7f, 0x0040, 0x8de4, 0x7e12, 0x2c00, 0x781a, 0x781f,
+	0x0003, 0x2021, 0x0005, 0x1078, 0x8e11, 0x2f60, 0x2009, 0x004e,
+	0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c,
+	0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x76c7, 0x2c78, 0x0c7f,
+	0x0040, 0x8e0d, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021,
+	0x0004, 0x1078, 0x8e11, 0x2001, 0xa89d, 0x2004, 0xd0fc, 0x0040,
+	0x8e06, 0x2f60, 0x1078, 0x772d, 0x0078, 0x8e0b, 0x2f60, 0x2009,
+	0x0052, 0x1078, 0x775c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f,
+	0x007c, 0x097e, 0x077e, 0x127e, 0x2091, 0x8000, 0x1078, 0x4775,
+	0x0040, 0x8e1e, 0x2001, 0x8e16, 0x0078, 0x8e24, 0x1078, 0x4739,
+	0x0040, 0x8e2d, 0x2001, 0x8e1e, 0x007e, 0xa00e, 0x2400, 0x1078,
+	0x4b51, 0x1078, 0x4a73, 0x007f, 0x007a, 0x2418, 0x1078, 0x6161,
+	0x62a0, 0x087e, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x1078,
+	0x5f1b, 0x087f, 0x1078, 0x5e0a, 0x2f08, 0x2648, 0x1078, 0x9f8b,
+	0x613c, 0x81ff, 0x1040, 0x5fdb, 0x1078, 0x62d1, 0x127f, 0x077f,
+	0x097f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078,
+	0x76c7, 0x017f, 0x0040, 0x8e63, 0x660a, 0x611a, 0x601f, 0x0001,
+	0x2d00, 0x6012, 0x2009, 0x001f, 0x1078, 0x775c, 0xa085, 0x0001,
+	0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e60, 0x0c7e, 0x127e,
+	0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x8e7f,
+	0x660a, 0x611a, 0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021,
+	0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006,
+	0x0078, 0x8e7c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078,
+	0x76c7, 0x017f, 0x0040, 0x8e9b, 0x660a, 0x611a, 0x601f, 0x0001,
+	0x2d00, 0x6012, 0x2009, 0x003d, 0x1078, 0x775c, 0xa085, 0x0001,
+	0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e98, 0x0c7e, 0x127e,
+	0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x8eb6,
+	0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x1078,
+	0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078,
+	0x8eb3, 0x027e, 0x0d7e, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0040,
+	0x8ec3, 0x8211, 0x6a3e, 0x0d7f, 0x027f, 0x007c, 0x007e, 0x6000,
+	0xa086, 0x0000, 0x0040, 0x8ed8, 0x6013, 0x0000, 0x601f, 0x0007,
+	0x2001, 0xa8a3, 0x2004, 0x6016, 0x1078, 0xa495, 0x603f, 0x0000,
+	0x007f, 0x007c, 0x067e, 0x0c7e, 0x0d7e, 0x2031, 0xa653, 0x2634,
+	0xd6e4, 0x0040, 0x8ee8, 0x6618, 0x2660, 0x6e48, 0x1078, 0x46e7,
+	0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e,
+	0x0002, 0x0040, 0x8efd, 0xa08e, 0x0003, 0x0040, 0x8efd, 0xa08e,
+	0x0004, 0x0040, 0x8efd, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c,
+	0x007e, 0x0d7e, 0x6010, 0xa06d, 0x0040, 0x8f0d, 0x6838, 0xd0fc,
+	0x0040, 0x8f0d, 0xa006, 0x0078, 0x8f0f, 0xa085, 0x0001, 0x0d7f,
+	0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078,
+	0x76c7, 0x017f, 0x0040, 0x8f2c, 0x611a, 0x601f, 0x0001, 0x2d00,
+	0x6012, 0x1078, 0x2880, 0x2009, 0x0028, 0x1078, 0x775c, 0xa085,
+	0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8f29, 0xa186,
+	0x0015, 0x00c0, 0x8f44, 0x2011, 0xa620, 0x2204, 0xa086, 0x0074,
+	0x00c0, 0x8f44, 0x1078, 0x7f91, 0x6003, 0x0001, 0x6007, 0x0029,
+	0x1078, 0x5dd7, 0x0078, 0x8f48, 0x1078, 0x7c83, 0x1078, 0x772d,
+	0x007c, 0xa186, 0x0016, 0x00c0, 0x8f53, 0x2001, 0x0004, 0x1078,
+	0x4502, 0x0078, 0x8f74, 0xa186, 0x0015, 0x00c0, 0x8f78, 0x2011,
+	0xa620, 0x2204, 0xa086, 0x0014, 0x00c0, 0x8f78, 0x0d7e, 0x6018,
+	0x2068, 0x1078, 0x4649, 0x0d7f, 0x1078, 0x8043, 0x00c0, 0x8f78,
+	0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, 0x0040, 0x8f78,
+	0x2001, 0x0006, 0x1078, 0x4502, 0x1078, 0x77f8, 0x0078, 0x8f7c,
+	0x1078, 0x7c83, 0x1078, 0x772d, 0x007c, 0x6848, 0xa086, 0x0005,
+	0x00c0, 0x8f84, 0x1078, 0x8f85, 0x007c, 0x6850, 0xc0ad, 0x6852,
+	0x007c, 0x0e7e, 0x2071, 0xab8c, 0x7014, 0xd0e4, 0x0040, 0x8f9a,
+	0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x1078, 0x5d8a,
+	0x1078, 0x62d1, 0x0e7f, 0x007c, 0x0c7e, 0x0f7e, 0x2c78, 0x1078,
+	0x4963, 0x0f7f, 0x0040, 0x8fa9, 0x601c, 0xa084, 0x000f, 0x1079,
+	0x8fab, 0x0c7f, 0x007c, 0x8ad5, 0x8fb6, 0x8fb9, 0x8fbc, 0xa25d,
+	0xa279, 0xa27c, 0x8ad5, 0x8ad5, 0x1078, 0x1332, 0x0005, 0x0005,
+	0x007c, 0x0005, 0x0005, 0x007c, 0x1078, 0x8fbf, 0x007c, 0x0f7e,
+	0x2c78, 0x1078, 0x4963, 0x0040, 0x8fee, 0x1078, 0x76c7, 0x00c0,
+	0x8fcf, 0x2001, 0xa8a4, 0x2004, 0x783e, 0x0078, 0x8fee, 0x7818,
+	0x601a, 0x781c, 0xa086, 0x0003, 0x0040, 0x8fdc, 0x7808, 0x6036,
+	0x2f00, 0x603a, 0x0078, 0x8fe0, 0x7808, 0x603a, 0x2f00, 0x6036,
+	0x602a, 0x601f, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, 0x7920,
+	0x6122, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x2f60, 0x0f7f, 0x007c,
+	0x017e, 0x0f7e, 0x682c, 0x6032, 0xa08e, 0x0001, 0x0040, 0x9001,
+	0xa086, 0x0005, 0x0040, 0x9005, 0xa006, 0x602a, 0x602e, 0x0078,
+	0x9016, 0x6824, 0xc0f4, 0xc0d5, 0x6826, 0x6810, 0x2078, 0x787c,
+	0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x00c8, 0x8ffc, 0x6834,
+	0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036,
+	0x6808, 0x603a, 0x6918, 0x611a, 0x6920, 0x6122, 0x601f, 0x0001,
+	0x6007, 0x0039, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x6803, 0x0002,
+	0x0f7f, 0x017f, 0x007c, 0x007e, 0x017e, 0x6004, 0xa08e, 0x0034,
+	0x0040, 0x9050, 0xa08e, 0x0035, 0x0040, 0x9050, 0xa08e, 0x0036,
+	0x0040, 0x9050, 0xa08e, 0x0037, 0x0040, 0x9050, 0xa08e, 0x0038,
+	0x0040, 0x9050, 0xa08e, 0x0039, 0x0040, 0x9050, 0xa08e, 0x003a,
+	0x0040, 0x9050, 0xa08e, 0x003b, 0x0040, 0x9050, 0xa085, 0x0001,
+	0x017f, 0x007f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4963, 0x00c0,
+	0x905d, 0xa085, 0x0001, 0x0078, 0x906c, 0x6024, 0xd0f4, 0x00c0,
+	0x906b, 0xc0f5, 0x6026, 0x6010, 0x2078, 0x7828, 0x603a, 0x782c,
+	0x6036, 0x1078, 0x1757, 0xa006, 0x0f7f, 0x007c, 0x007e, 0x017e,
+	0x027e, 0x037e, 0x0e7e, 0x2001, 0xa89e, 0x200c, 0x8000, 0x2014,
+	0x2001, 0x0032, 0x1078, 0x5c1c, 0x2001, 0xa8a2, 0x82ff, 0x00c0,
+	0x9083, 0x2011, 0x0014, 0x2202, 0x2001, 0xa8a0, 0x200c, 0x8000,
+	0x2014, 0x2071, 0xa88d, 0x711a, 0x721e, 0x2001, 0x0064, 0x1078,
+	0x5c1c, 0x2001, 0xa8a3, 0x82ff, 0x00c0, 0x9098, 0x2011, 0x0014,
+	0x2202, 0x2009, 0xa8a4, 0xa280, 0x000a, 0x200a, 0x1078, 0x498b,
+	0x0e7f, 0x037f, 0x027f, 0x017f, 0x007f, 0x007c, 0x007e, 0x0e7e,
+	0x2001, 0xa8a2, 0x2003, 0x0028, 0x2001, 0xa8a3, 0x2003, 0x0014,
+	0x2071, 0xa88d, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001, 0xa8a4,
+	0x2003, 0x001e, 0x0e7f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091,
+	0x8000, 0x0c7e, 0x1078, 0x76c7, 0x017f, 0x0040, 0x90d5, 0x611a,
+	0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x1078, 0x775c,
+	0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x90d2,
+	0x0d7e, 0x0e7e, 0x0f7e, 0x2071, 0xa600, 0xa186, 0x0015, 0x00c0,
+	0x9107, 0x7080, 0xa086, 0x0018, 0x00c0, 0x9107, 0x6010, 0x2068,
+	0x6a3c, 0xd2e4, 0x00c0, 0x90fb, 0x2c78, 0x1078, 0x6490, 0x0040,
+	0x910f, 0x706c, 0x6a50, 0xa206, 0x00c0, 0x9103, 0x7070, 0x6a54,
+	0xa206, 0x00c0, 0x9103, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009,
+	0x0000, 0x1078, 0x28c8, 0x1078, 0x77f8, 0x0078, 0x910b, 0x1078,
+	0x7c83, 0x1078, 0x772d, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x7050,
+	0xa080, 0x29c0, 0x2004, 0x6a54, 0xa206, 0x0040, 0x90fb, 0x0078,
+	0x9103, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x76c7,
+	0x017f, 0x0040, 0x9131, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012,
+	0x2009, 0x0043, 0x1078, 0x775c, 0xa085, 0x0001, 0x127f, 0x0c7f,
+	0x007c, 0xa006, 0x0078, 0x912e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071,
+	0xa600, 0xa186, 0x0015, 0x00c0, 0x915a, 0x7080, 0xa086, 0x0004,
+	0x00c0, 0x915a, 0x6010, 0xa0e8, 0x000f, 0x2c78, 0x1078, 0x6490,
+	0x0040, 0x9162, 0x706c, 0x6a08, 0xa206, 0x00c0, 0x9156, 0x7070,
+	0x6a0c, 0xa206, 0x00c0, 0x9156, 0x1078, 0x2880, 0x1078, 0x77f8,
+	0x0078, 0x915e, 0x1078, 0x7c83, 0x1078, 0x772d, 0x0f7f, 0x0e7f,
+	0x0d7f, 0x007c, 0x7050, 0xa080, 0x29c0, 0x2004, 0x6a0c, 0xa206,
+	0x0040, 0x9154, 0x0078, 0x9156, 0x017e, 0x027e, 0x684c, 0xd0ac,
+	0x0040, 0x9184, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, 0x9184,
+	0x6860, 0xa106, 0x00c0, 0x9180, 0x685c, 0xa206, 0x0040, 0x9184,
+	0x6962, 0x6a5e, 0xa085, 0x0001, 0x027f, 0x017f, 0x007c, 0x0e7e,
+	0x127e, 0x2071, 0xa600, 0x2091, 0x8000, 0x7548, 0xa582, 0x0001,
+	0x0048, 0x91b9, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040,
+	0x91a5, 0xace0, 0x0010, 0x7058, 0xac02, 0x00c8, 0x91a1, 0x0078,
+	0x9194, 0x2061, 0xad00, 0x0078, 0x9194, 0x6003, 0x0008, 0x8529,
+	0x754a, 0xaca8, 0x0010, 0x7058, 0xa502, 0x00c8, 0x91b5, 0x754e,
+	0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704f, 0xad00, 0x0078,
+	0x91b0, 0xa006, 0x0078, 0x91b2, 0x0c7e, 0x027e, 0x017e, 0xa186,
+	0x0035, 0x0040, 0x91c6, 0x6a34, 0x0078, 0x91c7, 0x6a28, 0x1078,
+	0x8cf2, 0x0040, 0x91f0, 0x2260, 0x611c, 0xa186, 0x0003, 0x0040,
+	0x91d5, 0xa186, 0x0006, 0x00c0, 0x91ec, 0x6834, 0xa206, 0x0040,
+	0x91e4, 0x6838, 0xa206, 0x00c0, 0x91ec, 0x6108, 0x6834, 0xa106,
+	0x00c0, 0x91ec, 0x0078, 0x91e9, 0x6008, 0x6938, 0xa106, 0x00c0,
+	0x91ec, 0x6018, 0x6918, 0xa106, 0x017f, 0x027f, 0x0c7f, 0x007c,
+	0xa085, 0x0001, 0x0078, 0x91ec, 0x6944, 0xd1cc, 0x0040, 0x920d,
+	0xa18c, 0x00ff, 0xa18e, 0x0002, 0x00c0, 0x920d, 0xad88, 0x001e,
+	0x210c, 0xa18c, 0x0f00, 0x810f, 0xa18e, 0x0001, 0x00c0, 0x920d,
+	0x6810, 0x6914, 0xa115, 0x10c0, 0x84d5, 0x007c, 0x067e, 0x6000,
+	0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x9218, 0x067f, 0x007c,
+	0x9228, 0x96df, 0x97fb, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228,
+	0x9262, 0x988e, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228, 0x9228,
+	0x1078, 0x1332, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1332,
+	0x1079, 0x9234, 0x067f, 0x007c, 0x9244, 0x9d53, 0x9244, 0x9244,
+	0x9244, 0x9244, 0x9244, 0x9244, 0x9d11, 0x9da1, 0x9244, 0xa3b0,
+	0xa3e4, 0xa3b0, 0xa3e4, 0x9244, 0x1078, 0x1332, 0x067e, 0x6000,
+	0xa0b2, 0x0010, 0x10c8, 0x1332, 0x1079, 0x9250, 0x067f, 0x007c,
+	0x9260, 0x99eb, 0x9ac7, 0x9af5, 0x9b70, 0x9260, 0x9c76, 0x9c1e,
+	0x989a, 0x9ce5, 0x9cfb, 0x9260, 0x9260, 0x9260, 0x9260, 0x9260,
+	0x1078, 0x1332, 0xa1b2, 0x0044, 0x10c8, 0x1332, 0x2100, 0x0079,
+	0x9269, 0x92a9, 0x9498, 0x92a9, 0x92a9, 0x92a9, 0x94a0, 0x92a9,
+	0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9,
+	0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9,
+	0x92ab, 0x9311, 0x9320, 0x9377, 0x9396, 0x9415, 0x9485, 0x92a9,
+	0x92a9, 0x94a4, 0x92a9, 0x92a9, 0x94b7, 0x94c2, 0x92a9, 0x92a9,
+	0x92a9, 0x92a9, 0x92a9, 0x94fa, 0x92a9, 0x92a9, 0x9509, 0x92a9,
+	0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x9522, 0x92a9, 0x92a9,
+	0x92a9, 0x95af, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9, 0x92a9,
+	0x9629, 0x1078, 0x1332, 0x1078, 0x4967, 0x00c0, 0x92bb, 0x2001,
+	0xa633, 0x2004, 0xd0cc, 0x00c0, 0x92bb, 0xa084, 0x0009, 0xa086,
+	0x0008, 0x00c0, 0x92c3, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013,
+	0x0000, 0x0078, 0x9493, 0x1078, 0x4957, 0x0e7e, 0x0c7e, 0x037e,
+	0x027e, 0x017e, 0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029,
+	0x1078, 0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x2c08,
+	0x1078, 0x9f8b, 0x077f, 0x017f, 0x2e60, 0x1078, 0x47e9, 0x017f,
+	0x027f, 0x037f, 0x0c7f, 0x0e7f, 0x6618, 0x0c7e, 0x2660, 0x1078,
+	0x45d6, 0x0c7f, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082,
+	0x0006, 0x0048, 0x9303, 0x1078, 0x9ebf, 0x00c0, 0x9371, 0x1078,
+	0x9e50, 0x00c0, 0x92ff, 0x6007, 0x0008, 0x0078, 0x9493, 0x6007,
+	0x0009, 0x0078, 0x9493, 0x1078, 0xa09f, 0x0040, 0x930d, 0x1078,
+	0x9ebf, 0x0040, 0x92f7, 0x0078, 0x9371, 0x6013, 0x1900, 0x0078,
+	0x92ff, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6106, 0x1078, 0x9e05,
+	0x6007, 0x0006, 0x0078, 0x9493, 0x6007, 0x0007, 0x0078, 0x9493,
+	0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0, 0x9664,
+	0x0d7e, 0x6618, 0x2668, 0x6e04, 0xa684, 0x00ff, 0xa082, 0x0006,
+	0x00c8, 0x9336, 0x2001, 0x0001, 0x1078, 0x44ee, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0006, 0x0040, 0x9353, 0xa686, 0x0004, 0x0040,
+	0x9353, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0040, 0x9353,
+	0xa686, 0x0004, 0x0040, 0x9353, 0xa686, 0x0005, 0x0040, 0x9353,
+	0x0d7f, 0x0078, 0x9371, 0x1078, 0x9f25, 0x00c0, 0x936c, 0xa686,
+	0x0006, 0x00c0, 0x9365, 0x027e, 0x6218, 0xa290, 0x0028, 0x2214,
+	0x2009, 0x0000, 0x1078, 0x28c8, 0x027f, 0x1078, 0x4649, 0x6007,
+	0x000a, 0x0d7f, 0x0078, 0x9493, 0x6007, 0x000b, 0x0d7f, 0x0078,
+	0x9493, 0x1078, 0x2880, 0x6007, 0x0001, 0x0078, 0x9493, 0x1078,
+	0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6618,
+	0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa686, 0x0707, 0x0040, 0x9371,
+	0x027e, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x1078,
+	0x28c8, 0x027f, 0x6007, 0x000c, 0x0078, 0x9493, 0x1078, 0x4967,
+	0x00c0, 0x93a3, 0x2001, 0xa633, 0x2004, 0xa084, 0x0009, 0xa086,
+	0x0008, 0x00c0, 0x93ab, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013,
+	0x0000, 0x0078, 0x9493, 0x1078, 0x4957, 0x6618, 0xa6b0, 0x0001,
+	0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x93ef, 0xa6b4,
+	0xff00, 0x8637, 0xa686, 0x0004, 0x0040, 0x93c2, 0xa686, 0x0006,
+	0x00c0, 0x9371, 0x1078, 0x9f34, 0x00c0, 0x93ca, 0x6007, 0x000e,
+	0x0078, 0x9493, 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4,
+	0x00ff, 0x8427, 0x047e, 0x1078, 0x2880, 0x047f, 0x017e, 0xa006,
+	0x2009, 0xa653, 0x210c, 0xd1a4, 0x0040, 0x93e9, 0x2009, 0x0029,
+	0x1078, 0xa21d, 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, 0x6802,
+	0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, 0x0078, 0x9493, 0x2001,
+	0x0001, 0x1078, 0x44ee, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9,
+	0x0004, 0x2019, 0xa605, 0x2011, 0xab90, 0x1078, 0x80de, 0x037f,
+	0x027f, 0x017f, 0x157f, 0xa005, 0x0040, 0x940f, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0006, 0x0040, 0x93c2, 0x0078, 0x9371, 0x6013,
+	0x1900, 0x6007, 0x0009, 0x0078, 0x9493, 0x1078, 0x4967, 0x00c0,
+	0x9422, 0x2001, 0xa633, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008,
+	0x00c0, 0x942a, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000,
+	0x0078, 0x9493, 0x1078, 0x4957, 0x6618, 0xa6b0, 0x0001, 0x2634,
+	0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x9472, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0004, 0x0040, 0x9441, 0xa686, 0x0006, 0x00c0,
+	0x9371, 0x1078, 0x9f5f, 0x00c0, 0x944d, 0x1078, 0x9e50, 0x00c0,
+	0x944d, 0x6007, 0x0010, 0x0078, 0x9493, 0x047e, 0x6418, 0xa4a0,
+	0x0028, 0x2424, 0xa4a4, 0x00ff, 0x8427, 0x047e, 0x1078, 0x2880,
+	0x047f, 0x017e, 0xa006, 0x2009, 0xa653, 0x210c, 0xd1a4, 0x0040,
+	0x946c, 0x2009, 0x0029, 0x1078, 0xa21d, 0x6018, 0x0d7e, 0x2068,
+	0x6800, 0xc0e5, 0x6802, 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001,
+	0x0078, 0x9493, 0x1078, 0xa09f, 0x0040, 0x947f, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0006, 0x0040, 0x9441, 0x0078, 0x9371, 0x6013,
+	0x1900, 0x6007, 0x0009, 0x0078, 0x9493, 0x1078, 0x29bb, 0x00c0,
+	0x9664, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0,
+	0x9371, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x007c,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x0078, 0x9497,
+	0x6007, 0x0005, 0x0078, 0x949a, 0x1078, 0xa41c, 0x00c0, 0x9664,
+	0x1078, 0x29bb, 0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0, 0x9371,
+	0x6007, 0x0020, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x007c, 0x1078,
+	0x29bb, 0x00c0, 0x9664, 0x6007, 0x0023, 0x6003, 0x0001, 0x1078,
+	0x5dd7, 0x007c, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb,
+	0x00c0, 0x9664, 0x1078, 0x9667, 0x00c0, 0x9371, 0x017e, 0x027e,
+	0x2011, 0xab90, 0x2214, 0x2c08, 0xa006, 0x1078, 0xa1e6, 0x00c0,
+	0x94e9, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x2011, 0xab89,
+	0x2214, 0xa296, 0xffff, 0x00c0, 0x94f3, 0x6007, 0x0025, 0x0078,
+	0x94f3, 0x6004, 0xa086, 0x0024, 0x00c0, 0x94f0, 0x1078, 0x772d,
+	0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x5dd7, 0x027f,
+	0x017f, 0x007c, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x6106, 0x1078,
+	0x9687, 0x6007, 0x002b, 0x0078, 0x9493, 0x6007, 0x002c, 0x0078,
+	0x9493, 0x1078, 0xa41c, 0x00c0, 0x9664, 0x1078, 0x29bb, 0x00c0,
+	0x9664, 0x1078, 0x9667, 0x00c0, 0x9371, 0x6106, 0x1078, 0x968c,
+	0x00c0, 0x951e, 0x6007, 0x002e, 0x0078, 0x9493, 0x6007, 0x002f,
+	0x0078, 0x9493, 0x1078, 0x29bb, 0x00c0, 0x9664, 0x0e7e, 0x0d7e,
+	0x0c7e, 0x6018, 0xa080, 0x0001, 0x200c, 0xa184, 0x00ff, 0xa086,
+	0x0006, 0x0040, 0x953f, 0xa184, 0xff00, 0x8007, 0xa086, 0x0006,
+	0x0040, 0x953f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0078, 0x9498, 0x2001,
+	0xa672, 0x2004, 0xd0e4, 0x0040, 0x95ab, 0x2071, 0xab8c, 0x7010,
+	0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, 0xa653, 0x2004,
+	0xd0a4, 0x0040, 0x955d, 0x6018, 0x2068, 0x6810, 0xa106, 0x00c0,
+	0x955d, 0x6814, 0xa206, 0x0040, 0x9581, 0x2001, 0xa653, 0x2004,
+	0xd0ac, 0x00c0, 0x959f, 0x2069, 0xa600, 0x6870, 0xa206, 0x00c0,
+	0x959f, 0x686c, 0xa106, 0x00c0, 0x959f, 0x7210, 0x1078, 0x8cf2,
+	0x0040, 0x95a5, 0x1078, 0xa28e, 0x0040, 0x95a5, 0x622a, 0x6007,
+	0x0036, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x0c7f, 0x0d7f, 0x0e7f,
+	0x007c, 0x7214, 0xa286, 0xffff, 0x0040, 0x9593, 0x1078, 0x8cf2,
+	0x0040, 0x95a5, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x00c0,
+	0x95a5, 0x0078, 0x956e, 0x7210, 0x2c08, 0xa085, 0x0001, 0x1078,
+	0xa1e6, 0x2c10, 0x2160, 0x0040, 0x95a5, 0x0078, 0x956e, 0x6007,
+	0x0037, 0x6013, 0x1500, 0x0078, 0x9579, 0x6007, 0x0037, 0x6013,
+	0x1700, 0x0078, 0x9579, 0x6007, 0x0012, 0x0078, 0x9579, 0x1078,
+	0x29bb, 0x00c0, 0x9664, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084,
+	0xff00, 0x8007, 0xa086, 0x0006, 0x00c0, 0x9498, 0x0e7e, 0x0d7e,
+	0x0c7e, 0x2001, 0xa672, 0x2004, 0xd0e4, 0x0040, 0x9621, 0x2069,
+	0xa600, 0x2071, 0xab8c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286,
+	0xffff, 0x00c0, 0x95de, 0x7208, 0x0c7e, 0x2c08, 0xa085, 0x0001,
+	0x1078, 0xa1e6, 0x2c10, 0x0c7f, 0x0040, 0x9615, 0x1078, 0x8cf2,
+	0x0040, 0x9615, 0x0c7e, 0x027e, 0x2260, 0x1078, 0x89f3, 0x027f,
+	0x0c7f, 0x7118, 0xa18c, 0xff00, 0x810f, 0xa186, 0x0001, 0x0040,
+	0x95ff, 0xa186, 0x0005, 0x0040, 0x95f9, 0xa186, 0x0007, 0x00c0,
+	0x9609, 0xa280, 0x0004, 0x2004, 0xa005, 0x0040, 0x9609, 0x057e,
+	0x7510, 0x7614, 0x1078, 0xa2a3, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f,
+	0x007c, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00, 0x6003,
+	0x0001, 0x1078, 0x5d8a, 0x0078, 0x9605, 0x6007, 0x003b, 0x602b,
+	0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x0078,
+	0x9605, 0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0078,
+	0x9579, 0x0e7e, 0x027e, 0x1078, 0x4967, 0x0040, 0x965e, 0x1078,
+	0x4957, 0x1078, 0xa4a9, 0x00c0, 0x965c, 0x2071, 0xa600, 0x70cc,
+	0xc085, 0x70ce, 0x0f7e, 0x2079, 0x0100, 0x7298, 0xa284, 0x00ff,
+	0x706e, 0x78e6, 0xa284, 0xff00, 0x7270, 0xa205, 0x7072, 0x78ea,
+	0x0f7f, 0x70d7, 0x0000, 0x2001, 0xa653, 0x2004, 0xd0a4, 0x0040,
+	0x9655, 0x2011, 0xa8ca, 0x2013, 0x07d0, 0xd0ac, 0x00c0, 0x965e,
+	0x1078, 0x2677, 0x0078, 0x965e, 0x1078, 0xa4d9, 0x027f, 0x0e7f,
+	0x1078, 0x772d, 0x0078, 0x9497, 0x1078, 0x772d, 0x007c, 0x0d7e,
+	0x067e, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0006, 0x0040, 0x9684, 0xa686, 0x0004, 0x0040, 0x9684, 0x6e04,
+	0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0040, 0x9684, 0xa686, 0x0004,
+	0x0040, 0x9684, 0xa085, 0x0001, 0x067f, 0x0d7f, 0x007c, 0x0d7e,
+	0x1078, 0x96bb, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x96ca, 0x00c0,
+	0x96b4, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, 0x00ff, 0xa115,
+	0x6212, 0x6824, 0x602a, 0xd1e4, 0x0040, 0x96a2, 0x2009, 0x0001,
+	0x0078, 0x96b0, 0xd1ec, 0x0040, 0x96b4, 0x6920, 0xa18c, 0x00ff,
+	0x6824, 0x1078, 0x254d, 0x00c0, 0x96b4, 0x2110, 0x2009, 0x0000,
+	0x1078, 0x28c8, 0x0078, 0x96b8, 0xa085, 0x0001, 0x0078, 0x96b9,
+	0xa006, 0x0d7f, 0x007c, 0x2069, 0xab8d, 0x6800, 0xa082, 0x0010,
+	0x00c8, 0x96c8, 0x6013, 0x0000, 0xa085, 0x0001, 0x0078, 0x96c9,
+	0xa006, 0x007c, 0x6013, 0x0000, 0x2069, 0xab8c, 0x6808, 0xa084,
+	0xff00, 0xa086, 0x0800, 0x00c0, 0x96de, 0x6800, 0xa084, 0x00ff,
+	0xa08e, 0x0014, 0x0040, 0x96de, 0xa08e, 0x0010, 0x007c, 0x6004,
+	0xa0b2, 0x0044, 0x10c8, 0x1332, 0xa1b6, 0x0013, 0x00c0, 0x96eb,
+	0x2008, 0x0079, 0x96fe, 0xa1b6, 0x0027, 0x0040, 0x96f3, 0xa1b6,
+	0x0014, 0x10c0, 0x1332, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078,
+	0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c, 0x973e, 0x9740,
+	0x973e, 0x973e, 0x973e, 0x9740, 0x974c, 0x97d6, 0x9799, 0x97d6,
+	0x97ad, 0x97d6, 0x974c, 0x97d6, 0x97ce, 0x97d6, 0x97ce, 0x97d6,
+	0x97d6, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e, 0x973e,
+	0x973e, 0x973e, 0x973e, 0x973e, 0x9740, 0x973e, 0x97d6, 0x973e,
+	0x973e, 0x97d6, 0x973e, 0x97d6, 0x97d6, 0x973e, 0x973e, 0x973e,
+	0x973e, 0x97d6, 0x97d6, 0x973e, 0x97d6, 0x97d6, 0x973e, 0x973e,
+	0x973e, 0x973e, 0x973e, 0x9740, 0x97d6, 0x97d6, 0x973e, 0x973e,
+	0x97d6, 0x97d6, 0x973e, 0x973e, 0x973e, 0x973e, 0x1078, 0x1332,
+	0x1078, 0x61cd, 0x2001, 0xa8a2, 0x2004, 0x6016, 0x6003, 0x0002,
+	0x1078, 0x62d1, 0x0078, 0x97dc, 0x0f7e, 0x2079, 0xa652, 0x7804,
+	0x0f7f, 0xd0ac, 0x00c0, 0x97d6, 0x2001, 0x0000, 0x1078, 0x44ee,
+	0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0040, 0x97d6,
+	0x0c7e, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x00c0, 0x9770, 0x6010,
+	0xa005, 0x0040, 0x9770, 0x0c7f, 0x1078, 0x3699, 0x0078, 0x97d6,
+	0x0c7f, 0x2001, 0xa600, 0x2004, 0xa086, 0x0002, 0x00c0, 0x977f,
+	0x0f7e, 0x2079, 0xa600, 0x7890, 0x8000, 0x7892, 0x0f7f, 0x2001,
+	0x0002, 0x1078, 0x4502, 0x1078, 0x61cd, 0x601f, 0x0001, 0x6003,
+	0x0001, 0x6007, 0x0002, 0x1078, 0x5dd7, 0x1078, 0x62d1, 0x0c7e,
+	0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x5a52, 0x0c7f, 0x0078,
+	0x97dc, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0006, 0x0040, 0x97d6, 0xa686, 0x0004, 0x0040,
+	0x97d6, 0x2001, 0x0004, 0x0078, 0x97d4, 0x2001, 0xa600, 0x2004,
+	0xa086, 0x0003, 0x00c0, 0x97b6, 0x1078, 0x3699, 0x2001, 0x0006,
+	0x1078, 0x97dd, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4,
+	0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x97d6, 0x2001, 0x0006,
+	0x0078, 0x97d4, 0x2001, 0x0004, 0x0078, 0x97d4, 0x2001, 0x0006,
+	0x1078, 0x97dd, 0x0078, 0x97d6, 0x1078, 0x4535, 0x1078, 0x61cd,
+	0x1078, 0x772d, 0x1078, 0x62d1, 0x007c, 0x017e, 0x0d7e, 0x6118,
+	0x2168, 0x6900, 0xd184, 0x0040, 0x97f8, 0x6104, 0xa18e, 0x000a,
+	0x00c0, 0x97f0, 0x699c, 0xd1a4, 0x00c0, 0x97f0, 0x2001, 0x0007,
+	0x1078, 0x4502, 0x2001, 0x0000, 0x1078, 0x44ee, 0x1078, 0x28a6,
+	0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084,
+	0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1332, 0xa1b6,
+	0x0015, 0x00c0, 0x980f, 0x1079, 0x9816, 0x0078, 0x9815, 0xa1b6,
+	0x0016, 0x10c0, 0x1332, 0x1079, 0x9822, 0x007c, 0x7d4e, 0x7d4e,
+	0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x9877, 0x982e, 0x7d4e, 0x7d4e,
+	0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e,
+	0x9877, 0x987f, 0x7d4e, 0x7d4e, 0x7d4e, 0x7d4e, 0x0f7e, 0x2079,
+	0xa652, 0x7804, 0xd0ac, 0x00c0, 0x9855, 0x6018, 0xa07d, 0x0040,
+	0x9855, 0x7800, 0xd0f4, 0x00c0, 0x9841, 0x7810, 0xa005, 0x00c0,
+	0x9855, 0x2001, 0x0000, 0x1078, 0x44ee, 0x2001, 0x0002, 0x1078,
+	0x4502, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078,
+	0x5dd7, 0x1078, 0x62d1, 0x0078, 0x9875, 0x2011, 0xab83, 0x2204,
+	0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x9875, 0x0c7e, 0x1078,
+	0x45c4, 0x0040, 0x9868, 0x0c7f, 0x1078, 0x772d, 0x0078, 0x9875,
+	0x6010, 0x007e, 0x6014, 0x007e, 0x1078, 0x42f8, 0x007f, 0x6016,
+	0x007f, 0x6012, 0x0c7f, 0x1078, 0x772d, 0x0f7f, 0x007c, 0x6604,
+	0xa6b6, 0x001e, 0x00c0, 0x987e, 0x1078, 0x772d, 0x007c, 0x1078,
+	0x7f8e, 0x00c0, 0x988b, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078,
+	0x5dd7, 0x0078, 0x988d, 0x1078, 0x772d, 0x007c, 0x6004, 0xa08a,
+	0x0044, 0x10c8, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078,
+	0x62d1, 0x007c, 0xa182, 0x0040, 0x0079, 0x989e, 0x98b1, 0x98b1,
+	0x98b1, 0x98b1, 0x98b3, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1,
+	0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1, 0x98b1,
+	0x98b1, 0x1078, 0x1332, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e,
+	0x027e, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0040, 0x98c4,
+	0x2021, 0x0000, 0x1078, 0xa472, 0x6106, 0x2071, 0xab80, 0x7444,
+	0xa4a4, 0xff00, 0x0040, 0x991b, 0xa486, 0x2000, 0x00c0, 0x98d6,
+	0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x5bf1, 0x1078, 0x138b,
+	0x1040, 0x1332, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803,
+	0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2,
+	0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x017e, 0xa084,
+	0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x4a73,
+	0x017f, 0xa486, 0x2000, 0x00c0, 0x9903, 0x2019, 0x0017, 0x1078,
+	0xa195, 0x0078, 0x997d, 0xa486, 0x0400, 0x00c0, 0x990d, 0x2019,
+	0x0002, 0x1078, 0xa146, 0x0078, 0x997d, 0xa486, 0x0200, 0x00c0,
+	0x9913, 0x1078, 0xa12b, 0xa486, 0x1000, 0x00c0, 0x9919, 0x1078,
+	0xa17a, 0x0078, 0x997d, 0x2069, 0xa933, 0x6a00, 0xd284, 0x0040,
+	0x99e7, 0xa284, 0x0300, 0x00c0, 0x99df, 0x6804, 0xa005, 0x0040,
+	0x99c5, 0x2d78, 0x6003, 0x0007, 0x1078, 0x1370, 0x0040, 0x9984,
+	0x7800, 0xd08c, 0x00c0, 0x9937, 0x7804, 0x8001, 0x7806, 0x6013,
+	0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008,
+	0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130,
+	0x6986, 0x6846, 0x7928, 0x698a, 0x792c, 0x698e, 0x7930, 0x6992,
+	0x7934, 0x6996, 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286,
+	0x0002, 0x00c0, 0x995f, 0x684f, 0x0040, 0x0078, 0x9969, 0xa286,
+	0x0001, 0x00c0, 0x9967, 0x684f, 0x0080, 0x0078, 0x9969, 0x684f,
+	0x0000, 0x20a9, 0x000a, 0x2001, 0xab90, 0xad90, 0x0015, 0x200c,
+	0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x996f, 0x200c, 0x6982,
+	0x8000, 0x200c, 0x697e, 0x1078, 0x4a73, 0x027f, 0x047f, 0x157f,
+	0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x2001, 0xa60e, 0x2004, 0xd084,
+	0x0040, 0x998e, 0x1078, 0x138b, 0x00c0, 0x9930, 0x6013, 0x0100,
+	0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1,
+	0x0078, 0x997d, 0x2069, 0xab92, 0x2d04, 0xa084, 0xff00, 0xa086,
+	0x1200, 0x00c0, 0x99b9, 0x2069, 0xab80, 0x686c, 0xa084, 0x00ff,
+	0x017e, 0x6110, 0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003,
+	0x0001, 0x6007, 0x0043, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078,
+	0x997d, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078,
+	0x5d8a, 0x1078, 0x62d1, 0x0078, 0x997d, 0x2001, 0xa60d, 0x2004,
+	0xd0ec, 0x0040, 0x99cf, 0x2011, 0x8049, 0x1078, 0x361b, 0x6013,
+	0x0300, 0x0078, 0x99d5, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x997d, 0x6013,
+	0x0500, 0x0078, 0x99d5, 0x6013, 0x0600, 0x0078, 0x999a, 0x6013,
+	0x0200, 0x0078, 0x999a, 0xa186, 0x0013, 0x00c0, 0x99fd, 0x6004,
+	0xa08a, 0x0040, 0x1048, 0x1332, 0xa08a, 0x0053, 0x10c8, 0x1332,
+	0xa082, 0x0040, 0x2008, 0x0079, 0x9a82, 0xa186, 0x0051, 0x0040,
+	0x9a0a, 0xa186, 0x0047, 0x00c0, 0x9a23, 0x6004, 0xa086, 0x0041,
+	0x0040, 0x9a31, 0x2001, 0x0109, 0x2004, 0xd084, 0x0040, 0x9a31,
+	0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x1078, 0x5c56,
+	0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086, 0x0002, 0x00c0,
+	0x9a31, 0x0078, 0x9ac7, 0xa186, 0x0027, 0x0040, 0x9a2b, 0xa186,
+	0x0014, 0x10c0, 0x1332, 0x6004, 0xa082, 0x0040, 0x2008, 0x0079,
+	0x9a34, 0x1078, 0x7773, 0x007c, 0x9a47, 0x9a49, 0x9a49, 0x9a71,
+	0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47,
+	0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x9a47, 0x1078,
+	0x1332, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x037e, 0x0d7e, 0x6010,
+	0xa06d, 0x0040, 0x9a6e, 0xad84, 0xf000, 0x0040, 0x9a6e, 0x6003,
+	0x0002, 0x6018, 0x2004, 0xd0bc, 0x00c0, 0x9a6e, 0x2019, 0x0004,
+	0x1078, 0xa1ca, 0x6013, 0x0000, 0x6014, 0xa005, 0x00c0, 0x9a6c,
+	0x2001, 0xa8a3, 0x2004, 0x6016, 0x6003, 0x0007, 0x0d7f, 0x037f,
+	0x007c, 0x0d7e, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x1078, 0x8d06,
+	0x0040, 0x9a7e, 0x6010, 0x2068, 0x1078, 0x13a4, 0x1078, 0x8ec6,
+	0x0d7f, 0x007c, 0x9a95, 0x9ab4, 0x9a9e, 0x9ac1, 0x9a95, 0x9a95,
+	0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95,
+	0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x1078, 0x1332, 0x6010,
+	0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x1078, 0x61cd,
+	0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0040, 0x9aaf, 0x6003,
+	0x0007, 0x2009, 0x0043, 0x1078, 0x775c, 0x0078, 0x9ab1, 0x6003,
+	0x0002, 0x1078, 0x62d1, 0x007c, 0x1078, 0x61cd, 0x1078, 0xa423,
+	0x00c0, 0x9abe, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x1078, 0x62d1,
+	0x007c, 0x1078, 0x61cd, 0x2009, 0x0041, 0x0078, 0x9c1e, 0xa182,
+	0x0040, 0x0079, 0x9acb, 0x9ade, 0x9ae0, 0x9ade, 0x9ade, 0x9ade,
+	0x9ade, 0x9ade, 0x9ae1, 0x9ade, 0x9ade, 0x9ade, 0x9ade, 0x9ade,
+	0x9ade, 0x9ade, 0x9ade, 0x9ade, 0x9aec, 0x9ade, 0x1078, 0x1332,
+	0x007c, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20,
+	0x2c10, 0x1078, 0x15fa, 0x007c, 0x0d7e, 0x1078, 0x5bc1, 0x0d7f,
+	0x1078, 0xa495, 0x1078, 0x772d, 0x007c, 0xa182, 0x0040, 0x0079,
+	0x9af9, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c,
+	0x9b0e, 0x9b0c, 0x9b11, 0x9b3c, 0x9b0c, 0x9b0c, 0x9b0c, 0x9b0c,
+	0x9b3c, 0x9b0c, 0x9b0c, 0x9b0c, 0x1078, 0x1332, 0x1078, 0x7773,
+	0x007c, 0x1078, 0x627a, 0x1078, 0x639b, 0x6010, 0x0d7e, 0x2068,
+	0x684c, 0xd0fc, 0x0040, 0x9b27, 0xa08c, 0x0003, 0xa18e, 0x0002,
+	0x0040, 0x9b2f, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x9c1e, 0x6003,
+	0x0007, 0x6017, 0x0000, 0x1078, 0x5bc1, 0x0d7f, 0x007c, 0x1078,
+	0xa423, 0x0040, 0x9b35, 0x0d7f, 0x007c, 0x1078, 0x5bc1, 0x1078,
+	0x772d, 0x0d7f, 0x0078, 0x9b2e, 0x037e, 0x1078, 0x627a, 0x1078,
+	0x639b, 0x6010, 0x0d7e, 0x2068, 0x6018, 0x2004, 0xd0bc, 0x0040,
+	0x9b5c, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x9b58,
+	0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a,
+	0x6003, 0x0002, 0x0078, 0x9b6d, 0x2019, 0x0004, 0x1078, 0xa1ca,
+	0x6014, 0xa005, 0x00c0, 0x9b69, 0x2001, 0xa8a3, 0x2004, 0x8003,
+	0x6016, 0x6013, 0x0000, 0x6003, 0x0007, 0x0d7f, 0x037f, 0x007c,
+	0xa186, 0x0013, 0x00c0, 0x9b7e, 0x6004, 0xa086, 0x0042, 0x10c0,
+	0x1332, 0x1078, 0x61cd, 0x1078, 0x62d1, 0x007c, 0xa186, 0x0027,
+	0x0040, 0x9b86, 0xa186, 0x0014, 0x00c0, 0x9b96, 0x6004, 0xa086,
+	0x0042, 0x10c0, 0x1332, 0x2001, 0x0007, 0x1078, 0x4535, 0x1078,
+	0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c, 0xa182, 0x0040,
+	0x0079, 0x9b9a, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad,
+	0x9bad, 0x9baf, 0x9bbb, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad,
+	0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x9bad, 0x1078, 0x1332, 0x037e,
+	0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15fa,
+	0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e, 0x2068, 0x6810, 0x6a14,
+	0x6118, 0x210c, 0xd1bc, 0x0040, 0x9bda, 0x6124, 0xd1f4, 0x00c0,
+	0x9bda, 0x007e, 0x047e, 0x057e, 0x6c7c, 0xa422, 0x6d80, 0x2200,
+	0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a, 0x057f,
+	0x047f, 0x007f, 0xa20d, 0x00c0, 0x9bee, 0x684c, 0xd0fc, 0x0040,
+	0x9be6, 0x2009, 0x0041, 0x0d7f, 0x0078, 0x9c1e, 0x6003, 0x0007,
+	0x6017, 0x0000, 0x1078, 0x5bc1, 0x0d7f, 0x007c, 0x007e, 0x0f7e,
+	0x2c78, 0x1078, 0x4963, 0x0f7f, 0x007f, 0x0040, 0x9bfb, 0x6003,
+	0x0002, 0x0d7f, 0x007c, 0x2009, 0xa60d, 0x210c, 0xd19c, 0x0040,
+	0x9c05, 0x6003, 0x0007, 0x0078, 0x9c07, 0x6003, 0x0006, 0x1078,
+	0x9c0d, 0x1078, 0x5bc3, 0x0d7f, 0x007c, 0xd2fc, 0x0040, 0x9c19,
+	0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009, 0x0078,
+	0x9c1b, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x007c, 0xa182, 0x0040,
+	0x0048, 0x9c24, 0x0079, 0x9c31, 0xa186, 0x0013, 0x0040, 0x9c2c,
+	0xa186, 0x0014, 0x10c0, 0x1332, 0x6024, 0xd0dc, 0x1040, 0x1332,
+	0x007c, 0x9c44, 0x9c4b, 0x9c57, 0x9c63, 0x9c44, 0x9c44, 0x9c44,
+	0x9c72, 0x9c44, 0x9c46, 0x9c46, 0x9c44, 0x9c44, 0x9c44, 0x9c44,
+	0x9c44, 0x9c44, 0x9c44, 0x9c44, 0x1078, 0x1332, 0x6024, 0xd0dc,
+	0x1040, 0x1332, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x62d1, 0x127f, 0x007c, 0x6003,
+	0x0001, 0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x62d1, 0x127f, 0x007c, 0x6003, 0x0003, 0x6106, 0x2c10, 0x1078,
+	0x1cf0, 0x127e, 0x2091, 0x8000, 0x1078, 0x5df6, 0x1078, 0x639b,
+	0x127f, 0x007c, 0xa016, 0x1078, 0x15fa, 0x007c, 0x127e, 0x2091,
+	0x8000, 0x037e, 0x0d7e, 0xa182, 0x0040, 0x1079, 0x9c83, 0x0d7f,
+	0x037f, 0x127f, 0x007c, 0x9c93, 0x9c95, 0x9caa, 0x9cc9, 0x9c93,
+	0x9c93, 0x9c93, 0x9ce1, 0x9c93, 0x9c93, 0x9c93, 0x9c93, 0x9c93,
+	0x9c93, 0x9c93, 0x9c93, 0x1078, 0x1332, 0x6010, 0x2068, 0x684c,
+	0xd0fc, 0x0040, 0x9cbf, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040,
+	0x9cbf, 0x6003, 0x0001, 0x6106, 0x1078, 0x5d8a, 0x1078, 0x62d1,
+	0x0078, 0x9ce4, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9cbf,
+	0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, 0x9cbf, 0x6003, 0x0001,
+	0x6106, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0078, 0x9ce4, 0x6013,
+	0x0000, 0x6017, 0x0000, 0x2019, 0x0004, 0x1078, 0xa1ca, 0x0078,
+	0x9ce4, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9cbf, 0xa09c,
+	0x0003, 0xa39e, 0x0003, 0x0040, 0x9cbf, 0x6003, 0x0003, 0x6106,
+	0x2c10, 0x1078, 0x1cf0, 0x1078, 0x5df6, 0x1078, 0x639b, 0x0078,
+	0x9ce4, 0xa016, 0x1078, 0x15fa, 0x007c, 0x1078, 0x61cd, 0x6110,
+	0x81ff, 0x0040, 0x9cf6, 0x0d7e, 0x2168, 0x1078, 0xa4e2, 0x037e,
+	0x2019, 0x0029, 0x1078, 0xa1ca, 0x037f, 0x0d7f, 0x1078, 0x8ec6,
+	0x1078, 0x62d1, 0x007c, 0x1078, 0x627a, 0x6110, 0x81ff, 0x0040,
+	0x9d0c, 0x0d7e, 0x2168, 0x1078, 0xa4e2, 0x037e, 0x2019, 0x0029,
+	0x1078, 0xa1ca, 0x037f, 0x0d7f, 0x1078, 0x8ec6, 0x1078, 0x639b,
+	0x007c, 0xa182, 0x0085, 0x0079, 0x9d15, 0x9d1e, 0x9d1c, 0x9d1c,
+	0x9d2a, 0x9d1c, 0x9d1c, 0x9d1c, 0x1078, 0x1332, 0x6003, 0x000b,
+	0x6106, 0x1078, 0x5d8a, 0x127e, 0x2091, 0x8000, 0x1078, 0x62d1,
+	0x127f, 0x007c, 0x027e, 0x0e7e, 0x1078, 0xa41c, 0x0040, 0x9d34,
+	0x1078, 0x772d, 0x0078, 0x9d50, 0x2071, 0xab80, 0x7224, 0x6212,
+	0x7220, 0x1078, 0xa069, 0x0040, 0x9d41, 0x6007, 0x0086, 0x0078,
+	0x9d4a, 0x6007, 0x0087, 0x7224, 0xa296, 0xffff, 0x00c0, 0x9d4a,
+	0x6007, 0x0086, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1,
+	0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x9d64, 0x6004,
+	0xa08a, 0x0085, 0x1048, 0x1332, 0xa08a, 0x008c, 0x10c8, 0x1332,
+	0xa082, 0x0085, 0x0079, 0x9d7b, 0xa186, 0x0027, 0x0040, 0x9d70,
+	0xa186, 0x0014, 0x0040, 0x9d70, 0x1078, 0x7773, 0x0078, 0x9d7a,
+	0x2001, 0x0007, 0x1078, 0x4535, 0x1078, 0x61cd, 0x1078, 0x8ec6,
+	0x1078, 0x62d1, 0x007c, 0x9d82, 0x9d84, 0x9d84, 0x9d82, 0x9d82,
+	0x9d82, 0x9d82, 0x1078, 0x1332, 0x1078, 0x61cd, 0x1078, 0x8ec6,
+	0x1078, 0x62d1, 0x007c, 0xa182, 0x0085, 0x1048, 0x1332, 0xa182,
+	0x008c, 0x10c8, 0x1332, 0xa182, 0x0085, 0x0079, 0x9d97, 0x9d9e,
+	0x9d9e, 0x9d9e, 0x9da0, 0x9d9e, 0x9d9e, 0x9d9e, 0x1078, 0x1332,
+	0x007c, 0xa186, 0x0013, 0x0040, 0x9db1, 0xa186, 0x0014, 0x0040,
+	0x9db1, 0xa186, 0x0027, 0x0040, 0x9db1, 0x1078, 0x7773, 0x0078,
+	0x9db7, 0x1078, 0x61cd, 0x1078, 0x8ec6, 0x1078, 0x62d1, 0x007c,
+	0x037e, 0x1078, 0xa495, 0x603f, 0x0000, 0x2019, 0x000b, 0x1078,
+	0x9dc7, 0x601f, 0x0006, 0x6003, 0x0007, 0x037f, 0x007c, 0x127e,
+	0x037e, 0x2091, 0x8000, 0x087e, 0x2c40, 0x097e, 0x2049, 0x0000,
+	0x1078, 0x7246, 0x097f, 0x087f, 0x00c0, 0x9e02, 0x077e, 0x2c38,
+	0x1078, 0x72f3, 0x077f, 0x00c0, 0x9e02, 0x6000, 0xa086, 0x0000,
+	0x0040, 0x9e02, 0x601c, 0xa086, 0x0007, 0x0040, 0x9e02, 0x0d7e,
+	0x6000, 0xa086, 0x0004, 0x00c0, 0x9df3, 0x1078, 0xa495, 0x601f,
+	0x0007, 0x1078, 0x1757, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040,
+	0x9dfb, 0x1078, 0xa1ca, 0x0d7f, 0x6013, 0x0000, 0x1078, 0xa495,
+	0x601f, 0x0007, 0x037f, 0x127f, 0x007c, 0x0f7e, 0x0c7e, 0x037e,
+	0x157e, 0x2079, 0xab80, 0x7938, 0x783c, 0x1078, 0x254d, 0x00c0,
+	0x9e49, 0x017e, 0x0c7e, 0x1078, 0x45c4, 0x00c0, 0x9e49, 0x017f,
+	0x027f, 0x027e, 0x017e, 0x2019, 0x0029, 0x1078, 0x73d0, 0x1078,
+	0x5f01, 0x077e, 0x2039, 0x0000, 0x1078, 0x5e0a, 0x077f, 0x017f,
+	0x077e, 0x2039, 0x0000, 0x1078, 0x9f8b, 0x077f, 0x1078, 0x47e9,
+	0x027e, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040,
+	0x9e3d, 0xa286, 0x0004, 0x00c0, 0x9e40, 0x62a0, 0x1078, 0x2942,
+	0x027f, 0x017f, 0x1078, 0x42f8, 0x6612, 0x6516, 0xa006, 0x0078,
+	0x9e4b, 0x0c7f, 0x017f, 0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c,
+	0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x2009, 0xa620, 0x2104, 0xa086,
+	0x0074, 0x00c0, 0x9eb3, 0x2069, 0xab8e, 0x690c, 0xa182, 0x0100,
+	0x0048, 0x9ea3, 0x6908, 0xa184, 0x8000, 0x0040, 0x9eaf, 0x6018,
+	0x2070, 0x7010, 0xa084, 0x00ff, 0x0040, 0x9e72, 0x7000, 0xd0f4,
+	0x0040, 0x9e76, 0xa184, 0x0800, 0x0040, 0x9eaf, 0x6910, 0xa18a,
+	0x0001, 0x0048, 0x9ea7, 0x6914, 0x2069, 0xabae, 0x6904, 0x81ff,
+	0x00c0, 0x9e9b, 0x690c, 0xa182, 0x0100, 0x0048, 0x9ea3, 0x6908,
+	0x81ff, 0x00c0, 0x9e9f, 0x6910, 0xa18a, 0x0001, 0x0048, 0x9ea7,
+	0x6918, 0xa18a, 0x0001, 0x0048, 0x9eaf, 0x0078, 0x9eb9, 0x6013,
+	0x0100, 0x0078, 0x9eb5, 0x6013, 0x0300, 0x0078, 0x9eb5, 0x6013,
+	0x0500, 0x0078, 0x9eb5, 0x6013, 0x0700, 0x0078, 0x9eb5, 0x6013,
+	0x0900, 0x0078, 0x9eb5, 0x6013, 0x0b00, 0x0078, 0x9eb5, 0x6013,
+	0x0f00, 0x0078, 0x9eb5, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0078,
+	0x9eba, 0xa006, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e,
+	0x0d7e, 0x027e, 0x037e, 0x157e, 0x6218, 0x2268, 0x6b04, 0xa394,
+	0x00ff, 0xa286, 0x0006, 0x0040, 0x9ee3, 0xa286, 0x0004, 0x0040,
+	0x9ee3, 0xa394, 0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x9ee3,
+	0xa286, 0x0004, 0x0040, 0x9ee3, 0x0c7e, 0x2d60, 0x1078, 0x45d6,
+	0x0c7f, 0x0078, 0x9f1e, 0x2011, 0xab96, 0xad98, 0x000a, 0x20a9,
+	0x0004, 0x1078, 0x80de, 0x00c0, 0x9f1f, 0x2011, 0xab9a, 0xad98,
+	0x0006, 0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x9f1f, 0x047e,
+	0x017e, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xa653,
+	0x210c, 0xd1a4, 0x0040, 0x9f0b, 0x2009, 0x0029, 0x1078, 0xa21d,
+	0x6800, 0xc0e5, 0x6802, 0x2019, 0x0029, 0x1078, 0x5f01, 0x077e,
+	0x2039, 0x0000, 0x1078, 0x5e0a, 0x2c08, 0x1078, 0x9f8b, 0x077f,
+	0x2001, 0x0007, 0x1078, 0x4535, 0x017f, 0x047f, 0xa006, 0x157f,
+	0x037f, 0x027f, 0x0d7f, 0x0c7f, 0x007c, 0x0d7e, 0x2069, 0xab8e,
+	0x6800, 0xa086, 0x0800, 0x0040, 0x9f31, 0x6013, 0x0000, 0x0078,
+	0x9f32, 0xa006, 0x0d7f, 0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e,
+	0x037e, 0x157e, 0x2079, 0xab8c, 0x7930, 0x7834, 0x1078, 0x254d,
+	0x00c0, 0x9f58, 0x1078, 0x45c4, 0x00c0, 0x9f58, 0x2011, 0xab90,
+	0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x80de, 0x00c0, 0x9f58,
+	0x2011, 0xab94, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078, 0x80de,
+	0x157f, 0x037f, 0x027f, 0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e,
+	0x007e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2011, 0xab83, 0x2204,
+	0x8211, 0x220c, 0x1078, 0x254d, 0x00c0, 0x9f84, 0x1078, 0x45c4,
+	0x00c0, 0x9f84, 0x2011, 0xab96, 0xac98, 0x000a, 0x20a9, 0x0004,
+	0x1078, 0x80de, 0x00c0, 0x9f84, 0x2011, 0xab9a, 0xac98, 0x0006,
+	0x20a9, 0x0004, 0x1078, 0x80de, 0x157f, 0x037f, 0x027f, 0x017f,
+	0x007f, 0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x087e, 0x077e, 0x067e,
+	0x057e, 0x047e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, 0x2029,
+	0xa8ba, 0x252c, 0x2021, 0xa8c0, 0x2424, 0x2061, 0xad00, 0x2071,
+	0xa600, 0x7648, 0x7064, 0x81ff, 0x0040, 0x9fb2, 0x007e, 0xa186,
+	0xa9b3, 0x007f, 0x0040, 0x9fb2, 0x8001, 0xa602, 0x00c8, 0xa01c,
+	0x0078, 0x9fb5, 0xa606, 0x0040, 0xa01c, 0x2100, 0xac06, 0x0040,
+	0xa012, 0x1078, 0xa242, 0x0040, 0xa012, 0x671c, 0xa786, 0x0001,
+	0x0040, 0xa037, 0xa786, 0x0004, 0x0040, 0xa037, 0xa786, 0x0007,
+	0x0040, 0xa012, 0x2500, 0xac06, 0x0040, 0xa012, 0x2400, 0xac06,
+	0x0040, 0xa012, 0x1078, 0xa256, 0x00c0, 0xa012, 0x88ff, 0x0040,
+	0x9fdd, 0x6020, 0xa906, 0x00c0, 0xa012, 0x0d7e, 0x6000, 0xa086,
+	0x0004, 0x00c0, 0x9fe7, 0x017e, 0x1078, 0x1757, 0x017f, 0xa786,
+	0x0008, 0x00c0, 0x9ff6, 0x1078, 0x8f00, 0x00c0, 0x9ff6, 0x1078,
+	0x7c83, 0x0d7f, 0x1078, 0x8ec6, 0x0078, 0xa012, 0x6010, 0x2068,
+	0x1078, 0x8d06, 0x0040, 0xa00f, 0xa786, 0x0003, 0x00c0, 0xa026,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0xa4e2, 0x017e,
+	0x1078, 0x8f7d, 0x1078, 0x4a73, 0x017f, 0x1078, 0x8eb9, 0x0d7f,
+	0x1078, 0x8ec6, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02,
+	0x00c8, 0xa01c, 0x0078, 0x9f9f, 0x127f, 0x027f, 0x047f, 0x057f,
+	0x067f, 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006,
+	0x00c0, 0xa000, 0xa386, 0x0005, 0x0040, 0xa034, 0x1078, 0xa4e2,
+	0x1078, 0xa1ca, 0x0078, 0xa00f, 0x0d7f, 0x0078, 0xa012, 0x1078,
+	0xa256, 0x00c0, 0xa012, 0x81ff, 0x0040, 0xa012, 0xa180, 0x0001,
+	0x2004, 0xa086, 0x0018, 0x0040, 0xa04c, 0xa180, 0x0001, 0x2004,
+	0xa086, 0x002d, 0x00c0, 0xa012, 0x6000, 0xa086, 0x0002, 0x00c0,
+	0xa012, 0x1078, 0x8eec, 0x0040, 0xa05d, 0x1078, 0x8f00, 0x00c0,
+	0xa012, 0x1078, 0x7c83, 0x0078, 0xa065, 0x1078, 0x28a6, 0x1078,
+	0x8f00, 0x00c0, 0xa065, 0x1078, 0x7c83, 0x1078, 0x8ec6, 0x0078,
+	0xa012, 0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0xa006, 0x1078,
+	0xa1e6, 0x017f, 0x0040, 0xa079, 0x601c, 0xa084, 0x000f, 0x1079,
+	0xa07c, 0x0e7f, 0x0c7f, 0x007c, 0xa084, 0xa084, 0xa084, 0xa084,
+	0xa084, 0xa084, 0xa086, 0xa084, 0xa006, 0x007c, 0x047e, 0x017e,
+	0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00,
+	0x2009, 0x0020, 0x1078, 0xa21d, 0x017f, 0x047f, 0x037e, 0x2019,
+	0x0002, 0x1078, 0x9dc7, 0x037f, 0xa085, 0x0001, 0x007c, 0x2001,
+	0x0001, 0x1078, 0x44ee, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9,
+	0x0004, 0x2019, 0xa605, 0x2011, 0xab96, 0x1078, 0x80de, 0x037f,
+	0x027f, 0x017f, 0x157f, 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e,
+	0x087e, 0x077e, 0x067e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740,
+	0x2061, 0xad00, 0x2079, 0x0001, 0x8fff, 0x0040, 0xa11d, 0x2071,
+	0xa600, 0x7648, 0x7064, 0x8001, 0xa602, 0x00c8, 0xa11d, 0x88ff,
+	0x0040, 0xa0d8, 0x2800, 0xac06, 0x00c0, 0xa113, 0x2079, 0x0000,
+	0x1078, 0xa242, 0x0040, 0xa113, 0x2400, 0xac06, 0x0040, 0xa113,
+	0x671c, 0xa786, 0x0006, 0x00c0, 0xa113, 0xa786, 0x0007, 0x0040,
+	0xa113, 0x88ff, 0x00c0, 0xa0f7, 0x6018, 0xa206, 0x00c0, 0xa113,
+	0x85ff, 0x0040, 0xa0f7, 0x6020, 0xa106, 0x00c0, 0xa113, 0x0d7e,
+	0x6000, 0xa086, 0x0004, 0x00c0, 0xa103, 0x1078, 0xa495, 0x601f,
+	0x0007, 0x1078, 0x1757, 0x6010, 0x2068, 0x1078, 0x8d06, 0x0040,
+	0xa10d, 0x047e, 0x1078, 0xa1ca, 0x047f, 0x0d7f, 0x1078, 0x8ec6,
+	0x88ff, 0x00c0, 0xa127, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004,
+	0xac02, 0x00c8, 0xa11d, 0x0078, 0xa0c4, 0xa006, 0x127f, 0x027f,
+	0x067f, 0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5,
+	0x0001, 0x0078, 0xa11e, 0x077e, 0x057e, 0x087e, 0x2041, 0x0000,
+	0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x097e, 0x2049,
+	0x0000, 0x1078, 0x7246, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078,
+	0x72f3, 0x1078, 0xa0b5, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e,
+	0x057e, 0x077e, 0x0c7e, 0x157e, 0x2c20, 0x2128, 0x20a9, 0x007f,
+	0x2009, 0x0000, 0x017e, 0x037e, 0x1078, 0x45c4, 0x00c0, 0xa16e,
+	0x2c10, 0x057e, 0x087e, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001,
+	0x097e, 0x2049, 0x0000, 0x1078, 0x7246, 0x097f, 0x087f, 0x2039,
+	0x0000, 0x1078, 0x72f3, 0x1078, 0xa0b5, 0x057f, 0x037f, 0x017f,
+	0x8108, 0x00f0, 0xa152, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f,
+	0x027f, 0x007c, 0x077e, 0x057e, 0x6218, 0x087e, 0x2041, 0x0000,
+	0x2029, 0x0001, 0x2019, 0x0048, 0x097e, 0x2049, 0x0000, 0x1078,
+	0x7246, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, 0x72f3, 0x2c20,
+	0x1078, 0xa0b5, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e,
+	0x077e, 0x0c7e, 0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x017e, 0x037e, 0x1078, 0x45c4, 0x00c0, 0xa1be, 0x2c10, 0x087e,
+	0x2041, 0x0000, 0x2828, 0x047e, 0x2021, 0x0001, 0x1078, 0xa472,
+	0x047f, 0x097e, 0x2049, 0x0000, 0x1078, 0x7246, 0x097f, 0x087f,
+	0x2039, 0x0000, 0x1078, 0x72f3, 0x1078, 0xa0b5, 0x037f, 0x017f,
+	0x8108, 0x00f0, 0xa1a0, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f,
+	0x027f, 0x007c, 0x017e, 0x0f7e, 0xad82, 0xcd00, 0x0048, 0xa1e3,
+	0xad82, 0xffff, 0x00c8, 0xa1e3, 0x6800, 0xa07d, 0x0040, 0xa1e0,
+	0x6803, 0x0000, 0x6b52, 0x1078, 0x4a73, 0x2f68, 0x0078, 0xa1d4,
+	0x6b52, 0x1078, 0x4a73, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e,
+	0x037e, 0x2061, 0xad00, 0xa005, 0x00c0, 0xa1f6, 0x2071, 0xa600,
+	0x7448, 0x7064, 0x8001, 0xa402, 0x00c8, 0xa218, 0x2100, 0xac06,
+	0x0040, 0xa20a, 0x6000, 0xa086, 0x0000, 0x0040, 0xa20a, 0x6008,
+	0xa206, 0x00c0, 0xa20a, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406,
+	0x0040, 0xa214, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004, 0xac02,
+	0x00c8, 0xa218, 0x0078, 0xa1f6, 0xa085, 0x0001, 0x0078, 0xa219,
+	0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c, 0x0d7e, 0x007e, 0x1078,
+	0x138b, 0x007f, 0x1040, 0x1332, 0x6837, 0x010d, 0x685e, 0x027e,
+	0x2010, 0x1078, 0x8cf2, 0x2001, 0x0000, 0x0040, 0xa233, 0x2200,
+	0xa080, 0x0008, 0x2004, 0x027f, 0x684a, 0x6956, 0x6c46, 0x684f,
+	0x0000, 0xa006, 0x68b2, 0x6802, 0x683a, 0x685a, 0x1078, 0x4a73,
+	0x0d7f, 0x007c, 0x6700, 0xa786, 0x0000, 0x0040, 0xa255, 0xa786,
+	0x0001, 0x0040, 0xa255, 0xa786, 0x000a, 0x0040, 0xa255, 0xa786,
+	0x0009, 0x0040, 0xa255, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x6018,
+	0x2070, 0x70a0, 0xa206, 0x0e7f, 0x007c, 0x017e, 0x6004, 0xa08e,
+	0x001e, 0x00c0, 0xa277, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105,
+	0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005, 0x2001,
+	0xa8a3, 0x2004, 0x6016, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x017f,
+	0x007c, 0x0005, 0x0005, 0x007c, 0x6024, 0xd0e4, 0x0040, 0xa28d,
+	0xd0cc, 0x0040, 0xa287, 0x1078, 0x8fbf, 0x0078, 0xa28d, 0x1078,
+	0xa495, 0x1078, 0x5bc1, 0x1078, 0x772d, 0x007c, 0xa280, 0x0007,
+	0x2004, 0xa084, 0x000f, 0x0079, 0xa295, 0xa29e, 0xa29e, 0xa29e,
+	0xa2a0, 0xa29e, 0xa2a0, 0xa2a0, 0xa29e, 0xa2a0, 0xa006, 0x007c,
+	0xa085, 0x0001, 0x007c, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f,
+	0x0079, 0xa2aa, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3, 0xa2b3,
+	0xa2be, 0xa2b3, 0xa2b3, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013,
+	0x2a00, 0x6003, 0x0001, 0x1078, 0x5d8a, 0x007c, 0x0c7e, 0x2260,
+	0x1078, 0xa495, 0x603f, 0x0000, 0x6024, 0xc0f4, 0xc0cc, 0x6026,
+	0x0c7f, 0x0d7e, 0x2268, 0xa186, 0x0007, 0x00c0, 0xa31f, 0x6810,
+	0xa005, 0x0040, 0xa2dc, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x00c0,
+	0xa2dc, 0x0d7f, 0x0078, 0xa2b3, 0x6007, 0x003a, 0x6003, 0x0001,
+	0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7e, 0x2d60, 0x6100, 0xa186,
+	0x0002, 0x00c0, 0xa3ad, 0x6010, 0xa005, 0x00c0, 0xa2f6, 0x6000,
+	0xa086, 0x0007, 0x10c0, 0x1332, 0x0078, 0xa3ad, 0xa08c, 0xf000,
+	0x00c0, 0xa302, 0x0078, 0xa302, 0x2068, 0x6800, 0xa005, 0x00c0,
+	0xa2fc, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084, 0x0003, 0xa086,
+	0x0002, 0x00c0, 0xa31b, 0x6010, 0x2068, 0x684c, 0xc0dc, 0xc0f4,
+	0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043, 0x1078,
+	0x9c1e, 0x0078, 0xa3ad, 0x2009, 0x0041, 0x0078, 0xa3a7, 0xa186,
+	0x0005, 0x00c0, 0xa366, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc,
+	0x00c0, 0xa32d, 0x0d7f, 0x0078, 0xa2b3, 0xd0b4, 0x0040, 0xa335,
+	0xd0fc, 0x1040, 0x1332, 0x0078, 0xa2cf, 0x6007, 0x003a, 0x6003,
+	0x0001, 0x1078, 0x5d8a, 0x1078, 0x62d1, 0x0c7e, 0x2d60, 0x6100,
+	0xa186, 0x0002, 0x0040, 0xa348, 0xa186, 0x0004, 0x00c0, 0xa3ad,
+	0x2071, 0xa8e7, 0x7000, 0xa086, 0x0003, 0x00c0, 0xa355, 0x7004,
+	0xac06, 0x00c0, 0xa355, 0x7003, 0x0000, 0x6810, 0xa080, 0x0013,
+	0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000, 0x200c, 0xc1f4, 0xc1fc,
+	0xc1bc, 0x2102, 0x2009, 0x0042, 0x0078, 0xa3a7, 0x037e, 0x0d7e,
+	0x0d7e, 0x1078, 0x138b, 0x037f, 0x1040, 0x1332, 0x6837, 0x010d,
+	0x6803, 0x0000, 0x683b, 0x0000, 0x685b, 0x0000, 0x6b5e, 0x6857,
+	0x0045, 0x2c00, 0x6862, 0x6034, 0x6872, 0x2360, 0x6024, 0xc0dd,
+	0x6026, 0x6018, 0xa080, 0x0028, 0x2004, 0xa084, 0x00ff, 0x8007,
+	0x6320, 0x6b4a, 0x6846, 0x684f, 0x0000, 0x6d6a, 0x6e66, 0x686f,
+	0x0001, 0x1078, 0x4a73, 0x2019, 0x0045, 0x6008, 0x2068, 0x1078,
+	0x9dc7, 0x2d00, 0x600a, 0x601f, 0x0006, 0x6003, 0x0007, 0x6017,
+	0x0000, 0x603f, 0x0000, 0x0d7f, 0x037f, 0x0078, 0xa3ae, 0x603f,
+	0x0000, 0x6003, 0x0007, 0x1078, 0x9c1e, 0x0c7f, 0x0d7f, 0x007c,
+	0xa186, 0x0013, 0x00c0, 0xa3ba, 0x6004, 0xa082, 0x0085, 0x2008,
+	0x0079, 0xa3d4, 0xa186, 0x0027, 0x00c0, 0xa3cd, 0x1078, 0x61cd,
+	0x037e, 0x0d7e, 0x6010, 0x2068, 0x2019, 0x0004, 0x1078, 0xa1ca,
+	0x0d7f, 0x037f, 0x1078, 0x62d1, 0x007c, 0xa186, 0x0014, 0x0040,
+	0xa3be, 0x1078, 0x7773, 0x007c, 0xa3dd, 0xa3db, 0xa3db, 0xa3db,
+	0xa3db, 0xa3db, 0xa3dd, 0x1078, 0x1332, 0x1078, 0x61cd, 0x6003,
+	0x000c, 0x1078, 0x62d1, 0x007c, 0xa182, 0x008c, 0x00c8, 0xa3ee,
+	0xa182, 0x0085, 0x0048, 0xa3ee, 0x0079, 0xa3f1, 0x1078, 0x7773,
+	0x007c, 0xa3f8, 0xa3f8, 0xa3f8, 0xa3f8, 0xa3fa, 0xa419, 0xa3f8,
+	0x1078, 0x1332, 0x0d7e, 0x2c68, 0x1078, 0x76c7, 0x0040, 0xa414,
+	0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xab8e, 0x210c, 0x6136,
+	0x2009, 0xab8f, 0x210c, 0x613a, 0x600b, 0xffff, 0x6918, 0x611a,
+	0x601f, 0x0004, 0x1078, 0x5d8a, 0x2d60, 0x1078, 0x772d, 0x0d7f,
+	0x007c, 0x1078, 0x772d, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000,
+	0xd0ec, 0x0e7f, 0x007c, 0x6010, 0xa08c, 0xf000, 0x0040, 0xa471,
+	0xa080, 0x0013, 0x200c, 0xd1ec, 0x0040, 0xa471, 0x2001, 0xa672,
+	0x2004, 0xd0ec, 0x0040, 0xa471, 0x6003, 0x0002, 0x6024, 0xc0e5,
+	0x6026, 0xd1ac, 0x0040, 0xa44f, 0x0f7e, 0x2c78, 0x1078, 0x495f,
+	0x0f7f, 0x0040, 0xa44f, 0x2001, 0xa8a4, 0x2004, 0x603e, 0x2009,
+	0xa672, 0x210c, 0xd1f4, 0x00c0, 0xa46f, 0x0078, 0xa461, 0x2009,
+	0xa672, 0x210c, 0xd1f4, 0x0040, 0xa45b, 0x6024, 0xc0e4, 0x6026,
+	0xa006, 0x0078, 0xa471, 0x2001, 0xa8a4, 0x200c, 0x8103, 0xa100,
+	0x603e, 0x6018, 0xa088, 0x002b, 0x2104, 0xa005, 0x0040, 0xa46c,
+	0xa088, 0x0003, 0x0078, 0xa464, 0x2c0a, 0x600f, 0x0000, 0xa085,
+	0x0001, 0x007c, 0x017e, 0x0c7e, 0x0e7e, 0x6120, 0xa2f0, 0x002b,
+	0x2e04, 0x2060, 0x8cff, 0x0040, 0xa491, 0x84ff, 0x00c0, 0xa484,
+	0x6020, 0xa106, 0x00c0, 0xa48c, 0x600c, 0x2072, 0x1078, 0x5bc1,
+	0x1078, 0x772d, 0x0078, 0xa48e, 0xacf0, 0x0003, 0x2e64, 0x0078,
+	0xa47a, 0x0e7f, 0x0c7f, 0x017f, 0x007c, 0x0d7e, 0x6018, 0xa0e8,
+	0x002b, 0x2d04, 0xa005, 0x0040, 0xa4a7, 0xac06, 0x0040, 0xa4a5,
+	0x2d04, 0xa0e8, 0x0003, 0x0078, 0xa499, 0x600c, 0x206a, 0x0d7f,
+	0x007c, 0x027e, 0x037e, 0x157e, 0x2011, 0xa626, 0x2204, 0xa084,
+	0x00ff, 0x2019, 0xab8e, 0x2334, 0xa636, 0x00c0, 0xa4d5, 0x8318,
+	0x2334, 0x2204, 0xa084, 0xff00, 0xa636, 0x00c0, 0xa4d5, 0x2011,
+	0xab90, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x1078, 0x80de,
+	0x00c0, 0xa4d5, 0x2011, 0xab94, 0x6018, 0xa098, 0x0006, 0x20a9,
+	0x0004, 0x1078, 0x80de, 0x00c0, 0xa4d5, 0x157f, 0x037f, 0x027f,
+	0x007c, 0x0e7e, 0x2071, 0xa600, 0x1078, 0x42b8, 0x1078, 0x2677,
+	0x0e7f, 0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0040,
+	0xa4eb, 0x1078, 0xa4ed, 0x0e7f, 0x007c, 0x6850, 0xc0e5, 0x6852,
+	0x007c, 0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e,
+	0x017e, 0x127e, 0x2091, 0x8000, 0x2029, 0xa8ba, 0x252c, 0x2021,
+	0xa8c0, 0x2424, 0x2061, 0xad00, 0x2071, 0xa600, 0x7648, 0x7064,
+	0xa606, 0x0040, 0xa545, 0x671c, 0xa786, 0x0001, 0x0040, 0xa514,
+	0xa786, 0x0008, 0x00c0, 0xa53b, 0x2500, 0xac06, 0x0040, 0xa53b,
+	0x2400, 0xac06, 0x0040, 0xa53b, 0x1078, 0xa242, 0x0040, 0xa53b,
+	0x1078, 0xa256, 0x00c0, 0xa53b, 0x6000, 0xa086, 0x0004, 0x00c0,
+	0xa52d, 0x017e, 0x1078, 0x1757, 0x017f, 0x1078, 0x8eec, 0x00c0,
+	0xa533, 0x1078, 0x28a6, 0x1078, 0x8f00, 0x00c0, 0xa539, 0x1078,
+	0x7c83, 0x1078, 0x8ec6, 0xace0, 0x0010, 0x2001, 0xa616, 0x2004,
+	0xac02, 0x00c8, 0xa545, 0x0078, 0xa504, 0x127f, 0x017f, 0x027f,
+	0x047f, 0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0x127e,
+	0x007e, 0x0e7e, 0x017e, 0x2091, 0x8000, 0x2071, 0xa640, 0xd5a4,
+	0x0040, 0xa55d, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa563,
+	0x7030, 0x8000, 0x7032, 0xd5ac, 0x0040, 0xa579, 0x2500, 0xa084,
+	0x0007, 0xa08e, 0x0003, 0x0040, 0xa579, 0xa08e, 0x0004, 0x0040,
+	0xa579, 0xa08e, 0x0005, 0x0040, 0xa579, 0x2071, 0xa64a, 0x1078,
+	0xa5ba, 0x017f, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e,
+	0x0e7e, 0x017e, 0x2091, 0x8000, 0x2071, 0xa640, 0xd5a4, 0x0040,
+	0xa58c, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa592, 0x7030,
+	0x8000, 0x7032, 0xd5ac, 0x0040, 0xa5a8, 0x2500, 0xa084, 0x0007,
+	0xa08e, 0x0003, 0x0040, 0xa5a8, 0xa08e, 0x0004, 0x0040, 0xa5a8,
+	0xa08e, 0x0005, 0x0040, 0xa5a8, 0x2071, 0xa64a, 0x1078, 0xa5ba,
+	0x017f, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e,
+	0x2091, 0x8000, 0x2071, 0xa642, 0x1078, 0xa5ba, 0x0e7f, 0x007f,
+	0x127f, 0x007c, 0x2e04, 0x8000, 0x2072, 0x00c8, 0xa5c3, 0x8e70,
+	0x2e04, 0x8000, 0x2072, 0x007c, 0x0e7e, 0x2071, 0xa640, 0x1078,
+	0xa5ba, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa644, 0x1078, 0xa5ba,
+	0x0e7f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071,
+	0xa640, 0x7044, 0x8000, 0x7046, 0x0e7f, 0x007f, 0x127f, 0x007c,
+	0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+	0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
+	0xa50c
+};
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2100tp_length01 = 0x95f1;
+#else
+unsigned short risc_code_length01 = 0x95f1;
+#endif
+
diff --git a/drivers/scsi/qla2xxx/ql2200.c b/drivers/scsi/qla2xxx/ql2200.c
new file mode 100644
index 0000000..2f5698d
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2200.c
@@ -0,0 +1,92 @@
+/*
+ * QLogic ISP2200 device driver for Linux 2.6.x
+ * Copyright (C) 2003 Christoph Hellwig.
+ * Copyright (C) 2003-2004 QLogic Corporation (www.qlogic.com)
+ *
+ * Released under GPL v2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "qla_def.h"
+
+static char qla_driver_name[] = "qla2200";
+
+extern unsigned char  fw2200tp_version[];
+extern unsigned char  fw2200tp_version_str[];
+extern unsigned short fw2200tp_addr01;
+extern unsigned short fw2200tp_code01[];
+extern unsigned short fw2200tp_length01;
+
+static struct qla_fw_info qla_fw_tbl[] = {
+	{
+		.addressing	= FW_INFO_ADDR_NORMAL,
+		.fwcode		= &fw2200tp_code01[0],
+		.fwlen		= &fw2200tp_length01,
+		.fwstart	= &fw2200tp_addr01,
+	},
+
+	{ FW_INFO_ADDR_NOMORE, },
+};
+
+static struct qla_board_info qla_board_tbl = {
+	.drv_name	= qla_driver_name,
+
+	.isp_name	= "ISP2200",
+	.fw_info	= qla_fw_tbl,
+};
+
+static struct pci_device_id qla2200_pci_tbl[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP2200,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl,
+	},
+
+	{0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla2200_pci_tbl);
+
+static int __devinit
+qla2200_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return qla2x00_probe_one(pdev,
+	    (struct qla_board_info *)id->driver_data);
+}
+
+static void __devexit
+qla2200_remove_one(struct pci_dev *pdev)
+{
+	qla2x00_remove_one(pdev);
+}
+
+static struct pci_driver qla2200_pci_driver = {
+	.name		= "qla2200",
+	.id_table	= qla2200_pci_tbl,
+	.probe		= qla2200_probe_one,
+	.remove		= __devexit_p(qla2200_remove_one),
+};
+
+static int __init
+qla2200_init(void)
+{
+	return pci_module_init(&qla2200_pci_driver);
+}
+
+static void __exit
+qla2200_exit(void)
+{
+	pci_unregister_driver(&qla2200_pci_driver);
+}
+
+module_init(qla2200_init);
+module_exit(qla2200_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP22xx FC-SCSI Host Bus Adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/ql2200_fw.c b/drivers/scsi/qla2xxx/ql2200_fw.c
new file mode 100644
index 0000000..5412dcb
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2200_fw.c
@@ -0,0 +1,5321 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ *************************************************************************/
+
+/*
+ *	Firmware Version 2.02.06 (08:46 Jun 26, 2003)
+ */
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2200tp_version = 2*1024+2;
+#else
+unsigned short risc_code_version = 2*1024+2;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned char fw2200tp_version_str[] = {2,2,6};
+#else
+unsigned char firmware_version[] = {2,2,6};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw2200tp_VERSION_STRING "2.02.06"
+#else
+#define FW_VERSION_STRING "2.02.06"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2200tp_addr01 = 0x1000 ;
+#else
+unsigned short risc_code_addr01 = 0x1000 ;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2200tp_code01[] = { 
+#else
+unsigned short risc_code01[] = { 
+#endif
+	0x0470, 0x0000, 0x0000, 0xa46f, 0x0000, 0x0002, 0x0002, 0x0006,
+	0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030,
+	0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x322e, 0x3032, 0x2e30, 0x3620, 0x2020, 0x2020, 0x2400, 0x20c1,
+	0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0xbaff, 0x2091,
+	0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x296a,
+	0x2051, 0xb500, 0x2a70, 0x2029, 0xed00, 0x2031, 0xffff, 0x2039,
+	0xece9, 0x2021, 0x0200, 0x0804, 0x1468, 0x20a1, 0xb46f, 0xa00e,
+	0x20a9, 0x0891, 0x41a4, 0x3400, 0x7562, 0x7666, 0x775e, 0x746a,
+	0x746e, 0x20a1, 0xbd00, 0x7164, 0x810d, 0x810d, 0x810d, 0x810d,
+	0xa18c, 0x000f, 0x2001, 0x000b, 0xa112, 0xa00e, 0x21a8, 0x41a4,
+	0x3400, 0x8211, 0x1dd8, 0x7164, 0x3400, 0xa102, 0x0120, 0x0218,
+	0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0xb500,
+	0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001,
+	0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0,
+	0x2009, 0xb500, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e,
+	0x41a4, 0x080c, 0x1411, 0x080c, 0x1632, 0x080c, 0x17cf, 0x080c,
+	0x1fa2, 0x080c, 0x4bff, 0x080c, 0x85bf, 0x080c, 0x15bb, 0x080c,
+	0x2ec4, 0x080c, 0x5d8a, 0x080c, 0x5341, 0x080c, 0x68ce, 0x080c,
+	0x2510, 0x080c, 0x6b61, 0x080c, 0x63bb, 0x080c, 0x23ca, 0x080c,
+	0x24de, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, 0x10c5, 0x7820,
+	0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, 0x10bd, 0x781b,
+	0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000,
+	0x2a70, 0x7000, 0xa08e, 0x0003, 0x1158, 0x080c, 0x3f08, 0x080c,
+	0x2eeb, 0x080c, 0x5dd8, 0x080c, 0x54f0, 0x080c, 0x68f9, 0x0c80,
+	0x000b, 0x0c98, 0x10e4, 0x10e5, 0x1210, 0x10e2, 0x12dd, 0x140e,
+	0x140f, 0x1410, 0x080c, 0x1515, 0x0005, 0x0126, 0x00f6, 0x2091,
+	0x8000, 0x7000, 0xa086, 0x0001, 0x1904, 0x11ed, 0x080c, 0x1588,
+	0x080c, 0x5acf, 0x0150, 0x080c, 0x5af5, 0x15c0, 0x2079, 0x0100,
+	0x7828, 0xa085, 0x1800, 0x782a, 0x0488, 0x080c, 0x5a07, 0x7000,
+	0xa086, 0x0001, 0x1904, 0x11ed, 0x708c, 0xa086, 0x0028, 0x1904,
+	0x11ed, 0x2001, 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, 0x7827,
+	0xffff, 0x7a28, 0xa295, 0x1e2f, 0x7a2a, 0x2011, 0x59a2, 0x080c,
+	0x699c, 0x2011, 0x5995, 0x080c, 0x6a5c, 0x2011, 0x59e4, 0x080c,
+	0x699c, 0x2011, 0x4adc, 0x080c, 0x699c, 0x2011, 0x8030, 0x2019,
+	0x0000, 0x708b, 0x0000, 0x080c, 0x1de9, 0x00e8, 0x080c, 0x448f,
+	0x2079, 0x0100, 0x7844, 0xa005, 0x1904, 0x11ed, 0x2011, 0x4adc,
+	0x080c, 0x699c, 0x2011, 0x59e4, 0x080c, 0x699c, 0x080c, 0x1de9,
+	0x2001, 0xb78d, 0x2004, 0x780e, 0x7840, 0xa084, 0xfffb, 0x7842,
+	0x2011, 0x8010, 0x73cc, 0x080c, 0x3ecc, 0x723c, 0xc284, 0x723e,
+	0x2001, 0xb50c, 0x200c, 0xc1ac, 0x2102, 0x080c, 0x7f35, 0x2011,
+	0x0004, 0x080c, 0x9c60, 0x080c, 0x524d, 0x080c, 0x5acf, 0x0158,
+	0x080c, 0x4be8, 0x0140, 0x708b, 0x0001, 0x70c7, 0x0000, 0x080c,
+	0x462c, 0x0804, 0x11ed, 0x080c, 0x5309, 0x0120, 0x7a0c, 0xc2b4,
+	0x7a0e, 0x0060, 0x7073, 0x0000, 0x080c, 0xa008, 0x70d4, 0xd09c,
+	0x1128, 0x70a0, 0xa005, 0x0110, 0x080c, 0x4bc6, 0x70df, 0x0000,
+	0x70db, 0x0000, 0x72d4, 0x080c, 0x5acf, 0x1178, 0x2011, 0x0000,
+	0x0016, 0x080c, 0x28eb, 0x2019, 0xb78f, 0x211a, 0x001e, 0x7053,
+	0xffff, 0x7057, 0x00ef, 0x7077, 0x0000, 0x2079, 0xb552, 0x7804,
+	0xd0ac, 0x0108, 0xc295, 0x72d6, 0x080c, 0x5acf, 0x0118, 0xa296,
+	0x0004, 0x0548, 0x2011, 0x0001, 0x080c, 0x9c60, 0x709b, 0x0000,
+	0x709f, 0xffff, 0x7003, 0x0002, 0x2079, 0x0100, 0x7827, 0x0003,
+	0x7828, 0xa085, 0x0003, 0x782a, 0x00fe, 0x080c, 0x2ab8, 0x2011,
+	0x0005, 0x080c, 0x8075, 0x080c, 0x7173, 0x080c, 0x5acf, 0x0148,
+	0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x28eb, 0x61e2, 0x001e,
+	0x00ce, 0x012e, 0x0420, 0x709b, 0x0000, 0x709f, 0xffff, 0x7003,
+	0x0002, 0x00f6, 0x2079, 0x0100, 0x7827, 0x0003, 0x7828, 0xa085,
+	0x0003, 0x782a, 0x00fe, 0x2011, 0x0005, 0x080c, 0x8075, 0x080c,
+	0x7173, 0x080c, 0x5acf, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016,
+	0x080c, 0x28eb, 0x61e2, 0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005,
+	0x00c6, 0x080c, 0x5acf, 0x1118, 0x20a9, 0x0100, 0x0010, 0x20a9,
+	0x0082, 0x080c, 0x5acf, 0x1118, 0x2009, 0x0000, 0x0010, 0x2009,
+	0x007e, 0x080c, 0x2d97, 0x8108, 0x1f04, 0x1201, 0x00ce, 0x7073,
+	0x0000, 0x7074, 0xa084, 0x00ff, 0x7076, 0x70a3, 0x0000, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x7000, 0xa086, 0x0002, 0x1904, 0x12db,
+	0x709c, 0xa086, 0xffff, 0x0130, 0x080c, 0x2ab8, 0x080c, 0x7173,
+	0x0804, 0x12db, 0x70d4, 0xd0ac, 0x1110, 0xd09c, 0x0540, 0xd084,
+	0x0530, 0x0006, 0x0016, 0x2001, 0x0103, 0x2009, 0xb78d, 0x210c,
+	0x2102, 0x001e, 0x000e, 0xd08c, 0x01d0, 0x70d8, 0xa086, 0xffff,
+	0x0190, 0x080c, 0x2c17, 0x080c, 0x7173, 0x70d4, 0xd094, 0x1904,
+	0x12db, 0x2011, 0x0001, 0x2019, 0x0000, 0x080c, 0x2c4f, 0x080c,
+	0x7173, 0x0804, 0x12db, 0x70dc, 0xa005, 0x1904, 0x12db, 0x7098,
+	0xa005, 0x1904, 0x12db, 0x70d4, 0xd0a4, 0x0118, 0xd0b4, 0x0904,
+	0x12db, 0x080c, 0x5309, 0x1904, 0x12db, 0x2001, 0xb553, 0x2004,
+	0xd0ac, 0x01c8, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x0016, 0x080c, 0x4fa9, 0x1118, 0x6000, 0xd0ec, 0x1138, 0x001e,
+	0x8108, 0x1f04, 0x1268, 0x00ce, 0x015e, 0x0028, 0x001e, 0x00ce,
+	0x015e, 0x0804, 0x12db, 0x0006, 0x0016, 0x2001, 0x0103, 0x2009,
+	0xb78d, 0x210c, 0x2102, 0x001e, 0x000e, 0x71a8, 0x81ff, 0x11b0,
+	0xa006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x20a1, 0xb7de, 0x40a1,
+	0x2009, 0x0700, 0x20a9, 0x0002, 0x20a1, 0xb7ce, 0x40a1, 0x7070,
+	0x8007, 0x7174, 0x810f, 0x20a9, 0x0002, 0x40a1, 0x20a1, 0xb7d2,
+	0x2009, 0x0000, 0x080c, 0x14fb, 0x2001, 0x0000, 0x810f, 0x20a9,
+	0x0002, 0x40a1, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x709f,
+	0xffff, 0x080c, 0x1581, 0xa006, 0x080c, 0x27c3, 0x080c, 0x3f3e,
+	0x00f6, 0x2079, 0x0100, 0x080c, 0x5af5, 0x0150, 0x080c, 0x5acf,
+	0x7828, 0x0118, 0xa084, 0xe1ff, 0x0010, 0xa084, 0xffdf, 0x782a,
+	0x00fe, 0x2001, 0xb7e1, 0x2004, 0xa086, 0x0005, 0x1120, 0x2011,
+	0x0000, 0x080c, 0x8075, 0x2011, 0x0000, 0x080c, 0x807f, 0x080c,
+	0x7173, 0x080c, 0x7230, 0x012e, 0x0005, 0x0016, 0x0046, 0x00f6,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0xb534, 0x2104,
+	0xa005, 0x1110, 0x080c, 0x2917, 0x2009, 0x00f7, 0x080c, 0x4baf,
+	0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827,
+	0x0040, 0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156,
+	0x7954, 0xd1ac, 0x1904, 0x134b, 0x080c, 0x5ae1, 0x0158, 0x080c,
+	0x5af5, 0x1128, 0x2001, 0xb79e, 0x2003, 0x0000, 0x0070, 0x080c,
+	0x5ad7, 0x0dc0, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f,
+	0x2003, 0x0001, 0x080c, 0x5a07, 0x0058, 0x080c, 0x5acf, 0x0140,
+	0x2009, 0x00f8, 0x080c, 0x4baf, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x5acf, 0x0138,
+	0x7824, 0xd0ac, 0x1904, 0x13f5, 0x1f04, 0x132a, 0x0070, 0x7824,
+	0x080c, 0x5aeb, 0x0118, 0xd0ac, 0x1904, 0x13f5, 0xa084, 0x1800,
+	0x0d98, 0x7003, 0x0001, 0x0804, 0x13f5, 0x2001, 0x0001, 0x080c,
+	0x27c3, 0x0804, 0x1404, 0x7850, 0xa084, 0x0180, 0x7852, 0x782f,
+	0x0020, 0x20a9, 0x0046, 0x1d04, 0x1353, 0x080c, 0x6a44, 0x1f04,
+	0x1353, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x782f,
+	0x0000, 0x080c, 0x5ae1, 0x0158, 0x080c, 0x5af5, 0x1128, 0x2001,
+	0xb79e, 0x2003, 0x0000, 0x0070, 0x080c, 0x5ad7, 0x0dc0, 0x2001,
+	0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, 0x2003, 0x0001, 0x080c,
+	0x5a07, 0x0020, 0x2009, 0x00f8, 0x080c, 0x4baf, 0x20a9, 0x000e,
+	0xe000, 0x1f04, 0x1380, 0x7850, 0xa084, 0x0180, 0xa085, 0x1400,
+	0x7852, 0x080c, 0x5acf, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x2021, 0xe678, 0x2019, 0xea60, 0x7820, 0xd09c, 0x1558, 0x080c,
+	0x5acf, 0x05d8, 0x7824, 0xd0ac, 0x1904, 0x13f5, 0x080c, 0x5af5,
+	0x1508, 0x0046, 0x2021, 0x0190, 0x8421, 0x1df0, 0x004e, 0x8421,
+	0x11c8, 0x7827, 0x0048, 0x20a9, 0x01f4, 0x1d04, 0x13ad, 0x080c,
+	0x6a44, 0x1f04, 0x13ad, 0x7824, 0xa084, 0x0068, 0x15c8, 0x2001,
+	0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f, 0x2003, 0x0001, 0x7003,
+	0x0001, 0x0498, 0x1d04, 0x13c6, 0x080c, 0x6a44, 0x8319, 0x1960,
+	0x2009, 0xb534, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0120,
+	0x200b, 0x0000, 0x080c, 0x2917, 0x00d8, 0x080c, 0x5ae1, 0x1140,
+	0xa4a2, 0x0064, 0x1128, 0x080c, 0x5aa6, 0x7003, 0x0001, 0x00a8,
+	0x7827, 0x1800, 0xe000, 0xe000, 0x7824, 0x080c, 0x5aeb, 0x0110,
+	0xd0ac, 0x1158, 0xa084, 0x1800, 0x09a8, 0x7003, 0x0001, 0x0028,
+	0x2001, 0x0001, 0x080c, 0x27c3, 0x0048, 0x2001, 0xb534, 0x2003,
+	0x0000, 0x7827, 0x0048, 0x7828, 0xc09d, 0x782a, 0x7850, 0xa084,
+	0x0180, 0xa085, 0x0400, 0x7852, 0x015e, 0x003e, 0x000e, 0x080c,
+	0x1558, 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0005, 0x0005,
+	0x0005, 0x2a70, 0x2061, 0xb7c1, 0x2063, 0x0002, 0x6007, 0x0002,
+	0x600b, 0x0006, 0x600f, 0x0017, 0x2001, 0xb79e, 0x2003, 0x0000,
+	0x708b, 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0218,
+	0x7053, 0xffff, 0x0010, 0x7053, 0x0000, 0x705b, 0xffff, 0x7073,
+	0x0000, 0x7077, 0x0000, 0x080c, 0xa008, 0x2061, 0xb78e, 0x6003,
+	0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013,
+	0x00ff, 0x6017, 0x000f, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061,
+	0xb796, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f,
+	0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f,
+	0x0000, 0x2061, 0xb7b9, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b,
+	0x4943, 0x600f, 0x2020, 0x2001, 0xb528, 0x2003, 0x0000, 0x0005,
+	0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, 0xa186, 0x0001, 0x1148,
+	0x2031, 0x8fff, 0x2039, 0xd501, 0x2021, 0x0100, 0x2029, 0xd500,
+	0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, 0x0000, 0x00b8, 0xa186,
+	0x0005, 0x1118, 0x2011, 0x0001, 0x0088, 0xa186, 0x0009, 0x1118,
+	0x2011, 0x0002, 0x0058, 0xa186, 0x000a, 0x1118, 0x2011, 0x0002,
+	0x0028, 0xa186, 0x0055, 0x1110, 0x2011, 0x0003, 0x3800, 0xa084,
+	0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, 0xa00e, 0x2011, 0x0003,
+	0x2019, 0x14a4, 0x0804, 0x14f5, 0x2019, 0xaaaa, 0x2061, 0xffff,
+	0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0xa306, 0x2262, 0x1110,
+	0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, 0x14b7, 0x04f0, 0x2019,
+	0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c1c,
+	0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, 0x2061, 0xffff, 0x2262,
+	0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, 0x2011, 0x0002, 0x2019,
+	0x14d2, 0x0418, 0x2061, 0xffff, 0x2019, 0xaaaa, 0x2c14, 0x2362,
+	0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, 0x1180, 0x2c14, 0x2362,
+	0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0x2c04, 0x2061, 0xffff,
+	0x2262, 0xa306, 0x1110, 0xc195, 0x0008, 0xc19d, 0x2011, 0x0001,
+	0x2019, 0x14f3, 0x0010, 0x0804, 0x1469, 0x3800, 0xa084, 0xfffc,
+	0xa205, 0x20c0, 0x0837, 0x2011, 0x0000, 0x080c, 0x4fa9, 0x1178,
+	0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0128, 0xa0c4, 0xff00,
+	0xa8c6, 0x0600, 0x1120, 0xa186, 0x0080, 0x0108, 0x8210, 0x8108,
+	0xa186, 0x0100, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000, 0x0e04,
+	0x1517, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084, 0x1de8,
+	0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900, 0x783a,
+	0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0126, 0x0156,
+	0x0146, 0x20a9, 0x0010, 0x20a1, 0xb90c, 0x2091, 0x2000, 0x40a1,
+	0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010, 0x2091,
+	0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1, 0x20a9,
+	0x0010, 0x2091, 0x2800, 0x40a1, 0x014e, 0x015e, 0x012e, 0x2079,
+	0xb500, 0x7803, 0x0005, 0x2091, 0x4080, 0x04c9, 0x0cf8, 0x0005,
+	0x0006, 0x080c, 0x15a3, 0x1518, 0x00f6, 0x2079, 0xb524, 0x2f04,
+	0x8000, 0x207a, 0xa082, 0x000f, 0x0258, 0xa006, 0x207a, 0x2079,
+	0xb526, 0x2f04, 0xa084, 0x0001, 0xa086, 0x0001, 0x207a, 0x0070,
+	0x2079, 0xb526, 0x2f7c, 0x8fff, 0x1128, 0x2001, 0x0c03, 0x2003,
+	0x0040, 0x0020, 0x2001, 0x0c03, 0x2003, 0x00c0, 0x00fe, 0x000e,
+	0x0005, 0x0409, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0080, 0x0005,
+	0x00d1, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0040, 0x0005, 0x0006,
+	0x0091, 0x1178, 0x2001, 0x0c03, 0x2003, 0x0040, 0x2009, 0x0fff,
+	0x00a1, 0x2001, 0x0c03, 0x2003, 0x0080, 0x2009, 0x0fff, 0x0069,
+	0x0c88, 0x000e, 0x0005, 0x00c6, 0x2061, 0x0c00, 0x2c04, 0xa084,
+	0x00ff, 0xa086, 0x00aa, 0x00ce, 0x0005, 0x0156, 0x0126, 0xa18c,
+	0x0fff, 0x21a8, 0x1d04, 0x15b2, 0x2091, 0x6000, 0x1f04, 0x15b2,
+	0x012e, 0x015e, 0x0005, 0x2071, 0xb500, 0x7160, 0x712e, 0x2021,
+	0x0001, 0xa190, 0x0030, 0xa298, 0x0030, 0x0240, 0x7064, 0xa302,
+	0x1228, 0x220a, 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800, 0xd08c,
+	0x0148, 0x7064, 0xa086, 0xb500, 0x0128, 0x7067, 0xb500, 0x2011,
+	0x1000, 0x0c48, 0x200b, 0x0000, 0x74b2, 0x74b6, 0x0005, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x70b4, 0xa0ea, 0x0010,
+	0x0268, 0x8001, 0x70b6, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b,
+	0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8,
+	0x00e6, 0x2071, 0xb500, 0x0126, 0x2091, 0x8000, 0x70b4, 0x8001,
+	0x0260, 0x70b6, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b, 0x0000,
+	0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x702c, 0x206a, 0x2d00,
+	0x702e, 0x70b4, 0x8000, 0x70b6, 0x012e, 0x00ee, 0x0005, 0x8dff,
+	0x0138, 0x6804, 0x6807, 0x0000, 0x0006, 0x0c49, 0x00de, 0x0cb8,
+	0x0005, 0x00e6, 0x2071, 0xb500, 0x70b4, 0xa08a, 0x0010, 0xa00d,
+	0x00ee, 0x0005, 0x00e6, 0x2071, 0xb812, 0x7007, 0x0000, 0x701b,
+	0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004,
+	0x7012, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x00e6, 0x2270,
+	0x700b, 0x0000, 0x2071, 0xb812, 0x7018, 0xa088, 0xb81b, 0x220a,
+	0x8000, 0xa084, 0x0007, 0x701a, 0x7004, 0xa005, 0x1128, 0x00f6,
+	0x2079, 0x0010, 0x0089, 0x00fe, 0x00ee, 0x012e, 0x0005, 0x00e6,
+	0x2071, 0xb812, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010,
+	0x0019, 0x00fe, 0x00ee, 0x0005, 0x7000, 0x0002, 0x1672, 0x16d6,
+	0x16f3, 0x16f3, 0x7018, 0x711c, 0xa106, 0x1118, 0x7007, 0x0000,
+	0x0005, 0x00d6, 0xa180, 0xb81b, 0x2004, 0x700a, 0x2068, 0x8108,
+	0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828,
+	0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c,
+	0x7016, 0x6804, 0x00de, 0xd084, 0x0120, 0x7007, 0x0001, 0x0029,
+	0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c,
+	0x2011, 0x0040, 0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e,
+	0x7212, 0x8203, 0x7822, 0x7803, 0x0020, 0x7803, 0x0041, 0x002e,
+	0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156, 0x7014,
+	0x2098, 0x20a1, 0x0014, 0x7803, 0x0026, 0x710c, 0x2011, 0x0040,
+	0xa182, 0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6,
+	0x8203, 0x7822, 0x7803, 0x0020, 0x3300, 0x7016, 0x7803, 0x0001,
+	0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x0136, 0x0146,
+	0x0156, 0x2099, 0xb5fa, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3,
+	0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0041, 0x7007,
+	0x0003, 0x7000, 0xc084, 0x7002, 0x700b, 0xb5f5, 0x012e, 0x015e,
+	0x014e, 0x013e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2001, 0xb629,
+	0x209c, 0x20a1, 0x0014, 0x7803, 0x0026, 0x2001, 0xb62a, 0x20ac,
+	0x53a6, 0x2099, 0xb62b, 0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3,
+	0x7803, 0x0020, 0x0126, 0x2091, 0x8000, 0x7803, 0x0001, 0x7007,
+	0x0004, 0x7000, 0xc08c, 0x7002, 0x700b, 0xb626, 0x012e, 0x015e,
+	0x014e, 0x013e, 0x0005, 0x0016, 0x00e6, 0x2071, 0xb812, 0x00f6,
+	0x2079, 0x0010, 0x7904, 0x7803, 0x0002, 0xd1fc, 0x0120, 0xa18c,
+	0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x166c,
+	0x1736, 0x1764, 0x178e, 0x17be, 0x1735, 0x0cf8, 0xa18c, 0x0700,
+	0x1528, 0x0136, 0x0146, 0x0156, 0x7014, 0x20a0, 0x2099, 0x0014,
+	0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016, 0x015e,
+	0x014e, 0x013e, 0x700c, 0xa005, 0x0570, 0x7830, 0x7832, 0x7834,
+	0x7836, 0x080c, 0x169d, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003,
+	0x0100, 0x7007, 0x0000, 0x080c, 0x166c, 0x0005, 0x7008, 0xa080,
+	0x0002, 0x2003, 0x0200, 0x0ca8, 0xa18c, 0x0700, 0x1150, 0x700c,
+	0xa005, 0x0188, 0x7830, 0x7832, 0x7834, 0x7836, 0x080c, 0x16b2,
+	0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200, 0x7007, 0x0000,
+	0x080c, 0x166c, 0x0005, 0x00d6, 0x7008, 0x2068, 0x7830, 0x6826,
+	0x7834, 0x682a, 0x7838, 0x682e, 0x783c, 0x6832, 0x680b, 0x0100,
+	0x00de, 0x7007, 0x0000, 0x080c, 0x166c, 0x0005, 0xa18c, 0x0700,
+	0x1540, 0x0136, 0x0146, 0x0156, 0x2001, 0xb5f8, 0x2004, 0xa080,
+	0x000d, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020,
+	0x53a5, 0x2001, 0xb5fa, 0x2004, 0xd0bc, 0x0148, 0x2001, 0xb603,
+	0x2004, 0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x015e,
+	0x014e, 0x013e, 0x7007, 0x0000, 0x080c, 0x5e6f, 0x080c, 0x166c,
+	0x0005, 0x2011, 0x8003, 0x080c, 0x3ecc, 0x0cf8, 0xa18c, 0x0700,
+	0x1148, 0x2001, 0xb628, 0x2003, 0x0100, 0x7007, 0x0000, 0x080c,
+	0x166c, 0x0005, 0x2011, 0x8004, 0x080c, 0x3ecc, 0x0cf8, 0x0126,
+	0x2091, 0x2200, 0x2079, 0x0030, 0x2071, 0xb823, 0x7003, 0x0000,
+	0x700f, 0xb82f, 0x7013, 0xb82f, 0x780f, 0x00f6, 0x7803, 0x0004,
+	0x012e, 0x0005, 0x6934, 0xa184, 0x0007, 0x0002, 0x17ee, 0x182c,
+	0x17ee, 0x17ee, 0x17ee, 0x1814, 0x17fb, 0x17f2, 0xa085, 0x0001,
+	0x0804, 0x1846, 0x684c, 0xd0bc, 0x0dc8, 0x6860, 0x682e, 0x685c,
+	0x682a, 0x6858, 0x04c8, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d70,
+	0x684c, 0xd0bc, 0x0d58, 0x6860, 0x682e, 0x685c, 0x682a, 0x6804,
+	0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x22e5,
+	0x2005, 0x6832, 0x6858, 0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015,
+	0x19a8, 0x684c, 0xd0ac, 0x0990, 0x6804, 0x681a, 0xa080, 0x000d,
+	0x2004, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0xa006,
+	0x682e, 0x682a, 0x6858, 0x0080, 0x684c, 0xd0ac, 0x0904, 0x17ee,
+	0xa006, 0x682e, 0x682a, 0x6858, 0xa18c, 0x000f, 0xa188, 0x22e5,
+	0x210d, 0x6932, 0x2d08, 0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e,
+	0xa006, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x684c,
+	0xd0ac, 0x090c, 0x1515, 0x6833, 0x22e2, 0x2d08, 0x691a, 0x6858,
+	0x8001, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x682e,
+	0x682a, 0x697c, 0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007,
+	0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x82ff, 0x01e8, 0xa280,
+	0x0004, 0x00d6, 0x206c, 0x684c, 0xd0dc, 0x1190, 0xa280, 0x0007,
+	0x2004, 0xa086, 0x000a, 0x1110, 0x0891, 0x0010, 0x080c, 0x17e2,
+	0x0138, 0x00de, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0020,
+	0x6808, 0x8000, 0x680a, 0x00de, 0x0126, 0x0046, 0x0036, 0x0026,
+	0x2091, 0x2200, 0x002e, 0x003e, 0x004e, 0x7000, 0xa005, 0x01d0,
+	0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182,
+	0xb84a, 0x0210, 0x2009, 0xb82f, 0x710e, 0x7010, 0xa102, 0xa082,
+	0x0009, 0x0118, 0xa080, 0x001b, 0x1118, 0x2009, 0x0138, 0x200a,
+	0x012e, 0x0005, 0x7206, 0x2001, 0x18a8, 0x0006, 0x2260, 0x0804,
+	0x19d5, 0x0126, 0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200,
+	0x000e, 0x004e, 0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110,
+	0x2168, 0x6a62, 0x6b5e, 0xa005, 0x0904, 0x190a, 0x6808, 0xa005,
+	0x0904, 0x1941, 0x7000, 0xa005, 0x1108, 0x0488, 0x700c, 0x7110,
+	0xa106, 0x1904, 0x1949, 0x7004, 0xa406, 0x1548, 0x2001, 0x0005,
+	0x2004, 0xd08c, 0x0168, 0x0046, 0x080c, 0x1b06, 0x004e, 0x2460,
+	0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0904, 0x1941, 0x0c10,
+	0x2001, 0x0207, 0x2004, 0xd09c, 0x1d48, 0x7804, 0xa084, 0x6000,
+	0x0120, 0xa086, 0x6000, 0x0108, 0x0c08, 0x7818, 0x6812, 0x781c,
+	0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6100,
+	0xa18e, 0x0004, 0x1904, 0x1949, 0x2009, 0x0048, 0x080c, 0x864c,
+	0x0804, 0x1949, 0x6808, 0xa005, 0x05a0, 0x7000, 0xa005, 0x0588,
+	0x700c, 0x7110, 0xa106, 0x1118, 0x7004, 0xa406, 0x1550, 0x2001,
+	0x0005, 0x2004, 0xd08c, 0x0160, 0x0046, 0x080c, 0x1b06, 0x004e,
+	0x2460, 0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x01d0, 0x0c28,
+	0x2001, 0x0207, 0x2004, 0xd09c, 0x1d50, 0x2001, 0x0005, 0x2004,
+	0xd08c, 0x1d50, 0x7804, 0xa084, 0x6000, 0x0118, 0xa086, 0x6000,
+	0x19f0, 0x7818, 0x6812, 0x781c, 0x6816, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x6100, 0xa18e, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c,
+	0x864c, 0x00ce, 0x00de, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x0026,
+	0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x7000, 0xa086, 0x0000,
+	0x0904, 0x19b3, 0x7004, 0xac06, 0x1904, 0x19a5, 0x2079, 0x0030,
+	0x7000, 0xa086, 0x0003, 0x0904, 0x19a5, 0x7804, 0xd0fc, 0x15c8,
+	0x20e1, 0x6000, 0x2011, 0x0032, 0x2001, 0x0208, 0x200c, 0x2001,
+	0x0209, 0x2004, 0xa106, 0x1d88, 0x8211, 0x1db0, 0x7804, 0xd0fc,
+	0x1540, 0x080c, 0x1e6e, 0x0026, 0x0056, 0x7803, 0x0004, 0x7804,
+	0xd0ac, 0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003,
+	0x7007, 0x0000, 0x005e, 0x002e, 0x2001, 0x015d, 0x2003, 0x0000,
+	0x080c, 0x5acf, 0x1138, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51,
+	0x006e, 0x0058, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202,
+	0x0020, 0x080c, 0x1b06, 0x0804, 0x1955, 0x0156, 0x20a9, 0x0009,
+	0x2009, 0xb82f, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003,
+	0x1f04, 0x19aa, 0x015e, 0x005e, 0x004e, 0x003e, 0x002e, 0x00ee,
+	0x00fe, 0x0005, 0x700c, 0x7110, 0xa106, 0x0904, 0x1a49, 0x2104,
+	0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182,
+	0xb84a, 0x0210, 0x2009, 0xb82f, 0x7112, 0x700c, 0xa106, 0x1128,
+	0x080c, 0x28eb, 0x2001, 0x0138, 0x2102, 0x8cff, 0x0598, 0x6010,
+	0x2068, 0x2d58, 0x6828, 0xa406, 0x1590, 0x682c, 0xa306, 0x1578,
+	0x7004, 0x2060, 0x6020, 0xc0d4, 0x6022, 0x684c, 0xd0f4, 0x0128,
+	0x6817, 0xffff, 0x6813, 0xffff, 0x00e8, 0x6850, 0xd0f4, 0x1130,
+	0x7803, 0x0004, 0x6810, 0x781a, 0x6814, 0x781e, 0x6824, 0x2050,
+	0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009,
+	0x0011, 0x080c, 0x1a4c, 0x0120, 0x2009, 0x0001, 0x080c, 0x1a4c,
+	0x2d58, 0x0005, 0x080c, 0x1ddd, 0x0904, 0x19ba, 0x0cd0, 0x6020,
+	0xd0f4, 0x11e0, 0xd0d4, 0x01b8, 0x6038, 0xa402, 0x6034, 0xa303,
+	0x0108, 0x1288, 0x643a, 0x6336, 0x6c2a, 0x6b2e, 0x0046, 0x0036,
+	0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, 0xa303, 0x6816,
+	0x003e, 0x004e, 0x0018, 0x080c, 0x9f9a, 0x09e0, 0x601c, 0xa08e,
+	0x0008, 0x0904, 0x19e0, 0xa08e, 0x000a, 0x0904, 0x19e0, 0x2001,
+	0xb574, 0x2004, 0xd0b4, 0x1140, 0x6018, 0x2004, 0xd0bc, 0x1120,
+	0x6817, 0x7fff, 0x6813, 0xffff, 0x080c, 0x2305, 0x1918, 0x0804,
+	0x19e0, 0x7003, 0x0000, 0x0005, 0x8aff, 0x0904, 0x1ae0, 0xa03e,
+	0x2730, 0xc9fc, 0x6850, 0xd0fc, 0x11b8, 0xd0f4, 0x1528, 0x00d6,
+	0x2805, 0xac68, 0x2900, 0x0002, 0x1a9e, 0x1a82, 0x1a82, 0x1a9e,
+	0x1a9e, 0x1a96, 0x1a9e, 0x1a82, 0x1a9e, 0x1a87, 0x1a87, 0x1a9e,
+	0x1a9e, 0x1a9e, 0x1a8e, 0x1a87, 0x7803, 0x0004, 0xc0fc, 0x6852,
+	0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6, 0xd99c, 0x0550, 0x2805,
+	0xac68, 0x6f08, 0x6e0c, 0x0430, 0xc0f4, 0x6852, 0x6b6c, 0x6a70,
+	0x00d6, 0x0468, 0x6b08, 0x6a0c, 0x6d00, 0x6c04, 0x00d0, 0x6b10,
+	0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x00a0, 0x00de, 0x00d6,
+	0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1140, 0x00de, 0x080c,
+	0x22a7, 0x1904, 0x1a4c, 0xa00e, 0x0804, 0x1ae0, 0x00de, 0x080c,
+	0x1515, 0xc9fd, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e,
+	0x7316, 0x721a, 0x751e, 0x7422, 0x7726, 0x762a, 0x7902, 0x7100,
+	0x8108, 0x7102, 0x00de, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201,
+	0x682e, 0x8109, 0x2d08, 0x1500, 0xd9fc, 0x0160, 0xc9fc, 0x080c,
+	0x22a7, 0x01e8, 0x2805, 0xac68, 0x6800, 0xa506, 0x11c0, 0x6804,
+	0xa406, 0x00a8, 0xc9fc, 0x080c, 0x22a7, 0x0188, 0x2805, 0xac68,
+	0x6800, 0xa506, 0x1160, 0x6804, 0xa406, 0x1148, 0x6808, 0xa706,
+	0x1130, 0x680c, 0xa606, 0x0018, 0xc9fc, 0x080c, 0x22a7, 0x2168,
+	0x0005, 0x080c, 0x1515, 0x080c, 0x1f55, 0x7004, 0x2060, 0x00d6,
+	0x6010, 0x2068, 0x7003, 0x0000, 0x080c, 0x1dfe, 0x080c, 0x9c5a,
+	0x0170, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916,
+	0x682b, 0xffff, 0x682f, 0xffff, 0x6850, 0xc0bd, 0x6852, 0x00de,
+	0x080c, 0x992a, 0x0804, 0x1d2b, 0x080c, 0x1515, 0x0126, 0x2091,
+	0x2200, 0x0006, 0x0016, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803,
+	0x0002, 0xa184, 0x0700, 0x1978, 0xa184, 0x0003, 0xa086, 0x0003,
+	0x0d58, 0x7000, 0x0002, 0x1b23, 0x1b29, 0x1c3a, 0x1d06, 0x1d1a,
+	0x1b23, 0x1b23, 0x1b23, 0x7804, 0xd09c, 0x1904, 0x1d2b, 0x080c,
+	0x1515, 0x8001, 0x7002, 0xd1bc, 0x11a0, 0xd19c, 0x1904, 0x1bbe,
+	0xd1dc, 0x1178, 0x8aff, 0x0904, 0x1bbe, 0x2009, 0x0001, 0x080c,
+	0x1a4c, 0x0904, 0x1d2b, 0x2009, 0x0001, 0x080c, 0x1a4c, 0x0804,
+	0x1d2b, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1b9e,
+	0x0026, 0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812,
+	0x781c, 0x6816, 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808,
+	0xd0ec, 0x1128, 0x7803, 0x0009, 0x7003, 0x0004, 0x0010, 0x080c,
+	0x1d2f, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500, 0x6872,
+	0xa213, 0x6b2a, 0x6a2e, 0x00c6, 0x7004, 0x2060, 0x6020, 0xd0f4,
+	0x1110, 0x633a, 0x6236, 0x00ce, 0x003e, 0x002e, 0x6e1e, 0x6f22,
+	0x2500, 0xa405, 0x0128, 0x080c, 0x22bd, 0x6850, 0xc0fd, 0x6852,
+	0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001,
+	0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004, 0x2060, 0x2009,
+	0x0048, 0x080c, 0x864c, 0x7000, 0xa086, 0x0004, 0x0904, 0x1d2b,
+	0x7003, 0x0000, 0x080c, 0x19ba, 0x0804, 0x1d2b, 0x0056, 0x7d0c,
+	0xd5bc, 0x1110, 0x080c, 0xb407, 0x005e, 0x080c, 0x1dfe, 0x00f6,
+	0x7004, 0x2078, 0x080c, 0x5305, 0x0118, 0x7820, 0xc0f5, 0x7822,
+	0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a,
+	0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1d2b, 0x7004, 0x00c6,
+	0x2060, 0x6020, 0x00ce, 0xd0f4, 0x0120, 0x6808, 0x8001, 0x680a,
+	0x04c0, 0x7818, 0x6812, 0x7a1c, 0x6a16, 0xd19c, 0x0160, 0xa205,
+	0x0150, 0x7004, 0xa080, 0x0007, 0x2004, 0xa084, 0xfffd, 0xa086,
+	0x0008, 0x1904, 0x1b41, 0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005,
+	0x1520, 0x7003, 0x0000, 0x6808, 0x8001, 0x680a, 0x01a0, 0x7004,
+	0x2060, 0x601c, 0xa086, 0x000a, 0x11a0, 0x0156, 0x20a9, 0x0009,
+	0x2009, 0xb82f, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003,
+	0x1f04, 0x1bf2, 0x015e, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c,
+	0x864c, 0x080c, 0x19ba, 0x0804, 0x1d2b, 0x7818, 0x6812, 0x781c,
+	0x6816, 0x7814, 0x7908, 0xa18c, 0x0fff, 0xa192, 0x0841, 0x1a04,
+	0x1ae3, 0xa188, 0x0007, 0x8114, 0x8214, 0x8214, 0xa10a, 0x8104,
+	0x8004, 0x8004, 0xa20a, 0x810b, 0x810b, 0x810b, 0x080c, 0x1e99,
+	0x7803, 0x0004, 0x780f, 0xffff, 0x7803, 0x0001, 0x7804, 0xd0fc,
+	0x0de8, 0x7803, 0x0002, 0x7803, 0x0004, 0x780f, 0x00f6, 0x7004,
+	0x7007, 0x0000, 0x2060, 0x2009, 0x0048, 0x080c, 0x864c, 0x080c,
+	0x1eef, 0x0838, 0x8001, 0x7002, 0xd194, 0x01b0, 0x7804, 0xd0fc,
+	0x1904, 0x1cd6, 0xd09c, 0x0138, 0x7804, 0xd0fc, 0x1904, 0x1cd6,
+	0xd09c, 0x1904, 0x1cda, 0x8aff, 0x0904, 0x1d2b, 0x2009, 0x0001,
+	0x080c, 0x1a4c, 0x0804, 0x1d2b, 0xa184, 0x0888, 0x1148, 0x8aff,
+	0x0904, 0x1d2b, 0x2009, 0x0001, 0x080c, 0x1a4c, 0x0804, 0x1d2b,
+	0x7818, 0x6812, 0x7a1c, 0x6a16, 0xa205, 0x0904, 0x1bdb, 0x7803,
+	0x0004, 0x7003, 0x0000, 0xd1bc, 0x1904, 0x1cb8, 0x6834, 0xa084,
+	0x00ff, 0xa086, 0x0029, 0x1118, 0xd19c, 0x1904, 0x1bdb, 0x0026,
+	0x0036, 0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c,
+	0x6816, 0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec,
+	0x1128, 0x7803, 0x0009, 0x7003, 0x0004, 0x0020, 0x0016, 0x080c,
+	0x1d2f, 0x001e, 0x6b28, 0x6a2c, 0x080c, 0x22bd, 0x00d6, 0x2805,
+	0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213,
+	0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0xd194, 0x0904,
+	0x1b63, 0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808,
+	0x8001, 0x680a, 0x6b2a, 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1c01,
+	0x0056, 0x7d0c, 0x080c, 0xb407, 0x005e, 0x080c, 0x1dfe, 0x00f6,
+	0x7004, 0x2078, 0x080c, 0x5305, 0x0118, 0x7820, 0xc0f5, 0x7822,
+	0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a,
+	0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1d2b, 0x7804, 0xd09c,
+	0x0904, 0x1b0e, 0x7c20, 0x7824, 0xa405, 0x1904, 0x1b0e, 0x7818,
+	0x6812, 0x7c1c, 0x6c16, 0xa405, 0x1120, 0x7803, 0x0002, 0x0804,
+	0x1bdb, 0x751c, 0x7420, 0x7724, 0x7628, 0x7014, 0xa528, 0x7018,
+	0xa421, 0xa7b9, 0x0000, 0xa6b1, 0x0000, 0x7830, 0xa506, 0x1150,
+	0x7834, 0xa406, 0x1138, 0x7838, 0xa706, 0x1120, 0x783c, 0xa606,
+	0x0904, 0x1b0e, 0x7803, 0x0002, 0x0804, 0x1c67, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x7004, 0xa00d, 0x0150, 0x6808, 0x8001, 0x680a,
+	0x1130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x864c, 0x080c,
+	0x19ba, 0x0088, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060,
+	0x6010, 0xa005, 0x0da0, 0x2068, 0x6808, 0x8000, 0x680a, 0x6c28,
+	0x6b2c, 0x080c, 0x19d5, 0x001e, 0x000e, 0x012e, 0x0005, 0x700c,
+	0x7110, 0xa106, 0x0904, 0x1dd1, 0x7004, 0x0016, 0x210c, 0xa106,
+	0x001e, 0x0904, 0x1dd1, 0x00d6, 0x00c6, 0x216c, 0x2d00, 0xa005,
+	0x0904, 0x1dcf, 0x681c, 0xa086, 0x0008, 0x0904, 0x1dcf, 0x6820,
+	0xd0d4, 0x1904, 0x1dcf, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x05a8,
+	0x8108, 0x2104, 0x6b2c, 0xa306, 0x1904, 0x1dcf, 0x8108, 0x2104,
+	0x6a28, 0xa206, 0x1904, 0x1dcf, 0x6850, 0xc0fc, 0xc0f5, 0x6852,
+	0x686c, 0x7822, 0x7016, 0x6870, 0x7826, 0x701a, 0x681c, 0x7832,
+	0x701e, 0x6820, 0x7836, 0x7022, 0x6818, 0x2060, 0x6034, 0xd09c,
+	0x0168, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808, 0x783a, 0x7026,
+	0x680c, 0x783e, 0x702a, 0x00de, 0x0804, 0x1dc9, 0xa006, 0x783a,
+	0x783e, 0x7026, 0x702a, 0x0804, 0x1dc9, 0x8108, 0x2104, 0xa005,
+	0x1904, 0x1dcf, 0x6b2c, 0xa306, 0x1904, 0x1dcf, 0x8108, 0x2104,
+	0xa005, 0x15e8, 0x6a28, 0xa206, 0x15d0, 0x6850, 0xc0f5, 0x6852,
+	0x6830, 0x2005, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004, 0xd09c,
+	0x11a0, 0x6008, 0x7822, 0x7016, 0x686e, 0x600c, 0x7826, 0x701a,
+	0x6872, 0x6000, 0x7832, 0x701e, 0x6004, 0x7836, 0x7022, 0xa006,
+	0x783a, 0x783e, 0x7026, 0x702a, 0x00a0, 0x6010, 0x7822, 0x7016,
+	0x686e, 0x6014, 0x7826, 0x701a, 0x6872, 0x6000, 0x7832, 0x701e,
+	0x6004, 0x7836, 0x7022, 0x6008, 0x783a, 0x7026, 0x600c, 0x783e,
+	0x702a, 0x6810, 0x781a, 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce,
+	0x00de, 0x0005, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005,
+	0x1118, 0x8109, 0x1dd8, 0x0005, 0x0005, 0x0ca1, 0x0118, 0x780c,
+	0xd0a4, 0x0120, 0x00d9, 0xa085, 0x0001, 0x0010, 0x080c, 0x1eef,
+	0x0005, 0x0126, 0x2091, 0x2200, 0x7000, 0xa086, 0x0003, 0x1160,
+	0x700c, 0x7110, 0xa106, 0x0140, 0x080c, 0x295c, 0x20e1, 0x9028,
+	0x700f, 0xb82f, 0x7013, 0xb82f, 0x012e, 0x0005, 0x00c6, 0x080c,
+	0x5acf, 0x11b8, 0x2001, 0x0160, 0x2003, 0x0000, 0x2001, 0x0138,
+	0x2003, 0x0000, 0x2011, 0x00c8, 0xe000, 0xe000, 0x8211, 0x1de0,
+	0x04b1, 0x0066, 0x2031, 0x0000, 0x080c, 0x5b51, 0x006e, 0x00ce,
+	0x0005, 0x080c, 0x1e6e, 0x080c, 0x295c, 0x20e1, 0x9028, 0x700c,
+	0x7110, 0xa106, 0x01c0, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010,
+	0x2060, 0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xb84a,
+	0x0210, 0x2009, 0xb82f, 0x7112, 0x700c, 0xa106, 0x1d40, 0x080c,
+	0x28eb, 0x2110, 0x0c20, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001,
+	0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x080c,
+	0x295c, 0x20e1, 0x9028, 0x2001, 0x015d, 0x2003, 0x0000, 0x00e6,
+	0x00c6, 0x0016, 0x2071, 0xb823, 0x700c, 0x7110, 0xa106, 0x0190,
+	0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001,
+	0x600a, 0xa188, 0x0003, 0xa182, 0xb84a, 0x0210, 0x2009, 0xb82f,
+	0x7112, 0x0c50, 0x001e, 0x00ce, 0x00ee, 0x0005, 0x2001, 0x0138,
+	0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000,
+	0x080c, 0x5acf, 0x1148, 0x2021, 0x0002, 0x1d04, 0x1e7d, 0x2091,
+	0x6000, 0x8421, 0x1dd0, 0x0005, 0x2021, 0xb015, 0x2001, 0x0141,
+	0x201c, 0xd3dc, 0x1168, 0x2001, 0x0109, 0x201c, 0xa39c, 0x0048,
+	0x1138, 0x2001, 0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70,
+	0x0005, 0x00e6, 0x2071, 0x0200, 0x7808, 0xa084, 0xf000, 0xa10d,
+	0x0869, 0x2001, 0x0105, 0x2004, 0xa084, 0x0003, 0x1130, 0x2001,
+	0xb84a, 0x2004, 0xa086, 0x0000, 0x0548, 0xa026, 0x2019, 0xf000,
+	0x8319, 0x1148, 0x2001, 0x012b, 0x2003, 0x95f5, 0x2001, 0x0129,
+	0x2003, 0x95f5, 0x00d8, 0x2001, 0x0105, 0x2004, 0xa084, 0x0003,
+	0x1130, 0x2001, 0xb84a, 0x2004, 0xa086, 0x0000, 0x0178, 0x2001,
+	0x0132, 0x2004, 0xa436, 0x0110, 0x2020, 0x0c00, 0x2001, 0x0021,
+	0x2004, 0xd0fc, 0x09e8, 0x080c, 0x214a, 0x08c0, 0x20e1, 0x7000,
+	0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f,
+	0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001,
+	0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ee, 0x0005, 0x0026,
+	0x2001, 0x015d, 0x2003, 0x0000, 0x7908, 0xa18c, 0x0fff, 0xa182,
+	0x0ffd, 0x0210, 0x2009, 0x0000, 0xa190, 0x0007, 0xa294, 0x1ff8,
+	0x8214, 0x8214, 0x8214, 0x2001, 0x020a, 0x82ff, 0x0140, 0x20e1,
+	0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x8211, 0x1dd0, 0x20e1,
+	0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0x20e1, 0x6000, 0x2001,
+	0x0208, 0x200c, 0x2001, 0x0209, 0x2004, 0xa106, 0x0158, 0x080c,
+	0x1dd2, 0x0130, 0x7908, 0xd1ec, 0x1128, 0x790c, 0xd1a4, 0x0960,
+	0x080c, 0x1dfe, 0xa006, 0x002e, 0x0005, 0x00f6, 0x00e6, 0x0016,
+	0x0026, 0x2071, 0xb823, 0x2079, 0x0030, 0x2011, 0x0050, 0x7000,
+	0xa086, 0x0000, 0x01a8, 0x8211, 0x0188, 0x2001, 0x0005, 0x2004,
+	0xd08c, 0x0dc8, 0x7904, 0xa18c, 0x0780, 0x0016, 0x080c, 0x1b06,
+	0x001e, 0x81ff, 0x1118, 0x2011, 0x0050, 0x0c48, 0xa085, 0x0001,
+	0x002e, 0x001e, 0x00ee, 0x00fe, 0x0005, 0x7803, 0x0004, 0x2009,
+	0x0064, 0x7804, 0xd0ac, 0x0904, 0x1fa1, 0x8109, 0x1dd0, 0x2009,
+	0x0100, 0x210c, 0xa18a, 0x0003, 0x0a0c, 0x1515, 0x080c, 0x2251,
+	0x00e6, 0x00f6, 0x2071, 0xb812, 0x2079, 0x0010, 0x7004, 0xa086,
+	0x0000, 0x0538, 0x7800, 0x0006, 0x7820, 0x0006, 0x7830, 0x0006,
+	0x7834, 0x0006, 0x7838, 0x0006, 0x783c, 0x0006, 0x7803, 0x0004,
+	0xe000, 0xe000, 0x2079, 0x0030, 0x7804, 0xd0ac, 0x190c, 0x1515,
+	0x2079, 0x0010, 0x000e, 0x783e, 0x000e, 0x783a, 0x000e, 0x7836,
+	0x000e, 0x7832, 0x000e, 0x7822, 0x000e, 0x7802, 0x00fe, 0x00ee,
+	0x0030, 0x00fe, 0x00ee, 0x7804, 0xd0ac, 0x190c, 0x1515, 0x080c,
+	0x7230, 0x0005, 0x00e6, 0x2071, 0xb84a, 0x7003, 0x0000, 0x00ee,
+	0x0005, 0x00d6, 0xa280, 0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904,
+	0x201f, 0x6934, 0xa184, 0x0007, 0x0002, 0x1fbd, 0x200a, 0x1fbd,
+	0x1fbd, 0x1fbd, 0x1ff1, 0x1fd0, 0x1fbf, 0x080c, 0x1515, 0x684c,
+	0xd0b4, 0x0904, 0x2107, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a,
+	0x6812, 0x687c, 0x680a, 0x6880, 0x680e, 0x6958, 0x0804, 0x2012,
+	0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1d38, 0x684c, 0xd0b4,
+	0x0904, 0x2107, 0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812,
+	0x687c, 0x680a, 0x6880, 0x680e, 0x6804, 0x681a, 0xa080, 0x000d,
+	0x2004, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0x6958,
+	0x0450, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4,
+	0x0904, 0x2107, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084,
+	0x000f, 0xa080, 0x22e5, 0x2005, 0x6832, 0x6958, 0xa006, 0x682e,
+	0x682a, 0x0088, 0x684c, 0xd0b4, 0x0904, 0x1ae1, 0x6958, 0xa006,
+	0x682e, 0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080,
+	0x22e5, 0x2005, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de,
+	0x0005, 0x00f6, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x190c, 0x214a,
+	0x00e6, 0x00d6, 0x2071, 0xb84a, 0x7000, 0xa005, 0x1904, 0x2087,
+	0x00c6, 0x7206, 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803,
+	0x0004, 0x6818, 0x00d6, 0x2068, 0x686c, 0x7812, 0x6890, 0x00f6,
+	0x20e1, 0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004,
+	0x78d6, 0x00fe, 0x00de, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060,
+	0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0x791a, 0x7116,
+	0x680c, 0x781e, 0x701a, 0xa006, 0x700e, 0x7012, 0x7004, 0x692c,
+	0x6814, 0xa106, 0x1120, 0x6928, 0x6810, 0xa106, 0x0158, 0x0036,
+	0x0046, 0x6b14, 0x6c10, 0x080c, 0x2305, 0x004e, 0x003e, 0x0110,
+	0x00ce, 0x00a8, 0x8aff, 0x1120, 0x00ce, 0xa085, 0x0001, 0x0078,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001, 0x0059,
+	0x0118, 0x2009, 0x0001, 0x0039, 0x012e, 0x00ce, 0xa006, 0x00de,
+	0x00ee, 0x00fe, 0x0005, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036,
+	0x0026, 0x8aff, 0x0904, 0x2100, 0x700c, 0x7214, 0xa23a, 0x7010,
+	0x7218, 0xa203, 0x0a04, 0x20ff, 0xa705, 0x0904, 0x20ff, 0xa03e,
+	0x2730, 0x6850, 0xd0fc, 0x11a8, 0x00d6, 0x2805, 0xac68, 0x2900,
+	0x0002, 0x20e2, 0x20c7, 0x20c7, 0x20e2, 0x20e2, 0x20db, 0x20e2,
+	0x20c7, 0x20e2, 0x20cc, 0x20cc, 0x20e2, 0x20e2, 0x20e2, 0x20d3,
+	0x20cc, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c,
+	0x0528, 0x00d6, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x00f0, 0x6b08,
+	0x6a0c, 0x6d00, 0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04,
+	0x6f08, 0x6e0c, 0x0090, 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff,
+	0xa086, 0x001e, 0x1138, 0x00de, 0x080c, 0x22a7, 0x1904, 0x2091,
+	0xa00e, 0x00f0, 0x00de, 0x080c, 0x1515, 0x00de, 0x7b22, 0x7a26,
+	0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002,
+	0x6828, 0xa300, 0x682a, 0x682c, 0xa201, 0x682e, 0x700c, 0xa300,
+	0x700e, 0x7010, 0xa201, 0x7012, 0x080c, 0x22a7, 0x0008, 0xa006,
+	0x002e, 0x003e, 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c,
+	0x1515, 0x0026, 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040,
+	0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x00d6, 0x6010,
+	0x2068, 0x080c, 0x9c5a, 0x0118, 0x6850, 0xc0bd, 0x6852, 0x601c,
+	0xa086, 0x0006, 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001, 0x00fa,
+	0x8001, 0x1df0, 0x60c8, 0xa206, 0x1dc0, 0x60c4, 0x686a, 0x60c8,
+	0x6866, 0x7004, 0x2060, 0x00de, 0x00c6, 0x080c, 0x992a, 0x00ce,
+	0x2001, 0xb7ef, 0x2004, 0xac06, 0x1150, 0x20e1, 0x9040, 0x080c,
+	0x825d, 0x2011, 0x0000, 0x080c, 0x807f, 0x080c, 0x7230, 0x002e,
+	0x0804, 0x2204, 0x0126, 0x2091, 0x2400, 0x0006, 0x0016, 0x00f6,
+	0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071, 0xb84a, 0x2b68,
+	0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x1904,
+	0x2109, 0x7000, 0x0002, 0x2204, 0x2167, 0x21d7, 0x2202, 0x8001,
+	0x7002, 0xd19c, 0x1170, 0x8aff, 0x05d0, 0x2009, 0x0001, 0x080c,
+	0x208b, 0x0904, 0x2204, 0x2009, 0x0001, 0x080c, 0x208b, 0x0804,
+	0x2204, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc, 0x6852,
+	0x8aff, 0x11d8, 0x684c, 0xc0f5, 0x684e, 0x00b8, 0x0026, 0x0036,
+	0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872, 0xa213,
+	0x7830, 0x681e, 0x7834, 0x6822, 0x6b2a, 0x6a2e, 0x003e, 0x002e,
+	0x080c, 0x22bd, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00,
+	0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0804, 0x2204, 0x00f6,
+	0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100, 0x7a14,
+	0xa284, 0x0184, 0xa085, 0x0012, 0x7816, 0x0036, 0x2019, 0x1000,
+	0x8319, 0x090c, 0x1515, 0x7820, 0xd0bc, 0x1dd0, 0x003e, 0x79c8,
+	0x000e, 0xa102, 0x001e, 0x0006, 0x0016, 0x79c4, 0x000e, 0xa103,
+	0x78c6, 0x000e, 0x78ca, 0xa284, 0x0184, 0xa085, 0x0012, 0x7816,
+	0x002e, 0x00fe, 0x7803, 0x0008, 0x7003, 0x0000, 0x0468, 0x8001,
+	0x7002, 0xd194, 0x0168, 0x7804, 0xd0fc, 0x1904, 0x215a, 0xd19c,
+	0x11f8, 0x8aff, 0x0508, 0x2009, 0x0001, 0x080c, 0x208b, 0x00e0,
+	0x0026, 0x0036, 0x6b28, 0x6a2c, 0x080c, 0x22bd, 0x00d6, 0x2805,
+	0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213,
+	0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0x0804, 0x218a,
+	0x0804, 0x2186, 0x080c, 0x1515, 0x00ce, 0x00de, 0x00ee, 0x00fe,
+	0x001e, 0x000e, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, 0xb84a,
+	0x7000, 0xa086, 0x0000, 0x05d0, 0x2079, 0x0020, 0x0016, 0x2009,
+	0x0207, 0x210c, 0xd194, 0x0198, 0x2009, 0x020c, 0x210c, 0xa184,
+	0x0003, 0x0168, 0x080c, 0xb450, 0x2001, 0x0133, 0x2004, 0xa005,
+	0x090c, 0x1515, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, 0x2009,
+	0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x1110, 0x20e1,
+	0x9040, 0x7804, 0xd0fc, 0x09d8, 0x080c, 0x214a, 0x7000, 0xa086,
+	0x0000, 0x19a8, 0x001e, 0x7803, 0x0004, 0x7804, 0xd0ac, 0x1de8,
+	0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x00ee, 0x00fe,
+	0x0005, 0x0026, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb84a,
+	0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0540, 0x7004, 0x2060,
+	0x6010, 0x2068, 0x080c, 0x9c5a, 0x0158, 0x6850, 0xc0b5, 0x6852,
+	0x680c, 0x7a1c, 0xa206, 0x1120, 0x6808, 0x7a18, 0xa206, 0x01e0,
+	0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x7004, 0x2060, 0x080c, 0x992a, 0x20e1, 0x9040,
+	0x080c, 0x825d, 0x2011, 0x0000, 0x080c, 0x807f, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x002e, 0x0005, 0x6810, 0x6a14, 0xa205, 0x1d00,
+	0x684c, 0xc0dc, 0x684e, 0x2c10, 0x080c, 0x1fa9, 0x2001, 0x0105,
+	0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003, 0x0000,
+	0x2069, 0xb7e0, 0x6833, 0x0000, 0x683f, 0x0000, 0x08f8, 0x8840,
+	0x2805, 0xa005, 0x1170, 0x6004, 0xa005, 0x0168, 0x681a, 0x2060,
+	0x6034, 0xa084, 0x000f, 0xa080, 0x22e5, 0x2045, 0x88ff, 0x090c,
+	0x1515, 0x8a51, 0x0005, 0x2050, 0x0005, 0x8a50, 0x8841, 0x2805,
+	0xa005, 0x1190, 0x2c00, 0xad06, 0x0120, 0x6000, 0xa005, 0x1108,
+	0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x22f5,
+	0x2045, 0x88ff, 0x090c, 0x1515, 0x0005, 0x0000, 0x0011, 0x0015,
+	0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015,
+	0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x22da, 0x22d6,
+	0x0000, 0x0000, 0x22e4, 0x0000, 0x22da, 0x0000, 0x22e1, 0x22de,
+	0x0000, 0x0000, 0x0000, 0x22e4, 0x22e1, 0x0000, 0x22dc, 0x22dc,
+	0x0000, 0x0000, 0x22e4, 0x0000, 0x22dc, 0x0000, 0x22e2, 0x22e2,
+	0x0000, 0x0000, 0x0000, 0x22e4, 0x22e2, 0x00a6, 0x0096, 0x0086,
+	0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0904, 0x2396, 0x2d60, 0x6034,
+	0xa0cc, 0x000f, 0xa9c0, 0x22e5, 0xa986, 0x0007, 0x0130, 0xa986,
+	0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422, 0x6060,
+	0xa31b, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2396, 0x6004,
+	0xa065, 0x0904, 0x2396, 0x0c18, 0x2805, 0xa005, 0x01a8, 0xac68,
+	0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020, 0x6810,
+	0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150, 0x8a51,
+	0x0904, 0x2396, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904, 0x2396,
+	0x0830, 0x8a51, 0x0904, 0x2396, 0x8840, 0x2805, 0xa005, 0x1158,
+	0x6004, 0xa065, 0x0904, 0x2396, 0x6034, 0xa0cc, 0x000f, 0xa9c0,
+	0x22e5, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0458,
+	0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68, 0x6c6e,
+	0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122, 0x690c,
+	0x2300, 0xa11b, 0x0a0c, 0x1515, 0x6800, 0xa420, 0x6804, 0xa319,
+	0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b, 0x0a0c,
+	0x1515, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e, 0x6b22,
+	0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832, 0x2a00,
+	0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e, 0x009e,
+	0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, 0xa084,
+	0x0007, 0x0002, 0x23aa, 0x23ab, 0x23ae, 0x23b1, 0x23b6, 0x23b9,
+	0x23be, 0x23c3, 0x0005, 0x080c, 0x214a, 0x0005, 0x080c, 0x1b06,
+	0x0005, 0x080c, 0x1b06, 0x080c, 0x214a, 0x0005, 0x080c, 0x171b,
+	0x0005, 0x080c, 0x214a, 0x080c, 0x171b, 0x0005, 0x080c, 0x1b06,
+	0x080c, 0x171b, 0x0005, 0x080c, 0x1b06, 0x080c, 0x214a, 0x080c,
+	0x171b, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071,
+	0xbb80, 0x2069, 0xb500, 0x080c, 0x24c0, 0x080c, 0x24b0, 0x2009,
+	0x0004, 0x7912, 0x7817, 0x0004, 0x080c, 0x27f8, 0x781b, 0x0002,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a9, 0x0080, 0x782f, 0x0000,
+	0x1f04, 0x23e6, 0x20e1, 0x9080, 0x783b, 0x001f, 0x20e1, 0x8700,
+	0x012e, 0x0005, 0x0126, 0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c,
+	0x24ad, 0xa084, 0x0007, 0x0002, 0x2416, 0x2404, 0x2407, 0x240a,
+	0x240f, 0x2411, 0x2413, 0x2415, 0x080c, 0x63c4, 0x0078, 0x080c,
+	0x6403, 0x0060, 0x080c, 0x63c4, 0x080c, 0x6403, 0x0038, 0x0041,
+	0x0028, 0x0031, 0x0018, 0x0021, 0x0008, 0x0011, 0x012e, 0x0005,
+	0x0006, 0x0016, 0x0026, 0x080c, 0xb450, 0x7930, 0xa184, 0x0003,
+	0x01b0, 0x2001, 0xb7ef, 0x2004, 0xa005, 0x0170, 0x2001, 0x0133,
+	0x2004, 0xa005, 0x090c, 0x1515, 0x00c6, 0x2001, 0xb7ef, 0x2064,
+	0x080c, 0x992a, 0x00ce, 0x04b8, 0x20e1, 0x9040, 0x04a0, 0xa184,
+	0x0030, 0x01e0, 0x6a00, 0xa286, 0x0003, 0x1108, 0x00a0, 0x080c,
+	0x5acf, 0x1178, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500,
+	0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07,
+	0x0010, 0x080c, 0x4b1f, 0x080c, 0x24b0, 0x00a8, 0xa184, 0x00c0,
+	0x0168, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x080c,
+	0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x0028, 0xa184, 0x0300,
+	0x0110, 0x20e1, 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x0016, 0x00e6, 0x00f6, 0x2071, 0xb500, 0x7128, 0x2001, 0xb791,
+	0x2102, 0x2001, 0xb799, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009,
+	0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0,
+	0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349,
+	0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009,
+	0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010,
+	0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c,
+	0x27f8, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x1515,
+	0x00e6, 0x0026, 0x2071, 0x0200, 0x20e1, 0x1000, 0x7220, 0x7028,
+	0x7020, 0xa206, 0x0de0, 0x20e1, 0x9010, 0x002e, 0x00ee, 0x0005,
+	0x20e1, 0xa000, 0x7837, 0x0001, 0x782f, 0x0000, 0x782f, 0x0000,
+	0x782f, 0x0000, 0x782f, 0x0000, 0x7837, 0x0005, 0x20a9, 0x0210,
+	0x7830, 0xd0bc, 0x1110, 0x1f04, 0x24d0, 0x7837, 0x0001, 0x7837,
+	0x0000, 0xe000, 0xe000, 0x20e1, 0xa000, 0x0005, 0x0126, 0x2091,
+	0x2800, 0x2061, 0x0100, 0x2071, 0xb500, 0x6024, 0x6026, 0x6053,
+	0x0030, 0x080c, 0x2837, 0x6050, 0xa084, 0xfe7f, 0x6052, 0x2009,
+	0x00ef, 0x6132, 0x6136, 0x080c, 0x2847, 0x60e7, 0x0000, 0x61ea,
+	0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080,
+	0x602f, 0x0000, 0x6007, 0x0e9f, 0x601b, 0x001e, 0x600f, 0x00ff,
+	0x2001, 0xb78d, 0x2003, 0x00ff, 0x602b, 0x002f, 0x012e, 0x0005,
+	0x2001, 0xb532, 0x2003, 0x0000, 0x2001, 0xb531, 0x2003, 0x0001,
+	0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x6124,
+	0xa184, 0x1e2c, 0x1118, 0xa184, 0x0007, 0x002a, 0xa195, 0x0004,
+	0xa284, 0x0007, 0x0002, 0x254d, 0x2533, 0x2536, 0x2539, 0x253e,
+	0x2540, 0x2544, 0x2548, 0x080c, 0x6b74, 0x00b8, 0x080c, 0x6c4f,
+	0x00a0, 0x080c, 0x6c4f, 0x080c, 0x6b74, 0x0078, 0x0099, 0x0068,
+	0x080c, 0x6b74, 0x0079, 0x0048, 0x080c, 0x6c4f, 0x0059, 0x0028,
+	0x080c, 0x6c4f, 0x080c, 0x6b74, 0x0029, 0x002e, 0x001e, 0x000e,
+	0x012e, 0x0005, 0x6124, 0x6028, 0xd09c, 0x0118, 0xd19c, 0x1904,
+	0x2766, 0x080c, 0x5acf, 0x0578, 0x7000, 0xa086, 0x0003, 0x0198,
+	0x6024, 0xa084, 0x1800, 0x0178, 0x080c, 0x5af5, 0x0118, 0x080c,
+	0x5ae1, 0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0xb79e,
+	0x2003, 0xaaaa, 0x0458, 0x080c, 0x5af5, 0x15d0, 0x6024, 0xa084,
+	0x1800, 0x1108, 0x04a8, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001,
+	0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x080c,
+	0x5a07, 0x0804, 0x2766, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170,
+	0xd0e4, 0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x708c, 0xa086,
+	0x0028, 0x1110, 0x080c, 0x5c5e, 0x0804, 0x2766, 0x2001, 0xb79f,
+	0x2003, 0x0000, 0x0048, 0x2001, 0xb79f, 0x2003, 0x0002, 0x0020,
+	0x080c, 0x5bd1, 0x0804, 0x2766, 0x080c, 0x5d03, 0x0804, 0x2766,
+	0xd1ac, 0x0904, 0x26ae, 0x080c, 0x5acf, 0x11d8, 0x6027, 0x0020,
+	0x0006, 0x0026, 0x0036, 0x080c, 0x5aeb, 0x1170, 0x2001, 0xb79f,
+	0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x080c, 0x5a07,
+	0x003e, 0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c,
+	0x5aa6, 0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, 0xf0f0, 0x1138,
+	0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ce,
+	0xa48c, 0xff00, 0x7034, 0xd084, 0x0178, 0xa186, 0xf800, 0x1160,
+	0x703c, 0xd084, 0x1148, 0xc085, 0x703e, 0x0036, 0x2418, 0x2011,
+	0x8016, 0x080c, 0x3ecc, 0x003e, 0xa196, 0xff00, 0x05b8, 0x7054,
+	0xa084, 0x00ff, 0x810f, 0xa116, 0x0588, 0x7130, 0xd184, 0x1570,
+	0x2011, 0xb553, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011,
+	0xb553, 0x2214, 0xd2ac, 0x1510, 0x6240, 0xa294, 0x0010, 0x0130,
+	0x6248, 0xa294, 0xff00, 0xa296, 0xff00, 0x01c0, 0x7030, 0xd08c,
+	0x0904, 0x267b, 0x7034, 0xd08c, 0x1140, 0x2001, 0xb50c, 0x200c,
+	0xd1ac, 0x1904, 0x267b, 0xc1ad, 0x2102, 0x0036, 0x73cc, 0x2011,
+	0x8013, 0x080c, 0x3ecc, 0x003e, 0x0804, 0x267b, 0x7034, 0xd08c,
+	0x1140, 0x2001, 0xb50c, 0x200c, 0xd1ac, 0x1904, 0x267b, 0xc1ad,
+	0x2102, 0x0036, 0x73cc, 0x2011, 0x8013, 0x080c, 0x3ecc, 0x003e,
+	0x7130, 0xc185, 0x7132, 0x2011, 0xb553, 0x220c, 0xd1a4, 0x01d0,
+	0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x6b1a, 0x2019,
+	0x000e, 0x080c, 0xb065, 0xa484, 0x00ff, 0xa080, 0x2dc4, 0x200d,
+	0xa18c, 0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c,
+	0xb0e8, 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019,
+	0x0004, 0x080c, 0x2c6f, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f,
+	0x2009, 0x0000, 0x080c, 0x4fa9, 0x1110, 0x080c, 0x4c0b, 0x8108,
+	0x1f04, 0x2672, 0x015e, 0x00ce, 0x004e, 0x2011, 0x0003, 0x080c,
+	0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036,
+	0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x60e3, 0x0000, 0x001e,
+	0x2001, 0xb500, 0x2014, 0xa296, 0x0004, 0x1128, 0xd19c, 0x11b0,
+	0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xb523, 0x2003,
+	0x0000, 0x6027, 0x0020, 0x080c, 0x5af5, 0x1140, 0x0016, 0x2009,
+	0x07d0, 0x2011, 0x59e4, 0x080c, 0x6a22, 0x001e, 0xd194, 0x0904,
+	0x2766, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2717, 0x080c, 0x6a10,
+	0x080c, 0x7d7a, 0x6027, 0x0004, 0x00f6, 0x2019, 0xb7e9, 0x2304,
+	0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6, 0x00c6,
+	0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e, 0x7808,
+	0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0, 0x6043,
+	0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a, 0x080c,
+	0x7090, 0x080c, 0x7173, 0x7810, 0x2070, 0x7037, 0x0103, 0x2f60,
+	0x080c, 0x861d, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, 0x0005,
+	0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0120,
+	0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061, 0xb7e0,
+	0x6028, 0xa09a, 0x00c8, 0x1238, 0x8000, 0x602a, 0x00ce, 0x080c,
+	0x7d6d, 0x0804, 0x2765, 0x2019, 0xb7e9, 0x2304, 0xa065, 0x0120,
+	0x2009, 0x0027, 0x080c, 0x864c, 0x00ce, 0x0804, 0x2765, 0xd2bc,
+	0x0904, 0x2765, 0x080c, 0x6a1d, 0x6014, 0xa084, 0x0184, 0xa085,
+	0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804,
+	0xa084, 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de,
+	0x00c6, 0x2061, 0xb7e0, 0x6044, 0xa09a, 0x00c8, 0x12f0, 0x8000,
+	0x6046, 0x603c, 0x00ce, 0xa005, 0x0540, 0x2009, 0x07d0, 0x080c,
+	0x6a15, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x1138, 0x6114,
+	0xa18c, 0x0184, 0xa18d, 0x0012, 0x6116, 0x00b8, 0x6114, 0xa18c,
+	0x0184, 0xa18d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019, 0x0001,
+	0x080c, 0x7fe4, 0x003e, 0x2019, 0xb7ef, 0x2304, 0xa065, 0x0120,
+	0x2009, 0x004f, 0x080c, 0x864c, 0x00ce, 0x001e, 0xd19c, 0x0904,
+	0x27bf, 0x7034, 0xd0ac, 0x1560, 0x0016, 0x0156, 0x6027, 0x0008,
+	0x602f, 0x0020, 0x20a9, 0x0006, 0x1d04, 0x2774, 0x2091, 0x6000,
+	0x1f04, 0x2774, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400, 0x6052,
+	0x20a9, 0x0366, 0x1d04, 0x2782, 0x2091, 0x6000, 0x6020, 0xd09c,
+	0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0480, 0x080c,
+	0x2907, 0x1f04, 0x2782, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008,
+	0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, 0x8075,
+	0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019,
+	0x0000, 0x080c, 0x7fe4, 0x003e, 0x60e3, 0x0000, 0x080c, 0xb42f,
+	0x080c, 0xb44a, 0xa085, 0x0001, 0x080c, 0x5b13, 0x2001, 0xb500,
+	0x2003, 0x0004, 0x6027, 0x0008, 0x080c, 0x12dd, 0x001e, 0xa18c,
+	0xffd0, 0x6126, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6,
+	0x0126, 0x2091, 0x8000, 0x2071, 0xb500, 0x71c4, 0x70c6, 0xa116,
+	0x0500, 0x81ff, 0x0128, 0x2011, 0x8011, 0x080c, 0x3ecc, 0x00c8,
+	0x2011, 0x8012, 0x080c, 0x3ecc, 0x2001, 0xb572, 0x2004, 0xd0fc,
+	0x1180, 0x0036, 0x00c6, 0x080c, 0x2892, 0x080c, 0x7f35, 0x2061,
+	0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2c6f, 0x00ce,
+	0x003e, 0x012e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x00c6, 0x00f6, 0x0006, 0x0026, 0x2061, 0x0100, 0xa190, 0x280b,
+	0x2205, 0x60f2, 0x2011, 0x2818, 0x2205, 0x60ee, 0x002e, 0x000e,
+	0x00fe, 0x00ce, 0x0005, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420,
+	0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8,
+	0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff,
+	0x2130, 0xa094, 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c, 0x66b1,
+	0x0038, 0xa080, 0x2dc4, 0x200d, 0xa18c, 0xff00, 0x810f, 0xa006,
+	0x0005, 0xa080, 0x2dc4, 0x200d, 0xa18c, 0x00ff, 0x0005, 0x00d6,
+	0x2069, 0x0140, 0x2001, 0xb515, 0x2003, 0x00ef, 0x20a9, 0x0010,
+	0xa006, 0x6852, 0x6856, 0x1f04, 0x2842, 0x00de, 0x0005, 0x0006,
+	0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0xb515, 0x2102, 0x8114,
+	0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0xa006,
+	0x82ff, 0x1128, 0xa184, 0x000f, 0xa080, 0xb45e, 0x2005, 0x6856,
+	0x8211, 0x1f04, 0x2857, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6,
+	0x2061, 0xb500, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032,
+	0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069,
+	0x0140, 0x6980, 0xa116, 0x0180, 0xa112, 0x1230, 0x8212, 0x8210,
+	0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e,
+	0x1f04, 0x2887, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de,
+	0x015e, 0x0005, 0x2001, 0xb553, 0x2004, 0xd0c4, 0x0150, 0xd0a4,
+	0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0xb0e8,
+	0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, 0x78c4,
+	0xd0dc, 0x0548, 0xa084, 0x0700, 0xa08e, 0x0300, 0x1520, 0x2011,
+	0x0000, 0x2009, 0x0002, 0x2300, 0xa080, 0x0020, 0x2018, 0x2300,
+	0x080c, 0x6b40, 0x2011, 0x0030, 0x2200, 0x8007, 0xa085, 0x004c,
+	0x78c2, 0x2009, 0x0204, 0x210c, 0x2200, 0xa100, 0x2009, 0x0138,
+	0x200a, 0x080c, 0x5acf, 0x1118, 0x2009, 0xb78f, 0x200a, 0x002e,
+	0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, 0x2091,
+	0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c, 0x8000,
+	0x2014, 0xa184, 0x0003, 0x0110, 0x0804, 0x1b04, 0x002e, 0x001e,
+	0x000e, 0x012e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, 0xa082,
+	0x0005, 0x000e, 0x0268, 0x2001, 0x0170, 0x200c, 0xa18c, 0x00ff,
+	0xa18e, 0x004c, 0x1128, 0x200c, 0xa18c, 0xff00, 0x810f, 0x0010,
+	0x2009, 0x0000, 0x2001, 0x0204, 0x2004, 0xa108, 0x0005, 0x0006,
+	0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c,
+	0x1110, 0x1f04, 0x290e, 0x00fe, 0x015e, 0x000e, 0x0005, 0x0016,
+	0x00c6, 0x0006, 0x2061, 0x0100, 0x6030, 0x0006, 0x6048, 0x0006,
+	0x60e4, 0x0006, 0x60e8, 0x0006, 0x6050, 0x0006, 0x60f0, 0x0006,
+	0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006,
+	0x60e0, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0xe000, 0xe000,
+	0xe000, 0xe000, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x60e2,
+	0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee,
+	0x000e, 0x60f2, 0x000e, 0x6052, 0x000e, 0x60ea, 0x000e, 0x60e6,
+	0x000e, 0x604a, 0x000e, 0x6032, 0x6036, 0x2008, 0x080c, 0x2847,
+	0x000e, 0x00ce, 0x001e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc,
+	0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xe000, 0xe000,
+	0x200a, 0x0005, 0x29fa, 0x29fe, 0x2a02, 0x2a08, 0x2a0e, 0x2a14,
+	0x2a1a, 0x2a22, 0x2a2a, 0x2a30, 0x2a36, 0x2a3e, 0x2a46, 0x2a4e,
+	0x2a56, 0x2a60, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2a6c, 0x2a6c, 0x2a72, 0x2a72, 0x2a79, 0x2a79,
+	0x2a80, 0x2a80, 0x2a89, 0x2a89, 0x2a90, 0x2a90, 0x2a99, 0x2a99,
+	0x2aa2, 0x2aa2, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad, 0x2aad,
+	0x2aad, 0x2aad, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a, 0x2a6a,
+	0x2a6a, 0x2a6a, 0x0106, 0x0006, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x0804, 0x2ab5,
+	0x0106, 0x0006, 0x080c, 0x2519, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x239c, 0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x239c,
+	0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c,
+	0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c,
+	0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x23f2, 0x0804, 0x2ab5,
+	0x0106, 0x0006, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x2519, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x2519, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5, 0x0106, 0x0006,
+	0x080c, 0x2519, 0x080c, 0x239c, 0x080c, 0x23f2, 0x0804, 0x2ab5,
+	0x0106, 0x0006, 0x080c, 0x2519, 0x080c, 0x239c, 0x080c, 0x23f2,
+	0x0804, 0x2ab5, 0xe000, 0x0cf0, 0x0106, 0x0006, 0x080c, 0x28d6,
+	0x0804, 0x2ab5, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519,
+	0x04e0, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x239c, 0x04a8,
+	0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, 0x080c, 0x239c,
+	0x0460, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x23f2, 0x0428,
+	0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519, 0x080c, 0x23f2,
+	0x00e0, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x239c, 0x080c,
+	0x23f2, 0x0098, 0x0106, 0x0006, 0x080c, 0x28d6, 0x080c, 0x2519,
+	0x080c, 0x239c, 0x080c, 0x23f2, 0x0040, 0x20d1, 0x0000, 0x20d1,
+	0x0001, 0x20d1, 0x0000, 0x080c, 0x1515, 0x000e, 0x010e, 0x000d,
+	0x00c6, 0x0026, 0x0046, 0x2021, 0x0000, 0x080c, 0x5309, 0x1904,
+	0x2b95, 0x72d4, 0x2001, 0xb79e, 0x2004, 0xa005, 0x1110, 0xd29c,
+	0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x2b95, 0x080c, 0x2b99,
+	0x0804, 0x2b95, 0xd2cc, 0x1904, 0x2b95, 0x080c, 0x5acf, 0x1120,
+	0x709f, 0xffff, 0x0804, 0x2b95, 0xd294, 0x0120, 0x709f, 0xffff,
+	0x0804, 0x2b95, 0x2001, 0xb515, 0x203c, 0x7288, 0xd284, 0x0904,
+	0x2b37, 0xd28c, 0x1904, 0x2b37, 0x0036, 0x739c, 0xa38e, 0xffff,
+	0x1110, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xbcc0, 0x2c04, 0xa38c,
+	0x0001, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, 0x00ff,
+	0xa70e, 0x0560, 0xa08e, 0x0000, 0x0548, 0xa08e, 0x00ff, 0x1150,
+	0x7230, 0xd284, 0x1538, 0x7288, 0xc28d, 0x728a, 0x709f, 0xffff,
+	0x003e, 0x0428, 0x2009, 0x0000, 0x080c, 0x281d, 0x080c, 0x4f4d,
+	0x11b8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1150, 0x7030,
+	0xd08c, 0x0118, 0x6000, 0xd0bc, 0x0120, 0x080c, 0x2bac, 0x0140,
+	0x0028, 0x080c, 0x2cdd, 0x080c, 0x2bda, 0x0110, 0x8318, 0x0818,
+	0x739e, 0x0010, 0x709f, 0xffff, 0x003e, 0x0804, 0x2b95, 0xa780,
+	0x2dc4, 0x203d, 0xa7bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x709c,
+	0xa096, 0xffff, 0x1120, 0x2009, 0x0000, 0x28a8, 0x0050, 0xa812,
+	0x0220, 0x2008, 0xa802, 0x20a8, 0x0020, 0x709f, 0xffff, 0x0804,
+	0x2b95, 0x2700, 0x0156, 0x0016, 0xa106, 0x05a0, 0xc484, 0x080c,
+	0x4fa9, 0x0120, 0x080c, 0x4f4d, 0x15a8, 0x0008, 0xc485, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x1130, 0x7030, 0xd08c, 0x01e8,
+	0x6000, 0xd0bc, 0x11d0, 0x7288, 0xd28c, 0x0188, 0x6004, 0xa084,
+	0x00ff, 0xa082, 0x0006, 0x02b0, 0xd484, 0x1118, 0x080c, 0x4f6c,
+	0x0028, 0x080c, 0x2d6a, 0x0170, 0x080c, 0x2d97, 0x0058, 0x080c,
+	0x2cdd, 0x080c, 0x2bda, 0x0170, 0x0028, 0x080c, 0x2d6a, 0x0110,
+	0x0419, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x2b51, 0x709f,
+	0xffff, 0x0018, 0x001e, 0x015e, 0x719e, 0x004e, 0x002e, 0x00ce,
+	0x0005, 0x00c6, 0x0016, 0x709f, 0x0001, 0x2009, 0x007e, 0x080c,
+	0x4f4d, 0x1138, 0x080c, 0x2cdd, 0x04a9, 0x0118, 0x70d4, 0xc0bd,
+	0x70d6, 0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6,
+	0x2c68, 0x2001, 0xb557, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c,
+	0x9ed6, 0x01d8, 0x2d00, 0x601a, 0x080c, 0xa027, 0x601f, 0x0001,
+	0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0000, 0x080c, 0x4efd,
+	0x0126, 0x2091, 0x8000, 0x7098, 0x8000, 0x709a, 0x012e, 0x2009,
+	0x0004, 0x080c, 0x864c, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e,
+	0x001e, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001,
+	0xb557, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9ed6, 0x0550,
+	0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e,
+	0x0140, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1110, 0x080c,
+	0x2c9c, 0x080c, 0xa027, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c,
+	0x4eeb, 0x2001, 0x0002, 0x080c, 0x4efd, 0x0126, 0x2091, 0x8000,
+	0x7098, 0x8000, 0x709a, 0x012e, 0x2009, 0x0002, 0x080c, 0x864c,
+	0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6,
+	0x0026, 0x2009, 0x0080, 0x080c, 0x4f4d, 0x1120, 0x0031, 0x0110,
+	0x70db, 0xffff, 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6,
+	0x00c6, 0x2c68, 0x080c, 0x85c7, 0x01e8, 0x2d00, 0x601a, 0x080c,
+	0xa027, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001,
+	0x0002, 0x080c, 0x4efd, 0x0126, 0x2091, 0x8000, 0x080c, 0x2c9c,
+	0x70dc, 0x8000, 0x70de, 0x012e, 0x2009, 0x0002, 0x080c, 0x864c,
+	0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6,
+	0x00d6, 0x0126, 0x2091, 0x8000, 0x2009, 0x007f, 0x080c, 0x4f4d,
+	0x1190, 0x2c68, 0x080c, 0x85c7, 0x0170, 0x2d00, 0x601a, 0x6312,
+	0x601f, 0x0001, 0x620a, 0x080c, 0xa027, 0x2009, 0x0022, 0x080c,
+	0x864c, 0xa085, 0x0001, 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6,
+	0x00c6, 0x0066, 0x0036, 0x0026, 0x080c, 0x6e01, 0x080c, 0x6da4,
+	0x080c, 0x906f, 0x2130, 0x81ff, 0x0128, 0x20a9, 0x007e, 0x2009,
+	0x0000, 0x0020, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c,
+	0x4fa9, 0x1120, 0x080c, 0x51aa, 0x080c, 0x4c0b, 0x001e, 0x8108,
+	0x1f04, 0x2c86, 0x86ff, 0x1110, 0x080c, 0x11f0, 0x002e, 0x003e,
+	0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026,
+	0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c,
+	0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x2c08, 0x080c,
+	0xae82, 0x007e, 0x001e, 0x2e60, 0x080c, 0x51aa, 0x6210, 0x6314,
+	0x080c, 0x4c0b, 0x6212, 0x6316, 0x001e, 0x002e, 0x003e, 0x00ce,
+	0x00ee, 0x0005, 0x00e6, 0x0006, 0x6018, 0xa080, 0x0028, 0x2004,
+	0xa086, 0x0080, 0x0150, 0x2071, 0xb500, 0x7098, 0xa005, 0x0110,
+	0x8001, 0x709a, 0x000e, 0x00ee, 0x0005, 0x2071, 0xb500, 0x70dc,
+	0xa005, 0x0dc0, 0x8001, 0x70de, 0x0ca8, 0x6000, 0xc08c, 0x6002,
+	0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x0156,
+	0x2178, 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0098, 0x2001, 0xb553,
+	0x2004, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020,
+	0x2009, 0x002d, 0x080c, 0xb0e8, 0x004e, 0x20a9, 0x00ff, 0x2011,
+	0x0000, 0x0026, 0xa28e, 0x007e, 0x0904, 0x2d49, 0xa28e, 0x007f,
+	0x0904, 0x2d49, 0xa28e, 0x0080, 0x05e0, 0xa288, 0xb635, 0x210c,
+	0x81ff, 0x05b8, 0x8fff, 0x1148, 0x2001, 0xb7be, 0x0006, 0x2003,
+	0x0001, 0x04d9, 0x000e, 0x2003, 0x0000, 0x00c6, 0x2160, 0x2001,
+	0x0001, 0x080c, 0x5313, 0x00ce, 0x2019, 0x0029, 0x080c, 0x6df5,
+	0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x00c6, 0x0026, 0x2160,
+	0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x1118, 0x6007, 0x0404,
+	0x0028, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x002e, 0x00ce,
+	0x0016, 0x2c08, 0x080c, 0xae82, 0x001e, 0x007e, 0x2160, 0x080c,
+	0x51aa, 0x002e, 0x8210, 0x1f04, 0x2d01, 0x015e, 0x001e, 0x002e,
+	0x003e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016,
+	0x2001, 0xb553, 0x2004, 0xd0c4, 0x0148, 0xd0a4, 0x0138, 0xa006,
+	0x2220, 0x8427, 0x2009, 0x0029, 0x080c, 0xb0e8, 0x001e, 0x002e,
+	0x004e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x7288, 0x82ff,
+	0x01f8, 0x2011, 0xb553, 0x2214, 0xd2ac, 0x11d0, 0x2100, 0x080c,
+	0x2831, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, 0xa2e0, 0xbcc0,
+	0x2c04, 0xd384, 0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084,
+	0x00ff, 0xa116, 0x0138, 0xa096, 0x00ff, 0x0110, 0x8318, 0x0c68,
+	0xa085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0016,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x0016, 0x0026, 0x0036, 0x2110,
+	0x0026, 0x2019, 0x0029, 0x080c, 0x8299, 0x002e, 0x080c, 0xb38d,
+	0x003e, 0x002e, 0x001e, 0xa180, 0xb635, 0x2004, 0xa065, 0x0158,
+	0x0016, 0x00c6, 0x2061, 0xb8f4, 0x001e, 0x611a, 0x080c, 0x2c9c,
+	0x001e, 0x080c, 0x4f6c, 0x012e, 0x00ce, 0x001e, 0x0005, 0x2001,
+	0xb535, 0x2004, 0xd0cc, 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2,
+	0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4,
+	0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca,
+	0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9,
+	0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad,
+	0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3,
+	0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797, 0x6690, 0x658f,
+	0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c, 0x607a, 0x8079,
+	0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d,
+	0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863,
+	0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454, 0x5353, 0x5252,
+	0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047,
+	0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35,
+	0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d, 0x462c, 0x452b,
+	0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e,
+	0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004,
+	0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700, 0x3600, 0x8000,
+	0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00,
+	0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00,
+	0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700, 0x2600, 0x2500,
+	0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00,
+	0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000,
+	0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x1800,
+	0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400, 0x1300, 0x1200,
+	0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00,
+	0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800, 0x0700, 0x8000,
+	0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400, 0x0300, 0x8000,
+	0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0xb582, 0x7003, 0x0002,
+	0xa006, 0x7012, 0x7016, 0x703a, 0x703e, 0x7033, 0xb592, 0x7037,
+	0xb592, 0x7007, 0x0001, 0x2061, 0xb5d2, 0x6003, 0x0002, 0x0005,
+	0x1004, 0x2eea, 0x0e04, 0x2eea, 0x2071, 0xb582, 0x2b78, 0x7818,
+	0xd084, 0x1140, 0x2a60, 0x7820, 0xa08e, 0x0069, 0x1904, 0x2fcf,
+	0x0804, 0x2f68, 0x0005, 0x2071, 0xb582, 0x7004, 0x0002, 0x2ef3,
+	0x2ef4, 0x2efd, 0x2f0e, 0x0005, 0x1004, 0x2efc, 0x0e04, 0x2efc,
+	0x2b78, 0x7818, 0xd084, 0x01e8, 0x0005, 0x2b78, 0x2061, 0xb5d2,
+	0x6008, 0xa08e, 0x0100, 0x0128, 0xa086, 0x0200, 0x0904, 0x2fc9,
+	0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807, 0x7010, 0x2068,
+	0x6834, 0xa086, 0x0103, 0x0108, 0x0005, 0x2a60, 0x2b78, 0x7018,
+	0x0807, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x1210, 0x61c4, 0x0042,
+	0x2100, 0xa08a, 0x003f, 0x1a04, 0x2fc6, 0x61c4, 0x0804, 0x2f68,
+	0x2faa, 0x2fd5, 0x2fdd, 0x2fe1, 0x2fe9, 0x2fef, 0x2ff3, 0x2fff,
+	0x3002, 0x300c, 0x300f, 0x2fc6, 0x2fc6, 0x2fc6, 0x3012, 0x2fc6,
+	0x3021, 0x3038, 0x304f, 0x30c9, 0x30ce, 0x30f7, 0x3148, 0x3159,
+	0x3178, 0x31b0, 0x31ba, 0x31c7, 0x31da, 0x31fb, 0x3204, 0x323a,
+	0x3240, 0x2fc6, 0x3269, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6,
+	0x3270, 0x327a, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6,
+	0x2fc6, 0x2fc6, 0x3282, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6,
+	0x3294, 0x329e, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6,
+	0x0002, 0x32c8, 0x331c, 0x3377, 0x3391, 0x2fc6, 0x33c2, 0x37f5,
+	0x4233, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6,
+	0x2fc6, 0x300c, 0x300f, 0x37f7, 0x2fc6, 0x3804, 0x42cc, 0x4327,
+	0x438b, 0x2fc6, 0x43ee, 0x4418, 0x4437, 0x4469, 0x2fc6, 0x2fc6,
+	0x2fc6, 0x3808, 0x39ad, 0x39c7, 0x39e5, 0x3a46, 0x3aa6, 0x3ab1,
+	0x3ae9, 0x3af8, 0x3b07, 0x3b0a, 0x3b2d, 0x3b79, 0x3bef, 0x3bfc,
+	0x3cfd, 0x3e23, 0x3e4c, 0x3f4a, 0x3f6c, 0x3f78, 0x3fb1, 0x4075,
+	0x2fc6, 0x2fc6, 0x2fc6, 0x2fc6, 0x40dd, 0x40f8, 0x416a, 0x421c,
+	0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x3ea9, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x2fb6, 0x7818, 0xd084, 0x0110, 0x012e, 0x0cb0,
+	0x7c22, 0x7926, 0x7a2a, 0x7b2e, 0x781b, 0x0001, 0x2091, 0x4080,
+	0x7007, 0x0001, 0x2091, 0x5000, 0x012e, 0x0005, 0x2021, 0x4001,
+	0x0c18, 0x2021, 0x4002, 0x0c00, 0x2021, 0x4003, 0x08e8, 0x2021,
+	0x4005, 0x08d0, 0x2021, 0x4006, 0x08b8, 0xa02e, 0x2520, 0x7b28,
+	0x7a2c, 0x7824, 0x7930, 0x0804, 0x3eb6, 0x7823, 0x0004, 0x7824,
+	0x0807, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804,
+	0x3eb9, 0x7924, 0x7828, 0x2114, 0x200a, 0x0804, 0x2faa, 0x7924,
+	0x2114, 0x0804, 0x2faa, 0x2099, 0x0009, 0x20a1, 0x0009, 0x20a9,
+	0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0804, 0x2faa, 0x7824,
+	0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0002, 0x2019, 0x0006,
+	0x783b, 0x0017, 0x0804, 0x2faa, 0x7d38, 0x7c3c, 0x0840, 0x7d38,
+	0x7c3c, 0x0888, 0x2061, 0x1000, 0xe10c, 0xa006, 0x2c15, 0xa200,
+	0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904, 0x2faa, 0x0804,
+	0x2fcc, 0x2069, 0xb552, 0x7824, 0x7930, 0xa11a, 0x1a04, 0x2fd2,
+	0x8019, 0x0904, 0x2fd2, 0x684a, 0x6942, 0x782c, 0x6852, 0x7828,
+	0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x5da5, 0x0804, 0x2faa,
+	0x2069, 0xb552, 0x7824, 0x7934, 0xa11a, 0x1a04, 0x2fd2, 0x8019,
+	0x0904, 0x2fd2, 0x684e, 0x6946, 0x782c, 0x6862, 0x7828, 0x6866,
+	0xa006, 0x686a, 0x686e, 0x080c, 0x53d5, 0x0804, 0x2faa, 0xa02e,
+	0x2520, 0x81ff, 0x1904, 0x2fcf, 0x7924, 0x7b28, 0x7a2c, 0x20a9,
+	0x0005, 0x20a1, 0xb589, 0x41a1, 0x080c, 0x3e75, 0x0904, 0x2fcf,
+	0x2009, 0x0020, 0x080c, 0x3eb6, 0x701b, 0x3067, 0x0005, 0x6834,
+	0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0138, 0xa096, 0x0019,
+	0x0120, 0xa096, 0x0015, 0x1904, 0x2fcf, 0x810f, 0xa18c, 0x00ff,
+	0x0904, 0x2fcf, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c,
+	0x3e75, 0x0904, 0x2fcf, 0x2009, 0x0020, 0x2061, 0xb5d2, 0x6224,
+	0x6328, 0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1,
+	0x0000, 0xa5a9, 0x0000, 0x080c, 0x3eb6, 0x701b, 0x3098, 0x0005,
+	0x6834, 0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a,
+	0x1904, 0x2fcf, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a,
+	0x080c, 0x4e49, 0x1128, 0x7007, 0x0003, 0x701b, 0x30b2, 0x0005,
+	0x080c, 0x54db, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099,
+	0xb589, 0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000,
+	0xa5a9, 0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x012e, 0x0804,
+	0x3eb9, 0x61ac, 0x7824, 0x60ae, 0x0804, 0x2faa, 0x2091, 0x8000,
+	0x7823, 0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020,
+	0x2009, 0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100,
+	0x6200, 0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009,
+	0x04fd, 0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff,
+	0x1904, 0x2fcf, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4fa9,
+	0x1904, 0x2fd2, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210,
+	0x0804, 0x2fd2, 0x7c28, 0x7d2c, 0x080c, 0x5171, 0xd28c, 0x1118,
+	0x080c, 0x511a, 0x0010, 0x080c, 0x514a, 0x1518, 0x2061, 0xbd00,
+	0x0126, 0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010,
+	0xa06d, 0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150,
+	0x012e, 0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02, 0x1a04,
+	0x2fcf, 0x0c30, 0x080c, 0x992a, 0x012e, 0x0904, 0x2fcf, 0x0804,
+	0x2faa, 0xa00e, 0x2001, 0x0005, 0x080c, 0x54db, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x9ed2, 0x080c, 0x5408, 0x012e, 0x0804, 0x2faa,
+	0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c,
+	0x506f, 0x0904, 0x2fcf, 0x080c, 0x517d, 0x0904, 0x2fcf, 0x0804,
+	0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2,
+	0x080c, 0x51e9, 0x0904, 0x2fcf, 0x2019, 0x0005, 0x7924, 0x080c,
+	0x5198, 0x0904, 0x2fcf, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2fd2,
+	0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x69a8, 0x0804, 0x2faa,
+	0x0126, 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0450,
+	0x2029, 0x00ff, 0x6450, 0x2400, 0xa506, 0x01f8, 0x2508, 0x080c,
+	0x4fa9, 0x11d8, 0x080c, 0x51e9, 0x1128, 0x2009, 0x0002, 0x62b4,
+	0x2518, 0x00c0, 0x2019, 0x0004, 0xa00e, 0x080c, 0x5198, 0x1118,
+	0x2009, 0x0006, 0x0078, 0x7824, 0xa08a, 0x1000, 0x1270, 0x8003,
+	0x800b, 0x810b, 0xa108, 0x080c, 0x69a8, 0x8529, 0x1ae0, 0x012e,
+	0x0804, 0x2faa, 0x012e, 0x0804, 0x2fcf, 0x012e, 0x0804, 0x2fd2,
+	0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x50d5, 0x080c, 0x5171,
+	0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904,
+	0x2fd2, 0x080c, 0x50c6, 0x080c, 0x5171, 0x0804, 0x2faa, 0x81ff,
+	0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x514c,
+	0x0904, 0x2fcf, 0x080c, 0x4e8d, 0x080c, 0x5113, 0x080c, 0x5171,
+	0x0804, 0x2faa, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x506f,
+	0x0904, 0x2fcf, 0x62a0, 0x2019, 0x0005, 0x00c6, 0x080c, 0x51aa,
+	0x2061, 0x0000, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c,
+	0x6d02, 0x2009, 0x0000, 0x080c, 0xae82, 0x007e, 0x00ce, 0x080c,
+	0x5171, 0x0804, 0x2faa, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c,
+	0x5171, 0x2208, 0x0804, 0x2faa, 0x0156, 0x00d6, 0x00e6, 0x2069,
+	0xb614, 0x6810, 0x6914, 0xa10a, 0x1210, 0x2009, 0x0000, 0x6816,
+	0x2011, 0x0000, 0x2019, 0x0000, 0x20a9, 0x007e, 0x2069, 0xb635,
+	0x2d04, 0xa075, 0x0130, 0x704c, 0x0071, 0xa210, 0x7080, 0x0059,
+	0xa318, 0x8d68, 0x1f04, 0x3218, 0x2300, 0xa218, 0x00ee, 0x00de,
+	0x015e, 0x0804, 0x2faa, 0x00f6, 0x0016, 0xa07d, 0x0140, 0x2001,
+	0x0000, 0x8000, 0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e,
+	0x00fe, 0x0005, 0x2069, 0xb614, 0x6910, 0x62b0, 0x0804, 0x2faa,
+	0x81ff, 0x1904, 0x2fcf, 0x6150, 0xa190, 0x2dc4, 0x2215, 0xa294,
+	0x00ff, 0x6370, 0x83ff, 0x0108, 0x6274, 0x67d4, 0xd79c, 0x0118,
+	0x2031, 0x0001, 0x0090, 0xd7ac, 0x0118, 0x2031, 0x0003, 0x0068,
+	0xd7a4, 0x0118, 0x2031, 0x0002, 0x0040, 0x080c, 0x5acf, 0x1118,
+	0x2031, 0x0004, 0x0010, 0x2031, 0x0000, 0x7e3a, 0x7f3e, 0x0804,
+	0x2faa, 0x6140, 0x6244, 0x2019, 0xb7b6, 0x231c, 0x0804, 0x2faa,
+	0x0126, 0x2091, 0x8000, 0x6134, 0xa006, 0x2010, 0x6338, 0x012e,
+	0x0804, 0x2faa, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6244, 0x6338,
+	0x0804, 0x2faa, 0x6140, 0x6244, 0x7824, 0x6042, 0x7b28, 0x6346,
+	0x2069, 0xb552, 0x831f, 0xa305, 0x6816, 0x782c, 0x2069, 0xb7b6,
+	0x2d1c, 0x206a, 0x0804, 0x2faa, 0x0126, 0x2091, 0x8000, 0x7824,
+	0x6036, 0x782c, 0x603a, 0x012e, 0x0804, 0x2faa, 0x7838, 0xa005,
+	0x01a8, 0x7828, 0xa025, 0x0904, 0x2fd2, 0x782c, 0xa02d, 0x0904,
+	0x2fd2, 0xa00e, 0x080c, 0x4fa9, 0x1120, 0x6244, 0x6338, 0x6446,
+	0x653a, 0xa186, 0x00ff, 0x0190, 0x8108, 0x0ca0, 0x080c, 0x3e9a,
+	0x0904, 0x2fd2, 0x7828, 0xa00d, 0x0904, 0x2fd2, 0x782c, 0xa005,
+	0x0904, 0x2fd2, 0x6244, 0x6146, 0x6338, 0x603a, 0x0804, 0x2faa,
+	0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x00c6,
+	0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff,
+	0x1130, 0x2001, 0xb515, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182,
+	0x007f, 0x16a0, 0xa188, 0x2dc4, 0x210d, 0xa18c, 0x00ff, 0x2001,
+	0xb515, 0x2004, 0xa116, 0x0550, 0x810f, 0xa105, 0x0126, 0x2091,
+	0x8000, 0x0006, 0x080c, 0x85c7, 0x000e, 0x01e0, 0x601a, 0x600b,
+	0xbc09, 0x601f, 0x0001, 0x080c, 0x3e75, 0x01d8, 0x6837, 0x0000,
+	0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b,
+	0x3370, 0x2d00, 0x6012, 0x2009, 0x0032, 0x080c, 0x864c, 0x012e,
+	0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804, 0x2fcf, 0x00ce, 0x0804,
+	0x2fd2, 0x080c, 0x861d, 0x0cb0, 0x2001, 0xb500, 0x2004, 0xa086,
+	0x0003, 0x1904, 0x2fcf, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f,
+	0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0xb515, 0x2004,
+	0xa085, 0xff00, 0x0078, 0xa182, 0x007f, 0x16a0, 0xa188, 0x2dc4,
+	0x210d, 0xa18c, 0x00ff, 0x2001, 0xb515, 0x2004, 0xa116, 0x0550,
+	0x810f, 0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x85c7,
+	0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05, 0x601f, 0x0001, 0x080c,
+	0x3e75, 0x01d8, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x701b, 0x3370, 0x2d00, 0x6012, 0x2009,
+	0x0032, 0x080c, 0x864c, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce,
+	0x0804, 0x2fcf, 0x00ce, 0x0804, 0x2fd2, 0x080c, 0x861d, 0x0cb0,
+	0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0x0804, 0x2faa, 0x2061,
+	0xb874, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0178, 0x6104,
+	0x6208, 0x2a60, 0x6068, 0x783a, 0x60b4, 0x783e, 0x60b0, 0x2019,
+	0x0072, 0x201a, 0x6348, 0x012e, 0x0804, 0x2faa, 0xa00e, 0x2110,
+	0x0c80, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x0904, 0x2fcf,
+	0x0126, 0x2091, 0x8000, 0x6248, 0x6068, 0xa202, 0x0248, 0xa085,
+	0x0001, 0x080c, 0x2867, 0x080c, 0x462c, 0x012e, 0x0804, 0x2faa,
+	0x012e, 0x0804, 0x2fd2, 0x0006, 0x0016, 0x00c6, 0x00e6, 0x2001,
+	0xb7bf, 0x2070, 0x2061, 0xb552, 0x6008, 0x2072, 0x2009, 0x0000,
+	0x2011, 0x1000, 0x080c, 0x6b40, 0x7206, 0x00ee, 0x00ce, 0x001e,
+	0x000e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7824, 0xa084, 0x0007,
+	0x0002, 0x33d4, 0x33dd, 0x33e4, 0x33d1, 0x33d1, 0x33d1, 0x33d1,
+	0x33d1, 0x012e, 0x0804, 0x2fd2, 0x2009, 0x0114, 0x2104, 0xa085,
+	0x0800, 0x200a, 0x080c, 0x354f, 0x0070, 0x2009, 0x010b, 0x200b,
+	0x0010, 0x080c, 0x354f, 0x0038, 0x81ff, 0x0128, 0x012e, 0x2021,
+	0x400b, 0x0804, 0x2fac, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x080c, 0x33ab, 0x2009, 0x0101, 0x210c,
+	0x0016, 0x2001, 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001,
+	0x007a, 0x2034, 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050,
+	0x2058, 0x080c, 0x379a, 0x080c, 0x36fe, 0xa03e, 0x2720, 0x00f6,
+	0x00e6, 0x00c6, 0x2d60, 0x2071, 0xb84a, 0x2079, 0x0020, 0x00d6,
+	0x2069, 0x0000, 0x6824, 0xd0b4, 0x0140, 0x2001, 0x007d, 0x2004,
+	0x783e, 0x2001, 0x007c, 0x2004, 0x783a, 0x00de, 0x2011, 0x0001,
+	0x080c, 0x36aa, 0x080c, 0x36aa, 0x00ce, 0x00ee, 0x00fe, 0x080c,
+	0x35f5, 0x080c, 0x36d2, 0x080c, 0x364f, 0x080c, 0x35b4, 0x080c,
+	0x35e5, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x0530, 0x7814,
+	0xa084, 0x0184, 0xa085, 0x0010, 0x7816, 0x2079, 0x0140, 0x080c,
+	0x352d, 0x1110, 0x00fe, 0x0430, 0x7804, 0xd0dc, 0x0dc0, 0x2079,
+	0x0100, 0x7827, 0x0086, 0x7814, 0xa084, 0x0184, 0xa085, 0x0032,
+	0x7816, 0x080c, 0x352d, 0x1110, 0x00fe, 0x00a0, 0x7824, 0xd0bc,
+	0x0dc0, 0x7827, 0x0080, 0xa026, 0x7c16, 0x7824, 0xd0ac, 0x0130,
+	0x8b58, 0x080c, 0x3537, 0x00fe, 0x0804, 0x34f7, 0x00fe, 0x080c,
+	0x352d, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, 0x007b,
+	0x2502, 0x080c, 0x3537, 0x0088, 0x87ff, 0x0140, 0x2001, 0x0201,
+	0x2004, 0xa005, 0x1904, 0x3431, 0x8739, 0x0038, 0x2001, 0xb823,
+	0x2004, 0xa086, 0x0000, 0x1904, 0x3431, 0x2001, 0x0033, 0x2003,
+	0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, 0x34f7,
+	0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, 0x34f7,
+	0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac,
+	0x1148, 0x2001, 0xb823, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003,
+	0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, 0xa005,
+	0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, 0x681a,
+	0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, 0x00c6,
+	0x20a9, 0x0004, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, 0x0203,
+	0x2004, 0x1f04, 0x34cc, 0x00ce, 0x0040, 0x6827, 0x0001, 0x2001,
+	0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, 0x2079,
+	0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, 0x2004,
+	0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, 0x601e,
+	0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x340f, 0x2061,
+	0x0100, 0x6027, 0x0002, 0x001e, 0x61e2, 0x001e, 0x6106, 0x7824,
+	0xa084, 0x0003, 0xa086, 0x0002, 0x0188, 0x20e1, 0x9028, 0x6050,
+	0xa084, 0xf7ef, 0x6052, 0x602f, 0x0000, 0x602c, 0xc0ac, 0x602e,
+	0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, 0x2a10,
+	0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, 0x2faa,
+	0x012e, 0x2021, 0x400c, 0x0804, 0x2fac, 0xa085, 0x0001, 0x1d04,
+	0x3536, 0x2091, 0x6000, 0x8420, 0xa486, 0x0064, 0x0005, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001,
+	0x0020, 0x2003, 0x0004, 0x2001, 0xb823, 0x2003, 0x0000, 0x2001,
+	0xb84a, 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6,
+	0x2079, 0x0100, 0x2001, 0xb515, 0x200c, 0x7932, 0x7936, 0x080c,
+	0x2847, 0x7850, 0xa084, 0x0980, 0xa085, 0x0030, 0x7852, 0x2019,
+	0x01f4, 0x8319, 0x1df0, 0xa084, 0x0980, 0x7852, 0x782c, 0xc0ad,
+	0x782e, 0x20a9, 0x0046, 0x1d04, 0x356b, 0x2091, 0x6000, 0x1f04,
+	0x356b, 0x7850, 0xa085, 0x0400, 0x7852, 0x2001, 0x0009, 0x2004,
+	0xa084, 0x0003, 0xa086, 0x0001, 0x1118, 0x782c, 0xc0ac, 0x782e,
+	0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e,
+	0xe000, 0x1f04, 0x3588, 0x7850, 0xa085, 0x1400, 0x7852, 0x2019,
+	0x61a8, 0x7854, 0xe000, 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8,
+	0x7827, 0x0048, 0x7850, 0xa085, 0x0400, 0x7852, 0x7843, 0x0040,
+	0x2019, 0x01f4, 0xe000, 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140,
+	0x2003, 0x0100, 0x7827, 0x0020, 0x7843, 0x0000, 0x2003, 0x0000,
+	0x7827, 0x0048, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, 0x00f6,
+	0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x2001, 0x0201, 0x2004,
+	0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, 0xd0bc,
+	0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, 0x00fe,
+	0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, 0x260a,
+	0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, 0x0108,
+	0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200,
+	0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001,
+	0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100,
+	0x2001, 0xb7c0, 0x2004, 0x70e2, 0x2009, 0xb515, 0x210c, 0x716e,
+	0x7063, 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, 0x0809,
+	0x7077, 0x0008, 0x7078, 0xa080, 0x0100, 0x707a, 0x7080, 0x8000,
+	0x7082, 0x7087, 0xaaaa, 0xa006, 0x708a, 0x708e, 0x707e, 0x70d6,
+	0x70ab, 0x0036, 0x70af, 0x95d5, 0x7027, 0x0080, 0x7014, 0xa084,
+	0x0184, 0xa085, 0x0032, 0x7016, 0x080c, 0x36d2, 0x080c, 0x352d,
+	0x1110, 0x8421, 0x0028, 0x7024, 0xd0bc, 0x0db0, 0x7027, 0x0080,
+	0x00f6, 0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x00d6, 0x2069,
+	0x0000, 0x6824, 0xd0b4, 0x0120, 0x683c, 0x783e, 0x6838, 0x783a,
+	0x00de, 0x2011, 0x0011, 0x080c, 0x36aa, 0x2011, 0x0001, 0x080c,
+	0x36aa, 0x00ee, 0x00fe, 0x7017, 0x0000, 0x00ee, 0x0005, 0x00f6,
+	0x00e6, 0x2071, 0xb823, 0x2079, 0x0030, 0x7904, 0xd1fc, 0x0904,
+	0x36a7, 0x7803, 0x0002, 0xa026, 0xd19c, 0x1904, 0x36a3, 0x7000,
+	0x0002, 0x36a7, 0x3665, 0x3689, 0x36a3, 0xd1bc, 0x1150, 0xd1dc,
+	0x1150, 0x8001, 0x7002, 0x2011, 0x0001, 0x04e1, 0x05c0, 0x04d1,
+	0x04b0, 0x780f, 0x0000, 0x7820, 0x7924, 0x7803, 0x0004, 0x7822,
+	0x7926, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c, 0x35d1,
+	0x2009, 0x0001, 0x7808, 0xd0ec, 0x0110, 0x2009, 0x0011, 0x7902,
+	0x00f0, 0x8001, 0x7002, 0xa184, 0x0880, 0x1138, 0x7804, 0xd0fc,
+	0x1940, 0x2011, 0x0001, 0x00b1, 0x0090, 0x6030, 0xa092, 0x0004,
+	0xa086, 0x0009, 0x1120, 0x6000, 0x601a, 0x2011, 0x0025, 0x6232,
+	0xd1dc, 0x1988, 0x0870, 0x7803, 0x0004, 0x7003, 0x0000, 0x00ee,
+	0x00fe, 0x0005, 0x6024, 0xa005, 0x0520, 0x8001, 0x6026, 0x6018,
+	0x6130, 0xa140, 0x2804, 0x7832, 0x8840, 0x2804, 0x7836, 0x8840,
+	0x2804, 0x7822, 0x8840, 0x2804, 0x7826, 0x8840, 0x7a02, 0x7000,
+	0x8000, 0x7002, 0x6018, 0xa802, 0xa08a, 0x0029, 0x1138, 0x6018,
+	0xa080, 0x0001, 0x2004, 0x601a, 0x2001, 0x000d, 0x6032, 0xa085,
+	0x0001, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2071, 0xb84a, 0x2079,
+	0x0020, 0x7904, 0xd1fc, 0x01f0, 0x7803, 0x0002, 0x2d60, 0xa026,
+	0x7000, 0x0002, 0x36fa, 0x36e5, 0x36f1, 0x8001, 0x7002, 0xd19c,
+	0x1188, 0x2011, 0x0001, 0x080c, 0x36aa, 0x0160, 0x080c, 0x36aa,
+	0x0048, 0x8001, 0x7002, 0x7804, 0xd0fc, 0x1d30, 0x2011, 0x0001,
+	0x080c, 0x36aa, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x2061, 0x0200, 0x2001, 0xb7c0, 0x2004, 0x601a, 0x2061,
+	0x0100, 0x2001, 0xb7bf, 0x2004, 0x60ce, 0x6004, 0xc0ac, 0xa085,
+	0x0200, 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038,
+	0x2001, 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3e75,
+	0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220,
+	0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080,
+	0x000d, 0x04b1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3e75,
+	0x6833, 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001,
+	0x0076, 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061,
+	0x0020, 0x2079, 0x0100, 0x2001, 0xb7bf, 0x2004, 0x6012, 0x20e1,
+	0x9040, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a,
+	0x0006, 0x2001, 0x0073, 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e,
+	0x78ca, 0xa006, 0x603a, 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005,
+	0x00e6, 0x2071, 0x0010, 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026,
+	0x7432, 0x7336, 0xa006, 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8,
+	0x810b, 0x7122, 0x7003, 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003,
+	0x0002, 0x7003, 0x0040, 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180,
+	0x00c6, 0x00d6, 0x2d60, 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x6018,
+	0x2070, 0x2d00, 0x7006, 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001,
+	0x00ee, 0x0005, 0x00e6, 0x2001, 0x0075, 0x2004, 0xa005, 0x0508,
+	0x2038, 0x2001, 0x0078, 0x2024, 0x2001, 0x0079, 0x201c, 0x080c,
+	0x3e75, 0x2d60, 0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a,
+	0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e,
+	0x6818, 0xa080, 0x000d, 0x080c, 0x3768, 0x1d88, 0x2d00, 0x681a,
+	0x00e0, 0x080c, 0x3e75, 0x2d60, 0x6033, 0x000d, 0x2070, 0x6027,
+	0x0001, 0x2c00, 0x601a, 0x2001, 0x0078, 0x2004, 0x2072, 0x2001,
+	0x0079, 0x2004, 0x7006, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8,
+	0x700a, 0x2001, 0x0073, 0x2004, 0x700e, 0x2001, 0x0030, 0x2003,
+	0x0004, 0x7824, 0xd0ac, 0x1178, 0x2001, 0x0101, 0x200c, 0xc1ed,
+	0x2102, 0x6027, 0x0000, 0x2001, 0xb823, 0x2003, 0x0003, 0x2001,
+	0x0030, 0x2003, 0x0009, 0x00ee, 0x0005, 0x0804, 0x2faa, 0x0126,
+	0x2091, 0x8000, 0x20a9, 0x0012, 0x2001, 0xb540, 0x20a0, 0xa006,
+	0x40a4, 0x012e, 0x0804, 0x2faa, 0x7d38, 0x7c3c, 0x0804, 0x3051,
+	0x080c, 0x3e75, 0x0904, 0x2fcf, 0x080c, 0x5acf, 0x0110, 0x080c,
+	0x4bf0, 0x2009, 0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c,
+	0x3eb6, 0x701b, 0x381c, 0x0005, 0xade8, 0x000d, 0x6800, 0xa005,
+	0x0904, 0x2fd2, 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x2fd2,
+	0xd094, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0xa292,
+	0x0005, 0x0218, 0xa18c, 0xffdf, 0x0010, 0xa18d, 0x0020, 0x6106,
+	0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0xa18d,
+	0x0010, 0x0010, 0xa18c, 0xffef, 0x6106, 0x00ce, 0x2009, 0x0100,
+	0x210c, 0xa18a, 0x0002, 0x0268, 0xd084, 0x0158, 0x6a28, 0xa28a,
+	0x007f, 0x1a04, 0x2fd2, 0xa288, 0x2dc4, 0x210d, 0xa18c, 0x00ff,
+	0x615a, 0xd0dc, 0x0130, 0x6828, 0xa08a, 0x007f, 0x1a04, 0x2fd2,
+	0x6052, 0x6808, 0xa08a, 0x0100, 0x0a04, 0x2fd2, 0xa08a, 0x0841,
+	0x1a04, 0x2fd2, 0xa084, 0x0007, 0x1904, 0x2fd2, 0x680c, 0xa005,
+	0x0904, 0x2fd2, 0x6810, 0xa005, 0x0904, 0x2fd2, 0x6848, 0x6940,
+	0xa10a, 0x1a04, 0x2fd2, 0x8001, 0x0904, 0x2fd2, 0x684c, 0x6944,
+	0xa10a, 0x1a04, 0x2fd2, 0x8001, 0x0904, 0x2fd2, 0x6804, 0xd0fc,
+	0x0560, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x2009, 0x0014, 0x7a2c,
+	0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399, 0x0000, 0x080c,
+	0x3eb6, 0x701b, 0x389c, 0x0005, 0xade8, 0x000d, 0x20a9, 0x0014,
+	0x2d98, 0x2069, 0xb56e, 0x2da0, 0x53a3, 0x7010, 0xa0e8, 0x000d,
+	0x2001, 0xb572, 0x200c, 0xd1e4, 0x0140, 0x00c6, 0x2061, 0x0100,
+	0x6004, 0xa085, 0x0b00, 0x6006, 0x00ce, 0x2009, 0xb7b1, 0x200b,
+	0x0000, 0x2001, 0xb574, 0x2004, 0xd0ac, 0x0158, 0x7824, 0x200a,
+	0x2009, 0x017f, 0x200a, 0x3200, 0xa084, 0x003f, 0xa085, 0x3020,
+	0x2090, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xb552, 0x2da0, 0x53a3,
+	0x6814, 0xa08c, 0x00ff, 0x6142, 0x8007, 0xa084, 0x00ff, 0x6046,
+	0x080c, 0x5da5, 0x080c, 0x536c, 0x080c, 0x53d5, 0x6000, 0xa086,
+	0x0000, 0x1904, 0x3997, 0x6808, 0x602a, 0x080c, 0x2470, 0x0006,
+	0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x000e, 0x0268, 0x2009,
+	0x0170, 0x200b, 0x0080, 0xe000, 0xe000, 0x200b, 0x0000, 0x0036,
+	0x6b08, 0x080c, 0x28a2, 0x003e, 0x6818, 0x691c, 0x6a20, 0x6b24,
+	0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e, 0x6322,
+	0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007,
+	0x810f, 0x8217, 0x831f, 0x0010, 0xa084, 0xf0ff, 0x6006, 0x610a,
+	0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f, 0x20a9, 0x0004,
+	0x20a1, 0xb7c6, 0x40a1, 0x080c, 0x6a68, 0x6904, 0xd1fc, 0x0520,
+	0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70, 0xd384, 0x01c8,
+	0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c, 0x635c, 0x6878,
+	0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, 0xa184,
+	0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003, 0x0010, 0x6003,
+	0x0001, 0x1f04, 0x3931, 0x00ce, 0x2069, 0xb552, 0x2001, 0xb79e,
+	0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, 0x0170, 0xa28e, 0x0010,
+	0x0118, 0xa28e, 0x0020, 0x0140, 0x2003, 0xaaaa, 0x080c, 0x28eb,
+	0x2001, 0xb78f, 0x2102, 0x0008, 0x2102, 0x00c6, 0x2061, 0x0100,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c, 0x5acf, 0x0128,
+	0x080c, 0x40cf, 0x0110, 0x080c, 0x2867, 0x60c8, 0xa005, 0x01d0,
+	0x6003, 0x0001, 0x2009, 0x397d, 0x00e0, 0x080c, 0x5acf, 0x1178,
+	0x2011, 0x59a2, 0x080c, 0x699c, 0x2011, 0x5995, 0x080c, 0x6a5c,
+	0x2001, 0xb79f, 0x2003, 0x0000, 0x080c, 0x5a07, 0x0040, 0x080c,
+	0x4b1f, 0x0028, 0x6003, 0x0004, 0x2009, 0x3997, 0x0010, 0x0804,
+	0x2faa, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0258, 0x2001,
+	0x0170, 0x2004, 0xa084, 0x00ff, 0xa086, 0x004c, 0x1118, 0x2091,
+	0x309d, 0x0817, 0x2091, 0x301d, 0x0817, 0x6000, 0xa086, 0x0000,
+	0x0904, 0x2fcf, 0x2069, 0xb552, 0x7830, 0x6842, 0x7834, 0x6846,
+	0x6804, 0xd0fc, 0x0118, 0x2009, 0x0030, 0x0010, 0x2009, 0x001c,
+	0x2d00, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0xa006,
+	0x080c, 0x2867, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x1178,
+	0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001,
+	0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0020, 0x080c,
+	0x4bf0, 0x080c, 0x4b1f, 0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf,
+	0x080c, 0x5acf, 0x1110, 0x0804, 0x2fcf, 0x6188, 0x81ff, 0x0198,
+	0x703f, 0x0000, 0x2001, 0xbcc0, 0x2009, 0x0040, 0x7a2c, 0x7b28,
+	0x7c3c, 0x7d38, 0x0126, 0x2091, 0x8000, 0x080c, 0x3eb9, 0x701b,
+	0x2fa8, 0x012e, 0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0xbcc0,
+	0x20a9, 0x0040, 0x20a1, 0xbcc0, 0x2019, 0xffff, 0x43a4, 0x6550,
+	0xa588, 0x2dc4, 0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011,
+	0x0002, 0x2100, 0xa506, 0x01a8, 0x080c, 0x4fa9, 0x1190, 0x6014,
+	0x821c, 0x0238, 0xa398, 0xbcc0, 0xa085, 0xff00, 0x8007, 0x201a,
+	0x0038, 0xa398, 0xbcc0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a,
+	0x8210, 0x8108, 0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007,
+	0x2d0c, 0xa105, 0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0xbcc0,
+	0x2099, 0xbcc0, 0x080c, 0x4b8f, 0x0804, 0x39f2, 0x080c, 0x3e9a,
+	0x0904, 0x2fd2, 0x00c6, 0x080c, 0x3e75, 0x00ce, 0x1120, 0x2009,
+	0x0002, 0x0804, 0x2fcf, 0x2001, 0xb553, 0x2004, 0xd0b4, 0x0550,
+	0x7824, 0xa084, 0xff00, 0xa08e, 0x7e00, 0x0520, 0xa08e, 0x7f00,
+	0x0508, 0xa08e, 0x8000, 0x01f0, 0x6000, 0xd08c, 0x11d8, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x11a8, 0x6837, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x080c, 0x9dda, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x2fcf, 0x7007, 0x0003, 0x701b, 0x3a7e, 0x0005, 0x080c, 0x3e9a,
+	0x0904, 0x2fd2, 0x20a9, 0x002b, 0x2c98, 0xade8, 0x0002, 0x2da0,
+	0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098, 0xad80, 0x0006,
+	0x20a0, 0x080c, 0x4b8f, 0x20a9, 0x0004, 0xac80, 0x000a, 0x2098,
+	0xad80, 0x000a, 0x20a0, 0x080c, 0x4b8f, 0x2d00, 0x2009, 0x002b,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x81ff, 0x1904,
+	0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c, 0x5186, 0x0804,
+	0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x7828, 0xa08a, 0x1000, 0x1a04,
+	0x2fd2, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x080c, 0x51e9, 0x0904,
+	0x2fcf, 0x2019, 0x0004, 0xa00e, 0x080c, 0x5198, 0x7924, 0x810f,
+	0x7a28, 0x0011, 0x0804, 0x2faa, 0xa186, 0x00ff, 0x0110, 0x0071,
+	0x0060, 0x2029, 0x007e, 0x2061, 0xb500, 0x6450, 0x2400, 0xa506,
+	0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c, 0x4fa9,
+	0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c, 0x69a8,
+	0x0005, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2,
+	0x080c, 0x506f, 0x0904, 0x2fcf, 0x080c, 0x518f, 0x0804, 0x2faa,
+	0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c,
+	0x506f, 0x0904, 0x2fcf, 0x080c, 0x517d, 0x0804, 0x2faa, 0x6100,
+	0x0804, 0x2faa, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x2001, 0xb500,
+	0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x00d6, 0xace8, 0x000a,
+	0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007, 0x783e,
+	0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217, 0x00de,
+	0x6100, 0xa18c, 0x0200, 0x0804, 0x2faa, 0x7824, 0xa09c, 0x0003,
+	0xd0b4, 0x1160, 0xa39a, 0x0003, 0x1a04, 0x2fcf, 0x6250, 0xa294,
+	0x00ff, 0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0xb540,
+	0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9,
+	0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x1904, 0x2fcf, 0x00c6, 0x080c,
+	0x3e75, 0x00ce, 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x080c, 0x9d86, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b,
+	0x3b6a, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0xad80,
+	0x000e, 0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804,
+	0x3eb9, 0xa006, 0x080c, 0x2867, 0x7824, 0xa084, 0x00ff, 0xa086,
+	0x00ff, 0x0118, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x5acf, 0x0110,
+	0x080c, 0x4bf0, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2fd2, 0x7924,
+	0xa18c, 0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f,
+	0x1a04, 0x2fd2, 0x2100, 0x080c, 0x2831, 0x0026, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x2061, 0xb7f3, 0x601b, 0x0000, 0x601f, 0x0000,
+	0x080c, 0x5acf, 0x1178, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001,
+	0xb500, 0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5b13, 0x080c,
+	0x5a07, 0x0420, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002,
+	0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019, 0x0000, 0x080c,
+	0x7fe4, 0x003e, 0x2061, 0x0100, 0x2001, 0xb515, 0x2004, 0xa084,
+	0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010,
+	0x2009, 0x002d, 0x2011, 0x4b54, 0x080c, 0x6a22, 0x7924, 0xa18c,
+	0xff00, 0x810f, 0x080c, 0x5acf, 0x1110, 0x2009, 0x00ff, 0x7a28,
+	0x080c, 0x3acc, 0x012e, 0x00ce, 0x002e, 0x0804, 0x2faa, 0x7924,
+	0xa18c, 0xff00, 0x810f, 0x00c6, 0x080c, 0x4f4d, 0x2c08, 0x00ce,
+	0x1904, 0x2fd2, 0x0804, 0x2faa, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x2fcf, 0x60d4, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009,
+	0x0005, 0x0804, 0x2fcf, 0x080c, 0x3e75, 0x1120, 0x2009, 0x0002,
+	0x0804, 0x2fcf, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c,
+	0x3eb6, 0x701b, 0x3c1c, 0x0005, 0x2009, 0x0080, 0x080c, 0x4fa9,
+	0x1130, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0120, 0x2021,
+	0x400a, 0x0804, 0x2fac, 0x00d6, 0xade8, 0x000d, 0x6900, 0x6a08,
+	0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0904,
+	0x3c93, 0xa0be, 0x0112, 0x0904, 0x3c93, 0xa0be, 0x0113, 0x0904,
+	0x3c93, 0xa0be, 0x0114, 0x0904, 0x3c93, 0xa0be, 0x0117, 0x0904,
+	0x3c93, 0xa0be, 0x011a, 0x0904, 0x3c93, 0xa0be, 0x011c, 0x0904,
+	0x3c93, 0xa0be, 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be,
+	0x0171, 0x05c8, 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120,
+	0x6830, 0x8007, 0x6832, 0x04a8, 0xa0be, 0x0212, 0x0540, 0xa0be,
+	0x0213, 0x0528, 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168,
+	0xa0be, 0x021a, 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be,
+	0x0300, 0x01c8, 0x00de, 0x0804, 0x2fd2, 0xad80, 0x0010, 0x20a9,
+	0x0007, 0x080c, 0x3cd9, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c,
+	0x3cd9, 0x0048, 0xad80, 0x000c, 0x080c, 0x3ce7, 0x0050, 0xad80,
+	0x000e, 0x080c, 0x3ce7, 0xad80, 0x000c, 0x20a9, 0x0001, 0x080c,
+	0x3cd9, 0x00c6, 0x080c, 0x3e75, 0x0568, 0x6838, 0xc0fd, 0x683a,
+	0x6837, 0x0119, 0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001,
+	0x810b, 0x697e, 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92,
+	0x6996, 0x689b, 0x0000, 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x9da2,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003, 0x701b,
+	0x3cd0, 0x0005, 0x00ce, 0x00de, 0x2009, 0x0002, 0x0804, 0x2fcf,
+	0x6820, 0xa086, 0x8001, 0x1904, 0x2faa, 0x2009, 0x0004, 0x0804,
+	0x2fcf, 0x0016, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a,
+	0x8108, 0x280a, 0x8108, 0x1f04, 0x3cdb, 0x001e, 0x0005, 0x0016,
+	0x00a6, 0x00b6, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054,
+	0x8000, 0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108,
+	0x280a, 0x00be, 0x00ae, 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009,
+	0x0001, 0x0804, 0x2fcf, 0x60d4, 0xd0ac, 0x1130, 0xd09c, 0x1120,
+	0x2009, 0x0005, 0x0804, 0x2fcf, 0x7924, 0x2140, 0xa18c, 0xff00,
+	0x810f, 0x60d4, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2fd2,
+	0xa182, 0x00ff, 0x1a04, 0x2fd2, 0x7a2c, 0x7b28, 0x6070, 0xa306,
+	0x1140, 0x6074, 0xa24e, 0x0904, 0x2fd2, 0xa9cc, 0xff00, 0x0904,
+	0x2fd2, 0x00c6, 0x080c, 0x3dc5, 0x2c68, 0x00ce, 0x0530, 0xa0c6,
+	0x4000, 0x1178, 0x00c6, 0x0006, 0x2d60, 0xa00e, 0x080c, 0x524a,
+	0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce,
+	0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008,
+	0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010,
+	0x2001, 0x4006, 0x2020, 0x0804, 0x2fac, 0x2d00, 0x7022, 0x0016,
+	0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0x85c7, 0x05d8, 0x2d00,
+	0x601a, 0x080c, 0xa027, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c,
+	0x3e75, 0x00ce, 0x2b70, 0x1150, 0x080c, 0x861d, 0x00ee, 0x00ce,
+	0x00be, 0x001e, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x6837, 0x0000,
+	0x683b, 0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0xd88c, 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x2c9c, 0x012e, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4eeb,
+	0x2001, 0x0002, 0x080c, 0x4efd, 0x2009, 0x0002, 0x080c, 0x864c,
+	0xa085, 0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009,
+	0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003, 0x701b, 0x3da8, 0x0005,
+	0x6830, 0xa086, 0x0100, 0x7020, 0x2060, 0x1138, 0x2009, 0x0004,
+	0x6204, 0xa294, 0x00ff, 0x0804, 0x2fcf, 0x2009, 0x0000, 0x6838,
+	0xd0f4, 0x1904, 0x2faa, 0x080c, 0x524a, 0x1108, 0xc185, 0x6000,
+	0xd0bc, 0x0108, 0xc18d, 0x0804, 0x2faa, 0x00e6, 0x00d6, 0xa02e,
+	0x2001, 0xb535, 0x2004, 0xd0ac, 0x0130, 0xa026, 0x20a9, 0x00ff,
+	0x2071, 0xb635, 0x0030, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071,
+	0xb6b5, 0x2e04, 0xa005, 0x1130, 0x2100, 0xa406, 0x1570, 0x2428,
+	0xc5fd, 0x0458, 0x2068, 0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14,
+	0x2600, 0xa206, 0x1190, 0x2400, 0xa106, 0x1160, 0x2d60, 0xd884,
+	0x0568, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1538, 0x2001,
+	0x4000, 0x0428, 0x2001, 0x4007, 0x0410, 0x2400, 0xa106, 0x1168,
+	0x6e14, 0x87ff, 0x1138, 0x86ff, 0x09d0, 0x2001, 0xb535, 0x2004,
+	0xd0ac, 0x19a8, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04,
+	0x3dd9, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001,
+	0x0030, 0x080c, 0x4f4d, 0x1dd0, 0x6312, 0x6216, 0xa006, 0xa005,
+	0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, 0x2fcf, 0x080c, 0x3e75,
+	0x0904, 0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7824,
+	0xa005, 0x0904, 0x2fd2, 0xa096, 0x00ff, 0x0120, 0xa092, 0x0004,
+	0x1a04, 0x2fd2, 0x2010, 0x2d18, 0x080c, 0x2c4f, 0x0904, 0x2fcf,
+	0x7007, 0x0003, 0x701b, 0x3e45, 0x0005, 0x6830, 0xa086, 0x0100,
+	0x0904, 0x2fcf, 0x0804, 0x2faa, 0x7924, 0xa18c, 0xff00, 0x810f,
+	0x60d4, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2fd2, 0xa182,
+	0x00ff, 0x1a04, 0x2fd2, 0x0126, 0x2091, 0x8000, 0x080c, 0x9c8a,
+	0x1188, 0xa190, 0xb635, 0x2204, 0xa065, 0x0160, 0x080c, 0x4c0b,
+	0x2001, 0xb535, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e,
+	0x0804, 0x2faa, 0x012e, 0x0804, 0x2fcf, 0x080c, 0x15f8, 0x0188,
+	0xa006, 0x6802, 0x7010, 0xa005, 0x1120, 0x2d00, 0x7012, 0x7016,
+	0x0030, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80,
+	0x000d, 0x0005, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4fa9,
+	0x1130, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0208, 0xa066,
+	0x8cff, 0x0005, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x080c, 0x4fa9,
+	0x1128, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0208, 0xa066, 0x8cff,
+	0x0005, 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c,
+	0x160f, 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001,
+	0x0010, 0x2031, 0x0000, 0x2061, 0xb5d2, 0x6606, 0x6112, 0x600e,
+	0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x080c, 0x1643, 0x7007,
+	0x0002, 0x701b, 0x2faa, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000,
+	0x2079, 0x0000, 0x2001, 0xb590, 0x2004, 0xa005, 0x1168, 0x0e04,
+	0x3ee4, 0x7818, 0xd084, 0x1140, 0x7a22, 0x7b26, 0x7c2a, 0x781b,
+	0x0001, 0x2091, 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071,
+	0xb582, 0x7138, 0xa182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078,
+	0x7030, 0xa0e0, 0x0004, 0xac82, 0xb5d2, 0x0210, 0x2061, 0xb592,
+	0x2c00, 0x7032, 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262,
+	0x6306, 0x640a, 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005,
+	0x00e6, 0x2071, 0xb582, 0x7038, 0xa005, 0x0570, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x3f3b, 0x00f6, 0x2079, 0x0000, 0x7818, 0xd084,
+	0x1508, 0x00c6, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826,
+	0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001,
+	0x703a, 0xa005, 0x1130, 0x7033, 0xb592, 0x7037, 0xb592, 0x00ce,
+	0x0048, 0xac80, 0x0004, 0xa0fa, 0xb5d2, 0x0210, 0x2001, 0xb592,
+	0x7036, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005, 0x0026, 0x2001,
+	0xb553, 0x2004, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x3ecc,
+	0x002e, 0x0005, 0x81ff, 0x1904, 0x2fcf, 0x0126, 0x2091, 0x8000,
+	0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x5acf, 0x1178,
+	0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001,
+	0xa085, 0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0010, 0x080c,
+	0x4b1f, 0x012e, 0x0804, 0x2faa, 0x7824, 0x2008, 0xa18c, 0xfffd,
+	0x1128, 0x61e0, 0xa10d, 0x61e2, 0x0804, 0x2faa, 0x0804, 0x2fd2,
+	0x81ff, 0x1904, 0x2fcf, 0x6000, 0xa086, 0x0003, 0x1904, 0x2fcf,
+	0x2001, 0xb553, 0x2004, 0xd0ac, 0x1904, 0x2fcf, 0x080c, 0x3e9a,
+	0x0904, 0x2fd2, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120,
+	0x7828, 0xa005, 0x0904, 0x2faa, 0x00c6, 0x080c, 0x3e75, 0x00ce,
+	0x0904, 0x2fcf, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x080c, 0x9e6b, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b,
+	0x3faa, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2fcf, 0x0804,
+	0x2faa, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf,
+	0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3e75, 0x0904,
+	0x2fcf, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f,
+	0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x080c, 0x4fa9, 0x1904,
+	0x4024, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0130, 0xa0c4,
+	0xff00, 0xa8c6, 0x0600, 0x1904, 0x4024, 0x2001, 0xb553, 0x2004,
+	0xd0ac, 0x1128, 0x080c, 0x524a, 0x1110, 0xd79c, 0x05e8, 0xd794,
+	0x1110, 0xd784, 0x0158, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9,
+	0x0004, 0x53a3, 0x080c, 0x3ce7, 0xd794, 0x0148, 0xac80, 0x000a,
+	0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, 0x3ce7, 0x21a2,
+	0xd794, 0x01d8, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002,
+	0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098,
+	0x3400, 0x20a9, 0x0002, 0x53a3, 0x080c, 0x3cd9, 0xac80, 0x0026,
+	0x2098, 0x20a9, 0x0002, 0x53a3, 0x0008, 0x94a0, 0xd794, 0x0110,
+	0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0x2001, 0xb535, 0x2004,
+	0xd0ac, 0x0118, 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186,
+	0x0100, 0x0170, 0x0018, 0xa186, 0x007e, 0x0150, 0xd794, 0x0118,
+	0xa686, 0x0020, 0x0010, 0xa686, 0x0028, 0x0150, 0x0804, 0x3fcd,
+	0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x2faa, 0x702f, 0x0001,
+	0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xb5d2, 0x6007,
+	0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532,
+	0x2c10, 0x080c, 0x1643, 0x7007, 0x0002, 0x701b, 0x4060, 0x0005,
+	0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031,
+	0x0000, 0x2061, 0xb5d2, 0x6224, 0x6328, 0x642c, 0x6530, 0x0804,
+	0x3fcd, 0x7120, 0x810b, 0x0804, 0x2faa, 0x2029, 0x007e, 0x7924,
+	0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020,
+	0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa184, 0x00ff, 0xa0e2,
+	0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa284, 0xff00,
+	0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2,
+	0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04,
+	0x2fd2, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2fd2,
+	0xa502, 0x0a04, 0x2fd2, 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0a04,
+	0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa484, 0xff00, 0x8007, 0xa0e2,
+	0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0xa484, 0x00ff,
+	0xa0e2, 0x0020, 0x0a04, 0x2fd2, 0xa502, 0x0a04, 0x2fd2, 0x2061,
+	0xb7b9, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x2faa, 0x0006,
+	0x2001, 0xb553, 0x2004, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001,
+	0xb572, 0x2004, 0xd0bc, 0x000e, 0x0005, 0x6168, 0x7a24, 0x6300,
+	0x82ff, 0x1118, 0x7926, 0x0804, 0x2faa, 0x83ff, 0x1904, 0x2fd2,
+	0x2001, 0xfff0, 0xa200, 0x1a04, 0x2fd2, 0x2019, 0xffff, 0x606c,
+	0xa302, 0xa200, 0x0a04, 0x2fd2, 0x7926, 0x626a, 0x0804, 0x2faa,
+	0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1904, 0x2fcf, 0x7c28,
+	0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x2009,
+	0x0000, 0x2019, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80,
+	0x0003, 0x7026, 0x20a0, 0xa1e0, 0xb635, 0x2c64, 0x8cff, 0x01b8,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0130, 0x6004, 0xa084,
+	0xff00, 0xa086, 0x0600, 0x1158, 0x6014, 0x20a2, 0x94a0, 0x6010,
+	0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108,
+	0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, 0x0148, 0x08e0, 0x83ff,
+	0x1120, 0x7120, 0x810c, 0x0804, 0x2faa, 0x702f, 0x0001, 0x711e,
+	0x7020, 0xa300, 0x7022, 0x2061, 0xb5d2, 0x6007, 0x0000, 0x6312,
+	0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, 0x2c10, 0x080c,
+	0x1643, 0x7007, 0x0002, 0x701b, 0x4156, 0x0005, 0x702c, 0xa005,
+	0x1168, 0x711c, 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xb5d2,
+	0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x4113, 0x7120, 0x810c,
+	0x0804, 0x2faa, 0x81ff, 0x1904, 0x2fcf, 0x60d4, 0xd0ac, 0x1118,
+	0xd09c, 0x0904, 0x2fcf, 0x080c, 0x3e75, 0x0904, 0x2fcf, 0x7924,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3eb6, 0x701b, 0x4181,
+	0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, 0x0148,
+	0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, 0x0804,
+	0x2fd2, 0x6820, 0x6924, 0x080c, 0x281d, 0x1510, 0x080c, 0x4f4d,
+	0x11f8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3e75,
+	0x01b8, 0x080c, 0x3e75, 0x01a0, 0x00ce, 0x00de, 0x6837, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c,
+	0x9dbe, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b, 0x41bb, 0x0005,
+	0x00de, 0x0804, 0x2fcf, 0x7120, 0x080c, 0x2d97, 0x6820, 0xa086,
+	0x8001, 0x0904, 0x2fcf, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002,
+	0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x4b8f, 0x000e,
+	0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xb5d2,
+	0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018,
+	0xa7c6, 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2fd2, 0x2009,
+	0x0004, 0x0804, 0x3eb9, 0xa7c6, 0x7200, 0x1904, 0x2fd2, 0xa6c2,
+	0x0054, 0x0a04, 0x2fd2, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a,
+	0x642e, 0x6532, 0x2c10, 0x080c, 0x1643, 0x7007, 0x0002, 0x701b,
+	0x4202, 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004,
+	0xa080, 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c,
+	0x4b8f, 0x000e, 0x2009, 0x002a, 0x2061, 0xb5d2, 0x6224, 0x6328,
+	0x642c, 0x6530, 0x0804, 0x3eb9, 0x81ff, 0x1904, 0x2fcf, 0x792c,
+	0x2001, 0xb7a0, 0x2102, 0x080c, 0x3e8a, 0x0904, 0x2fd2, 0x080c,
+	0x506f, 0x0904, 0x2fcf, 0x0126, 0x2091, 0x8000, 0x080c, 0x51a1,
+	0x012e, 0x0804, 0x2faa, 0x7824, 0xd08c, 0x1118, 0xd084, 0x0904,
+	0x3a46, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x00c6, 0x080c, 0x3e75,
+	0x00ce, 0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x0128, 0xa08e, 0x0004, 0x0110, 0xa08e,
+	0x0005, 0x15b8, 0x7824, 0xd08c, 0x0120, 0x6000, 0xc08c, 0x6002,
+	0x0030, 0x2001, 0xb553, 0x2004, 0xd0b4, 0x0904, 0x3a82, 0x7824,
+	0xa084, 0xff00, 0xa08e, 0x7e00, 0x0904, 0x3a82, 0xa08e, 0x7f00,
+	0x0904, 0x3a82, 0xa08e, 0x8000, 0x0904, 0x3a82, 0x6000, 0xd08c,
+	0x1904, 0x3a82, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c,
+	0x9dda, 0x1120, 0x2009, 0x0003, 0x0804, 0x2fcf, 0x7007, 0x0003,
+	0x701b, 0x4283, 0x0005, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x0804,
+	0x3a82, 0x2009, 0xb531, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x2fcf, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x0120,
+	0x2009, 0x0007, 0x0804, 0x2fcf, 0x2001, 0xb553, 0x2004, 0xd0ac,
+	0x0120, 0x2009, 0x0008, 0x0804, 0x2fcf, 0x609c, 0xd0a4, 0x1118,
+	0xd0ac, 0x1904, 0x3a82, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x080c, 0x9e6b, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x2fcf, 0x7007, 0x0003, 0x701b, 0x42be, 0x0005, 0x6830, 0xa086,
+	0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2fcf, 0x080c, 0x3e9a,
+	0x0904, 0x2fd2, 0x0804, 0x4252, 0x81ff, 0x2009, 0x0001, 0x1904,
+	0x2fcf, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, 0x2fcf,
+	0x2001, 0xb553, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x1904, 0x2fcf,
+	0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x2009, 0x0009, 0x1904, 0x2fcf, 0x00c6, 0x080c, 0x3e75,
+	0x00ce, 0x2009, 0x0002, 0x0904, 0x2fcf, 0x6837, 0x0000, 0x6833,
+	0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, 0xa18c,
+	0x00ff, 0xa006, 0x82ff, 0x1128, 0xc0ed, 0x6952, 0x792c, 0x6956,
+	0x0048, 0xa28e, 0x0100, 0x1904, 0x2fd2, 0xc0e5, 0x6853, 0x0000,
+	0x6857, 0x0000, 0x683e, 0x080c, 0xa028, 0x2009, 0x0003, 0x0904,
+	0x2fcf, 0x7007, 0x0003, 0x701b, 0x431e, 0x0005, 0x6830, 0xa086,
+	0x0100, 0x2009, 0x0004, 0x0904, 0x2fcf, 0x0804, 0x2faa, 0x81ff,
+	0x2009, 0x0001, 0x1904, 0x2fcf, 0x6000, 0xa086, 0x0003, 0x2009,
+	0x0007, 0x1904, 0x2fcf, 0x080c, 0x3e9a, 0x0904, 0x2fd2, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x1904, 0x2fcf,
+	0x00c6, 0x080c, 0x3e75, 0x00ce, 0x2009, 0x0002, 0x0904, 0x2fcf,
+	0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x080c, 0x3eb6, 0x701b, 0x4355, 0x0005, 0x00d6, 0xade8, 0x000f,
+	0x6800, 0xa086, 0x0500, 0x1140, 0x6804, 0xa005, 0x1128, 0x6808,
+	0xa084, 0xff00, 0x1108, 0x0018, 0x00de, 0x1904, 0x2fd2, 0x00de,
+	0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x00c6,
+	0x080c, 0x3e9a, 0x1118, 0x00ce, 0x0804, 0x2fd2, 0x080c, 0xa077,
+	0x2009, 0x0003, 0x00ce, 0x0904, 0x2fcf, 0x7007, 0x0003, 0x701b,
+	0x4382, 0x0005, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0904,
+	0x2fcf, 0x0804, 0x2faa, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x2fcf, 0x6000, 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, 0x0804,
+	0x2fcf, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0xa6b4, 0x00ff, 0x080c,
+	0x4fa9, 0x1904, 0x2fd2, 0xa186, 0x007f, 0x0150, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, 0x2fcf,
+	0x00c6, 0x080c, 0x3e75, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x2fcf, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x2001, 0x0100,
+	0x8007, 0x680a, 0x080c, 0x9df5, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x2fcf, 0x7007, 0x0003, 0x701b, 0x43ce, 0x0005, 0x6808, 0x8007,
+	0xa086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2fcf, 0x68b0,
+	0x6836, 0x6810, 0x8007, 0xa084, 0x00ff, 0x800c, 0x6814, 0x8007,
+	0xa084, 0x00ff, 0x8004, 0xa080, 0x0002, 0xa108, 0xad80, 0x0004,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x080c, 0x3e75,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x7924, 0xa194, 0xff00,
+	0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804, 0x2fd2, 0x2009,
+	0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3eb6, 0x701b,
+	0x440a, 0x0005, 0x2001, 0xb52a, 0x2003, 0x0001, 0xad80, 0x000d,
+	0x2098, 0x20a9, 0x001a, 0x20a1, 0xb7c6, 0x53a3, 0x0804, 0x2faa,
+	0x080c, 0x3e75, 0x1120, 0x2009, 0x0002, 0x0804, 0x2fcf, 0x7924,
+	0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804,
+	0x2fd2, 0x2099, 0xb7c6, 0x20a0, 0x20a9, 0x001a, 0x53a3, 0x2009,
+	0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3eb9, 0x7824,
+	0xa08a, 0x1000, 0x1a04, 0x2fd2, 0x0126, 0x2091, 0x8000, 0x8003,
+	0x800b, 0x810b, 0xa108, 0x00c6, 0x2061, 0xb7f3, 0x6142, 0x00ce,
+	0x012e, 0x0804, 0x2faa, 0x00c6, 0x080c, 0x5acf, 0x1188, 0x2001,
+	0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085,
+	0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x080c, 0x1515, 0x0038,
+	0x2061, 0xb500, 0x6030, 0xc09d, 0x6032, 0x080c, 0x4b1f, 0x00ce,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061, 0xb7f3, 0x7924,
+	0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009, 0x7838, 0x606a,
+	0x783c, 0x6066, 0x7828, 0x6062, 0x782c, 0x605e, 0x2061, 0xb7a1,
+	0x2001, 0xb808, 0x600e, 0x6013, 0x0001, 0x6017, 0x0002, 0x6007,
+	0x0000, 0x6037, 0x0000, 0x00ce, 0x012e, 0x0804, 0x2faa, 0x0126,
+	0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x6044, 0xd0a4,
+	0x11b0, 0xd084, 0x0118, 0x080c, 0x4606, 0x0068, 0xd08c, 0x0118,
+	0x080c, 0x4527, 0x0040, 0xd094, 0x0118, 0x080c, 0x44f8, 0x0018,
+	0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, 0x012e, 0x0005, 0x0016,
+	0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e, 0x0ca0, 0x624c,
+	0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, 0xf0f0, 0x0130, 0x624a,
+	0x6043, 0x0090, 0x6043, 0x0010, 0x0490, 0xa294, 0xff00, 0xa296,
+	0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, 0x6240, 0xa295, 0x0100,
+	0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x4baf,
+	0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0140, 0x6042, 0x6043,
+	0x0000, 0x707b, 0x0000, 0x7097, 0x0001, 0x70bb, 0x0000, 0x70d7,
+	0x0000, 0x2009, 0xbcc0, 0x200b, 0x0000, 0x708b, 0x0000, 0x707f,
+	0x000a, 0x2009, 0x000a, 0x2011, 0x4ad5, 0x080c, 0x6a22, 0x0005,
+	0x0156, 0x2001, 0xb574, 0x2004, 0xd08c, 0x0110, 0x7053, 0xffff,
+	0x707c, 0xa005, 0x1510, 0x2011, 0x4ad5, 0x080c, 0x699c, 0x6040,
+	0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8, 0x6044,
+	0xd08c, 0x1168, 0x1f04, 0x450f, 0x6242, 0x708f, 0x0000, 0x6040,
+	0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242, 0x0030, 0x6242,
+	0x708f, 0x0000, 0x7083, 0x0000, 0x0000, 0x015e, 0x0005, 0x7080,
+	0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c, 0x1515, 0x0005,
+	0x4533, 0x4583, 0x4605, 0x00f6, 0x7083, 0x0001, 0x20e1, 0xa000,
+	0xe000, 0x20e1, 0x8700, 0x080c, 0x2470, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x2079, 0xbb00, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b,
+	0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b,
+	0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b,
+	0x0000, 0x782f, 0x0000, 0x2079, 0xbb0c, 0x207b, 0x1101, 0x7807,
+	0x0000, 0x2099, 0xb505, 0x20a1, 0xbb0e, 0x20a9, 0x0004, 0x53a3,
+	0x2079, 0xbb12, 0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xbb00,
+	0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f,
+	0x0000, 0x080c, 0x4b06, 0x00fe, 0x7087, 0x0000, 0x6043, 0x0008,
+	0x6043, 0x0000, 0x0005, 0x00d6, 0x7084, 0x7087, 0x0000, 0xa025,
+	0x0904, 0x45ed, 0x6020, 0xd0b4, 0x1904, 0x45eb, 0x7194, 0x81ff,
+	0x0904, 0x45db, 0xa486, 0x000c, 0x1904, 0x45e6, 0xa480, 0x0018,
+	0x8004, 0x20a8, 0x2011, 0xbb80, 0x2019, 0xbb00, 0x220c, 0x2304,
+	0xa106, 0x11b8, 0x8210, 0x8318, 0x1f04, 0x459e, 0x6043, 0x0004,
+	0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x7083, 0x0002,
+	0x708f, 0x0002, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22,
+	0x0490, 0x2069, 0xbb80, 0x6930, 0xa18e, 0x1101, 0x1538, 0x6834,
+	0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, 0x1118, 0x6804, 0xa005,
+	0x0190, 0x2011, 0xbb8e, 0x2019, 0xb505, 0x20a9, 0x0004, 0x220c,
+	0x2304, 0xa102, 0x0230, 0x1190, 0x8210, 0x8318, 0x1f04, 0x45cf,
+	0x0068, 0x7097, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xbb80, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008,
+	0x6043, 0x0000, 0x0010, 0x00de, 0x0005, 0x6040, 0xa085, 0x0100,
+	0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c, 0x2011, 0xb7ea,
+	0x2013, 0x0000, 0x7087, 0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056,
+	0x60a7, 0x9575, 0x080c, 0x7d71, 0x0c30, 0x0005, 0x708c, 0xa08a,
+	0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x1515, 0x0005, 0x4639,
+	0x4648, 0x4670, 0x4689, 0x46ad, 0x46d5, 0x46f9, 0x472a, 0x474e,
+	0x4776, 0x47ad, 0x47d5, 0x47f1, 0x4807, 0x4827, 0x483a, 0x4842,
+	0x4872, 0x4896, 0x48be, 0x48e2, 0x4913, 0x4950, 0x497f, 0x499b,
+	0x49da, 0x49fa, 0x4a13, 0x4a14, 0x00c6, 0x2061, 0xb500, 0x6003,
+	0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006, 0x00ce,
+	0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002, 0x708f,
+	0x0001, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22, 0x0005,
+	0x00f6, 0x7084, 0xa086, 0x0014, 0x1508, 0x6043, 0x0000, 0x6020,
+	0xd0b4, 0x11e0, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1102, 0x11a0,
+	0x7834, 0xa005, 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005,
+	0x1110, 0x70bb, 0x0001, 0x2011, 0x4adc, 0x080c, 0x699c, 0x708f,
+	0x0010, 0x080c, 0x4842, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005,
+	0x708f, 0x0003, 0x6043, 0x0004, 0x2011, 0x4adc, 0x080c, 0x699c,
+	0x080c, 0x4b97, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a,
+	0x20a3, 0x0000, 0x1f04, 0x4680, 0x60c3, 0x0014, 0x080c, 0x4b06,
+	0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc, 0x080c,
+	0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30, 0xa296,
+	0x1102, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128,
+	0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0004, 0x0029,
+	0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0005, 0x080c,
+	0x4b97, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xbb8e,
+	0x080c, 0x4be8, 0x1160, 0x7078, 0xa005, 0x1148, 0x7150, 0xa186,
+	0xffff, 0x0128, 0x080c, 0x4aa0, 0x0110, 0x080c, 0x4bc6, 0x20a9,
+	0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0014, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005,
+	0x01f0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, 0x11a8,
+	0x2079, 0xbb80, 0x7a30, 0xa296, 0x1103, 0x1178, 0x7834, 0xa005,
+	0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb,
+	0x0001, 0x708f, 0x0006, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe,
+	0x0005, 0x708f, 0x0007, 0x080c, 0x4b97, 0x20a3, 0x1104, 0x20a3,
+	0x0000, 0x3430, 0x2011, 0xbb8e, 0x080c, 0x4be8, 0x11a8, 0x7078,
+	0xa005, 0x1190, 0x7158, 0xa186, 0xffff, 0x0170, 0xa180, 0x2dc4,
+	0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4aa0, 0x0128, 0x080c,
+	0x40d6, 0x0110, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2298, 0x26a0,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c,
+	0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc,
+	0x080c, 0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30,
+	0xa296, 0x1104, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc,
+	0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0008,
+	0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0009,
+	0x080c, 0x4b97, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430, 0x080c,
+	0x4be8, 0x1150, 0x7078, 0xa005, 0x1138, 0x080c, 0x4a15, 0x1170,
+	0xa085, 0x0001, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2099, 0xbb8e,
+	0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x080c, 0x4b06, 0x0010, 0x080c, 0x462c, 0x0005, 0x00f6, 0x7084,
+	0xa005, 0x0588, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014,
+	0x1540, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1105, 0x1510, 0x7834,
+	0x2011, 0x0100, 0xa21e, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8,
+	0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x000a, 0x00b1, 0x0098,
+	0xa005, 0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110,
+	0x70bb, 0x0001, 0x708b, 0x0000, 0x708f, 0x000e, 0x080c, 0x4827,
+	0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x000b, 0x2011,
+	0xbb0e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9,
+	0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x4b97, 0x20a3, 0x1106,
+	0x20a3, 0x0000, 0x080c, 0x4be8, 0x0118, 0x2013, 0x0000, 0x0020,
+	0x7054, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6,
+	0x60c3, 0x0084, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005,
+	0x01b0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0084, 0x1168,
+	0x2079, 0xbb80, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834, 0xa005,
+	0x1120, 0x708f, 0x000c, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe,
+	0x0005, 0x708f, 0x000d, 0x080c, 0x4b97, 0x20a3, 0x1107, 0x20a3,
+	0x0000, 0x2099, 0xbb8e, 0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4b06, 0x0005, 0x00f6,
+	0x7084, 0xa005, 0x01d0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086,
+	0x0084, 0x1188, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1107, 0x1158,
+	0x7834, 0xa005, 0x1140, 0x708b, 0x0001, 0x080c, 0x4b89, 0x708f,
+	0x000e, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f,
+	0x000f, 0x7087, 0x0000, 0x608b, 0xbc85, 0x608f, 0xb5b5, 0x6043,
+	0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c,
+	0x6990, 0x0005, 0x7084, 0xa005, 0x0120, 0x2011, 0x4adc, 0x080c,
+	0x699c, 0x0005, 0x708f, 0x0011, 0x080c, 0x4be8, 0x11a0, 0x7170,
+	0x81ff, 0x0188, 0x2009, 0x0000, 0x7074, 0xa084, 0x00ff, 0x080c,
+	0x281d, 0xa186, 0x007e, 0x0138, 0xa186, 0x0080, 0x0120, 0x2011,
+	0xbb8e, 0x080c, 0x4aa0, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xbb80, 0x20a1, 0x020b, 0x7484, 0xa480, 0x0018, 0xa080, 0x0007,
+	0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, 0x080c,
+	0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01f0, 0x2011, 0x4adc,
+	0x080c, 0x699c, 0xa086, 0x0014, 0x11a8, 0x2079, 0xbb80, 0x7a30,
+	0xa296, 0x1103, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc,
+	0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb, 0x0001, 0x708f, 0x0012,
+	0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0013,
+	0x080c, 0x4ba3, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011,
+	0xbb8e, 0x080c, 0x4be8, 0x1160, 0x7078, 0xa005, 0x1148, 0x7150,
+	0xa186, 0xffff, 0x0128, 0x080c, 0x4aa0, 0x0110, 0x080c, 0x4bc6,
+	0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0014, 0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084,
+	0xa005, 0x01f0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086, 0x0014,
+	0x11a8, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834,
+	0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110,
+	0x70bb, 0x0001, 0x708f, 0x0014, 0x0029, 0x0010, 0x080c, 0x4b1f,
+	0x00fe, 0x0005, 0x708f, 0x0015, 0x080c, 0x4ba3, 0x20a3, 0x1104,
+	0x20a3, 0x0000, 0x3430, 0x2011, 0xbb8e, 0x080c, 0x4be8, 0x11a8,
+	0x7078, 0xa005, 0x1190, 0x7158, 0xa186, 0xffff, 0x0170, 0xa180,
+	0x2dc4, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x4aa0, 0x0128,
+	0x080c, 0x40d6, 0x0110, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2298,
+	0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x080c, 0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x05b8, 0x2011,
+	0x4adc, 0x080c, 0x699c, 0xa086, 0x0014, 0x1570, 0x2079, 0xbb80,
+	0x7a30, 0xa296, 0x1105, 0x1540, 0x7834, 0x2011, 0x0100, 0xa21e,
+	0x1148, 0x7a38, 0xd2fc, 0x0128, 0x70b8, 0xa005, 0x1110, 0x70bb,
+	0x0001, 0x0060, 0xa005, 0x11c0, 0x7a38, 0xd2fc, 0x0128, 0x70b8,
+	0xa005, 0x1110, 0x70bb, 0x0001, 0x708b, 0x0000, 0x7a38, 0xd2f4,
+	0x0138, 0x2001, 0xb574, 0x2004, 0xd0a4, 0x1110, 0x70d7, 0x0008,
+	0x708f, 0x0016, 0x0029, 0x0010, 0x080c, 0x4b1f, 0x00fe, 0x0005,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xbb80, 0x20a1, 0x020b,
+	0x20a9, 0x000e, 0x53a6, 0x3430, 0x2011, 0xbb8e, 0x708f, 0x0017,
+	0x080c, 0x4be8, 0x1150, 0x7078, 0xa005, 0x1138, 0x080c, 0x4a15,
+	0x1170, 0xa085, 0x0001, 0x080c, 0x2867, 0x20a9, 0x0008, 0x2099,
+	0xbb8e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x080c, 0x4b06, 0x0010, 0x080c, 0x462c, 0x0005, 0x00f6,
+	0x7084, 0xa005, 0x01b0, 0x2011, 0x4adc, 0x080c, 0x699c, 0xa086,
+	0x0084, 0x1168, 0x2079, 0xbb80, 0x7a30, 0xa296, 0x1106, 0x1138,
+	0x7834, 0xa005, 0x1120, 0x708f, 0x0018, 0x0029, 0x0010, 0x080c,
+	0x4b1f, 0x00fe, 0x0005, 0x708f, 0x0019, 0x080c, 0x4ba3, 0x20a3,
+	0x1106, 0x20a3, 0x0000, 0x3430, 0x2099, 0xbb8e, 0x2039, 0xbb0e,
+	0x27a0, 0x20a9, 0x0040, 0x53a3, 0x080c, 0x4be8, 0x11e8, 0x2728,
+	0x2514, 0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff,
+	0x8007, 0xa205, 0x202a, 0x7054, 0x2310, 0x8214, 0xa2a0, 0xbb0e,
+	0x2414, 0xa38c, 0x0001, 0x0118, 0xa294, 0xff00, 0x0018, 0xa294,
+	0x00ff, 0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c,
+	0x4b06, 0x0005, 0x00f6, 0x7084, 0xa005, 0x01d0, 0x2011, 0x4adc,
+	0x080c, 0x699c, 0xa086, 0x0084, 0x1188, 0x2079, 0xbb80, 0x7a30,
+	0xa296, 0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x708b, 0x0001,
+	0x080c, 0x4b89, 0x708f, 0x001a, 0x0029, 0x0010, 0x080c, 0x4b1f,
+	0x00fe, 0x0005, 0x708f, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x2099, 0xbb80, 0x20a1, 0x020b, 0x7484, 0xa480, 0x0018, 0xa080,
+	0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084,
+	0x080c, 0x4b06, 0x0005, 0x0005, 0x0005, 0x0086, 0x0096, 0x2029,
+	0xb553, 0x252c, 0x20a9, 0x0008, 0x2041, 0xbb0e, 0x28a0, 0x2099,
+	0xbb8e, 0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110,
+	0x2011, 0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148,
+	0xd5d4, 0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x4a2a, 0x0804,
+	0x4a98, 0x82ff, 0x1160, 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90,
+	0x0020, 0xa1a6, 0x3fff, 0x0904, 0x4a98, 0xa18d, 0xc000, 0x20a9,
+	0x0010, 0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120,
+	0xd5d4, 0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110,
+	0x8319, 0x0008, 0x8318, 0x1f04, 0x4a50, 0x04d0, 0x23a8, 0x2021,
+	0x0001, 0x8426, 0x8425, 0x1f04, 0x4a62, 0x2328, 0x8529, 0xa2be,
+	0x0007, 0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e,
+	0x27a8, 0xa5a8, 0x0010, 0x1f04, 0x4a71, 0x7552, 0xa5c8, 0x2dc4,
+	0x292d, 0xa5ac, 0x00ff, 0x7576, 0x6532, 0x6536, 0x0016, 0x2508,
+	0x080c, 0x2847, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304,
+	0xa405, 0x201a, 0x707b, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0028,
+	0xa006, 0x0018, 0xa006, 0x080c, 0x1515, 0x009e, 0x008e, 0x0005,
+	0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0218,
+	0x8420, 0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0xa39a, 0x0010,
+	0x8421, 0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319,
+	0x1de8, 0xa238, 0x2704, 0xa42c, 0x11b8, 0xa405, 0x203a, 0x7152,
+	0xa1a0, 0x2dc4, 0x242d, 0xa5ac, 0x00ff, 0x7576, 0x6532, 0x6536,
+	0x0016, 0x2508, 0x080c, 0x2847, 0x001e, 0x60e7, 0x0000, 0x65ea,
+	0x707b, 0x0001, 0xa084, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb500,
+	0x707f, 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100,
+	0x2071, 0x0140, 0x080c, 0x7d7a, 0x7004, 0xa084, 0x4000, 0x0120,
+	0x7003, 0x1000, 0x7003, 0x0000, 0x0126, 0x2091, 0x8000, 0x2071,
+	0xb523, 0x2073, 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7,
+	0x080c, 0x4baf, 0x001e, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842,
+	0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x2011, 0xb7ea, 0x2013, 0x0000, 0x7087, 0x0000, 0x012e,
+	0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x7d71,
+	0x2009, 0x07d0, 0x2011, 0x4adc, 0x080c, 0x6a22, 0x0005, 0x0016,
+	0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0003, 0x080c,
+	0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x0036,
+	0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x2009, 0x00f7, 0x080c,
+	0x4baf, 0x2061, 0xb7f3, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061,
+	0xb500, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043,
+	0x0010, 0x2009, 0x002d, 0x2011, 0x4b54, 0x080c, 0x6990, 0x012e,
+	0x00ce, 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x0100, 0x080c, 0x7d7a, 0x2071, 0x0140, 0x7004,
+	0xa084, 0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c,
+	0x5ad7, 0x01a8, 0x080c, 0x5af5, 0x1190, 0x2001, 0xb79e, 0x2003,
+	0xaaaa, 0x0016, 0x080c, 0x28eb, 0x2001, 0xb78f, 0x2102, 0x001e,
+	0x2001, 0xb79f, 0x2003, 0x0000, 0x080c, 0x5a07, 0x0030, 0x2001,
+	0x0001, 0x080c, 0x27c3, 0x080c, 0x4b1f, 0x012e, 0x000e, 0x00ee,
+	0x0005, 0x20a9, 0x0040, 0x20a1, 0xbcc0, 0x2099, 0xbb8e, 0x3304,
+	0x8007, 0x20a2, 0x9398, 0x94a0, 0x1f04, 0x4b8f, 0x0005, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x2099, 0xbb00, 0x20a1, 0x020b, 0x20a9,
+	0x000c, 0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xbb80, 0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6,
+	0x0006, 0x2061, 0x0100, 0x810f, 0x2001, 0xb531, 0x2004, 0xa005,
+	0x1138, 0x2001, 0xb515, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010,
+	0xa185, 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046,
+	0x2001, 0xb553, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009,
+	0x002a, 0x080c, 0xb0e8, 0x2001, 0xb50c, 0x200c, 0xc195, 0x2102,
+	0x2019, 0x002a, 0x2009, 0x0000, 0x080c, 0x2c6f, 0x004e, 0x001e,
+	0x0005, 0x080c, 0x4b1f, 0x708f, 0x0000, 0x7087, 0x0000, 0x0005,
+	0x0006, 0x2001, 0xb50c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005,
+	0x0006, 0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c,
+	0xa18d, 0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x0156,
+	0x20a9, 0x00ff, 0x2009, 0xb635, 0xa006, 0x200a, 0x8108, 0x1f04,
+	0x4c05, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146,
+	0x2069, 0xb552, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e,
+	0x6012, 0xa198, 0x2dc4, 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9,
+	0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98,
+	0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056,
+	0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076,
+	0x607a, 0x607e, 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096,
+	0x609a, 0x609e, 0x60ae, 0x61a2, 0x00d6, 0x60a4, 0xa06d, 0x0110,
+	0x080c, 0x160f, 0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0110, 0x080c,
+	0x160f, 0x60ab, 0x0000, 0x00de, 0xa006, 0x604a, 0x6810, 0x603a,
+	0x680c, 0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x014e, 0x013e,
+	0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, 0x6944,
+	0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, 0x4d1a, 0xa18c,
+	0xff00, 0x810f, 0xa182, 0x00ff, 0x1a04, 0x4d1f, 0x2001, 0xb50c,
+	0x2004, 0xa084, 0x0003, 0x01c0, 0x2001, 0xb50c, 0x2004, 0xd084,
+	0x1904, 0x4d02, 0xa188, 0xb635, 0x2104, 0xa065, 0x0904, 0x4d02,
+	0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4d02, 0x6000,
+	0xd0c4, 0x0904, 0x4d02, 0x0068, 0xa188, 0xb635, 0x2104, 0xa065,
+	0x0904, 0x4ce6, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904,
+	0x4ceb, 0x60a4, 0xa00d, 0x0118, 0x080c, 0x51d4, 0x05d0, 0x60a8,
+	0xa00d, 0x0188, 0x080c, 0x521f, 0x1170, 0x694c, 0xd1fc, 0x1118,
+	0x080c, 0x4ede, 0x0448, 0x080c, 0x4e8d, 0x694c, 0xd1ec, 0x1520,
+	0x080c, 0x50c6, 0x0408, 0x694c, 0xa184, 0xa000, 0x0178, 0xd1ec,
+	0x0140, 0xd1fc, 0x0118, 0x080c, 0x50d5, 0x0028, 0x080c, 0x50d5,
+	0x0028, 0xd1fc, 0x0118, 0x080c, 0x4e8d, 0x0070, 0x6050, 0xa00d,
+	0x0130, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0028, 0x2d00,
+	0x6052, 0x604e, 0x6803, 0x0000, 0x080c, 0x6caa, 0xa006, 0x012e,
+	0x0005, 0x2001, 0x0005, 0x2009, 0x0000, 0x04e8, 0x2001, 0x0028,
+	0x2009, 0x0000, 0x04c0, 0xa082, 0x0006, 0x12a0, 0x2001, 0xb535,
+	0x2004, 0xd0ac, 0x1160, 0x60a0, 0xd0bc, 0x1148, 0x6100, 0xd1fc,
+	0x0904, 0x4ca1, 0x2001, 0x0029, 0x2009, 0x1000, 0x0420, 0x2001,
+	0x0028, 0x00a8, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001,
+	0x0004, 0x0068, 0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001,
+	0x0029, 0x6100, 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0060, 0x2009,
+	0x0000, 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001,
+	0x0029, 0x2009, 0x0000, 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x6844, 0x8007, 0xa084, 0x00ff, 0x2008, 0xa182,
+	0x00ff, 0x1a04, 0x4d79, 0xa188, 0xb635, 0x2104, 0xa065, 0x01c0,
+	0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x11a8, 0x2c70, 0x080c,
+	0x85c7, 0x05e8, 0x2e00, 0x601a, 0x2d00, 0x6012, 0x600b, 0xffff,
+	0x601f, 0x000a, 0x2009, 0x0003, 0x080c, 0x864c, 0xa006, 0x0460,
+	0x2001, 0x0028, 0x0440, 0xa082, 0x0006, 0x1298, 0x2001, 0xb535,
+	0x2004, 0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc,
+	0x09e8, 0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028,
+	0x0090, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004,
+	0x0050, 0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, 0x0029,
+	0x0010, 0x2001, 0x0029, 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001,
+	0x002c, 0x0cc8, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2011,
+	0x0000, 0x2079, 0xb500, 0x6944, 0xa18c, 0xff00, 0x810f, 0xa182,
+	0x00ff, 0x1a04, 0x4e44, 0x080c, 0x4fa9, 0x11a0, 0x6004, 0xa084,
+	0x00ff, 0xa082, 0x0006, 0x1270, 0x6864, 0xa0c6, 0x006f, 0x0150,
+	0x2001, 0xb535, 0x2004, 0xd0ac, 0x1904, 0x4e2d, 0x60a0, 0xd0bc,
+	0x1904, 0x4e2d, 0x6864, 0xa0c6, 0x006f, 0x0118, 0x2008, 0x0804,
+	0x4df6, 0x6968, 0x2140, 0xa18c, 0xff00, 0x810f, 0x78d4, 0xd0ac,
+	0x1118, 0xa182, 0x0080, 0x06d0, 0xa182, 0x00ff, 0x16b8, 0x6a70,
+	0x6b6c, 0x7870, 0xa306, 0x1160, 0x7874, 0xa24e, 0x1118, 0x2208,
+	0x2310, 0x0460, 0xa9cc, 0xff00, 0x1118, 0x2208, 0x2310, 0x0430,
+	0x080c, 0x3dc5, 0x2c70, 0x0550, 0x2009, 0x0000, 0x2011, 0x0000,
+	0xa0c6, 0x4000, 0x1160, 0x0006, 0x2e60, 0x080c, 0x524a, 0x1108,
+	0xc185, 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x0088, 0xa0c6,
+	0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118, 0x2708,
+	0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001, 0x4006,
+	0x6866, 0x696a, 0x6a6e, 0x2001, 0x0030, 0x0450, 0x080c, 0x85c7,
+	0x1138, 0x2001, 0x4005, 0x2009, 0x0003, 0x2011, 0x0000, 0x0c80,
+	0x2e00, 0x601a, 0x080c, 0xa027, 0x2d00, 0x6012, 0x601f, 0x0001,
+	0x6838, 0xd88c, 0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x2c9c, 0x012e, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001,
+	0x0002, 0x080c, 0x4efd, 0x2009, 0x0002, 0x080c, 0x864c, 0xa006,
+	0xa005, 0x012e, 0x00ee, 0x00fe, 0x0005, 0x2001, 0x0028, 0x2009,
+	0x0000, 0x0cb0, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x0118, 0x2001,
+	0x0004, 0x0038, 0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001,
+	0x0029, 0x2009, 0x0000, 0x0c20, 0x2001, 0x0029, 0x2009, 0x0000,
+	0x08f8, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082, 0x4000, 0x16b8,
+	0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff, 0x12e0, 0xa188, 0xb635,
+	0x2104, 0xa065, 0x01b8, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006,
+	0x11b0, 0x684c, 0xd0ec, 0x0120, 0x080c, 0x50d5, 0x0431, 0x0030,
+	0x0421, 0x684c, 0xd0fc, 0x0110, 0x080c, 0x50c6, 0x080c, 0x5113,
+	0xa006, 0x00c8, 0x2001, 0x0028, 0x2009, 0x0000, 0x00a0, 0xa082,
+	0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d20, 0x2001, 0x0029, 0x2009,
+	0x1000, 0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001,
+	0x0029, 0x2009, 0x0000, 0xa005, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x6050, 0xa00d, 0x0138, 0x2d00, 0x200a, 0x6803, 0x0000, 0x6052,
+	0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0,
+	0x0126, 0x2091, 0x8000, 0x604c, 0xa005, 0x0170, 0x00e6, 0x2071,
+	0xb7e0, 0x7004, 0xa086, 0x0002, 0x0168, 0x00ee, 0x604c, 0x6802,
+	0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e, 0x6803,
+	0x0000, 0x0cc0, 0x701c, 0xac06, 0x1d80, 0x604c, 0x2070, 0x7000,
+	0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x604c, 0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052,
+	0x604e, 0xad05, 0x012e, 0x0005, 0x604c, 0xa06d, 0x0130, 0x6800,
+	0xa005, 0x1108, 0x6052, 0x604e, 0xad05, 0x0005, 0x6803, 0x0000,
+	0x6084, 0xa00d, 0x0120, 0x2d00, 0x200a, 0x6086, 0x0005, 0x2d00,
+	0x6086, 0x6082, 0x0cd8, 0x0126, 0x00c6, 0x0026, 0x2091, 0x8000,
+	0x6218, 0x2260, 0x6200, 0xa005, 0x0110, 0xc285, 0x0008, 0xc284,
+	0x6202, 0x002e, 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091,
+	0x8000, 0x6218, 0x2260, 0x6204, 0x0006, 0xa086, 0x0006, 0x1180,
+	0x609c, 0xd0ac, 0x0168, 0x2001, 0xb553, 0x2004, 0xd0a4, 0x0140,
+	0xa284, 0xff00, 0x8007, 0xa086, 0x0007, 0x1110, 0x2011, 0x0600,
+	0x000e, 0xa294, 0xff00, 0xa215, 0x6206, 0x0006, 0xa086, 0x0006,
+	0x1128, 0x6290, 0x82ff, 0x1110, 0x080c, 0x1515, 0x000e, 0x00ce,
+	0x012e, 0x0005, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260,
+	0x6204, 0x0006, 0xa086, 0x0006, 0x1178, 0x609c, 0xd0a4, 0x0160,
+	0x2001, 0xb553, 0x2004, 0xd0ac, 0x1138, 0xa284, 0x00ff, 0xa086,
+	0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0xa294, 0x00ff, 0x8007,
+	0xa215, 0x6206, 0x00ce, 0x012e, 0x0005, 0x0026, 0xa182, 0x00ff,
+	0x0218, 0xa085, 0x0001, 0x00b0, 0xa190, 0xb635, 0x2204, 0xa065,
+	0x1180, 0x0016, 0x00d6, 0x080c, 0x15df, 0x2d60, 0x00de, 0x001e,
+	0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x080c,
+	0x4c0b, 0xa006, 0x002e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0026,
+	0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0480, 0x00d6, 0xa190,
+	0xb635, 0x2204, 0xa06d, 0x0540, 0x2013, 0x0000, 0x00d6, 0x00c6,
+	0x2d60, 0x60a4, 0xa06d, 0x0110, 0x080c, 0x160f, 0x60a8, 0xa06d,
+	0x0110, 0x080c, 0x160f, 0x00ce, 0x00de, 0x00d6, 0x00c6, 0x68ac,
+	0x2060, 0x8cff, 0x0168, 0x600c, 0x0006, 0x6010, 0x2068, 0x080c,
+	0x9c5a, 0x0110, 0x080c, 0x161f, 0x080c, 0x861d, 0x00ce, 0x0c88,
+	0x00ce, 0x00de, 0x080c, 0x160f, 0x00de, 0xa006, 0x002e, 0x012e,
+	0x0005, 0x0016, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x0030,
+	0xa188, 0xb635, 0x2104, 0xa065, 0x0dc0, 0xa006, 0x001e, 0x0005,
+	0x00d6, 0x0156, 0x0136, 0x0146, 0x600b, 0x0000, 0x600f, 0x0000,
+	0x6000, 0xc08c, 0x6002, 0x080c, 0x5acf, 0x1558, 0x60a0, 0xa086,
+	0x007e, 0x2069, 0xbb90, 0x0130, 0x2001, 0xb535, 0x2004, 0xd0ac,
+	0x1500, 0x0098, 0x2d04, 0xd0e4, 0x01e0, 0x00d6, 0x2069, 0xbb8e,
+	0x00c6, 0x2061, 0xb7b2, 0x6810, 0x2062, 0x6814, 0x6006, 0x6818,
+	0x600a, 0x681c, 0x600e, 0x00ce, 0x00de, 0x8d69, 0x2d04, 0x2069,
+	0x0140, 0xa005, 0x1110, 0x2001, 0x0001, 0x6886, 0x2069, 0xb500,
+	0x68a6, 0x2069, 0xbb8e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138,
+	0xa10a, 0x0208, 0x603a, 0x6814, 0x6066, 0x2099, 0xbb96, 0xac88,
+	0x000a, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xbb9a, 0xac88,
+	0x0006, 0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xbbae, 0x6808,
+	0x606a, 0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0x60a0,
+	0xa086, 0x007e, 0x1120, 0x2069, 0xbb8e, 0x690c, 0x616e, 0xa182,
+	0x0211, 0x1218, 0x2009, 0x0008, 0x0400, 0xa182, 0x0259, 0x1218,
+	0x2009, 0x0007, 0x00d0, 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006,
+	0x00a0, 0xa182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0xa182,
+	0x0421, 0x1218, 0x2009, 0x0004, 0x0040, 0xa182, 0x0581, 0x1218,
+	0x2009, 0x0003, 0x0010, 0x2009, 0x0002, 0x6192, 0x014e, 0x013e,
+	0x015e, 0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0xbb8d,
+	0x2e04, 0x6896, 0x2071, 0xbb8e, 0x7004, 0x689a, 0x701c, 0x689e,
+	0x6a00, 0x2009, 0xb572, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110,
+	0xc2ad, 0x0008, 0xc2ac, 0xd0c4, 0x0120, 0xd1e4, 0x0110, 0xc2bd,
+	0x0008, 0xc2bc, 0x6a02, 0x00ee, 0x002e, 0x001e, 0x0005, 0x00d6,
+	0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff,
+	0x1540, 0x6a04, 0xa282, 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9,
+	0x0010, 0x2104, 0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x5081,
+	0x080c, 0x1515, 0x260a, 0x8210, 0x6a06, 0x0098, 0x080c, 0x15f8,
+	0x01a8, 0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9,
+	0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x5099, 0x6807, 0x0001,
+	0x6e12, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8,
+	0x0126, 0x2091, 0x8000, 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168,
+	0x6800, 0xa005, 0x1160, 0x080c, 0x51d4, 0x1168, 0x200b, 0xffff,
+	0x6804, 0xa08a, 0x0002, 0x0218, 0x8001, 0x6806, 0x0020, 0x080c,
+	0x160f, 0x60a7, 0x0000, 0x00de, 0x012e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x5232, 0x0010, 0x080c, 0x4e8d, 0x080c, 0x514c,
+	0x1dd8, 0x080c, 0x5113, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x60a8, 0xa06d, 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54,
+	0xa282, 0x0010, 0x1670, 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104,
+	0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x50e7, 0x080c, 0x1515,
+	0x260a, 0x8210, 0x6a56, 0x0098, 0x080c, 0x15f8, 0x01d0, 0x2d00,
+	0x60aa, 0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b,
+	0xffff, 0x8108, 0x1f04, 0x50ff, 0x6857, 0x0001, 0x6e62, 0x0010,
+	0x080c, 0x4ede, 0x0089, 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de,
+	0x0005, 0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6caa,
+	0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126,
+	0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff,
+	0x01f8, 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c,
+	0xa406, 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068,
+	0x0c70, 0x080c, 0x811e, 0x6a00, 0x604c, 0xad06, 0x1110, 0x624e,
+	0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, 0x6152, 0x8dff,
+	0x012e, 0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x6080,
+	0x2068, 0x8dff, 0x01e8, 0x83ff, 0x0120, 0x6848, 0xa606, 0x0158,
+	0x0030, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0120, 0x2d08,
+	0x6800, 0x2068, 0x0c70, 0x6a00, 0x6080, 0xad06, 0x1110, 0x6282,
+	0x0018, 0xa180, 0x0000, 0x2202, 0x82ff, 0x1110, 0x6186, 0x8dff,
+	0x0005, 0xa016, 0x080c, 0x51ce, 0x1110, 0x2011, 0x0001, 0x080c,
+	0x5219, 0x1110, 0xa295, 0x0002, 0x0005, 0x080c, 0x524a, 0x0118,
+	0x080c, 0x9d0f, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x524a,
+	0x0118, 0x080c, 0x9c9f, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c,
+	0x524a, 0x0118, 0x080c, 0x9cf2, 0x0010, 0xa085, 0x0001, 0x0005,
+	0x080c, 0x524a, 0x0118, 0x080c, 0x9cbb, 0x0010, 0xa085, 0x0001,
+	0x0005, 0x080c, 0x524a, 0x0118, 0x080c, 0x9d2b, 0x0010, 0xa085,
+	0x0001, 0x0005, 0x0126, 0x0006, 0x00d6, 0x2091, 0x8000, 0x6080,
+	0xa06d, 0x01a0, 0x6800, 0x0006, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x080c, 0x9ecc, 0x0006, 0x6000, 0xd0fc, 0x0110, 0x080c,
+	0xb389, 0x000e, 0x080c, 0x5408, 0x000e, 0x0c50, 0x6083, 0x0000,
+	0x6087, 0x0000, 0x00de, 0x000e, 0x012e, 0x0005, 0x60a4, 0xa00d,
+	0x1118, 0xa085, 0x0001, 0x0005, 0x00e6, 0x2170, 0x7000, 0xa005,
+	0x1168, 0x20a9, 0x0010, 0xae88, 0x0004, 0x2104, 0xa606, 0x0130,
+	0x8108, 0x1f04, 0x51dd, 0xa085, 0x0001, 0x0008, 0xa006, 0x00ee,
+	0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x1128,
+	0x080c, 0x15f8, 0x01a0, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807,
+	0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108,
+	0x1f04, 0x51fd, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006,
+	0x0cd8, 0x00d6, 0x0126, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x0130,
+	0x60a7, 0x0000, 0x080c, 0x160f, 0xa085, 0x0001, 0x012e, 0x00de,
+	0x0005, 0x60a8, 0xa00d, 0x1118, 0xa085, 0x0001, 0x0005, 0x00e6,
+	0x2170, 0x7050, 0xa005, 0x1160, 0x20a9, 0x0010, 0xae88, 0x0018,
+	0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x5228, 0xa085, 0x0001,
+	0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x0c19, 0x1188, 0x200b,
+	0xffff, 0x00d6, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0218,
+	0x8001, 0x6856, 0x0020, 0x080c, 0x160f, 0x60ab, 0x0000, 0x00de,
+	0x012e, 0x0005, 0x609c, 0xd0a4, 0x0005, 0x00f6, 0x080c, 0x5acf,
+	0x01b0, 0x71b8, 0x81ff, 0x1198, 0x71d4, 0xd19c, 0x0180, 0x2001,
+	0x007e, 0xa080, 0xb635, 0x2004, 0xa07d, 0x0148, 0x7804, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x1118, 0x7800, 0xc0ed, 0x7802, 0x2079,
+	0xb552, 0x7804, 0xd0a4, 0x01e8, 0x0156, 0x00c6, 0x20a9, 0x007f,
+	0x2009, 0x0000, 0x0016, 0x080c, 0x4fa9, 0x1168, 0x6004, 0xa084,
+	0xff00, 0x8007, 0xa096, 0x0004, 0x0118, 0xa086, 0x0006, 0x1118,
+	0x6000, 0xc0ed, 0x6002, 0x001e, 0x8108, 0x1f04, 0x5272, 0x00ce,
+	0x015e, 0x080c, 0x5309, 0x0120, 0x2001, 0xb7b5, 0x200c, 0x0038,
+	0x2079, 0xb552, 0x7804, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011,
+	0x529d, 0x080c, 0x6a22, 0x00fe, 0x0005, 0x2011, 0x529d, 0x080c,
+	0x699c, 0x080c, 0x5309, 0x01f0, 0x2001, 0xb6b3, 0x2004, 0xa080,
+	0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xb553, 0x2004, 0xd0a4,
+	0x0130, 0x2009, 0x07d0, 0x2011, 0x529d, 0x080c, 0x6a22, 0x00e6,
+	0x2071, 0xb500, 0x7073, 0x0000, 0x7077, 0x0000, 0x080c, 0x2ab8,
+	0x00ee, 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x0016, 0x080c, 0x4fa9, 0x1530, 0x6000, 0xd0ec, 0x0518, 0x0046,
+	0x62a0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x080c,
+	0xb0e8, 0x6000, 0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff,
+	0xa085, 0x0700, 0x6006, 0x2019, 0x0029, 0x080c, 0x6df5, 0x0076,
+	0x2039, 0x0000, 0x080c, 0x6d02, 0x2009, 0x0000, 0x080c, 0xae82,
+	0x007e, 0x004e, 0x001e, 0x8108, 0x1f04, 0x52c8, 0x00ce, 0x015e,
+	0x0005, 0x00c6, 0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x00ce,
+	0x0005, 0x7818, 0x2004, 0xd0ac, 0x0005, 0x7818, 0x2004, 0xd0bc,
+	0x0005, 0x00f6, 0x2001, 0xb6b3, 0x2004, 0xa07d, 0x0110, 0x7800,
+	0xd0ec, 0x00fe, 0x0005, 0x0126, 0x0026, 0x2091, 0x8000, 0x0006,
+	0x62a0, 0xa290, 0xb635, 0x2204, 0xac06, 0x190c, 0x1515, 0x000e,
+	0x6200, 0xa005, 0x0110, 0xc2fd, 0x0008, 0xc2fc, 0x6202, 0x002e,
+	0x012e, 0x0005, 0x2011, 0xb535, 0x2204, 0xd0cc, 0x0138, 0x2001,
+	0xb7b3, 0x200c, 0x2011, 0x5337, 0x080c, 0x6a22, 0x0005, 0x2011,
+	0x5337, 0x080c, 0x699c, 0x2011, 0xb535, 0x2204, 0xc0cc, 0x2012,
+	0x0005, 0x2071, 0xb614, 0x7003, 0x0001, 0x7007, 0x0000, 0x7013,
+	0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000, 0x700b,
+	0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020, 0x705f,
+	0x0040, 0x707f, 0x0000, 0x2071, 0xb77d, 0x7003, 0xb614, 0x7007,
+	0x0000, 0x700b, 0x0000, 0x700f, 0xb75d, 0x7013, 0x0020, 0x7017,
+	0x0040, 0x7037, 0x0000, 0x0005, 0x0016, 0x00e6, 0x2071, 0xb735,
+	0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xb553, 0x2004,
+	0xd0fc, 0x1150, 0x2001, 0xb553, 0x2004, 0xa00e, 0xd09c, 0x0108,
+	0x8108, 0x7102, 0x0804, 0x53d2, 0x2001, 0xb572, 0x200c, 0xa184,
+	0x000f, 0x2009, 0xb573, 0x210c, 0x0002, 0x537a, 0x53ad, 0x53b4,
+	0x53be, 0x53c3, 0x537a, 0x537a, 0x537a, 0x539d, 0x537a, 0x537a,
+	0x537a, 0x537a, 0x537a, 0x537a, 0x537a, 0x7003, 0x0004, 0x0136,
+	0x0146, 0x0156, 0x2099, 0xb576, 0x20a1, 0xb786, 0x20a9, 0x0004,
+	0x53a3, 0x015e, 0x014e, 0x013e, 0x0428, 0x708f, 0x0005, 0x7007,
+	0x0122, 0x2001, 0x0002, 0x0030, 0x708f, 0x0002, 0x7007, 0x0121,
+	0x2001, 0x0003, 0x7002, 0x7097, 0x0001, 0x0088, 0x7007, 0x0122,
+	0x2001, 0x0002, 0x0020, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002,
+	0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, 0xa184,
+	0x00ff, 0x7092, 0x00ee, 0x001e, 0x0005, 0x00e6, 0x2071, 0xb614,
+	0x684c, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001,
+	0x0428, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868, 0x703e, 0x7076,
+	0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844, 0x7032, 0x2009,
+	0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006, 0x8006, 0xa08c,
+	0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x726e, 0x7372,
+	0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006, 0x00ee, 0x0005,
+	0x0156, 0x00e6, 0x0026, 0x6838, 0xd0fc, 0x1904, 0x5461, 0x6804,
+	0xa00d, 0x0188, 0x00d6, 0x2071, 0xb500, 0xa016, 0x702c, 0x2168,
+	0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x1dc8, 0x702e, 0x70b4,
+	0xa200, 0x70b6, 0x00de, 0x2071, 0xb614, 0x701c, 0xa005, 0x1904,
+	0x5471, 0x20a9, 0x0032, 0x0f04, 0x546f, 0x0e04, 0x542b, 0x2071,
+	0xb735, 0x7200, 0x82ff, 0x05d8, 0x6934, 0xa186, 0x0103, 0x1904,
+	0x547f, 0x6948, 0x6844, 0xa105, 0x1540, 0x2009, 0x8020, 0x2200,
+	0x0002, 0x546f, 0x5446, 0x5497, 0x54a3, 0x546f, 0x2071, 0x0000,
+	0x20a9, 0x0032, 0x0f04, 0x546f, 0x7018, 0xd084, 0x1dd8, 0x7122,
+	0x683c, 0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x2071, 0xb500, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70b4, 0x8000,
+	0x70b6, 0x002e, 0x00ee, 0x015e, 0x0005, 0x6844, 0xa086, 0x0100,
+	0x1130, 0x6868, 0xa005, 0x1118, 0x2009, 0x8020, 0x0880, 0x2071,
+	0xb614, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012, 0x7018,
+	0xa06d, 0x711a, 0x0110, 0x6902, 0x0008, 0x711e, 0x0c10, 0xa18c,
+	0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e, 0x0118, 0xa18e,
+	0x001f, 0x1d28, 0x684c, 0xd0cc, 0x0d10, 0x6850, 0xa084, 0x00ff,
+	0xa086, 0x0001, 0x19e0, 0x2009, 0x8021, 0x0804, 0x543f, 0x7084,
+	0x8008, 0xa092, 0x001e, 0x1a98, 0x7186, 0xae90, 0x0003, 0xa210,
+	0x683c, 0x2012, 0x0078, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a38,
+	0x7186, 0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210,
+	0x6840, 0x2012, 0x7088, 0xa10a, 0x0a04, 0x5458, 0x718c, 0x7084,
+	0xa10a, 0x0a04, 0x5458, 0x2071, 0x0000, 0x7018, 0xd084, 0x1904,
+	0x5458, 0x2071, 0xb735, 0x7000, 0xa086, 0x0002, 0x1150, 0x080c,
+	0x5722, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804,
+	0x5458, 0x080c, 0x574c, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091,
+	0x4080, 0x0804, 0x5458, 0x0006, 0x684c, 0x0006, 0x6837, 0x0103,
+	0x20a9, 0x001c, 0xad80, 0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4,
+	0x000e, 0xa084, 0x00ff, 0x684e, 0x000e, 0x684a, 0x6952, 0x0005,
+	0x2071, 0xb614, 0x7004, 0x0002, 0x54fe, 0x550f, 0x570d, 0x570e,
+	0x571b, 0x5721, 0x54ff, 0x56fe, 0x5694, 0x56ea, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x0e04, 0x550e, 0x2009, 0x000d, 0x7030, 0x200a,
+	0x2091, 0x4080, 0x7007, 0x0001, 0x700b, 0x0000, 0x012e, 0x2069,
+	0xb7f3, 0x683c, 0xa005, 0x03f8, 0x11f0, 0x0126, 0x2091, 0x8000,
+	0x2069, 0x0000, 0x6934, 0x2001, 0xb620, 0x2004, 0xa10a, 0x0170,
+	0x0e04, 0x5532, 0x2069, 0x0000, 0x6818, 0xd084, 0x1158, 0x2009,
+	0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x2069, 0xb7f3,
+	0x683f, 0xffff, 0x012e, 0x2069, 0xb500, 0x6848, 0x6968, 0xa102,
+	0x2069, 0xb735, 0x688a, 0x6984, 0x701c, 0xa06d, 0x0120, 0x81ff,
+	0x0904, 0x5588, 0x00a0, 0x81ff, 0x0904, 0x564e, 0x2071, 0xb735,
+	0x7184, 0x7088, 0xa10a, 0x1258, 0x7190, 0x2071, 0xb7f3, 0x7038,
+	0xa005, 0x0128, 0x1b04, 0x564e, 0x713a, 0x0804, 0x564e, 0x2071,
+	0xb735, 0x718c, 0x0126, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0a04,
+	0x5669, 0x0e04, 0x560a, 0x2071, 0x0000, 0x7018, 0xd084, 0x1904,
+	0x560a, 0x2001, 0xffff, 0x2071, 0xb7f3, 0x703a, 0x2071, 0xb735,
+	0x7000, 0xa086, 0x0002, 0x1150, 0x080c, 0x5722, 0x2071, 0x0000,
+	0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x560a, 0x080c, 0x574c,
+	0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x560a,
+	0x2071, 0xb735, 0x7000, 0xa005, 0x0904, 0x5630, 0x6934, 0xa186,
+	0x0103, 0x1904, 0x560d, 0x684c, 0xd0bc, 0x1904, 0x5630, 0x6948,
+	0x6844, 0xa105, 0x1904, 0x5625, 0x2009, 0x8020, 0x2071, 0xb735,
+	0x7000, 0x0002, 0x5630, 0x55f0, 0x55c8, 0x55da, 0x55a7, 0x0136,
+	0x0146, 0x0156, 0x2099, 0xb576, 0x20a1, 0xb786, 0x20a9, 0x0004,
+	0x53a3, 0x015e, 0x014e, 0x013e, 0x2071, 0xb77d, 0xad80, 0x000f,
+	0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10,
+	0x080c, 0x1643, 0x2071, 0xb614, 0x7007, 0x0009, 0x0804, 0x564e,
+	0x7084, 0x8008, 0xa092, 0x001e, 0x1a04, 0x564e, 0xae90, 0x0003,
+	0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xb614, 0x080c, 0x57a3,
+	0x0804, 0x564e, 0x7084, 0x8008, 0xa092, 0x000f, 0x1a04, 0x564e,
+	0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840,
+	0x2012, 0x7186, 0x2071, 0xb614, 0x080c, 0x57a3, 0x0804, 0x564e,
+	0x0126, 0x2091, 0x8000, 0x0e04, 0x560a, 0x2071, 0x0000, 0x7018,
+	0xd084, 0x1180, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a, 0x701b,
+	0x0001, 0x2091, 0x4080, 0x012e, 0x2071, 0xb614, 0x080c, 0x57a3,
+	0x0804, 0x564e, 0x012e, 0x0804, 0x564e, 0xa18c, 0x00ff, 0xa186,
+	0x0017, 0x0130, 0xa186, 0x001e, 0x0118, 0xa18e, 0x001f, 0x11c0,
+	0x684c, 0xd0cc, 0x01a8, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001,
+	0x1178, 0x2009, 0x8021, 0x0804, 0x559e, 0x6844, 0xa086, 0x0100,
+	0x1138, 0x6868, 0xa005, 0x1120, 0x2009, 0x8020, 0x0804, 0x559e,
+	0x2071, 0xb614, 0x080c, 0x57b5, 0x01c8, 0x2071, 0xb614, 0x700f,
+	0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x1130, 0x810f,
+	0xa18c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x7007, 0x0003, 0x080c,
+	0x57ce, 0x7050, 0xa086, 0x0100, 0x0904, 0x570e, 0x0126, 0x2091,
+	0x8000, 0x2071, 0xb614, 0x7008, 0xa086, 0x0001, 0x1180, 0x0e04,
+	0x5667, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x700b,
+	0x0000, 0x7004, 0xa086, 0x0006, 0x1110, 0x7007, 0x0001, 0x012e,
+	0x0005, 0x2071, 0xb614, 0x080c, 0x57b5, 0x0518, 0x2071, 0xb735,
+	0x7084, 0x700a, 0x20a9, 0x0020, 0x2099, 0xb736, 0x20a1, 0xb75d,
+	0x53a3, 0x7087, 0x0000, 0x2071, 0xb614, 0x2069, 0xb77d, 0x706c,
+	0x6826, 0x7070, 0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10,
+	0x080c, 0x1643, 0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xb7f3,
+	0x703a, 0x012e, 0x0804, 0x564e, 0x2069, 0xb77d, 0x6808, 0xa08e,
+	0x0000, 0x0904, 0x56e9, 0xa08e, 0x0200, 0x0904, 0x56e7, 0xa08e,
+	0x0100, 0x1904, 0x56e9, 0x0126, 0x2091, 0x8000, 0x0e04, 0x56e5,
+	0x2069, 0x0000, 0x6818, 0xd084, 0x15c0, 0x702c, 0x7130, 0x8108,
+	0xa102, 0x0230, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048,
+	0x706c, 0xa080, 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000,
+	0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001, 0xb75a, 0x2004,
+	0xa005, 0x1190, 0x6934, 0x2069, 0xb735, 0x689c, 0x699e, 0x2069,
+	0xb7f3, 0xa102, 0x1118, 0x683c, 0xa005, 0x1368, 0x2001, 0xb75b,
+	0x200c, 0x810d, 0x693e, 0x0038, 0x2009, 0x8040, 0x6922, 0x681b,
+	0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x012e, 0x0010, 0x7007,
+	0x0005, 0x0005, 0x2001, 0xb77f, 0x2004, 0xa08e, 0x0100, 0x1128,
+	0x7007, 0x0001, 0x080c, 0x57a3, 0x0005, 0xa08e, 0x0000, 0x0de0,
+	0xa08e, 0x0200, 0x1dc8, 0x7007, 0x0005, 0x0005, 0x701c, 0xa06d,
+	0x0158, 0x080c, 0x57b5, 0x0140, 0x7007, 0x0003, 0x080c, 0x57ce,
+	0x7050, 0xa086, 0x0100, 0x0110, 0x0005, 0x0005, 0x7050, 0xa09e,
+	0x0100, 0x1118, 0x7007, 0x0004, 0x0030, 0xa086, 0x0200, 0x1110,
+	0x7007, 0x0005, 0x0005, 0x080c, 0x5771, 0x7006, 0x080c, 0x57a3,
+	0x0005, 0x0005, 0x00e6, 0x0156, 0x2071, 0xb735, 0x7184, 0x81ff,
+	0x0500, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8,
+	0x2014, 0x7226, 0x8000, 0x0f04, 0x5746, 0x2014, 0x722a, 0x8000,
+	0x0f04, 0x5746, 0x2014, 0x722e, 0x8000, 0x0f04, 0x5746, 0x2014,
+	0x723a, 0x8000, 0x0f04, 0x5746, 0x2014, 0x723e, 0xa180, 0x8030,
+	0x7022, 0x015e, 0x00ee, 0x0005, 0x00e6, 0x0156, 0x2071, 0xb735,
+	0x7184, 0x81ff, 0x01d8, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071,
+	0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014, 0x722a, 0x8000,
+	0x0f04, 0x5768, 0x2014, 0x723a, 0x8000, 0x2014, 0x723e, 0x0018,
+	0x2001, 0x8020, 0x0010, 0x2001, 0x8042, 0x7022, 0x015e, 0x00ee,
+	0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034,
+	0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e,
+	0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001,
+	0x700e, 0x1180, 0x0126, 0x2091, 0x8000, 0x0e04, 0x579d, 0x2001,
+	0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, 0x0000,
+	0x012e, 0x0005, 0x2001, 0x0007, 0x0005, 0x2001, 0x0006, 0x700b,
+	0x0001, 0x012e, 0x0005, 0x701c, 0xa06d, 0x0170, 0x0126, 0x2091,
+	0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005, 0x1108,
+	0x701a, 0x012e, 0x080c, 0x160f, 0x0005, 0x2019, 0x000d, 0x2304,
+	0x230c, 0xa10e, 0x0130, 0x2304, 0x230c, 0xa10e, 0x0110, 0xa006,
+	0x0060, 0x732c, 0x8319, 0x7130, 0xa102, 0x1118, 0x2300, 0xa005,
+	0x0020, 0x0210, 0xa302, 0x0008, 0x8002, 0x0005, 0x2d00, 0x7026,
+	0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x0126, 0x2091, 0x8000,
+	0x2009, 0xb812, 0x2104, 0xc08d, 0x200a, 0x012e, 0x080c, 0x165f,
+	0x0005, 0x708c, 0xa08a, 0x0029, 0x1220, 0xa082, 0x001d, 0x0033,
+	0x0010, 0x080c, 0x1515, 0x6027, 0x1e00, 0x0005, 0x58dc, 0x5857,
+	0x586f, 0x58ac, 0x58cd, 0x5907, 0x5919, 0x586f, 0x58f3, 0x57fb,
+	0x5829, 0x57fa, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0xa005,
+	0x1180, 0x6808, 0xa005, 0x1518, 0x708f, 0x0028, 0x2069, 0xb7c5,
+	0x2d04, 0x7002, 0x080c, 0x5bd1, 0x6028, 0xa085, 0x0600, 0x602a,
+	0x00b0, 0x708f, 0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002, 0x6028,
+	0xa085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071,
+	0xb823, 0x080c, 0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de,
+	0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0xa005, 0x1180, 0x6808,
+	0xa005, 0x1518, 0x708f, 0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002,
+	0x080c, 0x5c5e, 0x6028, 0xa085, 0x0600, 0x602a, 0x00b0, 0x708f,
+	0x0028, 0x2069, 0xb7c5, 0x2d04, 0x7002, 0x6028, 0xa085, 0x0600,
+	0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xb823, 0x080c,
+	0x1dfe, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, 0x6803,
+	0x0090, 0x6124, 0xd1e4, 0x1190, 0x080c, 0x5984, 0xd1d4, 0x1160,
+	0xd1dc, 0x1138, 0xd1cc, 0x0150, 0x708f, 0x0020, 0x080c, 0x5984,
+	0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x001f, 0x0005, 0x6803,
+	0x0088, 0x6124, 0xd1cc, 0x1590, 0xd1dc, 0x1568, 0xd1e4, 0x1540,
+	0xa184, 0x1e00, 0x1580, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e,
+	0x080c, 0x5aff, 0x080c, 0x24b0, 0x0156, 0x6803, 0x0100, 0x20a9,
+	0x0014, 0x6804, 0xd0dc, 0x1118, 0x1f04, 0x5889, 0x0048, 0x20a9,
+	0x0014, 0x6803, 0x0080, 0x6804, 0xd0d4, 0x1130, 0x1f04, 0x5893,
+	0x080c, 0x5b20, 0x015e, 0x0078, 0x015e, 0x708f, 0x0028, 0x0058,
+	0x708f, 0x001e, 0x0040, 0x708f, 0x001d, 0x0028, 0x708f, 0x0020,
+	0x0010, 0x708f, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c, 0xc0b4,
+	0x600e, 0x080c, 0x5aff, 0x080c, 0x24b0, 0x6803, 0x0080, 0x6124,
+	0xd1d4, 0x1180, 0xd1dc, 0x1158, 0xd1e4, 0x1130, 0xa184, 0x1e00,
+	0x1158, 0x708f, 0x0028, 0x0040, 0x708f, 0x001e, 0x0028, 0x708f,
+	0x001d, 0x0010, 0x708f, 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124,
+	0xd1dc, 0x1138, 0xd1e4, 0x0138, 0x080c, 0x1e47, 0x708f, 0x001e,
+	0x0010, 0x708f, 0x001d, 0x0005, 0x080c, 0x59f6, 0x6124, 0xd1dc,
+	0x1188, 0x080c, 0x5984, 0x0016, 0x080c, 0x1e47, 0x001e, 0xd1d4,
+	0x1128, 0xd1e4, 0x0138, 0x708f, 0x001e, 0x0020, 0x708f, 0x001f,
+	0x080c, 0x5984, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1d4, 0x1160,
+	0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708f, 0x001e,
+	0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x0021, 0x0005, 0x080c,
+	0x59f6, 0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140,
+	0x708f, 0x001e, 0x0028, 0x708f, 0x001d, 0x0010, 0x708f, 0x001f,
+	0x0005, 0x6803, 0x0090, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150,
+	0xd1dc, 0x1128, 0xd1e4, 0x0158, 0x708f, 0x001e, 0x0040, 0x708f,
+	0x001d, 0x0028, 0x708f, 0x0020, 0x0010, 0x708f, 0x001f, 0x0005,
+	0x0016, 0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x2071, 0xb500, 0x2091, 0x8000, 0x080c, 0x5acf, 0x11e8,
+	0x2001, 0xb50c, 0x200c, 0xd1b4, 0x01c0, 0xc1b4, 0x2102, 0x6027,
+	0x0200, 0xe000, 0xe000, 0x6024, 0xd0cc, 0x0158, 0x6803, 0x00a0,
+	0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001,
+	0x0428, 0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x5aeb, 0x0150,
+	0x080c, 0x5ae1, 0x1138, 0x2001, 0x0001, 0x080c, 0x27c3, 0x080c,
+	0x5aa6, 0x00a0, 0x080c, 0x59f3, 0x0178, 0x2001, 0x0001, 0x080c,
+	0x27c3, 0x708c, 0xa086, 0x001e, 0x0120, 0x708c, 0xa086, 0x0022,
+	0x1118, 0x708f, 0x0025, 0x0010, 0x708f, 0x0021, 0x012e, 0x00ee,
+	0x00de, 0x00ce, 0x001e, 0x0005, 0x0026, 0x2011, 0x5995, 0x080c,
+	0x6a5c, 0x002e, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011, 0x5995,
+	0x080c, 0x6a53, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6, 0x0016,
+	0x080c, 0x7d7a, 0x2071, 0xb500, 0x080c, 0x5930, 0x001e, 0x00fe,
+	0x00ee, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x00f6, 0x0126, 0x080c, 0x7d7a, 0x2061, 0x0100, 0x2069, 0x0140,
+	0x2071, 0xb500, 0x2091, 0x8000, 0x6028, 0xc09c, 0x602a, 0x2011,
+	0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c,
+	0x7f59, 0x080c, 0x6a10, 0x0036, 0x2019, 0x0000, 0x080c, 0x7fe4,
+	0x003e, 0x60e3, 0x0000, 0x080c, 0xb42f, 0x080c, 0xb44a, 0x2001,
+	0xb500, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, 0x12dd, 0x2001,
+	0x0001, 0x080c, 0x27c3, 0x012e, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x003e, 0x002e, 0x001e, 0x0005, 0x2001, 0xb500, 0x2004, 0xa086,
+	0x0004, 0x0140, 0x2001, 0xb79e, 0x2003, 0xaaaa, 0x2001, 0xb79f,
+	0x2003, 0x0000, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6800, 0xa086,
+	0x00c0, 0x0160, 0x6803, 0x00c0, 0x0156, 0x20a9, 0x002d, 0x1d04,
+	0x59ff, 0x2091, 0x6000, 0x1f04, 0x59ff, 0x015e, 0x0005, 0x00c6,
+	0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500,
+	0x2001, 0xb79f, 0x200c, 0xa186, 0x0000, 0x0158, 0xa186, 0x0001,
+	0x0158, 0xa186, 0x0002, 0x0158, 0xa186, 0x0003, 0x0158, 0x0804,
+	0x5a94, 0x708f, 0x0022, 0x0040, 0x708f, 0x0021, 0x0028, 0x708f,
+	0x0023, 0x0020, 0x708f, 0x0024, 0x6043, 0x0000, 0x60e3, 0x0000,
+	0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2872, 0x0026, 0x2011,
+	0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c,
+	0x7f59, 0x0036, 0x2019, 0x0000, 0x080c, 0x7fe4, 0x003e, 0x002e,
+	0x7000, 0xa08e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b,
+	0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024,
+	0xd0ac, 0x0120, 0x012e, 0x015e, 0x0804, 0x5aa2, 0x6800, 0xa084,
+	0x00a0, 0xc0bd, 0x6802, 0x6904, 0xd1d4, 0x1130, 0x6803, 0x0100,
+	0x1f04, 0x5a57, 0x080c, 0x5b20, 0x012e, 0x015e, 0x080c, 0x5ae1,
+	0x01a8, 0x6044, 0xa005, 0x0168, 0x6050, 0x0006, 0xa085, 0x0020,
+	0x6052, 0x080c, 0x5b20, 0xa006, 0x8001, 0x1df0, 0x000e, 0x6052,
+	0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x5b20, 0x0016, 0x0026,
+	0x2009, 0x00c8, 0x2011, 0x59a2, 0x080c, 0x6a22, 0x002e, 0x001e,
+	0x2001, 0xb79f, 0x2003, 0x0004, 0x080c, 0x57e1, 0x080c, 0x5ae1,
+	0x0148, 0x6804, 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0xb79f,
+	0x2003, 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500, 0x2001,
+	0xb79e, 0x2003, 0x0000, 0x2001, 0xb78f, 0x2003, 0x0000, 0x708f,
+	0x0000, 0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c,
+	0x2872, 0x6803, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027,
+	0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006,
+	0x2001, 0xb79e, 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006,
+	0x2001, 0xb572, 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e,
+	0x0005, 0x0006, 0x2001, 0xb572, 0x2004, 0xa084, 0x0030, 0xa086,
+	0x0030, 0x000e, 0x0005, 0x0006, 0x2001, 0xb572, 0x2004, 0xa084,
+	0x0030, 0xa086, 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0xb572,
+	0x2004, 0xa084, 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001,
+	0xb50c, 0x2004, 0xd0a4, 0x0170, 0x080c, 0x2892, 0x0036, 0x0016,
+	0x2009, 0x0000, 0x2019, 0x0028, 0x080c, 0x2c6f, 0x001e, 0x003e,
+	0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0xb50c, 0x2e04, 0x0118,
+	0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, 0x00ee, 0x0005,
+	0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006,
+	0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, 0x6006,
+	0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, 0x60e3, 0x0000,
+	0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x2872, 0x6800, 0xa084,
+	0x00a0, 0xc0bd, 0x6802, 0x6803, 0x00a0, 0x000e, 0x6052, 0x6050,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xb500, 0x6020, 0xa084,
+	0x0080, 0x0138, 0x2001, 0xb50c, 0x200c, 0xc1bd, 0x2102, 0x0804,
+	0x5bc9, 0x2001, 0xb50c, 0x200c, 0xc1bc, 0x2102, 0x6028, 0xa084,
+	0xe1ff, 0x602a, 0x6027, 0x0200, 0x6803, 0x0090, 0x20a9, 0x0384,
+	0x6024, 0xd0cc, 0x1508, 0x1d04, 0x5b78, 0x2091, 0x6000, 0x1f04,
+	0x5b78, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002, 0x080c,
+	0x807f, 0x080c, 0x7f59, 0x2019, 0x0000, 0x080c, 0x7fe4, 0x6803,
+	0x00a0, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003,
+	0x0001, 0xa085, 0x0001, 0x0468, 0x86ff, 0x1120, 0x080c, 0x1e47,
+	0x080c, 0x24b0, 0x60e3, 0x0000, 0x2001, 0xb78f, 0x2004, 0x080c,
+	0x2872, 0x60e2, 0x6803, 0x0080, 0x20a9, 0x0384, 0x6027, 0x1e00,
+	0x2009, 0x1e00, 0xe000, 0x6024, 0xa10c, 0x0138, 0x1d04, 0x5bae,
+	0x2091, 0x6000, 0x1f04, 0x5bae, 0x0820, 0x6028, 0xa085, 0x1e00,
+	0x602a, 0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886,
+	0xa006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2071, 0xb500, 0x2069, 0x0140, 0x6020, 0xa084,
+	0x00c0, 0x0120, 0x6884, 0xa005, 0x1904, 0x5c25, 0x6803, 0x0088,
+	0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c, 0x2872,
+	0x2069, 0x0200, 0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01c0,
+	0x6028, 0xa084, 0xfbff, 0x602a, 0x6027, 0x0400, 0x2069, 0xb7c5,
+	0x7000, 0x206a, 0x708f, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002,
+	0x1d04, 0x5c08, 0x2091, 0x6000, 0x1f04, 0x5c08, 0x0804, 0x5c56,
+	0x2069, 0x0140, 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00,
+	0xe000, 0x6024, 0xa10c, 0x0520, 0xa084, 0x1a00, 0x1508, 0x1d04,
+	0x5c14, 0x2091, 0x6000, 0x1f04, 0x5c14, 0x2011, 0x0003, 0x080c,
+	0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x2019,
+	0x0000, 0x080c, 0x7fe4, 0x6803, 0x00a0, 0x2001, 0xb79f, 0x2003,
+	0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085, 0x0001, 0x00b0,
+	0x080c, 0x24b0, 0x6803, 0x0080, 0x2069, 0x0140, 0x60e3, 0x0000,
+	0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001,
+	0xb78f, 0x2004, 0x080c, 0x2872, 0x60e2, 0xa006, 0x00ee, 0x00de,
+	0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071,
+	0xb500, 0x6020, 0xa084, 0x00c0, 0x01e0, 0x2011, 0x0003, 0x080c,
+	0x8075, 0x2011, 0x0002, 0x080c, 0x807f, 0x080c, 0x7f59, 0x2019,
+	0x0000, 0x080c, 0x7fe4, 0x2069, 0x0140, 0x6803, 0x00a0, 0x2001,
+	0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0x0804,
+	0x5cfb, 0x2001, 0xb50c, 0x200c, 0xd1b4, 0x1160, 0xc1b5, 0x2102,
+	0x080c, 0x598a, 0x2069, 0x0140, 0x080c, 0x24b0, 0x6803, 0x0080,
+	0x60e3, 0x0000, 0x2069, 0x0200, 0x6804, 0xa005, 0x1118, 0x6808,
+	0xa005, 0x01c0, 0x6028, 0xa084, 0xfdff, 0x602a, 0x6027, 0x0200,
+	0x2069, 0xb7c5, 0x7000, 0x206a, 0x708f, 0x0027, 0x7003, 0x0001,
+	0x20a9, 0x0002, 0x1d04, 0x5cb2, 0x2091, 0x6000, 0x1f04, 0x5cb2,
+	0x0804, 0x5cfb, 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024,
+	0xa10c, 0x01c8, 0xa084, 0x1c00, 0x11b0, 0x1d04, 0x5cba, 0x0006,
+	0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x68f9, 0x00ee, 0x00de,
+	0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071, 0xb7f3, 0x7018, 0x00ee,
+	0xa005, 0x1d00, 0x0500, 0x0026, 0x2011, 0x59a2, 0x080c, 0x699c,
+	0x2011, 0x5995, 0x080c, 0x6a5c, 0x002e, 0x2069, 0x0140, 0x60e3,
+	0x0000, 0x70a4, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886,
+	0x2001, 0xb78f, 0x2004, 0x080c, 0x2872, 0x60e2, 0x2001, 0xb50c,
+	0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x0046,
+	0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x7130, 0xd184,
+	0x1180, 0x2011, 0xb553, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132,
+	0x2011, 0xb553, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, 0x0904,
+	0x5d68, 0x7130, 0xc185, 0x7132, 0x2011, 0xb553, 0x220c, 0xd1a4,
+	0x0530, 0x0016, 0x2019, 0x000e, 0x080c, 0xb065, 0x0156, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0xa186, 0x007e, 0x01a0, 0xa186, 0x0080,
+	0x0188, 0x080c, 0x4fa9, 0x1170, 0x8127, 0xa006, 0x0016, 0x2009,
+	0x000e, 0x080c, 0xb0e8, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c,
+	0x6b1a, 0x001e, 0x8108, 0x1f04, 0x5d33, 0x015e, 0x001e, 0xd1ac,
+	0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, 0x2c6f,
+	0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c,
+	0x4fa9, 0x1110, 0x080c, 0x4c0b, 0x8108, 0x1f04, 0x5d5f, 0x015e,
+	0x080c, 0x1e47, 0x2011, 0x0003, 0x080c, 0x8075, 0x2011, 0x0002,
+	0x080c, 0x807f, 0x080c, 0x7f59, 0x0036, 0x2019, 0x0000, 0x080c,
+	0x7fe4, 0x003e, 0x60e3, 0x0000, 0x2001, 0xb500, 0x2003, 0x0001,
+	0x080c, 0x5a07, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x0005, 0x2071, 0xb5e2, 0x7003, 0x0000, 0x7007, 0x0000,
+	0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001,
+	0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000,
+	0x708f, 0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb5e2,
+	0x6848, 0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001,
+	0x0428, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a,
+	0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009,
+	0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084,
+	0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084,
+	0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005,
+	0x2b78, 0x2071, 0xb5e2, 0x7004, 0x0043, 0x700c, 0x0002, 0x5de4,
+	0x5ddb, 0x5ddb, 0x5ddb, 0x5ddb, 0x0005, 0x5e3a, 0x5e3b, 0x5e6d,
+	0x5e6e, 0x5e38, 0x5ebc, 0x5ec1, 0x5ef2, 0x5ef3, 0x5f0e, 0x5f0f,
+	0x5f10, 0x5f11, 0x5f12, 0x5f13, 0x5fc9, 0x5ff0, 0x700c, 0x0002,
+	0x5dfd, 0x5e38, 0x5e38, 0x5e39, 0x5e39, 0x7830, 0x7930, 0xa106,
+	0x0120, 0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8,
+	0x1210, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x15df,
+	0x01b0, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057,
+	0x0000, 0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0xb812, 0x2104,
+	0xc085, 0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x165f, 0x0005,
+	0x080c, 0x15df, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x15df, 0x1108,
+	0x0c10, 0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8,
+	0x0005, 0x0005, 0x0005, 0x700c, 0x0002, 0x5e42, 0x5e45, 0x5e53,
+	0x5e6c, 0x5e6c, 0x080c, 0x5df6, 0x0005, 0x0126, 0x8001, 0x700e,
+	0x7058, 0x0006, 0x080c, 0x6343, 0x0120, 0x2091, 0x8000, 0x080c,
+	0x5df6, 0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x6343,
+	0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000,
+	0x6834, 0xa084, 0x00ff, 0xa08a, 0x003a, 0x1218, 0x00db, 0x012e,
+	0x0005, 0x012e, 0x080c, 0x5f14, 0x0005, 0x0005, 0x0005, 0x00e6,
+	0x2071, 0xb5e2, 0x700c, 0x0002, 0x5e79, 0x5e79, 0x5e79, 0x5e7b,
+	0x5e7e, 0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002,
+	0x00ee, 0x0005, 0x5f14, 0x5f14, 0x5f30, 0x5f14, 0x60ad, 0x5f14,
+	0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f30, 0x60ef, 0x6132, 0x617b,
+	0x618f, 0x5f14, 0x5f14, 0x5f4c, 0x5f30, 0x5f14, 0x5f14, 0x5fa6,
+	0x623b, 0x6256, 0x5f14, 0x5f4c, 0x5f14, 0x5f14, 0x5f14, 0x5f14,
+	0x5f9c, 0x6256, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14,
+	0x5f14, 0x5f14, 0x5f14, 0x5f60, 0x5f14, 0x5f14, 0x5f14, 0x5f14,
+	0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x5f14, 0x6361, 0x5f14, 0x5f14,
+	0x5f14, 0x5f14, 0x5f14, 0x5f75, 0x7020, 0x2068, 0x080c, 0x160f,
+	0x0005, 0x700c, 0x0002, 0x5ec8, 0x5ecb, 0x5ed9, 0x5ef1, 0x5ef1,
+	0x080c, 0x5df6, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006,
+	0x080c, 0x6343, 0x0120, 0x2091, 0x8000, 0x080c, 0x5df6, 0x00de,
+	0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x6343, 0x7058, 0x2068,
+	0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084,
+	0x00ff, 0xa08a, 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e,
+	0x0419, 0x0005, 0x0005, 0x0005, 0x5f14, 0x5f30, 0x6099, 0x5f14,
+	0x5f30, 0x5f14, 0x5f30, 0x5f30, 0x5f14, 0x5f30, 0x6099, 0x5f30,
+	0x5f30, 0x5f30, 0x5f30, 0x5f30, 0x5f14, 0x5f30, 0x6099, 0x5f14,
+	0x5f14, 0x5f30, 0x5f14, 0x5f14, 0x5f14, 0x5f30, 0x0005, 0x0005,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084,
+	0x00ff, 0xc0d5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408,
+	0x012e, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5,
+	0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005,
+	0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, 0x7007, 0x0001,
+	0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x5408, 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff,
+	0x0988, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x6059, 0x7007,
+	0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x6059, 0x0005,
+	0x6834, 0x8007, 0xa084, 0x00ff, 0x0904, 0x5f22, 0x8001, 0x1120,
+	0x7007, 0x0001, 0x0804, 0x6076, 0x7007, 0x0006, 0x7012, 0x2d00,
+	0x7016, 0x701a, 0x704b, 0x6076, 0x0005, 0x6834, 0x8007, 0xa084,
+	0x00ff, 0xa086, 0x0001, 0x1904, 0x5f22, 0x7007, 0x0001, 0x2009,
+	0xb531, 0x210c, 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a,
+	0x6853, 0x0000, 0x080c, 0x4d82, 0x1108, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x6837, 0x0139, 0x684a, 0x6952, 0x080c, 0x5408, 0x012e,
+	0x0ca0, 0x2001, 0x0028, 0x0c90, 0x684c, 0xa084, 0x00c0, 0xa086,
+	0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, 0x626e, 0x2d00, 0x7016,
+	0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0xb60d,
+	0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x1a04, 0x5f3e, 0x6a84,
+	0xa28a, 0x0002, 0x1a04, 0x5f3e, 0x82ff, 0x1138, 0x6888, 0x698c,
+	0xa105, 0x0118, 0x2001, 0x602c, 0x0018, 0xa280, 0x6022, 0x2005,
+	0x70c6, 0x7010, 0xa015, 0x0904, 0x600e, 0x080c, 0x15df, 0x1118,
+	0x7007, 0x000f, 0x0005, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x2c05,
+	0x6836, 0xe004, 0xad00, 0x7096, 0xe008, 0xa20a, 0x1210, 0xa00e,
+	0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0108,
+	0xa108, 0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x080c, 0x1643,
+	0x7090, 0xa08e, 0x0100, 0x0170, 0xa086, 0x0200, 0x0118, 0x7007,
+	0x0010, 0x0005, 0x7020, 0x2068, 0x080c, 0x160f, 0x7014, 0x2068,
+	0x0804, 0x5f3e, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000,
+	0x2d08, 0x2068, 0x6906, 0x711a, 0x0804, 0x5fc9, 0x7014, 0x2068,
+	0x7007, 0x0001, 0x6884, 0xa005, 0x1128, 0x6888, 0x698c, 0xa105,
+	0x0108, 0x00b1, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0904,
+	0x626e, 0x04b8, 0x6024, 0x6028, 0x0002, 0x0011, 0x0007, 0x0004,
+	0x000a, 0x000f, 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004,
+	0x00f6, 0x00e6, 0x00c6, 0x0076, 0x0066, 0x6f88, 0x6e8c, 0x6804,
+	0x2060, 0xacf0, 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c,
+	0x7816, 0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e,
+	0x7f0a, 0x8109, 0x0128, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0c78,
+	0x6004, 0xa065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0x2009, 0xb531, 0x210c, 0x81ff, 0x1198, 0x6838, 0xa084,
+	0x00ff, 0x683a, 0x080c, 0x4c64, 0x1108, 0x0005, 0x080c, 0x54db,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x9ecc, 0x080c, 0x5408, 0x012e,
+	0x0ca0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0xb531,
+	0x210c, 0x81ff, 0x11b0, 0x6858, 0xa005, 0x01c0, 0x6838, 0xa084,
+	0x00ff, 0x683a, 0x6853, 0x0000, 0x080c, 0x4d26, 0x1108, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x684a, 0x6952, 0x080c, 0x5408, 0x012e,
+	0x0cb0, 0x2001, 0x0028, 0x2009, 0x0000, 0x0c90, 0x2001, 0x0000,
+	0x0c78, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a, 0x7010,
+	0x8001, 0x7012, 0x0118, 0x7007, 0x0006, 0x0030, 0x7014, 0x2068,
+	0x7007, 0x0001, 0x7048, 0x080f, 0x0005, 0x7007, 0x0001, 0x6944,
+	0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084, 0x00ff, 0x20a9, 0x0001,
+	0xa096, 0x0001, 0x01b0, 0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096,
+	0x0002, 0x0178, 0xa005, 0x11f0, 0x6944, 0x810f, 0xa18c, 0x00ff,
+	0x080c, 0x4fa9, 0x11b8, 0x0066, 0x6e50, 0x080c, 0x50a8, 0x006e,
+	0x0088, 0x0046, 0x2011, 0xb50c, 0x2224, 0xc484, 0x2412, 0x004e,
+	0x00c6, 0x080c, 0x4fa9, 0x1110, 0x080c, 0x5209, 0x8108, 0x1f04,
+	0x60d9, 0x00ce, 0x684c, 0xd084, 0x1118, 0x080c, 0x160f, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xb553, 0x2004, 0xd0a4,
+	0x0580, 0x2061, 0xb874, 0x6100, 0xd184, 0x0178, 0x6858, 0xa084,
+	0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0xa005, 0x1538,
+	0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, 0x6860,
+	0xa005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0x6858, 0xa084,
+	0x00ff, 0x0178, 0x6006, 0x6858, 0x8007, 0xa084, 0x00ff, 0x0148,
+	0x600a, 0x6858, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804,
+	0x6332, 0x012e, 0x0804, 0x632c, 0x012e, 0x0804, 0x6326, 0x012e,
+	0x0804, 0x6329, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001,
+	0xb553, 0x2004, 0xd0a4, 0x05e0, 0x2061, 0xb874, 0x6000, 0xd084,
+	0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0x6c48, 0xa484, 0x0003,
+	0x0170, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x1120, 0x2100, 0xa210,
+	0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0xa212, 0x02f0, 0xa484,
+	0x000c, 0x0188, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004,
+	0x1120, 0x2100, 0xa318, 0x0288, 0x0030, 0xa082, 0x0004, 0x1168,
+	0x2100, 0xa31a, 0x0250, 0x6860, 0xa005, 0x0110, 0x8000, 0x6016,
+	0x6206, 0x630a, 0x012e, 0x0804, 0x6332, 0x012e, 0x0804, 0x632f,
+	0x012e, 0x0804, 0x632c, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001,
+	0x2061, 0xb874, 0x6300, 0xd38c, 0x1120, 0x6308, 0x8318, 0x0220,
+	0x630a, 0x012e, 0x0804, 0x6340, 0x012e, 0x0804, 0x632f, 0x0126,
+	0x00c6, 0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0148,
+	0x00c6, 0x2061, 0xb874, 0x6000, 0xa084, 0xfcff, 0x6002, 0x00ce,
+	0x0448, 0x6858, 0xa005, 0x05d0, 0x685c, 0xa065, 0x0598, 0x2001,
+	0xb531, 0x2004, 0xa005, 0x0118, 0x080c, 0x9e1d, 0x0068, 0x6013,
+	0x0400, 0x6057, 0x0000, 0x694c, 0xd1a4, 0x0110, 0x6950, 0x6156,
+	0x2009, 0x0041, 0x080c, 0x864c, 0x6958, 0xa18c, 0xff00, 0xa186,
+	0x2000, 0x1140, 0x0026, 0x2009, 0x0000, 0x2011, 0xfdff, 0x080c,
+	0x6b1a, 0x002e, 0x684c, 0xd0c4, 0x0148, 0x2061, 0xb874, 0x6000,
+	0xd08c, 0x1120, 0x6008, 0x8000, 0x0208, 0x600a, 0x00ce, 0x012e,
+	0x0804, 0x6332, 0x00ce, 0x012e, 0x0804, 0x632c, 0x6954, 0xa186,
+	0x002e, 0x0d40, 0xa186, 0x002d, 0x0d28, 0xa186, 0x0045, 0x0528,
+	0xa186, 0x002a, 0x1130, 0x2001, 0xb50c, 0x200c, 0xc194, 0x2102,
+	0x08c8, 0xa186, 0x0020, 0x0170, 0xa186, 0x0029, 0x1d18, 0x6944,
+	0xa18c, 0xff00, 0x810f, 0x080c, 0x4fa9, 0x1960, 0x6000, 0xc0e4,
+	0x6002, 0x0840, 0x685c, 0xa065, 0x09a8, 0x6007, 0x0024, 0x2001,
+	0xb7b6, 0x2004, 0x6016, 0x0804, 0x61ca, 0x685c, 0xa065, 0x0950,
+	0x00e6, 0x6860, 0xa075, 0x2001, 0xb531, 0x2004, 0xa005, 0x0150,
+	0x080c, 0x9e1d, 0x8eff, 0x0118, 0x2e60, 0x080c, 0x9e1d, 0x00ee,
+	0x0804, 0x61ca, 0x6020, 0xc0dc, 0xc0d5, 0x6022, 0x2e60, 0x6007,
+	0x003a, 0x6870, 0xa005, 0x0130, 0x6007, 0x003b, 0x6874, 0x602a,
+	0x6878, 0x6012, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x080c, 0x7173,
+	0x00ee, 0x0804, 0x61ca, 0x2061, 0xb874, 0x6000, 0xd084, 0x0190,
+	0xd08c, 0x1904, 0x6340, 0x0126, 0x2091, 0x8000, 0x6204, 0x8210,
+	0x0220, 0x6206, 0x012e, 0x0804, 0x6340, 0x012e, 0x6853, 0x0016,
+	0x0804, 0x6339, 0x6853, 0x0007, 0x0804, 0x6339, 0x6834, 0x8007,
+	0xa084, 0x00ff, 0x1118, 0x080c, 0x5f22, 0x0078, 0x2030, 0x8001,
+	0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007, 0x0006, 0x7012,
+	0x2d00, 0x7016, 0x701a, 0x704b, 0x626e, 0x0005, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0xa03e, 0x2009, 0xb531, 0x210c, 0x81ff, 0x1904,
+	0x62ec, 0x2009, 0xb50c, 0x210c, 0xd194, 0x1904, 0x6316, 0x6848,
+	0x2070, 0xae82, 0xbd00, 0x0a04, 0x62e0, 0x2001, 0xb517, 0x2004,
+	0xae02, 0x1a04, 0x62e0, 0x711c, 0xa186, 0x0006, 0x1904, 0x62cf,
+	0x7018, 0xa005, 0x0904, 0x62ec, 0x2004, 0xd0e4, 0x1904, 0x6311,
+	0x2061, 0xb874, 0x6100, 0xa184, 0x0301, 0xa086, 0x0001, 0x1550,
+	0x7020, 0xd0dc, 0x1904, 0x6319, 0x6853, 0x0000, 0x6803, 0x0000,
+	0x2d08, 0x7010, 0xa005, 0x1158, 0x7112, 0x684c, 0xd0f4, 0x1904,
+	0x631c, 0x2e60, 0x080c, 0x6a76, 0x012e, 0x00ee, 0x0005, 0x2068,
+	0x6800, 0xa005, 0x1de0, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x1904,
+	0x631c, 0x012e, 0x00ee, 0x0005, 0x012e, 0x00ee, 0x6853, 0x0006,
+	0x0804, 0x6339, 0xd184, 0x0dc0, 0xd1c4, 0x11a8, 0x00b8, 0x6944,
+	0xa18c, 0xff00, 0x810f, 0x080c, 0x4fa9, 0x15d8, 0x6000, 0xd0e4,
+	0x15c0, 0x711c, 0xa186, 0x0007, 0x1118, 0x6853, 0x0002, 0x0498,
+	0x6853, 0x0008, 0x0480, 0x6853, 0x000e, 0x0468, 0x6853, 0x0017,
+	0x0450, 0x6853, 0x0035, 0x0438, 0x2001, 0xb572, 0x2004, 0xd0fc,
+	0x01e8, 0x6848, 0x2070, 0xae82, 0xbd00, 0x02c0, 0x605c, 0xae02,
+	0x12a8, 0x711c, 0xa186, 0x0006, 0x1188, 0x7018, 0xa005, 0x0170,
+	0x2004, 0xd0bc, 0x0158, 0x2039, 0x0001, 0x7000, 0xa086, 0x0007,
+	0x1904, 0x6279, 0x7003, 0x0002, 0x0804, 0x6279, 0x6853, 0x0028,
+	0x0010, 0x6853, 0x0029, 0x012e, 0x00ee, 0x0418, 0x6853, 0x002a,
+	0x0cd0, 0x6853, 0x0045, 0x0cb8, 0x2e60, 0x2019, 0x0002, 0x6017,
+	0x0014, 0x080c, 0xace0, 0x012e, 0x00ee, 0x0005, 0x2009, 0x003e,
+	0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, 0x2009,
+	0x0016, 0x0010, 0x2009, 0x0001, 0x6854, 0xa084, 0xff00, 0xa105,
+	0x6856, 0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x0005,
+	0x080c, 0x160f, 0x0005, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230,
+	0xa00e, 0x7034, 0x7072, 0x7038, 0x7076, 0x0058, 0x7070, 0xa080,
+	0x0040, 0x7072, 0x1230, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085,
+	0x0001, 0x7932, 0x7132, 0x0005, 0x00d6, 0x080c, 0x6a6d, 0x00de,
+	0x0005, 0x00d6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x7007, 0x0001,
+	0x6a44, 0xa282, 0x0004, 0x1a04, 0x63ac, 0xd284, 0x0170, 0x6a4c,
+	0xa290, 0xb635, 0x2204, 0xa065, 0x6004, 0x05e0, 0x8007, 0xa084,
+	0x00ff, 0xa084, 0x0006, 0x1108, 0x04a8, 0x2c10, 0x080c, 0x85c7,
+	0x1118, 0x080c, 0x9ed6, 0x05a0, 0x621a, 0x6844, 0x0002, 0x638b,
+	0x6390, 0x6393, 0x6399, 0x2019, 0x0002, 0x080c, 0xb065, 0x0060,
+	0x080c, 0xaffc, 0x0048, 0x2019, 0x0002, 0x6950, 0x080c, 0xb017,
+	0x0018, 0x6950, 0x080c, 0xaffc, 0x080c, 0x861d, 0x6857, 0x0000,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x5408, 0x012e, 0x001e, 0x002e,
+	0x003e, 0x00ce, 0x00de, 0x0005, 0x6857, 0x0006, 0x0c88, 0x6857,
+	0x0002, 0x0c70, 0x6857, 0x0005, 0x0c58, 0x6857, 0x0004, 0x0c40,
+	0x6857, 0x0007, 0x0c28, 0x00d6, 0x2011, 0x0004, 0x2204, 0xa085,
+	0x8002, 0x2012, 0x00de, 0x0005, 0x20e1, 0x0002, 0x3d08, 0x20e1,
+	0x2000, 0x3d00, 0xa084, 0x7000, 0x0118, 0xa086, 0x1000, 0x1570,
+	0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, 0xf000,
+	0xa086, 0x3000, 0x1160, 0xa184, 0xff00, 0x8007, 0xa086, 0x0008,
+	0x11e8, 0x080c, 0x2dbf, 0x11d0, 0x080c, 0x6603, 0x0098, 0x20e1,
+	0x0004, 0x3d60, 0xd1bc, 0x1108, 0x3e60, 0xac84, 0x0007, 0x1170,
+	0xac82, 0xbd00, 0x0258, 0x685c, 0xac02, 0x1240, 0x2009, 0x0047,
+	0x080c, 0x864c, 0x7a1c, 0xd284, 0x1938, 0x0005, 0xa016, 0x080c,
+	0x185e, 0x0cc0, 0x0cd8, 0x781c, 0xd08c, 0x0500, 0x0156, 0x0136,
+	0x0146, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076, 0x1538,
+	0xa484, 0x7000, 0xa086, 0x1000, 0x11a8, 0x080c, 0x647e, 0x01f8,
+	0x20e1, 0x3000, 0x7828, 0x7828, 0x080c, 0x649a, 0x014e, 0x013e,
+	0x015e, 0x2009, 0xb7e8, 0x2104, 0xa005, 0x1108, 0x0005, 0x080c,
+	0x7173, 0x0ce0, 0xa484, 0x7000, 0x1548, 0x080c, 0x647e, 0x01d8,
+	0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0d10, 0x00a0, 0xd5a4,
+	0x0178, 0x0056, 0x0046, 0x080c, 0x1e6e, 0x080c, 0x24b0, 0x2001,
+	0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x004e, 0x005e, 0x0048,
+	0x04a9, 0x6887, 0x0000, 0x080c, 0xb3df, 0x20e1, 0x3000, 0x7828,
+	0x7828, 0x00b9, 0x014e, 0x013e, 0x015e, 0x0880, 0x0439, 0x1130,
+	0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x1d68, 0x080c, 0xb3df,
+	0x20e1, 0x3000, 0x7828, 0x7828, 0x0056, 0x080c, 0x6874, 0x005e,
+	0x0c40, 0x2001, 0xb50e, 0x2004, 0xd08c, 0x0178, 0x2001, 0xb500,
+	0x2004, 0xa086, 0x0003, 0x1148, 0x0026, 0x0036, 0x2011, 0x8048,
+	0x2518, 0x080c, 0x3ecc, 0x003e, 0x002e, 0x0005, 0xa484, 0x01ff,
+	0x6886, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac,
+	0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x0005, 0x20a9,
+	0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085,
+	0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007,
+	0xa196, 0x0000, 0x1118, 0x0804, 0x6708, 0x0005, 0xa196, 0x2000,
+	0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, 0x448f, 0x0ca8,
+	0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, 0x67b4, 0x0c68,
+	0x00c6, 0x6a84, 0x82ff, 0x0904, 0x65fd, 0x7110, 0xa18c, 0xff00,
+	0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, 0x1904, 0x65fd,
+	0xa08e, 0x0023, 0x1570, 0x080c, 0x684f, 0x0904, 0x65fd, 0x7124,
+	0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, 0xa005, 0x1904,
+	0x65fd, 0x2009, 0x0015, 0x080c, 0x864c, 0x0804, 0x65fd, 0xa08e,
+	0x0214, 0x0118, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c,
+	0x864c, 0x0804, 0x65fd, 0xa08e, 0x0100, 0x1904, 0x65fd, 0x7034,
+	0xa005, 0x1904, 0x65fd, 0x2009, 0x0016, 0x080c, 0x864c, 0x0804,
+	0x65fd, 0xa08e, 0x0022, 0x1904, 0x65fd, 0x7030, 0xa08e, 0x0300,
+	0x1580, 0x68d4, 0xd0a4, 0x0528, 0xc0b5, 0x68d6, 0x7100, 0xa18c,
+	0x00ff, 0x6972, 0x7004, 0x6876, 0x00f6, 0x2079, 0x0100, 0x79e6,
+	0x78ea, 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x2847,
+	0x7932, 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x281d, 0x6952,
+	0x703c, 0x00e6, 0x2071, 0x0140, 0x7086, 0x2071, 0xb500, 0x70a6,
+	0x00ee, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0017, 0x0804,
+	0x65c3, 0xa08e, 0x0400, 0x1158, 0x7034, 0xa005, 0x1904, 0x65fd,
+	0x68d4, 0xc0a5, 0x68d6, 0x2009, 0x0030, 0x0804, 0x65c3, 0xa08e,
+	0x0500, 0x1140, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0018,
+	0x0804, 0x65c3, 0xa08e, 0x2010, 0x1120, 0x2009, 0x0019, 0x0804,
+	0x65c3, 0xa08e, 0x2110, 0x1120, 0x2009, 0x001a, 0x0804, 0x65c3,
+	0xa08e, 0x5200, 0x1140, 0x7034, 0xa005, 0x1904, 0x65fd, 0x2009,
+	0x001b, 0x0804, 0x65c3, 0xa08e, 0x5000, 0x1140, 0x7034, 0xa005,
+	0x1904, 0x65fd, 0x2009, 0x001c, 0x0804, 0x65c3, 0xa08e, 0x1300,
+	0x1120, 0x2009, 0x0034, 0x0804, 0x65c3, 0xa08e, 0x1200, 0x1140,
+	0x7034, 0xa005, 0x1904, 0x65fd, 0x2009, 0x0024, 0x0804, 0x65c3,
+	0xa08c, 0xff00, 0xa18e, 0x2400, 0x1118, 0x2009, 0x002d, 0x04d8,
+	0xa08c, 0xff00, 0xa18e, 0x5300, 0x1118, 0x2009, 0x002a, 0x0498,
+	0xa08e, 0x0f00, 0x1118, 0x2009, 0x0020, 0x0468, 0xa08e, 0x5300,
+	0x1108, 0x00d8, 0xa08e, 0x6104, 0x11c0, 0x2011, 0xbb8d, 0x8208,
+	0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015,
+	0x211c, 0x8108, 0x0046, 0x2124, 0x080c, 0x3ecc, 0x004e, 0x8108,
+	0x1f04, 0x65a6, 0x2009, 0x0023, 0x0070, 0xa08e, 0x6000, 0x1118,
+	0x2009, 0x003f, 0x0040, 0xa08e, 0x7800, 0x1118, 0x2009, 0x0045,
+	0x0010, 0x2009, 0x001d, 0x0016, 0x2011, 0xbb83, 0x2204, 0x8211,
+	0x220c, 0x080c, 0x281d, 0x1598, 0x080c, 0x4f4d, 0x1580, 0x6612,
+	0x6516, 0x86ff, 0x01e8, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158,
+	0x6870, 0xa606, 0x11a8, 0x6874, 0xa506, 0xa084, 0xff00, 0x1180,
+	0x6000, 0xc0f5, 0x6002, 0xa186, 0x0046, 0x1150, 0x6870, 0xa606,
+	0x1138, 0x6874, 0xa506, 0xa084, 0xff00, 0x1110, 0x001e, 0x0068,
+	0x00c6, 0x080c, 0x85c7, 0x0168, 0x001e, 0x611a, 0x601f, 0x0004,
+	0x7120, 0x610a, 0x001e, 0x080c, 0x864c, 0x00ce, 0x0005, 0x001e,
+	0x0ce0, 0x00ce, 0x0ce0, 0x00c6, 0x0046, 0x080c, 0x6657, 0x1904,
+	0x6654, 0xa28e, 0x0033, 0x11e8, 0x080c, 0x684f, 0x0904, 0x6654,
+	0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1140, 0x7034, 0xa005,
+	0x15d8, 0x2009, 0x0015, 0x080c, 0x864c, 0x04b0, 0xa08e, 0x0100,
+	0x1598, 0x7034, 0xa005, 0x1580, 0x2009, 0x0016, 0x080c, 0x864c,
+	0x0458, 0xa28e, 0x0032, 0x1540, 0x7030, 0xa08e, 0x1400, 0x1520,
+	0x2009, 0x0038, 0x0016, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c,
+	0x080c, 0x281d, 0x11c0, 0x080c, 0x4f4d, 0x11a8, 0x6612, 0x6516,
+	0x00c6, 0x080c, 0x85c7, 0x0170, 0x001e, 0x611a, 0x080c, 0xa027,
+	0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x864c, 0x080c,
+	0x7173, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce, 0x0005, 0x00f6,
+	0x00d6, 0x0026, 0x0016, 0x0136, 0x0146, 0x0156, 0x3c00, 0x0006,
+	0x2079, 0x0030, 0x2069, 0x0200, 0x080c, 0x1f2d, 0x1590, 0x080c,
+	0x1dd2, 0x05e0, 0x04f1, 0x1130, 0x7908, 0xa18c, 0x1fff, 0xa182,
+	0x0011, 0x1688, 0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, 0x2099,
+	0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x7a0c,
+	0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0x0419, 0x1120, 0xa08a,
+	0x0140, 0x1a0c, 0x1515, 0x80ac, 0x20e1, 0x6000, 0x2099, 0x020a,
+	0x53a5, 0x20e1, 0x7000, 0x6828, 0x6828, 0x7803, 0x0004, 0xa294,
+	0x0070, 0x000e, 0x20e0, 0x015e, 0x014e, 0x013e, 0x001e, 0x002e,
+	0x00de, 0x00fe, 0x0005, 0xa016, 0x080c, 0x185e, 0xa085, 0x0001,
+	0x0c80, 0x0006, 0x2001, 0x0111, 0x2004, 0xa084, 0x0003, 0x000e,
+	0x0005, 0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130, 0xa696, 0x00ff,
+	0x1198, 0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, 0x6703,
+	0xa596, 0xfffe, 0x1118, 0x2009, 0x007e, 0x04e8, 0xa596, 0xfffc,
+	0x1118, 0x2009, 0x0080, 0x04b8, 0x2011, 0x0000, 0x2019, 0xb535,
+	0x231c, 0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071,
+	0xb635, 0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, 0x2071, 0xb6b6,
+	0x2e1c, 0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, 0xc2fd, 0x0080,
+	0x2368, 0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, 0x6b14, 0x1120,
+	0xa346, 0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, 0x83ff, 0x0d58,
+	0x8420, 0x8e70, 0x1f04, 0x66e0, 0x82ff, 0x1118, 0xa085, 0x0001,
+	0x0018, 0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, 0x004e, 0x0005,
+	0xa084, 0x0007, 0x000a, 0x0005, 0x6714, 0x6714, 0x6714, 0x6861,
+	0x6714, 0x6715, 0x672a, 0x679f, 0x0005, 0x7110, 0xd1bc, 0x0188,
+	0x7120, 0x2160, 0xac8c, 0x0007, 0x1160, 0xac8a, 0xbd00, 0x0248,
+	0x685c, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c,
+	0x864c, 0x0005, 0x00c6, 0xa484, 0x01ff, 0x0904, 0x677d, 0x7110,
+	0xd1bc, 0x1904, 0x677d, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c,
+	0x080c, 0x281d, 0x1904, 0x677d, 0x080c, 0x4f4d, 0x15f0, 0x6612,
+	0x6516, 0x6000, 0xd0ec, 0x15c8, 0x6204, 0xa294, 0xff00, 0x8217,
+	0xa286, 0x0006, 0x0148, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006,
+	0x11a0, 0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x85c7, 0x001e,
+	0x0530, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6152,
+	0x2009, 0x0044, 0x080c, 0x864c, 0x00c0, 0x00c6, 0x080c, 0x85c7,
+	0x001e, 0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286,
+	0x0004, 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003,
+	0x0001, 0x080c, 0x6cd3, 0x080c, 0x7173, 0x00ce, 0x0005, 0x2001,
+	0xb50d, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x3ecc,
+	0x00c6, 0x080c, 0x9ed6, 0x001e, 0x0d80, 0x611a, 0x601f, 0x0006,
+	0x7120, 0x610a, 0x7130, 0x6152, 0x6013, 0x0300, 0x6003, 0x0001,
+	0x6007, 0x0041, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x08f0, 0x7110,
+	0xd1bc, 0x0188, 0x7020, 0x2060, 0xac84, 0x0007, 0x1160, 0xac82,
+	0xbd00, 0x0248, 0x685c, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009,
+	0x0045, 0x080c, 0x864c, 0x0005, 0x0006, 0x080c, 0x2dbf, 0x000e,
+	0x1168, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000, 0x1130,
+	0xa084, 0x000f, 0xa08a, 0x0006, 0x1208, 0x000b, 0x0005, 0x67cd,
+	0x67ce, 0x67cd, 0x67cd, 0x6837, 0x6843, 0x0005, 0x7110, 0xd1bc,
+	0x0120, 0x702c, 0xd084, 0x0904, 0x6836, 0x700c, 0x7108, 0x080c,
+	0x281d, 0x1904, 0x6836, 0x080c, 0x4f4d, 0x1904, 0x6836, 0x6612,
+	0x6516, 0x6204, 0x7110, 0xd1bc, 0x01f8, 0xa28c, 0x00ff, 0xa186,
+	0x0004, 0x0118, 0xa186, 0x0006, 0x15c8, 0x00c6, 0x080c, 0x684f,
+	0x00ce, 0x0904, 0x6836, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x05f0,
+	0x611a, 0x080c, 0xa027, 0x601f, 0x0002, 0x7120, 0x610a, 0x2009,
+	0x0088, 0x080c, 0x864c, 0x0490, 0xa28c, 0x00ff, 0xa186, 0x0006,
+	0x0160, 0xa186, 0x0004, 0x0148, 0xa294, 0xff00, 0x8217, 0xa286,
+	0x0004, 0x0118, 0xa286, 0x0006, 0x1188, 0x00c6, 0x080c, 0x85c7,
+	0x001e, 0x01e0, 0x611a, 0x080c, 0xa027, 0x601f, 0x0005, 0x7120,
+	0x610a, 0x2009, 0x0088, 0x080c, 0x864c, 0x0080, 0x00c6, 0x080c,
+	0x85c7, 0x001e, 0x0158, 0x611a, 0x080c, 0xa027, 0x601f, 0x0004,
+	0x7120, 0x610a, 0x2009, 0x0001, 0x080c, 0x864c, 0x0005, 0x7110,
+	0xd1bc, 0x0140, 0x00a1, 0x0130, 0x7124, 0x610a, 0x2009, 0x0089,
+	0x080c, 0x864c, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x0041, 0x0130,
+	0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0x864c, 0x0005, 0x7020,
+	0x2060, 0xac84, 0x0007, 0x1158, 0xac82, 0xbd00, 0x0240, 0x2001,
+	0xb517, 0x2004, 0xac02, 0x1218, 0xa085, 0x0001, 0x0005, 0xa006,
+	0x0ce8, 0x7110, 0xd1bc, 0x1178, 0x7024, 0x2060, 0xac84, 0x0007,
+	0x1150, 0xac82, 0xbd00, 0x0238, 0x685c, 0xac02, 0x1220, 0x2009,
+	0x0051, 0x080c, 0x864c, 0x0005, 0x2031, 0x0105, 0x0069, 0x0005,
+	0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, 0x0005,
+	0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x00d6, 0x00f6, 0x7000,
+	0xa084, 0xf000, 0xa086, 0xc000, 0x05b0, 0x080c, 0x85c7, 0x0598,
+	0x0066, 0x00c6, 0x0046, 0x2011, 0xbb83, 0x2204, 0x8211, 0x220c,
+	0x080c, 0x281d, 0x1580, 0x080c, 0x4f4d, 0x1568, 0x6612, 0x6516,
+	0x2c00, 0x004e, 0x00ce, 0x601a, 0x080c, 0xa027, 0x080c, 0x15f8,
+	0x01f0, 0x2d00, 0x6056, 0x6803, 0x0000, 0x6837, 0x0000, 0x6c3a,
+	0xadf8, 0x000f, 0x20a9, 0x000e, 0x2fa0, 0x2e98, 0x53a3, 0x006e,
+	0x6612, 0x6007, 0x003e, 0x601f, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x6cd3, 0x080c, 0x7173, 0x00fe, 0x00de, 0x00ce, 0x0005, 0x080c,
+	0x861d, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x2071, 0xb7f3,
+	0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7076, 0x7012,
+	0x7017, 0xbd00, 0x7007, 0x0000, 0x7026, 0x702b, 0x7d91, 0x7032,
+	0x7037, 0x7df1, 0x703b, 0xffff, 0x703f, 0xffff, 0x7042, 0x7047,
+	0x444b, 0x704a, 0x705b, 0x6a2b, 0x2001, 0xb7a1, 0x2003, 0x0003,
+	0x2001, 0xb7a3, 0x2003, 0x0100, 0x3a00, 0xa084, 0x0005, 0x706e,
+	0x0005, 0x2071, 0xb7f3, 0x1d04, 0x698b, 0x2091, 0x6000, 0x700c,
+	0x8001, 0x700e, 0x1518, 0x700f, 0x0361, 0x7007, 0x0001, 0x0126,
+	0x2091, 0x8000, 0x7040, 0xa00d, 0x0128, 0x8109, 0x7142, 0x1110,
+	0x7044, 0x080f, 0x00c6, 0x2061, 0xb500, 0x6034, 0x00ce, 0xd0cc,
+	0x0180, 0x3a00, 0xa084, 0x0005, 0x726c, 0xa216, 0x0150, 0x706e,
+	0x2011, 0x8043, 0x2018, 0x080c, 0x3ecc, 0x0018, 0x0126, 0x2091,
+	0x8000, 0x7024, 0xa00d, 0x0188, 0x7020, 0x8001, 0x7022, 0x1168,
+	0x7023, 0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, 0x1110, 0x7028,
+	0x080f, 0x81ff, 0x1110, 0x7028, 0x080f, 0x7030, 0xa00d, 0x0180,
+	0x702c, 0x8001, 0x702e, 0x1160, 0x702f, 0x0009, 0x8109, 0x7132,
+	0x0128, 0xa184, 0x007f, 0x090c, 0x7e36, 0x0010, 0x7034, 0x080f,
+	0x7038, 0xa005, 0x0118, 0x0310, 0x8001, 0x703a, 0x703c, 0xa005,
+	0x0118, 0x0310, 0x8001, 0x703e, 0x704c, 0xa00d, 0x0168, 0x7048,
+	0x8001, 0x704a, 0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120,
+	0x7150, 0x714e, 0x7058, 0x080f, 0x7018, 0xa00d, 0x01d8, 0x0016,
+	0x7074, 0xa00d, 0x0158, 0x7070, 0x8001, 0x7072, 0x1138, 0x7073,
+	0x0009, 0x8109, 0x7176, 0x1110, 0x7078, 0x080f, 0x001e, 0x7008,
+	0x8001, 0x700a, 0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110,
+	0x701c, 0x080f, 0x012e, 0x7004, 0x0002, 0x69b1, 0x69b2, 0x69ca,
+	0x00e6, 0x2071, 0xb7f3, 0x7018, 0xa005, 0x1120, 0x711a, 0x721e,
+	0x700b, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0xb7f3,
+	0x701c, 0xa206, 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee, 0x0005,
+	0x00e6, 0x2071, 0xb7f3, 0x6088, 0xa102, 0x0208, 0x618a, 0x00ee,
+	0x0005, 0x0005, 0x7110, 0x080c, 0x4fa9, 0x1158, 0x6088, 0x8001,
+	0x0240, 0x608a, 0x1130, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173,
+	0x012e, 0x8108, 0xa182, 0x00ff, 0x0218, 0xa00e, 0x7007, 0x0002,
+	0x7112, 0x0005, 0x7014, 0x2060, 0x0126, 0x2091, 0x8000, 0x603c,
+	0xa005, 0x0128, 0x8001, 0x603e, 0x1110, 0x080c, 0x9f15, 0x6014,
+	0xa005, 0x0500, 0x8001, 0x6016, 0x11e8, 0x611c, 0xa186, 0x0003,
+	0x0118, 0xa186, 0x0006, 0x11a0, 0x6010, 0x2068, 0x6854, 0xa08a,
+	0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a, 0x0210,
+	0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0010,
+	0x080c, 0x99e5, 0x012e, 0xac88, 0x0018, 0x7116, 0x2001, 0xed00,
+	0xa102, 0x0220, 0x7017, 0xbd00, 0x7007, 0x0000, 0x0005, 0x00e6,
+	0x2071, 0xb7f3, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005,
+	0x2001, 0xb7fc, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0xb7f3,
+	0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0xb7ff, 0x2013,
+	0x0000, 0x0005, 0x00e6, 0x2071, 0xb7f3, 0x711a, 0x721e, 0x700b,
+	0x0009, 0x00ee, 0x0005, 0x00c6, 0x0026, 0x7054, 0x8000, 0x7056,
+	0x2061, 0xb7a1, 0x6008, 0xa086, 0x0000, 0x0158, 0x7068, 0x6032,
+	0x7064, 0x602e, 0x7060, 0x602a, 0x705c, 0x6026, 0x2c10, 0x080c,
+	0x1643, 0x002e, 0x00ce, 0x0005, 0x0006, 0x0016, 0x00c6, 0x00d6,
+	0x00e6, 0x00f6, 0x080c, 0x68f9, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0xb7f3, 0x7176, 0x727a,
+	0x7073, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0xb7f3,
+	0x7078, 0xa206, 0x1110, 0x7076, 0x707a, 0x000e, 0x00ee, 0x0005,
+	0x00c6, 0x2061, 0xb874, 0x00ce, 0x0005, 0xa184, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa080, 0xb874, 0x2060, 0x0005, 0x6854, 0xa08a,
+	0x199a, 0x0210, 0x2001, 0x1999, 0xa005, 0x1150, 0x00c6, 0x2061,
+	0xb874, 0x6014, 0x00ce, 0xa005, 0x1138, 0x2001, 0x001e, 0x0020,
+	0xa08e, 0xffff, 0x1108, 0xa006, 0x8003, 0x800b, 0x810b, 0xa108,
+	0x6116, 0x684c, 0xa08c, 0x00c0, 0xa18e, 0x00c0, 0x05e8, 0xd0b4,
+	0x1138, 0xd0bc, 0x1550, 0x2009, 0x0006, 0x080c, 0x6af1, 0x0005,
+	0xd0fc, 0x0138, 0xa084, 0x0003, 0x0120, 0xa086, 0x0003, 0x1904,
+	0x6aeb, 0x6020, 0xd0d4, 0x0130, 0xc0d4, 0x6022, 0x6860, 0x602a,
+	0x685c, 0x602e, 0x2009, 0xb574, 0x2104, 0xd084, 0x0138, 0x87ff,
+	0x1120, 0x2009, 0x0042, 0x080c, 0x864c, 0x0005, 0x87ff, 0x1120,
+	0x2009, 0x0043, 0x080c, 0x864c, 0x0005, 0xd0fc, 0x0130, 0xa084,
+	0x0003, 0x0118, 0xa086, 0x0003, 0x11f0, 0x87ff, 0x1120, 0x2009,
+	0x0042, 0x080c, 0x864c, 0x0005, 0xd0fc, 0x0160, 0xa084, 0x0003,
+	0xa08e, 0x0002, 0x0148, 0x87ff, 0x1120, 0x2009, 0x0041, 0x080c,
+	0x864c, 0x0005, 0x0061, 0x0ce8, 0x87ff, 0x1dd8, 0x2009, 0x0043,
+	0x080c, 0x864c, 0x0cb0, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009,
+	0x0001, 0x00d6, 0x6010, 0xa0ec, 0xf000, 0x0510, 0x2068, 0x6952,
+	0x6800, 0x6012, 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c, 0x8100,
+	0xa18e, 0x8100, 0x1158, 0x00c6, 0x2061, 0xb874, 0x6200, 0xd28c,
+	0x1120, 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x5408,
+	0x6010, 0xa06d, 0x0076, 0x2039, 0x0000, 0x190c, 0x6a76, 0x007e,
+	0x00de, 0x0005, 0x0156, 0x00c6, 0x2061, 0xb874, 0x6000, 0x81ff,
+	0x0110, 0xa205, 0x0008, 0xa204, 0x6002, 0x00ce, 0x015e, 0x0005,
+	0x6800, 0xd08c, 0x1138, 0x6808, 0xa005, 0x0120, 0x8001, 0x680a,
+	0xa085, 0x0001, 0x0005, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086,
+	0x818e, 0x1208, 0xa200, 0x1f04, 0x6b37, 0x8086, 0x818e, 0x0005,
+	0x0156, 0x20a9, 0x0010, 0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213,
+	0x818d, 0x0228, 0xa11a, 0x1220, 0x1f04, 0x6b47, 0x0028, 0xa11a,
+	0x2308, 0x8210, 0x1f04, 0x6b47, 0x0006, 0x3200, 0xa084, 0xefff,
+	0x2080, 0x000e, 0x015e, 0x0005, 0x0006, 0x3200, 0xa085, 0x1000,
+	0x0cb8, 0x0126, 0x2091, 0x2800, 0x2079, 0xb7e0, 0x012e, 0x00d6,
+	0x2069, 0xb7e0, 0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085,
+	0x8001, 0x206a, 0x00de, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804,
+	0xa084, 0x0007, 0x0002, 0x6b85, 0x6ba6, 0x6bf9, 0x6b8b, 0x6ba6,
+	0x6b85, 0x6b83, 0x6b83, 0x080c, 0x1515, 0x080c, 0x6a10, 0x080c,
+	0x7173, 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005,
+	0x2011, 0x4adc, 0x080c, 0x699c, 0x7828, 0xa092, 0x00c8, 0x1228,
+	0x8000, 0x782a, 0x080c, 0x4b16, 0x0c88, 0x080c, 0x4adc, 0x7807,
+	0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0c40, 0x080c, 0x6a10,
+	0x3c00, 0x0006, 0x2011, 0x0209, 0x20e1, 0x4000, 0x2214, 0x000e,
+	0x20e0, 0x82ff, 0x0178, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000,
+	0x7824, 0xa065, 0x090c, 0x1515, 0x2009, 0x0013, 0x080c, 0x864c,
+	0x00ce, 0x0005, 0x3900, 0xa082, 0xb92c, 0x1210, 0x080c, 0x8332,
+	0x00c6, 0x7824, 0xa065, 0x090c, 0x1515, 0x7804, 0xa086, 0x0004,
+	0x0904, 0x6c39, 0x7828, 0xa092, 0x2710, 0x1230, 0x8000, 0x782a,
+	0x00ce, 0x080c, 0x7d6d, 0x0c20, 0x6104, 0xa186, 0x0003, 0x1188,
+	0x00e6, 0x2071, 0xb500, 0x70e0, 0x00ee, 0xd08c, 0x0150, 0x00c6,
+	0x00e6, 0x2061, 0x0100, 0x2071, 0xb500, 0x080c, 0x4b1f, 0x00ee,
+	0x00ce, 0x080c, 0xb444, 0x2009, 0x0014, 0x080c, 0x864c, 0x00ce,
+	0x0838, 0x2001, 0xb7fc, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160,
+	0x782b, 0x0000, 0x7824, 0xa065, 0x090c, 0x1515, 0x2009, 0x0013,
+	0x080c, 0x86a0, 0x00ce, 0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082,
+	0xb92c, 0x1210, 0x080c, 0x8332, 0x7824, 0xa005, 0x090c, 0x1515,
+	0x781c, 0xa06d, 0x090c, 0x1515, 0x6800, 0xc0dc, 0x6802, 0x7924,
+	0x2160, 0x080c, 0x861d, 0x693c, 0x81ff, 0x090c, 0x1515, 0x8109,
+	0x693e, 0x6854, 0xa015, 0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e,
+	0x7807, 0x0000, 0x7827, 0x0000, 0x00de, 0x00ce, 0x080c, 0x7173,
+	0x0888, 0x6104, 0xa186, 0x0002, 0x0128, 0xa186, 0x0004, 0x0110,
+	0x0804, 0x6bd2, 0x7808, 0xac06, 0x0904, 0x6bd2, 0x080c, 0x7090,
+	0x080c, 0x6cd3, 0x00ce, 0x080c, 0x7173, 0x0804, 0x6bc0, 0x00c6,
+	0x6027, 0x0002, 0x62c8, 0x60c4, 0xa205, 0x1178, 0x793c, 0xa1e5,
+	0x0000, 0x0130, 0x2009, 0x0049, 0x080c, 0x864c, 0x00ce, 0x0005,
+	0x2011, 0xb7ff, 0x2013, 0x0000, 0x0cc8, 0x3908, 0xa192, 0xb92c,
+	0x1210, 0x080c, 0x8332, 0x793c, 0x81ff, 0x0d90, 0x7944, 0xa192,
+	0x7530, 0x12b8, 0x8108, 0x7946, 0x793c, 0xa188, 0x0007, 0x210c,
+	0xa18e, 0x0006, 0x1138, 0x6014, 0xa084, 0x0184, 0xa085, 0x0012,
+	0x6016, 0x08e0, 0x6014, 0xa084, 0x0184, 0xa085, 0x0016, 0x6016,
+	0x08a8, 0x7848, 0xc085, 0x784a, 0x0888, 0x0006, 0x0016, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0,
+	0x6020, 0x8000, 0x6022, 0x6010, 0xa005, 0x0148, 0xa080, 0x0003,
+	0x2102, 0x6112, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, 0x6116,
+	0x6112, 0x0cc0, 0x00d6, 0x2069, 0xb7e0, 0x6000, 0xd0d4, 0x0168,
+	0x6820, 0x8000, 0x6822, 0xa086, 0x0001, 0x1110, 0x2c00, 0x681e,
+	0x6804, 0xa084, 0x0007, 0x0804, 0x7179, 0xc0d5, 0x6002, 0x6818,
+	0xa005, 0x0158, 0x6056, 0x605b, 0x0000, 0x0006, 0x2c00, 0x681a,
+	0x00de, 0x685a, 0x2069, 0xb7e0, 0x0c18, 0x6056, 0x605a, 0x2c00,
+	0x681a, 0x681e, 0x08e8, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091,
+	0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0, 0x6020, 0x8000,
+	0x6022, 0x6008, 0xa005, 0x0148, 0xa080, 0x0003, 0x2102, 0x610a,
+	0x012e, 0x00ce, 0x001e, 0x000e, 0x0005, 0x610e, 0x610a, 0x0cc0,
+	0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061, 0xb7e0, 0x6034, 0xa005,
+	0x0130, 0xa080, 0x0003, 0x2102, 0x6136, 0x00ce, 0x0005, 0x613a,
+	0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066,
+	0x0056, 0x0036, 0x0026, 0x0016, 0x0006, 0x0126, 0xa02e, 0x2071,
+	0xb7e0, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904,
+	0x6d7b, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6d76,
+	0x87ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6d76, 0x703c, 0xac06,
+	0x1190, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7033, 0x0000,
+	0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, 0x0000,
+	0x003e, 0x2029, 0x0001, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a,
+	0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036,
+	0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x9c5a, 0x01c8,
+	0x6010, 0x2068, 0x601c, 0xa086, 0x0003, 0x1580, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x0016, 0x0036, 0x0076, 0x080c, 0x9ecc,
+	0x080c, 0xb380, 0x080c, 0x5408, 0x007e, 0x003e, 0x001e, 0x080c,
+	0x9e11, 0x080c, 0x9e1d, 0x00ce, 0x0804, 0x6d16, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0x6d16, 0x85ff, 0x0120, 0x0036, 0x080c, 0x7230,
+	0x003e, 0x012e, 0x000e, 0x001e, 0x002e, 0x003e, 0x005e, 0x006e,
+	0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086,
+	0x0006, 0x1158, 0x0016, 0x0036, 0x0076, 0x080c, 0xb380, 0x080c,
+	0xb099, 0x007e, 0x003e, 0x001e, 0x08a0, 0x601c, 0xa086, 0x000a,
+	0x0904, 0x6d60, 0x0804, 0x6d5e, 0x0006, 0x0066, 0x00c6, 0x00d6,
+	0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079, 0xb7e0,
+	0x7838, 0xa065, 0x0568, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c,
+	0xac06, 0x1180, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7833,
+	0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x784b,
+	0x0000, 0x003e, 0x080c, 0x9c5a, 0x0178, 0x6010, 0x2068, 0x601c,
+	0xa086, 0x0003, 0x11b0, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x000e, 0x0888,
+	0x7e3a, 0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e,
+	0x0005, 0x601c, 0xa086, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c60,
+	0x601c, 0xa086, 0x000a, 0x0d08, 0x08f0, 0x0016, 0x0026, 0x0086,
+	0x2041, 0x0000, 0x0099, 0x080c, 0x6ec3, 0x008e, 0x002e, 0x001e,
+	0x0005, 0x00f6, 0x0126, 0x2079, 0xb7e0, 0x2091, 0x8000, 0x080c,
+	0x6f50, 0x080c, 0x6fc2, 0x012e, 0x00fe, 0x0005, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, 0x2091, 0x8000,
+	0x2071, 0xb7e0, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0904, 0x6e99,
+	0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6e94, 0x88ff,
+	0x0120, 0x6050, 0xa106, 0x1904, 0x6e94, 0x7024, 0xac06, 0x1538,
+	0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6a10, 0x080c,
+	0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000, 0x0036,
+	0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100,
+	0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827,
+	0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a, 0x04e8, 0x7014,
+	0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00,
+	0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c,
+	0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f,
+	0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x01b8, 0x601c, 0xa086,
+	0x0003, 0x1540, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x0016,
+	0x0036, 0x0086, 0x080c, 0x9ecc, 0x080c, 0xb380, 0x080c, 0x5408,
+	0x008e, 0x003e, 0x001e, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x080c,
+	0x811e, 0x00ce, 0x0804, 0x6e1d, 0x2c78, 0x600c, 0x2060, 0x0804,
+	0x6e1d, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x1158, 0x0016, 0x0036,
+	0x0086, 0x080c, 0xb380, 0x080c, 0xb099, 0x008e, 0x003e, 0x001e,
+	0x08e0, 0x601c, 0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085,
+	0x0908, 0x0898, 0x601c, 0xa086, 0x0005, 0x1978, 0x6004, 0xa086,
+	0x0085, 0x0d20, 0x0850, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000,
+	0xa280, 0xb635, 0x2004, 0xa065, 0x0904, 0x6f4c, 0x00f6, 0x00e6,
+	0x00d6, 0x0066, 0x2071, 0xb7e0, 0x6654, 0x7018, 0xac06, 0x1108,
+	0x761a, 0x701c, 0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e,
+	0x0008, 0x761e, 0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000,
+	0x0110, 0x2f00, 0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000,
+	0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4ed4, 0x0904, 0x6f48, 0x7624,
+	0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6,
+	0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6a10, 0x080c,
+	0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000, 0x0036,
+	0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100,
+	0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827,
+	0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001,
+	0x603e, 0x2660, 0x080c, 0x9e1d, 0x00ce, 0x0048, 0x00de, 0x00c6,
+	0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6ef3, 0x8dff,
+	0x0158, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x9ecc,
+	0x080c, 0xb380, 0x080c, 0x5408, 0x080c, 0x811e, 0x0804, 0x6ef3,
+	0x006e, 0x00de, 0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005,
+	0x0006, 0x0066, 0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065,
+	0x0904, 0x6fa2, 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06,
+	0x1540, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6a10,
+	0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7827, 0x0000,
+	0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803,
+	0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110,
+	0x6827, 0x0001, 0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30,
+	0x00b0, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0168, 0x601c, 0xa086,
+	0x0003, 0x11b8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c,
+	0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x080c, 0x811e, 0x000e,
+	0x0804, 0x6f57, 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e,
+	0x0005, 0x601c, 0xa086, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c58,
+	0x601c, 0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x09d0,
+	0x0c10, 0x601c, 0xa086, 0x0005, 0x19f0, 0x6004, 0xa086, 0x0085,
+	0x0d60, 0x08c8, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x7818, 0xa065,
+	0x0904, 0x7028, 0x6054, 0x0006, 0x6057, 0x0000, 0x605b, 0x0000,
+	0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x080c, 0x4ed4, 0x0904, 0x7025,
+	0x7e24, 0x86ff, 0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0,
+	0x00d6, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6a10,
+	0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d, 0x7827, 0x0000,
+	0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803,
+	0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110,
+	0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110,
+	0x8001, 0x603e, 0x2660, 0x080c, 0x9e1d, 0x00ce, 0x0048, 0x00de,
+	0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6fd4,
+	0x8dff, 0x0138, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c,
+	0x5408, 0x080c, 0x811e, 0x0804, 0x6fd4, 0x000e, 0x0804, 0x6fc7,
+	0x781e, 0x781a, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x00e6,
+	0x00d6, 0x0066, 0x6000, 0xd0dc, 0x01a0, 0x604c, 0xa06d, 0x0188,
+	0x6848, 0xa606, 0x1170, 0x2071, 0xb7e0, 0x7024, 0xa035, 0x0148,
+	0xa080, 0x0004, 0x2004, 0xad06, 0x1120, 0x6000, 0xc0dc, 0x6002,
+	0x0021, 0x006e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079, 0x0100,
+	0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a,
+	0x00ce, 0x04a0, 0x080c, 0x7d7a, 0x78c3, 0x0000, 0x080c, 0x824d,
+	0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0xa384, 0x1000,
+	0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824,
+	0xd084, 0x0110, 0x7827, 0x0001, 0x080c, 0x824d, 0x003e, 0x080c,
+	0x4ed4, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660,
+	0x080c, 0x861d, 0x00ce, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x080c, 0x9ecc, 0x080c, 0x5408, 0x080c, 0x811e, 0x00fe, 0x0005,
+	0x00e6, 0x00c6, 0x2071, 0xb7e0, 0x7004, 0xa084, 0x0007, 0x0002,
+	0x70a2, 0x70a5, 0x70bb, 0x70d4, 0x7111, 0x70a2, 0x70a0, 0x70a0,
+	0x080c, 0x1515, 0x00ce, 0x00ee, 0x0005, 0x7024, 0xa065, 0x0148,
+	0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0150, 0x7216, 0x600f,
+	0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005,
+	0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060, 0x080c, 0x4ed4, 0x6000,
+	0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022, 0x0120, 0x6054, 0xa015,
+	0x0140, 0x721e, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee,
+	0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024, 0xa065, 0x05b8, 0x700c,
+	0xac06, 0x1160, 0x080c, 0x811e, 0x600c, 0xa015, 0x0120, 0x720e,
+	0x600f, 0x0000, 0x0448, 0x720e, 0x720a, 0x0430, 0x7014, 0xac06,
+	0x1160, 0x080c, 0x811e, 0x600c, 0xa015, 0x0120, 0x7216, 0x600f,
+	0x0000, 0x00d0, 0x7216, 0x7212, 0x00b8, 0x601c, 0xa086, 0x0003,
+	0x1198, 0x6018, 0x2060, 0x080c, 0x4ed4, 0x6000, 0xc0dc, 0x6002,
+	0x080c, 0x811e, 0x701c, 0xa065, 0x0138, 0x6054, 0xa015, 0x0110,
+	0x721e, 0x0010, 0x7218, 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee,
+	0x0005, 0x7024, 0xa065, 0x0140, 0x080c, 0x811e, 0x600c, 0xa015,
+	0x0150, 0x720e, 0x600f, 0x0000, 0x080c, 0x824d, 0x7027, 0x0000,
+	0x00ce, 0x00ee, 0x0005, 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069,
+	0xb7e0, 0x6830, 0xa084, 0x0003, 0x0002, 0x7133, 0x7135, 0x7159,
+	0x7131, 0x080c, 0x1515, 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086,
+	0x0001, 0x01b8, 0x683c, 0xa065, 0x0130, 0x600c, 0xa015, 0x0170,
+	0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011,
+	0xb7ff, 0x2013, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, 0x6836,
+	0x0c90, 0x6843, 0x0000, 0x6838, 0xa065, 0x0d68, 0x6003, 0x0003,
+	0x0c50, 0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x684b, 0x0000,
+	0x683c, 0xa065, 0x0168, 0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f,
+	0x0000, 0x683f, 0x0000, 0x0020, 0x683f, 0x0000, 0x683a, 0x6836,
+	0x00ce, 0x00de, 0x0005, 0x00d6, 0x2069, 0xb7e0, 0x6804, 0xa084,
+	0x0007, 0x0002, 0x7184, 0x7220, 0x7220, 0x7220, 0x7220, 0x7222,
+	0x7182, 0x7182, 0x080c, 0x1515, 0x6820, 0xa005, 0x1110, 0x00de,
+	0x0005, 0x00c6, 0x680c, 0xa065, 0x0150, 0x6807, 0x0004, 0x6826,
+	0x682b, 0x0000, 0x080c, 0x7272, 0x00ce, 0x00de, 0x0005, 0x6814,
+	0xa065, 0x0150, 0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c,
+	0x7272, 0x00ce, 0x00de, 0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5,
+	0x0000, 0x0904, 0x721c, 0x704c, 0xa00d, 0x0118, 0x7088, 0xa005,
+	0x01a0, 0x7054, 0xa075, 0x0120, 0xa20e, 0x0904, 0x721c, 0x0028,
+	0x6818, 0xa20e, 0x0904, 0x721c, 0x2070, 0x704c, 0xa00d, 0x0d88,
+	0x7088, 0xa005, 0x1d70, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302,
+	0x1e40, 0x080c, 0x85f4, 0x0904, 0x721c, 0x8318, 0x733e, 0x6112,
+	0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff, 0x605a,
+	0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004, 0xa08a,
+	0x199a, 0x0210, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b, 0xa318,
+	0x6316, 0x003e, 0x00f6, 0x2c78, 0x71a0, 0x2001, 0xb535, 0x2004,
+	0xd0ac, 0x1110, 0xd1bc, 0x0150, 0x7100, 0xd1f4, 0x0120, 0x7114,
+	0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2dc4,
+	0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x080c, 0x78a2,
+	0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b,
+	0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040, 0x00fe,
+	0x00ee, 0x00ce, 0x00de, 0x0005, 0x003e, 0x00ee, 0x00ce, 0x0cd0,
+	0x00de, 0x0005, 0x00c6, 0x680c, 0xa065, 0x0138, 0x6807, 0x0004,
+	0x6826, 0x682b, 0x0000, 0x080c, 0x7272, 0x00ce, 0x00de, 0x0005,
+	0x00f6, 0x00d6, 0x2069, 0xb7e0, 0x6830, 0xa086, 0x0000, 0x11d0,
+	0x2001, 0xb50c, 0x200c, 0xd1bc, 0x1560, 0x6838, 0xa07d, 0x0190,
+	0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x684b, 0x0000, 0x0126,
+	0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x2021, 0x1130, 0x012e,
+	0x080c, 0x7beb, 0x00de, 0x00fe, 0x0005, 0x012e, 0xe000, 0x6843,
+	0x0000, 0x7803, 0x0002, 0x780c, 0xa015, 0x0140, 0x6a3a, 0x780f,
+	0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c60, 0x683a, 0x6836,
+	0x0cc0, 0xc1bc, 0x2102, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51,
+	0x006e, 0x0858, 0x601c, 0xa084, 0x000f, 0x000b, 0x0005, 0x7280,
+	0x7285, 0x7743, 0x785f, 0x7285, 0x7743, 0x785f, 0x7280, 0x7285,
+	0x080c, 0x7090, 0x080c, 0x7173, 0x0005, 0x0156, 0x0136, 0x0146,
+	0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x1515, 0x6118,
+	0x2178, 0x79a0, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd1bc,
+	0x0150, 0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040,
+	0x2009, 0x0000, 0x0028, 0xa1f8, 0x2dc4, 0x2f0d, 0xa18c, 0x00ff,
+	0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x1a04, 0x72f9,
+	0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x73a8,
+	0x73f3, 0x7420, 0x74ed, 0x751b, 0x7523, 0x7549, 0x755a, 0x756b,
+	0x7573, 0x7589, 0x7573, 0x75ea, 0x755a, 0x760b, 0x7613, 0x756b,
+	0x7613, 0x7624, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7,
+	0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x72f7, 0x7e85, 0x7eaa, 0x7ebf,
+	0x7ee2, 0x7f03, 0x7549, 0x72f7, 0x7549, 0x7573, 0x72f7, 0x7420,
+	0x74ed, 0x72f7, 0x834f, 0x7573, 0x72f7, 0x836f, 0x7573, 0x72f7,
+	0x756b, 0x73a1, 0x730c, 0x72f7, 0x8394, 0x8409, 0x84e0, 0x72f7,
+	0x84f1, 0x7544, 0x850d, 0x72f7, 0x7f18, 0x8568, 0x72f7, 0x080c,
+	0x1515, 0x2100, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e,
+	0x0005, 0x730a, 0x730a, 0x730a, 0x7340, 0x735e, 0x7374, 0x730a,
+	0x730a, 0x730a, 0x080c, 0x1515, 0x00d6, 0x20a1, 0x020b, 0x080c,
+	0x7641, 0x7810, 0x2068, 0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3,
+	0x0800, 0x683c, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7d67, 0x00de,
+	0x0005, 0x00d6, 0x7818, 0x2068, 0x68a0, 0x2069, 0xb500, 0x6ad4,
+	0xd2ac, 0x1110, 0xd0bc, 0x0110, 0xa085, 0x0001, 0x00de, 0x0005,
+	0x00d6, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x0500, 0x20a3,
+	0x0000, 0x7810, 0xa0e8, 0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2,
+	0x6810, 0x20a2, 0x6814, 0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2,
+	0x60c3, 0x0010, 0x080c, 0x7d67, 0x00de, 0x0005, 0x0156, 0x0146,
+	0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x7800, 0x20a3, 0x0000,
+	0x7808, 0x8007, 0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x080c,
+	0x7d67, 0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b,
+	0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0xdf10,
+	0x20a3, 0x0034, 0x2099, 0xb505, 0x20a9, 0x0004, 0x53a6, 0x2099,
+	0xb501, 0x20a9, 0x0004, 0x53a6, 0x2099, 0xb7c6, 0x20a9, 0x001a,
+	0x3304, 0x8007, 0x20a2, 0x9398, 0x1f04, 0x7390, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x004c, 0x080c, 0x7d67, 0x014e, 0x015e,
+	0x0005, 0x2001, 0xb515, 0x2004, 0x609a, 0x080c, 0x7d67, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3, 0x5200, 0x20a3, 0x0000,
+	0x00d6, 0x2069, 0xb552, 0x6804, 0xd084, 0x0150, 0x6828, 0x20a3,
+	0x0000, 0x0016, 0x080c, 0x2831, 0x21a2, 0x001e, 0x00de, 0x0028,
+	0x00de, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099,
+	0xb505, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb501, 0x53a6, 0x2001,
+	0xb535, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004,
+	0xa082, 0x007f, 0x0238, 0x2001, 0xb51c, 0x20a6, 0x2001, 0xb51d,
+	0x20a6, 0x0040, 0x20a3, 0x0000, 0x2001, 0xb515, 0x2004, 0xa084,
+	0x00ff, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c,
+	0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3,
+	0x0500, 0x20a3, 0x0000, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1138,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0238, 0x2001,
+	0xb51c, 0x20a6, 0x2001, 0xb51d, 0x20a6, 0x0040, 0x20a3, 0x0000,
+	0x2001, 0xb515, 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004,
+	0x2099, 0xb505, 0x53a6, 0x60c3, 0x0010, 0x080c, 0x7d67, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x7641, 0x00c6, 0x7818, 0x2060, 0x2001,
+	0x0000, 0x080c, 0x5313, 0x00ce, 0x7818, 0xa080, 0x0028, 0x2004,
+	0xa086, 0x007e, 0x1130, 0x20a3, 0x0400, 0x620c, 0xc2b4, 0x620e,
+	0x0010, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa086, 0x007e, 0x1904, 0x74af, 0x2001, 0xb535, 0x2004,
+	0xd0a4, 0x01c8, 0x2099, 0xb78e, 0x33a6, 0x9398, 0x20a3, 0x0000,
+	0x9398, 0x3304, 0xa084, 0x2000, 0x20a2, 0x9398, 0x33a6, 0x9398,
+	0x20a3, 0x0000, 0x9398, 0x2001, 0x2710, 0x20a2, 0x9398, 0x33a6,
+	0x9398, 0x33a6, 0x00d0, 0x2099, 0xb78e, 0x33a6, 0x9398, 0x33a6,
+	0x9398, 0x3304, 0x080c, 0x5acf, 0x1118, 0xa084, 0x37ff, 0x0010,
+	0xa084, 0x3fff, 0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099,
+	0xb505, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xb501, 0x53a6, 0x20a9,
+	0x0008, 0x20a3, 0x0000, 0x1f04, 0x7489, 0x20a9, 0x0008, 0x20a3,
+	0x0000, 0x1f04, 0x748f, 0x2099, 0xb796, 0x3304, 0xc0dd, 0x20a2,
+	0x2001, 0xb572, 0x2004, 0xd0e4, 0x0158, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004, 0x0010,
+	0x20a9, 0x0007, 0x20a3, 0x0000, 0x1f04, 0x74aa, 0x0468, 0x2001,
+	0xb535, 0x2004, 0xd0a4, 0x0140, 0x2001, 0xb78f, 0x2004, 0x60e3,
+	0x0000, 0x080c, 0x2872, 0x60e2, 0x2099, 0xb78e, 0x20a9, 0x0008,
+	0x53a6, 0x20a9, 0x0004, 0x2099, 0xb505, 0x53a6, 0x20a9, 0x0004,
+	0x2099, 0xb501, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04,
+	0x74cd, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x74d3, 0x2099,
+	0xb796, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000,
+	0x1f04, 0x74de, 0x20a9, 0x000a, 0x20a3, 0x0000, 0x1f04, 0x74e4,
+	0x60c3, 0x0074, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c,
+	0x7641, 0x20a3, 0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3,
+	0x2000, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6,
+	0x2079, 0xb552, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020,
+	0xd1a4, 0x0110, 0xa085, 0x0010, 0xa085, 0x0002, 0x00d6, 0x0804,
+	0x75cc, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3,
+	0x5000, 0x0804, 0x743b, 0x20a1, 0x020b, 0x080c, 0x7641, 0x20a3,
+	0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76d5,
+	0x0020, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c,
+	0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100,
+	0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008,
+	0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3,
+	0x0200, 0x0804, 0x743b, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3,
+	0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0110, 0x20a2, 0x0010,
+	0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67,
+	0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0210,
+	0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818, 0x2068, 0x6894, 0xa086,
+	0x0014, 0x1198, 0x699c, 0xa184, 0x0030, 0x0190, 0x6998, 0xa184,
+	0xc000, 0x1140, 0xd1ec, 0x0118, 0x20a3, 0x2100, 0x0058, 0x20a3,
+	0x0100, 0x0040, 0x20a3, 0x0400, 0x0028, 0x20a3, 0x0700, 0x0010,
+	0x700f, 0x0800, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2,
+	0x00f6, 0x2079, 0xb552, 0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085,
+	0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010, 0x2009, 0xb574, 0x210c,
+	0xd184, 0x1110, 0xa085, 0x0002, 0x0026, 0x2009, 0xb572, 0x210c,
+	0xd1e4, 0x0130, 0xc0c5, 0xa094, 0x0030, 0xa296, 0x0010, 0x0140,
+	0xd1ec, 0x0130, 0xa094, 0x0030, 0xa296, 0x0010, 0x0108, 0xc0bd,
+	0x002e, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x0014, 0x080c, 0x7d67,
+	0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0210,
+	0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3,
+	0x0200, 0x0804, 0x73ae, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3,
+	0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3,
+	0x0008, 0x080c, 0x7d67, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x000b, 0x20a3, 0x0000, 0x60c3, 0x0008, 0x080c, 0x7d67,
+	0x0005, 0x0026, 0x0036, 0x0046, 0x2019, 0x3200, 0x2021, 0x0800,
+	0x0038, 0x0026, 0x0036, 0x0046, 0x2019, 0x2200, 0x2021, 0x0100,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014,
+	0xa286, 0x007e, 0x11a0, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe,
+	0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x2001, 0xb79e, 0x2004,
+	0xa005, 0x0118, 0x2011, 0xb51d, 0x2214, 0x22a2, 0x04d0, 0xa286,
+	0x007f, 0x1138, 0x00d6, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd,
+	0x00c8, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1110, 0xd2bc, 0x01c8,
+	0xa286, 0x0080, 0x00d6, 0x1130, 0xa385, 0x00ff, 0x20a2, 0x20a3,
+	0xfffc, 0x0040, 0xa2e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de,
+	0x0080, 0x00d6, 0xa2e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2,
+	0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214,
+	0x22a2, 0xa485, 0x0029, 0x20a2, 0x004e, 0x003e, 0x20a3, 0x0000,
+	0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x0026, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2,
+	0x00d6, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x20a3,
+	0x2029, 0x20a3, 0x0000, 0x08e0, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0xfc02, 0x20a3, 0x0000, 0x0005, 0x0026, 0x0036, 0x0046,
+	0x2019, 0x3300, 0x2021, 0x0800, 0x0038, 0x0026, 0x0036, 0x0046,
+	0x2019, 0x2300, 0x2021, 0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac,
+	0x1118, 0xa092, 0x007e, 0x02d8, 0x00d6, 0xa0e8, 0xb635, 0x2d6c,
+	0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x6810, 0xa005, 0x1140,
+	0x6814, 0xa005, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2,
+	0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0xa485,
+	0x0098, 0x20a2, 0x20a3, 0x0000, 0x004e, 0x003e, 0x080c, 0x7d56,
+	0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x002e, 0x0005, 0x080c, 0x7d56, 0x22a2, 0x20a3,
+	0x0000, 0x7a08, 0x22a2, 0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x002e, 0x0005, 0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085,
+	0x0a0c, 0x1515, 0xa08a, 0x008c, 0x1a0c, 0x1515, 0x6118, 0x2178,
+	0x79a0, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150,
+	0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009,
+	0x0000, 0x0028, 0xa1f8, 0x2dc4, 0x2f0d, 0xa18c, 0x00ff, 0x2c78,
+	0x2061, 0x0100, 0x619a, 0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce,
+	0x0005, 0x777a, 0x7784, 0x779f, 0x7778, 0x7778, 0x7778, 0x777a,
+	0x080c, 0x1515, 0x0146, 0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000,
+	0x080c, 0x7d67, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c,
+	0x77eb, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810,
+	0x20a2, 0x20a3, 0x0000, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x014e, 0x0005, 0x0146,
+	0x20a1, 0x020b, 0x080c, 0x7825, 0x20a3, 0x0003, 0x20a3, 0x0300,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004, 0x080c, 0x7d67,
+	0x014e, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1118,
+	0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810,
+	0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6,
+	0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c,
+	0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3,
+	0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3,
+	0x0000, 0x0804, 0x76a8, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac,
+	0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xb635, 0x2d6c,
+	0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c,
+	0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635,
+	0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2, 0x6814, 0x20a2, 0x00de,
+	0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2, 0x2001, 0x0099,
+	0x20a2, 0x20a3, 0x0000, 0x0804, 0x7734, 0x0026, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011, 0xb535,
+	0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8,
+	0xb635, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x8500, 0x20a2, 0x6814,
+	0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2,
+	0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000, 0x0804, 0x7734, 0x00c6,
+	0x00f6, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x0a0c, 0x1515, 0xa08a,
+	0x0053, 0x1a0c, 0x1515, 0x7918, 0x2160, 0x61a0, 0x2011, 0xb535,
+	0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x6100, 0xd1f4, 0x0120,
+	0x6114, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0,
+	0x2dc4, 0x2c0d, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082,
+	0x0040, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x78a2, 0x79ae, 0x794b,
+	0x7b60, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0, 0x78a0,
+	0x80d7, 0x80e7, 0x80f7, 0x8107, 0x78a0, 0x851e, 0x78a0, 0x80c6,
+	0x080c, 0x1515, 0x00d6, 0x0156, 0x0146, 0x780b, 0xffff, 0x20a1,
+	0x020b, 0x080c, 0x7902, 0x7910, 0x2168, 0x6948, 0x7952, 0x21a2,
+	0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x000f, 0x1118,
+	0x2001, 0x0005, 0x0040, 0xd184, 0x0118, 0x2001, 0x0004, 0x0018,
+	0xa084, 0x0006, 0x8004, 0x0016, 0x2008, 0x7858, 0xa084, 0x00ff,
+	0x8007, 0xa105, 0x001e, 0x20a2, 0xd1ac, 0x0118, 0x20a3, 0x0002,
+	0x0048, 0xd1b4, 0x0118, 0x20a3, 0x0001, 0x0020, 0x20a3, 0x0000,
+	0x2230, 0x0010, 0x6a80, 0x6e7c, 0x20a9, 0x0008, 0x0136, 0xad88,
+	0x0017, 0x2198, 0x20a1, 0x021b, 0x53a6, 0x013e, 0x20a1, 0x020b,
+	0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084,
+	0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xb7fc, 0x2003, 0x07d0,
+	0x2001, 0xb7fb, 0x2003, 0x0009, 0x080c, 0x17e2, 0x014e, 0x015e,
+	0x00de, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280,
+	0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2019, 0xb535, 0x231c, 0xd3ac, 0x1110,
+	0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085,
+	0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68,
+	0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810,
+	0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000,
+	0x2009, 0xb515, 0x210c, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000,
+	0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1,
+	0x020b, 0x00c1, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2,
+	0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2,
+	0x20a2, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x014e, 0x013e, 0x015e,
+	0x00de, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110,
+	0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085,
+	0x0500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68,
+	0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810,
+	0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000,
+	0x2011, 0xb515, 0x2214, 0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000,
+	0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00d6, 0x0156,
+	0x0136, 0x0146, 0x7810, 0xa0ec, 0xf000, 0x0168, 0xa06d, 0x080c,
+	0x5301, 0x0148, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020, 0x1118,
+	0x7820, 0xc0cd, 0x7822, 0x20a1, 0x020b, 0x080c, 0x7b16, 0xa016,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810, 0xa084, 0xf000,
+	0x1130, 0x7810, 0xa084, 0x0700, 0x8007, 0x0043, 0x0010, 0xa006,
+	0x002b, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x79e8, 0x7a7d,
+	0x7a8d, 0x7abf, 0x7ad2, 0x7aed, 0x7af6, 0x79e6, 0x080c, 0x1515,
+	0x0016, 0x0036, 0x694c, 0xa18c, 0x0003, 0x0118, 0xa186, 0x0003,
+	0x1170, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5, 0x23a2, 0x6868,
+	0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804, 0x7ac9, 0xa186,
+	0x0001, 0x190c, 0x1515, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5,
+	0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2, 0x6874, 0x20a2,
+	0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384, 0x0300, 0x0904,
+	0x7a77, 0xd3c4, 0x0110, 0x687c, 0xa108, 0xd3cc, 0x0110, 0x6874,
+	0xa108, 0x0156, 0x20a9, 0x000d, 0xad80, 0x0020, 0x201c, 0x831f,
+	0x23a2, 0x8000, 0x1f04, 0x7a26, 0x015e, 0x22a2, 0x22a2, 0x22a2,
+	0xa184, 0x0003, 0x0904, 0x7a77, 0x20a1, 0x020b, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011,
+	0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8,
+	0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814,
+	0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2,
+	0x000e, 0x7b20, 0xd3cc, 0x0118, 0x20a3, 0x0889, 0x0010, 0x20a3,
+	0x0898, 0x20a2, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x61c2,
+	0x003e, 0x001e, 0x080c, 0x7d67, 0x0005, 0x2011, 0x0008, 0x2001,
+	0xb50d, 0x2004, 0xd0f4, 0x0110, 0x2011, 0x0028, 0x7820, 0xd0cc,
+	0x0108, 0xc2e5, 0x22a2, 0xa016, 0x04d0, 0x2011, 0x0302, 0x0016,
+	0x0036, 0x7828, 0x792c, 0xa11d, 0x0108, 0xc2dd, 0x7b20, 0xd3cc,
+	0x0108, 0xc2e5, 0x22a2, 0x20a2, 0x21a2, 0x003e, 0x001e, 0xa016,
+	0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008, 0x22a2, 0x22a2,
+	0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500, 0x22a2, 0x20a3,
+	0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2, 0x22a2, 0x22a2,
+	0x22a2, 0x22a2, 0x60c3, 0x0032, 0x080c, 0x7d67, 0x0005, 0x2011,
+	0x0028, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x22a2,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0018, 0x080c,
+	0x7d67, 0x0005, 0x2011, 0x0100, 0x7820, 0xd0cc, 0x0108, 0xc2e5,
+	0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3,
+	0x0008, 0x22a2, 0x7854, 0xa084, 0x00ff, 0x20a2, 0x22a2, 0x22a2,
+	0x60c3, 0x0020, 0x080c, 0x7d67, 0x0005, 0x2011, 0x0008, 0x7820,
+	0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0888, 0x0036, 0x7b10,
+	0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x1138, 0x7820,
+	0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0x003e, 0x0808, 0x0046, 0x2021,
+	0x0800, 0x0006, 0x7820, 0xd0cc, 0x000e, 0x0108, 0xc4e5, 0x24a2,
+	0x004e, 0x22a2, 0x20a2, 0x003e, 0x0804, 0x7ac9, 0x0026, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011,
+	0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8,
+	0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814,
+	0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2,
+	0x7820, 0xd0cc, 0x0118, 0x20a3, 0x0889, 0x0010, 0x20a3, 0x0898,
+	0x20a3, 0x0000, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000, 0x7a08,
+	0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005,
+	0x00d6, 0x0156, 0x0136, 0x0146, 0x0016, 0x0036, 0x7810, 0xa084,
+	0x0700, 0x8007, 0x003b, 0x003e, 0x001e, 0x014e, 0x013e, 0x015e,
+	0x00de, 0x0005, 0x7b7a, 0x7b7a, 0x7b7c, 0x7b7a, 0x7b7a, 0x7b7a,
+	0x7b9e, 0x7b7a, 0x080c, 0x1515, 0x7910, 0xa18c, 0xf8ff, 0xa18d,
+	0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003, 0x00f9, 0x00d6,
+	0x2069, 0xb552, 0x6804, 0xd0bc, 0x0130, 0x682c, 0xa084, 0x00ff,
+	0x8007, 0x20a2, 0x0010, 0x20a3, 0x3f00, 0x00de, 0x22a2, 0x22a2,
+	0x22a2, 0x60c3, 0x0001, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b,
+	0x2009, 0x0003, 0x0019, 0x20a3, 0x7f00, 0x0c80, 0x0026, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0x2011,
+	0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6, 0xa0e8,
+	0xb635, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2, 0x6814,
+	0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xb515, 0x2214, 0x22a2,
+	0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x080c, 0x7d56, 0x22a2,
+	0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0056, 0x0046,
+	0x0036, 0x2061, 0x0100, 0x2071, 0xb500, 0x7154, 0x7818, 0x2068,
+	0x68a0, 0x2028, 0x76d4, 0xd6ac, 0x1130, 0xd0bc, 0x1120, 0x6910,
+	0x6a14, 0x7454, 0x0020, 0x6910, 0x6a14, 0x7370, 0x7474, 0x781c,
+	0xa0be, 0x0006, 0x0904, 0x7ca1, 0xa0be, 0x000a, 0x15e8, 0xa185,
+	0x0200, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x2029, 0x6077,
+	0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e, 0x8007, 0x607a,
+	0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086, 0x7810, 0x2070,
+	0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca,
+	0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x609f, 0x0000,
+	0x080c, 0x85b9, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005,
+	0x0110, 0x2009, 0x1b58, 0x080c, 0x6a15, 0x003e, 0x004e, 0x005e,
+	0x00ce, 0x00de, 0x00ee, 0x0005, 0x70d4, 0xd0ac, 0x1110, 0xd5bc,
+	0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038,
+	0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073,
+	0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086,
+	0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6,
+	0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294,
+	0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x85b9, 0x2009,
+	0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, 0x0110, 0x2009, 0x1b58,
+	0x080c, 0x6a15, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee,
+	0x0005, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002,
+	0x0904, 0x7cf7, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1110, 0xd5bc,
+	0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038,
+	0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073,
+	0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x7834, 0x607e, 0x2f00, 0x6086, 0x7808, 0x6082,
+	0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6, 0x707c, 0x60ca,
+	0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928, 0xa109, 0x792a,
+	0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080,
+	0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010,
+	0x2011, 0x0000, 0x629e, 0x080c, 0x85b6, 0x0804, 0x7c8f, 0x2001,
+	0xb535, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138, 0xa185, 0x0700,
+	0x6062, 0x6266, 0x636a, 0x646e, 0x0038, 0xa185, 0x0700, 0x6062,
+	0x6266, 0x606b, 0x0000, 0x646e, 0x080c, 0x5301, 0x0180, 0x00d6,
+	0x7810, 0xa06d, 0x684c, 0x00de, 0xa084, 0x2020, 0xa086, 0x2020,
+	0x1130, 0x7820, 0xc0cd, 0x7822, 0x6073, 0x0889, 0x0010, 0x6073,
+	0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082,
+	0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca,
+	0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080,
+	0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294, 0x00ff, 0x0010,
+	0x2011, 0x0000, 0x629e, 0x7820, 0xd0cc, 0x0120, 0x080c, 0x85b9,
+	0x0804, 0x7c8f, 0x080c, 0x85b6, 0x0804, 0x7c8f, 0x7a18, 0xa280,
+	0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x0005,
+	0x00d6, 0x2069, 0xb7e0, 0x6843, 0x0001, 0x00de, 0x0005, 0x20e1,
+	0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x0019, 0x080c, 0x6a07,
+	0x0005, 0x0006, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016,
+	0x000e, 0x0005, 0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, 0x61a4,
+	0x60a7, 0x95f5, 0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016,
+	0x000e, 0xe000, 0xe000, 0xe000, 0xe000, 0x61a6, 0x00ce, 0x001e,
+	0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x080c, 0x5acf, 0x1198, 0x2001, 0xb7fc, 0x2004, 0xa005,
+	0x15b8, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, 0x006e, 0x1118,
+	0x080c, 0x6a07, 0x0468, 0x00c6, 0x2061, 0xb7e0, 0x00d8, 0x6904,
+	0xa194, 0x4000, 0x0550, 0x0831, 0x6803, 0x1000, 0x6803, 0x0000,
+	0x00c6, 0x2061, 0xb7e0, 0x6128, 0xa192, 0x00c8, 0x1258, 0x8108,
+	0x612a, 0x6124, 0x00ce, 0x81ff, 0x0198, 0x080c, 0x6a07, 0x080c,
+	0x7d71, 0x0070, 0x6124, 0xa1e5, 0x0000, 0x0140, 0x080c, 0xb444,
+	0x080c, 0x6a10, 0x2009, 0x0014, 0x080c, 0x864c, 0x00ce, 0x0000,
+	0x002e, 0x001e, 0x00de, 0x00ce, 0x0005, 0x2001, 0xb7fc, 0x2004,
+	0xa005, 0x1db0, 0x00c6, 0x2061, 0xb7e0, 0x6128, 0xa192, 0x0003,
+	0x1e08, 0x8108, 0x612a, 0x00ce, 0x080c, 0x6a07, 0x080c, 0x4b1f,
+	0x0c38, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c, 0x6a1d,
+	0x2071, 0xb7e0, 0x713c, 0x81ff, 0x0590, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x080c, 0x5acf, 0x11a8, 0x0036, 0x2019, 0x0002, 0x080c,
+	0x7fe4, 0x003e, 0x713c, 0x2160, 0x080c, 0xb444, 0x2009, 0x004a,
+	0x080c, 0x864c, 0x0066, 0x2031, 0x0001, 0x080c, 0x5b51, 0x006e,
+	0x00b0, 0x6904, 0xa194, 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x003e, 0x713c,
+	0x2160, 0x080c, 0xb444, 0x2009, 0x004a, 0x080c, 0x864c, 0x002e,
+	0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0c58, 0x0026, 0x00e6,
+	0x2071, 0xb7e0, 0x7048, 0xd084, 0x01c0, 0x713c, 0x81ff, 0x01a8,
+	0x2071, 0x0100, 0xa188, 0x0007, 0x2114, 0xa28e, 0x0006, 0x1138,
+	0x7014, 0xa084, 0x0184, 0xa085, 0x0012, 0x7016, 0x0030, 0x7014,
+	0xa084, 0x0184, 0xa085, 0x0016, 0x7016, 0x00ee, 0x002e, 0x0005,
+	0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056, 0x0046, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, 0x2071, 0xb7e0, 0x7018,
+	0x2068, 0x8dff, 0x0188, 0x68a0, 0xa406, 0x0118, 0x6854, 0x2068,
+	0x0cc0, 0x6010, 0x2060, 0x643c, 0x6540, 0x6648, 0x2d60, 0x080c,
+	0x511a, 0x0110, 0xa085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x20a1, 0x020b, 0x080c,
+	0x7641, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c,
+	0xa086, 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0xb515, 0x2004,
+	0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006,
+	0x20a2, 0x1f04, 0x7ea0, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x080c,
+	0x7d67, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x7641,
+	0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2,
+	0x60c3, 0x0008, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3,
+	0x0000, 0x20a9, 0x0006, 0x2011, 0xb540, 0x2019, 0xb541, 0x23a6,
+	0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x7ecf, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7d67, 0x014e,
+	0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b,
+	0x080c, 0x76b6, 0x080c, 0x76cc, 0x7810, 0xa080, 0x0000, 0x2004,
+	0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6,
+	0xa080, 0x0004, 0x8003, 0x60c2, 0x080c, 0x7d67, 0x002e, 0x001e,
+	0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c,
+	0x7641, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808,
+	0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005,
+	0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, 0x080c, 0x7641,
+	0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808,
+	0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x080c, 0x7d67,
+	0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006,
+	0x0126, 0x2091, 0x8000, 0x2071, 0xb7e0, 0x700c, 0x2060, 0x8cff,
+	0x0178, 0x080c, 0x9e58, 0x1110, 0x080c, 0x8c19, 0x600c, 0x0006,
+	0x080c, 0xa01f, 0x080c, 0x861d, 0x080c, 0x811e, 0x00ce, 0x0c78,
+	0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, 0x00ce, 0x00ee,
+	0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026,
+	0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140,
+	0x2071, 0xb7e0, 0x7024, 0x2060, 0x8cff, 0x05a0, 0x080c, 0x7d7a,
+	0x68c3, 0x0000, 0x080c, 0x6a10, 0x2009, 0x0013, 0x080c, 0x864c,
+	0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804,
+	0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078,
+	0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x7f7a, 0x7804,
+	0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824,
+	0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e,
+	0x012e, 0x0005, 0x2001, 0xb500, 0x2004, 0xa096, 0x0001, 0x0590,
+	0xa096, 0x0004, 0x0578, 0x080c, 0x6a10, 0x6814, 0xa084, 0x0001,
+	0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011,
+	0x4adc, 0x080c, 0x699c, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158,
+	0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000,
+	0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010,
+	0x1f04, 0x7fbd, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100,
+	0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069,
+	0x0100, 0x2079, 0x0140, 0x2071, 0xb7e0, 0x703c, 0x2060, 0x8cff,
+	0x0904, 0x806b, 0xa386, 0x0002, 0x1128, 0x6814, 0xa084, 0x0002,
+	0x0904, 0x806b, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa,
+	0x8109, 0x1df0, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x080c, 0x6a1d,
+	0x080c, 0x220c, 0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021,
+	0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x1500, 0x68af,
+	0x95f5, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x00e6, 0x00f6, 0x2079,
+	0x0020, 0x2071, 0xb84a, 0x6814, 0xa084, 0x0184, 0xa085, 0x0012,
+	0x6816, 0x7803, 0x0008, 0x7003, 0x0000, 0x00fe, 0x00ee, 0xa386,
+	0x0002, 0x1128, 0x7884, 0xa005, 0x1110, 0x7887, 0x0001, 0x2001,
+	0xb7b1, 0x2004, 0x200a, 0x004e, 0xa39d, 0x0000, 0x1120, 0x2009,
+	0x0049, 0x080c, 0x864c, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0158,
+	0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000,
+	0x7803, 0x0000, 0x0078, 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010,
+	0x1f04, 0x804d, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100,
+	0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de,
+	0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x2069, 0xb7e0, 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6,
+	0x0126, 0x2091, 0x8000, 0x2069, 0xb7e0, 0x6a32, 0x012e, 0x00de,
+	0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006, 0x0126, 0x2071,
+	0xb7e0, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0538,
+	0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616,
+	0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012,
+	0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0x9e1d, 0x080c,
+	0x811e, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060, 0x08b8, 0x012e,
+	0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0156, 0x0146,
+	0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804, 0x8116, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0478, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x00f8, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x7902, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200, 0x0089, 0x60c3,
+	0x0020, 0x080c, 0x7d67, 0x014e, 0x015e, 0x0005, 0x00e6, 0x2071,
+	0xb7e0, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022, 0x00ee, 0x0005,
+	0x20a9, 0x0008, 0x20a2, 0x1f04, 0x812a, 0x20a2, 0x20a2, 0x0005,
+	0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0xb7e0, 0x7614, 0x2660, 0x2678, 0x2039,
+	0x0001, 0x87ff, 0x0904, 0x81c6, 0x8cff, 0x0904, 0x81c6, 0x601c,
+	0xa086, 0x0006, 0x1904, 0x81c1, 0x88ff, 0x0138, 0x2800, 0xac06,
+	0x1904, 0x81c1, 0x2039, 0x0000, 0x0050, 0x6018, 0xa206, 0x1904,
+	0x81c1, 0x85ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x81c1, 0x7024,
+	0xac06, 0x1598, 0x2069, 0x0100, 0x68c0, 0xa005, 0x1160, 0x6824,
+	0xd084, 0x0148, 0x6827, 0x0001, 0x080c, 0x6a10, 0x080c, 0x824d,
+	0x7027, 0x0000, 0x0410, 0x080c, 0x6a10, 0x6820, 0xd0b4, 0x0110,
+	0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, 0x824d,
+	0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000,
+	0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x7014, 0xac36, 0x1110,
+	0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118,
+	0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00,
+	0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1158, 0x600f,
+	0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110, 0x080c, 0xb099,
+	0x080c, 0x9e1d, 0x080c, 0x811e, 0x88ff, 0x1190, 0x00ce, 0x0804,
+	0x8141, 0x2c78, 0x600c, 0x2060, 0x0804, 0x8141, 0xa006, 0x012e,
+	0x000e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005,
+	0x6017, 0x0000, 0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000,
+	0x2071, 0xb7e0, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x823d,
+	0x601c, 0xa086, 0x0006, 0x1904, 0x8238, 0x87ff, 0x0128, 0x2700,
+	0xac06, 0x1904, 0x8238, 0x0048, 0x6018, 0xa206, 0x1904, 0x8238,
+	0x85ff, 0x0118, 0x6050, 0xa106, 0x15d8, 0x703c, 0xac06, 0x1180,
+	0x0036, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x7033, 0x0000, 0x703f,
+	0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x704b, 0x0000, 0x003e,
+	0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140,
+	0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110, 0x080c,
+	0xb099, 0x080c, 0x9e1d, 0x87ff, 0x1190, 0x00ce, 0x0804, 0x81e5,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0x81e5, 0xa006, 0x012e, 0x000e,
+	0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017,
+	0x0000, 0x00ce, 0xa7bd, 0x0001, 0x0c88, 0x00e6, 0x2071, 0xb7e0,
+	0x2001, 0xb500, 0x2004, 0xa086, 0x0002, 0x1118, 0x7007, 0x0005,
+	0x0010, 0x7007, 0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00c6,
+	0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xb7e0,
+	0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0518, 0x2200, 0xac06,
+	0x11e0, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36,
+	0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037,
+	0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0xa085, 0x0001, 0x0020, 0x2c78, 0x600c, 0x2060,
+	0x08d8, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0xb7e0, 0x760c, 0x2660, 0x2678, 0x8cff,
+	0x0904, 0x8323, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904,
+	0x831e, 0x7024, 0xac06, 0x1508, 0x2069, 0x0100, 0x68c0, 0xa005,
+	0x0904, 0x82fa, 0x080c, 0x7d7a, 0x68c3, 0x0000, 0x080c, 0x824d,
+	0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000,
+	0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0xac36, 0x1110,
+	0x660c, 0x760e, 0x7008, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118,
+	0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00,
+	0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c,
+	0x9e47, 0x1158, 0x080c, 0x2cc2, 0x080c, 0x9e58, 0x11f0, 0x080c,
+	0x8c19, 0x00d8, 0x080c, 0x824d, 0x08c0, 0x080c, 0x9e58, 0x1118,
+	0x080c, 0x8c19, 0x0090, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0168,
+	0x601c, 0xa086, 0x0003, 0x11f8, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0xa01f, 0x080c,
+	0x9e1d, 0x080c, 0x811e, 0x00ce, 0x0804, 0x82a7, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0x82a7, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00de,
+	0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x1d30, 0x080c,
+	0xb099, 0x0c18, 0x0036, 0x0156, 0x0136, 0x0146, 0x3908, 0xa006,
+	0xa190, 0x0020, 0x221c, 0xa39e, 0x2ab7, 0x1118, 0x8210, 0x8000,
+	0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020, 0x2198, 0xa110, 0x22a0,
+	0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e, 0x003e, 0x0005, 0x00d6,
+	0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0200, 0x20a3, 0x0014,
+	0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2099, 0xb7b9,
+	0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x080c, 0x7d67, 0x00de, 0x0005, 0x20a1,
+	0x020b, 0x080c, 0x76dd, 0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3,
+	0x0800, 0x7810, 0xa084, 0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff,
+	0x20a2, 0x7828, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0018, 0x080c, 0x7d67, 0x0005, 0x00d6, 0x0016, 0x2f68, 0x2009,
+	0x0035, 0x080c, 0xa10a, 0x1904, 0x8402, 0x20a1, 0x020b, 0x080c,
+	0x7641, 0x20a3, 0x1300, 0x20a3, 0x0000, 0x7828, 0x2068, 0x681c,
+	0xa086, 0x0003, 0x0580, 0x7818, 0xa080, 0x0028, 0x2014, 0x2001,
+	0xb535, 0x2004, 0xd0ac, 0x11d0, 0xa286, 0x007e, 0x1128, 0x20a3,
+	0x00ff, 0x20a3, 0xfffe, 0x04b8, 0xa286, 0x007f, 0x1128, 0x20a3,
+	0x00ff, 0x20a3, 0xfffd, 0x0478, 0xd2bc, 0x0180, 0xa286, 0x0080,
+	0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0428, 0xa2e8, 0xb635,
+	0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x00e8, 0x20a3, 0x0000,
+	0x6098, 0x20a2, 0x00c0, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1138,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007e, 0x0240, 0x00d6,
+	0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0020, 0x20a3,
+	0x0000, 0x6034, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c, 0x080c, 0x7d67, 0x001e,
+	0x00de, 0x0005, 0x7817, 0x0001, 0x7803, 0x0006, 0x001e, 0x00de,
+	0x0005, 0x00d6, 0x0026, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006,
+	0x01c0, 0xa186, 0x0003, 0x0904, 0x8478, 0xa186, 0x0005, 0x0904,
+	0x8461, 0xa186, 0x0004, 0x05b8, 0xa186, 0x0008, 0x0904, 0x8469,
+	0x7807, 0x0037, 0x7813, 0x1700, 0x080c, 0x84e0, 0x002e, 0x00de,
+	0x0005, 0x080c, 0x849c, 0x2009, 0x4000, 0x6800, 0x0002, 0x8442,
+	0x844d, 0x8444, 0x844d, 0x8449, 0x8442, 0x8442, 0x844d, 0x844d,
+	0x844d, 0x844d, 0x8442, 0x8442, 0x8442, 0x8442, 0x8442, 0x844d,
+	0x8442, 0x844d, 0x080c, 0x1515, 0x6820, 0xd0e4, 0x0110, 0xd0cc,
+	0x0110, 0xa00e, 0x0010, 0x2009, 0x2000, 0x6828, 0x20a2, 0x682c,
+	0x20a2, 0x0804, 0x8492, 0x080c, 0x849c, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x2009, 0x4000, 0x6a00, 0xa286, 0x0002, 0x1108, 0xa00e,
+	0x0488, 0x04d1, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0x0448, 0x0491, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0xa286, 0x0005, 0x0118, 0xa286, 0x0002, 0x1108, 0xa00e, 0x00d0,
+	0x0419, 0x6810, 0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814,
+	0xa103, 0x20a2, 0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e,
+	0x0002, 0x0130, 0xa08e, 0x0004, 0x0118, 0x2009, 0x4000, 0x0010,
+	0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c,
+	0x7d67, 0x002e, 0x00de, 0x0005, 0x0036, 0x0046, 0x0056, 0x0066,
+	0x20a1, 0x020b, 0x080c, 0x76dd, 0xa006, 0x20a3, 0x0200, 0x20a2,
+	0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028, 0x2004,
+	0x2011, 0xb535, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0268,
+	0x00d6, 0x2069, 0xb51c, 0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xb635,
+	0x2d6c, 0x6b10, 0x6c14, 0x00de, 0x0030, 0x2019, 0x0000, 0x6498,
+	0x2029, 0x0000, 0x6634, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086,
+	0x0003, 0x1128, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0020, 0x23a2,
+	0x24a2, 0x25a2, 0x26a2, 0x006e, 0x005e, 0x004e, 0x003e, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x76dd, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67,
+	0x0005, 0x20a1, 0x020b, 0x080c, 0x7639, 0x20a3, 0x1400, 0x20a3,
+	0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c,
+	0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000,
+	0x60c3, 0x0010, 0x080c, 0x7d67, 0x0005, 0x20a1, 0x020b, 0x080c,
+	0x76d5, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810,
+	0x20a2, 0x60c3, 0x0008, 0x080c, 0x7d67, 0x0005, 0x0146, 0x20a1,
+	0x020b, 0x0031, 0x60c3, 0x0000, 0x080c, 0x7d67, 0x014e, 0x0005,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004,
+	0x2011, 0xb535, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6,
+	0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2, 0x6814,
+	0x20a2, 0x2069, 0xb51c, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0078,
+	0x00d6, 0xa0e8, 0xb635, 0x2d6c, 0x6810, 0xa085, 0x0300, 0x20a2,
+	0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x6234, 0x22a2, 0x20a3,
+	0x0819, 0x20a3, 0x0000, 0x080c, 0x7d56, 0x22a2, 0x20a3, 0x0000,
+	0x2fa2, 0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005,
+	0x20a1, 0x020b, 0x0079, 0x7910, 0x21a2, 0x20a3, 0x0000, 0x60c3,
+	0x0000, 0x20e1, 0x9080, 0x60a7, 0x9575, 0x080c, 0x7d71, 0x080c,
+	0x6a07, 0x0005, 0x0156, 0x0136, 0x0036, 0x00d6, 0x00e6, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7854, 0x2068, 0xadf0, 0x000f, 0x7210,
+	0xa296, 0x00c0, 0xa294, 0xfffd, 0x7212, 0x7214, 0xa294, 0x0300,
+	0x7216, 0x7100, 0xa194, 0x00ff, 0x7308, 0xa384, 0x00ff, 0xa08d,
+	0xc200, 0x7102, 0xa384, 0xff00, 0xa215, 0x720a, 0x7004, 0x720c,
+	0x700e, 0x7206, 0x20a9, 0x000a, 0x2e98, 0x53a6, 0x60a3, 0x0035,
+	0x6a38, 0xa294, 0x7000, 0xa286, 0x3000, 0x0110, 0x60a3, 0x0037,
+	0x00ee, 0x00de, 0x003e, 0x013e, 0x015e, 0x0005, 0x2009, 0x0092,
+	0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, 0x6116, 0x0005, 0x2061,
+	0xbd00, 0x2a70, 0x7068, 0x704a, 0x704f, 0xbd00, 0x0005, 0x00e6,
+	0x0126, 0x2071, 0xb500, 0x2091, 0x8000, 0x7548, 0xa582, 0x0010,
+	0x0608, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0,
+	0x0018, 0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xbd00, 0x0c98,
+	0x6003, 0x0008, 0x8529, 0x754a, 0xaca8, 0x0018, 0x705c, 0xa502,
+	0x1230, 0x754e, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704f,
+	0xbd00, 0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xb500, 0x7548,
+	0xa582, 0x0010, 0x0600, 0x704c, 0x2060, 0x6000, 0xa086, 0x0000,
+	0x0148, 0xace0, 0x0018, 0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061,
+	0xbd00, 0x0c98, 0x6003, 0x0008, 0x8529, 0x754a, 0xaca8, 0x0018,
+	0x705c, 0xa502, 0x1228, 0x754e, 0xa085, 0x0001, 0x00ee, 0x0005,
+	0x704f, 0xbd00, 0x0cc8, 0xa006, 0x0cc8, 0xac82, 0xbd00, 0x0a0c,
+	0x1515, 0x2001, 0xb517, 0x2004, 0xac02, 0x1a0c, 0x1515, 0xa006,
+	0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000,
+	0x6003, 0x0000, 0x6052, 0x6056, 0x6022, 0x6026, 0x602a, 0x602e,
+	0x6032, 0x6036, 0x603a, 0x603e, 0x2061, 0xb500, 0x6048, 0x8000,
+	0x604a, 0xa086, 0x0001, 0x0108, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x7173, 0x012e, 0x0cc0, 0x601c, 0xa084, 0x000f, 0x0002,
+	0x865b, 0x866a, 0x8685, 0x86a0, 0xa152, 0xa16d, 0xa188, 0x865b,
+	0x866a, 0x865b, 0x86bb, 0xa186, 0x0013, 0x1128, 0x080c, 0x7090,
+	0x080c, 0x7173, 0x0005, 0xa18e, 0x0047, 0x1118, 0xa016, 0x080c,
+	0x185e, 0x0005, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515,
+	0x0013, 0x006e, 0x0005, 0x8683, 0x8a9b, 0x8c53, 0x8683, 0x8cc8,
+	0x8779, 0x8683, 0x8683, 0x8a2d, 0x90ef, 0x8683, 0x8683, 0x8683,
+	0x8683, 0x8683, 0x8683, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2,
+	0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, 0x0005, 0x869e, 0x9722,
+	0x869e, 0x869e, 0x869e, 0x869e, 0x869e, 0x869e, 0x96cd, 0x988e,
+	0x869e, 0x974f, 0x97c6, 0x974f, 0x97c6, 0x869e, 0x080c, 0x1515,
+	0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e,
+	0x0005, 0x86b9, 0x9130, 0x91fa, 0x9335, 0x9491, 0x86b9, 0x86b9,
+	0x86b9, 0x910a, 0x967d, 0x9680, 0x86b9, 0x86b9, 0x86b9, 0x86b9,
+	0x96aa, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c,
+	0x1515, 0x0013, 0x006e, 0x0005, 0x86d4, 0x86d4, 0x86d4, 0x8702,
+	0x874f, 0x86d4, 0x86d4, 0x86d4, 0x86d6, 0x86d4, 0x86d4, 0x86d4,
+	0x86d4, 0x86d4, 0x86d4, 0x86d4, 0x080c, 0x1515, 0xa186, 0x0003,
+	0x190c, 0x1515, 0x00d6, 0x6003, 0x0003, 0x6106, 0x6010, 0x2068,
+	0x684f, 0x0040, 0x687c, 0x680a, 0x6880, 0x680e, 0x6813, 0x0000,
+	0x6817, 0x0000, 0x6854, 0xa092, 0x199a, 0x0210, 0x2001, 0x1999,
+	0x8003, 0x8013, 0x8213, 0xa210, 0x6216, 0x00de, 0x2c10, 0x080c,
+	0x1fa9, 0x080c, 0x6cf0, 0x0126, 0x2091, 0x8000, 0x080c, 0x7230,
+	0x012e, 0x0005, 0xa182, 0x0047, 0x0002, 0x870e, 0x870e, 0x8710,
+	0x8729, 0x870e, 0x870e, 0x870e, 0x870e, 0x873b, 0x080c, 0x1515,
+	0x00d6, 0x0016, 0x080c, 0x7126, 0x080c, 0x7230, 0x6003, 0x0004,
+	0x6110, 0x2168, 0x684f, 0x0020, 0x685c, 0x685a, 0x6874, 0x687e,
+	0x6878, 0x6882, 0x6897, 0x0000, 0x689b, 0x0000, 0x001e, 0x00de,
+	0x0005, 0x080c, 0x7126, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9c5a,
+	0x0120, 0x684b, 0x0006, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d,
+	0x080c, 0x7230, 0x0005, 0x080c, 0x7126, 0x080c, 0x2c9c, 0x00d6,
+	0x6110, 0x2168, 0x080c, 0x9c5a, 0x0120, 0x684b, 0x0029, 0x080c,
+	0x5408, 0x00de, 0x080c, 0x861d, 0x080c, 0x7230, 0x0005, 0xa182,
+	0x0047, 0x0002, 0x875d, 0x876c, 0x875b, 0x875b, 0x875b, 0x875b,
+	0x875b, 0x875b, 0x875b, 0x080c, 0x1515, 0x00d6, 0x6010, 0x2068,
+	0x684c, 0xc0f4, 0x684e, 0x00de, 0x20e1, 0x0005, 0x3d18, 0x3e20,
+	0x2c10, 0x080c, 0x185e, 0x0005, 0x00d6, 0x6110, 0x2168, 0x684b,
+	0x0000, 0x6853, 0x0000, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d,
+	0x0005, 0xa1b6, 0x0015, 0x1118, 0x080c, 0x861d, 0x0030, 0xa1b6,
+	0x0016, 0x190c, 0x1515, 0x080c, 0x861d, 0x0005, 0x20a9, 0x000e,
+	0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420,
+	0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002,
+	0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x8794,
+	0x00e6, 0x080c, 0x9c5a, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000,
+	0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x0005, 0x00d6, 0x0036,
+	0x7330, 0xa386, 0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff,
+	0x6817, 0xfffd, 0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000,
+	0x6837, 0x0103, 0x6b32, 0x080c, 0x861d, 0x003e, 0x00de, 0x0005,
+	0x0016, 0x20a9, 0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080,
+	0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001,
+	0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004,
+	0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x001e, 0x0005,
+	0x0016, 0x2009, 0x0000, 0x7030, 0xa086, 0x0100, 0x0140, 0x7038,
+	0xa084, 0x00ff, 0x800c, 0x703c, 0xa084, 0x00ff, 0x8004, 0xa080,
+	0x0004, 0xa108, 0x21a8, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080,
+	0x0002, 0x20a0, 0x080c, 0x4b8f, 0x00e6, 0x080c, 0x9c5a, 0x0140,
+	0x6010, 0x2070, 0x7007, 0x0000, 0x7034, 0x70b2, 0x7037, 0x0103,
+	0x00ee, 0x080c, 0x861d, 0x001e, 0x0005, 0x00e6, 0x00d6, 0x603f,
+	0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, 0xa10a, 0x001e,
+	0x1168, 0x0026, 0x6228, 0x2268, 0x002e, 0x2071, 0xbb8c, 0x6b1c,
+	0xa386, 0x0003, 0x0130, 0xa386, 0x0006, 0x0128, 0x080c, 0x861d,
+	0x0020, 0x0031, 0x0010, 0x080c, 0x88f6, 0x00de, 0x00ee, 0x0005,
+	0x00f6, 0x6810, 0x2078, 0xa186, 0x0015, 0x0904, 0x88dd, 0xa18e,
+	0x0016, 0x1904, 0x88f4, 0x700c, 0xa08c, 0xff00, 0xa186, 0x1700,
+	0x0120, 0xa186, 0x0300, 0x1904, 0x88bc, 0x8fff, 0x1138, 0x6800,
+	0xa086, 0x000f, 0x0904, 0x88a0, 0x0804, 0x88f2, 0x6808, 0xa086,
+	0xffff, 0x1904, 0x88df, 0x784c, 0xa084, 0x0060, 0xa086, 0x0020,
+	0x1150, 0x797c, 0x7810, 0xa106, 0x1904, 0x88df, 0x7980, 0x7814,
+	0xa106, 0x1904, 0x88df, 0x080c, 0x9e11, 0x6858, 0x7852, 0x784c,
+	0xc0dc, 0xc0f4, 0xc0d4, 0x784e, 0x0026, 0xa00e, 0x6a14, 0x2001,
+	0x000a, 0x080c, 0x6b40, 0x7854, 0xa20a, 0x0208, 0x8011, 0x7a56,
+	0x82ff, 0x002e, 0x1138, 0x00c6, 0x2d60, 0x080c, 0x9a09, 0x00ce,
+	0x0804, 0x88f2, 0x00c6, 0x00d6, 0x2f68, 0x6838, 0xd0fc, 0x1118,
+	0x080c, 0x4c64, 0x0010, 0x080c, 0x4e49, 0x00de, 0x00ce, 0x1904,
+	0x88df, 0x00c6, 0x2d60, 0x080c, 0x861d, 0x00ce, 0x0804, 0x88f2,
+	0x00c6, 0x080c, 0x9ed6, 0x0190, 0x6013, 0x0000, 0x6818, 0x601a,
+	0x080c, 0xa027, 0x601f, 0x0003, 0x6904, 0x00c6, 0x2d60, 0x080c,
+	0x861d, 0x00ce, 0x080c, 0x864c, 0x00ce, 0x04e0, 0x2001, 0xb7b8,
+	0x2004, 0x683e, 0x00ce, 0x04b0, 0x7008, 0xa086, 0x000b, 0x11a0,
+	0x6018, 0x200c, 0xc1bc, 0x2102, 0x00c6, 0x2d60, 0x7853, 0x0003,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d,
+	0x080c, 0x7173, 0x00ce, 0x00f0, 0x700c, 0xa086, 0x2a00, 0x1138,
+	0x2001, 0xb7b8, 0x2004, 0x683e, 0x00a8, 0x0481, 0x00a8, 0x8fff,
+	0x090c, 0x1515, 0x00c6, 0x00d6, 0x2d60, 0x2f68, 0x6837, 0x0103,
+	0x684b, 0x0003, 0x080c, 0x98fd, 0x080c, 0x9e11, 0x080c, 0x9e1d,
+	0x00de, 0x00ce, 0x080c, 0x861d, 0x00fe, 0x0005, 0xa186, 0x0015,
+	0x1128, 0x2001, 0xb7b8, 0x2004, 0x683e, 0x0068, 0xa18e, 0x0016,
+	0x1160, 0x00c6, 0x2d00, 0x2060, 0x080c, 0xb33a, 0x080c, 0x6aef,
+	0x080c, 0x861d, 0x00ce, 0x080c, 0x861d, 0x0005, 0x0026, 0x0036,
+	0x0046, 0x7228, 0x7c80, 0x7b7c, 0xd2f4, 0x0130, 0x2001, 0xb7b8,
+	0x2004, 0x683e, 0x0804, 0x8970, 0x00c6, 0x2d60, 0x080c, 0x991d,
+	0x00ce, 0x6804, 0xa086, 0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060,
+	0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x6c8d, 0x080c, 0x7173,
+	0x00ce, 0x04f0, 0x6800, 0xa086, 0x000f, 0x01c8, 0x8fff, 0x090c,
+	0x1515, 0x6820, 0xd0dc, 0x1198, 0x6800, 0xa086, 0x0004, 0x1198,
+	0x784c, 0xd0ac, 0x0180, 0x784c, 0xc0dc, 0xc0f4, 0x784e, 0x7850,
+	0xc0f4, 0xc0fc, 0x7852, 0x2001, 0x0001, 0x682e, 0x00e0, 0x2001,
+	0x0007, 0x682e, 0x00c0, 0x784c, 0xd0b4, 0x1130, 0xd0ac, 0x0db8,
+	0x784c, 0xd0f4, 0x1da0, 0x0c38, 0xd2ec, 0x1d88, 0x7024, 0xa306,
+	0x1118, 0x7020, 0xa406, 0x0d58, 0x7020, 0x6836, 0x7024, 0x683a,
+	0x2001, 0x0005, 0x682e, 0x080c, 0x9f63, 0x080c, 0x7173, 0x0010,
+	0x080c, 0x861d, 0x004e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6,
+	0x0026, 0x6034, 0x2068, 0x6a1c, 0xa286, 0x0007, 0x0904, 0x89d4,
+	0xa286, 0x0002, 0x0904, 0x89d4, 0xa286, 0x0000, 0x0904, 0x89d4,
+	0x6808, 0x6338, 0xa306, 0x1904, 0x89d4, 0x2071, 0xbb8c, 0xa186,
+	0x0015, 0x05e0, 0xa18e, 0x0016, 0x1190, 0x6030, 0xa084, 0x00ff,
+	0xa086, 0x0001, 0x1160, 0x700c, 0xa086, 0x2a00, 0x1140, 0x6034,
+	0xa080, 0x0008, 0x200c, 0xc1dd, 0xc1f5, 0x2102, 0x0438, 0x00c6,
+	0x6034, 0x2060, 0x6104, 0xa186, 0x004b, 0x01a0, 0xa186, 0x004c,
+	0x0188, 0xa186, 0x004d, 0x0170, 0xa186, 0x004e, 0x0158, 0xa186,
+	0x0052, 0x0140, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x090c, 0x1515,
+	0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002,
+	0x080c, 0x6c8d, 0x080c, 0x7173, 0x00ce, 0x0030, 0x6034, 0x2070,
+	0x2001, 0xb7b8, 0x2004, 0x703e, 0x080c, 0x861d, 0x002e, 0x00de,
+	0x00ee, 0x0005, 0x00d6, 0x20a9, 0x000e, 0x2e98, 0x6010, 0x20a0,
+	0x53a3, 0xa1b6, 0x0015, 0x1558, 0x6018, 0x2068, 0x0156, 0x0036,
+	0x0026, 0xae90, 0x000c, 0xa290, 0x0004, 0x20a9, 0x0004, 0xad98,
+	0x000a, 0x080c, 0x90da, 0x002e, 0x003e, 0x015e, 0x11d8, 0x0156,
+	0x0036, 0x0026, 0xae90, 0x000c, 0xa290, 0x0008, 0x20a9, 0x0004,
+	0xad98, 0x0006, 0x080c, 0x90da, 0x002e, 0x003e, 0x015e, 0x1150,
+	0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, 0x00de,
+	0x0804, 0x87a0, 0x080c, 0x2c9c, 0x00c6, 0x080c, 0x85c7, 0x2f00,
+	0x601a, 0x6013, 0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003,
+	0x0001, 0x2001, 0x0007, 0x080c, 0x4efd, 0x080c, 0x4f2a, 0x080c,
+	0x6cd3, 0x080c, 0x7173, 0x00ce, 0x0c10, 0x2100, 0xa1b2, 0x0080,
+	0x1a0c, 0x1515, 0xa1b2, 0x0040, 0x1a04, 0x8a91, 0x0002, 0x8a85,
+	0x8a79, 0x8a85, 0x8a85, 0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77,
+	0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77,
+	0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77,
+	0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85, 0x8a77,
+	0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85,
+	0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77,
+	0x8a77, 0x8a85, 0x8a85, 0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a77,
+	0x8a77, 0x8a77, 0x8a77, 0x8a77, 0x8a85, 0x8a77, 0x8a77, 0x080c,
+	0x1515, 0x6003, 0x0001, 0x6106, 0x080c, 0x6cd3, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x7173, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106,
+	0x080c, 0x6cd3, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e,
+	0x0005, 0x2600, 0x0002, 0x8a85, 0x8a85, 0x8a99, 0x8a85, 0x8a85,
+	0x8a99, 0x080c, 0x1515, 0x6004, 0xa0b2, 0x0080, 0x1a0c, 0x1515,
+	0xa1b6, 0x0013, 0x0904, 0x8b4b, 0xa1b6, 0x0027, 0x1904, 0x8b11,
+	0x080c, 0x7090, 0x6004, 0x080c, 0x9e47, 0x0190, 0x080c, 0x9e58,
+	0x0904, 0x8b0b, 0xa08e, 0x0021, 0x0904, 0x8b0e, 0xa08e, 0x0022,
+	0x0904, 0x8b0b, 0xa08e, 0x003d, 0x0904, 0x8b0e, 0x0804, 0x8b04,
+	0x080c, 0x2cc2, 0x2001, 0x0007, 0x080c, 0x4efd, 0x6018, 0xa080,
+	0x0028, 0x200c, 0x080c, 0x8c19, 0xa186, 0x007e, 0x1148, 0x2001,
+	0xb535, 0x2014, 0xc285, 0x080c, 0x5acf, 0x1108, 0xc2ad, 0x2202,
+	0x0016, 0x0026, 0x0036, 0x2110, 0x0026, 0x2019, 0x0028, 0x080c,
+	0x8299, 0x002e, 0x080c, 0xb38d, 0x003e, 0x002e, 0x001e, 0x0016,
+	0x0026, 0x0036, 0x2110, 0x2019, 0x0028, 0x080c, 0x6df5, 0x0076,
+	0x2039, 0x0000, 0x080c, 0x6d02, 0x00c6, 0x6018, 0xa065, 0x0110,
+	0x080c, 0x51aa, 0x00ce, 0x2c08, 0x080c, 0xae82, 0x007e, 0x003e,
+	0x002e, 0x001e, 0x080c, 0x4f6c, 0x080c, 0xa01f, 0x080c, 0x861d,
+	0x080c, 0x7173, 0x0005, 0x080c, 0x8c19, 0x0cb0, 0x080c, 0x8c47,
+	0x0c98, 0xa186, 0x0014, 0x1db0, 0x080c, 0x7090, 0x080c, 0x2c9c,
+	0x080c, 0x9e47, 0x1188, 0x080c, 0x2cc2, 0x6018, 0xa080, 0x0028,
+	0x200c, 0x080c, 0x8c19, 0xa186, 0x007e, 0x1128, 0x2001, 0xb535,
+	0x200c, 0xc185, 0x2102, 0x08c0, 0x080c, 0x9e58, 0x1118, 0x080c,
+	0x8c19, 0x0890, 0x6004, 0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6,
+	0x2071, 0xb582, 0x2079, 0x0000, 0x080c, 0x2fcf, 0x00fe, 0x00ee,
+	0x0818, 0x6004, 0xa08e, 0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c,
+	0x8c19, 0x0804, 0x8b04, 0xa0b2, 0x0040, 0x1a04, 0x8c0e, 0x2008,
+	0x0002, 0x8b93, 0x8b94, 0x8b97, 0x8b9a, 0x8b9d, 0x8ba0, 0x8b91,
+	0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91,
+	0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91,
+	0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8ba3,
+	0x8bb2, 0x8b91, 0x8bb4, 0x8bb2, 0x8b91, 0x8b91, 0x8b91, 0x8b91,
+	0x8b91, 0x8bb2, 0x8bb2, 0x8b91, 0x8b91, 0x8b91, 0x8b91, 0x8b91,
+	0x8b91, 0x8b91, 0x8b91, 0x8bee, 0x8bb2, 0x8b91, 0x8bae, 0x8b91,
+	0x8b91, 0x8b91, 0x8baf, 0x8b91, 0x8b91, 0x8b91, 0x8bb2, 0x8be5,
+	0x8b91, 0x080c, 0x1515, 0x00f0, 0x2001, 0x000b, 0x0460, 0x2001,
+	0x0003, 0x0448, 0x2001, 0x0005, 0x0430, 0x2001, 0x0001, 0x0418,
+	0x2001, 0x0009, 0x0400, 0x080c, 0x7090, 0x6003, 0x0005, 0x2001,
+	0xb7b8, 0x2004, 0x603e, 0x080c, 0x7173, 0x00a0, 0x0018, 0x0010,
+	0x080c, 0x4efd, 0x0804, 0x8bff, 0x080c, 0x7090, 0x2001, 0xb7b6,
+	0x2004, 0x6016, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x0004,
+	0x080c, 0x7173, 0x0005, 0x080c, 0x4efd, 0x080c, 0x7090, 0x6003,
+	0x0002, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x0036, 0x2019, 0xb55d,
+	0x2304, 0xa084, 0xff00, 0x1120, 0x2001, 0xb7b6, 0x201c, 0x0040,
+	0x8007, 0xa09a, 0x0004, 0x0ec0, 0x8003, 0x801b, 0x831b, 0xa318,
+	0x6316, 0x003e, 0x080c, 0x7173, 0x08e8, 0x080c, 0x7090, 0x080c,
+	0xa01f, 0x080c, 0x861d, 0x080c, 0x7173, 0x08a0, 0x00e6, 0x00f6,
+	0x2071, 0xb582, 0x2079, 0x0000, 0x080c, 0x2fcf, 0x00fe, 0x00ee,
+	0x080c, 0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0818, 0x080c,
+	0x7090, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x0002, 0x2001,
+	0xb7b6, 0x2004, 0x6016, 0x080c, 0x7173, 0x0005, 0x2600, 0x2008,
+	0x0002, 0x8c17, 0x8c17, 0x8c17, 0x8bff, 0x8bff, 0x8c17, 0x080c,
+	0x1515, 0x00e6, 0x0026, 0x0016, 0x080c, 0x9c5a, 0x0508, 0x6010,
+	0x2070, 0x7034, 0xa086, 0x0139, 0x1148, 0x2001, 0x0030, 0x2009,
+	0x0000, 0x2011, 0x4005, 0x080c, 0xa0d6, 0x0090, 0x7038, 0xd0fc,
+	0x0178, 0x7007, 0x0000, 0x0016, 0x6004, 0xa08e, 0x0021, 0x0160,
+	0xa08e, 0x003d, 0x0148, 0x001e, 0x7037, 0x0103, 0x7033, 0x0100,
+	0x001e, 0x002e, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc8, 0x00e6,
+	0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x7023,
+	0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804, 0xa084,
+	0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x1515, 0x6604, 0xa6b6,
+	0x0043, 0x1120, 0x080c, 0xa092, 0x0804, 0x8cb8, 0x6604, 0xa6b6,
+	0x0033, 0x1120, 0x080c, 0xa042, 0x0804, 0x8cb8, 0x6604, 0xa6b6,
+	0x0028, 0x1120, 0x080c, 0x9e88, 0x0804, 0x8cb8, 0x6604, 0xa6b6,
+	0x0029, 0x1118, 0x080c, 0x9e9f, 0x04d8, 0x6604, 0xa6b6, 0x001f,
+	0x1118, 0x080c, 0x8786, 0x04a0, 0x6604, 0xa6b6, 0x0000, 0x1118,
+	0x080c, 0x89da, 0x0468, 0x6604, 0xa6b6, 0x0022, 0x1118, 0x080c,
+	0x87ae, 0x0430, 0x6604, 0xa6b6, 0x0035, 0x1118, 0x080c, 0x8815,
+	0x00f8, 0x6604, 0xa6b6, 0x0039, 0x1118, 0x080c, 0x8976, 0x00c0,
+	0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x87c8, 0x0088, 0x6604,
+	0xa6b6, 0x0044, 0x1118, 0x080c, 0x87e8, 0x0050, 0xa1b6, 0x0015,
+	0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, 0x1118, 0x0804, 0x8e7c,
+	0x0005, 0x080c, 0x8663, 0x0ce0, 0x8cdf, 0x8ce2, 0x8cdf, 0x8d24,
+	0x8cdf, 0x8e09, 0x8e8a, 0x8cdf, 0x8cdf, 0x8e58, 0x8cdf, 0x8e6c,
+	0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10,
+	0x080c, 0x185e, 0x0005, 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000,
+	0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x861d, 0x0005, 0xe000,
+	0xe000, 0x0005, 0x00e6, 0x2071, 0xb500, 0x7084, 0xa086, 0x0074,
+	0x1530, 0x080c, 0xae59, 0x11b0, 0x00d6, 0x6018, 0x2068, 0x7030,
+	0xd08c, 0x0128, 0x6800, 0xd0bc, 0x0110, 0xc0c5, 0x6802, 0x00d9,
+	0x00de, 0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c,
+	0x861d, 0x0078, 0x2001, 0x000a, 0x080c, 0x4efd, 0x080c, 0x2cc2,
+	0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c,
+	0x8df6, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168, 0x2001, 0x0000,
+	0x080c, 0x4eeb, 0x2069, 0xb552, 0x6804, 0xd0a4, 0x0120, 0x2001,
+	0x0006, 0x080c, 0x4f2a, 0x0005, 0x00d6, 0x2011, 0xb521, 0x2204,
+	0xa086, 0x0074, 0x1904, 0x8df3, 0x6018, 0x2068, 0x6aa0, 0xa286,
+	0x007e, 0x1120, 0x080c, 0x8fa2, 0x0804, 0x8d92, 0x080c, 0x8f98,
+	0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286, 0x0080, 0x11c0,
+	0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005, 0x0138, 0x2068,
+	0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200, 0x2001, 0x0006,
+	0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c, 0x861d, 0x0804, 0x8df4,
+	0x00e6, 0x2071, 0xb535, 0x2e04, 0xd09c, 0x0188, 0x2071, 0xbb80,
+	0x7108, 0x720c, 0xa18c, 0x00ff, 0x1118, 0xa284, 0xff00, 0x0138,
+	0x6018, 0x2070, 0x70a0, 0xd0bc, 0x1110, 0x7112, 0x7216, 0x00ee,
+	0x6010, 0xa005, 0x0198, 0x2068, 0x6838, 0xd0f4, 0x0178, 0x6834,
+	0xa084, 0x00ff, 0xa086, 0x0039, 0x1958, 0x2001, 0x0000, 0x2009,
+	0x0000, 0x2011, 0x4000, 0x080c, 0xa0d6, 0x0840, 0x2001, 0x0004,
+	0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x6cd3,
+	0x0804, 0x8df4, 0x685c, 0xd0e4, 0x01d8, 0x080c, 0x9fd2, 0x080c,
+	0x5acf, 0x0118, 0xd0dc, 0x1904, 0x8d4e, 0x2011, 0xb535, 0x2204,
+	0xc0ad, 0x2012, 0x2001, 0xb78f, 0x2004, 0x00f6, 0x2079, 0x0100,
+	0x78e3, 0x0000, 0x080c, 0x2872, 0x78e2, 0x00fe, 0x0804, 0x8d4e,
+	0x080c, 0xa008, 0x2011, 0xb535, 0x2204, 0xc0a5, 0x2012, 0x0006,
+	0x080c, 0xaf7b, 0x000e, 0x1904, 0x8d4e, 0xc0b5, 0x2012, 0x2001,
+	0x0006, 0x080c, 0x4efd, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x00c6,
+	0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936,
+	0x00fe, 0x080c, 0x2847, 0x00f6, 0x2079, 0xb500, 0x7976, 0x2100,
+	0x2009, 0x0000, 0x080c, 0x281d, 0x7952, 0x00fe, 0x8108, 0x080c,
+	0x4f4d, 0x2c00, 0x00ce, 0x1904, 0x8d4e, 0x601a, 0x2001, 0x0002,
+	0x080c, 0x4efd, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x6cd3, 0x0008, 0x0011, 0x00de, 0x0005, 0x2001, 0x0007,
+	0x080c, 0x4efd, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003, 0x1120,
+	0x2001, 0x0007, 0x080c, 0x4f2a, 0x080c, 0x2cc2, 0x080c, 0x861d,
+	0x0005, 0x00e6, 0x0026, 0x0016, 0x2071, 0xb500, 0x7084, 0xa086,
+	0x0014, 0x15f0, 0x7000, 0xa086, 0x0003, 0x1128, 0x6010, 0xa005,
+	0x1110, 0x080c, 0x3f3e, 0x00d6, 0x6018, 0x2068, 0x080c, 0x504b,
+	0x080c, 0x8d13, 0x00de, 0x080c, 0x9051, 0x1550, 0x00d6, 0x6018,
+	0x2068, 0x6890, 0x00de, 0xa005, 0x0518, 0x2001, 0x0006, 0x080c,
+	0x4efd, 0x00e6, 0x6010, 0xa075, 0x01a8, 0x7034, 0xa084, 0x00ff,
+	0xa086, 0x0039, 0x1148, 0x2001, 0x0000, 0x2009, 0x0000, 0x2011,
+	0x4000, 0x080c, 0xa0d6, 0x0030, 0x7007, 0x0000, 0x7037, 0x0103,
+	0x7033, 0x0200, 0x00ee, 0x080c, 0x2cc2, 0x080c, 0x861d, 0x0020,
+	0x080c, 0x8c19, 0x080c, 0x8df6, 0x001e, 0x002e, 0x00ee, 0x0005,
+	0x2011, 0xb521, 0x2204, 0xa086, 0x0014, 0x1158, 0x2001, 0x0002,
+	0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x6cd3,
+	0x0010, 0x080c, 0x8df6, 0x0005, 0x2011, 0xb521, 0x2204, 0xa086,
+	0x0004, 0x1138, 0x2001, 0x0007, 0x080c, 0x4efd, 0x080c, 0x861d,
+	0x0010, 0x080c, 0x8df6, 0x0005, 0x000b, 0x0005, 0x8cdf, 0x8e95,
+	0x8cdf, 0x8ec9, 0x8cdf, 0x8f54, 0x8e8a, 0x8cdf, 0x8cdf, 0x8f67,
+	0x8cdf, 0x8f77, 0x6604, 0xa686, 0x0003, 0x0904, 0x8e09, 0xa6b6,
+	0x001e, 0x1110, 0x080c, 0x861d, 0x0005, 0x00d6, 0x00c6, 0x080c,
+	0x8f87, 0x1178, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0002,
+	0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3,
+	0x00e8, 0x2009, 0xbb8e, 0x2104, 0xa086, 0x0009, 0x1160, 0x6018,
+	0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0170, 0x8001, 0x6842,
+	0x6017, 0x000a, 0x0058, 0x2009, 0xbb8f, 0x2104, 0xa084, 0xff00,
+	0xa086, 0x1900, 0x1108, 0x08d0, 0x080c, 0x8df6, 0x00ce, 0x00de,
+	0x0005, 0x0026, 0x2011, 0x0000, 0x080c, 0x8f95, 0x00d6, 0x2069,
+	0xb79e, 0x2d04, 0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, 0xa086,
+	0x007e, 0x1138, 0x2069, 0xb51d, 0x2d04, 0x8000, 0x206a, 0x00de,
+	0x0010, 0x00de, 0x0078, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001,
+	0x0002, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c,
+	0x6cd3, 0x0480, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x00de,
+	0x0108, 0x6a34, 0x080c, 0x8c19, 0x2009, 0xbb8e, 0x2134, 0xa6b4,
+	0x00ff, 0xa686, 0x0005, 0x0500, 0xa686, 0x000b, 0x01c8, 0x2009,
+	0xbb8f, 0x2104, 0xa084, 0xff00, 0x1118, 0xa686, 0x0009, 0x01a0,
+	0xa086, 0x1900, 0x1168, 0xa686, 0x0009, 0x0170, 0x2001, 0x0004,
+	0x080c, 0x4efd, 0x2001, 0x0028, 0x6016, 0x6007, 0x004b, 0x0010,
+	0x080c, 0x8df6, 0x002e, 0x0005, 0x00d6, 0xa286, 0x0139, 0x0160,
+	0x6010, 0x2068, 0x080c, 0x9c5a, 0x0148, 0x6834, 0xa086, 0x0139,
+	0x0118, 0x6838, 0xd0fc, 0x0110, 0x00de, 0x0c50, 0x6018, 0x2068,
+	0x6840, 0xa084, 0x00ff, 0xa005, 0x0140, 0x8001, 0x6842, 0x6017,
+	0x000a, 0x6007, 0x0016, 0x00de, 0x08e8, 0x68a0, 0xa086, 0x007e,
+	0x1138, 0x00e6, 0x2071, 0xb500, 0x080c, 0x4bc6, 0x00ee, 0x0010,
+	0x080c, 0x2c9c, 0x00de, 0x0860, 0x080c, 0x8f95, 0x1158, 0x2001,
+	0x0004, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c,
+	0x6cd3, 0x0020, 0x080c, 0x8c19, 0x080c, 0x8df6, 0x0005, 0x0469,
+	0x1158, 0x2001, 0x0008, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007,
+	0x0005, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x8df6, 0x0005, 0x00e9,
+	0x1158, 0x2001, 0x000a, 0x080c, 0x4efd, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x8df6, 0x0005, 0x2009,
+	0xbb8e, 0x2104, 0xa086, 0x0003, 0x1138, 0x2009, 0xbb8f, 0x2104,
+	0xa084, 0xff00, 0xa086, 0x2a00, 0x0005, 0xa085, 0x0001, 0x0005,
+	0x00c6, 0x0016, 0xac88, 0x0006, 0x2164, 0x080c, 0x4fb8, 0x001e,
+	0x00ce, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6018,
+	0x2068, 0x2071, 0xb535, 0x2e04, 0xa085, 0x0003, 0x2072, 0x080c,
+	0x9026, 0x0560, 0x2009, 0xb535, 0x2104, 0xc0cd, 0x200a, 0x2001,
+	0xb553, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a,
+	0x080c, 0xb0e8, 0x2001, 0xb50c, 0x200c, 0xc195, 0x2102, 0x2019,
+	0x002a, 0x2009, 0x0001, 0x080c, 0x2c6f, 0x2071, 0xb500, 0x080c,
+	0x2ab8, 0x00c6, 0x0156, 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c,
+	0x2d97, 0x8108, 0x1f04, 0x8fd7, 0x015e, 0x00ce, 0x080c, 0x8f98,
+	0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0xbb80, 0x2079, 0x0100,
+	0x2e04, 0xa084, 0x00ff, 0x2069, 0xb51c, 0x206a, 0x78e6, 0x0006,
+	0x8e70, 0x2e04, 0x2069, 0xb51d, 0x206a, 0x78ea, 0x7832, 0x7836,
+	0x2010, 0xa084, 0xff00, 0x001e, 0xa105, 0x2009, 0xb528, 0x200a,
+	0x2200, 0xa084, 0x00ff, 0x2008, 0x080c, 0x2847, 0x080c, 0x5acf,
+	0x0170, 0x2069, 0xbb8e, 0x2071, 0xb7b2, 0x6810, 0x2072, 0x6814,
+	0x7006, 0x6818, 0x700a, 0x681c, 0x700e, 0x080c, 0x9fd2, 0x0040,
+	0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x2cc2, 0x080c, 0x861d,
+	0x001e, 0x003e, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036,
+	0x00e6, 0x0156, 0x2019, 0xb528, 0x231c, 0x83ff, 0x01e8, 0x2071,
+	0xbb80, 0x2e14, 0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205,
+	0xa306, 0x1190, 0x2011, 0xbb96, 0xad98, 0x000a, 0x20a9, 0x0004,
+	0x080c, 0x90da, 0x1148, 0x2011, 0xbb9a, 0xad98, 0x0006, 0x20a9,
+	0x0004, 0x080c, 0x90da, 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e,
+	0x0005, 0x00e6, 0x2071, 0xbb8c, 0x7004, 0xa086, 0x0014, 0x11a8,
+	0x7008, 0xa086, 0x0800, 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084,
+	0x0f00, 0xa086, 0x0100, 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac,
+	0x0110, 0xa006, 0x0010, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6,
+	0x00d6, 0x00c6, 0x0076, 0x0056, 0x0046, 0x0026, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2029, 0xb7e9, 0x252c, 0x2021, 0xb7ef, 0x2424,
+	0x2061, 0xbd00, 0x2071, 0xb500, 0x7248, 0x7068, 0xa202, 0x16f0,
+	0x080c, 0xb110, 0x05a0, 0x671c, 0xa786, 0x0001, 0x0580, 0xa786,
+	0x0007, 0x0568, 0x2500, 0xac06, 0x0550, 0x2400, 0xac06, 0x0538,
+	0x00c6, 0x6000, 0xa086, 0x0004, 0x1110, 0x080c, 0x194d, 0xa786,
+	0x0008, 0x1148, 0x080c, 0x9e58, 0x1130, 0x00ce, 0x080c, 0x8c19,
+	0x080c, 0x9e1d, 0x00a0, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0160,
+	0xa786, 0x0003, 0x11e8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x080c, 0x5408, 0x080c, 0x9e11, 0x080c, 0x9e1d, 0x00ce, 0xace0,
+	0x0018, 0x705c, 0xac02, 0x1210, 0x0804, 0x9084, 0x012e, 0x000e,
+	0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005,
+	0xa786, 0x0006, 0x1118, 0x080c, 0xb099, 0x0c30, 0xa786, 0x000a,
+	0x09e0, 0x08c8, 0x220c, 0x2304, 0xa106, 0x1130, 0x8210, 0x8318,
+	0x1f04, 0x90da, 0xa006, 0x0005, 0x2304, 0xa102, 0x0218, 0x2001,
+	0x0001, 0x0010, 0x2001, 0x0000, 0xa18d, 0x0001, 0x0005, 0x6004,
+	0xa08a, 0x0080, 0x1a0c, 0x1515, 0x080c, 0x9e47, 0x0120, 0x080c,
+	0x9e58, 0x0168, 0x0028, 0x080c, 0x2cc2, 0x080c, 0x9e58, 0x0138,
+	0x080c, 0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c,
+	0x8c19, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x9120, 0x9120, 0x9120,
+	0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120, 0x9120,
+	0x9122, 0x9122, 0x9122, 0x9122, 0x9120, 0x9120, 0x9120, 0x9122,
+	0x080c, 0x1515, 0x600b, 0xffff, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, 0x0005,
+	0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0040, 0x0804, 0x91bc,
+	0xa186, 0x0027, 0x11e8, 0x080c, 0x7090, 0x080c, 0x2c9c, 0x00d6,
+	0x6110, 0x2168, 0x080c, 0x9c5a, 0x0168, 0x6837, 0x0103, 0x684b,
+	0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x080c, 0x5408,
+	0x080c, 0x9e11, 0x00de, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005,
+	0xa186, 0x0014, 0x1120, 0x6004, 0xa082, 0x0040, 0x0428, 0xa186,
+	0x0046, 0x0138, 0xa186, 0x0045, 0x0120, 0xa186, 0x0047, 0x190c,
+	0x1515, 0x2001, 0x0109, 0x2004, 0xd084, 0x0198, 0x0126, 0x2091,
+	0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6b74, 0x002e, 0x001e,
+	0x000e, 0x012e, 0xe000, 0x6000, 0xa086, 0x0002, 0x1110, 0x0804,
+	0x91fa, 0x080c, 0x8663, 0x0005, 0x0002, 0x919a, 0x9198, 0x9198,
+	0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198, 0x9198,
+	0x91b5, 0x91b5, 0x91b5, 0x91b5, 0x9198, 0x91b5, 0x9198, 0x91b5,
+	0x080c, 0x1515, 0x080c, 0x7090, 0x00d6, 0x6110, 0x2168, 0x080c,
+	0x9c5a, 0x0168, 0x6837, 0x0103, 0x684b, 0x0006, 0x6847, 0x0000,
+	0x6850, 0xc0ec, 0x6852, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de,
+	0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c,
+	0x861d, 0x080c, 0x7173, 0x0005, 0x0002, 0x91d2, 0x91d0, 0x91d0,
+	0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0, 0x91d0,
+	0x91e4, 0x91e4, 0x91e4, 0x91e4, 0x91d0, 0x91f3, 0x91d0, 0x91e4,
+	0x080c, 0x1515, 0x080c, 0x7090, 0x2001, 0xb7b8, 0x2004, 0x603e,
+	0x6003, 0x0002, 0x080c, 0x7173, 0x6010, 0xa088, 0x0013, 0x2104,
+	0xa085, 0x0400, 0x200a, 0x0005, 0x080c, 0x7090, 0x2001, 0xb7b6,
+	0x2004, 0x6016, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x6003, 0x000f,
+	0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c, 0x861d, 0x080c,
+	0x7173, 0x0005, 0xa182, 0x0040, 0x0002, 0x9210, 0x9210, 0x9210,
+	0x9210, 0x9210, 0x9212, 0x92f7, 0x9326, 0x9210, 0x9210, 0x9210,
+	0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210, 0x9210,
+	0x080c, 0x1515, 0x00e6, 0x00d6, 0x603f, 0x0000, 0x2071, 0xbb80,
+	0x7124, 0x610a, 0x2071, 0xbb8c, 0x6110, 0x2168, 0x7614, 0xa6b4,
+	0x0fff, 0x86ff, 0x0904, 0x92c0, 0xa68c, 0x0c00, 0x0518, 0x00f6,
+	0x2c78, 0x080c, 0x5305, 0x00fe, 0x01c8, 0x684c, 0xd0ac, 0x01b0,
+	0x6020, 0xd0dc, 0x1198, 0x6850, 0xd0bc, 0x1180, 0x7318, 0x6814,
+	0xa306, 0x1904, 0x92d3, 0x731c, 0x6810, 0xa31e, 0x0138, 0xd6d4,
+	0x0904, 0x92d3, 0x6b14, 0xa305, 0x1904, 0x92d3, 0x7318, 0x6b62,
+	0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0518, 0xa186,
+	0x0028, 0x1128, 0x080c, 0x9e36, 0x684b, 0x001c, 0x00e8, 0xd6dc,
+	0x01a0, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0170, 0x6914, 0x6a10,
+	0x2100, 0xa205, 0x0148, 0x7018, 0xa106, 0x1118, 0x701c, 0xa206,
+	0x0118, 0x6962, 0x6a5e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x684b,
+	0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e,
+	0xd6c4, 0x01f0, 0xa686, 0x0100, 0x1140, 0x2001, 0xbb99, 0x2004,
+	0xa005, 0x1118, 0xc6c4, 0x0804, 0x9221, 0x7328, 0x732c, 0x6b56,
+	0x83ff, 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036,
+	0x2308, 0x2019, 0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e,
+	0xd6cc, 0x0904, 0x92e6, 0x7124, 0x695a, 0x81ff, 0x0904, 0x92e6,
+	0xa192, 0x0021, 0x1260, 0x2071, 0xbb98, 0x831c, 0x2300, 0xae18,
+	0xad90, 0x001d, 0x080c, 0x990d, 0x080c, 0xa137, 0x04b8, 0x6838,
+	0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c68, 0x00f6, 0x2d78,
+	0x080c, 0x98b2, 0x00fe, 0x080c, 0xa137, 0x080c, 0x98fd, 0x0440,
+	0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0190, 0x684c, 0xd0ac,
+	0x0178, 0x6020, 0xd0dc, 0x1160, 0x6850, 0xd0bc, 0x1148, 0x6810,
+	0x6914, 0xa105, 0x0128, 0x080c, 0x9f35, 0x00de, 0x00ee, 0x00f0,
+	0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0130,
+	0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x9483, 0x080c, 0x5408,
+	0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, 0x080c,
+	0x9f03, 0x00de, 0x00ee, 0x1110, 0x080c, 0x861d, 0x0005, 0x00f6,
+	0x6003, 0x0003, 0x2079, 0xbb8c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08,
+	0x6010, 0x2078, 0x784c, 0xd0ac, 0x0138, 0x6003, 0x0002, 0x00fe,
+	0x0005, 0x2130, 0x2228, 0x0058, 0x2400, 0x797c, 0xa10a, 0x2300,
+	0x7a80, 0xa213, 0x2600, 0xa102, 0x2500, 0xa203, 0x0e90, 0x7c12,
+	0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x603f, 0x0000, 0x2c10, 0x080c,
+	0x1fa9, 0x080c, 0x6cf0, 0x080c, 0x7230, 0x0005, 0x2001, 0xb7b8,
+	0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005, 0x3d18,
+	0x3e20, 0x2c10, 0x080c, 0x185e, 0x0005, 0xa182, 0x0040, 0x0002,
+	0x934b, 0x934b, 0x934b, 0x934b, 0x934b, 0x934d, 0x93e0, 0x934b,
+	0x934b, 0x93f6, 0x945a, 0x934b, 0x934b, 0x934b, 0x934b, 0x9469,
+	0x934b, 0x934b, 0x934b, 0x080c, 0x1515, 0x0076, 0x00f6, 0x00e6,
+	0x00d6, 0x2071, 0xbb8c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff,
+	0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x82ff,
+	0x0110, 0x8211, 0x6a3e, 0x86ff, 0x0904, 0x93db, 0xa694, 0xff00,
+	0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, 0x701c, 0x785e, 0xa284,
+	0x0300, 0x0904, 0x93db, 0x080c, 0x15f8, 0x090c, 0x1515, 0x2d00,
+	0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a,
+	0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120,
+	0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002,
+	0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc,
+	0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007,
+	0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856,
+	0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170,
+	0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019,
+	0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e, 0xd6cc, 0x01d8,
+	0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071,
+	0xbb98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x990d,
+	0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78,
+	0x2d78, 0x080c, 0x98b2, 0x00de, 0x00ee, 0x00fe, 0x007e, 0x0005,
+	0x00f6, 0x6003, 0x0003, 0x2079, 0xbb8c, 0x7c04, 0x7b00, 0x7e0c,
+	0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x00fe,
+	0x2c10, 0x080c, 0x1fa9, 0x080c, 0x7d60, 0x0005, 0x00d6, 0x00f6,
+	0x2c78, 0x080c, 0x5305, 0x00fe, 0x0120, 0x2001, 0xb7b8, 0x2004,
+	0x603e, 0x6003, 0x0002, 0x080c, 0x7126, 0x080c, 0x7230, 0x6110,
+	0x2168, 0x694c, 0xd1e4, 0x0904, 0x9458, 0xd1cc, 0x0540, 0x6948,
+	0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, 0x6850, 0x0006,
+	0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8,
+	0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x9420, 0x015e, 0x000e,
+	0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x161f, 0x0418,
+	0x0016, 0x080c, 0x161f, 0x00de, 0x080c, 0x98fd, 0x00e0, 0x6837,
+	0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180, 0xa086,
+	0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, 0x0118, 0x684b,
+	0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0010, 0x684b,
+	0x0000, 0x080c, 0x5408, 0x080c, 0x9f03, 0x1110, 0x080c, 0x861d,
+	0x00de, 0x0005, 0x2019, 0x0001, 0x080c, 0x7fe4, 0x6003, 0x0002,
+	0x2001, 0xb7b8, 0x2004, 0x603e, 0x080c, 0x7126, 0x080c, 0x7230,
+	0x0005, 0x080c, 0x7126, 0x080c, 0x2c9c, 0x00d6, 0x6110, 0x2168,
+	0x080c, 0x9c5a, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847,
+	0x0000, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de, 0x080c, 0x861d,
+	0x080c, 0x7230, 0x0005, 0x684b, 0x0015, 0xd1fc, 0x0138, 0x684b,
+	0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962, 0x685e,
+	0x0005, 0xa182, 0x0040, 0x0002, 0x94a7, 0x94a7, 0x94a7, 0x94a7,
+	0x94a7, 0x94a9, 0x94a7, 0x9564, 0x9570, 0x94a7, 0x94a7, 0x94a7,
+	0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x94a7, 0x080c,
+	0x1515, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xbb8c, 0x6110,
+	0x2178, 0x7614, 0xa6b4, 0x0fff, 0x00f6, 0x2c78, 0x080c, 0x5305,
+	0x00fe, 0x0150, 0xa684, 0x00ff, 0x1138, 0x6020, 0xd0f4, 0x0120,
+	0x080c, 0x9f35, 0x0804, 0x955f, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e,
+	0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110, 0x8211, 0x6a3e, 0x86ff,
+	0x0904, 0x9555, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, 0x7018,
+	0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x9553, 0xa686,
+	0x0100, 0x1140, 0x2001, 0xbb99, 0x2004, 0xa005, 0x1118, 0xc6c4,
+	0x7e46, 0x0c28, 0x080c, 0x15f8, 0x090c, 0x1515, 0x2d00, 0x784a,
+	0x7f4c, 0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a,
+	0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120,
+	0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002,
+	0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc,
+	0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007,
+	0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856,
+	0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170,
+	0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019,
+	0xbb98, 0xad90, 0x0019, 0x080c, 0x990d, 0x003e, 0xd6cc, 0x01d8,
+	0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071,
+	0xbb98, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x990d,
+	0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78,
+	0x2d78, 0x080c, 0x98b2, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001,
+	0x0001, 0x2071, 0xbb8c, 0x7218, 0x731c, 0x080c, 0x18b1, 0x00de,
+	0x00ee, 0x00fe, 0x007e, 0x0005, 0x2001, 0xb7b8, 0x2004, 0x603e,
+	0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x185e, 0x0005,
+	0x2001, 0xb7b8, 0x2004, 0x603e, 0x00d6, 0x6003, 0x0002, 0x6110,
+	0x2168, 0x694c, 0xd1e4, 0x0904, 0x967b, 0x603f, 0x0000, 0x00f6,
+	0x2c78, 0x080c, 0x5305, 0x00fe, 0x0560, 0x6814, 0x6910, 0xa115,
+	0x0540, 0x6a60, 0xa206, 0x1118, 0x685c, 0xa106, 0x0510, 0x684c,
+	0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000,
+	0x6020, 0xd0f4, 0x1158, 0x697c, 0x6810, 0xa102, 0x603a, 0x6980,
+	0x6814, 0xa103, 0x6036, 0x6020, 0xc0f5, 0x6022, 0x00d6, 0x6018,
+	0x2068, 0x683c, 0x8000, 0x683e, 0x00de, 0x080c, 0x9f35, 0x0804,
+	0x967b, 0x694c, 0xd1cc, 0x0904, 0x964b, 0x6948, 0x6838, 0xd0fc,
+	0x0904, 0x960e, 0x0016, 0x684c, 0x0006, 0x6850, 0x0006, 0x00f6,
+	0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x01e0, 0xa086,
+	0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, 0x00e8, 0xd1dc,
+	0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, 0xa0bf, 0x0118,
+	0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, 0x684b, 0x0007,
+	0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914,
+	0xa115, 0x0110, 0x080c, 0x9483, 0x6848, 0x784a, 0x6860, 0x7862,
+	0x685c, 0x785e, 0xad90, 0x000d, 0xaf98, 0x000d, 0x2009, 0x0020,
+	0x0156, 0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x95fa,
+	0x015e, 0x00fe, 0x000e, 0x6852, 0x000e, 0x684e, 0x080c, 0xa137,
+	0x001e, 0x2168, 0x080c, 0x161f, 0x0804, 0x9676, 0x0016, 0x00f6,
+	0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x01e0, 0xa086,
+	0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c, 0x00e8, 0xd1dc,
+	0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c, 0xa0bf, 0x0118,
+	0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128, 0x684b, 0x0007,
+	0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914,
+	0xa115, 0x0110, 0x080c, 0x9483, 0x6860, 0x7862, 0x685c, 0x785e,
+	0x684c, 0x784e, 0x00fe, 0x080c, 0x161f, 0x00de, 0x080c, 0xa137,
+	0x080c, 0x98fd, 0x0458, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff,
+	0xa0b6, 0x0002, 0x01b0, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c,
+	0x00d8, 0xd1dc, 0x0148, 0x684b, 0x0015, 0x080c, 0xa0bf, 0x0118,
+	0x6944, 0xc1dc, 0x6946, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007,
+	0x0058, 0x684b, 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914,
+	0xa115, 0x0110, 0x080c, 0x9483, 0x080c, 0x5408, 0x080c, 0x9f03,
+	0x1110, 0x080c, 0x861d, 0x00de, 0x0005, 0x080c, 0x7090, 0x0010,
+	0x080c, 0x7126, 0x080c, 0x9c5a, 0x01c0, 0x00d6, 0x6110, 0x2168,
+	0x6837, 0x0103, 0x2009, 0xb50c, 0x210c, 0xd18c, 0x11c0, 0xd184,
+	0x1198, 0x6108, 0x694a, 0xa18e, 0x0029, 0x1110, 0x080c, 0xb380,
+	0x6847, 0x0000, 0x080c, 0x5408, 0x00de, 0x080c, 0x861d, 0x080c,
+	0x7173, 0x080c, 0x7230, 0x0005, 0x684b, 0x0004, 0x0c88, 0x684b,
+	0x0004, 0x0c70, 0xa182, 0x0040, 0x0002, 0x96c0, 0x96c0, 0x96c0,
+	0x96c0, 0x96c0, 0x96c2, 0x96c0, 0x96c5, 0x96c0, 0x96c0, 0x96c0,
+	0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0, 0x96c0,
+	0x080c, 0x1515, 0x080c, 0x861d, 0x0005, 0x0006, 0x0026, 0xa016,
+	0x080c, 0x185e, 0x002e, 0x000e, 0x0005, 0xa182, 0x0085, 0x0002,
+	0x96d9, 0x96d7, 0x96d7, 0x96e5, 0x96d7, 0x96d7, 0x96d7, 0x080c,
+	0x1515, 0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x7173, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6,
+	0x00e6, 0x2071, 0xbb80, 0x7224, 0x6212, 0x7220, 0x080c, 0x9c4a,
+	0x01a0, 0x2268, 0x6800, 0xa086, 0x0000, 0x0178, 0x6018, 0x6d18,
+	0xa52e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0x991d, 0x00ce, 0x0128,
+	0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003,
+	0x0001, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x00f6, 0x2278, 0x080c,
+	0x5305, 0x00fe, 0x0150, 0x6820, 0xd0ec, 0x0138, 0x00c6, 0x2260,
+	0x603f, 0x0000, 0x080c, 0x9f35, 0x00ce, 0x00ee, 0x00de, 0x005e,
+	0x002e, 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085,
+	0x0a0c, 0x1515, 0xa08a, 0x008c, 0x1a0c, 0x1515, 0xa082, 0x0085,
+	0x0072, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x1515,
+	0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0x9746,
+	0x9748, 0x9748, 0x9746, 0x9746, 0x9746, 0x9746, 0x080c, 0x1515,
+	0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0xa186,
+	0x0013, 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x04a8, 0xa186,
+	0x0027, 0x11e8, 0x080c, 0x7090, 0x080c, 0x2c9c, 0x00d6, 0x6010,
+	0x2068, 0x080c, 0x9c5a, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000,
+	0x684b, 0x0029, 0x080c, 0x5408, 0x080c, 0x9e11, 0x00de, 0x080c,
+	0x861d, 0x080c, 0x7173, 0x0005, 0x080c, 0x8663, 0x0ce0, 0xa186,
+	0x0014, 0x1dd0, 0x080c, 0x7090, 0x00d6, 0x6010, 0x2068, 0x080c,
+	0x9c5a, 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006,
+	0x6850, 0xc0ec, 0x6852, 0x08f0, 0x0002, 0x9796, 0x9794, 0x9794,
+	0x9794, 0x9794, 0x9794, 0x97ae, 0x080c, 0x1515, 0x080c, 0x7090,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x2001, 0xb7b6, 0x0010, 0x2001, 0xb7b7, 0x2004,
+	0x6016, 0x6003, 0x000c, 0x080c, 0x7173, 0x0005, 0x080c, 0x7090,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x2001, 0xb7b6, 0x0010, 0x2001, 0xb7b7, 0x2004,
+	0x6016, 0x6003, 0x000e, 0x080c, 0x7173, 0x0005, 0xa182, 0x008c,
+	0x1220, 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x8663, 0x0005,
+	0x97d7, 0x97d7, 0x97d7, 0x97d7, 0x97d9, 0x9832, 0x97d7, 0x080c,
+	0x1515, 0x00d6, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0168,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x00de, 0x0804, 0x9845, 0x080c, 0x9c5a, 0x1118,
+	0x080c, 0x9e11, 0x00f0, 0x6010, 0x2068, 0x684c, 0xd0e4, 0x1110,
+	0x080c, 0x9e11, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, 0x684b,
+	0x0006, 0xc0ec, 0x6852, 0x0048, 0xd0bc, 0x0118, 0x684b, 0x0002,
+	0x0020, 0x684b, 0x0005, 0x080c, 0x9ed2, 0x6847, 0x0000, 0x080c,
+	0x5408, 0x2c68, 0x080c, 0x85c7, 0x01c0, 0x6003, 0x0001, 0x6007,
+	0x001e, 0x600b, 0xffff, 0x2009, 0xbb8e, 0x210c, 0x6136, 0x2009,
+	0xbb8f, 0x210c, 0x613a, 0x6918, 0x611a, 0x080c, 0xa027, 0x6950,
+	0x6152, 0x601f, 0x0001, 0x080c, 0x6c8d, 0x2d60, 0x080c, 0x861d,
+	0x00de, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x00fe, 0x0598,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035, 0x0130, 0xa186,
+	0x001e, 0x0118, 0xa186, 0x0039, 0x1530, 0x00d6, 0x2c68, 0x080c,
+	0xa10a, 0x1904, 0x988a, 0x080c, 0x85c7, 0x01d8, 0x6106, 0x6003,
+	0x0001, 0x601f, 0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c,
+	0x612e, 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938,
+	0x613a, 0x6950, 0x6152, 0x080c, 0xa027, 0x080c, 0x6c8d, 0x080c,
+	0x7173, 0x2d60, 0x00f8, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9c5a,
+	0x01c8, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128, 0xc0ec, 0x6852,
+	0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b, 0x0002, 0x0020,
+	0x684b, 0x0005, 0x080c, 0x9ed2, 0x6847, 0x0000, 0x080c, 0x5408,
+	0x080c, 0x9e11, 0x00de, 0x080c, 0x861d, 0x0005, 0x0016, 0x00d6,
+	0x6010, 0x2068, 0x080c, 0x9c5a, 0x0140, 0x6837, 0x0103, 0x684b,
+	0x0028, 0x6847, 0x0000, 0x080c, 0x5408, 0x00de, 0x001e, 0xa186,
+	0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118,
+	0x080c, 0x8663, 0x0030, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c,
+	0x7173, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6, 0x2029, 0x0001,
+	0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100, 0x2130, 0x2069,
+	0xbb98, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90, 0x001d,
+	0x080c, 0x990d, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0110, 0x080c,
+	0x161f, 0x080c, 0x15f8, 0x0500, 0x8528, 0x6837, 0x0110, 0x683b,
+	0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228, 0x2608, 0xad90,
+	0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78,
+	0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f, 0xa5ad, 0x0003,
+	0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f, 0xa5ad, 0x0003,
+	0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6, 0x8dff, 0x0158,
+	0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c, 0x5408, 0x2f68,
+	0x0cb8, 0x080c, 0x5408, 0x00fe, 0x0005, 0x0156, 0xa184, 0x0001,
+	0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007, 0x2012, 0x8318,
+	0x8210, 0x1f04, 0x9914, 0x015e, 0x0005, 0x0066, 0x0126, 0x2091,
+	0x8000, 0x2031, 0x0001, 0x601c, 0xa084, 0x000f, 0x0083, 0x012e,
+	0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066, 0x2031, 0x0000,
+	0x601c, 0xa084, 0x000f, 0x001b, 0x006e, 0x012e, 0x0005, 0x9954,
+	0x9954, 0x994f, 0x9976, 0x9942, 0x994f, 0x9976, 0x994f, 0x994f,
+	0x9942, 0x994f, 0x080c, 0x1515, 0x0036, 0x2019, 0x0010, 0x080c,
+	0xace0, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0xa006,
+	0x0005, 0xa085, 0x0001, 0x0005, 0x00d6, 0x86ff, 0x11d8, 0x6010,
+	0x2068, 0x080c, 0x9c5a, 0x01c0, 0x6834, 0xa086, 0x0139, 0x1128,
+	0x684b, 0x0005, 0x6853, 0x0000, 0x0028, 0xa00e, 0x2001, 0x0005,
+	0x080c, 0x54db, 0x080c, 0x9ed2, 0x080c, 0x5408, 0x080c, 0x861d,
+	0xa085, 0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a,
+	0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005, 0x998d, 0x99ae, 0x998f,
+	0x99cd, 0x99ab, 0x998d, 0x994f, 0x9954, 0x9954, 0x994f, 0x994f,
+	0x994f, 0x994f, 0x994f, 0x994f, 0x994f, 0x080c, 0x1515, 0x86ff,
+	0x11b8, 0x601c, 0xa086, 0x0006, 0x0198, 0x00d6, 0x6010, 0x2068,
+	0x080c, 0x9c5a, 0x0110, 0x080c, 0x9ed2, 0x00de, 0x6007, 0x0085,
+	0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d, 0x080c, 0x7173,
+	0xa085, 0x0001, 0x0005, 0x080c, 0x194d, 0x0c08, 0x00e6, 0x2071,
+	0xb7e0, 0x7024, 0xac06, 0x1110, 0x080c, 0x7f59, 0x601c, 0xa084,
+	0x000f, 0xa086, 0x0006, 0x1150, 0x0086, 0x0096, 0x2049, 0x0001,
+	0x2c40, 0x080c, 0x8130, 0x009e, 0x008e, 0x0010, 0x080c, 0x7e58,
+	0x00ee, 0x1928, 0x080c, 0x994f, 0x0005, 0x0036, 0x00e6, 0x2071,
+	0xb7e0, 0x703c, 0xac06, 0x1140, 0x2019, 0x0000, 0x080c, 0x7fe4,
+	0x00ee, 0x003e, 0x0804, 0x998f, 0x080c, 0x825d, 0x00ee, 0x003e,
+	0x1904, 0x998f, 0x080c, 0x994f, 0x0005, 0x00c6, 0x601c, 0xa084,
+	0x000f, 0x0013, 0x00ce, 0x0005, 0x99fe, 0x9a6b, 0x9bb9, 0x9a09,
+	0x9e1d, 0x99fe, 0xacd2, 0xa14e, 0x9a6b, 0x99f7, 0x9c24, 0x080c,
+	0x1515, 0x080c, 0x9e58, 0x1110, 0x080c, 0x8c19, 0x0005, 0x080c,
+	0x7090, 0x080c, 0x7173, 0x080c, 0x861d, 0x0005, 0x6017, 0x0001,
+	0x0005, 0x080c, 0x9c5a, 0x0120, 0x6010, 0xa080, 0x0019, 0x2c02,
+	0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005, 0x9a27,
+	0x9a29, 0x9a49, 0x9a5b, 0x9a68, 0x9a27, 0x99fe, 0x99fe, 0x99fe,
+	0x9a5b, 0x9a5b, 0x9a27, 0x9a27, 0x9a27, 0x9a27, 0x9a65, 0x080c,
+	0x1515, 0x00e6, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071,
+	0xb7e0, 0x7024, 0xac06, 0x0190, 0x080c, 0x7e58, 0x6007, 0x0085,
+	0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xb7b7, 0x2004, 0x6016,
+	0x080c, 0x6c8d, 0x080c, 0x7173, 0x00ee, 0x0005, 0x6017, 0x0001,
+	0x0cd8, 0x00d6, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x6c8d,
+	0x080c, 0x7173, 0x0005, 0x00d6, 0x6017, 0x0001, 0x6010, 0x2068,
+	0x6850, 0xc0b5, 0x6852, 0x00de, 0x0005, 0x080c, 0x861d, 0x0005,
+	0x080c, 0x194d, 0x08f0, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515,
+	0x000b, 0x0005, 0x9a82, 0x9a06, 0x9a84, 0x9a82, 0x9a84, 0x9a84,
+	0x99ff, 0x9a82, 0x99f9, 0x99f9, 0x9a82, 0x9a82, 0x9a82, 0x9a82,
+	0x9a82, 0x9a82, 0x080c, 0x1515, 0x00d6, 0x6018, 0x2068, 0x6804,
+	0xa084, 0x00ff, 0x00de, 0xa08a, 0x000c, 0x1a0c, 0x1515, 0x000b,
+	0x0005, 0x9a9d, 0x9b5f, 0x9a9f, 0x9add, 0x9a9f, 0x9add, 0x9a9f,
+	0x9aad, 0x9a9d, 0x9add, 0x9a9d, 0x9ac9, 0x080c, 0x1515, 0x6004,
+	0xa08e, 0x0016, 0x05a8, 0xa08e, 0x0004, 0x0590, 0xa08e, 0x0002,
+	0x0578, 0xa08e, 0x004b, 0x0904, 0x9b5b, 0x6004, 0x080c, 0x9e58,
+	0x0904, 0x9b78, 0xa08e, 0x0021, 0x0904, 0x9b7c, 0xa08e, 0x0022,
+	0x0904, 0x9b78, 0xa08e, 0x003d, 0x0904, 0x9b7c, 0xa08e, 0x0039,
+	0x0904, 0x9b80, 0xa08e, 0x0035, 0x0904, 0x9b80, 0xa08e, 0x001e,
+	0x0188, 0xa08e, 0x0001, 0x1150, 0x00d6, 0x6018, 0x2068, 0x6804,
+	0xa084, 0x00ff, 0x00de, 0xa086, 0x0006, 0x0110, 0x080c, 0x2c9c,
+	0x080c, 0x8c19, 0x080c, 0x9e1d, 0x0005, 0x00c6, 0x00d6, 0x6104,
+	0xa186, 0x0016, 0x0904, 0x9b4c, 0xa186, 0x0002, 0x15d8, 0x2001,
+	0xb535, 0x2004, 0xd08c, 0x1198, 0x080c, 0x5acf, 0x1180, 0x2001,
+	0xb79f, 0x2003, 0x0001, 0x2001, 0xb500, 0x2003, 0x0001, 0xa085,
+	0x0001, 0x080c, 0x5b13, 0x080c, 0x5a07, 0x0804, 0x9ba2, 0x6018,
+	0x2068, 0x2001, 0xb535, 0x2004, 0xd0ac, 0x1904, 0x9ba2, 0x68a0,
+	0xd0bc, 0x1904, 0x9ba2, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0190,
+	0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007, 0x6017, 0x0398,
+	0x603f, 0x0000, 0x080c, 0x85c7, 0x0128, 0x2d00, 0x601a, 0x601f,
+	0x0001, 0x0450, 0x00de, 0x00ce, 0x6004, 0xa08e, 0x0002, 0x11a8,
+	0x6018, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1170, 0x2009,
+	0xb535, 0x2104, 0xc085, 0x200a, 0x00e6, 0x2071, 0xb500, 0x080c,
+	0x4bc6, 0x00ee, 0x080c, 0x8c19, 0x0020, 0x080c, 0x8c19, 0x080c,
+	0x2c9c, 0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2cc2, 0x012e,
+	0x00ee, 0x080c, 0x9e1d, 0x0005, 0x2001, 0x0002, 0x080c, 0x4efd,
+	0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3, 0x080c, 0x7173,
+	0x00de, 0x00ce, 0x0c80, 0x080c, 0x2cc2, 0x0804, 0x9ad8, 0x00c6,
+	0x00d6, 0x6104, 0xa186, 0x0016, 0x0d38, 0x6018, 0x2068, 0x6840,
+	0xa084, 0x00ff, 0xa005, 0x0904, 0x9b22, 0x8001, 0x6842, 0x6003,
+	0x0001, 0x080c, 0x6cd3, 0x080c, 0x7173, 0x00de, 0x00ce, 0x0898,
+	0x080c, 0x8c19, 0x0804, 0x9ada, 0x080c, 0x8c47, 0x0804, 0x9ada,
+	0x00d6, 0x2c68, 0x6104, 0x080c, 0xa10a, 0x00de, 0x0118, 0x080c,
+	0x861d, 0x00b8, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105,
+	0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038,
+	0x600a, 0x2001, 0xb7b7, 0x2004, 0x6016, 0x080c, 0x6c8d, 0x080c,
+	0x7173, 0x0005, 0x00de, 0x00ce, 0x080c, 0x8c19, 0x080c, 0x2c9c,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2cc2, 0x6013, 0x0000,
+	0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x012e, 0x00ee,
+	0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x1515, 0x000b, 0x0005,
+	0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0, 0x9bd0,
+	0x9bd0, 0x99fe, 0x9bd0, 0x9a06, 0x9bd2, 0x9a06, 0x9bdf, 0x9bd0,
+	0x080c, 0x1515, 0x6004, 0xa086, 0x008b, 0x0148, 0x6007, 0x008b,
+	0x6003, 0x000d, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0005, 0x080c,
+	0x9e11, 0x080c, 0x9c5a, 0x0580, 0x080c, 0x2c9c, 0x00d6, 0x080c,
+	0x9c5a, 0x0168, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006,
+	0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x080c, 0x5408, 0x2c68,
+	0x080c, 0x85c7, 0x0150, 0x6818, 0x601a, 0x080c, 0xa027, 0x00c6,
+	0x2d60, 0x080c, 0x9e1d, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6013,
+	0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x6cd3, 0x080c, 0x7173, 0x0078, 0x6030, 0xa08c, 0xff00, 0x810f,
+	0xa186, 0x0039, 0x0118, 0xa186, 0x0035, 0x1118, 0x080c, 0x2c9c,
+	0x08b0, 0x080c, 0x9e1d, 0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c,
+	0x1515, 0x000b, 0x0005, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3d, 0x9c3d,
+	0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b, 0x9c3b,
+	0x9c3b, 0x9c3b, 0x9c3b, 0x080c, 0x1515, 0x080c, 0x825d, 0x190c,
+	0x1515, 0x6110, 0x2168, 0x684b, 0x0006, 0x080c, 0x5408, 0x080c,
+	0x861d, 0x0005, 0xa284, 0x0007, 0x1158, 0xa282, 0xbd00, 0x0240,
+	0x2001, 0xb517, 0x2004, 0xa202, 0x1218, 0xa085, 0x0001, 0x0005,
+	0xa006, 0x0ce8, 0x0026, 0x6210, 0xa294, 0xf000, 0x002e, 0x0005,
+	0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061,
+	0xbd00, 0x2071, 0xb500, 0x7348, 0x7068, 0xa302, 0x12a8, 0x601c,
+	0xa206, 0x1160, 0x080c, 0x9fb2, 0x0148, 0x080c, 0x9e58, 0x1110,
+	0x080c, 0x8c19, 0x00c6, 0x080c, 0x861d, 0x00ce, 0xace0, 0x0018,
+	0x705c, 0xac02, 0x1208, 0x0c38, 0x012e, 0x000e, 0x003e, 0x00ce,
+	0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0xa188, 0xb635, 0x210c,
+	0x81ff, 0x0128, 0x2061, 0xb8f4, 0x611a, 0x080c, 0x2c9c, 0xa006,
+	0x0010, 0xa085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6,
+	0x0056, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x005e,
+	0x0180, 0x6612, 0x651a, 0x080c, 0xa027, 0x601f, 0x0003, 0x2009,
+	0x004b, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce,
+	0x0005, 0xa006, 0x0cd0, 0x00c6, 0x0056, 0x0126, 0x2091, 0x8000,
+	0x62a0, 0x00c6, 0x080c, 0x9ed6, 0x005e, 0x0550, 0x6013, 0x0000,
+	0x651a, 0x080c, 0xa027, 0x601f, 0x0003, 0x0016, 0x00c6, 0x2560,
+	0x080c, 0x51aa, 0x00ce, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000,
+	0x080c, 0x6d02, 0x2c08, 0x080c, 0xae82, 0x007e, 0x001e, 0xd184,
+	0x0128, 0x080c, 0x861d, 0xa085, 0x0001, 0x0030, 0x2009, 0x004c,
+	0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005,
+	0xa006, 0x0cd0, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c, 0x85c7,
+	0x2c78, 0x00ce, 0x0180, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003,
+	0x2021, 0x0005, 0x080c, 0x9d50, 0x2f60, 0x2009, 0x004d, 0x080c,
+	0x864c, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6,
+	0x00c6, 0x0046, 0x00c6, 0x080c, 0x85c7, 0x2c78, 0x00ce, 0x0178,
+	0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x0481,
+	0x2f60, 0x2009, 0x004e, 0x080c, 0x864c, 0xa085, 0x0001, 0x004e,
+	0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c,
+	0x85c7, 0x2c78, 0x00ce, 0x01c0, 0x7e12, 0x2c00, 0x781a, 0x781f,
+	0x0003, 0x2021, 0x0004, 0x00a1, 0x2001, 0xb7a0, 0x2004, 0xd0fc,
+	0x0120, 0x2f60, 0x080c, 0x861d, 0x0028, 0x2f60, 0x2009, 0x0052,
+	0x080c, 0x864c, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005,
+	0x0096, 0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0x514c, 0x0118,
+	0x2001, 0x9d55, 0x0028, 0x080c, 0x511c, 0x0158, 0x2001, 0x9d5b,
+	0x0006, 0xa00e, 0x2400, 0x080c, 0x54db, 0x080c, 0x5408, 0x000e,
+	0x0807, 0x2418, 0x080c, 0x702f, 0x62a0, 0x0086, 0x2041, 0x0001,
+	0x2039, 0x0001, 0x2608, 0x080c, 0x6e0e, 0x008e, 0x080c, 0x6d02,
+	0x2f08, 0x2648, 0x080c, 0xae82, 0x613c, 0x81ff, 0x090c, 0x6ec3,
+	0x080c, 0x7173, 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a,
+	0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009,
+	0x001f, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c,
+	0x85c7, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, 0xa027, 0x601f,
+	0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x080c, 0x864c, 0xa085,
+	0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a,
+	0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009,
+	0x003d, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c,
+	0x9ed6, 0x001e, 0x0180, 0x611a, 0x080c, 0xa027, 0x601f, 0x0001,
+	0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x864c, 0xa085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091,
+	0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0188, 0x660a, 0x611a,
+	0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0044,
+	0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006,
+	0x0cd8, 0x0026, 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff, 0x0110,
+	0x8211, 0x6a3e, 0x00de, 0x002e, 0x0005, 0x0006, 0x6000, 0xa086,
+	0x0000, 0x0190, 0x6013, 0x0000, 0x601f, 0x0007, 0x2001, 0xb7b6,
+	0x2004, 0x0006, 0xa082, 0x0051, 0x000e, 0x0208, 0x8004, 0x6016,
+	0x080c, 0xb33a, 0x603f, 0x0000, 0x000e, 0x0005, 0x0066, 0x00c6,
+	0x00d6, 0x2031, 0xb553, 0x2634, 0xd6e4, 0x0128, 0x6618, 0x2660,
+	0x6e48, 0x080c, 0x50d5, 0x00de, 0x00ce, 0x006e, 0x0005, 0x0006,
+	0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003, 0x0128,
+	0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e, 0x0005,
+	0x0006, 0x00d6, 0x6010, 0xa06d, 0x0148, 0x6834, 0xa086, 0x0139,
+	0x0138, 0x6838, 0xd0fc, 0x0110, 0xa006, 0x0010, 0xa085, 0x0001,
+	0x00de, 0x000e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6,
+	0x080c, 0x85c7, 0x001e, 0x0190, 0x611a, 0x080c, 0xa027, 0x601f,
+	0x0001, 0x2d00, 0x6012, 0x080c, 0x2c9c, 0x2009, 0x0028, 0x080c,
+	0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8,
+	0xa186, 0x0015, 0x1178, 0x2011, 0xb521, 0x2204, 0xa086, 0x0074,
+	0x1148, 0x080c, 0x8f98, 0x6003, 0x0001, 0x6007, 0x0029, 0x080c,
+	0x6cd3, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x0005, 0xa186,
+	0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x4efd, 0x00e8, 0xa186,
+	0x0015, 0x11e8, 0x2011, 0xb521, 0x2204, 0xa086, 0x0014, 0x11b8,
+	0x00d6, 0x6018, 0x2068, 0x080c, 0x504b, 0x00de, 0x080c, 0x9051,
+	0x1170, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, 0x0138,
+	0x2001, 0x0006, 0x080c, 0x4efd, 0x080c, 0x87a0, 0x0020, 0x080c,
+	0x8c19, 0x080c, 0x861d, 0x0005, 0x6848, 0xa086, 0x0005, 0x1108,
+	0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, 0x0005, 0x00e6, 0x0126,
+	0x2071, 0xb500, 0x2091, 0x8000, 0x7548, 0xa582, 0x0001, 0x0608,
+	0x704c, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018,
+	0x705c, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xbd00, 0x0c98, 0x6003,
+	0x0008, 0x8529, 0x754a, 0xaca8, 0x0018, 0x705c, 0xa502, 0x1230,
+	0x754e, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704f, 0xbd00,
+	0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xbb8c, 0x7014, 0xd0e4,
+	0x0150, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c,
+	0x6c8d, 0x080c, 0x7173, 0x00ee, 0x0005, 0x00c6, 0x00f6, 0x2c78,
+	0x080c, 0x5305, 0x00fe, 0x0120, 0x601c, 0xa084, 0x000f, 0x0013,
+	0x00ce, 0x0005, 0x99fe, 0x9f2d, 0x9f30, 0x9f33, 0xb127, 0xb142,
+	0xb145, 0x99fe, 0x99fe, 0x080c, 0x1515, 0xe000, 0xe000, 0x0005,
+	0xe000, 0xe000, 0x0005, 0x0009, 0x0005, 0x00f6, 0x2c78, 0x080c,
+	0x5305, 0x0538, 0x080c, 0x85c7, 0x1128, 0x2001, 0xb7b8, 0x2004,
+	0x783e, 0x00f8, 0x7818, 0x601a, 0x080c, 0xa027, 0x781c, 0xa086,
+	0x0003, 0x0128, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0020, 0x7808,
+	0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035,
+	0x6003, 0x0001, 0x7950, 0x6152, 0x080c, 0x6c8d, 0x080c, 0x7173,
+	0x2f60, 0x00fe, 0x0005, 0x0016, 0x00f6, 0x682c, 0x6032, 0xa08e,
+	0x0001, 0x0138, 0xa086, 0x0005, 0x0140, 0xa006, 0x602a, 0x602e,
+	0x00a0, 0x6820, 0xc0f4, 0xc0d5, 0x6822, 0x6810, 0x2078, 0x787c,
+	0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x1e78, 0x6834, 0x602a,
+	0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036, 0x6808,
+	0x603a, 0x6918, 0x611a, 0x6950, 0x6152, 0x601f, 0x0001, 0x6007,
+	0x0039, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x6803, 0x0002, 0x00fe,
+	0x001e, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5305, 0x1118, 0xa085,
+	0x0001, 0x0070, 0x6020, 0xd0f4, 0x1150, 0xc0f5, 0x6022, 0x6010,
+	0x2078, 0x7828, 0x603a, 0x782c, 0x6036, 0x080c, 0x194d, 0xa006,
+	0x00fe, 0x0005, 0x0006, 0x0016, 0x6004, 0xa08e, 0x0034, 0x01b8,
+	0xa08e, 0x0035, 0x01a0, 0xa08e, 0x0036, 0x0188, 0xa08e, 0x0037,
+	0x0170, 0xa08e, 0x0038, 0x0158, 0xa08e, 0x0039, 0x0140, 0xa08e,
+	0x003a, 0x0128, 0xa08e, 0x003b, 0x0110, 0xa085, 0x0001, 0x001e,
+	0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, 0x2001,
+	0xb7b2, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x080c, 0x6b40,
+	0x2001, 0xb7b6, 0x82ff, 0x1110, 0x2011, 0x0014, 0x2202, 0x2001,
+	0xb7b4, 0x200c, 0x8000, 0x2014, 0x2071, 0xb78e, 0x711a, 0x721e,
+	0x2001, 0x0064, 0x080c, 0x6b40, 0x2001, 0xb7b7, 0x82ff, 0x1110,
+	0x2011, 0x0014, 0x2202, 0x2009, 0xb7b8, 0xa280, 0x000a, 0x200a,
+	0x080c, 0x532a, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x0006, 0x00e6, 0x2001, 0xb7b6, 0x2003, 0x0028, 0x2001, 0xb7b7,
+	0x2003, 0x0014, 0x2071, 0xb78e, 0x701b, 0x0000, 0x701f, 0x07d0,
+	0x2001, 0xb7b8, 0x2003, 0x001e, 0x00ee, 0x000e, 0x0005, 0x00d6,
+	0x6054, 0xa06d, 0x0110, 0x080c, 0x160f, 0x00de, 0x0005, 0x0005,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e,
+	0x0178, 0x611a, 0x0ca1, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009,
+	0x0033, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0xa006, 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb500, 0xa186,
+	0x0015, 0x1500, 0x7084, 0xa086, 0x0018, 0x11e0, 0x6010, 0x2068,
+	0x6a3c, 0xd2e4, 0x1160, 0x2c78, 0x080c, 0x7331, 0x01d8, 0x7070,
+	0x6a50, 0xa206, 0x1160, 0x7074, 0x6a54, 0xa206, 0x1140, 0x6218,
+	0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x080c,
+	0x87a0, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x00fe, 0x00ee,
+	0x00de, 0x0005, 0x7054, 0x6a54, 0xa206, 0x0d48, 0x0c80, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x85c7, 0x001e, 0x0180,
+	0x611a, 0x080c, 0xa027, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009,
+	0x0043, 0x080c, 0x864c, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0xa006, 0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xb500, 0xa186,
+	0x0015, 0x11c0, 0x7084, 0xa086, 0x0004, 0x11a0, 0x6010, 0xa0e8,
+	0x000f, 0x2c78, 0x080c, 0x7331, 0x01a8, 0x7070, 0x6a08, 0xa206,
+	0x1130, 0x7074, 0x6a0c, 0xa206, 0x1110, 0x080c, 0x2c9c, 0x080c,
+	0x87a0, 0x0020, 0x080c, 0x8c19, 0x080c, 0x861d, 0x00fe, 0x00ee,
+	0x00de, 0x0005, 0x7054, 0x6a0c, 0xa206, 0x0d78, 0x0c80, 0x0016,
+	0x0026, 0x684c, 0xd0ac, 0x0178, 0x6914, 0x6a10, 0x2100, 0xa205,
+	0x0150, 0x6860, 0xa106, 0x1118, 0x685c, 0xa206, 0x0120, 0x6962,
+	0x6a5e, 0xa085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036,
+	0x6310, 0x2368, 0x684a, 0x6952, 0xa29e, 0x4000, 0x11a0, 0x00c6,
+	0x6318, 0x2360, 0x2009, 0x0000, 0x6838, 0xd0f4, 0x1140, 0x080c,
+	0x524a, 0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x6a66,
+	0x696a, 0x00ce, 0x0080, 0x6a66, 0x3918, 0xa398, 0x0006, 0x231c,
+	0x686b, 0x0004, 0x6b72, 0x00c6, 0x6318, 0x2360, 0x6004, 0xa084,
+	0x00ff, 0x686e, 0x00ce, 0x080c, 0x5408, 0x6013, 0x0000, 0x003e,
+	0x00de, 0x0005, 0x00c6, 0x0026, 0x0016, 0xa186, 0x0035, 0x0110,
+	0x6a34, 0x0008, 0x6a28, 0x080c, 0x9c4a, 0x01f0, 0x2260, 0x611c,
+	0xa186, 0x0003, 0x0118, 0xa186, 0x0006, 0x1190, 0x6834, 0xa206,
+	0x0140, 0x6838, 0xa206, 0x1160, 0x6108, 0x6834, 0xa106, 0x1140,
+	0x0020, 0x6008, 0x6938, 0xa106, 0x1118, 0x6018, 0x6918, 0xa106,
+	0x001e, 0x002e, 0x00ce, 0x0005, 0xa085, 0x0001, 0x0cc8, 0x6944,
+	0xd1cc, 0x0198, 0xa18c, 0x00ff, 0xa18e, 0x0002, 0x1170, 0xad88,
+	0x001e, 0x210c, 0xa18c, 0x0f00, 0x810f, 0xa18e, 0x0001, 0x1128,
+	0x6810, 0x6914, 0xa115, 0x190c, 0x9483, 0x0005, 0x080c, 0x861d,
+	0x0804, 0x7173, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515,
+	0x0013, 0x006e, 0x0005, 0xa16b, 0xa646, 0xa76c, 0xa16b, 0xa16b,
+	0xa16b, 0xa16b, 0xa16b, 0xa1a3, 0xa7f0, 0xa16b, 0xa16b, 0xa16b,
+	0xa16b, 0xa16b, 0xa16b, 0x080c, 0x1515, 0x0066, 0x6000, 0xa0b2,
+	0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e, 0x0005, 0xa186, 0xac77,
+	0xa186, 0xa186, 0xa186, 0xa186, 0xa186, 0xa186, 0xac39, 0xacbf,
+	0xa186, 0xb26c, 0xb29c, 0xb26c, 0xb29c, 0xa186, 0x080c, 0x1515,
+	0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x1515, 0x0013, 0x006e,
+	0x0005, 0xa1a1, 0xa940, 0xaa0d, 0xaa3a, 0xaabe, 0xa1a1, 0xabab,
+	0xab56, 0xa7fc, 0xac0f, 0xac24, 0xa1a1, 0xa1a1, 0xa1a1, 0xa1a1,
+	0xa1a1, 0x080c, 0x1515, 0xa1b2, 0x0080, 0x1a0c, 0x1515, 0x2100,
+	0xa1b2, 0x0040, 0x1a04, 0xa5ba, 0x0002, 0xa1ed, 0xa3b8, 0xa1ed,
+	0xa1ed, 0xa1ed, 0xa3bf, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed,
+	0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed,
+	0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ef, 0xa24d, 0xa25c, 0xa2aa,
+	0xa2c8, 0xa346, 0xa3a5, 0xa1ed, 0xa1ed, 0xa3c2, 0xa1ed, 0xa1ed,
+	0xa3d5, 0xa3e0, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa46b,
+	0xa1ed, 0xa1ed, 0xa47e, 0xa1ed, 0xa1ed, 0xa436, 0xa1ed, 0xa1ed,
+	0xa1ed, 0xa496, 0xa1ed, 0xa1ed, 0xa1ed, 0xa510, 0xa1ed, 0xa1ed,
+	0xa1ed, 0xa1ed, 0xa1ed, 0xa1ed, 0xa581, 0x080c, 0x1515, 0x080c,
+	0x5309, 0x1150, 0x2001, 0xb535, 0x2004, 0xd0cc, 0x1128, 0xa084,
+	0x0009, 0xa086, 0x0008, 0x1140, 0x6007, 0x0009, 0x602b, 0x0009,
+	0x6013, 0x0000, 0x0804, 0xa3b3, 0x080c, 0x52f9, 0x00e6, 0x00c6,
+	0x0036, 0x0026, 0x0016, 0x6218, 0x2270, 0x72a0, 0x0026, 0x2019,
+	0x0029, 0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02,
+	0x2c08, 0x080c, 0xae82, 0x007e, 0x001e, 0x2e60, 0x080c, 0x51aa,
+	0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x6618, 0x00c6, 0x2660,
+	0x080c, 0x4fb8, 0x00ce, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff,
+	0xa082, 0x0006, 0x0278, 0x080c, 0xadc6, 0x1904, 0xa2a4, 0x080c,
+	0xad66, 0x1120, 0x6007, 0x0008, 0x0804, 0xa3b3, 0x6007, 0x0009,
+	0x0804, 0xa3b3, 0x080c, 0xaf7b, 0x0128, 0x080c, 0xadc6, 0x0d78,
+	0x0804, 0xa2a4, 0x6013, 0x1900, 0x0c88, 0x080c, 0x2dbf, 0x1904,
+	0xa5b7, 0x6106, 0x080c, 0xad20, 0x6007, 0x0006, 0x0804, 0xa3b3,
+	0x6007, 0x0007, 0x0804, 0xa3b3, 0x080c, 0xb2d0, 0x1904, 0xa5b7,
+	0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x00d6, 0x6618, 0x2668, 0x6e04,
+	0xa684, 0x00ff, 0xa082, 0x0006, 0x1220, 0x2001, 0x0001, 0x080c,
+	0x4eeb, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0188, 0xa686,
+	0x0004, 0x0170, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006, 0x0140,
+	0xa686, 0x0004, 0x0128, 0xa686, 0x0005, 0x0110, 0x00de, 0x00e0,
+	0x080c, 0xae24, 0x11a0, 0xa686, 0x0006, 0x1150, 0x0026, 0x6218,
+	0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x002e,
+	0x080c, 0x504b, 0x6007, 0x000a, 0x00de, 0x0804, 0xa3b3, 0x6007,
+	0x000b, 0x00de, 0x0804, 0xa3b3, 0x080c, 0x2c9c, 0x6007, 0x0001,
+	0x0804, 0xa3b3, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf,
+	0x1904, 0xa5b7, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa686,
+	0x0707, 0x0d50, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009,
+	0x0000, 0x080c, 0x2ce1, 0x002e, 0x6007, 0x000c, 0x0804, 0xa3b3,
+	0x080c, 0x5309, 0x1140, 0x2001, 0xb535, 0x2004, 0xa084, 0x0009,
+	0xa086, 0x0008, 0x1110, 0x0804, 0xa1fc, 0x080c, 0x52f9, 0x6618,
+	0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06e8,
+	0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x4f2a, 0x002e, 0x0050,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006,
+	0x1904, 0xa2a4, 0x080c, 0xae31, 0x1120, 0x6007, 0x000e, 0x0804,
+	0xa3b3, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff,
+	0x8427, 0x0046, 0x080c, 0x2c9c, 0x004e, 0x0016, 0xa006, 0x2009,
+	0xb553, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xb0e8,
+	0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x0804, 0xa3b3, 0x2001, 0x0001, 0x080c,
+	0x4eeb, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0xb505, 0x2011, 0xbb90, 0x080c, 0x90da, 0x003e, 0x002e, 0x001e,
+	0x015e, 0xa005, 0x0168, 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004,
+	0x0a04, 0xa2a4, 0xa682, 0x0007, 0x0a04, 0xa2f2, 0x0804, 0xa2a4,
+	0x6013, 0x1900, 0x6007, 0x0009, 0x0804, 0xa3b3, 0x080c, 0x5309,
+	0x1140, 0x2001, 0xb535, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008,
+	0x1110, 0x0804, 0xa1fc, 0x080c, 0x52f9, 0x6618, 0xa6b0, 0x0001,
+	0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06b8, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0xa2a4,
+	0x080c, 0xae59, 0x1138, 0x080c, 0xad66, 0x1120, 0x6007, 0x0010,
+	0x0804, 0xa3b3, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4,
+	0x00ff, 0x8427, 0x0046, 0x080c, 0x2c9c, 0x004e, 0x0016, 0xa006,
+	0x2009, 0xb553, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c,
+	0xb0e8, 0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de,
+	0x001e, 0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xaf7b, 0x0140,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0950, 0x0804, 0xa2a4,
+	0x6013, 0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x2dbf, 0x1904,
+	0xa5b7, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0xa5df, 0x1904,
+	0xa2a4, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0cc0, 0x6007,
+	0x0005, 0x0cc0, 0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf,
+	0x1904, 0xa5b7, 0x080c, 0xa5df, 0x1904, 0xa2a4, 0x6007, 0x0020,
+	0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x080c, 0x2dbf, 0x1904,
+	0xa5b7, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005,
+	0x080c, 0xb2d0, 0x1904, 0xa5b7, 0x080c, 0x2dbf, 0x1904, 0xa5b7,
+	0x080c, 0xa5df, 0x1904, 0xa2a4, 0x0016, 0x0026, 0x2011, 0xbb91,
+	0x2214, 0xa286, 0xffff, 0x0190, 0x2c08, 0x080c, 0x9c4a, 0x01e0,
+	0x2260, 0x2011, 0xbb90, 0x2214, 0x6008, 0xa206, 0x11a8, 0x6018,
+	0xa190, 0x0006, 0x2214, 0xa206, 0x01e8, 0x0070, 0x2011, 0xbb90,
+	0x2214, 0x2c08, 0xa006, 0x080c, 0xb0ba, 0x11a0, 0x2011, 0xbb91,
+	0x2214, 0xa286, 0xffff, 0x01c0, 0x2160, 0x6007, 0x0026, 0x6013,
+	0x1700, 0x2011, 0xbb89, 0x2214, 0xa296, 0xffff, 0x1180, 0x6007,
+	0x0025, 0x0068, 0x601c, 0xa086, 0x0007, 0x1d70, 0x6004, 0xa086,
+	0x0024, 0x1110, 0x080c, 0x861d, 0x2160, 0x6007, 0x0025, 0x6003,
+	0x0001, 0x080c, 0x6cd3, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001,
+	0x080c, 0x4eeb, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004,
+	0x2019, 0xb505, 0x2011, 0xbb96, 0x080c, 0x90da, 0x003e, 0x002e,
+	0x001e, 0x015e, 0x0120, 0x6007, 0x0031, 0x0804, 0xa3b3, 0x080c,
+	0x8df6, 0x080c, 0x5acf, 0x11b0, 0x0006, 0x0026, 0x0036, 0x080c,
+	0x5aeb, 0x1158, 0x2001, 0xb79f, 0x2003, 0x0001, 0x2001, 0xb500,
+	0x2003, 0x0001, 0x080c, 0x5a07, 0x0010, 0x080c, 0x5aa6, 0x003e,
+	0x002e, 0x000e, 0x0005, 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x080c,
+	0xa5df, 0x1904, 0xa2a4, 0x6106, 0x080c, 0xa5fb, 0x6007, 0x002b,
+	0x0804, 0xa3b3, 0x6007, 0x002c, 0x0804, 0xa3b3, 0x080c, 0xb2d0,
+	0x1904, 0xa5b7, 0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x080c, 0xa5df,
+	0x1904, 0xa2a4, 0x6106, 0x080c, 0xa5ff, 0x1120, 0x6007, 0x002e,
+	0x0804, 0xa3b3, 0x6007, 0x002f, 0x0804, 0xa3b3, 0x080c, 0x2dbf,
+	0x1904, 0xa5b7, 0x00e6, 0x00d6, 0x00c6, 0x6018, 0xa080, 0x0001,
+	0x200c, 0xa184, 0x00ff, 0xa086, 0x0006, 0x0158, 0xa184, 0xff00,
+	0x8007, 0xa086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804,
+	0xa3b8, 0x2001, 0xb572, 0x2004, 0xd0e4, 0x0904, 0xa50d, 0x2071,
+	0xbb8c, 0x7010, 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001,
+	0xb553, 0x2004, 0xd0a4, 0x0140, 0x6018, 0x2068, 0x6810, 0xa106,
+	0x1118, 0x6814, 0xa206, 0x01f8, 0x2001, 0xb553, 0x2004, 0xd0ac,
+	0x1590, 0x2069, 0xb500, 0x6874, 0xa206, 0x1568, 0x6870, 0xa106,
+	0x1550, 0x7210, 0x080c, 0x9c4a, 0x0558, 0x080c, 0xb154, 0x0540,
+	0x622a, 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x00ce,
+	0x00de, 0x00ee, 0x0005, 0x7214, 0xa286, 0xffff, 0x0150, 0x080c,
+	0x9c4a, 0x01b0, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x1180,
+	0x0c08, 0x7210, 0x2c08, 0xa085, 0x0001, 0x080c, 0xb0ba, 0x2c10,
+	0x2160, 0x0130, 0x08b8, 0x6007, 0x0037, 0x6013, 0x1500, 0x08d8,
+	0x6007, 0x0037, 0x6013, 0x1700, 0x08b0, 0x6007, 0x0012, 0x0898,
+	0x080c, 0x2dbf, 0x1904, 0xa5b7, 0x6018, 0xa080, 0x0001, 0x2004,
+	0xa084, 0xff00, 0x8007, 0xa086, 0x0006, 0x1904, 0xa3b8, 0x00e6,
+	0x00d6, 0x00c6, 0x2001, 0xb572, 0x2004, 0xd0e4, 0x0904, 0xa579,
+	0x2069, 0xb500, 0x2071, 0xbb8c, 0x7008, 0x6036, 0x720c, 0x623a,
+	0xa286, 0xffff, 0x1150, 0x7208, 0x00c6, 0x2c08, 0xa085, 0x0001,
+	0x080c, 0xb0ba, 0x2c10, 0x00ce, 0x0588, 0x080c, 0x9c4a, 0x0570,
+	0x00c6, 0x0026, 0x2260, 0x080c, 0x991d, 0x002e, 0x00ce, 0x7118,
+	0xa18c, 0xff00, 0x810f, 0xa186, 0x0001, 0x0158, 0xa186, 0x0005,
+	0x0118, 0xa186, 0x0007, 0x1178, 0xa280, 0x0004, 0x2004, 0xa005,
+	0x0150, 0x0056, 0x7510, 0x7614, 0x080c, 0xb16b, 0x005e, 0x00ce,
+	0x00de, 0x00ee, 0x0005, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013,
+	0x2a00, 0x6003, 0x0001, 0x080c, 0x6c8d, 0x0c88, 0x6007, 0x003b,
+	0x602b, 0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x080c, 0x6c8d,
+	0x0c30, 0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0804,
+	0xa4e3, 0x00e6, 0x0026, 0x080c, 0x5309, 0x0558, 0x080c, 0x52f9,
+	0x080c, 0xb34b, 0x1520, 0x2071, 0xb500, 0x70d4, 0xc085, 0x70d6,
+	0x00f6, 0x2079, 0x0100, 0x72a0, 0xa284, 0x00ff, 0x7072, 0x78e6,
+	0xa284, 0xff00, 0x7274, 0xa205, 0x7076, 0x78ea, 0x00fe, 0x70df,
+	0x0000, 0x2001, 0xb553, 0x2004, 0xd0a4, 0x0120, 0x2011, 0xb7f9,
+	0x2013, 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x2ab8, 0x0010, 0x080c,
+	0xb377, 0x002e, 0x00ee, 0x080c, 0x861d, 0x0804, 0xa3b7, 0x080c,
+	0x861d, 0x0005, 0x2600, 0x0002, 0xa5c5, 0xa5c5, 0xa5c5, 0xa5c5,
+	0xa5c5, 0xa5c7, 0xa5c5, 0xa5c5, 0xa5c5, 0x080c, 0x1515, 0x080c,
+	0xb2d0, 0x1d68, 0x080c, 0x2dbf, 0x1d50, 0x0089, 0x1138, 0x6007,
+	0x0045, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x080c, 0x2c9c,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x6cd3, 0x0005, 0x00d6,
+	0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0006, 0x0170, 0xa686, 0x0004, 0x0158, 0x6e04, 0xa6b4, 0x00ff,
+	0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085, 0x0001,
+	0x006e, 0x00de, 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005, 0x00d6,
+	0x0491, 0x11f0, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084, 0x00ff,
+	0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, 0x0118, 0x2009, 0x0001,
+	0x0060, 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x080c,
+	0x281d, 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x2ce1, 0x0018,
+	0xa085, 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069, 0xbb8d,
+	0x6800, 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085, 0x0001,
+	0x0008, 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0xbb8c, 0x6808,
+	0xa084, 0xff00, 0xa086, 0x0800, 0x1140, 0x6800, 0xa084, 0x00ff,
+	0xa08e, 0x0014, 0x0110, 0xa08e, 0x0010, 0x0005, 0x6004, 0xa0b2,
+	0x0080, 0x1a0c, 0x1515, 0xa1b6, 0x0013, 0x1130, 0x2008, 0xa1b2,
+	0x0040, 0x1a04, 0xa746, 0x0092, 0xa1b6, 0x0027, 0x0120, 0xa1b6,
+	0x0014, 0x190c, 0x1515, 0x2001, 0x0007, 0x080c, 0x4f2a, 0x080c,
+	0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173, 0x0005, 0xa6a6, 0xa6a8,
+	0xa6a6, 0xa6a6, 0xa6a6, 0xa6a8, 0xa6ba, 0xa73f, 0xa70a, 0xa73f,
+	0xa71b, 0xa73f, 0xa6ba, 0xa73f, 0xa737, 0xa73f, 0xa737, 0xa73f,
+	0xa73f, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6,
+	0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a8, 0xa6a6, 0xa73f, 0xa6a6,
+	0xa6a6, 0xa73f, 0xa6a6, 0xa73c, 0xa73f, 0xa6a6, 0xa6a6, 0xa6a6,
+	0xa6a6, 0xa73f, 0xa73f, 0xa6a6, 0xa73f, 0xa73f, 0xa6a6, 0xa6b4,
+	0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0xa73b, 0xa73f, 0xa6a6, 0xa6a6,
+	0xa73f, 0xa73f, 0xa6a6, 0xa6a6, 0xa6a6, 0xa6a6, 0x080c, 0x1515,
+	0x080c, 0x7090, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x6003, 0x0002,
+	0x080c, 0x7173, 0x0804, 0xa745, 0x2001, 0x0000, 0x080c, 0x4eeb,
+	0x0804, 0xa73f, 0x00f6, 0x2079, 0xb552, 0x7804, 0x00fe, 0xd0ac,
+	0x1904, 0xa73f, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x6018, 0xa080,
+	0x0004, 0x2004, 0xa086, 0x00ff, 0x1140, 0x00f6, 0x2079, 0xb500,
+	0x7898, 0x8000, 0x789a, 0x00fe, 0x00e0, 0x00c6, 0x6018, 0x2060,
+	0x6000, 0xd0f4, 0x1140, 0x6010, 0xa005, 0x0128, 0x00ce, 0x080c,
+	0x3f3e, 0x0804, 0xa73f, 0x00ce, 0x2001, 0xb500, 0x2004, 0xa086,
+	0x0002, 0x1138, 0x00f6, 0x2079, 0xb500, 0x7898, 0x8000, 0x789a,
+	0x00fe, 0x2001, 0x0002, 0x080c, 0x4efd, 0x080c, 0x7090, 0x601f,
+	0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x6cd3, 0x080c,
+	0x7173, 0x00c6, 0x6118, 0x2160, 0x2009, 0x0001, 0x080c, 0x69a8,
+	0x00ce, 0x04d8, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4,
+	0xff00, 0x8637, 0xa686, 0x0006, 0x0550, 0xa686, 0x0004, 0x0538,
+	0x2001, 0x0004, 0x0410, 0x2001, 0xb500, 0x2004, 0xa086, 0x0003,
+	0x1110, 0x080c, 0x3f3e, 0x2001, 0x0006, 0x04a1, 0x6618, 0x00d6,
+	0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006,
+	0x0170, 0x2001, 0x0006, 0x0048, 0x2001, 0x0004, 0x0030, 0x2001,
+	0x0006, 0x0401, 0x0020, 0x0018, 0x0010, 0x080c, 0x4f2a, 0x080c,
+	0x7090, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x2600, 0x0002,
+	0xa751, 0xa751, 0xa751, 0xa751, 0xa751, 0xa753, 0xa751, 0xa751,
+	0xa751, 0x080c, 0x1515, 0x080c, 0x7090, 0x080c, 0x861d, 0x080c,
+	0x7173, 0x0005, 0x0016, 0x00d6, 0x6118, 0x2168, 0x6900, 0xd184,
+	0x0140, 0x080c, 0x4efd, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x080c,
+	0x2cc2, 0x00de, 0x001e, 0x0005, 0x00d6, 0x6618, 0x2668, 0x6804,
+	0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x1515,
+	0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028, 0xa1b6, 0x0016, 0x190c,
+	0x1515, 0x006b, 0x0005, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf,
+	0x8cdf, 0xa7dc, 0xa79b, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf,
+	0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0x8cdf, 0xa7dc, 0xa7e3, 0x8cdf,
+	0x8cdf, 0x8cdf, 0x8cdf, 0x00f6, 0x2079, 0xb552, 0x7804, 0xd0ac,
+	0x11e0, 0x6018, 0xa07d, 0x01c8, 0x7800, 0xd0f4, 0x1118, 0x7810,
+	0xa005, 0x1198, 0x2001, 0x0000, 0x080c, 0x4eeb, 0x2001, 0x0002,
+	0x080c, 0x4efd, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x6cd3, 0x080c, 0x7173, 0x00e8, 0x2011, 0xbb83, 0x2204,
+	0x8211, 0x220c, 0x080c, 0x281d, 0x11a8, 0x00c6, 0x080c, 0x4fa9,
+	0x0120, 0x00ce, 0x080c, 0x861d, 0x0068, 0x6010, 0x0006, 0x6014,
+	0x0006, 0x080c, 0x4c0b, 0x000e, 0x6016, 0x000e, 0x6012, 0x00ce,
+	0x080c, 0x861d, 0x00fe, 0x0005, 0x6604, 0xa6b6, 0x001e, 0x1110,
+	0x080c, 0x861d, 0x0005, 0x080c, 0x8f95, 0x1138, 0x6003, 0x0001,
+	0x6007, 0x0001, 0x080c, 0x6cd3, 0x0010, 0x080c, 0x861d, 0x0005,
+	0x6004, 0xa08a, 0x0080, 0x1a0c, 0x1515, 0x080c, 0x7090, 0x080c,
+	0x9e1d, 0x080c, 0x7173, 0x0005, 0xa182, 0x0040, 0x0002, 0xa812,
+	0xa812, 0xa812, 0xa812, 0xa814, 0xa812, 0xa812, 0xa812, 0xa812,
+	0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812, 0xa812,
+	0xa812, 0xa812, 0x080c, 0x1515, 0x00d6, 0x00e6, 0x00f6, 0x0156,
+	0x0046, 0x0026, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0120,
+	0x2021, 0x0000, 0x080c, 0xb31c, 0x6106, 0x2071, 0xbb80, 0x7444,
+	0xa4a4, 0xff00, 0x0904, 0xa878, 0xa486, 0x2000, 0x1130, 0x2009,
+	0x0001, 0x2011, 0x0200, 0x080c, 0x6b1a, 0x080c, 0x15f8, 0x090c,
+	0x1515, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803, 0x0000,
+	0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2, 0x6018,
+	0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x0016, 0xa084, 0xff00,
+	0x6846, 0x684f, 0x0000, 0x6853, 0x0000, 0x6857, 0x0036, 0x080c,
+	0x5408, 0x001e, 0xa486, 0x2000, 0x1130, 0x2019, 0x0017, 0x080c,
+	0xb065, 0x0804, 0xa8d5, 0xa486, 0x0400, 0x1130, 0x2019, 0x0002,
+	0x080c, 0xb017, 0x0804, 0xa8d5, 0xa486, 0x0200, 0x1110, 0x080c,
+	0xaffc, 0xa486, 0x1000, 0x1110, 0x080c, 0xb04a, 0x0804, 0xa8d5,
+	0x2069, 0xb874, 0x6a00, 0xd284, 0x0904, 0xa93c, 0xa284, 0x0300,
+	0x1904, 0xa935, 0x6804, 0xa005, 0x0904, 0xa91d, 0x2d78, 0x6003,
+	0x0007, 0x080c, 0x15df, 0x0904, 0xa8dc, 0x7800, 0xd08c, 0x1118,
+	0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, 0x0000, 0x6837,
+	0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, 0x684a, 0x6018,
+	0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, 0x7928, 0x698a,
+	0x792c, 0x698e, 0x7930, 0x6992, 0x7934, 0x6996, 0x6853, 0x003d,
+	0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, 0x684f, 0x0040,
+	0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, 0x0010, 0x684f,
+	0x0000, 0x20a9, 0x000a, 0x2001, 0xbb90, 0xad90, 0x0015, 0x200c,
+	0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0xa8c7, 0x200c, 0x6982,
+	0x8000, 0x200c, 0x697e, 0x080c, 0x5408, 0x002e, 0x004e, 0x015e,
+	0x00fe, 0x00ee, 0x00de, 0x0005, 0x2001, 0xb50e, 0x2004, 0xd084,
+	0x0120, 0x080c, 0x15f8, 0x1904, 0xa88d, 0x6013, 0x0100, 0x6003,
+	0x0001, 0x6007, 0x0041, 0x080c, 0x6c8d, 0x080c, 0x7173, 0x0c28,
+	0x2069, 0xbb92, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x11a8,
+	0x2069, 0xbb80, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, 0xa18c,
+	0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043,
+	0x080c, 0x6c8d, 0x080c, 0x7173, 0x0840, 0x6868, 0x602a, 0x686c,
+	0x602e, 0x6013, 0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c,
+	0x6c8d, 0x080c, 0x7173, 0x0804, 0xa8d5, 0x2001, 0xb50d, 0x2004,
+	0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x3ecc, 0x6013, 0x0300,
+	0x0010, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c,
+	0x6c8d, 0x080c, 0x7173, 0x0804, 0xa8d5, 0x6013, 0x0500, 0x0c98,
+	0x6013, 0x0600, 0x0804, 0xa8f0, 0x6013, 0x0200, 0x0804, 0xa8f0,
+	0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, 0x1515,
+	0xa08a, 0x0053, 0x1a0c, 0x1515, 0xa082, 0x0040, 0x2008, 0x0804,
+	0xa9ca, 0xa186, 0x0051, 0x0138, 0xa186, 0x0047, 0x11d8, 0x6004,
+	0xa086, 0x0041, 0x0518, 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6b74,
+	0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, 0x0002, 0x1170,
+	0x0804, 0xaa0d, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c,
+	0x1515, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, 0x080c, 0x8663,
+	0x0005, 0xa994, 0xa996, 0xa996, 0xa9ba, 0xa994, 0xa994, 0xa994,
+	0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994, 0xa994,
+	0xa994, 0xa994, 0xa994, 0xa994, 0x080c, 0x1515, 0x080c, 0x7090,
+	0x080c, 0x7173, 0x0036, 0x00d6, 0x6010, 0xa06d, 0x01c0, 0xad84,
+	0xf000, 0x01a8, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, 0x1178,
+	0x2019, 0x0004, 0x080c, 0xb099, 0x6013, 0x0000, 0x6014, 0xa005,
+	0x1120, 0x2001, 0xb7b7, 0x2004, 0x6016, 0x6003, 0x0007, 0x00de,
+	0x003e, 0x0005, 0x00d6, 0x080c, 0x7090, 0x080c, 0x7173, 0x080c,
+	0x9c5a, 0x0120, 0x6010, 0x2068, 0x080c, 0x160f, 0x080c, 0x9e1d,
+	0x00de, 0x0005, 0x0002, 0xa9de, 0xa9fb, 0xa9e7, 0xaa07, 0xa9de,
+	0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de,
+	0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0xa9de, 0x080c, 0x1515,
+	0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x080c,
+	0x7090, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0138, 0x6003,
+	0x0007, 0x2009, 0x0043, 0x080c, 0x864c, 0x0010, 0x6003, 0x0002,
+	0x080c, 0x7173, 0x0005, 0x080c, 0x7090, 0x080c, 0xb2d7, 0x1120,
+	0x080c, 0x6aef, 0x080c, 0x861d, 0x080c, 0x7173, 0x0005, 0x080c,
+	0x7090, 0x2009, 0x0041, 0x0804, 0xab56, 0xa182, 0x0040, 0x0002,
+	0xaa23, 0xaa25, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa26,
+	0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23, 0xaa23,
+	0xaa23, 0xaa31, 0xaa23, 0x080c, 0x1515, 0x0005, 0x6003, 0x0004,
+	0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x185e,
+	0x0005, 0x00d6, 0x080c, 0x6aef, 0x00de, 0x080c, 0xb33a, 0x080c,
+	0x861d, 0x0005, 0xa182, 0x0040, 0x0002, 0xaa50, 0xaa50, 0xaa50,
+	0xaa50, 0xaa50, 0xaa50, 0xaa50, 0xaa52, 0xaa50, 0xaa55, 0xaa8e,
+	0xaa50, 0xaa50, 0xaa50, 0xaa50, 0xaa8e, 0xaa50, 0xaa50, 0xaa50,
+	0x080c, 0x1515, 0x080c, 0x8663, 0x0005, 0x2001, 0xb572, 0x2004,
+	0xd0e4, 0x0158, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0228,
+	0x2001, 0x011f, 0x2004, 0x6036, 0x0010, 0x6037, 0x0000, 0x080c,
+	0x7126, 0x080c, 0x7230, 0x6010, 0x00d6, 0x2068, 0x684c, 0xd0fc,
+	0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0168, 0x2009, 0x0041,
+	0x00de, 0x0804, 0xab56, 0x6003, 0x0007, 0x6017, 0x0000, 0x080c,
+	0x6aef, 0x00de, 0x0005, 0x080c, 0xb2d7, 0x0110, 0x00de, 0x0005,
+	0x080c, 0x6aef, 0x080c, 0x861d, 0x00de, 0x0ca0, 0x0036, 0x080c,
+	0x7126, 0x080c, 0x7230, 0x6010, 0x00d6, 0x2068, 0x6018, 0x2004,
+	0xd0bc, 0x0188, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0140,
+	0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a,
+	0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xb099, 0x6014,
+	0xa005, 0x1128, 0x2001, 0xb7b7, 0x2004, 0x8003, 0x6016, 0x6013,
+	0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0xa186, 0x0013,
+	0x1150, 0x6004, 0xa086, 0x0042, 0x190c, 0x1515, 0x080c, 0x7090,
+	0x080c, 0x7173, 0x0005, 0xa186, 0x0027, 0x0118, 0xa186, 0x0014,
+	0x1180, 0x6004, 0xa086, 0x0042, 0x190c, 0x1515, 0x2001, 0x0007,
+	0x080c, 0x4f2a, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c, 0x7173,
+	0x0005, 0xa182, 0x0040, 0x0002, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7,
+	0xaaf7, 0xaaf7, 0xaaf7, 0xaaf9, 0xab05, 0xaaf7, 0xaaf7, 0xaaf7,
+	0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0xaaf7, 0x080c,
+	0x1515, 0x0036, 0x0046, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10,
+	0x080c, 0x185e, 0x004e, 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068,
+	0x6810, 0x6a14, 0x0006, 0x0046, 0x0056, 0x6c7c, 0xa422, 0x6d80,
+	0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a,
+	0x005e, 0x004e, 0x000e, 0xa20d, 0x1178, 0x684c, 0xd0fc, 0x0120,
+	0x2009, 0x0041, 0x00de, 0x0490, 0x6003, 0x0007, 0x6017, 0x0000,
+	0x080c, 0x6aef, 0x00de, 0x0005, 0x0006, 0x00f6, 0x2c78, 0x080c,
+	0x5305, 0x00fe, 0x000e, 0x0120, 0x6003, 0x0002, 0x00de, 0x0005,
+	0x2009, 0xb50d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010,
+	0x6003, 0x0006, 0x0021, 0x080c, 0x6af1, 0x00de, 0x0005, 0xd2fc,
+	0x0140, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009,
+	0x0010, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040,
+	0x0208, 0x0062, 0xa186, 0x0013, 0x0120, 0xa186, 0x0014, 0x190c,
+	0x1515, 0x6020, 0xd0dc, 0x090c, 0x1515, 0x0005, 0xab79, 0xab80,
+	0xab8c, 0xab98, 0xab79, 0xab79, 0xab79, 0xaba7, 0xab79, 0xab7b,
+	0xab7b, 0xab79, 0xab79, 0xab79, 0xab79, 0xab7b, 0xab79, 0xab7b,
+	0xab79, 0x080c, 0x1515, 0x6020, 0xd0dc, 0x090c, 0x1515, 0x0005,
+	0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x7173, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e, 0x0005,
+	0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1fa9, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6cf0, 0x080c, 0x7230, 0x012e, 0x0005, 0xa016,
+	0x080c, 0x185e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x00d6,
+	0xa182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, 0x0005, 0xabc7,
+	0xabc9, 0xabdb, 0xabf6, 0xabc7, 0xabc7, 0xabc7, 0xac0b, 0xabc7,
+	0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0xabc7, 0x080c,
+	0x1515, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x01f8, 0xa09c, 0x0003,
+	0xa39e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, 0x6c8d,
+	0x080c, 0x7173, 0x0498, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0168,
+	0xa09c, 0x0003, 0xa39e, 0x0003, 0x0140, 0x6003, 0x0001, 0x6106,
+	0x080c, 0x6c8d, 0x080c, 0x7173, 0x0408, 0x6013, 0x0000, 0x6017,
+	0x0000, 0x2019, 0x0004, 0x080c, 0xb099, 0x00c0, 0x6010, 0x2068,
+	0x684c, 0xd0fc, 0x0d90, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0d68,
+	0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1fa9, 0x080c, 0x6cf0,
+	0x080c, 0x7230, 0x0018, 0xa016, 0x080c, 0x185e, 0x0005, 0x080c,
+	0x7090, 0x6110, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xb380,
+	0x0036, 0x2019, 0x0029, 0x080c, 0xb099, 0x003e, 0x00de, 0x080c,
+	0x9e1d, 0x080c, 0x7173, 0x0005, 0x080c, 0x7126, 0x6110, 0x81ff,
+	0x0158, 0x00d6, 0x2168, 0x080c, 0xb380, 0x0036, 0x2019, 0x0029,
+	0x080c, 0xb099, 0x003e, 0x00de, 0x080c, 0x9e1d, 0x080c, 0x7230,
+	0x0005, 0xa182, 0x0085, 0x0002, 0xac45, 0xac43, 0xac43, 0xac51,
+	0xac43, 0xac43, 0xac43, 0x080c, 0x1515, 0x6003, 0x000b, 0x6106,
+	0x080c, 0x6c8d, 0x0126, 0x2091, 0x8000, 0x080c, 0x7173, 0x012e,
+	0x0005, 0x0026, 0x00e6, 0x080c, 0xb2d0, 0x0118, 0x080c, 0x861d,
+	0x00d8, 0x2071, 0xbb80, 0x7224, 0x6212, 0x7220, 0x080c, 0xaf47,
+	0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, 0xa296,
+	0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, 0x6c8d,
+	0x080c, 0x7173, 0x080c, 0x7230, 0x00ee, 0x002e, 0x0005, 0xa186,
+	0x0013, 0x1160, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x1515, 0xa08a,
+	0x008c, 0x1a0c, 0x1515, 0xa082, 0x0085, 0x00a2, 0xa186, 0x0027,
+	0x0130, 0xa186, 0x0014, 0x0118, 0x080c, 0x8663, 0x0050, 0x2001,
+	0x0007, 0x080c, 0x4f2a, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c,
+	0x7173, 0x0005, 0xaca1, 0xaca3, 0xaca3, 0xaca1, 0xaca1, 0xaca1,
+	0xaca1, 0x080c, 0x1515, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c,
+	0x7173, 0x0005, 0xa182, 0x0085, 0x0a0c, 0x1515, 0xa182, 0x008c,
+	0x1a0c, 0x1515, 0xa182, 0x0085, 0x0002, 0xacbc, 0xacbc, 0xacbc,
+	0xacbe, 0xacbc, 0xacbc, 0xacbc, 0x080c, 0x1515, 0x0005, 0xa186,
+	0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118,
+	0x080c, 0x8663, 0x0030, 0x080c, 0x7090, 0x080c, 0x9e1d, 0x080c,
+	0x7173, 0x0005, 0x0036, 0x080c, 0xb33a, 0x603f, 0x0000, 0x2019,
+	0x000b, 0x0031, 0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005,
+	0x0126, 0x0036, 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x2049,
+	0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x1578, 0x0076, 0x2c38,
+	0x080c, 0x81d6, 0x007e, 0x1548, 0x6000, 0xa086, 0x0000, 0x0528,
+	0x601c, 0xa086, 0x0007, 0x0508, 0x00d6, 0x6000, 0xa086, 0x0004,
+	0x1150, 0x080c, 0xb33a, 0x601f, 0x0007, 0x2001, 0xb7b6, 0x2004,
+	0x6016, 0x080c, 0x194d, 0x6010, 0x2068, 0x080c, 0x9c5a, 0x0110,
+	0x080c, 0xb099, 0x00de, 0x6013, 0x0000, 0x080c, 0xb33a, 0x601f,
+	0x0007, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x003e, 0x012e, 0x0005,
+	0x00f6, 0x00c6, 0x0036, 0x0156, 0x2079, 0xbb80, 0x7938, 0x783c,
+	0x080c, 0x281d, 0x15b0, 0x0016, 0x00c6, 0x080c, 0x4fa9, 0x1578,
+	0x001e, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x8299,
+	0x080c, 0x6df5, 0x0076, 0x2039, 0x0000, 0x080c, 0x6d02, 0x007e,
+	0x001e, 0x0076, 0x2039, 0x0000, 0x080c, 0xae82, 0x007e, 0x080c,
+	0x51aa, 0x0026, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006,
+	0x0118, 0xa286, 0x0004, 0x1118, 0x62a0, 0x080c, 0x2d55, 0x002e,
+	0x001e, 0x080c, 0x4c0b, 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce,
+	0x001e, 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x0016, 0x2009, 0xb521, 0x2104, 0xa086, 0x0074, 0x1904,
+	0xadbb, 0x2069, 0xbb8e, 0x690c, 0xa182, 0x0100, 0x06c0, 0x6908,
+	0xa184, 0x8000, 0x05e8, 0x2001, 0xb79e, 0x2004, 0xa005, 0x1160,
+	0x6018, 0x2070, 0x7010, 0xa084, 0x00ff, 0x0118, 0x7000, 0xd0f4,
+	0x0118, 0xa184, 0x0800, 0x0560, 0x6910, 0xa18a, 0x0001, 0x0610,
+	0x6914, 0x2069, 0xbbae, 0x6904, 0x81ff, 0x1198, 0x690c, 0xa182,
+	0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, 0x6910, 0xa18a, 0x0001,
+	0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, 0x00d0, 0x6013, 0x0100,
+	0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, 0x0500, 0x0070, 0x6013,
+	0x0700, 0x0058, 0x6013, 0x0900, 0x0040, 0x6013, 0x0b00, 0x0028,
+	0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0008,
+	0xa006, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff,
+	0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, 0xa394, 0xff00,
+	0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, 0x0130, 0x00c6,
+	0x2d60, 0x080c, 0x4fb8, 0x00ce, 0x04c0, 0x2011, 0xbb96, 0xad98,
+	0x000a, 0x20a9, 0x0004, 0x080c, 0x90da, 0x1580, 0x2011, 0xbb9a,
+	0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x90da, 0x1538, 0x0046,
+	0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xb553,
+	0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xb0e8, 0x6800,
+	0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x6df5, 0x0076, 0x2039,
+	0x0000, 0x080c, 0x6d02, 0x2c08, 0x080c, 0xae82, 0x007e, 0x2001,
+	0x0007, 0x080c, 0x4f2a, 0x001e, 0x004e, 0xa006, 0x015e, 0x003e,
+	0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, 0xbb8e, 0x6800,
+	0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, 0xa006, 0x00de,
+	0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079,
+	0xbb8c, 0x7930, 0x7834, 0x080c, 0x281d, 0x11a0, 0x080c, 0x4fa9,
+	0x1188, 0x2011, 0xbb90, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c,
+	0x90da, 0x1140, 0x2011, 0xbb94, 0xac98, 0x0006, 0x20a9, 0x0004,
+	0x080c, 0x90da, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce,
+	0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011,
+	0xbb83, 0x2204, 0x8211, 0x220c, 0x080c, 0x281d, 0x11a0, 0x080c,
+	0x4fa9, 0x1188, 0x2011, 0xbb96, 0xac98, 0x000a, 0x20a9, 0x0004,
+	0x080c, 0x90da, 0x1140, 0x2011, 0xbb9a, 0xac98, 0x0006, 0x20a9,
+	0x0004, 0x080c, 0x90da, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e,
+	0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056,
+	0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0xb7e9,
+	0x252c, 0x2021, 0xb7ef, 0x2424, 0x2061, 0xbd00, 0x2071, 0xb500,
+	0x7648, 0x7068, 0x81ff, 0x0150, 0x0006, 0xa186, 0xb8f4, 0x000e,
+	0x0128, 0x8001, 0xa602, 0x1a04, 0xaf03, 0x0018, 0xa606, 0x0904,
+	0xaf03, 0x2100, 0xac06, 0x0904, 0xaefa, 0x080c, 0xb110, 0x0904,
+	0xaefa, 0x671c, 0xa786, 0x0001, 0x0904, 0xaf1e, 0xa786, 0x0004,
+	0x0904, 0xaf1e, 0xa786, 0x0007, 0x05e8, 0x2500, 0xac06, 0x05d0,
+	0x2400, 0xac06, 0x05b8, 0x080c, 0xb120, 0x15a0, 0x88ff, 0x0118,
+	0x6050, 0xa906, 0x1578, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1120,
+	0x0016, 0x080c, 0x194d, 0x001e, 0xa786, 0x0008, 0x1148, 0x080c,
+	0x9e58, 0x1130, 0x080c, 0x8c19, 0x00de, 0x080c, 0x9e1d, 0x00d0,
+	0x6010, 0x2068, 0x080c, 0x9c5a, 0x0190, 0xa786, 0x0003, 0x1528,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0xb380, 0x0016,
+	0x080c, 0x9ecc, 0x080c, 0x5408, 0x001e, 0x080c, 0x9e11, 0x00de,
+	0x080c, 0x9e1d, 0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02,
+	0x1210, 0x0804, 0xae96, 0x012e, 0x002e, 0x004e, 0x005e, 0x006e,
+	0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, 0xa786, 0x0006, 0x1150,
+	0xa386, 0x0005, 0x0128, 0x080c, 0xb380, 0x080c, 0xb099, 0x08f8,
+	0x00de, 0x0c00, 0xa786, 0x000a, 0x0968, 0x0850, 0x080c, 0xb120,
+	0x19c8, 0x81ff, 0x09b8, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018,
+	0x0130, 0xa180, 0x0001, 0x2004, 0xa086, 0x002d, 0x1958, 0x6000,
+	0xa086, 0x0002, 0x1938, 0x080c, 0x9e47, 0x0130, 0x080c, 0x9e58,
+	0x1908, 0x080c, 0x8c19, 0x0038, 0x080c, 0x2cc2, 0x080c, 0x9e58,
+	0x1110, 0x080c, 0x8c19, 0x080c, 0x9e1d, 0x0804, 0xaefa, 0x00c6,
+	0x00e6, 0x0016, 0x2c08, 0x2170, 0xa006, 0x080c, 0xb0ba, 0x001e,
+	0x0120, 0x601c, 0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005,
+	0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf60, 0xaf62, 0xaf60,
+	0xa006, 0x0005, 0x0046, 0x0016, 0x7018, 0xa080, 0x0028, 0x2024,
+	0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, 0xb0e8,
+	0x001e, 0x004e, 0x0036, 0x2019, 0x0002, 0x080c, 0xace0, 0x003e,
+	0xa085, 0x0001, 0x0005, 0x2001, 0x0001, 0x080c, 0x4eeb, 0x0156,
+	0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0xb505, 0x2011,
+	0xbb96, 0x080c, 0x90da, 0x003e, 0x002e, 0x001e, 0x015e, 0xa005,
+	0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0026,
+	0x0126, 0x2091, 0x8000, 0x2740, 0x2061, 0xbd00, 0x2079, 0x0001,
+	0x8fff, 0x0904, 0xafef, 0x2071, 0xb500, 0x7648, 0x7068, 0x8001,
+	0xa602, 0x1a04, 0xafef, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15b0,
+	0x2079, 0x0000, 0x080c, 0xb110, 0x0588, 0x2400, 0xac06, 0x0570,
+	0x671c, 0xa786, 0x0006, 0x1550, 0xa786, 0x0007, 0x0538, 0x88ff,
+	0x1140, 0x6018, 0xa206, 0x1510, 0x85ff, 0x0118, 0x6050, 0xa106,
+	0x11e8, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1150, 0x080c, 0xb33a,
+	0x601f, 0x0007, 0x2001, 0xb7b6, 0x2004, 0x6016, 0x080c, 0x194d,
+	0x6010, 0x2068, 0x080c, 0x9c5a, 0x0120, 0x0046, 0x080c, 0xb099,
+	0x004e, 0x00de, 0x080c, 0x9e1d, 0x88ff, 0x1198, 0xace0, 0x0018,
+	0x2001, 0xb517, 0x2004, 0xac02, 0x1210, 0x0804, 0xafa0, 0xa006,
+	0x012e, 0x002e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0xa8c5, 0x0001, 0x0ca0, 0x0076, 0x0056, 0x0086, 0x2041,
+	0x0000, 0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x0096,
+	0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039, 0x0000,
+	0x080c, 0x81d6, 0x080c, 0xaf91, 0x005e, 0x007e, 0x0005, 0x0026,
+	0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0x0016, 0x0036, 0x080c, 0x4fa9, 0x11b0,
+	0x2c10, 0x0056, 0x0086, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001,
+	0x0096, 0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039,
+	0x0000, 0x080c, 0x81d6, 0x080c, 0xaf91, 0x005e, 0x003e, 0x001e,
+	0x8108, 0x1f04, 0xb023, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e,
+	0x002e, 0x0005, 0x0076, 0x0056, 0x6218, 0x0086, 0x2041, 0x0000,
+	0x2029, 0x0001, 0x2019, 0x0048, 0x0096, 0x2049, 0x0000, 0x080c,
+	0x8130, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x81d6, 0x2c20,
+	0x080c, 0xaf91, 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056,
+	0x0076, 0x00c6, 0x0156, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x0016, 0x0036, 0x080c, 0x4fa9, 0x11c0, 0x2c10, 0x0086, 0x2041,
+	0x0000, 0x2828, 0x0046, 0x2021, 0x0001, 0x080c, 0xb31c, 0x004e,
+	0x0096, 0x2049, 0x0000, 0x080c, 0x8130, 0x009e, 0x008e, 0x2039,
+	0x0000, 0x080c, 0x81d6, 0x080c, 0xaf91, 0x003e, 0x001e, 0x8108,
+	0x1f04, 0xb070, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e,
+	0x0005, 0x0016, 0x00f6, 0x3800, 0xd08c, 0x0130, 0xad82, 0x1000,
+	0x02b0, 0xad82, 0xb500, 0x0230, 0xad82, 0xed00, 0x0280, 0xad82,
+	0xffff, 0x1268, 0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, 0x6b52,
+	0x080c, 0x5408, 0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x5408, 0x00fe,
+	0x001e, 0x0005, 0x00e6, 0x0046, 0x0036, 0x2061, 0xbd00, 0xa005,
+	0x1138, 0x2071, 0xb500, 0x7448, 0x7068, 0x8001, 0xa402, 0x12d8,
+	0x2100, 0xac06, 0x0168, 0x6000, 0xa086, 0x0000, 0x0148, 0x6008,
+	0xa206, 0x1130, 0x6018, 0xa1a0, 0x0006, 0x2424, 0xa406, 0x0140,
+	0xace0, 0x0018, 0x2001, 0xb517, 0x2004, 0xac02, 0x1220, 0x0c40,
+	0xa085, 0x0001, 0x0008, 0xa006, 0x003e, 0x004e, 0x00ee, 0x0005,
+	0x00d6, 0x0006, 0x080c, 0x15f8, 0x000e, 0x090c, 0x1515, 0x6837,
+	0x010d, 0x685e, 0x0026, 0x2010, 0x080c, 0x9c4a, 0x2001, 0x0000,
+	0x0120, 0x2200, 0xa080, 0x0014, 0x2004, 0x002e, 0x684a, 0x6956,
+	0x6c46, 0x684f, 0x0000, 0x2001, 0xb7be, 0x2004, 0x6852, 0xa006,
+	0x68b2, 0x6802, 0x683a, 0x685a, 0x080c, 0x5408, 0x00de, 0x0005,
+	0x6700, 0xa786, 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786,
+	0x000a, 0x0128, 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005,
+	0x00e6, 0x6018, 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0x0016,
+	0x6004, 0xa08e, 0x001e, 0x11a0, 0x8007, 0x6130, 0xa18c, 0x00ff,
+	0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005,
+	0x2001, 0xb7b7, 0x2004, 0x6016, 0x080c, 0x6c8d, 0x080c, 0x7173,
+	0x001e, 0x0005, 0xe000, 0xe000, 0x0005, 0x6020, 0xd0e4, 0x0158,
+	0xd0cc, 0x0118, 0x080c, 0x9f35, 0x0030, 0x080c, 0xb33a, 0x080c,
+	0x6aef, 0x080c, 0x861d, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084,
+	0x000f, 0x0002, 0xb163, 0xb163, 0xb163, 0xb168, 0xb163, 0xb165,
+	0xb165, 0xb163, 0xb165, 0xa006, 0x0005, 0x00c6, 0x2260, 0x00ce,
+	0xa085, 0x0001, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f,
+	0x0002, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb17a, 0xb185,
+	0xb17a, 0xb17a, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00,
+	0x6003, 0x0001, 0x080c, 0x6c8d, 0x0005, 0x00c6, 0x2260, 0x080c,
+	0xb33a, 0x603f, 0x0000, 0x6020, 0xc0f4, 0xc0cc, 0x6022, 0x6037,
+	0x0000, 0x00ce, 0x00d6, 0x2268, 0xa186, 0x0007, 0x1904, 0xb1e0,
+	0x6810, 0xa005, 0x0138, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x1110,
+	0x00de, 0x08c0, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x6c8d,
+	0x080c, 0x7173, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x1904,
+	0xb269, 0x6010, 0xa005, 0x1138, 0x6000, 0xa086, 0x0007, 0x190c,
+	0x1515, 0x0804, 0xb269, 0xa08c, 0xf000, 0x1130, 0x0028, 0x2068,
+	0x6800, 0xa005, 0x1de0, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084,
+	0x0003, 0xa086, 0x0002, 0x1180, 0x6010, 0x2068, 0x684c, 0xc0dc,
+	0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043,
+	0x080c, 0xab56, 0x0804, 0xb269, 0x2009, 0x0041, 0x0804, 0xb263,
+	0xa186, 0x0005, 0x15f0, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc,
+	0x1118, 0x00de, 0x0804, 0xb17a, 0xd0b4, 0x0128, 0xd0fc, 0x090c,
+	0x1515, 0x0804, 0xb198, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c,
+	0x6c8d, 0x080c, 0x7173, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002,
+	0x0120, 0xa186, 0x0004, 0x1904, 0xb269, 0x2071, 0xb823, 0x7000,
+	0xa086, 0x0003, 0x1128, 0x7004, 0xac06, 0x1110, 0x7003, 0x0000,
+	0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000,
+	0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0804,
+	0xb263, 0x0036, 0x00d6, 0x00d6, 0x080c, 0x15f8, 0x003e, 0x090c,
+	0x1515, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b,
+	0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872,
+	0x2360, 0x6020, 0xc0dd, 0x6022, 0x6018, 0xa080, 0x0028, 0x2004,
+	0xa084, 0x00ff, 0x8007, 0x6350, 0x6b4a, 0x6846, 0x684f, 0x0000,
+	0x6853, 0x0000, 0x6d6a, 0x6e66, 0x686f, 0x0001, 0x080c, 0x5408,
+	0x2019, 0x0045, 0x6008, 0x2068, 0x080c, 0xace0, 0x2d00, 0x600a,
+	0x601f, 0x0006, 0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000,
+	0x00de, 0x003e, 0x0038, 0x603f, 0x0000, 0x6003, 0x0007, 0x080c,
+	0xab56, 0x00ce, 0x00de, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004,
+	0xa082, 0x0085, 0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, 0x080c,
+	0x7090, 0x0036, 0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, 0x080c,
+	0xb099, 0x00de, 0x003e, 0x080c, 0x7173, 0x0005, 0xa186, 0x0014,
+	0x0d70, 0x080c, 0x8663, 0x0005, 0xb295, 0xb293, 0xb293, 0xb293,
+	0xb293, 0xb293, 0xb295, 0x080c, 0x1515, 0x080c, 0x7090, 0x6003,
+	0x000c, 0x080c, 0x7173, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182,
+	0x0085, 0x0208, 0x001a, 0x080c, 0x8663, 0x0005, 0xb2ad, 0xb2ad,
+	0xb2ad, 0xb2ad, 0xb2af, 0xb2cd, 0xb2ad, 0x080c, 0x1515, 0x00d6,
+	0x2c68, 0x080c, 0x85c7, 0x01a0, 0x6003, 0x0001, 0x6007, 0x001e,
+	0x2009, 0xbb8e, 0x210c, 0x6136, 0x2009, 0xbb8f, 0x210c, 0x613a,
+	0x600b, 0xffff, 0x6918, 0x611a, 0x601f, 0x0004, 0x080c, 0x6c8d,
+	0x2d60, 0x080c, 0x861d, 0x00de, 0x0005, 0x080c, 0x861d, 0x0005,
+	0x00e6, 0x6018, 0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x6010,
+	0xa08c, 0xf000, 0x0904, 0xb31b, 0xa080, 0x0013, 0x200c, 0xd1ec,
+	0x05d0, 0x2001, 0xb572, 0x2004, 0xd0ec, 0x05a8, 0x6003, 0x0002,
+	0x6020, 0xc0e5, 0x6022, 0xd1ac, 0x0180, 0x00f6, 0x2c78, 0x080c,
+	0x5301, 0x00fe, 0x0150, 0x2001, 0xb7b8, 0x2004, 0x603e, 0x2009,
+	0xb572, 0x210c, 0xd1f4, 0x11e8, 0x0080, 0x2009, 0xb572, 0x210c,
+	0xd1f4, 0x0128, 0x6020, 0xc0e4, 0x6022, 0xa006, 0x00a0, 0x2001,
+	0xb7b8, 0x200c, 0x8103, 0xa100, 0x603e, 0x6018, 0xa088, 0x002b,
+	0x2104, 0xa005, 0x0118, 0xa088, 0x0003, 0x0cd0, 0x2c0a, 0x600f,
+	0x0000, 0xa085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6150,
+	0xa2f0, 0x002b, 0x2e04, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118,
+	0x6050, 0xa106, 0x1138, 0x600c, 0x2072, 0x080c, 0x6aef, 0x080c,
+	0x861d, 0x0010, 0xacf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce,
+	0x001e, 0x0005, 0x00d6, 0x6018, 0xa0e8, 0x002b, 0x2d04, 0xa005,
+	0x0140, 0xac06, 0x0120, 0x2d04, 0xa0e8, 0x0003, 0x0cb8, 0x600c,
+	0x206a, 0x00de, 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0xb528,
+	0x2204, 0xa084, 0x00ff, 0x2019, 0xbb8e, 0x2334, 0xa636, 0x11d8,
+	0x8318, 0x2334, 0x2204, 0xa084, 0xff00, 0xa636, 0x11a0, 0x2011,
+	0xbb90, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x080c, 0x90da,
+	0x1150, 0x2011, 0xbb94, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004,
+	0x080c, 0x90da, 0x1100, 0x015e, 0x003e, 0x002e, 0x0005, 0x00e6,
+	0x2071, 0xb500, 0x080c, 0x4bc6, 0x080c, 0x2ab8, 0x00ee, 0x0005,
+	0x00e6, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0108, 0x0011, 0x00ee,
+	0x0005, 0x6850, 0xc0e5, 0x6852, 0x0005, 0x00e6, 0x00c6, 0x0076,
+	0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000,
+	0x2029, 0xb7e9, 0x252c, 0x2021, 0xb7ef, 0x2424, 0x2061, 0xbd00,
+	0x2071, 0xb500, 0x7648, 0x7068, 0xa606, 0x0578, 0x671c, 0xa786,
+	0x0001, 0x0118, 0xa786, 0x0008, 0x1500, 0x2500, 0xac06, 0x01e8,
+	0x2400, 0xac06, 0x01d0, 0x080c, 0xb110, 0x01b8, 0x080c, 0xb120,
+	0x11a0, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016, 0x080c, 0x194d,
+	0x001e, 0x080c, 0x9e47, 0x1110, 0x080c, 0x2cc2, 0x080c, 0x9e58,
+	0x1110, 0x080c, 0x8c19, 0x080c, 0x9e1d, 0xace0, 0x0018, 0x2001,
+	0xb517, 0x2004, 0xac02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e,
+	0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x0005, 0x0126,
+	0x0006, 0x00e6, 0x0016, 0x2091, 0x8000, 0x2071, 0xb540, 0xd5a4,
+	0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000,
+	0x7032, 0xd5ac, 0x0178, 0x2500, 0xa084, 0x0007, 0xa08e, 0x0003,
+	0x0148, 0xa08e, 0x0004, 0x0130, 0xa08e, 0x0005, 0x0118, 0x2071,
+	0xb54a, 0x04c9, 0x001e, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126,
+	0x0006, 0x00e6, 0x0016, 0x2091, 0x8000, 0x2071, 0xb540, 0xd5a4,
+	0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030, 0x8000,
+	0x7032, 0xd5ac, 0x0178, 0x2500, 0xa084, 0x0007, 0xa08e, 0x0003,
+	0x0148, 0xa08e, 0x0004, 0x0130, 0xa08e, 0x0005, 0x0118, 0x2071,
+	0xb54a, 0x0089, 0x001e, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126,
+	0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb542, 0x0021, 0x00ee,
+	0x000e, 0x012e, 0x0005, 0x2e04, 0x8000, 0x2072, 0x1220, 0x8e70,
+	0x2e04, 0x8000, 0x2072, 0x0005, 0x00e6, 0x2071, 0xb540, 0x0c99,
+	0x00ee, 0x0005, 0x00e6, 0x2071, 0xb544, 0x0c69, 0x00ee, 0x0005,
+	0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xb540, 0x7044,
+	0x8000, 0x7046, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0001, 0x0002,
+	0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,
+	0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x2440
+};
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2200tp_length01 = 0xa46f;
+#else
+unsigned short risc_code_length01 = 0xa46f;
+#endif
+
diff --git a/drivers/scsi/qla2xxx/ql2300.c b/drivers/scsi/qla2xxx/ql2300.c
new file mode 100644
index 0000000..a4988cf
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2300.c
@@ -0,0 +1,103 @@
+/*
+ * QLogic ISP2300 device driver for Linux 2.6.x
+ * Copyright (C) 2003 Christoph Hellwig.
+ * Copyright (C) 2003-2004 QLogic Corporation (www.qlogic.com)
+ *
+ * Released under GPL v2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "qla_def.h"
+
+static char qla_driver_name[] = "qla2300";
+
+extern unsigned char  fw2300ipx_version[];
+extern unsigned char  fw2300ipx_version_str[];
+extern unsigned short fw2300ipx_addr01;
+extern unsigned short fw2300ipx_code01[];
+extern unsigned short fw2300ipx_length01;
+
+static struct qla_fw_info qla_fw_tbl[] = {
+	{
+		.addressing	= FW_INFO_ADDR_NORMAL,
+		.fwcode		= &fw2300ipx_code01[0],
+		.fwlen		= &fw2300ipx_length01,
+		.fwstart	= &fw2300ipx_addr01,
+	},
+	{ FW_INFO_ADDR_NOMORE, },
+};
+
+static struct qla_board_info qla_board_tbl[] = {
+	{
+		.drv_name	= qla_driver_name,
+		.isp_name	= "ISP2300",
+		.fw_info	= qla_fw_tbl,
+	},
+	{
+		.drv_name	= qla_driver_name,
+		.isp_name	= "ISP2312",
+		.fw_info	= qla_fw_tbl,
+	},
+};
+
+static struct pci_device_id qla2300_pci_tbl[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP2300,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl[0],
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP2312,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl[1],
+	},
+	{0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla2300_pci_tbl);
+
+static int __devinit
+qla2300_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return qla2x00_probe_one(pdev,
+	    (struct qla_board_info *)id->driver_data);
+}
+
+static void __devexit
+qla2300_remove_one(struct pci_dev *pdev)
+{
+	qla2x00_remove_one(pdev);
+}
+
+static struct pci_driver qla2300_pci_driver = {
+	.name		= "qla2300",
+	.id_table	= qla2300_pci_tbl,
+	.probe		= qla2300_probe_one,
+	.remove		= __devexit_p(qla2300_remove_one),
+};
+
+static int __init
+qla2300_init(void)
+{
+	return pci_module_init(&qla2300_pci_driver);
+}
+
+static void __exit
+qla2300_exit(void)
+{
+	pci_unregister_driver(&qla2300_pci_driver);
+}
+
+module_init(qla2300_init);
+module_exit(qla2300_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP23xx FC-SCSI Host Bus Adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/ql2300_fw.c b/drivers/scsi/qla2xxx/ql2300_fw.c
new file mode 100644
index 0000000..9af06ba
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2300_fw.c
@@ -0,0 +1,7590 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+/*
+ *	Firmware Version 3.03.08 (10:02 Nov 12, 2004)
+ */
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300ipx_version = 3*1024+3;
+#else
+unsigned short risc_code_version = 3*1024+3;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned char fw2300ipx_version_str[] = {3, 3, 8};
+#else
+unsigned char firmware_version[] = {3, 3, 8};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw2300ipx_VERSION_STRING "3.03.08"
+#else
+#define FW_VERSION_STRING "3.03.08"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300ipx_addr01 = 0x0800 ;
+#else
+unsigned short risc_code_addr01 = 0x0800 ;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300ipx_code01[] = { 
+#else
+unsigned short risc_code01[] = { 
+#endif
+	0x0470, 0x0000, 0x0000, 0xeb57, 0x0000, 0x0003, 0x0003, 0x0008,
+	0x0137, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030,
+	0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3233, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x332e, 0x3033, 0x2e30, 0x3820, 0x2020, 0x2020, 0x2400, 0x20a9,
+	0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2200, 0x20a9, 0x000f,
+	0x2001, 0x0000, 0x400f, 0x2091, 0x2400, 0x20a9, 0x000f, 0x2001,
+	0x0000, 0x400f, 0x2091, 0x2600, 0x20a9, 0x000f, 0x2001, 0x0000,
+	0x400f, 0x2091, 0x2800, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f,
+	0x2091, 0x2a00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091,
+	0x2c00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2e00,
+	0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2000, 0x2001,
+	0x0000, 0x20c1, 0x0004, 0x20c9, 0x1bff, 0x2059, 0x0000, 0x2b78,
+	0x7883, 0x0004, 0x2089, 0x2d88, 0x2051, 0x1800, 0x2a70, 0x20e1,
+	0x0001, 0x20e9, 0x0001, 0x2009, 0x0000, 0x080c, 0x0e51, 0x2029,
+	0x4d00, 0x2031, 0xffff, 0x2039, 0x4cd0, 0x2021, 0x0200, 0x20e9,
+	0x0001, 0x20a1, 0x0000, 0x20a9, 0x0800, 0x900e, 0x4104, 0x20e9,
+	0x0001, 0x20a1, 0x1000, 0x900e, 0x2001, 0x0cc0, 0x9084, 0x0fff,
+	0x20a8, 0x4104, 0x2001, 0x0000, 0x9086, 0x0000, 0x0120, 0x21a8,
+	0x4104, 0x8001, 0x1de0, 0x756e, 0x7672, 0x776a, 0x7476, 0x747a,
+	0x00e6, 0x2071, 0x1aca, 0x2472, 0x00ee, 0x20a1, 0x1cd0, 0x7170,
+	0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x000f, 0x2001, 0x0001,
+	0x9112, 0x900e, 0x21a8, 0x4104, 0x8211, 0x1de0, 0x7170, 0x3400,
+	0x8001, 0x9102, 0x0120, 0x0218, 0x20a8, 0x900e, 0x4104, 0x2009,
+	0x1800, 0x810d, 0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x001f,
+	0x2001, 0x0001, 0x9112, 0x20e9, 0x0001, 0x20a1, 0x0800, 0x900e,
+	0x20a9, 0x0800, 0x4104, 0x8211, 0x1dd8, 0x080c, 0x0f17, 0x080c,
+	0x60bb, 0x080c, 0xaed9, 0x080c, 0x10ce, 0x080c, 0x12ed, 0x080c,
+	0x1be2, 0x080c, 0x0d69, 0x080c, 0x1053, 0x080c, 0x3484, 0x080c,
+	0x7738, 0x080c, 0x6a30, 0x080c, 0x87b3, 0x080c, 0x84e7, 0x080c,
+	0x24b6, 0x080c, 0x9057, 0x080c, 0x7e03, 0x080c, 0x22ef, 0x080c,
+	0x2423, 0x080c, 0x24ab, 0x2091, 0x3009, 0x7883, 0x0000, 0x1004,
+	0x091f, 0x7880, 0x9086, 0x0002, 0x1190, 0x7883, 0x4000, 0x7837,
+	0x4000, 0x7833, 0x0010, 0x0e04, 0x0913, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x2071,
+	0x1800, 0x7003, 0x0000, 0x2071, 0x1800, 0x7000, 0x908e, 0x0003,
+	0x1178, 0x080c, 0x4c44, 0x080c, 0x34ab, 0x080c, 0x77a9, 0x080c,
+	0x6f61, 0x080c, 0x8896, 0x080c, 0x8510, 0x080c, 0x2cf2, 0x0c58,
+	0x000b, 0x0c78, 0x0944, 0x0945, 0x0ae7, 0x0942, 0x0bae, 0x0d68,
+	0x0d68, 0x0d68, 0x080c, 0x0dd5, 0x0005, 0x0126, 0x00f6, 0x2091,
+	0x8000, 0x7000, 0x9086, 0x0001, 0x1904, 0x0aba, 0x080c, 0x576c,
+	0x1130, 0x0026, 0x2011, 0x0080, 0x080c, 0x0edf, 0x002e, 0x080c,
+	0x743e, 0x0150, 0x080c, 0x7461, 0x15a0, 0x2079, 0x0100, 0x7828,
+	0x9085, 0x1800, 0x782a, 0x0468, 0x080c, 0x736a, 0x7000, 0x9086,
+	0x0001, 0x1904, 0x0aba, 0x7098, 0x9086, 0x0028, 0x1904, 0x0aba,
+	0x080c, 0x84d0, 0x080c, 0x84c2, 0x2001, 0x0161, 0x2003, 0x0001,
+	0x2079, 0x0100, 0x7827, 0xffff, 0x7a28, 0x9295, 0x5e2f, 0x7a2a,
+	0x2011, 0x72ce, 0x080c, 0x85b0, 0x2011, 0x72c1, 0x080c, 0x868a,
+	0x2011, 0x5f16, 0x080c, 0x85b0, 0x2011, 0x8030, 0x901e, 0x7396,
+	0x04d0, 0x080c, 0x57c3, 0x2079, 0x0100, 0x7844, 0x9005, 0x1904,
+	0x0aba, 0x2011, 0x5f16, 0x080c, 0x85b0, 0x2011, 0x72ce, 0x080c,
+	0x85b0, 0x2011, 0x72c1, 0x080c, 0x868a, 0x2001, 0x0265, 0x2001,
+	0x0205, 0x2003, 0x0000, 0x7840, 0x9084, 0xfffb, 0x7842, 0x2001,
+	0x19a5, 0x2004, 0x9005, 0x1140, 0x00c6, 0x2061, 0x0100, 0x080c,
+	0x6063, 0x00ce, 0x0804, 0x0aba, 0x780f, 0x006b, 0x7a28, 0x080c,
+	0x7446, 0x0118, 0x9295, 0x5e2f, 0x0010, 0x9295, 0x402f, 0x7a2a,
+	0x2011, 0x8010, 0x73d8, 0x2001, 0x19a6, 0x2003, 0x0001, 0x080c,
+	0x2b97, 0x080c, 0x4b7f, 0x7248, 0xc284, 0x724a, 0x2001, 0x180c,
+	0x200c, 0xc1ac, 0xc1cc, 0x2102, 0x080c, 0xa613, 0x2011, 0x0004,
+	0x080c, 0xcc96, 0x080c, 0x68bc, 0x080c, 0x743e, 0x1120, 0x080c,
+	0x2bdb, 0x02e0, 0x0400, 0x080c, 0x606a, 0x0140, 0x7097, 0x0001,
+	0x70d3, 0x0000, 0x080c, 0x5990, 0x0804, 0x0aba, 0x080c, 0x575d,
+	0xd094, 0x0188, 0x2011, 0x180c, 0x2204, 0xc0cd, 0x2012, 0x080c,
+	0x5761, 0xd0d4, 0x1118, 0x080c, 0x2bdb, 0x1270, 0x2011, 0x180c,
+	0x2204, 0xc0bc, 0x00a8, 0x080c, 0x5761, 0xd0d4, 0x1db8, 0x2011,
+	0x180c, 0x2204, 0xc0bd, 0x0060, 0x2011, 0x180c, 0x2204, 0xc0bd,
+	0x2012, 0x080c, 0x6a04, 0x1128, 0xd0a4, 0x0118, 0x2204, 0xc0fd,
+	0x2012, 0x080c, 0x69ca, 0x0120, 0x7a0c, 0xc2b4, 0x7a0e, 0x00a8,
+	0x707f, 0x0000, 0x080c, 0x743e, 0x1130, 0x70b0, 0x9005, 0x1168,
+	0x080c, 0xd0d9, 0x0050, 0x080c, 0xd0d9, 0x70dc, 0xd09c, 0x1128,
+	0x70b0, 0x9005, 0x0110, 0x080c, 0x6040, 0x70e7, 0x0000, 0x70e3,
+	0x0000, 0x70a7, 0x0000, 0x080c, 0x2be3, 0x0228, 0x2011, 0x0101,
+	0x2204, 0xc0c4, 0x2012, 0x72dc, 0x080c, 0x743e, 0x1178, 0x9016,
+	0x0016, 0x080c, 0x2994, 0x2019, 0x196c, 0x211a, 0x001e, 0x705f,
+	0xffff, 0x7063, 0x00ef, 0x7083, 0x0000, 0x0020, 0x2019, 0x196c,
+	0x201b, 0x0000, 0x2079, 0x1847, 0x7804, 0xd0ac, 0x0108, 0xc295,
+	0x72de, 0x080c, 0x743e, 0x0118, 0x9296, 0x0004, 0x0548, 0x2011,
+	0x0001, 0x080c, 0xcc96, 0x70ab, 0x0000, 0x70af, 0xffff, 0x7003,
+	0x0002, 0x2079, 0x0100, 0x7827, 0x0003, 0x7828, 0x9085, 0x0003,
+	0x782a, 0x00fe, 0x080c, 0x2ff5, 0x2011, 0x0005, 0x080c, 0xa722,
+	0x080c, 0x9763, 0x080c, 0x743e, 0x0148, 0x00c6, 0x2061, 0x0100,
+	0x0016, 0x080c, 0x2994, 0x61e2, 0x001e, 0x00ce, 0x012e, 0x0420,
+	0x70ab, 0x0000, 0x70af, 0xffff, 0x7003, 0x0002, 0x00f6, 0x2079,
+	0x0100, 0x7827, 0x0003, 0x7828, 0x9085, 0x0003, 0x782a, 0x00fe,
+	0x2011, 0x0005, 0x080c, 0xa722, 0x080c, 0x9763, 0x080c, 0x743e,
+	0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x2994, 0x61e2,
+	0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005, 0x00c6, 0x00b6, 0x080c,
+	0x743e, 0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9, 0x0782, 0x080c,
+	0x743e, 0x1110, 0x900e, 0x0010, 0x2009, 0x007e, 0x86ff, 0x0138,
+	0x9180, 0x1000, 0x2004, 0x905d, 0x0110, 0xb800, 0xd0bc, 0x090c,
+	0x331a, 0x8108, 0x1f04, 0x0ace, 0x707f, 0x0000, 0x7080, 0x9084,
+	0x00ff, 0x7082, 0x70b3, 0x0000, 0x00be, 0x00ce, 0x0005, 0x00b6,
+	0x0126, 0x2091, 0x8000, 0x7000, 0x9086, 0x0002, 0x1904, 0x0bab,
+	0x70ac, 0x9086, 0xffff, 0x0130, 0x080c, 0x2ff5, 0x080c, 0x9763,
+	0x0804, 0x0bab, 0x70dc, 0xd0ac, 0x1110, 0xd09c, 0x0558, 0xd084,
+	0x0548, 0x0006, 0x2001, 0x0103, 0x2003, 0x002b, 0x000e, 0xd08c,
+	0x0508, 0x080c, 0x337d, 0x11d0, 0x70e0, 0x9086, 0xffff, 0x01b0,
+	0x080c, 0x318a, 0x080c, 0x9763, 0x70dc, 0xd094, 0x1904, 0x0bab,
+	0x2011, 0x0001, 0x080c, 0xd388, 0x0110, 0x2011, 0x0003, 0x901e,
+	0x080c, 0x31c4, 0x080c, 0x9763, 0x0804, 0x0bab, 0x70e4, 0x9005,
+	0x1904, 0x0bab, 0x70a8, 0x9005, 0x1904, 0x0bab, 0x70dc, 0xd0a4,
+	0x0118, 0xd0b4, 0x0904, 0x0bab, 0x080c, 0x69ca, 0x1904, 0x0bab,
+	0x080c, 0x6a1d, 0x1904, 0x0bab, 0x080c, 0x6a04, 0x01c0, 0x0156,
+	0x00c6, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x6699, 0x1118,
+	0xb800, 0xd0ec, 0x1138, 0x001e, 0x8108, 0x1f04, 0x0b44, 0x00ce,
+	0x015e, 0x0028, 0x001e, 0x00ce, 0x015e, 0x0804, 0x0bab, 0x0006,
+	0x2001, 0x0103, 0x2003, 0x002b, 0x000e, 0x2011, 0x19b2, 0x080c,
+	0x0f87, 0x2011, 0x19cc, 0x080c, 0x0f87, 0x7030, 0xc08c, 0x7032,
+	0x7003, 0x0003, 0x70af, 0xffff, 0x080c, 0x576c, 0x1130, 0x0026,
+	0x2011, 0x0040, 0x080c, 0x0edf, 0x002e, 0x9006, 0x080c, 0x2828,
+	0x080c, 0x337d, 0x0118, 0x080c, 0x4d1c, 0x0050, 0x0036, 0x0046,
+	0x2019, 0xffff, 0x2021, 0x0006, 0x080c, 0x4d36, 0x004e, 0x003e,
+	0x00f6, 0x2079, 0x0100, 0x080c, 0x7461, 0x0150, 0x080c, 0x743e,
+	0x7828, 0x0118, 0x9084, 0xe1ff, 0x0010, 0x9084, 0xffdf, 0x782a,
+	0x00fe, 0x2001, 0x19e7, 0x2004, 0x9086, 0x0005, 0x1120, 0x2011,
+	0x0000, 0x080c, 0xa722, 0x2011, 0x0000, 0x080c, 0xa72c, 0x080c,
+	0x9763, 0x080c, 0x9891, 0x012e, 0x00be, 0x0005, 0x0016, 0x0046,
+	0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x7904, 0x918c,
+	0xfffd, 0x7906, 0x2009, 0x00f7, 0x080c, 0x6029, 0x7940, 0x918c,
+	0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, 0x0040, 0xd19c,
+	0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, 0x7954, 0xd1ac,
+	0x1904, 0x0c3b, 0x2001, 0x19a6, 0x2004, 0x9005, 0x1518, 0x080c,
+	0x2c5e, 0x1148, 0x2001, 0x0001, 0x080c, 0x2bc6, 0x2001, 0x0001,
+	0x080c, 0x2ba9, 0x00b8, 0x080c, 0x2c66, 0x1138, 0x9006, 0x080c,
+	0x2bc6, 0x9006, 0x080c, 0x2ba9, 0x0068, 0x080c, 0x2c6e, 0x1d50,
+	0x2001, 0x1997, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c, 0x29c0,
+	0x0804, 0x0d1a, 0x080c, 0x744f, 0x0148, 0x080c, 0x7461, 0x1118,
+	0x080c, 0x7733, 0x0050, 0x080c, 0x7446, 0x0dd0, 0x080c, 0x772e,
+	0x080c, 0x7724, 0x080c, 0x736a, 0x0058, 0x080c, 0x743e, 0x0140,
+	0x2009, 0x00f8, 0x080c, 0x6029, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x743e, 0x0138,
+	0x7824, 0xd0ac, 0x1904, 0x0d1f, 0x1f04, 0x0c1a, 0x0070, 0x7824,
+	0x080c, 0x7458, 0x0118, 0xd0ac, 0x1904, 0x0d1f, 0x9084, 0x1800,
+	0x0d98, 0x7003, 0x0001, 0x0804, 0x0d1f, 0x2001, 0x0001, 0x080c,
+	0x2828, 0x0804, 0x0d32, 0x2001, 0x19a6, 0x2004, 0x9005, 0x1518,
+	0x080c, 0x2c5e, 0x1148, 0x2001, 0x0001, 0x080c, 0x2bc6, 0x2001,
+	0x0001, 0x080c, 0x2ba9, 0x00b8, 0x080c, 0x2c66, 0x1138, 0x9006,
+	0x080c, 0x2bc6, 0x9006, 0x080c, 0x2ba9, 0x0068, 0x080c, 0x2c6e,
+	0x1d50, 0x2001, 0x1997, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c,
+	0x29c0, 0x0804, 0x0d1a, 0x7850, 0x9085, 0x0040, 0x7852, 0x7938,
+	0x7850, 0x9084, 0xfbcf, 0x7852, 0x080c, 0x2c76, 0x9085, 0x2000,
+	0x7852, 0x793a, 0x20a9, 0x0046, 0x1d04, 0x0c74, 0x080c, 0x866a,
+	0x1f04, 0x0c74, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x7852,
+	0x793a, 0x080c, 0x744f, 0x0148, 0x080c, 0x7461, 0x1118, 0x080c,
+	0x7733, 0x0050, 0x080c, 0x7446, 0x0dd0, 0x080c, 0x772e, 0x080c,
+	0x7724, 0x080c, 0x736a, 0x0020, 0x2009, 0x00f8, 0x080c, 0x6029,
+	0x20a9, 0x0028, 0xa001, 0x1f04, 0x0c9a, 0x7850, 0x9085, 0x1400,
+	0x7852, 0x080c, 0x743e, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x2021, 0xe678, 0x2019, 0xea60, 0x0d0c, 0x866a, 0x7820, 0xd09c,
+	0x1580, 0x080c, 0x743e, 0x0904, 0x0cff, 0x7824, 0xd0ac, 0x1904,
+	0x0d1f, 0x080c, 0x7461, 0x1528, 0x0046, 0x2021, 0x0320, 0x8421,
+	0x1df0, 0x004e, 0x7827, 0x1800, 0x080c, 0x2c76, 0x7824, 0x9084,
+	0x1800, 0x1160, 0x9484, 0x0fff, 0x1138, 0x2001, 0x1810, 0x2004,
+	0xd0fc, 0x0110, 0x080c, 0x0d45, 0x8421, 0x1158, 0x1d04, 0x0cda,
+	0x080c, 0x866a, 0x080c, 0x772e, 0x080c, 0x7724, 0x7003, 0x0001,
+	0x04f0, 0x8319, 0x1948, 0x1d04, 0x0ce7, 0x080c, 0x866a, 0x2009,
+	0x199a, 0x2104, 0x9005, 0x0118, 0x8001, 0x200a, 0x1178, 0x200b,
+	0x000a, 0x7827, 0x0048, 0x20a9, 0x0002, 0x080c, 0x2c57, 0x7924,
+	0x080c, 0x2c76, 0xd19c, 0x0110, 0x080c, 0x2b97, 0x00d8, 0x080c,
+	0x744f, 0x1140, 0x94a2, 0x03e8, 0x1128, 0x080c, 0x7416, 0x7003,
+	0x0001, 0x00a8, 0x7827, 0x1800, 0x080c, 0x2c76, 0x7824, 0x080c,
+	0x7458, 0x0110, 0xd0ac, 0x1158, 0x9084, 0x1800, 0x0950, 0x7003,
+	0x0001, 0x0028, 0x2001, 0x0001, 0x080c, 0x2828, 0x0078, 0x2009,
+	0x180c, 0x210c, 0xd19c, 0x1120, 0x7904, 0x918d, 0x0002, 0x7906,
+	0x7827, 0x0048, 0x7828, 0x9085, 0x0028, 0x782a, 0x7850, 0x9085,
+	0x0400, 0x7852, 0x2001, 0x19a6, 0x2003, 0x0000, 0x9006, 0x78f2,
+	0x015e, 0x003e, 0x000e, 0x080c, 0x576c, 0x1110, 0x080c, 0x0e62,
+	0x012e, 0x00fe, 0x004e, 0x001e, 0x0005, 0x0006, 0x0016, 0x0036,
+	0x0046, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0156, 0x0069,
+	0x0d0c, 0x866a, 0x015e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be,
+	0x004e, 0x003e, 0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0x189e,
+	0x7004, 0x9086, 0x0001, 0x1110, 0x080c, 0x34ab, 0x00ee, 0x0005,
+	0x0005, 0x2a70, 0x2061, 0x19aa, 0x2063, 0x0003, 0x6007, 0x0003,
+	0x600b, 0x0008, 0x600f, 0x0137, 0x2001, 0x197b, 0x900e, 0x2102,
+	0x7196, 0x2001, 0x0100, 0x2004, 0x9082, 0x0002, 0x0218, 0x705f,
+	0xffff, 0x0008, 0x715e, 0x7067, 0xffff, 0x717e, 0x7182, 0x080c,
+	0xd0d9, 0x2061, 0x196b, 0x6003, 0x0909, 0x6106, 0x600b, 0x8800,
+	0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x001f, 0x611a, 0x601f,
+	0x07d0, 0x2061, 0x1973, 0x6003, 0x8000, 0x6106, 0x610a, 0x600f,
+	0x0200, 0x6013, 0x00ff, 0x6116, 0x601b, 0x0001, 0x611e, 0x2061,
+	0x1988, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, 0x600f,
+	0x2020, 0x2001, 0x182c, 0x2102, 0x0005, 0x9016, 0x080c, 0x6699,
+	0x1178, 0xb804, 0x90c4, 0x00ff, 0x98c6, 0x0006, 0x0128, 0x90c4,
+	0xff00, 0x98c6, 0x0600, 0x1120, 0x9186, 0x0080, 0x0108, 0x8210,
+	0x8108, 0x9186, 0x0800, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000,
+	0x2079, 0x0000, 0x000e, 0x00f6, 0x0010, 0x2091, 0x8000, 0x0e04,
+	0x0dd7, 0x0006, 0x0016, 0x2001, 0x8002, 0x0006, 0x2079, 0x0000,
+	0x000e, 0x7882, 0x7836, 0x001e, 0x798e, 0x000e, 0x788a, 0x000e,
+	0x7886, 0x3900, 0x789a, 0x7833, 0x0012, 0x2091, 0x5000, 0x0156,
+	0x00d6, 0x0036, 0x0026, 0x2079, 0x0300, 0x2069, 0x1aa4, 0x7a08,
+	0x226a, 0x2069, 0x1aa5, 0x7a18, 0x226a, 0x8d68, 0x7a1c, 0x226a,
+	0x782c, 0x2019, 0x1ab2, 0x201a, 0x2019, 0x1ab5, 0x9016, 0x7808,
+	0xd09c, 0x0168, 0x7820, 0x201a, 0x8210, 0x8318, 0x9386, 0x1aca,
+	0x0108, 0x0ca8, 0x7808, 0xd09c, 0x0110, 0x2011, 0xdead, 0x2019,
+	0x1ab3, 0x782c, 0x201a, 0x8318, 0x221a, 0x7803, 0x0000, 0x2069,
+	0x1a84, 0x901e, 0x20a9, 0x0020, 0x7b26, 0x7a28, 0x226a, 0x8d68,
+	0x8318, 0x1f04, 0x0e24, 0x002e, 0x003e, 0x00de, 0x015e, 0x2079,
+	0x1800, 0x7803, 0x0005, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004,
+	0xd084, 0x0180, 0x2001, 0x1a18, 0x2004, 0x9005, 0x0128, 0x2001,
+	0x008b, 0x2004, 0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003, 0x0002,
+	0x2003, 0x1001, 0x080c, 0x576c, 0x1110, 0x080c, 0x0e99, 0x0cd0,
+	0x0005, 0x918c, 0x03ff, 0x2001, 0x0003, 0x2004, 0x9084, 0x0600,
+	0x1118, 0x918d, 0x2800, 0x0010, 0x918d, 0x2000, 0x2001, 0x017f,
+	0x2102, 0x0005, 0x00f6, 0x0006, 0x2079, 0x1827, 0x2f04, 0x8000,
+	0x207a, 0x080c, 0x2c6e, 0x1150, 0x0006, 0x2001, 0x1997, 0x2004,
+	0xd0fc, 0x000e, 0x1118, 0x9082, 0x7530, 0x0010, 0x9082, 0x000f,
+	0x0258, 0x9006, 0x207a, 0x2079, 0x182a, 0x2f04, 0x9084, 0x0001,
+	0x9086, 0x0001, 0x207a, 0x0090, 0x2079, 0x182a, 0x2f7c, 0x8fff,
+	0x1138, 0x0026, 0x2011, 0x0080, 0x080c, 0x0edf, 0x002e, 0x0030,
+	0x0026, 0x2011, 0x0000, 0x080c, 0x0edf, 0x002e, 0x000e, 0x00fe,
+	0x0005, 0x0026, 0x0126, 0x2011, 0x0080, 0x080c, 0x0edf, 0x20a9,
+	0x0fff, 0x080c, 0x0f00, 0x2011, 0x0040, 0x04c9, 0x20a9, 0x0fff,
+	0x080c, 0x0f00, 0x0c80, 0x7038, 0xd0b4, 0x1128, 0x0026, 0x2011,
+	0x0040, 0x0469, 0x002e, 0x0005, 0x7038, 0xd0b4, 0x1128, 0x0026,
+	0x2011, 0x0080, 0x0421, 0x002e, 0x0005, 0x0026, 0x70ef, 0x0000,
+	0x0459, 0x1148, 0x080c, 0x2c6e, 0x1118, 0x2011, 0x8484, 0x0058,
+	0x2011, 0x8282, 0x0040, 0x080c, 0x2c6e, 0x1118, 0x2011, 0xcdc5,
+	0x0010, 0x2011, 0xcac2, 0x00e9, 0x002e, 0x0005, 0xd0b4, 0x0130,
+	0x0006, 0x3b00, 0x9084, 0xff3f, 0x20d8, 0x000e, 0x0005, 0x0016,
+	0x3b08, 0x3a00, 0x9104, 0x918d, 0x00c0, 0x21d8, 0x9084, 0xff3f,
+	0x9205, 0x20d0, 0x001e, 0x0005, 0x2001, 0x183a, 0x2004, 0xd0dc,
+	0x0005, 0x9e86, 0x1800, 0x190c, 0x0dd5, 0x70e8, 0xd0e4, 0x0108,
+	0xc2e5, 0x72ea, 0xd0e4, 0x1118, 0x9294, 0x00c0, 0x0c01, 0x0005,
+	0x1d04, 0x0f00, 0x2091, 0x6000, 0x1f04, 0x0f00, 0x0005, 0x890e,
+	0x810e, 0x810f, 0x9194, 0x003f, 0x918c, 0xffc0, 0x0005, 0x0006,
+	0x2200, 0x914d, 0x894f, 0x894d, 0x894d, 0x000e, 0x0005, 0x01d6,
+	0x0146, 0x0036, 0x0096, 0x2061, 0x188d, 0x600b, 0x0000, 0x600f,
+	0x0000, 0x6003, 0x0000, 0x6007, 0x0000, 0x2009, 0xffc0, 0x2105,
+	0x0006, 0x2001, 0xaaaa, 0x200f, 0x2019, 0x5555, 0x9016, 0x2049,
+	0x0bff, 0xab02, 0xa001, 0xa001, 0xa800, 0x9306, 0x1138, 0x2105,
+	0x9306, 0x0120, 0x8210, 0x99c8, 0x0400, 0x0c98, 0x000e, 0x200f,
+	0x2001, 0x189d, 0x928a, 0x000e, 0x1638, 0x928a, 0x0006, 0x2011,
+	0x0006, 0x1210, 0x2011, 0x0000, 0x2202, 0x9006, 0x2008, 0x82ff,
+	0x01b0, 0x8200, 0x600a, 0x600f, 0xffff, 0x6003, 0x0002, 0x6007,
+	0x0000, 0x0026, 0x2019, 0x0010, 0x9280, 0x0001, 0x20e8, 0x21a0,
+	0x21a8, 0x4104, 0x8319, 0x1de0, 0x8211, 0x1da0, 0x002e, 0x009e,
+	0x003e, 0x014e, 0x01de, 0x0005, 0x2011, 0x000e, 0x08e8, 0x0016,
+	0x0026, 0x0096, 0x3348, 0x080c, 0x0f07, 0x2100, 0x9300, 0x2098,
+	0x22e0, 0x009e, 0x002e, 0x001e, 0x0036, 0x3518, 0x20a9, 0x0001,
+	0x4002, 0x8007, 0x4004, 0x8319, 0x1dd8, 0x003e, 0x0005, 0x20e9,
+	0x0001, 0x71b8, 0x81ff, 0x11c0, 0x9006, 0x2009, 0x0200, 0x20a9,
+	0x0002, 0x9298, 0x0018, 0x23a0, 0x4001, 0x2009, 0x0700, 0x20a9,
+	0x0002, 0x9298, 0x0008, 0x23a0, 0x4001, 0x707c, 0x8007, 0x7180,
+	0x810f, 0x20a9, 0x0002, 0x4001, 0x9298, 0x000c, 0x23a0, 0x900e,
+	0x080c, 0x0db5, 0x2001, 0x0000, 0x810f, 0x20a9, 0x0002, 0x4001,
+	0x0005, 0x89ff, 0x0140, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c,
+	0x1031, 0x009e, 0x0cb0, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c,
+	0x10aa, 0x090c, 0x0dd5, 0x00ee, 0x0005, 0x0086, 0x00e6, 0x0006,
+	0x0026, 0x0036, 0x0126, 0x2091, 0x8000, 0x00c9, 0x2071, 0x1800,
+	0x73c0, 0x702c, 0x9016, 0x9045, 0x0158, 0x8210, 0x9906, 0x090c,
+	0x0dd5, 0x2300, 0x9202, 0x0120, 0x1a0c, 0x0dd5, 0xa000, 0x0c98,
+	0x012e, 0x003e, 0x002e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x0086,
+	0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x1910, 0x7010,
+	0x9005, 0x0140, 0x7018, 0x9045, 0x0128, 0x9906, 0x090c, 0x0dd5,
+	0xa000, 0x0cc8, 0x012e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0x0126, 0x2091, 0x8000, 0x70c0, 0x8001, 0x0270,
+	0x70c2, 0x702c, 0x2048, 0x9085, 0x0001, 0xa800, 0x702e, 0xa803,
+	0x0000, 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e, 0x0cd8,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x70c0, 0x90ca,
+	0x0020, 0x0268, 0x8001, 0x70c2, 0x702c, 0x2048, 0xa800, 0x702e,
+	0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e,
+	0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x0016, 0x890e, 0x810e,
+	0x810f, 0x9184, 0x003f, 0xa862, 0x9184, 0xffc0, 0xa85e, 0x001e,
+	0x0020, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x702c,
+	0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c, 0x84c2,
+	0x012e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9026, 0x2009, 0x0000,
+	0x2049, 0x0400, 0x2900, 0x702e, 0x8940, 0x2800, 0xa802, 0xa95e,
+	0xa863, 0x0001, 0x8420, 0x9886, 0x0440, 0x0120, 0x2848, 0x9188,
+	0x0040, 0x0c90, 0x2071, 0x188d, 0x7000, 0x9005, 0x11a0, 0x2001,
+	0x0534, 0xa802, 0x2048, 0x2009, 0x4d00, 0x8940, 0x2800, 0xa802,
+	0xa95e, 0xa863, 0x0001, 0x8420, 0x9886, 0x0800, 0x0120, 0x2848,
+	0x9188, 0x0040, 0x0c90, 0x2071, 0x188d, 0x7104, 0x7200, 0x82ff,
+	0x01d0, 0x7308, 0x8318, 0x831f, 0x831b, 0x831b, 0x7312, 0x8319,
+	0x2001, 0x0800, 0xa802, 0x2048, 0x8900, 0xa802, 0x2040, 0xa95e,
+	0xaa62, 0x8420, 0x2300, 0x9906, 0x0130, 0x2848, 0x9188, 0x0040,
+	0x9291, 0x0000, 0x0c88, 0xa803, 0x0000, 0x2071, 0x1800, 0x74be,
+	0x74c2, 0x0005, 0x00e6, 0x0016, 0x9984, 0xfc00, 0x01e8, 0x908c,
+	0xf800, 0x1168, 0x9982, 0x0400, 0x02b8, 0x9982, 0x0440, 0x0278,
+	0x9982, 0x0534, 0x0288, 0x9982, 0x0800, 0x1270, 0x0040, 0x9982,
+	0x0800, 0x0250, 0x2071, 0x188d, 0x7010, 0x9902, 0x1228, 0x9085,
+	0x0001, 0x001e, 0x00ee, 0x0005, 0x9006, 0x0cd8, 0x00e6, 0x2071,
+	0x1a17, 0x7007, 0x0000, 0x9006, 0x701e, 0x7022, 0x7002, 0x2071,
+	0x0000, 0x7010, 0x9085, 0x8044, 0x7012, 0x2071, 0x0080, 0x9006,
+	0x20a9, 0x0040, 0x7022, 0x1f04, 0x10e2, 0x702b, 0x0020, 0x00ee,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x00e6, 0xa06f, 0x0000, 0x2071,
+	0x1a17, 0x701c, 0x9088, 0x1a21, 0x280a, 0x8000, 0x9084, 0x003f,
+	0x701e, 0x7120, 0x9106, 0x090c, 0x0dd5, 0x7004, 0x9005, 0x1128,
+	0x00f6, 0x2079, 0x0080, 0x00a9, 0x00fe, 0x00ee, 0x012e, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x00e6, 0x2071, 0x1a17, 0x7004, 0x9005,
+	0x1128, 0x00f6, 0x2079, 0x0080, 0x0021, 0x00fe, 0x00ee, 0x012e,
+	0x0005, 0x7004, 0x9086, 0x0000, 0x1110, 0x7007, 0x0006, 0x7000,
+	0x0002, 0x112b, 0x12ae, 0x1129, 0x1129, 0x12a2, 0x12a2, 0x12a2,
+	0x12a2, 0x080c, 0x0dd5, 0x701c, 0x7120, 0x9106, 0x1148, 0x792c,
+	0x9184, 0x0001, 0x1120, 0xd1fc, 0x1110, 0x7007, 0x0000, 0x0005,
+	0x0096, 0x9180, 0x1a21, 0x2004, 0x700a, 0x2048, 0x8108, 0x918c,
+	0x003f, 0x7122, 0x782b, 0x0026, 0xa88c, 0x7802, 0xa890, 0x7806,
+	0xa894, 0x780a, 0xa898, 0x780e, 0xa878, 0x700e, 0xa870, 0x7016,
+	0xa874, 0x701a, 0xa868, 0x009e, 0xd084, 0x0120, 0x7007, 0x0001,
+	0x0029, 0x0005, 0x7007, 0x0002, 0x00b1, 0x0005, 0x0016, 0x0026,
+	0x710c, 0x2011, 0x0040, 0x9182, 0x0040, 0x1210, 0x2110, 0x9006,
+	0x700e, 0x7212, 0x8203, 0x7812, 0x782b, 0x0020, 0x782b, 0x0041,
+	0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x0136, 0x0146, 0x0156,
+	0x7014, 0x20e0, 0x7018, 0x2098, 0x20e9, 0x0000, 0x20a1, 0x0088,
+	0x782b, 0x0026, 0x710c, 0x2011, 0x0040, 0x9182, 0x0040, 0x1210,
+	0x2110, 0x9006, 0x700e, 0x22a8, 0x4006, 0x8203, 0x7812, 0x782b,
+	0x0020, 0x3300, 0x701a, 0x782b, 0x0001, 0x015e, 0x014e, 0x013e,
+	0x002e, 0x001e, 0x0005, 0x2009, 0x1a17, 0x2104, 0xc095, 0x200a,
+	0x080c, 0x1108, 0x0005, 0x0016, 0x00e6, 0x2071, 0x1a17, 0x00f6,
+	0x2079, 0x0080, 0x792c, 0xd1bc, 0x190c, 0x0dce, 0x782b, 0x0002,
+	0xd1fc, 0x0120, 0x918c, 0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee,
+	0x001e, 0x0005, 0x1119, 0x11c1, 0x11f5, 0x12cd, 0x0dd5, 0x12e8,
+	0x0dd5, 0x918c, 0x0700, 0x1550, 0x0136, 0x0146, 0x0156, 0x7014,
+	0x20e8, 0x7018, 0x20a0, 0x20e1, 0x0000, 0x2099, 0x0088, 0x782b,
+	0x0040, 0x7010, 0x20a8, 0x4005, 0x3400, 0x701a, 0x015e, 0x014e,
+	0x013e, 0x700c, 0x9005, 0x0578, 0x7800, 0x7802, 0x7804, 0x7806,
+	0x080c, 0x115e, 0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, 0x0100,
+	0x009e, 0x7007, 0x0000, 0x080c, 0x1119, 0x0005, 0x7008, 0x0096,
+	0x2048, 0xa86f, 0x0200, 0x009e, 0x0ca0, 0x918c, 0x0700, 0x1150,
+	0x700c, 0x9005, 0x0180, 0x7800, 0x7802, 0x7804, 0x7806, 0x080c,
+	0x1173, 0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, 0x0200, 0x009e,
+	0x7007, 0x0000, 0x0080, 0x0096, 0x7008, 0x2048, 0x7800, 0xa88e,
+	0x7804, 0xa892, 0x7808, 0xa896, 0x780c, 0xa89a, 0xa86f, 0x0100,
+	0x009e, 0x7007, 0x0000, 0x0096, 0x00d6, 0x7008, 0x2048, 0x2001,
+	0x18b9, 0x2004, 0x9906, 0x1128, 0xa89c, 0x080f, 0x00de, 0x009e,
+	0x00a0, 0x00de, 0x009e, 0x0096, 0x00d6, 0x7008, 0x2048, 0x0081,
+	0x0150, 0xa89c, 0x0086, 0x2940, 0x080f, 0x008e, 0x00de, 0x009e,
+	0x080c, 0x1108, 0x0005, 0x00de, 0x009e, 0x080c, 0x1108, 0x0005,
+	0xa8a8, 0xd08c, 0x0005, 0x0096, 0xa0a0, 0x904d, 0x090c, 0x0dd5,
+	0xa06c, 0x908e, 0x0100, 0x0130, 0xa87b, 0x0030, 0xa883, 0x0000,
+	0xa897, 0x4002, 0x080c, 0x6d0b, 0xa09f, 0x0000, 0xa0a3, 0x0000,
+	0x2848, 0x080c, 0x1031, 0x009e, 0x0005, 0x00a6, 0xa0a0, 0x904d,
+	0x090c, 0x0dd5, 0xa06c, 0x908e, 0x0100, 0x0128, 0xa87b, 0x0001,
+	0xa883, 0x0000, 0x00c0, 0xa80c, 0x2050, 0xb004, 0x9005, 0x0198,
+	0xa80e, 0x2050, 0x8006, 0x8006, 0x8007, 0x908c, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x0002, 0xa076, 0xa172, 0xb000, 0xa07a, 0x2810,
+	0x080c, 0x10e9, 0x00e8, 0xa97c, 0xa894, 0x0016, 0x0006, 0x080c,
+	0x6d0b, 0x000e, 0x001e, 0xd1fc, 0x1138, 0xd1f4, 0x0128, 0x00c6,
+	0x2060, 0x080c, 0xaf43, 0x00ce, 0x7008, 0x2048, 0xa89f, 0x0000,
+	0xa8a3, 0x0000, 0x080c, 0x1031, 0x7007, 0x0000, 0x080c, 0x1108,
+	0x00ae, 0x0005, 0x0126, 0x2091, 0x8000, 0x782b, 0x1001, 0x7007,
+	0x0005, 0x7000, 0xc094, 0x7002, 0x012e, 0x0005, 0x0096, 0x2001,
+	0x192e, 0x204c, 0xa87c, 0x7812, 0xa88c, 0x7802, 0xa890, 0x7806,
+	0xa894, 0x780a, 0xa898, 0x780e, 0x782b, 0x0020, 0x0126, 0x2091,
+	0x8000, 0x782b, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084, 0x7002,
+	0x2900, 0x700a, 0x012e, 0x009e, 0x0005, 0x20e1, 0x0000, 0x2099,
+	0x0088, 0x782b, 0x0040, 0x0096, 0x2001, 0x192e, 0x204c, 0xaa7c,
+	0x009e, 0x080c, 0x8ad0, 0x2009, 0x188c, 0x2104, 0x9084, 0xfffc,
+	0x200a, 0x080c, 0x8939, 0x7007, 0x0000, 0x080c, 0x1119, 0x0005,
+	0x7007, 0x0000, 0x080c, 0x1119, 0x0005, 0x0126, 0x2091, 0x2200,
+	0x2079, 0x0300, 0x2071, 0x1a61, 0x7003, 0x0000, 0x78bf, 0x00f6,
+	0x781b, 0x4800, 0x00c1, 0x7803, 0x0003, 0x780f, 0x0000, 0x20a9,
+	0x03d0, 0x2061, 0xeba8, 0x2c0d, 0x7912, 0xe104, 0x9ce0, 0x0002,
+	0x7916, 0x1f04, 0x1303, 0x7807, 0x0007, 0x7803, 0x0000, 0x7803,
+	0x0001, 0x012e, 0x0005, 0x00c6, 0x7803, 0x0000, 0x7808, 0xd09c,
+	0x0120, 0x7820, 0x080c, 0x1362, 0x0cc8, 0x2001, 0x1a62, 0x2003,
+	0x0000, 0x78ab, 0x0004, 0x78ac, 0xd0ac, 0x1de8, 0x78ab, 0x0002,
+	0x7807, 0x0007, 0x7827, 0x0030, 0x782b, 0x0400, 0x7827, 0x0031,
+	0x782b, 0x1a84, 0x781f, 0xff00, 0x781b, 0xb700, 0x2001, 0x0200,
+	0x2004, 0xd0dc, 0x0110, 0x781f, 0x0303, 0x2061, 0x1a84, 0x602f,
+	0x1cd0, 0x2001, 0x181a, 0x2004, 0x9082, 0x1cd0, 0x6032, 0x603b,
+	0x20ce, 0x2001, 0x3384, 0xd0fc, 0x190c, 0x0dd5, 0x2001, 0x0003,
+	0x2004, 0xd0d4, 0x1118, 0x783f, 0x3384, 0x0020, 0x9084, 0xc000,
+	0x783f, 0xb384, 0x604f, 0x193c, 0x2001, 0x1927, 0x2004, 0x6042,
+	0x00ce, 0x0005, 0x9086, 0x000d, 0x11d0, 0x7808, 0xd09c, 0x01b8,
+	0x7820, 0x0026, 0x2010, 0x080c, 0xcc74, 0x0180, 0x2260, 0x6000,
+	0x9086, 0x0004, 0x1158, 0x0016, 0x6120, 0x9186, 0x0009, 0x0108,
+	0x0020, 0x2009, 0x004c, 0x080c, 0xafbe, 0x001e, 0x002e, 0x0005,
+	0x0126, 0x2091, 0x2200, 0x7908, 0x9184, 0x0070, 0x190c, 0x0dce,
+	0xd19c, 0x0158, 0x7820, 0x908c, 0xf000, 0x15e8, 0x908a, 0x0024,
+	0x1a0c, 0x0dd5, 0x0023, 0x012e, 0x0005, 0x012e, 0x0005, 0x13bb,
+	0x13bb, 0x13d2, 0x13d7, 0x13db, 0x13e0, 0x1408, 0x140c, 0x141a,
+	0x141e, 0x13bb, 0x14eb, 0x14ef, 0x1561, 0x1568, 0x13bb, 0x1569,
+	0x156a, 0x1575, 0x157c, 0x13bb, 0x13bb, 0x13bb, 0x13bb, 0x13bb,
+	0x13bb, 0x13bb, 0x13e2, 0x13bb, 0x13bb, 0x13bb, 0x13bb, 0x13bb,
+	0x13bb, 0x13bf, 0x13bd, 0x080c, 0x0dd5, 0x080c, 0x0dce, 0x080c,
+	0x1587, 0x2009, 0x1a7a, 0x2104, 0x8000, 0x200a, 0x080c, 0x7ed7,
+	0x080c, 0x1aec, 0x0005, 0x2009, 0x0048, 0x2060, 0x080c, 0xafbe,
+	0x012e, 0x0005, 0x7004, 0xc085, 0xc0b5, 0x7006, 0x0005, 0x7004,
+	0xc085, 0x7006, 0x0005, 0x080c, 0x1587, 0x080c, 0x16e7, 0x0005,
+	0x080c, 0x0dd5, 0x080c, 0x1587, 0x2060, 0x6014, 0x0096, 0x2048,
+	0xa83b, 0xffff, 0x009e, 0x2009, 0x0048, 0x080c, 0xafbe, 0x2001,
+	0x015d, 0x2003, 0x0000, 0x2009, 0x03e8, 0x8109, 0x0160, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec,
+	0x1110, 0x080c, 0x158c, 0x2001, 0x0307, 0x2003, 0x8000, 0x0005,
+	0x7004, 0xc095, 0x7006, 0x0005, 0x080c, 0x1587, 0x2060, 0x6014,
+	0x0096, 0x2048, 0xa83b, 0xffff, 0x009e, 0x2009, 0x0048, 0x080c,
+	0xafbe, 0x0005, 0x080c, 0x1587, 0x080c, 0x0dd5, 0x080c, 0x1587,
+	0x080c, 0x14d6, 0x7827, 0x0018, 0x79ac, 0xd1dc, 0x0904, 0x1487,
+	0x7827, 0x0015, 0x7828, 0x782b, 0x0000, 0x9065, 0x0140, 0x2001,
+	0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x0804, 0x148d, 0x7004,
+	0x9005, 0x01c8, 0x1188, 0x78ab, 0x0004, 0x7827, 0x0018, 0x782b,
+	0x0000, 0xd1bc, 0x090c, 0x0dd5, 0x2001, 0x020d, 0x2003, 0x0050,
+	0x2003, 0x0020, 0x0804, 0x14bb, 0x78ab, 0x0004, 0x7803, 0x0001,
+	0x080c, 0x14ef, 0x0005, 0x7827, 0x0018, 0xa001, 0x7828, 0x7827,
+	0x0011, 0xa001, 0x7928, 0x9106, 0x0110, 0x79ac, 0x08e0, 0x00e6,
+	0x2071, 0x0200, 0x702c, 0xd0c4, 0x0140, 0x00ee, 0x080c, 0x1aec,
+	0x080c, 0x1313, 0x7803, 0x0001, 0x0005, 0x7037, 0x0001, 0xa001,
+	0x7150, 0x00ee, 0x918c, 0xff00, 0x9186, 0x0500, 0x0110, 0x79ac,
+	0x0810, 0x7004, 0xc09d, 0x7006, 0x78ab, 0x0004, 0x7803, 0x0001,
+	0x080c, 0x14ef, 0x2001, 0x020d, 0x2003, 0x0020, 0x0005, 0x7828,
+	0x782b, 0x0000, 0x9065, 0x090c, 0x0dd5, 0x6014, 0x2048, 0x78ab,
+	0x0004, 0x918c, 0x0700, 0x01a8, 0x080c, 0x7ed7, 0x080c, 0x1aec,
+	0x080c, 0xcc86, 0x0158, 0xa9ac, 0xa936, 0xa9b0, 0xa93a, 0xa83f,
+	0xffff, 0xa843, 0xffff, 0xa880, 0xc0bd, 0xa882, 0x080c, 0xc8a5,
+	0x0005, 0x6020, 0x9086, 0x0009, 0x1128, 0x2009, 0x004c, 0x080c,
+	0xafbe, 0x0048, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc,
+	0x6024, 0x190c, 0xd072, 0x2029, 0x00c8, 0x8529, 0x0128, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x0dc8, 0x7dbc, 0x080c, 0xeb51, 0xd5a4,
+	0x1118, 0x080c, 0x158c, 0x0005, 0x080c, 0x7ed7, 0x080c, 0x1aec,
+	0x0005, 0x781f, 0x0300, 0x7803, 0x0001, 0x0005, 0x0016, 0x0066,
+	0x0076, 0x00f6, 0x2079, 0x0300, 0x7908, 0x918c, 0x0007, 0x9186,
+	0x0003, 0x0120, 0x2001, 0x0016, 0x080c, 0x15fd, 0x00fe, 0x007e,
+	0x006e, 0x001e, 0x0005, 0x7004, 0xc09d, 0x7006, 0x0005, 0x7104,
+	0x9184, 0x0004, 0x190c, 0x0dd5, 0xd184, 0x11b1, 0xd19c, 0x0180,
+	0xc19c, 0x7106, 0x0016, 0x080c, 0x16ca, 0x001e, 0x0148, 0x2001,
+	0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x080c, 0x158c, 0x0005,
+	0x81ff, 0x190c, 0x0dd5, 0x0005, 0x2100, 0xc184, 0xc1b4, 0x7106,
+	0xd0b4, 0x0016, 0x00e6, 0x1904, 0x1556, 0x2071, 0x0200, 0x080c,
+	0x16b7, 0x05e0, 0x080c, 0x16ca, 0x05b0, 0x6014, 0x9005, 0x05b0,
+	0x0096, 0x2048, 0xa864, 0x009e, 0x9084, 0x00ff, 0x908e, 0x0029,
+	0x0160, 0x908e, 0x0048, 0x1550, 0x601c, 0xd084, 0x11e0, 0x00f6,
+	0x2c78, 0x080c, 0x1754, 0x00fe, 0x00b0, 0x00f6, 0x2c78, 0x080c,
+	0x18dd, 0x00fe, 0x2009, 0x01f4, 0x8109, 0x0168, 0x2001, 0x0201,
+	0x2004, 0x9005, 0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec, 0x1118,
+	0x080c, 0x158c, 0x0040, 0x2001, 0x020d, 0x2003, 0x0020, 0x080c,
+	0x1313, 0x7803, 0x0001, 0x00ee, 0x001e, 0x0005, 0x080c, 0x16ca,
+	0x0dd0, 0x2001, 0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x0461,
+	0x0c90, 0x0429, 0x2060, 0x2009, 0x0053, 0x080c, 0xafbe, 0x0005,
+	0x0005, 0x0005, 0x00e1, 0x2008, 0x00d1, 0x0006, 0x7004, 0xc09d,
+	0x7006, 0x000e, 0x080c, 0x8e21, 0x0005, 0x0089, 0x9005, 0x0118,
+	0x080c, 0x8a28, 0x0cd0, 0x0005, 0x2001, 0x0036, 0x2009, 0x1820,
+	0x210c, 0x2011, 0x181f, 0x2214, 0x080c, 0x15fd, 0x0005, 0x7808,
+	0xd09c, 0x0de8, 0x7820, 0x0005, 0x080c, 0x14d6, 0x00d6, 0x2069,
+	0x0200, 0x2009, 0x01f4, 0x8109, 0x0510, 0x6804, 0x9005, 0x0dd8,
+	0x2001, 0x015d, 0x2003, 0x0000, 0x79bc, 0xd1a4, 0x1528, 0x79b8,
+	0x918c, 0x0fff, 0x0180, 0x9182, 0x0841, 0x1268, 0x9188, 0x0007,
+	0x918c, 0x0ff8, 0x810c, 0x810c, 0x810c, 0x080c, 0x15ef, 0x6827,
+	0x0001, 0x8109, 0x1dd0, 0x04d9, 0x6827, 0x0002, 0x04c1, 0x6804,
+	0x9005, 0x1130, 0x682c, 0xd0e4, 0x1500, 0x6804, 0x9005, 0x0de8,
+	0x79b8, 0xd1ec, 0x1130, 0x08c0, 0x080c, 0x7ed7, 0x080c, 0x1aec,
+	0x0090, 0x7827, 0x0015, 0x782b, 0x0000, 0x7827, 0x0018, 0x782b,
+	0x0000, 0x2001, 0x020d, 0x2003, 0x0020, 0x2001, 0x0307, 0x2003,
+	0x0300, 0x7803, 0x0001, 0x00de, 0x0005, 0x682c, 0x9084, 0x5400,
+	0x9086, 0x5400, 0x0d30, 0x7827, 0x0015, 0x782b, 0x0000, 0x7803,
+	0x0001, 0x6800, 0x9085, 0x1800, 0x6802, 0x00de, 0x0005, 0x6824,
+	0x9084, 0x0003, 0x1de0, 0x0005, 0x2001, 0x0030, 0x2c08, 0x621c,
+	0x0021, 0x7830, 0x9086, 0x0041, 0x0005, 0x00f6, 0x2079, 0x0300,
+	0x0006, 0x7808, 0xd09c, 0x0140, 0x0016, 0x0026, 0x00c6, 0x080c,
+	0x1380, 0x00ce, 0x002e, 0x001e, 0x000e, 0x0006, 0x7832, 0x7936,
+	0x7a3a, 0x781b, 0x8080, 0x0059, 0x1118, 0x000e, 0x00fe, 0x0005,
+	0x000e, 0x792c, 0x3900, 0x8000, 0x2004, 0x080c, 0x0dd5, 0x2009,
+	0x180c, 0x2104, 0xc0f4, 0x200a, 0x2009, 0xff00, 0x8109, 0x0904,
+	0x167b, 0x7a18, 0x9284, 0x0030, 0x0904, 0x1676, 0x9284, 0x0048,
+	0x9086, 0x0008, 0x1904, 0x1676, 0x2001, 0x0109, 0x2004, 0xd08c,
+	0x01f0, 0x0006, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x0126,
+	0x2091, 0x2800, 0x00f6, 0x0026, 0x0016, 0x2009, 0x1a7d, 0x2104,
+	0x8000, 0x0208, 0x200a, 0x080c, 0x9163, 0x001e, 0x002e, 0x00fe,
+	0x012e, 0x015e, 0x014e, 0x013e, 0x01de, 0x01ce, 0x000e, 0x2001,
+	0x009b, 0x2004, 0xd0fc, 0x01d0, 0x0006, 0x0126, 0x01c6, 0x01d6,
+	0x0136, 0x0146, 0x0156, 0x00f6, 0x0016, 0x2009, 0x1a7e, 0x2104,
+	0x8000, 0x0208, 0x200a, 0x080c, 0x1ef2, 0x001e, 0x00fe, 0x015e,
+	0x014e, 0x013e, 0x01de, 0x01ce, 0x012e, 0x000e, 0x7818, 0xd0bc,
+	0x1904, 0x1626, 0x0005, 0x2001, 0x180c, 0x2004, 0xd0f4, 0x1528,
+	0x7a18, 0x9284, 0x0030, 0x0508, 0x9284, 0x0048, 0x9086, 0x0008,
+	0x11e0, 0x2001, 0x19f5, 0x2004, 0x9005, 0x01b8, 0x2001, 0x1a65,
+	0x2004, 0x9086, 0x0000, 0x0188, 0x2009, 0x1a7c, 0x2104, 0x8000,
+	0x0208, 0x200a, 0x080c, 0xa3d4, 0x2009, 0x180c, 0x2104, 0xc0f5,
+	0x200a, 0x2009, 0xff00, 0x0804, 0x1626, 0x9085, 0x0001, 0x0005,
+	0x7832, 0x7936, 0x7a3a, 0x781b, 0x8080, 0x080c, 0x161f, 0x1108,
+	0x0005, 0x792c, 0x3900, 0x8000, 0x2004, 0x080c, 0x0dd5, 0x7037,
+	0x0001, 0x7150, 0x7037, 0x0002, 0x7050, 0x2060, 0xd1bc, 0x1110,
+	0x7054, 0x2060, 0x918c, 0xff00, 0x9186, 0x0500, 0x0110, 0x9085,
+	0x0001, 0x0005, 0x0006, 0x0046, 0x00e6, 0x2071, 0x0200, 0x7037,
+	0x0002, 0x7058, 0x9084, 0xff00, 0x8007, 0x9086, 0x00bc, 0x1158,
+	0x2021, 0x1a7b, 0x2404, 0x8000, 0x0208, 0x2022, 0x080c, 0x7ed7,
+	0x080c, 0x1aec, 0x9006, 0x00ee, 0x004e, 0x000e, 0x0005, 0x0c11,
+	0x1108, 0x0005, 0x00e6, 0x0016, 0x2071, 0x0200, 0x0841, 0x6124,
+	0xd1dc, 0x01f8, 0x701c, 0xd08c, 0x0904, 0x1749, 0x7017, 0x0000,
+	0x2001, 0x0264, 0x2004, 0xd0bc, 0x0904, 0x1749, 0x2001, 0x0268,
+	0x00c6, 0x2064, 0x6104, 0x6038, 0x00ce, 0x918e, 0x0039, 0x1904,
+	0x1749, 0x9c06, 0x15f0, 0x0126, 0x2091, 0x2600, 0x080c, 0x7e1e,
+	0x012e, 0x7358, 0x745c, 0x6014, 0x905d, 0x0598, 0x2b48, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x190c, 0xd04d, 0xab42,
+	0xac3e, 0x2001, 0x1869, 0x2004, 0xd0b4, 0x1170, 0x601c, 0xd0e4,
+	0x1158, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1120,
+	0xa83b, 0x7fff, 0xa837, 0xffff, 0x080c, 0x20ee, 0x1190, 0x080c,
+	0x193a, 0x2a00, 0xa816, 0x0130, 0x2800, 0xa80e, 0x2c05, 0xa80a,
+	0x2c00, 0xa812, 0x7037, 0x0020, 0x781f, 0x0300, 0x001e, 0x00ee,
+	0x0005, 0x7037, 0x0050, 0x7037, 0x0020, 0x001e, 0x00ee, 0x080c,
+	0x158c, 0x0005, 0x080c, 0x0dd5, 0x2ff0, 0x0126, 0x2091, 0x2200,
+	0x0016, 0x00c6, 0x3e60, 0x6014, 0x2048, 0x2940, 0x903e, 0x2730,
+	0xa864, 0x2068, 0xa81a, 0x9d84, 0x000f, 0x9088, 0x20ce, 0x2165,
+	0x0002, 0x1780, 0x17ee, 0x1780, 0x1780, 0x1784, 0x17cf, 0x1780,
+	0x17a4, 0x1779, 0x17e5, 0x1780, 0x1780, 0x1789, 0x18db, 0x17b8,
+	0x17ae, 0xa964, 0x918c, 0x00ff, 0x918e, 0x0048, 0x0904, 0x17e5,
+	0x9085, 0x0001, 0x0804, 0x18d1, 0xa87c, 0xd0ac, 0x0dc8, 0x0804,
+	0x17f5, 0xa87c, 0xd0ac, 0x0da0, 0x0804, 0x1860, 0xa898, 0x901d,
+	0x1108, 0xab9c, 0x9016, 0xaab2, 0xaa3e, 0xaa42, 0x3e00, 0x9080,
+	0x0008, 0x2004, 0x9080, 0x8fef, 0x2005, 0x9005, 0x090c, 0x0dd5,
+	0x2004, 0xa8ae, 0x0804, 0x18b9, 0xa87c, 0xd0bc, 0x09c8, 0xa890,
+	0xa842, 0xa88c, 0xa83e, 0xa888, 0x0804, 0x17f5, 0xa87c, 0xd0bc,
+	0x0978, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa888, 0x0804, 0x1860,
+	0xa87c, 0xd0bc, 0x0928, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa804,
+	0x9045, 0x090c, 0x0dd5, 0xa164, 0xa91a, 0x91ec, 0x000f, 0x9d80,
+	0x20ce, 0x2065, 0xa888, 0xd19c, 0x1904, 0x1860, 0x0430, 0xa87c,
+	0xd0ac, 0x0904, 0x1780, 0xa804, 0x9045, 0x090c, 0x0dd5, 0xa164,
+	0xa91a, 0x91ec, 0x000f, 0x9d80, 0x20ce, 0x2065, 0x9006, 0xa842,
+	0xa83e, 0xd19c, 0x1904, 0x1860, 0x0080, 0xa87c, 0xd0ac, 0x0904,
+	0x1780, 0x9006, 0xa842, 0xa83e, 0x0804, 0x1860, 0xa87c, 0xd0ac,
+	0x0904, 0x1780, 0x9006, 0xa842, 0xa83e, 0x2c05, 0x908a, 0x0036,
+	0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x1818, 0x1818, 0x181a,
+	0x1818, 0x1818, 0x1818, 0x1824, 0x1818, 0x1818, 0x1818, 0x182e,
+	0x1818, 0x1818, 0x1818, 0x1838, 0x1818, 0x1818, 0x1818, 0x1842,
+	0x1818, 0x1818, 0x1818, 0x184c, 0x1818, 0x1818, 0x1818, 0x1856,
+	0x080c, 0x0dd5, 0xa574, 0xa478, 0x9d86, 0x0024, 0x0904, 0x178e,
+	0xa37c, 0xa280, 0x0804, 0x18b9, 0xa584, 0xa488, 0x9d86, 0x0024,
+	0x0904, 0x178e, 0xa38c, 0xa290, 0x0804, 0x18b9, 0xa594, 0xa498,
+	0x9d86, 0x0024, 0x0904, 0x178e, 0xa39c, 0xa2a0, 0x0804, 0x18b9,
+	0xa5a4, 0xa4a8, 0x9d86, 0x0024, 0x0904, 0x178e, 0xa3ac, 0xa2b0,
+	0x0804, 0x18b9, 0xa5b4, 0xa4b8, 0x9d86, 0x0024, 0x0904, 0x178e,
+	0xa3bc, 0xa2c0, 0x0804, 0x18b9, 0xa5c4, 0xa4c8, 0x9d86, 0x0024,
+	0x0904, 0x178e, 0xa3cc, 0xa2d0, 0x0804, 0x18b9, 0xa5d4, 0xa4d8,
+	0x9d86, 0x0024, 0x0904, 0x178e, 0xa3dc, 0xa2e0, 0x0804, 0x18b9,
+	0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002,
+	0x1883, 0x1881, 0x1881, 0x1881, 0x1881, 0x1881, 0x188e, 0x1881,
+	0x1881, 0x1881, 0x1881, 0x1881, 0x1899, 0x1881, 0x1881, 0x1881,
+	0x1881, 0x1881, 0x18a4, 0x1881, 0x1881, 0x1881, 0x1881, 0x1881,
+	0x18af, 0x080c, 0x0dd5, 0xa56c, 0xa470, 0xa774, 0xa678, 0x9d86,
+	0x002c, 0x0904, 0x178e, 0xa37c, 0xa280, 0x0458, 0xa584, 0xa488,
+	0xa78c, 0xa690, 0x9d86, 0x002c, 0x0904, 0x178e, 0xa394, 0xa298,
+	0x0400, 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, 0x9d86, 0x002c, 0x0904,
+	0x178e, 0xa3ac, 0xa2b0, 0x00a8, 0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0,
+	0x9d86, 0x002c, 0x0904, 0x178e, 0xa3c4, 0xa2c8, 0x0050, 0xa5cc,
+	0xa4d0, 0xa7d4, 0xa6d8, 0x9d86, 0x002c, 0x0904, 0x178e, 0xa3dc,
+	0xa2e0, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a, 0xa988,
+	0x8c60, 0x2c1d, 0xa8ac, 0xaab0, 0xa836, 0xaa3a, 0x8109, 0xa916,
+	0x1160, 0x3e60, 0x601c, 0xc085, 0x601e, 0xa87c, 0xc0dd, 0xa87e,
+	0x9006, 0x00ce, 0x001e, 0x012e, 0x0005, 0x2800, 0xa80e, 0xab0a,
+	0x2c00, 0xa812, 0x0c70, 0x0804, 0x1780, 0x2ff0, 0x0126, 0x2091,
+	0x2200, 0x0016, 0x00c6, 0x3e60, 0x6014, 0x2048, 0x2940, 0xa80e,
+	0x2061, 0x20c9, 0xa813, 0x20c9, 0x2c05, 0xa80a, 0xa964, 0xa91a,
+	0xa87c, 0xd0ac, 0x090c, 0x0dd5, 0x9006, 0xa842, 0xa83e, 0x2c05,
+	0x908a, 0x0034, 0x1a0c, 0x0dd5, 0xadcc, 0xacd0, 0xafd4, 0xaed8,
+	0xabdc, 0xaae0, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a,
+	0xa8ac, 0xaab0, 0xa836, 0xaa3a, 0xa988, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0008, 0x1120, 0x8109, 0xa916, 0x0128, 0x0080, 0x918a,
+	0x0002, 0xa916, 0x1160, 0x3e60, 0x601c, 0xc085, 0x601e, 0xa87c,
+	0xc0dd, 0xa87e, 0x9006, 0x00ce, 0x001e, 0x012e, 0x0005, 0xa804,
+	0x9045, 0x090c, 0x0dd5, 0xa80e, 0xa064, 0xa81a, 0x9084, 0x000f,
+	0x9080, 0x20ce, 0x2015, 0x82ff, 0x090c, 0x0dd5, 0xaa12, 0x2205,
+	0xa80a, 0x0c08, 0x903e, 0x2730, 0xa880, 0xd0fc, 0x1190, 0x2d00,
+	0x0002, 0x1a64, 0x1991, 0x1991, 0x1a64, 0x1991, 0x1a5e, 0x1a64,
+	0x1991, 0x1a01, 0x1a01, 0x1a01, 0x1a64, 0x1a01, 0x1a64, 0x1a5b,
+	0x1a01, 0xc0fc, 0xa882, 0xab2c, 0xaa30, 0xad1c, 0xac20, 0xdd9c,
+	0x0904, 0x1a66, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082,
+	0x001b, 0x0002, 0x197d, 0x197b, 0x197b, 0x197b, 0x197b, 0x197b,
+	0x1981, 0x197b, 0x197b, 0x197b, 0x197b, 0x197b, 0x1985, 0x197b,
+	0x197b, 0x197b, 0x197b, 0x197b, 0x1989, 0x197b, 0x197b, 0x197b,
+	0x197b, 0x197b, 0x198d, 0x080c, 0x0dd5, 0xa774, 0xa678, 0x0804,
+	0x1a66, 0xa78c, 0xa690, 0x0804, 0x1a66, 0xa7a4, 0xa6a8, 0x0804,
+	0x1a66, 0xa7bc, 0xa6c0, 0x0804, 0x1a66, 0xa7d4, 0xa6d8, 0x0804,
+	0x1a66, 0xa898, 0x901d, 0x1108, 0xab9c, 0x9016, 0x2c05, 0x908a,
+	0x0036, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x19b9, 0x19b9,
+	0x19bb, 0x19b9, 0x19b9, 0x19b9, 0x19c5, 0x19b9, 0x19b9, 0x19b9,
+	0x19cf, 0x19b9, 0x19b9, 0x19b9, 0x19d9, 0x19b9, 0x19b9, 0x19b9,
+	0x19e3, 0x19b9, 0x19b9, 0x19b9, 0x19ed, 0x19b9, 0x19b9, 0x19b9,
+	0x19f7, 0x080c, 0x0dd5, 0xa574, 0xa478, 0x9d86, 0x0004, 0x0904,
+	0x1a66, 0xa37c, 0xa280, 0x0804, 0x1a66, 0xa584, 0xa488, 0x9d86,
+	0x0004, 0x0904, 0x1a66, 0xa38c, 0xa290, 0x0804, 0x1a66, 0xa594,
+	0xa498, 0x9d86, 0x0004, 0x0904, 0x1a66, 0xa39c, 0xa2a0, 0x0804,
+	0x1a66, 0xa5a4, 0xa4a8, 0x9d86, 0x0004, 0x0904, 0x1a66, 0xa3ac,
+	0xa2b0, 0x0804, 0x1a66, 0xa5b4, 0xa4b8, 0x9d86, 0x0004, 0x0904,
+	0x1a66, 0xa3bc, 0xa2c0, 0x0804, 0x1a66, 0xa5c4, 0xa4c8, 0x9d86,
+	0x0004, 0x0904, 0x1a66, 0xa3cc, 0xa2d0, 0x0804, 0x1a66, 0xa5d4,
+	0xa4d8, 0x9d86, 0x0004, 0x0904, 0x1a66, 0xa3dc, 0xa2e0, 0x0804,
+	0x1a66, 0xa898, 0x901d, 0x1108, 0xab9c, 0x9016, 0x2c05, 0x908a,
+	0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x1a29, 0x1a27,
+	0x1a27, 0x1a27, 0x1a27, 0x1a27, 0x1a33, 0x1a27, 0x1a27, 0x1a27,
+	0x1a27, 0x1a27, 0x1a3d, 0x1a27, 0x1a27, 0x1a27, 0x1a27, 0x1a27,
+	0x1a47, 0x1a27, 0x1a27, 0x1a27, 0x1a27, 0x1a27, 0x1a51, 0x080c,
+	0x0dd5, 0xa56c, 0xa470, 0xa774, 0xa678, 0x9d86, 0x000c, 0x05b0,
+	0xa37c, 0xa280, 0x0498, 0xa584, 0xa488, 0xa78c, 0xa690, 0x9d86,
+	0x000c, 0x0560, 0xa394, 0xa298, 0x0448, 0xa59c, 0xa4a0, 0xa7a4,
+	0xa6a8, 0x9d86, 0x000c, 0x0510, 0xa3ac, 0xa2b0, 0x00f8, 0xa5b4,
+	0xa4b8, 0xa7bc, 0xa6c0, 0x9d86, 0x000c, 0x01c0, 0xa3c4, 0xa2c8,
+	0x00a8, 0xa5cc, 0xa4d0, 0xa7d4, 0xa6d8, 0x9d86, 0x000c, 0x0170,
+	0xa3dc, 0xa2e0, 0x0058, 0x9d86, 0x000e, 0x1130, 0x080c, 0x2086,
+	0x1904, 0x193a, 0x900e, 0x0050, 0x080c, 0x0dd5, 0xab2e, 0xaa32,
+	0xad1e, 0xac22, 0xaf26, 0xae2a, 0x080c, 0x2086, 0x0005, 0x6014,
+	0x2048, 0x6118, 0x810c, 0x810c, 0x810c, 0x81ff, 0x1118, 0xa887,
+	0x0001, 0x0008, 0xa986, 0x601b, 0x0002, 0xa874, 0x9084, 0x00ff,
+	0x9084, 0x0008, 0x0150, 0x00e9, 0x6000, 0x9086, 0x0004, 0x1120,
+	0x2009, 0x0048, 0x080c, 0xafbe, 0x0005, 0xa974, 0xd1dc, 0x1108,
+	0x0005, 0xa934, 0xa88c, 0x9106, 0x1158, 0xa938, 0xa890, 0x9106,
+	0x1138, 0x601c, 0xc084, 0x601e, 0x2009, 0x0048, 0x0804, 0xafbe,
+	0x0005, 0x0126, 0x00c6, 0x2091, 0x2200, 0x00ce, 0x7908, 0x918c,
+	0x0007, 0x9186, 0x0000, 0x05b0, 0x9186, 0x0003, 0x0598, 0x6020,
+	0x6023, 0x0000, 0x0006, 0x2031, 0x0008, 0x00c6, 0x781f, 0x0808,
+	0x7808, 0xd09c, 0x0120, 0x080c, 0x1380, 0x8631, 0x1db8, 0x00ce,
+	0x781f, 0x0800, 0x2031, 0x0168, 0x00c6, 0x7808, 0xd09c, 0x190c,
+	0x1380, 0x00ce, 0x2001, 0x0038, 0x080c, 0x1b74, 0x7930, 0x9186,
+	0x0040, 0x0160, 0x9186, 0x0042, 0x190c, 0x0dd5, 0x2001, 0x001e,
+	0x8001, 0x1df0, 0x8631, 0x1d40, 0x080c, 0x1b83, 0x000e, 0x6022,
+	0x012e, 0x0005, 0x080c, 0x1b70, 0x7827, 0x0015, 0x7828, 0x9c06,
+	0x1db8, 0x782b, 0x0000, 0x0ca0, 0x00f6, 0x2079, 0x0300, 0x7803,
+	0x0000, 0x78ab, 0x0004, 0x00fe, 0x080c, 0x743e, 0x1188, 0x2001,
+	0x0138, 0x2003, 0x0000, 0x2001, 0x0160, 0x2003, 0x0000, 0x2011,
+	0x012c, 0xa001, 0xa001, 0x8211, 0x1de0, 0x0059, 0x0804, 0x74ee,
+	0x0479, 0x0039, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202,
+	0x0005, 0x00e6, 0x2071, 0x0200, 0x080c, 0x2c82, 0x2009, 0x003c,
+	0x080c, 0x2410, 0x2001, 0x015d, 0x2003, 0x0000, 0x7000, 0x9084,
+	0x003c, 0x1de0, 0x080c, 0x84c2, 0x70a0, 0x70a2, 0x7098, 0x709a,
+	0x709c, 0x709e, 0x2001, 0x020d, 0x2003, 0x0020, 0x00f6, 0x2079,
+	0x0300, 0x080c, 0x1313, 0x7803, 0x0001, 0x00fe, 0x00ee, 0x0005,
+	0x2001, 0x0138, 0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c,
+	0x2003, 0x0000, 0x080c, 0x743e, 0x1108, 0x0005, 0x2021, 0x0260,
+	0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168, 0x2001, 0x0109, 0x201c,
+	0x939c, 0x0048, 0x1160, 0x2001, 0x0111, 0x201c, 0x83ff, 0x1110,
+	0x8421, 0x1d70, 0x2001, 0x015d, 0x2003, 0x0000, 0x0005, 0x0046,
+	0x2021, 0x0019, 0x2003, 0x0048, 0xa001, 0xa001, 0x201c, 0x939c,
+	0x0048, 0x0120, 0x8421, 0x1db0, 0x004e, 0x0c60, 0x004e, 0x0c40,
+	0x601c, 0xc084, 0x601e, 0x0005, 0x2c08, 0x621c, 0x080c, 0x15fd,
+	0x7930, 0x0005, 0x2c08, 0x621c, 0x080c, 0x16a8, 0x7930, 0x0005,
+	0x8001, 0x1df0, 0x0005, 0x2031, 0x0064, 0x781c, 0x9084, 0x0007,
+	0x0170, 0x2001, 0x0038, 0x0c41, 0x9186, 0x0040, 0x0904, 0x1be1,
+	0x2001, 0x001e, 0x0c69, 0x8631, 0x1d80, 0x080c, 0x0dd5, 0x781f,
+	0x0202, 0x2001, 0x015d, 0x2003, 0x0000, 0x2001, 0x0dac, 0x0c01,
+	0x781c, 0xd084, 0x0110, 0x0861, 0x04e0, 0x2001, 0x0030, 0x0891,
+	0x9186, 0x0040, 0x0568, 0x781c, 0xd084, 0x1da8, 0x781f, 0x0101,
+	0x2001, 0x0014, 0x0869, 0x2001, 0x0037, 0x0821, 0x9186, 0x0040,
+	0x0140, 0x2001, 0x0030, 0x080c, 0x1b7a, 0x9186, 0x0040, 0x190c,
+	0x0dd5, 0x00d6, 0x2069, 0x0200, 0x692c, 0xd1f4, 0x1170, 0xd1c4,
+	0x0160, 0xd19c, 0x0130, 0x6800, 0x9085, 0x1800, 0x6802, 0x00de,
+	0x0080, 0x6908, 0x9184, 0x0007, 0x1db0, 0x00de, 0x781f, 0x0100,
+	0x791c, 0x9184, 0x0007, 0x090c, 0x0dd5, 0xa001, 0xa001, 0x781f,
+	0x0200, 0x0005, 0x0126, 0x2091, 0x2400, 0x2071, 0x1a65, 0x2079,
+	0x0090, 0x012e, 0x0005, 0x9280, 0x0005, 0x2004, 0x2048, 0xa97c,
+	0xd1dc, 0x1904, 0x1c83, 0xa964, 0x9184, 0x0007, 0x0002, 0x1bff,
+	0x1c6e, 0x1c16, 0x1c18, 0x1c16, 0x1c56, 0x1c36, 0x1c25, 0x918c,
+	0x00ff, 0x9186, 0x0008, 0x1170, 0xa87c, 0xd0b4, 0x0904, 0x1ead,
+	0x9006, 0xa842, 0xa83e, 0xa988, 0x2900, 0xa85a, 0xa813, 0x20c9,
+	0x0804, 0x1c7f, 0x9186, 0x0048, 0x0904, 0x1c6e, 0x080c, 0x0dd5,
+	0x9184, 0x00ff, 0x9086, 0x0013, 0x0904, 0x1c6e, 0x9184, 0x00ff,
+	0x9086, 0x001b, 0x0904, 0x1c6e, 0x0c88, 0xa87c, 0xd0b4, 0x0904,
+	0x1ead, 0xa890, 0xa842, 0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac,
+	0xa846, 0xa8b0, 0xa84a, 0xa988, 0x0804, 0x1c76, 0xa864, 0x9084,
+	0x00ff, 0x9086, 0x001e, 0x19d0, 0xa87c, 0xd0b4, 0x0904, 0x1ead,
+	0xa890, 0xa842, 0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac, 0xa846,
+	0xa8b0, 0xa84a, 0xa804, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f,
+	0x9080, 0x20ce, 0x2005, 0xa812, 0xa988, 0x0448, 0x918c, 0x00ff,
+	0x9186, 0x0015, 0x1540, 0xa87c, 0xd0b4, 0x0904, 0x1ead, 0xa804,
+	0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080, 0x20ce, 0x2005,
+	0xa812, 0xa988, 0x9006, 0xa842, 0xa83e, 0x0088, 0xa87c, 0xd0b4,
+	0x0904, 0x1ead, 0xa988, 0x9006, 0xa842, 0xa83e, 0x2900, 0xa85a,
+	0xa864, 0x9084, 0x000f, 0x9080, 0x20ce, 0x2005, 0xa812, 0xa916,
+	0xa87c, 0xc0dd, 0xa87e, 0x0005, 0x00f6, 0x2079, 0x0090, 0x782c,
+	0xd0fc, 0x190c, 0x1ef2, 0x00e6, 0x2071, 0x1a65, 0x7000, 0x9005,
+	0x1904, 0x1cec, 0x7206, 0x9280, 0x0005, 0x204c, 0x9280, 0x0004,
+	0x2004, 0x782b, 0x0004, 0x00f6, 0x2079, 0x0200, 0x7803, 0x0040,
+	0x00fe, 0x00b6, 0x2058, 0xb86c, 0x7836, 0xb890, 0x00be, 0x00f6,
+	0x2079, 0x0200, 0x7803, 0x0040, 0xa001, 0xa001, 0xa001, 0xa001,
+	0xa001, 0xa001, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe,
+	0xa814, 0x2050, 0xa858, 0x2040, 0xa810, 0x2060, 0xa064, 0x90ec,
+	0x000f, 0xa944, 0x791a, 0x7116, 0xa848, 0x781e, 0x701a, 0x9006,
+	0x700e, 0x7012, 0x7004, 0xa940, 0xa838, 0x9106, 0x1500, 0xa93c,
+	0xa834, 0x9106, 0x11e0, 0x0006, 0x0016, 0xa938, 0xa834, 0x9105,
+	0x0118, 0x001e, 0x000e, 0x0098, 0x001e, 0x000e, 0x8aff, 0x01c8,
+	0x0126, 0x2091, 0x8000, 0x2009, 0x0306, 0x200b, 0x0808, 0x00d9,
+	0x0108, 0x00c9, 0x012e, 0x9006, 0x00ee, 0x00fe, 0x0005, 0x0036,
+	0x0046, 0xab38, 0xac34, 0x080c, 0x20ee, 0x004e, 0x003e, 0x0d30,
+	0x0c98, 0x9085, 0x0001, 0x0c80, 0x2009, 0x0306, 0x200b, 0x4800,
+	0x7027, 0x0000, 0x0005, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036,
+	0x0026, 0x8aff, 0x0904, 0x1ea6, 0x700c, 0x7214, 0x923a, 0x7010,
+	0x7218, 0x9203, 0x0a04, 0x1ea5, 0x9705, 0x0904, 0x1ea5, 0x903e,
+	0x2730, 0xa880, 0xd0fc, 0x1190, 0x2d00, 0x0002, 0x1e2f, 0x1d6e,
+	0x1d6e, 0x1e2f, 0x1e2f, 0x1e0c, 0x1e2f, 0x1d6e, 0x1e13, 0x1dbd,
+	0x1dbd, 0x1e2f, 0x1e2f, 0x1e2f, 0x1e06, 0x1dbd, 0xc0fc, 0xa882,
+	0xab2c, 0xaa30, 0xad1c, 0xac20, 0xdd9c, 0x0904, 0x1e3c, 0x2c05,
+	0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x1d5a,
+	0x1d58, 0x1d58, 0x1d58, 0x1d58, 0x1d58, 0x1d5e, 0x1d58, 0x1d58,
+	0x1d58, 0x1d58, 0x1d58, 0x1d62, 0x1d58, 0x1d58, 0x1d58, 0x1d58,
+	0x1d58, 0x1d66, 0x1d58, 0x1d58, 0x1d58, 0x1d58, 0x1d58, 0x1d6a,
+	0x080c, 0x0dd5, 0xa774, 0xa678, 0x0804, 0x1e3c, 0xa78c, 0xa690,
+	0x0804, 0x1e3c, 0xa7a4, 0xa6a8, 0x0804, 0x1e3c, 0xa7bc, 0xa6c0,
+	0x0804, 0x1e3c, 0xa7d4, 0xa6d8, 0x0804, 0x1e3c, 0x2c05, 0x908a,
+	0x0036, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x1d91, 0x1d91,
+	0x1d93, 0x1d91, 0x1d91, 0x1d91, 0x1d99, 0x1d91, 0x1d91, 0x1d91,
+	0x1d9f, 0x1d91, 0x1d91, 0x1d91, 0x1da5, 0x1d91, 0x1d91, 0x1d91,
+	0x1dab, 0x1d91, 0x1d91, 0x1d91, 0x1db1, 0x1d91, 0x1d91, 0x1d91,
+	0x1db7, 0x080c, 0x0dd5, 0xa574, 0xa478, 0xa37c, 0xa280, 0x0804,
+	0x1e3c, 0xa584, 0xa488, 0xa38c, 0xa290, 0x0804, 0x1e3c, 0xa594,
+	0xa498, 0xa39c, 0xa2a0, 0x0804, 0x1e3c, 0xa5a4, 0xa4a8, 0xa3ac,
+	0xa2b0, 0x0804, 0x1e3c, 0xa5b4, 0xa4b8, 0xa3bc, 0xa2c0, 0x0804,
+	0x1e3c, 0xa5c4, 0xa4c8, 0xa3cc, 0xa2d0, 0x0804, 0x1e3c, 0xa5d4,
+	0xa4d8, 0xa3dc, 0xa2e0, 0x0804, 0x1e3c, 0x2c05, 0x908a, 0x0034,
+	0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x1de0, 0x1dde, 0x1dde,
+	0x1dde, 0x1dde, 0x1dde, 0x1de8, 0x1dde, 0x1dde, 0x1dde, 0x1dde,
+	0x1dde, 0x1df0, 0x1dde, 0x1dde, 0x1dde, 0x1dde, 0x1dde, 0x1df8,
+	0x1dde, 0x1dde, 0x1dde, 0x1dde, 0x1dde, 0x1dff, 0x080c, 0x0dd5,
+	0xa56c, 0xa470, 0xa774, 0xa678, 0xa37c, 0xa280, 0x0804, 0x1e3c,
+	0xa584, 0xa488, 0xa78c, 0xa690, 0xa394, 0xa298, 0x0804, 0x1e3c,
+	0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, 0xa3ac, 0xa2b0, 0x0804, 0x1e3c,
+	0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0xa3c4, 0xa2c8, 0x04e8, 0xa5cc,
+	0xa4d0, 0xa7d4, 0xa6d8, 0xa3dc, 0xa2e0, 0x04b0, 0xa864, 0x9084,
+	0x00ff, 0x9086, 0x001e, 0x1518, 0x080c, 0x2086, 0x1904, 0x1d09,
+	0x900e, 0x0804, 0x1ea6, 0xab64, 0x939c, 0x00ff, 0x9386, 0x0048,
+	0x1180, 0x00c6, 0x7004, 0x2060, 0x6004, 0x9086, 0x0043, 0x00ce,
+	0x0904, 0x1dbd, 0xab9c, 0x9016, 0xad8c, 0xac90, 0xaf94, 0xae98,
+	0x0098, 0x9386, 0x0008, 0x0904, 0x1dbd, 0x080c, 0x0dd5, 0xa964,
+	0x918c, 0x00ff, 0x9186, 0x0013, 0x0904, 0x1d6e, 0x9186, 0x001b,
+	0x0904, 0x1dbd, 0x080c, 0x0dd5, 0x2009, 0x030f, 0x2104, 0xd0fc,
+	0x0530, 0x0066, 0x2009, 0x0306, 0x2104, 0x9084, 0x0030, 0x15c8,
+	0x2031, 0x1000, 0x200b, 0x4000, 0x2600, 0x9302, 0x928b, 0x0000,
+	0xa82e, 0xa932, 0x0278, 0x9105, 0x0168, 0x2011, 0x0000, 0x2618,
+	0x2600, 0x9500, 0xa81e, 0x9481, 0x0000, 0xa822, 0xa880, 0xc0fd,
+	0xa882, 0x0020, 0xa82f, 0x0000, 0xa833, 0x0000, 0x006e, 0x7b12,
+	0x7a16, 0x7d02, 0x7c06, 0x7f0a, 0x7e0e, 0x782b, 0x0001, 0x7000,
+	0x8000, 0x7002, 0xa83c, 0x9300, 0xa83e, 0xa840, 0x9201, 0xa842,
+	0x700c, 0x9300, 0x700e, 0x7010, 0x9201, 0x7012, 0x080c, 0x2086,
+	0x0428, 0x2031, 0x0080, 0x9584, 0x007f, 0x0108, 0x9632, 0x7124,
+	0x7000, 0x9086, 0x0000, 0x1198, 0xc185, 0x7126, 0x2009, 0x0306,
+	0x2104, 0xd0b4, 0x1904, 0x1e4c, 0x200b, 0x4040, 0x2009, 0x1a7f,
+	0x2104, 0x8000, 0x0a04, 0x1e4c, 0x200a, 0x0804, 0x1e4c, 0xc18d,
+	0x7126, 0xd184, 0x1d58, 0x0804, 0x1e4c, 0x9006, 0x002e, 0x003e,
+	0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c, 0x0dd5, 0x0026,
+	0x2001, 0x0105, 0x2003, 0x0010, 0x782b, 0x0004, 0x7003, 0x0000,
+	0x7004, 0x0016, 0x080c, 0x1cfc, 0x001e, 0x2060, 0x6014, 0x2048,
+	0x080c, 0xcc86, 0x0118, 0xa880, 0xc0bd, 0xa882, 0x6020, 0x9086,
+	0x0006, 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001, 0x00fa, 0x8001,
+	0x1df0, 0x60c8, 0x9206, 0x1dc0, 0x60c4, 0xa89a, 0x60c8, 0xa896,
+	0x7004, 0x2060, 0x00c6, 0x080c, 0xc8a5, 0x00ce, 0x2001, 0x19f5,
+	0x2004, 0x9c06, 0x1160, 0x2009, 0x0040, 0x080c, 0x2410, 0x080c,
+	0xa89b, 0x2011, 0x0000, 0x080c, 0xa72c, 0x080c, 0x9891, 0x002e,
+	0x0804, 0x2036, 0x0126, 0x2091, 0x2400, 0xa858, 0x2040, 0x792c,
+	0x782b, 0x0002, 0x9184, 0x0700, 0x1904, 0x1eaf, 0x7000, 0x0002,
+	0x2036, 0x1f04, 0x1f84, 0x2034, 0x8001, 0x7002, 0x7027, 0x0000,
+	0xd19c, 0x1158, 0x8aff, 0x0904, 0x1f51, 0x080c, 0x1d03, 0x0904,
+	0x2036, 0x080c, 0x1d03, 0x0804, 0x2036, 0x782b, 0x0004, 0xd194,
+	0x0148, 0xa880, 0xc0fc, 0xa882, 0x8aff, 0x1518, 0xa87c, 0xc0f5,
+	0xa87e, 0x00f8, 0x0026, 0x0036, 0xab3c, 0xaa40, 0x0016, 0x7910,
+	0xa82c, 0x9100, 0xa82e, 0x7914, 0xa830, 0x9101, 0xa832, 0x001e,
+	0x7810, 0x931a, 0x7814, 0x9213, 0x7800, 0xa81e, 0x7804, 0xa822,
+	0xab3e, 0xaa42, 0x003e, 0x002e, 0x080c, 0x20a1, 0xa880, 0xc0fd,
+	0xa882, 0x2a00, 0xa816, 0x2800, 0xa85a, 0x2c00, 0xa812, 0x7003,
+	0x0000, 0x2009, 0x0306, 0x200b, 0x4800, 0x7027, 0x0000, 0x0804,
+	0x2036, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079,
+	0x0100, 0x7a14, 0x9284, 0x1984, 0x9085, 0x0012, 0x7816, 0x0036,
+	0x2019, 0x1000, 0x8319, 0x090c, 0x0dd5, 0x7820, 0xd0bc, 0x1dd0,
+	0x003e, 0x79c8, 0x000e, 0x9102, 0x001e, 0x0006, 0x0016, 0x79c4,
+	0x000e, 0x9103, 0x78c6, 0x000e, 0x78ca, 0x9284, 0x1984, 0x9085,
+	0x0012, 0x7816, 0x002e, 0x00fe, 0x782b, 0x0008, 0x7003, 0x0000,
+	0x080c, 0x1cfc, 0x0804, 0x2036, 0x8001, 0x7002, 0x7024, 0x8004,
+	0x7026, 0xd194, 0x0170, 0x782c, 0xd0fc, 0x1904, 0x1ef7, 0xd19c,
+	0x1904, 0x2032, 0x8aff, 0x0904, 0x2036, 0x080c, 0x1d03, 0x0804,
+	0x2036, 0x0026, 0x0036, 0xab3c, 0xaa40, 0x080c, 0x20a1, 0xdd9c,
+	0x1904, 0x1ff1, 0x2c05, 0x908a, 0x0036, 0x1a0c, 0x0dd5, 0x9082,
+	0x001b, 0x0002, 0x1fc5, 0x1fc5, 0x1fc7, 0x1fc5, 0x1fc5, 0x1fc5,
+	0x1fcd, 0x1fc5, 0x1fc5, 0x1fc5, 0x1fd3, 0x1fc5, 0x1fc5, 0x1fc5,
+	0x1fd9, 0x1fc5, 0x1fc5, 0x1fc5, 0x1fdf, 0x1fc5, 0x1fc5, 0x1fc5,
+	0x1fe5, 0x1fc5, 0x1fc5, 0x1fc5, 0x1feb, 0x080c, 0x0dd5, 0xa07c,
+	0x931a, 0xa080, 0x9213, 0x0804, 0x1f26, 0xa08c, 0x931a, 0xa090,
+	0x9213, 0x0804, 0x1f26, 0xa09c, 0x931a, 0xa0a0, 0x9213, 0x0804,
+	0x1f26, 0xa0ac, 0x931a, 0xa0b0, 0x9213, 0x0804, 0x1f26, 0xa0bc,
+	0x931a, 0xa0c0, 0x9213, 0x0804, 0x1f26, 0xa0cc, 0x931a, 0xa0d0,
+	0x9213, 0x0804, 0x1f26, 0xa0dc, 0x931a, 0xa0e0, 0x9213, 0x0804,
+	0x1f26, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b,
+	0x0002, 0x2014, 0x2012, 0x2012, 0x2012, 0x2012, 0x2012, 0x201a,
+	0x2012, 0x2012, 0x2012, 0x2012, 0x2012, 0x2020, 0x2012, 0x2012,
+	0x2012, 0x2012, 0x2012, 0x2026, 0x2012, 0x2012, 0x2012, 0x2012,
+	0x2012, 0x202c, 0x080c, 0x0dd5, 0xa07c, 0x931a, 0xa080, 0x9213,
+	0x0804, 0x1f26, 0xa094, 0x931a, 0xa098, 0x9213, 0x0804, 0x1f26,
+	0xa0ac, 0x931a, 0xa0b0, 0x9213, 0x0804, 0x1f26, 0xa0c4, 0x931a,
+	0xa0c8, 0x9213, 0x0804, 0x1f26, 0xa0dc, 0x931a, 0xa0e0, 0x9213,
+	0x0804, 0x1f26, 0x0804, 0x1f22, 0x080c, 0x0dd5, 0x012e, 0x0005,
+	0x00f6, 0x00e6, 0x2071, 0x1a65, 0x7000, 0x9086, 0x0000, 0x0904,
+	0x2081, 0x2079, 0x0090, 0x2009, 0x0207, 0x210c, 0xd194, 0x01b8,
+	0x2009, 0x020c, 0x210c, 0x9184, 0x0003, 0x0188, 0x080c, 0xeb9a,
+	0x2001, 0x0133, 0x2004, 0x9005, 0x090c, 0x0dd5, 0x0016, 0x2009,
+	0x0040, 0x080c, 0x2410, 0x001e, 0x2001, 0x020c, 0x2102, 0x2009,
+	0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0x9106, 0x1120, 0x2009,
+	0x0040, 0x080c, 0x2410, 0x782c, 0xd0fc, 0x09a8, 0x080c, 0x1ef2,
+	0x7000, 0x9086, 0x0000, 0x1978, 0x782b, 0x0004, 0x782c, 0xd0ac,
+	0x1de8, 0x2009, 0x0040, 0x080c, 0x2410, 0x782b, 0x0002, 0x7003,
+	0x0000, 0x080c, 0x1cfc, 0x00ee, 0x00fe, 0x0005, 0xa880, 0xd0fc,
+	0x11a8, 0x8c60, 0x2c05, 0x9005, 0x0110, 0x8a51, 0x0005, 0xa004,
+	0x9005, 0x0168, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080,
+	0x20ce, 0x2065, 0x8cff, 0x090c, 0x0dd5, 0x8a51, 0x0005, 0x2050,
+	0x0005, 0xa880, 0xd0fc, 0x11b8, 0x8a50, 0x8c61, 0x2c05, 0x9005,
+	0x1190, 0x2800, 0x9906, 0x0120, 0xa000, 0x9005, 0x1108, 0x2900,
+	0x2040, 0xa85a, 0xa064, 0x9084, 0x000f, 0x9080, 0x20de, 0x2065,
+	0x8cff, 0x090c, 0x0dd5, 0x0005, 0x0000, 0x001d, 0x0021, 0x0025,
+	0x0029, 0x002d, 0x0031, 0x0035, 0x0000, 0x001b, 0x0021, 0x0027,
+	0x002d, 0x0033, 0x0000, 0x0000, 0x0023, 0x0000, 0x0000, 0x20c1,
+	0x20bd, 0x20c1, 0x20c1, 0x20cb, 0x0000, 0x20c1, 0x20c8, 0x20c8,
+	0x20c5, 0x20c8, 0x20c8, 0x0000, 0x20cb, 0x20c8, 0x0000, 0x20c3,
+	0x20c3, 0x0000, 0x20c3, 0x20cb, 0x0000, 0x20c3, 0x20c9, 0x20c9,
+	0x20c9, 0x0000, 0x20c9, 0x0000, 0x20cb, 0x20c9, 0x00c6, 0x00d6,
+	0x0086, 0xab42, 0xac3e, 0xa888, 0x9055, 0x0904, 0x22cd, 0x2940,
+	0xa064, 0x90ec, 0x000f, 0x9084, 0x00ff, 0x9086, 0x0008, 0x1118,
+	0x2061, 0x20c9, 0x00d0, 0x9de0, 0x20ce, 0x9d86, 0x0007, 0x0130,
+	0x9d86, 0x000e, 0x0118, 0x9d86, 0x000f, 0x1120, 0xa08c, 0x9422,
+	0xa090, 0x931b, 0x2c05, 0x9065, 0x1140, 0x0310, 0x0804, 0x22cd,
+	0xa004, 0x9045, 0x0904, 0x22cd, 0x08d8, 0x2c05, 0x9005, 0x0904,
+	0x21b5, 0xdd9c, 0x1904, 0x2171, 0x908a, 0x0036, 0x1a0c, 0x0dd5,
+	0x9082, 0x001b, 0x0002, 0x2146, 0x2146, 0x2148, 0x2146, 0x2146,
+	0x2146, 0x214e, 0x2146, 0x2146, 0x2146, 0x2154, 0x2146, 0x2146,
+	0x2146, 0x215a, 0x2146, 0x2146, 0x2146, 0x2160, 0x2146, 0x2146,
+	0x2146, 0x2166, 0x2146, 0x2146, 0x2146, 0x216c, 0x080c, 0x0dd5,
+	0xa07c, 0x9422, 0xa080, 0x931b, 0x0804, 0x21ab, 0xa08c, 0x9422,
+	0xa090, 0x931b, 0x0804, 0x21ab, 0xa09c, 0x9422, 0xa0a0, 0x931b,
+	0x0804, 0x21ab, 0xa0ac, 0x9422, 0xa0b0, 0x931b, 0x0804, 0x21ab,
+	0xa0bc, 0x9422, 0xa0c0, 0x931b, 0x0804, 0x21ab, 0xa0cc, 0x9422,
+	0xa0d0, 0x931b, 0x0804, 0x21ab, 0xa0dc, 0x9422, 0xa0e0, 0x931b,
+	0x04d0, 0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002,
+	0x2193, 0x2191, 0x2191, 0x2191, 0x2191, 0x2191, 0x2198, 0x2191,
+	0x2191, 0x2191, 0x2191, 0x2191, 0x219d, 0x2191, 0x2191, 0x2191,
+	0x2191, 0x2191, 0x21a2, 0x2191, 0x2191, 0x2191, 0x2191, 0x2191,
+	0x21a7, 0x080c, 0x0dd5, 0xa07c, 0x9422, 0xa080, 0x931b, 0x0098,
+	0xa094, 0x9422, 0xa098, 0x931b, 0x0070, 0xa0ac, 0x9422, 0xa0b0,
+	0x931b, 0x0048, 0xa0c4, 0x9422, 0xa0c8, 0x931b, 0x0020, 0xa0dc,
+	0x9422, 0xa0e0, 0x931b, 0x0630, 0x2300, 0x9405, 0x0160, 0x8a51,
+	0x0904, 0x22cd, 0x8c60, 0x0804, 0x211d, 0xa004, 0x9045, 0x0904,
+	0x22cd, 0x0804, 0x20f8, 0x8a51, 0x0904, 0x22cd, 0x8c60, 0x2c05,
+	0x9005, 0x1158, 0xa004, 0x9045, 0x0904, 0x22cd, 0xa064, 0x90ec,
+	0x000f, 0x9de0, 0x20ce, 0x2c05, 0x2060, 0xa880, 0xc0fc, 0xa882,
+	0x0804, 0x22c2, 0x2c05, 0x8422, 0x8420, 0x831a, 0x9399, 0x0000,
+	0xac2e, 0xab32, 0xdd9c, 0x1904, 0x225f, 0x9082, 0x001b, 0x0002,
+	0x21fb, 0x21fb, 0x21fd, 0x21fb, 0x21fb, 0x21fb, 0x220b, 0x21fb,
+	0x21fb, 0x21fb, 0x2219, 0x21fb, 0x21fb, 0x21fb, 0x2227, 0x21fb,
+	0x21fb, 0x21fb, 0x2235, 0x21fb, 0x21fb, 0x21fb, 0x2243, 0x21fb,
+	0x21fb, 0x21fb, 0x2251, 0x080c, 0x0dd5, 0xa17c, 0x2400, 0x9122,
+	0xa180, 0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa074, 0x9420, 0xa078,
+	0x9319, 0x0804, 0x22bd, 0xa18c, 0x2400, 0x9122, 0xa190, 0x2300,
+	0x911b, 0x0a0c, 0x0dd5, 0xa084, 0x9420, 0xa088, 0x9319, 0x0804,
+	0x22bd, 0xa19c, 0x2400, 0x9122, 0xa1a0, 0x2300, 0x911b, 0x0a0c,
+	0x0dd5, 0xa094, 0x9420, 0xa098, 0x9319, 0x0804, 0x22bd, 0xa1ac,
+	0x2400, 0x9122, 0xa1b0, 0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa0a4,
+	0x9420, 0xa0a8, 0x9319, 0x0804, 0x22bd, 0xa1bc, 0x2400, 0x9122,
+	0xa1c0, 0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa0b4, 0x9420, 0xa0b8,
+	0x9319, 0x0804, 0x22bd, 0xa1cc, 0x2400, 0x9122, 0xa1d0, 0x2300,
+	0x911b, 0x0a0c, 0x0dd5, 0xa0c4, 0x9420, 0xa0c8, 0x9319, 0x0804,
+	0x22bd, 0xa1dc, 0x2400, 0x9122, 0xa1e0, 0x2300, 0x911b, 0x0a0c,
+	0x0dd5, 0xa0d4, 0x9420, 0xa0d8, 0x9319, 0x0804, 0x22bd, 0x9082,
+	0x001b, 0x0002, 0x227d, 0x227b, 0x227b, 0x227b, 0x227b, 0x227b,
+	0x228a, 0x227b, 0x227b, 0x227b, 0x227b, 0x227b, 0x2297, 0x227b,
+	0x227b, 0x227b, 0x227b, 0x227b, 0x22a4, 0x227b, 0x227b, 0x227b,
+	0x227b, 0x227b, 0x22b1, 0x080c, 0x0dd5, 0xa17c, 0x2400, 0x9122,
+	0xa180, 0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa06c, 0x9420, 0xa070,
+	0x9319, 0x0498, 0xa194, 0x2400, 0x9122, 0xa198, 0x2300, 0x911b,
+	0x0a0c, 0x0dd5, 0xa084, 0x9420, 0xa088, 0x9319, 0x0430, 0xa1ac,
+	0x2400, 0x9122, 0xa1b0, 0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa09c,
+	0x9420, 0xa0a0, 0x9319, 0x00c8, 0xa1c4, 0x2400, 0x9122, 0xa1c8,
+	0x2300, 0x911b, 0x0a0c, 0x0dd5, 0xa0b4, 0x9420, 0xa0b8, 0x9319,
+	0x0060, 0xa1dc, 0x2400, 0x9122, 0xa1e0, 0x2300, 0x911b, 0x0a0c,
+	0x0dd5, 0xa0cc, 0x9420, 0xa0d0, 0x9319, 0xac1e, 0xab22, 0xa880,
+	0xc0fd, 0xa882, 0x2800, 0xa85a, 0x2c00, 0xa812, 0x2a00, 0xa816,
+	0x000e, 0x000e, 0x000e, 0x9006, 0x0028, 0x008e, 0x00de, 0x00ce,
+	0x9085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004, 0xd0bc, 0x190c,
+	0x0dce, 0x9084, 0x0007, 0x0002, 0x22ee, 0x1ef2, 0x22ee, 0x22e4,
+	0x22e7, 0x22ea, 0x22e7, 0x22ea, 0x080c, 0x1ef2, 0x0005, 0x080c,
+	0x11a3, 0x0005, 0x080c, 0x1ef2, 0x080c, 0x11a3, 0x0005, 0x0126,
+	0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x0260, 0x2069, 0x1800,
+	0x7817, 0x0000, 0x789b, 0x0814, 0x78a3, 0x0406, 0x789f, 0x0410,
+	0x2009, 0x013b, 0x200b, 0x0400, 0x781b, 0x0002, 0x783b, 0x001f,
+	0x7837, 0x0020, 0x7803, 0x1600, 0x012e, 0x0005, 0x2091, 0x2600,
+	0x781c, 0xd0a4, 0x190c, 0x240d, 0x7900, 0xd1dc, 0x1118, 0x9084,
+	0x0006, 0x001a, 0x9084, 0x000e, 0x0002, 0x2335, 0x232d, 0x7e1e,
+	0x232d, 0x232f, 0x232f, 0x232f, 0x232f, 0x7e04, 0x232d, 0x2331,
+	0x232d, 0x232f, 0x232d, 0x232f, 0x232d, 0x080c, 0x0dd5, 0x0031,
+	0x0020, 0x080c, 0x7e04, 0x080c, 0x7e1e, 0x0005, 0x0006, 0x0016,
+	0x0026, 0x080c, 0xeb9a, 0x7930, 0x9184, 0x0003, 0x01c0, 0x2001,
+	0x19f5, 0x2004, 0x9005, 0x0170, 0x2001, 0x0133, 0x2004, 0x9005,
+	0x090c, 0x0dd5, 0x00c6, 0x2001, 0x19f5, 0x2064, 0x080c, 0xc8a5,
+	0x00ce, 0x00f8, 0x2009, 0x0040, 0x080c, 0x2410, 0x00d0, 0x9184,
+	0x0014, 0x01a0, 0x6a00, 0x9286, 0x0003, 0x0160, 0x080c, 0x743e,
+	0x1138, 0x080c, 0x7724, 0x080c, 0x60ad, 0x080c, 0x736a, 0x0010,
+	0x080c, 0x5f6c, 0x080c, 0x7ecd, 0x0041, 0x0018, 0x9184, 0x9540,
+	0x1dc8, 0x002e, 0x001e, 0x000e, 0x0005, 0x00e6, 0x0036, 0x0046,
+	0x0056, 0x2071, 0x1a61, 0x080c, 0x1aec, 0x005e, 0x004e, 0x003e,
+	0x00ee, 0x0005, 0x0126, 0x2091, 0x2e00, 0x2071, 0x1800, 0x7128,
+	0x2001, 0x196e, 0x2102, 0x2001, 0x1976, 0x2102, 0x2001, 0x013b,
+	0x2102, 0x2079, 0x0200, 0x2001, 0x0201, 0x789e, 0x78a3, 0x0200,
+	0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398, 0x0005, 0x2320,
+	0x9182, 0x0204, 0x1230, 0x2011, 0x0008, 0x8423, 0x8423, 0x8423,
+	0x0488, 0x9182, 0x024c, 0x1240, 0x2011, 0x0007, 0x8403, 0x8003,
+	0x9400, 0x9400, 0x9420, 0x0430, 0x9182, 0x02bc, 0x1238, 0x2011,
+	0x0006, 0x8403, 0x8003, 0x9400, 0x9420, 0x00e0, 0x9182, 0x034c,
+	0x1230, 0x2011, 0x0005, 0x8403, 0x8003, 0x9420, 0x0098, 0x9182,
+	0x042c, 0x1228, 0x2011, 0x0004, 0x8423, 0x8423, 0x0058, 0x9182,
+	0x059c, 0x1228, 0x2011, 0x0003, 0x8403, 0x9420, 0x0018, 0x2011,
+	0x0002, 0x8423, 0x9482, 0x0228, 0x8002, 0x8020, 0x8301, 0x9402,
+	0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405, 0x789a, 0x012e,
+	0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6814, 0x9084, 0xffc0,
+	0x910d, 0x6916, 0x00de, 0x000e, 0x0005, 0x00d6, 0x2069, 0x0200,
+	0x9005, 0x6810, 0x0110, 0xc0a5, 0x0008, 0xc0a4, 0x6812, 0x00de,
+	0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6810, 0x9084, 0xfff8,
+	0x910d, 0x6912, 0x00de, 0x000e, 0x0005, 0x7938, 0x080c, 0x0dce,
+	0x00f6, 0x2079, 0x0200, 0x7902, 0xa001, 0xa001, 0xa001, 0xa001,
+	0xa001, 0xa001, 0x7902, 0xa001, 0xa001, 0xa001, 0xa001, 0xa001,
+	0xa001, 0x00fe, 0x0005, 0x0126, 0x2091, 0x2800, 0x2061, 0x0100,
+	0x2071, 0x1800, 0x2009, 0x0000, 0x080c, 0x2c7c, 0x080c, 0x2b97,
+	0x6054, 0x8004, 0x8004, 0x8004, 0x8004, 0x9084, 0x000c, 0x6150,
+	0x918c, 0xfff3, 0x9105, 0x6052, 0x6050, 0x9084, 0xb17f, 0x9085,
+	0x2000, 0x6052, 0x2009, 0x199c, 0x2011, 0x199d, 0x6358, 0x939c,
+	0x38f0, 0x2320, 0x080c, 0x2bdb, 0x1238, 0x939d, 0x4003, 0x94a5,
+	0x8603, 0x230a, 0x2412, 0x0030, 0x939d, 0x0203, 0x94a5, 0x8603,
+	0x230a, 0x2412, 0x9006, 0x080c, 0x2bc6, 0x9006, 0x080c, 0x2ba9,
+	0x20a9, 0x0012, 0x1d04, 0x2462, 0x2091, 0x6000, 0x1f04, 0x2462,
+	0x602f, 0x0100, 0x602f, 0x0000, 0x6050, 0x9085, 0x0400, 0x9084,
+	0xdfff, 0x6052, 0x6024, 0x6026, 0x080c, 0x28b5, 0x2009, 0x00ef,
+	0x6132, 0x6136, 0x080c, 0x28c5, 0x60e7, 0x0000, 0x61ea, 0x60e3,
+	0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f,
+	0x0000, 0x6007, 0x349f, 0x60bb, 0x0000, 0x20a9, 0x0018, 0x60bf,
+	0x0000, 0x1f04, 0x248f, 0x60bb, 0x0000, 0x60bf, 0x0108, 0x60bf,
+	0x0012, 0x60bf, 0x0405, 0x60bf, 0x0014, 0x60bf, 0x0320, 0x60bf,
+	0x0018, 0x601b, 0x00f0, 0x601f, 0x001e, 0x600f, 0x006b, 0x602b,
+	0x402f, 0x012e, 0x0005, 0x00f6, 0x2079, 0x0140, 0x78c3, 0x0080,
+	0x78c3, 0x0083, 0x78c3, 0x0000, 0x00fe, 0x0005, 0x2001, 0x1835,
+	0x2003, 0x0000, 0x2001, 0x1834, 0x2003, 0x0001, 0x0005, 0x0126,
+	0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x6124, 0x0066, 0x2031,
+	0x1837, 0x2634, 0x96b4, 0x0028, 0x006e, 0x1138, 0x6020, 0xd1bc,
+	0x0120, 0xd0bc, 0x1168, 0xd0b4, 0x1198, 0x9184, 0x5e2c, 0x1118,
+	0x9184, 0x0007, 0x00aa, 0x9195, 0x0004, 0x9284, 0x0007, 0x0082,
+	0x0016, 0x2001, 0x188b, 0x200c, 0xd184, 0x001e, 0x0d70, 0x0c98,
+	0x0016, 0x2001, 0x188b, 0x200c, 0xd194, 0x001e, 0x0d30, 0x0c58,
+	0x2512, 0x24f8, 0x24fb, 0x24fe, 0x2503, 0x2505, 0x2509, 0x250d,
+	0x080c, 0x9094, 0x00b8, 0x080c, 0x9163, 0x00a0, 0x080c, 0x9163,
+	0x080c, 0x9094, 0x0078, 0x0099, 0x0068, 0x080c, 0x9094, 0x0079,
+	0x0048, 0x080c, 0x9163, 0x0059, 0x0028, 0x080c, 0x9163, 0x080c,
+	0x9094, 0x0029, 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x00a6,
+	0x6124, 0x6028, 0xd09c, 0x0118, 0xd19c, 0x1904, 0x277a, 0xd1f4,
+	0x190c, 0x0dce, 0x080c, 0x743e, 0x0904, 0x256d, 0x080c, 0xd388,
+	0x1120, 0x7000, 0x9086, 0x0003, 0x0570, 0x6024, 0x9084, 0x1800,
+	0x0550, 0x080c, 0x7461, 0x0118, 0x080c, 0x744f, 0x1520, 0x6027,
+	0x0020, 0x6043, 0x0000, 0x080c, 0xd388, 0x0168, 0x080c, 0x7461,
+	0x1150, 0x2001, 0x19a6, 0x2003, 0x0001, 0x6027, 0x1800, 0x080c,
+	0x72ce, 0x0804, 0x277d, 0x70a4, 0x9005, 0x1150, 0x70a7, 0x0001,
+	0x00d6, 0x2069, 0x0140, 0x080c, 0x7495, 0x00de, 0x1904, 0x277d,
+	0x080c, 0x772e, 0x0428, 0x080c, 0x7461, 0x1590, 0x6024, 0x9084,
+	0x1800, 0x1108, 0x0468, 0x080c, 0x772e, 0x080c, 0x7724, 0x080c,
+	0x60ad, 0x080c, 0x736a, 0x0804, 0x277a, 0xd1ac, 0x1508, 0x6024,
+	0xd0dc, 0x1170, 0xd0e4, 0x1178, 0xd0d4, 0x1190, 0xd0cc, 0x0130,
+	0x7098, 0x9086, 0x0028, 0x1110, 0x080c, 0x7611, 0x0804, 0x277a,
+	0x080c, 0x7729, 0x0048, 0x2001, 0x197c, 0x2003, 0x0002, 0x0020,
+	0x080c, 0x7576, 0x0804, 0x277a, 0x080c, 0x76ac, 0x0804, 0x277a,
+	0x6220, 0xd1bc, 0x0138, 0xd2bc, 0x1904, 0x27ed, 0xd2b4, 0x1904,
+	0x2800, 0x0000, 0xd1ac, 0x0904, 0x268f, 0x0036, 0x6328, 0xc3bc,
+	0x632a, 0x003e, 0x080c, 0x743e, 0x11c0, 0x6027, 0x0020, 0x0006,
+	0x0026, 0x0036, 0x080c, 0x7458, 0x1158, 0x080c, 0x7724, 0x080c,
+	0x60ad, 0x080c, 0x736a, 0x003e, 0x002e, 0x000e, 0x00ae, 0x0005,
+	0x003e, 0x002e, 0x000e, 0x080c, 0x7416, 0x0016, 0x0046, 0x00c6,
+	0x644c, 0x9486, 0xf0f0, 0x1138, 0x2061, 0x0100, 0x644a, 0x6043,
+	0x0090, 0x6043, 0x0010, 0x74da, 0x948c, 0xff00, 0x7038, 0xd084,
+	0x0178, 0x9186, 0xf800, 0x1160, 0x7048, 0xd084, 0x1148, 0xc085,
+	0x704a, 0x0036, 0x2418, 0x2011, 0x8016, 0x080c, 0x4b7f, 0x003e,
+	0x080c, 0xd381, 0x1904, 0x266c, 0x9196, 0xff00, 0x05a8, 0x7060,
+	0x9084, 0x00ff, 0x810f, 0x81ff, 0x0110, 0x9116, 0x0568, 0x7130,
+	0xd184, 0x1550, 0x080c, 0x3378, 0x0128, 0xc18d, 0x7132, 0x080c,
+	0x6a04, 0x1510, 0x6240, 0x9294, 0x0010, 0x0130, 0x6248, 0x9294,
+	0xff00, 0x9296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904, 0x266c,
+	0x7038, 0xd08c, 0x1140, 0x2001, 0x180c, 0x200c, 0xd1ac, 0x1904,
+	0x266c, 0xc1ad, 0x2102, 0x0036, 0x73d8, 0x2011, 0x8013, 0x080c,
+	0x4b7f, 0x003e, 0x0804, 0x266c, 0x7038, 0xd08c, 0x1140, 0x2001,
+	0x180c, 0x200c, 0xd1ac, 0x1904, 0x266c, 0xc1ad, 0x2102, 0x0036,
+	0x73d8, 0x2011, 0x8013, 0x080c, 0x4b7f, 0x003e, 0x7130, 0xc185,
+	0x7132, 0x2011, 0x1848, 0x220c, 0xd1a4, 0x01f0, 0x0016, 0x2009,
+	0x0001, 0x2011, 0x0100, 0x080c, 0x879a, 0x2019, 0x000e, 0x00c6,
+	0x2061, 0x0000, 0x080c, 0xe6ae, 0x00ce, 0x9484, 0x00ff, 0x9080,
+	0x3384, 0x200d, 0x918c, 0xff00, 0x810f, 0x2120, 0x9006, 0x2009,
+	0x000e, 0x080c, 0xe73a, 0x001e, 0x0016, 0x2009, 0x0002, 0x2019,
+	0x0004, 0x080c, 0x31e9, 0x001e, 0x0078, 0x0156, 0x00b6, 0x20a9,
+	0x007f, 0x900e, 0x080c, 0x6699, 0x1110, 0x080c, 0x60c7, 0x8108,
+	0x1f04, 0x2662, 0x00be, 0x015e, 0x00ce, 0x004e, 0x080c, 0xaeb4,
+	0x60e3, 0x0000, 0x001e, 0x2001, 0x1800, 0x2014, 0x9296, 0x0004,
+	0x1170, 0xd19c, 0x11a0, 0x2011, 0x180c, 0x2214, 0xd29c, 0x1120,
+	0x6204, 0x9295, 0x0002, 0x6206, 0x6228, 0xc29d, 0x622a, 0x2003,
+	0x0001, 0x2001, 0x1826, 0x2003, 0x0000, 0x6027, 0x0020, 0xd194,
+	0x0904, 0x277a, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2717, 0x080c,
+	0x8636, 0x080c, 0xa356, 0x6027, 0x0004, 0x00f6, 0x2019, 0x19ef,
+	0x2304, 0x907d, 0x0904, 0x26e6, 0x7804, 0x9086, 0x0032, 0x15f0,
+	0x00d6, 0x00c6, 0x00e6, 0x0096, 0x2069, 0x0140, 0x782c, 0x685e,
+	0x7808, 0x685a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0,
+	0x6043, 0x0000, 0x2001, 0x003c, 0x8001, 0x1df0, 0x080c, 0x2d5e,
+	0x2001, 0x001e, 0x8001, 0x0240, 0x20a9, 0x0009, 0x080c, 0x2c57,
+	0x6904, 0xd1dc, 0x1140, 0x0cb0, 0x2001, 0x0100, 0x080c, 0x2d4e,
+	0x9006, 0x080c, 0x2d4e, 0x080c, 0x9657, 0x080c, 0x9763, 0x7814,
+	0x2048, 0xa867, 0x0103, 0x2f60, 0x080c, 0xaf43, 0x009e, 0x00ee,
+	0x00ce, 0x00de, 0x00fe, 0x001e, 0x00ae, 0x0005, 0x00fe, 0x00d6,
+	0x2069, 0x0140, 0x6804, 0x9084, 0x4000, 0x0110, 0x080c, 0x2d5e,
+	0x00de, 0x00c6, 0x2061, 0x19e6, 0x6028, 0x080c, 0xd388, 0x0120,
+	0x909a, 0x0003, 0x1258, 0x0018, 0x909a, 0x00c8, 0x1238, 0x8000,
+	0x602a, 0x00ce, 0x080c, 0xa332, 0x0804, 0x2779, 0x2061, 0x0100,
+	0x62c0, 0x080c, 0xad3a, 0x2019, 0x19ef, 0x2304, 0x9065, 0x0120,
+	0x2009, 0x0027, 0x080c, 0xafbe, 0x00ce, 0x0804, 0x2779, 0xd2bc,
+	0x0904, 0x2760, 0x080c, 0x8643, 0x6014, 0x9084, 0x1984, 0x9085,
+	0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140, 0x6804,
+	0x9084, 0x4000, 0x0110, 0x080c, 0x2d5e, 0x00de, 0x00c6, 0x2061,
+	0x19e6, 0x6044, 0x080c, 0xd388, 0x0120, 0x909a, 0x0003, 0x1658,
+	0x0018, 0x909a, 0x00c8, 0x1638, 0x8000, 0x6046, 0x603c, 0x00ce,
+	0x9005, 0x05b8, 0x2009, 0x07d0, 0x080c, 0x863b, 0x9080, 0x0008,
+	0x2004, 0x9086, 0x0006, 0x1138, 0x6114, 0x918c, 0x1984, 0x918d,
+	0x0012, 0x6116, 0x0430, 0x9080, 0x0008, 0x2004, 0x9086, 0x0009,
+	0x0d98, 0x6114, 0x918c, 0x1984, 0x918d, 0x0016, 0x6116, 0x00c8,
+	0x6027, 0x0004, 0x00b0, 0x0036, 0x2019, 0x0001, 0x080c, 0xa6ac,
+	0x003e, 0x2019, 0x19f5, 0x2304, 0x9065, 0x0150, 0x2009, 0x004f,
+	0x6020, 0x9086, 0x0009, 0x1110, 0x2009, 0x004f, 0x080c, 0xafbe,
+	0x00ce, 0x001e, 0xd19c, 0x0904, 0x27e8, 0x7038, 0xd0ac, 0x1904,
+	0x27c1, 0x0016, 0x0156, 0x6027, 0x0008, 0x6050, 0x9085, 0x0040,
+	0x6052, 0x6050, 0x9084, 0xfbcf, 0x6052, 0x080c, 0x2c76, 0x9085,
+	0x2000, 0x6052, 0x20a9, 0x0012, 0x1d04, 0x2794, 0x080c, 0x866a,
+	0x1f04, 0x2794, 0x6050, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x6052,
+	0x20a9, 0x0028, 0xa001, 0x1f04, 0x27a2, 0x6150, 0x9185, 0x1400,
+	0x6052, 0x20a9, 0x0366, 0x1d04, 0x27ab, 0x080c, 0x866a, 0x6020,
+	0xd09c, 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0480,
+	0x080c, 0x2c3e, 0x1f04, 0x27ab, 0x015e, 0x6152, 0x001e, 0x6027,
+	0x0008, 0x0016, 0x6028, 0xc09c, 0x602a, 0x080c, 0xaeb4, 0x60e3,
+	0x0000, 0x080c, 0xeb79, 0x080c, 0xeb94, 0x080c, 0x5761, 0xd0fc,
+	0x1138, 0x080c, 0xd381, 0x1120, 0x9085, 0x0001, 0x080c, 0x7485,
+	0x9006, 0x080c, 0x2d4e, 0x2009, 0x0002, 0x080c, 0x2c7c, 0x2001,
+	0x1800, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c, 0x0bae, 0x001e,
+	0x918c, 0xffd0, 0x6126, 0x00ae, 0x0005, 0x0016, 0x2001, 0x188b,
+	0x200c, 0xd184, 0x001e, 0x0904, 0x259a, 0x0016, 0x2009, 0x27f9,
+	0x00d0, 0x2001, 0x188b, 0x200c, 0xc184, 0x2102, 0x001e, 0x0c40,
+	0x0016, 0x2001, 0x188b, 0x200c, 0xd194, 0x001e, 0x0904, 0x259a,
+	0x0016, 0x2009, 0x280c, 0x0038, 0x2001, 0x188b, 0x200c, 0xc194,
+	0x2102, 0x001e, 0x08a8, 0x6028, 0xc0bc, 0x602a, 0x2001, 0x0156,
+	0x2003, 0xbc91, 0x8000, 0x2003, 0xffff, 0x6043, 0x0001, 0x080c,
+	0x2c76, 0x6027, 0x0080, 0x6017, 0x0000, 0x6043, 0x0000, 0x0817,
+	0x0006, 0x0016, 0x0026, 0x0036, 0x00e6, 0x00f6, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x1800, 0x71d0, 0x70d2, 0x9116, 0x05e8, 0x81ff,
+	0x01a0, 0x2009, 0x0000, 0x080c, 0x2c7c, 0x2011, 0x8011, 0x2019,
+	0x010e, 0x231c, 0x939e, 0x0007, 0x1118, 0x2019, 0x0001, 0x0010,
+	0x2019, 0x0000, 0x080c, 0x4b7f, 0x0438, 0x2001, 0x19a7, 0x200c,
+	0x81ff, 0x1140, 0x2001, 0x0109, 0x2004, 0xd0b4, 0x0118, 0x2019,
+	0x0003, 0x0008, 0x2118, 0x2011, 0x8012, 0x080c, 0x4b7f, 0x080c,
+	0x5761, 0xd0fc, 0x1188, 0x080c, 0xd381, 0x1170, 0x00c6, 0x080c,
+	0x2910, 0x080c, 0xa613, 0x2061, 0x0100, 0x2019, 0x0028, 0x2009,
+	0x0002, 0x080c, 0x31e9, 0x00ce, 0x012e, 0x00fe, 0x00ee, 0x003e,
+	0x002e, 0x001e, 0x000e, 0x0005, 0x2028, 0x918c, 0x00ff, 0x2130,
+	0x9094, 0xff00, 0x11f0, 0x2011, 0x1837, 0x2214, 0xd2ac, 0x11c8,
+	0x81ff, 0x01e8, 0x2011, 0x181f, 0x2204, 0x9106, 0x1190, 0x2011,
+	0x1820, 0x2214, 0x9294, 0xff00, 0x9584, 0xff00, 0x9206, 0x1148,
+	0x2011, 0x1820, 0x2214, 0x9294, 0x00ff, 0x9584, 0x00ff, 0x9206,
+	0x1120, 0x2500, 0x080c, 0x8142, 0x0048, 0x9584, 0x00ff, 0x9080,
+	0x3384, 0x200d, 0x918c, 0xff00, 0x810f, 0x9006, 0x0005, 0x9080,
+	0x3384, 0x200d, 0x918c, 0x00ff, 0x0005, 0x00d6, 0x2069, 0x0140,
+	0x2001, 0x1818, 0x2003, 0x00ef, 0x20a9, 0x0010, 0x9006, 0x6852,
+	0x6856, 0x1f04, 0x28c0, 0x00de, 0x0005, 0x0006, 0x00d6, 0x0026,
+	0x2069, 0x0140, 0x2001, 0x1818, 0x2102, 0x8114, 0x8214, 0x8214,
+	0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0x9006, 0x82ff, 0x1128,
+	0x9184, 0x000f, 0x9080, 0xf346, 0x2005, 0x6856, 0x8211, 0x1f04,
+	0x28d5, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6, 0x2061, 0x1800,
+	0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032, 0x00ce, 0x0005,
+	0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069, 0x0140, 0x6980,
+	0x9116, 0x0180, 0x9112, 0x1230, 0x8212, 0x8210, 0x22a8, 0x2001,
+	0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e, 0x1f04, 0x2905,
+	0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de, 0x015e, 0x0005,
+	0x080c, 0x575d, 0xd0c4, 0x0150, 0xd0a4, 0x0140, 0x9006, 0x0046,
+	0x2020, 0x2009, 0x002e, 0x080c, 0xe73a, 0x004e, 0x0005, 0x00f6,
+	0x0016, 0x0026, 0x2079, 0x0140, 0x78c4, 0xd0dc, 0x0904, 0x297c,
+	0x080c, 0x2bdb, 0x0660, 0x9084, 0x0700, 0x908e, 0x0600, 0x1120,
+	0x2011, 0x4000, 0x900e, 0x0458, 0x908e, 0x0500, 0x1120, 0x2011,
+	0x8000, 0x900e, 0x0420, 0x908e, 0x0400, 0x1120, 0x9016, 0x2009,
+	0x0001, 0x00e8, 0x908e, 0x0300, 0x1120, 0x9016, 0x2009, 0x0002,
+	0x00b0, 0x908e, 0x0200, 0x1120, 0x9016, 0x2009, 0x0004, 0x0078,
+	0x908e, 0x0100, 0x1548, 0x9016, 0x2009, 0x0008, 0x0040, 0x9084,
+	0x0700, 0x908e, 0x0300, 0x1500, 0x2011, 0x0030, 0x0058, 0x2300,
+	0x9080, 0x0020, 0x2018, 0x080c, 0x9027, 0x928c, 0xff00, 0x0110,
+	0x2011, 0x00ff, 0x2200, 0x8007, 0x9085, 0x004c, 0x78c2, 0x2009,
+	0x0138, 0x220a, 0x080c, 0x743e, 0x1118, 0x2009, 0x196c, 0x220a,
+	0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126,
+	0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c,
+	0x8000, 0x2014, 0x9184, 0x0003, 0x0110, 0x080c, 0x0dce, 0x002e,
+	0x001e, 0x000e, 0x012e, 0x0005, 0x2001, 0x0171, 0x2004, 0xd0dc,
+	0x0168, 0x2001, 0x0170, 0x200c, 0x918c, 0x00ff, 0x918e, 0x004c,
+	0x1128, 0x200c, 0x918c, 0xff00, 0x810f, 0x0005, 0x900e, 0x2001,
+	0x0227, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004, 0x9108, 0x2001,
+	0x0226, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004, 0x9108, 0x0005,
+	0x0018, 0x000c, 0x0018, 0x0020, 0x1000, 0x0800, 0x1000, 0x1800,
+	0x0156, 0x0006, 0x0016, 0x0026, 0x00e6, 0x2001, 0x198f, 0x2004,
+	0x908a, 0x0007, 0x1a0c, 0x0dd5, 0x0033, 0x00ee, 0x002e, 0x001e,
+	0x000e, 0x015e, 0x0005, 0x29da, 0x29f8, 0x2a1c, 0x2a1e, 0x2a47,
+	0x2a49, 0x2a4b, 0x2001, 0x0001, 0x080c, 0x2828, 0x080c, 0x2c39,
+	0x2001, 0x1991, 0x2003, 0x0000, 0x7828, 0x9084, 0xe1d7, 0x782a,
+	0x9006, 0x20a9, 0x0009, 0x080c, 0x2bf7, 0x2001, 0x198f, 0x2003,
+	0x0006, 0x2009, 0x001e, 0x2011, 0x2a4c, 0x080c, 0x8648, 0x0005,
+	0x2009, 0x1994, 0x200b, 0x0000, 0x2001, 0x1999, 0x2003, 0x0036,
+	0x2001, 0x1998, 0x2003, 0x002a, 0x2001, 0x1991, 0x2003, 0x0001,
+	0x9006, 0x080c, 0x2ba9, 0x2001, 0xffff, 0x20a9, 0x0009, 0x080c,
+	0x2bf7, 0x2001, 0x198f, 0x2003, 0x0006, 0x2009, 0x001e, 0x2011,
+	0x2a4c, 0x080c, 0x8648, 0x0005, 0x080c, 0x0dd5, 0x2001, 0x1999,
+	0x2003, 0x0036, 0x2001, 0x1991, 0x2003, 0x0003, 0x7a38, 0x9294,
+	0x0005, 0x9296, 0x0004, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001,
+	0x080c, 0x2ba9, 0x2001, 0x1995, 0x2003, 0x0000, 0x2001, 0xffff,
+	0x20a9, 0x0009, 0x080c, 0x2bf7, 0x2001, 0x198f, 0x2003, 0x0006,
+	0x2009, 0x001e, 0x2011, 0x2a4c, 0x080c, 0x8648, 0x0005, 0x080c,
+	0x0dd5, 0x080c, 0x0dd5, 0x0005, 0x0006, 0x0016, 0x0026, 0x00e6,
+	0x00f6, 0x0156, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x2001,
+	0x1991, 0x2004, 0x908a, 0x0007, 0x1a0c, 0x0dd5, 0x0043, 0x012e,
+	0x015e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e, 0x0005, 0x2a6e,
+	0x2a8e, 0x2ace, 0x2afe, 0x2b22, 0x2b32, 0x2b34, 0x080c, 0x2beb,
+	0x11b0, 0x7850, 0x9084, 0xefff, 0x7852, 0x2009, 0x1997, 0x2104,
+	0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110, 0xc08d, 0x0008,
+	0xc085, 0x200a, 0x2001, 0x198f, 0x2003, 0x0001, 0x0030, 0x080c,
+	0x2b58, 0x2001, 0xffff, 0x080c, 0x29e9, 0x0005, 0x080c, 0x2b36,
+	0x05e0, 0x2009, 0x1998, 0x2104, 0x8001, 0x200a, 0x080c, 0x2beb,
+	0x1178, 0x7850, 0x9084, 0xefff, 0x7852, 0x7a38, 0x9294, 0x0005,
+	0x9296, 0x0005, 0x0518, 0x2009, 0x1997, 0x2104, 0xc085, 0x200a,
+	0x2009, 0x1994, 0x2104, 0x8000, 0x200a, 0x9086, 0x0005, 0x0118,
+	0x080c, 0x2b3e, 0x00c0, 0x200b, 0x0000, 0x7a38, 0x9294, 0x0006,
+	0x9296, 0x0004, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c,
+	0x2bc6, 0x2001, 0x1991, 0x2003, 0x0002, 0x0028, 0x2001, 0x198f,
+	0x2003, 0x0003, 0x0010, 0x080c, 0x2a0b, 0x0005, 0x080c, 0x2b36,
+	0x0560, 0x2009, 0x1998, 0x2104, 0x8001, 0x200a, 0x080c, 0x2beb,
+	0x1168, 0x7850, 0x9084, 0xefff, 0x7852, 0x2001, 0x198f, 0x2003,
+	0x0003, 0x2001, 0x1990, 0x2003, 0x0000, 0x00b8, 0x2009, 0x1998,
+	0x2104, 0x9005, 0x1118, 0x080c, 0x2b7b, 0x0010, 0x080c, 0x2b4b,
+	0x080c, 0x2b3e, 0x2009, 0x1994, 0x200b, 0x0000, 0x2001, 0x1991,
+	0x2003, 0x0001, 0x080c, 0x2a0b, 0x0000, 0x0005, 0x04b9, 0x0508,
+	0x080c, 0x2beb, 0x11b8, 0x7850, 0x9084, 0xefff, 0x7852, 0x2009,
+	0x1995, 0x2104, 0x8000, 0x200a, 0x9086, 0x0007, 0x0108, 0x0078,
+	0x2001, 0x199a, 0x2003, 0x000a, 0x2009, 0x1997, 0x2104, 0xc0fd,
+	0x200a, 0x0038, 0x0419, 0x2001, 0x1991, 0x2003, 0x0004, 0x080c,
+	0x2a36, 0x0005, 0x0099, 0x0168, 0x080c, 0x2beb, 0x1138, 0x7850,
+	0x9084, 0xefff, 0x7852, 0x080c, 0x2a22, 0x0018, 0x0079, 0x080c,
+	0x2a36, 0x0005, 0x080c, 0x0dd5, 0x080c, 0x0dd5, 0x2009, 0x1999,
+	0x2104, 0x8001, 0x200a, 0x090c, 0x2b97, 0x0005, 0x7a38, 0x9294,
+	0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001,
+	0x080c, 0x2bc6, 0x0005, 0x7a38, 0x9294, 0x0006, 0x9296, 0x0006,
+	0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c, 0x2ba9, 0x0005,
+	0x2009, 0x1994, 0x2104, 0x8000, 0x200a, 0x9086, 0x0005, 0x0108,
+	0x0068, 0x200b, 0x0000, 0x7a38, 0x9294, 0x0006, 0x9296, 0x0006,
+	0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x04d9, 0x7a38, 0x9294,
+	0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001,
+	0x080c, 0x2bc6, 0x0005, 0x0086, 0x2001, 0x1997, 0x2004, 0x9084,
+	0x7fff, 0x090c, 0x0dd5, 0x2009, 0x1996, 0x2144, 0x8846, 0x280a,
+	0x9844, 0x0dd8, 0xd08c, 0x1120, 0xd084, 0x1120, 0x080c, 0x0dd5,
+	0x9006, 0x0010, 0x2001, 0x0001, 0x00a1, 0x008e, 0x0005, 0x0006,
+	0x0156, 0x2001, 0x198f, 0x20a9, 0x0009, 0x2003, 0x0000, 0x8000,
+	0x1f04, 0x2b9d, 0x2001, 0x1996, 0x2003, 0x8000, 0x015e, 0x000e,
+	0x0005, 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000, 0x0158, 0x7838,
+	0x9084, 0xfff9, 0x9085, 0x0004, 0x783a, 0x2009, 0x199c, 0x210c,
+	0x795a, 0x0050, 0x7838, 0x9084, 0xfffb, 0x9085, 0x0006, 0x783a,
+	0x2009, 0x199d, 0x210c, 0x795a, 0x00fe, 0x0005, 0x00f6, 0x2079,
+	0x0100, 0x9085, 0x0000, 0x0138, 0x7838, 0x9084, 0xfffa, 0x9085,
+	0x0004, 0x783a, 0x0030, 0x7838, 0x9084, 0xfffb, 0x9085, 0x0005,
+	0x783a, 0x00fe, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, 0x9082,
+	0x0007, 0x000e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004, 0x9082,
+	0x0009, 0x000e, 0x0005, 0x0156, 0x20a9, 0x0064, 0x7820, 0x080c,
+	0x2c76, 0xd09c, 0x1110, 0x1f04, 0x2bee, 0x015e, 0x0005, 0x0126,
+	0x0016, 0x0006, 0x2091, 0x8000, 0x7850, 0x9085, 0x0040, 0x7852,
+	0x7850, 0x9084, 0xfbcf, 0x7852, 0x080c, 0x2c76, 0x9085, 0x2000,
+	0x7852, 0x000e, 0x2008, 0x9186, 0x0000, 0x1118, 0x783b, 0x0007,
+	0x0090, 0x9186, 0x0001, 0x1118, 0x783b, 0x0006, 0x0060, 0x9186,
+	0x0002, 0x1118, 0x783b, 0x0005, 0x0030, 0x9186, 0x0003, 0x1118,
+	0x783b, 0x0004, 0x0000, 0x0006, 0x1d04, 0x2c24, 0x080c, 0x866a,
+	0x1f04, 0x2c24, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x7852,
+	0x080c, 0x2c76, 0x9085, 0x1000, 0x7852, 0x000e, 0x001e, 0x012e,
+	0x0005, 0x7850, 0x9084, 0xffcf, 0x7852, 0x0005, 0x0006, 0x0156,
+	0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd0ac, 0x1130,
+	0x7820, 0xd0e4, 0x1140, 0x1f04, 0x2c48, 0x0028, 0x7854, 0xd08c,
+	0x1110, 0x1f04, 0x2c4e, 0x00fe, 0x015e, 0x000e, 0x0005, 0x1d04,
+	0x2c57, 0x080c, 0x866a, 0x1f04, 0x2c57, 0x0005, 0x0006, 0x2001,
+	0x199b, 0x2004, 0x9086, 0x0000, 0x000e, 0x0005, 0x0006, 0x2001,
+	0x199b, 0x2004, 0x9086, 0x0001, 0x000e, 0x0005, 0x0006, 0x2001,
+	0x199b, 0x2004, 0x9086, 0x0002, 0x000e, 0x0005, 0xa001, 0xa001,
+	0xa001, 0xa001, 0xa001, 0x0005, 0x0006, 0x2001, 0x19a7, 0x2102,
+	0x000e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc, 0x0140, 0x2009,
+	0x0170, 0x2104, 0x200b, 0x0080, 0xa001, 0xa001, 0x200a, 0x0005,
+	0x0036, 0x0046, 0x2001, 0x0141, 0x200c, 0x918c, 0xff00, 0x9186,
+	0x2100, 0x0140, 0x9186, 0x2000, 0x0170, 0x9186, 0x0100, 0x1904,
+	0x2cef, 0x0048, 0x0016, 0x2009, 0x1a82, 0x2104, 0x8000, 0x0208,
+	0x200a, 0x001e, 0x04f0, 0x2009, 0x00a2, 0x080c, 0x0e51, 0x2019,
+	0x0160, 0x2324, 0x2011, 0x0003, 0x2009, 0x0169, 0x2104, 0x9084,
+	0x0007, 0x210c, 0x918c, 0x0007, 0x910e, 0x1db0, 0x9086, 0x0003,
+	0x1548, 0x2304, 0x0066, 0x0076, 0x2031, 0x0002, 0x233c, 0x973e,
+	0x0148, 0x8631, 0x1dd8, 0x2031, 0x1a83, 0x263c, 0x8738, 0x0208,
+	0x2732, 0x2304, 0x007e, 0x006e, 0x9402, 0x02a0, 0x19d0, 0x8211,
+	0x19d8, 0x84ff, 0x0170, 0x2001, 0x0141, 0x200c, 0x918c, 0xff00,
+	0x9186, 0x0100, 0x0130, 0x2009, 0x180c, 0x2104, 0xc0dd, 0x200a,
+	0x0008, 0x0421, 0x2001, 0x1980, 0x200c, 0x080c, 0x0e51, 0x004e,
+	0x003e, 0x0005, 0x2001, 0x180c, 0x2004, 0xd0dc, 0x01b0, 0x2001,
+	0x0160, 0x2004, 0x9005, 0x0140, 0x2001, 0x0141, 0x2004, 0x9084,
+	0xff00, 0x9086, 0x0100, 0x1148, 0x0126, 0x2091, 0x8000, 0x0016,
+	0x0026, 0x0021, 0x002e, 0x001e, 0x012e, 0x0005, 0x00c6, 0x2061,
+	0x0100, 0x6014, 0x0006, 0x2001, 0x0161, 0x2003, 0x0000, 0x6017,
+	0x0018, 0xa001, 0xa001, 0x602f, 0x0008, 0x6104, 0x918e, 0x0010,
+	0x6106, 0x918e, 0x0010, 0x6106, 0x6017, 0x0040, 0x04b9, 0x001e,
+	0x9184, 0x0003, 0x01e0, 0x0036, 0x0016, 0x2019, 0x0141, 0x6124,
+	0x918c, 0x0028, 0x1120, 0x2304, 0x9084, 0x2800, 0x0dc0, 0x001e,
+	0x919c, 0xffe4, 0x9184, 0x0001, 0x0118, 0x9385, 0x0009, 0x6016,
+	0x9184, 0x0002, 0x0118, 0x9385, 0x0012, 0x6016, 0x003e, 0x2001,
+	0x180c, 0x200c, 0xc1dc, 0x2102, 0x00ce, 0x0005, 0x0016, 0x0026,
+	0x080c, 0x7458, 0x0108, 0xc0bc, 0x2009, 0x0140, 0x2114, 0x9294,
+	0x0001, 0x9215, 0x220a, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026,
+	0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9285, 0x1000, 0x200a,
+	0x220a, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026, 0x2009, 0x0140,
+	0x2114, 0x9294, 0x0001, 0x9215, 0x220a, 0x002e, 0x001e, 0x0005,
+	0x0006, 0x0016, 0x2009, 0x0140, 0x2104, 0x1128, 0x080c, 0x7458,
+	0x0110, 0xc0bc, 0x0008, 0xc0bd, 0x200a, 0x001e, 0x000e, 0x0005,
+	0x2ff4, 0x2ff4, 0x2e18, 0x2e18, 0x2e24, 0x2e24, 0x2e30, 0x2e30,
+	0x2e3e, 0x2e3e, 0x2e4a, 0x2e4a, 0x2e58, 0x2e58, 0x2e66, 0x2e66,
+	0x2e78, 0x2e78, 0x2e84, 0x2e84, 0x2e92, 0x2e92, 0x2eb0, 0x2eb0,
+	0x2ed0, 0x2ed0, 0x2ea0, 0x2ea0, 0x2ec0, 0x2ec0, 0x2ede, 0x2ede,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2ef0, 0x2ef0, 0x2efc, 0x2efc, 0x2f0a, 0x2f0a, 0x2f18, 0x2f18,
+	0x2f28, 0x2f28, 0x2f36, 0x2f36, 0x2f46, 0x2f46, 0x2f56, 0x2f56,
+	0x2f68, 0x2f68, 0x2f76, 0x2f76, 0x2f86, 0x2f86, 0x2fa8, 0x2fa8,
+	0x2fca, 0x2fca, 0x2f96, 0x2f96, 0x2fb9, 0x2fb9, 0x2fd9, 0x2fd9,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76, 0x2e76,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x24bf, 0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22d3, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x22d3, 0x080c, 0x24bf, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x230e,
+	0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x24bf, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x22d3, 0x080c, 0x230e, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22d3,
+	0x080c, 0x24bf, 0x080c, 0x230e, 0x0804, 0x2fec, 0xa001, 0x0cf0,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x1380, 0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x24bf, 0x080c, 0x1380,
+	0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x22d3, 0x080c, 0x1380, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x24bf, 0x080c, 0x1380, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x22d3, 0x080c, 0x24bf, 0x080c, 0x1380, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x22d3, 0x080c, 0x1380, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x1380, 0x080c, 0x230e, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22d3,
+	0x080c, 0x24bf, 0x080c, 0x1380, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x297f, 0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f, 0x080c, 0x24bf,
+	0x0804, 0x2fec, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x297f, 0x080c, 0x22d3, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x297f, 0x080c, 0x22d3, 0x080c, 0x24bf, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x297f, 0x080c, 0x230e, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x24bf, 0x080c, 0x230e, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x22d3, 0x080c, 0x230e, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x22d3, 0x080c, 0x24bf, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x297f, 0x080c, 0x1380, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x24bf, 0x080c, 0x1380, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x22d3, 0x080c, 0x1380, 0x0804, 0x2fec, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x297f,
+	0x080c, 0x24bf, 0x080c, 0x1380, 0x080c, 0x230e, 0x0804, 0x2fec,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x297f, 0x080c, 0x22d3, 0x080c, 0x24bf, 0x080c, 0x1380,
+	0x0498, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x297f, 0x080c, 0x22d3, 0x080c, 0x1380, 0x080c,
+	0x230e, 0x0410, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x297f, 0x080c, 0x1380, 0x080c, 0x230e,
+	0x0098, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x297f, 0x080c, 0x22d3, 0x080c, 0x24bf, 0x080c,
+	0x1380, 0x080c, 0x230e, 0x0000, 0x015e, 0x014e, 0x013e, 0x01de,
+	0x01ce, 0x012e, 0x000e, 0x010e, 0x000d, 0x00b6, 0x00c6, 0x0026,
+	0x0046, 0x9026, 0x080c, 0x69ca, 0x1904, 0x3105, 0x72dc, 0x2001,
+	0x197b, 0x2004, 0x9005, 0x1110, 0xd29c, 0x0148, 0xd284, 0x1138,
+	0xd2bc, 0x1904, 0x3105, 0x080c, 0x310a, 0x0804, 0x3105, 0xd2cc,
+	0x1904, 0x3105, 0x080c, 0x743e, 0x1120, 0x70af, 0xffff, 0x0804,
+	0x3105, 0xd294, 0x0120, 0x70af, 0xffff, 0x0804, 0x3105, 0x080c,
+	0x3373, 0x0160, 0x080c, 0xd388, 0x0128, 0x2001, 0x1818, 0x203c,
+	0x0804, 0x3092, 0x70af, 0xffff, 0x0804, 0x3105, 0x2001, 0x1818,
+	0x203c, 0x7294, 0xd284, 0x0904, 0x3092, 0xd28c, 0x1904, 0x3092,
+	0x0036, 0x73ac, 0x938e, 0xffff, 0x1110, 0x2019, 0x0001, 0x8314,
+	0x92e0, 0x1c80, 0x2c04, 0x938c, 0x0001, 0x0120, 0x9084, 0xff00,
+	0x8007, 0x0010, 0x9084, 0x00ff, 0x970e, 0x05d0, 0x908e, 0x0000,
+	0x05b8, 0x908e, 0x00ff, 0x1150, 0x7230, 0xd284, 0x15b0, 0x7294,
+	0xc28d, 0x7296, 0x70af, 0xffff, 0x003e, 0x04a0, 0x900e, 0x080c,
+	0x287c, 0x080c, 0x6638, 0x1538, 0x9006, 0xb8bb, 0x0520, 0xb8ac,
+	0x9005, 0x0148, 0x00c6, 0x2060, 0x080c, 0x8a3d, 0x00ce, 0x090c,
+	0x8dda, 0xb8af, 0x0000, 0x080c, 0x6a0c, 0x1168, 0x7030, 0xd08c,
+	0x0130, 0xb800, 0xd0bc, 0x0138, 0x080c, 0x68b9, 0x0120, 0x080c,
+	0x3123, 0x0148, 0x0028, 0x080c, 0x3263, 0x080c, 0x314f, 0x0118,
+	0x8318, 0x0804, 0x303f, 0x73ae, 0x0010, 0x70af, 0xffff, 0x003e,
+	0x0804, 0x3105, 0x9780, 0x3384, 0x203d, 0x97bc, 0xff00, 0x873f,
+	0x2041, 0x007e, 0x70ac, 0x9096, 0xffff, 0x1118, 0x900e, 0x28a8,
+	0x0050, 0x9812, 0x0220, 0x2008, 0x9802, 0x20a8, 0x0020, 0x70af,
+	0xffff, 0x0804, 0x3105, 0x2700, 0x0156, 0x0016, 0x9106, 0x0904,
+	0x30fa, 0xc484, 0x080c, 0x6699, 0x0148, 0x080c, 0xd388, 0x1904,
+	0x30fa, 0x080c, 0x6638, 0x1904, 0x3102, 0x0008, 0xc485, 0xb8bb,
+	0x0520, 0xb8ac, 0x9005, 0x0148, 0x00c6, 0x2060, 0x080c, 0x8a3d,
+	0x00ce, 0x090c, 0x8dda, 0xb8af, 0x0000, 0x080c, 0x6a0c, 0x1130,
+	0x7030, 0xd08c, 0x01f8, 0xb800, 0xd0bc, 0x11e0, 0x7294, 0xd28c,
+	0x0180, 0x080c, 0x6a0c, 0x9082, 0x0006, 0x02e0, 0xd484, 0x1118,
+	0x080c, 0x665d, 0x0028, 0x080c, 0x32ef, 0x01a0, 0x080c, 0x331a,
+	0x0088, 0x080c, 0x3263, 0x080c, 0xd388, 0x1160, 0x080c, 0x314f,
+	0x0188, 0x0040, 0x080c, 0xd388, 0x1118, 0x080c, 0x32ef, 0x0110,
+	0x0451, 0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x30ab, 0x70af,
+	0xffff, 0x0018, 0x001e, 0x015e, 0x71ae, 0x004e, 0x002e, 0x00ce,
+	0x00be, 0x0005, 0x00c6, 0x0016, 0x70af, 0x0001, 0x2009, 0x007e,
+	0x080c, 0x6638, 0x1168, 0xb813, 0x00ff, 0xb817, 0xfffe, 0x080c,
+	0x3263, 0x04a9, 0x0128, 0x70dc, 0xc0bd, 0x70de, 0x080c, 0xd0d9,
+	0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2001,
+	0x184c, 0x2004, 0x9084, 0x00ff, 0xb842, 0x080c, 0xaf91, 0x01d0,
+	0x2b00, 0x6012, 0x080c, 0xd102, 0x6023, 0x0001, 0x9006, 0x080c,
+	0x65d5, 0x2001, 0x0000, 0x080c, 0x65e9, 0x0126, 0x2091, 0x8000,
+	0x70a8, 0x8000, 0x70aa, 0x012e, 0x2009, 0x0004, 0x080c, 0xafbe,
+	0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x0016,
+	0x0076, 0x00d6, 0x00c6, 0x2001, 0x184c, 0x2004, 0x9084, 0x00ff,
+	0xb842, 0x080c, 0xaf91, 0x0548, 0x2b00, 0x6012, 0xb800, 0xc0c4,
+	0xb802, 0xb8a0, 0x9086, 0x007e, 0x0140, 0xb804, 0x9084, 0x00ff,
+	0x9086, 0x0006, 0x1110, 0x080c, 0x321e, 0x080c, 0xd102, 0x6023,
+	0x0001, 0x9006, 0x080c, 0x65d5, 0x2001, 0x0002, 0x080c, 0x65e9,
+	0x0126, 0x2091, 0x8000, 0x70a8, 0x8000, 0x70aa, 0x012e, 0x2009,
+	0x0002, 0x080c, 0xafbe, 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e,
+	0x001e, 0x0005, 0x00b6, 0x00c6, 0x0026, 0x2009, 0x0080, 0x080c,
+	0x6638, 0x1140, 0xb813, 0x00ff, 0xb817, 0xfffc, 0x0039, 0x0110,
+	0x70e3, 0xffff, 0x002e, 0x00ce, 0x00be, 0x0005, 0x0016, 0x0076,
+	0x00d6, 0x00c6, 0x080c, 0xaeed, 0x01d0, 0x2b00, 0x6012, 0x080c,
+	0xd102, 0x6023, 0x0001, 0x9006, 0x080c, 0x65d5, 0x2001, 0x0002,
+	0x080c, 0x65e9, 0x0126, 0x2091, 0x8000, 0x70e4, 0x8000, 0x70e6,
+	0x012e, 0x2009, 0x0002, 0x080c, 0xafbe, 0x9085, 0x0001, 0x00ce,
+	0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x2009, 0x007f, 0x080c, 0x6638, 0x11b8, 0xb813, 0x00ff,
+	0xb817, 0xfffd, 0xb8cf, 0x0004, 0x080c, 0xaeed, 0x0170, 0x2b00,
+	0x6012, 0x6316, 0x6023, 0x0001, 0x620a, 0x080c, 0xd102, 0x2009,
+	0x0022, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e, 0x00de, 0x00ce,
+	0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036, 0x0026, 0x00b6, 0x21f0,
+	0x080c, 0x9361, 0x080c, 0x92e1, 0x080c, 0xad81, 0x080c, 0xbe6b,
+	0x3e08, 0x2130, 0x81ff, 0x0120, 0x20a9, 0x007e, 0x900e, 0x0018,
+	0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x6699, 0x1140, 0x9686,
+	0x0002, 0x1118, 0xb800, 0xd0bc, 0x1110, 0x080c, 0x60c7, 0x001e,
+	0x8108, 0x1f04, 0x3203, 0x9686, 0x0001, 0x190c, 0x3347, 0x00be,
+	0x002e, 0x003e, 0x006e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6,
+	0x0046, 0x0036, 0x0026, 0x0016, 0x00b6, 0x6210, 0x2258, 0xbaa0,
+	0x0026, 0x2019, 0x0029, 0x080c, 0x9356, 0x0076, 0x2039, 0x0000,
+	0x080c, 0x9229, 0x2c08, 0x080c, 0xe477, 0x007e, 0x001e, 0xba10,
+	0xbb14, 0xbcc0, 0x080c, 0x60c7, 0xba12, 0xbb16, 0xbcc2, 0x00be,
+	0x001e, 0x002e, 0x003e, 0x004e, 0x00ce, 0x00ee, 0x0005, 0x00e6,
+	0x0006, 0x00b6, 0x6010, 0x2058, 0xb8a0, 0x00be, 0x9086, 0x0080,
+	0x0150, 0x2071, 0x1800, 0x70a8, 0x9005, 0x0110, 0x8001, 0x70aa,
+	0x000e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x70e4, 0x9005, 0x0dc0,
+	0x8001, 0x70e6, 0x0ca8, 0xb800, 0xc08c, 0xb802, 0x0005, 0x00f6,
+	0x00e6, 0x00c6, 0x00b6, 0x0046, 0x0036, 0x0026, 0x0016, 0x0156,
+	0x2178, 0x81ff, 0x1118, 0x20a9, 0x0001, 0x0078, 0x080c, 0x575d,
+	0xd0c4, 0x0140, 0xd0a4, 0x0130, 0x9006, 0x2020, 0x2009, 0x002d,
+	0x080c, 0xe73a, 0x20a9, 0x0800, 0x9016, 0x0026, 0x928e, 0x007e,
+	0x0904, 0x32ce, 0x928e, 0x007f, 0x0904, 0x32ce, 0x928e, 0x0080,
+	0x05e8, 0x9288, 0x1000, 0x210c, 0x81ff, 0x05c0, 0x8fff, 0x1148,
+	0x2001, 0x198d, 0x0006, 0x2003, 0x0001, 0x04f1, 0x000e, 0x2003,
+	0x0000, 0x00b6, 0x00c6, 0x2158, 0x2001, 0x0001, 0x080c, 0x69d6,
+	0x00ce, 0x00be, 0x2019, 0x0029, 0x080c, 0x9356, 0x0076, 0x2039,
+	0x0000, 0x080c, 0x9229, 0x00b6, 0x00c6, 0x0026, 0x2158, 0xba04,
+	0x9294, 0x00ff, 0x9286, 0x0006, 0x1118, 0xb807, 0x0404, 0x0028,
+	0x2001, 0x0004, 0x8007, 0x9215, 0xba06, 0x002e, 0x00ce, 0x00be,
+	0x0016, 0x2c08, 0x080c, 0xe477, 0x001e, 0x007e, 0x002e, 0x8210,
+	0x1f04, 0x3285, 0x015e, 0x001e, 0x002e, 0x003e, 0x004e, 0x00be,
+	0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x080c,
+	0x575d, 0xd0c4, 0x0140, 0xd0a4, 0x0130, 0x9006, 0x2220, 0x2009,
+	0x0029, 0x080c, 0xe73a, 0x001e, 0x002e, 0x004e, 0x0005, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x7294, 0x82ff, 0x01e8, 0x080c, 0x6a04,
+	0x11d0, 0x2100, 0x080c, 0x28af, 0x81ff, 0x01b8, 0x2019, 0x0001,
+	0x8314, 0x92e0, 0x1c80, 0x2c04, 0xd384, 0x0120, 0x9084, 0xff00,
+	0x8007, 0x0010, 0x9084, 0x00ff, 0x9116, 0x0138, 0x9096, 0x00ff,
+	0x0110, 0x8318, 0x0c68, 0x9085, 0x0001, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x0005, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x0036,
+	0x2019, 0x0029, 0x00a9, 0x003e, 0x9180, 0x1000, 0x2004, 0x9065,
+	0x0158, 0x0016, 0x00c6, 0x2061, 0x1ab2, 0x001e, 0x6112, 0x080c,
+	0x321e, 0x001e, 0x080c, 0x665d, 0x012e, 0x00ce, 0x001e, 0x0005,
+	0x0016, 0x0026, 0x2110, 0x080c, 0xa8dc, 0x080c, 0xeaa3, 0x002e,
+	0x001e, 0x0005, 0x2001, 0x1837, 0x2004, 0xd0cc, 0x0005, 0x00c6,
+	0x00b6, 0x080c, 0x743e, 0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9,
+	0x0782, 0x080c, 0x743e, 0x1110, 0x900e, 0x0010, 0x2009, 0x007e,
+	0x9180, 0x1000, 0x2004, 0x905d, 0x0130, 0x86ff, 0x0110, 0xb800,
+	0xd0bc, 0x090c, 0x665d, 0x8108, 0x1f04, 0x3358, 0x2061, 0x1800,
+	0x607f, 0x0000, 0x6080, 0x9084, 0x00ff, 0x6082, 0x60b3, 0x0000,
+	0x00be, 0x00ce, 0x0005, 0x2001, 0x1869, 0x2004, 0xd0bc, 0x0005,
+	0x2011, 0x1848, 0x2214, 0xd2ec, 0x0005, 0x0026, 0x2011, 0x1867,
+	0x2214, 0xd2dc, 0x002e, 0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2,
+	0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4,
+	0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca,
+	0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9,
+	0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad,
+	0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3,
+	0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797, 0x6690, 0x658f,
+	0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c, 0x607a, 0x8079,
+	0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d,
+	0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863,
+	0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454, 0x5353, 0x5252,
+	0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047,
+	0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039, 0x8036, 0x4b35,
+	0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d, 0x462c, 0x452b,
+	0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e,
+	0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004,
+	0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700, 0x3600, 0x8000,
+	0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000, 0x8000, 0x2f00,
+	0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00,
+	0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700, 0x2600, 0x2500,
+	0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100, 0x2000, 0x1f00,
+	0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000,
+	0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x1800,
+	0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400, 0x1300, 0x1200,
+	0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00,
+	0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800, 0x0700, 0x8000,
+	0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400, 0x0300, 0x8000,
+	0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0x189e, 0x7003, 0x0002,
+	0x9006, 0x7016, 0x701a, 0x704a, 0x704e, 0x700e, 0x7042, 0x7046,
+	0x703b, 0x18ba, 0x703f, 0x18ba, 0x7007, 0x0001, 0x080c, 0x1018,
+	0x090c, 0x0dd5, 0x2900, 0x706a, 0xa867, 0x0002, 0xa8ab, 0xdcb0,
+	0x080c, 0x1018, 0x090c, 0x0dd5, 0x2900, 0x706e, 0xa867, 0x0002,
+	0xa8ab, 0xdcb0, 0x0005, 0x2071, 0x189e, 0x7004, 0x0002, 0x34b3,
+	0x34b4, 0x34c7, 0x34db, 0x0005, 0x1004, 0x34c4, 0x0e04, 0x34c4,
+	0x2079, 0x0000, 0x0126, 0x2091, 0x8000, 0x700c, 0x9005, 0x1128,
+	0x700f, 0x0001, 0x012e, 0x0468, 0x0005, 0x012e, 0x0ce8, 0x2079,
+	0x0000, 0x2061, 0x18b8, 0x2c4c, 0xa86c, 0x908e, 0x0100, 0x0128,
+	0x9086, 0x0200, 0x0904, 0x35af, 0x0005, 0x7018, 0x2048, 0x2061,
+	0x1800, 0x701c, 0x0807, 0x7014, 0x2048, 0xa864, 0x9094, 0x00ff,
+	0x9296, 0x0029, 0x1120, 0xaa78, 0xd2fc, 0x0128, 0x0005, 0x9086,
+	0x0103, 0x0108, 0x0005, 0x2079, 0x0000, 0x2061, 0x1800, 0x701c,
+	0x0807, 0x2061, 0x1800, 0x7880, 0x908a, 0x0040, 0x1210, 0x61d0,
+	0x0042, 0x2100, 0x908a, 0x003f, 0x1a04, 0x35ac, 0x61d0, 0x0804,
+	0x3541, 0x3583, 0x35bb, 0x35ac, 0x35c5, 0x35cf, 0x35d5, 0x35d9,
+	0x35e9, 0x35ed, 0x3603, 0x3609, 0x360f, 0x361a, 0x3625, 0x3634,
+	0x3643, 0x3651, 0x3668, 0x3683, 0x35ac, 0x372c, 0x376a, 0x3810,
+	0x3821, 0x3844, 0x35ac, 0x35ac, 0x35ac, 0x387c, 0x3898, 0x38a1,
+	0x38d0, 0x38d6, 0x35ac, 0x391c, 0x35ac, 0x35ac, 0x35ac, 0x35ac,
+	0x35ac, 0x3927, 0x3930, 0x3938, 0x393a, 0x35ac, 0x35ac, 0x35ac,
+	0x35ac, 0x35ac, 0x35ac, 0x3966, 0x35ac, 0x35ac, 0x35ac, 0x35ac,
+	0x35ac, 0x3983, 0x39e4, 0x35ac, 0x35ac, 0x35ac, 0x35ac, 0x35ac,
+	0x35ac, 0x0002, 0x3a0e, 0x3a11, 0x3a70, 0x3a89, 0x3ab9, 0x3d57,
+	0x35ac, 0x5321, 0x35ac, 0x35ac, 0x35ac, 0x35ac, 0x35ac, 0x35ac,
+	0x35ac, 0x35ac, 0x3603, 0x3609, 0x4278, 0x5781, 0x4296, 0x53b0,
+	0x5401, 0x550c, 0x35ac, 0x556e, 0x55aa, 0x55db, 0x56e3, 0x5608,
+	0x5663, 0x35ac, 0x429a, 0x445b, 0x4471, 0x4496, 0x44fb, 0x456f,
+	0x458f, 0x4606, 0x4662, 0x46be, 0x46c1, 0x46e6, 0x4791, 0x47f7,
+	0x47ff, 0x4931, 0x4aa9, 0x4add, 0x4d41, 0x35ac, 0x4d5f, 0x4e05,
+	0x4ee7, 0x4f41, 0x35ac, 0x4ff8, 0x35ac, 0x5060, 0x507b, 0x47ff,
+	0x52c1, 0x714c, 0x0000, 0x2021, 0x4000, 0x080c, 0x4b5b, 0x0126,
+	0x2091, 0x8000, 0x0e04, 0x358d, 0x0010, 0x012e, 0x0cc0, 0x7c36,
+	0x9486, 0x4000, 0x0118, 0x7833, 0x0011, 0x0010, 0x7833, 0x0010,
+	0x7c82, 0x7986, 0x7a8a, 0x7b8e, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x190c, 0x119b, 0x7007, 0x0001, 0x2091, 0x5000,
+	0x700f, 0x0000, 0x012e, 0x0005, 0x2021, 0x4001, 0x08b0, 0x2021,
+	0x4002, 0x0898, 0x2021, 0x4003, 0x0880, 0x2021, 0x4005, 0x0868,
+	0x2021, 0x4006, 0x0850, 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88,
+	0x7a8c, 0x7884, 0x7990, 0x0804, 0x4b68, 0x2039, 0x0001, 0x902e,
+	0x2520, 0x7b88, 0x7a8c, 0x7884, 0x7990, 0x0804, 0x4b6b, 0x7984,
+	0x7888, 0x2114, 0x200a, 0x0804, 0x3583, 0x7984, 0x2114, 0x0804,
+	0x3583, 0x20e1, 0x0000, 0x2099, 0x0021, 0x20e9, 0x0000, 0x20a1,
+	0x0021, 0x20a9, 0x001f, 0x4003, 0x7984, 0x7a88, 0x7b8c, 0x0804,
+	0x3583, 0x7884, 0x2060, 0x0804, 0x3636, 0x2009, 0x0003, 0x2011,
+	0x0003, 0x2019, 0x0008, 0x789b, 0x0137, 0x7893, 0xffff, 0x2001,
+	0x188f, 0x2004, 0x9005, 0x0118, 0x7896, 0x0804, 0x3583, 0x7897,
+	0x0001, 0x0804, 0x3583, 0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0804,
+	0x35bf, 0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0804, 0x35c9, 0x79a0,
+	0x9182, 0x0040, 0x0210, 0x0804, 0x35b8, 0x2138, 0x7d98, 0x7c9c,
+	0x0804, 0x35bf, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x35b8,
+	0x2138, 0x7d98, 0x7c9c, 0x0804, 0x35c9, 0x79a0, 0x9182, 0x0040,
+	0x0210, 0x0804, 0x35b8, 0x21e8, 0x7984, 0x7888, 0x20a9, 0x0001,
+	0x21a0, 0x4004, 0x0804, 0x3583, 0x2061, 0x0800, 0xe10c, 0x9006,
+	0x2c15, 0x9200, 0x8c60, 0x8109, 0x1dd8, 0x2010, 0x9005, 0x0904,
+	0x3583, 0x0804, 0x35b2, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804,
+	0x35b8, 0x21e0, 0x20a9, 0x0001, 0x7984, 0x2198, 0x4012, 0x0804,
+	0x3583, 0x2069, 0x1847, 0x7884, 0x7990, 0x911a, 0x1a04, 0x35b8,
+	0x8019, 0x0904, 0x35b8, 0x684a, 0x6942, 0x788c, 0x6852, 0x7888,
+	0x6856, 0x9006, 0x685a, 0x685e, 0x080c, 0x7755, 0x0804, 0x3583,
+	0x2069, 0x1847, 0x7884, 0x7994, 0x911a, 0x1a04, 0x35b8, 0x8019,
+	0x0904, 0x35b8, 0x684e, 0x6946, 0x788c, 0x6862, 0x7888, 0x6866,
+	0x9006, 0x686a, 0x686e, 0x0126, 0x2091, 0x8000, 0x080c, 0x6a72,
+	0x012e, 0x0804, 0x3583, 0x902e, 0x2520, 0x81ff, 0x0120, 0x2009,
+	0x0001, 0x0804, 0x35b5, 0x7984, 0x7b88, 0x7a8c, 0x20a9, 0x0005,
+	0x20e9, 0x0001, 0x20a1, 0x18a6, 0x4101, 0x080c, 0x4b1f, 0x1120,
+	0x2009, 0x0002, 0x0804, 0x35b5, 0x2009, 0x0020, 0xa85c, 0x9080,
+	0x0019, 0xaf60, 0x080c, 0x4b68, 0x701f, 0x36a7, 0x0005, 0xa864,
+	0x2008, 0x9084, 0x00ff, 0x9096, 0x0011, 0x0168, 0x9096, 0x0019,
+	0x0150, 0x9096, 0x0015, 0x0138, 0x9096, 0x0048, 0x0120, 0x9096,
+	0x0029, 0x1904, 0x35b5, 0x810f, 0x918c, 0x00ff, 0x0904, 0x35b5,
+	0x7112, 0x7010, 0x8001, 0x0560, 0x7012, 0x080c, 0x4b1f, 0x1120,
+	0x2009, 0x0002, 0x0804, 0x35b5, 0x2009, 0x0020, 0x7068, 0x2040,
+	0xa28c, 0xa390, 0xa494, 0xa598, 0x9290, 0x0040, 0x9399, 0x0000,
+	0x94a1, 0x0000, 0x95a9, 0x0000, 0xa85c, 0x9080, 0x0019, 0xaf60,
+	0x080c, 0x4b68, 0x701f, 0x36e5, 0x0005, 0xa864, 0x9084, 0x00ff,
+	0x9096, 0x0002, 0x0120, 0x9096, 0x000a, 0x1904, 0x35b5, 0x0888,
+	0x7014, 0x2048, 0xa868, 0xc0fd, 0xa86a, 0xa864, 0x9084, 0x00ff,
+	0x9096, 0x0029, 0x1160, 0xc2fd, 0xaa7a, 0x080c, 0x621e, 0x0150,
+	0x0126, 0x2091, 0x8000, 0xa87a, 0xa982, 0x012e, 0x0050, 0x080c,
+	0x654e, 0x1128, 0x7007, 0x0003, 0x701f, 0x3711, 0x0005, 0x080c,
+	0x6f4a, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x20e1, 0x0001,
+	0x2099, 0x18a6, 0x400a, 0x2100, 0x9210, 0x9399, 0x0000, 0x94a1,
+	0x0000, 0x95a9, 0x0000, 0xa85c, 0x9080, 0x0019, 0x2009, 0x0020,
+	0x012e, 0xaf60, 0x0804, 0x4b6b, 0x2091, 0x8000, 0x7837, 0x4000,
+	0x7833, 0x0010, 0x7883, 0x4000, 0x7887, 0x4953, 0x788b, 0x5020,
+	0x788f, 0x2020, 0x2009, 0x017f, 0x2104, 0x7892, 0x3f00, 0x7896,
+	0x2061, 0x0100, 0x6200, 0x2061, 0x0200, 0x603c, 0x8007, 0x9205,
+	0x789a, 0x2009, 0x04fd, 0x2104, 0x789e, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x0180, 0x2001, 0x1a18,
+	0x2004, 0x9005, 0x0128, 0x2001, 0x008b, 0x2004, 0xd0fc, 0x0dd8,
+	0x2001, 0x008a, 0x2003, 0x0002, 0x2003, 0x1001, 0x2071, 0x0080,
+	0x0804, 0x0427, 0x81ff, 0x1904, 0x35b5, 0x7984, 0x080c, 0x6699,
+	0x1904, 0x35b8, 0x7e98, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04,
+	0x35b8, 0x7c88, 0x7d8c, 0x080c, 0x67fc, 0x080c, 0x67cb, 0x0000,
+	0x1518, 0x2061, 0x1cd0, 0x0126, 0x2091, 0x8000, 0x6000, 0x9086,
+	0x0000, 0x0148, 0x6014, 0x904d, 0x0130, 0xa86c, 0x9406, 0x1118,
+	0xa870, 0x9506, 0x0150, 0x012e, 0x9ce0, 0x0018, 0x2001, 0x181a,
+	0x2004, 0x9c02, 0x1a04, 0x35b5, 0x0c30, 0x080c, 0xc8a5, 0x012e,
+	0x0904, 0x35b5, 0x0804, 0x3583, 0x900e, 0x2001, 0x0005, 0x080c,
+	0x6f4a, 0x0126, 0x2091, 0x8000, 0x080c, 0xcf82, 0x080c, 0x6d17,
+	0x012e, 0x0804, 0x3583, 0x00a6, 0x2950, 0xb198, 0x080c, 0x6699,
+	0x1904, 0x37fd, 0xb6a4, 0x9684, 0x3fff, 0x9082, 0x4000, 0x16e8,
+	0xb49c, 0xb5a0, 0x080c, 0x67fc, 0x080c, 0x67cb, 0x1520, 0x2061,
+	0x1cd0, 0x0126, 0x2091, 0x8000, 0x6000, 0x9086, 0x0000, 0x0148,
+	0x6014, 0x904d, 0x0130, 0xa86c, 0x9406, 0x1118, 0xa870, 0x9506,
+	0x0158, 0x012e, 0x9ce0, 0x0018, 0x2001, 0x181a, 0x2004, 0x9c02,
+	0x2009, 0x000d, 0x12b0, 0x0c28, 0x080c, 0xc8a5, 0x012e, 0x2009,
+	0x0003, 0x0178, 0x00e0, 0x900e, 0x2001, 0x0005, 0x080c, 0x6f4a,
+	0x0126, 0x2091, 0x8000, 0x080c, 0xcf82, 0x080c, 0x6d0b, 0x012e,
+	0x0070, 0xb097, 0x4005, 0xb19a, 0x0010, 0xb097, 0x4006, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0030, 0x2a48, 0x00ae, 0x0005, 0xb097,
+	0x4000, 0x9006, 0x918d, 0x0001, 0x2008, 0x2a48, 0x00ae, 0x0005,
+	0x81ff, 0x1904, 0x35b5, 0x080c, 0x4b36, 0x0904, 0x35b8, 0x080c,
+	0x6760, 0x0904, 0x35b5, 0x080c, 0x6802, 0x0904, 0x35b5, 0x0804,
+	0x4586, 0x81ff, 0x1904, 0x35b5, 0x080c, 0x4b52, 0x0904, 0x35b8,
+	0x080c, 0x6890, 0x0904, 0x35b5, 0x2019, 0x0005, 0x79a8, 0x080c,
+	0x681d, 0x0904, 0x35b5, 0x7888, 0x908a, 0x1000, 0x1a04, 0x35b8,
+	0x8003, 0x800b, 0x810b, 0x9108, 0x080c, 0x85be, 0x7984, 0xd184,
+	0x1904, 0x3583, 0x0804, 0x4586, 0x0126, 0x2091, 0x8000, 0x81ff,
+	0x0118, 0x2009, 0x0001, 0x0450, 0x2029, 0x07ff, 0x645c, 0x2400,
+	0x9506, 0x01f8, 0x2508, 0x080c, 0x6699, 0x11d8, 0x080c, 0x6890,
+	0x1128, 0x2009, 0x0002, 0x62c0, 0x2518, 0x00c0, 0x2019, 0x0004,
+	0x900e, 0x080c, 0x681d, 0x1118, 0x2009, 0x0006, 0x0078, 0x7884,
+	0x908a, 0x1000, 0x1270, 0x8003, 0x800b, 0x810b, 0x9108, 0x080c,
+	0x85be, 0x8529, 0x1ae0, 0x012e, 0x0804, 0x3583, 0x012e, 0x0804,
+	0x35b5, 0x012e, 0x0804, 0x35b8, 0x080c, 0x4b36, 0x0904, 0x35b8,
+	0x080c, 0x6760, 0x0904, 0x35b5, 0xbaa0, 0x2019, 0x0005, 0x00c6,
+	0x9066, 0x080c, 0x9356, 0x0076, 0x903e, 0x080c, 0x9229, 0x900e,
+	0x080c, 0xe477, 0x007e, 0x00ce, 0x080c, 0x67fc, 0x0804, 0x3583,
+	0x080c, 0x4b36, 0x0904, 0x35b8, 0x080c, 0x67fc, 0x2208, 0x0804,
+	0x3583, 0x0156, 0x00d6, 0x00e6, 0x2069, 0x1910, 0x6810, 0x6914,
+	0x910a, 0x1208, 0x900e, 0x6816, 0x9016, 0x901e, 0x20a9, 0x007e,
+	0x2069, 0x1000, 0x2d04, 0x905d, 0x0118, 0xb84c, 0x0059, 0x9210,
+	0x8d68, 0x1f04, 0x38b2, 0x2300, 0x9218, 0x00ee, 0x00de, 0x015e,
+	0x0804, 0x3583, 0x00f6, 0x0016, 0x907d, 0x0138, 0x9006, 0x8000,
+	0x2f0c, 0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005,
+	0x2069, 0x1910, 0x6910, 0x62bc, 0x0804, 0x3583, 0x81ff, 0x0120,
+	0x2009, 0x0001, 0x0804, 0x35b5, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x5771, 0x0128, 0x2009, 0x0007, 0x012e, 0x0804, 0x35b5, 0x012e,
+	0x615c, 0x9190, 0x3384, 0x2215, 0x9294, 0x00ff, 0x637c, 0x83ff,
+	0x0108, 0x6280, 0x67dc, 0x97c4, 0x000a, 0x98c6, 0x000a, 0x1118,
+	0x2031, 0x0001, 0x00e8, 0x97c4, 0x0022, 0x98c6, 0x0022, 0x1118,
+	0x2031, 0x0003, 0x00a8, 0x97c4, 0x0012, 0x98c6, 0x0012, 0x1118,
+	0x2031, 0x0002, 0x0068, 0x080c, 0x743e, 0x1118, 0x2031, 0x0004,
+	0x0038, 0xd79c, 0x0120, 0x2009, 0x0005, 0x0804, 0x35b5, 0x9036,
+	0x7e9a, 0x7f9e, 0x0804, 0x3583, 0x614c, 0x6250, 0x2019, 0x1985,
+	0x231c, 0x2001, 0x1986, 0x2004, 0x789a, 0x0804, 0x3583, 0x0126,
+	0x2091, 0x8000, 0x6138, 0x623c, 0x6340, 0x012e, 0x0804, 0x3583,
+	0x080c, 0x4b52, 0x0904, 0x35b8, 0xba44, 0xbb38, 0x0804, 0x3583,
+	0x080c, 0x0dd5, 0x080c, 0x4b52, 0x2110, 0x0904, 0x35b8, 0xb804,
+	0x908c, 0x00ff, 0x918e, 0x0006, 0x0140, 0x9084, 0xff00, 0x9086,
+	0x0600, 0x2009, 0x0009, 0x1904, 0x35b5, 0x0126, 0x2091, 0x8000,
+	0x2019, 0x0005, 0x00c6, 0x9066, 0x080c, 0xa8dc, 0x080c, 0x9356,
+	0x0076, 0x903e, 0x080c, 0x9229, 0x900e, 0x080c, 0xe477, 0x007e,
+	0x00ce, 0xb807, 0x0407, 0x012e, 0x0804, 0x3583, 0x614c, 0x6250,
+	0x7884, 0x604e, 0x7b88, 0x6352, 0x2069, 0x1847, 0x831f, 0x9305,
+	0x6816, 0x788c, 0x2069, 0x1985, 0x2d1c, 0x206a, 0x7e98, 0x9682,
+	0x0014, 0x1210, 0x2031, 0x07d0, 0x2069, 0x1986, 0x2d04, 0x266a,
+	0x789a, 0x0804, 0x3583, 0x0126, 0x2091, 0x8000, 0x7884, 0x603a,
+	0xd0c4, 0x01a8, 0x00d6, 0x78a8, 0x2009, 0x199c, 0x200a, 0x78ac,
+	0x2011, 0x199d, 0x2012, 0x2069, 0x0100, 0x6838, 0x9086, 0x0007,
+	0x1118, 0x2214, 0x6a5a, 0x0010, 0x210c, 0x695a, 0x00de, 0x7884,
+	0xd0b4, 0x0120, 0x3b00, 0x9084, 0xff3f, 0x20d8, 0x7888, 0x603e,
+	0x2011, 0x0114, 0x220c, 0x7888, 0xd08c, 0x0118, 0x918d, 0x0080,
+	0x0010, 0x918c, 0xff7f, 0x2112, 0x788c, 0x6042, 0x9084, 0x0020,
+	0x0130, 0x78b4, 0x6046, 0x9084, 0x0001, 0x090c, 0x4278, 0x6040,
+	0xd0cc, 0x0120, 0x78b0, 0x2011, 0x0114, 0x2012, 0x012e, 0x0804,
+	0x3583, 0x00f6, 0x2079, 0x1800, 0x7a38, 0xa898, 0x9084, 0xfebf,
+	0x9215, 0xa89c, 0x9084, 0xfebf, 0x8002, 0x9214, 0x7838, 0x9084,
+	0x0140, 0x9215, 0x7a3a, 0xa897, 0x4000, 0x900e, 0x9085, 0x0001,
+	0x2001, 0x0000, 0x00fe, 0x0005, 0x7898, 0x9005, 0x01a8, 0x7888,
+	0x9025, 0x0904, 0x35b8, 0x788c, 0x902d, 0x0904, 0x35b8, 0x900e,
+	0x080c, 0x6699, 0x1120, 0xba44, 0xbb38, 0xbc46, 0xbd3a, 0x9186,
+	0x07ff, 0x0190, 0x8108, 0x0ca0, 0x080c, 0x4b52, 0x0904, 0x35b8,
+	0x7888, 0x900d, 0x0904, 0x35b8, 0x788c, 0x9005, 0x0904, 0x35b8,
+	0xba44, 0xb946, 0xbb38, 0xb83a, 0x0804, 0x3583, 0x2011, 0xbc09,
+	0x0010, 0x2011, 0xbc05, 0x080c, 0x5771, 0x1904, 0x35b5, 0x00c6,
+	0x2061, 0x0100, 0x7984, 0x9186, 0x00ff, 0x1130, 0x2001, 0x1818,
+	0x2004, 0x9085, 0xff00, 0x0088, 0x9182, 0x007f, 0x16e0, 0x9188,
+	0x3384, 0x210d, 0x918c, 0x00ff, 0x2001, 0x1818, 0x2004, 0x0026,
+	0x9116, 0x002e, 0x0580, 0x810f, 0x9105, 0x0126, 0x2091, 0x8000,
+	0x0006, 0x080c, 0xaeed, 0x000e, 0x0510, 0x602e, 0x620a, 0x7984,
+	0x00b6, 0x080c, 0x663e, 0x2b08, 0x00be, 0x1500, 0x6112, 0x6023,
+	0x0001, 0x080c, 0x4b1f, 0x01d0, 0x9006, 0xa866, 0x7007, 0x0003,
+	0xa832, 0xa868, 0xc0fd, 0xa86a, 0x701f, 0x3a69, 0x2900, 0x6016,
+	0x2009, 0x0032, 0x080c, 0xafbe, 0x012e, 0x00ce, 0x0005, 0x012e,
+	0x00ce, 0x0804, 0x35b5, 0x00ce, 0x0804, 0x35b8, 0x080c, 0xaf43,
+	0x0cb0, 0xa830, 0x9086, 0x0100, 0x0904, 0x35b5, 0x0804, 0x3583,
+	0x2061, 0x1a70, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0170,
+	0x6104, 0x6208, 0x2061, 0x1800, 0x6354, 0x6074, 0x789a, 0x60c0,
+	0x789e, 0x60bc, 0x78aa, 0x012e, 0x0804, 0x3583, 0x900e, 0x2110,
+	0x0c88, 0x81ff, 0x1904, 0x35b5, 0x080c, 0x743e, 0x0904, 0x35b5,
+	0x0126, 0x2091, 0x8000, 0x6254, 0x6074, 0x9202, 0x0248, 0x9085,
+	0x0001, 0x080c, 0x28e5, 0x080c, 0x5990, 0x012e, 0x0804, 0x3583,
+	0x012e, 0x0804, 0x35b8, 0x0006, 0x0016, 0x00c6, 0x00e6, 0x2001,
+	0x19a8, 0x2070, 0x2061, 0x1847, 0x6008, 0x2072, 0x900e, 0x2011,
+	0x1400, 0x080c, 0x9027, 0x7206, 0x00ee, 0x00ce, 0x001e, 0x000e,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0128, 0x012e, 0x2021,
+	0x400b, 0x0804, 0x3585, 0x7884, 0xd0fc, 0x0148, 0x2001, 0x002a,
+	0x2004, 0x9082, 0x00e1, 0x0288, 0x012e, 0x0804, 0x35b8, 0x2001,
+	0x002a, 0x2004, 0x2069, 0x1847, 0x6908, 0x9102, 0x1230, 0x012e,
+	0x0804, 0x35b8, 0x012e, 0x0804, 0x35b5, 0x080c, 0xaead, 0x0dd0,
+	0x7884, 0xd0fc, 0x0904, 0x3b34, 0x00c6, 0x080c, 0x4b1f, 0x00ce,
+	0x0d88, 0xa867, 0x0000, 0x7884, 0xa80a, 0x7898, 0xa80e, 0x789c,
+	0xa812, 0x2001, 0x002e, 0x2004, 0xa81a, 0x2001, 0x002f, 0x2004,
+	0xa81e, 0x2001, 0x0030, 0x2004, 0xa822, 0x2001, 0x0031, 0x2004,
+	0xa826, 0x2001, 0x0034, 0x2004, 0xa82a, 0x2001, 0x0035, 0x2004,
+	0xa82e, 0x2001, 0x002a, 0x2004, 0x9080, 0x0003, 0x9084, 0x00fc,
+	0x8004, 0xa816, 0x080c, 0x3cba, 0x0928, 0x7014, 0x2048, 0xad2c,
+	0xac28, 0xab1c, 0xaa18, 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029,
+	0x0000, 0x2021, 0x0000, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f,
+	0x9084, 0xffc0, 0x9080, 0x001b, 0x080c, 0x4b68, 0x701f, 0x3bf7,
+	0x7023, 0x0001, 0x012e, 0x0005, 0x0046, 0x0086, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x080c, 0x3aa3, 0x2001,
+	0x199e, 0x2003, 0x0000, 0x2021, 0x000a, 0x2061, 0x0100, 0x6104,
+	0x0016, 0x60bb, 0x0000, 0x60bf, 0x32e1, 0x60bf, 0x0012, 0x080c,
+	0x3d29, 0x080c, 0x3ce8, 0x00f6, 0x00e6, 0x0086, 0x2940, 0x2071,
+	0x1a65, 0x2079, 0x0090, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4,
+	0x0140, 0x2001, 0x0035, 0x2004, 0x780e, 0x2001, 0x0034, 0x2004,
+	0x780a, 0x00de, 0x2011, 0x0001, 0x080c, 0x40bc, 0x008e, 0x00ee,
+	0x00fe, 0x080c, 0x3fe9, 0x080c, 0x3eee, 0x05b8, 0x2001, 0x020b,
+	0x2004, 0x9084, 0x0140, 0x1db8, 0x080c, 0x4130, 0x00f6, 0x2079,
+	0x0300, 0x78bc, 0x00fe, 0x908c, 0x0070, 0x1560, 0x2071, 0x0200,
+	0x7037, 0x0000, 0x7050, 0x9084, 0xff00, 0x9086, 0x3200, 0x1510,
+	0x7037, 0x0001, 0x7050, 0x9084, 0xff00, 0x9086, 0xe100, 0x11d0,
+	0x7037, 0x0000, 0x7054, 0x7037, 0x0000, 0x715c, 0x9106, 0x1190,
+	0x2001, 0x1820, 0x2004, 0x9106, 0x1168, 0x00c6, 0x2061, 0x0100,
+	0x6024, 0x9084, 0x1e00, 0x00ce, 0x0138, 0x080c, 0x3ef8, 0x080c,
+	0x3ce3, 0x0058, 0x080c, 0x3ce3, 0x080c, 0x4054, 0x080c, 0x3fdf,
+	0x2001, 0x020b, 0x2004, 0xd0e4, 0x0dd8, 0x2001, 0x032a, 0x2003,
+	0x0004, 0x2061, 0x0100, 0x6027, 0x0002, 0x001e, 0x6106, 0x2011,
+	0x020d, 0x2013, 0x0020, 0x60bb, 0x0000, 0x60bf, 0x0108, 0x60bf,
+	0x0012, 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c,
+	0x12ed, 0x2009, 0x0028, 0x080c, 0x2410, 0x2001, 0x0227, 0x200c,
+	0x2102, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e,
+	0x008e, 0x004e, 0x2001, 0x199e, 0x2004, 0x9005, 0x1118, 0x012e,
+	0x0804, 0x3583, 0x012e, 0x2021, 0x400c, 0x0804, 0x3585, 0x0016,
+	0x0026, 0x0036, 0x0046, 0x0056, 0x0076, 0x0086, 0x0096, 0x00d6,
+	0x0156, 0x7014, 0x2048, 0x7020, 0x20a8, 0x8000, 0x7022, 0xa804,
+	0x9005, 0x0904, 0x3c53, 0x2048, 0x1f04, 0x3c07, 0x7068, 0x2040,
+	0xa28c, 0xa390, 0xa494, 0xa598, 0xa930, 0xa808, 0xd0b4, 0x1120,
+	0x2029, 0x0000, 0x2021, 0x0000, 0x0096, 0x7014, 0x2048, 0xa864,
+	0x009e, 0x9086, 0x0103, 0x0170, 0x8906, 0x8006, 0x8007, 0x90bc,
+	0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x080c, 0x4b68, 0x701f,
+	0x3bf7, 0x00b0, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x001b, 0x21a8, 0x27e0, 0x2098, 0x27e8, 0x20a0,
+	0x0006, 0x080c, 0x0f7c, 0x000e, 0x080c, 0x4b6b, 0x701f, 0x3bf7,
+	0x015e, 0x00de, 0x009e, 0x008e, 0x007e, 0x005e, 0x004e, 0x003e,
+	0x002e, 0x001e, 0x0005, 0x7014, 0x2048, 0xa864, 0x9086, 0x0103,
+	0x1118, 0x701f, 0x3cb8, 0x0450, 0x7014, 0x2048, 0xa868, 0xc0fd,
+	0xa86a, 0x2009, 0x007f, 0x080c, 0x6638, 0x0110, 0x9006, 0x0030,
+	0xb813, 0x00ff, 0xb817, 0xfffd, 0x080c, 0xd151, 0x015e, 0x00de,
+	0x009e, 0x008e, 0x007e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x0904, 0x35b5, 0x0016, 0x0026, 0x0036, 0x0046, 0x0056, 0x0076,
+	0x0086, 0x0096, 0x00d6, 0x0156, 0x701f, 0x3c8a, 0x7007, 0x0003,
+	0x0804, 0x3c48, 0xa830, 0x9086, 0x0100, 0x2021, 0x400c, 0x0904,
+	0x3585, 0x0076, 0xad10, 0xac0c, 0xab24, 0xaa20, 0xa930, 0xa808,
+	0xd0b4, 0x1120, 0x2029, 0x0000, 0x2021, 0x0000, 0x8906, 0x8006,
+	0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x21a8,
+	0x27e0, 0x2098, 0x27e8, 0x20a0, 0x0006, 0x080c, 0x0f7c, 0x000e,
+	0x080c, 0x4b6b, 0x007e, 0x701f, 0x3bf7, 0x7023, 0x0001, 0x0005,
+	0x0804, 0x3583, 0x0156, 0x00c6, 0xa814, 0x908a, 0x001e, 0x0218,
+	0xa833, 0x001e, 0x0010, 0xa832, 0x0078, 0x81ff, 0x0168, 0x0016,
+	0x080c, 0x4b1f, 0x001e, 0x0130, 0xa800, 0x2040, 0xa008, 0xa80a,
+	0x2100, 0x0c58, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ce, 0x015e,
+	0x0005, 0x0006, 0x00f6, 0x2079, 0x0000, 0x7880, 0x9086, 0x0044,
+	0x00fe, 0x000e, 0x0005, 0x2001, 0x199e, 0x2003, 0x0001, 0x0005,
+	0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x2001, 0x19a9, 0x2004,
+	0x601a, 0x2061, 0x0100, 0x2001, 0x19a8, 0x2004, 0x60ce, 0x6104,
+	0xc1ac, 0x6106, 0x080c, 0x4b1f, 0xa813, 0x0019, 0xa817, 0x0001,
+	0x2900, 0xa85a, 0x2001, 0x002e, 0x2004, 0xa866, 0x2001, 0x002f,
+	0x2004, 0xa86a, 0x2061, 0x0090, 0x2079, 0x0100, 0x2001, 0x19a8,
+	0x2004, 0x6036, 0x2009, 0x0040, 0x080c, 0x2410, 0x2001, 0x002a,
+	0x2004, 0x9084, 0xfff8, 0xa86e, 0x601a, 0xa873, 0x0000, 0x601f,
+	0x0000, 0x78ca, 0x9006, 0x600a, 0x600e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0x00e6, 0x080c, 0x4b1f, 0x2940, 0xa013, 0x0019, 0xa017,
+	0x0001, 0x2800, 0xa05a, 0x2001, 0x0030, 0x2004, 0xa866, 0x2001,
+	0x0031, 0x2004, 0xa86a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0xa86e, 0xa873, 0x0000, 0x2001, 0x032a, 0x2003, 0x0004, 0x2001,
+	0x0300, 0x2003, 0x0000, 0x2001, 0x020d, 0x2003, 0x0000, 0x2001,
+	0x0004, 0x200c, 0x918d, 0x0002, 0x2102, 0x00ee, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x81ff, 0x0148, 0x080c, 0x2c6e, 0x1130, 0x9006,
+	0x080c, 0x2bc6, 0x9006, 0x080c, 0x2ba9, 0x7884, 0x9084, 0x0007,
+	0x0002, 0x3d74, 0x3d7d, 0x3d86, 0x3d71, 0x3d71, 0x3d71, 0x3d71,
+	0x3d71, 0x012e, 0x0804, 0x35b8, 0x2009, 0x0114, 0x2104, 0x9085,
+	0x0800, 0x200a, 0x080c, 0x3f42, 0x00c0, 0x2009, 0x0114, 0x2104,
+	0x9085, 0x4000, 0x200a, 0x080c, 0x3f42, 0x0078, 0x080c, 0x743e,
+	0x1128, 0x012e, 0x2009, 0x0016, 0x0804, 0x35b5, 0x81ff, 0x0128,
+	0x012e, 0x2021, 0x400b, 0x0804, 0x3585, 0x0086, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x080c, 0x3aa3, 0x2009,
+	0x0101, 0x210c, 0x0016, 0x7ec8, 0x7dcc, 0x9006, 0x2068, 0x2060,
+	0x2058, 0x080c, 0x420b, 0x080c, 0x415b, 0x903e, 0x2720, 0x00f6,
+	0x00e6, 0x0086, 0x2940, 0x2071, 0x1a65, 0x2079, 0x0090, 0x00d6,
+	0x2069, 0x0000, 0x6884, 0xd0b4, 0x0120, 0x68d4, 0x780e, 0x68d0,
+	0x780a, 0x00de, 0x2011, 0x0001, 0x080c, 0x40bc, 0x080c, 0x2c76,
+	0x080c, 0x2c76, 0x080c, 0x2c76, 0x080c, 0x2c76, 0x080c, 0x40bc,
+	0x008e, 0x00ee, 0x00fe, 0x080c, 0x3fe9, 0x2009, 0x9c40, 0x8109,
+	0x11b0, 0x080c, 0x3ef8, 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd,
+	0x2102, 0x001e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae,
+	0x009e, 0x008e, 0x2009, 0x0017, 0x080c, 0x35b5, 0x0cf8, 0x2001,
+	0x020b, 0x2004, 0x9084, 0x0140, 0x1d10, 0x00f6, 0x2079, 0x0000,
+	0x7884, 0x00fe, 0xd0bc, 0x0178, 0x2001, 0x0201, 0x200c, 0x81ff,
+	0x0150, 0x080c, 0x3fc7, 0x2d00, 0x9c05, 0x9b05, 0x0120, 0x080c,
+	0x3ef8, 0x0804, 0x3ea5, 0x080c, 0x4130, 0x080c, 0x4054, 0x080c,
+	0x3faa, 0x080c, 0x3fdf, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd0ac,
+	0x0130, 0x8b58, 0x080c, 0x3ef8, 0x00fe, 0x0804, 0x3ea5, 0x00fe,
+	0x080c, 0x3eee, 0x1150, 0x8d68, 0x2001, 0x0032, 0x2602, 0x2001,
+	0x0033, 0x2502, 0x080c, 0x3ef8, 0x0080, 0x87ff, 0x0138, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x1908, 0x8739, 0x0038, 0x2001, 0x1a61,
+	0x2004, 0x9086, 0x0000, 0x1904, 0x3df5, 0x2001, 0x032f, 0x2003,
+	0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0x9605, 0x0904, 0x3ea5,
+	0x7884, 0xd0bc, 0x0128, 0x2d00, 0x9c05, 0x9b05, 0x1904, 0x3ea5,
+	0xa013, 0x0019, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, 0xd0ac,
+	0x1148, 0x2001, 0x1a61, 0x2003, 0x0003, 0x2001, 0x032a, 0x2003,
+	0x0009, 0x0030, 0xa017, 0x0001, 0x78b4, 0x9005, 0x0108, 0xa016,
+	0x2800, 0xa05a, 0x2009, 0x0040, 0x080c, 0x2410, 0x2900, 0xa85a,
+	0xa813, 0x0019, 0x7884, 0xd0a4, 0x1180, 0xa817, 0x0000, 0x00c6,
+	0x20a9, 0x0004, 0x2061, 0x0090, 0x602b, 0x0008, 0x2001, 0x0203,
+	0x2004, 0x1f04, 0x3e7c, 0x00ce, 0x0030, 0xa817, 0x0001, 0x78b0,
+	0x9005, 0x0108, 0xa816, 0x00f6, 0x00c6, 0x2079, 0x0100, 0x2061,
+	0x0090, 0x7827, 0x0002, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0x601a, 0x0006, 0x2001, 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e,
+	0x78ca, 0x00ce, 0x00fe, 0x0804, 0x3daf, 0x001e, 0x00c6, 0x2001,
+	0x032a, 0x2003, 0x0004, 0x2061, 0x0100, 0x6027, 0x0002, 0x6106,
+	0x2011, 0x020d, 0x2013, 0x0020, 0x2001, 0x0004, 0x200c, 0x918c,
+	0xfffd, 0x2102, 0x080c, 0x12ed, 0x7884, 0x9084, 0x0003, 0x9086,
+	0x0002, 0x01a0, 0x2009, 0x0028, 0x080c, 0x2410, 0x2001, 0x0227,
+	0x200c, 0x2102, 0x6050, 0x9084, 0xb7ef, 0x6052, 0x602f, 0x0000,
+	0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x00ce, 0x2d08,
+	0x2c10, 0x2b18, 0x2b00, 0x9c05, 0x9d05, 0x00fe, 0x00ee, 0x00de,
+	0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804,
+	0x3583, 0x012e, 0x2021, 0x400c, 0x0804, 0x3585, 0x9085, 0x0001,
+	0x1d04, 0x3ef7, 0x2091, 0x6000, 0x8420, 0x9486, 0x0064, 0x0005,
+	0x2001, 0x0105, 0x2003, 0x0010, 0x2001, 0x032a, 0x2003, 0x0004,
+	0x2001, 0x1a61, 0x2003, 0x0000, 0x0071, 0x2009, 0x0048, 0x080c,
+	0x2410, 0x2001, 0x0227, 0x2024, 0x2402, 0x2001, 0x0109, 0x2003,
+	0x4000, 0x9026, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a65, 0x7000,
+	0x9086, 0x0000, 0x0520, 0x2079, 0x0090, 0x2009, 0x0206, 0x2104,
+	0x2009, 0x0203, 0x210c, 0x9106, 0x1120, 0x2009, 0x0040, 0x080c,
+	0x2410, 0x782c, 0xd0fc, 0x0d88, 0x080c, 0x4130, 0x7000, 0x9086,
+	0x0000, 0x1d58, 0x782b, 0x0004, 0x782c, 0xd0ac, 0x1de8, 0x2009,
+	0x0040, 0x080c, 0x2410, 0x782b, 0x0002, 0x7003, 0x0000, 0x00ee,
+	0x00fe, 0x0005, 0x00f6, 0x2079, 0x0100, 0x2001, 0x1818, 0x200c,
+	0x7932, 0x7936, 0x080c, 0x28c5, 0x7850, 0x9084, 0xfbff, 0x9085,
+	0x0030, 0x7852, 0x2019, 0x01f4, 0x8319, 0x1df0, 0x9084, 0xffcf,
+	0x9085, 0x2000, 0x7852, 0x20a9, 0x0046, 0x1d04, 0x3f5d, 0x2091,
+	0x6000, 0x1f04, 0x3f5d, 0x7850, 0x9085, 0x0400, 0x9084, 0xdfff,
+	0x7852, 0x2001, 0x0021, 0x2004, 0x9084, 0x0003, 0x9086, 0x0001,
+	0x1120, 0x7850, 0x9084, 0xdfff, 0x7852, 0x784b, 0xf7f7, 0x7843,
+	0x0090, 0x7843, 0x0010, 0x20a9, 0x0028, 0xa001, 0x1f04, 0x3f7d,
+	0x7850, 0x9085, 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854, 0xa001,
+	0xa001, 0xd08c, 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048, 0x7850,
+	0x9085, 0x0400, 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4, 0xa001,
+	0xa001, 0x8319, 0x1de0, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x7827,
+	0x0020, 0x7843, 0x0000, 0x9006, 0x080c, 0x2d4e, 0x7827, 0x0048,
+	0x00fe, 0x0005, 0x7884, 0xd0ac, 0x11c8, 0x00f6, 0x00e6, 0x2071,
+	0x1a61, 0x2079, 0x0320, 0x2001, 0x0201, 0x2004, 0x9005, 0x0160,
+	0x7000, 0x9086, 0x0000, 0x1140, 0x0051, 0xd0bc, 0x0108, 0x8738,
+	0x7003, 0x0003, 0x782b, 0x0019, 0x00ee, 0x00fe, 0x0005, 0x00f6,
+	0x2079, 0x0300, 0x78bc, 0x00fe, 0x908c, 0x0070, 0x0178, 0x2009,
+	0x0032, 0x260a, 0x2009, 0x0033, 0x250a, 0xd0b4, 0x0108, 0x8c60,
+	0xd0ac, 0x0108, 0x8d68, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6,
+	0x2079, 0x0200, 0x781c, 0xd084, 0x0110, 0x7837, 0x0050, 0x00fe,
+	0x0005, 0x00e6, 0x2071, 0x0100, 0x2001, 0x19a9, 0x2004, 0x70e2,
+	0x080c, 0x3cd9, 0x1188, 0x2001, 0x1820, 0x2004, 0x2009, 0x181f,
+	0x210c, 0x918c, 0x00ff, 0x706e, 0x716a, 0x7066, 0x918d, 0x3200,
+	0x7162, 0x7073, 0xe109, 0x0080, 0x702c, 0x9085, 0x0002, 0x702e,
+	0x2009, 0x1818, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166, 0x719e,
+	0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078, 0x9080,
+	0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa, 0x9006,
+	0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af, 0x95d5,
+	0x7014, 0x9084, 0x1984, 0x9085, 0x0092, 0x7016, 0x080c, 0x4130,
+	0x00f6, 0x2071, 0x1a61, 0x2079, 0x0320, 0x00d6, 0x2069, 0x0000,
+	0x6884, 0xd0b4, 0x0120, 0x689c, 0x780e, 0x6898, 0x780a, 0x00de,
+	0x2009, 0x03e8, 0x8109, 0x1df0, 0x792c, 0xd1fc, 0x0110, 0x782b,
+	0x0004, 0x2011, 0x0011, 0x080c, 0x40bc, 0x2011, 0x0001, 0x080c,
+	0x40bc, 0x00fe, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a61,
+	0x2079, 0x0320, 0x792c, 0xd1fc, 0x0904, 0x40b9, 0x782b, 0x0002,
+	0x9026, 0xd19c, 0x1904, 0x40b5, 0x7000, 0x0002, 0x40b9, 0x406a,
+	0x409a, 0x40b5, 0xd1bc, 0x1170, 0xd1dc, 0x1190, 0x8001, 0x7002,
+	0x2011, 0x0001, 0x080c, 0x40bc, 0x0904, 0x40b9, 0x080c, 0x40bc,
+	0x0804, 0x40b9, 0x00f6, 0x2079, 0x0300, 0x78bf, 0x0000, 0x00fe,
+	0x7810, 0x7914, 0x782b, 0x0004, 0x7812, 0x7916, 0x2001, 0x0201,
+	0x200c, 0x81ff, 0x0de8, 0x080c, 0x3fc7, 0x2009, 0x0001, 0x00f6,
+	0x2079, 0x0300, 0x78b8, 0x00fe, 0xd0ec, 0x0110, 0x2009, 0x0011,
+	0x792a, 0x00f8, 0x8001, 0x7002, 0x9184, 0x0880, 0x1140, 0x782c,
+	0xd0fc, 0x1904, 0x405e, 0x2011, 0x0001, 0x00b1, 0x0090, 0xa010,
+	0x9092, 0x0004, 0x9086, 0x0015, 0x1120, 0xa000, 0xa05a, 0x2011,
+	0x0031, 0xa212, 0xd1dc, 0x1960, 0x0828, 0x782b, 0x0004, 0x7003,
+	0x0000, 0x00ee, 0x00fe, 0x0005, 0xa014, 0x9005, 0x0550, 0x8001,
+	0x0036, 0x0096, 0xa016, 0xa058, 0x2048, 0xa010, 0x2009, 0x0031,
+	0x911a, 0x831c, 0x831c, 0x938a, 0x0007, 0x1a0c, 0x0dd5, 0x9398,
+	0x40ea, 0x231d, 0x083f, 0x9080, 0x0004, 0x7a2a, 0x7100, 0x8108,
+	0x7102, 0x009e, 0x003e, 0x908a, 0x0035, 0x1140, 0x0096, 0xa058,
+	0x2048, 0xa804, 0xa05a, 0x2001, 0x0019, 0x009e, 0xa012, 0x9085,
+	0x0001, 0x0005, 0x4127, 0x411e, 0x4115, 0x410c, 0x4103, 0x40fa,
+	0x40f1, 0xa964, 0x7902, 0xa968, 0x7906, 0xa96c, 0x7912, 0xa970,
+	0x7916, 0x0005, 0xa974, 0x7902, 0xa978, 0x7906, 0xa97c, 0x7912,
+	0xa980, 0x7916, 0x0005, 0xa984, 0x7902, 0xa988, 0x7906, 0xa98c,
+	0x7912, 0xa990, 0x7916, 0x0005, 0xa994, 0x7902, 0xa998, 0x7906,
+	0xa99c, 0x7912, 0xa9a0, 0x7916, 0x0005, 0xa9a4, 0x7902, 0xa9a8,
+	0x7906, 0xa9ac, 0x7912, 0xa9b0, 0x7916, 0x0005, 0xa9b4, 0x7902,
+	0xa9b8, 0x7906, 0xa9bc, 0x7912, 0xa9c0, 0x7916, 0x0005, 0xa9c4,
+	0x7902, 0xa9c8, 0x7906, 0xa9cc, 0x7912, 0xa9d0, 0x7916, 0x0005,
+	0x00f6, 0x00e6, 0x0086, 0x2071, 0x1a65, 0x2079, 0x0090, 0x792c,
+	0xd1fc, 0x01e8, 0x782b, 0x0002, 0x2940, 0x9026, 0x7000, 0x0002,
+	0x4157, 0x4143, 0x414e, 0x8001, 0x7002, 0xd19c, 0x1180, 0x2011,
+	0x0001, 0x080c, 0x40bc, 0x190c, 0x40bc, 0x0048, 0x8001, 0x7002,
+	0x782c, 0xd0fc, 0x1d38, 0x2011, 0x0001, 0x080c, 0x40bc, 0x008e,
+	0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086, 0x2061,
+	0x0200, 0x2001, 0x19a9, 0x2004, 0x601a, 0x2061, 0x0100, 0x2001,
+	0x19a8, 0x2004, 0x60ce, 0x6104, 0xc1ac, 0x6106, 0x2001, 0x002c,
+	0x2004, 0x9005, 0x0520, 0x2038, 0x2001, 0x002e, 0x2024, 0x2001,
+	0x002f, 0x201c, 0x080c, 0x4b1f, 0xa813, 0x0019, 0xaf16, 0x2900,
+	0xa85a, 0x978a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010,
+	0x2708, 0x903e, 0x0096, 0xa858, 0x2048, 0xa85c, 0x9080, 0x0019,
+	0x009e, 0x080c, 0x41d3, 0x1d68, 0x2900, 0xa85a, 0x00d0, 0x080c,
+	0x4b1f, 0xa813, 0x0019, 0xa817, 0x0001, 0x2900, 0xa85a, 0x2001,
+	0x002e, 0x2004, 0xa866, 0x2001, 0x002f, 0x2004, 0xa86a, 0x2001,
+	0x002a, 0x2004, 0x9084, 0xfff8, 0xa86e, 0x2001, 0x002b, 0x2004,
+	0xa872, 0x2061, 0x0090, 0x2079, 0x0100, 0x2001, 0x19a8, 0x2004,
+	0x6036, 0x2009, 0x0040, 0x080c, 0x2410, 0x2001, 0x002a, 0x2004,
+	0x9084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x002b, 0x2004, 0x601e,
+	0x78c6, 0x000e, 0x78ca, 0x9006, 0x600a, 0x600e, 0x008e, 0x00ce,
+	0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0080, 0xaa60, 0x22e8,
+	0x20a0, 0x20e1, 0x0000, 0x2099, 0x0088, 0x702b, 0x0026, 0x7402,
+	0x7306, 0x9006, 0x700a, 0x700e, 0x810b, 0x810b, 0x21a8, 0x810b,
+	0x7112, 0x702b, 0x0041, 0x702c, 0xd0fc, 0x0de8, 0x702b, 0x0002,
+	0x702b, 0x0040, 0x4005, 0x7400, 0x7304, 0x87ff, 0x0190, 0x0086,
+	0x0096, 0x2940, 0x0086, 0x080c, 0x4b1f, 0x008e, 0xa058, 0x00a6,
+	0x2050, 0x2900, 0xb006, 0xa05a, 0x00ae, 0x009e, 0x008e, 0x9085,
+	0x0001, 0x00ee, 0x0005, 0x00e6, 0x2001, 0x002d, 0x2004, 0x9005,
+	0x0528, 0x2038, 0x2001, 0x0030, 0x2024, 0x2001, 0x0031, 0x201c,
+	0x080c, 0x4b1f, 0x2940, 0xa813, 0x0019, 0xaf16, 0x2900, 0xa85a,
+	0x978a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010, 0x2708,
+	0x903e, 0x0096, 0xa858, 0x2048, 0xa85c, 0x9080, 0x0019, 0x009e,
+	0x080c, 0x41d3, 0x1d68, 0x2900, 0xa85a, 0x00d8, 0x080c, 0x4b1f,
+	0x2940, 0xa013, 0x0019, 0xa017, 0x0001, 0x2800, 0xa05a, 0x2001,
+	0x0030, 0x2004, 0xa066, 0x2001, 0x0031, 0x2004, 0xa06a, 0x2001,
+	0x002a, 0x2004, 0x9084, 0xfff8, 0xa06e, 0x2001, 0x002b, 0x2004,
+	0xa072, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, 0xd0ac, 0x1180,
+	0x2001, 0x0101, 0x200c, 0x918d, 0x0200, 0x2102, 0xa017, 0x0000,
+	0x2001, 0x1a61, 0x2003, 0x0003, 0x2001, 0x032a, 0x2003, 0x0009,
+	0x2001, 0x0300, 0x2003, 0x0000, 0x2001, 0x020d, 0x2003, 0x0000,
+	0x2001, 0x0004, 0x200c, 0x918d, 0x0002, 0x2102, 0x00ee, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x20a9, 0x0007, 0x20a1, 0x1840, 0x20e9,
+	0x0001, 0x9006, 0x4004, 0x20a9, 0x0014, 0x20a1, 0xffec, 0x20e9,
+	0x0000, 0x9006, 0x4004, 0x2009, 0x013c, 0x200a, 0x012e, 0x7880,
+	0x9086, 0x0052, 0x0108, 0x0005, 0x0804, 0x3583, 0x7d98, 0x7c9c,
+	0x0804, 0x3685, 0x080c, 0x743e, 0x190c, 0x6072, 0x6040, 0x9084,
+	0x0020, 0x09b1, 0x2069, 0x1847, 0x2d00, 0x2009, 0x0030, 0x7a8c,
+	0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x080c, 0x4b68, 0x701f,
+	0x42b2, 0x0005, 0x080c, 0x576c, 0x1130, 0x3b00, 0x3a08, 0xc194,
+	0xc095, 0x20d8, 0x21d0, 0x2069, 0x1847, 0x6800, 0x9005, 0x0904,
+	0x35b8, 0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x35b8, 0xd094,
+	0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0x9292, 0x0005,
+	0x0218, 0x918c, 0xffdf, 0x0010, 0x918d, 0x0020, 0x6106, 0x00ce,
+	0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0x918d, 0x0010,
+	0x0010, 0x918c, 0xffef, 0x6106, 0x00ce, 0xd084, 0x0158, 0x6a28,
+	0x928a, 0x007f, 0x1a04, 0x35b8, 0x9288, 0x3384, 0x210d, 0x918c,
+	0x00ff, 0x6166, 0xd0dc, 0x0130, 0x6828, 0x908a, 0x007f, 0x1a04,
+	0x35b8, 0x605e, 0x6888, 0x9084, 0x0030, 0x8004, 0x8004, 0x8004,
+	0x8004, 0x0006, 0x2009, 0x19b0, 0x9080, 0x29b8, 0x2005, 0x200a,
+	0x000e, 0x2009, 0x19b1, 0x9080, 0x29bc, 0x2005, 0x200a, 0x6808,
+	0x908a, 0x0100, 0x0a04, 0x35b8, 0x908a, 0x0841, 0x1a04, 0x35b8,
+	0x9084, 0x0007, 0x1904, 0x35b8, 0x680c, 0x9005, 0x0904, 0x35b8,
+	0x6810, 0x9005, 0x0904, 0x35b8, 0x6848, 0x6940, 0x910a, 0x1a04,
+	0x35b8, 0x8001, 0x0904, 0x35b8, 0x684c, 0x6944, 0x910a, 0x1a04,
+	0x35b8, 0x8001, 0x0904, 0x35b8, 0x2009, 0x1980, 0x200b, 0x0000,
+	0x2001, 0x1869, 0x2004, 0xd0c4, 0x0140, 0x7884, 0x200a, 0x2009,
+	0x017f, 0x200a, 0x3b00, 0xc085, 0x20d8, 0x6814, 0x908c, 0x00ff,
+	0x614e, 0x8007, 0x9084, 0x00ff, 0x6052, 0x080c, 0x7755, 0x080c,
+	0x6a3e, 0x080c, 0x6a72, 0x6808, 0x602a, 0x080c, 0x2382, 0x2009,
+	0x0170, 0x200b, 0x0080, 0xa001, 0xa001, 0x200b, 0x0000, 0x0036,
+	0x6b08, 0x080c, 0x291f, 0x003e, 0x6000, 0x9086, 0x0000, 0x1904,
+	0x4449, 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217,
+	0x831f, 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148,
+	0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f,
+	0x0010, 0x9084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x8007,
+	0x810f, 0x8217, 0x831f, 0x20a9, 0x0004, 0x20a1, 0x19b2, 0x20e9,
+	0x0001, 0x4001, 0x20a9, 0x0004, 0x20a1, 0x19cc, 0x20e9, 0x0001,
+	0x4001, 0x080c, 0x86ac, 0x00c6, 0x900e, 0x20a9, 0x0001, 0x6b70,
+	0xd384, 0x0510, 0x0068, 0x2009, 0x0100, 0x210c, 0x918e, 0x0008,
+	0x1110, 0x839d, 0x0010, 0x83f5, 0x3e18, 0x12b0, 0x3508, 0x8109,
+	0x080c, 0x7d0c, 0x6878, 0x6016, 0x6874, 0x2008, 0x9084, 0xff00,
+	0x8007, 0x600a, 0x9184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003,
+	0x0003, 0x0010, 0x6003, 0x0001, 0x1f04, 0x43a3, 0x00ce, 0x00c6,
+	0x2061, 0x199b, 0x6a88, 0x9284, 0xc000, 0x2010, 0x9286, 0x0000,
+	0x1158, 0x2063, 0x0000, 0x2001, 0x0001, 0x080c, 0x2bc6, 0x2001,
+	0x0001, 0x080c, 0x2ba9, 0x0088, 0x9286, 0x4000, 0x1148, 0x2063,
+	0x0001, 0x9006, 0x080c, 0x2bc6, 0x9006, 0x080c, 0x2ba9, 0x0028,
+	0x9286, 0x8000, 0x1d30, 0x2063, 0x0002, 0x00ce, 0x6888, 0xd0ec,
+	0x0130, 0x2011, 0x0114, 0x2204, 0x9085, 0x0100, 0x2012, 0x6a80,
+	0x9284, 0x0030, 0x9086, 0x0030, 0x1128, 0x9294, 0xffcf, 0x9295,
+	0x0020, 0x6a82, 0x2001, 0x197b, 0x6a80, 0x9294, 0x0030, 0x928e,
+	0x0000, 0x0170, 0x928e, 0x0010, 0x0118, 0x928e, 0x0020, 0x0140,
+	0x2003, 0xaaaa, 0x080c, 0x2994, 0x2001, 0x196c, 0x2102, 0x0008,
+	0x2102, 0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000,
+	0x00ce, 0x080c, 0x743e, 0x0128, 0x080c, 0x5054, 0x0110, 0x080c,
+	0x28e5, 0x60d4, 0x9005, 0x01c0, 0x6003, 0x0001, 0x2009, 0x4431,
+	0x00e0, 0x080c, 0x743e, 0x1168, 0x2011, 0x72ce, 0x080c, 0x85b0,
+	0x2011, 0x72c1, 0x080c, 0x868a, 0x080c, 0x7729, 0x080c, 0x736a,
+	0x0040, 0x080c, 0x5f6c, 0x0028, 0x6003, 0x0004, 0x2009, 0x4449,
+	0x0020, 0x080c, 0x696e, 0x0804, 0x3583, 0x2001, 0x0170, 0x2004,
+	0x9084, 0x00ff, 0x9086, 0x004c, 0x1118, 0x2091, 0x30bd, 0x0817,
+	0x2091, 0x303d, 0x0817, 0x6000, 0x9086, 0x0000, 0x0904, 0x35b5,
+	0x2069, 0x1847, 0x7890, 0x6842, 0x7894, 0x6846, 0x2d00, 0x2009,
+	0x0030, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804,
+	0x4b6b, 0x9006, 0x080c, 0x28e5, 0x81ff, 0x1904, 0x35b5, 0x080c,
+	0x743e, 0x11b0, 0x080c, 0x7724, 0x080c, 0x60ad, 0x080c, 0x3378,
+	0x0118, 0x6130, 0xc18d, 0x6132, 0x080c, 0xd388, 0x0130, 0x080c,
+	0x7461, 0x1118, 0x080c, 0x7416, 0x0038, 0x080c, 0x736a, 0x0020,
+	0x080c, 0x6072, 0x080c, 0x5f6c, 0x0804, 0x3583, 0x81ff, 0x1904,
+	0x35b5, 0x080c, 0x743e, 0x1110, 0x0804, 0x35b5, 0x6194, 0x81ff,
+	0x01a8, 0x704f, 0x0000, 0x2001, 0x1c80, 0x2009, 0x0040, 0x7a8c,
+	0x7b88, 0x7c9c, 0x7d98, 0x0126, 0x2091, 0x8000, 0x2039, 0x0001,
+	0x080c, 0x4b6b, 0x701f, 0x3581, 0x012e, 0x0005, 0x704f, 0x0001,
+	0x00d6, 0x2069, 0x1c80, 0x20a9, 0x0040, 0x20e9, 0x0001, 0x20a1,
+	0x1c80, 0x2019, 0xffff, 0x4304, 0x655c, 0x9588, 0x3384, 0x210d,
+	0x918c, 0x00ff, 0x216a, 0x900e, 0x2011, 0x0002, 0x2100, 0x9506,
+	0x01a8, 0x080c, 0x6699, 0x1190, 0xb814, 0x821c, 0x0238, 0x9398,
+	0x1c80, 0x9085, 0xff00, 0x8007, 0x201a, 0x0038, 0x9398, 0x1c80,
+	0x2324, 0x94a4, 0xff00, 0x9405, 0x201a, 0x8210, 0x8108, 0x9182,
+	0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0x9105, 0x206a,
+	0x00de, 0x20a9, 0x0040, 0x20a1, 0x1c80, 0x2099, 0x1c80, 0x080c,
+	0x5ffd, 0x0804, 0x44a3, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x080c,
+	0x4b1f, 0x1120, 0x2009, 0x0002, 0x0804, 0x35b5, 0x080c, 0x575d,
+	0xd0b4, 0x0558, 0x7884, 0x908e, 0x007e, 0x0538, 0x908e, 0x007f,
+	0x0520, 0x908e, 0x0080, 0x0508, 0x080c, 0x3373, 0x1148, 0xb800,
+	0xd08c, 0x11d8, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x11a8,
+	0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xce51, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x35b5, 0x7007, 0x0003, 0x701f, 0x4531,
+	0x0005, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x20a9, 0x002b, 0xb8c4,
+	0x20e0, 0xb8c8, 0x2098, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002,
+	0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080, 0x0006, 0x20a0, 0xb8c4,
+	0x20e0, 0xb8c8, 0x9080, 0x0006, 0x2098, 0x080c, 0x0f7c, 0x0070,
+	0x20a9, 0x0004, 0xa85c, 0x9080, 0x000a, 0x20a0, 0xb8c4, 0x20e0,
+	0xb8c8, 0x9080, 0x000a, 0x2098, 0x080c, 0x0f7c, 0x8906, 0x8006,
+	0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0x2009,
+	0x002b, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, 0x4b6b, 0x81ff,
+	0x1904, 0x35b5, 0x080c, 0x4b36, 0x0904, 0x35b8, 0x080c, 0x680b,
+	0x0904, 0x35b5, 0x0058, 0xa878, 0x9005, 0x0120, 0x2009, 0x0004,
+	0x0804, 0x35b5, 0xa974, 0xaa94, 0x0804, 0x3583, 0x080c, 0x5765,
+	0x0904, 0x3583, 0x701f, 0x457b, 0x7007, 0x0003, 0x0005, 0x81ff,
+	0x1904, 0x35b5, 0x7888, 0x908a, 0x1000, 0x1a04, 0x35b8, 0x080c,
+	0x4b52, 0x0904, 0x35b8, 0x080c, 0x6a0c, 0x0120, 0x080c, 0x6a14,
+	0x1904, 0x35b8, 0x080c, 0x6890, 0x0904, 0x35b5, 0x2019, 0x0004,
+	0x900e, 0x080c, 0x681d, 0x0904, 0x35b5, 0x7984, 0x7a88, 0x04c9,
+	0x08a8, 0xa89c, 0x908a, 0x1000, 0x12f8, 0x080c, 0x4b50, 0x01e0,
+	0x080c, 0x6a0c, 0x0118, 0x080c, 0x6a14, 0x11b0, 0x080c, 0x6890,
+	0x2009, 0x0002, 0x0168, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c,
+	0x681d, 0x2009, 0x0003, 0x0120, 0xa998, 0xaa9c, 0x00d1, 0x0060,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x080c, 0x5765,
+	0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000,
+	0x0005, 0x9186, 0x00ff, 0x0110, 0x0071, 0x0060, 0x2029, 0x007e,
+	0x2061, 0x1800, 0x645c, 0x2400, 0x9506, 0x0110, 0x2508, 0x0019,
+	0x8529, 0x1ec8, 0x0005, 0x080c, 0x6699, 0x1138, 0x2200, 0x8003,
+	0x800b, 0x810b, 0x9108, 0x080c, 0x85be, 0x0005, 0x81ff, 0x1904,
+	0x35b5, 0x798c, 0x2001, 0x197f, 0x918c, 0x8000, 0x2102, 0x080c,
+	0x4b36, 0x0904, 0x35b8, 0x080c, 0x6a0c, 0x0120, 0x080c, 0x6a14,
+	0x1904, 0x35b8, 0x080c, 0x6760, 0x0904, 0x35b5, 0x080c, 0x6814,
+	0x0904, 0x35b5, 0x2001, 0x197f, 0x2004, 0xd0fc, 0x1904, 0x3583,
+	0x0804, 0x4586, 0xa9a0, 0x2001, 0x197f, 0x918c, 0x8000, 0xc18d,
+	0x2102, 0x080c, 0x4b43, 0x01a0, 0x080c, 0x6a0c, 0x0118, 0x080c,
+	0x6a14, 0x1170, 0x080c, 0x6760, 0x2009, 0x0002, 0x0128, 0x080c,
+	0x6814, 0x1170, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, 0x0010,
+	0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005,
+	0xa897, 0x4000, 0x2001, 0x197f, 0x2004, 0xd0fc, 0x1128, 0x080c,
+	0x5765, 0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0000, 0x0005, 0x81ff, 0x1904, 0x35b5, 0x798c, 0x2001, 0x197e,
+	0x918c, 0x8000, 0x2102, 0x080c, 0x4b36, 0x0904, 0x35b8, 0x080c,
+	0x6a0c, 0x0120, 0x080c, 0x6a14, 0x1904, 0x35b8, 0x080c, 0x6760,
+	0x0904, 0x35b5, 0x080c, 0x6802, 0x0904, 0x35b5, 0x2001, 0x197e,
+	0x2004, 0xd0fc, 0x1904, 0x3583, 0x0804, 0x4586, 0xa9a0, 0x2001,
+	0x197e, 0x918c, 0x8000, 0xc18d, 0x2102, 0x080c, 0x4b43, 0x01a0,
+	0x080c, 0x6a0c, 0x0118, 0x080c, 0x6a14, 0x1170, 0x080c, 0x6760,
+	0x2009, 0x0002, 0x0128, 0x080c, 0x6802, 0x1170, 0x2009, 0x0003,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x2001, 0x197e,
+	0x2004, 0xd0fc, 0x1128, 0x080c, 0x5765, 0x0110, 0x9006, 0x0018,
+	0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x6100, 0x0804,
+	0x3583, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x080c, 0x5771, 0x1904,
+	0x35b5, 0x79a8, 0xd184, 0x1158, 0xb834, 0x8007, 0x789e, 0xb830,
+	0x8007, 0x789a, 0xbb2c, 0x831f, 0xba28, 0x8217, 0x0050, 0xb824,
+	0x8007, 0x789e, 0xb820, 0x8007, 0x789a, 0xbb1c, 0x831f, 0xba18,
+	0x8217, 0xb900, 0x918c, 0x0202, 0x0804, 0x3583, 0x78a8, 0x909c,
+	0x0003, 0xd0ac, 0x1158, 0xd0b4, 0x1148, 0x939a, 0x0003, 0x1a04,
+	0x35b5, 0x625c, 0x7884, 0x9206, 0x1904, 0x473b, 0x080c, 0x8696,
+	0x2001, 0xffec, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98,
+	0x2039, 0x0000, 0x0006, 0x78a8, 0x9084, 0x0080, 0x11f8, 0x0006,
+	0x0036, 0x2001, 0x1a7f, 0x201c, 0x7b9a, 0x2003, 0x0000, 0x2001,
+	0x1a80, 0x201c, 0x7b9e, 0x2003, 0x0000, 0x2001, 0x1a81, 0x201c,
+	0x7ba2, 0x2003, 0x0000, 0x2001, 0x1a7b, 0x201c, 0x7baa, 0x2003,
+	0x0000, 0x003e, 0x000e, 0x000e, 0x0804, 0x4b6b, 0x000e, 0x2031,
+	0x0000, 0x2061, 0x18b8, 0x2c44, 0xa66a, 0xa17a, 0xa772, 0xa076,
+	0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x10e9, 0x7007, 0x0002,
+	0x701f, 0x475b, 0x0005, 0x81ff, 0x1904, 0x35b5, 0x080c, 0x4b52,
+	0x0904, 0x35b8, 0x080c, 0x6a0c, 0x1904, 0x35b5, 0x00c6, 0x080c,
+	0x4b1f, 0x00ce, 0x0904, 0x35b5, 0xa867, 0x0000, 0xa868, 0xc0fd,
+	0xa86a, 0x7ea8, 0x080c, 0xcdf7, 0x0904, 0x35b5, 0x7007, 0x0003,
+	0x701f, 0x477b, 0x0005, 0x080c, 0x4278, 0x0006, 0x0036, 0x2001,
+	0x1a7f, 0x201c, 0x7b9a, 0x2003, 0x0000, 0x2001, 0x1a80, 0x201c,
+	0x7b9e, 0x2003, 0x0000, 0x2001, 0x1a81, 0x201c, 0x7ba2, 0x2003,
+	0x0000, 0x2001, 0x1a7b, 0x201c, 0x7baa, 0x2003, 0x0000, 0x003e,
+	0x000e, 0x0804, 0x3583, 0xa830, 0x9086, 0x0100, 0x0904, 0x35b5,
+	0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080,
+	0x001b, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804,
+	0x4b6b, 0x9006, 0x080c, 0x28e5, 0x78a8, 0x9084, 0x00ff, 0x9086,
+	0x00ff, 0x0118, 0x81ff, 0x1904, 0x35b5, 0x080c, 0x743e, 0x0110,
+	0x080c, 0x6072, 0x7888, 0x908a, 0x1000, 0x1a04, 0x35b8, 0x7984,
+	0x9186, 0x00ff, 0x0138, 0x9182, 0x007f, 0x1a04, 0x35b8, 0x2100,
+	0x080c, 0x28af, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061,
+	0x19f9, 0x601b, 0x0000, 0x601f, 0x0000, 0x6073, 0x0000, 0x6077,
+	0x0000, 0x080c, 0x743e, 0x1158, 0x080c, 0x7724, 0x080c, 0x60ad,
+	0x9085, 0x0001, 0x080c, 0x7485, 0x080c, 0x736a, 0x00d0, 0x080c,
+	0xaeb4, 0x2061, 0x0100, 0x2001, 0x1818, 0x2004, 0x9084, 0x00ff,
+	0x810f, 0x9105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009,
+	0x1998, 0x200b, 0x0000, 0x2009, 0x002d, 0x2011, 0x5f98, 0x080c,
+	0x8648, 0x7984, 0x080c, 0x743e, 0x1110, 0x2009, 0x00ff, 0x7a88,
+	0x080c, 0x45e9, 0x012e, 0x00ce, 0x002e, 0x0804, 0x3583, 0x7984,
+	0x080c, 0x6638, 0x2b08, 0x1904, 0x35b8, 0x0804, 0x3583, 0x81ff,
+	0x0120, 0x2009, 0x0001, 0x0804, 0x35b5, 0x60dc, 0xd0ac, 0x1130,
+	0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x35b5, 0x080c, 0x4b1f,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x35b5, 0x7984, 0x9192, 0x0021,
+	0x1a04, 0x35b8, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080,
+	0x0019, 0x702a, 0xaf60, 0x7736, 0x080c, 0x4b68, 0x701f, 0x482f,
+	0x7880, 0x9086, 0x006e, 0x0110, 0x701f, 0x5206, 0x0005, 0x2009,
+	0x0080, 0x080c, 0x6699, 0x1118, 0x080c, 0x6a0c, 0x0120, 0x2021,
+	0x400a, 0x0804, 0x3585, 0x00d6, 0x0096, 0xa964, 0xaa6c, 0xab70,
+	0xac74, 0xad78, 0xae7c, 0xa884, 0x90be, 0x0100, 0x0904, 0x48c8,
+	0x90be, 0x0112, 0x0904, 0x48c8, 0x90be, 0x0113, 0x0904, 0x48c8,
+	0x90be, 0x0114, 0x0904, 0x48c8, 0x90be, 0x0117, 0x0904, 0x48c8,
+	0x90be, 0x011a, 0x0904, 0x48c8, 0x90be, 0x011c, 0x0904, 0x48c8,
+	0x90be, 0x0121, 0x0904, 0x48af, 0x90be, 0x0131, 0x0904, 0x48af,
+	0x90be, 0x0171, 0x0904, 0x48c8, 0x90be, 0x0173, 0x0904, 0x48c8,
+	0x90be, 0x01a1, 0x1128, 0xa894, 0x8007, 0xa896, 0x0804, 0x48d3,
+	0x90be, 0x0212, 0x0904, 0x48bc, 0x90be, 0x0213, 0x05e8, 0x90be,
+	0x0214, 0x0500, 0x90be, 0x0217, 0x0188, 0x90be, 0x021a, 0x1120,
+	0xa89c, 0x8007, 0xa89e, 0x04e0, 0x90be, 0x021f, 0x05c8, 0x90be,
+	0x0300, 0x05b0, 0x009e, 0x00de, 0x0804, 0x35b8, 0x7028, 0x9080,
+	0x0010, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0007,
+	0x080c, 0x4911, 0x7028, 0x9080, 0x000e, 0x2098, 0x20a0, 0x7034,
+	0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x4911, 0x00c8, 0x7028,
+	0x9080, 0x000c, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9,
+	0x0001, 0x080c, 0x491e, 0x00b8, 0x7028, 0x9080, 0x000e, 0x2098,
+	0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x491e,
+	0x7028, 0x9080, 0x000c, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8,
+	0x20a9, 0x0001, 0x04f1, 0x00c6, 0x080c, 0x4b1f, 0x0550, 0xa868,
+	0xc0fd, 0xa86a, 0xa867, 0x0119, 0x9006, 0xa882, 0xa87f, 0x0020,
+	0xa88b, 0x0001, 0x810b, 0xa9ae, 0xa8b2, 0xaab6, 0xabba, 0xacbe,
+	0xadc2, 0xa9c6, 0xa8ca, 0x00ce, 0x009e, 0x00de, 0xa866, 0xa822,
+	0xa868, 0xc0fd, 0xa86a, 0xa804, 0x2048, 0x080c, 0xce12, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x35b5, 0x7007, 0x0003, 0x701f, 0x4908,
+	0x0005, 0x00ce, 0x009e, 0x00de, 0x2009, 0x0002, 0x0804, 0x35b5,
+	0xa820, 0x9086, 0x8001, 0x1904, 0x3583, 0x2009, 0x0004, 0x0804,
+	0x35b5, 0x0016, 0x0026, 0x3510, 0x20a9, 0x0002, 0x4002, 0x4104,
+	0x4004, 0x8211, 0x1dc8, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026,
+	0x0036, 0x0046, 0x3520, 0x20a9, 0x0004, 0x4002, 0x4304, 0x4204,
+	0x4104, 0x4004, 0x8421, 0x1db8, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35b5, 0x60dc,
+	0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x35b5,
+	0x7984, 0x78a8, 0x2040, 0x080c, 0xaead, 0x1120, 0x9182, 0x007f,
+	0x0a04, 0x35b8, 0x9186, 0x00ff, 0x0904, 0x35b8, 0x9182, 0x0800,
+	0x1a04, 0x35b8, 0x7a8c, 0x7b88, 0x607c, 0x9306, 0x1158, 0x6080,
+	0x924e, 0x0904, 0x35b8, 0x080c, 0xaead, 0x1120, 0x99cc, 0xff00,
+	0x0904, 0x35b8, 0x0126, 0x2091, 0x8000, 0x080c, 0x4a32, 0x0904,
+	0x49b2, 0x0086, 0x90c6, 0x4000, 0x008e, 0x1538, 0x00c6, 0x0006,
+	0x0036, 0xb818, 0xbb1c, 0x9305, 0xbb20, 0x9305, 0xbb24, 0x9305,
+	0xbb28, 0x9305, 0xbb2c, 0x9305, 0xbb30, 0x9305, 0xbb34, 0x9305,
+	0x003e, 0x0570, 0xd88c, 0x1128, 0x080c, 0x6a0c, 0x0110, 0xc89d,
+	0x0438, 0x900e, 0x080c, 0x68b9, 0x1108, 0xc185, 0xb800, 0xd0bc,
+	0x0108, 0xc18d, 0x000e, 0x00ce, 0x00b8, 0x90c6, 0x4007, 0x1110,
+	0x2408, 0x0090, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0060,
+	0x90c6, 0x4009, 0x1108, 0x0040, 0x90c6, 0x4006, 0x1108, 0x0020,
+	0x2001, 0x4005, 0x2009, 0x000a, 0x2020, 0x012e, 0x0804, 0x3585,
+	0x000e, 0x00ce, 0x2b00, 0x7026, 0x0016, 0x00b6, 0x00c6, 0x00e6,
+	0x2c70, 0x080c, 0xaf91, 0x0904, 0x4a07, 0x2b00, 0x6012, 0x080c,
+	0xd102, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, 0x4b1f, 0x00ce,
+	0x2b70, 0x1158, 0x080c, 0xaf43, 0x00ee, 0x00ce, 0x00be, 0x001e,
+	0x012e, 0x2009, 0x0002, 0x0804, 0x35b5, 0x900e, 0xa966, 0xa96a,
+	0x2900, 0x6016, 0xa932, 0xa868, 0xc0fd, 0xd88c, 0x0108, 0xc0f5,
+	0xa86a, 0xd89c, 0x1110, 0x080c, 0x321e, 0x6023, 0x0001, 0x9006,
+	0x080c, 0x65d5, 0xd89c, 0x0138, 0x2001, 0x0004, 0x080c, 0x65e9,
+	0x2009, 0x0003, 0x0030, 0x2001, 0x0002, 0x080c, 0x65e9, 0x2009,
+	0x0002, 0x080c, 0xafbe, 0x78a8, 0xd094, 0x0138, 0x00ee, 0x7024,
+	0x00e6, 0x2058, 0xb8cc, 0xc08d, 0xb8ce, 0x9085, 0x0001, 0x00ee,
+	0x00ce, 0x00be, 0x001e, 0x012e, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x35b5, 0x7007, 0x0003, 0x701f, 0x4a16, 0x0005, 0xa830, 0x9086,
+	0x0100, 0x7024, 0x2058, 0x1138, 0x2009, 0x0004, 0xba04, 0x9294,
+	0x00ff, 0x0804, 0x56b1, 0x900e, 0xa868, 0xd0f4, 0x1904, 0x3583,
+	0x080c, 0x68b9, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d,
+	0x0804, 0x3583, 0x00e6, 0x00d6, 0x0096, 0x83ff, 0x0904, 0x4a81,
+	0x902e, 0x080c, 0xaead, 0x0130, 0x9026, 0x20a9, 0x0800, 0x2071,
+	0x1000, 0x0030, 0x2021, 0x007f, 0x20a9, 0x0781, 0x2071, 0x107f,
+	0x2e04, 0x9005, 0x11b8, 0x2100, 0x9406, 0x1904, 0x4a92, 0x2428,
+	0x94ce, 0x007f, 0x1120, 0x92ce, 0xfffd, 0x1558, 0x0030, 0x94ce,
+	0x0080, 0x1130, 0x92ce, 0xfffc, 0x1520, 0x93ce, 0x00ff, 0x1508,
+	0xc5fd, 0x0480, 0x2058, 0xbf10, 0x2700, 0x9306, 0x11e8, 0xbe14,
+	0x2600, 0x9206, 0x11c8, 0x2400, 0x9106, 0x1180, 0xd884, 0x0598,
+	0xd894, 0x1588, 0x080c, 0x69ac, 0x1570, 0x2001, 0x4000, 0x0460,
+	0x080c, 0x6a0c, 0x1540, 0x2001, 0x4000, 0x0430, 0x2001, 0x4007,
+	0x0418, 0x2001, 0x4006, 0x0400, 0x2400, 0x9106, 0x1158, 0xbe14,
+	0x87ff, 0x1128, 0x86ff, 0x0918, 0x080c, 0xaead, 0x1900, 0x2001,
+	0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, 0x4a48, 0x85ff, 0x1130,
+	0x2001, 0x4009, 0x0048, 0x2001, 0x0001, 0x0030, 0x080c, 0x6638,
+	0x1dd0, 0xbb12, 0xba16, 0x9006, 0x9005, 0x009e, 0x00de, 0x00ee,
+	0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35b5, 0x080c,
+	0x4b1f, 0x1120, 0x2009, 0x0002, 0x0804, 0x35b5, 0xa867, 0x0000,
+	0xa868, 0xc0fd, 0xa86a, 0x7884, 0x9005, 0x0904, 0x35b8, 0x9096,
+	0x00ff, 0x0120, 0x9092, 0x0004, 0x1a04, 0x35b8, 0x2010, 0x2918,
+	0x080c, 0x31c4, 0x1120, 0x2009, 0x0003, 0x0804, 0x35b5, 0x7007,
+	0x0003, 0x701f, 0x4ad4, 0x0005, 0xa830, 0x9086, 0x0100, 0x1904,
+	0x3583, 0x2009, 0x0004, 0x0804, 0x35b5, 0x7984, 0x080c, 0xaead,
+	0x1120, 0x9182, 0x007f, 0x0a04, 0x35b8, 0x9186, 0x00ff, 0x0904,
+	0x35b8, 0x9182, 0x0800, 0x1a04, 0x35b8, 0x2001, 0x9400, 0x080c,
+	0x570c, 0x1904, 0x35b5, 0x0804, 0x3583, 0xa998, 0x080c, 0xaead,
+	0x1118, 0x9182, 0x007f, 0x0280, 0x9186, 0x00ff, 0x0168, 0x9182,
+	0x0800, 0x1250, 0x2001, 0x9400, 0x080c, 0x570c, 0x11a8, 0x0060,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0000, 0x0005, 0x2009, 0x000a, 0x0c48, 0x080c,
+	0x0fff, 0x0198, 0x9006, 0xa802, 0x7014, 0x9005, 0x1120, 0x2900,
+	0x7016, 0x701a, 0x0040, 0x7018, 0xa802, 0x0086, 0x2040, 0x2900,
+	0xa006, 0x701a, 0x008e, 0x9085, 0x0001, 0x0005, 0x7984, 0x080c,
+	0x6699, 0x1130, 0x7e88, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0208,
+	0x905e, 0x8bff, 0x0005, 0xa998, 0x080c, 0x6699, 0x1130, 0xae9c,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x0208, 0x905e, 0x8bff, 0x0005,
+	0xae98, 0x0008, 0x7e84, 0x2608, 0x080c, 0x6699, 0x1108, 0x0008,
+	0x905e, 0x8bff, 0x0005, 0x0016, 0x7114, 0x81ff, 0x0128, 0x2148,
+	0xa904, 0x080c, 0x1031, 0x0cc8, 0x7116, 0x711a, 0x001e, 0x0005,
+	0x2031, 0x0001, 0x0010, 0x2031, 0x0000, 0x2061, 0x18b8, 0x2c44,
+	0xa66a, 0xa17a, 0xa772, 0xa076, 0xa28e, 0xa392, 0xa496, 0xa59a,
+	0x080c, 0x10e9, 0x7007, 0x0002, 0x701f, 0x3583, 0x0005, 0x00f6,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, 0x18b0, 0x2004,
+	0x9005, 0x1190, 0x0e04, 0x4b9c, 0x7a36, 0x7833, 0x0012, 0x7a82,
+	0x7b86, 0x7c8a, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x119b, 0x0804, 0x4c02, 0x0016, 0x0086, 0x0096, 0x00c6,
+	0x00e6, 0x2071, 0x189e, 0x7044, 0x9005, 0x1540, 0x7148, 0x9182,
+	0x0010, 0x0288, 0x7038, 0x2060, 0x080c, 0x0fff, 0x0904, 0x4bfa,
+	0xa84b, 0x0000, 0x2900, 0x7046, 0x2001, 0x0002, 0x9080, 0x20ce,
+	0x2005, 0xa846, 0x0098, 0x7038, 0x90e0, 0x0004, 0x2001, 0x18ba,
+	0x9c82, 0x18fa, 0x0210, 0x2061, 0x18ba, 0x2c00, 0x703a, 0x7148,
+	0x81ff, 0x1108, 0x703e, 0x8108, 0x714a, 0x0460, 0x7148, 0x8108,
+	0x714a, 0x7044, 0x2040, 0xa144, 0x2105, 0x0016, 0x908a, 0x0036,
+	0x1a0c, 0x0dd5, 0x2060, 0x001e, 0x8108, 0x2105, 0x9005, 0xa146,
+	0x1520, 0x080c, 0x0fff, 0x1130, 0x8109, 0xa946, 0x7148, 0x8109,
+	0x714a, 0x00d8, 0x9006, 0xa806, 0xa84a, 0xa046, 0x2800, 0xa802,
+	0x2900, 0xa006, 0x7046, 0x2001, 0x0002, 0x9080, 0x20ce, 0x2005,
+	0xa846, 0x0058, 0x2262, 0x6306, 0x640a, 0x00ee, 0x00ce, 0x009e,
+	0x008e, 0x001e, 0x012e, 0x00fe, 0x0005, 0x2c00, 0x9082, 0x001b,
+	0x0002, 0x4c24, 0x4c24, 0x4c26, 0x4c24, 0x4c24, 0x4c24, 0x4c2a,
+	0x4c24, 0x4c24, 0x4c24, 0x4c2e, 0x4c24, 0x4c24, 0x4c24, 0x4c32,
+	0x4c24, 0x4c24, 0x4c24, 0x4c36, 0x4c24, 0x4c24, 0x4c24, 0x4c3a,
+	0x4c24, 0x4c24, 0x4c24, 0x4c3f, 0x080c, 0x0dd5, 0xa276, 0xa37a,
+	0xa47e, 0x0898, 0xa286, 0xa38a, 0xa48e, 0x0878, 0xa296, 0xa39a,
+	0xa49e, 0x0858, 0xa2a6, 0xa3aa, 0xa4ae, 0x0838, 0xa2b6, 0xa3ba,
+	0xa4be, 0x0818, 0xa2c6, 0xa3ca, 0xa4ce, 0x0804, 0x4bfd, 0xa2d6,
+	0xa3da, 0xa4de, 0x0804, 0x4bfd, 0x00e6, 0x2071, 0x189e, 0x7048,
+	0x9005, 0x0904, 0x4cd6, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4cd5,
+	0x00f6, 0x2079, 0x0000, 0x00c6, 0x0096, 0x0086, 0x0076, 0x9006,
+	0x2038, 0x7040, 0x2048, 0x9005, 0x0500, 0xa948, 0x2105, 0x0016,
+	0x908a, 0x0036, 0x1a0c, 0x0dd5, 0x2060, 0x001e, 0x8108, 0x2105,
+	0x9005, 0xa94a, 0x1904, 0x4cd8, 0xa804, 0x9005, 0x090c, 0x0dd5,
+	0x7042, 0x2938, 0x2040, 0xa003, 0x0000, 0x2001, 0x0002, 0x9080,
+	0x20ce, 0x2005, 0xa04a, 0x0804, 0x4cd8, 0x703c, 0x2060, 0x2c14,
+	0x6304, 0x6408, 0x650c, 0x2200, 0x7836, 0x7833, 0x0012, 0x7882,
+	0x2300, 0x7886, 0x2400, 0x788a, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x190c, 0x119b, 0x87ff, 0x0118, 0x2748, 0x080c,
+	0x1031, 0x7048, 0x8001, 0x704a, 0x9005, 0x1170, 0x7040, 0x2048,
+	0x9005, 0x0128, 0x080c, 0x1031, 0x9006, 0x7042, 0x7046, 0x703b,
+	0x18ba, 0x703f, 0x18ba, 0x0420, 0x7040, 0x9005, 0x1508, 0x7238,
+	0x2c00, 0x9206, 0x0148, 0x9c80, 0x0004, 0x90fa, 0x18fa, 0x0210,
+	0x2001, 0x18ba, 0x703e, 0x00a0, 0x9006, 0x703e, 0x703a, 0x7044,
+	0x9005, 0x090c, 0x0dd5, 0x2048, 0xa800, 0x9005, 0x1de0, 0x2900,
+	0x7042, 0x2001, 0x0002, 0x9080, 0x20ce, 0x2005, 0xa84a, 0x0000,
+	0x007e, 0x008e, 0x009e, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005,
+	0x2c00, 0x9082, 0x001b, 0x0002, 0x4cf7, 0x4cf7, 0x4cf9, 0x4cf7,
+	0x4cf7, 0x4cf7, 0x4cfe, 0x4cf7, 0x4cf7, 0x4cf7, 0x4d03, 0x4cf7,
+	0x4cf7, 0x4cf7, 0x4d08, 0x4cf7, 0x4cf7, 0x4cf7, 0x4d0d, 0x4cf7,
+	0x4cf7, 0x4cf7, 0x4d12, 0x4cf7, 0x4cf7, 0x4cf7, 0x4d17, 0x080c,
+	0x0dd5, 0xaa74, 0xab78, 0xac7c, 0x0804, 0x4c83, 0xaa84, 0xab88,
+	0xac8c, 0x0804, 0x4c83, 0xaa94, 0xab98, 0xac9c, 0x0804, 0x4c83,
+	0xaaa4, 0xaba8, 0xacac, 0x0804, 0x4c83, 0xaab4, 0xabb8, 0xacbc,
+	0x0804, 0x4c83, 0xaac4, 0xabc8, 0xaccc, 0x0804, 0x4c83, 0xaad4,
+	0xabd8, 0xacdc, 0x0804, 0x4c83, 0x0016, 0x0026, 0x0036, 0x00b6,
+	0x00c6, 0x2009, 0x007e, 0x080c, 0x6699, 0x2019, 0x0001, 0xb85c,
+	0xd0ac, 0x0110, 0x2019, 0x0000, 0x2011, 0x801b, 0x080c, 0x4b7f,
+	0x00ce, 0x00be, 0x003e, 0x002e, 0x001e, 0x0005, 0x0026, 0x080c,
+	0x575d, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x4b7f, 0x002e,
+	0x0005, 0x81ff, 0x1904, 0x35b5, 0x0126, 0x2091, 0x8000, 0x6030,
+	0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x743e, 0x1158, 0x080c,
+	0x7724, 0x080c, 0x60ad, 0x9085, 0x0001, 0x080c, 0x7485, 0x080c,
+	0x736a, 0x0010, 0x080c, 0x5f6c, 0x012e, 0x0804, 0x3583, 0x81ff,
+	0x0120, 0x2009, 0x0001, 0x0804, 0x35b5, 0x080c, 0x5771, 0x0120,
+	0x2009, 0x0007, 0x0804, 0x35b5, 0x080c, 0x6a04, 0x0120, 0x2009,
+	0x0008, 0x0804, 0x35b5, 0x7984, 0x080c, 0x6638, 0x1904, 0x35b8,
+	0x080c, 0x4b52, 0x0904, 0x35b8, 0x2b00, 0x7026, 0x080c, 0x6a0c,
+	0x7888, 0x1170, 0x9084, 0x0005, 0x1158, 0x900e, 0x080c, 0x68b9,
+	0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x3583,
+	0x080c, 0x4b1f, 0x0904, 0x35b5, 0x9006, 0xa866, 0xa832, 0xa868,
+	0xc0fd, 0xa86a, 0x080c, 0xceb0, 0x0904, 0x35b5, 0x7888, 0xd094,
+	0x0118, 0xb8cc, 0xc08d, 0xb8ce, 0x7007, 0x0003, 0x701f, 0x4df2,
+	0x0005, 0x2061, 0x1800, 0x080c, 0x5771, 0x2009, 0x0007, 0x1560,
+	0x080c, 0x6a04, 0x0118, 0x2009, 0x0008, 0x0430, 0xa998, 0x080c,
+	0x6638, 0x1530, 0x080c, 0x4b50, 0x0518, 0x080c, 0x6a0c, 0xa89c,
+	0x1168, 0x9084, 0x0005, 0x1150, 0x900e, 0x080c, 0x68b9, 0x1108,
+	0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x00d0, 0xa868, 0xc0fc,
+	0xa86a, 0x080c, 0xceb0, 0x11e0, 0xa89c, 0xd094, 0x0118, 0xb8cc,
+	0xc08d, 0xb8ce, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, 0x0010,
+	0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005,
+	0xa897, 0x4000, 0xa99a, 0x9006, 0x918d, 0x0001, 0x2008, 0x0005,
+	0x9006, 0x0005, 0xa830, 0x9086, 0x0100, 0x7024, 0x2058, 0x1110,
+	0x0804, 0x56b1, 0x900e, 0x080c, 0x68b9, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0x0804, 0x3583, 0x080c, 0x5771, 0x0120,
+	0x2009, 0x0007, 0x0804, 0x35b5, 0x7f84, 0x7a8c, 0x7b88, 0x7c9c,
+	0x7d98, 0x080c, 0x4b1f, 0x1120, 0x2009, 0x0002, 0x0804, 0x35b5,
+	0x900e, 0x2130, 0x7126, 0x7132, 0xa860, 0x20e8, 0x7036, 0xa85c,
+	0x9080, 0x0005, 0x702a, 0x20a0, 0x080c, 0x6699, 0x1904, 0x4e94,
+	0x080c, 0x6a0c, 0x0138, 0x080c, 0x6a14, 0x0120, 0x080c, 0x69ac,
+	0x1904, 0x4e94, 0xd794, 0x1110, 0xd784, 0x01a8, 0xb8c4, 0x20e0,
+	0xb8c8, 0x9080, 0x0006, 0x2098, 0x3400, 0xd794, 0x0160, 0x20a9,
+	0x0008, 0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x20a9, 0x0002,
+	0x080c, 0x491e, 0x0048, 0x20a9, 0x0004, 0x4003, 0x2098, 0x20a0,
+	0x3d00, 0x20e0, 0x080c, 0x491e, 0x9186, 0x007e, 0x0170, 0x9186,
+	0x0080, 0x0158, 0x080c, 0x6a0c, 0x90c2, 0x0006, 0x1210, 0xc1fd,
+	0x0020, 0x080c, 0x68b9, 0x1108, 0xc1fd, 0x4104, 0xc1fc, 0xd794,
+	0x0528, 0xb8c4, 0x20e0, 0xb8c8, 0x2060, 0x9c80, 0x0000, 0x2098,
+	0x20a9, 0x0002, 0x4003, 0x9c80, 0x0003, 0x2098, 0x20a9, 0x0001,
+	0x4005, 0x9c80, 0x0004, 0x2098, 0x3400, 0x20a9, 0x0002, 0x4003,
+	0x2098, 0x20a0, 0x3d00, 0x20e0, 0x080c, 0x4911, 0x9c80, 0x0026,
+	0x2098, 0xb8c4, 0x20e0, 0x20a9, 0x0002, 0x4003, 0xd794, 0x0110,
+	0x96b0, 0x000b, 0x96b0, 0x0005, 0x8108, 0x080c, 0xaead, 0x0118,
+	0x9186, 0x0800, 0x0040, 0xd78c, 0x0120, 0x9186, 0x0800, 0x0170,
+	0x0018, 0x9186, 0x007e, 0x0150, 0xd794, 0x0118, 0x9686, 0x0020,
+	0x0010, 0x9686, 0x0028, 0x0150, 0x0804, 0x4e24, 0x86ff, 0x1120,
+	0x7124, 0x810b, 0x0804, 0x3583, 0x7033, 0x0001, 0x7122, 0x7024,
+	0x9600, 0x7026, 0x772e, 0x2061, 0x18b8, 0x2c44, 0xa06b, 0x0000,
+	0xa67a, 0x7034, 0xa072, 0x7028, 0xa076, 0xa28e, 0xa392, 0xa496,
+	0xa59a, 0x080c, 0x10e9, 0x7007, 0x0002, 0x701f, 0x4ed0, 0x0005,
+	0x7030, 0x9005, 0x1180, 0x7120, 0x7028, 0x20a0, 0x772c, 0x9036,
+	0x7034, 0x20e8, 0x2061, 0x18b8, 0x2c44, 0xa28c, 0xa390, 0xa494,
+	0xa598, 0x0804, 0x4e24, 0x7124, 0x810b, 0x0804, 0x3583, 0x2029,
+	0x007e, 0x7984, 0x7a88, 0x7b8c, 0x7c98, 0x9184, 0xff00, 0x8007,
+	0x90e2, 0x0020, 0x0a04, 0x35b8, 0x9502, 0x0a04, 0x35b8, 0x9184,
+	0x00ff, 0x90e2, 0x0020, 0x0a04, 0x35b8, 0x9502, 0x0a04, 0x35b8,
+	0x9284, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x35b8, 0x9502,
+	0x0a04, 0x35b8, 0x9284, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x35b8,
+	0x9502, 0x0a04, 0x35b8, 0x9384, 0xff00, 0x8007, 0x90e2, 0x0020,
+	0x0a04, 0x35b8, 0x9502, 0x0a04, 0x35b8, 0x9384, 0x00ff, 0x90e2,
+	0x0020, 0x0a04, 0x35b8, 0x9502, 0x0a04, 0x35b8, 0x9484, 0xff00,
+	0x8007, 0x90e2, 0x0020, 0x0a04, 0x35b8, 0x9502, 0x0a04, 0x35b8,
+	0x9484, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x35b8, 0x9502, 0x0a04,
+	0x35b8, 0x2061, 0x1988, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804,
+	0x3583, 0x080c, 0x4b1f, 0x0904, 0x35b5, 0x2009, 0x0016, 0x7a8c,
+	0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c,
+	0x4b68, 0x701f, 0x4f54, 0x0005, 0x2001, 0x0138, 0x2003, 0x0000,
+	0x00e6, 0x2071, 0x0300, 0x701c, 0xd0a4, 0x1de8, 0x00ee, 0x20a9,
+	0x0016, 0x896e, 0x8d6e, 0x8d6f, 0x9d84, 0xffc0, 0x9080, 0x0019,
+	0x2098, 0x9d84, 0x003f, 0x20e0, 0x2069, 0x1877, 0x20e9, 0x0001,
+	0x2da0, 0x4003, 0x6800, 0x9005, 0x0904, 0x4fd5, 0x6804, 0x2008,
+	0x918c, 0xfff8, 0x1904, 0x4fd5, 0x680c, 0x9005, 0x0904, 0x4fd5,
+	0x9082, 0xff01, 0x1a04, 0x4fd5, 0x6810, 0x9082, 0x005c, 0x0a04,
+	0x4fd5, 0x6824, 0x2008, 0x9082, 0x0008, 0x0a04, 0x4fd5, 0x9182,
+	0x0400, 0x1a04, 0x4fd5, 0x0056, 0x2029, 0x0000, 0x080c, 0x8bbf,
+	0x005e, 0x6944, 0x6820, 0x9102, 0x06c0, 0x6820, 0x9082, 0x0019,
+	0x16a0, 0x6828, 0x6944, 0x810c, 0x9102, 0x0678, 0x6840, 0x9082,
+	0x000f, 0x1658, 0x080c, 0x1018, 0x2900, 0x0904, 0x4ff1, 0x684e,
+	0x00e6, 0x2071, 0x1930, 0x00b6, 0x2059, 0x0000, 0x080c, 0x8a7b,
+	0x00be, 0x00ee, 0x0568, 0x080c, 0x87ce, 0x080c, 0x8819, 0x11e0,
+	0x6857, 0x0000, 0x00c6, 0x2061, 0x0100, 0x6104, 0x918d, 0x2000,
+	0x6106, 0x6b10, 0x2061, 0x1a61, 0x630a, 0x00ce, 0x080c, 0x2994,
+	0x2001, 0x0138, 0x2102, 0x0804, 0x3583, 0x080c, 0x2994, 0x2001,
+	0x0138, 0x2102, 0x0804, 0x35b8, 0x080c, 0x8812, 0x00e6, 0x2071,
+	0x1930, 0x080c, 0x8c3f, 0x080c, 0x8c4e, 0x080c, 0x8a62, 0x00ee,
+	0x2001, 0x188a, 0x204c, 0x080c, 0x1031, 0x2001, 0x188a, 0x2003,
+	0x0000, 0x080c, 0x2994, 0x2001, 0x0138, 0x2102, 0x0804, 0x35b5,
+	0x2001, 0x1924, 0x200c, 0x918e, 0x0000, 0x0904, 0x5052, 0x080c,
+	0x8a5d, 0x0904, 0x5052, 0x2001, 0x0101, 0x200c, 0x918c, 0xdfff,
+	0x2102, 0x2001, 0x0138, 0x2003, 0x0000, 0x00e6, 0x2071, 0x0300,
+	0x701c, 0xd0a4, 0x1de8, 0x00ee, 0x080c, 0x8a62, 0x2001, 0x0035,
+	0x080c, 0x15fd, 0x00c6, 0x2061, 0x193c, 0x6004, 0x6100, 0x9106,
+	0x1de0, 0x00ce, 0x080c, 0x2994, 0x2001, 0x0138, 0x2102, 0x00e6,
+	0x00f6, 0x2071, 0x1923, 0x080c, 0x899c, 0x0120, 0x2f00, 0x080c,
+	0x8a28, 0x0cc8, 0x00fe, 0x00ee, 0x0126, 0x2091, 0x8000, 0x2001,
+	0x188a, 0x200c, 0x81ff, 0x0138, 0x2148, 0x080c, 0x1031, 0x2001,
+	0x188a, 0x2003, 0x0000, 0x2001, 0x183c, 0x2003, 0x0020, 0x080c,
+	0x8812, 0x00e6, 0x2071, 0x1930, 0x080c, 0x8c3f, 0x080c, 0x8c4e,
+	0x00ee, 0x012e, 0x0804, 0x3583, 0x0006, 0x080c, 0x575d, 0xd0cc,
+	0x000e, 0x0005, 0x0006, 0x080c, 0x5761, 0xd0bc, 0x000e, 0x0005,
+	0x6174, 0x7a84, 0x6300, 0x82ff, 0x1118, 0x7986, 0x0804, 0x3583,
+	0x83ff, 0x1904, 0x35b8, 0x2001, 0xfff0, 0x9200, 0x1a04, 0x35b8,
+	0x2019, 0xffff, 0x6078, 0x9302, 0x9200, 0x0a04, 0x35b8, 0x7986,
+	0x6276, 0x0804, 0x3583, 0x080c, 0x5771, 0x1904, 0x35b5, 0x7c88,
+	0x7d84, 0x7e98, 0x7f8c, 0x080c, 0x4b1f, 0x0904, 0x35b5, 0x900e,
+	0x901e, 0x7326, 0x7332, 0xa860, 0x20e8, 0x7036, 0xa85c, 0x9080,
+	0x0003, 0x702a, 0x20a0, 0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178,
+	0x080c, 0x6a0c, 0x0118, 0x080c, 0x6a14, 0x1148, 0x20a9, 0x0001,
+	0xb814, 0x4004, 0xb810, 0x4004, 0x4104, 0x9398, 0x0003, 0x8108,
+	0x9182, 0x0800, 0x0120, 0x9386, 0x003c, 0x0170, 0x0c20, 0x83ff,
+	0x1148, 0x7224, 0x900e, 0x2001, 0x0003, 0x080c, 0x9027, 0x2208,
+	0x0804, 0x3583, 0x7033, 0x0001, 0x7122, 0x7024, 0x9300, 0x7026,
+	0x2061, 0x18b8, 0x2c44, 0xa06b, 0x0000, 0xa37a, 0x7028, 0xa076,
+	0x7034, 0xa072, 0xa48e, 0xa592, 0xa696, 0xa79a, 0x080c, 0x10e9,
+	0x7007, 0x0002, 0x701f, 0x50d5, 0x0005, 0x7030, 0x9005, 0x1178,
+	0x7120, 0x7028, 0x20a0, 0x901e, 0x7034, 0x20e8, 0x2061, 0x18b8,
+	0x2c44, 0xa48c, 0xa590, 0xa694, 0xa798, 0x0804, 0x5093, 0x7224,
+	0x900e, 0x2001, 0x0003, 0x080c, 0x9027, 0x2208, 0x0804, 0x3583,
+	0x00f6, 0x00e6, 0x080c, 0x5771, 0x2009, 0x0007, 0x1904, 0x5168,
+	0x2071, 0x189e, 0x745c, 0x84ff, 0x2009, 0x000e, 0x1904, 0x5168,
+	0xac9c, 0xad98, 0xaea4, 0xafa0, 0x0096, 0x080c, 0x1018, 0x2009,
+	0x0002, 0x0904, 0x5168, 0x2900, 0x705e, 0x900e, 0x901e, 0x7356,
+	0x7362, 0xa860, 0x7066, 0xa85c, 0x9080, 0x0003, 0x705a, 0x20a0,
+	0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178, 0x080c, 0x6a0c, 0x0118,
+	0x080c, 0x6a14, 0x1148, 0xb814, 0x20a9, 0x0001, 0x4004, 0xb810,
+	0x4004, 0x4104, 0x9398, 0x0003, 0x8108, 0x9182, 0x0800, 0x0120,
+	0x9386, 0x003c, 0x01e8, 0x0c20, 0x83ff, 0x11c0, 0x7254, 0x900e,
+	0x2001, 0x0003, 0x080c, 0x9027, 0x2208, 0x009e, 0xa897, 0x4000,
+	0xa99a, 0x715c, 0x81ff, 0x090c, 0x0dd5, 0x2148, 0x080c, 0x1031,
+	0x9006, 0x705e, 0x918d, 0x0001, 0x2008, 0x0418, 0x7063, 0x0001,
+	0x7152, 0x7054, 0x9300, 0x7056, 0x2061, 0x18b9, 0x2c44, 0xa37a,
+	0x7058, 0xa076, 0x7064, 0xa072, 0xa48e, 0xa592, 0xa696, 0xa79a,
+	0xa09f, 0x5174, 0x000e, 0xa0a2, 0x080c, 0x10e9, 0x9006, 0x0048,
+	0x009e, 0xa897, 0x4005, 0xa99a, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0030, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0xa0a0, 0x904d, 0x090c,
+	0x0dd5, 0x00e6, 0x2071, 0x189e, 0xa06c, 0x908e, 0x0100, 0x0138,
+	0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4002, 0x00d8, 0x7060,
+	0x9005, 0x1158, 0x7150, 0x7058, 0x20a0, 0x901e, 0x7064, 0x20e8,
+	0xa48c, 0xa590, 0xa694, 0xa798, 0x0428, 0xa87b, 0x0000, 0xa883,
+	0x0000, 0xa897, 0x4000, 0x7254, 0x900e, 0x2001, 0x0003, 0x080c,
+	0x9027, 0xaa9a, 0x715c, 0x81ff, 0x090c, 0x0dd5, 0x2148, 0x080c,
+	0x1031, 0x705f, 0x0000, 0xa0a0, 0x2048, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6d17, 0x012e, 0xa09f, 0x0000, 0xa0a3, 0x0000, 0x00ee,
+	0x00fe, 0x0005, 0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178, 0x080c,
+	0x6a0c, 0x0118, 0x080c, 0x6a14, 0x1148, 0xb814, 0x20a9, 0x0001,
+	0x4004, 0xb810, 0x4004, 0x4104, 0x9398, 0x0003, 0x8108, 0x9182,
+	0x0800, 0x0120, 0x9386, 0x003c, 0x0518, 0x0c20, 0x83ff, 0x11f0,
+	0x7154, 0x810c, 0xa99a, 0xa897, 0x4000, 0x715c, 0x81ff, 0x090c,
+	0x0dd5, 0x2148, 0x080c, 0x1031, 0x9006, 0x705e, 0x918d, 0x0001,
+	0x2008, 0xa0a0, 0x2048, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17,
+	0x012e, 0xa09f, 0x0000, 0xa0a3, 0x0000, 0x0070, 0x7063, 0x0001,
+	0x7152, 0x7054, 0x9300, 0x7056, 0xa37a, 0xa48e, 0xa592, 0xa696,
+	0xa79a, 0x080c, 0x10e9, 0x9006, 0x00ee, 0x0005, 0x0096, 0xa88c,
+	0x90be, 0x7000, 0x0148, 0x90be, 0x7100, 0x0130, 0x90be, 0x7200,
+	0x0118, 0x009e, 0x0804, 0x35b8, 0xa884, 0xa988, 0x080c, 0x287c,
+	0x1518, 0x080c, 0x6638, 0x1500, 0x7126, 0xbe12, 0xbd16, 0xae7c,
+	0x080c, 0x4b1f, 0x01c8, 0x080c, 0x4b1f, 0x01b0, 0x009e, 0xa867,
+	0x0000, 0xa868, 0xc0fd, 0xa86a, 0xa823, 0x0000, 0xa804, 0x2048,
+	0x080c, 0xce32, 0x1120, 0x2009, 0x0003, 0x0804, 0x35b5, 0x7007,
+	0x0003, 0x701f, 0x5241, 0x0005, 0x009e, 0x2009, 0x0002, 0x0804,
+	0x35b5, 0x7124, 0x080c, 0x331a, 0xa820, 0x9086, 0x8001, 0x1120,
+	0x2009, 0x0004, 0x0804, 0x35b5, 0x2900, 0x7022, 0xa804, 0x0096,
+	0x2048, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x009e, 0x9080, 0x0002, 0x0076, 0x0006, 0x2098, 0x20a0, 0x27e0,
+	0x27e8, 0x20a9, 0x002a, 0x080c, 0x0f7c, 0xaa6c, 0xab70, 0xac74,
+	0xad78, 0x2061, 0x18b8, 0x2c44, 0xa06b, 0x0000, 0xae64, 0xaf8c,
+	0x97c6, 0x7000, 0x0118, 0x97c6, 0x7100, 0x1148, 0x96c2, 0x0004,
+	0x0600, 0x2009, 0x0004, 0x000e, 0x007e, 0x0804, 0x4b6b, 0x97c6,
+	0x7200, 0x11b8, 0x96c2, 0x0054, 0x02a0, 0x000e, 0x007e, 0x2061,
+	0x18b8, 0x2c44, 0xa076, 0xa772, 0xa07b, 0x002a, 0xa28e, 0xa392,
+	0xa496, 0xa59a, 0x080c, 0x10e9, 0x7007, 0x0002, 0x701f, 0x529d,
+	0x0005, 0x000e, 0x007e, 0x0804, 0x35b8, 0x7020, 0x2048, 0xa804,
+	0x2048, 0xa804, 0x2048, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f,
+	0x9084, 0xffc0, 0x9080, 0x0002, 0x2098, 0x20a0, 0x27e0, 0x27e8,
+	0x20a9, 0x002a, 0x080c, 0x0f7c, 0x2100, 0x2238, 0x2061, 0x18b8,
+	0x2c44, 0xa28c, 0xa390, 0xa494, 0xa598, 0x2009, 0x002a, 0x0804,
+	0x4b6b, 0x81ff, 0x1904, 0x35b5, 0x798c, 0x2001, 0x197d, 0x918c,
+	0x8000, 0x2102, 0x080c, 0x4b36, 0x0904, 0x35b8, 0x080c, 0x6a0c,
+	0x0120, 0x080c, 0x6a14, 0x1904, 0x35b8, 0x080c, 0x6760, 0x0904,
+	0x35b5, 0x0126, 0x2091, 0x8000, 0x080c, 0x6826, 0x012e, 0x0904,
+	0x35b5, 0x2001, 0x197d, 0x2004, 0xd0fc, 0x1904, 0x3583, 0x0804,
+	0x4586, 0xa9a0, 0x2001, 0x197d, 0x918c, 0x8000, 0xc18d, 0x2102,
+	0x080c, 0x4b43, 0x01a0, 0x080c, 0x6a0c, 0x0118, 0x080c, 0x6a14,
+	0x1170, 0x080c, 0x6760, 0x2009, 0x0002, 0x0128, 0x080c, 0x6826,
+	0x1170, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897,
+	0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897,
+	0x4000, 0x2001, 0x197d, 0x2004, 0xd0fc, 0x1128, 0x080c, 0x5765,
+	0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000,
+	0x0005, 0x78a8, 0xd08c, 0x1118, 0xd084, 0x0904, 0x44fb, 0x080c,
+	0x4b52, 0x0904, 0x35b8, 0x080c, 0x4b1f, 0x1120, 0x2009, 0x0002,
+	0x0804, 0x35b5, 0x080c, 0x6a0c, 0x0130, 0x908e, 0x0004, 0x0118,
+	0x908e, 0x0005, 0x15a0, 0x78a8, 0xd08c, 0x0120, 0xb800, 0xc08c,
+	0xb802, 0x0028, 0x080c, 0x575d, 0xd0b4, 0x0904, 0x4535, 0x7884,
+	0x908e, 0x007e, 0x0904, 0x4535, 0x908e, 0x007f, 0x0904, 0x4535,
+	0x908e, 0x0080, 0x0904, 0x4535, 0xb800, 0xd08c, 0x1904, 0x4535,
+	0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xce51, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x35b5, 0x7007, 0x0003, 0x701f, 0x5369,
+	0x0005, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x0804, 0x4535, 0x080c,
+	0x3373, 0x0108, 0x0005, 0x2009, 0x1834, 0x210c, 0x81ff, 0x0120,
+	0x2009, 0x0001, 0x0804, 0x35b5, 0x080c, 0x5771, 0x0120, 0x2009,
+	0x0007, 0x0804, 0x35b5, 0x080c, 0x6a04, 0x0120, 0x2009, 0x0008,
+	0x0804, 0x35b5, 0xb89c, 0xd0a4, 0x1118, 0xd0ac, 0x1904, 0x4535,
+	0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xceb0,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x35b5, 0x7007, 0x0003, 0x701f,
+	0x53a2, 0x0005, 0xa830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004,
+	0x0804, 0x56b1, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x0804, 0x533b,
+	0x81ff, 0x2009, 0x0001, 0x1904, 0x35b5, 0x080c, 0x5771, 0x2009,
+	0x0007, 0x1904, 0x35b5, 0x080c, 0x6a04, 0x0120, 0x2009, 0x0008,
+	0x0804, 0x35b5, 0x080c, 0x4b52, 0x0904, 0x35b8, 0x080c, 0x6a0c,
+	0x2009, 0x0009, 0x1904, 0x35b5, 0x080c, 0x4b1f, 0x2009, 0x0002,
+	0x0904, 0x35b5, 0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a,
+	0x7988, 0x9194, 0xff00, 0x918c, 0x00ff, 0x9006, 0x82ff, 0x1128,
+	0xc0ed, 0xa952, 0x798c, 0xa956, 0x0038, 0x928e, 0x0100, 0x1904,
+	0x35b8, 0xc0e5, 0xa952, 0xa956, 0xa83e, 0x080c, 0xd103, 0x2009,
+	0x0003, 0x0904, 0x35b5, 0x7007, 0x0003, 0x701f, 0x53f8, 0x0005,
+	0xa830, 0x9086, 0x0100, 0x2009, 0x0004, 0x0904, 0x35b5, 0x0804,
+	0x3583, 0x7aa8, 0x9284, 0xc000, 0x0148, 0xd2ec, 0x01a0, 0x080c,
+	0x5771, 0x1188, 0x2009, 0x0014, 0x0804, 0x35b5, 0xd2dc, 0x1578,
+	0x81ff, 0x2009, 0x0001, 0x1904, 0x35b5, 0x080c, 0x5771, 0x2009,
+	0x0007, 0x1904, 0x35b5, 0xd2f4, 0x0138, 0x9284, 0x5000, 0xc0d5,
+	0x080c, 0x5737, 0x0804, 0x3583, 0xd2fc, 0x0160, 0x080c, 0x4b52,
+	0x0904, 0x35b8, 0x7984, 0x9284, 0x9000, 0xc0d5, 0x080c, 0x570c,
+	0x0804, 0x3583, 0x080c, 0x4b52, 0x0904, 0x35b8, 0xb804, 0x9084,
+	0x00ff, 0x9086, 0x0006, 0x2009, 0x0009, 0x1904, 0x54e7, 0x080c,
+	0x4b1f, 0x2009, 0x0002, 0x0904, 0x54e7, 0xa85c, 0x9080, 0x001b,
+	0xaf60, 0x2009, 0x0008, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x080c,
+	0x4b68, 0x701f, 0x5454, 0x0005, 0xa86c, 0x9086, 0x0500, 0x1138,
+	0xa870, 0x9005, 0x1120, 0xa874, 0x9084, 0xff00, 0x0110, 0x1904,
+	0x35b8, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0x4b52,
+	0x1110, 0x0804, 0x35b8, 0x2009, 0x0043, 0x080c, 0xd16b, 0x2009,
+	0x0003, 0x0904, 0x54e7, 0x7007, 0x0003, 0x701f, 0x5478, 0x0005,
+	0xa830, 0x9086, 0x0100, 0x2009, 0x0004, 0x0904, 0x54e7, 0x7984,
+	0x7aa8, 0x9284, 0x1000, 0xe085, 0x080c, 0x570c, 0x0804, 0x3583,
+	0x00c6, 0xaab0, 0x9284, 0xc000, 0x0148, 0xd2ec, 0x0170, 0x080c,
+	0x5771, 0x1158, 0x2009, 0x0014, 0x0804, 0x54d6, 0x2061, 0x1800,
+	0x080c, 0x5771, 0x2009, 0x0007, 0x15c8, 0xd2f4, 0x0130, 0x9284,
+	0x5000, 0xc0d5, 0x080c, 0x5737, 0x0058, 0xd2fc, 0x0180, 0x080c,
+	0x4b50, 0x0590, 0xa998, 0x9284, 0x9000, 0xc0d5, 0x080c, 0x570c,
+	0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x0438, 0x080c,
+	0x4b50, 0x0510, 0x080c, 0x6a0c, 0x2009, 0x0009, 0x11b8, 0xa8c4,
+	0x9086, 0x0500, 0x11c8, 0xa8c8, 0x9005, 0x11b0, 0xa8cc, 0x9084,
+	0xff00, 0x1190, 0x080c, 0x4b50, 0x1108, 0x0070, 0x2009, 0x004b,
+	0x080c, 0xd16b, 0x2009, 0x0003, 0x0108, 0x0078, 0x0431, 0x19c0,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x00ce, 0x0005, 0x9006, 0x0ce0, 0x7aa8,
+	0xd2dc, 0x0904, 0x35b5, 0x0016, 0x7984, 0x9284, 0x1000, 0xc0fd,
+	0x080c, 0x570c, 0x001e, 0x1904, 0x35b5, 0x0804, 0x3583, 0x00f6,
+	0x2d78, 0xaab0, 0x0021, 0x00fe, 0x0005, 0xaab0, 0xc2d5, 0xd2dc,
+	0x0150, 0x0016, 0xa998, 0x9284, 0x1400, 0xc0fd, 0x080c, 0x570c,
+	0x001e, 0x9085, 0x0001, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x35b5, 0x080c, 0x5771, 0x0120, 0x2009, 0x0007, 0x0804,
+	0x35b5, 0x7984, 0x7ea8, 0x96b4, 0x00ff, 0x080c, 0x6699, 0x1904,
+	0x35b8, 0x9186, 0x007f, 0x0138, 0x080c, 0x6a0c, 0x0120, 0x2009,
+	0x0009, 0x0804, 0x35b5, 0x080c, 0x4b1f, 0x1120, 0x2009, 0x0002,
+	0x0804, 0x35b5, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x2001,
+	0x0100, 0x8007, 0xa80a, 0x080c, 0xce6b, 0x1120, 0x2009, 0x0003,
+	0x0804, 0x35b5, 0x7007, 0x0003, 0x701f, 0x5547, 0x0005, 0xa808,
+	0x8007, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x35b5,
+	0xa8e0, 0xa866, 0xa810, 0x8007, 0x9084, 0x00ff, 0x800c, 0xa814,
+	0x8007, 0x9084, 0x00ff, 0x8004, 0x9080, 0x0002, 0x9108, 0x8906,
+	0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0004,
+	0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, 0x4b6b, 0x080c, 0x4b1f,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x35b5, 0x7984, 0x9194, 0xff00,
+	0x918c, 0x00ff, 0x8217, 0x82ff, 0x1118, 0x7023, 0x19b2, 0x0040,
+	0x92c6, 0x0001, 0x1118, 0x7023, 0x19cc, 0x0010, 0x0804, 0x35b8,
+	0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080,
+	0x0019, 0xaf60, 0x080c, 0x4b68, 0x701f, 0x5597, 0x0005, 0x2001,
+	0x182e, 0x2003, 0x0001, 0xa85c, 0x9080, 0x0019, 0x2098, 0xa860,
+	0x20e0, 0x20a9, 0x001a, 0x7020, 0x20a0, 0x20e9, 0x0001, 0x4003,
+	0x0804, 0x3583, 0x080c, 0x4b1f, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x35b5, 0x7984, 0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff,
+	0x1118, 0x2099, 0x19b2, 0x0040, 0x92c6, 0x0001, 0x1118, 0x2099,
+	0x19cc, 0x0010, 0x0804, 0x35b8, 0xa85c, 0x9080, 0x0019, 0x20a0,
+	0xa860, 0x20e8, 0x20a9, 0x001a, 0x20e1, 0x0001, 0x4003, 0x2009,
+	0x001a, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080, 0x0019,
+	0xaf60, 0x0804, 0x4b6b, 0x7884, 0x908a, 0x1000, 0x1a04, 0x35b8,
+	0x0126, 0x2091, 0x8000, 0x8003, 0x800b, 0x810b, 0x9108, 0x00c6,
+	0x2061, 0x19f9, 0x6142, 0x00ce, 0x012e, 0x0804, 0x3583, 0x00c6,
+	0x080c, 0x743e, 0x1160, 0x080c, 0x7724, 0x080c, 0x60ad, 0x9085,
+	0x0001, 0x080c, 0x7485, 0x080c, 0x736a, 0x080c, 0x0dd5, 0x2061,
+	0x1800, 0x6030, 0xc09d, 0x6032, 0x080c, 0x5f6c, 0x00ce, 0x0005,
+	0x00c6, 0x2001, 0x1800, 0x2004, 0x908e, 0x0000, 0x0904, 0x35b5,
+	0x7884, 0x9005, 0x0188, 0x7888, 0x2061, 0x199b, 0x2c0c, 0x2062,
+	0x080c, 0x2c5e, 0x01a0, 0x080c, 0x2c66, 0x0188, 0x080c, 0x2c6e,
+	0x0170, 0x2162, 0x0804, 0x35b8, 0x2061, 0x0100, 0x6038, 0x9086,
+	0x0007, 0x1118, 0x2009, 0x0001, 0x0010, 0x2009, 0x0000, 0x7884,
+	0x9086, 0x0002, 0x1568, 0x2061, 0x0100, 0x6028, 0xc09c, 0x602a,
+	0x0026, 0x2011, 0x0003, 0x080c, 0xa722, 0x2011, 0x0002, 0x080c,
+	0xa72c, 0x002e, 0x080c, 0xa636, 0x0036, 0x901e, 0x080c, 0xa6ac,
+	0x003e, 0x60e3, 0x0000, 0x080c, 0xeb79, 0x080c, 0xeb94, 0x9085,
+	0x0001, 0x080c, 0x7485, 0x9006, 0x080c, 0x2d4e, 0x2001, 0x1800,
+	0x2003, 0x0004, 0x2001, 0x19a6, 0x2003, 0x0000, 0x6027, 0x0008,
+	0x00ce, 0x0804, 0x3583, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x35b5, 0x080c, 0x5771, 0x0120, 0x2009, 0x0007, 0x0804, 0x35b5,
+	0x7984, 0x7ea8, 0x96b4, 0x00ff, 0x080c, 0x6699, 0x1904, 0x35b8,
+	0x9186, 0x007f, 0x0138, 0x080c, 0x6a0c, 0x0120, 0x2009, 0x0009,
+	0x0804, 0x35b5, 0x080c, 0x4b1f, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x35b5, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xce6e,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x35b5, 0x7007, 0x0003, 0x701f,
+	0x569a, 0x0005, 0xa830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004,
+	0x0804, 0x35b5, 0xa8e0, 0xa866, 0xa834, 0x8007, 0x800c, 0xa85c,
+	0x9080, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xaf60, 0x0804,
+	0x4b6b, 0xa898, 0x9086, 0x000d, 0x1904, 0x35b5, 0x2021, 0x4005,
+	0x0126, 0x2091, 0x8000, 0x0e04, 0x56be, 0x0010, 0x012e, 0x0cc0,
+	0x7c36, 0x9486, 0x4000, 0x0118, 0x7833, 0x0011, 0x0010, 0x7833,
+	0x0010, 0x7883, 0x4005, 0xa998, 0x7986, 0xa9a4, 0x799a, 0xa9a8,
+	0x799e, 0x080c, 0x4b5b, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004,
+	0xd084, 0x190c, 0x119b, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f,
+	0x0000, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061,
+	0x19f9, 0x7984, 0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009,
+	0x7898, 0x606a, 0x789c, 0x6066, 0x7888, 0x6062, 0x788c, 0x605e,
+	0x2001, 0x1a07, 0x2044, 0x2001, 0x1a0e, 0xa076, 0xa060, 0xa072,
+	0xa07b, 0x0001, 0xa07f, 0x0002, 0xa06b, 0x0000, 0xa09f, 0x0000,
+	0x00ce, 0x012e, 0x0804, 0x3583, 0x0126, 0x2091, 0x8000, 0x00b6,
+	0x00c6, 0x90e4, 0xc000, 0x0168, 0x0006, 0xd0d4, 0x0130, 0x0036,
+	0x2019, 0x0029, 0x080c, 0x3338, 0x003e, 0x080c, 0xccd3, 0x000e,
+	0x1198, 0xd0e4, 0x0160, 0x9180, 0x1000, 0x2004, 0x905d, 0x0160,
+	0x080c, 0x60c7, 0x080c, 0xaead, 0x0110, 0xb817, 0x0000, 0x9006,
+	0x00ce, 0x00be, 0x012e, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x0126,
+	0x2091, 0x8000, 0x0156, 0x2010, 0x900e, 0x20a9, 0x0800, 0x0016,
+	0x9180, 0x1000, 0x2004, 0x9005, 0x0188, 0x9186, 0x007e, 0x0170,
+	0x9186, 0x007f, 0x0158, 0x9186, 0x0080, 0x0140, 0x9186, 0x00ff,
+	0x0128, 0x0026, 0x2200, 0x080c, 0x570c, 0x002e, 0x001e, 0x8108,
+	0x1f04, 0x573f, 0x015e, 0x012e, 0x0005, 0x2001, 0x1848, 0x2004,
+	0x0005, 0x2001, 0x1867, 0x2004, 0x0005, 0x0006, 0x2001, 0x1810,
+	0x2004, 0xd0d4, 0x000e, 0x0005, 0x2001, 0x180e, 0x2004, 0xd0b4,
+	0x0005, 0x2001, 0x1800, 0x2004, 0x9086, 0x0003, 0x0005, 0x0016,
+	0x00e6, 0x2071, 0x189e, 0x7108, 0x910d, 0x710a, 0x00ee, 0x001e,
+	0x0005, 0x79a4, 0x9182, 0x0081, 0x1a04, 0x35b8, 0x810c, 0x0016,
+	0x080c, 0x4b1f, 0x0170, 0x080c, 0x0f07, 0x2100, 0x2238, 0x7d84,
+	0x7c88, 0x7b8c, 0x7a90, 0x001e, 0x080c, 0x4b68, 0x701f, 0x579d,
+	0x0005, 0x2009, 0x0002, 0x0804, 0x35b5, 0x2079, 0x0000, 0x7d94,
+	0x7c98, 0x7ba8, 0x7aac, 0x79a4, 0x810c, 0x2061, 0x18b8, 0x2c44,
+	0xa770, 0xa074, 0x2071, 0x189e, 0x080c, 0x4b6b, 0x701f, 0x57b1,
+	0x0005, 0x2061, 0x18b8, 0x2c44, 0x0016, 0x0026, 0xa270, 0xa174,
+	0x080c, 0x0f0f, 0x002e, 0x001e, 0x080c, 0x0fbc, 0x9006, 0xa802,
+	0xa806, 0x0804, 0x3583, 0x0126, 0x0156, 0x0136, 0x0146, 0x01c6,
+	0x01d6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2061, 0x0100, 0x2069,
+	0x0200, 0x2071, 0x1800, 0x6044, 0xd0a4, 0x11e8, 0xd084, 0x0118,
+	0x080c, 0x596c, 0x0068, 0xd08c, 0x0118, 0x080c, 0x5875, 0x0040,
+	0xd094, 0x0118, 0x080c, 0x5845, 0x0018, 0xd09c, 0x0108, 0x0099,
+	0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e,
+	0x015e, 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d,
+	0x612a, 0x001e, 0x0c68, 0x0006, 0x7098, 0x9005, 0x000e, 0x0120,
+	0x709b, 0x0000, 0x7093, 0x0000, 0x624c, 0x9286, 0xf0f0, 0x1150,
+	0x6048, 0x9086, 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, 0x6043,
+	0x0010, 0x0490, 0x9294, 0xff00, 0x9296, 0xf700, 0x0178, 0x7138,
+	0xd1a4, 0x1160, 0x6240, 0x9295, 0x0100, 0x6242, 0x9294, 0x0010,
+	0x0128, 0x2009, 0x00f7, 0x080c, 0x6029, 0x00f0, 0x6040, 0x9084,
+	0x0010, 0x9085, 0x0140, 0x6042, 0x6043, 0x0000, 0x7087, 0x0000,
+	0x70a3, 0x0001, 0x70c7, 0x0000, 0x70df, 0x0000, 0x2009, 0x1c80,
+	0x200b, 0x0000, 0x7097, 0x0000, 0x708b, 0x000f, 0x2009, 0x000f,
+	0x2011, 0x5f0f, 0x080c, 0x8648, 0x0005, 0x2001, 0x1869, 0x2004,
+	0xd08c, 0x0110, 0x705f, 0xffff, 0x7088, 0x9005, 0x1528, 0x2011,
+	0x5f0f, 0x080c, 0x85b0, 0x6040, 0x9094, 0x0010, 0x9285, 0x0020,
+	0x6042, 0x20a9, 0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04, 0x585b,
+	0x6242, 0x709b, 0x0000, 0x6040, 0x9094, 0x0010, 0x9285, 0x0080,
+	0x6042, 0x6242, 0x0048, 0x6242, 0x709b, 0x0000, 0x708f, 0x0000,
+	0x9006, 0x080c, 0x60b2, 0x0000, 0x0005, 0x708c, 0x908a, 0x0003,
+	0x1a0c, 0x0dd5, 0x000b, 0x0005, 0x587f, 0x58d0, 0x596b, 0x00f6,
+	0x0016, 0x6900, 0x918c, 0x0800, 0x708f, 0x0001, 0x2001, 0x015d,
+	0x2003, 0x0000, 0x6803, 0x00fc, 0x20a9, 0x0004, 0x6800, 0x9084,
+	0x00fc, 0x0120, 0x1f04, 0x588e, 0x080c, 0x0dd5, 0x68a0, 0x68a2,
+	0x689c, 0x689e, 0x6898, 0x689a, 0xa001, 0x918d, 0x1600, 0x6902,
+	0x001e, 0x6837, 0x0020, 0x080c, 0x608e, 0x2079, 0x1c00, 0x7833,
+	0x1101, 0x7837, 0x0000, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9,
+	0x0001, 0x20a1, 0x1c0e, 0x20a9, 0x0004, 0x4003, 0x080c, 0xabfe,
+	0x20e1, 0x0001, 0x2099, 0x1c00, 0x20e9, 0x0000, 0x20a1, 0x0240,
+	0x20a9, 0x0014, 0x4003, 0x60c3, 0x000c, 0x600f, 0x0000, 0x080c,
+	0x5f40, 0x00fe, 0x9006, 0x7092, 0x6043, 0x0008, 0x6042, 0x0005,
+	0x00f6, 0x7090, 0x7093, 0x0000, 0x9025, 0x0904, 0x5948, 0x6020,
+	0xd0b4, 0x1904, 0x5946, 0x71a0, 0x81ff, 0x0904, 0x5934, 0x9486,
+	0x000c, 0x1904, 0x5941, 0x9480, 0x0018, 0x8004, 0x20a8, 0x080c,
+	0x6087, 0x2011, 0x0260, 0x2019, 0x1c00, 0x220c, 0x2304, 0x9106,
+	0x11e8, 0x8210, 0x8318, 0x1f04, 0x58ed, 0x6043, 0x0004, 0x2061,
+	0x0140, 0x605b, 0xbc94, 0x605f, 0xf0f0, 0x2061, 0x0100, 0x6043,
+	0x0006, 0x708f, 0x0002, 0x709b, 0x0002, 0x2009, 0x07d0, 0x2011,
+	0x5f16, 0x080c, 0x8648, 0x080c, 0x608e, 0x04c0, 0x080c, 0x6087,
+	0x2079, 0x0260, 0x7930, 0x918e, 0x1101, 0x1558, 0x7834, 0x9005,
+	0x1540, 0x7900, 0x918c, 0x00ff, 0x1118, 0x7804, 0x9005, 0x0190,
+	0x080c, 0x6087, 0x2011, 0x026e, 0x2019, 0x1805, 0x20a9, 0x0004,
+	0x220c, 0x2304, 0x9102, 0x0230, 0x11a0, 0x8210, 0x8318, 0x1f04,
+	0x5928, 0x0078, 0x70a3, 0x0000, 0x080c, 0x6087, 0x20e1, 0x0000,
+	0x2099, 0x0260, 0x20e9, 0x0001, 0x20a1, 0x1c00, 0x20a9, 0x0014,
+	0x4003, 0x6043, 0x0008, 0x6043, 0x0000, 0x0010, 0x00fe, 0x0005,
+	0x6040, 0x9085, 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x080c,
+	0xabfe, 0x20e1, 0x0001, 0x2099, 0x1c00, 0x20e9, 0x0000, 0x20a1,
+	0x0240, 0x20a9, 0x0014, 0x4003, 0x60c3, 0x000c, 0x2011, 0x19f0,
+	0x2013, 0x0000, 0x7093, 0x0000, 0x60a3, 0x0056, 0x60a7, 0x9575,
+	0x080c, 0xa34d, 0x08d8, 0x0005, 0x7098, 0x908a, 0x001d, 0x1a0c,
+	0x0dd5, 0x000b, 0x0005, 0x599d, 0x59b0, 0x59d9, 0x59f9, 0x5a1f,
+	0x5a4e, 0x5a74, 0x5aac, 0x5ad2, 0x5b00, 0x5b3b, 0x5b73, 0x5b91,
+	0x5bbc, 0x5bde, 0x5bf9, 0x5c03, 0x5c37, 0x5c5d, 0x5c8c, 0x5cb2,
+	0x5cea, 0x5d2e, 0x5d6b, 0x5d8c, 0x5de5, 0x5e07, 0x5e35, 0x5e35,
+	0x00c6, 0x2061, 0x1800, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004,
+	0x9084, 0xfff9, 0x6006, 0x00ce, 0x0005, 0x2061, 0x0140, 0x605b,
+	0xbc94, 0x605f, 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0002, 0x709b,
+	0x0001, 0x2009, 0x07d0, 0x2011, 0x5f16, 0x080c, 0x8648, 0x0005,
+	0x00f6, 0x7090, 0x9086, 0x0014, 0x1510, 0x6042, 0x6020, 0xd0b4,
+	0x11f0, 0x080c, 0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1102,
+	0x11a0, 0x7834, 0x9005, 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70c4,
+	0x9005, 0x1110, 0x70c7, 0x0001, 0x2011, 0x5f16, 0x080c, 0x85b0,
+	0x709b, 0x0010, 0x080c, 0x5c03, 0x0010, 0x7093, 0x0000, 0x00fe,
+	0x0005, 0x00f6, 0x709b, 0x0003, 0x6043, 0x0004, 0x2011, 0x5f16,
+	0x080c, 0x85b0, 0x080c, 0x600b, 0x2079, 0x0240, 0x7833, 0x1102,
+	0x7837, 0x0000, 0x20a9, 0x0008, 0x9f88, 0x000e, 0x200b, 0x0000,
+	0x8108, 0x1f04, 0x59ee, 0x60c3, 0x0014, 0x080c, 0x5f40, 0x00fe,
+	0x0005, 0x00f6, 0x7090, 0x9005, 0x0500, 0x2011, 0x5f16, 0x080c,
+	0x85b0, 0x9086, 0x0014, 0x11b8, 0x080c, 0x6087, 0x2079, 0x0260,
+	0x7a30, 0x9296, 0x1102, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38,
+	0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001, 0x709b,
+	0x0004, 0x0029, 0x0010, 0x080c, 0x6063, 0x00fe, 0x0005, 0x00f6,
+	0x709b, 0x0005, 0x080c, 0x600b, 0x2079, 0x0240, 0x7833, 0x1103,
+	0x7837, 0x0000, 0x080c, 0x6087, 0x080c, 0x606a, 0x1170, 0x7084,
+	0x9005, 0x1158, 0x715c, 0x9186, 0xffff, 0x0138, 0x2011, 0x0008,
+	0x080c, 0x5ec3, 0x0168, 0x080c, 0x6040, 0x20a9, 0x0008, 0x20e1,
+	0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003,
+	0x60c3, 0x0014, 0x080c, 0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090,
+	0x9005, 0x0500, 0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086, 0x0014,
+	0x11b8, 0x080c, 0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103,
+	0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4,
+	0x9005, 0x1110, 0x70c7, 0x0001, 0x709b, 0x0006, 0x0029, 0x0010,
+	0x080c, 0x6063, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0007, 0x080c,
+	0x600b, 0x2079, 0x0240, 0x7833, 0x1104, 0x7837, 0x0000, 0x080c,
+	0x6087, 0x080c, 0x606a, 0x11b8, 0x7084, 0x9005, 0x11a0, 0x7164,
+	0x9186, 0xffff, 0x0180, 0x9180, 0x3384, 0x200d, 0x918c, 0xff00,
+	0x810f, 0x2011, 0x0008, 0x080c, 0x5ec3, 0x0180, 0x080c, 0x505a,
+	0x0110, 0x080c, 0x28e5, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099,
+	0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014,
+	0x080c, 0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x0500,
+	0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086, 0x0014, 0x11b8, 0x080c,
+	0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834,
+	0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110,
+	0x70c7, 0x0001, 0x709b, 0x0008, 0x0029, 0x0010, 0x080c, 0x6063,
+	0x00fe, 0x0005, 0x00f6, 0x709b, 0x0009, 0x080c, 0x600b, 0x2079,
+	0x0240, 0x7833, 0x1105, 0x7837, 0x0100, 0x080c, 0x606a, 0x1150,
+	0x7084, 0x9005, 0x1138, 0x080c, 0x5e36, 0x1188, 0x9085, 0x0001,
+	0x080c, 0x28e5, 0x20a9, 0x0008, 0x080c, 0x6087, 0x20e1, 0x0000,
+	0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3,
+	0x0014, 0x080c, 0x5f40, 0x0010, 0x080c, 0x5990, 0x00fe, 0x0005,
+	0x00f6, 0x7090, 0x9005, 0x05a8, 0x2011, 0x5f16, 0x080c, 0x85b0,
+	0x9086, 0x0014, 0x1560, 0x080c, 0x6087, 0x2079, 0x0260, 0x7a30,
+	0x9296, 0x1105, 0x1520, 0x7834, 0x9084, 0x0100, 0x2011, 0x0100,
+	0x921e, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110,
+	0x70c7, 0x0001, 0x709b, 0x000a, 0x00b1, 0x0098, 0x9005, 0x1178,
+	0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001,
+	0x7097, 0x0000, 0x709b, 0x000e, 0x080c, 0x5bde, 0x0010, 0x080c,
+	0x6063, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x000b, 0x2011, 0x1c0e,
+	0x20e9, 0x0001, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x4304,
+	0x080c, 0x600b, 0x2079, 0x0240, 0x7833, 0x1106, 0x7837, 0x0000,
+	0x080c, 0x606a, 0x0118, 0x2013, 0x0000, 0x0020, 0x7060, 0x9085,
+	0x0100, 0x2012, 0x20a9, 0x0040, 0x2009, 0x024e, 0x2011, 0x1c0e,
+	0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1128, 0x6810, 0x8000,
+	0x6812, 0x2009, 0x0240, 0x1f04, 0x5b60, 0x60c3, 0x0084, 0x080c,
+	0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x01c0, 0x2011,
+	0x5f16, 0x080c, 0x85b0, 0x9086, 0x0084, 0x1178, 0x080c, 0x6087,
+	0x2079, 0x0260, 0x7a30, 0x9296, 0x1106, 0x1138, 0x7834, 0x9005,
+	0x1120, 0x709b, 0x000c, 0x0029, 0x0010, 0x080c, 0x6063, 0x00fe,
+	0x0005, 0x00f6, 0x709b, 0x000d, 0x080c, 0x600b, 0x2079, 0x0240,
+	0x7833, 0x1107, 0x7837, 0x0000, 0x080c, 0x6087, 0x20a9, 0x0040,
+	0x2011, 0x026e, 0x2009, 0x024e, 0x220e, 0x8210, 0x8108, 0x9186,
+	0x0260, 0x1150, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x6814,
+	0x8000, 0x6816, 0x2011, 0x0260, 0x1f04, 0x5ba4, 0x60c3, 0x0084,
+	0x080c, 0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x01e0,
+	0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086, 0x0084, 0x1198, 0x080c,
+	0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834,
+	0x9005, 0x1140, 0x7097, 0x0001, 0x080c, 0x5fdd, 0x709b, 0x000e,
+	0x0029, 0x0010, 0x080c, 0x6063, 0x00fe, 0x0005, 0x918d, 0x0001,
+	0x080c, 0x60b2, 0x709b, 0x000f, 0x7093, 0x0000, 0x2061, 0x0140,
+	0x605b, 0xbc85, 0x605f, 0xb5b5, 0x2061, 0x0100, 0x6043, 0x0005,
+	0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x5f16, 0x080c, 0x85a4,
+	0x0005, 0x7090, 0x9005, 0x0130, 0x2011, 0x5f16, 0x080c, 0x85b0,
+	0x709b, 0x0000, 0x0005, 0x709b, 0x0011, 0x080c, 0xabfe, 0x080c,
+	0x6087, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1,
+	0x0240, 0x7490, 0x9480, 0x0018, 0x9080, 0x0007, 0x9084, 0x03f8,
+	0x8004, 0x20a8, 0x4003, 0x080c, 0x606a, 0x11a0, 0x717c, 0x81ff,
+	0x0188, 0x900e, 0x7080, 0x9084, 0x00ff, 0x0160, 0x080c, 0x287c,
+	0x9186, 0x007e, 0x0138, 0x9186, 0x0080, 0x0120, 0x2011, 0x0008,
+	0x080c, 0x5ec3, 0x60c3, 0x0014, 0x080c, 0x5f40, 0x0005, 0x00f6,
+	0x7090, 0x9005, 0x0500, 0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086,
+	0x0014, 0x11b8, 0x080c, 0x6087, 0x2079, 0x0260, 0x7a30, 0x9296,
+	0x1103, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128,
+	0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001, 0x709b, 0x0012, 0x0029,
+	0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0013,
+	0x080c, 0x6019, 0x2079, 0x0240, 0x7833, 0x1103, 0x7837, 0x0000,
+	0x080c, 0x6087, 0x080c, 0x606a, 0x1170, 0x7084, 0x9005, 0x1158,
+	0x715c, 0x9186, 0xffff, 0x0138, 0x2011, 0x0008, 0x080c, 0x5ec3,
+	0x0168, 0x080c, 0x6040, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099,
+	0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014,
+	0x080c, 0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x0500,
+	0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086, 0x0014, 0x11b8, 0x080c,
+	0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834,
+	0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110,
+	0x70c7, 0x0001, 0x709b, 0x0014, 0x0029, 0x0010, 0x7093, 0x0000,
+	0x00fe, 0x0005, 0x00f6, 0x709b, 0x0015, 0x080c, 0x6019, 0x2079,
+	0x0240, 0x7833, 0x1104, 0x7837, 0x0000, 0x080c, 0x6087, 0x080c,
+	0x606a, 0x11b8, 0x7084, 0x9005, 0x11a0, 0x7164, 0x9186, 0xffff,
+	0x0180, 0x9180, 0x3384, 0x200d, 0x918c, 0xff00, 0x810f, 0x2011,
+	0x0008, 0x080c, 0x5ec3, 0x0180, 0x080c, 0x505a, 0x0110, 0x080c,
+	0x28e5, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9,
+	0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5f40,
+	0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x05f0, 0x2011, 0x5f16,
+	0x080c, 0x85b0, 0x9086, 0x0014, 0x15a8, 0x080c, 0x6087, 0x2079,
+	0x0260, 0x7a30, 0x9296, 0x1105, 0x1568, 0x7834, 0x9084, 0x0100,
+	0x2011, 0x0100, 0x921e, 0x1168, 0x9085, 0x0001, 0x080c, 0x60b2,
+	0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001,
+	0x0080, 0x9005, 0x11b8, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005,
+	0x1110, 0x70c7, 0x0001, 0x9085, 0x0001, 0x080c, 0x60b2, 0x7097,
+	0x0000, 0x7a38, 0xd2f4, 0x0110, 0x70df, 0x0008, 0x709b, 0x0016,
+	0x0029, 0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x080c, 0xabfe,
+	0x080c, 0x6087, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000,
+	0x20a1, 0x0240, 0x20a9, 0x000e, 0x4003, 0x2011, 0x026d, 0x2204,
+	0x9084, 0x0100, 0x2011, 0x024d, 0x2012, 0x2011, 0x026e, 0x709b,
+	0x0017, 0x080c, 0x606a, 0x1150, 0x7084, 0x9005, 0x1138, 0x080c,
+	0x5e36, 0x1188, 0x9085, 0x0001, 0x080c, 0x28e5, 0x20a9, 0x0008,
+	0x080c, 0x6087, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000,
+	0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5f40, 0x0010,
+	0x080c, 0x5990, 0x0005, 0x00f6, 0x7090, 0x9005, 0x01d8, 0x2011,
+	0x5f16, 0x080c, 0x85b0, 0x9086, 0x0084, 0x1190, 0x080c, 0x6087,
+	0x2079, 0x0260, 0x7a30, 0x9296, 0x1106, 0x1150, 0x7834, 0x9005,
+	0x1138, 0x9006, 0x080c, 0x60b2, 0x709b, 0x0018, 0x0029, 0x0010,
+	0x7093, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0019, 0x080c,
+	0x6019, 0x2079, 0x0240, 0x7833, 0x1106, 0x7837, 0x0000, 0x080c,
+	0x6087, 0x2009, 0x026e, 0x2039, 0x1c0e, 0x20a9, 0x0040, 0x213e,
+	0x8738, 0x8108, 0x9186, 0x0280, 0x1128, 0x6814, 0x8000, 0x6816,
+	0x2009, 0x0260, 0x1f04, 0x5d9f, 0x2039, 0x1c0e, 0x080c, 0x606a,
+	0x11e8, 0x2728, 0x2514, 0x8207, 0x9084, 0x00ff, 0x8000, 0x2018,
+	0x9294, 0x00ff, 0x8007, 0x9205, 0x202a, 0x7060, 0x2310, 0x8214,
+	0x92a0, 0x1c0e, 0x2414, 0x938c, 0x0001, 0x0118, 0x9294, 0xff00,
+	0x0018, 0x9294, 0x00ff, 0x8007, 0x9215, 0x2222, 0x20a9, 0x0040,
+	0x2009, 0x024e, 0x270e, 0x8738, 0x8108, 0x9186, 0x0260, 0x1128,
+	0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x1f04, 0x5dd2, 0x60c3,
+	0x0084, 0x080c, 0x5f40, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005,
+	0x01e0, 0x2011, 0x5f16, 0x080c, 0x85b0, 0x9086, 0x0084, 0x1198,
+	0x080c, 0x6087, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1107, 0x1158,
+	0x7834, 0x9005, 0x1140, 0x7097, 0x0001, 0x080c, 0x5fdd, 0x709b,
+	0x001a, 0x0029, 0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x9085,
+	0x0001, 0x080c, 0x60b2, 0x709b, 0x001b, 0x080c, 0xabfe, 0x080c,
+	0x6087, 0x2011, 0x0260, 0x2009, 0x0240, 0x7490, 0x9480, 0x0018,
+	0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, 0x20a8, 0x220e, 0x8210,
+	0x8108, 0x9186, 0x0260, 0x1150, 0x6810, 0x8000, 0x6812, 0x2009,
+	0x0240, 0x6814, 0x8000, 0x6816, 0x2011, 0x0260, 0x1f04, 0x5e1e,
+	0x60c3, 0x0084, 0x080c, 0x5f40, 0x0005, 0x0005, 0x0086, 0x0096,
+	0x2029, 0x1848, 0x252c, 0x20a9, 0x0008, 0x2041, 0x1c0e, 0x20e9,
+	0x0001, 0x28a0, 0x080c, 0x6087, 0x20e1, 0x0000, 0x2099, 0x026e,
+	0x4003, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0108, 0x9016,
+	0x2800, 0x9200, 0x200c, 0x91a6, 0xffff, 0x1148, 0xd5d4, 0x0110,
+	0x8210, 0x0008, 0x8211, 0x1f04, 0x5e50, 0x0804, 0x5ebf, 0x82ff,
+	0x1160, 0xd5d4, 0x0120, 0x91a6, 0x3fff, 0x0d90, 0x0020, 0x91a6,
+	0x3fff, 0x0904, 0x5ebf, 0x918d, 0xc000, 0x20a9, 0x0010, 0x2019,
+	0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0110,
+	0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319, 0x0008,
+	0x8318, 0x1f04, 0x5e76, 0x04d8, 0x23a8, 0x2021, 0x0001, 0x8426,
+	0x8425, 0x1f04, 0x5e88, 0x2328, 0x8529, 0x92be, 0x0007, 0x0158,
+	0x0006, 0x2039, 0x0007, 0x2200, 0x973a, 0x000e, 0x27a8, 0x95a8,
+	0x0010, 0x1f04, 0x5e97, 0x755e, 0x95c8, 0x3384, 0x292d, 0x95ac,
+	0x00ff, 0x7582, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x28c5,
+	0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0x9405, 0x201a,
+	0x7087, 0x0001, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x20e1, 0x0001,
+	0x2898, 0x20a9, 0x0008, 0x4003, 0x9085, 0x0001, 0x0008, 0x9006,
+	0x009e, 0x008e, 0x0005, 0x0156, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x22a8, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x2011,
+	0x024e, 0x22a0, 0x4003, 0x014e, 0x013e, 0x01de, 0x01ce, 0x015e,
+	0x2118, 0x9026, 0x2001, 0x0007, 0x939a, 0x0010, 0x0218, 0x8420,
+	0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0x939a, 0x0010, 0x8421,
+	0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8,
+	0x9238, 0x2029, 0x026e, 0x9528, 0x2504, 0x942c, 0x11b8, 0x9405,
+	0x203a, 0x715e, 0x91a0, 0x3384, 0x242d, 0x95ac, 0x00ff, 0x7582,
+	0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x28c5, 0x001e, 0x60e7,
+	0x0000, 0x65ea, 0x7087, 0x0001, 0x9084, 0x0000, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0x708b, 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6,
+	0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x5fcc, 0x080c, 0xa356,
+	0x7004, 0x9084, 0x4000, 0x0110, 0x080c, 0x2d5e, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x1826, 0x2073, 0x0000, 0x7840, 0x0026, 0x0016,
+	0x2009, 0x00f7, 0x080c, 0x6029, 0x001e, 0x9094, 0x0010, 0x9285,
+	0x0080, 0x7842, 0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x2be3, 0x0228, 0x2011, 0x0101,
+	0x2204, 0xc0c5, 0x2012, 0x2011, 0x19f0, 0x2013, 0x0000, 0x7093,
+	0x0000, 0x012e, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0xa34d,
+	0x6144, 0xd184, 0x0120, 0x7198, 0x918d, 0x2000, 0x0018, 0x718c,
+	0x918d, 0x1000, 0x2011, 0x1998, 0x2112, 0x2009, 0x07d0, 0x2011,
+	0x5f16, 0x080c, 0x8648, 0x0005, 0x0016, 0x0026, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x080c, 0xaeb4, 0x2009, 0x00f7, 0x080c, 0x6029,
+	0x2061, 0x19f9, 0x900e, 0x611a, 0x611e, 0x6172, 0x6176, 0x2061,
+	0x1800, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043,
+	0x0010, 0x2009, 0x1998, 0x200b, 0x0000, 0x2009, 0x002d, 0x2011,
+	0x5f98, 0x080c, 0x85a4, 0x012e, 0x00ce, 0x002e, 0x001e, 0x0005,
+	0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x0471, 0x2071, 0x0100,
+	0x080c, 0xa356, 0x2071, 0x0140, 0x7004, 0x9084, 0x4000, 0x0110,
+	0x080c, 0x2d5e, 0x080c, 0x7446, 0x0188, 0x080c, 0x7461, 0x1170,
+	0x080c, 0x772e, 0x0016, 0x080c, 0x2994, 0x2001, 0x196c, 0x2102,
+	0x001e, 0x080c, 0x7729, 0x080c, 0x736a, 0x0050, 0x2009, 0x0001,
+	0x080c, 0x2c7c, 0x2001, 0x0001, 0x080c, 0x2828, 0x080c, 0x5f6c,
+	0x012e, 0x000e, 0x00ee, 0x0005, 0x2001, 0x180e, 0x2004, 0xd0bc,
+	0x0158, 0x0026, 0x0036, 0x2011, 0x8017, 0x2001, 0x1998, 0x201c,
+	0x080c, 0x4b7f, 0x003e, 0x002e, 0x0005, 0x20a9, 0x0012, 0x20e9,
+	0x0001, 0x20a1, 0x1c80, 0x080c, 0x6087, 0x20e9, 0x0000, 0x2099,
+	0x026e, 0x0099, 0x20a9, 0x0020, 0x080c, 0x6081, 0x2099, 0x0260,
+	0x20a1, 0x1c92, 0x0051, 0x20a9, 0x000e, 0x080c, 0x6084, 0x2099,
+	0x0260, 0x20a1, 0x1cb2, 0x0009, 0x0005, 0x0016, 0x0026, 0x3410,
+	0x3308, 0x2104, 0x8007, 0x2012, 0x8108, 0x8210, 0x1f04, 0x6001,
+	0x002e, 0x001e, 0x0005, 0x080c, 0xabfe, 0x20e1, 0x0001, 0x2099,
+	0x1c00, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003,
+	0x0005, 0x080c, 0xabfe, 0x080c, 0x6087, 0x20e1, 0x0000, 0x2099,
+	0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003,
+	0x0005, 0x00c6, 0x0006, 0x2061, 0x0100, 0x810f, 0x2001, 0x1834,
+	0x2004, 0x9005, 0x1138, 0x2001, 0x1818, 0x2004, 0x9084, 0x00ff,
+	0x9105, 0x0010, 0x9185, 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005,
+	0x0016, 0x0046, 0x080c, 0x6a08, 0x0158, 0x9006, 0x2020, 0x2009,
+	0x002a, 0x080c, 0xe73a, 0x2001, 0x180c, 0x200c, 0xc195, 0x2102,
+	0x2019, 0x002a, 0x900e, 0x080c, 0x31e9, 0x080c, 0xd388, 0x0140,
+	0x0036, 0x2019, 0xffff, 0x2021, 0x0007, 0x080c, 0x4d36, 0x003e,
+	0x004e, 0x001e, 0x0005, 0x080c, 0x5f6c, 0x709b, 0x0000, 0x7093,
+	0x0000, 0x0005, 0x0006, 0x2001, 0x180c, 0x2004, 0xd09c, 0x0100,
+	0x000e, 0x0005, 0x0006, 0x0016, 0x0126, 0x2091, 0x8000, 0x2001,
+	0x0101, 0x200c, 0x918d, 0x0006, 0x2102, 0x012e, 0x001e, 0x000e,
+	0x0005, 0x2009, 0x0001, 0x0020, 0x2009, 0x0002, 0x0008, 0x900e,
+	0x6814, 0x9084, 0xffc0, 0x910d, 0x6916, 0x0005, 0x00f6, 0x0156,
+	0x0146, 0x01d6, 0x9006, 0x20a9, 0x0080, 0x20e9, 0x0001, 0x20a1,
+	0x1c00, 0x4004, 0x2079, 0x1c00, 0x7803, 0x2200, 0x7807, 0x00ef,
+	0x780f, 0x00ef, 0x7813, 0x0138, 0x7823, 0xffff, 0x7827, 0xffff,
+	0x01de, 0x014e, 0x015e, 0x00fe, 0x0005, 0x2001, 0x1800, 0x2003,
+	0x0001, 0x0005, 0x2001, 0x19a5, 0x0118, 0x2003, 0x0001, 0x0010,
+	0x2003, 0x0000, 0x0005, 0x0156, 0x20a9, 0x0800, 0x2009, 0x1000,
+	0x9006, 0x200a, 0x8108, 0x1f04, 0x60c1, 0x015e, 0x0005, 0x00d6,
+	0x0036, 0x0156, 0x0136, 0x0146, 0x2069, 0x1847, 0x9006, 0xb802,
+	0xb8ce, 0xb807, 0x0707, 0xb80a, 0xb80e, 0xb812, 0x9198, 0x3384,
+	0x231d, 0x939c, 0x00ff, 0xbb16, 0x0016, 0x0026, 0xb8c2, 0x080c,
+	0xaead, 0x1120, 0x9192, 0x007e, 0x1208, 0xbbc2, 0x20a9, 0x0004,
+	0xb8c4, 0x20e8, 0xb9c8, 0x9198, 0x0006, 0x9006, 0x23a0, 0x4004,
+	0x20a9, 0x0004, 0x9198, 0x000a, 0x23a0, 0x4004, 0x002e, 0x001e,
+	0xb83e, 0xb842, 0xb84e, 0xb852, 0xb856, 0xb85a, 0xb85e, 0xb862,
+	0xb866, 0xb86a, 0xb86f, 0x0100, 0xb872, 0xb876, 0xb87a, 0xb88a,
+	0xb88e, 0xb893, 0x0008, 0xb896, 0xb89a, 0xb89e, 0xb8be, 0xb9a2,
+	0x0096, 0xb8a4, 0x904d, 0x0110, 0x080c, 0x1031, 0xb8a7, 0x0000,
+	0x009e, 0x9006, 0xb84a, 0x6810, 0xb83a, 0x680c, 0xb846, 0xb8bb,
+	0x0520, 0xb8ac, 0x9005, 0x0198, 0x00c6, 0x2060, 0x9c82, 0x1cd0,
+	0x0a0c, 0x0dd5, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1a0c, 0x0dd5,
+	0x080c, 0x8a3d, 0x00ce, 0x090c, 0x8dda, 0xb8af, 0x0000, 0x6814,
+	0x9084, 0x00ff, 0xb842, 0x014e, 0x013e, 0x015e, 0x003e, 0x00de,
+	0x0005, 0x0126, 0x2091, 0x8000, 0xa974, 0xae78, 0x9684, 0x3fff,
+	0x9082, 0x4000, 0x1a04, 0x61af, 0x9182, 0x0800, 0x1a04, 0x61b3,
+	0x2001, 0x180c, 0x2004, 0x9084, 0x0003, 0x1904, 0x61b9, 0x9188,
+	0x1000, 0x2104, 0x905d, 0x0518, 0xb804, 0x9084, 0x00ff, 0x908e,
+	0x0006, 0x1508, 0xb8a4, 0x900d, 0x1904, 0x61cb, 0xb850, 0x900d,
+	0x1148, 0xa802, 0x2900, 0xb852, 0xb84e, 0x080c, 0x91ce, 0x9006,
+	0x012e, 0x0005, 0x00a6, 0x2150, 0x2900, 0xb002, 0xa803, 0x0000,
+	0x00ae, 0xb852, 0x0c90, 0x2001, 0x0005, 0x900e, 0x04b8, 0x2001,
+	0x0028, 0x900e, 0x0498, 0x9082, 0x0006, 0x1290, 0x080c, 0xaead,
+	0x1160, 0xb8a0, 0x9084, 0xff80, 0x1140, 0xb900, 0xd1fc, 0x0990,
+	0x2001, 0x0029, 0x2009, 0x1000, 0x0408, 0x2001, 0x0028, 0x00a8,
+	0x2009, 0x180c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0068,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, 0x0029, 0xb900,
+	0xd1fc, 0x0118, 0x2009, 0x1000, 0x0048, 0x900e, 0x0038, 0x2001,
+	0x0029, 0x900e, 0x0018, 0x2001, 0x0029, 0x900e, 0x9005, 0x012e,
+	0x0005, 0x2001, 0x180c, 0x2004, 0xd084, 0x19d0, 0x9188, 0x1000,
+	0x2104, 0x905d, 0x09a8, 0x080c, 0x6a0c, 0x1990, 0xb800, 0xd0bc,
+	0x0978, 0x0804, 0x6162, 0x080c, 0x6835, 0x0904, 0x617b, 0x0804,
+	0x6166, 0x00b6, 0x00e6, 0x0126, 0x2091, 0x8000, 0xa874, 0x908e,
+	0x00ff, 0x1120, 0x2001, 0x196a, 0x205c, 0x0060, 0xa974, 0x9182,
+	0x0800, 0x1690, 0x9188, 0x1000, 0x2104, 0x905d, 0x01d0, 0x080c,
+	0x69ac, 0x11d0, 0x080c, 0xaeed, 0x0570, 0x2b00, 0x6012, 0x2900,
+	0x6016, 0x6023, 0x0009, 0x600b, 0x0000, 0xa874, 0x908e, 0x00ff,
+	0x1110, 0x600b, 0x8000, 0x2009, 0x0043, 0x080c, 0xafbe, 0x9006,
+	0x00b0, 0x2001, 0x0028, 0x0090, 0x2009, 0x180c, 0x210c, 0xd18c,
+	0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001, 0x0004,
+	0x0010, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, 0x9005, 0x012e,
+	0x00ee, 0x00be, 0x0005, 0x2001, 0x002c, 0x0cc0, 0x00b6, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0xa974, 0x9182, 0x0800, 0x1a04, 0x629c,
+	0x9188, 0x1000, 0x2104, 0x905d, 0x0904, 0x6274, 0xb8a0, 0x9086,
+	0x007f, 0x0190, 0xa87c, 0xd0fc, 0x1178, 0x080c, 0x6a14, 0x0160,
+	0xa994, 0x81ff, 0x0130, 0x908e, 0x0004, 0x0130, 0x908e, 0x0005,
+	0x0118, 0x080c, 0x6a0c, 0x1598, 0xa87c, 0xd0fc, 0x01e0, 0xa894,
+	0x9005, 0x01c8, 0x2060, 0x0026, 0x2010, 0x080c, 0xcc74, 0x002e,
+	0x1120, 0x2001, 0x0008, 0x0804, 0x629e, 0x6020, 0x9086, 0x000a,
+	0x0120, 0x2001, 0x0008, 0x0804, 0x629e, 0x601a, 0x6003, 0x0008,
+	0x2900, 0x6016, 0x0058, 0x080c, 0xaeed, 0x05e8, 0x2b00, 0x6012,
+	0x2900, 0x6016, 0x600b, 0xffff, 0x6023, 0x000a, 0x2009, 0x0003,
+	0x080c, 0xafbe, 0x9006, 0x0458, 0x2001, 0x0028, 0x0438, 0x9082,
+	0x0006, 0x1290, 0x080c, 0xaead, 0x1160, 0xb8a0, 0x9084, 0xff80,
+	0x1140, 0xb900, 0xd1fc, 0x0900, 0x2001, 0x0029, 0x2009, 0x1000,
+	0x00a8, 0x2001, 0x0028, 0x0090, 0x2009, 0x180c, 0x210c, 0xd18c,
+	0x0118, 0x2001, 0x0004, 0x0050, 0xd184, 0x0118, 0x2001, 0x0004,
+	0x0028, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, 0x9005, 0x012e,
+	0x00ee, 0x00be, 0x0005, 0x2001, 0x002c, 0x0cc0, 0x00f6, 0x00b6,
+	0x0126, 0x2091, 0x8000, 0xa8e0, 0x9005, 0x1550, 0xa8dc, 0x9082,
+	0x0101, 0x1630, 0xa8c8, 0x9005, 0x1518, 0xa8c4, 0x9082, 0x0101,
+	0x12f8, 0xa974, 0x2079, 0x1800, 0x9182, 0x0800, 0x12e8, 0x7830,
+	0x9084, 0x0003, 0x1130, 0xaa98, 0xab94, 0xa878, 0x9084, 0x0007,
+	0x00ea, 0x7930, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184,
+	0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e, 0x0038,
+	0x2001, 0x002c, 0x900e, 0x0018, 0x2001, 0x0029, 0x900e, 0x9006,
+	0x0008, 0x9005, 0x012e, 0x00be, 0x00fe, 0x0005, 0x6333, 0x62ee,
+	0x6305, 0x6333, 0x6333, 0x6333, 0x6333, 0x6333, 0x2100, 0x9082,
+	0x007e, 0x1278, 0x080c, 0x6638, 0x0148, 0x9046, 0xb810, 0x9306,
+	0x1904, 0x633b, 0xb814, 0x9206, 0x15f0, 0x0028, 0xbb12, 0xba16,
+	0x0010, 0x080c, 0x4a32, 0x0150, 0x04b0, 0x080c, 0x6699, 0x1598,
+	0xb810, 0x9306, 0x1580, 0xb814, 0x9206, 0x1568, 0x080c, 0xaeed,
+	0x0530, 0x2b00, 0x6012, 0x080c, 0xd102, 0x2900, 0x6016, 0x600b,
+	0xffff, 0x6023, 0x000a, 0xa878, 0x9086, 0x0001, 0x1170, 0x080c,
+	0x321e, 0x9006, 0x080c, 0x65d5, 0x2001, 0x0002, 0x080c, 0x65e9,
+	0x2001, 0x0200, 0xb86e, 0xb893, 0x0002, 0x2009, 0x0003, 0x080c,
+	0xafbe, 0x9006, 0x0068, 0x2001, 0x0001, 0x900e, 0x0038, 0x2001,
+	0x002c, 0x900e, 0x0018, 0x2001, 0x0028, 0x900e, 0x9005, 0x0000,
+	0x012e, 0x00be, 0x00fe, 0x0005, 0x00b6, 0x00f6, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0xa894, 0x90c6, 0x0015, 0x0904, 0x6526, 0x90c6,
+	0x0056, 0x0904, 0x652a, 0x90c6, 0x0066, 0x0904, 0x652e, 0x90c6,
+	0x0067, 0x0904, 0x6532, 0x90c6, 0x0068, 0x0904, 0x6536, 0x90c6,
+	0x0071, 0x0904, 0x653a, 0x90c6, 0x0074, 0x0904, 0x653e, 0x90c6,
+	0x007c, 0x0904, 0x6542, 0x90c6, 0x007e, 0x0904, 0x6546, 0x90c6,
+	0x0037, 0x0904, 0x654a, 0x9016, 0x2079, 0x1800, 0xa974, 0x9186,
+	0x00ff, 0x0904, 0x6521, 0x9182, 0x0800, 0x1a04, 0x6521, 0x080c,
+	0x6699, 0x1198, 0xb804, 0x9084, 0x00ff, 0x9082, 0x0006, 0x1268,
+	0xa894, 0x90c6, 0x006f, 0x0148, 0x080c, 0xaead, 0x1904, 0x650a,
+	0xb8a0, 0x9084, 0xff80, 0x1904, 0x650a, 0xa894, 0x90c6, 0x006f,
+	0x0158, 0x90c6, 0x005e, 0x0904, 0x646a, 0x90c6, 0x0064, 0x0904,
+	0x6493, 0x2008, 0x0804, 0x642c, 0xa998, 0xa8b0, 0x2040, 0x080c,
+	0xaead, 0x1120, 0x9182, 0x007f, 0x0a04, 0x642c, 0x9186, 0x00ff,
+	0x0904, 0x642c, 0x9182, 0x0800, 0x1a04, 0x642c, 0xaaa0, 0xab9c,
+	0x787c, 0x9306, 0x11a8, 0x7880, 0x0096, 0x924e, 0x1128, 0x2208,
+	0x2310, 0x009e, 0x0804, 0x642c, 0x080c, 0xaead, 0x1140, 0x99cc,
+	0xff00, 0x009e, 0x1128, 0x2208, 0x2310, 0x0804, 0x642c, 0x009e,
+	0x080c, 0x4a32, 0x0904, 0x6436, 0x900e, 0x9016, 0x90c6, 0x4000,
+	0x15e0, 0x0006, 0x080c, 0x68b9, 0x1108, 0xc185, 0xb800, 0xd0bc,
+	0x0108, 0xc18d, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0031, 0x20a0, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x0006, 0x2098,
+	0x080c, 0x0f7c, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0035, 0x20a0, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x000a, 0x2098,
+	0x080c, 0x0f7c, 0xa8c4, 0xabc8, 0x9305, 0xabcc, 0x9305, 0xabd0,
+	0x9305, 0xabd4, 0x9305, 0xabd8, 0x9305, 0xabdc, 0x9305, 0xabe0,
+	0x9305, 0x9005, 0x0510, 0x000e, 0x00c8, 0x90c6, 0x4007, 0x1110,
+	0x2408, 0x00a0, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0070,
+	0x90c6, 0x4009, 0x1108, 0x0050, 0x90c6, 0x4006, 0x0138, 0x2001,
+	0x4005, 0x2009, 0x000a, 0x0010, 0x2001, 0x4006, 0xa896, 0xa99a,
+	0xaa9e, 0x2001, 0x0030, 0x900e, 0x0478, 0x000e, 0x080c, 0xaeed,
+	0x1130, 0x2001, 0x4005, 0x2009, 0x0003, 0x9016, 0x0c78, 0x2b00,
+	0x6012, 0x080c, 0xd102, 0x2900, 0x6016, 0x6023, 0x0001, 0xa868,
+	0xd88c, 0x0108, 0xc0f5, 0xa86a, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x321e, 0x012e, 0x9006, 0x080c, 0x65d5, 0x2001, 0x0002, 0x080c,
+	0x65e9, 0x2009, 0x0002, 0x080c, 0xafbe, 0xa8b0, 0xd094, 0x0118,
+	0xb8cc, 0xc08d, 0xb8ce, 0x9006, 0x9005, 0x012e, 0x00ee, 0x00fe,
+	0x00be, 0x0005, 0x080c, 0x5771, 0x0118, 0x2009, 0x0007, 0x00f8,
+	0xa998, 0xaeb0, 0x080c, 0x6699, 0x1904, 0x6427, 0x9186, 0x007f,
+	0x0130, 0x080c, 0x6a0c, 0x0118, 0x2009, 0x0009, 0x0080, 0x0096,
+	0x080c, 0x0fff, 0x1120, 0x009e, 0x2009, 0x0002, 0x0040, 0x2900,
+	0x009e, 0xa806, 0x080c, 0xce6e, 0x19b0, 0x2009, 0x0003, 0x2001,
+	0x4005, 0x0804, 0x642e, 0xa998, 0xaeb0, 0x080c, 0x6699, 0x1904,
+	0x6427, 0x0096, 0x080c, 0x0fff, 0x1128, 0x009e, 0x2009, 0x0002,
+	0x0804, 0x64e7, 0x2900, 0x009e, 0xa806, 0x0096, 0x2048, 0x20a9,
+	0x002b, 0xb8c4, 0x20e0, 0xb8c8, 0x2098, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0002, 0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080, 0x0006,
+	0x20a0, 0xbbc8, 0x9398, 0x0006, 0x2398, 0x080c, 0x0f7c, 0x009e,
+	0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0xd684, 0x1168,
+	0x080c, 0x575d, 0xd0b4, 0x1118, 0xa89b, 0x000b, 0x00e0, 0xb800,
+	0xd08c, 0x0118, 0xa89b, 0x000c, 0x00b0, 0x080c, 0x6a0c, 0x0118,
+	0xa89b, 0x0009, 0x0080, 0x080c, 0x5771, 0x0118, 0xa89b, 0x0007,
+	0x0050, 0x080c, 0xce51, 0x1904, 0x6463, 0x2009, 0x0003, 0x2001,
+	0x4005, 0x0804, 0x642e, 0xa87b, 0x0030, 0xa897, 0x4005, 0xa804,
+	0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080,
+	0x0002, 0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031,
+	0x0000, 0x2041, 0x1243, 0x080c, 0xb45d, 0x1904, 0x6463, 0x2009,
+	0x0002, 0x08e8, 0x2001, 0x0028, 0x900e, 0x0804, 0x6464, 0x2009,
+	0x180c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184,
+	0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e, 0x0804,
+	0x6464, 0x2001, 0x0029, 0x900e, 0x0804, 0x6464, 0x080c, 0x37b3,
+	0x0804, 0x6465, 0x080c, 0x5488, 0x0804, 0x6465, 0x080c, 0x45b1,
+	0x0804, 0x6465, 0x080c, 0x462a, 0x0804, 0x6465, 0x080c, 0x4686,
+	0x0804, 0x6465, 0x080c, 0x4af5, 0x0804, 0x6465, 0x080c, 0x4da9,
+	0x0804, 0x6465, 0x080c, 0x50f0, 0x0804, 0x6465, 0x080c, 0x52e9,
+	0x0804, 0x6465, 0x080c, 0x39c9, 0x0804, 0x6465, 0x00b6, 0xa974,
+	0xae78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1618, 0x9182, 0x0800,
+	0x1268, 0x9188, 0x1000, 0x2104, 0x905d, 0x0140, 0x080c, 0x6a0c,
+	0x1148, 0x00e9, 0x080c, 0x67c4, 0x9006, 0x00b0, 0x2001, 0x0028,
+	0x900e, 0x0090, 0x9082, 0x0006, 0x1240, 0xb900, 0xd1fc, 0x0d88,
+	0x2001, 0x0029, 0x2009, 0x1000, 0x0038, 0x2001, 0x0029, 0x900e,
+	0x0018, 0x2001, 0x0029, 0x900e, 0x9005, 0x00be, 0x0005, 0x0126,
+	0x2091, 0x8000, 0xb850, 0x900d, 0x0150, 0x2900, 0x0096, 0x2148,
+	0xa802, 0x009e, 0xa803, 0x0000, 0xb852, 0x012e, 0x0005, 0x2900,
+	0xb852, 0xb84e, 0xa803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000,
+	0xb84c, 0x9005, 0x0170, 0x00e6, 0x2071, 0x19e6, 0x7004, 0x9086,
+	0x0002, 0x0168, 0x00ee, 0xb84c, 0xa802, 0x2900, 0xb84e, 0x012e,
+	0x0005, 0x2900, 0xb852, 0xb84e, 0xa803, 0x0000, 0x0cc0, 0x701c,
+	0x9b06, 0x1d80, 0xb84c, 0x00a6, 0x2050, 0xb000, 0xa802, 0x2900,
+	0xb002, 0x00ae, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000,
+	0xb84c, 0x904d, 0x0130, 0xa800, 0x9005, 0x1108, 0xb852, 0xb84e,
+	0x9905, 0x012e, 0x0005, 0xb84c, 0x904d, 0x0130, 0xa800, 0x9005,
+	0x1108, 0xb852, 0xb84e, 0x9905, 0x0005, 0x00b6, 0x0126, 0x00c6,
+	0x0026, 0x2091, 0x8000, 0x6210, 0x2258, 0xba00, 0x9005, 0x0110,
+	0xc285, 0x0008, 0xc284, 0xba02, 0x002e, 0x00ce, 0x012e, 0x00be,
+	0x0005, 0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, 0x2258,
+	0xba04, 0x0006, 0x9086, 0x0006, 0x1170, 0xb89c, 0xd0ac, 0x0158,
+	0x080c, 0x6a08, 0x0140, 0x9284, 0xff00, 0x8007, 0x9086, 0x0007,
+	0x1110, 0x2011, 0x0600, 0x000e, 0x9294, 0xff00, 0x9215, 0xba06,
+	0x0006, 0x9086, 0x0006, 0x1120, 0xba90, 0x82ff, 0x090c, 0x0dd5,
+	0x000e, 0x00ce, 0x012e, 0x00be, 0x0005, 0x00b6, 0x0126, 0x00c6,
+	0x2091, 0x8000, 0x6210, 0x2258, 0xba04, 0x0006, 0x9086, 0x0006,
+	0x1168, 0xb89c, 0xd0a4, 0x0150, 0x080c, 0x6a04, 0x1138, 0x9284,
+	0x00ff, 0x9086, 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0x9294,
+	0x00ff, 0x8007, 0x9215, 0xba06, 0x00ce, 0x012e, 0x00be, 0x0005,
+	0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0005, 0x00d6, 0x0026,
+	0x9190, 0x1000, 0x2204, 0x905d, 0x1188, 0x0096, 0x080c, 0x0fff,
+	0x2958, 0x009e, 0x0168, 0x2b00, 0x2012, 0xb85c, 0xb8ca, 0xb860,
+	0xb8c6, 0x9006, 0xb8a6, 0xb8ae, 0x080c, 0x60c7, 0x9006, 0x0010,
+	0x9085, 0x0001, 0x002e, 0x00de, 0x0005, 0x00b6, 0x0096, 0x0126,
+	0x2091, 0x8000, 0x0026, 0x9182, 0x0800, 0x0218, 0x9085, 0x0001,
+	0x0458, 0x00d6, 0x9190, 0x1000, 0x2204, 0x905d, 0x0518, 0x2013,
+	0x0000, 0xb8a4, 0x904d, 0x0110, 0x080c, 0x1031, 0x00d6, 0x00c6,
+	0xb8bc, 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006, 0x6014, 0x2048,
+	0x080c, 0xcc86, 0x0110, 0x080c, 0x0fb1, 0x080c, 0xaf43, 0x00ce,
+	0x0c88, 0x00ce, 0x00de, 0x2b48, 0xb8c8, 0xb85e, 0xb8c4, 0xb862,
+	0x080c, 0x1041, 0x00de, 0x9006, 0x002e, 0x012e, 0x009e, 0x00be,
+	0x0005, 0x0016, 0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0030,
+	0x9188, 0x1000, 0x2104, 0x905d, 0x0dc0, 0x9006, 0x001e, 0x0005,
+	0x00d6, 0x0156, 0x0136, 0x0146, 0x9006, 0xb80a, 0xb80e, 0xb800,
+	0xc08c, 0xb802, 0x080c, 0x743e, 0x1510, 0xb8a0, 0x9086, 0x007e,
+	0x0120, 0x080c, 0xaead, 0x11d8, 0x0078, 0x7040, 0xd0e4, 0x01b8,
+	0x00c6, 0x2061, 0x1981, 0x7048, 0x2062, 0x704c, 0x6006, 0x7050,
+	0x600a, 0x7054, 0x600e, 0x00ce, 0x703c, 0x2069, 0x0140, 0x9005,
+	0x1110, 0x2001, 0x0001, 0x6886, 0x2069, 0x1800, 0x68b6, 0x7040,
+	0xb85e, 0x7048, 0xb862, 0x704c, 0xb866, 0x20e1, 0x0000, 0x2099,
+	0x0276, 0xb8c4, 0x20e8, 0xb8c8, 0x9088, 0x000a, 0x21a0, 0x20a9,
+	0x0004, 0x4003, 0x2099, 0x027a, 0x9088, 0x0006, 0x21a0, 0x20a9,
+	0x0004, 0x4003, 0x2069, 0x0200, 0x6817, 0x0001, 0x7040, 0xb86a,
+	0x7144, 0xb96e, 0x7048, 0xb872, 0x7050, 0xb876, 0x2069, 0x0200,
+	0x6817, 0x0000, 0xb8a0, 0x9086, 0x007e, 0x1110, 0x7144, 0xb96e,
+	0x9182, 0x0211, 0x1218, 0x2009, 0x0008, 0x0400, 0x9182, 0x0259,
+	0x1218, 0x2009, 0x0007, 0x00d0, 0x9182, 0x02c1, 0x1218, 0x2009,
+	0x0006, 0x00a0, 0x9182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070,
+	0x9182, 0x0421, 0x1218, 0x2009, 0x0004, 0x0040, 0x9182, 0x0581,
+	0x1218, 0x2009, 0x0003, 0x0010, 0x2009, 0x0002, 0xb992, 0x014e,
+	0x013e, 0x015e, 0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071,
+	0x0260, 0x7034, 0xb896, 0x703c, 0xb89a, 0x7054, 0xb89e, 0x0036,
+	0xbbcc, 0xc384, 0xba00, 0x2009, 0x1867, 0x210c, 0xd0bc, 0x0120,
+	0xd1ec, 0x0110, 0xc2ad, 0x0008, 0xc2ac, 0xd0c4, 0x0148, 0xd1e4,
+	0x0138, 0xc2bd, 0xd0cc, 0x0128, 0xd38c, 0x1108, 0xc385, 0x0008,
+	0xc2bc, 0xba02, 0xbbce, 0x003e, 0x00ee, 0x002e, 0x001e, 0x0005,
+	0x0096, 0x0126, 0x2091, 0x8000, 0xb8a4, 0x904d, 0x0578, 0xa900,
+	0x81ff, 0x15c0, 0xaa04, 0x9282, 0x0010, 0x16c8, 0x0136, 0x0146,
+	0x01c6, 0x01d6, 0x8906, 0x8006, 0x8007, 0x908c, 0x003f, 0x21e0,
+	0x9084, 0xffc0, 0x9080, 0x0004, 0x2098, 0x2009, 0x0010, 0x20a9,
+	0x0001, 0x4002, 0x9086, 0xffff, 0x0120, 0x8109, 0x1dd0, 0x080c,
+	0x0dd5, 0x3c00, 0x20e8, 0x3300, 0x8001, 0x20a0, 0x4604, 0x8210,
+	0xaa06, 0x01de, 0x01ce, 0x014e, 0x013e, 0x0060, 0x080c, 0x0fff,
+	0x0170, 0x2900, 0xb8a6, 0xa803, 0x0000, 0x080c, 0x6855, 0xa807,
+	0x0001, 0xae12, 0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0x9006,
+	0x0cd8, 0x0126, 0x2091, 0x8000, 0x0096, 0xb8a4, 0x904d, 0x0188,
+	0xa800, 0x9005, 0x1150, 0x080c, 0x6864, 0x1158, 0xa804, 0x908a,
+	0x0002, 0x0218, 0x8001, 0xa806, 0x0020, 0x080c, 0x1031, 0xb8a7,
+	0x0000, 0x009e, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x91ce, 0x012e, 0x0005, 0x901e, 0x0010, 0x2019, 0x0001, 0x900e,
+	0x0126, 0x2091, 0x8000, 0xb84c, 0x2048, 0xb800, 0xd0dc, 0x1170,
+	0x89ff, 0x0500, 0x83ff, 0x0120, 0xa878, 0x9606, 0x0158, 0x0030,
+	0xa86c, 0x9406, 0x1118, 0xa870, 0x9506, 0x0120, 0x2908, 0xa800,
+	0x2048, 0x0c70, 0x080c, 0xa761, 0xaa00, 0xb84c, 0x9906, 0x1110,
+	0xba4e, 0x0020, 0x00a6, 0x2150, 0xb202, 0x00ae, 0x82ff, 0x1110,
+	0xb952, 0x89ff, 0x012e, 0x0005, 0x9016, 0x0489, 0x1110, 0x2011,
+	0x0001, 0x0005, 0x080c, 0x68b9, 0x0128, 0x080c, 0xcd43, 0x0010,
+	0x9085, 0x0001, 0x0005, 0x080c, 0x68b9, 0x0128, 0x080c, 0xcce8,
+	0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x68b9, 0x0128, 0x080c,
+	0xcd40, 0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x68b9, 0x0128,
+	0x080c, 0xcd07, 0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x68b9,
+	0x0128, 0x080c, 0xcd86, 0x0010, 0x9085, 0x0001, 0x0005, 0xb8a4,
+	0x900d, 0x1118, 0x9085, 0x0001, 0x0005, 0x0136, 0x01c6, 0xa800,
+	0x9005, 0x11b8, 0x890e, 0x810e, 0x810f, 0x9184, 0x003f, 0x20e0,
+	0x9184, 0xffc0, 0x9080, 0x0004, 0x2098, 0x20a9, 0x0001, 0x2009,
+	0x0010, 0x4002, 0x9606, 0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001,
+	0x0008, 0x9006, 0x01ce, 0x013e, 0x0005, 0x0146, 0x01d6, 0xa860,
+	0x20e8, 0xa85c, 0x9080, 0x0004, 0x20a0, 0x20a9, 0x0010, 0x2009,
+	0xffff, 0x4104, 0x01de, 0x014e, 0x0136, 0x01c6, 0xa800, 0x9005,
+	0x11b8, 0x890e, 0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184,
+	0xffc0, 0x9080, 0x0004, 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010,
+	0x4002, 0x9606, 0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0068,
+	0x0146, 0x01d6, 0x3300, 0x8001, 0x20a0, 0x3c00, 0x20e8, 0x2001,
+	0xffff, 0x4004, 0x01de, 0x014e, 0x9006, 0x01ce, 0x013e, 0x0005,
+	0x0096, 0x0126, 0x2091, 0x8000, 0xb8a4, 0x904d, 0x1128, 0x080c,
+	0x0fff, 0x0168, 0x2900, 0xb8a6, 0x080c, 0x6855, 0xa803, 0x0001,
+	0xa807, 0x0000, 0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0x9006,
+	0x0cd8, 0x0096, 0x0126, 0x2091, 0x8000, 0xb8a4, 0x904d, 0x0130,
+	0xb8a7, 0x0000, 0x080c, 0x1031, 0x9085, 0x0001, 0x012e, 0x009e,
+	0x0005, 0xb89c, 0xd0a4, 0x0005, 0x00b6, 0x00f6, 0x080c, 0x743e,
+	0x01b0, 0x71c4, 0x81ff, 0x1198, 0x71dc, 0xd19c, 0x0180, 0x2001,
+	0x007e, 0x9080, 0x1000, 0x2004, 0x905d, 0x0148, 0xb804, 0x9084,
+	0x00ff, 0x9086, 0x0006, 0x1118, 0xb800, 0xc0ed, 0xb802, 0x2079,
+	0x1847, 0x7804, 0xd0a4, 0x01d0, 0x0156, 0x20a9, 0x007f, 0x900e,
+	0x0016, 0x080c, 0x6699, 0x1168, 0xb804, 0x9084, 0xff00, 0x8007,
+	0x9096, 0x0004, 0x0118, 0x9086, 0x0006, 0x1118, 0xb800, 0xc0ed,
+	0xb802, 0x001e, 0x8108, 0x1f04, 0x68e0, 0x015e, 0x080c, 0x69ca,
+	0x0120, 0x2001, 0x1984, 0x200c, 0x0038, 0x2079, 0x1847, 0x7804,
+	0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011, 0x690b, 0x080c, 0x8648,
+	0x00fe, 0x00be, 0x0005, 0x00b6, 0x2011, 0x690b, 0x080c, 0x85b0,
+	0x080c, 0x69ca, 0x01d8, 0x2001, 0x107e, 0x2004, 0x2058, 0xb900,
+	0xc1ec, 0xb902, 0x080c, 0x6a08, 0x0130, 0x2009, 0x07d0, 0x2011,
+	0x690b, 0x080c, 0x8648, 0x00e6, 0x2071, 0x1800, 0x9006, 0x707e,
+	0x7060, 0x7082, 0x080c, 0x2ff5, 0x00ee, 0x04b0, 0x0156, 0x00c6,
+	0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x6699, 0x1538, 0xb800,
+	0xd0ec, 0x0520, 0x0046, 0xbaa0, 0x2220, 0x9006, 0x2009, 0x0029,
+	0x080c, 0xe73a, 0xb800, 0xc0e5, 0xc0ec, 0xb802, 0x080c, 0x6a04,
+	0x2001, 0x0707, 0x1128, 0xb804, 0x9084, 0x00ff, 0x9085, 0x0700,
+	0xb806, 0x2019, 0x0029, 0x080c, 0x9356, 0x0076, 0x903e, 0x080c,
+	0x9229, 0x900e, 0x080c, 0xe477, 0x007e, 0x004e, 0x001e, 0x8108,
+	0x1f04, 0x6933, 0x00ce, 0x015e, 0x00be, 0x0005, 0x00b6, 0x6010,
+	0x2058, 0xb800, 0xc0ec, 0xb802, 0x00be, 0x0005, 0x00b6, 0x00c6,
+	0x0096, 0x080c, 0x1018, 0x090c, 0x0dd5, 0x2958, 0x009e, 0x2001,
+	0x196a, 0x2b02, 0x8b07, 0x8006, 0x8006, 0x908c, 0x003f, 0xb9c6,
+	0x908c, 0xffc0, 0xb9ca, 0xb8af, 0x0000, 0x2009, 0x00ff, 0x080c,
+	0x60c7, 0xb807, 0x0006, 0xb813, 0x00ff, 0xb817, 0xffff, 0xb86f,
+	0x0200, 0xb86c, 0xb893, 0x0002, 0xb8bb, 0x0520, 0xb8a3, 0x00ff,
+	0xb8af, 0x0000, 0x00ce, 0x00be, 0x0005, 0x7810, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0ac, 0x0005, 0x6010, 0x00b6, 0x905d, 0x0108,
+	0xb800, 0x00be, 0xd0bc, 0x0005, 0x0006, 0x0016, 0x0026, 0xb804,
+	0x908c, 0x00ff, 0x9196, 0x0006, 0x0188, 0x9196, 0x0004, 0x0170,
+	0x9196, 0x0005, 0x0158, 0x908c, 0xff00, 0x810f, 0x9196, 0x0006,
+	0x0128, 0x9196, 0x0004, 0x0110, 0x9196, 0x0005, 0x002e, 0x001e,
+	0x000e, 0x0005, 0x00b6, 0x00f6, 0x2001, 0x107e, 0x2004, 0x905d,
+	0x0110, 0xb800, 0xd0ec, 0x00fe, 0x00be, 0x0005, 0x0126, 0x0026,
+	0x2091, 0x8000, 0x0006, 0xbaa0, 0x9290, 0x1000, 0x2204, 0x9b06,
+	0x190c, 0x0dd5, 0x000e, 0xba00, 0x9005, 0x0110, 0xc2fd, 0x0008,
+	0xc2fc, 0xba02, 0x002e, 0x012e, 0x0005, 0x2011, 0x1837, 0x2204,
+	0xd0cc, 0x0138, 0x2001, 0x1982, 0x200c, 0x2011, 0x69fa, 0x080c,
+	0x8648, 0x0005, 0x2011, 0x69fa, 0x080c, 0x85b0, 0x2011, 0x1837,
+	0x2204, 0xc0cc, 0x2012, 0x0005, 0x080c, 0x575d, 0xd0ac, 0x0005,
+	0x080c, 0x575d, 0xd0a4, 0x0005, 0x0016, 0xb904, 0x9184, 0x00ff,
+	0x908e, 0x0006, 0x001e, 0x0005, 0x0016, 0xb904, 0x9184, 0xff00,
+	0x8007, 0x908e, 0x0006, 0x001e, 0x0005, 0x00b6, 0x00f6, 0x080c,
+	0xd388, 0x0158, 0x70dc, 0x9084, 0x0028, 0x0138, 0x2001, 0x107f,
+	0x2004, 0x905d, 0x0110, 0xb8cc, 0xd094, 0x00fe, 0x00be, 0x0005,
+	0x2071, 0x1910, 0x7003, 0x0001, 0x7007, 0x0000, 0x9006, 0x7012,
+	0x7016, 0x701a, 0x701e, 0x700a, 0x7046, 0x0005, 0x0016, 0x00e6,
+	0x2071, 0x1947, 0x900e, 0x710a, 0x080c, 0x575d, 0xd0fc, 0x1140,
+	0x080c, 0x575d, 0x900e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x00f8,
+	0x2001, 0x1867, 0x200c, 0x9184, 0x0007, 0x0002, 0x6a48, 0x6a48,
+	0x6a48, 0x6a48, 0x6a48, 0x6a5e, 0x6a6c, 0x6a48, 0x7003, 0x0003,
+	0x2009, 0x1868, 0x210c, 0x9184, 0xff00, 0x8007, 0x9005, 0x1110,
+	0x2001, 0x0002, 0x7006, 0x0018, 0x7003, 0x0005, 0x0c88, 0x00ee,
+	0x001e, 0x0005, 0x00e6, 0x2071, 0x0050, 0x684c, 0x9005, 0x1150,
+	0x00e6, 0x2071, 0x1910, 0x7028, 0xc085, 0x702a, 0x00ee, 0x9085,
+	0x0001, 0x0488, 0x6844, 0x9005, 0x0158, 0x080c, 0x7796, 0x6a60,
+	0x9200, 0x7002, 0x6864, 0x9101, 0x7006, 0x9006, 0x7012, 0x7016,
+	0x6860, 0x7002, 0x6864, 0x7006, 0x6868, 0x700a, 0x686c, 0x700e,
+	0x6844, 0x9005, 0x1110, 0x7012, 0x7016, 0x684c, 0x701a, 0x701c,
+	0x9085, 0x0040, 0x701e, 0x7037, 0x0019, 0x702b, 0x0001, 0x00e6,
+	0x2071, 0x1910, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700b,
+	0x0000, 0x00ee, 0x9006, 0x00ee, 0x0005, 0x00e6, 0x0026, 0x2071,
+	0x1947, 0x7000, 0x9015, 0x0904, 0x6d1c, 0x9286, 0x0003, 0x0904,
+	0x6bb2, 0x9286, 0x0005, 0x0904, 0x6bb2, 0x2071, 0x1877, 0xa87c,
+	0x9005, 0x0904, 0x6b13, 0x7140, 0xa868, 0x9102, 0x0a04, 0x6d1c,
+	0xa878, 0xd084, 0x15d8, 0xa853, 0x0019, 0x2001, 0x8023, 0xa84e,
+	0x2071, 0x1910, 0x701c, 0x9005, 0x1904, 0x6eb2, 0x0e04, 0x6f20,
+	0x2071, 0x0000, 0xa850, 0x7032, 0xa84c, 0x7082, 0xa870, 0x7086,
+	0xa86c, 0x708a, 0xa880, 0x708e, 0x7036, 0x0146, 0x01d6, 0x0136,
+	0x01c6, 0x0156, 0x20e9, 0x0000, 0x20a1, 0x002a, 0xa868, 0x20a8,
+	0xa860, 0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x4003, 0x015e,
+	0x01ce, 0x013e, 0x01de, 0x014e, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x190c, 0x119b, 0x0804, 0x6b95, 0xa853, 0x001b,
+	0x2001, 0x8027, 0x0820, 0x7004, 0xd08c, 0x1904, 0x6d1c, 0xa853,
+	0x001a, 0x2001, 0x8024, 0x0804, 0x6ad7, 0x00e6, 0x0026, 0x2071,
+	0x1947, 0x7000, 0x9015, 0x0904, 0x6d1c, 0x9286, 0x0003, 0x0904,
+	0x6bb2, 0x9286, 0x0005, 0x0904, 0x6bb2, 0xa84f, 0x8022, 0xa853,
+	0x0018, 0x0804, 0x6b7a, 0xa868, 0xd0fc, 0x11d8, 0x00e6, 0x0026,
+	0x2001, 0x1947, 0x2004, 0x9005, 0x0904, 0x6d1c, 0xa87c, 0xd0bc,
+	0x1904, 0x6d1c, 0xa978, 0xa874, 0x9105, 0x1904, 0x6d1c, 0x2001,
+	0x1947, 0x2004, 0x0002, 0x6d1c, 0x6b76, 0x6bb2, 0x6bb2, 0x6d1c,
+	0x6bb2, 0x0005, 0xa868, 0xd0fc, 0x1500, 0x00e6, 0x0026, 0x2009,
+	0x1947, 0x210c, 0x81ff, 0x0904, 0x6d1c, 0xa87c, 0xd0cc, 0x0904,
+	0x6d1c, 0xa880, 0x9084, 0x00ff, 0x9086, 0x0001, 0x1904, 0x6d1c,
+	0x9186, 0x0003, 0x0904, 0x6bb2, 0x9186, 0x0005, 0x0904, 0x6bb2,
+	0xa84f, 0x8021, 0xa853, 0x0017, 0x0028, 0x0005, 0xa84f, 0x8020,
+	0xa853, 0x0016, 0x2071, 0x1910, 0x701c, 0x9005, 0x1904, 0x6eb2,
+	0x0e04, 0x6f20, 0x2071, 0x0000, 0xa84c, 0x7082, 0xa850, 0x7032,
+	0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x2071, 0x1800, 0x2011,
+	0x0001, 0xa804, 0x900d, 0x702c, 0x1158, 0xa802, 0x2900, 0x702e,
+	0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2, 0x002e, 0x00ee, 0x0005,
+	0x0096, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8,
+	0x009e, 0x0c58, 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050, 0x2071,
+	0x1910, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904, 0x6ca1, 0x782c,
+	0x908c, 0x0780, 0x190c, 0x706e, 0x8004, 0x8004, 0x8004, 0x9084,
+	0x0003, 0x0002, 0x6bd0, 0x6ca1, 0x6bf5, 0x6c3c, 0x080c, 0x0dd5,
+	0x2071, 0x1800, 0x2900, 0x7822, 0xa804, 0x900d, 0x1170, 0x2071,
+	0x19f9, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005,
+	0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0,
+	0x9200, 0x70c2, 0x080c, 0x84c2, 0x0c10, 0x2071, 0x1800, 0x2900,
+	0x7822, 0xa804, 0x900d, 0x1580, 0x7824, 0x00e6, 0x2071, 0x0040,
+	0x712c, 0xd19c, 0x1148, 0x2009, 0x1830, 0x210c, 0x918a, 0x0020,
+	0x0218, 0x7022, 0x00ee, 0x0058, 0x00ee, 0x2048, 0x702c, 0xa802,
+	0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c, 0x84c2, 0x782c,
+	0x9094, 0x0780, 0x190c, 0x706e, 0xd0a4, 0x19f0, 0x2071, 0x19f9,
+	0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005, 0x703e,
+	0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904,
+	0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200,
+	0x70c2, 0x080c, 0x84c2, 0x0800, 0x0096, 0x00e6, 0x7824, 0x2048,
+	0x2071, 0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000,
+	0x70c2, 0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e,
+	0xd0a4, 0x1d60, 0x00ee, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e,
+	0xd09c, 0x11a0, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x1560,
+	0x2071, 0x19f9, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004,
+	0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x009e, 0x2908,
+	0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902,
+	0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1170, 0x2071, 0x19f9,
+	0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005, 0x703e,
+	0x00fe, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c,
+	0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e,
+	0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a,
+	0x0110, 0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904,
+	0x6cf6, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd09c, 0x1198,
+	0x701c, 0x904d, 0x0180, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a,
+	0xa800, 0x701e, 0x2900, 0x7822, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x706e, 0xd09c, 0x0d68, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e,
+	0xd0a4, 0x01b0, 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800, 0x702c,
+	0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c, 0x84c2,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd0a4, 0x1d60, 0x00ee,
+	0x2071, 0x19f9, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004,
+	0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071,
+	0x1800, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900,
+	0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2,
+	0x00ee, 0x0804, 0x6cb1, 0xa868, 0xd0fc, 0x1560, 0x0096, 0xa804,
+	0xa807, 0x0000, 0x904d, 0x190c, 0x0fb1, 0x009e, 0x0018, 0xa868,
+	0xd0fc, 0x1500, 0x00e6, 0x0026, 0xa84f, 0x0000, 0x00f6, 0x2079,
+	0x0050, 0x2071, 0x1910, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904,
+	0x6e30, 0x782c, 0x908c, 0x0780, 0x190c, 0x706e, 0x8004, 0x8004,
+	0x8004, 0x9084, 0x0003, 0x0002, 0x6d3b, 0x6e30, 0x6d56, 0x6dc3,
+	0x080c, 0x0dd5, 0x0005, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804,
+	0x900d, 0x1120, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c,
+	0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e,
+	0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2, 0x0c60, 0x2071, 0x1800,
+	0x2900, 0x7822, 0xa804, 0x900d, 0x1904, 0x6db2, 0x7830, 0x8007,
+	0x9084, 0x001f, 0x9082, 0x0001, 0x1220, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1148,
+	0x2009, 0x1830, 0x210c, 0x918a, 0x0020, 0x0218, 0x7022, 0x00ee,
+	0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0,
+	0x8000, 0x70c2, 0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x706e, 0xd0a4, 0x19f0, 0x0e04, 0x6da9, 0x7838, 0x7938, 0x910e,
+	0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de,
+	0x2001, 0x1921, 0x200c, 0xc184, 0x2102, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x2001, 0x1921, 0x200c, 0xc185, 0x2102, 0x00fe, 0x002e,
+	0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210,
+	0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c,
+	0x84c2, 0x0804, 0x6d69, 0x0096, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2,
+	0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6e03, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x119b, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd09c,
+	0x1170, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x11e0, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x7044, 0xc085, 0x7046, 0x0c58, 0x009e,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1120, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0,
+	0x9200, 0x70c2, 0x080c, 0x84c2, 0x00fe, 0x002e, 0x00ee, 0x0005,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904, 0x6e9d,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd09c, 0x11b0, 0x701c,
+	0x904d, 0x0198, 0xa84c, 0x9005, 0x1180, 0x7010, 0x8001, 0x7012,
+	0x1108, 0x701a, 0xa800, 0x701e, 0x2900, 0x7822, 0x782c, 0x9094,
+	0x0780, 0x190c, 0x706e, 0xd09c, 0x0d50, 0x782c, 0x9094, 0x0780,
+	0x190c, 0x706e, 0xd0a4, 0x05a8, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2,
+	0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c, 0x706e, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6e96, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x119b, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x7044, 0xc085,
+	0x7046, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2, 0x00ee,
+	0x0804, 0x6e40, 0x2071, 0x1910, 0xa803, 0x0000, 0x2908, 0x7010,
+	0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008,
+	0x711e, 0x2148, 0xa804, 0x900d, 0x1128, 0x1e04, 0x6edd, 0x002e,
+	0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904,
+	0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200,
+	0x70c2, 0x080c, 0x84c2, 0x0e04, 0x6ec7, 0x2071, 0x1910, 0x701c,
+	0x2048, 0xa84c, 0x900d, 0x0d18, 0x2071, 0x0000, 0x7182, 0xa850,
+	0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0xa850, 0x9082,
+	0x0019, 0x1278, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x119b, 0x2071, 0x1910, 0x080c, 0x705a, 0x002e, 0x00ee,
+	0x0005, 0xa850, 0x9082, 0x001c, 0x1e68, 0xa880, 0x708e, 0x7036,
+	0x0146, 0x01d6, 0x0136, 0x01c6, 0x0156, 0x20e9, 0x0000, 0x20a1,
+	0x002a, 0xa868, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0021,
+	0x2098, 0x4003, 0x015e, 0x01ce, 0x013e, 0x01de, 0x014e, 0x0890,
+	0x2071, 0x1910, 0xa803, 0x0000, 0x2908, 0x7010, 0x8000, 0x7012,
+	0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, 0x2148,
+	0xa804, 0x900d, 0x1118, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x84c2, 0x002e,
+	0x00ee, 0x0005, 0x0006, 0xa87c, 0x0006, 0xa867, 0x0103, 0x20a9,
+	0x001c, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001d, 0x20a0, 0x9006,
+	0x4004, 0x000e, 0x9084, 0x00ff, 0xa87e, 0x000e, 0xa87a, 0xa982,
+	0x0005, 0x2071, 0x1910, 0x7004, 0x0002, 0x6f6d, 0x6f6e, 0x7059,
+	0x6f6e, 0x6f6b, 0x7059, 0x080c, 0x0dd5, 0x0005, 0x2001, 0x1947,
+	0x2004, 0x0002, 0x6f78, 0x6f78, 0x6ff2, 0x6ff3, 0x6f78, 0x6ff3,
+	0x0126, 0x2091, 0x8000, 0x1e0c, 0x7079, 0x701c, 0x904d, 0x0508,
+	0xa84c, 0x9005, 0x0904, 0x6fc3, 0x0e04, 0x6fa1, 0xa94c, 0x2071,
+	0x0000, 0x7182, 0xa850, 0x7032, 0xa86c, 0x7086, 0x7036, 0xa870,
+	0x708a, 0xa850, 0x9082, 0x0019, 0x1278, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x2071, 0x1910, 0x080c,
+	0x705a, 0x012e, 0x0804, 0x6ff1, 0xa850, 0x9082, 0x001c, 0x1e68,
+	0xa880, 0x708e, 0x7036, 0x0146, 0x01d6, 0x0136, 0x01c6, 0x0156,
+	0x20e9, 0x0000, 0x20a1, 0x002a, 0xa868, 0x20a8, 0xa860, 0x20e0,
+	0xa85c, 0x9080, 0x0021, 0x2098, 0x4003, 0x015e, 0x01ce, 0x013e,
+	0x01de, 0x014e, 0x0890, 0x2001, 0x005b, 0x2004, 0x9094, 0x0780,
+	0x190c, 0x706e, 0xd09c, 0x2071, 0x1910, 0x1510, 0x2071, 0x1910,
+	0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130,
+	0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900, 0x00d6,
+	0x2069, 0x0050, 0x6822, 0x00de, 0x2071, 0x1910, 0x701c, 0x2048,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x0005, 0x0005, 0x00d6, 0x2008, 0x2069, 0x19f9, 0x683c,
+	0x9005, 0x0760, 0x0158, 0x9186, 0x0003, 0x0540, 0x2001, 0x1815,
+	0x2004, 0x2009, 0x1aca, 0x210c, 0x9102, 0x1500, 0x0126, 0x2091,
+	0x8000, 0x2069, 0x0050, 0x693c, 0x6838, 0x9106, 0x0190, 0x0e04,
+	0x7025, 0x2069, 0x0000, 0x6837, 0x8040, 0x6833, 0x0012, 0x6883,
+	0x8040, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x119b, 0x2069, 0x19f9, 0x683f, 0xffff, 0x012e, 0x00de, 0x0126,
+	0x2091, 0x8000, 0x1e0c, 0x70da, 0x701c, 0x904d, 0x0540, 0x2001,
+	0x005b, 0x2004, 0x9094, 0x0780, 0x15c9, 0xd09c, 0x1500, 0x2071,
+	0x1910, 0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003,
+	0x1130, 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900,
+	0x00d6, 0x2069, 0x0050, 0x6822, 0x00de, 0x701c, 0x2048, 0x7010,
+	0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e,
+	0x0005, 0x0005, 0x0126, 0x2091, 0x8000, 0x701c, 0x904d, 0x0160,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x080c, 0x1031, 0x0005, 0x012e, 0x0005, 0x2091, 0x8000,
+	0x0e04, 0x7070, 0x0006, 0x0016, 0x2001, 0x8004, 0x0006, 0x0804,
+	0x0dde, 0x0096, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01c0,
+	0xc084, 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069,
+	0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x00fe, 0x009e, 0x0005,
+	0x782c, 0x9094, 0x0780, 0x1991, 0xd0a4, 0x0db8, 0x00e6, 0x2071,
+	0x1800, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1148,
+	0x2009, 0x1830, 0x210c, 0x918a, 0x0020, 0x0218, 0x7022, 0x00ee,
+	0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0,
+	0x8000, 0x70c2, 0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x706e, 0xd0a4, 0x19f0, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6,
+	0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x00ee, 0x00fe,
+	0x009e, 0x0005, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01b8,
+	0xc084, 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069,
+	0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x119b, 0x00fe, 0x0005, 0x782c,
+	0x9094, 0x0780, 0x190c, 0x706e, 0xd0a4, 0x0db8, 0x00e6, 0x2071,
+	0x1800, 0x7824, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0,
+	0x8000, 0x70c2, 0x080c, 0x84c2, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x706e, 0xd0a4, 0x1d70, 0x00d6, 0x2069, 0x0050, 0x693c, 0x2069,
+	0x1947, 0x6808, 0x690a, 0x2069, 0x19f9, 0x9102, 0x1118, 0x683c,
+	0x9005, 0x1328, 0x2001, 0x1948, 0x200c, 0x810d, 0x693e, 0x00de,
+	0x00ee, 0x00fe, 0x0005, 0x7098, 0x908a, 0x0029, 0x1a0c, 0x0dd5,
+	0x9082, 0x001d, 0x001b, 0x6027, 0x1e00, 0x0005, 0x7202, 0x7188,
+	0x71a4, 0x71ce, 0x71f1, 0x7231, 0x7243, 0x71a4, 0x7219, 0x7143,
+	0x7171, 0x7142, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005,
+	0x1180, 0x6808, 0x9005, 0x1518, 0x709b, 0x0028, 0x2069, 0x198e,
+	0x2d04, 0x7002, 0x080c, 0x7576, 0x6028, 0x9085, 0x0600, 0x602a,
+	0x00b0, 0x709b, 0x0028, 0x2069, 0x198e, 0x2d04, 0x7002, 0x6028,
+	0x9085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071,
+	0x1a61, 0x080c, 0x1aec, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de,
+	0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1178, 0x6808,
+	0x9005, 0x1160, 0x709b, 0x0028, 0x2069, 0x198e, 0x2d04, 0x7002,
+	0x080c, 0x7611, 0x6028, 0x9085, 0x0600, 0x602a, 0x00de, 0x0005,
+	0x0006, 0x2001, 0x0090, 0x080c, 0x2d4e, 0x000e, 0x6124, 0xd1e4,
+	0x1190, 0x080c, 0x72b0, 0xd1d4, 0x1160, 0xd1dc, 0x1138, 0xd1cc,
+	0x0150, 0x709b, 0x0020, 0x080c, 0x72b0, 0x0028, 0x709b, 0x001d,
+	0x0010, 0x709b, 0x001f, 0x0005, 0x2001, 0x0088, 0x080c, 0x2d4e,
+	0x6124, 0xd1cc, 0x11e8, 0xd1dc, 0x11c0, 0xd1e4, 0x1198, 0x9184,
+	0x1e00, 0x11d8, 0x080c, 0x1b11, 0x60e3, 0x0001, 0x600c, 0xc0b4,
+	0x600e, 0x080c, 0x746a, 0x2001, 0x0080, 0x080c, 0x2d4e, 0x709b,
+	0x0028, 0x0058, 0x709b, 0x001e, 0x0040, 0x709b, 0x001d, 0x0028,
+	0x709b, 0x0020, 0x0010, 0x709b, 0x001f, 0x0005, 0x080c, 0x1b11,
+	0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x746a, 0x2001,
+	0x0080, 0x080c, 0x2d4e, 0x6124, 0xd1d4, 0x1180, 0xd1dc, 0x1158,
+	0xd1e4, 0x1130, 0x9184, 0x1e00, 0x1158, 0x709b, 0x0028, 0x0040,
+	0x709b, 0x001e, 0x0028, 0x709b, 0x001d, 0x0010, 0x709b, 0x001f,
+	0x0005, 0x2001, 0x00a0, 0x080c, 0x2d4e, 0x6124, 0xd1dc, 0x1138,
+	0xd1e4, 0x0138, 0x080c, 0x1b11, 0x709b, 0x001e, 0x0010, 0x709b,
+	0x001d, 0x0005, 0x080c, 0x7333, 0x6124, 0xd1dc, 0x1188, 0x080c,
+	0x72b0, 0x0016, 0x080c, 0x1b11, 0x001e, 0xd1d4, 0x1128, 0xd1e4,
+	0x0138, 0x709b, 0x001e, 0x0020, 0x709b, 0x001f, 0x080c, 0x72b0,
+	0x0005, 0x0006, 0x2001, 0x00a0, 0x080c, 0x2d4e, 0x000e, 0x6124,
+	0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140,
+	0x709b, 0x001e, 0x0028, 0x709b, 0x001d, 0x0010, 0x709b, 0x0021,
+	0x0005, 0x080c, 0x7333, 0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128,
+	0xd1e4, 0x0140, 0x709b, 0x001e, 0x0028, 0x709b, 0x001d, 0x0010,
+	0x709b, 0x001f, 0x0005, 0x0006, 0x2001, 0x0090, 0x080c, 0x2d4e,
+	0x000e, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128,
+	0xd1e4, 0x0158, 0x709b, 0x001e, 0x0040, 0x709b, 0x001d, 0x0028,
+	0x709b, 0x0020, 0x0010, 0x709b, 0x001f, 0x0005, 0x0016, 0x00c6,
+	0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071,
+	0x1800, 0x2091, 0x8000, 0x080c, 0x743e, 0x11d8, 0x2001, 0x180c,
+	0x200c, 0xd1b4, 0x01b0, 0xc1b4, 0x2102, 0x6027, 0x0200, 0x080c,
+	0x2c76, 0x6024, 0xd0cc, 0x0148, 0x2001, 0x00a0, 0x080c, 0x2d4e,
+	0x080c, 0x7724, 0x080c, 0x60ad, 0x0428, 0x6028, 0xc0cd, 0x602a,
+	0x0408, 0x080c, 0x7458, 0x0150, 0x080c, 0x744f, 0x1138, 0x2001,
+	0x0001, 0x080c, 0x2828, 0x080c, 0x7416, 0x00a0, 0x080c, 0x7330,
+	0x0178, 0x2001, 0x0001, 0x080c, 0x2828, 0x7098, 0x9086, 0x001e,
+	0x0120, 0x7098, 0x9086, 0x0022, 0x1118, 0x709b, 0x0025, 0x0010,
+	0x709b, 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x0005,
+	0x0026, 0x2011, 0x72c1, 0x080c, 0x868a, 0x002e, 0x0016, 0x0026,
+	0x2009, 0x0064, 0x2011, 0x72c1, 0x080c, 0x8681, 0x002e, 0x001e,
+	0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, 0xa356, 0x2071, 0x1800,
+	0x080c, 0x725e, 0x001e, 0x00fe, 0x00ee, 0x0005, 0x0016, 0x0026,
+	0x0036, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0126, 0x080c, 0xa356,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x2091, 0x8000,
+	0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, 0xa722, 0x2011,
+	0x0002, 0x080c, 0xa72c, 0x080c, 0xa636, 0x080c, 0x8636, 0x0036,
+	0x901e, 0x080c, 0xa6ac, 0x003e, 0x60e3, 0x0000, 0x080c, 0xeb79,
+	0x080c, 0xeb94, 0x2009, 0x0004, 0x080c, 0x2c7c, 0x080c, 0x2b97,
+	0x2001, 0x1800, 0x2003, 0x0004, 0x6027, 0x0008, 0x2011, 0x72c1,
+	0x080c, 0x868a, 0x080c, 0x7458, 0x0118, 0x9006, 0x080c, 0x2d4e,
+	0x080c, 0x0bae, 0x2001, 0x0001, 0x080c, 0x2828, 0x012e, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0026,
+	0x00e6, 0x2011, 0x72ce, 0x2071, 0x19f9, 0x701c, 0x9206, 0x1118,
+	0x7018, 0x9005, 0x0110, 0x9085, 0x0001, 0x00ee, 0x002e, 0x0005,
+	0x6020, 0xd09c, 0x0005, 0x6800, 0x9084, 0xfffe, 0x9086, 0x00c0,
+	0x0170, 0x2001, 0x00c0, 0x080c, 0x2d4e, 0x0156, 0x20a9, 0x002d,
+	0x1d04, 0x7340, 0x2091, 0x6000, 0x1f04, 0x7340, 0x015e, 0x0005,
+	0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071,
+	0x1800, 0x080c, 0x7733, 0x2001, 0x196c, 0x2003, 0x0000, 0x9006,
+	0x709a, 0x60e2, 0x6886, 0x080c, 0x28f0, 0x9006, 0x080c, 0x2d4e,
+	0x080c, 0x5f6c, 0x6027, 0xffff, 0x602b, 0x182f, 0x00ee, 0x00de,
+	0x00ce, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x2071, 0x1800, 0x2001, 0x197c, 0x200c, 0x9186, 0x0000,
+	0x0158, 0x9186, 0x0001, 0x0158, 0x9186, 0x0002, 0x0158, 0x9186,
+	0x0003, 0x0158, 0x0804, 0x7406, 0x709b, 0x0022, 0x0040, 0x709b,
+	0x0021, 0x0028, 0x709b, 0x0023, 0x0010, 0x709b, 0x0024, 0x60e3,
+	0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x28f0, 0x0026,
+	0x080c, 0xaeb4, 0x002e, 0x7000, 0x908e, 0x0004, 0x0118, 0x602b,
+	0x0028, 0x0010, 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000,
+	0x20a9, 0x0005, 0x6024, 0xd0ac, 0x0150, 0x012e, 0x015e, 0x080c,
+	0xd388, 0x0118, 0x9006, 0x080c, 0x2d78, 0x0804, 0x7412, 0x6800,
+	0x9084, 0x00a1, 0xc0bd, 0x6802, 0x080c, 0x2c76, 0x6904, 0xd1d4,
+	0x1140, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x1f04, 0x73aa, 0x080c,
+	0x7495, 0x012e, 0x015e, 0x080c, 0x744f, 0x01d8, 0x6044, 0x9005,
+	0x0198, 0x2011, 0x0114, 0x2204, 0x9085, 0x0100, 0x2012, 0x6050,
+	0x0006, 0x9085, 0x0020, 0x6052, 0x080c, 0x7495, 0x9006, 0x8001,
+	0x1df0, 0x000e, 0x6052, 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c,
+	0x7495, 0x080c, 0xd388, 0x0118, 0x9006, 0x080c, 0x2d78, 0x0016,
+	0x0026, 0x7000, 0x908e, 0x0004, 0x0130, 0x2009, 0x00c8, 0x2011,
+	0x72ce, 0x080c, 0x8648, 0x002e, 0x001e, 0x080c, 0x84b9, 0x7034,
+	0xc085, 0x7036, 0x2001, 0x197c, 0x2003, 0x0004, 0x080c, 0x712b,
+	0x080c, 0x744f, 0x0138, 0x6804, 0xd0d4, 0x1120, 0xd0dc, 0x1100,
+	0x080c, 0x7729, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x080c,
+	0x84d0, 0x080c, 0x84c2, 0x080c, 0x7733, 0x2001, 0x196c, 0x2003,
+	0x0000, 0x9006, 0x709a, 0x60e2, 0x6886, 0x080c, 0x28f0, 0x9006,
+	0x080c, 0x2d4e, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027, 0xffff,
+	0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001,
+	0x197b, 0x2004, 0x9086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x080c,
+	0x5761, 0x9084, 0x0030, 0x9086, 0x0000, 0x000e, 0x0005, 0x0006,
+	0x080c, 0x5761, 0x9084, 0x0030, 0x9086, 0x0030, 0x000e, 0x0005,
+	0x0006, 0x080c, 0x5761, 0x9084, 0x0030, 0x9086, 0x0010, 0x000e,
+	0x0005, 0x0006, 0x080c, 0x5761, 0x9084, 0x0030, 0x9086, 0x0020,
+	0x000e, 0x0005, 0x0036, 0x0016, 0x2001, 0x180c, 0x2004, 0x908c,
+	0x0013, 0x0180, 0x0020, 0x080c, 0x2910, 0x900e, 0x0028, 0x080c,
+	0x6a04, 0x1dc8, 0x2009, 0x0002, 0x2019, 0x0028, 0x080c, 0x31e9,
+	0x9006, 0x0019, 0x001e, 0x003e, 0x0005, 0x00e6, 0x2071, 0x180c,
+	0x2e04, 0x0130, 0x080c, 0xd381, 0x1128, 0x9085, 0x0010, 0x0010,
+	0x9084, 0xffef, 0x2072, 0x00ee, 0x0005, 0x6050, 0x0006, 0x60ec,
+	0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, 0x0016,
+	0x6138, 0x6050, 0x9084, 0xfbff, 0x9085, 0x2000, 0x6052, 0x613a,
+	0x20a9, 0x0012, 0x1d04, 0x74aa, 0x2091, 0x6000, 0x1f04, 0x74aa,
+	0x602f, 0x0100, 0x602f, 0x0000, 0x6050, 0x9085, 0x0400, 0x9084,
+	0xdfff, 0x6052, 0x613a, 0x001e, 0x602f, 0x0040, 0x602f, 0x0000,
+	0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e, 0x60ee,
+	0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x28f0,
+	0x2001, 0x00a0, 0x0006, 0x080c, 0xd388, 0x000e, 0x0130, 0x080c,
+	0x2d6c, 0x9006, 0x080c, 0x2d78, 0x0010, 0x080c, 0x2d4e, 0x000e,
+	0x6052, 0x6050, 0x0006, 0xc0e5, 0x6052, 0x00f6, 0x2079, 0x0100,
+	0x080c, 0x2beb, 0x00fe, 0x000e, 0x6052, 0x0005, 0x0156, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x2071, 0x1800, 0x6020, 0x9084, 0x0080, 0x0138, 0x2001,
+	0x180c, 0x200c, 0xc1c5, 0x2102, 0x0804, 0x7568, 0x2001, 0x180c,
+	0x200c, 0xc1c4, 0x2102, 0x6028, 0x9084, 0xe1ff, 0x602a, 0x6027,
+	0x0200, 0x2001, 0x0090, 0x080c, 0x2d4e, 0x20a9, 0x0366, 0x6024,
+	0xd0cc, 0x1518, 0x1d04, 0x7517, 0x2091, 0x6000, 0x1f04, 0x7517,
+	0x2011, 0x0003, 0x080c, 0xa722, 0x2011, 0x0002, 0x080c, 0xa72c,
+	0x080c, 0xa636, 0x901e, 0x080c, 0xa6ac, 0x2001, 0x00a0, 0x080c,
+	0x2d4e, 0x080c, 0x7724, 0x080c, 0x60ad, 0x080c, 0xd388, 0x0110,
+	0x080c, 0x0d45, 0x9085, 0x0001, 0x0488, 0x080c, 0x1b11, 0x60e3,
+	0x0000, 0x2001, 0x196c, 0x2004, 0x080c, 0x28f0, 0x60e2, 0x2001,
+	0x0080, 0x080c, 0x2d4e, 0x20a9, 0x0366, 0x6027, 0x1e00, 0x2009,
+	0x1e00, 0x080c, 0x2c76, 0x6024, 0x910c, 0x0138, 0x1d04, 0x754d,
+	0x2091, 0x6000, 0x1f04, 0x754d, 0x0818, 0x6028, 0x9085, 0x1e00,
+	0x602a, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886,
+	0x080c, 0xd388, 0x0110, 0x080c, 0x0d45, 0x9006, 0x00ee, 0x00de,
+	0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071,
+	0x1800, 0x7000, 0x9086, 0x0003, 0x1168, 0x2001, 0x020b, 0x2004,
+	0x9084, 0x5540, 0x9086, 0x5540, 0x1128, 0x2069, 0x1a78, 0x2d04,
+	0x8000, 0x206a, 0x2069, 0x0140, 0x6020, 0x9084, 0x00c0, 0x0120,
+	0x6884, 0x9005, 0x1904, 0x75db, 0x2001, 0x0088, 0x080c, 0x2d4e,
+	0x9006, 0x60e2, 0x6886, 0x080c, 0x28f0, 0x2069, 0x0200, 0x6804,
+	0x9005, 0x1118, 0x6808, 0x9005, 0x01c0, 0x6028, 0x9084, 0xfbff,
+	0x602a, 0x6027, 0x0400, 0x2069, 0x198e, 0x7000, 0x206a, 0x709b,
+	0x0026, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x75bd, 0x2091,
+	0x6000, 0x1f04, 0x75bd, 0x0804, 0x7609, 0x2069, 0x0140, 0x20a9,
+	0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x2c76, 0x6024,
+	0x910c, 0x0508, 0x9084, 0x1a00, 0x11f0, 0x1d04, 0x75c9, 0x2091,
+	0x6000, 0x1f04, 0x75c9, 0x2011, 0x0003, 0x080c, 0xa722, 0x2011,
+	0x0002, 0x080c, 0xa72c, 0x080c, 0xa636, 0x901e, 0x080c, 0xa6ac,
+	0x2001, 0x00a0, 0x080c, 0x2d4e, 0x080c, 0x7724, 0x080c, 0x60ad,
+	0x9085, 0x0001, 0x00b0, 0x2001, 0x0080, 0x080c, 0x2d4e, 0x2069,
+	0x0140, 0x60e3, 0x0000, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001,
+	0x0008, 0x6886, 0x2001, 0x196c, 0x2004, 0x080c, 0x28f0, 0x60e2,
+	0x9006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2071, 0x1800, 0x6020, 0x9084, 0x00c0, 0x01c8,
+	0x2011, 0x0003, 0x080c, 0xa722, 0x2011, 0x0002, 0x080c, 0xa72c,
+	0x080c, 0xa636, 0x901e, 0x080c, 0xa6ac, 0x2069, 0x0140, 0x2001,
+	0x00a0, 0x080c, 0x2d4e, 0x080c, 0x7724, 0x080c, 0x60ad, 0x0804,
+	0x76a4, 0x2001, 0x180c, 0x200c, 0xd1b4, 0x1160, 0xc1b5, 0x2102,
+	0x080c, 0x72b6, 0x2069, 0x0140, 0x2001, 0x0080, 0x080c, 0x2d4e,
+	0x60e3, 0x0000, 0x2069, 0x0200, 0x6804, 0x9005, 0x1118, 0x6808,
+	0x9005, 0x0180, 0x6028, 0x9084, 0xfdff, 0x602a, 0x6027, 0x0200,
+	0x2069, 0x198e, 0x7000, 0x206a, 0x709b, 0x0027, 0x7003, 0x0001,
+	0x0804, 0x76a4, 0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x2c76,
+	0x6024, 0x910c, 0x01c8, 0x9084, 0x1c00, 0x11b0, 0x1d04, 0x7662,
+	0x0006, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x8510, 0x00ee,
+	0x00de, 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071, 0x19f9, 0x7070,
+	0x00ee, 0x9005, 0x19f8, 0x0400, 0x0026, 0x2011, 0x72ce, 0x080c,
+	0x85b0, 0x2011, 0x72c1, 0x080c, 0x868a, 0x002e, 0x2069, 0x0140,
+	0x60e3, 0x0000, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008,
+	0x6886, 0x2001, 0x196c, 0x2004, 0x080c, 0x28f0, 0x60e2, 0x2001,
+	0x180c, 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e,
+	0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036,
+	0x0046, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800, 0x080c,
+	0xd381, 0x1904, 0x7712, 0x7130, 0xd184, 0x1170, 0x080c, 0x3378,
+	0x0138, 0xc18d, 0x7132, 0x2011, 0x1848, 0x2214, 0xd2ac, 0x1120,
+	0x7030, 0xd08c, 0x0904, 0x7712, 0x2011, 0x1848, 0x220c, 0xd1a4,
+	0x0538, 0x0016, 0x2019, 0x000e, 0x080c, 0xe6ae, 0x0156, 0x00b6,
+	0x20a9, 0x007f, 0x900e, 0x9186, 0x007e, 0x01a0, 0x9186, 0x0080,
+	0x0188, 0x080c, 0x6699, 0x1170, 0x2120, 0x9006, 0x0016, 0x2009,
+	0x000e, 0x080c, 0xe73a, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c,
+	0x879a, 0x001e, 0x8108, 0x1f04, 0x76db, 0x00be, 0x015e, 0x001e,
+	0xd1ac, 0x1148, 0x0016, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c,
+	0x31e9, 0x001e, 0x0078, 0x0156, 0x00b6, 0x20a9, 0x007f, 0x900e,
+	0x080c, 0x6699, 0x1110, 0x080c, 0x60c7, 0x8108, 0x1f04, 0x7708,
+	0x00be, 0x015e, 0x080c, 0x1b11, 0x080c, 0xaeb4, 0x60e3, 0x0000,
+	0x080c, 0x60ad, 0x080c, 0x736a, 0x00ee, 0x00ce, 0x004e, 0x003e,
+	0x002e, 0x001e, 0x015e, 0x0005, 0x2001, 0x197c, 0x2003, 0x0001,
+	0x0005, 0x2001, 0x197c, 0x2003, 0x0000, 0x0005, 0x2001, 0x197b,
+	0x2003, 0xaaaa, 0x0005, 0x2001, 0x197b, 0x2003, 0x0000, 0x0005,
+	0x2071, 0x18fa, 0x7003, 0x0000, 0x7007, 0x0000, 0x080c, 0x1018,
+	0x090c, 0x0dd5, 0xa8ab, 0xdcb0, 0x2900, 0x704e, 0x080c, 0x1018,
+	0x090c, 0x0dd5, 0xa8ab, 0xdcb0, 0x2900, 0x7052, 0xa867, 0x0000,
+	0xa86b, 0x0001, 0xa89f, 0x0000, 0x0005, 0x00e6, 0x2071, 0x0040,
+	0x6848, 0x9005, 0x1118, 0x9085, 0x0001, 0x04b0, 0x6840, 0x9005,
+	0x0150, 0x04a1, 0x6a50, 0x9200, 0x7002, 0x6854, 0x9101, 0x7006,
+	0x9006, 0x7012, 0x7016, 0x6850, 0x7002, 0x6854, 0x7006, 0x6858,
+	0x700a, 0x685c, 0x700e, 0x6840, 0x9005, 0x1110, 0x7012, 0x7016,
+	0x6848, 0x701a, 0x701c, 0x9085, 0x0040, 0x701e, 0x2001, 0x0019,
+	0x7036, 0x702b, 0x0001, 0x2001, 0x0004, 0x200c, 0x918c, 0xfff7,
+	0x918d, 0x8000, 0x2102, 0x00d6, 0x2069, 0x18fa, 0x6807, 0x0001,
+	0x00de, 0x080c, 0x7d11, 0x9006, 0x00ee, 0x0005, 0x900e, 0x0156,
+	0x20a9, 0x0006, 0x8003, 0x2011, 0x0100, 0x2214, 0x9296, 0x0008,
+	0x1110, 0x818d, 0x0010, 0x81f5, 0x3e08, 0x1f04, 0x779a, 0x015e,
+	0x0005, 0x2079, 0x0040, 0x2071, 0x18fa, 0x7004, 0x0002, 0x77b9,
+	0x77ba, 0x77f2, 0x784d, 0x795d, 0x77b7, 0x77b7, 0x7987, 0x080c,
+	0x0dd5, 0x0005, 0x2079, 0x0040, 0x782c, 0x908c, 0x0780, 0x190c,
+	0x7df3, 0xd0a4, 0x01f8, 0x7824, 0x2048, 0x9006, 0xa802, 0xa806,
+	0xa864, 0x9084, 0x00ff, 0x908a, 0x0040, 0x0610, 0x00c0, 0x2001,
+	0x1800, 0x200c, 0x9186, 0x0003, 0x1168, 0x7004, 0x0002, 0x77e2,
+	0x77bc, 0x77e2, 0x77e0, 0x77e2, 0x77e2, 0x77e2, 0x77e2, 0x77e2,
+	0x080c, 0x784d, 0x782c, 0xd09c, 0x090c, 0x7d11, 0x0005, 0x9082,
+	0x005a, 0x1218, 0x2100, 0x003b, 0x0c10, 0x080c, 0x7883, 0x0c90,
+	0x00e3, 0x08e8, 0x0005, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x78a5, 0x7883, 0x7883, 0x7883, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x788f,
+	0x7883, 0x7a78, 0x7883, 0x7883, 0x7883, 0x78a5, 0x7883, 0x788f,
+	0x7ab9, 0x7afa, 0x7b41, 0x7b55, 0x7883, 0x7883, 0x78a5, 0x788f,
+	0x78b9, 0x7883, 0x7931, 0x7c00, 0x7c1b, 0x7883, 0x78a5, 0x7883,
+	0x78b9, 0x7883, 0x7883, 0x7927, 0x7c1b, 0x7883, 0x7883, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x78cd, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x7883,
+	0x7d97, 0x7883, 0x7d41, 0x7883, 0x7d41, 0x7883, 0x78e2, 0x7883,
+	0x7883, 0x7883, 0x7883, 0x7883, 0x7883, 0x2079, 0x0040, 0x7004,
+	0x9086, 0x0003, 0x1198, 0x782c, 0x080c, 0x7d3a, 0xd0a4, 0x0170,
+	0x7824, 0x2048, 0x9006, 0xa802, 0xa806, 0xa864, 0x9084, 0x00ff,
+	0x908a, 0x001a, 0x1210, 0x002b, 0x0c50, 0x00e9, 0x080c, 0x7d11,
+	0x0005, 0x7883, 0x788f, 0x7a64, 0x7883, 0x788f, 0x7883, 0x788f,
+	0x788f, 0x7883, 0x788f, 0x7a64, 0x788f, 0x788f, 0x788f, 0x788f,
+	0x788f, 0x7883, 0x788f, 0x7a64, 0x7883, 0x7883, 0x788f, 0x7883,
+	0x7883, 0x7883, 0x788f, 0x00e6, 0x2071, 0x18fa, 0x2009, 0x0400,
+	0x0071, 0x00ee, 0x0005, 0x2009, 0x1000, 0x0049, 0x0005, 0x2009,
+	0x2000, 0x0029, 0x0005, 0x2009, 0x0800, 0x0009, 0x0005, 0x7007,
+	0x0001, 0xa868, 0x9084, 0x00ff, 0x9105, 0xa86a, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6d17, 0x012e, 0x0005, 0xa864, 0x8007, 0x9084,
+	0x00ff, 0x0d08, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x7a06,
+	0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, 0x7a06,
+	0x0005, 0xa864, 0x8007, 0x9084, 0x00ff, 0x0968, 0x8001, 0x1120,
+	0x7007, 0x0001, 0x0804, 0x7a21, 0x7007, 0x0003, 0x7012, 0x2900,
+	0x7016, 0x701a, 0x704b, 0x7a21, 0x0005, 0xa864, 0x8007, 0x9084,
+	0x00ff, 0x0904, 0x788b, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804,
+	0x7a3d, 0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b,
+	0x7a3d, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff, 0x9086, 0x0001,
+	0x1904, 0x788b, 0x7007, 0x0001, 0x2009, 0x1834, 0x210c, 0x81ff,
+	0x11a8, 0xa868, 0x9084, 0x00ff, 0xa86a, 0xa883, 0x0000, 0x080c,
+	0x6344, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa867, 0x0139,
+	0xa87a, 0xa982, 0x080c, 0x6d17, 0x012e, 0x0ca0, 0xa994, 0x9186,
+	0x0071, 0x0d38, 0x9186, 0x0064, 0x0d20, 0x9186, 0x007c, 0x0d08,
+	0x9186, 0x0028, 0x09f0, 0x9186, 0x0038, 0x09d8, 0x9186, 0x0078,
+	0x09c0, 0x9186, 0x005f, 0x09a8, 0x9186, 0x0056, 0x0990, 0xa897,
+	0x4005, 0xa89b, 0x0001, 0x2001, 0x0030, 0x900e, 0x08a0, 0xa87c,
+	0x9084, 0x00c0, 0x9086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804,
+	0x7c32, 0x2900, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa860, 0x20e0,
+	0xa85c, 0x9080, 0x0030, 0x2098, 0x7050, 0x2040, 0xa060, 0x20e8,
+	0xa05c, 0x9080, 0x0023, 0x20a0, 0x4003, 0xa888, 0x7012, 0x9082,
+	0x0401, 0x1a04, 0x7893, 0xaab4, 0x928a, 0x0002, 0x1a04, 0x7893,
+	0x82ff, 0x1138, 0xa8b8, 0xa9bc, 0x9105, 0x0118, 0x2001, 0x79c4,
+	0x0018, 0x9280, 0x79ba, 0x2005, 0x7056, 0x7010, 0x9015, 0x0904,
+	0x79a5, 0x080c, 0x1018, 0x1118, 0x7007, 0x0004, 0x0005, 0x2900,
+	0x7022, 0x7054, 0x2060, 0xe000, 0xa866, 0x7050, 0x2040, 0xa95c,
+	0xe004, 0x9100, 0xa076, 0xa860, 0xa072, 0xe008, 0x920a, 0x1210,
+	0x900e, 0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0x9296, 0x0004,
+	0x0108, 0x9108, 0xa17a, 0x810b, 0xa17e, 0x080c, 0x10e9, 0xa06c,
+	0x908e, 0x0100, 0x0170, 0x9086, 0x0200, 0x0118, 0x7007, 0x0007,
+	0x0005, 0x7020, 0x2048, 0x080c, 0x1031, 0x7014, 0x2048, 0x0804,
+	0x7893, 0x7020, 0x2048, 0x7018, 0xa802, 0xa807, 0x0000, 0x2908,
+	0x2048, 0xa906, 0x711a, 0x0804, 0x795d, 0x7014, 0x2048, 0x7007,
+	0x0001, 0xa8b4, 0x9005, 0x1128, 0xa8b8, 0xa9bc, 0x9105, 0x0108,
+	0x00b9, 0xa864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x0904, 0x7c32,
+	0x0804, 0x7a06, 0x79bc, 0x79c0, 0x0002, 0x001d, 0x0007, 0x0004,
+	0x000a, 0x001b, 0x0005, 0x0006, 0x000a, 0x001d, 0x0005, 0x0004,
+	0x0076, 0x0066, 0xafb8, 0xaebc, 0xa804, 0x2050, 0xb0c0, 0xb0e2,
+	0xb0bc, 0xb0de, 0xb0b8, 0xb0d2, 0xb0b4, 0xb0ce, 0xb6da, 0xb7d6,
+	0xb0b0, 0xb0ca, 0xb0ac, 0xb0c6, 0xb0a8, 0xb0ba, 0xb0a4, 0xb0b6,
+	0xb6c2, 0xb7be, 0xb0a0, 0xb0b2, 0xb09c, 0xb0ae, 0xb098, 0xb0a2,
+	0xb094, 0xb09e, 0xb6aa, 0xb7a6, 0xb090, 0xb09a, 0xb08c, 0xb096,
+	0xb088, 0xb08a, 0xb084, 0xb086, 0xb692, 0xb78e, 0xb080, 0xb082,
+	0xb07c, 0xb07e, 0xb078, 0xb072, 0xb074, 0xb06e, 0xb67a, 0xb776,
+	0xb004, 0x9055, 0x1958, 0x006e, 0x007e, 0x0005, 0x2009, 0x1834,
+	0x210c, 0x81ff, 0x1178, 0x080c, 0x6141, 0x1108, 0x0005, 0x080c,
+	0x6f4a, 0x0126, 0x2091, 0x8000, 0x080c, 0xcf7c, 0x080c, 0x6d17,
+	0x012e, 0x0ca0, 0x080c, 0xd381, 0x1d70, 0x2001, 0x0028, 0x900e,
+	0x0c70, 0x2009, 0x1834, 0x210c, 0x81ff, 0x1188, 0xa888, 0x9005,
+	0x0188, 0xa883, 0x0000, 0x080c, 0x61d1, 0x1108, 0x0005, 0xa87a,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x6d17, 0x012e, 0x0cb8, 0x2001,
+	0x0028, 0x0ca8, 0x2001, 0x0000, 0x0c90, 0x2009, 0x1834, 0x210c,
+	0x81ff, 0x11d8, 0xa888, 0x9005, 0x01e0, 0xa883, 0x0000, 0xa87c,
+	0xd0f4, 0x0120, 0x080c, 0x62a6, 0x1138, 0x0005, 0x9006, 0xa87a,
+	0x080c, 0x621e, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa87a,
+	0xa982, 0x080c, 0x6d17, 0x012e, 0x0cb0, 0x2001, 0x0028, 0x900e,
+	0x0c98, 0x2001, 0x0000, 0x0c80, 0x7018, 0xa802, 0x2908, 0x2048,
+	0xa906, 0x711a, 0x7010, 0x8001, 0x7012, 0x0118, 0x7007, 0x0003,
+	0x0030, 0x7014, 0x2048, 0x7007, 0x0001, 0x7048, 0x080f, 0x0005,
+	0x00b6, 0x7007, 0x0001, 0xa974, 0xa878, 0x9084, 0x00ff, 0x9096,
+	0x0004, 0x0540, 0x20a9, 0x0001, 0x9096, 0x0001, 0x0190, 0x900e,
+	0x20a9, 0x0800, 0x9096, 0x0002, 0x0160, 0x9005, 0x11d8, 0xa974,
+	0x080c, 0x6699, 0x11b8, 0x0066, 0xae80, 0x080c, 0x67a9, 0x006e,
+	0x0088, 0x0046, 0x2011, 0x180c, 0x2224, 0xc484, 0x2412, 0x004e,
+	0x00c6, 0x080c, 0x6699, 0x1110, 0x080c, 0x68a9, 0x8108, 0x1f04,
+	0x7aa1, 0x00ce, 0xa87c, 0xd084, 0x1120, 0x080c, 0x1031, 0x00be,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17, 0x012e, 0x00be,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x080c, 0x6a08,
+	0x0580, 0x2061, 0x1a70, 0x6100, 0xd184, 0x0178, 0xa888, 0x9084,
+	0x00ff, 0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0x9005, 0x1538,
+	0x6003, 0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, 0xa890,
+	0x9005, 0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0xa888, 0x9084,
+	0x00ff, 0x0178, 0x6006, 0xa888, 0x8007, 0x9084, 0x00ff, 0x0148,
+	0x600a, 0xa888, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804,
+	0x7cfb, 0x012e, 0x0804, 0x7cf5, 0x012e, 0x0804, 0x7cef, 0x012e,
+	0x0804, 0x7cf2, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x080c,
+	0x6a08, 0x05e0, 0x2061, 0x1a70, 0x6000, 0xd084, 0x05b8, 0x6204,
+	0x6308, 0xd08c, 0x1530, 0xac78, 0x9484, 0x0003, 0x0170, 0xa988,
+	0x918c, 0x00ff, 0x8001, 0x1120, 0x2100, 0x9210, 0x0620, 0x0028,
+	0x8001, 0x1508, 0x2100, 0x9212, 0x02f0, 0x9484, 0x000c, 0x0188,
+	0xa988, 0x810f, 0x918c, 0x00ff, 0x9082, 0x0004, 0x1120, 0x2100,
+	0x9318, 0x0288, 0x0030, 0x9082, 0x0004, 0x1168, 0x2100, 0x931a,
+	0x0250, 0xa890, 0x9005, 0x0110, 0x8000, 0x6016, 0x6206, 0x630a,
+	0x012e, 0x0804, 0x7cfb, 0x012e, 0x0804, 0x7cf8, 0x012e, 0x0804,
+	0x7cf5, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0x1a70,
+	0x6300, 0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, 0x630a, 0x012e,
+	0x0804, 0x7d09, 0x012e, 0x0804, 0x7cf8, 0x00b6, 0x0126, 0x00c6,
+	0x2091, 0x8000, 0x7007, 0x0001, 0xa87c, 0xd0ac, 0x0148, 0x00c6,
+	0x2061, 0x1a70, 0x6000, 0x9084, 0xfcff, 0x6002, 0x00ce, 0x0440,
+	0xa888, 0x9005, 0x05d8, 0xa88c, 0x9065, 0x0598, 0x2001, 0x1834,
+	0x2004, 0x9005, 0x0118, 0x080c, 0xaf74, 0x0068, 0x6017, 0xf400,
+	0x605b, 0x0000, 0xa97c, 0xd1a4, 0x0110, 0xa980, 0x615a, 0x2009,
+	0x0041, 0x080c, 0xafbe, 0xa988, 0x918c, 0xff00, 0x9186, 0x2000,
+	0x1138, 0x0026, 0x900e, 0x2011, 0xfdff, 0x080c, 0x879a, 0x002e,
+	0xa87c, 0xd0c4, 0x0148, 0x2061, 0x1a70, 0x6000, 0xd08c, 0x1120,
+	0x6008, 0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, 0x00be, 0x0804,
+	0x7cfb, 0x00ce, 0x012e, 0x00be, 0x0804, 0x7cf5, 0xa984, 0x9186,
+	0x002e, 0x0d30, 0x9186, 0x002d, 0x0d18, 0x9186, 0x0045, 0x0510,
+	0x9186, 0x002a, 0x1130, 0x2001, 0x180c, 0x200c, 0xc194, 0x2102,
+	0x08b8, 0x9186, 0x0020, 0x0158, 0x9186, 0x0029, 0x1d10, 0xa974,
+	0x080c, 0x6699, 0x1968, 0xb800, 0xc0e4, 0xb802, 0x0848, 0xa88c,
+	0x9065, 0x09b8, 0x6007, 0x0024, 0x2001, 0x1985, 0x2004, 0x601a,
+	0x0804, 0x7b90, 0xa88c, 0x9065, 0x0960, 0x00e6, 0xa890, 0x9075,
+	0x2001, 0x1834, 0x2004, 0x9005, 0x0150, 0x080c, 0xaf74, 0x8eff,
+	0x0118, 0x2e60, 0x080c, 0xaf74, 0x00ee, 0x0804, 0x7b90, 0x6024,
+	0xc0dc, 0xc0d5, 0x6026, 0x2e60, 0x6007, 0x003a, 0xa8a0, 0x9005,
+	0x0130, 0x6007, 0x003b, 0xa8a4, 0x602e, 0xa8a8, 0x6016, 0x6003,
+	0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x00ee, 0x0804, 0x7b90,
+	0x2061, 0x1a70, 0x6000, 0xd084, 0x0190, 0xd08c, 0x1904, 0x7d09,
+	0x0126, 0x2091, 0x8000, 0x6204, 0x8210, 0x0220, 0x6206, 0x012e,
+	0x0804, 0x7d09, 0x012e, 0xa883, 0x0016, 0x0804, 0x7d02, 0xa883,
+	0x0007, 0x0804, 0x7d02, 0xa864, 0x8007, 0x9084, 0x00ff, 0x0130,
+	0x8001, 0x1138, 0x7007, 0x0001, 0x0069, 0x0005, 0x080c, 0x788b,
+	0x0040, 0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b,
+	0x7c32, 0x0005, 0x00b6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x903e,
+	0x2061, 0x1800, 0x61d0, 0x81ff, 0x1904, 0x7cb4, 0x6130, 0xd194,
+	0x1904, 0x7cde, 0xa878, 0x2070, 0x9e82, 0x1cd0, 0x0a04, 0x7ca8,
+	0x6068, 0x9e02, 0x1a04, 0x7ca8, 0x7120, 0x9186, 0x0006, 0x1904,
+	0x7c9a, 0x7010, 0x905d, 0x0904, 0x7cb4, 0xb800, 0xd0e4, 0x1904,
+	0x7cd8, 0x2061, 0x1a70, 0x6100, 0x9184, 0x0301, 0x9086, 0x0001,
+	0x15a0, 0x7024, 0xd0dc, 0x1904, 0x7ce1, 0xa883, 0x0000, 0xa803,
+	0x0000, 0x2908, 0x7014, 0x9005, 0x1198, 0x7116, 0xa87c, 0xd0f4,
+	0x1904, 0x7ce4, 0x080c, 0x575d, 0xd09c, 0x1118, 0xa87c, 0xc0cc,
+	0xa87e, 0x2e60, 0x080c, 0x86ba, 0x012e, 0x00ee, 0x00be, 0x0005,
+	0x2048, 0xa800, 0x9005, 0x1de0, 0xa902, 0x2148, 0xa87c, 0xd0f4,
+	0x1904, 0x7ce4, 0x012e, 0x00ee, 0x00be, 0x0005, 0x012e, 0x00ee,
+	0xa883, 0x0006, 0x00be, 0x0804, 0x7d02, 0xd184, 0x0db8, 0xd1c4,
+	0x1190, 0x00a0, 0xa974, 0x080c, 0x6699, 0x15d0, 0xb800, 0xd0e4,
+	0x15b8, 0x7120, 0x9186, 0x0007, 0x1118, 0xa883, 0x0002, 0x0490,
+	0xa883, 0x0008, 0x0478, 0xa883, 0x000e, 0x0460, 0xa883, 0x0017,
+	0x0448, 0xa883, 0x0035, 0x0430, 0x080c, 0x5761, 0xd0fc, 0x01e8,
+	0xa878, 0x2070, 0x9e82, 0x1cd0, 0x02c0, 0x6068, 0x9e02, 0x12a8,
+	0x7120, 0x9186, 0x0006, 0x1188, 0x7010, 0x905d, 0x0170, 0xb800,
+	0xd0bc, 0x0158, 0x2039, 0x0001, 0x7000, 0x9086, 0x0007, 0x1904,
+	0x7c3e, 0x7003, 0x0002, 0x0804, 0x7c3e, 0xa883, 0x0028, 0x0010,
+	0xa883, 0x0029, 0x012e, 0x00ee, 0x00be, 0x0420, 0xa883, 0x002a,
+	0x0cc8, 0xa883, 0x0045, 0x0cb0, 0x2e60, 0x2019, 0x0002, 0x601b,
+	0x0014, 0x080c, 0xe2c0, 0x012e, 0x00ee, 0x00be, 0x0005, 0x2009,
+	0x003e, 0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, 0x0028,
+	0x2009, 0x0016, 0x0010, 0x2009, 0x0001, 0xa884, 0x9084, 0xff00,
+	0x9105, 0xa886, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17, 0x012e,
+	0x0005, 0x080c, 0x1031, 0x0005, 0x00d6, 0x080c, 0x86b1, 0x00de,
+	0x0005, 0x00d6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x0040,
+	0x702c, 0xd084, 0x01d8, 0x908c, 0x0780, 0x190c, 0x7df3, 0xd09c,
+	0x11a8, 0x2071, 0x1800, 0x70c0, 0x90ea, 0x0020, 0x0278, 0x8001,
+	0x70c2, 0x702c, 0x2048, 0xa800, 0x702e, 0x9006, 0xa802, 0xa806,
+	0x2071, 0x0040, 0x2900, 0x7022, 0x702c, 0x0c28, 0x012e, 0x00ee,
+	0x00de, 0x0005, 0x0006, 0x9084, 0x0780, 0x190c, 0x7df3, 0x000e,
+	0x0005, 0xa898, 0x9084, 0x0003, 0x05a8, 0x080c, 0xaeed, 0x05d8,
+	0x2900, 0x6016, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0035, 0x1138,
+	0x6008, 0xc0fd, 0x600a, 0x2001, 0x196a, 0x2004, 0x0098, 0xa8a0,
+	0x9084, 0x00ff, 0xa99c, 0x918c, 0xff00, 0x9105, 0xa99c, 0x918c,
+	0x00ff, 0x080c, 0x287c, 0x1540, 0x00b6, 0x080c, 0x6699, 0x2b00,
+	0x00be, 0x1510, 0x6012, 0x6023, 0x0001, 0x2009, 0x0040, 0xa864,
+	0x9084, 0x00ff, 0x9086, 0x0035, 0x0110, 0x2009, 0x0041, 0x080c,
+	0xafbe, 0x0005, 0xa87b, 0x0101, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6d17, 0x012e, 0x0005, 0xa87b, 0x002c, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6d17, 0x012e, 0x0005, 0xa87b, 0x0028, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6d17, 0x012e, 0x080c, 0xaf43, 0x0005, 0x00d6,
+	0x00c6, 0x0036, 0x0026, 0x0016, 0x00b6, 0x7007, 0x0001, 0xaa74,
+	0x9282, 0x0004, 0x1a04, 0x7de4, 0xa97c, 0x9188, 0x1000, 0x2104,
+	0x905d, 0xb804, 0xd284, 0x0140, 0x05e8, 0x8007, 0x9084, 0x00ff,
+	0x9084, 0x0006, 0x1108, 0x04b0, 0x2b10, 0x080c, 0xaeed, 0x1118,
+	0x080c, 0xaf91, 0x05a8, 0x6212, 0xa874, 0x0002, 0x7dc2, 0x7dc7,
+	0x7dca, 0x7dd0, 0x2019, 0x0002, 0x080c, 0xe6ae, 0x0060, 0x080c,
+	0xe64a, 0x0048, 0x2019, 0x0002, 0xa980, 0x080c, 0xe665, 0x0018,
+	0xa980, 0x080c, 0xe64a, 0x080c, 0xaf43, 0xa887, 0x0000, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x6d17, 0x012e, 0x00be, 0x001e, 0x002e,
+	0x003e, 0x00ce, 0x00de, 0x0005, 0xa887, 0x0006, 0x0c80, 0xa887,
+	0x0002, 0x0c68, 0xa887, 0x0005, 0x0c50, 0xa887, 0x0004, 0x0c38,
+	0xa887, 0x0007, 0x0c20, 0x2091, 0x8000, 0x0e04, 0x7df5, 0x0006,
+	0x0016, 0x2001, 0x8003, 0x0006, 0x0804, 0x0dde, 0x2001, 0x1834,
+	0x2004, 0x9005, 0x0005, 0x0005, 0x00f6, 0x2079, 0x0300, 0x2001,
+	0x0200, 0x200c, 0xc1e5, 0xc1dc, 0x2102, 0x2009, 0x0218, 0x210c,
+	0xd1ec, 0x1120, 0x080c, 0x158c, 0x00fe, 0x0005, 0x2001, 0x020d,
+	0x2003, 0x0020, 0x781f, 0x0300, 0x00fe, 0x0005, 0x781c, 0xd08c,
+	0x0904, 0x7e75, 0x68c0, 0x90aa, 0x0005, 0x0a04, 0x84b9, 0x7d44,
+	0x7c40, 0x9584, 0x00f6, 0x1510, 0x9484, 0x7000, 0x0140, 0x908a,
+	0x2000, 0x1260, 0x9584, 0x0700, 0x8007, 0x0804, 0x7e7c, 0x7000,
+	0x9084, 0xff00, 0x9086, 0x8100, 0x0da8, 0x00b0, 0x9484, 0x0fff,
+	0x1130, 0x7000, 0x9084, 0xff00, 0x9086, 0x8100, 0x11c0, 0x080c,
+	0xeb51, 0x080c, 0x839e, 0x7817, 0x0140, 0x00a8, 0x9584, 0x0076,
+	0x1118, 0x080c, 0x83fc, 0x19c0, 0xd5a4, 0x0148, 0x0046, 0x0056,
+	0x080c, 0x7ed7, 0x080c, 0x2375, 0x005e, 0x004e, 0x0020, 0x080c,
+	0xeb51, 0x7817, 0x0140, 0x080c, 0x743e, 0x0168, 0x2001, 0x0111,
+	0x2004, 0xd08c, 0x0140, 0x6893, 0x0000, 0x2001, 0x0110, 0x2003,
+	0x0008, 0x2003, 0x0000, 0x080c, 0x7eb8, 0x2001, 0x19ef, 0x2004,
+	0x9005, 0x090c, 0x9763, 0x0005, 0x0002, 0x7e8e, 0x81a6, 0x7e85,
+	0x7e85, 0x7e85, 0x7e85, 0x7e85, 0x7e85, 0x7817, 0x0140, 0x2001,
+	0x19ef, 0x2004, 0x9005, 0x090c, 0x9763, 0x0005, 0x7000, 0x908c,
+	0xff00, 0x9194, 0xf000, 0x810f, 0x9484, 0x0fff, 0x6892, 0x9286,
+	0x2000, 0x1150, 0x6800, 0x9086, 0x0001, 0x1118, 0x080c, 0x57c3,
+	0x0070, 0x080c, 0x7ef7, 0x0058, 0x9286, 0x3000, 0x1118, 0x080c,
+	0x80de, 0x0028, 0x9286, 0x8000, 0x1110, 0x080c, 0x82c5, 0x7817,
+	0x0140, 0x2001, 0x19ef, 0x2004, 0x9005, 0x090c, 0x9763, 0x0005,
+	0x2001, 0x1810, 0x2004, 0xd08c, 0x0178, 0x2001, 0x1800, 0x2004,
+	0x9086, 0x0003, 0x1148, 0x0026, 0x0036, 0x2011, 0x8048, 0x2518,
+	0x080c, 0x4b7f, 0x003e, 0x002e, 0x0005, 0x0036, 0x0046, 0x0056,
+	0x00f6, 0x2079, 0x0200, 0x2019, 0xfffe, 0x7c30, 0x0050, 0x0036,
+	0x0046, 0x0056, 0x00f6, 0x2079, 0x0200, 0x7d44, 0x7c40, 0x2019,
+	0xffff, 0x2001, 0x1810, 0x2004, 0xd08c, 0x0160, 0x2001, 0x1800,
+	0x2004, 0x9086, 0x0003, 0x1130, 0x0026, 0x2011, 0x8048, 0x080c,
+	0x4b7f, 0x002e, 0x00fe, 0x005e, 0x004e, 0x003e, 0x0005, 0x00b6,
+	0x00c6, 0x7010, 0x9084, 0xff00, 0x8007, 0x9096, 0x0001, 0x0120,
+	0x9096, 0x0023, 0x1904, 0x80af, 0x9186, 0x0023, 0x15c0, 0x080c,
+	0x8363, 0x0904, 0x80af, 0x6120, 0x9186, 0x0001, 0x0150, 0x9186,
+	0x0004, 0x0138, 0x9186, 0x0008, 0x0120, 0x9186, 0x000a, 0x1904,
+	0x80af, 0x7124, 0x610a, 0x7030, 0x908e, 0x0200, 0x1130, 0x2009,
+	0x0015, 0x080c, 0xafbe, 0x0804, 0x80af, 0x908e, 0x0214, 0x0118,
+	0x908e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c, 0xafbe, 0x0804,
+	0x80af, 0x908e, 0x0100, 0x1904, 0x80af, 0x7034, 0x9005, 0x1904,
+	0x80af, 0x2009, 0x0016, 0x080c, 0xafbe, 0x0804, 0x80af, 0x9186,
+	0x0022, 0x1904, 0x80af, 0x7030, 0x908e, 0x0300, 0x1580, 0x68dc,
+	0xd0a4, 0x0528, 0xc0b5, 0x68de, 0x7100, 0x918c, 0x00ff, 0x697e,
+	0x7004, 0x6882, 0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006,
+	0x9084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x28c5, 0x7932, 0x7936,
+	0x001e, 0x000e, 0x00fe, 0x080c, 0x287c, 0x695e, 0x703c, 0x00e6,
+	0x2071, 0x0140, 0x7086, 0x2071, 0x1800, 0x70b6, 0x00ee, 0x7034,
+	0x9005, 0x1904, 0x80af, 0x2009, 0x0017, 0x0804, 0x805f, 0x908e,
+	0x0400, 0x1190, 0x7034, 0x9005, 0x1904, 0x80af, 0x080c, 0x743e,
+	0x0120, 0x2009, 0x001d, 0x0804, 0x805f, 0x68dc, 0xc0a5, 0x68de,
+	0x2009, 0x0030, 0x0804, 0x805f, 0x908e, 0x0500, 0x1140, 0x7034,
+	0x9005, 0x1904, 0x80af, 0x2009, 0x0018, 0x0804, 0x805f, 0x908e,
+	0x2010, 0x1120, 0x2009, 0x0019, 0x0804, 0x805f, 0x908e, 0x2110,
+	0x1120, 0x2009, 0x001a, 0x0804, 0x805f, 0x908e, 0x5200, 0x1140,
+	0x7034, 0x9005, 0x1904, 0x80af, 0x2009, 0x001b, 0x0804, 0x805f,
+	0x908e, 0x5000, 0x1140, 0x7034, 0x9005, 0x1904, 0x80af, 0x2009,
+	0x001c, 0x0804, 0x805f, 0x908e, 0x1300, 0x1120, 0x2009, 0x0034,
+	0x0804, 0x805f, 0x908e, 0x1200, 0x1140, 0x7034, 0x9005, 0x1904,
+	0x80af, 0x2009, 0x0024, 0x0804, 0x805f, 0x908c, 0xff00, 0x918e,
+	0x2400, 0x1170, 0x2009, 0x002d, 0x2001, 0x1810, 0x2004, 0xd09c,
+	0x0904, 0x805f, 0x080c, 0xda85, 0x1904, 0x80af, 0x0804, 0x805d,
+	0x908c, 0xff00, 0x918e, 0x5300, 0x1120, 0x2009, 0x002a, 0x0804,
+	0x805f, 0x908e, 0x0f00, 0x1120, 0x2009, 0x0020, 0x0804, 0x805f,
+	0x908e, 0x6104, 0x1530, 0x2029, 0x0205, 0x2011, 0x026d, 0x8208,
+	0x2204, 0x9082, 0x0004, 0x8004, 0x8004, 0x20a8, 0x2011, 0x8015,
+	0x211c, 0x8108, 0x0046, 0x2124, 0x080c, 0x4b7f, 0x004e, 0x8108,
+	0x0f04, 0x8013, 0x9186, 0x0280, 0x1d88, 0x2504, 0x8000, 0x202a,
+	0x2009, 0x0260, 0x0c58, 0x202b, 0x0000, 0x2009, 0x0023, 0x0804,
+	0x805f, 0x908e, 0x6000, 0x1120, 0x2009, 0x003f, 0x0804, 0x805f,
+	0x908e, 0x5400, 0x1138, 0x080c, 0x8469, 0x1904, 0x80af, 0x2009,
+	0x0046, 0x04a8, 0x908e, 0x5500, 0x1148, 0x080c, 0x8491, 0x1118,
+	0x2009, 0x0041, 0x0460, 0x2009, 0x0042, 0x0448, 0x908e, 0x7800,
+	0x1118, 0x2009, 0x0045, 0x0418, 0x908e, 0x1000, 0x1118, 0x2009,
+	0x004e, 0x00e8, 0x908e, 0x6300, 0x1118, 0x2009, 0x004a, 0x00b8,
+	0x908c, 0xff00, 0x918e, 0x5600, 0x1118, 0x2009, 0x004f, 0x0078,
+	0x908c, 0xff00, 0x918e, 0x5700, 0x1118, 0x2009, 0x0050, 0x0038,
+	0x2009, 0x001d, 0x6838, 0xd0d4, 0x0110, 0x2009, 0x004c, 0x0016,
+	0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x287c, 0x1904,
+	0x80b2, 0x080c, 0x6638, 0x1904, 0x80b2, 0xbe12, 0xbd16, 0x001e,
+	0x0016, 0x080c, 0x743e, 0x01c0, 0x68dc, 0xd08c, 0x1148, 0x7000,
+	0x9084, 0x00ff, 0x1188, 0x7004, 0x9084, 0xff00, 0x1168, 0x0040,
+	0x687c, 0x9606, 0x1148, 0x6880, 0x9506, 0x9084, 0xff00, 0x1120,
+	0x9584, 0x00ff, 0xb8c2, 0x0080, 0xb8c0, 0x9005, 0x1168, 0x9186,
+	0x0046, 0x1150, 0x687c, 0x9606, 0x1138, 0x6880, 0x9506, 0x9084,
+	0xff00, 0x1110, 0x001e, 0x0098, 0x080c, 0xaeed, 0x01a8, 0x2b08,
+	0x6112, 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x9186, 0x004c,
+	0x1110, 0x6023, 0x000a, 0x0016, 0x001e, 0x080c, 0xafbe, 0x00ce,
+	0x00be, 0x0005, 0x001e, 0x0cd8, 0x2001, 0x180e, 0x2004, 0xd0ec,
+	0x0120, 0x2011, 0x8049, 0x080c, 0x4b7f, 0x080c, 0xaf91, 0x0d90,
+	0x2b08, 0x6112, 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x0016,
+	0x9186, 0x0017, 0x0118, 0x9186, 0x0030, 0x1128, 0x6007, 0x0009,
+	0x6017, 0x2900, 0x0020, 0x6007, 0x0051, 0x6017, 0x0000, 0x602f,
+	0x0009, 0x6003, 0x0001, 0x080c, 0x91f9, 0x08a0, 0x080c, 0x84d8,
+	0x1158, 0x080c, 0x3342, 0x1140, 0x7010, 0x9084, 0xff00, 0x8007,
+	0x908e, 0x0008, 0x1108, 0x0009, 0x0005, 0x00b6, 0x00c6, 0x0046,
+	0x7000, 0x908c, 0xff00, 0x810f, 0x9186, 0x0033, 0x11e8, 0x080c,
+	0x8363, 0x0904, 0x813e, 0x7124, 0x610a, 0x7030, 0x908e, 0x0200,
+	0x1140, 0x7034, 0x9005, 0x15d0, 0x2009, 0x0015, 0x080c, 0xafbe,
+	0x04a8, 0x908e, 0x0100, 0x1590, 0x7034, 0x9005, 0x1578, 0x2009,
+	0x0016, 0x080c, 0xafbe, 0x0450, 0x9186, 0x0032, 0x1538, 0x7030,
+	0x908e, 0x1400, 0x1518, 0x2009, 0x0038, 0x0016, 0x2011, 0x0263,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x287c, 0x11b8, 0x080c, 0x6638,
+	0x11a0, 0xbe12, 0xbd16, 0x080c, 0xaeed, 0x0178, 0x2b08, 0x6112,
+	0x080c, 0xd102, 0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c,
+	0xafbe, 0x080c, 0x9763, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce,
+	0x00be, 0x0005, 0x00b6, 0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130,
+	0x9696, 0x00ff, 0x11b8, 0x9592, 0xfffc, 0x02a0, 0x9596, 0xfffd,
+	0x1120, 0x2009, 0x007f, 0x0804, 0x81a0, 0x9596, 0xfffe, 0x1120,
+	0x2009, 0x007e, 0x0804, 0x81a0, 0x9596, 0xfffc, 0x1118, 0x2009,
+	0x0080, 0x04f0, 0x2011, 0x0000, 0x2019, 0x1837, 0x231c, 0xd3ac,
+	0x0130, 0x9026, 0x20a9, 0x0800, 0x2071, 0x1000, 0x0030, 0x2021,
+	0x0081, 0x20a9, 0x077f, 0x2071, 0x1081, 0x2e1c, 0x93dd, 0x0000,
+	0x1140, 0x82ff, 0x11d0, 0x9496, 0x00ff, 0x01b8, 0x2410, 0xc2fd,
+	0x00a0, 0xbf10, 0x2600, 0x9706, 0xb814, 0x1120, 0x9546, 0x1110,
+	0x2408, 0x00b0, 0x9745, 0x1148, 0x94c6, 0x007e, 0x0130, 0x94c6,
+	0x007f, 0x0118, 0x94c6, 0x0080, 0x1d20, 0x8420, 0x8e70, 0x1f04,
+	0x8175, 0x82ff, 0x1118, 0x9085, 0x0001, 0x0018, 0xc2fc, 0x2208,
+	0x9006, 0x00de, 0x00ee, 0x004e, 0x00be, 0x0005, 0x2001, 0x1837,
+	0x200c, 0x9184, 0x0080, 0x0110, 0xd18c, 0x0138, 0x7000, 0x908c,
+	0xff00, 0x810f, 0x9184, 0x000f, 0x004a, 0x7817, 0x0140, 0x2001,
+	0x19ef, 0x2004, 0x9005, 0x090c, 0x9763, 0x0005, 0x81ce, 0x81ce,
+	0x81ce, 0x8375, 0x81ce, 0x81d7, 0x8202, 0x8290, 0x81ce, 0x81ce,
+	0x81ce, 0x81ce, 0x81ce, 0x81ce, 0x81ce, 0x81ce, 0x7817, 0x0140,
+	0x2001, 0x19ef, 0x2004, 0x9005, 0x090c, 0x9763, 0x0005, 0x00b6,
+	0x7110, 0xd1bc, 0x01e8, 0x7120, 0x2160, 0x9c8c, 0x0007, 0x11c0,
+	0x9c8a, 0x1cd0, 0x02a8, 0x6868, 0x9c02, 0x1290, 0x7008, 0x9084,
+	0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, 0x1150, 0x700c, 0xb914,
+	0x9106, 0x1130, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0xafbe,
+	0x7817, 0x0140, 0x2001, 0x19ef, 0x2004, 0x9005, 0x090c, 0x9763,
+	0x00be, 0x0005, 0x00b6, 0x00c6, 0x9484, 0x0fff, 0x0904, 0x8266,
+	0x7110, 0xd1bc, 0x1904, 0x8266, 0x7108, 0x700c, 0x2028, 0x918c,
+	0x00ff, 0x2130, 0x9094, 0xff00, 0x15b0, 0x81ff, 0x15a0, 0x9080,
+	0x3384, 0x200d, 0x918c, 0xff00, 0x810f, 0x2001, 0x0080, 0x9106,
+	0x0904, 0x8266, 0x080c, 0x6638, 0x1904, 0x8266, 0xbe12, 0xbd16,
+	0xb800, 0xd0ec, 0x15d8, 0xba04, 0x9294, 0xff00, 0x9286, 0x0600,
+	0x11a0, 0x080c, 0xaeed, 0x05e8, 0x2b08, 0x7028, 0x6046, 0x702c,
+	0x604a, 0x6112, 0x6023, 0x0006, 0x7120, 0x610a, 0x7130, 0x6156,
+	0x2009, 0x0044, 0x080c, 0xdce5, 0x0408, 0x080c, 0x6a0c, 0x1138,
+	0xb807, 0x0606, 0x0c30, 0x190c, 0x8142, 0x11c0, 0x0898, 0x080c,
+	0xaeed, 0x2b08, 0x0198, 0x6112, 0x6023, 0x0004, 0x7120, 0x610a,
+	0x9286, 0x0400, 0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001,
+	0x6003, 0x0001, 0x080c, 0x91f9, 0x080c, 0x9763, 0x7817, 0x0140,
+	0x2001, 0x19ef, 0x2004, 0x9005, 0x090c, 0x9763, 0x00ce, 0x00be,
+	0x0005, 0x2001, 0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049,
+	0x080c, 0x4b7f, 0x080c, 0xaf91, 0x0d48, 0x2b08, 0x6112, 0x6023,
+	0x0006, 0x7120, 0x610a, 0x7130, 0x6156, 0x6017, 0xf300, 0x6003,
+	0x0001, 0x6007, 0x0041, 0x080c, 0x91b1, 0x080c, 0x9763, 0x08b0,
+	0x00b6, 0x7110, 0xd1bc, 0x01e8, 0x7020, 0x2060, 0x9c84, 0x0007,
+	0x11c0, 0x9c82, 0x1cd0, 0x02a8, 0x6868, 0x9c02, 0x1290, 0x7008,
+	0x9084, 0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, 0x1150, 0x700c,
+	0xb914, 0x9106, 0x1130, 0x7124, 0x610a, 0x2009, 0x0045, 0x080c,
+	0xafbe, 0x7817, 0x0140, 0x2001, 0x19ef, 0x2004, 0x9005, 0x090c,
+	0x9763, 0x00be, 0x0005, 0x6120, 0x9186, 0x0002, 0x0128, 0x9186,
+	0x0005, 0x0110, 0x9085, 0x0001, 0x0005, 0x080c, 0x84d8, 0x1180,
+	0x080c, 0x3342, 0x1168, 0x7010, 0x9084, 0xff00, 0x8007, 0x9086,
+	0x0000, 0x1130, 0x9184, 0x000f, 0x908a, 0x0006, 0x1208, 0x000b,
+	0x0005, 0x82df, 0x82e0, 0x82df, 0x82df, 0x8345, 0x8354, 0x0005,
+	0x00b6, 0x700c, 0x7108, 0x080c, 0x287c, 0x1904, 0x8343, 0x080c,
+	0x6638, 0x1904, 0x8343, 0xbe12, 0xbd16, 0x7110, 0xd1bc, 0x0540,
+	0x702c, 0xd084, 0x1120, 0xb800, 0xd0bc, 0x1904, 0x8343, 0x080c,
+	0x6a0c, 0x0148, 0x9086, 0x0004, 0x0130, 0x080c, 0x6a14, 0x0118,
+	0x9086, 0x0004, 0x1588, 0x00c6, 0x080c, 0x8363, 0x00ce, 0x05d8,
+	0x080c, 0xaeed, 0x2b08, 0x05b8, 0x6112, 0x080c, 0xd102, 0x6023,
+	0x0002, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, 0xafbe, 0x0458,
+	0x080c, 0x6a0c, 0x0148, 0x9086, 0x0004, 0x0130, 0x080c, 0x6a14,
+	0x0118, 0x9086, 0x0004, 0x1180, 0x080c, 0xaeed, 0x2b08, 0x01d8,
+	0x6112, 0x080c, 0xd102, 0x6023, 0x0005, 0x7120, 0x610a, 0x2009,
+	0x0088, 0x080c, 0xafbe, 0x0078, 0x080c, 0xaeed, 0x2b08, 0x0158,
+	0x6112, 0x080c, 0xd102, 0x6023, 0x0004, 0x7120, 0x610a, 0x2009,
+	0x0001, 0x080c, 0xafbe, 0x00be, 0x0005, 0x7110, 0xd1bc, 0x0158,
+	0x00d1, 0x0148, 0x080c, 0x82bb, 0x1130, 0x7124, 0x610a, 0x2009,
+	0x0089, 0x080c, 0xafbe, 0x0005, 0x7110, 0xd1bc, 0x0158, 0x0059,
+	0x0148, 0x080c, 0x82bb, 0x1130, 0x7124, 0x610a, 0x2009, 0x008a,
+	0x080c, 0xafbe, 0x0005, 0x7020, 0x2060, 0x9c84, 0x0007, 0x1158,
+	0x9c82, 0x1cd0, 0x0240, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1218,
+	0x9085, 0x0001, 0x0005, 0x9006, 0x0ce8, 0x00b6, 0x7110, 0xd1bc,
+	0x11d8, 0x7024, 0x2060, 0x9c84, 0x0007, 0x11b0, 0x9c82, 0x1cd0,
+	0x0298, 0x6868, 0x9c02, 0x1280, 0x7008, 0x9084, 0x00ff, 0x6110,
+	0x2158, 0xb910, 0x9106, 0x1140, 0x700c, 0xb914, 0x9106, 0x1120,
+	0x2009, 0x0051, 0x080c, 0xafbe, 0x7817, 0x0140, 0x2001, 0x19ef,
+	0x2004, 0x9005, 0x090c, 0x9763, 0x00be, 0x0005, 0x2031, 0x0105,
+	0x0069, 0x0005, 0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207,
+	0x0029, 0x0005, 0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x0096,
+	0x00f6, 0x7000, 0x9084, 0xf000, 0x9086, 0xc000, 0x05d0, 0x080c,
+	0xaeed, 0x05b8, 0x0066, 0x00c6, 0x0046, 0x2011, 0x0263, 0x2204,
+	0x8211, 0x220c, 0x080c, 0x287c, 0x15a0, 0x080c, 0x6638, 0x1588,
+	0xbe12, 0xbd16, 0x2b00, 0x004e, 0x00ce, 0x6012, 0x080c, 0xd102,
+	0x080c, 0x0fff, 0x0510, 0x2900, 0x605a, 0x9006, 0xa802, 0xa866,
+	0xac6a, 0xa85c, 0x90f8, 0x001b, 0x20a9, 0x000e, 0xa860, 0x20e8,
+	0x20e1, 0x0000, 0x2fa0, 0x2e98, 0x4003, 0x006e, 0x6616, 0x6007,
+	0x003e, 0x6023, 0x0001, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c,
+	0x9763, 0x00fe, 0x009e, 0x00ce, 0x0005, 0x080c, 0xaf43, 0x006e,
+	0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x00c6, 0x7000, 0x908c, 0xff00,
+	0x9184, 0xf000, 0x810f, 0x9086, 0x2000, 0x1904, 0x8453, 0x9186,
+	0x0022, 0x15f0, 0x2001, 0x0111, 0x2004, 0x9005, 0x1904, 0x8455,
+	0x7030, 0x908e, 0x0400, 0x0904, 0x8455, 0x908e, 0x6000, 0x05e8,
+	0x908e, 0x5400, 0x05d0, 0x908e, 0x0300, 0x11d8, 0x2009, 0x1837,
+	0x210c, 0xd18c, 0x1590, 0xd1a4, 0x1580, 0x080c, 0x69ca, 0x0588,
+	0x68b0, 0x9084, 0x00ff, 0x7100, 0x918c, 0x00ff, 0x9106, 0x1518,
+	0x6880, 0x69b0, 0x918c, 0xff00, 0x9105, 0x7104, 0x9106, 0x11d8,
+	0x00e0, 0x2009, 0x0103, 0x210c, 0xd1b4, 0x11a8, 0x908e, 0x5200,
+	0x09e8, 0x908e, 0x0500, 0x09d0, 0x908e, 0x5000, 0x09b8, 0x0058,
+	0x9186, 0x0023, 0x1140, 0x080c, 0x8363, 0x0128, 0x6004, 0x9086,
+	0x0002, 0x0118, 0x0000, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ce,
+	0x0005, 0x7030, 0x908e, 0x0300, 0x0118, 0x908e, 0x5200, 0x1d98,
+	0x2001, 0x1837, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x0d68,
+	0x0c50, 0x0156, 0x0046, 0x0016, 0x0036, 0x7038, 0x2020, 0x8427,
+	0x94a4, 0x0007, 0xd484, 0x0148, 0x20a9, 0x0004, 0x2019, 0x1805,
+	0x2011, 0x027a, 0x080c, 0xbefd, 0x1178, 0xd48c, 0x0148, 0x20a9,
+	0x0004, 0x2019, 0x1801, 0x2011, 0x027e, 0x080c, 0xbefd, 0x1120,
+	0xd494, 0x0110, 0x9085, 0x0001, 0x003e, 0x001e, 0x004e, 0x015e,
+	0x0005, 0x0156, 0x0046, 0x0016, 0x0036, 0x7038, 0x2020, 0x8427,
+	0x94a4, 0x0007, 0xd484, 0x0148, 0x20a9, 0x0004, 0x2019, 0x1805,
+	0x2011, 0x0272, 0x080c, 0xbefd, 0x1178, 0xd48c, 0x0148, 0x20a9,
+	0x0004, 0x2019, 0x1801, 0x2011, 0x0276, 0x080c, 0xbefd, 0x1120,
+	0xd494, 0x0110, 0x9085, 0x0001, 0x003e, 0x001e, 0x004e, 0x015e,
+	0x0005, 0x00f6, 0x2079, 0x0200, 0x7800, 0xc0e5, 0xc0cc, 0x7802,
+	0x00fe, 0x0005, 0x00f6, 0x2079, 0x1800, 0x7834, 0xd084, 0x1130,
+	0x2079, 0x0200, 0x7800, 0x9085, 0x1200, 0x7802, 0x00fe, 0x0005,
+	0x00e6, 0x2071, 0x1800, 0x7034, 0xc084, 0x7036, 0x00ee, 0x0005,
+	0x0016, 0x2001, 0x1837, 0x200c, 0x9184, 0x0080, 0x0118, 0xd18c,
+	0x0118, 0x9006, 0x001e, 0x0005, 0x9085, 0x0001, 0x0cd8, 0x2071,
+	0x19f9, 0x7003, 0x0003, 0x700f, 0x0361, 0x9006, 0x701a, 0x7072,
+	0x7012, 0x7017, 0x1cd0, 0x7007, 0x0000, 0x7026, 0x702b, 0xa36c,
+	0x7032, 0x7037, 0xa3d4, 0x703f, 0xffff, 0x7042, 0x7047, 0x55ef,
+	0x704a, 0x705b, 0x8651, 0x080c, 0x1018, 0x090c, 0x0dd5, 0x2900,
+	0x703a, 0xa867, 0x0003, 0xa86f, 0x0100, 0xa8ab, 0xdcb0, 0x0005,
+	0x2071, 0x19f9, 0x1d04, 0x859f, 0x2091, 0x6000, 0x700c, 0x8001,
+	0x700e, 0x1530, 0x2001, 0x013c, 0x2004, 0x9005, 0x190c, 0x8696,
+	0x2001, 0x1869, 0x2004, 0xd0c4, 0x0158, 0x3a00, 0xd08c, 0x1140,
+	0x20d1, 0x0000, 0x20d1, 0x0001, 0x20d1, 0x0000, 0x080c, 0x0dd5,
+	0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, 0x8000, 0x7040,
+	0x900d, 0x0148, 0x8109, 0x7142, 0x1130, 0x7044, 0x080f, 0x0018,
+	0x0126, 0x2091, 0x8000, 0x7024, 0x900d, 0x0188, 0x7020, 0x8001,
+	0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126, 0x9186, 0x03e8,
+	0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028, 0x080f, 0x7030,
+	0x900d, 0x0180, 0x702c, 0x8001, 0x702e, 0x1160, 0x702f, 0x0009,
+	0x8109, 0x7132, 0x0128, 0x9184, 0x007f, 0x090c, 0xa50e, 0x0010,
+	0x7034, 0x080f, 0x703c, 0x9005, 0x0118, 0x0310, 0x8001, 0x703e,
+	0x704c, 0x900d, 0x0168, 0x7048, 0x8001, 0x704a, 0x1148, 0x704b,
+	0x0009, 0x8109, 0x714e, 0x1120, 0x7150, 0x714e, 0x7058, 0x080f,
+	0x7018, 0x900d, 0x01d8, 0x0016, 0x7070, 0x900d, 0x0158, 0x706c,
+	0x8001, 0x706e, 0x1138, 0x706f, 0x0009, 0x8109, 0x7172, 0x1110,
+	0x7074, 0x080f, 0x001e, 0x7008, 0x8001, 0x700a, 0x1138, 0x700b,
+	0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, 0x012e, 0x7004,
+	0x0002, 0x85c7, 0x85c8, 0x85e4, 0x00e6, 0x2071, 0x19f9, 0x7018,
+	0x9005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee, 0x0005,
+	0x00e6, 0x0006, 0x2071, 0x19f9, 0x701c, 0x9206, 0x1120, 0x701a,
+	0x701e, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005, 0x00e6, 0x2071,
+	0x19f9, 0xb888, 0x9102, 0x0208, 0xb98a, 0x00ee, 0x0005, 0x0005,
+	0x00b6, 0x7110, 0x080c, 0x6699, 0x1168, 0xb888, 0x8001, 0x0250,
+	0xb88a, 0x1140, 0x0126, 0x2091, 0x8000, 0x0016, 0x080c, 0x9763,
+	0x001e, 0x012e, 0x8108, 0x9182, 0x0800, 0x0218, 0x900e, 0x7007,
+	0x0002, 0x7112, 0x00be, 0x0005, 0x7014, 0x2060, 0x0126, 0x2091,
+	0x8000, 0x6040, 0x9005, 0x0128, 0x8001, 0x6042, 0x1110, 0x080c,
+	0xcf93, 0x6018, 0x9005, 0x0558, 0x8001, 0x601a, 0x1540, 0x6120,
+	0x9186, 0x0003, 0x0148, 0x9186, 0x0006, 0x0130, 0x9186, 0x0009,
+	0x11e0, 0x611c, 0xd1c4, 0x1100, 0x080c, 0xcc86, 0x01b0, 0x6014,
+	0x2048, 0xa884, 0x908a, 0x199a, 0x0280, 0x9082, 0x1999, 0xa886,
+	0x908a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, 0x800b, 0x810b,
+	0x9108, 0x611a, 0xa87c, 0xd0e4, 0x0110, 0x080c, 0xc972, 0x012e,
+	0x9c88, 0x0018, 0x7116, 0x2001, 0x181a, 0x2004, 0x9102, 0x0220,
+	0x7017, 0x1cd0, 0x7007, 0x0000, 0x0005, 0x00e6, 0x2071, 0x19f9,
+	0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005, 0x2001, 0x1a02,
+	0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0x19f9, 0x7132, 0x702f,
+	0x0009, 0x00ee, 0x0005, 0x2011, 0x1a05, 0x2013, 0x0000, 0x0005,
+	0x00e6, 0x2071, 0x19f9, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee,
+	0x0005, 0x0086, 0x0026, 0x7054, 0x8000, 0x7056, 0x2001, 0x1a07,
+	0x2044, 0xa06c, 0x9086, 0x0000, 0x0150, 0x7068, 0xa09a, 0x7064,
+	0xa096, 0x7060, 0xa092, 0x705c, 0xa08e, 0x080c, 0x10e9, 0x002e,
+	0x008e, 0x0005, 0x0006, 0x0016, 0x0096, 0x00a6, 0x00b6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x0156, 0x080c, 0x8510, 0x015e, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x001e, 0x000e,
+	0x0005, 0x00e6, 0x2071, 0x19f9, 0x7172, 0x7276, 0x706f, 0x0009,
+	0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x19f9, 0x7074, 0x9206,
+	0x1110, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005, 0x0016, 0x00c6,
+	0x2009, 0xfff4, 0x210d, 0x2061, 0x0100, 0x60f0, 0x9100, 0x60f3,
+	0x0000, 0x2009, 0xfff4, 0x200f, 0x1220, 0x8108, 0x2105, 0x8000,
+	0x200f, 0x00ce, 0x001e, 0x0005, 0x00c6, 0x2061, 0x1a70, 0x00ce,
+	0x0005, 0x9184, 0x000f, 0x8003, 0x8003, 0x8003, 0x9080, 0x1a70,
+	0x2060, 0x0005, 0xa884, 0x908a, 0x199a, 0x1638, 0x9005, 0x1150,
+	0x00c6, 0x2061, 0x1a70, 0x6014, 0x00ce, 0x9005, 0x1130, 0x2001,
+	0x001e, 0x0018, 0x908e, 0xffff, 0x01b0, 0x8003, 0x800b, 0x810b,
+	0x9108, 0x611a, 0xa87c, 0x908c, 0x00c0, 0x918e, 0x00c0, 0x0904,
+	0x8744, 0xd0b4, 0x1168, 0xd0bc, 0x1904, 0x871d, 0x2009, 0x0006,
+	0x080c, 0x8771, 0x0005, 0x900e, 0x0c60, 0x2001, 0x1999, 0x08b0,
+	0xd0fc, 0x0160, 0x908c, 0x0003, 0x0120, 0x918e, 0x0003, 0x1904,
+	0x876b, 0x908c, 0x2020, 0x918e, 0x2020, 0x01a8, 0x6024, 0xd0d4,
+	0x11e8, 0x2009, 0x1869, 0x2104, 0xd084, 0x1138, 0x87ff, 0x1120,
+	0x2009, 0x0043, 0x0804, 0xafbe, 0x0005, 0x87ff, 0x1de8, 0x2009,
+	0x0042, 0x0804, 0xafbe, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be,
+	0xd1ac, 0x0d20, 0x6024, 0xc0cd, 0x6026, 0x0c00, 0xc0d4, 0x6026,
+	0xa890, 0x602e, 0xa88c, 0x6032, 0x08e0, 0xd0fc, 0x0160, 0x908c,
+	0x0003, 0x0120, 0x918e, 0x0003, 0x1904, 0x876b, 0x908c, 0x2020,
+	0x918e, 0x2020, 0x0170, 0x0076, 0x00f6, 0x2c78, 0x080c, 0x1754,
+	0x00fe, 0x007e, 0x87ff, 0x1120, 0x2009, 0x0042, 0x080c, 0xafbe,
+	0x0005, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d58,
+	0x6124, 0xc1cd, 0x6126, 0x0c38, 0xd0fc, 0x0188, 0x908c, 0x2020,
+	0x918e, 0x2020, 0x01a8, 0x9084, 0x0003, 0x908e, 0x0002, 0x0148,
+	0x87ff, 0x1120, 0x2009, 0x0041, 0x080c, 0xafbe, 0x0005, 0x00b9,
+	0x0ce8, 0x87ff, 0x1dd8, 0x2009, 0x0043, 0x080c, 0xafbe, 0x0cb0,
+	0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d20, 0x6124,
+	0xc1cd, 0x6126, 0x0c00, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009,
+	0x0001, 0x0096, 0x080c, 0xcc86, 0x0518, 0x6014, 0x2048, 0xa982,
+	0xa800, 0x6016, 0x9186, 0x0001, 0x1188, 0xa97c, 0x918c, 0x8100,
+	0x918e, 0x8100, 0x1158, 0x00c6, 0x2061, 0x1a70, 0x6200, 0xd28c,
+	0x1120, 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x6b52,
+	0x6014, 0x904d, 0x0076, 0x2039, 0x0000, 0x190c, 0x86ba, 0x007e,
+	0x009e, 0x0005, 0x0156, 0x00c6, 0x2061, 0x1a70, 0x6000, 0x81ff,
+	0x0110, 0x9205, 0x0008, 0x9204, 0x6002, 0x00ce, 0x015e, 0x0005,
+	0x6800, 0xd08c, 0x1138, 0x6808, 0x9005, 0x0120, 0x8001, 0x680a,
+	0x9085, 0x0001, 0x0005, 0x2071, 0x1923, 0x7003, 0x0006, 0x7007,
+	0x0000, 0x700f, 0x0000, 0x7013, 0x0001, 0x080c, 0x1018, 0x090c,
+	0x0dd5, 0xa867, 0x0006, 0xa86b, 0x0001, 0xa8ab, 0xdcb0, 0xa89f,
+	0x0000, 0x2900, 0x702e, 0x7033, 0x0000, 0x0005, 0x0096, 0x00e6,
+	0x2071, 0x1923, 0x702c, 0x2048, 0x6a2c, 0x721e, 0x6b30, 0x7322,
+	0x6834, 0x7026, 0xa896, 0x6838, 0x702a, 0xa89a, 0x6824, 0x7016,
+	0x683c, 0x701a, 0x2009, 0x0028, 0x200a, 0x9005, 0x0148, 0x900e,
+	0x9188, 0x000c, 0x8001, 0x1de0, 0x2100, 0x9210, 0x1208, 0x8318,
+	0xaa8e, 0xab92, 0x7010, 0xd084, 0x0168, 0xc084, 0x7007, 0x0001,
+	0x700f, 0x0000, 0x0006, 0x2009, 0x1aca, 0x2104, 0x9082, 0x0007,
+	0x200a, 0x000e, 0xc095, 0x7012, 0x2008, 0x2001, 0x003b, 0x080c,
+	0x15fd, 0x9006, 0x2071, 0x193c, 0x7002, 0x7006, 0x702a, 0x00ee,
+	0x009e, 0x0005, 0x2009, 0x1aca, 0x2104, 0x9080, 0x0007, 0x200a,
+	0x0005, 0x00e6, 0x0126, 0x0156, 0x2091, 0x8000, 0x2071, 0x1800,
+	0x7154, 0x2001, 0x0008, 0x910a, 0x0638, 0x2001, 0x187d, 0x20ac,
+	0x9006, 0x9080, 0x0008, 0x1f04, 0x8829, 0x71c0, 0x9102, 0x02e0,
+	0x2071, 0x1877, 0x20a9, 0x0007, 0x00c6, 0x080c, 0xaeed, 0x6023,
+	0x0009, 0x6003, 0x0004, 0x601f, 0x0101, 0x0089, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x89a7, 0x012e, 0x1f04, 0x8835, 0x9006, 0x00ce,
+	0x015e, 0x012e, 0x00ee, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x00e6,
+	0x00b6, 0x0096, 0x0086, 0x0056, 0x0046, 0x0026, 0x7118, 0x720c,
+	0x7620, 0x7004, 0xd084, 0x1128, 0x2021, 0x0024, 0x2029, 0x0002,
+	0x0020, 0x2021, 0x002c, 0x2029, 0x000a, 0x080c, 0x0fff, 0x090c,
+	0x0dd5, 0x2900, 0x6016, 0x2058, 0xac66, 0x9006, 0xa802, 0xa806,
+	0xa86a, 0xa87a, 0xa8aa, 0xa887, 0x0005, 0xa87f, 0x0020, 0x7008,
+	0xa89a, 0x7010, 0xa89e, 0xae8a, 0xa8af, 0xffff, 0xa8b3, 0x0000,
+	0x8109, 0x0160, 0x080c, 0x0fff, 0x090c, 0x0dd5, 0xad66, 0x2b00,
+	0xa802, 0x2900, 0xb806, 0x2058, 0x8109, 0x1da0, 0x002e, 0x004e,
+	0x005e, 0x008e, 0x009e, 0x00be, 0x00ee, 0x0005, 0x2079, 0x0000,
+	0x2071, 0x1923, 0x7004, 0x004b, 0x700c, 0x0002, 0x88a1, 0x889a,
+	0x889a, 0x0005, 0x88ab, 0x8901, 0x8901, 0x8901, 0x8902, 0x8913,
+	0x8913, 0x700c, 0x0cba, 0x0126, 0x2091, 0x8000, 0x78a0, 0x79a0,
+	0x9106, 0x1904, 0x88f3, 0x7814, 0xd0bc, 0x1904, 0x88fc, 0x012e,
+	0x7018, 0x910a, 0x1128, 0x7030, 0x9005, 0x1904, 0x8945, 0x0005,
+	0x1210, 0x7114, 0x910a, 0x9192, 0x000a, 0x0210, 0x2009, 0x000a,
+	0x2001, 0x1888, 0x2014, 0x2001, 0x1935, 0x2004, 0x9100, 0x9202,
+	0x0e50, 0x080c, 0x8a9b, 0x2200, 0x9102, 0x0208, 0x2208, 0x0096,
+	0x702c, 0x2048, 0xa873, 0x0001, 0xa976, 0x080c, 0x8ba4, 0x2100,
+	0xa87e, 0xa86f, 0x0000, 0x009e, 0x0126, 0x2091, 0x8000, 0x2009,
+	0x1a17, 0x2104, 0xc085, 0x200a, 0x700f, 0x0002, 0x012e, 0x080c,
+	0x1108, 0x1de8, 0x0005, 0x78a0, 0x79a0, 0x9106, 0x0904, 0x88b3,
+	0x080c, 0x8a73, 0x012e, 0x0005, 0x7810, 0xc0c5, 0x7812, 0x0804,
+	0x88b3, 0x0005, 0x700c, 0x0002, 0x8907, 0x890a, 0x8909, 0x080c,
+	0x88a9, 0x0005, 0x8001, 0x700e, 0x0096, 0x702c, 0x2048, 0xa974,
+	0x009e, 0x0011, 0x0ca0, 0x0005, 0x0096, 0x702c, 0x2048, 0x7018,
+	0x9100, 0x7214, 0x921a, 0x1130, 0x701c, 0xa88e, 0x7020, 0xa892,
+	0x9006, 0x0068, 0x0006, 0x080c, 0x8ba4, 0x2100, 0xaa8c, 0x9210,
+	0xaa8e, 0x1220, 0xa890, 0x9081, 0x0000, 0xa892, 0x000e, 0x009e,
+	0x0126, 0x2091, 0x8000, 0x78a2, 0x701a, 0x080c, 0x8a73, 0x012e,
+	0x0005, 0x00e6, 0x2071, 0x1923, 0x700c, 0x0002, 0x8943, 0x8943,
+	0x8941, 0x700f, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x7030, 0x9005, 0x0508, 0x2078, 0x7814, 0x2048, 0xae88, 0x00b6,
+	0x2059, 0x0000, 0x080c, 0x89b0, 0x00be, 0x01b0, 0x00e6, 0x2071,
+	0x193c, 0x080c, 0x89f7, 0x00ee, 0x0178, 0x0096, 0x080c, 0x1018,
+	0x2900, 0x009e, 0x0148, 0xa8aa, 0x04b9, 0x0041, 0x2001, 0x1946,
+	0x2003, 0x0000, 0x012e, 0x08c8, 0x012e, 0x0005, 0x00d6, 0x00c6,
+	0x0086, 0x00a6, 0x2940, 0x2650, 0x2600, 0x9005, 0x0180, 0xa864,
+	0x9084, 0x000f, 0x2068, 0x9d88, 0x20ce, 0x2165, 0x0056, 0x2029,
+	0x0000, 0x080c, 0x8b29, 0x080c, 0x2086, 0x1dd8, 0x005e, 0x00ae,
+	0x2001, 0x187f, 0x2004, 0xa88a, 0x080c, 0x1754, 0x781f, 0x0101,
+	0x7813, 0x0000, 0x0126, 0x2091, 0x8000, 0x080c, 0x8a06, 0x012e,
+	0x008e, 0x00ce, 0x00de, 0x0005, 0x7030, 0x9005, 0x0138, 0x2078,
+	0x780c, 0x7032, 0x2001, 0x1946, 0x2003, 0x0001, 0x0005, 0x00e6,
+	0x2071, 0x1923, 0x7030, 0x600e, 0x2c00, 0x7032, 0x00ee, 0x0005,
+	0x00d6, 0x00c6, 0x0026, 0x9b80, 0x8c72, 0x2005, 0x906d, 0x090c,
+	0x0dd5, 0x9b80, 0x8c6a, 0x2005, 0x9065, 0x090c, 0x0dd5, 0x6114,
+	0x2600, 0x9102, 0x0248, 0x6828, 0x9102, 0x02f0, 0x9085, 0x0001,
+	0x002e, 0x00ce, 0x00de, 0x0005, 0x6804, 0xd094, 0x0148, 0x6854,
+	0xd084, 0x1178, 0xc085, 0x6856, 0x2011, 0x8026, 0x080c, 0x4b7f,
+	0x684c, 0x0096, 0x904d, 0x090c, 0x0dd5, 0xa804, 0x8000, 0xa806,
+	0x009e, 0x9006, 0x2030, 0x0c20, 0x6854, 0xd08c, 0x1d08, 0xc08d,
+	0x6856, 0x2011, 0x8025, 0x080c, 0x4b7f, 0x684c, 0x0096, 0x904d,
+	0x090c, 0x0dd5, 0xa800, 0x8000, 0xa802, 0x009e, 0x0888, 0x7000,
+	0x2019, 0x0008, 0x8319, 0x7104, 0x9102, 0x1118, 0x2300, 0x9005,
+	0x0020, 0x0210, 0x9302, 0x0008, 0x8002, 0x0005, 0x00d6, 0x7814,
+	0x9005, 0x090c, 0x0dd5, 0x781c, 0x9084, 0x0101, 0x9086, 0x0101,
+	0x190c, 0x0dd5, 0x7827, 0x0000, 0x2069, 0x193c, 0x6804, 0x9080,
+	0x193e, 0x2f08, 0x2102, 0x6904, 0x8108, 0x9182, 0x0008, 0x0208,
+	0x900e, 0x6906, 0x9180, 0x193e, 0x2003, 0x0000, 0x00de, 0x0005,
+	0x0096, 0x00c6, 0x2060, 0x6014, 0x2048, 0xa8a8, 0x0096, 0x2048,
+	0x9005, 0x190c, 0x1031, 0x009e, 0xa8ab, 0x0000, 0x080c, 0x0fb1,
+	0x080c, 0xaf43, 0x00ce, 0x009e, 0x0005, 0x6020, 0x9086, 0x0009,
+	0x1128, 0x601c, 0xd0c4, 0x0110, 0x9006, 0x0005, 0x9085, 0x0001,
+	0x0005, 0x6000, 0x9086, 0x0000, 0x0178, 0x6010, 0x9005, 0x0150,
+	0x00b6, 0x2058, 0x080c, 0x8da7, 0x00be, 0x6013, 0x0000, 0x601b,
+	0x0000, 0x0010, 0x2c00, 0x0861, 0x0005, 0x2009, 0x1927, 0x210c,
+	0xd194, 0x0005, 0x00e6, 0x2071, 0x1923, 0x7110, 0xc194, 0xd19c,
+	0x1118, 0xc185, 0x7007, 0x0000, 0x7112, 0x2001, 0x003b, 0x080c,
+	0x15fd, 0x00ee, 0x0005, 0x7814, 0xd0bc, 0x1108, 0x0005, 0x7810,
+	0xc0c5, 0x7812, 0x0cc0, 0x0096, 0x00d6, 0x9006, 0x7006, 0x700e,
+	0x701a, 0x701e, 0x7022, 0x7016, 0x702a, 0x7026, 0x702f, 0x0000,
+	0x080c, 0x8bf2, 0x0170, 0x080c, 0x8c27, 0x0158, 0x2900, 0x7002,
+	0x700a, 0x701a, 0x7013, 0x0001, 0x701f, 0x000a, 0x00de, 0x009e,
+	0x0005, 0x900e, 0x0cd8, 0x00e6, 0x0096, 0x0086, 0x00d6, 0x00c6,
+	0x2071, 0x1930, 0x721c, 0x2100, 0x9202, 0x1618, 0x080c, 0x8c27,
+	0x090c, 0x0dd5, 0x7018, 0x9005, 0x1160, 0x2900, 0x7002, 0x700a,
+	0x701a, 0x9006, 0x7006, 0x700e, 0xa806, 0xa802, 0x7012, 0x701e,
+	0x0038, 0x2040, 0xa806, 0x2900, 0xa002, 0x701a, 0xa803, 0x0000,
+	0x7010, 0x8000, 0x7012, 0x701c, 0x9080, 0x000a, 0x701e, 0x721c,
+	0x08d0, 0x721c, 0x00ce, 0x00de, 0x008e, 0x009e, 0x00ee, 0x0005,
+	0x0096, 0x0156, 0x0136, 0x0146, 0x00e6, 0x0126, 0x2091, 0x8000,
+	0x2071, 0x1930, 0x7300, 0x831f, 0x831e, 0x831e, 0x9384, 0x003f,
+	0x20e8, 0x939c, 0xffc0, 0x9398, 0x0003, 0x7104, 0x080c, 0x8ba4,
+	0x810c, 0x2100, 0x9318, 0x8003, 0x2228, 0x2021, 0x0078, 0x9402,
+	0x9532, 0x0208, 0x2028, 0x2500, 0x8004, 0x20a8, 0x23a0, 0xa001,
+	0xa001, 0x4005, 0x2508, 0x080c, 0x8bad, 0x2130, 0x7014, 0x9600,
+	0x7016, 0x2600, 0x711c, 0x9102, 0x701e, 0x7004, 0x9600, 0x2008,
+	0x9082, 0x000a, 0x1190, 0x7000, 0x2048, 0xa800, 0x9005, 0x1148,
+	0x2009, 0x0001, 0x0026, 0x080c, 0x8a9b, 0x002e, 0x7000, 0x2048,
+	0xa800, 0x7002, 0x7007, 0x0000, 0x0008, 0x7106, 0x2500, 0x9212,
+	0x1904, 0x8ada, 0x012e, 0x00ee, 0x014e, 0x013e, 0x015e, 0x009e,
+	0x0005, 0x0016, 0x0026, 0x00e6, 0x0126, 0x2091, 0x8000, 0x9580,
+	0x8c6a, 0x2005, 0x9075, 0x090c, 0x0dd5, 0x080c, 0x8b7f, 0x012e,
+	0x9580, 0x8c66, 0x2005, 0x9075, 0x090c, 0x0dd5, 0x0156, 0x0136,
+	0x01c6, 0x0146, 0x01d6, 0x831f, 0x831e, 0x831e, 0x9384, 0x003f,
+	0x20e0, 0x9384, 0xffc0, 0x9100, 0x2098, 0xa860, 0x20e8, 0xa95c,
+	0x2c05, 0x9100, 0x20a0, 0x20a9, 0x0002, 0x4003, 0x2e0c, 0x2d00,
+	0x0002, 0x8b69, 0x8b69, 0x8b6b, 0x8b69, 0x8b6b, 0x8b69, 0x8b69,
+	0x8b69, 0x8b69, 0x8b69, 0x8b71, 0x8b69, 0x8b71, 0x8b69, 0x8b69,
+	0x8b69, 0x080c, 0x0dd5, 0x4104, 0x20a9, 0x0002, 0x4002, 0x4003,
+	0x0028, 0x20a9, 0x0002, 0x4003, 0x4104, 0x4003, 0x01de, 0x014e,
+	0x01ce, 0x013e, 0x015e, 0x00ee, 0x002e, 0x001e, 0x0005, 0x0096,
+	0x7014, 0x8001, 0x7016, 0x710c, 0x2110, 0x00f1, 0x810c, 0x9188,
+	0x0003, 0x7308, 0x8210, 0x9282, 0x000a, 0x1198, 0x7008, 0x2048,
+	0xa800, 0x9005, 0x0158, 0x0006, 0x080c, 0x8c36, 0x009e, 0xa807,
+	0x0000, 0x2900, 0x700a, 0x7010, 0x8001, 0x7012, 0x700f, 0x0000,
+	0x0008, 0x720e, 0x009e, 0x0005, 0x0006, 0x810b, 0x810b, 0x2100,
+	0x810b, 0x9100, 0x2008, 0x000e, 0x0005, 0x0006, 0x0026, 0x2100,
+	0x9005, 0x0158, 0x9092, 0x000c, 0x0240, 0x900e, 0x8108, 0x9082,
+	0x000c, 0x1de0, 0x002e, 0x000e, 0x0005, 0x900e, 0x0cd8, 0x2d00,
+	0x90b8, 0x0008, 0x2031, 0x8bf0, 0x901e, 0x6808, 0x9005, 0x0108,
+	0x8318, 0x690c, 0x910a, 0x0248, 0x0140, 0x8318, 0x6810, 0x9112,
+	0x0220, 0x0118, 0x8318, 0x2208, 0x0cd0, 0x233a, 0x6804, 0xd084,
+	0x2300, 0x2021, 0x0001, 0x1150, 0x9082, 0x0003, 0x0967, 0x0a67,
+	0x8420, 0x9082, 0x0007, 0x0967, 0x0a67, 0x0cd0, 0x9082, 0x0002,
+	0x0967, 0x0a67, 0x8420, 0x9082, 0x0005, 0x0967, 0x0a67, 0x0cd0,
+	0x6c1a, 0x0005, 0x0096, 0x0046, 0x0126, 0x2091, 0x8000, 0x2b00,
+	0x9080, 0x8c6e, 0x2005, 0x9005, 0x090c, 0x0dd5, 0x2004, 0x90a0,
+	0x000a, 0x080c, 0x1018, 0x01d0, 0x2900, 0x7026, 0xa803, 0x0000,
+	0xa807, 0x0000, 0x080c, 0x1018, 0x0188, 0x7024, 0xa802, 0xa807,
+	0x0000, 0x2900, 0x7026, 0x94a2, 0x000a, 0x0110, 0x0208, 0x0c90,
+	0x9085, 0x0001, 0x012e, 0x004e, 0x009e, 0x0005, 0x7024, 0x9005,
+	0x0dc8, 0x2048, 0xac00, 0x080c, 0x1031, 0x2400, 0x0cc0, 0x0126,
+	0x2091, 0x8000, 0x7024, 0x2048, 0x9005, 0x0130, 0xa800, 0x7026,
+	0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x7024, 0xa802, 0x2900, 0x7026, 0x012e, 0x0005, 0x0096,
+	0x9e80, 0x0009, 0x2004, 0x9005, 0x0138, 0x2048, 0xa800, 0x0006,
+	0x080c, 0x1031, 0x000e, 0x0cb8, 0x009e, 0x0005, 0x0096, 0x7008,
+	0x9005, 0x0138, 0x2048, 0xa800, 0x0006, 0x080c, 0x1031, 0x000e,
+	0x0cb8, 0x9006, 0x7002, 0x700a, 0x7006, 0x700e, 0x701a, 0x701e,
+	0x7022, 0x702a, 0x7026, 0x702e, 0x009e, 0x0005, 0x1a63, 0x0000,
+	0x0000, 0x0000, 0x1930, 0x0000, 0x0000, 0x0000, 0x1888, 0x0000,
+	0x0000, 0x0000, 0x1877, 0x0000, 0x0000, 0x0000, 0x00e6, 0x00c6,
+	0x00b6, 0x00a6, 0xa8a8, 0x2040, 0x2071, 0x1877, 0x080c, 0x8d92,
+	0xa067, 0x0023, 0x6010, 0x905d, 0x0904, 0x8d67, 0xb814, 0xa06e,
+	0xb910, 0xa172, 0xb9a0, 0xa176, 0x2001, 0x0003, 0xa07e, 0xa834,
+	0xa082, 0xa07b, 0x0000, 0xa898, 0x9005, 0x0118, 0xa078, 0xc085,
+	0xa07a, 0x2858, 0x2031, 0x0018, 0xa068, 0x908a, 0x0019, 0x1a0c,
+	0x0dd5, 0x2020, 0x2050, 0x2940, 0xa864, 0x90bc, 0x00ff, 0x908c,
+	0x000f, 0x91e0, 0x20ce, 0x2c65, 0x9786, 0x0024, 0x2c05, 0x1590,
+	0x908a, 0x0036, 0x1a0c, 0x0dd5, 0x9082, 0x001b, 0x0002, 0x8cd2,
+	0x8cd2, 0x8cd4, 0x8cd2, 0x8cd2, 0x8cd2, 0x8cd6, 0x8cd2, 0x8cd2,
+	0x8cd2, 0x8cd8, 0x8cd2, 0x8cd2, 0x8cd2, 0x8cda, 0x8cd2, 0x8cd2,
+	0x8cd2, 0x8cdc, 0x8cd2, 0x8cd2, 0x8cd2, 0x8cde, 0x8cd2, 0x8cd2,
+	0x8cd2, 0x8ce0, 0x080c, 0x0dd5, 0xa180, 0x04b8, 0xa190, 0x04a8,
+	0xa1a0, 0x0498, 0xa1b0, 0x0488, 0xa1c0, 0x0478, 0xa1d0, 0x0468,
+	0xa1e0, 0x0458, 0x908a, 0x0034, 0x1a0c, 0x0dd5, 0x9082, 0x001b,
+	0x0002, 0x8d04, 0x8d02, 0x8d02, 0x8d02, 0x8d02, 0x8d02, 0x8d06,
+	0x8d02, 0x8d02, 0x8d02, 0x8d02, 0x8d02, 0x8d08, 0x8d02, 0x8d02,
+	0x8d02, 0x8d02, 0x8d02, 0x8d0a, 0x8d02, 0x8d02, 0x8d02, 0x8d02,
+	0x8d02, 0x8d0c, 0x080c, 0x0dd5, 0xa180, 0x0038, 0xa198, 0x0028,
+	0xa1b0, 0x0018, 0xa1c8, 0x0008, 0xa1e0, 0x2600, 0x0002, 0x8d28,
+	0x8d2a, 0x8d2c, 0x8d2e, 0x8d30, 0x8d32, 0x8d34, 0x8d36, 0x8d38,
+	0x8d3a, 0x8d3c, 0x8d3e, 0x8d40, 0x8d42, 0x8d44, 0x8d46, 0x8d48,
+	0x8d4a, 0x8d4c, 0x8d4e, 0x8d50, 0x8d52, 0x8d54, 0x8d56, 0x8d58,
+	0x080c, 0x0dd5, 0xb9e2, 0x0468, 0xb9de, 0x0458, 0xb9da, 0x0448,
+	0xb9d6, 0x0438, 0xb9d2, 0x0428, 0xb9ce, 0x0418, 0xb9ca, 0x0408,
+	0xb9c6, 0x00f8, 0xb9c2, 0x00e8, 0xb9be, 0x00d8, 0xb9ba, 0x00c8,
+	0xb9b6, 0x00b8, 0xb9b2, 0x00a8, 0xb9ae, 0x0098, 0xb9aa, 0x0088,
+	0xb9a6, 0x0078, 0xb9a2, 0x0068, 0xb99e, 0x0058, 0xb99a, 0x0048,
+	0xb996, 0x0038, 0xb992, 0x0028, 0xb98e, 0x0018, 0xb98a, 0x0008,
+	0xb986, 0x8631, 0x8421, 0x0130, 0x080c, 0x2086, 0x090c, 0x0dd5,
+	0x0804, 0x8cac, 0x00ae, 0x00be, 0x00ce, 0x00ee, 0x0005, 0xa86c,
+	0xa06e, 0xa870, 0xa072, 0xa077, 0x00ff, 0x9006, 0x0804, 0x8c8e,
+	0x0006, 0x0016, 0x00b6, 0x6010, 0x2058, 0xb810, 0x9005, 0x01b0,
+	0x2001, 0x1924, 0x2004, 0x9005, 0x0188, 0x2001, 0x1800, 0x2004,
+	0x9086, 0x0003, 0x1158, 0x0036, 0x0046, 0xbba0, 0x2021, 0x0004,
+	0x2011, 0x8014, 0x080c, 0x4b7f, 0x004e, 0x003e, 0x00be, 0x001e,
+	0x000e, 0x0005, 0x9016, 0x710c, 0xa834, 0x910a, 0xa936, 0x7008,
+	0x9005, 0x0120, 0x8210, 0x910a, 0x0238, 0x0130, 0x7010, 0x8210,
+	0x910a, 0x0210, 0x0108, 0x0cd8, 0xaa8a, 0xa26a, 0x0005, 0x00f6,
+	0x00d6, 0x0036, 0x2079, 0x0300, 0x781b, 0x0200, 0x7818, 0xd094,
+	0x1dd8, 0x781b, 0x0202, 0xa001, 0xa001, 0x7818, 0xd094, 0x1da0,
+	0xb8ac, 0x9005, 0x01b8, 0x2068, 0x2079, 0x0000, 0x2c08, 0x911e,
+	0x1118, 0x680c, 0xb8ae, 0x0060, 0x9106, 0x0140, 0x2d00, 0x2078,
+	0x680c, 0x9005, 0x090c, 0x0dd5, 0x2068, 0x0cb0, 0x6b0c, 0x7b0e,
+	0x600f, 0x0000, 0x2079, 0x0300, 0x781b, 0x0200, 0x003e, 0x00de,
+	0x00fe, 0x0005, 0x00e6, 0x00d6, 0x0096, 0x00c6, 0x0036, 0x0126,
+	0x2091, 0x8000, 0x0156, 0x20a9, 0x01ff, 0x2071, 0x0300, 0x701b,
+	0x0200, 0x7018, 0xd094, 0x0110, 0x1f04, 0x8de7, 0x701b, 0x0202,
+	0xa001, 0xa001, 0x7018, 0xd094, 0x1d90, 0xb8ac, 0x9005, 0x01e8,
+	0x2060, 0x600c, 0xb8ae, 0x6024, 0xc08d, 0x6026, 0x6003, 0x0004,
+	0x601b, 0x0000, 0x6013, 0x0000, 0x601f, 0x0101, 0x6014, 0x2048,
+	0xa88b, 0x0000, 0xa8a8, 0xa8ab, 0x0000, 0x904d, 0x090c, 0x0dd5,
+	0x080c, 0x1031, 0x080c, 0x89a7, 0x0c00, 0x2071, 0x0300, 0x701b,
+	0x0200, 0x015e, 0x012e, 0x003e, 0x00ce, 0x009e, 0x00de, 0x00ee,
+	0x0005, 0x00c6, 0x00b6, 0x0016, 0x0006, 0x0156, 0x080c, 0x287c,
+	0x015e, 0x11b0, 0x080c, 0x6638, 0x190c, 0x0dd5, 0x000e, 0x001e,
+	0xb912, 0xb816, 0x080c, 0xaeed, 0x0140, 0x2b00, 0x6012, 0x6023,
+	0x0001, 0x2009, 0x0001, 0x080c, 0xafbe, 0x00be, 0x00ce, 0x0005,
+	0x000e, 0x001e, 0x0cd0, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c,
+	0x0dd5, 0x0013, 0x006e, 0x0005, 0x8e5c, 0x8e5c, 0x8e5c, 0x8e5e,
+	0x8eaf, 0x8e5c, 0x8e5c, 0x8e5c, 0x8f16, 0x8e5c, 0x8f53, 0x8e5c,
+	0x8e5c, 0x8e5c, 0x8e5c, 0x8e5c, 0x080c, 0x0dd5, 0x9182, 0x0040,
+	0x0002, 0x8e71, 0x8e71, 0x8e71, 0x8e71, 0x8e71, 0x8e71, 0x8e71,
+	0x8e71, 0x8e71, 0x8e73, 0x8e88, 0x8e71, 0x8e71, 0x8e71, 0x8e71,
+	0x8e9b, 0x080c, 0x0dd5, 0x0096, 0x080c, 0x9713, 0x080c, 0x9891,
+	0x6114, 0x2148, 0xa87b, 0x0000, 0x6010, 0x00b6, 0x2058, 0xb8bb,
+	0x0500, 0x00be, 0x080c, 0x6b1d, 0x080c, 0xaf43, 0x009e, 0x0005,
+	0x080c, 0x9713, 0x00d6, 0x6114, 0x080c, 0xcc86, 0x0130, 0x0096,
+	0x6114, 0x2148, 0x080c, 0x6d17, 0x009e, 0x00de, 0x080c, 0xaf43,
+	0x080c, 0x9891, 0x0005, 0x080c, 0x9713, 0x080c, 0x321e, 0x6114,
+	0x0096, 0x2148, 0x080c, 0xcc86, 0x0120, 0xa87b, 0x0029, 0x080c,
+	0x6d17, 0x009e, 0x080c, 0xaf43, 0x080c, 0x9891, 0x0005, 0x601b,
+	0x0000, 0x9182, 0x0040, 0x0096, 0x0002, 0x8eca, 0x8eca, 0x8eca,
+	0x8eca, 0x8eca, 0x8eca, 0x8eca, 0x8eca, 0x8ecc, 0x8eca, 0x8eca,
+	0x8eca, 0x8f12, 0x8eca, 0x8eca, 0x8eca, 0x8eca, 0x8eca, 0x8eca,
+	0x8ed3, 0x8eca, 0x080c, 0x0dd5, 0x6114, 0x2148, 0xa938, 0x918e,
+	0xffff, 0x0904, 0x8f12, 0x6024, 0xd08c, 0x15c0, 0x00e6, 0x6114,
+	0x2148, 0x080c, 0x8c76, 0x0096, 0xa8a8, 0x2048, 0x080c, 0x6ab5,
+	0x009e, 0xa8ab, 0x0000, 0x6010, 0x9005, 0x0128, 0x00b6, 0x2058,
+	0x080c, 0x8da7, 0x00be, 0xae88, 0x00b6, 0x2059, 0x0000, 0x080c,
+	0x89b0, 0x00be, 0x01e0, 0x2071, 0x193c, 0x080c, 0x89f7, 0x01b8,
+	0x9086, 0x0001, 0x1128, 0x2001, 0x1946, 0x2004, 0x9005, 0x1178,
+	0x0096, 0x080c, 0x0fff, 0x2900, 0x009e, 0x0148, 0xa8aa, 0x00f6,
+	0x2c78, 0x080c, 0x896e, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x080c,
+	0x89a7, 0x0cd0, 0x080c, 0x8fc0, 0x009e, 0x0005, 0x9182, 0x0040,
+	0x0096, 0x0002, 0x8f2a, 0x8f2a, 0x8f2a, 0x8f2c, 0x8f2a, 0x8f2a,
+	0x8f2a, 0x8f51, 0x8f2a, 0x8f2a, 0x8f2a, 0x8f2a, 0x8f2a, 0x8f2a,
+	0x8f2a, 0x8f2a, 0x080c, 0x0dd5, 0x6003, 0x0003, 0x6106, 0x6014,
+	0x2048, 0xa8ac, 0xa846, 0xa8b0, 0xa84a, 0xa837, 0x0000, 0xa83b,
+	0x0000, 0xa884, 0x9092, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003,
+	0x8013, 0x8213, 0x9210, 0x621a, 0x2c10, 0x080c, 0x1beb, 0x080c,
+	0x9216, 0x0126, 0x2091, 0x8000, 0x080c, 0x9891, 0x012e, 0x009e,
+	0x0005, 0x080c, 0x0dd5, 0x080c, 0x9713, 0x080c, 0x9891, 0x6114,
+	0x2148, 0xa87b, 0x0000, 0x6010, 0x00b6, 0x2058, 0xb8bb, 0x0500,
+	0x00be, 0x080c, 0x6d17, 0x080c, 0xaf43, 0x009e, 0x0005, 0x6000,
+	0x908a, 0x0016, 0x1a0c, 0x0dd5, 0x0096, 0x0013, 0x009e, 0x0005,
+	0x8f80, 0x8f80, 0x8f80, 0x8f82, 0x8f93, 0x8f80, 0x8f80, 0x8f80,
+	0x8f80, 0x8f80, 0x8f80, 0x8f80, 0x8f80, 0x8f80, 0x8f80, 0x8f80,
+	0x080c, 0x0dd5, 0x080c, 0xa89b, 0x6114, 0x2148, 0xa87b, 0x0006,
+	0x6010, 0x00b6, 0x2058, 0xb8bb, 0x0500, 0x00be, 0x080c, 0x6d17,
+	0x080c, 0xaf43, 0x0005, 0x0461, 0x0005, 0x6000, 0x908a, 0x0016,
+	0x1a0c, 0x0dd5, 0x0096, 0x0013, 0x009e, 0x0005, 0x8fae, 0x8fae,
+	0x8fae, 0x8fb0, 0x8fc0, 0x8fae, 0x8fae, 0x8fae, 0x8fae, 0x8fae,
+	0x8fae, 0x8fae, 0x8fae, 0x8fae, 0x8fae, 0x8fae, 0x080c, 0x0dd5,
+	0x0036, 0x00e6, 0x2071, 0x19e6, 0x703c, 0x9c06, 0x1120, 0x2019,
+	0x0000, 0x080c, 0xa6ac, 0x080c, 0xa89b, 0x00ee, 0x003e, 0x0005,
+	0x6024, 0xd08c, 0x11f0, 0x00f6, 0x00e6, 0x601b, 0x0000, 0x6014,
+	0x2048, 0x6010, 0x9005, 0x0128, 0x00b6, 0x2058, 0x080c, 0x8da7,
+	0x00be, 0x2071, 0x193c, 0x080c, 0x89f7, 0x0160, 0x2001, 0x187f,
+	0x2004, 0xa88a, 0x2031, 0x0000, 0x2c78, 0x080c, 0x896e, 0x00ee,
+	0x00fe, 0x0005, 0x0096, 0xa88b, 0x0000, 0xa8a8, 0x2048, 0x080c,
+	0x1031, 0x009e, 0xa8ab, 0x0000, 0x080c, 0x89a7, 0x0c80, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x187a, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0126,
+	0x2091, 0x8000, 0x0036, 0x0046, 0x20a9, 0x0010, 0x9006, 0x8004,
+	0x2019, 0x0100, 0x231c, 0x93a6, 0x0008, 0x1118, 0x8086, 0x818e,
+	0x0020, 0x80f6, 0x3e00, 0x81f6, 0x3e08, 0x1208, 0x9200, 0x1f04,
+	0x9008, 0x93a6, 0x0008, 0x1118, 0x8086, 0x818e, 0x0020, 0x80f6,
+	0x3e00, 0x81f6, 0x3e08, 0x004e, 0x003e, 0x012e, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x0076, 0x0156, 0x20a9, 0x0010, 0x9005, 0x0510,
+	0x911a, 0x1600, 0x8213, 0x2039, 0x0100, 0x273c, 0x97be, 0x0008,
+	0x1110, 0x818d, 0x0010, 0x81f5, 0x3e08, 0x0228, 0x911a, 0x1220,
+	0x1f04, 0x9032, 0x0028, 0x911a, 0x2308, 0x8210, 0x1f04, 0x9032,
+	0x0006, 0x3200, 0x9084, 0xefff, 0x2080, 0x000e, 0x015e, 0x007e,
+	0x012e, 0x0005, 0x0006, 0x3200, 0x9085, 0x1000, 0x0ca8, 0x0126,
+	0x2091, 0x2800, 0x2079, 0x19e6, 0x012e, 0x00d6, 0x2069, 0x19e6,
+	0x6803, 0x0005, 0x0156, 0x0146, 0x01d6, 0x20e9, 0x0000, 0x2069,
+	0x0200, 0x080c, 0xabfe, 0x0401, 0x080c, 0xabe9, 0x00e9, 0x080c,
+	0xabec, 0x00d1, 0x080c, 0xabef, 0x00b9, 0x080c, 0xabf2, 0x00a1,
+	0x080c, 0xabf5, 0x0089, 0x080c, 0xabf8, 0x0071, 0x080c, 0xabfb,
+	0x0059, 0x01de, 0x014e, 0x015e, 0x2069, 0x0004, 0x2d04, 0x9085,
+	0x8001, 0x206a, 0x00de, 0x0005, 0x20a9, 0x0020, 0x20a1, 0x0240,
+	0x2001, 0x0000, 0x4004, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804,
+	0x9084, 0x0007, 0x0002, 0x90a5, 0x90c9, 0x910a, 0x90ab, 0x90c9,
+	0x90a5, 0x90a3, 0x90a3, 0x080c, 0x0dd5, 0x080c, 0x8636, 0x080c,
+	0x9763, 0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005,
+	0x2011, 0x5f16, 0x080c, 0x85b0, 0x7828, 0x9092, 0x00c8, 0x1228,
+	0x8000, 0x782a, 0x080c, 0x5f56, 0x0c88, 0x62c0, 0x080c, 0xad3a,
+	0x080c, 0x5f16, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000,
+	0x0c28, 0x080c, 0x8636, 0x6220, 0xd2a4, 0x0170, 0xd2cc, 0x0160,
+	0x782b, 0x0000, 0x7824, 0x9065, 0x090c, 0x0dd5, 0x2009, 0x0013,
+	0x080c, 0xafbe, 0x00ce, 0x0005, 0x00c6, 0x7824, 0x9065, 0x090c,
+	0x0dd5, 0x7828, 0x9092, 0xc350, 0x12c0, 0x8000, 0x782a, 0x00ce,
+	0x080c, 0x2be3, 0x0278, 0x00c6, 0x7924, 0x2160, 0x6010, 0x906d,
+	0x090c, 0x0dd5, 0x7807, 0x0000, 0x7827, 0x0000, 0x00ce, 0x080c,
+	0x9763, 0x0c00, 0x080c, 0xa332, 0x08e8, 0x2011, 0x0130, 0x2214,
+	0x080c, 0xad3a, 0x080c, 0xeb8e, 0x2009, 0x0014, 0x080c, 0xafbe,
+	0x00ce, 0x0880, 0x2001, 0x1a02, 0x2003, 0x0000, 0x62c0, 0x82ff,
+	0x1160, 0x782b, 0x0000, 0x7824, 0x9065, 0x090c, 0x0dd5, 0x2009,
+	0x0013, 0x080c, 0xb010, 0x00ce, 0x0005, 0x00b6, 0x00c6, 0x00d6,
+	0x7824, 0x9005, 0x090c, 0x0dd5, 0x7828, 0x9092, 0xc350, 0x1648,
+	0x8000, 0x782a, 0x00de, 0x00ce, 0x00be, 0x080c, 0x2be3, 0x02f0,
+	0x00b6, 0x00c6, 0x00d6, 0x781c, 0x905d, 0x090c, 0x0dd5, 0xb800,
+	0xc0dc, 0xb802, 0x7924, 0x2160, 0x080c, 0xaf43, 0xb93c, 0x81ff,
+	0x090c, 0x0dd5, 0x8109, 0xb93e, 0x7807, 0x0000, 0x7827, 0x0000,
+	0x00de, 0x00ce, 0x00be, 0x080c, 0x9763, 0x0868, 0x080c, 0xa332,
+	0x0850, 0x2011, 0x0130, 0x2214, 0x080c, 0xad3a, 0x080c, 0xeb8e,
+	0x7824, 0x9065, 0x2009, 0x0014, 0x080c, 0xafbe, 0x00de, 0x00ce,
+	0x00be, 0x0804, 0x911b, 0x00c6, 0x2001, 0x009b, 0x2004, 0xd0fc,
+	0x190c, 0x1ef2, 0x6024, 0x6027, 0x0002, 0xd0f4, 0x15b8, 0x62c8,
+	0x60c4, 0x9205, 0x1170, 0x783c, 0x9065, 0x0130, 0x2009, 0x0049,
+	0x080c, 0xafbe, 0x00ce, 0x0005, 0x2011, 0x1a05, 0x2013, 0x0000,
+	0x0cc8, 0x793c, 0x81ff, 0x0dc0, 0x7944, 0x9192, 0x7530, 0x1628,
+	0x8108, 0x7946, 0x793c, 0x9188, 0x0008, 0x210c, 0x918e, 0x0006,
+	0x1138, 0x6014, 0x9084, 0x1984, 0x9085, 0x0012, 0x6016, 0x0c10,
+	0x793c, 0x9188, 0x0008, 0x210c, 0x918e, 0x0009, 0x0d90, 0x6014,
+	0x9084, 0x1984, 0x9085, 0x0016, 0x6016, 0x08a0, 0x793c, 0x2160,
+	0x2009, 0x004a, 0x080c, 0xafbe, 0x0868, 0x7848, 0xc085, 0x784a,
+	0x0848, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19e6, 0x6020, 0x8000, 0x6022, 0x6010,
+	0x9005, 0x0148, 0x9080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069,
+	0x19e6, 0xb800, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0x9086,
+	0x0001, 0x1110, 0x2b00, 0x681e, 0x00de, 0x0804, 0x9763, 0x00de,
+	0x0005, 0xc0d5, 0xb802, 0x6818, 0x9005, 0x0168, 0xb856, 0xb85b,
+	0x0000, 0x0086, 0x0006, 0x2b00, 0x681a, 0x008e, 0xa05a, 0x008e,
+	0x2069, 0x19e6, 0x0c08, 0xb856, 0xb85a, 0x2b00, 0x681a, 0x681e,
+	0x08d8, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19e6, 0x6020, 0x8000, 0x6022, 0x6008,
+	0x9005, 0x0148, 0x9080, 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19e6, 0x6034, 0x9005, 0x0130, 0x9080,
+	0x0003, 0x2102, 0x6136, 0x00ce, 0x0005, 0x613a, 0x6136, 0x00ce,
+	0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x00b6, 0x0096, 0x0076,
+	0x0066, 0x0056, 0x0036, 0x0026, 0x0016, 0x0006, 0x0126, 0x902e,
+	0x2071, 0x19e6, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff,
+	0x0904, 0x92a5, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1904, 0x92a0,
+	0x87ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x92a0, 0x703c, 0x9c06,
+	0x1178, 0x0036, 0x2019, 0x0001, 0x080c, 0xa6ac, 0x7033, 0x0000,
+	0x9006, 0x703e, 0x7042, 0x7046, 0x704a, 0x003e, 0x2029, 0x0001,
+	0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140,
+	0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0x080c, 0xcc86, 0x01f0, 0x6014, 0x2048, 0x6020,
+	0x9086, 0x0003, 0x15b8, 0x6004, 0x9086, 0x0040, 0x090c, 0xa88b,
+	0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0076,
+	0x080c, 0xcf7c, 0x080c, 0xea94, 0x080c, 0x6d17, 0x007e, 0x003e,
+	0x001e, 0x080c, 0xce71, 0x080c, 0xaf74, 0x00ce, 0x0804, 0x923f,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0x923f, 0x85ff, 0x0120, 0x0036,
+	0x080c, 0x9891, 0x003e, 0x012e, 0x000e, 0x001e, 0x002e, 0x003e,
+	0x005e, 0x006e, 0x007e, 0x009e, 0x00be, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036,
+	0x0076, 0x080c, 0xea94, 0x080c, 0xe6dd, 0x007e, 0x003e, 0x001e,
+	0x0890, 0x6020, 0x9086, 0x0009, 0x1168, 0xa87b, 0x0006, 0x0016,
+	0x0036, 0x0076, 0x080c, 0x6d17, 0x080c, 0xaf43, 0x007e, 0x003e,
+	0x001e, 0x0818, 0x6020, 0x9086, 0x000a, 0x0904, 0x928a, 0x0804,
+	0x9283, 0x0006, 0x0066, 0x0096, 0x00c6, 0x00d6, 0x00f6, 0x9036,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x19e6, 0x7838, 0x9065, 0x0904,
+	0x9336, 0x600c, 0x0006, 0x600f, 0x0000, 0x783c, 0x9c06, 0x1168,
+	0x0036, 0x2019, 0x0001, 0x080c, 0xa6ac, 0x7833, 0x0000, 0x901e,
+	0x7b3e, 0x7b42, 0x7b46, 0x7b4a, 0x003e, 0x080c, 0xcc86, 0x0548,
+	0x6014, 0x2048, 0x6020, 0x9086, 0x0003, 0x1590, 0x3e08, 0x918e,
+	0x0002, 0x1188, 0x6010, 0x9005, 0x0170, 0x00b6, 0x2058, 0xb800,
+	0x00be, 0xd0bc, 0x0140, 0x6040, 0x9005, 0x11a8, 0x2001, 0x1987,
+	0x2004, 0x6042, 0x0080, 0x6004, 0x9086, 0x0040, 0x090c, 0xa88b,
+	0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6d0b, 0x080c,
+	0xce71, 0x080c, 0xaf74, 0x000e, 0x0804, 0x92ee, 0x7e3a, 0x7e36,
+	0x012e, 0x00fe, 0x00de, 0x00ce, 0x009e, 0x006e, 0x000e, 0x0005,
+	0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xe6dd, 0x0c50, 0x6020,
+	0x9086, 0x0009, 0x1130, 0xab7a, 0x080c, 0x6d17, 0x080c, 0xaf43,
+	0x0c10, 0x6020, 0x9086, 0x000a, 0x09a8, 0x0868, 0x0016, 0x0026,
+	0x0086, 0x9046, 0x0099, 0x080c, 0x9441, 0x008e, 0x002e, 0x001e,
+	0x0005, 0x00f6, 0x0126, 0x2079, 0x19e6, 0x2091, 0x8000, 0x080c,
+	0x94d8, 0x080c, 0x9568, 0x012e, 0x00fe, 0x0005, 0x00b6, 0x0096,
+	0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x19e6, 0x7614, 0x2660, 0x2678, 0x8cff,
+	0x0904, 0x9406, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1904, 0x9401,
+	0x88ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x9401, 0x7024, 0x9c06,
+	0x1568, 0x2069, 0x0100, 0x6820, 0xd0a4, 0x0110, 0xd0cc, 0x1508,
+	0x080c, 0x8636, 0x080c, 0xa356, 0x68c3, 0x0000, 0x080c, 0xa88b,
+	0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000,
+	0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006, 0x080c, 0x2d4e,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x0028, 0x6003, 0x0009, 0x630a, 0x0804, 0x9401, 0x7014, 0x9c36,
+	0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, 0x1140, 0x2c00, 0x9f36,
+	0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x6014, 0x2048, 0x080c, 0xcc86, 0x01e8, 0x6020, 0x9086, 0x0003,
+	0x1580, 0x080c, 0xce8e, 0x1118, 0x080c, 0xb905, 0x0098, 0xa867,
+	0x0103, 0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0086, 0x080c,
+	0xcf7c, 0x080c, 0xea94, 0x080c, 0x6d17, 0x008e, 0x003e, 0x001e,
+	0x080c, 0xce71, 0x080c, 0xaf74, 0x080c, 0xa761, 0x00ce, 0x0804,
+	0x937f, 0x2c78, 0x600c, 0x2060, 0x0804, 0x937f, 0x012e, 0x000e,
+	0x001e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x009e, 0x00be,
+	0x0005, 0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036, 0x0086,
+	0x080c, 0xea94, 0x080c, 0xe6dd, 0x008e, 0x003e, 0x001e, 0x08d0,
+	0x080c, 0xb905, 0x6020, 0x9086, 0x0002, 0x1160, 0x6004, 0x0006,
+	0x9086, 0x0085, 0x000e, 0x0904, 0x93e7, 0x9086, 0x008b, 0x0904,
+	0x93e7, 0x0840, 0x6020, 0x9086, 0x0005, 0x1920, 0x6004, 0x0006,
+	0x9086, 0x0085, 0x000e, 0x09c8, 0x9086, 0x008b, 0x09b0, 0x0804,
+	0x93fa, 0x00b6, 0x00a6, 0x0096, 0x00c6, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x9280, 0x1000, 0x2004, 0x905d, 0x0904, 0x94d1, 0x00f6,
+	0x00e6, 0x00d6, 0x0066, 0x2071, 0x19e6, 0xbe54, 0x7018, 0x9b06,
+	0x1108, 0x761a, 0x701c, 0x9b06, 0x1130, 0x86ff, 0x1118, 0x7018,
+	0x701e, 0x0008, 0x761e, 0xb858, 0x904d, 0x0108, 0xae56, 0x96d5,
+	0x0000, 0x0110, 0x2900, 0xb05a, 0xb857, 0x0000, 0xb85b, 0x0000,
+	0xb800, 0xc0d4, 0xc0dc, 0xb802, 0x080c, 0x65cb, 0x0904, 0x94cd,
+	0x7624, 0x86ff, 0x0904, 0x94bc, 0x9680, 0x0005, 0x2004, 0x9906,
+	0x15d8, 0x00d6, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0560, 0x080c,
+	0x8636, 0x080c, 0xa356, 0x68c3, 0x0000, 0x080c, 0xa88b, 0x7027,
+	0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138,
+	0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006, 0x080c, 0x2d4e, 0x2069,
+	0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de,
+	0x00c6, 0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x080c,
+	0xaf74, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003, 0x0009,
+	0x630a, 0x00ce, 0x0804, 0x9474, 0x89ff, 0x0158, 0xa867, 0x0103,
+	0xab7a, 0xa877, 0x0000, 0x080c, 0xcf7c, 0x080c, 0xea94, 0x080c,
+	0x6d17, 0x080c, 0xa761, 0x0804, 0x9474, 0x006e, 0x00de, 0x00ee,
+	0x00fe, 0x012e, 0x000e, 0x00ce, 0x009e, 0x00ae, 0x00be, 0x0005,
+	0x0096, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x9036, 0x7814, 0x9065,
+	0x0904, 0x953b, 0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0x9c06,
+	0x1580, 0x2069, 0x0100, 0x6820, 0xd0a4, 0x0110, 0xd0cc, 0x1508,
+	0x080c, 0x8636, 0x080c, 0xa356, 0x68c3, 0x0000, 0x080c, 0xa88b,
+	0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000,
+	0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006, 0x080c, 0x2d4e,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x0040, 0x080c, 0x69a4, 0x1520, 0x6003, 0x0009, 0x630a, 0x2c30,
+	0x00f8, 0x6014, 0x2048, 0x080c, 0xcc84, 0x01b0, 0x6020, 0x9086,
+	0x0003, 0x1508, 0x080c, 0xce8e, 0x1118, 0x080c, 0xb905, 0x0060,
+	0x080c, 0x69a4, 0x1168, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000,
+	0x080c, 0x6d17, 0x080c, 0xce71, 0x080c, 0xaf74, 0x080c, 0xa761,
+	0x000e, 0x0804, 0x94df, 0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e,
+	0x000e, 0x009e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, 0x080c,
+	0xe6dd, 0x0c50, 0x080c, 0xb905, 0x6020, 0x9086, 0x0002, 0x1150,
+	0x6004, 0x0006, 0x9086, 0x0085, 0x000e, 0x0990, 0x9086, 0x008b,
+	0x0978, 0x08d0, 0x6020, 0x9086, 0x0005, 0x19b0, 0x6004, 0x0006,
+	0x9086, 0x0085, 0x000e, 0x0d18, 0x9086, 0x008b, 0x0d00, 0x0860,
+	0x0006, 0x0066, 0x0096, 0x00b6, 0x00c6, 0x00d6, 0x7818, 0x905d,
+	0x0904, 0x95e8, 0xb854, 0x0006, 0x9006, 0xb856, 0xb85a, 0xb800,
+	0xc0d4, 0xc0dc, 0xb802, 0x080c, 0x65cb, 0x0904, 0x95e5, 0x7e24,
+	0x86ff, 0x0904, 0x95d8, 0x9680, 0x0005, 0x2004, 0x9906, 0x1904,
+	0x95d8, 0x00d6, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904, 0x95cf,
+	0x080c, 0x8636, 0x080c, 0xa356, 0x68c3, 0x0000, 0x080c, 0xa88b,
+	0x7827, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000,
+	0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006, 0x080c, 0x2d4e,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x00de, 0x00c6, 0x3e08, 0x918e, 0x0002, 0x1168, 0xb800, 0xd0bc,
+	0x0150, 0x9680, 0x0010, 0x200c, 0x81ff, 0x1518, 0x2009, 0x1987,
+	0x210c, 0x2102, 0x00f0, 0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e,
+	0x2660, 0x600f, 0x0000, 0x080c, 0xaf74, 0x00ce, 0x0048, 0x00de,
+	0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x957b,
+	0x89ff, 0x0138, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0x6d17, 0x080c, 0xa761, 0x0804, 0x957b, 0x000e, 0x0804, 0x956f,
+	0x781e, 0x781a, 0x00de, 0x00ce, 0x00be, 0x009e, 0x006e, 0x000e,
+	0x0005, 0x00e6, 0x00d6, 0x0096, 0x0066, 0xb800, 0xd0dc, 0x01a0,
+	0xb84c, 0x904d, 0x0188, 0xa878, 0x9606, 0x1170, 0x2071, 0x19e6,
+	0x7024, 0x9035, 0x0148, 0x9080, 0x0005, 0x2004, 0x9906, 0x1120,
+	0xb800, 0xc0dc, 0xb802, 0x0029, 0x006e, 0x009e, 0x00de, 0x00ee,
+	0x0005, 0x00f6, 0x2079, 0x0100, 0x78c0, 0x9005, 0x1138, 0x00c6,
+	0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x04b8, 0x080c, 0xa356,
+	0x78c3, 0x0000, 0x080c, 0xa88b, 0x7027, 0x0000, 0x0036, 0x2079,
+	0x0140, 0x7b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2d4e, 0x9006, 0x080c, 0x2d4e, 0x2079, 0x0100, 0x7824, 0xd084,
+	0x0110, 0x7827, 0x0001, 0x080c, 0xa88b, 0x003e, 0x080c, 0x65cb,
+	0x00c6, 0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x080c,
+	0xaf43, 0x00ce, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0xcf7c, 0x080c, 0x6d17, 0x080c, 0xa761, 0x00fe, 0x0005, 0x00b6,
+	0x00e6, 0x00c6, 0x2011, 0x0101, 0x2204, 0xc0c4, 0x2012, 0x2001,
+	0x180c, 0x2014, 0xc2e4, 0x2202, 0x2071, 0x19e6, 0x7004, 0x9084,
+	0x0007, 0x0002, 0x9674, 0x9678, 0x9696, 0x96bf, 0x96fd, 0x9674,
+	0x968f, 0x9672, 0x080c, 0x0dd5, 0x00ce, 0x00ee, 0x00be, 0x0005,
+	0x7024, 0x9065, 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0x9015,
+	0x0158, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000,
+	0x00ce, 0x00ee, 0x00be, 0x0005, 0x7216, 0x7212, 0x0ca8, 0x7007,
+	0x0000, 0x7027, 0x0000, 0x7020, 0x9005, 0x0070, 0x6010, 0x2058,
+	0x080c, 0x65cb, 0xb800, 0xc0dc, 0xb802, 0x7007, 0x0000, 0x7027,
+	0x0000, 0x7020, 0x8001, 0x7022, 0x1148, 0x2001, 0x180c, 0x2014,
+	0xd2ec, 0x1180, 0x00ce, 0x00ee, 0x00be, 0x0005, 0xb854, 0x9015,
+	0x0120, 0x721e, 0x080c, 0x9763, 0x0ca8, 0x7218, 0x721e, 0x080c,
+	0x9763, 0x0c80, 0xc2ec, 0x2202, 0x080c, 0x9891, 0x0c58, 0x7024,
+	0x9065, 0x05b8, 0x700c, 0x9c06, 0x1160, 0x080c, 0xa761, 0x600c,
+	0x9015, 0x0120, 0x720e, 0x600f, 0x0000, 0x0448, 0x720e, 0x720a,
+	0x0430, 0x7014, 0x9c06, 0x1160, 0x080c, 0xa761, 0x600c, 0x9015,
+	0x0120, 0x7216, 0x600f, 0x0000, 0x00d0, 0x7216, 0x7212, 0x00b8,
+	0x6020, 0x9086, 0x0003, 0x1198, 0x6010, 0x2058, 0x080c, 0x65cb,
+	0xb800, 0xc0dc, 0xb802, 0x080c, 0xa761, 0x701c, 0x9065, 0x0138,
+	0xb854, 0x9015, 0x0110, 0x721e, 0x0010, 0x7218, 0x721e, 0x7027,
+	0x0000, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x7024, 0x9065, 0x0140,
+	0x080c, 0xa761, 0x600c, 0x9015, 0x0158, 0x720e, 0x600f, 0x0000,
+	0x080c, 0xa88b, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x00be, 0x0005,
+	0x720e, 0x720a, 0x0ca8, 0x00d6, 0x2069, 0x19e6, 0x6830, 0x9084,
+	0x0003, 0x0002, 0x9720, 0x9722, 0x9746, 0x971e, 0x080c, 0x0dd5,
+	0x00de, 0x0005, 0x00c6, 0x6840, 0x9086, 0x0001, 0x01b8, 0x683c,
+	0x9065, 0x0130, 0x600c, 0x9015, 0x0170, 0x6a3a, 0x600f, 0x0000,
+	0x6833, 0x0000, 0x683f, 0x0000, 0x2011, 0x1a05, 0x2013, 0x0000,
+	0x00ce, 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90, 0x6843, 0x0000,
+	0x6838, 0x9065, 0x0d68, 0x6003, 0x0003, 0x0c50, 0x00c6, 0x9006,
+	0x6842, 0x6846, 0x684a, 0x683c, 0x9065, 0x0160, 0x600c, 0x9015,
+	0x0130, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000, 0x0018, 0x683e,
+	0x683a, 0x6836, 0x00ce, 0x00de, 0x0005, 0x2001, 0x180c, 0x200c,
+	0xc1e5, 0x2102, 0x0005, 0x2001, 0x180c, 0x200c, 0xd1ec, 0x0120,
+	0xc1ec, 0x2102, 0x080c, 0x9891, 0x2001, 0x19f2, 0x2004, 0x9086,
+	0x0001, 0x0d58, 0x00d6, 0x2069, 0x19e6, 0x6804, 0x9084, 0x0007,
+	0x0006, 0x9005, 0x11c8, 0x2001, 0x1837, 0x2004, 0x9084, 0x0028,
+	0x1198, 0x2001, 0x197b, 0x2004, 0x9086, 0xaaaa, 0x0168, 0x2001,
+	0x188b, 0x2004, 0xd08c, 0x1118, 0xd084, 0x1118, 0x0028, 0x080c,
+	0x9891, 0x000e, 0x00de, 0x0005, 0x000e, 0x0002, 0x97a0, 0x985f,
+	0x985f, 0x985f, 0x985f, 0x9861, 0x985f, 0x979e, 0x080c, 0x0dd5,
+	0x6820, 0x9005, 0x1110, 0x00de, 0x0005, 0x00c6, 0x680c, 0x9065,
+	0x0520, 0x6114, 0x0096, 0x2148, 0xa964, 0x009e, 0x918c, 0x00ff,
+	0x918e, 0x0035, 0x1180, 0x2009, 0x1837, 0x210c, 0x918c, 0x0028,
+	0x1150, 0x080c, 0x743e, 0x0138, 0x0006, 0x2009, 0x188b, 0x2104,
+	0xc095, 0x200a, 0x000e, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000,
+	0x080c, 0x993a, 0x00ce, 0x00de, 0x0005, 0x6814, 0x9065, 0x0150,
+	0x6807, 0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x993a, 0x00ce,
+	0x00de, 0x0005, 0x00b6, 0x00e6, 0x6a1c, 0x92dd, 0x0000, 0x0904,
+	0x9849, 0xb84c, 0x900d, 0x0118, 0xb888, 0x9005, 0x01a0, 0xb854,
+	0x905d, 0x0120, 0x920e, 0x0904, 0x9849, 0x0028, 0x6818, 0x920e,
+	0x0904, 0x9849, 0x2058, 0xb84c, 0x900d, 0x0d88, 0xb888, 0x9005,
+	0x1d70, 0x2b00, 0x681e, 0xbb3c, 0xb838, 0x9302, 0x1e40, 0x080c,
+	0xaf1a, 0x0904, 0x9849, 0x8318, 0xbb3e, 0x6116, 0x2b10, 0x6212,
+	0x0096, 0x2148, 0xa880, 0x9084, 0x00ff, 0x605e, 0xa883, 0x0000,
+	0xa884, 0x009e, 0x908a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003,
+	0x801b, 0x831b, 0x9318, 0x631a, 0x6114, 0x0096, 0x2148, 0xa964,
+	0x009e, 0x918c, 0x00ff, 0x918e, 0x0048, 0x0538, 0x00f6, 0x2c78,
+	0x2061, 0x0100, 0xbac0, 0x629a, 0x2069, 0x0200, 0x2071, 0x0240,
+	0x080c, 0x9e91, 0x2069, 0x19e6, 0xbb00, 0xc3dd, 0xbb02, 0x6807,
+	0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x7823, 0x0003, 0x7803,
+	0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00be, 0x00ce, 0x00de,
+	0x0005, 0x00ee, 0x00be, 0x00ce, 0x0cd0, 0x6807, 0x0006, 0x2c18,
+	0x6b26, 0x6820, 0x8001, 0x6822, 0x682b, 0x0000, 0x080c, 0x65cb,
+	0x080c, 0xad5a, 0x00ee, 0x00be, 0x00ce, 0x00de, 0x0005, 0x00de,
+	0x0005, 0x00c6, 0x680c, 0x9065, 0x0508, 0x6114, 0x0096, 0x2148,
+	0xa964, 0x009e, 0x918c, 0x00ff, 0x918e, 0x0035, 0x1180, 0x2009,
+	0x1837, 0x210c, 0x918c, 0x0028, 0x1150, 0x080c, 0x743e, 0x0138,
+	0x0006, 0x2009, 0x188b, 0x2104, 0xc095, 0x200a, 0x000e, 0x6807,
+	0x0004, 0x6826, 0x682b, 0x0000, 0x080c, 0x993a, 0x00ce, 0x00de,
+	0x0005, 0x2001, 0x180c, 0x2014, 0xc2ed, 0x2202, 0x00de, 0x00fe,
+	0x0005, 0x00f6, 0x00d6, 0x2069, 0x19e6, 0x6830, 0x9086, 0x0000,
+	0x1570, 0x2001, 0x180c, 0x2014, 0xd2e4, 0x0130, 0xc2e4, 0x2202,
+	0x080c, 0x9772, 0x2069, 0x19e6, 0x2001, 0x180c, 0x200c, 0xd1c4,
+	0x1508, 0x6838, 0x907d, 0x01d8, 0x6a04, 0x9296, 0x0000, 0x1904,
+	0x992e, 0x7920, 0x918e, 0x0009, 0x0568, 0x6833, 0x0001, 0x683e,
+	0x6847, 0x0000, 0x684b, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400,
+	0x002e, 0x080c, 0x1c84, 0x1158, 0x012e, 0x080c, 0xa1b3, 0x00de,
+	0x00fe, 0x0005, 0xc1c4, 0x2102, 0x080c, 0x74ee, 0x08d0, 0x012e,
+	0x6843, 0x0000, 0x7803, 0x0002, 0x780c, 0x9015, 0x0140, 0x6a3a,
+	0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c40, 0x683a,
+	0x6836, 0x0cc0, 0x7908, 0xd1fc, 0x1198, 0x6833, 0x0001, 0x683e,
+	0x6847, 0x0000, 0x684b, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400,
+	0x002e, 0x080c, 0x1c84, 0x19d8, 0x012e, 0x080c, 0xa134, 0x0878,
+	0x2001, 0x1837, 0x2004, 0x9084, 0x0028, 0x1188, 0x2001, 0x197b,
+	0x2004, 0x9086, 0xaaaa, 0x0158, 0x2001, 0x19e7, 0x2004, 0x9005,
+	0x11f0, 0x2001, 0x188b, 0x200c, 0xc185, 0xc18c, 0x2102, 0x2f00,
+	0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x684b, 0x0000, 0x0126,
+	0x00f6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1c84, 0x1904, 0x98cf,
+	0x012e, 0x6a3c, 0x2278, 0x080c, 0xa0be, 0x0804, 0x98c7, 0x2011,
+	0x188b, 0x2204, 0xc08d, 0x2012, 0x0804, 0x98c7, 0x6a04, 0x9296,
+	0x0006, 0x1904, 0x9889, 0x6a30, 0x9296, 0x0000, 0x0904, 0x98b1,
+	0x0804, 0x9889, 0x6020, 0x9084, 0x000f, 0x000b, 0x0005, 0x994e,
+	0x9953, 0x9dc1, 0x9e5a, 0x9953, 0x9dc1, 0x9e5a, 0x994e, 0x9953,
+	0x994e, 0x994e, 0x994e, 0x994e, 0x994e, 0x994e, 0x080c, 0x9657,
+	0x080c, 0x9763, 0x0005, 0x00b6, 0x0156, 0x0136, 0x0146, 0x01c6,
+	0x01d6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071,
+	0x0240, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dd5, 0x6110, 0x2158,
+	0xb9c0, 0x2c78, 0x2061, 0x0100, 0x619a, 0x908a, 0x0040, 0x1a04,
+	0x99bf, 0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce,
+	0x014e, 0x013e, 0x015e, 0x00be, 0x0005, 0x9b44, 0x9b7f, 0x9ba8,
+	0x9c50, 0x9c72, 0x9c78, 0x9c85, 0x9c8d, 0x9c99, 0x9c9f, 0x9cb0,
+	0x9c9f, 0x9d08, 0x9c8d, 0x9d14, 0x9d1a, 0x9c99, 0x9d1a, 0x9d26,
+	0x99bd, 0x99bd, 0x99bd, 0x99bd, 0x99bd, 0x99bd, 0x99bd, 0x99bd,
+	0x99bd, 0x99bd, 0x99bd, 0xa563, 0xa586, 0xa597, 0xa5b7, 0xa5e9,
+	0x9c85, 0x99bd, 0x9c85, 0x9c9f, 0x99bd, 0x9ba8, 0x9c50, 0x99bd,
+	0xa982, 0x9c9f, 0x99bd, 0xa99e, 0x9c9f, 0x99bd, 0x9c99, 0x9b3e,
+	0x99e0, 0x99bd, 0xa9ba, 0xaa27, 0xab02, 0x99bd, 0xab0f, 0x9c82,
+	0xab3a, 0x99bd, 0xa5f3, 0xab67, 0x99bd, 0x080c, 0x0dd5, 0x2100,
+	0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e,
+	0x013e, 0x015e, 0x00be, 0x0005, 0xac02, 0xacb4, 0x99de, 0x9a07,
+	0x9ab3, 0x9abe, 0x99de, 0x9c85, 0x99de, 0x9b05, 0x9b11, 0x9a22,
+	0x99de, 0x9a3d, 0x9a71, 0xae21, 0xae66, 0x9c9f, 0x080c, 0x0dd5,
+	0x00d6, 0x0096, 0x080c, 0x9d39, 0x7003, 0x2414, 0x7007, 0x0018,
+	0x700b, 0x0800, 0x7814, 0x2048, 0xa83c, 0x700e, 0xa850, 0x7022,
+	0xa854, 0x7026, 0x60c3, 0x0018, 0x080c, 0xa32a, 0x009e, 0x00de,
+	0x0005, 0x7810, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x080c, 0xaead,
+	0x1118, 0x9084, 0xff80, 0x0110, 0x9085, 0x0001, 0x0005, 0x00d6,
+	0x0096, 0x080c, 0x9d39, 0x7003, 0x0500, 0x7814, 0x2048, 0xa874,
+	0x700a, 0xa878, 0x700e, 0xa87c, 0x7012, 0xa880, 0x7016, 0xa884,
+	0x701a, 0xa888, 0x701e, 0x60c3, 0x0010, 0x080c, 0xa32a, 0x009e,
+	0x00de, 0x0005, 0x00d6, 0x0096, 0x080c, 0x9d39, 0x7003, 0x0500,
+	0x7814, 0x2048, 0xa8cc, 0x700a, 0xa8d0, 0x700e, 0xa8d4, 0x7012,
+	0xa8d8, 0x7016, 0xa8dc, 0x701a, 0xa8e0, 0x701e, 0x60c3, 0x0010,
+	0x080c, 0xa32a, 0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x9d39, 0x20e9, 0x0000, 0x2001, 0x19a2,
+	0x2003, 0x0000, 0x7814, 0x2048, 0xa814, 0x8003, 0x60c2, 0xa830,
+	0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, 0x2001,
+	0x19a2, 0x0016, 0x200c, 0x2001, 0x0001, 0x080c, 0x23f5, 0x080c,
+	0xd9e7, 0x9006, 0x080c, 0x23f5, 0x001e, 0xa804, 0x9005, 0x0110,
+	0x2048, 0x0c28, 0x04d9, 0x080c, 0xa32a, 0x012e, 0x009e, 0x00de,
+	0x0005, 0x00d6, 0x0096, 0x0126, 0x2091, 0x8000, 0x080c, 0x9d84,
+	0x20e9, 0x0000, 0x2001, 0x19a2, 0x2003, 0x0000, 0x7814, 0x2048,
+	0xa86f, 0x0200, 0xa873, 0x0000, 0xa814, 0x8003, 0x60c2, 0xa830,
+	0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, 0x2001,
+	0x19a2, 0x0016, 0x200c, 0x080c, 0xd9e7, 0x001e, 0xa804, 0x9005,
+	0x0110, 0x2048, 0x0c60, 0x0051, 0x7814, 0x2048, 0x080c, 0x0fb1,
+	0x080c, 0xa32a, 0x012e, 0x009e, 0x00de, 0x0005, 0x60c0, 0x8004,
+	0x9084, 0x0003, 0x9005, 0x0130, 0x9082, 0x0004, 0x20a3, 0x0000,
+	0x8000, 0x1de0, 0x0005, 0x080c, 0x9d39, 0x7003, 0x7800, 0x7808,
+	0x8007, 0x700a, 0x60c3, 0x0008, 0x0804, 0xa32a, 0x00d6, 0x00e6,
+	0x080c, 0x9d84, 0x7814, 0x9084, 0xff00, 0x2073, 0x0200, 0x8e70,
+	0x8e70, 0x9095, 0x0010, 0x2272, 0x8e70, 0x2073, 0x0034, 0x8e70,
+	0x2069, 0x1805, 0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70, 0x1f04,
+	0x9ad4, 0x2069, 0x1801, 0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70,
+	0x1f04, 0x9add, 0x2069, 0x19b2, 0x9086, 0xdf00, 0x0110, 0x2069,
+	0x19cc, 0x20a9, 0x001a, 0x9e86, 0x0260, 0x1148, 0x00c6, 0x2061,
+	0x0200, 0x6010, 0x8000, 0x6012, 0x00ce, 0x2071, 0x0240, 0x2d04,
+	0x8007, 0x2072, 0x8d68, 0x8e70, 0x1f04, 0x9aeb, 0x60c3, 0x004c,
+	0x080c, 0xa32a, 0x00ee, 0x00de, 0x0005, 0x080c, 0x9d39, 0x7003,
+	0x6300, 0x7007, 0x0028, 0x7808, 0x700e, 0x60c3, 0x0008, 0x0804,
+	0xa32a, 0x00d6, 0x0026, 0x0016, 0x080c, 0x9d84, 0x7003, 0x0200,
+	0x7814, 0x700e, 0x00e6, 0x9ef0, 0x0004, 0x2009, 0x0001, 0x2011,
+	0x000c, 0x2069, 0x1923, 0x6810, 0xd084, 0x1148, 0x2073, 0x0500,
+	0x8e70, 0x2073, 0x0000, 0x8e70, 0x8108, 0x9290, 0x0004, 0x2073,
+	0x0800, 0x8e70, 0x2073, 0x0000, 0x00ee, 0x7206, 0x710a, 0x62c2,
+	0x080c, 0xa32a, 0x001e, 0x002e, 0x00de, 0x0005, 0x2001, 0x1818,
+	0x2004, 0x609a, 0x0804, 0xa32a, 0x080c, 0x9d39, 0x7003, 0x5200,
+	0x2069, 0x1847, 0x6804, 0xd084, 0x0130, 0x6828, 0x0016, 0x080c,
+	0x28af, 0x710e, 0x001e, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099,
+	0x1805, 0x20e9, 0x0000, 0x20a1, 0x0250, 0x4003, 0x20a9, 0x0004,
+	0x2099, 0x1801, 0x20a1, 0x0254, 0x4003, 0x080c, 0xaead, 0x1120,
+	0xb8a0, 0x9082, 0x007f, 0x0248, 0x2001, 0x181f, 0x2004, 0x7032,
+	0x2001, 0x1820, 0x2004, 0x7036, 0x0030, 0x2001, 0x1818, 0x2004,
+	0x9084, 0x00ff, 0x7036, 0x60c3, 0x001c, 0x0804, 0xa32a, 0x080c,
+	0x9d39, 0x7003, 0x0500, 0x080c, 0xaead, 0x1120, 0xb8a0, 0x9082,
+	0x007f, 0x0248, 0x2001, 0x181f, 0x2004, 0x700a, 0x2001, 0x1820,
+	0x2004, 0x700e, 0x0030, 0x2001, 0x1818, 0x2004, 0x9084, 0x00ff,
+	0x700e, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9,
+	0x0000, 0x20a1, 0x0250, 0x4003, 0x60c3, 0x0010, 0x0804, 0xa32a,
+	0x080c, 0x9d39, 0x9006, 0x080c, 0x69d6, 0xb8a0, 0x9086, 0x007e,
+	0x1130, 0x7003, 0x0400, 0x620c, 0xc2b4, 0x620e, 0x0058, 0x7814,
+	0x0096, 0x904d, 0x0120, 0x9006, 0xa89a, 0xa8a6, 0xa8aa, 0x009e,
+	0x7003, 0x0300, 0xb8a0, 0x9086, 0x007e, 0x1904, 0x9c17, 0x00d6,
+	0x2069, 0x196b, 0x2001, 0x1837, 0x2004, 0xd0a4, 0x0188, 0x6800,
+	0x700a, 0x6808, 0x9084, 0x2000, 0x7012, 0x080c, 0xaec4, 0x680c,
+	0x7016, 0x701f, 0x2710, 0x6818, 0x7022, 0x681c, 0x7026, 0x0090,
+	0x6800, 0x700a, 0x6804, 0x700e, 0x6808, 0x080c, 0x743e, 0x1118,
+	0x9084, 0x37ff, 0x0010, 0x9084, 0x3fff, 0x7012, 0x080c, 0xaec4,
+	0x680c, 0x7016, 0x00de, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099,
+	0x1805, 0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003, 0x20a9, 0x0004,
+	0x2099, 0x1801, 0x20a1, 0x025a, 0x4003, 0x00d6, 0x080c, 0xabe9,
+	0x2069, 0x1973, 0x2071, 0x024e, 0x6800, 0xc0dd, 0x7002, 0x080c,
+	0x5761, 0xd0e4, 0x0110, 0x680c, 0x700e, 0x00de, 0x04a8, 0x2001,
+	0x1837, 0x2004, 0xd0a4, 0x0170, 0x0016, 0x2001, 0x196c, 0x200c,
+	0x60e0, 0x9106, 0x0130, 0x2100, 0x60e3, 0x0000, 0x080c, 0x28f0,
+	0x61e2, 0x001e, 0x20e1, 0x0001, 0x2099, 0x196b, 0x20e9, 0x0000,
+	0x20a1, 0x024e, 0x20a9, 0x0008, 0x4003, 0x20a9, 0x0004, 0x2099,
+	0x1805, 0x20a1, 0x0256, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801,
+	0x20a1, 0x025a, 0x4003, 0x080c, 0xabe9, 0x20a1, 0x024e, 0x20a9,
+	0x0008, 0x2099, 0x1973, 0x4003, 0x60c3, 0x0074, 0x0804, 0xa32a,
+	0x080c, 0x9d39, 0x7003, 0x2010, 0x7007, 0x0014, 0x700b, 0x0800,
+	0x700f, 0x2000, 0x9006, 0x00f6, 0x2079, 0x1847, 0x7904, 0x00fe,
+	0xd1ac, 0x1110, 0x9085, 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010,
+	0x9085, 0x0002, 0x00d6, 0x0804, 0x9ce9, 0x7026, 0x60c3, 0x0014,
+	0x0804, 0xa32a, 0x080c, 0x9d39, 0x7003, 0x5000, 0x0804, 0x9bc2,
+	0x080c, 0x9d39, 0x7003, 0x2110, 0x7007, 0x0014, 0x60c3, 0x0014,
+	0x0804, 0xa32a, 0x080c, 0x9d7b, 0x0010, 0x080c, 0x9d84, 0x7003,
+	0x0200, 0x60c3, 0x0004, 0x0804, 0xa32a, 0x080c, 0x9d84, 0x7003,
+	0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x0804,
+	0xa32a, 0x080c, 0x9d84, 0x7003, 0x0200, 0x0804, 0x9bc2, 0x080c,
+	0x9d84, 0x7003, 0x0100, 0x782c, 0x9005, 0x0110, 0x700a, 0x0010,
+	0x700b, 0x0003, 0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0xa32a,
+	0x00d6, 0x080c, 0x9d84, 0x7003, 0x0210, 0x7007, 0x0014, 0x700b,
+	0x0800, 0xb894, 0x9086, 0x0014, 0x1198, 0xb99c, 0x9184, 0x0030,
+	0x0190, 0xb998, 0x9184, 0xc000, 0x1140, 0xd1ec, 0x0118, 0x700f,
+	0x2100, 0x0058, 0x700f, 0x0100, 0x0040, 0x700f, 0x0400, 0x0028,
+	0x700f, 0x0700, 0x0010, 0x700f, 0x0800, 0x00f6, 0x2079, 0x1847,
+	0x7904, 0x00fe, 0xd1ac, 0x1110, 0x9085, 0x0020, 0xd1a4, 0x0110,
+	0x9085, 0x0010, 0x2009, 0x1869, 0x210c, 0xd184, 0x1110, 0x9085,
+	0x0002, 0x0026, 0x2009, 0x1867, 0x210c, 0xd1e4, 0x0150, 0xc0c5,
+	0xbacc, 0xd28c, 0x1108, 0xc0cd, 0x9094, 0x0030, 0x9296, 0x0010,
+	0x0140, 0xd1ec, 0x0130, 0x9094, 0x0030, 0x9296, 0x0010, 0x0108,
+	0xc0bd, 0x002e, 0x7026, 0x60c3, 0x0014, 0x00de, 0x0804, 0xa32a,
+	0x080c, 0x9d84, 0x7003, 0x0210, 0x7007, 0x0014, 0x700f, 0x0100,
+	0x60c3, 0x0014, 0x0804, 0xa32a, 0x080c, 0x9d84, 0x7003, 0x0200,
+	0x0804, 0x9b48, 0x080c, 0x9d84, 0x7003, 0x0100, 0x700b, 0x0003,
+	0x700f, 0x2a00, 0x60c3, 0x0008, 0x0804, 0xa32a, 0x080c, 0x9d84,
+	0x7003, 0x0100, 0x700b, 0x000b, 0x60c3, 0x0008, 0x0804, 0xa32a,
+	0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x3200, 0x2021, 0x0800,
+	0x0040, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x2200, 0x2021,
+	0x0100, 0x080c, 0xabfe, 0xb810, 0x9305, 0x7002, 0xb814, 0x7006,
+	0x2069, 0x1800, 0x687c, 0x700a, 0x6880, 0x700e, 0x9485, 0x0029,
+	0x7012, 0x004e, 0x003e, 0x00de, 0x080c, 0xa318, 0x721a, 0x9f95,
+	0x0000, 0x7222, 0x7027, 0xffff, 0x2071, 0x024c, 0x002e, 0x0005,
+	0x0026, 0x080c, 0xabfe, 0x7003, 0x02ff, 0x7007, 0xfffc, 0x00d6,
+	0x2069, 0x1800, 0x687c, 0x700a, 0x6880, 0x700e, 0x00de, 0x7013,
+	0x2029, 0x0c10, 0x7003, 0x0100, 0x7007, 0x0000, 0x700b, 0xfc02,
+	0x700f, 0x0000, 0x0005, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019,
+	0x3300, 0x2021, 0x0800, 0x0040, 0x0026, 0x00d6, 0x0036, 0x0046,
+	0x2019, 0x2300, 0x2021, 0x0100, 0x080c, 0xabfe, 0xb810, 0x9305,
+	0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0xb810, 0x9005, 0x1140,
+	0xb814, 0x9005, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffe, 0x0020,
+	0x687c, 0x700a, 0x6880, 0x700e, 0x0000, 0x9485, 0x0098, 0x7012,
+	0x004e, 0x003e, 0x00de, 0x080c, 0xa318, 0x721a, 0x7a08, 0x7222,
+	0x2f10, 0x7226, 0x2071, 0x024c, 0x002e, 0x0005, 0x080c, 0xa318,
+	0x721a, 0x7a08, 0x7222, 0x7814, 0x7026, 0x2071, 0x024c, 0x002e,
+	0x0005, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200,
+	0x2071, 0x0240, 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0dd5, 0x908a,
+	0x0092, 0x1a0c, 0x0dd5, 0x6110, 0x2158, 0xb9c0, 0x2c78, 0x2061,
+	0x0100, 0x619a, 0x9082, 0x0085, 0x0033, 0x00fe, 0x00ee, 0x00de,
+	0x00ce, 0x00be, 0x0005, 0x9df2, 0x9e01, 0x9e0c, 0x9df0, 0x9df0,
+	0x9df0, 0x9df2, 0x9df0, 0x9df0, 0x9df0, 0x9df0, 0x9df0, 0x9df0,
+	0x080c, 0x0dd5, 0x0411, 0x60c3, 0x0000, 0x0026, 0x080c, 0x2be3,
+	0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e, 0x0804,
+	0xa32a, 0x0431, 0x7808, 0x700a, 0x7814, 0x700e, 0x7017, 0xffff,
+	0x60c3, 0x000c, 0x0804, 0xa32a, 0x04a1, 0x7003, 0x0003, 0x7007,
+	0x0300, 0x60c3, 0x0004, 0x0804, 0xa32a, 0x0026, 0x080c, 0xabfe,
+	0xb810, 0x9085, 0x8100, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800,
+	0x687c, 0x700a, 0x6880, 0x700e, 0x7013, 0x0009, 0x0804, 0x9d54,
+	0x0026, 0x080c, 0xabfe, 0xb810, 0x9085, 0x8400, 0x7002, 0xb814,
+	0x7006, 0x2069, 0x1800, 0x687c, 0x700a, 0x6880, 0x700e, 0x2001,
+	0x0099, 0x7a20, 0x9296, 0x0005, 0x0108, 0xc0bc, 0x7012, 0x0804,
+	0x9db6, 0x0026, 0x080c, 0xabfe, 0xb810, 0x9085, 0x8500, 0x7002,
+	0xb814, 0x7006, 0x2069, 0x1800, 0x687c, 0x700a, 0x6880, 0x700e,
+	0x2001, 0x0099, 0x7a20, 0x9296, 0x0005, 0x0108, 0xc0bc, 0x7012,
+	0x0804, 0x9db6, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2c78,
+	0x2069, 0x0200, 0x2071, 0x0240, 0x7804, 0x908a, 0x0040, 0x0a0c,
+	0x0dd5, 0x908a, 0x0054, 0x1a0c, 0x0dd5, 0x7910, 0x2158, 0xb9c0,
+	0x2061, 0x0100, 0x619a, 0x9082, 0x0040, 0x0033, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x00be, 0x0005, 0x9e91, 0x9f4d, 0x9f20, 0xa06f,
+	0x9e8f, 0x9e8f, 0x9e8f, 0x9e8f, 0x9e8f, 0x9e8f, 0x9e8f, 0xa73e,
+	0xa746, 0xa74e, 0xa756, 0x9e8f, 0xab46, 0x9e8f, 0xa736, 0x080c,
+	0x0dd5, 0x0096, 0x780b, 0xffff, 0x080c, 0x9efc, 0x7914, 0x2148,
+	0xa978, 0x7956, 0xae64, 0x96b4, 0x00ff, 0x9686, 0x0008, 0x1148,
+	0xa8b4, 0x7032, 0xa8b8, 0x7036, 0xa8bc, 0x703a, 0xa8c0, 0x703e,
+	0x0008, 0x7132, 0xa97c, 0x9184, 0x000f, 0x1118, 0x2001, 0x0005,
+	0x0040, 0xd184, 0x0118, 0x2001, 0x0004, 0x0018, 0x9084, 0x0006,
+	0x8004, 0x2010, 0x785c, 0x9084, 0x00ff, 0x8007, 0x9205, 0x7042,
+	0xd1ac, 0x0158, 0x7047, 0x0002, 0x9686, 0x0008, 0x1118, 0x080c,
+	0x18dd, 0x0010, 0x080c, 0x1754, 0x0050, 0xd1b4, 0x0118, 0x7047,
+	0x0001, 0x0028, 0x7047, 0x0000, 0x9016, 0x2230, 0x0010, 0xaab0,
+	0xaeac, 0x726a, 0x766e, 0x20a9, 0x0008, 0x20e9, 0x0000, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x0023, 0x2098, 0x20a1, 0x0252, 0x2069,
+	0x0200, 0x6813, 0x0018, 0x4003, 0x6813, 0x0008, 0x60c3, 0x0020,
+	0x6017, 0x0009, 0x2001, 0x1a02, 0x2003, 0x07d0, 0x2001, 0x1a01,
+	0x2003, 0x0009, 0x009e, 0x0005, 0x6813, 0x0008, 0xba8c, 0x8210,
+	0xb8cc, 0xd084, 0x0128, 0x7a4a, 0x7b14, 0x7b46, 0x722e, 0x732a,
+	0x9294, 0x00ff, 0xba8e, 0x8217, 0x721a, 0xba10, 0x9295, 0x0600,
+	0x7202, 0xba14, 0x7206, 0x2069, 0x1800, 0x6a7c, 0x720a, 0x6a80,
+	0x720e, 0x7013, 0x0829, 0x2f10, 0x7222, 0x7027, 0xffff, 0x0005,
+	0x00d6, 0x0096, 0x0081, 0x7814, 0x2048, 0xa890, 0x7002, 0xa88c,
+	0x7006, 0xa8b0, 0x700a, 0xa8ac, 0x700e, 0x60c3, 0x000c, 0x009e,
+	0x00de, 0x0804, 0xa32a, 0x6813, 0x0008, 0xb810, 0x9085, 0x0500,
+	0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x687c, 0x700a, 0x6880,
+	0x700e, 0x7013, 0x0889, 0x080c, 0xa318, 0x721a, 0x7a08, 0x7222,
+	0x2f10, 0x7226, 0x2071, 0x024c, 0x0005, 0x00d6, 0x0096, 0x080c,
+	0xa04d, 0x7814, 0x2048, 0x080c, 0xcc84, 0x1130, 0x7814, 0x9084,
+	0x0700, 0x8007, 0x0033, 0x0010, 0x9006, 0x001b, 0x009e, 0x00de,
+	0x0005, 0x9f6b, 0x9fd4, 0x9fe4, 0xa00a, 0xa016, 0xa027, 0xa02f,
+	0x9f69, 0x080c, 0x0dd5, 0x0016, 0x0036, 0xa97c, 0x918c, 0x0003,
+	0x0118, 0x9186, 0x0003, 0x1198, 0xaba8, 0x7824, 0xd0cc, 0x1168,
+	0x7316, 0xa898, 0x701a, 0xa894, 0x701e, 0x003e, 0x001e, 0x2001,
+	0x19b0, 0x2004, 0x60c2, 0x0804, 0xa32a, 0xc3e5, 0x0c88, 0x9186,
+	0x0001, 0x190c, 0x0dd5, 0xaba8, 0x7824, 0xd0cc, 0x1904, 0x9fd1,
+	0x7316, 0xa898, 0x701a, 0xa894, 0x701e, 0xa8a4, 0x7026, 0xa8ac,
+	0x702e, 0x2009, 0x0018, 0x9384, 0x0300, 0x0570, 0xd3c4, 0x0110,
+	0xa8ac, 0x9108, 0xd3cc, 0x0110, 0xa8a4, 0x9108, 0x6810, 0x9085,
+	0x0010, 0x6812, 0x2011, 0x0258, 0x20e9, 0x0000, 0x22a0, 0x0156,
+	0x20a9, 0x0008, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x002c, 0x2098,
+	0x4003, 0x6810, 0x8000, 0x6812, 0x2011, 0x0240, 0x22a0, 0x20a9,
+	0x0005, 0x4003, 0x6810, 0xc084, 0x6812, 0x015e, 0x9184, 0x0003,
+	0x0118, 0x2019, 0x0245, 0x201a, 0x61c2, 0x003e, 0x001e, 0x0804,
+	0xa32a, 0xc3e5, 0x0804, 0x9f90, 0x2011, 0x0008, 0x2001, 0x180f,
+	0x2004, 0xd0a4, 0x0110, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x1110,
+	0x7216, 0x0470, 0x0ce8, 0xc2e5, 0x2011, 0x0302, 0x0016, 0x782c,
+	0x701a, 0x7930, 0x711e, 0x9105, 0x0108, 0xc2dd, 0x001e, 0x7824,
+	0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x7027, 0x0012, 0x702f, 0x0008,
+	0x7043, 0x7000, 0x7047, 0x0500, 0x704f, 0x000a, 0x2069, 0x0200,
+	0x6813, 0x0009, 0x2071, 0x0240, 0x700b, 0x2500, 0x60c3, 0x0032,
+	0x0804, 0xa32a, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x1128, 0x7216,
+	0x60c3, 0x0018, 0x0804, 0xa32a, 0x0cd0, 0xc2e5, 0x2011, 0x0100,
+	0x7824, 0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x702f, 0x0008, 0x7858,
+	0x9084, 0x00ff, 0x7036, 0x60c3, 0x0020, 0x0804, 0xa32a, 0x2011,
+	0x0008, 0x7824, 0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x0c08, 0x0036,
+	0x7b14, 0x9384, 0xff00, 0x7816, 0x9384, 0x00ff, 0x8001, 0x1138,
+	0x7824, 0xd0cc, 0x0108, 0xc2e5, 0x7216, 0x003e, 0x0888, 0x0046,
+	0x2021, 0x0800, 0x0006, 0x7824, 0xd0cc, 0x000e, 0x0108, 0xc4e5,
+	0x7416, 0x004e, 0x701e, 0x003e, 0x0818, 0x00d6, 0x6813, 0x0008,
+	0xb810, 0x9085, 0x0700, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800,
+	0x687c, 0x700a, 0x6880, 0x700e, 0x7824, 0xd0cc, 0x1168, 0x7013,
+	0x0898, 0x080c, 0xa318, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226,
+	0x2071, 0x024c, 0x00de, 0x0005, 0x7013, 0x0889, 0x0c90, 0x0016,
+	0x7814, 0x9084, 0x0700, 0x8007, 0x0013, 0x001e, 0x0005, 0xa07f,
+	0xa07f, 0xa081, 0xa07f, 0xa07f, 0xa07f, 0xa09b, 0xa07f, 0x080c,
+	0x0dd5, 0x7914, 0x918c, 0x08ff, 0x918d, 0xf600, 0x7916, 0x2009,
+	0x0003, 0x00b9, 0x2069, 0x1847, 0x6804, 0xd0bc, 0x0130, 0x682c,
+	0x9084, 0x00ff, 0x8007, 0x7032, 0x0010, 0x7033, 0x3f00, 0x60c3,
+	0x0001, 0x0804, 0xa32a, 0x2009, 0x0003, 0x0019, 0x7033, 0x7f00,
+	0x0cb0, 0x0016, 0x080c, 0xabfe, 0x001e, 0xb810, 0x9085, 0x0100,
+	0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6a7c, 0x720a, 0x6a80,
+	0x720e, 0x7013, 0x0888, 0x918d, 0x0008, 0x7116, 0x080c, 0xa318,
+	0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x0005, 0x00b6, 0x00e6,
+	0x00d6, 0x00c6, 0x0066, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100,
+	0x2071, 0x1800, 0x7160, 0x7810, 0x2058, 0x76dc, 0x96b4, 0x0028,
+	0x0110, 0x737c, 0x7480, 0x2500, 0x76dc, 0x96b4, 0x0028, 0x0140,
+	0x2001, 0x04ff, 0x6062, 0x6067, 0xffff, 0x636a, 0x646e, 0x0050,
+	0x2001, 0x00ff, 0x9085, 0x0400, 0x6062, 0x6067, 0xffff, 0x606b,
+	0x0000, 0x616e, 0xb8b8, 0x6073, 0x0530, 0x6077, 0x0008, 0xb88c,
+	0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x9085, 0x0020, 0x607a,
+	0x607f, 0x0000, 0x2b00, 0x6082, 0x6087, 0xffff, 0x7814, 0x0096,
+	0x2048, 0xa838, 0x608a, 0xa834, 0x608e, 0xa848, 0x60c6, 0xa844,
+	0x60ca, 0x009e, 0xb86c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5,
+	0x60d7, 0x0000, 0x2001, 0x1837, 0x2004, 0x9084, 0x0028, 0x0128,
+	0x609f, 0x0000, 0x2001, 0x0092, 0x0048, 0x6028, 0xc0bd, 0x602a,
+	0x609f, 0x00ff, 0x6027, 0xffff, 0x2001, 0x00b2, 0x6016, 0x2009,
+	0x07d0, 0x080c, 0x863b, 0x003e, 0x004e, 0x005e, 0x006e, 0x00ce,
+	0x00de, 0x00ee, 0x00be, 0x0005, 0x00b6, 0x00e6, 0x00d6, 0x00c6,
+	0x0066, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x1800,
+	0x7160, 0x7810, 0x2058, 0xb8a0, 0x2028, 0x76dc, 0xd6ac, 0x1168,
+	0x9582, 0x007e, 0x1250, 0x2500, 0x9094, 0xff80, 0x1130, 0x9080,
+	0x3384, 0x2015, 0x9294, 0x00ff, 0x0020, 0xb910, 0xba14, 0x737c,
+	0x7480, 0x70dc, 0xd0ac, 0x1130, 0x9582, 0x007e, 0x1218, 0x9584,
+	0xff80, 0x0138, 0x9185, 0x0400, 0x6062, 0x6266, 0x636a, 0x646e,
+	0x0030, 0x6063, 0x0400, 0x6266, 0x606b, 0x0000, 0x616e, 0xb8b8,
+	0x6072, 0x6077, 0x0000, 0xb864, 0xd0a4, 0x0110, 0x6077, 0x0008,
+	0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x9085, 0x0020,
+	0x607a, 0x607f, 0x0000, 0x2b00, 0x6082, 0x6087, 0xffff, 0x7814,
+	0x0096, 0x2048, 0xa838, 0x608a, 0xa834, 0x608e, 0xa848, 0x60c6,
+	0xa844, 0x60ca, 0x009e, 0xb86c, 0x60ce, 0x60ab, 0x0036, 0x60af,
+	0x95d5, 0x60d7, 0x0000, 0xbac0, 0x629e, 0x00f6, 0x2079, 0x0140,
+	0x7803, 0x0000, 0x00fe, 0x2009, 0x0092, 0x6116, 0x2009, 0x07d0,
+	0x080c, 0x863b, 0x003e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de,
+	0x00ee, 0x00be, 0x0005, 0x00b6, 0x0096, 0x00e6, 0x00d6, 0x00c6,
+	0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x1800, 0x7810,
+	0x2058, 0xb8a0, 0x2028, 0xb910, 0xba14, 0x737c, 0x7480, 0x7820,
+	0x90be, 0x0006, 0x0904, 0xa287, 0x90be, 0x000a, 0x1904, 0xa243,
+	0xb8c0, 0x609e, 0x7814, 0x2048, 0xa87c, 0xd0fc, 0x0558, 0xaf90,
+	0x9784, 0xff00, 0x9105, 0x6062, 0x873f, 0x9784, 0xff00, 0x0006,
+	0x7814, 0x2048, 0xa878, 0xc0fc, 0x9005, 0x000e, 0x1160, 0xaf94,
+	0x87ff, 0x0198, 0x2039, 0x0098, 0x9705, 0x6072, 0x7808, 0x6082,
+	0x2f00, 0x6086, 0x0038, 0x9185, 0x2200, 0x6062, 0x6073, 0x0129,
+	0x6077, 0x0000, 0xb8c0, 0x609e, 0x0050, 0x2039, 0x0029, 0x9705,
+	0x6072, 0x0cc0, 0x9185, 0x0200, 0x6062, 0x6073, 0x2029, 0xa87c,
+	0xd0fc, 0x0118, 0xaf94, 0x87ff, 0x1120, 0x2f00, 0x6082, 0x7808,
+	0x6086, 0x6266, 0x636a, 0x646e, 0x6077, 0x0000, 0xb88c, 0x8000,
+	0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f, 0x0000, 0xa838,
+	0x608a, 0xa834, 0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c,
+	0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x080c, 0xabe3, 0x2009,
+	0x07d0, 0x60c4, 0x9084, 0xfff0, 0x9005, 0x0110, 0x2009, 0x1b58,
+	0x080c, 0x863b, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee,
+	0x009e, 0x00be, 0x0005, 0x7804, 0x9086, 0x0040, 0x0904, 0xa2c3,
+	0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0809,
+	0x6077, 0x0008, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xb88c, 0x8000,
+	0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00,
+	0x6082, 0x7808, 0x6086, 0x7814, 0x2048, 0xa838, 0x608a, 0xa834,
+	0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c, 0x60ce, 0xbac0,
+	0x629e, 0x080c, 0xabe3, 0x2009, 0x07d0, 0x60c4, 0x9084, 0xfff0,
+	0x9005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x863b, 0x003e, 0x004e,
+	0x005e, 0x00ce, 0x00de, 0x00ee, 0x009e, 0x00be, 0x0005, 0x7814,
+	0x2048, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0904, 0xa2df,
+	0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0880,
+	0x6077, 0x0008, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007,
+	0x607a, 0x7838, 0x607e, 0x2f00, 0x6086, 0x7808, 0x6082, 0xa890,
+	0x608a, 0xa88c, 0x608e, 0xa8b0, 0x60c6, 0xa8ac, 0x60ca, 0xa8ac,
+	0x7930, 0x9108, 0x7932, 0xa8b0, 0x792c, 0x9109, 0x792e, 0xb86c,
+	0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xbac0, 0x629e, 0x080c,
+	0xabc0, 0x0804, 0xa273, 0xb8cc, 0xd084, 0x0148, 0xb88c, 0x7814,
+	0x2048, 0xb88c, 0x784a, 0xa836, 0x2900, 0xa83a, 0xb046, 0x9185,
+	0x0600, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0829, 0x6077,
+	0x0000, 0x60af, 0x9575, 0x60d7, 0x0000, 0x0804, 0xa256, 0x9185,
+	0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x7824, 0xd0cc, 0x7826,
+	0x0118, 0x6073, 0x0889, 0x0010, 0x6073, 0x0898, 0x6077, 0x0000,
+	0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f,
+	0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0xa838, 0x608a, 0xa834,
+	0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c, 0x60ce, 0x60af,
+	0x95d5, 0x60d7, 0x0000, 0xbac0, 0x629e, 0x7824, 0xd0cc, 0x0120,
+	0x080c, 0xabe3, 0x0804, 0xa273, 0x080c, 0xabc0, 0x0804, 0xa273,
+	0x7a10, 0x00b6, 0x2258, 0xba8c, 0x8210, 0x9294, 0x00ff, 0xba8e,
+	0x00be, 0x8217, 0x0005, 0x00d6, 0x2069, 0x19e6, 0x6843, 0x0001,
+	0x00de, 0x0005, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x00f1, 0x080c,
+	0x862d, 0x0005, 0x0016, 0x2001, 0x180c, 0x200c, 0x9184, 0x0600,
+	0x9086, 0x0600, 0x0128, 0x0089, 0x080c, 0x862d, 0x001e, 0x0005,
+	0xc1e5, 0x2001, 0x180c, 0x2102, 0x2001, 0x19e7, 0x2003, 0x0000,
+	0x2001, 0x19ef, 0x2003, 0x0000, 0x0c88, 0x0006, 0x6014, 0x9084,
+	0x1804, 0x9085, 0x0009, 0x6016, 0x000e, 0x0005, 0x0016, 0x00c6,
+	0x0006, 0x2061, 0x0100, 0x61a4, 0x60a7, 0x95f5, 0x6014, 0x9084,
+	0x1804, 0x9085, 0x0008, 0x6016, 0x000e, 0xa001, 0xa001, 0xa001,
+	0x61a6, 0x00ce, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x743e, 0x11c0, 0x2001,
+	0x1a02, 0x2004, 0x9005, 0x15d0, 0x080c, 0x74ee, 0x1160, 0x2061,
+	0x0100, 0x6020, 0xd0b4, 0x1120, 0x6024, 0xd084, 0x090c, 0x0dd5,
+	0x080c, 0x862d, 0x0458, 0x00c6, 0x2061, 0x19e6, 0x00c8, 0x6904,
+	0x9194, 0x4000, 0x0540, 0x0811, 0x080c, 0x2d5e, 0x00c6, 0x2061,
+	0x19e6, 0x6128, 0x9192, 0x0008, 0x1258, 0x8108, 0x612a, 0x6124,
+	0x00ce, 0x81ff, 0x0198, 0x080c, 0x862d, 0x080c, 0xa34d, 0x0070,
+	0x6124, 0x91e5, 0x0000, 0x0140, 0x080c, 0xeb8e, 0x080c, 0x8636,
+	0x2009, 0x0014, 0x080c, 0xafbe, 0x00ce, 0x0000, 0x002e, 0x001e,
+	0x00de, 0x00ce, 0x0005, 0x2001, 0x1a02, 0x2004, 0x9005, 0x1db0,
+	0x00c6, 0x2061, 0x19e6, 0x6128, 0x9192, 0x0003, 0x1e08, 0x8108,
+	0x612a, 0x00ce, 0x080c, 0x862d, 0x080c, 0x5f6c, 0x2009, 0x1846,
+	0x2114, 0x8210, 0x220a, 0x0c10, 0x0096, 0x00c6, 0x00d6, 0x00e6,
+	0x0016, 0x0026, 0x080c, 0x8643, 0x2071, 0x19e6, 0x713c, 0x81ff,
+	0x0904, 0xa456, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x743e,
+	0x11e0, 0x0036, 0x2019, 0x0002, 0x080c, 0xa6ac, 0x003e, 0x713c,
+	0x2160, 0x080c, 0xeb8e, 0x2009, 0x004a, 0x6220, 0x9296, 0x0009,
+	0x1130, 0x6114, 0x2148, 0xa87b, 0x0006, 0x2009, 0x004a, 0x080c,
+	0xafbe, 0x080c, 0x74ee, 0x0804, 0xa456, 0x080c, 0xa462, 0x0904,
+	0xa456, 0x6904, 0xd1f4, 0x0904, 0xa45d, 0x080c, 0x2d5e, 0x00c6,
+	0x703c, 0x9065, 0x090c, 0x0dd5, 0x6020, 0x00ce, 0x9086, 0x0006,
+	0x1528, 0x61c8, 0x60c4, 0x9105, 0x1508, 0x2009, 0x180c, 0x2104,
+	0xd0d4, 0x01e0, 0x6214, 0x9294, 0x1800, 0x1128, 0x6224, 0x9294,
+	0x0002, 0x1560, 0x0030, 0xc0d4, 0x200a, 0xd0cc, 0x0110, 0x080c,
+	0x2c90, 0x6014, 0x9084, 0xe7fd, 0x9085, 0x0010, 0x6016, 0x703c,
+	0x2060, 0x2009, 0x0049, 0x080c, 0xafbe, 0x00c0, 0x0036, 0x2019,
+	0x0001, 0x080c, 0xa6ac, 0x003e, 0x713c, 0x2160, 0x080c, 0xeb8e,
+	0x2009, 0x004a, 0x6220, 0x9296, 0x0009, 0x1130, 0x6114, 0x2148,
+	0xa87b, 0x0006, 0x2009, 0x004a, 0x080c, 0xafbe, 0x002e, 0x001e,
+	0x00ee, 0x00de, 0x00ce, 0x009e, 0x0005, 0xd1ec, 0x1904, 0xa40d,
+	0x0804, 0xa40f, 0x00d6, 0x00c6, 0x0096, 0x703c, 0x9065, 0x090c,
+	0x0dd5, 0x2001, 0x0306, 0x200c, 0x9184, 0x0030, 0x0904, 0xa50b,
+	0x9184, 0x0048, 0x9086, 0x0008, 0x1904, 0xa50b, 0x2009, 0x0206,
+	0x2104, 0x2009, 0x0203, 0x210c, 0x9106, 0x1904, 0xa50b, 0x2009,
+	0x022a, 0x2104, 0x2009, 0x022f, 0x210c, 0x9116, 0x9084, 0x03ff,
+	0x918c, 0x03ff, 0x9294, 0x0400, 0x0110, 0x9102, 0x0030, 0x2010,
+	0x2100, 0x9202, 0x2009, 0x0228, 0x9102, 0x9082, 0x0005, 0x0250,
+	0x2008, 0x2001, 0x013b, 0x2004, 0x8004, 0x8004, 0x8004, 0x9102,
+	0x1a04, 0xa50b, 0x2009, 0x1a80, 0x2104, 0x8000, 0x0208, 0x200a,
+	0x2069, 0x0100, 0x6914, 0x918c, 0x0184, 0x918d, 0x0010, 0x6916,
+	0x69c8, 0x2011, 0x0020, 0x68c8, 0x9106, 0x1570, 0x8211, 0x1dd8,
+	0x2001, 0x0306, 0x2003, 0x4800, 0x2001, 0x009a, 0x2003, 0x0004,
+	0x2001, 0x1a65, 0x2003, 0x0000, 0x2001, 0x1a6e, 0x2003, 0x0000,
+	0x6a88, 0x698c, 0x2200, 0x9105, 0x1120, 0x2c10, 0x080c, 0x1beb,
+	0x0040, 0x6014, 0x2048, 0xaa3a, 0xa936, 0x6ac4, 0x69c8, 0xa946,
+	0xaa4a, 0x0126, 0x00c6, 0x2091, 0x2400, 0x002e, 0x080c, 0x1c84,
+	0x190c, 0x0dd5, 0x012e, 0x0090, 0x2009, 0x1a81, 0x2104, 0x8000,
+	0x0208, 0x200a, 0x69c8, 0x2011, 0x0020, 0x8211, 0x1df0, 0x68c8,
+	0x9106, 0x1dc0, 0x69c4, 0x68c8, 0x9105, 0x0160, 0x6824, 0xd08c,
+	0x0110, 0x6827, 0x0002, 0x7048, 0xc085, 0x704a, 0x0079, 0x7048,
+	0xc084, 0x704a, 0x2009, 0x07d0, 0x080c, 0x863b, 0x9006, 0x009e,
+	0x00ce, 0x00de, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x0026, 0x00e6,
+	0x2071, 0x19e6, 0x7048, 0xd084, 0x01d8, 0x713c, 0x81ff, 0x01c0,
+	0x2071, 0x0100, 0x9188, 0x0008, 0x2114, 0x928e, 0x0006, 0x1138,
+	0x7014, 0x9084, 0x1984, 0x9085, 0x0012, 0x7016, 0x0048, 0x928e,
+	0x0009, 0x0db0, 0x7014, 0x9084, 0x1984, 0x9085, 0x0016, 0x7016,
+	0x00ee, 0x002e, 0x0005, 0x00b6, 0x00e6, 0x00d6, 0x00c6, 0x0066,
+	0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6010, 0x2058,
+	0xbca0, 0x2071, 0x19e6, 0x7018, 0x2058, 0x8bff, 0x0190, 0xb8a0,
+	0x9406, 0x0118, 0xb854, 0x2058, 0x0cc0, 0x6014, 0x0096, 0x2048,
+	0xac6c, 0xad70, 0xae78, 0x009e, 0x080c, 0x67cb, 0x0110, 0x9085,
+	0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce, 0x00de,
+	0x00ee, 0x00be, 0x0005, 0x080c, 0x9d39, 0x7003, 0x1200, 0x7838,
+	0x7012, 0x783c, 0x7016, 0x00c6, 0x7820, 0x9086, 0x0004, 0x1148,
+	0x7810, 0x9005, 0x0130, 0x00b6, 0x2058, 0xb810, 0xb914, 0x00be,
+	0x0020, 0x2061, 0x1800, 0x607c, 0x6180, 0x9084, 0x00ff, 0x700a,
+	0x710e, 0x00ce, 0x60c3, 0x002c, 0x0804, 0xa32a, 0x080c, 0x9d39,
+	0x7003, 0x0f00, 0x7808, 0xd09c, 0x0128, 0xb810, 0x9084, 0x00ff,
+	0x700a, 0xb814, 0x700e, 0x60c3, 0x0008, 0x0804, 0xa32a, 0x0156,
+	0x080c, 0x9d84, 0x7003, 0x0200, 0x080c, 0x8696, 0x20a9, 0x0006,
+	0x2011, 0xffec, 0x2019, 0xffed, 0x9ef0, 0x0002, 0x2305, 0x2072,
+	0x8e70, 0x2205, 0x2072, 0x8e70, 0x9398, 0x0002, 0x9290, 0x0002,
+	0x1f04, 0xa5a6, 0x60c3, 0x001c, 0x015e, 0x0804, 0xa32a, 0x0016,
+	0x0026, 0x080c, 0x9d60, 0x080c, 0x9d72, 0x9e80, 0x0004, 0x20e9,
+	0x0000, 0x20a0, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x009e, 0x7808, 0x9088,
+	0x0002, 0x21a8, 0x9192, 0x0010, 0x1250, 0x4003, 0x9080, 0x0004,
+	0x8003, 0x60c2, 0x080c, 0xa32a, 0x002e, 0x001e, 0x0005, 0x20a9,
+	0x0010, 0x4003, 0x080c, 0xabe9, 0x20a1, 0x0240, 0x22a8, 0x4003,
+	0x0c68, 0x080c, 0x9d39, 0x7003, 0x6200, 0x7808, 0x700e, 0x60c3,
+	0x0008, 0x0804, 0xa32a, 0x0016, 0x0026, 0x080c, 0x9d39, 0x20e9,
+	0x0000, 0x20a1, 0x024c, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048,
+	0xa860, 0x20e0, 0xa85c, 0x9080, 0x0023, 0x2098, 0x009e, 0x7808,
+	0x9088, 0x0002, 0x21a8, 0x4003, 0x8003, 0x60c2, 0x080c, 0xa32a,
+	0x002e, 0x001e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x19e6, 0x700c, 0x2060, 0x8cff, 0x0178, 0x080c,
+	0xce8e, 0x1110, 0x080c, 0xb905, 0x600c, 0x0006, 0x080c, 0xd0fa,
+	0x080c, 0xaf43, 0x080c, 0xa761, 0x00ce, 0x0c78, 0x2c00, 0x700e,
+	0x700a, 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005, 0x0126, 0x0156,
+	0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006,
+	0x2091, 0x8000, 0x2001, 0x180c, 0x200c, 0x918c, 0xe7ff, 0x2102,
+	0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x19e6, 0x7024, 0x2060,
+	0x8cff, 0x01f8, 0x080c, 0xa356, 0x6ac0, 0x68c3, 0x0000, 0x080c,
+	0x8636, 0x00c6, 0x2061, 0x0100, 0x080c, 0xad3a, 0x00ce, 0x20a9,
+	0x01f4, 0x0461, 0x2009, 0x0013, 0x080c, 0xafbe, 0x000e, 0x001e,
+	0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e,
+	0x0005, 0x2001, 0x1800, 0x2004, 0x9096, 0x0001, 0x0d78, 0x9096,
+	0x0004, 0x0d60, 0x080c, 0x8636, 0x6814, 0x9084, 0x0001, 0x0110,
+	0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011, 0x5f16,
+	0x080c, 0x85b0, 0x20a9, 0x01f4, 0x0009, 0x08c0, 0x6824, 0xd094,
+	0x0140, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c, 0x2d5e,
+	0x0090, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0xa68e,
+	0x7804, 0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e,
+	0x9006, 0x080c, 0x2d4e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000,
+	0x2001, 0x180c, 0x200c, 0x918c, 0xdbff, 0x2102, 0x2069, 0x0100,
+	0x2079, 0x0140, 0x2071, 0x19e6, 0x703c, 0x2060, 0x8cff, 0x0904,
+	0xa717, 0x9386, 0x0002, 0x1128, 0x6814, 0x9084, 0x0002, 0x0904,
+	0xa717, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109,
+	0x1df0, 0x69c6, 0x68cb, 0x0008, 0x080c, 0x8643, 0x080c, 0x2038,
+	0x2001, 0x0032, 0x6920, 0xd1bc, 0x0130, 0x8001, 0x1dd8, 0x692c,
+	0x918d, 0x0008, 0x692e, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0140,
+	0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c, 0x2d5e, 0x0090,
+	0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, 0x1f04, 0xa6ed, 0x7804,
+	0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006,
+	0x080c, 0x2d4e, 0x6827, 0x4000, 0x6824, 0x83ff, 0x1140, 0x2009,
+	0x0049, 0x6020, 0x9086, 0x0009, 0x0110, 0x080c, 0xafbe, 0x000e,
+	0x001e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e,
+	0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0x19e6,
+	0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000,
+	0x2069, 0x19e6, 0x6a32, 0x012e, 0x00de, 0x0005, 0x080c, 0x9efc,
+	0x7854, 0x7032, 0x7042, 0x7047, 0x1000, 0x00f8, 0x080c, 0x9efc,
+	0x7854, 0x7032, 0x7042, 0x7047, 0x4000, 0x00b8, 0x080c, 0x9efc,
+	0x7854, 0x7032, 0x7042, 0x7047, 0x2000, 0x0078, 0x080c, 0x9efc,
+	0x7854, 0x7032, 0x7042, 0x7047, 0x0400, 0x0038, 0x080c, 0x9efc,
+	0x7854, 0x7032, 0x7042, 0x7047, 0x0200, 0x60c3, 0x0020, 0x0804,
+	0xa32a, 0x00e6, 0x2071, 0x19e6, 0x7020, 0x9005, 0x0110, 0x8001,
+	0x7022, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076,
+	0x0066, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19e6, 0x7614,
+	0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0xa806, 0x8cff,
+	0x0904, 0xa806, 0x6020, 0x9086, 0x0006, 0x1904, 0xa801, 0x88ff,
+	0x0138, 0x2800, 0x9c06, 0x1904, 0xa801, 0x2039, 0x0000, 0x0050,
+	0x6010, 0x9b06, 0x1904, 0xa801, 0x85ff, 0x0120, 0x6054, 0x9106,
+	0x1904, 0xa801, 0x7024, 0x9c06, 0x15b0, 0x2069, 0x0100, 0x68c0,
+	0x9005, 0x1160, 0x6824, 0xd084, 0x0148, 0x6827, 0x0001, 0x080c,
+	0x8636, 0x080c, 0xa88b, 0x7027, 0x0000, 0x0428, 0x080c, 0x8636,
+	0x6820, 0xd0b4, 0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3,
+	0x0000, 0x080c, 0xa88b, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140,
+	0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e,
+	0x9006, 0x080c, 0x2d4e, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110,
+	0x6827, 0x0001, 0x003e, 0x7014, 0x9c36, 0x1110, 0x660c, 0x7616,
+	0x7010, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012,
+	0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1168, 0x600f, 0x0000, 0x6014,
+	0x0096, 0x2048, 0x080c, 0xcc84, 0x0110, 0x080c, 0xe6dd, 0x009e,
+	0x080c, 0xaf74, 0x080c, 0xa761, 0x88ff, 0x1190, 0x00ce, 0x0804,
+	0xa77c, 0x2c78, 0x600c, 0x2060, 0x0804, 0xa77c, 0x9006, 0x012e,
+	0x000e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005,
+	0x601b, 0x0000, 0x00ce, 0x98c5, 0x0001, 0x0c88, 0x00f6, 0x00e6,
+	0x00d6, 0x0096, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x19e6, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0904,
+	0xa87a, 0x6020, 0x9086, 0x0006, 0x1904, 0xa875, 0x87ff, 0x0128,
+	0x2700, 0x9c06, 0x1904, 0xa875, 0x0040, 0x6010, 0x9b06, 0x15e8,
+	0x85ff, 0x0118, 0x6054, 0x9106, 0x15c0, 0x703c, 0x9c06, 0x1168,
+	0x0036, 0x2019, 0x0001, 0x080c, 0xa6ac, 0x7033, 0x0000, 0x9006,
+	0x703e, 0x7042, 0x7046, 0x704a, 0x003e, 0x7038, 0x9c36, 0x1110,
+	0x660c, 0x763a, 0x7034, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118,
+	0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00,
+	0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6014,
+	0x2048, 0x080c, 0xcc84, 0x0110, 0x080c, 0xe6dd, 0x080c, 0xaf74,
+	0x87ff, 0x1198, 0x00ce, 0x0804, 0xa826, 0x2c78, 0x600c, 0x2060,
+	0x0804, 0xa826, 0x9006, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce,
+	0x009e, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000, 0x00ce,
+	0x97bd, 0x0001, 0x0c80, 0x00e6, 0x2071, 0x19e6, 0x2001, 0x1800,
+	0x2004, 0x9086, 0x0002, 0x1118, 0x7007, 0x0005, 0x0010, 0x7007,
+	0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026,
+	0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19e6, 0x2c10, 0x7638,
+	0x2660, 0x2678, 0x8cff, 0x0540, 0x2200, 0x9c06, 0x1508, 0x7038,
+	0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140, 0x2c00,
+	0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x6004, 0x9086, 0x0040, 0x090c, 0x9657, 0x9085, 0x0001, 0x0020,
+	0x2c78, 0x600c, 0x2060, 0x08b0, 0x012e, 0x000e, 0x002e, 0x006e,
+	0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0096, 0x00f6, 0x00e6, 0x00d6,
+	0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x19e6, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0904, 0xa971, 0x6010,
+	0x00b6, 0x2058, 0xb8a0, 0x00be, 0x9206, 0x1904, 0xa96c, 0x7024,
+	0x9c06, 0x1520, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904, 0xa943,
+	0x080c, 0xa356, 0x68c3, 0x0000, 0x080c, 0xa88b, 0x7027, 0x0000,
+	0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001,
+	0x0100, 0x080c, 0x2d4e, 0x9006, 0x080c, 0x2d4e, 0x2069, 0x0100,
+	0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c, 0x9c36,
+	0x1110, 0x660c, 0x760e, 0x7008, 0x9c36, 0x1140, 0x2c00, 0x9f36,
+	0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c, 0x0066,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x080c, 0xce7d, 0x1180, 0x080c, 0x3247, 0x080c, 0xce8e, 0x1518,
+	0x080c, 0xb905, 0x0400, 0x080c, 0xa88b, 0x6824, 0xd084, 0x09b0,
+	0x6827, 0x0001, 0x0898, 0x080c, 0xce8e, 0x1118, 0x080c, 0xb905,
+	0x0090, 0x6014, 0x2048, 0x080c, 0xcc84, 0x0168, 0x6020, 0x9086,
+	0x0003, 0x1508, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0x6d0b, 0x080c, 0xce71, 0x080c, 0xd0fa, 0x080c, 0xaf74, 0x080c,
+	0xa761, 0x00ce, 0x0804, 0xa8ec, 0x2c78, 0x600c, 0x2060, 0x0804,
+	0xa8ec, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x009e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1d20, 0x080c,
+	0xe6dd, 0x0c08, 0x00d6, 0x080c, 0x9d84, 0x7003, 0x0200, 0x7007,
+	0x0014, 0x60c3, 0x0014, 0x20e1, 0x0001, 0x2099, 0x1988, 0x20e9,
+	0x0000, 0x20a1, 0x0250, 0x20a9, 0x0004, 0x4003, 0x7023, 0x0004,
+	0x7027, 0x7878, 0x080c, 0xa32a, 0x00de, 0x0005, 0x080c, 0x9d84,
+	0x700b, 0x0800, 0x7814, 0x9084, 0xff00, 0x700e, 0x7814, 0x9084,
+	0x00ff, 0x7022, 0x782c, 0x7026, 0x7858, 0x9084, 0x00ff, 0x9085,
+	0x0200, 0x7002, 0x7858, 0x9084, 0xff00, 0x8007, 0x7006, 0x60c2,
+	0x0804, 0xa32a, 0x00b6, 0x00d6, 0x0016, 0x00d6, 0x2f68, 0x2009,
+	0x0035, 0x080c, 0xd300, 0x00de, 0x1904, 0xaa1f, 0x080c, 0x9d39,
+	0x7003, 0x1300, 0x782c, 0x080c, 0xab25, 0x2068, 0x6820, 0x9086,
+	0x0003, 0x0560, 0x7810, 0x2058, 0xbaa0, 0x080c, 0xaead, 0x11d8,
+	0x9286, 0x007e, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffe, 0x0498,
+	0x9286, 0x007f, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffd, 0x0458,
+	0x9284, 0xff80, 0x0180, 0x9286, 0x0080, 0x1128, 0x700b, 0x00ff,
+	0x700f, 0xfffc, 0x0400, 0x92d8, 0x1000, 0x2b5c, 0xb810, 0x700a,
+	0xb814, 0x700e, 0x00c0, 0x6098, 0x700e, 0x00a8, 0x080c, 0xaead,
+	0x1130, 0x7810, 0x2058, 0xb8a0, 0x9082, 0x007e, 0x0250, 0x00d6,
+	0x2069, 0x181f, 0x2d04, 0x700a, 0x8d68, 0x2d04, 0x700e, 0x00de,
+	0x0010, 0x6034, 0x700e, 0x7838, 0x7012, 0x783c, 0x7016, 0x60c3,
+	0x000c, 0x001e, 0x00de, 0x080c, 0xa32a, 0x00be, 0x0005, 0x781b,
+	0x0001, 0x7803, 0x0006, 0x001e, 0x00de, 0x00be, 0x0005, 0x792c,
+	0x9180, 0x0008, 0x200c, 0x9186, 0x0006, 0x01c0, 0x9186, 0x0003,
+	0x0904, 0xaa9a, 0x9186, 0x0005, 0x0904, 0xaa82, 0x9186, 0x0004,
+	0x05d8, 0x9186, 0x0008, 0x0904, 0xaa8b, 0x7807, 0x0037, 0x782f,
+	0x0003, 0x7817, 0x1700, 0x080c, 0xab02, 0x0005, 0x080c, 0xaac3,
+	0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x6800, 0x0002,
+	0xaa63, 0xaa6e, 0xaa65, 0xaa6e, 0xaa6a, 0xaa63, 0xaa63, 0xaa6e,
+	0xaa6e, 0xaa6e, 0xaa6e, 0xaa63, 0xaa63, 0xaa63, 0xaa63, 0xaa63,
+	0xaa6e, 0xaa63, 0xaa6e, 0x080c, 0x0dd5, 0x6824, 0xd0e4, 0x0110,
+	0xd0cc, 0x0110, 0x900e, 0x0010, 0x2009, 0x2000, 0x682c, 0x7022,
+	0x6830, 0x7026, 0x0804, 0xaabc, 0x080c, 0xaac3, 0x00d6, 0x0026,
+	0x792c, 0x2168, 0x2009, 0x4000, 0x6a00, 0x9286, 0x0002, 0x1108,
+	0x900e, 0x04d0, 0x080c, 0xaac3, 0x00d6, 0x0026, 0x792c, 0x2168,
+	0x2009, 0x4000, 0x0488, 0x04b9, 0x00d6, 0x0026, 0x792c, 0x2168,
+	0x2009, 0x4000, 0x9286, 0x0005, 0x0118, 0x9286, 0x0002, 0x1108,
+	0x900e, 0x0410, 0x0441, 0x00d6, 0x0026, 0x792c, 0x2168, 0x6814,
+	0x6924, 0xc185, 0x6926, 0x0096, 0x2048, 0xa9ac, 0xa834, 0x9112,
+	0xa9b0, 0xa838, 0x009e, 0x9103, 0x7022, 0x7226, 0x792c, 0x9180,
+	0x0000, 0x2004, 0x908e, 0x0002, 0x0130, 0x908e, 0x0004, 0x0118,
+	0x2009, 0x4000, 0x0008, 0x900e, 0x712a, 0x60c3, 0x0018, 0x002e,
+	0x00de, 0x0804, 0xa32a, 0x00b6, 0x0036, 0x0046, 0x0056, 0x0066,
+	0x080c, 0x9d84, 0x9006, 0x7003, 0x0200, 0x7938, 0x710a, 0x793c,
+	0x710e, 0x7810, 0x2058, 0xb8a0, 0x080c, 0xaead, 0x1118, 0x9092,
+	0x007e, 0x0268, 0x00d6, 0x2069, 0x181f, 0x2d2c, 0x8d68, 0x2d34,
+	0x90d8, 0x1000, 0x2b5c, 0xbb10, 0xbc14, 0x00de, 0x0028, 0x901e,
+	0x6498, 0x2029, 0x0000, 0x6634, 0x782c, 0x9080, 0x0008, 0x2004,
+	0x9086, 0x0003, 0x1128, 0x7512, 0x7616, 0x731a, 0x741e, 0x0020,
+	0x7312, 0x7416, 0x751a, 0x761e, 0x006e, 0x005e, 0x004e, 0x003e,
+	0x00be, 0x0005, 0x080c, 0x9d84, 0x7003, 0x0100, 0x782c, 0x700a,
+	0x7814, 0x700e, 0x700e, 0x60c3, 0x0008, 0x0804, 0xa32a, 0x080c,
+	0x9d30, 0x7003, 0x1400, 0x7838, 0x700a, 0x0079, 0x783c, 0x700e,
+	0x782c, 0x7012, 0x7830, 0x7016, 0x7834, 0x9084, 0x00ff, 0x8007,
+	0x701a, 0x60c3, 0x0010, 0x0804, 0xa32a, 0x00e6, 0x2071, 0x0240,
+	0x0006, 0x00f6, 0x2078, 0x7810, 0x00b6, 0x2058, 0xb8cc, 0xd084,
+	0x0120, 0x7844, 0x702a, 0x7848, 0x702e, 0x00be, 0x00fe, 0x000e,
+	0x00ee, 0x0005, 0x080c, 0x9d7b, 0x7003, 0x0100, 0x782c, 0x700a,
+	0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0xa32a, 0x0021, 0x60c3,
+	0x0000, 0x0804, 0xa32a, 0x00d6, 0x080c, 0xabfe, 0xb810, 0x9085,
+	0x0300, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x687c, 0x700a,
+	0x6880, 0x700e, 0x7013, 0x0819, 0x080c, 0xa318, 0x721a, 0x2f10,
+	0x7222, 0x7a08, 0x7226, 0x2071, 0x024c, 0x00de, 0x0005, 0x00a9,
+	0x7914, 0x712a, 0x60c3, 0x0000, 0x60a7, 0x9575, 0x0026, 0x080c,
+	0x2be3, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e,
+	0x080c, 0xa34d, 0x080c, 0x862d, 0x0005, 0x0036, 0x0096, 0x00d6,
+	0x00e6, 0x7858, 0x2048, 0xaa7c, 0x9296, 0x00c0, 0x9294, 0xfffd,
+	0xaa7e, 0xaa80, 0x9294, 0x0300, 0xaa82, 0xa96c, 0x9194, 0x00ff,
+	0xab74, 0x9384, 0x00ff, 0x908d, 0xc200, 0xa96e, 0x9384, 0xff00,
+	0x9215, 0xaa76, 0xa870, 0xaa78, 0xa87a, 0xaa72, 0x00d6, 0x2069,
+	0x0200, 0x080c, 0xabfe, 0x00de, 0x20e9, 0x0000, 0x20a1, 0x0240,
+	0x20a9, 0x000a, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098,
+	0x4003, 0x60a3, 0x0035, 0xaa68, 0x9294, 0x7000, 0x9286, 0x3000,
+	0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, 0x009e, 0x003e, 0x0005,
+	0x900e, 0x7814, 0x0096, 0x2048, 0xa87c, 0xd0fc, 0x01c0, 0x9084,
+	0x0003, 0x11a8, 0x2001, 0x180c, 0x2004, 0xd0bc, 0x0180, 0x7824,
+	0xd0cc, 0x1168, 0xd0c4, 0x1158, 0xa8a8, 0x9005, 0x1140, 0x2001,
+	0x180c, 0x200c, 0xc1d5, 0x2102, 0x2009, 0x19b1, 0x210c, 0x009e,
+	0x918d, 0x0092, 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, 0x6116,
+	0x0005, 0x2009, 0x0009, 0x00a0, 0x2009, 0x000a, 0x0088, 0x2009,
+	0x000b, 0x0070, 0x2009, 0x000c, 0x0058, 0x2009, 0x000d, 0x0040,
+	0x2009, 0x000e, 0x0028, 0x2009, 0x000f, 0x0010, 0x2009, 0x0008,
+	0x6912, 0x0005, 0x080c, 0x9d39, 0x0016, 0x0026, 0x0096, 0x00d6,
+	0x7814, 0x2048, 0x7013, 0x0138, 0x2001, 0x1837, 0x2004, 0x9084,
+	0x0028, 0x1138, 0x2001, 0x197b, 0x2004, 0x9086, 0xaaaa, 0x1904,
+	0xaca3, 0x7003, 0x5400, 0x00c6, 0x2061, 0x1800, 0x607c, 0x9084,
+	0x00ff, 0xa998, 0x810f, 0x918c, 0xff00, 0x9105, 0x700a, 0x6080,
+	0x700e, 0xa998, 0x918c, 0xff00, 0x7112, 0x20a9, 0x0004, 0x2009,
+	0x1805, 0x2e10, 0x9290, 0x0006, 0x2104, 0x2012, 0x8108, 0x8210,
+	0x1f04, 0xac34, 0x20a9, 0x0004, 0x2009, 0x1801, 0x2104, 0x2012,
+	0x8108, 0x8210, 0x1f04, 0xac3e, 0xa860, 0x20e0, 0xa85c, 0x9080,
+	0x0029, 0x2098, 0x2009, 0x0006, 0x20a9, 0x0001, 0x4002, 0x8007,
+	0x2012, 0x8210, 0x8109, 0x1dc0, 0x00d6, 0x2069, 0x0200, 0x080c,
+	0xabe9, 0x00de, 0x2071, 0x0240, 0x2011, 0x0240, 0x2009, 0x0002,
+	0x20a9, 0x0001, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0,
+	0x2009, 0x0008, 0x20a9, 0x0001, 0x4002, 0x8007, 0x2012, 0x8210,
+	0x8109, 0x1dc0, 0xa85c, 0x9080, 0x0031, 0x2098, 0x2009, 0x0008,
+	0x20a9, 0x0001, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0,
+	0x00ce, 0x60c3, 0x004c, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x2001,
+	0x1837, 0x2004, 0x9084, 0x0028, 0x1168, 0x080c, 0x743e, 0x0150,
+	0x6028, 0xc0bd, 0x602a, 0x6014, 0x9084, 0x1804, 0x9085, 0x0029,
+	0x6016, 0x0010, 0x080c, 0xa32a, 0x080c, 0x862d, 0x00de, 0x009e,
+	0x002e, 0x001e, 0x0005, 0x00e6, 0x2071, 0x0240, 0x2001, 0x2200,
+	0x9085, 0x00ff, 0x7002, 0x7007, 0xffff, 0x2071, 0x0100, 0x709b,
+	0x00ff, 0x00ee, 0x0804, 0xac19, 0x080c, 0x9d39, 0x0016, 0x0026,
+	0x0096, 0x00d6, 0x7814, 0x2048, 0x7013, 0x0138, 0x7003, 0x5500,
+	0x00c6, 0xa89c, 0x9084, 0x00ff, 0xa998, 0x810f, 0x918c, 0xff00,
+	0x9105, 0x700a, 0xa99c, 0x918c, 0xff00, 0xa8a0, 0x9084, 0x00ff,
+	0x9105, 0x700e, 0xa998, 0x918c, 0xff00, 0x2061, 0x1800, 0x607c,
+	0x9084, 0x00ff, 0x910d, 0x7112, 0x6180, 0x7116, 0x2009, 0x0008,
+	0xa860, 0x20e0, 0xa85c, 0x9080, 0x0029, 0x2098, 0x2e10, 0x9290,
+	0x0006, 0x20a9, 0x0001, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109,
+	0x1dc0, 0x20a9, 0x0004, 0x2009, 0x1805, 0x2104, 0x2012, 0x8108,
+	0x8210, 0x1f04, 0xacf5, 0x20a9, 0x0002, 0x2009, 0x1801, 0x2104,
+	0x2012, 0x8108, 0x8210, 0x1f04, 0xacff, 0x00d6, 0x0016, 0x2069,
+	0x0200, 0x080c, 0xabe9, 0x001e, 0x00de, 0x2071, 0x0240, 0x20a9,
+	0x0002, 0x2009, 0x1803, 0x2011, 0x0240, 0x2104, 0x2012, 0x8108,
+	0x8210, 0x1f04, 0xad15, 0x2009, 0x0008, 0x4002, 0x8007, 0x2012,
+	0x8210, 0x8109, 0x1dd0, 0x9006, 0x20a9, 0x0008, 0x2012, 0x8210,
+	0x1f04, 0xad26, 0x00ce, 0x60c3, 0x004c, 0x60a3, 0x0056, 0x60a7,
+	0x9575, 0x080c, 0xa32a, 0x080c, 0x862d, 0x00de, 0x009e, 0x002e,
+	0x001e, 0x0005, 0x00d6, 0x9290, 0x0018, 0x8214, 0x20e9, 0x0000,
+	0x2069, 0x0200, 0x6813, 0x0000, 0x22a8, 0x9284, 0x00e0, 0x0128,
+	0x20a9, 0x0020, 0x9292, 0x0020, 0x0008, 0x9016, 0x20a1, 0x0240,
+	0x9006, 0x4004, 0x82ff, 0x0120, 0x6810, 0x8000, 0x6812, 0x0c60,
+	0x00de, 0x0005, 0x00d6, 0x0096, 0x6014, 0x2048, 0xa878, 0x6056,
+	0x9006, 0xa836, 0xa83a, 0xa99c, 0xa946, 0xa84a, 0x6023, 0x0003,
+	0x6007, 0x0040, 0x6003, 0x0003, 0x600b, 0xffff, 0xa817, 0x0001,
+	0xa842, 0xa83e, 0x2900, 0xa85a, 0xa813, 0x20cc, 0x080c, 0x9216,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x9891, 0x012e, 0x009e, 0x00de,
+	0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x00a6, 0x0096, 0x0066,
+	0x0126, 0x2091, 0x8000, 0x2071, 0x19e6, 0x760c, 0x2660, 0x2678,
+	0x8cff, 0x0904, 0xae0d, 0x7024, 0x9c06, 0x1520, 0x2069, 0x0100,
+	0x68c0, 0x9005, 0x0904, 0xaddf, 0x080c, 0xa356, 0x68c3, 0x0000,
+	0x080c, 0xa88b, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04,
+	0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2d4e, 0x9006,
+	0x080c, 0x2d4e, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827,
+	0x0001, 0x003e, 0x700c, 0x9c36, 0x1110, 0x660c, 0x760e, 0x7008,
+	0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x700a, 0x0010,
+	0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e,
+	0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0xce7d, 0x1180, 0x080c,
+	0x3247, 0x080c, 0xce8e, 0x1518, 0x080c, 0xb905, 0x0400, 0x080c,
+	0xa88b, 0x6824, 0xd084, 0x09b0, 0x6827, 0x0001, 0x0898, 0x080c,
+	0xce8e, 0x1118, 0x080c, 0xb905, 0x0090, 0x6014, 0x2048, 0x080c,
+	0xcc84, 0x0168, 0x6020, 0x9086, 0x0003, 0x1520, 0xa867, 0x0103,
+	0xab7a, 0xa877, 0x0000, 0x080c, 0x6d17, 0x080c, 0xce71, 0x080c,
+	0xd0fa, 0x080c, 0xaf74, 0x080c, 0xa761, 0x00ce, 0x0804, 0xad90,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0xad90, 0x700f, 0x0000, 0x700b,
+	0x0000, 0x012e, 0x006e, 0x009e, 0x00ae, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1d08, 0x080c, 0xe6dd,
+	0x08f0, 0x00d6, 0x0156, 0x080c, 0x9d84, 0x7a14, 0x82ff, 0x0138,
+	0x7003, 0x0100, 0x700b, 0x0003, 0x60c3, 0x0008, 0x0490, 0x7003,
+	0x0200, 0x7007, 0x0000, 0x2069, 0x1800, 0x901e, 0x6800, 0x9086,
+	0x0004, 0x1110, 0xc38d, 0x0060, 0x080c, 0x743e, 0x1110, 0xc3ad,
+	0x0008, 0xc3a5, 0x6adc, 0xd29c, 0x1110, 0xd2ac, 0x0108, 0xc39d,
+	0x730e, 0x080c, 0x8696, 0x20a9, 0x0006, 0x2011, 0xffec, 0x2019,
+	0xffed, 0x2071, 0x0250, 0x2305, 0x2072, 0x8e70, 0x2205, 0x2072,
+	0x8e70, 0x9398, 0x0002, 0x9290, 0x0002, 0x1f04, 0xae53, 0x60c3,
+	0x0020, 0x080c, 0xa32a, 0x015e, 0x00de, 0x0005, 0x0156, 0x080c,
+	0x9d84, 0x7a14, 0x82ff, 0x0168, 0x9286, 0xffff, 0x0118, 0x9282,
+	0x000e, 0x1238, 0x7003, 0x0100, 0x700b, 0x0003, 0x60c3, 0x0008,
+	0x0488, 0x7003, 0x0200, 0x7007, 0x001c, 0x700f, 0x0001, 0x2011,
+	0x19bc, 0x2204, 0x8007, 0x701a, 0x8210, 0x2204, 0x8007, 0x701e,
+	0x0421, 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248, 0x2001, 0x181f,
+	0x2004, 0x7022, 0x2001, 0x1820, 0x2004, 0x7026, 0x0030, 0x2001,
+	0x1818, 0x2004, 0x9084, 0x00ff, 0x7026, 0x20a9, 0x0004, 0x20e1,
+	0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003,
+	0x60c3, 0x001c, 0x015e, 0x0804, 0xa32a, 0x0006, 0x2001, 0x1837,
+	0x2004, 0xd0ac, 0x000e, 0x0005, 0x2011, 0x0003, 0x080c, 0xa722,
+	0x2011, 0x0002, 0x080c, 0xa72c, 0x080c, 0xa636, 0x0036, 0x901e,
+	0x080c, 0xa6ac, 0x003e, 0x0005, 0x080c, 0x337d, 0x0188, 0x0016,
+	0x00b6, 0x00c6, 0x7010, 0x9085, 0x0020, 0x7012, 0x2009, 0x007e,
+	0x080c, 0x6699, 0xb85c, 0xc0ac, 0xb85e, 0x00ce, 0x00be, 0x001e,
+	0x0005, 0x2071, 0x188d, 0x7000, 0x9005, 0x0140, 0x2001, 0x0976,
+	0x2071, 0x1800, 0x7076, 0x707a, 0x706b, 0xffe0, 0x2071, 0x1800,
+	0x7074, 0x7056, 0x705b, 0x1cd0, 0x0005, 0x00e6, 0x0126, 0x2071,
+	0x1800, 0x2091, 0x8000, 0x7554, 0x9582, 0x0010, 0x0608, 0x7058,
+	0x2060, 0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7068,
+	0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0, 0x0c98, 0x6003, 0x0008,
+	0x8529, 0x7556, 0x9ca8, 0x0018, 0x7068, 0x9502, 0x1230, 0x755a,
+	0x9085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x705b, 0x1cd0, 0x0cc0,
+	0x9006, 0x0cc0, 0x00e6, 0x2071, 0x1800, 0x7554, 0x9582, 0x0010,
+	0x0600, 0x7058, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0,
+	0x0018, 0x7068, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0, 0x0c98,
+	0x6003, 0x0008, 0x8529, 0x7556, 0x9ca8, 0x0018, 0x7068, 0x9502,
+	0x1228, 0x755a, 0x9085, 0x0001, 0x00ee, 0x0005, 0x705b, 0x1cd0,
+	0x0cc8, 0x9006, 0x0cc8, 0x9c82, 0x1cd0, 0x0a0c, 0x0dd5, 0x2001,
+	0x181a, 0x2004, 0x9c02, 0x1a0c, 0x0dd5, 0x9006, 0x6006, 0x600a,
+	0x600e, 0x6016, 0x601a, 0x6012, 0x6023, 0x0000, 0x6003, 0x0000,
+	0x601e, 0x6056, 0x605a, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036,
+	0x603a, 0x603e, 0x6042, 0x602a, 0x2061, 0x1800, 0x6054, 0x8000,
+	0x6056, 0x9086, 0x0001, 0x0108, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x9763, 0x012e, 0x0cc0, 0x0006, 0x6000, 0x9086, 0x0000,
+	0x01b0, 0x601c, 0xd084, 0x190c, 0x1aa1, 0x6017, 0x0000, 0x6023,
+	0x0007, 0x2001, 0x1985, 0x2004, 0x0006, 0x9082, 0x0051, 0x000e,
+	0x0208, 0x8004, 0x601a, 0x080c, 0xe997, 0x6043, 0x0000, 0x000e,
+	0x0005, 0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, 0x8000, 0x7554,
+	0x9582, 0x0001, 0x0608, 0x7058, 0x2060, 0x6000, 0x9086, 0x0000,
+	0x0148, 0x9ce0, 0x0018, 0x7068, 0x9c02, 0x1208, 0x0cb0, 0x2061,
+	0x1cd0, 0x0c98, 0x6003, 0x0008, 0x8529, 0x7556, 0x9ca8, 0x0018,
+	0x7068, 0x9502, 0x1230, 0x755a, 0x9085, 0x0001, 0x012e, 0x00ee,
+	0x0005, 0x705b, 0x1cd0, 0x0cc0, 0x9006, 0x0cc0, 0x6020, 0x9084,
+	0x000f, 0x0002, 0xafd1, 0xafda, 0xaff5, 0xb010, 0xd3ae, 0xd3cb,
+	0xd3e6, 0xafd1, 0xafda, 0x8e43, 0xb02c, 0xafd1, 0xafd1, 0xafd1,
+	0xafd1, 0x9186, 0x0013, 0x1128, 0x080c, 0x9657, 0x080c, 0x9763,
+	0x0005, 0x0005, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0dd5,
+	0x0013, 0x006e, 0x0005, 0xaff3, 0xb76f, 0xb94c, 0xaff3, 0xb9e2,
+	0xb30f, 0xaff3, 0xaff3, 0xb6f1, 0xbf49, 0xaff3, 0xaff3, 0xaff3,
+	0xaff3, 0xaff3, 0xaff3, 0x080c, 0x0dd5, 0x0066, 0x6000, 0x90b2,
+	0x0016, 0x1a0c, 0x0dd5, 0x0013, 0x006e, 0x0005, 0xb00e, 0xc630,
+	0xb00e, 0xb00e, 0xb00e, 0xb00e, 0xb00e, 0xb00e, 0xc5c7, 0xc7b2,
+	0xb00e, 0xc671, 0xc6f0, 0xc671, 0xc6f0, 0xb00e, 0x080c, 0x0dd5,
+	0x6000, 0x9082, 0x0016, 0x1a0c, 0x0dd5, 0x6000, 0x0002, 0xb02a,
+	0xbf90, 0xc075, 0xc1a5, 0xc354, 0xb02a, 0xb02a, 0xb02a, 0xbf64,
+	0xc553, 0xc556, 0xb02a, 0xb02a, 0xb02a, 0xb02a, 0xc585, 0xb02a,
+	0xb02a, 0xb02a, 0x080c, 0x0dd5, 0x0066, 0x6000, 0x90b2, 0x0016,
+	0x1a0c, 0x0dd5, 0x0013, 0x006e, 0x0005, 0xb045, 0xb045, 0xb088,
+	0xb127, 0xb1bc, 0xb045, 0xb045, 0xb045, 0xb047, 0xb045, 0xb045,
+	0xb045, 0xb045, 0xb045, 0xb045, 0xb045, 0x080c, 0x0dd5, 0x9186,
+	0x004c, 0x0588, 0x9186, 0x0003, 0x190c, 0x0dd5, 0x0096, 0x601c,
+	0xc0ed, 0x601e, 0x6003, 0x0003, 0x6106, 0x6014, 0x2048, 0xa87c,
+	0x9084, 0xa000, 0xc0b5, 0xa87e, 0xa8ac, 0xa846, 0xa8b0, 0xa84a,
+	0x9006, 0xa836, 0xa83a, 0xa884, 0x9092, 0x199a, 0x0210, 0x2001,
+	0x1999, 0x8003, 0x8013, 0x8213, 0x9210, 0x621a, 0x009e, 0x2c10,
+	0x080c, 0x1beb, 0x080c, 0x9216, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x9891, 0x012e, 0x0005, 0x6010, 0x00b6, 0x2058, 0xbca0, 0x00be,
+	0x2c00, 0x080c, 0xb1de, 0x080c, 0xd3a0, 0x6003, 0x0007, 0x0005,
+	0x00d6, 0x0096, 0x00f6, 0x2079, 0x1800, 0x7a90, 0x6014, 0x2048,
+	0xa87c, 0xd0ec, 0x1110, 0x9290, 0x0018, 0xac78, 0xc4fc, 0x0046,
+	0xa8e0, 0x9005, 0x1140, 0xa8dc, 0x921a, 0x0140, 0x0220, 0xa87b,
+	0x0007, 0x2010, 0x0028, 0xa87b, 0x0015, 0x0010, 0xa87b, 0x0000,
+	0x8214, 0xa883, 0x0000, 0xaa02, 0x0006, 0x0016, 0x0026, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x2400, 0x9005, 0x1108, 0x009a, 0x2100,
+	0x9086, 0x0015, 0x1118, 0x2001, 0x0001, 0x0038, 0x2100, 0x9086,
+	0x0016, 0x0118, 0x2001, 0x0001, 0x002a, 0x94a4, 0x0007, 0x8423,
+	0x9405, 0x0002, 0xb0ef, 0xb0ef, 0xb0ea, 0xb0ed, 0xb0ef, 0xb0e7,
+	0xb0da, 0xb0da, 0xb0da, 0xb0da, 0xb0da, 0xb0da, 0xb0da, 0xb0da,
+	0xb0da, 0xb0da, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e, 0x001e,
+	0x000e, 0x004e, 0x00fe, 0x009e, 0x00de, 0x080c, 0x0dd5, 0x080c,
+	0xbba1, 0x0028, 0x080c, 0xbc86, 0x0010, 0x080c, 0xbd7c, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x002e, 0x001e, 0x2c00, 0xa896, 0x000e,
+	0x080c, 0xb29c, 0x0530, 0xa804, 0xa80e, 0x00a6, 0x2050, 0xb100,
+	0x00ae, 0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x9080, 0x0002, 0xaacc, 0xabd0, 0xacd4, 0xadd8, 0x2031, 0x0000,
+	0x2041, 0x125d, 0x080c, 0xb45d, 0x0160, 0x000e, 0x9005, 0x0120,
+	0x00fe, 0x009e, 0x00de, 0x0005, 0x00fe, 0x009e, 0x00de, 0x0804,
+	0xaf43, 0x2001, 0x002c, 0x900e, 0x080c, 0xb302, 0x0c70, 0x91b6,
+	0x0015, 0x0170, 0x91b6, 0x0016, 0x0158, 0x91b2, 0x0047, 0x0a0c,
+	0x0dd5, 0x91b2, 0x0050, 0x1a0c, 0x0dd5, 0x9182, 0x0047, 0x00ca,
+	0x2001, 0x0109, 0x2004, 0xd08c, 0x0198, 0x0126, 0x2091, 0x2800,
+	0x0006, 0x0016, 0x0026, 0x080c, 0x9163, 0x002e, 0x001e, 0x000e,
+	0x012e, 0xa001, 0x6000, 0x9086, 0x0002, 0x1110, 0x0804, 0xb088,
+	0x0005, 0xb15a, 0xb15a, 0xb15c, 0xb192, 0xb15a, 0xb15a, 0xb15a,
+	0xb15a, 0xb1a5, 0x080c, 0x0dd5, 0x00d6, 0x0016, 0x0096, 0x080c,
+	0x9713, 0x080c, 0x9891, 0x6003, 0x0004, 0x6114, 0x2148, 0xa87c,
+	0xd0fc, 0x01c0, 0xa878, 0xc0fc, 0x9005, 0x1158, 0xa894, 0x9005,
+	0x0140, 0x2001, 0x0000, 0x900e, 0x080c, 0xb302, 0x080c, 0xaf43,
+	0x00a8, 0x6003, 0x0002, 0xa8a4, 0xa9a8, 0x9105, 0x1178, 0xa8ae,
+	0xa8b2, 0x0c78, 0xa87f, 0x0020, 0xa88c, 0xa88a, 0xa8a4, 0xa8ae,
+	0xa8a8, 0xa8b2, 0xa8c7, 0x0000, 0xa8cb, 0x0000, 0x009e, 0x001e,
+	0x00de, 0x0005, 0x080c, 0x9713, 0x00d6, 0x0096, 0x6114, 0x2148,
+	0x080c, 0xcc86, 0x0120, 0xa87b, 0x0006, 0x080c, 0x6d17, 0x009e,
+	0x00de, 0x080c, 0xaf43, 0x0804, 0x9891, 0x080c, 0x9713, 0x080c,
+	0x321e, 0x080c, 0xd39d, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xcc86, 0x0120, 0xa87b, 0x0029, 0x080c, 0x6d17, 0x009e, 0x00de,
+	0x080c, 0xaf43, 0x0804, 0x9891, 0x9182, 0x0047, 0x0002, 0xb1cc,
+	0xb1ce, 0xb1cc, 0xb1cc, 0xb1cc, 0xb1cc, 0xb1cc, 0xb1cc, 0xb1cc,
+	0xb1cc, 0xb1cc, 0xb1cc, 0xb1ce, 0x080c, 0x0dd5, 0x00d6, 0x0096,
+	0x601f, 0x0000, 0x6114, 0x2148, 0xa87b, 0x0000, 0xa883, 0x0000,
+	0x080c, 0x6d17, 0x009e, 0x00de, 0x0804, 0xaf43, 0x0026, 0x0036,
+	0x0056, 0x0066, 0x0096, 0x00a6, 0x00f6, 0x0006, 0x080c, 0x0fff,
+	0x000e, 0x090c, 0x0dd5, 0xa960, 0x21e8, 0xa95c, 0x9188, 0x0019,
+	0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xa87a, 0x2079, 0x1800,
+	0x7990, 0x9188, 0x0018, 0x918c, 0x0fff, 0xa972, 0xac76, 0x2950,
+	0x00a6, 0x2001, 0x0205, 0x2003, 0x0000, 0x901e, 0x2029, 0x0001,
+	0x9182, 0x0034, 0x1228, 0x2011, 0x001f, 0x080c, 0xc837, 0x04c0,
+	0x2130, 0x2009, 0x0034, 0x2011, 0x001f, 0x080c, 0xc837, 0x96b2,
+	0x0034, 0xb004, 0x904d, 0x0110, 0x080c, 0x0fb1, 0x080c, 0x0fff,
+	0x01d0, 0x8528, 0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406,
+	0x968a, 0x003d, 0x1230, 0x2608, 0x2011, 0x001b, 0x080c, 0xc837,
+	0x00b8, 0x96b2, 0x003c, 0x2009, 0x003c, 0x2950, 0x2011, 0x001b,
+	0x080c, 0xc837, 0x0c18, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae,
+	0x852f, 0x95ad, 0x0050, 0xb566, 0xb070, 0xc0fd, 0xb072, 0x0048,
+	0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0050,
+	0xb566, 0x2a48, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c, 0x6d17,
+	0x000e, 0x2048, 0x9005, 0x1db0, 0x00fe, 0x00ae, 0x009e, 0x006e,
+	0x005e, 0x003e, 0x002e, 0x0005, 0x00d6, 0x00f6, 0x0096, 0x0006,
+	0x080c, 0x0fff, 0x000e, 0x090c, 0x0dd5, 0xa960, 0x21e8, 0xa95c,
+	0x9188, 0x0019, 0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xaa66,
+	0xa87a, 0x2079, 0x1800, 0x7990, 0x810c, 0x9188, 0x000c, 0x9182,
+	0x001a, 0x0210, 0x2009, 0x001a, 0x21a8, 0x810b, 0xa972, 0xac76,
+	0x2e98, 0xa85c, 0x9080, 0x001f, 0x20a0, 0x2001, 0x0205, 0x200c,
+	0x918d, 0x0080, 0x2102, 0x4003, 0x2003, 0x0000, 0x080c, 0x6d17,
+	0x009e, 0x00fe, 0x00de, 0x0005, 0x0016, 0x00d6, 0x00f6, 0x0096,
+	0x0016, 0x2001, 0x0205, 0x200c, 0x918d, 0x0080, 0x2102, 0x001e,
+	0x2079, 0x0200, 0x2e98, 0xa87c, 0xd0ec, 0x0118, 0x9e80, 0x000c,
+	0x2098, 0x2021, 0x003e, 0x901e, 0x9282, 0x0020, 0x0218, 0x2011,
+	0x0020, 0x2018, 0x9486, 0x003e, 0x1170, 0x0096, 0x080c, 0x0fff,
+	0x2900, 0x009e, 0x05c0, 0xa806, 0x2048, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0002, 0x20a0, 0x3300, 0x908e, 0x0260, 0x0140, 0x2009,
+	0x0280, 0x9102, 0x920a, 0x0218, 0x2010, 0x2100, 0x9318, 0x2200,
+	0x9402, 0x1228, 0x2400, 0x9202, 0x2410, 0x9318, 0x9006, 0x2020,
+	0x22a8, 0xa800, 0x9200, 0xa802, 0x20e1, 0x0000, 0x4003, 0x83ff,
+	0x0180, 0x3300, 0x9086, 0x0280, 0x1130, 0x7814, 0x8000, 0x9085,
+	0x0080, 0x7816, 0x2e98, 0x2310, 0x84ff, 0x0904, 0xb2b1, 0x0804,
+	0xb2b3, 0x9085, 0x0001, 0x7817, 0x0000, 0x009e, 0x00fe, 0x00de,
+	0x001e, 0x0005, 0x00d6, 0x0036, 0x0096, 0x6314, 0x2348, 0xa87a,
+	0xa982, 0x080c, 0x6d0b, 0x009e, 0x003e, 0x00de, 0x0005, 0x91b6,
+	0x0015, 0x1118, 0x080c, 0xaf43, 0x0030, 0x91b6, 0x0016, 0x190c,
+	0x0dd5, 0x080c, 0xaf43, 0x0005, 0x20a9, 0x000e, 0x20e1, 0x0000,
+	0x2e98, 0x6014, 0x0096, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x20a0,
+	0x009e, 0x4003, 0x0136, 0x9080, 0x001b, 0x20a0, 0x2011, 0x0006,
+	0x20a9, 0x0001, 0x3418, 0x8318, 0x23a0, 0x4003, 0x3318, 0x8318,
+	0x2398, 0x8211, 0x1db8, 0x2011, 0x0006, 0x013e, 0x20a0, 0x3318,
+	0x8318, 0x2398, 0x4003, 0x3418, 0x8318, 0x23a0, 0x8211, 0x1db8,
+	0x0096, 0x080c, 0xcc86, 0x0130, 0x6014, 0x2048, 0xa807, 0x0000,
+	0xa867, 0x0103, 0x009e, 0x0804, 0xaf43, 0x0096, 0x00d6, 0x0036,
+	0x7330, 0x9386, 0x0200, 0x11a8, 0x6010, 0x00b6, 0x2058, 0xb8cf,
+	0x0000, 0x00be, 0x6014, 0x9005, 0x0130, 0x2048, 0xa807, 0x0000,
+	0xa867, 0x0103, 0xab32, 0x080c, 0xaf43, 0x003e, 0x00de, 0x009e,
+	0x0005, 0x0011, 0x1d48, 0x0cc8, 0x0006, 0x0016, 0x080c, 0xd388,
+	0x0188, 0x6014, 0x9005, 0x1170, 0x600b, 0x0003, 0x601b, 0x0000,
+	0x6043, 0x0000, 0x2009, 0x0022, 0x080c, 0xb747, 0x9006, 0x001e,
+	0x000e, 0x0005, 0x9085, 0x0001, 0x0cd0, 0x0096, 0x0016, 0x20a9,
+	0x0014, 0x9e80, 0x000c, 0x20e1, 0x0000, 0x2098, 0x6014, 0x2048,
+	0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x2001,
+	0x0205, 0x2003, 0x0001, 0x2099, 0x0260, 0x20a9, 0x0016, 0x4003,
+	0x20a9, 0x000a, 0xa804, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0002, 0x20a0, 0x4003, 0x2001, 0x0205, 0x2003, 0x0002, 0x2099,
+	0x0260, 0x20a9, 0x0020, 0x4003, 0x2003, 0x0000, 0x6014, 0x2048,
+	0xa800, 0x2048, 0xa867, 0x0103, 0x080c, 0xaf43, 0x001e, 0x009e,
+	0x0005, 0x0096, 0x0016, 0x900e, 0x7030, 0x9086, 0x0100, 0x0140,
+	0x7038, 0x9084, 0x00ff, 0x800c, 0x703c, 0x9084, 0x00ff, 0x8004,
+	0x9080, 0x0004, 0x9108, 0x810b, 0x2011, 0x0002, 0x2019, 0x000c,
+	0x6014, 0x2048, 0x080c, 0xc837, 0x080c, 0xcc86, 0x0140, 0x6014,
+	0x2048, 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103, 0x080c,
+	0xaf43, 0x001e, 0x009e, 0x0005, 0x0016, 0x2009, 0x0000, 0x7030,
+	0x9086, 0x0200, 0x0110, 0x2009, 0x0001, 0x0096, 0x6014, 0x904d,
+	0x090c, 0x0dd5, 0xa97a, 0x080c, 0x6d17, 0x009e, 0x080c, 0xaf43,
+	0x001e, 0x0005, 0x0016, 0x0096, 0x7030, 0x9086, 0x0100, 0x1118,
+	0x2009, 0x0004, 0x0010, 0x7034, 0x800c, 0x810b, 0x2011, 0x000c,
+	0x2019, 0x000c, 0x6014, 0x2048, 0xa804, 0x0096, 0x9005, 0x0108,
+	0x2048, 0x080c, 0xc837, 0x009e, 0x080c, 0xcc86, 0x0148, 0xa804,
+	0x9005, 0x1158, 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103,
+	0x080c, 0xaf43, 0x009e, 0x001e, 0x0005, 0x0086, 0x2040, 0xa030,
+	0x8007, 0x9086, 0x0100, 0x1118, 0x080c, 0xb905, 0x00e0, 0xa034,
+	0x8007, 0x800c, 0x8806, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x000c, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897,
+	0x4000, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000, 0x2041,
+	0x1243, 0x0019, 0x0d08, 0x008e, 0x0898, 0x0096, 0x0006, 0x080c,
+	0x0fff, 0x000e, 0x01b0, 0xa8ab, 0x0dcb, 0xa876, 0x000e, 0xa8a2,
+	0x0006, 0xae6a, 0x2800, 0xa89e, 0xa97a, 0xaf72, 0xaa8e, 0xab92,
+	0xac96, 0xad9a, 0x0086, 0x2940, 0x080c, 0x10e9, 0x008e, 0x9085,
+	0x0001, 0x009e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008, 0x9084,
+	0x00ff, 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206, 0x1520,
+	0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206, 0x11e0,
+	0x6043, 0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, 0xd300,
+	0x001e, 0x1158, 0x622c, 0x2268, 0x2071, 0x026c, 0x6b20, 0x9386,
+	0x0003, 0x0130, 0x9386, 0x0006, 0x0128, 0x080c, 0xaf43, 0x0020,
+	0x0039, 0x0010, 0x080c, 0xb57c, 0x002e, 0x00de, 0x00ee, 0x0005,
+	0x0096, 0x6814, 0x2048, 0x9186, 0x0015, 0x0904, 0xb564, 0x918e,
+	0x0016, 0x1904, 0xb57a, 0x700c, 0x908c, 0xff00, 0x9186, 0x1700,
+	0x0120, 0x9186, 0x0300, 0x1904, 0xb53e, 0x89ff, 0x1138, 0x6800,
+	0x9086, 0x000f, 0x0904, 0xb521, 0x0804, 0xb578, 0x6808, 0x9086,
+	0xffff, 0x1904, 0xb566, 0xa87c, 0x9084, 0x0060, 0x9086, 0x0020,
+	0x1128, 0xa83c, 0xa940, 0x9105, 0x1904, 0xb566, 0x6824, 0xd084,
+	0x1904, 0xb566, 0xd0b4, 0x0158, 0x0016, 0x2001, 0x1985, 0x200c,
+	0x6018, 0x9102, 0x9082, 0x0005, 0x001e, 0x1a04, 0xb566, 0x080c,
+	0xce71, 0x685c, 0xa882, 0xa87c, 0xc0dc, 0xc0f4, 0xc0d4, 0xa87e,
+	0x0026, 0x900e, 0x6a18, 0x2001, 0x000a, 0x080c, 0x9027, 0xa884,
+	0x920a, 0x0208, 0x8011, 0xaa86, 0x82ff, 0x002e, 0x1138, 0x00c6,
+	0x2d60, 0x080c, 0xc999, 0x00ce, 0x0804, 0xb578, 0x00c6, 0xa868,
+	0xd0fc, 0x1118, 0x080c, 0x6141, 0x0010, 0x080c, 0x654e, 0x00ce,
+	0x1904, 0xb566, 0x00c6, 0x2d60, 0x080c, 0xaf43, 0x00ce, 0x0804,
+	0xb578, 0x00c6, 0x080c, 0xaf91, 0x0198, 0x6017, 0x0000, 0x6810,
+	0x6012, 0x080c, 0xd102, 0x6023, 0x0003, 0x6904, 0x00c6, 0x2d60,
+	0x080c, 0xaf43, 0x00ce, 0x080c, 0xafbe, 0x00ce, 0x0804, 0xb578,
+	0x2001, 0x1987, 0x2004, 0x6842, 0x00ce, 0x04d0, 0x7008, 0x9086,
+	0x000b, 0x11c8, 0x6010, 0x00b6, 0x2058, 0xb900, 0xc1bc, 0xb902,
+	0x00be, 0x00c6, 0x2d60, 0xa87b, 0x0003, 0x080c, 0xd342, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x91b1, 0x080c,
+	0x9763, 0x00ce, 0x00e8, 0x700c, 0x9086, 0x2a00, 0x1138, 0x2001,
+	0x1987, 0x2004, 0x6842, 0x00a0, 0x0479, 0x00a0, 0x89ff, 0x090c,
+	0x0dd5, 0x00c6, 0x00d6, 0x2d60, 0xa867, 0x0103, 0xa87b, 0x0003,
+	0x080c, 0x6b33, 0x080c, 0xce71, 0x080c, 0xaf74, 0x00de, 0x00ce,
+	0x080c, 0xaf43, 0x009e, 0x0005, 0x9186, 0x0015, 0x1128, 0x2001,
+	0x1987, 0x2004, 0x6842, 0x0068, 0x918e, 0x0016, 0x1160, 0x00c6,
+	0x2d00, 0x2060, 0x080c, 0xe997, 0x080c, 0x876f, 0x080c, 0xaf43,
+	0x00ce, 0x080c, 0xaf43, 0x0005, 0x0026, 0x0036, 0x0046, 0x7228,
+	0xacb0, 0xabac, 0xd2f4, 0x0130, 0x2001, 0x1987, 0x2004, 0x6842,
+	0x0804, 0xb5f6, 0x00c6, 0x2d60, 0x080c, 0xc898, 0x00ce, 0x6804,
+	0x9086, 0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003, 0x0001,
+	0x6007, 0x0050, 0x080c, 0x91b1, 0x080c, 0x9763, 0x00ce, 0x04f0,
+	0x6800, 0x9086, 0x000f, 0x01a8, 0x89ff, 0x090c, 0x0dd5, 0x6800,
+	0x9086, 0x0004, 0x1190, 0xa87c, 0xd0ac, 0x0178, 0xa843, 0x0fff,
+	0xa83f, 0x0fff, 0xa880, 0xc0fc, 0xa882, 0x2001, 0x0001, 0x6832,
+	0x0400, 0x2001, 0x0007, 0x6832, 0x00e0, 0xa87c, 0xd0b4, 0x1150,
+	0xd0ac, 0x0db8, 0x6824, 0xd0f4, 0x1d48, 0xa838, 0xa934, 0x9105,
+	0x0d80, 0x0c20, 0xd2ec, 0x1d68, 0x7024, 0x9306, 0x1118, 0x7020,
+	0x9406, 0x0d38, 0x7020, 0x683e, 0x7024, 0x683a, 0x2001, 0x0005,
+	0x6832, 0x080c, 0xcff9, 0x080c, 0x9763, 0x0010, 0x080c, 0xaf43,
+	0x004e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008,
+	0x9084, 0x00ff, 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206,
+	0x1904, 0xb661, 0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be,
+	0x9206, 0x1904, 0xb661, 0x6038, 0x2068, 0x6824, 0xc0dc, 0x6826,
+	0x6a20, 0x9286, 0x0007, 0x0904, 0xb661, 0x9286, 0x0002, 0x0904,
+	0xb661, 0x9286, 0x0000, 0x05e8, 0x6808, 0x633c, 0x9306, 0x15c8,
+	0x2071, 0x026c, 0x9186, 0x0015, 0x0570, 0x918e, 0x0016, 0x1100,
+	0x00c6, 0x6038, 0x2060, 0x6104, 0x9186, 0x004b, 0x01c0, 0x9186,
+	0x004c, 0x01a8, 0x9186, 0x004d, 0x0190, 0x9186, 0x004e, 0x0178,
+	0x9186, 0x0052, 0x0160, 0x6014, 0x0096, 0x2048, 0x080c, 0xcc86,
+	0x090c, 0x0dd5, 0xa87b, 0x0003, 0x009e, 0x080c, 0xd342, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x91b1, 0x080c,
+	0x9763, 0x00ce, 0x0030, 0x6038, 0x2070, 0x2001, 0x1987, 0x2004,
+	0x7042, 0x080c, 0xaf43, 0x002e, 0x00de, 0x00ee, 0x0005, 0x00b6,
+	0x0096, 0x00f6, 0x6014, 0x2048, 0x6010, 0x2058, 0x91b6, 0x0015,
+	0x0130, 0xba08, 0xbb0c, 0xbc00, 0xc48c, 0xbc02, 0x0460, 0x0096,
+	0x0156, 0x0036, 0x0026, 0x2b48, 0x9e90, 0x0010, 0x2019, 0x000a,
+	0x20a9, 0x0004, 0x080c, 0xbf11, 0x002e, 0x003e, 0x015e, 0x009e,
+	0x1904, 0xb6d0, 0x0096, 0x0156, 0x0036, 0x0026, 0x2b48, 0x9e90,
+	0x0014, 0x2019, 0x0006, 0x20a9, 0x0004, 0x080c, 0xbf11, 0x002e,
+	0x003e, 0x015e, 0x009e, 0x15a0, 0x7238, 0xba0a, 0x733c, 0xbb0e,
+	0xbc00, 0xc48d, 0xbc02, 0xa804, 0x9005, 0x1128, 0x00fe, 0x009e,
+	0x00be, 0x0804, 0xb348, 0x0096, 0x2048, 0xaa12, 0xab16, 0xac0a,
+	0x009e, 0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x9080, 0x0002, 0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4,
+	0x2031, 0x0000, 0x2041, 0x1243, 0x080c, 0xb45d, 0x0130, 0x00fe,
+	0x009e, 0x080c, 0xaf43, 0x00be, 0x0005, 0x080c, 0xb905, 0x0cb8,
+	0x2b78, 0x00f6, 0x080c, 0x321e, 0x080c, 0xd39d, 0x00fe, 0x00c6,
+	0x080c, 0xaeed, 0x2f00, 0x6012, 0x6017, 0x0000, 0x6023, 0x0001,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x2001, 0x0007, 0x080c, 0x65e9,
+	0x080c, 0x6615, 0x080c, 0x91f9, 0x080c, 0x9763, 0x00ce, 0x0804,
+	0xb6a3, 0x2100, 0x91b2, 0x0053, 0x1a0c, 0x0dd5, 0x91b2, 0x0040,
+	0x1a04, 0xb759, 0x0002, 0xb747, 0xb747, 0xb73d, 0xb747, 0xb747,
+	0xb747, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b,
+	0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b,
+	0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b,
+	0xb73b, 0xb73b, 0xb747, 0xb73b, 0xb747, 0xb747, 0xb73b, 0xb73b,
+	0xb73b, 0xb73b, 0xb73b, 0xb73d, 0xb73b, 0xb73b, 0xb73b, 0xb73b,
+	0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb747, 0xb747, 0xb73b,
+	0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b, 0xb73b,
+	0xb747, 0xb73b, 0xb73b, 0x080c, 0x0dd5, 0x0066, 0x00b6, 0x6610,
+	0x2658, 0xb8cc, 0xc08c, 0xb8ce, 0x00be, 0x006e, 0x0000, 0x6003,
+	0x0001, 0x6106, 0x9186, 0x0032, 0x0118, 0x080c, 0x91f9, 0x0010,
+	0x080c, 0x91b1, 0x0126, 0x2091, 0x8000, 0x080c, 0x9763, 0x012e,
+	0x0005, 0x2600, 0x0002, 0xb747, 0xb747, 0xb76d, 0xb747, 0xb747,
+	0xb76d, 0xb76d, 0xb76d, 0xb76d, 0xb747, 0xb76d, 0xb747, 0xb76d,
+	0xb747, 0xb76d, 0xb76d, 0xb76d, 0xb76d, 0x080c, 0x0dd5, 0x6004,
+	0x90b2, 0x0053, 0x1a0c, 0x0dd5, 0x91b6, 0x0013, 0x0904, 0xb831,
+	0x91b6, 0x0027, 0x1904, 0xb7ec, 0x080c, 0x9657, 0x6004, 0x080c,
+	0xce7d, 0x01b0, 0x080c, 0xce8e, 0x01a8, 0x908e, 0x0021, 0x0904,
+	0xb7e9, 0x908e, 0x0022, 0x1130, 0x080c, 0xb374, 0x0904, 0xb7e5,
+	0x0804, 0xb7e6, 0x908e, 0x003d, 0x0904, 0xb7e9, 0x0804, 0xb7df,
+	0x080c, 0x3247, 0x2001, 0x0007, 0x080c, 0x65e9, 0x6010, 0x00b6,
+	0x2058, 0xb9a0, 0x00be, 0x080c, 0xb905, 0x9186, 0x007e, 0x1148,
+	0x2001, 0x1837, 0x2014, 0xc285, 0x080c, 0x743e, 0x1108, 0xc2ad,
+	0x2202, 0x0036, 0x0026, 0x2019, 0x0028, 0x2110, 0x080c, 0xeaa3,
+	0x002e, 0x003e, 0x0016, 0x0026, 0x0036, 0x2110, 0x2019, 0x0028,
+	0x080c, 0x9356, 0x0076, 0x903e, 0x080c, 0x9229, 0x6010, 0x00b6,
+	0x905d, 0x0100, 0x00be, 0x2c08, 0x080c, 0xe477, 0x007e, 0x003e,
+	0x002e, 0x001e, 0x080c, 0xd39d, 0x0016, 0x080c, 0xd0fa, 0x080c,
+	0xaf43, 0x001e, 0x080c, 0x331a, 0x080c, 0x9763, 0x0030, 0x080c,
+	0xd0fa, 0x080c, 0xaf43, 0x080c, 0x9763, 0x0005, 0x080c, 0xb905,
+	0x0cb0, 0x080c, 0xb941, 0x0c98, 0x9186, 0x0014, 0x1db0, 0x080c,
+	0x9657, 0x6004, 0x908e, 0x0022, 0x1118, 0x080c, 0xb374, 0x0d68,
+	0x080c, 0x321e, 0x080c, 0xd39d, 0x080c, 0xce7d, 0x1190, 0x080c,
+	0x3247, 0x6010, 0x00b6, 0x2058, 0xb9a0, 0x00be, 0x080c, 0xb905,
+	0x9186, 0x007e, 0x1128, 0x2001, 0x1837, 0x200c, 0xc185, 0x2102,
+	0x0870, 0x080c, 0xce8e, 0x1118, 0x080c, 0xb905, 0x0840, 0x6004,
+	0x908e, 0x0032, 0x1160, 0x00e6, 0x00f6, 0x2071, 0x189e, 0x2079,
+	0x0000, 0x080c, 0x35b5, 0x00fe, 0x00ee, 0x0804, 0xb7df, 0x6004,
+	0x908e, 0x0021, 0x0d48, 0x908e, 0x0022, 0x090c, 0xb905, 0x0804,
+	0xb7df, 0x90b2, 0x0040, 0x1a04, 0xb8e1, 0x2008, 0x0002, 0xb879,
+	0xb87a, 0xb87d, 0xb880, 0xb883, 0xb886, 0xb877, 0xb877, 0xb877,
+	0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877,
+	0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877,
+	0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb889, 0xb896, 0xb877,
+	0xb898, 0xb896, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb896,
+	0xb896, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877, 0xb877,
+	0xb877, 0xb8c8, 0xb896, 0xb877, 0xb892, 0xb877, 0xb877, 0xb877,
+	0xb893, 0xb877, 0xb877, 0xb877, 0xb896, 0xb8bf, 0xb877, 0x080c,
+	0x0dd5, 0x00e0, 0x2001, 0x000b, 0x0420, 0x2001, 0x0003, 0x0408,
+	0x2001, 0x0005, 0x00f0, 0x2001, 0x0001, 0x00d8, 0x2001, 0x0009,
+	0x00c0, 0x080c, 0x9657, 0x6003, 0x0005, 0x080c, 0xd3a0, 0x080c,
+	0x9763, 0x0070, 0x0018, 0x0010, 0x080c, 0x65e9, 0x0804, 0xb8d9,
+	0x080c, 0x9657, 0x080c, 0xd3a0, 0x6003, 0x0004, 0x080c, 0x9763,
+	0x0005, 0x080c, 0x65e9, 0x080c, 0x9657, 0x6003, 0x0002, 0x0036,
+	0x2019, 0x1852, 0x2304, 0x9084, 0xff00, 0x1120, 0x2001, 0x1985,
+	0x201c, 0x0040, 0x8007, 0x909a, 0x0004, 0x0ec0, 0x8003, 0x801b,
+	0x831b, 0x9318, 0x631a, 0x003e, 0x080c, 0x9763, 0x0c08, 0x080c,
+	0x9657, 0x080c, 0xd0fa, 0x080c, 0xaf43, 0x080c, 0x9763, 0x08c0,
+	0x00e6, 0x00f6, 0x2071, 0x189e, 0x2079, 0x0000, 0x080c, 0x35b5,
+	0x00fe, 0x00ee, 0x080c, 0x9657, 0x080c, 0xaf43, 0x080c, 0x9763,
+	0x0838, 0x080c, 0x9657, 0x6003, 0x0002, 0x080c, 0xd3a0, 0x0804,
+	0x9763, 0x2600, 0x2008, 0x0002, 0xb8f8, 0xb8d9, 0xb8f6, 0xb8d9,
+	0xb8d9, 0xb8f6, 0xb8f6, 0xb8f6, 0xb8f6, 0xb8d9, 0xb8f6, 0xb8d9,
+	0xb8f6, 0xb8d9, 0xb8f6, 0xb8f6, 0xb8f6, 0xb8f6, 0x080c, 0x0dd5,
+	0x080c, 0x9657, 0x0096, 0x6014, 0x2048, 0x080c, 0x6d17, 0x009e,
+	0x080c, 0xaf43, 0x080c, 0x9763, 0x0005, 0x00e6, 0x0096, 0x0026,
+	0x0016, 0x080c, 0xcc86, 0x0568, 0x6014, 0x2048, 0xa864, 0x9086,
+	0x0139, 0x11a8, 0xa894, 0x9086, 0x0056, 0x1148, 0x080c, 0x54f7,
+	0x0130, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x0028, 0x2001,
+	0x0030, 0x900e, 0x2011, 0x4005, 0x080c, 0xd267, 0x0090, 0xa868,
+	0xd0fc, 0x0178, 0xa807, 0x0000, 0x0016, 0x6004, 0x908e, 0x0021,
+	0x0168, 0x908e, 0x003d, 0x0150, 0x001e, 0xa867, 0x0103, 0xa833,
+	0x0100, 0x001e, 0x002e, 0x009e, 0x00ee, 0x0005, 0x001e, 0x0009,
+	0x0cc0, 0x0096, 0x6014, 0x2048, 0xa800, 0x2048, 0xa867, 0x0103,
+	0xa823, 0x8001, 0x009e, 0x0005, 0x00b6, 0x6610, 0x2658, 0xb804,
+	0x9084, 0x00ff, 0x90b2, 0x000c, 0x1a0c, 0x0dd5, 0x6604, 0x96b6,
+	0x004d, 0x1120, 0x080c, 0xd186, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x0043, 0x1120, 0x080c, 0xd1cf, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x004b, 0x1120, 0x080c, 0xd1fb, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x0033, 0x1120, 0x080c, 0xd11c, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x0028, 0x1120, 0x080c, 0xcecc, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x0029, 0x1120, 0x080c, 0xcf0d, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x001f, 0x1120, 0x080c, 0xb31c, 0x0804, 0xb9d1, 0x6604, 0x96b6,
+	0x0000, 0x1118, 0x080c, 0xb667, 0x04e0, 0x6604, 0x96b6, 0x0022,
+	0x1118, 0x080c, 0xb355, 0x04a8, 0x6604, 0x96b6, 0x0035, 0x1118,
+	0x080c, 0xb47b, 0x0470, 0x6604, 0x96b6, 0x0039, 0x1118, 0x080c,
+	0xb5fc, 0x0438, 0x6604, 0x96b6, 0x003d, 0x1118, 0x080c, 0xb38d,
+	0x0400, 0x6604, 0x96b6, 0x0044, 0x1118, 0x080c, 0xb3c9, 0x00c8,
+	0x6604, 0x96b6, 0x0049, 0x1118, 0x080c, 0xb40a, 0x0090, 0x6604,
+	0x96b6, 0x0041, 0x1118, 0x080c, 0xb3f4, 0x0058, 0x91b6, 0x0015,
+	0x1110, 0x0063, 0x0030, 0x91b6, 0x0016, 0x1128, 0x00be, 0x0804,
+	0xbc2d, 0x00be, 0x0005, 0x080c, 0xafd9, 0x0cd8, 0xb9ee, 0xb9f1,
+	0xb9ee, 0xba38, 0xb9ee, 0xbba1, 0xbc3a, 0xb9ee, 0xb9ee, 0xbc03,
+	0xb9ee, 0xbc19, 0x0096, 0x601f, 0x0000, 0x6014, 0x2048, 0xa800,
+	0x2048, 0xa867, 0x0103, 0x009e, 0x0804, 0xaf43, 0xa001, 0xa001,
+	0x0005, 0x00e6, 0x2071, 0x1800, 0x7090, 0x9086, 0x0074, 0x1540,
+	0x080c, 0xe448, 0x11b0, 0x6010, 0x00b6, 0x2058, 0x7030, 0xd08c,
+	0x0128, 0xb800, 0xd0bc, 0x0110, 0xc0c5, 0xb802, 0x00f9, 0x00be,
+	0x2001, 0x0006, 0x080c, 0x65e9, 0x080c, 0x3247, 0x080c, 0xaf43,
+	0x0098, 0x2001, 0x000a, 0x080c, 0x65e9, 0x080c, 0x3247, 0x6003,
+	0x0001, 0x6007, 0x0001, 0x080c, 0x91f9, 0x080c, 0x9763, 0x0020,
+	0x2001, 0x0001, 0x080c, 0xbb71, 0x00ee, 0x0005, 0x00d6, 0xb800,
+	0xd084, 0x0160, 0x9006, 0x080c, 0x65d5, 0x2069, 0x1847, 0x6804,
+	0xd0a4, 0x0120, 0x2001, 0x0006, 0x080c, 0x6615, 0x00de, 0x0005,
+	0x00b6, 0x0096, 0x00d6, 0x2011, 0x1824, 0x2204, 0x9086, 0x0074,
+	0x1904, 0xbb46, 0x6010, 0x2058, 0xbaa0, 0x9286, 0x007e, 0x1120,
+	0x080c, 0xbd87, 0x0804, 0xbaaa, 0x080c, 0xbd7c, 0x6010, 0x2058,
+	0xbaa0, 0x9286, 0x0080, 0x1510, 0x6014, 0x9005, 0x01a8, 0x2048,
+	0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, 0x1140, 0x2001, 0x0000,
+	0x900e, 0x2011, 0x4000, 0x080c, 0xd267, 0x0030, 0xa807, 0x0000,
+	0xa867, 0x0103, 0xa833, 0x0200, 0x2001, 0x0006, 0x080c, 0x65e9,
+	0x080c, 0x3247, 0x080c, 0xaf43, 0x0804, 0xbb4b, 0x080c, 0xbb59,
+	0x6014, 0x9005, 0x0190, 0x2048, 0xa868, 0xd0f4, 0x01e8, 0xa864,
+	0x9084, 0x00ff, 0x9086, 0x0039, 0x1d08, 0x2001, 0x0000, 0x900e,
+	0x2011, 0x4000, 0x080c, 0xd267, 0x08f8, 0x080c, 0xbb4f, 0x0160,
+	0x9006, 0x080c, 0x65d5, 0x2001, 0x0004, 0x080c, 0x6615, 0x2001,
+	0x0007, 0x080c, 0x65e9, 0x08a0, 0x2001, 0x0004, 0x080c, 0x65e9,
+	0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x91f9, 0x080c, 0x9763,
+	0x0804, 0xbb4b, 0xb85c, 0xd0e4, 0x01d8, 0x080c, 0xd09c, 0x080c,
+	0x743e, 0x0118, 0xd0dc, 0x1904, 0xba6c, 0x2011, 0x1837, 0x2204,
+	0xc0ad, 0x2012, 0x2001, 0x196c, 0x2004, 0x00f6, 0x2079, 0x0100,
+	0x78e3, 0x0000, 0x080c, 0x28f0, 0x78e2, 0x00fe, 0x0804, 0xba6c,
+	0x080c, 0xd0d9, 0x2011, 0x1837, 0x2204, 0xc0a5, 0x2012, 0x0006,
+	0x080c, 0xe5cd, 0x000e, 0x1904, 0xba6c, 0xc0b5, 0x2012, 0x2001,
+	0x0006, 0x080c, 0x65e9, 0x9006, 0x080c, 0x65d5, 0x00c6, 0x2001,
+	0x180f, 0x2004, 0xd09c, 0x0520, 0x00f6, 0x2079, 0x0100, 0x00e6,
+	0x2071, 0x1800, 0x700c, 0x9084, 0x00ff, 0x78e6, 0x707e, 0x7010,
+	0x78ea, 0x7082, 0x908c, 0x00ff, 0x00ee, 0x780c, 0xc0b5, 0x780e,
+	0x00fe, 0x080c, 0x28c5, 0x00f6, 0x2100, 0x900e, 0x080c, 0x287c,
+	0x795e, 0x00fe, 0x9186, 0x0081, 0x01d8, 0x2009, 0x0081, 0x00c8,
+	0x2009, 0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936,
+	0x780c, 0xc0b5, 0x780e, 0x00fe, 0x080c, 0x28c5, 0x00f6, 0x2079,
+	0x1800, 0x7982, 0x2100, 0x900e, 0x080c, 0x287c, 0x795e, 0x00fe,
+	0x8108, 0x080c, 0x6638, 0x2b00, 0x00ce, 0x1904, 0xba6c, 0x6012,
+	0x2009, 0x180f, 0x210c, 0xd19c, 0x0150, 0x2009, 0x027c, 0x210c,
+	0x918c, 0x00ff, 0xb912, 0x2009, 0x027d, 0x210c, 0xb916, 0x2001,
+	0x0002, 0x080c, 0x65e9, 0x6023, 0x0001, 0x6003, 0x0001, 0x6007,
+	0x0002, 0x080c, 0x91f9, 0x080c, 0x9763, 0x0028, 0x080c, 0xb905,
+	0x2001, 0x0001, 0x0431, 0x00de, 0x009e, 0x00be, 0x0005, 0x2001,
+	0x1810, 0x2004, 0xd0a4, 0x0120, 0x2001, 0x1848, 0x2004, 0xd0ac,
+	0x0005, 0x00e6, 0x080c, 0xeafc, 0x0190, 0x2071, 0x0260, 0x7108,
+	0x720c, 0x918c, 0x00ff, 0x1118, 0x9284, 0xff00, 0x0140, 0x6010,
+	0x2058, 0xb8a0, 0x9084, 0xff80, 0x1110, 0xb912, 0xba16, 0x00ee,
+	0x0005, 0x2030, 0x9005, 0x0158, 0x2001, 0x0007, 0x080c, 0x65e9,
+	0x080c, 0x5771, 0x1120, 0x2001, 0x0007, 0x080c, 0x6615, 0x2600,
+	0x9005, 0x11b0, 0x6014, 0x0096, 0x2048, 0xa868, 0x009e, 0xd0fc,
+	0x1178, 0x0036, 0x0046, 0x6010, 0x00b6, 0x2058, 0xbba0, 0x00be,
+	0x2021, 0x0004, 0x2011, 0x8014, 0x080c, 0x4b7f, 0x004e, 0x003e,
+	0x080c, 0x3247, 0x6020, 0x9086, 0x000a, 0x1108, 0x0005, 0x0804,
+	0xaf43, 0x00b6, 0x00e6, 0x0026, 0x0016, 0x2071, 0x1800, 0x7090,
+	0x9086, 0x0014, 0x1904, 0xbbf9, 0x080c, 0x5771, 0x1170, 0x6014,
+	0x9005, 0x1158, 0x0036, 0x0046, 0x6010, 0x2058, 0xbba0, 0x2021,
+	0x0006, 0x080c, 0x4d36, 0x004e, 0x003e, 0x00d6, 0x6010, 0x2058,
+	0x080c, 0x6734, 0x080c, 0xba26, 0x00de, 0x080c, 0xbe4d, 0x1588,
+	0x6010, 0x2058, 0xb890, 0x9005, 0x0560, 0x2001, 0x0006, 0x080c,
+	0x65e9, 0x0096, 0x6014, 0x904d, 0x01d0, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0039, 0x1140, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000,
+	0x080c, 0xd267, 0x0060, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0029,
+	0x0130, 0xa807, 0x0000, 0xa867, 0x0103, 0xa833, 0x0200, 0x009e,
+	0x080c, 0x3247, 0x6020, 0x9086, 0x000a, 0x0140, 0x080c, 0xaf43,
+	0x0028, 0x080c, 0xb905, 0x9006, 0x080c, 0xbb71, 0x001e, 0x002e,
+	0x00ee, 0x00be, 0x0005, 0x2011, 0x1824, 0x2204, 0x9086, 0x0014,
+	0x1160, 0x2001, 0x0002, 0x080c, 0x65e9, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x080c, 0x91f9, 0x0804, 0x9763, 0x2001, 0x0001, 0x0804,
+	0xbb71, 0x2030, 0x2011, 0x1824, 0x2204, 0x9086, 0x0004, 0x1148,
+	0x96b6, 0x000b, 0x1120, 0x2001, 0x0007, 0x080c, 0x65e9, 0x0804,
+	0xaf43, 0x2001, 0x0001, 0x0804, 0xbb71, 0x0002, 0xb9ee, 0xbc45,
+	0xb9ee, 0xbc86, 0xb9ee, 0xbd33, 0xbc3a, 0xb9ee, 0xb9ee, 0xbd47,
+	0xb9ee, 0xbd59, 0x6604, 0x9686, 0x0003, 0x0904, 0xbba1, 0x96b6,
+	0x001e, 0x1110, 0x080c, 0xaf43, 0x0005, 0x00b6, 0x00d6, 0x00c6,
+	0x080c, 0xbd6b, 0x11a0, 0x9006, 0x080c, 0x65d5, 0x080c, 0x321e,
+	0x080c, 0xd39d, 0x2001, 0x0002, 0x080c, 0x65e9, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x91f9, 0x080c, 0x9763, 0x0418, 0x2009,
+	0x026e, 0x2104, 0x9086, 0x0009, 0x1160, 0x6010, 0x2058, 0xb840,
+	0x9084, 0x00ff, 0x9005, 0x0170, 0x8001, 0xb842, 0x601b, 0x000a,
+	0x0088, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x1900,
+	0x1108, 0x08a0, 0x080c, 0x321e, 0x080c, 0xd39d, 0x2001, 0x0001,
+	0x080c, 0xbb71, 0x00ce, 0x00de, 0x00be, 0x0005, 0x0096, 0x00b6,
+	0x0026, 0x9016, 0x080c, 0xbd79, 0x00d6, 0x2069, 0x197b, 0x2d04,
+	0x9005, 0x0168, 0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e, 0x1138,
+	0x2069, 0x1820, 0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de,
+	0x0088, 0x9006, 0x080c, 0x65d5, 0x2001, 0x0002, 0x080c, 0x65e9,
+	0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x91f9, 0x080c, 0x9763,
+	0x0804, 0xbd03, 0x080c, 0xcc86, 0x01b0, 0x6014, 0x2048, 0xa864,
+	0x2010, 0x9086, 0x0139, 0x1138, 0x6007, 0x0016, 0x2001, 0x0002,
+	0x080c, 0xd2c1, 0x00b0, 0x6014, 0x2048, 0xa864, 0xd0fc, 0x0118,
+	0x2001, 0x0001, 0x0ca8, 0x2001, 0x180e, 0x2004, 0xd0dc, 0x0148,
+	0x6010, 0x2058, 0xb840, 0x9084, 0x00ff, 0x9005, 0x1110, 0x9006,
+	0x0c38, 0x080c, 0xb905, 0x2009, 0x026e, 0x2134, 0x96b4, 0x00ff,
+	0x9686, 0x0005, 0x0520, 0x9686, 0x000b, 0x01c8, 0x2009, 0x026f,
+	0x2104, 0x9084, 0xff00, 0x1118, 0x9686, 0x0009, 0x01c0, 0x9086,
+	0x1900, 0x1168, 0x9686, 0x0009, 0x0190, 0x2001, 0x0004, 0x080c,
+	0x65e9, 0x2001, 0x0028, 0x601a, 0x6007, 0x0052, 0x0020, 0x2001,
+	0x0001, 0x080c, 0xbb71, 0x002e, 0x00be, 0x009e, 0x0005, 0x9286,
+	0x0139, 0x0160, 0x6014, 0x2048, 0x080c, 0xcc86, 0x0140, 0xa864,
+	0x9086, 0x0139, 0x0118, 0xa868, 0xd0fc, 0x0108, 0x0c40, 0x6010,
+	0x2058, 0xb840, 0x9084, 0x00ff, 0x9005, 0x0138, 0x8001, 0xb842,
+	0x601b, 0x000a, 0x6007, 0x0016, 0x08f0, 0xb8a0, 0x9086, 0x007e,
+	0x1138, 0x00e6, 0x2071, 0x1800, 0x080c, 0x6040, 0x00ee, 0x0010,
+	0x080c, 0x321e, 0x0860, 0x080c, 0xbd79, 0x1160, 0x2001, 0x0004,
+	0x080c, 0x65e9, 0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x91f9,
+	0x0804, 0x9763, 0x080c, 0xb905, 0x9006, 0x0804, 0xbb71, 0x0489,
+	0x1160, 0x2001, 0x0008, 0x080c, 0x65e9, 0x6003, 0x0001, 0x6007,
+	0x0005, 0x080c, 0x91f9, 0x0804, 0x9763, 0x2001, 0x0001, 0x0804,
+	0xbb71, 0x00f9, 0x1160, 0x2001, 0x000a, 0x080c, 0x65e9, 0x6003,
+	0x0001, 0x6007, 0x0001, 0x080c, 0x91f9, 0x0804, 0x9763, 0x2001,
+	0x0001, 0x0804, 0xbb71, 0x2009, 0x026e, 0x2104, 0x9086, 0x0003,
+	0x1138, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x2a00,
+	0x0005, 0x9085, 0x0001, 0x0005, 0x00b6, 0x00c6, 0x0016, 0x6110,
+	0x2158, 0x080c, 0x66a8, 0x001e, 0x00ce, 0x00be, 0x0005, 0x00b6,
+	0x00f6, 0x00e6, 0x00d6, 0x0036, 0x0016, 0x6010, 0x2058, 0x2009,
+	0x1837, 0x2104, 0x9085, 0x0003, 0x200a, 0x080c, 0xbe1f, 0x0560,
+	0x2009, 0x1837, 0x2104, 0xc0cd, 0x200a, 0x080c, 0x6a08, 0x0158,
+	0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xe73a, 0x2001, 0x180c,
+	0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x080c,
+	0x31e9, 0x00e6, 0x2071, 0x1800, 0x080c, 0x2ff5, 0x00ee, 0x00c6,
+	0x0156, 0x20a9, 0x0781, 0x2009, 0x007f, 0x080c, 0x331a, 0x8108,
+	0x1f04, 0xbdbd, 0x015e, 0x00ce, 0x080c, 0xbd7c, 0x2071, 0x0260,
+	0x2079, 0x0200, 0x7817, 0x0001, 0x2001, 0x1837, 0x200c, 0xc1c5,
+	0x7018, 0xd0fc, 0x0110, 0xd0dc, 0x0118, 0x7038, 0xd0dc, 0x1108,
+	0xc1c4, 0x7817, 0x0000, 0x2001, 0x1837, 0x2102, 0x2079, 0x0100,
+	0x2e04, 0x9084, 0x00ff, 0x2069, 0x181f, 0x206a, 0x78e6, 0x0006,
+	0x8e70, 0x2e04, 0x2069, 0x1820, 0x206a, 0x78ea, 0x7832, 0x7836,
+	0x2010, 0x9084, 0xff00, 0x001e, 0x9105, 0x2009, 0x182c, 0x200a,
+	0x2200, 0x9084, 0x00ff, 0x2008, 0x080c, 0x28c5, 0x080c, 0x743e,
+	0x0170, 0x2071, 0x0260, 0x2069, 0x1981, 0x7048, 0x206a, 0x704c,
+	0x6806, 0x7050, 0x680a, 0x7054, 0x680e, 0x080c, 0xd09c, 0x0040,
+	0x2001, 0x0006, 0x080c, 0x65e9, 0x080c, 0x3247, 0x080c, 0xaf43,
+	0x001e, 0x003e, 0x00de, 0x00ee, 0x00fe, 0x00be, 0x0005, 0x0096,
+	0x0026, 0x0036, 0x00e6, 0x0156, 0x2019, 0x182c, 0x231c, 0x83ff,
+	0x01f0, 0x2071, 0x0260, 0x7200, 0x9294, 0x00ff, 0x7004, 0x9084,
+	0xff00, 0x9205, 0x9306, 0x1198, 0x2011, 0x0276, 0x20a9, 0x0004,
+	0x2b48, 0x2019, 0x000a, 0x080c, 0xbf11, 0x1148, 0x2011, 0x027a,
+	0x20a9, 0x0004, 0x2019, 0x0006, 0x080c, 0xbf11, 0x1100, 0x015e,
+	0x00ee, 0x003e, 0x002e, 0x009e, 0x0005, 0x00e6, 0x2071, 0x0260,
+	0x7034, 0x9086, 0x0014, 0x11a8, 0x7038, 0x9086, 0x0800, 0x1188,
+	0x703c, 0xd0ec, 0x0160, 0x9084, 0x0f00, 0x9086, 0x0100, 0x1138,
+	0x7054, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0x9006, 0x0010, 0x9085,
+	0x0001, 0x00ee, 0x0005, 0x00e6, 0x0096, 0x00c6, 0x0076, 0x0056,
+	0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, 0x19ef,
+	0x252c, 0x2021, 0x19f5, 0x2424, 0x2061, 0x1cd0, 0x2071, 0x1800,
+	0x7254, 0x7074, 0x9202, 0x1a04, 0xbedd, 0x080c, 0x8a3d, 0x0904,
+	0xbed6, 0x080c, 0xe76b, 0x0904, 0xbed6, 0x6720, 0x9786, 0x0007,
+	0x0904, 0xbed6, 0x2500, 0x9c06, 0x0904, 0xbed6, 0x2400, 0x9c06,
+	0x05e8, 0x3e08, 0x9186, 0x0002, 0x1148, 0x6010, 0x9005, 0x0130,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1580, 0x00c6, 0x6000,
+	0x9086, 0x0004, 0x1110, 0x080c, 0x1aa1, 0x9786, 0x000a, 0x0148,
+	0x080c, 0xce8e, 0x1130, 0x00ce, 0x080c, 0xb905, 0x080c, 0xaf74,
+	0x00e8, 0x6014, 0x2048, 0x080c, 0xcc86, 0x01a8, 0x9786, 0x0003,
+	0x1530, 0xa867, 0x0103, 0xa87c, 0xd0cc, 0x0130, 0x0096, 0xa878,
+	0x2048, 0x080c, 0x0fb1, 0x009e, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0x6d0b, 0x080c, 0xce71, 0x080c, 0xaf74, 0x00ce, 0x9ce0, 0x0018,
+	0x7068, 0x9c02, 0x1210, 0x0804, 0xbe80, 0x012e, 0x000e, 0x002e,
+	0x004e, 0x005e, 0x007e, 0x00ce, 0x009e, 0x00ee, 0x0005, 0x9786,
+	0x0006, 0x1118, 0x080c, 0xe6dd, 0x0c30, 0x9786, 0x0009, 0x1148,
+	0x6000, 0x9086, 0x0004, 0x0d08, 0x2009, 0x004c, 0x080c, 0xafbe,
+	0x08e0, 0x9786, 0x000a, 0x0980, 0x0820, 0x220c, 0x2304, 0x9106,
+	0x1130, 0x8210, 0x8318, 0x1f04, 0xbefd, 0x9006, 0x0005, 0x2304,
+	0x9102, 0x0218, 0x2001, 0x0001, 0x0008, 0x9006, 0x918d, 0x0001,
+	0x0005, 0x0136, 0x01c6, 0x0016, 0x8906, 0x8006, 0x8007, 0x908c,
+	0x003f, 0x21e0, 0x9084, 0xffc0, 0x9300, 0x2098, 0x3518, 0x20a9,
+	0x0001, 0x220c, 0x4002, 0x910e, 0x1140, 0x8210, 0x8319, 0x1dc8,
+	0x9006, 0x001e, 0x01ce, 0x013e, 0x0005, 0x220c, 0x9102, 0x0218,
+	0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0x918d, 0x0001, 0x001e,
+	0x01ce, 0x013e, 0x0005, 0x220c, 0x810f, 0x2304, 0x9106, 0x1130,
+	0x8210, 0x8318, 0x1f04, 0xbf3b, 0x9006, 0x0005, 0x918d, 0x0001,
+	0x0005, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dd5, 0x080c, 0xce7d,
+	0x0120, 0x080c, 0xce8e, 0x0168, 0x0028, 0x080c, 0x3247, 0x080c,
+	0xce8e, 0x0138, 0x080c, 0x9657, 0x080c, 0xaf43, 0x080c, 0x9763,
+	0x0005, 0x080c, 0xb905, 0x0cb0, 0x9182, 0x0054, 0x1220, 0x9182,
+	0x0040, 0x0208, 0x000a, 0x0005, 0xbf80, 0xbf80, 0xbf80, 0xbf80,
+	0xbf80, 0xbf80, 0xbf80, 0xbf80, 0xbf80, 0xbf80, 0xbf80, 0xbf82,
+	0xbf82, 0xbf82, 0xbf82, 0xbf80, 0xbf80, 0xbf80, 0xbf82, 0xbf80,
+	0x080c, 0x0dd5, 0x600b, 0xffff, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x91b1, 0x0126, 0x2091, 0x8000, 0x080c, 0x9763, 0x012e, 0x0005,
+	0x9186, 0x0013, 0x1128, 0x6004, 0x9082, 0x0040, 0x0804, 0xc037,
+	0x9186, 0x0027, 0x1520, 0x080c, 0x9657, 0x080c, 0x321e, 0x080c,
+	0xd39d, 0x0096, 0x6114, 0x2148, 0x080c, 0xcc86, 0x0198, 0x080c,
+	0xce8e, 0x1118, 0x080c, 0xb905, 0x0068, 0xa867, 0x0103, 0xa87b,
+	0x0029, 0xa877, 0x0000, 0xa97c, 0xc1c5, 0xa97e, 0x080c, 0x6d17,
+	0x080c, 0xce71, 0x009e, 0x080c, 0xaf43, 0x0804, 0x9763, 0x9186,
+	0x0014, 0x1120, 0x6004, 0x9082, 0x0040, 0x04a0, 0x9186, 0x0046,
+	0x0150, 0x9186, 0x0045, 0x0138, 0x9186, 0x0053, 0x0120, 0x9186,
+	0x0048, 0x190c, 0x0dd5, 0x2001, 0x0109, 0x2004, 0xd084, 0x0508,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x0036, 0x00f6,
+	0x00e6, 0x00c6, 0x2079, 0x19e6, 0x2071, 0x1800, 0x2061, 0x0100,
+	0x080c, 0x9094, 0x00ce, 0x00ee, 0x00fe, 0x003e, 0x002e, 0x001e,
+	0x000e, 0x012e, 0xa001, 0x6000, 0x9086, 0x0002, 0x1110, 0x0804,
+	0xc075, 0x0005, 0x0002, 0xc011, 0xc00f, 0xc00f, 0xc00f, 0xc00f,
+	0xc00f, 0xc00f, 0xc00f, 0xc00f, 0xc00f, 0xc00f, 0xc02c, 0xc02c,
+	0xc02c, 0xc02c, 0xc00f, 0xc02c, 0xc00f, 0xc02c, 0xc00f, 0x080c,
+	0x0dd5, 0x080c, 0x9657, 0x0096, 0x6114, 0x2148, 0x080c, 0xcc86,
+	0x0168, 0xa867, 0x0103, 0xa87b, 0x0006, 0xa877, 0x0000, 0xa880,
+	0xc0ec, 0xa882, 0x080c, 0x6d17, 0x080c, 0xce71, 0x009e, 0x080c,
+	0xaf43, 0x080c, 0x9763, 0x0005, 0x080c, 0x9657, 0x080c, 0xce8e,
+	0x090c, 0xb905, 0x080c, 0xaf43, 0x080c, 0x9763, 0x0005, 0x0002,
+	0xc04e, 0xc04c, 0xc04c, 0xc04c, 0xc04c, 0xc04c, 0xc04c, 0xc04c,
+	0xc04c, 0xc04c, 0xc04c, 0xc065, 0xc065, 0xc065, 0xc065, 0xc04c,
+	0xc06f, 0xc04c, 0xc065, 0xc04c, 0x080c, 0x0dd5, 0x0096, 0x080c,
+	0x9657, 0x6014, 0x2048, 0x2001, 0x1987, 0x2004, 0x6042, 0xa97c,
+	0xd1ac, 0x0140, 0x6003, 0x0004, 0xa87c, 0x9085, 0x0400, 0xa87e,
+	0x009e, 0x0005, 0x6003, 0x0002, 0x0cb8, 0x080c, 0x9657, 0x080c,
+	0xd3a0, 0x080c, 0xd3a5, 0x6003, 0x000f, 0x0804, 0x9763, 0x080c,
+	0x9657, 0x080c, 0xaf43, 0x0804, 0x9763, 0x9182, 0x0054, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xc091, 0xc091, 0xc091,
+	0xc091, 0xc091, 0xc093, 0xc170, 0xc091, 0xc1a4, 0xc091, 0xc091,
+	0xc091, 0xc091, 0xc091, 0xc091, 0xc091, 0xc091, 0xc091, 0xc091,
+	0xc1a4, 0x080c, 0x0dd5, 0x00b6, 0x0096, 0x6114, 0x2148, 0x7644,
+	0x96b4, 0x0fff, 0x86ff, 0x1528, 0x6010, 0x2058, 0xb800, 0xd0bc,
+	0x1904, 0xc15f, 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76, 0xa87c,
+	0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xc33d, 0x080c,
+	0x6b33, 0x6210, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e,
+	0x7044, 0xd0e4, 0x1904, 0xc143, 0x080c, 0xaf43, 0x009e, 0x00be,
+	0x0005, 0x968c, 0x0c00, 0x0150, 0x6010, 0x2058, 0xb800, 0xd0bc,
+	0x1904, 0xc147, 0x7348, 0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff,
+	0x9186, 0x0002, 0x0508, 0x9186, 0x0028, 0x1118, 0xa87b, 0x001c,
+	0x00e8, 0xd6dc, 0x01a0, 0xa87b, 0x0015, 0xa87c, 0xd0ac, 0x0170,
+	0xa938, 0xaa34, 0x2100, 0x9205, 0x0148, 0x7048, 0x9106, 0x1118,
+	0x704c, 0x9206, 0x0118, 0xa992, 0xaa8e, 0xc6dc, 0x0038, 0xd6d4,
+	0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b, 0x0000, 0xa867, 0x0103,
+	0xae76, 0x901e, 0xd6c4, 0x01d8, 0x9686, 0x0100, 0x1130, 0x7064,
+	0x9005, 0x1118, 0xc6c4, 0x0804, 0xc09a, 0x735c, 0xab86, 0x83ff,
+	0x0170, 0x938a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308,
+	0x2019, 0x0018, 0x2011, 0x0025, 0x080c, 0xc837, 0x003e, 0xd6cc,
+	0x0904, 0xc0af, 0x7154, 0xa98a, 0x81ff, 0x0904, 0xc0af, 0x9192,
+	0x0021, 0x1278, 0x8304, 0x9098, 0x0018, 0x2011, 0x0029, 0x080c,
+	0xc837, 0x2011, 0x0205, 0x2013, 0x0000, 0x080c, 0xd32d, 0x0804,
+	0xc0af, 0xa868, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c50,
+	0x00a6, 0x2950, 0x080c, 0xc7d6, 0x00ae, 0x080c, 0xd32d, 0x080c,
+	0xc827, 0x0804, 0xc0b1, 0x080c, 0xcf86, 0x0804, 0xc0be, 0xa87c,
+	0xd0ac, 0x0904, 0xc0ca, 0xa880, 0xd0bc, 0x1904, 0xc0ca, 0x7348,
+	0xa838, 0x9306, 0x11c8, 0x734c, 0xa834, 0x931e, 0x0904, 0xc0ca,
+	0xd6d4, 0x0190, 0xab38, 0x9305, 0x0904, 0xc0ca, 0x0068, 0xa87c,
+	0xd0ac, 0x0904, 0xc0a2, 0xa838, 0xa934, 0x9105, 0x0904, 0xc0a2,
+	0xa880, 0xd0bc, 0x1904, 0xc0a2, 0x080c, 0xcfc0, 0x0804, 0xc0be,
+	0x0096, 0x00f6, 0x6003, 0x0003, 0x6007, 0x0043, 0x2079, 0x026c,
+	0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2048, 0xa87c, 0xd0ac,
+	0x0140, 0x6003, 0x0002, 0x00fe, 0x009e, 0x0005, 0x2130, 0x2228,
+	0x0058, 0x2400, 0xa9ac, 0x910a, 0x2300, 0xaab0, 0x9213, 0x2600,
+	0x9102, 0x2500, 0x9203, 0x0e90, 0xac36, 0xab3a, 0xae46, 0xad4a,
+	0x00fe, 0x6043, 0x0000, 0x2c10, 0x080c, 0x1beb, 0x080c, 0x9216,
+	0x080c, 0x9891, 0x009e, 0x0005, 0x0005, 0x9182, 0x0054, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xc1c1, 0xc1c1, 0xc1c1,
+	0xc1c1, 0xc1c1, 0xc1c3, 0xc259, 0xc1c1, 0xc1c1, 0xc270, 0xc300,
+	0xc1c1, 0xc1c1, 0xc1c1, 0xc1c1, 0xc315, 0xc1c1, 0xc1c1, 0xc1c1,
+	0xc1c1, 0x080c, 0x0dd5, 0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071,
+	0x0260, 0x6114, 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff, 0xb77c,
+	0xc7e5, 0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff, 0x0110,
+	0x8211, 0xba3e, 0x00be, 0x86ff, 0x0904, 0xc254, 0x9694, 0xff00,
+	0x9284, 0x0c00, 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e, 0x9284,
+	0x0300, 0x0904, 0xc254, 0x080c, 0x0fff, 0x090c, 0x0dd5, 0x2900,
+	0xb07a, 0xb77c, 0xc7cd, 0xb77e, 0xa867, 0x0103, 0xb068, 0xa86a,
+	0xb06c, 0xa86e, 0xb070, 0xa872, 0xae76, 0x968c, 0x0c00, 0x0120,
+	0x7348, 0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002,
+	0x0180, 0x9186, 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc,
+	0x0118, 0xa87b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007,
+	0x0010, 0xa87b, 0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886,
+	0x901e, 0xd6c4, 0x0190, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a,
+	0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018,
+	0x2011, 0x0025, 0x080c, 0xc837, 0x003e, 0xd6cc, 0x01e8, 0x7154,
+	0xa98a, 0x81ff, 0x01c8, 0x9192, 0x0021, 0x1260, 0x8304, 0x9098,
+	0x0018, 0x2011, 0x0029, 0x080c, 0xc837, 0x2011, 0x0205, 0x2013,
+	0x0000, 0x0050, 0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a,
+	0x0c68, 0x2950, 0x080c, 0xc7d6, 0x009e, 0x00ee, 0x00ae, 0x007e,
+	0x0005, 0x00f6, 0x00a6, 0x6003, 0x0003, 0x2079, 0x026c, 0x7c04,
+	0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2050, 0xb436, 0xb33a, 0xb646,
+	0xb54a, 0x00ae, 0x00fe, 0x2c10, 0x080c, 0x1beb, 0x0804, 0xa323,
+	0x6003, 0x0002, 0x6004, 0x9086, 0x0040, 0x11c8, 0x0096, 0x6014,
+	0x2048, 0xa87c, 0xd0ac, 0x0160, 0x601c, 0xd084, 0x1130, 0x00f6,
+	0x2c00, 0x2078, 0x080c, 0x1754, 0x00fe, 0x6003, 0x0004, 0x0010,
+	0x6003, 0x0002, 0x009e, 0x080c, 0x9657, 0x080c, 0x9763, 0x0096,
+	0x2001, 0x1987, 0x2004, 0x6042, 0x080c, 0x9713, 0x080c, 0x9891,
+	0x6114, 0x2148, 0xa97c, 0xd1e4, 0x0904, 0xc2fb, 0xd1cc, 0x05c8,
+	0xa978, 0xa868, 0xd0fc, 0x0540, 0x0016, 0xa87c, 0x0006, 0xa880,
+	0x0006, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0, 0x810e,
+	0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080,
+	0x0019, 0x2098, 0x0156, 0x20a9, 0x0020, 0x4003, 0x015e, 0x000e,
+	0xa882, 0x000e, 0xc0cc, 0xa87e, 0x001e, 0xa874, 0x0006, 0x2148,
+	0x080c, 0x0fb1, 0x001e, 0x0458, 0x0016, 0x080c, 0x0fb1, 0x009e,
+	0xa87c, 0xc0cc, 0xa87e, 0xa974, 0x0016, 0x080c, 0xc827, 0x001e,
+	0x00f0, 0xa867, 0x0103, 0xa974, 0x9184, 0x00ff, 0x90b6, 0x0002,
+	0x0180, 0x9086, 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd1dc,
+	0x0118, 0xa87b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0xa87b, 0x0007,
+	0x0010, 0xa87b, 0x0000, 0x0016, 0x080c, 0x6b33, 0x001e, 0xd1e4,
+	0x1120, 0x080c, 0xaf43, 0x009e, 0x0005, 0x080c, 0xcf86, 0x0cd8,
+	0x6004, 0x9086, 0x0040, 0x1120, 0x080c, 0x9657, 0x080c, 0x9763,
+	0x2019, 0x0001, 0x080c, 0xa6ac, 0x6003, 0x0002, 0x080c, 0xd3a5,
+	0x080c, 0x9713, 0x080c, 0x9891, 0x0005, 0x6004, 0x9086, 0x0040,
+	0x1120, 0x080c, 0x9657, 0x080c, 0x9763, 0x2019, 0x0001, 0x080c,
+	0xa6ac, 0x080c, 0x9713, 0x080c, 0x321e, 0x080c, 0xd39d, 0x0096,
+	0x6114, 0x2148, 0x080c, 0xcc86, 0x0150, 0xa867, 0x0103, 0xa87b,
+	0x0029, 0xa877, 0x0000, 0x080c, 0x6d17, 0x080c, 0xce71, 0x009e,
+	0x080c, 0xaf43, 0x080c, 0x9891, 0x0005, 0xa87b, 0x0015, 0xd1fc,
+	0x0180, 0xa87b, 0x0007, 0x8002, 0x8000, 0x810a, 0x9189, 0x0000,
+	0x0006, 0x0016, 0x2009, 0x1a79, 0x2104, 0x8000, 0x200a, 0x001e,
+	0x000e, 0xa992, 0xa88e, 0x0005, 0x9182, 0x0054, 0x1220, 0x9182,
+	0x0040, 0x0208, 0x000a, 0x0005, 0xc370, 0xc370, 0xc370, 0xc370,
+	0xc370, 0xc372, 0xc370, 0xc370, 0xc418, 0xc370, 0xc370, 0xc370,
+	0xc370, 0xc370, 0xc370, 0xc370, 0xc370, 0xc370, 0xc370, 0xc54a,
+	0x080c, 0x0dd5, 0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071, 0x0260,
+	0x6114, 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff, 0xb77c, 0xc7e5,
+	0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211,
+	0xba3e, 0x00be, 0x86ff, 0x0904, 0xc411, 0x9694, 0xff00, 0x9284,
+	0x0c00, 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e, 0x9284, 0x0300,
+	0x0904, 0xc411, 0x9686, 0x0100, 0x1130, 0x7064, 0x9005, 0x1118,
+	0xc6c4, 0xb676, 0x0c38, 0x080c, 0x0fff, 0x090c, 0x0dd5, 0x2900,
+	0xb07a, 0xb77c, 0x97bd, 0x0200, 0xb77e, 0xa867, 0x0103, 0xb068,
+	0xa86a, 0xb06c, 0xa86e, 0xb070, 0xa872, 0x7044, 0x9084, 0xf000,
+	0x9635, 0xae76, 0x968c, 0x0c00, 0x0120, 0x7348, 0xab92, 0x734c,
+	0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186, 0x0028,
+	0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0xa87b, 0x0015,
+	0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b, 0x0000,
+	0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886, 0x901e, 0xd6c4, 0x0190,
+	0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, 0x2019,
+	0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x2011, 0x0025, 0x080c,
+	0xc837, 0x003e, 0xd6cc, 0x01e8, 0x7154, 0xa98a, 0x81ff, 0x01c8,
+	0x9192, 0x0021, 0x1260, 0x8304, 0x9098, 0x0018, 0x2011, 0x0029,
+	0x080c, 0xc837, 0x2011, 0x0205, 0x2013, 0x0000, 0x0050, 0xb068,
+	0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c68, 0x2950, 0x080c,
+	0xc7d6, 0x080c, 0x1a6f, 0x009e, 0x00ee, 0x00ae, 0x007e, 0x0005,
+	0x2001, 0x1987, 0x2004, 0x6042, 0x0096, 0x6114, 0x2148, 0xa83c,
+	0xa940, 0x9105, 0x1118, 0xa87c, 0xc0dc, 0xa87e, 0x6003, 0x0002,
+	0xa97c, 0xd1e4, 0x0904, 0xc545, 0x6043, 0x0000, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x1500, 0xd1cc, 0x0904, 0xc514,
+	0xa978, 0xa868, 0xd0fc, 0x0904, 0xc4d5, 0x0016, 0xa87c, 0x0006,
+	0xa880, 0x0006, 0x00a6, 0x2150, 0xb174, 0x9184, 0x00ff, 0x90b6,
+	0x0002, 0x0904, 0xc4a2, 0x9086, 0x0028, 0x1904, 0xc48e, 0xa87b,
+	0x001c, 0xb07b, 0x001c, 0x0804, 0xc4aa, 0x6024, 0xd0f4, 0x11d0,
+	0xa838, 0xaa34, 0x9205, 0x09c8, 0xa838, 0xaa90, 0x9206, 0x1120,
+	0xa88c, 0xaa34, 0x9206, 0x0988, 0x6024, 0xd0d4, 0x1148, 0xa9ac,
+	0xa834, 0x9102, 0x603a, 0xa9b0, 0xa838, 0x9103, 0x603e, 0x6024,
+	0xc0f5, 0x6026, 0x6010, 0x00b6, 0x2058, 0xb83c, 0x8000, 0xb83e,
+	0x00be, 0x9006, 0xa876, 0xa892, 0xa88e, 0xa87c, 0xc0e4, 0xa87e,
+	0xd0cc, 0x0140, 0xc0cc, 0xa87e, 0x0096, 0xa878, 0x2048, 0x080c,
+	0x0fb1, 0x009e, 0x080c, 0xcfc0, 0x0804, 0xc545, 0xd1dc, 0x0158,
+	0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xd250, 0x0118, 0xb174,
+	0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, 0xb07b,
+	0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115,
+	0x190c, 0xc33d, 0xa87c, 0xb07e, 0xa890, 0xb092, 0xa88c, 0xb08e,
+	0xa860, 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0, 0x20a9, 0x0020,
+	0x8a06, 0x8006, 0x8007, 0x9094, 0x003f, 0x22e0, 0x9084, 0xffc0,
+	0x9080, 0x0019, 0x2098, 0x4003, 0x00ae, 0x000e, 0xa882, 0x000e,
+	0xc0cc, 0xa87e, 0x080c, 0xd32d, 0x001e, 0xa874, 0x0006, 0x2148,
+	0x080c, 0x0fb1, 0x001e, 0x0804, 0xc541, 0x0016, 0x00a6, 0x2150,
+	0xb174, 0x9184, 0x00ff, 0x90b6, 0x0002, 0x01e0, 0x9086, 0x0028,
+	0x1128, 0xa87b, 0x001c, 0xb07b, 0x001c, 0x00e0, 0xd1dc, 0x0158,
+	0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xd250, 0x0118, 0xb174,
+	0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, 0xb07b,
+	0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115,
+	0x190c, 0xc33d, 0xa890, 0xb092, 0xa88c, 0xb08e, 0xa87c, 0xb07e,
+	0x00ae, 0x080c, 0x0fb1, 0x009e, 0x080c, 0xd32d, 0xa974, 0x0016,
+	0x080c, 0xc827, 0x001e, 0x0468, 0xa867, 0x0103, 0xa974, 0x9184,
+	0x00ff, 0x90b6, 0x0002, 0x01b0, 0x9086, 0x0028, 0x1118, 0xa87b,
+	0x001c, 0x00d0, 0xd1dc, 0x0148, 0xa87b, 0x0015, 0x080c, 0xd250,
+	0x0118, 0xa974, 0xc1dc, 0xa976, 0x0078, 0xd1d4, 0x0118, 0xa87b,
+	0x0007, 0x0050, 0xa87b, 0x0000, 0xa87c, 0xd0ac, 0x0128, 0xa834,
+	0xa938, 0x9115, 0x190c, 0xc33d, 0xa974, 0x0016, 0x080c, 0x6b33,
+	0x001e, 0xd1e4, 0x1120, 0x080c, 0xaf43, 0x009e, 0x0005, 0x080c,
+	0xcf86, 0x0cd8, 0x6114, 0x0096, 0x2148, 0xa97c, 0xd1e4, 0x190c,
+	0x1a8d, 0x009e, 0x0005, 0x080c, 0x9657, 0x0010, 0x080c, 0x9713,
+	0x080c, 0xcc86, 0x01f0, 0x0096, 0x6114, 0x2148, 0x080c, 0xce8e,
+	0x1118, 0x080c, 0xb905, 0x00a0, 0xa867, 0x0103, 0x2009, 0x180c,
+	0x210c, 0xd18c, 0x11b8, 0xd184, 0x1190, 0x6108, 0xa97a, 0x918e,
+	0x0029, 0x1110, 0x080c, 0xea94, 0xa877, 0x0000, 0x080c, 0x6d17,
+	0x009e, 0x080c, 0xaf43, 0x080c, 0x9763, 0x0804, 0x9891, 0xa87b,
+	0x0004, 0x0c90, 0xa87b, 0x0004, 0x0c78, 0x9182, 0x0054, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xc5a1, 0xc5a1, 0xc5a1,
+	0xc5a1, 0xc5a1, 0xc5a3, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1,
+	0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1, 0xc5a1,
+	0xc5a1, 0x080c, 0x0dd5, 0x080c, 0x5765, 0x01f8, 0x6014, 0x7144,
+	0x918c, 0x0fff, 0x9016, 0xd1c4, 0x0118, 0x7264, 0x9294, 0x00ff,
+	0x0096, 0x904d, 0x0188, 0xa87b, 0x0000, 0xa864, 0x9086, 0x0139,
+	0x0128, 0xa867, 0x0103, 0xa976, 0xaa96, 0x0030, 0xa897, 0x4000,
+	0xa99a, 0xaa9e, 0x080c, 0x6d17, 0x009e, 0x0804, 0xaf43, 0x9182,
+	0x0085, 0x0002, 0xc5d9, 0xc5d7, 0xc5d7, 0xc5e5, 0xc5d7, 0xc5d7,
+	0xc5d7, 0xc5d7, 0xc5d7, 0xc5d7, 0xc5d7, 0xc5d7, 0xc5d7, 0x080c,
+	0x0dd5, 0x6003, 0x0001, 0x6106, 0x080c, 0x91b1, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x9763, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6,
+	0x00e6, 0x2071, 0x0260, 0x7224, 0x6216, 0x7220, 0x080c, 0xcc74,
+	0x01f8, 0x2268, 0x6800, 0x9086, 0x0000, 0x01d0, 0x6010, 0x6d10,
+	0x952e, 0x11b0, 0x00c6, 0x2d60, 0x00d6, 0x080c, 0xc898, 0x00de,
+	0x00ce, 0x0158, 0x702c, 0xd084, 0x1118, 0x080c, 0xc862, 0x0010,
+	0x6803, 0x0002, 0x6007, 0x0086, 0x0028, 0x080c, 0xc884, 0x0d90,
+	0x6007, 0x0087, 0x6003, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763,
+	0x7220, 0x080c, 0xcc74, 0x0178, 0x6810, 0x00b6, 0x2058, 0xb800,
+	0x00be, 0xd0bc, 0x0140, 0x6824, 0xd0ec, 0x0128, 0x00c6, 0x2d60,
+	0x080c, 0xcfc0, 0x00ce, 0x00ee, 0x00de, 0x005e, 0x002e, 0x0005,
+	0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0dd5,
+	0x908a, 0x0092, 0x1a0c, 0x0dd5, 0x9082, 0x0085, 0x00e2, 0x9186,
+	0x0027, 0x0120, 0x9186, 0x0014, 0x190c, 0x0dd5, 0x080c, 0x9657,
+	0x0096, 0x6014, 0x2048, 0x080c, 0xcc86, 0x0140, 0xa867, 0x0103,
+	0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6d17, 0x009e, 0x080c,
+	0xaf74, 0x0804, 0x9763, 0xc668, 0xc66a, 0xc66a, 0xc668, 0xc668,
+	0xc668, 0xc668, 0xc668, 0xc668, 0xc668, 0xc668, 0xc668, 0xc668,
+	0x080c, 0x0dd5, 0x080c, 0x9657, 0x080c, 0xaf74, 0x080c, 0x9763,
+	0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, 0x0085, 0x2008,
+	0x04b8, 0x9186, 0x0027, 0x11f8, 0x080c, 0x9657, 0x080c, 0x321e,
+	0x080c, 0xd39d, 0x0096, 0x6014, 0x2048, 0x080c, 0xcc86, 0x0150,
+	0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6d17,
+	0x080c, 0xce71, 0x009e, 0x080c, 0xaf43, 0x080c, 0x9763, 0x0005,
+	0x080c, 0xafd9, 0x0ce0, 0x9186, 0x0014, 0x1dd0, 0x080c, 0x9657,
+	0x0096, 0x6014, 0x2048, 0x080c, 0xcc86, 0x0d60, 0xa867, 0x0103,
+	0xa877, 0x0000, 0xa87b, 0x0006, 0xa880, 0xc0ec, 0xa882, 0x08f0,
+	0x0002, 0xc6c0, 0xc6be, 0xc6be, 0xc6be, 0xc6be, 0xc6be, 0xc6d8,
+	0xc6be, 0xc6be, 0xc6be, 0xc6be, 0xc6be, 0xc6be, 0x080c, 0x0dd5,
+	0x080c, 0x9657, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039,
+	0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x1985, 0x0010, 0x2001,
+	0x1986, 0x2004, 0x601a, 0x6003, 0x000c, 0x080c, 0x9763, 0x0005,
+	0x080c, 0x9657, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039,
+	0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x1985, 0x0010, 0x2001,
+	0x1986, 0x2004, 0x601a, 0x6003, 0x000e, 0x080c, 0x9763, 0x0005,
+	0x9182, 0x0092, 0x1220, 0x9182, 0x0085, 0x0208, 0x0012, 0x0804,
+	0xafd9, 0xc706, 0xc706, 0xc706, 0xc706, 0xc708, 0xc755, 0xc706,
+	0xc706, 0xc706, 0xc706, 0xc706, 0xc706, 0xc706, 0x080c, 0x0dd5,
+	0x0096, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0168,
+	0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118, 0x9186,
+	0x0035, 0x1118, 0x009e, 0x0804, 0xc769, 0x080c, 0xcc86, 0x1118,
+	0x080c, 0xce71, 0x0068, 0x6014, 0x2048, 0xa87c, 0xd0e4, 0x1110,
+	0x080c, 0xce71, 0xa867, 0x0103, 0x080c, 0xd368, 0x080c, 0x6d17,
+	0x00d6, 0x2c68, 0x080c, 0xaeed, 0x01d0, 0x6003, 0x0001, 0x6007,
+	0x001e, 0x600b, 0xffff, 0x2009, 0x026e, 0x210c, 0x613a, 0x2009,
+	0x026f, 0x210c, 0x613e, 0x6910, 0x6112, 0x080c, 0xd102, 0x6954,
+	0x6156, 0x6023, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x2d60,
+	0x00de, 0x080c, 0xaf43, 0x009e, 0x0005, 0x6010, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0bc, 0x05a0, 0x6034, 0x908c, 0xff00, 0x810f,
+	0x9186, 0x0035, 0x0130, 0x9186, 0x001e, 0x0118, 0x9186, 0x0039,
+	0x1538, 0x00d6, 0x2c68, 0x080c, 0xd300, 0x11f0, 0x080c, 0xaeed,
+	0x01d8, 0x6106, 0x6003, 0x0001, 0x6023, 0x0001, 0x6910, 0x6112,
+	0x692c, 0x612e, 0x6930, 0x6132, 0x6934, 0x918c, 0x00ff, 0x6136,
+	0x6938, 0x613a, 0x693c, 0x613e, 0x6954, 0x6156, 0x080c, 0xd102,
+	0x080c, 0x91b1, 0x080c, 0x9763, 0x2d60, 0x00de, 0x0804, 0xaf43,
+	0x0096, 0x6014, 0x2048, 0x080c, 0xcc86, 0x01c8, 0xa867, 0x0103,
+	0xa880, 0xd0b4, 0x0128, 0xc0ec, 0xa882, 0xa87b, 0x0006, 0x0048,
+	0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020, 0xa87b, 0x0005, 0x080c,
+	0xcf82, 0xa877, 0x0000, 0x080c, 0x6d17, 0x080c, 0xce71, 0x009e,
+	0x0804, 0xaf43, 0x0016, 0x0096, 0x6014, 0x2048, 0x080c, 0xcc86,
+	0x0140, 0xa867, 0x0103, 0xa87b, 0x0028, 0xa877, 0x0000, 0x080c,
+	0x6d17, 0x009e, 0x001e, 0x9186, 0x0013, 0x0148, 0x9186, 0x0014,
+	0x0130, 0x9186, 0x0027, 0x0118, 0x080c, 0xafd9, 0x0030, 0x080c,
+	0x9657, 0x080c, 0xaf74, 0x080c, 0x9763, 0x0005, 0x0056, 0x0066,
+	0x0096, 0x00a6, 0x2029, 0x0001, 0x9182, 0x0101, 0x1208, 0x0010,
+	0x2009, 0x0100, 0x2130, 0x8304, 0x9098, 0x0018, 0x2009, 0x0020,
+	0x2011, 0x0029, 0x080c, 0xc837, 0x96b2, 0x0020, 0xb004, 0x904d,
+	0x0110, 0x080c, 0x0fb1, 0x080c, 0x0fff, 0x0520, 0x8528, 0xa867,
+	0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a, 0x003d, 0x1228,
+	0x2608, 0x2011, 0x001b, 0x0499, 0x00a8, 0x96b2, 0x003c, 0x2009,
+	0x003c, 0x2950, 0x2011, 0x001b, 0x0451, 0x0c28, 0x2001, 0x0205,
+	0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0003, 0xb566, 0x95ac,
+	0x0000, 0x0048, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f,
+	0x95ad, 0x0003, 0xb566, 0x009e, 0x006e, 0x005e, 0x0005, 0x00a6,
+	0x89ff, 0x0158, 0xa804, 0x9055, 0x0130, 0xa807, 0x0000, 0x080c,
+	0x6d17, 0x2a48, 0x0cb8, 0x080c, 0x6d17, 0x00ae, 0x0005, 0x00f6,
+	0x2079, 0x0200, 0x7814, 0x9085, 0x0080, 0x7816, 0xd184, 0x0108,
+	0x8108, 0x810c, 0x20a9, 0x0001, 0xa860, 0x20e8, 0xa85c, 0x9200,
+	0x20a0, 0x20e1, 0x0000, 0x2300, 0x9e00, 0x2098, 0x4003, 0x8318,
+	0x9386, 0x0020, 0x1148, 0x2018, 0x2300, 0x9e00, 0x2098, 0x7814,
+	0x8000, 0x9085, 0x0080, 0x7816, 0x8109, 0x1d80, 0x7817, 0x0000,
+	0x00fe, 0x0005, 0x6920, 0x9186, 0x0003, 0x0118, 0x9186, 0x0002,
+	0x11d0, 0x00c6, 0x00d6, 0x00e6, 0x2d60, 0x0096, 0x6014, 0x2048,
+	0x080c, 0xcc86, 0x0150, 0x2001, 0x0006, 0xa980, 0xc1d5, 0x080c,
+	0x6f4a, 0x080c, 0x6d0b, 0x080c, 0xce71, 0x009e, 0x080c, 0xaf74,
+	0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x702c, 0xd084, 0x1170,
+	0x6008, 0x2060, 0x6020, 0x9086, 0x0002, 0x1140, 0x6104, 0x9186,
+	0x0085, 0x0118, 0x9186, 0x008b, 0x1108, 0x9006, 0x00ce, 0x0005,
+	0x0066, 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x6020, 0x9084,
+	0x000f, 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x0066, 0x2031, 0x0000, 0x6020, 0x9084, 0x000f, 0x001b, 0x006e,
+	0x012e, 0x0005, 0xc8d3, 0xc8d3, 0xc8ce, 0xc8f5, 0xc8c1, 0xc8ce,
+	0xc8f5, 0xc8ce, 0xc8c1, 0x8f95, 0xc8ce, 0xc8ce, 0xc8ce, 0xc8c1,
+	0xc8c1, 0x080c, 0x0dd5, 0x0036, 0x2019, 0x0010, 0x080c, 0xe2c0,
+	0x6023, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x9006, 0x0005,
+	0x9085, 0x0001, 0x0005, 0x0096, 0x86ff, 0x11d8, 0x6014, 0x2048,
+	0x080c, 0xcc86, 0x01c0, 0xa864, 0x9086, 0x0139, 0x1128, 0xa87b,
+	0x0005, 0xa883, 0x0000, 0x0028, 0x900e, 0x2001, 0x0005, 0x080c,
+	0x6f4a, 0x080c, 0xcf82, 0x080c, 0x6d0b, 0x080c, 0xaf74, 0x9085,
+	0x0001, 0x009e, 0x0005, 0x9006, 0x0ce0, 0x6000, 0x908a, 0x0016,
+	0x1a0c, 0x0dd5, 0x0002, 0xc90b, 0xc93b, 0xc90d, 0xc95c, 0xc936,
+	0xc90b, 0xc8ce, 0xc8d3, 0xc8d3, 0xc8ce, 0xc8ce, 0xc8ce, 0xc8ce,
+	0xc8ce, 0xc8ce, 0xc8ce, 0x080c, 0x0dd5, 0x86ff, 0x1520, 0x6020,
+	0x9086, 0x0006, 0x0500, 0x0096, 0x6014, 0x2048, 0x080c, 0xcc86,
+	0x0168, 0xa87c, 0xd0cc, 0x0140, 0x0096, 0xc0cc, 0xa87e, 0xa878,
+	0x2048, 0x080c, 0x0fb1, 0x009e, 0x080c, 0xcf82, 0x009e, 0x080c,
+	0xd342, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c,
+	0x91b1, 0x080c, 0x9763, 0x9085, 0x0001, 0x0005, 0x0066, 0x080c,
+	0x1aa1, 0x006e, 0x0890, 0x00e6, 0x2071, 0x19e6, 0x7024, 0x9c06,
+	0x1120, 0x080c, 0xa636, 0x00ee, 0x0840, 0x6020, 0x9084, 0x000f,
+	0x9086, 0x0006, 0x1150, 0x0086, 0x0096, 0x2049, 0x0001, 0x2c40,
+	0x080c, 0xa76b, 0x009e, 0x008e, 0x0010, 0x080c, 0xa533, 0x00ee,
+	0x1904, 0xc90d, 0x0804, 0xc8ce, 0x0036, 0x00e6, 0x2071, 0x19e6,
+	0x703c, 0x9c06, 0x1138, 0x901e, 0x080c, 0xa6ac, 0x00ee, 0x003e,
+	0x0804, 0xc90d, 0x080c, 0xa89b, 0x00ee, 0x003e, 0x1904, 0xc90d,
+	0x0804, 0xc8ce, 0x00c6, 0x6020, 0x9084, 0x000f, 0x0013, 0x00ce,
+	0x0005, 0xc98f, 0xca5a, 0xcbc4, 0xc999, 0xaf74, 0xc98f, 0xe2b2,
+	0xd3aa, 0xca5a, 0x8f67, 0xcc50, 0xc988, 0xc988, 0xc988, 0xc988,
+	0x080c, 0x0dd5, 0x080c, 0xce8e, 0x1110, 0x080c, 0xb905, 0x0005,
+	0x080c, 0x9657, 0x080c, 0x9763, 0x0804, 0xaf43, 0x601b, 0x0001,
+	0x0005, 0x080c, 0xcc86, 0x0130, 0x6014, 0x0096, 0x2048, 0x2c00,
+	0xa896, 0x009e, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dd5, 0x0002,
+	0xc9b8, 0xc9ba, 0xc9de, 0xc9f2, 0xca18, 0xc9b8, 0xc98f, 0xc98f,
+	0xc98f, 0xc9f2, 0xc9f2, 0xc9b8, 0xc9b8, 0xc9b8, 0xc9b8, 0xc9fc,
+	0x080c, 0x0dd5, 0x00e6, 0x6014, 0x0096, 0x2048, 0xa880, 0xc0b5,
+	0xa882, 0x009e, 0x2071, 0x19e6, 0x7024, 0x9c06, 0x01a0, 0x080c,
+	0xa533, 0x080c, 0xd342, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023,
+	0x0002, 0x2001, 0x1986, 0x2004, 0x601a, 0x080c, 0x91b1, 0x080c,
+	0x9763, 0x00ee, 0x0005, 0x601b, 0x0001, 0x0cd8, 0x0096, 0x6014,
+	0x2048, 0xa880, 0xc0b5, 0xa882, 0x009e, 0x080c, 0xd342, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x91b1, 0x080c,
+	0x9763, 0x0005, 0x0096, 0x601b, 0x0001, 0x6014, 0x2048, 0xa880,
+	0xc0b5, 0xa882, 0x009e, 0x0005, 0x080c, 0x5765, 0x01b8, 0x6014,
+	0x0096, 0x904d, 0x0190, 0xa864, 0xa867, 0x0103, 0xa87b, 0x0006,
+	0x9086, 0x0139, 0x1150, 0xa867, 0x0139, 0xa87b, 0x0030, 0xa897,
+	0x4005, 0xa89b, 0x0004, 0x080c, 0x6d17, 0x009e, 0x0804, 0xaf43,
+	0x6014, 0x0096, 0x904d, 0x05c8, 0xa97c, 0xd1e4, 0x05b0, 0x2001,
+	0x180f, 0x2004, 0xd0c4, 0x0110, 0x009e, 0x0005, 0xa884, 0x009e,
+	0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0x2001, 0x0030, 0x2c08,
+	0x080c, 0x15fd, 0x2001, 0x030c, 0x2004, 0x9086, 0x0041, 0x11a0,
+	0x6014, 0x0096, 0x904d, 0x090c, 0x0dd5, 0xa880, 0xd0f4, 0x1130,
+	0xc0f5, 0xa882, 0x009e, 0x601b, 0x0002, 0x0070, 0x009e, 0x2001,
+	0x0037, 0x2c08, 0x080c, 0x15fd, 0x6000, 0x9086, 0x0004, 0x1120,
+	0x2009, 0x0048, 0x080c, 0xafbe, 0x0005, 0x009e, 0x080c, 0x1aa1,
+	0x0804, 0xc9de, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dd5, 0x000b,
+	0x0005, 0xca71, 0xc996, 0xca73, 0xca71, 0xca73, 0xca73, 0xc990,
+	0xca71, 0xc98a, 0xc98a, 0xca71, 0xca71, 0xca71, 0xca71, 0xca71,
+	0xca71, 0x080c, 0x0dd5, 0x6010, 0x00b6, 0x2058, 0xb804, 0x9084,
+	0x00ff, 0x00be, 0x908a, 0x000c, 0x1a0c, 0x0dd5, 0x00b6, 0x0013,
+	0x00be, 0x0005, 0xca8e, 0xcb5b, 0xca90, 0xcad0, 0xca90, 0xcad0,
+	0xca90, 0xca9e, 0xca8e, 0xcad0, 0xca8e, 0xcabf, 0x080c, 0x0dd5,
+	0x6004, 0x908e, 0x0016, 0x05c0, 0x908e, 0x0004, 0x05a8, 0x908e,
+	0x0002, 0x0590, 0x908e, 0x0052, 0x0904, 0xcb57, 0x6004, 0x080c,
+	0xce8e, 0x0904, 0xcb74, 0x908e, 0x0004, 0x1110, 0x080c, 0x3247,
+	0x908e, 0x0021, 0x0904, 0xcb78, 0x908e, 0x0022, 0x0904, 0xcbbf,
+	0x908e, 0x003d, 0x0904, 0xcb78, 0x908e, 0x0039, 0x0904, 0xcb7c,
+	0x908e, 0x0035, 0x0904, 0xcb7c, 0x908e, 0x001e, 0x0178, 0x908e,
+	0x0001, 0x1140, 0x6010, 0x2058, 0xb804, 0x9084, 0x00ff, 0x9086,
+	0x0006, 0x0110, 0x080c, 0x321e, 0x080c, 0xb905, 0x0804, 0xaf74,
+	0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016, 0x0904, 0xcb48, 0x9186,
+	0x0002, 0x1904, 0xcb1d, 0x2001, 0x1837, 0x2004, 0xd08c, 0x11c8,
+	0x080c, 0x743e, 0x11b0, 0x080c, 0xd388, 0x0138, 0x080c, 0x7461,
+	0x1120, 0x080c, 0x7348, 0x0804, 0xcba8, 0x2001, 0x197c, 0x2003,
+	0x0001, 0x2001, 0x1800, 0x2003, 0x0001, 0x080c, 0x736a, 0x0804,
+	0xcba8, 0x6010, 0x2058, 0x2001, 0x1837, 0x2004, 0xd0ac, 0x1904,
+	0xcba8, 0xb8a0, 0x9084, 0xff80, 0x1904, 0xcba8, 0xb840, 0x9084,
+	0x00ff, 0x9005, 0x0190, 0x8001, 0xb842, 0x6017, 0x0000, 0x6023,
+	0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x080c, 0xaeed, 0x0128,
+	0x2b00, 0x6012, 0x6023, 0x0001, 0x0458, 0x00de, 0x00ce, 0x6004,
+	0x908e, 0x0002, 0x11a0, 0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e,
+	0x1170, 0x2009, 0x1837, 0x2104, 0xc085, 0x200a, 0x00e6, 0x2071,
+	0x1800, 0x080c, 0x6040, 0x00ee, 0x080c, 0xb905, 0x0030, 0x080c,
+	0xb905, 0x080c, 0x321e, 0x080c, 0xd39d, 0x00e6, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x3247, 0x012e, 0x00ee, 0x080c, 0xaf74, 0x0005,
+	0x2001, 0x0002, 0x080c, 0x65e9, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x91f9, 0x080c, 0x9763, 0x00de, 0x00ce, 0x0c80, 0x080c,
+	0x3247, 0x0804, 0xcacc, 0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016,
+	0x0d38, 0x6010, 0x2058, 0xb840, 0x9084, 0x00ff, 0x9005, 0x0904,
+	0xcb1d, 0x8001, 0xb842, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c,
+	0x9763, 0x00de, 0x00ce, 0x0898, 0x080c, 0xb905, 0x0804, 0xcace,
+	0x080c, 0xb941, 0x0804, 0xcace, 0x00d6, 0x2c68, 0x6104, 0x080c,
+	0xd300, 0x00de, 0x0118, 0x080c, 0xaf43, 0x0408, 0x6004, 0x8007,
+	0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x6023, 0x0002, 0x603c, 0x600a, 0x2001, 0x1986, 0x2004,
+	0x601a, 0x602c, 0x2c08, 0x2060, 0x6024, 0xd0b4, 0x0108, 0xc085,
+	0xc0b5, 0x6026, 0x2160, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0005,
+	0x00de, 0x00ce, 0x080c, 0xb905, 0x080c, 0x321e, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x3247, 0x6017, 0x0000, 0x6023, 0x0007,
+	0x601b, 0x0398, 0x6043, 0x0000, 0x012e, 0x00ee, 0x0005, 0x080c,
+	0xb374, 0x1904, 0xcb74, 0x0005, 0x6000, 0x908a, 0x0016, 0x1a0c,
+	0x0dd5, 0x0096, 0x00d6, 0x001b, 0x00de, 0x009e, 0x0005, 0xcbdf,
+	0xcbdf, 0xcbdf, 0xcbdf, 0xcbdf, 0xcbdf, 0xcbdf, 0xcbdf, 0xcbdf,
+	0xc98f, 0xcbdf, 0xc996, 0xcbe1, 0xc996, 0xcbfb, 0xcbdf, 0x080c,
+	0x0dd5, 0x6004, 0x9086, 0x008b, 0x01b0, 0x6034, 0x908c, 0xff00,
+	0x810f, 0x9186, 0x0035, 0x1130, 0x602c, 0x9080, 0x0009, 0x200c,
+	0xc185, 0x2102, 0x6007, 0x008b, 0x6003, 0x000d, 0x080c, 0x91b1,
+	0x080c, 0x9763, 0x0005, 0x080c, 0xd37c, 0x0118, 0x080c, 0xd38f,
+	0x0010, 0x080c, 0xd39d, 0x080c, 0xce71, 0x080c, 0xcc86, 0x0570,
+	0x080c, 0x321e, 0x080c, 0xcc86, 0x0168, 0x6014, 0x2048, 0xa867,
+	0x0103, 0xa87b, 0x0006, 0xa877, 0x0000, 0xa880, 0xc0ed, 0xa882,
+	0x080c, 0x6d17, 0x2c68, 0x080c, 0xaeed, 0x0150, 0x6810, 0x6012,
+	0x080c, 0xd102, 0x00c6, 0x2d60, 0x080c, 0xaf74, 0x00ce, 0x0008,
+	0x2d60, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001, 0x6003,
+	0x0001, 0x080c, 0x91f9, 0x080c, 0x9763, 0x00c8, 0x080c, 0xd37c,
+	0x0138, 0x6034, 0x9086, 0x4000, 0x1118, 0x080c, 0x321e, 0x08d0,
+	0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118, 0x9186,
+	0x0035, 0x1118, 0x080c, 0x321e, 0x0868, 0x080c, 0xaf74, 0x0005,
+	0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dd5, 0x0002, 0xcc66, 0xcc66,
+	0xcc68, 0xcc68, 0xcc68, 0xcc66, 0xcc66, 0xaf74, 0xcc66, 0xcc66,
+	0xcc66, 0xcc66, 0xcc66, 0xcc66, 0xcc66, 0xcc66, 0x080c, 0x0dd5,
+	0x080c, 0xa89b, 0x6114, 0x0096, 0x2148, 0xa87b, 0x0006, 0x080c,
+	0x6d17, 0x009e, 0x0804, 0xaf43, 0x9284, 0x0007, 0x1158, 0x9282,
+	0x1cd0, 0x0240, 0x2001, 0x181a, 0x2004, 0x9202, 0x1218, 0x9085,
+	0x0001, 0x0005, 0x9006, 0x0ce8, 0x0096, 0x0028, 0x0096, 0x0006,
+	0x6014, 0x2048, 0x000e, 0x0006, 0x9984, 0xf000, 0x9086, 0xf000,
+	0x0110, 0x080c, 0x10aa, 0x000e, 0x009e, 0x0005, 0x00e6, 0x00c6,
+	0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061, 0x1cd0, 0x2071,
+	0x1800, 0x7354, 0x7074, 0x9302, 0x1640, 0x6020, 0x9206, 0x11f8,
+	0x080c, 0xd388, 0x0180, 0x9286, 0x0001, 0x1168, 0x6004, 0x9086,
+	0x0004, 0x1148, 0x080c, 0x321e, 0x080c, 0xd39d, 0x00c6, 0x080c,
+	0xaf74, 0x00ce, 0x0060, 0x080c, 0xd07c, 0x0148, 0x080c, 0xce8e,
+	0x1110, 0x080c, 0xb905, 0x00c6, 0x080c, 0xaf43, 0x00ce, 0x9ce0,
+	0x0018, 0x7068, 0x9c02, 0x1208, 0x08a0, 0x012e, 0x000e, 0x003e,
+	0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0x9188, 0x1000,
+	0x210c, 0x81ff, 0x0128, 0x2061, 0x1ab2, 0x6112, 0x080c, 0x321e,
+	0x9006, 0x0010, 0x9085, 0x0001, 0x001e, 0x00ce, 0x00ee, 0x0005,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xaeed, 0x01b0, 0x6656,
+	0x2b00, 0x6012, 0x080c, 0x5765, 0x0118, 0x080c, 0xcdb5, 0x0168,
+	0x080c, 0xd102, 0x6023, 0x0003, 0x2009, 0x004b, 0x080c, 0xafbe,
+	0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0xbaa0, 0x080c, 0xaf91, 0x0560, 0x6057,
+	0x0000, 0x2b00, 0x6012, 0x080c, 0xd102, 0x6023, 0x0003, 0x0016,
+	0x080c, 0x9356, 0x0076, 0x903e, 0x080c, 0x9229, 0x2c08, 0x080c,
+	0xe477, 0x007e, 0x001e, 0xd184, 0x0128, 0x080c, 0xaf43, 0x9085,
+	0x0001, 0x0070, 0x080c, 0x5765, 0x0128, 0xd18c, 0x1170, 0x080c,
+	0xcdb5, 0x0148, 0x2009, 0x004c, 0x080c, 0xafbe, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2900, 0x6016, 0x0c90,
+	0x2009, 0x004d, 0x0010, 0x2009, 0x004e, 0x00f6, 0x00c6, 0x0046,
+	0x0016, 0x080c, 0xaeed, 0x2c78, 0x05a0, 0x7e56, 0x2b00, 0x7812,
+	0x7823, 0x0003, 0x0016, 0x2021, 0x0005, 0x080c, 0xcdc7, 0x001e,
+	0x9186, 0x004d, 0x0118, 0x9186, 0x004e, 0x0148, 0x2001, 0x197f,
+	0x200c, 0xd1fc, 0x0168, 0x2f60, 0x080c, 0xaf43, 0x00d0, 0x2001,
+	0x197e, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xaf43, 0x0088,
+	0x2f60, 0x080c, 0x5765, 0x0138, 0xd18c, 0x1118, 0x04f1, 0x0148,
+	0x0010, 0x2900, 0x7816, 0x001e, 0x0016, 0x080c, 0xafbe, 0x9085,
+	0x0001, 0x001e, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6,
+	0x0046, 0x080c, 0xaeed, 0x2c78, 0x0508, 0x7e56, 0x2b00, 0x7812,
+	0x7823, 0x0003, 0x0096, 0x2021, 0x0004, 0x0489, 0x009e, 0x2001,
+	0x197d, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xaf43, 0x0060,
+	0x2f60, 0x080c, 0x5765, 0x0120, 0xd18c, 0x1160, 0x0071, 0x0130,
+	0x2009, 0x0052, 0x080c, 0xafbe, 0x9085, 0x0001, 0x004e, 0x00ce,
+	0x00fe, 0x0005, 0x2900, 0x7816, 0x0c98, 0x00c6, 0x080c, 0x4b1f,
+	0x00ce, 0x1120, 0x080c, 0xaf43, 0x9006, 0x0005, 0xa867, 0x0000,
+	0xa86b, 0x8000, 0x2900, 0x6016, 0x9085, 0x0001, 0x0005, 0x0096,
+	0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0x67cd, 0x0158, 0x2001,
+	0xcdcc, 0x0006, 0x900e, 0x2400, 0x080c, 0x6f4a, 0x080c, 0x6d17,
+	0x000e, 0x0807, 0x2418, 0x080c, 0x95f1, 0xbaa0, 0x0086, 0x2041,
+	0x0001, 0x2039, 0x0001, 0x2608, 0x080c, 0x936e, 0x008e, 0x080c,
+	0x9229, 0x2f08, 0x2648, 0x080c, 0xe477, 0xb93c, 0x81ff, 0x090c,
+	0x9441, 0x080c, 0x9763, 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x080c, 0xaeed, 0x0190, 0x660a, 0x2b08,
+	0x6112, 0x080c, 0xd102, 0x6023, 0x0001, 0x2900, 0x6016, 0x2009,
+	0x001f, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xaf91,
+	0x01b8, 0x660a, 0x2b08, 0x6112, 0x080c, 0xd102, 0x6023, 0x0008,
+	0x2900, 0x6016, 0x00f6, 0x2c78, 0x080c, 0x1754, 0x00fe, 0x2009,
+	0x0021, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0x9006, 0x0cd8, 0x2009, 0x003d, 0x00c6, 0x0126, 0x0016, 0x2091,
+	0x8000, 0x080c, 0xaeed, 0x0198, 0x660a, 0x2b08, 0x6112, 0x080c,
+	0xd102, 0x6023, 0x0001, 0x2900, 0x6016, 0x001e, 0x0016, 0x080c,
+	0xafbe, 0x9085, 0x0001, 0x001e, 0x012e, 0x00ce, 0x0005, 0x9006,
+	0x0cd0, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xaf91, 0x0188,
+	0x2b08, 0x6112, 0x080c, 0xd102, 0x6023, 0x0001, 0x2900, 0x6016,
+	0x2009, 0x0000, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd8, 0x2009, 0x0044, 0x0830, 0x2009, 0x0049,
+	0x0818, 0x0026, 0x00b6, 0x6210, 0x2258, 0xba3c, 0x82ff, 0x0110,
+	0x8211, 0xba3e, 0x00be, 0x002e, 0x0005, 0x0006, 0x0016, 0x6004,
+	0x908e, 0x0002, 0x0140, 0x908e, 0x0003, 0x0128, 0x908e, 0x0004,
+	0x0110, 0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x0086,
+	0x0096, 0x6020, 0x9086, 0x0004, 0x01a8, 0x6014, 0x904d, 0x080c,
+	0xcc86, 0x0180, 0xa864, 0x9086, 0x0139, 0x0170, 0x6020, 0x90c6,
+	0x0003, 0x0140, 0x90c6, 0x0002, 0x0128, 0xa868, 0xd0fc, 0x0110,
+	0x9006, 0x0010, 0x9085, 0x0001, 0x009e, 0x008e, 0x000e, 0x0005,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xaf91, 0x0198, 0x2b08,
+	0x6112, 0x080c, 0xd102, 0x6023, 0x0001, 0x2900, 0x6016, 0x080c,
+	0x321e, 0x2009, 0x0028, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x9186, 0x0015, 0x11a8, 0x2011,
+	0x1824, 0x2204, 0x9086, 0x0074, 0x1178, 0x00b6, 0x080c, 0xbb59,
+	0x00be, 0x080c, 0xbd7c, 0x6003, 0x0001, 0x6007, 0x0029, 0x080c,
+	0x91f9, 0x080c, 0x9763, 0x0078, 0x6014, 0x0096, 0x2048, 0xa868,
+	0x009e, 0xd0fc, 0x0148, 0x2001, 0x0001, 0x080c, 0xd2c1, 0x080c,
+	0xb905, 0x080c, 0xaf43, 0x0005, 0x0096, 0x6014, 0x904d, 0x090c,
+	0x0dd5, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005, 0xa89b,
+	0x0004, 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17,
+	0x012e, 0x009e, 0x080c, 0xaf43, 0x0c30, 0x0096, 0x9186, 0x0016,
+	0x1128, 0x2001, 0x0004, 0x080c, 0x65e9, 0x00e8, 0x9186, 0x0015,
+	0x1510, 0x2011, 0x1824, 0x2204, 0x9086, 0x0014, 0x11e0, 0x6010,
+	0x00b6, 0x2058, 0x080c, 0x6734, 0x00be, 0x080c, 0xbe4d, 0x1198,
+	0x6010, 0x00b6, 0x2058, 0xb890, 0x00be, 0x9005, 0x0160, 0x2001,
+	0x0006, 0x080c, 0x65e9, 0x6014, 0x2048, 0xa868, 0xd0fc, 0x0170,
+	0x080c, 0xb348, 0x0048, 0x6014, 0x2048, 0xa868, 0xd0fc, 0x0528,
+	0x080c, 0xb905, 0x080c, 0xaf43, 0x009e, 0x0005, 0x6014, 0x6310,
+	0x2358, 0x904d, 0x090c, 0x0dd5, 0xa87b, 0x0000, 0xa883, 0x0000,
+	0xa897, 0x4000, 0x900e, 0x080c, 0x68b9, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0xa99a, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6d17, 0x012e, 0x080c, 0xaf43, 0x08f8, 0x6014, 0x904d, 0x090c,
+	0x0dd5, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005, 0xa89b,
+	0x0004, 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17,
+	0x012e, 0x080c, 0xaf43, 0x0840, 0xa878, 0x9086, 0x0005, 0x1108,
+	0x0009, 0x0005, 0xa880, 0xc0ad, 0xa882, 0x0005, 0x6043, 0x0000,
+	0x6017, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c, 0x91b1,
+	0x080c, 0x9763, 0x0005, 0x00c6, 0x6010, 0x00b6, 0x2058, 0xb800,
+	0x00be, 0xd0bc, 0x0120, 0x6020, 0x9084, 0x000f, 0x0013, 0x00ce,
+	0x0005, 0xc98f, 0xcfb2, 0xcfb2, 0xcfb5, 0xe789, 0xe7a4, 0xe7a7,
+	0xc98f, 0xc98f, 0xc98f, 0xc98f, 0xc98f, 0xc98f, 0xc98f, 0xc98f,
+	0x080c, 0x0dd5, 0xa001, 0xa001, 0x0005, 0x0096, 0x6014, 0x904d,
+	0x0118, 0xa87c, 0xd0e4, 0x1110, 0x009e, 0x0010, 0x009e, 0x0005,
+	0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0550, 0x2001,
+	0x1834, 0x2004, 0x9005, 0x1540, 0x00f6, 0x2c78, 0x080c, 0xaeed,
+	0x0508, 0x7810, 0x6012, 0x080c, 0xd102, 0x7820, 0x9086, 0x0003,
+	0x0128, 0x7808, 0x603a, 0x2f00, 0x603e, 0x0020, 0x7808, 0x603e,
+	0x2f00, 0x603a, 0x602e, 0x6023, 0x0001, 0x6007, 0x0035, 0x6003,
+	0x0001, 0x7954, 0x6156, 0x080c, 0x91b1, 0x080c, 0x9763, 0x2f60,
+	0x00fe, 0x0005, 0x2f60, 0x00fe, 0x2001, 0x1987, 0x2004, 0x6042,
+	0x0005, 0x0016, 0x0096, 0x6814, 0x2048, 0xa87c, 0xd0e4, 0x0180,
+	0xc0e4, 0xa87e, 0xa877, 0x0000, 0xa893, 0x0000, 0xa88f, 0x0000,
+	0xd0cc, 0x0130, 0xc0cc, 0xa87e, 0xa878, 0x2048, 0x080c, 0x0fb1,
+	0x6830, 0x6036, 0x908e, 0x0001, 0x0148, 0x6803, 0x0002, 0x9086,
+	0x0005, 0x0170, 0x9006, 0x602e, 0x6032, 0x00d0, 0x681c, 0xc085,
+	0x681e, 0x6803, 0x0004, 0x6824, 0xc0f4, 0x9085, 0x0c00, 0x6826,
+	0x6814, 0x2048, 0xa8ac, 0x6938, 0x9102, 0xa8b0, 0x693c, 0x9103,
+	0x1e48, 0x683c, 0x602e, 0x6838, 0x9084, 0xfffc, 0x683a, 0x6032,
+	0x2d00, 0x603a, 0x6808, 0x603e, 0x6910, 0x6112, 0x6954, 0x6156,
+	0x6023, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x080c, 0x91b1,
+	0x080c, 0x9763, 0x009e, 0x001e, 0x0005, 0x6024, 0xd0d4, 0x0510,
+	0xd0f4, 0x11f8, 0x6038, 0x940a, 0x603c, 0x9303, 0x0230, 0x9105,
+	0x0120, 0x6024, 0xc0d4, 0xc0f5, 0x0098, 0x643a, 0x633e, 0xac3e,
+	0xab42, 0x0046, 0x0036, 0x2400, 0xacac, 0x9402, 0xa836, 0x2300,
+	0xabb0, 0x9303, 0xa83a, 0x003e, 0x004e, 0x6024, 0xc0d4, 0x0000,
+	0x6026, 0x0005, 0xd0f4, 0x1138, 0xa83c, 0x603a, 0xa840, 0x603e,
+	0x6024, 0xc0f5, 0x6026, 0x0005, 0x0006, 0x0016, 0x6004, 0x908e,
+	0x0034, 0x01b8, 0x908e, 0x0035, 0x01a0, 0x908e, 0x0036, 0x0188,
+	0x908e, 0x0037, 0x0170, 0x908e, 0x0038, 0x0158, 0x908e, 0x0039,
+	0x0140, 0x908e, 0x003a, 0x0128, 0x908e, 0x003b, 0x0110, 0x9085,
+	0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036,
+	0x00e6, 0x2001, 0x1981, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032,
+	0x080c, 0x9027, 0x2001, 0x1985, 0x82ff, 0x1110, 0x2011, 0x0014,
+	0x2202, 0x2001, 0x1983, 0x200c, 0x8000, 0x2014, 0x2071, 0x196b,
+	0x711a, 0x721e, 0x2001, 0x0064, 0x080c, 0x9027, 0x2001, 0x1986,
+	0x82ff, 0x1110, 0x2011, 0x0014, 0x2202, 0x2001, 0x1987, 0x9288,
+	0x000a, 0x2102, 0x2001, 0x1a93, 0x2102, 0x2001, 0x0032, 0x080c,
+	0x15fd, 0x080c, 0x69ed, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e,
+	0x0005, 0x0006, 0x0016, 0x00e6, 0x2001, 0x1985, 0x2003, 0x0028,
+	0x2001, 0x1986, 0x2003, 0x0014, 0x2071, 0x196b, 0x701b, 0x0000,
+	0x701f, 0x07d0, 0x2001, 0x1987, 0x2009, 0x001e, 0x2102, 0x2001,
+	0x1a93, 0x2102, 0x2001, 0x0032, 0x080c, 0x15fd, 0x00ee, 0x001e,
+	0x000e, 0x0005, 0x0096, 0x6058, 0x904d, 0x0110, 0x080c, 0x1031,
+	0x009e, 0x0005, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c,
+	0xaeed, 0x0180, 0x2b08, 0x6112, 0x0ca9, 0x6023, 0x0001, 0x2900,
+	0x6016, 0x2009, 0x0033, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x0096, 0x00e6, 0x00f6, 0x2071,
+	0x1800, 0x9186, 0x0015, 0x1500, 0x7090, 0x9086, 0x0018, 0x11e0,
+	0x6014, 0x2048, 0xaa3c, 0xd2e4, 0x1160, 0x2c78, 0x080c, 0x99f9,
+	0x01d8, 0x707c, 0xaa50, 0x9206, 0x1160, 0x7080, 0xaa54, 0x9206,
+	0x1140, 0x6210, 0x00b6, 0x2258, 0xbaa0, 0x00be, 0x900e, 0x080c,
+	0x3267, 0x080c, 0xb348, 0x0020, 0x080c, 0xb905, 0x080c, 0xaf43,
+	0x00fe, 0x00ee, 0x009e, 0x0005, 0x7060, 0xaa54, 0x9206, 0x0d48,
+	0x0c80, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xaeed, 0x0188,
+	0x2b08, 0x6112, 0x080c, 0xd102, 0x6023, 0x0001, 0x2900, 0x6016,
+	0x2009, 0x004d, 0x080c, 0xafbe, 0x9085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x0016,
+	0x080c, 0xaeed, 0x0180, 0x2b08, 0x6112, 0x080c, 0xd102, 0x6023,
+	0x0001, 0x2900, 0x6016, 0x001e, 0x080c, 0xafbe, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x001e, 0x9006, 0x0cd0, 0x0016, 0x0026,
+	0x0036, 0x0046, 0x0056, 0x0066, 0x0096, 0x00e6, 0x00f6, 0x2071,
+	0x1800, 0x9186, 0x0015, 0x1568, 0x7190, 0x6014, 0x2048, 0xa814,
+	0x8003, 0x9106, 0x1530, 0x20e1, 0x0000, 0x2001, 0x199f, 0x2003,
+	0x0000, 0x6014, 0x2048, 0xa830, 0x20a8, 0x8906, 0x8006, 0x8007,
+	0x9094, 0x003f, 0x22e8, 0x9084, 0xffc0, 0x9080, 0x001b, 0x20a0,
+	0x2001, 0x199f, 0x0016, 0x200c, 0x080c, 0xd99b, 0x001e, 0xa804,
+	0x9005, 0x0110, 0x2048, 0x0c38, 0x6014, 0x2048, 0xa867, 0x0103,
+	0x0010, 0x080c, 0xb905, 0x080c, 0xaf43, 0x00fe, 0x00ee, 0x009e,
+	0x006e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005, 0x0096,
+	0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x11b8, 0x7090,
+	0x9086, 0x0004, 0x1198, 0x6014, 0x2048, 0x2c78, 0x080c, 0x99f9,
+	0x01a8, 0x707c, 0xaa74, 0x9206, 0x1130, 0x7080, 0xaa78, 0x9206,
+	0x1110, 0x080c, 0x321e, 0x080c, 0xb348, 0x0020, 0x080c, 0xb905,
+	0x080c, 0xaf43, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x7060, 0xaa78,
+	0x9206, 0x0d78, 0x0c80, 0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800,
+	0x9186, 0x0015, 0x1550, 0x7090, 0x9086, 0x0004, 0x1530, 0x6014,
+	0x2048, 0x2c78, 0x080c, 0x99f9, 0x05f0, 0x707c, 0xaacc, 0x9206,
+	0x1180, 0x7080, 0xaad0, 0x9206, 0x1160, 0x080c, 0x321e, 0x0016,
+	0xa998, 0xaab0, 0x9284, 0x1000, 0xc0fd, 0x080c, 0x570c, 0x001e,
+	0x0010, 0x080c, 0x54f7, 0x080c, 0xcc86, 0x0508, 0xa87b, 0x0000,
+	0xa883, 0x0000, 0xa897, 0x4000, 0x0080, 0x080c, 0xcc86, 0x01b8,
+	0x6014, 0x2048, 0x080c, 0x54f7, 0x1d70, 0xa87b, 0x0030, 0xa883,
+	0x0000, 0xa897, 0x4005, 0xa89b, 0x0004, 0x0126, 0x2091, 0x8000,
+	0xa867, 0x0139, 0x080c, 0x6d17, 0x012e, 0x080c, 0xaf43, 0x00fe,
+	0x00ee, 0x009e, 0x0005, 0x7060, 0xaad0, 0x9206, 0x0930, 0x0888,
+	0x0016, 0x0026, 0xa87c, 0xd0ac, 0x0178, 0xa938, 0xaa34, 0x2100,
+	0x9205, 0x0150, 0xa890, 0x9106, 0x1118, 0xa88c, 0x9206, 0x0120,
+	0xa992, 0xaa8e, 0x9085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00b6,
+	0x00d6, 0x0036, 0x080c, 0xcc86, 0x0904, 0xd2bd, 0x0096, 0x6314,
+	0x2348, 0xa87a, 0xa982, 0x929e, 0x4000, 0x1580, 0x6310, 0x00c6,
+	0x2358, 0x2009, 0x0000, 0xa868, 0xd0f4, 0x1140, 0x080c, 0x68b9,
+	0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0xaa96, 0xa99a,
+	0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0031, 0x20a0,
+	0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x0006, 0x2098, 0x080c, 0x0f7c,
+	0x20a9, 0x0004, 0xa85c, 0x9080, 0x0035, 0x20a0, 0xb8c8, 0x9080,
+	0x000a, 0x2098, 0x080c, 0x0f7c, 0x00ce, 0x0090, 0xaa96, 0x3918,
+	0x9398, 0x0007, 0x231c, 0x6004, 0x9086, 0x0016, 0x0110, 0xa89b,
+	0x0004, 0xaba2, 0x6310, 0x2358, 0xb804, 0x9084, 0x00ff, 0xa89e,
+	0x080c, 0x6d0b, 0x6017, 0x0000, 0x009e, 0x003e, 0x00de, 0x00be,
+	0x0005, 0x0026, 0x0036, 0x0046, 0x00b6, 0x0096, 0x00f6, 0x6214,
+	0x2248, 0x6210, 0x2258, 0x2079, 0x0260, 0x9096, 0x0000, 0x11a0,
+	0xb814, 0x9084, 0x00ff, 0x900e, 0x080c, 0x287c, 0x2118, 0x831f,
+	0x939c, 0xff00, 0x7838, 0x9084, 0x00ff, 0x931d, 0x7c3c, 0x2011,
+	0x8018, 0x080c, 0x4b7f, 0x00a8, 0x9096, 0x0001, 0x1148, 0x89ff,
+	0x0180, 0xa89b, 0x000d, 0x7838, 0xa8a6, 0x783c, 0xa8aa, 0x0048,
+	0x9096, 0x0002, 0x1130, 0xa89b, 0x000d, 0x7838, 0xa8a6, 0x783c,
+	0xa8aa, 0x00fe, 0x009e, 0x00be, 0x004e, 0x003e, 0x002e, 0x0005,
+	0x00c6, 0x0026, 0x0016, 0x9186, 0x0035, 0x0110, 0x6a38, 0x0008,
+	0x6a2c, 0x080c, 0xcc74, 0x01f0, 0x2260, 0x6120, 0x9186, 0x0003,
+	0x0118, 0x9186, 0x0006, 0x1190, 0x6838, 0x9206, 0x0140, 0x683c,
+	0x9206, 0x1160, 0x6108, 0x6838, 0x9106, 0x1140, 0x0020, 0x6008,
+	0x693c, 0x9106, 0x1118, 0x6010, 0x6910, 0x9106, 0x001e, 0x002e,
+	0x00ce, 0x0005, 0x9085, 0x0001, 0x0cc8, 0xa974, 0xd1cc, 0x0188,
+	0x918c, 0x00ff, 0x918e, 0x0002, 0x1160, 0xa9a8, 0x918c, 0x0f00,
+	0x810f, 0x918e, 0x0001, 0x1128, 0xa834, 0xa938, 0x9115, 0x190c,
+	0xc33d, 0x0005, 0x0036, 0x2019, 0x0001, 0x0010, 0x0036, 0x901e,
+	0x0499, 0x01e0, 0x080c, 0xcc86, 0x01c8, 0x080c, 0xce71, 0x6037,
+	0x4000, 0x6014, 0x6017, 0x0000, 0x0096, 0x2048, 0xa87c, 0x080c,
+	0xce8e, 0x1118, 0x080c, 0xb905, 0x0040, 0xa867, 0x0103, 0xa877,
+	0x0000, 0x83ff, 0x1129, 0x080c, 0x6d17, 0x009e, 0x003e, 0x0005,
+	0xa880, 0xd0b4, 0x0128, 0xa87b, 0x0006, 0xc0ec, 0xa882, 0x0048,
+	0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020, 0xa87b, 0x0005, 0x080c,
+	0xcf82, 0xa877, 0x0000, 0x0005, 0x2001, 0x1810, 0x2004, 0xd0ec,
+	0x0005, 0x0006, 0x2001, 0x1810, 0x2004, 0xd0f4, 0x000e, 0x0005,
+	0x0006, 0x2001, 0x1810, 0x2004, 0xd0e4, 0x000e, 0x0005, 0x0036,
+	0x0046, 0x6010, 0x00b6, 0x2058, 0xbba0, 0x00be, 0x2021, 0x0007,
+	0x080c, 0x4d36, 0x004e, 0x003e, 0x0005, 0x0c51, 0x1d81, 0x0005,
+	0x2001, 0x1985, 0x2004, 0x601a, 0x0005, 0x2001, 0x1987, 0x2004,
+	0x6042, 0x0005, 0x080c, 0xaf43, 0x0804, 0x9763, 0x00b6, 0x0066,
+	0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0dd5, 0x001b, 0x006e, 0x00be,
+	0x0005, 0xd3c9, 0xdaf8, 0xdc55, 0xd3c9, 0xd3c9, 0xd3c9, 0xd3c9,
+	0xd3c9, 0xd400, 0xdcd9, 0xd3c9, 0xd3c9, 0xd3c9, 0xd3c9, 0xd3c9,
+	0xd3c9, 0x080c, 0x0dd5, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c,
+	0x0dd5, 0x0013, 0x006e, 0x0005, 0xd3e4, 0xe24b, 0xd3e4, 0xd3e4,
+	0xd3e4, 0xd3e4, 0xd3e4, 0xd3e4, 0xe1f8, 0xe29f, 0xd3e4, 0xe8c4,
+	0xe8fa, 0xe8c4, 0xe8fa, 0xd3e4, 0x080c, 0x0dd5, 0x6000, 0x9082,
+	0x0016, 0x1a0c, 0x0dd5, 0x6000, 0x000a, 0x0005, 0xd3fe, 0xdeb7,
+	0xdfa9, 0xdfcc, 0xe08c, 0xd3fe, 0xe16b, 0xe114, 0xdce5, 0xe1ce,
+	0xe1e3, 0xd3fe, 0xd3fe, 0xd3fe, 0xd3fe, 0xd3fe, 0x080c, 0x0dd5,
+	0x91b2, 0x0053, 0x1a0c, 0x0dd5, 0x2100, 0x91b2, 0x0040, 0x1a04,
+	0xd86c, 0x0002, 0xd44a, 0xd63a, 0xd44a, 0xd44a, 0xd44a, 0xd643,
+	0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a,
+	0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a,
+	0xd44a, 0xd44c, 0xd4af, 0xd4be, 0xd522, 0xd54d, 0xd5c6, 0xd625,
+	0xd44a, 0xd44a, 0xd646, 0xd44a, 0xd44a, 0xd65b, 0xd668, 0xd44a,
+	0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd70e, 0xd44a, 0xd44a, 0xd722,
+	0xd44a, 0xd44a, 0xd6dd, 0xd44a, 0xd44a, 0xd44a, 0xd73a, 0xd44a,
+	0xd44a, 0xd44a, 0xd7b7, 0xd44a, 0xd44a, 0xd44a, 0xd44a, 0xd44a,
+	0xd44a, 0xd834, 0x080c, 0x0dd5, 0x080c, 0x69ca, 0x1150, 0x2001,
+	0x1837, 0x2004, 0xd0cc, 0x1128, 0x9084, 0x0009, 0x9086, 0x0008,
+	0x1140, 0x6007, 0x0009, 0x602f, 0x0009, 0x6017, 0x0000, 0x0804,
+	0xd633, 0x080c, 0x6966, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016,
+	0x6210, 0x2258, 0xbaa0, 0x0026, 0x2019, 0x0029, 0x080c, 0x9356,
+	0x0076, 0x903e, 0x080c, 0x9229, 0x2c08, 0x080c, 0xe477, 0x007e,
+	0x001e, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x6610, 0x2658,
+	0x080c, 0x66a8, 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006, 0x1268,
+	0x0016, 0x0026, 0x6210, 0x00b6, 0x2258, 0xbaa0, 0x00be, 0x2c08,
+	0x080c, 0xeb23, 0x002e, 0x001e, 0x1178, 0x080c, 0xe3a9, 0x1904,
+	0xd51a, 0x080c, 0xe345, 0x1120, 0x6007, 0x0008, 0x0804, 0xd633,
+	0x6007, 0x0009, 0x0804, 0xd633, 0x080c, 0xe5cd, 0x0128, 0x080c,
+	0xe3a9, 0x0d78, 0x0804, 0xd51a, 0x6017, 0x1900, 0x0c88, 0x080c,
+	0x3342, 0x1904, 0xd869, 0x6106, 0x080c, 0xe2fa, 0x6007, 0x0006,
+	0x0804, 0xd633, 0x6007, 0x0007, 0x0804, 0xd633, 0x080c, 0xe936,
+	0x1904, 0xd869, 0x080c, 0x3342, 0x1904, 0xd869, 0x00d6, 0x6610,
+	0x2658, 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006, 0x1220, 0x2001,
+	0x0001, 0x080c, 0x65d5, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006,
+	0x0188, 0x9686, 0x0004, 0x0170, 0xbe04, 0x96b4, 0x00ff, 0x9686,
+	0x0006, 0x0140, 0x9686, 0x0004, 0x0128, 0x9686, 0x0005, 0x0110,
+	0x00de, 0x0480, 0x00e6, 0x2071, 0x0260, 0x7034, 0x9084, 0x0003,
+	0x1140, 0x7034, 0x9082, 0x0014, 0x0220, 0x7030, 0x9084, 0x0003,
+	0x0130, 0x00ee, 0x6017, 0x0000, 0x602f, 0x0007, 0x00b0, 0x00ee,
+	0x080c, 0xe40d, 0x1190, 0x9686, 0x0006, 0x1140, 0x0026, 0x6210,
+	0x2258, 0xbaa0, 0x900e, 0x080c, 0x3267, 0x002e, 0x080c, 0x6734,
+	0x6007, 0x000a, 0x00de, 0x0804, 0xd633, 0x6007, 0x000b, 0x00de,
+	0x0804, 0xd633, 0x080c, 0x321e, 0x080c, 0xd39d, 0x6007, 0x0001,
+	0x0804, 0xd633, 0x080c, 0xe936, 0x1904, 0xd869, 0x080c, 0x3342,
+	0x1904, 0xd869, 0x2071, 0x0260, 0x7034, 0x90b4, 0x0003, 0x1948,
+	0x90b2, 0x0014, 0x0a30, 0x7030, 0x9084, 0x0003, 0x1910, 0x6610,
+	0x2658, 0xbe04, 0x9686, 0x0707, 0x09e8, 0x0026, 0x6210, 0x2258,
+	0xbaa0, 0x900e, 0x080c, 0x3267, 0x002e, 0x6007, 0x000c, 0x2001,
+	0x0001, 0x080c, 0xeb03, 0x0804, 0xd633, 0x080c, 0x69ca, 0x1140,
+	0x2001, 0x1837, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x1110,
+	0x0804, 0xd459, 0x080c, 0x6966, 0x6610, 0x2658, 0xbe04, 0x9684,
+	0x00ff, 0x9082, 0x0006, 0x06c8, 0x1138, 0x0026, 0x2001, 0x0006,
+	0x080c, 0x6615, 0x002e, 0x0050, 0x96b4, 0xff00, 0x8637, 0x9686,
+	0x0004, 0x0120, 0x9686, 0x0006, 0x1904, 0xd51a, 0x080c, 0xe41a,
+	0x1120, 0x6007, 0x000e, 0x0804, 0xd633, 0x0046, 0x6410, 0x2458,
+	0xbca0, 0x0046, 0x080c, 0x321e, 0x080c, 0xd39d, 0x004e, 0x0016,
+	0x9006, 0x2009, 0x1848, 0x210c, 0xd1a4, 0x0148, 0x2009, 0x0029,
+	0x080c, 0xe73a, 0x6010, 0x2058, 0xb800, 0xc0e5, 0xb802, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x0804, 0xd633, 0x2001, 0x0001, 0x080c,
+	0x65d5, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0x1805, 0x2011, 0x0270, 0x080c, 0xbefd, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x9005, 0x0168, 0x96b4, 0xff00, 0x8637, 0x9682, 0x0004,
+	0x0a04, 0xd51a, 0x9682, 0x0007, 0x0a04, 0xd576, 0x0804, 0xd51a,
+	0x6017, 0x1900, 0x6007, 0x0009, 0x0804, 0xd633, 0x080c, 0x69ca,
+	0x1140, 0x2001, 0x1837, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008,
+	0x1110, 0x0804, 0xd459, 0x080c, 0x6966, 0x6610, 0x2658, 0xbe04,
+	0x9684, 0x00ff, 0x0006, 0x9086, 0x0001, 0x000e, 0x0170, 0x9082,
+	0x0006, 0x0698, 0x0150, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0004,
+	0x0120, 0x9686, 0x0006, 0x1904, 0xd51a, 0x080c, 0xe448, 0x1130,
+	0x080c, 0xe345, 0x1118, 0x6007, 0x0010, 0x04e8, 0x0046, 0x6410,
+	0x2458, 0xbca0, 0x0046, 0x080c, 0x321e, 0x080c, 0xd39d, 0x004e,
+	0x0016, 0x9006, 0x2009, 0x1848, 0x210c, 0xd1a4, 0x0148, 0x2009,
+	0x0029, 0x080c, 0xe73a, 0x6010, 0x2058, 0xb800, 0xc0e5, 0xb802,
+	0x001e, 0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xe5cd, 0x0140,
+	0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x0978, 0x0804, 0xd51a,
+	0x6017, 0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x3342, 0x1904,
+	0xd869, 0x080c, 0xe936, 0x1904, 0xd869, 0x080c, 0xda36, 0x1904,
+	0xd51a, 0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c,
+	0x9763, 0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x91f9,
+	0x080c, 0x9763, 0x0cb0, 0x6007, 0x0005, 0x0c68, 0x080c, 0xe936,
+	0x1904, 0xd869, 0x080c, 0x3342, 0x1904, 0xd869, 0x080c, 0xda36,
+	0x1904, 0xd51a, 0x6007, 0x0020, 0x6003, 0x0001, 0x080c, 0x91f9,
+	0x080c, 0x9763, 0x0005, 0x080c, 0x3342, 0x1904, 0xd869, 0x6007,
+	0x0023, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c, 0x9763, 0x0005,
+	0x080c, 0xe936, 0x1904, 0xd869, 0x080c, 0x3342, 0x1904, 0xd869,
+	0x080c, 0xda36, 0x1904, 0xd51a, 0x0016, 0x0026, 0x00e6, 0x2071,
+	0x0260, 0x2c08, 0x2011, 0x1820, 0x2214, 0x703c, 0x9206, 0x11e0,
+	0x2011, 0x181f, 0x2214, 0x7038, 0x9084, 0x00ff, 0x9206, 0x11a0,
+	0x7240, 0x080c, 0xcc74, 0x0570, 0x2260, 0x6008, 0x9086, 0xffff,
+	0x0120, 0x7244, 0x6008, 0x9206, 0x1528, 0x6020, 0x9086, 0x0007,
+	0x1508, 0x080c, 0xaf43, 0x04a0, 0x7244, 0x9286, 0xffff, 0x0180,
+	0x2c08, 0x080c, 0xcc74, 0x01b0, 0x2260, 0x7240, 0x6008, 0x9206,
+	0x1188, 0x6010, 0x9190, 0x0004, 0x2214, 0x9206, 0x01b8, 0x0050,
+	0x7240, 0x2c08, 0x9006, 0x080c, 0xe704, 0x1180, 0x7244, 0x9286,
+	0xffff, 0x01b0, 0x2160, 0x6007, 0x0026, 0x6017, 0x1700, 0x7214,
+	0x9296, 0xffff, 0x1180, 0x6007, 0x0025, 0x0068, 0x6020, 0x9086,
+	0x0007, 0x1d80, 0x6004, 0x9086, 0x0024, 0x1110, 0x080c, 0xaf43,
+	0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c,
+	0x9763, 0x00ee, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c,
+	0x65d5, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0x1805, 0x2011, 0x0276, 0x080c, 0xbefd, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x0120, 0x6007, 0x0031, 0x0804, 0xd633, 0x080c, 0xbb71,
+	0x080c, 0x743e, 0x1190, 0x0006, 0x0026, 0x0036, 0x080c, 0x7458,
+	0x1138, 0x080c, 0x7724, 0x080c, 0x60ad, 0x080c, 0x736a, 0x0010,
+	0x080c, 0x7416, 0x003e, 0x002e, 0x000e, 0x0005, 0x080c, 0x3342,
+	0x1904, 0xd869, 0x080c, 0xda36, 0x1904, 0xd51a, 0x6106, 0x080c,
+	0xda52, 0x1120, 0x6007, 0x002b, 0x0804, 0xd633, 0x6007, 0x002c,
+	0x0804, 0xd633, 0x080c, 0xe936, 0x1904, 0xd869, 0x080c, 0x3342,
+	0x1904, 0xd869, 0x080c, 0xda36, 0x1904, 0xd51a, 0x6106, 0x080c,
+	0xda57, 0x1120, 0x6007, 0x002e, 0x0804, 0xd633, 0x6007, 0x002f,
+	0x0804, 0xd633, 0x080c, 0x3342, 0x1904, 0xd869, 0x00e6, 0x00d6,
+	0x00c6, 0x6010, 0x2058, 0xb904, 0x9184, 0x00ff, 0x9086, 0x0006,
+	0x0158, 0x9184, 0xff00, 0x8007, 0x9086, 0x0006, 0x0128, 0x00ce,
+	0x00de, 0x00ee, 0x0804, 0xd63a, 0x080c, 0x5761, 0xd0e4, 0x0904,
+	0xd7b4, 0x2071, 0x026c, 0x7010, 0x603a, 0x7014, 0x603e, 0x7108,
+	0x720c, 0x080c, 0x6a08, 0x0140, 0x6010, 0x2058, 0xb810, 0x9106,
+	0x1118, 0xb814, 0x9206, 0x0510, 0x080c, 0x6a04, 0x15b8, 0x2069,
+	0x1800, 0x6880, 0x9206, 0x1590, 0x687c, 0x9106, 0x1578, 0x7210,
+	0x080c, 0xcc74, 0x0590, 0x080c, 0xd921, 0x0578, 0x080c, 0xe7b6,
+	0x0560, 0x622e, 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x91b1,
+	0x080c, 0x9763, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x7214, 0x9286,
+	0xffff, 0x0150, 0x080c, 0xcc74, 0x01c0, 0x9280, 0x0002, 0x2004,
+	0x7110, 0x9106, 0x1190, 0x08e0, 0x7210, 0x2c08, 0x9085, 0x0001,
+	0x080c, 0xe704, 0x2c10, 0x2160, 0x0140, 0x0890, 0x6007, 0x0037,
+	0x602f, 0x0009, 0x6017, 0x1500, 0x08b8, 0x6007, 0x0037, 0x602f,
+	0x0003, 0x6017, 0x1700, 0x0880, 0x6007, 0x0012, 0x0868, 0x080c,
+	0x3342, 0x1904, 0xd869, 0x6010, 0x2058, 0xb804, 0x9084, 0xff00,
+	0x8007, 0x9086, 0x0006, 0x1904, 0xd63a, 0x00e6, 0x00d6, 0x00c6,
+	0x080c, 0x5761, 0xd0e4, 0x0904, 0xd82c, 0x2069, 0x1800, 0x2071,
+	0x026c, 0x7008, 0x603a, 0x720c, 0x623e, 0x9286, 0xffff, 0x1150,
+	0x7208, 0x00c6, 0x2c08, 0x9085, 0x0001, 0x080c, 0xe704, 0x2c10,
+	0x00ce, 0x05e8, 0x080c, 0xcc74, 0x05d0, 0x7108, 0x9280, 0x0002,
+	0x2004, 0x9106, 0x15a0, 0x00c6, 0x0026, 0x2260, 0x080c, 0xc898,
+	0x002e, 0x00ce, 0x7118, 0x918c, 0xff00, 0x810f, 0x9186, 0x0001,
+	0x0178, 0x9186, 0x0005, 0x0118, 0x9186, 0x0007, 0x1198, 0x9280,
+	0x0005, 0x2004, 0x9005, 0x0170, 0x080c, 0xd921, 0x0904, 0xd7ad,
+	0x0056, 0x7510, 0x7614, 0x080c, 0xe7cf, 0x005e, 0x00ce, 0x00de,
+	0x00ee, 0x0005, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, 0x2a00,
+	0x6003, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0c78, 0x6007,
+	0x003b, 0x602f, 0x0003, 0x6017, 0x0300, 0x6003, 0x0001, 0x080c,
+	0x91b1, 0x080c, 0x9763, 0x0c10, 0x6007, 0x003b, 0x602f, 0x000b,
+	0x6017, 0x0000, 0x0804, 0xd784, 0x00e6, 0x0026, 0x080c, 0x69ca,
+	0x0550, 0x080c, 0x6966, 0x080c, 0xe9a8, 0x1518, 0x2071, 0x1800,
+	0x70dc, 0x9085, 0x0003, 0x70de, 0x00f6, 0x2079, 0x0100, 0x72b0,
+	0x9284, 0x00ff, 0x707e, 0x78e6, 0x9284, 0xff00, 0x7280, 0x9205,
+	0x7082, 0x78ea, 0x00fe, 0x70e7, 0x0000, 0x080c, 0x6a08, 0x0120,
+	0x2011, 0x19ff, 0x2013, 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x2ff5,
+	0x0010, 0x080c, 0xe9da, 0x002e, 0x00ee, 0x080c, 0xaf43, 0x0804,
+	0xd639, 0x080c, 0xaf43, 0x0005, 0x2600, 0x0002, 0xd880, 0xd8b1,
+	0xd8c2, 0xd880, 0xd880, 0xd882, 0xd8d3, 0xd880, 0xd880, 0xd880,
+	0xd89f, 0xd880, 0xd880, 0xd880, 0xd8de, 0xd8eb, 0xd91c, 0xd880,
+	0x080c, 0x0dd5, 0x080c, 0xe936, 0x1d20, 0x080c, 0x3342, 0x1d08,
+	0x080c, 0xda36, 0x1148, 0x7038, 0x6016, 0x6007, 0x0045, 0x6003,
+	0x0001, 0x080c, 0x91f9, 0x0005, 0x080c, 0x321e, 0x080c, 0xd39d,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x91f9, 0x0005, 0x080c,
+	0xe936, 0x1938, 0x080c, 0x3342, 0x1920, 0x080c, 0xda36, 0x1d60,
+	0x703c, 0x6016, 0x6007, 0x004a, 0x6003, 0x0001, 0x080c, 0x91f9,
+	0x0005, 0x080c, 0x3342, 0x1904, 0xd869, 0x2009, 0x0041, 0x080c,
+	0xe9e3, 0x6007, 0x0047, 0x6003, 0x0001, 0x080c, 0x91f9, 0x080c,
+	0x9763, 0x0005, 0x080c, 0x3342, 0x1904, 0xd869, 0x2009, 0x0042,
+	0x080c, 0xe9e3, 0x6007, 0x0047, 0x6003, 0x0001, 0x080c, 0x91f9,
+	0x080c, 0x9763, 0x0005, 0x080c, 0x3342, 0x1904, 0xd869, 0x2009,
+	0x0046, 0x080c, 0xe9e3, 0x080c, 0xaf43, 0x0005, 0x080c, 0xd93e,
+	0x0904, 0xd869, 0x6007, 0x004e, 0x6003, 0x0001, 0x080c, 0x91f9,
+	0x080c, 0x9763, 0x0005, 0x6007, 0x004f, 0x6017, 0x0000, 0x7134,
+	0x918c, 0x00ff, 0x81ff, 0x0508, 0x9186, 0x0001, 0x1160, 0x7140,
+	0x2001, 0x19bc, 0x2004, 0x9106, 0x11b0, 0x7144, 0x2001, 0x19bd,
+	0x2004, 0x9106, 0x0190, 0x9186, 0x0002, 0x1168, 0x2011, 0x0276,
+	0x20a9, 0x0004, 0x6010, 0x0096, 0x2048, 0x2019, 0x000a, 0x080c,
+	0xbf11, 0x009e, 0x0110, 0x6017, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x91f9, 0x080c, 0x9763, 0x0005, 0x6007, 0x0050, 0x703c, 0x6016,
+	0x0ca0, 0x0016, 0x00e6, 0x2071, 0x0260, 0x00b6, 0x00c6, 0x2260,
+	0x6010, 0x2058, 0xb8cc, 0xd084, 0x0150, 0x7128, 0x6044, 0x9106,
+	0x1120, 0x712c, 0x6048, 0x9106, 0x0110, 0x9006, 0x0010, 0x9085,
+	0x0001, 0x00ce, 0x00be, 0x00ee, 0x001e, 0x0005, 0x0016, 0x0096,
+	0x0086, 0x00e6, 0x01c6, 0x01d6, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x1800, 0x7090, 0x908a, 0x00f9, 0x16e8, 0x20e1, 0x0000, 0x2001,
+	0x199f, 0x2003, 0x0000, 0x080c, 0x1018, 0x05a0, 0x2900, 0x6016,
+	0x7090, 0x8004, 0xa816, 0x908a, 0x001e, 0x02d0, 0xa833, 0x001e,
+	0x20a9, 0x001e, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001b, 0x20a0,
+	0x2001, 0x199f, 0x0016, 0x200c, 0x0471, 0x001e, 0x2940, 0x080c,
+	0x1018, 0x01c0, 0x2900, 0xa006, 0x2100, 0x81ff, 0x0180, 0x0c18,
+	0xa832, 0x20a8, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001b, 0x20a0,
+	0x2001, 0x199f, 0x0016, 0x200c, 0x00b1, 0x001e, 0x0000, 0x9085,
+	0x0001, 0x0048, 0x2071, 0x1800, 0x7093, 0x0000, 0x6014, 0x2048,
+	0x080c, 0x0fb1, 0x9006, 0x012e, 0x01de, 0x01ce, 0x00ee, 0x008e,
+	0x009e, 0x001e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00c6,
+	0x918c, 0xffff, 0x11a8, 0x080c, 0x23e9, 0x2099, 0x026c, 0x2001,
+	0x0014, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, 0x00f8, 0x20a8,
+	0x4003, 0x22a8, 0x8108, 0x080c, 0x23e9, 0x2099, 0x0260, 0x0ca8,
+	0x080c, 0x23e9, 0x2061, 0x199f, 0x6004, 0x2098, 0x6008, 0x3518,
+	0x9312, 0x1218, 0x23a8, 0x4003, 0x0048, 0x20a8, 0x4003, 0x22a8,
+	0x8108, 0x080c, 0x23e9, 0x2099, 0x0260, 0x0ca8, 0x2061, 0x199f,
+	0x2019, 0x0280, 0x3300, 0x931e, 0x0110, 0x6006, 0x0020, 0x2001,
+	0x0260, 0x6006, 0x8108, 0x2162, 0x9292, 0x0021, 0x9296, 0xffff,
+	0x620a, 0x00ce, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x0006,
+	0x0016, 0x0026, 0x0036, 0x00c6, 0x81ff, 0x11b8, 0x080c, 0x2401,
+	0x20a1, 0x024c, 0x2001, 0x0014, 0x3518, 0x9312, 0x1218, 0x23a8,
+	0x4003, 0x0418, 0x20a8, 0x4003, 0x82ff, 0x01f8, 0x22a8, 0x8108,
+	0x080c, 0x2401, 0x20a1, 0x0240, 0x0c98, 0x080c, 0x2401, 0x2061,
+	0x19a2, 0x6004, 0x20a0, 0x6008, 0x3518, 0x9312, 0x1218, 0x23a8,
+	0x4003, 0x0058, 0x20a8, 0x4003, 0x82ff, 0x0138, 0x22a8, 0x8108,
+	0x080c, 0x2401, 0x20a1, 0x0240, 0x0c98, 0x2061, 0x19a2, 0x2019,
+	0x0260, 0x3400, 0x931e, 0x0110, 0x6006, 0x0020, 0x2001, 0x0240,
+	0x6006, 0x8108, 0x2162, 0x9292, 0x0021, 0x9296, 0xffff, 0x620a,
+	0x00ce, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x00b6, 0x0066,
+	0x6610, 0x2658, 0xbe04, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0006,
+	0x0170, 0x9686, 0x0004, 0x0158, 0xbe04, 0x96b4, 0x00ff, 0x9686,
+	0x0006, 0x0128, 0x9686, 0x0004, 0x0110, 0x9085, 0x0001, 0x006e,
+	0x00be, 0x0005, 0x00d6, 0x080c, 0xdace, 0x00de, 0x0005, 0x00d6,
+	0x080c, 0xdadb, 0x1520, 0x680c, 0x908c, 0xff00, 0x6820, 0x9084,
+	0x00ff, 0x9115, 0x6216, 0x6824, 0x602e, 0xd1e4, 0x0130, 0x9006,
+	0x080c, 0xeb03, 0x2009, 0x0001, 0x0078, 0xd1ec, 0x0180, 0x6920,
+	0x918c, 0x00ff, 0x6824, 0x080c, 0x287c, 0x1148, 0x2001, 0x0001,
+	0x080c, 0xeb03, 0x2110, 0x900e, 0x080c, 0x3267, 0x0018, 0x9085,
+	0x0001, 0x0008, 0x9006, 0x00de, 0x0005, 0x00b6, 0x00c6, 0x080c,
+	0xaf91, 0x05a8, 0x0016, 0x0026, 0x00c6, 0x2011, 0x0263, 0x2204,
+	0x8211, 0x220c, 0x080c, 0x287c, 0x1578, 0x080c, 0x6638, 0x1560,
+	0xbe12, 0xbd16, 0x00ce, 0x002e, 0x001e, 0x2b00, 0x6012, 0x080c,
+	0xe936, 0x11d8, 0x080c, 0x3342, 0x11c0, 0x080c, 0xda36, 0x0510,
+	0x2001, 0x0007, 0x080c, 0x65e9, 0x2001, 0x0007, 0x080c, 0x6615,
+	0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001,
+	0x080c, 0x91f9, 0x080c, 0x9763, 0x0010, 0x080c, 0xaf43, 0x9085,
+	0x0001, 0x00ce, 0x00be, 0x0005, 0x080c, 0xaf43, 0x00ce, 0x002e,
+	0x001e, 0x0ca8, 0x080c, 0xaf43, 0x9006, 0x0c98, 0x2069, 0x026d,
+	0x6800, 0x9082, 0x0010, 0x1228, 0x6017, 0x0000, 0x9085, 0x0001,
+	0x0008, 0x9006, 0x0005, 0x6017, 0x0000, 0x2069, 0x026c, 0x6808,
+	0x9084, 0xff00, 0x9086, 0x0800, 0x1190, 0x6904, 0x9186, 0x0018,
+	0x0118, 0x9186, 0x0014, 0x1158, 0x810f, 0x6800, 0x9084, 0x00ff,
+	0x910d, 0x615a, 0x908e, 0x0014, 0x0110, 0x908e, 0x0010, 0x0005,
+	0x6004, 0x90b2, 0x0053, 0x1a0c, 0x0dd5, 0x91b6, 0x0013, 0x1130,
+	0x2008, 0x91b2, 0x0040, 0x1a04, 0xdc25, 0x0092, 0x91b6, 0x0027,
+	0x0120, 0x91b6, 0x0014, 0x190c, 0x0dd5, 0x2001, 0x0007, 0x080c,
+	0x6615, 0x080c, 0x9657, 0x080c, 0xaf74, 0x080c, 0x9763, 0x0005,
+	0xdb58, 0xdb5a, 0xdb58, 0xdb58, 0xdb58, 0xdb5a, 0xdb69, 0xdc1e,
+	0xdbbb, 0xdc1e, 0xdbcf, 0xdc1e, 0xdb69, 0xdc1e, 0xdc16, 0xdc1e,
+	0xdc16, 0xdc1e, 0xdc1e, 0xdb58, 0xdb58, 0xdb58, 0xdb58, 0xdb58,
+	0xdb58, 0xdb58, 0xdb58, 0xdb58, 0xdb58, 0xdb58, 0xdb5a, 0xdb58,
+	0xdc1e, 0xdb58, 0xdb58, 0xdc1e, 0xdb58, 0xdc1b, 0xdc1e, 0xdb58,
+	0xdb58, 0xdb58, 0xdb58, 0xdc1e, 0xdc1e, 0xdb58, 0xdc1e, 0xdc1e,
+	0xdb58, 0xdb64, 0xdb58, 0xdb58, 0xdb58, 0xdb58, 0xdc1a, 0xdc1e,
+	0xdb58, 0xdb58, 0xdc1e, 0xdc1e, 0xdb58, 0xdb58, 0xdb58, 0xdb58,
+	0x080c, 0x0dd5, 0x080c, 0x9657, 0x080c, 0xd3a0, 0x6003, 0x0002,
+	0x080c, 0x9763, 0x0804, 0xdc24, 0x9006, 0x080c, 0x65d5, 0x0804,
+	0xdc1e, 0x080c, 0x6a04, 0x1904, 0xdc1e, 0x9006, 0x080c, 0x65d5,
+	0x6010, 0x2058, 0xb810, 0x9086, 0x00ff, 0x1140, 0x00f6, 0x2079,
+	0x1800, 0x78a8, 0x8000, 0x78aa, 0x00fe, 0x0428, 0x6010, 0x2058,
+	0xb8c0, 0x9005, 0x1178, 0x080c, 0xd388, 0x1904, 0xdc1e, 0x0036,
+	0x0046, 0xbba0, 0x2021, 0x0007, 0x080c, 0x4d36, 0x004e, 0x003e,
+	0x0804, 0xdc1e, 0x080c, 0x3373, 0x1904, 0xdc1e, 0x2001, 0x1800,
+	0x2004, 0x9086, 0x0002, 0x1138, 0x00f6, 0x2079, 0x1800, 0x78a8,
+	0x8000, 0x78aa, 0x00fe, 0x2001, 0x0002, 0x080c, 0x65e9, 0x080c,
+	0x9657, 0x6023, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c,
+	0x91f9, 0x080c, 0x9763, 0x6110, 0x2158, 0x2009, 0x0001, 0x080c,
+	0x85be, 0x0804, 0xdc24, 0x6610, 0x2658, 0xbe04, 0x96b4, 0xff00,
+	0x8637, 0x9686, 0x0006, 0x0904, 0xdc1e, 0x9686, 0x0004, 0x0904,
+	0xdc1e, 0x080c, 0x8d70, 0x2001, 0x0004, 0x0804, 0xdc1c, 0x2001,
+	0x1800, 0x2004, 0x9086, 0x0003, 0x1158, 0x0036, 0x0046, 0x6010,
+	0x2058, 0xbba0, 0x2021, 0x0006, 0x080c, 0x4d36, 0x004e, 0x003e,
+	0x2001, 0x0006, 0x080c, 0xdc42, 0x6610, 0x2658, 0xbe04, 0x0066,
+	0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x006e, 0x0168, 0x2001,
+	0x0006, 0x080c, 0x6615, 0x9284, 0x00ff, 0x908e, 0x0007, 0x1120,
+	0x2001, 0x0006, 0x080c, 0x65e9, 0x080c, 0x6a04, 0x11f8, 0x2001,
+	0x1837, 0x2004, 0xd0a4, 0x01d0, 0xbe04, 0x96b4, 0x00ff, 0x9686,
+	0x0006, 0x01a0, 0x00f6, 0x2079, 0x1800, 0x78a8, 0x8000, 0x78aa,
+	0x00fe, 0x0804, 0xdba3, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006,
+	0x0449, 0x0020, 0x0018, 0x0010, 0x080c, 0x6615, 0x080c, 0x9657,
+	0x080c, 0xaf43, 0x080c, 0x9763, 0x0005, 0x2600, 0x0002, 0xdc39,
+	0xdc39, 0xdc39, 0xdc39, 0xdc39, 0xdc3b, 0xdc39, 0xdc3b, 0xdc39,
+	0xdc39, 0xdc3b, 0xdc39, 0xdc39, 0xdc39, 0xdc3b, 0xdc3b, 0xdc3b,
+	0xdc3b, 0x080c, 0x0dd5, 0x080c, 0x9657, 0x080c, 0xaf43, 0x080c,
+	0x9763, 0x0005, 0x0016, 0x00b6, 0x00d6, 0x6110, 0x2158, 0xb900,
+	0xd184, 0x0138, 0x080c, 0x65e9, 0x9006, 0x080c, 0x65d5, 0x080c,
+	0x3247, 0x00de, 0x00be, 0x001e, 0x0005, 0x6610, 0x2658, 0xb804,
+	0x9084, 0xff00, 0x8007, 0x90b2, 0x000c, 0x1a0c, 0x0dd5, 0x91b6,
+	0x0015, 0x1110, 0x003b, 0x0028, 0x91b6, 0x0016, 0x190c, 0x0dd5,
+	0x006b, 0x0005, 0xb9ee, 0xb9ee, 0xb9ee, 0xb9ee, 0xdcd7, 0xb9ee,
+	0xdcc1, 0xdc82, 0xb9ee, 0xb9ee, 0xb9ee, 0xb9ee, 0xb9ee, 0xb9ee,
+	0xb9ee, 0xb9ee, 0xdcd7, 0xb9ee, 0xdcc1, 0xdcc8, 0xb9ee, 0xb9ee,
+	0xb9ee, 0xb9ee, 0x00f6, 0x080c, 0x6a04, 0x11d8, 0x080c, 0xd388,
+	0x11c0, 0x6010, 0x905d, 0x01a8, 0xb8c0, 0x9005, 0x0190, 0x9006,
+	0x080c, 0x65d5, 0x2001, 0x0002, 0x080c, 0x65e9, 0x6023, 0x0001,
+	0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x91f9, 0x080c, 0x9763,
+	0x00f0, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x287c,
+	0x11b0, 0x080c, 0x6699, 0x0118, 0x080c, 0xaf43, 0x0080, 0xb810,
+	0x0006, 0xb814, 0x0006, 0xb8c0, 0x0006, 0x080c, 0x60c7, 0x000e,
+	0xb8c2, 0x000e, 0xb816, 0x000e, 0xb812, 0x080c, 0xaf43, 0x00fe,
+	0x0005, 0x6604, 0x96b6, 0x001e, 0x1110, 0x080c, 0xaf43, 0x0005,
+	0x080c, 0xbd79, 0x1148, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c,
+	0x91f9, 0x080c, 0x9763, 0x0010, 0x080c, 0xaf43, 0x0005, 0x0804,
+	0xaf43, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dd5, 0x080c, 0x9657,
+	0x080c, 0xaf74, 0x080c, 0x9763, 0x0005, 0x9182, 0x0040, 0x0002,
+	0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0xdcfe, 0xdcfc, 0xdcfc, 0xdcfc,
+	0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc,
+	0xdcfc, 0xdcfc, 0xdcfc, 0xdcfc, 0x080c, 0x0dd5, 0x0096, 0x00b6,
+	0x00d6, 0x00e6, 0x00f6, 0x0046, 0x0026, 0x6210, 0x2258, 0xb8bc,
+	0x9005, 0x11a8, 0x6106, 0x2071, 0x0260, 0x7444, 0x94a4, 0xff00,
+	0x0904, 0xdd64, 0x080c, 0xeaf7, 0x1170, 0x9486, 0x2000, 0x1158,
+	0x2009, 0x0001, 0x2011, 0x0200, 0x080c, 0x879a, 0x0020, 0x9026,
+	0x080c, 0xe97b, 0x0c38, 0x080c, 0x0fff, 0x090c, 0x0dd5, 0x6003,
+	0x0007, 0xa867, 0x010d, 0x9006, 0xa802, 0xa86a, 0xac8a, 0x2c00,
+	0xa88e, 0x6008, 0xa8e2, 0x6010, 0x2058, 0xb8a0, 0x7130, 0xa97a,
+	0x0016, 0xa876, 0xa87f, 0x0000, 0xa883, 0x0000, 0xa887, 0x0036,
+	0x080c, 0x6d17, 0x001e, 0x080c, 0xeaf7, 0x1904, 0xddc4, 0x9486,
+	0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0xe6ae, 0x0804, 0xddc4,
+	0x9486, 0x0200, 0x1120, 0x080c, 0xe64a, 0x0804, 0xddc4, 0x9486,
+	0x0400, 0x0120, 0x9486, 0x1000, 0x1904, 0xddc4, 0x2019, 0x0002,
+	0x080c, 0xe665, 0x0804, 0xddc4, 0x2069, 0x1a70, 0x6a00, 0xd284,
+	0x0904, 0xde2e, 0x9284, 0x0300, 0x1904, 0xde27, 0x6804, 0x9005,
+	0x0904, 0xde0f, 0x2d78, 0x6003, 0x0007, 0x080c, 0x1018, 0x0904,
+	0xddd0, 0x7800, 0xd08c, 0x1118, 0x7804, 0x8001, 0x7806, 0x6017,
+	0x0000, 0x2001, 0x180f, 0x2004, 0xd084, 0x1904, 0xde32, 0x9006,
+	0xa802, 0xa867, 0x0116, 0xa86a, 0x6008, 0xa8e2, 0x2c00, 0xa87a,
+	0x6010, 0x2058, 0xb8a0, 0x7130, 0xa9b6, 0xa876, 0xb928, 0xa9ba,
+	0xb92c, 0xa9be, 0xb930, 0xa9c2, 0xb934, 0xa9c6, 0xa883, 0x003d,
+	0x7044, 0x9084, 0x0003, 0x9080, 0xddcc, 0x2005, 0xa87e, 0x20a9,
+	0x000a, 0x2001, 0x0270, 0xaa5c, 0x9290, 0x0021, 0x2009, 0x0205,
+	0x200b, 0x0080, 0x20e1, 0x0000, 0xab60, 0x23e8, 0x2098, 0x22a0,
+	0x4003, 0x200b, 0x0000, 0x2001, 0x027a, 0x200c, 0xa9b2, 0x8000,
+	0x200c, 0xa9ae, 0x080c, 0x6d17, 0x002e, 0x004e, 0x00fe, 0x00ee,
+	0x00de, 0x00be, 0x009e, 0x0005, 0x0000, 0x0080, 0x0040, 0x0000,
+	0x2001, 0x1810, 0x2004, 0xd084, 0x0120, 0x080c, 0x0fff, 0x1904,
+	0xdd79, 0x6017, 0xf100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c,
+	0x91b1, 0x080c, 0x9763, 0x0c00, 0x2069, 0x0260, 0x6848, 0x9084,
+	0xff00, 0x9086, 0x1200, 0x1198, 0x686c, 0x9084, 0x00ff, 0x0016,
+	0x6114, 0x918c, 0xf700, 0x910d, 0x6116, 0x001e, 0x6003, 0x0001,
+	0x6007, 0x0043, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0828, 0x6868,
+	0x602e, 0x686c, 0x6032, 0x6017, 0xf200, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0804, 0xddc4, 0x2001,
+	0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x4b7f,
+	0x6017, 0xf300, 0x0010, 0x6017, 0xf100, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0804, 0xddc4, 0x6017,
+	0xf500, 0x0c98, 0x6017, 0xf600, 0x0804, 0xdde4, 0x6017, 0xf200,
+	0x0804, 0xdde4, 0xa867, 0x0146, 0xa86b, 0x0000, 0x6008, 0xa886,
+	0x2c00, 0xa87a, 0x7044, 0x9084, 0x0003, 0x9080, 0xddcc, 0x2005,
+	0xa87e, 0x2928, 0x6010, 0x2058, 0xb8a0, 0xa876, 0xb828, 0xa88a,
+	0xb82c, 0xa88e, 0xb830, 0xa892, 0xb834, 0xa896, 0xa883, 0x003d,
+	0x2009, 0x0205, 0x2104, 0x9085, 0x0080, 0x200a, 0x20e1, 0x0000,
+	0x2011, 0x0210, 0x2214, 0x9294, 0x0fff, 0xaaa2, 0x9282, 0x0111,
+	0x1a0c, 0x0dd5, 0x8210, 0x821c, 0x2001, 0x026c, 0x2098, 0xa860,
+	0x20e8, 0xa85c, 0x9080, 0x0029, 0x20a0, 0x2011, 0xdeae, 0x2041,
+	0x0001, 0x223d, 0x9784, 0x00ff, 0x9322, 0x1208, 0x2300, 0x20a8,
+	0x4003, 0x931a, 0x0530, 0x8210, 0xd7fc, 0x1130, 0x8d68, 0x2d0a,
+	0x2001, 0x0260, 0x2098, 0x0c68, 0x2950, 0x080c, 0x1018, 0x0170,
+	0x2900, 0xb002, 0xa867, 0x0147, 0xa86b, 0x0000, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x001b, 0x20a0, 0x8840, 0x08d8, 0x2548, 0xa800,
+	0x902d, 0x0118, 0x080c, 0x1031, 0x0cc8, 0x080c, 0x1031, 0x0804,
+	0xddd0, 0x2548, 0x8847, 0x9885, 0x0046, 0xa866, 0x2009, 0x0205,
+	0x200b, 0x0000, 0x080c, 0xe6dd, 0x0804, 0xddc4, 0x8010, 0x0004,
+	0x801a, 0x0006, 0x8018, 0x0008, 0x8016, 0x000a, 0x8014, 0x9186,
+	0x0013, 0x1160, 0x6004, 0x908a, 0x0054, 0x1a0c, 0x0dd5, 0x9082,
+	0x0040, 0x0a0c, 0x0dd5, 0x2008, 0x0804, 0xdf60, 0x9186, 0x0051,
+	0x0108, 0x00c0, 0x2001, 0x0109, 0x2004, 0xd084, 0x0904, 0xdf10,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x9094,
+	0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0x9086, 0x0002, 0x1580,
+	0x0804, 0xdfa9, 0x9186, 0x0027, 0x0530, 0x9186, 0x0048, 0x0128,
+	0x9186, 0x0014, 0x0500, 0x190c, 0x0dd5, 0x2001, 0x0109, 0x2004,
+	0xd084, 0x01f0, 0x00c6, 0x0126, 0x2091, 0x2800, 0x00c6, 0x2061,
+	0x0100, 0x0006, 0x0016, 0x0026, 0x080c, 0x9094, 0x002e, 0x001e,
+	0x000e, 0x00ce, 0x012e, 0x00ce, 0x6000, 0x9086, 0x0004, 0x190c,
+	0x0dd5, 0x0804, 0xe08c, 0x6004, 0x9082, 0x0040, 0x2008, 0x001a,
+	0x080c, 0xafd9, 0x0005, 0xdf27, 0xdf29, 0xdf29, 0xdf50, 0xdf27,
+	0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27,
+	0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0xdf27, 0x080c,
+	0x0dd5, 0x080c, 0x9657, 0x080c, 0x9763, 0x0036, 0x0096, 0x6014,
+	0x904d, 0x01d8, 0x080c, 0xcc86, 0x01c0, 0x6003, 0x0002, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1178, 0x2019, 0x0004,
+	0x080c, 0xe6dd, 0x6017, 0x0000, 0x6018, 0x9005, 0x1120, 0x2001,
+	0x1986, 0x2004, 0x601a, 0x6003, 0x0007, 0x009e, 0x003e, 0x0005,
+	0x0096, 0x080c, 0x9657, 0x080c, 0x9763, 0x080c, 0xcc86, 0x0120,
+	0x6014, 0x2048, 0x080c, 0x1031, 0x080c, 0xaf74, 0x009e, 0x0005,
+	0x0002, 0xdf75, 0xdf8c, 0xdf77, 0xdfa3, 0xdf75, 0xdf75, 0xdf75,
+	0xdf75, 0xdf75, 0xdf75, 0xdf75, 0xdf75, 0xdf75, 0xdf75, 0xdf75,
+	0xdf75, 0xdf75, 0xdf75, 0xdf75, 0xdf75, 0x080c, 0x0dd5, 0x0096,
+	0x080c, 0x9657, 0x6014, 0x2048, 0xa87c, 0xd0b4, 0x0138, 0x6003,
+	0x0007, 0x2009, 0x0043, 0x080c, 0xafbe, 0x0010, 0x6003, 0x0004,
+	0x080c, 0x9763, 0x009e, 0x0005, 0x080c, 0x9657, 0x080c, 0xcc86,
+	0x0138, 0x6114, 0x0096, 0x2148, 0xa97c, 0x009e, 0xd1ec, 0x1138,
+	0x080c, 0x876f, 0x080c, 0xaf43, 0x080c, 0x9763, 0x0005, 0x080c,
+	0xe93f, 0x0db0, 0x0cc8, 0x080c, 0x9657, 0x2009, 0x0041, 0x0804,
+	0xe114, 0x9182, 0x0040, 0x0002, 0xdfc0, 0xdfc2, 0xdfc0, 0xdfc0,
+	0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0,
+	0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc0, 0xdfc3, 0xdfc0, 0xdfc0,
+	0x080c, 0x0dd5, 0x0005, 0x00d6, 0x080c, 0x876f, 0x00de, 0x080c,
+	0xe997, 0x080c, 0xaf43, 0x0005, 0x9182, 0x0040, 0x0002, 0xdfe3,
+	0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3,
+	0xdfe5, 0xe054, 0xdfe3, 0xdfe3, 0xdfe3, 0xdfe3, 0xe054, 0xdfe3,
+	0xdfe3, 0xdfe3, 0xdfe3, 0x080c, 0x0dd5, 0x2001, 0x0105, 0x2004,
+	0x9084, 0x1800, 0x01c8, 0x2001, 0x0132, 0x200c, 0x2001, 0x0131,
+	0x2004, 0x9105, 0x1904, 0xe054, 0x2009, 0x180c, 0x2104, 0xd0d4,
+	0x0904, 0xe054, 0xc0d4, 0x200a, 0x2009, 0x0105, 0x2104, 0x9084,
+	0xe7fd, 0x9085, 0x0010, 0x200a, 0x2001, 0x1867, 0x2004, 0xd0e4,
+	0x1528, 0x603b, 0x0000, 0x080c, 0x9713, 0x6014, 0x0096, 0x2048,
+	0xa87c, 0xd0fc, 0x0188, 0x908c, 0x0003, 0x918e, 0x0002, 0x0508,
+	0x2001, 0x180c, 0x2004, 0xd0d4, 0x11e0, 0x080c, 0x9891, 0x2009,
+	0x0041, 0x009e, 0x0804, 0xe114, 0x080c, 0x9891, 0x6003, 0x0007,
+	0x601b, 0x0000, 0x080c, 0x876f, 0x009e, 0x0005, 0x2001, 0x0100,
+	0x2004, 0x9082, 0x0005, 0x0aa8, 0x2001, 0x011f, 0x2004, 0x603a,
+	0x0890, 0x2001, 0x180c, 0x200c, 0xc1d4, 0x2102, 0xd1cc, 0x0110,
+	0x080c, 0x2c90, 0x080c, 0x9891, 0x6014, 0x2048, 0xa97c, 0xd1ec,
+	0x1130, 0x080c, 0x876f, 0x080c, 0xaf43, 0x009e, 0x0005, 0x080c,
+	0xe93f, 0x0db8, 0x009e, 0x0005, 0x2001, 0x180c, 0x200c, 0xc1d4,
+	0x2102, 0x0036, 0x080c, 0x9713, 0x080c, 0x9891, 0x6014, 0x0096,
+	0x2048, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0188,
+	0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0140, 0xa8ac, 0x6330,
+	0x931a, 0x6332, 0xa8b0, 0x632c, 0x931b, 0x632e, 0x6003, 0x0002,
+	0x0080, 0x2019, 0x0004, 0x080c, 0xe6dd, 0x6018, 0x9005, 0x1128,
+	0x2001, 0x1986, 0x2004, 0x8003, 0x601a, 0x6017, 0x0000, 0x6003,
+	0x0007, 0x009e, 0x003e, 0x0005, 0x9182, 0x0040, 0x0002, 0xe0a3,
+	0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a5,
+	0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3, 0xe0a3,
+	0xe0a3, 0xe0a3, 0xe0f0, 0x080c, 0x0dd5, 0x6014, 0x0096, 0x2048,
+	0xa834, 0xaa38, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1bc,
+	0x1190, 0x920d, 0x1518, 0xa87c, 0xd0fc, 0x0128, 0x2009, 0x0041,
+	0x009e, 0x0804, 0xe114, 0x6003, 0x0007, 0x601b, 0x0000, 0x080c,
+	0x876f, 0x009e, 0x0005, 0x6124, 0xd1f4, 0x1d58, 0x0006, 0x0046,
+	0xacac, 0x9422, 0xa9b0, 0x2200, 0x910b, 0x6030, 0x9420, 0x6432,
+	0x602c, 0x9109, 0x612e, 0x004e, 0x000e, 0x08d8, 0x6110, 0x00b6,
+	0x2158, 0xb900, 0x00be, 0xd1bc, 0x1178, 0x2009, 0x180e, 0x210c,
+	0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, 0x6003, 0x0006, 0x00e9,
+	0x080c, 0x8771, 0x009e, 0x0005, 0x6003, 0x0002, 0x009e, 0x0005,
+	0x6024, 0xd0f4, 0x0128, 0x080c, 0x15f4, 0x1904, 0xe0a5, 0x0005,
+	0x6014, 0x0096, 0x2048, 0xa834, 0xa938, 0x009e, 0x9105, 0x1120,
+	0x080c, 0x15f4, 0x1904, 0xe0a5, 0x0005, 0xd2fc, 0x0140, 0x8002,
+	0x8000, 0x8212, 0x9291, 0x0000, 0x2009, 0x0009, 0x0010, 0x2009,
+	0x0015, 0xaa9a, 0xa896, 0x0005, 0x9182, 0x0040, 0x0208, 0x0062,
+	0x9186, 0x0013, 0x0120, 0x9186, 0x0014, 0x190c, 0x0dd5, 0x6024,
+	0xd0dc, 0x090c, 0x0dd5, 0x0005, 0xe138, 0xe144, 0xe150, 0xe15c,
+	0xe138, 0xe138, 0xe138, 0xe138, 0xe13f, 0xe13a, 0xe13a, 0xe138,
+	0xe138, 0xe138, 0xe138, 0xe13a, 0xe138, 0xe13a, 0xe138, 0xe13f,
+	0x080c, 0x0dd5, 0x6024, 0xd0dc, 0x090c, 0x0dd5, 0x0005, 0x6014,
+	0x9005, 0x190c, 0x0dd5, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x91b1, 0x0126, 0x2091, 0x8000, 0x080c, 0x9763, 0x012e, 0x0005,
+	0x6003, 0x0001, 0x6106, 0x080c, 0x91b1, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x9763, 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10,
+	0x080c, 0x1beb, 0x0126, 0x2091, 0x8000, 0x080c, 0x9216, 0x080c,
+	0x9891, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x0096,
+	0x9182, 0x0040, 0x0023, 0x009e, 0x003e, 0x012e, 0x0005, 0xe18b,
+	0xe18d, 0xe19f, 0xe1b9, 0xe18b, 0xe18b, 0xe18b, 0xe18b, 0xe18b,
+	0xe18b, 0xe18b, 0xe18b, 0xe18b, 0xe18b, 0xe18b, 0xe18b, 0xe18b,
+	0xe18b, 0xe18b, 0xe18b, 0x080c, 0x0dd5, 0x6014, 0x2048, 0xa87c,
+	0xd0fc, 0x01f8, 0x909c, 0x0003, 0x939e, 0x0003, 0x01d0, 0x6003,
+	0x0001, 0x6106, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0470, 0x6014,
+	0x2048, 0xa87c, 0xd0fc, 0x0168, 0x909c, 0x0003, 0x939e, 0x0003,
+	0x0140, 0x6003, 0x0001, 0x6106, 0x080c, 0x91b1, 0x080c, 0x9763,
+	0x00e0, 0x901e, 0x6316, 0x631a, 0x2019, 0x0004, 0x080c, 0xe6dd,
+	0x00a0, 0x6014, 0x2048, 0xa87c, 0xd0fc, 0x0d98, 0x909c, 0x0003,
+	0x939e, 0x0003, 0x0d70, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c,
+	0x1beb, 0x080c, 0x9216, 0x080c, 0x9891, 0x0005, 0x080c, 0x9657,
+	0x6114, 0x81ff, 0x0158, 0x0096, 0x2148, 0x080c, 0xea94, 0x0036,
+	0x2019, 0x0029, 0x080c, 0xe6dd, 0x003e, 0x009e, 0x080c, 0xaf74,
+	0x080c, 0x9763, 0x0005, 0x080c, 0x9713, 0x6114, 0x81ff, 0x0158,
+	0x0096, 0x2148, 0x080c, 0xea94, 0x0036, 0x2019, 0x0029, 0x080c,
+	0xe6dd, 0x003e, 0x009e, 0x080c, 0xaf74, 0x080c, 0x9891, 0x0005,
+	0x9182, 0x0085, 0x0002, 0xe20a, 0xe208, 0xe208, 0xe216, 0xe208,
+	0xe208, 0xe208, 0xe208, 0xe208, 0xe208, 0xe208, 0xe208, 0xe208,
+	0x080c, 0x0dd5, 0x6003, 0x000b, 0x6106, 0x080c, 0x91b1, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x9763, 0x012e, 0x0005, 0x0026, 0x00e6,
+	0x080c, 0xe936, 0x0118, 0x080c, 0xaf43, 0x0450, 0x2071, 0x0260,
+	0x7224, 0x6216, 0x2001, 0x180e, 0x2004, 0xd0e4, 0x0150, 0x6010,
+	0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00, 0x2011, 0x014e, 0x080c,
+	0xb264, 0x7220, 0x080c, 0xe583, 0x0118, 0x6007, 0x0086, 0x0040,
+	0x6007, 0x0087, 0x7224, 0x9296, 0xffff, 0x1110, 0x6007, 0x0086,
+	0x6003, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x080c, 0x9891,
+	0x00ee, 0x002e, 0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a,
+	0x0085, 0x0a0c, 0x0dd5, 0x908a, 0x0092, 0x1a0c, 0x0dd5, 0x9082,
+	0x0085, 0x00a2, 0x9186, 0x0027, 0x0130, 0x9186, 0x0014, 0x0118,
+	0x080c, 0xafd9, 0x0050, 0x2001, 0x0007, 0x080c, 0x6615, 0x080c,
+	0x9657, 0x080c, 0xaf74, 0x080c, 0x9763, 0x0005, 0xe27b, 0xe27d,
+	0xe27d, 0xe27b, 0xe27b, 0xe27b, 0xe27b, 0xe27b, 0xe27b, 0xe27b,
+	0xe27b, 0xe27b, 0xe27b, 0x080c, 0x0dd5, 0x080c, 0x9657, 0x080c,
+	0xaf74, 0x080c, 0x9763, 0x0005, 0x9182, 0x0085, 0x0a0c, 0x0dd5,
+	0x9182, 0x0092, 0x1a0c, 0x0dd5, 0x9182, 0x0085, 0x0002, 0xe29c,
+	0xe29c, 0xe29c, 0xe29e, 0xe29c, 0xe29c, 0xe29c, 0xe29c, 0xe29c,
+	0xe29c, 0xe29c, 0xe29c, 0xe29c, 0x080c, 0x0dd5, 0x0005, 0x9186,
+	0x0013, 0x0148, 0x9186, 0x0014, 0x0130, 0x9186, 0x0027, 0x0118,
+	0x080c, 0xafd9, 0x0030, 0x080c, 0x9657, 0x080c, 0xaf74, 0x080c,
+	0x9763, 0x0005, 0x0036, 0x080c, 0xe997, 0x6043, 0x0000, 0x2019,
+	0x000b, 0x0031, 0x6023, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005,
+	0x0126, 0x0036, 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x904e,
+	0x080c, 0xa76b, 0x009e, 0x008e, 0x1550, 0x0076, 0x2c38, 0x080c,
+	0xa816, 0x007e, 0x1520, 0x6000, 0x9086, 0x0000, 0x0500, 0x6020,
+	0x9086, 0x0007, 0x01e0, 0x0096, 0x601c, 0xd084, 0x0140, 0x080c,
+	0xe997, 0x080c, 0xd3a0, 0x080c, 0x1aa1, 0x6023, 0x0007, 0x6014,
+	0x2048, 0x080c, 0xcc86, 0x0110, 0x080c, 0xe6dd, 0x009e, 0x6017,
+	0x0000, 0x080c, 0xe997, 0x6023, 0x0007, 0x080c, 0xd3a0, 0x003e,
+	0x012e, 0x0005, 0x00f6, 0x00c6, 0x00b6, 0x0036, 0x0156, 0x2079,
+	0x0260, 0x7938, 0x783c, 0x080c, 0x287c, 0x15c8, 0x0016, 0x00c6,
+	0x080c, 0x6699, 0x1590, 0x001e, 0x00c6, 0x2160, 0x080c, 0xd39d,
+	0x00ce, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0xa8dc,
+	0x080c, 0x9356, 0x0076, 0x903e, 0x080c, 0x9229, 0x007e, 0x001e,
+	0x0076, 0x903e, 0x080c, 0xe477, 0x007e, 0x0026, 0xba04, 0x9294,
+	0xff00, 0x8217, 0x9286, 0x0006, 0x0118, 0x9286, 0x0004, 0x1118,
+	0xbaa0, 0x080c, 0x32dc, 0x002e, 0xbcc0, 0x001e, 0x080c, 0x60c7,
+	0xbe12, 0xbd16, 0xbcc2, 0x9006, 0x0010, 0x00ce, 0x001e, 0x015e,
+	0x003e, 0x00be, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, 0x00b6,
+	0x0016, 0x2009, 0x1824, 0x2104, 0x9086, 0x0074, 0x1904, 0xe39e,
+	0x2069, 0x0260, 0x6944, 0x9182, 0x0100, 0x06e0, 0x6940, 0x9184,
+	0x8000, 0x0904, 0xe39b, 0x2001, 0x197b, 0x2004, 0x9005, 0x1140,
+	0x6010, 0x2058, 0xb8c0, 0x9005, 0x0118, 0x9184, 0x0800, 0x0598,
+	0x6948, 0x918a, 0x0001, 0x0648, 0x080c, 0xeafc, 0x0118, 0x6978,
+	0xd1fc, 0x11b8, 0x2009, 0x0205, 0x200b, 0x0001, 0x693c, 0x81ff,
+	0x1198, 0x6944, 0x9182, 0x0100, 0x02a8, 0x6940, 0x81ff, 0x1178,
+	0x6948, 0x918a, 0x0001, 0x0288, 0x6950, 0x918a, 0x0001, 0x0298,
+	0x00d0, 0x6017, 0x0100, 0x00a0, 0x6017, 0x0300, 0x0088, 0x6017,
+	0x0500, 0x0070, 0x6017, 0x0700, 0x0058, 0x6017, 0x0900, 0x0040,
+	0x6017, 0x0b00, 0x0028, 0x6017, 0x0f00, 0x0010, 0x6017, 0x2d00,
+	0x9085, 0x0001, 0x0008, 0x9006, 0x001e, 0x00be, 0x00de, 0x00ce,
+	0x0005, 0x00c6, 0x00b6, 0x0026, 0x0036, 0x0156, 0x6210, 0x2258,
+	0xbb04, 0x9394, 0x00ff, 0x9286, 0x0006, 0x0180, 0x9286, 0x0004,
+	0x0168, 0x9394, 0xff00, 0x8217, 0x9286, 0x0006, 0x0138, 0x9286,
+	0x0004, 0x0120, 0x080c, 0x66a8, 0x0804, 0xe406, 0x2011, 0x0276,
+	0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x000a, 0x080c, 0xbf11,
+	0x009e, 0x15a8, 0x2011, 0x027a, 0x20a9, 0x0004, 0x0096, 0x2b48,
+	0x2019, 0x0006, 0x080c, 0xbf11, 0x009e, 0x1548, 0x0046, 0x0016,
+	0xbaa0, 0x2220, 0x9006, 0x2009, 0x1848, 0x210c, 0xd1a4, 0x0138,
+	0x2009, 0x0029, 0x080c, 0xe73a, 0xb800, 0xc0e5, 0xb802, 0x2019,
+	0x0029, 0x080c, 0x9356, 0x0076, 0x2039, 0x0000, 0x080c, 0x9229,
+	0x2c08, 0x080c, 0xe477, 0x007e, 0x2001, 0x0007, 0x080c, 0x6615,
+	0x2001, 0x0007, 0x080c, 0x65e9, 0x001e, 0x004e, 0x9006, 0x015e,
+	0x003e, 0x002e, 0x00be, 0x00ce, 0x0005, 0x00d6, 0x2069, 0x026e,
+	0x6800, 0x9086, 0x0800, 0x0118, 0x6017, 0x0000, 0x0008, 0x9006,
+	0x00de, 0x0005, 0x00b6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156,
+	0x2079, 0x026c, 0x7930, 0x7834, 0x080c, 0x287c, 0x11d0, 0x080c,
+	0x6699, 0x11b8, 0x2011, 0x0270, 0x20a9, 0x0004, 0x0096, 0x2b48,
+	0x2019, 0x000a, 0x080c, 0xbf11, 0x009e, 0x1158, 0x2011, 0x0274,
+	0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xbf11,
+	0x009e, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00be, 0x0005,
+	0x00b6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, 0x0263,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x287c, 0x11d0, 0x080c, 0x6699,
+	0x11b8, 0x2011, 0x0276, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019,
+	0x000a, 0x080c, 0xbf11, 0x009e, 0x1158, 0x2011, 0x027a, 0x20a9,
+	0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xbf11, 0x009e,
+	0x015e, 0x003e, 0x002e, 0x001e, 0x000e, 0x00be, 0x0005, 0x00e6,
+	0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0126,
+	0x2091, 0x8000, 0x2740, 0x2029, 0x19ef, 0x252c, 0x2021, 0x19f5,
+	0x2424, 0x2061, 0x1cd0, 0x2071, 0x1800, 0x7654, 0x7074, 0x81ff,
+	0x0150, 0x0006, 0x9186, 0x1ab2, 0x000e, 0x0128, 0x8001, 0x9602,
+	0x1a04, 0xe514, 0x0018, 0x9606, 0x0904, 0xe514, 0x080c, 0x8a3d,
+	0x0904, 0xe50b, 0x2100, 0x9c06, 0x0904, 0xe50b, 0x080c, 0xe77b,
+	0x1904, 0xe50b, 0x080c, 0xeb19, 0x0904, 0xe50b, 0x080c, 0xe76b,
+	0x0904, 0xe50b, 0x6720, 0x9786, 0x0001, 0x1148, 0x080c, 0x3373,
+	0x0904, 0xe553, 0x6004, 0x9086, 0x0000, 0x1904, 0xe553, 0x9786,
+	0x0004, 0x0904, 0xe553, 0x9786, 0x0007, 0x0904, 0xe50b, 0x2500,
+	0x9c06, 0x0904, 0xe50b, 0x2400, 0x9c06, 0x05e8, 0x88ff, 0x0118,
+	0x6054, 0x9906, 0x15c0, 0x0096, 0x6000, 0x9086, 0x0004, 0x1120,
+	0x0016, 0x080c, 0x1aa1, 0x001e, 0x9786, 0x000a, 0x0148, 0x080c,
+	0xce8e, 0x1130, 0x080c, 0xb905, 0x009e, 0x080c, 0xaf74, 0x0418,
+	0x6014, 0x2048, 0x080c, 0xcc86, 0x01d8, 0x9786, 0x0003, 0x1570,
+	0xa867, 0x0103, 0xa87c, 0xd0cc, 0x0130, 0x0096, 0xa878, 0x2048,
+	0x080c, 0x0fb1, 0x009e, 0xab7a, 0xa877, 0x0000, 0x080c, 0xea94,
+	0x0016, 0x080c, 0xcf7c, 0x080c, 0x6d0b, 0x001e, 0x080c, 0xce71,
+	0x009e, 0x080c, 0xaf74, 0x9ce0, 0x0018, 0x2001, 0x181a, 0x2004,
+	0x9c02, 0x1210, 0x0804, 0xe48b, 0x012e, 0x002e, 0x004e, 0x005e,
+	0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005, 0x9786, 0x0006,
+	0x1150, 0x9386, 0x0005, 0x0128, 0x080c, 0xea94, 0x080c, 0xe6dd,
+	0x08f8, 0x009e, 0x0c00, 0x9786, 0x0009, 0x11f8, 0x6000, 0x9086,
+	0x0004, 0x01c0, 0x6000, 0x9086, 0x0003, 0x11a0, 0x080c, 0x9713,
+	0x0096, 0x6114, 0x2148, 0x080c, 0xcc86, 0x0118, 0x6010, 0x080c,
+	0x6d17, 0x009e, 0x00c6, 0x080c, 0xaf43, 0x00ce, 0x0036, 0x080c,
+	0x9891, 0x003e, 0x009e, 0x0804, 0xe50b, 0x9786, 0x000a, 0x0904,
+	0xe4fb, 0x0804, 0xe4f0, 0x81ff, 0x0904, 0xe50b, 0x9180, 0x0001,
+	0x2004, 0x9086, 0x0018, 0x0138, 0x9180, 0x0001, 0x2004, 0x9086,
+	0x002d, 0x1904, 0xe50b, 0x6000, 0x9086, 0x0002, 0x1904, 0xe50b,
+	0x080c, 0xce7d, 0x0138, 0x080c, 0xce8e, 0x1904, 0xe50b, 0x080c,
+	0xb905, 0x0038, 0x080c, 0x3247, 0x080c, 0xce8e, 0x1110, 0x080c,
+	0xb905, 0x080c, 0xaf74, 0x0804, 0xe50b, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0039, 0x0005, 0x00c6, 0x00e6, 0x0016, 0x2c08, 0x2170,
+	0x9006, 0x080c, 0xe704, 0x001e, 0x0120, 0x6020, 0x9084, 0x000f,
+	0x001b, 0x00ee, 0x00ce, 0x0005, 0xe5a2, 0xe5a2, 0xe5a2, 0xe5a2,
+	0xe5a2, 0xe5a2, 0xe5a4, 0xe5a2, 0xe5a2, 0xe5a2, 0xe5a2, 0xaf74,
+	0xaf74, 0xe5a2, 0x9006, 0x0005, 0x0036, 0x0046, 0x0016, 0x7010,
+	0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00, 0x2009, 0x0020, 0x080c,
+	0xe73a, 0x001e, 0x004e, 0x2019, 0x0002, 0x080c, 0xe2c0, 0x003e,
+	0x9085, 0x0001, 0x0005, 0x0096, 0x080c, 0xcc86, 0x0140, 0x6014,
+	0x904d, 0x080c, 0xc8a5, 0x687b, 0x0005, 0x080c, 0x6d17, 0x009e,
+	0x080c, 0xaf74, 0x9085, 0x0001, 0x0005, 0x2001, 0x0001, 0x080c,
+	0x65d5, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0x1805, 0x2011, 0x0276, 0x080c, 0xbefd, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x9005, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086, 0x0076,
+	0x0066, 0x00b6, 0x0126, 0x2091, 0x8000, 0x2740, 0x2061, 0x1cd0,
+	0x2079, 0x0001, 0x8fff, 0x0904, 0xe63d, 0x2071, 0x1800, 0x7654,
+	0x7074, 0x8001, 0x9602, 0x1a04, 0xe63d, 0x88ff, 0x0120, 0x2800,
+	0x9c06, 0x1590, 0x2078, 0x080c, 0xe76b, 0x0570, 0x2400, 0x9c06,
+	0x0558, 0x6720, 0x9786, 0x0006, 0x1538, 0x9786, 0x0007, 0x0520,
+	0x88ff, 0x1140, 0x6010, 0x9b06, 0x11f8, 0x85ff, 0x0118, 0x6054,
+	0x9106, 0x11d0, 0x0096, 0x601c, 0xd084, 0x0140, 0x080c, 0xe997,
+	0x080c, 0xd3a0, 0x080c, 0x1aa1, 0x6023, 0x0007, 0x6014, 0x2048,
+	0x080c, 0xcc86, 0x0120, 0x0046, 0x080c, 0xe6dd, 0x004e, 0x009e,
+	0x080c, 0xaf74, 0x88ff, 0x1198, 0x9ce0, 0x0018, 0x2001, 0x181a,
+	0x2004, 0x9c02, 0x1210, 0x0804, 0xe5f2, 0x9006, 0x012e, 0x00be,
+	0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x98c5,
+	0x0001, 0x0ca0, 0x00b6, 0x0076, 0x0056, 0x0086, 0x9046, 0x2029,
+	0x0001, 0x2c20, 0x2019, 0x0002, 0x6210, 0x2258, 0x0096, 0x904e,
+	0x080c, 0xa76b, 0x009e, 0x008e, 0x903e, 0x080c, 0xa816, 0x080c,
+	0xe5e3, 0x005e, 0x007e, 0x00be, 0x0005, 0x00b6, 0x0046, 0x0056,
+	0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x900e,
+	0x0016, 0x0036, 0x080c, 0x6699, 0x1190, 0x0056, 0x0086, 0x9046,
+	0x2508, 0x2029, 0x0001, 0x0096, 0x904e, 0x080c, 0xa76b, 0x009e,
+	0x008e, 0x903e, 0x080c, 0xa816, 0x080c, 0xe5e3, 0x005e, 0x003e,
+	0x001e, 0x8108, 0x1f04, 0xe670, 0x015e, 0x00ce, 0x007e, 0x005e,
+	0x004e, 0x00be, 0x0005, 0x00b6, 0x0076, 0x0056, 0x6210, 0x2258,
+	0x0086, 0x9046, 0x2029, 0x0001, 0x2019, 0x0048, 0x0096, 0x904e,
+	0x080c, 0xa76b, 0x009e, 0x008e, 0x903e, 0x080c, 0xa816, 0x2c20,
+	0x080c, 0xe5e3, 0x005e, 0x007e, 0x00be, 0x0005, 0x00b6, 0x0046,
+	0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x20a9, 0x0800, 0x900e,
+	0x0016, 0x0036, 0x080c, 0x6699, 0x11a0, 0x0086, 0x9046, 0x2828,
+	0x0046, 0x2021, 0x0001, 0x080c, 0xe97b, 0x004e, 0x0096, 0x904e,
+	0x080c, 0xa76b, 0x009e, 0x008e, 0x903e, 0x080c, 0xa816, 0x080c,
+	0xe5e3, 0x003e, 0x001e, 0x8108, 0x1f04, 0xe6b8, 0x015e, 0x00ce,
+	0x007e, 0x005e, 0x004e, 0x00be, 0x0005, 0x0016, 0x00f6, 0x080c,
+	0xcc84, 0x0198, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0046, 0x0180,
+	0xa800, 0x907d, 0x0138, 0xa803, 0x0000, 0xab82, 0x080c, 0x6d17,
+	0x2f48, 0x0cb0, 0xab82, 0x080c, 0x6d17, 0x00fe, 0x001e, 0x0005,
+	0xa800, 0x907d, 0x0130, 0xa803, 0x0000, 0x080c, 0x6d17, 0x2f48,
+	0x0cb8, 0x080c, 0x6d17, 0x0c88, 0x00e6, 0x0046, 0x0036, 0x2061,
+	0x1cd0, 0x9005, 0x1138, 0x2071, 0x1800, 0x7454, 0x7074, 0x8001,
+	0x9402, 0x12f8, 0x2100, 0x9c06, 0x0188, 0x6000, 0x9086, 0x0000,
+	0x0168, 0x6008, 0x9206, 0x1150, 0x6320, 0x9386, 0x0009, 0x01b0,
+	0x6010, 0x91a0, 0x0004, 0x2424, 0x9406, 0x0140, 0x9ce0, 0x0018,
+	0x2001, 0x181a, 0x2004, 0x9c02, 0x1220, 0x0c20, 0x9085, 0x0001,
+	0x0008, 0x9006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x631c, 0xd3c4,
+	0x1d68, 0x0c30, 0x0096, 0x0006, 0x080c, 0x0fff, 0x000e, 0x090c,
+	0x0dd5, 0xaae2, 0xa867, 0x010d, 0xa88e, 0x0026, 0x2010, 0x080c,
+	0xcc74, 0x2001, 0x0000, 0x0120, 0x2200, 0x9080, 0x0015, 0x2004,
+	0x002e, 0xa87a, 0x9186, 0x0020, 0x0110, 0xa8e3, 0xffff, 0xa986,
+	0xac76, 0xa87f, 0x0000, 0x2001, 0x198d, 0x2004, 0xa882, 0x9006,
+	0xa802, 0xa86a, 0xa88a, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d17,
+	0x012e, 0x009e, 0x0005, 0x6700, 0x9786, 0x0000, 0x0158, 0x9786,
+	0x0001, 0x0140, 0x9786, 0x000a, 0x0128, 0x9786, 0x0009, 0x0110,
+	0x9085, 0x0001, 0x0005, 0x00e6, 0x6010, 0x9075, 0x0138, 0x00b6,
+	0x2058, 0xb8a0, 0x00be, 0x9206, 0x00ee, 0x0005, 0x9085, 0x0001,
+	0x0cd8, 0x0016, 0x6004, 0x908e, 0x001e, 0x11a0, 0x8007, 0x6134,
+	0x918c, 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x6023, 0x0005, 0x2001, 0x1986, 0x2004, 0x601a, 0x080c, 0x91b1,
+	0x080c, 0x9763, 0x001e, 0x0005, 0xa001, 0xa001, 0x0005, 0x6024,
+	0xd0e4, 0x0158, 0xd0cc, 0x0118, 0x080c, 0xcfc0, 0x0030, 0x080c,
+	0xe997, 0x080c, 0x876f, 0x080c, 0xaf43, 0x0005, 0x9280, 0x0008,
+	0x2004, 0x9084, 0x000f, 0x0002, 0xe7ca, 0xe7ca, 0xe7ca, 0xe7cc,
+	0xe7ca, 0xe7cc, 0xe7cc, 0xe7ca, 0xe7cc, 0xe7ca, 0xe7ca, 0xe7ca,
+	0xe7ca, 0xe7ca, 0x9006, 0x0005, 0x9085, 0x0001, 0x0005, 0x9280,
+	0x0008, 0x2004, 0x9084, 0x000f, 0x0002, 0xe7e3, 0xe7e3, 0xe7e3,
+	0xe7e3, 0xe7e3, 0xe7e3, 0xe7f0, 0xe7e3, 0xe7e3, 0xe7e3, 0xe7e3,
+	0xe7e3, 0xe7e3, 0xe7e3, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017,
+	0x2a00, 0x6003, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x0005,
+	0x0096, 0x00c6, 0x2260, 0x080c, 0xe997, 0x6043, 0x0000, 0x6024,
+	0xc0f4, 0xc0e4, 0x6026, 0x603b, 0x0000, 0x00ce, 0x00d6, 0x2268,
+	0x9186, 0x0007, 0x1904, 0xe849, 0x6814, 0x9005, 0x0138, 0x2048,
+	0xa87c, 0xd0fc, 0x1118, 0x00de, 0x009e, 0x08a8, 0x6007, 0x003a,
+	0x6003, 0x0001, 0x080c, 0x91b1, 0x080c, 0x9763, 0x00c6, 0x2d60,
+	0x6100, 0x9186, 0x0002, 0x1904, 0xe8c0, 0x6014, 0x9005, 0x1138,
+	0x6000, 0x9086, 0x0007, 0x190c, 0x0dd5, 0x0804, 0xe8c0, 0x2048,
+	0x080c, 0xcc86, 0x1130, 0x0028, 0x2048, 0xa800, 0x9005, 0x1de0,
+	0x2900, 0x2048, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x1168,
+	0xa87c, 0xc0dc, 0xc0f4, 0xa87e, 0xa880, 0xc0fc, 0xa882, 0x2009,
+	0x0043, 0x080c, 0xe114, 0x0804, 0xe8c0, 0x2009, 0x0041, 0x0804,
+	0xe8ba, 0x9186, 0x0005, 0x15a0, 0x6814, 0x2048, 0xa87c, 0xd0bc,
+	0x1120, 0x00de, 0x009e, 0x0804, 0xe7e3, 0xd0b4, 0x0128, 0xd0fc,
+	0x090c, 0x0dd5, 0x0804, 0xe804, 0x6007, 0x003a, 0x6003, 0x0001,
+	0x080c, 0x91b1, 0x080c, 0x9763, 0x00c6, 0x2d60, 0x6100, 0x9186,
+	0x0002, 0x0120, 0x9186, 0x0004, 0x1904, 0xe8c0, 0x6814, 0x2048,
+	0xa97c, 0xc1f4, 0xc1dc, 0xa97e, 0xa980, 0xc1fc, 0xc1bc, 0xa982,
+	0x00f6, 0x2c78, 0x080c, 0x1754, 0x00fe, 0x2009, 0x0042, 0x04d0,
+	0x0036, 0x080c, 0x0fff, 0x090c, 0x0dd5, 0xa867, 0x010d, 0x9006,
+	0xa802, 0xa86a, 0xa88a, 0x2d18, 0xab8e, 0xa887, 0x0045, 0x2c00,
+	0xa892, 0x6038, 0xa8a2, 0x2360, 0x6024, 0xc0dd, 0x6026, 0x6010,
+	0x00b6, 0x2058, 0xb8a0, 0x00be, 0x2004, 0x6354, 0xab7a, 0xa876,
+	0x9006, 0xa87e, 0xa882, 0xad9a, 0xae96, 0xa89f, 0x0001, 0x080c,
+	0x6d17, 0x2019, 0x0045, 0x6008, 0x2068, 0x080c, 0xe2c0, 0x2d00,
+	0x600a, 0x6023, 0x0006, 0x6003, 0x0007, 0x901e, 0x631a, 0x6342,
+	0x003e, 0x0038, 0x6043, 0x0000, 0x6003, 0x0007, 0x080c, 0xe114,
+	0x00ce, 0x00de, 0x009e, 0x0005, 0x9186, 0x0013, 0x1128, 0x6004,
+	0x9082, 0x0085, 0x2008, 0x00c2, 0x9186, 0x0027, 0x1178, 0x080c,
+	0x9657, 0x0036, 0x0096, 0x6014, 0x2048, 0x2019, 0x0004, 0x080c,
+	0xe6dd, 0x009e, 0x003e, 0x080c, 0x9763, 0x0005, 0x9186, 0x0014,
+	0x0d70, 0x080c, 0xafd9, 0x0005, 0xe8f3, 0xe8f1, 0xe8f1, 0xe8f1,
+	0xe8f1, 0xe8f1, 0xe8f3, 0xe8f1, 0xe8f1, 0xe8f1, 0xe8f1, 0xe8f1,
+	0xe8f1, 0x080c, 0x0dd5, 0x080c, 0x9657, 0x6003, 0x000c, 0x080c,
+	0x9763, 0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085, 0x0208,
+	0x001a, 0x080c, 0xafd9, 0x0005, 0xe911, 0xe911, 0xe911, 0xe911,
+	0xe913, 0xe933, 0xe911, 0xe911, 0xe911, 0xe911, 0xe911, 0xe911,
+	0xe911, 0x080c, 0x0dd5, 0x00d6, 0x2c68, 0x080c, 0xaeed, 0x01b0,
+	0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0x026e, 0x210c, 0x613a,
+	0x2009, 0x026f, 0x210c, 0x613e, 0x600b, 0xffff, 0x6910, 0x6112,
+	0x6023, 0x0004, 0x080c, 0x91b1, 0x080c, 0x9763, 0x2d60, 0x080c,
+	0xaf43, 0x00de, 0x0005, 0x080c, 0xaf43, 0x0005, 0x00e6, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0ec, 0x00ee, 0x0005, 0x2009,
+	0x1867, 0x210c, 0xd1ec, 0x05b0, 0x6003, 0x0002, 0x6024, 0xc0e5,
+	0x6026, 0xd0cc, 0x0150, 0x2001, 0x1987, 0x2004, 0x6042, 0x2009,
+	0x1867, 0x210c, 0xd1f4, 0x1520, 0x00a0, 0x2009, 0x1867, 0x210c,
+	0xd1f4, 0x0128, 0x6024, 0xc0e4, 0x6026, 0x9006, 0x00d8, 0x2001,
+	0x1987, 0x200c, 0x2001, 0x1985, 0x2004, 0x9100, 0x9080, 0x000a,
+	0x6042, 0x6010, 0x00b6, 0x2058, 0xb8bc, 0x00be, 0x0008, 0x2104,
+	0x9005, 0x0118, 0x9088, 0x0003, 0x0cd0, 0x2c0a, 0x600f, 0x0000,
+	0x9085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x6154, 0xb8bc,
+	0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, 0x6054, 0x9106, 0x1138,
+	0x600c, 0x2072, 0x080c, 0x876f, 0x080c, 0xaf43, 0x0010, 0x9cf0,
+	0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, 0x001e, 0x0005, 0x00d6,
+	0x00b6, 0x6010, 0x2058, 0xb8bc, 0x2068, 0x9005, 0x0130, 0x9c06,
+	0x0110, 0x680c, 0x0cd0, 0x600c, 0x680e, 0x00be, 0x00de, 0x0005,
+	0x0026, 0x0036, 0x0156, 0x2011, 0x182c, 0x2204, 0x9084, 0x00ff,
+	0x2019, 0x026e, 0x2334, 0x9636, 0x1508, 0x8318, 0x2334, 0x2204,
+	0x9084, 0xff00, 0x9636, 0x11d0, 0x2011, 0x0270, 0x20a9, 0x0004,
+	0x6010, 0x0096, 0x2048, 0x2019, 0x000a, 0x080c, 0xbf11, 0x009e,
+	0x1168, 0x2011, 0x0274, 0x20a9, 0x0004, 0x6010, 0x0096, 0x2048,
+	0x2019, 0x0006, 0x080c, 0xbf11, 0x009e, 0x1100, 0x015e, 0x003e,
+	0x002e, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c, 0x6040, 0x080c,
+	0x2ff5, 0x00ee, 0x0005, 0x0096, 0x0026, 0x080c, 0x0fff, 0x090c,
+	0x0dd5, 0xa85c, 0x9080, 0x001a, 0x20a0, 0x20a9, 0x000c, 0xa860,
+	0x20e8, 0x9006, 0x4004, 0x9186, 0x0046, 0x1118, 0xa867, 0x0136,
+	0x0038, 0xa867, 0x0138, 0x9186, 0x0041, 0x0110, 0xa87b, 0x0001,
+	0x7038, 0x9084, 0xff00, 0x7240, 0x9294, 0xff00, 0x8007, 0x9215,
+	0xaa9a, 0x9186, 0x0046, 0x1168, 0x7038, 0x9084, 0x00ff, 0x723c,
+	0x9294, 0xff00, 0x9215, 0xaa9e, 0x723c, 0x9294, 0x00ff, 0xaaa2,
+	0x0060, 0x7040, 0x9084, 0x00ff, 0x7244, 0x9294, 0xff00, 0x9215,
+	0xaa9e, 0x7244, 0x9294, 0x00ff, 0xaaa2, 0x9186, 0x0046, 0x1118,
+	0x9e90, 0x0012, 0x0010, 0x9e90, 0x001a, 0x2204, 0x8007, 0xa8a6,
+	0x8210, 0x2204, 0x8007, 0xa8aa, 0x8210, 0x2204, 0x8007, 0xa8ae,
+	0x8210, 0x2204, 0x8007, 0xa8b2, 0x8210, 0x9186, 0x0046, 0x11b8,
+	0x9e90, 0x0016, 0x2204, 0x8007, 0xa8b6, 0x8210, 0x2204, 0x8007,
+	0xa8ba, 0x8210, 0x2204, 0x8007, 0xa8be, 0x8210, 0x2204, 0x8007,
+	0xa8c2, 0x8210, 0x2011, 0x0205, 0x2013, 0x0001, 0x00b0, 0x9e90,
+	0x001e, 0x2204, 0x8007, 0xa8b6, 0x8210, 0x2204, 0x8007, 0xa8ba,
+	0x2011, 0x0205, 0x2013, 0x0001, 0x2011, 0x0260, 0x2204, 0x8007,
+	0xa8be, 0x8210, 0x2204, 0x8007, 0xa8c2, 0x9186, 0x0046, 0x1118,
+	0x2011, 0x0262, 0x0010, 0x2011, 0x026a, 0x0146, 0x01d6, 0x0036,
+	0x20a9, 0x0001, 0x2019, 0x0008, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0031, 0x20a0, 0x2204, 0x8007, 0x4004, 0x8210, 0x8319, 0x1dd0,
+	0x003e, 0x01ce, 0x013e, 0x2011, 0x0205, 0x2013, 0x0000, 0x002e,
+	0x080c, 0x6d17, 0x009e, 0x0005, 0x00e6, 0x6010, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0fc, 0x0108, 0x0011, 0x00ee, 0x0005, 0xa880,
+	0xc0e5, 0xa882, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066,
+	0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000, 0x2029,
+	0x19ef, 0x252c, 0x2021, 0x19f5, 0x2424, 0x2061, 0x1cd0, 0x2071,
+	0x1800, 0x7654, 0x7074, 0x9606, 0x0578, 0x6720, 0x9786, 0x0001,
+	0x0118, 0x9786, 0x0008, 0x1500, 0x2500, 0x9c06, 0x01e8, 0x2400,
+	0x9c06, 0x01d0, 0x080c, 0xe76b, 0x01b8, 0x080c, 0xe77b, 0x11a0,
+	0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x1aa1, 0x001e,
+	0x080c, 0xce7d, 0x1110, 0x080c, 0x3247, 0x080c, 0xce8e, 0x1110,
+	0x080c, 0xb905, 0x080c, 0xaf74, 0x9ce0, 0x0018, 0x2001, 0x181a,
+	0x2004, 0x9c02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e, 0x004e,
+	0x005e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x2001,
+	0x1810, 0x2004, 0xd0dc, 0x0005, 0x0006, 0x2001, 0x1837, 0x2004,
+	0xd09c, 0x000e, 0x0005, 0x0006, 0x0036, 0x0046, 0x080c, 0xd388,
+	0x0168, 0x2019, 0xffff, 0x9005, 0x0128, 0x6010, 0x00b6, 0x2058,
+	0xbba0, 0x00be, 0x2021, 0x0004, 0x080c, 0x4d36, 0x004e, 0x003e,
+	0x000e, 0x6004, 0x9086, 0x0001, 0x1128, 0x080c, 0xa8dc, 0x080c,
+	0xaf74, 0x9006, 0x0005, 0x00e6, 0x00c6, 0x00b6, 0x0046, 0x2061,
+	0x1cd0, 0x2071, 0x1800, 0x7454, 0x7074, 0x8001, 0x9402, 0x12d8,
+	0x2100, 0x9c06, 0x0168, 0x6000, 0x9086, 0x0000, 0x0148, 0x6010,
+	0x2058, 0xb8a0, 0x9206, 0x1120, 0x6004, 0x9086, 0x0002, 0x0140,
+	0x9ce0, 0x0018, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1220, 0x0c40,
+	0x9085, 0x0001, 0x0008, 0x9006, 0x004e, 0x00be, 0x00ce, 0x00ee,
+	0x0005, 0x0126, 0x0006, 0x00e6, 0x0016, 0x2091, 0x8000, 0x2071,
+	0x1840, 0xd5a4, 0x0118, 0x7004, 0x8000, 0x7006, 0xd5b4, 0x0118,
+	0x7000, 0x8000, 0x7002, 0xd5ac, 0x0178, 0x2500, 0x9084, 0x0007,
+	0x908e, 0x0003, 0x0148, 0x908e, 0x0004, 0x0130, 0x908e, 0x0005,
+	0x0118, 0x2071, 0xfff6, 0x0089, 0x001e, 0x00ee, 0x000e, 0x012e,
+	0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xffee,
+	0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e05, 0x8000, 0x2077,
+	0x1220, 0x8e70, 0x2e05, 0x8000, 0x2077, 0x0005, 0x00e6, 0x2071,
+	0xffec, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xfff0, 0x0c69,
+	0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071,
+	0x1840, 0x7014, 0x8000, 0x7016, 0x00ee, 0x000e, 0x012e, 0x0005,
+	0x0003, 0x000b, 0x079e, 0x0000, 0xc000, 0x0001, 0x8064, 0x0008,
+	0x0010, 0x0000, 0x8066, 0x0000, 0x0101, 0x0008, 0x4407, 0x0003,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x580d, 0x000b, 0x79a8, 0x000b,
+	0x50ee, 0x000b, 0x4c0a, 0x0003, 0xbac0, 0x0009, 0x008a, 0x0000,
+	0x0c0a, 0x000b, 0x15fe, 0x0008, 0x340a, 0x0003, 0xc4c0, 0x0009,
+	0x7000, 0x0000, 0xffa0, 0x0001, 0x2000, 0x0000, 0x1668, 0x000b,
+	0x808c, 0x0008, 0x0001, 0x0000, 0x0000, 0x0007, 0x4028, 0x0000,
+	0x4047, 0x000a, 0x808c, 0x0008, 0x0002, 0x0000, 0x0822, 0x0003,
+	0x4022, 0x0000, 0x0028, 0x000b, 0x4122, 0x0008, 0x94c0, 0x0009,
+	0xff00, 0x0008, 0xffe0, 0x0009, 0x0500, 0x0008, 0x0a93, 0x000b,
+	0x4447, 0x0002, 0x0e90, 0x0003, 0x0bfe, 0x0008, 0x11a0, 0x0001,
+	0x126e, 0x0003, 0x0ca0, 0x0001, 0x126e, 0x0003, 0x9180, 0x0001,
+	0x0004, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x0009, 0x0008, 0x4436, 0x000b, 0x808c, 0x0008,
+	0x0000, 0x0008, 0x0060, 0x0008, 0x8062, 0x0008, 0x0004, 0x0000,
+	0x8066, 0x0000, 0x0411, 0x0000, 0x443e, 0x0003, 0x03fe, 0x0000,
+	0x43e0, 0x0001, 0x0e6b, 0x000b, 0xc2c0, 0x0009, 0x00ff, 0x0008,
+	0x02e0, 0x0001, 0x0e6b, 0x000b, 0x9180, 0x0001, 0x0005, 0x0008,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000,
+	0x0019, 0x0000, 0x444d, 0x000b, 0x0240, 0x0002, 0x0a68, 0x0003,
+	0x00fe, 0x0000, 0x326b, 0x000b, 0x0248, 0x000a, 0x085c, 0x0003,
+	0x9180, 0x0001, 0x0006, 0x0008, 0x7f62, 0x0008, 0x8002, 0x0008,
+	0x0003, 0x0008, 0x8066, 0x0000, 0x020a, 0x0000, 0x445b, 0x0003,
+	0x112a, 0x0000, 0x002e, 0x0008, 0x022c, 0x0008, 0x3a44, 0x0002,
+	0x0c0a, 0x000b, 0x808c, 0x0008, 0x0002, 0x0000, 0x1760, 0x0008,
+	0x8062, 0x0008, 0x000f, 0x0008, 0x8066, 0x0000, 0x0011, 0x0008,
+	0x4468, 0x0003, 0x01fe, 0x0008, 0x42e0, 0x0009, 0x0e5c, 0x0003,
+	0x00fe, 0x0000, 0x43e0, 0x0001, 0x0e5c, 0x0003, 0x1734, 0x0000,
+	0x1530, 0x0000, 0x1632, 0x0008, 0x0d2a, 0x0008, 0x9880, 0x0001,
+	0x0010, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x1e0a, 0x0008, 0x447a, 0x0003, 0x808a, 0x0008,
+	0x0003, 0x0008, 0x1a60, 0x0000, 0x8062, 0x0008, 0x0002, 0x0000,
+	0x5880, 0x000b, 0x8066, 0x0000, 0x3679, 0x0000, 0x4483, 0x0003,
+	0x5884, 0x0003, 0x3efe, 0x0008, 0x7f4f, 0x0002, 0x088a, 0x000b,
+	0x0d00, 0x0000, 0x0092, 0x000c, 0x8054, 0x0008, 0x0011, 0x0008,
+	0x8074, 0x0000, 0x1010, 0x0008, 0x1efe, 0x0000, 0x300a, 0x000b,
+	0x00c8, 0x000c, 0x000a, 0x000b, 0x00fe, 0x0000, 0x349a, 0x0003,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x0007, 0x0000, 0x8066, 0x0000,
+	0x0231, 0x0008, 0x4499, 0x000b, 0x03fe, 0x0000, 0x04d0, 0x0001,
+	0x0cc0, 0x000b, 0x82c0, 0x0001, 0x1f00, 0x0000, 0xffa0, 0x0001,
+	0x0400, 0x0000, 0x08af, 0x0003, 0x14c0, 0x000b, 0x01fe, 0x0008,
+	0x0580, 0x0009, 0x7f06, 0x0000, 0x02fe, 0x0008, 0xffc0, 0x0001,
+	0x00ff, 0x0008, 0x0690, 0x0001, 0x10af, 0x0003, 0x7f08, 0x0008,
+	0x84c0, 0x0001, 0xff00, 0x0008, 0x08c0, 0x0003, 0x00fe, 0x0000,
+	0x34b6, 0x000b, 0x8072, 0x0000, 0x1010, 0x0008, 0x3944, 0x0002,
+	0x08b1, 0x0003, 0x00ba, 0x0003, 0x8072, 0x0000, 0x2020, 0x0008,
+	0x3945, 0x000a, 0x08b6, 0x000b, 0x3946, 0x000a, 0x0cc7, 0x0003,
+	0x0000, 0x0007, 0x3943, 0x000a, 0x08c7, 0x000b, 0x00ba, 0x0003,
+	0x00fe, 0x0000, 0x34c5, 0x0003, 0x8072, 0x0000, 0x1000, 0x0000,
+	0x00c7, 0x0003, 0x8072, 0x0000, 0x2000, 0x0000, 0x4000, 0x000f,
+	0x1c60, 0x0000, 0x1b62, 0x0000, 0x8066, 0x0000, 0x0231, 0x0008,
+	0x44cc, 0x000b, 0x58cd, 0x000b, 0x0140, 0x0008, 0x0242, 0x0000,
+	0x1f43, 0x0002, 0x0cdb, 0x000b, 0x0d44, 0x0000, 0x0d46, 0x0008,
+	0x0348, 0x0008, 0x044a, 0x0008, 0x030a, 0x0008, 0x040c, 0x0000,
+	0x0d06, 0x0000, 0x0d08, 0x0008, 0x00df, 0x0003, 0x0344, 0x0008,
+	0x0446, 0x0008, 0x0548, 0x0008, 0x064a, 0x0000, 0x1948, 0x000a,
+	0x08e2, 0x0003, 0x0d4a, 0x0008, 0x58e2, 0x0003, 0x3efe, 0x0008,
+	0x7f4f, 0x0002, 0x08e9, 0x000b, 0x8000, 0x0000, 0x0001, 0x0000,
+	0x0092, 0x000c, 0x8054, 0x0008, 0x0001, 0x0000, 0x8074, 0x0000,
+	0x2020, 0x0008, 0x4000, 0x000f, 0x3a40, 0x000a, 0x0c0d, 0x0003,
+	0x2b24, 0x0008, 0x2b24, 0x0008, 0x58f2, 0x000b, 0x8054, 0x0008,
+	0x0002, 0x0000, 0x1242, 0x0002, 0x0940, 0x0003, 0x3a45, 0x000a,
+	0x092f, 0x0003, 0x8072, 0x0000, 0x1000, 0x0000, 0x3945, 0x000a,
+	0x08ff, 0x0003, 0x8072, 0x0000, 0x3010, 0x0000, 0x1e10, 0x000a,
+	0x7f3c, 0x0000, 0x092a, 0x0003, 0x1d00, 0x0002, 0x7f3a, 0x0000,
+	0x0d60, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008,
+	0x4508, 0x000b, 0x00fe, 0x0000, 0x3527, 0x000b, 0x1c60, 0x0000,
+	0x8062, 0x0008, 0x0001, 0x0000, 0x8066, 0x0000, 0x0009, 0x0008,
+	0x4510, 0x000b, 0x00fe, 0x0000, 0x3243, 0x000b, 0x0038, 0x0000,
+	0x0060, 0x0008, 0x8062, 0x0008, 0x0019, 0x0000, 0x8066, 0x0000,
+	0x0009, 0x0008, 0x4519, 0x000b, 0x80c0, 0x0009, 0x00ff, 0x0008,
+	0x7f3e, 0x0008, 0x0d60, 0x0000, 0x0efe, 0x0008, 0x1f80, 0x0001,
+	0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008, 0x4523, 0x000b,
+	0x003a, 0x0008, 0x1dfe, 0x0000, 0x0104, 0x000b, 0x0036, 0x0008,
+	0x00c8, 0x000c, 0x0140, 0x000b, 0x8074, 0x0000, 0x2000, 0x0000,
+	0x8072, 0x0000, 0x2000, 0x0000, 0x0140, 0x000b, 0x3a44, 0x0002,
+	0x0a71, 0x000b, 0x8074, 0x0000, 0x1000, 0x0000, 0x8072, 0x0000,
+	0x1000, 0x0000, 0x2d0e, 0x0000, 0x2d0e, 0x0000, 0x3640, 0x0003,
+	0x26fe, 0x0008, 0x26fe, 0x0008, 0x2700, 0x0008, 0x2700, 0x0008,
+	0x00d0, 0x0009, 0x0d52, 0x000b, 0x8074, 0x0000, 0x4040, 0x0008,
+	0x5940, 0x0003, 0x50ee, 0x000b, 0x3a46, 0x000a, 0x0d52, 0x000b,
+	0x3a47, 0x0002, 0x094d, 0x000b, 0x8054, 0x0008, 0x0004, 0x0000,
+	0x8074, 0x0000, 0x8000, 0x0000, 0x8072, 0x0000, 0x3000, 0x0008,
+	0x019c, 0x0003, 0x92c0, 0x0009, 0x0fc8, 0x0000, 0x080a, 0x0003,
+	0x1246, 0x000a, 0x0e3a, 0x0003, 0x1a60, 0x0000, 0x8062, 0x0008,
+	0x0002, 0x0000, 0x8066, 0x0000, 0x362a, 0x0000, 0x4557, 0x000b,
+	0x2000, 0x0000, 0x2000, 0x0000, 0x2102, 0x0000, 0x2102, 0x0000,
+	0x2204, 0x0000, 0x2204, 0x0000, 0x2306, 0x0000, 0x2306, 0x0000,
+	0x2408, 0x0000, 0x2408, 0x0000, 0x250a, 0x0000, 0x250a, 0x0000,
+	0x260c, 0x0000, 0x260c, 0x0000, 0x270e, 0x0000, 0x270e, 0x0000,
+	0x2810, 0x0000, 0x2810, 0x0000, 0x2912, 0x0000, 0x2912, 0x0000,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x0007, 0x0000, 0x8066, 0x0000,
+	0x0052, 0x0000, 0x4571, 0x0003, 0x92c0, 0x0009, 0x0780, 0x0008,
+	0x0e56, 0x0003, 0x124b, 0x0002, 0x097a, 0x0003, 0x2e4d, 0x0002,
+	0x2e4d, 0x0002, 0x0a40, 0x0003, 0x3a46, 0x000a, 0x0d8a, 0x000b,
+	0x597c, 0x0003, 0x8054, 0x0008, 0x0004, 0x0000, 0x1243, 0x000a,
+	0x0998, 0x0003, 0x8010, 0x0008, 0x000d, 0x0000, 0x021b, 0x000c,
+	0x1948, 0x000a, 0x0987, 0x000b, 0x0210, 0x0004, 0x1810, 0x0000,
+	0x021b, 0x000c, 0x0198, 0x000b, 0x1948, 0x000a, 0x098e, 0x000b,
+	0x1243, 0x000a, 0x0a43, 0x0003, 0x194d, 0x000a, 0x0992, 0x0003,
+	0x1243, 0x000a, 0x0a4a, 0x0003, 0x5992, 0x0003, 0x8054, 0x0008,
+	0x0004, 0x0000, 0x0210, 0x0004, 0x1810, 0x0000, 0x021b, 0x000c,
+	0x8074, 0x0000, 0xf000, 0x0008, 0x8072, 0x0000, 0x3000, 0x0008,
+	0x0d30, 0x0000, 0x3a42, 0x0002, 0x0da2, 0x000b, 0x15fe, 0x0008,
+	0x3461, 0x000b, 0x000a, 0x000b, 0x8074, 0x0000, 0x0501, 0x0000,
+	0x8010, 0x0008, 0x000c, 0x0008, 0x021b, 0x000c, 0x000a, 0x000b,
+	0xbbe0, 0x0009, 0x0030, 0x0008, 0x0db8, 0x0003, 0x18fe, 0x0000,
+	0x3ce0, 0x0009, 0x09b5, 0x0003, 0x15fe, 0x0008, 0x3ce0, 0x0009,
+	0x09b5, 0x0003, 0x020b, 0x0004, 0x8076, 0x0008, 0x0040, 0x0000,
+	0x0208, 0x000b, 0x8076, 0x0008, 0x0041, 0x0008, 0x0208, 0x000b,
+	0xbbe0, 0x0009, 0x0032, 0x0000, 0x0dbd, 0x0003, 0x3c1e, 0x0008,
+	0x0208, 0x000b, 0xbbe0, 0x0009, 0x003b, 0x0000, 0x0dc2, 0x000b,
+	0x3c20, 0x0000, 0x0208, 0x000b, 0xbbe0, 0x0009, 0x0035, 0x0008,
+	0x0dc8, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, 0x0384, 0x000b,
+	0xbbe0, 0x0009, 0x0036, 0x0008, 0x0aa5, 0x000b, 0xbbe0, 0x0009,
+	0x0037, 0x0000, 0x0de9, 0x000b, 0x18fe, 0x0000, 0x3ce0, 0x0009,
+	0x0db5, 0x000b, 0x8076, 0x0008, 0x0040, 0x0000, 0x1a60, 0x0000,
+	0x8062, 0x0008, 0x000d, 0x0000, 0x2604, 0x0008, 0x2604, 0x0008,
+	0x2706, 0x0008, 0x2706, 0x0008, 0x2808, 0x0000, 0x2808, 0x0000,
+	0x290a, 0x0000, 0x290a, 0x0000, 0x8066, 0x0000, 0x0422, 0x0000,
+	0x45e0, 0x000b, 0x0210, 0x0004, 0x8054, 0x0008, 0x0004, 0x0000,
+	0x8074, 0x0000, 0xf000, 0x0008, 0x8072, 0x0000, 0xb000, 0x0000,
+	0x019c, 0x0003, 0xbbe0, 0x0009, 0x0038, 0x0000, 0x0dfb, 0x000b,
+	0x18fe, 0x0000, 0x3ce0, 0x0009, 0x09f8, 0x0003, 0x15fe, 0x0008,
+	0x3ce0, 0x0009, 0x0db1, 0x0003, 0x020b, 0x0004, 0x8076, 0x0008,
+	0x0040, 0x0000, 0x8072, 0x0000, 0x8000, 0x0000, 0x0268, 0x000b,
+	0x8076, 0x0008, 0x0042, 0x0008, 0x0208, 0x000b, 0xbbe0, 0x0009,
+	0x0016, 0x0000, 0x0e08, 0x000b, 0x8074, 0x0000, 0x0808, 0x0008,
+	0x3a44, 0x0002, 0x0c0c, 0x000b, 0x8074, 0x0000, 0x0800, 0x0000,
+	0x8072, 0x0000, 0x8000, 0x0000, 0x8000, 0x000f, 0x000a, 0x000b,
+	0x8072, 0x0000, 0x8000, 0x0000, 0x000a, 0x000b, 0x3d30, 0x000a,
+	0x7f00, 0x0000, 0xbc80, 0x0001, 0x0007, 0x0000, 0x0214, 0x0003,
+	0x1930, 0x000a, 0x7f00, 0x0000, 0x9880, 0x0001, 0x0007, 0x0000,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000,
+	0x000a, 0x0008, 0x4619, 0x000b, 0x4000, 0x000f, 0x221e, 0x000b,
+	0x0870, 0x0008, 0x4000, 0x000f, 0x7e1b, 0x000b, 0xbbe0, 0x0009,
+	0x0030, 0x0008, 0x0e1b, 0x0003, 0x18fe, 0x0000, 0x3ce0, 0x0009,
+	0x0a2c, 0x0003, 0x15fe, 0x0008, 0x3ce0, 0x0009, 0x0a2c, 0x0003,
+	0x020b, 0x0004, 0x8076, 0x0008, 0x0040, 0x0000, 0x022e, 0x0003,
+	0x8076, 0x0008, 0x0041, 0x0008, 0x8072, 0x0000, 0x8000, 0x0000,
+	0x021b, 0x0003, 0xbac0, 0x0009, 0x0090, 0x0008, 0x0a37, 0x0003,
+	0x8074, 0x0000, 0x0706, 0x0000, 0x0239, 0x0003, 0x8074, 0x0000,
+	0x0703, 0x0000, 0x4000, 0x000f, 0x8010, 0x0008, 0x0023, 0x0000,
+	0x0276, 0x000b, 0x8010, 0x0008, 0x0008, 0x0000, 0x0276, 0x000b,
+	0x8010, 0x0008, 0x0022, 0x0008, 0x0276, 0x000b, 0x0210, 0x0004,
+	0x8010, 0x0008, 0x0007, 0x0000, 0x021b, 0x000c, 0x1810, 0x0000,
+	0x021b, 0x000c, 0x0282, 0x0003, 0x0210, 0x0004, 0x8010, 0x0008,
+	0x001b, 0x0008, 0x021b, 0x000c, 0x1810, 0x0000, 0x021b, 0x000c,
+	0x8074, 0x0000, 0xf080, 0x0000, 0x8072, 0x0000, 0x3000, 0x0008,
+	0x0d30, 0x0000, 0x000a, 0x000b, 0x8010, 0x0008, 0x0009, 0x0008,
+	0x0276, 0x000b, 0x8010, 0x0008, 0x0005, 0x0008, 0x0276, 0x000b,
+	0x1648, 0x000a, 0x0c6f, 0x000b, 0x808c, 0x0008, 0x0001, 0x0000,
+	0x8010, 0x0008, 0x0004, 0x0000, 0x4143, 0x000a, 0x086f, 0x0003,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x0d2a, 0x0008, 0x0276, 0x000b,
+	0x8010, 0x0008, 0x0003, 0x0008, 0x027a, 0x000b, 0x8010, 0x0008,
+	0x000b, 0x0000, 0x027a, 0x000b, 0x8010, 0x0008, 0x0002, 0x0000,
+	0x027a, 0x000b, 0x3a47, 0x0002, 0x0d40, 0x000b, 0x8010, 0x0008,
+	0x0006, 0x0008, 0x027a, 0x000b, 0x8074, 0x0000, 0xf000, 0x0008,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x021b, 0x000c, 0x0231, 0x0004,
+	0x3a40, 0x000a, 0x080a, 0x0003, 0x8010, 0x0008, 0x000c, 0x0008,
+	0x021b, 0x000c, 0x000a, 0x000b, 0x8074, 0x0000, 0xf080, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000, 0x2e4d, 0x0002,
+	0x2e4d, 0x0002, 0x0a8d, 0x000b, 0x8054, 0x0008, 0x0019, 0x0000,
+	0x000a, 0x000b, 0x8054, 0x0008, 0x0009, 0x0008, 0x000a, 0x000b,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x026b, 0x000b, 0x808c, 0x0008,
+	0x0000, 0x0008, 0x4447, 0x0002, 0x0ab9, 0x0003, 0xc0c0, 0x0001,
+	0x00ff, 0x0008, 0xffe0, 0x0009, 0x00ff, 0x0008, 0x0e90, 0x0003,
+	0xc1e0, 0x0001, 0xffff, 0x0008, 0x0e90, 0x0003, 0x8010, 0x0008,
+	0x0013, 0x0000, 0x021b, 0x000c, 0x8074, 0x0000, 0x0202, 0x0008,
+	0x000a, 0x000b, 0x3a40, 0x000a, 0x0eb6, 0x000b, 0x8074, 0x0000,
+	0x0200, 0x0000, 0x3d00, 0x0000, 0x3cfe, 0x0000, 0x8072, 0x0000,
+	0x8000, 0x0000, 0x43e0, 0x0001, 0x0eb4, 0x0003, 0x42fe, 0x0000,
+	0xffc0, 0x0001, 0x00ff, 0x0008, 0x00e0, 0x0009, 0x0a90, 0x000b,
+	0x0d08, 0x0008, 0x0309, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000,
+	0x000a, 0x000b, 0x038d, 0x0004, 0x808c, 0x0008, 0x0001, 0x0000,
+	0x04fe, 0x0008, 0x3370, 0x0003, 0x0460, 0x0000, 0x8062, 0x0008,
+	0x0001, 0x0000, 0x8066, 0x0000, 0x0009, 0x0008, 0x46c3, 0x0003,
+	0x0004, 0x0000, 0x80c0, 0x0009, 0x00ff, 0x0008, 0x7f00, 0x0000,
+	0x80e0, 0x0001, 0x0004, 0x0000, 0x0add, 0x000b, 0x80e0, 0x0001,
+	0x0005, 0x0008, 0x0add, 0x000b, 0x80e0, 0x0001, 0x0006, 0x0008,
+	0x0add, 0x000b, 0x82c0, 0x0001, 0xff00, 0x0008, 0x7f04, 0x0008,
+	0x82e0, 0x0009, 0x0600, 0x0008, 0x0add, 0x000b, 0x82e0, 0x0009,
+	0x0500, 0x0008, 0x0add, 0x000b, 0x82e0, 0x0009, 0x0400, 0x0000,
+	0x0f70, 0x0003, 0xc4c0, 0x0009, 0x7000, 0x0000, 0xffe0, 0x0009,
+	0x1000, 0x0000, 0x0b09, 0x0003, 0x037e, 0x0004, 0x3941, 0x0002,
+	0x0ae8, 0x000b, 0x8072, 0x0000, 0x0400, 0x0000, 0x000a, 0x000b,
+	0x0460, 0x0000, 0x80fe, 0x0008, 0x002b, 0x0008, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x2209, 0x0008, 0x46ee, 0x0003, 0x11fe, 0x0000,
+	0x3304, 0x0003, 0x9180, 0x0001, 0x0002, 0x0000, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0609, 0x0008,
+	0x46f8, 0x000b, 0x42fe, 0x0000, 0xffc0, 0x0001, 0xff00, 0x0008,
+	0x03e0, 0x0009, 0x0f01, 0x0003, 0x8072, 0x0000, 0x0400, 0x0000,
+	0x0046, 0x0003, 0x9180, 0x0001, 0x0003, 0x0008, 0x02eb, 0x0003,
+	0x8072, 0x0000, 0x0400, 0x0000, 0x8010, 0x0008, 0x0010, 0x0000,
+	0x0361, 0x0003, 0x037e, 0x0004, 0x3941, 0x0002, 0x0b0f, 0x0003,
+	0x8072, 0x0000, 0x0400, 0x0000, 0x000a, 0x000b, 0x0346, 0x000c,
+	0x11fe, 0x0000, 0x3717, 0x0003, 0x8072, 0x0000, 0x0400, 0x0000,
+	0x8010, 0x0008, 0x000e, 0x0000, 0x0361, 0x0003, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x04fe, 0x0008, 0x372c, 0x000b, 0x808c, 0x0008,
+	0x0000, 0x0008, 0x9180, 0x0001, 0x0005, 0x0008, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x0009, 0x0008, 0x4722, 0x000b, 0x0060, 0x0008,
+	0x8062, 0x0008, 0x001b, 0x0008, 0x4304, 0x0008, 0x4206, 0x0008,
+	0x8066, 0x0000, 0x0412, 0x0000, 0x472a, 0x0003, 0x0343, 0x0003,
+	0x808c, 0x0008, 0x0001, 0x0000, 0x0460, 0x0000, 0x8062, 0x0008,
+	0x002b, 0x0008, 0x8066, 0x0000, 0x0609, 0x0008, 0x4733, 0x000b,
+	0x8066, 0x0000, 0x220a, 0x0008, 0x4736, 0x000b, 0x42fe, 0x0000,
+	0xffc0, 0x0001, 0xff00, 0x0008, 0x7f04, 0x0008, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x9180, 0x0001, 0x0002, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x041a, 0x0008, 0x4742, 0x000b, 0x8072, 0x0000,
+	0x0400, 0x0000, 0x0046, 0x0003, 0x8060, 0x0000, 0x0400, 0x0000,
+	0x1362, 0x0008, 0x8066, 0x0000, 0x0411, 0x0000, 0x474b, 0x000b,
+	0x02fe, 0x0008, 0x03e0, 0x0009, 0x0f51, 0x0003, 0x0d22, 0x0000,
+	0x4000, 0x000f, 0x8280, 0x0009, 0x0002, 0x0000, 0x1380, 0x0001,
+	0x7f62, 0x0008, 0x8066, 0x0000, 0x2209, 0x0008, 0x4757, 0x0003,
+	0x0200, 0x000a, 0xffc0, 0x0001, 0x0007, 0x0000, 0x7f06, 0x0000,
+	0x1362, 0x0008, 0x8066, 0x0000, 0x060a, 0x0008, 0x475f, 0x000b,
+	0x4000, 0x000f, 0x3a44, 0x0002, 0x0c0a, 0x000b, 0x2f44, 0x000a,
+	0x2f44, 0x000a, 0x0e6b, 0x000b, 0x808a, 0x0008, 0x0003, 0x0008,
+	0x8074, 0x0000, 0xf080, 0x0000, 0x8072, 0x0000, 0x3000, 0x0008,
+	0x5b6c, 0x0003, 0x8054, 0x0008, 0x0019, 0x0000, 0x000a, 0x000b,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x808c, 0x0008, 0x0000, 0x0008,
+	0x8010, 0x0008, 0x0011, 0x0008, 0x021b, 0x000c, 0x42fe, 0x0000,
+	0xffc0, 0x0001, 0x00ff, 0x0008, 0x7f10, 0x0008, 0x021b, 0x000c,
+	0x4310, 0x0008, 0x027a, 0x000b, 0x3941, 0x0002, 0x0b81, 0x0003,
+	0x4000, 0x000f, 0x8072, 0x0000, 0x0404, 0x0008, 0x4000, 0x000f,
+	0x8010, 0x0008, 0x0012, 0x0008, 0x021b, 0x000c, 0x0346, 0x000c,
+	0x1110, 0x0000, 0x021b, 0x000c, 0x11fe, 0x0000, 0x3787, 0x0003,
+	0x000a, 0x000b, 0xc2c0, 0x0009, 0x00ff, 0x0008, 0x7f00, 0x0000,
+	0xc3c0, 0x0001, 0xff00, 0x0008, 0x00d0, 0x0009, 0x0bb2, 0x0003,
+	0x0d0a, 0x0000, 0x8580, 0x0001, 0x1000, 0x0000, 0x7f62, 0x0008,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x8066, 0x0000, 0x0809, 0x0000,
+	0x479c, 0x000b, 0x04fe, 0x0008, 0x33ab, 0x0003, 0x0460, 0x0000,
+	0x8062, 0x0008, 0x0004, 0x0000, 0x8066, 0x0000, 0x0211, 0x0000,
+	0x47a4, 0x0003, 0x01fe, 0x0008, 0x00e0, 0x0009, 0x0fab, 0x0003,
+	0x02fe, 0x0008, 0x43e0, 0x0001, 0x0bb1, 0x0003, 0x0500, 0x0002,
+	0x7f0a, 0x0000, 0xffe0, 0x0009, 0x0800, 0x0000, 0x0f95, 0x000b,
+	0x0d08, 0x0008, 0x4000, 0x000f, 0x43fe, 0x0008, 0x3e80, 0x0001,
+	0xffc0, 0x0001, 0x7fff, 0x0000, 0x0d60, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x0809, 0x0000, 0x47ba, 0x0003, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x84c0, 0x0001, 0xff00, 0x0008, 0x7f60, 0x000a,
+	0x7f60, 0x000a, 0x7f60, 0x000a, 0x7f60, 0x000a, 0x7f60, 0x000a,
+	0x7f60, 0x000a, 0x7f60, 0x000a, 0x7f60, 0x000a, 0xff80, 0x0009,
+	0x1000, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0809, 0x0000,
+	0x47cc, 0x000b, 0x4000, 0x000f, 0x5ff4, 0xebed, 0x0001, 0x0002,
+	0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,
+	0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0xa258
+};
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300ipx_length01 = 0xeb57;
+#else
+unsigned short risc_code_length01 = 0xeb57;
+#endif
+
diff --git a/drivers/scsi/qla2xxx/ql2322.c b/drivers/scsi/qla2xxx/ql2322.c
new file mode 100644
index 0000000..70b6d75
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2322.c
@@ -0,0 +1,108 @@
+/*
+ * QLogic ISP2322 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation (www.qlogic.com)
+ *
+ * Released under GPL v2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "qla_def.h"
+
+static char qla_driver_name[] = "qla2322";
+
+extern unsigned char  fw2322ipx_version[];
+extern unsigned char  fw2322ipx_version_str[];
+extern unsigned short fw2322ipx_addr01;
+extern unsigned short fw2322ipx_code01[];
+extern unsigned short fw2322ipx_length01;
+extern unsigned long rseqipx_code_addr01;
+extern unsigned short rseqipx_code01[];
+extern unsigned short rseqipx_code_length01;
+extern unsigned long xseqipx_code_addr01;
+extern unsigned short xseqipx_code01[];
+extern unsigned short xseqipx_code_length01;
+
+static struct qla_fw_info qla_fw_tbl[] = {
+	{
+		.addressing	= FW_INFO_ADDR_NORMAL,
+		.fwcode		= &fw2322ipx_code01[0],
+		.fwlen		= &fw2322ipx_length01,
+		.fwstart	= &fw2322ipx_addr01,
+	},
+	{
+		.addressing	= FW_INFO_ADDR_EXTENDED,
+		.fwcode		= &rseqipx_code01[0],
+		.fwlen		= &rseqipx_code_length01,
+		.lfwstart	= &rseqipx_code_addr01,
+	},
+	{
+		.addressing	= FW_INFO_ADDR_EXTENDED,
+		.fwcode		= &xseqipx_code01[0],
+		.fwlen		= &xseqipx_code_length01,
+		.lfwstart	= &xseqipx_code_addr01,
+	},
+	{ FW_INFO_ADDR_NOMORE, },
+};
+
+static struct qla_board_info qla_board_tbl[] = {
+	{
+		.drv_name	= qla_driver_name,
+		.isp_name	= "ISP2322",
+		.fw_info	= qla_fw_tbl,
+	},
+};
+
+static struct pci_device_id qla2322_pci_tbl[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP2322,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl[0],
+	},
+	{0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla2322_pci_tbl);
+
+static int __devinit
+qla2322_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return qla2x00_probe_one(pdev,
+	    (struct qla_board_info *)id->driver_data);
+}
+
+static void __devexit
+qla2322_remove_one(struct pci_dev *pdev)
+{
+	qla2x00_remove_one(pdev);
+}
+
+static struct pci_driver qla2322_pci_driver = {
+	.name		= "qla2322",
+	.id_table	= qla2322_pci_tbl,
+	.probe		= qla2322_probe_one,
+	.remove		= __devexit_p(qla2322_remove_one),
+};
+
+static int __init
+qla2322_init(void)
+{
+	return pci_module_init(&qla2322_pci_driver);
+}
+
+static void __exit
+qla2322_exit(void)
+{
+	pci_unregister_driver(&qla2322_pci_driver);
+}
+
+module_init(qla2322_init);
+module_exit(qla2322_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP2322 FC-SCSI Host Bus Adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/ql2322_fw.c b/drivers/scsi/qla2xxx/ql2322_fw.c
new file mode 100644
index 0000000..d8c5a8d
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql2322_fw.c
@@ -0,0 +1,8124 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+/*
+ *	Firmware Version 3.03.08 (10:03 Nov 12, 2004)
+ */
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2322ipx_version = 3*1024+3;
+#else
+unsigned short risc_code_version = 3*1024+3;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned char fw2322ipx_version_str[] = {3, 3, 8};
+#else
+unsigned char firmware_version[] = {3, 3, 8};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw2322ipx_VERSION_STRING "3.03.08"
+#else
+#define FW_VERSION_STRING "3.03.08"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2322ipx_addr01 = 0x0800 ;
+#else
+unsigned short risc_code_addr01 = 0x0800 ;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2322ipx_code01[] = { 
+#else
+unsigned short risc_code01[] = { 
+#endif
+	0x0470, 0x0000, 0x0000, 0xe0c2, 0x0000, 0x0003, 0x0003, 0x0008,
+	0x0137, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030,
+	0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3233, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x332e, 0x3033, 0x2e30, 0x3820, 0x2020, 0x2020, 0x2400, 0x20a9,
+	0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2200, 0x20a9, 0x000f,
+	0x2001, 0x0000, 0x400f, 0x2091, 0x2400, 0x20a9, 0x000f, 0x2001,
+	0x0000, 0x400f, 0x2091, 0x2600, 0x20a9, 0x000f, 0x2001, 0x0000,
+	0x400f, 0x2091, 0x2800, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f,
+	0x2091, 0x2a00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091,
+	0x2c00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2e00,
+	0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2000, 0x2001,
+	0x0000, 0x20c1, 0x0004, 0x20c9, 0x1cff, 0x2059, 0x0000, 0x2b78,
+	0x7883, 0x0004, 0x2089, 0x2b14, 0x2051, 0x1800, 0x2a70, 0x20e1,
+	0x0001, 0x20e9, 0x0001, 0x2009, 0x0000, 0x080c, 0x0e62, 0x00f6,
+	0x7888, 0x9005, 0x11f8, 0x2061, 0xc000, 0x080c, 0x20b0, 0x1170,
+	0x2079, 0x0300, 0x080c, 0x20c6, 0x2061, 0xe000, 0x080c, 0x20b0,
+	0x1128, 0x2079, 0x0380, 0x080c, 0x20c6, 0x0060, 0x00fe, 0x7883,
+	0x4010, 0x7837, 0x4010, 0x7833, 0x0010, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0cf8, 0x00fe, 0x2029, 0x5600, 0x2031, 0xffff, 0x2039,
+	0x55dc, 0x2021, 0x0200, 0x20e9, 0x0001, 0x20a1, 0x0000, 0x20a9,
+	0x0800, 0x900e, 0x4104, 0x20e9, 0x0001, 0x20a1, 0x1000, 0x900e,
+	0x2001, 0x0dc1, 0x9084, 0x0fff, 0x20a8, 0x4104, 0x2001, 0x0000,
+	0x9086, 0x0000, 0x0120, 0x21a8, 0x4104, 0x8001, 0x1de0, 0x756e,
+	0x7672, 0x776a, 0x7476, 0x747a, 0x00e6, 0x2071, 0x1b50, 0x2472,
+	0x00ee, 0x20a1, 0x1ddc, 0x7170, 0x810d, 0x810d, 0x810d, 0x810d,
+	0x918c, 0x000f, 0x2001, 0x0001, 0x9112, 0x900e, 0x21a8, 0x4104,
+	0x8211, 0x1de0, 0x7170, 0x3400, 0x8001, 0x9102, 0x0120, 0x0218,
+	0x20a8, 0x900e, 0x4104, 0x2009, 0x1800, 0x810d, 0x810d, 0x810d,
+	0x810d, 0x810d, 0x918c, 0x001f, 0x2001, 0x0001, 0x9112, 0x20e9,
+	0x0001, 0x20a1, 0x0800, 0x900e, 0x20a9, 0x0800, 0x4104, 0x8211,
+	0x1dd8, 0x080c, 0x0f5f, 0x080c, 0x60a0, 0x080c, 0xac46, 0x080c,
+	0x1116, 0x080c, 0x1340, 0x080c, 0x1c06, 0x080c, 0x921f, 0x080c,
+	0x0d0f, 0x080c, 0x109b, 0x080c, 0x34b9, 0x080c, 0x7854, 0x080c,
+	0x6b01, 0x080c, 0x8992, 0x080c, 0x85f3, 0x080c, 0x22a1, 0x080c,
+	0x7f2a, 0x080c, 0x20df, 0x080c, 0x221d, 0x080c, 0x2296, 0x2091,
+	0x3009, 0x7883, 0x0000, 0x1004, 0x0943, 0x7880, 0x9086, 0x0002,
+	0x1190, 0x7883, 0x4000, 0x7837, 0x4000, 0x7833, 0x0010, 0x0e04,
+	0x0937, 0x2091, 0x5000, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004,
+	0xd084, 0x190c, 0x11ee, 0x2071, 0x1800, 0x7003, 0x0000, 0x780c,
+	0x9084, 0x0030, 0x9086, 0x0000, 0x190c, 0x0d7d, 0x2071, 0x1800,
+	0x7000, 0x908e, 0x0003, 0x1168, 0x080c, 0x4c17, 0x080c, 0x34e0,
+	0x080c, 0x78bc, 0x080c, 0x7039, 0x080c, 0x8a75, 0x080c, 0x861c,
+	0x0c68, 0x000b, 0x0c88, 0x096d, 0x096e, 0x0b09, 0x096b, 0x0bc3,
+	0x0d0e, 0x0d0e, 0x0d0e, 0x080c, 0x0d7d, 0x0005, 0x0126, 0x00f6,
+	0x2091, 0x8000, 0x7000, 0x9086, 0x0001, 0x1904, 0x0adc, 0x080c,
+	0x0eb2, 0x080c, 0x753d, 0x0150, 0x080c, 0x7560, 0x15b0, 0x2079,
+	0x0100, 0x7828, 0x9085, 0x1800, 0x782a, 0x0478, 0x080c, 0x746e,
+	0x7000, 0x9086, 0x0001, 0x1904, 0x0adc, 0x7098, 0x9086, 0x0028,
+	0x1904, 0x0adc, 0x080c, 0x85dc, 0x080c, 0x85ce, 0x2001, 0x0161,
+	0x2003, 0x0001, 0x2079, 0x0100, 0x2011, 0xffff, 0x080c, 0x2ab4,
+	0x7a28, 0x9295, 0x5e2c, 0x7a2a, 0x2011, 0x73b3, 0x080c, 0x86c8,
+	0x2011, 0x73a6, 0x080c, 0x87d4, 0x2011, 0x5ef7, 0x080c, 0x86c8,
+	0x2011, 0x8030, 0x901e, 0x7396, 0x04d0, 0x080c, 0x57a4, 0x2079,
+	0x0100, 0x7844, 0x9005, 0x1904, 0x0adc, 0x2011, 0x5ef7, 0x080c,
+	0x86c8, 0x2011, 0x73b3, 0x080c, 0x86c8, 0x2011, 0x73a6, 0x080c,
+	0x87d4, 0x2001, 0x0265, 0x2001, 0x0205, 0x2003, 0x0000, 0x7840,
+	0x9084, 0xfffb, 0x7842, 0x2001, 0x19a5, 0x2004, 0x9005, 0x1140,
+	0x00c6, 0x2061, 0x0100, 0x080c, 0x6048, 0x00ce, 0x0804, 0x0adc,
+	0x780f, 0x006b, 0x7a28, 0x080c, 0x7545, 0x0118, 0x9295, 0x5e2c,
+	0x0010, 0x9295, 0x402c, 0x7a2a, 0x2011, 0x8010, 0x73d8, 0x2001,
+	0x19a6, 0x2003, 0x0001, 0x080c, 0x297c, 0x080c, 0x4b52, 0x7248,
+	0xc284, 0x724a, 0x2001, 0x180c, 0x200c, 0xc1ac, 0xc1cc, 0x2102,
+	0x2001, 0x0390, 0x2003, 0x0400, 0x080c, 0xa91e, 0x080c, 0xa113,
+	0x2011, 0x0004, 0x080c, 0xc98a, 0x080c, 0xa93a, 0x080c, 0x6989,
+	0x080c, 0x753d, 0x1120, 0x080c, 0x29dd, 0x0600, 0x0420, 0x080c,
+	0x604f, 0x0140, 0x7097, 0x0001, 0x70d3, 0x0000, 0x080c, 0x5971,
+	0x0804, 0x0adc, 0x080c, 0x573e, 0xd094, 0x01a8, 0x2001, 0x0390,
+	0x2003, 0x0404, 0x2011, 0x180c, 0x2204, 0xc0cd, 0x2012, 0x080c,
+	0x5742, 0xd0d4, 0x1118, 0x080c, 0x29dd, 0x1270, 0x2011, 0x180c,
+	0x2204, 0xc0bc, 0x00a8, 0x080c, 0x5742, 0xd0d4, 0x1db8, 0x2011,
+	0x180c, 0x2204, 0xc0bd, 0x0060, 0x2011, 0x180c, 0x2204, 0xc0bd,
+	0x2012, 0x080c, 0x6ad5, 0x1128, 0xd0a4, 0x0118, 0x2204, 0xc0fd,
+	0x2012, 0x080c, 0x6a9b, 0x0120, 0x7a0c, 0xc2b4, 0x7a0e, 0x00a8,
+	0x707f, 0x0000, 0x080c, 0x753d, 0x1130, 0x70b0, 0x9005, 0x1168,
+	0x080c, 0xcde8, 0x0050, 0x080c, 0xcde8, 0x70dc, 0xd09c, 0x1128,
+	0x70b0, 0x9005, 0x0110, 0x080c, 0x6025, 0x70e7, 0x0000, 0x70e3,
+	0x0000, 0x70a7, 0x0000, 0x080c, 0x29e5, 0x0228, 0x2011, 0x0101,
+	0x2204, 0xc0c4, 0x2012, 0x72dc, 0x080c, 0x753d, 0x1178, 0x9016,
+	0x0016, 0x080c, 0x2779, 0x2019, 0x196c, 0x211a, 0x001e, 0x705f,
+	0xffff, 0x7063, 0x00ef, 0x7083, 0x0000, 0x0020, 0x2019, 0x196c,
+	0x201b, 0x0000, 0x2079, 0x1847, 0x7804, 0xd0ac, 0x0108, 0xc295,
+	0x72de, 0x080c, 0x753d, 0x0118, 0x9296, 0x0004, 0x0518, 0x2011,
+	0x0001, 0x080c, 0xc98a, 0x70ab, 0x0000, 0x70af, 0xffff, 0x7003,
+	0x0002, 0x00fe, 0x080c, 0x3011, 0x080c, 0xa91e, 0x2011, 0x0005,
+	0x080c, 0xa243, 0x080c, 0xa93a, 0x080c, 0x753d, 0x0148, 0x00c6,
+	0x2061, 0x0100, 0x0016, 0x080c, 0x2779, 0x61e2, 0x001e, 0x00ce,
+	0x012e, 0x00e0, 0x70ab, 0x0000, 0x70af, 0xffff, 0x7003, 0x0002,
+	0x080c, 0xa91e, 0x2011, 0x0005, 0x080c, 0xa243, 0x080c, 0xa93a,
+	0x080c, 0x753d, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, 0x080c,
+	0x2779, 0x61e2, 0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005, 0x00c6,
+	0x00b6, 0x080c, 0x753d, 0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9,
+	0x0782, 0x080c, 0x753d, 0x1110, 0x900e, 0x0010, 0x2009, 0x007e,
+	0x86ff, 0x0138, 0x9180, 0x1000, 0x2004, 0x905d, 0x0110, 0xb800,
+	0xd0bc, 0x090c, 0x3349, 0x8108, 0x1f04, 0x0af0, 0x707f, 0x0000,
+	0x7080, 0x9084, 0x00ff, 0x7082, 0x70b3, 0x0000, 0x00be, 0x00ce,
+	0x0005, 0x00b6, 0x0126, 0x2091, 0x8000, 0x7000, 0x9086, 0x0002,
+	0x1904, 0x0bc0, 0x70ac, 0x9086, 0xffff, 0x0120, 0x080c, 0x3011,
+	0x0804, 0x0bc0, 0x70dc, 0xd0ac, 0x1110, 0xd09c, 0x0538, 0xd084,
+	0x0528, 0x0006, 0x2001, 0x0103, 0x2003, 0x002b, 0x000e, 0xd08c,
+	0x01e8, 0x080c, 0x33b2, 0x11b0, 0x70e0, 0x9086, 0xffff, 0x0190,
+	0x080c, 0x31a6, 0x70dc, 0xd094, 0x1904, 0x0bc0, 0x2011, 0x0001,
+	0x080c, 0xd09b, 0x0110, 0x2011, 0x0003, 0x901e, 0x080c, 0x31e0,
+	0x0804, 0x0bc0, 0x70e4, 0x9005, 0x1904, 0x0bc0, 0x70a8, 0x9005,
+	0x1904, 0x0bc0, 0x70dc, 0xd0a4, 0x0118, 0xd0b4, 0x0904, 0x0bc0,
+	0x080c, 0x6a9b, 0x1904, 0x0bc0, 0x080c, 0x6aee, 0x1904, 0x0bc0,
+	0x080c, 0x6ad5, 0x01c0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x900e,
+	0x0016, 0x080c, 0x6693, 0x1118, 0xb800, 0xd0ec, 0x1138, 0x001e,
+	0x8108, 0x1f04, 0x0b60, 0x00ce, 0x015e, 0x0028, 0x001e, 0x00ce,
+	0x015e, 0x0804, 0x0bc0, 0x0006, 0x2001, 0x0103, 0x2003, 0x002b,
+	0x000e, 0x2011, 0x19b2, 0x080c, 0x0fcf, 0x2011, 0x19cc, 0x080c,
+	0x0fcf, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x70af, 0xffff,
+	0x080c, 0x0e86, 0x9006, 0x080c, 0x2606, 0x080c, 0x33b2, 0x0118,
+	0x080c, 0x4cef, 0x0050, 0x0036, 0x0046, 0x2019, 0xffff, 0x2021,
+	0x0006, 0x080c, 0x4d09, 0x004e, 0x003e, 0x00f6, 0x2079, 0x0100,
+	0x080c, 0x7560, 0x0150, 0x080c, 0x753d, 0x7828, 0x0118, 0x9084,
+	0xe1ff, 0x0010, 0x9084, 0xffdf, 0x782a, 0x00fe, 0x080c, 0xa91e,
+	0x2001, 0x19e7, 0x2004, 0x9086, 0x0005, 0x1120, 0x2011, 0x0000,
+	0x080c, 0xa243, 0x2011, 0x0000, 0x080c, 0xa24d, 0x080c, 0xa93a,
+	0x012e, 0x00be, 0x0005, 0x0016, 0x0026, 0x0046, 0x00f6, 0x0126,
+	0x2091, 0x8000, 0x2079, 0x0100, 0x7904, 0x918c, 0xfffd, 0x7906,
+	0x2009, 0x00f7, 0x080c, 0x600e, 0x7940, 0x918c, 0x0010, 0x7942,
+	0x7924, 0xd1b4, 0x0120, 0x2011, 0x0040, 0x080c, 0x2ab4, 0xd19c,
+	0x0120, 0x2011, 0x0008, 0x080c, 0x2ab4, 0x0006, 0x0036, 0x0156,
+	0x0000, 0x2001, 0x19a6, 0x2004, 0x9005, 0x1518, 0x080c, 0x2a48,
+	0x1148, 0x2001, 0x0001, 0x080c, 0x29ab, 0x2001, 0x0001, 0x080c,
+	0x298e, 0x00b8, 0x080c, 0x2a50, 0x1138, 0x9006, 0x080c, 0x29ab,
+	0x9006, 0x080c, 0x298e, 0x0068, 0x080c, 0x2a58, 0x1d50, 0x2001,
+	0x1997, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c, 0x27a5, 0x0804,
+	0x0cc1, 0x080c, 0x2ad7, 0x080c, 0x2b0a, 0x20a9, 0x003a, 0x1d04,
+	0x0c17, 0x080c, 0x87b4, 0x1f04, 0x0c17, 0x080c, 0x754e, 0x0148,
+	0x080c, 0x7560, 0x1118, 0x080c, 0x784f, 0x0050, 0x080c, 0x7545,
+	0x0dd0, 0x080c, 0x784a, 0x080c, 0x7840, 0x080c, 0x746e, 0x0020,
+	0x2009, 0x00f8, 0x080c, 0x600e, 0x7850, 0xc0e5, 0x7852, 0x080c,
+	0x753d, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, 0x2021, 0xe678,
+	0x2019, 0xea60, 0x0d0c, 0x87b4, 0x7820, 0xd09c, 0x15a0, 0x080c,
+	0x753d, 0x0904, 0x0ca3, 0x7824, 0xd0ac, 0x1904, 0x0cc6, 0x080c,
+	0x7560, 0x1548, 0x0046, 0x2021, 0x0320, 0x8421, 0x1df0, 0x004e,
+	0x2011, 0x1800, 0x080c, 0x2ab4, 0x080c, 0x2a60, 0x7824, 0x9084,
+	0x1800, 0x1168, 0x9484, 0x0fff, 0x1140, 0x2001, 0x1810, 0x2004,
+	0x9084, 0x9000, 0x0110, 0x080c, 0x0ce9, 0x8421, 0x1160, 0x1d04,
+	0x0c73, 0x080c, 0x87b4, 0x080c, 0x784a, 0x080c, 0x7840, 0x7003,
+	0x0001, 0x0804, 0x0cc6, 0x8319, 0x1928, 0x2001, 0x1810, 0x2004,
+	0x9084, 0x9000, 0x0110, 0x080c, 0x0ce9, 0x1d04, 0x0c89, 0x080c,
+	0x87b4, 0x2009, 0x199a, 0x2104, 0x9005, 0x0118, 0x8001, 0x200a,
+	0x1188, 0x200b, 0x000a, 0x2011, 0x0048, 0x080c, 0x2ab4, 0x20a9,
+	0x0002, 0x080c, 0x2a41, 0x7924, 0x080c, 0x2a60, 0xd19c, 0x0110,
+	0x080c, 0x297c, 0x00f0, 0x080c, 0x754e, 0x1140, 0x94a2, 0x03e8,
+	0x1128, 0x080c, 0x7511, 0x7003, 0x0001, 0x00c0, 0x2011, 0x1800,
+	0x080c, 0x2ab4, 0x080c, 0x2a60, 0x7824, 0x080c, 0x7557, 0x0110,
+	0xd0ac, 0x1160, 0x9084, 0x1800, 0x0904, 0x0c7b, 0x7003, 0x0001,
+	0x0028, 0x2001, 0x0001, 0x080c, 0x2606, 0x00a0, 0x7850, 0xc0e4,
+	0x7852, 0x2009, 0x180c, 0x210c, 0xd19c, 0x1120, 0x7904, 0x918d,
+	0x0002, 0x7906, 0x2011, 0x0048, 0x080c, 0x2ab4, 0x7828, 0x9085,
+	0x0028, 0x782a, 0x2001, 0x19a6, 0x2003, 0x0000, 0x9006, 0x78f2,
+	0x015e, 0x003e, 0x000e, 0x012e, 0x00fe, 0x004e, 0x002e, 0x001e,
+	0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x0046, 0x00b6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x0156, 0x0071, 0x0d0c, 0x87b4, 0x015e,
+	0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x004e, 0x003e, 0x002e,
+	0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0x189e, 0x7004, 0x9086,
+	0x0001, 0x1110, 0x080c, 0x34e0, 0x00ee, 0x0005, 0x0005, 0x2a70,
+	0x2061, 0x19aa, 0x2063, 0x0003, 0x6007, 0x0003, 0x600b, 0x0008,
+	0x600f, 0x0137, 0x2001, 0x197b, 0x900e, 0x2102, 0x7196, 0x2001,
+	0x0100, 0x2004, 0x9082, 0x0002, 0x0218, 0x705f, 0xffff, 0x0008,
+	0x715e, 0x7067, 0xffff, 0x717e, 0x7182, 0x080c, 0xcde8, 0x70ef,
+	0x00c0, 0x2061, 0x196b, 0x6003, 0x0909, 0x6106, 0x600b, 0x8800,
+	0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x001f, 0x611a, 0x601f,
+	0x07d0, 0x2061, 0x1973, 0x6003, 0x8000, 0x6106, 0x610a, 0x600f,
+	0x0200, 0x6013, 0x00ff, 0x6116, 0x601b, 0x0001, 0x611e, 0x2061,
+	0x1988, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b, 0x4943, 0x600f,
+	0x2020, 0x2001, 0x182c, 0x2102, 0x0005, 0x9016, 0x080c, 0x6693,
+	0x1178, 0xb804, 0x90c4, 0x00ff, 0x98c6, 0x0006, 0x0128, 0x90c4,
+	0xff00, 0x98c6, 0x0600, 0x1120, 0x9186, 0x0080, 0x0108, 0x8210,
+	0x8108, 0x9186, 0x0800, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000,
+	0x2079, 0x0000, 0x000e, 0x00f6, 0x0010, 0x2091, 0x8000, 0x0e04,
+	0x0d7f, 0x0006, 0x0016, 0x2001, 0x8002, 0x0006, 0x2079, 0x0000,
+	0x000e, 0x7882, 0x7836, 0x001e, 0x798e, 0x000e, 0x788a, 0x000e,
+	0x7886, 0x3900, 0x789a, 0x7833, 0x0012, 0x2091, 0x5000, 0x0156,
+	0x00d6, 0x0036, 0x0026, 0x2079, 0x0300, 0x2069, 0x1b26, 0x7a08,
+	0x226a, 0x2069, 0x1b27, 0x7a18, 0x226a, 0x8d68, 0x7a1c, 0x226a,
+	0x782c, 0x2019, 0x1b34, 0x201a, 0x2019, 0x1b37, 0x9016, 0x7808,
+	0xd09c, 0x0168, 0x7820, 0x201a, 0x8210, 0x8318, 0x9386, 0x1b50,
+	0x0108, 0x0ca8, 0x7808, 0xd09c, 0x0110, 0x2011, 0xdead, 0x2019,
+	0x1b35, 0x782c, 0x201a, 0x8318, 0x221a, 0x7803, 0x0000, 0x2069,
+	0x1a7c, 0x901e, 0x20a9, 0x0020, 0x7b26, 0x7a28, 0x226a, 0x8d68,
+	0x8318, 0x1f04, 0x0dcc, 0x2069, 0x1a9c, 0x2019, 0x0050, 0x20a9,
+	0x0020, 0x7b26, 0x7a28, 0x226a, 0x8d68, 0x8318, 0x1f04, 0x0dd9,
+	0x0491, 0x002e, 0x003e, 0x00de, 0x015e, 0x2079, 0x1800, 0x7803,
+	0x0005, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x0180,
+	0x2001, 0x1a21, 0x2004, 0x9005, 0x0128, 0x2001, 0x008b, 0x2004,
+	0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003, 0x0002, 0x2003, 0x1001,
+	0x080c, 0x574d, 0x1170, 0x080c, 0x0f20, 0x0110, 0x080c, 0x0e73,
+	0x080c, 0x574d, 0x1130, 0x2071, 0x1800, 0x2011, 0x8000, 0x080c,
+	0x0f34, 0x0c70, 0x0005, 0x2001, 0x0382, 0x2004, 0x9084, 0x0007,
+	0x9086, 0x0001, 0x1120, 0x2001, 0x0015, 0x080c, 0xa90f, 0x2079,
+	0x0380, 0x2069, 0x1b06, 0x7818, 0x6802, 0x781c, 0x6806, 0x7840,
+	0x680a, 0x7844, 0x680e, 0x782c, 0x6812, 0x2019, 0x1b11, 0x9016,
+	0x7808, 0xd09c, 0x0150, 0x7820, 0x201a, 0x8210, 0x8318, 0x8210,
+	0x9282, 0x0011, 0x0ea8, 0x2011, 0xdead, 0x6a2a, 0x7830, 0x681a,
+	0x7834, 0x681e, 0x7838, 0x6822, 0x783c, 0x6826, 0x7803, 0x0000,
+	0x2069, 0x1ac6, 0x901e, 0x20a9, 0x0020, 0x7b26, 0x7828, 0x206a,
+	0x8d68, 0x8318, 0x1f04, 0x0e4d, 0x2069, 0x1ae6, 0x2019, 0x00b0,
+	0x20a9, 0x0020, 0x7b26, 0x7828, 0x206a, 0x8d68, 0x8318, 0x1f04,
+	0x0e5a, 0x0005, 0x918c, 0x03ff, 0x2001, 0x0003, 0x2004, 0x9084,
+	0x0600, 0x1118, 0x918d, 0x6c00, 0x0010, 0x918d, 0x6400, 0x2001,
+	0x017f, 0x2102, 0x0005, 0x0026, 0x0126, 0x2011, 0x0080, 0x080c,
+	0x0f12, 0x20a9, 0x0900, 0x080c, 0x0f48, 0x2011, 0x0040, 0x080c,
+	0x0f12, 0x20a9, 0x0900, 0x080c, 0x0f48, 0x0c78, 0x0026, 0x080c,
+	0x0f20, 0x1188, 0x2011, 0x010e, 0x2214, 0x9294, 0x0007, 0x9296,
+	0x0007, 0x0118, 0x2011, 0x0947, 0x0010, 0x2011, 0x1b47, 0x080c,
+	0x0f34, 0x002e, 0x0005, 0x2011, 0x010e, 0x2214, 0x9294, 0x0007,
+	0x9296, 0x0007, 0x0118, 0x2011, 0xa880, 0x0010, 0x2011, 0x6840,
+	0xd0e4, 0x70f3, 0x0000, 0x1120, 0x70f3, 0x0fa0, 0x080c, 0x0f25,
+	0x002e, 0x0005, 0x0026, 0x080c, 0x0f20, 0x0148, 0xd0a4, 0x1138,
+	0x2011, 0xcdd5, 0x0010, 0x2011, 0x0080, 0x080c, 0x0f25, 0x002e,
+	0x0005, 0x0026, 0x70f3, 0x0000, 0x080c, 0x0f20, 0x1130, 0x2011,
+	0x8040, 0x080c, 0x0f34, 0x002e, 0x0005, 0x080c, 0x2a58, 0x1118,
+	0x2011, 0xcdc5, 0x0010, 0x2011, 0xcac2, 0x080c, 0x0f25, 0x002e,
+	0x0005, 0x00e6, 0x0016, 0x0006, 0x2071, 0x1800, 0xd0b4, 0x70ec,
+	0x71e8, 0x1118, 0xc0e4, 0xc1f4, 0x0050, 0x0006, 0x3b00, 0x9084,
+	0xff3e, 0x20d8, 0x000e, 0x70f3, 0x0000, 0xc0e5, 0xc1f5, 0x0099,
+	0x000e, 0x001e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800, 0xd0e4,
+	0x70ec, 0x1110, 0xc0dc, 0x0008, 0xc0dd, 0x0016, 0x71e8, 0x0019,
+	0x001e, 0x00ee, 0x0005, 0x70ee, 0x71ea, 0x7000, 0x9084, 0x0007,
+	0x000b, 0x0005, 0x0ed8, 0x0eb2, 0x0eb2, 0x0e86, 0x0ec1, 0x0eb2,
+	0x0eb2, 0x0ec1, 0xc284, 0x0016, 0x3b08, 0x3a00, 0x9104, 0x918d,
+	0x00c1, 0x21d8, 0x9084, 0xff3e, 0x9205, 0x20d0, 0x001e, 0x0005,
+	0x2001, 0x183b, 0x2004, 0xd0dc, 0x0005, 0x9e86, 0x1800, 0x190c,
+	0x0d7d, 0x70ec, 0xd0e4, 0x0108, 0xc2e5, 0x72ee, 0xd0e4, 0x1118,
+	0x9294, 0x00c1, 0x08f9, 0x0005, 0x9e86, 0x1800, 0x190c, 0x0d7d,
+	0x70e8, 0xd0f4, 0x0108, 0xc2f5, 0x72ea, 0xd0f4, 0x1140, 0x9284,
+	0x8000, 0x8005, 0xc284, 0x9215, 0x9294, 0x00c1, 0x0861, 0x0005,
+	0x1d04, 0x0f48, 0x2091, 0x6000, 0x1f04, 0x0f48, 0x0005, 0x890e,
+	0x810e, 0x810f, 0x9194, 0x003f, 0x918c, 0xffc0, 0x0005, 0x0006,
+	0x2200, 0x914d, 0x894f, 0x894d, 0x894d, 0x000e, 0x0005, 0x01d6,
+	0x0146, 0x0036, 0x0096, 0x2061, 0x188d, 0x600b, 0x0000, 0x600f,
+	0x0000, 0x6003, 0x0000, 0x6007, 0x0000, 0x2009, 0xffc0, 0x2105,
+	0x0006, 0x2001, 0xaaaa, 0x200f, 0x2019, 0x5555, 0x9016, 0x2049,
+	0x0bff, 0xab02, 0xa001, 0xa001, 0xa800, 0x9306, 0x1138, 0x2105,
+	0x9306, 0x0120, 0x8210, 0x99c8, 0x0400, 0x0c98, 0x000e, 0x200f,
+	0x2001, 0x189d, 0x928a, 0x000e, 0x1638, 0x928a, 0x0006, 0x2011,
+	0x0006, 0x1210, 0x2011, 0x0000, 0x2202, 0x9006, 0x2008, 0x82ff,
+	0x01b0, 0x8200, 0x600a, 0x600f, 0xffff, 0x6003, 0x0002, 0x6007,
+	0x0000, 0x0026, 0x2019, 0x0010, 0x9280, 0x0001, 0x20e8, 0x21a0,
+	0x21a8, 0x4104, 0x8319, 0x1de0, 0x8211, 0x1da0, 0x002e, 0x009e,
+	0x003e, 0x014e, 0x01de, 0x0005, 0x2011, 0x000e, 0x08e8, 0x0016,
+	0x0026, 0x0096, 0x3348, 0x080c, 0x0f4f, 0x2100, 0x9300, 0x2098,
+	0x22e0, 0x009e, 0x002e, 0x001e, 0x0036, 0x3518, 0x20a9, 0x0001,
+	0x4002, 0x8007, 0x4004, 0x8319, 0x1dd8, 0x003e, 0x0005, 0x20e9,
+	0x0001, 0x71b8, 0x81ff, 0x11c0, 0x9006, 0x2009, 0x0200, 0x20a9,
+	0x0002, 0x9298, 0x0018, 0x23a0, 0x4001, 0x2009, 0x0700, 0x20a9,
+	0x0002, 0x9298, 0x0008, 0x23a0, 0x4001, 0x707c, 0x8007, 0x7180,
+	0x810f, 0x20a9, 0x0002, 0x4001, 0x9298, 0x000c, 0x23a0, 0x900e,
+	0x080c, 0x0d5d, 0x2001, 0x0000, 0x810f, 0x20a9, 0x0002, 0x4001,
+	0x0005, 0x89ff, 0x0140, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c,
+	0x1079, 0x009e, 0x0cb0, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c,
+	0x10f2, 0x090c, 0x0d7d, 0x00ee, 0x0005, 0x0086, 0x00e6, 0x0006,
+	0x0026, 0x0036, 0x0126, 0x2091, 0x8000, 0x00c9, 0x2071, 0x1800,
+	0x73c0, 0x702c, 0x9016, 0x9045, 0x0158, 0x8210, 0x9906, 0x090c,
+	0x0d7d, 0x2300, 0x9202, 0x0120, 0x1a0c, 0x0d7d, 0xa000, 0x0c98,
+	0x012e, 0x003e, 0x002e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x0086,
+	0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x1910, 0x7010,
+	0x9005, 0x0140, 0x7018, 0x9045, 0x0128, 0x9906, 0x090c, 0x0d7d,
+	0xa000, 0x0cc8, 0x012e, 0x000e, 0x00ee, 0x008e, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0x0126, 0x2091, 0x8000, 0x70c0, 0x8001, 0x0270,
+	0x70c2, 0x702c, 0x2048, 0x9085, 0x0001, 0xa800, 0x702e, 0xa803,
+	0x0000, 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e, 0x0cd8,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x70c0, 0x90ca,
+	0x0020, 0x0268, 0x8001, 0x70c2, 0x702c, 0x2048, 0xa800, 0x702e,
+	0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005, 0x904e,
+	0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x0016, 0x890e, 0x810e,
+	0x810f, 0x9184, 0x003f, 0xa862, 0x9184, 0xffc0, 0xa85e, 0x001e,
+	0x0020, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x702c,
+	0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c, 0x85ce,
+	0x012e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9026, 0x2009, 0x0000,
+	0x2049, 0x0400, 0x2900, 0x702e, 0x8940, 0x2800, 0xa802, 0xa95e,
+	0xa863, 0x0001, 0x8420, 0x9886, 0x0440, 0x0120, 0x2848, 0x9188,
+	0x0040, 0x0c90, 0x2071, 0x188d, 0x7000, 0x9005, 0x11a0, 0x2001,
+	0x0558, 0xa802, 0x2048, 0x2009, 0x5600, 0x8940, 0x2800, 0xa802,
+	0xa95e, 0xa863, 0x0001, 0x8420, 0x9886, 0x0800, 0x0120, 0x2848,
+	0x9188, 0x0040, 0x0c90, 0x2071, 0x188d, 0x7104, 0x7200, 0x82ff,
+	0x01d0, 0x7308, 0x8318, 0x831f, 0x831b, 0x831b, 0x7312, 0x8319,
+	0x2001, 0x0800, 0xa802, 0x2048, 0x8900, 0xa802, 0x2040, 0xa95e,
+	0xaa62, 0x8420, 0x2300, 0x9906, 0x0130, 0x2848, 0x9188, 0x0040,
+	0x9291, 0x0000, 0x0c88, 0xa803, 0x0000, 0x2071, 0x1800, 0x74be,
+	0x74c2, 0x0005, 0x00e6, 0x0016, 0x9984, 0xfc00, 0x01e8, 0x908c,
+	0xf800, 0x1168, 0x9982, 0x0400, 0x02b8, 0x9982, 0x0440, 0x0278,
+	0x9982, 0x0558, 0x0288, 0x9982, 0x0800, 0x1270, 0x0040, 0x9982,
+	0x0800, 0x0250, 0x2071, 0x188d, 0x7010, 0x9902, 0x1228, 0x9085,
+	0x0001, 0x001e, 0x00ee, 0x0005, 0x9006, 0x0cd8, 0x00e6, 0x2071,
+	0x1a20, 0x7007, 0x0000, 0x9006, 0x701e, 0x7022, 0x7002, 0x2071,
+	0x0000, 0x7010, 0x9085, 0x8044, 0x7012, 0x2071, 0x0080, 0x9006,
+	0x702b, 0x0060, 0x20a9, 0x0040, 0x7022, 0x1f04, 0x112c, 0x702b,
+	0x0060, 0x702b, 0x0020, 0x20a9, 0x0040, 0x7022, 0x1f04, 0x1135,
+	0x702b, 0x0020, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x00e6,
+	0xa06f, 0x0000, 0x2071, 0x1a20, 0x701c, 0x9088, 0x1a2a, 0x280a,
+	0x8000, 0x9084, 0x003f, 0x701e, 0x7120, 0x9106, 0x090c, 0x0d7d,
+	0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080, 0x00a9, 0x00fe,
+	0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x00e6, 0x2071,
+	0x1a20, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080, 0x0021,
+	0x00fe, 0x00ee, 0x012e, 0x0005, 0x7004, 0x9086, 0x0000, 0x1110,
+	0x7007, 0x0006, 0x7000, 0x0002, 0x117e, 0x1301, 0x117c, 0x117c,
+	0x12f5, 0x12f5, 0x12f5, 0x12f5, 0x080c, 0x0d7d, 0x701c, 0x7120,
+	0x9106, 0x1148, 0x792c, 0x9184, 0x0001, 0x1120, 0xd1fc, 0x1110,
+	0x7007, 0x0000, 0x0005, 0x0096, 0x9180, 0x1a2a, 0x2004, 0x700a,
+	0x2048, 0x8108, 0x918c, 0x003f, 0x7122, 0x782b, 0x0026, 0xa88c,
+	0x7802, 0xa890, 0x7806, 0xa894, 0x780a, 0xa898, 0x780e, 0xa878,
+	0x700e, 0xa870, 0x7016, 0xa874, 0x701a, 0xa868, 0x009e, 0xd084,
+	0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007, 0x0002, 0x00b1,
+	0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040, 0x9182, 0x0040,
+	0x1210, 0x2110, 0x9006, 0x700e, 0x7212, 0x8203, 0x7812, 0x782b,
+	0x0020, 0x782b, 0x0041, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026,
+	0x0136, 0x0146, 0x0156, 0x7014, 0x20e0, 0x7018, 0x2098, 0x20e9,
+	0x0000, 0x20a1, 0x0088, 0x782b, 0x0026, 0x710c, 0x2011, 0x0040,
+	0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, 0x22a8, 0x4006,
+	0x8203, 0x7812, 0x782b, 0x0020, 0x3300, 0x701a, 0x782b, 0x0001,
+	0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005, 0x2009, 0x1a20,
+	0x2104, 0xc095, 0x200a, 0x080c, 0x115b, 0x0005, 0x0016, 0x00e6,
+	0x2071, 0x1a20, 0x00f6, 0x2079, 0x0080, 0x792c, 0xd1bc, 0x190c,
+	0x0d76, 0x782b, 0x0002, 0xd1fc, 0x0120, 0x918c, 0x0700, 0x7004,
+	0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x116c, 0x1214, 0x1248,
+	0x1320, 0x0d7d, 0x133b, 0x0d7d, 0x918c, 0x0700, 0x1550, 0x0136,
+	0x0146, 0x0156, 0x7014, 0x20e8, 0x7018, 0x20a0, 0x20e1, 0x0000,
+	0x2099, 0x0088, 0x782b, 0x0040, 0x7010, 0x20a8, 0x4005, 0x3400,
+	0x701a, 0x015e, 0x014e, 0x013e, 0x700c, 0x9005, 0x0578, 0x7800,
+	0x7802, 0x7804, 0x7806, 0x080c, 0x11b1, 0x0005, 0x7008, 0x0096,
+	0x2048, 0xa86f, 0x0100, 0x009e, 0x7007, 0x0000, 0x080c, 0x116c,
+	0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, 0x0200, 0x009e, 0x0ca0,
+	0x918c, 0x0700, 0x1150, 0x700c, 0x9005, 0x0180, 0x7800, 0x7802,
+	0x7804, 0x7806, 0x080c, 0x11c6, 0x0005, 0x7008, 0x0096, 0x2048,
+	0xa86f, 0x0200, 0x009e, 0x7007, 0x0000, 0x0080, 0x0096, 0x7008,
+	0x2048, 0x7800, 0xa88e, 0x7804, 0xa892, 0x7808, 0xa896, 0x780c,
+	0xa89a, 0xa86f, 0x0100, 0x009e, 0x7007, 0x0000, 0x0096, 0x00d6,
+	0x7008, 0x2048, 0x2001, 0x18b9, 0x2004, 0x9906, 0x1128, 0xa89c,
+	0x080f, 0x00de, 0x009e, 0x00a0, 0x00de, 0x009e, 0x0096, 0x00d6,
+	0x7008, 0x2048, 0x0081, 0x0150, 0xa89c, 0x0086, 0x2940, 0x080f,
+	0x008e, 0x00de, 0x009e, 0x080c, 0x115b, 0x0005, 0x00de, 0x009e,
+	0x080c, 0x115b, 0x0005, 0xa8a8, 0xd08c, 0x0005, 0x0096, 0xa0a0,
+	0x904d, 0x090c, 0x0d7d, 0xa06c, 0x908e, 0x0100, 0x0130, 0xa87b,
+	0x0030, 0xa883, 0x0000, 0xa897, 0x4002, 0x080c, 0x6de2, 0xa09f,
+	0x0000, 0xa0a3, 0x0000, 0x2848, 0x080c, 0x1079, 0x009e, 0x0005,
+	0x00a6, 0xa0a0, 0x904d, 0x090c, 0x0d7d, 0xa06c, 0x908e, 0x0100,
+	0x0128, 0xa87b, 0x0001, 0xa883, 0x0000, 0x00c0, 0xa80c, 0x2050,
+	0xb004, 0x9005, 0x0198, 0xa80e, 0x2050, 0x8006, 0x8006, 0x8007,
+	0x908c, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0xa076, 0xa172,
+	0xb000, 0xa07a, 0x2810, 0x080c, 0x113c, 0x00e8, 0xa97c, 0xa894,
+	0x0016, 0x0006, 0x080c, 0x6de2, 0x000e, 0x001e, 0xd1fc, 0x1138,
+	0xd1f4, 0x0128, 0x00c6, 0x2060, 0x080c, 0xacb0, 0x00ce, 0x7008,
+	0x2048, 0xa89f, 0x0000, 0xa8a3, 0x0000, 0x080c, 0x1079, 0x7007,
+	0x0000, 0x080c, 0x115b, 0x00ae, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x782b, 0x1001, 0x7007, 0x0005, 0x7000, 0xc094, 0x7002, 0x012e,
+	0x0005, 0x0096, 0x2001, 0x192e, 0x204c, 0xa87c, 0x7812, 0xa88c,
+	0x7802, 0xa890, 0x7806, 0xa894, 0x780a, 0xa898, 0x780e, 0x782b,
+	0x0020, 0x0126, 0x2091, 0x8000, 0x782b, 0x0041, 0x7007, 0x0003,
+	0x7000, 0xc084, 0x7002, 0x2900, 0x700a, 0x012e, 0x009e, 0x0005,
+	0x20e1, 0x0000, 0x2099, 0x0088, 0x782b, 0x0040, 0x0096, 0x2001,
+	0x192e, 0x204c, 0xaa7c, 0x009e, 0x080c, 0x8cb2, 0x2009, 0x188c,
+	0x2104, 0x9084, 0xfffc, 0x200a, 0x080c, 0x8b18, 0x7007, 0x0000,
+	0x080c, 0x116c, 0x0005, 0x7007, 0x0000, 0x080c, 0x116c, 0x0005,
+	0x0126, 0x2091, 0x2200, 0x2079, 0x0300, 0x2071, 0x1a6a, 0x7003,
+	0x0000, 0x78bf, 0x00f6, 0x0041, 0x7807, 0x0007, 0x7803, 0x0000,
+	0x7803, 0x0001, 0x012e, 0x0005, 0x00c6, 0x7803, 0x0000, 0x2001,
+	0x0165, 0x2003, 0x4198, 0x7808, 0xd09c, 0x0118, 0x7820, 0x04e9,
+	0x0cd0, 0x2001, 0x1a6b, 0x2003, 0x0000, 0x78ab, 0x0004, 0x78ac,
+	0xd0ac, 0x1de8, 0x78ab, 0x0002, 0x7807, 0x0007, 0x7827, 0x0030,
+	0x782b, 0x0400, 0x7827, 0x0031, 0x782b, 0x1a7c, 0x781f, 0xff00,
+	0x781b, 0xff00, 0x2001, 0x0200, 0x2004, 0xd0dc, 0x0110, 0x781f,
+	0x0303, 0x2061, 0x1a7c, 0x602f, 0x1ddc, 0x2001, 0x181a, 0x2004,
+	0x9082, 0x1ddc, 0x6032, 0x603b, 0x1eab, 0x602b, 0x1abc, 0x6007,
+	0x1a9c, 0x2061, 0x1a9c, 0x606f, 0x193c, 0x2001, 0x1927, 0x2004,
+	0x607a, 0x783f, 0x33b9, 0x00ce, 0x0005, 0x9086, 0x000d, 0x11d0,
+	0x7808, 0xd09c, 0x01b8, 0x7820, 0x0026, 0x2010, 0x080c, 0xc968,
+	0x0180, 0x2260, 0x6000, 0x9086, 0x0004, 0x1158, 0x0016, 0x6120,
+	0x9186, 0x0009, 0x0108, 0x0020, 0x2009, 0x004c, 0x080c, 0xad4d,
+	0x001e, 0x002e, 0x0005, 0x0126, 0x2091, 0x2200, 0x7908, 0x9184,
+	0x0070, 0x190c, 0x0d76, 0xd19c, 0x05a0, 0x7820, 0x908c, 0xf000,
+	0x0540, 0x2060, 0x6020, 0x9086, 0x0003, 0x1550, 0x6000, 0x9086,
+	0x0004, 0x1530, 0x6114, 0x2148, 0xa876, 0xa87a, 0xa867, 0x0103,
+	0x080c, 0x6c04, 0x00b6, 0x6010, 0x2058, 0xba3c, 0x8211, 0x0208,
+	0xba3e, 0xb8d0, 0x9005, 0x190c, 0x67be, 0x00be, 0x6044, 0xd0fc,
+	0x190c, 0xa947, 0x080c, 0xacd9, 0x7808, 0xd09c, 0x19b0, 0x012e,
+	0x0005, 0x908a, 0x0024, 0x1a0c, 0x0d7d, 0x002b, 0x012e, 0x0005,
+	0x04b0, 0x012e, 0x0005, 0x141f, 0x1445, 0x1475, 0x147a, 0x147e,
+	0x1483, 0x14ab, 0x14af, 0x14bd, 0x14c1, 0x141f, 0x158e, 0x1592,
+	0x1604, 0x160b, 0x141f, 0x160c, 0x160d, 0x1618, 0x161f, 0x141f,
+	0x141f, 0x141f, 0x141f, 0x141f, 0x141f, 0x141f, 0x1485, 0x141f,
+	0x144d, 0x1472, 0x1439, 0x141f, 0x1459, 0x1423, 0x1421, 0x080c,
+	0x0d7d, 0x080c, 0x0d76, 0x080c, 0x162a, 0x2009, 0x1a78, 0x2104,
+	0x8000, 0x200a, 0x080c, 0x7fed, 0x080c, 0x1b10, 0x0005, 0x6044,
+	0xd0fc, 0x190c, 0xa947, 0x2009, 0x0055, 0x080c, 0xad4d, 0x012e,
+	0x0005, 0x080c, 0x162a, 0x2060, 0x6044, 0xd0fc, 0x190c, 0xa947,
+	0x2009, 0x0055, 0x080c, 0xad4d, 0x0005, 0x2009, 0x0048, 0x080c,
+	0x162a, 0x2060, 0x080c, 0xad4d, 0x0005, 0x2009, 0x0054, 0x080c,
+	0x162a, 0x2060, 0x6044, 0xd0fc, 0x190c, 0xa947, 0x080c, 0xad4d,
+	0x0005, 0x080c, 0x162a, 0x2060, 0x0056, 0x0066, 0x080c, 0x162a,
+	0x2028, 0x080c, 0x162a, 0x2030, 0x0036, 0x0046, 0x2021, 0x0000,
+	0x2418, 0x2009, 0x0056, 0x080c, 0xad4d, 0x004e, 0x003e, 0x006e,
+	0x005e, 0x0005, 0x080c, 0x162a, 0x0005, 0x7004, 0xc085, 0xc0b5,
+	0x7006, 0x0005, 0x7004, 0xc085, 0x7006, 0x0005, 0x080c, 0x162a,
+	0x080c, 0x170b, 0x0005, 0x080c, 0x0d7d, 0x080c, 0x162a, 0x2060,
+	0x6014, 0x0096, 0x2048, 0xa83b, 0xffff, 0x009e, 0x2009, 0x0048,
+	0x080c, 0xad4d, 0x2001, 0x015d, 0x2003, 0x0000, 0x2009, 0x03e8,
+	0x8109, 0x0160, 0x2001, 0x0201, 0x2004, 0x9005, 0x0dc8, 0x2001,
+	0x0218, 0x2004, 0xd0ec, 0x1110, 0x080c, 0x162f, 0x2001, 0x0307,
+	0x2003, 0x8000, 0x0005, 0x7004, 0xc095, 0x7006, 0x0005, 0x080c,
+	0x162a, 0x2060, 0x6014, 0x0096, 0x2048, 0xa83b, 0xffff, 0x009e,
+	0x2009, 0x0048, 0x080c, 0xad4d, 0x0005, 0x080c, 0x162a, 0x080c,
+	0x0d7d, 0x080c, 0x162a, 0x080c, 0x1579, 0x7827, 0x0018, 0x79ac,
+	0xd1dc, 0x0904, 0x152a, 0x7827, 0x0015, 0x7828, 0x782b, 0x0000,
+	0x9065, 0x0140, 0x2001, 0x020d, 0x2003, 0x0050, 0x2003, 0x0020,
+	0x0804, 0x1530, 0x7004, 0x9005, 0x01c8, 0x1188, 0x78ab, 0x0004,
+	0x7827, 0x0018, 0x782b, 0x0000, 0xd1bc, 0x090c, 0x0d7d, 0x2001,
+	0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x0804, 0x155e, 0x78ab,
+	0x0004, 0x7803, 0x0001, 0x080c, 0x1592, 0x0005, 0x7827, 0x0018,
+	0xa001, 0x7828, 0x7827, 0x0011, 0xa001, 0x7928, 0x9106, 0x0110,
+	0x79ac, 0x08e0, 0x00e6, 0x2071, 0x0200, 0x702c, 0xd0c4, 0x0140,
+	0x00ee, 0x080c, 0x1b10, 0x080c, 0x1354, 0x7803, 0x0001, 0x0005,
+	0x7037, 0x0001, 0xa001, 0x7150, 0x00ee, 0x918c, 0xff00, 0x9186,
+	0x0500, 0x0110, 0x79ac, 0x0810, 0x7004, 0xc09d, 0x7006, 0x78ab,
+	0x0004, 0x7803, 0x0001, 0x080c, 0x1592, 0x2001, 0x020d, 0x2003,
+	0x0020, 0x0005, 0x7828, 0x782b, 0x0000, 0x9065, 0x090c, 0x0d7d,
+	0x6014, 0x2048, 0x78ab, 0x0004, 0x918c, 0x0700, 0x01a8, 0x080c,
+	0x7fed, 0x080c, 0x1b10, 0x080c, 0xc97a, 0x0158, 0xa9ac, 0xa936,
+	0xa9b0, 0xa93a, 0xa83f, 0xffff, 0xa843, 0xffff, 0xa880, 0xc0bd,
+	0xa882, 0x080c, 0xc566, 0x0005, 0x6020, 0x9086, 0x0009, 0x1128,
+	0x2009, 0x004c, 0x080c, 0xad4d, 0x0048, 0x6010, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0bc, 0x6024, 0x190c, 0xcd7d, 0x2029, 0x00c8,
+	0x8529, 0x0128, 0x2001, 0x0201, 0x2004, 0x9005, 0x0dc8, 0x7dbc,
+	0x080c, 0xe85a, 0xd5a4, 0x1118, 0x080c, 0x162f, 0x0005, 0x080c,
+	0x7fed, 0x080c, 0x1b10, 0x0005, 0x781f, 0x0300, 0x7803, 0x0001,
+	0x0005, 0x0016, 0x0066, 0x0076, 0x00f6, 0x2079, 0x0300, 0x7908,
+	0x918c, 0x0007, 0x9186, 0x0003, 0x0120, 0x2001, 0x0016, 0x080c,
+	0x16a0, 0x00fe, 0x007e, 0x006e, 0x001e, 0x0005, 0x7004, 0xc09d,
+	0x7006, 0x0005, 0x7104, 0x9184, 0x0004, 0x190c, 0x0d7d, 0xd184,
+	0x11b1, 0xd19c, 0x0180, 0xc19c, 0x7106, 0x0016, 0x080c, 0x16ee,
+	0x001e, 0x0148, 0x2001, 0x020d, 0x2003, 0x0050, 0x2003, 0x0020,
+	0x080c, 0x162f, 0x0005, 0x81ff, 0x190c, 0x0d7d, 0x0005, 0x2100,
+	0xc184, 0xc1b4, 0x7106, 0xd0b4, 0x0016, 0x00e6, 0x1904, 0x15f9,
+	0x2071, 0x0200, 0x080c, 0x16db, 0x05e0, 0x080c, 0x16ee, 0x05b0,
+	0x6014, 0x9005, 0x05b0, 0x0096, 0x2048, 0xa864, 0x009e, 0x9084,
+	0x00ff, 0x908e, 0x0029, 0x0160, 0x908e, 0x0048, 0x1550, 0x601c,
+	0xd084, 0x11e0, 0x00f6, 0x2c78, 0x080c, 0x1778, 0x00fe, 0x00b0,
+	0x00f6, 0x2c78, 0x080c, 0x1901, 0x00fe, 0x2009, 0x01f4, 0x8109,
+	0x0168, 0x2001, 0x0201, 0x2004, 0x9005, 0x0dc8, 0x2001, 0x0218,
+	0x2004, 0xd0ec, 0x1118, 0x080c, 0x162f, 0x0040, 0x2001, 0x020d,
+	0x2003, 0x0020, 0x080c, 0x1354, 0x7803, 0x0001, 0x00ee, 0x001e,
+	0x0005, 0x080c, 0x16ee, 0x0dd0, 0x2001, 0x020d, 0x2003, 0x0050,
+	0x2003, 0x0020, 0x0461, 0x0c90, 0x0429, 0x2060, 0x2009, 0x0053,
+	0x080c, 0xad4d, 0x0005, 0x0005, 0x0005, 0x00e1, 0x2008, 0x00d1,
+	0x0006, 0x7004, 0xc09d, 0x7006, 0x000e, 0x080c, 0x9003, 0x0005,
+	0x0089, 0x9005, 0x0118, 0x080c, 0x8c0a, 0x0cd0, 0x0005, 0x2001,
+	0x0036, 0x2009, 0x1820, 0x210c, 0x2011, 0x181f, 0x2214, 0x080c,
+	0x16a0, 0x0005, 0x7808, 0xd09c, 0x0de8, 0x7820, 0x0005, 0x080c,
+	0x1579, 0x00d6, 0x2069, 0x0200, 0x2009, 0x01f4, 0x8109, 0x0510,
+	0x6804, 0x9005, 0x0dd8, 0x2001, 0x015d, 0x2003, 0x0000, 0x79bc,
+	0xd1a4, 0x1528, 0x79b8, 0x918c, 0x0fff, 0x0180, 0x9182, 0x0841,
+	0x1268, 0x9188, 0x0007, 0x918c, 0x0ff8, 0x810c, 0x810c, 0x810c,
+	0x080c, 0x1692, 0x6827, 0x0001, 0x8109, 0x1dd0, 0x04d9, 0x6827,
+	0x0002, 0x04c1, 0x6804, 0x9005, 0x1130, 0x682c, 0xd0e4, 0x1500,
+	0x6804, 0x9005, 0x0de8, 0x79b8, 0xd1ec, 0x1130, 0x08c0, 0x080c,
+	0x7fed, 0x080c, 0x1b10, 0x0090, 0x7827, 0x0015, 0x782b, 0x0000,
+	0x7827, 0x0018, 0x782b, 0x0000, 0x2001, 0x020d, 0x2003, 0x0020,
+	0x2001, 0x0307, 0x2003, 0x0300, 0x7803, 0x0001, 0x00de, 0x0005,
+	0x682c, 0x9084, 0x5400, 0x9086, 0x5400, 0x0d30, 0x7827, 0x0015,
+	0x782b, 0x0000, 0x7803, 0x0001, 0x6800, 0x9085, 0x1800, 0x6802,
+	0x00de, 0x0005, 0x6824, 0x9084, 0x0003, 0x1de0, 0x0005, 0x2001,
+	0x0030, 0x2c08, 0x621c, 0x0021, 0x7830, 0x9086, 0x0041, 0x0005,
+	0x00f6, 0x2079, 0x0300, 0x0006, 0x7808, 0xd09c, 0x0140, 0x0016,
+	0x0026, 0x00c6, 0x080c, 0x13bb, 0x00ce, 0x002e, 0x001e, 0x000e,
+	0x0006, 0x7832, 0x7936, 0x7a3a, 0x781b, 0x8080, 0x0059, 0x1118,
+	0x000e, 0x00fe, 0x0005, 0x000e, 0x792c, 0x3900, 0x8000, 0x2004,
+	0x080c, 0x0d7d, 0x2009, 0xff00, 0x8109, 0x0120, 0x7818, 0xd0bc,
+	0x1dd8, 0x0005, 0x9085, 0x0001, 0x0005, 0x7832, 0x7936, 0x7a3a,
+	0x781b, 0x8080, 0x0c79, 0x1108, 0x0005, 0x792c, 0x3900, 0x8000,
+	0x2004, 0x080c, 0x0d7d, 0x7037, 0x0001, 0x7150, 0x7037, 0x0002,
+	0x7050, 0x2060, 0xd1bc, 0x1110, 0x7054, 0x2060, 0x918c, 0xff00,
+	0x9186, 0x0500, 0x0110, 0x9085, 0x0001, 0x0005, 0x0006, 0x0046,
+	0x00e6, 0x2071, 0x0200, 0x7037, 0x0002, 0x7058, 0x9084, 0xff00,
+	0x8007, 0x9086, 0x00bc, 0x1158, 0x2021, 0x1a79, 0x2404, 0x8000,
+	0x0208, 0x2022, 0x080c, 0x7fed, 0x080c, 0x1b10, 0x9006, 0x00ee,
+	0x004e, 0x000e, 0x0005, 0x0c11, 0x1108, 0x0005, 0x00e6, 0x0016,
+	0x2071, 0x0200, 0x0841, 0x6124, 0xd1dc, 0x01f8, 0x701c, 0xd08c,
+	0x0904, 0x176d, 0x7017, 0x0000, 0x2001, 0x0264, 0x2004, 0xd0bc,
+	0x0904, 0x176d, 0x2001, 0x0268, 0x00c6, 0x2064, 0x6104, 0x6038,
+	0x00ce, 0x918e, 0x0039, 0x1904, 0x176d, 0x9c06, 0x15f0, 0x0126,
+	0x2091, 0x2600, 0x080c, 0x7f45, 0x012e, 0x7358, 0x745c, 0x6014,
+	0x905d, 0x0598, 0x2b48, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be,
+	0xd0bc, 0x190c, 0xcd58, 0xab42, 0xac3e, 0x2001, 0x1869, 0x2004,
+	0xd0b4, 0x1170, 0x601c, 0xd0e4, 0x1158, 0x6010, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0bc, 0x1120, 0xa83b, 0x7fff, 0xa837, 0xffff,
+	0x080c, 0x1ecb, 0x1190, 0x080c, 0x195e, 0x2a00, 0xa816, 0x0130,
+	0x2800, 0xa80e, 0x2c05, 0xa80a, 0x2c00, 0xa812, 0x7037, 0x0020,
+	0x781f, 0x0300, 0x001e, 0x00ee, 0x0005, 0x7037, 0x0050, 0x7037,
+	0x0020, 0x001e, 0x00ee, 0x080c, 0x162f, 0x0005, 0x080c, 0x0d7d,
+	0x2cf0, 0x0126, 0x2091, 0x2200, 0x0016, 0x00c6, 0x3e60, 0x6014,
+	0x2048, 0x2940, 0x903e, 0x2730, 0xa864, 0x2068, 0xa81a, 0x9d84,
+	0x000f, 0x9088, 0x1eab, 0x2165, 0x0002, 0x17a4, 0x1812, 0x17a4,
+	0x17a4, 0x17a8, 0x17f3, 0x17a4, 0x17c8, 0x179d, 0x1809, 0x17a4,
+	0x17a4, 0x17ad, 0x18ff, 0x17dc, 0x17d2, 0xa964, 0x918c, 0x00ff,
+	0x918e, 0x0048, 0x0904, 0x1809, 0x9085, 0x0001, 0x0804, 0x18f5,
+	0xa87c, 0xd0ac, 0x0dc8, 0x0804, 0x1819, 0xa87c, 0xd0ac, 0x0da0,
+	0x0804, 0x1884, 0xa898, 0x901d, 0x1108, 0xab9c, 0x9016, 0xaab2,
+	0xaa3e, 0xaa42, 0x3e00, 0x9080, 0x0008, 0x2004, 0x9080, 0x91d3,
+	0x2005, 0x9005, 0x090c, 0x0d7d, 0x2004, 0xa8ae, 0x0804, 0x18dd,
+	0xa87c, 0xd0bc, 0x09c8, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa888,
+	0x0804, 0x1819, 0xa87c, 0xd0bc, 0x0978, 0xa890, 0xa842, 0xa88c,
+	0xa83e, 0xa888, 0x0804, 0x1884, 0xa87c, 0xd0bc, 0x0928, 0xa890,
+	0xa842, 0xa88c, 0xa83e, 0xa804, 0x9045, 0x090c, 0x0d7d, 0xa164,
+	0xa91a, 0x91ec, 0x000f, 0x9d80, 0x1eab, 0x2065, 0xa888, 0xd19c,
+	0x1904, 0x1884, 0x0430, 0xa87c, 0xd0ac, 0x0904, 0x17a4, 0xa804,
+	0x9045, 0x090c, 0x0d7d, 0xa164, 0xa91a, 0x91ec, 0x000f, 0x9d80,
+	0x1eab, 0x2065, 0x9006, 0xa842, 0xa83e, 0xd19c, 0x1904, 0x1884,
+	0x0080, 0xa87c, 0xd0ac, 0x0904, 0x17a4, 0x9006, 0xa842, 0xa83e,
+	0x0804, 0x1884, 0xa87c, 0xd0ac, 0x0904, 0x17a4, 0x9006, 0xa842,
+	0xa83e, 0x2c05, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x9082, 0x001b,
+	0x0002, 0x183c, 0x183c, 0x183e, 0x183c, 0x183c, 0x183c, 0x1848,
+	0x183c, 0x183c, 0x183c, 0x1852, 0x183c, 0x183c, 0x183c, 0x185c,
+	0x183c, 0x183c, 0x183c, 0x1866, 0x183c, 0x183c, 0x183c, 0x1870,
+	0x183c, 0x183c, 0x183c, 0x187a, 0x080c, 0x0d7d, 0xa574, 0xa478,
+	0x9d86, 0x0024, 0x0904, 0x17b2, 0xa37c, 0xa280, 0x0804, 0x18dd,
+	0xa584, 0xa488, 0x9d86, 0x0024, 0x0904, 0x17b2, 0xa38c, 0xa290,
+	0x0804, 0x18dd, 0xa594, 0xa498, 0x9d86, 0x0024, 0x0904, 0x17b2,
+	0xa39c, 0xa2a0, 0x0804, 0x18dd, 0xa5a4, 0xa4a8, 0x9d86, 0x0024,
+	0x0904, 0x17b2, 0xa3ac, 0xa2b0, 0x0804, 0x18dd, 0xa5b4, 0xa4b8,
+	0x9d86, 0x0024, 0x0904, 0x17b2, 0xa3bc, 0xa2c0, 0x0804, 0x18dd,
+	0xa5c4, 0xa4c8, 0x9d86, 0x0024, 0x0904, 0x17b2, 0xa3cc, 0xa2d0,
+	0x0804, 0x18dd, 0xa5d4, 0xa4d8, 0x9d86, 0x0024, 0x0904, 0x17b2,
+	0xa3dc, 0xa2e0, 0x0804, 0x18dd, 0x2c05, 0x908a, 0x0034, 0x1a0c,
+	0x0d7d, 0x9082, 0x001b, 0x0002, 0x18a7, 0x18a5, 0x18a5, 0x18a5,
+	0x18a5, 0x18a5, 0x18b2, 0x18a5, 0x18a5, 0x18a5, 0x18a5, 0x18a5,
+	0x18bd, 0x18a5, 0x18a5, 0x18a5, 0x18a5, 0x18a5, 0x18c8, 0x18a5,
+	0x18a5, 0x18a5, 0x18a5, 0x18a5, 0x18d3, 0x080c, 0x0d7d, 0xa56c,
+	0xa470, 0xa774, 0xa678, 0x9d86, 0x002c, 0x0904, 0x17b2, 0xa37c,
+	0xa280, 0x0458, 0xa584, 0xa488, 0xa78c, 0xa690, 0x9d86, 0x002c,
+	0x0904, 0x17b2, 0xa394, 0xa298, 0x0400, 0xa59c, 0xa4a0, 0xa7a4,
+	0xa6a8, 0x9d86, 0x002c, 0x0904, 0x17b2, 0xa3ac, 0xa2b0, 0x00a8,
+	0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0x9d86, 0x002c, 0x0904, 0x17b2,
+	0xa3c4, 0xa2c8, 0x0050, 0xa5cc, 0xa4d0, 0xa7d4, 0xa6d8, 0x9d86,
+	0x002c, 0x0904, 0x17b2, 0xa3dc, 0xa2e0, 0xab2e, 0xaa32, 0xad1e,
+	0xac22, 0xaf26, 0xae2a, 0xa988, 0x8c60, 0x2c1d, 0xa8ac, 0xaab0,
+	0xa836, 0xaa3a, 0x8109, 0xa916, 0x1160, 0x3e60, 0x601c, 0xc085,
+	0x601e, 0xa87c, 0xc0dd, 0xa87e, 0x9006, 0x00ce, 0x001e, 0x012e,
+	0x0005, 0x2800, 0xa80e, 0xab0a, 0x2c00, 0xa812, 0x0c70, 0x0804,
+	0x17a4, 0x2ff0, 0x0126, 0x2091, 0x2200, 0x0016, 0x00c6, 0x3e60,
+	0x6014, 0x2048, 0x2940, 0xa80e, 0x2061, 0x1ea6, 0xa813, 0x1ea6,
+	0x2c05, 0xa80a, 0xa964, 0xa91a, 0xa87c, 0xd0ac, 0x090c, 0x0d7d,
+	0x9006, 0xa842, 0xa83e, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0d7d,
+	0xadcc, 0xacd0, 0xafd4, 0xaed8, 0xabdc, 0xaae0, 0xab2e, 0xaa32,
+	0xad1e, 0xac22, 0xaf26, 0xae2a, 0xa8ac, 0xaab0, 0xa836, 0xaa3a,
+	0xa988, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0008, 0x1120, 0x8109,
+	0xa916, 0x0128, 0x0080, 0x918a, 0x0002, 0xa916, 0x1160, 0x3e60,
+	0x601c, 0xc085, 0x601e, 0xa87c, 0xc0dd, 0xa87e, 0x9006, 0x00ce,
+	0x001e, 0x012e, 0x0005, 0xa804, 0x9045, 0x090c, 0x0d7d, 0xa80e,
+	0xa064, 0xa81a, 0x9084, 0x000f, 0x9080, 0x1eab, 0x2015, 0x82ff,
+	0x090c, 0x0d7d, 0xaa12, 0x2205, 0xa80a, 0x0c08, 0x903e, 0x2730,
+	0xa880, 0xd0fc, 0x1190, 0x2d00, 0x0002, 0x1a88, 0x19b5, 0x19b5,
+	0x1a88, 0x19b5, 0x1a82, 0x1a88, 0x19b5, 0x1a25, 0x1a25, 0x1a25,
+	0x1a88, 0x1a25, 0x1a88, 0x1a7f, 0x1a25, 0xc0fc, 0xa882, 0xab2c,
+	0xaa30, 0xad1c, 0xac20, 0xdd9c, 0x0904, 0x1a8a, 0x2c05, 0x908a,
+	0x0034, 0x1a0c, 0x0d7d, 0x9082, 0x001b, 0x0002, 0x19a1, 0x199f,
+	0x199f, 0x199f, 0x199f, 0x199f, 0x19a5, 0x199f, 0x199f, 0x199f,
+	0x199f, 0x199f, 0x19a9, 0x199f, 0x199f, 0x199f, 0x199f, 0x199f,
+	0x19ad, 0x199f, 0x199f, 0x199f, 0x199f, 0x199f, 0x19b1, 0x080c,
+	0x0d7d, 0xa774, 0xa678, 0x0804, 0x1a8a, 0xa78c, 0xa690, 0x0804,
+	0x1a8a, 0xa7a4, 0xa6a8, 0x0804, 0x1a8a, 0xa7bc, 0xa6c0, 0x0804,
+	0x1a8a, 0xa7d4, 0xa6d8, 0x0804, 0x1a8a, 0xa898, 0x901d, 0x1108,
+	0xab9c, 0x9016, 0x2c05, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x9082,
+	0x001b, 0x0002, 0x19dd, 0x19dd, 0x19df, 0x19dd, 0x19dd, 0x19dd,
+	0x19e9, 0x19dd, 0x19dd, 0x19dd, 0x19f3, 0x19dd, 0x19dd, 0x19dd,
+	0x19fd, 0x19dd, 0x19dd, 0x19dd, 0x1a07, 0x19dd, 0x19dd, 0x19dd,
+	0x1a11, 0x19dd, 0x19dd, 0x19dd, 0x1a1b, 0x080c, 0x0d7d, 0xa574,
+	0xa478, 0x9d86, 0x0004, 0x0904, 0x1a8a, 0xa37c, 0xa280, 0x0804,
+	0x1a8a, 0xa584, 0xa488, 0x9d86, 0x0004, 0x0904, 0x1a8a, 0xa38c,
+	0xa290, 0x0804, 0x1a8a, 0xa594, 0xa498, 0x9d86, 0x0004, 0x0904,
+	0x1a8a, 0xa39c, 0xa2a0, 0x0804, 0x1a8a, 0xa5a4, 0xa4a8, 0x9d86,
+	0x0004, 0x0904, 0x1a8a, 0xa3ac, 0xa2b0, 0x0804, 0x1a8a, 0xa5b4,
+	0xa4b8, 0x9d86, 0x0004, 0x0904, 0x1a8a, 0xa3bc, 0xa2c0, 0x0804,
+	0x1a8a, 0xa5c4, 0xa4c8, 0x9d86, 0x0004, 0x0904, 0x1a8a, 0xa3cc,
+	0xa2d0, 0x0804, 0x1a8a, 0xa5d4, 0xa4d8, 0x9d86, 0x0004, 0x0904,
+	0x1a8a, 0xa3dc, 0xa2e0, 0x0804, 0x1a8a, 0xa898, 0x901d, 0x1108,
+	0xab9c, 0x9016, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0d7d, 0x9082,
+	0x001b, 0x0002, 0x1a4d, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a4b,
+	0x1a57, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a61, 0x1a4b,
+	0x1a4b, 0x1a4b, 0x1a4b, 0x1a4b, 0x1a6b, 0x1a4b, 0x1a4b, 0x1a4b,
+	0x1a4b, 0x1a4b, 0x1a75, 0x080c, 0x0d7d, 0xa56c, 0xa470, 0xa774,
+	0xa678, 0x9d86, 0x000c, 0x05b0, 0xa37c, 0xa280, 0x0498, 0xa584,
+	0xa488, 0xa78c, 0xa690, 0x9d86, 0x000c, 0x0560, 0xa394, 0xa298,
+	0x0448, 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, 0x9d86, 0x000c, 0x0510,
+	0xa3ac, 0xa2b0, 0x00f8, 0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0x9d86,
+	0x000c, 0x01c0, 0xa3c4, 0xa2c8, 0x00a8, 0xa5cc, 0xa4d0, 0xa7d4,
+	0xa6d8, 0x9d86, 0x000c, 0x0170, 0xa3dc, 0xa2e0, 0x0058, 0x9d86,
+	0x000e, 0x1130, 0x080c, 0x1e81, 0x1904, 0x195e, 0x900e, 0x0050,
+	0x080c, 0x0d7d, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a,
+	0x080c, 0x1e81, 0x0005, 0x6014, 0x2048, 0x6118, 0x810c, 0x810c,
+	0x810c, 0x81ff, 0x1118, 0xa887, 0x0001, 0x0008, 0xa986, 0x601b,
+	0x0002, 0xa874, 0x9084, 0x00ff, 0x9084, 0x0008, 0x0150, 0x00e9,
+	0x6000, 0x9086, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, 0xad4d,
+	0x0005, 0xa974, 0xd1dc, 0x1108, 0x0005, 0xa934, 0xa88c, 0x9106,
+	0x1158, 0xa938, 0xa890, 0x9106, 0x1138, 0x601c, 0xc084, 0x601e,
+	0x2009, 0x0048, 0x0804, 0xad4d, 0x0005, 0x0126, 0x00c6, 0x2091,
+	0x2200, 0x00ce, 0x7908, 0x918c, 0x0007, 0x9186, 0x0000, 0x05b0,
+	0x9186, 0x0003, 0x0598, 0x6020, 0x6023, 0x0000, 0x0006, 0x2031,
+	0x0008, 0x00c6, 0x781f, 0x0808, 0x7808, 0xd09c, 0x0120, 0x080c,
+	0x13bb, 0x8631, 0x1db8, 0x00ce, 0x781f, 0x0800, 0x2031, 0x0168,
+	0x00c6, 0x7808, 0xd09c, 0x190c, 0x13bb, 0x00ce, 0x2001, 0x0038,
+	0x080c, 0x1b98, 0x7930, 0x9186, 0x0040, 0x0160, 0x9186, 0x0042,
+	0x190c, 0x0d7d, 0x2001, 0x001e, 0x8001, 0x1df0, 0x8631, 0x1d40,
+	0x080c, 0x1ba7, 0x000e, 0x6022, 0x012e, 0x0005, 0x080c, 0x1b94,
+	0x7827, 0x0015, 0x7828, 0x9c06, 0x1db8, 0x782b, 0x0000, 0x0ca0,
+	0x00f6, 0x2079, 0x0300, 0x7803, 0x0000, 0x78ab, 0x0004, 0x00fe,
+	0x080c, 0x753d, 0x1188, 0x2001, 0x0138, 0x2003, 0x0000, 0x2001,
+	0x0160, 0x2003, 0x0000, 0x2011, 0x012c, 0xa001, 0xa001, 0x8211,
+	0x1de0, 0x0059, 0x0804, 0x75e2, 0x0479, 0x0039, 0x2001, 0x0160,
+	0x2502, 0x2001, 0x0138, 0x2202, 0x0005, 0x00e6, 0x2071, 0x0200,
+	0x080c, 0x2a6c, 0x2009, 0x003c, 0x080c, 0x220a, 0x2001, 0x015d,
+	0x2003, 0x0000, 0x7000, 0x9084, 0x003c, 0x1de0, 0x080c, 0x85ce,
+	0x70a0, 0x70a2, 0x7098, 0x709a, 0x709c, 0x709e, 0x2001, 0x020d,
+	0x2003, 0x0020, 0x00f6, 0x2079, 0x0300, 0x080c, 0x1354, 0x7803,
+	0x0001, 0x00fe, 0x00ee, 0x0005, 0x2001, 0x0138, 0x2014, 0x2003,
+	0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000, 0x080c, 0x753d,
+	0x1108, 0x0005, 0x2021, 0x0260, 0x2001, 0x0141, 0x201c, 0xd3dc,
+	0x1168, 0x2001, 0x0109, 0x201c, 0x939c, 0x0048, 0x1160, 0x2001,
+	0x0111, 0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x2001, 0x015d,
+	0x2003, 0x0000, 0x0005, 0x0046, 0x2021, 0x0019, 0x2003, 0x0048,
+	0xa001, 0xa001, 0x201c, 0x939c, 0x0048, 0x0120, 0x8421, 0x1db0,
+	0x004e, 0x0c60, 0x004e, 0x0c40, 0x601c, 0xc084, 0x601e, 0x0005,
+	0x2c08, 0x621c, 0x080c, 0x16a0, 0x7930, 0x0005, 0x2c08, 0x621c,
+	0x080c, 0x16cd, 0x7930, 0x0005, 0x8001, 0x1df0, 0x0005, 0x2031,
+	0x0064, 0x781c, 0x9084, 0x0007, 0x0170, 0x2001, 0x0038, 0x0c41,
+	0x9186, 0x0040, 0x0904, 0x1c05, 0x2001, 0x001e, 0x0c69, 0x8631,
+	0x1d80, 0x080c, 0x0d7d, 0x781f, 0x0202, 0x2001, 0x015d, 0x2003,
+	0x0000, 0x2001, 0x0dac, 0x0c01, 0x781c, 0xd084, 0x0110, 0x0861,
+	0x04e0, 0x2001, 0x0030, 0x0891, 0x9186, 0x0040, 0x0568, 0x781c,
+	0xd084, 0x1da8, 0x781f, 0x0101, 0x2001, 0x0014, 0x0869, 0x2001,
+	0x0037, 0x0821, 0x9186, 0x0040, 0x0140, 0x2001, 0x0030, 0x080c,
+	0x1b9e, 0x9186, 0x0040, 0x190c, 0x0d7d, 0x00d6, 0x2069, 0x0200,
+	0x692c, 0xd1f4, 0x1170, 0xd1c4, 0x0160, 0xd19c, 0x0130, 0x6800,
+	0x9085, 0x1800, 0x6802, 0x00de, 0x0080, 0x6908, 0x9184, 0x0007,
+	0x1db0, 0x00de, 0x781f, 0x0100, 0x791c, 0x9184, 0x0007, 0x090c,
+	0x0d7d, 0xa001, 0xa001, 0x781f, 0x0200, 0x0005, 0x0126, 0x2091,
+	0x2400, 0x2079, 0x0380, 0x2001, 0x19e6, 0x2070, 0x012e, 0x0005,
+	0x2cf0, 0x0126, 0x2091, 0x2400, 0x3e60, 0x6014, 0x2048, 0xa964,
+	0xa91a, 0x918c, 0x00ff, 0x9184, 0x000f, 0x0002, 0x1c3a, 0x1c3a,
+	0x1c3a, 0x1c3c, 0x1c3a, 0x1c3a, 0x1c3a, 0x1c3a, 0x1c2e, 0x1c44,
+	0x1c3a, 0x1c40, 0x1c3a, 0x1c3a, 0x1c3a, 0x1c3a, 0x9086, 0x0008,
+	0x1148, 0xa87c, 0xd0b4, 0x0904, 0x1db4, 0x2011, 0x1ea6, 0x2205,
+	0xab88, 0x00a8, 0x080c, 0x0d7d, 0x9186, 0x0013, 0x0128, 0x0cd0,
+	0x9186, 0x001b, 0x0108, 0x0cb0, 0xa87c, 0xd0b4, 0x0904, 0x1db4,
+	0x9184, 0x000f, 0x9080, 0x1eab, 0x2015, 0x2205, 0xab88, 0x2908,
+	0xa80a, 0xa90e, 0xaa12, 0xab16, 0x9006, 0xa842, 0xa83e, 0x012e,
+	0x0005, 0x2cf0, 0x0126, 0x2091, 0x2400, 0x3e60, 0x6014, 0x2048,
+	0xa88c, 0xa990, 0xaaac, 0xabb0, 0xaa36, 0xab3a, 0xa83e, 0xa942,
+	0xa846, 0xa94a, 0xa964, 0x918c, 0x00ff, 0x9186, 0x001e, 0x0198,
+	0x2940, 0xa064, 0xa81a, 0x90ec, 0x000f, 0x9d80, 0x1eab, 0x2065,
+	0x2c05, 0x2808, 0x2c10, 0xab88, 0xa80a, 0xa90e, 0xaa12, 0xab16,
+	0x012e, 0x3e60, 0x0005, 0xa804, 0x2040, 0x0c58, 0x2cf0, 0x0126,
+	0x2091, 0x2400, 0x3e60, 0x6014, 0x2048, 0xa97c, 0x2950, 0xd1dc,
+	0x1904, 0x1d7e, 0xc1dd, 0xa97e, 0x9006, 0xa842, 0xa83e, 0xa988,
+	0x8109, 0xa916, 0xa964, 0xa91a, 0x9184, 0x000f, 0x9088, 0x1eab,
+	0x2145, 0x0002, 0x1cb2, 0x1cc0, 0x1cb2, 0x1cb2, 0x1cb2, 0x1cb4,
+	0x1cb2, 0x1cb2, 0x1d15, 0x1d15, 0x1cb2, 0x1cb2, 0x1cb2, 0x1d13,
+	0x1cb2, 0x1cb2, 0x080c, 0x0d7d, 0xa804, 0x2050, 0xb164, 0xa91a,
+	0x9184, 0x000f, 0x9080, 0x1eab, 0x2045, 0xd19c, 0x1904, 0x1d15,
+	0x9036, 0x2638, 0x2805, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x9082,
+	0x001b, 0x0002, 0x1ce5, 0x1ce5, 0x1ce7, 0x1ce5, 0x1ce5, 0x1ce5,
+	0x1ced, 0x1ce5, 0x1ce5, 0x1ce5, 0x1cf3, 0x1ce5, 0x1ce5, 0x1ce5,
+	0x1cf9, 0x1ce5, 0x1ce5, 0x1ce5, 0x1cff, 0x1ce5, 0x1ce5, 0x1ce5,
+	0x1d05, 0x1ce5, 0x1ce5, 0x1ce5, 0x1d0b, 0x080c, 0x0d7d, 0xb574,
+	0xb478, 0xb37c, 0xb280, 0x0804, 0x1d5a, 0xb584, 0xb488, 0xb38c,
+	0xb290, 0x0804, 0x1d5a, 0xb594, 0xb498, 0xb39c, 0xb2a0, 0x0804,
+	0x1d5a, 0xb5a4, 0xb4a8, 0xb3ac, 0xb2b0, 0x0804, 0x1d5a, 0xb5b4,
+	0xb4b8, 0xb3bc, 0xb2c0, 0x0804, 0x1d5a, 0xb5c4, 0xb4c8, 0xb3cc,
+	0xb2d0, 0x0804, 0x1d5a, 0xb5d4, 0xb4d8, 0xb3dc, 0xb2e0, 0x0804,
+	0x1d5a, 0x0804, 0x1d5a, 0x080c, 0x0d7d, 0x2805, 0x908a, 0x0034,
+	0x1a0c, 0x0d7d, 0x9082, 0x001b, 0x0002, 0x1d38, 0x1d36, 0x1d36,
+	0x1d36, 0x1d36, 0x1d36, 0x1d3f, 0x1d36, 0x1d36, 0x1d36, 0x1d36,
+	0x1d36, 0x1d46, 0x1d36, 0x1d36, 0x1d36, 0x1d36, 0x1d36, 0x1d4d,
+	0x1d36, 0x1d36, 0x1d36, 0x1d36, 0x1d36, 0x1d54, 0x080c, 0x0d7d,
+	0xb56c, 0xb470, 0xb774, 0xb678, 0xb37c, 0xb280, 0x00d8, 0xb584,
+	0xb488, 0xb78c, 0xb690, 0xb394, 0xb298, 0x00a0, 0xb59c, 0xb4a0,
+	0xb7a4, 0xb6a8, 0xb3ac, 0xb2b0, 0x0068, 0xb5b4, 0xb4b8, 0xb7bc,
+	0xb6c0, 0xb3c4, 0xb2c8, 0x0030, 0xb5cc, 0xb4d0, 0xb7d4, 0xb6d8,
+	0xb3dc, 0xb2e0, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a,
+	0xa988, 0x8109, 0xa916, 0x1118, 0x9006, 0x012e, 0x0005, 0x8840,
+	0x2805, 0x9005, 0x1168, 0xb004, 0x9005, 0x090c, 0x0d7d, 0x2050,
+	0xb164, 0xa91a, 0x9184, 0x000f, 0x9080, 0x1eab, 0x2045, 0x2805,
+	0x2810, 0x2a08, 0xa80a, 0xa90e, 0xaa12, 0x0c30, 0x3e60, 0x6344,
+	0xd3fc, 0x190c, 0x0d7d, 0xa93c, 0xaa40, 0xa844, 0x9106, 0x1118,
+	0xa848, 0x9206, 0x0508, 0x2958, 0xab48, 0xac44, 0x2940, 0x080c,
+	0x1ecb, 0x1998, 0x2850, 0x2c40, 0xab14, 0xa880, 0xd0fc, 0x1140,
+	0xa810, 0x2005, 0xa80a, 0x2a00, 0xa80e, 0x2009, 0x8015, 0x0070,
+	0x00c6, 0x3e60, 0x6044, 0xc0a4, 0x9085, 0x8005, 0x6046, 0x00ce,
+	0x8319, 0xab16, 0x1904, 0x1d67, 0x2009, 0x8005, 0x3e60, 0x6044,
+	0x9105, 0x6046, 0x0804, 0x1d64, 0x080c, 0x0d7d, 0x00f6, 0x00e6,
+	0x0096, 0x00c6, 0x0026, 0x704c, 0x9c06, 0x190c, 0x0d7d, 0x2079,
+	0x0090, 0x2001, 0x0105, 0x2003, 0x0010, 0x782b, 0x0004, 0x7057,
+	0x0000, 0x6014, 0x2048, 0x080c, 0xc97a, 0x0118, 0xa880, 0xc0bd,
+	0xa882, 0x6020, 0x9086, 0x0006, 0x1170, 0x2061, 0x0100, 0x62c8,
+	0x2001, 0x00fa, 0x8001, 0x1df0, 0x60c8, 0x9206, 0x1dc0, 0x60c4,
+	0xa89a, 0x60c8, 0xa896, 0x704c, 0x2060, 0x00c6, 0x080c, 0xc566,
+	0x080c, 0xa91e, 0x00ce, 0x704c, 0x9c06, 0x1150, 0x2009, 0x0040,
+	0x080c, 0x220a, 0x080c, 0xa3c3, 0x2011, 0x0000, 0x080c, 0xa24d,
+	0x002e, 0x00ce, 0x009e, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x2079,
+	0x0090, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100, 0x7a14,
+	0x9284, 0x1984, 0x9085, 0x0012, 0x7816, 0x2019, 0x1000, 0x8319,
+	0x090c, 0x0d7d, 0x7820, 0xd0bc, 0x1dd0, 0x79c8, 0x000e, 0x9102,
+	0x001e, 0x0006, 0x0016, 0x79c4, 0x000e, 0x9103, 0x78c6, 0x000e,
+	0x78ca, 0x9284, 0x1984, 0x9085, 0x0012, 0x7816, 0x2079, 0x0090,
+	0x782b, 0x0008, 0x7057, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x00e6,
+	0x2071, 0x19e6, 0x7054, 0x9086, 0x0000, 0x0904, 0x1e7c, 0x2079,
+	0x0090, 0x2009, 0x0207, 0x210c, 0xd194, 0x01b8, 0x2009, 0x020c,
+	0x210c, 0x9184, 0x0003, 0x0188, 0x080c, 0xe8a3, 0x2001, 0x0133,
+	0x2004, 0x9005, 0x090c, 0x0d7d, 0x0016, 0x2009, 0x0040, 0x080c,
+	0x220a, 0x001e, 0x2001, 0x020c, 0x2102, 0x2009, 0x0206, 0x2104,
+	0x2009, 0x0203, 0x210c, 0x9106, 0x1120, 0x2009, 0x0040, 0x080c,
+	0x220a, 0x782c, 0xd0fc, 0x09a8, 0x080c, 0xa93a, 0x782c, 0xd0fc,
+	0x1de8, 0x080c, 0xa91e, 0x7054, 0x9086, 0x0000, 0x1950, 0x782b,
+	0x0004, 0x782c, 0xd0ac, 0x1de8, 0x2009, 0x0040, 0x080c, 0x220a,
+	0x782b, 0x0002, 0x7057, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x080c,
+	0x0d7d, 0x8c60, 0x2c05, 0x9005, 0x0110, 0x8a51, 0x0005, 0xa004,
+	0x9005, 0x0168, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080,
+	0x1eab, 0x2065, 0x8cff, 0x090c, 0x0d7d, 0x8a51, 0x0005, 0x2050,
+	0x0005, 0x0000, 0x001d, 0x0021, 0x0025, 0x0029, 0x002d, 0x0031,
+	0x0035, 0x0000, 0x001b, 0x0021, 0x0027, 0x002d, 0x0033, 0x0000,
+	0x0000, 0x0023, 0x0000, 0x0000, 0x1e9e, 0x1e9a, 0x1e9e, 0x1e9e,
+	0x1ea8, 0x0000, 0x1e9e, 0x1ea5, 0x1ea5, 0x1ea2, 0x1ea5, 0x1ea5,
+	0x0000, 0x1ea8, 0x1ea5, 0x0000, 0x1ea0, 0x1ea0, 0x0000, 0x1ea0,
+	0x1ea8, 0x0000, 0x1ea0, 0x1ea6, 0x1ea6, 0x1ea6, 0x0000, 0x1ea6,
+	0x0000, 0x1ea8, 0x1ea6, 0x00c6, 0x00d6, 0x0086, 0xab42, 0xac3e,
+	0xa888, 0x9055, 0x0904, 0x20aa, 0x2940, 0xa064, 0x90ec, 0x000f,
+	0x9084, 0x00ff, 0x9086, 0x0008, 0x1118, 0x2061, 0x1ea6, 0x00d0,
+	0x9de0, 0x1eab, 0x9d86, 0x0007, 0x0130, 0x9d86, 0x000e, 0x0118,
+	0x9d86, 0x000f, 0x1120, 0xa08c, 0x9422, 0xa090, 0x931b, 0x2c05,
+	0x9065, 0x1140, 0x0310, 0x0804, 0x20aa, 0xa004, 0x9045, 0x0904,
+	0x20aa, 0x08d8, 0x2c05, 0x9005, 0x0904, 0x1f92, 0xdd9c, 0x1904,
+	0x1f4e, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x9082, 0x001b, 0x0002,
+	0x1f23, 0x1f23, 0x1f25, 0x1f23, 0x1f23, 0x1f23, 0x1f2b, 0x1f23,
+	0x1f23, 0x1f23, 0x1f31, 0x1f23, 0x1f23, 0x1f23, 0x1f37, 0x1f23,
+	0x1f23, 0x1f23, 0x1f3d, 0x1f23, 0x1f23, 0x1f23, 0x1f43, 0x1f23,
+	0x1f23, 0x1f23, 0x1f49, 0x080c, 0x0d7d, 0xa07c, 0x9422, 0xa080,
+	0x931b, 0x0804, 0x1f88, 0xa08c, 0x9422, 0xa090, 0x931b, 0x0804,
+	0x1f88, 0xa09c, 0x9422, 0xa0a0, 0x931b, 0x0804, 0x1f88, 0xa0ac,
+	0x9422, 0xa0b0, 0x931b, 0x0804, 0x1f88, 0xa0bc, 0x9422, 0xa0c0,
+	0x931b, 0x0804, 0x1f88, 0xa0cc, 0x9422, 0xa0d0, 0x931b, 0x0804,
+	0x1f88, 0xa0dc, 0x9422, 0xa0e0, 0x931b, 0x04d0, 0x908a, 0x0034,
+	0x1a0c, 0x0d7d, 0x9082, 0x001b, 0x0002, 0x1f70, 0x1f6e, 0x1f6e,
+	0x1f6e, 0x1f6e, 0x1f6e, 0x1f75, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f6e,
+	0x1f6e, 0x1f7a, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f7f,
+	0x1f6e, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f6e, 0x1f84, 0x080c, 0x0d7d,
+	0xa07c, 0x9422, 0xa080, 0x931b, 0x0098, 0xa094, 0x9422, 0xa098,
+	0x931b, 0x0070, 0xa0ac, 0x9422, 0xa0b0, 0x931b, 0x0048, 0xa0c4,
+	0x9422, 0xa0c8, 0x931b, 0x0020, 0xa0dc, 0x9422, 0xa0e0, 0x931b,
+	0x0630, 0x2300, 0x9405, 0x0160, 0x8a51, 0x0904, 0x20aa, 0x8c60,
+	0x0804, 0x1efa, 0xa004, 0x9045, 0x0904, 0x20aa, 0x0804, 0x1ed5,
+	0x8a51, 0x0904, 0x20aa, 0x8c60, 0x2c05, 0x9005, 0x1158, 0xa004,
+	0x9045, 0x0904, 0x20aa, 0xa064, 0x90ec, 0x000f, 0x9de0, 0x1eab,
+	0x2c05, 0x2060, 0xa880, 0xc0fc, 0xa882, 0x0804, 0x209f, 0x2c05,
+	0x8422, 0x8420, 0x831a, 0x9399, 0x0000, 0xac2e, 0xab32, 0xdd9c,
+	0x1904, 0x203c, 0x9082, 0x001b, 0x0002, 0x1fd8, 0x1fd8, 0x1fda,
+	0x1fd8, 0x1fd8, 0x1fd8, 0x1fe8, 0x1fd8, 0x1fd8, 0x1fd8, 0x1ff6,
+	0x1fd8, 0x1fd8, 0x1fd8, 0x2004, 0x1fd8, 0x1fd8, 0x1fd8, 0x2012,
+	0x1fd8, 0x1fd8, 0x1fd8, 0x2020, 0x1fd8, 0x1fd8, 0x1fd8, 0x202e,
+	0x080c, 0x0d7d, 0xa17c, 0x2400, 0x9122, 0xa180, 0x2300, 0x911b,
+	0x0a0c, 0x0d7d, 0xa074, 0x9420, 0xa078, 0x9319, 0x0804, 0x209a,
+	0xa18c, 0x2400, 0x9122, 0xa190, 0x2300, 0x911b, 0x0a0c, 0x0d7d,
+	0xa084, 0x9420, 0xa088, 0x9319, 0x0804, 0x209a, 0xa19c, 0x2400,
+	0x9122, 0xa1a0, 0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa094, 0x9420,
+	0xa098, 0x9319, 0x0804, 0x209a, 0xa1ac, 0x2400, 0x9122, 0xa1b0,
+	0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa0a4, 0x9420, 0xa0a8, 0x9319,
+	0x0804, 0x209a, 0xa1bc, 0x2400, 0x9122, 0xa1c0, 0x2300, 0x911b,
+	0x0a0c, 0x0d7d, 0xa0b4, 0x9420, 0xa0b8, 0x9319, 0x0804, 0x209a,
+	0xa1cc, 0x2400, 0x9122, 0xa1d0, 0x2300, 0x911b, 0x0a0c, 0x0d7d,
+	0xa0c4, 0x9420, 0xa0c8, 0x9319, 0x0804, 0x209a, 0xa1dc, 0x2400,
+	0x9122, 0xa1e0, 0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa0d4, 0x9420,
+	0xa0d8, 0x9319, 0x0804, 0x209a, 0x9082, 0x001b, 0x0002, 0x205a,
+	0x2058, 0x2058, 0x2058, 0x2058, 0x2058, 0x2067, 0x2058, 0x2058,
+	0x2058, 0x2058, 0x2058, 0x2074, 0x2058, 0x2058, 0x2058, 0x2058,
+	0x2058, 0x2081, 0x2058, 0x2058, 0x2058, 0x2058, 0x2058, 0x208e,
+	0x080c, 0x0d7d, 0xa17c, 0x2400, 0x9122, 0xa180, 0x2300, 0x911b,
+	0x0a0c, 0x0d7d, 0xa06c, 0x9420, 0xa070, 0x9319, 0x0498, 0xa194,
+	0x2400, 0x9122, 0xa198, 0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa084,
+	0x9420, 0xa088, 0x9319, 0x0430, 0xa1ac, 0x2400, 0x9122, 0xa1b0,
+	0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa09c, 0x9420, 0xa0a0, 0x9319,
+	0x00c8, 0xa1c4, 0x2400, 0x9122, 0xa1c8, 0x2300, 0x911b, 0x0a0c,
+	0x0d7d, 0xa0b4, 0x9420, 0xa0b8, 0x9319, 0x0060, 0xa1dc, 0x2400,
+	0x9122, 0xa1e0, 0x2300, 0x911b, 0x0a0c, 0x0d7d, 0xa0cc, 0x9420,
+	0xa0d0, 0x9319, 0xac1e, 0xab22, 0xa880, 0xc0fd, 0xa882, 0x2800,
+	0xa85a, 0x2c00, 0xa812, 0x2a00, 0xa816, 0x000e, 0x000e, 0x000e,
+	0x9006, 0x0028, 0x008e, 0x00de, 0x00ce, 0x9085, 0x0001, 0x0005,
+	0x00c6, 0x610c, 0x0016, 0x9026, 0x2410, 0x6004, 0x9420, 0x9291,
+	0x0000, 0x2c04, 0x9210, 0x9ce0, 0x0002, 0x918a, 0x0002, 0x1da8,
+	0x9284, 0x000f, 0x9405, 0x001e, 0x00ce, 0x0005, 0x7803, 0x0003,
+	0x780f, 0x0000, 0x6004, 0x7812, 0x2c04, 0x7816, 0x9ce0, 0x0002,
+	0x918a, 0x0002, 0x1db8, 0x0005, 0x2001, 0x0005, 0x2004, 0xd0bc,
+	0x190c, 0x0d76, 0xd094, 0x0110, 0x080c, 0x11f6, 0x0005, 0x0126,
+	0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x0260, 0x2069, 0x1800,
+	0x7817, 0x0000, 0x789b, 0x0814, 0x78a3, 0x0406, 0x789f, 0x0410,
+	0x2009, 0x013b, 0x200b, 0x0400, 0x781b, 0x0002, 0x783b, 0x001f,
+	0x7837, 0x0020, 0x7803, 0x1600, 0x012e, 0x0005, 0x2091, 0x2600,
+	0x781c, 0xd0a4, 0x190c, 0x2207, 0x7900, 0xd1dc, 0x1118, 0x9084,
+	0x0006, 0x001a, 0x9084, 0x000e, 0x0002, 0x2125, 0x211d, 0x7f45,
+	0x211d, 0x211f, 0x211f, 0x211f, 0x211f, 0x7f2b, 0x211d, 0x2121,
+	0x211d, 0x211f, 0x211d, 0x211f, 0x211d, 0x080c, 0x0d7d, 0x0031,
+	0x0020, 0x080c, 0x7f2b, 0x080c, 0x7f45, 0x0005, 0x0006, 0x0016,
+	0x0026, 0x080c, 0xe8a3, 0x7930, 0x9184, 0x0003, 0x0510, 0x080c,
+	0xa91e, 0x2001, 0x19f9, 0x2004, 0x9005, 0x01a0, 0x2001, 0x0133,
+	0x2004, 0x9005, 0x090c, 0x0d7d, 0x00c6, 0x2001, 0x19f9, 0x2064,
+	0x080c, 0xa93a, 0x080c, 0xc566, 0x2009, 0x0040, 0x080c, 0x220a,
+	0x00ce, 0x0408, 0x2009, 0x0040, 0x080c, 0x220a, 0x080c, 0xa93a,
+	0x00d0, 0x9184, 0x0014, 0x01a0, 0x6a00, 0x9286, 0x0003, 0x0160,
+	0x080c, 0x753d, 0x1138, 0x080c, 0x7840, 0x080c, 0x6092, 0x080c,
+	0x746e, 0x0010, 0x080c, 0x5f4d, 0x080c, 0x7fe3, 0x0041, 0x0018,
+	0x9184, 0x9540, 0x1dc8, 0x002e, 0x001e, 0x000e, 0x0005, 0x00e6,
+	0x0036, 0x0046, 0x0056, 0x2071, 0x1a6a, 0x080c, 0x1b10, 0x005e,
+	0x004e, 0x003e, 0x00ee, 0x0005, 0x0126, 0x2091, 0x2e00, 0x2071,
+	0x1800, 0x7128, 0x2001, 0x196e, 0x2102, 0x2001, 0x1976, 0x2102,
+	0x2001, 0x013b, 0x2102, 0x2079, 0x0200, 0x2001, 0x0201, 0x789e,
+	0x78a3, 0x0200, 0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398,
+	0x0005, 0x2320, 0x9182, 0x0204, 0x1230, 0x2011, 0x0008, 0x8423,
+	0x8423, 0x8423, 0x0488, 0x9182, 0x024c, 0x1240, 0x2011, 0x0007,
+	0x8403, 0x8003, 0x9400, 0x9400, 0x9420, 0x0430, 0x9182, 0x02bc,
+	0x1238, 0x2011, 0x0006, 0x8403, 0x8003, 0x9400, 0x9420, 0x00e0,
+	0x9182, 0x034c, 0x1230, 0x2011, 0x0005, 0x8403, 0x8003, 0x9420,
+	0x0098, 0x9182, 0x042c, 0x1228, 0x2011, 0x0004, 0x8423, 0x8423,
+	0x0058, 0x9182, 0x059c, 0x1228, 0x2011, 0x0003, 0x8403, 0x9420,
+	0x0018, 0x2011, 0x0002, 0x8423, 0x9482, 0x0228, 0x8002, 0x8020,
+	0x8301, 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405,
+	0x789a, 0x012e, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6814,
+	0x9084, 0xffc0, 0x910d, 0x6916, 0x00de, 0x000e, 0x0005, 0x00d6,
+	0x2069, 0x0200, 0x9005, 0x6810, 0x0110, 0xc0a5, 0x0008, 0xc0a4,
+	0x6812, 0x00de, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6810,
+	0x9084, 0xfff8, 0x910d, 0x6912, 0x00de, 0x000e, 0x0005, 0x7938,
+	0x080c, 0x0d76, 0x00f6, 0x2079, 0x0200, 0x7902, 0xa001, 0xa001,
+	0xa001, 0xa001, 0xa001, 0xa001, 0x7902, 0xa001, 0xa001, 0xa001,
+	0xa001, 0xa001, 0xa001, 0x00fe, 0x0005, 0x0126, 0x2091, 0x2800,
+	0x2061, 0x0100, 0x2071, 0x1800, 0x2009, 0x0000, 0x080c, 0x2a66,
+	0x080c, 0x297c, 0x2001, 0x199c, 0x2003, 0x0700, 0x2001, 0x199d,
+	0x2003, 0x0700, 0x080c, 0x2ad7, 0x9006, 0x080c, 0x29ab, 0x9006,
+	0x080c, 0x298e, 0x20a9, 0x0012, 0x1d04, 0x223c, 0x2091, 0x6000,
+	0x1f04, 0x223c, 0x602f, 0x0100, 0x602f, 0x0000, 0x6050, 0x9085,
+	0x0400, 0x9084, 0xdfff, 0x6052, 0x6224, 0x080c, 0x2ab4, 0x080c,
+	0x269a, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x26aa, 0x60e7,
+	0x0000, 0x61ea, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000,
+	0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x349f, 0x00c6, 0x2061,
+	0x0140, 0x608b, 0x000b, 0x608f, 0x10b8, 0x6093, 0x0000, 0x6097,
+	0x0198, 0x00ce, 0x6004, 0x9085, 0x8000, 0x6006, 0x60bb, 0x0000,
+	0x20a9, 0x0018, 0x60bf, 0x0000, 0x1f04, 0x227a, 0x60bb, 0x0000,
+	0x60bf, 0x0108, 0x60bf, 0x0012, 0x60bf, 0x0405, 0x60bf, 0x0014,
+	0x60bf, 0x0320, 0x60bf, 0x0018, 0x601b, 0x00f0, 0x601f, 0x001e,
+	0x600f, 0x006b, 0x602b, 0x402c, 0x012e, 0x0005, 0x00f6, 0x2079,
+	0x0140, 0x78c3, 0x0080, 0x78c3, 0x0083, 0x78c3, 0x0000, 0x00fe,
+	0x0005, 0x2001, 0x1835, 0x2003, 0x0000, 0x2001, 0x1834, 0x2003,
+	0x0001, 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026,
+	0x6124, 0x6028, 0x910c, 0x0066, 0x2031, 0x1837, 0x2634, 0x96b4,
+	0x0028, 0x006e, 0x1138, 0x6020, 0xd1bc, 0x0120, 0xd0bc, 0x1168,
+	0xd0b4, 0x1198, 0x9184, 0x5e2c, 0x1118, 0x9184, 0x0007, 0x00aa,
+	0x9195, 0x0004, 0x9284, 0x0007, 0x0082, 0x0016, 0x2001, 0x0387,
+	0x200c, 0xd1a4, 0x001e, 0x0d70, 0x0c98, 0x0016, 0x2001, 0x0387,
+	0x200c, 0xd1b4, 0x001e, 0x0d30, 0x0c58, 0x22e8, 0x22e5, 0x22e5,
+	0x22e5, 0x22e7, 0x22e5, 0x22e5, 0x22e5, 0x080c, 0x0d7d, 0x0029,
+	0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x00a6, 0x6124, 0x6028,
+	0xd09c, 0x0118, 0xd19c, 0x1904, 0x2562, 0xd1f4, 0x190c, 0x0d76,
+	0x080c, 0x753d, 0x0904, 0x2345, 0x080c, 0xd09b, 0x1120, 0x7000,
+	0x9086, 0x0003, 0x0580, 0x6024, 0x9084, 0x1800, 0x0560, 0x080c,
+	0x7560, 0x0118, 0x080c, 0x754e, 0x1530, 0x2011, 0x0020, 0x080c,
+	0x2ab4, 0x6043, 0x0000, 0x080c, 0xd09b, 0x0168, 0x080c, 0x7560,
+	0x1150, 0x2001, 0x19a6, 0x2003, 0x0001, 0x6027, 0x1800, 0x080c,
+	0x73b3, 0x0804, 0x2565, 0x70a4, 0x9005, 0x1150, 0x70a7, 0x0001,
+	0x00d6, 0x2069, 0x0140, 0x080c, 0x7594, 0x00de, 0x1904, 0x2565,
+	0x080c, 0x784a, 0x0428, 0x080c, 0x7560, 0x1590, 0x6024, 0x9084,
+	0x1800, 0x1108, 0x0468, 0x080c, 0x784a, 0x080c, 0x7840, 0x080c,
+	0x6092, 0x080c, 0x746e, 0x0804, 0x2562, 0xd1ac, 0x1508, 0x6024,
+	0xd0dc, 0x1170, 0xd0e4, 0x1178, 0xd0d4, 0x1190, 0xd0cc, 0x0130,
+	0x7098, 0x9086, 0x0028, 0x1110, 0x080c, 0x7721, 0x0804, 0x2562,
+	0x080c, 0x7845, 0x0048, 0x2001, 0x197c, 0x2003, 0x0002, 0x0020,
+	0x080c, 0x767e, 0x0804, 0x2562, 0x080c, 0x77c4, 0x0804, 0x2562,
+	0x6220, 0xd1bc, 0x0138, 0xd2bc, 0x1904, 0x25cb, 0xd2b4, 0x1904,
+	0x25dd, 0x0000, 0xd1ac, 0x0904, 0x246f, 0x0036, 0x6328, 0xc3bc,
+	0x632a, 0x003e, 0x080c, 0x753d, 0x11d0, 0x2011, 0x0020, 0x080c,
+	0x2ab4, 0x0006, 0x0026, 0x0036, 0x080c, 0x7557, 0x1158, 0x080c,
+	0x7840, 0x080c, 0x6092, 0x080c, 0x746e, 0x003e, 0x002e, 0x000e,
+	0x00ae, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x7511, 0x0016,
+	0x0046, 0x00c6, 0x644c, 0x9486, 0xf0f0, 0x1138, 0x2061, 0x0100,
+	0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74da, 0x948c, 0xff00,
+	0x7038, 0xd084, 0x0178, 0x9186, 0xf800, 0x1160, 0x7048, 0xd084,
+	0x1148, 0xc085, 0x704a, 0x0036, 0x2418, 0x2011, 0x8016, 0x080c,
+	0x4b52, 0x003e, 0x080c, 0xd094, 0x1904, 0x2446, 0x9196, 0xff00,
+	0x05a8, 0x7060, 0x9084, 0x00ff, 0x810f, 0x81ff, 0x0110, 0x9116,
+	0x0568, 0x7130, 0xd184, 0x1550, 0x080c, 0x33ad, 0x0128, 0xc18d,
+	0x7132, 0x080c, 0x6ad5, 0x1510, 0x6240, 0x9294, 0x0010, 0x0130,
+	0x6248, 0x9294, 0xff00, 0x9296, 0xff00, 0x01c0, 0x7030, 0xd08c,
+	0x0904, 0x2446, 0x7038, 0xd08c, 0x1140, 0x2001, 0x180c, 0x200c,
+	0xd1ac, 0x1904, 0x2446, 0xc1ad, 0x2102, 0x0036, 0x73d8, 0x2011,
+	0x8013, 0x080c, 0x4b52, 0x003e, 0x0804, 0x2446, 0x7038, 0xd08c,
+	0x1140, 0x2001, 0x180c, 0x200c, 0xd1ac, 0x1904, 0x2446, 0xc1ad,
+	0x2102, 0x0036, 0x73d8, 0x2011, 0x8013, 0x080c, 0x4b52, 0x003e,
+	0x7130, 0xc185, 0x7132, 0x2011, 0x1848, 0x220c, 0xd1a4, 0x01f0,
+	0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x8979, 0x2019,
+	0x000e, 0x00c6, 0x2061, 0x0000, 0x080c, 0xe3b5, 0x00ce, 0x9484,
+	0x00ff, 0x9080, 0x33b9, 0x200d, 0x918c, 0xff00, 0x810f, 0x2120,
+	0x9006, 0x2009, 0x000e, 0x080c, 0xe445, 0x001e, 0x0016, 0x2009,
+	0x0002, 0x2019, 0x0004, 0x080c, 0x3205, 0x001e, 0x0078, 0x0156,
+	0x00b6, 0x20a9, 0x007f, 0x900e, 0x080c, 0x6693, 0x1110, 0x080c,
+	0x60ac, 0x8108, 0x1f04, 0x243c, 0x00be, 0x015e, 0x00ce, 0x004e,
+	0x080c, 0xa91e, 0x080c, 0xabe9, 0x080c, 0xa93a, 0x60e3, 0x0000,
+	0x001e, 0x2001, 0x1800, 0x2014, 0x9296, 0x0004, 0x1170, 0xd19c,
+	0x11b0, 0x2011, 0x180c, 0x2214, 0xd29c, 0x1120, 0x6204, 0x9295,
+	0x0002, 0x6206, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001,
+	0x1826, 0x2003, 0x0000, 0x2011, 0x0020, 0x080c, 0x2ab4, 0xd194,
+	0x0904, 0x2562, 0x0016, 0x080c, 0xa91e, 0x6220, 0xd2b4, 0x0904,
+	0x24fd, 0x080c, 0x8780, 0x080c, 0x9ed4, 0x2011, 0x0004, 0x080c,
+	0x2ab4, 0x00f6, 0x2019, 0x19f2, 0x2304, 0x907d, 0x0904, 0x24ca,
+	0x7804, 0x9086, 0x0032, 0x15f0, 0x00d6, 0x00c6, 0x00e6, 0x0096,
+	0x2069, 0x0140, 0x782c, 0x685e, 0x7808, 0x685a, 0x6043, 0x0002,
+	0x2001, 0x0003, 0x8001, 0x1df0, 0x6043, 0x0000, 0x2001, 0x003c,
+	0x8001, 0x1df0, 0x080c, 0x2a8a, 0x2001, 0x001e, 0x8001, 0x0240,
+	0x20a9, 0x0009, 0x080c, 0x2a41, 0x6904, 0xd1dc, 0x1140, 0x0cb0,
+	0x2001, 0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x080c,
+	0x967a, 0x080c, 0xa93a, 0x7814, 0x2048, 0xa867, 0x0103, 0x2f60,
+	0x080c, 0xacb0, 0x009e, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e,
+	0x00ae, 0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0x9084,
+	0x4000, 0x0110, 0x080c, 0x2a8a, 0x00de, 0x00c6, 0x2061, 0x19e6,
+	0x6034, 0x080c, 0xd09b, 0x0120, 0x909a, 0x0003, 0x1258, 0x0018,
+	0x909a, 0x00c8, 0x1238, 0x8000, 0x6036, 0x00ce, 0x080c, 0x9eac,
+	0x0804, 0x255f, 0x2061, 0x0100, 0x62c0, 0x080c, 0xa84f, 0x2019,
+	0x19f2, 0x2304, 0x9065, 0x0130, 0x6003, 0x0001, 0x2009, 0x0027,
+	0x080c, 0xad4d, 0x00ce, 0x0804, 0x255f, 0xd2bc, 0x0904, 0x2542,
+	0x080c, 0x878d, 0x2011, 0x0004, 0x080c, 0x2ab4, 0x00d6, 0x2069,
+	0x0140, 0x6804, 0x9084, 0x4000, 0x0110, 0x080c, 0x2a8a, 0x00de,
+	0x00c6, 0x2061, 0x19e6, 0x6050, 0x080c, 0xd09b, 0x0120, 0x909a,
+	0x0003, 0x1668, 0x0018, 0x909a, 0x00c8, 0x1648, 0x8000, 0x6052,
+	0x604c, 0x00ce, 0x9005, 0x05d8, 0x2009, 0x07d0, 0x080c, 0x8785,
+	0x9080, 0x0008, 0x2004, 0x9086, 0x0006, 0x1138, 0x2009, 0x1984,
+	0x2011, 0x0012, 0x080c, 0x2ac3, 0x0450, 0x9080, 0x0008, 0x2004,
+	0x9086, 0x0009, 0x0d98, 0x2009, 0x1984, 0x2011, 0x0016, 0x080c,
+	0x2ac3, 0x00e8, 0x2011, 0x0004, 0x080c, 0x2ab4, 0x00c0, 0x0036,
+	0x2019, 0x0001, 0x080c, 0xa1b8, 0x003e, 0x2019, 0x19f9, 0x2304,
+	0x9065, 0x0160, 0x2009, 0x004f, 0x6020, 0x9086, 0x0009, 0x1110,
+	0x2009, 0x004f, 0x6003, 0x0003, 0x080c, 0xad4d, 0x00ce, 0x080c,
+	0xa93a, 0x001e, 0xd19c, 0x0904, 0x25c4, 0x7038, 0xd0ac, 0x1558,
+	0x0016, 0x0156, 0x2011, 0x0008, 0x080c, 0x2ab4, 0x080c, 0x2ad7,
+	0x080c, 0x2b0a, 0x6050, 0xc0e5, 0x6052, 0x20a9, 0x0367, 0x1f04,
+	0x2591, 0x1d04, 0x2579, 0x080c, 0x87b4, 0x6020, 0xd09c, 0x1db8,
+	0x00f6, 0x2079, 0x0100, 0x080c, 0x29ed, 0x00fe, 0x1d80, 0x6050,
+	0xc0e4, 0x6052, 0x2011, 0x0008, 0x080c, 0x2ab4, 0x015e, 0x001e,
+	0x0498, 0x015e, 0x001e, 0x0016, 0x6028, 0xc09c, 0x602a, 0x080c,
+	0xa91e, 0x080c, 0xabe9, 0x080c, 0xa93a, 0x60e3, 0x0000, 0x080c,
+	0xe882, 0x080c, 0xe89d, 0x080c, 0x5742, 0xd0fc, 0x1138, 0x080c,
+	0xd094, 0x1120, 0x9085, 0x0001, 0x080c, 0x7584, 0x9006, 0x080c,
+	0x2a7a, 0x2009, 0x0002, 0x080c, 0x2a66, 0x00e6, 0x2071, 0x1800,
+	0x7003, 0x0004, 0x080c, 0x0ec1, 0x00ee, 0x2011, 0x0008, 0x080c,
+	0x2ab4, 0x080c, 0x0bc3, 0x001e, 0x918c, 0xffd0, 0x2110, 0x080c,
+	0x2ab4, 0x00ae, 0x0005, 0x0016, 0x2001, 0x0387, 0x200c, 0xd1a4,
+	0x001e, 0x0904, 0x2372, 0x0016, 0x2009, 0x25d7, 0x00c0, 0x2001,
+	0x0387, 0x2003, 0x1000, 0x001e, 0x0c38, 0x0016, 0x2001, 0x0387,
+	0x200c, 0xd1b4, 0x001e, 0x0904, 0x2372, 0x0016, 0x2009, 0x25e9,
+	0x0030, 0x2001, 0x0387, 0x2003, 0x4000, 0x001e, 0x08a8, 0x6028,
+	0xc0bc, 0x602a, 0x2001, 0x0156, 0x2003, 0xbc91, 0x8000, 0x2003,
+	0xffff, 0x6043, 0x0001, 0x080c, 0x2a60, 0x2011, 0x0080, 0x080c,
+	0x2ab4, 0x6017, 0x0000, 0x6043, 0x0000, 0x0817, 0x0006, 0x0016,
+	0x0026, 0x0036, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x1800, 0x71d0, 0x70d2, 0x9116, 0x0904, 0x2659, 0x81ff, 0x01a0,
+	0x2009, 0x0000, 0x080c, 0x2a66, 0x2011, 0x8011, 0x2019, 0x010e,
+	0x231c, 0x939e, 0x0007, 0x1118, 0x2019, 0x0001, 0x0010, 0x2019,
+	0x0000, 0x080c, 0x4b52, 0x0468, 0x2001, 0x19a7, 0x200c, 0x81ff,
+	0x1140, 0x2001, 0x0109, 0x2004, 0xd0b4, 0x0118, 0x2019, 0x0003,
+	0x0008, 0x2118, 0x2011, 0x8012, 0x080c, 0x4b52, 0x080c, 0x0ec1,
+	0x080c, 0x5742, 0xd0fc, 0x11a8, 0x080c, 0xd094, 0x1190, 0x00c6,
+	0x080c, 0x26f5, 0x080c, 0xa91e, 0x080c, 0xa113, 0x080c, 0xa93a,
+	0x2061, 0x0100, 0x2019, 0x0028, 0x2009, 0x0002, 0x080c, 0x3205,
+	0x00ce, 0x012e, 0x00fe, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e,
+	0x0005, 0x2028, 0x918c, 0x00ff, 0x2130, 0x9094, 0xff00, 0x11f0,
+	0x2011, 0x1837, 0x2214, 0xd2ac, 0x11c8, 0x81ff, 0x01e8, 0x2011,
+	0x181f, 0x2204, 0x9106, 0x1190, 0x2011, 0x1820, 0x2214, 0x9294,
+	0xff00, 0x9584, 0xff00, 0x9206, 0x1148, 0x2011, 0x1820, 0x2214,
+	0x9294, 0x00ff, 0x9584, 0x00ff, 0x9206, 0x1120, 0x2500, 0x080c,
+	0x8256, 0x0048, 0x9584, 0x00ff, 0x9080, 0x33b9, 0x200d, 0x918c,
+	0xff00, 0x810f, 0x9006, 0x0005, 0x9080, 0x33b9, 0x200d, 0x918c,
+	0x00ff, 0x0005, 0x00d6, 0x2069, 0x0140, 0x2001, 0x1818, 0x2003,
+	0x00ef, 0x20a9, 0x0010, 0x9006, 0x6852, 0x6856, 0x1f04, 0x26a5,
+	0x00de, 0x0005, 0x0006, 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001,
+	0x1818, 0x2102, 0x8114, 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010,
+	0x6853, 0x0000, 0x9006, 0x82ff, 0x1128, 0x9184, 0x000f, 0x9080,
+	0xe8b1, 0x2005, 0x6856, 0x8211, 0x1f04, 0x26ba, 0x002e, 0x00de,
+	0x000e, 0x0005, 0x00c6, 0x2061, 0x1800, 0x6030, 0x0110, 0xc09d,
+	0x0008, 0xc09c, 0x6032, 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026,
+	0x0016, 0x0006, 0x2069, 0x0140, 0x6980, 0x9116, 0x0180, 0x9112,
+	0x1230, 0x8212, 0x8210, 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8,
+	0x2001, 0x0404, 0x680e, 0x1f04, 0x26ea, 0x680f, 0x0000, 0x000e,
+	0x001e, 0x002e, 0x00de, 0x015e, 0x0005, 0x080c, 0x573e, 0xd0c4,
+	0x0150, 0xd0a4, 0x0140, 0x9006, 0x0046, 0x2020, 0x2009, 0x002e,
+	0x080c, 0xe445, 0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079,
+	0x0140, 0x78c4, 0xd0dc, 0x0904, 0x2761, 0x080c, 0x29dd, 0x0660,
+	0x9084, 0x0700, 0x908e, 0x0600, 0x1120, 0x2011, 0x4000, 0x900e,
+	0x0458, 0x908e, 0x0500, 0x1120, 0x2011, 0x8000, 0x900e, 0x0420,
+	0x908e, 0x0400, 0x1120, 0x9016, 0x2009, 0x0001, 0x00e8, 0x908e,
+	0x0300, 0x1120, 0x9016, 0x2009, 0x0002, 0x00b0, 0x908e, 0x0200,
+	0x1120, 0x9016, 0x2009, 0x0004, 0x0078, 0x908e, 0x0100, 0x1548,
+	0x9016, 0x2009, 0x0008, 0x0040, 0x9084, 0x0700, 0x908e, 0x0300,
+	0x1500, 0x2011, 0x0030, 0x0058, 0x2300, 0x9080, 0x0020, 0x2018,
+	0x080c, 0x91f8, 0x928c, 0xff00, 0x0110, 0x2011, 0x00ff, 0x2200,
+	0x8007, 0x9085, 0x004c, 0x78c2, 0x2009, 0x0138, 0x220a, 0x080c,
+	0x753d, 0x1118, 0x2009, 0x196c, 0x220a, 0x002e, 0x001e, 0x00fe,
+	0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126, 0x2091, 0x2800, 0x0006,
+	0x0016, 0x0026, 0x2001, 0x0170, 0x200c, 0x8000, 0x2014, 0x9184,
+	0x0003, 0x0110, 0x080c, 0x0d76, 0x002e, 0x001e, 0x000e, 0x012e,
+	0x0005, 0x2001, 0x0171, 0x2004, 0xd0dc, 0x0168, 0x2001, 0x0170,
+	0x200c, 0x918c, 0x00ff, 0x918e, 0x004c, 0x1128, 0x200c, 0x918c,
+	0xff00, 0x810f, 0x0005, 0x900e, 0x2001, 0x0227, 0x2004, 0x8007,
+	0x9084, 0x00ff, 0x8004, 0x9108, 0x2001, 0x0226, 0x2004, 0x8007,
+	0x9084, 0x00ff, 0x8004, 0x9108, 0x0005, 0x0018, 0x000c, 0x0018,
+	0x0020, 0x1000, 0x0800, 0x1000, 0x1800, 0x0156, 0x0006, 0x0016,
+	0x0026, 0x00e6, 0x2001, 0x198f, 0x2004, 0x908a, 0x0007, 0x1a0c,
+	0x0d7d, 0x0033, 0x00ee, 0x002e, 0x001e, 0x000e, 0x015e, 0x0005,
+	0x27bf, 0x27dd, 0x2801, 0x2803, 0x282c, 0x282e, 0x2830, 0x2001,
+	0x0001, 0x080c, 0x2606, 0x080c, 0x2a2b, 0x2001, 0x1991, 0x2003,
+	0x0000, 0x7828, 0x9084, 0xe1d7, 0x782a, 0x9006, 0x20a9, 0x0009,
+	0x080c, 0x29f9, 0x2001, 0x198f, 0x2003, 0x0006, 0x2009, 0x001e,
+	0x2011, 0x2831, 0x080c, 0x8792, 0x0005, 0x2009, 0x1994, 0x200b,
+	0x0000, 0x2001, 0x1999, 0x2003, 0x0036, 0x2001, 0x1998, 0x2003,
+	0x002a, 0x2001, 0x1991, 0x2003, 0x0001, 0x9006, 0x080c, 0x298e,
+	0x2001, 0xffff, 0x20a9, 0x0009, 0x080c, 0x29f9, 0x2001, 0x198f,
+	0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x2831, 0x080c, 0x8792,
+	0x0005, 0x080c, 0x0d7d, 0x2001, 0x1999, 0x2003, 0x0036, 0x2001,
+	0x1991, 0x2003, 0x0003, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004,
+	0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c, 0x298e, 0x2001,
+	0x1995, 0x2003, 0x0000, 0x2001, 0xffff, 0x20a9, 0x0009, 0x080c,
+	0x29f9, 0x2001, 0x198f, 0x2003, 0x0006, 0x2009, 0x001e, 0x2011,
+	0x2831, 0x080c, 0x8792, 0x0005, 0x080c, 0x0d7d, 0x080c, 0x0d7d,
+	0x0005, 0x0006, 0x0016, 0x0026, 0x00e6, 0x00f6, 0x0156, 0x0126,
+	0x2091, 0x8000, 0x2079, 0x0100, 0x2001, 0x1991, 0x2004, 0x908a,
+	0x0007, 0x1a0c, 0x0d7d, 0x0043, 0x012e, 0x015e, 0x00fe, 0x00ee,
+	0x002e, 0x001e, 0x000e, 0x0005, 0x2853, 0x2873, 0x28b3, 0x28e3,
+	0x2907, 0x2917, 0x2919, 0x080c, 0x29ed, 0x11b0, 0x7850, 0x9084,
+	0xefff, 0x7852, 0x2009, 0x1997, 0x2104, 0x7a38, 0x9294, 0x0005,
+	0x9296, 0x0004, 0x0110, 0xc08d, 0x0008, 0xc085, 0x200a, 0x2001,
+	0x198f, 0x2003, 0x0001, 0x0030, 0x080c, 0x293d, 0x2001, 0xffff,
+	0x080c, 0x27ce, 0x0005, 0x080c, 0x291b, 0x05e0, 0x2009, 0x1998,
+	0x2104, 0x8001, 0x200a, 0x080c, 0x29ed, 0x1178, 0x7850, 0x9084,
+	0xefff, 0x7852, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0518,
+	0x2009, 0x1997, 0x2104, 0xc085, 0x200a, 0x2009, 0x1994, 0x2104,
+	0x8000, 0x200a, 0x9086, 0x0005, 0x0118, 0x080c, 0x2923, 0x00c0,
+	0x200b, 0x0000, 0x7a38, 0x9294, 0x0006, 0x9296, 0x0004, 0x0110,
+	0x9006, 0x0010, 0x2001, 0x0001, 0x080c, 0x29ab, 0x2001, 0x1991,
+	0x2003, 0x0002, 0x0028, 0x2001, 0x198f, 0x2003, 0x0003, 0x0010,
+	0x080c, 0x27f0, 0x0005, 0x080c, 0x291b, 0x0560, 0x2009, 0x1998,
+	0x2104, 0x8001, 0x200a, 0x080c, 0x29ed, 0x1168, 0x7850, 0x9084,
+	0xefff, 0x7852, 0x2001, 0x198f, 0x2003, 0x0003, 0x2001, 0x1990,
+	0x2003, 0x0000, 0x00b8, 0x2009, 0x1998, 0x2104, 0x9005, 0x1118,
+	0x080c, 0x2960, 0x0010, 0x080c, 0x2930, 0x080c, 0x2923, 0x2009,
+	0x1994, 0x200b, 0x0000, 0x2001, 0x1991, 0x2003, 0x0001, 0x080c,
+	0x27f0, 0x0000, 0x0005, 0x04b9, 0x0508, 0x080c, 0x29ed, 0x11b8,
+	0x7850, 0x9084, 0xefff, 0x7852, 0x2009, 0x1995, 0x2104, 0x8000,
+	0x200a, 0x9086, 0x0007, 0x0108, 0x0078, 0x2001, 0x199a, 0x2003,
+	0x000a, 0x2009, 0x1997, 0x2104, 0xc0fd, 0x200a, 0x0038, 0x0419,
+	0x2001, 0x1991, 0x2003, 0x0004, 0x080c, 0x281b, 0x0005, 0x0099,
+	0x0168, 0x080c, 0x29ed, 0x1138, 0x7850, 0x9084, 0xefff, 0x7852,
+	0x080c, 0x2807, 0x0018, 0x0079, 0x080c, 0x281b, 0x0005, 0x080c,
+	0x0d7d, 0x080c, 0x0d7d, 0x2009, 0x1999, 0x2104, 0x8001, 0x200a,
+	0x090c, 0x297c, 0x0005, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005,
+	0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c, 0x29ab, 0x0005,
+	0x7a38, 0x9294, 0x0006, 0x9296, 0x0006, 0x0110, 0x9006, 0x0010,
+	0x2001, 0x0001, 0x080c, 0x298e, 0x0005, 0x2009, 0x1994, 0x2104,
+	0x8000, 0x200a, 0x9086, 0x0005, 0x0108, 0x0068, 0x200b, 0x0000,
+	0x7a38, 0x9294, 0x0006, 0x9296, 0x0006, 0x0110, 0x9006, 0x0010,
+	0x2001, 0x0001, 0x04d9, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0005,
+	0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c, 0x29ab, 0x0005,
+	0x0086, 0x2001, 0x1997, 0x2004, 0x9084, 0x7fff, 0x090c, 0x0d7d,
+	0x2009, 0x1996, 0x2144, 0x8846, 0x280a, 0x9844, 0x0dd8, 0xd08c,
+	0x1120, 0xd084, 0x1120, 0x080c, 0x0d7d, 0x9006, 0x0010, 0x2001,
+	0x0001, 0x00a1, 0x008e, 0x0005, 0x0006, 0x0156, 0x2001, 0x198f,
+	0x20a9, 0x0009, 0x2003, 0x0000, 0x8000, 0x1f04, 0x2982, 0x2001,
+	0x1996, 0x2003, 0x8000, 0x015e, 0x000e, 0x0005, 0x00f6, 0x2079,
+	0x0100, 0x9085, 0x0000, 0x0158, 0x7838, 0x9084, 0xfff9, 0x9085,
+	0x0004, 0x783a, 0x2009, 0x199c, 0x210c, 0x795a, 0x0050, 0x7838,
+	0x9084, 0xfffb, 0x9085, 0x0006, 0x783a, 0x2009, 0x199d, 0x210c,
+	0x795a, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000,
+	0x0158, 0x7838, 0x9084, 0xfffa, 0x9085, 0x0004, 0x783a, 0x7850,
+	0x9084, 0xfff0, 0x7852, 0x00f8, 0x7838, 0x9084, 0xfffb, 0x9085,
+	0x0005, 0x783a, 0x7850, 0x9084, 0xfff0, 0x0016, 0x2009, 0x017f,
+	0x210c, 0x918e, 0x0005, 0x0140, 0x2009, 0x0003, 0x210c, 0x918c,
+	0x0600, 0x918e, 0x0400, 0x0118, 0x9085, 0x000a, 0x0010, 0x9085,
+	0x0000, 0x001e, 0x7852, 0x00fe, 0x0005, 0x0006, 0x2001, 0x0100,
+	0x2004, 0x9082, 0x0007, 0x000e, 0x0005, 0x0006, 0x2001, 0x0100,
+	0x2004, 0x9082, 0x0009, 0x000e, 0x0005, 0x0156, 0x20a9, 0x0064,
+	0x7820, 0x080c, 0x2a60, 0xd09c, 0x1110, 0x1f04, 0x29f0, 0x015e,
+	0x0005, 0x0126, 0x0016, 0x0006, 0x2091, 0x8000, 0x080c, 0x2ad7,
+	0x080c, 0x2b0a, 0x000e, 0x2008, 0x9186, 0x0000, 0x1118, 0x783b,
+	0x0007, 0x0090, 0x9186, 0x0001, 0x1118, 0x783b, 0x0006, 0x0060,
+	0x9186, 0x0002, 0x1118, 0x783b, 0x0005, 0x0030, 0x9186, 0x0003,
+	0x1118, 0x783b, 0x0004, 0x0000, 0x0006, 0x1d04, 0x2a1d, 0x080c,
+	0x87b4, 0x1f04, 0x2a1d, 0x7850, 0x9085, 0x1000, 0x7852, 0x000e,
+	0x001e, 0x012e, 0x0005, 0x080c, 0x2b0a, 0x0005, 0x0006, 0x0156,
+	0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd0ac, 0x1100,
+	0x7854, 0xd08c, 0x1110, 0x1f04, 0x2a38, 0x00fe, 0x015e, 0x000e,
+	0x0005, 0x1d04, 0x2a41, 0x080c, 0x87b4, 0x1f04, 0x2a41, 0x0005,
+	0x0006, 0x2001, 0x199b, 0x2004, 0x9086, 0x0000, 0x000e, 0x0005,
+	0x0006, 0x2001, 0x199b, 0x2004, 0x9086, 0x0001, 0x000e, 0x0005,
+	0x0006, 0x2001, 0x199b, 0x2004, 0x9086, 0x0002, 0x000e, 0x0005,
+	0xa001, 0xa001, 0xa001, 0xa001, 0xa001, 0x0005, 0x0006, 0x2001,
+	0x19a7, 0x2102, 0x000e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc,
+	0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xa001, 0xa001,
+	0x200a, 0x0005, 0x0016, 0x0026, 0x080c, 0x7557, 0x0108, 0xc0bc,
+	0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9215, 0x220a, 0x002e,
+	0x001e, 0x0005, 0x0016, 0x0026, 0x2009, 0x0140, 0x2114, 0x9294,
+	0x0001, 0x9285, 0x1000, 0x200a, 0x220a, 0x002e, 0x001e, 0x0005,
+	0x0016, 0x0026, 0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9215,
+	0x220a, 0x002e, 0x001e, 0x0005, 0x0006, 0x0016, 0x2009, 0x0140,
+	0x2104, 0x1128, 0x080c, 0x7557, 0x0110, 0xc0bc, 0x0008, 0xc0bd,
+	0x200a, 0x001e, 0x000e, 0x0005, 0x00f6, 0x2079, 0x0380, 0x7843,
+	0x0101, 0x7844, 0xd084, 0x1de8, 0x2001, 0x0109, 0x2202, 0x7843,
+	0x0100, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0380, 0x7843, 0x0202,
+	0x7844, 0xd08c, 0x1de8, 0x2079, 0x0100, 0x7814, 0x9104, 0x9205,
+	0x7a16, 0x2079, 0x0380, 0x7843, 0x0200, 0x00fe, 0x0005, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x2061, 0x0100, 0x6050, 0x9084, 0xfbff,
+	0x9085, 0x0040, 0x6052, 0x20a9, 0x0002, 0x080c, 0x2a41, 0x6050,
+	0x9085, 0x0400, 0x9084, 0xff9f, 0x6052, 0x20a9, 0x0005, 0x080c,
+	0x2a41, 0x6054, 0xd0bc, 0x090c, 0x0d7d, 0x20a9, 0x0005, 0x080c,
+	0x2a41, 0x6054, 0xd0ac, 0x090c, 0x0d7d, 0x2009, 0x19ae, 0x9084,
+	0x7e00, 0x8007, 0x8004, 0x8004, 0x200a, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x0005, 0x0006, 0x00c6, 0x2061, 0x0100, 0x6050, 0xc0cd,
+	0x6052, 0x00ce, 0x000e, 0x0005, 0x3010, 0x3010, 0x2c14, 0x2c14,
+	0x2c20, 0x2c20, 0x2c2c, 0x2c2c, 0x2c3a, 0x2c3a, 0x2c46, 0x2c46,
+	0x2c54, 0x2c54, 0x2c62, 0x2c62, 0x2c74, 0x2c74, 0x2c80, 0x2c80,
+	0x2c8e, 0x2c8e, 0x2cac, 0x2cac, 0x2ccc, 0x2ccc, 0x2c9c, 0x2c9c,
+	0x2cbc, 0x2cbc, 0x2cda, 0x2cda, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2cec, 0x2cec, 0x2cf8, 0x2cf8,
+	0x2d06, 0x2d06, 0x2d14, 0x2d14, 0x2d24, 0x2d24, 0x2d32, 0x2d32,
+	0x2d42, 0x2d42, 0x2d52, 0x2d52, 0x2d64, 0x2d64, 0x2d72, 0x2d72,
+	0x2d82, 0x2d82, 0x2da4, 0x2da4, 0x2dc8, 0x2dc8, 0x2d92, 0x2d92,
+	0x2db6, 0x2db6, 0x2dd8, 0x2dd8, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2dec, 0x2dec, 0x2df8, 0x2df8,
+	0x2e06, 0x2e06, 0x2e14, 0x2e14, 0x2e24, 0x2e24, 0x2e32, 0x2e32,
+	0x2e42, 0x2e42, 0x2e52, 0x2e52, 0x2e64, 0x2e64, 0x2e72, 0x2e72,
+	0x2e82, 0x2e82, 0x2e92, 0x2e92, 0x2ea4, 0x2ea4, 0x2eb4, 0x2eb4,
+	0x2ec6, 0x2ec6, 0x2ed8, 0x2ed8, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2eec, 0x2eec, 0x2efa, 0x2efa,
+	0x2f0a, 0x2f0a, 0x2f1a, 0x2f1a, 0x2f2c, 0x2f2c, 0x2f3c, 0x2f3c,
+	0x2f4e, 0x2f4e, 0x2f60, 0x2f60, 0x2f74, 0x2f74, 0x2f84, 0x2f84,
+	0x2f96, 0x2f96, 0x2fa8, 0x2fa8, 0x2fbc, 0x2fbc, 0x2fcd, 0x2fcd,
+	0x2fe0, 0x2fe0, 0x2ff3, 0x2ff3, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x2c72,
+	0x2c72, 0x2c72, 0x2c72, 0x2c72, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22aa, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x20d4, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x22aa,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22aa,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x22aa, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0xa001, 0x0cf0, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x13bb, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x22aa, 0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4,
+	0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x22aa,
+	0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x13bb, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x22aa, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764,
+	0x080c, 0x20d4, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4,
+	0x080c, 0x22aa, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x22aa, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0x22aa,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4,
+	0x080c, 0x22aa, 0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764,
+	0x080c, 0x20d4, 0x080c, 0x13bb, 0x080c, 0x20fe, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x13bb, 0x080c, 0x20fe, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0xa984, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0xa984, 0x080c, 0x22aa, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4,
+	0x080c, 0xa984, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0xa984,
+	0x080c, 0x22aa, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x22aa, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x20fe,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x13bb,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x080c, 0x13bb, 0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x20d4,
+	0x080c, 0xa984, 0x080c, 0x13bb, 0x080c, 0x20fe, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x22aa, 0x080c, 0x13bb,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0xa984,
+	0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0xa984,
+	0x080c, 0x22aa, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x080c, 0x22aa, 0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764,
+	0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x20fe, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x080c, 0x20fe, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x080c, 0x22aa, 0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006,
+	0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764,
+	0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x13bb, 0x0804, 0x3008,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0xa984, 0x080c, 0x22aa,
+	0x080c, 0x13bb, 0x0804, 0x3008, 0x0106, 0x0006, 0x0126, 0x01c6,
+	0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0xa984,
+	0x080c, 0x13bb, 0x080c, 0x20fe, 0x04d8, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c,
+	0xa984, 0x080c, 0x22aa, 0x080c, 0x13bb, 0x080c, 0x20fe, 0x0440,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2764, 0x080c, 0x20d4, 0x080c, 0x13bb, 0x080c, 0xa984,
+	0x080c, 0x20fe, 0x00a8, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6,
+	0x0136, 0x0146, 0x0156, 0x080c, 0x2764, 0x080c, 0x20d4, 0x080c,
+	0xa984, 0x080c, 0x22aa, 0x080c, 0x13bb, 0x080c, 0x20fe, 0x0000,
+	0x015e, 0x014e, 0x013e, 0x01de, 0x01ce, 0x012e, 0x000e, 0x010e,
+	0x000d, 0x00b6, 0x00c6, 0x0026, 0x0046, 0x9026, 0x080c, 0x6a9b,
+	0x1904, 0x3121, 0x72dc, 0x2001, 0x197b, 0x2004, 0x9005, 0x1110,
+	0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x3121, 0x080c,
+	0x3126, 0x0804, 0x3121, 0xd2cc, 0x1904, 0x3121, 0x080c, 0x753d,
+	0x1120, 0x70af, 0xffff, 0x0804, 0x3121, 0xd294, 0x0120, 0x70af,
+	0xffff, 0x0804, 0x3121, 0x080c, 0x33a8, 0x0160, 0x080c, 0xd09b,
+	0x0128, 0x2001, 0x1818, 0x203c, 0x0804, 0x30ae, 0x70af, 0xffff,
+	0x0804, 0x3121, 0x2001, 0x1818, 0x203c, 0x7294, 0xd284, 0x0904,
+	0x30ae, 0xd28c, 0x1904, 0x30ae, 0x0036, 0x73ac, 0x938e, 0xffff,
+	0x1110, 0x2019, 0x0001, 0x8314, 0x92e0, 0x1d80, 0x2c04, 0x938c,
+	0x0001, 0x0120, 0x9084, 0xff00, 0x8007, 0x0010, 0x9084, 0x00ff,
+	0x970e, 0x05d0, 0x908e, 0x0000, 0x05b8, 0x908e, 0x00ff, 0x1150,
+	0x7230, 0xd284, 0x15b0, 0x7294, 0xc28d, 0x7296, 0x70af, 0xffff,
+	0x003e, 0x04a0, 0x900e, 0x080c, 0x2661, 0x080c, 0x6632, 0x1538,
+	0x9006, 0xb8bb, 0x0520, 0xb8ac, 0x9005, 0x0148, 0x00c6, 0x2060,
+	0x080c, 0x8c1f, 0x00ce, 0x090c, 0x8fbc, 0xb8af, 0x0000, 0x080c,
+	0x6add, 0x1168, 0x7030, 0xd08c, 0x0130, 0xb800, 0xd0bc, 0x0138,
+	0x080c, 0x6986, 0x0120, 0x080c, 0x313f, 0x0148, 0x0028, 0x080c,
+	0x328b, 0x080c, 0x316b, 0x0118, 0x8318, 0x0804, 0x305b, 0x73ae,
+	0x0010, 0x70af, 0xffff, 0x003e, 0x0804, 0x3121, 0x9780, 0x33b9,
+	0x203d, 0x97bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x70ac, 0x9096,
+	0xffff, 0x1118, 0x900e, 0x28a8, 0x0050, 0x9812, 0x0220, 0x2008,
+	0x9802, 0x20a8, 0x0020, 0x70af, 0xffff, 0x0804, 0x3121, 0x2700,
+	0x0156, 0x0016, 0x9106, 0x0904, 0x3116, 0xc484, 0x080c, 0x6693,
+	0x0148, 0x080c, 0xd09b, 0x1904, 0x3116, 0x080c, 0x6632, 0x1904,
+	0x311e, 0x0008, 0xc485, 0xb8bb, 0x0520, 0xb8ac, 0x9005, 0x0148,
+	0x00c6, 0x2060, 0x080c, 0x8c1f, 0x00ce, 0x090c, 0x8fbc, 0xb8af,
+	0x0000, 0x080c, 0x6add, 0x1130, 0x7030, 0xd08c, 0x01f8, 0xb800,
+	0xd0bc, 0x11e0, 0x7294, 0xd28c, 0x0180, 0x080c, 0x6add, 0x9082,
+	0x0006, 0x02e0, 0xd484, 0x1118, 0x080c, 0x6657, 0x0028, 0x080c,
+	0x331e, 0x01a0, 0x080c, 0x3349, 0x0088, 0x080c, 0x328b, 0x080c,
+	0xd09b, 0x1160, 0x080c, 0x316b, 0x0188, 0x0040, 0x080c, 0xd09b,
+	0x1118, 0x080c, 0x331e, 0x0110, 0x0451, 0x0140, 0x001e, 0x8108,
+	0x015e, 0x1f04, 0x30c7, 0x70af, 0xffff, 0x0018, 0x001e, 0x015e,
+	0x71ae, 0x004e, 0x002e, 0x00ce, 0x00be, 0x0005, 0x00c6, 0x0016,
+	0x70af, 0x0001, 0x2009, 0x007e, 0x080c, 0x6632, 0x1168, 0xb813,
+	0x00ff, 0xb817, 0xfffe, 0x080c, 0x328b, 0x04a9, 0x0128, 0x70dc,
+	0xc0bd, 0x70de, 0x080c, 0xcde8, 0x001e, 0x00ce, 0x0005, 0x0016,
+	0x0076, 0x00d6, 0x00c6, 0x2001, 0x184c, 0x2004, 0x9084, 0x00ff,
+	0xb842, 0x080c, 0xad20, 0x01d0, 0x2b00, 0x6012, 0x080c, 0xce15,
+	0x6023, 0x0001, 0x9006, 0x080c, 0x65cf, 0x2001, 0x0000, 0x080c,
+	0x65e3, 0x0126, 0x2091, 0x8000, 0x70a8, 0x8000, 0x70aa, 0x012e,
+	0x2009, 0x0004, 0x080c, 0xad4d, 0x9085, 0x0001, 0x00ce, 0x00de,
+	0x007e, 0x001e, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2001,
+	0x184c, 0x2004, 0x9084, 0x00ff, 0xb842, 0x080c, 0xad20, 0x0548,
+	0x2b00, 0x6012, 0xb800, 0xc0c4, 0xb802, 0xb8a0, 0x9086, 0x007e,
+	0x0140, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1110, 0x080c,
+	0x3240, 0x080c, 0xce15, 0x6023, 0x0001, 0x9006, 0x080c, 0x65cf,
+	0x2001, 0x0002, 0x080c, 0x65e3, 0x0126, 0x2091, 0x8000, 0x70a8,
+	0x8000, 0x70aa, 0x012e, 0x2009, 0x0002, 0x080c, 0xad4d, 0x9085,
+	0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00b6, 0x00c6,
+	0x0026, 0x2009, 0x0080, 0x080c, 0x6632, 0x1140, 0xb813, 0x00ff,
+	0xb817, 0xfffc, 0x0039, 0x0110, 0x70e3, 0xffff, 0x002e, 0x00ce,
+	0x00be, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x080c, 0xac5a,
+	0x01d0, 0x2b00, 0x6012, 0x080c, 0xce15, 0x6023, 0x0001, 0x9006,
+	0x080c, 0x65cf, 0x2001, 0x0002, 0x080c, 0x65e3, 0x0126, 0x2091,
+	0x8000, 0x70e4, 0x8000, 0x70e6, 0x012e, 0x2009, 0x0002, 0x080c,
+	0xad4d, 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005,
+	0x00c6, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2009, 0x007f, 0x080c,
+	0x6632, 0x11b8, 0xb813, 0x00ff, 0xb817, 0xfffd, 0xb8d7, 0x0004,
+	0x080c, 0xac5a, 0x0170, 0x2b00, 0x6012, 0x6316, 0x6023, 0x0001,
+	0x620a, 0x080c, 0xce15, 0x2009, 0x0022, 0x080c, 0xad4d, 0x9085,
+	0x0001, 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066,
+	0x0036, 0x0026, 0x00b6, 0x21f0, 0x080c, 0xa91e, 0x0106, 0x080c,
+	0x9448, 0x080c, 0x93b9, 0x080c, 0xa86f, 0x080c, 0xbbf9, 0x010e,
+	0x090c, 0xa93a, 0x3e08, 0x2130, 0x81ff, 0x0120, 0x20a9, 0x007e,
+	0x900e, 0x0018, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x6693,
+	0x1140, 0x9686, 0x0002, 0x1118, 0xb800, 0xd0bc, 0x1110, 0x080c,
+	0x60ac, 0x001e, 0x8108, 0x1f04, 0x3225, 0x9686, 0x0001, 0x190c,
+	0x337c, 0x00be, 0x002e, 0x003e, 0x006e, 0x00ce, 0x00ee, 0x0005,
+	0x00e6, 0x00c6, 0x0046, 0x0036, 0x0026, 0x0016, 0x00b6, 0x080c,
+	0xa91e, 0x0106, 0x6210, 0x2258, 0xbaa0, 0x0026, 0x2019, 0x0029,
+	0x080c, 0x943d, 0x0076, 0x2039, 0x0000, 0x080c, 0x9306, 0x2c08,
+	0x080c, 0xe167, 0x007e, 0x001e, 0x010e, 0x090c, 0xa93a, 0xba10,
+	0xbb14, 0xbc84, 0x080c, 0x60ac, 0xba12, 0xbb16, 0xbc86, 0x00be,
+	0x001e, 0x002e, 0x003e, 0x004e, 0x00ce, 0x00ee, 0x0005, 0x00e6,
+	0x0006, 0x00b6, 0x6010, 0x2058, 0xb8a0, 0x00be, 0x9086, 0x0080,
+	0x0150, 0x2071, 0x1800, 0x70a8, 0x9005, 0x0110, 0x8001, 0x70aa,
+	0x000e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x70e4, 0x9005, 0x0dc0,
+	0x8001, 0x70e6, 0x0ca8, 0xb800, 0xc08c, 0xb802, 0x0005, 0x00f6,
+	0x00e6, 0x00c6, 0x00b6, 0x0046, 0x0036, 0x0026, 0x0016, 0x0156,
+	0x2178, 0x080c, 0xa91e, 0x0106, 0x81ff, 0x1118, 0x20a9, 0x0001,
+	0x0078, 0x080c, 0x573e, 0xd0c4, 0x0140, 0xd0a4, 0x0130, 0x9006,
+	0x2020, 0x2009, 0x002d, 0x080c, 0xe445, 0x20a9, 0x0800, 0x9016,
+	0x0026, 0x928e, 0x007e, 0x0904, 0x32fa, 0x928e, 0x007f, 0x0904,
+	0x32fa, 0x928e, 0x0080, 0x05f0, 0x9288, 0x1000, 0x210c, 0x81ff,
+	0x05c8, 0x8fff, 0x1150, 0x2001, 0x198d, 0x0006, 0x2003, 0x0001,
+	0x080c, 0x330b, 0x000e, 0x2003, 0x0000, 0x00b6, 0x00c6, 0x2158,
+	0x2001, 0x0001, 0x080c, 0x6aa7, 0x00ce, 0x00be, 0x2019, 0x0029,
+	0x080c, 0x943d, 0x0076, 0x2039, 0x0000, 0x080c, 0x9306, 0x00b6,
+	0x00c6, 0x0026, 0x2158, 0xba04, 0x9294, 0x00ff, 0x9286, 0x0006,
+	0x1118, 0xb807, 0x0404, 0x0028, 0x2001, 0x0004, 0x8007, 0x9215,
+	0xba06, 0x002e, 0x00ce, 0x00be, 0x0016, 0x2c08, 0x080c, 0xe167,
+	0x001e, 0x007e, 0x002e, 0x8210, 0x1f04, 0x32b0, 0x010e, 0x090c,
+	0xa93a, 0x015e, 0x001e, 0x002e, 0x003e, 0x004e, 0x00be, 0x00ce,
+	0x00ee, 0x00fe, 0x0005, 0x0046, 0x0026, 0x0016, 0x080c, 0x573e,
+	0xd0c4, 0x0140, 0xd0a4, 0x0130, 0x9006, 0x2220, 0x2009, 0x0029,
+	0x080c, 0xe445, 0x001e, 0x002e, 0x004e, 0x0005, 0x0016, 0x0026,
+	0x0036, 0x00c6, 0x7294, 0x82ff, 0x01e8, 0x080c, 0x6ad5, 0x11d0,
+	0x2100, 0x080c, 0x2694, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314,
+	0x92e0, 0x1d80, 0x2c04, 0xd384, 0x0120, 0x9084, 0xff00, 0x8007,
+	0x0010, 0x9084, 0x00ff, 0x9116, 0x0138, 0x9096, 0x00ff, 0x0110,
+	0x8318, 0x0c68, 0x9085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa91e,
+	0x0106, 0x0036, 0x2019, 0x0029, 0x00c1, 0x003e, 0x010e, 0x090c,
+	0xa93a, 0x9180, 0x1000, 0x2004, 0x9065, 0x0158, 0x0016, 0x00c6,
+	0x2061, 0x1b34, 0x001e, 0x6112, 0x080c, 0x3240, 0x001e, 0x080c,
+	0x6657, 0x012e, 0x00ce, 0x001e, 0x0005, 0x0016, 0x0026, 0x2110,
+	0x080c, 0xa404, 0x080c, 0xe7ac, 0x002e, 0x001e, 0x0005, 0x2001,
+	0x1837, 0x2004, 0xd0cc, 0x0005, 0x00c6, 0x00b6, 0x080c, 0x753d,
+	0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9, 0x0782, 0x080c, 0x753d,
+	0x1110, 0x900e, 0x0010, 0x2009, 0x007e, 0x9180, 0x1000, 0x2004,
+	0x905d, 0x0130, 0x86ff, 0x0110, 0xb800, 0xd0bc, 0x090c, 0x6657,
+	0x8108, 0x1f04, 0x338d, 0x2061, 0x1800, 0x607f, 0x0000, 0x6080,
+	0x9084, 0x00ff, 0x6082, 0x60b3, 0x0000, 0x00be, 0x00ce, 0x0005,
+	0x2001, 0x1869, 0x2004, 0xd0bc, 0x0005, 0x2011, 0x1848, 0x2214,
+	0xd2ec, 0x0005, 0x0026, 0x2011, 0x1867, 0x2214, 0xd2dc, 0x002e,
+	0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc,
+	0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1,
+	0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6,
+	0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4,
+	0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa,
+	0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d,
+	0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282,
+	0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074,
+	0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a,
+	0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559,
+	0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d,
+	0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043,
+	0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932,
+	0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227,
+	0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18,
+	0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000,
+	0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000,
+	0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00,
+	0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900,
+	0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200,
+	0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00,
+	0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600,
+	0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00,
+	0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900,
+	0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000,
+	0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000,
+	0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x2071, 0x189e, 0x7003, 0x0002, 0x9006, 0x7016, 0x701a,
+	0x704a, 0x704e, 0x700e, 0x7042, 0x7046, 0x703b, 0x18ba, 0x703f,
+	0x18ba, 0x7007, 0x0001, 0x080c, 0x1060, 0x090c, 0x0d7d, 0x2900,
+	0x706a, 0xa867, 0x0002, 0xa8ab, 0xdcb0, 0x080c, 0x1060, 0x090c,
+	0x0d7d, 0x2900, 0x706e, 0xa867, 0x0002, 0xa8ab, 0xdcb0, 0x0005,
+	0x2071, 0x189e, 0x7004, 0x0002, 0x34e8, 0x34e9, 0x34fc, 0x3510,
+	0x0005, 0x1004, 0x34f9, 0x0e04, 0x34f9, 0x2079, 0x0000, 0x0126,
+	0x2091, 0x8000, 0x700c, 0x9005, 0x1128, 0x700f, 0x0001, 0x012e,
+	0x0468, 0x0005, 0x012e, 0x0ce8, 0x2079, 0x0000, 0x2061, 0x18b8,
+	0x2c4c, 0xa86c, 0x908e, 0x0100, 0x0128, 0x9086, 0x0200, 0x0904,
+	0x35e4, 0x0005, 0x7018, 0x2048, 0x2061, 0x1800, 0x701c, 0x0807,
+	0x7014, 0x2048, 0xa864, 0x9094, 0x00ff, 0x9296, 0x0029, 0x1120,
+	0xaa78, 0xd2fc, 0x0128, 0x0005, 0x9086, 0x0103, 0x0108, 0x0005,
+	0x2079, 0x0000, 0x2061, 0x1800, 0x701c, 0x0807, 0x2061, 0x1800,
+	0x7880, 0x908a, 0x0040, 0x1210, 0x61d0, 0x0042, 0x2100, 0x908a,
+	0x003f, 0x1a04, 0x35e1, 0x61d0, 0x0804, 0x3576, 0x35b8, 0x35f0,
+	0x35e1, 0x35fa, 0x3604, 0x360a, 0x360e, 0x361e, 0x3622, 0x3638,
+	0x363e, 0x3644, 0x364f, 0x365a, 0x3669, 0x3678, 0x3686, 0x369d,
+	0x36b8, 0x35e1, 0x3761, 0x379f, 0x3844, 0x3855, 0x3878, 0x35e1,
+	0x35e1, 0x35e1, 0x38b0, 0x38d0, 0x38d9, 0x3905, 0x390b, 0x35e1,
+	0x3951, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x395c, 0x3965,
+	0x396d, 0x396f, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1,
+	0x399f, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x39bc, 0x3a26,
+	0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x0002, 0x3a50,
+	0x3a53, 0x3ab2, 0x3acb, 0x3afb, 0x3d9d, 0x35e1, 0x52f4, 0x35e1,
+	0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x35e1, 0x3638,
+	0x363e, 0x428c, 0x5762, 0x42aa, 0x5383, 0x53d4, 0x54df, 0x35e1,
+	0x5541, 0x557d, 0x55ae, 0x56be, 0x55db, 0x563e, 0x35e1, 0x42ae,
+	0x4463, 0x4479, 0x449e, 0x4503, 0x4577, 0x4597, 0x460e, 0x466a,
+	0x46c6, 0x46c9, 0x46ee, 0x4760, 0x47ca, 0x47d2, 0x4904, 0x4a7c,
+	0x4ab0, 0x4d14, 0x35e1, 0x4d32, 0x4dd8, 0x4eba, 0x4f14, 0x35e1,
+	0x4fcb, 0x35e1, 0x5033, 0x504e, 0x47d2, 0x5294, 0x714c, 0x0000,
+	0x2021, 0x4000, 0x080c, 0x4b2e, 0x0126, 0x2091, 0x8000, 0x0e04,
+	0x35c2, 0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486, 0x4000, 0x0118,
+	0x7833, 0x0011, 0x0010, 0x7833, 0x0010, 0x7c82, 0x7986, 0x7a8a,
+	0x7b8e, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x11ee, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f, 0x0000, 0x012e,
+	0x0005, 0x2021, 0x4001, 0x08b0, 0x2021, 0x4002, 0x0898, 0x2021,
+	0x4003, 0x0880, 0x2021, 0x4005, 0x0868, 0x2021, 0x4006, 0x0850,
+	0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, 0x7884, 0x7990,
+	0x0804, 0x4b3b, 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c,
+	0x7884, 0x7990, 0x0804, 0x4b3e, 0x7984, 0x7888, 0x2114, 0x200a,
+	0x0804, 0x35b8, 0x7984, 0x2114, 0x0804, 0x35b8, 0x20e1, 0x0000,
+	0x2099, 0x0021, 0x20e9, 0x0000, 0x20a1, 0x0021, 0x20a9, 0x001f,
+	0x4003, 0x7984, 0x7a88, 0x7b8c, 0x0804, 0x35b8, 0x7884, 0x2060,
+	0x0804, 0x366b, 0x2009, 0x0003, 0x2011, 0x0003, 0x2019, 0x0008,
+	0x789b, 0x0137, 0x7893, 0xffff, 0x2001, 0x188f, 0x2004, 0x9005,
+	0x0118, 0x7896, 0x0804, 0x35b8, 0x7897, 0x0001, 0x0804, 0x35b8,
+	0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0804, 0x35f4, 0x2039, 0x0001,
+	0x7d98, 0x7c9c, 0x0804, 0x35fe, 0x79a0, 0x9182, 0x0040, 0x0210,
+	0x0804, 0x35ed, 0x2138, 0x7d98, 0x7c9c, 0x0804, 0x35f4, 0x79a0,
+	0x9182, 0x0040, 0x0210, 0x0804, 0x35ed, 0x2138, 0x7d98, 0x7c9c,
+	0x0804, 0x35fe, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x35ed,
+	0x21e8, 0x7984, 0x7888, 0x20a9, 0x0001, 0x21a0, 0x4004, 0x0804,
+	0x35b8, 0x2061, 0x0800, 0xe10c, 0x9006, 0x2c15, 0x9200, 0x8c60,
+	0x8109, 0x1dd8, 0x2010, 0x9005, 0x0904, 0x35b8, 0x0804, 0x35e7,
+	0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x35ed, 0x21e0, 0x20a9,
+	0x0001, 0x7984, 0x2198, 0x4012, 0x0804, 0x35b8, 0x2069, 0x1847,
+	0x7884, 0x7990, 0x911a, 0x1a04, 0x35ed, 0x8019, 0x0904, 0x35ed,
+	0x684a, 0x6942, 0x788c, 0x6852, 0x7888, 0x6856, 0x9006, 0x685a,
+	0x685e, 0x080c, 0x7871, 0x0804, 0x35b8, 0x2069, 0x1847, 0x7884,
+	0x7994, 0x911a, 0x1a04, 0x35ed, 0x8019, 0x0904, 0x35ed, 0x684e,
+	0x6946, 0x788c, 0x6862, 0x7888, 0x6866, 0x9006, 0x686a, 0x686e,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x6b43, 0x012e, 0x0804, 0x35b8,
+	0x902e, 0x2520, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35ea,
+	0x7984, 0x7b88, 0x7a8c, 0x20a9, 0x0005, 0x20e9, 0x0001, 0x20a1,
+	0x18a6, 0x4101, 0x080c, 0x4af2, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x35ea, 0x2009, 0x0020, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c,
+	0x4b3b, 0x701f, 0x36dc, 0x0005, 0xa864, 0x2008, 0x9084, 0x00ff,
+	0x9096, 0x0011, 0x0168, 0x9096, 0x0019, 0x0150, 0x9096, 0x0015,
+	0x0138, 0x9096, 0x0048, 0x0120, 0x9096, 0x0029, 0x1904, 0x35ea,
+	0x810f, 0x918c, 0x00ff, 0x0904, 0x35ea, 0x7112, 0x7010, 0x8001,
+	0x0560, 0x7012, 0x080c, 0x4af2, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x35ea, 0x2009, 0x0020, 0x7068, 0x2040, 0xa28c, 0xa390, 0xa494,
+	0xa598, 0x9290, 0x0040, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9,
+	0x0000, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c, 0x4b3b, 0x701f,
+	0x371a, 0x0005, 0xa864, 0x9084, 0x00ff, 0x9096, 0x0002, 0x0120,
+	0x9096, 0x000a, 0x1904, 0x35ea, 0x0888, 0x7014, 0x2048, 0xa868,
+	0xc0fd, 0xa86a, 0xa864, 0x9084, 0x00ff, 0x9096, 0x0029, 0x1160,
+	0xc2fd, 0xaa7a, 0x080c, 0x61ff, 0x0150, 0x0126, 0x2091, 0x8000,
+	0xa87a, 0xa982, 0x012e, 0x0050, 0x080c, 0x652f, 0x1128, 0x7007,
+	0x0003, 0x701f, 0x3746, 0x0005, 0x080c, 0x7022, 0x0126, 0x2091,
+	0x8000, 0x20a9, 0x0005, 0x20e1, 0x0001, 0x2099, 0x18a6, 0x400a,
+	0x2100, 0x9210, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9, 0x0000,
+	0xa85c, 0x9080, 0x0019, 0x2009, 0x0020, 0x012e, 0xaf60, 0x0804,
+	0x4b3e, 0x2091, 0x8000, 0x7837, 0x4000, 0x7833, 0x0010, 0x7883,
+	0x4000, 0x7887, 0x4953, 0x788b, 0x5020, 0x788f, 0x2020, 0x2009,
+	0x017f, 0x2104, 0x7892, 0x3f00, 0x7896, 0x2061, 0x0100, 0x6200,
+	0x2061, 0x0200, 0x603c, 0x8007, 0x9205, 0x789a, 0x2009, 0x04fd,
+	0x2104, 0x789e, 0x2091, 0x5000, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x0180, 0x2001, 0x1a21, 0x2004, 0x9005, 0x0128,
+	0x2001, 0x008b, 0x2004, 0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003,
+	0x0002, 0x2003, 0x1001, 0x2071, 0x0080, 0x0804, 0x0427, 0x81ff,
+	0x1904, 0x35ea, 0x7984, 0x080c, 0x6693, 0x1904, 0x35ed, 0x7e98,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04, 0x35ed, 0x7c88, 0x7d8c,
+	0x080c, 0x68c9, 0x080c, 0x6856, 0x1518, 0x2061, 0x1ddc, 0x0126,
+	0x2091, 0x8000, 0x6000, 0x9086, 0x0000, 0x0148, 0x6014, 0x904d,
+	0x0130, 0xa86c, 0x9406, 0x1118, 0xa870, 0x9506, 0x0150, 0x012e,
+	0x9ce0, 0x001c, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1a04, 0x35ea,
+	0x0c30, 0x080c, 0xc566, 0x012e, 0x0904, 0x35ea, 0x0804, 0x35b8,
+	0x900e, 0x2001, 0x0005, 0x080c, 0x7022, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xcc85, 0x080c, 0x6dee, 0x012e, 0x0804, 0x35b8, 0x00a6,
+	0x2950, 0xb198, 0x080c, 0x6693, 0x1904, 0x3831, 0xb6a4, 0x9684,
+	0x3fff, 0x9082, 0x4000, 0x16e8, 0xb49c, 0xb5a0, 0x080c, 0x68c9,
+	0x080c, 0x6873, 0x1520, 0x2061, 0x1ddc, 0x0126, 0x2091, 0x8000,
+	0x6000, 0x9086, 0x0000, 0x0148, 0x6014, 0x904d, 0x0130, 0xa86c,
+	0x9406, 0x1118, 0xa870, 0x9506, 0x0158, 0x012e, 0x9ce0, 0x001c,
+	0x2001, 0x181a, 0x2004, 0x9c02, 0x2009, 0x000d, 0x12b0, 0x0c28,
+	0x080c, 0xc566, 0x012e, 0x2009, 0x0003, 0x0178, 0x00e0, 0x900e,
+	0x2001, 0x0005, 0x080c, 0x7022, 0x0126, 0x2091, 0x8000, 0x080c,
+	0xcc85, 0x080c, 0x6de2, 0x012e, 0x0070, 0xb097, 0x4005, 0xb19a,
+	0x0010, 0xb097, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030,
+	0x2a48, 0x00ae, 0x0005, 0xb097, 0x4000, 0x9006, 0x918d, 0x0001,
+	0x2008, 0x2a48, 0x00ae, 0x0005, 0x81ff, 0x1904, 0x35ea, 0x080c,
+	0x4b09, 0x0904, 0x35ed, 0x080c, 0x675a, 0x0904, 0x35ea, 0x080c,
+	0x68cf, 0x0904, 0x35ea, 0x0804, 0x458e, 0x81ff, 0x1904, 0x35ea,
+	0x080c, 0x4b25, 0x0904, 0x35ed, 0x080c, 0x695d, 0x0904, 0x35ea,
+	0x2019, 0x0005, 0x79a8, 0x080c, 0x68ea, 0x0904, 0x35ea, 0x7888,
+	0x908a, 0x1000, 0x1a04, 0x35ed, 0x8003, 0x800b, 0x810b, 0x9108,
+	0x080c, 0x86d6, 0x7984, 0xd184, 0x1904, 0x35b8, 0x0804, 0x458e,
+	0x0126, 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0450,
+	0x2029, 0x07ff, 0x645c, 0x2400, 0x9506, 0x01f8, 0x2508, 0x080c,
+	0x6693, 0x11d8, 0x080c, 0x695d, 0x1128, 0x2009, 0x0002, 0x62c0,
+	0x2518, 0x00c0, 0x2019, 0x0004, 0x900e, 0x080c, 0x68ea, 0x1118,
+	0x2009, 0x0006, 0x0078, 0x7884, 0x908a, 0x1000, 0x1270, 0x8003,
+	0x800b, 0x810b, 0x9108, 0x080c, 0x86d6, 0x8529, 0x1ae0, 0x012e,
+	0x0804, 0x35b8, 0x012e, 0x0804, 0x35ea, 0x012e, 0x0804, 0x35ed,
+	0x080c, 0x4b09, 0x0904, 0x35ed, 0x080c, 0x675a, 0x0904, 0x35ea,
+	0x080c, 0xa91e, 0xbaa0, 0x2019, 0x0005, 0x00c6, 0x9066, 0x080c,
+	0x943d, 0x0076, 0x903e, 0x080c, 0x9306, 0x900e, 0x080c, 0xe167,
+	0x007e, 0x00ce, 0x080c, 0xa93a, 0x080c, 0x68c9, 0x0804, 0x35b8,
+	0x080c, 0x4b09, 0x0904, 0x35ed, 0x080c, 0x68c9, 0x2208, 0x0804,
+	0x35b8, 0x0156, 0x00d6, 0x00e6, 0x00c6, 0x2069, 0x1910, 0x6810,
+	0x6914, 0x910a, 0x1208, 0x900e, 0x6816, 0x9016, 0x901e, 0x2071,
+	0x19e6, 0x7028, 0x9065, 0x0118, 0x8210, 0x600c, 0x0cd8, 0x2300,
+	0x9218, 0x00ce, 0x00ee, 0x00de, 0x015e, 0x0804, 0x35b8, 0x00f6,
+	0x0016, 0x907d, 0x0138, 0x9006, 0x8000, 0x2f0c, 0x81ff, 0x0110,
+	0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069, 0x1910, 0x6910,
+	0x62bc, 0x0804, 0x35b8, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x35ea, 0x0126, 0x2091, 0x8000, 0x080c, 0x5752, 0x0128, 0x2009,
+	0x0007, 0x012e, 0x0804, 0x35ea, 0x012e, 0x615c, 0x9190, 0x33b9,
+	0x2215, 0x9294, 0x00ff, 0x637c, 0x83ff, 0x0108, 0x6280, 0x67dc,
+	0x97c4, 0x000a, 0x98c6, 0x000a, 0x1118, 0x2031, 0x0001, 0x00e8,
+	0x97c4, 0x0022, 0x98c6, 0x0022, 0x1118, 0x2031, 0x0003, 0x00a8,
+	0x97c4, 0x0012, 0x98c6, 0x0012, 0x1118, 0x2031, 0x0002, 0x0068,
+	0x080c, 0x753d, 0x1118, 0x2031, 0x0004, 0x0038, 0xd79c, 0x0120,
+	0x2009, 0x0005, 0x0804, 0x35ea, 0x9036, 0x7e9a, 0x7f9e, 0x0804,
+	0x35b8, 0x614c, 0x6250, 0x2019, 0x1985, 0x231c, 0x2001, 0x1986,
+	0x2004, 0x789a, 0x0804, 0x35b8, 0x0126, 0x2091, 0x8000, 0x6138,
+	0x623c, 0x6340, 0x012e, 0x0804, 0x35b8, 0x080c, 0x4b25, 0x0904,
+	0x35ed, 0xba44, 0xbb38, 0x0804, 0x35b8, 0x080c, 0x0d7d, 0x080c,
+	0x4b25, 0x2110, 0x0904, 0x35ed, 0xb804, 0x908c, 0x00ff, 0x918e,
+	0x0006, 0x0140, 0x9084, 0xff00, 0x9086, 0x0600, 0x2009, 0x0009,
+	0x1904, 0x35ea, 0x0126, 0x2091, 0x8000, 0x2019, 0x0005, 0x00c6,
+	0x9066, 0x080c, 0xa91e, 0x080c, 0xa404, 0x080c, 0x943d, 0x0076,
+	0x903e, 0x080c, 0x9306, 0x900e, 0x080c, 0xe167, 0x007e, 0x00ce,
+	0x080c, 0xa93a, 0xb807, 0x0407, 0x012e, 0x0804, 0x35b8, 0x614c,
+	0x6250, 0x7884, 0x604e, 0x7b88, 0x6352, 0x2069, 0x1847, 0x831f,
+	0x9305, 0x6816, 0x788c, 0x2069, 0x1985, 0x2d1c, 0x206a, 0x7e98,
+	0x9682, 0x0014, 0x1210, 0x2031, 0x07d0, 0x2069, 0x1986, 0x2d04,
+	0x266a, 0x789a, 0x0804, 0x35b8, 0x0126, 0x2091, 0x8000, 0x6138,
+	0x7884, 0x603a, 0x910e, 0xd1b4, 0x190c, 0x0ed9, 0xd0c4, 0x01a8,
+	0x00d6, 0x78a8, 0x2009, 0x199c, 0x200a, 0x78ac, 0x2011, 0x199d,
+	0x2012, 0x2069, 0x0100, 0x6838, 0x9086, 0x0007, 0x1118, 0x2214,
+	0x6a5a, 0x0010, 0x210c, 0x695a, 0x00de, 0x2011, 0x0116, 0x220c,
+	0x7888, 0xd08c, 0x0118, 0x918d, 0x0040, 0x0010, 0x918c, 0xff7f,
+	0x2112, 0x603c, 0x7988, 0x613e, 0x6140, 0x910d, 0x788c, 0x6042,
+	0x7a88, 0x9294, 0x1000, 0x9205, 0x910e, 0xd1e4, 0x190c, 0x0ef4,
+	0x9084, 0x0020, 0x0130, 0x78b4, 0x6046, 0x9084, 0x0001, 0x090c,
+	0x428c, 0x6040, 0xd0cc, 0x0120, 0x78b0, 0x2011, 0x0114, 0x2012,
+	0x012e, 0x0804, 0x35b8, 0x00f6, 0x2079, 0x1800, 0x7a38, 0xa898,
+	0x9084, 0xfebf, 0x9215, 0xa89c, 0x9084, 0xfebf, 0x8002, 0x9214,
+	0x7838, 0x9084, 0x0140, 0x9215, 0x7a3a, 0xa897, 0x4000, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0000, 0x00fe, 0x0005, 0x7898, 0x9005,
+	0x01a8, 0x7888, 0x9025, 0x0904, 0x35ed, 0x788c, 0x902d, 0x0904,
+	0x35ed, 0x900e, 0x080c, 0x6693, 0x1120, 0xba44, 0xbb38, 0xbc46,
+	0xbd3a, 0x9186, 0x07ff, 0x0190, 0x8108, 0x0ca0, 0x080c, 0x4b25,
+	0x0904, 0x35ed, 0x7888, 0x900d, 0x0904, 0x35ed, 0x788c, 0x9005,
+	0x0904, 0x35ed, 0xba44, 0xb946, 0xbb38, 0xb83a, 0x0804, 0x35b8,
+	0x2011, 0xbc09, 0x0010, 0x2011, 0xbc05, 0x080c, 0x5752, 0x1904,
+	0x35ea, 0x00c6, 0x2061, 0x0100, 0x7984, 0x9186, 0x00ff, 0x1130,
+	0x2001, 0x1818, 0x2004, 0x9085, 0xff00, 0x0088, 0x9182, 0x007f,
+	0x16e0, 0x9188, 0x33b9, 0x210d, 0x918c, 0x00ff, 0x2001, 0x1818,
+	0x2004, 0x0026, 0x9116, 0x002e, 0x0580, 0x810f, 0x9105, 0x0126,
+	0x2091, 0x8000, 0x0006, 0x080c, 0xac5a, 0x000e, 0x0510, 0x602e,
+	0x620a, 0x7984, 0x00b6, 0x080c, 0x6638, 0x2b08, 0x00be, 0x1500,
+	0x6112, 0x6023, 0x0001, 0x080c, 0x4af2, 0x01d0, 0x9006, 0xa866,
+	0x7007, 0x0003, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x701f, 0x3aab,
+	0x2900, 0x6016, 0x2009, 0x0032, 0x080c, 0xad4d, 0x012e, 0x00ce,
+	0x0005, 0x012e, 0x00ce, 0x0804, 0x35ea, 0x00ce, 0x0804, 0x35ed,
+	0x080c, 0xacb0, 0x0cb0, 0xa830, 0x9086, 0x0100, 0x0904, 0x35ea,
+	0x0804, 0x35b8, 0x2061, 0x1a6e, 0x0126, 0x2091, 0x8000, 0x6000,
+	0xd084, 0x0170, 0x6104, 0x6208, 0x2061, 0x1800, 0x6354, 0x6074,
+	0x789a, 0x60c0, 0x789e, 0x60bc, 0x78aa, 0x012e, 0x0804, 0x35b8,
+	0x900e, 0x2110, 0x0c88, 0x81ff, 0x1904, 0x35ea, 0x080c, 0x753d,
+	0x0904, 0x35ea, 0x0126, 0x2091, 0x8000, 0x6254, 0x6074, 0x9202,
+	0x0248, 0x9085, 0x0001, 0x080c, 0x26ca, 0x080c, 0x5971, 0x012e,
+	0x0804, 0x35b8, 0x012e, 0x0804, 0x35ed, 0x0006, 0x0016, 0x00c6,
+	0x00e6, 0x2001, 0x19a8, 0x2070, 0x2061, 0x1847, 0x6008, 0x2072,
+	0x900e, 0x2011, 0x1400, 0x080c, 0x91f8, 0x7206, 0x00ee, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0128,
+	0x012e, 0x2021, 0x400b, 0x0804, 0x35ba, 0x7884, 0xd0fc, 0x0148,
+	0x2001, 0x002a, 0x2004, 0x9082, 0x00e1, 0x0288, 0x012e, 0x0804,
+	0x35ed, 0x2001, 0x002a, 0x2004, 0x2069, 0x1847, 0x6908, 0x9102,
+	0x1230, 0x012e, 0x0804, 0x35ed, 0x012e, 0x0804, 0x35ea, 0x080c,
+	0xabe2, 0x0dd0, 0x7884, 0xd0fc, 0x0904, 0x3b76, 0x00c6, 0x080c,
+	0x4af2, 0x00ce, 0x0d88, 0xa867, 0x0000, 0x7884, 0xa80a, 0x7898,
+	0xa80e, 0x789c, 0xa812, 0x2001, 0x002e, 0x2004, 0xa81a, 0x2001,
+	0x002f, 0x2004, 0xa81e, 0x2001, 0x0030, 0x2004, 0xa822, 0x2001,
+	0x0031, 0x2004, 0xa826, 0x2001, 0x0034, 0x2004, 0xa82a, 0x2001,
+	0x0035, 0x2004, 0xa82e, 0x2001, 0x002a, 0x2004, 0x9080, 0x0003,
+	0x9084, 0x00fc, 0x8004, 0xa816, 0x080c, 0x3d00, 0x0928, 0x7014,
+	0x2048, 0xad2c, 0xac28, 0xab1c, 0xaa18, 0xa930, 0xa808, 0xd0b4,
+	0x1120, 0x2029, 0x0000, 0x2021, 0x0000, 0x8906, 0x8006, 0x8007,
+	0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x080c, 0x4b3b,
+	0x701f, 0x3c3d, 0x7023, 0x0001, 0x012e, 0x0005, 0x080c, 0xa91e,
+	0x0046, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, 0x00e6,
+	0x00f6, 0x080c, 0x3ae5, 0x2001, 0x199e, 0x2003, 0x0000, 0x2021,
+	0x000a, 0x2061, 0x0100, 0x6104, 0x0016, 0x60bb, 0x0000, 0x60bf,
+	0x32e1, 0x60bf, 0x0012, 0x080c, 0x3d6f, 0x080c, 0x3d2e, 0x00f6,
+	0x00e6, 0x0086, 0x2940, 0x2071, 0x19e6, 0x2079, 0x0090, 0x00d6,
+	0x2069, 0x0000, 0x6884, 0xd0b4, 0x0140, 0x2001, 0x0035, 0x2004,
+	0x780e, 0x2001, 0x0034, 0x2004, 0x780a, 0x00de, 0x2011, 0x0001,
+	0x080c, 0x40d0, 0x008e, 0x00ee, 0x00fe, 0x080c, 0x3ffd, 0x080c,
+	0x3f2a, 0x05b8, 0x2001, 0x020b, 0x2004, 0x9084, 0x0140, 0x1db8,
+	0x080c, 0x4144, 0x00f6, 0x2079, 0x0300, 0x78bc, 0x00fe, 0x908c,
+	0x0070, 0x1560, 0x2071, 0x0200, 0x7037, 0x0000, 0x7050, 0x9084,
+	0xff00, 0x9086, 0x3200, 0x1510, 0x7037, 0x0001, 0x7050, 0x9084,
+	0xff00, 0x9086, 0xe100, 0x11d0, 0x7037, 0x0000, 0x7054, 0x7037,
+	0x0000, 0x715c, 0x9106, 0x1190, 0x2001, 0x1820, 0x2004, 0x9106,
+	0x1168, 0x00c6, 0x2061, 0x0100, 0x6024, 0x9084, 0x1e00, 0x00ce,
+	0x0138, 0x080c, 0x3f34, 0x080c, 0x3d29, 0x0058, 0x080c, 0x3d29,
+	0x080c, 0x4068, 0x080c, 0x3ff3, 0x2001, 0x020b, 0x2004, 0xd0e4,
+	0x0dd8, 0x2001, 0x032a, 0x2003, 0x0004, 0x2061, 0x0100, 0x6027,
+	0x0002, 0x001e, 0x6106, 0x2011, 0x020d, 0x2013, 0x0020, 0x60bb,
+	0x0000, 0x60bf, 0x0108, 0x60bf, 0x0012, 0x2001, 0x0004, 0x200c,
+	0x918c, 0xfffd, 0x2102, 0x080c, 0x1340, 0x2009, 0x0028, 0x080c,
+	0x220a, 0x2001, 0x0227, 0x200c, 0x2102, 0x080c, 0xa93a, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x004e,
+	0x2001, 0x199e, 0x2004, 0x9005, 0x1118, 0x012e, 0x0804, 0x35b8,
+	0x012e, 0x2021, 0x400c, 0x0804, 0x35ba, 0x0016, 0x0026, 0x0036,
+	0x0046, 0x0056, 0x0076, 0x0086, 0x0096, 0x00d6, 0x0156, 0x7014,
+	0x2048, 0x7020, 0x20a8, 0x8000, 0x7022, 0xa804, 0x9005, 0x0904,
+	0x3c99, 0x2048, 0x1f04, 0x3c4d, 0x7068, 0x2040, 0xa28c, 0xa390,
+	0xa494, 0xa598, 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029, 0x0000,
+	0x2021, 0x0000, 0x0096, 0x7014, 0x2048, 0xa864, 0x009e, 0x9086,
+	0x0103, 0x0170, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x001b, 0x080c, 0x4b3b, 0x701f, 0x3c3d, 0x00b0,
+	0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080,
+	0x001b, 0x21a8, 0x27e0, 0x2098, 0x27e8, 0x20a0, 0x0006, 0x080c,
+	0x0fc4, 0x000e, 0x080c, 0x4b3e, 0x701f, 0x3c3d, 0x015e, 0x00de,
+	0x009e, 0x008e, 0x007e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x7014, 0x2048, 0xa864, 0x9086, 0x0103, 0x1118, 0x701f,
+	0x3cfe, 0x0450, 0x7014, 0x2048, 0xa868, 0xc0fd, 0xa86a, 0x2009,
+	0x007f, 0x080c, 0x6632, 0x0110, 0x9006, 0x0030, 0xb813, 0x00ff,
+	0xb817, 0xfffd, 0x080c, 0xce64, 0x015e, 0x00de, 0x009e, 0x008e,
+	0x007e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0904, 0x35ea,
+	0x0016, 0x0026, 0x0036, 0x0046, 0x0056, 0x0076, 0x0086, 0x0096,
+	0x00d6, 0x0156, 0x701f, 0x3cd0, 0x7007, 0x0003, 0x0804, 0x3c8e,
+	0xa830, 0x9086, 0x0100, 0x2021, 0x400c, 0x0904, 0x35ba, 0x0076,
+	0xad10, 0xac0c, 0xab24, 0xaa20, 0xa930, 0xa808, 0xd0b4, 0x1120,
+	0x2029, 0x0000, 0x2021, 0x0000, 0x8906, 0x8006, 0x8007, 0x90bc,
+	0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x21a8, 0x27e0, 0x2098,
+	0x27e8, 0x20a0, 0x0006, 0x080c, 0x0fc4, 0x000e, 0x080c, 0x4b3e,
+	0x007e, 0x701f, 0x3c3d, 0x7023, 0x0001, 0x0005, 0x0804, 0x35b8,
+	0x0156, 0x00c6, 0xa814, 0x908a, 0x001e, 0x0218, 0xa833, 0x001e,
+	0x0010, 0xa832, 0x0078, 0x81ff, 0x0168, 0x0016, 0x080c, 0x4af2,
+	0x001e, 0x0130, 0xa800, 0x2040, 0xa008, 0xa80a, 0x2100, 0x0c58,
+	0x9006, 0x0010, 0x9085, 0x0001, 0x00ce, 0x015e, 0x0005, 0x0006,
+	0x00f6, 0x2079, 0x0000, 0x7880, 0x9086, 0x0044, 0x00fe, 0x000e,
+	0x0005, 0x2001, 0x199e, 0x2003, 0x0001, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x2061, 0x0200, 0x2001, 0x19a9, 0x2004, 0x601a, 0x2061,
+	0x0100, 0x2001, 0x19a8, 0x2004, 0x60ce, 0x6104, 0xc1ac, 0x6106,
+	0x080c, 0x4af2, 0xa813, 0x0019, 0xa817, 0x0001, 0x2900, 0xa85a,
+	0x2001, 0x002e, 0x2004, 0xa866, 0x2001, 0x002f, 0x2004, 0xa86a,
+	0x2061, 0x0090, 0x2079, 0x0100, 0x2001, 0x19a8, 0x2004, 0x6036,
+	0x2009, 0x0040, 0x080c, 0x220a, 0x2001, 0x002a, 0x2004, 0x9084,
+	0xfff8, 0xa86e, 0x601a, 0xa873, 0x0000, 0x601f, 0x0000, 0x78ca,
+	0x9006, 0x600a, 0x600e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6,
+	0x080c, 0x4af2, 0x2940, 0xa013, 0x0019, 0xa017, 0x0001, 0x2800,
+	0xa05a, 0x2001, 0x0030, 0x2004, 0xa866, 0x2001, 0x0031, 0x2004,
+	0xa86a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0xa86e, 0xa873,
+	0x0000, 0x2001, 0x032a, 0x2003, 0x0004, 0x2001, 0x0300, 0x2003,
+	0x0000, 0x2001, 0x020d, 0x2003, 0x0000, 0x2001, 0x0004, 0x200c,
+	0x918d, 0x0002, 0x2102, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x81ff, 0x0148, 0x080c, 0x2a58, 0x1130, 0x9006, 0x080c, 0x29ab,
+	0x9006, 0x080c, 0x298e, 0x7884, 0x9084, 0x0007, 0x0002, 0x3dba,
+	0x3dbb, 0x3dbc, 0x3db7, 0x3db7, 0x3db7, 0x3db7, 0x3db7, 0x012e,
+	0x0804, 0x35ed, 0x0ce0, 0x0cd8, 0x080c, 0x753d, 0x1128, 0x012e,
+	0x2009, 0x0016, 0x0804, 0x35ea, 0x81ff, 0x0128, 0x012e, 0x2021,
+	0x400b, 0x0804, 0x35ba, 0x080c, 0xa91e, 0x0086, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x080c, 0x3ae5, 0x2009,
+	0x0101, 0x210c, 0x0016, 0x7ec8, 0x7dcc, 0x9006, 0x2068, 0x2060,
+	0x2058, 0x080c, 0x421f, 0x080c, 0x416f, 0x903e, 0x2720, 0x00f6,
+	0x00e6, 0x0086, 0x2940, 0x2071, 0x19e6, 0x2079, 0x0090, 0x00d6,
+	0x2069, 0x0000, 0x6884, 0xd0b4, 0x0120, 0x68d4, 0x780e, 0x68d0,
+	0x780a, 0x00de, 0x2011, 0x0001, 0x080c, 0x40d0, 0x080c, 0x2a60,
+	0x080c, 0x2a60, 0x080c, 0x2a60, 0x080c, 0x2a60, 0x080c, 0x40d0,
+	0x008e, 0x00ee, 0x00fe, 0x080c, 0x3ffd, 0x2009, 0x9c40, 0x8109,
+	0x11b0, 0x080c, 0x3f34, 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd,
+	0x2102, 0x001e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae,
+	0x009e, 0x008e, 0x2009, 0x0017, 0x080c, 0x35ea, 0x0cf8, 0x2001,
+	0x020b, 0x2004, 0x9084, 0x0140, 0x1d10, 0x00f6, 0x2079, 0x0000,
+	0x7884, 0x00fe, 0xd0bc, 0x0178, 0x2001, 0x0201, 0x200c, 0x81ff,
+	0x0150, 0x080c, 0x3fdb, 0x2d00, 0x9c05, 0x9b05, 0x0120, 0x080c,
+	0x3f34, 0x0804, 0x3edd, 0x080c, 0x4144, 0x080c, 0x4068, 0x080c,
+	0x3fbe, 0x080c, 0x3ff3, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd0ac,
+	0x0130, 0x8b58, 0x080c, 0x3f34, 0x00fe, 0x0804, 0x3edd, 0x00fe,
+	0x080c, 0x3f2a, 0x1150, 0x8d68, 0x2001, 0x0032, 0x2602, 0x2001,
+	0x0033, 0x2502, 0x080c, 0x3f34, 0x0080, 0x87ff, 0x0138, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x1908, 0x8739, 0x0038, 0x2001, 0x1a6a,
+	0x2004, 0x9086, 0x0000, 0x1904, 0x3e2d, 0x2001, 0x032f, 0x2003,
+	0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0x9605, 0x0904, 0x3edd,
+	0x7884, 0xd0bc, 0x0128, 0x2d00, 0x9c05, 0x9b05, 0x1904, 0x3edd,
+	0xa013, 0x0019, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, 0xd0ac,
+	0x1148, 0x2001, 0x1a6a, 0x2003, 0x0003, 0x2001, 0x032a, 0x2003,
+	0x0009, 0x0030, 0xa017, 0x0001, 0x78b4, 0x9005, 0x0108, 0xa016,
+	0x2800, 0xa05a, 0x2009, 0x0040, 0x080c, 0x220a, 0x2900, 0xa85a,
+	0xa813, 0x0019, 0x7884, 0xd0a4, 0x1180, 0xa817, 0x0000, 0x00c6,
+	0x20a9, 0x0004, 0x2061, 0x0090, 0x602b, 0x0008, 0x2001, 0x0203,
+	0x2004, 0x1f04, 0x3eb4, 0x00ce, 0x0030, 0xa817, 0x0001, 0x78b0,
+	0x9005, 0x0108, 0xa816, 0x00f6, 0x00c6, 0x2079, 0x0100, 0x2061,
+	0x0090, 0x7827, 0x0002, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0x601a, 0x0006, 0x2001, 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e,
+	0x78ca, 0x00ce, 0x00fe, 0x0804, 0x3de7, 0x001e, 0x00c6, 0x2001,
+	0x032a, 0x2003, 0x0004, 0x2061, 0x0100, 0x6027, 0x0002, 0x6106,
+	0x2011, 0x020d, 0x2013, 0x0020, 0x2001, 0x0004, 0x200c, 0x918c,
+	0xfffd, 0x2102, 0x080c, 0x1340, 0x7884, 0x9084, 0x0003, 0x9086,
+	0x0002, 0x01b0, 0x2009, 0x0028, 0x080c, 0x220a, 0x2001, 0x0227,
+	0x200c, 0x2102, 0x6050, 0x9084, 0xb7ff, 0x080c, 0x2b0a, 0x6052,
+	0x602f, 0x0000, 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010,
+	0x080c, 0xa93a, 0x00ce, 0x2d08, 0x2c10, 0x2b18, 0x2b00, 0x9c05,
+	0x9d05, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e,
+	0x008e, 0x1118, 0x012e, 0x0804, 0x35b8, 0x012e, 0x2021, 0x400c,
+	0x0804, 0x35ba, 0x9085, 0x0001, 0x1d04, 0x3f33, 0x2091, 0x6000,
+	0x8420, 0x9486, 0x0064, 0x0005, 0x2001, 0x0105, 0x2003, 0x0010,
+	0x2001, 0x032a, 0x2003, 0x0004, 0x2001, 0x1a6a, 0x2003, 0x0000,
+	0x0071, 0x2009, 0x0048, 0x080c, 0x220a, 0x2001, 0x0227, 0x2024,
+	0x2402, 0x2001, 0x0109, 0x2003, 0x4000, 0x9026, 0x0005, 0x00f6,
+	0x00e6, 0x2071, 0x19e6, 0x7054, 0x9086, 0x0000, 0x0520, 0x2079,
+	0x0090, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0x9106,
+	0x1120, 0x2009, 0x0040, 0x080c, 0x220a, 0x782c, 0xd0fc, 0x0d88,
+	0x080c, 0x4144, 0x7054, 0x9086, 0x0000, 0x1d58, 0x782b, 0x0004,
+	0x782c, 0xd0ac, 0x1de8, 0x2009, 0x0040, 0x080c, 0x220a, 0x782b,
+	0x0002, 0x7057, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x2079,
+	0x0100, 0x2001, 0x1818, 0x200c, 0x7932, 0x7936, 0x080c, 0x26aa,
+	0x080c, 0x2ad7, 0x080c, 0x2b0a, 0x784b, 0xf7f7, 0x7843, 0x0090,
+	0x7843, 0x0010, 0x7850, 0xc0e5, 0x7852, 0x2019, 0x61a8, 0x7820,
+	0xd09c, 0x0110, 0x8319, 0x1dd8, 0x7850, 0xc0e4, 0x7852, 0x2011,
+	0x0048, 0x080c, 0x2ab4, 0x7843, 0x0040, 0x2019, 0x01f4, 0xa001,
+	0xa001, 0x8319, 0x1de0, 0x2001, 0x0100, 0x080c, 0x2a7a, 0x2011,
+	0x0020, 0x080c, 0x2ab4, 0x7843, 0x0000, 0x9006, 0x080c, 0x2a7a,
+	0x2011, 0x0048, 0x080c, 0x2ab4, 0x00fe, 0x0005, 0x7884, 0xd0ac,
+	0x11c8, 0x00f6, 0x00e6, 0x2071, 0x1a6a, 0x2079, 0x0320, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x0160, 0x7000, 0x9086, 0x0000, 0x1140,
+	0x0051, 0xd0bc, 0x0108, 0x8738, 0x7003, 0x0003, 0x782b, 0x0019,
+	0x00ee, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0300, 0x78bc, 0x00fe,
+	0x908c, 0x0070, 0x0178, 0x2009, 0x0032, 0x260a, 0x2009, 0x0033,
+	0x250a, 0xd0b4, 0x0108, 0x8c60, 0xd0ac, 0x0108, 0x8d68, 0xd0a4,
+	0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200, 0x781c, 0xd084,
+	0x0110, 0x7837, 0x0050, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100,
+	0x2001, 0x19a9, 0x2004, 0x70e2, 0x080c, 0x3d1f, 0x1188, 0x2001,
+	0x1820, 0x2004, 0x2009, 0x181f, 0x210c, 0x918c, 0x00ff, 0x706e,
+	0x716a, 0x7066, 0x918d, 0x3200, 0x7162, 0x7073, 0xe109, 0x0080,
+	0x702c, 0x9085, 0x0002, 0x702e, 0x2009, 0x1818, 0x210c, 0x716e,
+	0x7063, 0x0100, 0x7166, 0x719e, 0x706b, 0x0000, 0x7073, 0x0809,
+	0x7077, 0x0008, 0x7078, 0x9080, 0x0100, 0x707a, 0x7080, 0x8000,
+	0x7082, 0x7087, 0xaaaa, 0x9006, 0x708a, 0x708e, 0x707e, 0x70d6,
+	0x70ab, 0x0036, 0x70af, 0x95d5, 0x7014, 0x9084, 0x1984, 0x9085,
+	0x0092, 0x7016, 0x080c, 0x4144, 0x00f6, 0x2071, 0x1a6a, 0x2079,
+	0x0320, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4, 0x0120, 0x689c,
+	0x780e, 0x6898, 0x780a, 0x00de, 0x2009, 0x03e8, 0x8109, 0x1df0,
+	0x792c, 0xd1fc, 0x0110, 0x782b, 0x0004, 0x2011, 0x0011, 0x080c,
+	0x40d0, 0x2011, 0x0001, 0x080c, 0x40d0, 0x00fe, 0x00ee, 0x0005,
+	0x00f6, 0x00e6, 0x2071, 0x1a6a, 0x2079, 0x0320, 0x792c, 0xd1fc,
+	0x0904, 0x40cd, 0x782b, 0x0002, 0x9026, 0xd19c, 0x1904, 0x40c9,
+	0x7000, 0x0002, 0x40cd, 0x407e, 0x40ae, 0x40c9, 0xd1bc, 0x1170,
+	0xd1dc, 0x1190, 0x8001, 0x7002, 0x2011, 0x0001, 0x080c, 0x40d0,
+	0x0904, 0x40cd, 0x080c, 0x40d0, 0x0804, 0x40cd, 0x00f6, 0x2079,
+	0x0300, 0x78bf, 0x0000, 0x00fe, 0x7810, 0x7914, 0x782b, 0x0004,
+	0x7812, 0x7916, 0x2001, 0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c,
+	0x3fdb, 0x2009, 0x0001, 0x00f6, 0x2079, 0x0300, 0x78b8, 0x00fe,
+	0xd0ec, 0x0110, 0x2009, 0x0011, 0x792a, 0x00f8, 0x8001, 0x7002,
+	0x9184, 0x0880, 0x1140, 0x782c, 0xd0fc, 0x1904, 0x4072, 0x2011,
+	0x0001, 0x00b1, 0x0090, 0xa010, 0x9092, 0x0004, 0x9086, 0x0015,
+	0x1120, 0xa000, 0xa05a, 0x2011, 0x0031, 0xa212, 0xd1dc, 0x1960,
+	0x0828, 0x782b, 0x0004, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005,
+	0xa014, 0x9005, 0x0550, 0x8001, 0x0036, 0x0096, 0xa016, 0xa058,
+	0x2048, 0xa010, 0x2009, 0x0031, 0x911a, 0x831c, 0x831c, 0x938a,
+	0x0007, 0x1a0c, 0x0d7d, 0x9398, 0x40fe, 0x231d, 0x083f, 0x9080,
+	0x0004, 0x7a2a, 0x7100, 0x8108, 0x7102, 0x009e, 0x003e, 0x908a,
+	0x0035, 0x1140, 0x0096, 0xa058, 0x2048, 0xa804, 0xa05a, 0x2001,
+	0x0019, 0x009e, 0xa012, 0x9085, 0x0001, 0x0005, 0x413b, 0x4132,
+	0x4129, 0x4120, 0x4117, 0x410e, 0x4105, 0xa964, 0x7902, 0xa968,
+	0x7906, 0xa96c, 0x7912, 0xa970, 0x7916, 0x0005, 0xa974, 0x7902,
+	0xa978, 0x7906, 0xa97c, 0x7912, 0xa980, 0x7916, 0x0005, 0xa984,
+	0x7902, 0xa988, 0x7906, 0xa98c, 0x7912, 0xa990, 0x7916, 0x0005,
+	0xa994, 0x7902, 0xa998, 0x7906, 0xa99c, 0x7912, 0xa9a0, 0x7916,
+	0x0005, 0xa9a4, 0x7902, 0xa9a8, 0x7906, 0xa9ac, 0x7912, 0xa9b0,
+	0x7916, 0x0005, 0xa9b4, 0x7902, 0xa9b8, 0x7906, 0xa9bc, 0x7912,
+	0xa9c0, 0x7916, 0x0005, 0xa9c4, 0x7902, 0xa9c8, 0x7906, 0xa9cc,
+	0x7912, 0xa9d0, 0x7916, 0x0005, 0x00f6, 0x00e6, 0x0086, 0x2071,
+	0x19e6, 0x2079, 0x0090, 0x792c, 0xd1fc, 0x01e8, 0x782b, 0x0002,
+	0x2940, 0x9026, 0x7054, 0x0002, 0x416b, 0x4157, 0x4162, 0x8001,
+	0x7056, 0xd19c, 0x1180, 0x2011, 0x0001, 0x080c, 0x40d0, 0x190c,
+	0x40d0, 0x0048, 0x8001, 0x7056, 0x782c, 0xd0fc, 0x1d38, 0x2011,
+	0x0001, 0x080c, 0x40d0, 0x008e, 0x00ee, 0x00fe, 0x0005, 0x00f6,
+	0x00e6, 0x00c6, 0x0086, 0x2061, 0x0200, 0x2001, 0x19a9, 0x2004,
+	0x601a, 0x2061, 0x0100, 0x2001, 0x19a8, 0x2004, 0x60ce, 0x6104,
+	0xc1ac, 0x6106, 0x2001, 0x002c, 0x2004, 0x9005, 0x0520, 0x2038,
+	0x2001, 0x002e, 0x2024, 0x2001, 0x002f, 0x201c, 0x080c, 0x4af2,
+	0xa813, 0x0019, 0xaf16, 0x2900, 0xa85a, 0x978a, 0x0007, 0x0220,
+	0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0x903e, 0x0096, 0xa858,
+	0x2048, 0xa85c, 0x9080, 0x0019, 0x009e, 0x080c, 0x41e7, 0x1d68,
+	0x2900, 0xa85a, 0x00d0, 0x080c, 0x4af2, 0xa813, 0x0019, 0xa817,
+	0x0001, 0x2900, 0xa85a, 0x2001, 0x002e, 0x2004, 0xa866, 0x2001,
+	0x002f, 0x2004, 0xa86a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0xa86e, 0x2001, 0x002b, 0x2004, 0xa872, 0x2061, 0x0090, 0x2079,
+	0x0100, 0x2001, 0x19a8, 0x2004, 0x6036, 0x2009, 0x0040, 0x080c,
+	0x220a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0x601a, 0x0006,
+	0x2001, 0x002b, 0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, 0x9006,
+	0x600a, 0x600e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6,
+	0x2071, 0x0080, 0xaa60, 0x22e8, 0x20a0, 0x20e1, 0x0000, 0x2099,
+	0x0088, 0x702b, 0x0026, 0x7402, 0x7306, 0x9006, 0x700a, 0x700e,
+	0x810b, 0x810b, 0x21a8, 0x810b, 0x7112, 0x702b, 0x0041, 0x702c,
+	0xd0fc, 0x0de8, 0x702b, 0x0002, 0x702b, 0x0040, 0x4005, 0x7400,
+	0x7304, 0x87ff, 0x0190, 0x0086, 0x0096, 0x2940, 0x0086, 0x080c,
+	0x4af2, 0x008e, 0xa058, 0x00a6, 0x2050, 0x2900, 0xb006, 0xa05a,
+	0x00ae, 0x009e, 0x008e, 0x9085, 0x0001, 0x00ee, 0x0005, 0x00e6,
+	0x2001, 0x002d, 0x2004, 0x9005, 0x0528, 0x2038, 0x2001, 0x0030,
+	0x2024, 0x2001, 0x0031, 0x201c, 0x080c, 0x4af2, 0x2940, 0xa813,
+	0x0019, 0xaf16, 0x2900, 0xa85a, 0x978a, 0x0007, 0x0220, 0x2138,
+	0x2009, 0x0007, 0x0010, 0x2708, 0x903e, 0x0096, 0xa858, 0x2048,
+	0xa85c, 0x9080, 0x0019, 0x009e, 0x080c, 0x41e7, 0x1d68, 0x2900,
+	0xa85a, 0x00d8, 0x080c, 0x4af2, 0x2940, 0xa013, 0x0019, 0xa017,
+	0x0001, 0x2800, 0xa05a, 0x2001, 0x0030, 0x2004, 0xa066, 0x2001,
+	0x0031, 0x2004, 0xa06a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0xa06e, 0x2001, 0x002b, 0x2004, 0xa072, 0x2001, 0x032a, 0x2003,
+	0x0004, 0x7884, 0xd0ac, 0x1180, 0x2001, 0x0101, 0x200c, 0x918d,
+	0x0200, 0x2102, 0xa017, 0x0000, 0x2001, 0x1a6a, 0x2003, 0x0003,
+	0x2001, 0x032a, 0x2003, 0x0009, 0x2001, 0x0300, 0x2003, 0x0000,
+	0x2001, 0x020d, 0x2003, 0x0000, 0x2001, 0x0004, 0x200c, 0x918d,
+	0x0002, 0x2102, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x20a9,
+	0x0007, 0x20a1, 0x1840, 0x20e9, 0x0001, 0x9006, 0x4004, 0x20a9,
+	0x0014, 0x20a1, 0xffec, 0x20e9, 0x0000, 0x9006, 0x4004, 0x2009,
+	0x013c, 0x200a, 0x012e, 0x7880, 0x9086, 0x0052, 0x0108, 0x0005,
+	0x0804, 0x35b8, 0x7d98, 0x7c9c, 0x0804, 0x36ba, 0x080c, 0x753d,
+	0x190c, 0x6057, 0x6040, 0x9084, 0x0020, 0x09b1, 0x2069, 0x1847,
+	0x2d00, 0x2009, 0x0030, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039,
+	0x0001, 0x080c, 0x4b3b, 0x701f, 0x42c6, 0x0005, 0x080c, 0x574d,
+	0x1130, 0x3b00, 0x3a08, 0xc194, 0xc095, 0x20d8, 0x21d0, 0x2069,
+	0x1847, 0x6800, 0x9005, 0x0904, 0x35ed, 0x6804, 0xd0ac, 0x0118,
+	0xd0a4, 0x0904, 0x35ed, 0xd094, 0x00c6, 0x2061, 0x0100, 0x6104,
+	0x0138, 0x6200, 0x9292, 0x0005, 0x0218, 0x918c, 0xffdf, 0x0010,
+	0x918d, 0x0020, 0x6106, 0x00ce, 0xd08c, 0x00c6, 0x2061, 0x0100,
+	0x6104, 0x0118, 0x918d, 0x0010, 0x0010, 0x918c, 0xffef, 0x6106,
+	0x00ce, 0xd084, 0x0158, 0x6a28, 0x928a, 0x007f, 0x1a04, 0x35ed,
+	0x9288, 0x33b9, 0x210d, 0x918c, 0x00ff, 0x6166, 0xd0dc, 0x0130,
+	0x6828, 0x908a, 0x007f, 0x1a04, 0x35ed, 0x605e, 0x6888, 0x9084,
+	0x0030, 0x8004, 0x8004, 0x8004, 0x8004, 0x0006, 0x2009, 0x19b0,
+	0x9080, 0x279d, 0x2005, 0x200a, 0x2008, 0x2001, 0x0018, 0x080c,
+	0xa90f, 0x2009, 0x0390, 0x200b, 0x0400, 0x000e, 0x2009, 0x19b1,
+	0x9080, 0x27a1, 0x2005, 0x200a, 0x6808, 0x908a, 0x0100, 0x0a04,
+	0x35ed, 0x908a, 0x0841, 0x1a04, 0x35ed, 0x9084, 0x0007, 0x1904,
+	0x35ed, 0x680c, 0x9005, 0x0904, 0x35ed, 0x6810, 0x9005, 0x0904,
+	0x35ed, 0x6848, 0x6940, 0x910a, 0x1a04, 0x35ed, 0x8001, 0x0904,
+	0x35ed, 0x684c, 0x6944, 0x910a, 0x1a04, 0x35ed, 0x8001, 0x0904,
+	0x35ed, 0x6814, 0x908c, 0x00ff, 0x614e, 0x8007, 0x9084, 0x00ff,
+	0x6052, 0x080c, 0x7871, 0x080c, 0x6b0f, 0x080c, 0x6b43, 0x6808,
+	0x602a, 0x080c, 0x217c, 0x2009, 0x0170, 0x200b, 0x0080, 0xa001,
+	0xa001, 0x200b, 0x0000, 0x0036, 0x6b08, 0x080c, 0x2704, 0x003e,
+	0x6000, 0x9086, 0x0000, 0x1904, 0x4451, 0x6818, 0x691c, 0x6a20,
+	0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a, 0x621e,
+	0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38, 0x6b3c,
+	0x8007, 0x810f, 0x8217, 0x831f, 0x0010, 0x9084, 0xf0ff, 0x6006,
+	0x610a, 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f, 0x20a9,
+	0x0004, 0x20a1, 0x19b2, 0x20e9, 0x0001, 0x4001, 0x20a9, 0x0004,
+	0x20a1, 0x19cc, 0x20e9, 0x0001, 0x4001, 0x080c, 0x885b, 0x00c6,
+	0x900e, 0x20a9, 0x0001, 0x6b70, 0xd384, 0x01c8, 0x0020, 0x839d,
+	0x12b0, 0x3508, 0x8109, 0x080c, 0x7e33, 0x6878, 0x6016, 0x6874,
+	0x2008, 0x9084, 0xff00, 0x8007, 0x600a, 0x9184, 0x00ff, 0x6006,
+	0x8108, 0x1118, 0x6003, 0x0003, 0x0010, 0x6003, 0x0001, 0x1f04,
+	0x43af, 0x00ce, 0x00c6, 0x2061, 0x199b, 0x6a88, 0x9284, 0xc000,
+	0x2010, 0x9286, 0x0000, 0x1158, 0x2063, 0x0000, 0x2001, 0x0001,
+	0x080c, 0x29ab, 0x2001, 0x0001, 0x080c, 0x298e, 0x0088, 0x9286,
+	0x4000, 0x1148, 0x2063, 0x0001, 0x9006, 0x080c, 0x29ab, 0x9006,
+	0x080c, 0x298e, 0x0028, 0x9286, 0x8000, 0x1d30, 0x2063, 0x0002,
+	0x00ce, 0x00e6, 0x2c70, 0x080c, 0x0ec1, 0x00ee, 0x6888, 0xd0ec,
+	0x0130, 0x2011, 0x0114, 0x2204, 0x9085, 0x0180, 0x2012, 0x6a80,
+	0x9284, 0x0030, 0x9086, 0x0030, 0x1128, 0x9294, 0xffcf, 0x9295,
+	0x0020, 0x6a82, 0x2001, 0x197b, 0x6a80, 0x9294, 0x0030, 0x928e,
+	0x0000, 0x0170, 0x928e, 0x0010, 0x0118, 0x928e, 0x0020, 0x0140,
+	0x2003, 0xaaaa, 0x080c, 0x2779, 0x2001, 0x196c, 0x2102, 0x0008,
+	0x2102, 0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000,
+	0x00ce, 0x080c, 0x753d, 0x0128, 0x080c, 0x5027, 0x0110, 0x080c,
+	0x26ca, 0x60d4, 0x9005, 0x01c0, 0x6003, 0x0001, 0x2009, 0x4439,
+	0x00e0, 0x080c, 0x753d, 0x1168, 0x2011, 0x73b3, 0x080c, 0x86c8,
+	0x2011, 0x73a6, 0x080c, 0x87d4, 0x080c, 0x7845, 0x080c, 0x746e,
+	0x0040, 0x080c, 0x5f4d, 0x0028, 0x6003, 0x0004, 0x2009, 0x4451,
+	0x0020, 0x080c, 0x6a3f, 0x0804, 0x35b8, 0x2001, 0x0170, 0x2004,
+	0x9084, 0x00ff, 0x9086, 0x004c, 0x1118, 0x2091, 0x31bd, 0x0817,
+	0x2091, 0x313d, 0x0817, 0x6000, 0x9086, 0x0000, 0x0904, 0x35ea,
+	0x2069, 0x1847, 0x7890, 0x6842, 0x7894, 0x6846, 0x2d00, 0x2009,
+	0x0030, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804,
+	0x4b3e, 0x9006, 0x080c, 0x26ca, 0x81ff, 0x1904, 0x35ea, 0x080c,
+	0x753d, 0x11b0, 0x080c, 0x7840, 0x080c, 0x6092, 0x080c, 0x33ad,
+	0x0118, 0x6130, 0xc18d, 0x6132, 0x080c, 0xd09b, 0x0130, 0x080c,
+	0x7560, 0x1118, 0x080c, 0x7511, 0x0038, 0x080c, 0x746e, 0x0020,
+	0x080c, 0x6057, 0x080c, 0x5f4d, 0x0804, 0x35b8, 0x81ff, 0x1904,
+	0x35ea, 0x080c, 0x753d, 0x1110, 0x0804, 0x35ea, 0x6194, 0x81ff,
+	0x01a8, 0x704f, 0x0000, 0x2001, 0x1d80, 0x2009, 0x0040, 0x7a8c,
+	0x7b88, 0x7c9c, 0x7d98, 0x0126, 0x2091, 0x8000, 0x2039, 0x0001,
+	0x080c, 0x4b3e, 0x701f, 0x35b6, 0x012e, 0x0005, 0x704f, 0x0001,
+	0x00d6, 0x2069, 0x1d80, 0x20a9, 0x0040, 0x20e9, 0x0001, 0x20a1,
+	0x1d80, 0x2019, 0xffff, 0x4304, 0x655c, 0x9588, 0x33b9, 0x210d,
+	0x918c, 0x00ff, 0x216a, 0x900e, 0x2011, 0x0002, 0x2100, 0x9506,
+	0x01a8, 0x080c, 0x6693, 0x1190, 0xb814, 0x821c, 0x0238, 0x9398,
+	0x1d80, 0x9085, 0xff00, 0x8007, 0x201a, 0x0038, 0x9398, 0x1d80,
+	0x2324, 0x94a4, 0xff00, 0x9405, 0x201a, 0x8210, 0x8108, 0x9182,
+	0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0x9105, 0x206a,
+	0x00de, 0x20a9, 0x0040, 0x20a1, 0x1d80, 0x2099, 0x1d80, 0x080c,
+	0x5fe2, 0x0804, 0x44ab, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x080c,
+	0x4af2, 0x1120, 0x2009, 0x0002, 0x0804, 0x35ea, 0x080c, 0x573e,
+	0xd0b4, 0x0558, 0x7884, 0x908e, 0x007e, 0x0538, 0x908e, 0x007f,
+	0x0520, 0x908e, 0x0080, 0x0508, 0x080c, 0x33a8, 0x1148, 0xb800,
+	0xd08c, 0x11d8, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x11a8,
+	0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xcb4b, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x35ea, 0x7007, 0x0003, 0x701f, 0x4539,
+	0x0005, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x20a9, 0x002b, 0xb8c4,
+	0x20e0, 0xb8c8, 0x2098, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002,
+	0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080, 0x0006, 0x20a0, 0xb8c4,
+	0x20e0, 0xb8c8, 0x9080, 0x0006, 0x2098, 0x080c, 0x0fc4, 0x0070,
+	0x20a9, 0x0004, 0xa85c, 0x9080, 0x000a, 0x20a0, 0xb8c4, 0x20e0,
+	0xb8c8, 0x9080, 0x000a, 0x2098, 0x080c, 0x0fc4, 0x8906, 0x8006,
+	0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0x2009,
+	0x002b, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, 0x4b3e, 0x81ff,
+	0x1904, 0x35ea, 0x080c, 0x4b09, 0x0904, 0x35ed, 0x080c, 0x68d8,
+	0x0904, 0x35ea, 0x0058, 0xa878, 0x9005, 0x0120, 0x2009, 0x0004,
+	0x0804, 0x35ea, 0xa974, 0xaa94, 0x0804, 0x35b8, 0x080c, 0x5746,
+	0x0904, 0x35b8, 0x701f, 0x4583, 0x7007, 0x0003, 0x0005, 0x81ff,
+	0x1904, 0x35ea, 0x7888, 0x908a, 0x1000, 0x1a04, 0x35ed, 0x080c,
+	0x4b25, 0x0904, 0x35ed, 0x080c, 0x6add, 0x0120, 0x080c, 0x6ae5,
+	0x1904, 0x35ed, 0x080c, 0x695d, 0x0904, 0x35ea, 0x2019, 0x0004,
+	0x900e, 0x080c, 0x68ea, 0x0904, 0x35ea, 0x7984, 0x7a88, 0x04c9,
+	0x08a8, 0xa89c, 0x908a, 0x1000, 0x12f8, 0x080c, 0x4b23, 0x01e0,
+	0x080c, 0x6add, 0x0118, 0x080c, 0x6ae5, 0x11b0, 0x080c, 0x695d,
+	0x2009, 0x0002, 0x0168, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c,
+	0x68ea, 0x2009, 0x0003, 0x0120, 0xa998, 0xaa9c, 0x00d1, 0x0060,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x080c, 0x5746,
+	0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000,
+	0x0005, 0x9186, 0x00ff, 0x0110, 0x0071, 0x0060, 0x2029, 0x007e,
+	0x2061, 0x1800, 0x645c, 0x2400, 0x9506, 0x0110, 0x2508, 0x0019,
+	0x8529, 0x1ec8, 0x0005, 0x080c, 0x6693, 0x1138, 0x2200, 0x8003,
+	0x800b, 0x810b, 0x9108, 0x080c, 0x86d6, 0x0005, 0x81ff, 0x1904,
+	0x35ea, 0x798c, 0x2001, 0x197f, 0x918c, 0x8000, 0x2102, 0x080c,
+	0x4b09, 0x0904, 0x35ed, 0x080c, 0x6add, 0x0120, 0x080c, 0x6ae5,
+	0x1904, 0x35ed, 0x080c, 0x675a, 0x0904, 0x35ea, 0x080c, 0x68e1,
+	0x0904, 0x35ea, 0x2001, 0x197f, 0x2004, 0xd0fc, 0x1904, 0x35b8,
+	0x0804, 0x458e, 0xa9a0, 0x2001, 0x197f, 0x918c, 0x8000, 0xc18d,
+	0x2102, 0x080c, 0x4b16, 0x01a0, 0x080c, 0x6add, 0x0118, 0x080c,
+	0x6ae5, 0x1170, 0x080c, 0x675a, 0x2009, 0x0002, 0x0128, 0x080c,
+	0x68e1, 0x1170, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a, 0x0010,
+	0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005,
+	0xa897, 0x4000, 0x2001, 0x197f, 0x2004, 0xd0fc, 0x1128, 0x080c,
+	0x5746, 0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0000, 0x0005, 0x81ff, 0x1904, 0x35ea, 0x798c, 0x2001, 0x197e,
+	0x918c, 0x8000, 0x2102, 0x080c, 0x4b09, 0x0904, 0x35ed, 0x080c,
+	0x6add, 0x0120, 0x080c, 0x6ae5, 0x1904, 0x35ed, 0x080c, 0x675a,
+	0x0904, 0x35ea, 0x080c, 0x68cf, 0x0904, 0x35ea, 0x2001, 0x197e,
+	0x2004, 0xd0fc, 0x1904, 0x35b8, 0x0804, 0x458e, 0xa9a0, 0x2001,
+	0x197e, 0x918c, 0x8000, 0xc18d, 0x2102, 0x080c, 0x4b16, 0x01a0,
+	0x080c, 0x6add, 0x0118, 0x080c, 0x6ae5, 0x1170, 0x080c, 0x675a,
+	0x2009, 0x0002, 0x0128, 0x080c, 0x68cf, 0x1170, 0x2009, 0x0003,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x2001, 0x197e,
+	0x2004, 0xd0fc, 0x1128, 0x080c, 0x5746, 0x0110, 0x9006, 0x0018,
+	0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x6100, 0x0804,
+	0x35b8, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x080c, 0x5752, 0x1904,
+	0x35ea, 0x79a8, 0xd184, 0x1158, 0xb834, 0x8007, 0x789e, 0xb830,
+	0x8007, 0x789a, 0xbb2c, 0x831f, 0xba28, 0x8217, 0x0050, 0xb824,
+	0x8007, 0x789e, 0xb820, 0x8007, 0x789a, 0xbb1c, 0x831f, 0xba18,
+	0x8217, 0xb900, 0x918c, 0x0202, 0x0804, 0x35b8, 0x78a8, 0x909c,
+	0x0003, 0xd0ac, 0x1150, 0xd0b4, 0x1140, 0x939a, 0x0003, 0x1a04,
+	0x35ea, 0x625c, 0x7884, 0x9206, 0x1548, 0x080c, 0x8845, 0x2001,
+	0xffec, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x2039,
+	0x0000, 0x0006, 0x78a8, 0x9084, 0x0080, 0x1118, 0x000e, 0x0804,
+	0x4b3e, 0x000e, 0x2031, 0x0000, 0x2061, 0x18b8, 0x2c44, 0xa66a,
+	0xa17a, 0xa772, 0xa076, 0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c,
+	0x113c, 0x7007, 0x0002, 0x701f, 0x4746, 0x0005, 0x81ff, 0x1904,
+	0x35ea, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x080c, 0x6add, 0x1904,
+	0x35ea, 0x00c6, 0x080c, 0x4af2, 0x00ce, 0x0904, 0x35ea, 0xa867,
+	0x0000, 0xa868, 0xc0fd, 0xa86a, 0x7ea8, 0x080c, 0xcaf1, 0x0904,
+	0x35ea, 0x7007, 0x0003, 0x701f, 0x474a, 0x0005, 0x080c, 0x428c,
+	0x0804, 0x35b8, 0xa830, 0x9086, 0x0100, 0x0904, 0x35ea, 0x8906,
+	0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b,
+	0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804, 0x4b3e,
+	0x9006, 0x080c, 0x26ca, 0x78a8, 0x9084, 0x00ff, 0x9086, 0x00ff,
+	0x0118, 0x81ff, 0x1904, 0x35ea, 0x080c, 0x753d, 0x0110, 0x080c,
+	0x6057, 0x7888, 0x908a, 0x1000, 0x1a04, 0x35ed, 0x7984, 0x9186,
+	0x00ff, 0x0138, 0x9182, 0x007f, 0x1a04, 0x35ed, 0x2100, 0x080c,
+	0x2694, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061, 0x1a02,
+	0x601b, 0x0000, 0x601f, 0x0000, 0x6073, 0x0000, 0x6077, 0x0000,
+	0x080c, 0x753d, 0x1158, 0x080c, 0x7840, 0x080c, 0x6092, 0x9085,
+	0x0001, 0x080c, 0x7584, 0x080c, 0x746e, 0x00f0, 0x080c, 0xa91e,
+	0x080c, 0xabe9, 0x080c, 0xa93a, 0x2061, 0x0100, 0x2001, 0x1818,
+	0x2004, 0x9084, 0x00ff, 0x810f, 0x9105, 0x604a, 0x6043, 0x0090,
+	0x6043, 0x0010, 0x2009, 0x1998, 0x200b, 0x0000, 0x2009, 0x002d,
+	0x2011, 0x5f7d, 0x080c, 0x8792, 0x7984, 0x080c, 0x753d, 0x1110,
+	0x2009, 0x00ff, 0x7a88, 0x080c, 0x45f1, 0x012e, 0x00ce, 0x002e,
+	0x0804, 0x35b8, 0x7984, 0x080c, 0x6632, 0x2b08, 0x1904, 0x35ed,
+	0x0804, 0x35b8, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35ea,
+	0x60dc, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, 0x0005, 0x0804,
+	0x35ea, 0x080c, 0x4af2, 0x1120, 0x2009, 0x0002, 0x0804, 0x35ea,
+	0x7984, 0x9192, 0x0021, 0x1a04, 0x35ed, 0x7a8c, 0x7b88, 0x7c9c,
+	0x7d98, 0xa85c, 0x9080, 0x0019, 0x702a, 0xaf60, 0x7736, 0x080c,
+	0x4b3b, 0x701f, 0x4802, 0x7880, 0x9086, 0x006e, 0x0110, 0x701f,
+	0x51d9, 0x0005, 0x2009, 0x0080, 0x080c, 0x6693, 0x1118, 0x080c,
+	0x6add, 0x0120, 0x2021, 0x400a, 0x0804, 0x35ba, 0x00d6, 0x0096,
+	0xa964, 0xaa6c, 0xab70, 0xac74, 0xad78, 0xae7c, 0xa884, 0x90be,
+	0x0100, 0x0904, 0x489b, 0x90be, 0x0112, 0x0904, 0x489b, 0x90be,
+	0x0113, 0x0904, 0x489b, 0x90be, 0x0114, 0x0904, 0x489b, 0x90be,
+	0x0117, 0x0904, 0x489b, 0x90be, 0x011a, 0x0904, 0x489b, 0x90be,
+	0x011c, 0x0904, 0x489b, 0x90be, 0x0121, 0x0904, 0x4882, 0x90be,
+	0x0131, 0x0904, 0x4882, 0x90be, 0x0171, 0x0904, 0x489b, 0x90be,
+	0x0173, 0x0904, 0x489b, 0x90be, 0x01a1, 0x1128, 0xa894, 0x8007,
+	0xa896, 0x0804, 0x48a6, 0x90be, 0x0212, 0x0904, 0x488f, 0x90be,
+	0x0213, 0x05e8, 0x90be, 0x0214, 0x0500, 0x90be, 0x0217, 0x0188,
+	0x90be, 0x021a, 0x1120, 0xa89c, 0x8007, 0xa89e, 0x04e0, 0x90be,
+	0x021f, 0x05c8, 0x90be, 0x0300, 0x05b0, 0x009e, 0x00de, 0x0804,
+	0x35ed, 0x7028, 0x9080, 0x0010, 0x2098, 0x20a0, 0x7034, 0x20e0,
+	0x20e8, 0x20a9, 0x0007, 0x080c, 0x48e4, 0x7028, 0x9080, 0x000e,
+	0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c,
+	0x48e4, 0x00c8, 0x7028, 0x9080, 0x000c, 0x2098, 0x20a0, 0x7034,
+	0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x48f1, 0x00b8, 0x7028,
+	0x9080, 0x000e, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9,
+	0x0001, 0x080c, 0x48f1, 0x7028, 0x9080, 0x000c, 0x2098, 0x20a0,
+	0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x04f1, 0x00c6, 0x080c,
+	0x4af2, 0x0550, 0xa868, 0xc0fd, 0xa86a, 0xa867, 0x0119, 0x9006,
+	0xa882, 0xa87f, 0x0020, 0xa88b, 0x0001, 0x810b, 0xa9ae, 0xa8b2,
+	0xaab6, 0xabba, 0xacbe, 0xadc2, 0xa9c6, 0xa8ca, 0x00ce, 0x009e,
+	0x00de, 0xa866, 0xa822, 0xa868, 0xc0fd, 0xa86a, 0xa804, 0x2048,
+	0x080c, 0xcb0c, 0x1120, 0x2009, 0x0003, 0x0804, 0x35ea, 0x7007,
+	0x0003, 0x701f, 0x48db, 0x0005, 0x00ce, 0x009e, 0x00de, 0x2009,
+	0x0002, 0x0804, 0x35ea, 0xa820, 0x9086, 0x8001, 0x1904, 0x35b8,
+	0x2009, 0x0004, 0x0804, 0x35ea, 0x0016, 0x0026, 0x3510, 0x20a9,
+	0x0002, 0x4002, 0x4104, 0x4004, 0x8211, 0x1dc8, 0x002e, 0x001e,
+	0x0005, 0x0016, 0x0026, 0x0036, 0x0046, 0x3520, 0x20a9, 0x0004,
+	0x4002, 0x4304, 0x4204, 0x4104, 0x4004, 0x8421, 0x1db8, 0x004e,
+	0x003e, 0x002e, 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x35ea, 0x60dc, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009,
+	0x0005, 0x0804, 0x35ea, 0x7984, 0x78a8, 0x2040, 0x080c, 0xabe2,
+	0x1120, 0x9182, 0x007f, 0x0a04, 0x35ed, 0x9186, 0x00ff, 0x0904,
+	0x35ed, 0x9182, 0x0800, 0x1a04, 0x35ed, 0x7a8c, 0x7b88, 0x607c,
+	0x9306, 0x1158, 0x6080, 0x924e, 0x0904, 0x35ed, 0x080c, 0xabe2,
+	0x1120, 0x99cc, 0xff00, 0x0904, 0x35ed, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x4a05, 0x0904, 0x4985, 0x0086, 0x90c6, 0x4000, 0x008e,
+	0x1538, 0x00c6, 0x0006, 0x0036, 0xb818, 0xbb1c, 0x9305, 0xbb20,
+	0x9305, 0xbb24, 0x9305, 0xbb28, 0x9305, 0xbb2c, 0x9305, 0xbb30,
+	0x9305, 0xbb34, 0x9305, 0x003e, 0x0570, 0xd88c, 0x1128, 0x080c,
+	0x6add, 0x0110, 0xc89d, 0x0438, 0x900e, 0x080c, 0x6986, 0x1108,
+	0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, 0x00b8,
+	0x90c6, 0x4007, 0x1110, 0x2408, 0x0090, 0x90c6, 0x4008, 0x1118,
+	0x2708, 0x2610, 0x0060, 0x90c6, 0x4009, 0x1108, 0x0040, 0x90c6,
+	0x4006, 0x1108, 0x0020, 0x2001, 0x4005, 0x2009, 0x000a, 0x2020,
+	0x012e, 0x0804, 0x35ba, 0x000e, 0x00ce, 0x2b00, 0x7026, 0x0016,
+	0x00b6, 0x00c6, 0x00e6, 0x2c70, 0x080c, 0xad20, 0x0904, 0x49da,
+	0x2b00, 0x6012, 0x080c, 0xce15, 0x2e58, 0x00ee, 0x00e6, 0x00c6,
+	0x080c, 0x4af2, 0x00ce, 0x2b70, 0x1158, 0x080c, 0xacb0, 0x00ee,
+	0x00ce, 0x00be, 0x001e, 0x012e, 0x2009, 0x0002, 0x0804, 0x35ea,
+	0x900e, 0xa966, 0xa96a, 0x2900, 0x6016, 0xa932, 0xa868, 0xc0fd,
+	0xd88c, 0x0108, 0xc0f5, 0xa86a, 0xd89c, 0x1110, 0x080c, 0x3240,
+	0x6023, 0x0001, 0x9006, 0x080c, 0x65cf, 0xd89c, 0x0138, 0x2001,
+	0x0004, 0x080c, 0x65e3, 0x2009, 0x0003, 0x0030, 0x2001, 0x0002,
+	0x080c, 0x65e3, 0x2009, 0x0002, 0x080c, 0xad4d, 0x78a8, 0xd094,
+	0x0138, 0x00ee, 0x7024, 0x00e6, 0x2058, 0xb8d4, 0xc08d, 0xb8d6,
+	0x9085, 0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x012e, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x35ea, 0x7007, 0x0003, 0x701f, 0x49e9,
+	0x0005, 0xa830, 0x9086, 0x0100, 0x7024, 0x2058, 0x1138, 0x2009,
+	0x0004, 0xba04, 0x9294, 0x00ff, 0x0804, 0x568c, 0x900e, 0xa868,
+	0xd0f4, 0x1904, 0x35b8, 0x080c, 0x6986, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0x0804, 0x35b8, 0x00e6, 0x00d6, 0x0096,
+	0x83ff, 0x0904, 0x4a54, 0x902e, 0x080c, 0xabe2, 0x0130, 0x9026,
+	0x20a9, 0x0800, 0x2071, 0x1000, 0x0030, 0x2021, 0x007f, 0x20a9,
+	0x0781, 0x2071, 0x107f, 0x2e04, 0x9005, 0x11b8, 0x2100, 0x9406,
+	0x1904, 0x4a65, 0x2428, 0x94ce, 0x007f, 0x1120, 0x92ce, 0xfffd,
+	0x1558, 0x0030, 0x94ce, 0x0080, 0x1130, 0x92ce, 0xfffc, 0x1520,
+	0x93ce, 0x00ff, 0x1508, 0xc5fd, 0x0480, 0x2058, 0xbf10, 0x2700,
+	0x9306, 0x11e8, 0xbe14, 0x2600, 0x9206, 0x11c8, 0x2400, 0x9106,
+	0x1180, 0xd884, 0x0598, 0xd894, 0x1588, 0x080c, 0x6a7d, 0x1570,
+	0x2001, 0x4000, 0x0460, 0x080c, 0x6add, 0x1540, 0x2001, 0x4000,
+	0x0430, 0x2001, 0x4007, 0x0418, 0x2001, 0x4006, 0x0400, 0x2400,
+	0x9106, 0x1158, 0xbe14, 0x87ff, 0x1128, 0x86ff, 0x0918, 0x080c,
+	0xabe2, 0x1900, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04,
+	0x4a1b, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001,
+	0x0030, 0x080c, 0x6632, 0x1dd0, 0xbb12, 0xba16, 0x9006, 0x9005,
+	0x009e, 0x00de, 0x00ee, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x35ea, 0x080c, 0x4af2, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x35ea, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x7884, 0x9005,
+	0x0904, 0x35ed, 0x9096, 0x00ff, 0x0120, 0x9092, 0x0004, 0x1a04,
+	0x35ed, 0x2010, 0x2918, 0x080c, 0x31e0, 0x1120, 0x2009, 0x0003,
+	0x0804, 0x35ea, 0x7007, 0x0003, 0x701f, 0x4aa7, 0x0005, 0xa830,
+	0x9086, 0x0100, 0x1904, 0x35b8, 0x2009, 0x0004, 0x0804, 0x35ea,
+	0x7984, 0x080c, 0xabe2, 0x1120, 0x9182, 0x007f, 0x0a04, 0x35ed,
+	0x9186, 0x00ff, 0x0904, 0x35ed, 0x9182, 0x0800, 0x1a04, 0x35ed,
+	0x2001, 0x9400, 0x080c, 0x56e7, 0x1904, 0x35ea, 0x0804, 0x35b8,
+	0xa998, 0x080c, 0xabe2, 0x1118, 0x9182, 0x007f, 0x0280, 0x9186,
+	0x00ff, 0x0168, 0x9182, 0x0800, 0x1250, 0x2001, 0x9400, 0x080c,
+	0x56e7, 0x11a8, 0x0060, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897,
+	0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897,
+	0x4000, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x2009,
+	0x000a, 0x0c48, 0x080c, 0x1047, 0x0198, 0x9006, 0xa802, 0x7014,
+	0x9005, 0x1120, 0x2900, 0x7016, 0x701a, 0x0040, 0x7018, 0xa802,
+	0x0086, 0x2040, 0x2900, 0xa006, 0x701a, 0x008e, 0x9085, 0x0001,
+	0x0005, 0x7984, 0x080c, 0x6693, 0x1130, 0x7e88, 0x9684, 0x3fff,
+	0x9082, 0x4000, 0x0208, 0x905e, 0x8bff, 0x0005, 0xa998, 0x080c,
+	0x6693, 0x1130, 0xae9c, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0208,
+	0x905e, 0x8bff, 0x0005, 0xae98, 0x0008, 0x7e84, 0x2608, 0x080c,
+	0x6693, 0x1108, 0x0008, 0x905e, 0x8bff, 0x0005, 0x0016, 0x7114,
+	0x81ff, 0x0128, 0x2148, 0xa904, 0x080c, 0x1079, 0x0cc8, 0x7116,
+	0x711a, 0x001e, 0x0005, 0x2031, 0x0001, 0x0010, 0x2031, 0x0000,
+	0x2061, 0x18b8, 0x2c44, 0xa66a, 0xa17a, 0xa772, 0xa076, 0xa28e,
+	0xa392, 0xa496, 0xa59a, 0x080c, 0x113c, 0x7007, 0x0002, 0x701f,
+	0x35b8, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0000,
+	0x2001, 0x18b0, 0x2004, 0x9005, 0x1190, 0x0e04, 0x4b6f, 0x7a36,
+	0x7833, 0x0012, 0x7a82, 0x7b86, 0x7c8a, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x0804, 0x4bd5, 0x0016,
+	0x0086, 0x0096, 0x00c6, 0x00e6, 0x2071, 0x189e, 0x7044, 0x9005,
+	0x1540, 0x7148, 0x9182, 0x0010, 0x0288, 0x7038, 0x2060, 0x080c,
+	0x1047, 0x0904, 0x4bcd, 0xa84b, 0x0000, 0x2900, 0x7046, 0x2001,
+	0x0002, 0x9080, 0x1eab, 0x2005, 0xa846, 0x0098, 0x7038, 0x90e0,
+	0x0004, 0x2001, 0x18ba, 0x9c82, 0x18fa, 0x0210, 0x2061, 0x18ba,
+	0x2c00, 0x703a, 0x7148, 0x81ff, 0x1108, 0x703e, 0x8108, 0x714a,
+	0x0460, 0x7148, 0x8108, 0x714a, 0x7044, 0x2040, 0xa144, 0x2105,
+	0x0016, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x2060, 0x001e, 0x8108,
+	0x2105, 0x9005, 0xa146, 0x1520, 0x080c, 0x1047, 0x1130, 0x8109,
+	0xa946, 0x7148, 0x8109, 0x714a, 0x00d8, 0x9006, 0xa806, 0xa84a,
+	0xa046, 0x2800, 0xa802, 0x2900, 0xa006, 0x7046, 0x2001, 0x0002,
+	0x9080, 0x1eab, 0x2005, 0xa846, 0x0058, 0x2262, 0x6306, 0x640a,
+	0x00ee, 0x00ce, 0x009e, 0x008e, 0x001e, 0x012e, 0x00fe, 0x0005,
+	0x2c00, 0x9082, 0x001b, 0x0002, 0x4bf7, 0x4bf7, 0x4bf9, 0x4bf7,
+	0x4bf7, 0x4bf7, 0x4bfd, 0x4bf7, 0x4bf7, 0x4bf7, 0x4c01, 0x4bf7,
+	0x4bf7, 0x4bf7, 0x4c05, 0x4bf7, 0x4bf7, 0x4bf7, 0x4c09, 0x4bf7,
+	0x4bf7, 0x4bf7, 0x4c0d, 0x4bf7, 0x4bf7, 0x4bf7, 0x4c12, 0x080c,
+	0x0d7d, 0xa276, 0xa37a, 0xa47e, 0x0898, 0xa286, 0xa38a, 0xa48e,
+	0x0878, 0xa296, 0xa39a, 0xa49e, 0x0858, 0xa2a6, 0xa3aa, 0xa4ae,
+	0x0838, 0xa2b6, 0xa3ba, 0xa4be, 0x0818, 0xa2c6, 0xa3ca, 0xa4ce,
+	0x0804, 0x4bd0, 0xa2d6, 0xa3da, 0xa4de, 0x0804, 0x4bd0, 0x00e6,
+	0x2071, 0x189e, 0x7048, 0x9005, 0x0904, 0x4ca9, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x4ca8, 0x00f6, 0x2079, 0x0000, 0x00c6, 0x0096,
+	0x0086, 0x0076, 0x9006, 0x2038, 0x7040, 0x2048, 0x9005, 0x0500,
+	0xa948, 0x2105, 0x0016, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x2060,
+	0x001e, 0x8108, 0x2105, 0x9005, 0xa94a, 0x1904, 0x4cab, 0xa804,
+	0x9005, 0x090c, 0x0d7d, 0x7042, 0x2938, 0x2040, 0xa003, 0x0000,
+	0x2001, 0x0002, 0x9080, 0x1eab, 0x2005, 0xa04a, 0x0804, 0x4cab,
+	0x703c, 0x2060, 0x2c14, 0x6304, 0x6408, 0x650c, 0x2200, 0x7836,
+	0x7833, 0x0012, 0x7882, 0x2300, 0x7886, 0x2400, 0x788a, 0x2091,
+	0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x87ff,
+	0x0118, 0x2748, 0x080c, 0x1079, 0x7048, 0x8001, 0x704a, 0x9005,
+	0x1170, 0x7040, 0x2048, 0x9005, 0x0128, 0x080c, 0x1079, 0x9006,
+	0x7042, 0x7046, 0x703b, 0x18ba, 0x703f, 0x18ba, 0x0420, 0x7040,
+	0x9005, 0x1508, 0x7238, 0x2c00, 0x9206, 0x0148, 0x9c80, 0x0004,
+	0x90fa, 0x18fa, 0x0210, 0x2001, 0x18ba, 0x703e, 0x00a0, 0x9006,
+	0x703e, 0x703a, 0x7044, 0x9005, 0x090c, 0x0d7d, 0x2048, 0xa800,
+	0x9005, 0x1de0, 0x2900, 0x7042, 0x2001, 0x0002, 0x9080, 0x1eab,
+	0x2005, 0xa84a, 0x0000, 0x007e, 0x008e, 0x009e, 0x00ce, 0x00fe,
+	0x012e, 0x00ee, 0x0005, 0x2c00, 0x9082, 0x001b, 0x0002, 0x4cca,
+	0x4cca, 0x4ccc, 0x4cca, 0x4cca, 0x4cca, 0x4cd1, 0x4cca, 0x4cca,
+	0x4cca, 0x4cd6, 0x4cca, 0x4cca, 0x4cca, 0x4cdb, 0x4cca, 0x4cca,
+	0x4cca, 0x4ce0, 0x4cca, 0x4cca, 0x4cca, 0x4ce5, 0x4cca, 0x4cca,
+	0x4cca, 0x4cea, 0x080c, 0x0d7d, 0xaa74, 0xab78, 0xac7c, 0x0804,
+	0x4c56, 0xaa84, 0xab88, 0xac8c, 0x0804, 0x4c56, 0xaa94, 0xab98,
+	0xac9c, 0x0804, 0x4c56, 0xaaa4, 0xaba8, 0xacac, 0x0804, 0x4c56,
+	0xaab4, 0xabb8, 0xacbc, 0x0804, 0x4c56, 0xaac4, 0xabc8, 0xaccc,
+	0x0804, 0x4c56, 0xaad4, 0xabd8, 0xacdc, 0x0804, 0x4c56, 0x0016,
+	0x0026, 0x0036, 0x00b6, 0x00c6, 0x2009, 0x007e, 0x080c, 0x6693,
+	0x2019, 0x0001, 0xb85c, 0xd0ac, 0x0110, 0x2019, 0x0000, 0x2011,
+	0x801b, 0x080c, 0x4b52, 0x00ce, 0x00be, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x0026, 0x080c, 0x573e, 0xd0c4, 0x0120, 0x2011, 0x8014,
+	0x080c, 0x4b52, 0x002e, 0x0005, 0x81ff, 0x1904, 0x35ea, 0x0126,
+	0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c,
+	0x753d, 0x1158, 0x080c, 0x7840, 0x080c, 0x6092, 0x9085, 0x0001,
+	0x080c, 0x7584, 0x080c, 0x746e, 0x0010, 0x080c, 0x5f4d, 0x012e,
+	0x0804, 0x35b8, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35ea,
+	0x080c, 0x5752, 0x0120, 0x2009, 0x0007, 0x0804, 0x35ea, 0x080c,
+	0x6ad5, 0x0120, 0x2009, 0x0008, 0x0804, 0x35ea, 0x7984, 0x080c,
+	0x6632, 0x1904, 0x35ed, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x2b00,
+	0x7026, 0x080c, 0x6add, 0x7888, 0x1170, 0x9084, 0x0005, 0x1158,
+	0x900e, 0x080c, 0x6986, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108,
+	0xc18d, 0x0804, 0x35b8, 0x080c, 0x4af2, 0x0904, 0x35ea, 0x9006,
+	0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xcbb3, 0x0904,
+	0x35ea, 0x7888, 0xd094, 0x0118, 0xb8d4, 0xc08d, 0xb8d6, 0x7007,
+	0x0003, 0x701f, 0x4dc5, 0x0005, 0x2061, 0x1800, 0x080c, 0x5752,
+	0x2009, 0x0007, 0x1560, 0x080c, 0x6ad5, 0x0118, 0x2009, 0x0008,
+	0x0430, 0xa998, 0x080c, 0x6632, 0x1530, 0x080c, 0x4b23, 0x0518,
+	0x080c, 0x6add, 0xa89c, 0x1168, 0x9084, 0x0005, 0x1150, 0x900e,
+	0x080c, 0x6986, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d,
+	0x00d0, 0xa868, 0xc0fc, 0xa86a, 0x080c, 0xcbb3, 0x11e0, 0xa89c,
+	0xd094, 0x0118, 0xb8d4, 0xc08d, 0xb8d6, 0x2009, 0x0003, 0xa897,
+	0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001,
+	0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0xa99a, 0x9006, 0x918d,
+	0x0001, 0x2008, 0x0005, 0x9006, 0x0005, 0xa830, 0x9086, 0x0100,
+	0x7024, 0x2058, 0x1110, 0x0804, 0x568c, 0x900e, 0x080c, 0x6986,
+	0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x35b8,
+	0x080c, 0x5752, 0x0120, 0x2009, 0x0007, 0x0804, 0x35ea, 0x7f84,
+	0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x080c, 0x4af2, 0x1120, 0x2009,
+	0x0002, 0x0804, 0x35ea, 0x900e, 0x2130, 0x7126, 0x7132, 0xa860,
+	0x20e8, 0x7036, 0xa85c, 0x9080, 0x0005, 0x702a, 0x20a0, 0x080c,
+	0x6693, 0x1904, 0x4e67, 0x080c, 0x6add, 0x0138, 0x080c, 0x6ae5,
+	0x0120, 0x080c, 0x6a7d, 0x1904, 0x4e67, 0xd794, 0x1110, 0xd784,
+	0x01a8, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x0006, 0x2098, 0x3400,
+	0xd794, 0x0160, 0x20a9, 0x0008, 0x4003, 0x2098, 0x20a0, 0x3d00,
+	0x20e0, 0x20a9, 0x0002, 0x080c, 0x48f1, 0x0048, 0x20a9, 0x0004,
+	0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x080c, 0x48f1, 0x9186,
+	0x007e, 0x0170, 0x9186, 0x0080, 0x0158, 0x080c, 0x6add, 0x90c2,
+	0x0006, 0x1210, 0xc1fd, 0x0020, 0x080c, 0x6986, 0x1108, 0xc1fd,
+	0x4104, 0xc1fc, 0xd794, 0x0528, 0xb8c4, 0x20e0, 0xb8c8, 0x2060,
+	0x9c80, 0x0000, 0x2098, 0x20a9, 0x0002, 0x4003, 0x9c80, 0x0003,
+	0x2098, 0x20a9, 0x0001, 0x4005, 0x9c80, 0x0004, 0x2098, 0x3400,
+	0x20a9, 0x0002, 0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x080c,
+	0x48e4, 0x9c80, 0x0026, 0x2098, 0xb8c4, 0x20e0, 0x20a9, 0x0002,
+	0x4003, 0xd794, 0x0110, 0x96b0, 0x000b, 0x96b0, 0x0005, 0x8108,
+	0x080c, 0xabe2, 0x0118, 0x9186, 0x0800, 0x0040, 0xd78c, 0x0120,
+	0x9186, 0x0800, 0x0170, 0x0018, 0x9186, 0x007e, 0x0150, 0xd794,
+	0x0118, 0x9686, 0x0020, 0x0010, 0x9686, 0x0028, 0x0150, 0x0804,
+	0x4df7, 0x86ff, 0x1120, 0x7124, 0x810b, 0x0804, 0x35b8, 0x7033,
+	0x0001, 0x7122, 0x7024, 0x9600, 0x7026, 0x772e, 0x2061, 0x18b8,
+	0x2c44, 0xa06b, 0x0000, 0xa67a, 0x7034, 0xa072, 0x7028, 0xa076,
+	0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x113c, 0x7007, 0x0002,
+	0x701f, 0x4ea3, 0x0005, 0x7030, 0x9005, 0x1180, 0x7120, 0x7028,
+	0x20a0, 0x772c, 0x9036, 0x7034, 0x20e8, 0x2061, 0x18b8, 0x2c44,
+	0xa28c, 0xa390, 0xa494, 0xa598, 0x0804, 0x4df7, 0x7124, 0x810b,
+	0x0804, 0x35b8, 0x2029, 0x007e, 0x7984, 0x7a88, 0x7b8c, 0x7c98,
+	0x9184, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x35ed, 0x9502,
+	0x0a04, 0x35ed, 0x9184, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x35ed,
+	0x9502, 0x0a04, 0x35ed, 0x9284, 0xff00, 0x8007, 0x90e2, 0x0020,
+	0x0a04, 0x35ed, 0x9502, 0x0a04, 0x35ed, 0x9284, 0x00ff, 0x90e2,
+	0x0020, 0x0a04, 0x35ed, 0x9502, 0x0a04, 0x35ed, 0x9384, 0xff00,
+	0x8007, 0x90e2, 0x0020, 0x0a04, 0x35ed, 0x9502, 0x0a04, 0x35ed,
+	0x9384, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x35ed, 0x9502, 0x0a04,
+	0x35ed, 0x9484, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x35ed,
+	0x9502, 0x0a04, 0x35ed, 0x9484, 0x00ff, 0x90e2, 0x0020, 0x0a04,
+	0x35ed, 0x9502, 0x0a04, 0x35ed, 0x2061, 0x1988, 0x6102, 0x6206,
+	0x630a, 0x640e, 0x0804, 0x35b8, 0x080c, 0x4af2, 0x0904, 0x35ea,
+	0x2009, 0x0016, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080,
+	0x0019, 0xaf60, 0x080c, 0x4b3b, 0x701f, 0x4f27, 0x0005, 0x2001,
+	0x0138, 0x2003, 0x0000, 0x00e6, 0x2071, 0x0300, 0x701c, 0xd0a4,
+	0x1de8, 0x00ee, 0x20a9, 0x0016, 0x896e, 0x8d6e, 0x8d6f, 0x9d84,
+	0xffc0, 0x9080, 0x0019, 0x2098, 0x9d84, 0x003f, 0x20e0, 0x2069,
+	0x1877, 0x20e9, 0x0001, 0x2da0, 0x4003, 0x6800, 0x9005, 0x0904,
+	0x4fa8, 0x6804, 0x2008, 0x918c, 0xfff8, 0x1904, 0x4fa8, 0x680c,
+	0x9005, 0x0904, 0x4fa8, 0x9082, 0xff01, 0x1a04, 0x4fa8, 0x6810,
+	0x9082, 0x005c, 0x0a04, 0x4fa8, 0x6824, 0x2008, 0x9082, 0x0008,
+	0x0a04, 0x4fa8, 0x9182, 0x0400, 0x1a04, 0x4fa8, 0x0056, 0x2029,
+	0x0000, 0x080c, 0x8da1, 0x005e, 0x6944, 0x6820, 0x9102, 0x06c0,
+	0x6820, 0x9082, 0x0019, 0x16a0, 0x6828, 0x6944, 0x810c, 0x9102,
+	0x0678, 0x6840, 0x9082, 0x000f, 0x1658, 0x080c, 0x1060, 0x2900,
+	0x0904, 0x4fc4, 0x684e, 0x00e6, 0x2071, 0x1930, 0x00b6, 0x2059,
+	0x0000, 0x080c, 0x8c5d, 0x00be, 0x00ee, 0x0568, 0x080c, 0x89ad,
+	0x080c, 0x89f8, 0x11e0, 0x6857, 0x0000, 0x00c6, 0x2061, 0x0100,
+	0x6104, 0x918d, 0x2000, 0x6106, 0x6b10, 0x2061, 0x1a6a, 0x630a,
+	0x00ce, 0x080c, 0x2779, 0x2001, 0x0138, 0x2102, 0x0804, 0x35b8,
+	0x080c, 0x2779, 0x2001, 0x0138, 0x2102, 0x0804, 0x35ed, 0x080c,
+	0x89f1, 0x00e6, 0x2071, 0x1930, 0x080c, 0x8e21, 0x080c, 0x8e30,
+	0x080c, 0x8c44, 0x00ee, 0x2001, 0x188a, 0x204c, 0x080c, 0x1079,
+	0x2001, 0x188a, 0x2003, 0x0000, 0x080c, 0x2779, 0x2001, 0x0138,
+	0x2102, 0x0804, 0x35ea, 0x2001, 0x1924, 0x200c, 0x918e, 0x0000,
+	0x0904, 0x5025, 0x080c, 0x8c3f, 0x0904, 0x5025, 0x2001, 0x0101,
+	0x200c, 0x918c, 0xdfff, 0x2102, 0x2001, 0x0138, 0x2003, 0x0000,
+	0x00e6, 0x2071, 0x0300, 0x701c, 0xd0a4, 0x1de8, 0x00ee, 0x080c,
+	0x8c44, 0x2001, 0x0035, 0x080c, 0x16a0, 0x00c6, 0x2061, 0x193c,
+	0x6004, 0x6100, 0x9106, 0x1de0, 0x00ce, 0x080c, 0x2779, 0x2001,
+	0x0138, 0x2102, 0x00e6, 0x00f6, 0x2071, 0x1923, 0x080c, 0x8b7e,
+	0x0120, 0x2f00, 0x080c, 0x8c0a, 0x0cc8, 0x00fe, 0x00ee, 0x0126,
+	0x2091, 0x8000, 0x2001, 0x188a, 0x200c, 0x81ff, 0x0138, 0x2148,
+	0x080c, 0x1079, 0x2001, 0x188a, 0x2003, 0x0000, 0x2001, 0x183d,
+	0x2003, 0x0020, 0x080c, 0x89f1, 0x00e6, 0x2071, 0x1930, 0x080c,
+	0x8e21, 0x080c, 0x8e30, 0x00ee, 0x012e, 0x0804, 0x35b8, 0x0006,
+	0x080c, 0x573e, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x080c, 0x5742,
+	0xd0bc, 0x000e, 0x0005, 0x6174, 0x7a84, 0x6300, 0x82ff, 0x1118,
+	0x7986, 0x0804, 0x35b8, 0x83ff, 0x1904, 0x35ed, 0x2001, 0xfff0,
+	0x9200, 0x1a04, 0x35ed, 0x2019, 0xffff, 0x6078, 0x9302, 0x9200,
+	0x0a04, 0x35ed, 0x7986, 0x6276, 0x0804, 0x35b8, 0x080c, 0x5752,
+	0x1904, 0x35ea, 0x7c88, 0x7d84, 0x7e98, 0x7f8c, 0x080c, 0x4af2,
+	0x0904, 0x35ea, 0x900e, 0x901e, 0x7326, 0x7332, 0xa860, 0x20e8,
+	0x7036, 0xa85c, 0x9080, 0x0003, 0x702a, 0x20a0, 0x91d8, 0x1000,
+	0x2b5c, 0x8bff, 0x0178, 0x080c, 0x6add, 0x0118, 0x080c, 0x6ae5,
+	0x1148, 0x20a9, 0x0001, 0xb814, 0x4004, 0xb810, 0x4004, 0x4104,
+	0x9398, 0x0003, 0x8108, 0x9182, 0x0800, 0x0120, 0x9386, 0x003c,
+	0x0170, 0x0c20, 0x83ff, 0x1148, 0x7224, 0x900e, 0x2001, 0x0003,
+	0x080c, 0x91f8, 0x2208, 0x0804, 0x35b8, 0x7033, 0x0001, 0x7122,
+	0x7024, 0x9300, 0x7026, 0x2061, 0x18b8, 0x2c44, 0xa06b, 0x0000,
+	0xa37a, 0x7028, 0xa076, 0x7034, 0xa072, 0xa48e, 0xa592, 0xa696,
+	0xa79a, 0x080c, 0x113c, 0x7007, 0x0002, 0x701f, 0x50a8, 0x0005,
+	0x7030, 0x9005, 0x1178, 0x7120, 0x7028, 0x20a0, 0x901e, 0x7034,
+	0x20e8, 0x2061, 0x18b8, 0x2c44, 0xa48c, 0xa590, 0xa694, 0xa798,
+	0x0804, 0x5066, 0x7224, 0x900e, 0x2001, 0x0003, 0x080c, 0x91f8,
+	0x2208, 0x0804, 0x35b8, 0x00f6, 0x00e6, 0x080c, 0x5752, 0x2009,
+	0x0007, 0x1904, 0x513b, 0x2071, 0x189e, 0x745c, 0x84ff, 0x2009,
+	0x000e, 0x1904, 0x513b, 0xac9c, 0xad98, 0xaea4, 0xafa0, 0x0096,
+	0x080c, 0x1060, 0x2009, 0x0002, 0x0904, 0x513b, 0x2900, 0x705e,
+	0x900e, 0x901e, 0x7356, 0x7362, 0xa860, 0x7066, 0xa85c, 0x9080,
+	0x0003, 0x705a, 0x20a0, 0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178,
+	0x080c, 0x6add, 0x0118, 0x080c, 0x6ae5, 0x1148, 0xb814, 0x20a9,
+	0x0001, 0x4004, 0xb810, 0x4004, 0x4104, 0x9398, 0x0003, 0x8108,
+	0x9182, 0x0800, 0x0120, 0x9386, 0x003c, 0x01e8, 0x0c20, 0x83ff,
+	0x11c0, 0x7254, 0x900e, 0x2001, 0x0003, 0x080c, 0x91f8, 0x2208,
+	0x009e, 0xa897, 0x4000, 0xa99a, 0x715c, 0x81ff, 0x090c, 0x0d7d,
+	0x2148, 0x080c, 0x1079, 0x9006, 0x705e, 0x918d, 0x0001, 0x2008,
+	0x0418, 0x7063, 0x0001, 0x7152, 0x7054, 0x9300, 0x7056, 0x2061,
+	0x18b9, 0x2c44, 0xa37a, 0x7058, 0xa076, 0x7064, 0xa072, 0xa48e,
+	0xa592, 0xa696, 0xa79a, 0xa09f, 0x5147, 0x000e, 0xa0a2, 0x080c,
+	0x113c, 0x9006, 0x0048, 0x009e, 0xa897, 0x4005, 0xa99a, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0030, 0x00ee, 0x00fe, 0x0005, 0x00f6,
+	0xa0a0, 0x904d, 0x090c, 0x0d7d, 0x00e6, 0x2071, 0x189e, 0xa06c,
+	0x908e, 0x0100, 0x0138, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897,
+	0x4002, 0x00d8, 0x7060, 0x9005, 0x1158, 0x7150, 0x7058, 0x20a0,
+	0x901e, 0x7064, 0x20e8, 0xa48c, 0xa590, 0xa694, 0xa798, 0x0428,
+	0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x7254, 0x900e,
+	0x2001, 0x0003, 0x080c, 0x91f8, 0xaa9a, 0x715c, 0x81ff, 0x090c,
+	0x0d7d, 0x2148, 0x080c, 0x1079, 0x705f, 0x0000, 0xa0a0, 0x2048,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x6dee, 0x012e, 0xa09f, 0x0000,
+	0xa0a3, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x91d8, 0x1000, 0x2b5c,
+	0x8bff, 0x0178, 0x080c, 0x6add, 0x0118, 0x080c, 0x6ae5, 0x1148,
+	0xb814, 0x20a9, 0x0001, 0x4004, 0xb810, 0x4004, 0x4104, 0x9398,
+	0x0003, 0x8108, 0x9182, 0x0800, 0x0120, 0x9386, 0x003c, 0x0518,
+	0x0c20, 0x83ff, 0x11f0, 0x7154, 0x810c, 0xa99a, 0xa897, 0x4000,
+	0x715c, 0x81ff, 0x090c, 0x0d7d, 0x2148, 0x080c, 0x1079, 0x9006,
+	0x705e, 0x918d, 0x0001, 0x2008, 0xa0a0, 0x2048, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6dee, 0x012e, 0xa09f, 0x0000, 0xa0a3, 0x0000,
+	0x0070, 0x7063, 0x0001, 0x7152, 0x7054, 0x9300, 0x7056, 0xa37a,
+	0xa48e, 0xa592, 0xa696, 0xa79a, 0x080c, 0x113c, 0x9006, 0x00ee,
+	0x0005, 0x0096, 0xa88c, 0x90be, 0x7000, 0x0148, 0x90be, 0x7100,
+	0x0130, 0x90be, 0x7200, 0x0118, 0x009e, 0x0804, 0x35ed, 0xa884,
+	0xa988, 0x080c, 0x2661, 0x1518, 0x080c, 0x6632, 0x1500, 0x7126,
+	0xbe12, 0xbd16, 0xae7c, 0x080c, 0x4af2, 0x01c8, 0x080c, 0x4af2,
+	0x01b0, 0x009e, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0xa823,
+	0x0000, 0xa804, 0x2048, 0x080c, 0xcb2c, 0x1120, 0x2009, 0x0003,
+	0x0804, 0x35ea, 0x7007, 0x0003, 0x701f, 0x5214, 0x0005, 0x009e,
+	0x2009, 0x0002, 0x0804, 0x35ea, 0x7124, 0x080c, 0x3349, 0xa820,
+	0x9086, 0x8001, 0x1120, 0x2009, 0x0004, 0x0804, 0x35ea, 0x2900,
+	0x7022, 0xa804, 0x0096, 0x2048, 0x8906, 0x8006, 0x8007, 0x90bc,
+	0x003f, 0x9084, 0xffc0, 0x009e, 0x9080, 0x0002, 0x0076, 0x0006,
+	0x2098, 0x20a0, 0x27e0, 0x27e8, 0x20a9, 0x002a, 0x080c, 0x0fc4,
+	0xaa6c, 0xab70, 0xac74, 0xad78, 0x2061, 0x18b8, 0x2c44, 0xa06b,
+	0x0000, 0xae64, 0xaf8c, 0x97c6, 0x7000, 0x0118, 0x97c6, 0x7100,
+	0x1148, 0x96c2, 0x0004, 0x0600, 0x2009, 0x0004, 0x000e, 0x007e,
+	0x0804, 0x4b3e, 0x97c6, 0x7200, 0x11b8, 0x96c2, 0x0054, 0x02a0,
+	0x000e, 0x007e, 0x2061, 0x18b8, 0x2c44, 0xa076, 0xa772, 0xa07b,
+	0x002a, 0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x113c, 0x7007,
+	0x0002, 0x701f, 0x5270, 0x0005, 0x000e, 0x007e, 0x0804, 0x35ed,
+	0x7020, 0x2048, 0xa804, 0x2048, 0xa804, 0x2048, 0x8906, 0x8006,
+	0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0x2098,
+	0x20a0, 0x27e0, 0x27e8, 0x20a9, 0x002a, 0x080c, 0x0fc4, 0x2100,
+	0x2238, 0x2061, 0x18b8, 0x2c44, 0xa28c, 0xa390, 0xa494, 0xa598,
+	0x2009, 0x002a, 0x0804, 0x4b3e, 0x81ff, 0x1904, 0x35ea, 0x798c,
+	0x2001, 0x197d, 0x918c, 0x8000, 0x2102, 0x080c, 0x4b09, 0x0904,
+	0x35ed, 0x080c, 0x6add, 0x0120, 0x080c, 0x6ae5, 0x1904, 0x35ed,
+	0x080c, 0x675a, 0x0904, 0x35ea, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x68f3, 0x012e, 0x0904, 0x35ea, 0x2001, 0x197d, 0x2004, 0xd0fc,
+	0x1904, 0x35b8, 0x0804, 0x458e, 0xa9a0, 0x2001, 0x197d, 0x918c,
+	0x8000, 0xc18d, 0x2102, 0x080c, 0x4b16, 0x01a0, 0x080c, 0x6add,
+	0x0118, 0x080c, 0x6ae5, 0x1170, 0x080c, 0x675a, 0x2009, 0x0002,
+	0x0128, 0x080c, 0x68f3, 0x1170, 0x2009, 0x0003, 0xa897, 0x4005,
+	0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0030, 0x0005, 0xa897, 0x4000, 0x2001, 0x197d, 0x2004, 0xd0fc,
+	0x1128, 0x080c, 0x5746, 0x0110, 0x9006, 0x0018, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0000, 0x0005, 0x78a8, 0xd08c, 0x1118, 0xd084,
+	0x0904, 0x4503, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x080c, 0x4af2,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x35ea, 0x080c, 0x6add, 0x0130,
+	0x908e, 0x0004, 0x0118, 0x908e, 0x0005, 0x15a0, 0x78a8, 0xd08c,
+	0x0120, 0xb800, 0xc08c, 0xb802, 0x0028, 0x080c, 0x573e, 0xd0b4,
+	0x0904, 0x453d, 0x7884, 0x908e, 0x007e, 0x0904, 0x453d, 0x908e,
+	0x007f, 0x0904, 0x453d, 0x908e, 0x0080, 0x0904, 0x453d, 0xb800,
+	0xd08c, 0x1904, 0x453d, 0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a,
+	0x080c, 0xcb4b, 0x1120, 0x2009, 0x0003, 0x0804, 0x35ea, 0x7007,
+	0x0003, 0x701f, 0x533c, 0x0005, 0x080c, 0x4b25, 0x0904, 0x35ed,
+	0x0804, 0x453d, 0x080c, 0x33a8, 0x0108, 0x0005, 0x2009, 0x1834,
+	0x210c, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x35ea, 0x080c,
+	0x5752, 0x0120, 0x2009, 0x0007, 0x0804, 0x35ea, 0x080c, 0x6ad5,
+	0x0120, 0x2009, 0x0008, 0x0804, 0x35ea, 0xb89c, 0xd0a4, 0x1118,
+	0xd0ac, 0x1904, 0x453d, 0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd,
+	0xa86a, 0x080c, 0xcbb3, 0x1120, 0x2009, 0x0003, 0x0804, 0x35ea,
+	0x7007, 0x0003, 0x701f, 0x5375, 0x0005, 0xa830, 0x9086, 0x0100,
+	0x1120, 0x2009, 0x0004, 0x0804, 0x568c, 0x080c, 0x4b25, 0x0904,
+	0x35ed, 0x0804, 0x530e, 0x81ff, 0x2009, 0x0001, 0x1904, 0x35ea,
+	0x080c, 0x5752, 0x2009, 0x0007, 0x1904, 0x35ea, 0x080c, 0x6ad5,
+	0x0120, 0x2009, 0x0008, 0x0804, 0x35ea, 0x080c, 0x4b25, 0x0904,
+	0x35ed, 0x080c, 0x6add, 0x2009, 0x0009, 0x1904, 0x35ea, 0x080c,
+	0x4af2, 0x2009, 0x0002, 0x0904, 0x35ea, 0x9006, 0xa866, 0xa832,
+	0xa868, 0xc0fd, 0xa86a, 0x7988, 0x9194, 0xff00, 0x918c, 0x00ff,
+	0x9006, 0x82ff, 0x1128, 0xc0ed, 0xa952, 0x798c, 0xa956, 0x0038,
+	0x928e, 0x0100, 0x1904, 0x35ed, 0xc0e5, 0xa952, 0xa956, 0xa83e,
+	0x080c, 0xce16, 0x2009, 0x0003, 0x0904, 0x35ea, 0x7007, 0x0003,
+	0x701f, 0x53cb, 0x0005, 0xa830, 0x9086, 0x0100, 0x2009, 0x0004,
+	0x0904, 0x35ea, 0x0804, 0x35b8, 0x7aa8, 0x9284, 0xc000, 0x0148,
+	0xd2ec, 0x01a0, 0x080c, 0x5752, 0x1188, 0x2009, 0x0014, 0x0804,
+	0x35ea, 0xd2dc, 0x1578, 0x81ff, 0x2009, 0x0001, 0x1904, 0x35ea,
+	0x080c, 0x5752, 0x2009, 0x0007, 0x1904, 0x35ea, 0xd2f4, 0x0138,
+	0x9284, 0x5000, 0xc0d5, 0x080c, 0x5718, 0x0804, 0x35b8, 0xd2fc,
+	0x0160, 0x080c, 0x4b25, 0x0904, 0x35ed, 0x7984, 0x9284, 0x9000,
+	0xc0d5, 0x080c, 0x56e7, 0x0804, 0x35b8, 0x080c, 0x4b25, 0x0904,
+	0x35ed, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x2009, 0x0009,
+	0x1904, 0x54ba, 0x080c, 0x4af2, 0x2009, 0x0002, 0x0904, 0x54ba,
+	0xa85c, 0x9080, 0x001b, 0xaf60, 0x2009, 0x0008, 0x7a8c, 0x7b88,
+	0x7c9c, 0x7d98, 0x080c, 0x4b3b, 0x701f, 0x5427, 0x0005, 0xa86c,
+	0x9086, 0x0500, 0x1138, 0xa870, 0x9005, 0x1120, 0xa874, 0x9084,
+	0xff00, 0x0110, 0x1904, 0x35ed, 0xa866, 0xa832, 0xa868, 0xc0fd,
+	0xa86a, 0x080c, 0x4b25, 0x1110, 0x0804, 0x35ed, 0x2009, 0x0043,
+	0x080c, 0xce7e, 0x2009, 0x0003, 0x0904, 0x54ba, 0x7007, 0x0003,
+	0x701f, 0x544b, 0x0005, 0xa830, 0x9086, 0x0100, 0x2009, 0x0004,
+	0x0904, 0x54ba, 0x7984, 0x7aa8, 0x9284, 0x1000, 0xe085, 0x080c,
+	0x56e7, 0x0804, 0x35b8, 0x00c6, 0xaab0, 0x9284, 0xc000, 0x0148,
+	0xd2ec, 0x0170, 0x080c, 0x5752, 0x1158, 0x2009, 0x0014, 0x0804,
+	0x54a9, 0x2061, 0x1800, 0x080c, 0x5752, 0x2009, 0x0007, 0x15c8,
+	0xd2f4, 0x0130, 0x9284, 0x5000, 0xc0d5, 0x080c, 0x5718, 0x0058,
+	0xd2fc, 0x0180, 0x080c, 0x4b23, 0x0590, 0xa998, 0x9284, 0x9000,
+	0xc0d5, 0x080c, 0x56e7, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897,
+	0x4000, 0x0438, 0x080c, 0x4b23, 0x0510, 0x080c, 0x6add, 0x2009,
+	0x0009, 0x11b8, 0xa8c4, 0x9086, 0x0500, 0x11c8, 0xa8c8, 0x9005,
+	0x11b0, 0xa8cc, 0x9084, 0xff00, 0x1190, 0x080c, 0x4b23, 0x1108,
+	0x0070, 0x2009, 0x004b, 0x080c, 0xce7e, 0x2009, 0x0003, 0x0108,
+	0x0078, 0x0431, 0x19c0, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897,
+	0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x00ce, 0x0005,
+	0x9006, 0x0ce0, 0x7aa8, 0xd2dc, 0x0904, 0x35ea, 0x0016, 0x7984,
+	0x9284, 0x1000, 0xc0fd, 0x080c, 0x56e7, 0x001e, 0x1904, 0x35ea,
+	0x0804, 0x35b8, 0x00f6, 0x2d78, 0xaab0, 0x0021, 0x00fe, 0x0005,
+	0xaab0, 0xc2d5, 0xd2dc, 0x0150, 0x0016, 0xa998, 0x9284, 0x1400,
+	0xc0fd, 0x080c, 0x56e7, 0x001e, 0x9085, 0x0001, 0x0005, 0x81ff,
+	0x0120, 0x2009, 0x0001, 0x0804, 0x35ea, 0x080c, 0x5752, 0x0120,
+	0x2009, 0x0007, 0x0804, 0x35ea, 0x7984, 0x7ea8, 0x96b4, 0x00ff,
+	0x080c, 0x6693, 0x1904, 0x35ed, 0x9186, 0x007f, 0x0138, 0x080c,
+	0x6add, 0x0120, 0x2009, 0x0009, 0x0804, 0x35ea, 0x080c, 0x4af2,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x35ea, 0xa867, 0x0000, 0xa868,
+	0xc0fd, 0xa86a, 0x2001, 0x0100, 0x8007, 0xa80a, 0x080c, 0xcb65,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x35ea, 0x7007, 0x0003, 0x701f,
+	0x551a, 0x0005, 0xa808, 0x8007, 0x9086, 0x0100, 0x1120, 0x2009,
+	0x0004, 0x0804, 0x35ea, 0xa8e0, 0xa866, 0xa810, 0x8007, 0x9084,
+	0x00ff, 0x800c, 0xa814, 0x8007, 0x9084, 0x00ff, 0x8004, 0x9080,
+	0x0002, 0x9108, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x0004, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804,
+	0x4b3e, 0x080c, 0x4af2, 0x1120, 0x2009, 0x0002, 0x0804, 0x35ea,
+	0x7984, 0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff, 0x1118,
+	0x7023, 0x19b2, 0x0040, 0x92c6, 0x0001, 0x1118, 0x7023, 0x19cc,
+	0x0010, 0x0804, 0x35ed, 0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c,
+	0x7d98, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c, 0x4b3b, 0x701f,
+	0x556a, 0x0005, 0x2001, 0x182e, 0x2003, 0x0001, 0xa85c, 0x9080,
+	0x0019, 0x2098, 0xa860, 0x20e0, 0x20a9, 0x001a, 0x7020, 0x20a0,
+	0x20e9, 0x0001, 0x4003, 0x0804, 0x35b8, 0x080c, 0x4af2, 0x1120,
+	0x2009, 0x0002, 0x0804, 0x35ea, 0x7984, 0x9194, 0xff00, 0x918c,
+	0x00ff, 0x8217, 0x82ff, 0x1118, 0x2099, 0x19b2, 0x0040, 0x92c6,
+	0x0001, 0x1118, 0x2099, 0x19cc, 0x0010, 0x0804, 0x35ed, 0xa85c,
+	0x9080, 0x0019, 0x20a0, 0xa860, 0x20e8, 0x20a9, 0x001a, 0x20e1,
+	0x0001, 0x4003, 0x2009, 0x001a, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98,
+	0xa85c, 0x9080, 0x0019, 0xaf60, 0x0804, 0x4b3e, 0x7884, 0x908a,
+	0x1000, 0x1a04, 0x35ed, 0x0126, 0x2091, 0x8000, 0x8003, 0x800b,
+	0x810b, 0x9108, 0x00c6, 0x2061, 0x1a02, 0x6142, 0x00ce, 0x012e,
+	0x0804, 0x35b8, 0x00c6, 0x080c, 0x753d, 0x1160, 0x080c, 0x7840,
+	0x080c, 0x6092, 0x9085, 0x0001, 0x080c, 0x7584, 0x080c, 0x746e,
+	0x080c, 0x0d7d, 0x2061, 0x1800, 0x6030, 0xc09d, 0x6032, 0x080c,
+	0x5f4d, 0x00ce, 0x0005, 0x00c6, 0x2001, 0x1800, 0x2004, 0x908e,
+	0x0000, 0x0904, 0x35ea, 0x7884, 0x9005, 0x0188, 0x7888, 0x2061,
+	0x199b, 0x2c0c, 0x2062, 0x080c, 0x2a48, 0x01a0, 0x080c, 0x2a50,
+	0x0188, 0x080c, 0x2a58, 0x0170, 0x2162, 0x0804, 0x35ed, 0x2061,
+	0x0100, 0x6038, 0x9086, 0x0007, 0x1118, 0x2009, 0x0001, 0x0010,
+	0x2009, 0x0000, 0x7884, 0x9086, 0x0002, 0x15a8, 0x2061, 0x0100,
+	0x6028, 0xc09c, 0x602a, 0x080c, 0xa91e, 0x0026, 0x2011, 0x0003,
+	0x080c, 0xa243, 0x2011, 0x0002, 0x080c, 0xa24d, 0x002e, 0x080c,
+	0xa138, 0x0036, 0x901e, 0x080c, 0xa1b8, 0x003e, 0x080c, 0xa93a,
+	0x60e3, 0x0000, 0x080c, 0xe882, 0x080c, 0xe89d, 0x9085, 0x0001,
+	0x080c, 0x7584, 0x9006, 0x080c, 0x2a7a, 0x2001, 0x1800, 0x2003,
+	0x0004, 0x2001, 0x19a6, 0x2003, 0x0000, 0x0026, 0x2011, 0x0008,
+	0x080c, 0x2ab4, 0x002e, 0x00ce, 0x0804, 0x35b8, 0x81ff, 0x0120,
+	0x2009, 0x0001, 0x0804, 0x35ea, 0x080c, 0x5752, 0x0120, 0x2009,
+	0x0007, 0x0804, 0x35ea, 0x7984, 0x7ea8, 0x96b4, 0x00ff, 0x080c,
+	0x6693, 0x1904, 0x35ed, 0x9186, 0x007f, 0x0138, 0x080c, 0x6add,
+	0x0120, 0x2009, 0x0009, 0x0804, 0x35ea, 0x080c, 0x4af2, 0x1120,
+	0x2009, 0x0002, 0x0804, 0x35ea, 0xa867, 0x0000, 0xa868, 0xc0fd,
+	0xa86a, 0x080c, 0xcb68, 0x1120, 0x2009, 0x0003, 0x0804, 0x35ea,
+	0x7007, 0x0003, 0x701f, 0x5675, 0x0005, 0xa830, 0x9086, 0x0100,
+	0x1120, 0x2009, 0x0004, 0x0804, 0x35ea, 0xa8e0, 0xa866, 0xa834,
+	0x8007, 0x800c, 0xa85c, 0x9080, 0x000c, 0x7a8c, 0x7b88, 0x7c9c,
+	0x7d98, 0xaf60, 0x0804, 0x4b3e, 0xa898, 0x9086, 0x000d, 0x1904,
+	0x35ea, 0x2021, 0x4005, 0x0126, 0x2091, 0x8000, 0x0e04, 0x5699,
+	0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486, 0x4000, 0x0118, 0x7833,
+	0x0011, 0x0010, 0x7833, 0x0010, 0x7883, 0x4005, 0xa998, 0x7986,
+	0xa9a4, 0x799a, 0xa9a8, 0x799e, 0x080c, 0x4b2e, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x7007, 0x0001,
+	0x2091, 0x5000, 0x700f, 0x0000, 0x012e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x00c6, 0x2061, 0x1a02, 0x7984, 0x6152, 0x614e, 0x6057,
+	0x0000, 0x604b, 0x0009, 0x7898, 0x606a, 0x789c, 0x6066, 0x7888,
+	0x6062, 0x788c, 0x605e, 0x2001, 0x1a10, 0x2044, 0x2001, 0x1a17,
+	0xa076, 0xa060, 0xa072, 0xa07b, 0x0001, 0xa07f, 0x0002, 0xa06b,
+	0x0000, 0xa09f, 0x0000, 0x00ce, 0x012e, 0x0804, 0x35b8, 0x0126,
+	0x2091, 0x8000, 0x00b6, 0x00c6, 0x90e4, 0xc000, 0x0198, 0x0006,
+	0xd0d4, 0x0160, 0x0036, 0x2019, 0x0029, 0x080c, 0xa91e, 0x0106,
+	0x080c, 0x336d, 0x010e, 0x090c, 0xa93a, 0x003e, 0x080c, 0xc9c7,
+	0x000e, 0x1198, 0xd0e4, 0x0160, 0x9180, 0x1000, 0x2004, 0x905d,
+	0x0160, 0x080c, 0x60ac, 0x080c, 0xabe2, 0x0110, 0xb817, 0x0000,
+	0x9006, 0x00ce, 0x00be, 0x012e, 0x0005, 0x9085, 0x0001, 0x0cc8,
+	0x0126, 0x2091, 0x8000, 0x0156, 0x2010, 0x900e, 0x20a9, 0x0800,
+	0x0016, 0x9180, 0x1000, 0x2004, 0x9005, 0x0188, 0x9186, 0x007e,
+	0x0170, 0x9186, 0x007f, 0x0158, 0x9186, 0x0080, 0x0140, 0x9186,
+	0x00ff, 0x0128, 0x0026, 0x2200, 0x080c, 0x56e7, 0x002e, 0x001e,
+	0x8108, 0x1f04, 0x5720, 0x015e, 0x012e, 0x0005, 0x2001, 0x1848,
+	0x2004, 0x0005, 0x2001, 0x1867, 0x2004, 0x0005, 0x0006, 0x2001,
+	0x1810, 0x2004, 0xd0d4, 0x000e, 0x0005, 0x2001, 0x180e, 0x2004,
+	0xd0b4, 0x0005, 0x2001, 0x1800, 0x2004, 0x9086, 0x0003, 0x0005,
+	0x0016, 0x00e6, 0x2071, 0x189e, 0x7108, 0x910d, 0x710a, 0x00ee,
+	0x001e, 0x0005, 0x79a4, 0x9182, 0x0081, 0x1a04, 0x35ed, 0x810c,
+	0x0016, 0x080c, 0x4af2, 0x0170, 0x080c, 0x0f4f, 0x2100, 0x2238,
+	0x7d84, 0x7c88, 0x7b8c, 0x7a90, 0x001e, 0x080c, 0x4b3b, 0x701f,
+	0x577e, 0x0005, 0x2009, 0x0002, 0x0804, 0x35ea, 0x2079, 0x0000,
+	0x7d94, 0x7c98, 0x7ba8, 0x7aac, 0x79a4, 0x810c, 0x2061, 0x18b8,
+	0x2c44, 0xa770, 0xa074, 0x2071, 0x189e, 0x080c, 0x4b3e, 0x701f,
+	0x5792, 0x0005, 0x2061, 0x18b8, 0x2c44, 0x0016, 0x0026, 0xa270,
+	0xa174, 0x080c, 0x0f57, 0x002e, 0x001e, 0x080c, 0x1004, 0x9006,
+	0xa802, 0xa806, 0x0804, 0x35b8, 0x0126, 0x0156, 0x0136, 0x0146,
+	0x01c6, 0x01d6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2061, 0x0100,
+	0x2069, 0x0200, 0x2071, 0x1800, 0x6044, 0xd0a4, 0x11e8, 0xd084,
+	0x0118, 0x080c, 0x594d, 0x0068, 0xd08c, 0x0118, 0x080c, 0x5856,
+	0x0040, 0xd094, 0x0118, 0x080c, 0x5826, 0x0018, 0xd09c, 0x0108,
+	0x0099, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e,
+	0x013e, 0x015e, 0x012e, 0x0005, 0x0016, 0x6128, 0xd19c, 0x1110,
+	0xc19d, 0x612a, 0x001e, 0x0c68, 0x0006, 0x7098, 0x9005, 0x000e,
+	0x0120, 0x709b, 0x0000, 0x7093, 0x0000, 0x624c, 0x9286, 0xf0f0,
+	0x1150, 0x6048, 0x9086, 0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090,
+	0x6043, 0x0010, 0x0490, 0x9294, 0xff00, 0x9296, 0xf700, 0x0178,
+	0x7138, 0xd1a4, 0x1160, 0x6240, 0x9295, 0x0100, 0x6242, 0x9294,
+	0x0010, 0x0128, 0x2009, 0x00f7, 0x080c, 0x600e, 0x00f0, 0x6040,
+	0x9084, 0x0010, 0x9085, 0x0140, 0x6042, 0x6043, 0x0000, 0x7087,
+	0x0000, 0x70a3, 0x0001, 0x70c7, 0x0000, 0x70df, 0x0000, 0x2009,
+	0x1d80, 0x200b, 0x0000, 0x7097, 0x0000, 0x708b, 0x000f, 0x2009,
+	0x000f, 0x2011, 0x5ef0, 0x080c, 0x8792, 0x0005, 0x2001, 0x1869,
+	0x2004, 0xd08c, 0x0110, 0x705f, 0xffff, 0x7088, 0x9005, 0x1528,
+	0x2011, 0x5ef0, 0x080c, 0x86c8, 0x6040, 0x9094, 0x0010, 0x9285,
+	0x0020, 0x6042, 0x20a9, 0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04,
+	0x583c, 0x6242, 0x709b, 0x0000, 0x6040, 0x9094, 0x0010, 0x9285,
+	0x0080, 0x6042, 0x6242, 0x0048, 0x6242, 0x709b, 0x0000, 0x708f,
+	0x0000, 0x9006, 0x080c, 0x6097, 0x0000, 0x0005, 0x708c, 0x908a,
+	0x0003, 0x1a0c, 0x0d7d, 0x000b, 0x0005, 0x5860, 0x58b1, 0x594c,
+	0x00f6, 0x0016, 0x6900, 0x918c, 0x0800, 0x708f, 0x0001, 0x2001,
+	0x015d, 0x2003, 0x0000, 0x6803, 0x00fc, 0x20a9, 0x0004, 0x6800,
+	0x9084, 0x00fc, 0x0120, 0x1f04, 0x586f, 0x080c, 0x0d7d, 0x68a0,
+	0x68a2, 0x689c, 0x689e, 0x6898, 0x689a, 0xa001, 0x918d, 0x1600,
+	0x6902, 0x001e, 0x6837, 0x0020, 0x080c, 0x6073, 0x2079, 0x1d00,
+	0x7833, 0x1101, 0x7837, 0x0000, 0x20e1, 0x0001, 0x2099, 0x1805,
+	0x20e9, 0x0001, 0x20a1, 0x1d0e, 0x20a9, 0x0004, 0x4003, 0x080c,
+	0xa713, 0x20e1, 0x0001, 0x2099, 0x1d00, 0x20e9, 0x0000, 0x20a1,
+	0x0240, 0x20a9, 0x0014, 0x4003, 0x60c3, 0x000c, 0x600f, 0x0000,
+	0x080c, 0x5f21, 0x00fe, 0x9006, 0x7092, 0x6043, 0x0008, 0x6042,
+	0x0005, 0x00f6, 0x7090, 0x7093, 0x0000, 0x9025, 0x0904, 0x5929,
+	0x6020, 0xd0b4, 0x1904, 0x5927, 0x71a0, 0x81ff, 0x0904, 0x5915,
+	0x9486, 0x000c, 0x1904, 0x5922, 0x9480, 0x0018, 0x8004, 0x20a8,
+	0x080c, 0x606c, 0x2011, 0x0260, 0x2019, 0x1d00, 0x220c, 0x2304,
+	0x9106, 0x11e8, 0x8210, 0x8318, 0x1f04, 0x58ce, 0x6043, 0x0004,
+	0x2061, 0x0140, 0x605b, 0xbc94, 0x605f, 0xf0f0, 0x2061, 0x0100,
+	0x6043, 0x0006, 0x708f, 0x0002, 0x709b, 0x0002, 0x2009, 0x07d0,
+	0x2011, 0x5ef7, 0x080c, 0x8792, 0x080c, 0x6073, 0x04c0, 0x080c,
+	0x606c, 0x2079, 0x0260, 0x7930, 0x918e, 0x1101, 0x1558, 0x7834,
+	0x9005, 0x1540, 0x7900, 0x918c, 0x00ff, 0x1118, 0x7804, 0x9005,
+	0x0190, 0x080c, 0x606c, 0x2011, 0x026e, 0x2019, 0x1805, 0x20a9,
+	0x0004, 0x220c, 0x2304, 0x9102, 0x0230, 0x11a0, 0x8210, 0x8318,
+	0x1f04, 0x5909, 0x0078, 0x70a3, 0x0000, 0x080c, 0x606c, 0x20e1,
+	0x0000, 0x2099, 0x0260, 0x20e9, 0x0001, 0x20a1, 0x1d00, 0x20a9,
+	0x0014, 0x4003, 0x6043, 0x0008, 0x6043, 0x0000, 0x0010, 0x00fe,
+	0x0005, 0x6040, 0x9085, 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8,
+	0x080c, 0xa713, 0x20e1, 0x0001, 0x2099, 0x1d00, 0x20e9, 0x0000,
+	0x20a1, 0x0240, 0x20a9, 0x0014, 0x4003, 0x60c3, 0x000c, 0x2011,
+	0x19f3, 0x2013, 0x0000, 0x7093, 0x0000, 0x60a3, 0x0056, 0x60a7,
+	0x9575, 0x080c, 0x9ec7, 0x08d8, 0x0005, 0x7098, 0x908a, 0x001d,
+	0x1a0c, 0x0d7d, 0x000b, 0x0005, 0x597e, 0x5991, 0x59ba, 0x59da,
+	0x5a00, 0x5a2f, 0x5a55, 0x5a8d, 0x5ab3, 0x5ae1, 0x5b1c, 0x5b54,
+	0x5b72, 0x5b9d, 0x5bbf, 0x5bda, 0x5be4, 0x5c18, 0x5c3e, 0x5c6d,
+	0x5c93, 0x5ccb, 0x5d0f, 0x5d4c, 0x5d6d, 0x5dc6, 0x5de8, 0x5e16,
+	0x5e16, 0x00c6, 0x2061, 0x1800, 0x6003, 0x0007, 0x2061, 0x0100,
+	0x6004, 0x9084, 0xfff9, 0x6006, 0x00ce, 0x0005, 0x2061, 0x0140,
+	0x605b, 0xbc94, 0x605f, 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0002,
+	0x709b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x5ef7, 0x080c, 0x8792,
+	0x0005, 0x00f6, 0x7090, 0x9086, 0x0014, 0x1510, 0x6042, 0x6020,
+	0xd0b4, 0x11f0, 0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296,
+	0x1102, 0x11a0, 0x7834, 0x9005, 0x1188, 0x7a38, 0xd2fc, 0x0128,
+	0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001, 0x2011, 0x5ef7, 0x080c,
+	0x86c8, 0x709b, 0x0010, 0x080c, 0x5be4, 0x0010, 0x7093, 0x0000,
+	0x00fe, 0x0005, 0x00f6, 0x709b, 0x0003, 0x6043, 0x0004, 0x2011,
+	0x5ef7, 0x080c, 0x86c8, 0x080c, 0x5ff0, 0x2079, 0x0240, 0x7833,
+	0x1102, 0x7837, 0x0000, 0x20a9, 0x0008, 0x9f88, 0x000e, 0x200b,
+	0x0000, 0x8108, 0x1f04, 0x59cf, 0x60c3, 0x0014, 0x080c, 0x5f21,
+	0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x0500, 0x2011, 0x5ef7,
+	0x080c, 0x86c8, 0x9086, 0x0014, 0x11b8, 0x080c, 0x606c, 0x2079,
+	0x0260, 0x7a30, 0x9296, 0x1102, 0x1178, 0x7834, 0x9005, 0x1160,
+	0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001,
+	0x709b, 0x0004, 0x0029, 0x0010, 0x080c, 0x6048, 0x00fe, 0x0005,
+	0x00f6, 0x709b, 0x0005, 0x080c, 0x5ff0, 0x2079, 0x0240, 0x7833,
+	0x1103, 0x7837, 0x0000, 0x080c, 0x606c, 0x080c, 0x604f, 0x1170,
+	0x7084, 0x9005, 0x1158, 0x715c, 0x9186, 0xffff, 0x0138, 0x2011,
+	0x0008, 0x080c, 0x5ea4, 0x0168, 0x080c, 0x6025, 0x20a9, 0x0008,
+	0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e,
+	0x4003, 0x60c3, 0x0014, 0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6,
+	0x7090, 0x9005, 0x0500, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086,
+	0x0014, 0x11b8, 0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296,
+	0x1103, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128,
+	0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001, 0x709b, 0x0006, 0x0029,
+	0x0010, 0x080c, 0x6048, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0007,
+	0x080c, 0x5ff0, 0x2079, 0x0240, 0x7833, 0x1104, 0x7837, 0x0000,
+	0x080c, 0x606c, 0x080c, 0x604f, 0x11b8, 0x7084, 0x9005, 0x11a0,
+	0x7164, 0x9186, 0xffff, 0x0180, 0x9180, 0x33b9, 0x200d, 0x918c,
+	0xff00, 0x810f, 0x2011, 0x0008, 0x080c, 0x5ea4, 0x0180, 0x080c,
+	0x502d, 0x0110, 0x080c, 0x26ca, 0x20a9, 0x0008, 0x20e1, 0x0000,
+	0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3,
+	0x0014, 0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005,
+	0x0500, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0014, 0x11b8,
+	0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1104, 0x1178,
+	0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005,
+	0x1110, 0x70c7, 0x0001, 0x709b, 0x0008, 0x0029, 0x0010, 0x080c,
+	0x6048, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0009, 0x080c, 0x5ff0,
+	0x2079, 0x0240, 0x7833, 0x1105, 0x7837, 0x0100, 0x080c, 0x604f,
+	0x1150, 0x7084, 0x9005, 0x1138, 0x080c, 0x5e17, 0x1188, 0x9085,
+	0x0001, 0x080c, 0x26ca, 0x20a9, 0x0008, 0x080c, 0x606c, 0x20e1,
+	0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003,
+	0x60c3, 0x0014, 0x080c, 0x5f21, 0x0010, 0x080c, 0x5971, 0x00fe,
+	0x0005, 0x00f6, 0x7090, 0x9005, 0x05a8, 0x2011, 0x5ef7, 0x080c,
+	0x86c8, 0x9086, 0x0014, 0x1560, 0x080c, 0x606c, 0x2079, 0x0260,
+	0x7a30, 0x9296, 0x1105, 0x1520, 0x7834, 0x9084, 0x0100, 0x2011,
+	0x0100, 0x921e, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005,
+	0x1110, 0x70c7, 0x0001, 0x709b, 0x000a, 0x00b1, 0x0098, 0x9005,
+	0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7,
+	0x0001, 0x7097, 0x0000, 0x709b, 0x000e, 0x080c, 0x5bbf, 0x0010,
+	0x080c, 0x6048, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x000b, 0x2011,
+	0x1d0e, 0x20e9, 0x0001, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff,
+	0x4304, 0x080c, 0x5ff0, 0x2079, 0x0240, 0x7833, 0x1106, 0x7837,
+	0x0000, 0x080c, 0x604f, 0x0118, 0x2013, 0x0000, 0x0020, 0x7060,
+	0x9085, 0x0100, 0x2012, 0x20a9, 0x0040, 0x2009, 0x024e, 0x2011,
+	0x1d0e, 0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1128, 0x6810,
+	0x8000, 0x6812, 0x2009, 0x0240, 0x1f04, 0x5b41, 0x60c3, 0x0084,
+	0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x01c0,
+	0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0084, 0x1178, 0x080c,
+	0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1106, 0x1138, 0x7834,
+	0x9005, 0x1120, 0x709b, 0x000c, 0x0029, 0x0010, 0x080c, 0x6048,
+	0x00fe, 0x0005, 0x00f6, 0x709b, 0x000d, 0x080c, 0x5ff0, 0x2079,
+	0x0240, 0x7833, 0x1107, 0x7837, 0x0000, 0x080c, 0x606c, 0x20a9,
+	0x0040, 0x2011, 0x026e, 0x2009, 0x024e, 0x220e, 0x8210, 0x8108,
+	0x9186, 0x0260, 0x1150, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240,
+	0x6814, 0x8000, 0x6816, 0x2011, 0x0260, 0x1f04, 0x5b85, 0x60c3,
+	0x0084, 0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005,
+	0x01e0, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0084, 0x1198,
+	0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1107, 0x1158,
+	0x7834, 0x9005, 0x1140, 0x7097, 0x0001, 0x080c, 0x5fc2, 0x709b,
+	0x000e, 0x0029, 0x0010, 0x080c, 0x6048, 0x00fe, 0x0005, 0x918d,
+	0x0001, 0x080c, 0x6097, 0x709b, 0x000f, 0x7093, 0x0000, 0x2061,
+	0x0140, 0x605b, 0xbc85, 0x605f, 0xb5b5, 0x2061, 0x0100, 0x6043,
+	0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011, 0x5ef7, 0x080c,
+	0x86bc, 0x0005, 0x7090, 0x9005, 0x0130, 0x2011, 0x5ef7, 0x080c,
+	0x86c8, 0x709b, 0x0000, 0x0005, 0x709b, 0x0011, 0x080c, 0xa713,
+	0x080c, 0x606c, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000,
+	0x20a1, 0x0240, 0x7490, 0x9480, 0x0018, 0x9080, 0x0007, 0x9084,
+	0x03f8, 0x8004, 0x20a8, 0x4003, 0x080c, 0x604f, 0x11a0, 0x717c,
+	0x81ff, 0x0188, 0x900e, 0x7080, 0x9084, 0x00ff, 0x0160, 0x080c,
+	0x2661, 0x9186, 0x007e, 0x0138, 0x9186, 0x0080, 0x0120, 0x2011,
+	0x0008, 0x080c, 0x5ea4, 0x60c3, 0x0014, 0x080c, 0x5f21, 0x0005,
+	0x00f6, 0x7090, 0x9005, 0x0500, 0x2011, 0x5ef7, 0x080c, 0x86c8,
+	0x9086, 0x0014, 0x11b8, 0x080c, 0x606c, 0x2079, 0x0260, 0x7a30,
+	0x9296, 0x1103, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc,
+	0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7, 0x0001, 0x709b, 0x0012,
+	0x0029, 0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x709b,
+	0x0013, 0x080c, 0x5ffe, 0x2079, 0x0240, 0x7833, 0x1103, 0x7837,
+	0x0000, 0x080c, 0x606c, 0x080c, 0x604f, 0x1170, 0x7084, 0x9005,
+	0x1158, 0x715c, 0x9186, 0xffff, 0x0138, 0x2011, 0x0008, 0x080c,
+	0x5ea4, 0x0168, 0x080c, 0x6025, 0x20a9, 0x0008, 0x20e1, 0x0000,
+	0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3,
+	0x0014, 0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005,
+	0x0500, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0014, 0x11b8,
+	0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1104, 0x1178,
+	0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005,
+	0x1110, 0x70c7, 0x0001, 0x709b, 0x0014, 0x0029, 0x0010, 0x7093,
+	0x0000, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0015, 0x080c, 0x5ffe,
+	0x2079, 0x0240, 0x7833, 0x1104, 0x7837, 0x0000, 0x080c, 0x606c,
+	0x080c, 0x604f, 0x11b8, 0x7084, 0x9005, 0x11a0, 0x7164, 0x9186,
+	0xffff, 0x0180, 0x9180, 0x33b9, 0x200d, 0x918c, 0xff00, 0x810f,
+	0x2011, 0x0008, 0x080c, 0x5ea4, 0x0180, 0x080c, 0x502d, 0x0110,
+	0x080c, 0x26ca, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e,
+	0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c,
+	0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090, 0x9005, 0x05f0, 0x2011,
+	0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0014, 0x15a8, 0x080c, 0x606c,
+	0x2079, 0x0260, 0x7a30, 0x9296, 0x1105, 0x1568, 0x7834, 0x9084,
+	0x0100, 0x2011, 0x0100, 0x921e, 0x1168, 0x9085, 0x0001, 0x080c,
+	0x6097, 0x7a38, 0xd2fc, 0x0128, 0x70c4, 0x9005, 0x1110, 0x70c7,
+	0x0001, 0x0080, 0x9005, 0x11b8, 0x7a38, 0xd2fc, 0x0128, 0x70c4,
+	0x9005, 0x1110, 0x70c7, 0x0001, 0x9085, 0x0001, 0x080c, 0x6097,
+	0x7097, 0x0000, 0x7a38, 0xd2f4, 0x0110, 0x70df, 0x0008, 0x709b,
+	0x0016, 0x0029, 0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x080c,
+	0xa713, 0x080c, 0x606c, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9,
+	0x0000, 0x20a1, 0x0240, 0x20a9, 0x000e, 0x4003, 0x2011, 0x026d,
+	0x2204, 0x9084, 0x0100, 0x2011, 0x024d, 0x2012, 0x2011, 0x026e,
+	0x709b, 0x0017, 0x080c, 0x604f, 0x1150, 0x7084, 0x9005, 0x1138,
+	0x080c, 0x5e17, 0x1188, 0x9085, 0x0001, 0x080c, 0x26ca, 0x20a9,
+	0x0008, 0x080c, 0x606c, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9,
+	0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5f21,
+	0x0010, 0x080c, 0x5971, 0x0005, 0x00f6, 0x7090, 0x9005, 0x01d8,
+	0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0084, 0x1190, 0x080c,
+	0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1106, 0x1150, 0x7834,
+	0x9005, 0x1138, 0x9006, 0x080c, 0x6097, 0x709b, 0x0018, 0x0029,
+	0x0010, 0x7093, 0x0000, 0x00fe, 0x0005, 0x00f6, 0x709b, 0x0019,
+	0x080c, 0x5ffe, 0x2079, 0x0240, 0x7833, 0x1106, 0x7837, 0x0000,
+	0x080c, 0x606c, 0x2009, 0x026e, 0x2039, 0x1d0e, 0x20a9, 0x0040,
+	0x213e, 0x8738, 0x8108, 0x9186, 0x0280, 0x1128, 0x6814, 0x8000,
+	0x6816, 0x2009, 0x0260, 0x1f04, 0x5d80, 0x2039, 0x1d0e, 0x080c,
+	0x604f, 0x11e8, 0x2728, 0x2514, 0x8207, 0x9084, 0x00ff, 0x8000,
+	0x2018, 0x9294, 0x00ff, 0x8007, 0x9205, 0x202a, 0x7060, 0x2310,
+	0x8214, 0x92a0, 0x1d0e, 0x2414, 0x938c, 0x0001, 0x0118, 0x9294,
+	0xff00, 0x0018, 0x9294, 0x00ff, 0x8007, 0x9215, 0x2222, 0x20a9,
+	0x0040, 0x2009, 0x024e, 0x270e, 0x8738, 0x8108, 0x9186, 0x0260,
+	0x1128, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x1f04, 0x5db3,
+	0x60c3, 0x0084, 0x080c, 0x5f21, 0x00fe, 0x0005, 0x00f6, 0x7090,
+	0x9005, 0x01e0, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x9086, 0x0084,
+	0x1198, 0x080c, 0x606c, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1107,
+	0x1158, 0x7834, 0x9005, 0x1140, 0x7097, 0x0001, 0x080c, 0x5fc2,
+	0x709b, 0x001a, 0x0029, 0x0010, 0x7093, 0x0000, 0x00fe, 0x0005,
+	0x9085, 0x0001, 0x080c, 0x6097, 0x709b, 0x001b, 0x080c, 0xa713,
+	0x080c, 0x606c, 0x2011, 0x0260, 0x2009, 0x0240, 0x7490, 0x9480,
+	0x0018, 0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, 0x20a8, 0x220e,
+	0x8210, 0x8108, 0x9186, 0x0260, 0x1150, 0x6810, 0x8000, 0x6812,
+	0x2009, 0x0240, 0x6814, 0x8000, 0x6816, 0x2011, 0x0260, 0x1f04,
+	0x5dff, 0x60c3, 0x0084, 0x080c, 0x5f21, 0x0005, 0x0005, 0x0086,
+	0x0096, 0x2029, 0x1848, 0x252c, 0x20a9, 0x0008, 0x2041, 0x1d0e,
+	0x20e9, 0x0001, 0x28a0, 0x080c, 0x606c, 0x20e1, 0x0000, 0x2099,
+	0x026e, 0x4003, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0108,
+	0x9016, 0x2800, 0x9200, 0x200c, 0x91a6, 0xffff, 0x1148, 0xd5d4,
+	0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x5e31, 0x0804, 0x5ea0,
+	0x82ff, 0x1160, 0xd5d4, 0x0120, 0x91a6, 0x3fff, 0x0d90, 0x0020,
+	0x91a6, 0x3fff, 0x0904, 0x5ea0, 0x918d, 0xc000, 0x20a9, 0x0010,
+	0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4,
+	0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319,
+	0x0008, 0x8318, 0x1f04, 0x5e57, 0x04d8, 0x23a8, 0x2021, 0x0001,
+	0x8426, 0x8425, 0x1f04, 0x5e69, 0x2328, 0x8529, 0x92be, 0x0007,
+	0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0x973a, 0x000e, 0x27a8,
+	0x95a8, 0x0010, 0x1f04, 0x5e78, 0x755e, 0x95c8, 0x33b9, 0x292d,
+	0x95ac, 0x00ff, 0x7582, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c,
+	0x26aa, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0x9405,
+	0x201a, 0x7087, 0x0001, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x20e1,
+	0x0001, 0x2898, 0x20a9, 0x0008, 0x4003, 0x9085, 0x0001, 0x0008,
+	0x9006, 0x009e, 0x008e, 0x0005, 0x0156, 0x01c6, 0x01d6, 0x0136,
+	0x0146, 0x22a8, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000,
+	0x2011, 0x024e, 0x22a0, 0x4003, 0x014e, 0x013e, 0x01de, 0x01ce,
+	0x015e, 0x2118, 0x9026, 0x2001, 0x0007, 0x939a, 0x0010, 0x0218,
+	0x8420, 0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0x939a, 0x0010,
+	0x8421, 0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319,
+	0x1de8, 0x9238, 0x2029, 0x026e, 0x9528, 0x2504, 0x942c, 0x11b8,
+	0x9405, 0x203a, 0x715e, 0x91a0, 0x33b9, 0x242d, 0x95ac, 0x00ff,
+	0x7582, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x26aa, 0x001e,
+	0x60e7, 0x0000, 0x65ea, 0x7087, 0x0001, 0x9084, 0x0000, 0x0005,
+	0x00e6, 0x2071, 0x1800, 0x708b, 0x0000, 0x00ee, 0x0005, 0x00e6,
+	0x00f6, 0x2079, 0x0100, 0x2071, 0x0140, 0x080c, 0x5fb1, 0x080c,
+	0x9ed4, 0x7004, 0x9084, 0x4000, 0x0110, 0x080c, 0x2a8a, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x1826, 0x2073, 0x0000, 0x7840, 0x0026,
+	0x0016, 0x2009, 0x00f7, 0x080c, 0x600e, 0x001e, 0x9094, 0x0010,
+	0x9285, 0x0080, 0x7842, 0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x29e5, 0x0228, 0x2011,
+	0x0101, 0x2204, 0xc0c5, 0x2012, 0x2011, 0x19f3, 0x2013, 0x0000,
+	0x7093, 0x0000, 0x012e, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c,
+	0x9ec7, 0x6144, 0xd184, 0x0120, 0x7198, 0x918d, 0x2000, 0x0018,
+	0x718c, 0x918d, 0x1000, 0x2011, 0x1998, 0x2112, 0x2009, 0x07d0,
+	0x2011, 0x5ef7, 0x080c, 0x8792, 0x0005, 0x0016, 0x0026, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x080c, 0xa91e, 0x080c, 0xabe9, 0x080c,
+	0xa93a, 0x2009, 0x00f7, 0x080c, 0x600e, 0x2061, 0x1a02, 0x900e,
+	0x611a, 0x611e, 0x6172, 0x6176, 0x2061, 0x1800, 0x6003, 0x0001,
+	0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009, 0x1998,
+	0x200b, 0x0000, 0x2009, 0x002d, 0x2011, 0x5f7d, 0x080c, 0x86bc,
+	0x012e, 0x00ce, 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x0471, 0x2071, 0x0100, 0x080c, 0x9ed4, 0x2071,
+	0x0140, 0x7004, 0x9084, 0x4000, 0x0110, 0x080c, 0x2a8a, 0x080c,
+	0x7545, 0x0188, 0x080c, 0x7560, 0x1170, 0x080c, 0x784a, 0x0016,
+	0x080c, 0x2779, 0x2001, 0x196c, 0x2102, 0x001e, 0x080c, 0x7845,
+	0x080c, 0x746e, 0x0050, 0x2009, 0x0001, 0x080c, 0x2a66, 0x2001,
+	0x0001, 0x080c, 0x2606, 0x080c, 0x5f4d, 0x012e, 0x000e, 0x00ee,
+	0x0005, 0x2001, 0x180e, 0x2004, 0xd0bc, 0x0158, 0x0026, 0x0036,
+	0x2011, 0x8017, 0x2001, 0x1998, 0x201c, 0x080c, 0x4b52, 0x003e,
+	0x002e, 0x0005, 0x20a9, 0x0012, 0x20e9, 0x0001, 0x20a1, 0x1d80,
+	0x080c, 0x606c, 0x20e9, 0x0000, 0x2099, 0x026e, 0x0099, 0x20a9,
+	0x0020, 0x080c, 0x6066, 0x2099, 0x0260, 0x20a1, 0x1d92, 0x0051,
+	0x20a9, 0x000e, 0x080c, 0x6069, 0x2099, 0x0260, 0x20a1, 0x1db2,
+	0x0009, 0x0005, 0x0016, 0x0026, 0x3410, 0x3308, 0x2104, 0x8007,
+	0x2012, 0x8108, 0x8210, 0x1f04, 0x5fe6, 0x002e, 0x001e, 0x0005,
+	0x080c, 0xa713, 0x20e1, 0x0001, 0x2099, 0x1d00, 0x20e9, 0x0000,
+	0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x080c, 0xa713,
+	0x080c, 0x606c, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000,
+	0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x00c6, 0x0006,
+	0x2061, 0x0100, 0x810f, 0x2001, 0x1834, 0x2004, 0x9005, 0x1138,
+	0x2001, 0x1818, 0x2004, 0x9084, 0x00ff, 0x9105, 0x0010, 0x9185,
+	0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x080c,
+	0x6ad9, 0x0158, 0x9006, 0x2020, 0x2009, 0x002a, 0x080c, 0xe445,
+	0x2001, 0x180c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x900e,
+	0x080c, 0x3205, 0x080c, 0xd09b, 0x0140, 0x0036, 0x2019, 0xffff,
+	0x2021, 0x0007, 0x080c, 0x4d09, 0x003e, 0x004e, 0x001e, 0x0005,
+	0x080c, 0x5f4d, 0x709b, 0x0000, 0x7093, 0x0000, 0x0005, 0x0006,
+	0x2001, 0x180c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006,
+	0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0x918d,
+	0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x2009, 0x0001,
+	0x0020, 0x2009, 0x0002, 0x0008, 0x900e, 0x6814, 0x9084, 0xffc0,
+	0x910d, 0x6916, 0x0005, 0x00f6, 0x0156, 0x0146, 0x01d6, 0x9006,
+	0x20a9, 0x0080, 0x20e9, 0x0001, 0x20a1, 0x1d00, 0x4004, 0x2079,
+	0x1d00, 0x7803, 0x2200, 0x7807, 0x00ef, 0x780f, 0x00ef, 0x7813,
+	0x0138, 0x7823, 0xffff, 0x7827, 0xffff, 0x01de, 0x014e, 0x015e,
+	0x00fe, 0x0005, 0x2001, 0x1800, 0x2003, 0x0001, 0x0005, 0x2001,
+	0x19a5, 0x0118, 0x2003, 0x0001, 0x0010, 0x2003, 0x0000, 0x0005,
+	0x0156, 0x20a9, 0x0800, 0x2009, 0x1000, 0x9006, 0x200a, 0x8108,
+	0x1f04, 0x60a6, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136,
+	0x0146, 0x2069, 0x1847, 0x9006, 0xb802, 0xb8d6, 0xb807, 0x0707,
+	0xb80a, 0xb80e, 0xb812, 0x9198, 0x33b9, 0x231d, 0x939c, 0x00ff,
+	0xbb16, 0x0016, 0x0026, 0xb886, 0x080c, 0xabe2, 0x1120, 0x9192,
+	0x007e, 0x1208, 0xbb86, 0x20a9, 0x0004, 0xb8c4, 0x20e8, 0xb9c8,
+	0x9198, 0x0006, 0x9006, 0x23a0, 0x4004, 0x20a9, 0x0004, 0x9198,
+	0x000a, 0x23a0, 0x4004, 0x002e, 0x001e, 0xb83e, 0xb842, 0xb8ce,
+	0xb8d2, 0xb85e, 0xb862, 0xb866, 0xb86a, 0xb86f, 0x0100, 0xb872,
+	0xb876, 0xb87a, 0xb88a, 0xb88e, 0xb893, 0x0008, 0xb896, 0xb89a,
+	0xb89e, 0xb8be, 0xb9a2, 0x0096, 0xb8a4, 0x904d, 0x0110, 0x080c,
+	0x1079, 0xb8a7, 0x0000, 0x009e, 0x9006, 0xb84a, 0x6810, 0xb83a,
+	0x680c, 0xb846, 0xb8bb, 0x0520, 0xb8ac, 0x9005, 0x0198, 0x00c6,
+	0x2060, 0x9c82, 0x1ddc, 0x0a0c, 0x0d7d, 0x2001, 0x181a, 0x2004,
+	0x9c02, 0x1a0c, 0x0d7d, 0x080c, 0x8c1f, 0x00ce, 0x090c, 0x8fbc,
+	0xb8af, 0x0000, 0x6814, 0x9084, 0x00ff, 0xb842, 0x014e, 0x013e,
+	0x015e, 0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, 0xa974,
+	0xae78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04, 0x6182, 0x9182,
+	0x0800, 0x1a04, 0x6186, 0x2001, 0x180c, 0x2004, 0x9084, 0x0003,
+	0x1904, 0x618c, 0x9188, 0x1000, 0x2104, 0x905d, 0x0198, 0xb804,
+	0x9084, 0x00ff, 0x908e, 0x0006, 0x1188, 0xb8a4, 0x900d, 0x1904,
+	0x619e, 0x080c, 0x655e, 0x9006, 0x012e, 0x0005, 0x2001, 0x0005,
+	0x900e, 0x04b8, 0x2001, 0x0028, 0x900e, 0x0498, 0x9082, 0x0006,
+	0x1290, 0x080c, 0xabe2, 0x1160, 0xb8a0, 0x9084, 0xff80, 0x1140,
+	0xb900, 0xd1fc, 0x0d10, 0x2001, 0x0029, 0x2009, 0x1000, 0x0408,
+	0x2001, 0x0028, 0x00a8, 0x2009, 0x180c, 0x210c, 0xd18c, 0x0118,
+	0x2001, 0x0004, 0x0068, 0xd184, 0x0118, 0x2001, 0x0004, 0x0040,
+	0x2001, 0x0029, 0xb900, 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0048,
+	0x900e, 0x0038, 0x2001, 0x0029, 0x900e, 0x0018, 0x2001, 0x0029,
+	0x900e, 0x9005, 0x012e, 0x0005, 0x2001, 0x180c, 0x2004, 0xd084,
+	0x19d0, 0x9188, 0x1000, 0x2104, 0x9065, 0x09a8, 0x080c, 0x6add,
+	0x1990, 0xb800, 0xd0bc, 0x0978, 0x0804, 0x6145, 0x080c, 0x6902,
+	0x0904, 0x614e, 0x0804, 0x6149, 0x00e6, 0x2071, 0x19e6, 0x7004,
+	0x9086, 0x0002, 0x1128, 0x7030, 0x9080, 0x0004, 0x2004, 0x9b06,
+	0x00ee, 0x0005, 0x00b6, 0x00e6, 0x0126, 0x2091, 0x8000, 0xa874,
+	0x908e, 0x00ff, 0x1120, 0x2001, 0x196a, 0x205c, 0x0060, 0xa974,
+	0x9182, 0x0800, 0x1690, 0x9188, 0x1000, 0x2104, 0x905d, 0x01d0,
+	0x080c, 0x6a7d, 0x11d0, 0x080c, 0xac5a, 0x0570, 0x2b00, 0x6012,
+	0x2900, 0x6016, 0x6023, 0x0009, 0x602b, 0x0000, 0xa874, 0x908e,
+	0x00ff, 0x1110, 0x602b, 0x8000, 0x2009, 0x0043, 0x080c, 0xad4d,
+	0x9006, 0x00b0, 0x2001, 0x0028, 0x0090, 0x2009, 0x180c, 0x210c,
+	0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001,
+	0x0004, 0x0010, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, 0x9005,
+	0x012e, 0x00ee, 0x00be, 0x0005, 0x2001, 0x002c, 0x0cc0, 0x00b6,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0xa974, 0x9182, 0x0800, 0x1a04,
+	0x627d, 0x9188, 0x1000, 0x2104, 0x905d, 0x0904, 0x6255, 0xb8a0,
+	0x9086, 0x007f, 0x0190, 0xa87c, 0xd0fc, 0x1178, 0x080c, 0x6ae5,
+	0x0160, 0xa994, 0x81ff, 0x0130, 0x908e, 0x0004, 0x0130, 0x908e,
+	0x0005, 0x0118, 0x080c, 0x6add, 0x1598, 0xa87c, 0xd0fc, 0x01e0,
+	0xa894, 0x9005, 0x01c8, 0x2060, 0x0026, 0x2010, 0x080c, 0xc968,
+	0x002e, 0x1120, 0x2001, 0x0008, 0x0804, 0x627f, 0x6020, 0x9086,
+	0x000a, 0x0120, 0x2001, 0x0008, 0x0804, 0x627f, 0x601a, 0x6003,
+	0x0008, 0x2900, 0x6016, 0x0058, 0x080c, 0xac5a, 0x05e8, 0x2b00,
+	0x6012, 0x2900, 0x6016, 0x600b, 0xffff, 0x6023, 0x000a, 0x2009,
+	0x0003, 0x080c, 0xad4d, 0x9006, 0x0458, 0x2001, 0x0028, 0x0438,
+	0x9082, 0x0006, 0x1290, 0x080c, 0xabe2, 0x1160, 0xb8a0, 0x9084,
+	0xff80, 0x1140, 0xb900, 0xd1fc, 0x0900, 0x2001, 0x0029, 0x2009,
+	0x1000, 0x00a8, 0x2001, 0x0028, 0x0090, 0x2009, 0x180c, 0x210c,
+	0xd18c, 0x0118, 0x2001, 0x0004, 0x0050, 0xd184, 0x0118, 0x2001,
+	0x0004, 0x0028, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, 0x9005,
+	0x012e, 0x00ee, 0x00be, 0x0005, 0x2001, 0x002c, 0x0cc0, 0x00f6,
+	0x00b6, 0x0126, 0x2091, 0x8000, 0xa8e0, 0x9005, 0x1550, 0xa8dc,
+	0x9082, 0x0101, 0x1630, 0xa8c8, 0x9005, 0x1518, 0xa8c4, 0x9082,
+	0x0101, 0x12f8, 0xa974, 0x2079, 0x1800, 0x9182, 0x0800, 0x12e8,
+	0x7830, 0x9084, 0x0003, 0x1130, 0xaa98, 0xab94, 0xa878, 0x9084,
+	0x0007, 0x00ea, 0x7930, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e,
+	0x0038, 0x2001, 0x002c, 0x900e, 0x0018, 0x2001, 0x0029, 0x900e,
+	0x9006, 0x0008, 0x9005, 0x012e, 0x00be, 0x00fe, 0x0005, 0x6314,
+	0x62cf, 0x62e6, 0x6314, 0x6314, 0x6314, 0x6314, 0x6314, 0x2100,
+	0x9082, 0x007e, 0x1278, 0x080c, 0x6632, 0x0148, 0x9046, 0xb810,
+	0x9306, 0x1904, 0x631c, 0xb814, 0x9206, 0x15f0, 0x0028, 0xbb12,
+	0xba16, 0x0010, 0x080c, 0x4a05, 0x0150, 0x04b0, 0x080c, 0x6693,
+	0x1598, 0xb810, 0x9306, 0x1580, 0xb814, 0x9206, 0x1568, 0x080c,
+	0xac5a, 0x0530, 0x2b00, 0x6012, 0x080c, 0xce15, 0x2900, 0x6016,
+	0x600b, 0xffff, 0x6023, 0x000a, 0xa878, 0x9086, 0x0001, 0x1170,
+	0x080c, 0x3240, 0x9006, 0x080c, 0x65cf, 0x2001, 0x0002, 0x080c,
+	0x65e3, 0x2001, 0x0200, 0xb86e, 0xb893, 0x0002, 0x2009, 0x0003,
+	0x080c, 0xad4d, 0x9006, 0x0068, 0x2001, 0x0001, 0x900e, 0x0038,
+	0x2001, 0x002c, 0x900e, 0x0018, 0x2001, 0x0028, 0x900e, 0x9005,
+	0x0000, 0x012e, 0x00be, 0x00fe, 0x0005, 0x00b6, 0x00f6, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0xa894, 0x90c6, 0x0015, 0x0904, 0x6507,
+	0x90c6, 0x0056, 0x0904, 0x650b, 0x90c6, 0x0066, 0x0904, 0x650f,
+	0x90c6, 0x0067, 0x0904, 0x6513, 0x90c6, 0x0068, 0x0904, 0x6517,
+	0x90c6, 0x0071, 0x0904, 0x651b, 0x90c6, 0x0074, 0x0904, 0x651f,
+	0x90c6, 0x007c, 0x0904, 0x6523, 0x90c6, 0x007e, 0x0904, 0x6527,
+	0x90c6, 0x0037, 0x0904, 0x652b, 0x9016, 0x2079, 0x1800, 0xa974,
+	0x9186, 0x00ff, 0x0904, 0x6502, 0x9182, 0x0800, 0x1a04, 0x6502,
+	0x080c, 0x6693, 0x1198, 0xb804, 0x9084, 0x00ff, 0x9082, 0x0006,
+	0x1268, 0xa894, 0x90c6, 0x006f, 0x0148, 0x080c, 0xabe2, 0x1904,
+	0x64eb, 0xb8a0, 0x9084, 0xff80, 0x1904, 0x64eb, 0xa894, 0x90c6,
+	0x006f, 0x0158, 0x90c6, 0x005e, 0x0904, 0x644b, 0x90c6, 0x0064,
+	0x0904, 0x6474, 0x2008, 0x0804, 0x640d, 0xa998, 0xa8b0, 0x2040,
+	0x080c, 0xabe2, 0x1120, 0x9182, 0x007f, 0x0a04, 0x640d, 0x9186,
+	0x00ff, 0x0904, 0x640d, 0x9182, 0x0800, 0x1a04, 0x640d, 0xaaa0,
+	0xab9c, 0x787c, 0x9306, 0x11a8, 0x7880, 0x0096, 0x924e, 0x1128,
+	0x2208, 0x2310, 0x009e, 0x0804, 0x640d, 0x080c, 0xabe2, 0x1140,
+	0x99cc, 0xff00, 0x009e, 0x1128, 0x2208, 0x2310, 0x0804, 0x640d,
+	0x009e, 0x080c, 0x4a05, 0x0904, 0x6417, 0x900e, 0x9016, 0x90c6,
+	0x4000, 0x15e0, 0x0006, 0x080c, 0x6986, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0031, 0x20a0, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x0006,
+	0x2098, 0x080c, 0x0fc4, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0035, 0x20a0, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x000a,
+	0x2098, 0x080c, 0x0fc4, 0xa8c4, 0xabc8, 0x9305, 0xabcc, 0x9305,
+	0xabd0, 0x9305, 0xabd4, 0x9305, 0xabd8, 0x9305, 0xabdc, 0x9305,
+	0xabe0, 0x9305, 0x9005, 0x0510, 0x000e, 0x00c8, 0x90c6, 0x4007,
+	0x1110, 0x2408, 0x00a0, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610,
+	0x0070, 0x90c6, 0x4009, 0x1108, 0x0050, 0x90c6, 0x4006, 0x0138,
+	0x2001, 0x4005, 0x2009, 0x000a, 0x0010, 0x2001, 0x4006, 0xa896,
+	0xa99a, 0xaa9e, 0x2001, 0x0030, 0x900e, 0x0478, 0x000e, 0x080c,
+	0xac5a, 0x1130, 0x2001, 0x4005, 0x2009, 0x0003, 0x9016, 0x0c78,
+	0x2b00, 0x6012, 0x080c, 0xce15, 0x2900, 0x6016, 0x6023, 0x0001,
+	0xa868, 0xd88c, 0x0108, 0xc0f5, 0xa86a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x3240, 0x012e, 0x9006, 0x080c, 0x65cf, 0x2001, 0x0002,
+	0x080c, 0x65e3, 0x2009, 0x0002, 0x080c, 0xad4d, 0xa8b0, 0xd094,
+	0x0118, 0xb8d4, 0xc08d, 0xb8d6, 0x9006, 0x9005, 0x012e, 0x00ee,
+	0x00fe, 0x00be, 0x0005, 0x080c, 0x5752, 0x0118, 0x2009, 0x0007,
+	0x00f8, 0xa998, 0xaeb0, 0x080c, 0x6693, 0x1904, 0x6408, 0x9186,
+	0x007f, 0x0130, 0x080c, 0x6add, 0x0118, 0x2009, 0x0009, 0x0080,
+	0x0096, 0x080c, 0x1047, 0x1120, 0x009e, 0x2009, 0x0002, 0x0040,
+	0x2900, 0x009e, 0xa806, 0x080c, 0xcb68, 0x19b0, 0x2009, 0x0003,
+	0x2001, 0x4005, 0x0804, 0x640f, 0xa998, 0xaeb0, 0x080c, 0x6693,
+	0x1904, 0x6408, 0x0096, 0x080c, 0x1047, 0x1128, 0x009e, 0x2009,
+	0x0002, 0x0804, 0x64c8, 0x2900, 0x009e, 0xa806, 0x0096, 0x2048,
+	0x20a9, 0x002b, 0xb8c4, 0x20e0, 0xb8c8, 0x2098, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080,
+	0x0006, 0x20a0, 0xbbc8, 0x9398, 0x0006, 0x2398, 0x080c, 0x0fc4,
+	0x009e, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0xd684,
+	0x1168, 0x080c, 0x573e, 0xd0b4, 0x1118, 0xa89b, 0x000b, 0x00e0,
+	0xb800, 0xd08c, 0x0118, 0xa89b, 0x000c, 0x00b0, 0x080c, 0x6add,
+	0x0118, 0xa89b, 0x0009, 0x0080, 0x080c, 0x5752, 0x0118, 0xa89b,
+	0x0007, 0x0050, 0x080c, 0xcb4b, 0x1904, 0x6444, 0x2009, 0x0003,
+	0x2001, 0x4005, 0x0804, 0x640f, 0xa87b, 0x0030, 0xa897, 0x4005,
+	0xa804, 0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x9080, 0x0002, 0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4,
+	0x2031, 0x0000, 0x2041, 0x1296, 0x080c, 0xb1d4, 0x1904, 0x6444,
+	0x2009, 0x0002, 0x08e8, 0x2001, 0x0028, 0x900e, 0x0804, 0x6445,
+	0x2009, 0x180c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e,
+	0x0804, 0x6445, 0x2001, 0x0029, 0x900e, 0x0804, 0x6445, 0x080c,
+	0x37e7, 0x0804, 0x6446, 0x080c, 0x545b, 0x0804, 0x6446, 0x080c,
+	0x45b9, 0x0804, 0x6446, 0x080c, 0x4632, 0x0804, 0x6446, 0x080c,
+	0x468e, 0x0804, 0x6446, 0x080c, 0x4ac8, 0x0804, 0x6446, 0x080c,
+	0x4d7c, 0x0804, 0x6446, 0x080c, 0x50c3, 0x0804, 0x6446, 0x080c,
+	0x52bc, 0x0804, 0x6446, 0x080c, 0x3a0b, 0x0804, 0x6446, 0x00b6,
+	0xa974, 0xae78, 0x9684, 0x3fff, 0x9082, 0x4000, 0x1608, 0x9182,
+	0x0800, 0x1258, 0x9188, 0x1000, 0x2104, 0x905d, 0x0130, 0x080c,
+	0x6add, 0x1138, 0x00d9, 0x9006, 0x00b0, 0x2001, 0x0028, 0x900e,
+	0x0090, 0x9082, 0x0006, 0x1240, 0xb900, 0xd1fc, 0x0d98, 0x2001,
+	0x0029, 0x2009, 0x1000, 0x0038, 0x2001, 0x0029, 0x900e, 0x0018,
+	0x2001, 0x0029, 0x900e, 0x9005, 0x00be, 0x0005, 0xa877, 0x0000,
+	0xb8d0, 0x9005, 0x1904, 0x65c3, 0xb888, 0x9005, 0x1904, 0x65c3,
+	0xb838, 0xb93c, 0x9102, 0x1a04, 0x65c3, 0x2b10, 0x080c, 0xac87,
+	0x0904, 0x65bf, 0x8108, 0xb93e, 0x6212, 0x2900, 0x6016, 0x6023,
+	0x0003, 0x600b, 0xffff, 0x6007, 0x0040, 0xa878, 0x605e, 0xa880,
+	0x6066, 0xa883, 0x0000, 0xa87c, 0xd0ac, 0x0588, 0xc0dd, 0xa87e,
+	0xa888, 0x8001, 0x1530, 0xa816, 0xa864, 0x9094, 0x00f7, 0x9296,
+	0x0011, 0x11f8, 0x9084, 0x00ff, 0xc0bd, 0x601e, 0xa8ac, 0xaab0,
+	0xa836, 0xaa3a, 0x2001, 0x000f, 0x8001, 0x1df0, 0x2001, 0x8004,
+	0x6003, 0x0004, 0x6046, 0x00f6, 0x2079, 0x0380, 0x7818, 0xd0bc,
+	0x1de8, 0x7833, 0x0010, 0x2c00, 0x7836, 0x781b, 0x8080, 0x00fe,
+	0x0005, 0x080c, 0x1778, 0x601c, 0xc0bd, 0x601e, 0x0c38, 0xd0b4,
+	0x190c, 0x1c86, 0x2001, 0x8004, 0x6003, 0x0002, 0x0c18, 0x81ff,
+	0x1110, 0xb88b, 0x0001, 0x2908, 0xb8cc, 0xb9ce, 0x9005, 0x1110,
+	0xb9d2, 0x0020, 0x0096, 0x2048, 0xa902, 0x009e, 0x0005, 0x00b6,
+	0x0126, 0x00c6, 0x0026, 0x2091, 0x8000, 0x6210, 0x2258, 0xba00,
+	0x9005, 0x0110, 0xc285, 0x0008, 0xc284, 0xba02, 0x002e, 0x00ce,
+	0x012e, 0x00be, 0x0005, 0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000,
+	0x6210, 0x2258, 0xba04, 0x0006, 0x9086, 0x0006, 0x1170, 0xb89c,
+	0xd0ac, 0x0158, 0x080c, 0x6ad9, 0x0140, 0x9284, 0xff00, 0x8007,
+	0x9086, 0x0007, 0x1110, 0x2011, 0x0600, 0x000e, 0x9294, 0xff00,
+	0x9215, 0xba06, 0x0006, 0x9086, 0x0006, 0x1120, 0xba90, 0x82ff,
+	0x090c, 0x0d7d, 0x000e, 0x00ce, 0x012e, 0x00be, 0x0005, 0x00b6,
+	0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, 0x2258, 0xba04, 0x0006,
+	0x9086, 0x0006, 0x1168, 0xb89c, 0xd0a4, 0x0150, 0x080c, 0x6ad5,
+	0x1138, 0x9284, 0x00ff, 0x9086, 0x0007, 0x1110, 0x2011, 0x0006,
+	0x000e, 0x9294, 0x00ff, 0x8007, 0x9215, 0xba06, 0x00ce, 0x012e,
+	0x00be, 0x0005, 0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0005,
+	0x00d6, 0x0026, 0x9190, 0x1000, 0x2204, 0x905d, 0x1188, 0x0096,
+	0x080c, 0x1047, 0x2958, 0x009e, 0x0168, 0x2b00, 0x2012, 0xb85c,
+	0xb8ca, 0xb860, 0xb8c6, 0x9006, 0xb8a6, 0xb8ae, 0x080c, 0x60ac,
+	0x9006, 0x0010, 0x9085, 0x0001, 0x002e, 0x00de, 0x0005, 0x00b6,
+	0x0096, 0x0126, 0x2091, 0x8000, 0x0026, 0x9182, 0x0800, 0x0218,
+	0x9085, 0x0001, 0x0458, 0x00d6, 0x9190, 0x1000, 0x2204, 0x905d,
+	0x0518, 0x2013, 0x0000, 0xb8a4, 0x904d, 0x0110, 0x080c, 0x1079,
+	0x00d6, 0x00c6, 0xb8bc, 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006,
+	0x6014, 0x2048, 0x080c, 0xc97a, 0x0110, 0x080c, 0x0ff9, 0x080c,
+	0xacb0, 0x00ce, 0x0c88, 0x00ce, 0x00de, 0x2b48, 0xb8c8, 0xb85e,
+	0xb8c4, 0xb862, 0x080c, 0x1089, 0x00de, 0x9006, 0x002e, 0x012e,
+	0x009e, 0x00be, 0x0005, 0x0016, 0x9182, 0x0800, 0x0218, 0x9085,
+	0x0001, 0x0030, 0x9188, 0x1000, 0x2104, 0x905d, 0x0dc0, 0x9006,
+	0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x9006, 0xb80a,
+	0xb80e, 0xb800, 0xc08c, 0xb802, 0x080c, 0x753d, 0x1510, 0xb8a0,
+	0x9086, 0x007e, 0x0120, 0x080c, 0xabe2, 0x11d8, 0x0078, 0x7040,
+	0xd0e4, 0x01b8, 0x00c6, 0x2061, 0x1981, 0x7048, 0x2062, 0x704c,
+	0x6006, 0x7050, 0x600a, 0x7054, 0x600e, 0x00ce, 0x703c, 0x2069,
+	0x0140, 0x9005, 0x1110, 0x2001, 0x0001, 0x6886, 0x2069, 0x1800,
+	0x68b6, 0x7040, 0xb85e, 0x7048, 0xb862, 0x704c, 0xb866, 0x20e1,
+	0x0000, 0x2099, 0x0276, 0xb8c4, 0x20e8, 0xb8c8, 0x9088, 0x000a,
+	0x21a0, 0x20a9, 0x0004, 0x4003, 0x2099, 0x027a, 0x9088, 0x0006,
+	0x21a0, 0x20a9, 0x0004, 0x4003, 0x2069, 0x0200, 0x6817, 0x0001,
+	0x7040, 0xb86a, 0x7144, 0xb96e, 0x7048, 0xb872, 0x7050, 0xb876,
+	0x2069, 0x0200, 0x6817, 0x0000, 0xb8a0, 0x9086, 0x007e, 0x1110,
+	0x7144, 0xb96e, 0x9182, 0x0211, 0x1218, 0x2009, 0x0008, 0x0400,
+	0x9182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0, 0x9182, 0x02c1,
+	0x1218, 0x2009, 0x0006, 0x00a0, 0x9182, 0x0349, 0x1218, 0x2009,
+	0x0005, 0x0070, 0x9182, 0x0421, 0x1218, 0x2009, 0x0004, 0x0040,
+	0x9182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010, 0x2009, 0x0002,
+	0xb992, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0016, 0x0026,
+	0x00e6, 0x2071, 0x0260, 0x7034, 0xb896, 0x703c, 0xb89a, 0x7054,
+	0xb89e, 0x0036, 0xbbd4, 0xc384, 0xba00, 0x2009, 0x1867, 0x210c,
+	0xd0bc, 0x0120, 0xd1ec, 0x0110, 0xc2ad, 0x0008, 0xc2ac, 0xd0c4,
+	0x0148, 0xd1e4, 0x0138, 0xc2bd, 0xd0cc, 0x0128, 0xd38c, 0x1108,
+	0xc385, 0x0008, 0xc2bc, 0xba02, 0xbbd6, 0x003e, 0x00ee, 0x002e,
+	0x001e, 0x0005, 0x0096, 0x0126, 0x2091, 0x8000, 0xb8a4, 0x904d,
+	0x0578, 0xa900, 0x81ff, 0x15c0, 0xaa04, 0x9282, 0x0010, 0x16c8,
+	0x0136, 0x0146, 0x01c6, 0x01d6, 0x8906, 0x8006, 0x8007, 0x908c,
+	0x003f, 0x21e0, 0x9084, 0xffc0, 0x9080, 0x0004, 0x2098, 0x2009,
+	0x0010, 0x20a9, 0x0001, 0x4002, 0x9086, 0xffff, 0x0120, 0x8109,
+	0x1dd0, 0x080c, 0x0d7d, 0x3c00, 0x20e8, 0x3300, 0x8001, 0x20a0,
+	0x4604, 0x8210, 0xaa06, 0x01de, 0x01ce, 0x014e, 0x013e, 0x0060,
+	0x080c, 0x1047, 0x0170, 0x2900, 0xb8a6, 0xa803, 0x0000, 0x080c,
+	0x6922, 0xa807, 0x0001, 0xae12, 0x9085, 0x0001, 0x012e, 0x009e,
+	0x0005, 0x9006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x0096, 0xb8a4,
+	0x904d, 0x0188, 0xa800, 0x9005, 0x1150, 0x080c, 0x6931, 0x1158,
+	0xa804, 0x908a, 0x0002, 0x0218, 0x8001, 0xa806, 0x0020, 0x080c,
+	0x1079, 0xb8a7, 0x0000, 0x009e, 0x012e, 0x0005, 0x0096, 0x00c6,
+	0xb888, 0x9005, 0x1904, 0x6817, 0xb8d0, 0x904d, 0x0904, 0x6817,
+	0x080c, 0xac87, 0x0904, 0x6813, 0x8210, 0xba3e, 0xa800, 0xb8d2,
+	0x9005, 0x1108, 0xb8ce, 0x2b00, 0x6012, 0x2900, 0x6016, 0x6023,
+	0x0003, 0x600b, 0xffff, 0x6007, 0x0040, 0xa878, 0x605e, 0xa880,
+	0x9084, 0x00ff, 0x6066, 0xa883, 0x0000, 0xa87c, 0xd0ac, 0x01c8,
+	0xc0dd, 0xa87e, 0xa888, 0x8001, 0x1568, 0xa816, 0xa864, 0x9094,
+	0x00f7, 0x9296, 0x0011, 0x1530, 0x9084, 0x00ff, 0xc0bd, 0x601e,
+	0xa8ac, 0xaab0, 0xa836, 0xaa3a, 0x2001, 0x8004, 0x6003, 0x0004,
+	0x0030, 0x080c, 0x1c86, 0x2001, 0x8004, 0x6003, 0x0002, 0x6046,
+	0x2001, 0x0010, 0x2c08, 0x080c, 0xa90f, 0xb838, 0xba3c, 0x9202,
+	0x0a04, 0x67c4, 0x0020, 0x82ff, 0x1110, 0xb88b, 0x0001, 0x00ce,
+	0x009e, 0x0005, 0x080c, 0x1778, 0x601c, 0xc0bd, 0x601e, 0x08e0,
+	0x00b6, 0x0096, 0x0016, 0x20a9, 0x0800, 0x900e, 0x0016, 0x080c,
+	0x6693, 0x1158, 0xb8d0, 0x904d, 0x0140, 0x3e00, 0x9086, 0x0002,
+	0x1118, 0xb800, 0xd0bc, 0x1108, 0x0041, 0x001e, 0x8108, 0x1f04,
+	0x6826, 0x001e, 0x00be, 0x009e, 0x0005, 0x0096, 0x0016, 0xb8d0,
+	0x904d, 0x0188, 0xa800, 0xb8d2, 0x9005, 0x1108, 0xb8ce, 0x9006,
+	0xa802, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0xcc7f,
+	0x080c, 0x6dee, 0x0c60, 0x001e, 0x009e, 0x0005, 0x0086, 0x9046,
+	0xb8d0, 0x904d, 0x01b0, 0xa86c, 0x9406, 0x1118, 0xa870, 0x9506,
+	0x0128, 0x2940, 0xa800, 0x904d, 0x0160, 0x0ca8, 0xa800, 0x88ff,
+	0x1128, 0xb8d2, 0x9005, 0x1118, 0xb8ce, 0x0008, 0xa002, 0xa803,
+	0x0000, 0x008e, 0x0005, 0x901e, 0x0010, 0x2019, 0x0001, 0x0126,
+	0x2091, 0x8000, 0x00e6, 0x0096, 0x00c6, 0x0086, 0x0026, 0x2071,
+	0x19e6, 0x9046, 0x7028, 0x9065, 0x01e8, 0x6014, 0x2068, 0x83ff,
+	0x0120, 0x605c, 0x9606, 0x0158, 0x0030, 0xa86c, 0x9406, 0x1118,
+	0xa870, 0x9506, 0x0120, 0x2c40, 0x600c, 0x2060, 0x0c60, 0x600c,
+	0x0006, 0x0066, 0x2830, 0x080c, 0xa042, 0x006e, 0x000e, 0x83ff,
+	0x0508, 0x0c08, 0x9046, 0xb8d0, 0x904d, 0x01e0, 0x83ff, 0x0120,
+	0xa878, 0x9606, 0x0158, 0x0030, 0xa86c, 0x9406, 0x1118, 0xa870,
+	0x9506, 0x0120, 0x2940, 0xa800, 0x2048, 0x0c70, 0xb8d0, 0xaa00,
+	0x0026, 0x9906, 0x1110, 0xbad2, 0x0008, 0xa202, 0x000e, 0x83ff,
+	0x0108, 0x0c10, 0x002e, 0x008e, 0x00ce, 0x009e, 0x00ee, 0x012e,
+	0x0005, 0x9016, 0x0489, 0x1110, 0x2011, 0x0001, 0x0005, 0x080c,
+	0x6986, 0x0128, 0x080c, 0xca3b, 0x0010, 0x9085, 0x0001, 0x0005,
+	0x080c, 0x6986, 0x0128, 0x080c, 0xc9dc, 0x0010, 0x9085, 0x0001,
+	0x0005, 0x080c, 0x6986, 0x0128, 0x080c, 0xca38, 0x0010, 0x9085,
+	0x0001, 0x0005, 0x080c, 0x6986, 0x0128, 0x080c, 0xc9fb, 0x0010,
+	0x9085, 0x0001, 0x0005, 0x080c, 0x6986, 0x0128, 0x080c, 0xca7e,
+	0x0010, 0x9085, 0x0001, 0x0005, 0xb8a4, 0x900d, 0x1118, 0x9085,
+	0x0001, 0x0005, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8, 0x890e,
+	0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080,
+	0x0004, 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002, 0x9606,
+	0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0008, 0x9006, 0x01ce,
+	0x013e, 0x0005, 0x0146, 0x01d6, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0004, 0x20a0, 0x20a9, 0x0010, 0x2009, 0xffff, 0x4104, 0x01de,
+	0x014e, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8, 0x890e, 0x810e,
+	0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080, 0x0004,
+	0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002, 0x9606, 0x0128,
+	0x8109, 0x1dd8, 0x9085, 0x0001, 0x0068, 0x0146, 0x01d6, 0x3300,
+	0x8001, 0x20a0, 0x3c00, 0x20e8, 0x2001, 0xffff, 0x4004, 0x01de,
+	0x014e, 0x9006, 0x01ce, 0x013e, 0x0005, 0x0096, 0x0126, 0x2091,
+	0x8000, 0xb8a4, 0x904d, 0x1128, 0x080c, 0x1047, 0x0168, 0x2900,
+	0xb8a6, 0x080c, 0x6922, 0xa803, 0x0001, 0xa807, 0x0000, 0x9085,
+	0x0001, 0x012e, 0x009e, 0x0005, 0x9006, 0x0cd8, 0x0096, 0x0126,
+	0x2091, 0x8000, 0xb8a4, 0x904d, 0x0130, 0xb8a7, 0x0000, 0x080c,
+	0x1079, 0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0xb89c, 0xd0a4,
+	0x0005, 0x00b6, 0x00f6, 0x080c, 0x753d, 0x01b0, 0x71c4, 0x81ff,
+	0x1198, 0x71dc, 0xd19c, 0x0180, 0x2001, 0x007e, 0x9080, 0x1000,
+	0x2004, 0x905d, 0x0148, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006,
+	0x1118, 0xb800, 0xc0ed, 0xb802, 0x2079, 0x1847, 0x7804, 0xd0a4,
+	0x01d0, 0x0156, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x6693,
+	0x1168, 0xb804, 0x9084, 0xff00, 0x8007, 0x9096, 0x0004, 0x0118,
+	0x9086, 0x0006, 0x1118, 0xb800, 0xc0ed, 0xb802, 0x001e, 0x8108,
+	0x1f04, 0x69ad, 0x015e, 0x080c, 0x6a9b, 0x0120, 0x2001, 0x1984,
+	0x200c, 0x0038, 0x2079, 0x1847, 0x7804, 0xd0a4, 0x0130, 0x2009,
+	0x07d0, 0x2011, 0x69d8, 0x080c, 0x8792, 0x00fe, 0x00be, 0x0005,
+	0x00b6, 0x2011, 0x69d8, 0x080c, 0x86c8, 0x080c, 0x6a9b, 0x01d8,
+	0x2001, 0x107e, 0x2004, 0x2058, 0xb900, 0xc1ec, 0xb902, 0x080c,
+	0x6ad9, 0x0130, 0x2009, 0x07d0, 0x2011, 0x69d8, 0x080c, 0x8792,
+	0x00e6, 0x2071, 0x1800, 0x9006, 0x707e, 0x7060, 0x7082, 0x080c,
+	0x3011, 0x00ee, 0x04d0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x900e,
+	0x0016, 0x080c, 0x6693, 0x1558, 0xb800, 0xd0ec, 0x0540, 0x0046,
+	0xbaa0, 0x2220, 0x9006, 0x2009, 0x0029, 0x080c, 0xe445, 0xb800,
+	0xc0e5, 0xc0ec, 0xb802, 0x080c, 0x6ad5, 0x2001, 0x0707, 0x1128,
+	0xb804, 0x9084, 0x00ff, 0x9085, 0x0700, 0xb806, 0x080c, 0xa91e,
+	0x2019, 0x0029, 0x080c, 0x943d, 0x0076, 0x903e, 0x080c, 0x9306,
+	0x900e, 0x080c, 0xe167, 0x007e, 0x004e, 0x080c, 0xa93a, 0x001e,
+	0x8108, 0x1f04, 0x6a00, 0x00ce, 0x015e, 0x00be, 0x0005, 0x00b6,
+	0x6010, 0x2058, 0xb800, 0xc0ec, 0xb802, 0x00be, 0x0005, 0x00b6,
+	0x00c6, 0x0096, 0x080c, 0x1060, 0x090c, 0x0d7d, 0x2958, 0x009e,
+	0x2001, 0x196a, 0x2b02, 0x8b07, 0x8006, 0x8006, 0x908c, 0x003f,
+	0xb9c6, 0x908c, 0xffc0, 0xb9ca, 0xb8af, 0x0000, 0x2009, 0x00ff,
+	0x080c, 0x60ac, 0xb807, 0x0006, 0xb813, 0x00ff, 0xb817, 0xffff,
+	0xb86f, 0x0200, 0xb86c, 0xb893, 0x0002, 0xb8bb, 0x0520, 0xb8a3,
+	0x00ff, 0xb8af, 0x0000, 0x00ce, 0x00be, 0x0005, 0x7810, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0ac, 0x0005, 0x6010, 0x00b6, 0x905d,
+	0x0108, 0xb800, 0x00be, 0xd0bc, 0x0005, 0x0006, 0x0016, 0x0026,
+	0xb804, 0x908c, 0x00ff, 0x9196, 0x0006, 0x0188, 0x9196, 0x0004,
+	0x0170, 0x9196, 0x0005, 0x0158, 0x908c, 0xff00, 0x810f, 0x9196,
+	0x0006, 0x0128, 0x9196, 0x0004, 0x0110, 0x9196, 0x0005, 0x002e,
+	0x001e, 0x000e, 0x0005, 0x00b6, 0x00f6, 0x2001, 0x107e, 0x2004,
+	0x905d, 0x0110, 0xb800, 0xd0ec, 0x00fe, 0x00be, 0x0005, 0x0126,
+	0x0026, 0x2091, 0x8000, 0x0006, 0xbaa0, 0x9290, 0x1000, 0x2204,
+	0x9b06, 0x190c, 0x0d7d, 0x000e, 0xba00, 0x9005, 0x0110, 0xc2fd,
+	0x0008, 0xc2fc, 0xba02, 0x002e, 0x012e, 0x0005, 0x2011, 0x1837,
+	0x2204, 0xd0cc, 0x0138, 0x2001, 0x1982, 0x200c, 0x2011, 0x6acb,
+	0x080c, 0x8792, 0x0005, 0x2011, 0x6acb, 0x080c, 0x86c8, 0x2011,
+	0x1837, 0x2204, 0xc0cc, 0x2012, 0x0005, 0x080c, 0x573e, 0xd0ac,
+	0x0005, 0x080c, 0x573e, 0xd0a4, 0x0005, 0x0016, 0xb904, 0x9184,
+	0x00ff, 0x908e, 0x0006, 0x001e, 0x0005, 0x0016, 0xb904, 0x9184,
+	0xff00, 0x8007, 0x908e, 0x0006, 0x001e, 0x0005, 0x00b6, 0x00f6,
+	0x080c, 0xd09b, 0x0158, 0x70dc, 0x9084, 0x0028, 0x0138, 0x2001,
+	0x107f, 0x2004, 0x905d, 0x0110, 0xb8d4, 0xd094, 0x00fe, 0x00be,
+	0x0005, 0x2071, 0x1910, 0x7003, 0x0001, 0x7007, 0x0000, 0x9006,
+	0x7012, 0x7016, 0x701a, 0x701e, 0x700a, 0x7046, 0x0005, 0x0016,
+	0x00e6, 0x2071, 0x1947, 0x900e, 0x710a, 0x080c, 0x573e, 0xd0fc,
+	0x1140, 0x080c, 0x573e, 0x900e, 0xd09c, 0x0108, 0x8108, 0x7102,
+	0x00f8, 0x2001, 0x1867, 0x200c, 0x9184, 0x0007, 0x0002, 0x6b19,
+	0x6b19, 0x6b19, 0x6b19, 0x6b19, 0x6b2f, 0x6b3d, 0x6b19, 0x7003,
+	0x0003, 0x2009, 0x1868, 0x210c, 0x9184, 0xff00, 0x8007, 0x9005,
+	0x1110, 0x2001, 0x0002, 0x7006, 0x0018, 0x7003, 0x0005, 0x0c88,
+	0x00ee, 0x001e, 0x0005, 0x00e6, 0x2071, 0x0050, 0x684c, 0x9005,
+	0x1150, 0x00e6, 0x2071, 0x1910, 0x7028, 0xc085, 0x702a, 0x00ee,
+	0x9085, 0x0001, 0x0488, 0x6844, 0x9005, 0x0158, 0x080c, 0x78b2,
+	0x6a60, 0x9200, 0x7002, 0x6864, 0x9101, 0x7006, 0x9006, 0x7012,
+	0x7016, 0x6860, 0x7002, 0x6864, 0x7006, 0x6868, 0x700a, 0x686c,
+	0x700e, 0x6844, 0x9005, 0x1110, 0x7012, 0x7016, 0x684c, 0x701a,
+	0x701c, 0x9085, 0x0040, 0x701e, 0x7037, 0x0019, 0x702b, 0x0001,
+	0x00e6, 0x2071, 0x1910, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001,
+	0x700b, 0x0000, 0x00ee, 0x9006, 0x00ee, 0x0005, 0x00e6, 0x0026,
+	0x2071, 0x1947, 0x7000, 0x9015, 0x0904, 0x6df3, 0x9286, 0x0003,
+	0x0904, 0x6c83, 0x9286, 0x0005, 0x0904, 0x6c83, 0x2071, 0x1877,
+	0xa87c, 0x9005, 0x0904, 0x6be4, 0x7140, 0xa868, 0x9102, 0x0a04,
+	0x6df3, 0xa878, 0xd084, 0x15d8, 0xa853, 0x0019, 0x2001, 0x8023,
+	0xa84e, 0x2071, 0x1910, 0x701c, 0x9005, 0x1904, 0x6f8a, 0x0e04,
+	0x6ff8, 0x2071, 0x0000, 0xa850, 0x7032, 0xa84c, 0x7082, 0xa870,
+	0x7086, 0xa86c, 0x708a, 0xa880, 0x708e, 0x7036, 0x0146, 0x01d6,
+	0x0136, 0x01c6, 0x0156, 0x20e9, 0x0000, 0x20a1, 0x002a, 0xa868,
+	0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x4003,
+	0x015e, 0x01ce, 0x013e, 0x01de, 0x014e, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x0804, 0x6c66, 0xa853,
+	0x001b, 0x2001, 0x8027, 0x0820, 0x7004, 0xd08c, 0x1904, 0x6df3,
+	0xa853, 0x001a, 0x2001, 0x8024, 0x0804, 0x6ba8, 0x00e6, 0x0026,
+	0x2071, 0x1947, 0x7000, 0x9015, 0x0904, 0x6df3, 0x9286, 0x0003,
+	0x0904, 0x6c83, 0x9286, 0x0005, 0x0904, 0x6c83, 0xa84f, 0x8022,
+	0xa853, 0x0018, 0x0804, 0x6c4b, 0xa868, 0xd0fc, 0x11d8, 0x00e6,
+	0x0026, 0x2001, 0x1947, 0x2004, 0x9005, 0x0904, 0x6df3, 0xa87c,
+	0xd0bc, 0x1904, 0x6df3, 0xa978, 0xa874, 0x9105, 0x1904, 0x6df3,
+	0x2001, 0x1947, 0x2004, 0x0002, 0x6df3, 0x6c47, 0x6c83, 0x6c83,
+	0x6df3, 0x6c83, 0x0005, 0xa868, 0xd0fc, 0x1500, 0x00e6, 0x0026,
+	0x2009, 0x1947, 0x210c, 0x81ff, 0x0904, 0x6df3, 0xa87c, 0xd0cc,
+	0x0904, 0x6df3, 0xa880, 0x9084, 0x00ff, 0x9086, 0x0001, 0x1904,
+	0x6df3, 0x9186, 0x0003, 0x0904, 0x6c83, 0x9186, 0x0005, 0x0904,
+	0x6c83, 0xa84f, 0x8021, 0xa853, 0x0017, 0x0028, 0x0005, 0xa84f,
+	0x8020, 0xa853, 0x0016, 0x2071, 0x1910, 0x701c, 0x9005, 0x1904,
+	0x6f8a, 0x0e04, 0x6ff8, 0x2071, 0x0000, 0xa84c, 0x7082, 0xa850,
+	0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x2071, 0x1800,
+	0x2011, 0x0001, 0xa804, 0x900d, 0x702c, 0x1158, 0xa802, 0x2900,
+	0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x85ce, 0x002e, 0x00ee,
+	0x0005, 0x0096, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x009e, 0x0c58, 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050,
+	0x2071, 0x1910, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904, 0x6d78,
+	0x782c, 0x908c, 0x0780, 0x190c, 0x7146, 0x8004, 0x8004, 0x8004,
+	0x9084, 0x0003, 0x0002, 0x6ca1, 0x6d78, 0x6cc6, 0x6d13, 0x080c,
+	0x0d7d, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, 0x900d, 0x1170,
+	0x2071, 0x1a02, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004,
+	0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c,
+	0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e,
+	0x70c0, 0x9200, 0x70c2, 0x080c, 0x85ce, 0x0c10, 0x2071, 0x1800,
+	0x2900, 0x7822, 0xa804, 0x900d, 0x15a8, 0x7824, 0x00e6, 0x2071,
+	0x0040, 0x712c, 0xd19c, 0x1170, 0x2009, 0x1830, 0x210c, 0x918a,
+	0x0020, 0x0240, 0x7022, 0x2001, 0x1dc0, 0x200c, 0x8108, 0x2102,
+	0x00ee, 0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e,
+	0x70c0, 0x8000, 0x70c2, 0x080c, 0x85ce, 0x782c, 0x9094, 0x0780,
+	0x190c, 0x7146, 0xd0a4, 0x19c8, 0x2071, 0x1a02, 0x703c, 0x9005,
+	0x1328, 0x2001, 0x1948, 0x2004, 0x8005, 0x703e, 0x00fe, 0x002e,
+	0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210,
+	0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c,
+	0x85ce, 0x0804, 0x6ccd, 0x0096, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2,
+	0x080c, 0x85ce, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4,
+	0x1d60, 0x00ee, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd09c,
+	0x11a0, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x1560, 0x2071,
+	0x1a02, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005,
+	0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x009e, 0x2908, 0x7010,
+	0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008,
+	0x711e, 0x2148, 0xa804, 0x900d, 0x1170, 0x2071, 0x1a02, 0x703c,
+	0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005, 0x703e, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0,
+	0x9200, 0x70c2, 0x080c, 0x85ce, 0x00fe, 0x002e, 0x00ee, 0x0005,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904, 0x6dcd,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd09c, 0x1198, 0x701c,
+	0x904d, 0x0180, 0x7010, 0x8001, 0x7012, 0x1108, 0x701a, 0xa800,
+	0x701e, 0x2900, 0x7822, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146,
+	0xd09c, 0x0d68, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4,
+	0x01b0, 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800, 0x702c, 0xa802,
+	0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c, 0x85ce, 0x782c,
+	0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4, 0x1d60, 0x00ee, 0x2071,
+	0x1a02, 0x703c, 0x9005, 0x1328, 0x2001, 0x1948, 0x2004, 0x8005,
+	0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x85ce, 0x00ee,
+	0x0804, 0x6d88, 0xa868, 0xd0fc, 0x1560, 0x0096, 0xa804, 0xa807,
+	0x0000, 0x904d, 0x190c, 0x0ff9, 0x009e, 0x0018, 0xa868, 0xd0fc,
+	0x1500, 0x00e6, 0x0026, 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050,
+	0x2071, 0x1910, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904, 0x6f08,
+	0x782c, 0x908c, 0x0780, 0x190c, 0x7146, 0x8004, 0x8004, 0x8004,
+	0x9084, 0x0003, 0x0002, 0x6e12, 0x6f08, 0x6e2d, 0x6e9b, 0x080c,
+	0x0d7d, 0x0005, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, 0x900d,
+	0x1120, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0,
+	0x9200, 0x70c2, 0x080c, 0x85ce, 0x0c60, 0x2071, 0x1800, 0x2900,
+	0x7822, 0xa804, 0x900d, 0x1904, 0x6e8a, 0x7830, 0xd0dc, 0x1120,
+	0x00fe, 0x002e, 0x00ee, 0x0005, 0x7824, 0x00e6, 0x2071, 0x0040,
+	0x712c, 0xd19c, 0x1170, 0x2009, 0x1830, 0x210c, 0x918a, 0x0020,
+	0x0240, 0x7022, 0x2001, 0x1dc0, 0x200c, 0x8108, 0x2102, 0x00ee,
+	0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0,
+	0x8000, 0x70c2, 0x080c, 0x85ce, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x7146, 0xd0a4, 0x19c8, 0x0e04, 0x6e81, 0x7838, 0x7938, 0x910e,
+	0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de,
+	0x2001, 0x1921, 0x200c, 0xc184, 0x2102, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x2001, 0x1921, 0x200c, 0xc185, 0x2102, 0x00fe, 0x002e,
+	0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210,
+	0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c,
+	0x85ce, 0x0804, 0x6e3c, 0x0096, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2,
+	0x080c, 0x85ce, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6edb, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11ee, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd09c,
+	0x1170, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x11e0, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x7044, 0xc085, 0x7046, 0x0c58, 0x009e,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1120, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0,
+	0x9200, 0x70c2, 0x080c, 0x85ce, 0x00fe, 0x002e, 0x00ee, 0x0005,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904, 0x6f75,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd09c, 0x11b0, 0x701c,
+	0x904d, 0x0198, 0xa84c, 0x9005, 0x1180, 0x7010, 0x8001, 0x7012,
+	0x1108, 0x701a, 0xa800, 0x701e, 0x2900, 0x7822, 0x782c, 0x9094,
+	0x0780, 0x190c, 0x7146, 0xd09c, 0x0d50, 0x782c, 0x9094, 0x0780,
+	0x190c, 0x7146, 0xd0a4, 0x05a8, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2,
+	0x080c, 0x85ce, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6f6e, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11ee, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x7044, 0xc085,
+	0x7046, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x85ce, 0x00ee,
+	0x0804, 0x6f18, 0x2071, 0x1910, 0xa803, 0x0000, 0x2908, 0x7010,
+	0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008,
+	0x711e, 0x2148, 0xa804, 0x900d, 0x1128, 0x1e04, 0x6fb5, 0x002e,
+	0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904,
+	0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70c0, 0x9200,
+	0x70c2, 0x080c, 0x85ce, 0x0e04, 0x6f9f, 0x2071, 0x1910, 0x701c,
+	0x2048, 0xa84c, 0x900d, 0x0d18, 0x2071, 0x0000, 0x7182, 0xa850,
+	0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0xa850, 0x9082,
+	0x0019, 0x1278, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11ee, 0x2071, 0x1910, 0x080c, 0x7132, 0x002e, 0x00ee,
+	0x0005, 0xa850, 0x9082, 0x001c, 0x1e68, 0xa880, 0x708e, 0x7036,
+	0x0146, 0x01d6, 0x0136, 0x01c6, 0x0156, 0x20e9, 0x0000, 0x20a1,
+	0x002a, 0xa868, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0021,
+	0x2098, 0x4003, 0x015e, 0x01ce, 0x013e, 0x01de, 0x014e, 0x0890,
+	0x2071, 0x1910, 0xa803, 0x0000, 0x2908, 0x7010, 0x8000, 0x7012,
+	0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008, 0x711e, 0x2148,
+	0xa804, 0x900d, 0x1118, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70c0, 0x9200, 0x70c2, 0x080c, 0x85ce, 0x002e,
+	0x00ee, 0x0005, 0x0006, 0xa87c, 0x0006, 0xa867, 0x0103, 0x20a9,
+	0x001c, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001d, 0x20a0, 0x9006,
+	0x4004, 0x000e, 0x9084, 0x00ff, 0xa87e, 0x000e, 0xa87a, 0xa982,
+	0x0005, 0x2071, 0x1910, 0x7004, 0x0002, 0x7045, 0x7046, 0x7131,
+	0x7046, 0x7043, 0x7131, 0x080c, 0x0d7d, 0x0005, 0x2001, 0x1947,
+	0x2004, 0x0002, 0x7050, 0x7050, 0x70ca, 0x70cb, 0x7050, 0x70cb,
+	0x0126, 0x2091, 0x8000, 0x1e0c, 0x7151, 0x701c, 0x904d, 0x0508,
+	0xa84c, 0x9005, 0x0904, 0x709b, 0x0e04, 0x7079, 0xa94c, 0x2071,
+	0x0000, 0x7182, 0xa850, 0x7032, 0xa86c, 0x7086, 0x7036, 0xa870,
+	0x708a, 0xa850, 0x9082, 0x0019, 0x1278, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x2071, 0x1910, 0x080c,
+	0x7132, 0x012e, 0x0804, 0x70c9, 0xa850, 0x9082, 0x001c, 0x1e68,
+	0xa880, 0x708e, 0x7036, 0x0146, 0x01d6, 0x0136, 0x01c6, 0x0156,
+	0x20e9, 0x0000, 0x20a1, 0x002a, 0xa868, 0x20a8, 0xa860, 0x20e0,
+	0xa85c, 0x9080, 0x0021, 0x2098, 0x4003, 0x015e, 0x01ce, 0x013e,
+	0x01de, 0x014e, 0x0890, 0x2001, 0x005b, 0x2004, 0x9094, 0x0780,
+	0x190c, 0x7146, 0xd09c, 0x2071, 0x1910, 0x1510, 0x2071, 0x1910,
+	0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130,
+	0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900, 0x00d6,
+	0x2069, 0x0050, 0x6822, 0x00de, 0x2071, 0x1910, 0x701c, 0x2048,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x0005, 0x0005, 0x00d6, 0x2008, 0x2069, 0x1a02, 0x683c,
+	0x9005, 0x0760, 0x0158, 0x9186, 0x0003, 0x0540, 0x2001, 0x1815,
+	0x2004, 0x2009, 0x1b50, 0x210c, 0x9102, 0x1500, 0x0126, 0x2091,
+	0x8000, 0x2069, 0x0050, 0x693c, 0x6838, 0x9106, 0x0190, 0x0e04,
+	0x70fd, 0x2069, 0x0000, 0x6837, 0x8040, 0x6833, 0x0012, 0x6883,
+	0x8040, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x11ee, 0x2069, 0x1a02, 0x683f, 0xffff, 0x012e, 0x00de, 0x0126,
+	0x2091, 0x8000, 0x1e0c, 0x71b7, 0x701c, 0x904d, 0x0540, 0x2001,
+	0x005b, 0x2004, 0x9094, 0x0780, 0x15c9, 0xd09c, 0x1500, 0x2071,
+	0x1910, 0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003,
+	0x1130, 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900,
+	0x00d6, 0x2069, 0x0050, 0x6822, 0x00de, 0x701c, 0x2048, 0x7010,
+	0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e,
+	0x0005, 0x0005, 0x0126, 0x2091, 0x8000, 0x701c, 0x904d, 0x0160,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x080c, 0x1079, 0x0005, 0x012e, 0x0005, 0x2091, 0x8000,
+	0x0e04, 0x7148, 0x0006, 0x0016, 0x2001, 0x8004, 0x0006, 0x0804,
+	0x0d86, 0x0096, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01c0,
+	0xc084, 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069,
+	0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11ee, 0x00fe, 0x009e, 0x0005,
+	0x782c, 0x9094, 0x0780, 0x1991, 0xd0a4, 0x0db8, 0x00e6, 0x2071,
+	0x1800, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1170,
+	0x2009, 0x1830, 0x210c, 0x918a, 0x0020, 0x0240, 0x7022, 0x2001,
+	0x1dc0, 0x200c, 0x8108, 0x2102, 0x00ee, 0x0058, 0x00ee, 0x2048,
+	0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c,
+	0x85ce, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4, 0x19c8,
+	0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836,
+	0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004,
+	0xd084, 0x190c, 0x11ee, 0x00ee, 0x00fe, 0x009e, 0x0005, 0x00f6,
+	0x2079, 0x0050, 0x7044, 0xd084, 0x01b8, 0xc084, 0x7046, 0x7838,
+	0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833,
+	0x0013, 0x00de, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11ee, 0x00fe, 0x0005, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x7146, 0xd0a4, 0x0db8, 0x00e6, 0x2071, 0x1800, 0x7824, 0x2048,
+	0x702c, 0xa802, 0x2900, 0x702e, 0x70c0, 0x8000, 0x70c2, 0x080c,
+	0x85ce, 0x782c, 0x9094, 0x0780, 0x190c, 0x7146, 0xd0a4, 0x1d70,
+	0x00d6, 0x2069, 0x0050, 0x693c, 0x2069, 0x1947, 0x6808, 0x690a,
+	0x2069, 0x1a02, 0x9102, 0x1118, 0x683c, 0x9005, 0x1328, 0x2001,
+	0x1948, 0x200c, 0x810d, 0x693e, 0x00de, 0x00ee, 0x00fe, 0x0005,
+	0x7098, 0x908a, 0x0029, 0x1a0c, 0x0d7d, 0x9082, 0x001d, 0x003b,
+	0x0026, 0x2011, 0x1e00, 0x080c, 0x2ab4, 0x002e, 0x0005, 0x72e3,
+	0x7269, 0x7285, 0x72af, 0x72d2, 0x7312, 0x7324, 0x7285, 0x72fa,
+	0x7224, 0x7252, 0x7223, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804,
+	0x9005, 0x1180, 0x6808, 0x9005, 0x1518, 0x709b, 0x0028, 0x2069,
+	0x198e, 0x2d04, 0x7002, 0x080c, 0x767e, 0x6028, 0x9085, 0x0600,
+	0x602a, 0x00b0, 0x709b, 0x0028, 0x2069, 0x198e, 0x2d04, 0x7002,
+	0x6028, 0x9085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056,
+	0x2071, 0x1a6a, 0x080c, 0x1b10, 0x005e, 0x004e, 0x003e, 0x00ee,
+	0x00de, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1178,
+	0x6808, 0x9005, 0x1160, 0x709b, 0x0028, 0x2069, 0x198e, 0x2d04,
+	0x7002, 0x080c, 0x7721, 0x6028, 0x9085, 0x0600, 0x602a, 0x00de,
+	0x0005, 0x0006, 0x2001, 0x0090, 0x080c, 0x2a7a, 0x000e, 0x6124,
+	0xd1e4, 0x1190, 0x080c, 0x7395, 0xd1d4, 0x1160, 0xd1dc, 0x1138,
+	0xd1cc, 0x0150, 0x709b, 0x0020, 0x080c, 0x7395, 0x0028, 0x709b,
+	0x001d, 0x0010, 0x709b, 0x001f, 0x0005, 0x2001, 0x0088, 0x080c,
+	0x2a7a, 0x6124, 0xd1cc, 0x11e8, 0xd1dc, 0x11c0, 0xd1e4, 0x1198,
+	0x9184, 0x1e00, 0x11d8, 0x080c, 0x1b35, 0x60e3, 0x0001, 0x600c,
+	0xc0b4, 0x600e, 0x080c, 0x7569, 0x2001, 0x0080, 0x080c, 0x2a7a,
+	0x709b, 0x0028, 0x0058, 0x709b, 0x001e, 0x0040, 0x709b, 0x001d,
+	0x0028, 0x709b, 0x0020, 0x0010, 0x709b, 0x001f, 0x0005, 0x080c,
+	0x1b35, 0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x7569,
+	0x2001, 0x0080, 0x080c, 0x2a7a, 0x6124, 0xd1d4, 0x1180, 0xd1dc,
+	0x1158, 0xd1e4, 0x1130, 0x9184, 0x1e00, 0x1158, 0x709b, 0x0028,
+	0x0040, 0x709b, 0x001e, 0x0028, 0x709b, 0x001d, 0x0010, 0x709b,
+	0x001f, 0x0005, 0x2001, 0x00a0, 0x080c, 0x2a7a, 0x6124, 0xd1dc,
+	0x1138, 0xd1e4, 0x0138, 0x080c, 0x1b35, 0x709b, 0x001e, 0x0010,
+	0x709b, 0x001d, 0x0005, 0x080c, 0x741e, 0x6124, 0xd1dc, 0x1188,
+	0x080c, 0x7395, 0x0016, 0x080c, 0x1b35, 0x001e, 0xd1d4, 0x1128,
+	0xd1e4, 0x0138, 0x709b, 0x001e, 0x0020, 0x709b, 0x001f, 0x080c,
+	0x7395, 0x0005, 0x0006, 0x2001, 0x00a0, 0x080c, 0x2a7a, 0x000e,
+	0x6124, 0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4,
+	0x0140, 0x709b, 0x001e, 0x0028, 0x709b, 0x001d, 0x0010, 0x709b,
+	0x0021, 0x0005, 0x080c, 0x741e, 0x6124, 0xd1d4, 0x1150, 0xd1dc,
+	0x1128, 0xd1e4, 0x0140, 0x709b, 0x001e, 0x0028, 0x709b, 0x001d,
+	0x0010, 0x709b, 0x001f, 0x0005, 0x0006, 0x2001, 0x0090, 0x080c,
+	0x2a7a, 0x000e, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc,
+	0x1128, 0xd1e4, 0x0158, 0x709b, 0x001e, 0x0040, 0x709b, 0x001d,
+	0x0028, 0x709b, 0x0020, 0x0010, 0x709b, 0x001f, 0x0005, 0x0016,
+	0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140,
+	0x2071, 0x1800, 0x2091, 0x8000, 0x080c, 0x753d, 0x11f8, 0x2001,
+	0x180c, 0x200c, 0xd1b4, 0x01d0, 0xc1b4, 0x2102, 0x0026, 0x2011,
+	0x0200, 0x080c, 0x2ab4, 0x002e, 0x080c, 0x2a60, 0x6024, 0xd0cc,
+	0x0148, 0x2001, 0x00a0, 0x080c, 0x2a7a, 0x080c, 0x7840, 0x080c,
+	0x6092, 0x0428, 0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x7557,
+	0x0150, 0x080c, 0x754e, 0x1138, 0x2001, 0x0001, 0x080c, 0x2606,
+	0x080c, 0x7511, 0x00a0, 0x080c, 0x741b, 0x0178, 0x2001, 0x0001,
+	0x080c, 0x2606, 0x7098, 0x9086, 0x001e, 0x0120, 0x7098, 0x9086,
+	0x0022, 0x1118, 0x709b, 0x0025, 0x0010, 0x709b, 0x0021, 0x012e,
+	0x00ee, 0x00de, 0x00ce, 0x001e, 0x0005, 0x0026, 0x2011, 0x73a6,
+	0x080c, 0x87d4, 0x002e, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011,
+	0x73a6, 0x080c, 0x87cb, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6,
+	0x0016, 0x080c, 0x9ed4, 0x2071, 0x1800, 0x080c, 0x733f, 0x001e,
+	0x00fe, 0x00ee, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6,
+	0x00e6, 0x00f6, 0x0126, 0x080c, 0x9ed4, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x2071, 0x1800, 0x2091, 0x8000, 0x6028, 0xc09c, 0x602a,
+	0x080c, 0xa91e, 0x2011, 0x0003, 0x080c, 0xa243, 0x2011, 0x0002,
+	0x080c, 0xa24d, 0x080c, 0xa138, 0x080c, 0x8780, 0x0036, 0x901e,
+	0x080c, 0xa1b8, 0x003e, 0x080c, 0xa93a, 0x60e3, 0x0000, 0x080c,
+	0xe882, 0x080c, 0xe89d, 0x2009, 0x0004, 0x080c, 0x2a66, 0x080c,
+	0x297c, 0x2001, 0x1800, 0x2003, 0x0004, 0x2011, 0x0008, 0x080c,
+	0x2ab4, 0x2011, 0x73a6, 0x080c, 0x87d4, 0x080c, 0x7557, 0x0118,
+	0x9006, 0x080c, 0x2a7a, 0x080c, 0x0bc3, 0x2001, 0x0001, 0x080c,
+	0x2606, 0x012e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x0005, 0x0026, 0x00e6, 0x2011, 0x73b3, 0x2071, 0x1a02,
+	0x701c, 0x9206, 0x1118, 0x7018, 0x9005, 0x0110, 0x9085, 0x0001,
+	0x00ee, 0x002e, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6800, 0x9084,
+	0xfffe, 0x9086, 0x00c0, 0x01b8, 0x2001, 0x00c0, 0x080c, 0x2a7a,
+	0x0156, 0x20a9, 0x002d, 0x1d04, 0x742b, 0x2091, 0x6000, 0x1f04,
+	0x742b, 0x015e, 0x00d6, 0x2069, 0x1800, 0x689c, 0x8001, 0x0220,
+	0x0118, 0x689e, 0x00de, 0x0005, 0x689f, 0x0014, 0x68ec, 0xd0dc,
+	0x0dc8, 0x6800, 0x9086, 0x0001, 0x1da8, 0x080c, 0x87e0, 0x0c90,
+	0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071,
+	0x1800, 0x080c, 0x784f, 0x2001, 0x196c, 0x2003, 0x0000, 0x9006,
+	0x709a, 0x60e2, 0x6886, 0x080c, 0x26d5, 0x9006, 0x080c, 0x2a7a,
+	0x080c, 0x5f4d, 0x0026, 0x2011, 0xffff, 0x080c, 0x2ab4, 0x002e,
+	0x602b, 0x182c, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x2001,
+	0x197c, 0x200c, 0x9186, 0x0000, 0x0158, 0x9186, 0x0001, 0x0158,
+	0x9186, 0x0002, 0x0158, 0x9186, 0x0003, 0x0158, 0x0804, 0x7501,
+	0x709b, 0x0022, 0x0040, 0x709b, 0x0021, 0x0028, 0x709b, 0x0023,
+	0x0010, 0x709b, 0x0024, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001,
+	0x0001, 0x080c, 0x26d5, 0x080c, 0xa91e, 0x0026, 0x080c, 0xabe9,
+	0x002e, 0x080c, 0xa93a, 0x7000, 0x908e, 0x0004, 0x0118, 0x602b,
+	0x0028, 0x0010, 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000,
+	0x20a9, 0x0005, 0x6024, 0xd0ac, 0x0150, 0x012e, 0x015e, 0x080c,
+	0xd09b, 0x0118, 0x9006, 0x080c, 0x2aa4, 0x0804, 0x750d, 0x6800,
+	0x9084, 0x00a1, 0xc0bd, 0x6802, 0x080c, 0x2a60, 0x6904, 0xd1d4,
+	0x1140, 0x2001, 0x0100, 0x080c, 0x2a7a, 0x1f04, 0x74b2, 0x080c,
+	0x7594, 0x012e, 0x015e, 0x080c, 0x754e, 0x0170, 0x6044, 0x9005,
+	0x0130, 0x080c, 0x7594, 0x9006, 0x8001, 0x1df0, 0x0028, 0x6804,
+	0xd0d4, 0x1110, 0x080c, 0x7594, 0x080c, 0xd09b, 0x0118, 0x9006,
+	0x080c, 0x2aa4, 0x0016, 0x0026, 0x7000, 0x908e, 0x0004, 0x0130,
+	0x2009, 0x00c8, 0x2011, 0x73b3, 0x080c, 0x8792, 0x002e, 0x001e,
+	0x080c, 0x85c5, 0x7034, 0xc085, 0x7036, 0x2001, 0x197c, 0x2003,
+	0x0004, 0x080c, 0x7208, 0x080c, 0x754e, 0x0138, 0x6804, 0xd0d4,
+	0x1120, 0xd0dc, 0x1100, 0x080c, 0x7845, 0x00ee, 0x00de, 0x00ce,
+	0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140,
+	0x2071, 0x1800, 0x080c, 0x85dc, 0x080c, 0x85ce, 0x080c, 0x784f,
+	0x2001, 0x196c, 0x2003, 0x0000, 0x9006, 0x709a, 0x60e2, 0x6886,
+	0x080c, 0x26d5, 0x9006, 0x080c, 0x2a7a, 0x6043, 0x0090, 0x6043,
+	0x0010, 0x0026, 0x2011, 0xffff, 0x080c, 0x2ab4, 0x002e, 0x602b,
+	0x182c, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006, 0x2001, 0x197b,
+	0x2004, 0x9086, 0xaaaa, 0x000e, 0x0005, 0x0006, 0x080c, 0x5742,
+	0x9084, 0x0030, 0x9086, 0x0000, 0x000e, 0x0005, 0x0006, 0x080c,
+	0x5742, 0x9084, 0x0030, 0x9086, 0x0030, 0x000e, 0x0005, 0x0006,
+	0x080c, 0x5742, 0x9084, 0x0030, 0x9086, 0x0010, 0x000e, 0x0005,
+	0x0006, 0x080c, 0x5742, 0x9084, 0x0030, 0x9086, 0x0020, 0x000e,
+	0x0005, 0x0036, 0x0016, 0x2001, 0x180c, 0x2004, 0x908c, 0x0013,
+	0x0180, 0x0020, 0x080c, 0x26f5, 0x900e, 0x0028, 0x080c, 0x6ad5,
+	0x1dc8, 0x2009, 0x0002, 0x2019, 0x0028, 0x080c, 0x3205, 0x9006,
+	0x0019, 0x001e, 0x003e, 0x0005, 0x00e6, 0x2071, 0x180c, 0x2e04,
+	0x0130, 0x080c, 0xd094, 0x1128, 0x9085, 0x0010, 0x0010, 0x9084,
+	0xffef, 0x2072, 0x00ee, 0x0005, 0x6050, 0x0006, 0x60ec, 0x0006,
+	0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006, 0x080c, 0x2ad7,
+	0x080c, 0x2b0a, 0x602f, 0x0100, 0x602f, 0x0000, 0x602f, 0x0040,
+	0x602f, 0x0000, 0x20a9, 0x0002, 0x080c, 0x2a41, 0x0026, 0x2011,
+	0x0040, 0x080c, 0x2ab4, 0x002e, 0x000e, 0x602a, 0x000e, 0x6006,
+	0x000e, 0x600e, 0x000e, 0x60ee, 0x60e3, 0x0000, 0x6887, 0x0001,
+	0x2001, 0x0001, 0x080c, 0x26d5, 0x2001, 0x00a0, 0x0006, 0x080c,
+	0xd09b, 0x000e, 0x0130, 0x080c, 0x2a98, 0x9006, 0x080c, 0x2aa4,
+	0x0010, 0x080c, 0x2a7a, 0x000e, 0x6052, 0x6050, 0x0006, 0xc0e5,
+	0x6052, 0x00f6, 0x2079, 0x0100, 0x080c, 0x29ed, 0x00fe, 0x000e,
+	0x6052, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x080c,
+	0xa97c, 0x0158, 0x2001, 0x0386, 0x2004, 0xd0b4, 0x1130, 0x2001,
+	0x0016, 0x080c, 0xa90f, 0x0804, 0x7670, 0x2001, 0x180c, 0x200c,
+	0xc1c4, 0x2102, 0x6028, 0x9084, 0xe1ff, 0x602a, 0x2011, 0x0200,
+	0x080c, 0x2ab4, 0x2001, 0x0090, 0x080c, 0x2a7a, 0x20a9, 0x0366,
+	0x6024, 0xd0cc, 0x1558, 0x1d04, 0x7610, 0x2091, 0x6000, 0x1f04,
+	0x7610, 0x080c, 0xa91e, 0x2011, 0x0003, 0x080c, 0xa243, 0x2011,
+	0x0002, 0x080c, 0xa24d, 0x080c, 0xa138, 0x901e, 0x080c, 0xa1b8,
+	0x2001, 0x0386, 0x2003, 0x7000, 0x080c, 0xa93a, 0x2001, 0x00a0,
+	0x080c, 0x2a7a, 0x080c, 0x7840, 0x080c, 0x6092, 0x080c, 0xd09b,
+	0x0110, 0x080c, 0x0ce9, 0x9085, 0x0001, 0x04c0, 0x080c, 0x1b35,
+	0x60e3, 0x0000, 0x2001, 0x196c, 0x2004, 0x080c, 0x26d5, 0x60e2,
+	0x2001, 0x0080, 0x080c, 0x2a7a, 0x20a9, 0x0366, 0x2011, 0x1e00,
+	0x080c, 0x2ab4, 0x2009, 0x1e00, 0x080c, 0x2a60, 0x6024, 0x910c,
+	0x0140, 0x1d04, 0x764e, 0x2091, 0x6000, 0x1f04, 0x764e, 0x0804,
+	0x7619, 0x2001, 0x0386, 0x2003, 0x7000, 0x6028, 0x9085, 0x1e00,
+	0x602a, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886,
+	0x080c, 0xd09b, 0x0110, 0x080c, 0x0ce9, 0x9006, 0x00ee, 0x00de,
+	0x00ce, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016,
+	0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071,
+	0x1800, 0x7000, 0x9086, 0x0003, 0x1168, 0x2001, 0x020b, 0x2004,
+	0x9084, 0x5540, 0x9086, 0x5540, 0x1128, 0x2069, 0x1a76, 0x2d04,
+	0x8000, 0x206a, 0x2069, 0x0140, 0x6020, 0x9084, 0x00c0, 0x0120,
+	0x6884, 0x9005, 0x1904, 0x76e7, 0x2001, 0x0088, 0x080c, 0x2a7a,
+	0x9006, 0x60e2, 0x6886, 0x080c, 0x26d5, 0x2069, 0x0200, 0x6804,
+	0x9005, 0x1118, 0x6808, 0x9005, 0x01d0, 0x6028, 0x9084, 0xfbff,
+	0x602a, 0x2011, 0x0400, 0x080c, 0x2ab4, 0x2069, 0x198e, 0x7000,
+	0x206a, 0x709b, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04,
+	0x76c7, 0x2091, 0x6000, 0x1f04, 0x76c7, 0x0804, 0x7719, 0x2069,
+	0x0140, 0x20a9, 0x0384, 0x2011, 0x1e00, 0x080c, 0x2ab4, 0x2009,
+	0x1e00, 0x080c, 0x2a60, 0x6024, 0x910c, 0x0528, 0x9084, 0x1a00,
+	0x1510, 0x1d04, 0x76d3, 0x2091, 0x6000, 0x1f04, 0x76d3, 0x080c,
+	0xa91e, 0x2011, 0x0003, 0x080c, 0xa243, 0x2011, 0x0002, 0x080c,
+	0xa24d, 0x080c, 0xa138, 0x901e, 0x080c, 0xa1b8, 0x080c, 0xa93a,
+	0x2001, 0x00a0, 0x080c, 0x2a7a, 0x080c, 0x7840, 0x080c, 0x6092,
+	0x9085, 0x0001, 0x00b0, 0x2001, 0x0080, 0x080c, 0x2a7a, 0x2069,
+	0x0140, 0x60e3, 0x0000, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001,
+	0x0008, 0x6886, 0x2001, 0x196c, 0x2004, 0x080c, 0x26d5, 0x60e2,
+	0x9006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2071, 0x1800, 0x6020, 0x9084, 0x00c0, 0x01e8,
+	0x080c, 0xa91e, 0x2011, 0x0003, 0x080c, 0xa243, 0x2011, 0x0002,
+	0x080c, 0xa24d, 0x080c, 0xa138, 0x901e, 0x080c, 0xa1b8, 0x080c,
+	0xa93a, 0x2069, 0x0140, 0x2001, 0x00a0, 0x080c, 0x2a7a, 0x080c,
+	0x7840, 0x080c, 0x6092, 0x0804, 0x77bc, 0x2001, 0x180c, 0x200c,
+	0xd1b4, 0x1160, 0xc1b5, 0x2102, 0x080c, 0x739b, 0x2069, 0x0140,
+	0x2001, 0x0080, 0x080c, 0x2a7a, 0x60e3, 0x0000, 0x2069, 0x0200,
+	0x6804, 0x9005, 0x1118, 0x6808, 0x9005, 0x0190, 0x6028, 0x9084,
+	0xfdff, 0x602a, 0x2011, 0x0200, 0x080c, 0x2ab4, 0x2069, 0x198e,
+	0x7000, 0x206a, 0x709b, 0x0027, 0x7003, 0x0001, 0x0804, 0x77bc,
+	0x2011, 0x1e00, 0x080c, 0x2ab4, 0x2009, 0x1e00, 0x080c, 0x2a60,
+	0x6024, 0x910c, 0x01c8, 0x9084, 0x1c00, 0x11b0, 0x1d04, 0x7778,
+	0x0006, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c, 0x861c, 0x00ee,
+	0x00de, 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071, 0x1a02, 0x7070,
+	0x00ee, 0x9005, 0x19e8, 0x0400, 0x0026, 0x2011, 0x73b3, 0x080c,
+	0x86c8, 0x2011, 0x73a6, 0x080c, 0x87d4, 0x002e, 0x2069, 0x0140,
+	0x60e3, 0x0000, 0x70b4, 0x9005, 0x1118, 0x6887, 0x0001, 0x0008,
+	0x6886, 0x2001, 0x196c, 0x2004, 0x080c, 0x26d5, 0x60e2, 0x2001,
+	0x180c, 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e,
+	0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036,
+	0x0046, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800, 0x080c,
+	0xd094, 0x1904, 0x782a, 0x7130, 0xd184, 0x1170, 0x080c, 0x33ad,
+	0x0138, 0xc18d, 0x7132, 0x2011, 0x1848, 0x2214, 0xd2ac, 0x1120,
+	0x7030, 0xd08c, 0x0904, 0x782a, 0x2011, 0x1848, 0x220c, 0xd1a4,
+	0x0538, 0x0016, 0x2019, 0x000e, 0x080c, 0xe3b5, 0x0156, 0x00b6,
+	0x20a9, 0x007f, 0x900e, 0x9186, 0x007e, 0x01a0, 0x9186, 0x0080,
+	0x0188, 0x080c, 0x6693, 0x1170, 0x2120, 0x9006, 0x0016, 0x2009,
+	0x000e, 0x080c, 0xe445, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c,
+	0x8979, 0x001e, 0x8108, 0x1f04, 0x77f3, 0x00be, 0x015e, 0x001e,
+	0xd1ac, 0x1148, 0x0016, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c,
+	0x3205, 0x001e, 0x0078, 0x0156, 0x00b6, 0x20a9, 0x007f, 0x900e,
+	0x080c, 0x6693, 0x1110, 0x080c, 0x60ac, 0x8108, 0x1f04, 0x7820,
+	0x00be, 0x015e, 0x080c, 0x1b35, 0x080c, 0xa91e, 0x080c, 0xabe9,
+	0x080c, 0xa93a, 0x60e3, 0x0000, 0x080c, 0x6092, 0x080c, 0x746e,
+	0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e, 0x015e, 0x0005,
+	0x2001, 0x197c, 0x2003, 0x0001, 0x0005, 0x2001, 0x197c, 0x2003,
+	0x0000, 0x0005, 0x2001, 0x197b, 0x2003, 0xaaaa, 0x0005, 0x2001,
+	0x197b, 0x2003, 0x0000, 0x0005, 0x2071, 0x18fa, 0x7003, 0x0000,
+	0x7007, 0x0000, 0x080c, 0x1060, 0x090c, 0x0d7d, 0xa8ab, 0xdcb0,
+	0x2900, 0x704e, 0x080c, 0x1060, 0x090c, 0x0d7d, 0xa8ab, 0xdcb0,
+	0x2900, 0x7052, 0xa867, 0x0000, 0xa86b, 0x0001, 0xa89f, 0x0000,
+	0x0005, 0x00e6, 0x2071, 0x0040, 0x6848, 0x9005, 0x1118, 0x9085,
+	0x0001, 0x04b0, 0x6840, 0x9005, 0x0150, 0x04a1, 0x6a50, 0x9200,
+	0x7002, 0x6854, 0x9101, 0x7006, 0x9006, 0x7012, 0x7016, 0x6850,
+	0x7002, 0x6854, 0x7006, 0x6858, 0x700a, 0x685c, 0x700e, 0x6840,
+	0x9005, 0x1110, 0x7012, 0x7016, 0x6848, 0x701a, 0x701c, 0x9085,
+	0x0040, 0x701e, 0x2001, 0x0019, 0x7036, 0x702b, 0x0001, 0x2001,
+	0x0004, 0x200c, 0x918c, 0xfff7, 0x918d, 0x8000, 0x2102, 0x00d6,
+	0x2069, 0x18fa, 0x6807, 0x0001, 0x00de, 0x080c, 0x7e38, 0x9006,
+	0x00ee, 0x0005, 0x900e, 0x0156, 0x20a9, 0x0006, 0x8003, 0x818d,
+	0x1f04, 0x78b6, 0x015e, 0x0005, 0x2079, 0x0040, 0x2071, 0x18fa,
+	0x7004, 0x0002, 0x78cc, 0x78cd, 0x7919, 0x7974, 0x7a84, 0x78ca,
+	0x78ca, 0x7aae, 0x080c, 0x0d7d, 0x0005, 0x2079, 0x0040, 0x2001,
+	0x1dc0, 0x2003, 0x0000, 0x782c, 0x908c, 0x0780, 0x190c, 0x7f1a,
+	0xd0a4, 0x0578, 0x2001, 0x1dc0, 0x2004, 0x9082, 0x0080, 0x1648,
+	0x1d04, 0x78ea, 0x2001, 0x1a05, 0x200c, 0x8109, 0x0510, 0x2091,
+	0x6000, 0x2102, 0x7824, 0x2048, 0x9006, 0xa802, 0xa806, 0xa864,
+	0x9084, 0x00ff, 0x908a, 0x0040, 0x0610, 0x00c0, 0x2001, 0x1800,
+	0x200c, 0x9186, 0x0003, 0x1168, 0x7004, 0x0002, 0x7909, 0x78d3,
+	0x7909, 0x7907, 0x7909, 0x7909, 0x7909, 0x7909, 0x7909, 0x080c,
+	0x7974, 0x782c, 0xd09c, 0x090c, 0x7e38, 0x0005, 0x9082, 0x005a,
+	0x1218, 0x2100, 0x003b, 0x0c10, 0x080c, 0x79aa, 0x0c90, 0x00e3,
+	0x08e8, 0x0005, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79cc, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79b6, 0x79aa,
+	0x7b9f, 0x79aa, 0x79aa, 0x79aa, 0x79cc, 0x79aa, 0x79b6, 0x7be0,
+	0x7c21, 0x7c68, 0x7c7c, 0x79aa, 0x79aa, 0x79cc, 0x79b6, 0x79e0,
+	0x79aa, 0x7a58, 0x7d27, 0x7d42, 0x79aa, 0x79cc, 0x79aa, 0x79e0,
+	0x79aa, 0x79aa, 0x7a4e, 0x7d42, 0x79aa, 0x79aa, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79f4, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x7ebe,
+	0x79aa, 0x7e68, 0x79aa, 0x7e68, 0x79aa, 0x7a09, 0x79aa, 0x79aa,
+	0x79aa, 0x79aa, 0x79aa, 0x79aa, 0x2079, 0x0040, 0x7004, 0x9086,
+	0x0003, 0x1198, 0x782c, 0x080c, 0x7e61, 0xd0a4, 0x0170, 0x7824,
+	0x2048, 0x9006, 0xa802, 0xa806, 0xa864, 0x9084, 0x00ff, 0x908a,
+	0x001a, 0x1210, 0x002b, 0x0c50, 0x00e9, 0x080c, 0x7e38, 0x0005,
+	0x79aa, 0x79b6, 0x7b8b, 0x79aa, 0x79b6, 0x79aa, 0x79b6, 0x79b6,
+	0x79aa, 0x79b6, 0x7b8b, 0x79b6, 0x79b6, 0x79b6, 0x79b6, 0x79b6,
+	0x79aa, 0x79b6, 0x7b8b, 0x79aa, 0x79aa, 0x79b6, 0x79aa, 0x79aa,
+	0x79aa, 0x79b6, 0x00e6, 0x2071, 0x18fa, 0x2009, 0x0400, 0x0071,
+	0x00ee, 0x0005, 0x2009, 0x1000, 0x0049, 0x0005, 0x2009, 0x2000,
+	0x0029, 0x0005, 0x2009, 0x0800, 0x0009, 0x0005, 0x7007, 0x0001,
+	0xa868, 0x9084, 0x00ff, 0x9105, 0xa86a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6dee, 0x012e, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff,
+	0x0d08, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x7b2d, 0x7007,
+	0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, 0x7b2d, 0x0005,
+	0xa864, 0x8007, 0x9084, 0x00ff, 0x0968, 0x8001, 0x1120, 0x7007,
+	0x0001, 0x0804, 0x7b48, 0x7007, 0x0003, 0x7012, 0x2900, 0x7016,
+	0x701a, 0x704b, 0x7b48, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff,
+	0x0904, 0x79b2, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x7b64,
+	0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, 0x7b64,
+	0x0005, 0xa864, 0x8007, 0x9084, 0x00ff, 0x9086, 0x0001, 0x1904,
+	0x79b2, 0x7007, 0x0001, 0x2009, 0x1834, 0x210c, 0x81ff, 0x11a8,
+	0xa868, 0x9084, 0x00ff, 0xa86a, 0xa883, 0x0000, 0x080c, 0x6325,
+	0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa867, 0x0139, 0xa87a,
+	0xa982, 0x080c, 0x6dee, 0x012e, 0x0ca0, 0xa994, 0x9186, 0x0071,
+	0x0d38, 0x9186, 0x0064, 0x0d20, 0x9186, 0x007c, 0x0d08, 0x9186,
+	0x0028, 0x09f0, 0x9186, 0x0038, 0x09d8, 0x9186, 0x0078, 0x09c0,
+	0x9186, 0x005f, 0x09a8, 0x9186, 0x0056, 0x0990, 0xa897, 0x4005,
+	0xa89b, 0x0001, 0x2001, 0x0030, 0x900e, 0x08a0, 0xa87c, 0x9084,
+	0x00c0, 0x9086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804, 0x7d59,
+	0x2900, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa860, 0x20e0, 0xa85c,
+	0x9080, 0x0030, 0x2098, 0x7050, 0x2040, 0xa060, 0x20e8, 0xa05c,
+	0x9080, 0x0023, 0x20a0, 0x4003, 0xa888, 0x7012, 0x9082, 0x0401,
+	0x1a04, 0x79ba, 0xaab4, 0x928a, 0x0002, 0x1a04, 0x79ba, 0x82ff,
+	0x1138, 0xa8b8, 0xa9bc, 0x9105, 0x0118, 0x2001, 0x7aeb, 0x0018,
+	0x9280, 0x7ae1, 0x2005, 0x7056, 0x7010, 0x9015, 0x0904, 0x7acc,
+	0x080c, 0x1060, 0x1118, 0x7007, 0x0004, 0x0005, 0x2900, 0x7022,
+	0x7054, 0x2060, 0xe000, 0xa866, 0x7050, 0x2040, 0xa95c, 0xe004,
+	0x9100, 0xa076, 0xa860, 0xa072, 0xe008, 0x920a, 0x1210, 0x900e,
+	0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0x9296, 0x0004, 0x0108,
+	0x9108, 0xa17a, 0x810b, 0xa17e, 0x080c, 0x113c, 0xa06c, 0x908e,
+	0x0100, 0x0170, 0x9086, 0x0200, 0x0118, 0x7007, 0x0007, 0x0005,
+	0x7020, 0x2048, 0x080c, 0x1079, 0x7014, 0x2048, 0x0804, 0x79ba,
+	0x7020, 0x2048, 0x7018, 0xa802, 0xa807, 0x0000, 0x2908, 0x2048,
+	0xa906, 0x711a, 0x0804, 0x7a84, 0x7014, 0x2048, 0x7007, 0x0001,
+	0xa8b4, 0x9005, 0x1128, 0xa8b8, 0xa9bc, 0x9105, 0x0108, 0x00b9,
+	0xa864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x0904, 0x7d59, 0x0804,
+	0x7b2d, 0x7ae3, 0x7ae7, 0x0002, 0x001d, 0x0007, 0x0004, 0x000a,
+	0x001b, 0x0005, 0x0006, 0x000a, 0x001d, 0x0005, 0x0004, 0x0076,
+	0x0066, 0xafb8, 0xaebc, 0xa804, 0x2050, 0xb0c0, 0xb0e2, 0xb0bc,
+	0xb0de, 0xb0b8, 0xb0d2, 0xb0b4, 0xb0ce, 0xb6da, 0xb7d6, 0xb0b0,
+	0xb0ca, 0xb0ac, 0xb0c6, 0xb0a8, 0xb0ba, 0xb0a4, 0xb0b6, 0xb6c2,
+	0xb7be, 0xb0a0, 0xb0b2, 0xb09c, 0xb0ae, 0xb098, 0xb0a2, 0xb094,
+	0xb09e, 0xb6aa, 0xb7a6, 0xb090, 0xb09a, 0xb08c, 0xb096, 0xb088,
+	0xb08a, 0xb084, 0xb086, 0xb692, 0xb78e, 0xb080, 0xb082, 0xb07c,
+	0xb07e, 0xb078, 0xb072, 0xb074, 0xb06e, 0xb67a, 0xb776, 0xb004,
+	0x9055, 0x1958, 0x006e, 0x007e, 0x0005, 0x2009, 0x1834, 0x210c,
+	0x81ff, 0x1178, 0x080c, 0x6124, 0x1108, 0x0005, 0x080c, 0x7022,
+	0x0126, 0x2091, 0x8000, 0x080c, 0xcc7f, 0x080c, 0x6dee, 0x012e,
+	0x0ca0, 0x080c, 0xd094, 0x1d70, 0x2001, 0x0028, 0x900e, 0x0c70,
+	0x2009, 0x1834, 0x210c, 0x81ff, 0x1188, 0xa888, 0x9005, 0x0188,
+	0xa883, 0x0000, 0x080c, 0x61b2, 0x1108, 0x0005, 0xa87a, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x6dee, 0x012e, 0x0cb8, 0x2001, 0x0028,
+	0x0ca8, 0x2001, 0x0000, 0x0c90, 0x2009, 0x1834, 0x210c, 0x81ff,
+	0x11d8, 0xa888, 0x9005, 0x01e0, 0xa883, 0x0000, 0xa87c, 0xd0f4,
+	0x0120, 0x080c, 0x6287, 0x1138, 0x0005, 0x9006, 0xa87a, 0x080c,
+	0x61ff, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa87a, 0xa982,
+	0x080c, 0x6dee, 0x012e, 0x0cb0, 0x2001, 0x0028, 0x900e, 0x0c98,
+	0x2001, 0x0000, 0x0c80, 0x7018, 0xa802, 0x2908, 0x2048, 0xa906,
+	0x711a, 0x7010, 0x8001, 0x7012, 0x0118, 0x7007, 0x0003, 0x0030,
+	0x7014, 0x2048, 0x7007, 0x0001, 0x7048, 0x080f, 0x0005, 0x00b6,
+	0x7007, 0x0001, 0xa974, 0xa878, 0x9084, 0x00ff, 0x9096, 0x0004,
+	0x0540, 0x20a9, 0x0001, 0x9096, 0x0001, 0x0190, 0x900e, 0x20a9,
+	0x0800, 0x9096, 0x0002, 0x0160, 0x9005, 0x11d8, 0xa974, 0x080c,
+	0x6693, 0x11b8, 0x0066, 0xae80, 0x080c, 0x67a3, 0x006e, 0x0088,
+	0x0046, 0x2011, 0x180c, 0x2224, 0xc484, 0x2412, 0x004e, 0x00c6,
+	0x080c, 0x6693, 0x1110, 0x080c, 0x6976, 0x8108, 0x1f04, 0x7bc8,
+	0x00ce, 0xa87c, 0xd084, 0x1120, 0x080c, 0x1079, 0x00be, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x6dee, 0x012e, 0x00be, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x080c, 0x6ad9, 0x0580,
+	0x2061, 0x1a6e, 0x6100, 0xd184, 0x0178, 0xa888, 0x9084, 0x00ff,
+	0x1550, 0x6000, 0xd084, 0x0520, 0x6004, 0x9005, 0x1538, 0x6003,
+	0x0000, 0x600b, 0x0000, 0x00c8, 0x2011, 0x0001, 0xa890, 0x9005,
+	0x1110, 0x2001, 0x001e, 0x8000, 0x6016, 0xa888, 0x9084, 0x00ff,
+	0x0178, 0x6006, 0xa888, 0x8007, 0x9084, 0x00ff, 0x0148, 0x600a,
+	0xa888, 0x8000, 0x1108, 0xc28d, 0x6202, 0x012e, 0x0804, 0x7e22,
+	0x012e, 0x0804, 0x7e1c, 0x012e, 0x0804, 0x7e16, 0x012e, 0x0804,
+	0x7e19, 0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x080c, 0x6ad9,
+	0x05e0, 0x2061, 0x1a6e, 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308,
+	0xd08c, 0x1530, 0xac78, 0x9484, 0x0003, 0x0170, 0xa988, 0x918c,
+	0x00ff, 0x8001, 0x1120, 0x2100, 0x9210, 0x0620, 0x0028, 0x8001,
+	0x1508, 0x2100, 0x9212, 0x02f0, 0x9484, 0x000c, 0x0188, 0xa988,
+	0x810f, 0x918c, 0x00ff, 0x9082, 0x0004, 0x1120, 0x2100, 0x9318,
+	0x0288, 0x0030, 0x9082, 0x0004, 0x1168, 0x2100, 0x931a, 0x0250,
+	0xa890, 0x9005, 0x0110, 0x8000, 0x6016, 0x6206, 0x630a, 0x012e,
+	0x0804, 0x7e22, 0x012e, 0x0804, 0x7e1f, 0x012e, 0x0804, 0x7e1c,
+	0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0x1a6e, 0x6300,
+	0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, 0x630a, 0x012e, 0x0804,
+	0x7e30, 0x012e, 0x0804, 0x7e1f, 0x00b6, 0x0126, 0x00c6, 0x2091,
+	0x8000, 0x7007, 0x0001, 0xa87c, 0xd0ac, 0x0148, 0x00c6, 0x2061,
+	0x1a6e, 0x6000, 0x9084, 0xfcff, 0x6002, 0x00ce, 0x0440, 0xa888,
+	0x9005, 0x05d8, 0xa88c, 0x9065, 0x0598, 0x2001, 0x1834, 0x2004,
+	0x9005, 0x0118, 0x080c, 0xaceb, 0x0068, 0x6017, 0xf400, 0x6063,
+	0x0000, 0xa97c, 0xd1a4, 0x0110, 0xa980, 0x6162, 0x2009, 0x0041,
+	0x080c, 0xad4d, 0xa988, 0x918c, 0xff00, 0x9186, 0x2000, 0x1138,
+	0x0026, 0x900e, 0x2011, 0xfdff, 0x080c, 0x8979, 0x002e, 0xa87c,
+	0xd0c4, 0x0148, 0x2061, 0x1a6e, 0x6000, 0xd08c, 0x1120, 0x6008,
+	0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, 0x00be, 0x0804, 0x7e22,
+	0x00ce, 0x012e, 0x00be, 0x0804, 0x7e1c, 0xa984, 0x9186, 0x002e,
+	0x0d30, 0x9186, 0x002d, 0x0d18, 0x9186, 0x0045, 0x0510, 0x9186,
+	0x002a, 0x1130, 0x2001, 0x180c, 0x200c, 0xc194, 0x2102, 0x08b8,
+	0x9186, 0x0020, 0x0158, 0x9186, 0x0029, 0x1d10, 0xa974, 0x080c,
+	0x6693, 0x1968, 0xb800, 0xc0e4, 0xb802, 0x0848, 0xa88c, 0x9065,
+	0x09b8, 0x6007, 0x0024, 0x2001, 0x1985, 0x2004, 0x601a, 0x0804,
+	0x7cb7, 0xa88c, 0x9065, 0x0960, 0x00e6, 0xa890, 0x9075, 0x2001,
+	0x1834, 0x2004, 0x9005, 0x0150, 0x080c, 0xaceb, 0x8eff, 0x0118,
+	0x2e60, 0x080c, 0xaceb, 0x00ee, 0x0804, 0x7cb7, 0x6024, 0xc0dc,
+	0xc0d5, 0x6026, 0x2e60, 0x6007, 0x003a, 0xa8a0, 0x9005, 0x0130,
+	0x6007, 0x003b, 0xa8a4, 0x602e, 0xa8a8, 0x6016, 0x6003, 0x0001,
+	0x2009, 0x8020, 0x080c, 0x92b0, 0x00ee, 0x0804, 0x7cb7, 0x2061,
+	0x1a6e, 0x6000, 0xd084, 0x0190, 0xd08c, 0x1904, 0x7e30, 0x0126,
+	0x2091, 0x8000, 0x6204, 0x8210, 0x0220, 0x6206, 0x012e, 0x0804,
+	0x7e30, 0x012e, 0xa883, 0x0016, 0x0804, 0x7e29, 0xa883, 0x0007,
+	0x0804, 0x7e29, 0xa864, 0x8007, 0x9084, 0x00ff, 0x0130, 0x8001,
+	0x1138, 0x7007, 0x0001, 0x0069, 0x0005, 0x080c, 0x79b2, 0x0040,
+	0x7007, 0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, 0x7d59,
+	0x0005, 0x00b6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x903e, 0x2061,
+	0x1800, 0x61d0, 0x81ff, 0x1904, 0x7ddb, 0x6130, 0xd194, 0x1904,
+	0x7e05, 0xa878, 0x2070, 0x9e82, 0x1ddc, 0x0a04, 0x7dcf, 0x6068,
+	0x9e02, 0x1a04, 0x7dcf, 0x7120, 0x9186, 0x0006, 0x1904, 0x7dc1,
+	0x7010, 0x905d, 0x0904, 0x7ddb, 0xb800, 0xd0e4, 0x1904, 0x7dff,
+	0x2061, 0x1a6e, 0x6100, 0x9184, 0x0301, 0x9086, 0x0001, 0x15a0,
+	0x7024, 0xd0dc, 0x1904, 0x7e08, 0xa883, 0x0000, 0xa803, 0x0000,
+	0x2908, 0x7014, 0x9005, 0x1198, 0x7116, 0xa87c, 0xd0f4, 0x1904,
+	0x7e0b, 0x080c, 0x573e, 0xd09c, 0x1118, 0xa87c, 0xc0cc, 0xa87e,
+	0x2e60, 0x080c, 0x8869, 0x012e, 0x00ee, 0x00be, 0x0005, 0x2048,
+	0xa800, 0x9005, 0x1de0, 0xa902, 0x2148, 0xa87c, 0xd0f4, 0x1904,
+	0x7e0b, 0x012e, 0x00ee, 0x00be, 0x0005, 0x012e, 0x00ee, 0xa883,
+	0x0006, 0x00be, 0x0804, 0x7e29, 0xd184, 0x0db8, 0xd1c4, 0x1190,
+	0x00a0, 0xa974, 0x080c, 0x6693, 0x15d0, 0xb800, 0xd0e4, 0x15b8,
+	0x7120, 0x9186, 0x0007, 0x1118, 0xa883, 0x0002, 0x0490, 0xa883,
+	0x0008, 0x0478, 0xa883, 0x000e, 0x0460, 0xa883, 0x0017, 0x0448,
+	0xa883, 0x0035, 0x0430, 0x080c, 0x5742, 0xd0fc, 0x01e8, 0xa878,
+	0x2070, 0x9e82, 0x1ddc, 0x02c0, 0x6068, 0x9e02, 0x12a8, 0x7120,
+	0x9186, 0x0006, 0x1188, 0x7010, 0x905d, 0x0170, 0xb800, 0xd0bc,
+	0x0158, 0x2039, 0x0001, 0x7000, 0x9086, 0x0007, 0x1904, 0x7d65,
+	0x7003, 0x0002, 0x0804, 0x7d65, 0xa883, 0x0028, 0x0010, 0xa883,
+	0x0029, 0x012e, 0x00ee, 0x00be, 0x0420, 0xa883, 0x002a, 0x0cc8,
+	0xa883, 0x0045, 0x0cb0, 0x2e60, 0x2019, 0x0002, 0x601b, 0x0014,
+	0x080c, 0xdfa1, 0x012e, 0x00ee, 0x00be, 0x0005, 0x2009, 0x003e,
+	0x0058, 0x2009, 0x0004, 0x0040, 0x2009, 0x0006, 0x0028, 0x2009,
+	0x0016, 0x0010, 0x2009, 0x0001, 0xa884, 0x9084, 0xff00, 0x9105,
+	0xa886, 0x0126, 0x2091, 0x8000, 0x080c, 0x6dee, 0x012e, 0x0005,
+	0x080c, 0x1079, 0x0005, 0x00d6, 0x080c, 0x8860, 0x00de, 0x0005,
+	0x00d6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x0040, 0x702c,
+	0xd084, 0x01d8, 0x908c, 0x0780, 0x190c, 0x7f1a, 0xd09c, 0x11a8,
+	0x2071, 0x1800, 0x70c0, 0x90ea, 0x0020, 0x0278, 0x8001, 0x70c2,
+	0x702c, 0x2048, 0xa800, 0x702e, 0x9006, 0xa802, 0xa806, 0x2071,
+	0x0040, 0x2900, 0x7022, 0x702c, 0x0c28, 0x012e, 0x00ee, 0x00de,
+	0x0005, 0x0006, 0x9084, 0x0780, 0x190c, 0x7f1a, 0x000e, 0x0005,
+	0xa898, 0x9084, 0x0003, 0x05a8, 0x080c, 0xac5a, 0x05d8, 0x2900,
+	0x6016, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0035, 0x1138, 0x6028,
+	0xc0fd, 0x602a, 0x2001, 0x196a, 0x2004, 0x0098, 0xa8a0, 0x9084,
+	0x00ff, 0xa99c, 0x918c, 0xff00, 0x9105, 0xa99c, 0x918c, 0x00ff,
+	0x080c, 0x2661, 0x1540, 0x00b6, 0x080c, 0x6693, 0x2b00, 0x00be,
+	0x1510, 0x6012, 0x6023, 0x0001, 0x2009, 0x0040, 0xa864, 0x9084,
+	0x00ff, 0x9086, 0x0035, 0x0110, 0x2009, 0x0041, 0x080c, 0xad4d,
+	0x0005, 0xa87b, 0x0101, 0x0126, 0x2091, 0x8000, 0x080c, 0x6dee,
+	0x012e, 0x0005, 0xa87b, 0x002c, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6dee, 0x012e, 0x0005, 0xa87b, 0x0028, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6dee, 0x012e, 0x080c, 0xacb0, 0x0005, 0x00d6, 0x00c6,
+	0x0036, 0x0026, 0x0016, 0x00b6, 0x7007, 0x0001, 0xaa74, 0x9282,
+	0x0004, 0x1a04, 0x7f0b, 0xa97c, 0x9188, 0x1000, 0x2104, 0x905d,
+	0xb804, 0xd284, 0x0140, 0x05e8, 0x8007, 0x9084, 0x00ff, 0x9084,
+	0x0006, 0x1108, 0x04b0, 0x2b10, 0x080c, 0xac5a, 0x1118, 0x080c,
+	0xad20, 0x05a8, 0x6212, 0xa874, 0x0002, 0x7ee9, 0x7eee, 0x7ef1,
+	0x7ef7, 0x2019, 0x0002, 0x080c, 0xe3b5, 0x0060, 0x080c, 0xe345,
+	0x0048, 0x2019, 0x0002, 0xa980, 0x080c, 0xe364, 0x0018, 0xa980,
+	0x080c, 0xe345, 0x080c, 0xacb0, 0xa887, 0x0000, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6dee, 0x012e, 0x00be, 0x001e, 0x002e, 0x003e,
+	0x00ce, 0x00de, 0x0005, 0xa887, 0x0006, 0x0c80, 0xa887, 0x0002,
+	0x0c68, 0xa887, 0x0005, 0x0c50, 0xa887, 0x0004, 0x0c38, 0xa887,
+	0x0007, 0x0c20, 0x2091, 0x8000, 0x0e04, 0x7f1c, 0x0006, 0x0016,
+	0x2001, 0x8003, 0x0006, 0x0804, 0x0d86, 0x2001, 0x1834, 0x2004,
+	0x9005, 0x0005, 0x0005, 0x00f6, 0x2079, 0x0300, 0x2001, 0x0200,
+	0x200c, 0xc1e5, 0xc1dc, 0x2102, 0x2009, 0x0218, 0x210c, 0xd1ec,
+	0x1120, 0x080c, 0x162f, 0x00fe, 0x0005, 0x2001, 0x020d, 0x2003,
+	0x0020, 0x781f, 0x0300, 0x00fe, 0x0005, 0x781c, 0xd08c, 0x0904,
+	0x7f9d, 0x68c0, 0x90aa, 0x0005, 0x0a04, 0x85c5, 0x7d44, 0x7c40,
+	0xd59c, 0x190c, 0x0d7d, 0x9584, 0x00f6, 0x1508, 0x9484, 0x7000,
+	0x0138, 0x908a, 0x2000, 0x1258, 0x9584, 0x0700, 0x8007, 0x04f0,
+	0x7000, 0x9084, 0xff00, 0x9086, 0x8100, 0x0db0, 0x00b0, 0x9484,
+	0x0fff, 0x1130, 0x7000, 0x9084, 0xff00, 0x9086, 0x8100, 0x11c0,
+	0x080c, 0xe85a, 0x080c, 0x84ac, 0x7817, 0x0140, 0x00a8, 0x9584,
+	0x0076, 0x1118, 0x080c, 0x8508, 0x19c8, 0xd5a4, 0x0148, 0x0046,
+	0x0056, 0x080c, 0x7fed, 0x080c, 0x216f, 0x005e, 0x004e, 0x0020,
+	0x080c, 0xe85a, 0x7817, 0x0140, 0x080c, 0x753d, 0x0168, 0x2001,
+	0x0111, 0x2004, 0xd08c, 0x0140, 0x6893, 0x0000, 0x2001, 0x0110,
+	0x2003, 0x0008, 0x2003, 0x0000, 0x0489, 0x0005, 0x0002, 0x7faa,
+	0x82ba, 0x7fa7, 0x7fa7, 0x7fa7, 0x7fa7, 0x7fa7, 0x7fa7, 0x7817,
+	0x0140, 0x0005, 0x7000, 0x908c, 0xff00, 0x9194, 0xf000, 0x810f,
+	0x9484, 0x0fff, 0x6892, 0x9286, 0x2000, 0x1150, 0x6800, 0x9086,
+	0x0001, 0x1118, 0x080c, 0x57a4, 0x0070, 0x080c, 0x800d, 0x0058,
+	0x9286, 0x3000, 0x1118, 0x080c, 0x81f4, 0x0028, 0x9286, 0x8000,
+	0x1110, 0x080c, 0x83d9, 0x7817, 0x0140, 0x0005, 0x2001, 0x1810,
+	0x2004, 0xd08c, 0x0178, 0x2001, 0x1800, 0x2004, 0x9086, 0x0003,
+	0x1148, 0x0026, 0x0036, 0x2011, 0x8048, 0x2518, 0x080c, 0x4b52,
+	0x003e, 0x002e, 0x0005, 0x0036, 0x0046, 0x0056, 0x00f6, 0x2079,
+	0x0200, 0x2019, 0xfffe, 0x7c30, 0x0050, 0x0036, 0x0046, 0x0056,
+	0x00f6, 0x2079, 0x0200, 0x7d44, 0x7c40, 0x2019, 0xffff, 0x2001,
+	0x1810, 0x2004, 0xd08c, 0x0160, 0x2001, 0x1800, 0x2004, 0x9086,
+	0x0003, 0x1130, 0x0026, 0x2011, 0x8048, 0x080c, 0x4b52, 0x002e,
+	0x00fe, 0x005e, 0x004e, 0x003e, 0x0005, 0x00b6, 0x00c6, 0x7010,
+	0x9084, 0xff00, 0x8007, 0x9096, 0x0001, 0x0120, 0x9096, 0x0023,
+	0x1904, 0x81c5, 0x9186, 0x0023, 0x15c0, 0x080c, 0x8477, 0x0904,
+	0x81c5, 0x6120, 0x9186, 0x0001, 0x0150, 0x9186, 0x0004, 0x0138,
+	0x9186, 0x0008, 0x0120, 0x9186, 0x000a, 0x1904, 0x81c5, 0x7124,
+	0x610a, 0x7030, 0x908e, 0x0200, 0x1130, 0x2009, 0x0015, 0x080c,
+	0xad4d, 0x0804, 0x81c5, 0x908e, 0x0214, 0x0118, 0x908e, 0x0210,
+	0x1130, 0x2009, 0x0015, 0x080c, 0xad4d, 0x0804, 0x81c5, 0x908e,
+	0x0100, 0x1904, 0x81c5, 0x7034, 0x9005, 0x1904, 0x81c5, 0x2009,
+	0x0016, 0x080c, 0xad4d, 0x0804, 0x81c5, 0x9186, 0x0022, 0x1904,
+	0x81c5, 0x7030, 0x908e, 0x0300, 0x1580, 0x68dc, 0xd0a4, 0x0528,
+	0xc0b5, 0x68de, 0x7100, 0x918c, 0x00ff, 0x697e, 0x7004, 0x6882,
+	0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006, 0x9084, 0x00ff,
+	0x0016, 0x2008, 0x080c, 0x26aa, 0x7932, 0x7936, 0x001e, 0x000e,
+	0x00fe, 0x080c, 0x2661, 0x695e, 0x703c, 0x00e6, 0x2071, 0x0140,
+	0x7086, 0x2071, 0x1800, 0x70b6, 0x00ee, 0x7034, 0x9005, 0x1904,
+	0x81c5, 0x2009, 0x0017, 0x0804, 0x8175, 0x908e, 0x0400, 0x1190,
+	0x7034, 0x9005, 0x1904, 0x81c5, 0x080c, 0x753d, 0x0120, 0x2009,
+	0x001d, 0x0804, 0x8175, 0x68dc, 0xc0a5, 0x68de, 0x2009, 0x0030,
+	0x0804, 0x8175, 0x908e, 0x0500, 0x1140, 0x7034, 0x9005, 0x1904,
+	0x81c5, 0x2009, 0x0018, 0x0804, 0x8175, 0x908e, 0x2010, 0x1120,
+	0x2009, 0x0019, 0x0804, 0x8175, 0x908e, 0x2110, 0x1120, 0x2009,
+	0x001a, 0x0804, 0x8175, 0x908e, 0x5200, 0x1140, 0x7034, 0x9005,
+	0x1904, 0x81c5, 0x2009, 0x001b, 0x0804, 0x8175, 0x908e, 0x5000,
+	0x1140, 0x7034, 0x9005, 0x1904, 0x81c5, 0x2009, 0x001c, 0x0804,
+	0x8175, 0x908e, 0x1300, 0x1120, 0x2009, 0x0034, 0x0804, 0x8175,
+	0x908e, 0x1200, 0x1140, 0x7034, 0x9005, 0x1904, 0x81c5, 0x2009,
+	0x0024, 0x0804, 0x8175, 0x908c, 0xff00, 0x918e, 0x2400, 0x1170,
+	0x2009, 0x002d, 0x2001, 0x1810, 0x2004, 0xd09c, 0x0904, 0x8175,
+	0x080c, 0xd7c9, 0x1904, 0x81c5, 0x0804, 0x8173, 0x908c, 0xff00,
+	0x918e, 0x5300, 0x1120, 0x2009, 0x002a, 0x0804, 0x8175, 0x908e,
+	0x0f00, 0x1120, 0x2009, 0x0020, 0x0804, 0x8175, 0x908e, 0x6104,
+	0x1530, 0x2029, 0x0205, 0x2011, 0x026d, 0x8208, 0x2204, 0x9082,
+	0x0004, 0x8004, 0x8004, 0x20a8, 0x2011, 0x8015, 0x211c, 0x8108,
+	0x0046, 0x2124, 0x080c, 0x4b52, 0x004e, 0x8108, 0x0f04, 0x8129,
+	0x9186, 0x0280, 0x1d88, 0x2504, 0x8000, 0x202a, 0x2009, 0x0260,
+	0x0c58, 0x202b, 0x0000, 0x2009, 0x0023, 0x0804, 0x8175, 0x908e,
+	0x6000, 0x1120, 0x2009, 0x003f, 0x0804, 0x8175, 0x908e, 0x5400,
+	0x1138, 0x080c, 0x8575, 0x1904, 0x81c5, 0x2009, 0x0046, 0x04a8,
+	0x908e, 0x5500, 0x1148, 0x080c, 0x859d, 0x1118, 0x2009, 0x0041,
+	0x0460, 0x2009, 0x0042, 0x0448, 0x908e, 0x7800, 0x1118, 0x2009,
+	0x0045, 0x0418, 0x908e, 0x1000, 0x1118, 0x2009, 0x004e, 0x00e8,
+	0x908e, 0x6300, 0x1118, 0x2009, 0x004a, 0x00b8, 0x908c, 0xff00,
+	0x918e, 0x5600, 0x1118, 0x2009, 0x004f, 0x0078, 0x908c, 0xff00,
+	0x918e, 0x5700, 0x1118, 0x2009, 0x0050, 0x0038, 0x2009, 0x001d,
+	0x6838, 0xd0d4, 0x0110, 0x2009, 0x004c, 0x0016, 0x2011, 0x0263,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x2661, 0x1904, 0x81c8, 0x080c,
+	0x6632, 0x1904, 0x81c8, 0xbe12, 0xbd16, 0x001e, 0x0016, 0x080c,
+	0x753d, 0x01c0, 0x68dc, 0xd08c, 0x1148, 0x7000, 0x9084, 0x00ff,
+	0x1188, 0x7004, 0x9084, 0xff00, 0x1168, 0x0040, 0x687c, 0x9606,
+	0x1148, 0x6880, 0x9506, 0x9084, 0xff00, 0x1120, 0x9584, 0x00ff,
+	0xb886, 0x0080, 0xb884, 0x9005, 0x1168, 0x9186, 0x0046, 0x1150,
+	0x687c, 0x9606, 0x1138, 0x6880, 0x9506, 0x9084, 0xff00, 0x1110,
+	0x001e, 0x0098, 0x080c, 0xac5a, 0x01a8, 0x2b08, 0x6112, 0x6023,
+	0x0004, 0x7120, 0x610a, 0x001e, 0x9186, 0x004c, 0x1110, 0x6023,
+	0x000a, 0x0016, 0x001e, 0x080c, 0xad4d, 0x00ce, 0x00be, 0x0005,
+	0x001e, 0x0cd8, 0x2001, 0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011,
+	0x8049, 0x080c, 0x4b52, 0x080c, 0xad20, 0x0d90, 0x2b08, 0x6112,
+	0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x0016, 0x9186, 0x0017,
+	0x0118, 0x9186, 0x0030, 0x1128, 0x6007, 0x0009, 0x6017, 0x2900,
+	0x0020, 0x6007, 0x0051, 0x6017, 0x0000, 0x602f, 0x0009, 0x6003,
+	0x0001, 0x080c, 0x92b7, 0x08a0, 0x080c, 0x85e4, 0x1158, 0x080c,
+	0x3377, 0x1140, 0x7010, 0x9084, 0xff00, 0x8007, 0x908e, 0x0008,
+	0x1108, 0x0009, 0x0005, 0x00b6, 0x00c6, 0x0046, 0x7000, 0x908c,
+	0xff00, 0x810f, 0x9186, 0x0033, 0x11e8, 0x080c, 0x8477, 0x0904,
+	0x8252, 0x7124, 0x610a, 0x7030, 0x908e, 0x0200, 0x1140, 0x7034,
+	0x9005, 0x15c0, 0x2009, 0x0015, 0x080c, 0xad4d, 0x0498, 0x908e,
+	0x0100, 0x1580, 0x7034, 0x9005, 0x1568, 0x2009, 0x0016, 0x080c,
+	0xad4d, 0x0440, 0x9186, 0x0032, 0x1528, 0x7030, 0x908e, 0x1400,
+	0x1508, 0x2009, 0x0038, 0x0016, 0x2011, 0x0263, 0x2204, 0x8211,
+	0x220c, 0x080c, 0x2661, 0x11a8, 0x080c, 0x6632, 0x1190, 0xbe12,
+	0xbd16, 0x080c, 0xac5a, 0x0168, 0x2b08, 0x6112, 0x080c, 0xce15,
+	0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0xad4d, 0x0010,
+	0x00ce, 0x001e, 0x004e, 0x00ce, 0x00be, 0x0005, 0x00b6, 0x0046,
+	0x00e6, 0x00d6, 0x2028, 0x2130, 0x9696, 0x00ff, 0x11b8, 0x9592,
+	0xfffc, 0x02a0, 0x9596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804,
+	0x82b4, 0x9596, 0xfffe, 0x1120, 0x2009, 0x007e, 0x0804, 0x82b4,
+	0x9596, 0xfffc, 0x1118, 0x2009, 0x0080, 0x04f0, 0x2011, 0x0000,
+	0x2019, 0x1837, 0x231c, 0xd3ac, 0x0130, 0x9026, 0x20a9, 0x0800,
+	0x2071, 0x1000, 0x0030, 0x2021, 0x0081, 0x20a9, 0x077f, 0x2071,
+	0x1081, 0x2e1c, 0x93dd, 0x0000, 0x1140, 0x82ff, 0x11d0, 0x9496,
+	0x00ff, 0x01b8, 0x2410, 0xc2fd, 0x00a0, 0xbf10, 0x2600, 0x9706,
+	0xb814, 0x1120, 0x9546, 0x1110, 0x2408, 0x00b0, 0x9745, 0x1148,
+	0x94c6, 0x007e, 0x0130, 0x94c6, 0x007f, 0x0118, 0x94c6, 0x0080,
+	0x1d20, 0x8420, 0x8e70, 0x1f04, 0x8289, 0x82ff, 0x1118, 0x9085,
+	0x0001, 0x0018, 0xc2fc, 0x2208, 0x9006, 0x00de, 0x00ee, 0x004e,
+	0x00be, 0x0005, 0x2001, 0x1837, 0x200c, 0x9184, 0x0080, 0x0110,
+	0xd18c, 0x0138, 0x7000, 0x908c, 0xff00, 0x810f, 0x9184, 0x000f,
+	0x001a, 0x7817, 0x0140, 0x0005, 0x82dc, 0x82dc, 0x82dc, 0x8489,
+	0x82dc, 0x82df, 0x8304, 0x838d, 0x82dc, 0x82dc, 0x82dc, 0x82dc,
+	0x82dc, 0x82dc, 0x82dc, 0x82dc, 0x7817, 0x0140, 0x0005, 0x00b6,
+	0x7110, 0xd1bc, 0x01e8, 0x7120, 0x2160, 0x9c8c, 0x0003, 0x11c0,
+	0x9c8a, 0x1ddc, 0x02a8, 0x6868, 0x9c02, 0x1290, 0x7008, 0x9084,
+	0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, 0x1150, 0x700c, 0xb914,
+	0x9106, 0x1130, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0xad4d,
+	0x7817, 0x0140, 0x00be, 0x0005, 0x00b6, 0x00c6, 0x9484, 0x0fff,
+	0x0904, 0x8369, 0x7110, 0xd1bc, 0x1904, 0x8369, 0x7108, 0x700c,
+	0x2028, 0x918c, 0x00ff, 0x2130, 0x9094, 0xff00, 0x15c8, 0x81ff,
+	0x15b8, 0x9080, 0x33b9, 0x200d, 0x918c, 0xff00, 0x810f, 0x2001,
+	0x0080, 0x9106, 0x0904, 0x8369, 0x9182, 0x0801, 0x1a04, 0x8369,
+	0x9190, 0x1000, 0x2204, 0x905d, 0x05e0, 0xbe12, 0xbd16, 0xb800,
+	0xd0ec, 0x15b8, 0xba04, 0x9294, 0xff00, 0x9286, 0x0600, 0x1190,
+	0x080c, 0xac5a, 0x0598, 0x2b08, 0x7028, 0x604e, 0x702c, 0x6052,
+	0x6112, 0x6023, 0x0006, 0x7120, 0x610a, 0x7130, 0x615e, 0x080c,
+	0xda32, 0x00f8, 0x080c, 0x6add, 0x1138, 0xb807, 0x0606, 0x0c40,
+	0x190c, 0x8256, 0x11b0, 0x0880, 0x080c, 0xac5a, 0x2b08, 0x0188,
+	0x6112, 0x6023, 0x0004, 0x7120, 0x610a, 0x9286, 0x0400, 0x1118,
+	0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x92b7, 0x7817, 0x0140, 0x00ce, 0x00be, 0x0005, 0x2001, 0x180e,
+	0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x4b52, 0x080c,
+	0xad20, 0x0d78, 0x2b08, 0x6112, 0x6023, 0x0006, 0x7120, 0x610a,
+	0x7130, 0x615e, 0x6017, 0xf300, 0x6003, 0x0001, 0x6007, 0x0041,
+	0x2009, 0xa022, 0x080c, 0x92b0, 0x08e0, 0x00b6, 0x7110, 0xd1bc,
+	0x05d0, 0x7020, 0x2060, 0x9c84, 0x0003, 0x15a8, 0x9c82, 0x1ddc,
+	0x0690, 0x6868, 0x9c02, 0x1678, 0x9484, 0x0fff, 0x9082, 0x000c,
+	0x0650, 0x7008, 0x9084, 0x00ff, 0x6110, 0x2158, 0xb910, 0x9106,
+	0x1510, 0x700c, 0xb914, 0x9106, 0x11f0, 0x7124, 0x610a, 0x601c,
+	0xd0fc, 0x11c8, 0x2001, 0x0271, 0x2004, 0x9005, 0x1180, 0x9484,
+	0x0fff, 0x9082, 0x000c, 0x0158, 0x0066, 0x2031, 0x0100, 0xa001,
+	0xa001, 0x8631, 0x1de0, 0x006e, 0x601c, 0xd0fc, 0x1120, 0x2009,
+	0x0045, 0x080c, 0xad4d, 0x7817, 0x0140, 0x00be, 0x0005, 0x6120,
+	0x9186, 0x0002, 0x0128, 0x9186, 0x0005, 0x0110, 0x9085, 0x0001,
+	0x0005, 0x080c, 0x85e4, 0x1180, 0x080c, 0x3377, 0x1168, 0x7010,
+	0x9084, 0xff00, 0x8007, 0x9086, 0x0000, 0x1130, 0x9184, 0x000f,
+	0x908a, 0x0006, 0x1208, 0x000b, 0x0005, 0x83f3, 0x83f4, 0x83f3,
+	0x83f3, 0x8459, 0x8468, 0x0005, 0x00b6, 0x700c, 0x7108, 0x080c,
+	0x2661, 0x1904, 0x8457, 0x080c, 0x6632, 0x1904, 0x8457, 0xbe12,
+	0xbd16, 0x7110, 0xd1bc, 0x0540, 0x702c, 0xd084, 0x1120, 0xb800,
+	0xd0bc, 0x1904, 0x8457, 0x080c, 0x6add, 0x0148, 0x9086, 0x0004,
+	0x0130, 0x080c, 0x6ae5, 0x0118, 0x9086, 0x0004, 0x1588, 0x00c6,
+	0x080c, 0x8477, 0x00ce, 0x05d8, 0x080c, 0xac5a, 0x2b08, 0x05b8,
+	0x6112, 0x080c, 0xce15, 0x6023, 0x0002, 0x7120, 0x610a, 0x2009,
+	0x0088, 0x080c, 0xad4d, 0x0458, 0x080c, 0x6add, 0x0148, 0x9086,
+	0x0004, 0x0130, 0x080c, 0x6ae5, 0x0118, 0x9086, 0x0004, 0x1180,
+	0x080c, 0xac5a, 0x2b08, 0x01d8, 0x6112, 0x080c, 0xce15, 0x6023,
+	0x0005, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c, 0xad4d, 0x0078,
+	0x080c, 0xac5a, 0x2b08, 0x0158, 0x6112, 0x080c, 0xce15, 0x6023,
+	0x0004, 0x7120, 0x610a, 0x2009, 0x0001, 0x080c, 0xad4d, 0x00be,
+	0x0005, 0x7110, 0xd1bc, 0x0158, 0x00d1, 0x0148, 0x080c, 0x83cf,
+	0x1130, 0x7124, 0x610a, 0x2009, 0x0089, 0x080c, 0xad4d, 0x0005,
+	0x7110, 0xd1bc, 0x0158, 0x0059, 0x0148, 0x080c, 0x83cf, 0x1130,
+	0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0xad4d, 0x0005, 0x7020,
+	0x2060, 0x9c84, 0x0003, 0x1158, 0x9c82, 0x1ddc, 0x0240, 0x2001,
+	0x181a, 0x2004, 0x9c02, 0x1218, 0x9085, 0x0001, 0x0005, 0x9006,
+	0x0ce8, 0x00b6, 0x7110, 0xd1bc, 0x11d8, 0x7024, 0x2060, 0x9c84,
+	0x0003, 0x11b0, 0x9c82, 0x1ddc, 0x0298, 0x6868, 0x9c02, 0x1280,
+	0x7008, 0x9084, 0x00ff, 0x6110, 0x2158, 0xb910, 0x9106, 0x1140,
+	0x700c, 0xb914, 0x9106, 0x1120, 0x2009, 0x0051, 0x080c, 0xad4d,
+	0x7817, 0x0140, 0x00be, 0x0005, 0x2031, 0x0105, 0x0069, 0x0005,
+	0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, 0x0005,
+	0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x0096, 0x00f6, 0x7000,
+	0x9084, 0xf000, 0x9086, 0xc000, 0x05c0, 0x080c, 0xac5a, 0x05a8,
+	0x0066, 0x00c6, 0x0046, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c,
+	0x080c, 0x2661, 0x1590, 0x080c, 0x6632, 0x1578, 0xbe12, 0xbd16,
+	0x2b00, 0x004e, 0x00ce, 0x6012, 0x080c, 0xce15, 0x080c, 0x1047,
+	0x0500, 0x2900, 0x6062, 0x9006, 0xa802, 0xa866, 0xac6a, 0xa85c,
+	0x90f8, 0x001b, 0x20a9, 0x000e, 0xa860, 0x20e8, 0x20e1, 0x0000,
+	0x2fa0, 0x2e98, 0x4003, 0x006e, 0x6616, 0x6007, 0x003e, 0x6023,
+	0x0001, 0x6003, 0x0001, 0x080c, 0x92b7, 0x00fe, 0x009e, 0x00ce,
+	0x0005, 0x080c, 0xacb0, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8,
+	0x00c6, 0x7000, 0x908c, 0xff00, 0x9184, 0xf000, 0x810f, 0x9086,
+	0x2000, 0x1904, 0x855f, 0x9186, 0x0022, 0x15f0, 0x2001, 0x0111,
+	0x2004, 0x9005, 0x1904, 0x8561, 0x7030, 0x908e, 0x0400, 0x0904,
+	0x8561, 0x908e, 0x6000, 0x05e8, 0x908e, 0x5400, 0x05d0, 0x908e,
+	0x0300, 0x11d8, 0x2009, 0x1837, 0x210c, 0xd18c, 0x1590, 0xd1a4,
+	0x1580, 0x080c, 0x6a9b, 0x0588, 0x68b0, 0x9084, 0x00ff, 0x7100,
+	0x918c, 0x00ff, 0x9106, 0x1518, 0x6880, 0x69b0, 0x918c, 0xff00,
+	0x9105, 0x7104, 0x9106, 0x11d8, 0x00e0, 0x2009, 0x0103, 0x210c,
+	0xd1b4, 0x11a8, 0x908e, 0x5200, 0x09e8, 0x908e, 0x0500, 0x09d0,
+	0x908e, 0x5000, 0x09b8, 0x0058, 0x9186, 0x0023, 0x1140, 0x080c,
+	0x8477, 0x0128, 0x6004, 0x9086, 0x0002, 0x0118, 0x0000, 0x9006,
+	0x0010, 0x9085, 0x0001, 0x00ce, 0x0005, 0x7030, 0x908e, 0x0300,
+	0x0118, 0x908e, 0x5200, 0x1d98, 0x2001, 0x1837, 0x2004, 0x9084,
+	0x0009, 0x9086, 0x0008, 0x0d68, 0x0c50, 0x0156, 0x0046, 0x0016,
+	0x0036, 0x7038, 0x2020, 0x8427, 0x94a4, 0x0007, 0xd484, 0x0148,
+	0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x027a, 0x080c, 0xbc8e,
+	0x1178, 0xd48c, 0x0148, 0x20a9, 0x0004, 0x2019, 0x1801, 0x2011,
+	0x027e, 0x080c, 0xbc8e, 0x1120, 0xd494, 0x0110, 0x9085, 0x0001,
+	0x003e, 0x001e, 0x004e, 0x015e, 0x0005, 0x0156, 0x0046, 0x0016,
+	0x0036, 0x7038, 0x2020, 0x8427, 0x94a4, 0x0007, 0xd484, 0x0148,
+	0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0272, 0x080c, 0xbc8e,
+	0x1178, 0xd48c, 0x0148, 0x20a9, 0x0004, 0x2019, 0x1801, 0x2011,
+	0x0276, 0x080c, 0xbc8e, 0x1120, 0xd494, 0x0110, 0x9085, 0x0001,
+	0x003e, 0x001e, 0x004e, 0x015e, 0x0005, 0x00f6, 0x2079, 0x0200,
+	0x7800, 0xc0e5, 0xc0cc, 0x7802, 0x00fe, 0x0005, 0x00f6, 0x2079,
+	0x1800, 0x7834, 0xd084, 0x1130, 0x2079, 0x0200, 0x7800, 0x9085,
+	0x1200, 0x7802, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x1800, 0x7034,
+	0xc084, 0x7036, 0x00ee, 0x0005, 0x0016, 0x2001, 0x1837, 0x200c,
+	0x9184, 0x0080, 0x0118, 0xd18c, 0x0118, 0x9006, 0x001e, 0x0005,
+	0x9085, 0x0001, 0x0cd8, 0x2071, 0x1a02, 0x7003, 0x0003, 0x700f,
+	0x0361, 0x9006, 0x701a, 0x7072, 0x7012, 0x7017, 0x1ddc, 0x7007,
+	0x0000, 0x7026, 0x702b, 0x9ef4, 0x7032, 0x7037, 0x9f71, 0x703f,
+	0xffff, 0x7042, 0x7047, 0x55c2, 0x704a, 0x705b, 0x879b, 0x080c,
+	0x1060, 0x090c, 0x0d7d, 0x2900, 0x703a, 0xa867, 0x0003, 0xa86f,
+	0x0100, 0xa8ab, 0xdcb0, 0x0005, 0x2071, 0x1a02, 0x1d04, 0x86b7,
+	0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x1590, 0x2001, 0x013c,
+	0x2004, 0x9005, 0x190c, 0x8845, 0x2001, 0x1869, 0x2004, 0xd0c4,
+	0x0158, 0x3a00, 0xd08c, 0x1140, 0x20d1, 0x0000, 0x20d1, 0x0001,
+	0x20d1, 0x0000, 0x080c, 0x0d7d, 0x700f, 0x0361, 0x7007, 0x0001,
+	0x0126, 0x2091, 0x8000, 0x2069, 0x1800, 0x69ec, 0xd1e4, 0x1138,
+	0xd1dc, 0x1118, 0x080c, 0x8809, 0x0010, 0x080c, 0x87e0, 0x7040,
+	0x900d, 0x0148, 0x8109, 0x7142, 0x1130, 0x7044, 0x080f, 0x0018,
+	0x0126, 0x2091, 0x8000, 0x7024, 0x900d, 0x0188, 0x7020, 0x8001,
+	0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126, 0x9186, 0x03e8,
+	0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028, 0x080f, 0x7030,
+	0x900d, 0x0180, 0x702c, 0x8001, 0x702e, 0x1160, 0x702f, 0x0009,
+	0x8109, 0x7132, 0x0128, 0x9184, 0x007f, 0x090c, 0xa00d, 0x0010,
+	0x7034, 0x080f, 0x703c, 0x9005, 0x0118, 0x0310, 0x8001, 0x703e,
+	0x704c, 0x900d, 0x0168, 0x7048, 0x8001, 0x704a, 0x1148, 0x704b,
+	0x0009, 0x8109, 0x714e, 0x1120, 0x7150, 0x714e, 0x7058, 0x080f,
+	0x7018, 0x900d, 0x01d8, 0x0016, 0x7070, 0x900d, 0x0158, 0x706c,
+	0x8001, 0x706e, 0x1138, 0x706f, 0x0009, 0x8109, 0x7172, 0x1110,
+	0x7074, 0x080f, 0x001e, 0x7008, 0x8001, 0x700a, 0x1138, 0x700b,
+	0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f, 0x012e, 0x7004,
+	0x0002, 0x86df, 0x86e0, 0x870a, 0x00e6, 0x2071, 0x1a02, 0x7018,
+	0x9005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009, 0x00ee, 0x0005,
+	0x00e6, 0x0006, 0x2071, 0x1a02, 0x701c, 0x9206, 0x1120, 0x701a,
+	0x701e, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005, 0x00e6, 0x2071,
+	0x1a02, 0xb888, 0x9102, 0x0208, 0xb98a, 0x00ee, 0x0005, 0x0005,
+	0x00b6, 0x2031, 0x0010, 0x7110, 0x080c, 0x6693, 0x11a8, 0xb888,
+	0x8001, 0x0290, 0xb88a, 0x1180, 0x0126, 0x2091, 0x8000, 0x0066,
+	0xb8d0, 0x9005, 0x0138, 0x0026, 0xba3c, 0x0016, 0x080c, 0x67be,
+	0x001e, 0x002e, 0x006e, 0x012e, 0x8108, 0x9182, 0x0800, 0x1220,
+	0x8631, 0x0128, 0x7112, 0x0c00, 0x900e, 0x7007, 0x0002, 0x7112,
+	0x00be, 0x0005, 0x2031, 0x0010, 0x7014, 0x2060, 0x0126, 0x2091,
+	0x8000, 0x6048, 0x9005, 0x0128, 0x8001, 0x604a, 0x1110, 0x080c,
+	0xcc96, 0x6018, 0x9005, 0x0904, 0x8762, 0x00f6, 0x2079, 0x0300,
+	0x7918, 0xd1b4, 0x1904, 0x8775, 0x781b, 0x2020, 0xa001, 0x7918,
+	0xd1b4, 0x0120, 0x781b, 0x2000, 0x0804, 0x8775, 0x8001, 0x601a,
+	0x0106, 0x781b, 0x2000, 0xa001, 0x7918, 0xd1ac, 0x1dd0, 0x010e,
+	0x00fe, 0x1540, 0x6120, 0x9186, 0x0003, 0x0148, 0x9186, 0x0006,
+	0x0130, 0x9186, 0x0009, 0x11e0, 0x611c, 0xd1c4, 0x1100, 0x080c,
+	0xc97a, 0x01b0, 0x6014, 0x2048, 0xa884, 0x908a, 0x199a, 0x0280,
+	0x9082, 0x1999, 0xa886, 0x908a, 0x199a, 0x0210, 0x2001, 0x1999,
+	0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0x080c, 0xd0c7, 0x0110,
+	0x080c, 0xc65b, 0x012e, 0x9c88, 0x001c, 0x7116, 0x2001, 0x181a,
+	0x2004, 0x9102, 0x1228, 0x8631, 0x0138, 0x2160, 0x0804, 0x870e,
+	0x7017, 0x1ddc, 0x7007, 0x0000, 0x0005, 0x00fe, 0x0c58, 0x00e6,
+	0x2071, 0x1a02, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee, 0x0005,
+	0x2001, 0x1a0b, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071, 0x1a02,
+	0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0x1a0e, 0x2013,
+	0x0000, 0x0005, 0x00e6, 0x2071, 0x1a02, 0x711a, 0x721e, 0x700b,
+	0x0009, 0x00ee, 0x0005, 0x0086, 0x0026, 0x7054, 0x8000, 0x7056,
+	0x2001, 0x1a10, 0x2044, 0xa06c, 0x9086, 0x0000, 0x0150, 0x7068,
+	0xa09a, 0x7064, 0xa096, 0x7060, 0xa092, 0x705c, 0xa08e, 0x080c,
+	0x113c, 0x002e, 0x008e, 0x0005, 0x0006, 0x0016, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0156, 0x080c, 0x861c,
+	0x015e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e,
+	0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0x1a02, 0x7172, 0x7276,
+	0x706f, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x1a02,
+	0x7074, 0x9206, 0x1110, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005,
+	0x2069, 0x1800, 0x69ec, 0xd1e4, 0x1518, 0x0026, 0xd1ec, 0x0140,
+	0x6a54, 0x6874, 0x9202, 0x0288, 0x8117, 0x9294, 0x00c1, 0x0088,
+	0x9184, 0x0007, 0x01a0, 0x8109, 0x9184, 0x0007, 0x0110, 0x69ee,
+	0x0070, 0x8107, 0x9084, 0x0007, 0x910d, 0x8107, 0x9106, 0x9094,
+	0x00c1, 0x9184, 0xff3e, 0x9205, 0x68ee, 0x080c, 0x0f12, 0x002e,
+	0x0005, 0x69e8, 0x9184, 0x003f, 0x05b8, 0x8109, 0x9184, 0x003f,
+	0x01a8, 0x6a54, 0x6874, 0x9202, 0x0220, 0xd1bc, 0x0168, 0xc1bc,
+	0x0018, 0xd1bc, 0x1148, 0xc1bd, 0x2110, 0x00e6, 0x2071, 0x1800,
+	0x080c, 0x0f34, 0x00ee, 0x0400, 0x69ea, 0x00f0, 0x0026, 0x8107,
+	0x9094, 0x0007, 0x0128, 0x8001, 0x8007, 0x9085, 0x0007, 0x0050,
+	0x2010, 0x8004, 0x8004, 0x8004, 0x9084, 0x0007, 0x9205, 0x8007,
+	0x9085, 0x0028, 0x9086, 0x0040, 0x2010, 0x00e6, 0x2071, 0x1800,
+	0x080c, 0x0f34, 0x00ee, 0x002e, 0x0005, 0x0016, 0x00c6, 0x2009,
+	0xfff4, 0x210d, 0x2061, 0x0100, 0x60f0, 0x9100, 0x60f3, 0x0000,
+	0x2009, 0xfff4, 0x200f, 0x1220, 0x8108, 0x2105, 0x8000, 0x200f,
+	0x00ce, 0x001e, 0x0005, 0x00c6, 0x2061, 0x1a6e, 0x00ce, 0x0005,
+	0x9184, 0x000f, 0x8003, 0x8003, 0x8003, 0x9080, 0x1a6e, 0x2060,
+	0x0005, 0xa884, 0x908a, 0x199a, 0x1638, 0x9005, 0x1150, 0x00c6,
+	0x2061, 0x1a6e, 0x6014, 0x00ce, 0x9005, 0x1130, 0x2001, 0x001e,
+	0x0018, 0x908e, 0xffff, 0x01b0, 0x8003, 0x800b, 0x810b, 0x9108,
+	0x611a, 0xa87c, 0x908c, 0x00c0, 0x918e, 0x00c0, 0x0904, 0x8923,
+	0xd0b4, 0x1168, 0xd0bc, 0x1904, 0x88fc, 0x2009, 0x0006, 0x080c,
+	0x8950, 0x0005, 0x900e, 0x0c60, 0x2001, 0x1999, 0x08b0, 0xd0fc,
+	0x05e0, 0x908c, 0x2023, 0x1568, 0x87ff, 0x1558, 0xa9a8, 0x81ff,
+	0x1540, 0x6124, 0x918c, 0x0500, 0x1520, 0x6100, 0x918e, 0x0007,
+	0x1500, 0x2009, 0x1869, 0x210c, 0xd184, 0x11d8, 0x6003, 0x0003,
+	0x6007, 0x0043, 0x6047, 0xb035, 0x080c, 0x1c59, 0xa87c, 0xc0dd,
+	0xa87e, 0x600f, 0x0000, 0x00f6, 0x2079, 0x0380, 0x7818, 0xd0bc,
+	0x1de8, 0x7833, 0x0013, 0x2c00, 0x7836, 0x781b, 0x8080, 0x00fe,
+	0x0005, 0x908c, 0x0003, 0x0120, 0x918e, 0x0003, 0x1904, 0x894a,
+	0x908c, 0x2020, 0x918e, 0x2020, 0x01a8, 0x6024, 0xd0d4, 0x11e8,
+	0x2009, 0x1869, 0x2104, 0xd084, 0x1138, 0x87ff, 0x1120, 0x2009,
+	0x0043, 0x0804, 0xad4d, 0x0005, 0x87ff, 0x1de8, 0x2009, 0x0042,
+	0x0804, 0xad4d, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac,
+	0x0d20, 0x6024, 0xc0cd, 0x6026, 0x0c00, 0xc0d4, 0x6026, 0xa890,
+	0x602e, 0xa88c, 0x6032, 0x08e0, 0xd0fc, 0x0160, 0x908c, 0x0003,
+	0x0120, 0x918e, 0x0003, 0x1904, 0x894a, 0x908c, 0x2020, 0x918e,
+	0x2020, 0x0170, 0x0076, 0x00f6, 0x2c78, 0x080c, 0x1778, 0x00fe,
+	0x007e, 0x87ff, 0x1120, 0x2009, 0x0042, 0x080c, 0xad4d, 0x0005,
+	0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d58, 0x6124,
+	0xc1cd, 0x6126, 0x0c38, 0xd0fc, 0x0188, 0x908c, 0x2020, 0x918e,
+	0x2020, 0x01a8, 0x9084, 0x0003, 0x908e, 0x0002, 0x0148, 0x87ff,
+	0x1120, 0x2009, 0x0041, 0x080c, 0xad4d, 0x0005, 0x00b9, 0x0ce8,
+	0x87ff, 0x1dd8, 0x2009, 0x0043, 0x080c, 0xad4d, 0x0cb0, 0x6110,
+	0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d20, 0x6124, 0xc1cd,
+	0x6126, 0x0c00, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001,
+	0x0096, 0x080c, 0xc97a, 0x0518, 0x6014, 0x2048, 0xa982, 0xa800,
+	0x6016, 0x9186, 0x0001, 0x1188, 0xa97c, 0x918c, 0x8100, 0x918e,
+	0x8100, 0x1158, 0x00c6, 0x2061, 0x1a6e, 0x6200, 0xd28c, 0x1120,
+	0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x6c23, 0x6014,
+	0x904d, 0x0076, 0x2039, 0x0000, 0x190c, 0x8869, 0x007e, 0x009e,
+	0x0005, 0x0156, 0x00c6, 0x2061, 0x1a6e, 0x6000, 0x81ff, 0x0110,
+	0x9205, 0x0008, 0x9204, 0x6002, 0x00ce, 0x015e, 0x0005, 0x6800,
+	0xd08c, 0x1138, 0x6808, 0x9005, 0x0120, 0x8001, 0x680a, 0x9085,
+	0x0001, 0x0005, 0x2071, 0x1923, 0x7003, 0x0006, 0x7007, 0x0000,
+	0x700f, 0x0000, 0x7013, 0x0001, 0x080c, 0x1060, 0x090c, 0x0d7d,
+	0xa867, 0x0006, 0xa86b, 0x0001, 0xa8ab, 0xdcb0, 0xa89f, 0x0000,
+	0x2900, 0x702e, 0x7033, 0x0000, 0x0005, 0x0096, 0x00e6, 0x2071,
+	0x1923, 0x702c, 0x2048, 0x6a2c, 0x721e, 0x6b30, 0x7322, 0x6834,
+	0x7026, 0xa896, 0x6838, 0x702a, 0xa89a, 0x6824, 0x7016, 0x683c,
+	0x701a, 0x2009, 0x0028, 0x200a, 0x9005, 0x0148, 0x900e, 0x9188,
+	0x000c, 0x8001, 0x1de0, 0x2100, 0x9210, 0x1208, 0x8318, 0xaa8e,
+	0xab92, 0x7010, 0xd084, 0x0168, 0xc084, 0x7007, 0x0001, 0x700f,
+	0x0000, 0x0006, 0x2009, 0x1b50, 0x2104, 0x9082, 0x0007, 0x200a,
+	0x000e, 0xc095, 0x7012, 0x2008, 0x2001, 0x003b, 0x080c, 0x16a0,
+	0x9006, 0x2071, 0x193c, 0x7002, 0x7006, 0x702a, 0x00ee, 0x009e,
+	0x0005, 0x2009, 0x1b50, 0x2104, 0x9080, 0x0007, 0x200a, 0x0005,
+	0x00e6, 0x0126, 0x0156, 0x2091, 0x8000, 0x2071, 0x1800, 0x7154,
+	0x2001, 0x0008, 0x910a, 0x0638, 0x2001, 0x187d, 0x20ac, 0x9006,
+	0x9080, 0x0008, 0x1f04, 0x8a08, 0x71c0, 0x9102, 0x02e0, 0x2071,
+	0x1877, 0x20a9, 0x0007, 0x00c6, 0x080c, 0xac5a, 0x6023, 0x0009,
+	0x6003, 0x0004, 0x601f, 0x0101, 0x0089, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x8b89, 0x012e, 0x1f04, 0x8a14, 0x9006, 0x00ce, 0x015e,
+	0x012e, 0x00ee, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x00e6, 0x00b6,
+	0x0096, 0x0086, 0x0056, 0x0046, 0x0026, 0x7118, 0x720c, 0x7620,
+	0x7004, 0xd084, 0x1128, 0x2021, 0x0024, 0x2029, 0x0002, 0x0020,
+	0x2021, 0x002c, 0x2029, 0x000a, 0x080c, 0x1047, 0x090c, 0x0d7d,
+	0x2900, 0x6016, 0x2058, 0xac66, 0x9006, 0xa802, 0xa806, 0xa86a,
+	0xa87a, 0xa8aa, 0xa887, 0x0005, 0xa87f, 0x0020, 0x7008, 0xa89a,
+	0x7010, 0xa89e, 0xae8a, 0xa8af, 0xffff, 0xa8b3, 0x0000, 0x8109,
+	0x0160, 0x080c, 0x1047, 0x090c, 0x0d7d, 0xad66, 0x2b00, 0xa802,
+	0x2900, 0xb806, 0x2058, 0x8109, 0x1da0, 0x002e, 0x004e, 0x005e,
+	0x008e, 0x009e, 0x00be, 0x00ee, 0x0005, 0x2079, 0x0000, 0x2071,
+	0x1923, 0x7004, 0x004b, 0x700c, 0x0002, 0x8a80, 0x8a79, 0x8a79,
+	0x0005, 0x8a8a, 0x8ae0, 0x8ae0, 0x8ae0, 0x8ae1, 0x8af2, 0x8af2,
+	0x700c, 0x0cba, 0x0126, 0x2091, 0x8000, 0x78a0, 0x79a0, 0x9106,
+	0x1904, 0x8ad2, 0x7814, 0xd0bc, 0x1904, 0x8adb, 0x012e, 0x7018,
+	0x910a, 0x1128, 0x7030, 0x9005, 0x1904, 0x8b24, 0x0005, 0x1210,
+	0x7114, 0x910a, 0x9192, 0x000a, 0x0210, 0x2009, 0x000a, 0x2001,
+	0x1888, 0x2014, 0x2001, 0x1935, 0x2004, 0x9100, 0x9202, 0x0e50,
+	0x080c, 0x8c7d, 0x2200, 0x9102, 0x0208, 0x2208, 0x0096, 0x702c,
+	0x2048, 0xa873, 0x0001, 0xa976, 0x080c, 0x8d86, 0x2100, 0xa87e,
+	0xa86f, 0x0000, 0x009e, 0x0126, 0x2091, 0x8000, 0x2009, 0x1a20,
+	0x2104, 0xc085, 0x200a, 0x700f, 0x0002, 0x012e, 0x080c, 0x115b,
+	0x1de8, 0x0005, 0x78a0, 0x79a0, 0x9106, 0x0904, 0x8a92, 0x080c,
+	0x8c55, 0x012e, 0x0005, 0x7810, 0xc0c5, 0x7812, 0x0804, 0x8a92,
+	0x0005, 0x700c, 0x0002, 0x8ae6, 0x8ae9, 0x8ae8, 0x080c, 0x8a88,
+	0x0005, 0x8001, 0x700e, 0x0096, 0x702c, 0x2048, 0xa974, 0x009e,
+	0x0011, 0x0ca0, 0x0005, 0x0096, 0x702c, 0x2048, 0x7018, 0x9100,
+	0x7214, 0x921a, 0x1130, 0x701c, 0xa88e, 0x7020, 0xa892, 0x9006,
+	0x0068, 0x0006, 0x080c, 0x8d86, 0x2100, 0xaa8c, 0x9210, 0xaa8e,
+	0x1220, 0xa890, 0x9081, 0x0000, 0xa892, 0x000e, 0x009e, 0x0126,
+	0x2091, 0x8000, 0x78a2, 0x701a, 0x080c, 0x8c55, 0x012e, 0x0005,
+	0x00e6, 0x2071, 0x1923, 0x700c, 0x0002, 0x8b22, 0x8b22, 0x8b20,
+	0x700f, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x7030,
+	0x9005, 0x0508, 0x2078, 0x7814, 0x2048, 0xae88, 0x00b6, 0x2059,
+	0x0000, 0x080c, 0x8b92, 0x00be, 0x01b0, 0x00e6, 0x2071, 0x193c,
+	0x080c, 0x8bd9, 0x00ee, 0x0178, 0x0096, 0x080c, 0x1060, 0x2900,
+	0x009e, 0x0148, 0xa8aa, 0x04d1, 0x0041, 0x2001, 0x1946, 0x2003,
+	0x0000, 0x012e, 0x08c8, 0x012e, 0x0005, 0x00d6, 0x00c6, 0x0086,
+	0x00a6, 0x2940, 0x2650, 0x2600, 0x9005, 0x0180, 0xa864, 0x9084,
+	0x000f, 0x2068, 0x9d88, 0x1eab, 0x2165, 0x0056, 0x2029, 0x0000,
+	0x080c, 0x8d0b, 0x080c, 0x1e81, 0x1dd8, 0x005e, 0x00ae, 0x2001,
+	0x187f, 0x2004, 0xa88a, 0x00c6, 0x2f60, 0x080c, 0x1778, 0x00ce,
+	0x781f, 0x0101, 0x7813, 0x0000, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x8be8, 0x012e, 0x008e, 0x00ce, 0x00de, 0x0005, 0x7030, 0x9005,
+	0x0138, 0x2078, 0x780c, 0x7032, 0x2001, 0x1946, 0x2003, 0x0001,
+	0x0005, 0x00e6, 0x2071, 0x1923, 0x7030, 0x600e, 0x2c00, 0x7032,
+	0x00ee, 0x0005, 0x00d6, 0x00c6, 0x0026, 0x9b80, 0x8e54, 0x2005,
+	0x906d, 0x090c, 0x0d7d, 0x9b80, 0x8e4c, 0x2005, 0x9065, 0x090c,
+	0x0d7d, 0x6114, 0x2600, 0x9102, 0x0248, 0x6828, 0x9102, 0x02f0,
+	0x9085, 0x0001, 0x002e, 0x00ce, 0x00de, 0x0005, 0x6804, 0xd094,
+	0x0148, 0x6854, 0xd084, 0x1178, 0xc085, 0x6856, 0x2011, 0x8026,
+	0x080c, 0x4b52, 0x684c, 0x0096, 0x904d, 0x090c, 0x0d7d, 0xa804,
+	0x8000, 0xa806, 0x009e, 0x9006, 0x2030, 0x0c20, 0x6854, 0xd08c,
+	0x1d08, 0xc08d, 0x6856, 0x2011, 0x8025, 0x080c, 0x4b52, 0x684c,
+	0x0096, 0x904d, 0x090c, 0x0d7d, 0xa800, 0x8000, 0xa802, 0x009e,
+	0x0888, 0x7000, 0x2019, 0x0008, 0x8319, 0x7104, 0x9102, 0x1118,
+	0x2300, 0x9005, 0x0020, 0x0210, 0x9302, 0x0008, 0x8002, 0x0005,
+	0x00d6, 0x7814, 0x9005, 0x090c, 0x0d7d, 0x781c, 0x9084, 0x0101,
+	0x9086, 0x0101, 0x190c, 0x0d7d, 0x7827, 0x0000, 0x2069, 0x193c,
+	0x6804, 0x9080, 0x193e, 0x2f08, 0x2102, 0x6904, 0x8108, 0x9182,
+	0x0008, 0x0208, 0x900e, 0x6906, 0x9180, 0x193e, 0x2003, 0x0000,
+	0x00de, 0x0005, 0x0096, 0x00c6, 0x2060, 0x6014, 0x2048, 0xa8a8,
+	0x0096, 0x2048, 0x9005, 0x190c, 0x1079, 0x009e, 0xa8ab, 0x0000,
+	0x080c, 0x0ff9, 0x080c, 0xacb0, 0x00ce, 0x009e, 0x0005, 0x6020,
+	0x9086, 0x0009, 0x1128, 0x601c, 0xd0c4, 0x0110, 0x9006, 0x0005,
+	0x9085, 0x0001, 0x0005, 0x6000, 0x9086, 0x0000, 0x0178, 0x6010,
+	0x9005, 0x0150, 0x00b6, 0x2058, 0x080c, 0x8f89, 0x00be, 0x6013,
+	0x0000, 0x601b, 0x0000, 0x0010, 0x2c00, 0x0861, 0x0005, 0x2009,
+	0x1927, 0x210c, 0xd194, 0x0005, 0x00e6, 0x2071, 0x1923, 0x7110,
+	0xc194, 0xd19c, 0x1118, 0xc185, 0x7007, 0x0000, 0x7112, 0x2001,
+	0x003b, 0x080c, 0x16a0, 0x00ee, 0x0005, 0x7814, 0xd0bc, 0x1108,
+	0x0005, 0x7810, 0xc0c5, 0x7812, 0x0cc0, 0x0096, 0x00d6, 0x9006,
+	0x7006, 0x700e, 0x701a, 0x701e, 0x7022, 0x7016, 0x702a, 0x7026,
+	0x702f, 0x0000, 0x080c, 0x8dd4, 0x0170, 0x080c, 0x8e09, 0x0158,
+	0x2900, 0x7002, 0x700a, 0x701a, 0x7013, 0x0001, 0x701f, 0x000a,
+	0x00de, 0x009e, 0x0005, 0x900e, 0x0cd8, 0x00e6, 0x0096, 0x0086,
+	0x00d6, 0x00c6, 0x2071, 0x1930, 0x721c, 0x2100, 0x9202, 0x1618,
+	0x080c, 0x8e09, 0x090c, 0x0d7d, 0x7018, 0x9005, 0x1160, 0x2900,
+	0x7002, 0x700a, 0x701a, 0x9006, 0x7006, 0x700e, 0xa806, 0xa802,
+	0x7012, 0x701e, 0x0038, 0x2040, 0xa806, 0x2900, 0xa002, 0x701a,
+	0xa803, 0x0000, 0x7010, 0x8000, 0x7012, 0x701c, 0x9080, 0x000a,
+	0x701e, 0x721c, 0x08d0, 0x721c, 0x00ce, 0x00de, 0x008e, 0x009e,
+	0x00ee, 0x0005, 0x0096, 0x0156, 0x0136, 0x0146, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x1930, 0x7300, 0x831f, 0x831e, 0x831e,
+	0x9384, 0x003f, 0x20e8, 0x939c, 0xffc0, 0x9398, 0x0003, 0x7104,
+	0x080c, 0x8d86, 0x810c, 0x2100, 0x9318, 0x8003, 0x2228, 0x2021,
+	0x0078, 0x9402, 0x9532, 0x0208, 0x2028, 0x2500, 0x8004, 0x20a8,
+	0x23a0, 0xa001, 0xa001, 0x4005, 0x2508, 0x080c, 0x8d8f, 0x2130,
+	0x7014, 0x9600, 0x7016, 0x2600, 0x711c, 0x9102, 0x701e, 0x7004,
+	0x9600, 0x2008, 0x9082, 0x000a, 0x1190, 0x7000, 0x2048, 0xa800,
+	0x9005, 0x1148, 0x2009, 0x0001, 0x0026, 0x080c, 0x8c7d, 0x002e,
+	0x7000, 0x2048, 0xa800, 0x7002, 0x7007, 0x0000, 0x0008, 0x7106,
+	0x2500, 0x9212, 0x1904, 0x8cbc, 0x012e, 0x00ee, 0x014e, 0x013e,
+	0x015e, 0x009e, 0x0005, 0x0016, 0x0026, 0x00e6, 0x0126, 0x2091,
+	0x8000, 0x9580, 0x8e4c, 0x2005, 0x9075, 0x090c, 0x0d7d, 0x080c,
+	0x8d61, 0x012e, 0x9580, 0x8e48, 0x2005, 0x9075, 0x090c, 0x0d7d,
+	0x0156, 0x0136, 0x01c6, 0x0146, 0x01d6, 0x831f, 0x831e, 0x831e,
+	0x9384, 0x003f, 0x20e0, 0x9384, 0xffc0, 0x9100, 0x2098, 0xa860,
+	0x20e8, 0xa95c, 0x2c05, 0x9100, 0x20a0, 0x20a9, 0x0002, 0x4003,
+	0x2e0c, 0x2d00, 0x0002, 0x8d4b, 0x8d4b, 0x8d4d, 0x8d4b, 0x8d4d,
+	0x8d4b, 0x8d4b, 0x8d4b, 0x8d4b, 0x8d4b, 0x8d53, 0x8d4b, 0x8d53,
+	0x8d4b, 0x8d4b, 0x8d4b, 0x080c, 0x0d7d, 0x4104, 0x20a9, 0x0002,
+	0x4002, 0x4003, 0x0028, 0x20a9, 0x0002, 0x4003, 0x4104, 0x4003,
+	0x01de, 0x014e, 0x01ce, 0x013e, 0x015e, 0x00ee, 0x002e, 0x001e,
+	0x0005, 0x0096, 0x7014, 0x8001, 0x7016, 0x710c, 0x2110, 0x00f1,
+	0x810c, 0x9188, 0x0003, 0x7308, 0x8210, 0x9282, 0x000a, 0x1198,
+	0x7008, 0x2048, 0xa800, 0x9005, 0x0158, 0x0006, 0x080c, 0x8e18,
+	0x009e, 0xa807, 0x0000, 0x2900, 0x700a, 0x7010, 0x8001, 0x7012,
+	0x700f, 0x0000, 0x0008, 0x720e, 0x009e, 0x0005, 0x0006, 0x810b,
+	0x810b, 0x2100, 0x810b, 0x9100, 0x2008, 0x000e, 0x0005, 0x0006,
+	0x0026, 0x2100, 0x9005, 0x0158, 0x9092, 0x000c, 0x0240, 0x900e,
+	0x8108, 0x9082, 0x000c, 0x1de0, 0x002e, 0x000e, 0x0005, 0x900e,
+	0x0cd8, 0x2d00, 0x90b8, 0x0008, 0x2031, 0x8dd2, 0x901e, 0x6808,
+	0x9005, 0x0108, 0x8318, 0x690c, 0x910a, 0x0248, 0x0140, 0x8318,
+	0x6810, 0x9112, 0x0220, 0x0118, 0x8318, 0x2208, 0x0cd0, 0x233a,
+	0x6804, 0xd084, 0x2300, 0x2021, 0x0001, 0x1150, 0x9082, 0x0003,
+	0x0967, 0x0a67, 0x8420, 0x9082, 0x0007, 0x0967, 0x0a67, 0x0cd0,
+	0x9082, 0x0002, 0x0967, 0x0a67, 0x8420, 0x9082, 0x0005, 0x0967,
+	0x0a67, 0x0cd0, 0x6c1a, 0x0005, 0x0096, 0x0046, 0x0126, 0x2091,
+	0x8000, 0x2b00, 0x9080, 0x8e50, 0x2005, 0x9005, 0x090c, 0x0d7d,
+	0x2004, 0x90a0, 0x000a, 0x080c, 0x1060, 0x01d0, 0x2900, 0x7026,
+	0xa803, 0x0000, 0xa807, 0x0000, 0x080c, 0x1060, 0x0188, 0x7024,
+	0xa802, 0xa807, 0x0000, 0x2900, 0x7026, 0x94a2, 0x000a, 0x0110,
+	0x0208, 0x0c90, 0x9085, 0x0001, 0x012e, 0x004e, 0x009e, 0x0005,
+	0x7024, 0x9005, 0x0dc8, 0x2048, 0xac00, 0x080c, 0x1079, 0x2400,
+	0x0cc0, 0x0126, 0x2091, 0x8000, 0x7024, 0x2048, 0x9005, 0x0130,
+	0xa800, 0x7026, 0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x7024, 0xa802, 0x2900, 0x7026, 0x012e,
+	0x0005, 0x0096, 0x9e80, 0x0009, 0x2004, 0x9005, 0x0138, 0x2048,
+	0xa800, 0x0006, 0x080c, 0x1079, 0x000e, 0x0cb8, 0x009e, 0x0005,
+	0x0096, 0x7008, 0x9005, 0x0138, 0x2048, 0xa800, 0x0006, 0x080c,
+	0x1079, 0x000e, 0x0cb8, 0x9006, 0x7002, 0x700a, 0x7006, 0x700e,
+	0x701a, 0x701e, 0x7022, 0x702a, 0x7026, 0x702e, 0x009e, 0x0005,
+	0x1a6c, 0x0000, 0x0000, 0x0000, 0x1930, 0x0000, 0x0000, 0x0000,
+	0x1888, 0x0000, 0x0000, 0x0000, 0x1877, 0x0000, 0x0000, 0x0000,
+	0x00e6, 0x00c6, 0x00b6, 0x00a6, 0xa8a8, 0x2040, 0x2071, 0x1877,
+	0x080c, 0x8f74, 0xa067, 0x0023, 0x6010, 0x905d, 0x0904, 0x8f49,
+	0xb814, 0xa06e, 0xb910, 0xa172, 0xb9a0, 0xa176, 0x2001, 0x0003,
+	0xa07e, 0xa834, 0xa082, 0xa07b, 0x0000, 0xa898, 0x9005, 0x0118,
+	0xa078, 0xc085, 0xa07a, 0x2858, 0x2031, 0x0018, 0xa068, 0x908a,
+	0x0019, 0x1a0c, 0x0d7d, 0x2020, 0x2050, 0x2940, 0xa864, 0x90bc,
+	0x00ff, 0x908c, 0x000f, 0x91e0, 0x1eab, 0x2c65, 0x9786, 0x0024,
+	0x2c05, 0x1590, 0x908a, 0x0036, 0x1a0c, 0x0d7d, 0x9082, 0x001b,
+	0x0002, 0x8eb4, 0x8eb4, 0x8eb6, 0x8eb4, 0x8eb4, 0x8eb4, 0x8eb8,
+	0x8eb4, 0x8eb4, 0x8eb4, 0x8eba, 0x8eb4, 0x8eb4, 0x8eb4, 0x8ebc,
+	0x8eb4, 0x8eb4, 0x8eb4, 0x8ebe, 0x8eb4, 0x8eb4, 0x8eb4, 0x8ec0,
+	0x8eb4, 0x8eb4, 0x8eb4, 0x8ec2, 0x080c, 0x0d7d, 0xa180, 0x04b8,
+	0xa190, 0x04a8, 0xa1a0, 0x0498, 0xa1b0, 0x0488, 0xa1c0, 0x0478,
+	0xa1d0, 0x0468, 0xa1e0, 0x0458, 0x908a, 0x0034, 0x1a0c, 0x0d7d,
+	0x9082, 0x001b, 0x0002, 0x8ee6, 0x8ee4, 0x8ee4, 0x8ee4, 0x8ee4,
+	0x8ee4, 0x8ee8, 0x8ee4, 0x8ee4, 0x8ee4, 0x8ee4, 0x8ee4, 0x8eea,
+	0x8ee4, 0x8ee4, 0x8ee4, 0x8ee4, 0x8ee4, 0x8eec, 0x8ee4, 0x8ee4,
+	0x8ee4, 0x8ee4, 0x8ee4, 0x8eee, 0x080c, 0x0d7d, 0xa180, 0x0038,
+	0xa198, 0x0028, 0xa1b0, 0x0018, 0xa1c8, 0x0008, 0xa1e0, 0x2600,
+	0x0002, 0x8f0a, 0x8f0c, 0x8f0e, 0x8f10, 0x8f12, 0x8f14, 0x8f16,
+	0x8f18, 0x8f1a, 0x8f1c, 0x8f1e, 0x8f20, 0x8f22, 0x8f24, 0x8f26,
+	0x8f28, 0x8f2a, 0x8f2c, 0x8f2e, 0x8f30, 0x8f32, 0x8f34, 0x8f36,
+	0x8f38, 0x8f3a, 0x080c, 0x0d7d, 0xb9e2, 0x0468, 0xb9de, 0x0458,
+	0xb9da, 0x0448, 0xb9d6, 0x0438, 0xb9d2, 0x0428, 0xb9ce, 0x0418,
+	0xb9ca, 0x0408, 0xb9c6, 0x00f8, 0xb9c2, 0x00e8, 0xb9be, 0x00d8,
+	0xb9ba, 0x00c8, 0xb9b6, 0x00b8, 0xb9b2, 0x00a8, 0xb9ae, 0x0098,
+	0xb9aa, 0x0088, 0xb9a6, 0x0078, 0xb9a2, 0x0068, 0xb99e, 0x0058,
+	0xb99a, 0x0048, 0xb996, 0x0038, 0xb992, 0x0028, 0xb98e, 0x0018,
+	0xb98a, 0x0008, 0xb986, 0x8631, 0x8421, 0x0130, 0x080c, 0x1e81,
+	0x090c, 0x0d7d, 0x0804, 0x8e8e, 0x00ae, 0x00be, 0x00ce, 0x00ee,
+	0x0005, 0xa86c, 0xa06e, 0xa870, 0xa072, 0xa077, 0x00ff, 0x9006,
+	0x0804, 0x8e70, 0x0006, 0x0016, 0x00b6, 0x6010, 0x2058, 0xb810,
+	0x9005, 0x01b0, 0x2001, 0x1924, 0x2004, 0x9005, 0x0188, 0x2001,
+	0x1800, 0x2004, 0x9086, 0x0003, 0x1158, 0x0036, 0x0046, 0xbba0,
+	0x2021, 0x0004, 0x2011, 0x8014, 0x080c, 0x4b52, 0x004e, 0x003e,
+	0x00be, 0x001e, 0x000e, 0x0005, 0x9016, 0x710c, 0xa834, 0x910a,
+	0xa936, 0x7008, 0x9005, 0x0120, 0x8210, 0x910a, 0x0238, 0x0130,
+	0x7010, 0x8210, 0x910a, 0x0210, 0x0108, 0x0cd8, 0xaa8a, 0xa26a,
+	0x0005, 0x00f6, 0x00d6, 0x0036, 0x2079, 0x0300, 0x781b, 0x0200,
+	0x7818, 0xd094, 0x1dd8, 0x781b, 0x0202, 0xa001, 0xa001, 0x7818,
+	0xd094, 0x1da0, 0xb8ac, 0x9005, 0x01b8, 0x2068, 0x2079, 0x0000,
+	0x2c08, 0x911e, 0x1118, 0x680c, 0xb8ae, 0x0060, 0x9106, 0x0140,
+	0x2d00, 0x2078, 0x680c, 0x9005, 0x090c, 0x0d7d, 0x2068, 0x0cb0,
+	0x6b0c, 0x7b0e, 0x600f, 0x0000, 0x2079, 0x0300, 0x781b, 0x0200,
+	0x003e, 0x00de, 0x00fe, 0x0005, 0x00e6, 0x00d6, 0x0096, 0x00c6,
+	0x0036, 0x0126, 0x2091, 0x8000, 0x0156, 0x20a9, 0x01ff, 0x2071,
+	0x0300, 0x701b, 0x0200, 0x7018, 0xd094, 0x0110, 0x1f04, 0x8fc9,
+	0x701b, 0x0202, 0xa001, 0xa001, 0x7018, 0xd094, 0x1d90, 0xb8ac,
+	0x9005, 0x01e8, 0x2060, 0x600c, 0xb8ae, 0x6024, 0xc08d, 0x6026,
+	0x6003, 0x0004, 0x601b, 0x0000, 0x6013, 0x0000, 0x601f, 0x0101,
+	0x6014, 0x2048, 0xa88b, 0x0000, 0xa8a8, 0xa8ab, 0x0000, 0x904d,
+	0x090c, 0x0d7d, 0x080c, 0x1079, 0x080c, 0x8b89, 0x0c00, 0x2071,
+	0x0300, 0x701b, 0x0200, 0x015e, 0x012e, 0x003e, 0x00ce, 0x009e,
+	0x00de, 0x00ee, 0x0005, 0x00c6, 0x00b6, 0x0016, 0x0006, 0x0156,
+	0x080c, 0x2661, 0x015e, 0x11b0, 0x080c, 0x6632, 0x190c, 0x0d7d,
+	0x000e, 0x001e, 0xb912, 0xb816, 0x080c, 0xac5a, 0x0140, 0x2b00,
+	0x6012, 0x6023, 0x0001, 0x2009, 0x0001, 0x080c, 0xad4d, 0x00be,
+	0x00ce, 0x0005, 0x000e, 0x001e, 0x0cd0, 0x0066, 0x6000, 0x90b2,
+	0x0016, 0x1a0c, 0x0d7d, 0x0013, 0x006e, 0x0005, 0x903e, 0x903e,
+	0x903e, 0x9040, 0x9089, 0x903e, 0x903e, 0x903e, 0x90f0, 0x903e,
+	0x9128, 0x903e, 0x903e, 0x903e, 0x903e, 0x903e, 0x080c, 0x0d7d,
+	0x9182, 0x0040, 0x0002, 0x9053, 0x9053, 0x9053, 0x9053, 0x9053,
+	0x9053, 0x9053, 0x9053, 0x9053, 0x9055, 0x9066, 0x9053, 0x9053,
+	0x9053, 0x9053, 0x9077, 0x080c, 0x0d7d, 0x0096, 0x6114, 0x2148,
+	0xa87b, 0x0000, 0x6010, 0x00b6, 0x2058, 0xb8bb, 0x0500, 0x00be,
+	0x080c, 0x6bee, 0x080c, 0xacb0, 0x009e, 0x0005, 0x080c, 0x96d5,
+	0x00d6, 0x6114, 0x080c, 0xc97a, 0x0130, 0x0096, 0x6114, 0x2148,
+	0x080c, 0x6dee, 0x009e, 0x00de, 0x080c, 0xacb0, 0x0005, 0x080c,
+	0x96d5, 0x080c, 0x3240, 0x6114, 0x0096, 0x2148, 0x080c, 0xc97a,
+	0x0120, 0xa87b, 0x0029, 0x080c, 0x6dee, 0x009e, 0x080c, 0xacb0,
+	0x0005, 0x601b, 0x0000, 0x9182, 0x0040, 0x0096, 0x0002, 0x90a4,
+	0x90a4, 0x90a4, 0x90a4, 0x90a4, 0x90a4, 0x90a4, 0x90a4, 0x90a6,
+	0x90a4, 0x90a4, 0x90a4, 0x90ec, 0x90a4, 0x90a4, 0x90a4, 0x90a4,
+	0x90a4, 0x90a4, 0x90ad, 0x90a4, 0x080c, 0x0d7d, 0x6114, 0x2148,
+	0xa938, 0x918e, 0xffff, 0x0904, 0x90ec, 0x6024, 0xd08c, 0x15c0,
+	0x00e6, 0x6114, 0x2148, 0x080c, 0x8e58, 0x0096, 0xa8a8, 0x2048,
+	0x080c, 0x6b86, 0x009e, 0xa8ab, 0x0000, 0x6010, 0x9005, 0x0128,
+	0x00b6, 0x2058, 0x080c, 0x8f89, 0x00be, 0xae88, 0x00b6, 0x2059,
+	0x0000, 0x080c, 0x8b92, 0x00be, 0x01e0, 0x2071, 0x193c, 0x080c,
+	0x8bd9, 0x01b8, 0x9086, 0x0001, 0x1128, 0x2001, 0x1946, 0x2004,
+	0x9005, 0x1178, 0x0096, 0x080c, 0x1047, 0x2900, 0x009e, 0x0148,
+	0xa8aa, 0x00f6, 0x2c78, 0x080c, 0x8b4d, 0x00fe, 0x00ee, 0x009e,
+	0x0005, 0x080c, 0x8b89, 0x0cd0, 0x080c, 0x91a4, 0x009e, 0x0005,
+	0x9182, 0x0040, 0x0096, 0x0002, 0x9104, 0x9104, 0x9104, 0x9106,
+	0x9104, 0x9104, 0x9104, 0x9126, 0x9104, 0x9104, 0x9104, 0x9104,
+	0x9104, 0x9104, 0x9104, 0x9104, 0x080c, 0x0d7d, 0x6003, 0x0003,
+	0x6106, 0x6014, 0x2048, 0xa8ac, 0xa836, 0xa8b0, 0xa83a, 0xa847,
+	0x0000, 0xa84b, 0x0000, 0xa884, 0x9092, 0x199a, 0x0210, 0x2001,
+	0x1999, 0x8003, 0x8013, 0x8213, 0x9210, 0x621a, 0x080c, 0x1c10,
+	0x2009, 0x8030, 0x080c, 0x92f7, 0x009e, 0x0005, 0x080c, 0x0d7d,
+	0x080c, 0x96d5, 0x6114, 0x2148, 0xa87b, 0x0000, 0x6010, 0x00b6,
+	0x2058, 0xb8bb, 0x0500, 0x00be, 0x080c, 0x6dee, 0x080c, 0xacb0,
+	0x009e, 0x0005, 0x080c, 0xa91e, 0x6144, 0xd1fc, 0x0120, 0xd1ac,
+	0x1110, 0x6003, 0x0003, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0d7d,
+	0x0096, 0x0023, 0x009e, 0x080c, 0xa93a, 0x0005, 0x915e, 0x915e,
+	0x915e, 0x9160, 0x9171, 0x915e, 0x915e, 0x915e, 0x915e, 0x915e,
+	0x915e, 0x915e, 0x915e, 0x915e, 0x915e, 0x915e, 0x080c, 0x0d7d,
+	0x080c, 0xaab5, 0x6114, 0x2148, 0xa87b, 0x0006, 0x6010, 0x00b6,
+	0x2058, 0xb8bb, 0x0500, 0x00be, 0x080c, 0x6dee, 0x080c, 0xacb0,
+	0x0005, 0x0491, 0x0005, 0x080c, 0xa91e, 0x6000, 0x6144, 0xd1fc,
+	0x0130, 0xd1ac, 0x1120, 0x6003, 0x0003, 0x2009, 0x0003, 0x908a,
+	0x0016, 0x1a0c, 0x0d7d, 0x0096, 0x0033, 0x009e, 0x0106, 0x080c,
+	0xa93a, 0x010e, 0x0005, 0x919b, 0x919b, 0x919b, 0x919d, 0x91a4,
+	0x919b, 0x919b, 0x919b, 0x919b, 0x919b, 0x919b, 0x919b, 0x919b,
+	0x919b, 0x919b, 0x919b, 0x080c, 0x0d7d, 0x0036, 0x00e6, 0x080c,
+	0xaab5, 0x00ee, 0x003e, 0x0005, 0x6024, 0xd08c, 0x11f0, 0x00f6,
+	0x00e6, 0x601b, 0x0000, 0x6014, 0x2048, 0x6010, 0x9005, 0x0128,
+	0x00b6, 0x2058, 0x080c, 0x8f89, 0x00be, 0x2071, 0x193c, 0x080c,
+	0x8bd9, 0x0160, 0x2001, 0x187f, 0x2004, 0xa88a, 0x2031, 0x0000,
+	0x2c78, 0x080c, 0x8b4d, 0x00ee, 0x00fe, 0x0005, 0x0096, 0xa88b,
+	0x0000, 0xa8a8, 0x2048, 0x080c, 0x1079, 0x009e, 0xa8ab, 0x0000,
+	0x080c, 0x8b89, 0x0c80, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0000, 0x187a, 0x0000, 0x0000, 0x0000,
+	0x0000, 0x0000, 0x0000, 0x0126, 0x2091, 0x8000, 0x0036, 0x0046,
+	0x20a9, 0x0010, 0x9006, 0x8004, 0x8086, 0x818e, 0x1208, 0x9200,
+	0x1f04, 0x91ec, 0x8086, 0x818e, 0x004e, 0x003e, 0x012e, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x0076, 0x0156, 0x20a9, 0x0010, 0x9005,
+	0x01c8, 0x911a, 0x12b8, 0x8213, 0x818d, 0x0228, 0x911a, 0x1220,
+	0x1f04, 0x9203, 0x0028, 0x911a, 0x2308, 0x8210, 0x1f04, 0x9203,
+	0x0006, 0x3200, 0x9084, 0xefff, 0x2080, 0x000e, 0x015e, 0x007e,
+	0x012e, 0x0005, 0x0006, 0x3200, 0x9085, 0x1000, 0x0ca8, 0x0126,
+	0x2091, 0x2800, 0x2079, 0x19e6, 0x012e, 0x00d6, 0x2069, 0x19e6,
+	0x6803, 0x0005, 0x0156, 0x0146, 0x01d6, 0x20e9, 0x0000, 0x2069,
+	0x0200, 0x080c, 0xa713, 0x04a9, 0x080c, 0xa6fe, 0x0491, 0x080c,
+	0xa701, 0x0479, 0x080c, 0xa704, 0x0461, 0x080c, 0xa707, 0x0449,
+	0x080c, 0xa70a, 0x0431, 0x080c, 0xa70d, 0x0419, 0x080c, 0xa710,
+	0x0401, 0x01de, 0x014e, 0x015e, 0x6857, 0x0000, 0x00f6, 0x2079,
+	0x0380, 0x00f9, 0x7807, 0x0003, 0x7803, 0x0000, 0x7803, 0x0001,
+	0x2069, 0x0004, 0x2d04, 0x9084, 0xfffe, 0x9085, 0x8000, 0x206a,
+	0x2069, 0x0100, 0x6828, 0x9084, 0xfffc, 0x682a, 0x00fe, 0x00de,
+	0x0005, 0x20a9, 0x0020, 0x20a1, 0x0240, 0x2001, 0x0000, 0x4004,
+	0x0005, 0x00c6, 0x7803, 0x0000, 0x9006, 0x7827, 0x0030, 0x782b,
+	0x0400, 0x7827, 0x0031, 0x782b, 0x1af1, 0x781f, 0xff00, 0x781b,
+	0xff00, 0x2061, 0x1ae6, 0x602f, 0x19e6, 0x6033, 0x1800, 0x6037,
+	0x1a02, 0x603b, 0x1eab, 0x603f, 0x1ebb, 0x6042, 0x6047, 0x1abc,
+	0x00ce, 0x0005, 0x2001, 0x0382, 0x2004, 0x9084, 0x0007, 0x9086,
+	0x0001, 0x01b0, 0x00c6, 0x6146, 0x600f, 0x0000, 0x2c08, 0x2061,
+	0x19e6, 0x602c, 0x8000, 0x602e, 0x601c, 0x9005, 0x0130, 0x9080,
+	0x0003, 0x2102, 0x611e, 0x00ce, 0x0005, 0x6122, 0x611e, 0x0cd8,
+	0x6146, 0x2c08, 0x2001, 0x0012, 0x080c, 0xa90f, 0x0005, 0x0016,
+	0x2009, 0x8020, 0x6146, 0x2c08, 0x2001, 0x0382, 0x2004, 0x9084,
+	0x0007, 0x9086, 0x0001, 0x1128, 0x2001, 0x0019, 0x080c, 0xa90f,
+	0x0088, 0x00c6, 0x2061, 0x19e6, 0x602c, 0x8000, 0x602e, 0x600c,
+	0x9005, 0x0128, 0x9080, 0x0003, 0x2102, 0x610e, 0x0010, 0x6112,
+	0x610e, 0x00ce, 0x001e, 0x0005, 0x2001, 0x0382, 0x2004, 0x9084,
+	0x0007, 0x9086, 0x0001, 0x0198, 0x00c6, 0x6146, 0x600f, 0x0000,
+	0x2c08, 0x2061, 0x19e6, 0x6044, 0x9005, 0x0130, 0x9080, 0x0003,
+	0x2102, 0x6146, 0x00ce, 0x0005, 0x614a, 0x6146, 0x0cd8, 0x6146,
+	0x600f, 0x0000, 0x2c08, 0x2001, 0x0013, 0x080c, 0xa90f, 0x0005,
+	0x6044, 0xd0dc, 0x0110, 0x080c, 0xa3ac, 0x0005, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x00b6, 0x0096, 0x0076, 0x0066, 0x0056, 0x0036,
+	0x0026, 0x0016, 0x0006, 0x0126, 0x902e, 0x2071, 0x19e6, 0x7648,
+	0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904, 0x9383, 0x6010,
+	0x2058, 0xb8a0, 0x9206, 0x1904, 0x937e, 0x87ff, 0x0120, 0x605c,
+	0x9106, 0x1904, 0x937e, 0x704c, 0x9c06, 0x1178, 0x0036, 0x2019,
+	0x0001, 0x080c, 0xa1b8, 0x703f, 0x0000, 0x9006, 0x704e, 0x706a,
+	0x7052, 0x706e, 0x003e, 0x2029, 0x0001, 0x0811, 0x7048, 0x9c36,
+	0x1110, 0x660c, 0x764a, 0x7044, 0x9c36, 0x1140, 0x2c00, 0x9f36,
+	0x0118, 0x2f00, 0x7046, 0x0010, 0x7047, 0x0000, 0x660c, 0x0066,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x080c, 0xc97a, 0x01f0, 0x6014, 0x2048, 0x6020, 0x9086, 0x0003,
+	0x1588, 0x6004, 0x9086, 0x0040, 0x090c, 0xa3ac, 0xa867, 0x0103,
+	0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0076, 0x080c, 0xcc7f,
+	0x080c, 0xe79d, 0x080c, 0x6dee, 0x007e, 0x003e, 0x001e, 0x080c,
+	0xcb6b, 0x080c, 0xaceb, 0x00ce, 0x0804, 0x931c, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0x931c, 0x012e, 0x000e, 0x001e, 0x002e, 0x003e,
+	0x005e, 0x006e, 0x007e, 0x009e, 0x00be, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036,
+	0x0076, 0x080c, 0xe79d, 0x080c, 0xe3e8, 0x007e, 0x003e, 0x001e,
+	0x08c0, 0x6020, 0x9086, 0x0009, 0x1168, 0xa87b, 0x0006, 0x0016,
+	0x0036, 0x0076, 0x080c, 0x6dee, 0x080c, 0xacb0, 0x007e, 0x003e,
+	0x001e, 0x0848, 0x6020, 0x9086, 0x000a, 0x0904, 0x9368, 0x0804,
+	0x9361, 0x0006, 0x0066, 0x0096, 0x00c6, 0x00d6, 0x00f6, 0x9036,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x19e6, 0x7848, 0x9065, 0x0904,
+	0x941d, 0x600c, 0x0006, 0x600f, 0x0000, 0x784c, 0x9c06, 0x11a0,
+	0x0036, 0x2019, 0x0001, 0x080c, 0xa1b8, 0x783f, 0x0000, 0x901e,
+	0x7b4e, 0x7b6a, 0x7b52, 0x7b6e, 0x003e, 0x000e, 0x9005, 0x1118,
+	0x600c, 0x600f, 0x0000, 0x0006, 0x00e6, 0x2f70, 0x080c, 0x9300,
+	0x00ee, 0x080c, 0xc97a, 0x0548, 0x6014, 0x2048, 0x6020, 0x9086,
+	0x0003, 0x15a8, 0x3e08, 0x918e, 0x0002, 0x1188, 0x6010, 0x9005,
+	0x0170, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0140, 0x6048,
+	0x9005, 0x11c0, 0x2001, 0x1987, 0x2004, 0x604a, 0x0098, 0x6004,
+	0x9086, 0x0040, 0x090c, 0xa3ac, 0xa867, 0x0103, 0xab7a, 0xa877,
+	0x0000, 0x080c, 0x6de2, 0x080c, 0xcb6b, 0x6044, 0xc0fc, 0x6046,
+	0x080c, 0xaceb, 0x000e, 0x0804, 0x93c6, 0x7e4a, 0x7e46, 0x012e,
+	0x00fe, 0x00de, 0x00ce, 0x009e, 0x006e, 0x000e, 0x0005, 0x6020,
+	0x9086, 0x0006, 0x1118, 0x080c, 0xe3e8, 0x0c38, 0x6020, 0x9086,
+	0x0009, 0x1130, 0xab7a, 0x080c, 0x6dee, 0x080c, 0xacb0, 0x0c10,
+	0x6020, 0x9086, 0x000a, 0x0990, 0x0850, 0x0016, 0x0026, 0x0086,
+	0x9046, 0x00a9, 0x080c, 0x9530, 0x008e, 0x002e, 0x001e, 0x0005,
+	0x00f6, 0x0126, 0x2079, 0x19e6, 0x2091, 0x8000, 0x080c, 0x9579,
+	0x080c, 0x960f, 0x080c, 0x6820, 0x012e, 0x00fe, 0x0005, 0x00b6,
+	0x0096, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006,
+	0x0126, 0x2091, 0x8000, 0x2071, 0x19e6, 0x7620, 0x2660, 0x2678,
+	0x8cff, 0x0904, 0x94f5, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1904,
+	0x94f0, 0x88ff, 0x0120, 0x605c, 0x9106, 0x1904, 0x94f0, 0x7030,
+	0x9c06, 0x1580, 0x2069, 0x0100, 0x6820, 0xd0a4, 0x0110, 0xd0cc,
+	0x1508, 0x080c, 0x8780, 0x080c, 0x9ed4, 0x68c3, 0x0000, 0x080c,
+	0xa3ac, 0x7033, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384,
+	0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c,
+	0x2a7a, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001,
+	0x003e, 0x0040, 0x7008, 0xc0ad, 0x700a, 0x6003, 0x0009, 0x630a,
+	0x0804, 0x94f0, 0x7020, 0x9c36, 0x1110, 0x660c, 0x7622, 0x701c,
+	0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x701e, 0x0010,
+	0x701f, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e,
+	0x0008, 0x2678, 0x600f, 0x0000, 0x6044, 0xc0fc, 0x6046, 0x6014,
+	0x2048, 0x080c, 0xc97a, 0x01e8, 0x6020, 0x9086, 0x0003, 0x1580,
+	0x080c, 0xcb91, 0x1118, 0x080c, 0xb693, 0x0098, 0xa867, 0x0103,
+	0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0086, 0x080c, 0xcc7f,
+	0x080c, 0xe79d, 0x080c, 0x6dee, 0x008e, 0x003e, 0x001e, 0x080c,
+	0xcb6b, 0x080c, 0xaceb, 0x080c, 0xa282, 0x00ce, 0x0804, 0x9468,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0x9468, 0x012e, 0x000e, 0x001e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x009e, 0x00be, 0x0005,
+	0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036, 0x0086, 0x080c,
+	0xe79d, 0x080c, 0xe3e8, 0x008e, 0x003e, 0x001e, 0x08d0, 0x080c,
+	0xb693, 0x6020, 0x9086, 0x0002, 0x1160, 0x6004, 0x0006, 0x9086,
+	0x0085, 0x000e, 0x0904, 0x94d6, 0x9086, 0x008b, 0x0904, 0x94d6,
+	0x0840, 0x6020, 0x9086, 0x0005, 0x1920, 0x6004, 0x0006, 0x9086,
+	0x0085, 0x000e, 0x09c8, 0x9086, 0x008b, 0x09b0, 0x0804, 0x94e9,
+	0x0006, 0x00f6, 0x00e6, 0x0096, 0x00b6, 0x00c6, 0x0066, 0x0016,
+	0x0126, 0x2091, 0x8000, 0x9280, 0x1000, 0x2004, 0x905d, 0x2079,
+	0x19e6, 0x9036, 0x7828, 0x2060, 0x8cff, 0x0538, 0x6010, 0x9b06,
+	0x1500, 0x6043, 0xffff, 0x080c, 0xab00, 0x01d8, 0x610c, 0x0016,
+	0x080c, 0xa042, 0x6014, 0x2048, 0xa867, 0x0103, 0xab7a, 0xa877,
+	0x0000, 0x0016, 0x0036, 0x0086, 0x080c, 0xcc7f, 0x080c, 0xe79d,
+	0x080c, 0x6dee, 0x008e, 0x003e, 0x001e, 0x080c, 0xaceb, 0x00ce,
+	0x08d8, 0x2c30, 0x600c, 0x2060, 0x08b8, 0x080c, 0x683d, 0x012e,
+	0x001e, 0x006e, 0x00ce, 0x00be, 0x009e, 0x00ee, 0x00fe, 0x000e,
+	0x0005, 0x0096, 0x0006, 0x0066, 0x00c6, 0x00d6, 0x9036, 0x7820,
+	0x9065, 0x0904, 0x95e2, 0x600c, 0x0006, 0x6044, 0xc0fc, 0x6046,
+	0x600f, 0x0000, 0x7830, 0x9c06, 0x1598, 0x2069, 0x0100, 0x6820,
+	0xd0a4, 0x0110, 0xd0cc, 0x1508, 0x080c, 0x8780, 0x080c, 0x9ed4,
+	0x68c3, 0x0000, 0x080c, 0xa3ac, 0x7833, 0x0000, 0x0036, 0x2069,
+	0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0110, 0x6827, 0x0001, 0x003e, 0x0058, 0x080c, 0x6a75, 0x1538,
+	0x6003, 0x0009, 0x630a, 0x7808, 0xc0ad, 0x780a, 0x2c30, 0x00f8,
+	0x6014, 0x2048, 0x080c, 0xc978, 0x01b0, 0x6020, 0x9086, 0x0003,
+	0x1508, 0x080c, 0xcb91, 0x1118, 0x080c, 0xb693, 0x0060, 0x080c,
+	0x6a75, 0x1168, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0x6dee, 0x080c, 0xcb6b, 0x080c, 0xaceb, 0x080c, 0xa282, 0x000e,
+	0x0804, 0x9580, 0x7e22, 0x7e1e, 0x00de, 0x00ce, 0x006e, 0x000e,
+	0x009e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xe3e8,
+	0x0c50, 0x080c, 0xb693, 0x6020, 0x9086, 0x0002, 0x1150, 0x6004,
+	0x0006, 0x9086, 0x0085, 0x000e, 0x0990, 0x9086, 0x008b, 0x0978,
+	0x08d0, 0x6020, 0x9086, 0x0005, 0x19b0, 0x6004, 0x0006, 0x9086,
+	0x0085, 0x000e, 0x0d18, 0x9086, 0x008b, 0x0d00, 0x0860, 0x0006,
+	0x0096, 0x00b6, 0x00c6, 0x0066, 0x9036, 0x7828, 0x9065, 0x0510,
+	0x6010, 0x2058, 0x600c, 0x0006, 0x3e08, 0x918e, 0x0002, 0x1118,
+	0xb800, 0xd0bc, 0x11a8, 0x6043, 0xffff, 0x080c, 0xab00, 0x0180,
+	0x610c, 0x080c, 0xa042, 0x6014, 0x2048, 0xa867, 0x0103, 0xab7a,
+	0xa877, 0x0000, 0x080c, 0x6dee, 0x080c, 0xaceb, 0x000e, 0x08f0,
+	0x2c30, 0x0ce0, 0x006e, 0x00ce, 0x00be, 0x009e, 0x000e, 0x0005,
+	0x00e6, 0x00d6, 0x0096, 0x0066, 0x080c, 0x61a4, 0x11b0, 0x2071,
+	0x19e6, 0x7030, 0x9080, 0x0005, 0x2004, 0x904d, 0x0170, 0xa878,
+	0x9606, 0x1158, 0x2071, 0x19e6, 0x7030, 0x9035, 0x0130, 0x9080,
+	0x0005, 0x2004, 0x9906, 0x1108, 0x0029, 0x006e, 0x009e, 0x00de,
+	0x00ee, 0x0005, 0x00c6, 0x2660, 0x6043, 0xffff, 0x080c, 0xab00,
+	0x0178, 0x080c, 0xa042, 0x6014, 0x2048, 0xa867, 0x0103, 0xab7a,
+	0xa877, 0x0000, 0x080c, 0xcc7f, 0x080c, 0x6dee, 0x080c, 0xaceb,
+	0x00ce, 0x0005, 0x00b6, 0x00e6, 0x00c6, 0x080c, 0xa91e, 0x0106,
+	0x2071, 0x0101, 0x2e04, 0xc0c4, 0x2072, 0x6044, 0xd0fc, 0x1138,
+	0x010e, 0x090c, 0xa93a, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x2071,
+	0x19e6, 0x7030, 0x9005, 0x0da0, 0x9c06, 0x190c, 0x0d7d, 0x7036,
+	0x080c, 0x8780, 0x7004, 0x9084, 0x0007, 0x0002, 0x96a8, 0x96aa,
+	0x96b1, 0x96bb, 0x96c9, 0x96a8, 0x96b6, 0x96a6, 0x080c, 0x0d7d,
+	0x0428, 0x0005, 0x080c, 0xaaeb, 0x7007, 0x0000, 0x7033, 0x0000,
+	0x00e8, 0x0066, 0x9036, 0x080c, 0xa042, 0x006e, 0x7007, 0x0000,
+	0x7033, 0x0000, 0x0098, 0x080c, 0xaad6, 0x0140, 0x080c, 0xaaeb,
+	0x0128, 0x0066, 0x9036, 0x080c, 0xa042, 0x006e, 0x7033, 0x0000,
+	0x0028, 0x080c, 0xaad6, 0x080c, 0xa3ac, 0x0000, 0x010e, 0x090c,
+	0xa93a, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x00d6, 0x00c6, 0x080c,
+	0xa91e, 0x0106, 0x6044, 0xd0fc, 0x1130, 0x010e, 0x090c, 0xa93a,
+	0x00ce, 0x00de, 0x0005, 0x2069, 0x19e6, 0x684c, 0x9005, 0x0da8,
+	0x9c06, 0x190c, 0x0d7d, 0x6852, 0x00e6, 0x2d70, 0x080c, 0x9300,
+	0x00ee, 0x080c, 0x878d, 0x0016, 0x2009, 0x0040, 0x080c, 0x220a,
+	0x001e, 0x683c, 0x9084, 0x0003, 0x0002, 0x9703, 0x9704, 0x9722,
+	0x9701, 0x080c, 0x0d7d, 0x0460, 0x6868, 0x9086, 0x0001, 0x0190,
+	0x600c, 0x9015, 0x0160, 0x6a4a, 0x600f, 0x0000, 0x6044, 0xc0fc,
+	0x6046, 0x9006, 0x7042, 0x684e, 0x683f, 0x0000, 0x00c8, 0x684a,
+	0x6846, 0x0ca0, 0x686b, 0x0000, 0x6848, 0x9065, 0x0d78, 0x6003,
+	0x0002, 0x0c60, 0x9006, 0x686a, 0x6852, 0x686e, 0x600c, 0x9015,
+	0x0120, 0x6a4a, 0x600f, 0x0000, 0x0018, 0x684e, 0x684a, 0x6846,
+	0x684f, 0x0000, 0x010e, 0x090c, 0xa93a, 0x00ce, 0x00de, 0x0005,
+	0x0005, 0x6020, 0x9084, 0x000f, 0x000b, 0x0005, 0x974e, 0x9751,
+	0x9bbf, 0x9c58, 0x9751, 0x9bbf, 0x9c58, 0x974e, 0x9751, 0x974e,
+	0x974e, 0x974e, 0x974e, 0x974e, 0x974e, 0x974e, 0x080c, 0x967a,
+	0x0005, 0x00b6, 0x0156, 0x0136, 0x0146, 0x01c6, 0x01d6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240, 0x6004,
+	0x908a, 0x0053, 0x1a0c, 0x0d7d, 0x6110, 0x2158, 0xb984, 0x2c78,
+	0x2061, 0x0100, 0x619a, 0x908a, 0x0040, 0x1a04, 0x97bd, 0x005b,
+	0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e,
+	0x015e, 0x00be, 0x0005, 0x9942, 0x997d, 0x99a6, 0x9a4e, 0x9a70,
+	0x9a76, 0x9a83, 0x9a8b, 0x9a97, 0x9a9d, 0x9aae, 0x9a9d, 0x9b06,
+	0x9a8b, 0x9b12, 0x9b18, 0x9a97, 0x9b18, 0x9b24, 0x97bb, 0x97bb,
+	0x97bb, 0x97bb, 0x97bb, 0x97bb, 0x97bb, 0x97bb, 0x97bb, 0x97bb,
+	0x97bb, 0xa063, 0xa086, 0xa097, 0xa0b7, 0xa0e9, 0x9a83, 0x97bb,
+	0x9a83, 0x9a9d, 0x97bb, 0x99a6, 0x9a4e, 0x97bb, 0xa4aa, 0x9a9d,
+	0x97bb, 0xa4c6, 0x9a9d, 0x97bb, 0x9a97, 0x993c, 0x97de, 0x97bb,
+	0xa4e2, 0xa54f, 0xa633, 0x97bb, 0xa640, 0x9a80, 0xa66b, 0x97bb,
+	0xa0f3, 0xa677, 0x97bb, 0x080c, 0x0d7d, 0x2100, 0x005b, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e,
+	0x00be, 0x0005, 0xa717, 0xa7c9, 0x97dc, 0x9805, 0x98b1, 0x98bc,
+	0x97dc, 0x9a83, 0x97dc, 0x9903, 0x990f, 0x9820, 0x97dc, 0x983b,
+	0x986f, 0xab56, 0xab9b, 0x9a9d, 0x080c, 0x0d7d, 0x00d6, 0x0096,
+	0x080c, 0x9b37, 0x7003, 0x2414, 0x7007, 0x0018, 0x700b, 0x0800,
+	0x7814, 0x2048, 0xa83c, 0x700e, 0xa850, 0x7022, 0xa854, 0x7026,
+	0x60c3, 0x0018, 0x080c, 0x9ea4, 0x009e, 0x00de, 0x0005, 0x7810,
+	0x00b6, 0x2058, 0xb8a0, 0x00be, 0x080c, 0xabe2, 0x1118, 0x9084,
+	0xff80, 0x0110, 0x9085, 0x0001, 0x0005, 0x00d6, 0x0096, 0x080c,
+	0x9b37, 0x7003, 0x0500, 0x7814, 0x2048, 0xa874, 0x700a, 0xa878,
+	0x700e, 0xa87c, 0x7012, 0xa880, 0x7016, 0xa884, 0x701a, 0xa888,
+	0x701e, 0x60c3, 0x0010, 0x080c, 0x9ea4, 0x009e, 0x00de, 0x0005,
+	0x00d6, 0x0096, 0x080c, 0x9b37, 0x7003, 0x0500, 0x7814, 0x2048,
+	0xa8cc, 0x700a, 0xa8d0, 0x700e, 0xa8d4, 0x7012, 0xa8d8, 0x7016,
+	0xa8dc, 0x701a, 0xa8e0, 0x701e, 0x60c3, 0x0010, 0x080c, 0x9ea4,
+	0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x9b37, 0x20e9, 0x0000, 0x2001, 0x19a2, 0x2003, 0x0000,
+	0x7814, 0x2048, 0xa814, 0x8003, 0x60c2, 0xa830, 0x20a8, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, 0x2001, 0x19a2, 0x0016,
+	0x200c, 0x2001, 0x0001, 0x080c, 0x21ef, 0x080c, 0xd72b, 0x9006,
+	0x080c, 0x21ef, 0x001e, 0xa804, 0x9005, 0x0110, 0x2048, 0x0c28,
+	0x04d9, 0x080c, 0x9ea4, 0x012e, 0x009e, 0x00de, 0x0005, 0x00d6,
+	0x0096, 0x0126, 0x2091, 0x8000, 0x080c, 0x9b82, 0x20e9, 0x0000,
+	0x2001, 0x19a2, 0x2003, 0x0000, 0x7814, 0x2048, 0xa86f, 0x0200,
+	0xa873, 0x0000, 0xa814, 0x8003, 0x60c2, 0xa830, 0x20a8, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, 0x2001, 0x19a2, 0x0016,
+	0x200c, 0x080c, 0xd72b, 0x001e, 0xa804, 0x9005, 0x0110, 0x2048,
+	0x0c60, 0x0051, 0x7814, 0x2048, 0x080c, 0x0ff9, 0x080c, 0x9ea4,
+	0x012e, 0x009e, 0x00de, 0x0005, 0x60c0, 0x8004, 0x9084, 0x0003,
+	0x9005, 0x0130, 0x9082, 0x0004, 0x20a3, 0x0000, 0x8000, 0x1de0,
+	0x0005, 0x080c, 0x9b37, 0x7003, 0x7800, 0x7808, 0x8007, 0x700a,
+	0x60c3, 0x0008, 0x0804, 0x9ea4, 0x00d6, 0x00e6, 0x080c, 0x9b82,
+	0x7814, 0x9084, 0xff00, 0x2073, 0x0200, 0x8e70, 0x8e70, 0x9095,
+	0x0010, 0x2272, 0x8e70, 0x2073, 0x0034, 0x8e70, 0x2069, 0x1805,
+	0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70, 0x1f04, 0x98d2, 0x2069,
+	0x1801, 0x20a9, 0x0004, 0x2d76, 0x8d68, 0x8e70, 0x1f04, 0x98db,
+	0x2069, 0x19b2, 0x9086, 0xdf00, 0x0110, 0x2069, 0x19cc, 0x20a9,
+	0x001a, 0x9e86, 0x0260, 0x1148, 0x00c6, 0x2061, 0x0200, 0x6010,
+	0x8000, 0x6012, 0x00ce, 0x2071, 0x0240, 0x2d04, 0x8007, 0x2072,
+	0x8d68, 0x8e70, 0x1f04, 0x98e9, 0x60c3, 0x004c, 0x080c, 0x9ea4,
+	0x00ee, 0x00de, 0x0005, 0x080c, 0x9b37, 0x7003, 0x6300, 0x7007,
+	0x0028, 0x7808, 0x700e, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x00d6,
+	0x0026, 0x0016, 0x080c, 0x9b82, 0x7003, 0x0200, 0x7814, 0x700e,
+	0x00e6, 0x9ef0, 0x0004, 0x2009, 0x0001, 0x2011, 0x000c, 0x2069,
+	0x1923, 0x6810, 0xd084, 0x1148, 0x2073, 0x0500, 0x8e70, 0x2073,
+	0x0000, 0x8e70, 0x8108, 0x9290, 0x0004, 0x2073, 0x0800, 0x8e70,
+	0x2073, 0x0000, 0x00ee, 0x7206, 0x710a, 0x62c2, 0x080c, 0x9ea4,
+	0x001e, 0x002e, 0x00de, 0x0005, 0x2001, 0x1818, 0x2004, 0x609a,
+	0x0804, 0x9ea4, 0x080c, 0x9b37, 0x7003, 0x5200, 0x2069, 0x1847,
+	0x6804, 0xd084, 0x0130, 0x6828, 0x0016, 0x080c, 0x2694, 0x710e,
+	0x001e, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9,
+	0x0000, 0x20a1, 0x0250, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801,
+	0x20a1, 0x0254, 0x4003, 0x080c, 0xabe2, 0x1120, 0xb8a0, 0x9082,
+	0x007f, 0x0248, 0x2001, 0x181f, 0x2004, 0x7032, 0x2001, 0x1820,
+	0x2004, 0x7036, 0x0030, 0x2001, 0x1818, 0x2004, 0x9084, 0x00ff,
+	0x7036, 0x60c3, 0x001c, 0x0804, 0x9ea4, 0x080c, 0x9b37, 0x7003,
+	0x0500, 0x080c, 0xabe2, 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248,
+	0x2001, 0x181f, 0x2004, 0x700a, 0x2001, 0x1820, 0x2004, 0x700e,
+	0x0030, 0x2001, 0x1818, 0x2004, 0x9084, 0x00ff, 0x700e, 0x20a9,
+	0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1,
+	0x0250, 0x4003, 0x60c3, 0x0010, 0x0804, 0x9ea4, 0x080c, 0x9b37,
+	0x9006, 0x080c, 0x6aa7, 0xb8a0, 0x9086, 0x007e, 0x1130, 0x7003,
+	0x0400, 0x620c, 0xc2b4, 0x620e, 0x0058, 0x7814, 0x0096, 0x904d,
+	0x0120, 0x9006, 0xa89a, 0xa8a6, 0xa8aa, 0x009e, 0x7003, 0x0300,
+	0xb8a0, 0x9086, 0x007e, 0x1904, 0x9a15, 0x00d6, 0x2069, 0x196b,
+	0x2001, 0x1837, 0x2004, 0xd0a4, 0x0188, 0x6800, 0x700a, 0x6808,
+	0x9084, 0x2000, 0x7012, 0x080c, 0xabf9, 0x680c, 0x7016, 0x701f,
+	0x2710, 0x6818, 0x7022, 0x681c, 0x7026, 0x0090, 0x6800, 0x700a,
+	0x6804, 0x700e, 0x6808, 0x080c, 0x753d, 0x1118, 0x9084, 0x37ff,
+	0x0010, 0x9084, 0x3fff, 0x7012, 0x080c, 0xabf9, 0x680c, 0x7016,
+	0x00de, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9,
+	0x0000, 0x20a1, 0x0256, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801,
+	0x20a1, 0x025a, 0x4003, 0x00d6, 0x080c, 0xa6fe, 0x2069, 0x1973,
+	0x2071, 0x024e, 0x6800, 0xc0dd, 0x7002, 0x080c, 0x5742, 0xd0e4,
+	0x0110, 0x680c, 0x700e, 0x00de, 0x04a8, 0x2001, 0x1837, 0x2004,
+	0xd0a4, 0x0170, 0x0016, 0x2001, 0x196c, 0x200c, 0x60e0, 0x9106,
+	0x0130, 0x2100, 0x60e3, 0x0000, 0x080c, 0x26d5, 0x61e2, 0x001e,
+	0x20e1, 0x0001, 0x2099, 0x196b, 0x20e9, 0x0000, 0x20a1, 0x024e,
+	0x20a9, 0x0008, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1805, 0x20a1,
+	0x0256, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801, 0x20a1, 0x025a,
+	0x4003, 0x080c, 0xa6fe, 0x20a1, 0x024e, 0x20a9, 0x0008, 0x2099,
+	0x1973, 0x4003, 0x60c3, 0x0074, 0x0804, 0x9ea4, 0x080c, 0x9b37,
+	0x7003, 0x2010, 0x7007, 0x0014, 0x700b, 0x0800, 0x700f, 0x2000,
+	0x9006, 0x00f6, 0x2079, 0x1847, 0x7904, 0x00fe, 0xd1ac, 0x1110,
+	0x9085, 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010, 0x9085, 0x0002,
+	0x00d6, 0x0804, 0x9ae7, 0x7026, 0x60c3, 0x0014, 0x0804, 0x9ea4,
+	0x080c, 0x9b37, 0x7003, 0x5000, 0x0804, 0x99c0, 0x080c, 0x9b37,
+	0x7003, 0x2110, 0x7007, 0x0014, 0x60c3, 0x0014, 0x0804, 0x9ea4,
+	0x080c, 0x9b79, 0x0010, 0x080c, 0x9b82, 0x7003, 0x0200, 0x60c3,
+	0x0004, 0x0804, 0x9ea4, 0x080c, 0x9b82, 0x7003, 0x0100, 0x700b,
+	0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x080c,
+	0x9b82, 0x7003, 0x0200, 0x0804, 0x99c0, 0x080c, 0x9b82, 0x7003,
+	0x0100, 0x782c, 0x9005, 0x0110, 0x700a, 0x0010, 0x700b, 0x0003,
+	0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x00d6, 0x080c,
+	0x9b82, 0x7003, 0x0210, 0x7007, 0x0014, 0x700b, 0x0800, 0xb894,
+	0x9086, 0x0014, 0x1198, 0xb99c, 0x9184, 0x0030, 0x0190, 0xb998,
+	0x9184, 0xc000, 0x1140, 0xd1ec, 0x0118, 0x700f, 0x2100, 0x0058,
+	0x700f, 0x0100, 0x0040, 0x700f, 0x0400, 0x0028, 0x700f, 0x0700,
+	0x0010, 0x700f, 0x0800, 0x00f6, 0x2079, 0x1847, 0x7904, 0x00fe,
+	0xd1ac, 0x1110, 0x9085, 0x0020, 0xd1a4, 0x0110, 0x9085, 0x0010,
+	0x2009, 0x1869, 0x210c, 0xd184, 0x1110, 0x9085, 0x0002, 0x0026,
+	0x2009, 0x1867, 0x210c, 0xd1e4, 0x0150, 0xc0c5, 0xbad4, 0xd28c,
+	0x1108, 0xc0cd, 0x9094, 0x0030, 0x9296, 0x0010, 0x0140, 0xd1ec,
+	0x0130, 0x9094, 0x0030, 0x9296, 0x0010, 0x0108, 0xc0bd, 0x002e,
+	0x7026, 0x60c3, 0x0014, 0x00de, 0x0804, 0x9ea4, 0x080c, 0x9b82,
+	0x7003, 0x0210, 0x7007, 0x0014, 0x700f, 0x0100, 0x60c3, 0x0014,
+	0x0804, 0x9ea4, 0x080c, 0x9b82, 0x7003, 0x0200, 0x0804, 0x9946,
+	0x080c, 0x9b82, 0x7003, 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00,
+	0x60c3, 0x0008, 0x0804, 0x9ea4, 0x080c, 0x9b82, 0x7003, 0x0100,
+	0x700b, 0x000b, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x0026, 0x00d6,
+	0x0036, 0x0046, 0x2019, 0x3200, 0x2021, 0x0800, 0x0040, 0x0026,
+	0x00d6, 0x0036, 0x0046, 0x2019, 0x2200, 0x2021, 0x0100, 0x080c,
+	0xa713, 0xb810, 0x9305, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800,
+	0x687c, 0x700a, 0x6880, 0x700e, 0x9485, 0x0029, 0x7012, 0x004e,
+	0x003e, 0x00de, 0x080c, 0x9e98, 0x721a, 0x9f95, 0x0000, 0x7222,
+	0x7027, 0xffff, 0x2071, 0x024c, 0x002e, 0x0005, 0x0026, 0x080c,
+	0xa713, 0x7003, 0x02ff, 0x7007, 0xfffc, 0x00d6, 0x2069, 0x1800,
+	0x687c, 0x700a, 0x6880, 0x700e, 0x00de, 0x7013, 0x2029, 0x0c10,
+	0x7003, 0x0100, 0x7007, 0x0000, 0x700b, 0xfc02, 0x700f, 0x0000,
+	0x0005, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x3300, 0x2021,
+	0x0800, 0x0040, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x2300,
+	0x2021, 0x0100, 0x080c, 0xa713, 0xb810, 0x9305, 0x7002, 0xb814,
+	0x7006, 0x2069, 0x1800, 0xb810, 0x9005, 0x1140, 0xb814, 0x9005,
+	0x1128, 0x700b, 0x00ff, 0x700f, 0xfffe, 0x0020, 0x687c, 0x700a,
+	0x6880, 0x700e, 0x0000, 0x9485, 0x0098, 0x7012, 0x004e, 0x003e,
+	0x00de, 0x080c, 0x9e98, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226,
+	0x2071, 0x024c, 0x002e, 0x0005, 0x080c, 0x9e98, 0x721a, 0x7a08,
+	0x7222, 0x7814, 0x7026, 0x2071, 0x024c, 0x002e, 0x0005, 0x00b6,
+	0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240,
+	0x6004, 0x908a, 0x0085, 0x0a0c, 0x0d7d, 0x908a, 0x0092, 0x1a0c,
+	0x0d7d, 0x6110, 0x2158, 0xb984, 0x2c78, 0x2061, 0x0100, 0x619a,
+	0x9082, 0x0085, 0x0033, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be,
+	0x0005, 0x9bf0, 0x9bff, 0x9c0a, 0x9bee, 0x9bee, 0x9bee, 0x9bf0,
+	0x9bee, 0x9bee, 0x9bee, 0x9bee, 0x9bee, 0x9bee, 0x080c, 0x0d7d,
+	0x0411, 0x60c3, 0x0000, 0x0026, 0x080c, 0x29e5, 0x0228, 0x2011,
+	0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e, 0x0804, 0x9ea4, 0x0431,
+	0x7808, 0x700a, 0x7814, 0x700e, 0x7017, 0xffff, 0x60c3, 0x000c,
+	0x0804, 0x9ea4, 0x04a1, 0x7003, 0x0003, 0x7007, 0x0300, 0x60c3,
+	0x0004, 0x0804, 0x9ea4, 0x0026, 0x080c, 0xa713, 0xb810, 0x9085,
+	0x8100, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x687c, 0x700a,
+	0x6880, 0x700e, 0x7013, 0x0009, 0x0804, 0x9b52, 0x0026, 0x080c,
+	0xa713, 0xb810, 0x9085, 0x8400, 0x7002, 0xb814, 0x7006, 0x2069,
+	0x1800, 0x687c, 0x700a, 0x6880, 0x700e, 0x2001, 0x0099, 0x7a20,
+	0x9296, 0x0005, 0x0108, 0xc0bc, 0x7012, 0x0804, 0x9bb4, 0x0026,
+	0x080c, 0xa713, 0xb810, 0x9085, 0x8500, 0x7002, 0xb814, 0x7006,
+	0x2069, 0x1800, 0x687c, 0x700a, 0x6880, 0x700e, 0x2001, 0x0099,
+	0x7a20, 0x9296, 0x0005, 0x0108, 0xc0bc, 0x7012, 0x0804, 0x9bb4,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2c78, 0x2069, 0x0200,
+	0x2071, 0x0240, 0x7804, 0x908a, 0x0040, 0x0a0c, 0x0d7d, 0x908a,
+	0x0057, 0x1a0c, 0x0d7d, 0x7910, 0x2158, 0xb984, 0x2061, 0x0100,
+	0x619a, 0x9082, 0x0040, 0x0033, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x00be, 0x0005, 0x9c8d, 0x9c8d, 0x9c8d, 0x9cb3, 0x9c8d, 0x9c8d,
+	0x9c8d, 0x9c8d, 0x9c8d, 0x9c8d, 0x9c8d, 0xa25f, 0xa267, 0xa26f,
+	0xa277, 0x9c8d, 0x9c8d, 0x9c8d, 0xa257, 0x080c, 0x0d7d, 0x6813,
+	0x0008, 0xba8c, 0x8210, 0xb8d4, 0xd084, 0x0128, 0x7a52, 0x7b14,
+	0x7b4e, 0x722e, 0x732a, 0x9294, 0x00ff, 0xba8e, 0x8217, 0x721a,
+	0xba10, 0x9295, 0x0600, 0x7202, 0xba14, 0x7206, 0x2069, 0x1800,
+	0x6a7c, 0x720a, 0x6a80, 0x720e, 0x7013, 0x0829, 0x2f10, 0x7222,
+	0x7027, 0xffff, 0x0005, 0x0016, 0x7814, 0x9084, 0x0700, 0x8007,
+	0x0013, 0x001e, 0x0005, 0x9cc3, 0x9cc3, 0x9cc5, 0x9cc3, 0x9cc3,
+	0x9cc3, 0x9cdf, 0x9cc3, 0x080c, 0x0d7d, 0x7914, 0x918c, 0x08ff,
+	0x918d, 0xf600, 0x7916, 0x2009, 0x0003, 0x00b9, 0x2069, 0x1847,
+	0x6804, 0xd0bc, 0x0130, 0x682c, 0x9084, 0x00ff, 0x8007, 0x7032,
+	0x0010, 0x7033, 0x3f00, 0x60c3, 0x0001, 0x0804, 0x9ea4, 0x2009,
+	0x0003, 0x0019, 0x7033, 0x7f00, 0x0cb0, 0x0016, 0x080c, 0xa713,
+	0x001e, 0xb810, 0x9085, 0x0100, 0x7002, 0xb814, 0x7006, 0x2069,
+	0x1800, 0x6a7c, 0x720a, 0x6a80, 0x720e, 0x7013, 0x0888, 0x918d,
+	0x0008, 0x7116, 0x080c, 0x9e98, 0x721a, 0x7a08, 0x7222, 0x2f10,
+	0x7226, 0x0005, 0x00b6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0056,
+	0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x1800, 0x7160, 0x7810,
+	0x2058, 0x76dc, 0x96b4, 0x0028, 0x0110, 0x737c, 0x7480, 0x2500,
+	0x76dc, 0x96b4, 0x0028, 0x0140, 0x2001, 0x04ff, 0x6062, 0x6067,
+	0xffff, 0x636a, 0x646e, 0x0050, 0x2001, 0x00ff, 0x9085, 0x0400,
+	0x6062, 0x6067, 0xffff, 0x606b, 0x0000, 0x616e, 0xb8b8, 0x6073,
+	0x0530, 0x6077, 0x0008, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e,
+	0x8007, 0x9085, 0x0020, 0x607a, 0x607f, 0x0000, 0x2b00, 0x6082,
+	0x6087, 0xffff, 0x7814, 0x0096, 0x2048, 0xa848, 0x608a, 0xa844,
+	0x608e, 0xa838, 0x60c6, 0xa834, 0x60ca, 0x009e, 0xb86c, 0x60ce,
+	0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x2001, 0x1837,
+	0x2004, 0x9084, 0x0028, 0x0128, 0x609f, 0x0000, 0x2001, 0x0092,
+	0x0058, 0x6028, 0xc0bd, 0x602a, 0x609f, 0x00ff, 0x2011, 0xffff,
+	0x080c, 0x2ab4, 0x2001, 0x00b2, 0x2010, 0x900e, 0x080c, 0x2ac3,
+	0x2009, 0x07d0, 0x080c, 0x8785, 0x003e, 0x004e, 0x005e, 0x006e,
+	0x00ce, 0x00de, 0x00ee, 0x00be, 0x0005, 0x00b6, 0x00e6, 0x00d6,
+	0x00c6, 0x0066, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071,
+	0x1800, 0x7160, 0x7810, 0x2058, 0xb8a0, 0x2028, 0x76dc, 0xd6ac,
+	0x1168, 0x9582, 0x007e, 0x1250, 0x2500, 0x9094, 0xff80, 0x1130,
+	0x9080, 0x33b9, 0x2015, 0x9294, 0x00ff, 0x0020, 0xb910, 0xba14,
+	0x737c, 0x7480, 0x70dc, 0xd0ac, 0x1130, 0x9582, 0x007e, 0x1218,
+	0x9584, 0xff80, 0x0138, 0x9185, 0x0400, 0x6062, 0x6266, 0x636a,
+	0x646e, 0x0030, 0x6063, 0x0400, 0x6266, 0x606b, 0x0000, 0x616e,
+	0xb8b8, 0x6072, 0x6077, 0x0000, 0xb864, 0xd0a4, 0x0110, 0x6077,
+	0x0008, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x9085,
+	0x0020, 0x607a, 0x607f, 0x0000, 0x2b00, 0x6082, 0x6087, 0xffff,
+	0x7814, 0x0096, 0x2048, 0xa848, 0x608a, 0xa844, 0x608e, 0xa838,
+	0x60c6, 0xa834, 0x60ca, 0x009e, 0xb86c, 0x60ce, 0x60ab, 0x0036,
+	0x60af, 0x95d5, 0x60d7, 0x0000, 0xba84, 0x629e, 0x00f6, 0x2079,
+	0x0140, 0x7803, 0x0000, 0x00fe, 0x900e, 0x2011, 0x0092, 0x080c,
+	0x2ac3, 0x2009, 0x07d0, 0x080c, 0x8785, 0x003e, 0x004e, 0x005e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x00be, 0x0005, 0x00b6, 0x0096,
+	0x00e6, 0x00d6, 0x00c6, 0x0056, 0x0046, 0x0036, 0x2061, 0x0100,
+	0x2071, 0x1800, 0x7810, 0x2058, 0xb8a0, 0x2028, 0xb910, 0xba14,
+	0x737c, 0x7480, 0x7820, 0x0002, 0x9e23, 0x9e23, 0x9e23, 0x9e23,
+	0x9e23, 0x9e23, 0x9e23, 0x9e23, 0x9e23, 0x9e23, 0x9e25, 0x9e23,
+	0x9e23, 0x9e23, 0x9e23, 0x080c, 0x0d7d, 0xb884, 0x609e, 0x7814,
+	0x2048, 0xa87c, 0xd0fc, 0x0558, 0xaf90, 0x9784, 0xff00, 0x9105,
+	0x6062, 0x873f, 0x9784, 0xff00, 0x0006, 0x7814, 0x2048, 0xa878,
+	0xc0fc, 0x9005, 0x000e, 0x1160, 0xaf94, 0x87ff, 0x0198, 0x2039,
+	0x0098, 0x9705, 0x6072, 0x7808, 0x6082, 0x2f00, 0x6086, 0x0038,
+	0x9185, 0x2200, 0x6062, 0x6073, 0x0129, 0x6077, 0x0000, 0xb884,
+	0x609e, 0x0050, 0x2039, 0x0029, 0x9705, 0x6072, 0x0cc0, 0x9185,
+	0x0200, 0x6062, 0x6073, 0x2029, 0xa87c, 0xd0fc, 0x0118, 0xaf94,
+	0x87ff, 0x1120, 0x2f00, 0x6082, 0x7808, 0x6086, 0x6266, 0x636a,
+	0x646e, 0x6077, 0x0000, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0xa848, 0x608a, 0xa844, 0x608e,
+	0xa838, 0x60c6, 0xa834, 0x60ca, 0xb86c, 0x60ce, 0x60af, 0x95d5,
+	0x60d7, 0x0000, 0x080c, 0xa6f3, 0x2009, 0x07d0, 0x60c4, 0x9084,
+	0xfff0, 0x9005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x8785, 0x003e,
+	0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x009e, 0x00be, 0x0005,
+	0x7a40, 0x9294, 0x00ff, 0x8217, 0x0005, 0x00d6, 0x2069, 0x19e6,
+	0x686b, 0x0001, 0x00de, 0x0005, 0x60a3, 0x0056, 0x60a7, 0x9575,
+	0x00f1, 0x080c, 0x8777, 0x0005, 0x0016, 0x2001, 0x180c, 0x200c,
+	0x9184, 0x0600, 0x9086, 0x0600, 0x0128, 0x0089, 0x080c, 0x8777,
+	0x001e, 0x0005, 0xc1e5, 0x2001, 0x180c, 0x2102, 0x2001, 0x19e7,
+	0x2003, 0x0000, 0x2001, 0x19f2, 0x2003, 0x0000, 0x0c88, 0x0006,
+	0x0016, 0x0026, 0x2009, 0x1804, 0x2011, 0x0009, 0x080c, 0x2ac3,
+	0x002e, 0x001e, 0x000e, 0x0005, 0x0016, 0x00c6, 0x0006, 0x080c,
+	0xa91e, 0x0106, 0x2061, 0x0100, 0x61a4, 0x60a7, 0x95f5, 0x0016,
+	0x0026, 0x2009, 0x1804, 0x2011, 0x0008, 0x080c, 0x2ac3, 0x002e,
+	0x001e, 0x010e, 0x090c, 0xa93a, 0x000e, 0xa001, 0xa001, 0xa001,
+	0x61a6, 0x00ce, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x753d, 0x1510, 0x2001,
+	0x1a0b, 0x2004, 0x9005, 0x1904, 0x9f53, 0x080c, 0x75e2, 0x11a8,
+	0x2069, 0x0380, 0x6843, 0x0101, 0x6844, 0xd084, 0x1de8, 0x2061,
+	0x0100, 0x6020, 0xd0b4, 0x1120, 0x6024, 0xd084, 0x090c, 0x0d7d,
+	0x6843, 0x0100, 0x080c, 0x8777, 0x04b0, 0x00c6, 0x2061, 0x19e6,
+	0x00f0, 0x6904, 0x9194, 0x4000, 0x0598, 0x080c, 0x9ed4, 0x080c,
+	0x2a8a, 0x00c6, 0x2061, 0x19e6, 0x6134, 0x9192, 0x0008, 0x1278,
+	0x8108, 0x6136, 0x080c, 0xa91e, 0x6130, 0x080c, 0xa93a, 0x00ce,
+	0x81ff, 0x01c8, 0x080c, 0x8777, 0x080c, 0x9ec7, 0x00a0, 0x080c,
+	0xa91e, 0x6130, 0x91e5, 0x0000, 0x0150, 0x080c, 0xe897, 0x080c,
+	0x8780, 0x6003, 0x0001, 0x2009, 0x0014, 0x080c, 0xad4d, 0x080c,
+	0xa93a, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce, 0x0005,
+	0x2001, 0x1a0b, 0x2004, 0x9005, 0x1db0, 0x00c6, 0x2061, 0x19e6,
+	0x6134, 0x9192, 0x0003, 0x1ad8, 0x8108, 0x6136, 0x00ce, 0x080c,
+	0x8777, 0x080c, 0x5f4d, 0x2009, 0x1846, 0x2114, 0x8210, 0x220a,
+	0x0c10, 0x0096, 0x00c6, 0x00d6, 0x00e6, 0x0016, 0x0026, 0x080c,
+	0x878d, 0x080c, 0xa91e, 0x2001, 0x0387, 0x2003, 0x0202, 0x2071,
+	0x19e6, 0x714c, 0x81ff, 0x0904, 0x9ffb, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x080c, 0x753d, 0x1510, 0x0036, 0x2019, 0x0002, 0x080c,
+	0xa1b8, 0x003e, 0x714c, 0x2160, 0x080c, 0xe897, 0x2009, 0x004a,
+	0x6220, 0x9296, 0x0009, 0x1130, 0x6114, 0x2148, 0xa87b, 0x0006,
+	0x2009, 0x004a, 0x6003, 0x0003, 0x080c, 0xad4d, 0x2001, 0x0386,
+	0x2003, 0x5040, 0x080c, 0x75e2, 0x0804, 0x9ffb, 0x6904, 0xd1f4,
+	0x0904, 0xa008, 0x080c, 0x2a8a, 0x00c6, 0x704c, 0x9065, 0x090c,
+	0x0d7d, 0x6020, 0x00ce, 0x9086, 0x0006, 0x1518, 0x61c8, 0x60c4,
+	0x9105, 0x11f8, 0x2009, 0x180c, 0x2104, 0xd0d4, 0x01d0, 0x6214,
+	0x9294, 0x1800, 0x1128, 0x6224, 0x9294, 0x0002, 0x1560, 0x0010,
+	0xc0d4, 0x200a, 0x6014, 0x9084, 0xe7fd, 0x9085, 0x0010, 0x6016,
+	0x704c, 0x2060, 0x080c, 0x96d5, 0x2009, 0x0049, 0x080c, 0xad4d,
+	0x00d0, 0x0036, 0x2019, 0x0001, 0x080c, 0xa1b8, 0x003e, 0x714c,
+	0x2160, 0x080c, 0xe897, 0x2009, 0x004a, 0x6220, 0x9296, 0x0009,
+	0x1130, 0x6114, 0x2148, 0xa87b, 0x0006, 0x2009, 0x004a, 0x6003,
+	0x0003, 0x080c, 0xad4d, 0x2001, 0x0387, 0x2003, 0x0200, 0x080c,
+	0xa93a, 0x002e, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x009e, 0x0005,
+	0xd1ec, 0x1904, 0x9fb2, 0x0804, 0x9fb4, 0x0026, 0x00e6, 0x2071,
+	0x19e6, 0x706c, 0xd084, 0x01e8, 0xc084, 0x706e, 0x714c, 0x81ff,
+	0x01c0, 0x2071, 0x0100, 0x9188, 0x0008, 0x2114, 0x928e, 0x0006,
+	0x1138, 0x2009, 0x1984, 0x2011, 0x0012, 0x080c, 0x2ac3, 0x0048,
+	0x928e, 0x0009, 0x0db0, 0x2009, 0x1984, 0x2011, 0x0016, 0x080c,
+	0x2ac3, 0x00ee, 0x002e, 0x0005, 0x9036, 0x2001, 0x19f0, 0x2004,
+	0x9005, 0x0128, 0x9c06, 0x0128, 0x2c30, 0x600c, 0x0cc8, 0x9085,
+	0x0001, 0x0005, 0x00f6, 0x2079, 0x19e6, 0x610c, 0x9006, 0x600e,
+	0x6044, 0xc0fc, 0x6046, 0x86ff, 0x1140, 0x7824, 0x9c06, 0x1118,
+	0x7826, 0x782a, 0x0050, 0x792a, 0x0040, 0x00c6, 0x2660, 0x610e,
+	0x00ce, 0x7824, 0x9c06, 0x1108, 0x7e26, 0x080c, 0xa282, 0x080c,
+	0xcb6b, 0x00fe, 0x0005, 0x080c, 0x9b37, 0x7003, 0x1200, 0x7838,
+	0x7012, 0x783c, 0x7016, 0x00c6, 0x7820, 0x9086, 0x0004, 0x1148,
+	0x7810, 0x9005, 0x0130, 0x00b6, 0x2058, 0xb810, 0xb914, 0x00be,
+	0x0020, 0x2061, 0x1800, 0x607c, 0x6180, 0x9084, 0x00ff, 0x700a,
+	0x710e, 0x00ce, 0x60c3, 0x002c, 0x0804, 0x9ea4, 0x080c, 0x9b37,
+	0x7003, 0x0f00, 0x7808, 0xd09c, 0x0128, 0xb810, 0x9084, 0x00ff,
+	0x700a, 0xb814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x0156,
+	0x080c, 0x9b82, 0x7003, 0x0200, 0x080c, 0x8845, 0x20a9, 0x0006,
+	0x2011, 0xffec, 0x2019, 0xffed, 0x9ef0, 0x0002, 0x2305, 0x2072,
+	0x8e70, 0x2205, 0x2072, 0x8e70, 0x9398, 0x0002, 0x9290, 0x0002,
+	0x1f04, 0xa0a6, 0x60c3, 0x001c, 0x015e, 0x0804, 0x9ea4, 0x0016,
+	0x0026, 0x080c, 0x9b5e, 0x080c, 0x9b70, 0x9e80, 0x0004, 0x20e9,
+	0x0000, 0x20a0, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x009e, 0x7808, 0x9088,
+	0x0002, 0x21a8, 0x9192, 0x0010, 0x1250, 0x4003, 0x9080, 0x0004,
+	0x8003, 0x60c2, 0x080c, 0x9ea4, 0x002e, 0x001e, 0x0005, 0x20a9,
+	0x0010, 0x4003, 0x080c, 0xa6fe, 0x20a1, 0x0240, 0x22a8, 0x4003,
+	0x0c68, 0x080c, 0x9b37, 0x7003, 0x6200, 0x7808, 0x700e, 0x60c3,
+	0x0008, 0x0804, 0x9ea4, 0x0016, 0x0026, 0x080c, 0x9b37, 0x20e9,
+	0x0000, 0x20a1, 0x024c, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048,
+	0xa860, 0x20e0, 0xa85c, 0x9080, 0x0023, 0x2098, 0x009e, 0x7808,
+	0x9088, 0x0002, 0x21a8, 0x4003, 0x8003, 0x60c2, 0x080c, 0x9ea4,
+	0x002e, 0x001e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x19e6, 0x7010, 0x2060, 0x8cff, 0x0188, 0x080c,
+	0xcb91, 0x1110, 0x080c, 0xb693, 0x600c, 0x0006, 0x080c, 0xce0d,
+	0x600f, 0x0000, 0x080c, 0xacb0, 0x080c, 0xa282, 0x00ce, 0x0c68,
+	0x2c00, 0x7012, 0x700e, 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005,
+	0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026,
+	0x0016, 0x0006, 0x2091, 0x8000, 0x2001, 0x180c, 0x200c, 0x918c,
+	0xe7ff, 0x2102, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x19e6,
+	0x7030, 0x2060, 0x8cff, 0x0548, 0x080c, 0x9ed4, 0x6ac0, 0x68c3,
+	0x0000, 0x080c, 0x8780, 0x00c6, 0x2061, 0x0100, 0x080c, 0xa84f,
+	0x00ce, 0x20a9, 0x01f4, 0x04b1, 0x080c, 0x967a, 0x6044, 0xd0ac,
+	0x1128, 0x2001, 0x1987, 0x2004, 0x604a, 0x0020, 0x2009, 0x0013,
+	0x080c, 0xad4d, 0x000e, 0x001e, 0x002e, 0x006e, 0x00ce, 0x00de,
+	0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x2001, 0x1800, 0x2004,
+	0x9096, 0x0001, 0x0d78, 0x9096, 0x0004, 0x0d60, 0x080c, 0x8780,
+	0x6814, 0x9084, 0x0001, 0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008,
+	0x68c3, 0x0000, 0x2011, 0x5ef7, 0x080c, 0x86c8, 0x20a9, 0x01f4,
+	0x0009, 0x08c0, 0x6824, 0xd094, 0x0140, 0x6827, 0x0004, 0x7804,
+	0x9084, 0x4000, 0x190c, 0x2a8a, 0x0090, 0xd084, 0x0118, 0x6827,
+	0x0001, 0x0010, 0x1f04, 0xa19a, 0x7804, 0x9084, 0x1000, 0x0138,
+	0x2001, 0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x0005,
+	0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026,
+	0x0016, 0x0006, 0x2091, 0x8000, 0x2001, 0x180c, 0x200c, 0x918c,
+	0xdbff, 0x2102, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x0380,
+	0x701c, 0x0006, 0x701f, 0x0202, 0x2071, 0x19e6, 0x704c, 0x2060,
+	0x8cff, 0x0904, 0xa231, 0x9386, 0x0002, 0x1128, 0x6814, 0x9084,
+	0x0002, 0x0904, 0xa231, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009,
+	0x00fa, 0x8109, 0x1df0, 0x69c6, 0x68cb, 0x0008, 0x080c, 0x878d,
+	0x080c, 0x1e2e, 0x2001, 0x0032, 0x6920, 0xd1bc, 0x0130, 0x8001,
+	0x1dd8, 0x692c, 0x918d, 0x0008, 0x692e, 0x20a9, 0x03e8, 0x6824,
+	0xd094, 0x0140, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c,
+	0x2a8a, 0x0090, 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, 0x1f04,
+	0xa1ff, 0x7804, 0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x6827, 0x4000, 0x6824, 0x83ff,
+	0x1180, 0x2009, 0x0049, 0x6020, 0x9086, 0x0009, 0x0150, 0x080c,
+	0x96d5, 0x6044, 0xd0ac, 0x1118, 0x6003, 0x0002, 0x0010, 0x080c,
+	0xad4d, 0x000e, 0x2071, 0x0380, 0xd08c, 0x1110, 0x701f, 0x0200,
+	0x000e, 0x001e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe,
+	0x015e, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069,
+	0x19e6, 0x6a06, 0x012e, 0x00de, 0x0005, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x2069, 0x19e6, 0x6a3e, 0x012e, 0x00de, 0x0005, 0x080c,
+	0x9c8f, 0x785c, 0x7032, 0x7042, 0x7047, 0x1000, 0x00f8, 0x080c,
+	0x9c8f, 0x785c, 0x7032, 0x7042, 0x7047, 0x4000, 0x00b8, 0x080c,
+	0x9c8f, 0x785c, 0x7032, 0x7042, 0x7047, 0x2000, 0x0078, 0x080c,
+	0x9c8f, 0x785c, 0x7032, 0x7042, 0x7047, 0x0400, 0x0038, 0x080c,
+	0x9c8f, 0x785c, 0x7032, 0x7042, 0x7047, 0x0200, 0x60c3, 0x0020,
+	0x0804, 0x9ea4, 0x00e6, 0x2071, 0x19e6, 0x702c, 0x9005, 0x0110,
+	0x8001, 0x702e, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6,
+	0x0076, 0x0066, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19e6,
+	0x7620, 0x2660, 0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0xa327,
+	0x8cff, 0x0904, 0xa327, 0x6020, 0x9086, 0x0006, 0x1904, 0xa322,
+	0x88ff, 0x0138, 0x2800, 0x9c06, 0x1904, 0xa322, 0x2039, 0x0000,
+	0x0050, 0x6010, 0x9b06, 0x1904, 0xa322, 0x85ff, 0x0120, 0x605c,
+	0x9106, 0x1904, 0xa322, 0x7030, 0x9c06, 0x15b0, 0x2069, 0x0100,
+	0x68c0, 0x9005, 0x1160, 0x6824, 0xd084, 0x0148, 0x6827, 0x0001,
+	0x080c, 0x8780, 0x080c, 0xa3ac, 0x7033, 0x0000, 0x0428, 0x080c,
+	0x8780, 0x6820, 0xd0b4, 0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008,
+	0x68c3, 0x0000, 0x080c, 0xa3ac, 0x7033, 0x0000, 0x0036, 0x2069,
+	0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0110, 0x6827, 0x0001, 0x003e, 0x7020, 0x9c36, 0x1110, 0x660c,
+	0x7622, 0x701c, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00,
+	0x701e, 0x0010, 0x701f, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06,
+	0x0110, 0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1168, 0x600f, 0x0000,
+	0x6014, 0x0096, 0x2048, 0x080c, 0xc978, 0x0110, 0x080c, 0xe3e8,
+	0x009e, 0x080c, 0xaceb, 0x080c, 0xa282, 0x88ff, 0x1190, 0x00ce,
+	0x0804, 0xa29d, 0x2c78, 0x600c, 0x2060, 0x0804, 0xa29d, 0x9006,
+	0x012e, 0x000e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe,
+	0x0005, 0x601b, 0x0000, 0x00ce, 0x98c5, 0x0001, 0x0c88, 0x00f6,
+	0x00e6, 0x00d6, 0x0096, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x19e6, 0x7648, 0x2660, 0x2678, 0x8cff,
+	0x0904, 0xa39b, 0x6020, 0x9086, 0x0006, 0x1904, 0xa396, 0x87ff,
+	0x0128, 0x2700, 0x9c06, 0x1904, 0xa396, 0x0040, 0x6010, 0x9b06,
+	0x15e8, 0x85ff, 0x0118, 0x605c, 0x9106, 0x15c0, 0x704c, 0x9c06,
+	0x1168, 0x0036, 0x2019, 0x0001, 0x080c, 0xa1b8, 0x703f, 0x0000,
+	0x9006, 0x704e, 0x706a, 0x7052, 0x706e, 0x003e, 0x7048, 0x9c36,
+	0x1110, 0x660c, 0x764a, 0x7044, 0x9c36, 0x1140, 0x2c00, 0x9f36,
+	0x0118, 0x2f00, 0x7046, 0x0010, 0x7047, 0x0000, 0x660c, 0x0066,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x6014, 0x2048, 0x080c, 0xc978, 0x0110, 0x080c, 0xe3e8, 0x080c,
+	0xaceb, 0x87ff, 0x1198, 0x00ce, 0x0804, 0xa347, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0xa347, 0x9006, 0x012e, 0x000e, 0x002e, 0x006e,
+	0x00ce, 0x009e, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000,
+	0x00ce, 0x97bd, 0x0001, 0x0c80, 0x00e6, 0x2071, 0x19e6, 0x9006,
+	0x7032, 0x700a, 0x7004, 0x9086, 0x0003, 0x0158, 0x2001, 0x1800,
+	0x2004, 0x9086, 0x0002, 0x1118, 0x7007, 0x0005, 0x0010, 0x7007,
+	0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026,
+	0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19e6, 0x2c10, 0x7648,
+	0x2660, 0x2678, 0x8cff, 0x0540, 0x2200, 0x9c06, 0x1508, 0x7048,
+	0x9c36, 0x1110, 0x660c, 0x764a, 0x7044, 0x9c36, 0x1140, 0x2c00,
+	0x9f36, 0x0118, 0x2f00, 0x7046, 0x0010, 0x7047, 0x0000, 0x660c,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x6004, 0x9086, 0x0040, 0x090c, 0x967a, 0x9085, 0x0001, 0x0020,
+	0x2c78, 0x600c, 0x2060, 0x08b0, 0x012e, 0x000e, 0x002e, 0x006e,
+	0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0096, 0x00f6, 0x00e6, 0x00d6,
+	0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x19e6, 0x7610, 0x2660, 0x2678, 0x8cff, 0x0904, 0xa499, 0x6010,
+	0x00b6, 0x2058, 0xb8a0, 0x00be, 0x9206, 0x1904, 0xa494, 0x7030,
+	0x9c06, 0x1520, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904, 0xa46b,
+	0x080c, 0x9ed4, 0x68c3, 0x0000, 0x080c, 0xa3ac, 0x7033, 0x0000,
+	0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001,
+	0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x2069, 0x0100,
+	0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x7010, 0x9c36,
+	0x1110, 0x660c, 0x7612, 0x700c, 0x9c36, 0x1140, 0x2c00, 0x9f36,
+	0x0118, 0x2f00, 0x700e, 0x0010, 0x700f, 0x0000, 0x660c, 0x0066,
+	0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000,
+	0x080c, 0xcb80, 0x1180, 0x080c, 0x326f, 0x080c, 0xcb91, 0x1518,
+	0x080c, 0xb693, 0x0400, 0x080c, 0xa3ac, 0x6824, 0xd084, 0x09b0,
+	0x6827, 0x0001, 0x0898, 0x080c, 0xcb91, 0x1118, 0x080c, 0xb693,
+	0x0090, 0x6014, 0x2048, 0x080c, 0xc978, 0x0168, 0x6020, 0x9086,
+	0x0003, 0x1508, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c,
+	0x6de2, 0x080c, 0xcb6b, 0x080c, 0xce0d, 0x080c, 0xaceb, 0x080c,
+	0xa282, 0x00ce, 0x0804, 0xa414, 0x2c78, 0x600c, 0x2060, 0x0804,
+	0xa414, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x009e, 0x0005, 0x6020, 0x9086, 0x0006, 0x1d20, 0x080c,
+	0xe3e8, 0x0c08, 0x00d6, 0x080c, 0x9b82, 0x7003, 0x0200, 0x7007,
+	0x0014, 0x60c3, 0x0014, 0x20e1, 0x0001, 0x2099, 0x1988, 0x20e9,
+	0x0000, 0x20a1, 0x0250, 0x20a9, 0x0004, 0x4003, 0x7023, 0x0004,
+	0x7027, 0x7878, 0x080c, 0x9ea4, 0x00de, 0x0005, 0x080c, 0x9b82,
+	0x700b, 0x0800, 0x7814, 0x9084, 0xff00, 0x700e, 0x7814, 0x9084,
+	0x00ff, 0x7022, 0x782c, 0x7026, 0x7860, 0x9084, 0x00ff, 0x9085,
+	0x0200, 0x7002, 0x7860, 0x9084, 0xff00, 0x8007, 0x7006, 0x60c2,
+	0x0804, 0x9ea4, 0x00b6, 0x00d6, 0x0016, 0x00d6, 0x2f68, 0x2009,
+	0x0035, 0x080c, 0xd013, 0x00de, 0x1904, 0xa547, 0x080c, 0x9b37,
+	0x7003, 0x1300, 0x782c, 0x080c, 0xa656, 0x2068, 0x6820, 0x9086,
+	0x0003, 0x0560, 0x7810, 0x2058, 0xbaa0, 0x080c, 0xabe2, 0x11d8,
+	0x9286, 0x007e, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffe, 0x0498,
+	0x9286, 0x007f, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffd, 0x0458,
+	0x9284, 0xff80, 0x0180, 0x9286, 0x0080, 0x1128, 0x700b, 0x00ff,
+	0x700f, 0xfffc, 0x0400, 0x92d8, 0x1000, 0x2b5c, 0xb810, 0x700a,
+	0xb814, 0x700e, 0x00c0, 0xb884, 0x700e, 0x00a8, 0x080c, 0xabe2,
+	0x1130, 0x7810, 0x2058, 0xb8a0, 0x9082, 0x007e, 0x0250, 0x00d6,
+	0x2069, 0x181f, 0x2d04, 0x700a, 0x8d68, 0x2d04, 0x700e, 0x00de,
+	0x0010, 0x6034, 0x700e, 0x7838, 0x7012, 0x783c, 0x7016, 0x60c3,
+	0x000c, 0x001e, 0x00de, 0x080c, 0x9ea4, 0x00be, 0x0005, 0x781b,
+	0x0001, 0x7803, 0x0006, 0x001e, 0x00de, 0x00be, 0x0005, 0x792c,
+	0x9180, 0x0008, 0x200c, 0x9186, 0x0006, 0x01c0, 0x9186, 0x0003,
+	0x0904, 0xa5c6, 0x9186, 0x0005, 0x0904, 0xa5ae, 0x9186, 0x0004,
+	0x05f0, 0x9186, 0x0008, 0x0904, 0xa5b7, 0x7807, 0x0037, 0x782f,
+	0x0003, 0x7817, 0x1700, 0x080c, 0xa633, 0x0005, 0x080c, 0xa5f4,
+	0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x6800, 0x6a44,
+	0xd2fc, 0x11f8, 0x0002, 0xa58e, 0xa599, 0xa590, 0xa599, 0xa595,
+	0xa58e, 0xa58e, 0xa599, 0xa599, 0xa599, 0xa599, 0xa58e, 0xa58e,
+	0xa58e, 0xa58e, 0xa58e, 0xa599, 0xa58e, 0xa599, 0x080c, 0x0d7d,
+	0x6824, 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0x900e, 0x0010, 0x2009,
+	0x2000, 0x682c, 0x7022, 0x6830, 0x7026, 0x0804, 0xa5ed, 0x080c,
+	0xa5f4, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x6a00,
+	0x9286, 0x0002, 0x1108, 0x900e, 0x0804, 0xa5ed, 0x080c, 0xa5f4,
+	0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x04b0, 0x04e1,
+	0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x9286, 0x0005,
+	0x0118, 0x9286, 0x0002, 0x1108, 0x900e, 0x0438, 0x0469, 0x00d6,
+	0x0026, 0x792c, 0x2168, 0x6814, 0x6924, 0xc185, 0x6926, 0x0096,
+	0x2048, 0xa9ac, 0xa834, 0x9112, 0xa9b0, 0xa838, 0x009e, 0x9103,
+	0x7022, 0x7226, 0x792c, 0x9180, 0x0011, 0x2004, 0xd0fc, 0x1148,
+	0x9180, 0x0000, 0x2004, 0x908e, 0x0002, 0x0130, 0x908e, 0x0004,
+	0x0118, 0x2009, 0x4000, 0x0008, 0x900e, 0x712a, 0x60c3, 0x0018,
+	0x002e, 0x00de, 0x0804, 0x9ea4, 0x00b6, 0x0036, 0x0046, 0x0056,
+	0x0066, 0x080c, 0x9b82, 0x9006, 0x7003, 0x0200, 0x7938, 0x710a,
+	0x793c, 0x710e, 0x7810, 0x2058, 0xb8a0, 0x080c, 0xabe2, 0x1118,
+	0x9092, 0x007e, 0x0268, 0x00d6, 0x2069, 0x181f, 0x2d2c, 0x8d68,
+	0x2d34, 0x90d8, 0x1000, 0x2b5c, 0xbb10, 0xbc14, 0x00de, 0x0028,
+	0x901e, 0xbc84, 0x2029, 0x0000, 0x6634, 0x782c, 0x9080, 0x0008,
+	0x2004, 0x9086, 0x0003, 0x1128, 0x7512, 0x7616, 0x731a, 0x741e,
+	0x0020, 0x7312, 0x7416, 0x751a, 0x761e, 0x006e, 0x005e, 0x004e,
+	0x003e, 0x00be, 0x0005, 0x080c, 0x9b82, 0x7003, 0x0100, 0x782c,
+	0x700a, 0x7814, 0x700e, 0x700e, 0x60c3, 0x0008, 0x0804, 0x9ea4,
+	0x080c, 0x9b2e, 0x7003, 0x1400, 0x7838, 0x700a, 0x0079, 0x783c,
+	0x700e, 0x782c, 0x7012, 0x7830, 0x7016, 0x7834, 0x9084, 0x00ff,
+	0x8007, 0x701a, 0x60c3, 0x0010, 0x0804, 0x9ea4, 0x00e6, 0x2071,
+	0x0240, 0x0006, 0x00f6, 0x2078, 0x7810, 0x00b6, 0x2058, 0xb8d4,
+	0xd084, 0x0120, 0x784c, 0x702a, 0x7850, 0x702e, 0x00be, 0x00fe,
+	0x000e, 0x00ee, 0x0005, 0x080c, 0x9b79, 0x7003, 0x0100, 0x782c,
+	0x700a, 0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x9ea4, 0x00a9,
+	0x7914, 0x712a, 0x60c3, 0x0000, 0x60a7, 0x9575, 0x0026, 0x080c,
+	0x29e5, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e,
+	0x080c, 0x9ec7, 0x080c, 0x8777, 0x0005, 0x0036, 0x0096, 0x00d6,
+	0x00e6, 0x7860, 0x2048, 0xaa7c, 0x9296, 0x00c0, 0x9294, 0xfffd,
+	0xaa7e, 0xaa80, 0x9294, 0x0300, 0xaa82, 0xa96c, 0x9194, 0x00ff,
+	0xab74, 0x9384, 0x00ff, 0x908d, 0xc200, 0xa96e, 0x9384, 0xff00,
+	0x9215, 0xaa76, 0xa870, 0xaa78, 0xa87a, 0xaa72, 0x00d6, 0x2069,
+	0x0200, 0x080c, 0xa713, 0x00de, 0x20e9, 0x0000, 0x20a1, 0x0240,
+	0x20a9, 0x000a, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098,
+	0x4003, 0x60a3, 0x0035, 0xaa68, 0x9294, 0x7000, 0x9286, 0x3000,
+	0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, 0x009e, 0x003e, 0x0005,
+	0x900e, 0x7814, 0x0096, 0x2048, 0xa87c, 0xd0fc, 0x01c0, 0x9084,
+	0x0003, 0x11a8, 0x2001, 0x180c, 0x2004, 0xd0bc, 0x0180, 0x7824,
+	0xd0cc, 0x1168, 0xd0c4, 0x1158, 0xa8a8, 0x9005, 0x1140, 0x2001,
+	0x180c, 0x200c, 0xc1d5, 0x2102, 0x2009, 0x19b1, 0x210c, 0x009e,
+	0x918d, 0x0092, 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036, 0x0026,
+	0x2110, 0x900e, 0x080c, 0x2ac3, 0x002e, 0x0005, 0x2009, 0x0009,
+	0x00a0, 0x2009, 0x000a, 0x0088, 0x2009, 0x000b, 0x0070, 0x2009,
+	0x000c, 0x0058, 0x2009, 0x000d, 0x0040, 0x2009, 0x000e, 0x0028,
+	0x2009, 0x000f, 0x0010, 0x2009, 0x0008, 0x6912, 0x0005, 0x080c,
+	0x9b37, 0x0016, 0x0026, 0x0096, 0x00d6, 0x7814, 0x2048, 0x7013,
+	0x0138, 0x2001, 0x1837, 0x2004, 0x9084, 0x0028, 0x1138, 0x2001,
+	0x197b, 0x2004, 0x9086, 0xaaaa, 0x1904, 0xa7b8, 0x7003, 0x5400,
+	0x00c6, 0x2061, 0x1800, 0x607c, 0x9084, 0x00ff, 0xa998, 0x810f,
+	0x918c, 0xff00, 0x9105, 0x700a, 0x6080, 0x700e, 0xa998, 0x918c,
+	0xff00, 0x7112, 0x20a9, 0x0004, 0x2009, 0x1805, 0x2e10, 0x9290,
+	0x0006, 0x2104, 0x2012, 0x8108, 0x8210, 0x1f04, 0xa749, 0x20a9,
+	0x0004, 0x2009, 0x1801, 0x2104, 0x2012, 0x8108, 0x8210, 0x1f04,
+	0xa753, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0029, 0x2098, 0x2009,
+	0x0006, 0x20a9, 0x0001, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109,
+	0x1dc0, 0x00d6, 0x2069, 0x0200, 0x080c, 0xa6fe, 0x00de, 0x2071,
+	0x0240, 0x2011, 0x0240, 0x2009, 0x0002, 0x20a9, 0x0001, 0x4002,
+	0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0, 0x2009, 0x0008, 0x20a9,
+	0x0001, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0, 0xa85c,
+	0x9080, 0x0031, 0x2098, 0x2009, 0x0008, 0x20a9, 0x0001, 0x4002,
+	0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0, 0x00ce, 0x60c3, 0x004c,
+	0x60a3, 0x0056, 0x60a7, 0x9575, 0x2001, 0x1837, 0x2004, 0x9084,
+	0x0028, 0x1168, 0x080c, 0x753d, 0x0150, 0x6028, 0xc0bd, 0x602a,
+	0x2009, 0x1804, 0x2011, 0x0029, 0x080c, 0x2ac3, 0x0010, 0x080c,
+	0x9ea4, 0x080c, 0x8777, 0x00de, 0x009e, 0x002e, 0x001e, 0x0005,
+	0x00e6, 0x2071, 0x0240, 0x2001, 0x2200, 0x9085, 0x00ff, 0x7002,
+	0x7007, 0xffff, 0x2071, 0x0100, 0x709b, 0x00ff, 0x00ee, 0x0804,
+	0xa72e, 0x080c, 0x9b37, 0x0016, 0x0026, 0x0096, 0x00d6, 0x7814,
+	0x2048, 0x7013, 0x0138, 0x7003, 0x5500, 0x00c6, 0xa89c, 0x9084,
+	0x00ff, 0xa998, 0x810f, 0x918c, 0xff00, 0x9105, 0x700a, 0xa99c,
+	0x918c, 0xff00, 0xa8a0, 0x9084, 0x00ff, 0x9105, 0x700e, 0xa998,
+	0x918c, 0xff00, 0x2061, 0x1800, 0x607c, 0x9084, 0x00ff, 0x910d,
+	0x7112, 0x6180, 0x7116, 0x2009, 0x0008, 0xa860, 0x20e0, 0xa85c,
+	0x9080, 0x0029, 0x2098, 0x2e10, 0x9290, 0x0006, 0x20a9, 0x0001,
+	0x4002, 0x8007, 0x2012, 0x8210, 0x8109, 0x1dc0, 0x20a9, 0x0004,
+	0x2009, 0x1805, 0x2104, 0x2012, 0x8108, 0x8210, 0x1f04, 0xa80a,
+	0x20a9, 0x0002, 0x2009, 0x1801, 0x2104, 0x2012, 0x8108, 0x8210,
+	0x1f04, 0xa814, 0x00d6, 0x0016, 0x2069, 0x0200, 0x080c, 0xa6fe,
+	0x001e, 0x00de, 0x2071, 0x0240, 0x20a9, 0x0002, 0x2009, 0x1803,
+	0x2011, 0x0240, 0x2104, 0x2012, 0x8108, 0x8210, 0x1f04, 0xa82a,
+	0x2009, 0x0008, 0x4002, 0x8007, 0x2012, 0x8210, 0x8109, 0x1dd0,
+	0x9006, 0x20a9, 0x0008, 0x2012, 0x8210, 0x1f04, 0xa83b, 0x00ce,
+	0x60c3, 0x004c, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x9ea4,
+	0x080c, 0x8777, 0x00de, 0x009e, 0x002e, 0x001e, 0x0005, 0x00d6,
+	0x9290, 0x0018, 0x8214, 0x20e9, 0x0000, 0x2069, 0x0200, 0x6813,
+	0x0000, 0x22a8, 0x9284, 0x00e0, 0x0128, 0x20a9, 0x0020, 0x9292,
+	0x0020, 0x0008, 0x9016, 0x20a1, 0x0240, 0x9006, 0x4004, 0x82ff,
+	0x0120, 0x6810, 0x8000, 0x6812, 0x0c60, 0x00de, 0x0005, 0x00f6,
+	0x00e6, 0x00d6, 0x00c6, 0x00a6, 0x0096, 0x0066, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x19e6, 0x7610, 0x2660, 0x2678, 0x8cff, 0x0904,
+	0xa8fb, 0x7030, 0x9c06, 0x1520, 0x2069, 0x0100, 0x68c0, 0x9005,
+	0x0904, 0xa8cd, 0x080c, 0x9ed4, 0x68c3, 0x0000, 0x080c, 0xa3ac,
+	0x7033, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000,
+	0x0138, 0x2001, 0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c, 0x2a7a,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x7010, 0x9c36, 0x1110, 0x660c, 0x7612, 0x700c, 0x9c36, 0x1140,
+	0x2c00, 0x9f36, 0x0118, 0x2f00, 0x700e, 0x0010, 0x700f, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0x080c, 0xcb80, 0x1180, 0x080c, 0x326f, 0x080c,
+	0xcb91, 0x1518, 0x080c, 0xb693, 0x0400, 0x080c, 0xa3ac, 0x6824,
+	0xd084, 0x09b0, 0x6827, 0x0001, 0x0898, 0x080c, 0xcb91, 0x1118,
+	0x080c, 0xb693, 0x0090, 0x6014, 0x2048, 0x080c, 0xc978, 0x0168,
+	0x6020, 0x9086, 0x0003, 0x1520, 0xa867, 0x0103, 0xab7a, 0xa877,
+	0x0000, 0x080c, 0x6dee, 0x080c, 0xcb6b, 0x080c, 0xce0d, 0x080c,
+	0xaceb, 0x080c, 0xa282, 0x00ce, 0x0804, 0xa87e, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0xa87e, 0x7013, 0x0000, 0x700f, 0x0000, 0x012e,
+	0x006e, 0x009e, 0x00ae, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005,
+	0x6020, 0x9086, 0x0006, 0x1d08, 0x080c, 0xe3e8, 0x08f0, 0x00f6,
+	0x0036, 0x2079, 0x0380, 0x7b18, 0xd3bc, 0x1de8, 0x7832, 0x7936,
+	0x7a3a, 0x781b, 0x8080, 0x003e, 0x00fe, 0x0005, 0x0016, 0x2001,
+	0x0382, 0x2004, 0x9084, 0x0007, 0x9086, 0x0001, 0x1188, 0x2001,
+	0x0015, 0x0c29, 0x2009, 0x1000, 0x2001, 0x0382, 0x2004, 0x9084,
+	0x0007, 0x9086, 0x0003, 0x0120, 0x8109, 0x1db0, 0x080c, 0x0d7d,
+	0x001e, 0x0005, 0x2001, 0x0382, 0x2004, 0x9084, 0x0007, 0x9086,
+	0x0003, 0x1120, 0x2001, 0x0380, 0x2003, 0x0001, 0x0005, 0x0156,
+	0x0016, 0x0026, 0x00e6, 0x900e, 0x2071, 0x19e6, 0x0469, 0x0106,
+	0x0190, 0x7004, 0x9086, 0x0003, 0x0148, 0x20a9, 0x1000, 0x6044,
+	0xd0fc, 0x01d8, 0x1f04, 0xa957, 0x080c, 0x0d7d, 0x080c, 0xa91e,
+	0x6044, 0xd0fc, 0x0190, 0x7030, 0x9c06, 0x1148, 0x080c, 0x967a,
+	0x6044, 0xd0dc, 0x0150, 0xc0dc, 0x6046, 0x700a, 0x7042, 0x704c,
+	0x9c06, 0x190c, 0x0d7d, 0x080c, 0x96d5, 0x010e, 0x1919, 0x00ee,
+	0x002e, 0x001e, 0x015e, 0x0005, 0x2001, 0x0382, 0x2004, 0x9084,
+	0x0007, 0x9086, 0x0003, 0x0005, 0x0126, 0x2091, 0x2400, 0x7808,
+	0xd0a4, 0x190c, 0x0d76, 0xd09c, 0x0128, 0x7820, 0x908c, 0xf000,
+	0x11b8, 0x0012, 0x012e, 0x0005, 0xa9a4, 0xa9e2, 0xaa0c, 0xaa43,
+	0xaa53, 0xaa64, 0xaa73, 0xaa81, 0xaaae, 0xaab2, 0xa9a4, 0xa9a4,
+	0xa9a4, 0xa9a4, 0xa9a4, 0xa9a4, 0x080c, 0x0d7d, 0x012e, 0x0005,
+	0x2060, 0x6044, 0xd0bc, 0x0140, 0xc0bc, 0x6046, 0x6000, 0x908a,
+	0x0016, 0x1a0c, 0x0d7d, 0x0012, 0x012e, 0x0005, 0xa9c9, 0xa9cb,
+	0xa9c9, 0xa9d1, 0xa9c9, 0xa9c9, 0xa9c9, 0xa9c9, 0xa9c9, 0xa9cb,
+	0xa9c9, 0xa9cb, 0xa9c9, 0xa9cb, 0xa9c9, 0xa9c9, 0xa9c9, 0xa9cb,
+	0xa9c9, 0x080c, 0x0d7d, 0x2009, 0x0013, 0x080c, 0xad4d, 0x012e,
+	0x0005, 0x6014, 0x2048, 0xa87c, 0xd0dc, 0x0130, 0x080c, 0x894e,
+	0x080c, 0xacb0, 0x012e, 0x0005, 0x2009, 0x0049, 0x080c, 0xad4d,
+	0x012e, 0x0005, 0x080c, 0xa91e, 0x2001, 0x1a0b, 0x2003, 0x0000,
+	0x7030, 0x9065, 0x090c, 0x0d7d, 0x7034, 0x9092, 0xc350, 0x1258,
+	0x8000, 0x7036, 0x7004, 0x9086, 0x0003, 0x0110, 0x7007, 0x0000,
+	0x781f, 0x0808, 0x0058, 0x080c, 0xac0e, 0x0140, 0x080c, 0xe897,
+	0x6003, 0x0001, 0x2009, 0x0014, 0x080c, 0xad4d, 0x781f, 0x0100,
+	0x080c, 0xa93a, 0x012e, 0x0005, 0x080c, 0xa91e, 0x714c, 0x81ff,
+	0x1128, 0x2011, 0x1a0e, 0x2013, 0x0000, 0x0438, 0x2061, 0x0100,
+	0x7150, 0x9192, 0x7530, 0x12f0, 0x8108, 0x7152, 0x714c, 0x9188,
+	0x0008, 0x210c, 0x918e, 0x0006, 0x1138, 0x6014, 0x9084, 0x1984,
+	0x9085, 0x0012, 0x6016, 0x0088, 0x714c, 0x9188, 0x0008, 0x210c,
+	0x918e, 0x0009, 0x0d90, 0x6014, 0x9084, 0x1984, 0x9085, 0x0016,
+	0x6016, 0x0018, 0x706c, 0xc085, 0x706e, 0x781f, 0x0200, 0x080c,
+	0xa93a, 0x012e, 0x0005, 0x080c, 0xa91e, 0x714c, 0x2160, 0x6003,
+	0x0003, 0x2009, 0x004a, 0x080c, 0xad4d, 0x781f, 0x0200, 0x080c,
+	0xa93a, 0x012e, 0x0005, 0x7808, 0xd09c, 0x0de8, 0x7820, 0x2060,
+	0x6003, 0x0003, 0x080c, 0xa91e, 0x080c, 0x1db6, 0x781f, 0x0400,
+	0x080c, 0xa93a, 0x012e, 0x0005, 0x7808, 0xd09c, 0x0de8, 0x7820,
+	0x2060, 0x080c, 0xa91e, 0x080c, 0x1dfe, 0x781f, 0x0400, 0x080c,
+	0xa93a, 0x012e, 0x0005, 0x7030, 0x9065, 0x0148, 0x6044, 0xc0bc,
+	0x6046, 0x7104, 0x9186, 0x0003, 0x0110, 0x080c, 0x9739, 0x012e,
+	0x0005, 0x00f6, 0x703c, 0x9086, 0x0002, 0x0528, 0x704c, 0x907d,
+	0x0510, 0x7844, 0xc0bc, 0x7846, 0x7820, 0x9086, 0x0009, 0x0118,
+	0x080c, 0x9dfe, 0x00c0, 0x7828, 0xd0fc, 0x1118, 0x080c, 0x9d7d,
+	0x0090, 0x2001, 0x1837, 0x2004, 0x9084, 0x0028, 0x1130, 0x2001,
+	0x197b, 0x2004, 0x9086, 0xaaaa, 0x1120, 0x2001, 0x0387, 0x2003,
+	0x1000, 0x080c, 0x9d02, 0x00fe, 0x012e, 0x0005, 0x080c, 0x75e2,
+	0x012e, 0x0005, 0x080c, 0x0d7d, 0x0005, 0x00e6, 0x2071, 0x19e6,
+	0x6044, 0xc0bc, 0x6046, 0xd0fc, 0x01b8, 0x704c, 0x9c06, 0x1190,
+	0x2019, 0x0001, 0x080c, 0xa1b8, 0x704f, 0x0000, 0x2001, 0x0109,
+	0x2004, 0xd08c, 0x1138, 0x2001, 0x0108, 0x2004, 0xd0bc, 0x1110,
+	0x703f, 0x0000, 0x080c, 0xa3c3, 0x00ee, 0x0005, 0x0026, 0x7010,
+	0x9c06, 0x1178, 0x080c, 0xa282, 0x6044, 0xc0fc, 0x6046, 0x600c,
+	0x9015, 0x0120, 0x7212, 0x600f, 0x0000, 0x0010, 0x7212, 0x720e,
+	0x9006, 0x002e, 0x0005, 0x0026, 0x7020, 0x9c06, 0x1178, 0x080c,
+	0xa282, 0x6044, 0xc0fc, 0x6046, 0x600c, 0x9015, 0x0120, 0x7222,
+	0x600f, 0x0000, 0x0010, 0x7222, 0x721e, 0x9006, 0x002e, 0x0005,
+	0x00d6, 0x0036, 0x7830, 0x9c06, 0x1558, 0x2069, 0x0100, 0x68c0,
+	0x9005, 0x01f8, 0x080c, 0x8780, 0x080c, 0x9ed4, 0x68c3, 0x0000,
+	0x080c, 0xa3ac, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138,
+	0x2001, 0x0100, 0x080c, 0x2a7a, 0x9006, 0x080c, 0x2a7a, 0x2069,
+	0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x9085, 0x0001,
+	0x0038, 0x7808, 0xc0ad, 0x780a, 0x6003, 0x0009, 0x630a, 0x9006,
+	0x003e, 0x00de, 0x0005, 0x0016, 0x0026, 0x0036, 0x6100, 0x2019,
+	0x0100, 0x2001, 0x0382, 0x2004, 0xd09c, 0x0190, 0x00c6, 0x0126,
+	0x2091, 0x2800, 0x0016, 0x0036, 0x080c, 0xa984, 0x003e, 0x001e,
+	0x012e, 0x00ce, 0x6200, 0x2200, 0x9106, 0x0d58, 0x2200, 0x0010,
+	0x8319, 0x1d38, 0x003e, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0156,
+	0x080c, 0x9b82, 0x7a14, 0x82ff, 0x0138, 0x7003, 0x0100, 0x700b,
+	0x0003, 0x60c3, 0x0008, 0x0490, 0x7003, 0x0200, 0x7007, 0x0000,
+	0x2069, 0x1800, 0x901e, 0x6800, 0x9086, 0x0004, 0x1110, 0xc38d,
+	0x0060, 0x080c, 0x753d, 0x1110, 0xc3ad, 0x0008, 0xc3a5, 0x6adc,
+	0xd29c, 0x1110, 0xd2ac, 0x0108, 0xc39d, 0x730e, 0x080c, 0x8845,
+	0x20a9, 0x0006, 0x2011, 0xffec, 0x2019, 0xffed, 0x2071, 0x0250,
+	0x2305, 0x2072, 0x8e70, 0x2205, 0x2072, 0x8e70, 0x9398, 0x0002,
+	0x9290, 0x0002, 0x1f04, 0xab88, 0x60c3, 0x0020, 0x080c, 0x9ea4,
+	0x015e, 0x00de, 0x0005, 0x0156, 0x080c, 0x9b82, 0x7a14, 0x82ff,
+	0x0168, 0x9286, 0xffff, 0x0118, 0x9282, 0x000e, 0x1238, 0x7003,
+	0x0100, 0x700b, 0x0003, 0x60c3, 0x0008, 0x0488, 0x7003, 0x0200,
+	0x7007, 0x001c, 0x700f, 0x0001, 0x2011, 0x19bc, 0x2204, 0x8007,
+	0x701a, 0x8210, 0x2204, 0x8007, 0x701e, 0x0421, 0x1120, 0xb8a0,
+	0x9082, 0x007f, 0x0248, 0x2001, 0x181f, 0x2004, 0x7022, 0x2001,
+	0x1820, 0x2004, 0x7026, 0x0030, 0x2001, 0x1818, 0x2004, 0x9084,
+	0x00ff, 0x7026, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805,
+	0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003, 0x60c3, 0x001c, 0x015e,
+	0x0804, 0x9ea4, 0x0006, 0x2001, 0x1837, 0x2004, 0xd0ac, 0x000e,
+	0x0005, 0x2011, 0x0003, 0x080c, 0xa243, 0x2011, 0x0002, 0x080c,
+	0xa24d, 0x080c, 0xa138, 0x0036, 0x901e, 0x080c, 0xa1b8, 0x003e,
+	0x0005, 0x080c, 0x33b2, 0x0188, 0x0016, 0x00b6, 0x00c6, 0x7010,
+	0x9085, 0x0020, 0x7012, 0x2009, 0x007e, 0x080c, 0x6693, 0xb85c,
+	0xc0ac, 0xb85e, 0x00ce, 0x00be, 0x001e, 0x0005, 0x00d6, 0x00f6,
+	0x7104, 0x9186, 0x0004, 0x1120, 0x7410, 0x9e90, 0x0004, 0x0068,
+	0x9186, 0x0001, 0x1120, 0x7420, 0x9e90, 0x0008, 0x0030, 0x9186,
+	0x0002, 0x1508, 0x7428, 0x9e90, 0x000a, 0x6110, 0x2468, 0x680c,
+	0x907d, 0x01c8, 0x7810, 0x9106, 0x1128, 0x2f68, 0x780c, 0x907d,
+	0x1dc8, 0x0088, 0x780c, 0x680e, 0x7c0e, 0x2f12, 0x9006, 0x7032,
+	0x7036, 0x7004, 0x9086, 0x0003, 0x0110, 0x7007, 0x0000, 0x9006,
+	0x00fe, 0x00de, 0x0005, 0x9085, 0x0001, 0x0cd0, 0x2071, 0x188d,
+	0x7000, 0x9005, 0x0140, 0x2001, 0x0812, 0x2071, 0x1800, 0x7076,
+	0x707a, 0x706b, 0xffd4, 0x2071, 0x1800, 0x7074, 0x7056, 0x705b,
+	0x1ddc, 0x0005, 0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, 0x8000,
+	0x7554, 0x9582, 0x0010, 0x0608, 0x7058, 0x2060, 0x6000, 0x9086,
+	0x0000, 0x0148, 0x9ce0, 0x001c, 0x7068, 0x9c02, 0x1208, 0x0cb0,
+	0x2061, 0x1ddc, 0x0c98, 0x6003, 0x0008, 0x8529, 0x7556, 0x9ca8,
+	0x001c, 0x7068, 0x9502, 0x1230, 0x755a, 0x9085, 0x0001, 0x012e,
+	0x00ee, 0x0005, 0x705b, 0x1ddc, 0x0cc0, 0x9006, 0x0cc0, 0x00e6,
+	0x2071, 0x1800, 0x7554, 0x9582, 0x0010, 0x0600, 0x7058, 0x2060,
+	0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0, 0x001c, 0x7068, 0x9c02,
+	0x1208, 0x0cb0, 0x2061, 0x1ddc, 0x0c98, 0x6003, 0x0008, 0x8529,
+	0x7556, 0x9ca8, 0x001c, 0x7068, 0x9502, 0x1228, 0x755a, 0x9085,
+	0x0001, 0x00ee, 0x0005, 0x705b, 0x1ddc, 0x0cc8, 0x9006, 0x0cc8,
+	0x9c82, 0x1ddc, 0x0a0c, 0x0d7d, 0x2001, 0x181a, 0x2004, 0x9c02,
+	0x1a0c, 0x0d7d, 0x9006, 0x6006, 0x600a, 0x600e, 0x6016, 0x601a,
+	0x6012, 0x6023, 0x0000, 0x6003, 0x0000, 0x601e, 0x605e, 0x6062,
+	0x6026, 0x602a, 0x602e, 0x6032, 0x6036, 0x603a, 0x603e, 0x604a,
+	0x602a, 0x6046, 0x6042, 0x2061, 0x1800, 0x6054, 0x8000, 0x6056,
+	0x0005, 0x9006, 0x600e, 0x6016, 0x601a, 0x6012, 0x6022, 0x6002,
+	0x601e, 0x605e, 0x6062, 0x604a, 0x6046, 0x2061, 0x1800, 0x6054,
+	0x8000, 0x6056, 0x0005, 0x0006, 0x6000, 0x9086, 0x0000, 0x01d0,
+	0x601c, 0xd084, 0x190c, 0x1ac5, 0x6023, 0x0007, 0x2001, 0x1985,
+	0x2004, 0x0006, 0x9082, 0x0051, 0x000e, 0x0208, 0x8004, 0x601a,
+	0x080c, 0xe6a0, 0x604b, 0x0000, 0x6044, 0xd0fc, 0x1129, 0x9006,
+	0x6046, 0x6016, 0x000e, 0x0005, 0x080c, 0xa91e, 0x0106, 0x2001,
+	0x19f9, 0x2004, 0x9c06, 0x1130, 0x0036, 0x2019, 0x0001, 0x080c,
+	0xa1b8, 0x003e, 0x080c, 0xa3c3, 0x010e, 0x090c, 0xa93a, 0x0005,
+	0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, 0x8000, 0x7554, 0x9582,
+	0x0001, 0x0608, 0x7058, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148,
+	0x9ce0, 0x001c, 0x7068, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1ddc,
+	0x0c98, 0x6003, 0x0008, 0x8529, 0x7556, 0x9ca8, 0x001c, 0x7068,
+	0x9502, 0x1230, 0x755a, 0x9085, 0x0001, 0x012e, 0x00ee, 0x0005,
+	0x705b, 0x1ddc, 0x0cc0, 0x9006, 0x0cc0, 0x6020, 0x9084, 0x000f,
+	0x0002, 0xad61, 0xad6b, 0xad86, 0xada1, 0xd0ee, 0xd10b, 0xd126,
+	0xad61, 0xad6b, 0x9025, 0xadbd, 0xad61, 0xad61, 0xad61, 0xad61,
+	0xad61, 0x9186, 0x0013, 0x1130, 0x6044, 0xd0fc, 0x0110, 0x080c,
+	0x967a, 0x0005, 0x0005, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c,
+	0x0d7d, 0x0013, 0x006e, 0x0005, 0xad84, 0xb4fd, 0xb6da, 0xad84,
+	0xb770, 0xb086, 0xad84, 0xad84, 0xb47f, 0xbcda, 0xad84, 0xad84,
+	0xad84, 0xad84, 0xad84, 0xad84, 0x080c, 0x0d7d, 0x0066, 0x6000,
+	0x90b2, 0x0016, 0x1a0c, 0x0d7d, 0x0013, 0x006e, 0x0005, 0xad9f,
+	0xc2f2, 0xad9f, 0xad9f, 0xad9f, 0xad9f, 0xad9f, 0xad9f, 0xc289,
+	0xc475, 0xad9f, 0xc32f, 0xc3b3, 0xc32f, 0xc3b3, 0xad9f, 0x080c,
+	0x0d7d, 0x6000, 0x9082, 0x0016, 0x1a0c, 0x0d7d, 0x6000, 0x0002,
+	0xadbb, 0xbd24, 0xbdbe, 0xbf3e, 0xbfad, 0xadbb, 0xadbb, 0xadbb,
+	0xbcf3, 0xc20a, 0xc20d, 0xadbb, 0xadbb, 0xadbb, 0xadbb, 0xc23d,
+	0xadbb, 0xadbb, 0xadbb, 0x080c, 0x0d7d, 0x0066, 0x6000, 0x90b2,
+	0x0016, 0x1a0c, 0x0d7d, 0x0013, 0x006e, 0x0005, 0xadd6, 0xadd6,
+	0xae14, 0xaeb3, 0xaf33, 0xadd6, 0xadd6, 0xadd6, 0xadd8, 0xadd6,
+	0xadd6, 0xadd6, 0xadd6, 0xadd6, 0xadd6, 0xadd6, 0x080c, 0x0d7d,
+	0x9186, 0x004c, 0x0560, 0x9186, 0x0003, 0x190c, 0x0d7d, 0x0096,
+	0x601c, 0xc0ed, 0x601e, 0x6003, 0x0003, 0x6106, 0x6014, 0x2048,
+	0xa87c, 0x9084, 0xa000, 0xc0b5, 0xa87e, 0xa8ac, 0xa836, 0xa8b0,
+	0xa83a, 0x9006, 0xa846, 0xa84a, 0xa884, 0x9092, 0x199a, 0x0210,
+	0x2001, 0x1999, 0x8003, 0x8013, 0x8213, 0x9210, 0x621a, 0x009e,
+	0x080c, 0x1c10, 0x2009, 0x8030, 0x080c, 0x92f7, 0x0005, 0x6010,
+	0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00, 0x080c, 0xaf55, 0x080c,
+	0xd0b3, 0x6003, 0x0007, 0x0005, 0x00d6, 0x0096, 0x00f6, 0x2079,
+	0x1800, 0x7a90, 0x6014, 0x2048, 0xa87c, 0xd0ec, 0x1110, 0x9290,
+	0x0018, 0xac78, 0xc4fc, 0x0046, 0xa8e0, 0x9005, 0x1140, 0xa8dc,
+	0x921a, 0x0140, 0x0220, 0xa87b, 0x0007, 0x2010, 0x0028, 0xa87b,
+	0x0015, 0x0010, 0xa87b, 0x0000, 0x8214, 0xa883, 0x0000, 0xaa02,
+	0x0006, 0x0016, 0x0026, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2400,
+	0x9005, 0x1108, 0x009a, 0x2100, 0x9086, 0x0015, 0x1118, 0x2001,
+	0x0001, 0x0038, 0x2100, 0x9086, 0x0016, 0x0118, 0x2001, 0x0001,
+	0x002a, 0x94a4, 0x0007, 0x8423, 0x9405, 0x0002, 0xae7b, 0xae7b,
+	0xae76, 0xae79, 0xae7b, 0xae73, 0xae66, 0xae66, 0xae66, 0xae66,
+	0xae66, 0xae66, 0xae66, 0xae66, 0xae66, 0xae66, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x002e, 0x001e, 0x000e, 0x004e, 0x00fe, 0x009e,
+	0x00de, 0x080c, 0x0d7d, 0x080c, 0xb92f, 0x0028, 0x080c, 0xba14,
+	0x0010, 0x080c, 0xbb0a, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e,
+	0x001e, 0x2c00, 0xa896, 0x000e, 0x080c, 0xb013, 0x0530, 0xa804,
+	0xa80e, 0x00a6, 0x2050, 0xb100, 0x00ae, 0x8006, 0x8006, 0x8007,
+	0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002, 0xaacc, 0xabd0,
+	0xacd4, 0xadd8, 0x2031, 0x0000, 0x2041, 0x12b0, 0x080c, 0xb1d4,
+	0x0160, 0x000e, 0x9005, 0x0120, 0x00fe, 0x009e, 0x00de, 0x0005,
+	0x00fe, 0x009e, 0x00de, 0x0804, 0xacb0, 0x2001, 0x002c, 0x900e,
+	0x080c, 0xb079, 0x0c70, 0x91b6, 0x0015, 0x0170, 0x91b6, 0x0016,
+	0x0158, 0x91b2, 0x0047, 0x0a0c, 0x0d7d, 0x91b2, 0x0050, 0x1a0c,
+	0x0d7d, 0x9182, 0x0047, 0x0042, 0x080c, 0xab33, 0x0120, 0x9086,
+	0x0002, 0x0904, 0xae14, 0x0005, 0xaed5, 0xaed5, 0xaed7, 0xaf09,
+	0xaed5, 0xaed5, 0xaed5, 0xaed5, 0xaf1c, 0x080c, 0x0d7d, 0x00d6,
+	0x0016, 0x0096, 0x6003, 0x0004, 0x6114, 0x2148, 0xa87c, 0xd0fc,
+	0x01c0, 0xa878, 0xc0fc, 0x9005, 0x1158, 0xa894, 0x9005, 0x0140,
+	0x2001, 0x0000, 0x900e, 0x080c, 0xb079, 0x080c, 0xacb0, 0x00a8,
+	0x6003, 0x0002, 0xa8a4, 0xa9a8, 0x9105, 0x1178, 0xa8ae, 0xa8b2,
+	0x0c78, 0xa87f, 0x0020, 0xa88c, 0xa88a, 0xa8a4, 0xa8ae, 0xa8a8,
+	0xa8b2, 0xa8c7, 0x0000, 0xa8cb, 0x0000, 0x009e, 0x001e, 0x00de,
+	0x0005, 0x080c, 0x96d5, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xc97a, 0x0120, 0xa87b, 0x0006, 0x080c, 0x6dee, 0x009e, 0x00de,
+	0x080c, 0xacb0, 0x0804, 0x9738, 0x080c, 0x96d5, 0x080c, 0x3240,
+	0x080c, 0xd0b0, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c, 0xc97a,
+	0x0120, 0xa87b, 0x0029, 0x080c, 0x6dee, 0x009e, 0x00de, 0x080c,
+	0xacb0, 0x0804, 0x9738, 0x9182, 0x0047, 0x0002, 0xaf43, 0xaf45,
+	0xaf43, 0xaf43, 0xaf43, 0xaf43, 0xaf43, 0xaf43, 0xaf43, 0xaf43,
+	0xaf43, 0xaf43, 0xaf45, 0x080c, 0x0d7d, 0x00d6, 0x0096, 0x601f,
+	0x0000, 0x6114, 0x2148, 0xa87b, 0x0000, 0xa883, 0x0000, 0x080c,
+	0x6dee, 0x009e, 0x00de, 0x0804, 0xacb0, 0x0026, 0x0036, 0x0056,
+	0x0066, 0x0096, 0x00a6, 0x00f6, 0x0006, 0x080c, 0x1047, 0x000e,
+	0x090c, 0x0d7d, 0xa960, 0x21e8, 0xa95c, 0x9188, 0x0019, 0x21a0,
+	0x900e, 0x20a9, 0x0020, 0x4104, 0xa87a, 0x2079, 0x1800, 0x7990,
+	0x9188, 0x0018, 0x918c, 0x0fff, 0xa972, 0xac76, 0x2950, 0x00a6,
+	0x2001, 0x0205, 0x2003, 0x0000, 0x901e, 0x2029, 0x0001, 0x9182,
+	0x0034, 0x1228, 0x2011, 0x001f, 0x080c, 0xc4f8, 0x04c0, 0x2130,
+	0x2009, 0x0034, 0x2011, 0x001f, 0x080c, 0xc4f8, 0x96b2, 0x0034,
+	0xb004, 0x904d, 0x0110, 0x080c, 0x0ff9, 0x080c, 0x1047, 0x01d0,
+	0x8528, 0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a,
+	0x003d, 0x1230, 0x2608, 0x2011, 0x001b, 0x080c, 0xc4f8, 0x00b8,
+	0x96b2, 0x003c, 0x2009, 0x003c, 0x2950, 0x2011, 0x001b, 0x080c,
+	0xc4f8, 0x0c18, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f,
+	0x95ad, 0x0050, 0xb566, 0xb070, 0xc0fd, 0xb072, 0x0048, 0x2001,
+	0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0050, 0xb566,
+	0x2a48, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c, 0x6dee, 0x000e,
+	0x2048, 0x9005, 0x1db0, 0x00fe, 0x00ae, 0x009e, 0x006e, 0x005e,
+	0x003e, 0x002e, 0x0005, 0x00d6, 0x00f6, 0x0096, 0x0006, 0x080c,
+	0x1047, 0x000e, 0x090c, 0x0d7d, 0xa960, 0x21e8, 0xa95c, 0x9188,
+	0x0019, 0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xaa66, 0xa87a,
+	0x2079, 0x1800, 0x7990, 0x810c, 0x9188, 0x000c, 0x9182, 0x001a,
+	0x0210, 0x2009, 0x001a, 0x21a8, 0x810b, 0xa972, 0xac76, 0x2e98,
+	0xa85c, 0x9080, 0x001f, 0x20a0, 0x2001, 0x0205, 0x200c, 0x918d,
+	0x0080, 0x2102, 0x4003, 0x2003, 0x0000, 0x080c, 0x6dee, 0x009e,
+	0x00fe, 0x00de, 0x0005, 0x0016, 0x00d6, 0x00f6, 0x0096, 0x0016,
+	0x2001, 0x0205, 0x200c, 0x918d, 0x0080, 0x2102, 0x001e, 0x2079,
+	0x0200, 0x2e98, 0xa87c, 0xd0ec, 0x0118, 0x9e80, 0x000c, 0x2098,
+	0x2021, 0x003e, 0x901e, 0x9282, 0x0020, 0x0218, 0x2011, 0x0020,
+	0x2018, 0x9486, 0x003e, 0x1170, 0x0096, 0x080c, 0x1047, 0x2900,
+	0x009e, 0x05c0, 0xa806, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0002, 0x20a0, 0x3300, 0x908e, 0x0260, 0x0140, 0x2009, 0x0280,
+	0x9102, 0x920a, 0x0218, 0x2010, 0x2100, 0x9318, 0x2200, 0x9402,
+	0x1228, 0x2400, 0x9202, 0x2410, 0x9318, 0x9006, 0x2020, 0x22a8,
+	0xa800, 0x9200, 0xa802, 0x20e1, 0x0000, 0x4003, 0x83ff, 0x0180,
+	0x3300, 0x9086, 0x0280, 0x1130, 0x7814, 0x8000, 0x9085, 0x0080,
+	0x7816, 0x2e98, 0x2310, 0x84ff, 0x0904, 0xb028, 0x0804, 0xb02a,
+	0x9085, 0x0001, 0x7817, 0x0000, 0x009e, 0x00fe, 0x00de, 0x001e,
+	0x0005, 0x00d6, 0x0036, 0x0096, 0x6314, 0x2348, 0xa87a, 0xa982,
+	0x080c, 0x6de2, 0x009e, 0x003e, 0x00de, 0x0005, 0x91b6, 0x0015,
+	0x1118, 0x080c, 0xacb0, 0x0030, 0x91b6, 0x0016, 0x190c, 0x0d7d,
+	0x080c, 0xacb0, 0x0005, 0x20a9, 0x000e, 0x20e1, 0x0000, 0x2e98,
+	0x6014, 0x0096, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x20a0, 0x009e,
+	0x4003, 0x0136, 0x9080, 0x001b, 0x20a0, 0x2011, 0x0006, 0x20a9,
+	0x0001, 0x3418, 0x8318, 0x23a0, 0x4003, 0x3318, 0x8318, 0x2398,
+	0x8211, 0x1db8, 0x2011, 0x0006, 0x013e, 0x20a0, 0x3318, 0x8318,
+	0x2398, 0x4003, 0x3418, 0x8318, 0x23a0, 0x8211, 0x1db8, 0x0096,
+	0x080c, 0xc97a, 0x0130, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0x009e, 0x0804, 0xacb0, 0x0096, 0x00d6, 0x0036, 0x7330,
+	0x9386, 0x0200, 0x11a8, 0x6010, 0x00b6, 0x2058, 0xb8d7, 0x0000,
+	0x00be, 0x6014, 0x9005, 0x0130, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0xab32, 0x080c, 0xacb0, 0x003e, 0x00de, 0x009e, 0x0005,
+	0x0011, 0x1d48, 0x0cc8, 0x0006, 0x0016, 0x080c, 0xd09b, 0x0188,
+	0x6014, 0x9005, 0x1170, 0x600b, 0x0003, 0x601b, 0x0000, 0x604b,
+	0x0000, 0x2009, 0x0022, 0x080c, 0xb4d5, 0x9006, 0x001e, 0x000e,
+	0x0005, 0x9085, 0x0001, 0x0cd0, 0x0096, 0x0016, 0x20a9, 0x0014,
+	0x9e80, 0x000c, 0x20e1, 0x0000, 0x2098, 0x6014, 0x2048, 0xa860,
+	0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x2001, 0x0205,
+	0x2003, 0x0001, 0x2099, 0x0260, 0x20a9, 0x0016, 0x4003, 0x20a9,
+	0x000a, 0xa804, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002,
+	0x20a0, 0x4003, 0x2001, 0x0205, 0x2003, 0x0002, 0x2099, 0x0260,
+	0x20a9, 0x0020, 0x4003, 0x2003, 0x0000, 0x6014, 0x2048, 0xa800,
+	0x2048, 0xa867, 0x0103, 0x080c, 0xacb0, 0x001e, 0x009e, 0x0005,
+	0x0096, 0x0016, 0x900e, 0x7030, 0x9086, 0x0100, 0x0140, 0x7038,
+	0x9084, 0x00ff, 0x800c, 0x703c, 0x9084, 0x00ff, 0x8004, 0x9080,
+	0x0004, 0x9108, 0x810b, 0x2011, 0x0002, 0x2019, 0x000c, 0x6014,
+	0x2048, 0x080c, 0xc4f8, 0x080c, 0xc97a, 0x0140, 0x6014, 0x2048,
+	0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103, 0x080c, 0xacb0,
+	0x001e, 0x009e, 0x0005, 0x0016, 0x2009, 0x0000, 0x7030, 0x9086,
+	0x0200, 0x0110, 0x2009, 0x0001, 0x0096, 0x6014, 0x904d, 0x090c,
+	0x0d7d, 0xa97a, 0x080c, 0x6dee, 0x009e, 0x080c, 0xacb0, 0x001e,
+	0x0005, 0x0016, 0x0096, 0x7030, 0x9086, 0x0100, 0x1118, 0x2009,
+	0x0004, 0x0010, 0x7034, 0x800c, 0x810b, 0x2011, 0x000c, 0x2019,
+	0x000c, 0x6014, 0x2048, 0xa804, 0x0096, 0x9005, 0x0108, 0x2048,
+	0x080c, 0xc4f8, 0x009e, 0x080c, 0xc97a, 0x0148, 0xa804, 0x9005,
+	0x1158, 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103, 0x080c,
+	0xacb0, 0x009e, 0x001e, 0x0005, 0x0086, 0x2040, 0xa030, 0x8007,
+	0x9086, 0x0100, 0x1118, 0x080c, 0xb693, 0x00e0, 0xa034, 0x8007,
+	0x800c, 0x8806, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x9080, 0x000c, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000,
+	0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000, 0x2041, 0x1296,
+	0x0019, 0x0d08, 0x008e, 0x0898, 0x0096, 0x0006, 0x080c, 0x1047,
+	0x000e, 0x01b0, 0xa8ab, 0x0dcb, 0xa876, 0x000e, 0xa8a2, 0x0006,
+	0xae6a, 0x2800, 0xa89e, 0xa97a, 0xaf72, 0xaa8e, 0xab92, 0xac96,
+	0xad9a, 0x0086, 0x2940, 0x080c, 0x113c, 0x008e, 0x9085, 0x0001,
+	0x009e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008, 0x9084, 0x00ff,
+	0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206, 0x1520, 0x700c,
+	0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206, 0x11e0, 0x604b,
+	0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c, 0xd013, 0x001e,
+	0x1158, 0x622c, 0x2268, 0x2071, 0x026c, 0x6b20, 0x9386, 0x0003,
+	0x0130, 0x9386, 0x0006, 0x0128, 0x080c, 0xacb0, 0x0020, 0x0039,
+	0x0010, 0x080c, 0xb30a, 0x002e, 0x00de, 0x00ee, 0x0005, 0x0096,
+	0x6814, 0x2048, 0x9186, 0x0015, 0x0904, 0xb2e9, 0x918e, 0x0016,
+	0x1904, 0xb308, 0x700c, 0x908c, 0xff00, 0x9186, 0x1700, 0x0120,
+	0x9186, 0x0300, 0x1904, 0xb2c3, 0x89ff, 0x1138, 0x6800, 0x9086,
+	0x000f, 0x0904, 0xb2a5, 0x0804, 0xb306, 0x6808, 0x9086, 0xffff,
+	0x1904, 0xb2eb, 0xa87c, 0x9084, 0x0060, 0x9086, 0x0020, 0x1150,
+	0xa8ac, 0xa934, 0x9106, 0x1904, 0xb2eb, 0xa8b0, 0xa938, 0x9106,
+	0x1904, 0xb2eb, 0x6824, 0xd084, 0x1904, 0xb2eb, 0xd0b4, 0x0158,
+	0x0016, 0x2001, 0x1985, 0x200c, 0x6018, 0x9102, 0x9082, 0x0005,
+	0x001e, 0x1a04, 0xb2eb, 0x080c, 0xcb6b, 0x6810, 0x0096, 0x2048,
+	0xa9a0, 0x009e, 0x685c, 0xa87a, 0xa976, 0x6864, 0xa882, 0xa87c,
+	0xc0dc, 0xc0f4, 0xc0d4, 0xa87e, 0x0026, 0x900e, 0x6a18, 0x2001,
+	0x000a, 0x080c, 0x91f8, 0xa884, 0x920a, 0x0208, 0x8011, 0xaa86,
+	0x82ff, 0x002e, 0x1138, 0x00c6, 0x2d60, 0x080c, 0xc683, 0x00ce,
+	0x0804, 0xb306, 0x00c6, 0xa868, 0xd0fc, 0x1118, 0x080c, 0x6124,
+	0x0010, 0x080c, 0x652f, 0x00ce, 0x1904, 0xb2eb, 0x00c6, 0x2d60,
+	0x080c, 0xacb0, 0x00ce, 0x0804, 0xb306, 0x00c6, 0x080c, 0xad20,
+	0x0198, 0x6017, 0x0000, 0x6810, 0x6012, 0x080c, 0xce15, 0x6023,
+	0x0003, 0x6904, 0x00c6, 0x2d60, 0x080c, 0xacb0, 0x00ce, 0x080c,
+	0xad4d, 0x00ce, 0x0804, 0xb306, 0x2001, 0x1987, 0x2004, 0x684a,
+	0x00ce, 0x0804, 0xb306, 0x7008, 0x9086, 0x000b, 0x11c8, 0x6010,
+	0x00b6, 0x2058, 0xb900, 0xc1bc, 0xb902, 0x00be, 0x00c6, 0x2d60,
+	0xa87b, 0x0003, 0x080c, 0xd055, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x6023, 0x0002, 0x2009, 0x8020, 0x080c, 0x92b0, 0x00ce, 0x0430,
+	0x700c, 0x9086, 0x2a00, 0x1138, 0x2001, 0x1987, 0x2004, 0x684a,
+	0x00e8, 0x04c1, 0x00e8, 0x89ff, 0x090c, 0x0d7d, 0x00c6, 0x00d6,
+	0x2d60, 0xa867, 0x0103, 0xa87b, 0x0003, 0x080c, 0x6c04, 0x080c,
+	0xcb6b, 0x080c, 0xaceb, 0x0026, 0x6010, 0x00b6, 0x2058, 0xba3c,
+	0x080c, 0x67be, 0x00be, 0x002e, 0x00de, 0x00ce, 0x080c, 0xacb0,
+	0x009e, 0x0005, 0x9186, 0x0015, 0x1128, 0x2001, 0x1987, 0x2004,
+	0x684a, 0x0068, 0x918e, 0x0016, 0x1160, 0x00c6, 0x2d00, 0x2060,
+	0x080c, 0xe6a0, 0x080c, 0x894e, 0x080c, 0xacb0, 0x00ce, 0x080c,
+	0xacb0, 0x0005, 0x0026, 0x0036, 0x0046, 0x7228, 0xacb0, 0xabac,
+	0xd2f4, 0x0130, 0x2001, 0x1987, 0x2004, 0x684a, 0x0804, 0xb384,
+	0x00c6, 0x2d60, 0x080c, 0xc559, 0x00ce, 0x6804, 0x9086, 0x0050,
+	0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007, 0x0050,
+	0x2009, 0x8023, 0x080c, 0x92b0, 0x00ce, 0x04f0, 0x6800, 0x9086,
+	0x000f, 0x01a8, 0x89ff, 0x090c, 0x0d7d, 0x6800, 0x9086, 0x0004,
+	0x1190, 0xa87c, 0xd0ac, 0x0178, 0xa843, 0x0fff, 0xa83f, 0x0fff,
+	0xa880, 0xc0fc, 0xa882, 0x2001, 0x0001, 0x6832, 0x0400, 0x2001,
+	0x0007, 0x6832, 0x00e0, 0xa87c, 0xd0b4, 0x1150, 0xd0ac, 0x0db8,
+	0x6824, 0xd0f4, 0x1d48, 0xa838, 0xa934, 0x9105, 0x0d80, 0x0c20,
+	0xd2ec, 0x1d68, 0x7024, 0x9306, 0x1118, 0x7020, 0x9406, 0x0d38,
+	0x7020, 0x683e, 0x7024, 0x683a, 0x2001, 0x0005, 0x6832, 0x080c,
+	0xccff, 0x080c, 0x9738, 0x0010, 0x080c, 0xacb0, 0x004e, 0x003e,
+	0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008, 0x9084, 0x00ff,
+	0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206, 0x1904, 0xb3ef,
+	0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206, 0x1904,
+	0xb3ef, 0x6038, 0x2068, 0x6824, 0xc0dc, 0x6826, 0x6a20, 0x9286,
+	0x0007, 0x0904, 0xb3ef, 0x9286, 0x0002, 0x0904, 0xb3ef, 0x9286,
+	0x0000, 0x05e8, 0x6808, 0x633c, 0x9306, 0x15c8, 0x2071, 0x026c,
+	0x9186, 0x0015, 0x0570, 0x918e, 0x0016, 0x1100, 0x00c6, 0x6038,
+	0x2060, 0x6104, 0x9186, 0x004b, 0x01c0, 0x9186, 0x004c, 0x01a8,
+	0x9186, 0x004d, 0x0190, 0x9186, 0x004e, 0x0178, 0x9186, 0x0052,
+	0x0160, 0x6014, 0x0096, 0x2048, 0x080c, 0xc97a, 0x090c, 0x0d7d,
+	0xa87b, 0x0003, 0x009e, 0x080c, 0xd055, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x6023, 0x0002, 0x2009, 0x8020, 0x080c, 0x92b0, 0x00ce,
+	0x0030, 0x6038, 0x2070, 0x2001, 0x1987, 0x2004, 0x704a, 0x080c,
+	0xacb0, 0x002e, 0x00de, 0x00ee, 0x0005, 0x00b6, 0x0096, 0x00f6,
+	0x6014, 0x2048, 0x6010, 0x2058, 0x91b6, 0x0015, 0x0130, 0xba08,
+	0xbb0c, 0xbc00, 0xc48c, 0xbc02, 0x0460, 0x0096, 0x0156, 0x0036,
+	0x0026, 0x2b48, 0x9e90, 0x0010, 0x2019, 0x000a, 0x20a9, 0x0004,
+	0x080c, 0xbca2, 0x002e, 0x003e, 0x015e, 0x009e, 0x1904, 0xb45e,
+	0x0096, 0x0156, 0x0036, 0x0026, 0x2b48, 0x9e90, 0x0014, 0x2019,
+	0x0006, 0x20a9, 0x0004, 0x080c, 0xbca2, 0x002e, 0x003e, 0x015e,
+	0x009e, 0x15a0, 0x7238, 0xba0a, 0x733c, 0xbb0e, 0xbc00, 0xc48d,
+	0xbc02, 0xa804, 0x9005, 0x1128, 0x00fe, 0x009e, 0x00be, 0x0804,
+	0xb0bf, 0x0096, 0x2048, 0xaa12, 0xab16, 0xac0a, 0x009e, 0x8006,
+	0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002,
+	0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000,
+	0x2041, 0x1296, 0x080c, 0xb1d4, 0x0130, 0x00fe, 0x009e, 0x080c,
+	0xacb0, 0x00be, 0x0005, 0x080c, 0xb693, 0x0cb8, 0x2b78, 0x00f6,
+	0x080c, 0x3240, 0x080c, 0xd0b0, 0x00fe, 0x00c6, 0x080c, 0xac5a,
+	0x2f00, 0x6012, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001,
+	0x6003, 0x0001, 0x2001, 0x0007, 0x080c, 0x65e3, 0x080c, 0x660f,
+	0x080c, 0x92b7, 0x080c, 0x9738, 0x00ce, 0x0804, 0xb431, 0x2100,
+	0x91b2, 0x0053, 0x1a0c, 0x0d7d, 0x91b2, 0x0040, 0x1a04, 0xb4e7,
+	0x0002, 0xb4d5, 0xb4d5, 0xb4cb, 0xb4d5, 0xb4d5, 0xb4d5, 0xb4c9,
+	0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4d5, 0xb4c9, 0xb4d5, 0xb4d5, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4c9, 0xb4cb, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4c9, 0xb4c9, 0xb4c9, 0xb4d5, 0xb4d5, 0xb4c9, 0xb4c9, 0xb4c9,
+	0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4c9, 0xb4d5, 0xb4c9,
+	0xb4c9, 0x080c, 0x0d7d, 0x0066, 0x00b6, 0x6610, 0x2658, 0xb8d4,
+	0xc08c, 0xb8d6, 0x00be, 0x006e, 0x0000, 0x6003, 0x0001, 0x6106,
+	0x9186, 0x0032, 0x0118, 0x080c, 0x92b7, 0x0010, 0x080c, 0x92b0,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x9738, 0x012e, 0x0005, 0x2600,
+	0x0002, 0xb4d5, 0xb4d5, 0xb4fb, 0xb4d5, 0xb4d5, 0xb4fb, 0xb4fb,
+	0xb4fb, 0xb4fb, 0xb4d5, 0xb4fb, 0xb4d5, 0xb4fb, 0xb4d5, 0xb4fb,
+	0xb4fb, 0xb4fb, 0xb4fb, 0x080c, 0x0d7d, 0x6004, 0x90b2, 0x0053,
+	0x1a0c, 0x0d7d, 0x91b6, 0x0013, 0x0904, 0xb5d2, 0x91b6, 0x0027,
+	0x1904, 0xb57e, 0x080c, 0x967a, 0x6004, 0x080c, 0xcb80, 0x01b0,
+	0x080c, 0xcb91, 0x01a8, 0x908e, 0x0021, 0x0904, 0xb57b, 0x908e,
+	0x0022, 0x1130, 0x080c, 0xb0eb, 0x0904, 0xb577, 0x0804, 0xb578,
+	0x908e, 0x003d, 0x0904, 0xb57b, 0x0804, 0xb571, 0x080c, 0x326f,
+	0x2001, 0x0007, 0x080c, 0x65e3, 0x6010, 0x00b6, 0x2058, 0xb9a0,
+	0x00be, 0x080c, 0xb693, 0x9186, 0x007e, 0x1148, 0x2001, 0x1837,
+	0x2014, 0xc285, 0x080c, 0x753d, 0x1108, 0xc2ad, 0x2202, 0x080c,
+	0xa91e, 0x0036, 0x0026, 0x2019, 0x0028, 0x2110, 0x080c, 0xe7ac,
+	0x002e, 0x003e, 0x0016, 0x0026, 0x0036, 0x2110, 0x2019, 0x0028,
+	0x080c, 0x943d, 0x0076, 0x903e, 0x080c, 0x9306, 0x6010, 0x00b6,
+	0x905d, 0x0100, 0x00be, 0x2c08, 0x080c, 0xe167, 0x007e, 0x003e,
+	0x002e, 0x001e, 0x080c, 0xa93a, 0x080c, 0xd0b0, 0x0016, 0x080c,
+	0xce0d, 0x080c, 0xacb0, 0x001e, 0x080c, 0x3349, 0x080c, 0x9738,
+	0x0030, 0x080c, 0xce0d, 0x080c, 0xacb0, 0x080c, 0x9738, 0x0005,
+	0x080c, 0xb693, 0x0cb0, 0x080c, 0xb6cf, 0x0c98, 0x9186, 0x0015,
+	0x0118, 0x9186, 0x0016, 0x1140, 0x080c, 0xab33, 0x0d80, 0x9086,
+	0x0002, 0x0904, 0xb6da, 0x0c58, 0x9186, 0x0014, 0x1d40, 0x080c,
+	0x967a, 0x6004, 0x908e, 0x0022, 0x1118, 0x080c, 0xb0eb, 0x09f8,
+	0x080c, 0x3240, 0x080c, 0xd0b0, 0x080c, 0xcb80, 0x1190, 0x080c,
+	0x326f, 0x6010, 0x00b6, 0x2058, 0xb9a0, 0x00be, 0x080c, 0xb693,
+	0x9186, 0x007e, 0x1128, 0x2001, 0x1837, 0x200c, 0xc185, 0x2102,
+	0x0800, 0x080c, 0xcb91, 0x1120, 0x080c, 0xb693, 0x0804, 0xb571,
+	0x6004, 0x908e, 0x0032, 0x1160, 0x00e6, 0x00f6, 0x2071, 0x189e,
+	0x2079, 0x0000, 0x080c, 0x35ea, 0x00fe, 0x00ee, 0x0804, 0xb571,
+	0x6004, 0x908e, 0x0021, 0x0d40, 0x908e, 0x0022, 0x090c, 0xb693,
+	0x0804, 0xb571, 0x90b2, 0x0040, 0x1a04, 0xb673, 0x2008, 0x0002,
+	0xb61a, 0xb61b, 0xb61e, 0xb621, 0xb624, 0xb627, 0xb618, 0xb618,
+	0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618,
+	0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618,
+	0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb62a, 0xb635,
+	0xb618, 0xb636, 0xb635, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618,
+	0xb635, 0xb635, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618, 0xb618,
+	0xb618, 0xb618, 0xb65e, 0xb635, 0xb618, 0xb631, 0xb618, 0xb618,
+	0xb618, 0xb632, 0xb618, 0xb618, 0xb618, 0xb635, 0xb659, 0xb618,
+	0x080c, 0x0d7d, 0x00d0, 0x2001, 0x000b, 0x00f8, 0x2001, 0x0003,
+	0x00e0, 0x2001, 0x0005, 0x00c8, 0x2001, 0x0001, 0x00b0, 0x2001,
+	0x0009, 0x0098, 0x6003, 0x0005, 0x080c, 0xd0b3, 0x080c, 0x9738,
+	0x0058, 0x0018, 0x0010, 0x080c, 0x65e3, 0x04b8, 0x080c, 0xd0b3,
+	0x6003, 0x0004, 0x080c, 0x9738, 0x0005, 0x080c, 0x65e3, 0x6003,
+	0x0002, 0x0036, 0x2019, 0x1852, 0x2304, 0x9084, 0xff00, 0x1120,
+	0x2001, 0x1985, 0x201c, 0x0040, 0x8007, 0x909a, 0x0004, 0x0ec0,
+	0x8003, 0x801b, 0x831b, 0x9318, 0x631a, 0x003e, 0x080c, 0x9738,
+	0x0c18, 0x080c, 0xce0d, 0x080c, 0xacb0, 0x08f0, 0x00e6, 0x00f6,
+	0x2071, 0x189e, 0x2079, 0x0000, 0x080c, 0x35ea, 0x00fe, 0x00ee,
+	0x080c, 0x967a, 0x080c, 0xacb0, 0x0878, 0x6003, 0x0002, 0x080c,
+	0xd0b3, 0x0804, 0x9738, 0x2600, 0x2008, 0x0002, 0xb68a, 0xb66d,
+	0xb688, 0xb66d, 0xb66d, 0xb688, 0xb688, 0xb688, 0xb688, 0xb66d,
+	0xb688, 0xb66d, 0xb688, 0xb66d, 0xb688, 0xb688, 0xb688, 0xb688,
+	0x080c, 0x0d7d, 0x0096, 0x6014, 0x2048, 0x080c, 0x6dee, 0x009e,
+	0x080c, 0xacb0, 0x0005, 0x00e6, 0x0096, 0x0026, 0x0016, 0x080c,
+	0xc97a, 0x0568, 0x6014, 0x2048, 0xa864, 0x9086, 0x0139, 0x11a8,
+	0xa894, 0x9086, 0x0056, 0x1148, 0x080c, 0x54ca, 0x0130, 0x2001,
+	0x0000, 0x900e, 0x2011, 0x4000, 0x0028, 0x2001, 0x0030, 0x900e,
+	0x2011, 0x4005, 0x080c, 0xcf7a, 0x0090, 0xa868, 0xd0fc, 0x0178,
+	0xa807, 0x0000, 0x0016, 0x6004, 0x908e, 0x0021, 0x0168, 0x908e,
+	0x003d, 0x0150, 0x001e, 0xa867, 0x0103, 0xa833, 0x0100, 0x001e,
+	0x002e, 0x009e, 0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc0, 0x0096,
+	0x6014, 0x2048, 0xa800, 0x2048, 0xa867, 0x0103, 0xa823, 0x8001,
+	0x009e, 0x0005, 0x00b6, 0x6610, 0x2658, 0xb804, 0x9084, 0x00ff,
+	0x90b2, 0x000c, 0x1a0c, 0x0d7d, 0x6604, 0x96b6, 0x004d, 0x1120,
+	0x080c, 0xce99, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x0043, 0x1120,
+	0x080c, 0xcee2, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x004b, 0x1120,
+	0x080c, 0xcf0e, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x0033, 0x1120,
+	0x080c, 0xce2f, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x0028, 0x1120,
+	0x080c, 0xcbcf, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x0029, 0x1120,
+	0x080c, 0xcc10, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x001f, 0x1120,
+	0x080c, 0xb093, 0x0804, 0xb75f, 0x6604, 0x96b6, 0x0000, 0x1118,
+	0x080c, 0xb3f5, 0x04e0, 0x6604, 0x96b6, 0x0022, 0x1118, 0x080c,
+	0xb0cc, 0x04a8, 0x6604, 0x96b6, 0x0035, 0x1118, 0x080c, 0xb1f2,
+	0x0470, 0x6604, 0x96b6, 0x0039, 0x1118, 0x080c, 0xb38a, 0x0438,
+	0x6604, 0x96b6, 0x003d, 0x1118, 0x080c, 0xb104, 0x0400, 0x6604,
+	0x96b6, 0x0044, 0x1118, 0x080c, 0xb140, 0x00c8, 0x6604, 0x96b6,
+	0x0049, 0x1118, 0x080c, 0xb181, 0x0090, 0x6604, 0x96b6, 0x0041,
+	0x1118, 0x080c, 0xb16b, 0x0058, 0x91b6, 0x0015, 0x1110, 0x0063,
+	0x0030, 0x91b6, 0x0016, 0x1128, 0x00be, 0x0804, 0xb9bb, 0x00be,
+	0x0005, 0x080c, 0xad6a, 0x0cd8, 0xb77c, 0xb77f, 0xb77c, 0xb7c6,
+	0xb77c, 0xb92f, 0xb9c8, 0xb77c, 0xb77c, 0xb991, 0xb77c, 0xb9a7,
+	0x0096, 0x601f, 0x0000, 0x6014, 0x2048, 0xa800, 0x2048, 0xa867,
+	0x0103, 0x009e, 0x0804, 0xacb0, 0xa001, 0xa001, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0x7090, 0x9086, 0x0074, 0x1540, 0x080c, 0xe138,
+	0x11b0, 0x6010, 0x00b6, 0x2058, 0x7030, 0xd08c, 0x0128, 0xb800,
+	0xd0bc, 0x0110, 0xc0c5, 0xb802, 0x00f9, 0x00be, 0x2001, 0x0006,
+	0x080c, 0x65e3, 0x080c, 0x326f, 0x080c, 0xacb0, 0x0098, 0x2001,
+	0x000a, 0x080c, 0x65e3, 0x080c, 0x326f, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0020, 0x2001, 0x0001,
+	0x080c, 0xb8ff, 0x00ee, 0x0005, 0x00d6, 0xb800, 0xd084, 0x0160,
+	0x9006, 0x080c, 0x65cf, 0x2069, 0x1847, 0x6804, 0xd0a4, 0x0120,
+	0x2001, 0x0006, 0x080c, 0x660f, 0x00de, 0x0005, 0x00b6, 0x0096,
+	0x00d6, 0x2011, 0x1824, 0x2204, 0x9086, 0x0074, 0x1904, 0xb8d4,
+	0x6010, 0x2058, 0xbaa0, 0x9286, 0x007e, 0x1120, 0x080c, 0xbb15,
+	0x0804, 0xb838, 0x080c, 0xbb0a, 0x6010, 0x2058, 0xbaa0, 0x9286,
+	0x0080, 0x1510, 0x6014, 0x9005, 0x01a8, 0x2048, 0xa864, 0x9084,
+	0x00ff, 0x9086, 0x0039, 0x1140, 0x2001, 0x0000, 0x900e, 0x2011,
+	0x4000, 0x080c, 0xcf7a, 0x0030, 0xa807, 0x0000, 0xa867, 0x0103,
+	0xa833, 0x0200, 0x2001, 0x0006, 0x080c, 0x65e3, 0x080c, 0x326f,
+	0x080c, 0xacb0, 0x0804, 0xb8d9, 0x080c, 0xb8e7, 0x6014, 0x9005,
+	0x0190, 0x2048, 0xa868, 0xd0f4, 0x01e8, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0039, 0x1d08, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000,
+	0x080c, 0xcf7a, 0x08f8, 0x080c, 0xb8dd, 0x0160, 0x9006, 0x080c,
+	0x65cf, 0x2001, 0x0004, 0x080c, 0x660f, 0x2001, 0x0007, 0x080c,
+	0x65e3, 0x08a0, 0x2001, 0x0004, 0x080c, 0x65e3, 0x6003, 0x0001,
+	0x6007, 0x0003, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0804, 0xb8d9,
+	0xb85c, 0xd0e4, 0x01d8, 0x080c, 0xcda7, 0x080c, 0x753d, 0x0118,
+	0xd0dc, 0x1904, 0xb7fa, 0x2011, 0x1837, 0x2204, 0xc0ad, 0x2012,
+	0x2001, 0x196c, 0x2004, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000,
+	0x080c, 0x26d5, 0x78e2, 0x00fe, 0x0804, 0xb7fa, 0x080c, 0xcde8,
+	0x2011, 0x1837, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0xe2c8,
+	0x000e, 0x1904, 0xb7fa, 0xc0b5, 0x2012, 0x2001, 0x0006, 0x080c,
+	0x65e3, 0x9006, 0x080c, 0x65cf, 0x00c6, 0x2001, 0x180f, 0x2004,
+	0xd09c, 0x0520, 0x00f6, 0x2079, 0x0100, 0x00e6, 0x2071, 0x1800,
+	0x700c, 0x9084, 0x00ff, 0x78e6, 0x707e, 0x7010, 0x78ea, 0x7082,
+	0x908c, 0x00ff, 0x00ee, 0x780c, 0xc0b5, 0x780e, 0x00fe, 0x080c,
+	0x26aa, 0x00f6, 0x2100, 0x900e, 0x080c, 0x2661, 0x795e, 0x00fe,
+	0x9186, 0x0081, 0x01d8, 0x2009, 0x0081, 0x00c8, 0x2009, 0x00ef,
+	0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, 0x780c, 0xc0b5,
+	0x780e, 0x00fe, 0x080c, 0x26aa, 0x00f6, 0x2079, 0x1800, 0x7982,
+	0x2100, 0x900e, 0x080c, 0x2661, 0x795e, 0x00fe, 0x8108, 0x080c,
+	0x6632, 0x2b00, 0x00ce, 0x1904, 0xb7fa, 0x6012, 0x2009, 0x180f,
+	0x210c, 0xd19c, 0x0150, 0x2009, 0x027c, 0x210c, 0x918c, 0x00ff,
+	0xb912, 0x2009, 0x027d, 0x210c, 0xb916, 0x2001, 0x0002, 0x080c,
+	0x65e3, 0x6023, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c,
+	0x92b7, 0x080c, 0x9738, 0x0028, 0x080c, 0xb693, 0x2001, 0x0001,
+	0x0431, 0x00de, 0x009e, 0x00be, 0x0005, 0x2001, 0x1810, 0x2004,
+	0xd0a4, 0x0120, 0x2001, 0x1848, 0x2004, 0xd0ac, 0x0005, 0x00e6,
+	0x080c, 0xe805, 0x0190, 0x2071, 0x0260, 0x7108, 0x720c, 0x918c,
+	0x00ff, 0x1118, 0x9284, 0xff00, 0x0140, 0x6010, 0x2058, 0xb8a0,
+	0x9084, 0xff80, 0x1110, 0xb912, 0xba16, 0x00ee, 0x0005, 0x2030,
+	0x9005, 0x0158, 0x2001, 0x0007, 0x080c, 0x65e3, 0x080c, 0x5752,
+	0x1120, 0x2001, 0x0007, 0x080c, 0x660f, 0x2600, 0x9005, 0x11b0,
+	0x6014, 0x0096, 0x2048, 0xa868, 0x009e, 0xd0fc, 0x1178, 0x0036,
+	0x0046, 0x6010, 0x00b6, 0x2058, 0xbba0, 0x00be, 0x2021, 0x0004,
+	0x2011, 0x8014, 0x080c, 0x4b52, 0x004e, 0x003e, 0x080c, 0x326f,
+	0x6020, 0x9086, 0x000a, 0x1108, 0x0005, 0x0804, 0xacb0, 0x00b6,
+	0x00e6, 0x0026, 0x0016, 0x2071, 0x1800, 0x7090, 0x9086, 0x0014,
+	0x1904, 0xb987, 0x080c, 0x5752, 0x1170, 0x6014, 0x9005, 0x1158,
+	0x0036, 0x0046, 0x6010, 0x2058, 0xbba0, 0x2021, 0x0006, 0x080c,
+	0x4d09, 0x004e, 0x003e, 0x00d6, 0x6010, 0x2058, 0x080c, 0x672e,
+	0x080c, 0xb7b4, 0x00de, 0x080c, 0xbbdb, 0x1588, 0x6010, 0x2058,
+	0xb890, 0x9005, 0x0560, 0x2001, 0x0006, 0x080c, 0x65e3, 0x0096,
+	0x6014, 0x904d, 0x01d0, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0039,
+	0x1140, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x080c, 0xcf7a,
+	0x0060, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0029, 0x0130, 0xa807,
+	0x0000, 0xa867, 0x0103, 0xa833, 0x0200, 0x009e, 0x080c, 0x326f,
+	0x6020, 0x9086, 0x000a, 0x0140, 0x080c, 0xacb0, 0x0028, 0x080c,
+	0xb693, 0x9006, 0x080c, 0xb8ff, 0x001e, 0x002e, 0x00ee, 0x00be,
+	0x0005, 0x2011, 0x1824, 0x2204, 0x9086, 0x0014, 0x1160, 0x2001,
+	0x0002, 0x080c, 0x65e3, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c,
+	0x92b7, 0x0804, 0x9738, 0x2001, 0x0001, 0x0804, 0xb8ff, 0x2030,
+	0x2011, 0x1824, 0x2204, 0x9086, 0x0004, 0x1148, 0x96b6, 0x000b,
+	0x1120, 0x2001, 0x0007, 0x080c, 0x65e3, 0x0804, 0xacb0, 0x2001,
+	0x0001, 0x0804, 0xb8ff, 0x0002, 0xb77c, 0xb9d3, 0xb77c, 0xba14,
+	0xb77c, 0xbac1, 0xb9c8, 0xb77c, 0xb77c, 0xbad5, 0xb77c, 0xbae7,
+	0x6604, 0x9686, 0x0003, 0x0904, 0xb92f, 0x96b6, 0x001e, 0x1110,
+	0x080c, 0xacb0, 0x0005, 0x00b6, 0x00d6, 0x00c6, 0x080c, 0xbaf9,
+	0x11a0, 0x9006, 0x080c, 0x65cf, 0x080c, 0x3240, 0x080c, 0xd0b0,
+	0x2001, 0x0002, 0x080c, 0x65e3, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x92b7, 0x080c, 0x9738, 0x0418, 0x2009, 0x026e, 0x2104,
+	0x9086, 0x0009, 0x1160, 0x6010, 0x2058, 0xb840, 0x9084, 0x00ff,
+	0x9005, 0x0170, 0x8001, 0xb842, 0x601b, 0x000a, 0x0088, 0x2009,
+	0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x1900, 0x1108, 0x08a0,
+	0x080c, 0x3240, 0x080c, 0xd0b0, 0x2001, 0x0001, 0x080c, 0xb8ff,
+	0x00ce, 0x00de, 0x00be, 0x0005, 0x0096, 0x00b6, 0x0026, 0x9016,
+	0x080c, 0xbb07, 0x00d6, 0x2069, 0x197b, 0x2d04, 0x9005, 0x0168,
+	0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x2069, 0x1820,
+	0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de, 0x0088, 0x9006,
+	0x080c, 0x65cf, 0x2001, 0x0002, 0x080c, 0x65e3, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0804, 0xba91,
+	0x080c, 0xc97a, 0x01b0, 0x6014, 0x2048, 0xa864, 0x2010, 0x9086,
+	0x0139, 0x1138, 0x6007, 0x0016, 0x2001, 0x0002, 0x080c, 0xcfd4,
+	0x00b0, 0x6014, 0x2048, 0xa864, 0xd0fc, 0x0118, 0x2001, 0x0001,
+	0x0ca8, 0x2001, 0x180e, 0x2004, 0xd0dc, 0x0148, 0x6010, 0x2058,
+	0xb840, 0x9084, 0x00ff, 0x9005, 0x1110, 0x9006, 0x0c38, 0x080c,
+	0xb693, 0x2009, 0x026e, 0x2134, 0x96b4, 0x00ff, 0x9686, 0x0005,
+	0x0520, 0x9686, 0x000b, 0x01c8, 0x2009, 0x026f, 0x2104, 0x9084,
+	0xff00, 0x1118, 0x9686, 0x0009, 0x01c0, 0x9086, 0x1900, 0x1168,
+	0x9686, 0x0009, 0x0190, 0x2001, 0x0004, 0x080c, 0x65e3, 0x2001,
+	0x0028, 0x601a, 0x6007, 0x0052, 0x0020, 0x2001, 0x0001, 0x080c,
+	0xb8ff, 0x002e, 0x00be, 0x009e, 0x0005, 0x9286, 0x0139, 0x0160,
+	0x6014, 0x2048, 0x080c, 0xc97a, 0x0140, 0xa864, 0x9086, 0x0139,
+	0x0118, 0xa868, 0xd0fc, 0x0108, 0x0c40, 0x6010, 0x2058, 0xb840,
+	0x9084, 0x00ff, 0x9005, 0x0138, 0x8001, 0xb842, 0x601b, 0x000a,
+	0x6007, 0x0016, 0x08f0, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x00e6,
+	0x2071, 0x1800, 0x080c, 0x6025, 0x00ee, 0x0010, 0x080c, 0x3240,
+	0x0860, 0x080c, 0xbb07, 0x1160, 0x2001, 0x0004, 0x080c, 0x65e3,
+	0x6003, 0x0001, 0x6007, 0x0003, 0x080c, 0x92b7, 0x0804, 0x9738,
+	0x080c, 0xb693, 0x9006, 0x0804, 0xb8ff, 0x0489, 0x1160, 0x2001,
+	0x0008, 0x080c, 0x65e3, 0x6003, 0x0001, 0x6007, 0x0005, 0x080c,
+	0x92b7, 0x0804, 0x9738, 0x2001, 0x0001, 0x0804, 0xb8ff, 0x00f9,
+	0x1160, 0x2001, 0x000a, 0x080c, 0x65e3, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x080c, 0x92b7, 0x0804, 0x9738, 0x2001, 0x0001, 0x0804,
+	0xb8ff, 0x2009, 0x026e, 0x2104, 0x9086, 0x0003, 0x1138, 0x2009,
+	0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x2a00, 0x0005, 0x9085,
+	0x0001, 0x0005, 0x00b6, 0x00c6, 0x0016, 0x6110, 0x2158, 0x080c,
+	0x66a2, 0x001e, 0x00ce, 0x00be, 0x0005, 0x00b6, 0x00f6, 0x00e6,
+	0x00d6, 0x0036, 0x0016, 0x6010, 0x2058, 0x2009, 0x1837, 0x2104,
+	0x9085, 0x0003, 0x200a, 0x080c, 0xbbad, 0x0560, 0x2009, 0x1837,
+	0x2104, 0xc0cd, 0x200a, 0x080c, 0x6ad9, 0x0158, 0x9006, 0x2020,
+	0x2009, 0x002a, 0x080c, 0xe445, 0x2001, 0x180c, 0x200c, 0xc195,
+	0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x080c, 0x3205, 0x00e6,
+	0x2071, 0x1800, 0x080c, 0x3011, 0x00ee, 0x00c6, 0x0156, 0x20a9,
+	0x0781, 0x2009, 0x007f, 0x080c, 0x3349, 0x8108, 0x1f04, 0xbb4b,
+	0x015e, 0x00ce, 0x080c, 0xbb0a, 0x2071, 0x0260, 0x2079, 0x0200,
+	0x7817, 0x0001, 0x2001, 0x1837, 0x200c, 0xc1c5, 0x7018, 0xd0fc,
+	0x0110, 0xd0dc, 0x0118, 0x7038, 0xd0dc, 0x1108, 0xc1c4, 0x7817,
+	0x0000, 0x2001, 0x1837, 0x2102, 0x2079, 0x0100, 0x2e04, 0x9084,
+	0x00ff, 0x2069, 0x181f, 0x206a, 0x78e6, 0x0006, 0x8e70, 0x2e04,
+	0x2069, 0x1820, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010, 0x9084,
+	0xff00, 0x001e, 0x9105, 0x2009, 0x182c, 0x200a, 0x2200, 0x9084,
+	0x00ff, 0x2008, 0x080c, 0x26aa, 0x080c, 0x753d, 0x0170, 0x2071,
+	0x0260, 0x2069, 0x1981, 0x7048, 0x206a, 0x704c, 0x6806, 0x7050,
+	0x680a, 0x7054, 0x680e, 0x080c, 0xcda7, 0x0040, 0x2001, 0x0006,
+	0x080c, 0x65e3, 0x080c, 0x326f, 0x080c, 0xacb0, 0x001e, 0x003e,
+	0x00de, 0x00ee, 0x00fe, 0x00be, 0x0005, 0x0096, 0x0026, 0x0036,
+	0x00e6, 0x0156, 0x2019, 0x182c, 0x231c, 0x83ff, 0x01f0, 0x2071,
+	0x0260, 0x7200, 0x9294, 0x00ff, 0x7004, 0x9084, 0xff00, 0x9205,
+	0x9306, 0x1198, 0x2011, 0x0276, 0x20a9, 0x0004, 0x2b48, 0x2019,
+	0x000a, 0x080c, 0xbca2, 0x1148, 0x2011, 0x027a, 0x20a9, 0x0004,
+	0x2019, 0x0006, 0x080c, 0xbca2, 0x1100, 0x015e, 0x00ee, 0x003e,
+	0x002e, 0x009e, 0x0005, 0x00e6, 0x2071, 0x0260, 0x7034, 0x9086,
+	0x0014, 0x11a8, 0x7038, 0x9086, 0x0800, 0x1188, 0x703c, 0xd0ec,
+	0x0160, 0x9084, 0x0f00, 0x9086, 0x0100, 0x1138, 0x7054, 0xd0a4,
+	0x1110, 0xd0ac, 0x0110, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ee,
+	0x0005, 0x00e6, 0x0096, 0x00c6, 0x0076, 0x0056, 0x0046, 0x0026,
+	0x0006, 0x0126, 0x2091, 0x8000, 0x2029, 0x19f2, 0x252c, 0x2021,
+	0x19f9, 0x2424, 0x2061, 0x1ddc, 0x2071, 0x1800, 0x7254, 0x7074,
+	0x9202, 0x1a04, 0xbc6e, 0x080c, 0x8c1f, 0x0904, 0xbc67, 0x080c,
+	0xe476, 0x0904, 0xbc67, 0x6720, 0x9786, 0x0007, 0x0904, 0xbc67,
+	0x2500, 0x9c06, 0x0904, 0xbc67, 0x2400, 0x9c06, 0x0904, 0xbc67,
+	0x3e08, 0x9186, 0x0002, 0x1148, 0x6010, 0x9005, 0x0130, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x1590, 0x00c6, 0x6043, 0xffff,
+	0x6000, 0x9086, 0x0004, 0x1110, 0x080c, 0x1ac5, 0x9786, 0x000a,
+	0x0148, 0x080c, 0xcb91, 0x1130, 0x00ce, 0x080c, 0xb693, 0x080c,
+	0xaceb, 0x00e8, 0x6014, 0x2048, 0x080c, 0xc97a, 0x01a8, 0x9786,
+	0x0003, 0x1530, 0xa867, 0x0103, 0xa87c, 0xd0cc, 0x0130, 0x0096,
+	0xa878, 0x2048, 0x080c, 0x0ff9, 0x009e, 0xab7a, 0xa877, 0x0000,
+	0x080c, 0x6de2, 0x080c, 0xcb6b, 0x080c, 0xaceb, 0x00ce, 0x9ce0,
+	0x001c, 0x7068, 0x9c02, 0x1210, 0x0804, 0xbc0e, 0x012e, 0x000e,
+	0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x009e, 0x00ee, 0x0005,
+	0x9786, 0x0006, 0x1118, 0x080c, 0xe3e8, 0x0c30, 0x9786, 0x0009,
+	0x1148, 0x6000, 0x9086, 0x0004, 0x0d08, 0x2009, 0x004c, 0x080c,
+	0xad4d, 0x08e0, 0x9786, 0x000a, 0x0980, 0x0820, 0x220c, 0x2304,
+	0x9106, 0x1130, 0x8210, 0x8318, 0x1f04, 0xbc8e, 0x9006, 0x0005,
+	0x2304, 0x9102, 0x0218, 0x2001, 0x0001, 0x0008, 0x9006, 0x918d,
+	0x0001, 0x0005, 0x0136, 0x01c6, 0x0016, 0x8906, 0x8006, 0x8007,
+	0x908c, 0x003f, 0x21e0, 0x9084, 0xffc0, 0x9300, 0x2098, 0x3518,
+	0x20a9, 0x0001, 0x220c, 0x4002, 0x910e, 0x1140, 0x8210, 0x8319,
+	0x1dc8, 0x9006, 0x001e, 0x01ce, 0x013e, 0x0005, 0x220c, 0x9102,
+	0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0x918d, 0x0001,
+	0x001e, 0x01ce, 0x013e, 0x0005, 0x220c, 0x810f, 0x2304, 0x9106,
+	0x1130, 0x8210, 0x8318, 0x1f04, 0xbccc, 0x9006, 0x0005, 0x918d,
+	0x0001, 0x0005, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0d7d, 0x080c,
+	0xcb80, 0x0120, 0x080c, 0xcb91, 0x0158, 0x0028, 0x080c, 0x326f,
+	0x080c, 0xcb91, 0x0128, 0x080c, 0x967a, 0x080c, 0xacb0, 0x0005,
+	0x080c, 0xb693, 0x0cc0, 0x9182, 0x0057, 0x1220, 0x9182, 0x0040,
+	0x0208, 0x000a, 0x0005, 0xbd12, 0xbd12, 0xbd12, 0xbd12, 0xbd12,
+	0xbd12, 0xbd12, 0xbd12, 0xbd12, 0xbd12, 0xbd12, 0xbd14, 0xbd14,
+	0xbd14, 0xbd14, 0xbd12, 0xbd12, 0xbd12, 0xbd14, 0xbd12, 0xbd12,
+	0xbd12, 0xbd12, 0x080c, 0x0d7d, 0x600b, 0xffff, 0x6003, 0x000f,
+	0x6106, 0x0126, 0x2091, 0x8000, 0x080c, 0xd0b3, 0x2009, 0x8000,
+	0x080c, 0x92b0, 0x012e, 0x0005, 0x9186, 0x0013, 0x1128, 0x6004,
+	0x9082, 0x0040, 0x0804, 0xbd9c, 0x9186, 0x0027, 0x1520, 0x080c,
+	0x967a, 0x080c, 0x3240, 0x080c, 0xd0b0, 0x0096, 0x6114, 0x2148,
+	0x080c, 0xc97a, 0x0198, 0x080c, 0xcb91, 0x1118, 0x080c, 0xb693,
+	0x0068, 0xa867, 0x0103, 0xa87b, 0x0029, 0xa877, 0x0000, 0xa97c,
+	0xc1c5, 0xa97e, 0x080c, 0x6dee, 0x080c, 0xcb6b, 0x009e, 0x080c,
+	0xacb0, 0x0804, 0x9738, 0x9186, 0x0014, 0x1120, 0x6004, 0x9082,
+	0x0040, 0x0030, 0x9186, 0x0053, 0x0110, 0x080c, 0x0d7d, 0x0005,
+	0x0002, 0xbd7a, 0xbd78, 0xbd78, 0xbd78, 0xbd78, 0xbd78, 0xbd78,
+	0xbd78, 0xbd78, 0xbd78, 0xbd78, 0xbd93, 0xbd93, 0xbd93, 0xbd93,
+	0xbd78, 0xbd93, 0xbd78, 0xbd93, 0xbd78, 0xbd78, 0xbd78, 0xbd78,
+	0x080c, 0x0d7d, 0x080c, 0x967a, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xc97a, 0x0168, 0xa867, 0x0103, 0xa87b, 0x0006, 0xa877, 0x0000,
+	0xa880, 0xc0ec, 0xa882, 0x080c, 0x6dee, 0x080c, 0xcb6b, 0x009e,
+	0x080c, 0xacb0, 0x0005, 0x080c, 0x967a, 0x080c, 0xcb91, 0x090c,
+	0xb693, 0x080c, 0xacb0, 0x0005, 0x0002, 0xbdb6, 0xbdb4, 0xbdb4,
+	0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4,
+	0xbdb8, 0xbdb8, 0xbdb8, 0xbdb8, 0xbdb4, 0xbdba, 0xbdb4, 0xbdb8,
+	0xbdb4, 0xbdb4, 0xbdb4, 0xbdb4, 0x080c, 0x0d7d, 0x080c, 0x0d7d,
+	0x080c, 0x0d7d, 0x080c, 0xacb0, 0x0804, 0x9738, 0x9182, 0x0057,
+	0x1220, 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xbddd, 0xbddd,
+	0xbddd, 0xbddd, 0xbddd, 0xbe16, 0xbf05, 0xbddd, 0xbf11, 0xbddd,
+	0xbddd, 0xbddd, 0xbddd, 0xbddd, 0xbddd, 0xbddd, 0xbddd, 0xbddd,
+	0xbddd, 0xbf11, 0xbddf, 0xbddd, 0xbf0f, 0x080c, 0x0d7d, 0x00b6,
+	0x0096, 0x6114, 0x2148, 0x6010, 0x2058, 0xb800, 0xd0bc, 0x1508,
+	0xa87b, 0x0000, 0xa867, 0x0103, 0xa877, 0x0000, 0xa87c, 0xd0ac,
+	0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xbf96, 0x080c, 0x6c04,
+	0x6210, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e, 0xb8d0,
+	0x9005, 0x0110, 0x080c, 0x67be, 0x080c, 0xacb0, 0x009e, 0x00be,
+	0x0005, 0xa87c, 0xd0ac, 0x09e0, 0xa838, 0xa934, 0x9105, 0x09c0,
+	0xa880, 0xd0bc, 0x19a8, 0x080c, 0xccc6, 0x0c80, 0x00b6, 0x0096,
+	0x6114, 0x2148, 0x601c, 0xd0fc, 0x1110, 0x7644, 0x0008, 0x9036,
+	0x96b4, 0x0fff, 0x86ff, 0x1590, 0x6010, 0x2058, 0xb800, 0xd0bc,
+	0x1904, 0xbef4, 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76, 0xa87c,
+	0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xbf96, 0x080c,
+	0x6c04, 0x6210, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211, 0xba3e,
+	0xb8d0, 0x9005, 0x0110, 0x080c, 0x67be, 0x601c, 0xd0fc, 0x1148,
+	0x7044, 0xd0e4, 0x1904, 0xbed8, 0x080c, 0xacb0, 0x009e, 0x00be,
+	0x0005, 0x2009, 0x0211, 0x210c, 0x080c, 0x0d7d, 0x968c, 0x0c00,
+	0x0150, 0x6010, 0x2058, 0xb800, 0xd0bc, 0x1904, 0xbedc, 0x7348,
+	0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0508,
+	0x9186, 0x0028, 0x1118, 0xa87b, 0x001c, 0x00e8, 0xd6dc, 0x01a0,
+	0xa87b, 0x0015, 0xa87c, 0xd0ac, 0x0170, 0xa938, 0xaa34, 0x2100,
+	0x9205, 0x0148, 0x7048, 0x9106, 0x1118, 0x704c, 0x9206, 0x0118,
+	0xa992, 0xaa8e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007,
+	0x0010, 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76, 0x901e, 0xd6c4,
+	0x01d8, 0x9686, 0x0100, 0x1130, 0x7064, 0x9005, 0x1118, 0xc6c4,
+	0x0804, 0xbe22, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, 0x0009,
+	0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x2011,
+	0x0025, 0x080c, 0xc4f8, 0x003e, 0xd6cc, 0x0904, 0xbe37, 0x7154,
+	0xa98a, 0x81ff, 0x0904, 0xbe37, 0x9192, 0x0021, 0x1278, 0x8304,
+	0x9098, 0x0018, 0x2011, 0x0029, 0x080c, 0xc4f8, 0x2011, 0x0205,
+	0x2013, 0x0000, 0x080c, 0xd040, 0x0804, 0xbe37, 0xa868, 0xd0fc,
+	0x0120, 0x2009, 0x0020, 0xa98a, 0x0c50, 0x00a6, 0x2950, 0x080c,
+	0xc497, 0x00ae, 0x080c, 0xd040, 0x080c, 0xc4e8, 0x0804, 0xbe39,
+	0x080c, 0xcc89, 0x0804, 0xbe4e, 0xa87c, 0xd0ac, 0x0904, 0xbe5f,
+	0xa880, 0xd0bc, 0x1904, 0xbe5f, 0x7348, 0xa838, 0x9306, 0x11c8,
+	0x734c, 0xa834, 0x931e, 0x0904, 0xbe5f, 0xd6d4, 0x0190, 0xab38,
+	0x9305, 0x0904, 0xbe5f, 0x0068, 0xa87c, 0xd0ac, 0x0904, 0xbe2a,
+	0xa838, 0xa934, 0x9105, 0x0904, 0xbe2a, 0xa880, 0xd0bc, 0x1904,
+	0xbe2a, 0x080c, 0xccc6, 0x0804, 0xbe4e, 0x00f6, 0x2079, 0x026c,
+	0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x00fe, 0x0021, 0x0005, 0x0011,
+	0x0005, 0x0005, 0x0096, 0x6003, 0x0002, 0x6007, 0x0043, 0x6014,
+	0x2048, 0xa87c, 0xd0ac, 0x0128, 0x009e, 0x0005, 0x2130, 0x2228,
+	0x0058, 0x2400, 0xa9ac, 0x910a, 0x2300, 0xaab0, 0x9213, 0x2600,
+	0x9102, 0x2500, 0x9203, 0x0e90, 0xac46, 0xab4a, 0xae36, 0xad3a,
+	0x6044, 0xd0fc, 0x190c, 0xa947, 0x604b, 0x0000, 0x080c, 0x1c86,
+	0x1118, 0x6144, 0x080c, 0x92dc, 0x009e, 0x0005, 0x9182, 0x0057,
+	0x1220, 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xbf5d, 0xbf5d,
+	0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d,
+	0xbf5f, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf5d, 0xbf70, 0xbf5d, 0xbf5d,
+	0xbf5d, 0xbf5d, 0xbf94, 0xbf5d, 0xbf5d, 0x080c, 0x0d7d, 0x6004,
+	0x9086, 0x0040, 0x1110, 0x080c, 0x967a, 0x2019, 0x0001, 0x080c,
+	0xa1b8, 0x6003, 0x0002, 0x080c, 0xd0b8, 0x080c, 0x96d5, 0x0005,
+	0x6004, 0x9086, 0x0040, 0x1110, 0x080c, 0x967a, 0x2019, 0x0001,
+	0x080c, 0xa1b8, 0x080c, 0x96d5, 0x080c, 0x3240, 0x080c, 0xd0b0,
+	0x0096, 0x6114, 0x2148, 0x080c, 0xc97a, 0x0150, 0xa867, 0x0103,
+	0xa87b, 0x0029, 0xa877, 0x0000, 0x080c, 0x6dee, 0x080c, 0xcb6b,
+	0x009e, 0x080c, 0xacb0, 0x0005, 0x080c, 0x0d7d, 0xa87b, 0x0015,
+	0xd1fc, 0x0180, 0xa87b, 0x0007, 0x8002, 0x8000, 0x810a, 0x9189,
+	0x0000, 0x0006, 0x0016, 0x2009, 0x1a77, 0x2104, 0x8000, 0x200a,
+	0x001e, 0x000e, 0xa992, 0xa88e, 0x0005, 0x9182, 0x0057, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xbfcc, 0xbfcc, 0xbfcc,
+	0xbfcc, 0xbfcc, 0xbfce, 0xbfcc, 0xbfcc, 0xc08b, 0xbfcc, 0xbfcc,
+	0xbfcc, 0xbfcc, 0xbfcc, 0xbfcc, 0xbfcc, 0xbfcc, 0xbfcc, 0xbfcc,
+	0xc1cb, 0xbfcc, 0xc1d5, 0xbfcc, 0x080c, 0x0d7d, 0x601c, 0xd0bc,
+	0x0178, 0xd084, 0x0168, 0xd0f4, 0x0120, 0xc084, 0x601e, 0x0804,
+	0xbdbe, 0x6114, 0x0096, 0x2148, 0xa87c, 0xc0e5, 0xa87e, 0x009e,
+	0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071, 0x0260, 0x6114, 0x2150,
+	0x601c, 0xd0fc, 0x1110, 0x7644, 0x0008, 0x9036, 0xb676, 0x96b4,
+	0x0fff, 0xb77c, 0xc7e5, 0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c,
+	0x82ff, 0x0110, 0x8211, 0xba3e, 0x00be, 0x86ff, 0x0904, 0xc084,
+	0x9694, 0xff00, 0x9284, 0x0c00, 0x0120, 0x7048, 0xb092, 0x704c,
+	0xb08e, 0x9284, 0x0300, 0x0904, 0xc084, 0x9686, 0x0100, 0x1130,
+	0x7064, 0x9005, 0x1118, 0xc6c4, 0xb676, 0x0c38, 0x080c, 0x1047,
+	0x090c, 0x0d7d, 0x2900, 0xb07a, 0xb77c, 0x97bd, 0x0200, 0xb77e,
+	0xa867, 0x0103, 0xb068, 0xa86a, 0xb06c, 0xa86e, 0xb070, 0xa872,
+	0x7044, 0x9084, 0xf000, 0x9635, 0xae76, 0x968c, 0x0c00, 0x0120,
+	0x7348, 0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002,
+	0x0180, 0x9186, 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc,
+	0x0118, 0xa87b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007,
+	0x0010, 0xa87b, 0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886,
+	0x901e, 0xd6c4, 0x0190, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a,
+	0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018,
+	0x2011, 0x0025, 0x080c, 0xc4f8, 0x003e, 0xd6cc, 0x01e8, 0x7154,
+	0xa98a, 0x81ff, 0x01c8, 0x9192, 0x0021, 0x1260, 0x8304, 0x9098,
+	0x0018, 0x2011, 0x0029, 0x080c, 0xc4f8, 0x2011, 0x0205, 0x2013,
+	0x0000, 0x0050, 0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a,
+	0x0c68, 0x2950, 0x080c, 0xc497, 0x080c, 0x1a93, 0x009e, 0x00ee,
+	0x00ae, 0x007e, 0x0005, 0x2001, 0x1987, 0x2004, 0x604a, 0x0096,
+	0x6114, 0x2148, 0xa83c, 0xa940, 0x9105, 0x1118, 0xa87c, 0xc0dc,
+	0xa87e, 0x6003, 0x0002, 0x080c, 0xd0c1, 0x0904, 0xc1c6, 0x604b,
+	0x0000, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1500,
+	0xd1cc, 0x0904, 0xc18a, 0xa978, 0xa868, 0xd0fc, 0x0904, 0xc14b,
+	0x0016, 0xa87c, 0x0006, 0xa880, 0x0006, 0x00a6, 0x2150, 0xb174,
+	0x9184, 0x00ff, 0x90b6, 0x0002, 0x0904, 0xc118, 0x9086, 0x0028,
+	0x1904, 0xc104, 0xa87b, 0x001c, 0xb07b, 0x001c, 0x0804, 0xc120,
+	0x6024, 0xd0f4, 0x11d0, 0xa838, 0xaa34, 0x9205, 0x09c8, 0xa838,
+	0xaa90, 0x9206, 0x1120, 0xa88c, 0xaa34, 0x9206, 0x0988, 0x6024,
+	0xd0d4, 0x1148, 0xa9ac, 0xa834, 0x9102, 0x603a, 0xa9b0, 0xa838,
+	0x9103, 0x603e, 0x6024, 0xc0f5, 0x6026, 0x6010, 0x00b6, 0x2058,
+	0xb83c, 0x8000, 0xb83e, 0x00be, 0x601c, 0xc0fc, 0x601e, 0x9006,
+	0xa876, 0xa892, 0xa88e, 0xa87c, 0xc0e4, 0xa87e, 0xd0cc, 0x0140,
+	0xc0cc, 0xa87e, 0x0096, 0xa878, 0x2048, 0x080c, 0x0ff9, 0x009e,
+	0x080c, 0xccc6, 0x0804, 0xc1c6, 0xd1dc, 0x0158, 0xa87b, 0x0015,
+	0xb07b, 0x0015, 0x080c, 0xcf63, 0x0118, 0xb174, 0xc1dc, 0xb176,
+	0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, 0xb07b, 0x0007, 0x0040,
+	0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xbf96,
+	0xa87c, 0xb07e, 0xa890, 0xb092, 0xa88c, 0xb08e, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x0019, 0x20a0, 0x20a9, 0x0020, 0x8a06, 0x8006,
+	0x8007, 0x9094, 0x003f, 0x22e0, 0x9084, 0xffc0, 0x9080, 0x0019,
+	0x2098, 0x4003, 0x00ae, 0x000e, 0xa882, 0x000e, 0xc0cc, 0xa87e,
+	0x080c, 0xd040, 0x001e, 0xa874, 0x0006, 0x2148, 0x080c, 0x0ff9,
+	0x001e, 0x0804, 0xc1b7, 0x0016, 0x00a6, 0x2150, 0xb174, 0x9184,
+	0x00ff, 0x90b6, 0x0002, 0x01e0, 0x9086, 0x0028, 0x1128, 0xa87b,
+	0x001c, 0xb07b, 0x001c, 0x00e0, 0xd1dc, 0x0158, 0xa87b, 0x0015,
+	0xb07b, 0x0015, 0x080c, 0xcf63, 0x0118, 0xb174, 0xc1dc, 0xb176,
+	0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007, 0xb07b, 0x0007, 0x0040,
+	0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xbf96,
+	0xa890, 0xb092, 0xa88c, 0xb08e, 0xa87c, 0xb07e, 0x00ae, 0x080c,
+	0x0ff9, 0x009e, 0x080c, 0xd040, 0xa974, 0x0016, 0x080c, 0xc4e8,
+	0x001e, 0x0468, 0xa867, 0x0103, 0xa974, 0x9184, 0x00ff, 0x90b6,
+	0x0002, 0x01b0, 0x9086, 0x0028, 0x1118, 0xa87b, 0x001c, 0x00d0,
+	0xd1dc, 0x0148, 0xa87b, 0x0015, 0x080c, 0xcf63, 0x0118, 0xa974,
+	0xc1dc, 0xa976, 0x0078, 0xd1d4, 0x0118, 0xa87b, 0x0007, 0x0050,
+	0xa87b, 0x0000, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115,
+	0x190c, 0xbf96, 0xa974, 0x0016, 0x080c, 0x6c04, 0x001e, 0x6010,
+	0x00b6, 0x2058, 0xba3c, 0xb8d0, 0x0016, 0x9005, 0x190c, 0x67be,
+	0x001e, 0x00be, 0xd1e4, 0x1120, 0x080c, 0xacb0, 0x009e, 0x0005,
+	0x080c, 0xcc89, 0x0cd8, 0x6114, 0x0096, 0x2148, 0xa97c, 0x080c,
+	0xd0c1, 0x190c, 0x1ab1, 0x009e, 0x0005, 0x0096, 0x6114, 0x2148,
+	0xa83c, 0xa940, 0x9105, 0x01e8, 0xa877, 0x0000, 0xa87b, 0x0000,
+	0xa867, 0x0103, 0x00b6, 0x6010, 0x2058, 0xa834, 0xa938, 0x9115,
+	0x11a0, 0x080c, 0x6c04, 0xba3c, 0x8211, 0x0208, 0xba3e, 0xb8d0,
+	0x9005, 0x0110, 0x080c, 0x67be, 0x080c, 0xacb0, 0x00be, 0x009e,
+	0x0005, 0xa87c, 0xc0dc, 0xa87e, 0x08f8, 0xb800, 0xd0bc, 0x1120,
+	0xa834, 0x080c, 0xbf96, 0x0c28, 0xa880, 0xd0bc, 0x1dc8, 0x080c,
+	0xccc6, 0x0c60, 0x080c, 0x967a, 0x0010, 0x080c, 0x96d5, 0x601c,
+	0xd084, 0x0110, 0x080c, 0x1ac5, 0x080c, 0xc97a, 0x01f0, 0x0096,
+	0x6114, 0x2148, 0x080c, 0xcb91, 0x1118, 0x080c, 0xb693, 0x00a0,
+	0xa867, 0x0103, 0x2009, 0x180c, 0x210c, 0xd18c, 0x1198, 0xd184,
+	0x1170, 0x6108, 0xa97a, 0x918e, 0x0029, 0x1110, 0x080c, 0xe79d,
+	0xa877, 0x0000, 0x080c, 0x6dee, 0x009e, 0x0804, 0xaceb, 0xa87b,
+	0x0004, 0x0cb0, 0xa87b, 0x0004, 0x0c98, 0x9182, 0x0057, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xc25c, 0xc25c, 0xc25c,
+	0xc25c, 0xc25c, 0xc25e, 0xc25c, 0xc25c, 0xc25c, 0xc25c, 0xc25c,
+	0xc25c, 0xc25c, 0xc25c, 0xc25c, 0xc25c, 0xc25c, 0xc25c, 0xc25c,
+	0xc25c, 0xc282, 0xc25c, 0xc25c, 0x080c, 0x0d7d, 0x080c, 0x5746,
+	0x01f8, 0x6014, 0x7144, 0x918c, 0x0fff, 0x9016, 0xd1c4, 0x0118,
+	0x7264, 0x9294, 0x00ff, 0x0096, 0x904d, 0x0188, 0xa87b, 0x0000,
+	0xa864, 0x9086, 0x0139, 0x0128, 0xa867, 0x0103, 0xa976, 0xaa96,
+	0x0030, 0xa897, 0x4000, 0xa99a, 0xaa9e, 0x080c, 0x6dee, 0x009e,
+	0x0804, 0xacb0, 0x080c, 0x5746, 0x0dd8, 0x6014, 0x900e, 0x9016,
+	0x0c10, 0x9182, 0x0085, 0x0002, 0xc29b, 0xc299, 0xc299, 0xc2a7,
+	0xc299, 0xc299, 0xc299, 0xc299, 0xc299, 0xc299, 0xc299, 0xc299,
+	0xc299, 0x080c, 0x0d7d, 0x6003, 0x0001, 0x6106, 0x0126, 0x2091,
+	0x8000, 0x2009, 0x8020, 0x080c, 0x92b0, 0x012e, 0x0005, 0x0026,
+	0x0056, 0x00d6, 0x00e6, 0x2071, 0x0260, 0x7224, 0x6216, 0x7220,
+	0x080c, 0xc968, 0x01f8, 0x2268, 0x6800, 0x9086, 0x0000, 0x01d0,
+	0x6010, 0x6d10, 0x952e, 0x11b0, 0x00c6, 0x2d60, 0x00d6, 0x080c,
+	0xc559, 0x00de, 0x00ce, 0x0158, 0x702c, 0xd084, 0x1118, 0x080c,
+	0xc523, 0x0010, 0x6803, 0x0002, 0x6007, 0x0086, 0x0028, 0x080c,
+	0xc545, 0x0d90, 0x6007, 0x0087, 0x6003, 0x0001, 0x2009, 0x8020,
+	0x080c, 0x92b0, 0x7220, 0x080c, 0xc968, 0x0178, 0x6810, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x0140, 0x6824, 0xd0ec, 0x0128,
+	0x00c6, 0x2d60, 0x080c, 0xccc6, 0x00ce, 0x00ee, 0x00de, 0x005e,
+	0x002e, 0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085,
+	0x0a0c, 0x0d7d, 0x908a, 0x0092, 0x1a0c, 0x0d7d, 0x9082, 0x0085,
+	0x00e2, 0x9186, 0x0027, 0x0120, 0x9186, 0x0014, 0x190c, 0x0d7d,
+	0x080c, 0x967a, 0x0096, 0x6014, 0x2048, 0x080c, 0xc97a, 0x0140,
+	0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6dee,
+	0x009e, 0x080c, 0xaceb, 0x0804, 0x9738, 0xc32a, 0xc32c, 0xc32c,
+	0xc32a, 0xc32a, 0xc32a, 0xc32a, 0xc32a, 0xc32a, 0xc32a, 0xc32a,
+	0xc32a, 0xc32a, 0x080c, 0x0d7d, 0x080c, 0xaceb, 0x0005, 0x9186,
+	0x0013, 0x1130, 0x6004, 0x9082, 0x0085, 0x2008, 0x0804, 0xc37b,
+	0x9186, 0x0027, 0x1558, 0x080c, 0x967a, 0x080c, 0x3240, 0x080c,
+	0xd0b0, 0x0096, 0x6014, 0x2048, 0x080c, 0xc97a, 0x0150, 0xa867,
+	0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6dee, 0x080c,
+	0xcb6b, 0x009e, 0x080c, 0xacb0, 0x0005, 0x9186, 0x0089, 0x0118,
+	0x9186, 0x008a, 0x1140, 0x080c, 0xab33, 0x0128, 0x9086, 0x000c,
+	0x0904, 0xc3b3, 0x0000, 0x080c, 0xad6a, 0x0c70, 0x9186, 0x0014,
+	0x1d60, 0x080c, 0x967a, 0x0096, 0x6014, 0x2048, 0x080c, 0xc97a,
+	0x0d00, 0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0006, 0xa880,
+	0xc0ec, 0xa882, 0x0890, 0x0002, 0xc38b, 0xc389, 0xc389, 0xc389,
+	0xc389, 0xc389, 0xc39f, 0xc389, 0xc389, 0xc389, 0xc389, 0xc389,
+	0xc389, 0x080c, 0x0d7d, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186,
+	0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x1985, 0x0010,
+	0x2001, 0x1986, 0x2004, 0x601a, 0x6003, 0x000c, 0x0005, 0x6034,
+	0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118, 0x9186, 0x0035,
+	0x1118, 0x2001, 0x1985, 0x0010, 0x2001, 0x1986, 0x2004, 0x601a,
+	0x6003, 0x000e, 0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085,
+	0x0208, 0x0012, 0x0804, 0xad6a, 0xc3c9, 0xc3c9, 0xc3c9, 0xc3c9,
+	0xc3cb, 0xc418, 0xc3c9, 0xc3c9, 0xc3c9, 0xc3c9, 0xc3c9, 0xc3c9,
+	0xc3c9, 0x080c, 0x0d7d, 0x0096, 0x6010, 0x00b6, 0x2058, 0xb800,
+	0x00be, 0xd0bc, 0x0168, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186,
+	0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x009e, 0x0804, 0xc42c,
+	0x080c, 0xc97a, 0x1118, 0x080c, 0xcb6b, 0x0068, 0x6014, 0x2048,
+	0x080c, 0xd0c7, 0x1110, 0x080c, 0xcb6b, 0xa867, 0x0103, 0x080c,
+	0xd07b, 0x080c, 0x6dee, 0x00d6, 0x2c68, 0x080c, 0xac5a, 0x01d0,
+	0x6003, 0x0001, 0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0x026e,
+	0x210c, 0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x6910, 0x6112,
+	0x080c, 0xce15, 0x695c, 0x615e, 0x6023, 0x0001, 0x2009, 0x8020,
+	0x080c, 0x92b0, 0x2d60, 0x00de, 0x080c, 0xacb0, 0x009e, 0x0005,
+	0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x05a0, 0x6034,
+	0x908c, 0xff00, 0x810f, 0x9186, 0x0035, 0x0130, 0x9186, 0x001e,
+	0x0118, 0x9186, 0x0039, 0x1538, 0x00d6, 0x2c68, 0x080c, 0xd013,
+	0x11f0, 0x080c, 0xac5a, 0x01d8, 0x6106, 0x6003, 0x0001, 0x6023,
+	0x0001, 0x6910, 0x6112, 0x692c, 0x612e, 0x6930, 0x6132, 0x6934,
+	0x918c, 0x00ff, 0x6136, 0x6938, 0x613a, 0x693c, 0x613e, 0x695c,
+	0x615e, 0x080c, 0xce15, 0x2009, 0x8020, 0x080c, 0x92b0, 0x2d60,
+	0x00de, 0x0804, 0xacb0, 0x0096, 0x6014, 0x2048, 0x080c, 0xc97a,
+	0x01c8, 0xa867, 0x0103, 0xa880, 0xd0b4, 0x0128, 0xc0ec, 0xa882,
+	0xa87b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020,
+	0xa87b, 0x0005, 0x080c, 0xcc85, 0xa877, 0x0000, 0x080c, 0x6dee,
+	0x080c, 0xcb6b, 0x009e, 0x0804, 0xacb0, 0x0016, 0x0096, 0x6014,
+	0x2048, 0x080c, 0xc97a, 0x0140, 0xa867, 0x0103, 0xa87b, 0x0028,
+	0xa877, 0x0000, 0x080c, 0x6dee, 0x009e, 0x001e, 0x9186, 0x0013,
+	0x0158, 0x9186, 0x0014, 0x0130, 0x9186, 0x0027, 0x0118, 0x080c,
+	0xad6a, 0x0020, 0x080c, 0x967a, 0x080c, 0xaceb, 0x0005, 0x0056,
+	0x0066, 0x0096, 0x00a6, 0x2029, 0x0001, 0x9182, 0x0101, 0x1208,
+	0x0010, 0x2009, 0x0100, 0x2130, 0x8304, 0x9098, 0x0018, 0x2009,
+	0x0020, 0x2011, 0x0029, 0x080c, 0xc4f8, 0x96b2, 0x0020, 0xb004,
+	0x904d, 0x0110, 0x080c, 0x0ff9, 0x080c, 0x1047, 0x0520, 0x8528,
+	0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a, 0x003d,
+	0x1228, 0x2608, 0x2011, 0x001b, 0x0499, 0x00a8, 0x96b2, 0x003c,
+	0x2009, 0x003c, 0x2950, 0x2011, 0x001b, 0x0451, 0x0c28, 0x2001,
+	0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0003, 0xb566,
+	0x95ac, 0x0000, 0x0048, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae,
+	0x852f, 0x95ad, 0x0003, 0xb566, 0x009e, 0x006e, 0x005e, 0x0005,
+	0x00a6, 0x89ff, 0x0158, 0xa804, 0x9055, 0x0130, 0xa807, 0x0000,
+	0x080c, 0x6dee, 0x2a48, 0x0cb8, 0x080c, 0x6dee, 0x00ae, 0x0005,
+	0x00f6, 0x2079, 0x0200, 0x7814, 0x9085, 0x0080, 0x7816, 0xd184,
+	0x0108, 0x8108, 0x810c, 0x20a9, 0x0001, 0xa860, 0x20e8, 0xa85c,
+	0x9200, 0x20a0, 0x20e1, 0x0000, 0x2300, 0x9e00, 0x2098, 0x4003,
+	0x8318, 0x9386, 0x0020, 0x1148, 0x2018, 0x2300, 0x9e00, 0x2098,
+	0x7814, 0x8000, 0x9085, 0x0080, 0x7816, 0x8109, 0x1d80, 0x7817,
+	0x0000, 0x00fe, 0x0005, 0x6920, 0x9186, 0x0003, 0x0118, 0x9186,
+	0x0002, 0x11d0, 0x00c6, 0x00d6, 0x00e6, 0x2d60, 0x0096, 0x6014,
+	0x2048, 0x080c, 0xc97a, 0x0150, 0x2001, 0x0006, 0xa980, 0xc1d5,
+	0x080c, 0x7022, 0x080c, 0x6de2, 0x080c, 0xcb6b, 0x009e, 0x080c,
+	0xaceb, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x702c, 0xd084,
+	0x1170, 0x6008, 0x2060, 0x6020, 0x9086, 0x0002, 0x1140, 0x6104,
+	0x9186, 0x0085, 0x0118, 0x9186, 0x008b, 0x1108, 0x9006, 0x00ce,
+	0x0005, 0x0066, 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x6020,
+	0x9084, 0x000f, 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x0066, 0x2031, 0x0000, 0x6020, 0x9084, 0x000f, 0x001b,
+	0x006e, 0x012e, 0x0005, 0xc5ab, 0xc5ab, 0xc5a6, 0xc5cf, 0xc583,
+	0xc5a6, 0xc585, 0xc5a6, 0xc583, 0x9173, 0xc5a6, 0xc5a6, 0xc5a6,
+	0xc583, 0xc583, 0xc583, 0x080c, 0x0d7d, 0x6010, 0x9080, 0x0000,
+	0x2004, 0xd0bc, 0x190c, 0xc5cf, 0x0036, 0x6014, 0x0096, 0x2048,
+	0xa880, 0x009e, 0xd0cc, 0x0118, 0x2019, 0x000c, 0x0038, 0xd094,
+	0x0118, 0x2019, 0x000d, 0x0010, 0x2019, 0x0010, 0x080c, 0xdfa1,
+	0x6023, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x9006, 0x0005,
+	0x9085, 0x0001, 0x0005, 0x0096, 0x86ff, 0x11e8, 0x6014, 0x2048,
+	0x080c, 0xc97a, 0x01d0, 0x6043, 0xffff, 0xa864, 0x9086, 0x0139,
+	0x1128, 0xa87b, 0x0005, 0xa883, 0x0000, 0x0028, 0x900e, 0x2001,
+	0x0005, 0x080c, 0x7022, 0x080c, 0xcc85, 0x080c, 0x6de2, 0x080c,
+	0xaceb, 0x9085, 0x0001, 0x009e, 0x0005, 0x9006, 0x0ce0, 0x080c,
+	0xa91e, 0x080c, 0xd0d5, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0d7d,
+	0x002b, 0x0106, 0x080c, 0xa93a, 0x010e, 0x0005, 0xc5ee, 0xc61e,
+	0xc5f0, 0xc645, 0xc619, 0xc5ee, 0xc5a6, 0xc5ab, 0xc5ab, 0xc5a6,
+	0xc5a6, 0xc5a6, 0xc5a6, 0xc5a6, 0xc5a6, 0xc5a6, 0x080c, 0x0d7d,
+	0x86ff, 0x1520, 0x6020, 0x9086, 0x0006, 0x0500, 0x0096, 0x6014,
+	0x2048, 0x080c, 0xc97a, 0x0168, 0xa87c, 0xd0cc, 0x0140, 0x0096,
+	0xc0cc, 0xa87e, 0xa878, 0x2048, 0x080c, 0x0ff9, 0x009e, 0x080c,
+	0xcc85, 0x009e, 0x080c, 0xd055, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x6023, 0x0002, 0x2009, 0x8020, 0x080c, 0x9292, 0x9085, 0x0001,
+	0x0005, 0x0066, 0x080c, 0x1ac5, 0x006e, 0x0890, 0x00e6, 0x2071,
+	0x19e6, 0x7030, 0x9c06, 0x1120, 0x080c, 0xa138, 0x00ee, 0x0840,
+	0x6020, 0x9084, 0x000f, 0x9086, 0x0006, 0x1150, 0x0086, 0x0096,
+	0x2049, 0x0001, 0x2c40, 0x080c, 0xa28c, 0x009e, 0x008e, 0x0040,
+	0x0066, 0x080c, 0xa034, 0x190c, 0x0d7d, 0x080c, 0xa042, 0x006e,
+	0x00ee, 0x1904, 0xc5f0, 0x0804, 0xc5a6, 0x0036, 0x00e6, 0x2071,
+	0x19e6, 0x704c, 0x9c06, 0x1138, 0x901e, 0x080c, 0xa1b8, 0x00ee,
+	0x003e, 0x0804, 0xc5f0, 0x080c, 0xa3c3, 0x00ee, 0x003e, 0x1904,
+	0xc5f0, 0x0804, 0xc5a6, 0x00c6, 0x0066, 0x6020, 0x9084, 0x000f,
+	0x001b, 0x006e, 0x00ce, 0x0005, 0xc67b, 0xc74a, 0xc8b4, 0xc683,
+	0xaceb, 0xc67b, 0xdf93, 0xd0bd, 0xc74a, 0x913a, 0xc940, 0xc674,
+	0xc674, 0xc674, 0xc674, 0xc674, 0x080c, 0x0d7d, 0x080c, 0xcb91,
+	0x1110, 0x080c, 0xb693, 0x0005, 0x080c, 0x967a, 0x0804, 0xacb0,
+	0x601b, 0x0001, 0x0005, 0x080c, 0xc97a, 0x0130, 0x6014, 0x0096,
+	0x2048, 0x2c00, 0xa896, 0x009e, 0x080c, 0xa91e, 0x080c, 0xd0d5,
+	0x6000, 0x908a, 0x0016, 0x1a0c, 0x0d7d, 0x0013, 0x0804, 0xa93a,
+	0xc6a8, 0xc6aa, 0xc6d4, 0xc6e8, 0xc715, 0xc6a8, 0xc67b, 0xc67b,
+	0xc67b, 0xc6ef, 0xc6ef, 0xc6a8, 0xc6a8, 0xc6a8, 0xc6a8, 0xc6f9,
+	0x080c, 0x0d7d, 0x00e6, 0x6014, 0x0096, 0x2048, 0xa880, 0xc0b5,
+	0xa882, 0x009e, 0x2071, 0x19e6, 0x7030, 0x9c06, 0x01d0, 0x0066,
+	0x080c, 0xa034, 0x190c, 0x0d7d, 0x080c, 0xa042, 0x006e, 0x080c,
+	0xd055, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x2001,
+	0x1986, 0x2004, 0x601a, 0x2009, 0x8020, 0x080c, 0x9292, 0x00ee,
+	0x0005, 0x601b, 0x0001, 0x0cd8, 0x0096, 0x6014, 0x2048, 0xa880,
+	0xc0b5, 0xa882, 0x009e, 0x080c, 0xd055, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x6023, 0x0002, 0x2009, 0x8020, 0x080c, 0x9292, 0x0005,
+	0x080c, 0xa91e, 0x080c, 0xaab5, 0x080c, 0xa93a, 0x0c28, 0x0096,
+	0x601b, 0x0001, 0x6014, 0x2048, 0xa880, 0xc0b5, 0xa882, 0x009e,
+	0x0005, 0x080c, 0x5746, 0x01b8, 0x6014, 0x0096, 0x904d, 0x0190,
+	0xa864, 0xa867, 0x0103, 0xa87b, 0x0006, 0x9086, 0x0139, 0x1150,
+	0xa867, 0x0139, 0xa87b, 0x0030, 0xa897, 0x4005, 0xa89b, 0x0004,
+	0x080c, 0x6dee, 0x009e, 0x0804, 0xacb0, 0x6014, 0x0096, 0x904d,
+	0x0560, 0xa97c, 0xd1e4, 0x1158, 0x611c, 0xd1fc, 0x0530, 0x6110,
+	0x00b6, 0x2158, 0xb93c, 0x8109, 0x0208, 0xb93e, 0x00be, 0x080c,
+	0xa93a, 0x2001, 0x180f, 0x2004, 0xd0c4, 0x0110, 0x009e, 0x0005,
+	0xa884, 0x009e, 0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0x2001,
+	0x0037, 0x2c08, 0x080c, 0x16a0, 0x6000, 0x9086, 0x0004, 0x1120,
+	0x2009, 0x0048, 0x080c, 0xad4d, 0x0005, 0x009e, 0x080c, 0x1ac5,
+	0x0804, 0xc6d4, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0d7d, 0x000b,
+	0x0005, 0xc761, 0xc680, 0xc763, 0xc761, 0xc763, 0xc763, 0xc67c,
+	0xc761, 0xc676, 0xc676, 0xc761, 0xc761, 0xc761, 0xc761, 0xc761,
+	0xc761, 0x080c, 0x0d7d, 0x6010, 0x00b6, 0x2058, 0xb804, 0x9084,
+	0x00ff, 0x00be, 0x908a, 0x000c, 0x1a0c, 0x0d7d, 0x00b6, 0x0013,
+	0x00be, 0x0005, 0xc77e, 0xc84b, 0xc780, 0xc7c0, 0xc780, 0xc7c0,
+	0xc780, 0xc78e, 0xc77e, 0xc7c0, 0xc77e, 0xc7af, 0x080c, 0x0d7d,
+	0x6004, 0x908e, 0x0016, 0x05c0, 0x908e, 0x0004, 0x05a8, 0x908e,
+	0x0002, 0x0590, 0x908e, 0x0052, 0x0904, 0xc847, 0x6004, 0x080c,
+	0xcb91, 0x0904, 0xc864, 0x908e, 0x0004, 0x1110, 0x080c, 0x326f,
+	0x908e, 0x0021, 0x0904, 0xc868, 0x908e, 0x0022, 0x0904, 0xc8af,
+	0x908e, 0x003d, 0x0904, 0xc868, 0x908e, 0x0039, 0x0904, 0xc86c,
+	0x908e, 0x0035, 0x0904, 0xc86c, 0x908e, 0x001e, 0x0178, 0x908e,
+	0x0001, 0x1140, 0x6010, 0x2058, 0xb804, 0x9084, 0x00ff, 0x9086,
+	0x0006, 0x0110, 0x080c, 0x3240, 0x080c, 0xb693, 0x0804, 0xaceb,
+	0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016, 0x0904, 0xc838, 0x9186,
+	0x0002, 0x1904, 0xc80d, 0x2001, 0x1837, 0x2004, 0xd08c, 0x11c8,
+	0x080c, 0x753d, 0x11b0, 0x080c, 0xd09b, 0x0138, 0x080c, 0x7560,
+	0x1120, 0x080c, 0x7448, 0x0804, 0xc898, 0x2001, 0x197c, 0x2003,
+	0x0001, 0x2001, 0x1800, 0x2003, 0x0001, 0x080c, 0x746e, 0x0804,
+	0xc898, 0x6010, 0x2058, 0x2001, 0x1837, 0x2004, 0xd0ac, 0x1904,
+	0xc898, 0xb8a0, 0x9084, 0xff80, 0x1904, 0xc898, 0xb840, 0x9084,
+	0x00ff, 0x9005, 0x0190, 0x8001, 0xb842, 0x6017, 0x0000, 0x6023,
+	0x0007, 0x601b, 0x0398, 0x604b, 0x0000, 0x080c, 0xac5a, 0x0128,
+	0x2b00, 0x6012, 0x6023, 0x0001, 0x0458, 0x00de, 0x00ce, 0x6004,
+	0x908e, 0x0002, 0x11a0, 0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e,
+	0x1170, 0x2009, 0x1837, 0x2104, 0xc085, 0x200a, 0x00e6, 0x2071,
+	0x1800, 0x080c, 0x6025, 0x00ee, 0x080c, 0xb693, 0x0030, 0x080c,
+	0xb693, 0x080c, 0x3240, 0x080c, 0xd0b0, 0x00e6, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x326f, 0x012e, 0x00ee, 0x080c, 0xaceb, 0x0005,
+	0x2001, 0x0002, 0x080c, 0x65e3, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x92b7, 0x080c, 0x9738, 0x00de, 0x00ce, 0x0c80, 0x080c,
+	0x326f, 0x0804, 0xc7bc, 0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016,
+	0x0d38, 0x6010, 0x2058, 0xb840, 0x9084, 0x00ff, 0x9005, 0x0904,
+	0xc80d, 0x8001, 0xb842, 0x6003, 0x0001, 0x080c, 0x92b7, 0x080c,
+	0x9738, 0x00de, 0x00ce, 0x0898, 0x080c, 0xb693, 0x0804, 0xc7be,
+	0x080c, 0xb6cf, 0x0804, 0xc7be, 0x00d6, 0x2c68, 0x6104, 0x080c,
+	0xd013, 0x00de, 0x0118, 0x080c, 0xacb0, 0x0408, 0x6004, 0x8007,
+	0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x6023, 0x0002, 0x603c, 0x600a, 0x2001, 0x1986, 0x2004,
+	0x601a, 0x602c, 0x2c08, 0x2060, 0x6024, 0xd0b4, 0x0108, 0xc085,
+	0xc0b5, 0x6026, 0x2160, 0x2009, 0x8020, 0x080c, 0x92b0, 0x0005,
+	0x00de, 0x00ce, 0x080c, 0xb693, 0x080c, 0x3240, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x326f, 0x6017, 0x0000, 0x6023, 0x0007,
+	0x601b, 0x0398, 0x604b, 0x0000, 0x012e, 0x00ee, 0x0005, 0x080c,
+	0xb0eb, 0x1904, 0xc864, 0x0005, 0x6000, 0x908a, 0x0016, 0x1a0c,
+	0x0d7d, 0x0096, 0x00d6, 0x001b, 0x00de, 0x009e, 0x0005, 0xc8cf,
+	0xc8cf, 0xc8cf, 0xc8cf, 0xc8cf, 0xc8cf, 0xc8cf, 0xc8cf, 0xc8cf,
+	0xc67b, 0xc8cf, 0xc680, 0xc8d1, 0xc680, 0xc8eb, 0xc8cf, 0x080c,
+	0x0d7d, 0x6004, 0x9086, 0x008b, 0x01b0, 0x6034, 0x908c, 0xff00,
+	0x810f, 0x9186, 0x0035, 0x1130, 0x602c, 0x9080, 0x0009, 0x200c,
+	0xc185, 0x2102, 0x6007, 0x008b, 0x6003, 0x000d, 0x2009, 0x8020,
+	0x080c, 0x92b0, 0x0005, 0x080c, 0xd08f, 0x0118, 0x080c, 0xd0a2,
+	0x0010, 0x080c, 0xd0b0, 0x080c, 0xcb6b, 0x080c, 0xc97a, 0x0570,
+	0x080c, 0x3240, 0x080c, 0xc97a, 0x0168, 0x6014, 0x2048, 0xa867,
+	0x0103, 0xa87b, 0x0006, 0xa877, 0x0000, 0xa880, 0xc0ed, 0xa882,
+	0x080c, 0x6dee, 0x2c68, 0x080c, 0xac5a, 0x0150, 0x6810, 0x6012,
+	0x080c, 0xce15, 0x00c6, 0x2d60, 0x080c, 0xaceb, 0x00ce, 0x0008,
+	0x2d60, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001, 0x6003,
+	0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x00c8, 0x080c, 0xd08f,
+	0x0138, 0x6034, 0x9086, 0x4000, 0x1118, 0x080c, 0x3240, 0x08d0,
+	0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118, 0x9186,
+	0x0035, 0x1118, 0x080c, 0x3240, 0x0868, 0x080c, 0xaceb, 0x0005,
+	0x6000, 0x908a, 0x0016, 0x1a0c, 0x0d7d, 0x0002, 0xc956, 0xc956,
+	0xc958, 0xc958, 0xc958, 0xc956, 0xc956, 0xaceb, 0xc956, 0xc956,
+	0xc956, 0xc956, 0xc956, 0xc956, 0xc956, 0xc956, 0x080c, 0x0d7d,
+	0x080c, 0xa91e, 0x080c, 0xaab5, 0x080c, 0xa93a, 0x6114, 0x0096,
+	0x2148, 0xa87b, 0x0006, 0x080c, 0x6dee, 0x009e, 0x0804, 0xacb0,
+	0x9284, 0x0003, 0x1158, 0x9282, 0x1ddc, 0x0240, 0x2001, 0x181a,
+	0x2004, 0x9202, 0x1218, 0x9085, 0x0001, 0x0005, 0x9006, 0x0ce8,
+	0x0096, 0x0028, 0x0096, 0x0006, 0x6014, 0x2048, 0x000e, 0x0006,
+	0x9984, 0xf000, 0x9086, 0xf000, 0x0110, 0x080c, 0x10f2, 0x000e,
+	0x009e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2061, 0x1ddc, 0x2071, 0x1800, 0x7354, 0x7074, 0x9302,
+	0x1640, 0x6020, 0x9206, 0x11f8, 0x080c, 0xd09b, 0x0180, 0x9286,
+	0x0001, 0x1168, 0x6004, 0x9086, 0x0004, 0x1148, 0x080c, 0x3240,
+	0x080c, 0xd0b0, 0x00c6, 0x080c, 0xaceb, 0x00ce, 0x0060, 0x080c,
+	0xcd87, 0x0148, 0x080c, 0xcb91, 0x1110, 0x080c, 0xb693, 0x00c6,
+	0x080c, 0xacb0, 0x00ce, 0x9ce0, 0x001c, 0x7068, 0x9c02, 0x1208,
+	0x08a0, 0x012e, 0x000e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6,
+	0x00c6, 0x0016, 0x9188, 0x1000, 0x210c, 0x81ff, 0x0128, 0x2061,
+	0x1b34, 0x6112, 0x080c, 0x3240, 0x9006, 0x0010, 0x9085, 0x0001,
+	0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xac5a, 0x01b0, 0x665e, 0x2b00, 0x6012, 0x080c, 0x5746,
+	0x0118, 0x080c, 0xcaad, 0x0168, 0x080c, 0xce15, 0x6023, 0x0003,
+	0x2009, 0x004b, 0x080c, 0xad4d, 0x9085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0xbaa0,
+	0x080c, 0xad20, 0x0580, 0x605f, 0x0000, 0x2b00, 0x6012, 0x080c,
+	0xce15, 0x6023, 0x0003, 0x0016, 0x080c, 0xa91e, 0x080c, 0x943d,
+	0x0076, 0x903e, 0x080c, 0x9306, 0x2c08, 0x080c, 0xe167, 0x007e,
+	0x080c, 0xa93a, 0x001e, 0xd184, 0x0128, 0x080c, 0xacb0, 0x9085,
+	0x0001, 0x0070, 0x080c, 0x5746, 0x0128, 0xd18c, 0x1170, 0x080c,
+	0xcaad, 0x0148, 0x2009, 0x004c, 0x080c, 0xad4d, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2900, 0x6016, 0x0c90,
+	0x2009, 0x004d, 0x0010, 0x2009, 0x004e, 0x00f6, 0x00c6, 0x0046,
+	0x0016, 0x080c, 0xac5a, 0x2c78, 0x05a0, 0x7e5e, 0x2b00, 0x7812,
+	0x7823, 0x0003, 0x0016, 0x2021, 0x0005, 0x080c, 0xcabf, 0x001e,
+	0x9186, 0x004d, 0x0118, 0x9186, 0x004e, 0x0148, 0x2001, 0x197f,
+	0x200c, 0xd1fc, 0x0168, 0x2f60, 0x080c, 0xacb0, 0x00d0, 0x2001,
+	0x197e, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xacb0, 0x0088,
+	0x2f60, 0x080c, 0x5746, 0x0138, 0xd18c, 0x1118, 0x04f1, 0x0148,
+	0x0010, 0x2900, 0x7816, 0x001e, 0x0016, 0x080c, 0xad4d, 0x9085,
+	0x0001, 0x001e, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6,
+	0x0046, 0x080c, 0xac5a, 0x2c78, 0x0508, 0x7e5e, 0x2b00, 0x7812,
+	0x7823, 0x0003, 0x0096, 0x2021, 0x0004, 0x0489, 0x009e, 0x2001,
+	0x197d, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xacb0, 0x0060,
+	0x2f60, 0x080c, 0x5746, 0x0120, 0xd18c, 0x1160, 0x0071, 0x0130,
+	0x2009, 0x0052, 0x080c, 0xad4d, 0x9085, 0x0001, 0x004e, 0x00ce,
+	0x00fe, 0x0005, 0x2900, 0x7816, 0x0c98, 0x00c6, 0x080c, 0x4af2,
+	0x00ce, 0x1120, 0x080c, 0xacb0, 0x9006, 0x0005, 0xa867, 0x0000,
+	0xa86b, 0x8000, 0x2900, 0x6016, 0x9085, 0x0001, 0x0005, 0x0096,
+	0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0xa91e, 0x080c, 0x6875,
+	0x0158, 0x2001, 0xcac6, 0x0006, 0x900e, 0x2400, 0x080c, 0x7022,
+	0x080c, 0x6dee, 0x000e, 0x0807, 0x2418, 0x080c, 0x9640, 0xbaa0,
+	0x0086, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x080c, 0x9457,
+	0x008e, 0x080c, 0x9306, 0x2f08, 0x2648, 0x080c, 0xe167, 0xb93c,
+	0x81ff, 0x090c, 0x9530, 0x080c, 0xa93a, 0x012e, 0x007e, 0x009e,
+	0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xac5a, 0x0190,
+	0x660a, 0x2b08, 0x6112, 0x080c, 0xce15, 0x6023, 0x0001, 0x2900,
+	0x6016, 0x2009, 0x001f, 0x080c, 0xad4d, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xad20, 0x01b8, 0x660a, 0x2b08, 0x6112, 0x080c, 0xce15,
+	0x6023, 0x0008, 0x2900, 0x6016, 0x00f6, 0x2c78, 0x080c, 0x1778,
+	0x00fe, 0x2009, 0x0021, 0x080c, 0xad4d, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2009, 0x003d, 0x00c6, 0x0126,
+	0x0016, 0x2091, 0x8000, 0x080c, 0xac5a, 0x0198, 0x660a, 0x2b08,
+	0x6112, 0x080c, 0xce15, 0x6023, 0x0001, 0x2900, 0x6016, 0x001e,
+	0x0016, 0x080c, 0xad4d, 0x9085, 0x0001, 0x001e, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd0, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c,
+	0xad20, 0x0188, 0x2b08, 0x6112, 0x080c, 0xce15, 0x6023, 0x0001,
+	0x2900, 0x6016, 0x2009, 0x0000, 0x080c, 0xad4d, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2009, 0x0044, 0x0830,
+	0x2009, 0x0049, 0x0818, 0x0026, 0x00b6, 0x6210, 0x2258, 0xba3c,
+	0x82ff, 0x0118, 0x8211, 0xba3e, 0x1140, 0xb8d0, 0x9005, 0x0128,
+	0xb888, 0x9005, 0x1110, 0xb88b, 0x0001, 0x00be, 0x002e, 0x0005,
+	0x0006, 0x0016, 0x6004, 0x908e, 0x0002, 0x0140, 0x908e, 0x0003,
+	0x0128, 0x908e, 0x0004, 0x0110, 0x9085, 0x0001, 0x001e, 0x000e,
+	0x0005, 0x0006, 0x0086, 0x0096, 0x6020, 0x9086, 0x0004, 0x01a8,
+	0x6014, 0x904d, 0x080c, 0xc97a, 0x0180, 0xa864, 0x9086, 0x0139,
+	0x0170, 0x6020, 0x90c6, 0x0003, 0x0140, 0x90c6, 0x0002, 0x0128,
+	0xa868, 0xd0fc, 0x0110, 0x9006, 0x0010, 0x9085, 0x0001, 0x009e,
+	0x008e, 0x000e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c,
+	0xad20, 0x0198, 0x2b08, 0x6112, 0x080c, 0xce15, 0x6023, 0x0001,
+	0x2900, 0x6016, 0x080c, 0x3240, 0x2009, 0x0028, 0x080c, 0xad4d,
+	0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x9186,
+	0x0015, 0x11a8, 0x2011, 0x1824, 0x2204, 0x9086, 0x0074, 0x1178,
+	0x00b6, 0x080c, 0xb8e7, 0x00be, 0x080c, 0xbb0a, 0x6003, 0x0001,
+	0x6007, 0x0029, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0078, 0x6014,
+	0x0096, 0x2048, 0xa868, 0x009e, 0xd0fc, 0x0148, 0x2001, 0x0001,
+	0x080c, 0xcfd4, 0x080c, 0xb693, 0x080c, 0xacb0, 0x0005, 0x0096,
+	0x6014, 0x904d, 0x090c, 0x0d7d, 0xa87b, 0x0030, 0xa883, 0x0000,
+	0xa897, 0x4005, 0xa89b, 0x0004, 0xa867, 0x0139, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6dee, 0x012e, 0x009e, 0x080c, 0xacb0, 0x0c30,
+	0x0096, 0x9186, 0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x65e3,
+	0x00e8, 0x9186, 0x0015, 0x1510, 0x2011, 0x1824, 0x2204, 0x9086,
+	0x0014, 0x11e0, 0x6010, 0x00b6, 0x2058, 0x080c, 0x672e, 0x00be,
+	0x080c, 0xbbdb, 0x1198, 0x6010, 0x00b6, 0x2058, 0xb890, 0x00be,
+	0x9005, 0x0160, 0x2001, 0x0006, 0x080c, 0x65e3, 0x6014, 0x2048,
+	0xa868, 0xd0fc, 0x0170, 0x080c, 0xb0bf, 0x0048, 0x6014, 0x2048,
+	0xa868, 0xd0fc, 0x0528, 0x080c, 0xb693, 0x080c, 0xacb0, 0x009e,
+	0x0005, 0x6014, 0x6310, 0x2358, 0x904d, 0x090c, 0x0d7d, 0xa87b,
+	0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x900e, 0x080c, 0x6986,
+	0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0xa99a, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x6dee, 0x012e, 0x080c, 0xacb0, 0x08f8,
+	0x6014, 0x904d, 0x090c, 0x0d7d, 0xa87b, 0x0030, 0xa883, 0x0000,
+	0xa897, 0x4005, 0xa89b, 0x0004, 0xa867, 0x0139, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6dee, 0x012e, 0x080c, 0xacb0, 0x0840, 0xa878,
+	0x9086, 0x0005, 0x1108, 0x0009, 0x0005, 0xa880, 0xc0ad, 0xa882,
+	0x0005, 0x604b, 0x0000, 0x6017, 0x0000, 0x6003, 0x0001, 0x6007,
+	0x0050, 0x2009, 0x8023, 0x080c, 0x92b0, 0x0005, 0x00c6, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0130, 0x0066, 0x6020,
+	0x9084, 0x000f, 0x001b, 0x006e, 0x00ce, 0x0005, 0xc67b, 0xccb8,
+	0xccb8, 0xccbb, 0xe494, 0xe4af, 0xe4b2, 0xc67b, 0xc67b, 0xc67b,
+	0xc67b, 0xc67b, 0xc67b, 0xc67b, 0xc67b, 0xc67b, 0x080c, 0x0d7d,
+	0xa001, 0xa001, 0x0005, 0x0096, 0x6014, 0x904d, 0x0118, 0xa87c,
+	0xd0e4, 0x1110, 0x009e, 0x0010, 0x009e, 0x0005, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x0550, 0x2001, 0x1834, 0x2004,
+	0x9005, 0x1540, 0x00f6, 0x2c78, 0x080c, 0xac5a, 0x0508, 0x7810,
+	0x6012, 0x080c, 0xce15, 0x7820, 0x9086, 0x0003, 0x0128, 0x7808,
+	0x603a, 0x2f00, 0x603e, 0x0020, 0x7808, 0x603e, 0x2f00, 0x603a,
+	0x602e, 0x6023, 0x0001, 0x6007, 0x0035, 0x6003, 0x0001, 0x795c,
+	0x615e, 0x2009, 0x8020, 0x080c, 0x92b0, 0x2f60, 0x00fe, 0x0005,
+	0x2f60, 0x00fe, 0x2001, 0x1987, 0x2004, 0x604a, 0x0005, 0x0016,
+	0x0096, 0x6814, 0x2048, 0x681c, 0xd0fc, 0xc0fc, 0x681e, 0xa87c,
+	0x1108, 0xd0e4, 0x0180, 0xc0e4, 0xa87e, 0xa877, 0x0000, 0xa893,
+	0x0000, 0xa88f, 0x0000, 0xd0cc, 0x0130, 0xc0cc, 0xa87e, 0xa878,
+	0x2048, 0x080c, 0x0ff9, 0x6830, 0x6036, 0x908e, 0x0001, 0x0148,
+	0x6803, 0x0002, 0x9086, 0x0005, 0x0170, 0x9006, 0x602e, 0x6032,
+	0x00d0, 0x681c, 0xc085, 0x681e, 0x6803, 0x0004, 0x6824, 0xc0f4,
+	0x9085, 0x0c00, 0x6826, 0x6814, 0x2048, 0xa8ac, 0x6938, 0x9102,
+	0xa8b0, 0x693c, 0x9103, 0x1e48, 0x683c, 0x602e, 0x6838, 0x9084,
+	0xfffc, 0x683a, 0x6032, 0x2d00, 0x603a, 0x6808, 0x603e, 0x6910,
+	0x6112, 0x695c, 0x615e, 0x6023, 0x0001, 0x6007, 0x0039, 0x6003,
+	0x0001, 0x2009, 0x8020, 0x080c, 0x92b0, 0x009e, 0x001e, 0x0005,
+	0x6024, 0xd0d4, 0x0510, 0xd0f4, 0x11f8, 0x6038, 0x940a, 0x603c,
+	0x9303, 0x0230, 0x9105, 0x0120, 0x6024, 0xc0d4, 0xc0f5, 0x0098,
+	0x643a, 0x633e, 0xac3e, 0xab42, 0x0046, 0x0036, 0x2400, 0xacac,
+	0x9402, 0xa836, 0x2300, 0xabb0, 0x9303, 0xa83a, 0x003e, 0x004e,
+	0x6024, 0xc0d4, 0x0000, 0x6026, 0x0005, 0xd0f4, 0x1138, 0xa83c,
+	0x603a, 0xa840, 0x603e, 0x6024, 0xc0f5, 0x6026, 0x0005, 0x0006,
+	0x0016, 0x6004, 0x908e, 0x0034, 0x01b8, 0x908e, 0x0035, 0x01a0,
+	0x908e, 0x0036, 0x0188, 0x908e, 0x0037, 0x0170, 0x908e, 0x0038,
+	0x0158, 0x908e, 0x0039, 0x0140, 0x908e, 0x003a, 0x0128, 0x908e,
+	0x003b, 0x0110, 0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006,
+	0x0016, 0x0026, 0x0036, 0x00e6, 0x2001, 0x1981, 0x200c, 0x8000,
+	0x2014, 0x2001, 0x0032, 0x080c, 0x91f8, 0x2001, 0x1985, 0x82ff,
+	0x1110, 0x2011, 0x0014, 0x2202, 0x2001, 0x1983, 0x200c, 0x8000,
+	0x2014, 0x2071, 0x196b, 0x711a, 0x721e, 0x2001, 0x0064, 0x080c,
+	0x91f8, 0x2001, 0x1986, 0x82ff, 0x1110, 0x2011, 0x0014, 0x2202,
+	0x2001, 0x1987, 0x9288, 0x000a, 0x2102, 0x2001, 0x0017, 0x080c,
+	0xa90f, 0x2001, 0x1a8b, 0x2102, 0x2001, 0x0032, 0x080c, 0x16a0,
+	0x080c, 0x6abe, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x0006, 0x0016, 0x00e6, 0x2001, 0x1985, 0x2003, 0x0028, 0x2001,
+	0x1986, 0x2003, 0x0014, 0x2071, 0x196b, 0x701b, 0x0000, 0x701f,
+	0x07d0, 0x2001, 0x1987, 0x2009, 0x001e, 0x2102, 0x2001, 0x0017,
+	0x080c, 0xa90f, 0x2001, 0x1a8b, 0x2102, 0x2001, 0x0032, 0x080c,
+	0x16a0, 0x00ee, 0x001e, 0x000e, 0x0005, 0x0096, 0x6060, 0x904d,
+	0x0110, 0x080c, 0x1079, 0x009e, 0x0005, 0x0005, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x080c, 0xac5a, 0x0180, 0x2b08, 0x6112, 0x0ca9,
+	0x6023, 0x0001, 0x2900, 0x6016, 0x2009, 0x0033, 0x080c, 0xad4d,
+	0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x0096,
+	0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x1500, 0x7090,
+	0x9086, 0x0018, 0x11e0, 0x6014, 0x2048, 0xaa3c, 0xd2e4, 0x1160,
+	0x2c78, 0x080c, 0x97f7, 0x01d8, 0x707c, 0xaa50, 0x9206, 0x1160,
+	0x7080, 0xaa54, 0x9206, 0x1140, 0x6210, 0x00b6, 0x2258, 0xbaa0,
+	0x00be, 0x900e, 0x080c, 0x328f, 0x080c, 0xb0bf, 0x0020, 0x080c,
+	0xb693, 0x080c, 0xacb0, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x7060,
+	0xaa54, 0x9206, 0x0d48, 0x0c80, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xac5a, 0x0188, 0x2b08, 0x6112, 0x080c, 0xce15, 0x6023,
+	0x0001, 0x2900, 0x6016, 0x2009, 0x004d, 0x080c, 0xad4d, 0x9085,
+	0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x0016, 0x080c, 0xac5a, 0x0180, 0x2b08, 0x6112,
+	0x080c, 0xce15, 0x6023, 0x0001, 0x2900, 0x6016, 0x001e, 0x080c,
+	0xad4d, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x001e, 0x9006,
+	0x0cd0, 0x0016, 0x0026, 0x0036, 0x0046, 0x0056, 0x0066, 0x0096,
+	0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x1568, 0x7190,
+	0x6014, 0x2048, 0xa814, 0x8003, 0x9106, 0x1530, 0x20e1, 0x0000,
+	0x2001, 0x199f, 0x2003, 0x0000, 0x6014, 0x2048, 0xa830, 0x20a8,
+	0x8906, 0x8006, 0x8007, 0x9094, 0x003f, 0x22e8, 0x9084, 0xffc0,
+	0x9080, 0x001b, 0x20a0, 0x2001, 0x199f, 0x0016, 0x200c, 0x080c,
+	0xd6df, 0x001e, 0xa804, 0x9005, 0x0110, 0x2048, 0x0c38, 0x6014,
+	0x2048, 0xa867, 0x0103, 0x0010, 0x080c, 0xb693, 0x080c, 0xacb0,
+	0x00fe, 0x00ee, 0x009e, 0x006e, 0x005e, 0x004e, 0x003e, 0x002e,
+	0x001e, 0x0005, 0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186,
+	0x0015, 0x11b8, 0x7090, 0x9086, 0x0004, 0x1198, 0x6014, 0x2048,
+	0x2c78, 0x080c, 0x97f7, 0x01a8, 0x707c, 0xaa74, 0x9206, 0x1130,
+	0x7080, 0xaa78, 0x9206, 0x1110, 0x080c, 0x3240, 0x080c, 0xb0bf,
+	0x0020, 0x080c, 0xb693, 0x080c, 0xacb0, 0x00fe, 0x00ee, 0x009e,
+	0x0005, 0x7060, 0xaa78, 0x9206, 0x0d78, 0x0c80, 0x0096, 0x00e6,
+	0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x1550, 0x7090, 0x9086,
+	0x0004, 0x1530, 0x6014, 0x2048, 0x2c78, 0x080c, 0x97f7, 0x05f0,
+	0x707c, 0xaacc, 0x9206, 0x1180, 0x7080, 0xaad0, 0x9206, 0x1160,
+	0x080c, 0x3240, 0x0016, 0xa998, 0xaab0, 0x9284, 0x1000, 0xc0fd,
+	0x080c, 0x56e7, 0x001e, 0x0010, 0x080c, 0x54ca, 0x080c, 0xc97a,
+	0x0508, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x0080,
+	0x080c, 0xc97a, 0x01b8, 0x6014, 0x2048, 0x080c, 0x54ca, 0x1d70,
+	0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005, 0xa89b, 0x0004,
+	0x0126, 0x2091, 0x8000, 0xa867, 0x0139, 0x080c, 0x6dee, 0x012e,
+	0x080c, 0xacb0, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x7060, 0xaad0,
+	0x9206, 0x0930, 0x0888, 0x0016, 0x0026, 0xa87c, 0xd0ac, 0x0178,
+	0xa938, 0xaa34, 0x2100, 0x9205, 0x0150, 0xa890, 0x9106, 0x1118,
+	0xa88c, 0x9206, 0x0120, 0xa992, 0xaa8e, 0x9085, 0x0001, 0x002e,
+	0x001e, 0x0005, 0x00b6, 0x00d6, 0x0036, 0x080c, 0xc97a, 0x0904,
+	0xcfd0, 0x0096, 0x6314, 0x2348, 0xa87a, 0xa982, 0x929e, 0x4000,
+	0x1580, 0x6310, 0x00c6, 0x2358, 0x2009, 0x0000, 0xa868, 0xd0f4,
+	0x1140, 0x080c, 0x6986, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108,
+	0xc18d, 0xaa96, 0xa99a, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0031, 0x20a0, 0xb8c4, 0x20e0, 0xb8c8, 0x9080, 0x0006,
+	0x2098, 0x080c, 0x0fc4, 0x20a9, 0x0004, 0xa85c, 0x9080, 0x0035,
+	0x20a0, 0xb8c8, 0x9080, 0x000a, 0x2098, 0x080c, 0x0fc4, 0x00ce,
+	0x0090, 0xaa96, 0x3918, 0x9398, 0x0007, 0x231c, 0x6004, 0x9086,
+	0x0016, 0x0110, 0xa89b, 0x0004, 0xaba2, 0x6310, 0x2358, 0xb804,
+	0x9084, 0x00ff, 0xa89e, 0x080c, 0x6de2, 0x6017, 0x0000, 0x009e,
+	0x003e, 0x00de, 0x00be, 0x0005, 0x0026, 0x0036, 0x0046, 0x00b6,
+	0x0096, 0x00f6, 0x6214, 0x2248, 0x6210, 0x2258, 0x2079, 0x0260,
+	0x9096, 0x0000, 0x11a0, 0xb814, 0x9084, 0x00ff, 0x900e, 0x080c,
+	0x2661, 0x2118, 0x831f, 0x939c, 0xff00, 0x7838, 0x9084, 0x00ff,
+	0x931d, 0x7c3c, 0x2011, 0x8018, 0x080c, 0x4b52, 0x00a8, 0x9096,
+	0x0001, 0x1148, 0x89ff, 0x0180, 0xa89b, 0x000d, 0x7838, 0xa8a6,
+	0x783c, 0xa8aa, 0x0048, 0x9096, 0x0002, 0x1130, 0xa89b, 0x000d,
+	0x7838, 0xa8a6, 0x783c, 0xa8aa, 0x00fe, 0x009e, 0x00be, 0x004e,
+	0x003e, 0x002e, 0x0005, 0x00c6, 0x0026, 0x0016, 0x9186, 0x0035,
+	0x0110, 0x6a38, 0x0008, 0x6a2c, 0x080c, 0xc968, 0x01f0, 0x2260,
+	0x6120, 0x9186, 0x0003, 0x0118, 0x9186, 0x0006, 0x1190, 0x6838,
+	0x9206, 0x0140, 0x683c, 0x9206, 0x1160, 0x6108, 0x6838, 0x9106,
+	0x1140, 0x0020, 0x6008, 0x693c, 0x9106, 0x1118, 0x6010, 0x6910,
+	0x9106, 0x001e, 0x002e, 0x00ce, 0x0005, 0x9085, 0x0001, 0x0cc8,
+	0xa974, 0xd1cc, 0x0188, 0x918c, 0x00ff, 0x918e, 0x0002, 0x1160,
+	0xa9a8, 0x918c, 0x0f00, 0x810f, 0x918e, 0x0001, 0x1128, 0xa834,
+	0xa938, 0x9115, 0x190c, 0xbf96, 0x0005, 0x0036, 0x2019, 0x0001,
+	0x0010, 0x0036, 0x901e, 0x0499, 0x01e0, 0x080c, 0xc97a, 0x01c8,
+	0x080c, 0xcb6b, 0x6037, 0x4000, 0x6014, 0x6017, 0x0000, 0x0096,
+	0x2048, 0xa87c, 0x080c, 0xcb91, 0x1118, 0x080c, 0xb693, 0x0040,
+	0xa867, 0x0103, 0xa877, 0x0000, 0x83ff, 0x1129, 0x080c, 0x6dee,
+	0x009e, 0x003e, 0x0005, 0xa880, 0xd0b4, 0x0128, 0xa87b, 0x0006,
+	0xc0ec, 0xa882, 0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020,
+	0xa87b, 0x0005, 0x080c, 0xcc85, 0xa877, 0x0000, 0x0005, 0x2001,
+	0x1810, 0x2004, 0xd0ec, 0x0005, 0x0006, 0x2001, 0x1810, 0x2004,
+	0xd0f4, 0x000e, 0x0005, 0x0006, 0x2001, 0x1810, 0x2004, 0xd0e4,
+	0x000e, 0x0005, 0x0036, 0x0046, 0x6010, 0x00b6, 0x2058, 0xbba0,
+	0x00be, 0x2021, 0x0007, 0x080c, 0x4d09, 0x004e, 0x003e, 0x0005,
+	0x0c51, 0x1d81, 0x0005, 0x2001, 0x1985, 0x2004, 0x601a, 0x0005,
+	0x2001, 0x1987, 0x2004, 0x604a, 0x0005, 0x080c, 0xacb0, 0x0804,
+	0x9738, 0x611c, 0xd1fc, 0xa97c, 0x1108, 0xd1e4, 0x0005, 0x601c,
+	0xd0fc, 0xa87c, 0x1108, 0xd0e4, 0x0005, 0x601c, 0xd0fc, 0xc0fc,
+	0x601e, 0xa87c, 0x1108, 0xd0e4, 0x0005, 0x6044, 0xd0fc, 0x1138,
+	0xd0bc, 0x0198, 0xc0bc, 0x6046, 0x6003, 0x0002, 0x0070, 0xd0ac,
+	0x1160, 0xd0dc, 0x1128, 0x908c, 0x000f, 0x9186, 0x0005, 0x1118,
+	0x6003, 0x0003, 0x0010, 0x6003, 0x0001, 0x0005, 0x00b6, 0x0066,
+	0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0d7d, 0x001b, 0x006e, 0x00be,
+	0x0005, 0xd109, 0xd83a, 0xd98b, 0xd109, 0xd109, 0xd109, 0xd109,
+	0xd109, 0xd140, 0xda0f, 0xd109, 0xd109, 0xd109, 0xd109, 0xd109,
+	0xd109, 0x080c, 0x0d7d, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c,
+	0x0d7d, 0x0013, 0x006e, 0x0005, 0xd124, 0xdf30, 0xd124, 0xd124,
+	0xd124, 0xd124, 0xd124, 0xd124, 0xdedf, 0xdf82, 0xd124, 0xe5cf,
+	0xe603, 0xe5cf, 0xe603, 0xd124, 0x080c, 0x0d7d, 0x6000, 0x9082,
+	0x0016, 0x1a0c, 0x0d7d, 0x6000, 0x000a, 0x0005, 0xd13e, 0xdbec,
+	0xdcb7, 0xdcda, 0xdd56, 0xd13e, 0xde51, 0xddde, 0xda19, 0xdeb7,
+	0xdecc, 0xd13e, 0xd13e, 0xd13e, 0xd13e, 0xd13e, 0x080c, 0x0d7d,
+	0x91b2, 0x0053, 0x1a0c, 0x0d7d, 0x2100, 0x91b2, 0x0040, 0x1a04,
+	0xd5b0, 0x0002, 0xd18a, 0xd37e, 0xd18a, 0xd18a, 0xd18a, 0xd387,
+	0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a,
+	0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a,
+	0xd18a, 0xd18c, 0xd1f3, 0xd202, 0xd266, 0xd291, 0xd30a, 0xd369,
+	0xd18a, 0xd18a, 0xd38a, 0xd18a, 0xd18a, 0xd39f, 0xd3ac, 0xd18a,
+	0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd452, 0xd18a, 0xd18a, 0xd466,
+	0xd18a, 0xd18a, 0xd421, 0xd18a, 0xd18a, 0xd18a, 0xd47e, 0xd18a,
+	0xd18a, 0xd18a, 0xd4fb, 0xd18a, 0xd18a, 0xd18a, 0xd18a, 0xd18a,
+	0xd18a, 0xd578, 0x080c, 0x0d7d, 0x080c, 0x6a9b, 0x1150, 0x2001,
+	0x1837, 0x2004, 0xd0cc, 0x1128, 0x9084, 0x0009, 0x9086, 0x0008,
+	0x1140, 0x6007, 0x0009, 0x602f, 0x0009, 0x6017, 0x0000, 0x0804,
+	0xd377, 0x080c, 0x6a37, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016,
+	0x6210, 0x2258, 0xbaa0, 0x0026, 0x2019, 0x0029, 0x080c, 0xa91e,
+	0x080c, 0x943d, 0x0076, 0x903e, 0x080c, 0x9306, 0x2c08, 0x080c,
+	0xe167, 0x007e, 0x001e, 0x080c, 0xa93a, 0x001e, 0x002e, 0x003e,
+	0x00ce, 0x00ee, 0x6610, 0x2658, 0x080c, 0x66a2, 0xbe04, 0x9684,
+	0x00ff, 0x9082, 0x0006, 0x1268, 0x0016, 0x0026, 0x6210, 0x00b6,
+	0x2258, 0xbaa0, 0x00be, 0x2c08, 0x080c, 0xe82c, 0x002e, 0x001e,
+	0x1178, 0x080c, 0xe095, 0x1904, 0xd25e, 0x080c, 0xe031, 0x1120,
+	0x6007, 0x0008, 0x0804, 0xd377, 0x6007, 0x0009, 0x0804, 0xd377,
+	0x080c, 0xe2c8, 0x0128, 0x080c, 0xe095, 0x0d78, 0x0804, 0xd25e,
+	0x6017, 0x1900, 0x0c88, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x6106,
+	0x080c, 0xdfe2, 0x6007, 0x0006, 0x0804, 0xd377, 0x6007, 0x0007,
+	0x0804, 0xd377, 0x080c, 0xe63f, 0x1904, 0xd5ad, 0x080c, 0x3377,
+	0x1904, 0xd5ad, 0x00d6, 0x6610, 0x2658, 0xbe04, 0x9684, 0x00ff,
+	0x9082, 0x0006, 0x1220, 0x2001, 0x0001, 0x080c, 0x65cf, 0x96b4,
+	0xff00, 0x8637, 0x9686, 0x0006, 0x0188, 0x9686, 0x0004, 0x0170,
+	0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, 0x0140, 0x9686, 0x0004,
+	0x0128, 0x9686, 0x0005, 0x0110, 0x00de, 0x0480, 0x00e6, 0x2071,
+	0x0260, 0x7034, 0x9084, 0x0003, 0x1140, 0x7034, 0x9082, 0x0014,
+	0x0220, 0x7030, 0x9084, 0x0003, 0x0130, 0x00ee, 0x6017, 0x0000,
+	0x602f, 0x0007, 0x00b0, 0x00ee, 0x080c, 0xe0fd, 0x1190, 0x9686,
+	0x0006, 0x1140, 0x0026, 0x6210, 0x2258, 0xbaa0, 0x900e, 0x080c,
+	0x328f, 0x002e, 0x080c, 0x672e, 0x6007, 0x000a, 0x00de, 0x0804,
+	0xd377, 0x6007, 0x000b, 0x00de, 0x0804, 0xd377, 0x080c, 0x3240,
+	0x080c, 0xd0b0, 0x6007, 0x0001, 0x0804, 0xd377, 0x080c, 0xe63f,
+	0x1904, 0xd5ad, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x2071, 0x0260,
+	0x7034, 0x90b4, 0x0003, 0x1948, 0x90b2, 0x0014, 0x0a30, 0x7030,
+	0x9084, 0x0003, 0x1910, 0x6610, 0x2658, 0xbe04, 0x9686, 0x0707,
+	0x09e8, 0x0026, 0x6210, 0x2258, 0xbaa0, 0x900e, 0x080c, 0x328f,
+	0x002e, 0x6007, 0x000c, 0x2001, 0x0001, 0x080c, 0xe80c, 0x0804,
+	0xd377, 0x080c, 0x6a9b, 0x1140, 0x2001, 0x1837, 0x2004, 0x9084,
+	0x0009, 0x9086, 0x0008, 0x1110, 0x0804, 0xd199, 0x080c, 0x6a37,
+	0x6610, 0x2658, 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006, 0x06c8,
+	0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x660f, 0x002e, 0x0050,
+	0x96b4, 0xff00, 0x8637, 0x9686, 0x0004, 0x0120, 0x9686, 0x0006,
+	0x1904, 0xd25e, 0x080c, 0xe10a, 0x1120, 0x6007, 0x000e, 0x0804,
+	0xd377, 0x0046, 0x6410, 0x2458, 0xbca0, 0x0046, 0x080c, 0x3240,
+	0x080c, 0xd0b0, 0x004e, 0x0016, 0x9006, 0x2009, 0x1848, 0x210c,
+	0xd1a4, 0x0148, 0x2009, 0x0029, 0x080c, 0xe445, 0x6010, 0x2058,
+	0xb800, 0xc0e5, 0xb802, 0x001e, 0x004e, 0x6007, 0x0001, 0x0804,
+	0xd377, 0x2001, 0x0001, 0x080c, 0x65cf, 0x0156, 0x0016, 0x0026,
+	0x0036, 0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0270, 0x080c,
+	0xbc8e, 0x003e, 0x002e, 0x001e, 0x015e, 0x9005, 0x0168, 0x96b4,
+	0xff00, 0x8637, 0x9682, 0x0004, 0x0a04, 0xd25e, 0x9682, 0x0007,
+	0x0a04, 0xd2ba, 0x0804, 0xd25e, 0x6017, 0x1900, 0x6007, 0x0009,
+	0x0804, 0xd377, 0x080c, 0x6a9b, 0x1140, 0x2001, 0x1837, 0x2004,
+	0x9084, 0x0009, 0x9086, 0x0008, 0x1110, 0x0804, 0xd199, 0x080c,
+	0x6a37, 0x6610, 0x2658, 0xbe04, 0x9684, 0x00ff, 0x0006, 0x9086,
+	0x0001, 0x000e, 0x0170, 0x9082, 0x0006, 0x0698, 0x0150, 0x96b4,
+	0xff00, 0x8637, 0x9686, 0x0004, 0x0120, 0x9686, 0x0006, 0x1904,
+	0xd25e, 0x080c, 0xe138, 0x1130, 0x080c, 0xe031, 0x1118, 0x6007,
+	0x0010, 0x04e8, 0x0046, 0x6410, 0x2458, 0xbca0, 0x0046, 0x080c,
+	0x3240, 0x080c, 0xd0b0, 0x004e, 0x0016, 0x9006, 0x2009, 0x1848,
+	0x210c, 0xd1a4, 0x0148, 0x2009, 0x0029, 0x080c, 0xe445, 0x6010,
+	0x2058, 0xb800, 0xc0e5, 0xb802, 0x001e, 0x004e, 0x6007, 0x0001,
+	0x00f0, 0x080c, 0xe2c8, 0x0140, 0x96b4, 0xff00, 0x8637, 0x9686,
+	0x0006, 0x0978, 0x0804, 0xd25e, 0x6017, 0x1900, 0x6007, 0x0009,
+	0x0070, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x080c, 0xe63f, 0x1904,
+	0xd5ad, 0x080c, 0xd77a, 0x1904, 0xd25e, 0x6007, 0x0012, 0x6003,
+	0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005, 0x6007, 0x0001,
+	0x6003, 0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0cb0, 0x6007,
+	0x0005, 0x0c68, 0x080c, 0xe63f, 0x1904, 0xd5ad, 0x080c, 0x3377,
+	0x1904, 0xd5ad, 0x080c, 0xd77a, 0x1904, 0xd25e, 0x6007, 0x0020,
+	0x6003, 0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005, 0x080c,
+	0x3377, 0x1904, 0xd5ad, 0x6007, 0x0023, 0x6003, 0x0001, 0x080c,
+	0x92b7, 0x080c, 0x9738, 0x0005, 0x080c, 0xe63f, 0x1904, 0xd5ad,
+	0x080c, 0x3377, 0x1904, 0xd5ad, 0x080c, 0xd77a, 0x1904, 0xd25e,
+	0x0016, 0x0026, 0x00e6, 0x2071, 0x0260, 0x2c08, 0x2011, 0x1820,
+	0x2214, 0x703c, 0x9206, 0x11e0, 0x2011, 0x181f, 0x2214, 0x7038,
+	0x9084, 0x00ff, 0x9206, 0x11a0, 0x7240, 0x080c, 0xc968, 0x0570,
+	0x2260, 0x6008, 0x9086, 0xffff, 0x0120, 0x7244, 0x6008, 0x9206,
+	0x1528, 0x6020, 0x9086, 0x0007, 0x1508, 0x080c, 0xacb0, 0x04a0,
+	0x7244, 0x9286, 0xffff, 0x0180, 0x2c08, 0x080c, 0xc968, 0x01b0,
+	0x2260, 0x7240, 0x6008, 0x9206, 0x1188, 0x6010, 0x9190, 0x0004,
+	0x2214, 0x9206, 0x01b8, 0x0050, 0x7240, 0x2c08, 0x9006, 0x080c,
+	0xe40f, 0x1180, 0x7244, 0x9286, 0xffff, 0x01b0, 0x2160, 0x6007,
+	0x0026, 0x6017, 0x1700, 0x7214, 0x9296, 0xffff, 0x1180, 0x6007,
+	0x0025, 0x0068, 0x6020, 0x9086, 0x0007, 0x1d80, 0x6004, 0x9086,
+	0x0024, 0x1110, 0x080c, 0xacb0, 0x2160, 0x6007, 0x0025, 0x6003,
+	0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x00ee, 0x002e, 0x001e,
+	0x0005, 0x2001, 0x0001, 0x080c, 0x65cf, 0x0156, 0x0016, 0x0026,
+	0x0036, 0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0276, 0x080c,
+	0xbc8e, 0x003e, 0x002e, 0x001e, 0x015e, 0x0120, 0x6007, 0x0031,
+	0x0804, 0xd377, 0x080c, 0xb8ff, 0x080c, 0x753d, 0x1190, 0x0006,
+	0x0026, 0x0036, 0x080c, 0x7557, 0x1138, 0x080c, 0x7840, 0x080c,
+	0x6092, 0x080c, 0x746e, 0x0010, 0x080c, 0x7511, 0x003e, 0x002e,
+	0x000e, 0x0005, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x080c, 0xd77a,
+	0x1904, 0xd25e, 0x6106, 0x080c, 0xd796, 0x1120, 0x6007, 0x002b,
+	0x0804, 0xd377, 0x6007, 0x002c, 0x0804, 0xd377, 0x080c, 0xe63f,
+	0x1904, 0xd5ad, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x080c, 0xd77a,
+	0x1904, 0xd25e, 0x6106, 0x080c, 0xd79b, 0x1120, 0x6007, 0x002e,
+	0x0804, 0xd377, 0x6007, 0x002f, 0x0804, 0xd377, 0x080c, 0x3377,
+	0x1904, 0xd5ad, 0x00e6, 0x00d6, 0x00c6, 0x6010, 0x2058, 0xb904,
+	0x9184, 0x00ff, 0x9086, 0x0006, 0x0158, 0x9184, 0xff00, 0x8007,
+	0x9086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, 0xd37e,
+	0x080c, 0x5742, 0xd0e4, 0x0904, 0xd4f8, 0x2071, 0x026c, 0x7010,
+	0x603a, 0x7014, 0x603e, 0x7108, 0x720c, 0x080c, 0x6ad9, 0x0140,
+	0x6010, 0x2058, 0xb810, 0x9106, 0x1118, 0xb814, 0x9206, 0x0510,
+	0x080c, 0x6ad5, 0x15b8, 0x2069, 0x1800, 0x6880, 0x9206, 0x1590,
+	0x687c, 0x9106, 0x1578, 0x7210, 0x080c, 0xc968, 0x0590, 0x080c,
+	0xd665, 0x0578, 0x080c, 0xe4c1, 0x0560, 0x622e, 0x6007, 0x0036,
+	0x6003, 0x0001, 0x2009, 0x8020, 0x080c, 0x92b0, 0x00ce, 0x00de,
+	0x00ee, 0x0005, 0x7214, 0x9286, 0xffff, 0x0150, 0x080c, 0xc968,
+	0x01c0, 0x9280, 0x0002, 0x2004, 0x7110, 0x9106, 0x1190, 0x08e0,
+	0x7210, 0x2c08, 0x9085, 0x0001, 0x080c, 0xe40f, 0x2c10, 0x2160,
+	0x0140, 0x0890, 0x6007, 0x0037, 0x602f, 0x0009, 0x6017, 0x1500,
+	0x08b8, 0x6007, 0x0037, 0x602f, 0x0003, 0x6017, 0x1700, 0x0880,
+	0x6007, 0x0012, 0x0868, 0x080c, 0x3377, 0x1904, 0xd5ad, 0x6010,
+	0x2058, 0xb804, 0x9084, 0xff00, 0x8007, 0x9086, 0x0006, 0x1904,
+	0xd37e, 0x00e6, 0x00d6, 0x00c6, 0x080c, 0x5742, 0xd0e4, 0x0904,
+	0xd570, 0x2069, 0x1800, 0x2071, 0x026c, 0x7008, 0x603a, 0x720c,
+	0x623e, 0x9286, 0xffff, 0x1150, 0x7208, 0x00c6, 0x2c08, 0x9085,
+	0x0001, 0x080c, 0xe40f, 0x2c10, 0x00ce, 0x05e8, 0x080c, 0xc968,
+	0x05d0, 0x7108, 0x9280, 0x0002, 0x2004, 0x9106, 0x15a0, 0x00c6,
+	0x0026, 0x2260, 0x080c, 0xc559, 0x002e, 0x00ce, 0x7118, 0x918c,
+	0xff00, 0x810f, 0x9186, 0x0001, 0x0178, 0x9186, 0x0005, 0x0118,
+	0x9186, 0x0007, 0x1198, 0x9280, 0x0005, 0x2004, 0x9005, 0x0170,
+	0x080c, 0xd665, 0x0904, 0xd4f1, 0x0056, 0x7510, 0x7614, 0x080c,
+	0xe4da, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x6007, 0x003b,
+	0x602f, 0x0009, 0x6017, 0x2a00, 0x6003, 0x0001, 0x2009, 0x8020,
+	0x080c, 0x92b0, 0x0c78, 0x6007, 0x003b, 0x602f, 0x0003, 0x6017,
+	0x0300, 0x6003, 0x0001, 0x2009, 0x8020, 0x080c, 0x92b0, 0x0c10,
+	0x6007, 0x003b, 0x602f, 0x000b, 0x6017, 0x0000, 0x0804, 0xd4c8,
+	0x00e6, 0x0026, 0x080c, 0x6a9b, 0x0550, 0x080c, 0x6a37, 0x080c,
+	0xe6b1, 0x1518, 0x2071, 0x1800, 0x70dc, 0x9085, 0x0003, 0x70de,
+	0x00f6, 0x2079, 0x0100, 0x72b0, 0x9284, 0x00ff, 0x707e, 0x78e6,
+	0x9284, 0xff00, 0x7280, 0x9205, 0x7082, 0x78ea, 0x00fe, 0x70e7,
+	0x0000, 0x080c, 0x6ad9, 0x0120, 0x2011, 0x1a08, 0x2013, 0x07d0,
+	0xd0ac, 0x1128, 0x080c, 0x3011, 0x0010, 0x080c, 0xe6e3, 0x002e,
+	0x00ee, 0x080c, 0xacb0, 0x0804, 0xd37d, 0x080c, 0xacb0, 0x0005,
+	0x2600, 0x0002, 0xd5c4, 0xd5f5, 0xd606, 0xd5c4, 0xd5c4, 0xd5c6,
+	0xd617, 0xd5c4, 0xd5c4, 0xd5c4, 0xd5e3, 0xd5c4, 0xd5c4, 0xd5c4,
+	0xd622, 0xd62f, 0xd660, 0xd5c4, 0x080c, 0x0d7d, 0x080c, 0xe63f,
+	0x1d20, 0x080c, 0x3377, 0x1d08, 0x080c, 0xd77a, 0x1148, 0x7038,
+	0x6016, 0x6007, 0x0045, 0x6003, 0x0001, 0x080c, 0x92b7, 0x0005,
+	0x080c, 0x3240, 0x080c, 0xd0b0, 0x6007, 0x0001, 0x6003, 0x0001,
+	0x080c, 0x92b7, 0x0005, 0x080c, 0xe63f, 0x1938, 0x080c, 0x3377,
+	0x1920, 0x080c, 0xd77a, 0x1d60, 0x703c, 0x6016, 0x6007, 0x004a,
+	0x6003, 0x0001, 0x080c, 0x92b7, 0x0005, 0x080c, 0x3377, 0x1904,
+	0xd5ad, 0x2009, 0x0041, 0x080c, 0xe6ec, 0x6007, 0x0047, 0x6003,
+	0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005, 0x080c, 0x3377,
+	0x1904, 0xd5ad, 0x2009, 0x0042, 0x080c, 0xe6ec, 0x6007, 0x0047,
+	0x6003, 0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005, 0x080c,
+	0x3377, 0x1904, 0xd5ad, 0x2009, 0x0046, 0x080c, 0xe6ec, 0x080c,
+	0xacb0, 0x0005, 0x080c, 0xd682, 0x0904, 0xd5ad, 0x6007, 0x004e,
+	0x6003, 0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005, 0x6007,
+	0x004f, 0x6017, 0x0000, 0x7134, 0x918c, 0x00ff, 0x81ff, 0x0508,
+	0x9186, 0x0001, 0x1160, 0x7140, 0x2001, 0x19bc, 0x2004, 0x9106,
+	0x11b0, 0x7144, 0x2001, 0x19bd, 0x2004, 0x9106, 0x0190, 0x9186,
+	0x0002, 0x1168, 0x2011, 0x0276, 0x20a9, 0x0004, 0x6010, 0x0096,
+	0x2048, 0x2019, 0x000a, 0x080c, 0xbca2, 0x009e, 0x0110, 0x6017,
+	0x0001, 0x6003, 0x0001, 0x080c, 0x92b7, 0x080c, 0x9738, 0x0005,
+	0x6007, 0x0050, 0x703c, 0x6016, 0x0ca0, 0x0016, 0x00e6, 0x2071,
+	0x0260, 0x00b6, 0x00c6, 0x2260, 0x6010, 0x2058, 0xb8d4, 0xd084,
+	0x0150, 0x7128, 0x604c, 0x9106, 0x1120, 0x712c, 0x6050, 0x9106,
+	0x0110, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ce, 0x00be, 0x00ee,
+	0x001e, 0x0005, 0x0016, 0x0096, 0x0086, 0x00e6, 0x01c6, 0x01d6,
+	0x0126, 0x2091, 0x8000, 0x2071, 0x1800, 0x7090, 0x908a, 0x00f9,
+	0x16e8, 0x20e1, 0x0000, 0x2001, 0x199f, 0x2003, 0x0000, 0x080c,
+	0x1060, 0x05a0, 0x2900, 0x6016, 0x7090, 0x8004, 0xa816, 0x908a,
+	0x001e, 0x02d0, 0xa833, 0x001e, 0x20a9, 0x001e, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x001b, 0x20a0, 0x2001, 0x199f, 0x0016, 0x200c,
+	0x0471, 0x001e, 0x2940, 0x080c, 0x1060, 0x01c0, 0x2900, 0xa006,
+	0x2100, 0x81ff, 0x0180, 0x0c18, 0xa832, 0x20a8, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x001b, 0x20a0, 0x2001, 0x199f, 0x0016, 0x200c,
+	0x00b1, 0x001e, 0x0000, 0x9085, 0x0001, 0x0048, 0x2071, 0x1800,
+	0x7093, 0x0000, 0x6014, 0x2048, 0x080c, 0x0ff9, 0x9006, 0x012e,
+	0x01de, 0x01ce, 0x00ee, 0x008e, 0x009e, 0x001e, 0x0005, 0x0006,
+	0x0016, 0x0026, 0x0036, 0x00c6, 0x918c, 0xffff, 0x11a8, 0x080c,
+	0x21e3, 0x2099, 0x026c, 0x2001, 0x0014, 0x3518, 0x9312, 0x1218,
+	0x23a8, 0x4003, 0x00f8, 0x20a8, 0x4003, 0x22a8, 0x8108, 0x080c,
+	0x21e3, 0x2099, 0x0260, 0x0ca8, 0x080c, 0x21e3, 0x2061, 0x199f,
+	0x6004, 0x2098, 0x6008, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003,
+	0x0048, 0x20a8, 0x4003, 0x22a8, 0x8108, 0x080c, 0x21e3, 0x2099,
+	0x0260, 0x0ca8, 0x2061, 0x199f, 0x2019, 0x0280, 0x3300, 0x931e,
+	0x0110, 0x6006, 0x0020, 0x2001, 0x0260, 0x6006, 0x8108, 0x2162,
+	0x9292, 0x0021, 0x9296, 0xffff, 0x620a, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00c6,
+	0x81ff, 0x11b8, 0x080c, 0x21fb, 0x20a1, 0x024c, 0x2001, 0x0014,
+	0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, 0x0418, 0x20a8, 0x4003,
+	0x82ff, 0x01f8, 0x22a8, 0x8108, 0x080c, 0x21fb, 0x20a1, 0x0240,
+	0x0c98, 0x080c, 0x21fb, 0x2061, 0x19a2, 0x6004, 0x20a0, 0x6008,
+	0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, 0x0058, 0x20a8, 0x4003,
+	0x82ff, 0x0138, 0x22a8, 0x8108, 0x080c, 0x21fb, 0x20a1, 0x0240,
+	0x0c98, 0x2061, 0x19a2, 0x2019, 0x0260, 0x3400, 0x931e, 0x0110,
+	0x6006, 0x0020, 0x2001, 0x0240, 0x6006, 0x8108, 0x2162, 0x9292,
+	0x0021, 0x9296, 0xffff, 0x620a, 0x00ce, 0x003e, 0x002e, 0x001e,
+	0x000e, 0x0005, 0x00b6, 0x0066, 0x6610, 0x2658, 0xbe04, 0x96b4,
+	0xff00, 0x8637, 0x9686, 0x0006, 0x0170, 0x9686, 0x0004, 0x0158,
+	0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, 0x0128, 0x9686, 0x0004,
+	0x0110, 0x9085, 0x0001, 0x006e, 0x00be, 0x0005, 0x00d6, 0x080c,
+	0xd810, 0x00de, 0x0005, 0x00d6, 0x080c, 0xd81d, 0x1520, 0x680c,
+	0x908c, 0xff00, 0x6820, 0x9084, 0x00ff, 0x9115, 0x6216, 0x6824,
+	0x602e, 0xd1e4, 0x0130, 0x9006, 0x080c, 0xe80c, 0x2009, 0x0001,
+	0x0078, 0xd1ec, 0x0180, 0x6920, 0x918c, 0x00ff, 0x6824, 0x080c,
+	0x2661, 0x1148, 0x2001, 0x0001, 0x080c, 0xe80c, 0x2110, 0x900e,
+	0x080c, 0x328f, 0x0018, 0x9085, 0x0001, 0x0008, 0x9006, 0x00de,
+	0x0005, 0x00b6, 0x00c6, 0x080c, 0xad20, 0x0598, 0x0016, 0x0026,
+	0x00c6, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x2661,
+	0x1568, 0x080c, 0x6632, 0x1550, 0xbe12, 0xbd16, 0x00ce, 0x002e,
+	0x001e, 0x2b00, 0x6012, 0x080c, 0xe63f, 0x11c8, 0x080c, 0x3377,
+	0x11b0, 0x080c, 0xd77a, 0x0500, 0x2001, 0x0007, 0x080c, 0x65e3,
+	0x2001, 0x0007, 0x080c, 0x660f, 0x6017, 0x0000, 0x6023, 0x0001,
+	0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x92b7, 0x0010, 0x080c,
+	0xacb0, 0x9085, 0x0001, 0x00ce, 0x00be, 0x0005, 0x080c, 0xacb0,
+	0x00ce, 0x002e, 0x001e, 0x0ca8, 0x080c, 0xacb0, 0x9006, 0x0c98,
+	0x2069, 0x026d, 0x6800, 0x9082, 0x0010, 0x1228, 0x6017, 0x0000,
+	0x9085, 0x0001, 0x0008, 0x9006, 0x0005, 0x6017, 0x0000, 0x2069,
+	0x026c, 0x6808, 0x9084, 0xff00, 0x9086, 0x0800, 0x1190, 0x6904,
+	0x9186, 0x0018, 0x0118, 0x9186, 0x0014, 0x1158, 0x810f, 0x6800,
+	0x9084, 0x00ff, 0x910d, 0x6162, 0x908e, 0x0014, 0x0110, 0x908e,
+	0x0010, 0x0005, 0x6004, 0x90b2, 0x0053, 0x1a0c, 0x0d7d, 0x91b6,
+	0x0013, 0x1130, 0x2008, 0x91b2, 0x0040, 0x1a04, 0xd95f, 0x0092,
+	0x91b6, 0x0027, 0x0120, 0x91b6, 0x0014, 0x190c, 0x0d7d, 0x2001,
+	0x0007, 0x080c, 0x660f, 0x080c, 0x967a, 0x080c, 0xaceb, 0x080c,
+	0x9738, 0x0005, 0xd89a, 0xd89c, 0xd89a, 0xd89a, 0xd89a, 0xd89c,
+	0xd8a9, 0xd95c, 0xd8f9, 0xd95c, 0xd90d, 0xd95c, 0xd8a9, 0xd95c,
+	0xd954, 0xd95c, 0xd954, 0xd95c, 0xd95c, 0xd89a, 0xd89a, 0xd89a,
+	0xd89a, 0xd89a, 0xd89a, 0xd89a, 0xd89a, 0xd89a, 0xd89a, 0xd89a,
+	0xd89c, 0xd89a, 0xd95c, 0xd89a, 0xd89a, 0xd95c, 0xd89a, 0xd959,
+	0xd95c, 0xd89a, 0xd89a, 0xd89a, 0xd89a, 0xd95c, 0xd95c, 0xd89a,
+	0xd95c, 0xd95c, 0xd89a, 0xd8a4, 0xd89a, 0xd89a, 0xd89a, 0xd89a,
+	0xd958, 0xd95c, 0xd89a, 0xd89a, 0xd95c, 0xd95c, 0xd89a, 0xd89a,
+	0xd89a, 0xd89a, 0x080c, 0x0d7d, 0x080c, 0xd0b3, 0x6003, 0x0002,
+	0x080c, 0x9738, 0x0804, 0xd95e, 0x9006, 0x080c, 0x65cf, 0x0804,
+	0xd95c, 0x080c, 0x6ad5, 0x1904, 0xd95c, 0x9006, 0x080c, 0x65cf,
+	0x6010, 0x2058, 0xb810, 0x9086, 0x00ff, 0x1140, 0x00f6, 0x2079,
+	0x1800, 0x78a8, 0x8000, 0x78aa, 0x00fe, 0x0428, 0x6010, 0x2058,
+	0xb884, 0x9005, 0x1178, 0x080c, 0xd09b, 0x1904, 0xd95c, 0x0036,
+	0x0046, 0xbba0, 0x2021, 0x0007, 0x080c, 0x4d09, 0x004e, 0x003e,
+	0x0804, 0xd95c, 0x080c, 0x33a8, 0x1904, 0xd95c, 0x2001, 0x1800,
+	0x2004, 0x9086, 0x0002, 0x1138, 0x00f6, 0x2079, 0x1800, 0x78a8,
+	0x8000, 0x78aa, 0x00fe, 0x2001, 0x0002, 0x080c, 0x65e3, 0x6023,
+	0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x92b7, 0x080c,
+	0x9738, 0x6110, 0x2158, 0x2009, 0x0001, 0x080c, 0x86d6, 0x0804,
+	0xd95e, 0x6610, 0x2658, 0xbe04, 0x96b4, 0xff00, 0x8637, 0x9686,
+	0x0006, 0x0904, 0xd95c, 0x9686, 0x0004, 0x0904, 0xd95c, 0x080c,
+	0x8f52, 0x2001, 0x0004, 0x0804, 0xd95a, 0x2001, 0x1800, 0x2004,
+	0x9086, 0x0003, 0x1158, 0x0036, 0x0046, 0x6010, 0x2058, 0xbba0,
+	0x2021, 0x0006, 0x080c, 0x4d09, 0x004e, 0x003e, 0x2001, 0x0006,
+	0x080c, 0xd978, 0x6610, 0x2658, 0xbe04, 0x0066, 0x96b4, 0xff00,
+	0x8637, 0x9686, 0x0006, 0x006e, 0x0168, 0x2001, 0x0006, 0x080c,
+	0x660f, 0x9284, 0x00ff, 0x908e, 0x0007, 0x1120, 0x2001, 0x0006,
+	0x080c, 0x65e3, 0x080c, 0x6ad5, 0x11f8, 0x2001, 0x1837, 0x2004,
+	0xd0a4, 0x01d0, 0xbe04, 0x96b4, 0x00ff, 0x9686, 0x0006, 0x01a0,
+	0x00f6, 0x2079, 0x1800, 0x78a8, 0x8000, 0x78aa, 0x00fe, 0x0804,
+	0xd8e3, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006, 0x0409, 0x0020,
+	0x0018, 0x0010, 0x080c, 0x660f, 0x080c, 0xacb0, 0x0005, 0x2600,
+	0x0002, 0xd973, 0xd973, 0xd973, 0xd973, 0xd973, 0xd975, 0xd973,
+	0xd975, 0xd973, 0xd973, 0xd975, 0xd973, 0xd973, 0xd973, 0xd975,
+	0xd975, 0xd975, 0xd975, 0x080c, 0x0d7d, 0x080c, 0xacb0, 0x0005,
+	0x0016, 0x00b6, 0x00d6, 0x6110, 0x2158, 0xb900, 0xd184, 0x0138,
+	0x080c, 0x65e3, 0x9006, 0x080c, 0x65cf, 0x080c, 0x326f, 0x00de,
+	0x00be, 0x001e, 0x0005, 0x6610, 0x2658, 0xb804, 0x9084, 0xff00,
+	0x8007, 0x90b2, 0x000c, 0x1a0c, 0x0d7d, 0x91b6, 0x0015, 0x1110,
+	0x003b, 0x0028, 0x91b6, 0x0016, 0x190c, 0x0d7d, 0x006b, 0x0005,
+	0xb77c, 0xb77c, 0xb77c, 0xb77c, 0xda0d, 0xb77c, 0xd9f7, 0xd9b8,
+	0xb77c, 0xb77c, 0xb77c, 0xb77c, 0xb77c, 0xb77c, 0xb77c, 0xb77c,
+	0xda0d, 0xb77c, 0xd9f7, 0xd9fe, 0xb77c, 0xb77c, 0xb77c, 0xb77c,
+	0x00f6, 0x080c, 0x6ad5, 0x11d8, 0x080c, 0xd09b, 0x11c0, 0x6010,
+	0x905d, 0x01a8, 0xb884, 0x9005, 0x0190, 0x9006, 0x080c, 0x65cf,
+	0x2001, 0x0002, 0x080c, 0x65e3, 0x6023, 0x0001, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x92b7, 0x080c, 0x9738, 0x00f0, 0x2011,
+	0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x2661, 0x11b0, 0x080c,
+	0x6693, 0x0118, 0x080c, 0xacb0, 0x0080, 0xb810, 0x0006, 0xb814,
+	0x0006, 0xb884, 0x0006, 0x080c, 0x60ac, 0x000e, 0xb886, 0x000e,
+	0xb816, 0x000e, 0xb812, 0x080c, 0xacb0, 0x00fe, 0x0005, 0x6604,
+	0x96b6, 0x001e, 0x1110, 0x080c, 0xacb0, 0x0005, 0x080c, 0xbb07,
+	0x1148, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x92b7, 0x080c,
+	0x9738, 0x0010, 0x080c, 0xacb0, 0x0005, 0x0804, 0xacb0, 0x6004,
+	0x908a, 0x0053, 0x1a0c, 0x0d7d, 0x080c, 0x967a, 0x080c, 0xaceb,
+	0x0005, 0x9182, 0x0040, 0x0002, 0xda30, 0xda30, 0xda30, 0xda30,
+	0xda32, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30,
+	0xda30, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30, 0xda30,
+	0x080c, 0x0d7d, 0x0096, 0x00b6, 0x00d6, 0x00e6, 0x00f6, 0x0046,
+	0x0026, 0x6210, 0x2258, 0xb8bc, 0x9005, 0x11b0, 0x6007, 0x0044,
+	0x2071, 0x0260, 0x7444, 0x94a4, 0xff00, 0x0904, 0xda99, 0x080c,
+	0xe800, 0x1170, 0x9486, 0x2000, 0x1158, 0x2009, 0x0001, 0x2011,
+	0x0200, 0x080c, 0x8979, 0x0020, 0x9026, 0x080c, 0xe684, 0x0c30,
+	0x080c, 0x1047, 0x090c, 0x0d7d, 0x6003, 0x0007, 0xa867, 0x010d,
+	0x9006, 0xa802, 0xa86a, 0xac8a, 0x2c00, 0xa88e, 0x6008, 0xa8e2,
+	0x6010, 0x2058, 0xb8a0, 0x7130, 0xa97a, 0x0016, 0xa876, 0xa87f,
+	0x0000, 0xa883, 0x0000, 0xa887, 0x0036, 0x080c, 0x6dee, 0x001e,
+	0x080c, 0xe800, 0x1904, 0xdaf9, 0x9486, 0x2000, 0x1130, 0x2019,
+	0x0017, 0x080c, 0xe3b5, 0x0804, 0xdaf9, 0x9486, 0x0200, 0x1120,
+	0x080c, 0xe345, 0x0804, 0xdaf9, 0x9486, 0x0400, 0x0120, 0x9486,
+	0x1000, 0x1904, 0xdaf9, 0x2019, 0x0002, 0x080c, 0xe364, 0x0804,
+	0xdaf9, 0x2069, 0x1a6e, 0x6a00, 0xd284, 0x0904, 0xdb63, 0x9284,
+	0x0300, 0x1904, 0xdb5c, 0x6804, 0x9005, 0x0904, 0xdb44, 0x2d78,
+	0x6003, 0x0007, 0x080c, 0x1060, 0x0904, 0xdb05, 0x7800, 0xd08c,
+	0x1118, 0x7804, 0x8001, 0x7806, 0x6017, 0x0000, 0x2001, 0x180f,
+	0x2004, 0xd084, 0x1904, 0xdb67, 0x9006, 0xa802, 0xa867, 0x0116,
+	0xa86a, 0x6008, 0xa8e2, 0x2c00, 0xa87a, 0x6010, 0x2058, 0xb8a0,
+	0x7130, 0xa9b6, 0xa876, 0xb928, 0xa9ba, 0xb92c, 0xa9be, 0xb930,
+	0xa9c2, 0xb934, 0xa9c6, 0xa883, 0x003d, 0x7044, 0x9084, 0x0003,
+	0x9080, 0xdb01, 0x2005, 0xa87e, 0x20a9, 0x000a, 0x2001, 0x0270,
+	0xaa5c, 0x9290, 0x0021, 0x2009, 0x0205, 0x200b, 0x0080, 0x20e1,
+	0x0000, 0xab60, 0x23e8, 0x2098, 0x22a0, 0x4003, 0x200b, 0x0000,
+	0x2001, 0x027a, 0x200c, 0xa9b2, 0x8000, 0x200c, 0xa9ae, 0x080c,
+	0x6df1, 0x002e, 0x004e, 0x00fe, 0x00ee, 0x00de, 0x00be, 0x009e,
+	0x0005, 0x0000, 0x0080, 0x0040, 0x0000, 0x2001, 0x1810, 0x2004,
+	0xd084, 0x0120, 0x080c, 0x1047, 0x1904, 0xdaae, 0x6017, 0xf100,
+	0x6003, 0x0001, 0x6007, 0x0041, 0x2009, 0xa022, 0x080c, 0x92b0,
+	0x0c00, 0x2069, 0x0260, 0x6848, 0x9084, 0xff00, 0x9086, 0x1200,
+	0x1198, 0x686c, 0x9084, 0x00ff, 0x0016, 0x6114, 0x918c, 0xf700,
+	0x910d, 0x6116, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043, 0x2009,
+	0xa025, 0x080c, 0x92b0, 0x0828, 0x6868, 0x602e, 0x686c, 0x6032,
+	0x6017, 0xf200, 0x6003, 0x0001, 0x6007, 0x0041, 0x2009, 0xa022,
+	0x080c, 0x92b0, 0x0804, 0xdaf9, 0x2001, 0x180e, 0x2004, 0xd0ec,
+	0x0120, 0x2011, 0x8049, 0x080c, 0x4b52, 0x6017, 0xf300, 0x0010,
+	0x6017, 0xf100, 0x6003, 0x0001, 0x6007, 0x0041, 0x2009, 0xa022,
+	0x080c, 0x92b0, 0x0804, 0xdaf9, 0x6017, 0xf500, 0x0c98, 0x6017,
+	0xf600, 0x0804, 0xdb19, 0x6017, 0xf200, 0x0804, 0xdb19, 0xa867,
+	0x0146, 0xa86b, 0x0000, 0x6008, 0xa886, 0x2c00, 0xa87a, 0x7044,
+	0x9084, 0x0003, 0x9080, 0xdb01, 0x2005, 0xa87e, 0x2928, 0x6010,
+	0x2058, 0xb8a0, 0xa876, 0xb828, 0xa88a, 0xb82c, 0xa88e, 0xb830,
+	0xa892, 0xb834, 0xa896, 0xa883, 0x003d, 0x2009, 0x0205, 0x2104,
+	0x9085, 0x0080, 0x200a, 0x20e1, 0x0000, 0x2011, 0x0210, 0x2214,
+	0x9294, 0x0fff, 0xaaa2, 0x9282, 0x0111, 0x1a0c, 0x0d7d, 0x8210,
+	0x821c, 0x2001, 0x026c, 0x2098, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0029, 0x20a0, 0x2011, 0xdbe3, 0x2041, 0x0001, 0x223d, 0x9784,
+	0x00ff, 0x9322, 0x1208, 0x2300, 0x20a8, 0x4003, 0x931a, 0x0530,
+	0x8210, 0xd7fc, 0x1130, 0x8d68, 0x2d0a, 0x2001, 0x0260, 0x2098,
+	0x0c68, 0x2950, 0x080c, 0x1060, 0x0170, 0x2900, 0xb002, 0xa867,
+	0x0147, 0xa86b, 0x0000, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x001b,
+	0x20a0, 0x8840, 0x08d8, 0x2548, 0xa800, 0x902d, 0x0118, 0x080c,
+	0x1079, 0x0cc8, 0x080c, 0x1079, 0x0804, 0xdb05, 0x2548, 0x8847,
+	0x9885, 0x0046, 0xa866, 0x2009, 0x0205, 0x200b, 0x0000, 0x080c,
+	0xe3e8, 0x0804, 0xdaf9, 0x8010, 0x0004, 0x801a, 0x0006, 0x8018,
+	0x0008, 0x8016, 0x000a, 0x8014, 0x9186, 0x0013, 0x1160, 0x6004,
+	0x908a, 0x0057, 0x1a0c, 0x0d7d, 0x9082, 0x0040, 0x0a0c, 0x0d7d,
+	0x2008, 0x0804, 0xdc6f, 0x9186, 0x0051, 0x0108, 0x0040, 0x080c,
+	0xab33, 0x01e8, 0x9086, 0x0002, 0x0904, 0xdcb7, 0x00c0, 0x9186,
+	0x0027, 0x0180, 0x9186, 0x0048, 0x0128, 0x9186, 0x0014, 0x0150,
+	0x190c, 0x0d7d, 0x080c, 0xab33, 0x0150, 0x9086, 0x0004, 0x0904,
+	0xdd56, 0x0028, 0x6004, 0x9082, 0x0040, 0x2008, 0x001a, 0x080c,
+	0xad6a, 0x0005, 0xdc36, 0xdc38, 0xdc38, 0xdc5f, 0xdc36, 0xdc36,
+	0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36,
+	0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36, 0xdc36, 0x080c, 0x0d7d,
+	0x080c, 0x967a, 0x080c, 0x9738, 0x0036, 0x0096, 0x6014, 0x904d,
+	0x01d8, 0x080c, 0xc97a, 0x01c0, 0x6003, 0x0002, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x1178, 0x2019, 0x0004, 0x080c,
+	0xe3e8, 0x6017, 0x0000, 0x6018, 0x9005, 0x1120, 0x2001, 0x1986,
+	0x2004, 0x601a, 0x6003, 0x0007, 0x009e, 0x003e, 0x0005, 0x0096,
+	0x080c, 0x967a, 0x080c, 0x9738, 0x080c, 0xc97a, 0x0120, 0x6014,
+	0x2048, 0x080c, 0x1079, 0x080c, 0xaceb, 0x009e, 0x0005, 0x0002,
+	0xdc84, 0xdc99, 0xdc86, 0xdcae, 0xdc84, 0xdc84, 0xdc84, 0xdc84,
+	0xdc84, 0xdc84, 0xdc84, 0xdc84, 0xdc84, 0xdc84, 0xdc84, 0xdc84,
+	0xdc84, 0xdc84, 0xdc84, 0xdc84, 0x080c, 0x0d7d, 0x0096, 0x6014,
+	0x2048, 0xa87c, 0xd0b4, 0x0138, 0x6003, 0x0007, 0x2009, 0x0043,
+	0x080c, 0xad4d, 0x0010, 0x6003, 0x0004, 0x080c, 0x9738, 0x009e,
+	0x0005, 0x080c, 0xc97a, 0x0138, 0x6114, 0x0096, 0x2148, 0xa97c,
+	0x009e, 0xd1ec, 0x1138, 0x080c, 0x894e, 0x080c, 0xacb0, 0x080c,
+	0x9738, 0x0005, 0x080c, 0xe648, 0x0db0, 0x0cc8, 0x6003, 0x0001,
+	0x6007, 0x0041, 0x2009, 0xa022, 0x080c, 0x92b0, 0x0005, 0x9182,
+	0x0040, 0x0002, 0xdcce, 0xdcd0, 0xdcce, 0xdcce, 0xdcce, 0xdcce,
+	0xdcce, 0xdcce, 0xdcce, 0xdcce, 0xdcce, 0xdcce, 0xdcce, 0xdcce,
+	0xdcce, 0xdcce, 0xdcce, 0xdcd1, 0xdcce, 0xdcce, 0x080c, 0x0d7d,
+	0x0005, 0x00d6, 0x080c, 0x894e, 0x00de, 0x080c, 0xe6a0, 0x080c,
+	0xacb0, 0x0005, 0x9182, 0x0040, 0x0002, 0xdcf1, 0xdcf1, 0xdcf1,
+	0xdcf1, 0xdcf1, 0xdcf1, 0xdcf1, 0xdcf1, 0xdcf1, 0xdcf3, 0xdd1e,
+	0xdcf1, 0xdcf1, 0xdcf1, 0xdcf1, 0xdd1e, 0xdcf1, 0xdcf1, 0xdcf1,
+	0xdcf1, 0x080c, 0x0d7d, 0x6014, 0x0096, 0x2048, 0xa87c, 0xd0fc,
+	0x0168, 0x908c, 0x0003, 0x918e, 0x0002, 0x0180, 0x6144, 0xd1e4,
+	0x1168, 0x2009, 0x0041, 0x009e, 0x0804, 0xddde, 0x6003, 0x0007,
+	0x601b, 0x0000, 0x080c, 0x894e, 0x009e, 0x0005, 0x6014, 0x2048,
+	0xa97c, 0xd1ec, 0x1130, 0x080c, 0x894e, 0x080c, 0xacb0, 0x009e,
+	0x0005, 0x080c, 0xe648, 0x0db8, 0x009e, 0x0005, 0x2001, 0x180c,
+	0x200c, 0xc1d4, 0x2102, 0x0036, 0x080c, 0x96d5, 0x080c, 0x9738,
+	0x6014, 0x0096, 0x2048, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be,
+	0xd0bc, 0x0188, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0140,
+	0xa8ac, 0x6330, 0x931a, 0x6332, 0xa8b0, 0x632c, 0x931b, 0x632e,
+	0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xe3e8, 0x6018,
+	0x9005, 0x1128, 0x2001, 0x1986, 0x2004, 0x8003, 0x601a, 0x6017,
+	0x0000, 0x6003, 0x0007, 0x009e, 0x003e, 0x0005, 0x9182, 0x0040,
+	0x0002, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d,
+	0xdd6d, 0xdd6f, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d,
+	0xdd6d, 0xdd6d, 0xdd6d, 0xdd6d, 0xddba, 0x080c, 0x0d7d, 0x6014,
+	0x0096, 0x2048, 0xa834, 0xaa38, 0x6110, 0x00b6, 0x2158, 0xb900,
+	0x00be, 0xd1bc, 0x1190, 0x920d, 0x1518, 0xa87c, 0xd0fc, 0x0128,
+	0x2009, 0x0041, 0x009e, 0x0804, 0xddde, 0x6003, 0x0007, 0x601b,
+	0x0000, 0x080c, 0x894e, 0x009e, 0x0005, 0x6124, 0xd1f4, 0x1d58,
+	0x0006, 0x0046, 0xacac, 0x9422, 0xa9b0, 0x2200, 0x910b, 0x6030,
+	0x9420, 0x6432, 0x602c, 0x9109, 0x612e, 0x004e, 0x000e, 0x08d8,
+	0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1bc, 0x1178, 0x2009,
+	0x180e, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, 0x6003,
+	0x0006, 0x00e9, 0x080c, 0x8950, 0x009e, 0x0005, 0x6003, 0x0002,
+	0x009e, 0x0005, 0x6024, 0xd0f4, 0x0128, 0x080c, 0x1697, 0x1904,
+	0xdd6f, 0x0005, 0x6014, 0x0096, 0x2048, 0xa834, 0xa938, 0x009e,
+	0x9105, 0x1120, 0x080c, 0x1697, 0x1904, 0xdd6f, 0x0005, 0xd2fc,
+	0x0140, 0x8002, 0x8000, 0x8212, 0x9291, 0x0000, 0x2009, 0x0009,
+	0x0010, 0x2009, 0x0015, 0xaa9a, 0xa896, 0x0005, 0x9182, 0x0040,
+	0x0208, 0x0062, 0x9186, 0x0013, 0x0120, 0x9186, 0x0014, 0x190c,
+	0x0d7d, 0x6024, 0xd0dc, 0x090c, 0x0d7d, 0x0005, 0xde02, 0xde0e,
+	0xde1a, 0xde26, 0xde02, 0xde02, 0xde02, 0xde02, 0xde09, 0xde04,
+	0xde04, 0xde02, 0xde02, 0xde02, 0xde02, 0xde04, 0xde02, 0xde04,
+	0xde02, 0xde09, 0x080c, 0x0d7d, 0x6024, 0xd0dc, 0x090c, 0x0d7d,
+	0x0005, 0x6014, 0x9005, 0x190c, 0x0d7d, 0x0005, 0x6003, 0x0001,
+	0x6106, 0x0126, 0x2091, 0x8000, 0x2009, 0xa022, 0x080c, 0x9292,
+	0x012e, 0x0005, 0x6003, 0x0004, 0x6106, 0x0126, 0x2091, 0x8000,
+	0x2009, 0xa001, 0x080c, 0x92b0, 0x012e, 0x0005, 0x6003, 0x0003,
+	0x6106, 0x080c, 0x1c59, 0x0126, 0x2091, 0x8000, 0x6014, 0x0096,
+	0x2048, 0xa87c, 0xd0fc, 0x0188, 0x9084, 0x0003, 0x9086, 0x0002,
+	0x01a0, 0x6024, 0xd0cc, 0x1148, 0xd0c4, 0x1138, 0xa8a8, 0x9005,
+	0x1120, 0x6144, 0x918d, 0xb035, 0x0018, 0x6144, 0x918d, 0xa035,
+	0x009e, 0x080c, 0x92f7, 0x012e, 0x0005, 0x6144, 0x918d, 0xa032,
+	0x0cb8, 0x0126, 0x2091, 0x8000, 0x0036, 0x0096, 0x9182, 0x0040,
+	0x0023, 0x009e, 0x003e, 0x012e, 0x0005, 0xde71, 0xde73, 0xde88,
+	0xdea2, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71,
+	0xde71, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71, 0xde71,
+	0xde71, 0x080c, 0x0d7d, 0x6014, 0x2048, 0xa87c, 0xd0fc, 0x0510,
+	0x909c, 0x0003, 0x939e, 0x0003, 0x01e8, 0x6003, 0x0001, 0x6106,
+	0x0126, 0x2091, 0x8000, 0x2009, 0xa022, 0x080c, 0x92b0, 0x0470,
+	0x6014, 0x2048, 0xa87c, 0xd0fc, 0x0168, 0x909c, 0x0003, 0x939e,
+	0x0003, 0x0140, 0x6003, 0x0001, 0x6106, 0x2009, 0xa001, 0x080c,
+	0x92b0, 0x00e0, 0x901e, 0x6316, 0x631a, 0x2019, 0x0004, 0x080c,
+	0xe3e8, 0x00a0, 0x6014, 0x2048, 0xa87c, 0xd0fc, 0x0d98, 0x909c,
+	0x0003, 0x939e, 0x0003, 0x0d70, 0x6003, 0x0003, 0x6106, 0x080c,
+	0x1c59, 0x6144, 0x918d, 0xa035, 0x080c, 0x92f7, 0x0005, 0x080c,
+	0x967a, 0x6114, 0x81ff, 0x0158, 0x0096, 0x2148, 0x080c, 0xe79d,
+	0x0036, 0x2019, 0x0029, 0x080c, 0xe3e8, 0x003e, 0x009e, 0x080c,
+	0xaceb, 0x080c, 0x9738, 0x0005, 0x080c, 0x96d5, 0x6114, 0x81ff,
+	0x0158, 0x0096, 0x2148, 0x080c, 0xe79d, 0x0036, 0x2019, 0x0029,
+	0x080c, 0xe3e8, 0x003e, 0x009e, 0x080c, 0xaceb, 0x0005, 0x9182,
+	0x0085, 0x0002, 0xdef1, 0xdeef, 0xdeef, 0xdefd, 0xdeef, 0xdeef,
+	0xdeef, 0xdeef, 0xdeef, 0xdeef, 0xdeef, 0xdeef, 0xdeef, 0x080c,
+	0x0d7d, 0x6003, 0x000b, 0x6106, 0x0126, 0x2091, 0x8000, 0x2009,
+	0x8020, 0x080c, 0x92b0, 0x012e, 0x0005, 0x0026, 0x00e6, 0x080c,
+	0xe63f, 0x0118, 0x080c, 0xacb0, 0x0440, 0x2071, 0x0260, 0x7224,
+	0x6216, 0x2001, 0x180e, 0x2004, 0xd0e4, 0x0150, 0x6010, 0x00b6,
+	0x2058, 0xbca0, 0x00be, 0x2c00, 0x2011, 0x014e, 0x080c, 0xafdb,
+	0x7220, 0x080c, 0xe27e, 0x0118, 0x6007, 0x0086, 0x0040, 0x6007,
+	0x0087, 0x7224, 0x9296, 0xffff, 0x1110, 0x6007, 0x0086, 0x6003,
+	0x0001, 0x2009, 0x8020, 0x080c, 0x92b0, 0x00ee, 0x002e, 0x0005,
+	0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085, 0x0a0c, 0x0d7d,
+	0x908a, 0x0092, 0x1a0c, 0x0d7d, 0x9082, 0x0085, 0x00a2, 0x9186,
+	0x0027, 0x0130, 0x9186, 0x0014, 0x0118, 0x080c, 0xad6a, 0x0050,
+	0x2001, 0x0007, 0x080c, 0x660f, 0x080c, 0x967a, 0x080c, 0xaceb,
+	0x080c, 0x9738, 0x0005, 0xdf60, 0xdf62, 0xdf62, 0xdf60, 0xdf60,
+	0xdf60, 0xdf60, 0xdf60, 0xdf60, 0xdf60, 0xdf60, 0xdf60, 0xdf60,
+	0x080c, 0x0d7d, 0x080c, 0xaceb, 0x080c, 0x9738, 0x0005, 0x9182,
+	0x0085, 0x0a0c, 0x0d7d, 0x9182, 0x0092, 0x1a0c, 0x0d7d, 0x9182,
+	0x0085, 0x0002, 0xdf7f, 0xdf7f, 0xdf7f, 0xdf81, 0xdf7f, 0xdf7f,
+	0xdf7f, 0xdf7f, 0xdf7f, 0xdf7f, 0xdf7f, 0xdf7f, 0xdf7f, 0x080c,
+	0x0d7d, 0x0005, 0x9186, 0x0013, 0x0148, 0x9186, 0x0014, 0x0130,
+	0x9186, 0x0027, 0x0118, 0x080c, 0xad6a, 0x0020, 0x080c, 0x967a,
+	0x080c, 0xaceb, 0x0005, 0x0036, 0x080c, 0xe6a0, 0x604b, 0x0000,
+	0x2019, 0x000b, 0x0031, 0x6023, 0x0006, 0x6003, 0x0007, 0x003e,
+	0x0005, 0x0126, 0x0036, 0x2091, 0x8000, 0x080c, 0xa91e, 0x0106,
+	0x0086, 0x2c40, 0x0096, 0x904e, 0x080c, 0xa28c, 0x009e, 0x008e,
+	0x1558, 0x0076, 0x2c38, 0x080c, 0xa337, 0x007e, 0x1528, 0x6000,
+	0x9086, 0x0000, 0x0508, 0x6020, 0x9086, 0x0007, 0x01e8, 0x0096,
+	0x601c, 0xd084, 0x0140, 0x080c, 0xe6a0, 0x080c, 0xd0b3, 0x080c,
+	0x1ac5, 0x6023, 0x0007, 0x6014, 0x2048, 0x080c, 0xc97a, 0x0110,
+	0x080c, 0xe3e8, 0x009e, 0x9006, 0x6046, 0x6016, 0x080c, 0xe6a0,
+	0x6023, 0x0007, 0x080c, 0xd0b3, 0x010e, 0x090c, 0xa93a, 0x003e,
+	0x012e, 0x0005, 0x00f6, 0x00c6, 0x00b6, 0x0036, 0x0156, 0x2079,
+	0x0260, 0x7938, 0x783c, 0x080c, 0x2661, 0x15e8, 0x0016, 0x00c6,
+	0x080c, 0x6693, 0x15b0, 0x001e, 0x00c6, 0x2160, 0x080c, 0xd0b0,
+	0x00ce, 0x002e, 0x0026, 0x0016, 0x080c, 0xa91e, 0x2019, 0x0029,
+	0x080c, 0xa404, 0x080c, 0x943d, 0x0076, 0x903e, 0x080c, 0x9306,
+	0x007e, 0x001e, 0x0076, 0x903e, 0x080c, 0xe167, 0x007e, 0x080c,
+	0xa93a, 0x0026, 0xba04, 0x9294, 0xff00, 0x8217, 0x9286, 0x0006,
+	0x0118, 0x9286, 0x0004, 0x1118, 0xbaa0, 0x080c, 0x330b, 0x002e,
+	0xbc84, 0x001e, 0x080c, 0x60ac, 0xbe12, 0xbd16, 0xbc86, 0x9006,
+	0x0010, 0x00ce, 0x001e, 0x015e, 0x003e, 0x00be, 0x00ce, 0x00fe,
+	0x0005, 0x00c6, 0x00d6, 0x00b6, 0x0016, 0x2009, 0x1824, 0x2104,
+	0x9086, 0x0074, 0x1904, 0xe08a, 0x2069, 0x0260, 0x6944, 0x9182,
+	0x0100, 0x06e0, 0x6940, 0x9184, 0x8000, 0x0904, 0xe087, 0x2001,
+	0x197b, 0x2004, 0x9005, 0x1140, 0x6010, 0x2058, 0xb884, 0x9005,
+	0x0118, 0x9184, 0x0800, 0x0598, 0x6948, 0x918a, 0x0001, 0x0648,
+	0x080c, 0xe805, 0x0118, 0x6978, 0xd1fc, 0x11b8, 0x2009, 0x0205,
+	0x200b, 0x0001, 0x693c, 0x81ff, 0x1198, 0x6944, 0x9182, 0x0100,
+	0x02a8, 0x6940, 0x81ff, 0x1178, 0x6948, 0x918a, 0x0001, 0x0288,
+	0x6950, 0x918a, 0x0001, 0x0298, 0x00d0, 0x6017, 0x0100, 0x00a0,
+	0x6017, 0x0300, 0x0088, 0x6017, 0x0500, 0x0070, 0x6017, 0x0700,
+	0x0058, 0x6017, 0x0900, 0x0040, 0x6017, 0x0b00, 0x0028, 0x6017,
+	0x0f00, 0x0010, 0x6017, 0x2d00, 0x9085, 0x0001, 0x0008, 0x9006,
+	0x001e, 0x00be, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00b6, 0x0026,
+	0x0036, 0x0156, 0x6210, 0x2258, 0xbb04, 0x9394, 0x00ff, 0x9286,
+	0x0006, 0x0180, 0x9286, 0x0004, 0x0168, 0x9394, 0xff00, 0x8217,
+	0x9286, 0x0006, 0x0138, 0x9286, 0x0004, 0x0120, 0x080c, 0x66a2,
+	0x0804, 0xe0f6, 0x2011, 0x0276, 0x20a9, 0x0004, 0x0096, 0x2b48,
+	0x2019, 0x000a, 0x080c, 0xbca2, 0x009e, 0x15c8, 0x2011, 0x027a,
+	0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xbca2,
+	0x009e, 0x1568, 0x0046, 0x0016, 0xbaa0, 0x2220, 0x9006, 0x2009,
+	0x1848, 0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xe445,
+	0xb800, 0xc0e5, 0xb802, 0x080c, 0xa91e, 0x2019, 0x0029, 0x080c,
+	0x943d, 0x0076, 0x2039, 0x0000, 0x080c, 0x9306, 0x2c08, 0x080c,
+	0xe167, 0x007e, 0x080c, 0xa93a, 0x2001, 0x0007, 0x080c, 0x660f,
+	0x2001, 0x0007, 0x080c, 0x65e3, 0x001e, 0x004e, 0x9006, 0x015e,
+	0x003e, 0x002e, 0x00be, 0x00ce, 0x0005, 0x00d6, 0x2069, 0x026e,
+	0x6800, 0x9086, 0x0800, 0x0118, 0x6017, 0x0000, 0x0008, 0x9006,
+	0x00de, 0x0005, 0x00b6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156,
+	0x2079, 0x026c, 0x7930, 0x7834, 0x080c, 0x2661, 0x11d0, 0x080c,
+	0x6693, 0x11b8, 0x2011, 0x0270, 0x20a9, 0x0004, 0x0096, 0x2b48,
+	0x2019, 0x000a, 0x080c, 0xbca2, 0x009e, 0x1158, 0x2011, 0x0274,
+	0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xbca2,
+	0x009e, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00be, 0x0005,
+	0x00b6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, 0x0263,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x2661, 0x11d0, 0x080c, 0x6693,
+	0x11b8, 0x2011, 0x0276, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019,
+	0x000a, 0x080c, 0xbca2, 0x009e, 0x1158, 0x2011, 0x027a, 0x20a9,
+	0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xbca2, 0x009e,
+	0x015e, 0x003e, 0x002e, 0x001e, 0x000e, 0x00be, 0x0005, 0x00e6,
+	0x00c6, 0x0086, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0126,
+	0x2091, 0x8000, 0x080c, 0xa97c, 0x0106, 0x190c, 0xa91e, 0x2740,
+	0x2029, 0x19f2, 0x252c, 0x2021, 0x19f9, 0x2424, 0x2061, 0x1ddc,
+	0x2071, 0x1800, 0x7654, 0x7074, 0x81ff, 0x0150, 0x0006, 0x9186,
+	0x1b34, 0x000e, 0x0128, 0x8001, 0x9602, 0x1a04, 0xe20c, 0x0018,
+	0x9606, 0x0904, 0xe20c, 0x080c, 0x8c1f, 0x0904, 0xe203, 0x2100,
+	0x9c06, 0x0904, 0xe203, 0x080c, 0xe486, 0x1904, 0xe203, 0x080c,
+	0xe822, 0x0904, 0xe203, 0x080c, 0xe476, 0x0904, 0xe203, 0x6720,
+	0x9786, 0x0001, 0x1148, 0x080c, 0x33a8, 0x0904, 0xe24e, 0x6004,
+	0x9086, 0x0000, 0x1904, 0xe24e, 0x9786, 0x0004, 0x0904, 0xe24e,
+	0x9786, 0x0007, 0x0904, 0xe203, 0x2500, 0x9c06, 0x0904, 0xe203,
+	0x2400, 0x9c06, 0x0904, 0xe203, 0x88ff, 0x0118, 0x605c, 0x9906,
+	0x15d0, 0x0096, 0x6043, 0xffff, 0x6000, 0x9086, 0x0004, 0x1120,
+	0x0016, 0x080c, 0x1ac5, 0x001e, 0x9786, 0x000a, 0x0148, 0x080c,
+	0xcb91, 0x1130, 0x080c, 0xb693, 0x009e, 0x080c, 0xaceb, 0x0418,
+	0x6014, 0x2048, 0x080c, 0xc97a, 0x01d8, 0x9786, 0x0003, 0x1588,
+	0xa867, 0x0103, 0xa87c, 0xd0cc, 0x0130, 0x0096, 0xa878, 0x2048,
+	0x080c, 0x0ff9, 0x009e, 0xab7a, 0xa877, 0x0000, 0x080c, 0xe79d,
+	0x0016, 0x080c, 0xcc7f, 0x080c, 0x6de2, 0x001e, 0x080c, 0xcb6b,
+	0x009e, 0x080c, 0xaceb, 0x9ce0, 0x001c, 0x2001, 0x181a, 0x2004,
+	0x9c02, 0x1210, 0x0804, 0xe180, 0x010e, 0x190c, 0xa93a, 0x012e,
+	0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee,
+	0x0005, 0x9786, 0x0006, 0x1150, 0x9386, 0x0005, 0x0128, 0x080c,
+	0xe79d, 0x080c, 0xe3e8, 0x08e0, 0x009e, 0x08e8, 0x9786, 0x0009,
+	0x11f8, 0x6000, 0x9086, 0x0004, 0x01c0, 0x6000, 0x9086, 0x0003,
+	0x11a0, 0x080c, 0x96d5, 0x0096, 0x6114, 0x2148, 0x080c, 0xc97a,
+	0x0118, 0x6010, 0x080c, 0x6dee, 0x009e, 0x00c6, 0x080c, 0xacb0,
+	0x00ce, 0x0036, 0x080c, 0x9738, 0x003e, 0x009e, 0x0804, 0xe203,
+	0x9786, 0x000a, 0x0904, 0xe1f3, 0x0804, 0xe1e8, 0x81ff, 0x0904,
+	0xe203, 0x9180, 0x0001, 0x2004, 0x9086, 0x0018, 0x0138, 0x9180,
+	0x0001, 0x2004, 0x9086, 0x002d, 0x1904, 0xe203, 0x6000, 0x9086,
+	0x0002, 0x1904, 0xe203, 0x080c, 0xcb80, 0x0138, 0x080c, 0xcb91,
+	0x1904, 0xe203, 0x080c, 0xb693, 0x0038, 0x080c, 0x326f, 0x080c,
+	0xcb91, 0x1110, 0x080c, 0xb693, 0x080c, 0xaceb, 0x0804, 0xe203,
+	0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, 0x0005, 0x00c6, 0x00e6,
+	0x0016, 0x2c08, 0x2170, 0x9006, 0x080c, 0xe40f, 0x001e, 0x0120,
+	0x6020, 0x9084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xe29d,
+	0xe29d, 0xe29d, 0xe29d, 0xe29d, 0xe29d, 0xe29f, 0xe29d, 0xe29d,
+	0xe29d, 0xe29d, 0xaceb, 0xaceb, 0xe29d, 0x9006, 0x0005, 0x0036,
+	0x0046, 0x0016, 0x7010, 0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00,
+	0x2009, 0x0020, 0x080c, 0xe445, 0x001e, 0x004e, 0x2019, 0x0002,
+	0x080c, 0xdfa1, 0x003e, 0x9085, 0x0001, 0x0005, 0x0096, 0x080c,
+	0xc97a, 0x0140, 0x6014, 0x904d, 0x080c, 0xc566, 0x687b, 0x0005,
+	0x080c, 0x6dee, 0x009e, 0x080c, 0xaceb, 0x9085, 0x0001, 0x0005,
+	0x2001, 0x0001, 0x080c, 0x65cf, 0x0156, 0x0016, 0x0026, 0x0036,
+	0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0276, 0x080c, 0xbc8e,
+	0x003e, 0x002e, 0x001e, 0x015e, 0x9005, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x0086, 0x0076, 0x0066, 0x00b6, 0x0126, 0x2091, 0x8000,
+	0x2740, 0x2061, 0x1ddc, 0x2079, 0x0001, 0x8fff, 0x0904, 0xe338,
+	0x2071, 0x1800, 0x7654, 0x7074, 0x8001, 0x9602, 0x1a04, 0xe338,
+	0x88ff, 0x0120, 0x2800, 0x9c06, 0x1590, 0x2078, 0x080c, 0xe476,
+	0x0570, 0x2400, 0x9c06, 0x0558, 0x6720, 0x9786, 0x0006, 0x1538,
+	0x9786, 0x0007, 0x0520, 0x88ff, 0x1140, 0x6010, 0x9b06, 0x11f8,
+	0x85ff, 0x0118, 0x605c, 0x9106, 0x11d0, 0x0096, 0x601c, 0xd084,
+	0x0140, 0x080c, 0xe6a0, 0x080c, 0xd0b3, 0x080c, 0x1ac5, 0x6023,
+	0x0007, 0x6014, 0x2048, 0x080c, 0xc97a, 0x0120, 0x0046, 0x080c,
+	0xe3e8, 0x004e, 0x009e, 0x080c, 0xaceb, 0x88ff, 0x1198, 0x9ce0,
+	0x001c, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1210, 0x0804, 0xe2ed,
+	0x9006, 0x012e, 0x00be, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee,
+	0x00fe, 0x0005, 0x98c5, 0x0001, 0x0ca0, 0x080c, 0xa91e, 0x00b6,
+	0x0076, 0x0056, 0x0086, 0x9046, 0x2029, 0x0001, 0x2c20, 0x2019,
+	0x0002, 0x6210, 0x2258, 0x0096, 0x904e, 0x080c, 0xa28c, 0x009e,
+	0x008e, 0x903e, 0x080c, 0xa337, 0x080c, 0xe2de, 0x005e, 0x007e,
+	0x00be, 0x080c, 0xa93a, 0x0005, 0x080c, 0xa91e, 0x00b6, 0x0046,
+	0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f,
+	0x900e, 0x0016, 0x0036, 0x080c, 0x6693, 0x1190, 0x0056, 0x0086,
+	0x9046, 0x2508, 0x2029, 0x0001, 0x0096, 0x904e, 0x080c, 0xa28c,
+	0x009e, 0x008e, 0x903e, 0x080c, 0xa337, 0x080c, 0xe2de, 0x005e,
+	0x003e, 0x001e, 0x8108, 0x1f04, 0xe371, 0x015e, 0x00ce, 0x007e,
+	0x005e, 0x004e, 0x00be, 0x080c, 0xa93a, 0x0005, 0x080c, 0xa91e,
+	0x00b6, 0x0076, 0x0056, 0x6210, 0x2258, 0x0086, 0x9046, 0x2029,
+	0x0001, 0x2019, 0x0048, 0x0096, 0x904e, 0x080c, 0xa28c, 0x009e,
+	0x008e, 0x903e, 0x080c, 0xa337, 0x2c20, 0x080c, 0xe2de, 0x005e,
+	0x007e, 0x00be, 0x080c, 0xa93a, 0x0005, 0x080c, 0xa91e, 0x00b6,
+	0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x20a9, 0x0800,
+	0x900e, 0x0016, 0x0036, 0x080c, 0x6693, 0x11a0, 0x0086, 0x9046,
+	0x2828, 0x0046, 0x2021, 0x0001, 0x080c, 0xe684, 0x004e, 0x0096,
+	0x904e, 0x080c, 0xa28c, 0x009e, 0x008e, 0x903e, 0x080c, 0xa337,
+	0x080c, 0xe2de, 0x003e, 0x001e, 0x8108, 0x1f04, 0xe3c1, 0x015e,
+	0x00ce, 0x007e, 0x005e, 0x004e, 0x00be, 0x080c, 0xa93a, 0x0005,
+	0x0016, 0x00f6, 0x080c, 0xc978, 0x0198, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0046, 0x0180, 0xa800, 0x907d, 0x0138, 0xa803, 0x0000,
+	0xab82, 0x080c, 0x6dee, 0x2f48, 0x0cb0, 0xab82, 0x080c, 0x6dee,
+	0x00fe, 0x001e, 0x0005, 0xa800, 0x907d, 0x0130, 0xa803, 0x0000,
+	0x080c, 0x6dee, 0x2f48, 0x0cb8, 0x080c, 0x6dee, 0x0c88, 0x00e6,
+	0x0046, 0x0036, 0x2061, 0x1ddc, 0x9005, 0x1138, 0x2071, 0x1800,
+	0x7454, 0x7074, 0x8001, 0x9402, 0x12f8, 0x2100, 0x9c06, 0x0188,
+	0x6000, 0x9086, 0x0000, 0x0168, 0x6008, 0x9206, 0x1150, 0x6320,
+	0x9386, 0x0009, 0x01b0, 0x6010, 0x91a0, 0x0004, 0x2424, 0x9406,
+	0x0140, 0x9ce0, 0x001c, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1220,
+	0x0c20, 0x9085, 0x0001, 0x0008, 0x9006, 0x003e, 0x004e, 0x00ee,
+	0x0005, 0x631c, 0xd3c4, 0x1d68, 0x0c30, 0x0096, 0x0006, 0x080c,
+	0x1047, 0x000e, 0x090c, 0x0d7d, 0xaae2, 0xa867, 0x010d, 0xa88e,
+	0x0026, 0x2010, 0x080c, 0xc968, 0x2001, 0x0000, 0x0120, 0x2200,
+	0x9080, 0x0017, 0x2004, 0x002e, 0xa87a, 0x9186, 0x0020, 0x0110,
+	0xa8e3, 0xffff, 0xa986, 0xac76, 0xa87f, 0x0000, 0x2001, 0x198d,
+	0x2004, 0xa882, 0x9006, 0xa802, 0xa86a, 0xa88a, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6dee, 0x012e, 0x009e, 0x0005, 0x6700, 0x9786,
+	0x0000, 0x0158, 0x9786, 0x0001, 0x0140, 0x9786, 0x000a, 0x0128,
+	0x9786, 0x0009, 0x0110, 0x9085, 0x0001, 0x0005, 0x00e6, 0x6010,
+	0x9075, 0x0138, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x9206, 0x00ee,
+	0x0005, 0x9085, 0x0001, 0x0cd8, 0x0016, 0x6004, 0x908e, 0x001e,
+	0x11a0, 0x8007, 0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x6023, 0x0005, 0x2001, 0x1986, 0x2004,
+	0x601a, 0x2009, 0x8020, 0x080c, 0x92b0, 0x001e, 0x0005, 0xa001,
+	0xa001, 0x0005, 0x6024, 0xd0e4, 0x0158, 0xd0cc, 0x0118, 0x080c,
+	0xccc6, 0x0030, 0x080c, 0xe6a0, 0x080c, 0x894e, 0x080c, 0xacb0,
+	0x0005, 0x9280, 0x0008, 0x2004, 0x9084, 0x000f, 0x0002, 0xe4d5,
+	0xe4d5, 0xe4d5, 0xe4d7, 0xe4d5, 0xe4d7, 0xe4d7, 0xe4d5, 0xe4d7,
+	0xe4d5, 0xe4d5, 0xe4d5, 0xe4d5, 0xe4d5, 0x9006, 0x0005, 0x9085,
+	0x0001, 0x0005, 0x9280, 0x0008, 0x2004, 0x9084, 0x000f, 0x0002,
+	0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0xe4fb, 0xe4ee,
+	0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0xe4ee, 0x6007, 0x003b,
+	0x602f, 0x0009, 0x6017, 0x2a00, 0x6003, 0x0001, 0x2009, 0x8020,
+	0x080c, 0x92b0, 0x0005, 0x0096, 0x00c6, 0x2260, 0x080c, 0xe6a0,
+	0x604b, 0x0000, 0x6024, 0xc0f4, 0xc0e4, 0x6026, 0x603b, 0x0000,
+	0x00ce, 0x00d6, 0x2268, 0x9186, 0x0007, 0x1904, 0xe554, 0x6814,
+	0x9005, 0x0138, 0x2048, 0xa87c, 0xd0fc, 0x1118, 0x00de, 0x009e,
+	0x08a8, 0x6007, 0x003a, 0x6003, 0x0001, 0x2009, 0x8020, 0x080c,
+	0x92b0, 0x00c6, 0x2d60, 0x6100, 0x9186, 0x0002, 0x1904, 0xe5cb,
+	0x6014, 0x9005, 0x1138, 0x6000, 0x9086, 0x0007, 0x190c, 0x0d7d,
+	0x0804, 0xe5cb, 0x2048, 0x080c, 0xc97a, 0x1130, 0x0028, 0x2048,
+	0xa800, 0x9005, 0x1de0, 0x2900, 0x2048, 0xa87c, 0x9084, 0x0003,
+	0x9086, 0x0002, 0x1168, 0xa87c, 0xc0dc, 0xc0f4, 0xa87e, 0xa880,
+	0xc0fc, 0xa882, 0x2009, 0x0043, 0x080c, 0xddde, 0x0804, 0xe5cb,
+	0x2009, 0x0041, 0x0804, 0xe5c5, 0x9186, 0x0005, 0x15a0, 0x6814,
+	0x2048, 0xa87c, 0xd0bc, 0x1120, 0x00de, 0x009e, 0x0804, 0xe4ee,
+	0xd0b4, 0x0128, 0xd0fc, 0x090c, 0x0d7d, 0x0804, 0xe50f, 0x6007,
+	0x003a, 0x6003, 0x0001, 0x2009, 0x8020, 0x080c, 0x92b0, 0x00c6,
+	0x2d60, 0x6100, 0x9186, 0x0002, 0x0120, 0x9186, 0x0004, 0x1904,
+	0xe5cb, 0x6814, 0x2048, 0xa97c, 0xc1f4, 0xc1dc, 0xa97e, 0xa980,
+	0xc1fc, 0xc1bc, 0xa982, 0x00f6, 0x2c78, 0x080c, 0x1778, 0x00fe,
+	0x2009, 0x0042, 0x04d0, 0x0036, 0x080c, 0x1047, 0x090c, 0x0d7d,
+	0xa867, 0x010d, 0x9006, 0xa802, 0xa86a, 0xa88a, 0x2d18, 0xab8e,
+	0xa887, 0x0045, 0x2c00, 0xa892, 0x6038, 0xa8a2, 0x2360, 0x6024,
+	0xc0dd, 0x6026, 0x6010, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x2004,
+	0x635c, 0xab7a, 0xa876, 0x9006, 0xa87e, 0xa882, 0xad9a, 0xae96,
+	0xa89f, 0x0001, 0x080c, 0x6dee, 0x2019, 0x0045, 0x6008, 0x2068,
+	0x080c, 0xdfa1, 0x2d00, 0x600a, 0x6023, 0x0006, 0x6003, 0x0007,
+	0x901e, 0x631a, 0x634a, 0x003e, 0x0038, 0x604b, 0x0000, 0x6003,
+	0x0007, 0x080c, 0xddde, 0x00ce, 0x00de, 0x009e, 0x0005, 0x9186,
+	0x0013, 0x1128, 0x6004, 0x9082, 0x0085, 0x2008, 0x00c2, 0x9186,
+	0x0027, 0x1178, 0x080c, 0x967a, 0x0036, 0x0096, 0x6014, 0x2048,
+	0x2019, 0x0004, 0x080c, 0xe3e8, 0x009e, 0x003e, 0x080c, 0x9738,
+	0x0005, 0x9186, 0x0014, 0x0d70, 0x080c, 0xad6a, 0x0005, 0xe5fe,
+	0xe5fc, 0xe5fc, 0xe5fc, 0xe5fc, 0xe5fc, 0xe5fe, 0xe5fc, 0xe5fc,
+	0xe5fc, 0xe5fc, 0xe5fc, 0xe5fc, 0x080c, 0x0d7d, 0x6003, 0x000c,
+	0x080c, 0x9738, 0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085,
+	0x0208, 0x001a, 0x080c, 0xad6a, 0x0005, 0xe61a, 0xe61a, 0xe61a,
+	0xe61a, 0xe61c, 0xe63c, 0xe61a, 0xe61a, 0xe61a, 0xe61a, 0xe61a,
+	0xe61a, 0xe61a, 0x080c, 0x0d7d, 0x00d6, 0x2c68, 0x080c, 0xac5a,
+	0x01b0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0x026e, 0x210c,
+	0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x600b, 0xffff, 0x6910,
+	0x6112, 0x6023, 0x0004, 0x2009, 0x8020, 0x080c, 0x92b0, 0x2d60,
+	0x080c, 0xacb0, 0x00de, 0x0005, 0x080c, 0xacb0, 0x0005, 0x00e6,
+	0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0ec, 0x00ee, 0x0005,
+	0x2009, 0x1867, 0x210c, 0xd1ec, 0x05b0, 0x6003, 0x0002, 0x6024,
+	0xc0e5, 0x6026, 0xd0cc, 0x0150, 0x2001, 0x1987, 0x2004, 0x604a,
+	0x2009, 0x1867, 0x210c, 0xd1f4, 0x1520, 0x00a0, 0x2009, 0x1867,
+	0x210c, 0xd1f4, 0x0128, 0x6024, 0xc0e4, 0x6026, 0x9006, 0x00d8,
+	0x2001, 0x1987, 0x200c, 0x2001, 0x1985, 0x2004, 0x9100, 0x9080,
+	0x000a, 0x604a, 0x6010, 0x00b6, 0x2058, 0xb8bc, 0x00be, 0x0008,
+	0x2104, 0x9005, 0x0118, 0x9088, 0x0003, 0x0cd0, 0x2c0a, 0x600f,
+	0x0000, 0x9085, 0x0001, 0x0005, 0x0016, 0x00c6, 0x00e6, 0x615c,
+	0xb8bc, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118, 0x605c, 0x9106,
+	0x1138, 0x600c, 0x2072, 0x080c, 0x894e, 0x080c, 0xacb0, 0x0010,
+	0x9cf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce, 0x001e, 0x0005,
+	0x00d6, 0x00b6, 0x6010, 0x2058, 0xb8bc, 0x2068, 0x9005, 0x0130,
+	0x9c06, 0x0110, 0x680c, 0x0cd0, 0x600c, 0x680e, 0x00be, 0x00de,
+	0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0x182c, 0x2204, 0x9084,
+	0x00ff, 0x2019, 0x026e, 0x2334, 0x9636, 0x1508, 0x8318, 0x2334,
+	0x2204, 0x9084, 0xff00, 0x9636, 0x11d0, 0x2011, 0x0270, 0x20a9,
+	0x0004, 0x6010, 0x0096, 0x2048, 0x2019, 0x000a, 0x080c, 0xbca2,
+	0x009e, 0x1168, 0x2011, 0x0274, 0x20a9, 0x0004, 0x6010, 0x0096,
+	0x2048, 0x2019, 0x0006, 0x080c, 0xbca2, 0x009e, 0x1100, 0x015e,
+	0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, 0x1800, 0x080c, 0x6025,
+	0x080c, 0x3011, 0x00ee, 0x0005, 0x0096, 0x0026, 0x080c, 0x1047,
+	0x090c, 0x0d7d, 0xa85c, 0x9080, 0x001a, 0x20a0, 0x20a9, 0x000c,
+	0xa860, 0x20e8, 0x9006, 0x4004, 0x9186, 0x0046, 0x1118, 0xa867,
+	0x0136, 0x0038, 0xa867, 0x0138, 0x9186, 0x0041, 0x0110, 0xa87b,
+	0x0001, 0x7038, 0x9084, 0xff00, 0x7240, 0x9294, 0xff00, 0x8007,
+	0x9215, 0xaa9a, 0x9186, 0x0046, 0x1168, 0x7038, 0x9084, 0x00ff,
+	0x723c, 0x9294, 0xff00, 0x9215, 0xaa9e, 0x723c, 0x9294, 0x00ff,
+	0xaaa2, 0x0060, 0x7040, 0x9084, 0x00ff, 0x7244, 0x9294, 0xff00,
+	0x9215, 0xaa9e, 0x7244, 0x9294, 0x00ff, 0xaaa2, 0x9186, 0x0046,
+	0x1118, 0x9e90, 0x0012, 0x0010, 0x9e90, 0x001a, 0x2204, 0x8007,
+	0xa8a6, 0x8210, 0x2204, 0x8007, 0xa8aa, 0x8210, 0x2204, 0x8007,
+	0xa8ae, 0x8210, 0x2204, 0x8007, 0xa8b2, 0x8210, 0x9186, 0x0046,
+	0x11b8, 0x9e90, 0x0016, 0x2204, 0x8007, 0xa8b6, 0x8210, 0x2204,
+	0x8007, 0xa8ba, 0x8210, 0x2204, 0x8007, 0xa8be, 0x8210, 0x2204,
+	0x8007, 0xa8c2, 0x8210, 0x2011, 0x0205, 0x2013, 0x0001, 0x00b0,
+	0x9e90, 0x001e, 0x2204, 0x8007, 0xa8b6, 0x8210, 0x2204, 0x8007,
+	0xa8ba, 0x2011, 0x0205, 0x2013, 0x0001, 0x2011, 0x0260, 0x2204,
+	0x8007, 0xa8be, 0x8210, 0x2204, 0x8007, 0xa8c2, 0x9186, 0x0046,
+	0x1118, 0x2011, 0x0262, 0x0010, 0x2011, 0x026a, 0x0146, 0x01d6,
+	0x0036, 0x20a9, 0x0001, 0x2019, 0x0008, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0031, 0x20a0, 0x2204, 0x8007, 0x4004, 0x8210, 0x8319,
+	0x1dd0, 0x003e, 0x01ce, 0x013e, 0x2011, 0x0205, 0x2013, 0x0000,
+	0x002e, 0x080c, 0x6dee, 0x009e, 0x0005, 0x00e6, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0fc, 0x0108, 0x0011, 0x00ee, 0x0005,
+	0xa880, 0xc0e5, 0xa882, 0x0005, 0x00e6, 0x00d6, 0x00c6, 0x0076,
+	0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091, 0x8000,
+	0x2029, 0x19f2, 0x252c, 0x2021, 0x19f9, 0x2424, 0x2061, 0x1ddc,
+	0x2071, 0x1800, 0x7654, 0x7074, 0x9606, 0x0578, 0x6720, 0x9786,
+	0x0001, 0x0118, 0x9786, 0x0008, 0x1500, 0x2500, 0x9c06, 0x01e8,
+	0x2400, 0x9c06, 0x01d0, 0x080c, 0xe476, 0x01b8, 0x080c, 0xe486,
+	0x11a0, 0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x1ac5,
+	0x001e, 0x080c, 0xcb80, 0x1110, 0x080c, 0x326f, 0x080c, 0xcb91,
+	0x1110, 0x080c, 0xb693, 0x080c, 0xaceb, 0x9ce0, 0x001c, 0x2001,
+	0x181a, 0x2004, 0x9c02, 0x1208, 0x0858, 0x012e, 0x001e, 0x002e,
+	0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005,
+	0x2001, 0x1810, 0x2004, 0xd0dc, 0x0005, 0x0006, 0x2001, 0x1837,
+	0x2004, 0xd09c, 0x000e, 0x0005, 0x0006, 0x0036, 0x0046, 0x080c,
+	0xd09b, 0x0168, 0x2019, 0xffff, 0x9005, 0x0128, 0x6010, 0x00b6,
+	0x2058, 0xbba0, 0x00be, 0x2021, 0x0004, 0x080c, 0x4d09, 0x004e,
+	0x003e, 0x000e, 0x6004, 0x9086, 0x0001, 0x1128, 0x080c, 0xa404,
+	0x080c, 0xaceb, 0x9006, 0x0005, 0x00e6, 0x00c6, 0x00b6, 0x0046,
+	0x2061, 0x1ddc, 0x2071, 0x1800, 0x7454, 0x7074, 0x8001, 0x9402,
+	0x12d8, 0x2100, 0x9c06, 0x0168, 0x6000, 0x9086, 0x0000, 0x0148,
+	0x6010, 0x2058, 0xb8a0, 0x9206, 0x1120, 0x6004, 0x9086, 0x0002,
+	0x0140, 0x9ce0, 0x001c, 0x2001, 0x181a, 0x2004, 0x9c02, 0x1220,
+	0x0c40, 0x9085, 0x0001, 0x0008, 0x9006, 0x004e, 0x00be, 0x00ce,
+	0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x0016, 0x2091, 0x8000,
+	0x2071, 0x1840, 0xd5a4, 0x0118, 0x7004, 0x8000, 0x7006, 0xd5b4,
+	0x0118, 0x7000, 0x8000, 0x7002, 0xd5ac, 0x0178, 0x2500, 0x9084,
+	0x0007, 0x908e, 0x0003, 0x0148, 0x908e, 0x0004, 0x0130, 0x908e,
+	0x0005, 0x0118, 0x2071, 0xfff6, 0x0089, 0x001e, 0x00ee, 0x000e,
+	0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071,
+	0xffee, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e05, 0x8000,
+	0x2077, 0x1220, 0x8e70, 0x2e05, 0x8000, 0x2077, 0x0005, 0x00e6,
+	0x2071, 0xffec, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xfff0,
+	0x0c69, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000,
+	0x2071, 0x1840, 0x7014, 0x8000, 0x7016, 0x00ee, 0x000e, 0x012e,
+	0x0005, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040,
+	0x0080, 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000,
+	0x8000, 0x3f07
+};
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2322ipx_length01 = 0xe0c2;
+#else
+unsigned short risc_code_length01 = 0xe0c2;
+#endif
+
+/*
+ *
+ */
+
+unsigned long rseqipx_code_addr01 = 0x0001c000 ;
+unsigned short rseqipx_code01[] = { 
+0x000b, 0x0003, 0x0000, 0x09e6, 0x0001, 0xc000, 0x0008, 0x8064,
+	0x0000, 0x0010, 0x0000, 0x8066, 0x0008, 0x0101, 0x0003, 0xc007,
+	0x0008, 0x80e0, 0x0008, 0xff00, 0x0000, 0x80e2, 0x0008, 0xff00,
+	0x0008, 0x0162, 0x0000, 0x8066, 0x0008, 0xa101, 0x000b, 0xc00f,
+	0x0008, 0x0d02, 0x0000, 0x8060, 0x0000, 0x0400, 0x0003, 0x60c2,
+	0x0003, 0x5817, 0x000b, 0x7ae3, 0x000b, 0x521c, 0x000b, 0xc813,
+	0x0009, 0xbac0, 0x0000, 0x008a, 0x0003, 0x8813, 0x0000, 0x15fc,
+	0x000b, 0xb013, 0x0009, 0xc4c0, 0x0000, 0x7000, 0x0001, 0xffa0,
+	0x0000, 0x2000, 0x0003, 0x939b, 0x0008, 0x808c, 0x0000, 0x0001,
+	0x0007, 0x0000, 0x0007, 0x0000, 0x0000, 0x40d4, 0x000a, 0x4047,
+	0x0008, 0x808c, 0x0000, 0x0002, 0x0007, 0x0000, 0x0003, 0x082e,
+	0x0000, 0x4022, 0x0003, 0x0034, 0x0008, 0x4122, 0x0009, 0xeac0,
+	0x0008, 0xff00, 0x0009, 0xffe0, 0x0008, 0x0500, 0x000b, 0x0bc2,
+	0x0002, 0x4447, 0x0003, 0x8bbf, 0x0008, 0x0bfe, 0x0001, 0x11a0,
+	0x000b, 0x13a1, 0x0001, 0x0ca0, 0x000b, 0x13a1, 0x0001, 0x9180,
+	0x0000, 0x0004, 0x0000, 0x8060, 0x0000, 0x0400, 0x0008, 0x7f62,
+	0x0000, 0x8066, 0x0008, 0x0009, 0x000b, 0xc042, 0x0008, 0x808c,
+	0x0008, 0x0000, 0x0008, 0x0060, 0x0008, 0x8062, 0x0000, 0x0004,
+	0x0000, 0x8066, 0x0000, 0x0411, 0x0003, 0xc04a, 0x0000, 0x03fe,
+	0x0001, 0x43e0, 0x0003, 0x8b9e, 0x0009, 0xc2c0, 0x0008, 0x00ff,
+	0x0001, 0x02e0, 0x0003, 0x8b9e, 0x0001, 0x9180, 0x0008, 0x0005,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0000, 0x0019, 0x000b, 0xc059, 0x0002, 0x0240, 0x000b, 0x0b9b,
+	0x0008, 0x00fc, 0x0003, 0x339e, 0x000a, 0x0244, 0x000b, 0x086b,
+	0x000c, 0x01f5, 0x0001, 0x9180, 0x0000, 0x0007, 0x0008, 0x7f62,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0002, 0x0234, 0x0008, 0x7f04,
+	0x0000, 0x8066, 0x0000, 0x040a, 0x000b, 0xc06a, 0x000a, 0x0248,
+	0x000b, 0x0875, 0x0001, 0x9180, 0x0008, 0x0006, 0x0008, 0x7f62,
+	0x0008, 0x8002, 0x0008, 0x0003, 0x0000, 0x8066, 0x0000, 0x020a,
+	0x000b, 0xc074, 0x0000, 0x112a, 0x0008, 0x002e, 0x0008, 0x022c,
+	0x0002, 0x3a44, 0x0003, 0x8813, 0x0008, 0x808c, 0x0000, 0x0002,
+	0x0008, 0x1760, 0x0008, 0x8062, 0x0008, 0x000f, 0x0000, 0x8066,
+	0x0008, 0x0011, 0x000b, 0xc081, 0x0008, 0x01fe, 0x0009, 0x42e0,
+	0x000b, 0x8b8e, 0x0000, 0x00fe, 0x0001, 0x43e0, 0x000b, 0x8b8e,
+	0x0000, 0x1734, 0x0000, 0x1530, 0x0008, 0x1632, 0x0008, 0x0d2a,
+	0x0001, 0x9880, 0x0008, 0x0012, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x1e0a, 0x000b, 0xc093,
+	0x0008, 0x808a, 0x0008, 0x0003, 0x0000, 0x1a60, 0x0008, 0x8062,
+	0x0000, 0x0002, 0x0003, 0x5899, 0x0000, 0x8066, 0x0000, 0x3679,
+	0x000b, 0xc09c, 0x000b, 0x589d, 0x0008, 0x8054, 0x0008, 0x0011,
+	0x0000, 0x8074, 0x0008, 0x1010, 0x0008, 0x1efc, 0x0003, 0x3013,
+	0x0004, 0x00a6, 0x0003, 0x0013, 0x0000, 0x1c60, 0x0000, 0x1b62,
+	0x0000, 0x8066, 0x0008, 0x0231, 0x000b, 0xc0aa, 0x000b, 0x58ab,
+	0x0008, 0x0140, 0x0000, 0x0242, 0x0002, 0x1f43, 0x0003, 0x88b5,
+	0x0000, 0x0d44, 0x0008, 0x0d46, 0x0008, 0x0348, 0x0008, 0x044a,
+	0x0003, 0x00b9, 0x0008, 0x0344, 0x0008, 0x0446, 0x0008, 0x0548,
+	0x0000, 0x064a, 0x000a, 0x1948, 0x000b, 0x08bc, 0x0008, 0x0d4a,
+	0x000b, 0x58bc, 0x0008, 0x8054, 0x0000, 0x0001, 0x0000, 0x8074,
+	0x0008, 0x2020, 0x000f, 0x4000, 0x0000, 0x4820, 0x0008, 0x0bfe,
+	0x0009, 0x10a0, 0x0003, 0x1123, 0x0001, 0x0ca0, 0x0003, 0x1123,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0009, 0x9080, 0x0000, 0x0008,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0009, 0x000b, 0xc0cf,
+	0x0001, 0x80e0, 0x0008, 0x0003, 0x000b, 0x8923, 0x0000, 0x49b4,
+	0x0002, 0x4b4e, 0x000b, 0x892c, 0x0008, 0x808a, 0x0000, 0x0004,
+	0x0000, 0x18fe, 0x0001, 0x10e0, 0x000b, 0x88dd, 0x0002, 0x192f,
+	0x0008, 0x7f32, 0x0008, 0x15fe, 0x0001, 0x10e0, 0x000b, 0x88e2,
+	0x0002, 0x162f, 0x0008, 0x7f2c, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0009, 0x9080, 0x0000, 0x0007, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x0009, 0x0003, 0xc0e9, 0x000a, 0x004f, 0x000b, 0x891a,
+	0x000a, 0x0040, 0x0003, 0x0904, 0x0002, 0x004e, 0x0003, 0x0904,
+	0x0002, 0x0030, 0x0002, 0x7f2f, 0x0000, 0x7f00, 0x0000, 0x8066,
+	0x0008, 0x000a, 0x000b, 0xc0f5, 0x0008, 0x1010, 0x0004, 0x01dc,
+	0x000b, 0xb0fd, 0x000c, 0x0362, 0x000c, 0x01c6, 0x000b, 0x7814,
+	0x0003, 0x0013, 0x0000, 0x0806, 0x0008, 0x8010, 0x0000, 0x001f,
+	0x000c, 0x0362, 0x0000, 0x0310, 0x000c, 0x0362, 0x0003, 0x00fb,
+	0x000a, 0x002f, 0x0000, 0x7f00, 0x0000, 0x8066, 0x0008, 0x000a,
+	0x000b, 0xc108, 0x000c, 0x019f, 0x000a, 0x0040, 0x000b, 0x091d,
+	0x000c, 0x020c, 0x0000, 0x8000, 0x0000, 0x0002, 0x0000, 0x8060,
+	0x0000, 0x0400, 0x0009, 0x9080, 0x0008, 0x0006, 0x0008, 0x7f62,
+	0x0000, 0x8066, 0x0008, 0x000a, 0x000b, 0xc116, 0x0000, 0x8072,
+	0x0000, 0x4000, 0x0003, 0x00fb, 0x0008, 0x8010, 0x0008, 0x001e,
+	0x000b, 0x011f, 0x0008, 0x8010, 0x0008, 0x001d, 0x000c, 0x0362,
+	0x0008, 0x1010, 0x000c, 0x0362, 0x000b, 0x0014, 0x0002, 0x4b4e,
+	0x0003, 0x0929, 0x0008, 0x808a, 0x0000, 0x0004, 0x000b, 0x6129,
+	0x000f, 0x8000, 0x0008, 0x808a, 0x0000, 0x0004, 0x000b, 0x0014,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0009, 0x9080, 0x0008, 0x0011,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0009, 0x0003, 0xc133,
+	0x000a, 0x004f, 0x0003, 0x8990, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0009, 0x9080, 0x0008, 0x0005, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x0009, 0x000b, 0xc13d, 0x0008, 0x0060, 0x0008, 0x8062,
+	0x0000, 0x001f, 0x0000, 0x8066, 0x0000, 0x0209, 0x000b, 0xc143,
+	0x000a, 0x014b, 0x000b, 0x0990, 0x0008, 0x8062, 0x0008, 0x000f,
+	0x0000, 0x8066, 0x0000, 0x0211, 0x000b, 0xc14a, 0x0008, 0x01fe,
+	0x0001, 0x02d0, 0x0003, 0x8990, 0x0004, 0x01a8, 0x000b, 0x0990,
+	0x0008, 0x03a0, 0x0008, 0x8004, 0x0000, 0x0002, 0x0000, 0x8006,
+	0x0000, 0x0043, 0x0008, 0x4908, 0x0008, 0x808a, 0x0000, 0x0004,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0009, 0x9080, 0x0008, 0x0000,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x041a, 0x0003, 0xc15f,
+	0x000b, 0xe160, 0x0008, 0x4908, 0x0008, 0x480a, 0x0008, 0x808a,
+	0x0000, 0x0004, 0x0008, 0x0060, 0x0008, 0x8062, 0x0008, 0x002b,
+	0x0000, 0x8066, 0x0000, 0x0411, 0x0003, 0xc16a, 0x0008, 0x04fe,
+	0x0009, 0x02a0, 0x0003, 0x9171, 0x0002, 0x0500, 0x000b, 0x098d,
+	0x0003, 0x0172, 0x0000, 0x05fe, 0x0001, 0x03a0, 0x000b, 0x118d,
+	0x0000, 0x0d0c, 0x0008, 0x0d0e, 0x0008, 0x0d10, 0x0000, 0x0d12,
+	0x0008, 0x0060, 0x0008, 0x8062, 0x0000, 0x000d, 0x0000, 0x8066,
+	0x0008, 0x0832, 0x0003, 0xc17d, 0x0000, 0x800a, 0x0000, 0x8005,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0009, 0x9080, 0x0008, 0x0011,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0a12, 0x0003, 0xc187,
+	0x0008, 0x5006, 0x0008, 0x100e, 0x0004, 0x01b3, 0x000b, 0x7814,
+	0x0003, 0x0013, 0x0008, 0x0208, 0x0008, 0x030a, 0x0003, 0x0174,
+	0x000c, 0x019f, 0x0008, 0x808a, 0x0000, 0x0004, 0x0008, 0x8010,
+	0x0008, 0x0021, 0x000c, 0x0362, 0x0008, 0x1010, 0x000c, 0x0362,
+	0x0000, 0x4810, 0x000c, 0x0362, 0x0008, 0x4910, 0x000c, 0x0362,
+	0x0008, 0x808a, 0x0000, 0x0004, 0x000b, 0x0014, 0x0000, 0x8060,
+	0x0000, 0x0400, 0x0009, 0x9080, 0x0000, 0x0002, 0x0008, 0x7f62,
+	0x0000, 0x8066, 0x0008, 0xb40a, 0x0003, 0xc1a6, 0x000f, 0x4000,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x0a62, 0x0000, 0x8066,
+	0x0000, 0x0411, 0x000b, 0xc1ad, 0x0002, 0x0210, 0x0001, 0xffc0,
+	0x0000, 0x0007, 0x0009, 0x03e0, 0x000f, 0x4000, 0x0000, 0x8060,
+	0x0000, 0x0400, 0x0001, 0x8380, 0x0000, 0x0002, 0x0009, 0x0a80,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0000, 0x0e0a, 0x0003, 0xc1bb,
+	0x0002, 0x0300, 0x0001, 0xffc0, 0x0000, 0x0007, 0x0000, 0x7f06,
+	0x0002, 0x0a00, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x060a,
+	0x000b, 0xc1c4, 0x000f, 0x4000, 0x0000, 0x0da0, 0x0008, 0x0da2,
+	0x0008, 0x0da4, 0x0009, 0x8880, 0x0000, 0x0001, 0x0008, 0x7f62,
+	0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x8066, 0x0008, 0xa012,
+	0x0000, 0x0da6, 0x0008, 0x0da8, 0x0000, 0x0daa, 0x0000, 0x0dac,
+	0x0003, 0xc1d4, 0x0009, 0x8880, 0x0008, 0x0009, 0x0008, 0x7f62,
+	0x0000, 0x8066, 0x0008, 0xa03a, 0x000b, 0xc1da, 0x000f, 0x4000,
+	0x0009, 0x8880, 0x0008, 0x0005, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0009, 0x000b, 0xc1e3,
+	0x0008, 0x0060, 0x0008, 0x8062, 0x0000, 0x000d, 0x0000, 0x8066,
+	0x0008, 0x0021, 0x000b, 0xc1e9, 0x0000, 0x00fe, 0x0001, 0x01d0,
+	0x000b, 0x89f2, 0x0008, 0x02fe, 0x0009, 0x03d0, 0x0003, 0x09f2,
+	0x0000, 0x0d06, 0x000f, 0x4000, 0x0000, 0x8006, 0x0000, 0x0001,
+	0x000f, 0x4000, 0x0008, 0x0060, 0x0008, 0x8062, 0x0008, 0x002b,
+	0x0000, 0x8066, 0x0008, 0xa041, 0x0003, 0xc1fa, 0x0002, 0x0243,
+	0x000b, 0x8a01, 0x0000, 0x54ac, 0x0000, 0x55ae, 0x0008, 0x0da8,
+	0x0000, 0x0daa, 0x0000, 0x50b0, 0x0000, 0x51b2, 0x0000, 0x0db4,
+	0x0008, 0x0db6, 0x0008, 0x0060, 0x0008, 0x8062, 0x0000, 0x0007,
+	0x0000, 0x8066, 0x0008, 0xa452, 0x0003, 0xc20a, 0x000f, 0x4000,
+	0x000a, 0x3945, 0x000b, 0x8a16, 0x0000, 0x8072, 0x0008, 0x4040,
+	0x0007, 0x0000, 0x000a, 0x3945, 0x0003, 0x8a14, 0x000f, 0x4000,
+	0x0000, 0x8072, 0x0000, 0x4000, 0x0007, 0x0000, 0x0007, 0x0000,
+	0x0007, 0x0000, 0x000a, 0x3945, 0x0003, 0x0a0e, 0x000b, 0x0216,
+	0x000a, 0x3a40, 0x000b, 0x8817, 0x0001, 0xabd0, 0x0008, 0x0000,
+	0x0000, 0x7f24, 0x000b, 0x5a21, 0x0008, 0x8054, 0x0000, 0x0002,
+	0x0002, 0x1242, 0x0003, 0x0a67, 0x000a, 0x3a45, 0x000b, 0x0a56,
+	0x000a, 0x1e10, 0x0000, 0x7f3c, 0x000b, 0x0a53, 0x0002, 0x1d00,
+	0x0000, 0x7f3a, 0x0000, 0x0d60, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x0009, 0x000b, 0xc231, 0x0008, 0x00fc, 0x000b, 0xb250,
+	0x0000, 0x1c60, 0x0008, 0x8062, 0x0000, 0x0001, 0x0000, 0x8066,
+	0x0008, 0x0009, 0x0003, 0xc239, 0x0008, 0x00fc, 0x000b, 0x3377,
+	0x0000, 0x0038, 0x0008, 0x0060, 0x0008, 0x8062, 0x0000, 0x0019,
+	0x0000, 0x8066, 0x0008, 0x0009, 0x0003, 0xc242, 0x0009, 0x80c0,
+	0x0008, 0x00ff, 0x0008, 0x7f3e, 0x0000, 0x0d60, 0x0008, 0x0efe,
+	0x0001, 0x1f80, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0009,
+	0x000b, 0xc24c, 0x0008, 0x003a, 0x0000, 0x1dfe, 0x0003, 0x022d,
+	0x0008, 0x0036, 0x0004, 0x00a6, 0x000b, 0x0267, 0x0000, 0x8074,
+	0x0000, 0x2000, 0x000b, 0x0267, 0x0002, 0x3a44, 0x000b, 0x0ba4,
+	0x0000, 0x8074, 0x0000, 0x1000, 0x0001, 0xadd0, 0x0008, 0x0000,
+	0x0008, 0x7f0e, 0x0003, 0xb374, 0x0001, 0xa7d0, 0x0008, 0x0000,
+	0x0000, 0x7f00, 0x0009, 0xa6d0, 0x0008, 0x0000, 0x0009, 0x00d0,
+	0x0003, 0x8a77, 0x0000, 0x8074, 0x0008, 0x4040, 0x0003, 0x5a67,
+	0x000b, 0x521c, 0x000a, 0x3a46, 0x0003, 0x8a77, 0x0002, 0x3a47,
+	0x000b, 0x0a72, 0x0008, 0x8054, 0x0000, 0x0004, 0x0000, 0x8074,
+	0x0000, 0x8000, 0x0003, 0x02d7, 0x0009, 0x92c0, 0x0000, 0x0fc8,
+	0x000b, 0x0813, 0x000a, 0x1246, 0x0003, 0x8b6e, 0x0000, 0x1a60,
+	0x0008, 0x8062, 0x0000, 0x0002, 0x0000, 0x8066, 0x0000, 0x367a,
+	0x000b, 0xc27c, 0x0009, 0x92c0, 0x0008, 0x0780, 0x000b, 0x8b88,
+	0x0002, 0x124b, 0x0003, 0x0a85, 0x0002, 0x2e4d, 0x0002, 0x2e4d,
+	0x0003, 0x0b74, 0x000a, 0x3a46, 0x0003, 0x8a95, 0x000b, 0x5a87,
+	0x0008, 0x8054, 0x0000, 0x0004, 0x000a, 0x1243, 0x0003, 0x0ad5,
+	0x0008, 0x8010, 0x0000, 0x000d, 0x000c, 0x0362, 0x000a, 0x1948,
+	0x0003, 0x0a92, 0x000c, 0x0357, 0x0000, 0x1810, 0x000c, 0x0362,
+	0x000b, 0x02d5, 0x000a, 0x1948, 0x000b, 0x0a99, 0x000a, 0x1243,
+	0x0003, 0x0b77, 0x000a, 0x194d, 0x0003, 0x0a9d, 0x000a, 0x1243,
+	0x0003, 0x0b7e, 0x0003, 0x5a9d, 0x0008, 0x8054, 0x0000, 0x0004,
+	0x000a, 0x192e, 0x0008, 0x7f32, 0x000a, 0x1947, 0x000b, 0x0acf,
+	0x0002, 0x194f, 0x0003, 0x0aad, 0x000c, 0x0357, 0x0000, 0x1810,
+	0x0004, 0x01dc, 0x0003, 0xb2c8, 0x000c, 0x0362, 0x000c, 0x01c6,
+	0x000b, 0x02d5, 0x0000, 0x1a60, 0x0008, 0x8062, 0x0000, 0x001f,
+	0x0000, 0x8066, 0x0008, 0x0009, 0x0003, 0xc2b2, 0x000a, 0x004c,
+	0x0003, 0x8acf, 0x0000, 0x8060, 0x0000, 0x0400, 0x0001, 0x9880,
+	0x0000, 0x0007, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0000, 0x320a,
+	0x000b, 0xc2bc, 0x0000, 0x8060, 0x0000, 0x0400, 0x0001, 0x9880,
+	0x0008, 0x0012, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x1e0a,
+	0x000b, 0xc2c4, 0x0000, 0x1826, 0x0000, 0x1928, 0x000b, 0x02d5,
+	0x0000, 0x0806, 0x0008, 0x8010, 0x0000, 0x001f, 0x000c, 0x0362,
+	0x0000, 0x0310, 0x000c, 0x0362, 0x000b, 0x02d5, 0x000c, 0x0357,
+	0x0008, 0x8010, 0x0000, 0x0001, 0x000c, 0x0362, 0x0000, 0x1810,
+	0x000c, 0x0362, 0x0000, 0x8074, 0x0008, 0xf000, 0x0000, 0x0d30,
+	0x0002, 0x3a42, 0x0003, 0x8add, 0x0000, 0x15fc, 0x000b, 0xb07a,
+	0x0003, 0x0013, 0x0000, 0x8074, 0x0000, 0x0501, 0x0008, 0x8010,
+	0x0008, 0x000c, 0x000c, 0x0362, 0x0003, 0x0013, 0x0009, 0xbbe0,
+	0x0008, 0x0030, 0x0003, 0x8af9, 0x0000, 0x18fe, 0x0009, 0x3ce0,
+	0x000b, 0x0af6, 0x0008, 0x15fe, 0x0009, 0x3ce0, 0x000b, 0x0af6,
+	0x0008, 0x13fe, 0x0009, 0x3ce0, 0x000b, 0x8af2, 0x0004, 0x0350,
+	0x0008, 0x0d26, 0x0003, 0x02f3, 0x000c, 0x0352, 0x0008, 0x8076,
+	0x0000, 0x0040, 0x000b, 0x034d, 0x0008, 0x8076, 0x0008, 0x0041,
+	0x000b, 0x034d, 0x0009, 0xbbe0, 0x0000, 0x0032, 0x000b, 0x8afe,
+	0x0008, 0x3c1e, 0x000b, 0x034d, 0x0009, 0xbbe0, 0x0000, 0x003b,
+	0x000b, 0x8b03, 0x0000, 0x3cdc, 0x000b, 0x034d, 0x0009, 0xbbe0,
+	0x0008, 0x0035, 0x000b, 0x8b09, 0x0000, 0x8072, 0x0000, 0x8000,
+	0x0003, 0x04b1, 0x0009, 0xbbe0, 0x0008, 0x0036, 0x0003, 0x0bd4,
+	0x0009, 0xbbe0, 0x0000, 0x0037, 0x000b, 0x8b2e, 0x0000, 0x18fe,
+	0x0009, 0x3ce0, 0x0003, 0x8af6, 0x0008, 0x8076, 0x0000, 0x0040,
+	0x0000, 0x1a60, 0x0008, 0x8062, 0x0000, 0x000d, 0x0009, 0xa6d0,
+	0x0008, 0x0000, 0x0008, 0x7f04, 0x0001, 0xa7d0, 0x0008, 0x0000,
+	0x0000, 0x7f06, 0x0001, 0xa8d0, 0x0008, 0x0000, 0x0008, 0x7f08,
+	0x0009, 0xa9d0, 0x0008, 0x0000, 0x0000, 0x7f0a, 0x0000, 0x8066,
+	0x0000, 0x0422, 0x0003, 0xc325, 0x000c, 0x0357, 0x0008, 0x8054,
+	0x0000, 0x0004, 0x0000, 0x8074, 0x0008, 0xf000, 0x0000, 0x8072,
+	0x0000, 0x8000, 0x0003, 0x02d7, 0x0009, 0xbbe0, 0x0000, 0x0038,
+	0x0003, 0x8b40, 0x0000, 0x18fe, 0x0009, 0x3ce0, 0x000b, 0x0b3d,
+	0x0008, 0x15fe, 0x0009, 0x3ce0, 0x000b, 0x8aec, 0x000c, 0x0352,
+	0x0008, 0x8076, 0x0000, 0x0040, 0x0000, 0x8072, 0x0000, 0x8000,
+	0x0003, 0x039b, 0x0008, 0x8076, 0x0008, 0x0042, 0x000b, 0x034d,
+	0x0009, 0xbbe0, 0x0000, 0x0016, 0x000b, 0x8b4d, 0x0000, 0x8074,
+	0x0008, 0x0808, 0x0002, 0x3a44, 0x0003, 0x8816, 0x0000, 0x8074,
+	0x0000, 0x0800, 0x0000, 0x8072, 0x0000, 0x8000, 0x000f, 0x8000,
+	0x0003, 0x0013, 0x0000, 0x8072, 0x0000, 0x8000, 0x0003, 0x0013,
+	0x0002, 0x1430, 0x000b, 0x0353, 0x000a, 0x3d30, 0x0000, 0x7f00,
+	0x0001, 0xbc80, 0x0000, 0x0007, 0x0003, 0x035b, 0x000a, 0x1930,
+	0x0000, 0x7f00, 0x0001, 0x9880, 0x0000, 0x0007, 0x0000, 0x8060,
+	0x0000, 0x0400, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x000a,
+	0x000b, 0xc360, 0x000f, 0x4000, 0x000b, 0x2362, 0x0008, 0x0870,
+	0x000f, 0x4000, 0x0009, 0xbac0, 0x0008, 0x0090, 0x000b, 0x0b6b,
+	0x0000, 0x8074, 0x0000, 0x0706, 0x0003, 0x036d, 0x0000, 0x8074,
+	0x0000, 0x0703, 0x000f, 0x4000, 0x0008, 0x8010, 0x0000, 0x0023,
+	0x000b, 0x03a9, 0x0008, 0x8010, 0x0000, 0x0008, 0x000b, 0x03a9,
+	0x0008, 0x8010, 0x0008, 0x0022, 0x000b, 0x03a9, 0x000c, 0x0357,
+	0x0008, 0x8010, 0x0000, 0x0007, 0x000c, 0x0362, 0x0000, 0x1810,
+	0x000c, 0x0362, 0x0003, 0x03b3, 0x000c, 0x0357, 0x0008, 0x8010,
+	0x0008, 0x001b, 0x000c, 0x0362, 0x0000, 0x1810, 0x000c, 0x0362,
+	0x0000, 0x8074, 0x0000, 0xf080, 0x0000, 0x0d30, 0x0003, 0x0013,
+	0x0008, 0x8010, 0x0008, 0x0009, 0x000b, 0x03a9, 0x0008, 0x8010,
+	0x0008, 0x0005, 0x000b, 0x03a9, 0x000a, 0x1648, 0x000b, 0x8888,
+	0x0008, 0x808c, 0x0000, 0x0001, 0x0007, 0x0000, 0x0008, 0x8010,
+	0x0000, 0x0004, 0x000a, 0x4143, 0x0003, 0x0888, 0x0002, 0x3a44,
+	0x0003, 0x8813, 0x0008, 0x0d2a, 0x000b, 0x03a9, 0x0008, 0x8010,
+	0x0008, 0x0003, 0x0003, 0x03ab, 0x0008, 0x8010, 0x0000, 0x000b,
+	0x0003, 0x03ab, 0x0008, 0x8010, 0x0000, 0x0002, 0x0003, 0x03ab,
+	0x0002, 0x3a47, 0x000b, 0x8a67, 0x0008, 0x8010, 0x0008, 0x0006,
+	0x0003, 0x03ab, 0x0000, 0x8074, 0x0008, 0xf000, 0x000c, 0x0362,
+	0x0004, 0x0365, 0x000a, 0x3a40, 0x000b, 0x0813, 0x0008, 0x8010,
+	0x0008, 0x000c, 0x000c, 0x0362, 0x0003, 0x0013, 0x0000, 0x8074,
+	0x0000, 0xf080, 0x0000, 0x0d30, 0x0002, 0x2e4d, 0x0002, 0x2e4d,
+	0x000b, 0x0bbc, 0x0008, 0x8054, 0x0000, 0x0019, 0x0003, 0x0013,
+	0x0008, 0x8054, 0x0008, 0x0009, 0x0003, 0x0013, 0x0002, 0x3a44,
+	0x0003, 0x8813, 0x0003, 0x039e, 0x0008, 0x808c, 0x0008, 0x0000,
+	0x0002, 0x4447, 0x0003, 0x0be8, 0x0001, 0xc0c0, 0x0008, 0x00ff,
+	0x0009, 0xffe0, 0x0008, 0x00ff, 0x0003, 0x8bbf, 0x0001, 0xc1e0,
+	0x0008, 0xffff, 0x0003, 0x8bbf, 0x0008, 0x8010, 0x0000, 0x0013,
+	0x000c, 0x0362, 0x0000, 0x8074, 0x0008, 0x0202, 0x0003, 0x0013,
+	0x000a, 0x3a40, 0x0003, 0x8be5, 0x0000, 0x8074, 0x0000, 0x0200,
+	0x0000, 0x3d00, 0x0000, 0x3cfe, 0x0000, 0x8072, 0x0000, 0x8000,
+	0x0001, 0x43e0, 0x0003, 0x8be3, 0x0000, 0x42fe, 0x0001, 0xffc0,
+	0x0008, 0x00ff, 0x0009, 0x00e0, 0x000b, 0x0bbf, 0x0008, 0x0d08,
+	0x000b, 0x0438, 0x0000, 0x8072, 0x0000, 0x8000, 0x0003, 0x0013,
+	0x0004, 0x04ba, 0x0008, 0x808c, 0x0000, 0x0001, 0x0000, 0x04fc,
+	0x000b, 0x349d, 0x0000, 0x0460, 0x0008, 0x8062, 0x0000, 0x0001,
+	0x0000, 0x8066, 0x0008, 0x0009, 0x0003, 0xc3f2, 0x0000, 0x0004,
+	0x0009, 0x80c0, 0x0008, 0x00ff, 0x0000, 0x7f00, 0x0001, 0x80e0,
+	0x0000, 0x0004, 0x000b, 0x0c0c, 0x0001, 0x80e0, 0x0008, 0x0005,
+	0x000b, 0x0c0c, 0x0001, 0x80e0, 0x0008, 0x0006, 0x000b, 0x0c0c,
+	0x0001, 0x82c0, 0x0008, 0xff00, 0x0008, 0x7f04, 0x0009, 0x82e0,
+	0x0008, 0x0600, 0x000b, 0x0c0c, 0x0009, 0x82e0, 0x0008, 0x0500,
+	0x000b, 0x0c0c, 0x0009, 0x82e0, 0x0000, 0x0400, 0x000b, 0x8c9d,
+	0x0009, 0xc4c0, 0x0000, 0x7000, 0x0009, 0xffe0, 0x0000, 0x1000,
+	0x0003, 0x0c38, 0x0004, 0x04ab, 0x0002, 0x3941, 0x000b, 0x0c17,
+	0x0000, 0x8072, 0x0000, 0x0400, 0x0003, 0x0013, 0x0000, 0x0460,
+	0x0008, 0x80fe, 0x0008, 0x002b, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x2209, 0x0003, 0xc41d, 0x0008, 0x11fc, 0x0003, 0x3433,
+	0x0001, 0x9180, 0x0000, 0x0002, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0008, 0x7f62, 0x0000, 0x8066, 0x0008, 0x0609, 0x0003, 0xc427,
+	0x0000, 0x42fe, 0x0001, 0xffc0, 0x0008, 0xff00, 0x0009, 0x03e0,
+	0x0003, 0x8c30, 0x0000, 0x8072, 0x0000, 0x0400, 0x0003, 0x0052,
+	0x0001, 0x9180, 0x0008, 0x0003, 0x000b, 0x041a, 0x0000, 0x8072,
+	0x0000, 0x0400, 0x0008, 0x8010, 0x0000, 0x0010, 0x0003, 0x0490,
+	0x0004, 0x04ab, 0x0002, 0x3941, 0x0003, 0x0c3e, 0x0000, 0x8072,
+	0x0000, 0x0400, 0x0003, 0x0013, 0x0004, 0x0475, 0x0008, 0x11fc,
+	0x0003, 0xb446, 0x0000, 0x8072, 0x0000, 0x0400, 0x0008, 0x8010,
+	0x0000, 0x000e, 0x0003, 0x0490, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0000, 0x04fc, 0x0003, 0xb45b, 0x0008, 0x808c, 0x0008, 0x0000,
+	0x0001, 0x9180, 0x0008, 0x0005, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x0009, 0x000b, 0xc451, 0x0008, 0x0060, 0x0008, 0x8062,
+	0x0008, 0x001b, 0x0008, 0x4304, 0x0008, 0x4206, 0x0000, 0x8066,
+	0x0000, 0x0412, 0x0003, 0xc459, 0x0003, 0x0472, 0x0008, 0x808c,
+	0x0000, 0x0001, 0x0000, 0x0460, 0x0008, 0x8062, 0x0008, 0x002b,
+	0x0000, 0x8066, 0x0008, 0x0609, 0x000b, 0xc462, 0x0000, 0x8066,
+	0x0008, 0x220a, 0x0003, 0xc465, 0x0000, 0x42fe, 0x0001, 0xffc0,
+	0x0008, 0xff00, 0x0008, 0x7f04, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0001, 0x9180, 0x0000, 0x0002, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0008, 0x041a, 0x0003, 0xc471, 0x0000, 0x8072, 0x0000, 0x0400,
+	0x0003, 0x0052, 0x0000, 0x8060, 0x0000, 0x0400, 0x0008, 0x6b62,
+	0x0000, 0x8066, 0x0000, 0x0411, 0x000b, 0xc47a, 0x0008, 0x02fe,
+	0x0009, 0x03e0, 0x000b, 0x8c80, 0x0000, 0x0d22, 0x000f, 0x4000,
+	0x0009, 0x8280, 0x0000, 0x0002, 0x0001, 0x6b80, 0x0008, 0x7f62,
+	0x0000, 0x8066, 0x0008, 0x2209, 0x000b, 0xc486, 0x000a, 0x0200,
+	0x0001, 0xffc0, 0x0000, 0x0007, 0x0000, 0x7f06, 0x0008, 0x6b62,
+	0x0000, 0x8066, 0x0008, 0x060a, 0x0003, 0xc48e, 0x000f, 0x4000,
+	0x0002, 0x3a44, 0x0003, 0x8813, 0x000a, 0x2f44, 0x000a, 0x2f44,
+	0x0003, 0x8b9e, 0x0008, 0x808a, 0x0008, 0x0003, 0x0000, 0x8074,
+	0x0000, 0xf080, 0x000b, 0x5c99, 0x0008, 0x8054, 0x0000, 0x0019,
+	0x0003, 0x0013, 0x0002, 0x3a44, 0x0003, 0x8813, 0x0008, 0x808c,
+	0x0008, 0x0000, 0x0008, 0x8010, 0x0008, 0x0011, 0x000c, 0x0362,
+	0x0000, 0x42fe, 0x0001, 0xffc0, 0x0008, 0x00ff, 0x0008, 0x7f10,
+	0x000c, 0x0362, 0x0008, 0x4310, 0x0003, 0x03ab, 0x0002, 0x3941,
+	0x0003, 0x0cae, 0x000f, 0x4000, 0x0000, 0x8072, 0x0008, 0x0404,
+	0x000f, 0x4000, 0x0008, 0x8010, 0x0008, 0x0012, 0x000c, 0x0362,
+	0x0004, 0x0475, 0x0000, 0x1110, 0x000c, 0x0362, 0x0008, 0x11fc,
+	0x000b, 0xb4b4, 0x0003, 0x0013, 0x0009, 0xc2c0, 0x0008, 0x00ff,
+	0x0000, 0x7f00, 0x0001, 0xc3c0, 0x0008, 0xff00, 0x0009, 0x00d0,
+	0x0003, 0x0cdf, 0x0000, 0x0d0a, 0x0001, 0x8580, 0x0000, 0x1000,
+	0x0008, 0x7f62, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x8066,
+	0x0000, 0x0809, 0x0003, 0xc4c9, 0x0000, 0x04fc, 0x0003, 0x34d8,
+	0x0000, 0x0460, 0x0008, 0x8062, 0x0000, 0x0004, 0x0000, 0x8066,
+	0x0000, 0x0211, 0x0003, 0xc4d1, 0x0008, 0x01fe, 0x0009, 0x00e0,
+	0x0003, 0x8cd8, 0x0008, 0x02fe, 0x0001, 0x43e0, 0x000b, 0x0cde,
+	0x0002, 0x0500, 0x0000, 0x7f0a, 0x0009, 0xffe0, 0x0000, 0x0800,
+	0x000b, 0x8cc2, 0x0008, 0x0d08, 0x000f, 0x4000, 0x0008, 0x43fe,
+	0x0001, 0x3e80, 0x0000, 0x0d60, 0x0008, 0x7f62, 0x0000, 0x8066,
+	0x0000, 0x0809, 0x000b, 0xc4e5, 0x0000, 0x8060, 0x0000, 0x0400,
+	0x0001, 0x84c0, 0x0008, 0xff00, 0x0002, 0x7f70, 0x0009, 0xff80,
+	0x0000, 0x1000, 0x0008, 0x7f62, 0x0000, 0x8066, 0x0000, 0x0809,
+	0x0003, 0xc4f0, 0x000f, 0x4000, 0xe504, 0x3334
+};
+unsigned short rseqipx_code_length01 = 0x09e6;
+/*
+ *
+ */
+
+unsigned long xseqipx_code_addr01 = 0x0001e000 ;
+unsigned short xseqipx_code01[] = { 
+0x0013, 0x0003, 0x0000, 0x10d6, 0x0001, 0xe000, 0x0005, 0x0032,
+	0x0000, 0x0010, 0x0015, 0x0033, 0x0010, 0xbb39, 0x000b, 0x8007,
+	0x0004, 0x010b, 0x0014, 0x011d, 0x0010, 0xc000, 0x0000, 0xc001,
+	0x0000, 0xc0b0, 0x0010, 0xc0b1, 0x0010, 0xc0b2, 0x0000, 0xc0b3,
+	0x0010, 0xc0b4, 0x0000, 0xc0b5, 0x0000, 0xc0b6, 0x0010, 0xc0b7,
+	0x0010, 0xc0b8, 0x0000, 0xc0b9, 0x0000, 0xc0ba, 0x0000, 0xc0c2,
+	0x0010, 0xc0c3, 0x0000, 0xc0c4, 0x0010, 0xc0c5, 0x0010, 0xc0c6,
+	0x0000, 0xc0c7, 0x0000, 0xc0c8, 0x0010, 0xc0c9, 0x0010, 0xc0ca,
+	0x0000, 0xc0cb, 0x0010, 0xc0cc, 0x0000, 0xc0cd, 0x0000, 0xc0ce,
+	0x0010, 0xc0cf, 0x0015, 0x0039, 0x0010, 0xff00, 0x0015, 0x003a,
+	0x0010, 0xff00, 0x0005, 0x00d0, 0x0010, 0xff00, 0x0015, 0x00d1,
+	0x0010, 0xff00, 0x0012, 0x3a40, 0x000b, 0x1031, 0x0002, 0x7940,
+	0x001b, 0x112f, 0x0002, 0x3a42, 0x001b, 0x1035, 0x0003, 0xb035,
+	0x0013, 0xa1dc, 0x0002, 0x3a41, 0x001b, 0x1039, 0x0012, 0x7941,
+	0x001b, 0x1311, 0x0003, 0xe055, 0x0012, 0xd042, 0x0003, 0x103f,
+	0x0000, 0x75ff, 0x0002, 0xff41, 0x001b, 0x1055, 0x0000, 0x0cfe,
+	0x0003, 0x6049, 0x0002, 0x3a44, 0x000b, 0x1049, 0x0011, 0x02e8,
+	0x0010, 0x0000, 0x0013, 0x13a2, 0x0011, 0x02e8, 0x0010, 0x0005,
+	0x0003, 0x1432, 0x0012, 0x3a46, 0x001b, 0x1055, 0x0012, 0xd042,
+	0x0003, 0x1050, 0x0000, 0x75ff, 0x0012, 0xff40, 0x001b, 0x1055,
+	0x0000, 0x12fe, 0x0013, 0x6055, 0x0001, 0x0fe8, 0x0010, 0x0000,
+	0x0003, 0x163f, 0x0015, 0x0030, 0x0000, 0x0400, 0x0010, 0xc131,
+	0x0015, 0x0033, 0x0010, 0xb211, 0x001b, 0x805a, 0x0010, 0xb2ff,
+	0x0001, 0xb3e0, 0x001c, 0x10cd, 0x000b, 0xf02d, 0x0011, 0x3be8,
+	0x0000, 0x0010, 0x001b, 0x1072, 0x0000, 0x0afe, 0x000b, 0x6066,
+	0x0000, 0x3c0b, 0x0003, 0x006e, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0001, 0x0a88, 0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0010, 0x3c0a, 0x000b, 0x806d, 0x0010, 0x3c0a, 0x0002, 0x0c00,
+	0x0010, 0xff0c, 0x0013, 0x00ca, 0x0011, 0x3be8, 0x0010, 0x0012,
+	0x000b, 0x1085, 0x0010, 0x08fe, 0x001b, 0x6079, 0x0010, 0x3c09,
+	0x0013, 0x0081, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0888,
+	0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0x3c0a,
+	0x000b, 0x8080, 0x0000, 0x3c08, 0x0002, 0x0c00, 0x0010, 0xff0c,
+	0x0013, 0x00ca, 0x0011, 0x3be8, 0x0000, 0x0013, 0x001b, 0x108b,
+	0x0000, 0x3cb0, 0x0004, 0x00dd, 0x0013, 0x00ca, 0x0011, 0x3be8,
+	0x0000, 0x0019, 0x000b, 0x109e, 0x0010, 0x04fe, 0x001b, 0x6092,
+	0x0010, 0x3c05, 0x0013, 0x009a, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x0488, 0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0010, 0x3c0a, 0x001b, 0x8099, 0x0000, 0x3c04, 0x0002, 0x0c00,
+	0x0010, 0xff0c, 0x0013, 0x00ca, 0x0011, 0x3be8, 0x0000, 0x0015,
+	0x001b, 0x10aa, 0x0014, 0x0114, 0x0004, 0x0126, 0x0015, 0x0039,
+	0x0000, 0x8000, 0x0017, 0x8000, 0x0004, 0x010b, 0x0014, 0x011d,
+	0x0004, 0x00f6, 0x0013, 0x002d, 0x0011, 0x3be8, 0x0000, 0x0016,
+	0x000b, 0x10bc, 0x0001, 0x0fe8, 0x0010, 0x0000, 0x0013, 0x10b6,
+	0x0001, 0x0fe8, 0x0000, 0x0002, 0x0013, 0x10b6, 0x0015, 0x0039,
+	0x0010, 0x1010, 0x0013, 0x00ca, 0x0015, 0x0039, 0x0000, 0x5040,
+	0x0015, 0x00b8, 0x0000, 0x0008, 0x0004, 0x0867, 0x0013, 0x00ca,
+	0x0011, 0x3be8, 0x0010, 0x0017, 0x000b, 0x10c1, 0x0010, 0x3cc3,
+	0x0013, 0x00ca, 0x0011, 0x3be8, 0x0010, 0x0018, 0x001b, 0x10c6,
+	0x0000, 0x3cc2, 0x0013, 0x00ca, 0x0005, 0x00ce, 0x0000, 0x0001,
+	0x0000, 0x3bcf, 0x0004, 0x0829, 0x0015, 0x0039, 0x0000, 0x8000,
+	0x0013, 0x002d, 0x0001, 0xb288, 0x0000, 0x0002, 0x0001, 0xc180,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x80d3,
+	0x0002, 0xb200, 0x0011, 0xffc8, 0x0000, 0x0007, 0x0010, 0xffb2,
+	0x0010, 0xc131, 0x0015, 0x0033, 0x0010, 0xb20a, 0x0001, 0xb0d0,
+	0x000b, 0x80dc, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0xb088,
+	0x0000, 0x0010, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb109,
+	0x001b, 0x80e4, 0x0001, 0xb1e8, 0x0010, 0xffff, 0x0003, 0x10f5,
+	0x0000, 0x11fe, 0x001b, 0x60ec, 0x0000, 0xb012, 0x0003, 0x00f4,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0x1188, 0x0010, 0x0003,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb00a, 0x001b, 0x80f3,
+	0x0000, 0xb011, 0x0017, 0x4000, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0xbc88, 0x0000, 0x001f, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xc411, 0x000b, 0x80fd, 0x0011, 0xbc88, 0x0010, 0x0018,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xc609, 0x000b, 0x8103,
+	0x0011, 0xbc88, 0x0000, 0x0037, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xc709, 0x000b, 0x8109, 0x0017, 0x4000, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0001, 0xbb88, 0x0000, 0x0001, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0x0269, 0x000b, 0x8112, 0x0017, 0x4000,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbb88, 0x0000, 0x0001,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0x026a, 0x000b, 0x811b,
+	0x0017, 0x4000, 0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbb88,
+	0x0010, 0x000f, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0x0f59,
+	0x000b, 0x8124, 0x0017, 0x4000, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0001, 0xbb88, 0x0010, 0x000f, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0010, 0x0f5a, 0x000b, 0x812d, 0x0017, 0x4000, 0x0000, 0xd0ff,
+	0x0012, 0xff40, 0x000b, 0x1031, 0x0015, 0x00d1, 0x0010, 0x0101,
+	0x0013, 0x9134, 0x0005, 0x0079, 0x0000, 0x0001, 0x0013, 0x9137,
+	0x0015, 0x00d1, 0x0000, 0x0100, 0x0011, 0x02e8, 0x0000, 0x0002,
+	0x0003, 0x1161, 0x0011, 0x02e8, 0x0000, 0x0001, 0x0003, 0x1179,
+	0x0011, 0x02e8, 0x0000, 0x0004, 0x0003, 0x1197, 0x0011, 0x02e8,
+	0x0010, 0x0003, 0x0003, 0x11c8, 0x0005, 0x0002, 0x0010, 0x0000,
+	0x0000, 0xc00e, 0x0000, 0xc00d, 0x0010, 0xc003, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0001, 0xbd88, 0x0010, 0x0009, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0010, 0xc00a, 0x001b, 0x8152, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0010, 0xc00a, 0x000b, 0x8156, 0x0012, 0x3a45,
+	0x0003, 0x115e, 0x0015, 0x003a, 0x0000, 0x2000, 0x0015, 0x003a,
+	0x0010, 0x1010, 0x0014, 0x0853, 0x0012, 0xd042, 0x0013, 0x1031,
+	0x0013, 0x0050, 0x0012, 0x7849, 0x0003, 0x11d6, 0x0010, 0x0dfe,
+	0x0003, 0x6148, 0x0012, 0x0c10, 0x0010, 0xff0c, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x0d88, 0x0010, 0x0003, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb309, 0x001b, 0x816e, 0x0010, 0xb3fe,
+	0x0013, 0x6176, 0x0010, 0xb30b, 0x0015, 0x0033, 0x0010, 0xc00a,
+	0x000b, 0x8174, 0x0013, 0x01cb, 0x0000, 0xc00b, 0x0010, 0xc00a,
+	0x0013, 0x01cb, 0x0000, 0x78b0, 0x0012, 0xb044, 0x0003, 0x11d6,
+	0x0002, 0xb049, 0x0003, 0x11d6, 0x0010, 0x71ff, 0x0012, 0xff38,
+	0x0010, 0xff71, 0x0010, 0x0dfe, 0x0013, 0x6146, 0x0012, 0x0c10,
+	0x0010, 0xff0c, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb309,
+	0x001b, 0x818c, 0x0010, 0xb3fe, 0x0013, 0x6194, 0x0000, 0xb309,
+	0x0015, 0x0033, 0x0010, 0xc00a, 0x001b, 0x8192, 0x0013, 0x01cb,
+	0x0010, 0xc009, 0x0000, 0xc008, 0x0013, 0x01cb, 0x0000, 0x78b0,
+	0x0012, 0xb044, 0x0003, 0x11d6, 0x0002, 0xb049, 0x0003, 0x11d6,
+	0x0010, 0x71ff, 0x0012, 0xff38, 0x0010, 0xff71, 0x0010, 0x0dfe,
+	0x0013, 0x6146, 0x0012, 0x0c10, 0x0010, 0xff0c, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x0d88, 0x0010, 0x0003, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb309, 0x000b, 0x81aa, 0x0010, 0xb3fe,
+	0x0003, 0x61b2, 0x0000, 0xb305, 0x0015, 0x0033, 0x0010, 0xc00a,
+	0x001b, 0x81b0, 0x0003, 0x01b4, 0x0010, 0xc005, 0x0000, 0xc004,
+	0x0002, 0x033f, 0x0002, 0xff27, 0x0000, 0x0db8, 0x0014, 0x0397,
+	0x0000, 0x0db8, 0x0004, 0x0867, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0xbc88, 0x0010, 0x0000, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb309, 0x001b, 0x81c1, 0x0011, 0xb3e8, 0x0000, 0x0002,
+	0x001b, 0x1146, 0x0005, 0x0002, 0x0010, 0x0005, 0x0003, 0x0148,
+	0x0012, 0x7849, 0x0003, 0x11d6, 0x0003, 0x0148, 0x0000, 0x0db8,
+	0x0012, 0x0345, 0x000b, 0x11d1, 0x0002, 0x033f, 0x0014, 0x0397,
+	0x0013, 0x0146, 0x0002, 0x033f, 0x0002, 0xff27, 0x0014, 0x0397,
+	0x0004, 0x0867, 0x0013, 0x0146, 0x0015, 0x00b8, 0x0000, 0x0001,
+	0x0015, 0x003a, 0x0010, 0x0101, 0x0004, 0x0867, 0x0013, 0x0157,
+	0x0001, 0x2bd8, 0x0010, 0x0000, 0x0000, 0xffba, 0x0003, 0xb1df,
+	0x0005, 0x002a, 0x0000, 0x0002, 0x0001, 0xbac8, 0x0000, 0x0700,
+	0x000b, 0x12cc, 0x0011, 0x15e8, 0x0000, 0x0002, 0x0013, 0x1242,
+	0x0011, 0x15e8, 0x0000, 0x0001, 0x0013, 0x11ee, 0x0005, 0x0015,
+	0x0010, 0x0000, 0x0013, 0x0225, 0x0005, 0x0015, 0x0010, 0x0000,
+	0x0002, 0xba43, 0x0003, 0x1226, 0x0003, 0xb1f2, 0x0005, 0x002a,
+	0x0000, 0x0004, 0x0012, 0xba42, 0x0003, 0x122c, 0x0012, 0x104b,
+	0x001b, 0x1225, 0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x0002,
+	0x0015, 0x0033, 0x0000, 0x1b2a, 0x001b, 0x81fe, 0x0011, 0x20d8,
+	0x0010, 0x0000, 0x0000, 0xffb0, 0x0001, 0x21d8, 0x0010, 0x0000,
+	0x0010, 0xffb1, 0x0001, 0x22d8, 0x0010, 0x0000, 0x0010, 0xffb2,
+	0x0011, 0x23d8, 0x0010, 0x0000, 0x0000, 0xffb3, 0x0001, 0x24d8,
+	0x0010, 0x0000, 0x0010, 0xffb4, 0x0011, 0x25d8, 0x0010, 0x0000,
+	0x0000, 0xffb5, 0x0001, 0x28d8, 0x0010, 0x0000, 0x0010, 0xffb8,
+	0x0011, 0x29d8, 0x0010, 0x0000, 0x0000, 0xffb9, 0x0000, 0x1a30,
+	0x0005, 0x0031, 0x0000, 0x0007, 0x0015, 0x0033, 0x0010, 0xb032,
+	0x001b, 0x821c, 0x0000, 0x1a30, 0x0005, 0x0031, 0x0010, 0x000f,
+	0x0015, 0x0033, 0x0010, 0xb812, 0x000b, 0x8222, 0x0005, 0x0015,
+	0x0010, 0x0000, 0x0013, 0x0035, 0x0000, 0x1efe, 0x0003, 0x623a,
+	0x0014, 0x0271, 0x0000, 0x1efe, 0x000c, 0x6271, 0x0013, 0x0225,
+	0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x0020, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x001b, 0x8231, 0x0002, 0xb02f, 0x0000, 0xffb0,
+	0x0005, 0x0031, 0x0000, 0x0020, 0x0015, 0x0033, 0x0000, 0xb00a,
+	0x001b, 0x8238, 0x0003, 0x01f9, 0x0015, 0x00b8, 0x0010, 0x0005,
+	0x0004, 0x0867, 0x0000, 0x13b8, 0x0015, 0x003a, 0x0010, 0x0404,
+	0x0004, 0x0867, 0x0013, 0x0225, 0x0005, 0x0015, 0x0000, 0x0001,
+	0x0012, 0xba42, 0x0013, 0x1250, 0x0003, 0xb246, 0x0001, 0x2bd8,
+	0x0010, 0x0000, 0x0012, 0xff4f, 0x001b, 0x11dc, 0x0002, 0xba43,
+	0x001b, 0x122c, 0x0000, 0x1efe, 0x000c, 0x6271, 0x0013, 0x0225,
+	0x0001, 0x28d8, 0x0010, 0x0000, 0x0010, 0xffb8, 0x0011, 0x29d8,
+	0x0010, 0x0000, 0x0000, 0xffb9, 0x0014, 0x02e2, 0x0002, 0x3a42,
+	0x001b, 0x1225, 0x0000, 0x1c30, 0x0015, 0x00ff, 0x0000, 0x0002,
+	0x0002, 0x1f43, 0x001b, 0x1261, 0x0001, 0xff88, 0x0000, 0x0002,
+	0x0003, 0x0263, 0x0001, 0xff88, 0x0000, 0x0004, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb011, 0x000b, 0x8266, 0x0000, 0xb0ff,
+	0x0011, 0x16a0, 0x0000, 0xff16, 0x001b, 0x226d, 0x0002, 0xb100,
+	0x0013, 0x026e, 0x0010, 0xb1ff, 0x0001, 0x17a0, 0x0010, 0xff17,
+	0x0013, 0x022c, 0x0000, 0x16ff, 0x0001, 0x18a0, 0x0010, 0xff00,
+	0x000b, 0x2278, 0x0002, 0x1700, 0x0003, 0x12cb, 0x0013, 0x0279,
+	0x0010, 0x17ff, 0x0011, 0x19a0, 0x0003, 0x22cb, 0x0011, 0x00d0,
+	0x0003, 0x12cb, 0x0000, 0x1c30, 0x0000, 0x1b31, 0x0015, 0x0033,
+	0x0000, 0xb131, 0x000b, 0x8281, 0x0013, 0xb282, 0x0000, 0xb120,
+	0x0010, 0xb221, 0x0002, 0x1f43, 0x000b, 0x128e, 0x0010, 0xc022,
+	0x0000, 0xc023, 0x0000, 0xb324, 0x0000, 0xb425, 0x0010, 0xb3b5,
+	0x0000, 0xb4b6, 0x0013, 0x0292, 0x0000, 0xb322, 0x0000, 0xb423,
+	0x0000, 0xb524, 0x0010, 0xb625, 0x0003, 0xb292, 0x0005, 0x002a,
+	0x0000, 0x0001, 0x0012, 0x1500, 0x0000, 0xff15, 0x0000, 0x16ff,
+	0x0001, 0xb580, 0x0000, 0xff16, 0x001b, 0x229d, 0x0002, 0x1700,
+	0x0013, 0x029e, 0x0010, 0x17ff, 0x0001, 0xb680, 0x0010, 0xff17,
+	0x0012, 0x1e10, 0x0010, 0xff1e, 0x0013, 0x62cb, 0x0002, 0x1d00,
+	0x0010, 0xff1d, 0x0010, 0xc030, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x000b, 0x82a9, 0x0010, 0xb0fe, 0x001b, 0x62ca,
+	0x0000, 0x1c30, 0x0005, 0x0031, 0x0000, 0x0001, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x000b, 0x82b1, 0x0010, 0xb0fe, 0x001b, 0x62b7,
+	0x0005, 0x00ce, 0x0010, 0x0005, 0x0013, 0x0829, 0x0010, 0xb01c,
+	0x0000, 0x1c30, 0x0005, 0x0031, 0x0000, 0x0019, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x000b, 0x82bd, 0x0001, 0xb0c8, 0x0010, 0x00ff,
+	0x0000, 0xff1f, 0x0010, 0xc030, 0x0011, 0xbe80, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x82c6, 0x0000, 0xb01d,
+	0x0010, 0x1dff, 0x0003, 0x02a5, 0x0000, 0xb01b, 0x0017, 0x4000,
+	0x0002, 0x3a41, 0x0013, 0x12d4, 0x0003, 0xb2ce, 0x0005, 0x002a,
+	0x0000, 0x0004, 0x0005, 0x0015, 0x0010, 0x0000, 0x0013, 0x0225,
+	0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x0002, 0x0015, 0x0033,
+	0x0000, 0x1b2a, 0x001b, 0x82d9, 0x0015, 0x00b8, 0x0000, 0x0004,
+	0x0004, 0x0867, 0x0000, 0x13b8, 0x0015, 0x003a, 0x0010, 0x0404,
+	0x0004, 0x0867, 0x0013, 0x0039, 0x0002, 0x1e00, 0x0010, 0xff1e,
+	0x0012, 0x1d10, 0x0010, 0xff1d, 0x0010, 0xc030, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x82ea, 0x0010, 0xb0fe,
+	0x000b, 0x630f, 0x0000, 0x1cff, 0x0001, 0x1ae0, 0x0013, 0x12f9,
+	0x0000, 0x1c30, 0x0005, 0x0031, 0x0010, 0x0000, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x000b, 0x82f5, 0x0010, 0xb0fe, 0x001b, 0x62f9,
+	0x0000, 0x1aff, 0x0000, 0xff1c, 0x0000, 0x1c30, 0x0005, 0x0031,
+	0x0000, 0x0019, 0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x82ff,
+	0x0001, 0xb0c8, 0x0010, 0x000f, 0x0000, 0xff1f, 0x0001, 0xbf80,
+	0x0010, 0xff1d, 0x0010, 0xc030, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x001b, 0x8309, 0x0010, 0xb0fe, 0x000b, 0x630f,
+	0x0005, 0x00ce, 0x0010, 0x0006, 0x0013, 0x0829, 0x0000, 0xb01b,
+	0x0017, 0x4000, 0x0010, 0x79b0, 0x0000, 0xd0ff, 0x0012, 0xff40,
+	0x001b, 0x1039, 0x0015, 0x00d1, 0x0010, 0x0101, 0x0013, 0x9317,
+	0x0005, 0x0079, 0x0000, 0x0002, 0x0003, 0x931a, 0x0015, 0x00d1,
+	0x0000, 0x0100, 0x0010, 0x13fe, 0x0003, 0x634f, 0x0012, 0xb04e,
+	0x001b, 0x136f, 0x0012, 0x784a, 0x0013, 0x1375, 0x0000, 0x75ff,
+	0x0011, 0xffc8, 0x0010, 0x1800, 0x000b, 0x1375, 0x0001, 0x0fe8,
+	0x0000, 0x0001, 0x001b, 0x1333, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x1388, 0x0000, 0x000e, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0x8f0a, 0x000b, 0x8331, 0x0013, 0x037b, 0x0001, 0x0fe8,
+	0x0000, 0x0002, 0x000b, 0x133e, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0005, 0x0031, 0x0000, 0x001a, 0x0015, 0x0033, 0x0010, 0xc00a,
+	0x001b, 0x833c, 0x0013, 0x037b, 0x0001, 0x0fe8, 0x0010, 0x0000,
+	0x0013, 0x1345, 0x0005, 0x00ce, 0x0000, 0x0007, 0x0010, 0x0fcf,
+	0x0013, 0x0823, 0x0000, 0x13b8, 0x0002, 0x1045, 0x0003, 0x134d,
+	0x0012, 0x103f, 0x0002, 0xff27, 0x0014, 0x0397, 0x0004, 0x0867,
+	0x0003, 0x034f, 0x0012, 0x103f, 0x0014, 0x0397, 0x0015, 0x000f,
+	0x0010, 0x0000, 0x0002, 0x3944, 0x0013, 0x1358, 0x0015, 0x0039,
+	0x0000, 0x5040, 0x0015, 0x00b8, 0x0000, 0x0008, 0x0004, 0x0867,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbd88, 0x0010, 0x000c,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xc00a, 0x001b, 0x835f,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xc00a, 0x001b, 0x8363,
+	0x0010, 0xc014, 0x0000, 0xc013, 0x0000, 0xc010, 0x0002, 0x3a47,
+	0x0013, 0x136e, 0x0015, 0x003a, 0x0000, 0x8000, 0x0015, 0x003a,
+	0x0010, 0x4040, 0x0014, 0x082e, 0x0013, 0x0039, 0x0015, 0x00b8,
+	0x0010, 0x0003, 0x0015, 0x003a, 0x0010, 0x0202, 0x0004, 0x0867,
+	0x0003, 0x0367, 0x0015, 0x00b8, 0x0000, 0x0002, 0x0015, 0x003a,
+	0x0010, 0x0202, 0x0004, 0x0867, 0x0003, 0x0367, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x1388, 0x0010, 0x0003, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x8382, 0x0011, 0x1388,
+	0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xc00a,
+	0x001b, 0x8388, 0x0010, 0xb0fe, 0x0013, 0x638d, 0x0000, 0xb012,
+	0x0003, 0x038f, 0x0010, 0xc012, 0x0010, 0xc011, 0x0012, 0x104b,
+	0x0013, 0x1345, 0x0002, 0x103b, 0x0010, 0xff03, 0x0005, 0x0002,
+	0x0010, 0x0000, 0x0000, 0xc00d, 0x0003, 0x0345, 0x0000, 0xffb0,
+	0x0010, 0xc3b1, 0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xb888,
+	0x0010, 0x0011, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb012,
+	0x001b, 0x83a0, 0x0017, 0x4000, 0x0012, 0x3a43, 0x0003, 0x13b1,
+	0x0015, 0x003a, 0x0000, 0x0800, 0x0010, 0x0db0, 0x0013, 0x63b1,
+	0x0000, 0x0bff, 0x0001, 0xb0e0, 0x0013, 0x13da, 0x0010, 0x09ff,
+	0x0001, 0xb0e0, 0x0003, 0x13be, 0x0010, 0x05ff, 0x0001, 0xb0e0,
+	0x0013, 0x13b5, 0x0000, 0xc00e, 0x0000, 0x05fe, 0x0013, 0x63bb,
+	0x0000, 0x050d, 0x0005, 0x0002, 0x0000, 0x0004, 0x0014, 0x043c,
+	0x0002, 0x3a47, 0x001b, 0x143b, 0x0003, 0x03d5, 0x0000, 0x09fe,
+	0x0013, 0x63d7, 0x0000, 0x090d, 0x0005, 0x0002, 0x0000, 0x0001,
+	0x0014, 0x0455, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0000, 0x0004, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xba09,
+	0x000b, 0x83c8, 0x0011, 0x03c8, 0x0010, 0x000f, 0x0000, 0xffb6,
+	0x0011, 0xb6e8, 0x0000, 0x0001, 0x0003, 0x14ec, 0x0011, 0xb6e8,
+	0x0000, 0x0002, 0x0013, 0x150e, 0x0011, 0xb6e8, 0x0010, 0x0003,
+	0x0013, 0x15fd, 0x0014, 0x082e, 0x0013, 0x043b, 0x0010, 0x0bfe,
+	0x0013, 0x643b, 0x0010, 0x0b0d, 0x0005, 0x0002, 0x0000, 0x0002,
+	0x0014, 0x0455, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0000, 0x0004, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xba09,
+	0x001b, 0x83e4, 0x0000, 0xb930, 0x0005, 0x0031, 0x0010, 0x0021,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x83ea, 0x0001, 0xb0a8,
+	0x0000, 0x199a, 0x0003, 0x23f0, 0x0005, 0x00b0, 0x0000, 0x1999,
+	0x0012, 0xb050, 0x0000, 0xffb0, 0x0002, 0xff50, 0x0002, 0xff50,
+	0x0001, 0xb080, 0x0000, 0xffb0, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x0d88, 0x0010, 0x0006, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb00a, 0x000b, 0x83fd, 0x0000, 0xb930, 0x0005, 0x0031,
+	0x0000, 0x0019, 0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x8403,
+	0x0001, 0xb0c8, 0x0010, 0x00ff, 0x0001, 0xffe8, 0x0010, 0x0048,
+	0x001b, 0x1464, 0x0005, 0x0002, 0x0010, 0x0006, 0x0012, 0x0c10,
+	0x0010, 0xff0c, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb109,
+	0x000b, 0x8414, 0x0000, 0xb10b, 0x001b, 0x6418, 0x0010, 0xb10a,
+	0x0015, 0x0033, 0x0010, 0xc00a, 0x001b, 0x841a, 0x0002, 0x032b,
+	0x0010, 0xff03, 0x0011, 0x0d88, 0x0010, 0x0011, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0010, 0x030a, 0x000b, 0x8422, 0x0000, 0x11fe,
+	0x001b, 0x6427, 0x0000, 0x0d12, 0x0003, 0x0430, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0001, 0x1188, 0x0010, 0x0003, 0x0000, 0xff31,
+	0x0010, 0x0db0, 0x0015, 0x0033, 0x0000, 0xb00a, 0x001b, 0x842f,
+	0x0000, 0x0d11, 0x0013, 0x043b, 0x0000, 0x05fe, 0x0013, 0x643b,
+	0x0005, 0x0002, 0x0000, 0x0004, 0x0000, 0x050d, 0x0014, 0x043c,
+	0x0002, 0x3a47, 0x001b, 0x143b, 0x0014, 0x082e, 0x0003, 0x0049,
+	0x0001, 0xc7c8, 0x0010, 0x0028, 0x001b, 0x1454, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x0d88, 0x0010, 0x000a, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x8446, 0x0002, 0xb04f,
+	0x0003, 0x1454, 0x0001, 0x0fe8, 0x0010, 0x0000, 0x0003, 0x1452,
+	0x0001, 0x0fe8, 0x0000, 0x0002, 0x0003, 0x1452, 0x0015, 0x003a,
+	0x0010, 0x8080, 0x0013, 0x0454, 0x0015, 0x003a, 0x0010, 0x4040,
+	0x0017, 0x4000, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0011, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0x0309,
+	0x000b, 0x845c, 0x0011, 0x0d88, 0x0010, 0x0005, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb909, 0x001b, 0x8462, 0x0017, 0x4000,
+	0x0005, 0x00b6, 0x0010, 0x0600, 0x0004, 0x062d, 0x0004, 0x04d6,
+	0x0000, 0xb05a, 0x0000, 0xb15b, 0x0005, 0x0054, 0x0010, 0x0829,
+	0x0010, 0x0d58, 0x0015, 0x0059, 0x0010, 0xffff, 0x0000, 0xb930,
+	0x0005, 0x0031, 0x0010, 0x001e, 0x0015, 0x0033, 0x0000, 0xb009,
+	0x000b, 0x8474, 0x0000, 0xb05c, 0x0005, 0x0031, 0x0000, 0x001f,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x847a, 0x0001, 0xb0c8,
+	0x0010, 0x000f, 0x000b, 0x1481, 0x0015, 0x00ff, 0x0010, 0x0005,
+	0x0013, 0x0489, 0x0002, 0xb040, 0x0003, 0x1486, 0x0015, 0x00ff,
+	0x0000, 0x0004, 0x0013, 0x0489, 0x0001, 0xb0c8, 0x0010, 0x0006,
+	0x0002, 0xff60, 0x0010, 0xffb2, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x0d88, 0x0000, 0x0019, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0010, 0xb109, 0x001b, 0x8491, 0x0012, 0xb170, 0x0011, 0xffc8,
+	0x0010, 0xff00, 0x0011, 0xb2d0, 0x0010, 0xff60, 0x0002, 0xb045,
+	0x0013, 0x149c, 0x0015, 0x00b2, 0x0000, 0x0002, 0x0003, 0x04a6,
+	0x0002, 0xb046, 0x0003, 0x14a1, 0x0015, 0x00b2, 0x0000, 0x0001,
+	0x0003, 0x04a6, 0x0015, 0x00b2, 0x0010, 0x0000, 0x0000, 0xc0b0,
+	0x0010, 0xc0b1, 0x0003, 0x04ac, 0x0000, 0xb930, 0x0005, 0x0031,
+	0x0010, 0x002b, 0x0015, 0x0033, 0x0000, 0xb011, 0x001b, 0x84ab,
+	0x0010, 0xb16a, 0x0010, 0xb06b, 0x0000, 0xb261, 0x0015, 0x0044,
+	0x0010, 0x0018, 0x0000, 0xb930, 0x0005, 0x0031, 0x0000, 0x0023,
+	0x0015, 0x0033, 0x0000, 0x6241, 0x001b, 0x84b6, 0x0003, 0x94b7,
+	0x0015, 0x00a0, 0x0000, 0x0020, 0x0012, 0xd041, 0x001b, 0x14ba,
+	0x0015, 0x00d1, 0x0010, 0x0202, 0x0003, 0x94be, 0x0000, 0x75ff,
+	0x0011, 0xffc8, 0x0000, 0x1804, 0x0001, 0xffd8, 0x0010, 0x0009,
+	0x0013, 0x94c4, 0x0000, 0xff75, 0x0003, 0x94c6, 0x0015, 0x00d1,
+	0x0000, 0x0200, 0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbd88,
+	0x0000, 0x0008, 0x0000, 0xff31, 0x0015, 0x00b1, 0x0010, 0x07d0,
+	0x0005, 0x00b0, 0x0010, 0x0009, 0x0015, 0x0033, 0x0000, 0xb012,
+	0x000b, 0x84d4, 0x0013, 0x043b, 0x0000, 0xba30, 0x0005, 0x0031,
+	0x0010, 0x0035, 0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x84db,
+	0x0002, 0xb040, 0x0003, 0x14e9, 0x0010, 0xb9b0, 0x0010, 0xb7b1,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88, 0x0000, 0x0013,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb012, 0x000b, 0x84e7,
+	0x0003, 0x04eb, 0x0010, 0xc0b1, 0x0000, 0xc0b0, 0x0017, 0x4000,
+	0x0005, 0x00b6, 0x0010, 0x0500, 0x0004, 0x062d, 0x0005, 0x0054,
+	0x0010, 0x0889, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0000, 0x0002, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009,
+	0x001b, 0x84f8, 0x0010, 0xb058, 0x0000, 0x0d59, 0x0000, 0xb930,
+	0x0005, 0x0031, 0x0000, 0x0023, 0x0015, 0x0033, 0x0000, 0xb011,
+	0x001b, 0x8500, 0x0010, 0xb15c, 0x0010, 0xb05d, 0x0005, 0x0031,
+	0x0010, 0x002b, 0x0015, 0x0033, 0x0000, 0xb011, 0x000b, 0x8507,
+	0x0000, 0xb15e, 0x0000, 0xb05f, 0x0013, 0x950a, 0x0015, 0x00a0,
+	0x0010, 0x000c, 0x0013, 0x0612, 0x0005, 0x00b6, 0x0000, 0x0700,
+	0x0004, 0x062d, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0009, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb709,
+	0x001b, 0x8518, 0x0012, 0xb749, 0x0003, 0x151e, 0x0005, 0x0054,
+	0x0010, 0x0889, 0x0003, 0x0520, 0x0005, 0x0054, 0x0010, 0x0898,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88, 0x0000, 0x0002,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x8527,
+	0x0010, 0xb058, 0x0000, 0x0d59, 0x0001, 0xb9a8, 0x0010, 0x00f0,
+	0x001b, 0x254e, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0005, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009,
+	0x000b, 0x8534, 0x0001, 0xb0c8, 0x0000, 0xf700, 0x0000, 0xffb0,
+	0x0011, 0xb0e8, 0x0000, 0xf100, 0x0003, 0x1595, 0x0011, 0xb0e8,
+	0x0000, 0xf200, 0x0003, 0x159a, 0x0011, 0xb0e8, 0x0010, 0xf300,
+	0x0013, 0x15bf, 0x0011, 0xb0e8, 0x0000, 0xf400, 0x0013, 0x15c4,
+	0x0011, 0xb0e8, 0x0010, 0xf500, 0x0003, 0x1595, 0x0011, 0xb0e8,
+	0x0010, 0xf600, 0x0013, 0x15d5, 0x0005, 0x00ce, 0x0010, 0x0009,
+	0x0000, 0xb0cf, 0x0013, 0x0823, 0x0000, 0xb930, 0x0005, 0x0031,
+	0x0000, 0x0025, 0x0015, 0x0033, 0x0000, 0xb039, 0x001b, 0x8553,
+	0x0012, 0xb749, 0x0013, 0x1558, 0x0002, 0xb52c, 0x0000, 0xffb5,
+	0x0000, 0xb162, 0x0000, 0xb063, 0x0005, 0x0031, 0x0000, 0x001f,
+	0x0015, 0x0033, 0x0000, 0xb309, 0x000b, 0x855e, 0x0001, 0xb3c8,
+	0x0010, 0x0003, 0x0003, 0x1566, 0x0010, 0xffb2, 0x0001, 0xffe8,
+	0x0010, 0x0003, 0x000b, 0x1568, 0x0000, 0xc2b7, 0x0003, 0x05f1,
+	0x0001, 0xb2e8, 0x0000, 0x0001, 0x0003, 0x156f, 0x0005, 0x00ce,
+	0x0010, 0x000a, 0x0010, 0xb2cf, 0x0013, 0x0823, 0x0010, 0xb465,
+	0x0010, 0xb667, 0x0015, 0x00b7, 0x0010, 0x0018, 0x0001, 0xb5c8,
+	0x0010, 0x0300, 0x0013, 0x1594, 0x0012, 0xb548, 0x0003, 0x157b,
+	0x0000, 0xb6ff, 0x0011, 0xb780, 0x0010, 0xffb7, 0x0002, 0xb549,
+	0x0013, 0x1580, 0x0010, 0xb4ff, 0x0011, 0xb780, 0x0010, 0xffb7,
+	0x0015, 0x0044, 0x0010, 0x0018, 0x0005, 0x0031, 0x0000, 0x002c,
+	0x0015, 0x0033, 0x0000, 0x6841, 0x000b, 0x8586, 0x0015, 0x0044,
+	0x0000, 0x0019, 0x0005, 0x0031, 0x0000, 0x0034, 0x0015, 0x0033,
+	0x0000, 0x5029, 0x001b, 0x858d, 0x0015, 0x0044, 0x0000, 0x0008,
+	0x0011, 0xb7c8, 0x0010, 0x0003, 0x0013, 0x1594, 0x0010, 0xff55,
+	0x0003, 0x05f1, 0x0005, 0x00b5, 0x0000, 0x0008, 0x0015, 0x00b7,
+	0x0010, 0x0018, 0x0003, 0x05f1, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x0d88, 0x0000, 0x000b, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb011, 0x000b, 0x85a1, 0x0010, 0xb1ff, 0x0001, 0xb0d0,
+	0x0003, 0x15aa, 0x0005, 0x00b5, 0x0010, 0x0b02, 0x0010, 0xb062,
+	0x0010, 0xb163, 0x0013, 0x05ac, 0x0005, 0x00b5, 0x0000, 0x0302,
+	0x0015, 0x0065, 0x0010, 0x0012, 0x0005, 0x0067, 0x0000, 0x0008,
+	0x0015, 0x006c, 0x0000, 0x7000, 0x0005, 0x006d, 0x0010, 0x0500,
+	0x0015, 0x006f, 0x0010, 0x000a, 0x0015, 0x0044, 0x0000, 0x0001,
+	0x0005, 0x0052, 0x0000, 0x2500, 0x0015, 0x0044, 0x0000, 0x0008,
+	0x0015, 0x00b7, 0x0000, 0x0032, 0x0003, 0x05f1, 0x0005, 0x00b5,
+	0x0010, 0x0028, 0x0015, 0x00b7, 0x0010, 0x0018, 0x0003, 0x05f1,
+	0x0005, 0x00b5, 0x0000, 0x0100, 0x0005, 0x0067, 0x0000, 0x0008,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88, 0x0010, 0x0018,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x85cf,
+	0x0001, 0xb0c8, 0x0010, 0x00ff, 0x0015, 0x00b7, 0x0000, 0x0020,
+	0x0003, 0x05f1, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0005, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb609,
+	0x000b, 0x85dc, 0x0001, 0xb6c8, 0x0010, 0xff00, 0x0000, 0xffb0,
+	0x0015, 0x0033, 0x0000, 0xb00a, 0x001b, 0x85e2, 0x0001, 0xb6c8,
+	0x0010, 0x00ff, 0x0012, 0xff10, 0x001b, 0x15eb, 0x0000, 0xffb5,
+	0x0015, 0x00b7, 0x0010, 0x0018, 0x0003, 0x05f1, 0x0010, 0xff63,
+	0x0005, 0x00b5, 0x0000, 0x0800, 0x0015, 0x00b7, 0x0010, 0x0018,
+	0x0003, 0x05f1, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88,
+	0x0010, 0x0009, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009,
+	0x000b, 0x85f8, 0x0010, 0xb561, 0x0013, 0x95fa, 0x0010, 0xb7a0,
+	0x0013, 0x0612, 0x0005, 0x00b6, 0x0010, 0x0300, 0x0004, 0x062d,
+	0x0005, 0x0054, 0x0010, 0x0819, 0x0010, 0x0d58, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x0d88, 0x0000, 0x0002, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x860a, 0x0000, 0xb059,
+	0x0013, 0x960c, 0x0010, 0xc0a0, 0x0010, 0x71ff, 0x0002, 0xff28,
+	0x0010, 0xff71, 0x0013, 0x0612, 0x0012, 0xd041, 0x001b, 0x1612,
+	0x0015, 0x00d1, 0x0010, 0x0202, 0x0000, 0x75ff, 0x0011, 0xffc8,
+	0x0000, 0x1804, 0x0001, 0xffd8, 0x0010, 0x0009, 0x0013, 0x961b,
+	0x0000, 0xff75, 0x0013, 0x961d, 0x0015, 0x00d1, 0x0000, 0x0200,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbd88, 0x0000, 0x0008,
+	0x0000, 0xff31, 0x0005, 0x00b0, 0x0010, 0x0009, 0x0015, 0x00b1,
+	0x0010, 0x07d0, 0x0015, 0x0033, 0x0000, 0xb012, 0x001b, 0x862b,
+	0x0013, 0x043b, 0x0015, 0x0044, 0x0000, 0x0008, 0x0005, 0x0098,
+	0x0010, 0x0056, 0x0015, 0x0099, 0x0000, 0x9575, 0x0004, 0x07ea,
+	0x0000, 0xb096, 0x0012, 0xb270, 0x0010, 0xff56, 0x0014, 0x080c,
+	0x0010, 0xb052, 0x0010, 0xb153, 0x0000, 0xb6ff, 0x0011, 0xb2d0,
+	0x0010, 0xff50, 0x0010, 0xb351, 0x0017, 0x4000, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0001, 0x1288, 0x0010, 0x0011, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0x1009, 0x000b, 0x8646, 0x0015, 0x000f,
+	0x0000, 0x0001, 0x0010, 0xc014, 0x0000, 0x1213, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x1388, 0x0000, 0x0004, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xba09, 0x000b, 0x8652, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x1388, 0x0010, 0x0005, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0x1a09, 0x001b, 0x865a, 0x0012, 0x104b,
+	0x001b, 0x1663, 0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x000b,
+	0x0015, 0x0033, 0x0000, 0x1621, 0x000b, 0x8662, 0x0010, 0x15fe,
+	0x000b, 0x6682, 0x0004, 0x06a9, 0x0002, 0x3a42, 0x000b, 0x16a8,
+	0x0001, 0x10c8, 0x0010, 0x000f, 0x001b, 0x170b, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x1388, 0x0000, 0x0008, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x8672, 0x0011, 0xb0e8,
+	0x0010, 0x0009, 0x0013, 0x1679, 0x0011, 0xb0e8, 0x0000, 0x0001,
+	0x000b, 0x16a7, 0x0011, 0x1388, 0x0010, 0x000a, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x867e, 0x0002, 0xb04f,
+	0x000b, 0x169e, 0x0003, 0x06a7, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x1388, 0x0010, 0x0003, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x000b, 0x8689, 0x0015, 0x0033, 0x0010, 0xc00a,
+	0x000b, 0x868c, 0x0010, 0xb0fe, 0x0003, 0x6691, 0x0000, 0xb012,
+	0x0013, 0x0693, 0x0010, 0xc012, 0x0010, 0xc011, 0x0015, 0x000f,
+	0x0010, 0x0000, 0x0002, 0x3944, 0x0003, 0x169c, 0x0015, 0x0039,
+	0x0000, 0x5040, 0x0015, 0x00b8, 0x0000, 0x0008, 0x0004, 0x0867,
+	0x0000, 0xc013, 0x0003, 0x06a8, 0x0010, 0x02fe, 0x0013, 0x66a3,
+	0x0015, 0x003a, 0x0010, 0x2020, 0x0003, 0x06a8, 0x0015, 0x003a,
+	0x0000, 0x2000, 0x0015, 0x003a, 0x0010, 0x1010, 0x0014, 0x0853,
+	0x0013, 0x0055, 0x0003, 0xb6a9, 0x0005, 0x002a, 0x0000, 0x0004,
+	0x0000, 0xba30, 0x0005, 0x0031, 0x0010, 0x001b, 0x0015, 0x0033,
+	0x0000, 0xb009, 0x001b, 0x86b1, 0x0000, 0xc02c, 0x0000, 0xb02d,
+	0x0012, 0x104b, 0x0003, 0x16cc, 0x0000, 0x1a30, 0x0005, 0x0031,
+	0x0000, 0x0023, 0x0015, 0x0033, 0x0000, 0xb129, 0x001b, 0x86bb,
+	0x0000, 0xb120, 0x0010, 0xb221, 0x0000, 0xb322, 0x0000, 0xb423,
+	0x0000, 0xb524, 0x0000, 0xc025, 0x0010, 0xb526, 0x0010, 0xc027,
+	0x0010, 0xb516, 0x0010, 0xc017, 0x0000, 0xb518, 0x0000, 0xc019,
+	0x0010, 0xc028, 0x0000, 0xc029, 0x0010, 0xc01e, 0x0013, 0x0702,
+	0x0012, 0x1044, 0x0003, 0x16fc, 0x0002, 0x1034, 0x0000, 0xff10,
+	0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x0002, 0x0015, 0x0033,
+	0x0000, 0x1b29, 0x000b, 0x86d5, 0x0000, 0x1c30, 0x0000, 0x1b31,
+	0x0015, 0x0033, 0x0000, 0xb131, 0x000b, 0x86da, 0x0002, 0x1f43,
+	0x001b, 0x16e1, 0x0010, 0xb3b5, 0x0000, 0xb4b6, 0x0000, 0xc0b3,
+	0x0010, 0xc0b4, 0x0000, 0xb120, 0x0010, 0xb221, 0x0000, 0xb322,
+	0x0000, 0xb423, 0x0000, 0xb524, 0x0010, 0xb625, 0x0010, 0xb516,
+	0x0000, 0xb617, 0x0000, 0x1826, 0x0000, 0x1927, 0x0000, 0x1a30,
+	0x0005, 0x0031, 0x0010, 0x000f, 0x0015, 0x0033, 0x0000, 0xb011,
+	0x001b, 0x86f0, 0x0000, 0xb028, 0x0000, 0xb129, 0x0012, 0x1e10,
+	0x0010, 0xff1e, 0x0013, 0x6702, 0x0002, 0x1d00, 0x0010, 0xff1d,
+	0x0014, 0x02a5, 0x0002, 0x3a42, 0x0003, 0x1702, 0x0003, 0x070a,
+	0x0000, 0x1a30, 0x0005, 0x0031, 0x0000, 0x0002, 0x0015, 0x0033,
+	0x0000, 0x1b79, 0x001b, 0x8701, 0x0003, 0xb702, 0x0005, 0x002a,
+	0x0000, 0x0001, 0x0005, 0x0015, 0x0000, 0x0001, 0x0000, 0x1efe,
+	0x0003, 0x670a, 0x0003, 0x0271, 0x0017, 0x4000, 0x0000, 0xba30,
+	0x0005, 0x0031, 0x0010, 0x001b, 0x0015, 0x0033, 0x0010, 0xb051,
+	0x001b, 0x8710, 0x0000, 0xb0a3, 0x0010, 0xb697, 0x0010, 0xb946,
+	0x0015, 0x00a5, 0x0000, 0x0010, 0x0015, 0x0030, 0x0000, 0x0400,
+	0x0011, 0x1388, 0x0000, 0x0002, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0000, 0xb509, 0x000b, 0x871d, 0x0014, 0x080c, 0x0004, 0x07fb,
+	0x0012, 0xb470, 0x0010, 0xffb4, 0x0010, 0xb48e, 0x0010, 0xb08a,
+	0x0010, 0xb18b, 0x0012, 0x104d, 0x0013, 0x1728, 0x0003, 0x0755,
+	0x0012, 0x104b, 0x0003, 0x173b, 0x0005, 0x008c, 0x0010, 0x0829,
+	0x0010, 0xc08d, 0x0001, 0xb2d8, 0x0010, 0x0600, 0x0010, 0xff88,
+	0x0010, 0xb389, 0x0000, 0x1390, 0x0010, 0xb591, 0x0000, 0xc08f,
+	0x0010, 0x1ab9, 0x0004, 0x04d6, 0x0003, 0x9736, 0x0010, 0xb092,
+	0x0010, 0xb193, 0x0003, 0x9739, 0x0003, 0x0750, 0x0005, 0x008c,
+	0x0000, 0x0809, 0x0015, 0x008d, 0x0000, 0x0008, 0x0001, 0xb2d8,
+	0x0000, 0x0100, 0x0010, 0xff88, 0x0010, 0xb389, 0x0000, 0x1390,
+	0x0010, 0xb591, 0x0000, 0xc08f, 0x0000, 0x1a30, 0x0005, 0x0031,
+	0x0010, 0x000f, 0x0015, 0x0033, 0x0000, 0xb011, 0x000b, 0x874b,
+	0x0013, 0x974c, 0x0000, 0xb192, 0x0000, 0xb093, 0x0013, 0x974f,
+	0x0010, 0x19a1, 0x0000, 0x18a2, 0x0015, 0x00b1, 0x0010, 0x0096,
+	0x0003, 0x07c6, 0x0000, 0xb590, 0x0010, 0x1391, 0x0001, 0x10c8,
+	0x0010, 0x000f, 0x0001, 0xffe8, 0x0010, 0x0005, 0x0003, 0x177c,
+	0x0001, 0xb2d8, 0x0000, 0x0700, 0x0010, 0xff88, 0x0010, 0xb389,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x1388, 0x0010, 0x0009,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009, 0x001b, 0x8767,
+	0x0002, 0xb049, 0x0013, 0x176f, 0x0005, 0x008c, 0x0010, 0x0889,
+	0x0015, 0x00b1, 0x0010, 0x0096, 0x0013, 0x0773, 0x0005, 0x008c,
+	0x0010, 0x0898, 0x0015, 0x00b1, 0x0000, 0x0092, 0x0010, 0xc08d,
+	0x0000, 0xc08f, 0x0013, 0x9775, 0x0000, 0xc092, 0x0010, 0xc093,
+	0x0003, 0x9778, 0x0010, 0x19a1, 0x0000, 0x18a2, 0x0003, 0x07c6,
+	0x0001, 0xb2d8, 0x0000, 0x0100, 0x0010, 0xff88, 0x0010, 0xb389,
+	0x0005, 0x008c, 0x0010, 0x0880, 0x0015, 0x008d, 0x0000, 0x0008,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x1388, 0x0000, 0x000e,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb009, 0x000b, 0x878b,
+	0x0010, 0xb08f, 0x0000, 0xb590, 0x0010, 0x1391, 0x0000, 0x1a30,
+	0x0005, 0x0031, 0x0000, 0x000d, 0x0015, 0x0033, 0x0000, 0xb021,
+	0x001b, 0x8794, 0x0003, 0x9795, 0x0010, 0xb392, 0x0010, 0xb293,
+	0x0013, 0x9798, 0x0000, 0xb1a1, 0x0010, 0xb0a2, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x1388, 0x0000, 0x000b, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0010, 0xb211, 0x001b, 0x87a2, 0x0000, 0xb3ff,
+	0x0001, 0xb080, 0x0000, 0xffb3, 0x000b, 0x27a9, 0x0002, 0xb200,
+	0x0003, 0x07aa, 0x0010, 0xb2ff, 0x0011, 0xb180, 0x0010, 0xffb2,
+	0x0011, 0x1388, 0x0000, 0x000b, 0x0000, 0xff31, 0x0015, 0x0033,
+	0x0010, 0xb212, 0x000b, 0x87b1, 0x0015, 0x00b1, 0x0000, 0x0092,
+	0x0002, 0x104c, 0x0003, 0x17c4, 0x0011, 0xc2e8, 0x0010, 0x000c,
+	0x001b, 0x17bc, 0x0015, 0x00ff, 0x0000, 0x0800, 0x0013, 0x07c4,
+	0x0011, 0xc2e8, 0x0000, 0x0020, 0x001b, 0x17c2, 0x0015, 0x00ff,
+	0x0010, 0x1800, 0x0013, 0x07c4, 0x0015, 0x00ff, 0x0000, 0x1000,
+	0x0011, 0xb1d0, 0x0010, 0xffb1, 0x0015, 0x009a, 0x0010, 0x0036,
+	0x0005, 0x009b, 0x0000, 0x95d5, 0x0012, 0xd041, 0x000b, 0x17ca,
+	0x0015, 0x00d1, 0x0010, 0x0202, 0x0013, 0x97ce, 0x0012, 0x104e,
+	0x0003, 0x17d3, 0x0012, 0xb12f, 0x0010, 0xffb1, 0x0000, 0xb175,
+	0x0003, 0x97d4, 0x0015, 0x00d1, 0x0000, 0x0200, 0x0001, 0x19c8,
+	0x0010, 0xfff0, 0x000b, 0x17dd, 0x0015, 0x00b1, 0x0010, 0x07d0,
+	0x0013, 0x07df, 0x0015, 0x00b1, 0x0000, 0x1b58, 0x0005, 0x00b0,
+	0x0010, 0x0009, 0x0015, 0x0030, 0x0000, 0x0400, 0x0001, 0xbd88,
+	0x0000, 0x000b, 0x0000, 0xff31, 0x0015, 0x0033, 0x0000, 0xb012,
+	0x000b, 0x87e8, 0x0003, 0x06a8, 0x0000, 0xba30, 0x0005, 0x0031,
+	0x0010, 0x0021, 0x0015, 0x0033, 0x0010, 0xb019, 0x001b, 0x87ef,
+	0x0002, 0xb200, 0x0011, 0xffc8, 0x0010, 0x00ff, 0x0010, 0xffb2,
+	0x0010, 0xb2b7, 0x0005, 0x0031, 0x0000, 0x0023, 0x0015, 0x0033,
+	0x0010, 0xb20a, 0x000b, 0x87f9, 0x0017, 0x4000, 0x0000, 0xba30,
+	0x0005, 0x0031, 0x0000, 0x0023, 0x0015, 0x0033, 0x0010, 0xb409,
+	0x000b, 0x8800, 0x0002, 0xb400, 0x0011, 0xffc8, 0x0010, 0x00ff,
+	0x0010, 0xffb4, 0x0010, 0xb4b7, 0x0005, 0x0031, 0x0000, 0x0023,
+	0x0015, 0x0033, 0x0010, 0xb40a, 0x000b, 0x880a, 0x0017, 0x4000,
+	0x0000, 0xba30, 0x0001, 0xc7c8, 0x0000, 0x0020, 0x000b, 0x1818,
+	0x0005, 0x0031, 0x0010, 0x0028, 0x0015, 0x0033, 0x0010, 0xb209,
+	0x000b, 0x8814, 0x0011, 0xb2c8, 0x0000, 0xff80, 0x0013, 0x181b,
+	0x0010, 0xc4b0, 0x0010, 0xc5b1, 0x0003, 0x081d, 0x0010, 0xc6b1,
+	0x0000, 0xc0b0, 0x0005, 0x0031, 0x0000, 0x0004, 0x0015, 0x0033,
+	0x0010, 0xb211, 0x000b, 0x8821, 0x0017, 0x4000, 0x0015, 0x00b8,
+	0x0010, 0x0009, 0x0015, 0x003a, 0x0010, 0x0707, 0x0004, 0x0867,
+	0x0013, 0x002d, 0x0015, 0x00b8, 0x0010, 0x0009, 0x0015, 0x003a,
+	0x0010, 0x0707, 0x0013, 0x0867, 0x0014, 0x0114, 0x0015, 0x0030,
+	0x0000, 0x0400, 0x0011, 0x0d88, 0x0000, 0x0004, 0x0000, 0xff31,
+	0x0015, 0x0033, 0x0000, 0xba09, 0x000b, 0x8836, 0x0004, 0x07ea,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88, 0x0000, 0x0010,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb20a, 0x000b, 0x883f,
+	0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x0d88, 0x0010, 0x0011,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0x0309, 0x000b, 0x8847,
+	0x0002, 0x0327, 0x0010, 0xffb2, 0x0011, 0x0d88, 0x0010, 0x0011,
+	0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb20a, 0x001b, 0x884f,
+	0x0015, 0x00b8, 0x0010, 0x0006, 0x0013, 0x0867, 0x0004, 0x0126,
+	0x0004, 0x07ea, 0x0015, 0x0030, 0x0000, 0x0400, 0x0011, 0x1388,
+	0x0000, 0x0010, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb20a,
+	0x000b, 0x885c, 0x0012, 0x1027, 0x0010, 0xffb2, 0x0011, 0x1388,
+	0x0010, 0x0011, 0x0000, 0xff31, 0x0015, 0x0033, 0x0010, 0xb20a,
+	0x001b, 0x8864, 0x0015, 0x00b8, 0x0000, 0x0007, 0x0003, 0x4867,
+	0x0000, 0xb838, 0x0017, 0x4000, 0xa2e7, 0x24ad
+};
+unsigned short xseqipx_code_length01 = 0x10d6;
diff --git a/drivers/scsi/qla2xxx/ql6312.c b/drivers/scsi/qla2xxx/ql6312.c
new file mode 100644
index 0000000..59268eb
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql6312.c
@@ -0,0 +1,102 @@
+/*
+ * QLogic ISP6312 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation (www.qlogic.com)
+ *
+ * Released under GPL v2.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+
+#include "qla_def.h"
+
+static char qla_driver_name[] = "qla6312";
+
+extern unsigned char  fw2300flx_version[];
+extern unsigned char  fw2300flx_version_str[];
+extern unsigned short fw2300flx_addr01;
+extern unsigned short fw2300flx_code01[];
+extern unsigned short fw2300flx_length01;
+
+static struct qla_fw_info qla_fw_tbl[] = {
+	{
+		.addressing	= FW_INFO_ADDR_NORMAL,
+		.fwcode		= &fw2300flx_code01[0],
+		.fwlen		= &fw2300flx_length01,
+		.fwstart	= &fw2300flx_addr01,
+	},
+	{ FW_INFO_ADDR_NOMORE, },
+};
+
+static struct qla_board_info qla_board_tbl[] = {
+	{
+		.drv_name	= qla_driver_name,
+		.isp_name	= "ISP6312",
+		.fw_info	= qla_fw_tbl,
+	},
+	{
+		.drv_name	= qla_driver_name,
+		.isp_name	= "ISP6322",
+		.fw_info	= qla_fw_tbl,
+	},
+};
+
+static struct pci_device_id qla6312_pci_tbl[] = {
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP6312,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl[0],
+	},
+	{
+		.vendor		= PCI_VENDOR_ID_QLOGIC,
+		.device		= PCI_DEVICE_ID_QLOGIC_ISP6322,
+		.subvendor	= PCI_ANY_ID,
+		.subdevice	= PCI_ANY_ID,
+		.driver_data	= (unsigned long)&qla_board_tbl[1],
+	},
+	{0, 0},
+};
+MODULE_DEVICE_TABLE(pci, qla6312_pci_tbl);
+
+static int __devinit
+qla6312_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	return qla2x00_probe_one(pdev,
+	    (struct qla_board_info *)id->driver_data);
+}
+
+static void __devexit
+qla6312_remove_one(struct pci_dev *pdev)
+{
+	qla2x00_remove_one(pdev);
+}
+
+static struct pci_driver qla6312_pci_driver = {
+	.name		= "qla6312",
+	.id_table	= qla6312_pci_tbl,
+	.probe		= qla6312_probe_one,
+	.remove		= __devexit_p(qla6312_remove_one),
+};
+
+static int __init
+qla6312_init(void)
+{
+	return pci_module_init(&qla6312_pci_driver);
+}
+
+static void __exit
+qla6312_exit(void)
+{
+	pci_unregister_driver(&qla6312_pci_driver);
+}
+
+module_init(qla6312_init);
+module_exit(qla6312_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic ISP63xx FC-SCSI Host Bus Adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/ql6312_fw.c b/drivers/scsi/qla2xxx/ql6312_fw.c
new file mode 100644
index 0000000..63d827d
--- /dev/null
+++ b/drivers/scsi/qla2xxx/ql6312_fw.c
@@ -0,0 +1,7147 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+/*
+ *	Firmware Version 3.03.08 (10:02 Nov 12, 2004)
+ */
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300flx_version = 3*1024+3;
+#else
+unsigned short risc_code_version = 3*1024+3;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned char fw2300flx_version_str[] = {3, 3, 8};
+#else
+unsigned char firmware_version[] = {3, 3, 8};
+#endif
+
+#ifdef UNIQUE_FW_NAME
+#define fw2300flx_VERSION_STRING "3.03.08"
+#else
+#define FW_VERSION_STRING "3.03.08"
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300flx_addr01 = 0x0800 ;
+#else
+unsigned short risc_code_addr01 = 0x0800 ;
+#endif
+
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300flx_code01[] = { 
+#else
+unsigned short risc_code01[] = { 
+#endif
+	0x0470, 0x0000, 0x0000, 0xdd79, 0x0000, 0x0003, 0x0003, 0x0008,
+	0x0317, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2032, 0x3030,
+	0x3120, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3233, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x332e, 0x3033, 0x2e30, 0x3820, 0x2020, 0x2020, 0x2400, 0x20a9,
+	0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2200, 0x20a9, 0x000f,
+	0x2001, 0x0000, 0x400f, 0x2091, 0x2400, 0x20a9, 0x000f, 0x2001,
+	0x0000, 0x400f, 0x2091, 0x2600, 0x20a9, 0x000f, 0x2001, 0x0000,
+	0x400f, 0x2091, 0x2800, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f,
+	0x2091, 0x2a00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091,
+	0x2c00, 0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2e00,
+	0x20a9, 0x000f, 0x2001, 0x0000, 0x400f, 0x2091, 0x2000, 0x2001,
+	0x0000, 0x20c1, 0x0004, 0x20c9, 0x1bff, 0x2059, 0x0000, 0x2b78,
+	0x7883, 0x0004, 0x2089, 0x2cff, 0x2051, 0x1800, 0x2a70, 0x20e1,
+	0x0001, 0x20e9, 0x0001, 0x2009, 0x0000, 0x080c, 0x0e75, 0x2029,
+	0x2480, 0x2031, 0xffff, 0x2039, 0x2450, 0x2021, 0x0050, 0x20e9,
+	0x0001, 0x20a1, 0x0000, 0x20a9, 0x0800, 0x900e, 0x4104, 0x20e9,
+	0x0001, 0x20a1, 0x1000, 0x900e, 0x2001, 0x0cc0, 0x9084, 0x0fff,
+	0x20a8, 0x4104, 0x2001, 0x0000, 0x9086, 0x0000, 0x0120, 0x21a8,
+	0x4104, 0x8001, 0x1de0, 0x756a, 0x766e, 0x7766, 0x7472, 0x7476,
+	0x00e6, 0x2071, 0x1aa2, 0x2472, 0x00ee, 0x20a1, 0x1cd0, 0x716c,
+	0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x000f, 0x2001, 0x0001,
+	0x9112, 0x900e, 0x21a8, 0x4104, 0x8211, 0x1de0, 0x716c, 0x3400,
+	0x8001, 0x9102, 0x0120, 0x0218, 0x20a8, 0x900e, 0x4104, 0x2009,
+	0x1800, 0x810d, 0x810d, 0x810d, 0x810d, 0x810d, 0x918c, 0x001f,
+	0x2001, 0x0001, 0x9112, 0x20e9, 0x0001, 0x20a1, 0x0800, 0x900e,
+	0x20a9, 0x0800, 0x4104, 0x8211, 0x1dd8, 0x080c, 0x0f49, 0x080c,
+	0x5f39, 0x080c, 0xa079, 0x080c, 0x1100, 0x080c, 0x12f8, 0x080c,
+	0x1af5, 0x080c, 0x0d8c, 0x080c, 0x1085, 0x080c, 0x33e9, 0x080c,
+	0x7518, 0x080c, 0x687e, 0x080c, 0x8215, 0x080c, 0x23bd, 0x080c,
+	0x8526, 0x080c, 0x7b99, 0x080c, 0x21e9, 0x080c, 0x231d, 0x080c,
+	0x23b2, 0x2091, 0x3009, 0x7883, 0x0000, 0x1004, 0x091d, 0x7880,
+	0x9086, 0x0002, 0x1190, 0x7883, 0x4000, 0x7837, 0x4000, 0x7833,
+	0x0010, 0x0e04, 0x0911, 0x2091, 0x5000, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x2071, 0x1800, 0x7003,
+	0x0000, 0x2071, 0x1800, 0x7000, 0x908e, 0x0003, 0x1168, 0x080c,
+	0x4be4, 0x080c, 0x3410, 0x080c, 0x7580, 0x080c, 0x6d2e, 0x080c,
+	0x823e, 0x080c, 0x2c2c, 0x0c68, 0x000b, 0x0c88, 0x0940, 0x0941,
+	0x0ad8, 0x093e, 0x0b8f, 0x0d8b, 0x0d8b, 0x0d8b, 0x080c, 0x0dfa,
+	0x0005, 0x0126, 0x00f6, 0x2091, 0x8000, 0x7000, 0x9086, 0x0001,
+	0x1904, 0x0aab, 0x080c, 0x0eb7, 0x080c, 0x7207, 0x0150, 0x080c,
+	0x722a, 0x15a0, 0x2079, 0x0100, 0x7828, 0x9085, 0x1800, 0x782a,
+	0x0468, 0x080c, 0x7127, 0x7000, 0x9086, 0x0001, 0x1904, 0x0aab,
+	0x7094, 0x9086, 0x0028, 0x1904, 0x0aab, 0x080c, 0x81fe, 0x080c,
+	0x81f0, 0x2001, 0x0161, 0x2003, 0x0001, 0x2079, 0x0100, 0x7827,
+	0xffff, 0x7a28, 0x9295, 0x5e2f, 0x7a2a, 0x2011, 0x7076, 0x080c,
+	0x82da, 0x2011, 0x7069, 0x080c, 0x83ae, 0x2011, 0x5d94, 0x080c,
+	0x82da, 0x2011, 0x8030, 0x901e, 0x7392, 0x04d0, 0x080c, 0x5641,
+	0x2079, 0x0100, 0x7844, 0x9005, 0x1904, 0x0aab, 0x2011, 0x5d94,
+	0x080c, 0x82da, 0x2011, 0x7076, 0x080c, 0x82da, 0x2011, 0x7069,
+	0x080c, 0x83ae, 0x2001, 0x0265, 0x2001, 0x0205, 0x2003, 0x0000,
+	0x7840, 0x9084, 0xfffb, 0x7842, 0x2001, 0x197e, 0x2004, 0x9005,
+	0x1140, 0x00c6, 0x2061, 0x0100, 0x080c, 0x5ee1, 0x00ce, 0x0804,
+	0x0aab, 0x780f, 0x006b, 0x7a28, 0x080c, 0x720f, 0x0118, 0x9295,
+	0x5e2f, 0x0010, 0x9295, 0x402f, 0x7a2a, 0x2011, 0x8010, 0x73d4,
+	0x2001, 0x197f, 0x2003, 0x0001, 0x080c, 0x2a89, 0x080c, 0x4b1f,
+	0x7244, 0xc284, 0x7246, 0x2001, 0x180c, 0x200c, 0xc1ac, 0xc1cc,
+	0x2102, 0x080c, 0x9904, 0x2011, 0x0004, 0x080c, 0xbe47, 0x080c,
+	0x66c2, 0x080c, 0x7207, 0x1120, 0x080c, 0x2af6, 0x02e0, 0x0400,
+	0x080c, 0x5ee8, 0x0140, 0x7093, 0x0001, 0x70cf, 0x0000, 0x080c,
+	0x580e, 0x0804, 0x0aab, 0x080c, 0x55db, 0xd094, 0x0188, 0x2011,
+	0x180c, 0x2204, 0xc0cd, 0x2012, 0x080c, 0x55df, 0xd0d4, 0x1118,
+	0x080c, 0x2af6, 0x1270, 0x2011, 0x180c, 0x2204, 0xc0bc, 0x0088,
+	0x080c, 0x55df, 0xd0d4, 0x1db8, 0x2011, 0x180c, 0x2204, 0xc0bd,
+	0x0040, 0x2011, 0x180c, 0x2204, 0xc0bd, 0x2012, 0x080c, 0x67bb,
+	0x0008, 0x2012, 0x080c, 0x6781, 0x0120, 0x7a0c, 0xc2b4, 0x7a0e,
+	0x00a8, 0x707b, 0x0000, 0x080c, 0x7207, 0x1130, 0x70ac, 0x9005,
+	0x1168, 0x080c, 0xc28a, 0x0050, 0x080c, 0xc28a, 0x70d8, 0xd09c,
+	0x1128, 0x70ac, 0x9005, 0x0110, 0x080c, 0x5ebe, 0x70e3, 0x0000,
+	0x70df, 0x0000, 0x70a3, 0x0000, 0x080c, 0x2afe, 0x0228, 0x2011,
+	0x0101, 0x2204, 0xc0c4, 0x2012, 0x72d8, 0x080c, 0x7207, 0x1178,
+	0x9016, 0x0016, 0x2009, 0x0002, 0x2019, 0x1945, 0x211a, 0x001e,
+	0x705b, 0xffff, 0x705f, 0x00ef, 0x707f, 0x0000, 0x0020, 0x2019,
+	0x1945, 0x201b, 0x0000, 0x2079, 0x185b, 0x7804, 0xd0ac, 0x0108,
+	0xc295, 0x72da, 0x080c, 0x7207, 0x0118, 0x9296, 0x0004, 0x0548,
+	0x2011, 0x0001, 0x080c, 0xbe47, 0x70a7, 0x0000, 0x70ab, 0xffff,
+	0x7003, 0x0002, 0x2079, 0x0100, 0x7827, 0x0003, 0x7828, 0x9085,
+	0x0003, 0x782a, 0x00fe, 0x080c, 0x2f6c, 0x2011, 0x0005, 0x080c,
+	0x9a0f, 0x080c, 0x8c10, 0x080c, 0x7207, 0x0148, 0x00c6, 0x2061,
+	0x0100, 0x0016, 0x2009, 0x0002, 0x61e2, 0x001e, 0x00ce, 0x012e,
+	0x0420, 0x70a7, 0x0000, 0x70ab, 0xffff, 0x7003, 0x0002, 0x00f6,
+	0x2079, 0x0100, 0x7827, 0x0003, 0x7828, 0x9085, 0x0003, 0x782a,
+	0x00fe, 0x2011, 0x0005, 0x080c, 0x9a0f, 0x080c, 0x8c10, 0x080c,
+	0x7207, 0x0148, 0x00c6, 0x2061, 0x0100, 0x0016, 0x2009, 0x0002,
+	0x61e2, 0x001e, 0x00ce, 0x00fe, 0x012e, 0x0005, 0x00c6, 0x00b6,
+	0x080c, 0x7207, 0x1118, 0x20a9, 0x0800, 0x0010, 0x20a9, 0x0782,
+	0x080c, 0x7207, 0x1110, 0x900e, 0x0010, 0x2009, 0x007e, 0x86ff,
+	0x0138, 0x9180, 0x1000, 0x2004, 0x905d, 0x0110, 0xb800, 0xd0bc,
+	0x090c, 0x3286, 0x8108, 0x1f04, 0x0abf, 0x707b, 0x0000, 0x707c,
+	0x9084, 0x00ff, 0x707e, 0x70af, 0x0000, 0x00be, 0x00ce, 0x0005,
+	0x00b6, 0x0126, 0x2091, 0x8000, 0x7000, 0x9086, 0x0002, 0x1904,
+	0x0b8c, 0x70a8, 0x9086, 0xffff, 0x0130, 0x080c, 0x2f6c, 0x080c,
+	0x8c10, 0x0804, 0x0b8c, 0x70d8, 0xd0ac, 0x1110, 0xd09c, 0x0540,
+	0xd084, 0x0530, 0x0006, 0x2001, 0x0103, 0x2003, 0x002b, 0x000e,
+	0xd08c, 0x01f0, 0x70dc, 0x9086, 0xffff, 0x01b0, 0x080c, 0x30f7,
+	0x080c, 0x8c10, 0x70d8, 0xd094, 0x1904, 0x0b8c, 0x2011, 0x0001,
+	0x080c, 0xc539, 0x0110, 0x2011, 0x0003, 0x901e, 0x080c, 0x3131,
+	0x080c, 0x8c10, 0x0804, 0x0b8c, 0x70e0, 0x9005, 0x1904, 0x0b8c,
+	0x70a4, 0x9005, 0x1904, 0x0b8c, 0x70d8, 0xd0a4, 0x0118, 0xd0b4,
+	0x0904, 0x0b8c, 0x080c, 0x6781, 0x1904, 0x0b8c, 0x080c, 0x67d4,
+	0x1904, 0x0b8c, 0x080c, 0x67bb, 0x01c0, 0x0156, 0x00c6, 0x20a9,
+	0x007f, 0x900e, 0x0016, 0x080c, 0x649f, 0x1118, 0xb800, 0xd0ec,
+	0x1138, 0x001e, 0x8108, 0x1f04, 0x0b32, 0x00ce, 0x015e, 0x0028,
+	0x001e, 0x00ce, 0x015e, 0x0804, 0x0b8c, 0x0006, 0x2001, 0x0103,
+	0x2003, 0x006b, 0x000e, 0x2011, 0x198b, 0x080c, 0x0fb9, 0x2011,
+	0x19a5, 0x080c, 0x0fb9, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003,
+	0x70ab, 0xffff, 0x080c, 0x0e99, 0x9006, 0x080c, 0x2717, 0x0036,
+	0x0046, 0x2019, 0xffff, 0x2021, 0x0006, 0x080c, 0x4cbc, 0x004e,
+	0x003e, 0x00f6, 0x2079, 0x0100, 0x080c, 0x722a, 0x0150, 0x080c,
+	0x7207, 0x7828, 0x0118, 0x9084, 0xe1ff, 0x0010, 0x9084, 0xffdf,
+	0x782a, 0x00fe, 0x2001, 0x19c0, 0x2004, 0x9086, 0x0005, 0x1120,
+	0x2011, 0x0000, 0x080c, 0x9a0f, 0x2011, 0x0000, 0x080c, 0x9a19,
+	0x080c, 0x8c10, 0x080c, 0x8ced, 0x012e, 0x00be, 0x0005, 0x0016,
+	0x0046, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2079, 0x0100, 0x7904,
+	0x918c, 0xfffd, 0x7906, 0x2009, 0x00f7, 0x080c, 0x5ea7, 0x7940,
+	0x918c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, 0x0040,
+	0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, 0x2001,
+	0x0100, 0x2004, 0x9086, 0x000a, 0x1904, 0x0c23, 0x7954, 0xd1ac,
+	0x1904, 0x0c23, 0x2001, 0x197f, 0x2004, 0x9005, 0x1518, 0x080c,
+	0x2b98, 0x1148, 0x2001, 0x0001, 0x080c, 0x2ab8, 0x2001, 0x0001,
+	0x080c, 0x2a9b, 0x00b8, 0x080c, 0x2ba0, 0x1138, 0x9006, 0x080c,
+	0x2ab8, 0x9006, 0x080c, 0x2a9b, 0x0068, 0x080c, 0x2ba8, 0x1d50,
+	0x2001, 0x1970, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c, 0x28b2,
+	0x0804, 0x0d33, 0x080c, 0x7218, 0x0148, 0x080c, 0x722a, 0x1118,
+	0x080c, 0x7513, 0x0050, 0x080c, 0x720f, 0x0dd0, 0x080c, 0x750e,
+	0x080c, 0x7504, 0x080c, 0x7127, 0x0058, 0x080c, 0x7207, 0x0140,
+	0x2009, 0x00f8, 0x080c, 0x5ea7, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x20a9, 0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x7207, 0x0138,
+	0x7824, 0xd0ac, 0x1904, 0x0d38, 0x1f04, 0x0c02, 0x0070, 0x7824,
+	0x080c, 0x7221, 0x0118, 0xd0ac, 0x1904, 0x0d38, 0x9084, 0x1800,
+	0x0d98, 0x7003, 0x0001, 0x0804, 0x0d38, 0x2001, 0x0001, 0x080c,
+	0x2717, 0x0804, 0x0d5a, 0x2001, 0x197f, 0x2004, 0x9005, 0x1518,
+	0x080c, 0x2b98, 0x1148, 0x2001, 0x0001, 0x080c, 0x2ab8, 0x2001,
+	0x0001, 0x080c, 0x2a9b, 0x00b8, 0x080c, 0x2ba0, 0x1138, 0x9006,
+	0x080c, 0x2ab8, 0x9006, 0x080c, 0x2a9b, 0x0068, 0x080c, 0x2ba8,
+	0x1d50, 0x2001, 0x1970, 0x2004, 0xd0fc, 0x0108, 0x0020, 0x080c,
+	0x28b2, 0x0804, 0x0d33, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x01f8, 0x7850, 0x9085, 0x0040, 0x7852, 0x7938, 0x7850, 0x9084,
+	0xfbcf, 0x7852, 0x080c, 0x2bb0, 0x9085, 0x2000, 0x7852, 0x793a,
+	0x20a9, 0x0046, 0x1d04, 0x0c62, 0x080c, 0x838e, 0x1f04, 0x0c62,
+	0x7850, 0x9085, 0x0400, 0x9084, 0xdfbf, 0x7852, 0x793a, 0x0060,
+	0x080c, 0x2cc2, 0x080c, 0x2cf5, 0x20a9, 0x003a, 0x1d04, 0x0c76,
+	0x080c, 0x838e, 0x1f04, 0x0c76, 0x080c, 0x7218, 0x0148, 0x080c,
+	0x722a, 0x1118, 0x080c, 0x7513, 0x0050, 0x080c, 0x720f, 0x0dd0,
+	0x080c, 0x750e, 0x080c, 0x7504, 0x080c, 0x7127, 0x0020, 0x2009,
+	0x00f8, 0x080c, 0x5ea7, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x0168, 0x20a9, 0x0028, 0xa001, 0x1f04, 0x0c9b, 0x7850, 0x9085,
+	0x1400, 0x7852, 0x080c, 0x7207, 0x0158, 0x0030, 0x7850, 0xc0e5,
+	0x7852, 0x080c, 0x7207, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x2021, 0xe678, 0x2019, 0xea60, 0x0d0c, 0x838e, 0x7820, 0xd09c,
+	0x1590, 0x080c, 0x7207, 0x0904, 0x0d17, 0x7824, 0xd0ac, 0x1904,
+	0x0d38, 0x080c, 0x722a, 0x1538, 0x0046, 0x2021, 0x0320, 0x8421,
+	0x1df0, 0x004e, 0x7827, 0x1800, 0x080c, 0x2bb0, 0x7824, 0x9084,
+	0x1800, 0x1168, 0x9484, 0x0fff, 0x1140, 0x2001, 0x1810, 0x2004,
+	0x9084, 0x9000, 0x0110, 0x080c, 0x0d68, 0x8421, 0x1160, 0x1d04,
+	0x0ce3, 0x080c, 0x838e, 0x080c, 0x750e, 0x080c, 0x7504, 0x7003,
+	0x0001, 0x0804, 0x0d38, 0x8319, 0x1938, 0x2001, 0x0100, 0x2004,
+	0x9086, 0x000a, 0x1140, 0x2001, 0x1810, 0x2004, 0x9084, 0x9000,
+	0x0110, 0x080c, 0x0d68, 0x1d04, 0x0cff, 0x080c, 0x838e, 0x2009,
+	0x1973, 0x2104, 0x9005, 0x0118, 0x8001, 0x200a, 0x1178, 0x200b,
+	0x000a, 0x7827, 0x0048, 0x20a9, 0x0002, 0x080c, 0x2b91, 0x7924,
+	0x080c, 0x2bb0, 0xd19c, 0x0110, 0x080c, 0x2a89, 0x00e0, 0x080c,
+	0x7218, 0x1140, 0x94a2, 0x03e8, 0x1128, 0x080c, 0x71df, 0x7003,
+	0x0001, 0x00b0, 0x7827, 0x1800, 0x080c, 0x2bb0, 0x7824, 0x080c,
+	0x7221, 0x0110, 0xd0ac, 0x1160, 0x9084, 0x1800, 0x0904, 0x0ceb,
+	0x7003, 0x0001, 0x0028, 0x2001, 0x0001, 0x080c, 0x2717, 0x00c0,
+	0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x1118, 0x7850, 0xc0e4,
+	0x7852, 0x2009, 0x180c, 0x210c, 0xd19c, 0x1120, 0x7904, 0x918d,
+	0x0002, 0x7906, 0x7827, 0x0048, 0x7828, 0x9085, 0x0028, 0x782a,
+	0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0120, 0x7850, 0x9085,
+	0x0400, 0x7852, 0x2001, 0x197f, 0x2003, 0x0000, 0x9006, 0x78f2,
+	0x015e, 0x003e, 0x000e, 0x012e, 0x00fe, 0x004e, 0x001e, 0x0005,
+	0x0006, 0x0016, 0x0036, 0x0046, 0x00b6, 0x00c6, 0x00d6, 0x00e6,
+	0x00f6, 0x0156, 0x0069, 0x0d0c, 0x838e, 0x015e, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x00be, 0x004e, 0x003e, 0x001e, 0x000e, 0x0005,
+	0x00e6, 0x2071, 0x189c, 0x7004, 0x9086, 0x0001, 0x1110, 0x080c,
+	0x3410, 0x00ee, 0x0005, 0x0005, 0x2a70, 0x2061, 0x1983, 0x2063,
+	0x0003, 0x6007, 0x0003, 0x600b, 0x0008, 0x600f, 0x0317, 0x2001,
+	0x1954, 0x900e, 0x2102, 0x7192, 0x2001, 0x0100, 0x2004, 0x9082,
+	0x0002, 0x0218, 0x705b, 0xffff, 0x0008, 0x715a, 0x7063, 0xffff,
+	0x717a, 0x717e, 0x080c, 0xc28a, 0x70e7, 0x00c0, 0x2061, 0x1944,
+	0x6003, 0x0909, 0x6106, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013,
+	0x00ff, 0x6017, 0x000f, 0x611a, 0x601f, 0x07d0, 0x2061, 0x194c,
+	0x6003, 0x8000, 0x6106, 0x610a, 0x600f, 0x0200, 0x6013, 0x00ff,
+	0x6116, 0x601b, 0x0001, 0x611e, 0x2061, 0x1961, 0x6003, 0x514c,
+	0x6007, 0x4f47, 0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0x182b,
+	0x2102, 0x0005, 0x9016, 0x080c, 0x649f, 0x1178, 0xb804, 0x90c4,
+	0x00ff, 0x98c6, 0x0006, 0x0128, 0x90c4, 0xff00, 0x98c6, 0x0600,
+	0x1120, 0x9186, 0x0080, 0x0108, 0x8210, 0x8108, 0x9186, 0x0800,
+	0x1d50, 0x2208, 0x0005, 0x2091, 0x8000, 0x2079, 0x0000, 0x000e,
+	0x00f6, 0x0010, 0x2091, 0x8000, 0x0e04, 0x0dfc, 0x0006, 0x0016,
+	0x2001, 0x8002, 0x0006, 0x2079, 0x0000, 0x000e, 0x7882, 0x7836,
+	0x001e, 0x798e, 0x000e, 0x788a, 0x000e, 0x7886, 0x3900, 0x789a,
+	0x7833, 0x0012, 0x2091, 0x5000, 0x0156, 0x00d6, 0x0036, 0x0026,
+	0x2079, 0x0300, 0x2069, 0x1a7c, 0x7a08, 0x226a, 0x2069, 0x1a7d,
+	0x7a18, 0x226a, 0x8d68, 0x7a1c, 0x226a, 0x782c, 0x2019, 0x1a8a,
+	0x201a, 0x2019, 0x1a8d, 0x9016, 0x7808, 0xd09c, 0x0168, 0x7820,
+	0x201a, 0x8210, 0x8318, 0x9386, 0x1aa2, 0x0108, 0x0ca8, 0x7808,
+	0xd09c, 0x0110, 0x2011, 0xdead, 0x2019, 0x1a8b, 0x782c, 0x201a,
+	0x8318, 0x221a, 0x7803, 0x0000, 0x2069, 0x1a5c, 0x901e, 0x20a9,
+	0x0020, 0x7b26, 0x7a28, 0x226a, 0x8d68, 0x8318, 0x1f04, 0x0e49,
+	0x002e, 0x003e, 0x00de, 0x015e, 0x2079, 0x1800, 0x7803, 0x0005,
+	0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x0180, 0x2001,
+	0x19f1, 0x2004, 0x9005, 0x0128, 0x2001, 0x008b, 0x2004, 0xd0fc,
+	0x0dd8, 0x2001, 0x008a, 0x2003, 0x0002, 0x2003, 0x1001, 0x080c,
+	0x55ea, 0x1108, 0x0099, 0x0cd8, 0x0005, 0x918c, 0x03ff, 0x2001,
+	0x0003, 0x2004, 0x9084, 0x0600, 0x1118, 0x918d, 0x6c00, 0x0010,
+	0x918d, 0x6400, 0x2001, 0x017f, 0x2102, 0x0005, 0x0026, 0x0126,
+	0x2011, 0x0080, 0x080c, 0x0f11, 0x20a9, 0x0900, 0x080c, 0x0f32,
+	0x2011, 0x0040, 0x080c, 0x0f11, 0x20a9, 0x0900, 0x080c, 0x0f32,
+	0x0c78, 0x0026, 0x080c, 0x0f1e, 0x1118, 0x2011, 0x0040, 0x0098,
+	0x2011, 0x010e, 0x2214, 0x9294, 0x0007, 0x9296, 0x0007, 0x0118,
+	0x2011, 0xa880, 0x0010, 0x2011, 0x6840, 0xd0e4, 0x70eb, 0x0000,
+	0x1120, 0x70eb, 0x0fa0, 0x080c, 0x0f23, 0x002e, 0x0005, 0x0026,
+	0x080c, 0x0f1e, 0x0128, 0xd0a4, 0x1138, 0x2011, 0xcdd5, 0x0010,
+	0x2011, 0x0080, 0x080c, 0x0f23, 0x002e, 0x0005, 0x0026, 0x70eb,
+	0x0000, 0x080c, 0x0f1e, 0x1148, 0x080c, 0x2ba8, 0x1118, 0x2011,
+	0x8484, 0x0058, 0x2011, 0x8282, 0x0040, 0x080c, 0x2ba8, 0x1118,
+	0x2011, 0xcdc5, 0x0010, 0x2011, 0xcac2, 0x080c, 0x0f23, 0x002e,
+	0x0005, 0x00e6, 0x0006, 0x2071, 0x1800, 0xd0b4, 0x70e4, 0x1110,
+	0xc0e4, 0x0048, 0x0006, 0x3b00, 0x9084, 0xff3f, 0x20d8, 0x000e,
+	0x70eb, 0x0000, 0xc0e5, 0x0079, 0x000e, 0x00ee, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0xd0e4, 0x70e4, 0x1110, 0xc0dc, 0x0008, 0xc0dd,
+	0x0011, 0x00ee, 0x0005, 0x70e6, 0x7000, 0x9084, 0x0007, 0x000b,
+	0x0005, 0x0ee0, 0x0eb7, 0x0eb7, 0x0e99, 0x0ec6, 0x0eb7, 0x0eb7,
+	0x0ec6, 0x0016, 0x3b08, 0x3a00, 0x9104, 0x918d, 0x00c0, 0x21d8,
+	0x9084, 0xff3f, 0x9205, 0x20d0, 0x001e, 0x0005, 0x2001, 0x1839,
+	0x2004, 0xd0dc, 0x0005, 0x9e86, 0x1800, 0x190c, 0x0dfa, 0x70e4,
+	0xd0e4, 0x0108, 0xc2e5, 0x72e6, 0xd0e4, 0x1118, 0x9294, 0x00c0,
+	0x0c01, 0x0005, 0x1d04, 0x0f32, 0x2091, 0x6000, 0x1f04, 0x0f32,
+	0x0005, 0x890e, 0x810e, 0x810f, 0x9194, 0x003f, 0x918c, 0xffc0,
+	0x0005, 0x0006, 0x2200, 0x914d, 0x894f, 0x894d, 0x894d, 0x000e,
+	0x0005, 0x01d6, 0x0146, 0x0036, 0x0096, 0x2061, 0x188b, 0x600b,
+	0x0000, 0x600f, 0x0000, 0x6003, 0x0000, 0x6007, 0x0000, 0x2009,
+	0xffc0, 0x2105, 0x0006, 0x2001, 0xaaaa, 0x200f, 0x2019, 0x5555,
+	0x9016, 0x2049, 0x0bff, 0xab02, 0xa001, 0xa001, 0xa800, 0x9306,
+	0x1138, 0x2105, 0x9306, 0x0120, 0x8210, 0x99c8, 0x0400, 0x0c98,
+	0x000e, 0x200f, 0x2001, 0x189b, 0x928a, 0x000e, 0x1638, 0x928a,
+	0x0006, 0x2011, 0x0006, 0x1210, 0x2011, 0x0000, 0x2202, 0x9006,
+	0x2008, 0x82ff, 0x01b0, 0x8200, 0x600a, 0x600f, 0xffff, 0x6003,
+	0x0002, 0x6007, 0x0000, 0x0026, 0x2019, 0x0010, 0x9280, 0x0001,
+	0x20e8, 0x21a0, 0x21a8, 0x4104, 0x8319, 0x1de0, 0x8211, 0x1da0,
+	0x002e, 0x009e, 0x003e, 0x014e, 0x01de, 0x0005, 0x2011, 0x000e,
+	0x08e8, 0x0016, 0x0026, 0x0096, 0x3348, 0x080c, 0x0f39, 0x2100,
+	0x9300, 0x2098, 0x22e0, 0x009e, 0x002e, 0x001e, 0x0036, 0x3518,
+	0x20a9, 0x0001, 0x4002, 0x8007, 0x4004, 0x8319, 0x1dd8, 0x003e,
+	0x0005, 0x20e9, 0x0001, 0x71b4, 0x81ff, 0x11c0, 0x9006, 0x2009,
+	0x0200, 0x20a9, 0x0002, 0x9298, 0x0018, 0x23a0, 0x4001, 0x2009,
+	0x0700, 0x20a9, 0x0002, 0x9298, 0x0008, 0x23a0, 0x4001, 0x7078,
+	0x8007, 0x717c, 0x810f, 0x20a9, 0x0002, 0x4001, 0x9298, 0x000c,
+	0x23a0, 0x900e, 0x080c, 0x0dda, 0x2001, 0x0000, 0x810f, 0x20a9,
+	0x0002, 0x4001, 0x0005, 0x89ff, 0x0140, 0xa804, 0xa807, 0x0000,
+	0x0006, 0x080c, 0x1063, 0x009e, 0x0cb0, 0x0005, 0x00e6, 0x2071,
+	0x1800, 0x080c, 0x10dc, 0x090c, 0x0dfa, 0x00ee, 0x0005, 0x0086,
+	0x00e6, 0x0006, 0x0026, 0x0036, 0x0126, 0x2091, 0x8000, 0x00c9,
+	0x2071, 0x1800, 0x73bc, 0x702c, 0x9016, 0x9045, 0x0158, 0x8210,
+	0x9906, 0x090c, 0x0dfa, 0x2300, 0x9202, 0x0120, 0x1a0c, 0x0dfa,
+	0xa000, 0x0c98, 0x012e, 0x003e, 0x002e, 0x000e, 0x00ee, 0x008e,
+	0x0005, 0x0086, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x190e, 0x7010, 0x9005, 0x0140, 0x7018, 0x9045, 0x0128, 0x9906,
+	0x090c, 0x0dfa, 0xa000, 0x0cc8, 0x012e, 0x000e, 0x00ee, 0x008e,
+	0x0005, 0x00e6, 0x2071, 0x1800, 0x0126, 0x2091, 0x8000, 0x70bc,
+	0x8001, 0x0270, 0x70be, 0x702c, 0x2048, 0x9085, 0x0001, 0xa800,
+	0x702e, 0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x00ee, 0x0005,
+	0x904e, 0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0x1800,
+	0x70bc, 0x90ca, 0x0040, 0x0268, 0x8001, 0x70be, 0x702c, 0x2048,
+	0xa800, 0x702e, 0xa803, 0x0000, 0xa807, 0x0000, 0x012e, 0x00ee,
+	0x0005, 0x904e, 0x0cd8, 0x00e6, 0x0126, 0x2091, 0x8000, 0x0016,
+	0x890e, 0x810e, 0x810f, 0x9184, 0x003f, 0xa862, 0x9184, 0xffc0,
+	0xa85e, 0x001e, 0x0020, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc, 0x8000, 0x70be,
+	0x080c, 0x81f0, 0x012e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9026,
+	0x2009, 0x0000, 0x2049, 0x0400, 0x2900, 0x702e, 0x8940, 0x2800,
+	0xa802, 0xa95e, 0xa863, 0x0001, 0x8420, 0x9886, 0x0440, 0x0120,
+	0x2848, 0x9188, 0x0040, 0x0c90, 0x2071, 0x188b, 0x7000, 0x9005,
+	0x11a0, 0x2001, 0x0492, 0xa802, 0x2048, 0x2009, 0x2480, 0x8940,
+	0x2800, 0xa802, 0xa95e, 0xa863, 0x0001, 0x8420, 0x9886, 0x0800,
+	0x0120, 0x2848, 0x9188, 0x0040, 0x0c90, 0x2071, 0x188b, 0x7104,
+	0x7200, 0x82ff, 0x01d0, 0x7308, 0x8318, 0x831f, 0x831b, 0x831b,
+	0x7312, 0x8319, 0x2001, 0x0800, 0xa802, 0x2048, 0x8900, 0xa802,
+	0x2040, 0xa95e, 0xaa62, 0x8420, 0x2300, 0x9906, 0x0130, 0x2848,
+	0x9188, 0x0040, 0x9291, 0x0000, 0x0c88, 0xa803, 0x0000, 0x2071,
+	0x1800, 0x74ba, 0x74be, 0x0005, 0x00e6, 0x0016, 0x9984, 0xfc00,
+	0x01e8, 0x908c, 0xf800, 0x1168, 0x9982, 0x0400, 0x02b8, 0x9982,
+	0x0440, 0x0278, 0x9982, 0x0492, 0x0288, 0x9982, 0x0800, 0x1270,
+	0x0040, 0x9982, 0x0800, 0x0250, 0x2071, 0x188b, 0x7010, 0x9902,
+	0x1228, 0x9085, 0x0001, 0x001e, 0x00ee, 0x0005, 0x9006, 0x0cd8,
+	0x00e6, 0x2071, 0x19f0, 0x7007, 0x0000, 0x9006, 0x701e, 0x7022,
+	0x7002, 0x2071, 0x0000, 0x7010, 0x9085, 0x8044, 0x7012, 0x2071,
+	0x0080, 0x9006, 0x0006, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x000e, 0x1158, 0x702b, 0x0060, 0x20a9, 0x0040, 0x7022, 0x1f04,
+	0x111e, 0x702b, 0x0060, 0x702b, 0x0020, 0x20a9, 0x0040, 0x7022,
+	0x1f04, 0x1127, 0x702b, 0x0020, 0x00ee, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x00e6, 0xa06f, 0x0000, 0x2071, 0x19f0, 0x701c, 0x9088,
+	0x19fa, 0x280a, 0x8000, 0x9084, 0x003f, 0x701e, 0x7120, 0x9106,
+	0x090c, 0x0dfa, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079, 0x0080,
+	0x00a9, 0x00fe, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x00e6, 0x2071, 0x19f0, 0x7004, 0x9005, 0x1128, 0x00f6, 0x2079,
+	0x0080, 0x0021, 0x00fe, 0x00ee, 0x012e, 0x0005, 0x7004, 0x9086,
+	0x0000, 0x1110, 0x7007, 0x0006, 0x7000, 0x0002, 0x1170, 0x116e,
+	0x116e, 0x116e, 0x12e7, 0x12e7, 0x12e7, 0x12e7, 0x080c, 0x0dfa,
+	0x701c, 0x7120, 0x9106, 0x1148, 0x792c, 0x9184, 0x0001, 0x1120,
+	0xd1fc, 0x1110, 0x7007, 0x0000, 0x0005, 0x0096, 0x9180, 0x19fa,
+	0x2004, 0x700a, 0x2048, 0x8108, 0x918c, 0x003f, 0x7122, 0x782b,
+	0x0026, 0xa88c, 0x7802, 0xa890, 0x7806, 0xa894, 0x780a, 0xa898,
+	0x780e, 0xa878, 0x700e, 0xa870, 0x7016, 0xa874, 0x701a, 0xa868,
+	0x009e, 0xd084, 0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007,
+	0x0002, 0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040,
+	0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e, 0x7212, 0x8203,
+	0x7812, 0x782b, 0x0020, 0x782b, 0x0041, 0x002e, 0x001e, 0x0005,
+	0x0016, 0x0026, 0x0136, 0x0146, 0x0156, 0x7014, 0x20e0, 0x7018,
+	0x2098, 0x20e9, 0x0000, 0x20a1, 0x0088, 0x782b, 0x0026, 0x710c,
+	0x2011, 0x0040, 0x9182, 0x0040, 0x1210, 0x2110, 0x9006, 0x700e,
+	0x22a8, 0x4006, 0x8203, 0x7812, 0x782b, 0x0020, 0x3300, 0x701a,
+	0x782b, 0x0001, 0x015e, 0x014e, 0x013e, 0x002e, 0x001e, 0x0005,
+	0x2009, 0x19f0, 0x2104, 0xc095, 0x200a, 0x080c, 0x114d, 0x0005,
+	0x0016, 0x00e6, 0x2071, 0x19f0, 0x00f6, 0x2079, 0x0080, 0x792c,
+	0xd1bc, 0x190c, 0x0df3, 0x782b, 0x0002, 0xd1fc, 0x0120, 0x918c,
+	0x0700, 0x7004, 0x0023, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x115e,
+	0x1206, 0x123a, 0x0dfa, 0x0dfa, 0x12f3, 0x0dfa, 0x918c, 0x0700,
+	0x1550, 0x0136, 0x0146, 0x0156, 0x7014, 0x20e8, 0x7018, 0x20a0,
+	0x20e1, 0x0000, 0x2099, 0x0088, 0x782b, 0x0040, 0x7010, 0x20a8,
+	0x4005, 0x3400, 0x701a, 0x015e, 0x014e, 0x013e, 0x700c, 0x9005,
+	0x0578, 0x7800, 0x7802, 0x7804, 0x7806, 0x080c, 0x11a3, 0x0005,
+	0x7008, 0x0096, 0x2048, 0xa86f, 0x0100, 0x009e, 0x7007, 0x0000,
+	0x080c, 0x115e, 0x0005, 0x7008, 0x0096, 0x2048, 0xa86f, 0x0200,
+	0x009e, 0x0ca0, 0x918c, 0x0700, 0x1150, 0x700c, 0x9005, 0x0180,
+	0x7800, 0x7802, 0x7804, 0x7806, 0x080c, 0x11b8, 0x0005, 0x7008,
+	0x0096, 0x2048, 0xa86f, 0x0200, 0x009e, 0x7007, 0x0000, 0x0080,
+	0x0096, 0x7008, 0x2048, 0x7800, 0xa88e, 0x7804, 0xa892, 0x7808,
+	0xa896, 0x780c, 0xa89a, 0xa86f, 0x0100, 0x009e, 0x7007, 0x0000,
+	0x0096, 0x00d6, 0x7008, 0x2048, 0x2001, 0x18b7, 0x2004, 0x9906,
+	0x1128, 0xa89c, 0x080f, 0x00de, 0x009e, 0x00a0, 0x00de, 0x009e,
+	0x0096, 0x00d6, 0x7008, 0x2048, 0x0081, 0x0150, 0xa89c, 0x0086,
+	0x2940, 0x080f, 0x008e, 0x00de, 0x009e, 0x080c, 0x114d, 0x0005,
+	0x00de, 0x009e, 0x080c, 0x114d, 0x0005, 0xa8a8, 0xd08c, 0x0005,
+	0x0096, 0xa0a0, 0x904d, 0x090c, 0x0dfa, 0xa06c, 0x908e, 0x0100,
+	0x0130, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4002, 0x080c,
+	0x6adc, 0xa09f, 0x0000, 0xa0a3, 0x0000, 0x2848, 0x080c, 0x1063,
+	0x009e, 0x0005, 0x00a6, 0xa0a0, 0x904d, 0x090c, 0x0dfa, 0xa06c,
+	0x908e, 0x0100, 0x0128, 0xa87b, 0x0001, 0xa883, 0x0000, 0x00c0,
+	0xa80c, 0x2050, 0xb004, 0x9005, 0x0198, 0xa80e, 0x2050, 0x8006,
+	0x8006, 0x8007, 0x908c, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002,
+	0xa076, 0xa172, 0xb000, 0xa07a, 0x2810, 0x080c, 0x112e, 0x00e8,
+	0xa97c, 0xa894, 0x0016, 0x0006, 0x080c, 0x6adc, 0x000e, 0x001e,
+	0xd1fc, 0x1138, 0xd1f4, 0x0128, 0x00c6, 0x2060, 0x080c, 0xa0e3,
+	0x00ce, 0x7008, 0x2048, 0xa89f, 0x0000, 0xa8a3, 0x0000, 0x080c,
+	0x1063, 0x7007, 0x0000, 0x080c, 0x114d, 0x00ae, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x782b, 0x1001, 0x7007, 0x0005, 0x7000, 0xc094,
+	0x7002, 0x012e, 0x0005, 0x7007, 0x0000, 0x080c, 0x115e, 0x0005,
+	0x0126, 0x2091, 0x2200, 0x2079, 0x0300, 0x2071, 0x1a3a, 0x7003,
+	0x0000, 0x78bf, 0x00f6, 0x781b, 0x4800, 0x0419, 0x7803, 0x0003,
+	0x780f, 0x0000, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0128,
+	0x20a9, 0x0254, 0x2061, 0xdc42, 0x0020, 0x20a9, 0x0241, 0x2061,
+	0xe0e8, 0x2c0d, 0x7912, 0xe104, 0x9ce0, 0x0002, 0x7916, 0x1f04,
+	0x1319, 0x7807, 0x0007, 0x7803, 0x0000, 0x7803, 0x0001, 0x012e,
+	0x0005, 0x00c6, 0x7803, 0x0000, 0x7808, 0xd09c, 0x0110, 0x7820,
+	0x0cd8, 0x2001, 0x1a3b, 0x2003, 0x0000, 0x78ab, 0x0004, 0x78ac,
+	0xd0ac, 0x1de8, 0x78ab, 0x0002, 0x7807, 0x0007, 0x7827, 0x0030,
+	0x782b, 0x0400, 0x7827, 0x0031, 0x782b, 0x1a5c, 0x781f, 0xff00,
+	0x781b, 0xb700, 0x2001, 0x0200, 0x2004, 0xd0dc, 0x0110, 0x781f,
+	0x0303, 0x2061, 0x1a5c, 0x602f, 0x1cd0, 0x2001, 0x1819, 0x2004,
+	0x9082, 0x1cd0, 0x6032, 0x603b, 0x1fc8, 0x2001, 0x32e9, 0xd0fc,
+	0x190c, 0x0dfa, 0x2001, 0x0003, 0x2004, 0xd0d4, 0x1118, 0x783f,
+	0x32e9, 0x0020, 0x9084, 0xc000, 0x783f, 0xb2e9, 0x00ce, 0x0005,
+	0x0126, 0x2091, 0x2200, 0x7908, 0x9184, 0x0070, 0x190c, 0x0df3,
+	0xd19c, 0x0158, 0x7820, 0x908c, 0xf000, 0x15e8, 0x908a, 0x0024,
+	0x1a0c, 0x0dfa, 0x0023, 0x012e, 0x0005, 0x012e, 0x0005, 0x13ab,
+	0x13ab, 0x13c2, 0x13c7, 0x13cb, 0x13d0, 0x13f8, 0x13fc, 0x140a,
+	0x140e, 0x13ab, 0x149a, 0x149e, 0x150e, 0x13ab, 0x13ab, 0x13ab,
+	0x13ab, 0x13ab, 0x13ab, 0x13ab, 0x13ab, 0x13ab, 0x13ab, 0x13ab,
+	0x13ab, 0x13ab, 0x13d2, 0x13ab, 0x13ab, 0x13ab, 0x13ab, 0x13ab,
+	0x13ab, 0x13af, 0x13ad, 0x080c, 0x0dfa, 0x080c, 0x0df3, 0x080c,
+	0x1515, 0x2009, 0x1a52, 0x2104, 0x8000, 0x200a, 0x080c, 0x7c6d,
+	0x080c, 0x19ff, 0x0005, 0x2009, 0x0048, 0x2060, 0x080c, 0xa15d,
+	0x012e, 0x0005, 0x7004, 0xc085, 0xc0b5, 0x7006, 0x0005, 0x7004,
+	0xc085, 0x7006, 0x0005, 0x080c, 0x1515, 0x080c, 0x166e, 0x0005,
+	0x080c, 0x0dfa, 0x080c, 0x1515, 0x2060, 0x6014, 0x0096, 0x2048,
+	0xa83b, 0xffff, 0x009e, 0x2009, 0x0048, 0x080c, 0xa15d, 0x2001,
+	0x015d, 0x2003, 0x0000, 0x2009, 0x03e8, 0x8109, 0x0160, 0x2001,
+	0x0201, 0x2004, 0x9005, 0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec,
+	0x1110, 0x080c, 0x151a, 0x2001, 0x0307, 0x2003, 0x8000, 0x0005,
+	0x7004, 0xc095, 0x7006, 0x0005, 0x080c, 0x1515, 0x2060, 0x6014,
+	0x0096, 0x2048, 0xa83b, 0xffff, 0x009e, 0x2009, 0x0048, 0x080c,
+	0xa15d, 0x0005, 0x080c, 0x1515, 0x080c, 0x0dfa, 0x080c, 0x1515,
+	0x080c, 0x1485, 0x7827, 0x0018, 0x79ac, 0xd1dc, 0x0540, 0x7827,
+	0x0015, 0x7828, 0x782b, 0x0000, 0x9065, 0x0138, 0x2001, 0x020d,
+	0x2003, 0x0050, 0x2003, 0x0020, 0x0400, 0x7004, 0x9005, 0x1180,
+	0x78ab, 0x0004, 0x7827, 0x0018, 0x782b, 0x0000, 0xd1bc, 0x090c,
+	0x0dfa, 0x2001, 0x020d, 0x2003, 0x0050, 0x2003, 0x0020, 0x0490,
+	0x78ab, 0x0004, 0x7803, 0x0001, 0x080c, 0x149e, 0x0005, 0x7828,
+	0x782b, 0x0000, 0x9065, 0x090c, 0x0dfa, 0x6014, 0x2048, 0x78ab,
+	0x0004, 0x918c, 0x0700, 0x01a8, 0x080c, 0x7c6d, 0x080c, 0x19ff,
+	0x080c, 0xbe37, 0x0158, 0xa9ac, 0xa936, 0xa9b0, 0xa93a, 0xa83f,
+	0xffff, 0xa843, 0xffff, 0xa880, 0xc0bd, 0xa882, 0x080c, 0xba56,
+	0x0005, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x6024,
+	0x190c, 0xc223, 0x2029, 0x00c8, 0x8529, 0x0128, 0x2001, 0x0201,
+	0x2004, 0x9005, 0x0dc8, 0x7dbc, 0x080c, 0xdbeb, 0xd5a4, 0x1118,
+	0x080c, 0x151a, 0x0005, 0x080c, 0x7c6d, 0x080c, 0x19ff, 0x0005,
+	0x781f, 0x0300, 0x7803, 0x0001, 0x0005, 0x0016, 0x0066, 0x0076,
+	0x00f6, 0x2079, 0x0300, 0x7908, 0x918c, 0x0007, 0x9186, 0x0003,
+	0x0120, 0x2001, 0x0016, 0x080c, 0x158b, 0x00fe, 0x007e, 0x006e,
+	0x001e, 0x0005, 0x7004, 0xc09d, 0x7006, 0x0005, 0x7104, 0x9184,
+	0x0004, 0x190c, 0x0dfa, 0xd184, 0x11b1, 0xd19c, 0x0180, 0xc19c,
+	0x7106, 0x0016, 0x080c, 0x1651, 0x001e, 0x0148, 0x2001, 0x020d,
+	0x2003, 0x0050, 0x2003, 0x0020, 0x080c, 0x151a, 0x0005, 0x81ff,
+	0x190c, 0x0dfa, 0x0005, 0x2100, 0xc184, 0xc1b4, 0x7106, 0xd0b4,
+	0x0016, 0x00e6, 0x1904, 0x1503, 0x2071, 0x0200, 0x080c, 0x1645,
+	0x080c, 0x1651, 0x05a8, 0x6014, 0x9005, 0x05a8, 0x0096, 0x2048,
+	0xa864, 0x009e, 0x9084, 0x00ff, 0x908e, 0x0029, 0x0160, 0x908e,
+	0x0048, 0x1548, 0x601c, 0xd084, 0x11d8, 0x00f6, 0x2c78, 0x080c,
+	0x16db, 0x00fe, 0x00a8, 0x00f6, 0x2c78, 0x080c, 0x1825, 0x00fe,
+	0x2009, 0x01f4, 0x8109, 0x0160, 0x2001, 0x0201, 0x2004, 0x9005,
+	0x0dc8, 0x2001, 0x0218, 0x2004, 0xd0ec, 0x1110, 0x0419, 0x0040,
+	0x2001, 0x020d, 0x2003, 0x0020, 0x080c, 0x1329, 0x7803, 0x0001,
+	0x00ee, 0x001e, 0x0005, 0x080c, 0x1651, 0x0dd0, 0x2001, 0x020d,
+	0x2003, 0x0050, 0x2003, 0x0020, 0x0069, 0x0c90, 0x0031, 0x2060,
+	0x2009, 0x0053, 0x080c, 0xa15d, 0x0005, 0x7808, 0xd09c, 0x0de8,
+	0x7820, 0x0005, 0x080c, 0x1485, 0x00d6, 0x2069, 0x0200, 0x2009,
+	0x01f4, 0x8109, 0x0510, 0x6804, 0x9005, 0x0dd8, 0x2001, 0x015d,
+	0x2003, 0x0000, 0x79bc, 0xd1a4, 0x1528, 0x79b8, 0x918c, 0x0fff,
+	0x0180, 0x9182, 0x0841, 0x1268, 0x9188, 0x0007, 0x918c, 0x0ff8,
+	0x810c, 0x810c, 0x810c, 0x080c, 0x157d, 0x6827, 0x0001, 0x8109,
+	0x1dd0, 0x04d9, 0x6827, 0x0002, 0x04c1, 0x6804, 0x9005, 0x1130,
+	0x682c, 0xd0e4, 0x1500, 0x6804, 0x9005, 0x0de8, 0x79b8, 0xd1ec,
+	0x1130, 0x08c0, 0x080c, 0x7c6d, 0x080c, 0x19ff, 0x0090, 0x7827,
+	0x0015, 0x782b, 0x0000, 0x7827, 0x0018, 0x782b, 0x0000, 0x2001,
+	0x020d, 0x2003, 0x0020, 0x2001, 0x0307, 0x2003, 0x0300, 0x7803,
+	0x0001, 0x00de, 0x0005, 0x682c, 0x9084, 0x5400, 0x9086, 0x5400,
+	0x0d30, 0x7827, 0x0015, 0x782b, 0x0000, 0x7803, 0x0001, 0x6800,
+	0x9085, 0x1800, 0x6802, 0x00de, 0x0005, 0x6824, 0x9084, 0x0003,
+	0x1de0, 0x0005, 0x2001, 0x0030, 0x2c08, 0x621c, 0x0021, 0x7830,
+	0x9086, 0x0041, 0x0005, 0x00f6, 0x2079, 0x0300, 0x0006, 0x7808,
+	0xd09c, 0x0140, 0x0016, 0x0026, 0x00c6, 0x080c, 0x1370, 0x00ce,
+	0x002e, 0x001e, 0x000e, 0x0006, 0x7832, 0x7936, 0x7a3a, 0x781b,
+	0x8080, 0x0059, 0x1118, 0x000e, 0x00fe, 0x0005, 0x000e, 0x792c,
+	0x3900, 0x8000, 0x2004, 0x080c, 0x0dfa, 0x2009, 0x180c, 0x2104,
+	0xc0f4, 0x200a, 0x2009, 0xff00, 0x8109, 0x0904, 0x1609, 0x7a18,
+	0x9284, 0x0030, 0x0904, 0x1604, 0x9284, 0x0048, 0x9086, 0x0008,
+	0x1904, 0x1604, 0x2001, 0x0109, 0x2004, 0xd08c, 0x01f0, 0x0006,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x0126, 0x2091, 0x2800,
+	0x00f6, 0x0026, 0x0016, 0x2009, 0x1a55, 0x2104, 0x8000, 0x0208,
+	0x200a, 0x080c, 0x8632, 0x001e, 0x002e, 0x00fe, 0x012e, 0x015e,
+	0x014e, 0x013e, 0x01de, 0x01ce, 0x000e, 0x2001, 0x009b, 0x2004,
+	0xd0fc, 0x01d0, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x00f6, 0x0016, 0x2009, 0x1a56, 0x2104, 0x8000, 0x0208,
+	0x200a, 0x080c, 0x1dec, 0x001e, 0x00fe, 0x015e, 0x014e, 0x013e,
+	0x01de, 0x01ce, 0x012e, 0x000e, 0x7818, 0xd0bc, 0x1904, 0x15b4,
+	0x0005, 0x2001, 0x180c, 0x2004, 0xd0f4, 0x1528, 0x7a18, 0x9284,
+	0x0030, 0x0508, 0x9284, 0x0048, 0x9086, 0x0008, 0x11e0, 0x2001,
+	0x19ce, 0x2004, 0x9005, 0x01b8, 0x2001, 0x1a3d, 0x2004, 0x9086,
+	0x0000, 0x0188, 0x2009, 0x1a54, 0x2104, 0x8000, 0x0208, 0x200a,
+	0x080c, 0x96d4, 0x2009, 0x180c, 0x2104, 0xc0f5, 0x200a, 0x2009,
+	0xff00, 0x0804, 0x15b4, 0x9085, 0x0001, 0x0005, 0x7832, 0x7936,
+	0x7a3a, 0x781b, 0x8080, 0x080c, 0x15ad, 0x1108, 0x0005, 0x792c,
+	0x3900, 0x8000, 0x2004, 0x080c, 0x0dfa, 0x7037, 0x0001, 0x7150,
+	0x7037, 0x0002, 0x7050, 0x2060, 0xd1bc, 0x1110, 0x7054, 0x2060,
+	0x0005, 0x0006, 0x0046, 0x00e6, 0x2071, 0x0200, 0x7037, 0x0002,
+	0x7058, 0x9084, 0xff00, 0x8007, 0x9086, 0x00bc, 0x1158, 0x2021,
+	0x1a53, 0x2404, 0x8000, 0x0208, 0x2022, 0x080c, 0x7c6d, 0x080c,
+	0x19ff, 0x9006, 0x00ee, 0x004e, 0x000e, 0x0005, 0x0c11, 0x1108,
+	0x0005, 0x00e6, 0x0016, 0x2071, 0x0200, 0x0879, 0x6124, 0xd1dc,
+	0x01f8, 0x701c, 0xd08c, 0x0904, 0x16d0, 0x7017, 0x0000, 0x2001,
+	0x0264, 0x2004, 0xd0bc, 0x0904, 0x16d0, 0x2001, 0x0268, 0x00c6,
+	0x2064, 0x6104, 0x6038, 0x00ce, 0x918e, 0x0039, 0x1904, 0x16d0,
+	0x9c06, 0x15f0, 0x0126, 0x2091, 0x2600, 0x080c, 0x7bb4, 0x012e,
+	0x7358, 0x745c, 0x6014, 0x905d, 0x0598, 0x2b48, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x190c, 0xc1fe, 0xab42, 0xac3e,
+	0x2001, 0x187d, 0x2004, 0xd0b4, 0x1170, 0x601c, 0xd0e4, 0x1158,
+	0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1120, 0xa83b,
+	0x7fff, 0xa837, 0xffff, 0x080c, 0x1fe8, 0x1190, 0x080c, 0x1882,
+	0x2a00, 0xa816, 0x0130, 0x2800, 0xa80e, 0x2c05, 0xa80a, 0x2c00,
+	0xa812, 0x7037, 0x0020, 0x781f, 0x0300, 0x001e, 0x00ee, 0x0005,
+	0x7037, 0x0050, 0x7037, 0x0020, 0x001e, 0x00ee, 0x080c, 0x151a,
+	0x0005, 0x080c, 0x0dfa, 0x0016, 0x2009, 0x00a0, 0x8109, 0xa001,
+	0xa001, 0xa001, 0x1dd8, 0x001e, 0x2ff0, 0x0126, 0x2091, 0x2200,
+	0x0016, 0x00c6, 0x3e60, 0x6014, 0x2048, 0x2940, 0x903e, 0x2730,
+	0xa864, 0x2068, 0xa81a, 0x9d84, 0x000f, 0x9088, 0x1fc8, 0x2165,
+	0x0002, 0x1710, 0x175d, 0x1710, 0x1710, 0x1710, 0x173f, 0x1710,
+	0x1714, 0x1709, 0x1754, 0x1710, 0x1710, 0x1710, 0x181a, 0x1728,
+	0x171e, 0xa964, 0x918c, 0x00ff, 0x918e, 0x0048, 0x0904, 0x1754,
+	0x9085, 0x0001, 0x0804, 0x1810, 0xa87c, 0xd0bc, 0x0dc8, 0xa890,
+	0xa842, 0xa88c, 0xa83e, 0xa888, 0x0804, 0x1764, 0xa87c, 0xd0bc,
+	0x0d78, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa888, 0x0804, 0x17b3,
+	0xa87c, 0xd0bc, 0x0d28, 0xa890, 0xa842, 0xa88c, 0xa83e, 0xa804,
+	0x9045, 0x090c, 0x0dfa, 0xa164, 0xa91a, 0x91ec, 0x000f, 0x9d80,
+	0x1fc8, 0x2065, 0xa888, 0xd19c, 0x1904, 0x17b3, 0x0428, 0xa87c,
+	0xd0ac, 0x0970, 0xa804, 0x9045, 0x090c, 0x0dfa, 0xa164, 0xa91a,
+	0x91ec, 0x000f, 0x9d80, 0x1fc8, 0x2065, 0x9006, 0xa842, 0xa83e,
+	0xd19c, 0x1904, 0x17b3, 0x0080, 0xa87c, 0xd0ac, 0x0904, 0x1710,
+	0x9006, 0xa842, 0xa83e, 0x0804, 0x17b3, 0xa87c, 0xd0ac, 0x0904,
+	0x1710, 0x9006, 0xa842, 0xa83e, 0x2c05, 0x908a, 0x0036, 0x1a0c,
+	0x0dfa, 0x9082, 0x001b, 0x0002, 0x1787, 0x1787, 0x1789, 0x1787,
+	0x1787, 0x1787, 0x178f, 0x1787, 0x1787, 0x1787, 0x1795, 0x1787,
+	0x1787, 0x1787, 0x179b, 0x1787, 0x1787, 0x1787, 0x17a1, 0x1787,
+	0x1787, 0x1787, 0x17a7, 0x1787, 0x1787, 0x1787, 0x17ad, 0x080c,
+	0x0dfa, 0xa574, 0xa478, 0xa37c, 0xa280, 0x0804, 0x17f8, 0xa584,
+	0xa488, 0xa38c, 0xa290, 0x0804, 0x17f8, 0xa594, 0xa498, 0xa39c,
+	0xa2a0, 0x0804, 0x17f8, 0xa5a4, 0xa4a8, 0xa3ac, 0xa2b0, 0x0804,
+	0x17f8, 0xa5b4, 0xa4b8, 0xa3bc, 0xa2c0, 0x0804, 0x17f8, 0xa5c4,
+	0xa4c8, 0xa3cc, 0xa2d0, 0x0804, 0x17f8, 0xa5d4, 0xa4d8, 0xa3dc,
+	0xa2e0, 0x0804, 0x17f8, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dfa,
+	0x9082, 0x001b, 0x0002, 0x17d6, 0x17d4, 0x17d4, 0x17d4, 0x17d4,
+	0x17d4, 0x17dd, 0x17d4, 0x17d4, 0x17d4, 0x17d4, 0x17d4, 0x17e4,
+	0x17d4, 0x17d4, 0x17d4, 0x17d4, 0x17d4, 0x17eb, 0x17d4, 0x17d4,
+	0x17d4, 0x17d4, 0x17d4, 0x17f2, 0x080c, 0x0dfa, 0xa56c, 0xa470,
+	0xa774, 0xa678, 0xa37c, 0xa280, 0x00d8, 0xa584, 0xa488, 0xa78c,
+	0xa690, 0xa394, 0xa298, 0x00a0, 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8,
+	0xa3ac, 0xa2b0, 0x0068, 0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0xa3c4,
+	0xa2c8, 0x0030, 0xa5cc, 0xa4d0, 0xa7d4, 0xa6d8, 0xa3dc, 0xa2e0,
+	0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a, 0xa988, 0x8c60,
+	0x2c1d, 0xa8ac, 0xaab0, 0xa836, 0xaa3a, 0x8109, 0xa916, 0x1160,
+	0x3e60, 0x601c, 0xc085, 0x601e, 0xa87c, 0xc0dd, 0xa87e, 0x9006,
+	0x00ce, 0x001e, 0x012e, 0x0005, 0x2800, 0xa80e, 0xab0a, 0x2c00,
+	0xa812, 0x0c70, 0x0804, 0x1710, 0x0016, 0x2009, 0x00a0, 0x8109,
+	0xa001, 0xa001, 0xa001, 0x1dd8, 0x001e, 0x2ff0, 0x0126, 0x2091,
+	0x2200, 0x0016, 0x00c6, 0x3e60, 0x6014, 0x2048, 0x2940, 0xa80e,
+	0x2061, 0x1fc3, 0xa813, 0x1fc3, 0x2c05, 0xa80a, 0xa964, 0xa91a,
+	0xa87c, 0xd0ac, 0x090c, 0x0dfa, 0x9006, 0xa842, 0xa83e, 0x2c05,
+	0x908a, 0x0034, 0x1a0c, 0x0dfa, 0xadcc, 0xacd0, 0xafd4, 0xaed8,
+	0xabdc, 0xaae0, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a,
+	0xa8ac, 0xaab0, 0xa836, 0xaa3a, 0xa988, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0008, 0x1120, 0x8109, 0xa916, 0x0128, 0x0080, 0x918a,
+	0x0002, 0xa916, 0x1160, 0x3e60, 0x601c, 0xc085, 0x601e, 0xa87c,
+	0xc0dd, 0xa87e, 0x9006, 0x00ce, 0x001e, 0x012e, 0x0005, 0xa804,
+	0x9045, 0x090c, 0x0dfa, 0xa80e, 0xa064, 0xa81a, 0x9084, 0x000f,
+	0x9080, 0x1fc8, 0x2015, 0x82ff, 0x090c, 0x0dfa, 0xaa12, 0x2205,
+	0xa80a, 0x0c08, 0x903e, 0x2730, 0xa880, 0xd0fc, 0x1190, 0x2d00,
+	0x0002, 0x1977, 0x18d9, 0x18d9, 0x1977, 0x1977, 0x1971, 0x1977,
+	0x18d9, 0x1928, 0x1928, 0x1928, 0x1977, 0x1977, 0x1977, 0x196e,
+	0x1928, 0xc0fc, 0xa882, 0xab2c, 0xaa30, 0xad1c, 0xac20, 0xdd9c,
+	0x0904, 0x1979, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dfa, 0x9082,
+	0x001b, 0x0002, 0x18c5, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3,
+	0x18c9, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18cd, 0x18c3,
+	0x18c3, 0x18c3, 0x18c3, 0x18c3, 0x18d1, 0x18c3, 0x18c3, 0x18c3,
+	0x18c3, 0x18c3, 0x18d5, 0x080c, 0x0dfa, 0xa774, 0xa678, 0x0804,
+	0x1979, 0xa78c, 0xa690, 0x0804, 0x1979, 0xa7a4, 0xa6a8, 0x0804,
+	0x1979, 0xa7bc, 0xa6c0, 0x0804, 0x1979, 0xa7d4, 0xa6d8, 0x0804,
+	0x1979, 0x2c05, 0x908a, 0x0036, 0x1a0c, 0x0dfa, 0x9082, 0x001b,
+	0x0002, 0x18fc, 0x18fc, 0x18fe, 0x18fc, 0x18fc, 0x18fc, 0x1904,
+	0x18fc, 0x18fc, 0x18fc, 0x190a, 0x18fc, 0x18fc, 0x18fc, 0x1910,
+	0x18fc, 0x18fc, 0x18fc, 0x1916, 0x18fc, 0x18fc, 0x18fc, 0x191c,
+	0x18fc, 0x18fc, 0x18fc, 0x1922, 0x080c, 0x0dfa, 0xa574, 0xa478,
+	0xa37c, 0xa280, 0x0804, 0x1979, 0xa584, 0xa488, 0xa38c, 0xa290,
+	0x0804, 0x1979, 0xa594, 0xa498, 0xa39c, 0xa2a0, 0x0804, 0x1979,
+	0xa5a4, 0xa4a8, 0xa3ac, 0xa2b0, 0x0804, 0x1979, 0xa5b4, 0xa4b8,
+	0xa3bc, 0xa2c0, 0x0804, 0x1979, 0xa5c4, 0xa4c8, 0xa3cc, 0xa2d0,
+	0x0804, 0x1979, 0xa5d4, 0xa4d8, 0xa3dc, 0xa2e0, 0x0804, 0x1979,
+	0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dfa, 0x9082, 0x001b, 0x0002,
+	0x194b, 0x1949, 0x1949, 0x1949, 0x1949, 0x1949, 0x1952, 0x1949,
+	0x1949, 0x1949, 0x1949, 0x1949, 0x1959, 0x1949, 0x1949, 0x1949,
+	0x1949, 0x1949, 0x1960, 0x1949, 0x1949, 0x1949, 0x1949, 0x1949,
+	0x1967, 0x080c, 0x0dfa, 0xa56c, 0xa470, 0xa774, 0xa678, 0xa37c,
+	0xa280, 0x0438, 0xa584, 0xa488, 0xa78c, 0xa690, 0xa394, 0xa298,
+	0x0400, 0xa59c, 0xa4a0, 0xa7a4, 0xa6a8, 0xa3ac, 0xa2b0, 0x00c8,
+	0xa5b4, 0xa4b8, 0xa7bc, 0xa6c0, 0xa3c4, 0xa2c8, 0x0090, 0xa5cc,
+	0xa4d0, 0xa7d4, 0xa6d8, 0xa3dc, 0xa2e0, 0x0058, 0x9d86, 0x000e,
+	0x1130, 0x080c, 0x1f80, 0x1904, 0x1882, 0x900e, 0x0050, 0x080c,
+	0x0dfa, 0xab2e, 0xaa32, 0xad1e, 0xac22, 0xaf26, 0xae2a, 0x080c,
+	0x1f80, 0x0005, 0x6014, 0x2048, 0x6118, 0x810c, 0x810c, 0x810c,
+	0x81ff, 0x1118, 0xa887, 0x0001, 0x0008, 0xa986, 0x601b, 0x0002,
+	0xa874, 0x9084, 0x00ff, 0x9084, 0x0008, 0x0150, 0x00e9, 0x6000,
+	0x9086, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, 0xa15d, 0x0005,
+	0xa974, 0xd1dc, 0x1108, 0x0005, 0xa934, 0xa88c, 0x9106, 0x1158,
+	0xa938, 0xa890, 0x9106, 0x1138, 0x601c, 0xc084, 0x601e, 0x2009,
+	0x0048, 0x0804, 0xa15d, 0x0005, 0x0126, 0x00c6, 0x2091, 0x2200,
+	0x00ce, 0x7908, 0x918c, 0x0007, 0x9186, 0x0000, 0x05b0, 0x9186,
+	0x0003, 0x0598, 0x6020, 0x6023, 0x0000, 0x0006, 0x2031, 0x0008,
+	0x00c6, 0x781f, 0x0808, 0x7808, 0xd09c, 0x0120, 0x080c, 0x1370,
+	0x8631, 0x1db8, 0x00ce, 0x781f, 0x0800, 0x2031, 0x0168, 0x00c6,
+	0x7808, 0xd09c, 0x190c, 0x1370, 0x00ce, 0x2001, 0x0038, 0x080c,
+	0x1a87, 0x7930, 0x9186, 0x0040, 0x0160, 0x9186, 0x0042, 0x190c,
+	0x0dfa, 0x2001, 0x001e, 0x8001, 0x1df0, 0x8631, 0x1d40, 0x080c,
+	0x1a96, 0x000e, 0x6022, 0x012e, 0x0005, 0x080c, 0x1a83, 0x7827,
+	0x0015, 0x7828, 0x9c06, 0x1db8, 0x782b, 0x0000, 0x0ca0, 0x00f6,
+	0x2079, 0x0300, 0x7803, 0x0000, 0x78ab, 0x0004, 0x00fe, 0x080c,
+	0x7207, 0x1188, 0x2001, 0x0138, 0x2003, 0x0000, 0x2001, 0x0160,
+	0x2003, 0x0000, 0x2011, 0x012c, 0xa001, 0xa001, 0x8211, 0x1de0,
+	0x0059, 0x0804, 0x72d2, 0x0479, 0x0039, 0x2001, 0x0160, 0x2502,
+	0x2001, 0x0138, 0x2202, 0x0005, 0x00e6, 0x2071, 0x0200, 0x080c,
+	0x2bbc, 0x2009, 0x003c, 0x080c, 0x230a, 0x2001, 0x015d, 0x2003,
+	0x0000, 0x7000, 0x9084, 0x003c, 0x1de0, 0x080c, 0x81f0, 0x70a0,
+	0x70a2, 0x7098, 0x709a, 0x709c, 0x709e, 0x2001, 0x020d, 0x2003,
+	0x0020, 0x00f6, 0x2079, 0x0300, 0x080c, 0x1329, 0x7803, 0x0001,
+	0x00fe, 0x00ee, 0x0005, 0x2001, 0x0138, 0x2014, 0x2003, 0x0000,
+	0x2001, 0x0160, 0x202c, 0x2003, 0x0000, 0x080c, 0x7207, 0x1108,
+	0x0005, 0x2021, 0x0260, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168,
+	0x2001, 0x0109, 0x201c, 0x939c, 0x0048, 0x1160, 0x2001, 0x0111,
+	0x201c, 0x83ff, 0x1110, 0x8421, 0x1d70, 0x2001, 0x015d, 0x2003,
+	0x0000, 0x0005, 0x0046, 0x2021, 0x0019, 0x2003, 0x0048, 0xa001,
+	0xa001, 0x201c, 0x939c, 0x0048, 0x0120, 0x8421, 0x1db0, 0x004e,
+	0x0c60, 0x004e, 0x0c40, 0x601c, 0xc084, 0x601e, 0x0005, 0x2c08,
+	0x621c, 0x080c, 0x158b, 0x7930, 0x0005, 0x2c08, 0x621c, 0x080c,
+	0x1636, 0x7930, 0x0005, 0x8001, 0x1df0, 0x0005, 0x2031, 0x0064,
+	0x781c, 0x9084, 0x0007, 0x0170, 0x2001, 0x0038, 0x0c41, 0x9186,
+	0x0040, 0x0904, 0x1af4, 0x2001, 0x001e, 0x0c69, 0x8631, 0x1d80,
+	0x080c, 0x0dfa, 0x781f, 0x0202, 0x2001, 0x015d, 0x2003, 0x0000,
+	0x2001, 0x0dac, 0x0c01, 0x781c, 0xd084, 0x0110, 0x0861, 0x04e0,
+	0x2001, 0x0030, 0x0891, 0x9186, 0x0040, 0x0568, 0x781c, 0xd084,
+	0x1da8, 0x781f, 0x0101, 0x2001, 0x0014, 0x0869, 0x2001, 0x0037,
+	0x0821, 0x9186, 0x0040, 0x0140, 0x2001, 0x0030, 0x080c, 0x1a8d,
+	0x9186, 0x0040, 0x190c, 0x0dfa, 0x00d6, 0x2069, 0x0200, 0x692c,
+	0xd1f4, 0x1170, 0xd1c4, 0x0160, 0xd19c, 0x0130, 0x6800, 0x9085,
+	0x1800, 0x6802, 0x00de, 0x0080, 0x6908, 0x9184, 0x0007, 0x1db0,
+	0x00de, 0x781f, 0x0100, 0x791c, 0x9184, 0x0007, 0x090c, 0x0dfa,
+	0xa001, 0xa001, 0x781f, 0x0200, 0x0005, 0x0126, 0x2091, 0x2400,
+	0x2071, 0x1a3d, 0x2079, 0x0090, 0x012e, 0x0005, 0x9280, 0x0005,
+	0x2004, 0x2048, 0xa97c, 0xd1dc, 0x1904, 0x1b89, 0xa964, 0x9184,
+	0x0007, 0x0002, 0x1b12, 0x1b74, 0x1b29, 0x1b29, 0x1b29, 0x1b5c,
+	0x1b3c, 0x1b2b, 0x918c, 0x00ff, 0x9186, 0x0008, 0x1170, 0xa87c,
+	0xd0b4, 0x0904, 0x1da7, 0x9006, 0xa842, 0xa83e, 0xa988, 0x2900,
+	0xa85a, 0xa813, 0x1fc3, 0x0804, 0x1b85, 0x9186, 0x0048, 0x0904,
+	0x1b74, 0x080c, 0x0dfa, 0xa87c, 0xd0b4, 0x0904, 0x1da7, 0xa890,
+	0xa842, 0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac, 0xa846, 0xa8b0,
+	0xa84a, 0xa988, 0x0804, 0x1b7c, 0xa864, 0x9084, 0x00ff, 0x9086,
+	0x001e, 0x1d38, 0xa87c, 0xd0b4, 0x0904, 0x1da7, 0xa890, 0xa842,
+	0xa83a, 0xa88c, 0xa83e, 0xa836, 0xa8ac, 0xa846, 0xa8b0, 0xa84a,
+	0xa804, 0xa85a, 0x2040, 0xa064, 0x9084, 0x000f, 0x9080, 0x1fc8,
+	0x2005, 0xa812, 0xa988, 0x0448, 0x918c, 0x00ff, 0x9186, 0x0015,
+	0x1540, 0xa87c, 0xd0b4, 0x0904, 0x1da7, 0xa804, 0xa85a, 0x2040,
+	0xa064, 0x9084, 0x000f, 0x9080, 0x1fc8, 0x2005, 0xa812, 0xa988,
+	0x9006, 0xa842, 0xa83e, 0x0088, 0xa87c, 0xd0b4, 0x0904, 0x1da7,
+	0xa988, 0x9006, 0xa842, 0xa83e, 0x2900, 0xa85a, 0xa864, 0x9084,
+	0x000f, 0x9080, 0x1fc8, 0x2005, 0xa812, 0xa916, 0xa87c, 0xc0dd,
+	0xa87e, 0x0005, 0x00f6, 0x2079, 0x0090, 0x782c, 0xd0fc, 0x190c,
+	0x1dec, 0x00e6, 0x2071, 0x1a3d, 0x7000, 0x9005, 0x1904, 0x1bf2,
+	0x7206, 0x9280, 0x0005, 0x204c, 0x9280, 0x0004, 0x2004, 0x782b,
+	0x0004, 0x00f6, 0x2079, 0x0200, 0x7803, 0x0040, 0x00fe, 0x00b6,
+	0x2058, 0xb86c, 0x7836, 0xb890, 0x00be, 0x00f6, 0x2079, 0x0200,
+	0x7803, 0x0040, 0xa001, 0xa001, 0xa001, 0xa001, 0xa001, 0xa001,
+	0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, 0xa814, 0x2050,
+	0xa858, 0x2040, 0xa810, 0x2060, 0xa064, 0x90ec, 0x000f, 0xa944,
+	0x791a, 0x7116, 0xa848, 0x781e, 0x701a, 0x9006, 0x700e, 0x7012,
+	0x7004, 0xa940, 0xa838, 0x9106, 0x1500, 0xa93c, 0xa834, 0x9106,
+	0x11e0, 0x0006, 0x0016, 0xa938, 0xa834, 0x9105, 0x0118, 0x001e,
+	0x000e, 0x0098, 0x001e, 0x000e, 0x8aff, 0x01c8, 0x0126, 0x2091,
+	0x8000, 0x2009, 0x0306, 0x200b, 0x0808, 0x00d9, 0x0108, 0x00c9,
+	0x012e, 0x9006, 0x00ee, 0x00fe, 0x0005, 0x0036, 0x0046, 0xab38,
+	0xac34, 0x080c, 0x1fe8, 0x004e, 0x003e, 0x0d30, 0x0c98, 0x9085,
+	0x0001, 0x0c80, 0x2009, 0x0306, 0x200b, 0x4800, 0x7027, 0x0000,
+	0x0005, 0x0076, 0x0066, 0x0056, 0x0046, 0x0036, 0x0026, 0x8aff,
+	0x0904, 0x1da0, 0x700c, 0x7214, 0x923a, 0x7010, 0x7218, 0x9203,
+	0x0a04, 0x1d9f, 0x9705, 0x0904, 0x1d9f, 0x903e, 0x2730, 0xa880,
+	0xd0fc, 0x1190, 0x2d00, 0x0002, 0x1d34, 0x1c74, 0x1c74, 0x1d34,
+	0x1d34, 0x1d11, 0x1d34, 0x1c74, 0x1d18, 0x1cc3, 0x1cc3, 0x1d34,
+	0x1d34, 0x1d34, 0x1d0b, 0x1cc3, 0xc0fc, 0xa882, 0xab2c, 0xaa30,
+	0xad1c, 0xac20, 0xdd9c, 0x0904, 0x1d36, 0x2c05, 0x908a, 0x0034,
+	0x1a0c, 0x0dfa, 0x9082, 0x001b, 0x0002, 0x1c60, 0x1c5e, 0x1c5e,
+	0x1c5e, 0x1c5e, 0x1c5e, 0x1c64, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c5e,
+	0x1c5e, 0x1c68, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c6c,
+	0x1c5e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c5e, 0x1c70, 0x080c, 0x0dfa,
+	0xa774, 0xa678, 0x0804, 0x1d36, 0xa78c, 0xa690, 0x0804, 0x1d36,
+	0xa7a4, 0xa6a8, 0x0804, 0x1d36, 0xa7bc, 0xa6c0, 0x0804, 0x1d36,
+	0xa7d4, 0xa6d8, 0x0804, 0x1d36, 0x2c05, 0x908a, 0x0036, 0x1a0c,
+	0x0dfa, 0x9082, 0x001b, 0x0002, 0x1c97, 0x1c97, 0x1c99, 0x1c97,
+	0x1c97, 0x1c97, 0x1c9f, 0x1c97, 0x1c97, 0x1c97, 0x1ca5, 0x1c97,
+	0x1c97, 0x1c97, 0x1cab, 0x1c97, 0x1c97, 0x1c97, 0x1cb1, 0x1c97,
+	0x1c97, 0x1c97, 0x1cb7, 0x1c97, 0x1c97, 0x1c97, 0x1cbd, 0x080c,
+	0x0dfa, 0xa574, 0xa478, 0xa37c, 0xa280, 0x0804, 0x1d36, 0xa584,
+	0xa488, 0xa38c, 0xa290, 0x0804, 0x1d36, 0xa594, 0xa498, 0xa39c,
+	0xa2a0, 0x0804, 0x1d36, 0xa5a4, 0xa4a8, 0xa3ac, 0xa2b0, 0x0804,
+	0x1d36, 0xa5b4, 0xa4b8, 0xa3bc, 0xa2c0, 0x0804, 0x1d36, 0xa5c4,
+	0xa4c8, 0xa3cc, 0xa2d0, 0x0804, 0x1d36, 0xa5d4, 0xa4d8, 0xa3dc,
+	0xa2e0, 0x0804, 0x1d36, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dfa,
+	0x9082, 0x001b, 0x0002, 0x1ce6, 0x1ce4, 0x1ce4, 0x1ce4, 0x1ce4,
+	0x1ce4, 0x1cee, 0x1ce4, 0x1ce4, 0x1ce4, 0x1ce4, 0x1ce4, 0x1cf6,
+	0x1ce4, 0x1ce4, 0x1ce4, 0x1ce4, 0x1ce4, 0x1cfd, 0x1ce4, 0x1ce4,
+	0x1ce4, 0x1ce4, 0x1ce4, 0x1d04, 0x080c, 0x0dfa, 0xa56c, 0xa470,
+	0xa774, 0xa678, 0xa37c, 0xa280, 0x0804, 0x1d36, 0xa584, 0xa488,
+	0xa78c, 0xa690, 0xa394, 0xa298, 0x0804, 0x1d36, 0xa59c, 0xa4a0,
+	0xa7a4, 0xa6a8, 0xa3ac, 0xa2b0, 0x04c8, 0xa5b4, 0xa4b8, 0xa7bc,
+	0xa6c0, 0xa3c4, 0xa2c8, 0x0490, 0xa5cc, 0xa4d0, 0xa7d4, 0xa6d8,
+	0xa3dc, 0xa2e0, 0x0458, 0xa864, 0x9084, 0x00ff, 0x9086, 0x001e,
+	0x1518, 0x080c, 0x1f80, 0x1904, 0x1c0f, 0x900e, 0x0804, 0x1da0,
+	0xab64, 0x939c, 0x00ff, 0x9386, 0x0048, 0x1180, 0x00c6, 0x7004,
+	0x2060, 0x6004, 0x9086, 0x0043, 0x00ce, 0x0904, 0x1cc3, 0xab9c,
+	0x9016, 0xad8c, 0xac90, 0xaf94, 0xae98, 0x0040, 0x9386, 0x0008,
+	0x0904, 0x1cc3, 0x080c, 0x0dfa, 0x080c, 0x0dfa, 0x2009, 0x030f,
+	0x2104, 0xd0fc, 0x0530, 0x0066, 0x2009, 0x0306, 0x2104, 0x9084,
+	0x0030, 0x15c8, 0x2031, 0x1000, 0x200b, 0x4000, 0x2600, 0x9302,
+	0x928b, 0x0000, 0xa82e, 0xa932, 0x0278, 0x9105, 0x0168, 0x2011,
+	0x0000, 0x2618, 0x2600, 0x9500, 0xa81e, 0x9481, 0x0000, 0xa822,
+	0xa880, 0xc0fd, 0xa882, 0x0020, 0xa82f, 0x0000, 0xa833, 0x0000,
+	0x006e, 0x7b12, 0x7a16, 0x7d02, 0x7c06, 0x7f0a, 0x7e0e, 0x782b,
+	0x0001, 0x7000, 0x8000, 0x7002, 0xa83c, 0x9300, 0xa83e, 0xa840,
+	0x9201, 0xa842, 0x700c, 0x9300, 0x700e, 0x7010, 0x9201, 0x7012,
+	0x080c, 0x1f80, 0x0428, 0x2031, 0x0080, 0x9584, 0x007f, 0x0108,
+	0x9632, 0x7124, 0x7000, 0x9086, 0x0000, 0x1198, 0xc185, 0x7126,
+	0x2009, 0x0306, 0x2104, 0xd0b4, 0x1904, 0x1d46, 0x200b, 0x4040,
+	0x2009, 0x1a57, 0x2104, 0x8000, 0x0a04, 0x1d46, 0x200a, 0x0804,
+	0x1d46, 0xc18d, 0x7126, 0xd184, 0x1d58, 0x0804, 0x1d46, 0x9006,
+	0x002e, 0x003e, 0x004e, 0x005e, 0x006e, 0x007e, 0x0005, 0x080c,
+	0x0dfa, 0x0026, 0x2001, 0x0105, 0x2003, 0x0010, 0x782b, 0x0004,
+	0x7003, 0x0000, 0x7004, 0x0016, 0x080c, 0x1c02, 0x001e, 0x2060,
+	0x6014, 0x2048, 0x080c, 0xbe37, 0x0118, 0xa880, 0xc0bd, 0xa882,
+	0x6020, 0x9086, 0x0006, 0x1180, 0x2061, 0x0100, 0x62c8, 0x2001,
+	0x00fa, 0x8001, 0x1df0, 0x60c8, 0x9206, 0x1dc0, 0x60c4, 0xa89a,
+	0x60c8, 0xa896, 0x7004, 0x2060, 0x00c6, 0x080c, 0xba56, 0x00ce,
+	0x2001, 0x19ce, 0x2004, 0x9c06, 0x1160, 0x2009, 0x0040, 0x080c,
+	0x230a, 0x080c, 0x9b88, 0x2011, 0x0000, 0x080c, 0x9a19, 0x080c,
+	0x8ced, 0x002e, 0x0804, 0x1f30, 0x0126, 0x2091, 0x2400, 0xa858,
+	0x2040, 0x792c, 0x782b, 0x0002, 0x9184, 0x0700, 0x1904, 0x1da9,
+	0x7000, 0x0002, 0x1f30, 0x1dfe, 0x1e7e, 0x1f2e, 0x8001, 0x7002,
+	0x7027, 0x0000, 0xd19c, 0x1158, 0x8aff, 0x0904, 0x1e4b, 0x080c,
+	0x1c09, 0x0904, 0x1f30, 0x080c, 0x1c09, 0x0804, 0x1f30, 0x782b,
+	0x0004, 0xd194, 0x0148, 0xa880, 0xc0fc, 0xa882, 0x8aff, 0x1518,
+	0xa87c, 0xc0f5, 0xa87e, 0x00f8, 0x0026, 0x0036, 0xab3c, 0xaa40,
+	0x0016, 0x7910, 0xa82c, 0x9100, 0xa82e, 0x7914, 0xa830, 0x9101,
+	0xa832, 0x001e, 0x7810, 0x931a, 0x7814, 0x9213, 0x7800, 0xa81e,
+	0x7804, 0xa822, 0xab3e, 0xaa42, 0x003e, 0x002e, 0x080c, 0x1f9b,
+	0xa880, 0xc0fd, 0xa882, 0x2a00, 0xa816, 0x2800, 0xa85a, 0x2c00,
+	0xa812, 0x7003, 0x0000, 0x2009, 0x0306, 0x200b, 0x4800, 0x7027,
+	0x0000, 0x0804, 0x1f30, 0x00f6, 0x0026, 0x781c, 0x0006, 0x7818,
+	0x0006, 0x2079, 0x0100, 0x7a14, 0x9284, 0x1984, 0x9085, 0x0012,
+	0x7816, 0x0036, 0x2019, 0x1000, 0x8319, 0x090c, 0x0dfa, 0x7820,
+	0xd0bc, 0x1dd0, 0x003e, 0x79c8, 0x000e, 0x9102, 0x001e, 0x0006,
+	0x0016, 0x79c4, 0x000e, 0x9103, 0x78c6, 0x000e, 0x78ca, 0x9284,
+	0x1984, 0x9085, 0x0012, 0x7816, 0x002e, 0x00fe, 0x782b, 0x0008,
+	0x7003, 0x0000, 0x080c, 0x1c02, 0x0804, 0x1f30, 0x8001, 0x7002,
+	0x7024, 0x8004, 0x7026, 0xd194, 0x0170, 0x782c, 0xd0fc, 0x1904,
+	0x1df1, 0xd19c, 0x1904, 0x1f2c, 0x8aff, 0x0904, 0x1f30, 0x080c,
+	0x1c09, 0x0804, 0x1f30, 0x0026, 0x0036, 0xab3c, 0xaa40, 0x080c,
+	0x1f9b, 0xdd9c, 0x1904, 0x1eeb, 0x2c05, 0x908a, 0x0036, 0x1a0c,
+	0x0dfa, 0x9082, 0x001b, 0x0002, 0x1ebf, 0x1ebf, 0x1ec1, 0x1ebf,
+	0x1ebf, 0x1ebf, 0x1ec7, 0x1ebf, 0x1ebf, 0x1ebf, 0x1ecd, 0x1ebf,
+	0x1ebf, 0x1ebf, 0x1ed3, 0x1ebf, 0x1ebf, 0x1ebf, 0x1ed9, 0x1ebf,
+	0x1ebf, 0x1ebf, 0x1edf, 0x1ebf, 0x1ebf, 0x1ebf, 0x1ee5, 0x080c,
+	0x0dfa, 0xa07c, 0x931a, 0xa080, 0x9213, 0x0804, 0x1e20, 0xa08c,
+	0x931a, 0xa090, 0x9213, 0x0804, 0x1e20, 0xa09c, 0x931a, 0xa0a0,
+	0x9213, 0x0804, 0x1e20, 0xa0ac, 0x931a, 0xa0b0, 0x9213, 0x0804,
+	0x1e20, 0xa0bc, 0x931a, 0xa0c0, 0x9213, 0x0804, 0x1e20, 0xa0cc,
+	0x931a, 0xa0d0, 0x9213, 0x0804, 0x1e20, 0xa0dc, 0x931a, 0xa0e0,
+	0x9213, 0x0804, 0x1e20, 0x2c05, 0x908a, 0x0034, 0x1a0c, 0x0dfa,
+	0x9082, 0x001b, 0x0002, 0x1f0e, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f0c,
+	0x1f0c, 0x1f14, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f1a,
+	0x1f0c, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f0c, 0x1f20, 0x1f0c, 0x1f0c,
+	0x1f0c, 0x1f0c, 0x1f0c, 0x1f26, 0x080c, 0x0dfa, 0xa07c, 0x931a,
+	0xa080, 0x9213, 0x0804, 0x1e20, 0xa094, 0x931a, 0xa098, 0x9213,
+	0x0804, 0x1e20, 0xa0ac, 0x931a, 0xa0b0, 0x9213, 0x0804, 0x1e20,
+	0xa0c4, 0x931a, 0xa0c8, 0x9213, 0x0804, 0x1e20, 0xa0dc, 0x931a,
+	0xa0e0, 0x9213, 0x0804, 0x1e20, 0x0804, 0x1e1c, 0x080c, 0x0dfa,
+	0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a3d, 0x7000, 0x9086,
+	0x0000, 0x0904, 0x1f7b, 0x2079, 0x0090, 0x2009, 0x0207, 0x210c,
+	0xd194, 0x01b8, 0x2009, 0x020c, 0x210c, 0x9184, 0x0003, 0x0188,
+	0x080c, 0xdc34, 0x2001, 0x0133, 0x2004, 0x9005, 0x090c, 0x0dfa,
+	0x0016, 0x2009, 0x0040, 0x080c, 0x230a, 0x001e, 0x2001, 0x020c,
+	0x2102, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0x9106,
+	0x1120, 0x2009, 0x0040, 0x080c, 0x230a, 0x782c, 0xd0fc, 0x09a8,
+	0x080c, 0x1dec, 0x7000, 0x9086, 0x0000, 0x1978, 0x782b, 0x0004,
+	0x782c, 0xd0ac, 0x1de8, 0x2009, 0x0040, 0x080c, 0x230a, 0x782b,
+	0x0002, 0x7003, 0x0000, 0x080c, 0x1c02, 0x00ee, 0x00fe, 0x0005,
+	0xa880, 0xd0fc, 0x11a8, 0x8c60, 0x2c05, 0x9005, 0x0110, 0x8a51,
+	0x0005, 0xa004, 0x9005, 0x0168, 0xa85a, 0x2040, 0xa064, 0x9084,
+	0x000f, 0x9080, 0x1fc8, 0x2065, 0x8cff, 0x090c, 0x0dfa, 0x8a51,
+	0x0005, 0x2050, 0x0005, 0xa880, 0xd0fc, 0x11b8, 0x8a50, 0x8c61,
+	0x2c05, 0x9005, 0x1190, 0x2800, 0x9906, 0x0120, 0xa000, 0x9005,
+	0x1108, 0x2900, 0x2040, 0xa85a, 0xa064, 0x9084, 0x000f, 0x9080,
+	0x1fd8, 0x2065, 0x8cff, 0x090c, 0x0dfa, 0x0005, 0x0000, 0x001d,
+	0x0021, 0x0025, 0x0029, 0x002d, 0x0031, 0x0035, 0x0000, 0x001b,
+	0x0021, 0x0027, 0x002d, 0x0033, 0x0000, 0x0000, 0x0023, 0x0000,
+	0x0000, 0x1fbb, 0x1fb7, 0x0000, 0x0000, 0x1fc5, 0x0000, 0x1fbb,
+	0x1fc2, 0x1fc2, 0x1fbf, 0x0000, 0x0000, 0x0000, 0x1fc5, 0x1fc2,
+	0x0000, 0x1fbd, 0x1fbd, 0x0000, 0x0000, 0x1fc5, 0x0000, 0x1fbd,
+	0x1fc3, 0x1fc3, 0x1fc3, 0x0000, 0x0000, 0x0000, 0x1fc5, 0x1fc3,
+	0x00c6, 0x00d6, 0x0086, 0xab42, 0xac3e, 0xa888, 0x9055, 0x0904,
+	0x21c7, 0x2940, 0xa064, 0x90ec, 0x000f, 0x9084, 0x00ff, 0x9086,
+	0x0008, 0x1118, 0x2061, 0x1fc3, 0x00d0, 0x9de0, 0x1fc8, 0x9d86,
+	0x0007, 0x0130, 0x9d86, 0x000e, 0x0118, 0x9d86, 0x000f, 0x1120,
+	0xa08c, 0x9422, 0xa090, 0x931b, 0x2c05, 0x9065, 0x1140, 0x0310,
+	0x0804, 0x21c7, 0xa004, 0x9045, 0x0904, 0x21c7, 0x08d8, 0x2c05,
+	0x9005, 0x0904, 0x20af, 0xdd9c, 0x1904, 0x206b, 0x908a, 0x0036,
+	0x1a0c, 0x0dfa, 0x9082, 0x001b, 0x0002, 0x2040, 0x2040, 0x2042,
+	0x2040, 0x2040, 0x2040, 0x2048, 0x2040, 0x2040, 0x2040, 0x204e,
+	0x2040, 0x2040, 0x2040, 0x2054, 0x2040, 0x2040, 0x2040, 0x205a,
+	0x2040, 0x2040, 0x2040, 0x2060, 0x2040, 0x2040, 0x2040, 0x2066,
+	0x080c, 0x0dfa, 0xa07c, 0x9422, 0xa080, 0x931b, 0x0804, 0x20a5,
+	0xa08c, 0x9422, 0xa090, 0x931b, 0x0804, 0x20a5, 0xa09c, 0x9422,
+	0xa0a0, 0x931b, 0x0804, 0x20a5, 0xa0ac, 0x9422, 0xa0b0, 0x931b,
+	0x0804, 0x20a5, 0xa0bc, 0x9422, 0xa0c0, 0x931b, 0x0804, 0x20a5,
+	0xa0cc, 0x9422, 0xa0d0, 0x931b, 0x0804, 0x20a5, 0xa0dc, 0x9422,
+	0xa0e0, 0x931b, 0x04d0, 0x908a, 0x0034, 0x1a0c, 0x0dfa, 0x9082,
+	0x001b, 0x0002, 0x208d, 0x208b, 0x208b, 0x208b, 0x208b, 0x208b,
+	0x2092, 0x208b, 0x208b, 0x208b, 0x208b, 0x208b, 0x2097, 0x208b,
+	0x208b, 0x208b, 0x208b, 0x208b, 0x209c, 0x208b, 0x208b, 0x208b,
+	0x208b, 0x208b, 0x20a1, 0x080c, 0x0dfa, 0xa07c, 0x9422, 0xa080,
+	0x931b, 0x0098, 0xa094, 0x9422, 0xa098, 0x931b, 0x0070, 0xa0ac,
+	0x9422, 0xa0b0, 0x931b, 0x0048, 0xa0c4, 0x9422, 0xa0c8, 0x931b,
+	0x0020, 0xa0dc, 0x9422, 0xa0e0, 0x931b, 0x0630, 0x2300, 0x9405,
+	0x0160, 0x8a51, 0x0904, 0x21c7, 0x8c60, 0x0804, 0x2017, 0xa004,
+	0x9045, 0x0904, 0x21c7, 0x0804, 0x1ff2, 0x8a51, 0x0904, 0x21c7,
+	0x8c60, 0x2c05, 0x9005, 0x1158, 0xa004, 0x9045, 0x0904, 0x21c7,
+	0xa064, 0x90ec, 0x000f, 0x9de0, 0x1fc8, 0x2c05, 0x2060, 0xa880,
+	0xc0fc, 0xa882, 0x0804, 0x21bc, 0x2c05, 0x8422, 0x8420, 0x831a,
+	0x9399, 0x0000, 0xac2e, 0xab32, 0xdd9c, 0x1904, 0x2159, 0x9082,
+	0x001b, 0x0002, 0x20f5, 0x20f5, 0x20f7, 0x20f5, 0x20f5, 0x20f5,
+	0x2105, 0x20f5, 0x20f5, 0x20f5, 0x2113, 0x20f5, 0x20f5, 0x20f5,
+	0x2121, 0x20f5, 0x20f5, 0x20f5, 0x212f, 0x20f5, 0x20f5, 0x20f5,
+	0x213d, 0x20f5, 0x20f5, 0x20f5, 0x214b, 0x080c, 0x0dfa, 0xa17c,
+	0x2400, 0x9122, 0xa180, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa074,
+	0x9420, 0xa078, 0x9319, 0x0804, 0x21b7, 0xa18c, 0x2400, 0x9122,
+	0xa190, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa084, 0x9420, 0xa088,
+	0x9319, 0x0804, 0x21b7, 0xa19c, 0x2400, 0x9122, 0xa1a0, 0x2300,
+	0x911b, 0x0a0c, 0x0dfa, 0xa094, 0x9420, 0xa098, 0x9319, 0x0804,
+	0x21b7, 0xa1ac, 0x2400, 0x9122, 0xa1b0, 0x2300, 0x911b, 0x0a0c,
+	0x0dfa, 0xa0a4, 0x9420, 0xa0a8, 0x9319, 0x0804, 0x21b7, 0xa1bc,
+	0x2400, 0x9122, 0xa1c0, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa0b4,
+	0x9420, 0xa0b8, 0x9319, 0x0804, 0x21b7, 0xa1cc, 0x2400, 0x9122,
+	0xa1d0, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa0c4, 0x9420, 0xa0c8,
+	0x9319, 0x0804, 0x21b7, 0xa1dc, 0x2400, 0x9122, 0xa1e0, 0x2300,
+	0x911b, 0x0a0c, 0x0dfa, 0xa0d4, 0x9420, 0xa0d8, 0x9319, 0x0804,
+	0x21b7, 0x9082, 0x001b, 0x0002, 0x2177, 0x2175, 0x2175, 0x2175,
+	0x2175, 0x2175, 0x2184, 0x2175, 0x2175, 0x2175, 0x2175, 0x2175,
+	0x2191, 0x2175, 0x2175, 0x2175, 0x2175, 0x2175, 0x219e, 0x2175,
+	0x2175, 0x2175, 0x2175, 0x2175, 0x21ab, 0x080c, 0x0dfa, 0xa17c,
+	0x2400, 0x9122, 0xa180, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa06c,
+	0x9420, 0xa070, 0x9319, 0x0498, 0xa194, 0x2400, 0x9122, 0xa198,
+	0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa084, 0x9420, 0xa088, 0x9319,
+	0x0430, 0xa1ac, 0x2400, 0x9122, 0xa1b0, 0x2300, 0x911b, 0x0a0c,
+	0x0dfa, 0xa09c, 0x9420, 0xa0a0, 0x9319, 0x00c8, 0xa1c4, 0x2400,
+	0x9122, 0xa1c8, 0x2300, 0x911b, 0x0a0c, 0x0dfa, 0xa0b4, 0x9420,
+	0xa0b8, 0x9319, 0x0060, 0xa1dc, 0x2400, 0x9122, 0xa1e0, 0x2300,
+	0x911b, 0x0a0c, 0x0dfa, 0xa0cc, 0x9420, 0xa0d0, 0x9319, 0xac1e,
+	0xab22, 0xa880, 0xc0fd, 0xa882, 0x2800, 0xa85a, 0x2c00, 0xa812,
+	0x2a00, 0xa816, 0x000e, 0x000e, 0x000e, 0x9006, 0x0028, 0x008e,
+	0x00de, 0x00ce, 0x9085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004,
+	0xd0bc, 0x190c, 0x0df3, 0x9084, 0x0007, 0x0002, 0x21e8, 0x1dec,
+	0x21e8, 0x21de, 0x21e1, 0x21e4, 0x21e1, 0x21e4, 0x080c, 0x1dec,
+	0x0005, 0x080c, 0x11e8, 0x0005, 0x080c, 0x1dec, 0x080c, 0x11e8,
+	0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200, 0x2071, 0x0260,
+	0x2069, 0x1800, 0x7817, 0x0000, 0x789b, 0x0814, 0x78a3, 0x0406,
+	0x789f, 0x0410, 0x2009, 0x013b, 0x200b, 0x0400, 0x781b, 0x0002,
+	0x783b, 0x001f, 0x7837, 0x0020, 0x7803, 0x1600, 0x012e, 0x0005,
+	0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, 0x2307, 0x7900, 0xd1dc,
+	0x1118, 0x9084, 0x0006, 0x001a, 0x9084, 0x000e, 0x0002, 0x222f,
+	0x2227, 0x7bb4, 0x2227, 0x2229, 0x2229, 0x2229, 0x2229, 0x7b9a,
+	0x2227, 0x222b, 0x2227, 0x2229, 0x2227, 0x2229, 0x2227, 0x080c,
+	0x0dfa, 0x0031, 0x0020, 0x080c, 0x7b9a, 0x080c, 0x7bb4, 0x0005,
+	0x0006, 0x0016, 0x0026, 0x080c, 0xdc34, 0x7930, 0x9184, 0x0003,
+	0x01c0, 0x2001, 0x19ce, 0x2004, 0x9005, 0x0170, 0x2001, 0x0133,
+	0x2004, 0x9005, 0x090c, 0x0dfa, 0x00c6, 0x2001, 0x19ce, 0x2064,
+	0x080c, 0xba56, 0x00ce, 0x00f8, 0x2009, 0x0040, 0x080c, 0x230a,
+	0x00d0, 0x9184, 0x0014, 0x01a0, 0x6a00, 0x9286, 0x0003, 0x0160,
+	0x080c, 0x7207, 0x1138, 0x080c, 0x7504, 0x080c, 0x5f2b, 0x080c,
+	0x7127, 0x0010, 0x080c, 0x5dea, 0x080c, 0x7c63, 0x0041, 0x0018,
+	0x9184, 0x9540, 0x1dc8, 0x002e, 0x001e, 0x000e, 0x0005, 0x00e6,
+	0x0036, 0x0046, 0x0056, 0x2071, 0x1a3a, 0x080c, 0x19ff, 0x005e,
+	0x004e, 0x003e, 0x00ee, 0x0005, 0x0126, 0x2091, 0x2e00, 0x2071,
+	0x1800, 0x7128, 0x2001, 0x1947, 0x2102, 0x2001, 0x194f, 0x2102,
+	0x2001, 0x013b, 0x2102, 0x2079, 0x0200, 0x2001, 0x0201, 0x789e,
+	0x78a3, 0x0200, 0x9198, 0x0007, 0x831c, 0x831c, 0x831c, 0x9398,
+	0x0005, 0x2320, 0x9182, 0x0204, 0x1230, 0x2011, 0x0008, 0x8423,
+	0x8423, 0x8423, 0x0488, 0x9182, 0x024c, 0x1240, 0x2011, 0x0007,
+	0x8403, 0x8003, 0x9400, 0x9400, 0x9420, 0x0430, 0x9182, 0x02bc,
+	0x1238, 0x2011, 0x0006, 0x8403, 0x8003, 0x9400, 0x9420, 0x00e0,
+	0x9182, 0x034c, 0x1230, 0x2011, 0x0005, 0x8403, 0x8003, 0x9420,
+	0x0098, 0x9182, 0x042c, 0x1228, 0x2011, 0x0004, 0x8423, 0x8423,
+	0x0058, 0x9182, 0x059c, 0x1228, 0x2011, 0x0003, 0x8403, 0x9420,
+	0x0018, 0x2011, 0x0002, 0x8423, 0x9482, 0x0228, 0x8002, 0x8020,
+	0x8301, 0x9402, 0x0110, 0x0208, 0x8321, 0x8217, 0x8203, 0x9405,
+	0x789a, 0x012e, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6814,
+	0x9084, 0xffc0, 0x910d, 0x6916, 0x00de, 0x000e, 0x0005, 0x00d6,
+	0x2069, 0x0200, 0x9005, 0x6810, 0x0110, 0xc0a5, 0x0008, 0xc0a4,
+	0x6812, 0x00de, 0x0005, 0x0006, 0x00d6, 0x2069, 0x0200, 0x6810,
+	0x9084, 0xfff8, 0x910d, 0x6912, 0x00de, 0x000e, 0x0005, 0x7938,
+	0x080c, 0x0df3, 0x00f6, 0x2079, 0x0200, 0x7902, 0xa001, 0xa001,
+	0xa001, 0xa001, 0xa001, 0xa001, 0x7902, 0xa001, 0xa001, 0xa001,
+	0xa001, 0xa001, 0xa001, 0x00fe, 0x0005, 0x0126, 0x2091, 0x2800,
+	0x2061, 0x0100, 0x2071, 0x1800, 0x2009, 0x0000, 0x080c, 0x2bb6,
+	0x080c, 0x2a89, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0558,
+	0x6054, 0x8004, 0x8004, 0x8004, 0x8004, 0x9084, 0x000c, 0x6150,
+	0x918c, 0xfff3, 0x9105, 0x6052, 0x6050, 0x9084, 0xb17f, 0x9085,
+	0x2000, 0x6052, 0x2009, 0x1975, 0x2011, 0x1976, 0x6358, 0x939c,
+	0x38f0, 0x2320, 0x080c, 0x2af6, 0x1238, 0x939d, 0x4003, 0x94a5,
+	0x8603, 0x230a, 0x2412, 0x0030, 0x939d, 0x0203, 0x94a5, 0x8603,
+	0x230a, 0x2412, 0x0050, 0x2001, 0x1975, 0x2003, 0x0700, 0x2001,
+	0x1976, 0x2003, 0x0700, 0x080c, 0x2cc2, 0x9006, 0x080c, 0x2ab8,
+	0x9006, 0x080c, 0x2a9b, 0x20a9, 0x0012, 0x1d04, 0x236d, 0x2091,
+	0x6000, 0x1f04, 0x236d, 0x602f, 0x0100, 0x602f, 0x0000, 0x6050,
+	0x9085, 0x0400, 0x9084, 0xdfff, 0x6052, 0x6024, 0x6026, 0x080c,
+	0x27a7, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x27b7, 0x60e7,
+	0x0000, 0x61ea, 0x60e3, 0x0002, 0x604b, 0xf7f7, 0x6043, 0x0000,
+	0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x149f, 0x60bb, 0x0000,
+	0x20a9, 0x0018, 0x60bf, 0x0000, 0x1f04, 0x239a, 0x60bb, 0x0000,
+	0x60bf, 0x0108, 0x60bf, 0x0012, 0x60bf, 0x0320, 0x60bf, 0x0018,
+	0x601b, 0x00f0, 0x601f, 0x001e, 0x600f, 0x006b, 0x602b, 0x402f,
+	0x012e, 0x0005, 0x00f6, 0x2079, 0x0140, 0x78c3, 0x0080, 0x78c3,
+	0x0083, 0x78c3, 0x0000, 0x00fe, 0x0005, 0x2001, 0x1834, 0x2003,
+	0x0000, 0x2001, 0x1833, 0x2003, 0x0001, 0x0005, 0x0126, 0x2091,
+	0x2800, 0x0006, 0x0016, 0x0026, 0x6124, 0x9184, 0x5e2c, 0x1118,
+	0x9184, 0x0007, 0x002a, 0x9195, 0x0004, 0x9284, 0x0007, 0x0002,
+	0x23fa, 0x23e0, 0x23e3, 0x23e6, 0x23eb, 0x23ed, 0x23f1, 0x23f5,
+	0x080c, 0x8563, 0x00b8, 0x080c, 0x8632, 0x00a0, 0x080c, 0x8632,
+	0x080c, 0x8563, 0x0078, 0x0099, 0x0068, 0x080c, 0x8563, 0x0079,
+	0x0048, 0x080c, 0x8632, 0x0059, 0x0028, 0x080c, 0x8632, 0x080c,
+	0x8563, 0x0029, 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x00a6,
+	0x6124, 0x6028, 0xd09c, 0x0118, 0xd19c, 0x1904, 0x2648, 0xd1f4,
+	0x190c, 0x0df3, 0x080c, 0x7207, 0x0904, 0x2455, 0x080c, 0xc539,
+	0x1120, 0x7000, 0x9086, 0x0003, 0x0570, 0x6024, 0x9084, 0x1800,
+	0x0550, 0x080c, 0x722a, 0x0118, 0x080c, 0x7218, 0x1520, 0x6027,
+	0x0020, 0x6043, 0x0000, 0x080c, 0xc539, 0x0168, 0x080c, 0x722a,
+	0x1150, 0x2001, 0x197f, 0x2003, 0x0001, 0x6027, 0x1800, 0x080c,
+	0x7076, 0x0804, 0x264b, 0x70a0, 0x9005, 0x1150, 0x70a3, 0x0001,
+	0x00d6, 0x2069, 0x0140, 0x080c, 0x725e, 0x00de, 0x1904, 0x264b,
+	0x080c, 0x750e, 0x0428, 0x080c, 0x722a, 0x1590, 0x6024, 0x9084,
+	0x1800, 0x1108, 0x0468, 0x080c, 0x750e, 0x080c, 0x7504, 0x080c,
+	0x5f2b, 0x080c, 0x7127, 0x0804, 0x2648, 0xd1ac, 0x1508, 0x6024,
+	0xd0dc, 0x1170, 0xd0e4, 0x1178, 0xd0d4, 0x1190, 0xd0cc, 0x0130,
+	0x7094, 0x9086, 0x0028, 0x1110, 0x080c, 0x73f3, 0x0804, 0x2648,
+	0x080c, 0x7509, 0x0048, 0x2001, 0x1955, 0x2003, 0x0002, 0x0020,
+	0x080c, 0x7359, 0x0804, 0x2648, 0x080c, 0x748d, 0x0804, 0x2648,
+	0xd1ac, 0x0904, 0x2569, 0x080c, 0x7207, 0x11c0, 0x6027, 0x0020,
+	0x0006, 0x0026, 0x0036, 0x080c, 0x7221, 0x1158, 0x080c, 0x7504,
+	0x080c, 0x5f2b, 0x080c, 0x7127, 0x003e, 0x002e, 0x000e, 0x00ae,
+	0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x71df, 0x0016, 0x0046,
+	0x00c6, 0x644c, 0x9486, 0xf0f0, 0x1138, 0x2061, 0x0100, 0x644a,
+	0x6043, 0x0090, 0x6043, 0x0010, 0x74d6, 0x948c, 0xff00, 0x7038,
+	0xd084, 0x0178, 0x9186, 0xf800, 0x1160, 0x7044, 0xd084, 0x1148,
+	0xc085, 0x7046, 0x0036, 0x2418, 0x2011, 0x8016, 0x080c, 0x4b1f,
+	0x003e, 0x080c, 0xc532, 0x1904, 0x2546, 0x9196, 0xff00, 0x05a8,
+	0x705c, 0x9084, 0x00ff, 0x810f, 0x81ff, 0x0110, 0x9116, 0x0568,
+	0x7130, 0xd184, 0x1550, 0x080c, 0x32e4, 0x0128, 0xc18d, 0x7132,
+	0x080c, 0x67bb, 0x1510, 0x6240, 0x9294, 0x0010, 0x0130, 0x6248,
+	0x9294, 0xff00, 0x9296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904,
+	0x2546, 0x7038, 0xd08c, 0x1140, 0x2001, 0x180c, 0x200c, 0xd1ac,
+	0x1904, 0x2546, 0xc1ad, 0x2102, 0x0036, 0x73d4, 0x2011, 0x8013,
+	0x080c, 0x4b1f, 0x003e, 0x0804, 0x2546, 0x7038, 0xd08c, 0x1140,
+	0x2001, 0x180c, 0x200c, 0xd1ac, 0x1904, 0x2546, 0xc1ad, 0x2102,
+	0x0036, 0x73d4, 0x2011, 0x8013, 0x080c, 0x4b1f, 0x003e, 0x7130,
+	0xc185, 0x7132, 0x2011, 0x185c, 0x220c, 0x00f0, 0x0016, 0x2009,
+	0x0001, 0x2011, 0x0100, 0x080c, 0x84d1, 0x2019, 0x000e, 0x00c6,
+	0x2061, 0x0000, 0x080c, 0xd801, 0x00ce, 0x9484, 0x00ff, 0x9080,
+	0x32e9, 0x200d, 0x918c, 0xff00, 0x810f, 0x2120, 0x9006, 0x2009,
+	0x000e, 0x080c, 0xd885, 0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009,
+	0x0002, 0x2019, 0x0004, 0x080c, 0x3156, 0x001e, 0x0078, 0x0156,
+	0x00b6, 0x20a9, 0x007f, 0x900e, 0x080c, 0x649f, 0x1110, 0x080c,
+	0x5f45, 0x8108, 0x1f04, 0x253c, 0x00be, 0x015e, 0x00ce, 0x004e,
+	0x080c, 0xa069, 0x60e3, 0x0000, 0x001e, 0x2001, 0x1800, 0x2014,
+	0x9296, 0x0004, 0x1170, 0xd19c, 0x11a0, 0x2011, 0x180c, 0x2214,
+	0xd29c, 0x1120, 0x6204, 0x9295, 0x0002, 0x6206, 0x6228, 0xc29d,
+	0x622a, 0x2003, 0x0001, 0x2001, 0x1825, 0x2003, 0x0000, 0x6027,
+	0x0020, 0xd194, 0x0904, 0x2648, 0x0016, 0x6220, 0xd2b4, 0x0904,
+	0x25f1, 0x080c, 0x835a, 0x080c, 0x9656, 0x6027, 0x0004, 0x00f6,
+	0x2019, 0x19c8, 0x2304, 0x907d, 0x0904, 0x25c0, 0x7804, 0x9086,
+	0x0032, 0x15f0, 0x00d6, 0x00c6, 0x00e6, 0x0096, 0x2069, 0x0140,
+	0x782c, 0x685e, 0x7808, 0x685a, 0x6043, 0x0002, 0x2001, 0x0003,
+	0x8001, 0x1df0, 0x6043, 0x0000, 0x2001, 0x003c, 0x8001, 0x1df0,
+	0x080c, 0x2c98, 0x2001, 0x001e, 0x8001, 0x0240, 0x20a9, 0x0009,
+	0x080c, 0x2b91, 0x6904, 0xd1dc, 0x1140, 0x0cb0, 0x2001, 0x0100,
+	0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88, 0x080c, 0x8b04, 0x080c,
+	0x8c10, 0x7814, 0x2048, 0xa867, 0x0103, 0x2f60, 0x080c, 0xa0e3,
+	0x009e, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e, 0x00ae, 0x0005,
+	0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0x9084, 0x4000, 0x0110,
+	0x080c, 0x2c98, 0x00de, 0x00c6, 0x2061, 0x19bf, 0x6028, 0x080c,
+	0xc539, 0x0120, 0x909a, 0x0003, 0x1258, 0x0018, 0x909a, 0x00c8,
+	0x1238, 0x8000, 0x602a, 0x00ce, 0x080c, 0x9632, 0x0804, 0x2647,
+	0x2061, 0x0100, 0x62c0, 0x080c, 0x9eef, 0x2019, 0x19c8, 0x2304,
+	0x9065, 0x0120, 0x2009, 0x0027, 0x080c, 0xa15d, 0x00ce, 0x0804,
+	0x2647, 0xd2bc, 0x0904, 0x2634, 0x080c, 0x8367, 0x6014, 0x9084,
+	0x1984, 0x9085, 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069,
+	0x0140, 0x6804, 0x9084, 0x4000, 0x0110, 0x080c, 0x2c98, 0x00de,
+	0x00c6, 0x2061, 0x19bf, 0x6044, 0x080c, 0xc539, 0x0120, 0x909a,
+	0x0003, 0x1628, 0x0018, 0x909a, 0x00c8, 0x1608, 0x8000, 0x6046,
+	0x603c, 0x00ce, 0x9005, 0x0558, 0x2009, 0x07d0, 0x080c, 0x835f,
+	0x9080, 0x0008, 0x2004, 0x9086, 0x0006, 0x1138, 0x6114, 0x918c,
+	0x1984, 0x918d, 0x0012, 0x6116, 0x00d0, 0x6114, 0x918c, 0x1984,
+	0x918d, 0x0016, 0x6116, 0x0098, 0x6027, 0x0004, 0x0080, 0x0036,
+	0x2019, 0x0001, 0x080c, 0x999d, 0x003e, 0x2019, 0x19ce, 0x2304,
+	0x9065, 0x0120, 0x2009, 0x004f, 0x080c, 0xa15d, 0x00ce, 0x001e,
+	0xd19c, 0x0904, 0x2712, 0x7038, 0xd0ac, 0x1904, 0x26e7, 0x0016,
+	0x0156, 0x6027, 0x0008, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x0904, 0x26c4, 0x6050, 0x9085, 0x0040, 0x6052, 0x6050, 0x9084,
+	0xfbcf, 0x6052, 0x080c, 0x2bb0, 0x9085, 0x2000, 0x6052, 0x20a9,
+	0x0012, 0x1d04, 0x2669, 0x080c, 0x838e, 0x1f04, 0x2669, 0x6050,
+	0x9085, 0x0400, 0x9084, 0xdfbf, 0x6052, 0x20a9, 0x0028, 0xa001,
+	0x1f04, 0x2677, 0x6150, 0x9185, 0x1400, 0x6052, 0x20a9, 0x0366,
+	0x1d04, 0x2680, 0x080c, 0x838e, 0x6020, 0xd09c, 0x1138, 0x015e,
+	0x6152, 0x001e, 0x6027, 0x0008, 0x0804, 0x2712, 0x080c, 0x2b78,
+	0x1f04, 0x2680, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0016,
+	0x6028, 0xc09c, 0x602a, 0x080c, 0xa069, 0x60e3, 0x0000, 0x080c,
+	0xdc13, 0x080c, 0xdc2e, 0x080c, 0x55df, 0xd0fc, 0x1138, 0x080c,
+	0xc532, 0x1120, 0x9085, 0x0001, 0x080c, 0x724e, 0x9006, 0x080c,
+	0x2c88, 0x2009, 0x0002, 0x080c, 0x2bb6, 0x00e6, 0x2071, 0x1800,
+	0x7003, 0x0004, 0x080c, 0x0ec6, 0x00ee, 0x6027, 0x0008, 0x080c,
+	0x0b8f, 0x001e, 0x0804, 0x2712, 0x080c, 0x2cc2, 0x080c, 0x2cf5,
+	0x6050, 0xc0e5, 0x6052, 0x20a9, 0x0367, 0x1f04, 0x26e5, 0x1d04,
+	0x26cf, 0x080c, 0x838e, 0x6020, 0xd09c, 0x1db8, 0x00f6, 0x2079,
+	0x0100, 0x080c, 0x2b06, 0x00fe, 0x1d80, 0x6050, 0xc0e4, 0x6052,
+	0x6027, 0x0008, 0x015e, 0x001e, 0x0468, 0x015e, 0x001e, 0x0016,
+	0x6028, 0xc09c, 0x602a, 0x080c, 0xa069, 0x60e3, 0x0000, 0x080c,
+	0xdc13, 0x080c, 0xdc2e, 0x080c, 0x55df, 0xd0fc, 0x1138, 0x080c,
+	0xc532, 0x1120, 0x9085, 0x0001, 0x080c, 0x724e, 0x9006, 0x080c,
+	0x2c88, 0x2009, 0x0002, 0x080c, 0x2bb6, 0x00e6, 0x2071, 0x1800,
+	0x7003, 0x0004, 0x080c, 0x0ec6, 0x00ee, 0x6027, 0x0008, 0x080c,
+	0x0b8f, 0x001e, 0x918c, 0xffd0, 0x6126, 0x00ae, 0x0005, 0x0006,
+	0x0016, 0x0026, 0x0036, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000,
+	0x2071, 0x1800, 0x71cc, 0x70ce, 0x9116, 0x0904, 0x2766, 0x81ff,
+	0x01a0, 0x2009, 0x0000, 0x080c, 0x2bb6, 0x2011, 0x8011, 0x2019,
+	0x010e, 0x231c, 0x939e, 0x0007, 0x1118, 0x2019, 0x0001, 0x0010,
+	0x2019, 0x0000, 0x080c, 0x4b1f, 0x0448, 0x2001, 0x1980, 0x200c,
+	0x81ff, 0x1140, 0x2001, 0x0109, 0x2004, 0xd0b4, 0x0118, 0x2019,
+	0x0003, 0x0008, 0x2118, 0x2011, 0x8012, 0x080c, 0x4b1f, 0x080c,
+	0x0ec6, 0x080c, 0x55df, 0xd0fc, 0x1188, 0x080c, 0xc532, 0x1170,
+	0x00c6, 0x080c, 0x2802, 0x080c, 0x9904, 0x2061, 0x0100, 0x2019,
+	0x0028, 0x2009, 0x0002, 0x080c, 0x3156, 0x00ce, 0x012e, 0x00fe,
+	0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x2028, 0x918c,
+	0x00ff, 0x2130, 0x9094, 0xff00, 0x11f0, 0x2011, 0x1836, 0x2214,
+	0xd2ac, 0x11c8, 0x81ff, 0x01e8, 0x2011, 0x181e, 0x2204, 0x9106,
+	0x1190, 0x2011, 0x181f, 0x2214, 0x9294, 0xff00, 0x9584, 0xff00,
+	0x9206, 0x1148, 0x2011, 0x181f, 0x2214, 0x9294, 0x00ff, 0x9584,
+	0x00ff, 0x9206, 0x1120, 0x2500, 0x080c, 0x7ec0, 0x0048, 0x9584,
+	0x00ff, 0x9080, 0x32e9, 0x200d, 0x918c, 0xff00, 0x810f, 0x9006,
+	0x0005, 0x9080, 0x32e9, 0x200d, 0x918c, 0x00ff, 0x0005, 0x00d6,
+	0x2069, 0x0140, 0x2001, 0x1817, 0x2003, 0x00ef, 0x20a9, 0x0010,
+	0x9006, 0x6852, 0x6856, 0x1f04, 0x27b2, 0x00de, 0x0005, 0x0006,
+	0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0x1817, 0x2102, 0x8114,
+	0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000, 0x9006,
+	0x82ff, 0x1128, 0x9184, 0x000f, 0x9080, 0xe568, 0x2005, 0x6856,
+	0x8211, 0x1f04, 0x27c7, 0x002e, 0x00de, 0x000e, 0x0005, 0x00c6,
+	0x2061, 0x1800, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c, 0x6032,
+	0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006, 0x2069,
+	0x0140, 0x6980, 0x9116, 0x0180, 0x9112, 0x1230, 0x8212, 0x8210,
+	0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404, 0x680e,
+	0x1f04, 0x27f7, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e, 0x00de,
+	0x015e, 0x0005, 0x080c, 0x55db, 0xd0c4, 0x0150, 0xd0a4, 0x0140,
+	0x9006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c, 0xd885, 0x004e,
+	0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140, 0x78c4, 0xd0dc,
+	0x0904, 0x286e, 0x080c, 0x2af6, 0x0660, 0x9084, 0x0700, 0x908e,
+	0x0600, 0x1120, 0x2011, 0x4000, 0x900e, 0x0458, 0x908e, 0x0500,
+	0x1120, 0x2011, 0x8000, 0x900e, 0x0420, 0x908e, 0x0400, 0x1120,
+	0x9016, 0x2009, 0x0001, 0x00e8, 0x908e, 0x0300, 0x1120, 0x9016,
+	0x2009, 0x0002, 0x00b0, 0x908e, 0x0200, 0x1120, 0x9016, 0x2009,
+	0x0004, 0x0078, 0x908e, 0x0100, 0x1548, 0x9016, 0x2009, 0x0008,
+	0x0040, 0x9084, 0x0700, 0x908e, 0x0300, 0x1500, 0x2011, 0x0030,
+	0x0058, 0x2300, 0x9080, 0x0020, 0x2018, 0x080c, 0x84ff, 0x928c,
+	0xff00, 0x0110, 0x2011, 0x00ff, 0x2200, 0x8007, 0x9085, 0x004c,
+	0x78c2, 0x2009, 0x0138, 0x220a, 0x080c, 0x7207, 0x1118, 0x2009,
+	0x1945, 0x220a, 0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000,
+	0x0cc8, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001,
+	0x0170, 0x200c, 0x8000, 0x2014, 0x9184, 0x0003, 0x0110, 0x080c,
+	0x0df3, 0x002e, 0x001e, 0x000e, 0x012e, 0x0005, 0x2001, 0x0171,
+	0x2004, 0xd0dc, 0x0168, 0x2001, 0x0170, 0x200c, 0x918c, 0x00ff,
+	0x918e, 0x004c, 0x1128, 0x200c, 0x918c, 0xff00, 0x810f, 0x0005,
+	0x900e, 0x2001, 0x0227, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004,
+	0x9108, 0x2001, 0x0226, 0x2004, 0x8007, 0x9084, 0x00ff, 0x8004,
+	0x9108, 0x0005, 0x0018, 0x000c, 0x0018, 0x0020, 0x1000, 0x0800,
+	0x1000, 0x1800, 0x0156, 0x0006, 0x0016, 0x0026, 0x00e6, 0x2001,
+	0x1968, 0x2004, 0x908a, 0x0007, 0x1a0c, 0x0dfa, 0x0033, 0x00ee,
+	0x002e, 0x001e, 0x000e, 0x015e, 0x0005, 0x28cc, 0x28ea, 0x290e,
+	0x2910, 0x2939, 0x293b, 0x293d, 0x2001, 0x0001, 0x080c, 0x2717,
+	0x080c, 0x2b6a, 0x2001, 0x196a, 0x2003, 0x0000, 0x7828, 0x9084,
+	0xe1d7, 0x782a, 0x9006, 0x20a9, 0x0009, 0x080c, 0x2b12, 0x2001,
+	0x1968, 0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x293e, 0x080c,
+	0x836c, 0x0005, 0x2009, 0x196d, 0x200b, 0x0000, 0x2001, 0x1972,
+	0x2003, 0x0036, 0x2001, 0x1971, 0x2003, 0x002a, 0x2001, 0x196a,
+	0x2003, 0x0001, 0x9006, 0x080c, 0x2a9b, 0x2001, 0xffff, 0x20a9,
+	0x0009, 0x080c, 0x2b12, 0x2001, 0x1968, 0x2003, 0x0006, 0x2009,
+	0x001e, 0x2011, 0x293e, 0x080c, 0x836c, 0x0005, 0x080c, 0x0dfa,
+	0x2001, 0x1972, 0x2003, 0x0036, 0x2001, 0x196a, 0x2003, 0x0003,
+	0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110, 0x9006, 0x0010,
+	0x2001, 0x0001, 0x080c, 0x2a9b, 0x2001, 0x196e, 0x2003, 0x0000,
+	0x2001, 0xffff, 0x20a9, 0x0009, 0x080c, 0x2b12, 0x2001, 0x1968,
+	0x2003, 0x0006, 0x2009, 0x001e, 0x2011, 0x293e, 0x080c, 0x836c,
+	0x0005, 0x080c, 0x0dfa, 0x080c, 0x0dfa, 0x0005, 0x0006, 0x0016,
+	0x0026, 0x00e6, 0x00f6, 0x0156, 0x0126, 0x2091, 0x8000, 0x2079,
+	0x0100, 0x2001, 0x196a, 0x2004, 0x908a, 0x0007, 0x1a0c, 0x0dfa,
+	0x0043, 0x012e, 0x015e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e,
+	0x0005, 0x2960, 0x2980, 0x29c0, 0x29f0, 0x2a14, 0x2a24, 0x2a26,
+	0x080c, 0x2b06, 0x11b0, 0x7850, 0x9084, 0xefff, 0x7852, 0x2009,
+	0x1970, 0x2104, 0x7a38, 0x9294, 0x0005, 0x9296, 0x0004, 0x0110,
+	0xc08d, 0x0008, 0xc085, 0x200a, 0x2001, 0x1968, 0x2003, 0x0001,
+	0x0030, 0x080c, 0x2a4a, 0x2001, 0xffff, 0x080c, 0x28db, 0x0005,
+	0x080c, 0x2a28, 0x05e0, 0x2009, 0x1971, 0x2104, 0x8001, 0x200a,
+	0x080c, 0x2b06, 0x1178, 0x7850, 0x9084, 0xefff, 0x7852, 0x7a38,
+	0x9294, 0x0005, 0x9296, 0x0005, 0x0518, 0x2009, 0x1970, 0x2104,
+	0xc085, 0x200a, 0x2009, 0x196d, 0x2104, 0x8000, 0x200a, 0x9086,
+	0x0005, 0x0118, 0x080c, 0x2a30, 0x00c0, 0x200b, 0x0000, 0x7a38,
+	0x9294, 0x0006, 0x9296, 0x0004, 0x0110, 0x9006, 0x0010, 0x2001,
+	0x0001, 0x080c, 0x2ab8, 0x2001, 0x196a, 0x2003, 0x0002, 0x0028,
+	0x2001, 0x1968, 0x2003, 0x0003, 0x0010, 0x080c, 0x28fd, 0x0005,
+	0x080c, 0x2a28, 0x0560, 0x2009, 0x1971, 0x2104, 0x8001, 0x200a,
+	0x080c, 0x2b06, 0x1168, 0x7850, 0x9084, 0xefff, 0x7852, 0x2001,
+	0x1968, 0x2003, 0x0003, 0x2001, 0x1969, 0x2003, 0x0000, 0x00b8,
+	0x2009, 0x1971, 0x2104, 0x9005, 0x1118, 0x080c, 0x2a6d, 0x0010,
+	0x080c, 0x2a3d, 0x080c, 0x2a30, 0x2009, 0x196d, 0x200b, 0x0000,
+	0x2001, 0x196a, 0x2003, 0x0001, 0x080c, 0x28fd, 0x0000, 0x0005,
+	0x04b9, 0x0508, 0x080c, 0x2b06, 0x11b8, 0x7850, 0x9084, 0xefff,
+	0x7852, 0x2009, 0x196e, 0x2104, 0x8000, 0x200a, 0x9086, 0x0007,
+	0x0108, 0x0078, 0x2001, 0x1973, 0x2003, 0x000a, 0x2009, 0x1970,
+	0x2104, 0xc0fd, 0x200a, 0x0038, 0x0419, 0x2001, 0x196a, 0x2003,
+	0x0004, 0x080c, 0x2928, 0x0005, 0x0099, 0x0168, 0x080c, 0x2b06,
+	0x1138, 0x7850, 0x9084, 0xefff, 0x7852, 0x080c, 0x2914, 0x0018,
+	0x0079, 0x080c, 0x2928, 0x0005, 0x080c, 0x0dfa, 0x080c, 0x0dfa,
+	0x2009, 0x1972, 0x2104, 0x8001, 0x200a, 0x090c, 0x2a89, 0x0005,
+	0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010,
+	0x2001, 0x0001, 0x080c, 0x2ab8, 0x0005, 0x7a38, 0x9294, 0x0006,
+	0x9296, 0x0006, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x080c,
+	0x2a9b, 0x0005, 0x2009, 0x196d, 0x2104, 0x8000, 0x200a, 0x9086,
+	0x0005, 0x0108, 0x0068, 0x200b, 0x0000, 0x7a38, 0x9294, 0x0006,
+	0x9296, 0x0006, 0x0110, 0x9006, 0x0010, 0x2001, 0x0001, 0x04d9,
+	0x7a38, 0x9294, 0x0005, 0x9296, 0x0005, 0x0110, 0x9006, 0x0010,
+	0x2001, 0x0001, 0x080c, 0x2ab8, 0x0005, 0x0086, 0x2001, 0x1970,
+	0x2004, 0x9084, 0x7fff, 0x090c, 0x0dfa, 0x2009, 0x196f, 0x2144,
+	0x8846, 0x280a, 0x9844, 0x0dd8, 0xd08c, 0x1120, 0xd084, 0x1120,
+	0x080c, 0x0dfa, 0x9006, 0x0010, 0x2001, 0x0001, 0x00a1, 0x008e,
+	0x0005, 0x0006, 0x0156, 0x2001, 0x1968, 0x20a9, 0x0009, 0x2003,
+	0x0000, 0x8000, 0x1f04, 0x2a8f, 0x2001, 0x196f, 0x2003, 0x8000,
+	0x015e, 0x000e, 0x0005, 0x00f6, 0x2079, 0x0100, 0x9085, 0x0000,
+	0x0158, 0x7838, 0x9084, 0xfff9, 0x9085, 0x0004, 0x783a, 0x2009,
+	0x1975, 0x210c, 0x795a, 0x0050, 0x7838, 0x9084, 0xfffb, 0x9085,
+	0x0006, 0x783a, 0x2009, 0x1976, 0x210c, 0x795a, 0x00fe, 0x0005,
+	0x00f6, 0x2079, 0x0100, 0x9085, 0x0000, 0x0188, 0x7838, 0x9084,
+	0xfffa, 0x9085, 0x0004, 0x783a, 0x2001, 0x0100, 0x2004, 0x9086,
+	0x000a, 0x1120, 0x7850, 0x9084, 0xfff0, 0x7852, 0x0428, 0x7838,
+	0x9084, 0xfffb, 0x9085, 0x0005, 0x783a, 0x2001, 0x0100, 0x2004,
+	0x9086, 0x000a, 0x11c8, 0x7850, 0x9084, 0xfff0, 0x0016, 0x2009,
+	0x017f, 0x210c, 0x918e, 0x0005, 0x0140, 0x2009, 0x0003, 0x210c,
+	0x918c, 0x0600, 0x918e, 0x0400, 0x0118, 0x9085, 0x000a, 0x0010,
+	0x9085, 0x0000, 0x001e, 0x7852, 0x00fe, 0x0005, 0x0006, 0x2001,
+	0x0100, 0x2004, 0x9082, 0x0007, 0x000e, 0x0005, 0x0006, 0x2001,
+	0x0100, 0x2004, 0x9082, 0x0009, 0x000e, 0x0005, 0x0156, 0x20a9,
+	0x0064, 0x7820, 0x080c, 0x2bb0, 0xd09c, 0x1110, 0x1f04, 0x2b09,
+	0x015e, 0x0005, 0x0126, 0x0016, 0x0006, 0x2091, 0x8000, 0x2001,
+	0x0100, 0x2004, 0x9086, 0x000a, 0x0170, 0x7850, 0x9085, 0x0040,
+	0x7852, 0x7850, 0x9084, 0xfbcf, 0x7852, 0x080c, 0x2bb0, 0x9085,
+	0x2000, 0x7852, 0x0020, 0x080c, 0x2cc2, 0x080c, 0x2cf5, 0x000e,
+	0x2008, 0x9186, 0x0000, 0x1118, 0x783b, 0x0007, 0x0090, 0x9186,
+	0x0001, 0x1118, 0x783b, 0x0006, 0x0060, 0x9186, 0x0002, 0x1118,
+	0x783b, 0x0005, 0x0030, 0x9186, 0x0003, 0x1118, 0x783b, 0x0004,
+	0x0000, 0x0006, 0x1d04, 0x2b4a, 0x080c, 0x838e, 0x1f04, 0x2b4a,
+	0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0160, 0x7850, 0x9085,
+	0x0400, 0x9084, 0xdfbf, 0x7852, 0x080c, 0x2bb0, 0x9085, 0x1000,
+	0x7852, 0x0020, 0x7850, 0x9085, 0x1000, 0x7852, 0x000e, 0x001e,
+	0x012e, 0x0005, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0128,
+	0x7850, 0x9084, 0xffcf, 0x7852, 0x0010, 0x080c, 0x2cf5, 0x0005,
+	0x0006, 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854,
+	0xd0ac, 0x1130, 0x7820, 0xd0e4, 0x1140, 0x1f04, 0x2b82, 0x0028,
+	0x7854, 0xd08c, 0x1110, 0x1f04, 0x2b88, 0x00fe, 0x015e, 0x000e,
+	0x0005, 0x1d04, 0x2b91, 0x080c, 0x838e, 0x1f04, 0x2b91, 0x0005,
+	0x0006, 0x2001, 0x1974, 0x2004, 0x9086, 0x0000, 0x000e, 0x0005,
+	0x0006, 0x2001, 0x1974, 0x2004, 0x9086, 0x0001, 0x000e, 0x0005,
+	0x0006, 0x2001, 0x1974, 0x2004, 0x9086, 0x0002, 0x000e, 0x0005,
+	0xa001, 0xa001, 0xa001, 0xa001, 0xa001, 0x0005, 0x0006, 0x2001,
+	0x1980, 0x2102, 0x000e, 0x0005, 0x2009, 0x0171, 0x2104, 0xd0dc,
+	0x0140, 0x2009, 0x0170, 0x2104, 0x200b, 0x0080, 0xa001, 0xa001,
+	0x200a, 0x0005, 0x0036, 0x0046, 0x2001, 0x0141, 0x200c, 0x918c,
+	0xff00, 0x9186, 0x2100, 0x0140, 0x9186, 0x2000, 0x0170, 0x9186,
+	0x0100, 0x1904, 0x2c29, 0x0048, 0x0016, 0x2009, 0x1a5a, 0x2104,
+	0x8000, 0x0208, 0x200a, 0x001e, 0x04f0, 0x2009, 0x00a2, 0x080c,
+	0x0e75, 0x2019, 0x0160, 0x2324, 0x2011, 0x0003, 0x2009, 0x0169,
+	0x2104, 0x9084, 0x0007, 0x210c, 0x918c, 0x0007, 0x910e, 0x1db0,
+	0x9086, 0x0003, 0x1548, 0x2304, 0x0066, 0x0076, 0x2031, 0x0002,
+	0x233c, 0x973e, 0x0148, 0x8631, 0x1dd8, 0x2031, 0x1a5b, 0x263c,
+	0x8738, 0x0208, 0x2732, 0x2304, 0x007e, 0x006e, 0x9402, 0x02a0,
+	0x19d0, 0x8211, 0x19d8, 0x84ff, 0x0170, 0x2001, 0x0141, 0x200c,
+	0x918c, 0xff00, 0x9186, 0x0100, 0x0130, 0x2009, 0x180c, 0x2104,
+	0xc0dd, 0x200a, 0x0008, 0x0421, 0x2001, 0x1959, 0x200c, 0x080c,
+	0x0e75, 0x004e, 0x003e, 0x0005, 0x2001, 0x180c, 0x2004, 0xd0dc,
+	0x01b0, 0x2001, 0x0160, 0x2004, 0x9005, 0x0140, 0x2001, 0x0141,
+	0x2004, 0x9084, 0xff00, 0x9086, 0x0100, 0x1148, 0x0126, 0x2091,
+	0x8000, 0x0016, 0x0026, 0x0021, 0x002e, 0x001e, 0x012e, 0x0005,
+	0x00c6, 0x2061, 0x0100, 0x6014, 0x0006, 0x2001, 0x0161, 0x2003,
+	0x0000, 0x6017, 0x0018, 0xa001, 0xa001, 0x602f, 0x0008, 0x6104,
+	0x918e, 0x0010, 0x6106, 0x918e, 0x0010, 0x6106, 0x6017, 0x0040,
+	0x04b9, 0x001e, 0x9184, 0x0003, 0x01e0, 0x0036, 0x0016, 0x2019,
+	0x0141, 0x6124, 0x918c, 0x0028, 0x1120, 0x2304, 0x9084, 0x2800,
+	0x0dc0, 0x001e, 0x919c, 0xffe4, 0x9184, 0x0001, 0x0118, 0x9385,
+	0x0009, 0x6016, 0x9184, 0x0002, 0x0118, 0x9385, 0x0012, 0x6016,
+	0x003e, 0x2001, 0x180c, 0x200c, 0xc1dc, 0x2102, 0x00ce, 0x0005,
+	0x0016, 0x0026, 0x080c, 0x7221, 0x0108, 0xc0bc, 0x2009, 0x0140,
+	0x2114, 0x9294, 0x0001, 0x9215, 0x220a, 0x002e, 0x001e, 0x0005,
+	0x0016, 0x0026, 0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9285,
+	0x1000, 0x200a, 0x220a, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026,
+	0x2009, 0x0140, 0x2114, 0x9294, 0x0001, 0x9215, 0x220a, 0x002e,
+	0x001e, 0x0005, 0x0006, 0x0016, 0x2009, 0x0140, 0x2104, 0x1128,
+	0x080c, 0x7221, 0x0110, 0xc0bc, 0x0008, 0xc0bd, 0x200a, 0x001e,
+	0x000e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x2061, 0x0100,
+	0x6050, 0x9084, 0xfbff, 0x9085, 0x0040, 0x6052, 0x20a9, 0x0002,
+	0x080c, 0x2b91, 0x6050, 0x9085, 0x0400, 0x9084, 0xff9f, 0x6052,
+	0x20a9, 0x0005, 0x080c, 0x2b91, 0x6054, 0xd0bc, 0x090c, 0x0dfa,
+	0x20a9, 0x0005, 0x080c, 0x2b91, 0x6054, 0xd0ac, 0x090c, 0x0dfa,
+	0x2009, 0x1987, 0x9084, 0x7e00, 0x8007, 0x8004, 0x8004, 0x200a,
+	0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0006, 0x00c6, 0x2061,
+	0x0100, 0x6050, 0xc0cd, 0x6052, 0x00ce, 0x000e, 0x0005, 0x2f6b,
+	0x2f6b, 0x2d8f, 0x2d8f, 0x2d9b, 0x2d9b, 0x2da7, 0x2da7, 0x2db5,
+	0x2db5, 0x2dc1, 0x2dc1, 0x2dcf, 0x2dcf, 0x2ddd, 0x2ddd, 0x2def,
+	0x2def, 0x2dfb, 0x2dfb, 0x2e09, 0x2e09, 0x2e27, 0x2e27, 0x2e47,
+	0x2e47, 0x2e17, 0x2e17, 0x2e37, 0x2e37, 0x2e55, 0x2e55, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2e67,
+	0x2e67, 0x2e73, 0x2e73, 0x2e81, 0x2e81, 0x2e8f, 0x2e8f, 0x2e9f,
+	0x2e9f, 0x2ead, 0x2ead, 0x2ebd, 0x2ebd, 0x2ecd, 0x2ecd, 0x2edf,
+	0x2edf, 0x2eed, 0x2eed, 0x2efd, 0x2efd, 0x2f1f, 0x2f1f, 0x2f41,
+	0x2f41, 0x2f0d, 0x2f0d, 0x2f30, 0x2f30, 0x2f50, 0x2f50, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded,
+	0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x2ded, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x23c6, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6,
+	0x0136, 0x0146, 0x0156, 0x080c, 0x21cd, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x21cd, 0x080c, 0x23c6, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2208, 0x0804,
+	0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x23c6, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x21cd, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x21cd, 0x080c,
+	0x23c6, 0x080c, 0x2208, 0x0804, 0x2f63, 0xa001, 0x0cf0, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x1370, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6,
+	0x0136, 0x0146, 0x0156, 0x080c, 0x23c6, 0x080c, 0x1370, 0x0804,
+	0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x21cd, 0x080c, 0x1370, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x23c6, 0x080c, 0x1370, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x21cd, 0x080c, 0x23c6, 0x080c, 0x1370, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x21cd, 0x080c, 0x1370, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x1370, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x21cd, 0x080c,
+	0x23c6, 0x080c, 0x1370, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x2871, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6,
+	0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c, 0x23c6, 0x0804,
+	0x2f63, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x2871, 0x080c, 0x21cd, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x2871, 0x080c, 0x21cd, 0x080c, 0x23c6, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x2871, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x23c6, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x21cd, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x21cd, 0x080c, 0x23c6, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x2871, 0x080c, 0x1370, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x23c6, 0x080c, 0x1370, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x21cd, 0x080c, 0x1370, 0x0804, 0x2f63, 0x0106, 0x0006, 0x0126,
+	0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c, 0x2871, 0x080c,
+	0x23c6, 0x080c, 0x1370, 0x080c, 0x2208, 0x0804, 0x2f63, 0x0106,
+	0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156, 0x080c,
+	0x2871, 0x080c, 0x21cd, 0x080c, 0x23c6, 0x080c, 0x1370, 0x0498,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2871, 0x080c, 0x21cd, 0x080c, 0x1370, 0x080c, 0x2208,
+	0x0410, 0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146,
+	0x0156, 0x080c, 0x2871, 0x080c, 0x1370, 0x080c, 0x2208, 0x0098,
+	0x0106, 0x0006, 0x0126, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x0156,
+	0x080c, 0x2871, 0x080c, 0x21cd, 0x080c, 0x23c6, 0x080c, 0x1370,
+	0x080c, 0x2208, 0x0000, 0x015e, 0x014e, 0x013e, 0x01de, 0x01ce,
+	0x012e, 0x000e, 0x010e, 0x000d, 0x00b6, 0x00c6, 0x0026, 0x0046,
+	0x9026, 0x080c, 0x6781, 0x1904, 0x3072, 0x72d8, 0x2001, 0x1954,
+	0x2004, 0x9005, 0x1110, 0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc,
+	0x1904, 0x3072, 0x080c, 0x3077, 0x0804, 0x3072, 0xd2cc, 0x1904,
+	0x3072, 0x080c, 0x7207, 0x1120, 0x70ab, 0xffff, 0x0804, 0x3072,
+	0xd294, 0x0120, 0x70ab, 0xffff, 0x0804, 0x3072, 0x080c, 0x32df,
+	0x0160, 0x080c, 0xc539, 0x0128, 0x2001, 0x1817, 0x203c, 0x0804,
+	0x3004, 0x70ab, 0xffff, 0x0804, 0x3072, 0x2001, 0x1817, 0x203c,
+	0x7290, 0xd284, 0x0904, 0x3004, 0xd28c, 0x1904, 0x3004, 0x0036,
+	0x73a8, 0x938e, 0xffff, 0x1110, 0x2019, 0x0001, 0x8314, 0x92e0,
+	0x1c80, 0x2c04, 0x938c, 0x0001, 0x0120, 0x9084, 0xff00, 0x8007,
+	0x0010, 0x9084, 0x00ff, 0x970e, 0x05a8, 0x908e, 0x0000, 0x0590,
+	0x908e, 0x00ff, 0x1150, 0x7230, 0xd284, 0x1588, 0x7290, 0xc28d,
+	0x7292, 0x70ab, 0xffff, 0x003e, 0x0478, 0x0026, 0x2011, 0x0010,
+	0x080c, 0x67e7, 0x002e, 0x0118, 0x70ab, 0xffff, 0x0410, 0x900e,
+	0x080c, 0x276e, 0x080c, 0x643f, 0x11c0, 0x080c, 0x67c3, 0x1168,
+	0x7030, 0xd08c, 0x0130, 0xb800, 0xd0bc, 0x0138, 0x080c, 0x66bf,
+	0x0120, 0x080c, 0x3090, 0x0148, 0x0028, 0x080c, 0x31d0, 0x080c,
+	0x30bc, 0x0118, 0x8318, 0x0804, 0x2fb6, 0x73aa, 0x0010, 0x70ab,
+	0xffff, 0x003e, 0x0804, 0x3072, 0x9780, 0x32e9, 0x203d, 0x97bc,
+	0xff00, 0x873f, 0x2041, 0x007e, 0x70a8, 0x9096, 0xffff, 0x1118,
+	0x900e, 0x28a8, 0x0050, 0x9812, 0x0220, 0x2008, 0x9802, 0x20a8,
+	0x0020, 0x70ab, 0xffff, 0x0804, 0x3072, 0x2700, 0x0156, 0x0016,
+	0x9106, 0x0904, 0x3067, 0x0026, 0x2011, 0x0010, 0x080c, 0x67e7,
+	0x002e, 0x0120, 0x2009, 0xffff, 0x0804, 0x306f, 0xc484, 0x080c,
+	0x649f, 0x0138, 0x080c, 0xc539, 0x1590, 0x080c, 0x643f, 0x15b8,
+	0x0008, 0xc485, 0x080c, 0x67c3, 0x1130, 0x7030, 0xd08c, 0x01f8,
+	0xb800, 0xd0bc, 0x11e0, 0x7290, 0xd28c, 0x0180, 0x080c, 0x67c3,
+	0x9082, 0x0006, 0x02e0, 0xd484, 0x1118, 0x080c, 0x6463, 0x0028,
+	0x080c, 0x325b, 0x01a0, 0x080c, 0x3286, 0x0088, 0x080c, 0x31d0,
+	0x080c, 0xc539, 0x1160, 0x080c, 0x30bc, 0x0188, 0x0040, 0x080c,
+	0xc539, 0x1118, 0x080c, 0x325b, 0x0110, 0x0451, 0x0140, 0x001e,
+	0x8108, 0x015e, 0x1f04, 0x301d, 0x70ab, 0xffff, 0x0018, 0x001e,
+	0x015e, 0x71aa, 0x004e, 0x002e, 0x00ce, 0x00be, 0x0005, 0x00c6,
+	0x0016, 0x70ab, 0x0001, 0x2009, 0x007e, 0x080c, 0x643f, 0x1168,
+	0xb813, 0x00ff, 0xb817, 0xfffe, 0x080c, 0x31d0, 0x04a9, 0x0128,
+	0x70d8, 0xc0bd, 0x70da, 0x080c, 0xc28a, 0x001e, 0x00ce, 0x0005,
+	0x0016, 0x0076, 0x00d6, 0x00c6, 0x2001, 0x1860, 0x2004, 0x9084,
+	0x00ff, 0xb842, 0x080c, 0xa130, 0x01d0, 0x2b00, 0x6012, 0x080c,
+	0xc2b3, 0x6023, 0x0001, 0x9006, 0x080c, 0x63dc, 0x2001, 0x0000,
+	0x080c, 0x63f0, 0x0126, 0x2091, 0x8000, 0x70a4, 0x8000, 0x70a6,
+	0x012e, 0x2009, 0x0004, 0x080c, 0xa15d, 0x9085, 0x0001, 0x00ce,
+	0x00de, 0x007e, 0x001e, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6,
+	0x2001, 0x1860, 0x2004, 0x9084, 0x00ff, 0xb842, 0x080c, 0xa130,
+	0x0548, 0x2b00, 0x6012, 0xb800, 0xc0c4, 0xb802, 0xb8a0, 0x9086,
+	0x007e, 0x0140, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1110,
+	0x080c, 0x318b, 0x080c, 0xc2b3, 0x6023, 0x0001, 0x9006, 0x080c,
+	0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0, 0x0126, 0x2091, 0x8000,
+	0x70a4, 0x8000, 0x70a6, 0x012e, 0x2009, 0x0002, 0x080c, 0xa15d,
+	0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00b6,
+	0x00c6, 0x0026, 0x2009, 0x0080, 0x080c, 0x643f, 0x1140, 0xb813,
+	0x00ff, 0xb817, 0xfffc, 0x0039, 0x0110, 0x70df, 0xffff, 0x002e,
+	0x00ce, 0x00be, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x080c,
+	0xa08d, 0x01d0, 0x2b00, 0x6012, 0x080c, 0xc2b3, 0x6023, 0x0001,
+	0x9006, 0x080c, 0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0, 0x0126,
+	0x2091, 0x8000, 0x70e0, 0x8000, 0x70e2, 0x012e, 0x2009, 0x0002,
+	0x080c, 0xa15d, 0x9085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e,
+	0x0005, 0x00c6, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2009, 0x007f,
+	0x080c, 0x643f, 0x11b8, 0xb813, 0x00ff, 0xb817, 0xfffd, 0xb8bf,
+	0x0004, 0x080c, 0xa08d, 0x0170, 0x2b00, 0x6012, 0x6316, 0x6023,
+	0x0001, 0x620a, 0x080c, 0xc2b3, 0x2009, 0x0022, 0x080c, 0xa15d,
+	0x9085, 0x0001, 0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6,
+	0x0066, 0x0036, 0x0026, 0x00b6, 0x21f0, 0x080c, 0x880e, 0x080c,
+	0x8798, 0x080c, 0x9f36, 0x080c, 0xb03a, 0x3e08, 0x2130, 0x81ff,
+	0x0120, 0x20a9, 0x007e, 0x900e, 0x0018, 0x20a9, 0x007f, 0x900e,
+	0x0016, 0x080c, 0x649f, 0x1140, 0x9686, 0x0002, 0x1118, 0xb800,
+	0xd0bc, 0x1110, 0x080c, 0x5f45, 0x001e, 0x8108, 0x1f04, 0x3170,
+	0x9686, 0x0001, 0x190c, 0x32b3, 0x00be, 0x002e, 0x003e, 0x006e,
+	0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0046, 0x0036, 0x0026,
+	0x0016, 0x00b6, 0x6210, 0x2258, 0xbaa0, 0x0026, 0x2019, 0x0029,
+	0x080c, 0x8803, 0x0076, 0x2039, 0x0000, 0x080c, 0x86f1, 0x2c08,
+	0x080c, 0xd5f6, 0x007e, 0x001e, 0xba10, 0xbb14, 0xbcb0, 0x080c,
+	0x5f45, 0xba12, 0xbb16, 0xbcb2, 0x00be, 0x001e, 0x002e, 0x003e,
+	0x004e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x00b6, 0x6010,
+	0x2058, 0xb8a0, 0x00be, 0x9086, 0x0080, 0x0150, 0x2071, 0x1800,
+	0x70a4, 0x9005, 0x0110, 0x8001, 0x70a6, 0x000e, 0x00ee, 0x0005,
+	0x2071, 0x1800, 0x70e0, 0x9005, 0x0dc0, 0x8001, 0x70e2, 0x0ca8,
+	0xb800, 0xc08c, 0xb802, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x00b6,
+	0x0046, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, 0x81ff, 0x1118,
+	0x20a9, 0x0001, 0x0070, 0x080c, 0x55db, 0xd0c4, 0x0138, 0x0030,
+	0x9006, 0x2020, 0x2009, 0x002d, 0x080c, 0xd885, 0x20a9, 0x0800,
+	0x9016, 0x0026, 0x928e, 0x007e, 0x0904, 0x323a, 0x928e, 0x007f,
+	0x0904, 0x323a, 0x928e, 0x0080, 0x05e8, 0x9288, 0x1000, 0x210c,
+	0x81ff, 0x05c0, 0x8fff, 0x1148, 0x2001, 0x1966, 0x0006, 0x2003,
+	0x0001, 0x04f1, 0x000e, 0x2003, 0x0000, 0x00b6, 0x00c6, 0x2158,
+	0x2001, 0x0001, 0x080c, 0x678d, 0x00ce, 0x00be, 0x2019, 0x0029,
+	0x080c, 0x8803, 0x0076, 0x2039, 0x0000, 0x080c, 0x86f1, 0x00b6,
+	0x00c6, 0x0026, 0x2158, 0xba04, 0x9294, 0x00ff, 0x9286, 0x0006,
+	0x1118, 0xb807, 0x0404, 0x0028, 0x2001, 0x0004, 0x8007, 0x9215,
+	0xba06, 0x002e, 0x00ce, 0x00be, 0x0016, 0x2c08, 0x080c, 0xd5f6,
+	0x001e, 0x007e, 0x002e, 0x8210, 0x1f04, 0x31f1, 0x015e, 0x001e,
+	0x002e, 0x003e, 0x004e, 0x00be, 0x00ce, 0x00ee, 0x00fe, 0x0005,
+	0x0046, 0x0026, 0x0016, 0x080c, 0x55db, 0xd0c4, 0x0140, 0xd0a4,
+	0x0130, 0x9006, 0x2220, 0x2009, 0x0029, 0x080c, 0xd885, 0x001e,
+	0x002e, 0x004e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6, 0x7290,
+	0x82ff, 0x01e8, 0x080c, 0x67bb, 0x11d0, 0x2100, 0x080c, 0x27a1,
+	0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314, 0x92e0, 0x1c80, 0x2c04,
+	0xd384, 0x0120, 0x9084, 0xff00, 0x8007, 0x0010, 0x9084, 0x00ff,
+	0x9116, 0x0138, 0x9096, 0x00ff, 0x0110, 0x8318, 0x0c68, 0x9085,
+	0x0001, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0016, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x0036, 0x2019, 0x0029, 0x00a9, 0x003e,
+	0x9180, 0x1000, 0x2004, 0x9065, 0x0158, 0x0016, 0x00c6, 0x2061,
+	0x1a8a, 0x001e, 0x6112, 0x080c, 0x318b, 0x001e, 0x080c, 0x6463,
+	0x012e, 0x00ce, 0x001e, 0x0005, 0x0016, 0x0026, 0x2110, 0x080c,
+	0x9bc9, 0x080c, 0xdb3d, 0x002e, 0x001e, 0x0005, 0x2001, 0x1836,
+	0x2004, 0xd0cc, 0x0005, 0x00c6, 0x00b6, 0x080c, 0x7207, 0x1118,
+	0x20a9, 0x0800, 0x0010, 0x20a9, 0x0782, 0x080c, 0x7207, 0x1110,
+	0x900e, 0x0010, 0x2009, 0x007e, 0x9180, 0x1000, 0x2004, 0x905d,
+	0x0130, 0x86ff, 0x0110, 0xb800, 0xd0bc, 0x090c, 0x6463, 0x8108,
+	0x1f04, 0x32c4, 0x2061, 0x1800, 0x607b, 0x0000, 0x607c, 0x9084,
+	0x00ff, 0x607e, 0x60af, 0x0000, 0x00be, 0x00ce, 0x0005, 0x2001,
+	0x187d, 0x2004, 0xd0bc, 0x0005, 0x2011, 0x185c, 0x2214, 0xd2ec,
+	0x0005, 0x7eef, 0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc,
+	0x80da, 0x7ad9, 0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1,
+	0x79ce, 0x78cd, 0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6,
+	0x77c5, 0x76c3, 0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4,
+	0x72b3, 0x80b2, 0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa,
+	0x6ea9, 0x80a7, 0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d,
+	0x809b, 0x8098, 0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282,
+	0x8081, 0x8080, 0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074,
+	0x8073, 0x8072, 0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a,
+	0x5b69, 0x8067, 0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559,
+	0x8056, 0x8055, 0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d,
+	0x804c, 0x804b, 0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043,
+	0x803c, 0x803a, 0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932,
+	0x4831, 0x802e, 0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227,
+	0x8026, 0x8025, 0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18,
+	0x8017, 0x8010, 0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000,
+	0x8000, 0x3800, 0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000,
+	0x8000, 0x3400, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x3300, 0x3200, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x3100, 0x3000, 0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00,
+	0x2c00, 0x8000, 0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900,
+	0x2800, 0x8000, 0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200,
+	0x8000, 0x8000, 0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00,
+	0x8000, 0x8000, 0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600,
+	0x1500, 0x8000, 0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00,
+	0x8000, 0x8000, 0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900,
+	0x8000, 0x8000, 0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000,
+	0x8000, 0x0500, 0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000,
+	0x8000, 0x0100, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x0000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x2071, 0x189c, 0x7003, 0x0002, 0x9006, 0x7016, 0x701a,
+	0x704a, 0x704e, 0x700e, 0x7042, 0x7046, 0x703b, 0x18b8, 0x703f,
+	0x18b8, 0x7007, 0x0001, 0x080c, 0x104a, 0x090c, 0x0dfa, 0x2900,
+	0x706a, 0xa867, 0x0002, 0xa8ab, 0xdcb0, 0x080c, 0x104a, 0x090c,
+	0x0dfa, 0x2900, 0x706e, 0xa867, 0x0002, 0xa8ab, 0xdcb0, 0x0005,
+	0x2071, 0x189c, 0x7004, 0x0002, 0x3418, 0x3419, 0x342c, 0x3440,
+	0x0005, 0x1004, 0x3429, 0x0e04, 0x3429, 0x2079, 0x0000, 0x0126,
+	0x2091, 0x8000, 0x700c, 0x9005, 0x1128, 0x700f, 0x0001, 0x012e,
+	0x0468, 0x0005, 0x012e, 0x0ce8, 0x2079, 0x0000, 0x2061, 0x18b6,
+	0x2c4c, 0xa86c, 0x908e, 0x0100, 0x0128, 0x9086, 0x0200, 0x0904,
+	0x3514, 0x0005, 0x7018, 0x2048, 0x2061, 0x1800, 0x701c, 0x0807,
+	0x7014, 0x2048, 0xa864, 0x9094, 0x00ff, 0x9296, 0x0029, 0x1120,
+	0xaa78, 0xd2fc, 0x0128, 0x0005, 0x9086, 0x0103, 0x0108, 0x0005,
+	0x2079, 0x0000, 0x2061, 0x1800, 0x701c, 0x0807, 0x2061, 0x1800,
+	0x7880, 0x908a, 0x0040, 0x1210, 0x61cc, 0x0042, 0x2100, 0x908a,
+	0x003f, 0x1a04, 0x3511, 0x61cc, 0x0804, 0x34a6, 0x34e8, 0x3520,
+	0x3511, 0x352a, 0x3534, 0x353a, 0x353e, 0x354e, 0x3552, 0x3568,
+	0x356e, 0x3574, 0x357f, 0x358a, 0x3599, 0x35a8, 0x35b6, 0x35cd,
+	0x35e8, 0x3511, 0x3691, 0x36cf, 0x3775, 0x3786, 0x37a9, 0x3511,
+	0x3511, 0x3511, 0x37e1, 0x37fd, 0x3806, 0x3835, 0x383b, 0x3511,
+	0x3881, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x388c, 0x3895,
+	0x389d, 0x389f, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511,
+	0x38cb, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x38e8, 0x395c,
+	0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x0002, 0x3986,
+	0x3989, 0x39e8, 0x3a01, 0x3a31, 0x3ccf, 0x3511, 0x519f, 0x3511,
+	0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x3511, 0x3568,
+	0x356e, 0x4249, 0x55ff, 0x425f, 0x522e, 0x527f, 0x538a, 0x3511,
+	0x53ec, 0x5428, 0x5459, 0x5561, 0x5486, 0x54e1, 0x3511, 0x4263,
+	0x4408, 0x441e, 0x4443, 0x44a8, 0x451c, 0x453c, 0x45b3, 0x460f,
+	0x466b, 0x466e, 0x4693, 0x4741, 0x47a7, 0x47af, 0x48e1, 0x4a49,
+	0x4a7d, 0x4cc7, 0x3511, 0x4ce5, 0x4da2, 0x4e78, 0x3511, 0x3511,
+	0x3511, 0x3511, 0x4ede, 0x4ef9, 0x47af, 0x513f, 0x714c, 0x0000,
+	0x2021, 0x4000, 0x080c, 0x4afb, 0x0126, 0x2091, 0x8000, 0x0e04,
+	0x34f2, 0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486, 0x4000, 0x0118,
+	0x7833, 0x0011, 0x0010, 0x7833, 0x0010, 0x7c82, 0x7986, 0x7a8a,
+	0x7b8e, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x11e0, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f, 0x0000, 0x012e,
+	0x0005, 0x2021, 0x4001, 0x08b0, 0x2021, 0x4002, 0x0898, 0x2021,
+	0x4003, 0x0880, 0x2021, 0x4005, 0x0868, 0x2021, 0x4006, 0x0850,
+	0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c, 0x7884, 0x7990,
+	0x0804, 0x4b08, 0x2039, 0x0001, 0x902e, 0x2520, 0x7b88, 0x7a8c,
+	0x7884, 0x7990, 0x0804, 0x4b0b, 0x7984, 0x7888, 0x2114, 0x200a,
+	0x0804, 0x34e8, 0x7984, 0x2114, 0x0804, 0x34e8, 0x20e1, 0x0000,
+	0x2099, 0x0021, 0x20e9, 0x0000, 0x20a1, 0x0021, 0x20a9, 0x001f,
+	0x4003, 0x7984, 0x7a88, 0x7b8c, 0x0804, 0x34e8, 0x7884, 0x2060,
+	0x0804, 0x359b, 0x2009, 0x0003, 0x2011, 0x0003, 0x2019, 0x0008,
+	0x789b, 0x0317, 0x7893, 0xffff, 0x2001, 0x188d, 0x2004, 0x9005,
+	0x0118, 0x7896, 0x0804, 0x34e8, 0x7897, 0x0001, 0x0804, 0x34e8,
+	0x2039, 0x0001, 0x7d98, 0x7c9c, 0x0804, 0x3524, 0x2039, 0x0001,
+	0x7d98, 0x7c9c, 0x0804, 0x352e, 0x79a0, 0x9182, 0x0040, 0x0210,
+	0x0804, 0x351d, 0x2138, 0x7d98, 0x7c9c, 0x0804, 0x3524, 0x79a0,
+	0x9182, 0x0040, 0x0210, 0x0804, 0x351d, 0x2138, 0x7d98, 0x7c9c,
+	0x0804, 0x352e, 0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x351d,
+	0x21e8, 0x7984, 0x7888, 0x20a9, 0x0001, 0x21a0, 0x4004, 0x0804,
+	0x34e8, 0x2061, 0x0800, 0xe10c, 0x9006, 0x2c15, 0x9200, 0x8c60,
+	0x8109, 0x1dd8, 0x2010, 0x9005, 0x0904, 0x34e8, 0x0804, 0x3517,
+	0x79a0, 0x9182, 0x0040, 0x0210, 0x0804, 0x351d, 0x21e0, 0x20a9,
+	0x0001, 0x7984, 0x2198, 0x4012, 0x0804, 0x34e8, 0x2069, 0x185b,
+	0x7884, 0x7990, 0x911a, 0x1a04, 0x351d, 0x8019, 0x0904, 0x351d,
+	0x684a, 0x6942, 0x788c, 0x6852, 0x7888, 0x6856, 0x9006, 0x685a,
+	0x685e, 0x080c, 0x7535, 0x0804, 0x34e8, 0x2069, 0x185b, 0x7884,
+	0x7994, 0x911a, 0x1a04, 0x351d, 0x8019, 0x0904, 0x351d, 0x684e,
+	0x6946, 0x788c, 0x6862, 0x7888, 0x6866, 0x9006, 0x686a, 0x686e,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x68c1, 0x012e, 0x0804, 0x34e8,
+	0x902e, 0x2520, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x351a,
+	0x7984, 0x7b88, 0x7a8c, 0x20a9, 0x0005, 0x20e9, 0x0001, 0x20a1,
+	0x18a4, 0x4101, 0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x351a, 0x2009, 0x0020, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c,
+	0x4b08, 0x701f, 0x360c, 0x0005, 0xa864, 0x2008, 0x9084, 0x00ff,
+	0x9096, 0x0011, 0x0168, 0x9096, 0x0019, 0x0150, 0x9096, 0x0015,
+	0x0138, 0x9096, 0x0048, 0x0120, 0x9096, 0x0029, 0x1904, 0x351a,
+	0x810f, 0x918c, 0x00ff, 0x0904, 0x351a, 0x7112, 0x7010, 0x8001,
+	0x0560, 0x7012, 0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x351a, 0x2009, 0x0020, 0x7068, 0x2040, 0xa28c, 0xa390, 0xa494,
+	0xa598, 0x9290, 0x0040, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9,
+	0x0000, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x080c, 0x4b08, 0x701f,
+	0x364a, 0x0005, 0xa864, 0x9084, 0x00ff, 0x9096, 0x0002, 0x0120,
+	0x9096, 0x000a, 0x1904, 0x351a, 0x0888, 0x7014, 0x2048, 0xa868,
+	0xc0fd, 0xa86a, 0xa864, 0x9084, 0x00ff, 0x9096, 0x0029, 0x1160,
+	0xc2fd, 0xaa7a, 0x080c, 0x6037, 0x0150, 0x0126, 0x2091, 0x8000,
+	0xa87a, 0xa982, 0x012e, 0x0050, 0x080c, 0x6355, 0x1128, 0x7007,
+	0x0003, 0x701f, 0x3676, 0x0005, 0x080c, 0x6d17, 0x0126, 0x2091,
+	0x8000, 0x20a9, 0x0005, 0x20e1, 0x0001, 0x2099, 0x18a4, 0x400a,
+	0x2100, 0x9210, 0x9399, 0x0000, 0x94a1, 0x0000, 0x95a9, 0x0000,
+	0xa85c, 0x9080, 0x0019, 0x2009, 0x0020, 0x012e, 0xaf60, 0x0804,
+	0x4b0b, 0x2091, 0x8000, 0x7837, 0x4000, 0x7833, 0x0010, 0x7883,
+	0x4000, 0x7887, 0x4953, 0x788b, 0x5020, 0x788f, 0x2020, 0x2009,
+	0x017f, 0x2104, 0x7892, 0x3f00, 0x7896, 0x2061, 0x0100, 0x6200,
+	0x2061, 0x0200, 0x603c, 0x8007, 0x9205, 0x789a, 0x2009, 0x04fd,
+	0x2104, 0x789e, 0x2091, 0x5000, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x0180, 0x2001, 0x19f1, 0x2004, 0x9005, 0x0128,
+	0x2001, 0x008b, 0x2004, 0xd0fc, 0x0dd8, 0x2001, 0x008a, 0x2003,
+	0x0002, 0x2003, 0x1001, 0x2071, 0x0080, 0x0804, 0x0427, 0x81ff,
+	0x1904, 0x351a, 0x7984, 0x080c, 0x649f, 0x1904, 0x351d, 0x7e98,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x1a04, 0x351d, 0x7c88, 0x7d8c,
+	0x080c, 0x6602, 0x080c, 0x65d1, 0x0000, 0x1518, 0x2061, 0x1cd0,
+	0x0126, 0x2091, 0x8000, 0x6000, 0x9086, 0x0000, 0x0148, 0x6014,
+	0x904d, 0x0130, 0xa86c, 0x9406, 0x1118, 0xa870, 0x9506, 0x0150,
+	0x012e, 0x9ce0, 0x0018, 0x2001, 0x1819, 0x2004, 0x9c02, 0x1a04,
+	0x351a, 0x0c30, 0x080c, 0xba56, 0x012e, 0x0904, 0x351a, 0x0804,
+	0x34e8, 0x900e, 0x2001, 0x0005, 0x080c, 0x6d17, 0x0126, 0x2091,
+	0x8000, 0x080c, 0xc133, 0x080c, 0x6ae9, 0x012e, 0x0804, 0x34e8,
+	0x00a6, 0x2950, 0xb198, 0x080c, 0x649f, 0x1904, 0x3762, 0xb6a4,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x16e8, 0xb49c, 0xb5a0, 0x080c,
+	0x6602, 0x080c, 0x65d1, 0x1520, 0x2061, 0x1cd0, 0x0126, 0x2091,
+	0x8000, 0x6000, 0x9086, 0x0000, 0x0148, 0x6014, 0x904d, 0x0130,
+	0xa86c, 0x9406, 0x1118, 0xa870, 0x9506, 0x0158, 0x012e, 0x9ce0,
+	0x0018, 0x2001, 0x1819, 0x2004, 0x9c02, 0x2009, 0x000d, 0x12b0,
+	0x0c28, 0x080c, 0xba56, 0x012e, 0x2009, 0x0003, 0x0178, 0x00e0,
+	0x900e, 0x2001, 0x0005, 0x080c, 0x6d17, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xc133, 0x080c, 0x6adc, 0x012e, 0x0070, 0xb097, 0x4005,
+	0xb19a, 0x0010, 0xb097, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0030, 0x2a48, 0x00ae, 0x0005, 0xb097, 0x4000, 0x9006, 0x918d,
+	0x0001, 0x2008, 0x2a48, 0x00ae, 0x0005, 0x81ff, 0x1904, 0x351a,
+	0x080c, 0x4ad6, 0x0904, 0x351d, 0x080c, 0x6566, 0x0904, 0x351a,
+	0x080c, 0x6608, 0x0904, 0x351a, 0x0804, 0x4533, 0x81ff, 0x1904,
+	0x351a, 0x080c, 0x4af2, 0x0904, 0x351d, 0x080c, 0x6696, 0x0904,
+	0x351a, 0x2019, 0x0005, 0x79a8, 0x080c, 0x6623, 0x0904, 0x351a,
+	0x7888, 0x908a, 0x1000, 0x1a04, 0x351d, 0x8003, 0x800b, 0x810b,
+	0x9108, 0x080c, 0x82e8, 0x7984, 0xd184, 0x1904, 0x34e8, 0x0804,
+	0x4533, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0118, 0x2009, 0x0001,
+	0x0450, 0x2029, 0x07ff, 0x6458, 0x2400, 0x9506, 0x01f8, 0x2508,
+	0x080c, 0x649f, 0x11d8, 0x080c, 0x6696, 0x1128, 0x2009, 0x0002,
+	0x62bc, 0x2518, 0x00c0, 0x2019, 0x0004, 0x900e, 0x080c, 0x6623,
+	0x1118, 0x2009, 0x0006, 0x0078, 0x7884, 0x908a, 0x1000, 0x1270,
+	0x8003, 0x800b, 0x810b, 0x9108, 0x080c, 0x82e8, 0x8529, 0x1ae0,
+	0x012e, 0x0804, 0x34e8, 0x012e, 0x0804, 0x351a, 0x012e, 0x0804,
+	0x351d, 0x080c, 0x4ad6, 0x0904, 0x351d, 0x080c, 0x6566, 0x0904,
+	0x351a, 0xbaa0, 0x2019, 0x0005, 0x00c6, 0x9066, 0x080c, 0x8803,
+	0x0076, 0x903e, 0x080c, 0x86f1, 0x900e, 0x080c, 0xd5f6, 0x007e,
+	0x00ce, 0x080c, 0x6602, 0x0804, 0x34e8, 0x080c, 0x4ad6, 0x0904,
+	0x351d, 0x080c, 0x6602, 0x2208, 0x0804, 0x34e8, 0x0156, 0x00d6,
+	0x00e6, 0x2069, 0x190e, 0x6810, 0x6914, 0x910a, 0x1208, 0x900e,
+	0x6816, 0x9016, 0x901e, 0x20a9, 0x007e, 0x2069, 0x1000, 0x2d04,
+	0x905d, 0x0118, 0xb84c, 0x0059, 0x9210, 0x8d68, 0x1f04, 0x3817,
+	0x2300, 0x9218, 0x00ee, 0x00de, 0x015e, 0x0804, 0x34e8, 0x00f6,
+	0x0016, 0x907d, 0x0138, 0x9006, 0x8000, 0x2f0c, 0x81ff, 0x0110,
+	0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069, 0x190e, 0x6910,
+	0x62b8, 0x0804, 0x34e8, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x351a, 0x0126, 0x2091, 0x8000, 0x080c, 0x55ef, 0x0128, 0x2009,
+	0x0007, 0x012e, 0x0804, 0x351a, 0x012e, 0x6158, 0x9190, 0x32e9,
+	0x2215, 0x9294, 0x00ff, 0x6378, 0x83ff, 0x0108, 0x627c, 0x67d8,
+	0x97c4, 0x000a, 0x98c6, 0x000a, 0x1118, 0x2031, 0x0001, 0x00e8,
+	0x97c4, 0x0022, 0x98c6, 0x0022, 0x1118, 0x2031, 0x0003, 0x00a8,
+	0x97c4, 0x0012, 0x98c6, 0x0012, 0x1118, 0x2031, 0x0002, 0x0068,
+	0x080c, 0x7207, 0x1118, 0x2031, 0x0004, 0x0038, 0xd79c, 0x0120,
+	0x2009, 0x0005, 0x0804, 0x351a, 0x9036, 0x7e9a, 0x7f9e, 0x0804,
+	0x34e8, 0x6148, 0x624c, 0x2019, 0x195e, 0x231c, 0x2001, 0x195f,
+	0x2004, 0x789a, 0x0804, 0x34e8, 0x0126, 0x2091, 0x8000, 0x6138,
+	0x623c, 0x6340, 0x012e, 0x0804, 0x34e8, 0x080c, 0x4af2, 0x0904,
+	0x351d, 0xba44, 0xbb38, 0x0804, 0x34e8, 0x080c, 0x0dfa, 0x080c,
+	0x4af2, 0x2110, 0x0904, 0x351d, 0xb804, 0x908c, 0x00ff, 0x918e,
+	0x0006, 0x0140, 0x9084, 0xff00, 0x9086, 0x0600, 0x2009, 0x0009,
+	0x1904, 0x351a, 0x0126, 0x2091, 0x8000, 0x2019, 0x0005, 0x00c6,
+	0x9066, 0x080c, 0x9bc9, 0x080c, 0x8803, 0x0076, 0x903e, 0x080c,
+	0x86f1, 0x900e, 0x080c, 0xd5f6, 0x007e, 0x00ce, 0xb807, 0x0407,
+	0x012e, 0x0804, 0x34e8, 0x6148, 0x624c, 0x7884, 0x604a, 0x7b88,
+	0x634e, 0x2069, 0x185b, 0x831f, 0x9305, 0x6816, 0x788c, 0x2069,
+	0x195e, 0x2d1c, 0x206a, 0x7e98, 0x9682, 0x0014, 0x1210, 0x2031,
+	0x07d0, 0x2069, 0x195f, 0x2d04, 0x266a, 0x789a, 0x0804, 0x34e8,
+	0x0126, 0x2091, 0x8000, 0x6138, 0x7884, 0x603a, 0x910e, 0xd1b4,
+	0x190c, 0x0ee1, 0xd0c4, 0x01a8, 0x00d6, 0x78a8, 0x2009, 0x1975,
+	0x200a, 0x78ac, 0x2011, 0x1976, 0x2012, 0x2069, 0x0100, 0x6838,
+	0x9086, 0x0007, 0x1118, 0x2214, 0x6a5a, 0x0010, 0x210c, 0x695a,
+	0x00de, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0168, 0x2011,
+	0x0114, 0x220c, 0x7888, 0xd08c, 0x0118, 0x918d, 0x0080, 0x0010,
+	0x918c, 0xff7f, 0x2112, 0x0060, 0x2011, 0x0116, 0x220c, 0x7888,
+	0xd08c, 0x0118, 0x918d, 0x0040, 0x0010, 0x918c, 0xff7f, 0x2112,
+	0x603c, 0x7988, 0x613e, 0x6140, 0x910d, 0x788c, 0x6042, 0x7a88,
+	0x9294, 0x1000, 0x9205, 0x910e, 0xd1e4, 0x190c, 0x0ef7, 0x6040,
+	0xd0cc, 0x0120, 0x78b0, 0x2011, 0x0114, 0x2012, 0x012e, 0x0804,
+	0x34e8, 0x00f6, 0x2079, 0x1800, 0x7a38, 0xa898, 0x9084, 0xfebf,
+	0x9215, 0xa89c, 0x9084, 0xfebf, 0x8002, 0x9214, 0x7838, 0x9084,
+	0x0140, 0x9215, 0x7a3a, 0xa897, 0x4000, 0x900e, 0x9085, 0x0001,
+	0x2001, 0x0000, 0x00fe, 0x0005, 0x7898, 0x9005, 0x01a8, 0x7888,
+	0x9025, 0x0904, 0x351d, 0x788c, 0x902d, 0x0904, 0x351d, 0x900e,
+	0x080c, 0x649f, 0x1120, 0xba44, 0xbb38, 0xbc46, 0xbd3a, 0x9186,
+	0x07ff, 0x0190, 0x8108, 0x0ca0, 0x080c, 0x4af2, 0x0904, 0x351d,
+	0x7888, 0x900d, 0x0904, 0x351d, 0x788c, 0x9005, 0x0904, 0x351d,
+	0xba44, 0xb946, 0xbb38, 0xb83a, 0x0804, 0x34e8, 0x2011, 0xbc09,
+	0x0010, 0x2011, 0xbc05, 0x080c, 0x55ef, 0x1904, 0x351a, 0x00c6,
+	0x2061, 0x0100, 0x7984, 0x9186, 0x00ff, 0x1130, 0x2001, 0x1817,
+	0x2004, 0x9085, 0xff00, 0x0088, 0x9182, 0x007f, 0x16e0, 0x9188,
+	0x32e9, 0x210d, 0x918c, 0x00ff, 0x2001, 0x1817, 0x2004, 0x0026,
+	0x9116, 0x002e, 0x0580, 0x810f, 0x9105, 0x0126, 0x2091, 0x8000,
+	0x0006, 0x080c, 0xa08d, 0x000e, 0x0510, 0x602e, 0x620a, 0x7984,
+	0x00b6, 0x080c, 0x6445, 0x2b08, 0x00be, 0x1500, 0x6112, 0x6023,
+	0x0001, 0x080c, 0x4abf, 0x01d0, 0x9006, 0xa866, 0x7007, 0x0003,
+	0xa832, 0xa868, 0xc0fd, 0xa86a, 0x701f, 0x39e1, 0x2900, 0x6016,
+	0x2009, 0x0032, 0x080c, 0xa15d, 0x012e, 0x00ce, 0x0005, 0x012e,
+	0x00ce, 0x0804, 0x351a, 0x00ce, 0x0804, 0x351d, 0x080c, 0xa0e3,
+	0x0cb0, 0xa830, 0x9086, 0x0100, 0x0904, 0x351a, 0x0804, 0x34e8,
+	0x2061, 0x1a48, 0x0126, 0x2091, 0x8000, 0x6000, 0xd084, 0x0170,
+	0x6104, 0x6208, 0x2061, 0x1800, 0x6350, 0x6070, 0x789a, 0x60bc,
+	0x789e, 0x60b8, 0x78aa, 0x012e, 0x0804, 0x34e8, 0x900e, 0x2110,
+	0x0c88, 0x81ff, 0x1904, 0x351a, 0x080c, 0x7207, 0x0904, 0x351a,
+	0x0126, 0x2091, 0x8000, 0x6250, 0x6070, 0x9202, 0x0248, 0x9085,
+	0x0001, 0x080c, 0x27d7, 0x080c, 0x580e, 0x012e, 0x0804, 0x34e8,
+	0x012e, 0x0804, 0x351d, 0x0006, 0x0016, 0x00c6, 0x00e6, 0x2001,
+	0x1981, 0x2070, 0x2061, 0x185b, 0x6008, 0x2072, 0x900e, 0x2011,
+	0x1400, 0x080c, 0x84ff, 0x7206, 0x00ee, 0x00ce, 0x001e, 0x000e,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x81ff, 0x0128, 0x012e, 0x2021,
+	0x400b, 0x0804, 0x34ea, 0x7884, 0xd0fc, 0x0148, 0x2001, 0x002a,
+	0x2004, 0x9082, 0x00e1, 0x0288, 0x012e, 0x0804, 0x351d, 0x2001,
+	0x002a, 0x2004, 0x2069, 0x185b, 0x6908, 0x9102, 0x1230, 0x012e,
+	0x0804, 0x351d, 0x012e, 0x0804, 0x351a, 0x080c, 0xa062, 0x0dd0,
+	0x7884, 0xd0fc, 0x0904, 0x3aac, 0x00c6, 0x080c, 0x4abf, 0x00ce,
+	0x0d88, 0xa867, 0x0000, 0x7884, 0xa80a, 0x7898, 0xa80e, 0x789c,
+	0xa812, 0x2001, 0x002e, 0x2004, 0xa81a, 0x2001, 0x002f, 0x2004,
+	0xa81e, 0x2001, 0x0030, 0x2004, 0xa822, 0x2001, 0x0031, 0x2004,
+	0xa826, 0x2001, 0x0034, 0x2004, 0xa82a, 0x2001, 0x0035, 0x2004,
+	0xa82e, 0x2001, 0x002a, 0x2004, 0x9080, 0x0003, 0x9084, 0x00fc,
+	0x8004, 0xa816, 0x080c, 0x3c32, 0x0928, 0x7014, 0x2048, 0xad2c,
+	0xac28, 0xab1c, 0xaa18, 0xa930, 0xa808, 0xd0b4, 0x1120, 0x2029,
+	0x0000, 0x2021, 0x0000, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f,
+	0x9084, 0xffc0, 0x9080, 0x001b, 0x080c, 0x4b08, 0x701f, 0x3b6f,
+	0x7023, 0x0001, 0x012e, 0x0005, 0x0046, 0x0086, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x080c, 0x3a1b, 0x2001,
+	0x1977, 0x2003, 0x0000, 0x2021, 0x000a, 0x2061, 0x0100, 0x6104,
+	0x0016, 0x60bb, 0x0000, 0x60bf, 0x32e1, 0x60bf, 0x0012, 0x080c,
+	0x3ca1, 0x080c, 0x3c60, 0x00f6, 0x00e6, 0x0086, 0x2940, 0x2071,
+	0x1a3d, 0x2079, 0x0090, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4,
+	0x0140, 0x2001, 0x0035, 0x2004, 0x780e, 0x2001, 0x0034, 0x2004,
+	0x780a, 0x00de, 0x2011, 0x0001, 0x080c, 0x408d, 0x008e, 0x00ee,
+	0x00fe, 0x080c, 0x3fba, 0x080c, 0x3e7f, 0x05b8, 0x2001, 0x020b,
+	0x2004, 0x9084, 0x0140, 0x1db8, 0x080c, 0x4101, 0x00f6, 0x2079,
+	0x0300, 0x78bc, 0x00fe, 0x908c, 0x0070, 0x1560, 0x2071, 0x0200,
+	0x7037, 0x0000, 0x7050, 0x9084, 0xff00, 0x9086, 0x3200, 0x1510,
+	0x7037, 0x0001, 0x7050, 0x9084, 0xff00, 0x9086, 0xe100, 0x11d0,
+	0x7037, 0x0000, 0x7054, 0x7037, 0x0000, 0x715c, 0x9106, 0x1190,
+	0x2001, 0x181f, 0x2004, 0x9106, 0x1168, 0x00c6, 0x2061, 0x0100,
+	0x6024, 0x9084, 0x1e00, 0x00ce, 0x0138, 0x080c, 0x3e89, 0x080c,
+	0x3c5b, 0x0058, 0x080c, 0x3c5b, 0x080c, 0x4025, 0x080c, 0x3fb0,
+	0x2001, 0x020b, 0x2004, 0xd0e4, 0x0dd8, 0x2001, 0x032a, 0x2003,
+	0x0004, 0x2061, 0x0100, 0x6027, 0x0002, 0x001e, 0x6106, 0x2011,
+	0x020d, 0x2013, 0x0020, 0x60bb, 0x0000, 0x60bf, 0x0108, 0x60bf,
+	0x0012, 0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c,
+	0x12f8, 0x2009, 0x0028, 0x080c, 0x230a, 0x2001, 0x0227, 0x200c,
+	0x2102, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e,
+	0x008e, 0x004e, 0x2001, 0x1977, 0x2004, 0x9005, 0x1118, 0x012e,
+	0x0804, 0x34e8, 0x012e, 0x2021, 0x400c, 0x0804, 0x34ea, 0x0016,
+	0x0026, 0x0036, 0x0046, 0x0056, 0x0076, 0x0086, 0x0096, 0x00d6,
+	0x0156, 0x7014, 0x2048, 0x7020, 0x20a8, 0x8000, 0x7022, 0xa804,
+	0x9005, 0x0904, 0x3bcb, 0x2048, 0x1f04, 0x3b7f, 0x7068, 0x2040,
+	0xa28c, 0xa390, 0xa494, 0xa598, 0xa930, 0xa808, 0xd0b4, 0x1120,
+	0x2029, 0x0000, 0x2021, 0x0000, 0x0096, 0x7014, 0x2048, 0xa864,
+	0x009e, 0x9086, 0x0103, 0x0170, 0x8906, 0x8006, 0x8007, 0x90bc,
+	0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x080c, 0x4b08, 0x701f,
+	0x3b6f, 0x00b0, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x001b, 0x21a8, 0x27e0, 0x2098, 0x27e8, 0x20a0,
+	0x0006, 0x080c, 0x0fae, 0x000e, 0x080c, 0x4b0b, 0x701f, 0x3b6f,
+	0x015e, 0x00de, 0x009e, 0x008e, 0x007e, 0x005e, 0x004e, 0x003e,
+	0x002e, 0x001e, 0x0005, 0x7014, 0x2048, 0xa864, 0x9086, 0x0103,
+	0x1118, 0x701f, 0x3c30, 0x0450, 0x7014, 0x2048, 0xa868, 0xc0fd,
+	0xa86a, 0x2009, 0x007f, 0x080c, 0x643f, 0x0110, 0x9006, 0x0030,
+	0xb813, 0x00ff, 0xb817, 0xfffd, 0x080c, 0xc302, 0x015e, 0x00de,
+	0x009e, 0x008e, 0x007e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x0904, 0x351a, 0x0016, 0x0026, 0x0036, 0x0046, 0x0056, 0x0076,
+	0x0086, 0x0096, 0x00d6, 0x0156, 0x701f, 0x3c02, 0x7007, 0x0003,
+	0x0804, 0x3bc0, 0xa830, 0x9086, 0x0100, 0x2021, 0x400c, 0x0904,
+	0x34ea, 0x0076, 0xad10, 0xac0c, 0xab24, 0xaa20, 0xa930, 0xa808,
+	0xd0b4, 0x1120, 0x2029, 0x0000, 0x2021, 0x0000, 0x8906, 0x8006,
+	0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x001b, 0x21a8,
+	0x27e0, 0x2098, 0x27e8, 0x20a0, 0x0006, 0x080c, 0x0fae, 0x000e,
+	0x080c, 0x4b0b, 0x007e, 0x701f, 0x3b6f, 0x7023, 0x0001, 0x0005,
+	0x0804, 0x34e8, 0x0156, 0x00c6, 0xa814, 0x908a, 0x001e, 0x0218,
+	0xa833, 0x001e, 0x0010, 0xa832, 0x0078, 0x81ff, 0x0168, 0x0016,
+	0x080c, 0x4abf, 0x001e, 0x0130, 0xa800, 0x2040, 0xa008, 0xa80a,
+	0x2100, 0x0c58, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ce, 0x015e,
+	0x0005, 0x0006, 0x00f6, 0x2079, 0x0000, 0x7880, 0x9086, 0x0044,
+	0x00fe, 0x000e, 0x0005, 0x2001, 0x1977, 0x2003, 0x0001, 0x0005,
+	0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x2001, 0x1982, 0x2004,
+	0x601a, 0x2061, 0x0100, 0x2001, 0x1981, 0x2004, 0x60ce, 0x6104,
+	0xc1ac, 0x6106, 0x080c, 0x4abf, 0xa813, 0x0019, 0xa817, 0x0001,
+	0x2900, 0xa85a, 0x2001, 0x002e, 0x2004, 0xa866, 0x2001, 0x002f,
+	0x2004, 0xa86a, 0x2061, 0x0090, 0x2079, 0x0100, 0x2001, 0x1981,
+	0x2004, 0x6036, 0x2009, 0x0040, 0x080c, 0x230a, 0x2001, 0x002a,
+	0x2004, 0x9084, 0xfff8, 0xa86e, 0x601a, 0xa873, 0x0000, 0x601f,
+	0x0000, 0x78ca, 0x9006, 0x600a, 0x600e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0x00e6, 0x080c, 0x4abf, 0x2940, 0xa013, 0x0019, 0xa017,
+	0x0001, 0x2800, 0xa05a, 0x2001, 0x0030, 0x2004, 0xa866, 0x2001,
+	0x0031, 0x2004, 0xa86a, 0x2001, 0x002a, 0x2004, 0x9084, 0xfff8,
+	0xa86e, 0xa873, 0x0000, 0x2001, 0x032a, 0x2003, 0x0004, 0x2001,
+	0x0300, 0x2003, 0x0000, 0x2001, 0x020d, 0x2003, 0x0000, 0x2001,
+	0x0004, 0x200c, 0x918d, 0x0002, 0x2102, 0x00ee, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x81ff, 0x0148, 0x080c, 0x2ba8, 0x1130, 0x9006,
+	0x080c, 0x2ab8, 0x9006, 0x080c, 0x2a9b, 0x7884, 0x9084, 0x0007,
+	0x0002, 0x3cec, 0x3cfb, 0x3d0a, 0x3ce9, 0x3ce9, 0x3ce9, 0x3ce9,
+	0x3ce9, 0x012e, 0x0804, 0x351d, 0x2001, 0x0100, 0x2004, 0x9086,
+	0x000a, 0x0db8, 0x2009, 0x0114, 0x2104, 0x9085, 0x0800, 0x200a,
+	0x080c, 0x3ed3, 0x00f0, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x0d40, 0x2009, 0x0114, 0x2104, 0x9085, 0x4000, 0x200a, 0x080c,
+	0x3ed3, 0x0078, 0x080c, 0x7207, 0x1128, 0x012e, 0x2009, 0x0016,
+	0x0804, 0x351a, 0x81ff, 0x0128, 0x012e, 0x2021, 0x400b, 0x0804,
+	0x34ea, 0x0086, 0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, 0x00e6,
+	0x00f6, 0x080c, 0x3a1b, 0x2009, 0x0101, 0x210c, 0x0016, 0x7ec8,
+	0x7dcc, 0x9006, 0x2068, 0x2060, 0x2058, 0x080c, 0x41dc, 0x080c,
+	0x412c, 0x903e, 0x2720, 0x00f6, 0x00e6, 0x0086, 0x2940, 0x2071,
+	0x1a3d, 0x2079, 0x0090, 0x00d6, 0x2069, 0x0000, 0x6884, 0xd0b4,
+	0x0120, 0x68d4, 0x780e, 0x68d0, 0x780a, 0x00de, 0x2011, 0x0001,
+	0x080c, 0x408d, 0x080c, 0x2bb0, 0x080c, 0x2bb0, 0x080c, 0x2bb0,
+	0x080c, 0x2bb0, 0x080c, 0x408d, 0x008e, 0x00ee, 0x00fe, 0x080c,
+	0x3fba, 0x2009, 0x9c40, 0x8109, 0x11b0, 0x080c, 0x3e89, 0x2001,
+	0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x001e, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x2009, 0x0017,
+	0x080c, 0x351a, 0x0cf8, 0x2001, 0x020b, 0x2004, 0x9084, 0x0140,
+	0x1d10, 0x00f6, 0x2079, 0x0000, 0x7884, 0x00fe, 0xd0bc, 0x0178,
+	0x2001, 0x0201, 0x200c, 0x81ff, 0x0150, 0x080c, 0x3f98, 0x2d00,
+	0x9c05, 0x9b05, 0x0120, 0x080c, 0x3e89, 0x0804, 0x3e29, 0x080c,
+	0x4101, 0x080c, 0x4025, 0x080c, 0x3f7b, 0x080c, 0x3fb0, 0x00f6,
+	0x2079, 0x0100, 0x7824, 0xd0ac, 0x0130, 0x8b58, 0x080c, 0x3e89,
+	0x00fe, 0x0804, 0x3e29, 0x00fe, 0x080c, 0x3e7f, 0x1150, 0x8d68,
+	0x2001, 0x0032, 0x2602, 0x2001, 0x0033, 0x2502, 0x080c, 0x3e89,
+	0x0080, 0x87ff, 0x0138, 0x2001, 0x0201, 0x2004, 0x9005, 0x1908,
+	0x8739, 0x0038, 0x2001, 0x1a3a, 0x2004, 0x9086, 0x0000, 0x1904,
+	0x3d79, 0x2001, 0x032f, 0x2003, 0x00f6, 0x8631, 0x1208, 0x8529,
+	0x2500, 0x9605, 0x0904, 0x3e29, 0x7884, 0xd0bc, 0x0128, 0x2d00,
+	0x9c05, 0x9b05, 0x1904, 0x3e29, 0xa013, 0x0019, 0x2001, 0x032a,
+	0x2003, 0x0004, 0x7884, 0xd0ac, 0x1148, 0x2001, 0x1a3a, 0x2003,
+	0x0003, 0x2001, 0x032a, 0x2003, 0x0009, 0x0030, 0xa017, 0x0001,
+	0x78b4, 0x9005, 0x0108, 0xa016, 0x2800, 0xa05a, 0x2009, 0x0040,
+	0x080c, 0x230a, 0x2900, 0xa85a, 0xa813, 0x0019, 0x7884, 0xd0a4,
+	0x1180, 0xa817, 0x0000, 0x00c6, 0x20a9, 0x0004, 0x2061, 0x0090,
+	0x602b, 0x0008, 0x2001, 0x0203, 0x2004, 0x1f04, 0x3e00, 0x00ce,
+	0x0030, 0xa817, 0x0001, 0x78b0, 0x9005, 0x0108, 0xa816, 0x00f6,
+	0x00c6, 0x2079, 0x0100, 0x2061, 0x0090, 0x7827, 0x0002, 0x2001,
+	0x002a, 0x2004, 0x9084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x002b,
+	0x2004, 0x601e, 0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804,
+	0x3d33, 0x001e, 0x00c6, 0x2001, 0x032a, 0x2003, 0x0004, 0x2061,
+	0x0100, 0x6027, 0x0002, 0x6106, 0x2011, 0x020d, 0x2013, 0x0020,
+	0x2001, 0x0004, 0x200c, 0x918c, 0xfffd, 0x2102, 0x080c, 0x12f8,
+	0x7884, 0x9084, 0x0003, 0x9086, 0x0002, 0x0508, 0x2009, 0x0028,
+	0x080c, 0x230a, 0x2001, 0x0227, 0x200c, 0x2102, 0x6050, 0x0006,
+	0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x000e, 0x0118, 0x9084,
+	0xb7ef, 0x0020, 0x9084, 0xb7ff, 0x080c, 0x2cf5, 0x6052, 0x602f,
+	0x0000, 0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x00ce,
+	0x2d08, 0x2c10, 0x2b18, 0x2b00, 0x9c05, 0x9d05, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e,
+	0x0804, 0x34e8, 0x012e, 0x2021, 0x400c, 0x0804, 0x34ea, 0x9085,
+	0x0001, 0x1d04, 0x3e88, 0x2091, 0x6000, 0x8420, 0x9486, 0x0064,
+	0x0005, 0x2001, 0x0105, 0x2003, 0x0010, 0x2001, 0x032a, 0x2003,
+	0x0004, 0x2001, 0x1a3a, 0x2003, 0x0000, 0x0071, 0x2009, 0x0048,
+	0x080c, 0x230a, 0x2001, 0x0227, 0x2024, 0x2402, 0x2001, 0x0109,
+	0x2003, 0x4000, 0x9026, 0x0005, 0x00f6, 0x00e6, 0x2071, 0x1a3d,
+	0x7000, 0x9086, 0x0000, 0x0520, 0x2079, 0x0090, 0x2009, 0x0206,
+	0x2104, 0x2009, 0x0203, 0x210c, 0x9106, 0x1120, 0x2009, 0x0040,
+	0x080c, 0x230a, 0x782c, 0xd0fc, 0x0d88, 0x080c, 0x4101, 0x7000,
+	0x9086, 0x0000, 0x1d58, 0x782b, 0x0004, 0x782c, 0xd0ac, 0x1de8,
+	0x2009, 0x0040, 0x080c, 0x230a, 0x782b, 0x0002, 0x7003, 0x0000,
+	0x00ee, 0x00fe, 0x0005, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x15d0, 0x00f6, 0x2079, 0x0100, 0x2001, 0x1817, 0x200c, 0x7932,
+	0x7936, 0x080c, 0x27b7, 0x080c, 0x2cc2, 0x080c, 0x2cf5, 0x784b,
+	0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, 0x7850, 0xc0e5, 0x7852,
+	0x2019, 0x61a8, 0x7820, 0xd09c, 0x0110, 0x8319, 0x1dd8, 0x7850,
+	0xc0e4, 0x7852, 0x7827, 0x0048, 0x7843, 0x0040, 0x2019, 0x01f4,
+	0xa001, 0xa001, 0x8319, 0x1de0, 0x2001, 0x0100, 0x080c, 0x2c88,
+	0x7827, 0x0020, 0x7843, 0x0000, 0x9006, 0x080c, 0x2c88, 0x7827,
+	0x0048, 0x00fe, 0x0005, 0x00f6, 0x2079, 0x0100, 0x2001, 0x1817,
+	0x200c, 0x7932, 0x7936, 0x080c, 0x27b7, 0x7850, 0x9084, 0xfbff,
+	0x9085, 0x0030, 0x7852, 0x2019, 0x01f4, 0x8319, 0x1df0, 0x9084,
+	0xffcf, 0x9085, 0x2000, 0x7852, 0x20a9, 0x0046, 0x1d04, 0x3f2e,
+	0x2091, 0x6000, 0x1f04, 0x3f2e, 0x7850, 0x9085, 0x0400, 0x9084,
+	0xdfff, 0x7852, 0x2001, 0x0021, 0x2004, 0x9084, 0x0003, 0x9086,
+	0x0001, 0x1120, 0x7850, 0x9084, 0xdfff, 0x7852, 0x784b, 0xf7f7,
+	0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x0028, 0xa001, 0x1f04,
+	0x3f4e, 0x7850, 0x9085, 0x1400, 0x7852, 0x2019, 0x61a8, 0x7854,
+	0xa001, 0xa001, 0xd08c, 0x1110, 0x8319, 0x1dc8, 0x7827, 0x0048,
+	0x7850, 0x9085, 0x0400, 0x7852, 0x7843, 0x0040, 0x2019, 0x01f4,
+	0xa001, 0xa001, 0x8319, 0x1de0, 0x2001, 0x0100, 0x080c, 0x2c88,
+	0x7827, 0x0020, 0x7843, 0x0000, 0x9006, 0x080c, 0x2c88, 0x7827,
+	0x0048, 0x00fe, 0x0005, 0x7884, 0xd0ac, 0x11c8, 0x00f6, 0x00e6,
+	0x2071, 0x1a3a, 0x2079, 0x0320, 0x2001, 0x0201, 0x2004, 0x9005,
+	0x0160, 0x7000, 0x9086, 0x0000, 0x1140, 0x0051, 0xd0bc, 0x0108,
+	0x8738, 0x7003, 0x0003, 0x782b, 0x0019, 0x00ee, 0x00fe, 0x0005,
+	0x00f6, 0x2079, 0x0300, 0x78bc, 0x00fe, 0x908c, 0x0070, 0x0178,
+	0x2009, 0x0032, 0x260a, 0x2009, 0x0033, 0x250a, 0xd0b4, 0x0108,
+	0x8c60, 0xd0ac, 0x0108, 0x8d68, 0xd0a4, 0x0108, 0x8b58, 0x0005,
+	0x00f6, 0x2079, 0x0200, 0x781c, 0xd084, 0x0110, 0x7837, 0x0050,
+	0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100, 0x2001, 0x1982, 0x2004,
+	0x70e2, 0x080c, 0x3c51, 0x1188, 0x2001, 0x181f, 0x2004, 0x2009,
+	0x181e, 0x210c, 0x918c, 0x00ff, 0x706e, 0x716a, 0x7066, 0x918d,
+	0x3200, 0x7162, 0x7073, 0xe109, 0x0080, 0x702c, 0x9085, 0x0002,
+	0x702e, 0x2009, 0x1817, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166,
+	0x719e, 0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078,
+	0x9080, 0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa,
+	0x9006, 0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af,
+	0x95d5, 0x7014, 0x9084, 0x1984, 0x9085, 0x0092, 0x7016, 0x080c,
+	0x4101, 0x00f6, 0x2071, 0x1a3a, 0x2079, 0x0320, 0x00d6, 0x2069,
+	0x0000, 0x6884, 0xd0b4, 0x0120, 0x689c, 0x780e, 0x6898, 0x780a,
+	0x00de, 0x2009, 0x03e8, 0x8109, 0x1df0, 0x792c, 0xd1fc, 0x0110,
+	0x782b, 0x0004, 0x2011, 0x0011, 0x080c, 0x408d, 0x2011, 0x0001,
+	0x080c, 0x408d, 0x00fe, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071,
+	0x1a3a, 0x2079, 0x0320, 0x792c, 0xd1fc, 0x0904, 0x408a, 0x782b,
+	0x0002, 0x9026, 0xd19c, 0x1904, 0x4086, 0x7000, 0x0002, 0x408a,
+	0x403b, 0x406b, 0x4086, 0xd1bc, 0x1170, 0xd1dc, 0x1190, 0x8001,
+	0x7002, 0x2011, 0x0001, 0x080c, 0x408d, 0x0904, 0x408a, 0x080c,
+	0x408d, 0x0804, 0x408a, 0x00f6, 0x2079, 0x0300, 0x78bf, 0x0000,
+	0x00fe, 0x7810, 0x7914, 0x782b, 0x0004, 0x7812, 0x7916, 0x2001,
+	0x0201, 0x200c, 0x81ff, 0x0de8, 0x080c, 0x3f98, 0x2009, 0x0001,
+	0x00f6, 0x2079, 0x0300, 0x78b8, 0x00fe, 0xd0ec, 0x0110, 0x2009,
+	0x0011, 0x792a, 0x00f8, 0x8001, 0x7002, 0x9184, 0x0880, 0x1140,
+	0x782c, 0xd0fc, 0x1904, 0x402f, 0x2011, 0x0001, 0x00b1, 0x0090,
+	0xa010, 0x9092, 0x0004, 0x9086, 0x0015, 0x1120, 0xa000, 0xa05a,
+	0x2011, 0x0031, 0xa212, 0xd1dc, 0x1960, 0x0828, 0x782b, 0x0004,
+	0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0xa014, 0x9005, 0x0550,
+	0x8001, 0x0036, 0x0096, 0xa016, 0xa058, 0x2048, 0xa010, 0x2009,
+	0x0031, 0x911a, 0x831c, 0x831c, 0x938a, 0x0007, 0x1a0c, 0x0dfa,
+	0x9398, 0x40bb, 0x231d, 0x083f, 0x9080, 0x0004, 0x7a2a, 0x7100,
+	0x8108, 0x7102, 0x009e, 0x003e, 0x908a, 0x0035, 0x1140, 0x0096,
+	0xa058, 0x2048, 0xa804, 0xa05a, 0x2001, 0x0019, 0x009e, 0xa012,
+	0x9085, 0x0001, 0x0005, 0x40f8, 0x40ef, 0x40e6, 0x40dd, 0x40d4,
+	0x40cb, 0x40c2, 0xa964, 0x7902, 0xa968, 0x7906, 0xa96c, 0x7912,
+	0xa970, 0x7916, 0x0005, 0xa974, 0x7902, 0xa978, 0x7906, 0xa97c,
+	0x7912, 0xa980, 0x7916, 0x0005, 0xa984, 0x7902, 0xa988, 0x7906,
+	0xa98c, 0x7912, 0xa990, 0x7916, 0x0005, 0xa994, 0x7902, 0xa998,
+	0x7906, 0xa99c, 0x7912, 0xa9a0, 0x7916, 0x0005, 0xa9a4, 0x7902,
+	0xa9a8, 0x7906, 0xa9ac, 0x7912, 0xa9b0, 0x7916, 0x0005, 0xa9b4,
+	0x7902, 0xa9b8, 0x7906, 0xa9bc, 0x7912, 0xa9c0, 0x7916, 0x0005,
+	0xa9c4, 0x7902, 0xa9c8, 0x7906, 0xa9cc, 0x7912, 0xa9d0, 0x7916,
+	0x0005, 0x00f6, 0x00e6, 0x0086, 0x2071, 0x1a3d, 0x2079, 0x0090,
+	0x792c, 0xd1fc, 0x01e8, 0x782b, 0x0002, 0x2940, 0x9026, 0x7000,
+	0x0002, 0x4128, 0x4114, 0x411f, 0x8001, 0x7002, 0xd19c, 0x1180,
+	0x2011, 0x0001, 0x080c, 0x408d, 0x190c, 0x408d, 0x0048, 0x8001,
+	0x7002, 0x782c, 0xd0fc, 0x1d38, 0x2011, 0x0001, 0x080c, 0x408d,
+	0x008e, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0086,
+	0x2061, 0x0200, 0x2001, 0x1982, 0x2004, 0x601a, 0x2061, 0x0100,
+	0x2001, 0x1981, 0x2004, 0x60ce, 0x6104, 0xc1ac, 0x6106, 0x2001,
+	0x002c, 0x2004, 0x9005, 0x0520, 0x2038, 0x2001, 0x002e, 0x2024,
+	0x2001, 0x002f, 0x201c, 0x080c, 0x4abf, 0xa813, 0x0019, 0xaf16,
+	0x2900, 0xa85a, 0x978a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007,
+	0x0010, 0x2708, 0x903e, 0x0096, 0xa858, 0x2048, 0xa85c, 0x9080,
+	0x0019, 0x009e, 0x080c, 0x41a4, 0x1d68, 0x2900, 0xa85a, 0x00d0,
+	0x080c, 0x4abf, 0xa813, 0x0019, 0xa817, 0x0001, 0x2900, 0xa85a,
+	0x2001, 0x002e, 0x2004, 0xa866, 0x2001, 0x002f, 0x2004, 0xa86a,
+	0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0xa86e, 0x2001, 0x002b,
+	0x2004, 0xa872, 0x2061, 0x0090, 0x2079, 0x0100, 0x2001, 0x1981,
+	0x2004, 0x6036, 0x2009, 0x0040, 0x080c, 0x230a, 0x2001, 0x002a,
+	0x2004, 0x9084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x002b, 0x2004,
+	0x601e, 0x78c6, 0x000e, 0x78ca, 0x9006, 0x600a, 0x600e, 0x008e,
+	0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0080, 0xaa60,
+	0x22e8, 0x20a0, 0x20e1, 0x0000, 0x2099, 0x0088, 0x702b, 0x0026,
+	0x7402, 0x7306, 0x9006, 0x700a, 0x700e, 0x810b, 0x810b, 0x21a8,
+	0x810b, 0x7112, 0x702b, 0x0041, 0x702c, 0xd0fc, 0x0de8, 0x702b,
+	0x0002, 0x702b, 0x0040, 0x4005, 0x7400, 0x7304, 0x87ff, 0x0190,
+	0x0086, 0x0096, 0x2940, 0x0086, 0x080c, 0x4abf, 0x008e, 0xa058,
+	0x00a6, 0x2050, 0x2900, 0xb006, 0xa05a, 0x00ae, 0x009e, 0x008e,
+	0x9085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x2001, 0x002d, 0x2004,
+	0x9005, 0x0528, 0x2038, 0x2001, 0x0030, 0x2024, 0x2001, 0x0031,
+	0x201c, 0x080c, 0x4abf, 0x2940, 0xa813, 0x0019, 0xaf16, 0x2900,
+	0xa85a, 0x978a, 0x0007, 0x0220, 0x2138, 0x2009, 0x0007, 0x0010,
+	0x2708, 0x903e, 0x0096, 0xa858, 0x2048, 0xa85c, 0x9080, 0x0019,
+	0x009e, 0x080c, 0x41a4, 0x1d68, 0x2900, 0xa85a, 0x00d8, 0x080c,
+	0x4abf, 0x2940, 0xa013, 0x0019, 0xa017, 0x0001, 0x2800, 0xa05a,
+	0x2001, 0x0030, 0x2004, 0xa066, 0x2001, 0x0031, 0x2004, 0xa06a,
+	0x2001, 0x002a, 0x2004, 0x9084, 0xfff8, 0xa06e, 0x2001, 0x002b,
+	0x2004, 0xa072, 0x2001, 0x032a, 0x2003, 0x0004, 0x7884, 0xd0ac,
+	0x1180, 0x2001, 0x0101, 0x200c, 0x918d, 0x0200, 0x2102, 0xa017,
+	0x0000, 0x2001, 0x1a3a, 0x2003, 0x0003, 0x2001, 0x032a, 0x2003,
+	0x0009, 0x2001, 0x0300, 0x2003, 0x0000, 0x2001, 0x020d, 0x2003,
+	0x0000, 0x2001, 0x0004, 0x200c, 0x918d, 0x0002, 0x2102, 0x00ee,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x20a9, 0x001b, 0x20a1, 0x1840,
+	0x20e9, 0x0001, 0x9006, 0x4004, 0x2009, 0x013c, 0x200a, 0x012e,
+	0x7880, 0x9086, 0x0052, 0x0108, 0x0005, 0x0804, 0x34e8, 0x7d98,
+	0x7c9c, 0x0804, 0x35ea, 0x080c, 0x7207, 0x190c, 0x5ef0, 0x2069,
+	0x185b, 0x2d00, 0x2009, 0x0030, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98,
+	0x2039, 0x0001, 0x080c, 0x4b08, 0x701f, 0x4277, 0x0005, 0x080c,
+	0x55ea, 0x1130, 0x3b00, 0x3a08, 0xc194, 0xc095, 0x20d8, 0x21d0,
+	0x2069, 0x185b, 0x6800, 0x9005, 0x0904, 0x351d, 0x6804, 0xd094,
+	0x00c6, 0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0x9292, 0x0005,
+	0x0218, 0x918c, 0xffdf, 0x0010, 0x918d, 0x0020, 0x6106, 0x00ce,
+	0xd08c, 0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0x918d, 0x0010,
+	0x0010, 0x918c, 0xffef, 0x6106, 0x00ce, 0xd084, 0x0158, 0x6a28,
+	0x928a, 0x007f, 0x1a04, 0x351d, 0x9288, 0x32e9, 0x210d, 0x918c,
+	0x00ff, 0x6162, 0xd0dc, 0x0130, 0x6828, 0x908a, 0x007f, 0x1a04,
+	0x351d, 0x605a, 0x6888, 0x9084, 0x0030, 0x8004, 0x8004, 0x8004,
+	0x8004, 0x0006, 0x2009, 0x1989, 0x9080, 0x28aa, 0x2005, 0x200a,
+	0x000e, 0x2009, 0x198a, 0x9080, 0x28ae, 0x2005, 0x200a, 0x6808,
+	0x908a, 0x0100, 0x0a04, 0x351d, 0x908a, 0x0841, 0x1a04, 0x351d,
+	0x9084, 0x0007, 0x1904, 0x351d, 0x680c, 0x9005, 0x0904, 0x351d,
+	0x6810, 0x9005, 0x0904, 0x351d, 0x6848, 0x6940, 0x910a, 0x1a04,
+	0x351d, 0x8001, 0x0904, 0x351d, 0x684c, 0x6944, 0x910a, 0x1a04,
+	0x351d, 0x8001, 0x0904, 0x351d, 0x2009, 0x1959, 0x200b, 0x0000,
+	0x2001, 0x187d, 0x2004, 0xd0c4, 0x0140, 0x7884, 0x200a, 0x2009,
+	0x017f, 0x200a, 0x3b00, 0xc085, 0x20d8, 0x6814, 0x908c, 0x00ff,
+	0x614a, 0x8007, 0x9084, 0x00ff, 0x604e, 0x080c, 0x7535, 0x080c,
+	0x688c, 0x080c, 0x68c1, 0x6808, 0x602a, 0x080c, 0x227c, 0x2009,
+	0x0170, 0x200b, 0x0080, 0xa001, 0xa001, 0x200b, 0x0000, 0x0036,
+	0x6b08, 0x080c, 0x2811, 0x003e, 0x6000, 0x9086, 0x0000, 0x1904,
+	0x43f8, 0x6818, 0x691c, 0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217,
+	0x831f, 0x6016, 0x611a, 0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148,
+	0x6830, 0x6934, 0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f,
+	0x0010, 0x9084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x8007,
+	0x810f, 0x8217, 0x831f, 0x20a9, 0x0004, 0x20a1, 0x198b, 0x20e9,
+	0x0001, 0x4001, 0x20a9, 0x0004, 0x20a1, 0x19a5, 0x20e9, 0x0001,
+	0x4001, 0x080c, 0x83e3, 0x00c6, 0x900e, 0x20a9, 0x0001, 0x6b70,
+	0xd384, 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c,
+	0x7af8, 0x6878, 0x6016, 0x6874, 0x2008, 0x9084, 0xff00, 0x8007,
+	0x600a, 0x9184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003,
+	0x0010, 0x6003, 0x0001, 0x1f04, 0x4363, 0x00ce, 0x00c6, 0x2061,
+	0x1974, 0x2063, 0x0001, 0x9006, 0x080c, 0x2ab8, 0x9006, 0x080c,
+	0x2a9b, 0x0000, 0x00ce, 0x00e6, 0x2c70, 0x080c, 0x0ec6, 0x00ee,
+	0x6888, 0xd0ec, 0x0198, 0x2001, 0x0100, 0x2004, 0x9086, 0x000a,
+	0x0138, 0x2011, 0x0114, 0x2204, 0x9085, 0x0100, 0x2012, 0x0030,
+	0x2011, 0x0114, 0x2204, 0x9085, 0x0180, 0x2012, 0x6a80, 0x9284,
+	0x0030, 0x9086, 0x0030, 0x1128, 0x9294, 0xffcf, 0x9295, 0x0020,
+	0x6a82, 0x2001, 0x1954, 0x6a80, 0x9294, 0x0030, 0x928e, 0x0000,
+	0x0170, 0x928e, 0x0010, 0x0118, 0x928e, 0x0020, 0x0140, 0x2003,
+	0xaaaa, 0x080c, 0x2886, 0x2001, 0x1945, 0x2102, 0x0008, 0x2102,
+	0x00c6, 0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce,
+	0x080c, 0x7207, 0x0128, 0x080c, 0x4ed2, 0x0110, 0x080c, 0x27d7,
+	0x60d0, 0x9005, 0x01c0, 0x6003, 0x0001, 0x2009, 0x43e0, 0x00d0,
+	0x080c, 0x7207, 0x1168, 0x2011, 0x7076, 0x080c, 0x82da, 0x2011,
+	0x7069, 0x080c, 0x83ae, 0x080c, 0x7509, 0x080c, 0x7127, 0x0040,
+	0x080c, 0x5dea, 0x0028, 0x6003, 0x0004, 0x2009, 0x43f8, 0x0010,
+	0x0804, 0x34e8, 0x2001, 0x0170, 0x2004, 0x9084, 0x00ff, 0x9086,
+	0x004c, 0x1118, 0x2091, 0x30bd, 0x0817, 0x2091, 0x303d, 0x0817,
+	0x6000, 0x9086, 0x0000, 0x0904, 0x351a, 0x2069, 0x185b, 0x7890,
+	0x6842, 0x7894, 0x6846, 0x2d00, 0x2009, 0x0030, 0x7a8c, 0x7b88,
+	0x7c9c, 0x7d98, 0x2039, 0x0001, 0x0804, 0x4b0b, 0x9006, 0x080c,
+	0x27d7, 0x81ff, 0x1904, 0x351a, 0x080c, 0x7207, 0x11b0, 0x080c,
+	0x7504, 0x080c, 0x5f2b, 0x080c, 0x32e4, 0x0118, 0x6130, 0xc18d,
+	0x6132, 0x080c, 0xc539, 0x0130, 0x080c, 0x722a, 0x1118, 0x080c,
+	0x71df, 0x0038, 0x080c, 0x7127, 0x0020, 0x080c, 0x5ef0, 0x080c,
+	0x5dea, 0x0804, 0x34e8, 0x81ff, 0x1904, 0x351a, 0x080c, 0x7207,
+	0x1110, 0x0804, 0x351a, 0x6190, 0x81ff, 0x01a8, 0x704f, 0x0000,
+	0x2001, 0x1c80, 0x2009, 0x0040, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98,
+	0x0126, 0x2091, 0x8000, 0x2039, 0x0001, 0x080c, 0x4b0b, 0x701f,
+	0x34e6, 0x012e, 0x0005, 0x704f, 0x0001, 0x00d6, 0x2069, 0x1c80,
+	0x20a9, 0x0040, 0x20e9, 0x0001, 0x20a1, 0x1c80, 0x2019, 0xffff,
+	0x4304, 0x6558, 0x9588, 0x32e9, 0x210d, 0x918c, 0x00ff, 0x216a,
+	0x900e, 0x2011, 0x0002, 0x2100, 0x9506, 0x01a8, 0x080c, 0x649f,
+	0x1190, 0xb814, 0x821c, 0x0238, 0x9398, 0x1c80, 0x9085, 0xff00,
+	0x8007, 0x201a, 0x0038, 0x9398, 0x1c80, 0x2324, 0x94a4, 0xff00,
+	0x9405, 0x201a, 0x8210, 0x8108, 0x9182, 0x0080, 0x1208, 0x0c18,
+	0x8201, 0x8007, 0x2d0c, 0x9105, 0x206a, 0x00de, 0x20a9, 0x0040,
+	0x20a1, 0x1c80, 0x2099, 0x1c80, 0x080c, 0x5e7b, 0x0804, 0x4450,
+	0x080c, 0x4af2, 0x0904, 0x351d, 0x080c, 0x4abf, 0x1120, 0x2009,
+	0x0002, 0x0804, 0x351a, 0x080c, 0x55db, 0xd0b4, 0x0558, 0x7884,
+	0x908e, 0x007e, 0x0538, 0x908e, 0x007f, 0x0520, 0x908e, 0x0080,
+	0x0508, 0x080c, 0x32df, 0x1148, 0xb800, 0xd08c, 0x11d8, 0xb804,
+	0x9084, 0x00ff, 0x9086, 0x0006, 0x11a8, 0xa867, 0x0000, 0xa868,
+	0xc0fd, 0xa86a, 0x080c, 0xc002, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x351a, 0x7007, 0x0003, 0x701f, 0x44de, 0x0005, 0x080c, 0x4af2,
+	0x0904, 0x351d, 0x20a9, 0x002b, 0xb8b4, 0x20e0, 0xb8b8, 0x2098,
+	0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x20a9,
+	0x0008, 0x9080, 0x0006, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080,
+	0x0006, 0x2098, 0x080c, 0x0fae, 0x0070, 0x20a9, 0x0004, 0xa85c,
+	0x9080, 0x000a, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x000a,
+	0x2098, 0x080c, 0x0fae, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f,
+	0x9084, 0xffc0, 0x9080, 0x0002, 0x2009, 0x002b, 0x7a8c, 0x7b88,
+	0x7c9c, 0x7d98, 0x0804, 0x4b0b, 0x81ff, 0x1904, 0x351a, 0x080c,
+	0x4ad6, 0x0904, 0x351d, 0x080c, 0x6611, 0x0904, 0x351a, 0x0058,
+	0xa878, 0x9005, 0x0120, 0x2009, 0x0004, 0x0804, 0x351a, 0xa974,
+	0xaa94, 0x0804, 0x34e8, 0x080c, 0x55e3, 0x0904, 0x34e8, 0x701f,
+	0x4528, 0x7007, 0x0003, 0x0005, 0x81ff, 0x1904, 0x351a, 0x7888,
+	0x908a, 0x1000, 0x1a04, 0x351d, 0x080c, 0x4af2, 0x0904, 0x351d,
+	0x080c, 0x67c3, 0x0120, 0x080c, 0x67cb, 0x1904, 0x351d, 0x080c,
+	0x6696, 0x0904, 0x351a, 0x2019, 0x0004, 0x900e, 0x080c, 0x6623,
+	0x0904, 0x351a, 0x7984, 0x7a88, 0x04c9, 0x08a8, 0xa89c, 0x908a,
+	0x1000, 0x12f8, 0x080c, 0x4af0, 0x01e0, 0x080c, 0x67c3, 0x0118,
+	0x080c, 0x67cb, 0x11b0, 0x080c, 0x6696, 0x2009, 0x0002, 0x0168,
+	0x2009, 0x0002, 0x2019, 0x0004, 0x080c, 0x6623, 0x2009, 0x0003,
+	0x0120, 0xa998, 0xaa9c, 0x00d1, 0x0060, 0xa897, 0x4005, 0xa99a,
+	0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030,
+	0x0005, 0xa897, 0x4000, 0x080c, 0x55e3, 0x0110, 0x9006, 0x0018,
+	0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x9186, 0x00ff,
+	0x0110, 0x0071, 0x0060, 0x2029, 0x007e, 0x2061, 0x1800, 0x6458,
+	0x2400, 0x9506, 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005,
+	0x080c, 0x649f, 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0x9108,
+	0x080c, 0x82e8, 0x0005, 0x81ff, 0x1904, 0x351a, 0x798c, 0x2001,
+	0x1958, 0x918c, 0x8000, 0x2102, 0x080c, 0x4ad6, 0x0904, 0x351d,
+	0x080c, 0x67c3, 0x0120, 0x080c, 0x67cb, 0x1904, 0x351d, 0x080c,
+	0x6566, 0x0904, 0x351a, 0x080c, 0x661a, 0x0904, 0x351a, 0x2001,
+	0x1958, 0x2004, 0xd0fc, 0x1904, 0x34e8, 0x0804, 0x4533, 0xa9a0,
+	0x2001, 0x1958, 0x918c, 0x8000, 0xc18d, 0x2102, 0x080c, 0x4ae3,
+	0x01a0, 0x080c, 0x67c3, 0x0118, 0x080c, 0x67cb, 0x1170, 0x080c,
+	0x6566, 0x2009, 0x0002, 0x0128, 0x080c, 0x661a, 0x1170, 0x2009,
+	0x0003, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x2001,
+	0x1958, 0x2004, 0xd0fc, 0x1128, 0x080c, 0x55e3, 0x0110, 0x9006,
+	0x0018, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x81ff,
+	0x1904, 0x351a, 0x798c, 0x2001, 0x1957, 0x918c, 0x8000, 0x2102,
+	0x080c, 0x4ad6, 0x0904, 0x351d, 0x080c, 0x67c3, 0x0120, 0x080c,
+	0x67cb, 0x1904, 0x351d, 0x080c, 0x6566, 0x0904, 0x351a, 0x080c,
+	0x6608, 0x0904, 0x351a, 0x2001, 0x1957, 0x2004, 0xd0fc, 0x1904,
+	0x34e8, 0x0804, 0x4533, 0xa9a0, 0x2001, 0x1957, 0x918c, 0x8000,
+	0xc18d, 0x2102, 0x080c, 0x4ae3, 0x01a0, 0x080c, 0x67c3, 0x0118,
+	0x080c, 0x67cb, 0x1170, 0x080c, 0x6566, 0x2009, 0x0002, 0x0128,
+	0x080c, 0x6608, 0x1170, 0x2009, 0x0003, 0xa897, 0x4005, 0xa99a,
+	0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030,
+	0x0005, 0xa897, 0x4000, 0x2001, 0x1957, 0x2004, 0xd0fc, 0x1128,
+	0x080c, 0x55e3, 0x0110, 0x9006, 0x0018, 0x900e, 0x9085, 0x0001,
+	0x2001, 0x0000, 0x0005, 0x6100, 0x0804, 0x34e8, 0x080c, 0x4af2,
+	0x0904, 0x351d, 0x080c, 0x55ef, 0x1904, 0x351a, 0x79a8, 0xd184,
+	0x1158, 0xb834, 0x8007, 0x789e, 0xb830, 0x8007, 0x789a, 0xbb2c,
+	0x831f, 0xba28, 0x8217, 0x0050, 0xb824, 0x8007, 0x789e, 0xb820,
+	0x8007, 0x789a, 0xbb1c, 0x831f, 0xba18, 0x8217, 0xb900, 0x918c,
+	0x0202, 0x0804, 0x34e8, 0x78a8, 0x909c, 0x0003, 0xd0ac, 0x1158,
+	0xd0b4, 0x1148, 0x939a, 0x0003, 0x1a04, 0x351a, 0x6258, 0x7884,
+	0x9206, 0x1904, 0x46eb, 0x2031, 0x1848, 0x2009, 0x013c, 0x2136,
+	0x2001, 0x1840, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98,
+	0x2039, 0x0001, 0x0006, 0x78a8, 0x9084, 0x0080, 0x11f8, 0x0006,
+	0x0036, 0x2001, 0x1a57, 0x201c, 0x7b9a, 0x2003, 0x0000, 0x2001,
+	0x1a58, 0x201c, 0x7b9e, 0x2003, 0x0000, 0x2001, 0x1a59, 0x201c,
+	0x7ba2, 0x2003, 0x0000, 0x2001, 0x1a53, 0x201c, 0x7baa, 0x2003,
+	0x0000, 0x003e, 0x000e, 0x000e, 0x0804, 0x4b0b, 0x000e, 0x2031,
+	0x0000, 0x2061, 0x18b6, 0x2c44, 0xa66a, 0xa17a, 0xa772, 0xa076,
+	0xa28e, 0xa392, 0xa496, 0xa59a, 0x080c, 0x112e, 0x7007, 0x0002,
+	0x701f, 0x470b, 0x0005, 0x81ff, 0x1904, 0x351a, 0x080c, 0x4af2,
+	0x0904, 0x351d, 0x080c, 0x67c3, 0x1904, 0x351a, 0x00c6, 0x080c,
+	0x4abf, 0x00ce, 0x0904, 0x351a, 0xa867, 0x0000, 0xa868, 0xc0fd,
+	0xa86a, 0x7ea8, 0x080c, 0xbfa8, 0x0904, 0x351a, 0x7007, 0x0003,
+	0x701f, 0x472b, 0x0005, 0x080c, 0x4249, 0x0006, 0x0036, 0x2001,
+	0x1a57, 0x201c, 0x7b9a, 0x2003, 0x0000, 0x2001, 0x1a58, 0x201c,
+	0x7b9e, 0x2003, 0x0000, 0x2001, 0x1a59, 0x201c, 0x7ba2, 0x2003,
+	0x0000, 0x2001, 0x1a53, 0x201c, 0x7baa, 0x2003, 0x0000, 0x003e,
+	0x000e, 0x0804, 0x34e8, 0xa830, 0x9086, 0x0100, 0x0904, 0x351a,
+	0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080,
+	0x001b, 0x2009, 0x000c, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x0804,
+	0x4b0b, 0x9006, 0x080c, 0x27d7, 0x78a8, 0x9084, 0x00ff, 0x9086,
+	0x00ff, 0x0118, 0x81ff, 0x1904, 0x351a, 0x080c, 0x7207, 0x0110,
+	0x080c, 0x5ef0, 0x7888, 0x908a, 0x1000, 0x1a04, 0x351d, 0x7984,
+	0x9186, 0x00ff, 0x0138, 0x9182, 0x007f, 0x1a04, 0x351d, 0x2100,
+	0x080c, 0x27a1, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000, 0x2061,
+	0x19d2, 0x601b, 0x0000, 0x601f, 0x0000, 0x6073, 0x0000, 0x6077,
+	0x0000, 0x080c, 0x7207, 0x1158, 0x080c, 0x7504, 0x080c, 0x5f2b,
+	0x9085, 0x0001, 0x080c, 0x724e, 0x080c, 0x7127, 0x00d0, 0x080c,
+	0xa069, 0x2061, 0x0100, 0x2001, 0x1817, 0x2004, 0x9084, 0x00ff,
+	0x810f, 0x9105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009,
+	0x1971, 0x200b, 0x0000, 0x2009, 0x002d, 0x2011, 0x5e16, 0x080c,
+	0x836c, 0x7984, 0x080c, 0x7207, 0x1110, 0x2009, 0x00ff, 0x7a88,
+	0x080c, 0x4596, 0x012e, 0x00ce, 0x002e, 0x0804, 0x34e8, 0x7984,
+	0x080c, 0x643f, 0x2b08, 0x1904, 0x351d, 0x0804, 0x34e8, 0x81ff,
+	0x0120, 0x2009, 0x0001, 0x0804, 0x351a, 0x60d8, 0xd0ac, 0x1130,
+	0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x351a, 0x080c, 0x4abf,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x351a, 0x7984, 0x9192, 0x0021,
+	0x1a04, 0x351d, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080,
+	0x0019, 0x702a, 0xaf60, 0x7736, 0x080c, 0x4b08, 0x701f, 0x47df,
+	0x7880, 0x9086, 0x006e, 0x0110, 0x701f, 0x5084, 0x0005, 0x2009,
+	0x0080, 0x080c, 0x649f, 0x1118, 0x080c, 0x67c3, 0x0120, 0x2021,
+	0x400a, 0x0804, 0x34ea, 0x00d6, 0x0096, 0xa964, 0xaa6c, 0xab70,
+	0xac74, 0xad78, 0xae7c, 0xa884, 0x90be, 0x0100, 0x0904, 0x4878,
+	0x90be, 0x0112, 0x0904, 0x4878, 0x90be, 0x0113, 0x0904, 0x4878,
+	0x90be, 0x0114, 0x0904, 0x4878, 0x90be, 0x0117, 0x0904, 0x4878,
+	0x90be, 0x011a, 0x0904, 0x4878, 0x90be, 0x011c, 0x0904, 0x4878,
+	0x90be, 0x0121, 0x0904, 0x485f, 0x90be, 0x0131, 0x0904, 0x485f,
+	0x90be, 0x0171, 0x0904, 0x4878, 0x90be, 0x0173, 0x0904, 0x4878,
+	0x90be, 0x01a1, 0x1128, 0xa894, 0x8007, 0xa896, 0x0804, 0x4883,
+	0x90be, 0x0212, 0x0904, 0x486c, 0x90be, 0x0213, 0x05e8, 0x90be,
+	0x0214, 0x0500, 0x90be, 0x0217, 0x0188, 0x90be, 0x021a, 0x1120,
+	0xa89c, 0x8007, 0xa89e, 0x04e0, 0x90be, 0x021f, 0x05c8, 0x90be,
+	0x0300, 0x05b0, 0x009e, 0x00de, 0x0804, 0x351d, 0x7028, 0x9080,
+	0x0010, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0007,
+	0x080c, 0x48c1, 0x7028, 0x9080, 0x000e, 0x2098, 0x20a0, 0x7034,
+	0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x48c1, 0x00c8, 0x7028,
+	0x9080, 0x000c, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9,
+	0x0001, 0x080c, 0x48ce, 0x00b8, 0x7028, 0x9080, 0x000e, 0x2098,
+	0x20a0, 0x7034, 0x20e0, 0x20e8, 0x20a9, 0x0001, 0x080c, 0x48ce,
+	0x7028, 0x9080, 0x000c, 0x2098, 0x20a0, 0x7034, 0x20e0, 0x20e8,
+	0x20a9, 0x0001, 0x04f1, 0x00c6, 0x080c, 0x4abf, 0x0550, 0xa868,
+	0xc0fd, 0xa86a, 0xa867, 0x0119, 0x9006, 0xa882, 0xa87f, 0x0020,
+	0xa88b, 0x0001, 0x810b, 0xa9ae, 0xa8b2, 0xaab6, 0xabba, 0xacbe,
+	0xadc2, 0xa9c6, 0xa8ca, 0x00ce, 0x009e, 0x00de, 0xa866, 0xa822,
+	0xa868, 0xc0fd, 0xa86a, 0xa804, 0x2048, 0x080c, 0xbfc3, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x351a, 0x7007, 0x0003, 0x701f, 0x48b8,
+	0x0005, 0x00ce, 0x009e, 0x00de, 0x2009, 0x0002, 0x0804, 0x351a,
+	0xa820, 0x9086, 0x8001, 0x1904, 0x34e8, 0x2009, 0x0004, 0x0804,
+	0x351a, 0x0016, 0x0026, 0x3510, 0x20a9, 0x0002, 0x4002, 0x4104,
+	0x4004, 0x8211, 0x1dc8, 0x002e, 0x001e, 0x0005, 0x0016, 0x0026,
+	0x0036, 0x0046, 0x3520, 0x20a9, 0x0004, 0x4002, 0x4304, 0x4204,
+	0x4104, 0x4004, 0x8421, 0x1db8, 0x004e, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x351a, 0x60d8,
+	0xd0ac, 0x1160, 0xd09c, 0x0120, 0x2009, 0x0016, 0x0804, 0x351a,
+	0xd09c, 0x1120, 0x2009, 0x0005, 0x0804, 0x351a, 0x7984, 0x78a8,
+	0x2040, 0x080c, 0xa062, 0x1120, 0x9182, 0x007f, 0x0a04, 0x351d,
+	0x9186, 0x00ff, 0x0904, 0x351d, 0x9182, 0x0800, 0x1a04, 0x351d,
+	0x7a8c, 0x7b88, 0x6078, 0x9306, 0x1158, 0x607c, 0x924e, 0x0904,
+	0x351d, 0x080c, 0xa062, 0x1120, 0x99cc, 0xff00, 0x0904, 0x351d,
+	0x0126, 0x2091, 0x8000, 0x9386, 0xffff, 0x0178, 0x0026, 0x2011,
+	0x8008, 0x080c, 0x67e7, 0x002e, 0x0140, 0x918d, 0x8000, 0x080c,
+	0x6831, 0x1118, 0x2001, 0x4009, 0x0458, 0x080c, 0x49d9, 0x0560,
+	0x90c6, 0x4000, 0x1170, 0x00c6, 0x0006, 0x900e, 0x080c, 0x66bf,
+	0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce,
+	0x00b8, 0x90c6, 0x4007, 0x1110, 0x2408, 0x0090, 0x90c6, 0x4008,
+	0x1118, 0x2708, 0x2610, 0x0060, 0x90c6, 0x4009, 0x1108, 0x0040,
+	0x90c6, 0x4006, 0x1108, 0x0020, 0x2001, 0x4005, 0x2009, 0x000a,
+	0x2020, 0x012e, 0x0804, 0x34ea, 0x2b00, 0x7026, 0x0016, 0x00b6,
+	0x00c6, 0x00e6, 0x2c70, 0x080c, 0xa130, 0x0904, 0x49a6, 0x2b00,
+	0x6012, 0x080c, 0xc2b3, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c,
+	0x4abf, 0x00ce, 0x2b70, 0x1158, 0x080c, 0xa0e3, 0x00ee, 0x00ce,
+	0x00be, 0x001e, 0x012e, 0x2009, 0x0002, 0x0804, 0x351a, 0x900e,
+	0xa966, 0xa96a, 0x2900, 0x6016, 0xa932, 0xa868, 0xc0fd, 0xd88c,
+	0x0108, 0xc0f5, 0xa86a, 0x080c, 0x318b, 0x6023, 0x0001, 0x9006,
+	0x080c, 0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0, 0x2009, 0x0002,
+	0x080c, 0xa15d, 0x78a8, 0xd094, 0x0138, 0x00ee, 0x7024, 0x00e6,
+	0x2058, 0xb8bc, 0xc08d, 0xb8be, 0x9085, 0x0001, 0x00ee, 0x00ce,
+	0x00be, 0x001e, 0x012e, 0x1120, 0x2009, 0x0003, 0x0804, 0x351a,
+	0x7007, 0x0003, 0x701f, 0x49b5, 0x0005, 0xa830, 0x2008, 0x918e,
+	0xdead, 0x1120, 0x2021, 0x4009, 0x0804, 0x34ea, 0x9086, 0x0100,
+	0x7024, 0x2058, 0x1138, 0x2009, 0x0004, 0xba04, 0x9294, 0x00ff,
+	0x0804, 0x552f, 0x900e, 0xa868, 0xd0f4, 0x1904, 0x34e8, 0x080c,
+	0x66bf, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0x0804,
+	0x34e8, 0x00e6, 0x00d6, 0x0096, 0x83ff, 0x0904, 0x4a21, 0x902e,
+	0x080c, 0xa062, 0x0130, 0x9026, 0x20a9, 0x0800, 0x2071, 0x1000,
+	0x0030, 0x2021, 0x007f, 0x20a9, 0x0781, 0x2071, 0x107f, 0x2e04,
+	0x9005, 0x11b0, 0x2100, 0x9406, 0x15e8, 0x2428, 0x94ce, 0x007f,
+	0x1120, 0x92ce, 0xfffd, 0x1528, 0x0030, 0x94ce, 0x0080, 0x1130,
+	0x92ce, 0xfffc, 0x11f0, 0x93ce, 0x00ff, 0x11d8, 0xc5fd, 0x0450,
+	0x2058, 0xbf10, 0x2700, 0x9306, 0x11b8, 0xbe14, 0x2600, 0x9206,
+	0x1198, 0x2400, 0x9106, 0x1150, 0xd884, 0x0568, 0xd894, 0x1558,
+	0x080c, 0x67c3, 0x1540, 0x2001, 0x4000, 0x0430, 0x2001, 0x4007,
+	0x0418, 0x2001, 0x4006, 0x0400, 0x2400, 0x9106, 0x1158, 0xbe14,
+	0x87ff, 0x1128, 0x86ff, 0x0948, 0x080c, 0xa062, 0x1930, 0x2001,
+	0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04, 0x49ef, 0x85ff, 0x1130,
+	0x2001, 0x4009, 0x0048, 0x2001, 0x0001, 0x0030, 0x080c, 0x643f,
+	0x1dd0, 0xbb12, 0xba16, 0x9006, 0x9005, 0x009e, 0x00de, 0x00ee,
+	0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x351a, 0x080c,
+	0x4abf, 0x1120, 0x2009, 0x0002, 0x0804, 0x351a, 0xa867, 0x0000,
+	0xa868, 0xc0fd, 0xa86a, 0x7884, 0x9005, 0x0904, 0x351d, 0x9096,
+	0x00ff, 0x0120, 0x9092, 0x0004, 0x1a04, 0x351d, 0x2010, 0x2918,
+	0x080c, 0x3131, 0x1120, 0x2009, 0x0003, 0x0804, 0x351a, 0x7007,
+	0x0003, 0x701f, 0x4a74, 0x0005, 0xa830, 0x9086, 0x0100, 0x1904,
+	0x34e8, 0x2009, 0x0004, 0x0804, 0x351a, 0x7984, 0x080c, 0xa062,
+	0x1120, 0x9182, 0x007f, 0x0a04, 0x351d, 0x9186, 0x00ff, 0x0904,
+	0x351d, 0x9182, 0x0800, 0x1a04, 0x351d, 0x2001, 0x9400, 0x080c,
+	0x558a, 0x1904, 0x351a, 0x0804, 0x34e8, 0xa998, 0x080c, 0xa062,
+	0x1118, 0x9182, 0x007f, 0x0280, 0x9186, 0x00ff, 0x0168, 0x9182,
+	0x0800, 0x1250, 0x2001, 0x9400, 0x080c, 0x558a, 0x11a8, 0x0060,
+	0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x900e, 0x9085,
+	0x0001, 0x2001, 0x0000, 0x0005, 0x2009, 0x000a, 0x0c48, 0x080c,
+	0x1031, 0x0198, 0x9006, 0xa802, 0x7014, 0x9005, 0x1120, 0x2900,
+	0x7016, 0x701a, 0x0040, 0x7018, 0xa802, 0x0086, 0x2040, 0x2900,
+	0xa006, 0x701a, 0x008e, 0x9085, 0x0001, 0x0005, 0x7984, 0x080c,
+	0x649f, 0x1130, 0x7e88, 0x9684, 0x3fff, 0x9082, 0x4000, 0x0208,
+	0x905e, 0x8bff, 0x0005, 0xa998, 0x080c, 0x649f, 0x1130, 0xae9c,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x0208, 0x905e, 0x8bff, 0x0005,
+	0xae98, 0x0008, 0x7e84, 0x2608, 0x080c, 0x649f, 0x1108, 0x0008,
+	0x905e, 0x8bff, 0x0005, 0x0016, 0x7114, 0x81ff, 0x0128, 0x2148,
+	0xa904, 0x080c, 0x1063, 0x0cc8, 0x7116, 0x711a, 0x001e, 0x0005,
+	0x2031, 0x0001, 0x0010, 0x2031, 0x0000, 0x2061, 0x18b6, 0x2c44,
+	0xa66a, 0xa17a, 0xa772, 0xa076, 0xa28e, 0xa392, 0xa496, 0xa59a,
+	0x080c, 0x112e, 0x7007, 0x0002, 0x701f, 0x34e8, 0x0005, 0x00f6,
+	0x0126, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001, 0x18ae, 0x2004,
+	0x9005, 0x1190, 0x0e04, 0x4b3c, 0x7a36, 0x7833, 0x0012, 0x7a82,
+	0x7b86, 0x7c8a, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11e0, 0x0804, 0x4ba2, 0x0016, 0x0086, 0x0096, 0x00c6,
+	0x00e6, 0x2071, 0x189c, 0x7044, 0x9005, 0x1540, 0x7148, 0x9182,
+	0x0010, 0x0288, 0x7038, 0x2060, 0x080c, 0x1031, 0x0904, 0x4b9a,
+	0xa84b, 0x0000, 0x2900, 0x7046, 0x2001, 0x0002, 0x9080, 0x1fc8,
+	0x2005, 0xa846, 0x0098, 0x7038, 0x90e0, 0x0004, 0x2001, 0x18b8,
+	0x9c82, 0x18f8, 0x0210, 0x2061, 0x18b8, 0x2c00, 0x703a, 0x7148,
+	0x81ff, 0x1108, 0x703e, 0x8108, 0x714a, 0x0460, 0x7148, 0x8108,
+	0x714a, 0x7044, 0x2040, 0xa144, 0x2105, 0x0016, 0x908a, 0x0036,
+	0x1a0c, 0x0dfa, 0x2060, 0x001e, 0x8108, 0x2105, 0x9005, 0xa146,
+	0x1520, 0x080c, 0x1031, 0x1130, 0x8109, 0xa946, 0x7148, 0x8109,
+	0x714a, 0x00d8, 0x9006, 0xa806, 0xa84a, 0xa046, 0x2800, 0xa802,
+	0x2900, 0xa006, 0x7046, 0x2001, 0x0002, 0x9080, 0x1fc8, 0x2005,
+	0xa846, 0x0058, 0x2262, 0x6306, 0x640a, 0x00ee, 0x00ce, 0x009e,
+	0x008e, 0x001e, 0x012e, 0x00fe, 0x0005, 0x2c00, 0x9082, 0x001b,
+	0x0002, 0x4bc4, 0x4bc4, 0x4bc6, 0x4bc4, 0x4bc4, 0x4bc4, 0x4bca,
+	0x4bc4, 0x4bc4, 0x4bc4, 0x4bce, 0x4bc4, 0x4bc4, 0x4bc4, 0x4bd2,
+	0x4bc4, 0x4bc4, 0x4bc4, 0x4bd6, 0x4bc4, 0x4bc4, 0x4bc4, 0x4bda,
+	0x4bc4, 0x4bc4, 0x4bc4, 0x4bdf, 0x080c, 0x0dfa, 0xa276, 0xa37a,
+	0xa47e, 0x0898, 0xa286, 0xa38a, 0xa48e, 0x0878, 0xa296, 0xa39a,
+	0xa49e, 0x0858, 0xa2a6, 0xa3aa, 0xa4ae, 0x0838, 0xa2b6, 0xa3ba,
+	0xa4be, 0x0818, 0xa2c6, 0xa3ca, 0xa4ce, 0x0804, 0x4b9d, 0xa2d6,
+	0xa3da, 0xa4de, 0x0804, 0x4b9d, 0x00e6, 0x2071, 0x189c, 0x7048,
+	0x9005, 0x0904, 0x4c76, 0x0126, 0x2091, 0x8000, 0x0e04, 0x4c75,
+	0x00f6, 0x2079, 0x0000, 0x00c6, 0x0096, 0x0086, 0x0076, 0x9006,
+	0x2038, 0x7040, 0x2048, 0x9005, 0x0500, 0xa948, 0x2105, 0x0016,
+	0x908a, 0x0036, 0x1a0c, 0x0dfa, 0x2060, 0x001e, 0x8108, 0x2105,
+	0x9005, 0xa94a, 0x1904, 0x4c78, 0xa804, 0x9005, 0x090c, 0x0dfa,
+	0x7042, 0x2938, 0x2040, 0xa003, 0x0000, 0x2001, 0x0002, 0x9080,
+	0x1fc8, 0x2005, 0xa04a, 0x0804, 0x4c78, 0x703c, 0x2060, 0x2c14,
+	0x6304, 0x6408, 0x650c, 0x2200, 0x7836, 0x7833, 0x0012, 0x7882,
+	0x2300, 0x7886, 0x2400, 0x788a, 0x2091, 0x4080, 0x2001, 0x0089,
+	0x2004, 0xd084, 0x190c, 0x11e0, 0x87ff, 0x0118, 0x2748, 0x080c,
+	0x1063, 0x7048, 0x8001, 0x704a, 0x9005, 0x1170, 0x7040, 0x2048,
+	0x9005, 0x0128, 0x080c, 0x1063, 0x9006, 0x7042, 0x7046, 0x703b,
+	0x18b8, 0x703f, 0x18b8, 0x0420, 0x7040, 0x9005, 0x1508, 0x7238,
+	0x2c00, 0x9206, 0x0148, 0x9c80, 0x0004, 0x90fa, 0x18f8, 0x0210,
+	0x2001, 0x18b8, 0x703e, 0x00a0, 0x9006, 0x703e, 0x703a, 0x7044,
+	0x9005, 0x090c, 0x0dfa, 0x2048, 0xa800, 0x9005, 0x1de0, 0x2900,
+	0x7042, 0x2001, 0x0002, 0x9080, 0x1fc8, 0x2005, 0xa84a, 0x0000,
+	0x007e, 0x008e, 0x009e, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005,
+	0x2c00, 0x9082, 0x001b, 0x0002, 0x4c97, 0x4c97, 0x4c99, 0x4c97,
+	0x4c97, 0x4c97, 0x4c9e, 0x4c97, 0x4c97, 0x4c97, 0x4ca3, 0x4c97,
+	0x4c97, 0x4c97, 0x4ca8, 0x4c97, 0x4c97, 0x4c97, 0x4cad, 0x4c97,
+	0x4c97, 0x4c97, 0x4cb2, 0x4c97, 0x4c97, 0x4c97, 0x4cb7, 0x080c,
+	0x0dfa, 0xaa74, 0xab78, 0xac7c, 0x0804, 0x4c23, 0xaa84, 0xab88,
+	0xac8c, 0x0804, 0x4c23, 0xaa94, 0xab98, 0xac9c, 0x0804, 0x4c23,
+	0xaaa4, 0xaba8, 0xacac, 0x0804, 0x4c23, 0xaab4, 0xabb8, 0xacbc,
+	0x0804, 0x4c23, 0xaac4, 0xabc8, 0xaccc, 0x0804, 0x4c23, 0xaad4,
+	0xabd8, 0xacdc, 0x0804, 0x4c23, 0x0026, 0x080c, 0x55db, 0xd0c4,
+	0x0120, 0x2011, 0x8014, 0x080c, 0x4b1f, 0x002e, 0x0005, 0x81ff,
+	0x1904, 0x351a, 0x0126, 0x2091, 0x8000, 0x6030, 0xc08d, 0xc085,
+	0xc0ac, 0x6032, 0x080c, 0x7207, 0x1158, 0x080c, 0x7504, 0x080c,
+	0x5f2b, 0x9085, 0x0001, 0x080c, 0x724e, 0x080c, 0x7127, 0x0010,
+	0x080c, 0x5dea, 0x012e, 0x0804, 0x34e8, 0x81ff, 0x0120, 0x2009,
+	0x0001, 0x0804, 0x351a, 0x080c, 0x55ef, 0x0120, 0x2009, 0x0007,
+	0x0804, 0x351a, 0x080c, 0x67bb, 0x0120, 0x2009, 0x0008, 0x0804,
+	0x351a, 0x0026, 0x2011, 0x0010, 0x080c, 0x67e7, 0x002e, 0x0140,
+	0x7984, 0x080c, 0x6831, 0x1120, 0x2009, 0x4009, 0x0804, 0x351a,
+	0x7984, 0x080c, 0x643f, 0x1904, 0x351d, 0x080c, 0x4af2, 0x0904,
+	0x351d, 0x2b00, 0x7026, 0x080c, 0x67c3, 0x7888, 0x1170, 0x9084,
+	0x0005, 0x1158, 0x900e, 0x080c, 0x66bf, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0x0804, 0x34e8, 0x080c, 0x4abf, 0x0904,
+	0x351a, 0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c,
+	0xc061, 0x0904, 0x351a, 0x7888, 0xd094, 0x0118, 0xb8bc, 0xc08d,
+	0xb8be, 0x7007, 0x0003, 0x701f, 0x4d87, 0x0005, 0x2061, 0x1800,
+	0x080c, 0x55ef, 0x2009, 0x0007, 0x1560, 0x080c, 0x67bb, 0x0118,
+	0x2009, 0x0008, 0x0430, 0xa998, 0x080c, 0x643f, 0x1530, 0x080c,
+	0x4af0, 0x0518, 0x080c, 0x67c3, 0xa89c, 0x1168, 0x9084, 0x0005,
+	0x1150, 0x900e, 0x080c, 0x66bf, 0x1108, 0xc185, 0xb800, 0xd0bc,
+	0x0108, 0xc18d, 0x00d0, 0xa868, 0xc0fc, 0xa86a, 0x080c, 0xc061,
+	0x11e0, 0xa89c, 0xd094, 0x0118, 0xb8bc, 0xc08d, 0xb8be, 0x2009,
+	0x0003, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0xa99a,
+	0x9006, 0x918d, 0x0001, 0x2008, 0x0005, 0x9006, 0x0005, 0xa830,
+	0x2008, 0x918e, 0xdead, 0x1120, 0x2021, 0x4009, 0x0804, 0x34ea,
+	0x9086, 0x0100, 0x7024, 0x2058, 0x1110, 0x0804, 0x552f, 0x900e,
+	0x080c, 0x66bf, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d,
+	0x0804, 0x34e8, 0x080c, 0x55ef, 0x0120, 0x2009, 0x0007, 0x0804,
+	0x351a, 0x7f84, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x080c, 0x4abf,
+	0x1120, 0x2009, 0x0002, 0x0804, 0x351a, 0x900e, 0x2130, 0x7126,
+	0x7132, 0xa860, 0x20e8, 0x7036, 0xa85c, 0x9080, 0x0005, 0x702a,
+	0x20a0, 0x080c, 0x649f, 0x1904, 0x4e25, 0x080c, 0x67c3, 0x0120,
+	0x080c, 0x67cb, 0x1904, 0x4e25, 0x080c, 0x67bb, 0x1130, 0x080c,
+	0x66bf, 0x1118, 0xd79c, 0x0904, 0x4e25, 0xd794, 0x1110, 0xd784,
+	0x01a8, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x0006, 0x2098, 0x3400,
+	0xd794, 0x0160, 0x20a9, 0x0008, 0x4003, 0x2098, 0x20a0, 0x3d00,
+	0x20e0, 0x20a9, 0x0002, 0x080c, 0x48ce, 0x0048, 0x20a9, 0x0004,
+	0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x080c, 0x48ce, 0x4104,
+	0xd794, 0x0528, 0xb8b4, 0x20e0, 0xb8b8, 0x2060, 0x9c80, 0x0000,
+	0x2098, 0x20a9, 0x0002, 0x4003, 0x9c80, 0x0003, 0x2098, 0x20a9,
+	0x0001, 0x4005, 0x9c80, 0x0004, 0x2098, 0x3400, 0x20a9, 0x0002,
+	0x4003, 0x2098, 0x20a0, 0x3d00, 0x20e0, 0x080c, 0x48c1, 0x9c80,
+	0x0026, 0x2098, 0xb8b4, 0x20e0, 0x20a9, 0x0002, 0x4003, 0xd794,
+	0x0110, 0x96b0, 0x000b, 0x96b0, 0x0005, 0x8108, 0x080c, 0xa062,
+	0x0118, 0x9186, 0x0800, 0x0040, 0xd78c, 0x0120, 0x9186, 0x0800,
+	0x0170, 0x0018, 0x9186, 0x007e, 0x0150, 0xd794, 0x0118, 0x9686,
+	0x0020, 0x0010, 0x9686, 0x0028, 0x0150, 0x0804, 0x4dc1, 0x86ff,
+	0x1120, 0x7124, 0x810b, 0x0804, 0x34e8, 0x7033, 0x0001, 0x7122,
+	0x7024, 0x9600, 0x7026, 0x772e, 0x2061, 0x18b6, 0x2c44, 0xa06b,
+	0x0000, 0xa67a, 0x7034, 0xa072, 0x7028, 0xa076, 0xa28e, 0xa392,
+	0xa496, 0xa59a, 0x080c, 0x112e, 0x7007, 0x0002, 0x701f, 0x4e61,
+	0x0005, 0x7030, 0x9005, 0x1180, 0x7120, 0x7028, 0x20a0, 0x772c,
+	0x9036, 0x7034, 0x20e8, 0x2061, 0x18b6, 0x2c44, 0xa28c, 0xa390,
+	0xa494, 0xa598, 0x0804, 0x4dc1, 0x7124, 0x810b, 0x0804, 0x34e8,
+	0x2029, 0x007e, 0x7984, 0x7a88, 0x7b8c, 0x7c98, 0x9184, 0xff00,
+	0x8007, 0x90e2, 0x0020, 0x0a04, 0x351d, 0x9502, 0x0a04, 0x351d,
+	0x9184, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x351d, 0x9502, 0x0a04,
+	0x351d, 0x9284, 0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x351d,
+	0x9502, 0x0a04, 0x351d, 0x9284, 0x00ff, 0x90e2, 0x0020, 0x0a04,
+	0x351d, 0x9502, 0x0a04, 0x351d, 0x9384, 0xff00, 0x8007, 0x90e2,
+	0x0020, 0x0a04, 0x351d, 0x9502, 0x0a04, 0x351d, 0x9384, 0x00ff,
+	0x90e2, 0x0020, 0x0a04, 0x351d, 0x9502, 0x0a04, 0x351d, 0x9484,
+	0xff00, 0x8007, 0x90e2, 0x0020, 0x0a04, 0x351d, 0x9502, 0x0a04,
+	0x351d, 0x9484, 0x00ff, 0x90e2, 0x0020, 0x0a04, 0x351d, 0x9502,
+	0x0a04, 0x351d, 0x2061, 0x1961, 0x6102, 0x6206, 0x630a, 0x640e,
+	0x0804, 0x34e8, 0x0006, 0x080c, 0x55db, 0xd0cc, 0x000e, 0x0005,
+	0x0006, 0x080c, 0x55df, 0xd0bc, 0x000e, 0x0005, 0x6170, 0x7a84,
+	0x6300, 0x82ff, 0x1118, 0x7986, 0x0804, 0x34e8, 0x83ff, 0x1904,
+	0x351d, 0x2001, 0xfff0, 0x9200, 0x1a04, 0x351d, 0x2019, 0xffff,
+	0x6074, 0x9302, 0x9200, 0x0a04, 0x351d, 0x7986, 0x6272, 0x0804,
+	0x34e8, 0x080c, 0x55ef, 0x1904, 0x351a, 0x7c88, 0x7d84, 0x7e98,
+	0x7f8c, 0x080c, 0x4abf, 0x0904, 0x351a, 0x900e, 0x901e, 0x7326,
+	0x7332, 0xa860, 0x20e8, 0x7036, 0xa85c, 0x9080, 0x0003, 0x702a,
+	0x20a0, 0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178, 0x080c, 0x67c3,
+	0x0118, 0x080c, 0x67cb, 0x1148, 0x20a9, 0x0001, 0xb814, 0x4004,
+	0xb810, 0x4004, 0x4104, 0x9398, 0x0003, 0x8108, 0x9182, 0x0800,
+	0x0120, 0x9386, 0x003c, 0x0170, 0x0c20, 0x83ff, 0x1148, 0x7224,
+	0x900e, 0x2001, 0x0003, 0x080c, 0x84ff, 0x2208, 0x0804, 0x34e8,
+	0x7033, 0x0001, 0x7122, 0x7024, 0x9300, 0x7026, 0x2061, 0x18b6,
+	0x2c44, 0xa06b, 0x0000, 0xa37a, 0x7028, 0xa076, 0x7034, 0xa072,
+	0xa48e, 0xa592, 0xa696, 0xa79a, 0x080c, 0x112e, 0x7007, 0x0002,
+	0x701f, 0x4f53, 0x0005, 0x7030, 0x9005, 0x1178, 0x7120, 0x7028,
+	0x20a0, 0x901e, 0x7034, 0x20e8, 0x2061, 0x18b6, 0x2c44, 0xa48c,
+	0xa590, 0xa694, 0xa798, 0x0804, 0x4f11, 0x7224, 0x900e, 0x2001,
+	0x0003, 0x080c, 0x84ff, 0x2208, 0x0804, 0x34e8, 0x00f6, 0x00e6,
+	0x080c, 0x55ef, 0x2009, 0x0007, 0x1904, 0x4fe6, 0x2071, 0x189c,
+	0x745c, 0x84ff, 0x2009, 0x000e, 0x1904, 0x4fe6, 0xac9c, 0xad98,
+	0xaea4, 0xafa0, 0x0096, 0x080c, 0x104a, 0x2009, 0x0002, 0x0904,
+	0x4fe6, 0x2900, 0x705e, 0x900e, 0x901e, 0x7356, 0x7362, 0xa860,
+	0x7066, 0xa85c, 0x9080, 0x0003, 0x705a, 0x20a0, 0x91d8, 0x1000,
+	0x2b5c, 0x8bff, 0x0178, 0x080c, 0x67c3, 0x0118, 0x080c, 0x67cb,
+	0x1148, 0xb814, 0x20a9, 0x0001, 0x4004, 0xb810, 0x4004, 0x4104,
+	0x9398, 0x0003, 0x8108, 0x9182, 0x0800, 0x0120, 0x9386, 0x003c,
+	0x01e8, 0x0c20, 0x83ff, 0x11c0, 0x7254, 0x900e, 0x2001, 0x0003,
+	0x080c, 0x84ff, 0x2208, 0x009e, 0xa897, 0x4000, 0xa99a, 0x715c,
+	0x81ff, 0x090c, 0x0dfa, 0x2148, 0x080c, 0x1063, 0x9006, 0x705e,
+	0x918d, 0x0001, 0x2008, 0x0418, 0x7063, 0x0001, 0x7152, 0x7054,
+	0x9300, 0x7056, 0x2061, 0x18b7, 0x2c44, 0xa37a, 0x7058, 0xa076,
+	0x7064, 0xa072, 0xa48e, 0xa592, 0xa696, 0xa79a, 0xa09f, 0x4ff2,
+	0x000e, 0xa0a2, 0x080c, 0x112e, 0x9006, 0x0048, 0x009e, 0xa897,
+	0x4005, 0xa99a, 0x900e, 0x9085, 0x0001, 0x2001, 0x0030, 0x00ee,
+	0x00fe, 0x0005, 0x00f6, 0xa0a0, 0x904d, 0x090c, 0x0dfa, 0x00e6,
+	0x2071, 0x189c, 0xa06c, 0x908e, 0x0100, 0x0138, 0xa87b, 0x0030,
+	0xa883, 0x0000, 0xa897, 0x4002, 0x00d8, 0x7060, 0x9005, 0x1158,
+	0x7150, 0x7058, 0x20a0, 0x901e, 0x7064, 0x20e8, 0xa48c, 0xa590,
+	0xa694, 0xa798, 0x0428, 0xa87b, 0x0000, 0xa883, 0x0000, 0xa897,
+	0x4000, 0x7254, 0x900e, 0x2001, 0x0003, 0x080c, 0x84ff, 0xaa9a,
+	0x715c, 0x81ff, 0x090c, 0x0dfa, 0x2148, 0x080c, 0x1063, 0x705f,
+	0x0000, 0xa0a0, 0x2048, 0x0126, 0x2091, 0x8000, 0x080c, 0x6ae9,
+	0x012e, 0xa09f, 0x0000, 0xa0a3, 0x0000, 0x00ee, 0x00fe, 0x0005,
+	0x91d8, 0x1000, 0x2b5c, 0x8bff, 0x0178, 0x080c, 0x67c3, 0x0118,
+	0x080c, 0x67cb, 0x1148, 0xb814, 0x20a9, 0x0001, 0x4004, 0xb810,
+	0x4004, 0x4104, 0x9398, 0x0003, 0x8108, 0x9182, 0x0800, 0x0120,
+	0x9386, 0x003c, 0x0518, 0x0c20, 0x83ff, 0x11f0, 0x7154, 0x810c,
+	0xa99a, 0xa897, 0x4000, 0x715c, 0x81ff, 0x090c, 0x0dfa, 0x2148,
+	0x080c, 0x1063, 0x9006, 0x705e, 0x918d, 0x0001, 0x2008, 0xa0a0,
+	0x2048, 0x0126, 0x2091, 0x8000, 0x080c, 0x6ae9, 0x012e, 0xa09f,
+	0x0000, 0xa0a3, 0x0000, 0x0070, 0x7063, 0x0001, 0x7152, 0x7054,
+	0x9300, 0x7056, 0xa37a, 0xa48e, 0xa592, 0xa696, 0xa79a, 0x080c,
+	0x112e, 0x9006, 0x00ee, 0x0005, 0x0096, 0xa88c, 0x90be, 0x7000,
+	0x0148, 0x90be, 0x7100, 0x0130, 0x90be, 0x7200, 0x0118, 0x009e,
+	0x0804, 0x351d, 0xa884, 0xa988, 0x080c, 0x276e, 0x1518, 0x080c,
+	0x643f, 0x1500, 0x7126, 0xbe12, 0xbd16, 0xae7c, 0x080c, 0x4abf,
+	0x01c8, 0x080c, 0x4abf, 0x01b0, 0x009e, 0xa867, 0x0000, 0xa868,
+	0xc0fd, 0xa86a, 0xa823, 0x0000, 0xa804, 0x2048, 0x080c, 0xbfe3,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x351a, 0x7007, 0x0003, 0x701f,
+	0x50bf, 0x0005, 0x009e, 0x2009, 0x0002, 0x0804, 0x351a, 0x7124,
+	0x080c, 0x3286, 0xa820, 0x9086, 0x8001, 0x1120, 0x2009, 0x0004,
+	0x0804, 0x351a, 0x2900, 0x7022, 0xa804, 0x0096, 0x2048, 0x8906,
+	0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x009e, 0x9080,
+	0x0002, 0x0076, 0x0006, 0x2098, 0x20a0, 0x27e0, 0x27e8, 0x20a9,
+	0x002a, 0x080c, 0x0fae, 0xaa6c, 0xab70, 0xac74, 0xad78, 0x2061,
+	0x18b6, 0x2c44, 0xa06b, 0x0000, 0xae64, 0xaf8c, 0x97c6, 0x7000,
+	0x0118, 0x97c6, 0x7100, 0x1148, 0x96c2, 0x0004, 0x0600, 0x2009,
+	0x0004, 0x000e, 0x007e, 0x0804, 0x4b0b, 0x97c6, 0x7200, 0x11b8,
+	0x96c2, 0x0054, 0x02a0, 0x000e, 0x007e, 0x2061, 0x18b6, 0x2c44,
+	0xa076, 0xa772, 0xa07b, 0x002a, 0xa28e, 0xa392, 0xa496, 0xa59a,
+	0x080c, 0x112e, 0x7007, 0x0002, 0x701f, 0x511b, 0x0005, 0x000e,
+	0x007e, 0x0804, 0x351d, 0x7020, 0x2048, 0xa804, 0x2048, 0xa804,
+	0x2048, 0x8906, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0,
+	0x9080, 0x0002, 0x2098, 0x20a0, 0x27e0, 0x27e8, 0x20a9, 0x002a,
+	0x080c, 0x0fae, 0x2100, 0x2238, 0x2061, 0x18b6, 0x2c44, 0xa28c,
+	0xa390, 0xa494, 0xa598, 0x2009, 0x002a, 0x0804, 0x4b0b, 0x81ff,
+	0x1904, 0x351a, 0x798c, 0x2001, 0x1956, 0x918c, 0x8000, 0x2102,
+	0x080c, 0x4ad6, 0x0904, 0x351d, 0x080c, 0x67c3, 0x0120, 0x080c,
+	0x67cb, 0x1904, 0x351d, 0x080c, 0x6566, 0x0904, 0x351a, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x662c, 0x012e, 0x0904, 0x351a, 0x2001,
+	0x1956, 0x2004, 0xd0fc, 0x1904, 0x34e8, 0x0804, 0x4533, 0xa9a0,
+	0x2001, 0x1956, 0x918c, 0x8000, 0xc18d, 0x2102, 0x080c, 0x4ae3,
+	0x01a0, 0x080c, 0x67c3, 0x0118, 0x080c, 0x67cb, 0x1170, 0x080c,
+	0x6566, 0x2009, 0x0002, 0x0128, 0x080c, 0x662c, 0x1170, 0x2009,
+	0x0003, 0xa897, 0x4005, 0xa99a, 0x0010, 0xa897, 0x4006, 0x900e,
+	0x9085, 0x0001, 0x2001, 0x0030, 0x0005, 0xa897, 0x4000, 0x2001,
+	0x1956, 0x2004, 0xd0fc, 0x1128, 0x080c, 0x55e3, 0x0110, 0x9006,
+	0x0018, 0x900e, 0x9085, 0x0001, 0x2001, 0x0000, 0x0005, 0x78a8,
+	0xd08c, 0x1118, 0xd084, 0x0904, 0x44a8, 0x080c, 0x4af2, 0x0904,
+	0x351d, 0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804, 0x351a,
+	0x080c, 0x67c3, 0x0130, 0x908e, 0x0004, 0x0118, 0x908e, 0x0005,
+	0x15a0, 0x78a8, 0xd08c, 0x0120, 0xb800, 0xc08c, 0xb802, 0x0028,
+	0x080c, 0x55db, 0xd0b4, 0x0904, 0x44e2, 0x7884, 0x908e, 0x007e,
+	0x0904, 0x44e2, 0x908e, 0x007f, 0x0904, 0x44e2, 0x908e, 0x0080,
+	0x0904, 0x44e2, 0xb800, 0xd08c, 0x1904, 0x44e2, 0xa867, 0x0000,
+	0xa868, 0xc0fd, 0xa86a, 0x080c, 0xc002, 0x1120, 0x2009, 0x0003,
+	0x0804, 0x351a, 0x7007, 0x0003, 0x701f, 0x51e7, 0x0005, 0x080c,
+	0x4af2, 0x0904, 0x351d, 0x0804, 0x44e2, 0x080c, 0x32df, 0x0108,
+	0x0005, 0x2009, 0x1833, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x351a, 0x080c, 0x55ef, 0x0120, 0x2009, 0x0007, 0x0804,
+	0x351a, 0x080c, 0x67bb, 0x0120, 0x2009, 0x0008, 0x0804, 0x351a,
+	0xb89c, 0xd0a4, 0x1118, 0xd0ac, 0x1904, 0x44e2, 0x9006, 0xa866,
+	0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xc061, 0x1120, 0x2009,
+	0x0003, 0x0804, 0x351a, 0x7007, 0x0003, 0x701f, 0x5220, 0x0005,
+	0xa830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x552f,
+	0x080c, 0x4af2, 0x0904, 0x351d, 0x0804, 0x51b9, 0x81ff, 0x2009,
+	0x0001, 0x1904, 0x351a, 0x080c, 0x55ef, 0x2009, 0x0007, 0x1904,
+	0x351a, 0x080c, 0x67bb, 0x0120, 0x2009, 0x0008, 0x0804, 0x351a,
+	0x080c, 0x4af2, 0x0904, 0x351d, 0x080c, 0x67c3, 0x2009, 0x0009,
+	0x1904, 0x351a, 0x080c, 0x4abf, 0x2009, 0x0002, 0x0904, 0x351a,
+	0x9006, 0xa866, 0xa832, 0xa868, 0xc0fd, 0xa86a, 0x7988, 0x9194,
+	0xff00, 0x918c, 0x00ff, 0x9006, 0x82ff, 0x1128, 0xc0ed, 0xa952,
+	0x798c, 0xa956, 0x0038, 0x928e, 0x0100, 0x1904, 0x351d, 0xc0e5,
+	0xa952, 0xa956, 0xa83e, 0x080c, 0xc2b4, 0x2009, 0x0003, 0x0904,
+	0x351a, 0x7007, 0x0003, 0x701f, 0x5276, 0x0005, 0xa830, 0x9086,
+	0x0100, 0x2009, 0x0004, 0x0904, 0x351a, 0x0804, 0x34e8, 0x7aa8,
+	0x9284, 0xc000, 0x0148, 0xd2ec, 0x01a0, 0x080c, 0x55ef, 0x1188,
+	0x2009, 0x0014, 0x0804, 0x351a, 0xd2dc, 0x1578, 0x81ff, 0x2009,
+	0x0001, 0x1904, 0x351a, 0x080c, 0x55ef, 0x2009, 0x0007, 0x1904,
+	0x351a, 0xd2f4, 0x0138, 0x9284, 0x5000, 0xc0d5, 0x080c, 0x55b5,
+	0x0804, 0x34e8, 0xd2fc, 0x0160, 0x080c, 0x4af2, 0x0904, 0x351d,
+	0x7984, 0x9284, 0x9000, 0xc0d5, 0x080c, 0x558a, 0x0804, 0x34e8,
+	0x080c, 0x4af2, 0x0904, 0x351d, 0xb804, 0x9084, 0x00ff, 0x9086,
+	0x0006, 0x2009, 0x0009, 0x1904, 0x5365, 0x080c, 0x4abf, 0x2009,
+	0x0002, 0x0904, 0x5365, 0xa85c, 0x9080, 0x001b, 0xaf60, 0x2009,
+	0x0008, 0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0x080c, 0x4b08, 0x701f,
+	0x52d2, 0x0005, 0xa86c, 0x9086, 0x0500, 0x1138, 0xa870, 0x9005,
+	0x1120, 0xa874, 0x9084, 0xff00, 0x0110, 0x1904, 0x351d, 0xa866,
+	0xa832, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0x4af2, 0x1110, 0x0804,
+	0x351d, 0x2009, 0x0043, 0x080c, 0xc31c, 0x2009, 0x0003, 0x0904,
+	0x5365, 0x7007, 0x0003, 0x701f, 0x52f6, 0x0005, 0xa830, 0x9086,
+	0x0100, 0x2009, 0x0004, 0x0904, 0x5365, 0x7984, 0x7aa8, 0x9284,
+	0x1000, 0xe085, 0x080c, 0x558a, 0x0804, 0x34e8, 0x00c6, 0xaab0,
+	0x9284, 0xc000, 0x0148, 0xd2ec, 0x0170, 0x080c, 0x55ef, 0x1158,
+	0x2009, 0x0014, 0x0804, 0x5354, 0x2061, 0x1800, 0x080c, 0x55ef,
+	0x2009, 0x0007, 0x15c8, 0xd2f4, 0x0130, 0x9284, 0x5000, 0xc0d5,
+	0x080c, 0x55b5, 0x0058, 0xd2fc, 0x0180, 0x080c, 0x4af0, 0x0590,
+	0xa998, 0x9284, 0x9000, 0xc0d5, 0x080c, 0x558a, 0xa87b, 0x0000,
+	0xa883, 0x0000, 0xa897, 0x4000, 0x0438, 0x080c, 0x4af0, 0x0510,
+	0x080c, 0x67c3, 0x2009, 0x0009, 0x11b8, 0xa8c4, 0x9086, 0x0500,
+	0x11c8, 0xa8c8, 0x9005, 0x11b0, 0xa8cc, 0x9084, 0xff00, 0x1190,
+	0x080c, 0x4af0, 0x1108, 0x0070, 0x2009, 0x004b, 0x080c, 0xc31c,
+	0x2009, 0x0003, 0x0108, 0x0078, 0x0431, 0x19c0, 0xa897, 0x4005,
+	0xa99a, 0x0010, 0xa897, 0x4006, 0x900e, 0x9085, 0x0001, 0x2001,
+	0x0030, 0x00ce, 0x0005, 0x9006, 0x0ce0, 0x7aa8, 0xd2dc, 0x0904,
+	0x351a, 0x0016, 0x7984, 0x9284, 0x1000, 0xc0fd, 0x080c, 0x558a,
+	0x001e, 0x1904, 0x351a, 0x0804, 0x34e8, 0x00f6, 0x2d78, 0xaab0,
+	0x0021, 0x00fe, 0x0005, 0xaab0, 0xc2d5, 0xd2dc, 0x0150, 0x0016,
+	0xa998, 0x9284, 0x1400, 0xc0fd, 0x080c, 0x558a, 0x001e, 0x9085,
+	0x0001, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x351a,
+	0x080c, 0x55ef, 0x0120, 0x2009, 0x0007, 0x0804, 0x351a, 0x7984,
+	0x7ea8, 0x96b4, 0x00ff, 0x080c, 0x649f, 0x1904, 0x351d, 0x9186,
+	0x007f, 0x0138, 0x080c, 0x67c3, 0x0120, 0x2009, 0x0009, 0x0804,
+	0x351a, 0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804, 0x351a,
+	0xa867, 0x0000, 0xa868, 0xc0fd, 0xa86a, 0x2001, 0x0100, 0x8007,
+	0xa80a, 0x080c, 0xc01c, 0x1120, 0x2009, 0x0003, 0x0804, 0x351a,
+	0x7007, 0x0003, 0x701f, 0x53c5, 0x0005, 0xa808, 0x8007, 0x9086,
+	0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x351a, 0xa8e0, 0xa866,
+	0xa810, 0x8007, 0x9084, 0x00ff, 0x800c, 0xa814, 0x8007, 0x9084,
+	0x00ff, 0x8004, 0x9080, 0x0002, 0x9108, 0x8906, 0x8006, 0x8007,
+	0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0004, 0x7a8c, 0x7b88,
+	0x7c9c, 0x7d98, 0x0804, 0x4b0b, 0x080c, 0x4abf, 0x1120, 0x2009,
+	0x0002, 0x0804, 0x351a, 0x7984, 0x9194, 0xff00, 0x918c, 0x00ff,
+	0x8217, 0x82ff, 0x1118, 0x7023, 0x198b, 0x0040, 0x92c6, 0x0001,
+	0x1118, 0x7023, 0x19a5, 0x0010, 0x0804, 0x351d, 0x2009, 0x001a,
+	0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080, 0x0019, 0xaf60,
+	0x080c, 0x4b08, 0x701f, 0x5415, 0x0005, 0x2001, 0x182d, 0x2003,
+	0x0001, 0xa85c, 0x9080, 0x0019, 0x2098, 0xa860, 0x20e0, 0x20a9,
+	0x001a, 0x7020, 0x20a0, 0x20e9, 0x0001, 0x4003, 0x0804, 0x34e8,
+	0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804, 0x351a, 0x7984,
+	0x9194, 0xff00, 0x918c, 0x00ff, 0x8217, 0x82ff, 0x1118, 0x2099,
+	0x198b, 0x0040, 0x92c6, 0x0001, 0x1118, 0x2099, 0x19a5, 0x0010,
+	0x0804, 0x351d, 0xa85c, 0x9080, 0x0019, 0x20a0, 0xa860, 0x20e8,
+	0x20a9, 0x001a, 0x20e1, 0x0001, 0x4003, 0x2009, 0x001a, 0x7a8c,
+	0x7b88, 0x7c9c, 0x7d98, 0xa85c, 0x9080, 0x0019, 0xaf60, 0x0804,
+	0x4b0b, 0x7884, 0x908a, 0x1000, 0x1a04, 0x351d, 0x0126, 0x2091,
+	0x8000, 0x8003, 0x800b, 0x810b, 0x9108, 0x00c6, 0x2061, 0x19d2,
+	0x6142, 0x00ce, 0x012e, 0x0804, 0x34e8, 0x00c6, 0x080c, 0x7207,
+	0x1160, 0x080c, 0x7504, 0x080c, 0x5f2b, 0x9085, 0x0001, 0x080c,
+	0x724e, 0x080c, 0x7127, 0x080c, 0x0dfa, 0x2061, 0x1800, 0x6030,
+	0xc09d, 0x6032, 0x080c, 0x5dea, 0x00ce, 0x0005, 0x00c6, 0x2001,
+	0x1800, 0x2004, 0x908e, 0x0000, 0x0904, 0x351a, 0x7884, 0x9005,
+	0x0188, 0x7888, 0x2061, 0x1974, 0x2c0c, 0x2062, 0x080c, 0x2b98,
+	0x01a0, 0x080c, 0x2ba0, 0x0188, 0x080c, 0x2ba8, 0x0170, 0x2162,
+	0x0804, 0x351d, 0x2061, 0x0100, 0x6038, 0x9086, 0x0007, 0x1118,
+	0x2009, 0x0001, 0x0010, 0x2009, 0x0000, 0x7884, 0x9086, 0x0002,
+	0x1568, 0x2061, 0x0100, 0x6028, 0xc09c, 0x602a, 0x0026, 0x2011,
+	0x0003, 0x080c, 0x9a0f, 0x2011, 0x0002, 0x080c, 0x9a19, 0x002e,
+	0x080c, 0x9927, 0x0036, 0x901e, 0x080c, 0x999d, 0x003e, 0x60e3,
+	0x0000, 0x080c, 0xdc13, 0x080c, 0xdc2e, 0x9085, 0x0001, 0x080c,
+	0x724e, 0x9006, 0x080c, 0x2c88, 0x2001, 0x1800, 0x2003, 0x0004,
+	0x2001, 0x197f, 0x2003, 0x0000, 0x6027, 0x0008, 0x00ce, 0x0804,
+	0x34e8, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804, 0x351a, 0x080c,
+	0x55ef, 0x0120, 0x2009, 0x0007, 0x0804, 0x351a, 0x7984, 0x7ea8,
+	0x96b4, 0x00ff, 0x080c, 0x649f, 0x1904, 0x351d, 0x9186, 0x007f,
+	0x0138, 0x080c, 0x67c3, 0x0120, 0x2009, 0x0009, 0x0804, 0x351a,
+	0x080c, 0x4abf, 0x1120, 0x2009, 0x0002, 0x0804, 0x351a, 0xa867,
+	0x0000, 0xa868, 0xc0fd, 0xa86a, 0x080c, 0xc01f, 0x1120, 0x2009,
+	0x0003, 0x0804, 0x351a, 0x7007, 0x0003, 0x701f, 0x5518, 0x0005,
+	0xa830, 0x9086, 0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x351a,
+	0xa8e0, 0xa866, 0xa834, 0x8007, 0x800c, 0xa85c, 0x9080, 0x000c,
+	0x7a8c, 0x7b88, 0x7c9c, 0x7d98, 0xaf60, 0x0804, 0x4b0b, 0xa898,
+	0x9086, 0x000d, 0x1904, 0x351a, 0x2021, 0x4005, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x553c, 0x0010, 0x012e, 0x0cc0, 0x7c36, 0x9486,
+	0x4000, 0x0118, 0x7833, 0x0011, 0x0010, 0x7833, 0x0010, 0x7883,
+	0x4005, 0xa998, 0x7986, 0xa9a4, 0x799a, 0xa9a8, 0x799e, 0x080c,
+	0x4afb, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x11e0, 0x7007, 0x0001, 0x2091, 0x5000, 0x700f, 0x0000, 0x012e,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x00c6, 0x2061, 0x19d2, 0x7984,
+	0x6152, 0x614e, 0x6057, 0x0000, 0x604b, 0x0009, 0x7898, 0x606a,
+	0x789c, 0x6066, 0x7888, 0x6062, 0x788c, 0x605e, 0x2001, 0x19e0,
+	0x2044, 0x2001, 0x19e7, 0xa076, 0xa060, 0xa072, 0xa07b, 0x0001,
+	0xa07f, 0x0002, 0xa06b, 0x0000, 0xa09f, 0x0000, 0x00ce, 0x012e,
+	0x0804, 0x34e8, 0x0126, 0x2091, 0x8000, 0x00b6, 0x00c6, 0x90e4,
+	0xc000, 0x0168, 0x0006, 0xd0d4, 0x0130, 0x0036, 0x2019, 0x0029,
+	0x080c, 0x32a4, 0x003e, 0x080c, 0xbe84, 0x000e, 0x1198, 0xd0e4,
+	0x0160, 0x9180, 0x1000, 0x2004, 0x905d, 0x0160, 0x080c, 0x5f45,
+	0x080c, 0xa062, 0x0110, 0xb817, 0x0000, 0x9006, 0x00ce, 0x00be,
+	0x012e, 0x0005, 0x9085, 0x0001, 0x0cc8, 0x0126, 0x2091, 0x8000,
+	0x0156, 0x2010, 0x900e, 0x20a9, 0x0800, 0x0016, 0x9180, 0x1000,
+	0x2004, 0x9005, 0x0188, 0x9186, 0x007e, 0x0170, 0x9186, 0x007f,
+	0x0158, 0x9186, 0x0080, 0x0140, 0x9186, 0x00ff, 0x0128, 0x0026,
+	0x2200, 0x080c, 0x558a, 0x002e, 0x001e, 0x8108, 0x1f04, 0x55bd,
+	0x015e, 0x012e, 0x0005, 0x2001, 0x185c, 0x2004, 0x0005, 0x2001,
+	0x187b, 0x2004, 0x0005, 0x0006, 0x2001, 0x1810, 0x2004, 0xd0d4,
+	0x000e, 0x0005, 0x2001, 0x180e, 0x2004, 0xd0b4, 0x0005, 0x2001,
+	0x1800, 0x2004, 0x9086, 0x0003, 0x0005, 0x0016, 0x00e6, 0x2071,
+	0x189c, 0x7108, 0x910d, 0x710a, 0x00ee, 0x001e, 0x0005, 0x79a4,
+	0x9182, 0x0081, 0x1a04, 0x351d, 0x810c, 0x0016, 0x080c, 0x4abf,
+	0x0170, 0x080c, 0x0f39, 0x2100, 0x2238, 0x7d84, 0x7c88, 0x7b8c,
+	0x7a90, 0x001e, 0x080c, 0x4b08, 0x701f, 0x561b, 0x0005, 0x2009,
+	0x0002, 0x0804, 0x351a, 0x2079, 0x0000, 0x7d94, 0x7c98, 0x7ba8,
+	0x7aac, 0x79a4, 0x810c, 0x2061, 0x18b6, 0x2c44, 0xa770, 0xa074,
+	0x2071, 0x189c, 0x080c, 0x4b0b, 0x701f, 0x562f, 0x0005, 0x2061,
+	0x18b6, 0x2c44, 0x0016, 0x0026, 0xa270, 0xa174, 0x080c, 0x0f41,
+	0x002e, 0x001e, 0x080c, 0x0fee, 0x9006, 0xa802, 0xa806, 0x0804,
+	0x34e8, 0x0126, 0x0156, 0x0136, 0x0146, 0x01c6, 0x01d6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x2061, 0x0100, 0x2069, 0x0200, 0x2071,
+	0x1800, 0x6044, 0xd0a4, 0x11e8, 0xd084, 0x0118, 0x080c, 0x57ea,
+	0x0068, 0xd08c, 0x0118, 0x080c, 0x56f3, 0x0040, 0xd094, 0x0118,
+	0x080c, 0x56c3, 0x0018, 0xd09c, 0x0108, 0x0099, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, 0x012e,
+	0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e,
+	0x0c68, 0x0006, 0x7094, 0x9005, 0x000e, 0x0120, 0x7097, 0x0000,
+	0x708f, 0x0000, 0x624c, 0x9286, 0xf0f0, 0x1150, 0x6048, 0x9086,
+	0xf0f0, 0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0490,
+	0x9294, 0xff00, 0x9296, 0xf700, 0x0178, 0x7138, 0xd1a4, 0x1160,
+	0x6240, 0x9295, 0x0100, 0x6242, 0x9294, 0x0010, 0x0128, 0x2009,
+	0x00f7, 0x080c, 0x5ea7, 0x00f0, 0x6040, 0x9084, 0x0010, 0x9085,
+	0x0140, 0x6042, 0x6043, 0x0000, 0x7083, 0x0000, 0x709f, 0x0001,
+	0x70c3, 0x0000, 0x70db, 0x0000, 0x2009, 0x1c80, 0x200b, 0x0000,
+	0x7093, 0x0000, 0x7087, 0x000f, 0x2009, 0x000f, 0x2011, 0x5d8d,
+	0x080c, 0x836c, 0x0005, 0x2001, 0x187d, 0x2004, 0xd08c, 0x0110,
+	0x705b, 0xffff, 0x7084, 0x9005, 0x1528, 0x2011, 0x5d8d, 0x080c,
+	0x82da, 0x6040, 0x9094, 0x0010, 0x9285, 0x0020, 0x6042, 0x20a9,
+	0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04, 0x56d9, 0x6242, 0x7097,
+	0x0000, 0x6040, 0x9094, 0x0010, 0x9285, 0x0080, 0x6042, 0x6242,
+	0x0048, 0x6242, 0x7097, 0x0000, 0x708b, 0x0000, 0x9006, 0x080c,
+	0x5f30, 0x0000, 0x0005, 0x7088, 0x908a, 0x0003, 0x1a0c, 0x0dfa,
+	0x000b, 0x0005, 0x56fd, 0x574e, 0x57e9, 0x00f6, 0x0016, 0x6900,
+	0x918c, 0x0800, 0x708b, 0x0001, 0x2001, 0x015d, 0x2003, 0x0000,
+	0x6803, 0x00fc, 0x20a9, 0x0004, 0x6800, 0x9084, 0x00fc, 0x0120,
+	0x1f04, 0x570c, 0x080c, 0x0dfa, 0x68a0, 0x68a2, 0x689c, 0x689e,
+	0x6898, 0x689a, 0xa001, 0x918d, 0x1600, 0x6902, 0x001e, 0x6837,
+	0x0020, 0x080c, 0x5f0c, 0x2079, 0x1c00, 0x7833, 0x1101, 0x7837,
+	0x0000, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0001, 0x20a1,
+	0x1c0e, 0x20a9, 0x0004, 0x4003, 0x080c, 0x9eeb, 0x20e1, 0x0001,
+	0x2099, 0x1c00, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x0014,
+	0x4003, 0x60c3, 0x000c, 0x600f, 0x0000, 0x080c, 0x5dbe, 0x00fe,
+	0x9006, 0x708e, 0x6043, 0x0008, 0x6042, 0x0005, 0x00f6, 0x708c,
+	0x708f, 0x0000, 0x9025, 0x0904, 0x57c6, 0x6020, 0xd0b4, 0x1904,
+	0x57c4, 0x719c, 0x81ff, 0x0904, 0x57b2, 0x9486, 0x000c, 0x1904,
+	0x57bf, 0x9480, 0x0018, 0x8004, 0x20a8, 0x080c, 0x5f05, 0x2011,
+	0x0260, 0x2019, 0x1c00, 0x220c, 0x2304, 0x9106, 0x11e8, 0x8210,
+	0x8318, 0x1f04, 0x576b, 0x6043, 0x0004, 0x2061, 0x0140, 0x605b,
+	0xbc94, 0x605f, 0xf0f0, 0x2061, 0x0100, 0x6043, 0x0006, 0x708b,
+	0x0002, 0x7097, 0x0002, 0x2009, 0x07d0, 0x2011, 0x5d94, 0x080c,
+	0x836c, 0x080c, 0x5f0c, 0x04c0, 0x080c, 0x5f05, 0x2079, 0x0260,
+	0x7930, 0x918e, 0x1101, 0x1558, 0x7834, 0x9005, 0x1540, 0x7900,
+	0x918c, 0x00ff, 0x1118, 0x7804, 0x9005, 0x0190, 0x080c, 0x5f05,
+	0x2011, 0x026e, 0x2019, 0x1805, 0x20a9, 0x0004, 0x220c, 0x2304,
+	0x9102, 0x0230, 0x11a0, 0x8210, 0x8318, 0x1f04, 0x57a6, 0x0078,
+	0x709f, 0x0000, 0x080c, 0x5f05, 0x20e1, 0x0000, 0x2099, 0x0260,
+	0x20e9, 0x0001, 0x20a1, 0x1c00, 0x20a9, 0x0014, 0x4003, 0x6043,
+	0x0008, 0x6043, 0x0000, 0x0010, 0x00fe, 0x0005, 0x6040, 0x9085,
+	0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x080c, 0x9eeb, 0x20e1,
+	0x0001, 0x2099, 0x1c00, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9,
+	0x0014, 0x4003, 0x60c3, 0x000c, 0x2011, 0x19c9, 0x2013, 0x0000,
+	0x708f, 0x0000, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x964d,
+	0x08d8, 0x0005, 0x7094, 0x908a, 0x001d, 0x1a0c, 0x0dfa, 0x000b,
+	0x0005, 0x581b, 0x582e, 0x5857, 0x5877, 0x589d, 0x58cc, 0x58f2,
+	0x592a, 0x5950, 0x597e, 0x59b9, 0x59f1, 0x5a0f, 0x5a3a, 0x5a5c,
+	0x5a77, 0x5a81, 0x5ab5, 0x5adb, 0x5b0a, 0x5b30, 0x5b68, 0x5bac,
+	0x5be9, 0x5c0a, 0x5c63, 0x5c85, 0x5cb3, 0x5cb3, 0x00c6, 0x2061,
+	0x1800, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0x9084, 0xfff9,
+	0x6006, 0x00ce, 0x0005, 0x2061, 0x0140, 0x605b, 0xbc94, 0x605f,
+	0xf0f0, 0x2061, 0x0100, 0x6043, 0x0002, 0x7097, 0x0001, 0x2009,
+	0x07d0, 0x2011, 0x5d94, 0x080c, 0x836c, 0x0005, 0x00f6, 0x708c,
+	0x9086, 0x0014, 0x1510, 0x6042, 0x6020, 0xd0b4, 0x11f0, 0x080c,
+	0x5f05, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1102, 0x11a0, 0x7834,
+	0x9005, 0x1188, 0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110,
+	0x70c3, 0x0001, 0x2011, 0x5d94, 0x080c, 0x82da, 0x7097, 0x0010,
+	0x080c, 0x5a81, 0x0010, 0x708f, 0x0000, 0x00fe, 0x0005, 0x00f6,
+	0x7097, 0x0003, 0x6043, 0x0004, 0x2011, 0x5d94, 0x080c, 0x82da,
+	0x080c, 0x5e89, 0x2079, 0x0240, 0x7833, 0x1102, 0x7837, 0x0000,
+	0x20a9, 0x0008, 0x9f88, 0x000e, 0x200b, 0x0000, 0x8108, 0x1f04,
+	0x586c, 0x60c3, 0x0014, 0x080c, 0x5dbe, 0x00fe, 0x0005, 0x00f6,
+	0x708c, 0x9005, 0x0500, 0x2011, 0x5d94, 0x080c, 0x82da, 0x9086,
+	0x0014, 0x11b8, 0x080c, 0x5f05, 0x2079, 0x0260, 0x7a30, 0x9296,
+	0x1102, 0x1178, 0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128,
+	0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001, 0x7097, 0x0004, 0x0029,
+	0x0010, 0x080c, 0x5ee1, 0x00fe, 0x0005, 0x00f6, 0x7097, 0x0005,
+	0x080c, 0x5e89, 0x2079, 0x0240, 0x7833, 0x1103, 0x7837, 0x0000,
+	0x080c, 0x5f05, 0x080c, 0x5ee8, 0x1170, 0x7080, 0x9005, 0x1158,
+	0x7158, 0x9186, 0xffff, 0x0138, 0x2011, 0x0008, 0x080c, 0x5d41,
+	0x0168, 0x080c, 0x5ebe, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099,
+	0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014,
+	0x080c, 0x5dbe, 0x00fe, 0x0005, 0x00f6, 0x708c, 0x9005, 0x0500,
+	0x2011, 0x5d94, 0x080c, 0x82da, 0x9086, 0x0014, 0x11b8, 0x080c,
+	0x5f05, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178, 0x7834,
+	0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110,
+	0x70c3, 0x0001, 0x7097, 0x0006, 0x0029, 0x0010, 0x080c, 0x5ee1,
+	0x00fe, 0x0005, 0x00f6, 0x7097, 0x0007, 0x080c, 0x5e89, 0x2079,
+	0x0240, 0x7833, 0x1104, 0x7837, 0x0000, 0x080c, 0x5f05, 0x080c,
+	0x5ee8, 0x11b8, 0x7080, 0x9005, 0x11a0, 0x7160, 0x9186, 0xffff,
+	0x0180, 0x9180, 0x32e9, 0x200d, 0x918c, 0xff00, 0x810f, 0x2011,
+	0x0008, 0x080c, 0x5d41, 0x0180, 0x080c, 0x4ed8, 0x0110, 0x080c,
+	0x27d7, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9,
+	0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5dbe,
+	0x00fe, 0x0005, 0x00f6, 0x708c, 0x9005, 0x0500, 0x2011, 0x5d94,
+	0x080c, 0x82da, 0x9086, 0x0014, 0x11b8, 0x080c, 0x5f05, 0x2079,
+	0x0260, 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, 0x1160,
+	0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001,
+	0x7097, 0x0008, 0x0029, 0x0010, 0x080c, 0x5ee1, 0x00fe, 0x0005,
+	0x00f6, 0x7097, 0x0009, 0x080c, 0x5e89, 0x2079, 0x0240, 0x7833,
+	0x1105, 0x7837, 0x0100, 0x080c, 0x5ee8, 0x1150, 0x7080, 0x9005,
+	0x1138, 0x080c, 0x5cb4, 0x1188, 0x9085, 0x0001, 0x080c, 0x27d7,
+	0x20a9, 0x0008, 0x080c, 0x5f05, 0x20e1, 0x0000, 0x2099, 0x026e,
+	0x20e9, 0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c,
+	0x5dbe, 0x0010, 0x080c, 0x580e, 0x00fe, 0x0005, 0x00f6, 0x708c,
+	0x9005, 0x05a8, 0x2011, 0x5d94, 0x080c, 0x82da, 0x9086, 0x0014,
+	0x1560, 0x080c, 0x5f05, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1105,
+	0x1520, 0x7834, 0x9084, 0x0100, 0x2011, 0x0100, 0x921e, 0x1160,
+	0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001,
+	0x7097, 0x000a, 0x00b1, 0x0098, 0x9005, 0x1178, 0x7a38, 0xd2fc,
+	0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001, 0x7093, 0x0000,
+	0x7097, 0x000e, 0x080c, 0x5a5c, 0x0010, 0x080c, 0x5ee1, 0x00fe,
+	0x0005, 0x00f6, 0x7097, 0x000b, 0x2011, 0x1c0e, 0x20e9, 0x0001,
+	0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff, 0x4304, 0x080c, 0x5e89,
+	0x2079, 0x0240, 0x7833, 0x1106, 0x7837, 0x0000, 0x080c, 0x5ee8,
+	0x0118, 0x2013, 0x0000, 0x0020, 0x705c, 0x9085, 0x0100, 0x2012,
+	0x20a9, 0x0040, 0x2009, 0x024e, 0x2011, 0x1c0e, 0x220e, 0x8210,
+	0x8108, 0x9186, 0x0260, 0x1128, 0x6810, 0x8000, 0x6812, 0x2009,
+	0x0240, 0x1f04, 0x59de, 0x60c3, 0x0084, 0x080c, 0x5dbe, 0x00fe,
+	0x0005, 0x00f6, 0x708c, 0x9005, 0x01c0, 0x2011, 0x5d94, 0x080c,
+	0x82da, 0x9086, 0x0084, 0x1178, 0x080c, 0x5f05, 0x2079, 0x0260,
+	0x7a30, 0x9296, 0x1106, 0x1138, 0x7834, 0x9005, 0x1120, 0x7097,
+	0x000c, 0x0029, 0x0010, 0x080c, 0x5ee1, 0x00fe, 0x0005, 0x00f6,
+	0x7097, 0x000d, 0x080c, 0x5e89, 0x2079, 0x0240, 0x7833, 0x1107,
+	0x7837, 0x0000, 0x080c, 0x5f05, 0x20a9, 0x0040, 0x2011, 0x026e,
+	0x2009, 0x024e, 0x220e, 0x8210, 0x8108, 0x9186, 0x0260, 0x1150,
+	0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x6814, 0x8000, 0x6816,
+	0x2011, 0x0260, 0x1f04, 0x5a22, 0x60c3, 0x0084, 0x080c, 0x5dbe,
+	0x00fe, 0x0005, 0x00f6, 0x708c, 0x9005, 0x01e0, 0x2011, 0x5d94,
+	0x080c, 0x82da, 0x9086, 0x0084, 0x1198, 0x080c, 0x5f05, 0x2079,
+	0x0260, 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834, 0x9005, 0x1140,
+	0x7093, 0x0001, 0x080c, 0x5e5b, 0x7097, 0x000e, 0x0029, 0x0010,
+	0x080c, 0x5ee1, 0x00fe, 0x0005, 0x918d, 0x0001, 0x080c, 0x5f30,
+	0x7097, 0x000f, 0x708f, 0x0000, 0x2061, 0x0140, 0x605b, 0xbc85,
+	0x605f, 0xb5b5, 0x2061, 0x0100, 0x6043, 0x0005, 0x6043, 0x0004,
+	0x2009, 0x07d0, 0x2011, 0x5d94, 0x080c, 0x82ce, 0x0005, 0x708c,
+	0x9005, 0x0130, 0x2011, 0x5d94, 0x080c, 0x82da, 0x7097, 0x0000,
+	0x0005, 0x7097, 0x0011, 0x080c, 0x9eeb, 0x080c, 0x5f05, 0x20e1,
+	0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x748c,
+	0x9480, 0x0018, 0x9080, 0x0007, 0x9084, 0x03f8, 0x8004, 0x20a8,
+	0x4003, 0x080c, 0x5ee8, 0x11a0, 0x7178, 0x81ff, 0x0188, 0x900e,
+	0x707c, 0x9084, 0x00ff, 0x0160, 0x080c, 0x276e, 0x9186, 0x007e,
+	0x0138, 0x9186, 0x0080, 0x0120, 0x2011, 0x0008, 0x080c, 0x5d41,
+	0x60c3, 0x0014, 0x080c, 0x5dbe, 0x0005, 0x00f6, 0x708c, 0x9005,
+	0x0500, 0x2011, 0x5d94, 0x080c, 0x82da, 0x9086, 0x0014, 0x11b8,
+	0x080c, 0x5f05, 0x2079, 0x0260, 0x7a30, 0x9296, 0x1103, 0x1178,
+	0x7834, 0x9005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005,
+	0x1110, 0x70c3, 0x0001, 0x7097, 0x0012, 0x0029, 0x0010, 0x708f,
+	0x0000, 0x00fe, 0x0005, 0x00f6, 0x7097, 0x0013, 0x080c, 0x5e97,
+	0x2079, 0x0240, 0x7833, 0x1103, 0x7837, 0x0000, 0x080c, 0x5f05,
+	0x080c, 0x5ee8, 0x1170, 0x7080, 0x9005, 0x1158, 0x7158, 0x9186,
+	0xffff, 0x0138, 0x2011, 0x0008, 0x080c, 0x5d41, 0x0168, 0x080c,
+	0x5ebe, 0x20a9, 0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9,
+	0x0000, 0x20a1, 0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5dbe,
+	0x00fe, 0x0005, 0x00f6, 0x708c, 0x9005, 0x0500, 0x2011, 0x5d94,
+	0x080c, 0x82da, 0x9086, 0x0014, 0x11b8, 0x080c, 0x5f05, 0x2079,
+	0x0260, 0x7a30, 0x9296, 0x1104, 0x1178, 0x7834, 0x9005, 0x1160,
+	0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001,
+	0x7097, 0x0014, 0x0029, 0x0010, 0x708f, 0x0000, 0x00fe, 0x0005,
+	0x00f6, 0x7097, 0x0015, 0x080c, 0x5e97, 0x2079, 0x0240, 0x7833,
+	0x1104, 0x7837, 0x0000, 0x080c, 0x5f05, 0x080c, 0x5ee8, 0x11b8,
+	0x7080, 0x9005, 0x11a0, 0x7160, 0x9186, 0xffff, 0x0180, 0x9180,
+	0x32e9, 0x200d, 0x918c, 0xff00, 0x810f, 0x2011, 0x0008, 0x080c,
+	0x5d41, 0x0180, 0x080c, 0x4ed8, 0x0110, 0x080c, 0x27d7, 0x20a9,
+	0x0008, 0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1,
+	0x024e, 0x4003, 0x60c3, 0x0014, 0x080c, 0x5dbe, 0x00fe, 0x0005,
+	0x00f6, 0x708c, 0x9005, 0x05f0, 0x2011, 0x5d94, 0x080c, 0x82da,
+	0x9086, 0x0014, 0x15a8, 0x080c, 0x5f05, 0x2079, 0x0260, 0x7a30,
+	0x9296, 0x1105, 0x1568, 0x7834, 0x9084, 0x0100, 0x2011, 0x0100,
+	0x921e, 0x1168, 0x9085, 0x0001, 0x080c, 0x5f30, 0x7a38, 0xd2fc,
+	0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3, 0x0001, 0x0080, 0x9005,
+	0x11b8, 0x7a38, 0xd2fc, 0x0128, 0x70c0, 0x9005, 0x1110, 0x70c3,
+	0x0001, 0x9085, 0x0001, 0x080c, 0x5f30, 0x7093, 0x0000, 0x7a38,
+	0xd2f4, 0x0110, 0x70db, 0x0008, 0x7097, 0x0016, 0x0029, 0x0010,
+	0x708f, 0x0000, 0x00fe, 0x0005, 0x080c, 0x9eeb, 0x080c, 0x5f05,
+	0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9, 0x0000, 0x20a1, 0x0240,
+	0x20a9, 0x000e, 0x4003, 0x2011, 0x026d, 0x2204, 0x9084, 0x0100,
+	0x2011, 0x024d, 0x2012, 0x2011, 0x026e, 0x7097, 0x0017, 0x080c,
+	0x5ee8, 0x1150, 0x7080, 0x9005, 0x1138, 0x080c, 0x5cb4, 0x1188,
+	0x9085, 0x0001, 0x080c, 0x27d7, 0x20a9, 0x0008, 0x080c, 0x5f05,
+	0x20e1, 0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x20a1, 0x024e,
+	0x4003, 0x60c3, 0x0014, 0x080c, 0x5dbe, 0x0010, 0x080c, 0x580e,
+	0x0005, 0x00f6, 0x708c, 0x9005, 0x01d8, 0x2011, 0x5d94, 0x080c,
+	0x82da, 0x9086, 0x0084, 0x1190, 0x080c, 0x5f05, 0x2079, 0x0260,
+	0x7a30, 0x9296, 0x1106, 0x1150, 0x7834, 0x9005, 0x1138, 0x9006,
+	0x080c, 0x5f30, 0x7097, 0x0018, 0x0029, 0x0010, 0x708f, 0x0000,
+	0x00fe, 0x0005, 0x00f6, 0x7097, 0x0019, 0x080c, 0x5e97, 0x2079,
+	0x0240, 0x7833, 0x1106, 0x7837, 0x0000, 0x080c, 0x5f05, 0x2009,
+	0x026e, 0x2039, 0x1c0e, 0x20a9, 0x0040, 0x213e, 0x8738, 0x8108,
+	0x9186, 0x0280, 0x1128, 0x6814, 0x8000, 0x6816, 0x2009, 0x0260,
+	0x1f04, 0x5c1d, 0x2039, 0x1c0e, 0x080c, 0x5ee8, 0x11e8, 0x2728,
+	0x2514, 0x8207, 0x9084, 0x00ff, 0x8000, 0x2018, 0x9294, 0x00ff,
+	0x8007, 0x9205, 0x202a, 0x705c, 0x2310, 0x8214, 0x92a0, 0x1c0e,
+	0x2414, 0x938c, 0x0001, 0x0118, 0x9294, 0xff00, 0x0018, 0x9294,
+	0x00ff, 0x8007, 0x9215, 0x2222, 0x20a9, 0x0040, 0x2009, 0x024e,
+	0x270e, 0x8738, 0x8108, 0x9186, 0x0260, 0x1128, 0x6810, 0x8000,
+	0x6812, 0x2009, 0x0240, 0x1f04, 0x5c50, 0x60c3, 0x0084, 0x080c,
+	0x5dbe, 0x00fe, 0x0005, 0x00f6, 0x708c, 0x9005, 0x01e0, 0x2011,
+	0x5d94, 0x080c, 0x82da, 0x9086, 0x0084, 0x1198, 0x080c, 0x5f05,
+	0x2079, 0x0260, 0x7a30, 0x9296, 0x1107, 0x1158, 0x7834, 0x9005,
+	0x1140, 0x7093, 0x0001, 0x080c, 0x5e5b, 0x7097, 0x001a, 0x0029,
+	0x0010, 0x708f, 0x0000, 0x00fe, 0x0005, 0x9085, 0x0001, 0x080c,
+	0x5f30, 0x7097, 0x001b, 0x080c, 0x9eeb, 0x080c, 0x5f05, 0x2011,
+	0x0260, 0x2009, 0x0240, 0x748c, 0x9480, 0x0018, 0x9080, 0x0007,
+	0x9084, 0x03f8, 0x8004, 0x20a8, 0x220e, 0x8210, 0x8108, 0x9186,
+	0x0260, 0x1150, 0x6810, 0x8000, 0x6812, 0x2009, 0x0240, 0x6814,
+	0x8000, 0x6816, 0x2011, 0x0260, 0x1f04, 0x5c9c, 0x60c3, 0x0084,
+	0x080c, 0x5dbe, 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0x185c,
+	0x252c, 0x20a9, 0x0008, 0x2041, 0x1c0e, 0x20e9, 0x0001, 0x28a0,
+	0x080c, 0x5f05, 0x20e1, 0x0000, 0x2099, 0x026e, 0x4003, 0x20a9,
+	0x0008, 0x2011, 0x0007, 0xd5d4, 0x0108, 0x9016, 0x2800, 0x9200,
+	0x200c, 0x91a6, 0xffff, 0x1148, 0xd5d4, 0x0110, 0x8210, 0x0008,
+	0x8211, 0x1f04, 0x5cce, 0x0804, 0x5d3d, 0x82ff, 0x1160, 0xd5d4,
+	0x0120, 0x91a6, 0x3fff, 0x0d90, 0x0020, 0x91a6, 0x3fff, 0x0904,
+	0x5d3d, 0x918d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4,
+	0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0110, 0x8423, 0x0008,
+	0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319, 0x0008, 0x8318, 0x1f04,
+	0x5cf4, 0x04d8, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x1f04,
+	0x5d06, 0x2328, 0x8529, 0x92be, 0x0007, 0x0158, 0x0006, 0x2039,
+	0x0007, 0x2200, 0x973a, 0x000e, 0x27a8, 0x95a8, 0x0010, 0x1f04,
+	0x5d15, 0x755a, 0x95c8, 0x32e9, 0x292d, 0x95ac, 0x00ff, 0x757e,
+	0x6532, 0x6536, 0x0016, 0x2508, 0x080c, 0x27b7, 0x001e, 0x60e7,
+	0x0000, 0x65ea, 0x2018, 0x2304, 0x9405, 0x201a, 0x7083, 0x0001,
+	0x20e9, 0x0000, 0x20a1, 0x024e, 0x20e1, 0x0001, 0x2898, 0x20a9,
+	0x0008, 0x4003, 0x9085, 0x0001, 0x0008, 0x9006, 0x009e, 0x008e,
+	0x0005, 0x0156, 0x01c6, 0x01d6, 0x0136, 0x0146, 0x22a8, 0x20e1,
+	0x0000, 0x2099, 0x026e, 0x20e9, 0x0000, 0x2011, 0x024e, 0x22a0,
+	0x4003, 0x014e, 0x013e, 0x01de, 0x01ce, 0x015e, 0x2118, 0x9026,
+	0x2001, 0x0007, 0x939a, 0x0010, 0x0218, 0x8420, 0x8001, 0x0cd0,
+	0x2118, 0x84ff, 0x0120, 0x939a, 0x0010, 0x8421, 0x1de0, 0x2021,
+	0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8, 0x9238, 0x2029,
+	0x026e, 0x9528, 0x2504, 0x942c, 0x11b8, 0x9405, 0x203a, 0x715a,
+	0x91a0, 0x32e9, 0x242d, 0x95ac, 0x00ff, 0x757e, 0x6532, 0x6536,
+	0x0016, 0x2508, 0x080c, 0x27b7, 0x001e, 0x60e7, 0x0000, 0x65ea,
+	0x7083, 0x0001, 0x9084, 0x0000, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x7087, 0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100,
+	0x2071, 0x0140, 0x080c, 0x5e4a, 0x080c, 0x9656, 0x7004, 0x9084,
+	0x4000, 0x0110, 0x080c, 0x2c98, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x1825, 0x2073, 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7,
+	0x080c, 0x5ea7, 0x001e, 0x9094, 0x0010, 0x9285, 0x0080, 0x7842,
+	0x7a42, 0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x2afe, 0x0228, 0x2011, 0x0101, 0x2204, 0xc0c5,
+	0x2012, 0x2011, 0x19c9, 0x2013, 0x0000, 0x708f, 0x0000, 0x012e,
+	0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x964d, 0x6144, 0xd184,
+	0x0120, 0x7194, 0x918d, 0x2000, 0x0018, 0x7188, 0x918d, 0x1000,
+	0x2011, 0x1971, 0x2112, 0x2009, 0x07d0, 0x2011, 0x5d94, 0x080c,
+	0x836c, 0x0005, 0x0016, 0x0026, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xa069, 0x2009, 0x00f7, 0x080c, 0x5ea7, 0x2061, 0x19d2,
+	0x900e, 0x611a, 0x611e, 0x6172, 0x6176, 0x2061, 0x1800, 0x6003,
+	0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009,
+	0x1971, 0x200b, 0x0000, 0x2009, 0x002d, 0x2011, 0x5e16, 0x080c,
+	0x82ce, 0x012e, 0x00ce, 0x002e, 0x001e, 0x0005, 0x00e6, 0x0006,
+	0x0126, 0x2091, 0x8000, 0x0471, 0x2071, 0x0100, 0x080c, 0x9656,
+	0x2071, 0x0140, 0x7004, 0x9084, 0x4000, 0x0110, 0x080c, 0x2c98,
+	0x080c, 0x720f, 0x0188, 0x080c, 0x722a, 0x1170, 0x080c, 0x750e,
+	0x0016, 0x080c, 0x2886, 0x2001, 0x1945, 0x2102, 0x001e, 0x080c,
+	0x7509, 0x080c, 0x7127, 0x0050, 0x2009, 0x0001, 0x080c, 0x2bb6,
+	0x2001, 0x0001, 0x080c, 0x2717, 0x080c, 0x5dea, 0x012e, 0x000e,
+	0x00ee, 0x0005, 0x2001, 0x180e, 0x2004, 0xd0bc, 0x0158, 0x0026,
+	0x0036, 0x2011, 0x8017, 0x2001, 0x1971, 0x201c, 0x080c, 0x4b1f,
+	0x003e, 0x002e, 0x0005, 0x20a9, 0x0012, 0x20e9, 0x0001, 0x20a1,
+	0x1c80, 0x080c, 0x5f05, 0x20e9, 0x0000, 0x2099, 0x026e, 0x0099,
+	0x20a9, 0x0020, 0x080c, 0x5eff, 0x2099, 0x0260, 0x20a1, 0x1c92,
+	0x0051, 0x20a9, 0x000e, 0x080c, 0x5f02, 0x2099, 0x0260, 0x20a1,
+	0x1cb2, 0x0009, 0x0005, 0x0016, 0x0026, 0x3410, 0x3308, 0x2104,
+	0x8007, 0x2012, 0x8108, 0x8210, 0x1f04, 0x5e7f, 0x002e, 0x001e,
+	0x0005, 0x080c, 0x9eeb, 0x20e1, 0x0001, 0x2099, 0x1c00, 0x20e9,
+	0x0000, 0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x080c,
+	0x9eeb, 0x080c, 0x5f05, 0x20e1, 0x0000, 0x2099, 0x0260, 0x20e9,
+	0x0000, 0x20a1, 0x0240, 0x20a9, 0x000c, 0x4003, 0x0005, 0x00c6,
+	0x0006, 0x2061, 0x0100, 0x810f, 0x2001, 0x1833, 0x2004, 0x9005,
+	0x1138, 0x2001, 0x1817, 0x2004, 0x9084, 0x00ff, 0x9105, 0x0010,
+	0x9185, 0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046,
+	0x080c, 0x67bf, 0x0158, 0x9006, 0x2020, 0x2009, 0x002a, 0x080c,
+	0xd885, 0x2001, 0x180c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a,
+	0x900e, 0x080c, 0x3156, 0x080c, 0xc539, 0x0140, 0x0036, 0x2019,
+	0xffff, 0x2021, 0x0007, 0x080c, 0x4cbc, 0x003e, 0x004e, 0x001e,
+	0x0005, 0x080c, 0x5dea, 0x7097, 0x0000, 0x708f, 0x0000, 0x0005,
+	0x0006, 0x2001, 0x180c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005,
+	0x0006, 0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c,
+	0x918d, 0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x2009,
+	0x0001, 0x0020, 0x2009, 0x0002, 0x0008, 0x900e, 0x6814, 0x9084,
+	0xffc0, 0x910d, 0x6916, 0x0005, 0x00f6, 0x0156, 0x0146, 0x01d6,
+	0x9006, 0x20a9, 0x0080, 0x20e9, 0x0001, 0x20a1, 0x1c00, 0x4004,
+	0x2079, 0x1c00, 0x7803, 0x2200, 0x7807, 0x00ef, 0x780f, 0x00ef,
+	0x7813, 0x0138, 0x7823, 0xffff, 0x7827, 0xffff, 0x01de, 0x014e,
+	0x015e, 0x00fe, 0x0005, 0x2001, 0x1800, 0x2003, 0x0001, 0x0005,
+	0x2001, 0x197e, 0x0118, 0x2003, 0x0001, 0x0010, 0x2003, 0x0000,
+	0x0005, 0x0156, 0x20a9, 0x0800, 0x2009, 0x1000, 0x9006, 0x200a,
+	0x8108, 0x1f04, 0x5f3f, 0x015e, 0x0005, 0x00d6, 0x0036, 0x0156,
+	0x0136, 0x0146, 0x2069, 0x185b, 0x9006, 0xb802, 0xb8be, 0xb807,
+	0x0707, 0xb80a, 0xb80e, 0xb812, 0x9198, 0x32e9, 0x231d, 0x939c,
+	0x00ff, 0xbb16, 0x0016, 0x0026, 0xb8b2, 0x080c, 0xa062, 0x1120,
+	0x9192, 0x007e, 0x1208, 0xbbb2, 0x20a9, 0x0004, 0xb8b4, 0x20e8,
+	0xb9b8, 0x9198, 0x0006, 0x9006, 0x23a0, 0x4004, 0x20a9, 0x0004,
+	0x9198, 0x000a, 0x23a0, 0x4004, 0x002e, 0x001e, 0xb83e, 0xb842,
+	0xb84e, 0xb852, 0xb856, 0xb85a, 0xb85e, 0xb862, 0xb866, 0xb86a,
+	0xb86f, 0x0100, 0xb872, 0xb876, 0xb87a, 0xb88a, 0xb88e, 0xb893,
+	0x0008, 0xb896, 0xb89a, 0xb89e, 0xb8ae, 0xb9a2, 0x0096, 0xb8a4,
+	0x904d, 0x0110, 0x080c, 0x1063, 0xb8a7, 0x0000, 0x009e, 0x9006,
+	0xb84a, 0x6810, 0xb83a, 0x680c, 0xb846, 0x6814, 0x9084, 0x00ff,
+	0xb842, 0x014e, 0x013e, 0x015e, 0x003e, 0x00de, 0x0005, 0x0126,
+	0x2091, 0x8000, 0xa974, 0xae78, 0x9684, 0x3fff, 0x9082, 0x4000,
+	0x1a04, 0x6015, 0x9182, 0x0800, 0x1a04, 0x6019, 0x2001, 0x180c,
+	0x2004, 0x9084, 0x0003, 0x1904, 0x601f, 0x9188, 0x1000, 0x2104,
+	0x905d, 0x0518, 0xb804, 0x9084, 0x00ff, 0x908e, 0x0006, 0x1508,
+	0xb8a4, 0x900d, 0x1904, 0x6031, 0xb850, 0x900d, 0x1148, 0xa802,
+	0x2900, 0xb852, 0xb84e, 0x080c, 0x8696, 0x9006, 0x012e, 0x0005,
+	0x00a6, 0x2150, 0x2900, 0xb002, 0xa803, 0x0000, 0x00ae, 0xb852,
+	0x0c90, 0x2001, 0x0005, 0x900e, 0x04b8, 0x2001, 0x0028, 0x900e,
+	0x0498, 0x9082, 0x0006, 0x1290, 0x080c, 0xa062, 0x1160, 0xb8a0,
+	0x9084, 0xff80, 0x1140, 0xb900, 0xd1fc, 0x0990, 0x2001, 0x0029,
+	0x2009, 0x1000, 0x0408, 0x2001, 0x0028, 0x00a8, 0x2009, 0x180c,
+	0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0068, 0xd184, 0x0118,
+	0x2001, 0x0004, 0x0040, 0x2001, 0x0029, 0xb900, 0xd1fc, 0x0118,
+	0x2009, 0x1000, 0x0048, 0x900e, 0x0038, 0x2001, 0x0029, 0x900e,
+	0x0018, 0x2001, 0x0029, 0x900e, 0x9005, 0x012e, 0x0005, 0x2001,
+	0x180c, 0x2004, 0xd084, 0x19d0, 0x9188, 0x1000, 0x2104, 0x905d,
+	0x09a8, 0x080c, 0x67c3, 0x1990, 0xb800, 0xd0bc, 0x0978, 0x0804,
+	0x5fc8, 0x080c, 0x663b, 0x0904, 0x5fe1, 0x0804, 0x5fcc, 0x00b6,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0xa974, 0x9182, 0x0800, 0x1a04,
+	0x60b5, 0x9188, 0x1000, 0x2104, 0x905d, 0x0904, 0x608d, 0xb8a0,
+	0x9086, 0x007f, 0x0190, 0xa87c, 0xd0fc, 0x1178, 0x080c, 0x67cb,
+	0x0160, 0xa994, 0x81ff, 0x0130, 0x908e, 0x0004, 0x0130, 0x908e,
+	0x0005, 0x0118, 0x080c, 0x67c3, 0x1598, 0xa87c, 0xd0fc, 0x01e0,
+	0xa894, 0x9005, 0x01c8, 0x2060, 0x0026, 0x2010, 0x080c, 0xbe25,
+	0x002e, 0x1120, 0x2001, 0x0008, 0x0804, 0x60b7, 0x6020, 0x9086,
+	0x000a, 0x0120, 0x2001, 0x0008, 0x0804, 0x60b7, 0x601a, 0x6003,
+	0x0008, 0x2900, 0x6016, 0x0058, 0x080c, 0xa08d, 0x05e8, 0x2b00,
+	0x6012, 0x2900, 0x6016, 0x600b, 0xffff, 0x6023, 0x000a, 0x2009,
+	0x0003, 0x080c, 0xa15d, 0x9006, 0x0458, 0x2001, 0x0028, 0x0438,
+	0x9082, 0x0006, 0x1290, 0x080c, 0xa062, 0x1160, 0xb8a0, 0x9084,
+	0xff80, 0x1140, 0xb900, 0xd1fc, 0x0900, 0x2001, 0x0029, 0x2009,
+	0x1000, 0x00a8, 0x2001, 0x0028, 0x0090, 0x2009, 0x180c, 0x210c,
+	0xd18c, 0x0118, 0x2001, 0x0004, 0x0050, 0xd184, 0x0118, 0x2001,
+	0x0004, 0x0028, 0x2001, 0x0029, 0x0010, 0x2001, 0x0029, 0x9005,
+	0x012e, 0x00ee, 0x00be, 0x0005, 0x2001, 0x002c, 0x0cc0, 0x00f6,
+	0x00b6, 0x0126, 0x2091, 0x8000, 0xa8e0, 0x9005, 0x1550, 0xa8dc,
+	0x9082, 0x0101, 0x1630, 0xa8c8, 0x9005, 0x1518, 0xa8c4, 0x9082,
+	0x0101, 0x12f8, 0xa974, 0x2079, 0x1800, 0x9182, 0x0800, 0x12e8,
+	0x7830, 0x9084, 0x0003, 0x1130, 0xaa98, 0xab94, 0xa878, 0x9084,
+	0x0007, 0x00ea, 0x7930, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e,
+	0x0038, 0x2001, 0x002c, 0x900e, 0x0018, 0x2001, 0x0029, 0x900e,
+	0x9006, 0x0008, 0x9005, 0x012e, 0x00be, 0x00fe, 0x0005, 0x614c,
+	0x6107, 0x611e, 0x614c, 0x614c, 0x614c, 0x614c, 0x614c, 0x2100,
+	0x9082, 0x007e, 0x1278, 0x080c, 0x643f, 0x0148, 0x9046, 0xb810,
+	0x9306, 0x1904, 0x6154, 0xb814, 0x9206, 0x15f0, 0x0028, 0xbb12,
+	0xba16, 0x0010, 0x080c, 0x49d9, 0x0150, 0x04b0, 0x080c, 0x649f,
+	0x1598, 0xb810, 0x9306, 0x1580, 0xb814, 0x9206, 0x1568, 0x080c,
+	0xa08d, 0x0530, 0x2b00, 0x6012, 0x080c, 0xc2b3, 0x2900, 0x6016,
+	0x600b, 0xffff, 0x6023, 0x000a, 0xa878, 0x9086, 0x0001, 0x1170,
+	0x080c, 0x318b, 0x9006, 0x080c, 0x63dc, 0x2001, 0x0002, 0x080c,
+	0x63f0, 0x2001, 0x0200, 0xb86e, 0xb893, 0x0002, 0x2009, 0x0003,
+	0x080c, 0xa15d, 0x9006, 0x0068, 0x2001, 0x0001, 0x900e, 0x0038,
+	0x2001, 0x002c, 0x900e, 0x0018, 0x2001, 0x0028, 0x900e, 0x9005,
+	0x0000, 0x012e, 0x00be, 0x00fe, 0x0005, 0x00b6, 0x00f6, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0xa894, 0x90c6, 0x0015, 0x0904, 0x632d,
+	0x90c6, 0x0056, 0x0904, 0x6331, 0x90c6, 0x0066, 0x0904, 0x6335,
+	0x90c6, 0x0067, 0x0904, 0x6339, 0x90c6, 0x0068, 0x0904, 0x633d,
+	0x90c6, 0x0071, 0x0904, 0x6341, 0x90c6, 0x0074, 0x0904, 0x6345,
+	0x90c6, 0x007c, 0x0904, 0x6349, 0x90c6, 0x007e, 0x0904, 0x634d,
+	0x90c6, 0x0037, 0x0904, 0x6351, 0x9016, 0x2079, 0x1800, 0xa974,
+	0x9186, 0x00ff, 0x0904, 0x6328, 0x9182, 0x0800, 0x1a04, 0x6328,
+	0x080c, 0x649f, 0x1198, 0xb804, 0x9084, 0x00ff, 0x9082, 0x0006,
+	0x1268, 0xa894, 0x90c6, 0x006f, 0x0148, 0x080c, 0xa062, 0x1904,
+	0x6311, 0xb8a0, 0x9084, 0xff80, 0x1904, 0x6311, 0xa894, 0x90c6,
+	0x006f, 0x0158, 0x90c6, 0x005e, 0x0904, 0x6271, 0x90c6, 0x0064,
+	0x0904, 0x629a, 0x2008, 0x0804, 0x6234, 0xa998, 0xa8b0, 0x2040,
+	0x080c, 0xa062, 0x1120, 0x9182, 0x007f, 0x0a04, 0x6234, 0x9186,
+	0x00ff, 0x0904, 0x6234, 0x9182, 0x0800, 0x1a04, 0x6234, 0xaaa0,
+	0xab9c, 0x7878, 0x9306, 0x11a8, 0x787c, 0x0096, 0x924e, 0x1128,
+	0x2208, 0x2310, 0x009e, 0x0804, 0x6234, 0x080c, 0xa062, 0x1140,
+	0x99cc, 0xff00, 0x009e, 0x1128, 0x2208, 0x2310, 0x0804, 0x6234,
+	0x009e, 0x080c, 0x49d9, 0x0904, 0x623d, 0x900e, 0x9016, 0x90c6,
+	0x4000, 0x1558, 0x0006, 0x080c, 0x66bf, 0x1108, 0xc185, 0xb800,
+	0xd0bc, 0x0108, 0xc18d, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0031, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x0006,
+	0x2098, 0x080c, 0x0fae, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0035, 0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x000a,
+	0x2098, 0x080c, 0x0fae, 0x000e, 0x00c8, 0x90c6, 0x4007, 0x1110,
+	0x2408, 0x00a0, 0x90c6, 0x4008, 0x1118, 0x2708, 0x2610, 0x0070,
+	0x90c6, 0x4009, 0x1108, 0x0050, 0x90c6, 0x4006, 0x0138, 0x2001,
+	0x4005, 0x2009, 0x000a, 0x0010, 0x2001, 0x4006, 0xa896, 0xa99a,
+	0xaa9e, 0x2001, 0x0030, 0x900e, 0x0470, 0x080c, 0xa08d, 0x1130,
+	0x2001, 0x4005, 0x2009, 0x0003, 0x9016, 0x0c80, 0x2b00, 0x6012,
+	0x080c, 0xc2b3, 0x2900, 0x6016, 0x6023, 0x0001, 0xa868, 0xd88c,
+	0x0108, 0xc0f5, 0xa86a, 0x0126, 0x2091, 0x8000, 0x080c, 0x318b,
+	0x012e, 0x9006, 0x080c, 0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0,
+	0x2009, 0x0002, 0x080c, 0xa15d, 0xa8b0, 0xd094, 0x0118, 0xb8bc,
+	0xc08d, 0xb8be, 0x9006, 0x9005, 0x012e, 0x00ee, 0x00fe, 0x00be,
+	0x0005, 0x080c, 0x55ef, 0x0118, 0x2009, 0x0007, 0x00f8, 0xa998,
+	0xaeb0, 0x080c, 0x649f, 0x1904, 0x622f, 0x9186, 0x007f, 0x0130,
+	0x080c, 0x67c3, 0x0118, 0x2009, 0x0009, 0x0080, 0x0096, 0x080c,
+	0x1031, 0x1120, 0x009e, 0x2009, 0x0002, 0x0040, 0x2900, 0x009e,
+	0xa806, 0x080c, 0xc01f, 0x19b0, 0x2009, 0x0003, 0x2001, 0x4005,
+	0x0804, 0x6236, 0xa998, 0xaeb0, 0x080c, 0x649f, 0x1904, 0x622f,
+	0x0096, 0x080c, 0x1031, 0x1128, 0x009e, 0x2009, 0x0002, 0x0804,
+	0x62ee, 0x2900, 0x009e, 0xa806, 0x0096, 0x2048, 0x20a9, 0x002b,
+	0xb8b4, 0x20e0, 0xb8b8, 0x2098, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0002, 0x20a0, 0x4003, 0x20a9, 0x0008, 0x9080, 0x0006, 0x20a0,
+	0xbbb8, 0x9398, 0x0006, 0x2398, 0x080c, 0x0fae, 0x009e, 0xa87b,
+	0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0xd684, 0x1168, 0x080c,
+	0x55db, 0xd0b4, 0x1118, 0xa89b, 0x000b, 0x00e0, 0xb800, 0xd08c,
+	0x0118, 0xa89b, 0x000c, 0x00b0, 0x080c, 0x67c3, 0x0118, 0xa89b,
+	0x0009, 0x0080, 0x080c, 0x55ef, 0x0118, 0xa89b, 0x0007, 0x0050,
+	0x080c, 0xc002, 0x1904, 0x626a, 0x2009, 0x0003, 0x2001, 0x4005,
+	0x0804, 0x6236, 0xa87b, 0x0030, 0xa897, 0x4005, 0xa804, 0x8006,
+	0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080, 0x0002,
+	0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000,
+	0x2041, 0x1288, 0x080c, 0xa5e6, 0x1904, 0x626a, 0x2009, 0x0002,
+	0x08e8, 0x2001, 0x0028, 0x900e, 0x0804, 0x626b, 0x2009, 0x180c,
+	0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118,
+	0x2001, 0x0004, 0x0010, 0x2001, 0x0029, 0x900e, 0x0804, 0x626b,
+	0x2001, 0x0029, 0x900e, 0x0804, 0x626b, 0x080c, 0x3718, 0x0804,
+	0x626c, 0x080c, 0x5306, 0x0804, 0x626c, 0x080c, 0x455e, 0x0804,
+	0x626c, 0x080c, 0x45d7, 0x0804, 0x626c, 0x080c, 0x4633, 0x0804,
+	0x626c, 0x080c, 0x4a95, 0x0804, 0x626c, 0x080c, 0x4d3e, 0x0804,
+	0x626c, 0x080c, 0x4f6e, 0x0804, 0x626c, 0x080c, 0x5167, 0x0804,
+	0x626c, 0x080c, 0x3941, 0x0804, 0x626c, 0x00b6, 0xa974, 0xae78,
+	0x9684, 0x3fff, 0x9082, 0x4000, 0x1618, 0x9182, 0x0800, 0x1268,
+	0x9188, 0x1000, 0x2104, 0x905d, 0x0140, 0x080c, 0x67c3, 0x1148,
+	0x00e9, 0x080c, 0x65ca, 0x9006, 0x00b0, 0x2001, 0x0028, 0x900e,
+	0x0090, 0x9082, 0x0006, 0x1240, 0xb900, 0xd1fc, 0x0d88, 0x2001,
+	0x0029, 0x2009, 0x1000, 0x0038, 0x2001, 0x0029, 0x900e, 0x0018,
+	0x2001, 0x0029, 0x900e, 0x9005, 0x00be, 0x0005, 0x0126, 0x2091,
+	0x8000, 0xb850, 0x900d, 0x0150, 0x2900, 0x0096, 0x2148, 0xa802,
+	0x009e, 0xa803, 0x0000, 0xb852, 0x012e, 0x0005, 0x2900, 0xb852,
+	0xb84e, 0xa803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000, 0xb84c,
+	0x9005, 0x0170, 0x00e6, 0x2071, 0x19bf, 0x7004, 0x9086, 0x0002,
+	0x0168, 0x00ee, 0xb84c, 0xa802, 0x2900, 0xb84e, 0x012e, 0x0005,
+	0x2900, 0xb852, 0xb84e, 0xa803, 0x0000, 0x0cc0, 0x701c, 0x9b06,
+	0x1d80, 0xb84c, 0x00a6, 0x2050, 0xb000, 0xa802, 0x2900, 0xb002,
+	0x00ae, 0x00ee, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0xb84c,
+	0x904d, 0x0130, 0xa800, 0x9005, 0x1108, 0xb852, 0xb84e, 0x9905,
+	0x012e, 0x0005, 0xb84c, 0x904d, 0x0130, 0xa800, 0x9005, 0x1108,
+	0xb852, 0xb84e, 0x9905, 0x0005, 0x00b6, 0x0126, 0x00c6, 0x0026,
+	0x2091, 0x8000, 0x6210, 0x2258, 0xba00, 0x9005, 0x0110, 0xc285,
+	0x0008, 0xc284, 0xba02, 0x002e, 0x00ce, 0x012e, 0x00be, 0x0005,
+	0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000, 0x6210, 0x2258, 0xba04,
+	0x0006, 0x9086, 0x0006, 0x1170, 0xb89c, 0xd0ac, 0x0158, 0x080c,
+	0x67bf, 0x0140, 0x9284, 0xff00, 0x8007, 0x9086, 0x0007, 0x1110,
+	0x2011, 0x0600, 0x000e, 0x9294, 0xff00, 0x9215, 0xba06, 0x0006,
+	0x9086, 0x0006, 0x1120, 0xba90, 0x82ff, 0x090c, 0x0dfa, 0x000e,
+	0x00ce, 0x012e, 0x00be, 0x0005, 0x00b6, 0x0126, 0x00c6, 0x2091,
+	0x8000, 0x6210, 0x2258, 0xba04, 0x0006, 0x9086, 0x0006, 0x1168,
+	0xb89c, 0xd0a4, 0x0150, 0x080c, 0x67bb, 0x1138, 0x9284, 0x00ff,
+	0x9086, 0x0007, 0x1110, 0x2011, 0x0006, 0x000e, 0x9294, 0x00ff,
+	0x8007, 0x9215, 0xba06, 0x00ce, 0x012e, 0x00be, 0x0005, 0x9182,
+	0x0800, 0x0218, 0x9085, 0x0001, 0x0005, 0x00d6, 0x0026, 0x9190,
+	0x1000, 0x2204, 0x905d, 0x1180, 0x0096, 0x080c, 0x1031, 0x2958,
+	0x009e, 0x0160, 0x2b00, 0x2012, 0xb85c, 0xb8ba, 0xb860, 0xb8b6,
+	0x9006, 0xb8a6, 0x080c, 0x5f45, 0x9006, 0x0010, 0x9085, 0x0001,
+	0x002e, 0x00de, 0x0005, 0x00b6, 0x0096, 0x0126, 0x2091, 0x8000,
+	0x0026, 0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0458, 0x00d6,
+	0x9190, 0x1000, 0x2204, 0x905d, 0x0518, 0x2013, 0x0000, 0xb8a4,
+	0x904d, 0x0110, 0x080c, 0x1063, 0x00d6, 0x00c6, 0xb8ac, 0x2060,
+	0x8cff, 0x0168, 0x600c, 0x0006, 0x6014, 0x2048, 0x080c, 0xbe37,
+	0x0110, 0x080c, 0x0fe3, 0x080c, 0xa0e3, 0x00ce, 0x0c88, 0x00ce,
+	0x00de, 0x2b48, 0xb8b8, 0xb85e, 0xb8b4, 0xb862, 0x080c, 0x1073,
+	0x00de, 0x9006, 0x002e, 0x012e, 0x009e, 0x00be, 0x0005, 0x0016,
+	0x9182, 0x0800, 0x0218, 0x9085, 0x0001, 0x0030, 0x9188, 0x1000,
+	0x2104, 0x905d, 0x0dc0, 0x9006, 0x001e, 0x0005, 0x00d6, 0x0156,
+	0x0136, 0x0146, 0x9006, 0xb80a, 0xb80e, 0xb800, 0xc08c, 0xb802,
+	0x080c, 0x7207, 0x1510, 0xb8a0, 0x9086, 0x007e, 0x0120, 0x080c,
+	0xa062, 0x11d8, 0x0078, 0x7040, 0xd0e4, 0x01b8, 0x00c6, 0x2061,
+	0x195a, 0x7048, 0x2062, 0x704c, 0x6006, 0x7050, 0x600a, 0x7054,
+	0x600e, 0x00ce, 0x703c, 0x2069, 0x0140, 0x9005, 0x1110, 0x2001,
+	0x0001, 0x6886, 0x2069, 0x1800, 0x68b2, 0x7040, 0xb85e, 0x7048,
+	0xb862, 0x704c, 0xb866, 0x20e1, 0x0000, 0x2099, 0x0276, 0xb8b4,
+	0x20e8, 0xb8b8, 0x9088, 0x000a, 0x21a0, 0x20a9, 0x0004, 0x4003,
+	0x2099, 0x027a, 0x9088, 0x0006, 0x21a0, 0x20a9, 0x0004, 0x4003,
+	0x2069, 0x0200, 0x6817, 0x0001, 0x7040, 0xb86a, 0x7144, 0xb96e,
+	0x7048, 0xb872, 0x7050, 0xb876, 0x2069, 0x0200, 0x6817, 0x0000,
+	0xb8a0, 0x9086, 0x007e, 0x1110, 0x7144, 0xb96e, 0x9182, 0x0211,
+	0x1218, 0x2009, 0x0008, 0x0400, 0x9182, 0x0259, 0x1218, 0x2009,
+	0x0007, 0x00d0, 0x9182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0,
+	0x9182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0x9182, 0x0421,
+	0x1218, 0x2009, 0x0004, 0x0040, 0x9182, 0x0581, 0x1218, 0x2009,
+	0x0003, 0x0010, 0x2009, 0x0002, 0xb992, 0x014e, 0x013e, 0x015e,
+	0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0x0260, 0x7034,
+	0xb896, 0x703c, 0xb89a, 0x7054, 0xb89e, 0x0036, 0xbbbc, 0xc384,
+	0xba00, 0x2009, 0x187b, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110,
+	0xc2ad, 0x0008, 0xc2ac, 0xd0c4, 0x0148, 0xd1e4, 0x0138, 0xc2bd,
+	0xd0cc, 0x0128, 0xd38c, 0x1108, 0xc385, 0x0008, 0xc2bc, 0xba02,
+	0xbbbe, 0x003e, 0x00ee, 0x002e, 0x001e, 0x0005, 0x0096, 0x0126,
+	0x2091, 0x8000, 0xb8a4, 0x904d, 0x0578, 0xa900, 0x81ff, 0x15c0,
+	0xaa04, 0x9282, 0x0010, 0x16c8, 0x0136, 0x0146, 0x01c6, 0x01d6,
+	0x8906, 0x8006, 0x8007, 0x908c, 0x003f, 0x21e0, 0x9084, 0xffc0,
+	0x9080, 0x0004, 0x2098, 0x2009, 0x0010, 0x20a9, 0x0001, 0x4002,
+	0x9086, 0xffff, 0x0120, 0x8109, 0x1dd0, 0x080c, 0x0dfa, 0x3c00,
+	0x20e8, 0x3300, 0x8001, 0x20a0, 0x4604, 0x8210, 0xaa06, 0x01de,
+	0x01ce, 0x014e, 0x013e, 0x0060, 0x080c, 0x1031, 0x0170, 0x2900,
+	0xb8a6, 0xa803, 0x0000, 0x080c, 0x665b, 0xa807, 0x0001, 0xae12,
+	0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0x9006, 0x0cd8, 0x0126,
+	0x2091, 0x8000, 0x0096, 0xb8a4, 0x904d, 0x0188, 0xa800, 0x9005,
+	0x1150, 0x080c, 0x666a, 0x1158, 0xa804, 0x908a, 0x0002, 0x0218,
+	0x8001, 0xa806, 0x0020, 0x080c, 0x1063, 0xb8a7, 0x0000, 0x009e,
+	0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c, 0x8696, 0x012e,
+	0x0005, 0x901e, 0x0010, 0x2019, 0x0001, 0x900e, 0x0126, 0x2091,
+	0x8000, 0xb84c, 0x2048, 0xb800, 0xd0dc, 0x1170, 0x89ff, 0x0500,
+	0x83ff, 0x0120, 0xa878, 0x9606, 0x0158, 0x0030, 0xa86c, 0x9406,
+	0x1118, 0xa870, 0x9506, 0x0120, 0x2908, 0xa800, 0x2048, 0x0c70,
+	0x080c, 0x9a4e, 0xaa00, 0xb84c, 0x9906, 0x1110, 0xba4e, 0x0020,
+	0x00a6, 0x2150, 0xb202, 0x00ae, 0x82ff, 0x1110, 0xb952, 0x89ff,
+	0x012e, 0x0005, 0x9016, 0x0489, 0x1110, 0x2011, 0x0001, 0x0005,
+	0x080c, 0x66bf, 0x0128, 0x080c, 0xbef4, 0x0010, 0x9085, 0x0001,
+	0x0005, 0x080c, 0x66bf, 0x0128, 0x080c, 0xbe99, 0x0010, 0x9085,
+	0x0001, 0x0005, 0x080c, 0x66bf, 0x0128, 0x080c, 0xbef1, 0x0010,
+	0x9085, 0x0001, 0x0005, 0x080c, 0x66bf, 0x0128, 0x080c, 0xbeb8,
+	0x0010, 0x9085, 0x0001, 0x0005, 0x080c, 0x66bf, 0x0128, 0x080c,
+	0xbf37, 0x0010, 0x9085, 0x0001, 0x0005, 0xb8a4, 0x900d, 0x1118,
+	0x9085, 0x0001, 0x0005, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8,
+	0x890e, 0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0,
+	0x9080, 0x0004, 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002,
+	0x9606, 0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0008, 0x9006,
+	0x01ce, 0x013e, 0x0005, 0x0146, 0x01d6, 0xa860, 0x20e8, 0xa85c,
+	0x9080, 0x0004, 0x20a0, 0x20a9, 0x0010, 0x2009, 0xffff, 0x4104,
+	0x01de, 0x014e, 0x0136, 0x01c6, 0xa800, 0x9005, 0x11b8, 0x890e,
+	0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0, 0x9080,
+	0x0004, 0x2098, 0x20a9, 0x0001, 0x2009, 0x0010, 0x4002, 0x9606,
+	0x0128, 0x8109, 0x1dd8, 0x9085, 0x0001, 0x0068, 0x0146, 0x01d6,
+	0x3300, 0x8001, 0x20a0, 0x3c00, 0x20e8, 0x2001, 0xffff, 0x4004,
+	0x01de, 0x014e, 0x9006, 0x01ce, 0x013e, 0x0005, 0x0096, 0x0126,
+	0x2091, 0x8000, 0xb8a4, 0x904d, 0x1128, 0x080c, 0x1031, 0x0168,
+	0x2900, 0xb8a6, 0x080c, 0x665b, 0xa803, 0x0001, 0xa807, 0x0000,
+	0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0x9006, 0x0cd8, 0x0096,
+	0x0126, 0x2091, 0x8000, 0xb8a4, 0x904d, 0x0130, 0xb8a7, 0x0000,
+	0x080c, 0x1063, 0x9085, 0x0001, 0x012e, 0x009e, 0x0005, 0xb89c,
+	0xd0a4, 0x0005, 0x00b6, 0x00f6, 0x080c, 0x7207, 0x01b0, 0x71c0,
+	0x81ff, 0x1198, 0x71d8, 0xd19c, 0x0180, 0x2001, 0x007e, 0x9080,
+	0x1000, 0x2004, 0x905d, 0x0148, 0xb804, 0x9084, 0x00ff, 0x9086,
+	0x0006, 0x1118, 0xb800, 0xc0ed, 0xb802, 0x2079, 0x185b, 0x7804,
+	0x00d0, 0x0156, 0x20a9, 0x007f, 0x900e, 0x0016, 0x080c, 0x649f,
+	0x1168, 0xb804, 0x9084, 0xff00, 0x8007, 0x9096, 0x0004, 0x0118,
+	0x9086, 0x0006, 0x1118, 0xb800, 0xc0ed, 0xb802, 0x001e, 0x8108,
+	0x1f04, 0x66e5, 0x015e, 0x080c, 0x6781, 0x0120, 0x2001, 0x195d,
+	0x200c, 0x0030, 0x2079, 0x185b, 0x7804, 0x0030, 0x2009, 0x07d0,
+	0x2011, 0x670f, 0x080c, 0x836c, 0x00fe, 0x00be, 0x0005, 0x00b6,
+	0x2011, 0x670f, 0x080c, 0x82da, 0x080c, 0x6781, 0x01d8, 0x2001,
+	0x107e, 0x2004, 0x2058, 0xb900, 0xc1ec, 0xb902, 0x080c, 0x67bf,
+	0x0130, 0x2009, 0x07d0, 0x2011, 0x670f, 0x080c, 0x836c, 0x00e6,
+	0x2071, 0x1800, 0x9006, 0x707a, 0x705c, 0x707e, 0x080c, 0x2f6c,
+	0x00ee, 0x04b0, 0x0156, 0x00c6, 0x20a9, 0x007f, 0x900e, 0x0016,
+	0x080c, 0x649f, 0x1538, 0xb800, 0xd0ec, 0x0520, 0x0046, 0xbaa0,
+	0x2220, 0x9006, 0x2009, 0x0029, 0x080c, 0xd885, 0xb800, 0xc0e5,
+	0xc0ec, 0xb802, 0x080c, 0x67bb, 0x2001, 0x0707, 0x1128, 0xb804,
+	0x9084, 0x00ff, 0x9085, 0x0700, 0xb806, 0x2019, 0x0029, 0x080c,
+	0x8803, 0x0076, 0x903e, 0x080c, 0x86f1, 0x900e, 0x080c, 0xd5f6,
+	0x007e, 0x004e, 0x001e, 0x8108, 0x1f04, 0x6737, 0x00ce, 0x015e,
+	0x00be, 0x0005, 0x00b6, 0x6010, 0x2058, 0xb800, 0xc0ec, 0xb802,
+	0x00be, 0x0005, 0x7810, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0ac,
+	0x0005, 0x6010, 0x00b6, 0x905d, 0x0108, 0xb800, 0x00be, 0xd0bc,
+	0x0005, 0x00b6, 0x00f6, 0x2001, 0x107e, 0x2004, 0x905d, 0x0110,
+	0xb800, 0xd0ec, 0x00fe, 0x00be, 0x0005, 0x0126, 0x0026, 0x2091,
+	0x8000, 0x0006, 0xbaa0, 0x9290, 0x1000, 0x2204, 0x9b06, 0x190c,
+	0x0dfa, 0x000e, 0xba00, 0x9005, 0x0110, 0xc2fd, 0x0008, 0xc2fc,
+	0xba02, 0x002e, 0x012e, 0x0005, 0x2011, 0x1836, 0x2204, 0xd0cc,
+	0x0138, 0x2001, 0x195b, 0x200c, 0x2011, 0x67b1, 0x080c, 0x836c,
+	0x0005, 0x2011, 0x67b1, 0x080c, 0x82da, 0x2011, 0x1836, 0x2204,
+	0xc0cc, 0x2012, 0x0005, 0x080c, 0x55db, 0xd0ac, 0x0005, 0x080c,
+	0x55db, 0xd0a4, 0x0005, 0x0016, 0xb904, 0x9184, 0x00ff, 0x908e,
+	0x0006, 0x001e, 0x0005, 0x0016, 0xb904, 0x9184, 0xff00, 0x8007,
+	0x908e, 0x0006, 0x001e, 0x0005, 0x00b6, 0x00f6, 0x080c, 0xc539,
+	0x0158, 0x70d8, 0x9084, 0x0028, 0x0138, 0x2001, 0x107f, 0x2004,
+	0x905d, 0x0110, 0xb8bc, 0xd094, 0x00fe, 0x00be, 0x0005, 0x0006,
+	0x0016, 0x0036, 0x0046, 0x0076, 0x00b6, 0x2001, 0x1817, 0x203c,
+	0x9780, 0x32e9, 0x203d, 0x97bc, 0xff00, 0x873f, 0x9006, 0x2018,
+	0x2008, 0x9284, 0x8000, 0x0110, 0x2019, 0x0001, 0x9294, 0x7fff,
+	0x2100, 0x9706, 0x0190, 0x91a0, 0x1000, 0x2404, 0x905d, 0x0168,
+	0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1138, 0x83ff, 0x0118,
+	0xb89c, 0xd0a4, 0x0110, 0x8211, 0x0158, 0x8108, 0x83ff, 0x0120,
+	0x9182, 0x0800, 0x0e28, 0x0068, 0x9182, 0x007e, 0x0e08, 0x0048,
+	0x00be, 0x007e, 0x004e, 0x003e, 0x001e, 0x9085, 0x0001, 0x000e,
+	0x0005, 0x00be, 0x007e, 0x004e, 0x003e, 0x001e, 0x9006, 0x000e,
+	0x0005, 0x0046, 0x0056, 0x0076, 0x00b6, 0x2100, 0x9084, 0x7fff,
+	0x9080, 0x1000, 0x2004, 0x905d, 0x0130, 0xb804, 0x9084, 0x00ff,
+	0x9086, 0x0006, 0x0550, 0x9184, 0x8000, 0x0580, 0x2001, 0x1817,
+	0x203c, 0x9780, 0x32e9, 0x203d, 0x97bc, 0xff00, 0x873f, 0x9006,
+	0x2020, 0x2400, 0x9706, 0x01a0, 0x94a8, 0x1000, 0x2504, 0x905d,
+	0x0178, 0xb804, 0x9084, 0x00ff, 0x9086, 0x0006, 0x1148, 0xb89c,
+	0xd0a4, 0x0130, 0xb814, 0x9206, 0x1118, 0xb810, 0x9306, 0x0128,
+	0x8420, 0x9482, 0x0800, 0x0e28, 0x0048, 0x918c, 0x7fff, 0x00be,
+	0x007e, 0x005e, 0x004e, 0x9085, 0x0001, 0x0005, 0x918c, 0x7fff,
+	0x00be, 0x007e, 0x005e, 0x004e, 0x9006, 0x0005, 0x2071, 0x190e,
+	0x7003, 0x0001, 0x7007, 0x0000, 0x9006, 0x7012, 0x7016, 0x701a,
+	0x701e, 0x700a, 0x7046, 0x0005, 0x0016, 0x00e6, 0x2071, 0x1921,
+	0x900e, 0x710a, 0x080c, 0x55db, 0xd0fc, 0x1140, 0x080c, 0x55db,
+	0x900e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x0400, 0x2001, 0x187b,
+	0x200c, 0x9184, 0x0007, 0x9006, 0x0002, 0x6896, 0x6896, 0x6896,
+	0x6896, 0x6896, 0x68ad, 0x68bb, 0x6896, 0x7003, 0x0003, 0x2009,
+	0x187c, 0x210c, 0x9184, 0xff00, 0x8007, 0x9005, 0x1110, 0x2001,
+	0x0002, 0x7006, 0x0018, 0x7003, 0x0005, 0x0c88, 0x00ee, 0x001e,
+	0x0005, 0x00e6, 0x2071, 0x0050, 0x684c, 0x9005, 0x1150, 0x00e6,
+	0x2071, 0x190e, 0x7028, 0xc085, 0x702a, 0x00ee, 0x9085, 0x0001,
+	0x0488, 0x6844, 0x9005, 0x0158, 0x080c, 0x7576, 0x6a60, 0x9200,
+	0x7002, 0x6864, 0x9101, 0x7006, 0x9006, 0x7012, 0x7016, 0x6860,
+	0x7002, 0x6864, 0x7006, 0x6868, 0x700a, 0x686c, 0x700e, 0x6844,
+	0x9005, 0x1110, 0x7012, 0x7016, 0x684c, 0x701a, 0x701c, 0x9085,
+	0x0040, 0x701e, 0x7037, 0x0019, 0x702b, 0x0001, 0x00e6, 0x2071,
+	0x190e, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700b, 0x0000,
+	0x00ee, 0x9006, 0x00ee, 0x0005, 0xa868, 0xd0fc, 0x11d8, 0x00e6,
+	0x0026, 0x2001, 0x1921, 0x2004, 0x9005, 0x0904, 0x6aee, 0xa87c,
+	0xd0bc, 0x1904, 0x6aee, 0xa978, 0xa874, 0x9105, 0x1904, 0x6aee,
+	0x2001, 0x1921, 0x2004, 0x0002, 0x6aee, 0x6947, 0x6983, 0x6983,
+	0x6aee, 0x6983, 0x0005, 0xa868, 0xd0fc, 0x1500, 0x00e6, 0x0026,
+	0x2009, 0x1921, 0x210c, 0x81ff, 0x0904, 0x6aee, 0xa87c, 0xd0cc,
+	0x0904, 0x6aee, 0xa880, 0x9084, 0x00ff, 0x9086, 0x0001, 0x1904,
+	0x6aee, 0x9186, 0x0003, 0x0904, 0x6983, 0x9186, 0x0005, 0x0904,
+	0x6983, 0xa84f, 0x8021, 0xa853, 0x0017, 0x0028, 0x0005, 0xa84f,
+	0x8020, 0xa853, 0x0016, 0x2071, 0x190e, 0x701c, 0x9005, 0x1904,
+	0x6ca2, 0x0e04, 0x6ced, 0x2071, 0x0000, 0xa84c, 0x7082, 0xa850,
+	0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x2071, 0x1800,
+	0x2011, 0x0001, 0xa804, 0x900d, 0x702c, 0x1158, 0xa802, 0x2900,
+	0x702e, 0x70bc, 0x9200, 0x70be, 0x080c, 0x81f0, 0x002e, 0x00ee,
+	0x0005, 0x0096, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x009e, 0x0c58, 0xa84f, 0x0000, 0x00f6, 0x2079, 0x0050,
+	0x2071, 0x190e, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904, 0x6a72,
+	0x782c, 0x908c, 0x0780, 0x190c, 0x6e16, 0x8004, 0x8004, 0x8004,
+	0x9084, 0x0003, 0x0002, 0x69a1, 0x6a72, 0x69c6, 0x6a0d, 0x080c,
+	0x0dfa, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804, 0x900d, 0x1170,
+	0x2071, 0x19d2, 0x703c, 0x9005, 0x1328, 0x2001, 0x1922, 0x2004,
+	0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c,
+	0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e,
+	0x70bc, 0x9200, 0x70be, 0x080c, 0x81f0, 0x0c10, 0x2071, 0x1800,
+	0x2900, 0x7822, 0xa804, 0x900d, 0x1580, 0x7824, 0x00e6, 0x2071,
+	0x0040, 0x712c, 0xd19c, 0x1148, 0x2009, 0x182f, 0x210c, 0x918a,
+	0x0040, 0x0218, 0x7022, 0x00ee, 0x0058, 0x00ee, 0x2048, 0x702c,
+	0xa802, 0x2900, 0x702e, 0x70bc, 0x8000, 0x70be, 0x080c, 0x81f0,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd0a4, 0x19f0, 0x2071,
+	0x19d2, 0x703c, 0x9005, 0x1328, 0x2001, 0x1922, 0x2004, 0x8005,
+	0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc,
+	0x9200, 0x70be, 0x080c, 0x81f0, 0x0800, 0x0096, 0x00e6, 0x7824,
+	0x2048, 0x2071, 0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc,
+	0x8000, 0x70be, 0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd0a4, 0x1d60, 0x00ee, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd09c, 0x11a0, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d,
+	0x1560, 0x2071, 0x19d2, 0x703c, 0x9005, 0x1328, 0x2001, 0x1922,
+	0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x009e,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1170, 0x2071,
+	0x19d2, 0x703c, 0x9005, 0x1328, 0x2001, 0x1922, 0x2004, 0x8005,
+	0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016,
+	0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8,
+	0x702e, 0x70bc, 0x9200, 0x70be, 0x080c, 0x81f0, 0x00fe, 0x002e,
+	0x00ee, 0x0005, 0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d,
+	0x711a, 0x0110, 0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d,
+	0x1904, 0x6ac7, 0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd09c,
+	0x1198, 0x701c, 0x904d, 0x0180, 0x7010, 0x8001, 0x7012, 0x1108,
+	0x701a, 0xa800, 0x701e, 0x2900, 0x7822, 0x782c, 0x9094, 0x0780,
+	0x190c, 0x6e16, 0xd09c, 0x0d68, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd0a4, 0x01b0, 0x00e6, 0x7824, 0x2048, 0x2071, 0x1800,
+	0x702c, 0xa802, 0x2900, 0x702e, 0x70bc, 0x8000, 0x70be, 0x080c,
+	0x81f0, 0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd0a4, 0x1d60,
+	0x00ee, 0x2071, 0x19d2, 0x703c, 0x9005, 0x1328, 0x2001, 0x1922,
+	0x2004, 0x8005, 0x703e, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6,
+	0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210,
+	0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc, 0x9200, 0x70be, 0x080c,
+	0x81f0, 0x00ee, 0x0804, 0x6a82, 0xa868, 0xd0fc, 0x1904, 0x6b2a,
+	0x0096, 0xa804, 0xa807, 0x0000, 0x904d, 0x190c, 0x0fe3, 0x009e,
+	0x0018, 0xa868, 0xd0fc, 0x15f0, 0x00e6, 0x0026, 0xa84f, 0x0000,
+	0x00f6, 0x2079, 0x0050, 0x2071, 0x1800, 0x70e8, 0x8001, 0x01d0,
+	0x1678, 0x2071, 0x190e, 0xa803, 0x0000, 0x7010, 0x9005, 0x1904,
+	0x6c20, 0x782c, 0x908c, 0x0780, 0x190c, 0x6e16, 0x8004, 0x8004,
+	0x8004, 0x9084, 0x0003, 0x0002, 0x6b2b, 0x6c20, 0x6b46, 0x6bb3,
+	0x080c, 0x0dfa, 0x70eb, 0x0fa0, 0x71e4, 0x8107, 0x9106, 0x9094,
+	0x00c0, 0x9184, 0xff3f, 0x9205, 0x70e6, 0x3b08, 0x3a00, 0x9104,
+	0x918d, 0x00c0, 0x21d8, 0x9084, 0xff3f, 0x9205, 0x20d0, 0x0888,
+	0x70ea, 0x0878, 0x0005, 0x2071, 0x1800, 0x2900, 0x7822, 0xa804,
+	0x900d, 0x1120, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x9016, 0x702c,
+	0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e,
+	0x70bc, 0x9200, 0x70be, 0x080c, 0x81f0, 0x0c60, 0x2071, 0x1800,
+	0x2900, 0x7822, 0xa804, 0x900d, 0x1904, 0x6ba2, 0x7830, 0x8007,
+	0x9084, 0x001f, 0x9082, 0x0001, 0x1220, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1148,
+	0x2009, 0x182f, 0x210c, 0x918a, 0x0040, 0x0218, 0x7022, 0x00ee,
+	0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc,
+	0x8000, 0x70be, 0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd0a4, 0x19f0, 0x0e04, 0x6b99, 0x7838, 0x7938, 0x910e,
+	0x1de0, 0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de,
+	0x2001, 0x191f, 0x200c, 0xc184, 0x2102, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x00fe, 0x002e, 0x00ee,
+	0x0005, 0x2001, 0x191f, 0x200c, 0xc185, 0x2102, 0x00fe, 0x002e,
+	0x00ee, 0x0005, 0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210,
+	0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc, 0x9200, 0x70be, 0x080c,
+	0x81f0, 0x0804, 0x6b59, 0x0096, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc, 0x8000, 0x70be,
+	0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6bf3, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11e0, 0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd09c,
+	0x1170, 0x009e, 0x2900, 0x7822, 0xa804, 0x900d, 0x11e0, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x7044, 0xc085, 0x7046, 0x0c58, 0x009e,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1120, 0x00fe,
+	0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc,
+	0x9200, 0x70be, 0x080c, 0x81f0, 0x00fe, 0x002e, 0x00ee, 0x0005,
+	0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110,
+	0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1904, 0x6c8d,
+	0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd09c, 0x11b0, 0x701c,
+	0x904d, 0x0198, 0xa84c, 0x9005, 0x1180, 0x7010, 0x8001, 0x7012,
+	0x1108, 0x701a, 0xa800, 0x701e, 0x2900, 0x7822, 0x782c, 0x9094,
+	0x0780, 0x190c, 0x6e16, 0xd09c, 0x0d50, 0x782c, 0x9094, 0x0780,
+	0x190c, 0x6e16, 0xd0a4, 0x05a8, 0x00e6, 0x7824, 0x2048, 0x2071,
+	0x1800, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc, 0x8000, 0x70be,
+	0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c, 0x6e16, 0xd0a4,
+	0x1d60, 0x00ee, 0x0e04, 0x6c86, 0x7838, 0x7938, 0x910e, 0x1de0,
+	0x00d6, 0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x7044,
+	0xc084, 0x7046, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084,
+	0x190c, 0x11e0, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x7044, 0xc085,
+	0x7046, 0x00fe, 0x002e, 0x00ee, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x9016, 0x702c, 0x2148, 0xa904, 0xa802, 0x8210, 0x2900, 0x81ff,
+	0x1dc8, 0x702e, 0x70bc, 0x9200, 0x70be, 0x080c, 0x81f0, 0x00ee,
+	0x0804, 0x6c30, 0x2071, 0x190e, 0xa803, 0x0000, 0x2908, 0x7010,
+	0x8000, 0x7012, 0x7018, 0x904d, 0x711a, 0x0110, 0xa902, 0x0008,
+	0x711e, 0x2148, 0xa804, 0x900d, 0x1128, 0x1e04, 0x6ccd, 0x002e,
+	0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148, 0xa904,
+	0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc, 0x9200,
+	0x70be, 0x080c, 0x81f0, 0x0e04, 0x6cb7, 0x2071, 0x190e, 0x701c,
+	0x2048, 0xa84c, 0x900d, 0x0d18, 0x2071, 0x0000, 0x7182, 0xa850,
+	0x7032, 0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x2071, 0x190e,
+	0x080c, 0x6e02, 0x002e, 0x00ee, 0x0005, 0x2071, 0x190e, 0xa803,
+	0x0000, 0x2908, 0x7010, 0x8000, 0x7012, 0x7018, 0x904d, 0x711a,
+	0x0110, 0xa902, 0x0008, 0x711e, 0x2148, 0xa804, 0x900d, 0x1118,
+	0x002e, 0x00ee, 0x0005, 0x2071, 0x1800, 0x9016, 0x702c, 0x2148,
+	0xa904, 0xa802, 0x8210, 0x2900, 0x81ff, 0x1dc8, 0x702e, 0x70bc,
+	0x9200, 0x70be, 0x080c, 0x81f0, 0x002e, 0x00ee, 0x0005, 0x0006,
+	0xa87c, 0x0006, 0xa867, 0x0103, 0x20a9, 0x001c, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x001d, 0x20a0, 0x9006, 0x4004, 0x000e, 0x9084,
+	0x00ff, 0xa87e, 0x000e, 0xa87a, 0xa982, 0x0005, 0x2071, 0x190e,
+	0x7004, 0x0002, 0x6d3a, 0x6d3b, 0x6e01, 0x6d3b, 0x6d38, 0x6e01,
+	0x080c, 0x0dfa, 0x0005, 0x2001, 0x1921, 0x2004, 0x0002, 0x6d45,
+	0x6d45, 0x6d9a, 0x6d9b, 0x6d45, 0x6d9b, 0x0126, 0x2091, 0x8000,
+	0x1e0c, 0x6e21, 0x701c, 0x904d, 0x01e0, 0xa84c, 0x9005, 0x01d8,
+	0x0e04, 0x6d69, 0xa94c, 0x2071, 0x0000, 0x7182, 0xa850, 0x7032,
+	0xa86c, 0x7086, 0x7036, 0xa870, 0x708a, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x2071, 0x190e, 0x080c,
+	0x6e02, 0x012e, 0x0470, 0x2001, 0x005b, 0x2004, 0x9094, 0x0780,
+	0x190c, 0x6e16, 0xd09c, 0x2071, 0x190e, 0x1510, 0x2071, 0x190e,
+	0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003, 0x1130,
+	0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900, 0x00d6,
+	0x2069, 0x0050, 0x6822, 0x00de, 0x2071, 0x190e, 0x701c, 0x2048,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x0005, 0x0005, 0x00d6, 0x2008, 0x2069, 0x19d2, 0x683c,
+	0x9005, 0x0760, 0x0158, 0x9186, 0x0003, 0x0540, 0x2001, 0x1814,
+	0x2004, 0x2009, 0x1aa2, 0x210c, 0x9102, 0x1500, 0x0126, 0x2091,
+	0x8000, 0x2069, 0x0050, 0x693c, 0x6838, 0x9106, 0x0190, 0x0e04,
+	0x6dcd, 0x2069, 0x0000, 0x6837, 0x8040, 0x6833, 0x0012, 0x6883,
+	0x8040, 0x2091, 0x4080, 0x2001, 0x0089, 0x2004, 0xd084, 0x190c,
+	0x11e0, 0x2069, 0x19d2, 0x683f, 0xffff, 0x012e, 0x00de, 0x0126,
+	0x2091, 0x8000, 0x1e0c, 0x6e82, 0x701c, 0x904d, 0x0540, 0x2001,
+	0x005b, 0x2004, 0x9094, 0x0780, 0x15c9, 0xd09c, 0x1500, 0x2071,
+	0x190e, 0x700f, 0x0001, 0xa964, 0x9184, 0x00ff, 0x9086, 0x0003,
+	0x1130, 0x810f, 0x918c, 0x00ff, 0x8101, 0x0108, 0x710e, 0x2900,
+	0x00d6, 0x2069, 0x0050, 0x6822, 0x00de, 0x701c, 0x2048, 0x7010,
+	0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a, 0x012e,
+	0x0005, 0x0005, 0x0126, 0x2091, 0x8000, 0x701c, 0x904d, 0x0160,
+	0x7010, 0x8001, 0x7012, 0xa800, 0x701e, 0x9005, 0x1108, 0x701a,
+	0x012e, 0x080c, 0x1063, 0x0005, 0x012e, 0x0005, 0x2091, 0x8000,
+	0x0e04, 0x6e18, 0x0006, 0x0016, 0x2001, 0x8004, 0x0006, 0x0804,
+	0x0e03, 0x0096, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01c0,
+	0xc084, 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069,
+	0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x00fe, 0x009e, 0x0005,
+	0x782c, 0x9094, 0x0780, 0x1991, 0xd0a4, 0x0db8, 0x00e6, 0x2071,
+	0x1800, 0x7824, 0x00e6, 0x2071, 0x0040, 0x712c, 0xd19c, 0x1148,
+	0x2009, 0x182f, 0x210c, 0x918a, 0x0040, 0x0218, 0x7022, 0x00ee,
+	0x0058, 0x00ee, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc,
+	0x8000, 0x70be, 0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd0a4, 0x19f0, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6,
+	0x2069, 0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080,
+	0x2001, 0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x00ee, 0x00fe,
+	0x009e, 0x0005, 0x00f6, 0x2079, 0x0050, 0x7044, 0xd084, 0x01b8,
+	0xc084, 0x7046, 0x7838, 0x7938, 0x910e, 0x1de0, 0x00d6, 0x2069,
+	0x0000, 0x6836, 0x6833, 0x0013, 0x00de, 0x2091, 0x4080, 0x2001,
+	0x0089, 0x2004, 0xd084, 0x190c, 0x11e0, 0x00fe, 0x0005, 0x782c,
+	0x9094, 0x0780, 0x190c, 0x6e16, 0xd0a4, 0x0db8, 0x00e6, 0x2071,
+	0x1800, 0x7824, 0x2048, 0x702c, 0xa802, 0x2900, 0x702e, 0x70bc,
+	0x8000, 0x70be, 0x080c, 0x81f0, 0x782c, 0x9094, 0x0780, 0x190c,
+	0x6e16, 0xd0a4, 0x1d70, 0x00d6, 0x2069, 0x0050, 0x693c, 0x2069,
+	0x1921, 0x6808, 0x690a, 0x2069, 0x19d2, 0x9102, 0x1118, 0x683c,
+	0x9005, 0x1328, 0x2001, 0x1922, 0x200c, 0x810d, 0x693e, 0x00de,
+	0x00ee, 0x00fe, 0x0005, 0x7094, 0x908a, 0x0029, 0x1a0c, 0x0dfa,
+	0x9082, 0x001d, 0x001b, 0x6027, 0x1e00, 0x0005, 0x6faa, 0x6f30,
+	0x6f4c, 0x6f76, 0x6f99, 0x6fd9, 0x6feb, 0x6f4c, 0x6fc1, 0x6eeb,
+	0x6f19, 0x6eea, 0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005,
+	0x1180, 0x6808, 0x9005, 0x1518, 0x7097, 0x0028, 0x2069, 0x1967,
+	0x2d04, 0x7002, 0x080c, 0x7359, 0x6028, 0x9085, 0x0600, 0x602a,
+	0x00b0, 0x7097, 0x0028, 0x2069, 0x1967, 0x2d04, 0x7002, 0x6028,
+	0x9085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071,
+	0x1a3a, 0x080c, 0x19ff, 0x005e, 0x004e, 0x003e, 0x00ee, 0x00de,
+	0x0005, 0x00d6, 0x2069, 0x0200, 0x6804, 0x9005, 0x1178, 0x6808,
+	0x9005, 0x1160, 0x7097, 0x0028, 0x2069, 0x1967, 0x2d04, 0x7002,
+	0x080c, 0x73f3, 0x6028, 0x9085, 0x0600, 0x602a, 0x00de, 0x0005,
+	0x0006, 0x2001, 0x0090, 0x080c, 0x2c88, 0x000e, 0x6124, 0xd1e4,
+	0x1190, 0x080c, 0x7058, 0xd1d4, 0x1160, 0xd1dc, 0x1138, 0xd1cc,
+	0x0150, 0x7097, 0x0020, 0x080c, 0x7058, 0x0028, 0x7097, 0x001d,
+	0x0010, 0x7097, 0x001f, 0x0005, 0x2001, 0x0088, 0x080c, 0x2c88,
+	0x6124, 0xd1cc, 0x11e8, 0xd1dc, 0x11c0, 0xd1e4, 0x1198, 0x9184,
+	0x1e00, 0x11d8, 0x080c, 0x1a24, 0x60e3, 0x0001, 0x600c, 0xc0b4,
+	0x600e, 0x080c, 0x7233, 0x2001, 0x0080, 0x080c, 0x2c88, 0x7097,
+	0x0028, 0x0058, 0x7097, 0x001e, 0x0040, 0x7097, 0x001d, 0x0028,
+	0x7097, 0x0020, 0x0010, 0x7097, 0x001f, 0x0005, 0x080c, 0x1a24,
+	0x60e3, 0x0001, 0x600c, 0xc0b4, 0x600e, 0x080c, 0x7233, 0x2001,
+	0x0080, 0x080c, 0x2c88, 0x6124, 0xd1d4, 0x1180, 0xd1dc, 0x1158,
+	0xd1e4, 0x1130, 0x9184, 0x1e00, 0x1158, 0x7097, 0x0028, 0x0040,
+	0x7097, 0x001e, 0x0028, 0x7097, 0x001d, 0x0010, 0x7097, 0x001f,
+	0x0005, 0x2001, 0x00a0, 0x080c, 0x2c88, 0x6124, 0xd1dc, 0x1138,
+	0xd1e4, 0x0138, 0x080c, 0x1a24, 0x7097, 0x001e, 0x0010, 0x7097,
+	0x001d, 0x0005, 0x080c, 0x70db, 0x6124, 0xd1dc, 0x1188, 0x080c,
+	0x7058, 0x0016, 0x080c, 0x1a24, 0x001e, 0xd1d4, 0x1128, 0xd1e4,
+	0x0138, 0x7097, 0x001e, 0x0020, 0x7097, 0x001f, 0x080c, 0x7058,
+	0x0005, 0x0006, 0x2001, 0x00a0, 0x080c, 0x2c88, 0x000e, 0x6124,
+	0xd1d4, 0x1160, 0xd1cc, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140,
+	0x7097, 0x001e, 0x0028, 0x7097, 0x001d, 0x0010, 0x7097, 0x0021,
+	0x0005, 0x080c, 0x70db, 0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128,
+	0xd1e4, 0x0140, 0x7097, 0x001e, 0x0028, 0x7097, 0x001d, 0x0010,
+	0x7097, 0x001f, 0x0005, 0x0006, 0x2001, 0x0090, 0x080c, 0x2c88,
+	0x000e, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc, 0x1128,
+	0xd1e4, 0x0158, 0x7097, 0x001e, 0x0040, 0x7097, 0x001d, 0x0028,
+	0x7097, 0x0020, 0x0010, 0x7097, 0x001f, 0x0005, 0x0016, 0x00c6,
+	0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071,
+	0x1800, 0x2091, 0x8000, 0x080c, 0x7207, 0x11d8, 0x2001, 0x180c,
+	0x200c, 0xd1b4, 0x01b0, 0xc1b4, 0x2102, 0x6027, 0x0200, 0x080c,
+	0x2bb0, 0x6024, 0xd0cc, 0x0148, 0x2001, 0x00a0, 0x080c, 0x2c88,
+	0x080c, 0x7504, 0x080c, 0x5f2b, 0x0428, 0x6028, 0xc0cd, 0x602a,
+	0x0408, 0x080c, 0x7221, 0x0150, 0x080c, 0x7218, 0x1138, 0x2001,
+	0x0001, 0x080c, 0x2717, 0x080c, 0x71df, 0x00a0, 0x080c, 0x70d8,
+	0x0178, 0x2001, 0x0001, 0x080c, 0x2717, 0x7094, 0x9086, 0x001e,
+	0x0120, 0x7094, 0x9086, 0x0022, 0x1118, 0x7097, 0x0025, 0x0010,
+	0x7097, 0x0021, 0x012e, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x0005,
+	0x0026, 0x2011, 0x7069, 0x080c, 0x83ae, 0x002e, 0x0016, 0x0026,
+	0x2009, 0x0064, 0x2011, 0x7069, 0x080c, 0x83a5, 0x002e, 0x001e,
+	0x0005, 0x00e6, 0x00f6, 0x0016, 0x080c, 0x9656, 0x2071, 0x1800,
+	0x080c, 0x7006, 0x001e, 0x00fe, 0x00ee, 0x0005, 0x0016, 0x0026,
+	0x0036, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0126, 0x080c, 0x9656,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x2091, 0x8000,
+	0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c, 0x9a0f, 0x2011,
+	0x0002, 0x080c, 0x9a19, 0x080c, 0x9927, 0x080c, 0x835a, 0x0036,
+	0x901e, 0x080c, 0x999d, 0x003e, 0x60e3, 0x0000, 0x080c, 0xdc13,
+	0x080c, 0xdc2e, 0x2009, 0x0004, 0x080c, 0x2bb6, 0x080c, 0x2a89,
+	0x2001, 0x1800, 0x2003, 0x0004, 0x6027, 0x0008, 0x2011, 0x7069,
+	0x080c, 0x83ae, 0x080c, 0x7221, 0x0118, 0x9006, 0x080c, 0x2c88,
+	0x080c, 0x0b8f, 0x2001, 0x0001, 0x080c, 0x2717, 0x012e, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x0005, 0x0026,
+	0x00e6, 0x2011, 0x7076, 0x2071, 0x19d2, 0x701c, 0x9206, 0x1118,
+	0x7018, 0x9005, 0x0110, 0x9085, 0x0001, 0x00ee, 0x002e, 0x0005,
+	0x6020, 0xd09c, 0x0005, 0x6800, 0x9084, 0xfffe, 0x9086, 0x00c0,
+	0x01b8, 0x2001, 0x00c0, 0x080c, 0x2c88, 0x0156, 0x20a9, 0x002d,
+	0x1d04, 0x70e8, 0x2091, 0x6000, 0x1f04, 0x70e8, 0x015e, 0x00d6,
+	0x2069, 0x1800, 0x6898, 0x8001, 0x0220, 0x0118, 0x689a, 0x00de,
+	0x0005, 0x689b, 0x0014, 0x68e4, 0xd0dc, 0x0dc8, 0x6800, 0x9086,
+	0x0001, 0x1da8, 0x080c, 0x83ba, 0x0c90, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x080c, 0x7513,
+	0x2001, 0x1945, 0x2003, 0x0000, 0x9006, 0x7096, 0x60e2, 0x6886,
+	0x080c, 0x27e2, 0x9006, 0x080c, 0x2c88, 0x080c, 0x5dea, 0x6027,
+	0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6,
+	0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800,
+	0x2001, 0x1955, 0x200c, 0x9186, 0x0000, 0x0158, 0x9186, 0x0001,
+	0x0158, 0x9186, 0x0002, 0x0158, 0x9186, 0x0003, 0x0158, 0x0804,
+	0x71cf, 0x7097, 0x0022, 0x0040, 0x7097, 0x0021, 0x0028, 0x7097,
+	0x0023, 0x0010, 0x7097, 0x0024, 0x60e3, 0x0000, 0x6887, 0x0001,
+	0x2001, 0x0001, 0x080c, 0x27e2, 0x0026, 0x080c, 0xa069, 0x002e,
+	0x7000, 0x908e, 0x0004, 0x0118, 0x602b, 0x0028, 0x0010, 0x602b,
+	0x0020, 0x0156, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x6024,
+	0xd0ac, 0x0150, 0x012e, 0x015e, 0x080c, 0xc539, 0x0118, 0x9006,
+	0x080c, 0x2cb2, 0x0804, 0x71db, 0x6800, 0x9084, 0x00a1, 0xc0bd,
+	0x6802, 0x080c, 0x2bb0, 0x6904, 0xd1d4, 0x1140, 0x2001, 0x0100,
+	0x080c, 0x2c88, 0x1f04, 0x7167, 0x080c, 0x725e, 0x012e, 0x015e,
+	0x080c, 0x7218, 0x0538, 0x6044, 0x9005, 0x01f8, 0x2001, 0x0100,
+	0x2004, 0x9086, 0x000a, 0x0158, 0x2011, 0x0114, 0x2204, 0x9085,
+	0x0100, 0x2012, 0x6050, 0x0006, 0x9085, 0x0020, 0x6052, 0x080c,
+	0x725e, 0x9006, 0x8001, 0x1df0, 0x2001, 0x0100, 0x2004, 0x9086,
+	0x000a, 0x0140, 0x000e, 0x6052, 0x0028, 0x6804, 0xd0d4, 0x1110,
+	0x080c, 0x725e, 0x080c, 0xc539, 0x0118, 0x9006, 0x080c, 0x2cb2,
+	0x0016, 0x0026, 0x7000, 0x908e, 0x0004, 0x0130, 0x2009, 0x00c8,
+	0x2011, 0x7076, 0x080c, 0x836c, 0x002e, 0x001e, 0x080c, 0x81e7,
+	0x7034, 0xc085, 0x7036, 0x2001, 0x1955, 0x2003, 0x0004, 0x080c,
+	0x6ed3, 0x080c, 0x7218, 0x0138, 0x6804, 0xd0d4, 0x1120, 0xd0dc,
+	0x1100, 0x080c, 0x7509, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6,
+	0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800,
+	0x080c, 0x81fe, 0x080c, 0x81f0, 0x080c, 0x7513, 0x2001, 0x1945,
+	0x2003, 0x0000, 0x9006, 0x7096, 0x60e2, 0x6886, 0x080c, 0x27e2,
+	0x9006, 0x080c, 0x2c88, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027,
+	0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006,
+	0x2001, 0x1954, 0x2004, 0x9086, 0xaaaa, 0x000e, 0x0005, 0x0006,
+	0x080c, 0x55df, 0x9084, 0x0030, 0x9086, 0x0000, 0x000e, 0x0005,
+	0x0006, 0x080c, 0x55df, 0x9084, 0x0030, 0x9086, 0x0030, 0x000e,
+	0x0005, 0x0006, 0x080c, 0x55df, 0x9084, 0x0030, 0x9086, 0x0010,
+	0x000e, 0x0005, 0x0006, 0x080c, 0x55df, 0x9084, 0x0030, 0x9086,
+	0x0020, 0x000e, 0x0005, 0x0036, 0x0016, 0x2001, 0x180c, 0x2004,
+	0x908c, 0x0013, 0x0180, 0x0020, 0x080c, 0x2802, 0x900e, 0x0028,
+	0x080c, 0x67bb, 0x1dc8, 0x2009, 0x0002, 0x2019, 0x0028, 0x080c,
+	0x3156, 0x9006, 0x0019, 0x001e, 0x003e, 0x0005, 0x00e6, 0x2071,
+	0x180c, 0x2e04, 0x0130, 0x080c, 0xc532, 0x1128, 0x9085, 0x0010,
+	0x0010, 0x9084, 0xffef, 0x2072, 0x00ee, 0x0005, 0x6050, 0x0006,
+	0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028, 0x0006,
+	0x2001, 0x0100, 0x2004, 0x9086, 0x000a, 0x0510, 0x0016, 0x6138,
+	0x6050, 0x9084, 0xfbff, 0x9085, 0x2000, 0x6052, 0x613a, 0x20a9,
+	0x0012, 0x1d04, 0x7279, 0x2091, 0x6000, 0x1f04, 0x7279, 0x602f,
+	0x0100, 0x602f, 0x0000, 0x6050, 0x9085, 0x0400, 0x9084, 0xdfff,
+	0x6052, 0x613a, 0x001e, 0x602f, 0x0040, 0x602f, 0x0000, 0x00a0,
+	0x080c, 0x2cc2, 0x080c, 0x2cf5, 0x602f, 0x0100, 0x602f, 0x0000,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x20a9, 0x0002, 0x080c, 0x2b91,
+	0x0026, 0x6027, 0x0040, 0x002e, 0x000e, 0x602a, 0x000e, 0x6006,
+	0x000e, 0x600e, 0x000e, 0x60ee, 0x60e3, 0x0000, 0x6887, 0x0001,
+	0x2001, 0x0001, 0x080c, 0x27e2, 0x2001, 0x00a0, 0x0006, 0x080c,
+	0xc539, 0x000e, 0x0130, 0x080c, 0x2ca6, 0x9006, 0x080c, 0x2cb2,
+	0x0010, 0x080c, 0x2c88, 0x000e, 0x6052, 0x6050, 0x0006, 0xc0e5,
+	0x6052, 0x00f6, 0x2079, 0x0100, 0x080c, 0x2b06, 0x00fe, 0x000e,
+	0x6052, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0x1800, 0x6020,
+	0x9084, 0x0080, 0x0138, 0x2001, 0x180c, 0x200c, 0xc1c5, 0x2102,
+	0x0804, 0x734b, 0x2001, 0x180c, 0x200c, 0xc1c4, 0x2102, 0x6028,
+	0x9084, 0xe1ff, 0x602a, 0x6027, 0x0200, 0x2001, 0x0090, 0x080c,
+	0x2c88, 0x20a9, 0x0366, 0x6024, 0xd0cc, 0x1518, 0x1d04, 0x72fb,
+	0x2091, 0x6000, 0x1f04, 0x72fb, 0x2011, 0x0003, 0x080c, 0x9a0f,
+	0x2011, 0x0002, 0x080c, 0x9a19, 0x080c, 0x9927, 0x901e, 0x080c,
+	0x999d, 0x2001, 0x00a0, 0x080c, 0x2c88, 0x080c, 0x7504, 0x080c,
+	0x5f2b, 0x080c, 0xc539, 0x0110, 0x080c, 0x0d68, 0x9085, 0x0001,
+	0x0480, 0x080c, 0x1a24, 0x60e3, 0x0000, 0x2001, 0x0002, 0x080c,
+	0x27e2, 0x60e2, 0x2001, 0x0080, 0x080c, 0x2c88, 0x20a9, 0x0366,
+	0x6027, 0x1e00, 0x2009, 0x1e00, 0x080c, 0x2bb0, 0x6024, 0x910c,
+	0x0138, 0x1d04, 0x7330, 0x2091, 0x6000, 0x1f04, 0x7330, 0x0820,
+	0x6028, 0x9085, 0x1e00, 0x602a, 0x70b0, 0x9005, 0x1118, 0x6887,
+	0x0001, 0x0008, 0x6886, 0x080c, 0xc539, 0x0110, 0x080c, 0x0d68,
+	0x9006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2071, 0x1800, 0x7000, 0x9086, 0x0003, 0x1168,
+	0x2001, 0x020b, 0x2004, 0x9084, 0x5540, 0x9086, 0x5540, 0x1128,
+	0x2069, 0x1a50, 0x2d04, 0x8000, 0x206a, 0x2069, 0x0140, 0x6020,
+	0x9084, 0x00c0, 0x0120, 0x6884, 0x9005, 0x1904, 0x73be, 0x2001,
+	0x0088, 0x080c, 0x2c88, 0x9006, 0x60e2, 0x6886, 0x080c, 0x27e2,
+	0x2069, 0x0200, 0x6804, 0x9005, 0x1118, 0x6808, 0x9005, 0x01c0,
+	0x6028, 0x9084, 0xfbff, 0x602a, 0x6027, 0x0400, 0x2069, 0x1967,
+	0x7000, 0x206a, 0x7097, 0x0026, 0x7003, 0x0001, 0x20a9, 0x0002,
+	0x1d04, 0x73a0, 0x2091, 0x6000, 0x1f04, 0x73a0, 0x0804, 0x73eb,
+	0x2069, 0x0140, 0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00,
+	0x080c, 0x2bb0, 0x6024, 0x910c, 0x0508, 0x9084, 0x1a00, 0x11f0,
+	0x1d04, 0x73ac, 0x2091, 0x6000, 0x1f04, 0x73ac, 0x2011, 0x0003,
+	0x080c, 0x9a0f, 0x2011, 0x0002, 0x080c, 0x9a19, 0x080c, 0x9927,
+	0x901e, 0x080c, 0x999d, 0x2001, 0x00a0, 0x080c, 0x2c88, 0x080c,
+	0x7504, 0x080c, 0x5f2b, 0x9085, 0x0001, 0x00a8, 0x2001, 0x0080,
+	0x080c, 0x2c88, 0x2069, 0x0140, 0x60e3, 0x0000, 0x70b0, 0x9005,
+	0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001, 0x0002, 0x080c,
+	0x27e2, 0x60e2, 0x9006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e,
+	0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6,
+	0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800, 0x6020, 0x9084,
+	0x00c0, 0x01c8, 0x2011, 0x0003, 0x080c, 0x9a0f, 0x2011, 0x0002,
+	0x080c, 0x9a19, 0x080c, 0x9927, 0x901e, 0x080c, 0x999d, 0x2069,
+	0x0140, 0x2001, 0x00a0, 0x080c, 0x2c88, 0x080c, 0x7504, 0x080c,
+	0x5f2b, 0x0804, 0x7485, 0x2001, 0x180c, 0x200c, 0xd1b4, 0x1160,
+	0xc1b5, 0x2102, 0x080c, 0x705e, 0x2069, 0x0140, 0x2001, 0x0080,
+	0x080c, 0x2c88, 0x60e3, 0x0000, 0x2069, 0x0200, 0x6804, 0x9005,
+	0x1118, 0x6808, 0x9005, 0x0180, 0x6028, 0x9084, 0xfdff, 0x602a,
+	0x6027, 0x0200, 0x2069, 0x1967, 0x7000, 0x206a, 0x7097, 0x0027,
+	0x7003, 0x0001, 0x0804, 0x7485, 0x6027, 0x1e00, 0x2009, 0x1e00,
+	0x080c, 0x2bb0, 0x6024, 0x910c, 0x01c8, 0x9084, 0x1c00, 0x11b0,
+	0x1d04, 0x7444, 0x0006, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c,
+	0x823e, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071,
+	0x19d2, 0x7070, 0x00ee, 0x9005, 0x19f8, 0x00f8, 0x0026, 0x2011,
+	0x7076, 0x080c, 0x82da, 0x2011, 0x7069, 0x080c, 0x83ae, 0x002e,
+	0x2069, 0x0140, 0x60e3, 0x0000, 0x70b0, 0x9005, 0x1118, 0x6887,
+	0x0001, 0x0008, 0x6886, 0x2001, 0x0002, 0x080c, 0x27e2, 0x60e2,
+	0x2001, 0x180c, 0x200c, 0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce,
+	0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026,
+	0x0036, 0x0046, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0x1800,
+	0x080c, 0xc532, 0x1904, 0x74f2, 0x7130, 0xd184, 0x1170, 0x080c,
+	0x32e4, 0x0138, 0xc18d, 0x7132, 0x2011, 0x185c, 0x2214, 0xd2ac,
+	0x1120, 0x7030, 0xd08c, 0x0904, 0x74f2, 0x2011, 0x185c, 0x220c,
+	0x0438, 0x0016, 0x2019, 0x000e, 0x080c, 0xd801, 0x0156, 0x00b6,
+	0x20a9, 0x007f, 0x900e, 0x9186, 0x007e, 0x01a0, 0x9186, 0x0080,
+	0x0188, 0x080c, 0x649f, 0x1170, 0x2120, 0x9006, 0x0016, 0x2009,
+	0x000e, 0x080c, 0xd885, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c,
+	0x84d1, 0x001e, 0x8108, 0x1f04, 0x74bb, 0x00be, 0x015e, 0x001e,
+	0xd1ac, 0x1148, 0x0016, 0x2009, 0x0002, 0x2019, 0x0004, 0x080c,
+	0x3156, 0x001e, 0x0078, 0x0156, 0x00b6, 0x20a9, 0x007f, 0x900e,
+	0x080c, 0x649f, 0x1110, 0x080c, 0x5f45, 0x8108, 0x1f04, 0x74e8,
+	0x00be, 0x015e, 0x080c, 0x1a24, 0x080c, 0xa069, 0x60e3, 0x0000,
+	0x080c, 0x5f2b, 0x080c, 0x7127, 0x00ee, 0x00ce, 0x004e, 0x003e,
+	0x002e, 0x001e, 0x015e, 0x0005, 0x2001, 0x1955, 0x2003, 0x0001,
+	0x0005, 0x2001, 0x1955, 0x2003, 0x0000, 0x0005, 0x2001, 0x1954,
+	0x2003, 0xaaaa, 0x0005, 0x2001, 0x1954, 0x2003, 0x0000, 0x0005,
+	0x2071, 0x18f8, 0x7003, 0x0000, 0x7007, 0x0000, 0x080c, 0x104a,
+	0x090c, 0x0dfa, 0xa8ab, 0xdcb0, 0x2900, 0x704e, 0x080c, 0x104a,
+	0x090c, 0x0dfa, 0xa8ab, 0xdcb0, 0x2900, 0x7052, 0xa867, 0x0000,
+	0xa86b, 0x0001, 0xa89f, 0x0000, 0x0005, 0x00e6, 0x2071, 0x0040,
+	0x6848, 0x9005, 0x1118, 0x9085, 0x0001, 0x04b0, 0x6840, 0x9005,
+	0x0150, 0x04a1, 0x6a50, 0x9200, 0x7002, 0x6854, 0x9101, 0x7006,
+	0x9006, 0x7012, 0x7016, 0x6850, 0x7002, 0x6854, 0x7006, 0x6858,
+	0x700a, 0x685c, 0x700e, 0x6840, 0x9005, 0x1110, 0x7012, 0x7016,
+	0x6848, 0x701a, 0x701c, 0x9085, 0x0040, 0x701e, 0x2001, 0x0019,
+	0x7036, 0x702b, 0x0001, 0x2001, 0x0004, 0x200c, 0x918c, 0xfff7,
+	0x918d, 0x8000, 0x2102, 0x00d6, 0x2069, 0x18f8, 0x6807, 0x0001,
+	0x00de, 0x080c, 0x7afd, 0x9006, 0x00ee, 0x0005, 0x900e, 0x0156,
+	0x20a9, 0x0006, 0x8003, 0x818d, 0x1f04, 0x757a, 0x015e, 0x0005,
+	0x2079, 0x0040, 0x2071, 0x18f8, 0x7004, 0x0002, 0x7590, 0x7591,
+	0x75c9, 0x7624, 0x7765, 0x758e, 0x758e, 0x778f, 0x080c, 0x0dfa,
+	0x0005, 0x2079, 0x0040, 0x782c, 0x908c, 0x0780, 0x190c, 0x7b89,
+	0xd0a4, 0x01f8, 0x7824, 0x2048, 0x9006, 0xa802, 0xa806, 0xa864,
+	0x9084, 0x00ff, 0x908a, 0x0040, 0x0610, 0x00c0, 0x2001, 0x1800,
+	0x200c, 0x9186, 0x0003, 0x1168, 0x7004, 0x0002, 0x75b9, 0x7593,
+	0x75b9, 0x75b7, 0x75b9, 0x75b9, 0x75b9, 0x75b9, 0x75b9, 0x080c,
+	0x7624, 0x782c, 0xd09c, 0x090c, 0x7afd, 0x0005, 0x9082, 0x005a,
+	0x1218, 0x2100, 0x003b, 0x0c10, 0x080c, 0x765a, 0x0c90, 0x00e3,
+	0x08e8, 0x0005, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x767c, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x7666, 0x765a,
+	0x7864, 0x765a, 0x765a, 0x765a, 0x767c, 0x765a, 0x7666, 0x78a5,
+	0x78e6, 0x792d, 0x7941, 0x765a, 0x765a, 0x767c, 0x7666, 0x765a,
+	0x765a, 0x7739, 0x79ec, 0x7a07, 0x765a, 0x767c, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x772f, 0x7a07, 0x765a, 0x765a, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x7690, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x7b2d,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x765a, 0x76a4, 0x765a, 0x765a,
+	0x765a, 0x765a, 0x765a, 0x765a, 0x2079, 0x0040, 0x7004, 0x9086,
+	0x0003, 0x1198, 0x782c, 0x080c, 0x7b26, 0xd0a4, 0x0170, 0x7824,
+	0x2048, 0x9006, 0xa802, 0xa806, 0xa864, 0x9084, 0x00ff, 0x908a,
+	0x001a, 0x1210, 0x002b, 0x0c50, 0x00e9, 0x080c, 0x7afd, 0x0005,
+	0x765a, 0x7666, 0x7850, 0x765a, 0x7666, 0x765a, 0x7666, 0x7666,
+	0x765a, 0x7666, 0x7850, 0x7666, 0x7666, 0x7666, 0x7666, 0x7666,
+	0x765a, 0x7666, 0x7850, 0x765a, 0x765a, 0x7666, 0x765a, 0x765a,
+	0x765a, 0x7666, 0x00e6, 0x2071, 0x18f8, 0x2009, 0x0400, 0x0071,
+	0x00ee, 0x0005, 0x2009, 0x1000, 0x0049, 0x0005, 0x2009, 0x2000,
+	0x0029, 0x0005, 0x2009, 0x0800, 0x0009, 0x0005, 0x7007, 0x0001,
+	0xa868, 0x9084, 0x00ff, 0x9105, 0xa86a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6ae9, 0x012e, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff,
+	0x0d08, 0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x780e, 0x7007,
+	0x0003, 0x7012, 0x2900, 0x7016, 0x701a, 0x704b, 0x780e, 0x0005,
+	0xa864, 0x8007, 0x9084, 0x00ff, 0x0968, 0x8001, 0x1120, 0x7007,
+	0x0001, 0x0804, 0x7829, 0x7007, 0x0003, 0x7012, 0x2900, 0x7016,
+	0x701a, 0x704b, 0x7829, 0x0005, 0xa864, 0x8007, 0x9084, 0x00ff,
+	0x9086, 0x0001, 0x1904, 0x7662, 0x7007, 0x0001, 0x2009, 0x1833,
+	0x210c, 0x81ff, 0x1904, 0x7706, 0xa994, 0x9186, 0x006f, 0x0188,
+	0x9186, 0x0074, 0x15b0, 0x0026, 0x2011, 0x0010, 0x080c, 0x67e7,
+	0x002e, 0x0578, 0x0016, 0xa998, 0x080c, 0x6831, 0x001e, 0x1548,
+	0x0400, 0x080c, 0x7207, 0x0140, 0xa897, 0x4005, 0xa89b, 0x0016,
+	0x2001, 0x0030, 0x900e, 0x0438, 0x0026, 0x2011, 0x8008, 0x080c,
+	0x67e7, 0x002e, 0x01b0, 0x0016, 0x0026, 0x0036, 0xa998, 0xaaa0,
+	0xab9c, 0x918d, 0x8000, 0x080c, 0x6831, 0x003e, 0x002e, 0x001e,
+	0x1140, 0xa897, 0x4005, 0xa89b, 0x4009, 0x2001, 0x0030, 0x900e,
+	0x0050, 0xa868, 0x9084, 0x00ff, 0xa86a, 0xa883, 0x0000, 0x080c,
+	0x615d, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000, 0xa867, 0x0139,
+	0xa87a, 0xa982, 0x080c, 0x6ae9, 0x012e, 0x0ca0, 0xa994, 0x9186,
+	0x0071, 0x0904, 0x76b4, 0x9186, 0x0064, 0x0904, 0x76b4, 0x9186,
+	0x007c, 0x0904, 0x76b4, 0x9186, 0x0028, 0x0904, 0x76b4, 0x9186,
+	0x0038, 0x0904, 0x76b4, 0x9186, 0x0078, 0x0904, 0x76b4, 0x9186,
+	0x005f, 0x0904, 0x76b4, 0x9186, 0x0056, 0x0904, 0x76b4, 0xa897,
+	0x4005, 0xa89b, 0x0001, 0x2001, 0x0030, 0x900e, 0x0860, 0xa87c,
+	0x9084, 0x00c0, 0x9086, 0x00c0, 0x1120, 0x7007, 0x0001, 0x0804,
+	0x7a1e, 0x2900, 0x7016, 0x701a, 0x20a9, 0x0004, 0xa860, 0x20e0,
+	0xa85c, 0x9080, 0x0030, 0x2098, 0x7050, 0x2040, 0xa060, 0x20e8,
+	0xa05c, 0x9080, 0x0023, 0x20a0, 0x4003, 0xa888, 0x7012, 0x9082,
+	0x0401, 0x1a04, 0x766a, 0xaab4, 0x928a, 0x0002, 0x1a04, 0x766a,
+	0x82ff, 0x1138, 0xa8b8, 0xa9bc, 0x9105, 0x0118, 0x2001, 0x77cc,
+	0x0018, 0x9280, 0x77c2, 0x2005, 0x7056, 0x7010, 0x9015, 0x0904,
+	0x77ad, 0x080c, 0x104a, 0x1118, 0x7007, 0x0004, 0x0005, 0x2900,
+	0x7022, 0x7054, 0x2060, 0xe000, 0xa866, 0x7050, 0x2040, 0xa95c,
+	0xe004, 0x9100, 0xa076, 0xa860, 0xa072, 0xe008, 0x920a, 0x1210,
+	0x900e, 0x2200, 0x7112, 0xe20c, 0x8003, 0x800b, 0x9296, 0x0004,
+	0x0108, 0x9108, 0xa17a, 0x810b, 0xa17e, 0x080c, 0x112e, 0xa06c,
+	0x908e, 0x0100, 0x0170, 0x9086, 0x0200, 0x0118, 0x7007, 0x0007,
+	0x0005, 0x7020, 0x2048, 0x080c, 0x1063, 0x7014, 0x2048, 0x0804,
+	0x766a, 0x7020, 0x2048, 0x7018, 0xa802, 0xa807, 0x0000, 0x2908,
+	0x2048, 0xa906, 0x711a, 0x0804, 0x7765, 0x7014, 0x2048, 0x7007,
+	0x0001, 0xa8b4, 0x9005, 0x1128, 0xa8b8, 0xa9bc, 0x9105, 0x0108,
+	0x00b9, 0xa864, 0x9084, 0x00ff, 0x9086, 0x001e, 0x0904, 0x7a1e,
+	0x0804, 0x780e, 0x77c4, 0x77c8, 0x0002, 0x001d, 0x0007, 0x0004,
+	0x000a, 0x001b, 0x0005, 0x0006, 0x000a, 0x001d, 0x0005, 0x0004,
+	0x0076, 0x0066, 0xafb8, 0xaebc, 0xa804, 0x2050, 0xb0c0, 0xb0e2,
+	0xb0bc, 0xb0de, 0xb0b8, 0xb0d2, 0xb0b4, 0xb0ce, 0xb6da, 0xb7d6,
+	0xb0b0, 0xb0ca, 0xb0ac, 0xb0c6, 0xb0a8, 0xb0ba, 0xb0a4, 0xb0b6,
+	0xb6c2, 0xb7be, 0xb0a0, 0xb0b2, 0xb09c, 0xb0ae, 0xb098, 0xb0a2,
+	0xb094, 0xb09e, 0xb6aa, 0xb7a6, 0xb090, 0xb09a, 0xb08c, 0xb096,
+	0xb088, 0xb08a, 0xb084, 0xb086, 0xb692, 0xb78e, 0xb080, 0xb082,
+	0xb07c, 0xb07e, 0xb078, 0xb072, 0xb074, 0xb06e, 0xb67a, 0xb776,
+	0xb004, 0x9055, 0x1958, 0x006e, 0x007e, 0x0005, 0x2009, 0x1833,
+	0x210c, 0x81ff, 0x1178, 0x080c, 0x5fa7, 0x1108, 0x0005, 0x080c,
+	0x6d17, 0x0126, 0x2091, 0x8000, 0x080c, 0xc12d, 0x080c, 0x6ae9,
+	0x012e, 0x0ca0, 0x080c, 0xc532, 0x1d70, 0x2001, 0x0028, 0x900e,
+	0x0c70, 0x2009, 0x1833, 0x210c, 0x81ff, 0x11d8, 0xa888, 0x9005,
+	0x01e0, 0xa883, 0x0000, 0xa87c, 0xd0f4, 0x0120, 0x080c, 0x60bf,
+	0x1138, 0x0005, 0x9006, 0xa87a, 0x080c, 0x6037, 0x1108, 0x0005,
+	0x0126, 0x2091, 0x8000, 0xa87a, 0xa982, 0x080c, 0x6ae9, 0x012e,
+	0x0cb0, 0x2001, 0x0028, 0x900e, 0x0c98, 0x2001, 0x0000, 0x0c80,
+	0x7018, 0xa802, 0x2908, 0x2048, 0xa906, 0x711a, 0x7010, 0x8001,
+	0x7012, 0x0118, 0x7007, 0x0003, 0x0030, 0x7014, 0x2048, 0x7007,
+	0x0001, 0x7048, 0x080f, 0x0005, 0x00b6, 0x7007, 0x0001, 0xa974,
+	0xa878, 0x9084, 0x00ff, 0x9096, 0x0004, 0x0540, 0x20a9, 0x0001,
+	0x9096, 0x0001, 0x0190, 0x900e, 0x20a9, 0x0800, 0x9096, 0x0002,
+	0x0160, 0x9005, 0x11d8, 0xa974, 0x080c, 0x649f, 0x11b8, 0x0066,
+	0xae80, 0x080c, 0x65af, 0x006e, 0x0088, 0x0046, 0x2011, 0x180c,
+	0x2224, 0xc484, 0x2412, 0x004e, 0x00c6, 0x080c, 0x649f, 0x1110,
+	0x080c, 0x66af, 0x8108, 0x1f04, 0x788d, 0x00ce, 0xa87c, 0xd084,
+	0x1120, 0x080c, 0x1063, 0x00be, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6ae9, 0x012e, 0x00be, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x7007, 0x0001, 0x080c, 0x67bf, 0x0580, 0x2061, 0x1a48, 0x6100,
+	0xd184, 0x0178, 0xa888, 0x9084, 0x00ff, 0x1550, 0x6000, 0xd084,
+	0x0520, 0x6004, 0x9005, 0x1538, 0x6003, 0x0000, 0x600b, 0x0000,
+	0x00c8, 0x2011, 0x0001, 0xa890, 0x9005, 0x1110, 0x2001, 0x001e,
+	0x8000, 0x6016, 0xa888, 0x9084, 0x00ff, 0x0178, 0x6006, 0xa888,
+	0x8007, 0x9084, 0x00ff, 0x0148, 0x600a, 0xa888, 0x8000, 0x1108,
+	0xc28d, 0x6202, 0x012e, 0x0804, 0x7ae7, 0x012e, 0x0804, 0x7ae1,
+	0x012e, 0x0804, 0x7adb, 0x012e, 0x0804, 0x7ade, 0x0126, 0x2091,
+	0x8000, 0x7007, 0x0001, 0x080c, 0x67bf, 0x05e0, 0x2061, 0x1a48,
+	0x6000, 0xd084, 0x05b8, 0x6204, 0x6308, 0xd08c, 0x1530, 0xac78,
+	0x9484, 0x0003, 0x0170, 0xa988, 0x918c, 0x00ff, 0x8001, 0x1120,
+	0x2100, 0x9210, 0x0620, 0x0028, 0x8001, 0x1508, 0x2100, 0x9212,
+	0x02f0, 0x9484, 0x000c, 0x0188, 0xa988, 0x810f, 0x918c, 0x00ff,
+	0x9082, 0x0004, 0x1120, 0x2100, 0x9318, 0x0288, 0x0030, 0x9082,
+	0x0004, 0x1168, 0x2100, 0x931a, 0x0250, 0xa890, 0x9005, 0x0110,
+	0x8000, 0x6016, 0x6206, 0x630a, 0x012e, 0x0804, 0x7ae7, 0x012e,
+	0x0804, 0x7ae4, 0x012e, 0x0804, 0x7ae1, 0x0126, 0x2091, 0x8000,
+	0x7007, 0x0001, 0x2061, 0x1a48, 0x6300, 0xd38c, 0x1120, 0x6308,
+	0x8318, 0x0220, 0x630a, 0x012e, 0x0804, 0x7af5, 0x012e, 0x0804,
+	0x7ae4, 0x00b6, 0x0126, 0x00c6, 0x2091, 0x8000, 0x7007, 0x0001,
+	0xa87c, 0xd0ac, 0x0148, 0x00c6, 0x2061, 0x1a48, 0x6000, 0x9084,
+	0xfcff, 0x6002, 0x00ce, 0x0440, 0xa888, 0x9005, 0x05d8, 0xa88c,
+	0x9065, 0x0598, 0x2001, 0x1833, 0x2004, 0x9005, 0x0118, 0x080c,
+	0xa113, 0x0068, 0x6017, 0xf400, 0x605b, 0x0000, 0xa97c, 0xd1a4,
+	0x0110, 0xa980, 0x615a, 0x2009, 0x0041, 0x080c, 0xa15d, 0xa988,
+	0x918c, 0xff00, 0x9186, 0x2000, 0x1138, 0x0026, 0x900e, 0x2011,
+	0xfdff, 0x080c, 0x84d1, 0x002e, 0xa87c, 0xd0c4, 0x0148, 0x2061,
+	0x1a48, 0x6000, 0xd08c, 0x1120, 0x6008, 0x8000, 0x0208, 0x600a,
+	0x00ce, 0x012e, 0x00be, 0x0804, 0x7ae7, 0x00ce, 0x012e, 0x00be,
+	0x0804, 0x7ae1, 0xa984, 0x9186, 0x002e, 0x0d30, 0x9186, 0x002d,
+	0x0d18, 0x9186, 0x0045, 0x0510, 0x9186, 0x002a, 0x1130, 0x2001,
+	0x180c, 0x200c, 0xc194, 0x2102, 0x08b8, 0x9186, 0x0020, 0x0158,
+	0x9186, 0x0029, 0x1d10, 0xa974, 0x080c, 0x649f, 0x1968, 0xb800,
+	0xc0e4, 0xb802, 0x0848, 0xa88c, 0x9065, 0x09b8, 0x6007, 0x0024,
+	0x2001, 0x195e, 0x2004, 0x601a, 0x0804, 0x797c, 0xa88c, 0x9065,
+	0x0960, 0x00e6, 0xa890, 0x9075, 0x2001, 0x1833, 0x2004, 0x9005,
+	0x0150, 0x080c, 0xa113, 0x8eff, 0x0118, 0x2e60, 0x080c, 0xa113,
+	0x00ee, 0x0804, 0x797c, 0x6024, 0xc0dc, 0xc0d5, 0x6026, 0x2e60,
+	0x6007, 0x003a, 0xa8a0, 0x9005, 0x0130, 0x6007, 0x003b, 0xa8a4,
+	0x602e, 0xa8a8, 0x6016, 0x6003, 0x0001, 0x080c, 0x8679, 0x080c,
+	0x8c10, 0x00ee, 0x0804, 0x797c, 0x2061, 0x1a48, 0x6000, 0xd084,
+	0x0190, 0xd08c, 0x1904, 0x7af5, 0x0126, 0x2091, 0x8000, 0x6204,
+	0x8210, 0x0220, 0x6206, 0x012e, 0x0804, 0x7af5, 0x012e, 0xa883,
+	0x0016, 0x0804, 0x7aee, 0xa883, 0x0007, 0x0804, 0x7aee, 0xa864,
+	0x8007, 0x9084, 0x00ff, 0x0130, 0x8001, 0x1138, 0x7007, 0x0001,
+	0x0069, 0x0005, 0x080c, 0x7662, 0x0040, 0x7007, 0x0003, 0x7012,
+	0x2900, 0x7016, 0x701a, 0x704b, 0x7a1e, 0x0005, 0x00b6, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0x903e, 0x2061, 0x1800, 0x61cc, 0x81ff,
+	0x1904, 0x7aa0, 0x6130, 0xd194, 0x1904, 0x7aca, 0xa878, 0x2070,
+	0x9e82, 0x1cd0, 0x0a04, 0x7a94, 0x6064, 0x9e02, 0x1a04, 0x7a94,
+	0x7120, 0x9186, 0x0006, 0x1904, 0x7a86, 0x7010, 0x905d, 0x0904,
+	0x7aa0, 0xb800, 0xd0e4, 0x1904, 0x7ac4, 0x2061, 0x1a48, 0x6100,
+	0x9184, 0x0301, 0x9086, 0x0001, 0x15a0, 0x7024, 0xd0dc, 0x1904,
+	0x7acd, 0xa883, 0x0000, 0xa803, 0x0000, 0x2908, 0x7014, 0x9005,
+	0x1198, 0x7116, 0xa87c, 0xd0f4, 0x1904, 0x7ad0, 0x080c, 0x55db,
+	0xd09c, 0x1118, 0xa87c, 0xc0cc, 0xa87e, 0x2e60, 0x080c, 0x83f1,
+	0x012e, 0x00ee, 0x00be, 0x0005, 0x2048, 0xa800, 0x9005, 0x1de0,
+	0xa902, 0x2148, 0xa87c, 0xd0f4, 0x1904, 0x7ad0, 0x012e, 0x00ee,
+	0x00be, 0x0005, 0x012e, 0x00ee, 0xa883, 0x0006, 0x00be, 0x0804,
+	0x7aee, 0xd184, 0x0db8, 0xd1c4, 0x1190, 0x00a0, 0xa974, 0x080c,
+	0x649f, 0x15d0, 0xb800, 0xd0e4, 0x15b8, 0x7120, 0x9186, 0x0007,
+	0x1118, 0xa883, 0x0002, 0x0490, 0xa883, 0x0008, 0x0478, 0xa883,
+	0x000e, 0x0460, 0xa883, 0x0017, 0x0448, 0xa883, 0x0035, 0x0430,
+	0x080c, 0x55df, 0xd0fc, 0x01e8, 0xa878, 0x2070, 0x9e82, 0x1cd0,
+	0x02c0, 0x6064, 0x9e02, 0x12a8, 0x7120, 0x9186, 0x0006, 0x1188,
+	0x7010, 0x905d, 0x0170, 0xb800, 0xd0bc, 0x0158, 0x2039, 0x0001,
+	0x7000, 0x9086, 0x0007, 0x1904, 0x7a2a, 0x7003, 0x0002, 0x0804,
+	0x7a2a, 0xa883, 0x0028, 0x0010, 0xa883, 0x0029, 0x012e, 0x00ee,
+	0x00be, 0x0420, 0xa883, 0x002a, 0x0cc8, 0xa883, 0x0045, 0x0cb0,
+	0x2e60, 0x2019, 0x0002, 0x601b, 0x0014, 0x080c, 0xd440, 0x012e,
+	0x00ee, 0x00be, 0x0005, 0x2009, 0x003e, 0x0058, 0x2009, 0x0004,
+	0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, 0x2009,
+	0x0001, 0xa884, 0x9084, 0xff00, 0x9105, 0xa886, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6ae9, 0x012e, 0x0005, 0x080c, 0x1063, 0x0005,
+	0x00d6, 0x080c, 0x83e8, 0x00de, 0x0005, 0x00d6, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x0040, 0x702c, 0xd084, 0x01d8, 0x908c,
+	0x0780, 0x190c, 0x7b89, 0xd09c, 0x11a8, 0x2071, 0x1800, 0x70bc,
+	0x90ea, 0x0040, 0x0278, 0x8001, 0x70be, 0x702c, 0x2048, 0xa800,
+	0x702e, 0x9006, 0xa802, 0xa806, 0x2071, 0x0040, 0x2900, 0x7022,
+	0x702c, 0x0c28, 0x012e, 0x00ee, 0x00de, 0x0005, 0x0006, 0x9084,
+	0x0780, 0x190c, 0x7b89, 0x000e, 0x0005, 0x00d6, 0x00c6, 0x0036,
+	0x0026, 0x0016, 0x00b6, 0x7007, 0x0001, 0xaa74, 0x9282, 0x0004,
+	0x1a04, 0x7b7a, 0xa97c, 0x9188, 0x1000, 0x2104, 0x905d, 0xb804,
+	0xd284, 0x0140, 0x05e8, 0x8007, 0x9084, 0x00ff, 0x9084, 0x0006,
+	0x1108, 0x04b0, 0x2b10, 0x080c, 0xa08d, 0x1118, 0x080c, 0xa130,
+	0x05a8, 0x6212, 0xa874, 0x0002, 0x7b58, 0x7b5d, 0x7b60, 0x7b66,
+	0x2019, 0x0002, 0x080c, 0xd801, 0x0060, 0x080c, 0xd79d, 0x0048,
+	0x2019, 0x0002, 0xa980, 0x080c, 0xd7b8, 0x0018, 0xa980, 0x080c,
+	0xd79d, 0x080c, 0xa0e3, 0xa887, 0x0000, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6ae9, 0x012e, 0x00be, 0x001e, 0x002e, 0x003e, 0x00ce,
+	0x00de, 0x0005, 0xa887, 0x0006, 0x0c80, 0xa887, 0x0002, 0x0c68,
+	0xa887, 0x0005, 0x0c50, 0xa887, 0x0004, 0x0c38, 0xa887, 0x0007,
+	0x0c20, 0x2091, 0x8000, 0x0e04, 0x7b8b, 0x0006, 0x0016, 0x2001,
+	0x8003, 0x0006, 0x0804, 0x0e03, 0x2001, 0x1833, 0x2004, 0x9005,
+	0x0005, 0x0005, 0x00f6, 0x2079, 0x0300, 0x2001, 0x0200, 0x200c,
+	0xc1e5, 0xc1dc, 0x2102, 0x2009, 0x0218, 0x210c, 0xd1ec, 0x1120,
+	0x080c, 0x151a, 0x00fe, 0x0005, 0x2001, 0x020d, 0x2003, 0x0020,
+	0x781f, 0x0300, 0x00fe, 0x0005, 0x781c, 0xd08c, 0x0904, 0x7c0b,
+	0x68bc, 0x90aa, 0x0005, 0x0a04, 0x81e7, 0x7d44, 0x7c40, 0x9584,
+	0x00f6, 0x1510, 0x9484, 0x7000, 0x0140, 0x908a, 0x2000, 0x1260,
+	0x9584, 0x0700, 0x8007, 0x0804, 0x7c12, 0x7000, 0x9084, 0xff00,
+	0x9086, 0x8100, 0x0da8, 0x00b0, 0x9484, 0x0fff, 0x1130, 0x7000,
+	0x9084, 0xff00, 0x9086, 0x8100, 0x11c0, 0x080c, 0xdbeb, 0x080c,
+	0x811c, 0x7817, 0x0140, 0x00a8, 0x9584, 0x0076, 0x1118, 0x080c,
+	0x817a, 0x19c0, 0xd5a4, 0x0148, 0x0046, 0x0056, 0x080c, 0x7c6d,
+	0x080c, 0x226f, 0x005e, 0x004e, 0x0020, 0x080c, 0xdbeb, 0x7817,
+	0x0140, 0x080c, 0x7207, 0x0168, 0x2001, 0x0111, 0x2004, 0xd08c,
+	0x0140, 0x688f, 0x0000, 0x2001, 0x0110, 0x2003, 0x0008, 0x2003,
+	0x0000, 0x080c, 0x7c4e, 0x2001, 0x19c8, 0x2004, 0x9005, 0x090c,
+	0x8c10, 0x0005, 0x0002, 0x7c24, 0x7f24, 0x7c1b, 0x7c1b, 0x7c1b,
+	0x7c1b, 0x7c1b, 0x7c1b, 0x7817, 0x0140, 0x2001, 0x19c8, 0x2004,
+	0x9005, 0x090c, 0x8c10, 0x0005, 0x7000, 0x908c, 0xff00, 0x9194,
+	0xf000, 0x810f, 0x9484, 0x0fff, 0x688e, 0x9286, 0x2000, 0x1150,
+	0x6800, 0x9086, 0x0001, 0x1118, 0x080c, 0x5641, 0x0070, 0x080c,
+	0x7c8d, 0x0058, 0x9286, 0x3000, 0x1118, 0x080c, 0x7e5c, 0x0028,
+	0x9286, 0x8000, 0x1110, 0x080c, 0x8043, 0x7817, 0x0140, 0x2001,
+	0x19c8, 0x2004, 0x9005, 0x090c, 0x8c10, 0x0005, 0x2001, 0x1810,
+	0x2004, 0xd08c, 0x0178, 0x2001, 0x1800, 0x2004, 0x9086, 0x0003,
+	0x1148, 0x0026, 0x0036, 0x2011, 0x8048, 0x2518, 0x080c, 0x4b1f,
+	0x003e, 0x002e, 0x0005, 0x0036, 0x0046, 0x0056, 0x00f6, 0x2079,
+	0x0200, 0x2019, 0xfffe, 0x7c30, 0x0050, 0x0036, 0x0046, 0x0056,
+	0x00f6, 0x2079, 0x0200, 0x7d44, 0x7c40, 0x2019, 0xffff, 0x2001,
+	0x1810, 0x2004, 0xd08c, 0x0160, 0x2001, 0x1800, 0x2004, 0x9086,
+	0x0003, 0x1130, 0x0026, 0x2011, 0x8048, 0x080c, 0x4b1f, 0x002e,
+	0x00fe, 0x005e, 0x004e, 0x003e, 0x0005, 0x00b6, 0x00c6, 0x7010,
+	0x9084, 0xff00, 0x8007, 0x9096, 0x0001, 0x0120, 0x9096, 0x0023,
+	0x1904, 0x7e2d, 0x9186, 0x0023, 0x15c0, 0x080c, 0x80e1, 0x0904,
+	0x7e2d, 0x6120, 0x9186, 0x0001, 0x0150, 0x9186, 0x0004, 0x0138,
+	0x9186, 0x0008, 0x0120, 0x9186, 0x000a, 0x1904, 0x7e2d, 0x7124,
+	0x610a, 0x7030, 0x908e, 0x0200, 0x1130, 0x2009, 0x0015, 0x080c,
+	0xa15d, 0x0804, 0x7e2d, 0x908e, 0x0214, 0x0118, 0x908e, 0x0210,
+	0x1130, 0x2009, 0x0015, 0x080c, 0xa15d, 0x0804, 0x7e2d, 0x908e,
+	0x0100, 0x1904, 0x7e2d, 0x7034, 0x9005, 0x1904, 0x7e2d, 0x2009,
+	0x0016, 0x080c, 0xa15d, 0x0804, 0x7e2d, 0x9186, 0x0022, 0x1904,
+	0x7e2d, 0x7030, 0x908e, 0x0300, 0x1580, 0x68d8, 0xd0a4, 0x0528,
+	0xc0b5, 0x68da, 0x7100, 0x918c, 0x00ff, 0x697a, 0x7004, 0x687e,
+	0x00f6, 0x2079, 0x0100, 0x79e6, 0x78ea, 0x0006, 0x9084, 0x00ff,
+	0x0016, 0x2008, 0x080c, 0x27b7, 0x7932, 0x7936, 0x001e, 0x000e,
+	0x00fe, 0x080c, 0x276e, 0x695a, 0x703c, 0x00e6, 0x2071, 0x0140,
+	0x7086, 0x2071, 0x1800, 0x70b2, 0x00ee, 0x7034, 0x9005, 0x1904,
+	0x7e2d, 0x2009, 0x0017, 0x0804, 0x7ddd, 0x908e, 0x0400, 0x1190,
+	0x7034, 0x9005, 0x1904, 0x7e2d, 0x080c, 0x7207, 0x0120, 0x2009,
+	0x001d, 0x0804, 0x7ddd, 0x68d8, 0xc0a5, 0x68da, 0x2009, 0x0030,
+	0x0804, 0x7ddd, 0x908e, 0x0500, 0x1140, 0x7034, 0x9005, 0x1904,
+	0x7e2d, 0x2009, 0x0018, 0x0804, 0x7ddd, 0x908e, 0x2010, 0x1120,
+	0x2009, 0x0019, 0x0804, 0x7ddd, 0x908e, 0x2110, 0x1120, 0x2009,
+	0x001a, 0x0804, 0x7ddd, 0x908e, 0x5200, 0x1140, 0x7034, 0x9005,
+	0x1904, 0x7e2d, 0x2009, 0x001b, 0x0804, 0x7ddd, 0x908e, 0x5000,
+	0x1140, 0x7034, 0x9005, 0x1904, 0x7e2d, 0x2009, 0x001c, 0x0804,
+	0x7ddd, 0x908e, 0x1300, 0x1120, 0x2009, 0x0034, 0x0804, 0x7ddd,
+	0x908e, 0x1200, 0x1140, 0x7034, 0x9005, 0x1904, 0x7e2d, 0x2009,
+	0x0024, 0x0804, 0x7ddd, 0x908c, 0xff00, 0x918e, 0x2400, 0x1170,
+	0x2009, 0x002d, 0x2001, 0x1810, 0x2004, 0xd09c, 0x0904, 0x7ddd,
+	0x080c, 0xcc07, 0x1904, 0x7e2d, 0x0804, 0x7ddb, 0x908c, 0xff00,
+	0x918e, 0x5300, 0x1120, 0x2009, 0x002a, 0x0804, 0x7ddd, 0x908e,
+	0x0f00, 0x1120, 0x2009, 0x0020, 0x0804, 0x7ddd, 0x908e, 0x6104,
+	0x1528, 0x2029, 0x0205, 0x2011, 0x026d, 0x8208, 0x2204, 0x9082,
+	0x0004, 0x8004, 0x8004, 0x20a8, 0x2011, 0x8015, 0x211c, 0x8108,
+	0x0046, 0x2124, 0x080c, 0x4b1f, 0x004e, 0x8108, 0x0f04, 0x7da9,
+	0x9186, 0x0280, 0x1d88, 0x2504, 0x8000, 0x202a, 0x2009, 0x0260,
+	0x0c58, 0x202b, 0x0000, 0x2009, 0x0023, 0x0478, 0x908e, 0x6000,
+	0x1118, 0x2009, 0x003f, 0x0448, 0x908e, 0x7800, 0x1118, 0x2009,
+	0x0045, 0x0418, 0x908e, 0x1000, 0x1118, 0x2009, 0x004e, 0x00e8,
+	0x908e, 0x6300, 0x1118, 0x2009, 0x004a, 0x00b8, 0x908c, 0xff00,
+	0x918e, 0x5600, 0x1118, 0x2009, 0x004f, 0x0078, 0x908c, 0xff00,
+	0x918e, 0x5700, 0x1118, 0x2009, 0x0050, 0x0038, 0x2009, 0x001d,
+	0x6838, 0xd0d4, 0x0110, 0x2009, 0x004c, 0x0016, 0x2011, 0x0263,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x276e, 0x1904, 0x7e30, 0x080c,
+	0x643f, 0x1904, 0x7e30, 0xbe12, 0xbd16, 0x001e, 0x0016, 0x080c,
+	0x7207, 0x01c0, 0x68d8, 0xd08c, 0x1148, 0x7000, 0x9084, 0x00ff,
+	0x1188, 0x7004, 0x9084, 0xff00, 0x1168, 0x0040, 0x6878, 0x9606,
+	0x1148, 0x687c, 0x9506, 0x9084, 0xff00, 0x1120, 0x9584, 0x00ff,
+	0xb8b2, 0x0080, 0xb8b0, 0x9005, 0x1168, 0x9186, 0x0046, 0x1150,
+	0x6878, 0x9606, 0x1138, 0x687c, 0x9506, 0x9084, 0xff00, 0x1110,
+	0x001e, 0x0098, 0x080c, 0xa08d, 0x01a8, 0x2b08, 0x6112, 0x6023,
+	0x0004, 0x7120, 0x610a, 0x001e, 0x9186, 0x004c, 0x1110, 0x6023,
+	0x000a, 0x0016, 0x001e, 0x080c, 0xa15d, 0x00ce, 0x00be, 0x0005,
+	0x001e, 0x0cd8, 0x2001, 0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011,
+	0x8049, 0x080c, 0x4b1f, 0x080c, 0xa130, 0x0d90, 0x2b08, 0x6112,
+	0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x0016, 0x9186, 0x0017,
+	0x0118, 0x9186, 0x0030, 0x1128, 0x6007, 0x0009, 0x6017, 0x2900,
+	0x0020, 0x6007, 0x0051, 0x6017, 0x0000, 0x602f, 0x0009, 0x6003,
+	0x0001, 0x080c, 0x86c1, 0x08a0, 0x080c, 0x8206, 0x1158, 0x080c,
+	0x32ae, 0x1140, 0x7010, 0x9084, 0xff00, 0x8007, 0x908e, 0x0008,
+	0x1108, 0x0009, 0x0005, 0x00b6, 0x00c6, 0x0046, 0x7000, 0x908c,
+	0xff00, 0x810f, 0x9186, 0x0033, 0x11e8, 0x080c, 0x80e1, 0x0904,
+	0x7ebc, 0x7124, 0x610a, 0x7030, 0x908e, 0x0200, 0x1140, 0x7034,
+	0x9005, 0x15d0, 0x2009, 0x0015, 0x080c, 0xa15d, 0x04a8, 0x908e,
+	0x0100, 0x1590, 0x7034, 0x9005, 0x1578, 0x2009, 0x0016, 0x080c,
+	0xa15d, 0x0450, 0x9186, 0x0032, 0x1538, 0x7030, 0x908e, 0x1400,
+	0x1518, 0x2009, 0x0038, 0x0016, 0x2011, 0x0263, 0x2204, 0x8211,
+	0x220c, 0x080c, 0x276e, 0x11b8, 0x080c, 0x643f, 0x11a0, 0xbe12,
+	0xbd16, 0x080c, 0xa08d, 0x0178, 0x2b08, 0x6112, 0x080c, 0xc2b3,
+	0x6023, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0xa15d, 0x080c,
+	0x8c10, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce, 0x00be, 0x0005,
+	0x00b6, 0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130, 0x9696, 0x00ff,
+	0x11b8, 0x9592, 0xfffc, 0x02a0, 0x9596, 0xfffd, 0x1120, 0x2009,
+	0x007f, 0x0804, 0x7f1e, 0x9596, 0xfffe, 0x1120, 0x2009, 0x007e,
+	0x0804, 0x7f1e, 0x9596, 0xfffc, 0x1118, 0x2009, 0x0080, 0x04f0,
+	0x2011, 0x0000, 0x2019, 0x1836, 0x231c, 0xd3ac, 0x0130, 0x9026,
+	0x20a9, 0x0800, 0x2071, 0x1000, 0x0030, 0x2021, 0x0081, 0x20a9,
+	0x077f, 0x2071, 0x1081, 0x2e1c, 0x93dd, 0x0000, 0x1140, 0x82ff,
+	0x11d0, 0x9496, 0x00ff, 0x01b8, 0x2410, 0xc2fd, 0x00a0, 0xbf10,
+	0x2600, 0x9706, 0xb814, 0x1120, 0x9546, 0x1110, 0x2408, 0x00b0,
+	0x9745, 0x1148, 0x94c6, 0x007e, 0x0130, 0x94c6, 0x007f, 0x0118,
+	0x94c6, 0x0080, 0x1d20, 0x8420, 0x8e70, 0x1f04, 0x7ef3, 0x82ff,
+	0x1118, 0x9085, 0x0001, 0x0018, 0xc2fc, 0x2208, 0x9006, 0x00de,
+	0x00ee, 0x004e, 0x00be, 0x0005, 0x2001, 0x1836, 0x200c, 0x9184,
+	0x0080, 0x0110, 0xd18c, 0x0138, 0x7000, 0x908c, 0xff00, 0x810f,
+	0x9184, 0x000f, 0x004a, 0x7817, 0x0140, 0x2001, 0x19c8, 0x2004,
+	0x9005, 0x090c, 0x8c10, 0x0005, 0x7f4c, 0x7f4c, 0x7f4c, 0x80f3,
+	0x7f4c, 0x7f55, 0x7f80, 0x800e, 0x7f4c, 0x7f4c, 0x7f4c, 0x7f4c,
+	0x7f4c, 0x7f4c, 0x7f4c, 0x7f4c, 0x7817, 0x0140, 0x2001, 0x19c8,
+	0x2004, 0x9005, 0x090c, 0x8c10, 0x0005, 0x00b6, 0x7110, 0xd1bc,
+	0x01e8, 0x7120, 0x2160, 0x9c8c, 0x0007, 0x11c0, 0x9c8a, 0x1cd0,
+	0x02a8, 0x6864, 0x9c02, 0x1290, 0x7008, 0x9084, 0x00ff, 0x6110,
+	0x2158, 0xb910, 0x9106, 0x1150, 0x700c, 0xb914, 0x9106, 0x1130,
+	0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0xa15d, 0x7817, 0x0140,
+	0x2001, 0x19c8, 0x2004, 0x9005, 0x090c, 0x8c10, 0x00be, 0x0005,
+	0x00b6, 0x00c6, 0x9484, 0x0fff, 0x0904, 0x7fe4, 0x7110, 0xd1bc,
+	0x1904, 0x7fe4, 0x7108, 0x700c, 0x2028, 0x918c, 0x00ff, 0x2130,
+	0x9094, 0xff00, 0x15b0, 0x81ff, 0x15a0, 0x9080, 0x32e9, 0x200d,
+	0x918c, 0xff00, 0x810f, 0x2001, 0x0080, 0x9106, 0x0904, 0x7fe4,
+	0x080c, 0x643f, 0x1904, 0x7fe4, 0xbe12, 0xbd16, 0xb800, 0xd0ec,
+	0x15d8, 0xba04, 0x9294, 0xff00, 0x9286, 0x0600, 0x11a0, 0x080c,
+	0xa08d, 0x05e8, 0x2b08, 0x7028, 0x6046, 0x702c, 0x604a, 0x6112,
+	0x6023, 0x0006, 0x7120, 0x610a, 0x7130, 0x6156, 0x2009, 0x0044,
+	0x080c, 0xce65, 0x0408, 0x080c, 0x67c3, 0x1138, 0xb807, 0x0606,
+	0x0c30, 0x190c, 0x7ec0, 0x11c0, 0x0898, 0x080c, 0xa08d, 0x2b08,
+	0x0198, 0x6112, 0x6023, 0x0004, 0x7120, 0x610a, 0x9286, 0x0400,
+	0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001,
+	0x080c, 0x86c1, 0x080c, 0x8c10, 0x7817, 0x0140, 0x2001, 0x19c8,
+	0x2004, 0x9005, 0x090c, 0x8c10, 0x00ce, 0x00be, 0x0005, 0x2001,
+	0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x4b1f,
+	0x080c, 0xa130, 0x0d48, 0x2b08, 0x6112, 0x6023, 0x0006, 0x7120,
+	0x610a, 0x7130, 0x6156, 0x6017, 0xf300, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x8679, 0x080c, 0x8c10, 0x08b0, 0x00b6, 0x7110,
+	0xd1bc, 0x01e8, 0x7020, 0x2060, 0x9c84, 0x0007, 0x11c0, 0x9c82,
+	0x1cd0, 0x02a8, 0x6864, 0x9c02, 0x1290, 0x7008, 0x9084, 0x00ff,
+	0x6110, 0x2158, 0xb910, 0x9106, 0x1150, 0x700c, 0xb914, 0x9106,
+	0x1130, 0x7124, 0x610a, 0x2009, 0x0045, 0x080c, 0xa15d, 0x7817,
+	0x0140, 0x2001, 0x19c8, 0x2004, 0x9005, 0x090c, 0x8c10, 0x00be,
+	0x0005, 0x6120, 0x9186, 0x0002, 0x0128, 0x9186, 0x0005, 0x0110,
+	0x9085, 0x0001, 0x0005, 0x080c, 0x8206, 0x1180, 0x080c, 0x32ae,
+	0x1168, 0x7010, 0x9084, 0xff00, 0x8007, 0x9086, 0x0000, 0x1130,
+	0x9184, 0x000f, 0x908a, 0x0006, 0x1208, 0x000b, 0x0005, 0x805d,
+	0x805e, 0x805d, 0x805d, 0x80c3, 0x80d2, 0x0005, 0x00b6, 0x700c,
+	0x7108, 0x080c, 0x276e, 0x1904, 0x80c1, 0x080c, 0x643f, 0x1904,
+	0x80c1, 0xbe12, 0xbd16, 0x7110, 0xd1bc, 0x0540, 0x702c, 0xd084,
+	0x1120, 0xb800, 0xd0bc, 0x1904, 0x80c1, 0x080c, 0x67c3, 0x0148,
+	0x9086, 0x0004, 0x0130, 0x080c, 0x67cb, 0x0118, 0x9086, 0x0004,
+	0x1588, 0x00c6, 0x080c, 0x80e1, 0x00ce, 0x05d8, 0x080c, 0xa08d,
+	0x2b08, 0x05b8, 0x6112, 0x080c, 0xc2b3, 0x6023, 0x0002, 0x7120,
+	0x610a, 0x2009, 0x0088, 0x080c, 0xa15d, 0x0458, 0x080c, 0x67c3,
+	0x0148, 0x9086, 0x0004, 0x0130, 0x080c, 0x67cb, 0x0118, 0x9086,
+	0x0004, 0x1180, 0x080c, 0xa08d, 0x2b08, 0x01d8, 0x6112, 0x080c,
+	0xc2b3, 0x6023, 0x0005, 0x7120, 0x610a, 0x2009, 0x0088, 0x080c,
+	0xa15d, 0x0078, 0x080c, 0xa08d, 0x2b08, 0x0158, 0x6112, 0x080c,
+	0xc2b3, 0x6023, 0x0004, 0x7120, 0x610a, 0x2009, 0x0001, 0x080c,
+	0xa15d, 0x00be, 0x0005, 0x7110, 0xd1bc, 0x0158, 0x00d1, 0x0148,
+	0x080c, 0x8039, 0x1130, 0x7124, 0x610a, 0x2009, 0x0089, 0x080c,
+	0xa15d, 0x0005, 0x7110, 0xd1bc, 0x0158, 0x0059, 0x0148, 0x080c,
+	0x8039, 0x1130, 0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0xa15d,
+	0x0005, 0x7020, 0x2060, 0x9c84, 0x0007, 0x1158, 0x9c82, 0x1cd0,
+	0x0240, 0x2001, 0x1819, 0x2004, 0x9c02, 0x1218, 0x9085, 0x0001,
+	0x0005, 0x9006, 0x0ce8, 0x00b6, 0x7110, 0xd1bc, 0x11d8, 0x7024,
+	0x2060, 0x9c84, 0x0007, 0x11b0, 0x9c82, 0x1cd0, 0x0298, 0x6864,
+	0x9c02, 0x1280, 0x7008, 0x9084, 0x00ff, 0x6110, 0x2158, 0xb910,
+	0x9106, 0x1140, 0x700c, 0xb914, 0x9106, 0x1120, 0x2009, 0x0051,
+	0x080c, 0xa15d, 0x7817, 0x0140, 0x2001, 0x19c8, 0x2004, 0x9005,
+	0x090c, 0x8c10, 0x00be, 0x0005, 0x2031, 0x0105, 0x0069, 0x0005,
+	0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029, 0x0005,
+	0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x0096, 0x00f6, 0x7000,
+	0x9084, 0xf000, 0x9086, 0xc000, 0x05d0, 0x080c, 0xa08d, 0x05b8,
+	0x0066, 0x00c6, 0x0046, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c,
+	0x080c, 0x276e, 0x15a0, 0x080c, 0x643f, 0x1588, 0xbe12, 0xbd16,
+	0x2b00, 0x004e, 0x00ce, 0x6012, 0x080c, 0xc2b3, 0x080c, 0x1031,
+	0x0510, 0x2900, 0x605a, 0x9006, 0xa802, 0xa866, 0xac6a, 0xa85c,
+	0x90f8, 0x001b, 0x20a9, 0x000e, 0xa860, 0x20e8, 0x20e1, 0x0000,
+	0x2fa0, 0x2e98, 0x4003, 0x006e, 0x6616, 0x6007, 0x003e, 0x6023,
+	0x0001, 0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x00fe,
+	0x009e, 0x00ce, 0x0005, 0x080c, 0xa0e3, 0x006e, 0x0cc0, 0x004e,
+	0x00ce, 0x0cc8, 0x00c6, 0x7000, 0x908c, 0xff00, 0x9184, 0xf000,
+	0x810f, 0x9086, 0x2000, 0x1904, 0x81d1, 0x9186, 0x0022, 0x15f0,
+	0x2001, 0x0111, 0x2004, 0x9005, 0x1904, 0x81d3, 0x7030, 0x908e,
+	0x0400, 0x0904, 0x81d3, 0x908e, 0x6000, 0x05e8, 0x908e, 0x5400,
+	0x05d0, 0x908e, 0x0300, 0x11d8, 0x2009, 0x1836, 0x210c, 0xd18c,
+	0x1590, 0xd1a4, 0x1580, 0x080c, 0x6781, 0x0588, 0x68ac, 0x9084,
+	0x00ff, 0x7100, 0x918c, 0x00ff, 0x9106, 0x1518, 0x687c, 0x69ac,
+	0x918c, 0xff00, 0x9105, 0x7104, 0x9106, 0x11d8, 0x00e0, 0x2009,
+	0x0103, 0x210c, 0xd1b4, 0x11a8, 0x908e, 0x5200, 0x09e8, 0x908e,
+	0x0500, 0x09d0, 0x908e, 0x5000, 0x09b8, 0x0058, 0x9186, 0x0023,
+	0x1140, 0x080c, 0x80e1, 0x0128, 0x6004, 0x9086, 0x0002, 0x0118,
+	0x0000, 0x9006, 0x0010, 0x9085, 0x0001, 0x00ce, 0x0005, 0x7030,
+	0x908e, 0x0300, 0x0118, 0x908e, 0x5200, 0x1d98, 0x2001, 0x1836,
+	0x2004, 0x9084, 0x0009, 0x9086, 0x0008, 0x0d68, 0x0c50, 0x00f6,
+	0x2079, 0x0200, 0x7800, 0xc0e5, 0xc0cc, 0x7802, 0x00fe, 0x0005,
+	0x00f6, 0x2079, 0x1800, 0x7834, 0xd084, 0x1130, 0x2079, 0x0200,
+	0x7800, 0x9085, 0x1200, 0x7802, 0x00fe, 0x0005, 0x00e6, 0x2071,
+	0x1800, 0x7034, 0xc084, 0x7036, 0x00ee, 0x0005, 0x0016, 0x2001,
+	0x1836, 0x200c, 0x9184, 0x0080, 0x0118, 0xd18c, 0x0118, 0x9006,
+	0x001e, 0x0005, 0x9085, 0x0001, 0x0cd8, 0x2071, 0x19d2, 0x7003,
+	0x0003, 0x700f, 0x0361, 0x9006, 0x701a, 0x7072, 0x7012, 0x7017,
+	0x1cd0, 0x7007, 0x0000, 0x7026, 0x702b, 0x966c, 0x7032, 0x7037,
+	0x96d4, 0x703f, 0xffff, 0x7042, 0x7047, 0x546d, 0x704a, 0x705b,
+	0x8375, 0x080c, 0x104a, 0x090c, 0x0dfa, 0x2900, 0x703a, 0xa867,
+	0x0003, 0xa86f, 0x0100, 0xa8ab, 0xdcb0, 0x0005, 0x2071, 0x19d2,
+	0x1d04, 0x82c9, 0x2091, 0x6000, 0x700c, 0x8001, 0x700e, 0x1510,
+	0x2001, 0x187d, 0x2004, 0xd0c4, 0x0158, 0x3a00, 0xd08c, 0x1140,
+	0x20d1, 0x0000, 0x20d1, 0x0001, 0x20d1, 0x0000, 0x080c, 0x0dfa,
+	0x700f, 0x0361, 0x7007, 0x0001, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x83ba, 0x7040, 0x900d, 0x0148, 0x8109, 0x7142, 0x1130, 0x7044,
+	0x080f, 0x0018, 0x0126, 0x2091, 0x8000, 0x7024, 0x900d, 0x0188,
+	0x7020, 0x8001, 0x7022, 0x1168, 0x7023, 0x0009, 0x8109, 0x7126,
+	0x9186, 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff, 0x1110, 0x7028,
+	0x080f, 0x7030, 0x900d, 0x0180, 0x702c, 0x8001, 0x702e, 0x1160,
+	0x702f, 0x0009, 0x8109, 0x7132, 0x0128, 0x9184, 0x007f, 0x090c,
+	0x9802, 0x0010, 0x7034, 0x080f, 0x703c, 0x9005, 0x0118, 0x0310,
+	0x8001, 0x703e, 0x704c, 0x900d, 0x0168, 0x7048, 0x8001, 0x704a,
+	0x1148, 0x704b, 0x0009, 0x8109, 0x714e, 0x1120, 0x7150, 0x714e,
+	0x7058, 0x080f, 0x7018, 0x900d, 0x01d8, 0x0016, 0x7070, 0x900d,
+	0x0158, 0x706c, 0x8001, 0x706e, 0x1138, 0x706f, 0x0009, 0x8109,
+	0x7172, 0x1110, 0x7074, 0x080f, 0x001e, 0x7008, 0x8001, 0x700a,
+	0x1138, 0x700b, 0x0009, 0x8109, 0x711a, 0x1110, 0x701c, 0x080f,
+	0x012e, 0x7004, 0x0002, 0x82f1, 0x82f2, 0x830e, 0x00e6, 0x2071,
+	0x19d2, 0x7018, 0x9005, 0x1120, 0x711a, 0x721e, 0x700b, 0x0009,
+	0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071, 0x19d2, 0x701c, 0x9206,
+	0x1120, 0x701a, 0x701e, 0x7072, 0x7076, 0x000e, 0x00ee, 0x0005,
+	0x00e6, 0x2071, 0x19d2, 0xb888, 0x9102, 0x0208, 0xb98a, 0x00ee,
+	0x0005, 0x0005, 0x00b6, 0x7110, 0x080c, 0x649f, 0x1168, 0xb888,
+	0x8001, 0x0250, 0xb88a, 0x1140, 0x0126, 0x2091, 0x8000, 0x0016,
+	0x080c, 0x8c10, 0x001e, 0x012e, 0x8108, 0x9182, 0x0800, 0x0218,
+	0x900e, 0x7007, 0x0002, 0x7112, 0x00be, 0x0005, 0x7014, 0x2060,
+	0x0126, 0x2091, 0x8000, 0x6040, 0x9005, 0x0128, 0x8001, 0x6042,
+	0x1110, 0x080c, 0xc144, 0x6018, 0x9005, 0x0528, 0x8001, 0x601a,
+	0x1510, 0x6120, 0x9186, 0x0003, 0x0118, 0x9186, 0x0006, 0x11c8,
+	0x080c, 0xbe37, 0x01b0, 0x6014, 0x2048, 0xa884, 0x908a, 0x199a,
+	0x0280, 0x9082, 0x1999, 0xa886, 0x908a, 0x199a, 0x0210, 0x2001,
+	0x1999, 0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0xa87c, 0xd0e4,
+	0x0110, 0x080c, 0xbb23, 0x012e, 0x9c88, 0x0018, 0x7116, 0x2001,
+	0x1819, 0x2004, 0x9102, 0x0220, 0x7017, 0x1cd0, 0x7007, 0x0000,
+	0x0005, 0x00e6, 0x2071, 0x19d2, 0x7027, 0x07d0, 0x7023, 0x0009,
+	0x00ee, 0x0005, 0x2001, 0x19db, 0x2003, 0x0000, 0x0005, 0x00e6,
+	0x2071, 0x19d2, 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011,
+	0x19de, 0x2013, 0x0000, 0x0005, 0x00e6, 0x2071, 0x19d2, 0x711a,
+	0x721e, 0x700b, 0x0009, 0x00ee, 0x0005, 0x0086, 0x0026, 0x7054,
+	0x8000, 0x7056, 0x2001, 0x19e0, 0x2044, 0xa06c, 0x9086, 0x0000,
+	0x0150, 0x7068, 0xa09a, 0x7064, 0xa096, 0x7060, 0xa092, 0x705c,
+	0xa08e, 0x080c, 0x112e, 0x002e, 0x008e, 0x0005, 0x0006, 0x0016,
+	0x0096, 0x00a6, 0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x0156,
+	0x080c, 0x823e, 0x015e, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be,
+	0x00ae, 0x009e, 0x001e, 0x000e, 0x0005, 0x00e6, 0x2071, 0x19d2,
+	0x7172, 0x7276, 0x706f, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006,
+	0x2071, 0x19d2, 0x7074, 0x9206, 0x1110, 0x7072, 0x7076, 0x000e,
+	0x00ee, 0x0005, 0x2069, 0x1800, 0x69e4, 0xd1e4, 0x1518, 0x0026,
+	0xd1ec, 0x0140, 0x6a50, 0x6870, 0x9202, 0x0288, 0x8117, 0x9294,
+	0x00c0, 0x0088, 0x9184, 0x0007, 0x01a0, 0x8109, 0x9184, 0x0007,
+	0x0110, 0x69e6, 0x0070, 0x8107, 0x9084, 0x0007, 0x910d, 0x8107,
+	0x9106, 0x9094, 0x00c0, 0x9184, 0xff3f, 0x9205, 0x68e6, 0x080c,
+	0x0f11, 0x002e, 0x0005, 0x00c6, 0x2061, 0x1a48, 0x00ce, 0x0005,
+	0x9184, 0x000f, 0x8003, 0x8003, 0x8003, 0x9080, 0x1a48, 0x2060,
+	0x0005, 0xa884, 0x908a, 0x199a, 0x1638, 0x9005, 0x1150, 0x00c6,
+	0x2061, 0x1a48, 0x6014, 0x00ce, 0x9005, 0x1130, 0x2001, 0x001e,
+	0x0018, 0x908e, 0xffff, 0x01b0, 0x8003, 0x800b, 0x810b, 0x9108,
+	0x611a, 0xa87c, 0x908c, 0x00c0, 0x918e, 0x00c0, 0x0904, 0x847b,
+	0xd0b4, 0x1168, 0xd0bc, 0x1904, 0x8454, 0x2009, 0x0006, 0x080c,
+	0x84a8, 0x0005, 0x900e, 0x0c60, 0x2001, 0x1999, 0x08b0, 0xd0fc,
+	0x0160, 0x908c, 0x0003, 0x0120, 0x918e, 0x0003, 0x1904, 0x84a2,
+	0x908c, 0x2020, 0x918e, 0x2020, 0x01a8, 0x6024, 0xd0d4, 0x11e8,
+	0x2009, 0x187d, 0x2104, 0xd084, 0x1138, 0x87ff, 0x1120, 0x2009,
+	0x0043, 0x0804, 0xa15d, 0x0005, 0x87ff, 0x1de8, 0x2009, 0x0042,
+	0x0804, 0xa15d, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac,
+	0x0d20, 0x6024, 0xc0cd, 0x6026, 0x0c00, 0xc0d4, 0x6026, 0xa890,
+	0x602e, 0xa88c, 0x6032, 0x08e0, 0xd0fc, 0x0160, 0x908c, 0x0003,
+	0x0120, 0x918e, 0x0003, 0x1904, 0x84a2, 0x908c, 0x2020, 0x918e,
+	0x2020, 0x0170, 0x0076, 0x00f6, 0x2c78, 0x080c, 0x16db, 0x00fe,
+	0x007e, 0x87ff, 0x1120, 0x2009, 0x0042, 0x080c, 0xa15d, 0x0005,
+	0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d58, 0x6124,
+	0xc1cd, 0x6126, 0x0c38, 0xd0fc, 0x0188, 0x908c, 0x2020, 0x918e,
+	0x2020, 0x01a8, 0x9084, 0x0003, 0x908e, 0x0002, 0x0148, 0x87ff,
+	0x1120, 0x2009, 0x0041, 0x080c, 0xa15d, 0x0005, 0x00b9, 0x0ce8,
+	0x87ff, 0x1dd8, 0x2009, 0x0043, 0x080c, 0xa15d, 0x0cb0, 0x6110,
+	0x00b6, 0x2158, 0xb900, 0x00be, 0xd1ac, 0x0d20, 0x6124, 0xc1cd,
+	0x6126, 0x0c00, 0x2009, 0x0004, 0x0019, 0x0005, 0x2009, 0x0001,
+	0x0096, 0x080c, 0xbe37, 0x0518, 0x6014, 0x2048, 0xa982, 0xa800,
+	0x6016, 0x9186, 0x0001, 0x1188, 0xa97c, 0x918c, 0x8100, 0x918e,
+	0x8100, 0x1158, 0x00c6, 0x2061, 0x1a48, 0x6200, 0xd28c, 0x1120,
+	0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c, 0x6923, 0x6014,
+	0x904d, 0x0076, 0x2039, 0x0000, 0x190c, 0x83f1, 0x007e, 0x009e,
+	0x0005, 0x0156, 0x00c6, 0x2061, 0x1a48, 0x6000, 0x81ff, 0x0110,
+	0x9205, 0x0008, 0x9204, 0x6002, 0x00ce, 0x015e, 0x0005, 0x6800,
+	0xd08c, 0x1138, 0x6808, 0x9005, 0x0120, 0x8001, 0x680a, 0x9085,
+	0x0001, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x0046, 0x20a9,
+	0x0010, 0x9006, 0x8004, 0x8086, 0x818e, 0x1208, 0x9200, 0x1f04,
+	0x84f3, 0x8086, 0x818e, 0x004e, 0x003e, 0x012e, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x0076, 0x0156, 0x20a9, 0x0010, 0x9005, 0x01c8,
+	0x911a, 0x12b8, 0x8213, 0x818d, 0x0228, 0x911a, 0x1220, 0x1f04,
+	0x850a, 0x0028, 0x911a, 0x2308, 0x8210, 0x1f04, 0x850a, 0x0006,
+	0x3200, 0x9084, 0xefff, 0x2080, 0x000e, 0x015e, 0x007e, 0x012e,
+	0x0005, 0x0006, 0x3200, 0x9085, 0x1000, 0x0ca8, 0x0126, 0x2091,
+	0x2800, 0x2079, 0x19bf, 0x012e, 0x00d6, 0x2069, 0x19bf, 0x6803,
+	0x0005, 0x0156, 0x0146, 0x01d6, 0x20e9, 0x0000, 0x2069, 0x0200,
+	0x080c, 0x9eeb, 0x0401, 0x080c, 0x9ed6, 0x00e9, 0x080c, 0x9ed9,
+	0x00d1, 0x080c, 0x9edc, 0x00b9, 0x080c, 0x9edf, 0x00a1, 0x080c,
+	0x9ee2, 0x0089, 0x080c, 0x9ee5, 0x0071, 0x080c, 0x9ee8, 0x0059,
+	0x01de, 0x014e, 0x015e, 0x2069, 0x0004, 0x2d04, 0x9085, 0x8001,
+	0x206a, 0x00de, 0x0005, 0x20a9, 0x0020, 0x20a1, 0x0240, 0x2001,
+	0x0000, 0x4004, 0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, 0x9084,
+	0x0007, 0x0002, 0x8574, 0x8598, 0x85d9, 0x857a, 0x8598, 0x8574,
+	0x8572, 0x8572, 0x080c, 0x0dfa, 0x080c, 0x835a, 0x080c, 0x8c10,
+	0x00ce, 0x0005, 0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, 0x2011,
+	0x5d94, 0x080c, 0x82da, 0x7828, 0x9092, 0x00c8, 0x1228, 0x8000,
+	0x782a, 0x080c, 0x5dd4, 0x0c88, 0x62c0, 0x080c, 0x9eef, 0x080c,
+	0x5d94, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0c28,
+	0x080c, 0x835a, 0x6220, 0xd2a4, 0x0170, 0xd2cc, 0x0160, 0x782b,
+	0x0000, 0x7824, 0x9065, 0x090c, 0x0dfa, 0x2009, 0x0013, 0x080c,
+	0xa15d, 0x00ce, 0x0005, 0x00c6, 0x7824, 0x9065, 0x090c, 0x0dfa,
+	0x7828, 0x9092, 0xc350, 0x12c0, 0x8000, 0x782a, 0x00ce, 0x080c,
+	0x2afe, 0x0278, 0x00c6, 0x7924, 0x2160, 0x6010, 0x906d, 0x090c,
+	0x0dfa, 0x7807, 0x0000, 0x7827, 0x0000, 0x00ce, 0x080c, 0x8c10,
+	0x0c00, 0x080c, 0x9632, 0x08e8, 0x2011, 0x0130, 0x2214, 0x080c,
+	0x9eef, 0x080c, 0xdc28, 0x2009, 0x0014, 0x080c, 0xa15d, 0x00ce,
+	0x0880, 0x2001, 0x19db, 0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160,
+	0x782b, 0x0000, 0x7824, 0x9065, 0x090c, 0x0dfa, 0x2009, 0x0013,
+	0x080c, 0xa1af, 0x00ce, 0x0005, 0x00b6, 0x00c6, 0x00d6, 0x7824,
+	0x9005, 0x090c, 0x0dfa, 0x7828, 0x9092, 0xc350, 0x1648, 0x8000,
+	0x782a, 0x00de, 0x00ce, 0x00be, 0x080c, 0x2afe, 0x02f0, 0x00b6,
+	0x00c6, 0x00d6, 0x781c, 0x905d, 0x090c, 0x0dfa, 0xb800, 0xc0dc,
+	0xb802, 0x7924, 0x2160, 0x080c, 0xa0e3, 0xb93c, 0x81ff, 0x090c,
+	0x0dfa, 0x8109, 0xb93e, 0x7807, 0x0000, 0x7827, 0x0000, 0x00de,
+	0x00ce, 0x00be, 0x080c, 0x8c10, 0x0868, 0x080c, 0x9632, 0x0850,
+	0x2011, 0x0130, 0x2214, 0x080c, 0x9eef, 0x080c, 0xdc28, 0x7824,
+	0x9065, 0x2009, 0x0014, 0x080c, 0xa15d, 0x00de, 0x00ce, 0x00be,
+	0x0804, 0x85ea, 0x00c6, 0x2001, 0x009b, 0x2004, 0xd0fc, 0x190c,
+	0x1dec, 0x6024, 0x6027, 0x0002, 0xd0f4, 0x1580, 0x62c8, 0x60c4,
+	0x9205, 0x1170, 0x783c, 0x9065, 0x0130, 0x2009, 0x0049, 0x080c,
+	0xa15d, 0x00ce, 0x0005, 0x2011, 0x19de, 0x2013, 0x0000, 0x0cc8,
+	0x793c, 0x81ff, 0x0dc0, 0x7944, 0x9192, 0x7530, 0x12f0, 0x8108,
+	0x7946, 0x793c, 0x9188, 0x0008, 0x210c, 0x918e, 0x0006, 0x1138,
+	0x6014, 0x9084, 0x1984, 0x9085, 0x0012, 0x6016, 0x0c10, 0x6014,
+	0x9084, 0x1984, 0x9085, 0x0016, 0x6016, 0x08d8, 0x793c, 0x2160,
+	0x2009, 0x004a, 0x080c, 0xa15d, 0x08a0, 0x7848, 0xc085, 0x784a,
+	0x0880, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19bf, 0x6020, 0x8000, 0x6022, 0x6010,
+	0x9005, 0x0148, 0x9080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069,
+	0x19bf, 0xb800, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0x9086,
+	0x0001, 0x1110, 0x2b00, 0x681e, 0x00de, 0x0804, 0x8c10, 0x00de,
+	0x0005, 0xc0d5, 0xb802, 0x6818, 0x9005, 0x0168, 0xb856, 0xb85b,
+	0x0000, 0x0086, 0x0006, 0x2b00, 0x681a, 0x008e, 0xa05a, 0x008e,
+	0x2069, 0x19bf, 0x0c08, 0xb856, 0xb85a, 0x2b00, 0x681a, 0x681e,
+	0x08d8, 0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19bf, 0x6020, 0x8000, 0x6022, 0x6008,
+	0x9005, 0x0148, 0x9080, 0x0003, 0x2102, 0x610a, 0x012e, 0x00ce,
+	0x001e, 0x000e, 0x0005, 0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f,
+	0x0000, 0x2c08, 0x2061, 0x19bf, 0x6034, 0x9005, 0x0130, 0x9080,
+	0x0003, 0x2102, 0x6136, 0x00ce, 0x0005, 0x613a, 0x6136, 0x00ce,
+	0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x00b6, 0x0096, 0x0076,
+	0x0066, 0x0056, 0x0036, 0x0026, 0x0016, 0x0006, 0x0126, 0x902e,
+	0x2071, 0x19bf, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff,
+	0x0904, 0x876d, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1904, 0x8768,
+	0x87ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x8768, 0x703c, 0x9c06,
+	0x1178, 0x0036, 0x2019, 0x0001, 0x080c, 0x999d, 0x7033, 0x0000,
+	0x9006, 0x703e, 0x7042, 0x7046, 0x704a, 0x003e, 0x2029, 0x0001,
+	0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034, 0x9c36, 0x1140,
+	0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0x080c, 0xbe37, 0x01f0, 0x6014, 0x2048, 0x6020,
+	0x9086, 0x0003, 0x15b8, 0x6004, 0x9086, 0x0040, 0x090c, 0x9b78,
+	0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x0016, 0x0036, 0x0076,
+	0x080c, 0xc12d, 0x080c, 0xdb2e, 0x080c, 0x6ae9, 0x007e, 0x003e,
+	0x001e, 0x080c, 0xc022, 0x080c, 0xa113, 0x00ce, 0x0804, 0x8707,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0x8707, 0x85ff, 0x0120, 0x0036,
+	0x080c, 0x8ced, 0x003e, 0x012e, 0x000e, 0x001e, 0x002e, 0x003e,
+	0x005e, 0x006e, 0x007e, 0x009e, 0x00be, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x6020, 0x9086, 0x0006, 0x1158, 0x0016, 0x0036,
+	0x0076, 0x080c, 0xdb2e, 0x080c, 0xd830, 0x007e, 0x003e, 0x001e,
+	0x0890, 0x6020, 0x9086, 0x000a, 0x0904, 0x8752, 0x0804, 0x874b,
+	0x0006, 0x0066, 0x0096, 0x00c6, 0x00d6, 0x00f6, 0x9036, 0x0126,
+	0x2091, 0x8000, 0x2079, 0x19bf, 0x7838, 0x9065, 0x0904, 0x87ed,
+	0x600c, 0x0006, 0x600f, 0x0000, 0x783c, 0x9c06, 0x1168, 0x0036,
+	0x2019, 0x0001, 0x080c, 0x999d, 0x7833, 0x0000, 0x901e, 0x7b3e,
+	0x7b42, 0x7b46, 0x7b4a, 0x003e, 0x080c, 0xbe37, 0x0548, 0x6014,
+	0x2048, 0x6020, 0x9086, 0x0003, 0x1590, 0x3e08, 0x918e, 0x0002,
+	0x1188, 0x6010, 0x9005, 0x0170, 0x00b6, 0x2058, 0xb800, 0x00be,
+	0xd0bc, 0x0140, 0x6040, 0x9005, 0x11a8, 0x2001, 0x1960, 0x2004,
+	0x6042, 0x0080, 0x6004, 0x9086, 0x0040, 0x090c, 0x9b78, 0xa867,
+	0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6adc, 0x080c, 0xc022,
+	0x080c, 0xa113, 0x000e, 0x0804, 0x87a5, 0x7e3a, 0x7e36, 0x012e,
+	0x00fe, 0x00de, 0x00ce, 0x009e, 0x006e, 0x000e, 0x0005, 0x6020,
+	0x9086, 0x0006, 0x1118, 0x080c, 0xd830, 0x0c50, 0x6020, 0x9086,
+	0x000a, 0x09f8, 0x08b8, 0x0016, 0x0026, 0x0086, 0x9046, 0x0099,
+	0x080c, 0x88ee, 0x008e, 0x002e, 0x001e, 0x0005, 0x00f6, 0x0126,
+	0x2079, 0x19bf, 0x2091, 0x8000, 0x080c, 0x8985, 0x080c, 0x8a15,
+	0x012e, 0x00fe, 0x0005, 0x00b6, 0x0096, 0x00f6, 0x00e6, 0x00d6,
+	0x00c6, 0x0066, 0x0016, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071,
+	0x19bf, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0904, 0x88b3, 0x6010,
+	0x2058, 0xb8a0, 0x9206, 0x1904, 0x88ae, 0x88ff, 0x0120, 0x6054,
+	0x9106, 0x1904, 0x88ae, 0x7024, 0x9c06, 0x1568, 0x2069, 0x0100,
+	0x6820, 0xd0a4, 0x0110, 0xd0cc, 0x1508, 0x080c, 0x835a, 0x080c,
+	0x9656, 0x68c3, 0x0000, 0x080c, 0x9b78, 0x7027, 0x0000, 0x0036,
+	0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100,
+	0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0028, 0x6003, 0x0009,
+	0x630a, 0x0804, 0x88ae, 0x7014, 0x9c36, 0x1110, 0x660c, 0x7616,
+	0x7010, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012,
+	0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6014, 0x2048, 0x080c,
+	0xbe37, 0x01e8, 0x6020, 0x9086, 0x0003, 0x1580, 0x080c, 0xc03f,
+	0x1118, 0x080c, 0xaa81, 0x0098, 0xa867, 0x0103, 0xab7a, 0xa877,
+	0x0000, 0x0016, 0x0036, 0x0086, 0x080c, 0xc12d, 0x080c, 0xdb2e,
+	0x080c, 0x6ae9, 0x008e, 0x003e, 0x001e, 0x080c, 0xc022, 0x080c,
+	0xa113, 0x080c, 0x9a4e, 0x00ce, 0x0804, 0x882c, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0x882c, 0x012e, 0x000e, 0x001e, 0x006e, 0x00ce,
+	0x00de, 0x00ee, 0x00fe, 0x009e, 0x00be, 0x0005, 0x6020, 0x9086,
+	0x0006, 0x1158, 0x0016, 0x0036, 0x0086, 0x080c, 0xdb2e, 0x080c,
+	0xd830, 0x008e, 0x003e, 0x001e, 0x08d0, 0x080c, 0xaa81, 0x6020,
+	0x9086, 0x0002, 0x1160, 0x6004, 0x0006, 0x9086, 0x0085, 0x000e,
+	0x0904, 0x8894, 0x9086, 0x008b, 0x0904, 0x8894, 0x0840, 0x6020,
+	0x9086, 0x0005, 0x1920, 0x6004, 0x0006, 0x9086, 0x0085, 0x000e,
+	0x09c8, 0x9086, 0x008b, 0x09b0, 0x0804, 0x88a7, 0x00b6, 0x00a6,
+	0x0096, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, 0x9280, 0x1000,
+	0x2004, 0x905d, 0x0904, 0x897e, 0x00f6, 0x00e6, 0x00d6, 0x0066,
+	0x2071, 0x19bf, 0xbe54, 0x7018, 0x9b06, 0x1108, 0x761a, 0x701c,
+	0x9b06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, 0x0008, 0x761e,
+	0xb858, 0x904d, 0x0108, 0xae56, 0x96d5, 0x0000, 0x0110, 0x2900,
+	0xb05a, 0xb857, 0x0000, 0xb85b, 0x0000, 0xb800, 0xc0d4, 0xc0dc,
+	0xb802, 0x080c, 0x63d2, 0x0904, 0x897a, 0x7624, 0x86ff, 0x0904,
+	0x8969, 0x9680, 0x0005, 0x2004, 0x9906, 0x15d8, 0x00d6, 0x2069,
+	0x0100, 0x68c0, 0x9005, 0x0560, 0x080c, 0x835a, 0x080c, 0x9656,
+	0x68c3, 0x0000, 0x080c, 0x9b78, 0x7027, 0x0000, 0x0036, 0x2069,
+	0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2c88, 0x9006, 0x080c, 0x2c88, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0110, 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0xb83c, 0x9005,
+	0x0110, 0x8001, 0xb83e, 0x2660, 0x080c, 0xa113, 0x00ce, 0x0048,
+	0x00de, 0x00c6, 0x2660, 0x6003, 0x0009, 0x630a, 0x00ce, 0x0804,
+	0x8921, 0x89ff, 0x0158, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000,
+	0x080c, 0xc12d, 0x080c, 0xdb2e, 0x080c, 0x6ae9, 0x080c, 0x9a4e,
+	0x0804, 0x8921, 0x006e, 0x00de, 0x00ee, 0x00fe, 0x012e, 0x000e,
+	0x00ce, 0x009e, 0x00ae, 0x00be, 0x0005, 0x0096, 0x0006, 0x0066,
+	0x00c6, 0x00d6, 0x9036, 0x7814, 0x9065, 0x0904, 0x89e8, 0x600c,
+	0x0006, 0x600f, 0x0000, 0x7824, 0x9c06, 0x1580, 0x2069, 0x0100,
+	0x6820, 0xd0a4, 0x0110, 0xd0cc, 0x1508, 0x080c, 0x835a, 0x080c,
+	0x9656, 0x68c3, 0x0000, 0x080c, 0x9b78, 0x7827, 0x0000, 0x0036,
+	0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100,
+	0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0040, 0x080c, 0x6779,
+	0x1520, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00f8, 0x6014, 0x2048,
+	0x080c, 0xbe35, 0x01b0, 0x6020, 0x9086, 0x0003, 0x1508, 0x080c,
+	0xc03f, 0x1118, 0x080c, 0xaa81, 0x0060, 0x080c, 0x6779, 0x1168,
+	0xa867, 0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6ae9, 0x080c,
+	0xc022, 0x080c, 0xa113, 0x080c, 0x9a4e, 0x000e, 0x0804, 0x898c,
+	0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x009e, 0x0005,
+	0x6020, 0x9086, 0x0006, 0x1118, 0x080c, 0xd830, 0x0c50, 0x080c,
+	0xaa81, 0x6020, 0x9086, 0x0002, 0x1150, 0x6004, 0x0006, 0x9086,
+	0x0085, 0x000e, 0x0990, 0x9086, 0x008b, 0x0978, 0x08d0, 0x6020,
+	0x9086, 0x0005, 0x19b0, 0x6004, 0x0006, 0x9086, 0x0085, 0x000e,
+	0x0d18, 0x9086, 0x008b, 0x0d00, 0x0860, 0x0006, 0x0066, 0x0096,
+	0x00b6, 0x00c6, 0x00d6, 0x7818, 0x905d, 0x0904, 0x8a95, 0xb854,
+	0x0006, 0x9006, 0xb856, 0xb85a, 0xb800, 0xc0d4, 0xc0dc, 0xb802,
+	0x080c, 0x63d2, 0x0904, 0x8a92, 0x7e24, 0x86ff, 0x0904, 0x8a85,
+	0x9680, 0x0005, 0x2004, 0x9906, 0x1904, 0x8a85, 0x00d6, 0x2069,
+	0x0100, 0x68c0, 0x9005, 0x0904, 0x8a7c, 0x080c, 0x835a, 0x080c,
+	0x9656, 0x68c3, 0x0000, 0x080c, 0x9b78, 0x7827, 0x0000, 0x0036,
+	0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100,
+	0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x00de, 0x00c6, 0x3e08,
+	0x918e, 0x0002, 0x1168, 0xb800, 0xd0bc, 0x0150, 0x9680, 0x0010,
+	0x200c, 0x81ff, 0x1518, 0x2009, 0x1960, 0x210c, 0x2102, 0x00f0,
+	0xb83c, 0x9005, 0x0110, 0x8001, 0xb83e, 0x2660, 0x600f, 0x0000,
+	0x080c, 0xa113, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003,
+	0x0009, 0x630a, 0x00ce, 0x0804, 0x8a28, 0x89ff, 0x0138, 0xa867,
+	0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6ae9, 0x080c, 0x9a4e,
+	0x0804, 0x8a28, 0x000e, 0x0804, 0x8a1c, 0x781e, 0x781a, 0x00de,
+	0x00ce, 0x00be, 0x009e, 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6,
+	0x0096, 0x0066, 0xb800, 0xd0dc, 0x01a0, 0xb84c, 0x904d, 0x0188,
+	0xa878, 0x9606, 0x1170, 0x2071, 0x19bf, 0x7024, 0x9035, 0x0148,
+	0x9080, 0x0005, 0x2004, 0x9906, 0x1120, 0xb800, 0xc0dc, 0xb802,
+	0x0029, 0x006e, 0x009e, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x2079,
+	0x0100, 0x78c0, 0x9005, 0x1138, 0x00c6, 0x2660, 0x6003, 0x0009,
+	0x630a, 0x00ce, 0x04b8, 0x080c, 0x9656, 0x78c3, 0x0000, 0x080c,
+	0x9b78, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140, 0x7b04, 0x9384,
+	0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2c88, 0x9006, 0x080c,
+	0x2c88, 0x2079, 0x0100, 0x7824, 0xd084, 0x0110, 0x7827, 0x0001,
+	0x080c, 0x9b78, 0x003e, 0x080c, 0x63d2, 0x00c6, 0xb83c, 0x9005,
+	0x0110, 0x8001, 0xb83e, 0x2660, 0x080c, 0xa0e3, 0x00ce, 0xa867,
+	0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0xc12d, 0x080c, 0x6ae9,
+	0x080c, 0x9a4e, 0x00fe, 0x0005, 0x00b6, 0x00e6, 0x00c6, 0x2011,
+	0x0101, 0x2204, 0xc0c4, 0x2012, 0x2001, 0x180c, 0x2014, 0xc2e4,
+	0x2202, 0x2071, 0x19bf, 0x7004, 0x9084, 0x0007, 0x0002, 0x8b21,
+	0x8b25, 0x8b43, 0x8b6c, 0x8baa, 0x8b21, 0x8b3c, 0x8b1f, 0x080c,
+	0x0dfa, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x7024, 0x9065, 0x0148,
+	0x7020, 0x8001, 0x7022, 0x600c, 0x9015, 0x0158, 0x7216, 0x600f,
+	0x0000, 0x7007, 0x0000, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x00be,
+	0x0005, 0x7216, 0x7212, 0x0ca8, 0x7007, 0x0000, 0x7027, 0x0000,
+	0x7020, 0x9005, 0x0070, 0x6010, 0x2058, 0x080c, 0x63d2, 0xb800,
+	0xc0dc, 0xb802, 0x7007, 0x0000, 0x7027, 0x0000, 0x7020, 0x8001,
+	0x7022, 0x1148, 0x2001, 0x180c, 0x2014, 0xd2ec, 0x1180, 0x00ce,
+	0x00ee, 0x00be, 0x0005, 0xb854, 0x9015, 0x0120, 0x721e, 0x080c,
+	0x8c10, 0x0ca8, 0x7218, 0x721e, 0x080c, 0x8c10, 0x0c80, 0xc2ec,
+	0x2202, 0x080c, 0x8ced, 0x0c58, 0x7024, 0x9065, 0x05b8, 0x700c,
+	0x9c06, 0x1160, 0x080c, 0x9a4e, 0x600c, 0x9015, 0x0120, 0x720e,
+	0x600f, 0x0000, 0x0448, 0x720e, 0x720a, 0x0430, 0x7014, 0x9c06,
+	0x1160, 0x080c, 0x9a4e, 0x600c, 0x9015, 0x0120, 0x7216, 0x600f,
+	0x0000, 0x00d0, 0x7216, 0x7212, 0x00b8, 0x6020, 0x9086, 0x0003,
+	0x1198, 0x6010, 0x2058, 0x080c, 0x63d2, 0xb800, 0xc0dc, 0xb802,
+	0x080c, 0x9a4e, 0x701c, 0x9065, 0x0138, 0xb854, 0x9015, 0x0110,
+	0x721e, 0x0010, 0x7218, 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee,
+	0x00be, 0x0005, 0x7024, 0x9065, 0x0140, 0x080c, 0x9a4e, 0x600c,
+	0x9015, 0x0158, 0x720e, 0x600f, 0x0000, 0x080c, 0x9b78, 0x7027,
+	0x0000, 0x00ce, 0x00ee, 0x00be, 0x0005, 0x720e, 0x720a, 0x0ca8,
+	0x00d6, 0x2069, 0x19bf, 0x6830, 0x9084, 0x0003, 0x0002, 0x8bcd,
+	0x8bcf, 0x8bf3, 0x8bcb, 0x080c, 0x0dfa, 0x00de, 0x0005, 0x00c6,
+	0x6840, 0x9086, 0x0001, 0x01b8, 0x683c, 0x9065, 0x0130, 0x600c,
+	0x9015, 0x0170, 0x6a3a, 0x600f, 0x0000, 0x6833, 0x0000, 0x683f,
+	0x0000, 0x2011, 0x19de, 0x2013, 0x0000, 0x00ce, 0x00de, 0x0005,
+	0x683a, 0x6836, 0x0c90, 0x6843, 0x0000, 0x6838, 0x9065, 0x0d68,
+	0x6003, 0x0003, 0x0c50, 0x00c6, 0x9006, 0x6842, 0x6846, 0x684a,
+	0x683c, 0x9065, 0x0160, 0x600c, 0x9015, 0x0130, 0x6a3a, 0x600f,
+	0x0000, 0x683f, 0x0000, 0x0018, 0x683e, 0x683a, 0x6836, 0x00ce,
+	0x00de, 0x0005, 0x2001, 0x180c, 0x200c, 0xc1e5, 0x2102, 0x0005,
+	0x2001, 0x180c, 0x200c, 0xd1ec, 0x0120, 0xc1ec, 0x2102, 0x080c,
+	0x8ced, 0x2001, 0x19cb, 0x2004, 0x9086, 0x0001, 0x0d58, 0x00d6,
+	0x2069, 0x19bf, 0x6804, 0x9084, 0x0007, 0x0002, 0x8c30, 0x8cd5,
+	0x8cd5, 0x8cd5, 0x8cd5, 0x8cd7, 0x8cd5, 0x8c2e, 0x080c, 0x0dfa,
+	0x6820, 0x9005, 0x1110, 0x00de, 0x0005, 0x00c6, 0x680c, 0x9065,
+	0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c, 0x8d44,
+	0x00ce, 0x00de, 0x0005, 0x6814, 0x9065, 0x0150, 0x6807, 0x0001,
+	0x6826, 0x682b, 0x0000, 0x080c, 0x8d44, 0x00ce, 0x00de, 0x0005,
+	0x00b6, 0x00e6, 0x6a1c, 0x92dd, 0x0000, 0x0904, 0x8cbf, 0xb84c,
+	0x900d, 0x0118, 0xb888, 0x9005, 0x01a0, 0xb854, 0x905d, 0x0120,
+	0x920e, 0x0904, 0x8cbf, 0x0028, 0x6818, 0x920e, 0x0904, 0x8cbf,
+	0x2058, 0xb84c, 0x900d, 0x0d88, 0xb888, 0x9005, 0x1d70, 0x2b00,
+	0x681e, 0xbb3c, 0xb838, 0x9302, 0x1e40, 0x080c, 0xa0ba, 0x0904,
+	0x8cbf, 0x8318, 0xbb3e, 0x6116, 0x2b10, 0x6212, 0x0096, 0x2148,
+	0xa880, 0x9084, 0x00ff, 0x605e, 0xa883, 0x0000, 0xa884, 0x009e,
+	0x908a, 0x199a, 0x0210, 0x2001, 0x1999, 0x8003, 0x801b, 0x831b,
+	0x9318, 0x631a, 0x6114, 0x0096, 0x2148, 0xa964, 0x009e, 0x918c,
+	0x00ff, 0x918e, 0x0048, 0x0538, 0x00f6, 0x2c78, 0x2061, 0x0100,
+	0xbab0, 0x629a, 0x2069, 0x0200, 0x2071, 0x0240, 0x080c, 0x9286,
+	0x2069, 0x19bf, 0xbb00, 0xc3dd, 0xbb02, 0x6807, 0x0002, 0x2f18,
+	0x6b26, 0x682b, 0x0000, 0x7823, 0x0003, 0x7803, 0x0001, 0x7807,
+	0x0040, 0x00fe, 0x00ee, 0x00be, 0x00ce, 0x00de, 0x0005, 0x00ee,
+	0x00be, 0x00ce, 0x0cd0, 0x6807, 0x0006, 0x2c18, 0x6b26, 0x6820,
+	0x8001, 0x6822, 0x682b, 0x0000, 0x080c, 0x63d2, 0x080c, 0x9f0f,
+	0x00ee, 0x00be, 0x00ce, 0x00de, 0x0005, 0x00de, 0x0005, 0x00c6,
+	0x680c, 0x9065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000,
+	0x080c, 0x8d44, 0x00ce, 0x00de, 0x0005, 0x2001, 0x180c, 0x2014,
+	0xc2ed, 0x2202, 0x00de, 0x00fe, 0x0005, 0x00f6, 0x00d6, 0x2069,
+	0x19bf, 0x6830, 0x9086, 0x0000, 0x1548, 0x2001, 0x180c, 0x2014,
+	0xd2e4, 0x0130, 0xc2e4, 0x2202, 0x080c, 0x8c1f, 0x2069, 0x19bf,
+	0x2001, 0x180c, 0x200c, 0xd1c4, 0x11e0, 0x6838, 0x907d, 0x01b0,
+	0x6a04, 0x9296, 0x0000, 0x1568, 0x6833, 0x0001, 0x683e, 0x6847,
+	0x0000, 0x684b, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e,
+	0x080c, 0x1b8a, 0x1158, 0x012e, 0x080c, 0x94b3, 0x00de, 0x00fe,
+	0x0005, 0xc1c4, 0x2102, 0x080c, 0x72d2, 0x08f8, 0x012e, 0x6843,
+	0x0000, 0x7803, 0x0002, 0x780c, 0x9015, 0x0140, 0x6a3a, 0x780f,
+	0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c40, 0x683a, 0x6836,
+	0x0cc0, 0x6a04, 0x9296, 0x0006, 0x1904, 0x8ce5, 0x6a30, 0x9296,
+	0x0000, 0x0950, 0x0804, 0x8ce5, 0x6020, 0x9084, 0x000f, 0x000b,
+	0x0005, 0x8d58, 0x8d5d, 0x91b6, 0x924f, 0x8d5d, 0x91b6, 0x924f,
+	0x8d58, 0x8d5d, 0x8d58, 0x8d58, 0x8d58, 0x8d58, 0x8d58, 0x8d58,
+	0x080c, 0x8b04, 0x080c, 0x8c10, 0x0005, 0x00b6, 0x0156, 0x0136,
+	0x0146, 0x01c6, 0x01d6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2069,
+	0x0200, 0x2071, 0x0240, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dfa,
+	0x6110, 0x2158, 0xb9b0, 0x2c78, 0x2061, 0x0100, 0x619a, 0x908a,
+	0x0040, 0x1a04, 0x8dc9, 0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x01de, 0x01ce, 0x014e, 0x013e, 0x015e, 0x00be, 0x0005, 0x8f40,
+	0x8f7b, 0x8fa4, 0x9047, 0x9068, 0x906e, 0x907b, 0x9083, 0x908f,
+	0x9095, 0x90a6, 0x9095, 0x90fd, 0x9083, 0x9109, 0x910f, 0x908f,
+	0x910f, 0x911b, 0x8dc7, 0x8dc7, 0x8dc7, 0x8dc7, 0x8dc7, 0x8dc7,
+	0x8dc7, 0x8dc7, 0x8dc7, 0x8dc7, 0x8dc7, 0x9854, 0x9877, 0x9888,
+	0x98a8, 0x98da, 0x907b, 0x8dc7, 0x907b, 0x9095, 0x8dc7, 0x8fa4,
+	0x9047, 0x8dc7, 0x9c6f, 0x9095, 0x8dc7, 0x9c8b, 0x9095, 0x8dc7,
+	0x908f, 0x8f3a, 0x8dea, 0x8dc7, 0x9ca7, 0x9d14, 0x9def, 0x8dc7,
+	0x9dfc, 0x9078, 0x9e27, 0x8dc7, 0x98e4, 0x9e54, 0x8dc7, 0x080c,
+	0x0dfa, 0x2100, 0x005b, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x01de,
+	0x01ce, 0x014e, 0x013e, 0x015e, 0x00be, 0x0005, 0x8de8, 0x8de8,
+	0x8de8, 0x8e11, 0x8ebd, 0x8ec8, 0x8de8, 0x8de8, 0x8de8, 0x8f0f,
+	0x8f1b, 0x8e2c, 0x8de8, 0x8e47, 0x8e7b, 0x9fd6, 0xa01b, 0x9095,
+	0x080c, 0x0dfa, 0x00d6, 0x0096, 0x080c, 0x912e, 0x7003, 0x2414,
+	0x7007, 0x0018, 0x700b, 0x0800, 0x7814, 0x2048, 0xa83c, 0x700e,
+	0xa850, 0x7022, 0xa854, 0x7026, 0x60c3, 0x0018, 0x080c, 0x962a,
+	0x009e, 0x00de, 0x0005, 0x7810, 0x00b6, 0x2058, 0xb8a0, 0x00be,
+	0x080c, 0xa062, 0x1118, 0x9084, 0xff80, 0x0110, 0x9085, 0x0001,
+	0x0005, 0x00d6, 0x0096, 0x080c, 0x912e, 0x7003, 0x0500, 0x7814,
+	0x2048, 0xa874, 0x700a, 0xa878, 0x700e, 0xa87c, 0x7012, 0xa880,
+	0x7016, 0xa884, 0x701a, 0xa888, 0x701e, 0x60c3, 0x0010, 0x080c,
+	0x962a, 0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, 0x080c, 0x912e,
+	0x7003, 0x0500, 0x7814, 0x2048, 0xa8cc, 0x700a, 0xa8d0, 0x700e,
+	0xa8d4, 0x7012, 0xa8d8, 0x7016, 0xa8dc, 0x701a, 0xa8e0, 0x701e,
+	0x60c3, 0x0010, 0x080c, 0x962a, 0x009e, 0x00de, 0x0005, 0x00d6,
+	0x0096, 0x0126, 0x2091, 0x8000, 0x080c, 0x912e, 0x20e9, 0x0000,
+	0x2001, 0x197b, 0x2003, 0x0000, 0x7814, 0x2048, 0xa814, 0x8003,
+	0x60c2, 0xa830, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b,
+	0x2098, 0x2001, 0x197b, 0x0016, 0x200c, 0x2001, 0x0001, 0x080c,
+	0x22ef, 0x080c, 0xcb69, 0x9006, 0x080c, 0x22ef, 0x001e, 0xa804,
+	0x9005, 0x0110, 0x2048, 0x0c28, 0x04d9, 0x080c, 0x962a, 0x012e,
+	0x009e, 0x00de, 0x0005, 0x00d6, 0x0096, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x9179, 0x20e9, 0x0000, 0x2001, 0x197b, 0x2003, 0x0000,
+	0x7814, 0x2048, 0xa86f, 0x0200, 0xa873, 0x0000, 0xa814, 0x8003,
+	0x60c2, 0xa830, 0x20a8, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x001b,
+	0x2098, 0x2001, 0x197b, 0x0016, 0x200c, 0x080c, 0xcb69, 0x001e,
+	0xa804, 0x9005, 0x0110, 0x2048, 0x0c60, 0x0051, 0x7814, 0x2048,
+	0x080c, 0x0fe3, 0x080c, 0x962a, 0x012e, 0x009e, 0x00de, 0x0005,
+	0x60c0, 0x8004, 0x9084, 0x0003, 0x9005, 0x0130, 0x9082, 0x0004,
+	0x20a3, 0x0000, 0x8000, 0x1de0, 0x0005, 0x080c, 0x912e, 0x7003,
+	0x7800, 0x7808, 0x8007, 0x700a, 0x60c3, 0x0008, 0x0804, 0x962a,
+	0x00d6, 0x00e6, 0x080c, 0x9179, 0x7814, 0x9084, 0xff00, 0x2073,
+	0x0200, 0x8e70, 0x8e70, 0x9095, 0x0010, 0x2272, 0x8e70, 0x2073,
+	0x0034, 0x8e70, 0x2069, 0x1805, 0x20a9, 0x0004, 0x2d76, 0x8d68,
+	0x8e70, 0x1f04, 0x8ede, 0x2069, 0x1801, 0x20a9, 0x0004, 0x2d76,
+	0x8d68, 0x8e70, 0x1f04, 0x8ee7, 0x2069, 0x198b, 0x9086, 0xdf00,
+	0x0110, 0x2069, 0x19a5, 0x20a9, 0x001a, 0x9e86, 0x0260, 0x1148,
+	0x00c6, 0x2061, 0x0200, 0x6010, 0x8000, 0x6012, 0x00ce, 0x2071,
+	0x0240, 0x2d04, 0x8007, 0x2072, 0x8d68, 0x8e70, 0x1f04, 0x8ef5,
+	0x60c3, 0x004c, 0x080c, 0x962a, 0x00ee, 0x00de, 0x0005, 0x080c,
+	0x912e, 0x7003, 0x6300, 0x7007, 0x0028, 0x7808, 0x700e, 0x60c3,
+	0x0008, 0x0804, 0x962a, 0x00d6, 0x0026, 0x0016, 0x080c, 0x9179,
+	0x7003, 0x0200, 0x7814, 0x700e, 0x00e6, 0x9ef0, 0x0004, 0x2009,
+	0x0001, 0x2011, 0x000c, 0x2073, 0x0800, 0x8e70, 0x2073, 0x0000,
+	0x00ee, 0x7206, 0x710a, 0x62c2, 0x080c, 0x962a, 0x001e, 0x002e,
+	0x00de, 0x0005, 0x2001, 0x1817, 0x2004, 0x609a, 0x0804, 0x962a,
+	0x080c, 0x912e, 0x7003, 0x5200, 0x2069, 0x185b, 0x6804, 0xd084,
+	0x0130, 0x6828, 0x0016, 0x080c, 0x27a1, 0x710e, 0x001e, 0x20a9,
+	0x0004, 0x20e1, 0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1,
+	0x0250, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801, 0x20a1, 0x0254,
+	0x4003, 0x080c, 0xa062, 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248,
+	0x2001, 0x181e, 0x2004, 0x7032, 0x2001, 0x181f, 0x2004, 0x7036,
+	0x0030, 0x2001, 0x1817, 0x2004, 0x9084, 0x00ff, 0x7036, 0x60c3,
+	0x001c, 0x0804, 0x962a, 0x080c, 0x912e, 0x7003, 0x0500, 0x080c,
+	0xa062, 0x1120, 0xb8a0, 0x9082, 0x007f, 0x0248, 0x2001, 0x181e,
+	0x2004, 0x700a, 0x2001, 0x181f, 0x2004, 0x700e, 0x0030, 0x2001,
+	0x1817, 0x2004, 0x9084, 0x00ff, 0x700e, 0x20a9, 0x0004, 0x20e1,
+	0x0001, 0x2099, 0x1805, 0x20e9, 0x0000, 0x20a1, 0x0250, 0x4003,
+	0x60c3, 0x0010, 0x0804, 0x962a, 0x080c, 0x912e, 0x9006, 0x080c,
+	0x678d, 0xb8a0, 0x9086, 0x007e, 0x1130, 0x7003, 0x0400, 0x620c,
+	0xc2b4, 0x620e, 0x0058, 0x7814, 0x0096, 0x904d, 0x0120, 0x9006,
+	0xa89a, 0xa8a6, 0xa8aa, 0x009e, 0x7003, 0x0300, 0xb8a0, 0x9086,
+	0x007e, 0x1904, 0x900f, 0x00d6, 0x2069, 0x1944, 0x2001, 0x1836,
+	0x2004, 0xd0a4, 0x0178, 0x6800, 0x700a, 0x6808, 0x9084, 0x2000,
+	0x7012, 0x680c, 0x7016, 0x701f, 0x2710, 0x6818, 0x7022, 0x681c,
+	0x7026, 0x0080, 0x6800, 0x700a, 0x6804, 0x700e, 0x6808, 0x080c,
+	0x7207, 0x1118, 0x9084, 0x37ff, 0x0010, 0x9084, 0x3fff, 0x7012,
+	0x680c, 0x7016, 0x00de, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099,
+	0x1805, 0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003, 0x20a9, 0x0004,
+	0x2099, 0x1801, 0x20a1, 0x025a, 0x4003, 0x00d6, 0x080c, 0x9ed6,
+	0x2069, 0x194c, 0x2071, 0x024e, 0x6800, 0xc0dd, 0x7002, 0x080c,
+	0x55df, 0xd0e4, 0x0110, 0x680c, 0x700e, 0x00de, 0x04a0, 0x2001,
+	0x1836, 0x2004, 0xd0a4, 0x0168, 0x0016, 0x2009, 0x0002, 0x60e0,
+	0x9106, 0x0130, 0x2100, 0x60e3, 0x0000, 0x080c, 0x27e2, 0x61e2,
+	0x001e, 0x20e1, 0x0001, 0x2099, 0x1944, 0x20e9, 0x0000, 0x20a1,
+	0x024e, 0x20a9, 0x0008, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1805,
+	0x20a1, 0x0256, 0x4003, 0x20a9, 0x0004, 0x2099, 0x1801, 0x20a1,
+	0x025a, 0x4003, 0x080c, 0x9ed6, 0x20a1, 0x024e, 0x20a9, 0x0008,
+	0x2099, 0x194c, 0x4003, 0x60c3, 0x0074, 0x0804, 0x962a, 0x080c,
+	0x912e, 0x7003, 0x2010, 0x7007, 0x0014, 0x700b, 0x0800, 0x700f,
+	0x2000, 0x9006, 0x00f6, 0x2079, 0x185b, 0x7904, 0x00fe, 0xd1ac,
+	0x1110, 0x9085, 0x0020, 0x0010, 0x9085, 0x0010, 0x9085, 0x0002,
+	0x00d6, 0x0804, 0x90de, 0x7026, 0x60c3, 0x0014, 0x0804, 0x962a,
+	0x080c, 0x912e, 0x7003, 0x5000, 0x0804, 0x8fbe, 0x080c, 0x912e,
+	0x7003, 0x2110, 0x7007, 0x0014, 0x60c3, 0x0014, 0x0804, 0x962a,
+	0x080c, 0x9170, 0x0010, 0x080c, 0x9179, 0x7003, 0x0200, 0x60c3,
+	0x0004, 0x0804, 0x962a, 0x080c, 0x9179, 0x7003, 0x0100, 0x700b,
+	0x0003, 0x700f, 0x2a00, 0x60c3, 0x0008, 0x0804, 0x962a, 0x080c,
+	0x9179, 0x7003, 0x0200, 0x0804, 0x8fbe, 0x080c, 0x9179, 0x7003,
+	0x0100, 0x782c, 0x9005, 0x0110, 0x700a, 0x0010, 0x700b, 0x0003,
+	0x7814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x962a, 0x00d6, 0x080c,
+	0x9179, 0x7003, 0x0210, 0x7007, 0x0014, 0x700b, 0x0800, 0xb894,
+	0x9086, 0x0014, 0x1198, 0xb99c, 0x9184, 0x0030, 0x0190, 0xb998,
+	0x9184, 0xc000, 0x1140, 0xd1ec, 0x0118, 0x700f, 0x2100, 0x0058,
+	0x700f, 0x0100, 0x0040, 0x700f, 0x0400, 0x0028, 0x700f, 0x0700,
+	0x0010, 0x700f, 0x0800, 0x00f6, 0x2079, 0x185b, 0x7904, 0x00fe,
+	0xd1ac, 0x1110, 0x9085, 0x0020, 0x0010, 0x9085, 0x0010, 0x2009,
+	0x187d, 0x210c, 0xd184, 0x1110, 0x9085, 0x0002, 0x0026, 0x2009,
+	0x187b, 0x210c, 0xd1e4, 0x0150, 0xc0c5, 0xbabc, 0xd28c, 0x1108,
+	0xc0cd, 0x9094, 0x0030, 0x9296, 0x0010, 0x0140, 0xd1ec, 0x0130,
+	0x9094, 0x0030, 0x9296, 0x0010, 0x0108, 0xc0bd, 0x002e, 0x7026,
+	0x60c3, 0x0014, 0x00de, 0x0804, 0x962a, 0x080c, 0x9179, 0x7003,
+	0x0210, 0x7007, 0x0014, 0x700f, 0x0100, 0x60c3, 0x0014, 0x0804,
+	0x962a, 0x080c, 0x9179, 0x7003, 0x0200, 0x0804, 0x8f44, 0x080c,
+	0x9179, 0x7003, 0x0100, 0x700b, 0x0003, 0x700f, 0x2a00, 0x60c3,
+	0x0008, 0x0804, 0x962a, 0x080c, 0x9179, 0x7003, 0x0100, 0x700b,
+	0x000b, 0x60c3, 0x0008, 0x0804, 0x962a, 0x0026, 0x00d6, 0x0036,
+	0x0046, 0x2019, 0x3200, 0x2021, 0x0800, 0x0040, 0x0026, 0x00d6,
+	0x0036, 0x0046, 0x2019, 0x2200, 0x2021, 0x0100, 0x080c, 0x9eeb,
+	0xb810, 0x9305, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6878,
+	0x700a, 0x687c, 0x700e, 0x9485, 0x0029, 0x7012, 0x004e, 0x003e,
+	0x00de, 0x080c, 0x9618, 0x721a, 0x9f95, 0x0000, 0x7222, 0x7027,
+	0xffff, 0x2071, 0x024c, 0x002e, 0x0005, 0x0026, 0x080c, 0x9eeb,
+	0x7003, 0x02ff, 0x7007, 0xfffc, 0x00d6, 0x2069, 0x1800, 0x6878,
+	0x700a, 0x687c, 0x700e, 0x00de, 0x7013, 0x2029, 0x0c10, 0x7003,
+	0x0100, 0x7007, 0x0000, 0x700b, 0xfc02, 0x700f, 0x0000, 0x0005,
+	0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x3300, 0x2021, 0x0800,
+	0x0040, 0x0026, 0x00d6, 0x0036, 0x0046, 0x2019, 0x2300, 0x2021,
+	0x0100, 0x080c, 0x9eeb, 0xb810, 0x9305, 0x7002, 0xb814, 0x7006,
+	0x2069, 0x1800, 0xb810, 0x9005, 0x1140, 0xb814, 0x9005, 0x1128,
+	0x700b, 0x00ff, 0x700f, 0xfffe, 0x0020, 0x6878, 0x700a, 0x687c,
+	0x700e, 0x0000, 0x9485, 0x0098, 0x7012, 0x004e, 0x003e, 0x00de,
+	0x080c, 0x9618, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071,
+	0x024c, 0x002e, 0x0005, 0x080c, 0x9618, 0x721a, 0x7a08, 0x7222,
+	0x7814, 0x7026, 0x2071, 0x024c, 0x002e, 0x0005, 0x00b6, 0x00c6,
+	0x00d6, 0x00e6, 0x00f6, 0x2069, 0x0200, 0x2071, 0x0240, 0x6004,
+	0x908a, 0x0085, 0x0a0c, 0x0dfa, 0x908a, 0x0092, 0x1a0c, 0x0dfa,
+	0x6110, 0x2158, 0xb9b0, 0x2c78, 0x2061, 0x0100, 0x619a, 0x9082,
+	0x0085, 0x0033, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be, 0x0005,
+	0x91e7, 0x91f6, 0x9201, 0x91e5, 0x91e5, 0x91e5, 0x91e7, 0x91e5,
+	0x91e5, 0x91e5, 0x91e5, 0x91e5, 0x91e5, 0x080c, 0x0dfa, 0x0411,
+	0x60c3, 0x0000, 0x0026, 0x080c, 0x2afe, 0x0228, 0x2011, 0x0101,
+	0x2204, 0xc0c5, 0x2012, 0x002e, 0x0804, 0x962a, 0x0431, 0x7808,
+	0x700a, 0x7814, 0x700e, 0x7017, 0xffff, 0x60c3, 0x000c, 0x0804,
+	0x962a, 0x04a1, 0x7003, 0x0003, 0x7007, 0x0300, 0x60c3, 0x0004,
+	0x0804, 0x962a, 0x0026, 0x080c, 0x9eeb, 0xb810, 0x9085, 0x8100,
+	0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6878, 0x700a, 0x687c,
+	0x700e, 0x7013, 0x0009, 0x0804, 0x9149, 0x0026, 0x080c, 0x9eeb,
+	0xb810, 0x9085, 0x8400, 0x7002, 0xb814, 0x7006, 0x2069, 0x1800,
+	0x6878, 0x700a, 0x687c, 0x700e, 0x2001, 0x0099, 0x7a20, 0x9296,
+	0x0005, 0x0108, 0xc0bc, 0x7012, 0x0804, 0x91ab, 0x0026, 0x080c,
+	0x9eeb, 0xb810, 0x9085, 0x8500, 0x7002, 0xb814, 0x7006, 0x2069,
+	0x1800, 0x6878, 0x700a, 0x687c, 0x700e, 0x2001, 0x0099, 0x7a20,
+	0x9296, 0x0005, 0x0108, 0xc0bc, 0x7012, 0x0804, 0x91ab, 0x00b6,
+	0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2c78, 0x2069, 0x0200, 0x2071,
+	0x0240, 0x7804, 0x908a, 0x0040, 0x0a0c, 0x0dfa, 0x908a, 0x0054,
+	0x1a0c, 0x0dfa, 0x7910, 0x2158, 0xb9b0, 0x2061, 0x0100, 0x619a,
+	0x9082, 0x0040, 0x0033, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x00be,
+	0x0005, 0x9286, 0x9342, 0x9315, 0x9464, 0x9284, 0x9284, 0x9284,
+	0x9284, 0x9284, 0x9284, 0x9284, 0x9a2b, 0x9a33, 0x9a3b, 0x9a43,
+	0x9284, 0x9e33, 0x9284, 0x9a23, 0x080c, 0x0dfa, 0x0096, 0x780b,
+	0xffff, 0x080c, 0x92f1, 0x7914, 0x2148, 0xa978, 0x7956, 0xae64,
+	0x96b4, 0x00ff, 0x9686, 0x0008, 0x1148, 0xa8b4, 0x7032, 0xa8b8,
+	0x7036, 0xa8bc, 0x703a, 0xa8c0, 0x703e, 0x0008, 0x7132, 0xa97c,
+	0x9184, 0x000f, 0x1118, 0x2001, 0x0005, 0x0040, 0xd184, 0x0118,
+	0x2001, 0x0004, 0x0018, 0x9084, 0x0006, 0x8004, 0x2010, 0x785c,
+	0x9084, 0x00ff, 0x8007, 0x9205, 0x7042, 0xd1ac, 0x0158, 0x7047,
+	0x0002, 0x9686, 0x0008, 0x1118, 0x080c, 0x181c, 0x0010, 0x080c,
+	0x16db, 0x0050, 0xd1b4, 0x0118, 0x7047, 0x0001, 0x0028, 0x7047,
+	0x0000, 0x9016, 0x2230, 0x0010, 0xaab0, 0xaeac, 0x726a, 0x766e,
+	0x20a9, 0x0008, 0x20e9, 0x0000, 0xa860, 0x20e0, 0xa85c, 0x9080,
+	0x0023, 0x2098, 0x20a1, 0x0252, 0x2069, 0x0200, 0x6813, 0x0018,
+	0x4003, 0x6813, 0x0008, 0x60c3, 0x0020, 0x6017, 0x0009, 0x2001,
+	0x19db, 0x2003, 0x07d0, 0x2001, 0x19da, 0x2003, 0x0009, 0x009e,
+	0x0005, 0x6813, 0x0008, 0xba8c, 0x8210, 0xb8bc, 0xd084, 0x0128,
+	0x7a4a, 0x7b14, 0x7b46, 0x722e, 0x732a, 0x9294, 0x00ff, 0xba8e,
+	0x8217, 0x721a, 0xba10, 0x9295, 0x0600, 0x7202, 0xba14, 0x7206,
+	0x2069, 0x1800, 0x6a78, 0x720a, 0x6a7c, 0x720e, 0x7013, 0x0829,
+	0x2f10, 0x7222, 0x7027, 0xffff, 0x0005, 0x00d6, 0x0096, 0x0081,
+	0x7814, 0x2048, 0xa890, 0x7002, 0xa88c, 0x7006, 0xa8b0, 0x700a,
+	0xa8ac, 0x700e, 0x60c3, 0x000c, 0x009e, 0x00de, 0x0804, 0x962a,
+	0x6813, 0x0008, 0xb810, 0x9085, 0x0500, 0x7002, 0xb814, 0x7006,
+	0x2069, 0x1800, 0x6878, 0x700a, 0x687c, 0x700e, 0x7013, 0x0889,
+	0x080c, 0x9618, 0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071,
+	0x024c, 0x0005, 0x00d6, 0x0096, 0x080c, 0x9442, 0x7814, 0x2048,
+	0x080c, 0xbe35, 0x1130, 0x7814, 0x9084, 0x0700, 0x8007, 0x0033,
+	0x0010, 0x9006, 0x001b, 0x009e, 0x00de, 0x0005, 0x9360, 0x93c9,
+	0x93d9, 0x93ff, 0x940b, 0x941c, 0x9424, 0x935e, 0x080c, 0x0dfa,
+	0x0016, 0x0036, 0xa97c, 0x918c, 0x0003, 0x0118, 0x9186, 0x0003,
+	0x1198, 0xaba8, 0x7824, 0xd0cc, 0x1168, 0x7316, 0xa898, 0x701a,
+	0xa894, 0x701e, 0x003e, 0x001e, 0x2001, 0x1989, 0x2004, 0x60c2,
+	0x0804, 0x962a, 0xc3e5, 0x0c88, 0x9186, 0x0001, 0x190c, 0x0dfa,
+	0xaba8, 0x7824, 0xd0cc, 0x1904, 0x93c6, 0x7316, 0xa898, 0x701a,
+	0xa894, 0x701e, 0xa8a4, 0x7026, 0xa8ac, 0x702e, 0x2009, 0x0018,
+	0x9384, 0x0300, 0x0570, 0xd3c4, 0x0110, 0xa8ac, 0x9108, 0xd3cc,
+	0x0110, 0xa8a4, 0x9108, 0x6810, 0x9085, 0x0010, 0x6812, 0x2011,
+	0x0258, 0x20e9, 0x0000, 0x22a0, 0x0156, 0x20a9, 0x0008, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x002c, 0x2098, 0x4003, 0x6810, 0x8000,
+	0x6812, 0x2011, 0x0240, 0x22a0, 0x20a9, 0x0005, 0x4003, 0x6810,
+	0xc084, 0x6812, 0x015e, 0x9184, 0x0003, 0x0118, 0x2019, 0x0245,
+	0x201a, 0x61c2, 0x003e, 0x001e, 0x0804, 0x962a, 0xc3e5, 0x0804,
+	0x9385, 0x2011, 0x0008, 0x2001, 0x180f, 0x2004, 0xd0a4, 0x0110,
+	0x2011, 0x0028, 0x7824, 0xd0cc, 0x1110, 0x7216, 0x0470, 0x0ce8,
+	0xc2e5, 0x2011, 0x0302, 0x0016, 0x782c, 0x701a, 0x7930, 0x711e,
+	0x9105, 0x0108, 0xc2dd, 0x001e, 0x7824, 0xd0cc, 0x0108, 0xc2e5,
+	0x7216, 0x7027, 0x0012, 0x702f, 0x0008, 0x7043, 0x7000, 0x7047,
+	0x0500, 0x704f, 0x000a, 0x2069, 0x0200, 0x6813, 0x0009, 0x2071,
+	0x0240, 0x700b, 0x2500, 0x60c3, 0x0032, 0x0804, 0x962a, 0x2011,
+	0x0028, 0x7824, 0xd0cc, 0x1128, 0x7216, 0x60c3, 0x0018, 0x0804,
+	0x962a, 0x0cd0, 0xc2e5, 0x2011, 0x0100, 0x7824, 0xd0cc, 0x0108,
+	0xc2e5, 0x7216, 0x702f, 0x0008, 0x7858, 0x9084, 0x00ff, 0x7036,
+	0x60c3, 0x0020, 0x0804, 0x962a, 0x2011, 0x0008, 0x7824, 0xd0cc,
+	0x0108, 0xc2e5, 0x7216, 0x0c08, 0x0036, 0x7b14, 0x9384, 0xff00,
+	0x7816, 0x9384, 0x00ff, 0x8001, 0x1138, 0x7824, 0xd0cc, 0x0108,
+	0xc2e5, 0x7216, 0x003e, 0x0888, 0x0046, 0x2021, 0x0800, 0x0006,
+	0x7824, 0xd0cc, 0x000e, 0x0108, 0xc4e5, 0x7416, 0x004e, 0x701e,
+	0x003e, 0x0818, 0x00d6, 0x6813, 0x0008, 0xb810, 0x9085, 0x0700,
+	0x7002, 0xb814, 0x7006, 0x2069, 0x1800, 0x6878, 0x700a, 0x687c,
+	0x700e, 0x7824, 0xd0cc, 0x1168, 0x7013, 0x0898, 0x080c, 0x9618,
+	0x721a, 0x7a08, 0x7222, 0x2f10, 0x7226, 0x2071, 0x024c, 0x00de,
+	0x0005, 0x7013, 0x0889, 0x0c90, 0x0016, 0x7814, 0x9084, 0x0700,
+	0x8007, 0x0013, 0x001e, 0x0005, 0x9474, 0x9474, 0x9476, 0x9474,
+	0x9474, 0x9474, 0x9490, 0x9474, 0x080c, 0x0dfa, 0x7914, 0x918c,
+	0x08ff, 0x918d, 0xf600, 0x7916, 0x2009, 0x0003, 0x00b9, 0x2069,
+	0x185b, 0x6804, 0xd0bc, 0x0130, 0x682c, 0x9084, 0x00ff, 0x8007,
+	0x7032, 0x0010, 0x7033, 0x3f00, 0x60c3, 0x0001, 0x0804, 0x962a,
+	0x2009, 0x0003, 0x0019, 0x7033, 0x7f00, 0x0cb0, 0x0016, 0x080c,
+	0x9eeb, 0x001e, 0xb810, 0x9085, 0x0100, 0x7002, 0xb814, 0x7006,
+	0x2069, 0x1800, 0x6a78, 0x720a, 0x6a7c, 0x720e, 0x7013, 0x0888,
+	0x918d, 0x0008, 0x7116, 0x080c, 0x9618, 0x721a, 0x7a08, 0x7222,
+	0x2f10, 0x7226, 0x0005, 0x00b6, 0x0096, 0x00e6, 0x00d6, 0x00c6,
+	0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0x1800, 0x7810,
+	0x2058, 0xb8a0, 0x2028, 0xb910, 0xba14, 0x7378, 0x747c, 0x7820,
+	0x90be, 0x0006, 0x0904, 0x9587, 0x90be, 0x000a, 0x1904, 0x9543,
+	0xb8b0, 0x609e, 0x7814, 0x2048, 0xa87c, 0xd0fc, 0x0558, 0xaf90,
+	0x9784, 0xff00, 0x9105, 0x6062, 0x873f, 0x9784, 0xff00, 0x0006,
+	0x7814, 0x2048, 0xa878, 0xc0fc, 0x9005, 0x000e, 0x1160, 0xaf94,
+	0x87ff, 0x0198, 0x2039, 0x0098, 0x9705, 0x6072, 0x7808, 0x6082,
+	0x2f00, 0x6086, 0x0038, 0x9185, 0x2200, 0x6062, 0x6073, 0x0129,
+	0x6077, 0x0000, 0xb8b0, 0x609e, 0x0050, 0x2039, 0x0029, 0x9705,
+	0x6072, 0x0cc0, 0x9185, 0x0200, 0x6062, 0x6073, 0x2029, 0xa87c,
+	0xd0fc, 0x0118, 0xaf94, 0x87ff, 0x1120, 0x2f00, 0x6082, 0x7808,
+	0x6086, 0x6266, 0x636a, 0x646e, 0x6077, 0x0000, 0xb88c, 0x8000,
+	0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f, 0x0000, 0xa838,
+	0x608a, 0xa834, 0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c,
+	0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0x080c, 0x9ed0, 0x2009,
+	0x07d0, 0x60c4, 0x9084, 0xfff0, 0x9005, 0x0110, 0x2009, 0x1b58,
+	0x080c, 0x835f, 0x003e, 0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee,
+	0x009e, 0x00be, 0x0005, 0x7804, 0x9086, 0x0040, 0x0904, 0x95c3,
+	0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0809,
+	0x6077, 0x0008, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xb88c, 0x8000,
+	0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00,
+	0x6082, 0x7808, 0x6086, 0x7814, 0x2048, 0xa838, 0x608a, 0xa834,
+	0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c, 0x60ce, 0xbab0,
+	0x629e, 0x080c, 0x9ed0, 0x2009, 0x07d0, 0x60c4, 0x9084, 0xfff0,
+	0x9005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x835f, 0x003e, 0x004e,
+	0x005e, 0x00ce, 0x00de, 0x00ee, 0x009e, 0x00be, 0x0005, 0x7814,
+	0x2048, 0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0904, 0x95df,
+	0x9185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0880,
+	0x6077, 0x0008, 0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007,
+	0x607a, 0x7838, 0x607e, 0x2f00, 0x6086, 0x7808, 0x6082, 0xa890,
+	0x608a, 0xa88c, 0x608e, 0xa8b0, 0x60c6, 0xa8ac, 0x60ca, 0xa8ac,
+	0x7930, 0x9108, 0x7932, 0xa8b0, 0x792c, 0x9109, 0x792e, 0xb86c,
+	0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000, 0xbab0, 0x629e, 0x080c,
+	0x9ead, 0x0804, 0x9573, 0xb8bc, 0xd084, 0x0148, 0xb88c, 0x7814,
+	0x2048, 0xb88c, 0x784a, 0xa836, 0x2900, 0xa83a, 0xb046, 0x9185,
+	0x0600, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073, 0x0829, 0x6077,
+	0x0000, 0x60af, 0x9575, 0x60d7, 0x0000, 0x0804, 0x9556, 0x9185,
+	0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x7824, 0xd0cc, 0x7826,
+	0x0118, 0x6073, 0x0889, 0x0010, 0x6073, 0x0898, 0x6077, 0x0000,
+	0xb88c, 0x8000, 0x9084, 0x00ff, 0xb88e, 0x8007, 0x607a, 0x607f,
+	0x0000, 0x2f00, 0x6086, 0x7808, 0x6082, 0xa838, 0x608a, 0xa834,
+	0x608e, 0xa848, 0x60c6, 0xa844, 0x60ca, 0xb86c, 0x60ce, 0x60af,
+	0x95d5, 0x60d7, 0x0000, 0xbab0, 0x629e, 0x7824, 0xd0cc, 0x0120,
+	0x080c, 0x9ed0, 0x0804, 0x9573, 0x080c, 0x9ead, 0x0804, 0x9573,
+	0x7a10, 0x00b6, 0x2258, 0xba8c, 0x8210, 0x9294, 0x00ff, 0xba8e,
+	0x00be, 0x8217, 0x0005, 0x00d6, 0x2069, 0x19bf, 0x6843, 0x0001,
+	0x00de, 0x0005, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x00f1, 0x080c,
+	0x8351, 0x0005, 0x0016, 0x2001, 0x180c, 0x200c, 0x9184, 0x0600,
+	0x9086, 0x0600, 0x0128, 0x0089, 0x080c, 0x8351, 0x001e, 0x0005,
+	0xc1e5, 0x2001, 0x180c, 0x2102, 0x2001, 0x19c0, 0x2003, 0x0000,
+	0x2001, 0x19c8, 0x2003, 0x0000, 0x0c88, 0x0006, 0x6014, 0x9084,
+	0x1804, 0x9085, 0x0009, 0x6016, 0x000e, 0x0005, 0x0016, 0x00c6,
+	0x0006, 0x2061, 0x0100, 0x61a4, 0x60a7, 0x95f5, 0x6014, 0x9084,
+	0x1804, 0x9085, 0x0008, 0x6016, 0x000e, 0xa001, 0xa001, 0xa001,
+	0x61a6, 0x00ce, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x7207, 0x11c0, 0x2001,
+	0x19db, 0x2004, 0x9005, 0x15d0, 0x080c, 0x72d2, 0x1160, 0x2061,
+	0x0100, 0x6020, 0xd0b4, 0x1120, 0x6024, 0xd084, 0x090c, 0x0dfa,
+	0x080c, 0x8351, 0x0458, 0x00c6, 0x2061, 0x19bf, 0x00c8, 0x6904,
+	0x9194, 0x4000, 0x0540, 0x0811, 0x080c, 0x2c98, 0x00c6, 0x2061,
+	0x19bf, 0x6128, 0x9192, 0x0008, 0x1258, 0x8108, 0x612a, 0x6124,
+	0x00ce, 0x81ff, 0x0198, 0x080c, 0x8351, 0x080c, 0x964d, 0x0070,
+	0x6124, 0x91e5, 0x0000, 0x0140, 0x080c, 0xdc28, 0x080c, 0x835a,
+	0x2009, 0x0014, 0x080c, 0xa15d, 0x00ce, 0x0000, 0x002e, 0x001e,
+	0x00de, 0x00ce, 0x0005, 0x2001, 0x19db, 0x2004, 0x9005, 0x1db0,
+	0x00c6, 0x2061, 0x19bf, 0x6128, 0x9192, 0x0003, 0x1e08, 0x8108,
+	0x612a, 0x00ce, 0x080c, 0x8351, 0x080c, 0x5dea, 0x2009, 0x185a,
+	0x2114, 0x8210, 0x220a, 0x0c10, 0x0096, 0x00c6, 0x00d6, 0x00e6,
+	0x0016, 0x0026, 0x080c, 0x8367, 0x2071, 0x19bf, 0x713c, 0x81ff,
+	0x0904, 0x974a, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x7207,
+	0x1190, 0x0036, 0x2019, 0x0002, 0x080c, 0x999d, 0x003e, 0x713c,
+	0x2160, 0x080c, 0xdc28, 0x2009, 0x004a, 0x080c, 0xa15d, 0x080c,
+	0x72d2, 0x0804, 0x974a, 0x080c, 0x9756, 0x0904, 0x974a, 0x6904,
+	0xd1f4, 0x0904, 0x9751, 0x080c, 0x2c98, 0x00c6, 0x703c, 0x9065,
+	0x090c, 0x0dfa, 0x6020, 0x00ce, 0x9086, 0x0006, 0x1568, 0x61c8,
+	0x60c4, 0x9105, 0x1548, 0x2009, 0x180c, 0x2104, 0xd0d4, 0x0520,
+	0x6214, 0x9294, 0x1800, 0x1128, 0x6224, 0x9294, 0x0002, 0x1550,
+	0x0070, 0xc0d4, 0x200a, 0x0006, 0x2001, 0x0100, 0x2004, 0x9086,
+	0x000a, 0x000e, 0x0120, 0xd0cc, 0x0110, 0x080c, 0x2bca, 0x6014,
+	0x9084, 0xe7fd, 0x9085, 0x0010, 0x6016, 0x703c, 0x2060, 0x2009,
+	0x0049, 0x080c, 0xa15d, 0x0070, 0x0036, 0x2019, 0x0001, 0x080c,
+	0x999d, 0x003e, 0x713c, 0x2160, 0x080c, 0xdc28, 0x2009, 0x004a,
+	0x080c, 0xa15d, 0x002e, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x009e,
+	0x0005, 0xd1ec, 0x1904, 0x9703, 0x0804, 0x9705, 0x00d6, 0x00c6,
+	0x0096, 0x703c, 0x9065, 0x090c, 0x0dfa, 0x2001, 0x0306, 0x200c,
+	0x9184, 0x0030, 0x0904, 0x97ff, 0x9184, 0x0048, 0x9086, 0x0008,
+	0x1904, 0x97ff, 0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c,
+	0x9106, 0x1904, 0x97ff, 0x2009, 0x022a, 0x2104, 0x2009, 0x022f,
+	0x210c, 0x9116, 0x9084, 0x03ff, 0x918c, 0x03ff, 0x9294, 0x0400,
+	0x0110, 0x9102, 0x0030, 0x2010, 0x2100, 0x9202, 0x2009, 0x0228,
+	0x9102, 0x9082, 0x0005, 0x0250, 0x2008, 0x2001, 0x013b, 0x2004,
+	0x8004, 0x8004, 0x8004, 0x9102, 0x1a04, 0x97ff, 0x2009, 0x1a58,
+	0x2104, 0x8000, 0x0208, 0x200a, 0x2069, 0x0100, 0x6914, 0x918c,
+	0x0184, 0x918d, 0x0010, 0x6916, 0x69c8, 0x2011, 0x0020, 0x68c8,
+	0x9106, 0x1570, 0x8211, 0x1dd8, 0x2001, 0x0306, 0x2003, 0x4800,
+	0x2001, 0x009a, 0x2003, 0x0004, 0x2001, 0x1a3d, 0x2003, 0x0000,
+	0x2001, 0x1a46, 0x2003, 0x0000, 0x6a88, 0x698c, 0x2200, 0x9105,
+	0x1120, 0x2c10, 0x080c, 0x1afe, 0x0040, 0x6014, 0x2048, 0xaa3a,
+	0xa936, 0x6ac4, 0x69c8, 0xa946, 0xaa4a, 0x0126, 0x00c6, 0x2091,
+	0x2400, 0x002e, 0x080c, 0x1b8a, 0x190c, 0x0dfa, 0x012e, 0x0090,
+	0x2009, 0x1a59, 0x2104, 0x8000, 0x0208, 0x200a, 0x69c8, 0x2011,
+	0x0020, 0x8211, 0x1df0, 0x68c8, 0x9106, 0x1dc0, 0x69c4, 0x68c8,
+	0x9105, 0x0160, 0x6824, 0xd08c, 0x0110, 0x6827, 0x0002, 0x7048,
+	0xc085, 0x704a, 0x0079, 0x7048, 0xc084, 0x704a, 0x2009, 0x07d0,
+	0x080c, 0x835f, 0x9006, 0x009e, 0x00ce, 0x00de, 0x0005, 0x9085,
+	0x0001, 0x0cc8, 0x0026, 0x00e6, 0x2071, 0x19bf, 0x7048, 0xd084,
+	0x01c0, 0x713c, 0x81ff, 0x01a8, 0x2071, 0x0100, 0x9188, 0x0008,
+	0x2114, 0x928e, 0x0006, 0x1138, 0x7014, 0x9084, 0x1984, 0x9085,
+	0x0012, 0x7016, 0x0030, 0x7014, 0x9084, 0x1984, 0x9085, 0x0016,
+	0x7016, 0x00ee, 0x002e, 0x0005, 0x00b6, 0x00e6, 0x00d6, 0x00c6,
+	0x0066, 0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000, 0x6010,
+	0x2058, 0xbca0, 0x2071, 0x19bf, 0x7018, 0x2058, 0x8bff, 0x0190,
+	0xb8a0, 0x9406, 0x0118, 0xb854, 0x2058, 0x0cc0, 0x6014, 0x0096,
+	0x2048, 0xac6c, 0xad70, 0xae78, 0x009e, 0x080c, 0x65d1, 0x0110,
+	0x9085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e, 0x006e, 0x00ce,
+	0x00de, 0x00ee, 0x00be, 0x0005, 0x080c, 0x912e, 0x7003, 0x1200,
+	0x7838, 0x7012, 0x783c, 0x7016, 0x00c6, 0x7820, 0x9086, 0x0004,
+	0x1148, 0x7810, 0x9005, 0x0130, 0x00b6, 0x2058, 0xb810, 0xb914,
+	0x00be, 0x0020, 0x2061, 0x1800, 0x6078, 0x617c, 0x9084, 0x00ff,
+	0x700a, 0x710e, 0x00ce, 0x60c3, 0x002c, 0x0804, 0x962a, 0x080c,
+	0x912e, 0x7003, 0x0f00, 0x7808, 0xd09c, 0x0128, 0xb810, 0x9084,
+	0x00ff, 0x700a, 0xb814, 0x700e, 0x60c3, 0x0008, 0x0804, 0x962a,
+	0x0156, 0x080c, 0x9179, 0x7003, 0x0200, 0x2011, 0x1848, 0x63f0,
+	0x2312, 0x20a9, 0x0006, 0x2011, 0x1840, 0x2019, 0x1841, 0x9ef0,
+	0x0002, 0x2376, 0x8e70, 0x2276, 0x8e70, 0x9398, 0x0002, 0x9290,
+	0x0002, 0x1f04, 0x9899, 0x60c3, 0x001c, 0x015e, 0x0804, 0x962a,
+	0x0016, 0x0026, 0x080c, 0x9155, 0x080c, 0x9167, 0x9e80, 0x0004,
+	0x20e9, 0x0000, 0x20a0, 0x7814, 0x0096, 0x2048, 0xa800, 0x2048,
+	0xa860, 0x20e0, 0xa85c, 0x9080, 0x0021, 0x2098, 0x009e, 0x7808,
+	0x9088, 0x0002, 0x21a8, 0x9192, 0x0010, 0x1250, 0x4003, 0x9080,
+	0x0004, 0x8003, 0x60c2, 0x080c, 0x962a, 0x002e, 0x001e, 0x0005,
+	0x20a9, 0x0010, 0x4003, 0x080c, 0x9ed6, 0x20a1, 0x0240, 0x22a8,
+	0x4003, 0x0c68, 0x080c, 0x912e, 0x7003, 0x6200, 0x7808, 0x700e,
+	0x60c3, 0x0008, 0x0804, 0x962a, 0x0016, 0x0026, 0x080c, 0x912e,
+	0x20e9, 0x0000, 0x20a1, 0x024c, 0x7814, 0x0096, 0x2048, 0xa800,
+	0x2048, 0xa860, 0x20e0, 0xa85c, 0x9080, 0x0023, 0x2098, 0x009e,
+	0x7808, 0x9088, 0x0002, 0x21a8, 0x4003, 0x8003, 0x60c2, 0x080c,
+	0x962a, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00c6, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x19bf, 0x700c, 0x2060, 0x8cff, 0x0178,
+	0x080c, 0xc03f, 0x1110, 0x080c, 0xaa81, 0x600c, 0x0006, 0x080c,
+	0xc2ab, 0x080c, 0xa0e3, 0x080c, 0x9a4e, 0x00ce, 0x0c78, 0x2c00,
+	0x700e, 0x700a, 0x012e, 0x000e, 0x00ce, 0x00ee, 0x0005, 0x0126,
+	0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016,
+	0x0006, 0x2091, 0x8000, 0x2001, 0x180c, 0x200c, 0x918c, 0xe7ff,
+	0x2102, 0x2069, 0x0100, 0x2079, 0x0140, 0x2071, 0x19bf, 0x7024,
+	0x2060, 0x8cff, 0x01f8, 0x080c, 0x9656, 0x6ac0, 0x68c3, 0x0000,
+	0x080c, 0x835a, 0x00c6, 0x2061, 0x0100, 0x080c, 0x9eef, 0x00ce,
+	0x20a9, 0x01f4, 0x0461, 0x2009, 0x0013, 0x080c, 0xa15d, 0x000e,
+	0x001e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e,
+	0x012e, 0x0005, 0x2001, 0x1800, 0x2004, 0x9096, 0x0001, 0x0d78,
+	0x9096, 0x0004, 0x0d60, 0x080c, 0x835a, 0x6814, 0x9084, 0x0001,
+	0x0110, 0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011,
+	0x5d94, 0x080c, 0x82da, 0x20a9, 0x01f4, 0x0009, 0x08c0, 0x6824,
+	0xd094, 0x0140, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c,
+	0x2c98, 0x0090, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04,
+	0x997f, 0x7804, 0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c,
+	0x2c88, 0x9006, 0x080c, 0x2c88, 0x0005, 0x0126, 0x0156, 0x00f6,
+	0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026, 0x0016, 0x0006, 0x2091,
+	0x8000, 0x2001, 0x180c, 0x200c, 0x918c, 0xdbff, 0x2102, 0x2069,
+	0x0100, 0x2079, 0x0140, 0x2071, 0x19bf, 0x703c, 0x2060, 0x8cff,
+	0x0904, 0x9a04, 0x9386, 0x0002, 0x1128, 0x6814, 0x9084, 0x0002,
+	0x0904, 0x9a04, 0x68af, 0x95f5, 0x6817, 0x0010, 0x2009, 0x00fa,
+	0x8109, 0x1df0, 0x69c6, 0x68cb, 0x0008, 0x080c, 0x8367, 0x080c,
+	0x1f32, 0x2001, 0x0032, 0x6920, 0xd1bc, 0x0130, 0x8001, 0x1dd8,
+	0x692c, 0x918d, 0x0008, 0x692e, 0x20a9, 0x03e8, 0x6824, 0xd094,
+	0x0140, 0x6827, 0x0004, 0x7804, 0x9084, 0x4000, 0x190c, 0x2c98,
+	0x0090, 0xd08c, 0x0118, 0x6827, 0x0002, 0x0010, 0x1f04, 0x99de,
+	0x7804, 0x9084, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2c88,
+	0x9006, 0x080c, 0x2c88, 0x6827, 0x4000, 0x6824, 0x83ff, 0x1120,
+	0x2009, 0x0049, 0x080c, 0xa15d, 0x000e, 0x001e, 0x002e, 0x006e,
+	0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6,
+	0x0126, 0x2091, 0x8000, 0x2069, 0x19bf, 0x6a06, 0x012e, 0x00de,
+	0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0x19bf, 0x6a32,
+	0x012e, 0x00de, 0x0005, 0x080c, 0x92f1, 0x7854, 0x7032, 0x7042,
+	0x7047, 0x1000, 0x00f8, 0x080c, 0x92f1, 0x7854, 0x7032, 0x7042,
+	0x7047, 0x4000, 0x00b8, 0x080c, 0x92f1, 0x7854, 0x7032, 0x7042,
+	0x7047, 0x2000, 0x0078, 0x080c, 0x92f1, 0x7854, 0x7032, 0x7042,
+	0x7047, 0x0400, 0x0038, 0x080c, 0x92f1, 0x7854, 0x7032, 0x7042,
+	0x7047, 0x0200, 0x60c3, 0x0020, 0x0804, 0x962a, 0x00e6, 0x2071,
+	0x19bf, 0x7020, 0x9005, 0x0110, 0x8001, 0x7022, 0x00ee, 0x0005,
+	0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0x19bf, 0x7614, 0x2660, 0x2678, 0x2039,
+	0x0001, 0x87ff, 0x0904, 0x9af3, 0x8cff, 0x0904, 0x9af3, 0x6020,
+	0x9086, 0x0006, 0x1904, 0x9aee, 0x88ff, 0x0138, 0x2800, 0x9c06,
+	0x1904, 0x9aee, 0x2039, 0x0000, 0x0050, 0x6010, 0x9b06, 0x1904,
+	0x9aee, 0x85ff, 0x0120, 0x6054, 0x9106, 0x1904, 0x9aee, 0x7024,
+	0x9c06, 0x15b0, 0x2069, 0x0100, 0x68c0, 0x9005, 0x1160, 0x6824,
+	0xd084, 0x0148, 0x6827, 0x0001, 0x080c, 0x835a, 0x080c, 0x9b78,
+	0x7027, 0x0000, 0x0428, 0x080c, 0x835a, 0x6820, 0xd0b4, 0x0110,
+	0x68a7, 0x95f5, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c, 0x9b78,
+	0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000,
+	0x0138, 0x2001, 0x0100, 0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x7014, 0x9c36, 0x1110, 0x660c, 0x7616, 0x7010, 0x9c36, 0x1140,
+	0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x89ff, 0x1168, 0x600f, 0x0000, 0x6014, 0x0096, 0x2048, 0x080c,
+	0xbe35, 0x0110, 0x080c, 0xd830, 0x009e, 0x080c, 0xa113, 0x080c,
+	0x9a4e, 0x88ff, 0x1190, 0x00ce, 0x0804, 0x9a69, 0x2c78, 0x600c,
+	0x2060, 0x0804, 0x9a69, 0x9006, 0x012e, 0x000e, 0x006e, 0x007e,
+	0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601b, 0x0000, 0x00ce,
+	0x98c5, 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x0096, 0x00c6,
+	0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19bf,
+	0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x9b67, 0x6020, 0x9086,
+	0x0006, 0x1904, 0x9b62, 0x87ff, 0x0128, 0x2700, 0x9c06, 0x1904,
+	0x9b62, 0x0040, 0x6010, 0x9b06, 0x15e8, 0x85ff, 0x0118, 0x6054,
+	0x9106, 0x15c0, 0x703c, 0x9c06, 0x1168, 0x0036, 0x2019, 0x0001,
+	0x080c, 0x999d, 0x7033, 0x0000, 0x9006, 0x703e, 0x7042, 0x7046,
+	0x704a, 0x003e, 0x7038, 0x9c36, 0x1110, 0x660c, 0x763a, 0x7034,
+	0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x7036, 0x0010,
+	0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e,
+	0x0008, 0x2678, 0x600f, 0x0000, 0x6014, 0x2048, 0x080c, 0xbe35,
+	0x0110, 0x080c, 0xd830, 0x080c, 0xa113, 0x87ff, 0x1198, 0x00ce,
+	0x0804, 0x9b13, 0x2c78, 0x600c, 0x2060, 0x0804, 0x9b13, 0x9006,
+	0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x009e, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x601b, 0x0000, 0x00ce, 0x97bd, 0x0001, 0x0c80,
+	0x00e6, 0x2071, 0x19bf, 0x2001, 0x1800, 0x2004, 0x9086, 0x0002,
+	0x1118, 0x7007, 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005,
+	0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x19bf, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff,
+	0x0540, 0x2200, 0x9c06, 0x1508, 0x7038, 0x9c36, 0x1110, 0x660c,
+	0x763a, 0x7034, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00,
+	0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x2c00, 0x9f06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6004, 0x9086, 0x0040,
+	0x090c, 0x8b04, 0x9085, 0x0001, 0x0020, 0x2c78, 0x600c, 0x2060,
+	0x08b0, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00ee, 0x00fe,
+	0x0005, 0x0096, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0026,
+	0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0x19bf, 0x760c, 0x2660,
+	0x2678, 0x8cff, 0x0904, 0x9c5e, 0x6010, 0x00b6, 0x2058, 0xb8a0,
+	0x00be, 0x9206, 0x1904, 0x9c59, 0x7024, 0x9c06, 0x1520, 0x2069,
+	0x0100, 0x68c0, 0x9005, 0x0904, 0x9c30, 0x080c, 0x9656, 0x68c3,
+	0x0000, 0x080c, 0x9b78, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140,
+	0x6b04, 0x9384, 0x1000, 0x0138, 0x2001, 0x0100, 0x080c, 0x2c88,
+	0x9006, 0x080c, 0x2c88, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110,
+	0x6827, 0x0001, 0x003e, 0x700c, 0x9c36, 0x1110, 0x660c, 0x760e,
+	0x7008, 0x9c36, 0x1140, 0x2c00, 0x9f36, 0x0118, 0x2f00, 0x700a,
+	0x0010, 0x700b, 0x0000, 0x660c, 0x0066, 0x2c00, 0x9f06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c, 0xc02e, 0x1180,
+	0x080c, 0x31b4, 0x080c, 0xc03f, 0x1518, 0x080c, 0xaa81, 0x0400,
+	0x080c, 0x9b78, 0x6824, 0xd084, 0x09b0, 0x6827, 0x0001, 0x0898,
+	0x080c, 0xc03f, 0x1118, 0x080c, 0xaa81, 0x0090, 0x6014, 0x2048,
+	0x080c, 0xbe35, 0x0168, 0x6020, 0x9086, 0x0003, 0x1508, 0xa867,
+	0x0103, 0xab7a, 0xa877, 0x0000, 0x080c, 0x6adc, 0x080c, 0xc022,
+	0x080c, 0xc2ab, 0x080c, 0xa113, 0x080c, 0x9a4e, 0x00ce, 0x0804,
+	0x9bd9, 0x2c78, 0x600c, 0x2060, 0x0804, 0x9bd9, 0x012e, 0x000e,
+	0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x009e, 0x0005,
+	0x6020, 0x9086, 0x0006, 0x1d20, 0x080c, 0xd830, 0x0c08, 0x00d6,
+	0x080c, 0x9179, 0x7003, 0x0200, 0x7007, 0x0014, 0x60c3, 0x0014,
+	0x20e1, 0x0001, 0x2099, 0x1961, 0x20e9, 0x0000, 0x20a1, 0x0250,
+	0x20a9, 0x0004, 0x4003, 0x7023, 0x0004, 0x7027, 0x7878, 0x080c,
+	0x962a, 0x00de, 0x0005, 0x080c, 0x9179, 0x700b, 0x0800, 0x7814,
+	0x9084, 0xff00, 0x700e, 0x7814, 0x9084, 0x00ff, 0x7022, 0x782c,
+	0x7026, 0x7858, 0x9084, 0x00ff, 0x9085, 0x0200, 0x7002, 0x7858,
+	0x9084, 0xff00, 0x8007, 0x7006, 0x60c2, 0x0804, 0x962a, 0x00b6,
+	0x00d6, 0x0016, 0x00d6, 0x2f68, 0x2009, 0x0035, 0x080c, 0xc4b1,
+	0x00de, 0x1904, 0x9d0c, 0x080c, 0x912e, 0x7003, 0x1300, 0x782c,
+	0x080c, 0x9e12, 0x2068, 0x6820, 0x9086, 0x0003, 0x0560, 0x7810,
+	0x2058, 0xbaa0, 0x080c, 0xa062, 0x11d8, 0x9286, 0x007e, 0x1128,
+	0x700b, 0x00ff, 0x700f, 0xfffe, 0x0498, 0x9286, 0x007f, 0x1128,
+	0x700b, 0x00ff, 0x700f, 0xfffd, 0x0458, 0x9284, 0xff80, 0x0180,
+	0x9286, 0x0080, 0x1128, 0x700b, 0x00ff, 0x700f, 0xfffc, 0x0400,
+	0x92d8, 0x1000, 0x2b5c, 0xb810, 0x700a, 0xb814, 0x700e, 0x00c0,
+	0x6098, 0x700e, 0x00a8, 0x080c, 0xa062, 0x1130, 0x7810, 0x2058,
+	0xb8a0, 0x9082, 0x007e, 0x0250, 0x00d6, 0x2069, 0x181e, 0x2d04,
+	0x700a, 0x8d68, 0x2d04, 0x700e, 0x00de, 0x0010, 0x6034, 0x700e,
+	0x7838, 0x7012, 0x783c, 0x7016, 0x60c3, 0x000c, 0x001e, 0x00de,
+	0x080c, 0x962a, 0x00be, 0x0005, 0x781b, 0x0001, 0x7803, 0x0006,
+	0x001e, 0x00de, 0x00be, 0x0005, 0x792c, 0x9180, 0x0008, 0x200c,
+	0x9186, 0x0006, 0x01c0, 0x9186, 0x0003, 0x0904, 0x9d87, 0x9186,
+	0x0005, 0x0904, 0x9d6f, 0x9186, 0x0004, 0x05d8, 0x9186, 0x0008,
+	0x0904, 0x9d78, 0x7807, 0x0037, 0x782f, 0x0003, 0x7817, 0x1700,
+	0x080c, 0x9def, 0x0005, 0x080c, 0x9db0, 0x00d6, 0x0026, 0x792c,
+	0x2168, 0x2009, 0x4000, 0x6800, 0x0002, 0x9d50, 0x9d5b, 0x9d52,
+	0x9d5b, 0x9d57, 0x9d50, 0x9d50, 0x9d5b, 0x9d5b, 0x9d5b, 0x9d5b,
+	0x9d50, 0x9d50, 0x9d50, 0x9d50, 0x9d50, 0x9d5b, 0x9d50, 0x9d5b,
+	0x080c, 0x0dfa, 0x6824, 0xd0e4, 0x0110, 0xd0cc, 0x0110, 0x900e,
+	0x0010, 0x2009, 0x2000, 0x682c, 0x7022, 0x6830, 0x7026, 0x0804,
+	0x9da9, 0x080c, 0x9db0, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009,
+	0x4000, 0x6a00, 0x9286, 0x0002, 0x1108, 0x900e, 0x04d0, 0x080c,
+	0x9db0, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x0488,
+	0x04b9, 0x00d6, 0x0026, 0x792c, 0x2168, 0x2009, 0x4000, 0x9286,
+	0x0005, 0x0118, 0x9286, 0x0002, 0x1108, 0x900e, 0x0410, 0x0441,
+	0x00d6, 0x0026, 0x792c, 0x2168, 0x6814, 0x6924, 0xc185, 0x6926,
+	0x0096, 0x2048, 0xa9ac, 0xa834, 0x9112, 0xa9b0, 0xa838, 0x009e,
+	0x9103, 0x7022, 0x7226, 0x792c, 0x9180, 0x0000, 0x2004, 0x908e,
+	0x0002, 0x0130, 0x908e, 0x0004, 0x0118, 0x2009, 0x4000, 0x0008,
+	0x900e, 0x712a, 0x60c3, 0x0018, 0x002e, 0x00de, 0x0804, 0x962a,
+	0x00b6, 0x0036, 0x0046, 0x0056, 0x0066, 0x080c, 0x9179, 0x9006,
+	0x7003, 0x0200, 0x7938, 0x710a, 0x793c, 0x710e, 0x7810, 0x2058,
+	0xb8a0, 0x080c, 0xa062, 0x1118, 0x9092, 0x007e, 0x0268, 0x00d6,
+	0x2069, 0x181e, 0x2d2c, 0x8d68, 0x2d34, 0x90d8, 0x1000, 0x2b5c,
+	0xbb10, 0xbc14, 0x00de, 0x0028, 0x901e, 0x6498, 0x2029, 0x0000,
+	0x6634, 0x782c, 0x9080, 0x0008, 0x2004, 0x9086, 0x0003, 0x1128,
+	0x7512, 0x7616, 0x731a, 0x741e, 0x0020, 0x7312, 0x7416, 0x751a,
+	0x761e, 0x006e, 0x005e, 0x004e, 0x003e, 0x00be, 0x0005, 0x080c,
+	0x9179, 0x7003, 0x0100, 0x782c, 0x700a, 0x7814, 0x700e, 0x700e,
+	0x60c3, 0x0008, 0x0804, 0x962a, 0x080c, 0x9125, 0x7003, 0x1400,
+	0x7838, 0x700a, 0x0079, 0x783c, 0x700e, 0x782c, 0x7012, 0x7830,
+	0x7016, 0x7834, 0x9084, 0x00ff, 0x8007, 0x701a, 0x60c3, 0x0010,
+	0x0804, 0x962a, 0x00e6, 0x2071, 0x0240, 0x0006, 0x00f6, 0x2078,
+	0x7810, 0x00b6, 0x2058, 0xb8bc, 0xd084, 0x0120, 0x7844, 0x702a,
+	0x7848, 0x702e, 0x00be, 0x00fe, 0x000e, 0x00ee, 0x0005, 0x080c,
+	0x9170, 0x7003, 0x0100, 0x782c, 0x700a, 0x7814, 0x700e, 0x60c3,
+	0x0008, 0x0804, 0x962a, 0x0021, 0x60c3, 0x0000, 0x0804, 0x962a,
+	0x00d6, 0x080c, 0x9eeb, 0xb810, 0x9085, 0x0300, 0x7002, 0xb814,
+	0x7006, 0x2069, 0x1800, 0x6878, 0x700a, 0x687c, 0x700e, 0x7013,
+	0x0819, 0x080c, 0x9618, 0x721a, 0x2f10, 0x7222, 0x7a08, 0x7226,
+	0x2071, 0x024c, 0x00de, 0x0005, 0x00a9, 0x7914, 0x712a, 0x60c3,
+	0x0000, 0x60a7, 0x9575, 0x0026, 0x080c, 0x2afe, 0x0228, 0x2011,
+	0x0101, 0x2204, 0xc0c5, 0x2012, 0x002e, 0x080c, 0x964d, 0x080c,
+	0x8351, 0x0005, 0x0036, 0x0096, 0x00d6, 0x00e6, 0x7858, 0x2048,
+	0xaa7c, 0x9296, 0x00c0, 0x9294, 0xfffd, 0xaa7e, 0xaa80, 0x9294,
+	0x0300, 0xaa82, 0xa96c, 0x9194, 0x00ff, 0xab74, 0x9384, 0x00ff,
+	0x908d, 0xc200, 0xa96e, 0x9384, 0xff00, 0x9215, 0xaa76, 0xa870,
+	0xaa78, 0xa87a, 0xaa72, 0x00d6, 0x2069, 0x0200, 0x080c, 0x9eeb,
+	0x00de, 0x20e9, 0x0000, 0x20a1, 0x0240, 0x20a9, 0x000a, 0xa860,
+	0x20e0, 0xa85c, 0x9080, 0x001b, 0x2098, 0x4003, 0x60a3, 0x0035,
+	0xaa68, 0x9294, 0x7000, 0x9286, 0x3000, 0x0110, 0x60a3, 0x0037,
+	0x00ee, 0x00de, 0x009e, 0x003e, 0x0005, 0x900e, 0x7814, 0x0096,
+	0x2048, 0xa87c, 0xd0fc, 0x01c0, 0x9084, 0x0003, 0x11a8, 0x2001,
+	0x180c, 0x2004, 0xd0bc, 0x0180, 0x7824, 0xd0cc, 0x1168, 0xd0c4,
+	0x1158, 0xa8a8, 0x9005, 0x1140, 0x2001, 0x180c, 0x200c, 0xc1d5,
+	0x2102, 0x2009, 0x198a, 0x210c, 0x009e, 0x918d, 0x0092, 0x0010,
+	0x2009, 0x0096, 0x60ab, 0x0036, 0x6116, 0x0005, 0x2009, 0x0009,
+	0x00a0, 0x2009, 0x000a, 0x0088, 0x2009, 0x000b, 0x0070, 0x2009,
+	0x000c, 0x0058, 0x2009, 0x000d, 0x0040, 0x2009, 0x000e, 0x0028,
+	0x2009, 0x000f, 0x0010, 0x2009, 0x0008, 0x6912, 0x0005, 0x00d6,
+	0x9290, 0x0018, 0x8214, 0x20e9, 0x0000, 0x2069, 0x0200, 0x6813,
+	0x0000, 0x22a8, 0x9284, 0x00e0, 0x0128, 0x20a9, 0x0020, 0x9292,
+	0x0020, 0x0008, 0x9016, 0x20a1, 0x0240, 0x9006, 0x4004, 0x82ff,
+	0x0120, 0x6810, 0x8000, 0x6812, 0x0c60, 0x00de, 0x0005, 0x00d6,
+	0x0096, 0x6014, 0x2048, 0xa878, 0x6056, 0x9006, 0xa836, 0xa83a,
+	0xa99c, 0xa946, 0xa84a, 0x6023, 0x0003, 0x6007, 0x0040, 0x6003,
+	0x0003, 0x600b, 0xffff, 0xa817, 0x0001, 0xa842, 0xa83e, 0x2900,
+	0xa85a, 0xa813, 0x1fc6, 0x080c, 0x86de, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x8ced, 0x012e, 0x009e, 0x00de, 0x0005, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x00a6, 0x0096, 0x0066, 0x0126, 0x2091, 0x8000,
+	0x2071, 0x19bf, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0904, 0x9fc2,
+	0x7024, 0x9c06, 0x1520, 0x2069, 0x0100, 0x68c0, 0x9005, 0x0904,
+	0x9f94, 0x080c, 0x9656, 0x68c3, 0x0000, 0x080c, 0x9b78, 0x7027,
+	0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0x9384, 0x1000, 0x0138,
+	0x2001, 0x0100, 0x080c, 0x2c88, 0x9006, 0x080c, 0x2c88, 0x2069,
+	0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x700c,
+	0x9c36, 0x1110, 0x660c, 0x760e, 0x7008, 0x9c36, 0x1140, 0x2c00,
+	0x9f36, 0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000, 0x660c,
+	0x0066, 0x2c00, 0x9f06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f,
+	0x0000, 0x080c, 0xc02e, 0x1180, 0x080c, 0x31b4, 0x080c, 0xc03f,
+	0x1518, 0x080c, 0xaa81, 0x0400, 0x080c, 0x9b78, 0x6824, 0xd084,
+	0x09b0, 0x6827, 0x0001, 0x0898, 0x080c, 0xc03f, 0x1118, 0x080c,
+	0xaa81, 0x0090, 0x6014, 0x2048, 0x080c, 0xbe35, 0x0168, 0x6020,
+	0x9086, 0x0003, 0x1520, 0xa867, 0x0103, 0xab7a, 0xa877, 0x0000,
+	0x080c, 0x6ae9, 0x080c, 0xc022, 0x080c, 0xc2ab, 0x080c, 0xa113,
+	0x080c, 0x9a4e, 0x00ce, 0x0804, 0x9f45, 0x2c78, 0x600c, 0x2060,
+	0x0804, 0x9f45, 0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x006e,
+	0x009e, 0x00ae, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6020,
+	0x9086, 0x0006, 0x1d08, 0x080c, 0xd830, 0x08f0, 0x00d6, 0x0156,
+	0x080c, 0x9179, 0x7a14, 0x82ff, 0x0138, 0x7003, 0x0100, 0x700b,
+	0x0003, 0x60c3, 0x0008, 0x0490, 0x7003, 0x0200, 0x7007, 0x0000,
+	0x2069, 0x1800, 0x901e, 0x6800, 0x9086, 0x0004, 0x1110, 0xc38d,
+	0x0060, 0x080c, 0x7207, 0x1110, 0xc3ad, 0x0008, 0xc3a5, 0x6ad8,
+	0xd29c, 0x1110, 0xd2ac, 0x0108, 0xc39d, 0x730e, 0x2011, 0x1848,
+	0x63f0, 0x2312, 0x20a9, 0x0006, 0x2011, 0x1840, 0x2019, 0x1841,
+	0x2071, 0x0250, 0x2376, 0x8e70, 0x2276, 0x8e70, 0x9398, 0x0002,
+	0x9290, 0x0002, 0x1f04, 0xa00a, 0x60c3, 0x0020, 0x080c, 0x962a,
+	0x015e, 0x00de, 0x0005, 0x0156, 0x080c, 0x9179, 0x7a14, 0x82ff,
+	0x0168, 0x9286, 0xffff, 0x0118, 0x9282, 0x000e, 0x1238, 0x7003,
+	0x0100, 0x700b, 0x0003, 0x60c3, 0x0008, 0x0488, 0x7003, 0x0200,
+	0x7007, 0x001c, 0x700f, 0x0001, 0x2011, 0x1995, 0x2204, 0x8007,
+	0x701a, 0x8210, 0x2204, 0x8007, 0x701e, 0x0421, 0x1120, 0xb8a0,
+	0x9082, 0x007f, 0x0248, 0x2001, 0x181e, 0x2004, 0x7022, 0x2001,
+	0x181f, 0x2004, 0x7026, 0x0030, 0x2001, 0x1817, 0x2004, 0x9084,
+	0x00ff, 0x7026, 0x20a9, 0x0004, 0x20e1, 0x0001, 0x2099, 0x1805,
+	0x20e9, 0x0000, 0x20a1, 0x0256, 0x4003, 0x60c3, 0x001c, 0x015e,
+	0x0804, 0x962a, 0x0006, 0x2001, 0x1836, 0x2004, 0xd0ac, 0x000e,
+	0x0005, 0x2011, 0x0003, 0x080c, 0x9a0f, 0x2011, 0x0002, 0x080c,
+	0x9a19, 0x080c, 0x9927, 0x0036, 0x901e, 0x080c, 0x999d, 0x003e,
+	0x0005, 0x2071, 0x188b, 0x7000, 0x9005, 0x0140, 0x2001, 0x0976,
+	0x2071, 0x1800, 0x7072, 0x7076, 0x7067, 0xffe0, 0x2071, 0x1800,
+	0x7070, 0x7052, 0x7057, 0x1cd0, 0x0005, 0x00e6, 0x0126, 0x2071,
+	0x1800, 0x2091, 0x8000, 0x7550, 0x9582, 0x0010, 0x0608, 0x7054,
+	0x2060, 0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0, 0x0018, 0x7064,
+	0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0, 0x0c98, 0x6003, 0x0008,
+	0x8529, 0x7552, 0x9ca8, 0x0018, 0x7064, 0x9502, 0x1230, 0x7556,
+	0x9085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x7057, 0x1cd0, 0x0cc0,
+	0x9006, 0x0cc0, 0x00e6, 0x2071, 0x1800, 0x7550, 0x9582, 0x0010,
+	0x0600, 0x7054, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148, 0x9ce0,
+	0x0018, 0x7064, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0, 0x0c98,
+	0x6003, 0x0008, 0x8529, 0x7552, 0x9ca8, 0x0018, 0x7064, 0x9502,
+	0x1228, 0x7556, 0x9085, 0x0001, 0x00ee, 0x0005, 0x7057, 0x1cd0,
+	0x0cc8, 0x9006, 0x0cc8, 0x9c82, 0x1cd0, 0x0a0c, 0x0dfa, 0x2001,
+	0x1819, 0x2004, 0x9c02, 0x1a0c, 0x0dfa, 0x9006, 0x6006, 0x600a,
+	0x600e, 0x6016, 0x601a, 0x6012, 0x6023, 0x0000, 0x6003, 0x0000,
+	0x601e, 0x6056, 0x605a, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036,
+	0x603a, 0x603e, 0x6042, 0x2061, 0x1800, 0x6050, 0x8000, 0x6052,
+	0x9086, 0x0001, 0x0108, 0x0005, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x8c10, 0x012e, 0x0cc0, 0x0006, 0x6000, 0x9086, 0x0000, 0x01b0,
+	0x601c, 0xd084, 0x190c, 0x19b4, 0x6017, 0x0000, 0x6023, 0x0007,
+	0x2001, 0x195e, 0x2004, 0x0006, 0x9082, 0x0051, 0x000e, 0x0208,
+	0x8004, 0x601a, 0x080c, 0xdae2, 0x6043, 0x0000, 0x000e, 0x0005,
+	0x00e6, 0x0126, 0x2071, 0x1800, 0x2091, 0x8000, 0x7550, 0x9582,
+	0x0001, 0x0608, 0x7054, 0x2060, 0x6000, 0x9086, 0x0000, 0x0148,
+	0x9ce0, 0x0018, 0x7064, 0x9c02, 0x1208, 0x0cb0, 0x2061, 0x1cd0,
+	0x0c98, 0x6003, 0x0008, 0x8529, 0x7552, 0x9ca8, 0x0018, 0x7064,
+	0x9502, 0x1230, 0x7556, 0x9085, 0x0001, 0x012e, 0x00ee, 0x0005,
+	0x7057, 0x1cd0, 0x0cc0, 0x9006, 0x0cc0, 0x6020, 0x9084, 0x000f,
+	0x0002, 0xa170, 0xa179, 0xa194, 0xa1af, 0xc55f, 0xc57c, 0xc597,
+	0xa170, 0xa179, 0xa170, 0xa1cb, 0xa170, 0xa170, 0xa170, 0xa170,
+	0x9186, 0x0013, 0x1128, 0x080c, 0x8b04, 0x080c, 0x8c10, 0x0005,
+	0x0005, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0dfa, 0x0013,
+	0x006e, 0x0005, 0xa192, 0xa8f8, 0xaac8, 0xa192, 0xab56, 0xa4ae,
+	0xa192, 0xa192, 0xa87a, 0xb0fa, 0xa192, 0xa192, 0xa192, 0xa192,
+	0xa192, 0xa192, 0x080c, 0x0dfa, 0x0066, 0x6000, 0x90b2, 0x0016,
+	0x1a0c, 0x0dfa, 0x0013, 0x006e, 0x0005, 0xa1ad, 0xb7e1, 0xa1ad,
+	0xa1ad, 0xa1ad, 0xa1ad, 0xa1ad, 0xa1ad, 0xb778, 0xb963, 0xa1ad,
+	0xb822, 0xb8a1, 0xb822, 0xb8a1, 0xa1ad, 0x080c, 0x0dfa, 0x6000,
+	0x9082, 0x0016, 0x1a0c, 0x0dfa, 0x6000, 0x0002, 0xa1c9, 0xb141,
+	0xb226, 0xb356, 0xb505, 0xa1c9, 0xa1c9, 0xa1c9, 0xb115, 0xb704,
+	0xb707, 0xa1c9, 0xa1c9, 0xa1c9, 0xa1c9, 0xb736, 0xa1c9, 0xa1c9,
+	0xa1c9, 0x080c, 0x0dfa, 0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c,
+	0x0dfa, 0x0013, 0x006e, 0x0005, 0xa1e4, 0xa1e4, 0xa227, 0xa2c6,
+	0xa35b, 0xa1e4, 0xa1e4, 0xa1e4, 0xa1e6, 0xa1e4, 0xa1e4, 0xa1e4,
+	0xa1e4, 0xa1e4, 0xa1e4, 0xa1e4, 0x080c, 0x0dfa, 0x9186, 0x004c,
+	0x0588, 0x9186, 0x0003, 0x190c, 0x0dfa, 0x0096, 0x601c, 0xc0ed,
+	0x601e, 0x6003, 0x0003, 0x6106, 0x6014, 0x2048, 0xa87c, 0x9084,
+	0xa000, 0xc0b5, 0xa87e, 0xa8ac, 0xa846, 0xa8b0, 0xa84a, 0x9006,
+	0xa836, 0xa83a, 0xa884, 0x9092, 0x199a, 0x0210, 0x2001, 0x1999,
+	0x8003, 0x8013, 0x8213, 0x9210, 0x621a, 0x009e, 0x2c10, 0x080c,
+	0x1afe, 0x080c, 0x86de, 0x0126, 0x2091, 0x8000, 0x080c, 0x8ced,
+	0x012e, 0x0005, 0x6010, 0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00,
+	0x080c, 0xa37d, 0x080c, 0xc551, 0x6003, 0x0007, 0x0005, 0x00d6,
+	0x0096, 0x00f6, 0x2079, 0x1800, 0x7a8c, 0x6014, 0x2048, 0xa87c,
+	0xd0ec, 0x1110, 0x9290, 0x0018, 0xac78, 0xc4fc, 0x0046, 0xa8e0,
+	0x9005, 0x1140, 0xa8dc, 0x921a, 0x0140, 0x0220, 0xa87b, 0x0007,
+	0x2010, 0x0028, 0xa87b, 0x0015, 0x0010, 0xa87b, 0x0000, 0x8214,
+	0xa883, 0x0000, 0xaa02, 0x0006, 0x0016, 0x0026, 0x00c6, 0x00d6,
+	0x00e6, 0x00f6, 0x2400, 0x9005, 0x1108, 0x009a, 0x2100, 0x9086,
+	0x0015, 0x1118, 0x2001, 0x0001, 0x0038, 0x2100, 0x9086, 0x0016,
+	0x0118, 0x2001, 0x0001, 0x002a, 0x94a4, 0x0007, 0x8423, 0x9405,
+	0x0002, 0xa28e, 0xa28e, 0xa289, 0xa28c, 0xa28e, 0xa286, 0xa279,
+	0xa279, 0xa279, 0xa279, 0xa279, 0xa279, 0xa279, 0xa279, 0xa279,
+	0xa279, 0x00fe, 0x00ee, 0x00de, 0x00ce, 0x002e, 0x001e, 0x000e,
+	0x004e, 0x00fe, 0x009e, 0x00de, 0x080c, 0x0dfa, 0x080c, 0xad39,
+	0x0028, 0x080c, 0xae5c, 0x0010, 0x080c, 0xaf4b, 0x00fe, 0x00ee,
+	0x00de, 0x00ce, 0x002e, 0x001e, 0x2c00, 0xa896, 0x000e, 0x080c,
+	0xa43b, 0x0530, 0xa804, 0xa80e, 0x00a6, 0x2050, 0xb100, 0x00ae,
+	0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084, 0xffc0, 0x9080,
+	0x0002, 0xaacc, 0xabd0, 0xacd4, 0xadd8, 0x2031, 0x0000, 0x2041,
+	0x12a2, 0x080c, 0xa5e6, 0x0160, 0x000e, 0x9005, 0x0120, 0x00fe,
+	0x009e, 0x00de, 0x0005, 0x00fe, 0x009e, 0x00de, 0x0804, 0xa0e3,
+	0x2001, 0x002c, 0x900e, 0x080c, 0xa4a1, 0x0c70, 0x91b6, 0x0015,
+	0x0170, 0x91b6, 0x0016, 0x0158, 0x91b2, 0x0047, 0x0a0c, 0x0dfa,
+	0x91b2, 0x0050, 0x1a0c, 0x0dfa, 0x9182, 0x0047, 0x00ca, 0x2001,
+	0x0109, 0x2004, 0xd08c, 0x0198, 0x0126, 0x2091, 0x2800, 0x0006,
+	0x0016, 0x0026, 0x080c, 0x8632, 0x002e, 0x001e, 0x000e, 0x012e,
+	0xa001, 0x6000, 0x9086, 0x0002, 0x1110, 0x0804, 0xa227, 0x0005,
+	0xa2f9, 0xa2f9, 0xa2fb, 0xa331, 0xa2f9, 0xa2f9, 0xa2f9, 0xa2f9,
+	0xa344, 0x080c, 0x0dfa, 0x00d6, 0x0016, 0x0096, 0x080c, 0x8bc0,
+	0x080c, 0x8ced, 0x6003, 0x0004, 0x6114, 0x2148, 0xa87c, 0xd0fc,
+	0x01c0, 0xa878, 0xc0fc, 0x9005, 0x1158, 0xa894, 0x9005, 0x0140,
+	0x2001, 0x0000, 0x900e, 0x080c, 0xa4a1, 0x080c, 0xa0e3, 0x00a8,
+	0x6003, 0x0002, 0xa8a4, 0xa9a8, 0x9105, 0x1178, 0xa8ae, 0xa8b2,
+	0x0c78, 0xa87f, 0x0020, 0xa88c, 0xa88a, 0xa8a4, 0xa8ae, 0xa8a8,
+	0xa8b2, 0xa8c7, 0x0000, 0xa8cb, 0x0000, 0x009e, 0x001e, 0x00de,
+	0x0005, 0x080c, 0x8bc0, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xbe37, 0x0120, 0xa87b, 0x0006, 0x080c, 0x6ae9, 0x009e, 0x00de,
+	0x080c, 0xa0e3, 0x0804, 0x8ced, 0x080c, 0x8bc0, 0x080c, 0x318b,
+	0x080c, 0xc54e, 0x00d6, 0x0096, 0x6114, 0x2148, 0x080c, 0xbe37,
+	0x0120, 0xa87b, 0x0029, 0x080c, 0x6ae9, 0x009e, 0x00de, 0x080c,
+	0xa0e3, 0x0804, 0x8ced, 0x9182, 0x0047, 0x0002, 0xa36b, 0xa36d,
+	0xa36b, 0xa36b, 0xa36b, 0xa36b, 0xa36b, 0xa36b, 0xa36b, 0xa36b,
+	0xa36b, 0xa36b, 0xa36d, 0x080c, 0x0dfa, 0x00d6, 0x0096, 0x080c,
+	0x1582, 0x6114, 0x2148, 0xa87b, 0x0000, 0xa883, 0x0000, 0x080c,
+	0x6ae9, 0x009e, 0x00de, 0x0804, 0xa0e3, 0x0026, 0x0036, 0x0056,
+	0x0066, 0x0096, 0x00a6, 0x00f6, 0x0006, 0x080c, 0x1031, 0x000e,
+	0x090c, 0x0dfa, 0xa960, 0x21e8, 0xa95c, 0x9188, 0x0019, 0x21a0,
+	0x900e, 0x20a9, 0x0020, 0x4104, 0xa87a, 0x2079, 0x1800, 0x798c,
+	0x9188, 0x0018, 0x918c, 0x0fff, 0xa972, 0xac76, 0x2950, 0x00a6,
+	0x2001, 0x0205, 0x2003, 0x0000, 0x901e, 0x2029, 0x0001, 0x9182,
+	0x0034, 0x1228, 0x2011, 0x001f, 0x080c, 0xb9e8, 0x04c0, 0x2130,
+	0x2009, 0x0034, 0x2011, 0x001f, 0x080c, 0xb9e8, 0x96b2, 0x0034,
+	0xb004, 0x904d, 0x0110, 0x080c, 0x0fe3, 0x080c, 0x1031, 0x01d0,
+	0x8528, 0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a,
+	0x003d, 0x1230, 0x2608, 0x2011, 0x001b, 0x080c, 0xb9e8, 0x00b8,
+	0x96b2, 0x003c, 0x2009, 0x003c, 0x2950, 0x2011, 0x001b, 0x080c,
+	0xb9e8, 0x0c18, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae, 0x852f,
+	0x95ad, 0x0050, 0xb566, 0xb070, 0xc0fd, 0xb072, 0x0048, 0x2001,
+	0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0050, 0xb566,
+	0x2a48, 0xa804, 0xa807, 0x0000, 0x0006, 0x080c, 0x6ae9, 0x000e,
+	0x2048, 0x9005, 0x1db0, 0x00fe, 0x00ae, 0x009e, 0x006e, 0x005e,
+	0x003e, 0x002e, 0x0005, 0x00d6, 0x00f6, 0x0096, 0x0006, 0x080c,
+	0x1031, 0x000e, 0x090c, 0x0dfa, 0xa960, 0x21e8, 0xa95c, 0x9188,
+	0x0019, 0x21a0, 0x900e, 0x20a9, 0x0020, 0x4104, 0xaa66, 0xa87a,
+	0x2079, 0x1800, 0x798c, 0x810c, 0x9188, 0x000c, 0x9182, 0x001a,
+	0x0210, 0x2009, 0x001a, 0x21a8, 0x810b, 0xa972, 0xac76, 0x2e98,
+	0xa85c, 0x9080, 0x001f, 0x20a0, 0x2001, 0x0205, 0x200c, 0x918d,
+	0x0080, 0x2102, 0x4003, 0x2003, 0x0000, 0x080c, 0x6ae9, 0x009e,
+	0x00fe, 0x00de, 0x0005, 0x0016, 0x00d6, 0x00f6, 0x0096, 0x0016,
+	0x2001, 0x0205, 0x200c, 0x918d, 0x0080, 0x2102, 0x001e, 0x2079,
+	0x0200, 0x2e98, 0xa87c, 0xd0ec, 0x0118, 0x9e80, 0x000c, 0x2098,
+	0x2021, 0x003e, 0x901e, 0x9282, 0x0020, 0x0218, 0x2011, 0x0020,
+	0x2018, 0x9486, 0x003e, 0x1170, 0x0096, 0x080c, 0x1031, 0x2900,
+	0x009e, 0x05c0, 0xa806, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x0002, 0x20a0, 0x3300, 0x908e, 0x0260, 0x0140, 0x2009, 0x0280,
+	0x9102, 0x920a, 0x0218, 0x2010, 0x2100, 0x9318, 0x2200, 0x9402,
+	0x1228, 0x2400, 0x9202, 0x2410, 0x9318, 0x9006, 0x2020, 0x22a8,
+	0xa800, 0x9200, 0xa802, 0x20e1, 0x0000, 0x4003, 0x83ff, 0x0180,
+	0x3300, 0x9086, 0x0280, 0x1130, 0x7814, 0x8000, 0x9085, 0x0080,
+	0x7816, 0x2e98, 0x2310, 0x84ff, 0x0904, 0xa450, 0x0804, 0xa452,
+	0x9085, 0x0001, 0x7817, 0x0000, 0x009e, 0x00fe, 0x00de, 0x001e,
+	0x0005, 0x00d6, 0x0036, 0x0096, 0x6314, 0x2348, 0xa87a, 0xa982,
+	0x080c, 0x6adc, 0x009e, 0x003e, 0x00de, 0x0005, 0x91b6, 0x0015,
+	0x1118, 0x080c, 0xa0e3, 0x0030, 0x91b6, 0x0016, 0x190c, 0x0dfa,
+	0x080c, 0xa0e3, 0x0005, 0x20a9, 0x000e, 0x20e1, 0x0000, 0x2e98,
+	0x6014, 0x0096, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x20a0, 0x009e,
+	0x4003, 0x0136, 0x9080, 0x001b, 0x20a0, 0x2011, 0x0006, 0x20a9,
+	0x0001, 0x3418, 0x8318, 0x23a0, 0x4003, 0x3318, 0x8318, 0x2398,
+	0x8211, 0x1db8, 0x2011, 0x0006, 0x013e, 0x20a0, 0x3318, 0x8318,
+	0x2398, 0x4003, 0x3418, 0x8318, 0x23a0, 0x8211, 0x1db8, 0x0096,
+	0x080c, 0xbe37, 0x0130, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0x009e, 0x0804, 0xa0e3, 0x0096, 0x00d6, 0x0036, 0x7330,
+	0x9386, 0x0200, 0x11a8, 0x6010, 0x00b6, 0x2058, 0xb8bf, 0x0000,
+	0x00be, 0x6014, 0x9005, 0x0130, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0xab32, 0x080c, 0xa0e3, 0x003e, 0x00de, 0x009e, 0x0005,
+	0x0011, 0x1d48, 0x0cc8, 0x0006, 0x0016, 0x080c, 0xc539, 0x0188,
+	0x6014, 0x9005, 0x1170, 0x600b, 0x0003, 0x601b, 0x0000, 0x6043,
+	0x0000, 0x2009, 0x0022, 0x080c, 0xa8d0, 0x9006, 0x001e, 0x000e,
+	0x0005, 0x9085, 0x0001, 0x0cd0, 0x0096, 0x0016, 0x20a9, 0x0014,
+	0x9e80, 0x000c, 0x20e1, 0x0000, 0x2098, 0x6014, 0x2048, 0xa860,
+	0x20e8, 0xa85c, 0x9080, 0x0002, 0x20a0, 0x4003, 0x2001, 0x0205,
+	0x2003, 0x0001, 0x2099, 0x0260, 0x20a9, 0x0016, 0x4003, 0x20a9,
+	0x000a, 0xa804, 0x2048, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0002,
+	0x20a0, 0x4003, 0x2001, 0x0205, 0x2003, 0x0002, 0x2099, 0x0260,
+	0x20a9, 0x0020, 0x4003, 0x2003, 0x0000, 0x6014, 0x2048, 0xa800,
+	0x2048, 0xa867, 0x0103, 0x080c, 0xa0e3, 0x001e, 0x009e, 0x0005,
+	0x0096, 0x0016, 0x900e, 0x7030, 0x9086, 0x0100, 0x0140, 0x7038,
+	0x9084, 0x00ff, 0x800c, 0x703c, 0x9084, 0x00ff, 0x8004, 0x9080,
+	0x0004, 0x9108, 0x810b, 0x2011, 0x0002, 0x2019, 0x000c, 0x6014,
+	0x2048, 0x080c, 0xb9e8, 0x080c, 0xbe37, 0x0140, 0x6014, 0x2048,
+	0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867, 0x0103, 0x080c, 0xa0e3,
+	0x001e, 0x009e, 0x0005, 0x0016, 0x0096, 0x7030, 0x9086, 0x0100,
+	0x1118, 0x2009, 0x0004, 0x0010, 0x7034, 0x800c, 0x810b, 0x2011,
+	0x000c, 0x2019, 0x000c, 0x6014, 0x2048, 0xa804, 0x0096, 0x9005,
+	0x0108, 0x2048, 0x080c, 0xb9e8, 0x009e, 0x080c, 0xbe37, 0x0148,
+	0xa804, 0x9005, 0x1158, 0xa807, 0x0000, 0xa864, 0xa8e2, 0xa867,
+	0x0103, 0x080c, 0xa0e3, 0x009e, 0x001e, 0x0005, 0x0086, 0x2040,
+	0xa030, 0x8007, 0x9086, 0x0100, 0x1118, 0x080c, 0xaa81, 0x00e0,
+	0xa034, 0x8007, 0x800c, 0x8806, 0x8006, 0x8007, 0x90bc, 0x003f,
+	0x9084, 0xffc0, 0x9080, 0x000c, 0xa87b, 0x0000, 0xa883, 0x0000,
+	0xa897, 0x4000, 0xaaa0, 0xab9c, 0xaca8, 0xada4, 0x2031, 0x0000,
+	0x2041, 0x1288, 0x0019, 0x0d08, 0x008e, 0x0898, 0x0096, 0x0006,
+	0x080c, 0x1031, 0x000e, 0x01b0, 0xa8ab, 0x0dcb, 0xa876, 0x000e,
+	0xa8a2, 0x0006, 0xae6a, 0x2800, 0xa89e, 0xa97a, 0xaf72, 0xaa8e,
+	0xab92, 0xac96, 0xad9a, 0x0086, 0x2940, 0x080c, 0x112e, 0x008e,
+	0x9085, 0x0001, 0x009e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x7008,
+	0x9084, 0x00ff, 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be, 0x9206,
+	0x1520, 0x700c, 0x6210, 0x00b6, 0x2258, 0xba14, 0x00be, 0x9206,
+	0x11e0, 0x6043, 0x0000, 0x2c68, 0x0016, 0x2009, 0x0035, 0x080c,
+	0xc4b1, 0x001e, 0x1158, 0x622c, 0x2268, 0x2071, 0x026c, 0x6b20,
+	0x9386, 0x0003, 0x0130, 0x9386, 0x0006, 0x0128, 0x080c, 0xa0e3,
+	0x0020, 0x0039, 0x0010, 0x080c, 0xa705, 0x002e, 0x00de, 0x00ee,
+	0x0005, 0x0096, 0x6814, 0x2048, 0x9186, 0x0015, 0x0904, 0xa6ed,
+	0x918e, 0x0016, 0x1904, 0xa703, 0x700c, 0x908c, 0xff00, 0x9186,
+	0x1700, 0x0120, 0x9186, 0x0300, 0x1904, 0xa6c7, 0x89ff, 0x1138,
+	0x6800, 0x9086, 0x000f, 0x0904, 0xa6aa, 0x0804, 0xa701, 0x6808,
+	0x9086, 0xffff, 0x1904, 0xa6ef, 0xa87c, 0x9084, 0x0060, 0x9086,
+	0x0020, 0x1128, 0xa83c, 0xa940, 0x9105, 0x1904, 0xa6ef, 0x6824,
+	0xd084, 0x1904, 0xa6ef, 0xd0b4, 0x0158, 0x0016, 0x2001, 0x195e,
+	0x200c, 0x6018, 0x9102, 0x9082, 0x0005, 0x001e, 0x1a04, 0xa6ef,
+	0x080c, 0xc022, 0x685c, 0xa882, 0xa87c, 0xc0dc, 0xc0f4, 0xc0d4,
+	0xa87e, 0x0026, 0x900e, 0x6a18, 0x2001, 0x000a, 0x080c, 0x84ff,
+	0xa884, 0x920a, 0x0208, 0x8011, 0xaa86, 0x82ff, 0x002e, 0x1138,
+	0x00c6, 0x2d60, 0x080c, 0xbb4a, 0x00ce, 0x0804, 0xa701, 0x00c6,
+	0xa868, 0xd0fc, 0x1118, 0x080c, 0x5fa7, 0x0010, 0x080c, 0x6355,
+	0x00ce, 0x1904, 0xa6ef, 0x00c6, 0x2d60, 0x080c, 0xa0e3, 0x00ce,
+	0x0804, 0xa701, 0x00c6, 0x080c, 0xa130, 0x0198, 0x6017, 0x0000,
+	0x6810, 0x6012, 0x080c, 0xc2b3, 0x6023, 0x0003, 0x6904, 0x00c6,
+	0x2d60, 0x080c, 0xa0e3, 0x00ce, 0x080c, 0xa15d, 0x00ce, 0x0804,
+	0xa701, 0x2001, 0x1960, 0x2004, 0x6842, 0x00ce, 0x04d0, 0x7008,
+	0x9086, 0x000b, 0x11c8, 0x6010, 0x00b6, 0x2058, 0xb900, 0xc1bc,
+	0xb902, 0x00be, 0x00c6, 0x2d60, 0xa87b, 0x0003, 0x080c, 0xc4f3,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x00ce, 0x00e8, 0x700c, 0x9086, 0x2a00, 0x1138,
+	0x2001, 0x1960, 0x2004, 0x6842, 0x00a0, 0x0479, 0x00a0, 0x89ff,
+	0x090c, 0x0dfa, 0x00c6, 0x00d6, 0x2d60, 0xa867, 0x0103, 0xa87b,
+	0x0003, 0x080c, 0x6904, 0x080c, 0xc022, 0x080c, 0xa113, 0x00de,
+	0x00ce, 0x080c, 0xa0e3, 0x009e, 0x0005, 0x9186, 0x0015, 0x1128,
+	0x2001, 0x1960, 0x2004, 0x6842, 0x0068, 0x918e, 0x0016, 0x1160,
+	0x00c6, 0x2d00, 0x2060, 0x080c, 0xdae2, 0x080c, 0x84a6, 0x080c,
+	0xa0e3, 0x00ce, 0x080c, 0xa0e3, 0x0005, 0x0026, 0x0036, 0x0046,
+	0x7228, 0xacb0, 0xabac, 0xd2f4, 0x0130, 0x2001, 0x1960, 0x2004,
+	0x6842, 0x0804, 0xa77f, 0x00c6, 0x2d60, 0x080c, 0xba49, 0x00ce,
+	0x6804, 0x9086, 0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003,
+	0x0001, 0x6007, 0x0050, 0x080c, 0x8679, 0x080c, 0x8c10, 0x00ce,
+	0x04f0, 0x6800, 0x9086, 0x000f, 0x01a8, 0x89ff, 0x090c, 0x0dfa,
+	0x6800, 0x9086, 0x0004, 0x1190, 0xa87c, 0xd0ac, 0x0178, 0xa843,
+	0x0fff, 0xa83f, 0x0fff, 0xa880, 0xc0fc, 0xa882, 0x2001, 0x0001,
+	0x6832, 0x0400, 0x2001, 0x0007, 0x6832, 0x00e0, 0xa87c, 0xd0b4,
+	0x1150, 0xd0ac, 0x0db8, 0x6824, 0xd0f4, 0x1d48, 0xa838, 0xa934,
+	0x9105, 0x0d80, 0x0c20, 0xd2ec, 0x1d68, 0x7024, 0x9306, 0x1118,
+	0x7020, 0x9406, 0x0d38, 0x7020, 0x683e, 0x7024, 0x683a, 0x2001,
+	0x0005, 0x6832, 0x080c, 0xc1aa, 0x080c, 0x8c10, 0x0010, 0x080c,
+	0xa0e3, 0x004e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026,
+	0x7008, 0x9084, 0x00ff, 0x6210, 0x00b6, 0x2258, 0xba10, 0x00be,
+	0x9206, 0x1904, 0xa7ea, 0x700c, 0x6210, 0x00b6, 0x2258, 0xba14,
+	0x00be, 0x9206, 0x1904, 0xa7ea, 0x6038, 0x2068, 0x6824, 0xc0dc,
+	0x6826, 0x6a20, 0x9286, 0x0007, 0x0904, 0xa7ea, 0x9286, 0x0002,
+	0x0904, 0xa7ea, 0x9286, 0x0000, 0x05e8, 0x6808, 0x633c, 0x9306,
+	0x15c8, 0x2071, 0x026c, 0x9186, 0x0015, 0x0570, 0x918e, 0x0016,
+	0x1100, 0x00c6, 0x6038, 0x2060, 0x6104, 0x9186, 0x004b, 0x01c0,
+	0x9186, 0x004c, 0x01a8, 0x9186, 0x004d, 0x0190, 0x9186, 0x004e,
+	0x0178, 0x9186, 0x0052, 0x0160, 0x6014, 0x0096, 0x2048, 0x080c,
+	0xbe37, 0x090c, 0x0dfa, 0xa87b, 0x0003, 0x009e, 0x080c, 0xc4f3,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x00ce, 0x0030, 0x6038, 0x2070, 0x2001, 0x1960,
+	0x2004, 0x7042, 0x080c, 0xa0e3, 0x002e, 0x00de, 0x00ee, 0x0005,
+	0x00b6, 0x0096, 0x00f6, 0x6014, 0x2048, 0x6010, 0x2058, 0x91b6,
+	0x0015, 0x0130, 0xba08, 0xbb0c, 0xbc00, 0xc48c, 0xbc02, 0x0460,
+	0x0096, 0x0156, 0x0036, 0x0026, 0x2b48, 0x9e90, 0x0010, 0x2019,
+	0x000a, 0x20a9, 0x0004, 0x080c, 0xb0d0, 0x002e, 0x003e, 0x015e,
+	0x009e, 0x1904, 0xa859, 0x0096, 0x0156, 0x0036, 0x0026, 0x2b48,
+	0x9e90, 0x0014, 0x2019, 0x0006, 0x20a9, 0x0004, 0x080c, 0xb0d0,
+	0x002e, 0x003e, 0x015e, 0x009e, 0x15a0, 0x7238, 0xba0a, 0x733c,
+	0xbb0e, 0xbc00, 0xc48d, 0xbc02, 0xa804, 0x9005, 0x1128, 0x00fe,
+	0x009e, 0x00be, 0x0804, 0xa4e7, 0x0096, 0x2048, 0xaa12, 0xab16,
+	0xac0a, 0x009e, 0x8006, 0x8006, 0x8007, 0x90bc, 0x003f, 0x9084,
+	0xffc0, 0x9080, 0x0002, 0x2009, 0x002b, 0xaaa0, 0xab9c, 0xaca8,
+	0xada4, 0x2031, 0x0000, 0x2041, 0x1288, 0x080c, 0xa5e6, 0x0130,
+	0x00fe, 0x009e, 0x080c, 0xa0e3, 0x00be, 0x0005, 0x080c, 0xaa81,
+	0x0cb8, 0x2b78, 0x00f6, 0x080c, 0x318b, 0x080c, 0xc54e, 0x00fe,
+	0x00c6, 0x080c, 0xa08d, 0x2f00, 0x6012, 0x6017, 0x0000, 0x6023,
+	0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x2001, 0x0007, 0x080c,
+	0x63f0, 0x080c, 0x641c, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x00ce,
+	0x0804, 0xa82c, 0x2100, 0x91b2, 0x0053, 0x1a0c, 0x0dfa, 0x91b2,
+	0x0040, 0x1a04, 0xa8e2, 0x0002, 0xa8d0, 0xa8d0, 0xa8c6, 0xa8d0,
+	0xa8d0, 0xa8d0, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8d0, 0xa8c4, 0xa8d0, 0xa8d0, 0xa8c4,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c6, 0xa8c4, 0xa8c4, 0xa8c4,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8d0, 0xa8d0,
+	0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4, 0xa8c4,
+	0xa8c4, 0xa8d0, 0xa8c4, 0xa8c4, 0x080c, 0x0dfa, 0x0066, 0x00b6,
+	0x6610, 0x2658, 0xb8bc, 0xc08c, 0xb8be, 0x00be, 0x006e, 0x0000,
+	0x6003, 0x0001, 0x6106, 0x9186, 0x0032, 0x0118, 0x080c, 0x86c1,
+	0x0010, 0x080c, 0x8679, 0x0126, 0x2091, 0x8000, 0x080c, 0x8c10,
+	0x012e, 0x0005, 0x2600, 0x0002, 0xa8f6, 0xa8f6, 0xa8f6, 0xa8d0,
+	0xa8d0, 0xa8f6, 0xa8f6, 0xa8f6, 0xa8f6, 0xa8d0, 0xa8f6, 0xa8d0,
+	0xa8f6, 0xa8d0, 0xa8f6, 0xa8f6, 0xa8f6, 0xa8f6, 0x080c, 0x0dfa,
+	0x6004, 0x90b2, 0x0053, 0x1a0c, 0x0dfa, 0x91b6, 0x0013, 0x0904,
+	0xa9ba, 0x91b6, 0x0027, 0x1904, 0xa975, 0x080c, 0x8b04, 0x6004,
+	0x080c, 0xc02e, 0x01b0, 0x080c, 0xc03f, 0x01a8, 0x908e, 0x0021,
+	0x0904, 0xa972, 0x908e, 0x0022, 0x1130, 0x080c, 0xa513, 0x0904,
+	0xa96e, 0x0804, 0xa96f, 0x908e, 0x003d, 0x0904, 0xa972, 0x0804,
+	0xa968, 0x080c, 0x31b4, 0x2001, 0x0007, 0x080c, 0x63f0, 0x6010,
+	0x00b6, 0x2058, 0xb9a0, 0x00be, 0x080c, 0xaa81, 0x9186, 0x007e,
+	0x1148, 0x2001, 0x1836, 0x2014, 0xc285, 0x080c, 0x7207, 0x1108,
+	0xc2ad, 0x2202, 0x0036, 0x0026, 0x2019, 0x0028, 0x2110, 0x080c,
+	0xdb3d, 0x002e, 0x003e, 0x0016, 0x0026, 0x0036, 0x2110, 0x2019,
+	0x0028, 0x080c, 0x8803, 0x0076, 0x903e, 0x080c, 0x86f1, 0x6010,
+	0x00b6, 0x905d, 0x0100, 0x00be, 0x2c08, 0x080c, 0xd5f6, 0x007e,
+	0x003e, 0x002e, 0x001e, 0x080c, 0xc54e, 0x0016, 0x080c, 0xc2ab,
+	0x080c, 0xa0e3, 0x001e, 0x080c, 0x3286, 0x080c, 0x8c10, 0x0030,
+	0x080c, 0xc2ab, 0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0005, 0x080c,
+	0xaa81, 0x0cb0, 0x080c, 0xaabd, 0x0c98, 0x9186, 0x0014, 0x1db0,
+	0x080c, 0x8b04, 0x6004, 0x908e, 0x0022, 0x1118, 0x080c, 0xa513,
+	0x0d68, 0x080c, 0x318b, 0x080c, 0xc54e, 0x080c, 0xc02e, 0x1190,
+	0x080c, 0x31b4, 0x6010, 0x00b6, 0x2058, 0xb9a0, 0x00be, 0x080c,
+	0xaa81, 0x9186, 0x007e, 0x1128, 0x2001, 0x1836, 0x200c, 0xc185,
+	0x2102, 0x0870, 0x080c, 0xc03f, 0x1118, 0x080c, 0xaa81, 0x0840,
+	0x6004, 0x908e, 0x0032, 0x1160, 0x00e6, 0x00f6, 0x2071, 0x189c,
+	0x2079, 0x0000, 0x080c, 0x351a, 0x00fe, 0x00ee, 0x0804, 0xa968,
+	0x6004, 0x908e, 0x0021, 0x0d48, 0x908e, 0x0022, 0x090c, 0xaa81,
+	0x0804, 0xa968, 0x90b2, 0x0040, 0x1a04, 0xaa6a, 0x2008, 0x0002,
+	0xaa02, 0xaa03, 0xaa06, 0xaa09, 0xaa0c, 0xaa0f, 0xaa00, 0xaa00,
+	0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00,
+	0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00,
+	0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa12, 0xaa1f,
+	0xaa00, 0xaa21, 0xaa1f, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00,
+	0xaa1f, 0xaa1f, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00, 0xaa00,
+	0xaa00, 0xaa00, 0xaa51, 0xaa1f, 0xaa00, 0xaa1b, 0xaa00, 0xaa00,
+	0xaa00, 0xaa1c, 0xaa00, 0xaa00, 0xaa00, 0xaa1f, 0xaa48, 0xaa00,
+	0x080c, 0x0dfa, 0x00e0, 0x2001, 0x000b, 0x0420, 0x2001, 0x0003,
+	0x0408, 0x2001, 0x0005, 0x00f0, 0x2001, 0x0001, 0x00d8, 0x2001,
+	0x0009, 0x00c0, 0x080c, 0x8b04, 0x6003, 0x0005, 0x080c, 0xc551,
+	0x080c, 0x8c10, 0x0070, 0x0018, 0x0010, 0x080c, 0x63f0, 0x0804,
+	0xaa62, 0x080c, 0x8b04, 0x080c, 0xc551, 0x6003, 0x0004, 0x080c,
+	0x8c10, 0x0005, 0x080c, 0x63f0, 0x080c, 0x8b04, 0x6003, 0x0002,
+	0x0036, 0x2019, 0x1866, 0x2304, 0x9084, 0xff00, 0x1120, 0x2001,
+	0x195e, 0x201c, 0x0040, 0x8007, 0x909a, 0x0004, 0x0ec0, 0x8003,
+	0x801b, 0x831b, 0x9318, 0x631a, 0x003e, 0x080c, 0x8c10, 0x0c08,
+	0x080c, 0x8b04, 0x080c, 0xc2ab, 0x080c, 0xa0e3, 0x080c, 0x8c10,
+	0x08c0, 0x00e6, 0x00f6, 0x2071, 0x189c, 0x2079, 0x0000, 0x080c,
+	0x351a, 0x00fe, 0x00ee, 0x080c, 0x8b04, 0x080c, 0xa0e3, 0x080c,
+	0x8c10, 0x0838, 0x080c, 0x8b04, 0x6003, 0x0002, 0x080c, 0xc551,
+	0x0804, 0x8c10, 0x2600, 0x2008, 0x0002, 0xaa7f, 0xaa7f, 0xaa7f,
+	0xaa62, 0xaa62, 0xaa7f, 0xaa7f, 0xaa7f, 0xaa7f, 0xaa62, 0xaa7f,
+	0xaa62, 0xaa7f, 0xaa62, 0xaa7f, 0xaa7f, 0xaa7f, 0xaa7f, 0x080c,
+	0x0dfa, 0x00e6, 0x0096, 0x0026, 0x0016, 0x080c, 0xbe37, 0x0568,
+	0x6014, 0x2048, 0xa864, 0x9086, 0x0139, 0x11a8, 0xa894, 0x9086,
+	0x0056, 0x1148, 0x080c, 0x5375, 0x0130, 0x2001, 0x0000, 0x900e,
+	0x2011, 0x4000, 0x0028, 0x2001, 0x0030, 0x900e, 0x2011, 0x4005,
+	0x080c, 0xc418, 0x0090, 0xa868, 0xd0fc, 0x0178, 0xa807, 0x0000,
+	0x0016, 0x6004, 0x908e, 0x0021, 0x0168, 0x908e, 0x003d, 0x0150,
+	0x001e, 0xa867, 0x0103, 0xa833, 0x0100, 0x001e, 0x002e, 0x009e,
+	0x00ee, 0x0005, 0x001e, 0x0009, 0x0cc0, 0x0096, 0x6014, 0x2048,
+	0xa800, 0x2048, 0xa867, 0x0103, 0xa823, 0x8001, 0x009e, 0x0005,
+	0x00b6, 0x6610, 0x2658, 0xb804, 0x9084, 0x00ff, 0x90b2, 0x000c,
+	0x1a0c, 0x0dfa, 0x6604, 0x96b6, 0x004d, 0x1120, 0x080c, 0xc337,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x0043, 0x1120, 0x080c, 0xc380,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x004b, 0x1120, 0x080c, 0xc3ac,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x0033, 0x1120, 0x080c, 0xc2cd,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x0028, 0x1120, 0x080c, 0xc07d,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x0029, 0x1120, 0x080c, 0xc0be,
+	0x0804, 0xab45, 0x6604, 0x96b6, 0x001f, 0x1118, 0x080c, 0xa4bb,
+	0x04e0, 0x6604, 0x96b6, 0x0000, 0x1118, 0x080c, 0xa7f0, 0x04a8,
+	0x6604, 0x96b6, 0x0022, 0x1118, 0x080c, 0xa4f4, 0x0470, 0x6604,
+	0x96b6, 0x0035, 0x1118, 0x080c, 0xa604, 0x0438, 0x6604, 0x96b6,
+	0x0039, 0x1118, 0x080c, 0xa785, 0x0400, 0x6604, 0x96b6, 0x003d,
+	0x1118, 0x080c, 0xa52c, 0x00c8, 0x6604, 0x96b6, 0x0044, 0x1118,
+	0x080c, 0xa568, 0x0090, 0x6604, 0x96b6, 0x0049, 0x1118, 0x080c,
+	0xa593, 0x0058, 0x91b6, 0x0015, 0x1110, 0x0063, 0x0030, 0x91b6,
+	0x0016, 0x1128, 0x00be, 0x0804, 0xae05, 0x00be, 0x0005, 0x080c,
+	0xa178, 0x0cd8, 0xab62, 0xab65, 0xab62, 0xaba9, 0xab62, 0xad39,
+	0xae12, 0xab62, 0xab62, 0xaddf, 0xab62, 0xadf3, 0x0096, 0x080c,
+	0x1582, 0x6014, 0x2048, 0xa800, 0x2048, 0xa867, 0x0103, 0x009e,
+	0x0804, 0xa0e3, 0xa001, 0xa001, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x708c, 0x9086, 0x0074, 0x1540, 0x080c, 0xd5c7, 0x11b0, 0x6010,
+	0x00b6, 0x2058, 0x7030, 0xd08c, 0x0128, 0xb800, 0xd0bc, 0x0110,
+	0xc0c5, 0xb802, 0x00e9, 0x00be, 0x2001, 0x0006, 0x080c, 0x63f0,
+	0x080c, 0x31b4, 0x080c, 0xa0e3, 0x0088, 0x2001, 0x000a, 0x080c,
+	0x63f0, 0x080c, 0x31b4, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c,
+	0x86c1, 0x080c, 0x8c10, 0x0010, 0x080c, 0xad24, 0x00ee, 0x0005,
+	0x00d6, 0xb800, 0xd084, 0x0158, 0x9006, 0x080c, 0x63dc, 0x2069,
+	0x185b, 0x6804, 0x0020, 0x2001, 0x0006, 0x080c, 0x641c, 0x00de,
+	0x0005, 0x00b6, 0x0096, 0x00d6, 0x2011, 0x1823, 0x2204, 0x9086,
+	0x0074, 0x1904, 0xacfb, 0x6010, 0x2058, 0xbaa0, 0x9286, 0x007e,
+	0x1120, 0x080c, 0xaf56, 0x0804, 0xac60, 0x00d6, 0x080c, 0x7207,
+	0x0198, 0x0026, 0x2011, 0x0010, 0x080c, 0x67e7, 0x002e, 0x05c8,
+	0x080c, 0x55ef, 0x1540, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0xa833, 0xdead, 0x00f8, 0x0026, 0x2011, 0x8008, 0x080c,
+	0x67e7, 0x002e, 0x0530, 0x6014, 0x2048, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0039, 0x1140, 0x2001, 0x0030, 0x900e, 0x2011, 0x4009,
+	0x080c, 0xc418, 0x0040, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867,
+	0x0103, 0xa833, 0xdead, 0x6010, 0x2058, 0xb9a0, 0x0016, 0x080c,
+	0x31b4, 0x080c, 0xa0e3, 0x001e, 0x080c, 0x3286, 0x00de, 0x0804,
+	0xacfe, 0x00de, 0x080c, 0xaf4b, 0x6010, 0x2058, 0xbaa0, 0x9286,
+	0x0080, 0x1510, 0x6014, 0x9005, 0x01a8, 0x2048, 0xa864, 0x9084,
+	0x00ff, 0x9086, 0x0039, 0x1140, 0x2001, 0x0000, 0x900e, 0x2011,
+	0x4000, 0x080c, 0xc418, 0x0030, 0xa807, 0x0000, 0xa867, 0x0103,
+	0xa833, 0x0200, 0x2001, 0x0006, 0x080c, 0x63f0, 0x080c, 0x31b4,
+	0x080c, 0xa0e3, 0x0804, 0xacfe, 0x080c, 0xad0c, 0x6014, 0x9005,
+	0x0190, 0x2048, 0xa868, 0xd0f4, 0x01e8, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0039, 0x1d08, 0x2001, 0x0000, 0x900e, 0x2011, 0x4000,
+	0x080c, 0xc418, 0x08f8, 0x080c, 0xad02, 0x0160, 0x9006, 0x080c,
+	0x63dc, 0x2001, 0x0004, 0x080c, 0x641c, 0x2001, 0x0007, 0x080c,
+	0x63f0, 0x08a0, 0x2001, 0x0004, 0x080c, 0x63f0, 0x6003, 0x0001,
+	0x6007, 0x0003, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0804, 0xacfe,
+	0xb85c, 0xd0e4, 0x01d0, 0x080c, 0xc24d, 0x080c, 0x7207, 0x0118,
+	0xd0dc, 0x1904, 0xac22, 0x2011, 0x1836, 0x2204, 0xc0ad, 0x2012,
+	0x2001, 0x0002, 0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, 0x080c,
+	0x27e2, 0x78e2, 0x00fe, 0x0804, 0xac22, 0x080c, 0xc28a, 0x2011,
+	0x1836, 0x2204, 0xc0a5, 0x2012, 0x0006, 0x080c, 0xd720, 0x000e,
+	0x1904, 0xac22, 0xc0b5, 0x2012, 0x2001, 0x0006, 0x080c, 0x63f0,
+	0x9006, 0x080c, 0x63dc, 0x00c6, 0x2001, 0x180f, 0x2004, 0xd09c,
+	0x0520, 0x00f6, 0x2079, 0x0100, 0x00e6, 0x2071, 0x1800, 0x700c,
+	0x9084, 0x00ff, 0x78e6, 0x707a, 0x7010, 0x78ea, 0x707e, 0x908c,
+	0x00ff, 0x00ee, 0x780c, 0xc0b5, 0x780e, 0x00fe, 0x080c, 0x27b7,
+	0x00f6, 0x2100, 0x900e, 0x080c, 0x276e, 0x795a, 0x00fe, 0x9186,
+	0x0081, 0x01d8, 0x2009, 0x0081, 0x00c8, 0x2009, 0x00ef, 0x00f6,
+	0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, 0x780c, 0xc0b5, 0x780e,
+	0x00fe, 0x080c, 0x27b7, 0x00f6, 0x2079, 0x1800, 0x797e, 0x2100,
+	0x900e, 0x080c, 0x276e, 0x795a, 0x00fe, 0x8108, 0x080c, 0x643f,
+	0x2b00, 0x00ce, 0x1904, 0xac22, 0x6012, 0x2009, 0x180f, 0x210c,
+	0xd19c, 0x0150, 0x2009, 0x027c, 0x210c, 0x918c, 0x00ff, 0xb912,
+	0x2009, 0x027d, 0x210c, 0xb916, 0x2001, 0x0002, 0x080c, 0x63f0,
+	0x6023, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x86c1,
+	0x080c, 0x8c10, 0x0018, 0x080c, 0xaa81, 0x0431, 0x00de, 0x009e,
+	0x00be, 0x0005, 0x2001, 0x1810, 0x2004, 0xd0a4, 0x0120, 0x2001,
+	0x185c, 0x2004, 0xd0ac, 0x0005, 0x00e6, 0x080c, 0xdb96, 0x0190,
+	0x2071, 0x0260, 0x7108, 0x720c, 0x918c, 0x00ff, 0x1118, 0x9284,
+	0xff00, 0x0140, 0x6010, 0x2058, 0xb8a0, 0x9084, 0xff80, 0x1110,
+	0xb912, 0xba16, 0x00ee, 0x0005, 0x2030, 0x2001, 0x0007, 0x080c,
+	0x63f0, 0x080c, 0x55ef, 0x1120, 0x2001, 0x0007, 0x080c, 0x641c,
+	0x080c, 0x31b4, 0x6020, 0x9086, 0x000a, 0x1108, 0x0005, 0x0804,
+	0xa0e3, 0x00b6, 0x00e6, 0x0026, 0x0016, 0x2071, 0x1800, 0x708c,
+	0x9086, 0x0014, 0x1904, 0xadd6, 0x00d6, 0x080c, 0x7207, 0x0198,
+	0x0026, 0x2011, 0x0010, 0x080c, 0x67e7, 0x002e, 0x05c8, 0x080c,
+	0x55ef, 0x1540, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867, 0x0103,
+	0xa833, 0xdead, 0x00f8, 0x0026, 0x2011, 0x8008, 0x080c, 0x67e7,
+	0x002e, 0x0530, 0x6014, 0x2048, 0xa864, 0x9084, 0x00ff, 0x9086,
+	0x0039, 0x1140, 0x2001, 0x0030, 0x900e, 0x2011, 0x4009, 0x080c,
+	0xc418, 0x0040, 0x6014, 0x2048, 0xa807, 0x0000, 0xa867, 0x0103,
+	0xa833, 0xdead, 0x6010, 0x2058, 0xb9a0, 0x0016, 0x080c, 0x31b4,
+	0x080c, 0xa0e3, 0x001e, 0x080c, 0x3286, 0x00de, 0x0804, 0xadda,
+	0x00de, 0x080c, 0x55ef, 0x1170, 0x6014, 0x9005, 0x1158, 0x0036,
+	0x0046, 0x6010, 0x2058, 0xbba0, 0x2021, 0x0006, 0x080c, 0x4cbc,
+	0x004e, 0x003e, 0x00d6, 0x6010, 0x2058, 0x080c, 0x653a, 0x080c,
+	0xab98, 0x00de, 0x080c, 0xb01c, 0x1588, 0x6010, 0x2058, 0xb890,
+	0x9005, 0x0560, 0x2001, 0x0006, 0x080c, 0x63f0, 0x0096, 0x6014,
+	0x904d, 0x01d0, 0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, 0x1140,
+	0x2001, 0x0000, 0x900e, 0x2011, 0x4000, 0x080c, 0xc418, 0x0060,
+	0xa864, 0x9084, 0x00ff, 0x9086, 0x0029, 0x0130, 0xa807, 0x0000,
+	0xa867, 0x0103, 0xa833, 0x0200, 0x009e, 0x080c, 0x31b4, 0x6020,
+	0x9086, 0x000a, 0x0138, 0x080c, 0xa0e3, 0x0020, 0x080c, 0xaa81,
+	0x080c, 0xad24, 0x001e, 0x002e, 0x00ee, 0x00be, 0x0005, 0x2011,
+	0x1823, 0x2204, 0x9086, 0x0014, 0x1160, 0x2001, 0x0002, 0x080c,
+	0x63f0, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x86c1, 0x0804,
+	0x8c10, 0x0804, 0xad24, 0x2030, 0x2011, 0x1823, 0x2204, 0x9086,
+	0x0004, 0x1148, 0x96b6, 0x000b, 0x1120, 0x2001, 0x0007, 0x080c,
+	0x63f0, 0x0804, 0xa0e3, 0x0804, 0xad24, 0x0002, 0xab62, 0xae1d,
+	0xab62, 0xae5c, 0xab62, 0xaf07, 0xae12, 0xab62, 0xab62, 0xaf1a,
+	0xab62, 0xaf2a, 0x6604, 0x9686, 0x0003, 0x0904, 0xad39, 0x96b6,
+	0x001e, 0x1110, 0x080c, 0xa0e3, 0x0005, 0x00b6, 0x00d6, 0x00c6,
+	0x080c, 0xaf3a, 0x11a0, 0x9006, 0x080c, 0x63dc, 0x080c, 0x318b,
+	0x080c, 0xc54e, 0x2001, 0x0002, 0x080c, 0x63f0, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0408, 0x2009,
+	0x026e, 0x2104, 0x9086, 0x0009, 0x1160, 0x6010, 0x2058, 0xb840,
+	0x9084, 0x00ff, 0x9005, 0x0170, 0x8001, 0xb842, 0x601b, 0x000a,
+	0x0078, 0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x1900,
+	0x1108, 0x08a0, 0x080c, 0x318b, 0x080c, 0xc54e, 0x080c, 0xad24,
+	0x00ce, 0x00de, 0x00be, 0x0005, 0x0096, 0x00b6, 0x0026, 0x9016,
+	0x080c, 0xaf48, 0x00d6, 0x2069, 0x1954, 0x2d04, 0x9005, 0x0168,
+	0x6010, 0x2058, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x2069, 0x181f,
+	0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de, 0x0088, 0x9006,
+	0x080c, 0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0804, 0xaed7,
+	0x080c, 0xbe37, 0x01b0, 0x6014, 0x2048, 0xa864, 0x2010, 0x9086,
+	0x0139, 0x1138, 0x6007, 0x0016, 0x2001, 0x0002, 0x080c, 0xc472,
+	0x00b0, 0x6014, 0x2048, 0xa864, 0xd0fc, 0x0118, 0x2001, 0x0001,
+	0x0ca8, 0x2001, 0x180e, 0x2004, 0xd0dc, 0x0148, 0x6010, 0x2058,
+	0xb840, 0x9084, 0x00ff, 0x9005, 0x1110, 0x9006, 0x0c38, 0x080c,
+	0xaa81, 0x2009, 0x026e, 0x2134, 0x96b4, 0x00ff, 0x9686, 0x0005,
+	0x0510, 0x9686, 0x000b, 0x01c8, 0x2009, 0x026f, 0x2104, 0x9084,
+	0xff00, 0x1118, 0x9686, 0x0009, 0x01b0, 0x9086, 0x1900, 0x1168,
+	0x9686, 0x0009, 0x0180, 0x2001, 0x0004, 0x080c, 0x63f0, 0x2001,
+	0x0028, 0x601a, 0x6007, 0x0052, 0x0010, 0x080c, 0xad24, 0x002e,
+	0x00be, 0x009e, 0x0005, 0x9286, 0x0139, 0x0160, 0x6014, 0x2048,
+	0x080c, 0xbe37, 0x0140, 0xa864, 0x9086, 0x0139, 0x0118, 0xa868,
+	0xd0fc, 0x0108, 0x0c50, 0x6010, 0x2058, 0xb840, 0x9084, 0x00ff,
+	0x9005, 0x0138, 0x8001, 0xb842, 0x601b, 0x000a, 0x6007, 0x0016,
+	0x08f0, 0xb8a0, 0x9086, 0x007e, 0x1138, 0x00e6, 0x2071, 0x1800,
+	0x080c, 0x5ebe, 0x00ee, 0x0010, 0x080c, 0x318b, 0x0870, 0x080c,
+	0xaf48, 0x1160, 0x2001, 0x0004, 0x080c, 0x63f0, 0x6003, 0x0001,
+	0x6007, 0x0003, 0x080c, 0x86c1, 0x0804, 0x8c10, 0x080c, 0xaa81,
+	0x0804, 0xad24, 0x0469, 0x1160, 0x2001, 0x0008, 0x080c, 0x63f0,
+	0x6003, 0x0001, 0x6007, 0x0005, 0x080c, 0x86c1, 0x0804, 0x8c10,
+	0x0804, 0xad24, 0x00e9, 0x1160, 0x2001, 0x000a, 0x080c, 0x63f0,
+	0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x86c1, 0x0804, 0x8c10,
+	0x0804, 0xad24, 0x2009, 0x026e, 0x2104, 0x9086, 0x0003, 0x1138,
+	0x2009, 0x026f, 0x2104, 0x9084, 0xff00, 0x9086, 0x2a00, 0x0005,
+	0x9085, 0x0001, 0x0005, 0x00b6, 0x00c6, 0x0016, 0x6110, 0x2158,
+	0x080c, 0x64ae, 0x001e, 0x00ce, 0x00be, 0x0005, 0x00b6, 0x00f6,
+	0x00e6, 0x00d6, 0x0036, 0x0016, 0x6010, 0x2058, 0x2009, 0x1836,
+	0x2104, 0x9085, 0x0003, 0x200a, 0x080c, 0xafee, 0x0560, 0x2009,
+	0x1836, 0x2104, 0xc0cd, 0x200a, 0x080c, 0x67bf, 0x0158, 0x9006,
+	0x2020, 0x2009, 0x002a, 0x080c, 0xd885, 0x2001, 0x180c, 0x200c,
+	0xc195, 0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x080c, 0x3156,
+	0x00e6, 0x2071, 0x1800, 0x080c, 0x2f6c, 0x00ee, 0x00c6, 0x0156,
+	0x20a9, 0x0781, 0x2009, 0x007f, 0x080c, 0x3286, 0x8108, 0x1f04,
+	0xaf8c, 0x015e, 0x00ce, 0x080c, 0xaf4b, 0x2071, 0x0260, 0x2079,
+	0x0200, 0x7817, 0x0001, 0x2001, 0x1836, 0x200c, 0xc1c5, 0x7018,
+	0xd0fc, 0x0110, 0xd0dc, 0x0118, 0x7038, 0xd0dc, 0x1108, 0xc1c4,
+	0x7817, 0x0000, 0x2001, 0x1836, 0x2102, 0x2079, 0x0100, 0x2e04,
+	0x9084, 0x00ff, 0x2069, 0x181e, 0x206a, 0x78e6, 0x0006, 0x8e70,
+	0x2e04, 0x2069, 0x181f, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010,
+	0x9084, 0xff00, 0x001e, 0x9105, 0x2009, 0x182b, 0x200a, 0x2200,
+	0x9084, 0x00ff, 0x2008, 0x080c, 0x27b7, 0x080c, 0x7207, 0x0170,
+	0x2071, 0x0260, 0x2069, 0x195a, 0x7048, 0x206a, 0x704c, 0x6806,
+	0x7050, 0x680a, 0x7054, 0x680e, 0x080c, 0xc24d, 0x0040, 0x2001,
+	0x0006, 0x080c, 0x63f0, 0x080c, 0x31b4, 0x080c, 0xa0e3, 0x001e,
+	0x003e, 0x00de, 0x00ee, 0x00fe, 0x00be, 0x0005, 0x0096, 0x0026,
+	0x0036, 0x00e6, 0x0156, 0x2019, 0x182b, 0x231c, 0x83ff, 0x01f0,
+	0x2071, 0x0260, 0x7200, 0x9294, 0x00ff, 0x7004, 0x9084, 0xff00,
+	0x9205, 0x9306, 0x1198, 0x2011, 0x0276, 0x20a9, 0x0004, 0x2b48,
+	0x2019, 0x000a, 0x080c, 0xb0d0, 0x1148, 0x2011, 0x027a, 0x20a9,
+	0x0004, 0x2019, 0x0006, 0x080c, 0xb0d0, 0x1100, 0x015e, 0x00ee,
+	0x003e, 0x002e, 0x009e, 0x0005, 0x00e6, 0x2071, 0x0260, 0x7034,
+	0x9086, 0x0014, 0x11a8, 0x7038, 0x9086, 0x0800, 0x1188, 0x703c,
+	0xd0ec, 0x0160, 0x9084, 0x0f00, 0x9086, 0x0100, 0x1138, 0x7054,
+	0xd0a4, 0x1110, 0xd0ac, 0x0110, 0x9006, 0x0010, 0x9085, 0x0001,
+	0x00ee, 0x0005, 0x00e6, 0x0096, 0x00c6, 0x0076, 0x0056, 0x0046,
+	0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2029, 0x19c8, 0x252c,
+	0x2021, 0x19ce, 0x2424, 0x2061, 0x1cd0, 0x2071, 0x1800, 0x7250,
+	0x7070, 0x9202, 0x1a04, 0xb0a8, 0x080c, 0xd8b6, 0x0904, 0xb0a1,
+	0x6720, 0x9786, 0x0007, 0x0904, 0xb0a1, 0x2500, 0x9c06, 0x0904,
+	0xb0a1, 0x2400, 0x9c06, 0x05e8, 0x3e08, 0x9186, 0x0002, 0x1148,
+	0x6010, 0x9005, 0x0130, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc,
+	0x1580, 0x00c6, 0x6000, 0x9086, 0x0004, 0x1110, 0x080c, 0x19b4,
+	0x9786, 0x000a, 0x0148, 0x080c, 0xc03f, 0x1130, 0x00ce, 0x080c,
+	0xaa81, 0x080c, 0xa113, 0x00e8, 0x6014, 0x2048, 0x080c, 0xbe37,
+	0x01a8, 0x9786, 0x0003, 0x1530, 0xa867, 0x0103, 0xa87c, 0xd0cc,
+	0x0130, 0x0096, 0xa878, 0x2048, 0x080c, 0x0fe3, 0x009e, 0xab7a,
+	0xa877, 0x0000, 0x080c, 0x6adc, 0x080c, 0xc022, 0x080c, 0xa113,
+	0x00ce, 0x9ce0, 0x0018, 0x7064, 0x9c02, 0x1210, 0x0804, 0xb04f,
+	0x012e, 0x000e, 0x002e, 0x004e, 0x005e, 0x007e, 0x00ce, 0x009e,
+	0x00ee, 0x0005, 0x9786, 0x0006, 0x1118, 0x080c, 0xd830, 0x0c30,
+	0x9786, 0x000a, 0x09e0, 0x0880, 0x220c, 0x2304, 0x9106, 0x1130,
+	0x8210, 0x8318, 0x1f04, 0xb0bc, 0x9006, 0x0005, 0x2304, 0x9102,
+	0x0218, 0x2001, 0x0001, 0x0008, 0x9006, 0x918d, 0x0001, 0x0005,
+	0x0136, 0x01c6, 0x0016, 0x8906, 0x8006, 0x8007, 0x908c, 0x003f,
+	0x21e0, 0x9084, 0xffc0, 0x9300, 0x2098, 0x3518, 0x20a9, 0x0001,
+	0x220c, 0x4002, 0x910e, 0x1140, 0x8210, 0x8319, 0x1dc8, 0x9006,
+	0x001e, 0x01ce, 0x013e, 0x0005, 0x220c, 0x9102, 0x0218, 0x2001,
+	0x0001, 0x0010, 0x2001, 0x0000, 0x918d, 0x0001, 0x001e, 0x01ce,
+	0x013e, 0x0005, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dfa, 0x080c,
+	0xc02e, 0x0120, 0x080c, 0xc03f, 0x0168, 0x0028, 0x080c, 0x31b4,
+	0x080c, 0xc03f, 0x0138, 0x080c, 0x8b04, 0x080c, 0xa0e3, 0x080c,
+	0x8c10, 0x0005, 0x080c, 0xaa81, 0x0cb0, 0x9182, 0x0054, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xb131, 0xb131, 0xb131,
+	0xb131, 0xb131, 0xb131, 0xb131, 0xb131, 0xb131, 0xb131, 0xb131,
+	0xb133, 0xb133, 0xb133, 0xb133, 0xb131, 0xb131, 0xb131, 0xb133,
+	0xb131, 0x080c, 0x0dfa, 0x600b, 0xffff, 0x6003, 0x0001, 0x6106,
+	0x080c, 0x8679, 0x0126, 0x2091, 0x8000, 0x080c, 0x8c10, 0x012e,
+	0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, 0x0040, 0x0804,
+	0xb1e8, 0x9186, 0x0027, 0x1520, 0x080c, 0x8b04, 0x080c, 0x318b,
+	0x080c, 0xc54e, 0x0096, 0x6114, 0x2148, 0x080c, 0xbe37, 0x0198,
+	0x080c, 0xc03f, 0x1118, 0x080c, 0xaa81, 0x0068, 0xa867, 0x0103,
+	0xa87b, 0x0029, 0xa877, 0x0000, 0xa97c, 0xc1c5, 0xa97e, 0x080c,
+	0x6ae9, 0x080c, 0xc022, 0x009e, 0x080c, 0xa0e3, 0x0804, 0x8c10,
+	0x9186, 0x0014, 0x1120, 0x6004, 0x9082, 0x0040, 0x04a0, 0x9186,
+	0x0046, 0x0150, 0x9186, 0x0045, 0x0138, 0x9186, 0x0053, 0x0120,
+	0x9186, 0x0048, 0x190c, 0x0dfa, 0x2001, 0x0109, 0x2004, 0xd084,
+	0x0508, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x0036,
+	0x00f6, 0x00e6, 0x00c6, 0x2079, 0x19bf, 0x2071, 0x1800, 0x2061,
+	0x0100, 0x080c, 0x8563, 0x00ce, 0x00ee, 0x00fe, 0x003e, 0x002e,
+	0x001e, 0x000e, 0x012e, 0xa001, 0x6000, 0x9086, 0x0002, 0x1110,
+	0x0804, 0xb226, 0x0005, 0x0002, 0xb1c2, 0xb1c0, 0xb1c0, 0xb1c0,
+	0xb1c0, 0xb1c0, 0xb1c0, 0xb1c0, 0xb1c0, 0xb1c0, 0xb1c0, 0xb1dd,
+	0xb1dd, 0xb1dd, 0xb1dd, 0xb1c0, 0xb1dd, 0xb1c0, 0xb1dd, 0xb1c0,
+	0x080c, 0x0dfa, 0x080c, 0x8b04, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xbe37, 0x0168, 0xa867, 0x0103, 0xa87b, 0x0006, 0xa877, 0x0000,
+	0xa880, 0xc0ec, 0xa882, 0x080c, 0x6ae9, 0x080c, 0xc022, 0x009e,
+	0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0005, 0x080c, 0x8b04, 0x080c,
+	0xc03f, 0x090c, 0xaa81, 0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0005,
+	0x0002, 0xb1ff, 0xb1fd, 0xb1fd, 0xb1fd, 0xb1fd, 0xb1fd, 0xb1fd,
+	0xb1fd, 0xb1fd, 0xb1fd, 0xb1fd, 0xb216, 0xb216, 0xb216, 0xb216,
+	0xb1fd, 0xb220, 0xb1fd, 0xb216, 0xb1fd, 0x080c, 0x0dfa, 0x0096,
+	0x080c, 0x8b04, 0x6014, 0x2048, 0x2001, 0x1960, 0x2004, 0x6042,
+	0xa97c, 0xd1ac, 0x0140, 0x6003, 0x0004, 0xa87c, 0x9085, 0x0400,
+	0xa87e, 0x009e, 0x0005, 0x6003, 0x0002, 0x0cb8, 0x080c, 0x8b04,
+	0x080c, 0xc551, 0x080c, 0xc556, 0x6003, 0x000f, 0x0804, 0x8c10,
+	0x080c, 0x8b04, 0x080c, 0xa0e3, 0x0804, 0x8c10, 0x9182, 0x0054,
+	0x1220, 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xb242, 0xb242,
+	0xb242, 0xb242, 0xb242, 0xb244, 0xb321, 0xb242, 0xb355, 0xb242,
+	0xb242, 0xb242, 0xb242, 0xb242, 0xb242, 0xb242, 0xb242, 0xb242,
+	0xb242, 0xb355, 0x080c, 0x0dfa, 0x00b6, 0x0096, 0x6114, 0x2148,
+	0x7644, 0x96b4, 0x0fff, 0x86ff, 0x1528, 0x6010, 0x2058, 0xb800,
+	0xd0bc, 0x1904, 0xb310, 0xa87b, 0x0000, 0xa867, 0x0103, 0xae76,
+	0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938, 0x9115, 0x190c, 0xb4ee,
+	0x080c, 0x6904, 0x6210, 0x2258, 0xba3c, 0x82ff, 0x0110, 0x8211,
+	0xba3e, 0x7044, 0xd0e4, 0x1904, 0xb2f4, 0x080c, 0xa0e3, 0x009e,
+	0x00be, 0x0005, 0x968c, 0x0c00, 0x0150, 0x6010, 0x2058, 0xb800,
+	0xd0bc, 0x1904, 0xb2f8, 0x7348, 0xab92, 0x734c, 0xab8e, 0x968c,
+	0x00ff, 0x9186, 0x0002, 0x0508, 0x9186, 0x0028, 0x1118, 0xa87b,
+	0x001c, 0x00e8, 0xd6dc, 0x01a0, 0xa87b, 0x0015, 0xa87c, 0xd0ac,
+	0x0170, 0xa938, 0xaa34, 0x2100, 0x9205, 0x0148, 0x7048, 0x9106,
+	0x1118, 0x704c, 0x9206, 0x0118, 0xa992, 0xaa8e, 0xc6dc, 0x0038,
+	0xd6d4, 0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b, 0x0000, 0xa867,
+	0x0103, 0xae76, 0x901e, 0xd6c4, 0x01d8, 0x9686, 0x0100, 0x1130,
+	0x7064, 0x9005, 0x1118, 0xc6c4, 0x0804, 0xb24b, 0x735c, 0xab86,
+	0x83ff, 0x0170, 0x938a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036,
+	0x2308, 0x2019, 0x0018, 0x2011, 0x0025, 0x080c, 0xb9e8, 0x003e,
+	0xd6cc, 0x0904, 0xb260, 0x7154, 0xa98a, 0x81ff, 0x0904, 0xb260,
+	0x9192, 0x0021, 0x1278, 0x8304, 0x9098, 0x0018, 0x2011, 0x0029,
+	0x080c, 0xb9e8, 0x2011, 0x0205, 0x2013, 0x0000, 0x080c, 0xc4de,
+	0x0804, 0xb260, 0xa868, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a,
+	0x0c50, 0x00a6, 0x2950, 0x080c, 0xb987, 0x00ae, 0x080c, 0xc4de,
+	0x080c, 0xb9d8, 0x0804, 0xb262, 0x080c, 0xc137, 0x0804, 0xb26f,
+	0xa87c, 0xd0ac, 0x0904, 0xb27b, 0xa880, 0xd0bc, 0x1904, 0xb27b,
+	0x7348, 0xa838, 0x9306, 0x11c8, 0x734c, 0xa834, 0x931e, 0x0904,
+	0xb27b, 0xd6d4, 0x0190, 0xab38, 0x9305, 0x0904, 0xb27b, 0x0068,
+	0xa87c, 0xd0ac, 0x0904, 0xb253, 0xa838, 0xa934, 0x9105, 0x0904,
+	0xb253, 0xa880, 0xd0bc, 0x1904, 0xb253, 0x080c, 0xc171, 0x0804,
+	0xb26f, 0x0096, 0x00f6, 0x6003, 0x0003, 0x6007, 0x0043, 0x2079,
+	0x026c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2048, 0xa87c,
+	0xd0ac, 0x0140, 0x6003, 0x0002, 0x00fe, 0x009e, 0x0005, 0x2130,
+	0x2228, 0x0058, 0x2400, 0xa9ac, 0x910a, 0x2300, 0xaab0, 0x9213,
+	0x2600, 0x9102, 0x2500, 0x9203, 0x0e90, 0xac36, 0xab3a, 0xae46,
+	0xad4a, 0x00fe, 0x6043, 0x0000, 0x2c10, 0x080c, 0x1afe, 0x080c,
+	0x86de, 0x080c, 0x8ced, 0x009e, 0x0005, 0x0005, 0x9182, 0x0054,
+	0x1220, 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xb372, 0xb372,
+	0xb372, 0xb372, 0xb372, 0xb374, 0xb40a, 0xb372, 0xb372, 0xb421,
+	0xb4b1, 0xb372, 0xb372, 0xb372, 0xb372, 0xb4c6, 0xb372, 0xb372,
+	0xb372, 0xb372, 0x080c, 0x0dfa, 0x0076, 0x00a6, 0x00e6, 0x0096,
+	0x2071, 0x0260, 0x6114, 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff,
+	0xb77c, 0xc7e5, 0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff,
+	0x0110, 0x8211, 0xba3e, 0x00be, 0x86ff, 0x0904, 0xb405, 0x9694,
+	0xff00, 0x9284, 0x0c00, 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e,
+	0x9284, 0x0300, 0x0904, 0xb405, 0x080c, 0x1031, 0x090c, 0x0dfa,
+	0x2900, 0xb07a, 0xb77c, 0xc7cd, 0xb77e, 0xa867, 0x0103, 0xb068,
+	0xa86a, 0xb06c, 0xa86e, 0xb070, 0xa872, 0xae76, 0x968c, 0x0c00,
+	0x0120, 0x7348, 0xab92, 0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186,
+	0x0002, 0x0180, 0x9186, 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060,
+	0xd6dc, 0x0118, 0xa87b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b,
+	0x0007, 0x0010, 0xa87b, 0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084,
+	0xa886, 0x901e, 0xd6c4, 0x0190, 0x735c, 0xab86, 0x83ff, 0x0170,
+	0x938a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019,
+	0x0018, 0x2011, 0x0025, 0x080c, 0xb9e8, 0x003e, 0xd6cc, 0x01e8,
+	0x7154, 0xa98a, 0x81ff, 0x01c8, 0x9192, 0x0021, 0x1260, 0x8304,
+	0x9098, 0x0018, 0x2011, 0x0029, 0x080c, 0xb9e8, 0x2011, 0x0205,
+	0x2013, 0x0000, 0x0050, 0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020,
+	0xa98a, 0x0c68, 0x2950, 0x080c, 0xb987, 0x009e, 0x00ee, 0x00ae,
+	0x007e, 0x0005, 0x00f6, 0x00a6, 0x6003, 0x0003, 0x2079, 0x026c,
+	0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6014, 0x2050, 0xb436, 0xb33a,
+	0xb646, 0xb54a, 0x00ae, 0x00fe, 0x2c10, 0x080c, 0x1afe, 0x0804,
+	0x9623, 0x6003, 0x0002, 0x6004, 0x9086, 0x0040, 0x11c8, 0x0096,
+	0x6014, 0x2048, 0xa87c, 0xd0ac, 0x0160, 0x601c, 0xd084, 0x1130,
+	0x00f6, 0x2c00, 0x2078, 0x080c, 0x16db, 0x00fe, 0x6003, 0x0004,
+	0x0010, 0x6003, 0x0002, 0x009e, 0x080c, 0x8b04, 0x080c, 0x8c10,
+	0x0096, 0x2001, 0x1960, 0x2004, 0x6042, 0x080c, 0x8bc0, 0x080c,
+	0x8ced, 0x6114, 0x2148, 0xa97c, 0xd1e4, 0x0904, 0xb4ac, 0xd1cc,
+	0x05c8, 0xa978, 0xa868, 0xd0fc, 0x0540, 0x0016, 0xa87c, 0x0006,
+	0xa880, 0x0006, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0,
+	0x810e, 0x810e, 0x810f, 0x9184, 0x003f, 0x20e0, 0x9184, 0xffc0,
+	0x9080, 0x0019, 0x2098, 0x0156, 0x20a9, 0x0020, 0x4003, 0x015e,
+	0x000e, 0xa882, 0x000e, 0xc0cc, 0xa87e, 0x001e, 0xa874, 0x0006,
+	0x2148, 0x080c, 0x0fe3, 0x001e, 0x0458, 0x0016, 0x080c, 0x0fe3,
+	0x009e, 0xa87c, 0xc0cc, 0xa87e, 0xa974, 0x0016, 0x080c, 0xb9d8,
+	0x001e, 0x00f0, 0xa867, 0x0103, 0xa974, 0x9184, 0x00ff, 0x90b6,
+	0x0002, 0x0180, 0x9086, 0x0028, 0x1118, 0xa87b, 0x001c, 0x0060,
+	0xd1dc, 0x0118, 0xa87b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0xa87b,
+	0x0007, 0x0010, 0xa87b, 0x0000, 0x0016, 0x080c, 0x6904, 0x001e,
+	0xd1e4, 0x1120, 0x080c, 0xa0e3, 0x009e, 0x0005, 0x080c, 0xc137,
+	0x0cd8, 0x6004, 0x9086, 0x0040, 0x1120, 0x080c, 0x8b04, 0x080c,
+	0x8c10, 0x2019, 0x0001, 0x080c, 0x999d, 0x6003, 0x0002, 0x080c,
+	0xc556, 0x080c, 0x8bc0, 0x080c, 0x8ced, 0x0005, 0x6004, 0x9086,
+	0x0040, 0x1120, 0x080c, 0x8b04, 0x080c, 0x8c10, 0x2019, 0x0001,
+	0x080c, 0x999d, 0x080c, 0x8bc0, 0x080c, 0x318b, 0x080c, 0xc54e,
+	0x0096, 0x6114, 0x2148, 0x080c, 0xbe37, 0x0150, 0xa867, 0x0103,
+	0xa87b, 0x0029, 0xa877, 0x0000, 0x080c, 0x6ae9, 0x080c, 0xc022,
+	0x009e, 0x080c, 0xa0e3, 0x080c, 0x8ced, 0x0005, 0xa87b, 0x0015,
+	0xd1fc, 0x0180, 0xa87b, 0x0007, 0x8002, 0x8000, 0x810a, 0x9189,
+	0x0000, 0x0006, 0x0016, 0x2009, 0x1a51, 0x2104, 0x8000, 0x200a,
+	0x001e, 0x000e, 0xa992, 0xa88e, 0x0005, 0x9182, 0x0054, 0x1220,
+	0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xb521, 0xb521, 0xb521,
+	0xb521, 0xb521, 0xb523, 0xb521, 0xb521, 0xb5c9, 0xb521, 0xb521,
+	0xb521, 0xb521, 0xb521, 0xb521, 0xb521, 0xb521, 0xb521, 0xb521,
+	0xb6fb, 0x080c, 0x0dfa, 0x0076, 0x00a6, 0x00e6, 0x0096, 0x2071,
+	0x0260, 0x6114, 0x2150, 0x7644, 0xb676, 0x96b4, 0x0fff, 0xb77c,
+	0xc7e5, 0xb77e, 0x6210, 0x00b6, 0x2258, 0xba3c, 0x82ff, 0x0110,
+	0x8211, 0xba3e, 0x00be, 0x86ff, 0x0904, 0xb5c2, 0x9694, 0xff00,
+	0x9284, 0x0c00, 0x0120, 0x7048, 0xb092, 0x704c, 0xb08e, 0x9284,
+	0x0300, 0x0904, 0xb5c2, 0x9686, 0x0100, 0x1130, 0x7064, 0x9005,
+	0x1118, 0xc6c4, 0xb676, 0x0c38, 0x080c, 0x1031, 0x090c, 0x0dfa,
+	0x2900, 0xb07a, 0xb77c, 0x97bd, 0x0200, 0xb77e, 0xa867, 0x0103,
+	0xb068, 0xa86a, 0xb06c, 0xa86e, 0xb070, 0xa872, 0x7044, 0x9084,
+	0xf000, 0x9635, 0xae76, 0x968c, 0x0c00, 0x0120, 0x7348, 0xab92,
+	0x734c, 0xab8e, 0x968c, 0x00ff, 0x9186, 0x0002, 0x0180, 0x9186,
+	0x0028, 0x1118, 0xa87b, 0x001c, 0x0060, 0xd6dc, 0x0118, 0xa87b,
+	0x0015, 0x0038, 0xd6d4, 0x0118, 0xa87b, 0x0007, 0x0010, 0xa87b,
+	0x0000, 0xaf7e, 0xb080, 0xa882, 0xb084, 0xa886, 0x901e, 0xd6c4,
+	0x0190, 0x735c, 0xab86, 0x83ff, 0x0170, 0x938a, 0x0009, 0x0210,
+	0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0x0018, 0x2011, 0x0025,
+	0x080c, 0xb9e8, 0x003e, 0xd6cc, 0x01e8, 0x7154, 0xa98a, 0x81ff,
+	0x01c8, 0x9192, 0x0021, 0x1260, 0x8304, 0x9098, 0x0018, 0x2011,
+	0x0029, 0x080c, 0xb9e8, 0x2011, 0x0205, 0x2013, 0x0000, 0x0050,
+	0xb068, 0xd0fc, 0x0120, 0x2009, 0x0020, 0xa98a, 0x0c68, 0x2950,
+	0x080c, 0xb987, 0x080c, 0x1982, 0x009e, 0x00ee, 0x00ae, 0x007e,
+	0x0005, 0x2001, 0x1960, 0x2004, 0x6042, 0x0096, 0x6114, 0x2148,
+	0xa83c, 0xa940, 0x9105, 0x1118, 0xa87c, 0xc0dc, 0xa87e, 0x6003,
+	0x0002, 0xa97c, 0xd1e4, 0x0904, 0xb6f6, 0x6043, 0x0000, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1500, 0xd1cc, 0x0904,
+	0xb6c5, 0xa978, 0xa868, 0xd0fc, 0x0904, 0xb686, 0x0016, 0xa87c,
+	0x0006, 0xa880, 0x0006, 0x00a6, 0x2150, 0xb174, 0x9184, 0x00ff,
+	0x90b6, 0x0002, 0x0904, 0xb653, 0x9086, 0x0028, 0x1904, 0xb63f,
+	0xa87b, 0x001c, 0xb07b, 0x001c, 0x0804, 0xb65b, 0x6024, 0xd0f4,
+	0x11d0, 0xa838, 0xaa34, 0x9205, 0x09c8, 0xa838, 0xaa90, 0x9206,
+	0x1120, 0xa88c, 0xaa34, 0x9206, 0x0988, 0x6024, 0xd0d4, 0x1148,
+	0xa9ac, 0xa834, 0x9102, 0x603a, 0xa9b0, 0xa838, 0x9103, 0x603e,
+	0x6024, 0xc0f5, 0x6026, 0x6010, 0x00b6, 0x2058, 0xb83c, 0x8000,
+	0xb83e, 0x00be, 0x9006, 0xa876, 0xa892, 0xa88e, 0xa87c, 0xc0e4,
+	0xa87e, 0xd0cc, 0x0140, 0xc0cc, 0xa87e, 0x0096, 0xa878, 0x2048,
+	0x080c, 0x0fe3, 0x009e, 0x080c, 0xc171, 0x0804, 0xb6f6, 0xd1dc,
+	0x0158, 0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xc401, 0x0118,
+	0xb174, 0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007,
+	0xb07b, 0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938,
+	0x9115, 0x190c, 0xb4ee, 0xa87c, 0xb07e, 0xa890, 0xb092, 0xa88c,
+	0xb08e, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0019, 0x20a0, 0x20a9,
+	0x0020, 0x8a06, 0x8006, 0x8007, 0x9094, 0x003f, 0x22e0, 0x9084,
+	0xffc0, 0x9080, 0x0019, 0x2098, 0x4003, 0x00ae, 0x000e, 0xa882,
+	0x000e, 0xc0cc, 0xa87e, 0x080c, 0xc4de, 0x001e, 0xa874, 0x0006,
+	0x2148, 0x080c, 0x0fe3, 0x001e, 0x0804, 0xb6f2, 0x0016, 0x00a6,
+	0x2150, 0xb174, 0x9184, 0x00ff, 0x90b6, 0x0002, 0x01e0, 0x9086,
+	0x0028, 0x1128, 0xa87b, 0x001c, 0xb07b, 0x001c, 0x00e0, 0xd1dc,
+	0x0158, 0xa87b, 0x0015, 0xb07b, 0x0015, 0x080c, 0xc401, 0x0118,
+	0xb174, 0xc1dc, 0xb176, 0x0078, 0xd1d4, 0x0128, 0xa87b, 0x0007,
+	0xb07b, 0x0007, 0x0040, 0xa87c, 0xd0ac, 0x0128, 0xa834, 0xa938,
+	0x9115, 0x190c, 0xb4ee, 0xa890, 0xb092, 0xa88c, 0xb08e, 0xa87c,
+	0xb07e, 0x00ae, 0x080c, 0x0fe3, 0x009e, 0x080c, 0xc4de, 0xa974,
+	0x0016, 0x080c, 0xb9d8, 0x001e, 0x0468, 0xa867, 0x0103, 0xa974,
+	0x9184, 0x00ff, 0x90b6, 0x0002, 0x01b0, 0x9086, 0x0028, 0x1118,
+	0xa87b, 0x001c, 0x00d0, 0xd1dc, 0x0148, 0xa87b, 0x0015, 0x080c,
+	0xc401, 0x0118, 0xa974, 0xc1dc, 0xa976, 0x0078, 0xd1d4, 0x0118,
+	0xa87b, 0x0007, 0x0050, 0xa87b, 0x0000, 0xa87c, 0xd0ac, 0x0128,
+	0xa834, 0xa938, 0x9115, 0x190c, 0xb4ee, 0xa974, 0x0016, 0x080c,
+	0x6904, 0x001e, 0xd1e4, 0x1120, 0x080c, 0xa0e3, 0x009e, 0x0005,
+	0x080c, 0xc137, 0x0cd8, 0x6114, 0x0096, 0x2148, 0xa97c, 0xd1e4,
+	0x190c, 0x19a0, 0x009e, 0x0005, 0x080c, 0x8b04, 0x0010, 0x080c,
+	0x8bc0, 0x080c, 0xbe37, 0x01f0, 0x0096, 0x6114, 0x2148, 0x080c,
+	0xc03f, 0x1118, 0x080c, 0xaa81, 0x00a0, 0xa867, 0x0103, 0x2009,
+	0x180c, 0x210c, 0xd18c, 0x11b8, 0xd184, 0x1190, 0x6108, 0xa97a,
+	0x918e, 0x0029, 0x1110, 0x080c, 0xdb2e, 0xa877, 0x0000, 0x080c,
+	0x6ae9, 0x009e, 0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0804, 0x8ced,
+	0xa87b, 0x0004, 0x0c90, 0xa87b, 0x0004, 0x0c78, 0x9182, 0x0054,
+	0x1220, 0x9182, 0x0040, 0x0208, 0x000a, 0x0005, 0xb752, 0xb752,
+	0xb752, 0xb752, 0xb752, 0xb754, 0xb752, 0xb752, 0xb752, 0xb752,
+	0xb752, 0xb752, 0xb752, 0xb752, 0xb752, 0xb752, 0xb752, 0xb752,
+	0xb752, 0xb752, 0x080c, 0x0dfa, 0x080c, 0x55e3, 0x01f8, 0x6014,
+	0x7144, 0x918c, 0x0fff, 0x9016, 0xd1c4, 0x0118, 0x7264, 0x9294,
+	0x00ff, 0x0096, 0x904d, 0x0188, 0xa87b, 0x0000, 0xa864, 0x9086,
+	0x0139, 0x0128, 0xa867, 0x0103, 0xa976, 0xaa96, 0x0030, 0xa897,
+	0x4000, 0xa99a, 0xaa9e, 0x080c, 0x6ae9, 0x009e, 0x0804, 0xa0e3,
+	0x9182, 0x0085, 0x0002, 0xb78a, 0xb788, 0xb788, 0xb796, 0xb788,
+	0xb788, 0xb788, 0xb788, 0xb788, 0xb788, 0xb788, 0xb788, 0xb788,
+	0x080c, 0x0dfa, 0x6003, 0x0001, 0x6106, 0x080c, 0x8679, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x8c10, 0x012e, 0x0005, 0x0026, 0x0056,
+	0x00d6, 0x00e6, 0x2071, 0x0260, 0x7224, 0x6216, 0x7220, 0x080c,
+	0xbe25, 0x01f8, 0x2268, 0x6800, 0x9086, 0x0000, 0x01d0, 0x6010,
+	0x6d10, 0x952e, 0x11b0, 0x00c6, 0x2d60, 0x00d6, 0x080c, 0xba49,
+	0x00de, 0x00ce, 0x0158, 0x702c, 0xd084, 0x1118, 0x080c, 0xba13,
+	0x0010, 0x6803, 0x0002, 0x6007, 0x0086, 0x0028, 0x080c, 0xba35,
+	0x0d90, 0x6007, 0x0087, 0x6003, 0x0001, 0x080c, 0x8679, 0x080c,
+	0x8c10, 0x7220, 0x080c, 0xbe25, 0x0178, 0x6810, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0bc, 0x0140, 0x6824, 0xd0ec, 0x0128, 0x00c6,
+	0x2d60, 0x080c, 0xc171, 0x00ce, 0x00ee, 0x00de, 0x005e, 0x002e,
+	0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a, 0x0085, 0x0a0c,
+	0x0dfa, 0x908a, 0x0092, 0x1a0c, 0x0dfa, 0x9082, 0x0085, 0x00e2,
+	0x9186, 0x0027, 0x0120, 0x9186, 0x0014, 0x190c, 0x0dfa, 0x080c,
+	0x8b04, 0x0096, 0x6014, 0x2048, 0x080c, 0xbe37, 0x0140, 0xa867,
+	0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c, 0x6ae9, 0x009e,
+	0x080c, 0xa113, 0x0804, 0x8c10, 0xb819, 0xb81b, 0xb81b, 0xb819,
+	0xb819, 0xb819, 0xb819, 0xb819, 0xb819, 0xb819, 0xb819, 0xb819,
+	0xb819, 0x080c, 0x0dfa, 0x080c, 0x8b04, 0x080c, 0xa113, 0x080c,
+	0x8c10, 0x0005, 0x9186, 0x0013, 0x1128, 0x6004, 0x9082, 0x0085,
+	0x2008, 0x04b8, 0x9186, 0x0027, 0x11f8, 0x080c, 0x8b04, 0x080c,
+	0x318b, 0x080c, 0xc54e, 0x0096, 0x6014, 0x2048, 0x080c, 0xbe37,
+	0x0150, 0xa867, 0x0103, 0xa877, 0x0000, 0xa87b, 0x0029, 0x080c,
+	0x6ae9, 0x080c, 0xc022, 0x009e, 0x080c, 0xa0e3, 0x080c, 0x8c10,
+	0x0005, 0x080c, 0xa178, 0x0ce0, 0x9186, 0x0014, 0x1dd0, 0x080c,
+	0x8b04, 0x0096, 0x6014, 0x2048, 0x080c, 0xbe37, 0x0d60, 0xa867,
+	0x0103, 0xa877, 0x0000, 0xa87b, 0x0006, 0xa880, 0xc0ec, 0xa882,
+	0x08f0, 0x0002, 0xb871, 0xb86f, 0xb86f, 0xb86f, 0xb86f, 0xb86f,
+	0xb889, 0xb86f, 0xb86f, 0xb86f, 0xb86f, 0xb86f, 0xb86f, 0x080c,
+	0x0dfa, 0x080c, 0x8b04, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186,
+	0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x195e, 0x0010,
+	0x2001, 0x195f, 0x2004, 0x601a, 0x6003, 0x000c, 0x080c, 0x8c10,
+	0x0005, 0x080c, 0x8b04, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186,
+	0x0039, 0x0118, 0x9186, 0x0035, 0x1118, 0x2001, 0x195e, 0x0010,
+	0x2001, 0x195f, 0x2004, 0x601a, 0x6003, 0x000e, 0x080c, 0x8c10,
+	0x0005, 0x9182, 0x0092, 0x1220, 0x9182, 0x0085, 0x0208, 0x0012,
+	0x0804, 0xa178, 0xb8b7, 0xb8b7, 0xb8b7, 0xb8b7, 0xb8b9, 0xb906,
+	0xb8b7, 0xb8b7, 0xb8b7, 0xb8b7, 0xb8b7, 0xb8b7, 0xb8b7, 0x080c,
+	0x0dfa, 0x0096, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc,
+	0x0168, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118,
+	0x9186, 0x0035, 0x1118, 0x009e, 0x0804, 0xb91a, 0x080c, 0xbe37,
+	0x1118, 0x080c, 0xc022, 0x0068, 0x6014, 0x2048, 0xa87c, 0xd0e4,
+	0x1110, 0x080c, 0xc022, 0xa867, 0x0103, 0x080c, 0xc519, 0x080c,
+	0x6ae9, 0x00d6, 0x2c68, 0x080c, 0xa08d, 0x01d0, 0x6003, 0x0001,
+	0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0x026e, 0x210c, 0x613a,
+	0x2009, 0x026f, 0x210c, 0x613e, 0x6910, 0x6112, 0x080c, 0xc2b3,
+	0x6954, 0x6156, 0x6023, 0x0001, 0x080c, 0x8679, 0x080c, 0x8c10,
+	0x2d60, 0x00de, 0x080c, 0xa0e3, 0x009e, 0x0005, 0x6010, 0x00b6,
+	0x2058, 0xb800, 0x00be, 0xd0bc, 0x05a0, 0x6034, 0x908c, 0xff00,
+	0x810f, 0x9186, 0x0035, 0x0130, 0x9186, 0x001e, 0x0118, 0x9186,
+	0x0039, 0x1538, 0x00d6, 0x2c68, 0x080c, 0xc4b1, 0x11f0, 0x080c,
+	0xa08d, 0x01d8, 0x6106, 0x6003, 0x0001, 0x6023, 0x0001, 0x6910,
+	0x6112, 0x692c, 0x612e, 0x6930, 0x6132, 0x6934, 0x918c, 0x00ff,
+	0x6136, 0x6938, 0x613a, 0x693c, 0x613e, 0x6954, 0x6156, 0x080c,
+	0xc2b3, 0x080c, 0x8679, 0x080c, 0x8c10, 0x2d60, 0x00de, 0x0804,
+	0xa0e3, 0x0096, 0x6014, 0x2048, 0x080c, 0xbe37, 0x01c8, 0xa867,
+	0x0103, 0xa880, 0xd0b4, 0x0128, 0xc0ec, 0xa882, 0xa87b, 0x0006,
+	0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020, 0xa87b, 0x0005,
+	0x080c, 0xc133, 0xa877, 0x0000, 0x080c, 0x6ae9, 0x080c, 0xc022,
+	0x009e, 0x0804, 0xa0e3, 0x0016, 0x0096, 0x6014, 0x2048, 0x080c,
+	0xbe37, 0x0140, 0xa867, 0x0103, 0xa87b, 0x0028, 0xa877, 0x0000,
+	0x080c, 0x6ae9, 0x009e, 0x001e, 0x9186, 0x0013, 0x0148, 0x9186,
+	0x0014, 0x0130, 0x9186, 0x0027, 0x0118, 0x080c, 0xa178, 0x0030,
+	0x080c, 0x8b04, 0x080c, 0xa113, 0x080c, 0x8c10, 0x0005, 0x0056,
+	0x0066, 0x0096, 0x00a6, 0x2029, 0x0001, 0x9182, 0x0101, 0x1208,
+	0x0010, 0x2009, 0x0100, 0x2130, 0x8304, 0x9098, 0x0018, 0x2009,
+	0x0020, 0x2011, 0x0029, 0x080c, 0xb9e8, 0x96b2, 0x0020, 0xb004,
+	0x904d, 0x0110, 0x080c, 0x0fe3, 0x080c, 0x1031, 0x0520, 0x8528,
+	0xa867, 0x0110, 0xa86b, 0x0000, 0x2920, 0xb406, 0x968a, 0x003d,
+	0x1228, 0x2608, 0x2011, 0x001b, 0x0499, 0x00a8, 0x96b2, 0x003c,
+	0x2009, 0x003c, 0x2950, 0x2011, 0x001b, 0x0451, 0x0c28, 0x2001,
+	0x0205, 0x2003, 0x0000, 0x00ae, 0x852f, 0x95ad, 0x0003, 0xb566,
+	0x95ac, 0x0000, 0x0048, 0x2001, 0x0205, 0x2003, 0x0000, 0x00ae,
+	0x852f, 0x95ad, 0x0003, 0xb566, 0x009e, 0x006e, 0x005e, 0x0005,
+	0x00a6, 0x89ff, 0x0158, 0xa804, 0x9055, 0x0130, 0xa807, 0x0000,
+	0x080c, 0x6ae9, 0x2a48, 0x0cb8, 0x080c, 0x6ae9, 0x00ae, 0x0005,
+	0x00f6, 0x2079, 0x0200, 0x7814, 0x9085, 0x0080, 0x7816, 0xd184,
+	0x0108, 0x8108, 0x810c, 0x20a9, 0x0001, 0xa860, 0x20e8, 0xa85c,
+	0x9200, 0x20a0, 0x20e1, 0x0000, 0x2300, 0x9e00, 0x2098, 0x4003,
+	0x8318, 0x9386, 0x0020, 0x1148, 0x2018, 0x2300, 0x9e00, 0x2098,
+	0x7814, 0x8000, 0x9085, 0x0080, 0x7816, 0x8109, 0x1d80, 0x7817,
+	0x0000, 0x00fe, 0x0005, 0x6920, 0x9186, 0x0003, 0x0118, 0x9186,
+	0x0002, 0x11d0, 0x00c6, 0x00d6, 0x00e6, 0x2d60, 0x0096, 0x6014,
+	0x2048, 0x080c, 0xbe37, 0x0150, 0x2001, 0x0006, 0xa980, 0xc1d5,
+	0x080c, 0x6d17, 0x080c, 0x6adc, 0x080c, 0xc022, 0x009e, 0x080c,
+	0xa113, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x702c, 0xd084,
+	0x1170, 0x6008, 0x2060, 0x6020, 0x9086, 0x0002, 0x1140, 0x6104,
+	0x9186, 0x0085, 0x0118, 0x9186, 0x008b, 0x1108, 0x9006, 0x00ce,
+	0x0005, 0x0066, 0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x6020,
+	0x9084, 0x000f, 0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x0066, 0x2031, 0x0000, 0x6020, 0x9084, 0x000f, 0x001b,
+	0x006e, 0x012e, 0x0005, 0xba84, 0xba84, 0xba7f, 0xbaa6, 0xba72,
+	0xba7f, 0xbaa6, 0xba7f, 0xba72, 0xba72, 0xba7f, 0xba7f, 0xba7f,
+	0xba72, 0xba72, 0x080c, 0x0dfa, 0x0036, 0x2019, 0x0010, 0x080c,
+	0xd440, 0x6023, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x9006,
+	0x0005, 0x9085, 0x0001, 0x0005, 0x0096, 0x86ff, 0x11d8, 0x6014,
+	0x2048, 0x080c, 0xbe37, 0x01c0, 0xa864, 0x9086, 0x0139, 0x1128,
+	0xa87b, 0x0005, 0xa883, 0x0000, 0x0028, 0x900e, 0x2001, 0x0005,
+	0x080c, 0x6d17, 0x080c, 0xc133, 0x080c, 0x6adc, 0x080c, 0xa113,
+	0x9085, 0x0001, 0x009e, 0x0005, 0x9006, 0x0ce0, 0x6000, 0x908a,
+	0x0016, 0x1a0c, 0x0dfa, 0x0002, 0xbabc, 0xbaec, 0xbabe, 0xbb0d,
+	0xbae7, 0xbabc, 0xba7f, 0xba84, 0xba84, 0xba7f, 0xba7f, 0xba7f,
+	0xba7f, 0xba7f, 0xba7f, 0xba7f, 0x080c, 0x0dfa, 0x86ff, 0x1520,
+	0x6020, 0x9086, 0x0006, 0x0500, 0x0096, 0x6014, 0x2048, 0x080c,
+	0xbe37, 0x0168, 0xa87c, 0xd0cc, 0x0140, 0x0096, 0xc0cc, 0xa87e,
+	0xa878, 0x2048, 0x080c, 0x0fe3, 0x009e, 0x080c, 0xc133, 0x009e,
+	0x080c, 0xc4f3, 0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002,
+	0x080c, 0x8679, 0x080c, 0x8c10, 0x9085, 0x0001, 0x0005, 0x0066,
+	0x080c, 0x19b4, 0x006e, 0x0890, 0x00e6, 0x2071, 0x19bf, 0x7024,
+	0x9c06, 0x1120, 0x080c, 0x9927, 0x00ee, 0x0840, 0x6020, 0x9084,
+	0x000f, 0x9086, 0x0006, 0x1150, 0x0086, 0x0096, 0x2049, 0x0001,
+	0x2c40, 0x080c, 0x9a58, 0x009e, 0x008e, 0x0010, 0x080c, 0x9824,
+	0x00ee, 0x1904, 0xbabe, 0x0804, 0xba7f, 0x0036, 0x00e6, 0x2071,
+	0x19bf, 0x703c, 0x9c06, 0x1138, 0x901e, 0x080c, 0x999d, 0x00ee,
+	0x003e, 0x0804, 0xbabe, 0x080c, 0x9b88, 0x00ee, 0x003e, 0x1904,
+	0xbabe, 0x0804, 0xba7f, 0x00c6, 0x6020, 0x9084, 0x000f, 0x0013,
+	0x00ce, 0x0005, 0xbb40, 0xbc0b, 0xbd75, 0xbb4a, 0xa113, 0xbb40,
+	0xd432, 0xc55b, 0xbc0b, 0xbb39, 0xbe01, 0xbb39, 0xbb39, 0xbb39,
+	0xbb39, 0x080c, 0x0dfa, 0x080c, 0xc03f, 0x1110, 0x080c, 0xaa81,
+	0x0005, 0x080c, 0x8b04, 0x080c, 0x8c10, 0x0804, 0xa0e3, 0x601b,
+	0x0001, 0x0005, 0x080c, 0xbe37, 0x0130, 0x6014, 0x0096, 0x2048,
+	0x2c00, 0xa896, 0x009e, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dfa,
+	0x0002, 0xbb69, 0xbb6b, 0xbb8f, 0xbba3, 0xbbc9, 0xbb69, 0xbb40,
+	0xbb40, 0xbb40, 0xbba3, 0xbba3, 0xbb69, 0xbb69, 0xbb69, 0xbb69,
+	0xbbad, 0x080c, 0x0dfa, 0x00e6, 0x6014, 0x0096, 0x2048, 0xa880,
+	0xc0b5, 0xa882, 0x009e, 0x2071, 0x19bf, 0x7024, 0x9c06, 0x01a0,
+	0x080c, 0x9824, 0x080c, 0xc4f3, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x6023, 0x0002, 0x2001, 0x195f, 0x2004, 0x601a, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x00ee, 0x0005, 0x601b, 0x0001, 0x0cd8, 0x0096,
+	0x6014, 0x2048, 0xa880, 0xc0b5, 0xa882, 0x009e, 0x080c, 0xc4f3,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x6023, 0x0002, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x0005, 0x0096, 0x601b, 0x0001, 0x6014, 0x2048,
+	0xa880, 0xc0b5, 0xa882, 0x009e, 0x0005, 0x080c, 0x55e3, 0x01b8,
+	0x6014, 0x0096, 0x904d, 0x0190, 0xa864, 0xa867, 0x0103, 0xa87b,
+	0x0006, 0x9086, 0x0139, 0x1150, 0xa867, 0x0139, 0xa87b, 0x0030,
+	0xa897, 0x4005, 0xa89b, 0x0004, 0x080c, 0x6ae9, 0x009e, 0x0804,
+	0xa0e3, 0x6014, 0x0096, 0x904d, 0x05c8, 0xa97c, 0xd1e4, 0x05b0,
+	0x2001, 0x180f, 0x2004, 0xd0c4, 0x0110, 0x009e, 0x0005, 0xa884,
+	0x009e, 0x8003, 0x800b, 0x810b, 0x9108, 0x611a, 0x2001, 0x0030,
+	0x2c08, 0x080c, 0x158b, 0x2001, 0x030c, 0x2004, 0x9086, 0x0041,
+	0x11a0, 0x6014, 0x0096, 0x904d, 0x090c, 0x0dfa, 0xa880, 0xd0f4,
+	0x1130, 0xc0f5, 0xa882, 0x009e, 0x601b, 0x0002, 0x0070, 0x009e,
+	0x2001, 0x0037, 0x2c08, 0x080c, 0x158b, 0x6000, 0x9086, 0x0004,
+	0x1120, 0x2009, 0x0048, 0x080c, 0xa15d, 0x0005, 0x009e, 0x080c,
+	0x19b4, 0x0804, 0xbb8f, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dfa,
+	0x000b, 0x0005, 0xbc22, 0xbb47, 0xbc24, 0xbc22, 0xbc24, 0xbc24,
+	0xbb41, 0xbc22, 0xbb3b, 0xbb3b, 0xbc22, 0xbc22, 0xbc22, 0xbc22,
+	0xbc22, 0xbc22, 0x080c, 0x0dfa, 0x6010, 0x00b6, 0x2058, 0xb804,
+	0x9084, 0x00ff, 0x00be, 0x908a, 0x000c, 0x1a0c, 0x0dfa, 0x00b6,
+	0x0013, 0x00be, 0x0005, 0xbc3f, 0xbd0c, 0xbc41, 0xbc81, 0xbc41,
+	0xbc81, 0xbc41, 0xbc4f, 0xbc3f, 0xbc81, 0xbc3f, 0xbc70, 0x080c,
+	0x0dfa, 0x6004, 0x908e, 0x0016, 0x05c0, 0x908e, 0x0004, 0x05a8,
+	0x908e, 0x0002, 0x0590, 0x908e, 0x0052, 0x0904, 0xbd08, 0x6004,
+	0x080c, 0xc03f, 0x0904, 0xbd25, 0x908e, 0x0004, 0x1110, 0x080c,
+	0x31b4, 0x908e, 0x0021, 0x0904, 0xbd29, 0x908e, 0x0022, 0x0904,
+	0xbd70, 0x908e, 0x003d, 0x0904, 0xbd29, 0x908e, 0x0039, 0x0904,
+	0xbd2d, 0x908e, 0x0035, 0x0904, 0xbd2d, 0x908e, 0x001e, 0x0178,
+	0x908e, 0x0001, 0x1140, 0x6010, 0x2058, 0xb804, 0x9084, 0x00ff,
+	0x9086, 0x0006, 0x0110, 0x080c, 0x318b, 0x080c, 0xaa81, 0x0804,
+	0xa113, 0x00c6, 0x00d6, 0x6104, 0x9186, 0x0016, 0x0904, 0xbcf9,
+	0x9186, 0x0002, 0x1904, 0xbcce, 0x2001, 0x1836, 0x2004, 0xd08c,
+	0x11c8, 0x080c, 0x7207, 0x11b0, 0x080c, 0xc539, 0x0138, 0x080c,
+	0x722a, 0x1120, 0x080c, 0x7105, 0x0804, 0xbd59, 0x2001, 0x1955,
+	0x2003, 0x0001, 0x2001, 0x1800, 0x2003, 0x0001, 0x080c, 0x7127,
+	0x0804, 0xbd59, 0x6010, 0x2058, 0x2001, 0x1836, 0x2004, 0xd0ac,
+	0x1904, 0xbd59, 0xb8a0, 0x9084, 0xff80, 0x1904, 0xbd59, 0xb840,
+	0x9084, 0x00ff, 0x9005, 0x0190, 0x8001, 0xb842, 0x6017, 0x0000,
+	0x6023, 0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x080c, 0xa08d,
+	0x0128, 0x2b00, 0x6012, 0x6023, 0x0001, 0x0458, 0x00de, 0x00ce,
+	0x6004, 0x908e, 0x0002, 0x11a0, 0x6010, 0x2058, 0xb8a0, 0x9086,
+	0x007e, 0x1170, 0x2009, 0x1836, 0x2104, 0xc085, 0x200a, 0x00e6,
+	0x2071, 0x1800, 0x080c, 0x5ebe, 0x00ee, 0x080c, 0xaa81, 0x0030,
+	0x080c, 0xaa81, 0x080c, 0x318b, 0x080c, 0xc54e, 0x00e6, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x31b4, 0x012e, 0x00ee, 0x080c, 0xa113,
+	0x0005, 0x2001, 0x0002, 0x080c, 0x63f0, 0x6003, 0x0001, 0x6007,
+	0x0002, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x00de, 0x00ce, 0x0c80,
+	0x080c, 0x31b4, 0x0804, 0xbc7d, 0x00c6, 0x00d6, 0x6104, 0x9186,
+	0x0016, 0x0d38, 0x6010, 0x2058, 0xb840, 0x9084, 0x00ff, 0x9005,
+	0x0904, 0xbcce, 0x8001, 0xb842, 0x6003, 0x0001, 0x080c, 0x86c1,
+	0x080c, 0x8c10, 0x00de, 0x00ce, 0x0898, 0x080c, 0xaa81, 0x0804,
+	0xbc7f, 0x080c, 0xaabd, 0x0804, 0xbc7f, 0x00d6, 0x2c68, 0x6104,
+	0x080c, 0xc4b1, 0x00de, 0x0118, 0x080c, 0xa0e3, 0x0408, 0x6004,
+	0x8007, 0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007, 0x0085,
+	0x6003, 0x000b, 0x6023, 0x0002, 0x603c, 0x600a, 0x2001, 0x195f,
+	0x2004, 0x601a, 0x602c, 0x2c08, 0x2060, 0x6024, 0xd0b4, 0x0108,
+	0xc085, 0xc0b5, 0x6026, 0x2160, 0x080c, 0x8679, 0x080c, 0x8c10,
+	0x0005, 0x00de, 0x00ce, 0x080c, 0xaa81, 0x080c, 0x318b, 0x00e6,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x31b4, 0x6017, 0x0000, 0x6023,
+	0x0007, 0x601b, 0x0398, 0x6043, 0x0000, 0x012e, 0x00ee, 0x0005,
+	0x080c, 0xa513, 0x1904, 0xbd25, 0x0005, 0x6000, 0x908a, 0x0016,
+	0x1a0c, 0x0dfa, 0x0096, 0x00d6, 0x001b, 0x00de, 0x009e, 0x0005,
+	0xbd90, 0xbd90, 0xbd90, 0xbd90, 0xbd90, 0xbd90, 0xbd90, 0xbd90,
+	0xbd90, 0xbb40, 0xbd90, 0xbb47, 0xbd92, 0xbb47, 0xbdac, 0xbd90,
+	0x080c, 0x0dfa, 0x6004, 0x9086, 0x008b, 0x01b0, 0x6034, 0x908c,
+	0xff00, 0x810f, 0x9186, 0x0035, 0x1130, 0x602c, 0x9080, 0x0009,
+	0x200c, 0xc185, 0x2102, 0x6007, 0x008b, 0x6003, 0x000d, 0x080c,
+	0x8679, 0x080c, 0x8c10, 0x0005, 0x080c, 0xc52d, 0x0118, 0x080c,
+	0xc540, 0x0010, 0x080c, 0xc54e, 0x080c, 0xc022, 0x080c, 0xbe37,
+	0x0570, 0x080c, 0x318b, 0x080c, 0xbe37, 0x0168, 0x6014, 0x2048,
+	0xa867, 0x0103, 0xa87b, 0x0006, 0xa877, 0x0000, 0xa880, 0xc0ed,
+	0xa882, 0x080c, 0x6ae9, 0x2c68, 0x080c, 0xa08d, 0x0150, 0x6810,
+	0x6012, 0x080c, 0xc2b3, 0x00c6, 0x2d60, 0x080c, 0xa113, 0x00ce,
+	0x0008, 0x2d60, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001,
+	0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x00c8, 0x080c,
+	0xc52d, 0x0138, 0x6034, 0x9086, 0x4000, 0x1118, 0x080c, 0x318b,
+	0x08d0, 0x6034, 0x908c, 0xff00, 0x810f, 0x9186, 0x0039, 0x0118,
+	0x9186, 0x0035, 0x1118, 0x080c, 0x318b, 0x0868, 0x080c, 0xa113,
+	0x0005, 0x6000, 0x908a, 0x0016, 0x1a0c, 0x0dfa, 0x0002, 0xbe17,
+	0xbe17, 0xbe19, 0xbe19, 0xbe19, 0xbe17, 0xbe17, 0xa113, 0xbe17,
+	0xbe17, 0xbe17, 0xbe17, 0xbe17, 0xbe17, 0xbe17, 0xbe17, 0x080c,
+	0x0dfa, 0x080c, 0x9b88, 0x6114, 0x0096, 0x2148, 0xa87b, 0x0006,
+	0x080c, 0x6ae9, 0x009e, 0x0804, 0xa0e3, 0x9284, 0x0007, 0x1158,
+	0x9282, 0x1cd0, 0x0240, 0x2001, 0x1819, 0x2004, 0x9202, 0x1218,
+	0x9085, 0x0001, 0x0005, 0x9006, 0x0ce8, 0x0096, 0x0028, 0x0096,
+	0x0006, 0x6014, 0x2048, 0x000e, 0x0006, 0x9984, 0xf000, 0x9086,
+	0xf000, 0x0110, 0x080c, 0x10dc, 0x000e, 0x009e, 0x0005, 0x00e6,
+	0x00c6, 0x0036, 0x0006, 0x0126, 0x2091, 0x8000, 0x2061, 0x1cd0,
+	0x2071, 0x1800, 0x7350, 0x7070, 0x9302, 0x1640, 0x6020, 0x9206,
+	0x11f8, 0x080c, 0xc539, 0x0180, 0x9286, 0x0001, 0x1168, 0x6004,
+	0x9086, 0x0004, 0x1148, 0x080c, 0x318b, 0x080c, 0xc54e, 0x00c6,
+	0x080c, 0xa113, 0x00ce, 0x0060, 0x080c, 0xc22d, 0x0148, 0x080c,
+	0xc03f, 0x1110, 0x080c, 0xaa81, 0x00c6, 0x080c, 0xa0e3, 0x00ce,
+	0x9ce0, 0x0018, 0x7064, 0x9c02, 0x1208, 0x08a0, 0x012e, 0x000e,
+	0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6, 0x0016, 0x9188,
+	0x1000, 0x210c, 0x81ff, 0x0128, 0x2061, 0x1a8a, 0x6112, 0x080c,
+	0x318b, 0x9006, 0x0010, 0x9085, 0x0001, 0x001e, 0x00ce, 0x00ee,
+	0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa08d, 0x01b0,
+	0x6656, 0x2b00, 0x6012, 0x080c, 0x55e3, 0x0118, 0x080c, 0xbf66,
+	0x0168, 0x080c, 0xc2b3, 0x6023, 0x0003, 0x2009, 0x004b, 0x080c,
+	0xa15d, 0x9085, 0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0xbaa0, 0x080c, 0xa130, 0x0560,
+	0x6057, 0x0000, 0x2b00, 0x6012, 0x080c, 0xc2b3, 0x6023, 0x0003,
+	0x0016, 0x080c, 0x8803, 0x0076, 0x903e, 0x080c, 0x86f1, 0x2c08,
+	0x080c, 0xd5f6, 0x007e, 0x001e, 0xd184, 0x0128, 0x080c, 0xa0e3,
+	0x9085, 0x0001, 0x0070, 0x080c, 0x55e3, 0x0128, 0xd18c, 0x1170,
+	0x080c, 0xbf66, 0x0148, 0x2009, 0x004c, 0x080c, 0xa15d, 0x9085,
+	0x0001, 0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2900, 0x6016,
+	0x0c90, 0x2009, 0x004d, 0x0010, 0x2009, 0x004e, 0x00f6, 0x00c6,
+	0x0046, 0x0016, 0x080c, 0xa08d, 0x2c78, 0x05a0, 0x7e56, 0x2b00,
+	0x7812, 0x7823, 0x0003, 0x0016, 0x2021, 0x0005, 0x080c, 0xbf78,
+	0x001e, 0x9186, 0x004d, 0x0118, 0x9186, 0x004e, 0x0148, 0x2001,
+	0x1958, 0x200c, 0xd1fc, 0x0168, 0x2f60, 0x080c, 0xa0e3, 0x00d0,
+	0x2001, 0x1957, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xa0e3,
+	0x0088, 0x2f60, 0x080c, 0x55e3, 0x0138, 0xd18c, 0x1118, 0x04f1,
+	0x0148, 0x0010, 0x2900, 0x7816, 0x001e, 0x0016, 0x080c, 0xa15d,
+	0x9085, 0x0001, 0x001e, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6,
+	0x00c6, 0x0046, 0x080c, 0xa08d, 0x2c78, 0x0508, 0x7e56, 0x2b00,
+	0x7812, 0x7823, 0x0003, 0x0096, 0x2021, 0x0004, 0x0489, 0x009e,
+	0x2001, 0x1956, 0x200c, 0xd1fc, 0x0120, 0x2f60, 0x080c, 0xa0e3,
+	0x0060, 0x2f60, 0x080c, 0x55e3, 0x0120, 0xd18c, 0x1160, 0x0071,
+	0x0130, 0x2009, 0x0052, 0x080c, 0xa15d, 0x9085, 0x0001, 0x004e,
+	0x00ce, 0x00fe, 0x0005, 0x2900, 0x7816, 0x0c98, 0x00c6, 0x080c,
+	0x4abf, 0x00ce, 0x1120, 0x080c, 0xa0e3, 0x9006, 0x0005, 0xa867,
+	0x0000, 0xa86b, 0x8000, 0x2900, 0x6016, 0x9085, 0x0001, 0x0005,
+	0x0096, 0x0076, 0x0126, 0x2091, 0x8000, 0x080c, 0x65d3, 0x0158,
+	0x2001, 0xbf7d, 0x0006, 0x900e, 0x2400, 0x080c, 0x6d17, 0x080c,
+	0x6ae9, 0x000e, 0x0807, 0x2418, 0x080c, 0x8a9e, 0xbaa0, 0x0086,
+	0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x080c, 0x881b, 0x008e,
+	0x080c, 0x86f1, 0x2f08, 0x2648, 0x080c, 0xd5f6, 0xb93c, 0x81ff,
+	0x090c, 0x88ee, 0x080c, 0x8c10, 0x012e, 0x007e, 0x009e, 0x0005,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa08d, 0x0190, 0x660a,
+	0x2b08, 0x6112, 0x080c, 0xc2b3, 0x6023, 0x0001, 0x2900, 0x6016,
+	0x2009, 0x001f, 0x080c, 0xa15d, 0x9085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c,
+	0xa130, 0x01b8, 0x660a, 0x2b08, 0x6112, 0x080c, 0xc2b3, 0x6023,
+	0x0008, 0x2900, 0x6016, 0x00f6, 0x2c78, 0x080c, 0x16db, 0x00fe,
+	0x2009, 0x0021, 0x080c, 0xa15d, 0x9085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0x9006, 0x0cd8, 0x2009, 0x003d, 0x00c6, 0x0126, 0x0016,
+	0x2091, 0x8000, 0x080c, 0xa08d, 0x0198, 0x660a, 0x2b08, 0x6112,
+	0x080c, 0xc2b3, 0x6023, 0x0001, 0x2900, 0x6016, 0x001e, 0x0016,
+	0x080c, 0xa15d, 0x9085, 0x0001, 0x001e, 0x012e, 0x00ce, 0x0005,
+	0x9006, 0x0cd0, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa130,
+	0x0188, 0x2b08, 0x6112, 0x080c, 0xc2b3, 0x6023, 0x0001, 0x2900,
+	0x6016, 0x2009, 0x0000, 0x080c, 0xa15d, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x2009, 0x0044, 0x0830, 0x2009,
+	0x0049, 0x0818, 0x0026, 0x00b6, 0x6210, 0x2258, 0xba3c, 0x82ff,
+	0x0110, 0x8211, 0xba3e, 0x00be, 0x002e, 0x0005, 0x0006, 0x0016,
+	0x6004, 0x908e, 0x0002, 0x0140, 0x908e, 0x0003, 0x0128, 0x908e,
+	0x0004, 0x0110, 0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006,
+	0x0086, 0x0096, 0x6020, 0x9086, 0x0004, 0x01a8, 0x6014, 0x904d,
+	0x080c, 0xbe37, 0x0180, 0xa864, 0x9086, 0x0139, 0x0170, 0x6020,
+	0x90c6, 0x0003, 0x0140, 0x90c6, 0x0002, 0x0128, 0xa868, 0xd0fc,
+	0x0110, 0x9006, 0x0010, 0x9085, 0x0001, 0x009e, 0x008e, 0x000e,
+	0x0005, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa130, 0x0198,
+	0x2b08, 0x6112, 0x080c, 0xc2b3, 0x6023, 0x0001, 0x2900, 0x6016,
+	0x080c, 0x318b, 0x2009, 0x0028, 0x080c, 0xa15d, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x9186, 0x0015, 0x11a8,
+	0x2011, 0x1823, 0x2204, 0x9086, 0x0074, 0x1178, 0x00b6, 0x080c,
+	0xad0c, 0x00be, 0x080c, 0xaf4b, 0x6003, 0x0001, 0x6007, 0x0029,
+	0x080c, 0x86c1, 0x080c, 0x8c10, 0x0078, 0x6014, 0x0096, 0x2048,
+	0xa868, 0x009e, 0xd0fc, 0x0148, 0x2001, 0x0001, 0x080c, 0xc472,
+	0x080c, 0xaa81, 0x080c, 0xa0e3, 0x0005, 0x0096, 0x6014, 0x904d,
+	0x090c, 0x0dfa, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005,
+	0xa89b, 0x0004, 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6ae9, 0x012e, 0x009e, 0x080c, 0xa0e3, 0x0c30, 0x0096, 0x9186,
+	0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x63f0, 0x00e8, 0x9186,
+	0x0015, 0x1510, 0x2011, 0x1823, 0x2204, 0x9086, 0x0014, 0x11e0,
+	0x6010, 0x00b6, 0x2058, 0x080c, 0x653a, 0x00be, 0x080c, 0xb01c,
+	0x1198, 0x6010, 0x00b6, 0x2058, 0xb890, 0x00be, 0x9005, 0x0160,
+	0x2001, 0x0006, 0x080c, 0x63f0, 0x6014, 0x2048, 0xa868, 0xd0fc,
+	0x0170, 0x080c, 0xa4e7, 0x0048, 0x6014, 0x2048, 0xa868, 0xd0fc,
+	0x0528, 0x080c, 0xaa81, 0x080c, 0xa0e3, 0x009e, 0x0005, 0x6014,
+	0x6310, 0x2358, 0x904d, 0x090c, 0x0dfa, 0xa87b, 0x0000, 0xa883,
+	0x0000, 0xa897, 0x4000, 0x900e, 0x080c, 0x66bf, 0x1108, 0xc185,
+	0xb800, 0xd0bc, 0x0108, 0xc18d, 0xa99a, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6ae9, 0x012e, 0x080c, 0xa0e3, 0x08f8, 0x6014, 0x904d,
+	0x090c, 0x0dfa, 0xa87b, 0x0030, 0xa883, 0x0000, 0xa897, 0x4005,
+	0xa89b, 0x0004, 0xa867, 0x0139, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6ae9, 0x012e, 0x080c, 0xa0e3, 0x0840, 0xa878, 0x9086, 0x0005,
+	0x1108, 0x0009, 0x0005, 0xa880, 0xc0ad, 0xa882, 0x0005, 0x6043,
+	0x0000, 0x6017, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050, 0x080c,
+	0x8679, 0x080c, 0x8c10, 0x0005, 0x00c6, 0x6010, 0x00b6, 0x2058,
+	0xb800, 0x00be, 0xd0bc, 0x0120, 0x6020, 0x9084, 0x000f, 0x0013,
+	0x00ce, 0x0005, 0xbb40, 0xc163, 0xc163, 0xc166, 0xd8d4, 0xd8ef,
+	0xd8f2, 0xbb40, 0xbb40, 0xbb40, 0xbb40, 0xbb40, 0xbb40, 0xbb40,
+	0xbb40, 0x080c, 0x0dfa, 0xa001, 0xa001, 0x0005, 0x0096, 0x6014,
+	0x904d, 0x0118, 0xa87c, 0xd0e4, 0x1110, 0x009e, 0x0010, 0x009e,
+	0x0005, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0550,
+	0x2001, 0x1833, 0x2004, 0x9005, 0x1540, 0x00f6, 0x2c78, 0x080c,
+	0xa08d, 0x0508, 0x7810, 0x6012, 0x080c, 0xc2b3, 0x7820, 0x9086,
+	0x0003, 0x0128, 0x7808, 0x603a, 0x2f00, 0x603e, 0x0020, 0x7808,
+	0x603e, 0x2f00, 0x603a, 0x602e, 0x6023, 0x0001, 0x6007, 0x0035,
+	0x6003, 0x0001, 0x7954, 0x6156, 0x080c, 0x8679, 0x080c, 0x8c10,
+	0x2f60, 0x00fe, 0x0005, 0x2f60, 0x00fe, 0x2001, 0x1960, 0x2004,
+	0x6042, 0x0005, 0x0016, 0x0096, 0x6814, 0x2048, 0xa87c, 0xd0e4,
+	0x0180, 0xc0e4, 0xa87e, 0xa877, 0x0000, 0xa893, 0x0000, 0xa88f,
+	0x0000, 0xd0cc, 0x0130, 0xc0cc, 0xa87e, 0xa878, 0x2048, 0x080c,
+	0x0fe3, 0x6830, 0x6036, 0x908e, 0x0001, 0x0148, 0x6803, 0x0002,
+	0x9086, 0x0005, 0x0170, 0x9006, 0x602e, 0x6032, 0x00d0, 0x681c,
+	0xc085, 0x681e, 0x6803, 0x0004, 0x6824, 0xc0f4, 0x9085, 0x0c00,
+	0x6826, 0x6814, 0x2048, 0xa8ac, 0x6938, 0x9102, 0xa8b0, 0x693c,
+	0x9103, 0x1e48, 0x683c, 0x602e, 0x6838, 0x9084, 0xfffc, 0x683a,
+	0x6032, 0x2d00, 0x603a, 0x6808, 0x603e, 0x6910, 0x6112, 0x6954,
+	0x6156, 0x6023, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x080c,
+	0x8679, 0x080c, 0x8c10, 0x009e, 0x001e, 0x0005, 0x6024, 0xd0d4,
+	0x0510, 0xd0f4, 0x11f8, 0x6038, 0x940a, 0x603c, 0x9303, 0x0230,
+	0x9105, 0x0120, 0x6024, 0xc0d4, 0xc0f5, 0x0098, 0x643a, 0x633e,
+	0xac3e, 0xab42, 0x0046, 0x0036, 0x2400, 0xacac, 0x9402, 0xa836,
+	0x2300, 0xabb0, 0x9303, 0xa83a, 0x003e, 0x004e, 0x6024, 0xc0d4,
+	0x0000, 0x6026, 0x0005, 0xd0f4, 0x1138, 0xa83c, 0x603a, 0xa840,
+	0x603e, 0x6024, 0xc0f5, 0x6026, 0x0005, 0x0006, 0x0016, 0x6004,
+	0x908e, 0x0034, 0x01b8, 0x908e, 0x0035, 0x01a0, 0x908e, 0x0036,
+	0x0188, 0x908e, 0x0037, 0x0170, 0x908e, 0x0038, 0x0158, 0x908e,
+	0x0039, 0x0140, 0x908e, 0x003a, 0x0128, 0x908e, 0x003b, 0x0110,
+	0x9085, 0x0001, 0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026,
+	0x0036, 0x00e6, 0x2001, 0x195a, 0x200c, 0x8000, 0x2014, 0x2001,
+	0x0032, 0x080c, 0x84ff, 0x2001, 0x195e, 0x82ff, 0x1110, 0x2011,
+	0x0014, 0x2202, 0x2001, 0x195c, 0x200c, 0x8000, 0x2014, 0x2071,
+	0x1944, 0x711a, 0x721e, 0x2001, 0x0064, 0x080c, 0x84ff, 0x2001,
+	0x195f, 0x82ff, 0x1110, 0x2011, 0x0014, 0x2202, 0x2001, 0x1960,
+	0x9288, 0x000a, 0x2102, 0x2001, 0x1a6b, 0x2102, 0x2001, 0x0032,
+	0x080c, 0x158b, 0x080c, 0x67a4, 0x00ee, 0x003e, 0x002e, 0x001e,
+	0x000e, 0x0005, 0x0006, 0x0016, 0x00e6, 0x2001, 0x195e, 0x2003,
+	0x0028, 0x2001, 0x195f, 0x2003, 0x0014, 0x2071, 0x1944, 0x701b,
+	0x0000, 0x701f, 0x07d0, 0x2001, 0x1960, 0x2009, 0x001e, 0x2102,
+	0x2001, 0x1a6b, 0x2102, 0x2001, 0x0032, 0x080c, 0x158b, 0x00ee,
+	0x001e, 0x000e, 0x0005, 0x0096, 0x6058, 0x904d, 0x0110, 0x080c,
+	0x1063, 0x009e, 0x0005, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x080c, 0xa08d, 0x0180, 0x2b08, 0x6112, 0x0ca9, 0x6023, 0x0001,
+	0x2900, 0x6016, 0x2009, 0x0033, 0x080c, 0xa15d, 0x9085, 0x0001,
+	0x012e, 0x00ce, 0x0005, 0x9006, 0x0cd8, 0x0096, 0x00e6, 0x00f6,
+	0x2071, 0x1800, 0x9186, 0x0015, 0x1500, 0x708c, 0x9086, 0x0018,
+	0x11e0, 0x6014, 0x2048, 0xaa3c, 0xd2e4, 0x1160, 0x2c78, 0x080c,
+	0x8e03, 0x01d8, 0x7078, 0xaa50, 0x9206, 0x1160, 0x707c, 0xaa54,
+	0x9206, 0x1140, 0x6210, 0x00b6, 0x2258, 0xbaa0, 0x00be, 0x900e,
+	0x080c, 0x31d4, 0x080c, 0xa4e7, 0x0020, 0x080c, 0xaa81, 0x080c,
+	0xa0e3, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x705c, 0xaa54, 0x9206,
+	0x0d48, 0x0c80, 0x00c6, 0x0126, 0x2091, 0x8000, 0x080c, 0xa08d,
+	0x0188, 0x2b08, 0x6112, 0x080c, 0xc2b3, 0x6023, 0x0001, 0x2900,
+	0x6016, 0x2009, 0x004d, 0x080c, 0xa15d, 0x9085, 0x0001, 0x012e,
+	0x00ce, 0x0005, 0x9006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x0016, 0x080c, 0xa08d, 0x0180, 0x2b08, 0x6112, 0x080c, 0xc2b3,
+	0x6023, 0x0001, 0x2900, 0x6016, 0x001e, 0x080c, 0xa15d, 0x9085,
+	0x0001, 0x012e, 0x00ce, 0x0005, 0x001e, 0x9006, 0x0cd0, 0x0016,
+	0x0026, 0x0036, 0x0046, 0x0056, 0x0066, 0x0096, 0x00e6, 0x00f6,
+	0x2071, 0x1800, 0x9186, 0x0015, 0x1568, 0x718c, 0x6014, 0x2048,
+	0xa814, 0x8003, 0x9106, 0x1530, 0x20e1, 0x0000, 0x2001, 0x1978,
+	0x2003, 0x0000, 0x6014, 0x2048, 0xa830, 0x20a8, 0x8906, 0x8006,
+	0x8007, 0x9094, 0x003f, 0x22e8, 0x9084, 0xffc0, 0x9080, 0x001b,
+	0x20a0, 0x2001, 0x1978, 0x0016, 0x200c, 0x080c, 0xcb1d, 0x001e,
+	0xa804, 0x9005, 0x0110, 0x2048, 0x0c38, 0x6014, 0x2048, 0xa867,
+	0x0103, 0x0010, 0x080c, 0xaa81, 0x080c, 0xa0e3, 0x00fe, 0x00ee,
+	0x009e, 0x006e, 0x005e, 0x004e, 0x003e, 0x002e, 0x001e, 0x0005,
+	0x0096, 0x00e6, 0x00f6, 0x2071, 0x1800, 0x9186, 0x0015, 0x11b8,
+	0x708c, 0x9086, 0x0004, 0x1198, 0x6014, 0x2048, 0x2c78, 0x080c,
+	0x8e03, 0x01a8, 0x7078, 0xaa74, 0x9206, 0x1130, 0x707c, 0xaa78,
+	0x9206, 0x1110, 0x080c, 0x318b, 0x080c, 0xa4e7, 0x0020, 0x080c,
+	0xaa81, 0x080c, 0xa0e3, 0x00fe, 0x00ee, 0x009e, 0x0005, 0x705c,
+	0xaa78, 0x9206, 0x0d78, 0x0c80, 0x0096, 0x00e6, 0x00f6, 0x2071,
+	0x1800, 0x9186, 0x0015, 0x1550, 0x708c, 0x9086, 0x0004, 0x1530,
+	0x6014, 0x2048, 0x2c78, 0x080c, 0x8e03, 0x05f0, 0x7078, 0xaacc,
+	0x9206, 0x1180, 0x707c, 0xaad0, 0x9206, 0x1160, 0x080c, 0x318b,
+	0x0016, 0xa998, 0xaab0, 0x9284, 0x1000, 0xc0fd, 0x080c, 0x558a,
+	0x001e, 0x0010, 0x080c, 0x5375, 0x080c, 0xbe37, 0x0508, 0xa87b,
+	0x0000, 0xa883, 0x0000, 0xa897, 0x4000, 0x0080, 0x080c, 0xbe37,
+	0x01b8, 0x6014, 0x2048, 0x080c, 0x5375, 0x1d70, 0xa87b, 0x0030,
+	0xa883, 0x0000, 0xa897, 0x4005, 0xa89b, 0x0004, 0x0126, 0x2091,
+	0x8000, 0xa867, 0x0139, 0x080c, 0x6ae9, 0x012e, 0x080c, 0xa0e3,
+	0x00fe, 0x00ee, 0x009e, 0x0005, 0x705c, 0xaad0, 0x9206, 0x0930,
+	0x0888, 0x0016, 0x0026, 0xa87c, 0xd0ac, 0x0178, 0xa938, 0xaa34,
+	0x2100, 0x9205, 0x0150, 0xa890, 0x9106, 0x1118, 0xa88c, 0x9206,
+	0x0120, 0xa992, 0xaa8e, 0x9085, 0x0001, 0x002e, 0x001e, 0x0005,
+	0x00b6, 0x00d6, 0x0036, 0x080c, 0xbe37, 0x0904, 0xc46e, 0x0096,
+	0x6314, 0x2348, 0xa87a, 0xa982, 0x929e, 0x4000, 0x1580, 0x6310,
+	0x00c6, 0x2358, 0x2009, 0x0000, 0xa868, 0xd0f4, 0x1140, 0x080c,
+	0x66bf, 0x1108, 0xc185, 0xb800, 0xd0bc, 0x0108, 0xc18d, 0xaa96,
+	0xa99a, 0x20a9, 0x0004, 0xa860, 0x20e8, 0xa85c, 0x9080, 0x0031,
+	0x20a0, 0xb8b4, 0x20e0, 0xb8b8, 0x9080, 0x0006, 0x2098, 0x080c,
+	0x0fae, 0x20a9, 0x0004, 0xa85c, 0x9080, 0x0035, 0x20a0, 0xb8b8,
+	0x9080, 0x000a, 0x2098, 0x080c, 0x0fae, 0x00ce, 0x0090, 0xaa96,
+	0x3918, 0x9398, 0x0007, 0x231c, 0x6004, 0x9086, 0x0016, 0x0110,
+	0xa89b, 0x0004, 0xaba2, 0x6310, 0x2358, 0xb804, 0x9084, 0x00ff,
+	0xa89e, 0x080c, 0x6adc, 0x6017, 0x0000, 0x009e, 0x003e, 0x00de,
+	0x00be, 0x0005, 0x0026, 0x0036, 0x0046, 0x00b6, 0x0096, 0x00f6,
+	0x6214, 0x2248, 0x6210, 0x2258, 0x2079, 0x0260, 0x9096, 0x0000,
+	0x11a0, 0xb814, 0x9084, 0x00ff, 0x900e, 0x080c, 0x276e, 0x2118,
+	0x831f, 0x939c, 0xff00, 0x7838, 0x9084, 0x00ff, 0x931d, 0x7c3c,
+	0x2011, 0x8018, 0x080c, 0x4b1f, 0x00a8, 0x9096, 0x0001, 0x1148,
+	0x89ff, 0x0180, 0xa89b, 0x000d, 0x7838, 0xa8a6, 0x783c, 0xa8aa,
+	0x0048, 0x9096, 0x0002, 0x1130, 0xa89b, 0x000d, 0x7838, 0xa8a6,
+	0x783c, 0xa8aa, 0x00fe, 0x009e, 0x00be, 0x004e, 0x003e, 0x002e,
+	0x0005, 0x00c6, 0x0026, 0x0016, 0x9186, 0x0035, 0x0110, 0x6a38,
+	0x0008, 0x6a2c, 0x080c, 0xbe25, 0x01f0, 0x2260, 0x6120, 0x9186,
+	0x0003, 0x0118, 0x9186, 0x0006, 0x1190, 0x6838, 0x9206, 0x0140,
+	0x683c, 0x9206, 0x1160, 0x6108, 0x6838, 0x9106, 0x1140, 0x0020,
+	0x6008, 0x693c, 0x9106, 0x1118, 0x6010, 0x6910, 0x9106, 0x001e,
+	0x002e, 0x00ce, 0x0005, 0x9085, 0x0001, 0x0cc8, 0xa974, 0xd1cc,
+	0x0188, 0x918c, 0x00ff, 0x918e, 0x0002, 0x1160, 0xa9a8, 0x918c,
+	0x0f00, 0x810f, 0x918e, 0x0001, 0x1128, 0xa834, 0xa938, 0x9115,
+	0x190c, 0xb4ee, 0x0005, 0x0036, 0x2019, 0x0001, 0x0010, 0x0036,
+	0x901e, 0x0499, 0x01e0, 0x080c, 0xbe37, 0x01c8, 0x080c, 0xc022,
+	0x6037, 0x4000, 0x6014, 0x6017, 0x0000, 0x0096, 0x2048, 0xa87c,
+	0x080c, 0xc03f, 0x1118, 0x080c, 0xaa81, 0x0040, 0xa867, 0x0103,
+	0xa877, 0x0000, 0x83ff, 0x1129, 0x080c, 0x6ae9, 0x009e, 0x003e,
+	0x0005, 0xa880, 0xd0b4, 0x0128, 0xa87b, 0x0006, 0xc0ec, 0xa882,
+	0x0048, 0xd0bc, 0x0118, 0xa87b, 0x0002, 0x0020, 0xa87b, 0x0005,
+	0x080c, 0xc133, 0xa877, 0x0000, 0x0005, 0x2001, 0x1810, 0x2004,
+	0xd0ec, 0x0005, 0x0006, 0x2001, 0x1810, 0x2004, 0xd0f4, 0x000e,
+	0x0005, 0x0006, 0x2001, 0x1810, 0x2004, 0xd0e4, 0x000e, 0x0005,
+	0x0036, 0x0046, 0x6010, 0x00b6, 0x2058, 0xbba0, 0x00be, 0x2021,
+	0x0007, 0x080c, 0x4cbc, 0x004e, 0x003e, 0x0005, 0x0c51, 0x1d81,
+	0x0005, 0x2001, 0x195e, 0x2004, 0x601a, 0x0005, 0x2001, 0x1960,
+	0x2004, 0x6042, 0x0005, 0x080c, 0xa0e3, 0x0804, 0x8c10, 0x00b6,
+	0x0066, 0x6000, 0x90b2, 0x0016, 0x1a0c, 0x0dfa, 0x001b, 0x006e,
+	0x00be, 0x0005, 0xc57a, 0xcc7a, 0xcdd5, 0xc57a, 0xc57a, 0xc57a,
+	0xc57a, 0xc57a, 0xc5b1, 0xce59, 0xc57a, 0xc57a, 0xc57a, 0xc57a,
+	0xc57a, 0xc57a, 0x080c, 0x0dfa, 0x0066, 0x6000, 0x90b2, 0x0016,
+	0x1a0c, 0x0dfa, 0x0013, 0x006e, 0x0005, 0xc595, 0xd3cb, 0xc595,
+	0xc595, 0xc595, 0xc595, 0xc595, 0xc595, 0xd378, 0xd41f, 0xc595,
+	0xda0f, 0xda45, 0xda0f, 0xda45, 0xc595, 0x080c, 0x0dfa, 0x6000,
+	0x9082, 0x0016, 0x1a0c, 0x0dfa, 0x6000, 0x000a, 0x0005, 0xc5af,
+	0xd037, 0xd129, 0xd14c, 0xd20c, 0xc5af, 0xd2eb, 0xd294, 0xce65,
+	0xd34e, 0xd363, 0xc5af, 0xc5af, 0xc5af, 0xc5af, 0xc5af, 0x080c,
+	0x0dfa, 0x91b2, 0x0053, 0x1a0c, 0x0dfa, 0x2100, 0x91b2, 0x0040,
+	0x1a04, 0xca1b, 0x0002, 0xc5fb, 0xc7e9, 0xc5fb, 0xc5fb, 0xc5fb,
+	0xc7f2, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb,
+	0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb,
+	0xc5fb, 0xc5fb, 0xc5fd, 0xc660, 0xc66f, 0xc6d3, 0xc6fe, 0xc776,
+	0xc7d4, 0xc5fb, 0xc5fb, 0xc7f5, 0xc5fb, 0xc5fb, 0xc80a, 0xc817,
+	0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb, 0xc8bd, 0xc5fb, 0xc5fb,
+	0xc8d1, 0xc5fb, 0xc5fb, 0xc88c, 0xc5fb, 0xc5fb, 0xc5fb, 0xc8e9,
+	0xc5fb, 0xc5fb, 0xc5fb, 0xc966, 0xc5fb, 0xc5fb, 0xc5fb, 0xc5fb,
+	0xc5fb, 0xc5fb, 0xc9e3, 0x080c, 0x0dfa, 0x080c, 0x6781, 0x1150,
+	0x2001, 0x1836, 0x2004, 0xd0cc, 0x1128, 0x9084, 0x0009, 0x9086,
+	0x0008, 0x1140, 0x6007, 0x0009, 0x602f, 0x0009, 0x6017, 0x0000,
+	0x0804, 0xc7e2, 0x080c, 0x676a, 0x00e6, 0x00c6, 0x0036, 0x0026,
+	0x0016, 0x6210, 0x2258, 0xbaa0, 0x0026, 0x2019, 0x0029, 0x080c,
+	0x8803, 0x0076, 0x903e, 0x080c, 0x86f1, 0x2c08, 0x080c, 0xd5f6,
+	0x007e, 0x001e, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x6610,
+	0x2658, 0x080c, 0x64ae, 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006,
+	0x1268, 0x0016, 0x0026, 0x6210, 0x00b6, 0x2258, 0xbaa0, 0x00be,
+	0x2c08, 0x080c, 0xdbbd, 0x002e, 0x001e, 0x1178, 0x080c, 0xd529,
+	0x1904, 0xc6cb, 0x080c, 0xd4c5, 0x1120, 0x6007, 0x0008, 0x0804,
+	0xc7e2, 0x6007, 0x0009, 0x0804, 0xc7e2, 0x080c, 0xd720, 0x0128,
+	0x080c, 0xd529, 0x0d78, 0x0804, 0xc6cb, 0x6017, 0x1900, 0x0c88,
+	0x080c, 0x32ae, 0x1904, 0xca18, 0x6106, 0x080c, 0xd47a, 0x6007,
+	0x0006, 0x0804, 0xc7e2, 0x6007, 0x0007, 0x0804, 0xc7e2, 0x080c,
+	0xda81, 0x1904, 0xca18, 0x080c, 0x32ae, 0x1904, 0xca18, 0x00d6,
+	0x6610, 0x2658, 0xbe04, 0x9684, 0x00ff, 0x9082, 0x0006, 0x1220,
+	0x2001, 0x0001, 0x080c, 0x63dc, 0x96b4, 0xff00, 0x8637, 0x9686,
+	0x0006, 0x0188, 0x9686, 0x0004, 0x0170, 0xbe04, 0x96b4, 0x00ff,
+	0x9686, 0x0006, 0x0140, 0x9686, 0x0004, 0x0128, 0x9686, 0x0005,
+	0x0110, 0x00de, 0x0480, 0x00e6, 0x2071, 0x0260, 0x7034, 0x9084,
+	0x0003, 0x1140, 0x7034, 0x9082, 0x0014, 0x0220, 0x7030, 0x9084,
+	0x0003, 0x0130, 0x00ee, 0x6017, 0x0000, 0x602f, 0x0007, 0x00b0,
+	0x00ee, 0x080c, 0xd58c, 0x1190, 0x9686, 0x0006, 0x1140, 0x0026,
+	0x6210, 0x2258, 0xbaa0, 0x900e, 0x080c, 0x31d4, 0x002e, 0x080c,
+	0x653a, 0x6007, 0x000a, 0x00de, 0x0804, 0xc7e2, 0x6007, 0x000b,
+	0x00de, 0x0804, 0xc7e2, 0x080c, 0x318b, 0x080c, 0xc54e, 0x6007,
+	0x0001, 0x0804, 0xc7e2, 0x080c, 0xda81, 0x1904, 0xca18, 0x080c,
+	0x32ae, 0x1904, 0xca18, 0x2071, 0x0260, 0x7034, 0x90b4, 0x0003,
+	0x1948, 0x90b2, 0x0014, 0x0a30, 0x7030, 0x9084, 0x0003, 0x1910,
+	0x6610, 0x2658, 0xbe04, 0x9686, 0x0707, 0x09e8, 0x0026, 0x6210,
+	0x2258, 0xbaa0, 0x900e, 0x080c, 0x31d4, 0x002e, 0x6007, 0x000c,
+	0x2001, 0x0001, 0x080c, 0xdb9d, 0x0804, 0xc7e2, 0x080c, 0x6781,
+	0x1140, 0x2001, 0x1836, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008,
+	0x1110, 0x0804, 0xc60a, 0x080c, 0x676a, 0x6610, 0x2658, 0xbe04,
+	0x9684, 0x00ff, 0x9082, 0x0006, 0x06c0, 0x1138, 0x0026, 0x2001,
+	0x0006, 0x080c, 0x641c, 0x002e, 0x0050, 0x96b4, 0xff00, 0x8637,
+	0x9686, 0x0004, 0x0120, 0x9686, 0x0006, 0x1904, 0xc6cb, 0x080c,
+	0xd599, 0x1120, 0x6007, 0x000e, 0x0804, 0xc7e2, 0x0046, 0x6410,
+	0x2458, 0xbca0, 0x0046, 0x080c, 0x318b, 0x080c, 0xc54e, 0x004e,
+	0x0016, 0x9006, 0x2009, 0x185c, 0x210c, 0x0048, 0x2009, 0x0029,
+	0x080c, 0xd885, 0x6010, 0x2058, 0xb800, 0xc0e5, 0xb802, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x0804, 0xc7e2, 0x2001, 0x0001, 0x080c,
+	0x63dc, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0x1805, 0x2011, 0x0270, 0x080c, 0xb0bc, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x9005, 0x0168, 0x96b4, 0xff00, 0x8637, 0x9682, 0x0004,
+	0x0a04, 0xc6cb, 0x9682, 0x0007, 0x0a04, 0xc727, 0x0804, 0xc6cb,
+	0x6017, 0x1900, 0x6007, 0x0009, 0x0804, 0xc7e2, 0x080c, 0x6781,
+	0x1140, 0x2001, 0x1836, 0x2004, 0x9084, 0x0009, 0x9086, 0x0008,
+	0x1110, 0x0804, 0xc60a, 0x080c, 0x676a, 0x6610, 0x2658, 0xbe04,
+	0x9684, 0x00ff, 0x0006, 0x9086, 0x0001, 0x000e, 0x0170, 0x9082,
+	0x0006, 0x0690, 0x0150, 0x96b4, 0xff00, 0x8637, 0x9686, 0x0004,
+	0x0120, 0x9686, 0x0006, 0x1904, 0xc6cb, 0x080c, 0xd5c7, 0x1130,
+	0x080c, 0xd4c5, 0x1118, 0x6007, 0x0010, 0x04e0, 0x0046, 0x6410,
+	0x2458, 0xbca0, 0x0046, 0x080c, 0x318b, 0x080c, 0xc54e, 0x004e,
+	0x0016, 0x9006, 0x2009, 0x185c, 0x210c, 0x0048, 0x2009, 0x0029,
+	0x080c, 0xd885, 0x6010, 0x2058, 0xb800, 0xc0e5, 0xb802, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x00f0, 0x080c, 0xd720, 0x0140, 0x96b4,
+	0xff00, 0x8637, 0x9686, 0x0006, 0x0980, 0x0804, 0xc6cb, 0x6017,
+	0x1900, 0x6007, 0x0009, 0x0070, 0x080c, 0x32ae, 0x1904, 0xca18,
+	0x080c, 0xda81, 0x1904, 0xca18, 0x080c, 0xcbb8, 0x1904, 0xc6cb,
+	0x6007, 0x0012, 0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10,
+	0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x86c1, 0x080c,
+	0x8c10, 0x0cb0, 0x6007, 0x0005, 0x0c68, 0x080c, 0xda81, 0x1904,
+	0xca18, 0x080c, 0x32ae, 0x1904, 0xca18, 0x080c, 0xcbb8, 0x1904,
+	0xc6cb, 0x6007, 0x0020, 0x6003, 0x0001, 0x080c, 0x86c1, 0x080c,
+	0x8c10, 0x0005, 0x080c, 0x32ae, 0x1904, 0xca18, 0x6007, 0x0023,
+	0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0005, 0x080c,
+	0xda81, 0x1904, 0xca18, 0x080c, 0x32ae, 0x1904, 0xca18, 0x080c,
+	0xcbb8, 0x1904, 0xc6cb, 0x0016, 0x0026, 0x00e6, 0x2071, 0x0260,
+	0x2c08, 0x2011, 0x181f, 0x2214, 0x703c, 0x9206, 0x11e0, 0x2011,
+	0x181e, 0x2214, 0x7038, 0x9084, 0x00ff, 0x9206, 0x11a0, 0x7240,
+	0x080c, 0xbe25, 0x0570, 0x2260, 0x6008, 0x9086, 0xffff, 0x0120,
+	0x7244, 0x6008, 0x9206, 0x1528, 0x6020, 0x9086, 0x0007, 0x1508,
+	0x080c, 0xa0e3, 0x04a0, 0x7244, 0x9286, 0xffff, 0x0180, 0x2c08,
+	0x080c, 0xbe25, 0x01b0, 0x2260, 0x7240, 0x6008, 0x9206, 0x1188,
+	0x6010, 0x9190, 0x0004, 0x2214, 0x9206, 0x01b8, 0x0050, 0x7240,
+	0x2c08, 0x9006, 0x080c, 0xd857, 0x1180, 0x7244, 0x9286, 0xffff,
+	0x01b0, 0x2160, 0x6007, 0x0026, 0x6017, 0x1700, 0x7214, 0x9296,
+	0xffff, 0x1180, 0x6007, 0x0025, 0x0068, 0x6020, 0x9086, 0x0007,
+	0x1d80, 0x6004, 0x9086, 0x0024, 0x1110, 0x080c, 0xa0e3, 0x2160,
+	0x6007, 0x0025, 0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10,
+	0x00ee, 0x002e, 0x001e, 0x0005, 0x2001, 0x0001, 0x080c, 0x63dc,
+	0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019, 0x1805,
+	0x2011, 0x0276, 0x080c, 0xb0bc, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0120, 0x6007, 0x0031, 0x0804, 0xc7e2, 0x080c, 0xad24, 0x080c,
+	0x7207, 0x1190, 0x0006, 0x0026, 0x0036, 0x080c, 0x7221, 0x1138,
+	0x080c, 0x7504, 0x080c, 0x5f2b, 0x080c, 0x7127, 0x0010, 0x080c,
+	0x71df, 0x003e, 0x002e, 0x000e, 0x0005, 0x080c, 0x32ae, 0x1904,
+	0xca18, 0x080c, 0xcbb8, 0x1904, 0xc6cb, 0x6106, 0x080c, 0xcbd4,
+	0x1120, 0x6007, 0x002b, 0x0804, 0xc7e2, 0x6007, 0x002c, 0x0804,
+	0xc7e2, 0x080c, 0xda81, 0x1904, 0xca18, 0x080c, 0x32ae, 0x1904,
+	0xca18, 0x080c, 0xcbb8, 0x1904, 0xc6cb, 0x6106, 0x080c, 0xcbd9,
+	0x1120, 0x6007, 0x002e, 0x0804, 0xc7e2, 0x6007, 0x002f, 0x0804,
+	0xc7e2, 0x080c, 0x32ae, 0x1904, 0xca18, 0x00e6, 0x00d6, 0x00c6,
+	0x6010, 0x2058, 0xb904, 0x9184, 0x00ff, 0x9086, 0x0006, 0x0158,
+	0x9184, 0xff00, 0x8007, 0x9086, 0x0006, 0x0128, 0x00ce, 0x00de,
+	0x00ee, 0x0804, 0xc7e9, 0x080c, 0x55df, 0xd0e4, 0x0904, 0xc963,
+	0x2071, 0x026c, 0x7010, 0x603a, 0x7014, 0x603e, 0x7108, 0x720c,
+	0x080c, 0x67bf, 0x0140, 0x6010, 0x2058, 0xb810, 0x9106, 0x1118,
+	0xb814, 0x9206, 0x0510, 0x080c, 0x67bb, 0x15b8, 0x2069, 0x1800,
+	0x687c, 0x9206, 0x1590, 0x6878, 0x9106, 0x1578, 0x7210, 0x080c,
+	0xbe25, 0x0590, 0x080c, 0xcaa3, 0x0578, 0x080c, 0xd901, 0x0560,
+	0x622e, 0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x8679, 0x080c,
+	0x8c10, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x7214, 0x9286, 0xffff,
+	0x0150, 0x080c, 0xbe25, 0x01c0, 0x9280, 0x0002, 0x2004, 0x7110,
+	0x9106, 0x1190, 0x08e0, 0x7210, 0x2c08, 0x9085, 0x0001, 0x080c,
+	0xd857, 0x2c10, 0x2160, 0x0140, 0x0890, 0x6007, 0x0037, 0x602f,
+	0x0009, 0x6017, 0x1500, 0x08b8, 0x6007, 0x0037, 0x602f, 0x0003,
+	0x6017, 0x1700, 0x0880, 0x6007, 0x0012, 0x0868, 0x080c, 0x32ae,
+	0x1904, 0xca18, 0x6010, 0x2058, 0xb804, 0x9084, 0xff00, 0x8007,
+	0x9086, 0x0006, 0x1904, 0xc7e9, 0x00e6, 0x00d6, 0x00c6, 0x080c,
+	0x55df, 0xd0e4, 0x0904, 0xc9db, 0x2069, 0x1800, 0x2071, 0x026c,
+	0x7008, 0x603a, 0x720c, 0x623e, 0x9286, 0xffff, 0x1150, 0x7208,
+	0x00c6, 0x2c08, 0x9085, 0x0001, 0x080c, 0xd857, 0x2c10, 0x00ce,
+	0x05e8, 0x080c, 0xbe25, 0x05d0, 0x7108, 0x9280, 0x0002, 0x2004,
+	0x9106, 0x15a0, 0x00c6, 0x0026, 0x2260, 0x080c, 0xba49, 0x002e,
+	0x00ce, 0x7118, 0x918c, 0xff00, 0x810f, 0x9186, 0x0001, 0x0178,
+	0x9186, 0x0005, 0x0118, 0x9186, 0x0007, 0x1198, 0x9280, 0x0005,
+	0x2004, 0x9005, 0x0170, 0x080c, 0xcaa3, 0x0904, 0xc95c, 0x0056,
+	0x7510, 0x7614, 0x080c, 0xd91a, 0x005e, 0x00ce, 0x00de, 0x00ee,
+	0x0005, 0x6007, 0x003b, 0x602f, 0x0009, 0x6017, 0x2a00, 0x6003,
+	0x0001, 0x080c, 0x8679, 0x080c, 0x8c10, 0x0c78, 0x6007, 0x003b,
+	0x602f, 0x0003, 0x6017, 0x0300, 0x6003, 0x0001, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x0c10, 0x6007, 0x003b, 0x602f, 0x000b, 0x6017,
+	0x0000, 0x0804, 0xc933, 0x00e6, 0x0026, 0x080c, 0x6781, 0x0550,
+	0x080c, 0x676a, 0x080c, 0xdaf3, 0x1518, 0x2071, 0x1800, 0x70d8,
+	0x9085, 0x0003, 0x70da, 0x00f6, 0x2079, 0x0100, 0x72ac, 0x9284,
+	0x00ff, 0x707a, 0x78e6, 0x9284, 0xff00, 0x727c, 0x9205, 0x707e,
+	0x78ea, 0x00fe, 0x70e3, 0x0000, 0x080c, 0x67bf, 0x0120, 0x2011,
+	0x19d8, 0x2013, 0x07d0, 0xd0ac, 0x1128, 0x080c, 0x2f6c, 0x0010,
+	0x080c, 0xdb25, 0x002e, 0x00ee, 0x080c, 0xa0e3, 0x0804, 0xc7e8,
+	0x080c, 0xa0e3, 0x0005, 0x2600, 0x0002, 0xca2f, 0xca2f, 0xca2f,
+	0xca2f, 0xca2f, 0xca31, 0xca2f, 0xca2f, 0xca2f, 0xca2f, 0xca4e,
+	0xca2f, 0xca2f, 0xca2f, 0xca60, 0xca6d, 0xca9e, 0xca2f, 0x080c,
+	0x0dfa, 0x080c, 0xda81, 0x1d20, 0x080c, 0x32ae, 0x1d08, 0x080c,
+	0xcbb8, 0x1148, 0x7038, 0x6016, 0x6007, 0x0045, 0x6003, 0x0001,
+	0x080c, 0x86c1, 0x0005, 0x080c, 0x318b, 0x080c, 0xc54e, 0x6007,
+	0x0001, 0x6003, 0x0001, 0x080c, 0x86c1, 0x0005, 0x080c, 0xda81,
+	0x1938, 0x080c, 0x32ae, 0x1920, 0x080c, 0xcbb8, 0x1d60, 0x703c,
+	0x6016, 0x6007, 0x004a, 0x6003, 0x0001, 0x080c, 0x86c1, 0x0005,
+	0x080c, 0xcac0, 0x0904, 0xca18, 0x6007, 0x004e, 0x6003, 0x0001,
+	0x080c, 0x86c1, 0x080c, 0x8c10, 0x0005, 0x6007, 0x004f, 0x6017,
+	0x0000, 0x7134, 0x918c, 0x00ff, 0x81ff, 0x0508, 0x9186, 0x0001,
+	0x1160, 0x7140, 0x2001, 0x1995, 0x2004, 0x9106, 0x11b0, 0x7144,
+	0x2001, 0x1996, 0x2004, 0x9106, 0x0190, 0x9186, 0x0002, 0x1168,
+	0x2011, 0x0276, 0x20a9, 0x0004, 0x6010, 0x0096, 0x2048, 0x2019,
+	0x000a, 0x080c, 0xb0d0, 0x009e, 0x0110, 0x6017, 0x0001, 0x6003,
+	0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0005, 0x6007, 0x0050,
+	0x703c, 0x6016, 0x0ca0, 0x0016, 0x00e6, 0x2071, 0x0260, 0x00b6,
+	0x00c6, 0x2260, 0x6010, 0x2058, 0xb8bc, 0xd084, 0x0150, 0x7128,
+	0x6044, 0x9106, 0x1120, 0x712c, 0x6048, 0x9106, 0x0110, 0x9006,
+	0x0010, 0x9085, 0x0001, 0x00ce, 0x00be, 0x00ee, 0x001e, 0x0005,
+	0x0016, 0x0096, 0x0086, 0x00e6, 0x01c6, 0x01d6, 0x0126, 0x2091,
+	0x8000, 0x2071, 0x1800, 0x708c, 0x908a, 0x00f9, 0x16e8, 0x20e1,
+	0x0000, 0x2001, 0x1978, 0x2003, 0x0000, 0x080c, 0x104a, 0x05a0,
+	0x2900, 0x6016, 0x708c, 0x8004, 0xa816, 0x908a, 0x001e, 0x02d0,
+	0xa833, 0x001e, 0x20a9, 0x001e, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x001b, 0x20a0, 0x2001, 0x1978, 0x0016, 0x200c, 0x0471, 0x001e,
+	0x2940, 0x080c, 0x104a, 0x01c0, 0x2900, 0xa006, 0x2100, 0x81ff,
+	0x0180, 0x0c18, 0xa832, 0x20a8, 0xa860, 0x20e8, 0xa85c, 0x9080,
+	0x001b, 0x20a0, 0x2001, 0x1978, 0x0016, 0x200c, 0x00b1, 0x001e,
+	0x0000, 0x9085, 0x0001, 0x0048, 0x2071, 0x1800, 0x708f, 0x0000,
+	0x6014, 0x2048, 0x080c, 0x0fe3, 0x9006, 0x012e, 0x01de, 0x01ce,
+	0x00ee, 0x008e, 0x009e, 0x001e, 0x0005, 0x0006, 0x0016, 0x0026,
+	0x0036, 0x00c6, 0x918c, 0xffff, 0x11a8, 0x080c, 0x22e3, 0x2099,
+	0x026c, 0x2001, 0x0014, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003,
+	0x00f8, 0x20a8, 0x4003, 0x22a8, 0x8108, 0x080c, 0x22e3, 0x2099,
+	0x0260, 0x0ca8, 0x080c, 0x22e3, 0x2061, 0x1978, 0x6004, 0x2098,
+	0x6008, 0x3518, 0x9312, 0x1218, 0x23a8, 0x4003, 0x0048, 0x20a8,
+	0x4003, 0x22a8, 0x8108, 0x080c, 0x22e3, 0x2099, 0x0260, 0x0ca8,
+	0x2061, 0x1978, 0x2019, 0x0280, 0x3300, 0x931e, 0x0110, 0x6006,
+	0x0020, 0x2001, 0x0260, 0x6006, 0x8108, 0x2162, 0x9292, 0x0021,
+	0x9296, 0xffff, 0x620a, 0x00ce, 0x003e, 0x002e, 0x001e, 0x000e,
+	0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00c6, 0x81ff, 0x11b8,
+	0x080c, 0x22fb, 0x20a1, 0x024c, 0x2001, 0x0014, 0x3518, 0x9312,
+	0x1218, 0x23a8, 0x4003, 0x0418, 0x20a8, 0x4003, 0x82ff, 0x01f8,
+	0x22a8, 0x8108, 0x080c, 0x22fb, 0x20a1, 0x0240, 0x0c98, 0x080c,
+	0x22fb, 0x2061, 0x197b, 0x6004, 0x20a0, 0x6008, 0x3518, 0x9312,
+	0x1218, 0x23a8, 0x4003, 0x0058, 0x20a8, 0x4003, 0x82ff, 0x0138,
+	0x22a8, 0x8108, 0x080c, 0x22fb, 0x20a1, 0x0240, 0x0c98, 0x2061,
+	0x197b, 0x2019, 0x0260, 0x3400, 0x931e, 0x0110, 0x6006, 0x0020,
+	0x2001, 0x0240, 0x6006, 0x8108, 0x2162, 0x9292, 0x0021, 0x9296,
+	0xffff, 0x620a, 0x00ce, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x00b6, 0x0066, 0x6610, 0x2658, 0xbe04, 0x96b4, 0xff00, 0x8637,
+	0x9686, 0x0006, 0x0170, 0x9686, 0x0004, 0x0158, 0xbe04, 0x96b4,
+	0x00ff, 0x9686, 0x0006, 0x0128, 0x9686, 0x0004, 0x0110, 0x9085,
+	0x0001, 0x006e, 0x00be, 0x0005, 0x00d6, 0x080c, 0xcc50, 0x00de,
+	0x0005, 0x00d6, 0x080c, 0xcc5d, 0x1520, 0x680c, 0x908c, 0xff00,
+	0x6820, 0x9084, 0x00ff, 0x9115, 0x6216, 0x6824, 0x602e, 0xd1e4,
+	0x0130, 0x9006, 0x080c, 0xdb9d, 0x2009, 0x0001, 0x0078, 0xd1ec,
+	0x0180, 0x6920, 0x918c, 0x00ff, 0x6824, 0x080c, 0x276e, 0x1148,
+	0x2001, 0x0001, 0x080c, 0xdb9d, 0x2110, 0x900e, 0x080c, 0x31d4,
+	0x0018, 0x9085, 0x0001, 0x0008, 0x9006, 0x00de, 0x0005, 0x00b6,
+	0x00c6, 0x080c, 0xa130, 0x05a8, 0x0016, 0x0026, 0x00c6, 0x2011,
+	0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x276e, 0x1578, 0x080c,
+	0x643f, 0x1560, 0xbe12, 0xbd16, 0x00ce, 0x002e, 0x001e, 0x2b00,
+	0x6012, 0x080c, 0xda81, 0x11d8, 0x080c, 0x32ae, 0x11c0, 0x080c,
+	0xcbb8, 0x0510, 0x2001, 0x0007, 0x080c, 0x63f0, 0x2001, 0x0007,
+	0x080c, 0x641c, 0x6017, 0x0000, 0x6023, 0x0001, 0x6007, 0x0001,
+	0x6003, 0x0001, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x0010, 0x080c,
+	0xa0e3, 0x9085, 0x0001, 0x00ce, 0x00be, 0x0005, 0x080c, 0xa0e3,
+	0x00ce, 0x002e, 0x001e, 0x0ca8, 0x080c, 0xa0e3, 0x9006, 0x0c98,
+	0x2069, 0x026d, 0x6800, 0x9082, 0x0010, 0x1228, 0x6017, 0x0000,
+	0x9085, 0x0001, 0x0008, 0x9006, 0x0005, 0x6017, 0x0000, 0x2069,
+	0x026c, 0x6808, 0x9084, 0xff00, 0x9086, 0x0800, 0x1190, 0x6904,
+	0x9186, 0x0018, 0x0118, 0x9186, 0x0014, 0x1158, 0x810f, 0x6800,
+	0x9084, 0x00ff, 0x910d, 0x615a, 0x908e, 0x0014, 0x0110, 0x908e,
+	0x0010, 0x0005, 0x6004, 0x90b2, 0x0053, 0x1a0c, 0x0dfa, 0x91b6,
+	0x0013, 0x1130, 0x2008, 0x91b2, 0x0040, 0x1a04, 0xcda5, 0x0092,
+	0x91b6, 0x0027, 0x0120, 0x91b6, 0x0014, 0x190c, 0x0dfa, 0x2001,
+	0x0007, 0x080c, 0x641c, 0x080c, 0x8b04, 0x080c, 0xa113, 0x080c,
+	0x8c10, 0x0005, 0xccda, 0xccdc, 0xccda, 0xccda, 0xccda, 0xccdc,
+	0xcceb, 0xcd9e, 0xcd3d, 0xcd9e, 0xcd4f, 0xcd9e, 0xcceb, 0xcd9e,
+	0xcd96, 0xcd9e, 0xcd96, 0xcd9e, 0xcd9e, 0xccda, 0xccda, 0xccda,
+	0xccda, 0xccda, 0xccda, 0xccda, 0xccda, 0xccda, 0xccda, 0xccda,
+	0xccdc, 0xccda, 0xcd9e, 0xccda, 0xccda, 0xcd9e, 0xccda, 0xcd9b,
+	0xcd9e, 0xccda, 0xccda, 0xccda, 0xccda, 0xcd9e, 0xcd9e, 0xccda,
+	0xcd9e, 0xcd9e, 0xccda, 0xcce6, 0xccda, 0xccda, 0xccda, 0xccda,
+	0xcd9a, 0xcd9e, 0xccda, 0xccda, 0xcd9e, 0xcd9e, 0xccda, 0xccda,
+	0xccda, 0xccda, 0x080c, 0x0dfa, 0x080c, 0x8b04, 0x080c, 0xc551,
+	0x6003, 0x0002, 0x080c, 0x8c10, 0x0804, 0xcda4, 0x9006, 0x080c,
+	0x63dc, 0x0804, 0xcd9e, 0x080c, 0x67bb, 0x1904, 0xcd9e, 0x9006,
+	0x080c, 0x63dc, 0x6010, 0x2058, 0xb810, 0x9086, 0x00ff, 0x1140,
+	0x00f6, 0x2079, 0x1800, 0x78a4, 0x8000, 0x78a6, 0x00fe, 0x0428,
+	0x6010, 0x2058, 0xb8b0, 0x9005, 0x1178, 0x080c, 0xc539, 0x1904,
+	0xcd9e, 0x0036, 0x0046, 0xbba0, 0x2021, 0x0007, 0x080c, 0x4cbc,
+	0x004e, 0x003e, 0x0804, 0xcd9e, 0x080c, 0x32df, 0x1904, 0xcd9e,
+	0x2001, 0x1800, 0x2004, 0x9086, 0x0002, 0x1138, 0x00f6, 0x2079,
+	0x1800, 0x78a4, 0x8000, 0x78a6, 0x00fe, 0x2001, 0x0002, 0x080c,
+	0x63f0, 0x080c, 0x8b04, 0x6023, 0x0001, 0x6003, 0x0001, 0x6007,
+	0x0002, 0x080c, 0x86c1, 0x080c, 0x8c10, 0x6110, 0x2158, 0x2009,
+	0x0001, 0x080c, 0x82e8, 0x0804, 0xcda4, 0x6610, 0x2658, 0xbe04,
+	0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x0904, 0xcd9e, 0x9686,
+	0x0004, 0x0904, 0xcd9e, 0x2001, 0x0004, 0x0804, 0xcd9c, 0x2001,
+	0x1800, 0x2004, 0x9086, 0x0003, 0x1158, 0x0036, 0x0046, 0x6010,
+	0x2058, 0xbba0, 0x2021, 0x0006, 0x080c, 0x4cbc, 0x004e, 0x003e,
+	0x2001, 0x0006, 0x080c, 0xcdc2, 0x6610, 0x2658, 0xbe04, 0x0066,
+	0x96b4, 0xff00, 0x8637, 0x9686, 0x0006, 0x006e, 0x0168, 0x2001,
+	0x0006, 0x080c, 0x641c, 0x9284, 0x00ff, 0x908e, 0x0007, 0x1120,
+	0x2001, 0x0006, 0x080c, 0x63f0, 0x080c, 0x67bb, 0x11f8, 0x2001,
+	0x1836, 0x2004, 0xd0a4, 0x01d0, 0xbe04, 0x96b4, 0x00ff, 0x9686,
+	0x0006, 0x01a0, 0x00f6, 0x2079, 0x1800, 0x78a4, 0x8000, 0x78a6,
+	0x00fe, 0x0804, 0xcd25, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006,
+	0x0449, 0x0020, 0x0018, 0x0010, 0x080c, 0x641c, 0x080c, 0x8b04,
+	0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0005, 0x2600, 0x0002, 0xcdb9,
+	0xcdb9, 0xcdb9, 0xcdb9, 0xcdb9, 0xcdbb, 0xcdb9, 0xcdb9, 0xcdb9,
+	0xcdb9, 0xcdbb, 0xcdb9, 0xcdb9, 0xcdb9, 0xcdbb, 0xcdbb, 0xcdbb,
+	0xcdbb, 0x080c, 0x0dfa, 0x080c, 0x8b04, 0x080c, 0xa0e3, 0x080c,
+	0x8c10, 0x0005, 0x0016, 0x00b6, 0x00d6, 0x6110, 0x2158, 0xb900,
+	0xd184, 0x0138, 0x080c, 0x63f0, 0x9006, 0x080c, 0x63dc, 0x080c,
+	0x31b4, 0x00de, 0x00be, 0x001e, 0x0005, 0x6610, 0x2658, 0xb804,
+	0x9084, 0xff00, 0x8007, 0x90b2, 0x000c, 0x1a0c, 0x0dfa, 0x91b6,
+	0x0015, 0x1110, 0x003b, 0x0028, 0x91b6, 0x0016, 0x190c, 0x0dfa,
+	0x006b, 0x0005, 0xab62, 0xab62, 0xab62, 0xab62, 0xce57, 0xab62,
+	0xce41, 0xce02, 0xab62, 0xab62, 0xab62, 0xab62, 0xab62, 0xab62,
+	0xab62, 0xab62, 0xce57, 0xab62, 0xce41, 0xce48, 0xab62, 0xab62,
+	0xab62, 0xab62, 0x00f6, 0x080c, 0x67bb, 0x11d8, 0x080c, 0xc539,
+	0x11c0, 0x6010, 0x905d, 0x01a8, 0xb8b0, 0x9005, 0x0190, 0x9006,
+	0x080c, 0x63dc, 0x2001, 0x0002, 0x080c, 0x63f0, 0x6023, 0x0001,
+	0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x86c1, 0x080c, 0x8c10,
+	0x00f0, 0x2011, 0x0263, 0x2204, 0x8211, 0x220c, 0x080c, 0x276e,
+	0x11b0, 0x080c, 0x649f, 0x0118, 0x080c, 0xa0e3, 0x0080, 0xb810,
+	0x0006, 0xb814, 0x0006, 0xb8b0, 0x0006, 0x080c, 0x5f45, 0x000e,
+	0xb8b2, 0x000e, 0xb816, 0x000e, 0xb812, 0x080c, 0xa0e3, 0x00fe,
+	0x0005, 0x6604, 0x96b6, 0x001e, 0x1110, 0x080c, 0xa0e3, 0x0005,
+	0x080c, 0xaf48, 0x1148, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c,
+	0x86c1, 0x080c, 0x8c10, 0x0010, 0x080c, 0xa0e3, 0x0005, 0x0804,
+	0xa0e3, 0x6004, 0x908a, 0x0053, 0x1a0c, 0x0dfa, 0x080c, 0x8b04,
+	0x080c, 0xa113, 0x080c, 0x8c10, 0x0005, 0x9182, 0x0040, 0x0002,
+	0xce7c, 0xce7c, 0xce7c, 0xce7c, 0xce7e, 0xce7c, 0xce7c, 0xce7c,
+	0xce7c, 0xce7c, 0xce7c, 0xce7c, 0xce7c, 0xce7c, 0xce7c, 0xce7c,
+	0xce7c, 0xce7c, 0xce7c, 0xce7c, 0x080c, 0x0dfa, 0x0096, 0x00b6,
+	0x00d6, 0x00e6, 0x00f6, 0x0046, 0x0026, 0x6210, 0x2258, 0xb8ac,
+	0x9005, 0x11a8, 0x6106, 0x2071, 0x0260, 0x7444, 0x94a4, 0xff00,
+	0x0904, 0xcee4, 0x080c, 0xdb91, 0x1170, 0x9486, 0x2000, 0x1158,
+	0x2009, 0x0001, 0x2011, 0x0200, 0x080c, 0x84d1, 0x0020, 0x9026,
+	0x080c, 0xdac6, 0x0c38, 0x080c, 0x1031, 0x090c, 0x0dfa, 0x6003,
+	0x0007, 0xa867, 0x010d, 0x9006, 0xa802, 0xa86a, 0xac8a, 0x2c00,
+	0xa88e, 0x6008, 0xa8e2, 0x6010, 0x2058, 0xb8a0, 0x7130, 0xa97a,
+	0x0016, 0xa876, 0xa87f, 0x0000, 0xa883, 0x0000, 0xa887, 0x0036,
+	0x080c, 0x6ae9, 0x001e, 0x080c, 0xdb91, 0x1904, 0xcf44, 0x9486,
+	0x2000, 0x1130, 0x2019, 0x0017, 0x080c, 0xd801, 0x0804, 0xcf44,
+	0x9486, 0x0200, 0x1120, 0x080c, 0xd79d, 0x0804, 0xcf44, 0x9486,
+	0x0400, 0x0120, 0x9486, 0x1000, 0x1904, 0xcf44, 0x2019, 0x0002,
+	0x080c, 0xd7b8, 0x0804, 0xcf44, 0x2069, 0x1a48, 0x6a00, 0xd284,
+	0x0904, 0xcfae, 0x9284, 0x0300, 0x1904, 0xcfa7, 0x6804, 0x9005,
+	0x0904, 0xcf8f, 0x2d78, 0x6003, 0x0007, 0x080c, 0x104a, 0x0904,
+	0xcf50, 0x7800, 0xd08c, 0x1118, 0x7804, 0x8001, 0x7806, 0x6017,
+	0x0000, 0x2001, 0x180f, 0x2004, 0xd084, 0x1904, 0xcfb2, 0x9006,
+	0xa802, 0xa867, 0x0116, 0xa86a, 0x6008, 0xa8e2, 0x2c00, 0xa87a,
+	0x6010, 0x2058, 0xb8a0, 0x7130, 0xa9b6, 0xa876, 0xb928, 0xa9ba,
+	0xb92c, 0xa9be, 0xb930, 0xa9c2, 0xb934, 0xa9c6, 0xa883, 0x003d,
+	0x7044, 0x9084, 0x0003, 0x9080, 0xcf4c, 0x2005, 0xa87e, 0x20a9,
+	0x000a, 0x2001, 0x0270, 0xaa5c, 0x9290, 0x0021, 0x2009, 0x0205,
+	0x200b, 0x0080, 0x20e1, 0x0000, 0xab60, 0x23e8, 0x2098, 0x22a0,
+	0x4003, 0x200b, 0x0000, 0x2001, 0x027a, 0x200c, 0xa9b2, 0x8000,
+	0x200c, 0xa9ae, 0x080c, 0x6ae9, 0x002e, 0x004e, 0x00fe, 0x00ee,
+	0x00de, 0x00be, 0x009e, 0x0005, 0x0000, 0x0080, 0x0040, 0x0000,
+	0x2001, 0x1810, 0x2004, 0xd084, 0x0120, 0x080c, 0x1031, 0x1904,
+	0xcef9, 0x6017, 0xf100, 0x6003, 0x0001, 0x6007, 0x0041, 0x080c,
+	0x8679, 0x080c, 0x8c10, 0x0c00, 0x2069, 0x0260, 0x6848, 0x9084,
+	0xff00, 0x9086, 0x1200, 0x1198, 0x686c, 0x9084, 0x00ff, 0x0016,
+	0x6114, 0x918c, 0xf700, 0x910d, 0x6116, 0x001e, 0x6003, 0x0001,
+	0x6007, 0x0043, 0x080c, 0x8679, 0x080c, 0x8c10, 0x0828, 0x6868,
+	0x602e, 0x686c, 0x6032, 0x6017, 0xf200, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x8679, 0x080c, 0x8c10, 0x0804, 0xcf44, 0x2001,
+	0x180e, 0x2004, 0xd0ec, 0x0120, 0x2011, 0x8049, 0x080c, 0x4b1f,
+	0x6017, 0xf300, 0x0010, 0x6017, 0xf100, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x8679, 0x080c, 0x8c10, 0x0804, 0xcf44, 0x6017,
+	0xf500, 0x0c98, 0x6017, 0xf600, 0x0804, 0xcf64, 0x6017, 0xf200,
+	0x0804, 0xcf64, 0xa867, 0x0146, 0xa86b, 0x0000, 0x6008, 0xa886,
+	0x2c00, 0xa87a, 0x7044, 0x9084, 0x0003, 0x9080, 0xcf4c, 0x2005,
+	0xa87e, 0x2928, 0x6010, 0x2058, 0xb8a0, 0xa876, 0xb828, 0xa88a,
+	0xb82c, 0xa88e, 0xb830, 0xa892, 0xb834, 0xa896, 0xa883, 0x003d,
+	0x2009, 0x0205, 0x2104, 0x9085, 0x0080, 0x200a, 0x20e1, 0x0000,
+	0x2011, 0x0210, 0x2214, 0x9294, 0x0fff, 0xaaa2, 0x9282, 0x0111,
+	0x1a0c, 0x0dfa, 0x8210, 0x821c, 0x2001, 0x026c, 0x2098, 0xa860,
+	0x20e8, 0xa85c, 0x9080, 0x0029, 0x20a0, 0x2011, 0xd02e, 0x2041,
+	0x0001, 0x223d, 0x9784, 0x00ff, 0x9322, 0x1208, 0x2300, 0x20a8,
+	0x4003, 0x931a, 0x0530, 0x8210, 0xd7fc, 0x1130, 0x8d68, 0x2d0a,
+	0x2001, 0x0260, 0x2098, 0x0c68, 0x2950, 0x080c, 0x104a, 0x0170,
+	0x2900, 0xb002, 0xa867, 0x0147, 0xa86b, 0x0000, 0xa860, 0x20e8,
+	0xa85c, 0x9080, 0x001b, 0x20a0, 0x8840, 0x08d8, 0x2548, 0xa800,
+	0x902d, 0x0118, 0x080c, 0x1063, 0x0cc8, 0x080c, 0x1063, 0x0804,
+	0xcf50, 0x2548, 0x8847, 0x9885, 0x0046, 0xa866, 0x2009, 0x0205,
+	0x200b, 0x0000, 0x080c, 0xd830, 0x0804, 0xcf44, 0x8010, 0x0004,
+	0x801a, 0x0006, 0x8018, 0x0008, 0x8016, 0x000a, 0x8014, 0x9186,
+	0x0013, 0x1160, 0x6004, 0x908a, 0x0054, 0x1a0c, 0x0dfa, 0x9082,
+	0x0040, 0x0a0c, 0x0dfa, 0x2008, 0x0804, 0xd0e0, 0x9186, 0x0051,
+	0x0108, 0x00c0, 0x2001, 0x0109, 0x2004, 0xd084, 0x0904, 0xd090,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x8563,
+	0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0x9086, 0x0002, 0x1580,
+	0x0804, 0xd129, 0x9186, 0x0027, 0x0530, 0x9186, 0x0048, 0x0128,
+	0x9186, 0x0014, 0x0500, 0x190c, 0x0dfa, 0x2001, 0x0109, 0x2004,
+	0xd084, 0x01f0, 0x00c6, 0x0126, 0x2091, 0x2800, 0x00c6, 0x2061,
+	0x0100, 0x0006, 0x0016, 0x0026, 0x080c, 0x8563, 0x002e, 0x001e,
+	0x000e, 0x00ce, 0x012e, 0x00ce, 0x6000, 0x9086, 0x0004, 0x190c,
+	0x0dfa, 0x0804, 0xd20c, 0x6004, 0x9082, 0x0040, 0x2008, 0x001a,
+	0x080c, 0xa178, 0x0005, 0xd0a7, 0xd0a9, 0xd0a9, 0xd0d0, 0xd0a7,
+	0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7,
+	0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0xd0a7, 0x080c,
+	0x0dfa, 0x080c, 0x8b04, 0x080c, 0x8c10, 0x0036, 0x0096, 0x6014,
+	0x904d, 0x01d8, 0x080c, 0xbe37, 0x01c0, 0x6003, 0x0002, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x1178, 0x2019, 0x0004,
+	0x080c, 0xd830, 0x6017, 0x0000, 0x6018, 0x9005, 0x1120, 0x2001,
+	0x195f, 0x2004, 0x601a, 0x6003, 0x0007, 0x009e, 0x003e, 0x0005,
+	0x0096, 0x080c, 0x8b04, 0x080c, 0x8c10, 0x080c, 0xbe37, 0x0120,
+	0x6014, 0x2048, 0x080c, 0x1063, 0x080c, 0xa113, 0x009e, 0x0005,
+	0x0002, 0xd0f5, 0xd10c, 0xd0f7, 0xd123, 0xd0f5, 0xd0f5, 0xd0f5,
+	0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5,
+	0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0xd0f5, 0x080c, 0x0dfa, 0x0096,
+	0x080c, 0x8b04, 0x6014, 0x2048, 0xa87c, 0xd0b4, 0x0138, 0x6003,
+	0x0007, 0x2009, 0x0043, 0x080c, 0xa15d, 0x0010, 0x6003, 0x0004,
+	0x080c, 0x8c10, 0x009e, 0x0005, 0x080c, 0x8b04, 0x080c, 0xbe37,
+	0x0138, 0x6114, 0x0096, 0x2148, 0xa97c, 0x009e, 0xd1ec, 0x1138,
+	0x080c, 0x84a6, 0x080c, 0xa0e3, 0x080c, 0x8c10, 0x0005, 0x080c,
+	0xda8a, 0x0db0, 0x0cc8, 0x080c, 0x8b04, 0x2009, 0x0041, 0x0804,
+	0xd294, 0x9182, 0x0040, 0x0002, 0xd140, 0xd142, 0xd140, 0xd140,
+	0xd140, 0xd140, 0xd140, 0xd140, 0xd140, 0xd140, 0xd140, 0xd140,
+	0xd140, 0xd140, 0xd140, 0xd140, 0xd140, 0xd143, 0xd140, 0xd140,
+	0x080c, 0x0dfa, 0x0005, 0x00d6, 0x080c, 0x84a6, 0x00de, 0x080c,
+	0xdae2, 0x080c, 0xa0e3, 0x0005, 0x9182, 0x0040, 0x0002, 0xd163,
+	0xd163, 0xd163, 0xd163, 0xd163, 0xd163, 0xd163, 0xd163, 0xd163,
+	0xd165, 0xd1d4, 0xd163, 0xd163, 0xd163, 0xd163, 0xd1d4, 0xd163,
+	0xd163, 0xd163, 0xd163, 0x080c, 0x0dfa, 0x2001, 0x0105, 0x2004,
+	0x9084, 0x1800, 0x01c8, 0x2001, 0x0132, 0x200c, 0x2001, 0x0131,
+	0x2004, 0x9105, 0x1904, 0xd1d4, 0x2009, 0x180c, 0x2104, 0xd0d4,
+	0x0904, 0xd1d4, 0xc0d4, 0x200a, 0x2009, 0x0105, 0x2104, 0x9084,
+	0xe7fd, 0x9085, 0x0010, 0x200a, 0x2001, 0x187b, 0x2004, 0xd0e4,
+	0x1528, 0x603b, 0x0000, 0x080c, 0x8bc0, 0x6014, 0x0096, 0x2048,
+	0xa87c, 0xd0fc, 0x0188, 0x908c, 0x0003, 0x918e, 0x0002, 0x0508,
+	0x2001, 0x180c, 0x2004, 0xd0d4, 0x11e0, 0x080c, 0x8ced, 0x2009,
+	0x0041, 0x009e, 0x0804, 0xd294, 0x080c, 0x8ced, 0x6003, 0x0007,
+	0x601b, 0x0000, 0x080c, 0x84a6, 0x009e, 0x0005, 0x2001, 0x0100,
+	0x2004, 0x9082, 0x0005, 0x0aa8, 0x2001, 0x011f, 0x2004, 0x603a,
+	0x0890, 0x2001, 0x180c, 0x200c, 0xc1d4, 0x2102, 0xd1cc, 0x0110,
+	0x080c, 0x2bca, 0x080c, 0x8ced, 0x6014, 0x2048, 0xa97c, 0xd1ec,
+	0x1130, 0x080c, 0x84a6, 0x080c, 0xa0e3, 0x009e, 0x0005, 0x080c,
+	0xda8a, 0x0db8, 0x009e, 0x0005, 0x2001, 0x180c, 0x200c, 0xc1d4,
+	0x2102, 0x0036, 0x080c, 0x8bc0, 0x080c, 0x8ced, 0x6014, 0x0096,
+	0x2048, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0bc, 0x0188,
+	0xa87c, 0x9084, 0x0003, 0x9086, 0x0002, 0x0140, 0xa8ac, 0x6330,
+	0x931a, 0x6332, 0xa8b0, 0x632c, 0x931b, 0x632e, 0x6003, 0x0002,
+	0x0080, 0x2019, 0x0004, 0x080c, 0xd830, 0x6018, 0x9005, 0x1128,
+	0x2001, 0x195f, 0x2004, 0x8003, 0x601a, 0x6017, 0x0000, 0x6003,
+	0x0007, 0x009e, 0x003e, 0x0005, 0x9182, 0x0040, 0x0002, 0xd223,
+	0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd225,
+	0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd223, 0xd223,
+	0xd223, 0xd223, 0xd270, 0x080c, 0x0dfa, 0x6014, 0x0096, 0x2048,
+	0xa834, 0xaa38, 0x6110, 0x00b6, 0x2158, 0xb900, 0x00be, 0xd1bc,
+	0x1190, 0x920d, 0x1518, 0xa87c, 0xd0fc, 0x0128, 0x2009, 0x0041,
+	0x009e, 0x0804, 0xd294, 0x6003, 0x0007, 0x601b, 0x0000, 0x080c,
+	0x84a6, 0x009e, 0x0005, 0x6124, 0xd1f4, 0x1d58, 0x0006, 0x0046,
+	0xacac, 0x9422, 0xa9b0, 0x2200, 0x910b, 0x6030, 0x9420, 0x6432,
+	0x602c, 0x9109, 0x612e, 0x004e, 0x000e, 0x08d8, 0x6110, 0x00b6,
+	0x2158, 0xb900, 0x00be, 0xd1bc, 0x1178, 0x2009, 0x180e, 0x210c,
+	0xd19c, 0x0118, 0x6003, 0x0007, 0x0010, 0x6003, 0x0006, 0x00e9,
+	0x080c, 0x84a8, 0x009e, 0x0005, 0x6003, 0x0002, 0x009e, 0x0005,
+	0x6024, 0xd0f4, 0x0128, 0x080c, 0x1582, 0x1904, 0xd225, 0x0005,
+	0x6014, 0x0096, 0x2048, 0xa834, 0xa938, 0x009e, 0x9105, 0x1120,
+	0x080c, 0x1582, 0x1904, 0xd225, 0x0005, 0xd2fc, 0x0140, 0x8002,
+	0x8000, 0x8212, 0x9291, 0x0000, 0x2009, 0x0009, 0x0010, 0x2009,
+	0x0015, 0xaa9a, 0xa896, 0x0005, 0x9182, 0x0040, 0x0208, 0x0062,
+	0x9186, 0x0013, 0x0120, 0x9186, 0x0014, 0x190c, 0x0dfa, 0x6024,
+	0xd0dc, 0x090c, 0x0dfa, 0x0005, 0xd2b8, 0xd2c4, 0xd2d0, 0xd2dc,
+	0xd2b8, 0xd2b8, 0xd2b8, 0xd2b8, 0xd2bf, 0xd2ba, 0xd2ba, 0xd2b8,
+	0xd2b8, 0xd2b8, 0xd2b8, 0xd2ba, 0xd2b8, 0xd2ba, 0xd2b8, 0xd2bf,
+	0x080c, 0x0dfa, 0x6024, 0xd0dc, 0x090c, 0x0dfa, 0x0005, 0x6014,
+	0x9005, 0x190c, 0x0dfa, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x8679, 0x0126, 0x2091, 0x8000, 0x080c, 0x8c10, 0x012e, 0x0005,
+	0x6003, 0x0001, 0x6106, 0x080c, 0x8679, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x8c10, 0x012e, 0x0005, 0x6003, 0x0003, 0x6106, 0x2c10,
+	0x080c, 0x1afe, 0x0126, 0x2091, 0x8000, 0x080c, 0x86de, 0x080c,
+	0x8ced, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x0096,
+	0x9182, 0x0040, 0x0023, 0x009e, 0x003e, 0x012e, 0x0005, 0xd30b,
+	0xd30d, 0xd31f, 0xd339, 0xd30b, 0xd30b, 0xd30b, 0xd30b, 0xd30b,
+	0xd30b, 0xd30b, 0xd30b, 0xd30b, 0xd30b, 0xd30b, 0xd30b, 0xd30b,
+	0xd30b, 0xd30b, 0xd30b, 0x080c, 0x0dfa, 0x6014, 0x2048, 0xa87c,
+	0xd0fc, 0x01f8, 0x909c, 0x0003, 0x939e, 0x0003, 0x01d0, 0x6003,
+	0x0001, 0x6106, 0x080c, 0x8679, 0x080c, 0x8c10, 0x0470, 0x6014,
+	0x2048, 0xa87c, 0xd0fc, 0x0168, 0x909c, 0x0003, 0x939e, 0x0003,
+	0x0140, 0x6003, 0x0001, 0x6106, 0x080c, 0x8679, 0x080c, 0x8c10,
+	0x00e0, 0x901e, 0x6316, 0x631a, 0x2019, 0x0004, 0x080c, 0xd830,
+	0x00a0, 0x6014, 0x2048, 0xa87c, 0xd0fc, 0x0d98, 0x909c, 0x0003,
+	0x939e, 0x0003, 0x0d70, 0x6003, 0x0003, 0x6106, 0x2c10, 0x080c,
+	0x1afe, 0x080c, 0x86de, 0x080c, 0x8ced, 0x0005, 0x080c, 0x8b04,
+	0x6114, 0x81ff, 0x0158, 0x0096, 0x2148, 0x080c, 0xdb2e, 0x0036,
+	0x2019, 0x0029, 0x080c, 0xd830, 0x003e, 0x009e, 0x080c, 0xa113,
+	0x080c, 0x8c10, 0x0005, 0x080c, 0x8bc0, 0x6114, 0x81ff, 0x0158,
+	0x0096, 0x2148, 0x080c, 0xdb2e, 0x0036, 0x2019, 0x0029, 0x080c,
+	0xd830, 0x003e, 0x009e, 0x080c, 0xa113, 0x080c, 0x8ced, 0x0005,
+	0x9182, 0x0085, 0x0002, 0xd38a, 0xd388, 0xd388, 0xd396, 0xd388,
+	0xd388, 0xd388, 0xd388, 0xd388, 0xd388, 0xd388, 0xd388, 0xd388,
+	0x080c, 0x0dfa, 0x6003, 0x000b, 0x6106, 0x080c, 0x8679, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x8c10, 0x012e, 0x0005, 0x0026, 0x00e6,
+	0x080c, 0xda81, 0x0118, 0x080c, 0xa0e3, 0x0450, 0x2071, 0x0260,
+	0x7224, 0x6216, 0x2001, 0x180e, 0x2004, 0xd0e4, 0x0150, 0x6010,
+	0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00, 0x2011, 0x014e, 0x080c,
+	0xa403, 0x7220, 0x080c, 0xd6d6, 0x0118, 0x6007, 0x0086, 0x0040,
+	0x6007, 0x0087, 0x7224, 0x9296, 0xffff, 0x1110, 0x6007, 0x0086,
+	0x6003, 0x0001, 0x080c, 0x8679, 0x080c, 0x8c10, 0x080c, 0x8ced,
+	0x00ee, 0x002e, 0x0005, 0x9186, 0x0013, 0x1160, 0x6004, 0x908a,
+	0x0085, 0x0a0c, 0x0dfa, 0x908a, 0x0092, 0x1a0c, 0x0dfa, 0x9082,
+	0x0085, 0x00a2, 0x9186, 0x0027, 0x0130, 0x9186, 0x0014, 0x0118,
+	0x080c, 0xa178, 0x0050, 0x2001, 0x0007, 0x080c, 0x641c, 0x080c,
+	0x8b04, 0x080c, 0xa113, 0x080c, 0x8c10, 0x0005, 0xd3fb, 0xd3fd,
+	0xd3fd, 0xd3fb, 0xd3fb, 0xd3fb, 0xd3fb, 0xd3fb, 0xd3fb, 0xd3fb,
+	0xd3fb, 0xd3fb, 0xd3fb, 0x080c, 0x0dfa, 0x080c, 0x8b04, 0x080c,
+	0xa113, 0x080c, 0x8c10, 0x0005, 0x9182, 0x0085, 0x0a0c, 0x0dfa,
+	0x9182, 0x0092, 0x1a0c, 0x0dfa, 0x9182, 0x0085, 0x0002, 0xd41c,
+	0xd41c, 0xd41c, 0xd41e, 0xd41c, 0xd41c, 0xd41c, 0xd41c, 0xd41c,
+	0xd41c, 0xd41c, 0xd41c, 0xd41c, 0x080c, 0x0dfa, 0x0005, 0x9186,
+	0x0013, 0x0148, 0x9186, 0x0014, 0x0130, 0x9186, 0x0027, 0x0118,
+	0x080c, 0xa178, 0x0030, 0x080c, 0x8b04, 0x080c, 0xa113, 0x080c,
+	0x8c10, 0x0005, 0x0036, 0x080c, 0xdae2, 0x6043, 0x0000, 0x2019,
+	0x000b, 0x0031, 0x6023, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005,
+	0x0126, 0x0036, 0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x904e,
+	0x080c, 0x9a58, 0x009e, 0x008e, 0x1550, 0x0076, 0x2c38, 0x080c,
+	0x9b03, 0x007e, 0x1520, 0x6000, 0x9086, 0x0000, 0x0500, 0x6020,
+	0x9086, 0x0007, 0x01e0, 0x0096, 0x601c, 0xd084, 0x0140, 0x080c,
+	0xdae2, 0x080c, 0xc551, 0x080c, 0x19b4, 0x6023, 0x0007, 0x6014,
+	0x2048, 0x080c, 0xbe37, 0x0110, 0x080c, 0xd830, 0x009e, 0x6017,
+	0x0000, 0x080c, 0xdae2, 0x6023, 0x0007, 0x080c, 0xc551, 0x003e,
+	0x012e, 0x0005, 0x00f6, 0x00c6, 0x00b6, 0x0036, 0x0156, 0x2079,
+	0x0260, 0x7938, 0x783c, 0x080c, 0x276e, 0x15c8, 0x0016, 0x00c6,
+	0x080c, 0x649f, 0x1590, 0x001e, 0x00c6, 0x2160, 0x080c, 0xc54e,
+	0x00ce, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x9bc9,
+	0x080c, 0x8803, 0x0076, 0x903e, 0x080c, 0x86f1, 0x007e, 0x001e,
+	0x0076, 0x903e, 0x080c, 0xd5f6, 0x007e, 0x0026, 0xba04, 0x9294,
+	0xff00, 0x8217, 0x9286, 0x0006, 0x0118, 0x9286, 0x0004, 0x1118,
+	0xbaa0, 0x080c, 0x3248, 0x002e, 0xbcb0, 0x001e, 0x080c, 0x5f45,
+	0xbe12, 0xbd16, 0xbcb2, 0x9006, 0x0010, 0x00ce, 0x001e, 0x015e,
+	0x003e, 0x00be, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6, 0x00b6,
+	0x0016, 0x2009, 0x1823, 0x2104, 0x9086, 0x0074, 0x1904, 0xd51e,
+	0x2069, 0x0260, 0x6944, 0x9182, 0x0100, 0x06e0, 0x6940, 0x9184,
+	0x8000, 0x0904, 0xd51b, 0x2001, 0x1954, 0x2004, 0x9005, 0x1140,
+	0x6010, 0x2058, 0xb8b0, 0x9005, 0x0118, 0x9184, 0x0800, 0x0598,
+	0x6948, 0x918a, 0x0001, 0x0648, 0x080c, 0xdb96, 0x0118, 0x6978,
+	0xd1fc, 0x11b8, 0x2009, 0x0205, 0x200b, 0x0001, 0x693c, 0x81ff,
+	0x1198, 0x6944, 0x9182, 0x0100, 0x02a8, 0x6940, 0x81ff, 0x1178,
+	0x6948, 0x918a, 0x0001, 0x0288, 0x6950, 0x918a, 0x0001, 0x0298,
+	0x00d0, 0x6017, 0x0100, 0x00a0, 0x6017, 0x0300, 0x0088, 0x6017,
+	0x0500, 0x0070, 0x6017, 0x0700, 0x0058, 0x6017, 0x0900, 0x0040,
+	0x6017, 0x0b00, 0x0028, 0x6017, 0x0f00, 0x0010, 0x6017, 0x2d00,
+	0x9085, 0x0001, 0x0008, 0x9006, 0x001e, 0x00be, 0x00de, 0x00ce,
+	0x0005, 0x00c6, 0x00b6, 0x0026, 0x0036, 0x0156, 0x6210, 0x2258,
+	0xbb04, 0x9394, 0x00ff, 0x9286, 0x0006, 0x0180, 0x9286, 0x0004,
+	0x0168, 0x9394, 0xff00, 0x8217, 0x9286, 0x0006, 0x0138, 0x9286,
+	0x0004, 0x0120, 0x080c, 0x64ae, 0x0804, 0xd585, 0x2011, 0x0276,
+	0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x000a, 0x080c, 0xb0d0,
+	0x009e, 0x15a0, 0x2011, 0x027a, 0x20a9, 0x0004, 0x0096, 0x2b48,
+	0x2019, 0x0006, 0x080c, 0xb0d0, 0x009e, 0x1540, 0x0046, 0x0016,
+	0xbaa0, 0x2220, 0x9006, 0x2009, 0x185c, 0x210c, 0x0038, 0x2009,
+	0x0029, 0x080c, 0xd885, 0xb800, 0xc0e5, 0xb802, 0x2019, 0x0029,
+	0x080c, 0x8803, 0x0076, 0x2039, 0x0000, 0x080c, 0x86f1, 0x2c08,
+	0x080c, 0xd5f6, 0x007e, 0x2001, 0x0007, 0x080c, 0x641c, 0x2001,
+	0x0007, 0x080c, 0x63f0, 0x001e, 0x004e, 0x9006, 0x015e, 0x003e,
+	0x002e, 0x00be, 0x00ce, 0x0005, 0x00d6, 0x2069, 0x026e, 0x6800,
+	0x9086, 0x0800, 0x0118, 0x6017, 0x0000, 0x0008, 0x9006, 0x00de,
+	0x0005, 0x00b6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079,
+	0x026c, 0x7930, 0x7834, 0x080c, 0x276e, 0x11d0, 0x080c, 0x649f,
+	0x11b8, 0x2011, 0x0270, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019,
+	0x000a, 0x080c, 0xb0d0, 0x009e, 0x1158, 0x2011, 0x0274, 0x20a9,
+	0x0004, 0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xb0d0, 0x009e,
+	0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00be, 0x0005, 0x00b6,
+	0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011, 0x0263, 0x2204,
+	0x8211, 0x220c, 0x080c, 0x276e, 0x11d0, 0x080c, 0x649f, 0x11b8,
+	0x2011, 0x0276, 0x20a9, 0x0004, 0x0096, 0x2b48, 0x2019, 0x000a,
+	0x080c, 0xb0d0, 0x009e, 0x1158, 0x2011, 0x027a, 0x20a9, 0x0004,
+	0x0096, 0x2b48, 0x2019, 0x0006, 0x080c, 0xb0d0, 0x009e, 0x015e,
+	0x003e, 0x002e, 0x001e, 0x000e, 0x00be, 0x0005, 0x00e6, 0x00c6,
+	0x0086, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0126, 0x2091,
+	0x8000, 0x2740, 0x2029, 0x19c8, 0x252c, 0x2021, 0x19ce, 0x2424,
+	0x2061, 0x1cd0, 0x2071, 0x1800, 0x7650, 0x7070, 0x81ff, 0x0150,
+	0x0006, 0x9186, 0x1a8a, 0x000e, 0x0128, 0x8001, 0x9602, 0x1a04,
+	0xd68f, 0x0018, 0x9606, 0x0904, 0xd68f, 0x2100, 0x9c06, 0x0904,
+	0xd686, 0x080c, 0xd8c6, 0x1904, 0xd686, 0x080c, 0xdbb3, 0x0904,
+	0xd686, 0x080c, 0xd8b6, 0x0904, 0xd686, 0x6720, 0x9786, 0x0001,
+	0x1148, 0x080c, 0x32df, 0x0904, 0xd6aa, 0x6004, 0x9086, 0x0000,
+	0x1904, 0xd6aa, 0x9786, 0x0004, 0x0904, 0xd6aa, 0x9786, 0x0007,
+	0x0904, 0xd686, 0x2500, 0x9c06, 0x0904, 0xd686, 0x2400, 0x9c06,
+	0x05e8, 0x88ff, 0x0118, 0x6054, 0x9906, 0x15c0, 0x0096, 0x6000,
+	0x9086, 0x0004, 0x1120, 0x0016, 0x080c, 0x19b4, 0x001e, 0x9786,
+	0x000a, 0x0148, 0x080c, 0xc03f, 0x1130, 0x080c, 0xaa81, 0x009e,
+	0x080c, 0xa113, 0x0418, 0x6014, 0x2048, 0x080c, 0xbe37, 0x01d8,
+	0x9786, 0x0003, 0x1570, 0xa867, 0x0103, 0xa87c, 0xd0cc, 0x0130,
+	0x0096, 0xa878, 0x2048, 0x080c, 0x0fe3, 0x009e, 0xab7a, 0xa877,
+	0x0000, 0x080c, 0xdb2e, 0x0016, 0x080c, 0xc12d, 0x080c, 0x6adc,
+	0x001e, 0x080c, 0xc022, 0x009e, 0x080c, 0xa113, 0x9ce0, 0x0018,
+	0x2001, 0x1819, 0x2004, 0x9c02, 0x1210, 0x0804, 0xd60a, 0x012e,
+	0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee,
+	0x0005, 0x9786, 0x0006, 0x1150, 0x9386, 0x0005, 0x0128, 0x080c,
+	0xdb2e, 0x080c, 0xd830, 0x08f8, 0x009e, 0x0c00, 0x9786, 0x000a,
+	0x0968, 0x0808, 0x81ff, 0x09d0, 0x9180, 0x0001, 0x2004, 0x9086,
+	0x0018, 0x0130, 0x9180, 0x0001, 0x2004, 0x9086, 0x002d, 0x1970,
+	0x6000, 0x9086, 0x0002, 0x1950, 0x080c, 0xc02e, 0x0130, 0x080c,
+	0xc03f, 0x1920, 0x080c, 0xaa81, 0x0038, 0x080c, 0x31b4, 0x080c,
+	0xc03f, 0x1110, 0x080c, 0xaa81, 0x080c, 0xa113, 0x0804, 0xd686,
+	0xa864, 0x9084, 0x00ff, 0x9086, 0x0039, 0x0005, 0x00c6, 0x00e6,
+	0x0016, 0x2c08, 0x2170, 0x9006, 0x080c, 0xd857, 0x001e, 0x0120,
+	0x6020, 0x9084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xd6f5,
+	0xd6f5, 0xd6f5, 0xd6f5, 0xd6f5, 0xd6f5, 0xd6f7, 0xd6f5, 0xd6f5,
+	0xd6f5, 0xd6f5, 0xa113, 0xa113, 0xd6f5, 0x9006, 0x0005, 0x0036,
+	0x0046, 0x0016, 0x7010, 0x00b6, 0x2058, 0xbca0, 0x00be, 0x2c00,
+	0x2009, 0x0020, 0x080c, 0xd885, 0x001e, 0x004e, 0x2019, 0x0002,
+	0x080c, 0xd440, 0x003e, 0x9085, 0x0001, 0x0005, 0x0096, 0x080c,
+	0xbe37, 0x0140, 0x6014, 0x904d, 0x080c, 0xba56, 0x687b, 0x0005,
+	0x080c, 0x6ae9, 0x009e, 0x080c, 0xa113, 0x9085, 0x0001, 0x0005,
+	0x2001, 0x0001, 0x080c, 0x63dc, 0x0156, 0x0016, 0x0026, 0x0036,
+	0x20a9, 0x0004, 0x2019, 0x1805, 0x2011, 0x0276, 0x080c, 0xb0bc,
+	0x003e, 0x002e, 0x001e, 0x015e, 0x9005, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x0086, 0x0076, 0x0066, 0x00b6, 0x0126, 0x2091, 0x8000,
+	0x2740, 0x2061, 0x1cd0, 0x2079, 0x0001, 0x8fff, 0x0904, 0xd790,
+	0x2071, 0x1800, 0x7650, 0x7070, 0x8001, 0x9602, 0x1a04, 0xd790,
+	0x88ff, 0x0120, 0x2800, 0x9c06, 0x1590, 0x2078, 0x080c, 0xd8b6,
+	0x0570, 0x2400, 0x9c06, 0x0558, 0x6720, 0x9786, 0x0006, 0x1538,
+	0x9786, 0x0007, 0x0520, 0x88ff, 0x1140, 0x6010, 0x9b06, 0x11f8,
+	0x85ff, 0x0118, 0x6054, 0x9106, 0x11d0, 0x0096, 0x601c, 0xd084,
+	0x0140, 0x080c, 0xdae2, 0x080c, 0xc551, 0x080c, 0x19b4, 0x6023,
+	0x0007, 0x6014, 0x2048, 0x080c, 0xbe37, 0x0120, 0x0046, 0x080c,
+	0xd830, 0x004e, 0x009e, 0x080c, 0xa113, 0x88ff, 0x1198, 0x9ce0,
+	0x0018, 0x2001, 0x1819, 0x2004, 0x9c02, 0x1210, 0x0804, 0xd745,
+	0x9006, 0x012e, 0x00be, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee,
+	0x00fe, 0x0005, 0x98c5, 0x0001, 0x0ca0, 0x00b6, 0x0076, 0x0056,
+	0x0086, 0x9046, 0x2029, 0x0001, 0x2c20, 0x2019, 0x0002, 0x6210,
+	0x2258, 0x0096, 0x904e, 0x080c, 0x9a58, 0x009e, 0x008e, 0x903e,
+	0x080c, 0x9b03, 0x080c, 0xd736, 0x005e, 0x007e, 0x00be, 0x0005,
+	0x00b6, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128,
+	0x20a9, 0x007f, 0x900e, 0x0016, 0x0036, 0x080c, 0x649f, 0x1190,
+	0x0056, 0x0086, 0x9046, 0x2508, 0x2029, 0x0001, 0x0096, 0x904e,
+	0x080c, 0x9a58, 0x009e, 0x008e, 0x903e, 0x080c, 0x9b03, 0x080c,
+	0xd736, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04, 0xd7c3, 0x015e,
+	0x00ce, 0x007e, 0x005e, 0x004e, 0x00be, 0x0005, 0x00b6, 0x0076,
+	0x0056, 0x6210, 0x2258, 0x0086, 0x9046, 0x2029, 0x0001, 0x2019,
+	0x0048, 0x0096, 0x904e, 0x080c, 0x9a58, 0x009e, 0x008e, 0x903e,
+	0x080c, 0x9b03, 0x2c20, 0x080c, 0xd736, 0x005e, 0x007e, 0x00be,
+	0x0005, 0x00b6, 0x0046, 0x0056, 0x0076, 0x00c6, 0x0156, 0x2c20,
+	0x20a9, 0x0800, 0x900e, 0x0016, 0x0036, 0x080c, 0x649f, 0x11a0,
+	0x0086, 0x9046, 0x2828, 0x0046, 0x2021, 0x0001, 0x080c, 0xdac6,
+	0x004e, 0x0096, 0x904e, 0x080c, 0x9a58, 0x009e, 0x008e, 0x903e,
+	0x080c, 0x9b03, 0x080c, 0xd736, 0x003e, 0x001e, 0x8108, 0x1f04,
+	0xd80b, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x00be, 0x0005,
+	0x0016, 0x00f6, 0x080c, 0xbe35, 0x0198, 0xa864, 0x9084, 0x00ff,
+	0x9086, 0x0046, 0x0180, 0xa800, 0x907d, 0x0138, 0xa803, 0x0000,
+	0xab82, 0x080c, 0x6ae9, 0x2f48, 0x0cb0, 0xab82, 0x080c, 0x6ae9,
+	0x00fe, 0x001e, 0x0005, 0xa800, 0x907d, 0x0130, 0xa803, 0x0000,
+	0x080c, 0x6ae9, 0x2f48, 0x0cb8, 0x080c, 0x6ae9, 0x0c88, 0x00e6,
+	0x0046, 0x0036, 0x2061, 0x1cd0, 0x9005, 0x1138, 0x2071, 0x1800,
+	0x7450, 0x7070, 0x8001, 0x9402, 0x12d8, 0x2100, 0x9c06, 0x0168,
+	0x6000, 0x9086, 0x0000, 0x0148, 0x6008, 0x9206, 0x1130, 0x6010,
+	0x91a0, 0x0004, 0x2424, 0x9406, 0x0140, 0x9ce0, 0x0018, 0x2001,
+	0x1819, 0x2004, 0x9c02, 0x1220, 0x0c40, 0x9085, 0x0001, 0x0008,
+	0x9006, 0x003e, 0x004e, 0x00ee, 0x0005, 0x0096, 0x0006, 0x080c,
+	0x1031, 0x000e, 0x090c, 0x0dfa, 0xaae2, 0xa867, 0x010d, 0xa88e,
+	0x0026, 0x2010, 0x080c, 0xbe25, 0x2001, 0x0000, 0x0120, 0x2200,
+	0x9080, 0x0015, 0x2004, 0x002e, 0xa87a, 0x9186, 0x0020, 0x0110,
+	0xa8e3, 0xffff, 0xa986, 0xac76, 0xa87f, 0x0000, 0x2001, 0x1966,
+	0x2004, 0xa882, 0x9006, 0xa802, 0xa86a, 0xa88a, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6ae9, 0x012e, 0x009e, 0x0005, 0x6700, 0x9786,
+	0x0000, 0x0158, 0x9786, 0x0001, 0x0140, 0x9786, 0x000a, 0x0128,
+	0x9786, 0x0009, 0x0110, 0x9085, 0x0001, 0x0005, 0x00e6, 0x6010,
+	0x9075, 0x0138, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x9206, 0x00ee,
+	0x0005, 0x9085, 0x0001, 0x0cd8, 0x0016, 0x6004, 0x908e, 0x001e,
+	0x11a0, 0x8007, 0x6134, 0x918c, 0x00ff, 0x9105, 0x6036, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x6023, 0x0005, 0x2001, 0x195f, 0x2004,
+	0x601a, 0x080c, 0x8679, 0x080c, 0x8c10, 0x001e, 0x0005, 0xa001,
+	0xa001, 0x0005, 0x6024, 0xd0e4, 0x0158, 0xd0cc, 0x0118, 0x080c,
+	0xc171, 0x0030, 0x080c, 0xdae2, 0x080c, 0x84a6, 0x080c, 0xa0e3,
+	0x0005, 0x9280, 0x0008, 0x2004, 0x9084, 0x000f, 0x0002, 0xd915,
+	0xd915, 0xd915, 0xd917, 0xd915, 0xd917, 0xd917, 0xd915, 0xd917,
+	0xd915, 0xd915, 0xd915, 0xd915, 0xd915, 0x9006, 0x0005, 0x9085,
+	0x0001, 0x0005, 0x9280, 0x0008, 0x2004, 0x9084, 0x000f, 0x0002,
+	0xd92e, 0xd92e, 0xd92e, 0xd92e, 0xd92e, 0xd92e, 0xd93b, 0xd92e,
+	0xd92e, 0xd92e, 0xd92e, 0xd92e, 0xd92e, 0xd92e, 0x6007, 0x003b,
+	0x602f, 0x0009, 0x6017, 0x2a00, 0x6003, 0x0001, 0x080c, 0x8679,
+	0x080c, 0x8c10, 0x0005, 0x0096, 0x00c6, 0x2260, 0x080c, 0xdae2,
+	0x6043, 0x0000, 0x6024, 0xc0f4, 0xc0e4, 0x6026, 0x603b, 0x0000,
+	0x00ce, 0x00d6, 0x2268, 0x9186, 0x0007, 0x1904, 0xd994, 0x6814,
+	0x9005, 0x0138, 0x2048, 0xa87c, 0xd0fc, 0x1118, 0x00de, 0x009e,
+	0x08a8, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x8679, 0x080c,
+	0x8c10, 0x00c6, 0x2d60, 0x6100, 0x9186, 0x0002, 0x1904, 0xda0b,
+	0x6014, 0x9005, 0x1138, 0x6000, 0x9086, 0x0007, 0x190c, 0x0dfa,
+	0x0804, 0xda0b, 0x2048, 0x080c, 0xbe37, 0x1130, 0x0028, 0x2048,
+	0xa800, 0x9005, 0x1de0, 0x2900, 0x2048, 0xa87c, 0x9084, 0x0003,
+	0x9086, 0x0002, 0x1168, 0xa87c, 0xc0dc, 0xc0f4, 0xa87e, 0xa880,
+	0xc0fc, 0xa882, 0x2009, 0x0043, 0x080c, 0xd294, 0x0804, 0xda0b,
+	0x2009, 0x0041, 0x0804, 0xda05, 0x9186, 0x0005, 0x15a0, 0x6814,
+	0x2048, 0xa87c, 0xd0bc, 0x1120, 0x00de, 0x009e, 0x0804, 0xd92e,
+	0xd0b4, 0x0128, 0xd0fc, 0x090c, 0x0dfa, 0x0804, 0xd94f, 0x6007,
+	0x003a, 0x6003, 0x0001, 0x080c, 0x8679, 0x080c, 0x8c10, 0x00c6,
+	0x2d60, 0x6100, 0x9186, 0x0002, 0x0120, 0x9186, 0x0004, 0x1904,
+	0xda0b, 0x6814, 0x2048, 0xa97c, 0xc1f4, 0xc1dc, 0xa97e, 0xa980,
+	0xc1fc, 0xc1bc, 0xa982, 0x00f6, 0x2c78, 0x080c, 0x16db, 0x00fe,
+	0x2009, 0x0042, 0x04d0, 0x0036, 0x080c, 0x1031, 0x090c, 0x0dfa,
+	0xa867, 0x010d, 0x9006, 0xa802, 0xa86a, 0xa88a, 0x2d18, 0xab8e,
+	0xa887, 0x0045, 0x2c00, 0xa892, 0x6038, 0xa8a2, 0x2360, 0x6024,
+	0xc0dd, 0x6026, 0x6010, 0x00b6, 0x2058, 0xb8a0, 0x00be, 0x2004,
+	0x6354, 0xab7a, 0xa876, 0x9006, 0xa87e, 0xa882, 0xad9a, 0xae96,
+	0xa89f, 0x0001, 0x080c, 0x6ae9, 0x2019, 0x0045, 0x6008, 0x2068,
+	0x080c, 0xd440, 0x2d00, 0x600a, 0x6023, 0x0006, 0x6003, 0x0007,
+	0x901e, 0x631a, 0x6342, 0x003e, 0x0038, 0x6043, 0x0000, 0x6003,
+	0x0007, 0x080c, 0xd294, 0x00ce, 0x00de, 0x009e, 0x0005, 0x9186,
+	0x0013, 0x1128, 0x6004, 0x9082, 0x0085, 0x2008, 0x00c2, 0x9186,
+	0x0027, 0x1178, 0x080c, 0x8b04, 0x0036, 0x0096, 0x6014, 0x2048,
+	0x2019, 0x0004, 0x080c, 0xd830, 0x009e, 0x003e, 0x080c, 0x8c10,
+	0x0005, 0x9186, 0x0014, 0x0d70, 0x080c, 0xa178, 0x0005, 0xda3e,
+	0xda3c, 0xda3c, 0xda3c, 0xda3c, 0xda3c, 0xda3e, 0xda3c, 0xda3c,
+	0xda3c, 0xda3c, 0xda3c, 0xda3c, 0x080c, 0x0dfa, 0x080c, 0x8b04,
+	0x6003, 0x000c, 0x080c, 0x8c10, 0x0005, 0x9182, 0x0092, 0x1220,
+	0x9182, 0x0085, 0x0208, 0x001a, 0x080c, 0xa178, 0x0005, 0xda5c,
+	0xda5c, 0xda5c, 0xda5c, 0xda5e, 0xda7e, 0xda5c, 0xda5c, 0xda5c,
+	0xda5c, 0xda5c, 0xda5c, 0xda5c, 0x080c, 0x0dfa, 0x00d6, 0x2c68,
+	0x080c, 0xa08d, 0x01b0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009,
+	0x026e, 0x210c, 0x613a, 0x2009, 0x026f, 0x210c, 0x613e, 0x600b,
+	0xffff, 0x6910, 0x6112, 0x6023, 0x0004, 0x080c, 0x8679, 0x080c,
+	0x8c10, 0x2d60, 0x080c, 0xa0e3, 0x00de, 0x0005, 0x080c, 0xa0e3,
+	0x0005, 0x00e6, 0x6010, 0x00b6, 0x2058, 0xb800, 0x00be, 0xd0ec,
+	0x00ee, 0x0005, 0x2009, 0x187b, 0x210c, 0xd1ec, 0x05b0, 0x6003,
+	0x0002, 0x6024, 0xc0e5, 0x6026, 0xd0cc, 0x0150, 0x2001, 0x1960,
+	0x2004, 0x6042, 0x2009, 0x187b, 0x210c, 0xd1f4, 0x1520, 0x00a0,
+	0x2009, 0x187b, 0x210c, 0xd1f4, 0x0128, 0x6024, 0xc0e4, 0x6026,
+	0x9006, 0x00d8, 0x2001, 0x1960, 0x200c, 0x2001, 0x195e, 0x2004,
+	0x9100, 0x9080, 0x000a, 0x6042, 0x6010, 0x00b6, 0x2058, 0xb8ac,
+	0x00be, 0x0008, 0x2104, 0x9005, 0x0118, 0x9088, 0x0003, 0x0cd0,
+	0x2c0a, 0x600f, 0x0000, 0x9085, 0x0001, 0x0005, 0x0016, 0x00c6,
+	0x00e6, 0x6154, 0xb8ac, 0x2060, 0x8cff, 0x0180, 0x84ff, 0x1118,
+	0x6054, 0x9106, 0x1138, 0x600c, 0x2072, 0x080c, 0x84a6, 0x080c,
+	0xa0e3, 0x0010, 0x9cf0, 0x0003, 0x2e64, 0x0c70, 0x00ee, 0x00ce,
+	0x001e, 0x0005, 0x00d6, 0x00b6, 0x6010, 0x2058, 0xb8ac, 0x2068,
+	0x9005, 0x0130, 0x9c06, 0x0110, 0x680c, 0x0cd0, 0x600c, 0x680e,
+	0x00be, 0x00de, 0x0005, 0x0026, 0x0036, 0x0156, 0x2011, 0x182b,
+	0x2204, 0x9084, 0x00ff, 0x2019, 0x026e, 0x2334, 0x9636, 0x1508,
+	0x8318, 0x2334, 0x2204, 0x9084, 0xff00, 0x9636, 0x11d0, 0x2011,
+	0x0270, 0x20a9, 0x0004, 0x6010, 0x0096, 0x2048, 0x2019, 0x000a,
+	0x080c, 0xb0d0, 0x009e, 0x1168, 0x2011, 0x0274, 0x20a9, 0x0004,
+	0x6010, 0x0096, 0x2048, 0x2019, 0x0006, 0x080c, 0xb0d0, 0x009e,
+	0x1100, 0x015e, 0x003e, 0x002e, 0x0005, 0x00e6, 0x2071, 0x1800,
+	0x080c, 0x5ebe, 0x080c, 0x2f6c, 0x00ee, 0x0005, 0x00e6, 0x6010,
+	0x00b6, 0x2058, 0xb800, 0x00be, 0xd0fc, 0x0108, 0x0011, 0x00ee,
+	0x0005, 0xa880, 0xc0e5, 0xa882, 0x0005, 0x00e6, 0x00d6, 0x00c6,
+	0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126, 0x2091,
+	0x8000, 0x2029, 0x19c8, 0x252c, 0x2021, 0x19ce, 0x2424, 0x2061,
+	0x1cd0, 0x2071, 0x1800, 0x7650, 0x7070, 0x9606, 0x0578, 0x6720,
+	0x9786, 0x0001, 0x0118, 0x9786, 0x0008, 0x1500, 0x2500, 0x9c06,
+	0x01e8, 0x2400, 0x9c06, 0x01d0, 0x080c, 0xd8b6, 0x01b8, 0x080c,
+	0xd8c6, 0x11a0, 0x6000, 0x9086, 0x0004, 0x1120, 0x0016, 0x080c,
+	0x19b4, 0x001e, 0x080c, 0xc02e, 0x1110, 0x080c, 0x31b4, 0x080c,
+	0xc03f, 0x1110, 0x080c, 0xaa81, 0x080c, 0xa113, 0x9ce0, 0x0018,
+	0x2001, 0x1819, 0x2004, 0x9c02, 0x1208, 0x0858, 0x012e, 0x001e,
+	0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00de, 0x00ee,
+	0x0005, 0x2001, 0x1810, 0x2004, 0xd0dc, 0x0005, 0x0006, 0x2001,
+	0x1836, 0x2004, 0xd09c, 0x000e, 0x0005, 0x0006, 0x0036, 0x0046,
+	0x080c, 0xc539, 0x0168, 0x2019, 0xffff, 0x9005, 0x0128, 0x6010,
+	0x00b6, 0x2058, 0xbba0, 0x00be, 0x2021, 0x0004, 0x080c, 0x4cbc,
+	0x004e, 0x003e, 0x000e, 0x6004, 0x9086, 0x0001, 0x1128, 0x080c,
+	0x9bc9, 0x080c, 0xa113, 0x9006, 0x0005, 0x00e6, 0x00c6, 0x00b6,
+	0x0046, 0x2061, 0x1cd0, 0x2071, 0x1800, 0x7450, 0x7070, 0x8001,
+	0x9402, 0x12d8, 0x2100, 0x9c06, 0x0168, 0x6000, 0x9086, 0x0000,
+	0x0148, 0x6010, 0x2058, 0xb8a0, 0x9206, 0x1120, 0x6004, 0x9086,
+	0x0002, 0x0140, 0x9ce0, 0x0018, 0x2001, 0x1819, 0x2004, 0x9c02,
+	0x1220, 0x0c40, 0x9085, 0x0001, 0x0008, 0x9006, 0x004e, 0x00be,
+	0x00ce, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x0016, 0x2091,
+	0x8000, 0x2071, 0x1840, 0xd5a4, 0x0118, 0x7054, 0x8000, 0x7056,
+	0xd5b4, 0x0118, 0x7050, 0x8000, 0x7052, 0xd5ac, 0x0178, 0x2500,
+	0x9084, 0x0007, 0x908e, 0x0003, 0x0148, 0x908e, 0x0004, 0x0130,
+	0x908e, 0x0005, 0x0118, 0x2071, 0x184a, 0x0089, 0x001e, 0x00ee,
+	0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000,
+	0x2071, 0x1842, 0x0021, 0x00ee, 0x000e, 0x012e, 0x0005, 0x2e04,
+	0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000, 0x2072, 0x0005,
+	0x00e6, 0x2071, 0x1840, 0x0c99, 0x00ee, 0x0005, 0x00e6, 0x2071,
+	0x1844, 0x0c69, 0x00ee, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091,
+	0x8000, 0x2071, 0x1840, 0x7064, 0x8000, 0x7066, 0x00ee, 0x000e,
+	0x012e, 0x0005, 0x0003, 0x000b, 0x04a6, 0x0000, 0xc000, 0x0001,
+	0x8064, 0x0008, 0x0010, 0x0000, 0x8066, 0x0000, 0x0101, 0x0008,
+	0x4407, 0x0003, 0x8060, 0x0000, 0x0400, 0x0000, 0x580d, 0x000b,
+	0x798e, 0x0003, 0x50db, 0x000b, 0x4c0a, 0x0003, 0xbac0, 0x0009,
+	0x008a, 0x0000, 0x0c0a, 0x000b, 0x15fe, 0x0008, 0x340a, 0x0003,
+	0xc4c0, 0x0009, 0x7000, 0x0000, 0xffa0, 0x0001, 0x2000, 0x0000,
+	0x1627, 0x0003, 0x808c, 0x0008, 0x0001, 0x0000, 0x0000, 0x0007,
+	0x4047, 0x000a, 0x808c, 0x0008, 0x0002, 0x0000, 0x0821, 0x0003,
+	0x4022, 0x0000, 0x0022, 0x000b, 0x4122, 0x0008, 0x4447, 0x0002,
+	0x0e4f, 0x000b, 0x0bfe, 0x0008, 0x11a0, 0x0001, 0x122d, 0x000b,
+	0x0ca0, 0x0001, 0x122d, 0x000b, 0x9180, 0x0001, 0x0004, 0x0000,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000,
+	0x0009, 0x0008, 0x4430, 0x000b, 0x808c, 0x0008, 0x0000, 0x0008,
+	0x0060, 0x0008, 0x8062, 0x0008, 0x0004, 0x0000, 0x8066, 0x0000,
+	0x0411, 0x0000, 0x4438, 0x0003, 0x03fe, 0x0000, 0x43e0, 0x0001,
+	0x0e2a, 0x000b, 0xc2c0, 0x0009, 0x00ff, 0x0008, 0x02e0, 0x0001,
+	0x0e2a, 0x000b, 0x9180, 0x0001, 0x0005, 0x0008, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0019, 0x0000,
+	0x4447, 0x000b, 0x0240, 0x0002, 0x0a27, 0x000b, 0x00fe, 0x0000,
+	0x322a, 0x000b, 0x112a, 0x0000, 0x002e, 0x0008, 0x022c, 0x0008,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x808c, 0x0008, 0x0002, 0x0000,
+	0x1760, 0x0008, 0x8062, 0x0008, 0x000f, 0x0008, 0x8066, 0x0000,
+	0x0011, 0x0008, 0x4458, 0x0003, 0x01fe, 0x0008, 0x42e0, 0x0009,
+	0x0e1d, 0x0003, 0x00fe, 0x0000, 0x43e0, 0x0001, 0x0e1d, 0x0003,
+	0x1734, 0x0000, 0x1530, 0x0000, 0x1632, 0x0008, 0x0d2a, 0x0008,
+	0x9880, 0x0001, 0x0010, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000,
+	0x7f62, 0x0008, 0x8066, 0x0000, 0x1e0a, 0x0008, 0x446a, 0x000b,
+	0x808a, 0x0008, 0x0003, 0x0008, 0x1a60, 0x0000, 0x8062, 0x0008,
+	0x0002, 0x0000, 0x5870, 0x000b, 0x8066, 0x0000, 0x3679, 0x0000,
+	0x4473, 0x0003, 0x5874, 0x0003, 0x3efe, 0x0008, 0x7f4f, 0x0002,
+	0x087a, 0x000b, 0x0d00, 0x0000, 0x0082, 0x0004, 0x8054, 0x0008,
+	0x0011, 0x0008, 0x8074, 0x0000, 0x1010, 0x0008, 0x1efe, 0x0000,
+	0x300a, 0x000b, 0x00b8, 0x0004, 0x000a, 0x000b, 0x00fe, 0x0000,
+	0x348a, 0x000b, 0x1a60, 0x0000, 0x8062, 0x0008, 0x0007, 0x0000,
+	0x8066, 0x0000, 0x0231, 0x0008, 0x4489, 0x0003, 0x03fe, 0x0000,
+	0x04d0, 0x0001, 0x0cb0, 0x0003, 0x82c0, 0x0001, 0x1f00, 0x0000,
+	0xffa0, 0x0001, 0x0400, 0x0000, 0x089f, 0x0003, 0x14b0, 0x0003,
+	0x01fe, 0x0008, 0x0580, 0x0009, 0x7f06, 0x0000, 0x02fe, 0x0008,
+	0xffc0, 0x0001, 0x00ff, 0x0008, 0x0690, 0x0001, 0x109f, 0x0003,
+	0x7f08, 0x0008, 0x84c0, 0x0001, 0xff00, 0x0008, 0x08b0, 0x000b,
+	0x00fe, 0x0000, 0x34a6, 0x0003, 0x8072, 0x0000, 0x1010, 0x0008,
+	0x3944, 0x0002, 0x08a1, 0x000b, 0x00aa, 0x000b, 0x8072, 0x0000,
+	0x2020, 0x0008, 0x3945, 0x000a, 0x08a6, 0x0003, 0x3946, 0x000a,
+	0x0cb7, 0x000b, 0x0000, 0x0007, 0x3943, 0x000a, 0x08b7, 0x0003,
+	0x00aa, 0x000b, 0x00fe, 0x0000, 0x34b5, 0x000b, 0x8072, 0x0000,
+	0x1000, 0x0000, 0x00b7, 0x000b, 0x8072, 0x0000, 0x2000, 0x0000,
+	0x4000, 0x000f, 0x1c60, 0x0000, 0x1b62, 0x0000, 0x8066, 0x0000,
+	0x0231, 0x0008, 0x44bc, 0x0003, 0x58bd, 0x0003, 0x0140, 0x0008,
+	0x0242, 0x0000, 0x1f43, 0x0002, 0x0ccb, 0x0003, 0x0d44, 0x0000,
+	0x0d46, 0x0008, 0x0348, 0x0008, 0x044a, 0x0008, 0x030a, 0x0008,
+	0x040c, 0x0000, 0x0d06, 0x0000, 0x0d08, 0x0008, 0x00cf, 0x000b,
+	0x0344, 0x0008, 0x0446, 0x0008, 0x0548, 0x0008, 0x064a, 0x0000,
+	0x58cf, 0x0003, 0x3efe, 0x0008, 0x7f4f, 0x0002, 0x08d6, 0x000b,
+	0x8000, 0x0000, 0x0001, 0x0000, 0x0082, 0x0004, 0x8054, 0x0008,
+	0x0001, 0x0000, 0x8074, 0x0000, 0x2020, 0x0008, 0x4000, 0x000f,
+	0x3a40, 0x000a, 0x0c0d, 0x0003, 0x2b24, 0x0008, 0x2b24, 0x0008,
+	0x58df, 0x000b, 0x8054, 0x0008, 0x0002, 0x0000, 0x1242, 0x0002,
+	0x092d, 0x000b, 0x3a45, 0x000a, 0x091c, 0x0003, 0x8072, 0x0000,
+	0x1000, 0x0000, 0x3945, 0x000a, 0x08ec, 0x000b, 0x8072, 0x0000,
+	0x3010, 0x0000, 0x1e10, 0x000a, 0x7f3c, 0x0000, 0x0917, 0x000b,
+	0x1d00, 0x0002, 0x7f3a, 0x0000, 0x0d60, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x0009, 0x0008, 0x44f5, 0x000b, 0x00fe, 0x0000,
+	0x3514, 0x000b, 0x1c60, 0x0000, 0x8062, 0x0008, 0x0001, 0x0000,
+	0x8066, 0x0000, 0x0009, 0x0008, 0x44fd, 0x0003, 0x00fe, 0x0000,
+	0x3204, 0x000b, 0x0038, 0x0000, 0x0060, 0x0008, 0x8062, 0x0008,
+	0x0019, 0x0000, 0x8066, 0x0000, 0x0009, 0x0008, 0x4506, 0x0003,
+	0x80c0, 0x0009, 0x00ff, 0x0008, 0x7f3e, 0x0008, 0x0d60, 0x0000,
+	0x0efe, 0x0008, 0x1f80, 0x0001, 0x7f62, 0x0008, 0x8066, 0x0000,
+	0x0009, 0x0008, 0x4510, 0x000b, 0x003a, 0x0008, 0x1dfe, 0x0000,
+	0x00f1, 0x0003, 0x0036, 0x0008, 0x00b8, 0x0004, 0x012d, 0x0003,
+	0x8074, 0x0000, 0x2000, 0x0000, 0x8072, 0x0000, 0x2000, 0x0000,
+	0x012d, 0x0003, 0x3a44, 0x0002, 0x0a30, 0x000b, 0x8074, 0x0000,
+	0x1000, 0x0000, 0x8072, 0x0000, 0x1000, 0x0000, 0x2d0e, 0x0000,
+	0x2d0e, 0x0000, 0x3601, 0x0003, 0x26fe, 0x0008, 0x26fe, 0x0008,
+	0x2700, 0x0008, 0x2700, 0x0008, 0x00d0, 0x0009, 0x0d3f, 0x0003,
+	0x8074, 0x0000, 0x4040, 0x0008, 0x592d, 0x000b, 0x50db, 0x000b,
+	0x3a46, 0x000a, 0x0d3f, 0x0003, 0x3a47, 0x0002, 0x093a, 0x000b,
+	0x8054, 0x0008, 0x0004, 0x0000, 0x8074, 0x0000, 0x8000, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0182, 0x0003, 0x92c0, 0x0009,
+	0x0fc8, 0x0000, 0x080a, 0x0003, 0x1246, 0x000a, 0x0dfb, 0x000b,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x0002, 0x0000, 0x8066, 0x0000,
+	0x362a, 0x0000, 0x4544, 0x0003, 0x2000, 0x0000, 0x2000, 0x0000,
+	0x2102, 0x0000, 0x2102, 0x0000, 0x2204, 0x0000, 0x2204, 0x0000,
+	0x2306, 0x0000, 0x2306, 0x0000, 0x2408, 0x0000, 0x2408, 0x0000,
+	0x250a, 0x0000, 0x250a, 0x0000, 0x260c, 0x0000, 0x260c, 0x0000,
+	0x270e, 0x0000, 0x270e, 0x0000, 0x2810, 0x0000, 0x2810, 0x0000,
+	0x2912, 0x0000, 0x2912, 0x0000, 0x1a60, 0x0000, 0x8062, 0x0008,
+	0x0007, 0x0000, 0x8066, 0x0000, 0x0052, 0x0000, 0x455e, 0x000b,
+	0x92c0, 0x0009, 0x0780, 0x0008, 0x0e17, 0x0003, 0x124b, 0x0002,
+	0x0967, 0x0003, 0x2e4d, 0x0002, 0x2e4d, 0x0002, 0x0a01, 0x0003,
+	0x3a46, 0x000a, 0x0d74, 0x0003, 0x5969, 0x000b, 0x8054, 0x0008,
+	0x0004, 0x0000, 0x1243, 0x000a, 0x097e, 0x000b, 0x8010, 0x0008,
+	0x000d, 0x0000, 0x01ef, 0x0004, 0x1810, 0x0000, 0x01ef, 0x0004,
+	0x017e, 0x0003, 0x194d, 0x000a, 0x0978, 0x000b, 0x1243, 0x000a,
+	0x0a0b, 0x0003, 0x5978, 0x000b, 0x8054, 0x0008, 0x0004, 0x0000,
+	0x01e4, 0x000c, 0x1810, 0x0000, 0x01ef, 0x0004, 0x8074, 0x0000,
+	0xf000, 0x0008, 0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000,
+	0x3a42, 0x0002, 0x0d88, 0x0003, 0x15fe, 0x0008, 0x3451, 0x000b,
+	0x000a, 0x000b, 0x8074, 0x0000, 0x0501, 0x0000, 0x8010, 0x0008,
+	0x000c, 0x0008, 0x01ef, 0x0004, 0x000a, 0x000b, 0xbbe0, 0x0009,
+	0x0030, 0x0008, 0x0d9e, 0x000b, 0x18fe, 0x0000, 0x3ce0, 0x0009,
+	0x099b, 0x0003, 0x15fe, 0x0008, 0x3ce0, 0x0009, 0x099b, 0x0003,
+	0x01df, 0x0004, 0x8076, 0x0008, 0x0040, 0x0000, 0x01dc, 0x000b,
+	0x8076, 0x0008, 0x0041, 0x0008, 0x01dc, 0x000b, 0xbbe0, 0x0009,
+	0x0032, 0x0000, 0x0da3, 0x0003, 0x3c1e, 0x0008, 0x01dc, 0x000b,
+	0xbbe0, 0x0009, 0x0037, 0x0000, 0x0dc1, 0x000b, 0x18fe, 0x0000,
+	0x3ce0, 0x0009, 0x0d9b, 0x000b, 0x8076, 0x0008, 0x0040, 0x0000,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x000d, 0x0000, 0x2604, 0x0008,
+	0x2604, 0x0008, 0x2706, 0x0008, 0x2706, 0x0008, 0x2808, 0x0000,
+	0x2808, 0x0000, 0x290a, 0x0000, 0x290a, 0x0000, 0x8066, 0x0000,
+	0x0422, 0x0000, 0x45b8, 0x0003, 0x01e4, 0x000c, 0x8054, 0x0008,
+	0x0004, 0x0000, 0x8074, 0x0000, 0xf000, 0x0008, 0x8072, 0x0000,
+	0xb000, 0x0000, 0x0182, 0x0003, 0xbbe0, 0x0009, 0x0038, 0x0000,
+	0x0dd3, 0x000b, 0x18fe, 0x0000, 0x3ce0, 0x0009, 0x09d0, 0x0003,
+	0x15fe, 0x0008, 0x3ce0, 0x0009, 0x0d97, 0x000b, 0x01df, 0x0004,
+	0x8076, 0x0008, 0x0040, 0x0000, 0x8072, 0x0000, 0x8000, 0x0000,
+	0x0227, 0x0003, 0x8076, 0x0008, 0x0042, 0x0008, 0x01dc, 0x000b,
+	0xbbe0, 0x0009, 0x0016, 0x0000, 0x0ddc, 0x000b, 0x3a44, 0x0002,
+	0x0c0c, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, 0x8000, 0x000f,
+	0x000a, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, 0x000a, 0x000b,
+	0x3d30, 0x000a, 0x7f00, 0x0000, 0xbc80, 0x0001, 0x0007, 0x0000,
+	0x01e8, 0x0003, 0x1930, 0x000a, 0x7f00, 0x0000, 0x9880, 0x0001,
+	0x0007, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x000a, 0x0008, 0x45ed, 0x0003, 0x4000, 0x000f,
+	0x21ef, 0x0003, 0x0870, 0x0008, 0x4000, 0x000f, 0xbac0, 0x0009,
+	0x0090, 0x0008, 0x09f8, 0x0003, 0x8074, 0x0000, 0x0706, 0x0000,
+	0x01fa, 0x0003, 0x8074, 0x0000, 0x0703, 0x0000, 0x4000, 0x000f,
+	0x8010, 0x0008, 0x0023, 0x0000, 0x0235, 0x0003, 0x8010, 0x0008,
+	0x0008, 0x0000, 0x0235, 0x0003, 0x8010, 0x0008, 0x0022, 0x0008,
+	0x0235, 0x0003, 0x01e4, 0x000c, 0x8010, 0x0008, 0x0007, 0x0000,
+	0x01ef, 0x0004, 0x1810, 0x0000, 0x01ef, 0x0004, 0x0241, 0x0003,
+	0x01e4, 0x000c, 0x8010, 0x0008, 0x001b, 0x0008, 0x01ef, 0x0004,
+	0x1810, 0x0000, 0x01ef, 0x0004, 0x8074, 0x0000, 0xf080, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000, 0x000a, 0x000b,
+	0x8010, 0x0008, 0x0009, 0x0008, 0x0235, 0x0003, 0x8010, 0x0008,
+	0x0005, 0x0008, 0x0235, 0x0003, 0x808c, 0x0008, 0x0001, 0x0000,
+	0x8010, 0x0008, 0x0004, 0x0000, 0x4143, 0x000a, 0x085f, 0x0003,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x0d2a, 0x0008, 0x0235, 0x0003,
+	0x8010, 0x0008, 0x0003, 0x0008, 0x0239, 0x0003, 0x8010, 0x0008,
+	0x000b, 0x0000, 0x0239, 0x0003, 0x8010, 0x0008, 0x0002, 0x0000,
+	0x0239, 0x0003, 0x3a47, 0x0002, 0x0d2d, 0x0003, 0x8010, 0x0008,
+	0x0006, 0x0008, 0x0239, 0x0003, 0x8074, 0x0000, 0xf000, 0x0008,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x01ef, 0x0004, 0x01f2, 0x0004,
+	0x3a40, 0x000a, 0x080a, 0x0003, 0x8010, 0x0008, 0x000c, 0x0008,
+	0x01ef, 0x0004, 0x000a, 0x000b, 0x8074, 0x0000, 0xf080, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000, 0x2e4d, 0x0002,
+	0x2e4d, 0x0002, 0x0a4c, 0x0003, 0x8054, 0x0008, 0x0019, 0x0000,
+	0x000a, 0x000b, 0x8054, 0x0008, 0x0009, 0x0008, 0x000a, 0x000b,
+	0x3a44, 0x0002, 0x0c0a, 0x000b, 0x022a, 0x000b, 0x15b6, 0xf4ac,
+	0x0003, 0x000b, 0x0480, 0x0000, 0xc000, 0x0001, 0x8064, 0x0008,
+	0x0010, 0x0000, 0x8066, 0x0000, 0x0101, 0x0008, 0xc007, 0x0003,
+	0x8060, 0x0000, 0x0400, 0x0000, 0x580d, 0x000b, 0x7977, 0x0003,
+	0x50db, 0x000b, 0xc80a, 0x0003, 0xbac0, 0x0009, 0x008a, 0x0000,
+	0x880a, 0x000b, 0x15fe, 0x0008, 0xb00a, 0x0003, 0xc4c0, 0x0009,
+	0x7000, 0x0000, 0xffa0, 0x0001, 0x2000, 0x0000, 0x9214, 0x0003,
+	0x808c, 0x0008, 0x0001, 0x0000, 0x0000, 0x0007, 0x4047, 0x000a,
+	0x808c, 0x0008, 0x0002, 0x0000, 0x0821, 0x0003, 0x4022, 0x0000,
+	0x0022, 0x000b, 0x4122, 0x0008, 0x4447, 0x0002, 0x8a3c, 0x0003,
+	0x0bfe, 0x0008, 0x11a0, 0x0001, 0x121a, 0x0003, 0x0ca0, 0x0001,
+	0x121a, 0x0003, 0x9180, 0x0001, 0x0004, 0x0000, 0x8060, 0x0000,
+	0x0400, 0x0000, 0x7f62, 0x0008, 0x8066, 0x0000, 0x0009, 0x0008,
+	0xc030, 0x000b, 0x808c, 0x0008, 0x0000, 0x0008, 0x0060, 0x0008,
+	0x8062, 0x0008, 0x0004, 0x0000, 0x8066, 0x0000, 0x0411, 0x0000,
+	0xc038, 0x0003, 0x03fe, 0x0000, 0x43e0, 0x0001, 0x8a17, 0x0003,
+	0xc2c0, 0x0009, 0x00ff, 0x0008, 0x02e0, 0x0001, 0x8a17, 0x0003,
+	0x9180, 0x0001, 0x0005, 0x0008, 0x8060, 0x0000, 0x0400, 0x0000,
+	0x7f62, 0x0008, 0x8066, 0x0000, 0x0019, 0x0000, 0xc047, 0x000b,
+	0x0240, 0x0002, 0x0a14, 0x000b, 0x00fe, 0x0000, 0x3217, 0x0003,
+	0x112a, 0x0000, 0x002e, 0x0008, 0x022c, 0x0008, 0x3a44, 0x0002,
+	0x880a, 0x000b, 0x808c, 0x0008, 0x0002, 0x0000, 0x1760, 0x0008,
+	0x8062, 0x0008, 0x000f, 0x0008, 0x8066, 0x0000, 0x0011, 0x0008,
+	0xc058, 0x0003, 0x01fe, 0x0008, 0x42e0, 0x0009, 0x8a0a, 0x0003,
+	0x00fe, 0x0000, 0x43e0, 0x0001, 0x8a0a, 0x0003, 0x1734, 0x0000,
+	0x1530, 0x0000, 0x1632, 0x0008, 0x0d2a, 0x0008, 0x9880, 0x0001,
+	0x0010, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x1e0a, 0x0008, 0xc06a, 0x000b, 0x808a, 0x0008,
+	0x0003, 0x0008, 0x1a60, 0x0000, 0x8062, 0x0008, 0x0002, 0x0000,
+	0x5870, 0x000b, 0x8066, 0x0000, 0x3679, 0x0000, 0xc073, 0x0003,
+	0x5874, 0x0003, 0x3efe, 0x0008, 0x7f4f, 0x0002, 0x087a, 0x000b,
+	0x0d00, 0x0000, 0x0082, 0x0004, 0x8054, 0x0008, 0x0011, 0x0008,
+	0x8074, 0x0000, 0x1010, 0x0008, 0x1efe, 0x0000, 0x300a, 0x000b,
+	0x00b8, 0x0004, 0x000a, 0x000b, 0x00fe, 0x0000, 0xb08a, 0x000b,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x0007, 0x0000, 0x8066, 0x0000,
+	0x0231, 0x0008, 0xc089, 0x0003, 0x03fe, 0x0000, 0x04d0, 0x0001,
+	0x88b0, 0x0003, 0x82c0, 0x0001, 0x1f00, 0x0000, 0xffa0, 0x0001,
+	0x0400, 0x0000, 0x089f, 0x0003, 0x90b0, 0x0003, 0x01fe, 0x0008,
+	0x0580, 0x0009, 0x7f06, 0x0000, 0x02fe, 0x0008, 0xffc0, 0x0001,
+	0x00ff, 0x0008, 0x0690, 0x0001, 0x109f, 0x0003, 0x7f08, 0x0008,
+	0x84c0, 0x0001, 0xff00, 0x0008, 0x08b0, 0x000b, 0x00fe, 0x0000,
+	0xb0a6, 0x0003, 0x8072, 0x0000, 0x1010, 0x0008, 0x3944, 0x0002,
+	0x08a1, 0x000b, 0x00aa, 0x000b, 0x8072, 0x0000, 0x2020, 0x0008,
+	0x3945, 0x000a, 0x08a6, 0x0003, 0x3946, 0x000a, 0x88b7, 0x000b,
+	0x0000, 0x0007, 0x3943, 0x000a, 0x08b7, 0x0003, 0x00aa, 0x000b,
+	0x00fe, 0x0000, 0xb0b5, 0x000b, 0x8072, 0x0000, 0x1000, 0x0000,
+	0x00b7, 0x000b, 0x8072, 0x0000, 0x2000, 0x0000, 0x4000, 0x000f,
+	0x1c60, 0x0000, 0x1b62, 0x0000, 0x8066, 0x0000, 0x0231, 0x0008,
+	0xc0bc, 0x0003, 0x58bd, 0x0003, 0x0140, 0x0008, 0x0242, 0x0000,
+	0x1f43, 0x0002, 0x88cb, 0x0003, 0x0d44, 0x0000, 0x0d46, 0x0008,
+	0x0348, 0x0008, 0x044a, 0x0008, 0x030a, 0x0008, 0x040c, 0x0000,
+	0x0d06, 0x0000, 0x0d08, 0x0008, 0x00cf, 0x000b, 0x0344, 0x0008,
+	0x0446, 0x0008, 0x0548, 0x0008, 0x064a, 0x0000, 0x58cf, 0x0003,
+	0x3efe, 0x0008, 0x7f4f, 0x0002, 0x08d6, 0x000b, 0x8000, 0x0000,
+	0x0001, 0x0000, 0x0082, 0x0004, 0x8054, 0x0008, 0x0001, 0x0000,
+	0x8074, 0x0000, 0x2020, 0x0008, 0x4000, 0x000f, 0x3a40, 0x000a,
+	0x880d, 0x0003, 0xabd0, 0x0001, 0x0000, 0x0008, 0x7f24, 0x0000,
+	0x58e0, 0x000b, 0x8054, 0x0008, 0x0002, 0x0000, 0x1242, 0x0002,
+	0x0930, 0x000b, 0x3a45, 0x000a, 0x091d, 0x000b, 0x8072, 0x0000,
+	0x1000, 0x0000, 0x3945, 0x000a, 0x08ed, 0x0003, 0x8072, 0x0000,
+	0x3010, 0x0000, 0x1e10, 0x000a, 0x7f3c, 0x0000, 0x0918, 0x000b,
+	0x1d00, 0x0002, 0x7f3a, 0x0000, 0x0d60, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x0009, 0x0008, 0xc0f6, 0x000b, 0x00fe, 0x0000,
+	0xb115, 0x0003, 0x1c60, 0x0000, 0x8062, 0x0008, 0x0001, 0x0000,
+	0x8066, 0x0000, 0x0009, 0x0008, 0xc0fe, 0x0003, 0x00fe, 0x0000,
+	0x31f1, 0x000b, 0x0038, 0x0000, 0x0060, 0x0008, 0x8062, 0x0008,
+	0x0019, 0x0000, 0x8066, 0x0000, 0x0009, 0x0008, 0xc107, 0x000b,
+	0x80c0, 0x0009, 0x00ff, 0x0008, 0x7f3e, 0x0008, 0x0d60, 0x0000,
+	0x0efe, 0x0008, 0x1f80, 0x0001, 0x7f62, 0x0008, 0x8066, 0x0000,
+	0x0009, 0x0008, 0xc111, 0x0003, 0x003a, 0x0008, 0x1dfe, 0x0000,
+	0x00f2, 0x0003, 0x0036, 0x0008, 0x00b8, 0x0004, 0x0130, 0x0003,
+	0x8074, 0x0000, 0x2000, 0x0000, 0x8072, 0x0000, 0x2000, 0x0000,
+	0x0130, 0x0003, 0x3a44, 0x0002, 0x0a1d, 0x000b, 0x8074, 0x0000,
+	0x1000, 0x0000, 0x8072, 0x0000, 0x1000, 0x0000, 0xadd0, 0x0001,
+	0x0000, 0x0008, 0x7f0e, 0x0008, 0xb1ee, 0x000b, 0xa7d0, 0x0001,
+	0x0000, 0x0008, 0x7f00, 0x0000, 0xa6d0, 0x0009, 0x0000, 0x0008,
+	0x00d0, 0x0009, 0x8942, 0x0003, 0x8074, 0x0000, 0x4040, 0x0008,
+	0x5930, 0x000b, 0x50db, 0x000b, 0x3a46, 0x000a, 0x8942, 0x0003,
+	0x3a47, 0x0002, 0x093d, 0x0003, 0x8054, 0x0008, 0x0004, 0x0000,
+	0x8074, 0x0000, 0x8000, 0x0000, 0x8072, 0x0000, 0x3000, 0x0008,
+	0x016b, 0x000b, 0x92c0, 0x0009, 0x0fc8, 0x0000, 0x080a, 0x0003,
+	0x1246, 0x000a, 0x89e8, 0x0003, 0x1a60, 0x0000, 0x8062, 0x0008,
+	0x0002, 0x0000, 0x8066, 0x0000, 0x367a, 0x0000, 0xc147, 0x0003,
+	0x92c0, 0x0009, 0x0780, 0x0008, 0x8a04, 0x000b, 0x124b, 0x0002,
+	0x0950, 0x000b, 0x2e4d, 0x0002, 0x2e4d, 0x0002, 0x09ee, 0x000b,
+	0x3a46, 0x000a, 0x895d, 0x000b, 0x5952, 0x0003, 0x8054, 0x0008,
+	0x0004, 0x0000, 0x1243, 0x000a, 0x0967, 0x0003, 0x8010, 0x0008,
+	0x000d, 0x0000, 0x01dc, 0x0004, 0x1810, 0x0000, 0x01dc, 0x0004,
+	0x0167, 0x000b, 0x194d, 0x000a, 0x0961, 0x0003, 0x1243, 0x000a,
+	0x09f8, 0x0003, 0x5961, 0x0003, 0x8054, 0x0008, 0x0004, 0x0000,
+	0x01d1, 0x000c, 0x1810, 0x0000, 0x01dc, 0x0004, 0x8074, 0x0000,
+	0xf000, 0x0008, 0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000,
+	0x3a42, 0x0002, 0x8971, 0x0003, 0x15fe, 0x0008, 0xb051, 0x000b,
+	0x000a, 0x000b, 0x8074, 0x0000, 0x0501, 0x0000, 0x8010, 0x0008,
+	0x000c, 0x0008, 0x01dc, 0x0004, 0x000a, 0x000b, 0xbbe0, 0x0009,
+	0x0030, 0x0008, 0x8987, 0x0003, 0x18fe, 0x0000, 0x3ce0, 0x0009,
+	0x0984, 0x000b, 0x15fe, 0x0008, 0x3ce0, 0x0009, 0x0984, 0x000b,
+	0x01cc, 0x000c, 0x8076, 0x0008, 0x0040, 0x0000, 0x01c9, 0x0003,
+	0x8076, 0x0008, 0x0041, 0x0008, 0x01c9, 0x0003, 0xbbe0, 0x0009,
+	0x0032, 0x0000, 0x898c, 0x000b, 0x3c1e, 0x0008, 0x01c9, 0x0003,
+	0xbbe0, 0x0009, 0x0037, 0x0000, 0x89ae, 0x000b, 0x18fe, 0x0000,
+	0x3ce0, 0x0009, 0x8984, 0x0003, 0x8076, 0x0008, 0x0040, 0x0000,
+	0x1a60, 0x0000, 0x8062, 0x0008, 0x000d, 0x0000, 0xa6d0, 0x0009,
+	0x0000, 0x0008, 0x7f04, 0x0008, 0xa7d0, 0x0001, 0x0000, 0x0008,
+	0x7f06, 0x0000, 0xa8d0, 0x0001, 0x0000, 0x0008, 0x7f08, 0x0008,
+	0xa9d0, 0x0009, 0x0000, 0x0008, 0x7f0a, 0x0000, 0x8066, 0x0000,
+	0x0422, 0x0000, 0xc1a5, 0x0003, 0x01d1, 0x000c, 0x8054, 0x0008,
+	0x0004, 0x0000, 0x8074, 0x0000, 0xf000, 0x0008, 0x8072, 0x0000,
+	0xb000, 0x0000, 0x016b, 0x000b, 0xbbe0, 0x0009, 0x0038, 0x0000,
+	0x89c0, 0x0003, 0x18fe, 0x0000, 0x3ce0, 0x0009, 0x09bd, 0x000b,
+	0x15fe, 0x0008, 0x3ce0, 0x0009, 0x8980, 0x000b, 0x01cc, 0x000c,
+	0x8076, 0x0008, 0x0040, 0x0000, 0x8072, 0x0000, 0x8000, 0x0000,
+	0x0214, 0x0003, 0x8076, 0x0008, 0x0042, 0x0008, 0x01c9, 0x0003,
+	0xbbe0, 0x0009, 0x0016, 0x0000, 0x89c9, 0x0003, 0x3a44, 0x0002,
+	0x880c, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, 0x8000, 0x000f,
+	0x000a, 0x000b, 0x8072, 0x0000, 0x8000, 0x0000, 0x000a, 0x000b,
+	0x3d30, 0x000a, 0x7f00, 0x0000, 0xbc80, 0x0001, 0x0007, 0x0000,
+	0x01d5, 0x000b, 0x1930, 0x000a, 0x7f00, 0x0000, 0x9880, 0x0001,
+	0x0007, 0x0000, 0x8060, 0x0000, 0x0400, 0x0000, 0x7f62, 0x0008,
+	0x8066, 0x0000, 0x000a, 0x0008, 0xc1da, 0x000b, 0x4000, 0x000f,
+	0x21dc, 0x0003, 0x0870, 0x0008, 0x4000, 0x000f, 0xbac0, 0x0009,
+	0x0090, 0x0008, 0x09e5, 0x0003, 0x8074, 0x0000, 0x0706, 0x0000,
+	0x01e7, 0x0003, 0x8074, 0x0000, 0x0703, 0x0000, 0x4000, 0x000f,
+	0x8010, 0x0008, 0x0023, 0x0000, 0x0222, 0x0003, 0x8010, 0x0008,
+	0x0008, 0x0000, 0x0222, 0x0003, 0x8010, 0x0008, 0x0022, 0x0008,
+	0x0222, 0x0003, 0x01d1, 0x000c, 0x8010, 0x0008, 0x0007, 0x0000,
+	0x01dc, 0x0004, 0x1810, 0x0000, 0x01dc, 0x0004, 0x022e, 0x0003,
+	0x01d1, 0x000c, 0x8010, 0x0008, 0x001b, 0x0008, 0x01dc, 0x0004,
+	0x1810, 0x0000, 0x01dc, 0x0004, 0x8074, 0x0000, 0xf080, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000, 0x000a, 0x000b,
+	0x8010, 0x0008, 0x0009, 0x0008, 0x0222, 0x0003, 0x8010, 0x0008,
+	0x0005, 0x0008, 0x0222, 0x0003, 0x808c, 0x0008, 0x0001, 0x0000,
+	0x8010, 0x0008, 0x0004, 0x0000, 0x4143, 0x000a, 0x085f, 0x0003,
+	0x3a44, 0x0002, 0x880a, 0x000b, 0x0d2a, 0x0008, 0x0222, 0x0003,
+	0x8010, 0x0008, 0x0003, 0x0008, 0x0226, 0x000b, 0x8010, 0x0008,
+	0x000b, 0x0000, 0x0226, 0x000b, 0x8010, 0x0008, 0x0002, 0x0000,
+	0x0226, 0x000b, 0x3a47, 0x0002, 0x8930, 0x0003, 0x8010, 0x0008,
+	0x0006, 0x0008, 0x0226, 0x000b, 0x8074, 0x0000, 0xf000, 0x0008,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x01dc, 0x0004, 0x01df, 0x0004,
+	0x3a40, 0x000a, 0x080a, 0x0003, 0x8010, 0x0008, 0x000c, 0x0008,
+	0x01dc, 0x0004, 0x000a, 0x000b, 0x8074, 0x0000, 0xf080, 0x0000,
+	0x8072, 0x0000, 0x3000, 0x0008, 0x0d30, 0x0000, 0x2e4d, 0x0002,
+	0x2e4d, 0x0002, 0x0a39, 0x000b, 0x8054, 0x0008, 0x0019, 0x0000,
+	0x000a, 0x000b, 0x8054, 0x0008, 0x0009, 0x0008, 0x000a, 0x000b,
+	0x3a44, 0x0002, 0x880a, 0x000b, 0x0217, 0x0003, 0xf4e5, 0xf482,
+	0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
+	0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000,
+	0x6870
+};
+#ifdef UNIQUE_FW_NAME
+unsigned short fw2300flx_length01 = 0xdd79;
+#else
+unsigned short risc_code_length01 = 0xdd79;
+#endif
+
diff --git a/drivers/scsi/qla2xxx/qla_dbg.c b/drivers/scsi/qla2xxx/qla_dbg.c
new file mode 100644
index 0000000..dcc33da
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_dbg.c
@@ -0,0 +1,1158 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/delay.h>
+
+static int qla_uprintf(char **, char *, ...);
+
+/**
+ * qla2300_fw_dump() - Dumps binary data from the 2300 firmware.
+ * @ha: HA context
+ * @hardware_locked: Called with the hardware_lock
+ */
+void
+qla2300_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+{
+	int		rval;
+	uint32_t	cnt, timer;
+	uint32_t	risc_address;
+	uint16_t	mb0, mb2;
+
+	uint32_t	stat;
+	device_reg_t __iomem *reg = ha->iobase;
+	uint16_t __iomem *dmp_reg;
+	unsigned long	flags;
+	struct qla2300_fw_dump	*fw;
+	uint32_t	dump_size, data_ram_cnt;
+
+	risc_address = data_ram_cnt = 0;
+	mb0 = mb2 = 0;
+	flags = 0;
+
+	if (!hardware_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	if (ha->fw_dump != NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Firmware has been previously dumped (%p) -- ignoring "
+		    "request...\n", ha->fw_dump);
+		goto qla2300_fw_dump_failed;
+	}
+
+	/* Allocate (large) dump buffer. */
+	dump_size = sizeof(struct qla2300_fw_dump);
+	dump_size += (ha->fw_memory_size - 0x11000) * sizeof(uint16_t);
+	ha->fw_dump_order = get_order(dump_size);
+	ha->fw_dump = (struct qla2300_fw_dump *) __get_free_pages(GFP_ATOMIC,
+	    ha->fw_dump_order);
+	if (ha->fw_dump == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocated memory for firmware dump (%d/%d).\n",
+		    ha->fw_dump_order, dump_size);
+		goto qla2300_fw_dump_failed;
+	}
+	fw = ha->fw_dump;
+
+	rval = QLA_SUCCESS;
+	fw->hccr = RD_REG_WORD(&reg->hccr);
+
+	/* Pause RISC. */
+	WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC); 
+	if (IS_QLA2300(ha)) {
+		for (cnt = 30000;
+		    (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
+			rval == QLA_SUCCESS; cnt--) {
+			if (cnt)
+				udelay(100);
+			else
+				rval = QLA_FUNCTION_TIMEOUT;
+		}
+	} else {
+		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
+		udelay(10);
+	}
+
+	if (rval == QLA_SUCCESS) {
+		dmp_reg = (uint16_t __iomem *)(reg + 0);
+		for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) 
+			fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+		for (cnt = 0; cnt < sizeof(fw->risc_host_reg) / 2; cnt++) 
+			fw->risc_host_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x40);
+		for (cnt = 0; cnt < sizeof(fw->mailbox_reg) / 2; cnt++) 
+			fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x40);
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->resp_dma_reg) / 2; cnt++) 
+			fw->resp_dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x50);
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) 
+			fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x00);
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+		for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) 
+			fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2000); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) 
+			fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2200); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) 
+			fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2400); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) 
+			fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2600); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) 
+			fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2800); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) 
+			fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2A00); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) 
+			fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2C00); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) 
+			fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2E00); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) 
+			fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x10); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) 
+			fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x20); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) 
+			fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x30); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) 
+			fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		/* Reset RISC. */
+		WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
+		for (cnt = 0; cnt < 30000; cnt++) {
+			if ((RD_REG_WORD(&reg->ctrl_status) &
+			    CSR_ISP_SOFT_RESET) == 0)
+				break;
+
+			udelay(10);
+		}
+	}
+
+	if (!IS_QLA2300(ha)) {
+		for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 &&
+		    rval == QLA_SUCCESS; cnt--) {
+			if (cnt)
+				udelay(100);
+			else
+				rval = QLA_FUNCTION_TIMEOUT;
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Get RISC SRAM. */
+		risc_address = 0x800;
+ 		WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD);
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+	}
+	for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+ 		WRT_MAILBOX_REG(ha, reg, 1, (uint16_t)risc_address);
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+
+		for (timer = 6000000; timer; timer--) {
+			/* Check for pending interrupts. */
+ 			stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+			if (stat & HSR_RISC_INT) {
+				stat &= 0xff;
+
+				if (stat == 0x1 || stat == 0x2) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					/* Release mailbox registers. */
+					WRT_REG_WORD(&reg->semaphore, 0);
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				} else if (stat == 0x10 || stat == 0x11) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				}
+
+				/* clear this intr; it wasn't a mailbox intr */
+				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+				RD_REG_WORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb0 & MBS_MASK;
+			fw->risc_ram[cnt] = mb2;
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Get stack SRAM. */
+		risc_address = 0x10000;
+ 		WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+	}
+	for (cnt = 0; cnt < sizeof(fw->stack_ram) / 2 && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+ 		WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
+ 		WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+
+		for (timer = 6000000; timer; timer--) {
+			/* Check for pending interrupts. */
+ 			stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+			if (stat & HSR_RISC_INT) {
+				stat &= 0xff;
+
+				if (stat == 0x1 || stat == 0x2) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					/* Release mailbox registers. */
+					WRT_REG_WORD(&reg->semaphore, 0);
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				} else if (stat == 0x10 || stat == 0x11) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				}
+
+				/* clear this intr; it wasn't a mailbox intr */
+				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+				RD_REG_WORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb0 & MBS_MASK;
+			fw->stack_ram[cnt] = mb2;
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Get data SRAM. */
+		risc_address = 0x11000;
+		data_ram_cnt = ha->fw_memory_size - risc_address + 1;
+ 		WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_EXTENDED);
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+	}
+	for (cnt = 0; cnt < data_ram_cnt && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+ 		WRT_MAILBOX_REG(ha, reg, 1, LSW(risc_address));
+ 		WRT_MAILBOX_REG(ha, reg, 8, MSW(risc_address));
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+
+		for (timer = 6000000; timer; timer--) {
+			/* Check for pending interrupts. */
+ 			stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+			if (stat & HSR_RISC_INT) {
+				stat &= 0xff;
+
+				if (stat == 0x1 || stat == 0x2) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					/* Release mailbox registers. */
+					WRT_REG_WORD(&reg->semaphore, 0);
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				} else if (stat == 0x10 || stat == 0x11) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				}
+
+				/* clear this intr; it wasn't a mailbox intr */
+				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+				RD_REG_WORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb0 & MBS_MASK;
+			fw->data_ram[cnt] = mb2;
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to dump firmware (%x)!!!\n", rval);
+
+		free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order);
+		ha->fw_dump = NULL;
+	} else {
+		qla_printk(KERN_INFO, ha,
+		    "Firmware dump saved to temp buffer (%ld/%p).\n",
+		    ha->host_no, ha->fw_dump);
+	}
+
+qla2300_fw_dump_failed:
+	if (!hardware_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qla2300_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
+ * @ha: HA context
+ */
+void
+qla2300_ascii_fw_dump(scsi_qla_host_t *ha)
+{
+	uint32_t cnt;
+	char *uiter;
+	char fw_info[30];
+	struct qla2300_fw_dump *fw;
+	uint32_t data_ram_cnt;
+
+	uiter = ha->fw_dump_buffer;
+	fw = ha->fw_dump;
+
+	qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
+	    qla2x00_get_fw_version_str(ha, fw_info));
+
+	qla_uprintf(&uiter, "\n[==>BEG]\n");
+
+	qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
+
+	qla_uprintf(&uiter, "PBIU Registers:");
+	for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nReqQ-RspQ-Risc2Host Status registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_host_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_host_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nMailbox Registers:");
+	for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nAuto Request Response DMA Registers:");
+	for (cnt = 0; cnt < sizeof (fw->resp_dma_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->resp_dma_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nDMA Registers:");
+	for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
+	for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nCode RAM Dump:");
+	for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n%04x: ", cnt + 0x0800);
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nStack RAM Dump:");
+	for (cnt = 0; cnt < sizeof (fw->stack_ram) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n%05x: ", cnt + 0x10000);
+		}
+		qla_uprintf(&uiter, "%04x ", fw->stack_ram[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nData RAM Dump:");
+	data_ram_cnt = ha->fw_memory_size - 0x11000 + 1;
+	for (cnt = 0; cnt < data_ram_cnt; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n%05x: ", cnt + 0x11000);
+		}
+		qla_uprintf(&uiter, "%04x ", fw->data_ram[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
+}
+
+/**
+ * qla2100_fw_dump() - Dumps binary data from the 2100/2200 firmware.
+ * @ha: HA context
+ * @hardware_locked: Called with the hardware_lock
+ */
+void
+qla2100_fw_dump(scsi_qla_host_t *ha, int hardware_locked)
+{
+	int		rval;
+	uint32_t	cnt, timer;
+	uint16_t	risc_address;
+	uint16_t	mb0, mb2;
+	device_reg_t __iomem *reg = ha->iobase;
+	uint16_t __iomem *dmp_reg;
+	unsigned long	flags;
+	struct qla2100_fw_dump	*fw;
+
+	risc_address = 0;
+	mb0 = mb2 = 0;
+	flags = 0;
+
+	if (!hardware_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	if (ha->fw_dump != NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Firmware has been previously dumped (%p) -- ignoring "
+		    "request...\n", ha->fw_dump);
+		goto qla2100_fw_dump_failed;
+	}
+
+	/* Allocate (large) dump buffer. */
+	ha->fw_dump_order = get_order(sizeof(struct qla2100_fw_dump));
+	ha->fw_dump = (struct qla2100_fw_dump *) __get_free_pages(GFP_ATOMIC,
+	    ha->fw_dump_order);
+	if (ha->fw_dump == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocated memory for firmware dump (%d/%Zd).\n",
+		    ha->fw_dump_order, sizeof(struct qla2100_fw_dump));
+		goto qla2100_fw_dump_failed;
+	}
+	fw = ha->fw_dump;
+
+	rval = QLA_SUCCESS;
+	fw->hccr = RD_REG_WORD(&reg->hccr);
+
+	/* Pause RISC. */
+	WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC); 
+	for (cnt = 30000; (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
+	    rval == QLA_SUCCESS; cnt--) {
+		if (cnt)
+			udelay(100);
+		else
+			rval = QLA_FUNCTION_TIMEOUT;
+	}
+	if (rval == QLA_SUCCESS) {
+		dmp_reg = (uint16_t __iomem *)(reg + 0);
+		for (cnt = 0; cnt < sizeof(fw->pbiu_reg) / 2; cnt++) 
+			fw->pbiu_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x10);
+		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+			if (cnt == 8) {
+				dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xe0);
+			}
+			fw->mailbox_reg[cnt] = RD_REG_WORD(dmp_reg++);
+		}
+
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x20);
+		for (cnt = 0; cnt < sizeof(fw->dma_reg) / 2; cnt++) 
+			fw->dma_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x00);
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0xA0);
+		for (cnt = 0; cnt < sizeof(fw->risc_hdw_reg) / 2; cnt++) 
+			fw->risc_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2000); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp0_reg) / 2; cnt++) 
+			fw->risc_gp0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2100); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp1_reg) / 2; cnt++) 
+			fw->risc_gp1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2200); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp2_reg) / 2; cnt++) 
+			fw->risc_gp2_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2300); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp3_reg) / 2; cnt++) 
+			fw->risc_gp3_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2400); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp4_reg) / 2; cnt++) 
+			fw->risc_gp4_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2500); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp5_reg) / 2; cnt++) 
+			fw->risc_gp5_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2600); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp6_reg) / 2; cnt++) 
+			fw->risc_gp6_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->pcr, 0x2700); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->risc_gp7_reg) / 2; cnt++) 
+			fw->risc_gp7_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x10); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->frame_buf_hdw_reg) / 2; cnt++) 
+			fw->frame_buf_hdw_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x20); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->fpm_b0_reg) / 2; cnt++) 
+			fw->fpm_b0_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		WRT_REG_WORD(&reg->ctrl_status, 0x30); 
+		dmp_reg = (uint16_t __iomem *)((uint8_t __iomem *)reg + 0x80);
+		for (cnt = 0; cnt < sizeof(fw->fpm_b1_reg) / 2; cnt++) 
+			fw->fpm_b1_reg[cnt] = RD_REG_WORD(dmp_reg++);
+
+		/* Reset the ISP. */
+		WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
+	}
+
+	for (cnt = 30000; RD_MAILBOX_REG(ha, reg, 0) != 0 &&
+	    rval == QLA_SUCCESS; cnt--) {
+		if (cnt)
+			udelay(100);
+		else
+			rval = QLA_FUNCTION_TIMEOUT;
+	}
+
+	/* Pause RISC. */
+	if (rval == QLA_SUCCESS && (IS_QLA2200(ha) || (IS_QLA2100(ha) &&
+	    (RD_REG_WORD(&reg->mctr) & (BIT_1 | BIT_0)) != 0))) {
+
+		WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC); 
+		for (cnt = 30000;
+		    (RD_REG_WORD(&reg->hccr) & HCCR_RISC_PAUSE) == 0 &&
+		    rval == QLA_SUCCESS; cnt--) {
+			if (cnt)
+				udelay(100);
+			else
+				rval = QLA_FUNCTION_TIMEOUT;
+		}
+		if (rval == QLA_SUCCESS) {
+			/* Set memory configuration and timing. */
+			if (IS_QLA2100(ha))
+				WRT_REG_WORD(&reg->mctr, 0xf1);
+			else
+				WRT_REG_WORD(&reg->mctr, 0xf2);
+			RD_REG_WORD(&reg->mctr);	/* PCI Posting. */
+
+			/* Release RISC. */
+			WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Get RISC SRAM. */
+		risc_address = 0x1000;
+ 		WRT_MAILBOX_REG(ha, reg, 0, MBC_READ_RAM_WORD);
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+	}
+	for (cnt = 0; cnt < sizeof(fw->risc_ram) / 2 && rval == QLA_SUCCESS;
+	    cnt++, risc_address++) {
+ 		WRT_MAILBOX_REG(ha, reg, 1, risc_address);
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+
+		for (timer = 6000000; timer != 0; timer--) {
+			/* Check for pending interrupts. */
+			if (RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) {
+				if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
+					set_bit(MBX_INTERRUPT,
+					    &ha->mbx_cmd_flags);
+
+					mb0 = RD_MAILBOX_REG(ha, reg, 0);
+					mb2 = RD_MAILBOX_REG(ha, reg, 2);
+
+					WRT_REG_WORD(&reg->semaphore, 0);
+					WRT_REG_WORD(&reg->hccr,
+					    HCCR_CLR_RISC_INT);
+					RD_REG_WORD(&reg->hccr);
+					break;
+				}
+				WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+				RD_REG_WORD(&reg->hccr);
+			}
+			udelay(5);
+		}
+
+		if (test_and_clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags)) {
+			rval = mb0 & MBS_MASK;
+			fw->risc_ram[cnt] = mb2;
+		} else {
+			rval = QLA_FUNCTION_FAILED;
+		}
+	}
+
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to dump firmware (%x)!!!\n", rval);
+
+		free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order);
+		ha->fw_dump = NULL;
+	} else {
+		qla_printk(KERN_INFO, ha,
+		    "Firmware dump saved to temp buffer (%ld/%p).\n",
+		    ha->host_no, ha->fw_dump);
+	}
+
+qla2100_fw_dump_failed:
+	if (!hardware_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qla2100_ascii_fw_dump() - Converts a binary firmware dump to ASCII.
+ * @ha: HA context
+ */
+void
+qla2100_ascii_fw_dump(scsi_qla_host_t *ha)
+{
+	uint32_t cnt;
+	char *uiter;
+	char fw_info[30];
+	struct qla2100_fw_dump *fw;
+
+	uiter = ha->fw_dump_buffer;
+	fw = ha->fw_dump;
+
+	qla_uprintf(&uiter, "%s Firmware Version %s\n", ha->model_number,
+	    qla2x00_get_fw_version_str(ha, fw_info));
+
+	qla_uprintf(&uiter, "\n[==>BEG]\n");
+
+	qla_uprintf(&uiter, "HCCR Register:\n%04x\n\n", fw->hccr);
+
+	qla_uprintf(&uiter, "PBIU Registers:");
+	for (cnt = 0; cnt < sizeof (fw->pbiu_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->pbiu_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nMailbox Registers:");
+	for (cnt = 0; cnt < sizeof (fw->mailbox_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->mailbox_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nDMA Registers:");
+	for (cnt = 0; cnt < sizeof (fw->dma_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->dma_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC Hardware Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_hdw_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_hdw_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP0 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp0_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp0_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP1 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp1_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp1_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP2 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp2_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp2_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP3 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp3_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp3_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP4 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp4_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp4_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP5 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp5_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp5_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP6 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp6_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp6_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC GP7 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->risc_gp7_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_gp7_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFrame Buffer Hardware Registers:");
+	for (cnt = 0; cnt < sizeof (fw->frame_buf_hdw_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->frame_buf_hdw_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFPM B0 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->fpm_b0_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->fpm_b0_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nFPM B1 Registers:");
+	for (cnt = 0; cnt < sizeof (fw->fpm_b1_reg) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n");
+		}
+		qla_uprintf(&uiter, "%04x ", fw->fpm_b1_reg[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\nRISC SRAM:");
+	for (cnt = 0; cnt < sizeof (fw->risc_ram) / 2; cnt++) {
+		if (cnt % 8 == 0) {
+			qla_uprintf(&uiter, "\n%04x: ", cnt + 0x1000);
+		}
+		qla_uprintf(&uiter, "%04x ", fw->risc_ram[cnt]);
+	}
+
+	qla_uprintf(&uiter, "\n\n[<==END] ISP Debug Dump.");
+
+	return;
+}
+
+static int
+qla_uprintf(char **uiter, char *fmt, ...)
+{
+	int	iter, len;
+	char	buf[128];
+	va_list	args;
+ 
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	for (iter = 0; iter < len; iter++, *uiter += 1)
+		*uiter[0] = buf[iter];
+
+	return (len);
+}
+
+//FIXME
+
+/****************************************************************************/
+/*                         Driver Debug Functions.                          */
+/****************************************************************************/
+
+void 
+qla2x00_dump_regs(scsi_qla_host_t *ha) 
+{
+	device_reg_t __iomem *reg = ha->iobase;
+
+	printk("Mailbox registers:\n");
+	printk("scsi(%ld): mbox 0 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 0));
+	printk("scsi(%ld): mbox 1 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 1));
+	printk("scsi(%ld): mbox 2 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 2));
+	printk("scsi(%ld): mbox 3 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 3));
+	printk("scsi(%ld): mbox 4 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 4));
+	printk("scsi(%ld): mbox 5 0x%04x \n",
+	    ha->host_no, RD_MAILBOX_REG(ha, reg, 5));
+}
+
+
+void
+qla2x00_dump_buffer(uint8_t * b, uint32_t size) 
+{
+	uint32_t cnt;
+	uint8_t c;
+
+	printk(" 0   1   2   3   4   5   6   7   8   9  "
+	    "Ah  Bh  Ch  Dh  Eh  Fh\n");
+	printk("----------------------------------------"
+	    "----------------------\n");
+
+	for (cnt = 0; cnt < size;) {
+		c = *b++;
+		printk("%02x",(uint32_t) c);
+		cnt++;
+		if (!(cnt % 16))
+			printk("\n");
+		else
+			printk("  ");
+	}
+	if (cnt % 16)
+		printk("\n");
+}
+
+/**************************************************************************
+ *   qla2x00_print_scsi_cmd
+ *	 Dumps out info about the scsi cmd and srb.
+ *   Input	 
+ *	 cmd : struct scsi_cmnd
+ **************************************************************************/
+void
+qla2x00_print_scsi_cmd(struct scsi_cmnd * cmd) 
+{
+	int i;
+	struct scsi_qla_host *ha;
+	srb_t *sp;
+
+	ha = (struct scsi_qla_host *)cmd->device->host->hostdata;
+
+	sp = (srb_t *) cmd->SCp.ptr;
+	printk("SCSI Command @=0x%p, Handle=0x%p\n", cmd, cmd->host_scribble);
+	printk("  chan=0x%02x, target=0x%02x, lun=0x%02x, cmd_len=0x%02x\n",
+	    cmd->device->channel, cmd->device->id, cmd->device->lun,
+	    cmd->cmd_len);
+	printk(" CDB: ");
+	for (i = 0; i < cmd->cmd_len; i++) {
+		printk("0x%02x ", cmd->cmnd[i]);
+	}
+	printk("\n  seg_cnt=%d, allowed=%d, retries=%d, "
+	    "serial_number_at_timeout=0x%lx\n",
+	    cmd->use_sg, cmd->allowed, cmd->retries,
+	    cmd->serial_number_at_timeout);
+	printk("  request buffer=0x%p, request buffer len=0x%x\n",
+	    cmd->request_buffer, cmd->request_bufflen);
+	printk("  tag=%d, transfersize=0x%x\n",
+	    cmd->tag, cmd->transfersize);
+	printk("  serial_number=%lx, SP=%p\n", cmd->serial_number, sp); 
+	printk("  data direction=%d\n", cmd->sc_data_direction);
+
+	if (!sp)
+		return;
+
+	printk("  sp flags=0x%x\n", sp->flags);
+	printk("  r_start=0x%lx, u_start=0x%lx, f_start=0x%lx, state=%d\n",
+	    sp->r_start, sp->u_start, sp->f_start, sp->state);
+
+	printk(" e_start= 0x%lx, ext_history=%d, fo retry=%d, loopid=%x, "
+	    "port path=%d\n", sp->e_start, sp->ext_history, sp->fo_retry_cnt,
+	    sp->lun_queue->fclun->fcport->loop_id,
+	    sp->lun_queue->fclun->fcport->cur_path);
+}
+
+#if defined(QL_DEBUG_ROUTINES)
+/*
+ * qla2x00_formatted_dump_buffer
+ *       Prints string plus buffer.
+ *
+ * Input:
+ *       string  = Null terminated string (no newline at end).
+ *       buffer  = buffer address.
+ *       wd_size = word size 8, 16, 32 or 64 bits
+ *       count   = number of words.
+ */
+void
+qla2x00_formatted_dump_buffer(char *string, uint8_t * buffer, 
+				uint8_t wd_size, uint32_t count) 
+{
+	uint32_t cnt;
+	uint16_t *buf16;
+	uint32_t *buf32;
+
+	if (strcmp(string, "") != 0)
+		printk("%s\n",string);
+
+	switch (wd_size) {
+		case 8:
+			printk(" 0    1    2    3    4    5    6    7    "
+				"8    9    Ah   Bh   Ch   Dh   Eh   Fh\n");
+			printk("-----------------------------------------"
+				"-------------------------------------\n");
+
+			for (cnt = 1; cnt <= count; cnt++, buffer++) {
+				printk("%02x",*buffer);
+				if (cnt % 16 == 0)
+					printk("\n");
+				else
+					printk("  ");
+			}
+			if (cnt % 16 != 0)
+				printk("\n");
+			break;
+		case 16:
+			printk("   0      2      4      6      8      Ah "
+				"	Ch     Eh\n");
+			printk("-----------------------------------------"
+				"-------------\n");
+
+			buf16 = (uint16_t *) buffer;
+			for (cnt = 1; cnt <= count; cnt++, buf16++) {
+				printk("%4x",*buf16);
+
+				if (cnt % 8 == 0)
+					printk("\n");
+				else if (*buf16 < 10)
+					printk("   ");
+				else
+					printk("  ");
+			}
+			if (cnt % 8 != 0)
+				printk("\n");
+			break;
+		case 32:
+			printk("       0          4          8          Ch\n");
+			printk("------------------------------------------\n");
+
+			buf32 = (uint32_t *) buffer;
+			for (cnt = 1; cnt <= count; cnt++, buf32++) {
+				printk("%8x", *buf32);
+
+				if (cnt % 4 == 0)
+					printk("\n");
+				else if (*buf32 < 10)
+					printk("   ");
+				else
+					printk("  ");
+			}
+			if (cnt % 4 != 0)
+				printk("\n");
+			break;
+		default:
+			break;
+	}
+}
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_dbg.h b/drivers/scsi/qla2xxx/qla_dbg.h
new file mode 100644
index 0000000..d7f56c7
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_dbg.h
@@ -0,0 +1,233 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+/*
+ * Driver debug definitions.
+ */
+/* #define QL_DEBUG_LEVEL_1  */ /* Output register accesses to COM1 */
+/* #define QL_DEBUG_LEVEL_2  */ /* Output error msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_3  */ /* Output function trace msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_4  */ /* Output NVRAM trace msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_5  */ /* Output ring trace msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_6  */ /* Output WATCHDOG timer trace to COM1 */
+/* #define QL_DEBUG_LEVEL_7  */ /* Output RISC load trace msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_8  */ /* Output ring saturation msgs to COM1 */
+/* #define QL_DEBUG_LEVEL_9  */ /* Output IOCTL trace msgs */
+/* #define QL_DEBUG_LEVEL_10 */ /* Output IOCTL error msgs */
+/* #define QL_DEBUG_LEVEL_11 */ /* Output Mbx Cmd trace msgs */
+/* #define QL_DEBUG_LEVEL_12 */ /* Output IP trace msgs */
+/* #define QL_DEBUG_LEVEL_13 */ /* Output fdmi function trace msgs */
+/* #define QL_DEBUG_LEVEL_14 */ /* Output RSCN trace msgs */
+/*
+ *  Local Macro Definitions.
+ */
+#if defined(QL_DEBUG_LEVEL_1)  || defined(QL_DEBUG_LEVEL_2) || \
+    defined(QL_DEBUG_LEVEL_3)  || defined(QL_DEBUG_LEVEL_4) || \
+    defined(QL_DEBUG_LEVEL_5)  || defined(QL_DEBUG_LEVEL_6) || \
+    defined(QL_DEBUG_LEVEL_7)  || defined(QL_DEBUG_LEVEL_8) || \
+    defined(QL_DEBUG_LEVEL_9)  || defined(QL_DEBUG_LEVEL_10) || \
+    defined(QL_DEBUG_LEVEL_11) || defined(QL_DEBUG_LEVEL_12) || \
+    defined(QL_DEBUG_LEVEL_13) || defined(QL_DEBUG_LEVEL_14)
+    #define QL_DEBUG_ROUTINES
+#endif
+
+/*
+* Macros use for debugging the driver.
+*/
+#undef ENTER_TRACE
+#if defined(ENTER_TRACE)
+#define ENTER(x)	do { printk("qla2100 : Entering %s()\n", x); } while (0)
+#define LEAVE(x)	do { printk("qla2100 : Leaving %s()\n", x);  } while (0)
+#define ENTER_INTR(x)	do { printk("qla2100 : Entering %s()\n", x); } while (0)
+#define LEAVE_INTR(x)	do { printk("qla2100 : Leaving %s()\n", x);  } while (0)
+#else
+#define ENTER(x)	do {} while (0)
+#define LEAVE(x)	do {} while (0)
+#define ENTER_INTR(x) 	do {} while (0)
+#define LEAVE_INTR(x)   do {} while (0)
+#endif
+
+#if  DEBUG_QLA2100
+#define DEBUG(x)	do {x;} while (0);
+#else
+#define DEBUG(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_1)
+#define DEBUG1(x)	do {x;} while (0);
+#else
+#define DEBUG1(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_2)
+#define DEBUG2(x)       do {x;} while (0);
+#define DEBUG2_3(x)     do {x;} while (0);
+#define DEBUG2_3_11(x)  do {x;} while (0);
+#define DEBUG2_9_10(x)    do {x;} while (0);
+#define DEBUG2_11(x)    do {x;} while (0);
+#else
+#define DEBUG2(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_3)
+#define DEBUG3(x)	do {x;} while (0);
+#define DEBUG2_3(x)	do {x;} while (0);
+#define DEBUG2_3_11(x)	do {x;} while (0);
+#define DEBUG3_11(x)	do {x;} while (0);
+#else
+#define DEBUG3(x)	do {} while (0);
+  #if !defined(QL_DEBUG_LEVEL_2)
+  #define DEBUG2_3(x)	do {} while (0);
+  #endif
+#endif
+
+#if defined(QL_DEBUG_LEVEL_4)
+#define DEBUG4(x)	do {x;} while (0);
+#else
+#define DEBUG4(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_5)
+#define DEBUG5(x)          do {x;} while (0);
+#else
+#define DEBUG5(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_7)
+#define DEBUG7(x)          do {x;} while (0);
+#else
+#define DEBUG7(x)	   do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_9)
+#define DEBUG9(x)       do {x;} while (0);
+#define DEBUG9_10(x)    do {x;} while (0);
+#define DEBUG2_9_10(x)	do {x;} while (0);
+#else
+#define DEBUG9(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_10)
+#define DEBUG10(x)      do {x;} while (0);
+#define DEBUG2_9_10(x)	do {x;} while (0);
+#define DEBUG9_10(x)	do {x;} while (0);
+#else
+#define DEBUG10(x)	do {} while (0);
+  #if !defined(DEBUG2_9_10)
+  #define DEBUG2_9_10(x)	do {} while (0);
+  #endif
+  #if !defined(DEBUG9_10)
+  #define DEBUG9_10(x)	do {} while (0);
+  #endif
+#endif
+
+#if defined(QL_DEBUG_LEVEL_11)
+#define DEBUG11(x)      do{x;} while(0);
+#if !defined(DEBUG2_11)
+#define DEBUG2_11(x)    do{x;} while(0);
+#endif
+#if !defined(DEBUG2_3_11)
+#define DEBUG2_3_11(x)  do{x;} while(0);
+#endif
+#if !defined(DEBUG3_11)
+#define DEBUG3_11(x)    do{x;} while(0);
+#endif
+#else
+#define DEBUG11(x)	do{} while(0);
+  #if !defined(QL_DEBUG_LEVEL_2)
+  #define DEBUG2_11(x)	do{} while(0);
+    #if !defined(QL_DEBUG_LEVEL_3)
+    #define DEBUG2_3_11(x) do{} while(0);
+    #endif
+  #endif
+  #if !defined(QL_DEBUG_LEVEL_3)
+  #define DEBUG3_11(x)	do{} while(0);
+  #endif
+#endif
+
+#if defined(QL_DEBUG_LEVEL_12)
+#define DEBUG12(x)      do {x;} while (0);
+#else
+#define DEBUG12(x)	do {} while (0);
+#endif
+
+#if defined(QL_DEBUG_LEVEL_13)
+#define DEBUG13(x)      do {x;} while (0)
+#else
+#define DEBUG13(x)	do {} while (0)
+#endif
+
+#if defined(QL_DEBUG_LEVEL_14)
+#define DEBUG14(x)      do {x;} while (0)
+#else
+#define DEBUG14(x)	do {} while (0)
+#endif
+
+/*
+ * Firmware Dump structure definition
+ */
+#define FW_DUMP_SIZE_128K	0xBC000
+#define FW_DUMP_SIZE_512K	0x2FC000
+#define FW_DUMP_SIZE_1M		0x5FC000
+
+struct qla2300_fw_dump {
+	uint16_t hccr;
+	uint16_t pbiu_reg[8];
+	uint16_t risc_host_reg[8];
+	uint16_t mailbox_reg[32];
+	uint16_t resp_dma_reg[32];
+	uint16_t dma_reg[48];
+	uint16_t risc_hdw_reg[16];
+	uint16_t risc_gp0_reg[16];
+	uint16_t risc_gp1_reg[16];
+	uint16_t risc_gp2_reg[16];
+	uint16_t risc_gp3_reg[16];
+	uint16_t risc_gp4_reg[16];
+	uint16_t risc_gp5_reg[16];
+	uint16_t risc_gp6_reg[16];
+	uint16_t risc_gp7_reg[16];
+	uint16_t frame_buf_hdw_reg[64];
+	uint16_t fpm_b0_reg[64];
+	uint16_t fpm_b1_reg[64];
+	uint16_t risc_ram[0xf800];
+	uint16_t stack_ram[0x1000];
+	uint16_t data_ram[1];
+};
+
+struct qla2100_fw_dump {
+	uint16_t hccr;
+	uint16_t pbiu_reg[8];
+	uint16_t mailbox_reg[32];
+	uint16_t dma_reg[48];
+	uint16_t risc_hdw_reg[16];
+	uint16_t risc_gp0_reg[16];
+	uint16_t risc_gp1_reg[16];
+	uint16_t risc_gp2_reg[16];
+	uint16_t risc_gp3_reg[16];
+	uint16_t risc_gp4_reg[16];
+	uint16_t risc_gp5_reg[16];
+	uint16_t risc_gp6_reg[16];
+	uint16_t risc_gp7_reg[16];
+	uint16_t frame_buf_hdw_reg[16];
+	uint16_t fpm_b0_reg[64];
+	uint16_t fpm_b1_reg[64];
+	uint16_t risc_ram[0xf000];
+};
+
+
diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h
new file mode 100644
index 0000000..36ae031
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_def.h
@@ -0,0 +1,2497 @@
+/********************************************************************************
+*                  QLOGIC LINUX SOFTWARE
+*
+* QLogic ISP2x00 device driver for Linux 2.6.x
+* Copyright (C) 2003-2004 QLogic Corporation
+* (www.qlogic.com)
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+**
+******************************************************************************/
+
+#ifndef __QLA_DEF_H
+#define __QLA_DEF_H
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/dmapool.h>
+#include <linux/mempool.h>
+#include <linux/spinlock.h>
+#include <linux/completion.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+
+/* XXX(hch): move to pci_ids.h */
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP2300
+#define PCI_DEVICE_ID_QLOGIC_ISP2300	0x2300
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP2312
+#define PCI_DEVICE_ID_QLOGIC_ISP2312	0x2312
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP2322
+#define PCI_DEVICE_ID_QLOGIC_ISP2322	0x2322
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP6312
+#define PCI_DEVICE_ID_QLOGIC_ISP6312	0x6312
+#endif
+
+#ifndef PCI_DEVICE_ID_QLOGIC_ISP6322
+#define PCI_DEVICE_ID_QLOGIC_ISP6322	0x6322
+#endif
+
+#if defined(CONFIG_SCSI_QLA21XX) || defined(CONFIG_SCSI_QLA21XX_MODULE)
+#define IS_QLA2100(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2100)
+#else
+#define IS_QLA2100(ha)	0
+#endif
+
+#if defined(CONFIG_SCSI_QLA22XX) || defined(CONFIG_SCSI_QLA22XX_MODULE)
+#define IS_QLA2200(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2200)
+#else
+#define IS_QLA2200(ha)	0
+#endif
+
+#if defined(CONFIG_SCSI_QLA2300) || defined(CONFIG_SCSI_QLA2300_MODULE)
+#define IS_QLA2300(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2300)
+#define IS_QLA2312(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2312)
+#else
+#define IS_QLA2300(ha)	0
+#define IS_QLA2312(ha)	0
+#endif
+
+#if defined(CONFIG_SCSI_QLA2322) || defined(CONFIG_SCSI_QLA2322_MODULE)
+#define IS_QLA2322(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP2322)
+#else
+#define IS_QLA2322(ha)	0
+#endif
+
+#if defined(CONFIG_SCSI_QLA6312) || defined(CONFIG_SCSI_QLA6312_MODULE)
+#define IS_QLA6312(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6312)
+#define IS_QLA6322(ha)	((ha)->pdev->device == PCI_DEVICE_ID_QLOGIC_ISP6322)
+#else
+#define IS_QLA6312(ha)	0
+#define IS_QLA6322(ha)	0
+#endif
+
+#define IS_QLA23XX(ha)	(IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA2322(ha) || \
+    			 IS_QLA6312(ha) || IS_QLA6322(ha))
+
+/*
+ * Only non-ISP2[12]00 have extended addressing support in the firmware.
+ */
+#define HAS_EXTENDED_IDS(ha)	(!IS_QLA2100(ha) && !IS_QLA2200(ha))
+
+/*
+ * We have MAILBOX_REGISTER_COUNT sized arrays in a few places,
+ * but that's fine as we don't look at the last 24 ones for
+ * ISP2100 HBAs.
+ */
+#define MAILBOX_REGISTER_COUNT_2100	8
+#define MAILBOX_REGISTER_COUNT		32
+
+#define QLA2200A_RISC_ROM_VER	4
+#define FPM_2300		6
+#define FPM_2310		7
+
+#include "qla_settings.h"
+
+/* 
+ * Data bit definitions
+ */
+#define BIT_0	0x1
+#define BIT_1	0x2
+#define BIT_2	0x4
+#define BIT_3	0x8
+#define BIT_4	0x10
+#define BIT_5	0x20
+#define BIT_6	0x40
+#define BIT_7	0x80
+#define BIT_8	0x100
+#define BIT_9	0x200
+#define BIT_10	0x400
+#define BIT_11	0x800
+#define BIT_12	0x1000
+#define BIT_13	0x2000
+#define BIT_14	0x4000
+#define BIT_15	0x8000
+#define BIT_16	0x10000
+#define BIT_17	0x20000
+#define BIT_18	0x40000
+#define BIT_19	0x80000
+#define BIT_20	0x100000
+#define BIT_21	0x200000
+#define BIT_22	0x400000
+#define BIT_23	0x800000
+#define BIT_24	0x1000000
+#define BIT_25	0x2000000
+#define BIT_26	0x4000000
+#define BIT_27	0x8000000
+#define BIT_28	0x10000000
+#define BIT_29	0x20000000
+#define BIT_30	0x40000000
+#define BIT_31	0x80000000
+
+#define LSB(x)	((uint8_t)(x))
+#define MSB(x)	((uint8_t)((uint16_t)(x) >> 8))
+
+#define LSW(x)	((uint16_t)(x))
+#define MSW(x)	((uint16_t)((uint32_t)(x) >> 16))
+
+#define LSD(x)	((uint32_t)((uint64_t)(x)))
+#define MSD(x)	((uint32_t)((((uint64_t)(x)) >> 16) >> 16))
+
+
+/*
+ * I/O register
+*/
+
+#define RD_REG_BYTE(addr)		readb(addr)
+#define RD_REG_WORD(addr)		readw(addr)
+#define RD_REG_DWORD(addr)		readl(addr)
+#define RD_REG_BYTE_RELAXED(addr)	readb_relaxed(addr)
+#define RD_REG_WORD_RELAXED(addr)	readw_relaxed(addr)
+#define RD_REG_DWORD_RELAXED(addr)	readl_relaxed(addr)
+#define WRT_REG_BYTE(addr, data)	writeb(data,addr)
+#define WRT_REG_WORD(addr, data)	writew(data,addr)
+#define WRT_REG_DWORD(addr, data)	writel(data,addr)
+
+/*
+ * Fibre Channel device definitions.
+ */
+#define WWN_SIZE		8	/* Size of WWPN, WWN & WWNN */
+#define MAX_FIBRE_DEVICES	512
+#define MAX_FIBRE_LUNS  	256
+#define	MAX_RSCN_COUNT		32
+#define	MAX_HOST_COUNT		16
+
+/*
+ * Host adapter default definitions.
+ */
+#define MAX_BUSES		1  /* We only have one bus today */
+#define MAX_TARGETS_2100	MAX_FIBRE_DEVICES
+#define MAX_TARGETS_2200	MAX_FIBRE_DEVICES
+#define MAX_TARGETS		MAX_FIBRE_DEVICES
+#define MIN_LUNS		8
+#define MAX_LUNS		MAX_FIBRE_LUNS
+#define MAX_CMDS_PER_LUN	255 
+                                    
+/*
+ * Fibre Channel device definitions.
+ */
+#define SNS_LAST_LOOP_ID_2100	0xfe
+#define SNS_LAST_LOOP_ID_2300	0x7ff
+
+#define LAST_LOCAL_LOOP_ID	0x7d
+#define SNS_FL_PORT		0x7e
+#define FABRIC_CONTROLLER	0x7f
+#define SIMPLE_NAME_SERVER	0x80
+#define SNS_FIRST_LOOP_ID	0x81
+#define MANAGEMENT_SERVER	0xfe
+#define BROADCAST		0xff
+
+#define RESERVED_LOOP_ID(x)	((x > LAST_LOCAL_LOOP_ID && \
+				 x < SNS_FIRST_LOOP_ID) || \
+				 x == MANAGEMENT_SERVER || \
+				 x == BROADCAST)
+
+/*
+ * Timeout timer counts in seconds
+ */
+#define PORT_RETRY_TIME			2
+#define LOOP_DOWN_TIMEOUT		60
+#define LOOP_DOWN_TIME			255	/* 240 */
+#define	LOOP_DOWN_RESET			(LOOP_DOWN_TIME - 30)
+
+/* Maximum outstanding commands in ISP queues (1-65535) */
+#define MAX_OUTSTANDING_COMMANDS	1024
+
+/* ISP request and response entry counts (37-65535) */
+#define REQUEST_ENTRY_CNT_2100		128	/* Number of request entries. */
+#define REQUEST_ENTRY_CNT_2200		2048	/* Number of request entries. */
+#define REQUEST_ENTRY_CNT_2XXX_EXT_MEM	4096	/* Number of request entries. */
+#define RESPONSE_ENTRY_CNT_2100		64	/* Number of response entries.*/
+#define RESPONSE_ENTRY_CNT_2300		512	/* Number of response entries.*/
+
+/*
+ * SCSI Request Block 
+ */
+typedef struct srb {
+	struct list_head list;
+
+	struct scsi_qla_host *ha;	/* HA the SP is queued on */
+
+	struct scsi_cmnd *cmd;		/* Linux SCSI command pkt */
+
+	struct timer_list timer;	/* Command timer */
+	atomic_t ref_count;	/* Reference count for this structure */			
+	uint16_t flags;
+
+	/* Request state */
+	uint16_t state;
+
+	/* Target/LUN queue pointers. */
+	struct os_tgt *tgt_queue;	/* ptr to visible ha's target */
+	struct os_lun *lun_queue;	/* ptr to visible ha's lun */
+	struct fc_lun *fclun;		/* FC LUN context pointer. */
+
+	/* Timing counts. */
+	unsigned long e_start;		/* Start of extend timeout */
+	unsigned long r_start;		/* Start of request */
+	unsigned long u_start;		/* When sent to RISC */
+	unsigned long f_start;		/* When placed in FO queue*/
+
+	/* Single transfer DMA context */
+	dma_addr_t dma_handle;
+
+	uint32_t request_sense_length;
+	uint8_t *request_sense_ptr;
+
+	int ext_history;
+
+	/* Suspend delay */
+	int delay;
+
+	/* Raw completion info for use by failover ? */
+	uint8_t	fo_retry_cnt;		/* Retry count this request */
+	uint8_t	err_id;			/* error id */
+#define SRB_ERR_PORT	1		/* Request failed -- "port down" */
+#define SRB_ERR_LOOP	2		/* Request failed -- "loop down" */
+#define SRB_ERR_DEVICE	3		/* Request failed -- "device error" */
+#define SRB_ERR_OTHER	4
+
+	/* SRB magic number */
+	uint16_t magic;
+#define SRB_MAGIC       0x10CB
+} srb_t;
+
+/*
+ * SRB flag definitions
+ */
+#define SRB_TIMEOUT		BIT_0	/* Command timed out */
+#define SRB_DMA_VALID		BIT_1	/* Command sent to ISP */
+#define SRB_WATCHDOG		BIT_2	/* Command on watchdog list */
+#define SRB_ABORT_PENDING	BIT_3	/* Command abort sent to device */
+
+#define SRB_ABORTED		BIT_4	/* Command aborted command already */
+#define SRB_RETRY		BIT_5	/* Command needs retrying */
+#define SRB_GOT_SENSE		BIT_6	/* Command has sense data */
+#define SRB_FAILOVER		BIT_7	/* Command in failover state */
+
+#define SRB_BUSY		BIT_8	/* Command is in busy retry state */
+#define SRB_FO_CANCEL		BIT_9	/* Command don't need to do failover */
+#define SRB_IOCTL		BIT_10	/* IOCTL command. */
+#define SRB_TAPE		BIT_11	/* FCP2 (Tape) command. */
+
+/*
+ * SRB state definitions
+ */
+#define SRB_FREE_STATE		0	/*   returned back */
+#define SRB_PENDING_STATE	1	/*   queued in LUN Q */
+#define SRB_ACTIVE_STATE	2	/*   in Active Array */
+#define SRB_DONE_STATE		3	/*   queued in Done Queue */
+#define SRB_RETRY_STATE		4	/*   in Retry Queue */
+#define SRB_SUSPENDED_STATE	5	/*   in suspended state */
+#define SRB_NO_QUEUE_STATE	6	/*   is in between states */
+#define SRB_ACTIVE_TIMEOUT_STATE 7	/*   in Active Array but timed out */
+#define SRB_FAILOVER_STATE	8	/*   in Failover Queue */
+#define SRB_SCSI_RETRY_STATE	9	/*   in Scsi Retry Queue */
+
+
+/*
+ * ISP I/O Register Set structure definitions.
+ */
+typedef volatile struct {
+	volatile uint16_t flash_address; /* Flash BIOS address */
+	volatile uint16_t flash_data;	/* Flash BIOS data */
+	uint16_t unused_1[1];		/* Gap */
+	volatile uint16_t ctrl_status;	/* Control/Status */
+#define CSR_FLASH_64K_BANK	BIT_3	/* Flash upper 64K bank select */ 
+#define CSR_FLASH_ENABLE	BIT_1	/* Flash BIOS Read/Write enable */
+#define CSR_ISP_SOFT_RESET	BIT_0	/* ISP soft reset */
+
+	volatile uint16_t ictrl;	/* Interrupt control */
+#define ICR_EN_INT		BIT_15	/* ISP enable interrupts. */
+#define ICR_EN_RISC		BIT_3	/* ISP enable RISC interrupts. */
+
+	volatile uint16_t istatus;	/* Interrupt status */
+#define ISR_RISC_INT		BIT_3	/* RISC interrupt */
+
+	volatile uint16_t semaphore;	/* Semaphore */
+	volatile uint16_t nvram;	/* NVRAM register. */
+#define NVR_DESELECT		0
+#define NVR_BUSY		BIT_15
+#define NVR_WRT_ENABLE		BIT_14	/* Write enable */
+#define NVR_PR_ENABLE		BIT_13	/* Protection register enable */
+#define NVR_DATA_IN		BIT_3
+#define NVR_DATA_OUT		BIT_2
+#define NVR_SELECT		BIT_1
+#define NVR_CLOCK		BIT_0
+
+	union {
+		struct {
+			volatile uint16_t mailbox0;
+			volatile uint16_t mailbox1;
+			volatile uint16_t mailbox2;
+			volatile uint16_t mailbox3;
+			volatile uint16_t mailbox4;
+			volatile uint16_t mailbox5;
+			volatile uint16_t mailbox6;
+			volatile uint16_t mailbox7;
+			uint16_t unused_2[59];		/* Gap */
+		} __attribute__((packed)) isp2100;
+		struct {
+							/* Request Queue */
+			volatile uint16_t req_q_in;	/*  In-Pointer */
+			volatile uint16_t req_q_out;	/*  Out-Pointer */
+							/* Response Queue */
+			volatile uint16_t rsp_q_in;	/*  In-Pointer */
+			volatile uint16_t rsp_q_out;	/*  Out-Pointer */
+
+						/* RISC to Host Status */
+			volatile uint32_t host_status;	
+#define HSR_RISC_INT		BIT_15	/* RISC interrupt */
+#define HSR_RISC_PAUSED		BIT_8	/* RISC Paused */
+
+					/* Host to Host Semaphore */
+			volatile uint16_t host_semaphore; 
+			uint16_t unused_3[17];		/* Gap */
+			volatile uint16_t mailbox0;
+			volatile uint16_t mailbox1;
+			volatile uint16_t mailbox2;
+			volatile uint16_t mailbox3;
+			volatile uint16_t mailbox4;
+			volatile uint16_t mailbox5;
+			volatile uint16_t mailbox6;
+			volatile uint16_t mailbox7;
+			volatile uint16_t mailbox8;
+			volatile uint16_t mailbox9;
+			volatile uint16_t mailbox10;
+			volatile uint16_t mailbox11;
+			volatile uint16_t mailbox12;
+			volatile uint16_t mailbox13;
+			volatile uint16_t mailbox14;
+			volatile uint16_t mailbox15;
+			volatile uint16_t mailbox16;
+			volatile uint16_t mailbox17;
+			volatile uint16_t mailbox18;
+			volatile uint16_t mailbox19;
+			volatile uint16_t mailbox20;
+			volatile uint16_t mailbox21;
+			volatile uint16_t mailbox22;
+			volatile uint16_t mailbox23;
+			volatile uint16_t mailbox24;
+			volatile uint16_t mailbox25;
+			volatile uint16_t mailbox26;
+			volatile uint16_t mailbox27;
+			volatile uint16_t mailbox28;
+			volatile uint16_t mailbox29;
+			volatile uint16_t mailbox30;
+			volatile uint16_t mailbox31;
+			volatile uint16_t fb_cmd;
+			uint16_t unused_4[10];		/* Gap */
+		} __attribute__((packed)) isp2300;
+	} u;
+
+	volatile uint16_t fpm_diag_config;
+	uint16_t unused_5[0x6];		/* Gap */
+	volatile uint16_t pcr;		/* Processor Control Register. */
+	uint16_t unused_6[0x5];		/* Gap */
+	volatile uint16_t mctr;		/* Memory Configuration and Timing. */
+	uint16_t unused_7[0x3];		/* Gap */
+	volatile uint16_t fb_cmd_2100;	/* Unused on 23XX */
+	uint16_t unused_8[0x3];		/* Gap */
+	volatile uint16_t hccr;		/* Host command & control register. */
+#define HCCR_HOST_INT		BIT_7	/* Host interrupt bit */
+#define HCCR_RISC_PAUSE		BIT_5	/* Pause mode bit */
+					/* HCCR commands */
+#define HCCR_RESET_RISC		0x1000	/* Reset RISC */
+#define HCCR_PAUSE_RISC		0x2000	/* Pause RISC */
+#define HCCR_RELEASE_RISC	0x3000	/* Release RISC from reset. */
+#define HCCR_SET_HOST_INT	0x5000	/* Set host interrupt */
+#define HCCR_CLR_HOST_INT	0x6000	/* Clear HOST interrupt */
+#define HCCR_CLR_RISC_INT	0x7000	/* Clear RISC interrupt */
+#define	HCCR_DISABLE_PARITY_PAUSE 0x4001 /* Disable parity error RISC pause. */
+#define HCCR_ENABLE_PARITY	0xA000	/* Enable PARITY interrupt */
+
+	uint16_t unused_9[5];		/* Gap */
+	volatile uint16_t gpiod;	/* GPIO Data register. */
+	volatile uint16_t gpioe;	/* GPIO Enable register. */
+#define GPIO_LED_MASK			0x00C0
+#define GPIO_LED_GREEN_OFF_AMBER_OFF	0x0000
+#define GPIO_LED_GREEN_ON_AMBER_OFF	0x0040
+#define GPIO_LED_GREEN_OFF_AMBER_ON	0x0080
+#define GPIO_LED_GREEN_ON_AMBER_ON	0x00C0
+
+	union {
+		struct {
+			uint16_t unused_10[8];		/* Gap */
+			volatile uint16_t mailbox8;
+			volatile uint16_t mailbox9;
+			volatile uint16_t mailbox10;
+			volatile uint16_t mailbox11;
+			volatile uint16_t mailbox12;
+			volatile uint16_t mailbox13;
+			volatile uint16_t mailbox14;
+			volatile uint16_t mailbox15;
+			volatile uint16_t mailbox16;
+			volatile uint16_t mailbox17;
+			volatile uint16_t mailbox18;
+			volatile uint16_t mailbox19;
+			volatile uint16_t mailbox20;
+			volatile uint16_t mailbox21;
+			volatile uint16_t mailbox22;
+			volatile uint16_t mailbox23;	/* Also probe reg. */
+		} __attribute__((packed)) isp2200;
+	} u_end;
+} device_reg_t;
+
+#define ISP_REQ_Q_IN(ha, reg) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 &(reg)->u.isp2100.mailbox4 : \
+	 &(reg)->u.isp2300.req_q_in)
+#define ISP_REQ_Q_OUT(ha, reg) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 &(reg)->u.isp2100.mailbox4 : \
+	 &(reg)->u.isp2300.req_q_out)
+#define ISP_RSP_Q_IN(ha, reg) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 &(reg)->u.isp2100.mailbox5 : \
+	 &(reg)->u.isp2300.rsp_q_in)
+#define ISP_RSP_Q_OUT(ha, reg) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 &(reg)->u.isp2100.mailbox5 : \
+	 &(reg)->u.isp2300.rsp_q_out)
+
+#define MAILBOX_REG(ha, reg, num) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 (num < 8 ? \
+	  &(reg)->u.isp2100.mailbox0 + (num) : \
+	  &(reg)->u_end.isp2200.mailbox8 + (num) - 8) : \
+	 &(reg)->u.isp2300.mailbox0 + (num))
+#define RD_MAILBOX_REG(ha, reg, num) \
+	RD_REG_WORD(MAILBOX_REG(ha, reg, num))
+#define WRT_MAILBOX_REG(ha, reg, num, data) \
+	WRT_REG_WORD(MAILBOX_REG(ha, reg, num), data)
+
+#define FB_CMD_REG(ha, reg) \
+	(IS_QLA2100(ha) || IS_QLA2200(ha) ? \
+	 &(reg)->fb_cmd_2100 : \
+	 &(reg)->u.isp2300.fb_cmd)
+#define RD_FB_CMD_REG(ha, reg) \
+	RD_REG_WORD(FB_CMD_REG(ha, reg))
+#define WRT_FB_CMD_REG(ha, reg, data) \
+	WRT_REG_WORD(FB_CMD_REG(ha, reg), data)
+
+typedef struct {
+	uint32_t	out_mb;		/* outbound from driver */
+	uint32_t	in_mb;			/* Incoming from RISC */
+	uint16_t	mb[MAILBOX_REGISTER_COUNT];
+	long		buf_size;
+	void		*bufp;
+	uint32_t	tov;
+	uint8_t		flags;
+#define MBX_DMA_IN	BIT_0
+#define	MBX_DMA_OUT	BIT_1
+#define IOCTL_CMD	BIT_2
+} mbx_cmd_t;
+
+#define	MBX_TOV_SECONDS	30
+
+/*
+ *  ISP product identification definitions in mailboxes after reset.
+ */
+#define PROD_ID_1		0x4953
+#define PROD_ID_2		0x0000
+#define PROD_ID_2a		0x5020
+#define PROD_ID_3		0x2020
+
+/*
+ * ISP mailbox Self-Test status codes
+ */
+#define MBS_FRM_ALIVE		0	/* Firmware Alive. */
+#define MBS_CHKSUM_ERR		1	/* Checksum Error. */
+#define MBS_BUSY		4	/* Busy. */
+
+/*
+ * ISP mailbox command complete status codes
+ */
+#define MBS_COMMAND_COMPLETE		0x4000
+#define MBS_INVALID_COMMAND		0x4001
+#define MBS_HOST_INTERFACE_ERROR	0x4002
+#define MBS_TEST_FAILED			0x4003
+#define MBS_COMMAND_ERROR		0x4005
+#define MBS_COMMAND_PARAMETER_ERROR	0x4006
+#define MBS_PORT_ID_USED		0x4007
+#define MBS_LOOP_ID_USED		0x4008
+#define MBS_ALL_IDS_IN_USE		0x4009
+#define MBS_NOT_LOGGED_IN		0x400A
+
+/*
+ * ISP mailbox asynchronous event status codes
+ */
+#define MBA_ASYNC_EVENT		0x8000	/* Asynchronous event. */
+#define MBA_RESET		0x8001	/* Reset Detected. */
+#define MBA_SYSTEM_ERR		0x8002	/* System Error. */
+#define MBA_REQ_TRANSFER_ERR	0x8003	/* Request Transfer Error. */
+#define MBA_RSP_TRANSFER_ERR	0x8004	/* Response Transfer Error. */
+#define MBA_WAKEUP_THRES	0x8005	/* Request Queue Wake-up. */
+#define MBA_LIP_OCCURRED	0x8010	/* Loop Initialization Procedure */
+					/* occurred. */
+#define MBA_LOOP_UP		0x8011	/* FC Loop UP. */
+#define MBA_LOOP_DOWN		0x8012	/* FC Loop Down. */
+#define MBA_LIP_RESET		0x8013	/* LIP reset occurred. */
+#define MBA_PORT_UPDATE		0x8014	/* Port Database update. */
+#define MBA_RSCN_UPDATE		0x8015	/* Register State Chg Notification. */
+#define MBA_LIP_F8		0x8016	/* Received a LIP F8. */
+#define MBA_LOOP_INIT_ERR	0x8017	/* Loop Initialization Error. */
+#define MBA_FABRIC_AUTH_REQ	0x801b	/* Fabric Authentication Required. */
+#define MBA_SCSI_COMPLETION	0x8020	/* SCSI Command Complete. */
+#define MBA_CTIO_COMPLETION	0x8021	/* CTIO Complete. */
+#define MBA_IP_COMPLETION	0x8022	/* IP Transmit Command Complete. */
+#define MBA_IP_RECEIVE		0x8023	/* IP Received. */
+#define MBA_IP_BROADCAST	0x8024	/* IP Broadcast Received. */
+#define MBA_IP_LOW_WATER_MARK	0x8025	/* IP Low Water Mark reached. */
+#define MBA_IP_RCV_BUFFER_EMPTY 0x8026	/* IP receive buffer queue empty. */
+#define MBA_IP_HDR_DATA_SPLIT	0x8027	/* IP header/data splitting feature */
+					/* used. */
+#define MBA_POINT_TO_POINT	0x8030	/* Point to point mode. */
+#define MBA_CMPLT_1_16BIT	0x8031	/* Completion 1 16bit IOSB. */
+#define MBA_CMPLT_2_16BIT	0x8032	/* Completion 2 16bit IOSB. */
+#define MBA_CMPLT_3_16BIT	0x8033	/* Completion 3 16bit IOSB. */
+#define MBA_CMPLT_4_16BIT	0x8034	/* Completion 4 16bit IOSB. */
+#define MBA_CMPLT_5_16BIT	0x8035	/* Completion 5 16bit IOSB. */
+#define MBA_CHG_IN_CONNECTION	0x8036	/* Change in connection mode. */
+#define MBA_RIO_RESPONSE	0x8040	/* RIO response queue update. */
+#define MBA_ZIO_RESPONSE	0x8040	/* ZIO response queue update. */
+#define MBA_CMPLT_2_32BIT	0x8042	/* Completion 2 32bit IOSB. */
+#define MBA_BYPASS_NOTIFICATION	0x8043	/* Auto bypass notification. */
+#define MBA_DISCARD_RND_FRAME	0x8048	/* discard RND frame due to error. */
+#define MBA_REJECTED_FCP_CMD	0x8049	/* rejected FCP_CMD. */
+
+/*
+ * Firmware options 1, 2, 3.
+ */
+#define FO1_AE_ON_LIPF8			BIT_0
+#define FO1_AE_ALL_LIP_RESET		BIT_1
+#define FO1_CTIO_RETRY			BIT_3
+#define FO1_DISABLE_LIP_F7_SW		BIT_4
+#define FO1_DISABLE_100MS_LOS_WAIT	BIT_5
+#define FO1_DISABLE_GPIO6_7		BIT_6
+#define FO1_AE_ON_LOOP_INIT_ERR		BIT_7
+#define FO1_SET_EMPHASIS_SWING		BIT_8
+#define FO1_AE_AUTO_BYPASS		BIT_9
+#define FO1_ENABLE_PURE_IOCB		BIT_10
+#define FO1_AE_PLOGI_RJT		BIT_11
+#define FO1_ENABLE_ABORT_SEQUENCE	BIT_12
+#define FO1_AE_QUEUE_FULL		BIT_13
+
+#define FO2_ENABLE_ATIO_TYPE_3		BIT_0
+#define FO2_REV_LOOPBACK		BIT_1
+
+#define FO3_ENABLE_EMERG_IOCB		BIT_0
+#define FO3_AE_RND_ERROR		BIT_1
+
+/*
+ * ISP mailbox commands
+ */
+#define MBC_LOAD_RAM			1	/* Load RAM. */
+#define MBC_EXECUTE_FIRMWARE		2	/* Execute firmware. */
+#define MBC_WRITE_RAM_WORD		4	/* Write RAM word. */
+#define MBC_READ_RAM_WORD		5	/* Read RAM word. */
+#define MBC_MAILBOX_REGISTER_TEST	6	/* Wrap incoming mailboxes */
+#define MBC_VERIFY_CHECKSUM		7	/* Verify checksum. */
+#define MBC_GET_FIRMWARE_VERSION	8	/* Get firmware revision. */
+#define MBC_LOAD_RISC_RAM		9	/* Load RAM command. */
+#define MBC_DUMP_RISC_RAM		0xa	/* Dump RAM command. */
+#define MBC_LOAD_RISC_RAM_EXTENDED	0xb	/* Load RAM extended. */
+#define MBC_DUMP_RISC_RAM_EXTENDED	0xc	/* Dump RAM extended. */
+#define MBC_WRITE_RAM_WORD_EXTENDED	0xd	/* Write RAM word extended */
+#define MBC_READ_RAM_EXTENDED		0xf	/* Read RAM extended. */
+#define MBC_IOCB_COMMAND		0x12	/* Execute IOCB command. */
+#define MBC_ABORT_COMMAND		0x15	/* Abort IOCB command. */
+#define MBC_ABORT_DEVICE		0x16	/* Abort device (ID/LUN). */
+#define MBC_ABORT_TARGET		0x17	/* Abort target (ID). */
+#define MBC_RESET			0x18	/* Reset. */
+#define MBC_GET_ADAPTER_LOOP_ID		0x20	/* Get loop id of ISP2200. */
+#define MBC_GET_RETRY_COUNT		0x22	/* Get f/w retry cnt/delay. */
+#define MBC_DISABLE_VI			0x24	/* Disable VI operation. */
+#define MBC_ENABLE_VI			0x25	/* Enable VI operation. */
+#define MBC_GET_FIRMWARE_OPTION		0x28	/* Get Firmware Options. */
+#define MBC_SET_FIRMWARE_OPTION		0x38	/* Set Firmware Options. */
+#define MBC_LOOP_PORT_BYPASS		0x40	/* Loop Port Bypass. */
+#define MBC_LOOP_PORT_ENABLE		0x41	/* Loop Port Enable. */
+#define MBC_GET_RESOURCE_COUNTS		0x42	/* Get Resource Counts. */
+#define MBC_NON_PARTICIPATE		0x43	/* Non-Participating Mode. */
+#define MBC_DIAGNOSTIC_ECHO		0x44	/* Diagnostic echo. */
+#define MBC_DIAGNOSTIC_LOOP_BACK	0x45	/* Diagnostic loop back. */
+#define MBC_ONLINE_SELF_TEST		0x46	/* Online self-test. */
+#define MBC_ENHANCED_GET_PORT_DATABASE	0x47	/* Get port database + login */
+#define MBC_RESET_LINK_STATUS		0x52	/* Reset Link Error Status */
+#define MBC_IOCB_COMMAND_A64		0x54	/* Execute IOCB command (64) */
+#define MBC_SEND_RNID_ELS		0x57	/* Send RNID ELS request */
+#define MBC_SET_RNID_PARAMS		0x59	/* Set RNID parameters */
+#define MBC_GET_RNID_PARAMS		0x5a	/* Data Rate */
+#define MBC_DATA_RATE			0x5d	/* Get RNID parameters */
+#define MBC_INITIALIZE_FIRMWARE		0x60	/* Initialize firmware */
+#define MBC_INITIATE_LIP		0x62	/* Initiate Loop */
+						/* Initialization Procedure */
+#define MBC_GET_FC_AL_POSITION_MAP	0x63	/* Get FC_AL Position Map. */
+#define MBC_GET_PORT_DATABASE		0x64	/* Get Port Database. */
+#define MBC_CLEAR_ACA			0x65	/* Clear ACA. */
+#define MBC_TARGET_RESET		0x66	/* Target Reset. */
+#define MBC_CLEAR_TASK_SET		0x67	/* Clear Task Set. */
+#define MBC_ABORT_TASK_SET		0x68	/* Abort Task Set. */
+#define MBC_GET_FIRMWARE_STATE		0x69	/* Get firmware state. */
+#define MBC_GET_PORT_NAME		0x6a	/* Get port name. */
+#define MBC_GET_LINK_STATUS		0x6b	/* Get port link status. */
+#define MBC_LIP_RESET			0x6c	/* LIP reset. */
+#define MBC_SEND_SNS_COMMAND		0x6e	/* Send Simple Name Server */
+						/* commandd. */
+#define MBC_LOGIN_FABRIC_PORT		0x6f	/* Login fabric port. */
+#define MBC_SEND_CHANGE_REQUEST		0x70	/* Send Change Request. */
+#define MBC_LOGOUT_FABRIC_PORT		0x71	/* Logout fabric port. */
+#define MBC_LIP_FULL_LOGIN		0x72	/* Full login LIP. */
+#define MBC_LOGIN_LOOP_PORT		0x74	/* Login Loop Port. */
+#define MBC_PORT_NODE_NAME_LIST		0x75	/* Get port/node name list. */
+#define MBC_INITIALIZE_RECEIVE_QUEUE	0x77	/* Initialize receive queue */
+#define MBC_UNLOAD_IP			0x79	/* Shutdown IP */
+#define MBC_GET_ID_LIST			0x7C	/* Get Port ID list. */
+#define MBC_SEND_LFA_COMMAND		0x7D	/* Send Loop Fabric Address */
+#define MBC_LUN_RESET			0x7E	/* Send LUN reset */
+
+/* Firmware return data sizes */
+#define FCAL_MAP_SIZE	128
+
+/* Mailbox bit definitions for out_mb and in_mb */
+#define	MBX_31		BIT_31
+#define	MBX_30		BIT_30
+#define	MBX_29		BIT_29
+#define	MBX_28		BIT_28
+#define	MBX_27		BIT_27
+#define	MBX_26		BIT_26
+#define	MBX_25		BIT_25
+#define	MBX_24		BIT_24
+#define	MBX_23		BIT_23
+#define	MBX_22		BIT_22
+#define	MBX_21		BIT_21
+#define	MBX_20		BIT_20
+#define	MBX_19		BIT_19
+#define	MBX_18		BIT_18
+#define	MBX_17		BIT_17
+#define	MBX_16		BIT_16
+#define	MBX_15		BIT_15
+#define	MBX_14		BIT_14
+#define	MBX_13		BIT_13
+#define	MBX_12		BIT_12
+#define	MBX_11		BIT_11
+#define	MBX_10		BIT_10
+#define	MBX_9		BIT_9
+#define	MBX_8		BIT_8
+#define	MBX_7		BIT_7
+#define	MBX_6		BIT_6
+#define	MBX_5		BIT_5
+#define	MBX_4		BIT_4
+#define	MBX_3		BIT_3
+#define	MBX_2		BIT_2
+#define	MBX_1		BIT_1
+#define	MBX_0		BIT_0
+
+/*
+ * Firmware state codes from get firmware state mailbox command
+ */
+#define FSTATE_CONFIG_WAIT      0
+#define FSTATE_WAIT_AL_PA       1
+#define FSTATE_WAIT_LOGIN       2
+#define FSTATE_READY            3
+#define FSTATE_LOSS_OF_SYNC     4
+#define FSTATE_ERROR            5
+#define FSTATE_REINIT           6
+#define FSTATE_NON_PART         7
+
+#define FSTATE_CONFIG_CORRECT      0
+#define FSTATE_P2P_RCV_LIP         1
+#define FSTATE_P2P_CHOOSE_LOOP     2
+#define FSTATE_P2P_RCV_UNIDEN_LIP  3
+#define FSTATE_FATAL_ERROR         4
+#define FSTATE_LOOP_BACK_CONN      5
+
+/*
+ * Port Database structure definition
+ * Little endian except where noted.
+ */
+#define	PORT_DATABASE_SIZE	128	/* bytes */
+typedef struct {
+	uint8_t options;
+	uint8_t control;
+	uint8_t master_state;
+	uint8_t slave_state;
+	uint8_t reserved[2];
+	uint8_t hard_address;
+	uint8_t reserved_1;
+	uint8_t port_id[4];
+	uint8_t node_name[WWN_SIZE];
+	uint8_t port_name[WWN_SIZE];
+	uint16_t execution_throttle;
+	uint16_t execution_count;
+	uint8_t reset_count;
+	uint8_t reserved_2;
+	uint16_t resource_allocation;
+	uint16_t current_allocation;
+	uint16_t queue_head;
+	uint16_t queue_tail;
+	uint16_t transmit_execution_list_next;
+	uint16_t transmit_execution_list_previous;
+	uint16_t common_features;
+	uint16_t total_concurrent_sequences;
+	uint16_t RO_by_information_category;
+	uint8_t recipient;
+	uint8_t initiator;
+	uint16_t receive_data_size;
+	uint16_t concurrent_sequences;
+	uint16_t open_sequences_per_exchange;
+	uint16_t lun_abort_flags;
+	uint16_t lun_stop_flags;
+	uint16_t stop_queue_head;
+	uint16_t stop_queue_tail;
+	uint16_t port_retry_timer;
+	uint16_t next_sequence_id;
+	uint16_t frame_count;
+	uint16_t PRLI_payload_length;
+	uint8_t prli_svc_param_word_0[2];	/* Big endian */
+						/* Bits 15-0 of word 0 */
+	uint8_t prli_svc_param_word_3[2];	/* Big endian */
+						/* Bits 15-0 of word 3 */
+	uint16_t loop_id;
+	uint16_t extended_lun_info_list_pointer;
+	uint16_t extended_lun_stop_list_pointer;
+} port_database_t;
+
+/*
+ * Port database slave/master states
+ */
+#define PD_STATE_DISCOVERY			0
+#define PD_STATE_WAIT_DISCOVERY_ACK		1
+#define PD_STATE_PORT_LOGIN			2
+#define PD_STATE_WAIT_PORT_LOGIN_ACK		3
+#define PD_STATE_PROCESS_LOGIN			4
+#define PD_STATE_WAIT_PROCESS_LOGIN_ACK		5
+#define PD_STATE_PORT_LOGGED_IN			6
+#define PD_STATE_PORT_UNAVAILABLE		7
+#define PD_STATE_PROCESS_LOGOUT			8
+#define PD_STATE_WAIT_PROCESS_LOGOUT_ACK	9
+#define PD_STATE_PORT_LOGOUT			10
+#define PD_STATE_WAIT_PORT_LOGOUT_ACK		11
+
+
+/*
+ * ISP Initialization Control Block.
+ * Little endian except where noted.
+ */
+#define	ICB_VERSION 1
+typedef struct {
+	uint8_t  version;
+	uint8_t  reserved_1;
+
+	/*
+	 * LSB BIT 0  = Enable Hard Loop Id
+	 * LSB BIT 1  = Enable Fairness
+	 * LSB BIT 2  = Enable Full-Duplex
+	 * LSB BIT 3  = Enable Fast Posting
+	 * LSB BIT 4  = Enable Target Mode
+	 * LSB BIT 5  = Disable Initiator Mode
+	 * LSB BIT 6  = Enable ADISC
+	 * LSB BIT 7  = Enable Target Inquiry Data
+	 *
+	 * MSB BIT 0  = Enable PDBC Notify
+	 * MSB BIT 1  = Non Participating LIP
+	 * MSB BIT 2  = Descending Loop ID Search
+	 * MSB BIT 3  = Acquire Loop ID in LIPA
+	 * MSB BIT 4  = Stop PortQ on Full Status
+	 * MSB BIT 5  = Full Login after LIP
+	 * MSB BIT 6  = Node Name Option
+	 * MSB BIT 7  = Ext IFWCB enable bit
+	 */
+	uint8_t  firmware_options[2];
+
+	uint16_t frame_payload_size;
+	uint16_t max_iocb_allocation;
+	uint16_t execution_throttle;
+	uint8_t  retry_count;
+	uint8_t	 retry_delay;			/* unused */
+	uint8_t	 port_name[WWN_SIZE];		/* Big endian. */
+	uint16_t hard_address;
+	uint8_t	 inquiry_data;
+	uint8_t	 login_timeout;
+	uint8_t	 node_name[WWN_SIZE];		/* Big endian. */
+
+	uint16_t request_q_outpointer;
+	uint16_t response_q_inpointer;
+	uint16_t request_q_length;
+	uint16_t response_q_length;
+	uint32_t request_q_address[2];
+	uint32_t response_q_address[2];
+
+	uint16_t lun_enables;
+	uint8_t  command_resource_count;
+	uint8_t  immediate_notify_resource_count;
+	uint16_t timeout;
+	uint8_t  reserved_2[2];
+
+	/*
+	 * LSB BIT 0 = Timer Operation mode bit 0
+	 * LSB BIT 1 = Timer Operation mode bit 1
+	 * LSB BIT 2 = Timer Operation mode bit 2
+	 * LSB BIT 3 = Timer Operation mode bit 3
+	 * LSB BIT 4 = Init Config Mode bit 0
+	 * LSB BIT 5 = Init Config Mode bit 1
+	 * LSB BIT 6 = Init Config Mode bit 2
+	 * LSB BIT 7 = Enable Non part on LIHA failure
+	 *
+	 * MSB BIT 0 = Enable class 2
+	 * MSB BIT 1 = Enable ACK0
+	 * MSB BIT 2 =
+	 * MSB BIT 3 =
+	 * MSB BIT 4 = FC Tape Enable
+	 * MSB BIT 5 = Enable FC Confirm
+	 * MSB BIT 6 = Enable command queuing in target mode
+	 * MSB BIT 7 = No Logo On Link Down
+	 */
+	uint8_t	 add_firmware_options[2];
+
+	uint8_t	 response_accumulation_timer;
+	uint8_t	 interrupt_delay_timer;
+
+	/*
+	 * LSB BIT 0 = Enable Read xfr_rdy
+	 * LSB BIT 1 = Soft ID only
+	 * LSB BIT 2 =
+	 * LSB BIT 3 =
+	 * LSB BIT 4 = FCP RSP Payload [0]
+	 * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200
+	 * LSB BIT 6 = Enable Out-of-Order frame handling
+	 * LSB BIT 7 = Disable Automatic PLOGI on Local Loop
+	 *
+	 * MSB BIT 0 = Sbus enable - 2300
+	 * MSB BIT 1 =
+	 * MSB BIT 2 =
+	 * MSB BIT 3 =
+	 * MSB BIT 4 =
+	 * MSB BIT 5 = enable 50 ohm termination
+	 * MSB BIT 6 = Data Rate (2300 only)
+	 * MSB BIT 7 = Data Rate (2300 only)
+	 */
+	uint8_t	 special_options[2];
+
+	uint8_t  reserved_3[26];
+} init_cb_t;
+
+/*
+ * Get Link Status mailbox command return buffer.
+ */
+typedef struct {
+	uint32_t	link_fail_cnt;
+	uint32_t	loss_sync_cnt;
+	uint32_t	loss_sig_cnt;
+	uint32_t	prim_seq_err_cnt;
+	uint32_t	inval_xmit_word_cnt;
+	uint32_t	inval_crc_cnt;
+} link_stat_t;
+
+/*
+ * NVRAM Command values.
+ */
+#define NV_START_BIT            BIT_2
+#define NV_WRITE_OP             (BIT_26+BIT_24)
+#define NV_READ_OP              (BIT_26+BIT_25)
+#define NV_ERASE_OP             (BIT_26+BIT_25+BIT_24)
+#define NV_MASK_OP              (BIT_26+BIT_25+BIT_24)
+#define NV_DELAY_COUNT          10
+
+/*
+ * QLogic ISP2100, ISP2200 and ISP2300 NVRAM structure definition.
+ */
+typedef struct {
+	/*
+	 * NVRAM header
+	 */
+	uint8_t	id[4];
+	uint8_t	nvram_version;
+	uint8_t	reserved_0;
+
+	/*
+	 * NVRAM RISC parameter block
+	 */
+	uint8_t	parameter_block_version;
+	uint8_t	reserved_1;
+
+	/*
+	 * LSB BIT 0  = Enable Hard Loop Id
+	 * LSB BIT 1  = Enable Fairness
+	 * LSB BIT 2  = Enable Full-Duplex
+	 * LSB BIT 3  = Enable Fast Posting
+	 * LSB BIT 4  = Enable Target Mode
+	 * LSB BIT 5  = Disable Initiator Mode
+	 * LSB BIT 6  = Enable ADISC
+	 * LSB BIT 7  = Enable Target Inquiry Data
+	 *
+	 * MSB BIT 0  = Enable PDBC Notify
+	 * MSB BIT 1  = Non Participating LIP
+	 * MSB BIT 2  = Descending Loop ID Search
+	 * MSB BIT 3  = Acquire Loop ID in LIPA
+	 * MSB BIT 4  = Stop PortQ on Full Status
+	 * MSB BIT 5  = Full Login after LIP
+	 * MSB BIT 6  = Node Name Option
+	 * MSB BIT 7  = Ext IFWCB enable bit
+	 */
+	uint8_t	 firmware_options[2];
+
+	uint16_t frame_payload_size;
+	uint16_t max_iocb_allocation;
+	uint16_t execution_throttle;
+	uint8_t	 retry_count;
+	uint8_t	 retry_delay;			/* unused */
+	uint8_t	 port_name[WWN_SIZE];		/* Big endian. */
+	uint16_t hard_address;
+	uint8_t	 inquiry_data;
+	uint8_t	 login_timeout;
+	uint8_t	 node_name[WWN_SIZE];		/* Big endian. */
+
+	/*
+	 * LSB BIT 0 = Timer Operation mode bit 0
+	 * LSB BIT 1 = Timer Operation mode bit 1
+	 * LSB BIT 2 = Timer Operation mode bit 2
+	 * LSB BIT 3 = Timer Operation mode bit 3
+	 * LSB BIT 4 = Init Config Mode bit 0
+	 * LSB BIT 5 = Init Config Mode bit 1
+	 * LSB BIT 6 = Init Config Mode bit 2
+	 * LSB BIT 7 = Enable Non part on LIHA failure
+	 *
+	 * MSB BIT 0 = Enable class 2
+	 * MSB BIT 1 = Enable ACK0
+	 * MSB BIT 2 =
+	 * MSB BIT 3 =
+	 * MSB BIT 4 = FC Tape Enable
+	 * MSB BIT 5 = Enable FC Confirm
+	 * MSB BIT 6 = Enable command queuing in target mode
+	 * MSB BIT 7 = No Logo On Link Down
+	 */
+	uint8_t	 add_firmware_options[2];
+
+	uint8_t	 response_accumulation_timer;
+	uint8_t	 interrupt_delay_timer;
+
+	/*
+	 * LSB BIT 0 = Enable Read xfr_rdy
+	 * LSB BIT 1 = Soft ID only
+	 * LSB BIT 2 =
+	 * LSB BIT 3 =
+	 * LSB BIT 4 = FCP RSP Payload [0]
+	 * LSB BIT 5 = FCP RSP Payload [1] / Sbus enable - 2200
+	 * LSB BIT 6 = Enable Out-of-Order frame handling
+	 * LSB BIT 7 = Disable Automatic PLOGI on Local Loop
+	 *
+	 * MSB BIT 0 = Sbus enable - 2300
+	 * MSB BIT 1 =
+	 * MSB BIT 2 =
+	 * MSB BIT 3 =
+	 * MSB BIT 4 =
+	 * MSB BIT 5 = enable 50 ohm termination
+	 * MSB BIT 6 = Data Rate (2300 only)
+	 * MSB BIT 7 = Data Rate (2300 only)
+	 */
+	uint8_t	 special_options[2];
+
+	/* Reserved for expanded RISC parameter block */
+	uint8_t reserved_2[22];
+
+	/*
+	 * LSB BIT 0 = Tx Sensitivity 1G bit 0
+	 * LSB BIT 1 = Tx Sensitivity 1G bit 1
+	 * LSB BIT 2 = Tx Sensitivity 1G bit 2
+	 * LSB BIT 3 = Tx Sensitivity 1G bit 3
+	 * LSB BIT 4 = Rx Sensitivity 1G bit 0
+	 * LSB BIT 5 = Rx Sensitivity 1G bit 1
+	 * LSB BIT 6 = Rx Sensitivity 1G bit 2
+	 * LSB BIT 7 = Rx Sensitivity 1G bit 3
+	 *            
+	 * MSB BIT 0 = Tx Sensitivity 2G bit 0
+	 * MSB BIT 1 = Tx Sensitivity 2G bit 1
+	 * MSB BIT 2 = Tx Sensitivity 2G bit 2
+	 * MSB BIT 3 = Tx Sensitivity 2G bit 3
+	 * MSB BIT 4 = Rx Sensitivity 2G bit 0
+	 * MSB BIT 5 = Rx Sensitivity 2G bit 1
+	 * MSB BIT 6 = Rx Sensitivity 2G bit 2
+	 * MSB BIT 7 = Rx Sensitivity 2G bit 3
+	 *
+	 * LSB BIT 0 = Output Swing 1G bit 0
+	 * LSB BIT 1 = Output Swing 1G bit 1
+	 * LSB BIT 2 = Output Swing 1G bit 2
+	 * LSB BIT 3 = Output Emphasis 1G bit 0
+	 * LSB BIT 4 = Output Emphasis 1G bit 1
+	 * LSB BIT 5 = Output Swing 2G bit 0
+	 * LSB BIT 6 = Output Swing 2G bit 1
+	 * LSB BIT 7 = Output Swing 2G bit 2
+	 *            
+	 * MSB BIT 0 = Output Emphasis 2G bit 0
+	 * MSB BIT 1 = Output Emphasis 2G bit 1
+	 * MSB BIT 2 = Output Enable
+	 * MSB BIT 3 =
+	 * MSB BIT 4 =
+	 * MSB BIT 5 =
+	 * MSB BIT 6 =
+	 * MSB BIT 7 =
+	 */
+	uint8_t seriallink_options[4];
+
+	/*
+	 * NVRAM host parameter block
+	 *
+	 * LSB BIT 0 = Enable spinup delay
+	 * LSB BIT 1 = Disable BIOS
+	 * LSB BIT 2 = Enable Memory Map BIOS
+	 * LSB BIT 3 = Enable Selectable Boot
+	 * LSB BIT 4 = Disable RISC code load
+	 * LSB BIT 5 = Set cache line size 1
+	 * LSB BIT 6 = PCI Parity Disable
+	 * LSB BIT 7 = Enable extended logging
+	 *
+	 * MSB BIT 0 = Enable 64bit addressing
+	 * MSB BIT 1 = Enable lip reset
+	 * MSB BIT 2 = Enable lip full login
+	 * MSB BIT 3 = Enable target reset
+	 * MSB BIT 4 = Enable database storage
+	 * MSB BIT 5 = Enable cache flush read
+	 * MSB BIT 6 = Enable database load
+	 * MSB BIT 7 = Enable alternate WWN
+	 */
+	uint8_t host_p[2];
+
+	uint8_t boot_node_name[WWN_SIZE];
+	uint8_t boot_lun_number;
+	uint8_t reset_delay;
+	uint8_t port_down_retry_count;
+	uint8_t boot_id_number;
+	uint16_t max_luns_per_target;
+	uint8_t fcode_boot_port_name[WWN_SIZE];
+	uint8_t alternate_port_name[WWN_SIZE];
+	uint8_t alternate_node_name[WWN_SIZE];
+
+	/*
+	 * BIT 0 = Selective Login
+	 * BIT 1 = Alt-Boot Enable
+	 * BIT 2 =
+	 * BIT 3 = Boot Order List
+	 * BIT 4 =
+	 * BIT 5 = Selective LUN
+	 * BIT 6 =
+	 * BIT 7 = unused
+	 */
+	uint8_t efi_parameters;
+
+	uint8_t link_down_timeout;
+
+	uint8_t adapter_id_0[4];
+	uint8_t adapter_id_1[4];
+	uint8_t adapter_id_2[4];
+	uint8_t adapter_id_3[4];
+
+	uint8_t alt1_boot_node_name[WWN_SIZE];
+	uint16_t alt1_boot_lun_number;
+	uint8_t alt2_boot_node_name[WWN_SIZE];
+	uint16_t alt2_boot_lun_number;
+	uint8_t alt3_boot_node_name[WWN_SIZE];
+	uint16_t alt3_boot_lun_number;
+	uint8_t alt4_boot_node_name[WWN_SIZE];
+	uint16_t alt4_boot_lun_number;
+	uint8_t alt5_boot_node_name[WWN_SIZE];
+	uint16_t alt5_boot_lun_number;
+	uint8_t alt6_boot_node_name[WWN_SIZE];
+	uint16_t alt6_boot_lun_number;
+	uint8_t alt7_boot_node_name[WWN_SIZE];
+	uint16_t alt7_boot_lun_number;
+
+	uint8_t reserved_3[2];
+
+	/* Offset 200-215 : Model Number */
+	uint8_t model_number[16];
+
+	/* OEM related items */
+	uint8_t oem_specific[16];
+
+	/*
+	 * NVRAM Adapter Features offset 232-239
+	 *
+	 * LSB BIT 0 = External GBIC
+	 * LSB BIT 1 = Risc RAM parity
+	 * LSB BIT 2 = Buffer Plus Module
+	 * LSB BIT 3 = Multi Chip Adapter
+	 * LSB BIT 4 = Internal connector
+	 * LSB BIT 5 =
+	 * LSB BIT 6 =
+	 * LSB BIT 7 =
+	 *
+	 * MSB BIT 0 =
+	 * MSB BIT 1 =
+	 * MSB BIT 2 =
+	 * MSB BIT 3 =
+	 * MSB BIT 4 =
+	 * MSB BIT 5 =
+	 * MSB BIT 6 =
+	 * MSB BIT 7 =
+	 */
+	uint8_t	adapter_features[2];
+
+	uint8_t reserved_4[16];
+
+	/* Subsystem vendor ID for ISP2200 */
+	uint16_t subsystem_vendor_id_2200;
+
+	/* Subsystem device ID for ISP2200 */
+	uint16_t subsystem_device_id_2200;
+
+	uint8_t	 reserved_5;
+	uint8_t	 checksum;
+} nvram_t;
+
+/*
+ * ISP queue - response queue entry definition.
+ */
+typedef struct {
+	uint8_t		data[60];
+	uint32_t	signature;
+#define RESPONSE_PROCESSED	0xDEADDEAD	/* Signature */
+} response_t;
+
+typedef union {
+	uint16_t extended;
+	struct {
+		uint8_t reserved;
+		uint8_t standard;
+	} id;
+} target_id_t;
+
+#define SET_TARGET_ID(ha, to, from)			\
+do {							\
+	if (HAS_EXTENDED_IDS(ha))			\
+		to.extended = cpu_to_le16(from);	\
+	else						\
+		to.id.standard = (uint8_t)from;		\
+} while (0)
+
+/*
+ * ISP queue - command entry structure definition.
+ */
+#define COMMAND_TYPE	0x11		/* Command entry */
+#define MAX_CMDSZ	16		/* SCSI maximum CDB size. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	target_id_t target;		/* SCSI ID */
+	uint16_t lun;			/* SCSI LUN */
+	uint16_t control_flags;		/* Control flags. */
+#define CF_WRITE	BIT_6
+#define CF_READ		BIT_5
+#define CF_SIMPLE_TAG	BIT_3
+#define CF_ORDERED_TAG	BIT_2
+#define CF_HEAD_TAG	BIT_1
+	uint16_t reserved_1;
+	uint16_t timeout;		/* Command timeout. */
+	uint16_t dseg_count;		/* Data segment count. */
+	uint8_t scsi_cdb[MAX_CMDSZ]; 	/* SCSI command words. */
+	uint32_t byte_count;		/* Total byte count. */
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+	uint32_t dseg_2_address;	/* Data segment 2 address. */
+	uint32_t dseg_2_length;		/* Data segment 2 length. */
+} cmd_entry_t;
+
+/*
+ * ISP queue - 64-Bit addressing, command entry structure definition.
+ */
+#define COMMAND_A64_TYPE	0x19	/* Command A64 entry */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	target_id_t target;		/* SCSI ID */
+	uint16_t lun;			/* SCSI LUN */
+	uint16_t control_flags;		/* Control flags. */
+	uint16_t reserved_1;
+	uint16_t timeout;		/* Command timeout. */
+	uint16_t dseg_count;		/* Data segment count. */
+	uint8_t scsi_cdb[MAX_CMDSZ];	/* SCSI command words. */
+	uint32_t byte_count;		/* Total byte count. */
+	uint32_t dseg_0_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+} cmd_a64_entry_t, request_t;
+
+/*
+ * ISP queue - continuation entry structure definition.
+ */
+#define CONTINUE_TYPE		0x02	/* Continuation entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t reserved;
+	uint32_t dseg_0_address;	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address;	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+	uint32_t dseg_2_address;	/* Data segment 2 address. */
+	uint32_t dseg_2_length;		/* Data segment 2 length. */
+	uint32_t dseg_3_address;	/* Data segment 3 address. */
+	uint32_t dseg_3_length;		/* Data segment 3 length. */
+	uint32_t dseg_4_address;	/* Data segment 4 address. */
+	uint32_t dseg_4_length;		/* Data segment 4 length. */
+	uint32_t dseg_5_address;	/* Data segment 5 address. */
+	uint32_t dseg_5_length;		/* Data segment 5 length. */
+	uint32_t dseg_6_address;	/* Data segment 6 address. */
+	uint32_t dseg_6_length;		/* Data segment 6 length. */
+} cont_entry_t;
+
+/*
+ * ISP queue - 64-Bit addressing, continuation entry structure definition.
+ */
+#define CONTINUE_A64_TYPE	0x0A	/* Continuation A64 entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t dseg_0_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_0_length;		/* Data segment 0 length. */
+	uint32_t dseg_1_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_1_length;		/* Data segment 1 length. */
+	uint32_t dseg_2_address	[2];	/* Data segment 2 address. */
+	uint32_t dseg_2_length;		/* Data segment 2 length. */
+	uint32_t dseg_3_address[2];	/* Data segment 3 address. */
+	uint32_t dseg_3_length;		/* Data segment 3 length. */
+	uint32_t dseg_4_address[2];	/* Data segment 4 address. */
+	uint32_t dseg_4_length;		/* Data segment 4 length. */
+} cont_a64_entry_t;
+
+/*
+ * ISP queue - status entry structure definition.
+ */
+#define	STATUS_TYPE	0x03		/* Status entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle;		/* System handle. */
+	uint16_t scsi_status;		/* SCSI status. */
+	uint16_t comp_status;		/* Completion status. */
+	uint16_t state_flags;		/* State flags. */
+	uint16_t status_flags;		/* Status flags. */
+	uint16_t rsp_info_len;		/* Response Info Length. */
+	uint16_t req_sense_length;	/* Request sense data length. */
+	uint32_t residual_length;	/* Residual transfer length. */
+	uint8_t rsp_info[8];		/* FCP response information. */
+	uint8_t req_sense_data[32];	/* Request sense data. */
+} sts_entry_t;
+
+/*
+ * Status entry entry status
+ */
+#define RF_INV_E_ORDER	BIT_5		/* Invalid entry order. */
+#define RF_INV_E_COUNT	BIT_4		/* Invalid entry count. */
+#define RF_INV_E_PARAM	BIT_3		/* Invalid entry parameter. */
+#define RF_INV_E_TYPE	BIT_2		/* Invalid entry type. */
+#define RF_BUSY		BIT_1		/* Busy */
+
+/*
+ * Status entry SCSI status bit definitions.
+ */
+#define SS_MASK				0xfff	/* Reserved bits BIT_12-BIT_15*/
+#define SS_RESIDUAL_UNDER		BIT_11
+#define SS_RESIDUAL_OVER		BIT_10
+#define SS_SENSE_LEN_VALID		BIT_9
+#define SS_RESPONSE_INFO_LEN_VALID	BIT_8
+
+#define SS_RESERVE_CONFLICT		(BIT_4 | BIT_3)
+#define SS_BUSY_CONDITION		BIT_3
+#define SS_CONDITION_MET		BIT_2
+#define SS_CHECK_CONDITION		BIT_1
+
+/*
+ * Status entry completion status
+ */
+#define CS_COMPLETE		0x0	/* No errors */
+#define CS_INCOMPLETE		0x1	/* Incomplete transfer of cmd. */
+#define CS_DMA			0x2	/* A DMA direction error. */
+#define CS_TRANSPORT		0x3	/* Transport error. */
+#define CS_RESET		0x4	/* SCSI bus reset occurred */
+#define CS_ABORTED		0x5	/* System aborted command. */
+#define CS_TIMEOUT		0x6	/* Timeout error. */
+#define CS_DATA_OVERRUN		0x7	/* Data overrun. */
+
+#define CS_DATA_UNDERRUN	0x15	/* Data Underrun. */
+#define CS_QUEUE_FULL		0x1C	/* Queue Full. */
+#define CS_PORT_UNAVAILABLE	0x28	/* Port unavailable */
+					/* (selection timeout) */
+#define CS_PORT_LOGGED_OUT	0x29	/* Port Logged Out */
+#define CS_PORT_CONFIG_CHG	0x2A	/* Port Configuration Changed */
+#define CS_PORT_BUSY		0x2B	/* Port Busy */
+#define CS_COMPLETE_CHKCOND	0x30	/* Error? */
+#define CS_BAD_PAYLOAD		0x80	/* Driver defined */
+#define CS_UNKNOWN		0x81	/* Driver defined */
+#define CS_RETRY		0x82	/* Driver defined */
+#define CS_LOOP_DOWN_ABORT	0x83	/* Driver defined */
+
+/*
+ * Status entry status flags
+ */
+#define SF_ABTS_TERMINATED	BIT_10
+#define SF_LOGOUT_SENT		BIT_13
+
+/*
+ * ISP queue - status continuation entry structure definition.
+ */
+#define	STATUS_CONT_TYPE	0x10	/* Status continuation entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t sys_define;		/* System defined. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint8_t data[60];		/* data */
+} sts_cont_entry_t;
+
+/*
+ * ISP queue -	RIO Type 1 status entry (32 bit I/O entry handles)
+ *		structure definition.
+ */
+#define	STATUS_TYPE_21 0x21		/* Status entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle[15];		/* System handles. */
+} sts21_entry_t;
+
+/*
+ * ISP queue -	RIO Type 2 status entry (16 bit I/O entry handles)
+ *		structure definition.
+ */
+#define	STATUS_TYPE_22	0x22		/* Status entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint16_t handle[30];		/* System handles. */
+} sts22_entry_t;
+
+/*
+ * ISP queue - marker entry structure definition.
+ */
+#define MARKER_TYPE	0x04		/* Marker entry. */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t sys_define_2;		/* System defined. */
+	target_id_t target;		/* SCSI ID */
+	uint8_t modifier;		/* Modifier (7-0). */
+#define MK_SYNC_ID_LUN	0		/* Synchronize ID/LUN */
+#define MK_SYNC_ID	1		/* Synchronize ID */
+#define MK_SYNC_ALL	2		/* Synchronize all ID/LUN */
+#define MK_SYNC_LIP	3		/* Synchronize all ID/LUN, */
+					/* clear port changed, */
+					/* use sequence number. */
+	uint8_t reserved_1;
+	uint16_t sequence_number;	/* Sequence number of event */
+	uint16_t lun;			/* SCSI LUN */
+	uint8_t reserved_2[48];
+} mrk_entry_t;
+
+/*
+ * ISP queue - Management Server entry structure definition.
+ */
+#define MS_IOCB_TYPE		0x29	/* Management Server IOCB entry */
+typedef struct {
+	uint8_t entry_type;		/* Entry type. */
+	uint8_t entry_count;		/* Entry count. */
+	uint8_t handle_count;		/* Handle count. */
+	uint8_t entry_status;		/* Entry Status. */
+	uint32_t handle1;		/* System handle. */
+	target_id_t loop_id;
+	uint16_t status;
+	uint16_t control_flags;		/* Control flags. */
+	uint16_t reserved2;
+	uint16_t timeout;
+	uint16_t cmd_dsd_count;
+	uint16_t total_dsd_count;
+	uint8_t type;
+	uint8_t r_ctl;
+	uint16_t rx_id;
+	uint16_t reserved3;
+	uint32_t handle2;
+	uint32_t rsp_bytecount;
+	uint32_t req_bytecount;
+	uint32_t dseg_req_address[2];	/* Data segment 0 address. */
+	uint32_t dseg_req_length;	/* Data segment 0 length. */
+	uint32_t dseg_rsp_address[2];	/* Data segment 1 address. */
+	uint32_t dseg_rsp_length;	/* Data segment 1 length. */
+} ms_iocb_entry_t;
+
+
+/*
+ * ISP queue - Mailbox Command entry structure definition.
+ */
+#define MBX_IOCB_TYPE	0x39
+struct mbx_entry {
+	uint8_t entry_type;
+	uint8_t entry_count;
+	uint8_t sys_define1;
+	/* Use sys_define1 for source type */
+#define SOURCE_SCSI	0x00
+#define SOURCE_IP	0x01
+#define SOURCE_VI	0x02
+#define SOURCE_SCTP	0x03
+#define SOURCE_MP	0x04
+#define SOURCE_MPIOCTL	0x05
+#define SOURCE_ASYNC_IOCB 0x07
+
+	uint8_t entry_status;
+
+	uint32_t handle;
+	target_id_t loop_id;
+
+	uint16_t status;
+	uint16_t state_flags;
+	uint16_t status_flags;
+
+	uint32_t sys_define2[2];
+
+	uint16_t mb0;
+	uint16_t mb1;
+	uint16_t mb2;
+	uint16_t mb3;
+	uint16_t mb6;
+	uint16_t mb7;
+	uint16_t mb9;
+	uint16_t mb10;
+	uint32_t reserved_2[2];
+	uint8_t node_name[WWN_SIZE];
+	uint8_t port_name[WWN_SIZE];
+};
+
+/*
+ * ISP request and response queue entry sizes
+ */
+#define RESPONSE_ENTRY_SIZE	(sizeof(response_t))
+#define REQUEST_ENTRY_SIZE	(sizeof(request_t))
+
+
+/*
+ * 24 bit port ID type definition.
+ */
+typedef union {
+	uint32_t b24 : 24;
+
+	struct {
+		uint8_t d_id[3];
+		uint8_t rsvd_1;
+	} r;
+
+	struct {
+		uint8_t al_pa;
+		uint8_t area;
+		uint8_t domain;
+		uint8_t rsvd_1;
+	} b;
+} port_id_t;
+#define INVALID_PORT_ID	0xFFFFFF
+
+/*
+ * Switch info gathering structure.
+ */
+typedef struct {
+	port_id_t d_id;
+	uint8_t node_name[WWN_SIZE];
+	uint8_t port_name[WWN_SIZE];
+	uint32_t type;
+#define SW_TYPE_IP	BIT_1
+#define SW_TYPE_SCSI	BIT_0
+} sw_info_t;
+
+/*
+ * Inquiry command structure.
+ */
+#define INQ_DATA_SIZE	36
+
+/*
+ * Inquiry mailbox IOCB packet definition.
+ */
+typedef struct {
+	union {
+		cmd_a64_entry_t cmd;
+		sts_entry_t rsp;
+	} p;
+	uint8_t inq[INQ_DATA_SIZE];
+} inq_cmd_rsp_t;
+
+/*
+ * Report LUN command structure.
+ */
+#define CHAR_TO_SHORT(a, b)	(uint16_t)((uint8_t)b << 8 | (uint8_t)a)
+
+typedef struct {
+	uint32_t len;
+	uint32_t rsrv;
+} rpt_hdr_t;
+
+typedef struct {
+	struct {
+		uint8_t b : 6;
+		uint8_t address_method : 2;
+	} msb;
+	uint8_t lsb;
+	uint8_t unused[6];
+} rpt_lun_t;
+
+typedef struct {
+	rpt_hdr_t hdr;
+	rpt_lun_t lst[MAX_LUNS];
+} rpt_lun_lst_t;
+
+/*
+ * Report Lun mailbox IOCB packet definition.
+ */
+typedef struct {
+	union {
+		cmd_a64_entry_t cmd;
+		sts_entry_t rsp;
+	} p;
+	rpt_lun_lst_t list;
+} rpt_lun_cmd_rsp_t;
+
+/*
+ * SCSI Target Queue structure
+ */
+typedef struct os_tgt {
+	struct os_lun *olun[MAX_LUNS]; /* LUN context pointer. */
+	struct fc_port *fcport;
+	unsigned long flags;
+	uint8_t port_down_retry_count;
+    	uint32_t down_timer;
+	struct scsi_qla_host *ha;
+
+	/* Persistent binding information */
+	port_id_t d_id;
+	uint8_t node_name[WWN_SIZE];
+	uint8_t port_name[WWN_SIZE];
+} os_tgt_t;
+
+/*
+ * SCSI Target Queue flags
+ */
+#define TQF_ONLINE		0		/* Device online to OS. */
+#define TQF_SUSPENDED		1
+#define TQF_RETRY_CMDS		2
+
+/*
+ * SCSI LUN Queue structure
+ */
+typedef struct os_lun {
+	struct fc_lun *fclun;		/* FC LUN context pointer. */
+    	spinlock_t q_lock;		/* Lun Lock */
+
+	unsigned long q_flag;
+#define LUN_MPIO_RESET_CNTS	1	/* Lun */
+#define LUN_MPIO_BUSY		2	/* Lun is changing paths  */
+#define LUN_EXEC_DELAYED	7	/* Lun execution is delayed */
+
+	u_long q_timeout;		/* total command timeouts */
+	atomic_t q_timer;		/* suspend timer */
+	uint32_t q_count;		/* current count */
+	uint32_t q_max;			/* maxmum count lun can be suspended */
+	uint8_t q_state;		/* lun State */
+#define LUN_STATE_READY		1	/* lun is ready for i/o */
+#define LUN_STATE_RUN		2	/* lun has a timer running */
+#define LUN_STATE_WAIT		3	/* lun is suspended */
+#define LUN_STATE_TIMEOUT	4	/* lun has timed out */
+
+	u_long io_cnt;			/* total xfer count since boot */
+	u_long out_cnt;			/* total outstanding IO count */
+	u_long w_cnt;			/* total writes */
+	u_long r_cnt;			/* total reads */
+	u_long avg_time;		/*  */
+} os_lun_t;
+
+
+/* LUN BitMask structure definition, array of 32bit words,
+ * 1 bit per lun.  When bit == 1, the lun is masked.
+ * Most significant bit of mask[0] is lun 0, bit 24 is lun 7.
+ */
+typedef struct lun_bit_mask {
+	/* Must allocate at least enough bits to accomodate all LUNs */
+#if ((MAX_FIBRE_LUNS & 0x7) == 0)
+	uint8_t mask[MAX_FIBRE_LUNS >> 3];
+#else
+	uint8_t mask[(MAX_FIBRE_LUNS + 8) >> 3];
+#endif
+} lun_bit_mask_t;
+
+/*
+ * Fibre channel port type.
+ */
+ typedef enum {
+	FCT_UNKNOWN,
+	FCT_RSCN,
+	FCT_SWITCH,
+	FCT_BROADCAST,
+	FCT_INITIATOR,
+	FCT_TARGET
+} fc_port_type_t;
+
+/*
+ * Fibre channel port structure.
+ */
+typedef struct fc_port {
+	struct list_head list;
+	struct list_head fcluns;
+
+	struct scsi_qla_host *ha;
+	struct scsi_qla_host *vis_ha;	/* only used when suspending lun */
+
+	uint8_t node_name[WWN_SIZE];
+	uint8_t port_name[WWN_SIZE];
+	port_id_t d_id;
+	uint16_t loop_id;
+	uint16_t old_loop_id;
+
+	fc_port_type_t port_type;
+
+	atomic_t state;
+	uint32_t flags;
+
+	os_tgt_t *tgt_queue;
+	uint16_t os_target_id;
+
+	uint16_t iodesc_idx_sent;
+
+	int port_login_retry_count;
+	int login_retry;
+	atomic_t port_down_timer;
+
+	uint8_t device_type;
+	uint8_t unused;
+
+	uint8_t mp_byte;		/* multi-path byte (not used) */
+    	uint8_t cur_path;		/* current path id */
+
+	lun_bit_mask_t lun_mask;
+} fc_port_t;
+
+/*
+ * Fibre channel port/lun states.
+ */
+#define FCS_UNCONFIGURED	1
+#define FCS_DEVICE_DEAD		2
+#define FCS_DEVICE_LOST		3
+#define FCS_ONLINE		4
+#define FCS_NOT_SUPPORTED	5
+#define FCS_FAILOVER		6
+#define FCS_FAILOVER_FAILED	7
+
+/*
+ * FC port flags.
+ */
+#define FCF_FABRIC_DEVICE	BIT_0
+#define FCF_LOGIN_NEEDED	BIT_1
+#define FCF_FO_MASKED		BIT_2
+#define FCF_FAILOVER_NEEDED	BIT_3
+#define FCF_RESET_NEEDED	BIT_4
+#define FCF_PERSISTENT_BOUND	BIT_5
+#define FCF_TAPE_PRESENT	BIT_6
+#define FCF_FARP_DONE		BIT_7
+#define FCF_FARP_FAILED		BIT_8
+#define FCF_FARP_REPLY_NEEDED	BIT_9
+#define FCF_AUTH_REQ		BIT_10
+#define FCF_SEND_AUTH_REQ	BIT_11
+#define FCF_RECEIVE_AUTH_REQ	BIT_12
+#define FCF_AUTH_SUCCESS	BIT_13
+#define FCF_RLC_SUPPORT		BIT_14
+#define FCF_CONFIG		BIT_15	/* Needed? */
+#define FCF_RESCAN_NEEDED	BIT_16
+#define FCF_XP_DEVICE		BIT_17
+#define FCF_MSA_DEVICE		BIT_18
+#define FCF_EVA_DEVICE		BIT_19
+#define FCF_MSA_PORT_ACTIVE	BIT_20
+#define FCF_FAILBACK_DISABLE	BIT_21
+#define FCF_FAILOVER_DISABLE	BIT_22
+#define FCF_DSXXX_DEVICE	BIT_23
+#define FCF_AA_EVA_DEVICE	BIT_24
+
+/* No loop ID flag. */
+#define FC_NO_LOOP_ID		0x1000
+
+/*
+ * Fibre channel LUN structure.
+ */
+typedef struct fc_lun {
+        struct list_head list;
+
+	fc_port_t *fcport;
+	fc_port_t *o_fcport;
+	uint16_t lun;
+	atomic_t state;
+	uint8_t device_type;
+
+	uint8_t max_path_retries;
+	uint32_t flags;
+} fc_lun_t;
+
+#define	FLF_VISIBLE_LUN		BIT_0
+#define	FLF_ACTIVE_LUN		BIT_1
+
+/*
+ * FC-CT interface
+ *
+ * NOTE: All structures are big-endian in form.
+ */
+
+#define CT_REJECT_RESPONSE	0x8001
+#define CT_ACCEPT_RESPONSE	0x8002
+
+#define NS_N_PORT_TYPE	0x01
+#define NS_NL_PORT_TYPE	0x02
+#define NS_NX_PORT_TYPE	0x7F
+
+#define	GA_NXT_CMD	0x100
+#define	GA_NXT_REQ_SIZE	(16 + 4)
+#define	GA_NXT_RSP_SIZE	(16 + 620)
+
+#define	GID_PT_CMD	0x1A1
+#define	GID_PT_REQ_SIZE	(16 + 4)
+#define	GID_PT_RSP_SIZE	(16 + (MAX_FIBRE_DEVICES * 4))
+
+#define	GPN_ID_CMD	0x112
+#define	GPN_ID_REQ_SIZE	(16 + 4)
+#define	GPN_ID_RSP_SIZE	(16 + 8)
+
+#define	GNN_ID_CMD	0x113
+#define	GNN_ID_REQ_SIZE	(16 + 4)
+#define	GNN_ID_RSP_SIZE	(16 + 8)
+
+#define	GFT_ID_CMD	0x117
+#define	GFT_ID_REQ_SIZE	(16 + 4)
+#define	GFT_ID_RSP_SIZE	(16 + 32)
+
+#define	RFT_ID_CMD	0x217
+#define	RFT_ID_REQ_SIZE	(16 + 4 + 32)
+#define	RFT_ID_RSP_SIZE	16
+
+#define	RFF_ID_CMD	0x21F
+#define	RFF_ID_REQ_SIZE	(16 + 4 + 2 + 1 + 1)
+#define	RFF_ID_RSP_SIZE	16
+
+#define	RNN_ID_CMD	0x213
+#define	RNN_ID_REQ_SIZE	(16 + 4 + 8)
+#define	RNN_ID_RSP_SIZE	16
+
+#define	RSNN_NN_CMD	 0x239
+#define	RSNN_NN_REQ_SIZE (16 + 8 + 1 + 255)
+#define	RSNN_NN_RSP_SIZE 16
+
+/* CT command header -- request/response common fields */
+struct ct_cmd_hdr {
+	uint8_t revision;
+	uint8_t in_id[3];
+	uint8_t gs_type;
+	uint8_t gs_subtype;
+	uint8_t options;
+	uint8_t reserved;
+};
+
+/* CT command request */
+struct ct_sns_req {
+	struct ct_cmd_hdr header;
+	uint16_t command;
+	uint16_t max_rsp_size;
+	uint8_t fragment_id;
+	uint8_t reserved[3];
+
+	union {
+		/* GA_NXT, GPN_ID, GNN_ID, GFT_ID */
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+		} port_id;
+
+		struct {
+			uint8_t port_type;
+			uint8_t domain;
+			uint8_t area;
+			uint8_t reserved;
+		} gid_pt;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint8_t fc4_types[32];
+		} rft_id;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint16_t reserved2;
+			uint8_t fc4_feature;
+			uint8_t fc4_type;
+		} rff_id;
+
+		struct {
+			uint8_t reserved;
+			uint8_t port_id[3];
+			uint8_t node_name[8];
+		} rnn_id;
+
+		struct {
+			uint8_t node_name[8];
+			uint8_t name_len;
+			uint8_t sym_node_name[255];
+		} rsnn_nn;
+	} req;
+};
+
+/* CT command response header */
+struct ct_rsp_hdr {
+	struct ct_cmd_hdr header;
+	uint16_t response;
+	uint16_t residual;
+	uint8_t fragment_id;
+	uint8_t reason_code;
+	uint8_t explanation_code;
+	uint8_t vendor_unique;
+};
+
+struct ct_sns_gid_pt_data {
+	uint8_t control_byte;
+	uint8_t port_id[3];
+};
+
+struct ct_sns_rsp {
+	struct ct_rsp_hdr header;
+
+	union {
+		struct {
+			uint8_t port_type;
+			uint8_t port_id[3];
+			uint8_t port_name[8];
+			uint8_t sym_port_name_len;
+			uint8_t sym_port_name[255];
+			uint8_t node_name[8];
+			uint8_t sym_node_name_len;
+			uint8_t sym_node_name[255];
+			uint8_t init_proc_assoc[8];
+			uint8_t node_ip_addr[16];
+			uint8_t class_of_service[4];
+			uint8_t fc4_types[32];
+			uint8_t ip_address[16];
+			uint8_t fabric_port_name[8];
+			uint8_t reserved;
+			uint8_t hard_address[3];
+		} ga_nxt;
+
+		struct {
+			struct ct_sns_gid_pt_data entries[MAX_FIBRE_DEVICES];
+		} gid_pt;
+
+		struct {
+			uint8_t port_name[8];
+		} gpn_id;
+
+		struct {
+			uint8_t node_name[8];
+		} gnn_id;
+
+		struct {
+			uint8_t fc4_types[32];
+		} gft_id;
+	} rsp;
+};
+
+struct ct_sns_pkt {
+	union {
+		struct ct_sns_req req;
+		struct ct_sns_rsp rsp;
+	} p;
+};
+
+/*
+ * SNS command structures -- for 2200 compatability.
+ */
+#define	RFT_ID_SNS_SCMD_LEN	22
+#define	RFT_ID_SNS_CMD_SIZE	60
+#define	RFT_ID_SNS_DATA_SIZE	16
+
+#define	RNN_ID_SNS_SCMD_LEN	10
+#define	RNN_ID_SNS_CMD_SIZE	36
+#define	RNN_ID_SNS_DATA_SIZE	16
+
+#define	GA_NXT_SNS_SCMD_LEN	6
+#define	GA_NXT_SNS_CMD_SIZE	28
+#define	GA_NXT_SNS_DATA_SIZE	(620 + 16)
+
+#define	GID_PT_SNS_SCMD_LEN	6
+#define	GID_PT_SNS_CMD_SIZE	28
+#define	GID_PT_SNS_DATA_SIZE	(MAX_FIBRE_DEVICES * 4 + 16)
+
+#define	GPN_ID_SNS_SCMD_LEN	6
+#define	GPN_ID_SNS_CMD_SIZE	28
+#define	GPN_ID_SNS_DATA_SIZE	(8 + 16)
+
+#define	GNN_ID_SNS_SCMD_LEN	6
+#define	GNN_ID_SNS_CMD_SIZE	28
+#define	GNN_ID_SNS_DATA_SIZE	(8 + 16)
+
+struct sns_cmd_pkt {
+	union {
+		struct {
+			uint16_t buffer_length;
+			uint16_t reserved_1;
+			uint32_t buffer_address[2];
+			uint16_t subcommand_length;
+			uint16_t reserved_2;
+			uint16_t subcommand;
+			uint16_t size;
+			uint32_t reserved_3;
+			uint8_t param[36];
+		} cmd;
+
+		uint8_t rft_data[RFT_ID_SNS_DATA_SIZE];
+		uint8_t rnn_data[RNN_ID_SNS_DATA_SIZE];
+		uint8_t gan_data[GA_NXT_SNS_DATA_SIZE];
+		uint8_t gid_data[GID_PT_SNS_DATA_SIZE];
+		uint8_t gpn_data[GPN_ID_SNS_DATA_SIZE];
+		uint8_t gnn_data[GNN_ID_SNS_DATA_SIZE];
+	} p;
+};
+
+/* IO descriptors */
+#define MAX_IO_DESCRIPTORS	32
+
+#define ABORT_IOCB_CB		0
+#define ADISC_PORT_IOCB_CB	1
+#define LOGOUT_PORT_IOCB_CB	2
+#define LOGIN_PORT_IOCB_CB	3
+#define LAST_IOCB_CB		4
+
+#define IODESC_INVALID_INDEX	0xFFFF
+#define IODESC_ADISC_NEEDED	0xFFFE
+#define IODESC_LOGIN_NEEDED	0xFFFD
+
+struct io_descriptor {
+	uint16_t used:1;
+	uint16_t idx:11;
+	uint16_t cb_idx:4;
+
+	struct timer_list timer;
+
+	struct scsi_qla_host *ha;
+
+	port_id_t d_id;
+	fc_port_t *remote_fcport;
+
+	uint32_t signature;
+};
+
+struct qla_fw_info {
+	unsigned short addressing;	/* addressing method used to load fw */
+#define FW_INFO_ADDR_NORMAL	0
+#define FW_INFO_ADDR_EXTENDED	1
+#define FW_INFO_ADDR_NOMORE	0xffff
+	unsigned short *fwcode;		/* pointer to FW array */
+	unsigned short *fwlen;		/* number of words in array */
+	unsigned short *fwstart;	/* start address for F/W */
+	unsigned long *lfwstart;	/* start address (long) for F/W */
+};
+
+struct qla_board_info {
+	char *drv_name;
+
+	char isp_name[8];
+	struct qla_fw_info *fw_info;
+};
+
+/* Return data from MBC_GET_ID_LIST call. */
+struct gid_list_info {
+	uint8_t	al_pa;
+	uint8_t	area;
+	uint8_t	domain;		
+	uint8_t	loop_id_2100;	/* ISP2100/ISP2200 -- 4 bytes. */
+	uint16_t loop_id;	/* ISP23XX         -- 6 bytes. */
+};
+#define GID_LIST_SIZE (sizeof(struct gid_list_info) * MAX_FIBRE_DEVICES)
+
+/*
+ * Linux Host Adapter structure
+ */
+typedef struct scsi_qla_host {
+	struct list_head list;
+
+	/* Commonly used flags and state information. */
+	struct Scsi_Host *host;
+	struct pci_dev	*pdev;
+
+	unsigned long	host_no;
+	unsigned long	instance;
+
+	volatile struct {
+		uint32_t	init_done		:1;
+		uint32_t	online			:1;
+		uint32_t	mbox_int		:1;
+		uint32_t	mbox_busy		:1;
+		uint32_t	rscn_queue_overflow	:1;
+		uint32_t	reset_active		:1;
+
+		uint32_t	management_server_logged_in :1;
+                uint32_t	process_response_queue	:1;
+
+		uint32_t	disable_risc_code_load	:1;
+		uint32_t	enable_64bit_addressing	:1;
+		uint32_t	enable_lip_reset	:1;
+		uint32_t	enable_lip_full_login	:1;
+		uint32_t	enable_target_reset	:1;
+		uint32_t	enable_led_scheme	:1;
+	} flags;
+
+	atomic_t	loop_state;
+#define LOOP_TIMEOUT	1
+#define LOOP_DOWN	2
+#define LOOP_UP		3
+#define LOOP_UPDATE	4
+#define LOOP_READY	5
+#define LOOP_DEAD	6
+
+	unsigned long   dpc_flags;
+#define	RESET_MARKER_NEEDED	0	/* Send marker to ISP. */
+#define	RESET_ACTIVE		1
+#define	ISP_ABORT_NEEDED	2	/* Initiate ISP abort. */
+#define	ABORT_ISP_ACTIVE	3	/* ISP abort in progress. */
+#define	LOOP_RESYNC_NEEDED	4	/* Device Resync needed. */
+#define	LOOP_RESYNC_ACTIVE	5
+#define LOCAL_LOOP_UPDATE       6	/* Perform a local loop update. */
+#define RSCN_UPDATE             7	/* Perform an RSCN update. */
+#define MAILBOX_RETRY           8
+#define ISP_RESET_NEEDED        9	/* Initiate a ISP reset. */
+#define FAILOVER_EVENT_NEEDED   10
+#define FAILOVER_EVENT		11
+#define FAILOVER_NEEDED   	12
+#define SCSI_RESTART_NEEDED	13	/* Processes SCSI retry queue. */
+#define PORT_RESTART_NEEDED	14	/* Processes Retry queue. */
+#define RESTART_QUEUES_NEEDED	15	/* Restarts the Lun queue. */
+#define ABORT_QUEUES_NEEDED	16
+#define RELOGIN_NEEDED	        17
+#define LOGIN_RETRY_NEEDED	18	/* Initiate required fabric logins. */
+#define REGISTER_FC4_NEEDED	19	/* SNS FC4 registration required. */
+#define ISP_ABORT_RETRY         20      /* ISP aborted. */
+#define FCPORT_RESCAN_NEEDED	21      /* IO descriptor processing needed */
+#define IODESC_PROCESS_NEEDED	22      /* IO descriptor processing needed */
+#define IOCTL_ERROR_RECOVERY	23      
+#define LOOP_RESET_NEEDED	24
+
+	uint32_t	device_flags;
+#define DFLG_LOCAL_DEVICES		BIT_0
+#define DFLG_RETRY_LOCAL_DEVICES	BIT_1
+#define DFLG_FABRIC_DEVICES		BIT_2
+#define	SWITCH_FOUND			BIT_3
+#define	DFLG_NO_CABLE			BIT_4
+
+	/* SRB cache. */
+#define SRB_MIN_REQ	128
+	mempool_t	*srb_mempool;
+
+	/* This spinlock is used to protect "io transactions", you must	
+	 * aquire it before doing any IO to the card, eg with RD_REG*() and
+	 * WRT_REG*() for the duration of your entire commandtransaction.
+	 *
+	 * This spinlock is of lower priority than the io request lock.
+	 */
+
+	spinlock_t		hardware_lock ____cacheline_aligned;
+
+	device_reg_t __iomem *iobase;		/* Base I/O address */
+	unsigned long	pio_address;
+	unsigned long	pio_length;
+#define MIN_IOBASE_LEN		0x100
+
+	/* ISP ring lock, rings, and indexes */
+	dma_addr_t	request_dma;        /* Physical address. */
+	request_t       *request_ring;      /* Base virtual address */
+	request_t       *request_ring_ptr;  /* Current address. */
+	uint16_t        req_ring_index;     /* Current index. */
+	uint16_t        req_q_cnt;          /* Number of available entries. */
+	uint16_t	request_q_length;
+
+	dma_addr_t	response_dma;       /* Physical address. */
+	response_t      *response_ring;     /* Base virtual address */
+	response_t      *response_ring_ptr; /* Current address. */
+	uint16_t        rsp_ring_index;     /* Current index. */
+	uint16_t	response_q_length;
+    
+	uint16_t	(*calc_request_entries)(uint16_t);
+	void		(*build_scsi_iocbs)(srb_t *, cmd_entry_t *, uint16_t);
+
+	/* Outstandings ISP commands. */
+	srb_t		*outstanding_cmds[MAX_OUTSTANDING_COMMANDS];
+	uint32_t	current_outstanding_cmd; 
+	srb_t		*status_srb;	/* Status continuation entry. */
+
+	/*
+	 * Need to hold the list_lock with irq's disabled in order to access
+	 * the following list.
+	 *
+	 * This list_lock is of lower priority than the host_lock.
+	 */
+	spinlock_t		list_lock ____cacheline_aligned;
+						/* lock to guard lists which
+						 * hold srb_t's */
+        struct list_head        retry_queue;    /* watchdog queue */
+        struct list_head        done_queue;     /* job on done queue */
+        struct list_head        failover_queue; /* failover list link. */
+	struct list_head        scsi_retry_queue;     /* SCSI retry queue */
+	struct list_head        pending_queue;	/* SCSI command pending queue */
+
+	unsigned long    done_q_cnt;
+	unsigned long    pending_in_q;
+        uint32_t	retry_q_cnt; 
+        uint32_t	scsi_retry_q_cnt; 
+        uint32_t	failover_cnt; 
+
+	unsigned long	last_irq_cpu;	/* cpu where we got our last irq */
+
+	uint16_t           revision;
+	uint8_t           ports;
+	u_long            actthreads;
+	u_long            ipreq_cnt;
+	u_long            qthreads;
+
+	uint32_t        total_isr_cnt;		/* Interrupt count */
+	uint32_t        total_isp_aborts;	/* controller err cnt */
+	uint32_t        total_lip_cnt;		/* LIP cnt */
+	uint32_t	total_dev_errs;		/* device error cnt */
+	uint32_t	total_ios;		/* IO cnt */
+	uint64_t	total_bytes;		/* xfr byte cnt */
+	uint32_t	total_mbx_timeout;	/* mailbox timeout cnt */
+	uint32_t 	total_loop_resync; 	/* loop resyn cnt */
+	uint32_t	dropped_frame_error_cnt;
+
+	/* ISP configuration data. */
+	uint16_t	loop_id;		/* Host adapter loop id */
+	uint16_t	fb_rev;
+
+	port_id_t	d_id;			/* Host adapter port id */
+	uint16_t	max_public_loop_ids;
+	uint16_t	min_external_loopid;	/* First external loop Id */
+
+	uint16_t	link_data_rate;		/* F/W operating speed */
+
+	uint8_t		current_topology;
+	uint8_t		prev_topology;
+#define ISP_CFG_NL	1
+#define ISP_CFG_N	2
+#define ISP_CFG_FL	4
+#define ISP_CFG_F	8
+
+	uint8_t		operating_mode;		/* F/W operating mode */
+#define LOOP      0
+#define P2P       1
+#define LOOP_P2P  2
+#define P2P_LOOP  3
+
+        uint8_t		marker_needed; 
+	uint8_t		sns_retry_cnt;
+	uint8_t		mem_err;
+
+	uint8_t		interrupts_on;
+
+	/* HBA serial number */
+	uint8_t		serial0;
+	uint8_t		serial1;
+	uint8_t		serial2;
+
+	/* NVRAM configuration data */
+	uint16_t	nvram_base;
+
+	uint16_t	loop_reset_delay;
+	uint16_t	minimum_timeout;
+	uint8_t		retry_count;
+	uint8_t		login_timeout;
+	uint16_t	r_a_tov;
+	int		port_down_retry_count;
+	uint8_t		loop_down_timeout;
+	uint8_t		mbx_count;
+	uint16_t	max_probe_luns;
+	uint16_t	max_luns;
+	uint16_t	max_targets;
+	uint16_t	last_loop_id;
+
+        uint32_t	login_retry_count; 
+
+	/* Fibre Channel Device List. */
+	struct list_head	fcports;
+	struct list_head	rscn_fcports;
+
+	struct io_descriptor	io_descriptors[MAX_IO_DESCRIPTORS];
+	uint16_t		iodesc_signature;
+
+	/* OS target queue pointers. */
+	os_tgt_t		*otgt[MAX_FIBRE_DEVICES];
+
+	/* RSCN queue. */
+	uint32_t rscn_queue[MAX_RSCN_COUNT];
+	uint8_t rscn_in_ptr;
+	uint8_t rscn_out_ptr;
+
+	/* SNS command interfaces. */
+	ms_iocb_entry_t		*ms_iocb;
+	dma_addr_t		ms_iocb_dma;
+	struct ct_sns_pkt	*ct_sns;
+	dma_addr_t		ct_sns_dma;
+	/* SNS command interfaces for 2200. */
+	struct sns_cmd_pkt	*sns_cmd;
+	dma_addr_t		sns_cmd_dma;
+
+	pid_t			dpc_pid;
+	int			dpc_should_die;
+	struct completion	dpc_inited;
+	struct completion	dpc_exited;
+	struct semaphore	*dpc_wait;
+	uint8_t dpc_active;                  /* DPC routine is active */
+
+	/* Timeout timers. */
+	uint8_t         queue_restart_timer;   
+	uint8_t         loop_down_abort_time;    /* port down timer */
+	atomic_t        loop_down_timer;         /* loop down timer */
+	uint8_t         link_down_timeout;       /* link down timeout */
+
+	uint32_t        timer_active;
+	struct timer_list        timer;
+
+	dma_addr_t	gid_list_dma;
+	struct gid_list_info *gid_list;
+
+	dma_addr_t	rlc_rsp_dma;
+	rpt_lun_cmd_rsp_t *rlc_rsp;
+
+	/* Small DMA pool allocations -- maximum 256 bytes in length. */ 
+#define DMA_POOL_SIZE	256
+	struct dma_pool *s_dma_pool;
+
+	dma_addr_t	init_cb_dma;
+	init_cb_t       *init_cb;
+
+	dma_addr_t	iodesc_pd_dma;
+	port_database_t *iodesc_pd;
+
+	/* These are used by mailbox operations. */
+	volatile uint16_t mailbox_out[MAILBOX_REGISTER_COUNT];
+
+	mbx_cmd_t	*mcp;
+	unsigned long	mbx_cmd_flags;
+#define MBX_INTERRUPT	1
+#define MBX_INTR_WAIT	2
+#define MBX_UPDATE_FLASH_ACTIVE	3
+
+	spinlock_t	mbx_reg_lock;   /* Mbx Cmd Register Lock */
+
+	struct semaphore mbx_cmd_sem;	/* Serialialize mbx access */
+	struct semaphore mbx_intr_sem;  /* Used for completion notification */
+
+	uint32_t	mbx_flags;
+#define  MBX_IN_PROGRESS	BIT_0
+#define  MBX_BUSY		BIT_1	/* Got the Access */
+#define  MBX_SLEEPING_ON_SEM	BIT_2 
+#define  MBX_POLLING_FOR_COMP	BIT_3
+#define  MBX_COMPLETED		BIT_4
+#define  MBX_TIMEDOUT		BIT_5 
+#define  MBX_ACCESS_TIMEDOUT	BIT_6
+
+	mbx_cmd_t 	mc;
+
+	uint8_t	*cmdline;
+
+	uint32_t failover_type;
+	uint32_t failback_delay;
+	unsigned long   cfg_flags;
+#define	CFG_ACTIVE	0	/* CFG during a failover, event update, or ioctl */
+#define	CFG_FAILOVER	1	/* CFG during path change */
+
+	uint32_t	binding_type;
+#define BIND_BY_PORT_NAME	0
+#define BIND_BY_PORT_ID		1
+
+	/* Basic firmware related information. */
+	struct qla_board_info	*brd_info;
+	uint16_t	fw_major_version;
+	uint16_t	fw_minor_version;
+	uint16_t	fw_subminor_version;
+	uint16_t	fw_attributes;
+	uint32_t	fw_memory_size;
+	uint32_t	fw_transfer_size;
+
+	uint16_t	fw_options[16];		/* slots: 1,2,3,10,11 */
+	uint8_t		fw_seriallink_options[4];
+
+	/* Firmware dump information. */
+	void		*fw_dump;
+	int		fw_dump_order;
+	int		fw_dump_reading;
+	char		*fw_dump_buffer;
+	int		fw_dump_buffer_len;
+
+	uint8_t		host_str[16];
+	uint16_t	pci_attr;
+
+	uint16_t	product_id[4];
+
+	uint8_t		model_number[16+1];
+#define BINZERO		"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
+	char		*model_desc;
+
+	uint8_t     node_name[WWN_SIZE];
+	uint8_t     nvram_version; 
+	uint32_t    isp_abort_cnt;
+
+	/* Adapter I/O statistics for failover */
+	uint64_t	IosRequested;
+	uint64_t	BytesRequested;
+	uint64_t	IosExecuted;
+	uint64_t	BytesExecuted;
+
+	/* Needed for BEACON */
+	uint16_t	beacon_blink_led;
+	uint16_t	beacon_green_on;
+} scsi_qla_host_t;
+
+
+/*
+ * Macros to help code, maintain, etc.
+ */
+#define LOOP_TRANSITION(ha) \
+	(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \
+	 test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+
+#define LOOP_NOT_READY(ha) \
+	((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) || \
+	  test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) || \
+	  test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) || \
+	  test_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags)) || \
+	 atomic_read(&ha->loop_state) == LOOP_DOWN)
+				 
+#define LOOP_RDY(ha)	(!LOOP_NOT_READY(ha))
+
+#define TGT_Q(ha, t) (ha->otgt[t])
+#define LUN_Q(ha, t, l)	(TGT_Q(ha, t)->olun[l])
+#define GET_LU_Q(ha, t, l) ((TGT_Q(ha,t) != NULL)? TGT_Q(ha, t)->olun[l] : NULL)
+
+#define to_qla_host(x)		((scsi_qla_host_t *) (x)->hostdata)
+
+#define qla_printk(level, ha, format, arg...) \
+	dev_printk(level , &((ha)->pdev->dev) , format , ## arg)
+
+/*
+ * qla2x00 local function return status codes
+ */
+#define MBS_MASK		0x3fff
+
+#define QLA_SUCCESS		(MBS_COMMAND_COMPLETE & MBS_MASK)
+#define QLA_INVALID_COMMAND	(MBS_INVALID_COMMAND & MBS_MASK)
+#define QLA_INTERFACE_ERROR	(MBS_HOST_INTERFACE_ERROR & MBS_MASK)
+#define QLA_TEST_FAILED		(MBS_TEST_FAILED & MBS_MASK)
+#define QLA_COMMAND_ERROR	(MBS_COMMAND_ERROR & MBS_MASK)
+#define QLA_PARAMETER_ERROR	(MBS_COMMAND_PARAMETER_ERROR & MBS_MASK)
+#define QLA_PORT_ID_USED	(MBS_PORT_ID_USED & MBS_MASK)
+#define QLA_LOOP_ID_USED	(MBS_LOOP_ID_USED & MBS_MASK)
+#define QLA_ALL_IDS_IN_USE	(MBS_ALL_IDS_IN_USE & MBS_MASK)
+#define QLA_NOT_LOGGED_IN	(MBS_NOT_LOGGED_IN & MBS_MASK)
+
+#define QLA_FUNCTION_TIMEOUT		0x100
+#define QLA_FUNCTION_PARAMETER_ERROR	0x101
+#define QLA_FUNCTION_FAILED		0x102
+#define QLA_MEMORY_ALLOC_FAILED		0x103
+#define QLA_LOCK_TIMEOUT		0x104
+#define QLA_ABORTED			0x105
+#define QLA_SUSPENDED			0x106
+#define QLA_BUSY			0x107
+#define QLA_RSCNS_HANDLED		0x108
+
+/*
+* Stat info for all adpaters
+*/
+struct _qla2x00stats  {
+        unsigned long   mboxtout;            /* mailbox timeouts */
+        unsigned long   mboxerr;             /* mailbox errors */
+        unsigned long   ispAbort;            /* ISP aborts */
+        unsigned long   debugNo;
+        unsigned long   loop_resync;
+        unsigned long   outarray_full;
+        unsigned long   retry_q_cnt;
+};
+
+#define NVRAM_DELAY()		udelay(10)
+
+#define INVALID_HANDLE	(MAX_OUTSTANDING_COMMANDS+1)
+
+/*
+ * Flash support definitions
+ */
+#define FLASH_IMAGE_SIZE	131072
+
+#include "qla_gbl.h"
+#include "qla_dbg.h"
+#include "qla_inline.h"
+#include "qla_listops.h"
+
+/*
+* String arrays
+*/
+#define LINESIZE    256
+#define MAXARGS      26
+
+#define CMD_SP(Cmnd)		((Cmnd)->SCp.ptr)
+#define CMD_COMPL_STATUS(Cmnd)  ((Cmnd)->SCp.this_residual)
+#define CMD_RESID_LEN(Cmnd)	((Cmnd)->SCp.buffers_residual)
+#define CMD_SCSI_STATUS(Cmnd)	((Cmnd)->SCp.Status)
+#define CMD_ACTUAL_SNSLEN(Cmnd)	((Cmnd)->SCp.Message)
+#define CMD_ENTRY_STATUS(Cmnd)	((Cmnd)->SCp.have_data_in)
+
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_devtbl.h b/drivers/scsi/qla2xxx/qla_devtbl.h
new file mode 100644
index 0000000..4de4801
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_devtbl.h
@@ -0,0 +1,110 @@
+#define QLA_MODEL_NAMES         0x32
+
+/*
+ * Adapter model names.
+ */
+static char *qla2x00_model_name[QLA_MODEL_NAMES] = {
+	"QLA2340",	/* 0x100 */
+	"QLA2342",	/* 0x101 */
+	"QLA2344",	/* 0x102 */
+	"QCP2342",	/* 0x103 */
+	"QSB2340",	/* 0x104 */
+	"QSB2342",	/* 0x105 */
+	"QLA2310",	/* 0x106 */
+	"QLA2332",	/* 0x107 */
+	"QCP2332",	/* 0x108 */
+	"QCP2340",	/* 0x109 */
+	"QLA2342",	/* 0x10a */
+	"QCP2342",	/* 0x10b */
+	"QLA2350",	/* 0x10c */
+	"QLA2352",	/* 0x10d */
+	"QLA2352",	/* 0x10e */
+	"HPQ SVS",	/* 0x10f */
+	"HPQ SVS",	/* 0x110 */
+	" ",		/* 0x111 */
+	" ",		/* 0x112 */
+	" ",		/* 0x113 */
+	" ",		/* 0x114 */
+	"QLA2360",	/* 0x115 */
+	"QLA2362",	/* 0x116 */
+	"QLE2360",	/* 0x117 */
+	"QLE2362",	/* 0x118 */
+	"QLA200",	/* 0x119 */
+	"QLA200C",	/* 0x11a */
+	"QLA200P",	/* 0x11b */
+	"QLA200P",	/* 0x11c */
+	" ",		/* 0x11d */
+	" ",		/* 0x11e */
+	" ",		/* 0x11f */
+	" ",		/* 0x120 */
+	" ",		/* 0x121 */
+	" ",		/* 0x122 */
+	" ",		/* 0x123 */
+	" ",		/* 0x124 */
+	" ",		/* 0x125 */
+	" ",		/* 0x126 */
+	" ",		/* 0x127 */
+	" ",		/* 0x128 */
+	" ",		/* 0x129 */
+	" ",		/* 0x12a */
+	" ",		/* 0x12b */
+	" ",		/* 0x12c */
+	" ",		/* 0x12d */
+	" ",		/* 0x12e */
+	"QLA210",	/* 0x12f */
+	"EMC 250",	/* 0x130 */
+	"HP A7538A"	/* 0x131 */
+};
+
+static char *qla2x00_model_desc[QLA_MODEL_NAMES] = {
+	"133MHz PCI-X to 2Gb FC, Single Channel",	/* 0x100 */
+	"133MHz PCI-X to 2Gb FC, Dual Channel",		/* 0x101 */
+	"133MHz PCI-X to 2Gb FC, Quad Channel",		/* 0x102 */
+	" ",						/* 0x103 */
+	" ",						/* 0x104 */
+	" ",						/* 0x105 */
+	" ",						/* 0x106 */
+	" ",						/* 0x107 */
+	" ",						/* 0x108 */
+	" ",						/* 0x109 */
+	" ",						/* 0x10a */
+	" ",						/* 0x10b */
+	"133MHz PCI-X to 2Gb FC, Single Channel",	/* 0x10c */
+	"133MHz PCI-X to 2Gb FC, Dual Channel",		/* 0x10d */
+	" ",						/* 0x10e */
+	"HPQ SVS HBA- Initiator device",		/* 0x10f */
+	"HPQ SVS HBA- Target device",			/* 0x110 */
+	" ",						/* 0x111 */
+	" ",						/* 0x112 */
+	" ",						/* 0x113 */
+	" ",						/* 0x114 */
+	"133MHz PCI-X to 2Gb FC Single Channel",	/* 0x115 */
+	"133MHz PCI-X to 2Gb FC Dual Channel",		/* 0x116 */
+	"PCI-Express to 2Gb FC, Single Channel",	/* 0x117 */
+	"PCI-Express to 2Gb FC, Dual Channel",		/* 0x118 */
+	"133MHz PCI-X to 2Gb FC Optical",		/* 0x119 */
+	"133MHz PCI-X to 2Gb FC Copper",		/* 0x11a */
+	"133MHz PCI-X to 2Gb FC SFP",			/* 0x11b */
+	"133MHz PCI-X to 2Gb FC SFP",			/* 0x11c */
+	" ",						/* 0x11d */
+	" ",						/* 0x11e */
+	" ",						/* 0x11f */
+	" ",						/* 0x120 */
+	" ",						/* 0x121 */
+	" ",						/* 0x122 */
+	" ",						/* 0x123 */
+	" ",						/* 0x124 */
+	" ",						/* 0x125 */
+	" ",						/* 0x126 */
+	" ",						/* 0x127 */
+	" ",						/* 0x128 */
+	" ",						/* 0x129 */
+	" ",						/* 0x12a */
+	" ",						/* 0x12b */
+	" ",						/* 0x12c */
+	" ",						/* 0x12d */
+	" ",						/* 0x12e */
+	"133MHz PCI-X to 2Gb FC SFF",			/* 0x12f */
+	"133MHz PCI-X to 2Gb FC SFF",			/* 0x130 */
+	"HP 1p2g QLA2340"				/* 0x131 */
+};
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
new file mode 100644
index 0000000..5adf2af
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -0,0 +1,257 @@
+/********************************************************************************
+*                  QLOGIC LINUX SOFTWARE
+*
+* QLogic ISP2x00 device driver for Linux 2.6.x
+* Copyright (C) 2003-2004 QLogic Corporation
+* (www.qlogic.com)
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License as published by the
+* Free Software Foundation; either version 2, or (at your option) any
+* later version.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* General Public License for more details.
+*
+******************************************************************************
+* Global include file.
+******************************************************************************/
+
+
+#ifndef __QLA_GBL_H
+#define	__QLA_GBL_H
+
+#include <linux/interrupt.h>
+
+extern void qla2x00_remove_one(struct pci_dev *);
+extern int qla2x00_probe_one(struct pci_dev *, struct qla_board_info *);
+
+/*
+ * Global Function Prototypes in qla_init.c source file.
+ */
+extern int qla2x00_initialize_adapter(scsi_qla_host_t *);
+extern fc_port_t *qla2x00_alloc_fcport(scsi_qla_host_t *, int);
+
+extern int qla2x00_loop_resync(scsi_qla_host_t *);
+
+extern int qla2x00_find_new_loop_id(scsi_qla_host_t *, fc_port_t *);
+extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *);
+extern int qla2x00_local_device_login(scsi_qla_host_t *, uint16_t);
+
+extern void qla2x00_restart_queues(scsi_qla_host_t *, uint8_t);
+
+extern void qla2x00_rescan_fcports(scsi_qla_host_t *);
+
+extern void qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t t);
+
+extern int qla2x00_abort_isp(scsi_qla_host_t *);
+
+/*
+ * Global Data in qla_os.c source file.
+ */
+extern char qla2x00_version_str[];
+
+extern int num_hosts;
+extern int apiHBAInstance;
+
+extern struct _qla2x00stats qla2x00_stats;
+extern int ql2xretrycount;
+extern int ql2xlogintimeout;
+extern int qlport_down_retry;
+extern int ql2xmaxqdepth;
+extern int displayConfig;
+extern int ql2xplogiabsentdevice;
+extern int ql2xenablezio;
+extern int ql2xintrdelaytimer;
+extern int ql2xloginretrycount;
+
+extern int ConfigRequired;
+
+extern int Bind;
+extern int ql2xsuspendcount;
+#if defined(MODULE)
+extern char *ql2xopts;
+#endif
+
+extern char *qla2x00_get_fw_version_str(struct scsi_qla_host *, char *);
+
+extern void qla2x00_cmd_timeout(srb_t *);
+
+extern int __qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int, int);
+
+extern void qla2x00_done(scsi_qla_host_t *);
+extern void qla2x00_next(scsi_qla_host_t *);
+extern void qla2x00_flush_failover_q(scsi_qla_host_t *, os_lun_t *);
+extern void qla2x00_reset_lun_fo_counts(scsi_qla_host_t *, os_lun_t *);
+
+extern void qla2x00_extend_timeout(struct scsi_cmnd *, int);
+
+extern void qla2x00_mark_device_lost(scsi_qla_host_t *, fc_port_t *, int);
+extern void qla2x00_mark_all_devices_lost(scsi_qla_host_t *);
+
+extern void qla2x00_abort_queues(scsi_qla_host_t *, uint8_t);
+
+extern void qla2x00_blink_led(scsi_qla_host_t *);
+
+extern int qla2x00_down_timeout(struct semaphore *, unsigned long);
+
+/*
+ * Global Function Prototypes in qla_iocb.c source file.
+ */
+extern void qla2x00_isp_cmd(scsi_qla_host_t *);
+
+extern uint16_t qla2x00_calc_iocbs_32(uint16_t);
+extern uint16_t qla2x00_calc_iocbs_64(uint16_t);
+extern void qla2x00_build_scsi_iocbs_32(srb_t *, cmd_entry_t *, uint16_t);
+extern void qla2x00_build_scsi_iocbs_64(srb_t *, cmd_entry_t *, uint16_t);
+extern int qla2x00_start_scsi(srb_t *sp);
+int qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
+int __qla2x00_marker(scsi_qla_host_t *, uint16_t, uint16_t, uint8_t);
+
+/*
+ * Global Function Prototypes in qla_mbx.c source file.
+ */
+extern int
+qla2x00_load_ram(scsi_qla_host_t *, dma_addr_t, uint16_t, uint16_t);
+
+extern int
+qla2x00_load_ram_ext(scsi_qla_host_t *, dma_addr_t, uint32_t, uint16_t);
+
+extern int
+qla2x00_execute_fw(scsi_qla_host_t *);
+
+extern void
+qla2x00_get_fw_version(scsi_qla_host_t *, uint16_t *,
+    uint16_t *, uint16_t *, uint16_t *, uint32_t *);
+
+extern int
+qla2x00_get_fw_options(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla2x00_set_fw_options(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla2x00_mbx_reg_test(scsi_qla_host_t *);
+
+extern int
+qla2x00_verify_checksum(scsi_qla_host_t *);
+
+extern int
+qla2x00_issue_iocb(scsi_qla_host_t *, void *, dma_addr_t, size_t);
+
+extern int
+qla2x00_abort_command(scsi_qla_host_t *, srb_t *);
+
+#if USE_ABORT_TGT
+extern int
+qla2x00_abort_target(fc_port_t *fcport);
+#endif
+
+extern int
+qla2x00_target_reset(scsi_qla_host_t *, uint16_t, uint16_t);
+
+extern int
+qla2x00_get_adapter_id(scsi_qla_host_t *, uint16_t *, uint8_t *, uint8_t *,
+    uint8_t *, uint16_t *);
+
+extern int
+qla2x00_get_retry_cnt(scsi_qla_host_t *, uint8_t *, uint8_t *, uint16_t *);
+
+extern int
+qla2x00_init_firmware(scsi_qla_host_t *, uint16_t);
+
+extern int
+qla2x00_get_port_database(scsi_qla_host_t *, fc_port_t *, uint8_t);
+
+extern int
+qla2x00_get_firmware_state(scsi_qla_host_t *, uint16_t *);
+
+extern int
+qla2x00_get_port_name(scsi_qla_host_t *, uint16_t, uint8_t *, uint8_t);
+
+extern int
+qla2x00_lip_reset(scsi_qla_host_t *);
+
+extern int
+qla2x00_send_sns(scsi_qla_host_t *, dma_addr_t, uint16_t, size_t);
+
+extern int
+qla2x00_login_fabric(scsi_qla_host_t *, uint16_t, uint8_t, uint8_t, uint8_t,
+    uint16_t *, uint8_t);
+
+extern int
+qla2x00_login_local_device(scsi_qla_host_t *, uint16_t, uint16_t *, uint8_t);
+
+extern int
+qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id);
+
+extern int
+qla2x00_full_login_lip(scsi_qla_host_t *ha);
+
+extern int
+qla2x00_get_id_list(scsi_qla_host_t *, void *, dma_addr_t, uint16_t *);
+
+extern int
+qla2x00_get_resource_cnts(scsi_qla_host_t *, uint16_t *, uint16_t *, uint16_t *,
+    uint16_t *);
+
+extern int
+qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map);
+
+/*
+ * Global Function Prototypes in qla_isr.c source file.
+ */
+extern irqreturn_t qla2100_intr_handler(int, void *, struct pt_regs *);
+extern irqreturn_t qla2300_intr_handler(int, void *, struct pt_regs *);
+extern void qla2x00_process_response_queue(struct scsi_qla_host *);
+
+/*
+ * Global Function Prototypes in qla_sup.c source file.
+ */
+extern void qla2x00_lock_nvram_access(scsi_qla_host_t *);
+extern void qla2x00_unlock_nvram_access(scsi_qla_host_t *);
+extern void qla2x00_release_nvram_protection(scsi_qla_host_t *);
+extern uint16_t qla2x00_get_nvram_word(scsi_qla_host_t *, uint32_t);
+extern void qla2x00_write_nvram_word(scsi_qla_host_t *, uint32_t, uint16_t);
+/*
+ * Global Function Prototypes in qla_dbg.c source file.
+ */
+extern void qla2100_fw_dump(scsi_qla_host_t *, int);
+extern void qla2300_fw_dump(scsi_qla_host_t *, int);
+extern void qla2100_ascii_fw_dump(scsi_qla_host_t *);
+extern void qla2300_ascii_fw_dump(scsi_qla_host_t *);
+extern void qla2x00_dump_regs(scsi_qla_host_t *);
+extern void qla2x00_dump_buffer(uint8_t *, uint32_t);
+extern void qla2x00_print_scsi_cmd(struct scsi_cmnd *);
+
+/*
+ * Global Function Prototypes in qla_gs.c source file.
+ */
+extern int qla2x00_ga_nxt(scsi_qla_host_t *, fc_port_t *);
+extern int qla2x00_gid_pt(scsi_qla_host_t *, sw_info_t *);
+extern int qla2x00_gpn_id(scsi_qla_host_t *, sw_info_t *);
+extern int qla2x00_gnn_id(scsi_qla_host_t *, sw_info_t *);
+extern int qla2x00_rft_id(scsi_qla_host_t *);
+extern int qla2x00_rff_id(scsi_qla_host_t *);
+extern int qla2x00_rnn_id(scsi_qla_host_t *);
+extern int qla2x00_rsnn_nn(scsi_qla_host_t *);
+
+/*
+ * Global Function Prototypes in qla_rscn.c source file.
+ */
+extern fc_port_t *qla2x00_alloc_rscn_fcport(scsi_qla_host_t *, int);
+extern int qla2x00_handle_port_rscn(scsi_qla_host_t *, uint32_t, fc_port_t *,
+    int);
+extern void qla2x00_process_iodesc(scsi_qla_host_t *, struct mbx_entry *);
+extern void qla2x00_cancel_io_descriptors(scsi_qla_host_t *);
+
+/*
+ * Global Function Prototypes in qla_xioctl.c source file.
+ */
+#define qla2x00_enqueue_aen(ha, cmd, mode)	do { } while (0)
+#define qla2x00_alloc_ioctl_mem(ha)		(0)
+#define qla2x00_free_ioctl_mem(ha)		do { } while (0)
+
+#endif /* _QLA_GBL_H */
diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c
new file mode 100644
index 0000000..531dad9
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_gs.c
@@ -0,0 +1,1059 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+static inline ms_iocb_entry_t *
+qla2x00_prep_ms_iocb(scsi_qla_host_t *, uint32_t, uint32_t);
+
+static inline struct ct_sns_req *
+qla2x00_prep_ct_req(struct ct_sns_req *, uint16_t, uint16_t);
+
+static inline struct sns_cmd_pkt *
+qla2x00_prep_sns_cmd(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t);
+
+static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *);
+static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *);
+static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *);
+static int qla2x00_sns_gnn_id(scsi_qla_host_t *, sw_info_t *);
+static int qla2x00_sns_rft_id(scsi_qla_host_t *);
+static int qla2x00_sns_rnn_id(scsi_qla_host_t *);
+
+/**
+ * qla2x00_prep_ms_iocb() - Prepare common MS IOCB fields for SNS CT query.
+ * @ha: HA context
+ * @req_size: request size in bytes
+ * @rsp_size: response size in bytes
+ *
+ * Returns a pointer to the @ha's ms_iocb.
+ */
+static inline ms_iocb_entry_t *
+qla2x00_prep_ms_iocb(scsi_qla_host_t *ha, uint32_t req_size, uint32_t rsp_size)
+{
+	ms_iocb_entry_t *ms_pkt;
+
+	ms_pkt = ha->ms_iocb;
+	memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
+
+	ms_pkt->entry_type = MS_IOCB_TYPE;
+	ms_pkt->entry_count = 1;
+	SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER);
+	ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
+	ms_pkt->timeout = __constant_cpu_to_le16(25);
+	ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
+	ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
+	ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
+	ms_pkt->req_bytecount = cpu_to_le32(req_size);
+
+	ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+	ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+
+	ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
+	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
+	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
+
+	return (ms_pkt);
+}
+
+/**
+ * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
+ * @ct_req: CT request buffer
+ * @cmd: GS command
+ * @rsp_size: response size in bytes
+ *
+ * Returns a pointer to the intitialized @ct_req.
+ */
+static inline struct ct_sns_req *
+qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size)
+{
+	memset(ct_req, 0, sizeof(struct ct_sns_pkt));
+
+	ct_req->header.revision = 0x01;
+	ct_req->header.gs_type = 0xFC;
+	ct_req->header.gs_subtype = 0x02;
+	ct_req->command = cpu_to_be16(cmd);
+	ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
+
+	return (ct_req);
+}
+
+
+/**
+ * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
+ * @ha: HA context
+ * @fcport: fcport entry to updated
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+	int		rval;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_ga_nxt(ha, fcport));
+	}
+
+	/* Issue GA_NXT */
+	/* Prepare common MS IOCB */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, GA_NXT_REQ_SIZE, GA_NXT_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
+	    GA_NXT_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- port_id */
+	ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain;
+	ct_req->req.port_id.port_id[1] = fcport->d_id.b.area;
+	ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa;
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): GA_NXT issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, "
+		    "ga_nxt_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		/* Populate fc_port_t entry. */
+		fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0];
+		fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1];
+		fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2];
+
+		memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name,
+		    WWN_SIZE);
+		memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name,
+		    WWN_SIZE);
+
+		if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE &&
+		    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
+			fcport->d_id.b.domain = 0xf0;
+
+		DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
+		    "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "portid=%02x%02x%02x.\n",
+		    ha->host_no,
+		    fcport->node_name[0], fcport->node_name[1],
+		    fcport->node_name[2], fcport->node_name[3],
+		    fcport->node_name[4], fcport->node_name[5],
+		    fcport->node_name[6], fcport->node_name[7],
+		    fcport->port_name[0], fcport->port_name[1],
+		    fcport->port_name[2], fcport->port_name[3],
+		    fcport->port_name[4], fcport->port_name[5],
+		    fcport->port_name[6], fcport->port_name[7],
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * NOTE: Non-Nx_Ports are not requested.
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gid_pt(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+	uint16_t	i;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	struct ct_sns_gid_pt_data *gid_data;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_gid_pt(ha, list));
+	}
+
+	gid_data = NULL;
+
+	/* Issue GID_PT */
+	/* Prepare common MS IOCB */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, GID_PT_REQ_SIZE, GID_PT_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
+	    GID_PT_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- port_type */
+	ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE;
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): GID_PT issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, "
+		    "gid_pt_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		/* Set port IDs in switch info list. */
+		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+			gid_data = &ct_rsp->rsp.gid_pt.entries[i];
+			list[i].d_id.b.domain = gid_data->port_id[0];
+			list[i].d_id.b.area = gid_data->port_id[1];
+			list[i].d_id.b.al_pa = gid_data->port_id[2];
+
+			/* Last one exit. */
+			if (gid_data->control_byte & BIT_7) {
+				list[i].d_id.b.rsvd_1 = gid_data->control_byte;
+				break;
+			}
+		}
+
+		/*
+		 * If we've used all available slots, then the switch is
+		 * reporting back more devices than we can handle with this
+		 * single call.  Return a failed status, and let GA_NXT handle
+		 * the overload.
+		 */
+		if (i == MAX_FIBRE_DEVICES) 
+			rval = QLA_FUNCTION_FAILED;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gpn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+	uint16_t	i;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_gpn_id(ha, list));
+	}
+
+	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		/* Issue GPN_ID */
+		/* Prepare common MS IOCB */
+		ms_pkt = qla2x00_prep_ms_iocb(ha, GPN_ID_REQ_SIZE,
+		    GPN_ID_RSP_SIZE);
+
+		/* Prepare CT request */
+		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD,
+		    GPN_ID_RSP_SIZE);
+		ct_rsp = &ha->ct_sns->p.rsp;
+
+		/* Prepare CT arguments -- port_id */
+		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+		/* Execute MS IOCB */
+		rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+		    sizeof(ms_iocb_entry_t));
+		if (rval != QLA_SUCCESS) {
+			/*EMPTY*/
+			DEBUG2_3(printk("scsi(%ld): GPN_ID issue IOCB failed "
+			    "(%d).\n", ha->host_no, rval));
+		} else if (ct_rsp->header.response !=
+		    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+			DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected "
+			    "request, gpn_id_rsp:\n", ha->host_no));
+			DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+			    sizeof(struct ct_rsp_hdr)));
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			/* Save portname */
+			memcpy(list[i].port_name,
+			    ct_rsp->rsp.gpn_id.port_name, WWN_SIZE);
+		}
+
+		/* Last device exit. */
+		if (list[i].d_id.b.rsvd_1 != 0)
+			break;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_gnn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+	uint16_t	i;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_gnn_id(ha, list));
+	}
+
+	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		/* Issue GNN_ID */
+		/* Prepare common MS IOCB */
+		ms_pkt = qla2x00_prep_ms_iocb(ha, GNN_ID_REQ_SIZE,
+		    GNN_ID_RSP_SIZE);
+
+		/* Prepare CT request */
+		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD,
+		    GNN_ID_RSP_SIZE);
+		ct_rsp = &ha->ct_sns->p.rsp;
+
+		/* Prepare CT arguments -- port_id */
+		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
+		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
+		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
+
+		/* Execute MS IOCB */
+		rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+		    sizeof(ms_iocb_entry_t));
+		if (rval != QLA_SUCCESS) {
+			/*EMPTY*/
+			DEBUG2_3(printk("scsi(%ld): GNN_ID issue IOCB failed "
+			    "(%d).\n", ha->host_no, rval));
+		} else if (ct_rsp->header.response !=
+		    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+			DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected "
+			    "request, gnn_id_rsp:\n", ha->host_no));
+			DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+			    sizeof(struct ct_rsp_hdr)));
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			/* Save nodename */
+			memcpy(list[i].node_name,
+			    ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
+
+			DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
+			    "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+			    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+			    "portid=%02x%02x%02x.\n",
+			    ha->host_no,
+			    list[i].node_name[0], list[i].node_name[1],
+			    list[i].node_name[2], list[i].node_name[3],
+			    list[i].node_name[4], list[i].node_name[5],
+			    list[i].node_name[6], list[i].node_name[7],
+			    list[i].port_name[0], list[i].port_name[1],
+			    list[i].port_name[2], list[i].port_name[3],
+			    list[i].port_name[4], list[i].port_name[5],
+			    list[i].port_name[6], list[i].port_name[7],
+			    list[i].d_id.b.domain, list[i].d_id.b.area,
+			    list[i].d_id.b.al_pa));
+		}
+
+		/* Last device exit. */
+		if (list[i].d_id.b.rsvd_1 != 0)
+			break;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_rft_id(scsi_qla_host_t *ha)
+{
+	int		rval;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_rft_id(ha));
+	}
+
+	/* Issue RFT_ID */
+	/* Prepare common MS IOCB */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, RFT_ID_REQ_SIZE, RFT_ID_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
+	    RFT_ID_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- port_id, FC-4 types */
+	ct_req->req.rft_id.port_id[0] = ha->d_id.b.domain;
+	ct_req->req.rft_id.port_id[1] = ha->d_id.b.area;
+	ct_req->req.rft_id.port_id[2] = ha->d_id.b.al_pa;
+
+	ct_req->req.rft_id.fc4_types[2] = 0x01;		/* FCP-3 */
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RFT_ID issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected "
+		    "request, rft_id_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_rff_id(scsi_qla_host_t *ha)
+{
+	int		rval;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		DEBUG2(printk("scsi(%ld): RFF_ID call unsupported on "
+		    "ISP2100/ISP2200.\n", ha->host_no));
+		return (QLA_SUCCESS);
+	}
+
+	/* Issue RFF_ID */
+	/* Prepare common MS IOCB */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, RFF_ID_REQ_SIZE, RFF_ID_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
+	    RFF_ID_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */
+	ct_req->req.rff_id.port_id[0] = ha->d_id.b.domain;
+	ct_req->req.rff_id.port_id[1] = ha->d_id.b.area;
+	ct_req->req.rff_id.port_id[2] = ha->d_id.b.al_pa;
+
+	ct_req->req.rff_id.fc4_type = 0x08;		/* SCSI - FCP */
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RFF_ID issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): RFF_ID failed, rejected "
+		    "request, rff_id_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RFF_ID exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_rnn_id(scsi_qla_host_t *ha)
+{
+	int		rval;
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		return (qla2x00_sns_rnn_id(ha));
+	}
+
+	/* Issue RNN_ID */
+	/* Prepare common MS IOCB */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, RNN_ID_REQ_SIZE, RNN_ID_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
+	    RNN_ID_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- port_id, node_name */
+	ct_req->req.rnn_id.port_id[0] = ha->d_id.b.domain;
+	ct_req->req.rnn_id.port_id[1] = ha->d_id.b.area;
+	ct_req->req.rnn_id.port_id[2] = ha->d_id.b.al_pa;
+
+	memcpy(ct_req->req.rnn_id.node_name, ha->init_cb->node_name, WWN_SIZE);
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RNN_ID issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected "
+		    "request, rnn_id_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+int
+qla2x00_rsnn_nn(scsi_qla_host_t *ha)
+{
+	int		rval;
+	uint8_t		*snn;
+	uint8_t		version[20];
+
+	ms_iocb_entry_t	*ms_pkt;
+	struct ct_sns_req	*ct_req;
+	struct ct_sns_rsp	*ct_rsp;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		DEBUG2(printk("scsi(%ld): RSNN_ID call unsupported on "
+		    "ISP2100/ISP2200.\n", ha->host_no));
+		return (QLA_SUCCESS);
+	}
+
+	/* Issue RSNN_NN */
+	/* Prepare common MS IOCB */
+	/*   Request size adjusted after CT preparation */
+	ms_pkt = qla2x00_prep_ms_iocb(ha, 0, RSNN_NN_RSP_SIZE);
+
+	/* Prepare CT request */
+	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
+	    RSNN_NN_RSP_SIZE);
+	ct_rsp = &ha->ct_sns->p.rsp;
+
+	/* Prepare CT arguments -- node_name, symbolic node_name, size */
+	memcpy(ct_req->req.rsnn_nn.node_name, ha->init_cb->node_name, WWN_SIZE);
+	
+	/* Prepare the Symbolic Node Name */
+	/* Board type */
+	snn = ct_req->req.rsnn_nn.sym_node_name;
+	strcpy(snn, ha->model_number);
+	/* Firmware version */
+	strcat(snn, " FW:v");
+	sprintf(version, "%d.%02d.%02d", ha->fw_major_version,
+	    ha->fw_minor_version, ha->fw_subminor_version);
+	strcat(snn, version);
+	/* Driver version */
+	strcat(snn, " DVR:v");
+	strcat(snn, qla2x00_version_str);
+
+	/* Calculate SNN length */
+	ct_req->req.rsnn_nn.name_len = (uint8_t)strlen(snn);
+
+	/* Update MS IOCB request */
+	ms_pkt->req_bytecount =
+	    cpu_to_le32(24 + 1 + ct_req->req.rsnn_nn.name_len);
+	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
+
+	/* Execute MS IOCB */
+	rval = qla2x00_issue_iocb(ha, ha->ms_iocb, ha->ms_iocb_dma,
+	    sizeof(ms_iocb_entry_t));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RSNN_NN issue IOCB failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (ct_rsp->header.response !=
+	    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
+		DEBUG2_3(printk("scsi(%ld): RSNN_NN failed, rejected "
+		    "request, rsnn_id_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer((uint8_t *)&ct_rsp->header,
+		    sizeof(struct ct_rsp_hdr)));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RSNN_NN exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+
+/**
+ * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
+ * @ha: HA context
+ * @cmd: GS command
+ * @scmd_len: Subcommand length
+ * @data_size: response size in bytes
+ *
+ * Returns a pointer to the @ha's sns_cmd.
+ */
+static inline struct sns_cmd_pkt *
+qla2x00_prep_sns_cmd(scsi_qla_host_t *ha, uint16_t cmd, uint16_t scmd_len,
+    uint16_t data_size)
+{
+	uint16_t		wc;
+	struct sns_cmd_pkt	*sns_cmd;
+
+	sns_cmd = ha->sns_cmd;
+	memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt));
+	wc = data_size / 2;			/* Size in 16bit words. */
+	sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc);
+	sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma));
+	sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma));
+	sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len);
+	sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd);
+	wc = (data_size - 16) / 4;		/* Size in 32bit words. */
+	sns_cmd->p.cmd.size = cpu_to_le16(wc);
+
+	return (sns_cmd);
+}
+
+/**
+ * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
+ * @ha: HA context
+ * @fcport: fcport entry to updated
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_ga_nxt(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+	int		rval;
+
+	struct sns_cmd_pkt	*sns_cmd;
+
+	/* Issue GA_NXT. */
+	/* Prepare SNS command request. */
+	sns_cmd = qla2x00_prep_sns_cmd(ha, GA_NXT_CMD, GA_NXT_SNS_SCMD_LEN,
+	    GA_NXT_SNS_DATA_SIZE);
+
+	/* Prepare SNS command arguments -- port_id. */
+	sns_cmd->p.cmd.param[0] = fcport->d_id.b.al_pa;
+	sns_cmd->p.cmd.param[1] = fcport->d_id.b.area;
+	sns_cmd->p.cmd.param[2] = fcport->d_id.b.domain;
+
+	/* Execute SNS command. */
+	rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, GA_NXT_SNS_CMD_SIZE / 2,
+	    sizeof(struct sns_cmd_pkt));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): GA_NXT Send SNS failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (sns_cmd->p.gan_data[8] != 0x80 ||
+	    sns_cmd->p.gan_data[9] != 0x02) {
+		DEBUG2_3(printk("scsi(%ld): GA_NXT failed, rejected request, "
+		    "ga_nxt_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gan_data, 16));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		/* Populate fc_port_t entry. */
+		fcport->d_id.b.domain = sns_cmd->p.gan_data[17];
+		fcport->d_id.b.area = sns_cmd->p.gan_data[18];
+		fcport->d_id.b.al_pa = sns_cmd->p.gan_data[19];
+
+		memcpy(fcport->node_name, &sns_cmd->p.gan_data[284], WWN_SIZE);
+		memcpy(fcport->port_name, &sns_cmd->p.gan_data[20], WWN_SIZE);
+
+		if (sns_cmd->p.gan_data[16] != NS_N_PORT_TYPE &&
+		    sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE)
+			fcport->d_id.b.domain = 0xf0;
+
+		DEBUG2_3(printk("scsi(%ld): GA_NXT entry - "
+		    "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+		    "portid=%02x%02x%02x.\n",
+		    ha->host_no,
+		    fcport->node_name[0], fcport->node_name[1],
+		    fcport->node_name[2], fcport->node_name[3],
+		    fcport->node_name[4], fcport->node_name[5],
+		    fcport->node_name[6], fcport->node_name[7],
+		    fcport->port_name[0], fcport->port_name[1],
+		    fcport->port_name[2], fcport->port_name[3],
+		    fcport->port_name[4], fcport->port_name[5],
+		    fcport->port_name[6], fcport->port_name[7],
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * NOTE: Non-Nx_Ports are not requested.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_gid_pt(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+
+	uint16_t	i;
+	uint8_t		*entry;
+	struct sns_cmd_pkt	*sns_cmd;
+
+	/* Issue GID_PT. */
+	/* Prepare SNS command request. */
+	sns_cmd = qla2x00_prep_sns_cmd(ha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN,
+	    GID_PT_SNS_DATA_SIZE);
+
+	/* Prepare SNS command arguments -- port_type. */
+	sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE;
+
+	/* Execute SNS command. */
+	rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, GID_PT_SNS_CMD_SIZE / 2,
+	    sizeof(struct sns_cmd_pkt));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): GID_PT Send SNS failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (sns_cmd->p.gid_data[8] != 0x80 ||
+	    sns_cmd->p.gid_data[9] != 0x02) {
+		DEBUG2_3(printk("scsi(%ld): GID_PT failed, rejected request, "
+		    "gid_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gid_data, 16));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		/* Set port IDs in switch info list. */
+		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+			entry = &sns_cmd->p.gid_data[(i * 4) + 16];
+			list[i].d_id.b.domain = entry[1];
+			list[i].d_id.b.area = entry[2];
+			list[i].d_id.b.al_pa = entry[3];
+
+			/* Last one exit. */
+			if (entry[0] & BIT_7) {
+				list[i].d_id.b.rsvd_1 = entry[0];
+				break;
+			}
+		}
+
+		/*
+		 * If we've used all available slots, then the switch is
+		 * reporting back more devices that we can handle with this
+		 * single call.  Return a failed status, and let GA_NXT handle
+		 * the overload.
+		 */
+		if (i == MAX_FIBRE_DEVICES) 
+			rval = QLA_FUNCTION_FAILED;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_gpn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+
+	uint16_t	i;
+	struct sns_cmd_pkt	*sns_cmd;
+
+	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		/* Issue GPN_ID */
+		/* Prepare SNS command request. */
+		sns_cmd = qla2x00_prep_sns_cmd(ha, GPN_ID_CMD,
+		    GPN_ID_SNS_SCMD_LEN, GPN_ID_SNS_DATA_SIZE);
+
+		/* Prepare SNS command arguments -- port_id. */
+		sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa;
+		sns_cmd->p.cmd.param[1] = list[i].d_id.b.area;
+		sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain;
+
+		/* Execute SNS command. */
+		rval = qla2x00_send_sns(ha, ha->sns_cmd_dma,
+		    GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
+		if (rval != QLA_SUCCESS) {
+			/*EMPTY*/
+			DEBUG2_3(printk("scsi(%ld): GPN_ID Send SNS failed "
+			    "(%d).\n", ha->host_no, rval));
+		} else if (sns_cmd->p.gpn_data[8] != 0x80 ||
+		    sns_cmd->p.gpn_data[9] != 0x02) {
+			DEBUG2_3(printk("scsi(%ld): GPN_ID failed, rejected "
+			    "request, gpn_rsp:\n", ha->host_no));
+			DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gpn_data, 16));
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			/* Save portname */
+			memcpy(list[i].port_name, &sns_cmd->p.gpn_data[16],
+			    WWN_SIZE);
+		}
+
+		/* Last device exit. */
+		if (list[i].d_id.b.rsvd_1 != 0)
+			break;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query.
+ * @ha: HA context
+ * @list: switch info entries to populate
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_gnn_id(scsi_qla_host_t *ha, sw_info_t *list)
+{
+	int		rval;
+
+	uint16_t	i;
+	struct sns_cmd_pkt	*sns_cmd;
+
+	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
+		/* Issue GNN_ID */
+		/* Prepare SNS command request. */
+		sns_cmd = qla2x00_prep_sns_cmd(ha, GNN_ID_CMD,
+		    GNN_ID_SNS_SCMD_LEN, GNN_ID_SNS_DATA_SIZE);
+
+		/* Prepare SNS command arguments -- port_id. */
+		sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa;
+		sns_cmd->p.cmd.param[1] = list[i].d_id.b.area;
+		sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain;
+
+		/* Execute SNS command. */
+		rval = qla2x00_send_sns(ha, ha->sns_cmd_dma,
+		    GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
+		if (rval != QLA_SUCCESS) {
+			/*EMPTY*/
+			DEBUG2_3(printk("scsi(%ld): GNN_ID Send SNS failed "
+			    "(%d).\n", ha->host_no, rval));
+		} else if (sns_cmd->p.gnn_data[8] != 0x80 ||
+		    sns_cmd->p.gnn_data[9] != 0x02) {
+			DEBUG2_3(printk("scsi(%ld): GNN_ID failed, rejected "
+			    "request, gnn_rsp:\n", ha->host_no));
+			DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.gnn_data, 16));
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			/* Save nodename */
+			memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16],
+			    WWN_SIZE);
+
+			DEBUG2_3(printk("scsi(%ld): GID_PT entry - "
+			    "nn %02x%02x%02x%02x%02x%02x%02x%02x "
+			    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
+			    "portid=%02x%02x%02x.\n",
+			    ha->host_no,
+			    list[i].node_name[0], list[i].node_name[1],
+			    list[i].node_name[2], list[i].node_name[3],
+			    list[i].node_name[4], list[i].node_name[5],
+			    list[i].node_name[6], list[i].node_name[7],
+			    list[i].port_name[0], list[i].port_name[1],
+			    list[i].port_name[2], list[i].port_name[3],
+			    list[i].port_name[4], list[i].port_name[5],
+			    list[i].port_name[6], list[i].port_name[7],
+			    list[i].d_id.b.domain, list[i].d_id.b.area,
+			    list[i].d_id.b.al_pa));
+		}
+
+		/* Last device exit. */
+		if (list[i].d_id.b.rsvd_1 != 0)
+			break;
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
+ * @ha: HA context
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_rft_id(scsi_qla_host_t *ha)
+{
+	int		rval;
+
+	struct sns_cmd_pkt	*sns_cmd;
+
+	/* Issue RFT_ID. */
+	/* Prepare SNS command request. */
+	sns_cmd = qla2x00_prep_sns_cmd(ha, RFT_ID_CMD, RFT_ID_SNS_SCMD_LEN,
+	    RFT_ID_SNS_DATA_SIZE);
+
+	/* Prepare SNS command arguments -- port_id, FC-4 types */
+	sns_cmd->p.cmd.param[0] = ha->d_id.b.al_pa;
+	sns_cmd->p.cmd.param[1] = ha->d_id.b.area;
+	sns_cmd->p.cmd.param[2] = ha->d_id.b.domain;
+
+	sns_cmd->p.cmd.param[5] = 0x01;			/* FCP-3 */
+
+	/* Execute SNS command. */
+	rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, RFT_ID_SNS_CMD_SIZE / 2,
+	    sizeof(struct sns_cmd_pkt));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RFT_ID Send SNS failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (sns_cmd->p.rft_data[8] != 0x80 ||
+	    sns_cmd->p.rft_data[9] != 0x02) {
+		DEBUG2_3(printk("scsi(%ld): RFT_ID failed, rejected request, "
+		    "rft_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rft_data, 16));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RFT_ID exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
+ * HBA.
+ * @ha: HA context
+ *
+ * This command uses the old Exectute SNS Command mailbox routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_sns_rnn_id(scsi_qla_host_t *ha)
+{
+	int		rval;
+
+	struct sns_cmd_pkt	*sns_cmd;
+
+	/* Issue RNN_ID. */
+	/* Prepare SNS command request. */
+	sns_cmd = qla2x00_prep_sns_cmd(ha, RNN_ID_CMD, RNN_ID_SNS_SCMD_LEN,
+	    RNN_ID_SNS_DATA_SIZE);
+
+	/* Prepare SNS command arguments -- port_id, nodename. */
+	sns_cmd->p.cmd.param[0] = ha->d_id.b.al_pa;
+	sns_cmd->p.cmd.param[1] = ha->d_id.b.area;
+	sns_cmd->p.cmd.param[2] = ha->d_id.b.domain;
+
+	sns_cmd->p.cmd.param[4] = ha->init_cb->node_name[7];
+	sns_cmd->p.cmd.param[5] = ha->init_cb->node_name[6];
+	sns_cmd->p.cmd.param[6] = ha->init_cb->node_name[5];
+	sns_cmd->p.cmd.param[7] = ha->init_cb->node_name[4];
+	sns_cmd->p.cmd.param[8] = ha->init_cb->node_name[3];
+	sns_cmd->p.cmd.param[9] = ha->init_cb->node_name[2];
+	sns_cmd->p.cmd.param[10] = ha->init_cb->node_name[1];
+	sns_cmd->p.cmd.param[11] = ha->init_cb->node_name[0];
+
+	/* Execute SNS command. */
+	rval = qla2x00_send_sns(ha, ha->sns_cmd_dma, RNN_ID_SNS_CMD_SIZE / 2,
+	    sizeof(struct sns_cmd_pkt));
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3(printk("scsi(%ld): RNN_ID Send SNS failed (%d).\n",
+		    ha->host_no, rval));
+	} else if (sns_cmd->p.rnn_data[8] != 0x80 ||
+	    sns_cmd->p.rnn_data[9] != 0x02) {
+		DEBUG2_3(printk("scsi(%ld): RNN_ID failed, rejected request, "
+		    "rnn_rsp:\n", ha->host_no));
+		DEBUG2_3(qla2x00_dump_buffer(sns_cmd->p.rnn_data, 16));
+		rval = QLA_FUNCTION_FAILED;
+	} else {
+		DEBUG2(printk("scsi(%ld): RNN_ID exiting normally.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c
new file mode 100644
index 0000000..1ab5d92
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_init.c
@@ -0,0 +1,3908 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/delay.h>
+
+#include "qla_devtbl.h"
+
+/* XXX(hch): this is ugly, but we don't want to pull in exioctl.h */
+#ifndef EXT_IS_LUN_BIT_SET
+#define EXT_IS_LUN_BIT_SET(P,L) \
+    (((P)->mask[L/8] & (0x80 >> (L%8)))?1:0)
+#define EXT_SET_LUN_BIT(P,L) \
+    ((P)->mask[L/8] |= (0x80 >> (L%8)))
+#endif
+
+/*
+*  QLogic ISP2x00 Hardware Support Function Prototypes.
+*/
+static int qla2x00_pci_config(scsi_qla_host_t *);
+static int qla2x00_isp_firmware(scsi_qla_host_t *);
+static void qla2x00_reset_chip(scsi_qla_host_t *);
+static int qla2x00_chip_diag(scsi_qla_host_t *);
+static void qla2x00_resize_request_q(scsi_qla_host_t *);
+static int qla2x00_setup_chip(scsi_qla_host_t *);
+static void qla2x00_init_response_q_entries(scsi_qla_host_t *);
+static int qla2x00_init_rings(scsi_qla_host_t *);
+static int qla2x00_fw_ready(scsi_qla_host_t *);
+static int qla2x00_configure_hba(scsi_qla_host_t *);
+static int qla2x00_nvram_config(scsi_qla_host_t *);
+static void qla2x00_init_tgt_map(scsi_qla_host_t *);
+static int qla2x00_configure_loop(scsi_qla_host_t *);
+static int qla2x00_configure_local_loop(scsi_qla_host_t *);
+static void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
+static void qla2x00_lun_discovery(scsi_qla_host_t *, fc_port_t *);
+static int qla2x00_rpt_lun_discovery(scsi_qla_host_t *, fc_port_t *,
+    inq_cmd_rsp_t *, dma_addr_t);
+static int qla2x00_report_lun(scsi_qla_host_t *, fc_port_t *);
+static fc_lun_t *qla2x00_cfg_lun(scsi_qla_host_t *, fc_port_t *, uint16_t,
+    inq_cmd_rsp_t *, dma_addr_t);
+static fc_lun_t * qla2x00_add_lun(fc_port_t *, uint16_t);
+static int qla2x00_inquiry(scsi_qla_host_t *, fc_port_t *, uint16_t,
+    inq_cmd_rsp_t *, dma_addr_t);
+static int qla2x00_configure_fabric(scsi_qla_host_t *);
+static int qla2x00_find_all_fabric_devs(scsi_qla_host_t *, struct list_head *);
+static int qla2x00_device_resync(scsi_qla_host_t *);
+static int qla2x00_fabric_dev_login(scsi_qla_host_t *, fc_port_t *,
+    uint16_t *);
+static void qla2x00_config_os(scsi_qla_host_t *ha);
+static uint16_t qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport);
+static os_lun_t * qla2x00_fclun_bind(scsi_qla_host_t *, fc_port_t *,
+    fc_lun_t *);
+static void qla2x00_lun_free(scsi_qla_host_t *, uint16_t, uint16_t);
+
+static int qla2x00_restart_isp(scsi_qla_host_t *);
+static void qla2x00_reset_adapter(scsi_qla_host_t *);
+static os_tgt_t *qla2x00_tgt_alloc(scsi_qla_host_t *, uint16_t);
+static os_lun_t *qla2x00_lun_alloc(scsi_qla_host_t *, uint16_t, uint16_t);
+
+/****************************************************************************/
+/*                QLogic ISP2x00 Hardware Support Functions.                */
+/****************************************************************************/
+
+/*
+* qla2x00_initialize_adapter
+*      Initialize board.
+*
+* Input:
+*      ha = adapter block pointer.
+*
+* Returns:
+*      0 = success
+*/
+int
+qla2x00_initialize_adapter(scsi_qla_host_t *ha)
+{
+	int	rval;
+	uint8_t	restart_risc = 0;
+	uint8_t	retry;
+	uint32_t wait_time;
+
+	/* Clear adapter flags. */
+	ha->flags.online = 0;
+	ha->flags.reset_active = 0;
+	atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+	atomic_set(&ha->loop_state, LOOP_DOWN);
+	ha->device_flags = 0;
+	ha->sns_retry_cnt = 0;
+	ha->dpc_flags = 0;
+	ha->failback_delay = 0;
+	ha->flags.management_server_logged_in = 0;
+	ha->marker_needed = 0;
+	ha->mbx_flags = 0;
+	ha->isp_abort_cnt = 0;
+	ha->beacon_blink_led = 0;
+
+	rval = qla2x00_pci_config(ha);
+	if (rval) {
+		DEBUG2(printk("scsi(%ld): Unable to configure PCI space=n",
+		    ha->host_no));
+		return (rval);
+	}
+
+	qla2x00_reset_chip(ha);
+
+	/* Initialize target map database. */
+	qla2x00_init_tgt_map(ha);
+
+	qla_printk(KERN_INFO, ha, "Configure NVRAM parameters...\n");
+	qla2x00_nvram_config(ha);
+
+	qla_printk(KERN_INFO, ha, "Verifying loaded RISC code...\n");
+
+	retry = 10;
+	/*
+	 * Try to configure the loop.
+	 */
+	do {
+		restart_risc = 0;
+
+		/* If firmware needs to be loaded */
+		if (qla2x00_isp_firmware(ha) != QLA_SUCCESS) {
+			if ((rval = qla2x00_chip_diag(ha)) == QLA_SUCCESS) {
+				rval = qla2x00_setup_chip(ha);
+			}
+		}
+
+		if (rval == QLA_SUCCESS &&
+		    (rval = qla2x00_init_rings(ha)) == QLA_SUCCESS) {
+check_fw_ready_again:
+			/*
+			 * Wait for a successful LIP up to a maximum 
+			 * of (in seconds): RISC login timeout value,
+			 * RISC retry count value, and port down retry
+			 * value OR a minimum of 4 seconds OR If no 
+			 * cable, only 5 seconds.
+			 */
+			rval = qla2x00_fw_ready(ha);
+			if (rval == QLA_SUCCESS) {
+				clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+
+				/*
+				 * Wait at most MAX_TARGET RSCNs for a stable
+				 * link.
+				 */
+				wait_time = 256;
+				do {
+					clear_bit(LOOP_RESYNC_NEEDED,
+					    &ha->dpc_flags);
+					rval = qla2x00_configure_loop(ha);
+
+					if (test_and_clear_bit(ISP_ABORT_NEEDED,
+					    &ha->dpc_flags)) {
+						restart_risc = 1;
+						break;
+					}
+
+					/*
+					 * If loop state change while we were
+					 * discoverying devices then wait for
+					 * LIP to complete
+					 */
+
+					if (atomic_read(&ha->loop_state) ==
+					    LOOP_DOWN && retry--) {
+						goto check_fw_ready_again;
+					}
+					wait_time--;
+				} while (!atomic_read(&ha->loop_down_timer) &&
+				    retry &&
+				    wait_time &&
+				    (test_bit(LOOP_RESYNC_NEEDED,
+					&ha->dpc_flags)));
+
+				if (wait_time == 0)
+					rval = QLA_FUNCTION_FAILED;
+				if (ha->mem_err)
+					restart_risc = 1;
+			} else if (ha->device_flags & DFLG_NO_CABLE)
+				/* If no cable, then all is good. */
+				rval = QLA_SUCCESS;
+		}
+	} while (restart_risc && retry--);
+
+	if (rval == QLA_SUCCESS) {
+		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+		ha->marker_needed = 1;
+		qla2x00_marker(ha, 0, 0, MK_SYNC_ALL);
+		ha->marker_needed = 0;
+
+		ha->flags.online = 1;
+	} else {
+		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_pci_config() - Setup device PCI configuration registers.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_pci_config(scsi_qla_host_t *ha)
+{
+	uint16_t	w, mwi;
+	unsigned long   flags = 0;
+	uint32_t	cnt;
+
+	qla_printk(KERN_INFO, ha, "Configuring PCI space...\n");
+
+	/* 
+	 * Turn on PCI master; for system BIOSes that don't turn it on by
+	 * default.
+	 */
+	pci_set_master(ha->pdev);
+	mwi = 0;
+	if (pci_set_mwi(ha->pdev))
+		mwi = PCI_COMMAND_INVALIDATE;
+	pci_read_config_word(ha->pdev, PCI_REVISION_ID, &ha->revision);
+
+	if (!ha->iobase)
+		return (QLA_FUNCTION_FAILED);
+
+	/*
+	 * We want to respect framework's setting of PCI configuration space
+	 * command register and also want to make sure that all bits of
+	 * interest to us are properly set in command register.
+	 */
+	pci_read_config_word(ha->pdev, PCI_COMMAND, &w);
+	w |= mwi | (PCI_COMMAND_PARITY | PCI_COMMAND_SERR);
+
+	/* Get PCI bus information. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->pci_attr = RD_REG_WORD(&ha->iobase->ctrl_status);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) {
+		pci_write_config_byte(ha->pdev, PCI_LATENCY_TIMER, 0x80);
+
+		/* PCI Specification Revision 2.3 changes */
+		if (IS_QLA2322(ha) || IS_QLA6322(ha))
+			/* Command Register - Reset Interrupt Disable. */
+			w &= ~PCI_COMMAND_INTX_DISABLE;
+
+		/*
+		 * If this is a 2300 card and not 2312, reset the
+		 * COMMAND_INVALIDATE due to a bug in the 2300. Unfortunately,
+		 * the 2310 also reports itself as a 2300 so we need to get the
+		 * fb revision level -- a 6 indicates it really is a 2300 and
+		 * not a 2310.
+		 */
+		if (IS_QLA2300(ha)) {
+			spin_lock_irqsave(&ha->hardware_lock, flags);
+
+			/* Pause RISC. */
+			WRT_REG_WORD(&ha->iobase->hccr, HCCR_PAUSE_RISC);
+			for (cnt = 0; cnt < 30000; cnt++) {
+				if ((RD_REG_WORD(&ha->iobase->hccr) &
+				    HCCR_RISC_PAUSE) != 0)
+					break;
+	
+				udelay(10);
+			}
+
+			/* Select FPM registers. */
+			WRT_REG_WORD(&ha->iobase->ctrl_status, 0x20);
+			RD_REG_WORD(&ha->iobase->ctrl_status);
+
+			/* Get the fb rev level */
+			ha->fb_rev = RD_FB_CMD_REG(ha, ha->iobase);
+
+			if (ha->fb_rev == FPM_2300)
+				w &= ~PCI_COMMAND_INVALIDATE;
+
+			/* Deselect FPM registers. */
+			WRT_REG_WORD(&ha->iobase->ctrl_status, 0x0);
+			RD_REG_WORD(&ha->iobase->ctrl_status);
+
+			/* Release RISC module. */
+			WRT_REG_WORD(&ha->iobase->hccr, HCCR_RELEASE_RISC);
+			for (cnt = 0; cnt < 30000; cnt++) {
+				if ((RD_REG_WORD(&ha->iobase->hccr) &
+				    HCCR_RISC_PAUSE) == 0)
+					break;
+	
+				udelay(10);
+			}
+
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		}
+	}
+
+	pci_write_config_word(ha->pdev, PCI_COMMAND, w);
+
+	/* Reset expansion ROM address decode enable */
+	pci_read_config_word(ha->pdev, PCI_ROM_ADDRESS, &w);
+	w &= ~PCI_ROM_ADDRESS_ENABLE;
+	pci_write_config_word(ha->pdev, PCI_ROM_ADDRESS, w);
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_isp_firmware() - Choose firmware image.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_isp_firmware(scsi_qla_host_t *ha)
+{
+	int  rval;
+
+	/* Assume loading risc code */
+	rval = QLA_FUNCTION_FAILED; 
+
+	if (ha->flags.disable_risc_code_load) {
+		DEBUG2(printk("scsi(%ld): RISC CODE NOT loaded\n",
+		    ha->host_no));
+		qla_printk(KERN_INFO, ha, "RISC CODE NOT loaded\n");
+
+		/* Verify checksum of loaded RISC code. */
+		rval = qla2x00_verify_checksum(ha);
+	}
+
+	if (rval) {
+		DEBUG2_3(printk("scsi(%ld): **** Load RISC code ****\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_reset_chip() - Reset ISP chip.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static void
+qla2x00_reset_chip(scsi_qla_host_t *ha) 
+{
+	unsigned long   flags = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+	uint32_t	cnt;
+	unsigned long	mbx_flags = 0;
+	uint16_t	cmd;
+
+	/* Disable ISP interrupts. */
+	qla2x00_disable_intrs(ha);
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Turn off master enable */
+	cmd = 0;
+	pci_read_config_word(ha->pdev, PCI_COMMAND, &cmd);
+	cmd &= ~PCI_COMMAND_MASTER;
+	pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
+
+	if (!IS_QLA2100(ha)) {
+		/* Pause RISC. */
+		WRT_REG_WORD(&reg->hccr, HCCR_PAUSE_RISC);
+		if (IS_QLA2200(ha) || IS_QLA2300(ha)) {
+			for (cnt = 0; cnt < 30000; cnt++) {
+				if ((RD_REG_WORD(&reg->hccr) &
+				    HCCR_RISC_PAUSE) != 0)
+					break;
+				udelay(100);
+			}
+		} else {
+			RD_REG_WORD(&reg->hccr);	/* PCI Posting. */
+			udelay(10);
+		}
+
+		/* Select FPM registers. */
+		WRT_REG_WORD(&reg->ctrl_status, 0x20);
+		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */
+
+		/* FPM Soft Reset. */
+		WRT_REG_WORD(&reg->fpm_diag_config, 0x100);
+		RD_REG_WORD(&reg->fpm_diag_config);	/* PCI Posting. */
+
+		/* Toggle Fpm Reset. */
+		if (!IS_QLA2200(ha)) {
+			WRT_REG_WORD(&reg->fpm_diag_config, 0x0);
+			RD_REG_WORD(&reg->fpm_diag_config); /* PCI Posting. */
+		}
+
+		/* Select frame buffer registers. */
+		WRT_REG_WORD(&reg->ctrl_status, 0x10);
+		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */
+
+		/* Reset frame buffer FIFOs. */
+		if (IS_QLA2200(ha)) {
+			WRT_FB_CMD_REG(ha, reg, 0xa000);
+			RD_FB_CMD_REG(ha, reg);		/* PCI Posting. */
+		} else {
+			WRT_FB_CMD_REG(ha, reg, 0x00fc);
+
+			/* Read back fb_cmd until zero or 3 seconds max */
+			for (cnt = 0; cnt < 3000; cnt++) {
+				if ((RD_FB_CMD_REG(ha, reg) & 0xff) == 0)
+					break;
+				udelay(100);
+			}
+		}
+
+		/* Select RISC module registers. */
+		WRT_REG_WORD(&reg->ctrl_status, 0);
+		RD_REG_WORD(&reg->ctrl_status);		/* PCI Posting. */
+
+		/* Reset RISC processor. */
+		WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
+
+		/* Release RISC processor. */
+		WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
+		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
+	}
+
+	WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+	WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
+
+	/* Reset ISP chip. */
+	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
+
+	/* Wait for RISC to recover from reset. */
+	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
+		/*
+		 * It is necessary to for a delay here since the card doesn't
+		 * respond to PCI reads during a reset. On some architectures
+		 * this will result in an MCA.
+		 */
+		udelay(20);
+		for (cnt = 30000; cnt; cnt--) {
+			if ((RD_REG_WORD(&reg->ctrl_status) &
+			    CSR_ISP_SOFT_RESET) == 0)
+				break;
+			udelay(100);
+		}
+	} else
+		udelay(10);
+
+	/* Reset RISC processor. */
+	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+
+	WRT_REG_WORD(&reg->semaphore, 0);
+
+	/* Release RISC processor. */
+	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
+	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
+		for (cnt = 0; cnt < 30000; cnt++) {
+			if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)))
+				spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
+
+			if (RD_MAILBOX_REG(ha, reg, 0) != MBS_BUSY) {
+				if (!(test_bit(ABORT_ISP_ACTIVE,
+				    &ha->dpc_flags)))
+					spin_unlock_irqrestore(
+					    &ha->mbx_reg_lock, mbx_flags);
+				break;
+			}
+
+			if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)))
+				spin_unlock_irqrestore(&ha->mbx_reg_lock,
+				    mbx_flags);
+
+			udelay(100);
+		}
+	} else
+		udelay(100);
+
+	/* Turn on master enable */
+	cmd |= PCI_COMMAND_MASTER;
+	pci_write_config_word(ha->pdev, PCI_COMMAND, cmd);
+
+	/* Disable RISC pause on FPM parity error. */
+	if (!IS_QLA2100(ha)) {
+		WRT_REG_WORD(&reg->hccr, HCCR_DISABLE_PARITY_PAUSE);
+		RD_REG_WORD(&reg->hccr);		/* PCI Posting. */
+	}
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/**
+ * qla2x00_chip_diag() - Test chip for proper operation.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_chip_diag(scsi_qla_host_t *ha)
+{
+	int		rval;
+	device_reg_t __iomem *reg = ha->iobase;
+	unsigned long	flags = 0;
+	uint16_t	data;
+	uint32_t	cnt;
+	uint16_t	mb[5];
+
+	/* Assume a failed state */
+	rval = QLA_FUNCTION_FAILED;
+
+	DEBUG3(printk("scsi(%ld): Testing device at %lx.\n",
+	    ha->host_no, (u_long)&reg->flash_address));
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Reset ISP chip. */
+	WRT_REG_WORD(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
+
+	/*
+	 * We need to have a delay here since the card will not respond while
+	 * in reset causing an MCA on some architectures.
+	 */
+	udelay(20);
+	data = qla2x00_debounce_register(&reg->ctrl_status);
+	for (cnt = 6000000 ; cnt && (data & CSR_ISP_SOFT_RESET); cnt--) {
+		udelay(5);
+		data = RD_REG_WORD(&reg->ctrl_status);
+		barrier();
+	}
+
+	if (!cnt)
+		goto chip_diag_failed;
+
+	DEBUG3(printk("scsi(%ld): Reset register cleared by chip reset\n",
+	    ha->host_no));
+
+	/* Reset RISC processor. */
+	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
+
+	/* Workaround for QLA2312 PCI parity error */
+	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
+		data = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 0));
+		for (cnt = 6000000; cnt && (data == MBS_BUSY); cnt--) {
+			udelay(5);
+			data = RD_MAILBOX_REG(ha, reg, 0);
+			barrier(); 
+		}
+	} else
+		udelay(10);
+
+	if (!cnt)
+		goto chip_diag_failed;
+
+	/* Check product ID of chip */
+	DEBUG3(printk("scsi(%ld): Checking product ID of chip\n", ha->host_no));
+
+	mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+	mb[2] = RD_MAILBOX_REG(ha, reg, 2);
+	mb[3] = RD_MAILBOX_REG(ha, reg, 3);
+	mb[4] = qla2x00_debounce_register(MAILBOX_REG(ha, reg, 4));
+	if (mb[1] != PROD_ID_1 || (mb[2] != PROD_ID_2 && mb[2] != PROD_ID_2a) ||
+	    mb[3] != PROD_ID_3) {
+		qla_printk(KERN_WARNING, ha,
+		    "Wrong product ID = 0x%x,0x%x,0x%x\n", mb[1], mb[2], mb[3]);
+
+		goto chip_diag_failed;
+	}
+	ha->product_id[0] = mb[1];
+	ha->product_id[1] = mb[2];
+	ha->product_id[2] = mb[3];
+	ha->product_id[3] = mb[4];
+
+	/* Adjust fw RISC transfer size */
+	if (ha->request_q_length > 1024)
+		ha->fw_transfer_size = REQUEST_ENTRY_SIZE * 1024;
+	else
+		ha->fw_transfer_size = REQUEST_ENTRY_SIZE *
+		    ha->request_q_length;
+
+	if (IS_QLA2200(ha) &&
+	    RD_MAILBOX_REG(ha, reg, 7) == QLA2200A_RISC_ROM_VER) {
+		/* Limit firmware transfer size with a 2200A */
+		DEBUG3(printk("scsi(%ld): Found QLA2200A chip.\n",
+		    ha->host_no));
+
+		ha->fw_transfer_size = 128;
+	}
+
+	/* Wrap Incoming Mailboxes Test. */
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	DEBUG3(printk("scsi(%ld): Checking mailboxes.\n", ha->host_no));
+	rval = qla2x00_mbx_reg_test(ha);
+	if (rval) {
+		DEBUG(printk("scsi(%ld): Failed mailbox send register test\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha,
+		    "Failed mailbox send register test\n");
+	}
+	else {
+		/* Flag a successful rval */
+		rval = QLA_SUCCESS;
+	}
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+chip_diag_failed:
+	if (rval)
+		DEBUG2_3(printk("scsi(%ld): Chip diagnostics **** FAILED "
+		    "****\n", ha->host_no));
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (rval);
+}
+
+/**
+ * qla2x00_resize_request_q() - Resize request queue given available ISP memory.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static void
+qla2x00_resize_request_q(scsi_qla_host_t *ha)
+{
+	int rval;
+	uint16_t fw_iocb_cnt = 0;
+	uint16_t request_q_length = REQUEST_ENTRY_CNT_2XXX_EXT_MEM;
+	dma_addr_t request_dma;
+	request_t *request_ring;
+
+	/* Valid only on recent ISPs. */
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		return;
+
+	/* Retrieve IOCB counts available to the firmware. */
+	rval = qla2x00_get_resource_cnts(ha, NULL, NULL, NULL, &fw_iocb_cnt);
+	if (rval)
+		return;
+	/* No point in continuing if current settings are sufficient. */
+	if (fw_iocb_cnt < 1024)
+		return;
+	if (ha->request_q_length >= request_q_length)
+		return;
+
+	/* Attempt to claim larger area for request queue. */
+	request_ring = dma_alloc_coherent(&ha->pdev->dev,
+	    (request_q_length + 1) * sizeof(request_t), &request_dma,
+	    GFP_KERNEL);
+	if (request_ring == NULL)
+		return;
+
+	/* Resize successful, report extensions. */
+	qla_printk(KERN_INFO, ha, "Extended memory detected (%d KB)...\n",
+	    (ha->fw_memory_size + 1) / 1024);
+	qla_printk(KERN_INFO, ha, "Resizing request queue depth "
+	    "(%d -> %d)...\n", ha->request_q_length, request_q_length);
+
+	/* Clear old allocations. */
+	dma_free_coherent(&ha->pdev->dev,
+	    (ha->request_q_length + 1) * sizeof(request_t), ha->request_ring,
+	    ha->request_dma);
+
+	/* Begin using larger queue. */
+	ha->request_q_length = request_q_length;
+	ha->request_ring = request_ring;
+	ha->request_dma = request_dma;
+}
+
+/**
+ * qla2x00_setup_chip() - Load and start RISC firmware.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_setup_chip(scsi_qla_host_t *ha)
+{
+	int		rval;
+	uint16_t	cnt;
+	uint16_t	*risc_code;
+	unsigned long	risc_address;
+	unsigned long	risc_code_size;
+	int		num;
+	int		i;
+	uint16_t	*req_ring;
+	struct qla_fw_info *fw_iter;
+
+	rval = QLA_SUCCESS;
+
+	/* Load firmware sequences */
+	fw_iter = ha->brd_info->fw_info;
+	while (fw_iter->addressing != FW_INFO_ADDR_NOMORE) {
+		risc_code = fw_iter->fwcode;
+		risc_code_size = *fw_iter->fwlen;
+
+		if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) {
+			risc_address = *fw_iter->fwstart;
+		} else {
+			/* Extended address */
+			risc_address = *fw_iter->lfwstart;
+		}
+
+		num = 0;
+		rval = 0;
+		while (risc_code_size > 0 && !rval) {
+			cnt = (uint16_t)(ha->fw_transfer_size >> 1);
+			if (cnt > risc_code_size)
+				cnt = risc_code_size;
+
+			DEBUG7(printk("scsi(%ld): Loading risc segment@ "
+			    "addr %p, number of bytes 0x%x, offset 0x%lx.\n",
+			    ha->host_no, risc_code, cnt, risc_address));
+
+			req_ring = (uint16_t *)ha->request_ring;
+			for (i = 0; i < cnt; i++)
+				req_ring[i] = cpu_to_le16(risc_code[i]);
+
+			if (fw_iter->addressing == FW_INFO_ADDR_NORMAL) {
+				rval = qla2x00_load_ram(ha,
+				    ha->request_dma, risc_address, cnt);
+			} else {
+				rval = qla2x00_load_ram_ext(ha,
+				    ha->request_dma, risc_address, cnt);
+			}
+			if (rval) {
+				DEBUG(printk("scsi(%ld): [ERROR] Failed to "
+				    "load segment %d of firmware\n",
+				    ha->host_no, num));
+				qla_printk(KERN_WARNING, ha,
+				    "[ERROR] Failed to load "
+				    "segment %d of firmware\n", num);
+
+				qla2x00_dump_regs(ha);
+				break;
+			}
+
+			risc_code += cnt;
+			risc_address += cnt;
+			risc_code_size -= cnt;
+			num++;
+		}
+
+		/* Next firmware sequence */
+		fw_iter++;
+	}
+
+	/* Verify checksum of loaded RISC code. */
+	if (!rval) {
+		DEBUG(printk("scsi(%ld): Verifying Checksum of loaded RISC "
+		    "code.\n", ha->host_no));
+
+		rval = qla2x00_verify_checksum(ha);
+		if (rval == QLA_SUCCESS) {
+			/* Start firmware execution. */
+			DEBUG(printk("scsi(%ld): Checksum OK, start "
+			    "firmware.\n", ha->host_no));
+
+			rval = qla2x00_execute_fw(ha);
+			/* Retrieve firmware information. */
+			if (rval == QLA_SUCCESS && ha->fw_major_version == 0) {
+				qla2x00_get_fw_version(ha,
+				    &ha->fw_major_version,
+				    &ha->fw_minor_version,
+				    &ha->fw_subminor_version,
+				    &ha->fw_attributes, &ha->fw_memory_size);
+				qla2x00_resize_request_q(ha);
+			}
+		} else {
+			DEBUG2(printk(KERN_INFO
+			    "scsi(%ld): ISP Firmware failed checksum.\n",
+			    ha->host_no));
+		}
+	}
+
+	if (rval) {
+		DEBUG2_3(printk("scsi(%ld): Setup chip **** FAILED ****.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_init_response_q_entries() - Initializes response queue entries.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ *
+ * Returns 0 on success.
+ */
+static void
+qla2x00_init_response_q_entries(scsi_qla_host_t *ha)
+{
+	uint16_t cnt;
+	response_t *pkt;
+
+	pkt = ha->response_ring_ptr;
+	for (cnt = 0; cnt < ha->response_q_length; cnt++) {
+		pkt->signature = RESPONSE_PROCESSED;
+		pkt++;
+	}
+
+}
+
+/**
+ * qla2x00_update_fw_options() - Read and process firmware options.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static void
+qla2x00_update_fw_options(scsi_qla_host_t *ha)
+{
+	uint16_t swing, emphasis, tx_sens, rx_sens;
+
+	memset(ha->fw_options, 0, sizeof(ha->fw_options));
+	qla2x00_get_fw_options(ha, ha->fw_options);
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		return;
+
+	/* Serial Link options. */
+	DEBUG3(printk("scsi(%ld): Serial link options:\n",
+	    ha->host_no));
+	DEBUG3(qla2x00_dump_buffer((uint8_t *)&ha->fw_seriallink_options,
+	    sizeof(ha->fw_seriallink_options)));
+
+	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
+	if (ha->fw_seriallink_options[3] & BIT_2) {
+		ha->fw_options[1] |= FO1_SET_EMPHASIS_SWING;
+
+		/*  1G settings */
+		swing = ha->fw_seriallink_options[2] & (BIT_2 | BIT_1 | BIT_0);
+		emphasis = (ha->fw_seriallink_options[2] &
+		    (BIT_4 | BIT_3)) >> 3;
+		tx_sens = ha->fw_seriallink_options[0] &
+		    (BIT_3 | BIT_2 | BIT_1 | BIT_0); 
+		rx_sens = (ha->fw_seriallink_options[0] &
+		    (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
+		ha->fw_options[10] = (emphasis << 14) | (swing << 8);
+		if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
+			if (rx_sens == 0x0)
+				rx_sens = 0x3;
+			ha->fw_options[10] |= (tx_sens << 4) | rx_sens;
+		} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
+			ha->fw_options[10] |= BIT_5 |
+			    ((rx_sens & (BIT_1 | BIT_0)) << 2) |
+			    (tx_sens & (BIT_1 | BIT_0));
+
+		/*  2G settings */
+		swing = (ha->fw_seriallink_options[2] &
+		    (BIT_7 | BIT_6 | BIT_5)) >> 5;
+		emphasis = ha->fw_seriallink_options[3] & (BIT_1 | BIT_0);
+		tx_sens = ha->fw_seriallink_options[1] &
+		    (BIT_3 | BIT_2 | BIT_1 | BIT_0); 
+		rx_sens = (ha->fw_seriallink_options[1] &
+		    (BIT_7 | BIT_6 | BIT_5 | BIT_4)) >> 4;
+		ha->fw_options[11] = (emphasis << 14) | (swing << 8);
+		if (IS_QLA2300(ha) || IS_QLA2312(ha) || IS_QLA6312(ha)) {
+			if (rx_sens == 0x0)
+				rx_sens = 0x3;
+			ha->fw_options[11] |= (tx_sens << 4) | rx_sens;
+		} else if (IS_QLA2322(ha) || IS_QLA6322(ha))
+			ha->fw_options[11] |= BIT_5 |
+			    ((rx_sens & (BIT_1 | BIT_0)) << 2) |
+			    (tx_sens & (BIT_1 | BIT_0));
+	}
+
+	/* FCP2 options. */
+	/*  Return command IOCBs without waiting for an ABTS to complete. */
+	ha->fw_options[3] |= BIT_13;
+
+	/* LED scheme. */
+	if (ha->flags.enable_led_scheme)
+		ha->fw_options[2] |= BIT_12;
+
+	/* Update firmware options. */
+	qla2x00_set_fw_options(ha, ha->fw_options);
+}
+
+/**
+ * qla2x00_init_rings() - Initializes firmware.
+ * @ha: HA context
+ *
+ * Beginning of request ring has initialization control block already built
+ * by nvram config routine.
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_init_rings(scsi_qla_host_t *ha)
+{
+	int	rval;
+	unsigned long flags = 0;
+	int cnt;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Clear outstanding commands array. */
+	for (cnt = 0; cnt < MAX_OUTSTANDING_COMMANDS; cnt++)
+		ha->outstanding_cmds[cnt] = NULL;
+
+	ha->current_outstanding_cmd = 0;
+
+	/* Clear RSCN queue. */
+	ha->rscn_in_ptr = 0;
+	ha->rscn_out_ptr = 0;
+
+	/* Initialize firmware. */
+	ha->request_ring_ptr  = ha->request_ring;
+	ha->req_ring_index    = 0;
+	ha->req_q_cnt         = ha->request_q_length;
+	ha->response_ring_ptr = ha->response_ring;
+	ha->rsp_ring_index    = 0;
+
+	/* Setup ring parameters in initialization control block. */
+	ha->init_cb->request_q_outpointer = __constant_cpu_to_le16(0);
+	ha->init_cb->response_q_inpointer = __constant_cpu_to_le16(0);
+	ha->init_cb->request_q_length = cpu_to_le16(ha->request_q_length);
+	ha->init_cb->response_q_length = cpu_to_le16(ha->response_q_length);
+	ha->init_cb->request_q_address[0] = cpu_to_le32(LSD(ha->request_dma));
+	ha->init_cb->request_q_address[1] = cpu_to_le32(MSD(ha->request_dma));
+	ha->init_cb->response_q_address[0] = cpu_to_le32(LSD(ha->response_dma));
+	ha->init_cb->response_q_address[1] = cpu_to_le32(MSD(ha->response_dma));
+
+	/* Initialize response queue entries */
+	qla2x00_init_response_q_entries(ha);
+
+ 	WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), 0);
+ 	WRT_REG_WORD(ISP_REQ_Q_OUT(ha, reg), 0);
+ 	WRT_REG_WORD(ISP_RSP_Q_IN(ha, reg), 0);
+ 	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), 0);
+	RD_REG_WORD(ISP_RSP_Q_OUT(ha, reg));		/* PCI Posting. */
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	/* Update any ISP specific firmware options before initialization. */
+	qla2x00_update_fw_options(ha);
+
+	DEBUG(printk("scsi(%ld): Issue init firmware.\n", ha->host_no));
+	rval = qla2x00_init_firmware(ha, sizeof(init_cb_t));
+	if (rval) {
+		DEBUG2_3(printk("scsi(%ld): Init firmware **** FAILED ****.\n",
+		    ha->host_no));
+	} else {
+		DEBUG3(printk("scsi(%ld): Init firmware -- success.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/**
+ * qla2x00_fw_ready() - Waits for firmware ready.
+ * @ha: HA context
+ *
+ * Returns 0 on success.
+ */
+static int
+qla2x00_fw_ready(scsi_qla_host_t *ha)
+{
+	int		rval;
+	unsigned long	wtime, mtime;
+	uint16_t	min_wait;	/* Minimum wait time if loop is down */
+	uint16_t	wait_time;	/* Wait time if loop is coming ready */
+	uint16_t	fw_state;
+
+	rval = QLA_SUCCESS;
+
+	/* 20 seconds for loop down. */
+	min_wait = 20;		
+
+	/*
+	 * Firmware should take at most one RATOV to login, plus 5 seconds for
+	 * our own processing.
+	 */
+	if ((wait_time = (ha->retry_count*ha->login_timeout) + 5) < min_wait) {
+		wait_time = min_wait;
+	}
+
+	/* Min wait time if loop down */
+	mtime = jiffies + (min_wait * HZ);
+
+	/* wait time before firmware ready */
+	wtime = jiffies + (wait_time * HZ);
+
+	/* Wait for ISP to finish LIP */
+	if (!ha->flags.init_done)
+ 		qla_printk(KERN_INFO, ha, "Waiting for LIP to complete...\n");
+
+	DEBUG3(printk("scsi(%ld): Waiting for LIP to complete...\n",
+	    ha->host_no));
+
+	do {
+		rval = qla2x00_get_firmware_state(ha, &fw_state);
+		if (rval == QLA_SUCCESS) {
+			if (fw_state < FSTATE_LOSS_OF_SYNC) {
+				ha->device_flags &= ~DFLG_NO_CABLE;
+			}
+			if (fw_state == FSTATE_READY) {
+				DEBUG(printk("scsi(%ld): F/W Ready - OK \n",
+				    ha->host_no));
+
+				qla2x00_get_retry_cnt(ha, &ha->retry_count,
+				    &ha->login_timeout, &ha->r_a_tov);
+
+				rval = QLA_SUCCESS;
+				break;
+			}
+
+			rval = QLA_FUNCTION_FAILED;
+
+			if (atomic_read(&ha->loop_down_timer) &&
+			    (fw_state >= FSTATE_LOSS_OF_SYNC ||
+				fw_state == FSTATE_WAIT_AL_PA)) {
+				/* Loop down. Timeout on min_wait for states
+				 * other than Wait for Login. 
+				 */	
+				if (time_after_eq(jiffies, mtime)) {
+					qla_printk(KERN_INFO, ha,
+					    "Cable is unplugged...\n");
+
+					ha->device_flags |= DFLG_NO_CABLE;
+					break;
+				}
+			}
+		} else {
+			/* Mailbox cmd failed. Timeout on min_wait. */
+			if (time_after_eq(jiffies, mtime))
+				break;
+		}
+
+		if (time_after_eq(jiffies, wtime))
+			break;
+
+		/* Delay for a while */
+		msleep(500);
+
+		DEBUG3(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
+		    ha->host_no, fw_state, jiffies));
+	} while (1);
+
+	DEBUG(printk("scsi(%ld): fw_state=%x curr time=%lx.\n",
+	    ha->host_no, fw_state, jiffies));
+
+	if (rval) {
+		DEBUG2_3(printk("scsi(%ld): Firmware ready **** FAILED ****.\n",
+		    ha->host_no));
+	}
+
+	return (rval);
+}
+
+/*
+*  qla2x00_configure_hba
+*      Setup adapter context.
+*
+* Input:
+*      ha = adapter state pointer.
+*
+* Returns:
+*      0 = success
+*
+* Context:
+*      Kernel context.
+*/
+static int
+qla2x00_configure_hba(scsi_qla_host_t *ha)
+{
+	int       rval;
+	uint16_t      loop_id;
+	uint16_t      topo;
+	uint8_t       al_pa;
+	uint8_t       area;
+	uint8_t       domain;
+	char		connect_type[22];
+
+	/* Get host addresses. */
+	rval = qla2x00_get_adapter_id(ha,
+	    &loop_id, &al_pa, &area, &domain, &topo);
+	if (rval != QLA_SUCCESS) {
+		qla_printk(KERN_WARNING, ha,
+		    "ERROR -- Unable to get host loop ID.\n");
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		return (rval);
+	}
+
+	if (topo == 4) {
+		qla_printk(KERN_INFO, ha,
+			"Cannot get topology - retrying.\n");
+		return (QLA_FUNCTION_FAILED);
+	}
+
+	ha->loop_id = loop_id;
+
+	/* initialize */
+	ha->min_external_loopid = SNS_FIRST_LOOP_ID;
+	ha->operating_mode = LOOP;
+
+	switch (topo) {
+	case 0:
+		DEBUG3(printk("scsi(%ld): HBA in NL topology.\n",
+		    ha->host_no));
+		ha->current_topology = ISP_CFG_NL;
+		strcpy(connect_type, "(Loop)");
+		break;
+
+	case 1:
+		DEBUG3(printk("scsi(%ld): HBA in FL topology.\n",
+		    ha->host_no));
+		ha->current_topology = ISP_CFG_FL;
+		strcpy(connect_type, "(FL_Port)");
+		break;
+
+	case 2:
+		DEBUG3(printk("scsi(%ld): HBA in N P2P topology.\n",
+		    ha->host_no));
+		ha->operating_mode = P2P;
+		ha->current_topology = ISP_CFG_N;
+		strcpy(connect_type, "(N_Port-to-N_Port)");
+		break;
+
+	case 3:
+		DEBUG3(printk("scsi(%ld): HBA in F P2P topology.\n",
+		    ha->host_no));
+		ha->operating_mode = P2P;
+		ha->current_topology = ISP_CFG_F;
+		strcpy(connect_type, "(F_Port)");
+		break;
+
+	default:
+		DEBUG3(printk("scsi(%ld): HBA in unknown topology %x. "
+		    "Using NL.\n",
+		    ha->host_no, topo));
+		ha->current_topology = ISP_CFG_NL;
+		strcpy(connect_type, "(Loop)");
+		break;
+	}
+
+	/* Save Host port and loop ID. */
+	/* byte order - Big Endian */
+	ha->d_id.b.domain = domain;
+	ha->d_id.b.area = area;
+	ha->d_id.b.al_pa = al_pa;
+
+	if (!ha->flags.init_done)
+ 		qla_printk(KERN_INFO, ha,
+		    "Topology - %s, Host Loop address 0x%x\n",
+ 		    connect_type, ha->loop_id);
+
+	if (rval) {
+		DEBUG2_3(printk("scsi(%ld): FAILED.\n", ha->host_no));
+	} else {
+		DEBUG3(printk("scsi(%ld): exiting normally.\n", ha->host_no));
+	}
+
+	return(rval);
+}
+
+/*
+* NVRAM configuration for ISP 2xxx
+*
+* Input:
+*      ha                = adapter block pointer.
+*
+* Output:
+*      initialization control block in response_ring
+*      host adapters parameters in host adapter block
+*
+* Returns:
+*      0 = success.
+*/
+static int
+qla2x00_nvram_config(scsi_qla_host_t *ha)
+{
+	int   rval;
+	uint8_t   chksum = 0;
+	uint16_t  cnt;
+	uint8_t   *dptr1, *dptr2;
+	init_cb_t *icb   = ha->init_cb;
+	nvram_t *nv    = (nvram_t *)ha->request_ring;
+	uint16_t  *wptr  = (uint16_t *)ha->request_ring;
+	device_reg_t __iomem *reg = ha->iobase;
+	uint8_t  timer_mode;
+
+	rval = QLA_SUCCESS;
+
+	/* Determine NVRAM starting address. */
+	ha->nvram_base = 0;
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha))
+		if ((RD_REG_WORD(&reg->ctrl_status) >> 14) == 1)
+			ha->nvram_base = 0x80;
+
+	/* Get NVRAM data and calculate checksum. */
+	qla2x00_lock_nvram_access(ha);
+	for (cnt = 0; cnt < sizeof(nvram_t)/2; cnt++) {
+		*wptr = cpu_to_le16(qla2x00_get_nvram_word(ha,
+		    (cnt+ha->nvram_base)));
+		chksum += (uint8_t)*wptr;
+		chksum += (uint8_t)(*wptr >> 8);
+		wptr++;
+	}
+	qla2x00_unlock_nvram_access(ha);
+
+	DEBUG5(printk("scsi(%ld): Contents of NVRAM\n", ha->host_no));
+	DEBUG5(qla2x00_dump_buffer((uint8_t *)ha->request_ring,
+	    sizeof(nvram_t)));
+
+	/* Bad NVRAM data, set defaults parameters. */
+	if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' ||
+	    nv->id[2] != 'P' || nv->id[3] != ' ' || nv->nvram_version < 1) {
+		/* Reset NVRAM data. */
+		qla_printk(KERN_WARNING, ha, "Inconsistent NVRAM detected: "
+		    "checksum=0x%x id=%c version=0x%x.\n", chksum, nv->id[0],
+		    nv->nvram_version);
+		qla_printk(KERN_WARNING, ha, "Falling back to functioning (yet "
+		    "invalid -- WWPN) defaults.\n");
+
+		/*
+		 * Set default initialization control block.
+		 */
+		memset(nv, 0, sizeof(nvram_t));
+		nv->parameter_block_version = ICB_VERSION;
+
+		if (IS_QLA23XX(ha)) {
+			nv->firmware_options[0] = BIT_2 | BIT_1;
+			nv->firmware_options[1] = BIT_7 | BIT_5;
+			nv->add_firmware_options[0] = BIT_5;
+			nv->add_firmware_options[1] = BIT_5 | BIT_4;
+			nv->frame_payload_size = __constant_cpu_to_le16(2048);
+			nv->special_options[1] = BIT_7;
+		} else if (IS_QLA2200(ha)) {
+			nv->firmware_options[0] = BIT_2 | BIT_1;
+			nv->firmware_options[1] = BIT_7 | BIT_5;
+			nv->add_firmware_options[0] = BIT_5;
+			nv->add_firmware_options[1] = BIT_5 | BIT_4;
+			nv->frame_payload_size = __constant_cpu_to_le16(1024);
+		} else if (IS_QLA2100(ha)) {
+			nv->firmware_options[0] = BIT_3 | BIT_1;
+			nv->firmware_options[1] = BIT_5;
+			nv->frame_payload_size = __constant_cpu_to_le16(1024);
+		}
+
+		nv->max_iocb_allocation = __constant_cpu_to_le16(256);
+		nv->execution_throttle = __constant_cpu_to_le16(16);
+		nv->retry_count = 8;
+		nv->retry_delay = 1;
+
+		nv->port_name[0] = 33;
+		nv->port_name[3] = 224;
+		nv->port_name[4] = 139;
+
+		nv->login_timeout = 4;
+
+		/*
+		 * Set default host adapter parameters
+		 */
+		nv->host_p[1] = BIT_2;
+		nv->reset_delay = 5;
+		nv->port_down_retry_count = 8;
+		nv->max_luns_per_target = __constant_cpu_to_le16(8);
+		nv->link_down_timeout = 60;
+
+		rval = 1;
+	}
+
+#if defined(CONFIG_IA64_GENERIC) || defined(CONFIG_IA64_SGI_SN2)
+	/*
+	 * The SN2 does not provide BIOS emulation which means you can't change
+	 * potentially bogus BIOS settings. Force the use of default settings
+	 * for link rate and frame size.  Hope that the rest of the settings
+	 * are valid.
+	 */
+	if (ia64_platform_is("sn2")) {
+		nv->frame_payload_size = __constant_cpu_to_le16(2048);
+		if (IS_QLA23XX(ha))
+			nv->special_options[1] = BIT_7;
+	}
+#endif
+
+	/* Reset Initialization control block */
+	memset(icb, 0, sizeof(init_cb_t));
+
+	/*
+	 * Setup driver NVRAM options.
+	 */
+	nv->firmware_options[0] |= (BIT_6 | BIT_1);
+	nv->firmware_options[0] &= ~(BIT_5 | BIT_4);
+	nv->firmware_options[1] |= (BIT_5 | BIT_0);
+	nv->firmware_options[1] &= ~BIT_4;
+
+	if (IS_QLA23XX(ha)) {
+		nv->firmware_options[0] |= BIT_2;
+		nv->firmware_options[0] &= ~BIT_3;
+
+		if (IS_QLA2300(ha)) {
+			if (ha->fb_rev == FPM_2310) {
+				strcpy(ha->model_number, "QLA2310");
+			} else {
+				strcpy(ha->model_number, "QLA2300");
+			}
+		} else {
+			if (rval == 0 &&
+			    memcmp(nv->model_number, BINZERO,
+				    sizeof(nv->model_number)) != 0) {
+				char *st, *en;
+
+				strncpy(ha->model_number, nv->model_number,
+				    sizeof(nv->model_number));
+				st = en = ha->model_number;
+				en += sizeof(nv->model_number) - 1;
+				while (en > st) {
+					if (*en != 0x20 && *en != 0x00)
+						break;
+					*en-- = '\0';
+				}
+			} else {
+				uint16_t        index;
+
+				index = (ha->pdev->subsystem_device & 0xff);
+				if (index < QLA_MODEL_NAMES) {
+					strcpy(ha->model_number,
+					    qla2x00_model_name[index]);
+					ha->model_desc =
+					    qla2x00_model_desc[index];
+				} else {
+					strcpy(ha->model_number, "QLA23xx");
+				}
+			}
+		}
+	} else if (IS_QLA2200(ha)) {
+		nv->firmware_options[0] |= BIT_2;
+		/*
+		 * 'Point-to-point preferred, else loop' is not a safe
+		 * connection mode setting.
+		 */
+		if ((nv->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) ==
+		    (BIT_5 | BIT_4)) {
+			/* Force 'loop preferred, else point-to-point'. */
+			nv->add_firmware_options[0] &= ~(BIT_6 | BIT_5 | BIT_4);
+			nv->add_firmware_options[0] |= BIT_5;
+		}
+		strcpy(ha->model_number, "QLA22xx");
+	} else /*if (IS_QLA2100(ha))*/ {
+		strcpy(ha->model_number, "QLA2100");
+	}
+
+	/*
+	 * Copy over NVRAM RISC parameter block to initialization control block.
+	 */
+	dptr1 = (uint8_t *)icb;
+	dptr2 = (uint8_t *)&nv->parameter_block_version;
+	cnt = (uint8_t *)&icb->request_q_outpointer - (uint8_t *)&icb->version;
+	while (cnt--)
+		*dptr1++ = *dptr2++;
+
+	/* Copy 2nd half. */
+	dptr1 = (uint8_t *)icb->add_firmware_options;
+	cnt = (uint8_t *)icb->reserved_3 - (uint8_t *)icb->add_firmware_options;
+	while (cnt--)
+		*dptr1++ = *dptr2++;
+
+	/* Prepare nodename */
+	if ((icb->firmware_options[1] & BIT_6) == 0) {
+		/*
+		 * Firmware will apply the following mask if the nodename was
+		 * not provided.
+		 */
+		memcpy(icb->node_name, icb->port_name, WWN_SIZE);
+		icb->node_name[0] &= 0xF0;
+	}
+
+	/*
+	 * Set host adapter parameters.
+	 */
+	ha->nvram_version = nv->nvram_version;
+
+	ha->flags.disable_risc_code_load = ((nv->host_p[0] & BIT_4) ? 1 : 0);
+	/* Always load RISC code on non ISP2[12]00 chips. */
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
+		ha->flags.disable_risc_code_load = 0;
+	ha->flags.enable_lip_reset = ((nv->host_p[1] & BIT_1) ? 1 : 0);
+	ha->flags.enable_lip_full_login = ((nv->host_p[1] & BIT_2) ? 1 : 0);
+	ha->flags.enable_target_reset = ((nv->host_p[1] & BIT_3) ? 1 : 0);
+	ha->flags.enable_led_scheme = ((nv->efi_parameters & BIT_3) ? 1 : 0);
+
+	ha->operating_mode =
+	    (icb->add_firmware_options[0] & (BIT_6 | BIT_5 | BIT_4)) >> 4;
+
+	memcpy(ha->fw_seriallink_options, nv->seriallink_options,
+	    sizeof(ha->fw_seriallink_options));
+
+	/* save HBA serial number */
+	ha->serial0 = icb->port_name[5];
+	ha->serial1 = icb->port_name[6];
+	ha->serial2 = icb->port_name[7];
+	memcpy(ha->node_name, icb->node_name, WWN_SIZE);
+
+	icb->execution_throttle = __constant_cpu_to_le16(0xFFFF);
+
+	ha->retry_count = nv->retry_count;
+
+	/* Set minimum login_timeout to 4 seconds. */
+	if (nv->login_timeout < ql2xlogintimeout)
+		nv->login_timeout = ql2xlogintimeout;
+	if (nv->login_timeout < 4)
+		nv->login_timeout = 4;
+	ha->login_timeout = nv->login_timeout;
+	icb->login_timeout = nv->login_timeout;
+
+	/* Set minimum RATOV to 200 tenths of a second. */
+	ha->r_a_tov = 200;
+
+	ha->minimum_timeout =
+	    (ha->login_timeout * ha->retry_count) + nv->port_down_retry_count;
+	ha->loop_reset_delay = nv->reset_delay;
+
+	/* Will get the value from NVRAM. */
+	ha->loop_down_timeout = LOOP_DOWN_TIMEOUT;
+
+	/* Link Down Timeout = 0:
+	 *
+	 * 	When Port Down timer expires we will start returning
+	 *	I/O's to OS with "DID_NO_CONNECT".
+	 *
+	 * Link Down Timeout != 0:
+	 *
+	 *	 The driver waits for the link to come up after link down
+	 *	 before returning I/Os to OS with "DID_NO_CONNECT".
+	 */						
+	if (nv->link_down_timeout == 0) {
+		ha->loop_down_abort_time =
+		    (LOOP_DOWN_TIME - ha->loop_down_timeout);
+	} else {
+		ha->link_down_timeout =	 nv->link_down_timeout;
+		ha->loop_down_abort_time =
+		    (LOOP_DOWN_TIME - ha->link_down_timeout);
+	} 
+
+	ha->max_luns = MAX_LUNS;
+	ha->max_probe_luns = le16_to_cpu(nv->max_luns_per_target);
+	if (ha->max_probe_luns == 0)
+		ha->max_probe_luns = MIN_LUNS;
+
+	/*
+	 * Need enough time to try and get the port back.
+	 */
+	ha->port_down_retry_count = nv->port_down_retry_count;
+	if (qlport_down_retry)
+		ha->port_down_retry_count = qlport_down_retry;
+	/* Set login_retry_count */
+	ha->login_retry_count  = nv->retry_count;
+	if (ha->port_down_retry_count == nv->port_down_retry_count &&
+	    ha->port_down_retry_count > 3)
+		ha->login_retry_count = ha->port_down_retry_count;
+	else if (ha->port_down_retry_count > (int)ha->login_retry_count)
+		ha->login_retry_count = ha->port_down_retry_count;
+	if (ql2xloginretrycount)
+		ha->login_retry_count = ql2xloginretrycount;
+
+	ha->binding_type = Bind;
+	if (ha->binding_type != BIND_BY_PORT_NAME &&
+	    ha->binding_type != BIND_BY_PORT_ID) {
+		qla_printk(KERN_WARNING, ha,
+		    "Invalid binding type specified (%d), "
+		    "defaulting to BIND_BY_PORT_NAME!!!\n", ha->binding_type);
+
+		ha->binding_type = BIND_BY_PORT_NAME;
+	}
+
+	icb->lun_enables = __constant_cpu_to_le16(0);
+	icb->command_resource_count = 0;
+	icb->immediate_notify_resource_count = 0;
+	icb->timeout = __constant_cpu_to_le16(0);
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+		/* Enable RIO */
+		icb->firmware_options[0] &= ~BIT_3;
+		icb->add_firmware_options[0] &=
+		    ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->add_firmware_options[0] |= BIT_2;
+		icb->response_accumulation_timer = 3;
+		icb->interrupt_delay_timer = 5;
+
+		ha->flags.process_response_queue = 1;
+	} else {
+		/* Enable ZIO -- Support mode 5 only. */
+		timer_mode = icb->add_firmware_options[0] &
+		    (BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		icb->add_firmware_options[0] &=
+		    ~(BIT_3 | BIT_2 | BIT_1 | BIT_0);
+		if (ql2xenablezio)
+			timer_mode = BIT_2 | BIT_0;
+		if (timer_mode == (BIT_2 | BIT_0)) {
+			DEBUG2(printk("scsi(%ld): ZIO enabled; timer delay "
+			    "(%d).\n", ha->host_no, ql2xintrdelaytimer));
+			qla_printk(KERN_INFO, ha,
+			    "ZIO enabled; timer delay (%d).\n",
+			    ql2xintrdelaytimer);
+
+			icb->add_firmware_options[0] |= timer_mode;
+			icb->interrupt_delay_timer = ql2xintrdelaytimer;
+			ha->flags.process_response_queue = 1;
+		}
+	}
+
+	if (rval) {
+		DEBUG2_3(printk(KERN_WARNING
+		    "scsi(%ld): NVRAM configuration failed!\n", ha->host_no));
+	}
+	return (rval);
+}
+
+/*
+* qla2x00_init_tgt_map
+*      Initializes target map.
+*
+* Input:
+*      ha = adapter block pointer.
+*
+* Output:
+*      TGT_Q initialized
+*/
+static void
+qla2x00_init_tgt_map(scsi_qla_host_t *ha)
+{
+	uint32_t t;
+
+	for (t = 0; t < MAX_TARGETS; t++)
+		TGT_Q(ha, t) = (os_tgt_t *)NULL;
+}
+
+/**
+ * qla2x00_alloc_fcport() - Allocate a generic fcport.
+ * @ha: HA context
+ * @flags: allocation flags
+ *
+ * Returns a pointer to the allocated fcport, or NULL, if none available.
+ */
+fc_port_t *
+qla2x00_alloc_fcport(scsi_qla_host_t *ha, int flags)
+{
+	fc_port_t *fcport;
+
+	fcport = kmalloc(sizeof(fc_port_t), flags);
+	if (fcport == NULL)
+		return (fcport);
+
+	/* Setup fcport template structure. */
+	memset(fcport, 0, sizeof (fc_port_t));
+	fcport->ha = ha;
+	fcport->port_type = FCT_UNKNOWN;
+	fcport->loop_id = FC_NO_LOOP_ID;
+	fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
+	atomic_set(&fcport->state, FCS_UNCONFIGURED);
+	fcport->flags = FCF_RLC_SUPPORT;
+	INIT_LIST_HEAD(&fcport->fcluns);
+
+	return (fcport);
+}
+
+/*
+ * qla2x00_configure_loop
+ *      Updates Fibre Channel Device Database with what is actually on loop.
+ *
+ * Input:
+ *      ha                = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success.
+ *      1 = error.
+ *      2 = database was full and device was not configured.
+ */
+static int
+qla2x00_configure_loop(scsi_qla_host_t *ha) 
+{
+	int  rval;
+	unsigned long flags, save_flags;
+
+	rval = QLA_SUCCESS;
+
+	/* Get Initiator ID */
+	if (test_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags)) {
+		rval = qla2x00_configure_hba(ha);
+		if (rval != QLA_SUCCESS) {
+			DEBUG(printk("scsi(%ld): Unable to configure HBA.\n",
+			    ha->host_no));
+			return (rval);
+		}
+	}
+
+	save_flags = flags = ha->dpc_flags;
+	DEBUG(printk("scsi(%ld): Configure loop -- dpc flags =0x%lx\n",
+	    ha->host_no, flags));
+
+	/*
+	 * If we have both an RSCN and PORT UPDATE pending then handle them
+	 * both at the same time.
+	 */
+	clear_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+	clear_bit(RSCN_UPDATE, &ha->dpc_flags);
+	ha->mem_err = 0 ;
+
+	/* Determine what we need to do */
+	if (ha->current_topology == ISP_CFG_FL &&
+	    (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
+
+		ha->flags.rscn_queue_overflow = 1;
+		set_bit(RSCN_UPDATE, &flags);
+
+	} else if (ha->current_topology == ISP_CFG_F &&
+	    (test_bit(LOCAL_LOOP_UPDATE, &flags))) {
+
+		ha->flags.rscn_queue_overflow = 1;
+		set_bit(RSCN_UPDATE, &flags);
+		clear_bit(LOCAL_LOOP_UPDATE, &flags);
+
+	} else if (!ha->flags.online ||
+	    (test_bit(ABORT_ISP_ACTIVE, &flags))) {
+
+		ha->flags.rscn_queue_overflow = 1;
+		set_bit(RSCN_UPDATE, &flags);
+		set_bit(LOCAL_LOOP_UPDATE, &flags);
+	}
+
+	if (test_bit(LOCAL_LOOP_UPDATE, &flags)) {
+		if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			rval = qla2x00_configure_local_loop(ha);
+		}
+	}
+
+	if (rval == QLA_SUCCESS && test_bit(RSCN_UPDATE, &flags)) {
+		if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			rval = qla2x00_configure_fabric(ha);
+		}
+	}
+
+	if (rval == QLA_SUCCESS) {
+		if (atomic_read(&ha->loop_down_timer) ||
+		    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+			rval = QLA_FUNCTION_FAILED;
+		} else {
+			qla2x00_config_os(ha);
+			atomic_set(&ha->loop_state, LOOP_READY);
+
+			DEBUG(printk("scsi(%ld): LOOP READY\n", ha->host_no));
+		}
+	}
+
+	if (rval) {
+		DEBUG2_3(printk("%s(%ld): *** FAILED ***\n",
+		    __func__, ha->host_no));
+	} else {
+		DEBUG3(printk("%s: exiting normally\n", __func__));
+	}
+
+	/* Restore state if a resync event occured during processing */
+	if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+		if (test_bit(LOCAL_LOOP_UPDATE, &save_flags))
+			set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+		if (test_bit(RSCN_UPDATE, &save_flags))
+			set_bit(RSCN_UPDATE, &ha->dpc_flags);
+	}
+
+	return (rval);
+}
+
+
+
+/*
+ * qla2x00_configure_local_loop
+ *	Updates Fibre Channel Device Database with local loop devices.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	0 = success.
+ */
+static int
+qla2x00_configure_local_loop(scsi_qla_host_t *ha) 
+{
+	int		rval, rval2;
+	int		found_devs;
+	int		found;
+	fc_port_t	*fcport, *new_fcport;
+
+	uint16_t	index;
+	uint16_t	entries;
+	char		*id_iter;
+	uint16_t	loop_id;
+	uint8_t		domain, area, al_pa;
+
+	found_devs = 0;
+	new_fcport = NULL;
+	entries = MAX_FIBRE_DEVICES;
+
+	DEBUG3(printk("scsi(%ld): Getting FCAL position map\n", ha->host_no));
+	DEBUG3(qla2x00_get_fcal_position_map(ha, NULL));
+
+	/* Get list of logged in devices. */
+	memset(ha->gid_list, 0, GID_LIST_SIZE);
+	rval = qla2x00_get_id_list(ha, ha->gid_list, ha->gid_list_dma,
+	    &entries);
+	if (rval != QLA_SUCCESS)
+		goto cleanup_allocation;
+
+	DEBUG3(printk("scsi(%ld): Entries in ID list (%d)\n",
+	    ha->host_no, entries));
+	DEBUG3(qla2x00_dump_buffer((uint8_t *)ha->gid_list,
+	    entries * sizeof(struct gid_list_info)));
+
+	/* Allocate temporary fcport for any new fcports discovered. */
+	new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
+	if (new_fcport == NULL) {
+		rval = QLA_MEMORY_ALLOC_FAILED;
+		goto cleanup_allocation;
+	}
+	new_fcport->flags &= ~FCF_FABRIC_DEVICE;
+
+	/*
+	 * Mark local devices that were present with FCF_DEVICE_LOST for now.
+	 */
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (atomic_read(&fcport->state) == FCS_ONLINE &&
+		    fcport->port_type != FCT_BROADCAST &&
+		    (fcport->flags & FCF_FABRIC_DEVICE) == 0) {
+
+			DEBUG(printk("scsi(%ld): Marking port lost, "
+			    "loop_id=0x%04x\n",
+			    ha->host_no, fcport->loop_id));
+
+			atomic_set(&fcport->state, FCS_DEVICE_LOST);
+			fcport->flags &= ~FCF_FARP_DONE;
+		}
+	}
+
+	/* Add devices to port list. */
+	id_iter = (char *)ha->gid_list;
+	for (index = 0; index < entries; index++) {
+		domain = ((struct gid_list_info *)id_iter)->domain;
+		area = ((struct gid_list_info *)id_iter)->area;
+		al_pa = ((struct gid_list_info *)id_iter)->al_pa;
+		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+			loop_id = (uint16_t)
+			    ((struct gid_list_info *)id_iter)->loop_id_2100;
+			id_iter += 4;
+		} else {
+			loop_id = le16_to_cpu(
+			    ((struct gid_list_info *)id_iter)->loop_id);
+			id_iter += 6;
+		}
+
+		/* Bypass reserved domain fields. */
+		if ((domain & 0xf0) == 0xf0)
+			continue;
+
+		/* Bypass if not same domain and area of adapter. */
+		if (area != ha->d_id.b.area || domain != ha->d_id.b.domain)
+			continue;
+
+		/* Bypass invalid local loop ID. */
+		if (loop_id > LAST_LOCAL_LOOP_ID)
+			continue;
+
+		/* Fill in member data. */
+		new_fcport->d_id.b.domain = domain;
+		new_fcport->d_id.b.area = area;
+		new_fcport->d_id.b.al_pa = al_pa;
+		new_fcport->loop_id = loop_id;
+		rval2 = qla2x00_get_port_database(ha, new_fcport, 0);
+		if (rval2 != QLA_SUCCESS) {
+			DEBUG2(printk("scsi(%ld): Failed to retrieve fcport "
+			    "information -- get_port_database=%x, "
+			    "loop_id=0x%04x\n",
+			    ha->host_no, rval2, new_fcport->loop_id));
+			continue;
+		}
+
+		/* Check for matching device in port list. */
+		found = 0;
+		fcport = NULL;
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (memcmp(new_fcport->port_name, fcport->port_name,
+			    WWN_SIZE))
+				continue;
+
+			fcport->flags &= ~(FCF_FABRIC_DEVICE |
+			    FCF_PERSISTENT_BOUND);
+			fcport->loop_id = new_fcport->loop_id;
+			fcport->port_type = new_fcport->port_type;
+			fcport->d_id.b24 = new_fcport->d_id.b24;
+			memcpy(fcport->node_name, new_fcport->node_name,
+			    WWN_SIZE);
+
+			found++;
+			break;
+		}
+
+		if (!found) {
+			/* New device, add to fcports list. */
+			new_fcport->flags &= ~FCF_PERSISTENT_BOUND;
+			list_add_tail(&new_fcport->list, &ha->fcports);
+
+			/* Allocate a new replacement fcport. */
+			fcport = new_fcport;
+			new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
+			if (new_fcport == NULL) {
+				rval = QLA_MEMORY_ALLOC_FAILED;
+				goto cleanup_allocation;
+			}
+			new_fcport->flags &= ~FCF_FABRIC_DEVICE;
+		}
+
+		qla2x00_update_fcport(ha, fcport);
+
+		found_devs++;
+	}
+
+cleanup_allocation:
+	if (new_fcport)
+		kfree(new_fcport);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(printk("scsi(%ld): Configure local loop error exit: "
+		    "rval=%x\n", ha->host_no, rval));
+	}
+
+	if (found_devs) {
+		ha->device_flags |= DFLG_LOCAL_DEVICES;
+		ha->device_flags &= ~DFLG_RETRY_LOCAL_DEVICES;
+	}
+
+	return (rval);
+}
+
+static void
+qla2x00_probe_for_all_luns(scsi_qla_host_t *ha) 
+{
+	fc_port_t	*fcport;
+
+	qla2x00_mark_all_devices_lost(ha); 
+ 	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (fcport->port_type != FCT_TARGET)
+			continue;
+
+		qla2x00_update_fcport(ha, fcport); 
+	}
+}
+
+/*
+ * qla2x00_update_fcport
+ *	Updates device on list.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fcport = port structure pointer.
+ *
+ * Return:
+ *	0  - Success
+ *  BIT_0 - error
+ *
+ * Context:
+ *	Kernel context.
+ */
+static void
+qla2x00_update_fcport(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+	uint16_t	index;
+	unsigned long flags;
+	srb_t *sp;
+
+	fcport->ha = ha;
+	fcport->login_retry = 0;
+	fcport->port_login_retry_count = ha->port_down_retry_count *
+	    PORT_RETRY_TIME;
+	atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+	    PORT_RETRY_TIME);
+	fcport->flags &= ~FCF_LOGIN_NEEDED;
+
+	/*
+	 * Check for outstanding cmd on tape Bypass LUN discovery if active
+	 * command on tape.
+	 */
+	if (fcport->flags & FCF_TAPE_PRESENT) {
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
+			if ((sp = ha->outstanding_cmds[index]) != 0) {
+				if (sp->fclun->fcport == fcport) {
+					atomic_set(&fcport->state, FCS_ONLINE);
+					spin_unlock_irqrestore(
+					    &ha->hardware_lock, flags);
+					return;
+				}
+			}
+		}
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	}
+
+	/* Do LUN discovery. */
+	if (fcport->port_type == FCT_INITIATOR ||
+	    fcport->port_type == FCT_BROADCAST) {
+		fcport->device_type = TYPE_PROCESSOR;
+	} else {
+		qla2x00_lun_discovery(ha, fcport);
+	}
+	atomic_set(&fcport->state, FCS_ONLINE);
+}
+
+/*
+ * qla2x00_lun_discovery
+ *	Issue SCSI inquiry command for LUN discovery.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fcport:		FC port structure pointer.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static void
+qla2x00_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+	inq_cmd_rsp_t	*inq;
+	dma_addr_t	inq_dma;
+	uint16_t	lun;
+
+	inq = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL, &inq_dma);
+	if (inq == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Memory Allocation failed - INQ\n");
+		return;
+	}
+
+	/* Always add a fc_lun_t structure for lun 0 -- mid-layer requirement */
+	qla2x00_add_lun(fcport, 0);
+
+	/* If report LUN works, exit. */
+	if (qla2x00_rpt_lun_discovery(ha, fcport, inq, inq_dma) !=
+	    QLA_SUCCESS) {
+		for (lun = 0; lun < ha->max_probe_luns; lun++) {
+			/* Configure LUN. */
+			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);
+		}
+	}
+
+	dma_pool_free(ha->s_dma_pool, inq, inq_dma);
+}
+
+/*
+ * qla2x00_rpt_lun_discovery
+ *	Issue SCSI report LUN command for LUN discovery.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fcport:		FC port structure pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_rpt_lun_discovery(scsi_qla_host_t *ha, fc_port_t *fcport,
+    inq_cmd_rsp_t *inq, dma_addr_t inq_dma)
+{
+	int			rval;
+	uint32_t		len, cnt;
+	uint16_t		lun;
+
+	/* Assume a failed status */
+	rval = QLA_FUNCTION_FAILED;
+
+	/* No point in continuing if the device doesn't support RLC */
+	if ((fcport->flags & FCF_RLC_SUPPORT) == 0)
+		return (rval);
+
+	rval = qla2x00_report_lun(ha, fcport);
+	if (rval != QLA_SUCCESS)
+		return (rval);
+
+	/* Configure LUN list. */
+	len = be32_to_cpu(ha->rlc_rsp->list.hdr.len);
+	len /= 8;
+	for (cnt = 0; cnt < len; cnt++) {
+		lun = CHAR_TO_SHORT(ha->rlc_rsp->list.lst[cnt].lsb,
+		    ha->rlc_rsp->list.lst[cnt].msb.b);
+
+		DEBUG3(printk("scsi(%ld): RLC lun = (%d)\n", ha->host_no, lun));
+
+		/* We only support 0 through MAX_LUNS-1 range */
+		if (lun < MAX_LUNS) {
+			qla2x00_cfg_lun(ha, fcport, lun, inq, inq_dma);
+		}
+	}
+	atomic_set(&fcport->state, FCS_ONLINE);
+
+	return (rval);
+}
+
+/*
+ * qla2x00_report_lun
+ *	Issue SCSI report LUN command.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fcport:		FC port structure pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_report_lun(scsi_qla_host_t *ha, fc_port_t *fcport)
+{
+	int rval;
+	uint16_t retries;
+	uint16_t comp_status;
+	uint16_t scsi_status;
+	rpt_lun_cmd_rsp_t *rlc;
+	dma_addr_t rlc_dma;
+
+	rval = QLA_FUNCTION_FAILED;
+	rlc = ha->rlc_rsp;
+	rlc_dma = ha->rlc_rsp_dma;
+
+	for (retries = 3; retries; retries--) {
+		memset(rlc, 0, sizeof(rpt_lun_cmd_rsp_t));
+		rlc->p.cmd.entry_type = COMMAND_A64_TYPE;
+		rlc->p.cmd.entry_count = 1;
+		SET_TARGET_ID(ha, rlc->p.cmd.target, fcport->loop_id);
+		rlc->p.cmd.control_flags =
+		    __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG);
+		rlc->p.cmd.scsi_cdb[0] = REPORT_LUNS;
+		rlc->p.cmd.scsi_cdb[8] = MSB(sizeof(rpt_lun_lst_t));
+		rlc->p.cmd.scsi_cdb[9] = LSB(sizeof(rpt_lun_lst_t));
+		rlc->p.cmd.dseg_count = __constant_cpu_to_le16(1);
+		rlc->p.cmd.timeout = __constant_cpu_to_le16(10);
+		rlc->p.cmd.byte_count =
+		    __constant_cpu_to_le32(sizeof(rpt_lun_lst_t));
+		rlc->p.cmd.dseg_0_address[0] = cpu_to_le32(
+		    LSD(rlc_dma + sizeof(sts_entry_t)));
+		rlc->p.cmd.dseg_0_address[1] = cpu_to_le32(
+		    MSD(rlc_dma + sizeof(sts_entry_t)));
+		rlc->p.cmd.dseg_0_length =
+		    __constant_cpu_to_le32(sizeof(rpt_lun_lst_t));
+
+		rval = qla2x00_issue_iocb(ha, rlc, rlc_dma,
+		    sizeof(rpt_lun_cmd_rsp_t));
+
+		comp_status = le16_to_cpu(rlc->p.rsp.comp_status);
+		scsi_status = le16_to_cpu(rlc->p.rsp.scsi_status);
+
+		if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE ||
+		    scsi_status & SS_CHECK_CONDITION) {
+
+			/* Device underrun, treat as OK. */
+			if (rval == QLA_SUCCESS &&
+			    comp_status == CS_DATA_UNDERRUN &&
+			    scsi_status & SS_RESIDUAL_UNDER) {
+
+				rval = QLA_SUCCESS;
+				break;
+			}
+
+			DEBUG(printk("scsi(%ld): RLC failed to issue iocb! "
+			    "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n",
+			    ha->host_no, fcport->loop_id, fcport, rval,
+			    comp_status, scsi_status));
+
+			rval = QLA_FUNCTION_FAILED;
+			if (scsi_status & SS_CHECK_CONDITION) {
+				DEBUG2(printk("scsi(%ld): RLC "
+				    "SS_CHECK_CONDITION Sense Data "
+				    "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+				    ha->host_no,
+				    rlc->p.rsp.req_sense_data[0],
+				    rlc->p.rsp.req_sense_data[1],
+				    rlc->p.rsp.req_sense_data[2],
+				    rlc->p.rsp.req_sense_data[3],
+				    rlc->p.rsp.req_sense_data[4],
+				    rlc->p.rsp.req_sense_data[5],
+				    rlc->p.rsp.req_sense_data[6],
+				    rlc->p.rsp.req_sense_data[7]));
+				if (rlc->p.rsp.req_sense_data[2] ==
+				    ILLEGAL_REQUEST) {
+					fcport->flags &= ~(FCF_RLC_SUPPORT);
+					break;
+				}
+			}
+		} else {
+			break;
+		}
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_cfg_lun
+ *	Configures LUN into fcport LUN list.
+ *
+ * Input:
+ *	fcport:		FC port structure pointer.
+ *	lun:		LUN number.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static fc_lun_t *
+qla2x00_cfg_lun(scsi_qla_host_t *ha, fc_port_t *fcport, uint16_t lun,
+    inq_cmd_rsp_t *inq, dma_addr_t inq_dma) 
+{
+	fc_lun_t *fclun;
+	uint8_t	  device_type;
+
+	/* Bypass LUNs that failed. */
+	if (qla2x00_inquiry(ha, fcport, lun, inq, inq_dma) != QLA_SUCCESS) {
+		DEBUG2(printk("scsi(%ld): Failed inquiry - loop id=0x%04x "
+		    "lun=%d\n", ha->host_no, fcport->loop_id, lun));
+
+		return (NULL);
+	}
+	device_type = (inq->inq[0] & 0x1f);
+	switch (device_type) {
+	case TYPE_DISK:
+	case TYPE_PROCESSOR:
+	case TYPE_WORM:
+	case TYPE_ROM:
+	case TYPE_SCANNER:
+	case TYPE_MOD:
+	case TYPE_MEDIUM_CHANGER:
+	case TYPE_ENCLOSURE:
+	case 0x20:
+	case 0x0C:
+		break;
+	case TYPE_TAPE:
+		fcport->flags |= FCF_TAPE_PRESENT;
+		break;
+	default:
+		DEBUG2(printk("scsi(%ld): Unsupported lun type -- "
+		    "loop id=0x%04x lun=%d type=%x\n",
+		    ha->host_no, fcport->loop_id, lun, device_type));
+		return (NULL);
+	}
+
+	fcport->device_type = device_type;
+	fclun = qla2x00_add_lun(fcport, lun);
+
+	if (fclun != NULL) {
+		atomic_set(&fcport->state, FCS_ONLINE);
+	}
+
+	return (fclun);
+}
+
+/*
+ * qla2x00_add_lun
+ *	Adds LUN to database
+ *
+ * Input:
+ *	fcport:		FC port structure pointer.
+ *	lun:		LUN number.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static fc_lun_t *
+qla2x00_add_lun(fc_port_t *fcport, uint16_t lun)
+{
+	int		found;
+	fc_lun_t	*fclun;
+
+	if (fcport == NULL) {
+		DEBUG(printk("scsi: Unable to add lun to NULL port\n"));
+		return (NULL);
+	}
+
+	/* Allocate LUN if not already allocated. */
+	found = 0;
+	list_for_each_entry(fclun, &fcport->fcluns, list) {
+		if (fclun->lun == lun) {
+			found++;
+			break;
+		}
+	}
+	if (found)
+		return (NULL);
+
+	fclun = kmalloc(sizeof(fc_lun_t), GFP_ATOMIC);
+	if (fclun == NULL) {
+		printk(KERN_WARNING
+		    "%s(): Memory Allocation failed - FCLUN\n",
+		    __func__);
+		return (NULL);
+	}
+
+	/* Setup LUN structure. */
+	memset(fclun, 0, sizeof(fc_lun_t));
+	fclun->lun = lun;
+	fclun->fcport = fcport;
+	fclun->o_fcport = fcport;
+	fclun->device_type = fcport->device_type;
+	atomic_set(&fcport->state, FCS_UNCONFIGURED);
+
+	list_add_tail(&fclun->list, &fcport->fcluns);
+
+	return (fclun);
+}
+
+/*
+ * qla2x00_inquiry
+ *	Issue SCSI inquiry command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fcport = FC port structure pointer.
+ *
+ * Return:
+ *	0  - Success
+ *  BIT_0 - error
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_inquiry(scsi_qla_host_t *ha,
+    fc_port_t *fcport, uint16_t lun, inq_cmd_rsp_t *inq, dma_addr_t inq_dma)
+{
+	int rval;
+	uint16_t retries;
+	uint16_t comp_status;
+	uint16_t scsi_status;
+
+	rval = QLA_FUNCTION_FAILED;
+
+	for (retries = 3; retries; retries--) {
+		memset(inq, 0, sizeof(inq_cmd_rsp_t));
+		inq->p.cmd.entry_type = COMMAND_A64_TYPE;
+		inq->p.cmd.entry_count = 1;
+		inq->p.cmd.lun = cpu_to_le16(lun);
+		SET_TARGET_ID(ha, inq->p.cmd.target, fcport->loop_id);
+		inq->p.cmd.control_flags =
+		    __constant_cpu_to_le16(CF_READ | CF_SIMPLE_TAG);
+		inq->p.cmd.scsi_cdb[0] = INQUIRY;
+		inq->p.cmd.scsi_cdb[4] = INQ_DATA_SIZE;
+		inq->p.cmd.dseg_count = __constant_cpu_to_le16(1);
+		inq->p.cmd.timeout = __constant_cpu_to_le16(10);
+		inq->p.cmd.byte_count =
+		    __constant_cpu_to_le32(INQ_DATA_SIZE);
+		inq->p.cmd.dseg_0_address[0] = cpu_to_le32(
+		    LSD(inq_dma + sizeof(sts_entry_t)));
+		inq->p.cmd.dseg_0_address[1] = cpu_to_le32(
+		    MSD(inq_dma + sizeof(sts_entry_t)));
+		inq->p.cmd.dseg_0_length =
+		    __constant_cpu_to_le32(INQ_DATA_SIZE);
+
+		DEBUG5(printk("scsi(%ld): Lun Inquiry - fcport=[%04x/%p],"
+		    " lun (%d)\n",
+		    ha->host_no, fcport->loop_id, fcport, lun));
+
+		rval = qla2x00_issue_iocb(ha, inq, inq_dma,
+		    sizeof(inq_cmd_rsp_t));
+
+		comp_status = le16_to_cpu(inq->p.rsp.comp_status);
+		scsi_status = le16_to_cpu(inq->p.rsp.scsi_status);
+
+		DEBUG5(printk("scsi(%ld): lun (%d) inquiry - "
+		    "inq[0]= 0x%x, comp status 0x%x, scsi status 0x%x, "
+		    "rval=%d\n",
+		    ha->host_no, lun, inq->inq[0], comp_status, scsi_status,
+		    rval));
+
+		if (rval != QLA_SUCCESS || comp_status != CS_COMPLETE ||
+		    scsi_status & SS_CHECK_CONDITION) {
+
+			DEBUG(printk("scsi(%ld): INQ failed to issue iocb! "
+			    "fcport=[%04x/%p] rval=%x cs=%x ss=%x\n",
+			    ha->host_no, fcport->loop_id, fcport, rval,
+			    comp_status, scsi_status));
+
+			if (rval == QLA_SUCCESS)
+				rval = QLA_FUNCTION_FAILED;
+
+			if (scsi_status & SS_CHECK_CONDITION) {
+				DEBUG2(printk("scsi(%ld): INQ "
+				    "SS_CHECK_CONDITION Sense Data "
+				    "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+				    ha->host_no,
+				    inq->p.rsp.req_sense_data[0],
+				    inq->p.rsp.req_sense_data[1],
+				    inq->p.rsp.req_sense_data[2],
+				    inq->p.rsp.req_sense_data[3],
+				    inq->p.rsp.req_sense_data[4],
+				    inq->p.rsp.req_sense_data[5],
+				    inq->p.rsp.req_sense_data[6],
+				    inq->p.rsp.req_sense_data[7]));
+			}
+
+			/* Device underrun drop LUN. */
+			if (comp_status == CS_DATA_UNDERRUN &&
+			    scsi_status & SS_RESIDUAL_UNDER) {
+				break;
+			}
+		} else {
+			break;
+		}
+	}
+
+	return (rval);
+}
+
+
+/*
+ * qla2x00_configure_fabric
+ *      Setup SNS devices with loop ID's.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success.
+ *      BIT_0 = error
+ */
+static int
+qla2x00_configure_fabric(scsi_qla_host_t *ha)
+{
+	int	rval, rval2;
+	fc_port_t	*fcport, *fcptemp;
+	uint16_t	next_loopid;
+	uint16_t	mb[MAILBOX_REGISTER_COUNT];
+	LIST_HEAD(new_fcports);
+
+	/* If FL port exists, then SNS is present */
+	rval = qla2x00_get_port_name(ha, SNS_FL_PORT, NULL, 0);
+	if (rval != QLA_SUCCESS) {
+		DEBUG2(printk("scsi(%ld): MBC_GET_PORT_NAME Failed, No FL "
+		    "Port\n", ha->host_no));
+
+		ha->device_flags &= ~SWITCH_FOUND;
+		return (QLA_SUCCESS);
+	}
+
+	/* Mark devices that need re-synchronization. */
+	rval2 = qla2x00_device_resync(ha);
+	if (rval2 == QLA_RSCNS_HANDLED) {
+		/* No point doing the scan, just continue. */
+		return (QLA_SUCCESS);
+	}
+	do {
+		/* Ensure we are logged into the SNS. */
+		qla2x00_login_fabric(ha, SIMPLE_NAME_SERVER, 0xff, 0xff, 0xfc,
+		    mb, BIT_1 | BIT_0);
+		if (mb[0] != MBS_COMMAND_COMPLETE) {
+			DEBUG2(qla_printk(KERN_INFO, ha,
+			    "Failed SNS login: loop_id=%x mb[0]=%x mb[1]=%x "
+			    "mb[2]=%x mb[6]=%x mb[7]=%x\n", SIMPLE_NAME_SERVER,
+			    mb[0], mb[1], mb[2], mb[6], mb[7]));
+			return (QLA_SUCCESS);
+		}
+
+		if (test_and_clear_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags)) {
+			if (qla2x00_rft_id(ha)) {
+				/* EMPTY */
+				DEBUG2(printk("scsi(%ld): Register FC-4 "
+				    "TYPE failed.\n", ha->host_no));
+			}
+			if (qla2x00_rff_id(ha)) {
+				/* EMPTY */
+				DEBUG2(printk("scsi(%ld): Register FC-4 "
+				    "Features failed.\n", ha->host_no));
+			}
+			if (qla2x00_rnn_id(ha)) {
+				/* EMPTY */
+				DEBUG2(printk("scsi(%ld): Register Node Name "
+				    "failed.\n", ha->host_no));
+			} else if (qla2x00_rsnn_nn(ha)) {
+				/* EMPTY */
+				DEBUG2(printk("scsi(%ld): Register Symbolic "
+				    "Node Name failed.\n", ha->host_no));
+			}
+		}
+
+		rval = qla2x00_find_all_fabric_devs(ha, &new_fcports);
+		if (rval != QLA_SUCCESS)
+			break;
+
+		/*
+		 * Logout all previous fabric devices marked lost, except
+		 * tape devices.
+		 */
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+				break;
+
+			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0)
+				continue;
+
+			if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+				qla2x00_mark_device_lost(ha, fcport,
+				    ql2xplogiabsentdevice);
+				if (fcport->loop_id != FC_NO_LOOP_ID &&
+				    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
+				    fcport->port_type != FCT_INITIATOR &&
+				    fcport->port_type != FCT_BROADCAST) {
+
+					qla2x00_fabric_logout(ha,
+					    fcport->loop_id);
+					fcport->loop_id = FC_NO_LOOP_ID;
+				}
+			}
+		}
+
+		/* Starting free loop ID. */
+		next_loopid = ha->min_external_loopid;
+
+		/*
+		 * Scan through our port list and login entries that need to be
+		 * logged in.
+		 */
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (atomic_read(&ha->loop_down_timer) ||
+			    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+				break;
+
+			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
+			    (fcport->flags & FCF_LOGIN_NEEDED) == 0)
+				continue;
+
+			if (fcport->loop_id == FC_NO_LOOP_ID) {
+				fcport->loop_id = next_loopid;
+				rval = qla2x00_find_new_loop_id(ha, fcport);
+				if (rval != QLA_SUCCESS) {
+					/* Ran out of IDs to use */
+					break;
+				}
+			}
+
+			/* Login and update database */
+			qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+		}
+
+		/* Exit if out of loop IDs. */
+		if (rval != QLA_SUCCESS) {
+			break;
+		}
+
+		/*
+		 * Login and add the new devices to our port list.
+		 */
+		list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
+			if (atomic_read(&ha->loop_down_timer) ||
+			    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+				break;
+
+			/* Find a new loop ID to use. */
+			fcport->loop_id = next_loopid;
+			rval = qla2x00_find_new_loop_id(ha, fcport);
+			if (rval != QLA_SUCCESS) {
+				/* Ran out of IDs to use */
+				break;
+			}
+
+			/* Login and update database */
+			qla2x00_fabric_dev_login(ha, fcport, &next_loopid);
+
+			/* Remove device from the new list and add it to DB */
+			list_del(&fcport->list);
+			list_add_tail(&fcport->list, &ha->fcports);
+		}
+	} while (0);
+
+	/* Free all new device structures not processed. */
+	list_for_each_entry_safe(fcport, fcptemp, &new_fcports, list) {
+		list_del(&fcport->list);
+		kfree(fcport);
+	}
+
+	if (rval) {
+		DEBUG2(printk("scsi(%ld): Configure fabric error exit: "
+		    "rval=%d\n", ha->host_no, rval));
+	}
+
+	return (rval);
+}
+
+
+/*
+ * qla2x00_find_all_fabric_devs
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	dev = database device entry pointer.
+ *
+ * Returns:
+ *	0 = success.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_find_all_fabric_devs(scsi_qla_host_t *ha, struct list_head *new_fcports)
+{
+	int		rval;
+	uint16_t	loop_id;
+	fc_port_t	*fcport, *new_fcport, *fcptemp;
+	int		found;
+
+	sw_info_t	*swl;
+	int		swl_idx;
+	int		first_dev, last_dev;
+	port_id_t	wrap, nxt_d_id;
+
+	rval = QLA_SUCCESS;
+
+	/* Try GID_PT to get device list, else GAN. */
+	swl = kmalloc(sizeof(sw_info_t) * MAX_FIBRE_DEVICES, GFP_ATOMIC);
+	if (swl == NULL) {
+		/*EMPTY*/
+		DEBUG2(printk("scsi(%ld): GID_PT allocations failed, fallback "
+		    "on GA_NXT\n", ha->host_no));
+	} else {
+		memset(swl, 0, sizeof(sw_info_t) * MAX_FIBRE_DEVICES);
+		if (qla2x00_gid_pt(ha, swl) != QLA_SUCCESS) {
+			kfree(swl);
+			swl = NULL;
+		} else if (qla2x00_gpn_id(ha, swl) != QLA_SUCCESS) {
+			kfree(swl);
+			swl = NULL;
+		} else if (qla2x00_gnn_id(ha, swl) != QLA_SUCCESS) {
+			kfree(swl);
+			swl = NULL;
+		}
+	}
+	swl_idx = 0;
+
+	/* Allocate temporary fcport for any new fcports discovered. */
+	new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
+	if (new_fcport == NULL) {
+		if (swl)
+			kfree(swl);
+		return (QLA_MEMORY_ALLOC_FAILED);
+	}
+	new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
+
+	/* Set start port ID scan at adapter ID. */
+	first_dev = 1;
+	last_dev = 0;
+
+	/* Starting free loop ID. */
+	loop_id = ha->min_external_loopid;
+
+	for (; loop_id <= ha->last_loop_id; loop_id++) {
+		if (RESERVED_LOOP_ID(loop_id))
+			continue;
+
+		if (atomic_read(&ha->loop_down_timer) ||
+		    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+			break;
+
+		if (swl != NULL) {
+			if (last_dev) {
+				wrap.b24 = new_fcport->d_id.b24;
+			} else {
+				new_fcport->d_id.b24 = swl[swl_idx].d_id.b24;
+				memcpy(new_fcport->node_name,
+				    swl[swl_idx].node_name, WWN_SIZE);
+				memcpy(new_fcport->port_name,
+				    swl[swl_idx].port_name, WWN_SIZE);
+
+				if (swl[swl_idx].d_id.b.rsvd_1 != 0) {
+					last_dev = 1;
+				}
+				swl_idx++;
+			}
+		} else {
+			/* Send GA_NXT to the switch */
+			rval = qla2x00_ga_nxt(ha, new_fcport);
+			if (rval != QLA_SUCCESS) {
+				qla_printk(KERN_WARNING, ha,
+				    "SNS scan failed -- assuming zero-entry "
+				    "result...\n");
+				list_for_each_entry_safe(fcport, fcptemp,
+				    new_fcports, list) {
+					list_del(&fcport->list);
+					kfree(fcport);
+				}
+				rval = QLA_SUCCESS;
+				break;
+			}
+		}
+
+		/* If wrap on switch device list, exit. */
+		if (first_dev) {
+			wrap.b24 = new_fcport->d_id.b24;
+			first_dev = 0;
+		} else if (new_fcport->d_id.b24 == wrap.b24) {
+			DEBUG2(printk("scsi(%ld): device wrap (%02x%02x%02x)\n",
+			    ha->host_no, new_fcport->d_id.b.domain,
+			    new_fcport->d_id.b.area, new_fcport->d_id.b.al_pa));
+			break;
+		}
+
+		/* Bypass if host adapter. */
+		if (new_fcport->d_id.b24 == ha->d_id.b24)
+			continue;
+
+		/* Bypass reserved domain fields. */
+		if ((new_fcport->d_id.b.domain & 0xf0) == 0xf0)
+			continue;
+
+		/* Locate matching device in database. */
+		found = 0;
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (memcmp(new_fcport->port_name, fcport->port_name,
+			    WWN_SIZE))
+				continue;
+
+			found++;
+
+			/*
+			 * If address the same and state FCS_ONLINE, nothing
+			 * changed.
+			 */
+			if (fcport->d_id.b24 == new_fcport->d_id.b24 &&
+			    atomic_read(&fcport->state) == FCS_ONLINE) {
+				break;
+			}
+
+			/*
+			 * If device was not a fabric device before.
+			 */
+			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
+				fcport->d_id.b24 = new_fcport->d_id.b24;
+				fcport->loop_id = FC_NO_LOOP_ID;
+				fcport->flags |= (FCF_FABRIC_DEVICE |
+				    FCF_LOGIN_NEEDED);
+				fcport->flags &= ~FCF_PERSISTENT_BOUND;
+				break;
+			}
+
+			/*
+			 * Port ID changed or device was marked to be updated;
+			 * Log it out if still logged in and mark it for
+			 * relogin later.
+			 */
+			fcport->d_id.b24 = new_fcport->d_id.b24;
+			fcport->flags |= FCF_LOGIN_NEEDED;
+			if (fcport->loop_id != FC_NO_LOOP_ID &&
+			    (fcport->flags & FCF_TAPE_PRESENT) == 0 &&
+			    fcport->port_type != FCT_INITIATOR &&
+			    fcport->port_type != FCT_BROADCAST) {
+				qla2x00_fabric_logout(ha, fcport->loop_id);
+				fcport->loop_id = FC_NO_LOOP_ID;
+			}
+
+			break;
+		}
+
+		if (found)
+			continue;
+
+		/* If device was not in our fcports list, then add it. */
+		list_add_tail(&new_fcport->list, new_fcports);
+
+		/* Allocate a new replacement fcport. */
+		nxt_d_id.b24 = new_fcport->d_id.b24;
+		new_fcport = qla2x00_alloc_fcport(ha, GFP_KERNEL);
+		if (new_fcport == NULL) {
+			if (swl)
+				kfree(swl);
+			return (QLA_MEMORY_ALLOC_FAILED);
+		}
+		new_fcport->flags |= (FCF_FABRIC_DEVICE | FCF_LOGIN_NEEDED);
+		new_fcport->d_id.b24 = nxt_d_id.b24;
+	}
+
+	if (swl)
+		kfree(swl);
+
+	if (new_fcport)
+		kfree(new_fcport);
+
+	if (!list_empty(new_fcports))
+		ha->device_flags |= DFLG_FABRIC_DEVICES;
+
+	return (rval);
+}
+
+/*
+ * qla2x00_find_new_loop_id
+ *	Scan through our port list and find a new usable loop ID.
+ *
+ * Input:
+ *	ha:	adapter state pointer.
+ *	dev:	port structure pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_find_new_loop_id(scsi_qla_host_t *ha, fc_port_t *dev)
+{
+	int	rval;
+	int	found;
+	fc_port_t *fcport;
+	uint16_t first_loop_id;
+
+	rval = QLA_SUCCESS;
+
+	/* Save starting loop ID. */
+	first_loop_id = dev->loop_id;
+
+	for (;;) {
+		/* Skip loop ID if already used by adapter. */
+		if (dev->loop_id == ha->loop_id) {
+			dev->loop_id++;
+		}
+
+		/* Skip reserved loop IDs. */
+		while (RESERVED_LOOP_ID(dev->loop_id)) {
+			dev->loop_id++;
+		}
+
+		/* Reset loop ID if passed the end. */
+		if (dev->loop_id > ha->last_loop_id) {
+			/* first loop ID. */
+			dev->loop_id = ha->min_external_loopid;
+		}
+
+		/* Check for loop ID being already in use. */
+		found = 0;
+		fcport = NULL;
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (fcport->loop_id == dev->loop_id && fcport != dev) {
+				/* ID possibly in use */
+				found++;
+				break;
+			}
+		}
+
+		/* If not in use then it is free to use. */
+		if (!found) {
+			break;
+		}
+
+		/* ID in use. Try next value. */
+		dev->loop_id++;
+
+		/* If wrap around. No free ID to use. */
+		if (dev->loop_id == first_loop_id) {
+			dev->loop_id = FC_NO_LOOP_ID;
+			rval = QLA_FUNCTION_FAILED;
+			break;
+		}
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_device_resync
+ *	Marks devices in the database that needs resynchronization.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_device_resync(scsi_qla_host_t *ha) 
+{
+	int	rval;
+	int	rval2;
+	uint32_t mask;
+	fc_port_t *fcport;
+	uint32_t rscn_entry;
+	uint8_t rscn_out_iter;
+	uint8_t format;
+	port_id_t d_id;
+
+	rval = QLA_RSCNS_HANDLED;
+
+	while (ha->rscn_out_ptr != ha->rscn_in_ptr ||
+	    ha->flags.rscn_queue_overflow) {
+
+		rscn_entry = ha->rscn_queue[ha->rscn_out_ptr];
+		format = MSB(MSW(rscn_entry));
+		d_id.b.domain = LSB(MSW(rscn_entry));
+		d_id.b.area = MSB(LSW(rscn_entry));
+		d_id.b.al_pa = LSB(LSW(rscn_entry));
+
+		DEBUG(printk("scsi(%ld): RSCN queue entry[%d] = "
+		    "[%02x/%02x%02x%02x].\n",
+		    ha->host_no, ha->rscn_out_ptr, format, d_id.b.domain,
+		    d_id.b.area, d_id.b.al_pa));
+
+		ha->rscn_out_ptr++;
+		if (ha->rscn_out_ptr == MAX_RSCN_COUNT)
+			ha->rscn_out_ptr = 0;
+
+		/* Skip duplicate entries. */
+		for (rscn_out_iter = ha->rscn_out_ptr;
+		    !ha->flags.rscn_queue_overflow &&
+		    rscn_out_iter != ha->rscn_in_ptr;
+		    rscn_out_iter = (rscn_out_iter ==
+			(MAX_RSCN_COUNT - 1)) ? 0: rscn_out_iter + 1) {
+
+			if (rscn_entry != ha->rscn_queue[rscn_out_iter])
+				break;
+
+			DEBUG(printk("scsi(%ld): Skipping duplicate RSCN queue "
+			    "entry found at [%d].\n", ha->host_no,
+			    rscn_out_iter));
+
+			ha->rscn_out_ptr = rscn_out_iter;
+		}
+
+		/* Queue overflow, set switch default case. */
+		if (ha->flags.rscn_queue_overflow) {
+			DEBUG(printk("scsi(%ld): device_resync: rscn "
+			    "overflow.\n", ha->host_no));
+
+			format = 3;
+			ha->flags.rscn_queue_overflow = 0;
+		}
+
+		switch (format) {
+		case 0:
+			if (!IS_QLA2100(ha) && !IS_QLA2200(ha) &&
+			    !IS_QLA6312(ha) && !IS_QLA6322(ha) &&
+			    ha->flags.init_done) {
+				/* Handle port RSCN via asyncronous IOCBs */
+				rval2 = qla2x00_handle_port_rscn(ha, rscn_entry,
+				    NULL, 0);
+				if (rval2 == QLA_SUCCESS)
+					continue;
+			}
+			mask = 0xffffff;
+			break;
+		case 1:
+			mask = 0xffff00;
+			break;
+		case 2:
+			mask = 0xff0000;
+			break;
+		default:
+			mask = 0x0;
+			d_id.b24 = 0;
+			ha->rscn_out_ptr = ha->rscn_in_ptr;
+			break;
+		}
+
+		rval = QLA_SUCCESS;
+
+		/* Abort any outstanding IO descriptors. */
+		if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
+			qla2x00_cancel_io_descriptors(ha);
+
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if ((fcport->flags & FCF_FABRIC_DEVICE) == 0 ||
+			    (fcport->d_id.b24 & mask) != d_id.b24 ||
+			    fcport->port_type == FCT_BROADCAST)
+				continue;
+
+			if (atomic_read(&fcport->state) == FCS_ONLINE) {
+				if (format != 3 ||
+				    fcport->port_type != FCT_INITIATOR) {
+					atomic_set(&fcport->state,
+					    FCS_DEVICE_LOST);
+				}
+			}
+			fcport->flags &= ~FCF_FARP_DONE;
+		}
+	}
+	return (rval);
+}
+
+/*
+ * qla2x00_fabric_dev_login
+ *	Login fabric target device and update FC port database.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fcport:		port structure list pointer.
+ *	next_loopid:	contains value of a new loop ID that can be used
+ *			by the next login attempt.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_fabric_dev_login(scsi_qla_host_t *ha, fc_port_t *fcport,
+    uint16_t *next_loopid)
+{
+	int	rval;
+	int	retry;
+
+	rval = QLA_SUCCESS;
+	retry = 0;
+
+	rval = qla2x00_fabric_login(ha, fcport, next_loopid);
+	if (rval == QLA_SUCCESS) {
+		rval = qla2x00_get_port_database(ha, fcport, 0);
+		if (rval != QLA_SUCCESS) {
+			qla2x00_fabric_logout(ha, fcport->loop_id);
+		} else {
+			qla2x00_update_fcport(ha, fcport);
+		}
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_fabric_login
+ *	Issue fabric login command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	device = pointer to FC device type structure.
+ *
+ * Returns:
+ *      0 - Login successfully
+ *      1 - Login failed
+ *      2 - Initiator device
+ *      3 - Fatal error
+ */
+int
+qla2x00_fabric_login(scsi_qla_host_t *ha, fc_port_t *fcport,
+    uint16_t *next_loopid)
+{
+	int	rval;
+	int	retry;
+	uint16_t tmp_loopid;
+	uint16_t mb[MAILBOX_REGISTER_COUNT];
+
+	retry = 0;
+	tmp_loopid = 0;
+
+	for (;;) {
+		DEBUG(printk("scsi(%ld): Trying Fabric Login w/loop id 0x%04x "
+ 		    "for port %02x%02x%02x.\n",
+ 		    ha->host_no, fcport->loop_id, fcport->d_id.b.domain,
+		    fcport->d_id.b.area, fcport->d_id.b.al_pa));
+
+		/* Login fcport on switch. */
+		qla2x00_login_fabric(ha, fcport->loop_id,
+		    fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa, mb, BIT_0);
+		if (mb[0] == MBS_PORT_ID_USED) {
+			/*
+			 * Device has another loop ID.  The firmware team
+			 * recommends us to perform an implicit login with the
+			 * specified ID again. The ID we just used is save here
+			 * so we return with an ID that can be tried by the
+			 * next login.
+			 */
+			retry++;
+			tmp_loopid = fcport->loop_id;
+			fcport->loop_id = mb[1];
+
+			DEBUG(printk("Fabric Login: port in use - next "
+ 			    "loop id=0x%04x, port Id=%02x%02x%02x.\n",
+			    fcport->loop_id, fcport->d_id.b.domain,
+			    fcport->d_id.b.area, fcport->d_id.b.al_pa));
+
+		} else if (mb[0] == MBS_COMMAND_COMPLETE) {
+			/*
+			 * Login succeeded.
+			 */
+			if (retry) {
+				/* A retry occurred before. */
+				*next_loopid = tmp_loopid;
+			} else {
+				/*
+				 * No retry occurred before. Just increment the
+				 * ID value for next login.
+				 */
+				*next_loopid = (fcport->loop_id + 1);
+			}
+
+			if (mb[1] & BIT_0) {
+				fcport->port_type = FCT_INITIATOR;
+			} else {
+				fcport->port_type = FCT_TARGET;
+				if (mb[1] & BIT_1) {
+					fcport->flags |= FCF_TAPE_PRESENT;
+				}
+			}
+
+			rval = QLA_SUCCESS;
+			break;
+		} else if (mb[0] == MBS_LOOP_ID_USED) {
+			/*
+			 * Loop ID already used, try next loop ID.
+			 */
+			fcport->loop_id++;
+			rval = qla2x00_find_new_loop_id(ha, fcport);
+			if (rval != QLA_SUCCESS) {
+				/* Ran out of loop IDs to use */
+				break;
+			}
+		} else if (mb[0] == MBS_COMMAND_ERROR) {
+			/*
+			 * Firmware possibly timed out during login. If NO
+			 * retries are left to do then the device is declared
+			 * dead.
+			 */
+			*next_loopid = fcport->loop_id;
+			qla2x00_fabric_logout(ha, fcport->loop_id);
+			qla2x00_mark_device_lost(ha, fcport, 1);
+
+			rval = 1;
+			break;
+		} else {
+			/*
+			 * unrecoverable / not handled error
+			 */
+			DEBUG2(printk("%s(%ld): failed=%x port_id=%02x%02x%02x "
+ 			    "loop_id=%x jiffies=%lx.\n", 
+ 			    __func__, ha->host_no, mb[0], 
+			    fcport->d_id.b.domain, fcport->d_id.b.area,
+			    fcport->d_id.b.al_pa, fcport->loop_id, jiffies));
+
+			*next_loopid = fcport->loop_id;
+			qla2x00_fabric_logout(ha, fcport->loop_id);
+			fcport->loop_id = FC_NO_LOOP_ID;
+			atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+
+			rval = 3;
+			break;
+		}
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_local_device_login
+ *	Issue local device login command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	loop_id = loop id of device to login to.
+ *
+ * Returns (Where's the #define!!!!):
+ *      0 - Login successfully
+ *      1 - Login failed
+ *      3 - Fatal error
+ */
+int
+qla2x00_local_device_login(scsi_qla_host_t *ha, uint16_t loop_id)
+{
+	int		rval;
+	uint16_t	mb[MAILBOX_REGISTER_COUNT];
+
+	memset(mb, 0, sizeof(mb));
+	rval = qla2x00_login_local_device(ha, loop_id, mb, BIT_0);
+	if (rval == QLA_SUCCESS) {
+		/* Interrogate mailbox registers for any errors */
+		if (mb[0] == MBS_COMMAND_ERROR)
+			rval = 1;
+		else if (mb[0] == MBS_COMMAND_PARAMETER_ERROR)
+			/* device not in PCB table */
+			rval = 3;
+	}
+
+	return (rval);
+}
+
+/*
+ *  qla2x00_loop_resync
+ *      Resync with fibre channel devices.
+ *
+ * Input:
+ *      ha = adapter block pointer.
+ *
+ * Returns:
+ *      0 = success
+ */
+int
+qla2x00_loop_resync(scsi_qla_host_t *ha) 
+{
+	int   rval;
+	uint32_t wait_time;
+
+	rval = QLA_SUCCESS;
+
+	atomic_set(&ha->loop_state, LOOP_UPDATE);
+	qla2x00_stats.loop_resync++;
+	clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+	if (ha->flags.online) {
+		if (!(rval = qla2x00_fw_ready(ha))) {
+			/* Wait at most MAX_TARGET RSCNs for a stable link. */
+			wait_time = 256;
+			do {
+				/* v2.19.05b6 */
+				atomic_set(&ha->loop_state, LOOP_UPDATE);
+
+				/*
+				 * Issue marker command only when we are going
+				 * to start the I/O .
+				 */
+				ha->marker_needed = 1;
+
+				/* Remap devices on Loop. */
+				clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+
+				qla2x00_configure_loop(ha);
+				wait_time--;
+			} while (!atomic_read(&ha->loop_down_timer) &&
+				!(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
+				wait_time &&
+				(test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
+		}
+		qla2x00_restart_queues(ha, 1);
+	}
+
+	if (test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
+		return (QLA_FUNCTION_FAILED);
+	}
+
+	if (rval) {
+		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+	}
+
+	return (rval);
+}
+
+/*
+ *  qla2x00_restart_queues
+ *	Restart device queues.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Context:
+ *	Kernel/Interrupt context.
+ */
+void
+qla2x00_restart_queues(scsi_qla_host_t *ha, uint8_t flush) 
+{
+	srb_t  		*sp;
+	int		retry_q_cnt = 0;
+	int		pending_q_cnt = 0;
+	struct list_head *list, *temp;
+	unsigned long flags = 0;
+
+	clear_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags);
+
+	/* start pending queue */
+	pending_q_cnt = ha->qthreads;
+	if (flush) {
+		spin_lock_irqsave(&ha->list_lock,flags);
+		list_for_each_safe(list, temp, &ha->pending_queue) {
+			sp = list_entry(list, srb_t, list);
+
+			if ((sp->flags & SRB_TAPE))
+				continue;
+			 
+			/* 
+			 * When time expire return request back to OS as BUSY 
+			 */
+			__del_from_pending_queue(ha, sp);
+			sp->cmd->result = DID_BUS_BUSY << 16;
+			sp->cmd->host_scribble = (unsigned char *)NULL;
+			__add_to_done_queue(ha, sp);
+		}
+		spin_unlock_irqrestore(&ha->list_lock, flags);
+	} else {
+		if (!list_empty(&ha->pending_queue))
+			qla2x00_next(ha);
+	}
+
+	/*
+	 * Clear out our retry queue
+	 */
+	if (flush) {
+		spin_lock_irqsave(&ha->list_lock, flags);
+		retry_q_cnt = ha->retry_q_cnt;
+		list_for_each_safe(list, temp, &ha->retry_queue) {
+			sp = list_entry(list, srb_t, list);
+			/* when time expire return request back to OS as BUSY */
+			__del_from_retry_queue(ha, sp);
+			sp->cmd->result = DID_BUS_BUSY << 16;
+			sp->cmd->host_scribble = (unsigned char *)NULL;
+			__add_to_done_queue(ha, sp);
+		}
+		spin_unlock_irqrestore(&ha->list_lock, flags);
+
+		DEBUG2(printk("%s(%ld): callback %d commands.\n",
+				__func__,
+				ha->host_no,
+				retry_q_cnt);)
+	}
+
+	DEBUG2(printk("%s(%ld): active=%ld, retry=%d, pending=%d, "
+			"done=%ld, scsi retry=%d commands.\n",
+			__func__,
+			ha->host_no,
+			ha->actthreads,
+			ha->retry_q_cnt,
+			pending_q_cnt,
+			ha->done_q_cnt,
+			ha->scsi_retry_q_cnt);)
+
+	if (!list_empty(&ha->done_queue))
+		qla2x00_done(ha);
+}
+
+void
+qla2x00_rescan_fcports(scsi_qla_host_t *ha)
+{
+	int rescan_done;
+	fc_port_t *fcport;
+
+	rescan_done = 0;
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if ((fcport->flags & FCF_RESCAN_NEEDED) == 0)
+			continue;
+
+		qla2x00_update_fcport(ha, fcport);
+		fcport->flags &= ~FCF_RESCAN_NEEDED;
+
+		rescan_done = 1;
+	}
+	qla2x00_probe_for_all_luns(ha); 
+
+	/* Update OS target and lun structures if necessary. */
+	if (rescan_done) {
+		qla2x00_config_os(ha);
+	}
+}
+
+
+/*
+ * qla2x00_config_os
+ *	Setup OS target and LUN structures.
+ *
+ * Input:
+ *	ha = adapter state pointer.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static void
+qla2x00_config_os(scsi_qla_host_t *ha) 
+{
+	fc_port_t	*fcport;
+	fc_lun_t	*fclun;
+	os_tgt_t	*tq;
+	uint16_t	tgt;
+
+
+	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+		if ((tq = TGT_Q(ha, tgt)) == NULL)
+			continue;
+
+		clear_bit(TQF_ONLINE, &tq->flags);
+	}
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (atomic_read(&fcport->state) != FCS_ONLINE ||
+		    fcport->port_type == FCT_INITIATOR ||
+		    fcport->port_type == FCT_BROADCAST) {
+			fcport->os_target_id = MAX_TARGETS;
+			continue;
+		}
+
+		if (fcport->flags & FCF_FO_MASKED) {
+			continue;
+		}
+
+		/* Bind FC port to OS target number. */
+		if (qla2x00_fcport_bind(ha, fcport) == MAX_TARGETS) {
+			continue;
+		}
+
+		/* Bind FC LUN to OS LUN number. */
+		list_for_each_entry(fclun, &fcport->fcluns, list) {
+			qla2x00_fclun_bind(ha, fcport, fclun);
+		}
+	}
+}
+
+/*
+ * qla2x00_fcport_bind
+ *	Locates a target number for FC port.
+ *
+ * Input:
+ *	ha = adapter state pointer.
+ *	fcport = FC port structure pointer.
+ *
+ * Returns:
+ *	target number
+ *
+ * Context:
+ *	Kernel context.
+ */
+static uint16_t
+qla2x00_fcport_bind(scsi_qla_host_t *ha, fc_port_t *fcport) 
+{
+	int		found;
+	uint16_t	tgt;
+	os_tgt_t	*tq;
+
+	/* Check for persistent binding. */
+	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+		if ((tq = TGT_Q(ha, tgt)) == NULL)
+			continue;
+
+		found = 0;
+		switch (ha->binding_type) {
+		case BIND_BY_PORT_ID:
+			if (fcport->d_id.b24 == tq->d_id.b24) {
+				memcpy(tq->node_name, fcport->node_name,
+				    WWN_SIZE);
+				memcpy(tq->port_name, fcport->port_name,
+				    WWN_SIZE);
+				found++;
+			}
+			break;
+		case BIND_BY_PORT_NAME:    
+			if (memcmp(fcport->port_name, tq->port_name,
+			    WWN_SIZE) == 0) {
+				/*
+				 * In case of persistent binding, update the
+				 * WWNN.
+				 */
+				memcpy(tq->node_name, fcport->node_name,
+				    WWN_SIZE);
+				found++;
+			}
+			break;
+		}
+		if (found)
+		    break;	
+	}
+
+	/* TODO: honor the ConfigRequired flag */
+	if (tgt == MAX_TARGETS) {
+		/* Check if targetID 0 available. */
+		tgt = 0;
+
+		if (TGT_Q(ha, tgt) != NULL) {
+			/* Locate first free target for device. */
+			for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+				if (TGT_Q(ha, tgt) == NULL) {
+					break;
+				}
+			}
+		}
+		if (tgt != MAX_TARGETS) {
+			if ((tq = qla2x00_tgt_alloc(ha, tgt)) != NULL) {
+				memcpy(tq->node_name, fcport->node_name,
+				    WWN_SIZE);
+				memcpy(tq->port_name, fcport->port_name,
+				    WWN_SIZE);
+				tq->d_id.b24 = fcport->d_id.b24;
+			}
+		}
+	}
+
+	/* Reset target numbers incase it changed. */
+	fcport->os_target_id = tgt;
+	if (tgt != MAX_TARGETS && tq != NULL) {
+		DEBUG2(printk("scsi(%ld): Assigning target ID=%02d @ %p to "
+		    "loop id=0x%04x, port state=0x%x, port down retry=%d\n",
+		    ha->host_no, tgt, tq, fcport->loop_id,
+		    atomic_read(&fcport->state),
+		    atomic_read(&fcport->port_down_timer)));
+
+		fcport->tgt_queue = tq;
+		fcport->flags |= FCF_PERSISTENT_BOUND;
+		tq->fcport = fcport;
+		set_bit(TQF_ONLINE, &tq->flags);
+		tq->port_down_retry_count = ha->port_down_retry_count;
+	}
+
+	if (tgt == MAX_TARGETS) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to bind fcport, loop_id=%x\n", fcport->loop_id);
+	}
+
+	return (tgt);
+}
+
+/*
+ * qla2x00_fclun_bind
+ *	Binds all FC device LUNS to OS LUNS.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	fcport:		FC port structure pointer.
+ *
+ * Returns:
+ *	target number
+ *
+ * Context:
+ *	Kernel context.
+ */
+static os_lun_t *
+qla2x00_fclun_bind(scsi_qla_host_t *ha, fc_port_t *fcport, fc_lun_t *fclun)
+{
+	os_lun_t	*lq;
+	uint16_t	tgt;
+	uint16_t	lun;
+
+	tgt = fcport->os_target_id;
+	lun = fclun->lun;
+
+	/* Allocate LUNs */
+	if (lun >= MAX_LUNS) {
+		DEBUG2(printk("scsi(%ld): Unable to bind lun, invalid "
+		    "lun=(%x).\n", ha->host_no, lun));
+		return (NULL);
+	}
+
+	/* Always alloc LUN 0 so kernel will scan past LUN 0. */
+	if (lun != 0 && (EXT_IS_LUN_BIT_SET(&(fcport->lun_mask), lun))) {
+		return (NULL);
+	}
+
+	if ((lq = qla2x00_lun_alloc(ha, tgt, lun)) == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to bind fclun, loop_id=%x lun=%x\n",
+		    fcport->loop_id, lun);
+		return (NULL);
+	}
+
+	lq->fclun = fclun;
+
+	return (lq);
+}
+
+/*
+ * qla2x00_tgt_alloc
+ *	Allocate and pre-initialize target queue.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	t = SCSI target number.
+ *
+ * Returns:
+ *	NULL = failure
+ *
+ * Context:
+ *	Kernel context.
+ */
+static os_tgt_t *
+qla2x00_tgt_alloc(scsi_qla_host_t *ha, uint16_t tgt) 
+{
+	os_tgt_t	*tq;
+
+	/*
+	 * If SCSI addressing OK, allocate TGT queue and lock.
+	 */
+	if (tgt >= MAX_TARGETS) {
+		DEBUG2(printk("scsi(%ld): Unable to allocate target, invalid "
+		    "target number %d.\n", ha->host_no, tgt));
+		return (NULL);
+	}
+
+	tq = TGT_Q(ha, tgt);
+	if (tq == NULL) {
+		tq = kmalloc(sizeof(os_tgt_t), GFP_ATOMIC);
+		if (tq != NULL) {
+			DEBUG2(printk("scsi(%ld): Alloc Target %d @ %p\n",
+			    ha->host_no, tgt, tq));
+
+			memset(tq, 0, sizeof(os_tgt_t));
+			tq->ha = ha;
+
+			TGT_Q(ha, tgt) = tq;
+		}
+	}
+	if (tq != NULL) {
+		tq->port_down_retry_count = ha->port_down_retry_count;
+	} else {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to allocate target.\n");
+		ha->mem_err++;
+	}
+
+	return (tq);
+}
+
+/*
+ * qla2x00_tgt_free
+ *	Frees target and LUN queues.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	t = SCSI target number.
+ *
+ * Context:
+ *	Kernel context.
+ */
+void
+qla2x00_tgt_free(scsi_qla_host_t *ha, uint16_t tgt) 
+{
+	os_tgt_t	*tq;
+	uint16_t	lun;
+
+	/*
+	 * If SCSI addressing OK, allocate TGT queue and lock.
+	 */
+	if (tgt >= MAX_TARGETS) {
+		DEBUG2(printk("scsi(%ld): Unable to de-allocate target, "
+		    "invalid target number %d.\n", ha->host_no, tgt));
+
+		return;
+	}
+
+	tq = TGT_Q(ha, tgt);
+	if (tq != NULL) {
+		TGT_Q(ha, tgt) = NULL;
+
+		/* Free LUN structures. */
+		for (lun = 0; lun < MAX_LUNS; lun++)
+			qla2x00_lun_free(ha, tgt, lun);
+
+		kfree(tq);
+	}
+
+	return;
+}
+
+/*
+ * qla2x00_lun_alloc
+ *	Allocate and initialize LUN queue.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	t = SCSI target number.
+ *	l = LUN number.
+ *
+ * Returns:
+ *	NULL = failure
+ *
+ * Context:
+ *	Kernel context.
+ */
+static os_lun_t *
+qla2x00_lun_alloc(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) 
+{
+	os_lun_t	*lq;
+
+	/*
+	 * If SCSI addressing OK, allocate LUN queue.
+	 */
+	if (tgt >= MAX_TARGETS || lun >= MAX_LUNS || TGT_Q(ha, tgt) == NULL) {
+		DEBUG2(printk("scsi(%ld): Unable to allocate lun, invalid "
+		    "parameter.\n", ha->host_no));
+
+		return (NULL);
+	}
+
+	lq = LUN_Q(ha, tgt, lun);
+	if (lq == NULL) {
+		lq = kmalloc(sizeof(os_lun_t), GFP_ATOMIC);
+		if (lq != NULL) {
+			DEBUG2(printk("scsi(%ld): Alloc Lun %d @ tgt %d.\n",
+			    ha->host_no, lun, tgt));
+
+			memset(lq, 0, sizeof(os_lun_t));
+			LUN_Q(ha, tgt, lun) = lq;
+
+			/*
+			 * The following lun queue initialization code
+			 * must be duplicated in alloc_ioctl_mem function
+			 * for ioctl_lq.
+			 */
+			lq->q_state = LUN_STATE_READY;
+			spin_lock_init(&lq->q_lock);
+		}
+	}
+
+	if (lq == NULL) {
+		qla_printk(KERN_WARNING, ha, "Unable to allocate lun.\n");
+	}
+
+	return (lq);
+}
+
+/*
+ * qla2x00_lun_free
+ *	Frees LUN queue.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	t = SCSI target number.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static void
+qla2x00_lun_free(scsi_qla_host_t *ha, uint16_t tgt, uint16_t lun) 
+{
+	os_lun_t	*lq;
+
+	/*
+	 * If SCSI addressing OK, allocate TGT queue and lock.
+	 */
+	if (tgt >= MAX_TARGETS || lun >= MAX_LUNS) {
+		DEBUG2(printk("scsi(%ld): Unable to deallocate lun, invalid "
+		    "parameter.\n", ha->host_no));
+
+		return;
+	}
+
+	if (TGT_Q(ha, tgt) != NULL && (lq = LUN_Q(ha, tgt, lun)) != NULL) {
+		LUN_Q(ha, tgt, lun) = NULL;
+		kfree(lq);
+	}
+
+	return;
+}
+
+/*
+*  qla2x00_abort_isp
+*      Resets ISP and aborts all outstanding commands.
+*
+* Input:
+*      ha           = adapter block pointer.
+*
+* Returns:
+*      0 = success
+*/
+int
+qla2x00_abort_isp(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	uint16_t       cnt;
+	srb_t          *sp;
+	uint8_t        status = 0;
+
+	if (ha->flags.online) {
+		ha->flags.online = 0;
+		clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		qla2x00_stats.ispAbort++;
+		ha->total_isp_aborts++;  /* used by ioctl */
+		ha->sns_retry_cnt = 0;
+
+		qla_printk(KERN_INFO, ha,
+		    "Performing ISP error recovery - ha= %p.\n", ha);
+		qla2x00_reset_chip(ha);
+
+		atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);
+			qla2x00_mark_all_devices_lost(ha);
+		} else {
+			if (!atomic_read(&ha->loop_down_timer))
+				atomic_set(&ha->loop_down_timer,
+				    LOOP_DOWN_TIME);
+		}
+
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+		/* Requeue all commands in outstanding command list. */
+		for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+			sp = ha->outstanding_cmds[cnt];
+			if (sp) {
+				ha->outstanding_cmds[cnt] = NULL;
+				if (ha->actthreads)
+					ha->actthreads--;
+				sp->lun_queue->out_cnt--;
+
+				/*
+				 * Set the cmd host_byte status depending on
+				 * whether the scsi_error_handler is
+				 * active or not.
+ 				 */
+				if (sp->flags & SRB_TAPE) {
+					sp->cmd->result = DID_NO_CONNECT << 16;
+				} else {
+					if (ha->host->eh_active != EH_ACTIVE)
+						sp->cmd->result =
+						    DID_BUS_BUSY << 16;
+					else
+						sp->cmd->result =
+						    DID_RESET << 16;
+				}
+				sp->flags = 0;
+				sp->cmd->host_scribble = (unsigned char *)NULL;
+				add_to_done_queue(ha, sp);
+			}
+		}
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		qla2x00_nvram_config(ha);
+
+		if (!qla2x00_restart_isp(ha)) {
+			clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+
+			if (!atomic_read(&ha->loop_down_timer)) {
+				/*
+				 * Issue marker command only when we are going
+				 * to start the I/O .
+				 */
+				ha->marker_needed = 1;
+			}
+
+			ha->flags.online = 1;
+
+			/* Enable ISP interrupts. */
+			qla2x00_enable_intrs(ha);
+
+			/* v2.19.5b6 Return all commands */
+			qla2x00_abort_queues(ha, 1);
+
+			/* Restart queues that may have been stopped. */
+			qla2x00_restart_queues(ha, 1);
+			ha->isp_abort_cnt = 0; 
+			clear_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+		} else {	/* failed the ISP abort */
+			ha->flags.online = 1;
+			if (test_bit(ISP_ABORT_RETRY, &ha->dpc_flags)) {
+				if (ha->isp_abort_cnt == 0) {
+ 					qla_printk(KERN_WARNING, ha,
+					    "ISP error recovery failed - "
+					    "board disabled\n");
+					/* 
+					 * The next call disables the board
+					 * completely.
+					 */
+					qla2x00_reset_adapter(ha);
+					qla2x00_abort_queues(ha, 0);
+					ha->flags.online = 0;
+					clear_bit(ISP_ABORT_RETRY,
+					    &ha->dpc_flags);
+					status = 0;
+				} else { /* schedule another ISP abort */
+					ha->isp_abort_cnt--;
+					DEBUG(printk("qla%ld: ISP abort - "
+					    "retry remainning %d\n",
+					    ha->host_no, ha->isp_abort_cnt);)
+					status = 1;
+				}
+			} else {
+				ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
+				DEBUG(printk("qla2x00(%ld): ISP error recovery "
+				    "- retrying (%d) more times\n",
+				    ha->host_no, ha->isp_abort_cnt);)
+				set_bit(ISP_ABORT_RETRY, &ha->dpc_flags);
+				status = 1;
+			}
+		}
+		       
+	}
+
+	if (status) {
+		qla_printk(KERN_INFO, ha,
+			"qla2x00_abort_isp: **** FAILED ****\n");
+	} else {
+		DEBUG(printk(KERN_INFO
+				"qla2x00_abort_isp(%ld): exiting.\n",
+				ha->host_no);)
+	}
+
+	return(status);
+}
+
+/*
+*  qla2x00_restart_isp
+*      restarts the ISP after a reset
+*
+* Input:
+*      ha = adapter block pointer.
+*
+* Returns:
+*      0 = success
+*/
+static int
+qla2x00_restart_isp(scsi_qla_host_t *ha)
+{
+	uint8_t		status = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+	unsigned long	flags = 0;
+	uint32_t wait_time;
+
+	/* If firmware needs to be loaded */
+	if (qla2x00_isp_firmware(ha)) {
+		ha->flags.online = 0;
+		if (!(status = qla2x00_chip_diag(ha))) {
+			if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+				status = qla2x00_setup_chip(ha);
+				goto done;
+			}
+
+			reg = ha->iobase;
+
+			spin_lock_irqsave(&ha->hardware_lock, flags);
+
+			/* Disable SRAM, Instruction RAM and GP RAM parity. */
+			WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x0));
+			RD_REG_WORD(&reg->hccr);	/* PCI Posting. */
+
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	
+			status = qla2x00_setup_chip(ha);
+
+			spin_lock_irqsave(&ha->hardware_lock, flags);
+ 
+ 			/* Enable proper parity */
+ 			if (IS_QLA2300(ha))
+ 				/* SRAM parity */
+ 				WRT_REG_WORD(&reg->hccr,
+ 				    (HCCR_ENABLE_PARITY + 0x1));
+ 			else
+ 				/* SRAM, Instruction RAM and GP RAM parity */
+ 				WRT_REG_WORD(&reg->hccr,
+ 				    (HCCR_ENABLE_PARITY + 0x7));
+			RD_REG_WORD(&reg->hccr);	/* PCI Posting. */
+
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		}
+	}
+
+ done:
+	if (!status && !(status = qla2x00_init_rings(ha))) {
+		clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+		if (!(status = qla2x00_fw_ready(ha))) {
+			DEBUG(printk("%s(): Start configure loop, "
+					"status = %d\n",
+					__func__,
+					status);)
+			ha->flags.online = 1;
+			/* Wait at most MAX_TARGET RSCNs for a stable link. */
+			wait_time = 256;
+			do {
+				clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+				qla2x00_configure_loop(ha);
+				wait_time--;
+			} while (!atomic_read(&ha->loop_down_timer) &&
+				!(test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) &&
+				wait_time &&
+				(test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)));
+		}
+
+		/* if no cable then assume it's good */
+		if ((ha->device_flags & DFLG_NO_CABLE)) 
+			status = 0;
+
+		DEBUG(printk("%s(): Configure loop done, status = 0x%x\n",
+				__func__,
+				status);)
+	}
+	return (status);
+}
+
+/*
+* qla2x00_reset_adapter
+*      Reset adapter.
+*
+* Input:
+*      ha = adapter block pointer.
+*/
+static void
+qla2x00_reset_adapter(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	ha->flags.online = 0;
+	qla2x00_disable_intrs(ha);
+
+	/* Reset RISC processor. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */
+	WRT_REG_WORD(&reg->hccr, HCCR_RELEASE_RISC);
+	RD_REG_WORD(&reg->hccr);			/* PCI Posting. */
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h
new file mode 100644
index 0000000..07c1133
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_inline.h
@@ -0,0 +1,292 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+
+
+static __inline__ uint16_t qla2x00_debounce_register(volatile uint16_t __iomem *);
+/*
+ * qla2x00_debounce_register
+ *      Debounce register.
+ *
+ * Input:
+ *      port = register address.
+ *
+ * Returns:
+ *      register value.
+ */
+static __inline__ uint16_t
+qla2x00_debounce_register(volatile uint16_t __iomem *addr) 
+{
+	volatile uint16_t first;
+	volatile uint16_t second;
+
+	do {
+		first = RD_REG_WORD(addr);
+		barrier();
+		cpu_relax();
+		second = RD_REG_WORD(addr);
+	} while (first != second);
+
+	return (first);
+}
+
+static __inline__ int qla2x00_normalize_dma_addr(
+    dma_addr_t *e_addr,  uint32_t *e_len,
+    dma_addr_t *ne_addr, uint32_t *ne_len);
+
+/**
+ * qla2x00_normalize_dma_addr() - Normalize an DMA address.
+ * @e_addr: Raw DMA address
+ * @e_len: Raw DMA length
+ * @ne_addr: Normalized second DMA address
+ * @ne_len: Normalized second DMA length
+ *
+ * If the address does not span a 4GB page boundary, the contents of @ne_addr
+ * and @ne_len are undefined.  @e_len is updated to reflect a normalization.
+ *
+ * Example:
+ *
+ * 	ffffabc0ffffeeee	(e_addr) start of DMA address
+ * 	0000000020000000	(e_len)  length of DMA transfer
+ *	ffffabc11fffeeed	end of DMA transfer
+ *
+ * Is the 4GB boundary crossed?
+ *
+ * 	ffffabc0ffffeeee	(e_addr)
+ *	ffffabc11fffeeed	(e_addr + e_len - 1)
+ *	00000001e0000003	((e_addr ^ (e_addr + e_len - 1))
+ *	0000000100000000	((e_addr ^ (e_addr + e_len - 1)) & ~(0xffffffff)
+ *
+ * Compute start of second DMA segment:
+ *
+ * 	ffffabc0ffffeeee	(e_addr)
+ *	ffffabc1ffffeeee	(0x100000000 + e_addr)
+ *	ffffabc100000000	(0x100000000 + e_addr) & ~(0xffffffff)
+ *	ffffabc100000000	(ne_addr)
+ *	
+ * Compute length of second DMA segment:
+ *
+ *	00000000ffffeeee	(e_addr & 0xffffffff)
+ *	0000000000001112	(0x100000000 - (e_addr & 0xffffffff))
+ *	000000001fffeeee	(e_len - (0x100000000 - (e_addr & 0xffffffff))
+ *	000000001fffeeee	(ne_len)
+ *
+ * Adjust length of first DMA segment
+ *
+ * 	0000000020000000	(e_len)
+ *	0000000000001112	(e_len - ne_len)
+ *	0000000000001112	(e_len)
+ *
+ * Returns non-zero if the specified address was normalized, else zero.
+ */
+static __inline__ int
+qla2x00_normalize_dma_addr(
+    dma_addr_t *e_addr,  uint32_t *e_len,
+    dma_addr_t *ne_addr, uint32_t *ne_len)
+{
+	int normalized;
+
+	normalized = 0;
+	if ((*e_addr ^ (*e_addr + *e_len - 1)) & ~(0xFFFFFFFFULL)) {
+		/* Compute normalized crossed address and len */
+		*ne_addr = (0x100000000ULL + *e_addr) & ~(0xFFFFFFFFULL);
+		*ne_len = *e_len - (0x100000000ULL - (*e_addr & 0xFFFFFFFFULL));
+		*e_len -= *ne_len;
+
+		normalized++;
+	}
+	return (normalized);
+}
+
+static __inline__ void qla2x00_poll(scsi_qla_host_t *);
+static inline void 
+qla2x00_poll(scsi_qla_host_t *ha)
+{
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		qla2100_intr_handler(0, ha, NULL);
+	else
+		qla2300_intr_handler(0, ha, NULL);
+}
+
+
+static __inline__ void qla2x00_enable_intrs(scsi_qla_host_t *);
+static __inline__ void qla2x00_disable_intrs(scsi_qla_host_t *);
+
+static inline void 
+qla2x00_enable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 1;
+	/* enable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, ICR_EN_INT | ICR_EN_RISC);
+	RD_REG_WORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+}
+
+static inline void 
+qla2x00_disable_intrs(scsi_qla_host_t *ha)
+{
+	unsigned long flags = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ha->interrupts_on = 0;
+	/* disable risc and host interrupts */
+	WRT_REG_WORD(&reg->ictrl, 0);
+	RD_REG_WORD(&reg->ictrl);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+
+static __inline__ int qla2x00_is_wwn_zero(uint8_t *);
+
+/*
+ * qla2x00_is_wwn_zero - Check for zero node name
+ *
+ * Input:
+ *      wwn = Pointer to WW name to check
+ *
+ * Returns:
+ *      1 if name is 0x00 else 0
+ *
+ * Context:
+ *      Kernel context.
+ */
+static __inline__ int
+qla2x00_is_wwn_zero(uint8_t *wwn)
+{
+	int cnt;
+
+	for (cnt = 0; cnt < WWN_SIZE ; cnt++, wwn++) {
+		if (*wwn != 0)
+			break;
+	}
+	/* if zero return 1 */
+	if (cnt == WWN_SIZE)
+		return (1);
+	else
+		return (0);
+}
+
+static __inline__ uint8_t
+qla2x00_suspend_lun(scsi_qla_host_t *, os_lun_t *, int, int);
+static __inline__ uint8_t
+qla2x00_delay_lun(scsi_qla_host_t *, os_lun_t *, int);
+
+static __inline__ uint8_t
+qla2x00_suspend_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time, int count)
+{
+	return (__qla2x00_suspend_lun(ha, lq, time, count, 0));
+}
+
+static __inline__ uint8_t
+qla2x00_delay_lun(scsi_qla_host_t *ha, os_lun_t *lq, int time)
+{
+	return (__qla2x00_suspend_lun(ha, lq, time, 1, 1));
+}
+
+static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *);
+/*
+ * This routine will wait for fabric devices for
+ * the reset delay.
+ */
+static __inline__ void qla2x00_check_fabric_devices(scsi_qla_host_t *ha) 
+{
+	uint16_t	fw_state;
+
+	qla2x00_get_firmware_state(ha, &fw_state);
+}
+
+/**
+ * qla2x00_issue_marker() - Issue a Marker IOCB if necessary.
+ * @ha: HA context
+ * @ha_locked: is function called with the hardware lock
+ *
+ * Returns non-zero if a failure occured, else zero.
+ */
+static inline int
+qla2x00_issue_marker(scsi_qla_host_t *ha, int ha_locked)
+{
+	/* Send marker if required */
+	if (ha->marker_needed != 0) {
+		if (ha_locked) {
+			if (__qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) !=
+			    QLA_SUCCESS)
+				return (QLA_FUNCTION_FAILED);
+		} else {
+			if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) !=
+			    QLA_SUCCESS)
+				return (QLA_FUNCTION_FAILED);
+		}
+		ha->marker_needed = 0;
+	}
+	return (QLA_SUCCESS);
+}
+
+static __inline__ void qla2x00_add_timer_to_cmd(srb_t *, int);
+static __inline__ void qla2x00_delete_timer_from_cmd(srb_t *);
+
+/**************************************************************************
+*   qla2x00_add_timer_to_cmd
+*
+* Description:
+*       Creates a timer for the specified command. The timeout is usually
+*       the command time from kernel minus 2 secs.
+*
+* Input:
+*     sp - pointer to validate
+*
+* Returns:
+*     None.
+**************************************************************************/
+static inline void
+qla2x00_add_timer_to_cmd(srb_t *sp, int timeout)
+{
+	init_timer(&sp->timer);
+	sp->timer.expires = jiffies + timeout * HZ;
+	sp->timer.data = (unsigned long) sp;
+	sp->timer.function = (void (*) (unsigned long))qla2x00_cmd_timeout;
+	add_timer(&sp->timer);
+}
+
+/**************************************************************************
+*   qla2x00_delete_timer_from_cmd
+*
+* Description:
+*       Delete the timer for the specified command.
+*
+* Input:
+*     sp - pointer to validate
+*
+* Returns:
+*     None.
+**************************************************************************/
+static inline void 
+qla2x00_delete_timer_from_cmd(srb_t *sp)
+{
+	if (sp->timer.function != NULL) {
+		del_timer(&sp->timer);
+		sp->timer.function =  NULL;
+		sp->timer.data = (unsigned long) NULL;
+	}
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
new file mode 100644
index 0000000..ec06607
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -0,0 +1,633 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+#include "qla_def.h"
+
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_tcq.h>
+
+static inline uint16_t qla2x00_get_cmd_direction(struct scsi_cmnd *cmd);
+static inline cont_entry_t *qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *);
+static inline cont_a64_entry_t *qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *);
+static request_t *qla2x00_req_pkt(scsi_qla_host_t *ha);
+
+/**
+ * qla2x00_get_cmd_direction() - Determine control_flag data direction.
+ * @cmd: SCSI command
+ *
+ * Returns the proper CF_* direction based on CDB.
+ */
+static inline uint16_t
+qla2x00_get_cmd_direction(struct scsi_cmnd *cmd)
+{
+	uint16_t cflags;
+
+	cflags = 0;
+
+	/* Set transfer direction */
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		cflags = CF_WRITE;
+	else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+		cflags = CF_READ;
+	return (cflags);
+}
+
+/**
+ * qla2x00_calc_iocbs_32() - Determine number of Command Type 2 and
+ * Continuation Type 0 IOCBs to allocate.
+ *
+ * @dsds: number of data segment decriptors needed
+ *
+ * Returns the number of IOCB entries needed to store @dsds.
+ */
+uint16_t
+qla2x00_calc_iocbs_32(uint16_t dsds)
+{
+	uint16_t iocbs;
+
+	iocbs = 1;
+	if (dsds > 3) {
+		iocbs += (dsds - 3) / 7;
+		if ((dsds - 3) % 7)
+			iocbs++;
+	}
+	return (iocbs);
+}
+
+/**
+ * qla2x00_calc_iocbs_64() - Determine number of Command Type 3 and
+ * Continuation Type 1 IOCBs to allocate.
+ *
+ * @dsds: number of data segment decriptors needed
+ *
+ * Returns the number of IOCB entries needed to store @dsds.
+ */
+uint16_t
+qla2x00_calc_iocbs_64(uint16_t dsds)
+{
+	uint16_t iocbs;
+
+	iocbs = 1;
+	if (dsds > 2) {
+		iocbs += (dsds - 2) / 5;
+		if ((dsds - 2) % 5)
+			iocbs++;
+	}
+	return (iocbs);
+}
+
+/**
+ * qla2x00_prep_cont_type0_iocb() - Initialize a Continuation Type 0 IOCB.
+ * @ha: HA context
+ *
+ * Returns a pointer to the Continuation Type 0 IOCB packet.
+ */
+static inline cont_entry_t *
+qla2x00_prep_cont_type0_iocb(scsi_qla_host_t *ha)
+{
+	cont_entry_t *cont_pkt;
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == ha->request_q_length) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else {
+		ha->request_ring_ptr++;
+	}
+
+	cont_pkt = (cont_entry_t *)ha->request_ring_ptr;
+
+	/* Load packet defaults. */
+	*((uint32_t *)(&cont_pkt->entry_type)) =
+	    __constant_cpu_to_le32(CONTINUE_TYPE);
+
+	return (cont_pkt);
+}
+
+/**
+ * qla2x00_prep_cont_type1_iocb() - Initialize a Continuation Type 1 IOCB.
+ * @ha: HA context
+ *
+ * Returns a pointer to the continuation type 1 IOCB packet.
+ */
+static inline cont_a64_entry_t *
+qla2x00_prep_cont_type1_iocb(scsi_qla_host_t *ha)
+{
+	cont_a64_entry_t *cont_pkt;
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == ha->request_q_length) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else {
+		ha->request_ring_ptr++;
+	}
+
+	cont_pkt = (cont_a64_entry_t *)ha->request_ring_ptr;
+
+	/* Load packet defaults. */
+	*((uint32_t *)(&cont_pkt->entry_type)) =
+	    __constant_cpu_to_le32(CONTINUE_A64_TYPE);
+
+	return (cont_pkt);
+}
+
+/**
+ * qla2x00_build_scsi_iocbs_32() - Build IOCB command utilizing 32bit
+ * capable IOCB types.
+ *
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type 2 IOCB
+ * @tot_dsds: Total number of segments to transfer
+ */
+void qla2x00_build_scsi_iocbs_32(srb_t *sp, cmd_entry_t *cmd_pkt,
+    uint16_t tot_dsds)
+{
+	uint16_t	avail_dsds;
+	uint32_t	*cur_dsd;
+	scsi_qla_host_t	*ha;
+	struct scsi_cmnd *cmd;
+
+	cmd = sp->cmd;
+
+	/* Update entry type to indicate Command Type 2 IOCB */
+	*((uint32_t *)(&cmd_pkt->entry_type)) =
+	    __constant_cpu_to_le32(COMMAND_TYPE);
+
+	/* No data transfer */
+	if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+		cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+		return;
+	}
+
+	ha = sp->ha;
+
+	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+
+	/* Three DSDs are available in the Command Type 2 IOCB */
+	avail_dsds = 3;
+	cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
+
+	/* Load data segments */
+	if (cmd->use_sg != 0) {
+		struct	scatterlist *cur_seg;
+		struct	scatterlist *end_seg;
+
+		cur_seg = (struct scatterlist *)cmd->request_buffer;
+		end_seg = cur_seg + tot_dsds;
+		while (cur_seg < end_seg) {
+			cont_entry_t	*cont_pkt;
+
+			/* Allocate additional continuation packets? */
+			if (avail_dsds == 0) {
+				/*
+				 * Seven DSDs are available in the Continuation
+				 * Type 0 IOCB.
+				 */
+				cont_pkt = qla2x00_prep_cont_type0_iocb(ha);
+				cur_dsd = (uint32_t *)&cont_pkt->dseg_0_address;
+				avail_dsds = 7;
+			}
+
+			*cur_dsd++ = cpu_to_le32(sg_dma_address(cur_seg));
+			*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
+			avail_dsds--;
+
+			cur_seg++;
+		}
+	} else {
+		dma_addr_t	req_dma;
+		struct page	*page;
+		unsigned long	offset;
+
+		page = virt_to_page(cmd->request_buffer);
+		offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
+		req_dma = pci_map_page(ha->pdev, page, offset,
+		    cmd->request_bufflen, cmd->sc_data_direction);
+
+		sp->dma_handle = req_dma;
+
+		*cur_dsd++ = cpu_to_le32(req_dma);
+		*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+	}
+}
+
+/**
+ * qla2x00_build_scsi_iocbs_64() - Build IOCB command utilizing 64bit
+ * capable IOCB types.
+ *
+ * @sp: SRB command to process
+ * @cmd_pkt: Command type 3 IOCB
+ * @tot_dsds: Total number of segments to transfer
+ */
+void qla2x00_build_scsi_iocbs_64(srb_t *sp, cmd_entry_t *cmd_pkt,
+    uint16_t tot_dsds)
+{
+	uint16_t	avail_dsds;
+	uint32_t	*cur_dsd;
+	scsi_qla_host_t	*ha;
+	struct scsi_cmnd *cmd;
+
+	cmd = sp->cmd;
+
+	/* Update entry type to indicate Command Type 3 IOCB */
+	*((uint32_t *)(&cmd_pkt->entry_type)) =
+	    __constant_cpu_to_le32(COMMAND_A64_TYPE);
+
+	/* No data transfer */
+	if (cmd->request_bufflen == 0 || cmd->sc_data_direction == DMA_NONE) {
+		cmd_pkt->byte_count = __constant_cpu_to_le32(0);
+		return;
+	}
+
+	ha = sp->ha;
+
+	cmd_pkt->control_flags |= cpu_to_le16(qla2x00_get_cmd_direction(cmd));
+
+	/* Two DSDs are available in the Command Type 3 IOCB */
+	avail_dsds = 2;
+	cur_dsd = (uint32_t *)&cmd_pkt->dseg_0_address;
+
+	/* Load data segments */
+	if (cmd->use_sg != 0) {
+		struct	scatterlist *cur_seg;
+		struct	scatterlist *end_seg;
+
+		cur_seg = (struct scatterlist *)cmd->request_buffer;
+		end_seg = cur_seg + tot_dsds;
+		while (cur_seg < end_seg) {
+			dma_addr_t	sle_dma;
+			cont_a64_entry_t *cont_pkt;
+
+			/* Allocate additional continuation packets? */
+			if (avail_dsds == 0) {
+				/*
+				 * Five DSDs are available in the Continuation
+				 * Type 1 IOCB.
+				 */
+				cont_pkt = qla2x00_prep_cont_type1_iocb(ha);
+				cur_dsd = (uint32_t *)cont_pkt->dseg_0_address;
+				avail_dsds = 5;
+			}
+
+			sle_dma = sg_dma_address(cur_seg);
+			*cur_dsd++ = cpu_to_le32(LSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(MSD(sle_dma));
+			*cur_dsd++ = cpu_to_le32(sg_dma_len(cur_seg));
+			avail_dsds--;
+
+			cur_seg++;
+		}
+	} else {
+		dma_addr_t	req_dma;
+		struct page	*page;
+		unsigned long	offset;
+
+		page = virt_to_page(cmd->request_buffer);
+		offset = ((unsigned long)cmd->request_buffer & ~PAGE_MASK);
+		req_dma = pci_map_page(ha->pdev, page, offset,
+		    cmd->request_bufflen, cmd->sc_data_direction);
+
+		sp->dma_handle = req_dma;
+
+		*cur_dsd++ = cpu_to_le32(LSD(req_dma));
+		*cur_dsd++ = cpu_to_le32(MSD(req_dma));
+		*cur_dsd++ = cpu_to_le32(cmd->request_bufflen);
+	}
+}
+
+/**
+ * qla2x00_start_scsi() - Send a SCSI command to the ISP
+ * @sp: command to send to the ISP
+ *
+ * Returns non-zero if a failure occured, else zero.
+ */
+int
+qla2x00_start_scsi(srb_t *sp)
+{
+	int		ret;
+	unsigned long   flags;
+	scsi_qla_host_t	*ha;
+	fc_lun_t	*fclun;
+	struct scsi_cmnd *cmd;
+	uint32_t	*clr_ptr;
+	uint32_t        index;
+	uint32_t	handle;
+	cmd_entry_t	*cmd_pkt;
+	uint32_t        timeout;
+	struct scatterlist *sg;
+	uint16_t	cnt;
+	uint16_t	req_cnt;
+	uint16_t	tot_dsds;
+	device_reg_t __iomem *reg;
+	char		tag[2];
+
+	/* Setup device pointers. */
+	ret = 0;
+	fclun = sp->lun_queue->fclun;
+	ha = fclun->fcport->ha;
+	reg = ha->iobase;
+	cmd = sp->cmd;
+
+	/* Send marker if required */
+	if (ha->marker_needed != 0) {
+		if (qla2x00_marker(ha, 0, 0, MK_SYNC_ALL) != QLA_SUCCESS) {
+			return (QLA_FUNCTION_FAILED);
+		}
+		ha->marker_needed = 0;
+	}
+
+	/* Acquire ring specific lock */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Check for room in outstanding command list. */
+	handle = ha->current_outstanding_cmd;
+	for (index = 1; index < MAX_OUTSTANDING_COMMANDS; index++) {
+		handle++;
+		if (handle == MAX_OUTSTANDING_COMMANDS)
+			handle = 1;
+		if (ha->outstanding_cmds[handle] == 0)
+			break;
+	}
+	if (index == MAX_OUTSTANDING_COMMANDS)
+		goto queuing_error;
+
+	/* Calculate the number of request entries needed. */
+	req_cnt = (ha->calc_request_entries)(cmd->request->nr_hw_segments);
+	if (ha->req_q_cnt < (req_cnt + 2)) {
+		cnt = RD_REG_WORD_RELAXED(ISP_REQ_Q_OUT(ha, reg));
+		if (ha->req_ring_index < cnt)
+			ha->req_q_cnt = cnt - ha->req_ring_index;
+		else
+			ha->req_q_cnt = ha->request_q_length -
+			    (ha->req_ring_index - cnt);
+	}
+	if (ha->req_q_cnt < (req_cnt + 2))
+		goto queuing_error;
+
+	/* Finally, we have enough space, now perform mappings. */
+	tot_dsds = 0;
+	if (cmd->use_sg) {
+		sg = (struct scatterlist *) cmd->request_buffer;
+		tot_dsds = pci_map_sg(ha->pdev, sg, cmd->use_sg,
+		    cmd->sc_data_direction);
+		if (tot_dsds == 0)
+			goto queuing_error;
+	} else if (cmd->request_bufflen) {
+	    tot_dsds++;
+	}
+	req_cnt = (ha->calc_request_entries)(tot_dsds);
+
+	/* Build command packet */
+	ha->current_outstanding_cmd = handle;
+	ha->outstanding_cmds[handle] = sp;
+	sp->ha = ha;
+	sp->cmd->host_scribble = (unsigned char *)(unsigned long)handle;
+	ha->req_q_cnt -= req_cnt;
+
+	cmd_pkt = (cmd_entry_t *)ha->request_ring_ptr;
+	cmd_pkt->handle = handle;
+	/* Zero out remaining portion of packet. */
+	clr_ptr = (uint32_t *)cmd_pkt + 2;
+	memset(clr_ptr, 0, REQUEST_ENTRY_SIZE - 8);
+	cmd_pkt->dseg_count = cpu_to_le16(tot_dsds);
+
+	/* Set target ID */
+	SET_TARGET_ID(ha, cmd_pkt->target, fclun->fcport->loop_id);
+
+	/* Set LUN number*/
+	cmd_pkt->lun = cpu_to_le16(fclun->lun);
+
+	/* Update tagged queuing modifier */
+	cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
+	if (scsi_populate_tag_msg(cmd, tag)) {
+		switch (tag[0]) {
+		case MSG_HEAD_TAG:
+			cmd_pkt->control_flags =
+			    __constant_cpu_to_le16(CF_HEAD_TAG);
+			break;
+		case MSG_ORDERED_TAG:
+			cmd_pkt->control_flags =
+			    __constant_cpu_to_le16(CF_ORDERED_TAG);
+			break;
+		}
+	}
+
+	/*
+	 * Allocate at least 5 (+ QLA_CMD_TIMER_DELTA) seconds for RISC timeout.
+	 */
+	timeout = (uint32_t)(cmd->timeout_per_command / HZ);
+	if (timeout > 65535)
+		cmd_pkt->timeout = __constant_cpu_to_le16(0);
+	else if (timeout > 25)
+		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout -
+		    (5 + QLA_CMD_TIMER_DELTA));
+	else
+		cmd_pkt->timeout = cpu_to_le16((uint16_t)timeout);
+
+	/* Load SCSI command packet. */
+	memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
+	cmd_pkt->byte_count = cpu_to_le32((uint32_t)cmd->request_bufflen);
+
+	/* Build IOCB segments */
+	(ha->build_scsi_iocbs)(sp, cmd_pkt, tot_dsds);
+
+	/* Set total data segment count. */
+	cmd_pkt->entry_count = (uint8_t)req_cnt;
+	wmb();
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == ha->request_q_length) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else
+		ha->request_ring_ptr++;
+
+	ha->actthreads++;
+	ha->total_ios++;
+	sp->lun_queue->out_cnt++;
+	sp->flags |= SRB_DMA_VALID;
+	sp->state = SRB_ACTIVE_STATE;
+	sp->u_start = jiffies;
+
+	/* Set chip new ring index. */
+	WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
+	RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */
+
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+	return (QLA_SUCCESS);
+
+queuing_error:
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (QLA_FUNCTION_FAILED);
+}
+
+/**
+ * qla2x00_marker() - Send a marker IOCB to the firmware.
+ * @ha: HA context
+ * @loop_id: loop ID
+ * @lun: LUN
+ * @type: marker modifier
+ *
+ * Can be called from both normal and interrupt context.
+ *
+ * Returns non-zero if a failure occured, else zero.
+ */
+int
+__qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
+    uint8_t type)
+{
+	mrk_entry_t	*pkt;
+
+	pkt = (mrk_entry_t *)qla2x00_req_pkt(ha);
+	if (pkt == NULL) {
+		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+
+		return (QLA_FUNCTION_FAILED);
+	}
+
+	pkt->entry_type = MARKER_TYPE;
+	pkt->modifier = type;
+
+	if (type != MK_SYNC_ALL) {
+		pkt->lun = cpu_to_le16(lun);
+		SET_TARGET_ID(ha, pkt->target, loop_id);
+	}
+	wmb();
+
+	/* Issue command to ISP */
+	qla2x00_isp_cmd(ha);
+
+	return (QLA_SUCCESS);
+}
+
+int 
+qla2x00_marker(scsi_qla_host_t *ha, uint16_t loop_id, uint16_t lun,
+    uint8_t type)
+{
+	int ret;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	ret = __qla2x00_marker(ha, loop_id, lun, type);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (ret);
+}
+
+/**
+ * qla2x00_req_pkt() - Retrieve a request packet from the request ring.
+ * @ha: HA context
+ *
+ * Note: The caller must hold the hardware lock before calling this routine.
+ *
+ * Returns NULL if function failed, else, a pointer to the request packet.
+ */
+static request_t *
+qla2x00_req_pkt(scsi_qla_host_t *ha)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+	request_t	*pkt = NULL;
+	uint16_t	cnt;
+	uint32_t	*dword_ptr;
+	uint32_t	timer;
+	uint16_t	req_cnt = 1;
+
+	/* Wait 1 second for slot. */
+	for (timer = HZ; timer; timer--) {
+		if ((req_cnt + 2) >= ha->req_q_cnt) {
+			/* Calculate number of free request entries. */
+			cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg));
+			if  (ha->req_ring_index < cnt)
+				ha->req_q_cnt = cnt - ha->req_ring_index;
+			else
+				ha->req_q_cnt = ha->request_q_length -
+				    (ha->req_ring_index - cnt);
+		}
+		/* If room for request in request ring. */
+		if ((req_cnt + 2) < ha->req_q_cnt) {
+			ha->req_q_cnt--;
+			pkt = ha->request_ring_ptr;
+
+			/* Zero out packet. */
+			dword_ptr = (uint32_t *)pkt;
+			for (cnt = 0; cnt < REQUEST_ENTRY_SIZE / 4; cnt++)
+				*dword_ptr++ = 0;
+
+			/* Set system defined field. */
+			pkt->sys_define = (uint8_t)ha->req_ring_index;
+
+			/* Set entry count. */
+			pkt->entry_count = 1;
+
+			break;
+		}
+
+		/* Release ring specific lock */
+		spin_unlock(&ha->hardware_lock);
+
+		udelay(2);   /* 2 us */
+
+		/* Check for pending interrupts. */
+		/* During init we issue marker directly */
+		if (!ha->marker_needed)
+			qla2x00_poll(ha);
+
+		spin_lock_irq(&ha->hardware_lock);
+	}
+	if (!pkt) {
+		DEBUG2_3(printk("%s(): **** FAILED ****\n", __func__));
+	}
+
+	return (pkt);
+}
+
+/**
+ * qla2x00_isp_cmd() - Modify the request ring pointer.
+ * @ha: HA context
+ *
+ * Note: The caller must hold the hardware lock before calling this routine.
+ */
+void
+qla2x00_isp_cmd(scsi_qla_host_t *ha)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+
+	DEBUG5(printk("%s(): IOCB data:\n", __func__));
+	DEBUG5(qla2x00_dump_buffer(
+	    (uint8_t *)ha->request_ring_ptr, REQUEST_ENTRY_SIZE));
+
+	/* Adjust ring index. */
+	ha->req_ring_index++;
+	if (ha->req_ring_index == ha->request_q_length) {
+		ha->req_ring_index = 0;
+		ha->request_ring_ptr = ha->request_ring;
+	} else
+		ha->request_ring_ptr++;
+
+	/* Set chip new ring index. */
+	WRT_REG_WORD(ISP_REQ_Q_IN(ha, reg), ha->req_ring_index);
+	RD_REG_WORD_RELAXED(ISP_REQ_Q_IN(ha, reg));	/* PCI Posting. */
+}
diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c
new file mode 100644
index 0000000..603d4c6
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_isr.c
@@ -0,0 +1,1464 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+static void qla2x00_mbx_completion(scsi_qla_host_t *, uint16_t);
+static void qla2x00_async_event(scsi_qla_host_t *, uint32_t);
+static void qla2x00_process_completed_request(struct scsi_qla_host *, uint32_t);
+void qla2x00_process_response_queue(struct scsi_qla_host *);
+static void qla2x00_status_entry(scsi_qla_host_t *, sts_entry_t *);
+static void qla2x00_status_cont_entry(scsi_qla_host_t *, sts_cont_entry_t *);
+static void qla2x00_error_entry(scsi_qla_host_t *, sts_entry_t *);
+static void qla2x00_ms_entry(scsi_qla_host_t *, ms_iocb_entry_t *);
+
+static int qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *);
+
+/**
+ * qla2100_intr_handler() - Process interrupts for the ISP2100 and ISP2200.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qla2100_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	scsi_qla_host_t	*ha;
+	device_reg_t __iomem *reg;
+	int		status;
+	unsigned long	flags;
+	unsigned long	iter;
+	uint32_t	mbx;
+
+	ha = (scsi_qla_host_t *) dev_id;
+	if (!ha) {
+		printk(KERN_INFO
+		    "%s(): NULL host pointer\n", __func__);
+		return (IRQ_NONE);
+	}
+
+	reg = ha->iobase;
+	status = 0;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (iter = 50; iter--; ) {
+		if ((RD_REG_WORD(&reg->istatus) & ISR_RISC_INT) == 0)
+			break;
+
+		if (RD_REG_WORD(&reg->semaphore) & BIT_0) {
+			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+			RD_REG_WORD(&reg->hccr);
+
+			/* Get mailbox data. */
+			mbx = RD_MAILBOX_REG(ha, reg, 0);
+			if (mbx > 0x3fff && mbx < 0x8000) {
+				qla2x00_mbx_completion(ha, (uint16_t)mbx);
+				status |= MBX_INTERRUPT;
+			} else if (mbx > 0x7fff && mbx < 0xc000) {
+				qla2x00_async_event(ha, mbx);
+			} else {
+				/*EMPTY*/
+				DEBUG2(printk("scsi(%ld): Unrecognized "
+				    "interrupt type (%d)\n",
+				    ha->host_no, mbx));
+			}
+			/* Release mailbox registers. */
+			WRT_REG_WORD(&reg->semaphore, 0);
+			RD_REG_WORD(&reg->semaphore);
+		} else {
+			qla2x00_process_response_queue(ha);
+
+			WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+			RD_REG_WORD(&reg->hccr);
+		}
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	qla2x00_next(ha);
+	ha->last_irq_cpu = _smp_processor_id();
+	ha->total_isr_cnt++;
+
+	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+		spin_lock_irqsave(&ha->mbx_reg_lock, flags);
+
+		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+		up(&ha->mbx_intr_sem);
+
+		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
+	}
+
+	if (!list_empty(&ha->done_queue))
+		qla2x00_done(ha);
+
+	return (IRQ_HANDLED);
+}
+
+/**
+ * qla2300_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
+ * @irq:
+ * @dev_id: SCSI driver HA context
+ * @regs:
+ *
+ * Called by system whenever the host adapter generates an interrupt.
+ *
+ * Returns handled flag.
+ */
+irqreturn_t
+qla2300_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	scsi_qla_host_t	*ha;
+	device_reg_t __iomem *reg;
+	int		status;
+	unsigned long	flags;
+	unsigned long	iter;
+	uint32_t	stat;
+	uint32_t	mbx;
+	uint16_t	hccr;
+
+	ha = (scsi_qla_host_t *) dev_id;
+	if (!ha) {
+		printk(KERN_INFO
+		    "%s(): NULL host pointer\n", __func__);
+		return (IRQ_NONE);
+	}
+
+	reg = ha->iobase;
+	status = 0;
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (iter = 50; iter--; ) {
+		stat = RD_REG_DWORD(&reg->u.isp2300.host_status);
+		if (stat & HSR_RISC_PAUSED) {
+			hccr = RD_REG_WORD(&reg->hccr);
+			if (hccr & (BIT_15 | BIT_13 | BIT_11 | BIT_8))
+				qla_printk(KERN_INFO, ha,
+				    "Parity error -- HCCR=%x.\n", hccr);
+			else
+				qla_printk(KERN_INFO, ha,
+				    "RISC paused -- HCCR=%x\n", hccr);
+
+			/*
+			 * Issue a "HARD" reset in order for the RISC
+			 * interrupt bit to be cleared.  Schedule a big
+			 * hammmer to get out of the RISC PAUSED state.
+			 */
+			WRT_REG_WORD(&reg->hccr, HCCR_RESET_RISC);
+			RD_REG_WORD(&reg->hccr);
+			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			break;
+		} else if ((stat & HSR_RISC_INT) == 0)
+			break;
+
+		mbx = MSW(stat);
+		switch (stat & 0xff) {
+		case 0x13:
+			qla2x00_process_response_queue(ha);
+			break;
+		case 0x1:
+		case 0x2:
+		case 0x10:
+		case 0x11:
+			qla2x00_mbx_completion(ha, (uint16_t)mbx);
+			status |= MBX_INTERRUPT;
+
+			/* Release mailbox registers. */
+			WRT_REG_WORD(&reg->semaphore, 0);
+			break;
+		case 0x12:
+			qla2x00_async_event(ha, mbx);
+			break;
+		case 0x15:
+			mbx = mbx << 16 | MBA_CMPLT_1_16BIT;
+			qla2x00_async_event(ha, mbx);
+			break;
+		case 0x16:
+			mbx = mbx << 16 | MBA_SCSI_COMPLETION;
+			qla2x00_async_event(ha, mbx);
+			break;
+		default:
+			DEBUG2(printk("scsi(%ld): Unrecognized interrupt type "
+			    "(%d)\n",
+			    ha->host_no, stat & 0xff));
+			break;
+		}
+		WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+		RD_REG_WORD_RELAXED(&reg->hccr);
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	qla2x00_next(ha);
+	ha->last_irq_cpu = _smp_processor_id();
+	ha->total_isr_cnt++;
+
+	if (test_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags) &&
+	    (status & MBX_INTERRUPT) && ha->flags.mbox_int) {
+		spin_lock_irqsave(&ha->mbx_reg_lock, flags);
+
+		set_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+		up(&ha->mbx_intr_sem);
+
+		spin_unlock_irqrestore(&ha->mbx_reg_lock, flags);
+	}
+
+	if (!list_empty(&ha->done_queue))
+		qla2x00_done(ha);
+
+	return (IRQ_HANDLED);
+}
+
+/**
+ * qla2x00_mbx_completion() - Process mailbox command completions.
+ * @ha: SCSI driver HA context
+ * @mb0: Mailbox0 register
+ */
+static void
+qla2x00_mbx_completion(scsi_qla_host_t *ha, uint16_t mb0)
+{
+	uint16_t	cnt;
+	uint16_t __iomem *wptr;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	/* Load return mailbox registers. */
+	ha->flags.mbox_int = 1;
+	ha->mailbox_out[0] = mb0;
+	wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 1);
+
+	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
+		if (IS_QLA2200(ha) && cnt == 8) 
+			wptr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
+		if (cnt == 4 || cnt == 5)
+			ha->mailbox_out[cnt] = qla2x00_debounce_register(wptr);
+		else
+			ha->mailbox_out[cnt] = RD_REG_WORD(wptr);
+	
+		wptr++;
+	}
+
+	if (ha->mcp) {
+		DEBUG3(printk("%s(%ld): Got mailbox completion. cmd=%x.\n",
+		    __func__, ha->host_no, ha->mcp->mb[0]));
+	} else {
+		DEBUG2_3(printk("%s(%ld): MBX pointer ERROR!\n",
+		    __func__, ha->host_no));
+	}
+}
+
+/**
+ * qla2x00_async_event() - Process aynchronous events.
+ * @ha: SCSI driver HA context
+ * @mb0: Mailbox0 register
+ */
+static void
+qla2x00_async_event(scsi_qla_host_t *ha, uint32_t mbx)
+{
+	static char	*link_speeds[5] = { "1", "2", "4", "?", "10" };
+	char		*link_speed;
+	uint16_t	mb[4];
+	uint16_t	handle_cnt;
+	uint16_t	cnt;
+	uint32_t	handles[5];
+	device_reg_t __iomem *reg = ha->iobase;
+	uint32_t	rscn_entry, host_pid;
+	uint8_t		rscn_queue_index;
+
+	/* Setup to process RIO completion. */
+	handle_cnt = 0;
+	mb[0] = LSW(mbx);
+	switch (mb[0]) {
+	case MBA_SCSI_COMPLETION:
+		if (IS_QLA2100(ha) || IS_QLA2200(ha))
+			handles[0] = le32_to_cpu(
+			    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |
+			    RD_MAILBOX_REG(ha, reg, 1));
+		else
+			handles[0] = le32_to_cpu(
+			    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |
+			    MSW(mbx));
+		handle_cnt = 1;
+		break;
+	case MBA_CMPLT_1_16BIT:
+		if (IS_QLA2100(ha) || IS_QLA2200(ha))
+			handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);
+		else
+			handles[0] = MSW(mbx);
+		handle_cnt = 1;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	case MBA_CMPLT_2_16BIT:
+		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);
+		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);
+		handle_cnt = 2;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	case MBA_CMPLT_3_16BIT:
+		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);
+		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);
+		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);
+		handle_cnt = 3;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	case MBA_CMPLT_4_16BIT:
+		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);
+		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);
+		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);
+		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
+		handle_cnt = 4;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	case MBA_CMPLT_5_16BIT:
+		handles[0] = (uint32_t)RD_MAILBOX_REG(ha, reg, 1);
+		handles[1] = (uint32_t)RD_MAILBOX_REG(ha, reg, 2);
+		handles[2] = (uint32_t)RD_MAILBOX_REG(ha, reg, 3);
+		handles[3] = (uint32_t)RD_MAILBOX_REG(ha, reg, 6);
+		handles[4] = (uint32_t)RD_MAILBOX_REG(ha, reg, 7);
+		handle_cnt = 5;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	case MBA_CMPLT_2_32BIT:
+		handles[0] = le32_to_cpu(
+		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 2) << 16)) |
+		    RD_MAILBOX_REG(ha, reg, 1));
+		handles[1] = le32_to_cpu(
+		    ((uint32_t)(RD_MAILBOX_REG(ha, reg, 7) << 16)) |
+		    RD_MAILBOX_REG(ha, reg, 6));
+		handle_cnt = 2;
+		mb[0] = MBA_SCSI_COMPLETION;
+		break;
+	default:
+		break;
+	}
+
+	switch (mb[0]) {
+	case MBA_SCSI_COMPLETION:	/* Fast Post */
+		if (!ha->flags.online)
+			break;
+
+		for (cnt = 0; cnt < handle_cnt; cnt++)
+			qla2x00_process_completed_request(ha, handles[cnt]);
+		break;
+
+	case MBA_RESET:			/* Reset */
+		DEBUG2(printk("scsi(%ld): Asynchronous RESET.\n", ha->host_no));
+
+		set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+		break;
+
+	case MBA_SYSTEM_ERR:		/* System Error */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
+		mb[3] = RD_MAILBOX_REG(ha, reg, 3);
+
+		qla_printk(KERN_INFO, ha,
+		    "ISP System Error - mbx1=%xh mbx2=%xh mbx3=%xh.\n",
+		    mb[1], mb[2], mb[3]);
+
+		if (IS_QLA2100(ha) || IS_QLA2200(ha))
+			qla2100_fw_dump(ha, 1);
+		else
+	    		qla2300_fw_dump(ha, 1);
+
+		if (mb[1] == 0) {
+			qla_printk(KERN_INFO, ha,
+			    "Unrecoverable Hardware Error: adapter marked "
+			    "OFFLINE!\n");
+			ha->flags.online = 0;
+		} else
+			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		break;
+
+	case MBA_REQ_TRANSFER_ERR:	/* Request Transfer Error */
+		DEBUG2(printk("scsi(%ld): ISP Request Transfer Error.\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha, "ISP Request Transfer Error.\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		break;
+
+	case MBA_RSP_TRANSFER_ERR:	/* Response Transfer Error */
+		DEBUG2(printk("scsi(%ld): ISP Response Transfer Error.\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha, "ISP Response Transfer Error.\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		break;
+
+	case MBA_WAKEUP_THRES:		/* Request Queue Wake-up */
+		DEBUG2(printk("scsi(%ld): Asynchronous WAKEUP_THRES.\n",
+		    ha->host_no));
+		break;
+
+	case MBA_LIP_OCCURRED:		/* Loop Initialization Procedure */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+
+		DEBUG2(printk("scsi(%ld): LIP occured (%x).\n", ha->host_no,
+		    mb[1]));
+		qla_printk(KERN_INFO, ha, "LIP occured (%x).\n", mb[1]);
+
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);
+			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+			qla2x00_mark_all_devices_lost(ha);
+		}
+
+		set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+
+		ha->flags.management_server_logged_in = 0;
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_LIP_OCCURRED, NULL);
+
+		ha->total_lip_cnt++;
+		break;
+
+	case MBA_LOOP_UP:		/* Loop Up Event */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+
+		ha->link_data_rate = 0;
+		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+			link_speed = link_speeds[0];
+		} else {
+			link_speed = link_speeds[3];
+			if (mb[1] < 5)
+				link_speed = link_speeds[mb[1]];
+			ha->link_data_rate = mb[1];
+		}
+
+		DEBUG2(printk("scsi(%ld): Asynchronous LOOP UP (%s Gbps).\n",
+		    ha->host_no, link_speed));
+		qla_printk(KERN_INFO, ha, "LOOP UP detected (%s Gbps).\n",
+		    link_speed);
+
+		ha->flags.management_server_logged_in = 0;
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_LOOP_UP, NULL);
+		break;
+
+	case MBA_LOOP_DOWN:		/* Loop Down Event */
+		DEBUG2(printk("scsi(%ld): Asynchronous LOOP DOWN.\n",
+		    ha->host_no));
+		qla_printk(KERN_INFO, ha, "LOOP DOWN detected.\n");
+
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);
+			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+			ha->device_flags |= DFLG_NO_CABLE;
+			qla2x00_mark_all_devices_lost(ha);
+		}
+
+		ha->flags.management_server_logged_in = 0;
+		ha->link_data_rate = 0;
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_LOOP_DOWN, NULL);
+		break;
+
+	case MBA_LIP_RESET:		/* LIP reset occurred */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+
+		DEBUG2(printk("scsi(%ld): Asynchronous LIP RESET (%x).\n",
+		    ha->host_no, mb[1]));
+		qla_printk(KERN_INFO, ha,
+		    "LIP reset occured (%x).\n", mb[1]);
+
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);
+			atomic_set(&ha->loop_down_timer, LOOP_DOWN_TIME);
+			qla2x00_mark_all_devices_lost(ha);
+		}
+
+		set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+
+		ha->operating_mode = LOOP;
+		ha->flags.management_server_logged_in = 0;
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_LIP_RESET, NULL);
+
+		ha->total_lip_cnt++;
+		break;
+
+	case MBA_POINT_TO_POINT:	/* Point-to-Point */
+		if (IS_QLA2100(ha))
+			break;
+
+		DEBUG2(printk("scsi(%ld): Asynchronous P2P MODE received.\n",
+		    ha->host_no));
+
+		/*
+		 * Until there's a transition from loop down to loop up, treat
+		 * this as loop down only.
+		 */
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);
+			if (!atomic_read(&ha->loop_down_timer))
+				atomic_set(&ha->loop_down_timer,
+				    LOOP_DOWN_TIME);
+			qla2x00_mark_all_devices_lost(ha);
+		}
+
+		if (!(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
+			set_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+		}
+		set_bit(REGISTER_FC4_NEEDED, &ha->dpc_flags);
+		break;
+
+	case MBA_CHG_IN_CONNECTION:	/* Change in connection mode */
+		if (IS_QLA2100(ha))
+			break;
+
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+
+		DEBUG2(printk("scsi(%ld): Asynchronous Change In Connection "
+		    "received.\n",
+		    ha->host_no));
+		qla_printk(KERN_INFO, ha,
+		    "Configuration change detected: value=%x.\n", mb[1]);
+
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN) {
+			atomic_set(&ha->loop_state, LOOP_DOWN);  
+			if (!atomic_read(&ha->loop_down_timer))
+				atomic_set(&ha->loop_down_timer,
+				    LOOP_DOWN_TIME);
+			qla2x00_mark_all_devices_lost(ha);
+		}
+
+		set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+		set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+		break;
+
+	case MBA_PORT_UPDATE:		/* Port database update */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
+
+		/*
+		 * If a single remote port just logged into (or logged out of)
+		 * us, create a new entry in our rscn fcports list and handle
+		 * the event like an RSCN.
+		 */
+		if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA6312(ha) &&
+		    !IS_QLA6322(ha) && ha->flags.init_done && mb[1] != 0xffff &&
+		    ((ha->operating_mode == P2P && mb[1] != 0) ||
+		    (ha->operating_mode != P2P && mb[1] !=
+			SNS_FIRST_LOOP_ID)) && (mb[2] == 6 || mb[2] == 7)) {
+			int rval;
+			fc_port_t *rscn_fcport;
+
+			/* Create new fcport for login. */
+			rscn_fcport = qla2x00_alloc_rscn_fcport(ha, GFP_ATOMIC);
+			if (rscn_fcport) {
+				DEBUG14(printk("scsi(%ld): Port Update -- "
+				    "creating RSCN fcport %p for %x/%x.\n",
+				    ha->host_no, rscn_fcport, mb[1], mb[2]));
+
+				rscn_fcport->loop_id = mb[1];
+				rscn_fcport->d_id.b24 = INVALID_PORT_ID;
+				atomic_set(&rscn_fcport->state,
+				    FCS_DEVICE_LOST);
+				list_add_tail(&rscn_fcport->list,
+				    &ha->rscn_fcports);
+
+				rval = qla2x00_handle_port_rscn(ha, 0,
+				    rscn_fcport, 1);
+				if (rval == QLA_SUCCESS)
+					break;
+			} else {
+				DEBUG14(printk("scsi(%ld): Port Update -- "
+				    "-- unable to allocate RSCN fcport "
+				    "login.\n", ha->host_no));
+			}
+		}
+
+		/*
+		 * If PORT UPDATE is global (recieved LIP_OCCURED/LIP_RESET
+		 * event etc. earlier indicating loop is down) then process
+		 * it.  Otherwise ignore it and Wait for RSCN to come in.
+		 */
+		atomic_set(&ha->loop_down_timer, 0);
+		if (atomic_read(&ha->loop_state) != LOOP_DOWN &&
+		    atomic_read(&ha->loop_state) != LOOP_DEAD) {
+			DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE "
+			    "ignored.\n", ha->host_no));
+			break;
+		}
+
+		DEBUG2(printk("scsi(%ld): Asynchronous PORT UPDATE.\n",
+		    ha->host_no));
+		DEBUG(printk(KERN_INFO
+		    "scsi(%ld): Port database changed %04x %04x.\n",
+		    ha->host_no, mb[1], mb[2]));
+
+		/*
+		 * Mark all devices as missing so we will login again.
+		 */
+		atomic_set(&ha->loop_state, LOOP_UP);
+
+		qla2x00_mark_all_devices_lost(ha);
+
+		ha->flags.rscn_queue_overflow = 1;
+
+		set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+		set_bit(LOCAL_LOOP_UPDATE, &ha->dpc_flags);
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_PORT_UPDATE, NULL);
+		break;
+
+	case MBA_RSCN_UPDATE:		/* State Change Registration */
+		mb[1] = RD_MAILBOX_REG(ha, reg, 1);
+		mb[2] = RD_MAILBOX_REG(ha, reg, 2);
+
+		DEBUG2(printk("scsi(%ld): Asynchronous RSCR UPDATE.\n",
+		    ha->host_no));
+		DEBUG(printk(KERN_INFO
+		    "scsi(%ld): RSCN database changed -- %04x %04x.\n",
+		    ha->host_no, mb[1], mb[2]));
+
+		rscn_entry = (mb[1] << 16) | mb[2];
+		host_pid = (ha->d_id.b.domain << 16) | (ha->d_id.b.area << 8) |
+		    ha->d_id.b.al_pa;
+		if (rscn_entry == host_pid) {
+			DEBUG(printk(KERN_INFO
+			    "scsi(%ld): Ignoring RSCN update to local host "
+			    "port ID (%06x)\n",
+			    ha->host_no, host_pid));
+			break;
+		}
+
+		rscn_queue_index = ha->rscn_in_ptr + 1;
+		if (rscn_queue_index == MAX_RSCN_COUNT)
+			rscn_queue_index = 0;
+		if (rscn_queue_index != ha->rscn_out_ptr) {
+			ha->rscn_queue[ha->rscn_in_ptr] = rscn_entry;
+			ha->rscn_in_ptr = rscn_queue_index;
+		} else {
+			ha->flags.rscn_queue_overflow = 1;
+		}
+
+		atomic_set(&ha->loop_state, LOOP_UPDATE);
+		atomic_set(&ha->loop_down_timer, 0);
+		ha->flags.management_server_logged_in = 0;
+
+		set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+		set_bit(RSCN_UPDATE, &ha->dpc_flags);
+
+		/* Update AEN queue. */
+		qla2x00_enqueue_aen(ha, MBA_RSCN_UPDATE, &mb[0]);
+		break;
+
+	/* case MBA_RIO_RESPONSE: */
+	case MBA_ZIO_RESPONSE:
+		DEBUG2(printk("scsi(%ld): [R|Z]IO update completion.\n",
+		    ha->host_no));
+		DEBUG(printk(KERN_INFO
+		    "scsi(%ld): [R|Z]IO update completion.\n",
+		    ha->host_no));
+
+		qla2x00_process_response_queue(ha);
+		break;
+	}
+}
+
+/**
+ * qla2x00_process_completed_request() - Process a Fast Post response.
+ * @ha: SCSI driver HA context
+ * @index: SRB index
+ */
+static void
+qla2x00_process_completed_request(struct scsi_qla_host *ha, uint32_t index)
+{
+	srb_t *sp;
+
+	/* Validate handle. */
+	if (index >= MAX_OUTSTANDING_COMMANDS) {
+		DEBUG2(printk("scsi(%ld): Invalid SCSI completion handle %d.\n",
+		    ha->host_no, index));
+		qla_printk(KERN_WARNING, ha,
+		    "Invalid SCSI completion handle %d.\n", index);
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		return;
+	}
+
+	sp = ha->outstanding_cmds[index];
+	if (sp) {
+		/* Free outstanding command slot. */
+		ha->outstanding_cmds[index] = NULL;
+
+		if (ha->actthreads)
+			ha->actthreads--;
+		sp->lun_queue->out_cnt--;
+		CMD_COMPL_STATUS(sp->cmd) = 0L;
+		CMD_SCSI_STATUS(sp->cmd) = 0L;
+
+		/* Save ISP completion status */
+		sp->cmd->result = DID_OK << 16;
+		sp->fo_retry_cnt = 0;
+		add_to_done_queue(ha, sp);
+	} else {
+		DEBUG2(printk("scsi(%ld): Invalid ISP SCSI completion handle\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha,
+		    "Invalid ISP SCSI completion handle\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+	}
+}
+
+/**
+ * qla2x00_process_response_queue() - Process response queue entries.
+ * @ha: SCSI driver HA context
+ */
+void
+qla2x00_process_response_queue(struct scsi_qla_host *ha)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+	sts_entry_t	*pkt;
+	uint16_t        handle_cnt;
+	uint16_t        cnt;
+
+	if (!ha->flags.online)
+		return;
+
+	while (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
+		pkt = (sts_entry_t *)ha->response_ring_ptr;
+
+		ha->rsp_ring_index++;
+		if (ha->rsp_ring_index == ha->response_q_length) {
+			ha->rsp_ring_index = 0;
+			ha->response_ring_ptr = ha->response_ring;
+		} else {
+			ha->response_ring_ptr++;
+		}
+
+		if (pkt->entry_status != 0) {
+			DEBUG3(printk(KERN_INFO
+			    "scsi(%ld): Process error entry.\n", ha->host_no));
+
+			qla2x00_error_entry(ha, pkt);
+			((response_t *)pkt)->signature = RESPONSE_PROCESSED;
+			wmb();
+			continue;
+		}
+
+		switch (pkt->entry_type) {
+		case STATUS_TYPE:
+			qla2x00_status_entry(ha, pkt);
+			break;
+		case STATUS_TYPE_21:
+			handle_cnt = ((sts21_entry_t *)pkt)->handle_count;
+			for (cnt = 0; cnt < handle_cnt; cnt++) {
+				qla2x00_process_completed_request(ha,
+				    ((sts21_entry_t *)pkt)->handle[cnt]);
+			}
+			break;
+		case STATUS_TYPE_22:
+			handle_cnt = ((sts22_entry_t *)pkt)->handle_count;
+			for (cnt = 0; cnt < handle_cnt; cnt++) {
+				qla2x00_process_completed_request(ha,
+				    ((sts22_entry_t *)pkt)->handle[cnt]);
+			}
+			break;
+		case STATUS_CONT_TYPE:
+			qla2x00_status_cont_entry(ha, (sts_cont_entry_t *)pkt);
+			break;
+		case MS_IOCB_TYPE:
+			qla2x00_ms_entry(ha, (ms_iocb_entry_t *)pkt);
+			break;
+		case MBX_IOCB_TYPE:
+			if (!IS_QLA2100(ha) && !IS_QLA2200(ha) &&
+			    !IS_QLA6312(ha) && !IS_QLA6322(ha)) {
+				if (pkt->sys_define == SOURCE_ASYNC_IOCB) {
+					qla2x00_process_iodesc(ha,
+					    (struct mbx_entry *)pkt);
+				} else {
+					/* MBX IOCB Type Not Supported. */
+					DEBUG4(printk(KERN_WARNING
+					    "scsi(%ld): Received unknown MBX "
+					    "IOCB response pkt type=%x "
+					    "source=%x entry status=%x.\n",
+					    ha->host_no, pkt->entry_type,
+					    pkt->sys_define,
+					    pkt->entry_status));
+				}
+				break;
+			}
+			/* Fallthrough. */
+		default:
+			/* Type Not Supported. */
+			DEBUG4(printk(KERN_WARNING
+			    "scsi(%ld): Received unknown response pkt type %x "
+			    "entry status=%x.\n",
+			    ha->host_no, pkt->entry_type, pkt->entry_status));
+			break;
+		}
+		((response_t *)pkt)->signature = RESPONSE_PROCESSED;
+		wmb();
+	}
+
+	/* Adjust ring index */
+	WRT_REG_WORD(ISP_RSP_Q_OUT(ha, reg), ha->rsp_ring_index);
+}
+
+/**
+ * qla2x00_status_entry() - Process a Status IOCB entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qla2x00_status_entry(scsi_qla_host_t *ha, sts_entry_t *pkt)
+{
+	int		ret;
+	unsigned	b, t, l;
+	srb_t		*sp;
+	os_lun_t	*lq;
+	os_tgt_t	*tq;
+	fc_port_t	*fcport;
+	struct scsi_cmnd *cp;
+	uint16_t	comp_status;
+	uint16_t	scsi_status;
+	uint8_t		lscsi_status;
+	int32_t		resid;
+	uint8_t		sense_sz = 0;
+	uint16_t	rsp_info_len;
+
+	/* Fast path completion. */
+	if (le16_to_cpu(pkt->comp_status) == CS_COMPLETE &&
+	    (le16_to_cpu(pkt->scsi_status) & SS_MASK) == 0) {
+		qla2x00_process_completed_request(ha, pkt->handle);
+
+		return;
+	}
+
+	/* Validate handle. */
+	if (pkt->handle < MAX_OUTSTANDING_COMMANDS) {
+		sp = ha->outstanding_cmds[pkt->handle];
+		ha->outstanding_cmds[pkt->handle] = NULL;
+	} else
+		sp = NULL;
+
+	if (sp == NULL) {
+		DEBUG2(printk("scsi(%ld): Status Entry invalid handle.\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha, "Status Entry invalid handle.\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		if (ha->dpc_wait && !ha->dpc_active) 
+			up(ha->dpc_wait);
+
+		return;
+	}
+	cp = sp->cmd;
+	if (cp == NULL) {
+		DEBUG2(printk("scsi(%ld): Command already returned back to OS "
+		    "pkt->handle=%d sp=%p sp->state:%d\n",
+		    ha->host_no, pkt->handle, sp, sp->state));
+		qla_printk(KERN_WARNING, ha,
+		    "Command is NULL: already returned to OS (sp=%p)\n", sp);
+
+		return;
+	}
+
+	if (ha->actthreads)
+		ha->actthreads--;
+
+	if (sp->lun_queue == NULL) {
+		DEBUG2(printk("scsi(%ld): Status Entry invalid lun pointer.\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha,
+		    "Status Entry invalid lun pointer.\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		if (ha->dpc_wait && !ha->dpc_active) 
+			up(ha->dpc_wait);
+
+		return;
+	}
+
+	sp->lun_queue->out_cnt--;
+
+	comp_status = le16_to_cpu(pkt->comp_status);
+	/* Mask of reserved bits 12-15, before we examine the scsi status */
+	scsi_status = le16_to_cpu(pkt->scsi_status) & SS_MASK;
+	lscsi_status = scsi_status & STATUS_MASK;
+
+	CMD_ENTRY_STATUS(cp) = pkt->entry_status;
+	CMD_COMPL_STATUS(cp) = comp_status;
+	CMD_SCSI_STATUS(cp) = scsi_status;
+
+	/* Generate LU queue on cntrl, target, LUN */
+	b = cp->device->channel;
+	t = cp->device->id;
+	l = cp->device->lun,
+
+	tq = sp->tgt_queue;
+	lq = sp->lun_queue;
+
+	/*
+	 * If loop is in transient state Report DID_BUS_BUSY
+	 */
+	if ((comp_status != CS_COMPLETE || scsi_status != 0)) {
+		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
+		    (atomic_read(&ha->loop_down_timer) ||
+			atomic_read(&ha->loop_state) != LOOP_READY)) {
+
+			DEBUG2(printk("scsi(%ld:%d:%d:%d): Loop Not Ready - "
+			    "pid=%lx.\n",
+			    ha->host_no, b, t, l, cp->serial_number));
+
+			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
+			add_to_retry_queue(ha, sp);
+			return;
+		}
+	}
+
+	/* Check for any FCP transport errors. */
+	if (scsi_status & SS_RESPONSE_INFO_LEN_VALID) {
+		rsp_info_len = le16_to_cpu(pkt->rsp_info_len);
+		if (rsp_info_len > 3 && pkt->rsp_info[3]) {
+			DEBUG2(printk("scsi(%ld:%d:%d:%d) FCP I/O protocol "
+			    "failure (%x/%02x%02x%02x%02x%02x%02x%02x%02x)..."
+			    "retrying command\n", ha->host_no, b, t, l,
+			    rsp_info_len, pkt->rsp_info[0], pkt->rsp_info[1],
+			    pkt->rsp_info[2], pkt->rsp_info[3],
+			    pkt->rsp_info[4], pkt->rsp_info[5],
+			    pkt->rsp_info[6], pkt->rsp_info[7]));
+
+			cp->result = DID_BUS_BUSY << 16;
+			add_to_done_queue(ha, sp);
+			return;
+		}
+	}
+
+	/*
+	 * Based on Host and scsi status generate status code for Linux
+	 */
+	switch (comp_status) {
+	case CS_COMPLETE:
+		if (scsi_status == 0) {
+			cp->result = DID_OK << 16;
+			break;
+		}
+		if (scsi_status & (SS_RESIDUAL_UNDER | SS_RESIDUAL_OVER)) {
+			resid = le32_to_cpu(pkt->residual_length);
+			cp->resid = resid;
+			CMD_RESID_LEN(cp) = resid;
+		}
+		if (lscsi_status == SS_BUSY_CONDITION) {
+			cp->result = DID_BUS_BUSY << 16 | lscsi_status;
+			break;
+		}
+
+		cp->result = DID_OK << 16 | lscsi_status;
+
+		if (lscsi_status != SS_CHECK_CONDITION)
+			break;
+
+		/*
+		 * Copy Sense Data into sense buffer
+		 */
+		memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
+
+		if (!(scsi_status & SS_SENSE_LEN_VALID))
+			break;
+
+		if (le16_to_cpu(pkt->req_sense_length) <
+		    sizeof(cp->sense_buffer))
+			sense_sz = le16_to_cpu(pkt->req_sense_length);
+		else
+			sense_sz = sizeof(cp->sense_buffer);
+
+		CMD_ACTUAL_SNSLEN(cp) = sense_sz;
+		sp->request_sense_length = sense_sz;
+		sp->request_sense_ptr = cp->sense_buffer;
+
+		if (sp->request_sense_length > 32)
+			sense_sz = 32;
+
+		memcpy(cp->sense_buffer, pkt->req_sense_data, sense_sz);
+
+		sp->request_sense_ptr += sense_sz;
+		sp->request_sense_length -= sense_sz;
+		if (sp->request_sense_length != 0)
+			ha->status_srb = sp;
+
+		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
+		    qla2x00_check_sense(cp, lq) == QLA_SUCCESS) {
+			/* Throw away status_cont if any */
+			ha->status_srb = NULL;
+			add_to_scsi_retry_queue(ha, sp);
+			return;
+		}
+
+		DEBUG5(printk("%s(): Check condition Sense data, "
+		    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
+		    __func__, ha->host_no, b, t, l, cp,
+		    cp->serial_number));
+		if (sense_sz)
+			DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+			    CMD_ACTUAL_SNSLEN(cp)));
+		break;
+
+	case CS_DATA_UNDERRUN:
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld:%d:%d) UNDERRUN status detected 0x%x-0x%x.\n",
+		    ha->host_no, t, l, comp_status, scsi_status));
+
+		resid = le32_to_cpu(pkt->residual_length);
+		if (scsi_status & SS_RESIDUAL_UNDER) {
+			cp->resid = resid;
+			CMD_RESID_LEN(cp) = resid;
+		}
+
+		/*
+		 * Check to see if SCSI Status is non zero. If so report SCSI 
+		 * Status.
+		 */
+		if (lscsi_status != 0) {
+			if (lscsi_status == SS_BUSY_CONDITION) {
+				cp->result = DID_BUS_BUSY << 16 |
+				    lscsi_status;
+				break;
+			}
+
+			cp->result = DID_OK << 16 | lscsi_status;
+
+			if (lscsi_status != SS_CHECK_CONDITION)
+				break;
+
+			/* Copy Sense Data into sense buffer */
+			memset(cp->sense_buffer, 0, sizeof(cp->sense_buffer));
+
+			if (!(scsi_status & SS_SENSE_LEN_VALID))
+				break;
+
+			if (le16_to_cpu(pkt->req_sense_length) <
+			    sizeof(cp->sense_buffer))
+				sense_sz = le16_to_cpu(pkt->req_sense_length);
+			else
+				sense_sz = sizeof(cp->sense_buffer);
+
+			CMD_ACTUAL_SNSLEN(cp) = sense_sz;
+			sp->request_sense_length = sense_sz;
+			sp->request_sense_ptr = cp->sense_buffer;
+
+			if (sp->request_sense_length > 32) 
+				sense_sz = 32;
+
+			memcpy(cp->sense_buffer, pkt->req_sense_data, sense_sz);
+
+			sp->request_sense_ptr += sense_sz;
+			sp->request_sense_length -= sense_sz;
+			if (sp->request_sense_length != 0)
+				ha->status_srb = sp;
+
+			if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
+			    (qla2x00_check_sense(cp, lq) == QLA_SUCCESS)) {
+				ha->status_srb = NULL;
+				add_to_scsi_retry_queue(ha, sp);
+				return;
+			}
+			DEBUG5(printk("%s(): Check condition Sense data, "
+			    "scsi(%ld:%d:%d:%d) cmd=%p pid=%ld\n",
+			    __func__, ha->host_no, b, t, l, cp,
+			    cp->serial_number));
+			if (sense_sz)
+				DEBUG5(qla2x00_dump_buffer(cp->sense_buffer,
+				    CMD_ACTUAL_SNSLEN(cp)));
+		} else {
+			/*
+			 * If RISC reports underrun and target does not report
+			 * it then we must have a lost frame, so tell upper
+			 * layer to retry it by reporting a bus busy.
+			 */
+			if (!(scsi_status & SS_RESIDUAL_UNDER)) {
+				DEBUG2(printk("scsi(%ld:%d:%d:%d) Dropped "
+				    "frame(s) detected (%x of %x bytes)..."
+				    "retrying command.\n",
+				    ha->host_no, b, t, l, resid,
+				    cp->request_bufflen));
+
+				cp->result = DID_BUS_BUSY << 16;
+				ha->dropped_frame_error_cnt++;
+				break;
+			}
+
+			/* Handle mid-layer underflow */
+			if ((unsigned)(cp->request_bufflen - resid) <
+			    cp->underflow) {
+				qla_printk(KERN_INFO, ha,
+				    "scsi(%ld:%d:%d:%d): Mid-layer underflow "
+				    "detected (%x of %x bytes)...returning "
+				    "error status.\n",
+				    ha->host_no, b, t, l, resid,
+				    cp->request_bufflen);
+
+				cp->result = DID_ERROR << 16;
+				break;
+			}
+
+			/* Everybody online, looking good... */
+			cp->result = DID_OK << 16;
+		}
+		break;
+
+	case CS_DATA_OVERRUN:
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld:%d:%d): OVERRUN status detected 0x%x-0x%x\n",
+		    ha->host_no, t, l, comp_status, scsi_status));
+		DEBUG2(printk(KERN_INFO
+		    "CDB: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n",
+		    cp->cmnd[0], cp->cmnd[1], cp->cmnd[2], cp->cmnd[3],
+		    cp->cmnd[4], cp->cmnd[5]));
+		DEBUG2(printk(KERN_INFO
+		    "PID=0x%lx req=0x%x xtra=0x%x -- returning DID_ERROR "
+		    "status!\n",
+		    cp->serial_number, cp->request_bufflen,
+		    le32_to_cpu(pkt->residual_length)));
+
+		cp->result = DID_ERROR << 16;
+		break;
+
+	case CS_PORT_LOGGED_OUT:
+	case CS_PORT_CONFIG_CHG:
+	case CS_PORT_BUSY:
+	case CS_INCOMPLETE:
+	case CS_PORT_UNAVAILABLE:
+		/*
+		 * If the port is in Target Down state, return all IOs for this
+		 * Target with DID_NO_CONNECT ELSE Queue the IOs in the
+		 * retry_queue.
+		 */
+		fcport = sp->fclun->fcport;
+		DEBUG2(printk("scsi(%ld:%d:%d): status_entry: Port Down "
+		    "pid=%ld, compl status=0x%x, port state=0x%x\n",
+		    ha->host_no, t, l, cp->serial_number, comp_status,
+		    atomic_read(&fcport->state)));
+
+		if ((sp->flags & (SRB_IOCTL | SRB_TAPE)) ||
+		    atomic_read(&fcport->state) == FCS_DEVICE_DEAD) {
+			cp->result = DID_NO_CONNECT << 16;
+			if (atomic_read(&ha->loop_state) == LOOP_DOWN) 
+				sp->err_id = SRB_ERR_LOOP;
+			else
+				sp->err_id = SRB_ERR_PORT;
+			add_to_done_queue(ha, sp);
+		} else {
+			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
+			add_to_retry_queue(ha, sp);
+		}
+
+		if (atomic_read(&fcport->state) == FCS_ONLINE) {
+			qla2x00_mark_device_lost(ha, fcport, 1);
+		}
+
+		return;
+		break;
+
+	case CS_RESET:
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld): RESET status detected 0x%x-0x%x.\n",
+		    ha->host_no, comp_status, scsi_status));
+
+		if (sp->flags & (SRB_IOCTL | SRB_TAPE)) {
+			cp->result = DID_RESET << 16;
+		} else {
+			qla2x00_extend_timeout(cp, EXTEND_CMD_TIMEOUT);
+			add_to_retry_queue(ha, sp);
+			return;
+		}
+		break;
+
+	case CS_ABORTED:
+		/* 
+		 * hv2.19.12 - DID_ABORT does not retry the request if we
+		 * aborted this request then abort otherwise it must be a
+		 * reset.
+		 */
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld): ABORT status detected 0x%x-0x%x.\n",
+		    ha->host_no, comp_status, scsi_status));
+
+		cp->result = DID_RESET << 16;
+		break;
+
+	case CS_TIMEOUT:
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld:%d:%d:%d): TIMEOUT status detected 0x%x-0x%x "
+		    "sflags=%x.\n", ha->host_no, b, t, l, comp_status,
+		    scsi_status, le16_to_cpu(pkt->status_flags)));
+
+		cp->result = DID_BUS_BUSY << 16;
+
+		fcport = lq->fclun->fcport;
+
+		/* Check to see if logout occurred */
+		if ((le16_to_cpu(pkt->status_flags) & SF_LOGOUT_SENT)) {
+			qla2x00_mark_device_lost(ha, fcport, 1);
+		}
+		break;
+
+	case CS_QUEUE_FULL:
+		DEBUG2(printk(KERN_INFO
+		    "scsi(%ld): QUEUE FULL status detected 0x%x-0x%x.\n",
+		    ha->host_no, comp_status, scsi_status));
+
+		/* SCSI Mid-Layer handles device queue full */
+
+		cp->result = DID_OK << 16 | lscsi_status; 
+
+		/* TODO: ??? */
+		/* Adjust queue depth */
+		ret = scsi_track_queue_full(cp->device,
+		    sp->lun_queue->out_cnt - 1);
+		if (ret) {
+			qla_printk(KERN_INFO, ha,
+			    "scsi(%ld:%d:%d:%d): Queue depth adjusted to %d.\n",
+			    ha->host_no, cp->device->channel, cp->device->id,
+			    cp->device->lun, ret);
+		}
+		break;
+
+	default:
+		DEBUG3(printk("scsi(%ld): Error detected (unknown status) "
+		    "0x%x-0x%x.\n",
+		    ha->host_no, comp_status, scsi_status));
+		qla_printk(KERN_INFO, ha,
+		    "Unknown status detected 0x%x-0x%x.\n",
+		    comp_status, scsi_status);
+
+		cp->result = DID_ERROR << 16;
+		break;
+	}
+
+	/* Place command on done queue. */
+	if (ha->status_srb == NULL)
+		add_to_done_queue(ha, sp);
+}
+
+/**
+ * qla2x00_status_cont_entry() - Process a Status Continuations entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ *
+ * Extended sense data.
+ */
+static void
+qla2x00_status_cont_entry(scsi_qla_host_t *ha, sts_cont_entry_t *pkt)
+{
+	uint8_t		sense_sz = 0;
+	srb_t		*sp = ha->status_srb;
+	struct scsi_cmnd *cp;
+
+	if (sp != NULL && sp->request_sense_length != 0) {
+		cp = sp->cmd;
+		if (cp == NULL) {
+			DEBUG2(printk("%s(): Cmd already returned back to OS "
+			    "sp=%p sp->state:%d\n", __func__, sp, sp->state));
+			qla_printk(KERN_INFO, ha,
+			    "cmd is NULL: already returned to OS (sp=%p)\n",
+			    sp); 
+
+			ha->status_srb = NULL;
+			return;
+		}
+
+		if (sp->request_sense_length > sizeof(pkt->data)) {
+			sense_sz = sizeof(pkt->data);
+		} else {
+			sense_sz = sp->request_sense_length;
+		}
+
+		/* Move sense data. */
+		memcpy(sp->request_sense_ptr, pkt->data, sense_sz);
+		DEBUG5(qla2x00_dump_buffer(sp->request_sense_ptr, sense_sz));
+
+		sp->request_sense_ptr += sense_sz;
+		sp->request_sense_length -= sense_sz;
+
+		/* Place command on done queue. */
+		if (sp->request_sense_length == 0) {
+			add_to_done_queue(ha, sp);
+			ha->status_srb = NULL;
+		}
+	}
+}
+
+/**
+ * qla2x00_error_entry() - Process an error entry.
+ * @ha: SCSI driver HA context
+ * @pkt: Entry pointer
+ */
+static void
+qla2x00_error_entry(scsi_qla_host_t *ha, sts_entry_t *pkt) 
+{
+	srb_t *sp;
+
+#if defined(QL_DEBUG_LEVEL_2)
+	if (pkt->entry_status & RF_INV_E_ORDER)
+		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Order\n", __func__);
+	else if (pkt->entry_status & RF_INV_E_COUNT)
+		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Count\n", __func__);
+	else if (pkt->entry_status & RF_INV_E_PARAM)
+		qla_printk(KERN_ERR, ha, 
+		    "%s: Invalid Entry Parameter\n", __func__);
+	else if (pkt->entry_status & RF_INV_E_TYPE)
+		qla_printk(KERN_ERR, ha, "%s: Invalid Entry Type\n", __func__);
+	else if (pkt->entry_status & RF_BUSY)
+		qla_printk(KERN_ERR, ha, "%s: Busy\n", __func__);
+	else
+		qla_printk(KERN_ERR, ha, "%s: UNKNOWN flag error\n", __func__);
+#endif
+
+	/* Validate handle. */
+	if (pkt->handle < MAX_OUTSTANDING_COMMANDS)
+		sp = ha->outstanding_cmds[pkt->handle];
+	else
+		sp = NULL;
+
+	if (sp) {
+		/* Free outstanding command slot. */
+		ha->outstanding_cmds[pkt->handle] = NULL;
+		if (ha->actthreads)
+			ha->actthreads--;
+		sp->lun_queue->out_cnt--;
+
+		/* Bad payload or header */
+		if (pkt->entry_status &
+		    (RF_INV_E_ORDER | RF_INV_E_COUNT |
+		     RF_INV_E_PARAM | RF_INV_E_TYPE)) {
+			sp->cmd->result = DID_ERROR << 16;
+		} else if (pkt->entry_status & RF_BUSY) {
+			sp->cmd->result = DID_BUS_BUSY << 16;
+		} else {
+			sp->cmd->result = DID_ERROR << 16;
+		}
+		/* Place command on done queue. */
+		add_to_done_queue(ha, sp);
+
+	} else if (pkt->entry_type == COMMAND_A64_TYPE ||
+	    pkt->entry_type == COMMAND_TYPE) {
+		DEBUG2(printk("scsi(%ld): Error entry - invalid handle\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha,
+		    "Error entry - invalid handle\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		if (ha->dpc_wait && !ha->dpc_active) 
+			up(ha->dpc_wait);
+	}
+}
+
+/**
+ * qla2x00_ms_entry() - Process a Management Server entry.
+ * @ha: SCSI driver HA context
+ * @index: Response queue out pointer
+ */
+static void
+qla2x00_ms_entry(scsi_qla_host_t *ha, ms_iocb_entry_t *pkt) 
+{
+	srb_t          *sp;
+
+	DEBUG3(printk("%s(%ld): pkt=%p pkthandle=%d.\n",
+	    __func__, ha->host_no, pkt, pkt->handle1));
+
+	/* Validate handle. */
+ 	if (pkt->handle1 < MAX_OUTSTANDING_COMMANDS)
+ 		sp = ha->outstanding_cmds[pkt->handle1];
+	else
+		sp = NULL;
+
+	if (sp == NULL) {
+		DEBUG2(printk("scsi(%ld): MS entry - invalid handle\n",
+		    ha->host_no));
+		qla_printk(KERN_WARNING, ha, "MS entry - invalid handle\n");
+
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+		return;
+	}
+
+	CMD_COMPL_STATUS(sp->cmd) = le16_to_cpu(pkt->status);
+	CMD_ENTRY_STATUS(sp->cmd) = pkt->entry_status;
+
+	/* Free outstanding command slot. */
+	ha->outstanding_cmds[pkt->handle1] = NULL;
+
+	add_to_done_queue(ha, sp);
+}
+
+/**
+ * qla2x00_check_sense() - Perform any sense data interrogation.
+ * @cp: SCSI Command
+ * @lq: Lun queue
+ *
+ * Returns QLA_SUCCESS if the lun queue is suspended, else
+ * QLA_FUNCTION_FAILED  (lun queue not suspended).
+ */
+static int 
+qla2x00_check_sense(struct scsi_cmnd *cp, os_lun_t *lq)
+{
+	scsi_qla_host_t	*ha;
+	srb_t		*sp;
+	fc_port_t	*fcport;
+
+	ha = (scsi_qla_host_t *) cp->device->host->hostdata;
+	if ((cp->sense_buffer[0] & 0x70) != 0x70) {
+		return (QLA_FUNCTION_FAILED);
+	}
+
+	sp = (srb_t * )CMD_SP(cp);
+	sp->flags |= SRB_GOT_SENSE;
+
+	switch (cp->sense_buffer[2] & 0xf) {
+	case RECOVERED_ERROR:
+		cp->result = DID_OK << 16;
+		cp->sense_buffer[0] = 0;
+		break;
+
+	case NOT_READY:
+		fcport = lq->fclun->fcport;
+
+		/*
+		 * Suspend the lun only for hard disk device type.
+		 */
+		if ((fcport->flags & FCF_TAPE_PRESENT) == 0 &&
+		    lq->q_state != LUN_STATE_TIMEOUT) {
+			/*
+			 * If target is in process of being ready then suspend
+			 * lun for 6 secs and retry all the commands.
+			 */
+			if (cp->sense_buffer[12] == 0x4 &&
+			    cp->sense_buffer[13] == 0x1) {
+
+				/* Suspend the lun for 6 secs */
+				qla2x00_suspend_lun(ha, lq, 6,
+				    ql2xsuspendcount);
+
+				return (QLA_SUCCESS);
+			}
+		}
+		break;
+	}
+
+	return (QLA_FUNCTION_FAILED);
+}
diff --git a/drivers/scsi/qla2xxx/qla_listops.h b/drivers/scsi/qla2xxx/qla_listops.h
new file mode 100644
index 0000000..5da034f
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_listops.h
@@ -0,0 +1,351 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+/* Management functions for various lists */
+
+/* __add_to_done_queue()
+ * 
+ * Place SRB command on done queue.
+ *
+ * Input:
+ *      ha           = host pointer
+ *      sp           = srb pointer.
+ * Locking:
+ * 	this function assumes the ha->list_lock is already taken
+ */
+static inline void 
+__add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+	/*
+        if (sp->state != SRB_NO_QUEUE_STATE && 
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+        /* Place block on done queue */
+        sp->cmd->host_scribble = (unsigned char *) NULL;
+        sp->state = SRB_DONE_STATE;
+        list_add_tail(&sp->list,&ha->done_queue);
+        ha->done_q_cnt++;
+	sp->ha = ha;
+}
+
+static inline void 
+__add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+	/*
+        if( sp->state != SRB_NO_QUEUE_STATE && 
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+        /* Place block on retry queue */
+        list_add_tail(&sp->list,&ha->retry_queue);
+        ha->retry_q_cnt++;
+        sp->flags |= SRB_WATCHDOG;
+        sp->state = SRB_RETRY_STATE;
+	sp->ha = ha;
+}
+
+static inline void 
+__add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+	/*
+        if( sp->state != SRB_NO_QUEUE_STATE && 
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+        /* Place block on retry queue */
+        list_add_tail(&sp->list,&ha->scsi_retry_queue);
+        ha->scsi_retry_q_cnt++;
+        sp->state = SRB_SCSI_RETRY_STATE;
+	sp->ha = ha;
+}
+
+static inline void 
+add_to_done_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+        __add_to_done_queue(ha,sp);
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+static inline void 
+add_to_free_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+	mempool_free(sp, ha->srb_mempool);
+}
+
+static inline void 
+add_to_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+        __add_to_retry_queue(ha,sp);
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+static inline void 
+add_to_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+        __add_to_scsi_retry_queue(ha,sp);
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+/*
+ * __del_from_retry_queue
+ *      Function used to remove a command block from the
+ *      watchdog timer queue.
+ *
+ *      Note: Must insure that command is on watchdog
+ *            list before calling del_from_retry_queue
+ *            if (sp->flags & SRB_WATCHDOG)
+ *
+ * Input: 
+ *      ha = adapter block pointer.
+ *      sp = srb pointer.
+ * Locking:
+ *	this function assumes the list_lock is already taken
+ */
+static inline void 
+__del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        list_del_init(&sp->list);
+
+        sp->flags &= ~(SRB_WATCHDOG | SRB_BUSY);
+        sp->state = SRB_NO_QUEUE_STATE;
+        ha->retry_q_cnt--;
+}
+
+/*
+ * __del_from_scsi_retry_queue
+ *      Function used to remove a command block from the
+ *      scsi retry queue.
+ *
+ * Input: 
+ *      ha = adapter block pointer.
+ *      sp = srb pointer.
+ * Locking:
+ *	this function assumes the list_lock is already taken
+ */
+static inline void 
+__del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        list_del_init(&sp->list);
+
+        ha->scsi_retry_q_cnt--;
+        sp->state = SRB_NO_QUEUE_STATE;
+}
+
+/*
+ * del_from_retry_queue
+ *      Function used to remove a command block from the
+ *      watchdog timer queue.
+ *
+ *      Note: Must insure that command is on watchdog
+ *            list before calling del_from_retry_queue
+ *            if (sp->flags & SRB_WATCHDOG)
+ *
+ * Input: 
+ *      ha = adapter block pointer.
+ *      sp = srb pointer.
+ * Locking:
+ *	this function takes and releases the list_lock
+ */
+static inline void 
+del_from_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        /*	if (unlikely(!(sp->flags & SRB_WATCHDOG)))
+        		BUG();*/
+        spin_lock_irqsave(&ha->list_lock, flags);
+
+        /*	if (unlikely(list_empty(&ha->retry_queue)))
+        		BUG();*/
+
+        __del_from_retry_queue(ha,sp);
+
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+/*
+ * del_from_scsi_retry_queue
+ *      Function used to remove a command block from the
+ *      scsi retry queue.
+ *
+ * Input: 
+ *      ha = adapter block pointer.
+ *      sp = srb pointer.
+ * Locking:
+ *	this function takes and releases the list_lock
+ */
+static inline void 
+del_from_scsi_retry_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+
+        /*	if (unlikely(list_empty(&ha->scsi_retry_queue)))
+        		BUG();*/
+
+        __del_from_scsi_retry_queue(ha,sp);
+
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+/*
+ * __add_to_pending_queue
+ *      Add the standard SCB job to the bottom of standard SCB commands.
+ *
+ * Input:
+ * COMPLETE!!!
+ *      q  = SCSI LU pointer.
+ *      sp = srb pointer.
+ *      SCSI_LU_Q lock must be already obtained.
+ */
+static inline int 
+__add_to_pending_queue(struct scsi_qla_host *ha, srb_t * sp)
+{
+	int	empty;
+	/*
+        if( sp->state != SRB_NO_QUEUE_STATE &&
+        	sp->state != SRB_FREE_STATE &&
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+	empty = list_empty(&ha->pending_queue);
+	list_add_tail(&sp->list, &ha->pending_queue);
+	ha->qthreads++;
+	sp->state = SRB_PENDING_STATE;
+
+	return (empty);
+}
+
+static inline void 
+__add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t * sp)
+{
+	/*
+        if( sp->state != SRB_NO_QUEUE_STATE && 
+        	sp->state != SRB_FREE_STATE &&
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+	list_add(&sp->list, &ha->pending_queue);
+	ha->qthreads++;
+	sp->state = SRB_PENDING_STATE;
+}
+
+static inline int
+add_to_pending_queue(struct scsi_qla_host *ha, srb_t *sp)
+{
+	int	empty;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->list_lock, flags);
+	empty = __add_to_pending_queue(ha, sp);
+	spin_unlock_irqrestore(&ha->list_lock, flags);
+
+	return (empty);
+}
+static inline void
+add_to_pending_queue_head(struct scsi_qla_host *ha, srb_t *sp)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&ha->list_lock, flags);
+	__add_to_pending_queue_head(ha, sp);
+	spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+static inline void
+__del_from_pending_queue(struct scsi_qla_host *ha, srb_t *sp)
+{
+	list_del_init(&sp->list);
+	ha->qthreads--;
+	sp->state = SRB_NO_QUEUE_STATE;
+}
+
+/*
+ * Failover Stuff.
+ */
+static inline void
+__add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+	/*
+        if( sp->state != SRB_NO_QUEUE_STATE && 
+        	sp->state != SRB_ACTIVE_STATE)
+		BUG();
+	*/
+
+        list_add_tail(&sp->list,&ha->failover_queue);
+        ha->failover_cnt++;
+        sp->state = SRB_FAILOVER_STATE;
+	sp->ha = ha;
+}
+
+static inline void add_to_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+
+        __add_to_failover_queue(ha,sp);
+
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+static inline void __del_from_failover_queue(struct scsi_qla_host * ha, srb_t *
+                sp)
+{
+        ha->failover_cnt--;
+        list_del_init(&sp->list);
+        sp->state = SRB_NO_QUEUE_STATE;
+}
+
+static inline void del_from_failover_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+
+        __del_from_failover_queue(ha,sp);
+
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+static inline void 
+del_from_pending_queue(struct scsi_qla_host * ha, srb_t * sp)
+{
+        unsigned long flags;
+
+        spin_lock_irqsave(&ha->list_lock, flags);
+
+        __del_from_pending_queue(ha,sp);
+
+        spin_unlock_irqrestore(&ha->list_lock, flags);
+}
diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c
new file mode 100644
index 0000000..c04fbcd
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_mbx.c
@@ -0,0 +1,1950 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/delay.h>
+
+static void
+qla2x00_mbx_sem_timeout(unsigned long data)
+{
+	struct semaphore	*sem_ptr = (struct semaphore *)data;
+
+	DEBUG11(printk("qla2x00_sem_timeout: entered.\n");)
+
+	if (sem_ptr != NULL) {
+		up(sem_ptr);
+	}
+
+	DEBUG11(printk("qla2x00_mbx_sem_timeout: exiting.\n");)
+}
+
+/*
+ * qla2x00_mailbox_command
+ *	Issue mailbox command and waits for completion.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	mcp = driver internal mbx struct pointer.
+ *
+ * Output:
+ *	mb[MAX_MAILBOX_REGISTER_COUNT] = returned mailbox data.
+ *
+ * Returns:
+ *	0 : QLA_SUCCESS = cmd performed success
+ *	1 : QLA_FUNCTION_FAILED   (error encountered)
+ *	6 : QLA_FUNCTION_TIMEOUT (timeout condition encountered)
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_mailbox_command(scsi_qla_host_t *ha, mbx_cmd_t *mcp)
+{
+	int		rval;
+	unsigned long    flags = 0;
+	device_reg_t __iomem *reg = ha->iobase;
+	struct timer_list	tmp_intr_timer;
+	uint8_t		abort_active = test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+	uint8_t		io_lock_on = ha->flags.init_done;
+	uint16_t	command;
+	uint16_t	*iptr;
+	uint16_t __iomem *optr;
+	uint32_t	cnt;
+	uint32_t	mboxes;
+	unsigned long	mbx_flags = 0;
+	unsigned long	wait_time;
+
+	rval = QLA_SUCCESS;
+
+	DEBUG11(printk("qla2x00_mailbox_command(%ld): entered.\n",
+	    ha->host_no);)
+	/*
+	 * Wait for active mailbox commands to finish by waiting at most
+	 * tov seconds. This is to serialize actual issuing of mailbox cmds
+	 * during non ISP abort time.
+	 */
+	if (!abort_active) {
+		if (qla2x00_down_timeout(&ha->mbx_cmd_sem, mcp->tov * HZ)) {
+			/* Timeout occurred. Return error. */
+			DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): cmd "
+			    "access timeout. Exiting.\n", ha->host_no);)
+			return QLA_FUNCTION_TIMEOUT;
+		}
+	}
+
+	ha->flags.mbox_busy = 1;
+	/* Save mailbox command for debug */
+	ha->mcp = mcp;
+
+	/* Try to get mailbox register access */
+	if (!abort_active)
+		spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
+
+	DEBUG11(printk("scsi%d: prepare to issue mbox cmd=0x%x.\n",
+	    (int)ha->host_no, mcp->mb[0]);)
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Load mailbox registers. */
+	optr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 0);
+
+	iptr = mcp->mb;
+	command = mcp->mb[0];
+	mboxes = mcp->out_mb;
+
+	for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+		if (IS_QLA2200(ha) && cnt == 8)
+			optr = (uint16_t __iomem *)MAILBOX_REG(ha, reg, 8);
+		if (mboxes & BIT_0)
+			WRT_REG_WORD(optr, *iptr);
+
+		mboxes >>= 1;
+		optr++;
+		iptr++;
+	}
+
+#if defined(QL_DEBUG_LEVEL_1)
+	printk("qla2x00_mailbox_command: Loaded MBX registers "
+	    "(displayed in bytes) = \n");
+	qla2x00_dump_buffer((uint8_t *)mcp->mb, 16);
+	printk("\n");
+	qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x10), 16);
+	printk("\n");
+	qla2x00_dump_buffer(((uint8_t *)mcp->mb + 0x20), 8);
+	printk("\n");
+	printk("qla2x00_mailbox_command: I/O address = %lx.\n",
+	    (u_long)optr);
+	qla2x00_dump_regs(ha);
+#endif
+
+	/* Issue set host interrupt command to send cmd out. */
+	ha->flags.mbox_int = 0;
+	clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+	/* Unlock mbx registers and wait for interrupt */
+
+	DEBUG11(printk("qla2x00_mailbox_command: going to unlock irq & "
+	    "waiting for interrupt. jiffies=%lx.\n", jiffies);)
+
+	/* Wait for mbx cmd completion until timeout */
+
+	if (!abort_active && io_lock_on) {
+		/* sleep on completion semaphore */
+		DEBUG11(printk("qla2x00_mailbox_command(%ld): "
+		    "INTERRUPT MODE. Initializing timer.\n",
+		    ha->host_no);)
+
+		init_timer(&tmp_intr_timer);
+		tmp_intr_timer.data = (unsigned long)&ha->mbx_intr_sem;
+		tmp_intr_timer.expires = jiffies + mcp->tov * HZ;
+		tmp_intr_timer.function =
+		    (void (*)(unsigned long))qla2x00_mbx_sem_timeout;
+
+		DEBUG11(printk("qla2x00_mailbox_command(%ld): "
+		    "Adding timer.\n", ha->host_no);)
+		add_timer(&tmp_intr_timer);
+
+		DEBUG11(printk("qla2x00_mailbox_command: going to "
+		    "unlock & sleep. time=0x%lx.\n", jiffies);)
+
+		set_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		if (!abort_active)
+			spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
+
+		/* Wait for either the timer to expire
+		 * or the mbox completion interrupt
+		 */
+		down(&ha->mbx_intr_sem);
+
+		DEBUG11(printk("qla2x00_mailbox_command:"
+		    "waking up."
+		    "time=0x%lx\n", jiffies);)
+		clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags);
+
+		/* delete the timer */
+		del_timer(&tmp_intr_timer);
+	} else {
+
+		DEBUG3_11(printk("qla2x00_mailbox_command(%ld): cmd=%x "
+			"POLLING MODE.\n", ha->host_no, command);)
+
+		WRT_REG_WORD(&reg->hccr, HCCR_SET_HOST_INT);
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		if (!abort_active)
+			spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
+
+		wait_time = jiffies + mcp->tov * HZ; /* wait at most tov secs */
+		while (!ha->flags.mbox_int) {
+			if (time_after(jiffies, wait_time))
+				break;
+
+			/* Check for pending interrupts. */
+			qla2x00_poll(ha);
+
+			udelay(10); /* v4.27 */
+		} /* while */
+	}
+
+	if (!abort_active)
+		spin_lock_irqsave(&ha->mbx_reg_lock, mbx_flags);
+
+	/* Check whether we timed out */
+	if (ha->flags.mbox_int) {
+		uint16_t *iptr2;
+
+		DEBUG3_11(printk("qla2x00_mailbox_cmd: cmd %x completed.\n",
+		    command);)
+
+		/* Got interrupt. Clear the flag. */
+		ha->flags.mbox_int = 0;
+		clear_bit(MBX_INTERRUPT, &ha->mbx_cmd_flags);
+
+		if (ha->mailbox_out[0] != MBS_COMMAND_COMPLETE) {
+			qla2x00_stats.mboxerr++;
+			rval = QLA_FUNCTION_FAILED;
+		}
+
+		/* Load return mailbox registers. */
+		iptr2 = mcp->mb;
+		iptr = (uint16_t *)&ha->mailbox_out[0];
+		mboxes = mcp->in_mb;
+		for (cnt = 0; cnt < ha->mbx_count; cnt++) {
+			if (mboxes & BIT_0)
+				*iptr2 = *iptr;
+
+			mboxes >>= 1;
+			iptr2++;
+			iptr++;
+		}
+	} else {
+
+#if defined(QL_DEBUG_LEVEL_2) || defined(QL_DEBUG_LEVEL_3) || \
+		defined(QL_DEBUG_LEVEL_11)
+		printk("qla2x00_mailbox_command(%ld): **** MB Command Timeout "
+		    "for cmd %x ****\n", ha->host_no, command);
+		printk("qla2x00_mailbox_command: icontrol=%x jiffies=%lx\n",
+		    RD_REG_WORD(&reg->ictrl), jiffies);
+		printk("qla2x00_mailbox_command: *** mailbox[0] = 0x%x ***\n",
+		    RD_REG_WORD(optr));
+		qla2x00_dump_regs(ha);
+#endif
+
+		qla2x00_stats.mboxtout++;
+		ha->total_mbx_timeout++;
+		rval = QLA_FUNCTION_TIMEOUT;
+	}
+
+	if (!abort_active)
+		spin_unlock_irqrestore(&ha->mbx_reg_lock, mbx_flags);
+
+	ha->flags.mbox_busy = 0;
+
+	/* Clean up */
+	ha->mcp = NULL;
+
+	if (!abort_active) {
+		DEBUG11(printk("qla2x00_mailbox_cmd: checking for additional "
+		    "resp interrupt.\n");)
+
+		/* polling mode for non isp_abort commands. */
+		qla2x00_poll(ha);
+	}
+
+	if (rval == QLA_FUNCTION_TIMEOUT) {
+		if (!io_lock_on || (mcp->flags & IOCTL_CMD)) {
+			/* not in dpc. schedule it for dpc to take over. */
+			DEBUG(printk("qla2x00_mailbox_command(%ld): timeout "
+			    "schedule isp_abort_needed.\n",
+			    ha->host_no);)
+			DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): "
+			    "timeout schedule isp_abort_needed.\n",
+			    ha->host_no);)
+			qla_printk(KERN_WARNING, ha,
+			    "Mailbox command timeout occured. Scheduling ISP "
+			    "abort.\n");
+			set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			if (ha->dpc_wait && !ha->dpc_active) 
+				up(ha->dpc_wait);
+
+		} else if (!abort_active) {
+
+			/* call abort directly since we are in the DPC thread */
+			DEBUG(printk("qla2x00_mailbox_command(%ld): timeout "
+			    "calling abort_isp\n", ha->host_no);)
+			DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): "
+			    "timeout calling abort_isp\n", ha->host_no);)
+			qla_printk(KERN_WARNING, ha,
+			    "Mailbox command timeout occured. Issuing ISP "
+			    "abort.\n");
+
+			set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+			clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			if (qla2x00_abort_isp(ha)) {
+				/* failed. retry later. */
+				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			}
+			clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+			DEBUG(printk("qla2x00_mailbox_command: finished "
+			    "abort_isp\n");)
+			DEBUG2_3_11(printk("qla2x00_mailbox_command: finished "
+			    "abort_isp\n");)
+		}
+	}
+
+	/* Allow next mbx cmd to come in. */
+	if (!abort_active)
+		up(&ha->mbx_cmd_sem);
+
+	if (rval) {
+		DEBUG2_3_11(printk("qla2x00_mailbox_command(%ld): **** FAILED. "
+		    "mbx0=%x, mbx1=%x, mbx2=%x, cmd=%x ****\n",
+		ha->host_no, mcp->mb[0], mcp->mb[1], mcp->mb[2], command);)
+	} else {
+		DEBUG11(printk("qla2x00_mailbox_command(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	DEBUG11(printk("qla2x00_mailbox_command(%ld): exiting.\n",
+	    ha->host_no);)
+
+	return rval;
+}
+
+/*
+ * qla2x00_load_ram
+ *	Load adapter RAM using DMA.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_load_ram(scsi_qla_host_t *ha, dma_addr_t req_dma, uint16_t risc_addr,
+    uint16_t risc_code_size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	uint32_t	req_len;
+	dma_addr_t	nml_dma;
+	uint32_t	nml_len;
+	uint32_t	normalized;
+
+	DEBUG11(printk("qla2x00_load_ram(%ld): entered.\n",
+	    ha->host_no);)
+
+	req_len = risc_code_size;
+	nml_dma = 0;
+	nml_len = 0;
+
+	normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma,
+	    &nml_len);
+
+	/* Load first segment */
+	mcp->mb[0] = MBC_LOAD_RISC_RAM;
+	mcp->mb[1] = risc_addr;
+	mcp->mb[2] = MSW(req_dma);
+	mcp->mb[3] = LSW(req_dma);
+	mcp->mb[4] = (uint16_t)req_len;
+	mcp->mb[6] = MSW(MSD(req_dma));
+	mcp->mb[7] = LSW(MSD(req_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Load second segment - if necessary */
+	if (normalized && (rval == QLA_SUCCESS)) {
+		mcp->mb[0] = MBC_LOAD_RISC_RAM;
+		mcp->mb[1] = risc_addr + (uint16_t)req_len;
+		mcp->mb[2] = MSW(nml_dma);
+		mcp->mb[3] = LSW(nml_dma);
+		mcp->mb[4] = (uint16_t)nml_len;
+		mcp->mb[6] = MSW(MSD(nml_dma));
+		mcp->mb[7] = LSW(MSD(nml_dma));
+		mcp->out_mb = MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+		mcp->in_mb = MBX_0;
+		mcp->tov = 30;
+		mcp->flags = 0;
+		rval = qla2x00_mailbox_command(ha, mcp);
+	}
+
+	if (rval == QLA_SUCCESS) {
+		/* Empty */
+		DEBUG11(printk("qla2x00_load_ram(%ld): done.\n", ha->host_no);)
+	} else {
+		/* Empty */
+		DEBUG2_3_11(printk("qla2x00_load_ram(%ld): failed. rval=%x "
+		    "mb[0]=%x.\n", ha->host_no, rval, mcp->mb[0]);)
+	}
+	return rval;
+}
+
+/*
+ * qla2x00_load_ram_ext
+ *	Load adapter extended RAM using DMA.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_load_ram_ext(scsi_qla_host_t *ha, dma_addr_t req_dma,
+    uint32_t risc_addr, uint16_t risc_code_size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	uint32_t	req_len;
+	dma_addr_t	nml_dma;
+	uint32_t	nml_len;
+	uint32_t	normalized;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	req_len = risc_code_size;
+	nml_dma = 0;
+	nml_len = 0;
+
+	normalized = qla2x00_normalize_dma_addr(&req_dma, &req_len, &nml_dma,
+	    &nml_len);
+
+	/* Load first segment */
+	mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
+	mcp->mb[1] = LSW(risc_addr);
+	mcp->mb[2] = MSW(req_dma);
+	mcp->mb[3] = LSW(req_dma);
+	mcp->mb[4] = (uint16_t)req_len;
+	mcp->mb[6] = MSW(MSD(req_dma));
+	mcp->mb[7] = LSW(MSD(req_dma));
+	mcp->mb[8] = MSW(risc_addr);
+	mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Load second segment - if necessary */
+	if (normalized && (rval == QLA_SUCCESS)) {
+		risc_addr += req_len;
+		mcp->mb[0] = MBC_LOAD_RISC_RAM_EXTENDED;
+		mcp->mb[1] = LSW(risc_addr);
+		mcp->mb[2] = MSW(nml_dma);
+		mcp->mb[3] = LSW(nml_dma);
+		mcp->mb[4] = (uint16_t)nml_len;
+		mcp->mb[6] = MSW(MSD(nml_dma));
+		mcp->mb[7] = LSW(MSD(nml_dma));
+		mcp->mb[8] = MSW(risc_addr);
+		mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+		mcp->in_mb = MBX_0;
+		mcp->tov = 30;
+		mcp->flags = 0;
+		rval = qla2x00_mailbox_command(ha, mcp);
+	}
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed=%x mb[0]=%x.\n",
+		    __func__, ha->host_no, rval, mcp->mb[0]));
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_execute_fw
+ *	Start adapter firmware.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_execute_fw(scsi_qla_host_t *ha)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_execute_fw(%ld): entered.\n", ha->host_no);)
+
+	mcp->mb[0] = MBC_EXECUTE_FIRMWARE;
+	mcp->mb[1] = *ha->brd_info->fw_info[0].fwstart;
+	mcp->out_mb = MBX_1|MBX_0;
+	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
+		mcp->mb[2] = 0;
+		mcp->out_mb |= MBX_2;
+	}
+
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	DEBUG11(printk("qla2x00_execute_fw(%ld): done.\n", ha->host_no);)
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_fw_version
+ *	Get firmware version.
+ *
+ * Input:
+ *	ha:		adapter state pointer.
+ *	major:		pointer for major number.
+ *	minor:		pointer for minor number.
+ *	subminor:	pointer for subminor number.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+void
+qla2x00_get_fw_version(scsi_qla_host_t *ha, uint16_t *major, uint16_t *minor,
+    uint16_t *subminor, uint16_t *attributes, uint32_t *memory)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_GET_FIRMWARE_VERSION;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->flags = 0;
+	mcp->tov = 30;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Return mailbox data. */
+	*major = mcp->mb[1];
+	*minor = mcp->mb[2];
+	*subminor = mcp->mb[3];
+	*attributes = mcp->mb[6];
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		*memory = 0x1FFFF;			/* Defaults to 128KB. */
+	else
+		*memory = (mcp->mb[5] << 16) | mcp->mb[4];
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+}
+
+/*
+ * qla2x00_get_fw_options
+ *	Set firmware options.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fwopt = pointer for firmware options.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_GET_FIRMWARE_OPTION;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
+	} else {
+		fwopts[1] = mcp->mb[1];
+		fwopts[2] = mcp->mb[2];
+		fwopts[3] = mcp->mb[3];
+
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+
+/*
+ * qla2x00_set_fw_options
+ *	Set firmware options.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fwopt = pointer for firmware options.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_set_fw_options(scsi_qla_host_t *ha, uint16_t *fwopts)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_SET_FIRMWARE_OPTION;
+	mcp->mb[1] = fwopts[1];
+	mcp->mb[2] = fwopts[2];
+	mcp->mb[3] = fwopts[3];
+	mcp->mb[10] = fwopts[10];
+	mcp->mb[11] = fwopts[11];
+	mcp->mb[12] = 0;	/* Undocumented, but used */
+	mcp->out_mb = MBX_12|MBX_11|MBX_10|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_mbx_reg_test
+ *	Mailbox register wrap test.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_mbx_reg_test(scsi_qla_host_t *ha)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_mbx_reg_test(%ld): entered.\n", ha->host_no);)
+
+	mcp->mb[0] = MBC_MAILBOX_REGISTER_TEST;
+	mcp->mb[1] = 0xAAAA;
+	mcp->mb[2] = 0x5555;
+	mcp->mb[3] = 0xAA55;
+	mcp->mb[4] = 0x55AA;
+	mcp->mb[5] = 0xA5A5;
+	mcp->mb[6] = 0x5A5A;
+	mcp->mb[7] = 0x2525;
+	mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval == QLA_SUCCESS) {
+		if (mcp->mb[1] != 0xAAAA || mcp->mb[2] != 0x5555 ||
+		    mcp->mb[3] != 0xAA55 || mcp->mb[4] != 0x55AA)
+			rval = QLA_FUNCTION_FAILED;
+		if (mcp->mb[5] != 0xA5A5 || mcp->mb[6] != 0x5A5A ||
+		    mcp->mb[7] != 0x2525)
+			rval = QLA_FUNCTION_FAILED;
+	}
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_mbx_reg_test(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_mbx_reg_test(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_verify_checksum
+ *	Verify firmware checksum.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_verify_checksum(scsi_qla_host_t *ha)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_verify_checksum(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_VERIFY_CHECKSUM;
+	mcp->mb[1] = *ha->brd_info->fw_info[0].fwstart;
+	mcp->out_mb = MBX_1|MBX_0;
+	mcp->in_mb = MBX_2|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_verify_checksum(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_verify_checksum(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_issue_iocb
+ *	Issue IOCB using mailbox command
+ *
+ * Input:
+ *	ha = adapter state pointer.
+ *	buffer = buffer pointer.
+ *	phys_addr = physical address of buffer.
+ *	size = size of buffer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_issue_iocb(scsi_qla_host_t *ha, void*  buffer, dma_addr_t phys_addr,
+    size_t size)
+{
+	int		rval;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	mcp->mb[0] = MBC_IOCB_COMMAND_A64;
+	mcp->mb[1] = 0;
+	mcp->mb[2] = MSW(phys_addr);
+	mcp->mb[3] = LSW(phys_addr);
+	mcp->mb[6] = MSW(MSD(phys_addr));
+	mcp->mb[7] = LSW(MSD(phys_addr));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_2|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x",
+		    ha->host_no,rval);)
+		DEBUG2(printk("qla2x00_issue_iocb(%ld): failed rval 0x%x",
+		    ha->host_no,rval);)
+	} else {
+		/*EMPTY*/
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_abort_command
+ *	Abort command aborts a specified IOCB.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	sp = SB structure pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_abort_command(scsi_qla_host_t *ha, srb_t *sp)
+{
+	unsigned long   flags = 0;
+	fc_port_t	*fcport;
+	int		rval;
+	uint32_t	handle;
+	mbx_cmd_t	mc;
+	mbx_cmd_t	*mcp = &mc;
+
+	DEBUG11(printk("qla2x00_abort_command(%ld): entered.\n", ha->host_no);)
+
+	fcport = sp->fclun->fcport;
+
+	if (atomic_read(&ha->loop_state) == LOOP_DOWN ||
+	    atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+		return 1;
+	}
+
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	for (handle = 1; handle < MAX_OUTSTANDING_COMMANDS; handle++) {
+		if (ha->outstanding_cmds[handle] == sp)
+			break;
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	if (handle == MAX_OUTSTANDING_COMMANDS) {
+		/* command not found */
+		return QLA_FUNCTION_FAILED;
+	}
+
+	mcp->mb[0] = MBC_ABORT_COMMAND;
+	if (HAS_EXTENDED_IDS(ha))
+		mcp->mb[1] = fcport->loop_id;
+	else
+		mcp->mb[1] = fcport->loop_id << 8;
+	mcp->mb[2] = (uint16_t)handle;
+	mcp->mb[3] = (uint16_t)(handle >> 16);
+	mcp->mb[6] = (uint16_t)sp->fclun->lun;
+	mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("qla2x00_abort_command(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		sp->flags |= SRB_ABORT_PENDING;
+		DEBUG11(printk("qla2x00_abort_command(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+#if USE_ABORT_TGT
+/*
+ * qla2x00_abort_target
+ *	Issue abort target mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_abort_target(fc_port_t *fcport)
+{
+	int        rval;
+	mbx_cmd_t  mc;
+	mbx_cmd_t  *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_abort_target(%ld): entered.\n",
+	    fcport->ha->host_no);)
+
+	if (fcport == NULL) {
+		/* no target to abort */
+		return 0;
+	}
+
+	mcp->mb[0] = MBC_ABORT_TARGET;
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(fcport->ha)) {
+		mcp->mb[1] = fcport->loop_id;
+		mcp->mb[10] = 0;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = fcport->loop_id << 8;
+	}
+	mcp->mb[2] = fcport->ha->loop_reset_delay;
+
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(fcport->ha, mcp);
+
+	/* Issue marker command. */
+	fcport->ha->marker_needed = 1;
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("qla2x00_abort_target(%ld): failed=%x.\n",
+		    fcport->ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_abort_target(%ld): done.\n",
+		    fcport->ha->host_no);)
+	}
+
+	return rval;
+}
+#endif
+
+/*
+ * qla2x00_target_reset
+ *	Issue target reset mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_target_reset(scsi_qla_host_t *ha, uint16_t b, uint16_t t)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	os_tgt_t *tgt;
+
+	DEBUG11(printk("qla2x00_target_reset(%ld): entered.\n", ha->host_no);)
+
+	tgt = TGT_Q(ha, t);
+	if (tgt->fcport == NULL) {
+		/* no target to abort */
+		return 0;
+	}
+	if (atomic_read(&tgt->fcport->state) != FCS_ONLINE) {
+		/* target not online */
+		return 0;
+	}
+
+	mcp->mb[0] = MBC_TARGET_RESET;
+	if (HAS_EXTENDED_IDS(ha))
+		mcp->mb[1] = tgt->fcport->loop_id;
+	else
+		mcp->mb[1] = tgt->fcport->loop_id << 8;
+	mcp->mb[2] = ha->loop_reset_delay;
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_target_reset(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_target_reset(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_adapter_id
+ *	Get adapter ID and topology.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	id = pointer for loop ID.
+ *	al_pa = pointer for AL_PA.
+ *	area = pointer for area.
+ *	domain = pointer for domain.
+ *	top = pointer for topology.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_adapter_id(scsi_qla_host_t *ha, uint16_t *id, uint8_t *al_pa,
+    uint8_t *area, uint8_t *domain, uint16_t *top)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_get_adapter_id(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_GET_ADAPTER_LOOP_ID;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Return data. */
+	*id = mcp->mb[1];
+	*al_pa = LSB(mcp->mb[2]);
+	*area = MSB(mcp->mb[2]);
+	*domain	= LSB(mcp->mb[3]);
+	*top = mcp->mb[6];
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_adapter_id(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_get_adapter_id(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_retry_cnt
+ *	Get current firmware login retry count and delay.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	retry_cnt = pointer to login retry count.
+ *	tov = pointer to login timeout value.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_retry_cnt(scsi_qla_host_t *ha, uint8_t *retry_cnt, uint8_t *tov,
+    uint16_t *r_a_tov)
+{
+	int rval;
+	uint16_t ratov;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_get_retry_cnt(%ld): entered.\n",
+			ha->host_no);)
+
+	mcp->mb[0] = MBC_GET_RETRY_COUNT;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_retry_cnt(%ld): failed = %x.\n",
+		    ha->host_no, mcp->mb[0]);)
+	} else {
+		/* Convert returned data and check our values. */
+		*r_a_tov = mcp->mb[3] / 2;
+		ratov = (mcp->mb[3]/2) / 10;  /* mb[3] value is in 100ms */
+		if (mcp->mb[1] * ratov > (*retry_cnt) * (*tov)) {
+			/* Update to the larger values */
+			*retry_cnt = (uint8_t)mcp->mb[1];
+			*tov = ratov;
+		}
+
+		DEBUG11(printk("qla2x00_get_retry_cnt(%ld): done. mb3=%d "
+		    "ratov=%d.\n", ha->host_no, mcp->mb[3], ratov);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_init_firmware
+ *	Initialize adapter firmware.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	dptr = Initialization control block pointer.
+ *	size = size of initialization control block.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_init_firmware(scsi_qla_host_t *ha, uint16_t size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_init_firmware(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_INITIALIZE_FIRMWARE;
+	mcp->mb[2] = MSW(ha->init_cb_dma);
+	mcp->mb[3] = LSW(ha->init_cb_dma);
+	mcp->mb[4] = 0;
+	mcp->mb[5] = 0;
+	mcp->mb[6] = MSW(MSD(ha->init_cb_dma));
+	mcp->mb[7] = LSW(MSD(ha->init_cb_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_5|MBX_4|MBX_0;
+	mcp->buf_size = size;
+	mcp->flags = MBX_DMA_OUT;
+	mcp->tov = 30;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_init_firmware(%ld): failed=%x "
+		    "mb0=%x.\n",
+		    ha->host_no, rval, mcp->mb[0]);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_init_firmware(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_port_database
+ *	Issue normal/enhanced get port database mailbox command
+ *	and copy device name as necessary.
+ *
+ * Input:
+ *	ha = adapter state pointer.
+ *	dev = structure pointer.
+ *	opt = enhanced cmd option byte.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_port_database(scsi_qla_host_t *ha, fc_port_t *fcport, uint8_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	port_database_t *pd;
+	dma_addr_t pd_dma;
+
+	DEBUG11(printk("qla2x00_get_port_database(%ld): entered.\n",
+	    ha->host_no);)
+
+	pd = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &pd_dma);
+	if (pd  == NULL) {
+		DEBUG2_3_11(printk("qla2x00_get_port_database(%ld): **** "
+		    "Mem Alloc Failed ****", ha->host_no);)
+		return QLA_MEMORY_ALLOC_FAILED;
+	}
+	memset(pd, 0, PORT_DATABASE_SIZE);
+
+	if (opt != 0)
+		mcp->mb[0] = MBC_ENHANCED_GET_PORT_DATABASE;
+	else
+		mcp->mb[0] = MBC_GET_PORT_DATABASE;
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = fcport->loop_id;
+		mcp->mb[10] = opt;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = fcport->loop_id << 8 | opt;
+	}
+	mcp->mb[2] = MSW(pd_dma);
+	mcp->mb[3] = LSW(pd_dma);
+	mcp->mb[6] = MSW(MSD(pd_dma));
+	mcp->mb[7] = LSW(MSD(pd_dma));
+
+	mcp->in_mb = MBX_0;
+	mcp->buf_size = PORT_DATABASE_SIZE;
+	mcp->flags = MBX_DMA_IN;
+	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
+	rval = qla2x00_mailbox_command(ha, mcp);
+	if (rval != QLA_SUCCESS)
+		goto gpd_error_out;
+
+	/* Check for logged in state. */
+	if (pd->master_state != PD_STATE_PORT_LOGGED_IN &&
+	    pd->slave_state != PD_STATE_PORT_LOGGED_IN) {
+		rval = QLA_FUNCTION_FAILED;
+		goto gpd_error_out;
+	}
+
+	/* Names are little-endian. */
+	memcpy(fcport->node_name, pd->node_name, WWN_SIZE);
+	memcpy(fcport->port_name, pd->port_name, WWN_SIZE);
+
+	/* Get port_id of device. */
+	fcport->d_id.b.al_pa = pd->port_id[2];
+	fcport->d_id.b.area = pd->port_id[3];
+	fcport->d_id.b.domain = pd->port_id[0];
+	fcport->d_id.b.rsvd_1 = 0;
+
+	/* Check for device require authentication. */
+	pd->common_features & BIT_5 ? (fcport->flags |= FCF_AUTH_REQ) :
+	    (fcport->flags &= ~FCF_AUTH_REQ);
+
+	/* If not target must be initiator or unknown type. */
+	if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0)
+		fcport->port_type = FCT_INITIATOR;
+	else
+		fcport->port_type = FCT_TARGET;
+
+gpd_error_out:
+	dma_pool_free(ha->s_dma_pool, pd, pd_dma);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_port_database(%ld): "
+		    "failed=%x.\n", ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_get_port_database(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_firmware_state
+ *	Get adapter firmware state.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	dptr = pointer for firmware state.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_firmware_state(scsi_qla_host_t *ha, uint16_t *dptr)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_get_firmware_state(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_GET_FIRMWARE_STATE;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Return firmware state. */
+	*dptr = mcp->mb[1];
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_firmware_state(%ld): "
+		    "failed=%x.\n", ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_get_firmware_state(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_port_name
+ *	Issue get port name mailbox command.
+ *	Returned name is in big endian format.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	loop_id = loop ID of device.
+ *	name = pointer for name.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_port_name(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t *name,
+    uint8_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_get_port_name(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_GET_PORT_NAME;
+	mcp->out_mb = MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = loop_id;
+		mcp->mb[10] = opt;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = loop_id << 8 | opt;
+	}
+
+	mcp->in_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_port_name(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		if (name != NULL) {
+			/* This function returns name in big endian. */
+			name[0] = LSB(mcp->mb[2]);
+			name[1] = MSB(mcp->mb[2]);
+			name[2] = LSB(mcp->mb[3]);
+			name[3] = MSB(mcp->mb[3]);
+			name[4] = LSB(mcp->mb[6]);
+			name[5] = MSB(mcp->mb[6]);
+			name[6] = LSB(mcp->mb[7]);
+			name[7] = MSB(mcp->mb[7]);
+		}
+
+		DEBUG11(printk("qla2x00_get_port_name(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_lip_reset
+ *	Issue LIP reset mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_lip_reset(scsi_qla_host_t *ha)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_lip_reset(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_LIP_RESET;
+	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = 0x00ff;
+		mcp->mb[10] = 0;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = 0xff00;
+	}
+	mcp->mb[2] = ha->loop_reset_delay;
+	mcp->mb[3] = 0;
+
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_lip_reset(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_lip_reset(%ld): done.\n", ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_send_sns
+ *	Send SNS command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	sns = pointer for command.
+ *	cmd_size = command size.
+ *	buf_size = response/command size.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_send_sns(scsi_qla_host_t *ha, dma_addr_t sns_phys_address,
+    uint16_t cmd_size, size_t buf_size)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_send_sns(%ld): entered.\n",
+	    ha->host_no);)
+
+	DEBUG11(printk("qla2x00_send_sns: retry cnt=%d ratov=%d total "
+	    "tov=%d.\n", ha->retry_count, ha->login_timeout, mcp->tov);)
+
+	mcp->mb[0] = MBC_SEND_SNS_COMMAND;
+	mcp->mb[1] = cmd_size;
+	mcp->mb[2] = MSW(sns_phys_address);
+	mcp->mb[3] = LSW(sns_phys_address);
+	mcp->mb[6] = MSW(MSD(sns_phys_address));
+	mcp->mb[7] = LSW(MSD(sns_phys_address));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0|MBX_1;
+	mcp->buf_size = buf_size;
+	mcp->flags = MBX_DMA_OUT|MBX_DMA_IN;
+	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
+		    "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+		DEBUG2_3_11(printk("qla2x00_send_sns(%ld): failed=%x mb[0]=%x "
+		    "mb[1]=%x.\n", ha->host_no, rval, mcp->mb[0], mcp->mb[1]);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_send_sns(%ld): done.\n", ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_login_fabric
+ *	Issue login fabric port mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	loop_id = device loop ID.
+ *	domain = device domain.
+ *	area = device area.
+ *	al_pa = device AL_PA.
+ *	status = pointer for return status.
+ *	opt = command options.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_login_fabric(scsi_qla_host_t *ha, uint16_t loop_id, uint8_t domain,
+    uint8_t area, uint8_t al_pa, uint16_t *mb, uint8_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_login_fabric(%ld): entered.\n", ha->host_no);)
+
+	mcp->mb[0] = MBC_LOGIN_FABRIC_PORT;
+	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = loop_id;
+		mcp->mb[10] = opt;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = (loop_id << 8) | opt;
+	}
+	mcp->mb[2] = domain;
+	mcp->mb[3] = area << 8 | al_pa;
+
+	mcp->in_mb = MBX_7|MBX_6|MBX_2|MBX_1|MBX_0;
+	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	/* Return mailbox statuses. */
+	if (mb != NULL) {
+		mb[0] = mcp->mb[0];
+		mb[1] = mcp->mb[1];
+		mb[2] = mcp->mb[2];
+		mb[6] = mcp->mb[6];
+		mb[7] = mcp->mb[7];
+	}
+
+	if (rval != QLA_SUCCESS) {
+		/* RLU tmp code: need to change main mailbox_command function to
+		 * return ok even when the mailbox completion value is not
+		 * SUCCESS. The caller needs to be responsible to interpret
+		 * the return values of this mailbox command if we're not
+		 * to change too much of the existing code.
+		 */
+		if (mcp->mb[0] == 0x4001 || mcp->mb[0] == 0x4002 ||
+		    mcp->mb[0] == 0x4003 || mcp->mb[0] == 0x4005 ||
+		    mcp->mb[0] == 0x4006)
+			rval = QLA_SUCCESS;
+
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_login_fabric(%ld): failed=%x "
+		    "mb[0]=%x mb[1]=%x mb[2]=%x.\n", ha->host_no, rval,
+		    mcp->mb[0], mcp->mb[1], mcp->mb[2]);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_login_fabric(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_login_local_device
+ *           Issue login loop port mailbox command.
+ *    
+ * Input:
+ *           ha = adapter block pointer.
+ *           loop_id = device loop ID.
+ *           opt = command options.
+ *          
+ * Returns:
+ *            Return status code.
+ *             
+ * Context:
+ *            Kernel context.
+ *             
+ */
+int
+qla2x00_login_local_device(scsi_qla_host_t *ha, uint16_t loop_id,
+    uint16_t *mb_ret, uint8_t opt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG3(printk("%s(%ld): entered.\n", __func__, ha->host_no);)
+
+	mcp->mb[0] = MBC_LOGIN_LOOP_PORT;
+	if (HAS_EXTENDED_IDS(ha))
+		mcp->mb[1] = loop_id;
+	else
+		mcp->mb[1] = loop_id << 8;
+	mcp->mb[2] = opt;
+	mcp->out_mb = MBX_2|MBX_1|MBX_0;
+ 	mcp->in_mb = MBX_7|MBX_6|MBX_1|MBX_0;
+	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+ 	/* Return mailbox statuses. */
+ 	if (mb_ret != NULL) {
+ 		mb_ret[0] = mcp->mb[0];
+ 		mb_ret[1] = mcp->mb[1];
+ 		mb_ret[6] = mcp->mb[6];
+ 		mb_ret[7] = mcp->mb[7];
+ 	}
+
+	if (rval != QLA_SUCCESS) {
+ 		/* AV tmp code: need to change main mailbox_command function to
+ 		 * return ok even when the mailbox completion value is not
+ 		 * SUCCESS. The caller needs to be responsible to interpret
+ 		 * the return values of this mailbox command if we're not
+ 		 * to change too much of the existing code.
+ 		 */
+ 		if (mcp->mb[0] == 0x4005 || mcp->mb[0] == 0x4006)
+ 			rval = QLA_SUCCESS;
+
+		DEBUG(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
+		    "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
+		    mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+		DEBUG2_3(printk("%s(%ld): failed=%x mb[0]=%x mb[1]=%x "
+		    "mb[6]=%x mb[7]=%x.\n", __func__, ha->host_no, rval,
+		    mcp->mb[0], mcp->mb[1], mcp->mb[6], mcp->mb[7]);)
+	} else {
+		/*EMPTY*/
+		DEBUG3(printk("%s(%ld): done.\n", __func__, ha->host_no);)
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_fabric_logout
+ *	Issue logout fabric port mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	loop_id = device loop ID.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_fabric_logout(scsi_qla_host_t *ha, uint16_t loop_id)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_fabric_logout(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_LOGOUT_FABRIC_PORT;
+	mcp->out_mb = MBX_1|MBX_0;
+	if (HAS_EXTENDED_IDS(ha)) {
+		mcp->mb[1] = loop_id;
+		mcp->mb[10] = 0;
+		mcp->out_mb |= MBX_10;
+	} else {
+		mcp->mb[1] = loop_id << 8;
+	}
+
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_fabric_logout(%ld): failed=%x "
+		    "mbx1=%x.\n", ha->host_no, rval, mcp->mb[1]);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_fabric_logout(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_full_login_lip
+ *	Issue full login LIP mailbox command.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_full_login_lip(scsi_qla_host_t *ha)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_full_login_lip(%ld): entered.\n",
+	    ha->host_no);)
+
+	mcp->mb[0] = MBC_LIP_FULL_LOGIN;
+	mcp->mb[1] = 0;
+	mcp->mb[2] = 0;
+	mcp->mb[3] = 0;
+	mcp->out_mb = MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_full_login_lip(%ld): failed=%x.\n",
+		    ha->instance, rval);)
+	} else {
+		/*EMPTY*/
+		DEBUG11(printk("qla2x00_full_login_lip(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_id_list
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_id_list(scsi_qla_host_t *ha, void *id_list, dma_addr_t id_list_dma,
+    uint16_t *entries)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("qla2x00_get_id_list(%ld): entered.\n",
+	    ha->host_no);)
+
+	if (id_list == NULL)
+		return QLA_FUNCTION_FAILED;
+
+	mcp->mb[0] = MBC_GET_ID_LIST;
+	mcp->mb[1] = MSW(id_list_dma);
+	mcp->mb[2] = LSW(id_list_dma);
+	mcp->mb[3] = MSW(MSD(id_list_dma));
+	mcp->mb[6] = LSW(MSD(id_list_dma));
+	mcp->out_mb = MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("qla2x00_get_id_list(%ld): failed=%x.\n",
+		    ha->host_no, rval);)
+	} else {
+		*entries = mcp->mb[1];
+		DEBUG11(printk("qla2x00_get_id_list(%ld): done.\n",
+		    ha->host_no);)
+	}
+
+	return rval;
+}
+
+/*
+ * qla2x00_get_resource_cnts
+ *	Get current firmware resource counts.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_resource_cnts(scsi_qla_host_t *ha, uint16_t *cur_xchg_cnt,
+    uint16_t *orig_xchg_cnt, uint16_t *cur_iocb_cnt, uint16_t *orig_iocb_cnt)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+
+	DEBUG11(printk("%s(%ld): entered.\n", __func__, ha->host_no));
+
+	mcp->mb[0] = MBC_GET_RESOURCE_COUNTS;
+	mcp->out_mb = MBX_0;
+	mcp->in_mb = MBX_10|MBX_7|MBX_6|MBX_3|MBX_2|MBX_1|MBX_0;
+	mcp->tov = 30;
+	mcp->flags = 0;
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval != QLA_SUCCESS) {
+		/*EMPTY*/
+		DEBUG2_3_11(printk("%s(%ld): failed = %x.\n", __func__,
+		    ha->host_no, mcp->mb[0]);)
+	} else {
+		DEBUG11(printk("%s(%ld): done. mb1=%x mb2=%x mb3=%x mb6=%x "
+		    "mb7=%x mb10=%x.\n", __func__, ha->host_no,
+		    mcp->mb[1], mcp->mb[2], mcp->mb[3], mcp->mb[6], mcp->mb[7], 
+		    mcp->mb[10]));
+
+		if (cur_xchg_cnt)
+			*cur_xchg_cnt = mcp->mb[3];
+		if (orig_xchg_cnt)
+			*orig_xchg_cnt = mcp->mb[6];
+		if (cur_iocb_cnt)
+			*cur_iocb_cnt = mcp->mb[7];
+		if (orig_iocb_cnt)
+			*orig_iocb_cnt = mcp->mb[10];
+	}
+
+	return (rval);
+}
+
+#if defined(QL_DEBUG_LEVEL_3)
+/*
+ * qla2x00_get_fcal_position_map
+ *	Get FCAL (LILP) position map using mailbox command
+ *
+ * Input:
+ *	ha = adapter state pointer.
+ *	pos_map = buffer pointer (can be NULL).
+ *
+ * Returns:
+ *	qla2x00 local function return status code.
+ *
+ * Context:
+ *	Kernel context.
+ */
+int
+qla2x00_get_fcal_position_map(scsi_qla_host_t *ha, char *pos_map)
+{
+	int rval;
+	mbx_cmd_t mc;
+	mbx_cmd_t *mcp = &mc;
+	char *pmap;
+	dma_addr_t pmap_dma;
+
+	pmap = dma_pool_alloc(ha->s_dma_pool, GFP_ATOMIC, &pmap_dma);
+	if (pmap  == NULL) {
+		DEBUG2_3_11(printk("%s(%ld): **** Mem Alloc Failed ****",
+		    __func__, ha->host_no));
+		return QLA_MEMORY_ALLOC_FAILED;
+	}
+	memset(pmap, 0, FCAL_MAP_SIZE);
+
+	mcp->mb[0] = MBC_GET_FC_AL_POSITION_MAP;
+	mcp->mb[2] = MSW(pmap_dma);
+	mcp->mb[3] = LSW(pmap_dma);
+	mcp->mb[6] = MSW(MSD(pmap_dma));
+	mcp->mb[7] = LSW(MSD(pmap_dma));
+	mcp->out_mb = MBX_7|MBX_6|MBX_3|MBX_2|MBX_0;
+	mcp->in_mb = MBX_1|MBX_0;
+	mcp->buf_size = FCAL_MAP_SIZE;
+	mcp->flags = MBX_DMA_IN;
+	mcp->tov = (ha->login_timeout * 2) + (ha->login_timeout / 2);
+	rval = qla2x00_mailbox_command(ha, mcp);
+
+	if (rval == QLA_SUCCESS) {
+		DEBUG11(printk("%s(%ld): (mb0=%x/mb1=%x) FC/AL Position Map "
+		    "size (%x)\n", __func__, ha->host_no, mcp->mb[0],
+		    mcp->mb[1], (unsigned)pmap[0]));
+		DEBUG11(qla2x00_dump_buffer(pmap, pmap[0] + 1));
+
+		if (pos_map)
+			memcpy(pos_map, pmap, FCAL_MAP_SIZE);
+	}
+	dma_pool_free(ha->s_dma_pool, pmap, pmap_dma);
+
+	if (rval != QLA_SUCCESS) {
+		DEBUG2_3_11(printk("%s(%ld): failed=%x.\n", __func__,
+		    ha->host_no, rval));
+	} else {
+		DEBUG11(printk("%s(%ld): done.\n", __func__, ha->host_no));
+	}
+
+	return rval;
+}
+#endif
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
new file mode 100644
index 0000000..b5863d8
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -0,0 +1,4456 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+#include <linux/moduleparam.h>
+#include <linux/vmalloc.h>
+#include <linux/smp_lock.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+
+/*
+ * Driver version
+ */
+char qla2x00_version_str[40];
+
+/*
+ * SRB allocation cache
+ */
+char srb_cachep_name[16];
+kmem_cache_t *srb_cachep;
+
+/*
+ * Stats for all adpaters.
+ */
+struct _qla2x00stats qla2x00_stats;
+
+/*
+ * Ioctl related information.
+ */
+int num_hosts;
+int apiHBAInstance;
+
+/*
+ * Module parameter information and variables
+ */
+int ql2xmaxqdepth;
+module_param(ql2xmaxqdepth, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xmaxqdepth,
+		"Maximum queue depth to report for target devices.");
+
+int ql2xlogintimeout = 20;
+module_param(ql2xlogintimeout, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xlogintimeout,
+		"Login timeout value in seconds.");
+
+int qlport_down_retry;
+module_param(qlport_down_retry, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(qlport_down_retry,
+		"Maximum number of command retries to a port that returns"
+		"a PORT-DOWN status.");
+
+int ql2xretrycount = 20;
+module_param(ql2xretrycount, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xretrycount,
+		"Maximum number of mid-layer retries allowed for a command.  "
+		"Default value is 20, ");
+
+int displayConfig;
+module_param(displayConfig, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(displayConfig,
+		"If 1 then display the configuration used in /etc/modprobe.conf.");
+
+int ql2xplogiabsentdevice;
+module_param(ql2xplogiabsentdevice, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xplogiabsentdevice,
+		"Option to enable PLOGI to devices that are not present after "
+		"a Fabric scan.  This is needed for several broken switches."
+		"Default is 0 - no PLOGI. 1 - perfom PLOGI.");
+
+int ql2xenablezio = 0;
+module_param(ql2xenablezio, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xenablezio,
+		"Option to enable ZIO:If 1 then enable it otherwise" 
+		" use the default set in the NVRAM."
+		" Default is 0 : disabled");
+
+int ql2xintrdelaytimer = 10;
+module_param(ql2xintrdelaytimer, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xintrdelaytimer,
+		"ZIO: Waiting time for Firmware before it generates an "
+		"interrupt to the host to notify completion of request.");
+
+int ConfigRequired;
+module_param(ConfigRequired, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ConfigRequired,
+		"If 1, then only configured devices passed in through the"
+		"ql2xopts parameter will be presented to the OS");
+
+int Bind = BIND_BY_PORT_NAME;
+module_param(Bind, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(Bind,
+		"Target persistent binding method: "
+		"0 by Portname (default); 1 by PortID; 2 by Nodename. ");
+
+int ql2xsuspendcount = SUSPEND_COUNT;
+module_param(ql2xsuspendcount, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xsuspendcount,
+		"Number of 6-second suspend iterations to perform while a "
+		"target returns a <NOT READY> status.  Default is 10 "
+		"iterations.");
+
+int ql2xdoinitscan = 1;
+module_param(ql2xdoinitscan, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(ql2xdoinitscan,
+		"Signal mid-layer to perform scan after driver load: 0 -- no "
+		"signal sent to mid-layer.");
+
+int ql2xloginretrycount = 0;
+module_param(ql2xloginretrycount, int, S_IRUGO|S_IRUSR);
+MODULE_PARM_DESC(ql2xloginretrycount,
+		"Specify an alternate value for the NVRAM login retry count.");
+
+/*
+ * Proc structures and functions
+ */
+struct info_str {
+	char	*buffer;
+	int	length;
+	off_t	offset;
+	int	pos;
+};
+
+static void copy_mem_info(struct info_str *, char *, int);
+static int copy_info(struct info_str *, char *, ...);
+
+static void qla2x00_free_device(scsi_qla_host_t *);
+
+static void qla2x00_config_dma_addressing(scsi_qla_host_t *ha);
+
+/*
+ * SCSI host template entry points 
+ */
+static int qla2xxx_slave_configure(struct scsi_device * device);
+static int qla2x00_queuecommand(struct scsi_cmnd *cmd,
+		void (*fn)(struct scsi_cmnd *));
+static int qla2xxx_eh_abort(struct scsi_cmnd *);
+static int qla2xxx_eh_device_reset(struct scsi_cmnd *);
+static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
+static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
+static int qla2x00_loop_reset(scsi_qla_host_t *ha);
+static int qla2x00_device_reset(scsi_qla_host_t *, fc_port_t *);
+
+static int qla2x00_proc_info(struct Scsi_Host *, char *, char **,
+    off_t, int, int);
+
+static struct scsi_host_template qla2x00_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "qla2xxx",
+	.proc_name		= "qla2xxx",
+	.proc_info		= qla2x00_proc_info,
+	.queuecommand		= qla2x00_queuecommand,
+
+	.eh_abort_handler	= qla2xxx_eh_abort,
+	.eh_device_reset_handler = qla2xxx_eh_device_reset,
+	.eh_bus_reset_handler	= qla2xxx_eh_bus_reset,
+	.eh_host_reset_handler	= qla2xxx_eh_host_reset,
+
+	.slave_configure	= qla2xxx_slave_configure,
+
+	.this_id		= -1,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.sg_tablesize		= SG_ALL,
+
+	/*
+	 * The RISC allows for each command to transfer (2^32-1) bytes of data,
+	 * which equates to 0x800000 sectors.
+	 */
+	.max_sectors		= 0xFFFF,
+};
+
+static struct scsi_transport_template *qla2xxx_transport_template = NULL;
+
+static void qla2x00_display_fc_names(scsi_qla_host_t *);
+
+/* TODO Convert to inlines
+ *
+ * Timer routines
+ */
+#define	WATCH_INTERVAL		1       /* number of seconds */
+
+static void qla2x00_timer(scsi_qla_host_t *);
+
+static __inline__ void qla2x00_start_timer(scsi_qla_host_t *,
+    void *, unsigned long);
+static __inline__ void qla2x00_restart_timer(scsi_qla_host_t *, unsigned long);
+static __inline__ void qla2x00_stop_timer(scsi_qla_host_t *);
+
+static inline void
+qla2x00_start_timer(scsi_qla_host_t *ha, void *func, unsigned long interval)
+{
+	init_timer(&ha->timer);
+	ha->timer.expires = jiffies + interval * HZ;
+	ha->timer.data = (unsigned long)ha;
+	ha->timer.function = (void (*)(unsigned long))func;
+	add_timer(&ha->timer);
+	ha->timer_active = 1;
+}
+
+static inline void
+qla2x00_restart_timer(scsi_qla_host_t *ha, unsigned long interval)
+{
+	mod_timer(&ha->timer, jiffies + interval * HZ);
+}
+
+static __inline__ void
+qla2x00_stop_timer(scsi_qla_host_t *ha)
+{
+	del_timer_sync(&ha->timer);
+	ha->timer_active = 0;
+}
+
+void qla2x00_cmd_timeout(srb_t *);
+
+static __inline__ void qla2x00_callback(scsi_qla_host_t *, struct scsi_cmnd *);
+static __inline__ void sp_put(struct scsi_qla_host * ha, srb_t *sp);
+static __inline__ void sp_get(struct scsi_qla_host * ha, srb_t *sp);
+static __inline__ void
+qla2x00_delete_from_done_queue(scsi_qla_host_t *, srb_t *); 
+
+/*
+* qla2x00_callback
+*      Returns the completed SCSI command to LINUX.
+*
+* Input:
+*	ha -- Host adapter structure
+*	cmd -- SCSI mid-level command structure.
+* Returns:
+*      None
+* Note:From failover point of view we always get the sp
+*      from vis_ha pool in queuecommand.So when we put it 
+*      back to the pool it has to be the vis_ha.	 
+*      So rely on struct scsi_cmnd to get the vis_ha and not on sp. 		 	
+*/
+static inline void
+qla2x00_callback(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
+{
+	srb_t *sp = (srb_t *) CMD_SP(cmd);
+	scsi_qla_host_t *vis_ha;
+	os_lun_t *lq;
+	int got_sense;
+	unsigned long	cpu_flags = 0;
+
+	cmd->host_scribble = (unsigned char *) NULL;
+	vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
+
+	if (sp == NULL) {
+		qla_printk(KERN_INFO, ha,
+			"%s(): **** CMD derives a NULL SP\n",
+			__func__);
+                DEBUG2(BUG();)
+		return;
+	}
+
+	/*
+	 * If command status is not DID_BUS_BUSY then go ahead and freed sp.
+	 */
+	/*
+	 * Cancel command timeout
+	 */
+	qla2x00_delete_timer_from_cmd(sp);
+
+	/*
+	 * Put SP back in the free queue
+	 */
+	sp->cmd   = NULL;
+	CMD_SP(cmd) = NULL;
+	lq = sp->lun_queue;
+	got_sense = (sp->flags & SRB_GOT_SENSE)? 1: 0;
+	add_to_free_queue(vis_ha, sp);
+
+	if (host_byte(cmd->result) == DID_OK) {
+		/* device ok */
+		ha->total_bytes += cmd->bufflen;
+		if (!got_sense) {
+			/* If lun was suspended then clear retry count */
+			spin_lock_irqsave(&lq->q_lock, cpu_flags);
+			if (!test_bit(LUN_EXEC_DELAYED, &lq->q_flag))
+				lq->q_state = LUN_STATE_READY;
+			spin_unlock_irqrestore(&lq->q_lock, cpu_flags);
+		}
+	} else if (host_byte(cmd->result) == DID_ERROR) {
+		/* device error */
+		ha->total_dev_errs++;
+	}
+
+	/* Call the mid-level driver interrupt handler */
+	(*(cmd)->scsi_done)(cmd);
+}
+
+/**************************************************************************
+* sp_put
+*
+* Description:
+*   Decrement reference count and call the callback if we're the last
+*   owner of the specified sp. Will get the host_lock before calling
+*   the callback.
+*
+* Input:
+*   ha - pointer to the scsi_qla_host_t where the callback is to occur.
+*   sp - pointer to srb_t structure to use.
+*
+* Returns:
+*
+**************************************************************************/
+static inline void
+sp_put(struct scsi_qla_host * ha, srb_t *sp)
+{
+        if (atomic_read(&sp->ref_count) == 0) {
+		qla_printk(KERN_INFO, ha,
+			"%s(): **** SP->ref_count not zero\n",
+			__func__);
+                DEBUG2(BUG();)
+
+                return;
+	}
+
+        if (!atomic_dec_and_test(&sp->ref_count)) {
+                return;
+        }
+
+        qla2x00_callback(ha, sp->cmd);
+}
+
+/**************************************************************************
+* sp_get
+*
+* Description:
+*   Increment reference count of the specified sp.
+*
+* Input:
+*   sp - pointer to srb_t structure to use.
+*
+* Returns:
+*
+**************************************************************************/
+static inline void
+sp_get(struct scsi_qla_host * ha, srb_t *sp)
+{
+        atomic_inc(&sp->ref_count);
+
+        if (atomic_read(&sp->ref_count) > 2) {
+		qla_printk(KERN_INFO, ha,
+			"%s(): **** SP->ref_count greater than two\n",
+			__func__);
+                DEBUG2(BUG();)
+
+		return;
+	}
+}
+
+static inline void 
+qla2x00_delete_from_done_queue(scsi_qla_host_t *dest_ha, srb_t *sp) 
+{
+	/* remove command from done list */
+	list_del_init(&sp->list);
+	dest_ha->done_q_cnt--;
+	sp->state = SRB_NO_QUEUE_STATE;
+
+	if (sp->flags & SRB_DMA_VALID) {
+		sp->flags &= ~SRB_DMA_VALID;
+
+		/* Release memory used for this I/O */
+		if (sp->cmd->use_sg) {
+			pci_unmap_sg(dest_ha->pdev, sp->cmd->request_buffer,
+			    sp->cmd->use_sg, sp->cmd->sc_data_direction);
+		} else if (sp->cmd->request_bufflen) {
+			pci_unmap_page(dest_ha->pdev, sp->dma_handle,
+			    sp->cmd->request_bufflen,
+			    sp->cmd->sc_data_direction);
+		}
+	}
+}
+
+static int qla2x00_do_dpc(void *data);
+
+static void qla2x00_rst_aen(scsi_qla_host_t *);
+
+static uint8_t qla2x00_mem_alloc(scsi_qla_host_t *);
+static void qla2x00_mem_free(scsi_qla_host_t *ha);
+static int qla2x00_allocate_sp_pool( scsi_qla_host_t *ha);
+static void qla2x00_free_sp_pool(scsi_qla_host_t *ha);
+static srb_t *qla2x00_get_new_sp(scsi_qla_host_t *ha);
+
+static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *, char *, loff_t,
+    size_t);
+static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *, char *, loff_t,
+    size_t);
+static struct bin_attribute sysfs_fw_dump_attr = {
+	.attr = {
+		.name = "fw_dump",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = 0,
+	.read = qla2x00_sysfs_read_fw_dump,
+	.write = qla2x00_sysfs_write_fw_dump,
+};
+static ssize_t qla2x00_sysfs_read_nvram(struct kobject *, char *, loff_t,
+    size_t);
+static ssize_t qla2x00_sysfs_write_nvram(struct kobject *, char *, loff_t,
+    size_t);
+static struct bin_attribute sysfs_nvram_attr = {
+	.attr = {
+		.name = "nvram",
+		.mode = S_IRUSR | S_IWUSR,
+		.owner = THIS_MODULE,
+	},
+	.size = sizeof(nvram_t),
+	.read = qla2x00_sysfs_read_nvram,
+	.write = qla2x00_sysfs_write_nvram,
+};
+
+/* -------------------------------------------------------------------------- */
+
+
+/* SysFS attributes. */
+static ssize_t qla2x00_sysfs_read_fw_dump(struct kobject *kobj, char *buf,
+    loff_t off, size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+
+	if (ha->fw_dump_reading == 0)
+		return 0;
+	if (off > ha->fw_dump_buffer_len)
+		return 0;
+	if (off + count > ha->fw_dump_buffer_len)
+		count = ha->fw_dump_buffer_len - off;
+
+	memcpy(buf, &ha->fw_dump_buffer[off], count);
+
+	return (count);
+}
+
+static ssize_t qla2x00_sysfs_write_fw_dump(struct kobject *kobj, char *buf,
+    loff_t off, size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	int reading;
+	uint32_t dump_size;
+
+	if (off != 0)
+		return (0);
+
+	reading = simple_strtol(buf, NULL, 10);
+	switch (reading) {
+	case 0:
+		if (ha->fw_dump_reading == 1) {
+			qla_printk(KERN_INFO, ha,
+			    "Firmware dump cleared on (%ld).\n",
+			    ha->host_no);
+
+			vfree(ha->fw_dump_buffer);
+			free_pages((unsigned long)ha->fw_dump,
+			    ha->fw_dump_order);
+
+			ha->fw_dump_reading = 0;
+			ha->fw_dump_buffer = NULL;
+			ha->fw_dump = NULL;
+		}
+		break;
+	case 1:
+		if (ha->fw_dump != NULL && !ha->fw_dump_reading) {
+			ha->fw_dump_reading = 1;
+
+			dump_size = FW_DUMP_SIZE_1M;
+			if (ha->fw_memory_size < 0x20000) 
+				dump_size = FW_DUMP_SIZE_128K;
+			else if (ha->fw_memory_size < 0x80000) 
+				dump_size = FW_DUMP_SIZE_512K;
+			ha->fw_dump_buffer = (char *)vmalloc(dump_size);
+			if (ha->fw_dump_buffer == NULL) {
+				qla_printk(KERN_WARNING, ha,
+				    "Unable to allocate memory for firmware "
+				    "dump buffer (%d).\n", dump_size);
+
+				ha->fw_dump_reading = 0;
+				return (count);
+			}
+			qla_printk(KERN_INFO, ha,
+			    "Firmware dump ready for read on (%ld).\n",
+			    ha->host_no);
+			memset(ha->fw_dump_buffer, 0, dump_size);
+			if (IS_QLA2100(ha) || IS_QLA2200(ha))
+ 				qla2100_ascii_fw_dump(ha);
+ 			else
+ 				qla2300_ascii_fw_dump(ha);
+			ha->fw_dump_buffer_len = strlen(ha->fw_dump_buffer);
+		}
+		break;
+	}
+	return (count);
+}
+
+static ssize_t qla2x00_sysfs_read_nvram(struct kobject *kobj, char *buf,
+    loff_t off, size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint16_t	*witer;
+	unsigned long	flags;
+	uint16_t	cnt;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+		return 0;
+
+	/* Read NVRAM. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qla2x00_lock_nvram_access(ha);
+ 	witer = (uint16_t *)buf;
+ 	for (cnt = 0; cnt < count / 2; cnt++) {
+		*witer = cpu_to_le16(qla2x00_get_nvram_word(ha,
+		    cnt+ha->nvram_base));
+		witer++;
+ 	}
+	qla2x00_unlock_nvram_access(ha);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (count);
+}
+
+static ssize_t qla2x00_sysfs_write_nvram(struct kobject *kobj, char *buf,
+    loff_t off, size_t count)
+{
+	struct scsi_qla_host *ha = to_qla_host(dev_to_shost(container_of(kobj,
+	    struct device, kobj)));
+	uint8_t		*iter;
+	uint16_t	*witer;
+	unsigned long	flags;
+	uint16_t	cnt;
+	uint8_t		chksum;
+
+	if (!capable(CAP_SYS_ADMIN) || off != 0 || count != sizeof(nvram_t))
+		return 0;
+
+	/* Checksum NVRAM. */
+	iter = (uint8_t *)buf;
+	chksum = 0;
+	for (cnt = 0; cnt < count - 1; cnt++)
+		chksum += *iter++;
+	chksum = ~chksum + 1;
+	*iter = chksum;
+
+	/* Write NVRAM. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	qla2x00_lock_nvram_access(ha);
+	qla2x00_release_nvram_protection(ha);
+ 	witer = (uint16_t *)buf;
+	for (cnt = 0; cnt < count / 2; cnt++) {
+		qla2x00_write_nvram_word(ha, cnt+ha->nvram_base,
+		    cpu_to_le16(*witer));
+		witer++;
+	}
+	qla2x00_unlock_nvram_access(ha);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	return (count);
+}
+
+/* -------------------------------------------------------------------------- */
+static char *
+qla2x00_get_pci_info_str(struct scsi_qla_host *ha, char *str)
+{
+	static char *pci_bus_modes[] = {
+		"33", "66", "100", "133",
+	};
+	uint16_t pci_bus;
+
+	strcpy(str, "PCI");
+	pci_bus = (ha->pci_attr & (BIT_9 | BIT_10)) >> 9;
+	if (pci_bus) {
+		strcat(str, "-X (");
+		strcat(str, pci_bus_modes[pci_bus]);
+	} else {
+		pci_bus = (ha->pci_attr & BIT_8) >> 8;
+		strcat(str, " (");
+		strcat(str, pci_bus_modes[pci_bus]);
+	}
+	strcat(str, " MHz)");
+
+	return (str);
+}
+
+char *
+qla2x00_get_fw_version_str(struct scsi_qla_host *ha, char *str)
+{
+	char un_str[10];
+	
+	sprintf(str, "%d.%02d.%02d ", ha->fw_major_version,
+	    ha->fw_minor_version,
+	    ha->fw_subminor_version);
+
+	if (ha->fw_attributes & BIT_9) {
+		strcat(str, "FLX");
+		return (str);
+	}
+
+	switch (ha->fw_attributes & 0xFF) {
+	case 0x7:
+		strcat(str, "EF");
+		break;
+	case 0x17:
+		strcat(str, "TP");
+		break;
+	case 0x37:
+		strcat(str, "IP");
+		break;
+	case 0x77:
+		strcat(str, "VI");
+		break;
+	default:
+		sprintf(un_str, "(%x)", ha->fw_attributes);
+		strcat(str, un_str);
+		break;
+	}
+	if (ha->fw_attributes & 0x100)
+		strcat(str, "X");
+
+	return (str);
+}
+
+/**************************************************************************
+* qla2x00_queuecommand
+*
+* Description:
+*     Queue a command to the controller.
+*
+* Input:
+*     cmd - pointer to Scsi cmd structure
+*     fn - pointer to Scsi done function
+*
+* Returns:
+*   0 - Always
+*
+* Note:
+* The mid-level driver tries to ensures that queuecommand never gets invoked
+* concurrently with itself or the interrupt handler (although the
+* interrupt handler may call this routine as part of request-completion
+* handling).
+**************************************************************************/
+static int
+qla2x00_queuecommand(struct scsi_cmnd *cmd, void (*fn)(struct scsi_cmnd *))
+{
+	fc_port_t	*fcport;
+	os_lun_t	*lq;
+	os_tgt_t	*tq;
+	scsi_qla_host_t	*ha, *ha2;
+	srb_t		*sp;
+	struct Scsi_Host *host;
+	unsigned int	b, t, l;
+	unsigned long	handle;
+	int		was_empty;
+
+
+	host = cmd->device->host;
+	ha = (scsi_qla_host_t *) host->hostdata;
+	was_empty = 1;
+
+	cmd->scsi_done = fn;
+
+	spin_unlock_irq(ha->host->host_lock);
+
+	/*
+	 * Allocate a command packet from the "sp" pool.  If we cant get back
+	 * one then let scsi layer come back later.
+	 */
+	if ((sp = qla2x00_get_new_sp(ha)) == NULL) {
+		qla_printk(KERN_WARNING, ha,
+		    "Couldn't allocate memory for sp - retried.\n");
+
+		spin_lock_irq(ha->host->host_lock);
+
+		return (1);
+	}
+
+	sp->cmd = cmd;
+	CMD_SP(cmd) = (void *)sp;
+
+	sp->flags = 0;
+	if (CMD_RESID_LEN(cmd) & SRB_IOCTL) {
+		/* Need to set sp->flags */
+		sp->flags |= SRB_IOCTL;
+		CMD_RESID_LEN(cmd) = 0; /* Clear it since no more use. */
+	}
+
+	sp->fo_retry_cnt = 0;
+	sp->err_id = 0;
+
+	/* Generate LU queue on bus, target, LUN */
+	b = cmd->device->channel;
+	t = cmd->device->id;
+	l = cmd->device->lun;
+
+	/*
+	 * Start Command Timer. Typically it will be 2 seconds less than what
+	 * is requested by the Host such that we can return the IO before
+	 * aborts are called.
+	 */
+	if ((cmd->timeout_per_command / HZ) > QLA_CMD_TIMER_DELTA)
+		qla2x00_add_timer_to_cmd(sp,
+		    (cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA);
+	else
+		qla2x00_add_timer_to_cmd(sp, cmd->timeout_per_command / HZ);
+
+	if (l >= ha->max_luns) {
+		cmd->result = DID_NO_CONNECT << 16;
+		sp->err_id = SRB_ERR_PORT;
+
+		spin_lock_irq(ha->host->host_lock);
+
+		sp_put(ha, sp);
+
+		return (0);
+	}
+
+	if ((tq = (os_tgt_t *) TGT_Q(ha, t)) != NULL &&
+	    (lq = (os_lun_t *) LUN_Q(ha, t, l)) != NULL) {
+		fcport = lq->fclun->fcport;
+		ha2 = fcport->ha;
+	} else {
+		lq = NULL;
+		fcport = NULL;
+		ha2 = ha;
+	}
+
+	/* Set an invalid handle until we issue the command to ISP */
+	/* then we will set the real handle value.                 */
+	handle = INVALID_HANDLE;
+	cmd->host_scribble = (unsigned char *)handle;
+
+	/* Bookkeeping information */
+	sp->r_start = jiffies;		/* Time the request was recieved. */
+	sp->u_start = 0;
+
+	/* Setup device queue pointers. */
+	sp->tgt_queue = tq;
+	sp->lun_queue = lq;
+
+	/*
+	 * NOTE : q is NULL
+	 *
+	 * 1. When device is added from persistent binding but has not been
+	 *    discovered yet.The state of loopid == PORT_AVAIL.
+	 * 2. When device is never found on the bus.(loopid == UNUSED)
+	 *
+	 * IF Device Queue is not created, or device is not in a valid state
+	 * and link down error reporting is enabled, reject IO.
+	 */
+	if (fcport == NULL) {
+		DEBUG3(printk("scsi(%ld:%2d:%2d): port unavailable\n",
+		    ha->host_no,t,l));
+
+		cmd->result = DID_NO_CONNECT << 16;
+		sp->err_id = SRB_ERR_PORT;
+
+		spin_lock_irq(ha->host->host_lock);
+
+		sp_put(ha, sp);
+
+		return (0);
+	}
+
+	/* Only modify the allowed count if the target is a *non* tape device */
+	if ((fcport->flags & FCF_TAPE_PRESENT) == 0) {
+		sp->flags &= ~SRB_TAPE;
+		if (cmd->allowed < ql2xretrycount) {
+			cmd->allowed = ql2xretrycount;
+		}
+	} else
+		sp->flags |= SRB_TAPE;
+
+	DEBUG5(printk("scsi(%ld:%2d:%2d): (queuecmd) queue sp = %p, "
+	    "flags=0x%x fo retry=%d, pid=%ld\n",
+	    ha->host_no, t, l, sp, sp->flags, sp->fo_retry_cnt,
+	    cmd->serial_number));
+	DEBUG5(qla2x00_print_scsi_cmd(cmd));
+
+	sp->fclun = lq->fclun;
+	sp->ha = ha2;
+
+	if (cmd->sc_data_direction == DMA_BIDIRECTIONAL &&
+	    cmd->request_bufflen != 0) {
+
+		DEBUG2(printk(KERN_WARNING
+		    "scsi(%ld): Incorrect data direction - transfer "
+		    "length=%d, direction=%d, pid=%ld, opcode=%x\n",
+		    ha->host_no, cmd->request_bufflen, cmd->sc_data_direction,
+		    cmd->serial_number, cmd->cmnd[0]));
+	}
+
+	/* Final pre-check :
+	 *
+	 *	Either PORT_DOWN_TIMER OR LINK_DOWN_TIMER Expired.
+	 */
+	if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
+	    atomic_read(&ha2->loop_state) == LOOP_DEAD) {
+		/*
+		 * Add the command to the done-queue for later failover
+		 * processing.
+		 */
+		cmd->result = DID_NO_CONNECT << 16;
+		if (atomic_read(&ha2->loop_state) == LOOP_DOWN) 
+			sp->err_id = SRB_ERR_LOOP;
+		else
+			sp->err_id = SRB_ERR_PORT;
+
+		add_to_done_queue(ha, sp);
+		qla2x00_done(ha);
+
+		spin_lock_irq(ha->host->host_lock);
+		return (0);
+	}
+
+	if (tq && test_bit(TQF_SUSPENDED, &tq->flags) &&
+	    (sp->flags & SRB_TAPE) == 0) {
+		/* If target suspended put incoming I/O in retry_q. */
+		qla2x00_extend_timeout(sp->cmd, 10);
+		add_to_scsi_retry_queue(ha, sp);
+	} else
+		was_empty = add_to_pending_queue(ha, sp);
+
+	if ((IS_QLA2100(ha) || IS_QLA2200(ha)) && ha->flags.online) {
+		if (ha->response_ring_ptr->signature != RESPONSE_PROCESSED) {
+			unsigned long flags;
+
+			spin_lock_irqsave(&ha->hardware_lock, flags);	
+			qla2x00_process_response_queue(ha);
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+		}
+	}
+
+	/* We submit to the hardware if:
+	 *
+	 *	1) we're on the cpu the irq's arrive on or
+	 *	2) there are very few io's outstanding.
+	 *
+	 * In all other cases we'll let an irq pick up our IO and submit it
+	 * to the controller to improve affinity.
+	 */
+	if (_smp_processor_id() == ha->last_irq_cpu || was_empty)
+		qla2x00_next(ha);
+
+	spin_lock_irq(ha->host->host_lock);
+
+	return (0);
+}
+
+/*
+ * qla2x00_eh_wait_on_command
+ *    Waits for the command to be returned by the Firmware for some
+ *    max time.
+ *
+ * Input:
+ *    ha = actual ha whose done queue will contain the command
+ *	      returned by firmware.
+ *    cmd = Scsi Command to wait on.
+ *    flag = Abort/Reset(Bus or Device Reset)
+ *
+ * Return:
+ *    Not Found : 0
+ *    Found : 1
+ */
+static int
+qla2x00_eh_wait_on_command(scsi_qla_host_t *ha, struct scsi_cmnd *cmd)
+{
+#define ABORT_POLLING_PERIOD	HZ
+#define ABORT_WAIT_TIME		((10 * HZ) / (ABORT_POLLING_PERIOD))
+
+	int		found = 0;
+	int		done = 0;
+	srb_t		*rp = NULL;
+	struct list_head *list, *temp;
+	u_long		max_wait_time = ABORT_WAIT_TIME;
+
+	do {
+		/* Check on done queue */
+		spin_lock(&ha->list_lock);
+		list_for_each_safe(list, temp, &ha->done_queue) {
+			rp = list_entry(list, srb_t, list);
+
+			/*
+			 * Found command. Just exit and wait for the cmd sent
+			 * to OS.
+			*/
+			if (cmd == rp->cmd) {
+				found++;
+				DEBUG3(printk("%s: found in done queue.\n",
+				    __func__);)
+				break;
+			}
+		}
+		spin_unlock(&ha->list_lock);
+
+		/* Complete the cmd right away. */
+		if (found) { 
+			qla2x00_delete_from_done_queue(ha, rp);
+			sp_put(ha, rp);
+			done++;
+			break;
+		}
+
+		spin_unlock_irq(ha->host->host_lock);
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(ABORT_POLLING_PERIOD);
+
+		spin_lock_irq(ha->host->host_lock);
+
+	} while ((max_wait_time--));
+
+	if (done)
+		DEBUG2(printk(KERN_INFO "%s: found cmd=%p.\n", __func__, cmd));
+
+	return (done);
+}
+
+/*
+ * qla2x00_wait_for_hba_online
+ *    Wait till the HBA is online after going through 
+ *    <= MAX_RETRIES_OF_ISP_ABORT  or
+ *    finally HBA is disabled ie marked offline
+ *
+ * Input:
+ *     ha - pointer to host adapter structure
+ * 
+ * Note:    
+ *    Does context switching-Release SPIN_LOCK
+ *    (if any) before calling this routine.
+ *
+ * Return:
+ *    Success (Adapter is online) : 0
+ *    Failed  (Adapter is offline/disabled) : 1
+ */
+static int 
+qla2x00_wait_for_hba_online(scsi_qla_host_t *ha)
+{
+	int 	 return_status;
+	unsigned long wait_online;
+
+	wait_online = jiffies + (MAX_LOOP_TIMEOUT * HZ); 
+	while (((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) ||
+	    test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags) ||
+	    test_bit(ISP_ABORT_RETRY, &ha->dpc_flags) ||
+	    ha->dpc_active) && time_before(jiffies, wait_online)) {
+
+		msleep(1000);
+	}
+	if (ha->flags.online) 
+		return_status = QLA_SUCCESS; 
+	else
+		return_status = QLA_FUNCTION_FAILED;
+
+	DEBUG2(printk("%s return_status=%d\n",__func__,return_status));
+
+	return (return_status);
+}
+
+/*
+ * qla2x00_wait_for_loop_ready
+ *    Wait for MAX_LOOP_TIMEOUT(5 min) value for loop
+ *    to be in LOOP_READY state.	 
+ * Input:
+ *     ha - pointer to host adapter structure
+ * 
+ * Note:    
+ *    Does context switching-Release SPIN_LOCK
+ *    (if any) before calling this routine.
+ *    
+ *
+ * Return:
+ *    Success (LOOP_READY) : 0
+ *    Failed  (LOOP_NOT_READY) : 1
+ */
+static inline int 
+qla2x00_wait_for_loop_ready(scsi_qla_host_t *ha)
+{
+	int 	 return_status = QLA_SUCCESS;
+	unsigned long loop_timeout ;
+
+	/* wait for 5 min at the max for loop to be ready */
+	loop_timeout = jiffies + (MAX_LOOP_TIMEOUT * HZ); 
+
+	while ((!atomic_read(&ha->loop_down_timer) &&
+	    atomic_read(&ha->loop_state) == LOOP_DOWN) ||
+	    test_bit(CFG_ACTIVE, &ha->cfg_flags) ||
+	    atomic_read(&ha->loop_state) != LOOP_READY) {
+		msleep(1000);
+		if (time_after_eq(jiffies, loop_timeout)) {
+			return_status = QLA_FUNCTION_FAILED;
+			break;
+		}
+	}
+	return (return_status);	
+}
+
+/**************************************************************************
+* qla2xxx_eh_abort
+*
+* Description:
+*    The abort function will abort the specified command.
+*
+* Input:
+*    cmd = Linux SCSI command packet to be aborted.
+*
+* Returns:
+*    Either SUCCESS or FAILED.
+*
+* Note:
+**************************************************************************/
+int
+qla2xxx_eh_abort(struct scsi_cmnd *cmd)
+{
+	int		i;
+	int		return_status = FAILED;
+	os_lun_t	*q;
+	scsi_qla_host_t *ha;
+	scsi_qla_host_t *vis_ha;
+	srb_t		*sp;
+	srb_t		*rp;
+	struct list_head *list, *temp;
+	struct Scsi_Host *host;
+	uint8_t		found = 0;
+	unsigned int	b, t, l;
+
+	/* Get the SCSI request ptr */
+	sp = (srb_t *) CMD_SP(cmd);
+
+	/*
+	 * If sp is NULL, command is already returned.
+	 * sp is NULLED just before we call back scsi_done
+	 *
+	 */
+	if ((sp == NULL)) {
+		/* no action - we don't have command */
+		qla_printk(KERN_INFO, to_qla_host(cmd->device->host),
+		    "qla2xxx_eh_abort: cmd already done sp=%p\n", sp);
+		DEBUG(printk("qla2xxx_eh_abort: cmd already done sp=%p\n", sp);)
+		return SUCCESS;
+	}
+	if (sp) {
+		DEBUG(printk("qla2xxx_eh_abort: refcount %i \n",
+		    atomic_read(&sp->ref_count));)
+	}
+
+	vis_ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
+	ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
+
+	host = ha->host;
+
+	/* Generate LU queue on bus, target, LUN */
+	b = cmd->device->channel;
+	t = cmd->device->id;
+	l = cmd->device->lun;
+	q = GET_LU_Q(vis_ha, t, l);
+
+	qla_printk(KERN_INFO, ha, 
+	    "%s scsi(%ld:%d:%d:%d): cmd_timeout_in_sec=0x%x.\n", __func__,
+	    ha->host_no, (int)b, (int)t, (int)l,
+	    cmd->timeout_per_command / HZ);
+
+	/*
+	 * if no LUN queue then something is very wrong!!!
+	 */
+	if (q == NULL) {
+		qla_printk(KERN_WARNING, ha,
+			"qla2x00: (%x:%x:%x) No LUN queue.\n", b, t, l);
+
+		/* no action - we don't have command */
+		return FAILED;
+	}
+
+	DEBUG2(printk("scsi(%ld): ABORTing cmd=%p sp=%p jiffies = 0x%lx, "
+	    "timeout=%x, dpc_flags=%lx, vis_ha->dpc_flags=%lx q->flag=%lx\n",
+	    ha->host_no, cmd, sp, jiffies, cmd->timeout_per_command / HZ,
+	    ha->dpc_flags, vis_ha->dpc_flags, q->q_flag));
+	DEBUG2(qla2x00_print_scsi_cmd(cmd));
+
+	spin_unlock_irq(ha->host->host_lock);
+	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
+		DEBUG2(printk("%s failed:board disabled\n", __func__);)
+		spin_lock_irq(ha->host->host_lock);
+		return FAILED;
+	}
+	spin_lock_irq(ha->host->host_lock);
+
+	/* Search done queue */
+	spin_lock(&ha->list_lock);
+	list_for_each_safe(list, temp, &ha->done_queue) {
+		rp = list_entry(list, srb_t, list);
+
+		if (cmd != rp->cmd)
+			continue;
+
+		/*
+		 * Found command.Remove it from done list.
+		 * And proceed to post completion to scsi mid layer.
+		 */
+		return_status = SUCCESS;
+		found++;
+		qla2x00_delete_from_done_queue(ha, sp);
+
+		break;
+	} /* list_for_each_safe() */
+	spin_unlock(&ha->list_lock);
+
+	/*
+	 * Return immediately if the aborted command was already in the done
+	 * queue
+	 */
+	if (found) {
+		qla_printk(KERN_INFO, ha,
+		    "qla2xxx_eh_abort: Returning completed command=%p sp=%p\n",
+		    cmd, sp);
+		sp_put(ha, sp);
+		return (return_status);
+	}
+	
+
+	/*
+	 * See if this command is in the retry queue
+	 */
+	DEBUG3(printk("qla2xxx_eh_abort: searching sp %p in retry "
+		    "queue.\n", sp);)
+
+	spin_lock(&ha->list_lock);
+	list_for_each_safe(list, temp, &ha->retry_queue) {
+		rp = list_entry(list, srb_t, list);
+
+		if (cmd != rp->cmd)
+			continue;
+
+
+		DEBUG2(printk("qla2xxx_eh_abort: found "
+		    "in retry queue. SP=%p\n", sp);)
+
+		__del_from_retry_queue(ha, rp);
+		cmd->result = DID_ABORT << 16;
+		__add_to_done_queue(ha, rp);
+
+		return_status = SUCCESS;
+		found++;
+
+		break;
+
+	} 
+	spin_unlock(&ha->list_lock);
+
+
+	/*
+	 * Our SP pointer points at the command we want to remove from the
+	 * pending queue providing we haven't already sent it to the adapter.
+	 */
+	if (!found) {
+		DEBUG3(printk("qla2xxx_eh_abort: searching sp %p "
+		    "in pending queue.\n", sp);)
+
+		spin_lock(&vis_ha->list_lock);
+		list_for_each_safe(list, temp, &vis_ha->pending_queue) {
+			rp = list_entry(list, srb_t, list);
+
+			if (rp->cmd != cmd)
+				continue;
+
+			/* Remove srb from LUN queue. */
+			rp->flags |=  SRB_ABORTED;
+
+			DEBUG2(printk("qla2xxx_eh_abort: Cmd in pending queue."
+			    " serial_number %ld.\n",
+			    sp->cmd->serial_number);)
+
+			__del_from_pending_queue(vis_ha, rp);
+			cmd->result = DID_ABORT << 16;
+
+			__add_to_done_queue(vis_ha, rp);
+
+			return_status = SUCCESS;
+
+			found++;
+			break;
+		} /* list_for_each_safe() */
+		spin_unlock(&vis_ha->list_lock);
+	} /*End of if !found */
+
+	if (!found) {  /* find the command in our active list */
+		DEBUG3(printk("qla2xxx_eh_abort: searching sp %p "
+		    "in outstanding queue.\n", sp);)
+
+		spin_lock(&ha->hardware_lock);
+		for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) {
+			sp = ha->outstanding_cmds[i];
+
+			if (sp == NULL)
+				continue;
+
+			if (sp->cmd != cmd)
+				continue;
+
+			DEBUG2(printk("qla2xxx_eh_abort(%ld): aborting sp %p "
+			    "from RISC. pid=%ld sp->state=%x q->q_flag=%lx\n",
+			    ha->host_no, sp, sp->cmd->serial_number,
+			    sp->state, q->q_flag);)
+			DEBUG(qla2x00_print_scsi_cmd(cmd);)
+
+			/* Get a reference to the sp and drop the lock.*/
+			sp_get(ha, sp);
+
+			spin_unlock(&ha->hardware_lock);
+			spin_unlock_irq(ha->host->host_lock);
+
+			if (qla2x00_abort_command(ha, sp)) {
+				DEBUG2(printk("qla2xxx_eh_abort: abort_command "
+				    "mbx failed.\n");)
+				return_status = FAILED;
+			} else {
+				DEBUG3(printk("qla2xxx_eh_abort: abort_command "
+				    " mbx success.\n");)
+				return_status = SUCCESS;
+			}
+
+			sp_put(ha,sp);
+
+			spin_lock_irq(ha->host->host_lock);
+			spin_lock(&ha->hardware_lock);
+
+			/*
+			 * Regardless of mailbox command status, go check on
+			 * done queue just in case the sp is already done.
+			 */
+			break;
+
+		}/*End of for loop */
+		spin_unlock(&ha->hardware_lock);
+
+	} /*End of if !found */
+
+	/* Waiting for our command in done_queue to be returned to OS.*/
+	if (qla2x00_eh_wait_on_command(ha, cmd) != 0) {
+		DEBUG2(printk("qla2xxx_eh_abort: cmd returned back to OS.\n");)
+		return_status = SUCCESS;
+	}
+
+	if (return_status == FAILED) {
+		qla_printk(KERN_INFO, ha, 
+			"qla2xxx_eh_abort Exiting: status=Failed\n");
+		return FAILED;
+	}
+
+	DEBUG2(printk("qla2xxx_eh_abort: Exiting. return_status=0x%x.\n",
+	    return_status));
+
+	return return_status;
+}
+
+/**************************************************************************
+* qla2x00_eh_wait_for_pending_target_commands
+*
+* Description:
+*    Waits for all the commands to come back from the specified target.
+*
+* Input:
+*    ha - pointer to scsi_qla_host structure.
+*    t  - target 	
+* Returns:
+*    Either SUCCESS or FAILED.
+*
+* Note:
+**************************************************************************/
+static int
+qla2x00_eh_wait_for_pending_target_commands(scsi_qla_host_t *ha, unsigned int t)
+{
+	int	cnt;
+	int	status;
+	srb_t		*sp;
+	struct scsi_cmnd *cmd;
+
+	status = 0;
+
+	/*
+	 * Waiting for all commands for the designated target in the active
+	 * array
+	 */
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		spin_lock(&ha->hardware_lock);
+		sp = ha->outstanding_cmds[cnt];
+		if (sp) {
+			cmd = sp->cmd;
+			spin_unlock(&ha->hardware_lock);
+			if (cmd->device->id == t) {
+				if (!qla2x00_eh_wait_on_command(ha, cmd)) {
+					status = 1;
+					break;
+				}
+			}
+		}
+		else {
+			spin_unlock(&ha->hardware_lock);
+		}
+	}
+	return (status);
+}
+
+
+/**************************************************************************
+* qla2xxx_eh_device_reset
+*
+* Description:
+*    The device reset function will reset the target and abort any
+*    executing commands.
+*
+*    NOTE: The use of SP is undefined within this context.  Do *NOT*
+*          attempt to use this value, even if you determine it is 
+*          non-null.
+*
+* Input:
+*    cmd = Linux SCSI command packet of the command that cause the
+*          bus device reset.
+*
+* Returns:
+*    SUCCESS/FAILURE (defined as macro in scsi.h).
+*
+**************************************************************************/
+int
+qla2xxx_eh_device_reset(struct scsi_cmnd *cmd)
+{
+	int		return_status;
+	unsigned int	b, t, l;
+	scsi_qla_host_t	*ha;
+	os_tgt_t	*tq;
+	os_lun_t	*lq;
+	fc_port_t	*fcport_to_reset;
+	srb_t		*rp;
+	struct list_head *list, *temp;
+
+	return_status = FAILED;
+	if (cmd == NULL) {
+		printk(KERN_INFO
+		    "%s(): **** SCSI mid-layer passing in NULL cmd\n",
+		    __func__);
+
+		return (return_status);
+	}
+
+	b = cmd->device->channel;
+	t = cmd->device->id;
+	l = cmd->device->lun;
+	ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
+
+	tq = TGT_Q(ha, t);
+	if (tq == NULL) {
+		qla_printk(KERN_INFO, ha,
+		    "%s(): **** CMD derives a NULL TGT_Q\n", __func__);
+
+		return (return_status);
+	}
+	lq = (os_lun_t *)LUN_Q(ha, t, l);
+	if (lq == NULL) {
+		printk(KERN_INFO
+		    "%s(): **** CMD derives a NULL LUN_Q\n", __func__);
+
+		return (return_status);
+	}
+	fcport_to_reset = lq->fclun->fcport;
+
+	/* If we are coming in from the back-door, stall I/O until complete. */
+	if (!cmd->device->host->eh_active)
+		set_bit(TQF_SUSPENDED, &tq->flags);
+
+	qla_printk(KERN_INFO, ha,
+	    "scsi(%ld:%d:%d:%d): DEVICE RESET ISSUED.\n", ha->host_no, b, t, l);
+
+	DEBUG2(printk(KERN_INFO
+	    "scsi(%ld): DEVICE_RESET cmd=%p jiffies = 0x%lx, timeout=%x, "
+	    "dpc_flags=%lx, status=%x allowed=%d cmd.state=%x\n",
+	    ha->host_no, cmd, jiffies, cmd->timeout_per_command / HZ,
+	    ha->dpc_flags, cmd->result, cmd->allowed, cmd->state));
+
+ 	/* Clear commands from the retry queue. */
+ 	spin_lock(&ha->list_lock);
+ 	list_for_each_safe(list, temp, &ha->retry_queue) {
+ 		rp = list_entry(list, srb_t, list);
+ 
+ 		if (t != rp->cmd->device->id) 
+ 			continue;
+ 
+ 		DEBUG2(printk(KERN_INFO
+		    "qla2xxx_eh_reset: found in retry queue. SP=%p\n", rp));
+ 
+ 		__del_from_retry_queue(ha, rp);
+ 		rp->cmd->result = DID_RESET << 16;
+ 		__add_to_done_queue(ha, rp);
+ 	}
+ 	spin_unlock(&ha->list_lock);
+
+	spin_unlock_irq(ha->host->host_lock);
+
+	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
+		DEBUG2(printk(KERN_INFO
+		    "%s failed:board disabled\n",__func__));
+
+		spin_lock_irq(ha->host->host_lock);
+		goto eh_dev_reset_done;
+	}
+
+	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
+		if (qla2x00_device_reset(ha, fcport_to_reset) == 0) {
+			return_status = SUCCESS;
+		}
+
+#if defined(LOGOUT_AFTER_DEVICE_RESET)
+		if (return_status == SUCCESS) {
+			if (fcport_to_reset->flags & FC_FABRIC_DEVICE) {
+				qla2x00_fabric_logout(ha,
+				    fcport_to_reset->loop_id);
+				qla2x00_mark_device_lost(ha, fcport_to_reset);
+			}
+		}
+#endif
+	} else {
+		DEBUG2(printk(KERN_INFO
+		    "%s failed: loop not ready\n",__func__);)
+	}
+
+	spin_lock_irq(ha->host->host_lock);
+
+	if (return_status == FAILED) {
+		DEBUG3(printk("%s(%ld): device reset failed\n",
+		    __func__, ha->host_no));
+		qla_printk(KERN_INFO, ha, "%s: device reset failed\n",
+		    __func__);
+
+		goto eh_dev_reset_done;
+	}
+
+	/*
+	 * If we are coming down the EH path, wait for all commands to
+	 * complete for the device.
+	 */
+	if (cmd->device->host->eh_active) {
+		if (qla2x00_eh_wait_for_pending_target_commands(ha, t))
+			return_status = FAILED;
+
+		if (return_status == FAILED) {
+			DEBUG3(printk("%s(%ld): failed while waiting for "
+			    "commands\n", __func__, ha->host_no));
+			qla_printk(KERN_INFO, ha,
+			    "%s: failed while waiting for commands\n",
+			    __func__); 
+
+			goto eh_dev_reset_done;
+		}
+	}
+
+	qla_printk(KERN_INFO, ha,
+	    "scsi(%ld:%d:%d:%d): DEVICE RESET SUCCEEDED.\n",
+	    ha->host_no, b, t, l);
+
+eh_dev_reset_done:
+
+	if (!cmd->device->host->eh_active)
+		clear_bit(TQF_SUSPENDED, &tq->flags);
+
+	return (return_status);
+}
+
+/**************************************************************************
+* qla2x00_eh_wait_for_pending_commands
+*
+* Description:
+*    Waits for all the commands to come back from the specified host.
+*
+* Input:
+*    ha - pointer to scsi_qla_host structure.
+*
+* Returns:
+*    1 : SUCCESS
+*    0 : FAILED
+*
+* Note:
+**************************************************************************/
+static int
+qla2x00_eh_wait_for_pending_commands(scsi_qla_host_t *ha)
+{
+	int	cnt;
+	int	status;
+	srb_t		*sp;
+	struct scsi_cmnd *cmd;
+
+	status = 1;
+
+	/*
+	 * Waiting for all commands for the designated target in the active
+	 * array
+	 */
+	for (cnt = 1; cnt < MAX_OUTSTANDING_COMMANDS; cnt++) {
+		spin_lock(&ha->hardware_lock);
+		sp = ha->outstanding_cmds[cnt];
+		if (sp) {
+			cmd = sp->cmd;
+			spin_unlock(&ha->hardware_lock);
+			status = qla2x00_eh_wait_on_command(ha, cmd);
+			if (status == 0)
+				break;
+		}
+		else {
+			spin_unlock(&ha->hardware_lock);
+		}
+	}
+	return (status);
+}
+
+
+/**************************************************************************
+* qla2xxx_eh_bus_reset
+*
+* Description:
+*    The bus reset function will reset the bus and abort any executing
+*    commands.
+*
+* Input:
+*    cmd = Linux SCSI command packet of the command that cause the
+*          bus reset.
+*
+* Returns:
+*    SUCCESS/FAILURE (defined as macro in scsi.h).
+*
+**************************************************************************/
+int
+qla2xxx_eh_bus_reset(struct scsi_cmnd *cmd)
+{
+	scsi_qla_host_t *ha;
+	srb_t *sp;
+	int rval = FAILED;
+
+	ha = (scsi_qla_host_t *) cmd->device->host->hostdata;
+	sp = (srb_t *) CMD_SP(cmd);
+
+	qla_printk(KERN_INFO, ha,
+	    "scsi(%ld:%d:%d:%d): LOOP RESET ISSUED.\n", ha->host_no,
+	    cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+	spin_unlock_irq(ha->host->host_lock);
+
+	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS) {
+		DEBUG2(printk("%s failed:board disabled\n",__func__));
+		spin_lock_irq(ha->host->host_lock);
+		return FAILED;
+	}
+
+	if (qla2x00_wait_for_loop_ready(ha) == QLA_SUCCESS) {
+		if (qla2x00_loop_reset(ha) == QLA_SUCCESS) 
+			rval = SUCCESS;
+	}
+
+	spin_lock_irq(ha->host->host_lock);
+	if (rval == FAILED)
+		goto out;
+
+	/* Waiting for our command in done_queue to be returned to OS.*/
+	if (cmd->device->host->eh_active)
+		if (!qla2x00_eh_wait_for_pending_commands(ha))
+			rval = FAILED;
+
+ out:
+	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
+			(rval == FAILED) ? "failed" : "succeded");
+
+	return rval;
+}
+
+/**************************************************************************
+* qla2xxx_eh_host_reset
+*
+* Description:
+*    The reset function will reset the Adapter.
+*
+* Input:
+*      cmd = Linux SCSI command packet of the command that cause the
+*            adapter reset.
+*
+* Returns:
+*      Either SUCCESS or FAILED.
+*
+* Note:
+**************************************************************************/
+int
+qla2xxx_eh_host_reset(struct scsi_cmnd *cmd)
+{
+	scsi_qla_host_t *ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
+	int		rval = SUCCESS;
+
+	/* Display which one we're actually resetting for debug. */
+	DEBUG(printk("qla2xxx_eh_host_reset:Resetting scsi(%ld).\n",
+	    ha->host_no));
+
+	/*
+	 *  Now issue reset.
+	 */
+	qla_printk(KERN_INFO, ha,
+	    "scsi(%ld:%d:%d:%d): ADAPTER RESET issued.\n", ha->host_no,
+	    cmd->device->channel, cmd->device->id, cmd->device->lun);
+
+	spin_unlock_irq(ha->host->host_lock);
+
+	if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
+		goto board_disabled;
+
+	/*
+	 * Fixme-may be dpc thread is active and processing
+	 * loop_resync,so wait a while for it to 
+	 * be completed and then issue big hammer.Otherwise
+	 * it may cause I/O failure as big hammer marks the
+	 * devices as lost kicking of the port_down_timer
+	 * while dpc is stuck for the mailbox to complete.
+	 */
+	/* Blocking call-Does context switching if loop is Not Ready */
+	qla2x00_wait_for_loop_ready(ha);
+	set_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+	if (qla2x00_abort_isp(ha)) {
+		clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+		/* failed. schedule dpc to try */
+		set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+
+		if (qla2x00_wait_for_hba_online(ha) != QLA_SUCCESS)
+			goto board_disabled;
+	} 
+
+	clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+
+	spin_lock_irq(ha->host->host_lock);
+	if (rval == FAILED)
+		goto out;
+
+	/* Waiting for our command in done_queue to be returned to OS.*/
+	if (!qla2x00_eh_wait_for_pending_commands(ha))
+		rval = FAILED;
+
+ out:
+	qla_printk(KERN_INFO, ha, "%s: reset %s\n", __func__,
+			(rval == FAILED) ? "failed" : "succeded");
+
+	return rval;
+
+ board_disabled:
+	spin_lock_irq(ha->host->host_lock);
+
+	qla_printk(KERN_INFO, ha, "%s: failed:board disabled\n", __func__);
+	return FAILED;
+}
+
+
+/*
+* qla2x00_loop_reset
+*      Issue loop reset.
+*
+* Input:
+*      ha = adapter block pointer.
+*
+* Returns:
+*      0 = success
+*/
+static int
+qla2x00_loop_reset(scsi_qla_host_t *ha)
+{
+	int status = QLA_SUCCESS;
+	uint16_t t;
+	os_tgt_t        *tq;
+
+	if (ha->flags.enable_lip_reset) {
+		status = qla2x00_lip_reset(ha);
+	}
+
+	if (status == QLA_SUCCESS && ha->flags.enable_target_reset) {
+		for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
+			if ((tq = TGT_Q(ha, t)) == NULL)
+				continue;
+
+			if (tq->fcport == NULL)
+				continue;
+
+			status = qla2x00_target_reset(ha, 0, t);
+			if (status != QLA_SUCCESS) {
+				break;
+			}
+		}
+	}
+
+	if (status == QLA_SUCCESS &&
+		((!ha->flags.enable_target_reset && 
+		  !ha->flags.enable_lip_reset) ||
+		ha->flags.enable_lip_full_login)) {
+
+		status = qla2x00_full_login_lip(ha);
+	}
+
+	/* Issue marker command only when we are going to start the I/O */
+	ha->marker_needed = 1;
+
+	if (status) {
+		/* Empty */
+		DEBUG2_3(printk("%s(%ld): **** FAILED ****\n",
+				__func__,
+				ha->host_no);)
+	} else {
+		/* Empty */
+		DEBUG3(printk("%s(%ld): exiting normally.\n",
+				__func__,
+				ha->host_no);)
+	}
+
+	return(status);
+}
+
+/*
+ * qla2x00_device_reset
+ *	Issue bus device reset message to the target.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	t = SCSI ID.
+ *	TARGET_QUEUE_LOCK must be released.
+ *	ADAPTER_STATE_LOCK must be released.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static int
+qla2x00_device_reset(scsi_qla_host_t *ha, fc_port_t *reset_fcport)
+{
+	/* Abort Target command will clear Reservation */
+	return qla2x00_abort_target(reset_fcport);
+}
+
+/**************************************************************************
+* qla2xxx_slave_configure
+*
+* Description:
+**************************************************************************/
+int
+qla2xxx_slave_configure(struct scsi_device *sdev)
+{
+	scsi_qla_host_t *ha = to_qla_host(sdev->host);
+	int queue_depth;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		queue_depth = 16;
+	else
+		queue_depth = 32;
+
+	if (sdev->tagged_supported) {
+		if (ql2xmaxqdepth != 0 && ql2xmaxqdepth <= 0xffffU)
+			queue_depth = ql2xmaxqdepth;
+
+		ql2xmaxqdepth = queue_depth;
+
+		scsi_activate_tcq(sdev, queue_depth);
+
+		qla_printk(KERN_INFO, ha,
+		    "scsi(%d:%d:%d:%d): Enabled tagged queuing, queue "
+		    "depth %d.\n",
+		    sdev->host->host_no, sdev->channel, sdev->id, sdev->lun,
+		    sdev->queue_depth);
+	} else {
+		 scsi_adjust_queue_depth(sdev, 0 /* TCQ off */,
+		     sdev->host->hostt->cmd_per_lun /* 3 */);
+	}
+
+	return (0);
+}
+
+/**
+ * qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
+ * @ha: HA context
+ *
+ * At exit, the @ha's flags.enable_64bit_addressing set to indicated
+ * supported addressing method.
+ */
+static void
+qla2x00_config_dma_addressing(scsi_qla_host_t *ha)
+{
+	/* Assume 32bit DMA address */
+	ha->flags.enable_64bit_addressing = 0;
+	ha->calc_request_entries = qla2x00_calc_iocbs_32;
+	ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_32;
+
+	/*
+	 * Given the two variants pci_set_dma_mask(), allow the compiler to
+	 * assist in setting the proper dma mask.
+	 */
+	if (sizeof(dma_addr_t) > 4) {
+		if (pci_set_dma_mask(ha->pdev, DMA_64BIT_MASK) == 0) {
+			ha->flags.enable_64bit_addressing = 1;
+			ha->calc_request_entries = qla2x00_calc_iocbs_64;
+			ha->build_scsi_iocbs = qla2x00_build_scsi_iocbs_64;
+
+			if (pci_set_consistent_dma_mask(ha->pdev,
+			    DMA_64BIT_MASK)) {
+				qla_printk(KERN_DEBUG, ha, 
+				    "Failed to set 64 bit PCI consistent mask; "
+				    "using 32 bit.\n");
+				pci_set_consistent_dma_mask(ha->pdev,
+				    DMA_32BIT_MASK);
+			}
+		} else {
+			qla_printk(KERN_DEBUG, ha,
+			    "Failed to set 64 bit PCI DMA mask, falling back "
+			    "to 32 bit MASK.\n");
+			pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
+		}
+	} else {
+		pci_set_dma_mask(ha->pdev, DMA_32BIT_MASK);
+	}
+}
+
+static int
+qla2x00_iospace_config(scsi_qla_host_t *ha)
+{
+	unsigned long	pio, pio_len, pio_flags;
+	unsigned long	mmio, mmio_len, mmio_flags;
+
+	/* We only need PIO for Flash operations on ISP2312 v2 chips. */
+	pio = pci_resource_start(ha->pdev, 0);
+	pio_len = pci_resource_len(ha->pdev, 0);
+	pio_flags = pci_resource_flags(ha->pdev, 0);
+	if (pio_flags & IORESOURCE_IO) {
+		if (pio_len < MIN_IOBASE_LEN) {
+			qla_printk(KERN_WARNING, ha,
+			    "Invalid PCI I/O region size (%s)...\n",
+				pci_name(ha->pdev));
+			pio = 0;
+		}
+	} else {
+		qla_printk(KERN_WARNING, ha,
+		    "region #0 not a PIO resource (%s)...\n",
+		    pci_name(ha->pdev));
+		pio = 0;
+	}
+
+	/* Use MMIO operations for all accesses. */
+	mmio = pci_resource_start(ha->pdev, 1);
+	mmio_len = pci_resource_len(ha->pdev, 1);
+	mmio_flags = pci_resource_flags(ha->pdev, 1);
+
+	if (!(mmio_flags & IORESOURCE_MEM)) {
+		qla_printk(KERN_ERR, ha,
+		    "region #0 not an MMIO resource (%s), aborting\n",
+		    pci_name(ha->pdev));
+		goto iospace_error_exit;
+	}
+	if (mmio_len < MIN_IOBASE_LEN) {
+		qla_printk(KERN_ERR, ha,
+		    "Invalid PCI mem region size (%s), aborting\n",
+			pci_name(ha->pdev));
+		goto iospace_error_exit;
+	}
+
+	if (pci_request_regions(ha->pdev, ha->brd_info->drv_name)) {
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to reserve PIO/MMIO regions (%s)\n",
+		    pci_name(ha->pdev));
+
+		goto iospace_error_exit;
+	}
+
+	ha->pio_address = pio;
+	ha->pio_length = pio_len;
+	ha->iobase = ioremap(mmio, MIN_IOBASE_LEN);
+	if (!ha->iobase) {
+		qla_printk(KERN_ERR, ha,
+		    "cannot remap MMIO (%s), aborting\n", pci_name(ha->pdev));
+
+		goto iospace_error_exit;
+	}
+
+	return (0);
+
+iospace_error_exit:
+	return (-ENOMEM);
+}
+
+/*
+ * PCI driver interface
+ */
+int qla2x00_probe_one(struct pci_dev *pdev, struct qla_board_info *brd_info)
+{
+	int	ret;
+	device_reg_t __iomem *reg;
+	struct Scsi_Host *host;
+	scsi_qla_host_t *ha;
+	unsigned long	flags = 0;
+	unsigned long	wait_switch = 0;
+	char pci_info[20];
+	char fw_str[30];
+
+	if (pci_enable_device(pdev))
+		return -1;
+
+	host = scsi_host_alloc(&qla2x00_driver_template,
+	    sizeof(scsi_qla_host_t));
+	if (host == NULL) {
+		printk(KERN_WARNING
+		    "qla2xxx: Couldn't allocate host from scsi layer!\n");
+		goto probe_disable_device;
+	}
+
+	/* Clear our data area */
+	ha = (scsi_qla_host_t *)host->hostdata;
+	memset(ha, 0, sizeof(scsi_qla_host_t));
+
+	ha->pdev = pdev;
+	ha->host = host;
+	ha->host_no = host->host_no;
+	ha->brd_info = brd_info;
+	sprintf(ha->host_str, "%s_%ld", ha->brd_info->drv_name, ha->host_no);
+
+	/* Configure PCI I/O space */
+	ret = qla2x00_iospace_config(ha);
+	if (ret != 0) {
+		goto probe_failed;
+	}
+
+	/* Sanitize the information from PCI BIOS. */
+	host->irq = pdev->irq;
+
+	qla_printk(KERN_INFO, ha,
+	    "Found an %s, irq %d, iobase 0x%p\n", ha->brd_info->isp_name,
+	    host->irq, ha->iobase);
+
+	spin_lock_init(&ha->hardware_lock);
+
+	/* 4.23 Initialize /proc/scsi/qla2x00 counters */
+	ha->actthreads = 0;
+	ha->qthreads   = 0;
+	ha->total_isr_cnt = 0;
+	ha->total_isp_aborts = 0;
+	ha->total_lip_cnt = 0;
+	ha->total_dev_errs = 0;
+	ha->total_ios = 0;
+	ha->total_bytes = 0;
+
+	ha->prev_topology = 0;
+	ha->ports = MAX_BUSES;
+
+	if (IS_QLA2100(ha)) {
+		ha->max_targets = MAX_TARGETS_2100;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT_2100;
+		ha->request_q_length = REQUEST_ENTRY_CNT_2100;
+		ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
+		ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
+		host->sg_tablesize = 32;
+	} else if (IS_QLA2200(ha)) {
+		ha->max_targets = MAX_TARGETS_2200;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		ha->request_q_length = REQUEST_ENTRY_CNT_2200;
+		ha->response_q_length = RESPONSE_ENTRY_CNT_2100;
+		ha->last_loop_id = SNS_LAST_LOOP_ID_2100;
+	} else /*if (IS_QLA2300(ha))*/ {
+		ha->max_targets = MAX_TARGETS_2200;
+		ha->mbx_count = MAILBOX_REGISTER_COUNT;
+		ha->request_q_length = REQUEST_ENTRY_CNT_2200;
+		ha->response_q_length = RESPONSE_ENTRY_CNT_2300;
+		ha->last_loop_id = SNS_LAST_LOOP_ID_2300;
+	}
+	host->can_queue = ha->request_q_length + 128;
+
+	/* load the F/W, read paramaters, and init the H/W */
+	ha->instance = num_hosts;
+
+	init_MUTEX(&ha->mbx_cmd_sem);
+	init_MUTEX_LOCKED(&ha->mbx_intr_sem);
+
+	INIT_LIST_HEAD(&ha->list);
+	INIT_LIST_HEAD(&ha->fcports);
+	INIT_LIST_HEAD(&ha->rscn_fcports);
+	INIT_LIST_HEAD(&ha->done_queue);
+	INIT_LIST_HEAD(&ha->retry_queue);
+	INIT_LIST_HEAD(&ha->scsi_retry_queue);
+	INIT_LIST_HEAD(&ha->pending_queue);
+
+	/*
+	 * These locks are used to prevent more than one CPU
+	 * from modifying the queue at the same time. The
+	 * higher level "host_lock" will reduce most
+	 * contention for these locks.
+	 */
+	spin_lock_init(&ha->mbx_reg_lock);
+	spin_lock_init(&ha->list_lock);
+
+	ha->dpc_pid = -1;
+	init_completion(&ha->dpc_inited);
+	init_completion(&ha->dpc_exited);
+
+	qla2x00_config_dma_addressing(ha);
+	if (qla2x00_mem_alloc(ha)) {
+		qla_printk(KERN_WARNING, ha,
+		    "[ERROR] Failed to allocate memory for adapter\n");
+
+		goto probe_failed;
+	}
+
+	if (qla2x00_initialize_adapter(ha) &&
+	    !(ha->device_flags & DFLG_NO_CABLE)) {
+
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to initialize adapter\n");
+
+		DEBUG2(printk("scsi(%ld): Failed to initialize adapter - "
+		    "Adapter flags %x.\n",
+		    ha->host_no, ha->device_flags));
+
+		goto probe_failed;
+	}
+
+	/*
+	 * Startup the kernel thread for this host adapter
+	 */
+	ha->dpc_should_die = 0;
+	ha->dpc_pid = kernel_thread(qla2x00_do_dpc, ha, 0);
+	if (ha->dpc_pid < 0) {
+		qla_printk(KERN_WARNING, ha,
+		    "Unable to start DPC thread!\n");
+
+		goto probe_failed;
+	}
+	wait_for_completion(&ha->dpc_inited);
+
+	host->this_id = 255;
+	host->cmd_per_lun = 3;
+	host->max_cmd_len = MAX_CMDSZ;
+	host->max_channel = ha->ports - 1;
+	host->max_lun = ha->max_luns;
+	BUG_ON(qla2xxx_transport_template == NULL);
+	host->transportt = qla2xxx_transport_template;
+	host->unique_id = ha->instance;
+	host->max_id = ha->max_targets;
+
+	if (IS_QLA2100(ha) || IS_QLA2200(ha))
+		ret = request_irq(host->irq, qla2100_intr_handler,
+		    SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha);
+	else
+		ret = request_irq(host->irq, qla2300_intr_handler,
+		    SA_INTERRUPT|SA_SHIRQ, ha->brd_info->drv_name, ha);
+	if (ret != 0) {
+		qla_printk(KERN_WARNING, ha,
+		    "Failed to reserve interrupt %d already in use.\n",
+		    host->irq);
+		goto probe_failed;
+	}
+
+	/* Initialized the timer */
+	qla2x00_start_timer(ha, qla2x00_timer, WATCH_INTERVAL);
+
+	DEBUG2(printk("DEBUG: detect hba %ld at address = %p\n",
+	    ha->host_no, ha));
+
+	reg = ha->iobase;
+
+	/* Disable ISP interrupts. */
+	qla2x00_disable_intrs(ha);
+
+	/* Ensure mailbox registers are free. */
+	spin_lock_irqsave(&ha->hardware_lock, flags);
+	WRT_REG_WORD(&reg->semaphore, 0);
+	WRT_REG_WORD(&reg->hccr, HCCR_CLR_RISC_INT);
+	WRT_REG_WORD(&reg->hccr, HCCR_CLR_HOST_INT);
+
+	/* Enable proper parity */
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha)) {
+		if (IS_QLA2300(ha))
+			/* SRAM parity */
+			WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x1));
+		else
+			/* SRAM, Instruction RAM and GP RAM parity */
+			WRT_REG_WORD(&reg->hccr, (HCCR_ENABLE_PARITY + 0x7));
+	}
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	/* Enable chip interrupts. */
+	qla2x00_enable_intrs(ha);
+
+	/* v2.19.5b6 */
+	/*
+	 * Wait around max loop_reset_delay secs for the devices to come
+	 * on-line. We don't want Linux scanning before we are ready.
+	 *
+	 */
+	for (wait_switch = jiffies + (ha->loop_reset_delay * HZ);
+	    time_before(jiffies,wait_switch) &&
+	     !(ha->device_flags & (DFLG_NO_CABLE | DFLG_FABRIC_DEVICES))
+	     && (ha->device_flags & SWITCH_FOUND) ;) {
+
+		qla2x00_check_fabric_devices(ha);
+
+		msleep(10);
+	}
+
+	pci_set_drvdata(pdev, ha);
+	ha->flags.init_done = 1;
+	num_hosts++;
+
+	/* List the target we have found */
+	if (displayConfig) {
+		qla2x00_display_fc_names(ha);
+	}
+
+	if (scsi_add_host(host, &pdev->dev))
+		goto probe_failed;
+
+	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_fw_dump_attr);
+	sysfs_create_bin_file(&host->shost_gendev.kobj, &sysfs_nvram_attr);
+
+	qla_printk(KERN_INFO, ha, "\n"
+	    " QLogic Fibre Channel HBA Driver: %s\n"
+	    "  QLogic %s - %s\n"
+	    "  %s: %s @ %s hdma%c, host#=%ld, fw=%s\n", qla2x00_version_str,
+	    ha->model_number, ha->model_desc ? ha->model_desc: "",
+	    ha->brd_info->isp_name, qla2x00_get_pci_info_str(ha, pci_info),
+	    pci_name(ha->pdev), ha->flags.enable_64bit_addressing ? '+': '-',
+	    ha->host_no, qla2x00_get_fw_version_str(ha, fw_str));
+
+	if (ql2xdoinitscan)
+		scsi_scan_host(host);
+
+	return 0;
+
+probe_failed:
+	qla2x00_free_device(ha);
+
+	scsi_host_put(host);
+
+probe_disable_device:
+	pci_disable_device(pdev);
+
+	return -1;
+}
+EXPORT_SYMBOL_GPL(qla2x00_probe_one);
+
+void qla2x00_remove_one(struct pci_dev *pdev)
+{
+	scsi_qla_host_t *ha;
+
+	ha = pci_get_drvdata(pdev);
+
+	sysfs_remove_bin_file(&ha->host->shost_gendev.kobj,
+	    &sysfs_fw_dump_attr);
+	sysfs_remove_bin_file(&ha->host->shost_gendev.kobj, &sysfs_nvram_attr);
+
+	scsi_remove_host(ha->host);
+
+	qla2x00_free_device(ha);
+
+	scsi_host_put(ha->host);
+
+	pci_set_drvdata(pdev, NULL);
+}
+EXPORT_SYMBOL_GPL(qla2x00_remove_one);
+
+static void
+qla2x00_free_device(scsi_qla_host_t *ha)
+{
+	int ret;
+
+	/* Abort any outstanding IO descriptors. */
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha))
+		qla2x00_cancel_io_descriptors(ha);
+
+	/* turn-off interrupts on the card */
+	if (ha->interrupts_on)
+		qla2x00_disable_intrs(ha);
+
+	/* Disable timer */
+	if (ha->timer_active)
+		qla2x00_stop_timer(ha);
+
+	/* Kill the kernel thread for this host */
+	if (ha->dpc_pid >= 0) {
+		ha->dpc_should_die = 1;
+		wmb();
+		ret = kill_proc(ha->dpc_pid, SIGHUP, 1);
+		if (ret) {
+			qla_printk(KERN_ERR, ha,
+			    "Unable to signal DPC thread -- (%d)\n", ret);
+
+			/* TODO: SOMETHING MORE??? */
+		} else {
+			wait_for_completion(&ha->dpc_exited);
+		}
+	}
+
+	qla2x00_mem_free(ha);
+
+
+	ha->flags.online = 0;
+
+	/* Detach interrupts */
+	if (ha->pdev->irq)
+		free_irq(ha->pdev->irq, ha);
+
+	/* release io space registers  */
+	if (ha->iobase)
+		iounmap(ha->iobase);
+	pci_release_regions(ha->pdev);
+
+	pci_disable_device(ha->pdev);
+}
+
+
+/*
+ * The following support functions are adopted to handle
+ * the re-entrant qla2x00_proc_info correctly.
+ */
+static void
+copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->offset + info->length)
+		len = info->offset + info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+ 
+	if (info->pos < info->offset) {
+		off_t partial;
+ 
+		partial = info->offset - info->pos;
+		data += partial;
+		info->pos += partial;
+		len  -= partial;
+	}
+ 
+	if (len > 0) {
+		memcpy(info->buffer, data, len);
+		info->pos += len;
+		info->buffer += len;
+	}
+}
+
+static int
+copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[256];
+	int len;
+ 
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+ 
+	copy_mem_info(info, buf, len);
+
+	return (len);
+}
+
+/*************************************************************************
+* qla2x00_proc_info
+*
+* Description:
+*   Return information to handle /proc support for the driver.
+*
+* inout : decides the direction of the dataflow and the meaning of the
+*         variables
+* buffer: If inout==0 data is being written to it else read from it
+*         (ptr to a page buffer)
+* *start: If inout==0 start of the valid data in the buffer
+* offset: If inout==0 starting offset from the beginning of all
+*         possible data to return.
+* length: If inout==0 max number of bytes to be written into the buffer
+*         else number of bytes in "buffer"
+* Returns:
+*         < 0:  error. errno value.
+*         >= 0: sizeof data returned.
+*************************************************************************/
+int
+qla2x00_proc_info(struct Scsi_Host *shost, char *buffer,
+    char **start, off_t offset, int length, int inout)
+{
+	struct info_str	info;
+	int             retval = -EINVAL;
+	os_lun_t	*up;
+	os_tgt_t	*tq;
+	unsigned int	t, l;
+	uint32_t        tmp_sn;
+	uint32_t	*flags;
+	uint8_t		*loop_state;
+	scsi_qla_host_t *ha;
+	char fw_info[30];
+ 
+	DEBUG3(printk(KERN_INFO
+	    "Entering proc_info buff_in=%p, offset=0x%lx, length=0x%x\n",
+	    buffer, offset, length);)
+
+	ha = (scsi_qla_host_t *) shost->hostdata;
+
+	if (inout) {
+		/* Has data been written to the file? */
+		DEBUG3(printk(
+		    "%s: has data been written to the file. \n",
+		    __func__);)
+
+		return -ENOSYS;
+	}
+
+	if (start) {
+		*start = buffer;
+	}
+
+	info.buffer = buffer;
+	info.length = length;
+	info.offset = offset;
+	info.pos    = 0;
+
+	/* start building the print buffer */
+	copy_info(&info,
+	    "QLogic PCI to Fibre Channel Host Adapter for %s:\n"
+	    "        Firmware version %s, ",
+	    ha->model_number, qla2x00_get_fw_version_str(ha, fw_info));
+
+	copy_info(&info, "Driver version %s\n", qla2x00_version_str);
+
+	tmp_sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | 
+	    ha->serial1;
+	copy_info(&info, "ISP: %s, Serial# %c%05d\n",
+	    ha->brd_info->isp_name, ('A' + tmp_sn/100000), (tmp_sn%100000));
+
+	copy_info(&info,
+	    "Request Queue = 0x%llx, Response Queue = 0x%llx\n",
+		(unsigned long long)ha->request_dma,
+		(unsigned long long)ha->response_dma);
+
+	copy_info(&info,
+	    "Request Queue count = %d, Response Queue count = %d\n",
+	    ha->request_q_length, ha->response_q_length);
+
+	copy_info(&info,
+	    "Total number of active commands = %ld\n",
+	    ha->actthreads);
+
+	copy_info(&info,
+	    "Total number of interrupts = %ld\n",
+	    (long)ha->total_isr_cnt);
+
+	copy_info(&info,
+	    "    Device queue depth = 0x%x\n",
+	    (ql2xmaxqdepth == 0) ? 16 : ql2xmaxqdepth);
+
+	copy_info(&info,
+	    "Number of free request entries = %d\n", ha->req_q_cnt);
+
+	copy_info(&info,
+	    "Number of mailbox timeouts = %ld\n", ha->total_mbx_timeout);
+
+	copy_info(&info,
+	    "Number of ISP aborts = %ld\n", ha->total_isp_aborts);
+
+	copy_info(&info,
+	    "Number of loop resyncs = %ld\n", ha->total_loop_resync);
+
+	copy_info(&info,
+	    "Number of retries for empty slots = %ld\n",
+	    qla2x00_stats.outarray_full);
+
+	copy_info(&info,
+	    "Number of reqs in pending_q= %ld, retry_q= %d, "
+	    "done_q= %ld, scsi_retry_q= %d\n",
+	    ha->qthreads, ha->retry_q_cnt,
+	    ha->done_q_cnt, ha->scsi_retry_q_cnt);
+
+
+	flags = (uint32_t *) &ha->flags;
+
+	if (atomic_read(&ha->loop_state) == LOOP_DOWN) {
+		loop_state = "DOWN";
+	} else if (atomic_read(&ha->loop_state) == LOOP_UP) {
+		loop_state = "UP";
+	} else if (atomic_read(&ha->loop_state) == LOOP_READY) {
+		loop_state = "READY";
+	} else if (atomic_read(&ha->loop_state) == LOOP_TIMEOUT) {
+		loop_state = "TIMEOUT";
+	} else if (atomic_read(&ha->loop_state) == LOOP_UPDATE) {
+		loop_state = "UPDATE";
+	} else {
+		loop_state = "UNKNOWN";
+	}
+
+	copy_info(&info, 
+	    "Host adapter:loop state = <%s>, flags = 0x%lx\n",
+	    loop_state , *flags);
+
+	copy_info(&info, "Dpc flags = 0x%lx\n", ha->dpc_flags);
+
+	copy_info(&info, "MBX flags = 0x%x\n", ha->mbx_flags);
+
+	copy_info(&info, "Link down Timeout = %3.3d\n",
+	    ha->link_down_timeout);
+
+	copy_info(&info, "Port down retry = %3.3d\n",
+	    ha->port_down_retry_count);
+
+	copy_info(&info, "Login retry count = %3.3d\n",
+	    ha->login_retry_count);
+
+	copy_info(&info,
+	    "Commands retried with dropped frame(s) = %d\n",
+	    ha->dropped_frame_error_cnt);
+
+	copy_info(&info,
+	    "Product ID = %04x %04x %04x %04x\n", ha->product_id[0],
+	    ha->product_id[1], ha->product_id[2], ha->product_id[3]);
+
+	copy_info(&info, "\n");
+
+	/* 2.25 node/port display to proc */
+	/* Display the node name for adapter */
+	copy_info(&info, "\nSCSI Device Information:\n");
+	copy_info(&info,
+	    "scsi-qla%d-adapter-node="
+	    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
+	    (int)ha->instance,
+	    ha->init_cb->node_name[0],
+	    ha->init_cb->node_name[1],
+	    ha->init_cb->node_name[2],
+	    ha->init_cb->node_name[3],
+	    ha->init_cb->node_name[4],
+	    ha->init_cb->node_name[5],
+	    ha->init_cb->node_name[6],
+	    ha->init_cb->node_name[7]);
+
+	/* display the port name for adapter */
+	copy_info(&info,
+	    "scsi-qla%d-adapter-port="
+	    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
+	    (int)ha->instance,
+	    ha->init_cb->port_name[0],
+	    ha->init_cb->port_name[1],
+	    ha->init_cb->port_name[2],
+	    ha->init_cb->port_name[3],
+	    ha->init_cb->port_name[4],
+	    ha->init_cb->port_name[5],
+	    ha->init_cb->port_name[6],
+	    ha->init_cb->port_name[7]);
+
+	/* Print out device port names */
+	for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
+		if ((tq = TGT_Q(ha, t)) == NULL)
+			continue;
+
+		copy_info(&info,
+		    "scsi-qla%d-target-%d="
+		    "%02x%02x%02x%02x%02x%02x%02x%02x;\n",
+		    (int)ha->instance, t,
+		    tq->port_name[0], tq->port_name[1],
+		    tq->port_name[2], tq->port_name[3],
+		    tq->port_name[4], tq->port_name[5],
+		    tq->port_name[6], tq->port_name[7]);
+	}
+
+	copy_info(&info, "\nSCSI LUN Information:\n");
+	copy_info(&info,
+	    "(Id:Lun)  * - indicates lun is not registered with the OS.\n");
+
+	/* scan for all equipment stats */
+	for (t = 0; t < MAX_FIBRE_DEVICES; t++) {
+		/* scan all luns */
+		for (l = 0; l < ha->max_luns; l++) {
+			up = (os_lun_t *) GET_LU_Q(ha, t, l);
+
+			if (up == NULL) {
+				continue;
+			}
+			if (up->fclun == NULL) {
+				continue;
+			}
+
+			copy_info(&info,
+			    "(%2d:%2d): Total reqs %ld,",
+			    t,l,up->io_cnt);
+
+			copy_info(&info,
+			    " Pending reqs %ld,",
+			    up->out_cnt);
+
+			if (up->io_cnt < 4) {
+				copy_info(&info,
+				    " flags 0x%x*,",
+				    (int)up->q_flag);
+			} else {
+				copy_info(&info,
+				    " flags 0x%x,",
+				    (int)up->q_flag);
+			}
+
+			copy_info(&info, 
+			    " %ld:%d:%02x %02x",
+			    up->fclun->fcport->ha->instance,
+			    up->fclun->fcport->cur_path,
+			    up->fclun->fcport->loop_id,
+			    up->fclun->device_type);
+
+			copy_info(&info, "\n");
+
+			if (info.pos >= info.offset + info.length) {
+				/* No need to continue */
+				goto profile_stop;
+			}
+		}
+
+		if (info.pos >= info.offset + info.length) {
+			/* No need to continue */
+			break;
+		}
+	}
+
+profile_stop:
+
+	retval = info.pos > info.offset ? info.pos - info.offset : 0;
+
+	DEBUG3(printk(KERN_INFO 
+	    "Exiting proc_info: info.pos=%d, offset=0x%lx, "
+	    "length=0x%x\n", info.pos, offset, length);)
+
+	return (retval);
+}
+
+/*
+* qla2x00_display_fc_names
+*      This routine will the node names of the different devices found
+*      after port inquiry.
+*
+* Input:
+*      cmd = SCSI command structure
+*
+* Returns:
+*      None.
+*/
+static void
+qla2x00_display_fc_names(scsi_qla_host_t *ha) 
+{
+	uint16_t	tgt;
+	os_tgt_t	*tq;
+
+	/* Display the node name for adapter */
+	qla_printk(KERN_INFO, ha,
+	    "scsi-qla%d-adapter-node=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
+	    (int)ha->instance,
+	    ha->init_cb->node_name[0],
+	    ha->init_cb->node_name[1],
+	    ha->init_cb->node_name[2],
+	    ha->init_cb->node_name[3],
+	    ha->init_cb->node_name[4],
+	    ha->init_cb->node_name[5],
+	    ha->init_cb->node_name[6],
+	    ha->init_cb->node_name[7]);
+
+	/* display the port name for adapter */
+	qla_printk(KERN_INFO, ha,
+	    "scsi-qla%d-adapter-port=%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
+	    (int)ha->instance,
+	    ha->init_cb->port_name[0],
+	    ha->init_cb->port_name[1],
+	    ha->init_cb->port_name[2],
+	    ha->init_cb->port_name[3],
+	    ha->init_cb->port_name[4],
+	    ha->init_cb->port_name[5],
+	    ha->init_cb->port_name[6],
+	    ha->init_cb->port_name[7]);
+
+	/* Print out device port names */
+	for (tgt = 0; tgt < MAX_TARGETS; tgt++) {
+		if ((tq = ha->otgt[tgt]) == NULL)
+			continue;
+
+		if (tq->fcport == NULL)
+			continue;
+
+		switch (ha->binding_type) {
+			case BIND_BY_PORT_NAME:
+				qla_printk(KERN_INFO, ha,
+				    "scsi-qla%d-tgt-%d-di-0-port="
+				    "%02x%02x%02x%02x%02x%02x%02x%02x\\;\n",
+				    (int)ha->instance, 
+				    tgt,
+				    tq->port_name[0], 
+				    tq->port_name[1],
+				    tq->port_name[2], 
+				    tq->port_name[3],
+				    tq->port_name[4], 
+				    tq->port_name[5],
+				    tq->port_name[6], 
+				    tq->port_name[7]);
+
+				break;
+
+			case BIND_BY_PORT_ID:
+				qla_printk(KERN_INFO, ha,
+				    "scsi-qla%d-tgt-%d-di-0-pid="
+				    "%02x%02x%02x\\;\n",
+				    (int)ha->instance,
+				    tgt,
+				    tq->d_id.b.domain,
+				    tq->d_id.b.area,
+				    tq->d_id.b.al_pa);
+				break;
+		}
+
+#if VSA
+		qla_printk(KERN_INFO, ha,
+		    "scsi-qla%d-target-%d-vsa=01;\n", (int)ha->instance, tgt);
+#endif
+	}
+}
+
+/*
+ *  qla2x00_suspend_lun
+ *	Suspend lun and start port down timer
+ *
+ * Input:
+ *	ha = visable adapter block pointer.
+ *  lq = lun queue
+ *  cp = Scsi command pointer 
+ *  time = time in seconds
+ *  count = number of times to let time expire
+ *  delay_lun = non-zero, if lun should be delayed rather than suspended
+ *
+ * Return:
+ *     QLA_SUCCESS  -- suspended lun 
+ *     QLA_FUNCTION_FAILED  -- Didn't suspend lun
+ *
+ * Context:
+ *	Interrupt context.
+ */
+int
+__qla2x00_suspend_lun(scsi_qla_host_t *ha,
+		os_lun_t *lq, int time, int count, int delay_lun)
+{
+	int	rval;
+	srb_t *sp;
+	struct list_head *list, *temp;
+	unsigned long flags;
+
+	rval = QLA_SUCCESS;
+
+	/* if the lun_q is already suspended then don't do it again */
+	if (lq->q_state == LUN_STATE_READY ||lq->q_state == LUN_STATE_RUN) {
+
+		spin_lock_irqsave(&lq->q_lock, flags);
+		if (lq->q_state == LUN_STATE_READY) {
+			lq->q_max = count;
+			lq->q_count = 0;
+		}
+		/* Set the suspend time usually 6 secs */
+		atomic_set(&lq->q_timer, time);
+
+		/* now suspend the lun */
+		lq->q_state = LUN_STATE_WAIT;
+
+		if (delay_lun) {
+			set_bit(LUN_EXEC_DELAYED, &lq->q_flag);
+			DEBUG(printk(KERN_INFO
+			    "scsi(%ld): Delay lun execution for %d secs, "
+			    "count=%d, max count=%d, state=%d\n",
+			    ha->host_no,
+			    time,
+			    lq->q_count, lq->q_max, lq->q_state));
+		} else {
+			DEBUG(printk(KERN_INFO
+			    "scsi(%ld): Suspend lun for %d secs, count=%d, "
+			    "max count=%d, state=%d\n",
+			    ha->host_no,
+			    time,
+			    lq->q_count, lq->q_max, lq->q_state));
+		}
+		spin_unlock_irqrestore(&lq->q_lock, flags);
+
+		/*
+		 * Remove all pending commands from request queue and  put them
+		 * in the scsi_retry queue.
+		 */
+		spin_lock_irqsave(&ha->list_lock, flags);
+		list_for_each_safe(list, temp, &ha->pending_queue) {
+			sp = list_entry(list, srb_t, list);
+			if (sp->lun_queue != lq)
+				continue;
+
+			__del_from_pending_queue(ha, sp);
+
+			if (sp->cmd->allowed < count)
+				sp->cmd->allowed = count;
+			__add_to_scsi_retry_queue(ha, sp);
+
+		} /* list_for_each_safe */
+		spin_unlock_irqrestore(&ha->list_lock, flags);
+		rval = QLA_SUCCESS;
+	} else {
+		rval = QLA_FUNCTION_FAILED;
+	}
+
+	return (rval);
+}
+
+/*
+ * qla2x00_mark_device_lost Updates fcport state when device goes offline.
+ *
+ * Input: ha = adapter block pointer.  fcport = port structure pointer.
+ *
+ * Return: None.
+ *
+ * Context:
+ */
+void qla2x00_mark_device_lost(scsi_qla_host_t *ha, fc_port_t *fcport,
+    int do_login)
+{
+	/* 
+	 * We may need to retry the login, so don't change the state of the
+	 * port but do the retries.
+	 */
+	if (atomic_read(&fcport->state) != FCS_DEVICE_DEAD)
+		atomic_set(&fcport->state, FCS_DEVICE_LOST);
+
+	if (!do_login)
+		return;
+
+	if (fcport->login_retry == 0) {
+		fcport->login_retry = ha->login_retry_count;
+		set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
+
+		DEBUG(printk("scsi(%ld): Port login retry: "
+		    "%02x%02x%02x%02x%02x%02x%02x%02x, "
+		    "id = 0x%04x retry cnt=%d\n",
+		    ha->host_no,
+		    fcport->port_name[0],
+		    fcport->port_name[1],
+		    fcport->port_name[2],
+		    fcport->port_name[3],
+		    fcport->port_name[4],
+		    fcport->port_name[5],
+		    fcport->port_name[6],
+		    fcport->port_name[7],
+		    fcport->loop_id,
+		    fcport->login_retry));
+	}
+}
+
+/*
+ * qla2x00_mark_all_devices_lost
+ *	Updates fcport state when device goes offline.
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *	fcport = port structure pointer.
+ *
+ * Return:
+ *	None.
+ *
+ * Context:
+ */
+void
+qla2x00_mark_all_devices_lost(scsi_qla_host_t *ha) 
+{
+	fc_port_t *fcport;
+
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (fcport->port_type != FCT_TARGET)
+			continue;
+
+		/*
+		 * No point in marking the device as lost, if the device is
+		 * already DEAD.
+		 */
+		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD)
+			continue;
+
+		atomic_set(&fcport->state, FCS_DEVICE_LOST);
+	}
+}
+
+/*
+* qla2x00_mem_alloc
+*      Allocates adapter memory.
+*
+* Returns:
+*      0  = success.
+*      1  = failure.
+*/
+static uint8_t
+qla2x00_mem_alloc(scsi_qla_host_t *ha)
+{
+	char	name[16];
+	uint8_t   status = 1;
+	int	retry= 10;
+
+	do {
+		/*
+		 * This will loop only once if everything goes well, else some
+		 * number of retries will be performed to get around a kernel
+		 * bug where available mem is not allocated until after a
+		 * little delay and a retry.
+		 */
+		ha->request_ring = dma_alloc_coherent(&ha->pdev->dev,
+		    (ha->request_q_length + 1) * sizeof(request_t),
+		    &ha->request_dma, GFP_KERNEL);
+		if (ha->request_ring == NULL) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - request_ring\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		ha->response_ring = dma_alloc_coherent(&ha->pdev->dev,
+		    (ha->response_q_length + 1) * sizeof(response_t),
+		    &ha->response_dma, GFP_KERNEL);
+		if (ha->response_ring == NULL) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - response_ring\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		ha->gid_list = dma_alloc_coherent(&ha->pdev->dev, GID_LIST_SIZE,
+		    &ha->gid_list_dma, GFP_KERNEL);
+		if (ha->gid_list == NULL) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - gid_list\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		ha->rlc_rsp = dma_alloc_coherent(&ha->pdev->dev,
+		    sizeof(rpt_lun_cmd_rsp_t), &ha->rlc_rsp_dma, GFP_KERNEL);
+		if (ha->rlc_rsp == NULL) {
+			qla_printk(KERN_WARNING, ha,
+				"Memory Allocation failed - rlc");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		snprintf(name, sizeof(name), "qla2xxx_%ld", ha->host_no);
+		ha->s_dma_pool = dma_pool_create(name, &ha->pdev->dev,
+		    DMA_POOL_SIZE, 8, 0);
+		if (ha->s_dma_pool == NULL) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - s_dma_pool\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		/* get consistent memory allocated for init control block */
+		ha->init_cb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+		    &ha->init_cb_dma);
+		if (ha->init_cb == NULL) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - init_cb\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+		memset(ha->init_cb, 0, sizeof(init_cb_t));
+
+		/* Get consistent memory allocated for Get Port Database cmd */
+		ha->iodesc_pd = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+		    &ha->iodesc_pd_dma);
+		if (ha->iodesc_pd == NULL) {
+			/* error */
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - iodesc_pd\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+		memset(ha->iodesc_pd, 0, PORT_DATABASE_SIZE);
+
+		/* Allocate ioctl related memory. */
+		if (qla2x00_alloc_ioctl_mem(ha)) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - ioctl_mem\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		if (qla2x00_allocate_sp_pool(ha)) {
+			qla_printk(KERN_WARNING, ha,
+			    "Memory Allocation failed - "
+			    "qla2x00_allocate_sp_pool()\n");
+
+			qla2x00_mem_free(ha);
+			msleep(100);
+
+			continue;
+		}
+
+		/* Allocate memory for SNS commands */
+		if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
+			/* Get consistent memory allocated for SNS commands */
+			ha->sns_cmd = dma_alloc_coherent(&ha->pdev->dev,
+			    sizeof(struct sns_cmd_pkt), &ha->sns_cmd_dma,
+			    GFP_KERNEL);
+			if (ha->sns_cmd == NULL) {
+				/* error */
+				qla_printk(KERN_WARNING, ha,
+				    "Memory Allocation failed - sns_cmd\n");
+
+				qla2x00_mem_free(ha);
+				msleep(100);
+
+				continue;
+			}
+			memset(ha->sns_cmd, 0, sizeof(struct sns_cmd_pkt));
+		} else {
+			/* Get consistent memory allocated for MS IOCB */
+			ha->ms_iocb = dma_pool_alloc(ha->s_dma_pool, GFP_KERNEL,
+			    &ha->ms_iocb_dma);
+			if (ha->ms_iocb == NULL) {
+				/* error */
+				qla_printk(KERN_WARNING, ha,
+				    "Memory Allocation failed - ms_iocb\n");
+
+				qla2x00_mem_free(ha);
+				msleep(100);
+
+				continue;
+			}
+			memset(ha->ms_iocb, 0, sizeof(ms_iocb_entry_t));
+
+			/*
+			 * Get consistent memory allocated for CT SNS
+			 * commands
+			 */
+			ha->ct_sns = dma_alloc_coherent(&ha->pdev->dev,
+			    sizeof(struct ct_sns_pkt), &ha->ct_sns_dma,
+			    GFP_KERNEL);
+			if (ha->ct_sns == NULL) {
+				/* error */
+				qla_printk(KERN_WARNING, ha,
+				    "Memory Allocation failed - ct_sns\n");
+
+				qla2x00_mem_free(ha);
+				msleep(100);
+
+				continue;
+			}
+			memset(ha->ct_sns, 0, sizeof(struct ct_sns_pkt));
+		}
+
+		/* Done all allocations without any error. */
+		status = 0;
+
+	} while (retry-- && status != 0);
+
+	if (status) {
+		printk(KERN_WARNING
+			"%s(): **** FAILED ****\n", __func__);
+	}
+
+	return(status);
+}
+
+/*
+* qla2x00_mem_free
+*      Frees all adapter allocated memory.
+*
+* Input:
+*      ha = adapter block pointer.
+*/
+static void
+qla2x00_mem_free(scsi_qla_host_t *ha)
+{
+	uint32_t	t;
+	struct list_head	*fcpl, *fcptemp;
+	fc_port_t	*fcport;
+	struct list_head	*fcll, *fcltemp;
+	fc_lun_t	*fclun;
+	unsigned long	wtime;/* max wait time if mbx cmd is busy. */
+
+	if (ha == NULL) {
+		/* error */
+		DEBUG2(printk("%s(): ERROR invalid ha pointer.\n", __func__));
+		return;
+	}
+
+	/* Free the target queues */
+	for (t = 0; t < MAX_TARGETS; t++) {
+		qla2x00_tgt_free(ha, t);
+	}
+
+	/* Make sure all other threads are stopped. */
+	wtime = 60 * HZ;
+	while (ha->dpc_wait && wtime) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		wtime = schedule_timeout(wtime);
+	}
+
+	/* free ioctl memory */
+	qla2x00_free_ioctl_mem(ha);
+
+	/* free sp pool */
+	qla2x00_free_sp_pool(ha);
+
+	if (ha->sns_cmd)
+		dma_free_coherent(&ha->pdev->dev, sizeof(struct sns_cmd_pkt),
+		    ha->sns_cmd, ha->sns_cmd_dma);
+
+	if (ha->ct_sns)
+		dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
+		    ha->ct_sns, ha->ct_sns_dma);
+
+	if (ha->ms_iocb)
+		dma_pool_free(ha->s_dma_pool, ha->ms_iocb, ha->ms_iocb_dma);
+
+	if (ha->iodesc_pd)
+		dma_pool_free(ha->s_dma_pool, ha->iodesc_pd, ha->iodesc_pd_dma);
+
+	if (ha->init_cb)
+		dma_pool_free(ha->s_dma_pool, ha->init_cb, ha->init_cb_dma);
+
+	if (ha->s_dma_pool)
+		dma_pool_destroy(ha->s_dma_pool);
+
+	if (ha->rlc_rsp)
+		dma_free_coherent(&ha->pdev->dev,
+		    sizeof(rpt_lun_cmd_rsp_t), ha->rlc_rsp,
+		    ha->rlc_rsp_dma);
+
+	if (ha->gid_list)
+		dma_free_coherent(&ha->pdev->dev, GID_LIST_SIZE, ha->gid_list,
+		    ha->gid_list_dma);
+
+	if (ha->response_ring)
+		dma_free_coherent(&ha->pdev->dev,
+		    (ha->response_q_length + 1) * sizeof(response_t),
+		    ha->response_ring, ha->response_dma);
+
+	if (ha->request_ring)
+		dma_free_coherent(&ha->pdev->dev,
+		    (ha->request_q_length + 1) * sizeof(request_t),
+		    ha->request_ring, ha->request_dma);
+
+	ha->sns_cmd = NULL;
+	ha->sns_cmd_dma = 0;
+	ha->ct_sns = NULL;
+	ha->ct_sns_dma = 0;
+	ha->ms_iocb = NULL;
+	ha->ms_iocb_dma = 0;
+	ha->iodesc_pd = NULL;
+	ha->iodesc_pd_dma = 0;
+	ha->init_cb = NULL;
+	ha->init_cb_dma = 0;
+
+	ha->s_dma_pool = NULL;
+
+	ha->rlc_rsp = NULL;
+	ha->rlc_rsp_dma = 0;
+	ha->gid_list = NULL;
+	ha->gid_list_dma = 0;
+
+	ha->response_ring = NULL;
+	ha->response_dma = 0;
+	ha->request_ring = NULL;
+	ha->request_dma = 0;
+
+	list_for_each_safe(fcpl, fcptemp, &ha->fcports) {
+		fcport = list_entry(fcpl, fc_port_t, list);
+
+		/* fc luns */
+		list_for_each_safe(fcll, fcltemp, &fcport->fcluns) {
+			fclun = list_entry(fcll, fc_lun_t, list);
+
+			list_del_init(&fclun->list);
+			kfree(fclun);
+		}
+
+		/* fc ports */
+		list_del_init(&fcport->list);
+		kfree(fcport);
+	}
+	INIT_LIST_HEAD(&ha->fcports);
+
+	if (ha->fw_dump)
+		free_pages((unsigned long)ha->fw_dump, ha->fw_dump_order);
+
+	if (ha->fw_dump_buffer)
+		vfree(ha->fw_dump_buffer);
+
+	ha->fw_dump = NULL;
+	ha->fw_dump_reading = 0;
+	ha->fw_dump_buffer = NULL;
+}
+
+/*
+ * qla2x00_allocate_sp_pool
+ * 	 This routine is called during initialization to allocate
+ *  	 memory for local srb_t.
+ *
+ * Input:
+ *	 ha   = adapter block pointer.
+ *
+ * Context:
+ *      Kernel context.
+ * 
+ * Note: Sets the ref_count for non Null sp to one.
+ */
+static int
+qla2x00_allocate_sp_pool(scsi_qla_host_t *ha) 
+{
+	int      rval;
+
+	rval = QLA_SUCCESS;
+	ha->srb_mempool = mempool_create(SRB_MIN_REQ, mempool_alloc_slab,
+	    mempool_free_slab, srb_cachep);
+	if (ha->srb_mempool == NULL) {
+		qla_printk(KERN_INFO, ha, "Unable to allocate SRB mempool.\n");
+		rval = QLA_FUNCTION_FAILED;
+	}
+	return (rval);
+}
+
+/*
+ *  This routine frees all adapter allocated memory.
+ *  
+ */
+static void
+qla2x00_free_sp_pool( scsi_qla_host_t *ha) 
+{
+	if (ha->srb_mempool) {
+		mempool_destroy(ha->srb_mempool);
+		ha->srb_mempool = NULL;
+	}
+}
+
+/**************************************************************************
+* qla2x00_do_dpc
+*   This kernel thread is a task that is schedule by the interrupt handler
+*   to perform the background processing for interrupts.
+*
+* Notes:
+* This task always run in the context of a kernel thread.  It
+* is kick-off by the driver's detect code and starts up
+* up one per adapter. It immediately goes to sleep and waits for
+* some fibre event.  When either the interrupt handler or
+* the timer routine detects a event it will one of the task
+* bits then wake us up.
+**************************************************************************/
+static int
+qla2x00_do_dpc(void *data)
+{
+	DECLARE_MUTEX_LOCKED(sem);
+	scsi_qla_host_t *ha;
+	fc_port_t	*fcport;
+	os_lun_t        *q;
+	srb_t           *sp;
+	uint8_t		status;
+	unsigned long	flags = 0;
+	struct list_head *list, *templist;
+	int	dead_cnt, online_cnt;
+	int	retry_cmds = 0;
+	uint16_t	next_loopid;
+	int t;
+	os_tgt_t *tq;
+
+	ha = (scsi_qla_host_t *)data;
+
+	lock_kernel();
+
+	daemonize("%s_dpc", ha->host_str);
+	allow_signal(SIGHUP);
+
+	ha->dpc_wait = &sem;
+
+	set_user_nice(current, -20);
+
+	unlock_kernel();
+
+	complete(&ha->dpc_inited);
+
+	while (1) {
+		DEBUG3(printk("qla2x00: DPC handler sleeping\n"));
+
+		if (down_interruptible(&sem))
+			break;
+
+		if (ha->dpc_should_die)
+			break;
+
+		DEBUG3(printk("qla2x00: DPC handler waking up\n"));
+
+		/* Initialization not yet finished. Don't do anything yet. */
+		if (!ha->flags.init_done || ha->dpc_active)
+			continue;
+
+		DEBUG3(printk("scsi(%ld): DPC handler\n", ha->host_no));
+
+		ha->dpc_active = 1;
+
+		if (!list_empty(&ha->done_queue))
+			qla2x00_done(ha);
+
+		/* Process commands in retry queue */
+		if (test_and_clear_bit(PORT_RESTART_NEEDED, &ha->dpc_flags)) {
+			DEBUG(printk("scsi(%ld): DPC checking retry_q. "
+			    "total=%d\n",
+			    ha->host_no, ha->retry_q_cnt));
+
+			spin_lock_irqsave(&ha->list_lock, flags);
+			dead_cnt = online_cnt = 0;
+			list_for_each_safe(list, templist, &ha->retry_queue) {
+				sp = list_entry(list, srb_t, list);
+				q = sp->lun_queue;
+				DEBUG3(printk("scsi(%ld): pid=%ld sp=%p, "
+				    "spflags=0x%x, q_flag= 0x%lx\n",
+				    ha->host_no, sp->cmd->serial_number, sp,
+				    sp->flags, q->q_flag));
+
+				if (q == NULL)
+					continue;
+				fcport = q->fclun->fcport;
+
+				if (atomic_read(&fcport->state) ==
+				    FCS_DEVICE_DEAD ||
+				    atomic_read(&fcport->ha->loop_state) == LOOP_DEAD) {
+
+					__del_from_retry_queue(ha, sp);
+					sp->cmd->result = DID_NO_CONNECT << 16;
+					if (atomic_read(&fcport->ha->loop_state) ==
+					    LOOP_DOWN) 
+						sp->err_id = SRB_ERR_LOOP;
+					else
+						sp->err_id = SRB_ERR_PORT;
+					sp->cmd->host_scribble =
+					    (unsigned char *) NULL;
+					__add_to_done_queue(ha, sp);
+					dead_cnt++;
+				} else if (atomic_read(&fcport->state) !=
+				    FCS_DEVICE_LOST) {
+
+					__del_from_retry_queue(ha, sp);
+					sp->cmd->result = DID_BUS_BUSY << 16;
+					sp->cmd->host_scribble =
+					    (unsigned char *) NULL;
+					__add_to_done_queue(ha, sp);
+					online_cnt++;
+				}
+			} /* list_for_each_safe() */
+			spin_unlock_irqrestore(&ha->list_lock, flags);
+
+			DEBUG(printk("scsi(%ld): done processing retry queue "
+			    "- dead=%d, online=%d\n ",
+			    ha->host_no, dead_cnt, online_cnt));
+		}
+
+		/* Process commands in scsi retry queue */
+		if (test_and_clear_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags)) {
+			/*
+			 * Any requests we want to delay for some period is put
+			 * in the scsi retry queue with a delay added. The
+			 * timer will schedule a "scsi_restart_needed" every 
+			 * second as long as there are requests in the scsi
+			 * queue. 
+			 */
+			DEBUG(printk("scsi(%ld): DPC checking scsi "
+			    "retry_q.total=%d\n",
+			    ha->host_no, ha->scsi_retry_q_cnt));
+
+			online_cnt = 0;
+			spin_lock_irqsave(&ha->list_lock, flags);
+			list_for_each_safe(list, templist,
+			    &ha->scsi_retry_queue) {
+
+				sp = list_entry(list, srb_t, list);
+				q = sp->lun_queue;
+				tq = sp->tgt_queue;
+
+				DEBUG3(printk("scsi(%ld): scsi_retry_q: "
+				    "pid=%ld sp=%p, spflags=0x%x, "
+				    "q_flag= 0x%lx,q_state=%d\n",
+				    ha->host_no, sp->cmd->serial_number,
+				    sp, sp->flags, q->q_flag, q->q_state));
+
+				/* Was this lun suspended */
+				if (q->q_state != LUN_STATE_WAIT) {
+					online_cnt++;
+					__del_from_scsi_retry_queue(ha, sp);
+
+					if (test_bit(TQF_RETRY_CMDS,
+					    &tq->flags)) {
+						qla2x00_extend_timeout(sp->cmd,
+						    (sp->cmd->timeout_per_command / HZ) - QLA_CMD_TIMER_DELTA);
+						__add_to_pending_queue(ha, sp);
+						retry_cmds++;
+					} else
+						__add_to_retry_queue(ha, sp);
+				}
+
+				/* Was this command suspended for N secs */
+				if (sp->delay != 0) {
+					sp->delay--;
+					if (sp->delay == 0) {
+						online_cnt++;
+						__del_from_scsi_retry_queue(
+						    ha, sp);
+						__add_to_retry_queue(ha,sp);
+					}
+				}
+			}
+			spin_unlock_irqrestore(&ha->list_lock, flags);
+
+			/* Clear all Target Unsuspended bits */
+			for (t = 0; t < ha->max_targets; t++) {
+				if ((tq = ha->otgt[t]) == NULL)
+					continue;
+
+				if (test_bit(TQF_RETRY_CMDS, &tq->flags))
+					clear_bit(TQF_RETRY_CMDS, &tq->flags);
+			}
+			if (retry_cmds)
+				qla2x00_next(ha);
+
+			DEBUG(if (online_cnt > 0))
+			DEBUG(printk("scsi(%ld): dpc() found scsi reqs to "
+			    "restart= %d\n",
+			    ha->host_no, online_cnt));
+		}
+
+		if (ha->flags.mbox_busy) {
+			if (!list_empty(&ha->done_queue))
+				qla2x00_done(ha);
+
+			ha->dpc_active = 0;
+			continue;
+		}
+
+		if (test_and_clear_bit(ISP_ABORT_NEEDED, &ha->dpc_flags)) {
+
+			DEBUG(printk("scsi(%ld): dpc: sched "
+			    "qla2x00_abort_isp ha = %p\n",
+			    ha->host_no, ha));
+			if (!(test_and_set_bit(ABORT_ISP_ACTIVE,
+			    &ha->dpc_flags))) {
+
+				if (qla2x00_abort_isp(ha)) {
+					/* failed. retry later */
+					set_bit(ISP_ABORT_NEEDED,
+					    &ha->dpc_flags);
+				}
+				clear_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags);
+			}
+			DEBUG(printk("scsi(%ld): dpc: qla2x00_abort_isp end\n",
+			    ha->host_no));
+		}
+
+		if (test_and_clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags) &&
+		    (!(test_and_set_bit(RESET_ACTIVE, &ha->dpc_flags)))) {
+
+			DEBUG(printk("scsi(%ld): qla2x00_reset_marker()\n",
+			    ha->host_no));
+
+			qla2x00_rst_aen(ha);
+			clear_bit(RESET_ACTIVE, &ha->dpc_flags);
+		}
+
+		/* Retry each device up to login retry count */
+		if ((test_and_clear_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
+		    !test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) &&
+		    atomic_read(&ha->loop_state) != LOOP_DOWN) {
+
+			DEBUG(printk("scsi(%ld): qla2x00_port_login()\n",
+			    ha->host_no));
+
+			next_loopid = 0;
+			list_for_each_entry(fcport, &ha->fcports, list) {
+				if (fcport->port_type != FCT_TARGET)
+					continue;
+
+				/*
+				 * If the port is not ONLINE then try to login
+				 * to it if we haven't run out of retries.
+				 */
+				if (atomic_read(&fcport->state) != FCS_ONLINE &&
+				    fcport->login_retry) {
+
+					fcport->login_retry--;
+					if (fcport->flags & FCF_FABRIC_DEVICE) {
+						if (fcport->flags &
+						    FCF_TAPE_PRESENT)
+							qla2x00_fabric_logout(
+							    ha,
+							    fcport->loop_id);
+						status = qla2x00_fabric_login(
+						    ha, fcport, &next_loopid);
+					} else
+						status =
+						    qla2x00_local_device_login(
+							ha, fcport->loop_id);
+
+					if (status == QLA_SUCCESS) {
+						fcport->old_loop_id = fcport->loop_id;
+
+						DEBUG(printk("scsi(%ld): port login OK: logged in ID 0x%x\n",
+						    ha->host_no, fcport->loop_id));
+						
+						fcport->port_login_retry_count =
+						    ha->port_down_retry_count * PORT_RETRY_TIME;
+						atomic_set(&fcport->state, FCS_ONLINE);
+						atomic_set(&fcport->port_down_timer,
+						    ha->port_down_retry_count * PORT_RETRY_TIME);
+
+						fcport->login_retry = 0;
+					} else if (status == 1) {
+						set_bit(RELOGIN_NEEDED, &ha->dpc_flags);
+						/* retry the login again */
+						DEBUG(printk("scsi(%ld): Retrying %d login again loop_id 0x%x\n",
+						    ha->host_no,
+						    fcport->login_retry, fcport->loop_id));
+					} else {
+						fcport->login_retry = 0;
+					}
+				}
+				if (test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags))
+					break;
+			}
+			DEBUG(printk("scsi(%ld): qla2x00_port_login - end\n",
+			    ha->host_no));
+		}
+
+		if ((test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags)) &&
+		    atomic_read(&ha->loop_state) != LOOP_DOWN) {
+
+			clear_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags);
+			DEBUG(printk("scsi(%ld): qla2x00_login_retry()\n",
+			    ha->host_no));
+				
+			set_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags);
+
+			DEBUG(printk("scsi(%ld): qla2x00_login_retry - end\n",
+			    ha->host_no));
+		}
+
+		if (test_and_clear_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags)) {
+
+			DEBUG(printk("scsi(%ld): qla2x00_loop_resync()\n",
+			    ha->host_no));
+
+			if (!(test_and_set_bit(LOOP_RESYNC_ACTIVE,
+			    &ha->dpc_flags))) {
+
+				qla2x00_loop_resync(ha);
+
+				clear_bit(LOOP_RESYNC_ACTIVE, &ha->dpc_flags);
+			}
+
+			DEBUG(printk("scsi(%ld): qla2x00_loop_resync - end\n",
+			    ha->host_no));
+		}
+
+
+		if (test_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags)) {
+			DEBUG(printk("scsi(%ld): qla2x00_restart_queues()\n",
+			    ha->host_no));
+
+			qla2x00_restart_queues(ha, 0);
+
+			DEBUG(printk("scsi(%ld): qla2x00_restart_queues - end\n",
+			    ha->host_no));
+		}
+
+		if (test_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags)) {
+
+			DEBUG(printk("scsi(%ld): qla2x00_abort_queues()\n",
+			    ha->host_no));
+				
+			qla2x00_abort_queues(ha, 0);
+
+			DEBUG(printk("scsi(%ld): qla2x00_abort_queues - end\n",
+			    ha->host_no));
+		}
+
+		if (test_and_clear_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags)) {
+
+			DEBUG(printk("scsi(%ld): Rescan flagged fcports...\n",
+			    ha->host_no));
+
+			qla2x00_rescan_fcports(ha);
+
+			DEBUG(printk("scsi(%ld): Rescan flagged fcports..."
+			    "end.\n",
+			    ha->host_no));
+		}
+
+
+		if (!ha->interrupts_on)
+			qla2x00_enable_intrs(ha);
+
+		if (!list_empty(&ha->done_queue))
+			qla2x00_done(ha);
+
+		ha->dpc_active = 0;
+	} /* End of while(1) */
+
+	DEBUG(printk("scsi(%ld): DPC handler exiting\n", ha->host_no));
+
+	/*
+	 * Make sure that nobody tries to wake us up again.
+	 */
+	ha->dpc_wait = NULL;
+	ha->dpc_active = 0;
+
+	complete_and_exit(&ha->dpc_exited, 0);
+}
+
+/*
+ *  qla2x00_abort_queues
+ *	Abort all commands on queues on device
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Context:
+ *	Interrupt context.
+ */
+void
+qla2x00_abort_queues(scsi_qla_host_t *ha, uint8_t doneqflg) 
+{
+
+	srb_t       *sp;
+	struct list_head *list, *temp;
+	unsigned long flags;
+
+	clear_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
+
+	/* Return all commands device queues. */
+	spin_lock_irqsave(&ha->list_lock,flags);
+	list_for_each_safe(list, temp, &ha->pending_queue) {
+		sp = list_entry(list, srb_t, list);
+
+		if (sp->flags & SRB_ABORTED)
+			continue;
+
+		/* Remove srb from LUN queue. */
+		__del_from_pending_queue(ha, sp);
+
+		/* Set ending status. */
+		sp->cmd->result = DID_BUS_BUSY << 16;
+
+		__add_to_done_queue(ha, sp);
+	}
+	spin_unlock_irqrestore(&ha->list_lock, flags);
+}
+
+/*
+*  qla2x00_rst_aen
+*      Processes asynchronous reset.
+*
+* Input:
+*      ha  = adapter block pointer.
+*/
+static void
+qla2x00_rst_aen(scsi_qla_host_t *ha) 
+{
+	if (ha->flags.online && !ha->flags.reset_active &&
+	    !atomic_read(&ha->loop_down_timer) &&
+	    !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags))) {
+		do {
+			clear_bit(RESET_MARKER_NEEDED, &ha->dpc_flags);
+
+			/*
+			 * Issue marker command only when we are going to start
+			 * the I/O.
+			 */
+			ha->marker_needed = 1;
+		} while (!atomic_read(&ha->loop_down_timer) &&
+		    (test_bit(RESET_MARKER_NEEDED, &ha->dpc_flags)));
+	}
+}
+
+
+/*
+ * This routine will allocate SP from the free queue
+ * input:
+ *        scsi_qla_host_t *
+ * output:
+ *        srb_t * or NULL
+ */
+static srb_t *
+qla2x00_get_new_sp(scsi_qla_host_t *ha)
+{
+	srb_t *sp;
+
+	sp = mempool_alloc(ha->srb_mempool, GFP_ATOMIC);
+	if (sp)
+		atomic_set(&sp->ref_count, 1);
+	return (sp);
+}
+
+/**************************************************************************
+*   qla2x00_timer
+*
+* Description:
+*   One second timer
+*
+* Context: Interrupt
+***************************************************************************/
+static void
+qla2x00_timer(scsi_qla_host_t *ha)
+{
+	int		t,l;
+	unsigned long	cpu_flags = 0;
+	fc_port_t	*fcport;
+	os_lun_t *lq;
+	os_tgt_t *tq;
+	int		start_dpc = 0;
+	int		index;
+	srb_t		*sp;
+
+	/*
+	 * We try and restart any request in the retry queue every second.
+	 */
+	if (!list_empty(&ha->retry_queue)) {
+		set_bit(PORT_RESTART_NEEDED, &ha->dpc_flags);
+		start_dpc++;
+	}
+
+	/*
+	 * We try and restart any request in the scsi_retry queue every second.
+	 */
+	if (!list_empty(&ha->scsi_retry_queue)) {
+		set_bit(SCSI_RESTART_NEEDED, &ha->dpc_flags);
+		start_dpc++;
+	}
+
+	/*
+	 * Ports - Port down timer.
+	 *
+	 * Whenever, a port is in the LOST state we start decrementing its port
+	 * down timer every second until it reaches zero. Once  it reaches zero
+	 * the port it marked DEAD. 
+	 */
+	t = 0;
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		if (fcport->port_type != FCT_TARGET)
+			continue;
+
+		if (atomic_read(&fcport->state) == FCS_DEVICE_LOST) {
+
+			if (atomic_read(&fcport->port_down_timer) == 0)
+				continue;
+
+			if (atomic_dec_and_test(&fcport->port_down_timer) != 0) 
+				atomic_set(&fcport->state, FCS_DEVICE_DEAD);
+			
+			DEBUG(printk("scsi(%ld): fcport-%d - port retry count: "
+			    "%d remainning\n",
+			    ha->host_no,
+			    t, atomic_read(&fcport->port_down_timer)));
+		}
+		t++;
+	} /* End of for fcport  */
+
+	/*
+	 * LUNS - lun suspend timer.
+	 *
+	 * Whenever, a lun is suspended the timer starts decrementing its
+	 * suspend timer every second until it reaches zero. Once  it reaches
+	 * zero the lun retry count is decremented. 
+	 */
+
+	/*
+	 * FIXME(dg) - Need to convert this linear search of luns into a search
+	 * of a list of suspended luns.
+	 */
+	for (t = 0; t < ha->max_targets; t++) {
+		if ((tq = ha->otgt[t]) == NULL)
+			continue;
+
+		for (l = 0; l < ha->max_luns; l++) {
+			if ((lq = (os_lun_t *) tq->olun[l]) == NULL)
+				continue;
+
+			spin_lock_irqsave(&lq->q_lock, cpu_flags);
+			if (lq->q_state == LUN_STATE_WAIT &&
+				atomic_read(&lq->q_timer) != 0) {
+
+				if (atomic_dec_and_test(&lq->q_timer) != 0) {
+					/*
+					 * A delay should immediately
+					 * transition to a READY state
+					 */
+					if (test_and_clear_bit(LUN_EXEC_DELAYED,
+					    &lq->q_flag)) {
+						lq->q_state = LUN_STATE_READY;
+					}
+					else {
+						lq->q_count++;
+						if (lq->q_count == lq->q_max)
+							lq->q_state =
+							    LUN_STATE_TIMEOUT;
+						else
+							lq->q_state =
+							    LUN_STATE_RUN;
+					}
+				}
+				DEBUG3(printk("scsi(%ld): lun%d - timer %d, "
+				    "count=%d, max=%d, state=%d\n",
+				    ha->host_no,
+				    l,
+				    atomic_read(&lq->q_timer),
+				    lq->q_count, lq->q_max, lq->q_state));
+			}
+			spin_unlock_irqrestore(&lq->q_lock, cpu_flags);
+		} /* End of for luns  */
+	} /* End of for targets  */
+
+	/* Loop down handler. */
+	if (atomic_read(&ha->loop_down_timer) > 0 &&
+	    !(test_bit(ABORT_ISP_ACTIVE, &ha->dpc_flags)) && ha->flags.online) {
+
+		if (atomic_read(&ha->loop_down_timer) ==
+		    ha->loop_down_abort_time) {
+
+			DEBUG(printk("scsi(%ld): Loop Down - aborting the "
+			    "queues before time expire\n",
+			    ha->host_no));
+
+			if (!IS_QLA2100(ha) && ha->link_down_timeout)
+				atomic_set(&ha->loop_state, LOOP_DEAD); 
+
+			/* Schedule an ISP abort to return any tape commands. */
+			spin_lock_irqsave(&ha->hardware_lock, cpu_flags);
+			for (index = 1; index < MAX_OUTSTANDING_COMMANDS;
+			    index++) {
+				sp = ha->outstanding_cmds[index];
+				if (!sp)
+					continue;
+				if (!(sp->fclun->fcport->flags &
+				    FCF_TAPE_PRESENT))
+					continue;
+
+				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+				break;
+			}
+			spin_unlock_irqrestore(&ha->hardware_lock, cpu_flags);
+
+			set_bit(ABORT_QUEUES_NEEDED, &ha->dpc_flags);
+			start_dpc++;
+		}
+
+		/* if the loop has been down for 4 minutes, reinit adapter */
+		if (atomic_dec_and_test(&ha->loop_down_timer) != 0) {
+			DEBUG(printk("scsi(%ld): Loop down exceed 4 mins - "
+			    "restarting queues.\n",
+			    ha->host_no));
+
+			set_bit(RESTART_QUEUES_NEEDED, &ha->dpc_flags);
+			start_dpc++;
+
+			if (!(ha->device_flags & DFLG_NO_CABLE)) {
+				DEBUG(printk("scsi(%ld): Loop down - "
+				    "aborting ISP.\n",
+				    ha->host_no));
+				qla_printk(KERN_WARNING, ha,
+				    "Loop down - aborting ISP.\n");
+
+				set_bit(ISP_ABORT_NEEDED, &ha->dpc_flags);
+			}
+		}
+		DEBUG3(printk("scsi(%ld): Loop Down - seconds remainning %d\n",
+		    ha->host_no,
+		    atomic_read(&ha->loop_down_timer)));
+	}
+
+	/*
+	 * Done Q Handler -- dgFIXME This handler will kick off doneq if we
+	 * haven't process it in 2 seconds.
+	 */
+	if (!list_empty(&ha->done_queue))
+		qla2x00_done(ha);
+
+
+	/* Schedule the DPC routine if needed */
+	if ((test_bit(ISP_ABORT_NEEDED, &ha->dpc_flags) ||
+	    test_bit(LOOP_RESYNC_NEEDED, &ha->dpc_flags) ||
+	    start_dpc ||
+	    test_bit(LOGIN_RETRY_NEEDED, &ha->dpc_flags) ||
+	    test_bit(RELOGIN_NEEDED, &ha->dpc_flags)) &&
+	    ha->dpc_wait && !ha->dpc_active) {
+
+		up(ha->dpc_wait);
+	}
+
+	qla2x00_restart_timer(ha, WATCH_INTERVAL);
+}
+
+/*
+ * qla2x00_extend_timeout
+ *      This routine will extend the timeout to the specified value.
+ *
+ * Input:
+ *      cmd = SCSI command structure
+ *
+ * Returns:
+ *      None.
+ */
+void 
+qla2x00_extend_timeout(struct scsi_cmnd *cmd, int timeout) 
+{
+	srb_t *sp = (srb_t *) CMD_SP(cmd);
+	u_long our_jiffies = (timeout * HZ) + jiffies;
+
+    	sp->ext_history= 0; 
+	sp->e_start = jiffies;
+	if (cmd->eh_timeout.function) {
+		mod_timer(&cmd->eh_timeout,our_jiffies);
+		sp->ext_history |= 1;
+	}
+	if (sp->timer.function != NULL) {
+		/* 
+		 * Our internal timer should timeout before the midlayer has a
+		 * chance begin the abort process
+		 */
+		mod_timer(&sp->timer,our_jiffies - (QLA_CMD_TIMER_DELTA * HZ));
+
+    	 	sp->ext_history |= 2;
+	}
+}
+
+/**************************************************************************
+*   qla2x00_cmd_timeout
+*
+* Description:
+*       Handles the command if it times out in any state.
+*
+* Input:
+*     sp - pointer to validate
+*
+* Returns:
+* None.
+* Note:Need to add the support for if( sp->state == SRB_FAILOVER_STATE).
+**************************************************************************/
+void
+qla2x00_cmd_timeout(srb_t *sp)
+{
+	int t, l;
+	int processed;
+	scsi_qla_host_t *vis_ha, *dest_ha;
+	struct scsi_cmnd *cmd;
+	unsigned long flags, cpu_flags;
+	fc_port_t *fcport;
+
+	cmd = sp->cmd;
+	vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
+
+	DEBUG3(printk("cmd_timeout: Entering sp->state = %x\n", sp->state));
+
+	t = cmd->device->id;
+	l = cmd->device->lun;
+	fcport = sp->fclun->fcport;
+	dest_ha = sp->ha;
+
+	/*
+	 * If IO is found either in retry Queue 
+	 *    OR in Lun Queue
+	 * Return this IO back to host
+	 */
+	spin_lock_irqsave(&vis_ha->list_lock, flags);
+	processed = 0;
+	if (sp->state == SRB_PENDING_STATE) {
+		__del_from_pending_queue(vis_ha, sp);
+		DEBUG2(printk("scsi(%ld): Found in Pending queue pid %ld, "
+		    "State = %x., fcport state=%d sjiffs=%lx njiffs=%lx\n",
+		    vis_ha->host_no, cmd->serial_number, sp->state,
+		    atomic_read(&fcport->state), sp->r_start, jiffies));
+
+		/*
+		 * If FC_DEVICE is marked as dead return the cmd with
+		 * DID_NO_CONNECT status.  Otherwise set the host_byte to
+		 * DID_BUS_BUSY to let the OS  retry this cmd.
+		 */
+		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD ||
+		    atomic_read(&fcport->ha->loop_state) == LOOP_DEAD) {
+			cmd->result = DID_NO_CONNECT << 16;
+			if (atomic_read(&fcport->ha->loop_state) == LOOP_DOWN) 
+				sp->err_id = SRB_ERR_LOOP;
+			else
+				sp->err_id = SRB_ERR_PORT;
+		} else {
+			cmd->result = DID_BUS_BUSY << 16;
+		}
+		__add_to_done_queue(vis_ha, sp);
+		processed++;
+	} 
+	spin_unlock_irqrestore(&vis_ha->list_lock, flags);
+
+	if (processed) {
+		qla2x00_done(vis_ha);
+		return;
+	}
+
+	spin_lock_irqsave(&dest_ha->list_lock, flags);
+	if ((sp->state == SRB_RETRY_STATE) ||
+	    (sp->state == SRB_SCSI_RETRY_STATE)) {
+
+		DEBUG2(printk("scsi(%ld): Found in (Scsi) Retry queue or "
+		    "failover Q pid %ld, State = %x., fcport state=%d "
+		    "jiffies=%lx retried=%d\n",
+		    dest_ha->host_no, cmd->serial_number, sp->state,
+		    atomic_read(&fcport->state), jiffies, cmd->retries));
+
+		if ((sp->state == SRB_RETRY_STATE)) {
+			__del_from_retry_queue(dest_ha, sp);
+		} else if ((sp->state == SRB_SCSI_RETRY_STATE)) {
+			__del_from_scsi_retry_queue(dest_ha, sp);
+		} 
+
+		/*
+		 * If FC_DEVICE is marked as dead return the cmd with
+		 * DID_NO_CONNECT status.  Otherwise set the host_byte to
+		 * DID_BUS_BUSY to let the OS  retry this cmd.
+		 */
+		if ((atomic_read(&fcport->state) == FCS_DEVICE_DEAD) ||
+		    atomic_read(&dest_ha->loop_state) == LOOP_DEAD) {
+			qla2x00_extend_timeout(cmd, EXTEND_CMD_TIMEOUT);
+			cmd->result = DID_NO_CONNECT << 16;
+			if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN) 
+				sp->err_id = SRB_ERR_LOOP;
+			else
+				sp->err_id = SRB_ERR_PORT;
+		} else {
+			cmd->result = DID_BUS_BUSY << 16;
+		}
+
+		__add_to_done_queue(dest_ha, sp);
+		processed++;
+	} 
+	spin_unlock_irqrestore(&dest_ha->list_lock, flags);
+
+	if (processed) {
+		qla2x00_done(dest_ha);
+		return;
+	}
+
+	spin_lock_irqsave(&dest_ha->list_lock, cpu_flags);
+	if (sp->state == SRB_DONE_STATE) {
+		/* IO in done_q  -- leave it */
+		DEBUG(printk("scsi(%ld): Found in Done queue pid %ld sp=%p.\n",
+		    dest_ha->host_no, cmd->serial_number, sp));
+	} else if (sp->state == SRB_SUSPENDED_STATE) {
+		DEBUG(printk("scsi(%ld): Found SP %p in suspended state  "
+		    "- pid %ld:\n",
+		    dest_ha->host_no, sp, cmd->serial_number));
+		DEBUG(qla2x00_dump_buffer((uint8_t *)sp, sizeof(srb_t));)
+	} else if (sp->state == SRB_ACTIVE_STATE) {
+		/*
+		 * IO is with ISP find the command in our active list.
+		 */
+		spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags);
+		spin_lock_irqsave(&dest_ha->hardware_lock, flags);
+		if (sp == dest_ha->outstanding_cmds[
+		    (unsigned long)sp->cmd->host_scribble]) {
+
+			DEBUG(printk("cmd_timeout: Found in ISP \n"));
+
+			if (sp->flags & SRB_TAPE) {
+				/*
+				 * We cannot allow the midlayer error handler
+				 * to wakeup and begin the abort process.
+				 * Extend the timer so that the firmware can
+				 * properly return the IOCB.
+				 */
+				DEBUG(printk("cmd_timeout: Extending timeout "
+				    "of FCP2 tape command!\n"));
+				qla2x00_extend_timeout(sp->cmd,
+				    EXTEND_CMD_TIMEOUT);
+			}
+			sp->state = SRB_ACTIVE_TIMEOUT_STATE;
+			spin_unlock_irqrestore(&dest_ha->hardware_lock, flags);
+		} else {
+			spin_unlock_irqrestore(&dest_ha->hardware_lock, flags);
+			printk(KERN_INFO 
+				"qla_cmd_timeout: State indicates it is with "
+				"ISP, But not in active array\n");
+		}
+		spin_lock_irqsave(&dest_ha->list_lock, cpu_flags);
+	} else if (sp->state == SRB_ACTIVE_TIMEOUT_STATE) {
+		DEBUG(printk("qla2100%ld: Found in Active timeout state"
+				"pid %ld, State = %x., \n",
+				dest_ha->host_no,
+				sp->cmd->serial_number, sp->state);)
+	} else {
+		/* EMPTY */
+		DEBUG2(printk("cmd_timeout%ld: LOST command state = "
+				"0x%x, sp=%p\n",
+				vis_ha->host_no, sp->state,sp);)
+
+		qla_printk(KERN_INFO, vis_ha,
+			"cmd_timeout: LOST command state = 0x%x\n", sp->state);
+	}
+	spin_unlock_irqrestore(&dest_ha->list_lock, cpu_flags);
+
+	DEBUG3(printk("cmd_timeout: Leaving\n");)
+}
+
+/**************************************************************************
+* qla2x00_done
+*      Process completed commands.
+*
+* Input:
+*      old_ha           = adapter block pointer.
+*
+**************************************************************************/
+void
+qla2x00_done(scsi_qla_host_t *old_ha)
+{
+	os_lun_t	*lq;
+	struct scsi_cmnd *cmd;
+	unsigned long	flags = 0;
+	scsi_qla_host_t	*ha;
+	scsi_qla_host_t	*vis_ha;
+	int	send_marker_once = 0;
+	srb_t           *sp, *sptemp;
+	LIST_HEAD(local_sp_list);
+
+	/*
+	 * Get into local queue such that we do not wind up calling done queue
+	 * tasklet for the same IOs from DPC or any other place.
+	 */
+	spin_lock_irqsave(&old_ha->list_lock, flags);
+	list_splice_init(&old_ha->done_queue, &local_sp_list);
+	spin_unlock_irqrestore(&old_ha->list_lock, flags);
+
+	/*
+	 * All done commands are in the local queue, now do the call back.
+	 */
+	list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
+		old_ha->done_q_cnt--;
+        	sp->state = SRB_NO_QUEUE_STATE;
+
+		/* remove command from local list */
+		list_del_init(&sp->list);
+
+		cmd = sp->cmd;
+		if (cmd == NULL)
+		 	continue;
+
+		vis_ha = (scsi_qla_host_t *)cmd->device->host->hostdata;
+		lq = sp->lun_queue;
+		ha = sp->ha;
+
+		if (sp->flags & SRB_DMA_VALID) {
+			sp->flags &= ~SRB_DMA_VALID;
+
+			/* Release memory used for this I/O */
+			if (cmd->use_sg) {
+				pci_unmap_sg(ha->pdev, cmd->request_buffer,
+				    cmd->use_sg, cmd->sc_data_direction);
+			} else if (cmd->request_bufflen) {
+				pci_unmap_page(ha->pdev, sp->dma_handle,
+				    cmd->request_bufflen,
+				    cmd->sc_data_direction);
+			}
+		}
+
+
+		switch (host_byte(cmd->result)) {
+			case DID_OK:
+			case DID_ERROR:
+				break;
+
+			case DID_RESET:
+				/*
+				 * Set marker needed, so we don't have to
+				 * send multiple markers
+				 */
+				if (!send_marker_once) {
+					ha->marker_needed = 1;
+					send_marker_once++;
+				}
+
+				/*
+				 * WORKAROUND
+				 *
+				 * A backdoor device-reset requires different
+				 * error handling.  This code differentiates
+				 * between normal error handling and the
+				 * backdoor method.
+				 *
+				 */
+				if (ha->host->eh_active != EH_ACTIVE)
+					cmd->result = DID_BUS_BUSY << 16;
+				break;
+
+
+			case DID_ABORT:
+				sp->flags &= ~SRB_ABORT_PENDING;
+				sp->flags |= SRB_ABORTED;
+
+				if (sp->flags & SRB_TIMEOUT)
+					cmd->result = DID_TIME_OUT << 16;
+
+				break;
+
+			default:
+				DEBUG2(printk("scsi(%ld:%d:%d) %s: did_error "
+				    "= %d, comp-scsi= 0x%x-0x%x pid=%ld.\n",
+				    vis_ha->host_no,
+				    cmd->device->id, cmd->device->lun,
+				    __func__,
+				    host_byte(cmd->result),
+				    CMD_COMPL_STATUS(cmd),
+				    CMD_SCSI_STATUS(cmd), cmd->serial_number));
+				break;
+		}
+
+		/*
+		 * Call the mid-level driver interrupt handler -- via sp_put()
+		 */
+		sp_put(ha, sp);
+	} /* end of while */
+}
+
+/*
+ * qla2x00_process_response_queue_in_zio_mode
+ *	Process response queue completion as fast as possible
+ *	to achieve Zero Interrupt Opertions-ZIO
+ *
+ * Input:
+ *	ha = adapter block pointer.
+ *
+ * Context:
+ *	Kernel context.
+ */
+static inline void
+qla2x00_process_response_queue_in_zio_mode(scsi_qla_host_t *ha)
+{
+	unsigned long flags;
+
+	/* Check for unprocessed commands in response queue. */
+	if (!ha->flags.process_response_queue)
+		return;
+	if (!ha->flags.online)
+		return;
+	if (ha->response_ring_ptr->signature == RESPONSE_PROCESSED)
+		return;
+	
+	spin_lock_irqsave(&ha->hardware_lock,flags);
+	qla2x00_process_response_queue(ha);
+	spin_unlock_irqrestore(&ha->hardware_lock, flags);
+}
+
+/*
+ * qla2x00_next
+ *	Retrieve and process next job in the LUN queue.
+ *
+ * Input:
+ *	tq = SCSI target queue pointer.
+ *	lq = SCSI LUN queue pointer.
+ *	TGT_LOCK must be already obtained.
+ *
+ * Output:
+ *	Releases TGT_LOCK upon exit.
+ *
+ * Context:
+ *	Kernel/Interrupt context.
+ * 
+ * Note: This routine will always try to start I/O from visible HBA.
+ */
+void
+qla2x00_next(scsi_qla_host_t *vis_ha) 
+{
+	int		rval;
+	unsigned long   flags;
+	scsi_qla_host_t *dest_ha;
+	fc_port_t	*fcport;
+	srb_t           *sp, *sptemp;
+	LIST_HEAD(local_sp_list);
+
+	dest_ha = NULL;
+
+	spin_lock_irqsave(&vis_ha->list_lock, flags);
+	list_splice_init(&vis_ha->pending_queue, &local_sp_list);
+	vis_ha->qthreads = 0;
+	spin_unlock_irqrestore(&vis_ha->list_lock, flags);
+
+	list_for_each_entry_safe(sp, sptemp, &local_sp_list, list) {
+		list_del_init(&sp->list);
+        	sp->state = SRB_NO_QUEUE_STATE;
+
+		fcport = sp->fclun->fcport;
+		dest_ha = fcport->ha;
+
+		/* If device is dead then send request back to OS */
+		if (atomic_read(&fcport->state) == FCS_DEVICE_DEAD) {
+			sp->cmd->result = DID_NO_CONNECT << 16;
+			if (atomic_read(&dest_ha->loop_state) == LOOP_DOWN) 
+				sp->err_id = SRB_ERR_LOOP;
+			else
+				sp->err_id = SRB_ERR_PORT;
+
+			DEBUG3(printk("scsi(%ld): loop/port is down - pid=%ld, "
+			    "sp=%p err_id=%d loopid=0x%x queued to dest HBA "
+			    "scsi%ld.\n", dest_ha->host_no,
+			    sp->cmd->serial_number, sp, sp->err_id,
+			    fcport->loop_id, dest_ha->host_no));
+			/* 
+			 * Initiate a failover - done routine will initiate.
+			 */
+			add_to_done_queue(vis_ha, sp);
+
+			continue;
+		}
+
+		/*
+		 * SCSI Kluge: Whenever, we need to wait for an event such as
+		 * loop down (i.e. loop_down_timer ) or port down (i.e.  LUN
+		 * request qeueue is suspended) then we will recycle new
+		 * commands back to the SCSI layer.  We do this because this is
+		 * normally a temporary condition and we don't want the
+		 * mid-level scsi.c driver to get upset and start aborting
+		 * commands.  The timeout value is extracted from the command
+		 * minus 1-second and put on a retry queue (watchdog). Once the
+		 * command timeout it is returned to the mid-level with a BUSY
+		 * status, so the mid-level will retry it. This process
+		 * continues until the LOOP DOWN time expires or the condition
+		 * goes away.
+		 */
+		if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
+		    (atomic_read(&fcport->state) != FCS_ONLINE ||
+			test_bit(ABORT_ISP_ACTIVE, &dest_ha->dpc_flags) ||
+			atomic_read(&dest_ha->loop_state) != LOOP_READY)) {
+
+			DEBUG3(printk("scsi(%ld): pid=%ld port=0x%x state=%d "
+			    "loop state=%d, loop counter=0x%x "
+			    "dpc_flags=0x%lx\n", sp->cmd->serial_number,
+			    dest_ha->host_no, fcport->loop_id,
+			    atomic_read(&fcport->state),
+			    atomic_read(&dest_ha->loop_state),
+			    atomic_read(&dest_ha->loop_down_timer),
+			    dest_ha->dpc_flags));
+
+			qla2x00_extend_timeout(sp->cmd, EXTEND_CMD_TIMEOUT);
+			add_to_retry_queue(vis_ha, sp);
+
+			continue;
+		} 
+
+		/*
+		 * If this request's lun is suspended then put the request on
+		 * the  scsi_retry queue. 
+		 */
+	 	if (!(sp->flags & (SRB_IOCTL | SRB_TAPE)) &&
+		    sp->lun_queue->q_state == LUN_STATE_WAIT) {
+			DEBUG3(printk("scsi(%ld): lun wait state - pid=%ld, "
+			    "opcode=%d, allowed=%d, retries=%d\n",
+			    dest_ha->host_no,
+			    sp->cmd->serial_number,
+			    sp->cmd->cmnd[0],
+			    sp->cmd->allowed,
+			    sp->cmd->retries));
+				
+			add_to_scsi_retry_queue(vis_ha, sp);
+
+			continue;
+		}
+
+		sp->lun_queue->io_cnt++;
+
+		rval = qla2x00_start_scsi(sp);
+		if (rval != QLA_SUCCESS) {
+			/* Place request back on top of device queue */
+			/* add to the top of queue */
+			add_to_pending_queue_head(vis_ha, sp);
+
+			sp->lun_queue->io_cnt--;
+		}
+	}
+
+	if (!IS_QLA2100(vis_ha) && !IS_QLA2200(vis_ha)) {
+		/* Process response_queue if ZIO support is enabled*/ 
+		qla2x00_process_response_queue_in_zio_mode(vis_ha);
+
+	}
+}
+
+/* XXX(hch): crude hack to emulate a down_timeout() */
+int
+qla2x00_down_timeout(struct semaphore *sema, unsigned long timeout)
+{
+	const unsigned int step = HZ/10;
+
+	do {
+		if (!down_trylock(sema))
+			return 0;
+		set_current_state(TASK_INTERRUPTIBLE);
+		if (schedule_timeout(step))
+			break;
+	} while ((timeout -= step) > 0);
+
+	return -ETIMEDOUT;
+}
+
+static void
+qla2xxx_get_port_id(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
+	struct fc_port *fc;
+
+	list_for_each_entry(fc, &ha->fcports, list) {
+		if (fc->os_target_id == starget->id) {
+			fc_starget_port_id(starget) = fc->d_id.b.domain << 16 |
+				fc->d_id.b.area << 8 | 
+				fc->d_id.b.al_pa;
+			return;
+		}
+	}
+	fc_starget_port_id(starget) = -1;
+}
+
+static void
+qla2xxx_get_port_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
+	struct fc_port *fc;
+
+	list_for_each_entry(fc, &ha->fcports, list) {
+		if (fc->os_target_id == starget->id) {
+			fc_starget_port_name(starget) =
+				__be64_to_cpu(*(uint64_t *)fc->port_name);
+			return;
+		}
+	}
+	fc_starget_port_name(starget) = -1;
+}
+
+static void
+qla2xxx_get_node_name(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	scsi_qla_host_t *ha = to_qla_host(shost);
+	struct fc_port *fc;
+
+	list_for_each_entry(fc, &ha->fcports, list) {
+		if (fc->os_target_id == starget->id) {
+			fc_starget_node_name(starget) =
+				__be64_to_cpu(*(uint64_t *)fc->node_name);
+			return;
+		}
+	}
+	fc_starget_node_name(starget) = -1;
+}
+
+static struct fc_function_template qla2xxx_transport_functions = {
+	.get_starget_port_id = qla2xxx_get_port_id,
+	.show_starget_port_id = 1,
+	.get_starget_port_name = qla2xxx_get_port_name,
+	.show_starget_port_name = 1,
+	.get_starget_node_name = qla2xxx_get_node_name,
+	.show_starget_node_name = 1,
+};
+
+/**
+ * qla2x00_module_init - Module initialization.
+ **/
+static int __init
+qla2x00_module_init(void)
+{
+	/* Allocate cache for SRBs. */
+	sprintf(srb_cachep_name, "qla2xxx_srbs");
+	srb_cachep = kmem_cache_create(srb_cachep_name, sizeof(srb_t), 0,
+	    SLAB_HWCACHE_ALIGN, NULL, NULL);
+	if (srb_cachep == NULL) {
+		printk(KERN_ERR
+		    "qla2xxx: Unable to allocate SRB cache...Failing load!\n");
+		return -ENOMEM;
+	}
+
+	/* Derive version string. */
+	strcpy(qla2x00_version_str, QLA2XXX_VERSION);
+#if DEBUG_QLA2100
+	strcat(qla2x00_version_str, "-debug");
+#endif
+
+	qla2xxx_transport_template = fc_attach_transport(&qla2xxx_transport_functions);
+	if (!qla2xxx_transport_template)
+		return -ENODEV;
+
+	printk(KERN_INFO "QLogic Fibre Channel HBA Driver\n");
+	return 0;
+}
+
+/**
+ * qla2x00_module_exit - Module cleanup.
+ **/
+static void __exit
+qla2x00_module_exit(void)
+{
+	/* Free SRBs cache. */
+	if (srb_cachep != NULL) {
+		if (kmem_cache_destroy(srb_cachep) != 0) {
+			printk(KERN_ERR
+			    "qla2xxx: Unable to free SRB cache...Memory pools "
+			    "still active?\n");
+		}
+		srb_cachep = NULL;
+	}
+
+	fc_release_transport(qla2xxx_transport_template);
+}
+
+module_init(qla2x00_module_init);
+module_exit(qla2x00_module_exit);
+
+MODULE_AUTHOR("QLogic Corporation");
+MODULE_DESCRIPTION("QLogic Fibre Channel HBA Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(QLA2XXX_VERSION);
diff --git a/drivers/scsi/qla2xxx/qla_rscn.c b/drivers/scsi/qla2xxx/qla_rscn.c
new file mode 100644
index 0000000..fb545b5
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_rscn.c
@@ -0,0 +1,1437 @@
+/*
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ */
+#include "qla_def.h"
+
+/**
+ * IO descriptor handle definitions.
+ *
+ * Signature form:
+ *
+ *	|31------28|27-------------------12|11-------0|
+ *	|   Type   |   Rolling Signature   |   Index  |
+ *	|----------|-----------------------|----------|
+ *
+ **/
+
+#define HDL_TYPE_SCSI		0
+#define HDL_TYPE_ASYNC_IOCB	0x0A
+
+#define HDL_INDEX_BITS	12
+#define HDL_ITER_BITS	16
+#define HDL_TYPE_BITS	4
+
+#define HDL_INDEX_MASK	((1UL << HDL_INDEX_BITS) - 1)
+#define HDL_ITER_MASK	((1UL << HDL_ITER_BITS) - 1)
+#define HDL_TYPE_MASK	((1UL << HDL_TYPE_BITS) - 1)
+
+#define HDL_INDEX_SHIFT	0
+#define HDL_ITER_SHIFT	(HDL_INDEX_SHIFT + HDL_INDEX_BITS)
+#define HDL_TYPE_SHIFT	(HDL_ITER_SHIFT + HDL_ITER_BITS)
+
+/* Local Prototypes. */
+static inline uint32_t qla2x00_to_handle(uint16_t, uint16_t, uint16_t);
+static inline uint16_t qla2x00_handle_to_idx(uint32_t);
+static inline uint32_t qla2x00_iodesc_to_handle(struct io_descriptor *);
+static inline struct io_descriptor *qla2x00_handle_to_iodesc(scsi_qla_host_t *,
+    uint32_t);
+
+static inline struct io_descriptor *qla2x00_alloc_iodesc(scsi_qla_host_t *);
+static inline void qla2x00_free_iodesc(struct io_descriptor *);
+static inline void qla2x00_init_io_descriptors(scsi_qla_host_t *);
+
+static void qla2x00_iodesc_timeout(unsigned long);
+static inline void qla2x00_add_iodesc_timer(struct io_descriptor *);
+static inline void qla2x00_remove_iodesc_timer(struct io_descriptor *);
+
+static inline void qla2x00_update_login_fcport(scsi_qla_host_t *,
+    struct mbx_entry *, fc_port_t *);
+
+static int qla2x00_send_abort_iocb(scsi_qla_host_t *, struct io_descriptor *,
+    uint32_t, int);
+static int qla2x00_send_abort_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
+    struct mbx_entry *);
+
+static int qla2x00_send_adisc_iocb(scsi_qla_host_t *, struct io_descriptor *,
+    int);
+static int qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
+    struct mbx_entry *);
+
+static int qla2x00_send_logout_iocb(scsi_qla_host_t *, struct io_descriptor *,
+    int);
+static int qla2x00_send_logout_iocb_cb(scsi_qla_host_t *,
+    struct io_descriptor *, struct mbx_entry *);
+
+static int qla2x00_send_login_iocb(scsi_qla_host_t *, struct io_descriptor *,
+    port_id_t *, int);
+static int qla2x00_send_login_iocb_cb(scsi_qla_host_t *, struct io_descriptor *,
+    struct mbx_entry *);
+
+/** 
+ * Mailbox IOCB callback array.
+ **/
+static int (*iocb_function_cb_list[LAST_IOCB_CB])
+	(scsi_qla_host_t *, struct io_descriptor *, struct mbx_entry *) = {
+
+	qla2x00_send_abort_iocb_cb,
+	qla2x00_send_adisc_iocb_cb,
+	qla2x00_send_logout_iocb_cb,
+	qla2x00_send_login_iocb_cb,
+};
+
+
+/** 
+ * Generic IO descriptor handle routines.
+ **/
+
+/**
+ * qla2x00_to_handle() - Create a descriptor handle.
+ * @type: descriptor type
+ * @iter: descriptor rolling signature
+ * @idx: index to the descriptor array
+ *
+ * Returns a composite handle based in the @type, @iter, and @idx.
+ */
+static inline uint32_t
+qla2x00_to_handle(uint16_t type, uint16_t iter, uint16_t idx)
+{
+	return ((uint32_t)(((uint32_t)type << HDL_TYPE_SHIFT) |
+	    ((uint32_t)iter << HDL_ITER_SHIFT) |
+	    ((uint32_t)idx << HDL_INDEX_SHIFT)));
+}
+
+/**
+ * qla2x00_handle_to_idx() - Retrive the index for a given handle.
+ * @handle: descriptor handle
+ *
+ * Returns the index specified by the @handle.
+ */
+static inline uint16_t
+qla2x00_handle_to_idx(uint32_t handle)
+{
+	return ((uint16_t)(((handle) >> HDL_INDEX_SHIFT) & HDL_INDEX_MASK));
+}
+
+/**
+ * qla2x00_iodesc_to_handle() - Convert an IO descriptor to a unique handle.
+ * @iodesc: io descriptor
+ *
+ * Returns a unique handle for @iodesc.
+ */
+static inline uint32_t
+qla2x00_iodesc_to_handle(struct io_descriptor *iodesc)
+{
+	uint32_t handle;
+
+	handle = qla2x00_to_handle(HDL_TYPE_ASYNC_IOCB,
+	    ++iodesc->ha->iodesc_signature, iodesc->idx);
+	iodesc->signature = handle;
+
+	return (handle);
+}
+
+/**
+ * qla2x00_handle_to_iodesc() - Retrieve an IO descriptor given a unique handle.
+ * @ha: HA context
+ * @handle: handle to io descriptor
+ *
+ * Returns a pointer to the io descriptor, or NULL, if the io descriptor does
+ * not exist or the io descriptors signature does not @handle.
+ */
+static inline struct io_descriptor *
+qla2x00_handle_to_iodesc(scsi_qla_host_t *ha, uint32_t handle)
+{
+	uint16_t idx;
+	struct io_descriptor *iodesc;
+
+	idx = qla2x00_handle_to_idx(handle);
+	iodesc = &ha->io_descriptors[idx];
+	if (iodesc)
+		if (iodesc->signature != handle)
+			iodesc = NULL;
+
+	return (iodesc);
+}
+
+
+/** 
+ * IO descriptor allocation routines.
+ **/
+
+/**
+ * qla2x00_alloc_iodesc() - Allocate an IO descriptor from the pool.
+ * @ha: HA context
+ *
+ * Returns a pointer to the allocated io descriptor, or NULL, if none available.
+ */
+static inline struct io_descriptor *
+qla2x00_alloc_iodesc(scsi_qla_host_t *ha)
+{
+	uint16_t iter;
+	struct io_descriptor *iodesc;
+
+	iodesc = NULL;
+	for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) {
+		if (ha->io_descriptors[iter].used)
+			continue;
+
+		iodesc = &ha->io_descriptors[iter];
+		iodesc->used = 1;
+		iodesc->idx = iter;
+		init_timer(&iodesc->timer);
+		iodesc->ha = ha;
+		iodesc->signature = qla2x00_iodesc_to_handle(iodesc);
+		break;
+	}
+
+	return (iodesc);
+}
+
+/**
+ * qla2x00_free_iodesc() - Free an IO descriptor.
+ * @iodesc: io descriptor
+ *
+ * NOTE: The io descriptors timer *must* be stopped before it can be free'd.
+ */
+static inline void
+qla2x00_free_iodesc(struct io_descriptor *iodesc)
+{
+	iodesc->used = 0;
+	iodesc->signature = 0;
+}
+
+/**
+ * qla2x00_remove_iodesc_timer() - Remove an active timer from an IO descriptor.
+ * @iodesc: io descriptor
+ */
+static inline void
+qla2x00_remove_iodesc_timer(struct io_descriptor *iodesc)
+{
+	if (iodesc->timer.function != NULL) {
+		del_timer_sync(&iodesc->timer);
+		iodesc->timer.data = (unsigned long) NULL;
+		iodesc->timer.function = NULL;
+	}
+}
+
+/**
+ * qla2x00_init_io_descriptors() - Initialize the pool of IO descriptors.
+ * @ha: HA context
+ */
+static inline void
+qla2x00_init_io_descriptors(scsi_qla_host_t *ha)
+{
+	uint16_t iter;
+
+	for (iter = 0; iter < MAX_IO_DESCRIPTORS; iter++) {
+		if (!ha->io_descriptors[iter].used)
+			continue;
+
+		qla2x00_remove_iodesc_timer(&ha->io_descriptors[iter]);
+		qla2x00_free_iodesc(&ha->io_descriptors[iter]);
+	}
+}
+
+
+/** 
+ * IO descriptor timer routines.
+ **/
+
+/**
+ * qla2x00_iodesc_timeout() - Timeout IO descriptor handler.
+ * @data: io descriptor
+ */
+static void
+qla2x00_iodesc_timeout(unsigned long data)
+{
+	struct io_descriptor *iodesc;
+
+	iodesc = (struct io_descriptor *) data;
+
+	DEBUG14(printk("scsi(%ld): IO descriptor timeout, index=%x "
+	    "signature=%08x, scheduling ISP abort.\n", iodesc->ha->host_no,
+	    iodesc->idx, iodesc->signature));
+
+	qla2x00_free_iodesc(iodesc);
+
+	qla_printk(KERN_WARNING, iodesc->ha,
+	    "IO descriptor timeout. Scheduling ISP abort.\n");
+	set_bit(ISP_ABORT_NEEDED, &iodesc->ha->dpc_flags);
+}
+
+/**
+ * qla2x00_add_iodesc_timer() - Add and start a timer for an IO descriptor.
+ * @iodesc: io descriptor
+ *
+ * NOTE:
+ * The firmware shall timeout an outstanding mailbox IOCB in 2 * R_A_TOV (in
+ * tenths of a second) after it hits the wire.  But, if there are any request
+ * resource contraints (i.e. during heavy I/O), exchanges can be held off for
+ * at most R_A_TOV.  Therefore, the driver will wait 4 * R_A_TOV before
+ * scheduling a recovery (big hammer).
+ */
+static inline void
+qla2x00_add_iodesc_timer(struct io_descriptor *iodesc)
+{
+	unsigned long timeout;
+
+	timeout = (iodesc->ha->r_a_tov * 4) / 10;
+	init_timer(&iodesc->timer);
+	iodesc->timer.data = (unsigned long) iodesc;
+	iodesc->timer.expires = jiffies + (timeout * HZ);
+	iodesc->timer.function =
+	    (void (*) (unsigned long)) qla2x00_iodesc_timeout;
+	add_timer(&iodesc->timer);
+}
+
+/** 
+ * IO descriptor support routines.
+ **/
+
+/**
+ * qla2x00_update_login_fcport() - Update fcport data after login processing.
+ * @ha: HA context
+ * @mbxstat: Mailbox command status IOCB
+ * @fcport: port to update
+ */
+static inline void
+qla2x00_update_login_fcport(scsi_qla_host_t *ha, struct mbx_entry *mbxstat,
+    fc_port_t *fcport)
+{
+	if (le16_to_cpu(mbxstat->mb1) & BIT_0) {
+		fcport->port_type = FCT_INITIATOR;
+	} else {
+		fcport->port_type = FCT_TARGET;
+		if (le16_to_cpu(mbxstat->mb1) & BIT_1) {
+			fcport->flags |= FCF_TAPE_PRESENT;
+		}
+	}
+	fcport->login_retry = 0;
+	fcport->port_login_retry_count = ha->port_down_retry_count *
+	    PORT_RETRY_TIME;
+	atomic_set(&fcport->port_down_timer, ha->port_down_retry_count *
+	    PORT_RETRY_TIME);
+	fcport->flags |= FCF_FABRIC_DEVICE;
+	fcport->flags &= ~FCF_FAILOVER_NEEDED;
+	fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
+	atomic_set(&fcport->state, FCS_ONLINE);
+}
+
+
+/** 
+ * Mailbox IOCB commands.
+ **/
+
+/**
+ * qla2x00_get_mbx_iocb_entry() - Retrieve an IOCB from the request queue.
+ * @ha: HA context
+ * @handle: handle to io descriptor
+ *
+ * Returns a pointer to the reqest entry, or NULL, if none were available.
+ */
+static inline struct mbx_entry *
+qla2x00_get_mbx_iocb_entry(scsi_qla_host_t *ha, uint32_t handle)
+{
+	uint16_t cnt;
+	device_reg_t __iomem *reg = ha->iobase;
+	struct mbx_entry *mbxentry;
+
+	mbxentry = NULL;
+
+	if (ha->req_q_cnt < 3) {
+		cnt = qla2x00_debounce_register(ISP_REQ_Q_OUT(ha, reg));
+		if  (ha->req_ring_index < cnt)
+			ha->req_q_cnt = cnt - ha->req_ring_index;
+		else
+			ha->req_q_cnt = ha->request_q_length -
+			    (ha->req_ring_index - cnt);
+	}
+	if (ha->req_q_cnt >= 3) {
+		mbxentry = (struct mbx_entry *)ha->request_ring_ptr;
+
+		memset(mbxentry, 0, sizeof(struct mbx_entry));
+		mbxentry->entry_type = MBX_IOCB_TYPE;
+		mbxentry->entry_count = 1;
+		mbxentry->sys_define1 = SOURCE_ASYNC_IOCB;
+		mbxentry->handle = handle;
+	}
+	return (mbxentry);
+}
+
+/**
+ * qla2x00_send_abort_iocb() - Issue an abort IOCB to the firmware.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @handle_to_abort: firmware handle to abort
+ * @ha_locked: is function called with the hardware lock
+ *
+ * Returns QLA_SUCCESS if the IOCB was issued.
+ */
+static int
+qla2x00_send_abort_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc, 
+    uint32_t handle_to_abort, int ha_locked)
+{
+	unsigned long flags = 0;
+	struct mbx_entry *mbxentry;
+
+	/* Send marker if required. */
+	if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
+		return (QLA_FUNCTION_FAILED);
+
+	if (!ha_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Build abort mailbox IOCB. */
+	mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
+	if (mbxentry == NULL) {
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		return (QLA_FUNCTION_FAILED);
+	}
+	mbxentry->mb0 = __constant_cpu_to_le16(MBC_ABORT_COMMAND);
+	mbxentry->mb1 = mbxentry->loop_id.extended =
+	    cpu_to_le16(iodesc->remote_fcport->loop_id);
+	mbxentry->mb2 = LSW(handle_to_abort);
+	mbxentry->mb3 = MSW(handle_to_abort);
+	wmb();
+
+	qla2x00_add_iodesc_timer(iodesc);
+
+	/* Issue command to ISP. */
+	qla2x00_isp_cmd(ha);
+
+	if (!ha_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	DEBUG14(printk("scsi(%ld): Sending Abort IOCB (%08x) to [%x], aborting "
+	    "%08x.\n", ha->host_no, iodesc->signature,
+	    iodesc->remote_fcport->loop_id, handle_to_abort));
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_send_abort_iocb_cb() - Abort IOCB callback.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @mbxstat: mailbox status IOCB
+ *
+ * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
+ * will be used for a retry.
+ */
+static int
+qla2x00_send_abort_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    struct mbx_entry *mbxstat)
+{
+	DEBUG14(printk("scsi(%ld): Abort IOCB -- sent to [%x/%02x%02x%02x], "
+	    "status=%x mb0=%x.\n", ha->host_no, iodesc->remote_fcport->loop_id,
+	    iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa,
+	    le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
+
+	return (QLA_SUCCESS);
+}
+
+
+/**
+ * qla2x00_send_adisc_iocb() - Issue a Get Port Database IOCB to the firmware.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @ha_locked: is function called with the hardware lock
+ *
+ * Returns QLA_SUCCESS if the IOCB was issued.
+ */
+static int
+qla2x00_send_adisc_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    int ha_locked)
+{
+	unsigned long flags = 0;
+	struct mbx_entry *mbxentry;
+
+	/* Send marker if required. */
+	if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
+		return (QLA_FUNCTION_FAILED);
+
+	if (!ha_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Build Get Port Database IOCB. */
+	mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
+	if (mbxentry == NULL) {
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		return (QLA_FUNCTION_FAILED);
+	}
+	mbxentry->mb0 = __constant_cpu_to_le16(MBC_GET_PORT_DATABASE);
+	mbxentry->mb1 = mbxentry->loop_id.extended =
+	    cpu_to_le16(iodesc->remote_fcport->loop_id);
+	mbxentry->mb2 = cpu_to_le16(MSW(LSD(ha->iodesc_pd_dma)));
+	mbxentry->mb3 = cpu_to_le16(LSW(LSD(ha->iodesc_pd_dma)));
+	mbxentry->mb6 = cpu_to_le16(MSW(MSD(ha->iodesc_pd_dma)));
+	mbxentry->mb7 = cpu_to_le16(LSW(MSD(ha->iodesc_pd_dma)));
+	mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
+	wmb();
+
+	qla2x00_add_iodesc_timer(iodesc);
+
+	/* Issue command to ISP. */
+	qla2x00_isp_cmd(ha);
+
+	if (!ha_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	DEBUG14(printk("scsi(%ld): Sending Adisc IOCB (%08x) to [%x].\n",
+	    ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_send_adisc_iocb_cb() - Get Port Database IOCB callback.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @mbxstat: mailbox status IOCB
+ *
+ * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
+ * will be used for a retry.
+ */
+static int
+qla2x00_send_adisc_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    struct mbx_entry *mbxstat)
+{
+	fc_port_t *remote_fcport;
+
+	remote_fcport = iodesc->remote_fcport;
+
+	/* Ensure the port IDs are consistent. */
+	if (remote_fcport->d_id.b24 != iodesc->d_id.b24) {
+		DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, remote port "
+		    "id changed from [%02x%02x%02x] to [%02x%02x%02x].\n",
+		    ha->host_no, remote_fcport->d_id.b.domain,
+		    remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
+		    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+		    iodesc->d_id.b.al_pa));
+
+		return (QLA_SUCCESS);
+	}
+
+	/* Only process the last command. */
+	if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
+		DEBUG14(printk("scsi(%ld): Adisc IOCB -- ignoring, sent to "
+		    "[%02x%02x%02x], expected %x, received %x.\n", ha->host_no,
+		    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+		    iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
+		    iodesc->idx));
+
+		return (QLA_SUCCESS);
+	}
+
+	if (le16_to_cpu(mbxstat->status) == CS_COMPLETE) {
+		DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
+		    "[%x/%02x%02x%02x] online.\n", ha->host_no,
+		    remote_fcport->loop_id, remote_fcport->d_id.b.domain,
+		    remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
+
+		atomic_set(&remote_fcport->state, FCS_ONLINE);
+	} else {
+		DEBUG14(printk("scsi(%ld): Adisc IOCB -- marking "
+		    "[%x/%02x%02x%02x] lost, status=%x mb0=%x.\n", ha->host_no,
+		    remote_fcport->loop_id, remote_fcport->d_id.b.domain,
+		    remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa,
+		    le16_to_cpu(mbxstat->status), le16_to_cpu(mbxstat->mb0)));
+
+		if (atomic_read(&remote_fcport->state) != FCS_DEVICE_DEAD)
+			atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
+	}
+	remote_fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
+
+	return (QLA_SUCCESS);
+}
+
+
+/**
+ * qla2x00_send_logout_iocb() - Issue a fabric port logout IOCB to the firmware.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @ha_locked: is function called with the hardware lock
+ *
+ * Returns QLA_SUCCESS if the IOCB was issued.
+ */
+static int
+qla2x00_send_logout_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    int ha_locked)
+{
+	unsigned long flags = 0;
+	struct mbx_entry *mbxentry;
+
+	/* Send marker if required. */
+	if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
+		return (QLA_FUNCTION_FAILED);
+
+	if (!ha_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Build fabric port logout mailbox IOCB. */
+	mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
+	if (mbxentry == NULL) {
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		return (QLA_FUNCTION_FAILED);
+	}
+	mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGOUT_FABRIC_PORT);
+	mbxentry->mb1 = mbxentry->loop_id.extended =
+	    cpu_to_le16(iodesc->remote_fcport->loop_id);
+	wmb();
+
+	qla2x00_add_iodesc_timer(iodesc);
+
+	/* Issue command to ISP. */
+	qla2x00_isp_cmd(ha);
+
+	if (!ha_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	DEBUG14(printk("scsi(%ld): Sending Logout IOCB (%08x) to [%x].\n",
+	    ha->host_no, iodesc->signature, iodesc->remote_fcport->loop_id));
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_send_logout_iocb_cb() - Fabric port logout IOCB callback.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @mbxstat: mailbox status IOCB
+ *
+ * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
+ * will be used for a retry.
+ */
+static int
+qla2x00_send_logout_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    struct mbx_entry *mbxstat)
+{
+	DEBUG14(printk("scsi(%ld): Logout IOCB -- sent to [%x/%02x%02x%02x], "
+	    "status=%x mb0=%x mb1=%x.\n", ha->host_no,
+	    iodesc->remote_fcport->loop_id,
+	    iodesc->remote_fcport->d_id.b.domain,
+	    iodesc->remote_fcport->d_id.b.area,
+	    iodesc->remote_fcport->d_id.b.al_pa, le16_to_cpu(mbxstat->status),
+	    le16_to_cpu(mbxstat->mb0), le16_to_cpu(mbxstat->mb1)));
+
+	return (QLA_SUCCESS);
+}
+
+
+/**
+ * qla2x00_send_login_iocb() - Issue a fabric port login IOCB to the firmware.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @d_id: port id for device
+ * @ha_locked: is function called with the hardware lock
+ *
+ * Returns QLA_SUCCESS if the IOCB was issued.
+ */
+static int
+qla2x00_send_login_iocb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    port_id_t *d_id, int ha_locked)
+{
+	unsigned long flags = 0;
+	struct mbx_entry *mbxentry;
+
+	/* Send marker if required. */
+	if (qla2x00_issue_marker(ha, ha_locked) != QLA_SUCCESS)
+		return (QLA_FUNCTION_FAILED);
+
+	if (!ha_locked)
+		spin_lock_irqsave(&ha->hardware_lock, flags);
+
+	/* Build fabric port login mailbox IOCB. */
+	mbxentry = qla2x00_get_mbx_iocb_entry(ha, iodesc->signature);
+	if (mbxentry == NULL) {
+		if (!ha_locked)
+			spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+		return (QLA_FUNCTION_FAILED);
+	}
+	mbxentry->mb0 = __constant_cpu_to_le16(MBC_LOGIN_FABRIC_PORT);
+	mbxentry->mb1 = mbxentry->loop_id.extended =
+	    cpu_to_le16(iodesc->remote_fcport->loop_id);
+	mbxentry->mb2 = cpu_to_le16(d_id->b.domain);
+	mbxentry->mb3 = cpu_to_le16(d_id->b.area << 8 | d_id->b.al_pa);
+	mbxentry->mb10 = __constant_cpu_to_le16(BIT_0);
+	wmb();
+
+	qla2x00_add_iodesc_timer(iodesc);
+
+	/* Issue command to ISP. */
+	qla2x00_isp_cmd(ha);
+
+	if (!ha_locked)
+		spin_unlock_irqrestore(&ha->hardware_lock, flags);
+
+	DEBUG14(printk("scsi(%ld): Sending Login IOCB (%08x) to "
+	    "[%x/%02x%02x%02x].\n", ha->host_no, iodesc->signature,
+	    iodesc->remote_fcport->loop_id, d_id->b.domain, d_id->b.area,
+	    d_id->b.al_pa));
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_send_login_iocb_cb() - Fabric port logout IOCB callback.
+ * @ha: HA context
+ * @iodesc: io descriptor
+ * @mbxstat: mailbox status IOCB
+ *
+ * Returns QLA_SUCCESS if @iodesc can be freed by the caller, else, @iodesc
+ * will be used for a retry.
+ */
+static int
+qla2x00_send_login_iocb_cb(scsi_qla_host_t *ha, struct io_descriptor *iodesc,
+    struct mbx_entry *mbxstat)
+{
+	int rval;
+	fc_port_t *fcport, *remote_fcport, *exist_fcport;
+	struct io_descriptor *abort_iodesc, *login_iodesc;
+	uint16_t status, mb[8];
+	uint16_t reuse;
+	uint16_t remote_loopid;
+	port_id_t remote_did, inuse_did;
+
+	remote_fcport = iodesc->remote_fcport;
+
+	/* Only process the last command. */
+	if (remote_fcport->iodesc_idx_sent != iodesc->idx) {
+		DEBUG14(printk("scsi(%ld): Login IOCB -- ignoring, sent to "
+		    "[%02x%02x%02x], expected %x, received %x.\n", 
+		    ha->host_no, iodesc->d_id.b.domain, iodesc->d_id.b.area,
+		    iodesc->d_id.b.al_pa, remote_fcport->iodesc_idx_sent,
+		    iodesc->idx));
+
+		/* Free RSCN fcport resources. */
+		if (remote_fcport->port_type == FCT_RSCN) {
+			DEBUG14(printk("scsi(%ld): Login IOCB -- Freeing RSCN "
+			    "fcport %p [%x/%02x%02x%02x] given ignored Login "
+			    "IOCB.\n", ha->host_no, remote_fcport,
+			    remote_fcport->loop_id,
+			    remote_fcport->d_id.b.domain,
+			    remote_fcport->d_id.b.area,
+			    remote_fcport->d_id.b.al_pa));
+
+			list_del(&remote_fcport->list);
+			kfree(remote_fcport);
+		}
+		return (QLA_SUCCESS);
+	}
+
+	status = le16_to_cpu(mbxstat->status);
+	mb[0] = le16_to_cpu(mbxstat->mb0);
+	mb[1] = le16_to_cpu(mbxstat->mb1);
+	mb[2] = le16_to_cpu(mbxstat->mb2);
+	mb[6] = le16_to_cpu(mbxstat->mb6);
+	mb[7] = le16_to_cpu(mbxstat->mb7);
+
+	/* Good status? */
+	if ((status == CS_COMPLETE || status == CS_COMPLETE_CHKCOND) &&
+	    mb[0] == MBS_COMMAND_COMPLETE) {
+
+		DEBUG14(printk("scsi(%ld): Login IOCB -- status=%x mb1=%x pn="
+		    "%02x%02x%02x%02x%02x%02x%02x%02x.\n", ha->host_no, status,
+		    mb[1], mbxstat->port_name[0], mbxstat->port_name[1], 
+		    mbxstat->port_name[2], mbxstat->port_name[3], 
+		    mbxstat->port_name[4], mbxstat->port_name[5], 
+		    mbxstat->port_name[6], mbxstat->port_name[7]));
+
+		memcpy(remote_fcport->node_name, mbxstat->node_name, WWN_SIZE);
+		memcpy(remote_fcport->port_name, mbxstat->port_name, WWN_SIZE);
+
+		/* Is the device already in our fcports list? */
+		if (remote_fcport->port_type != FCT_RSCN) {
+			DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
+			    "[%x/%02x%02x%02x] online.\n", ha->host_no,
+			    remote_fcport->loop_id,
+			    remote_fcport->d_id.b.domain,
+			    remote_fcport->d_id.b.area,
+			    remote_fcport->d_id.b.al_pa));
+
+			qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
+
+			return (QLA_SUCCESS);
+		}
+
+		/* Does the RSCN portname already exist in our fcports list? */
+		exist_fcport = NULL;
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (memcmp(remote_fcport->port_name, fcport->port_name,
+			    WWN_SIZE) == 0) {
+				exist_fcport = fcport;
+				break;
+			}
+		}
+		if (exist_fcport != NULL) {
+			DEBUG14(printk("scsi(%ld): Login IOCB -- found RSCN "
+			    "fcport in fcports list [%p].\n", ha->host_no,
+			    exist_fcport));
+
+			/* Abort any ADISC that could have been sent. */
+			if (exist_fcport->iodesc_idx_sent != iodesc->idx &&
+			    exist_fcport->iodesc_idx_sent <
+			    MAX_IO_DESCRIPTORS &&
+			    ha->io_descriptors[exist_fcport->iodesc_idx_sent].
+			    cb_idx == ADISC_PORT_IOCB_CB) {
+
+				abort_iodesc = qla2x00_alloc_iodesc(ha);
+				if (abort_iodesc) {
+					DEBUG14(printk("scsi(%ld): Login IOCB "
+					    "-- issuing abort to outstanding "
+					    "Adisc [%x/%02x%02x%02x].\n",
+					    ha->host_no, remote_fcport->loop_id,
+					    exist_fcport->d_id.b.domain,
+					    exist_fcport->d_id.b.area,
+					    exist_fcport->d_id.b.al_pa));
+
+					abort_iodesc->cb_idx = ABORT_IOCB_CB;
+					abort_iodesc->d_id.b24 =
+					    exist_fcport->d_id.b24;
+					abort_iodesc->remote_fcport =
+					    exist_fcport;
+					exist_fcport->iodesc_idx_sent =
+					    abort_iodesc->idx;
+					qla2x00_send_abort_iocb(ha,
+					    abort_iodesc, ha->io_descriptors[
+					     exist_fcport->iodesc_idx_sent].
+					      signature, 1);
+				} else {
+					DEBUG14(printk("scsi(%ld): Login IOCB "
+					    "-- unable to abort outstanding "
+					    "Adisc [%x/%02x%02x%02x].\n",
+					    ha->host_no, remote_fcport->loop_id,
+					    exist_fcport->d_id.b.domain,
+					    exist_fcport->d_id.b.area,
+					    exist_fcport->d_id.b.al_pa));
+				}
+			}
+
+			/*
+			 * If the existing fcport is waiting to send an ADISC
+			 * or LOGIN, then reuse remote fcport (RSCN) to
+			 * continue waiting.
+			 */
+			reuse = 0;
+			remote_loopid = remote_fcport->loop_id;
+			remote_did.b24 = remote_fcport->d_id.b24;
+			if (exist_fcport->iodesc_idx_sent ==
+			    IODESC_ADISC_NEEDED ||
+			    exist_fcport->iodesc_idx_sent ==
+			    IODESC_LOGIN_NEEDED) {
+				DEBUG14(printk("scsi(%ld): Login IOCB -- "
+				    "existing fcport [%x/%02x%02x%02x] "
+				    "waiting for IO descriptor, reuse RSCN "
+				    "fcport.\n", ha->host_no,
+				    exist_fcport->loop_id,
+				    exist_fcport->d_id.b.domain,
+				    exist_fcport->d_id.b.area,
+				    exist_fcport->d_id.b.al_pa));
+
+				reuse++;
+				remote_fcport->iodesc_idx_sent =
+				    exist_fcport->iodesc_idx_sent;
+				exist_fcport->iodesc_idx_sent =
+				    IODESC_INVALID_INDEX;
+				remote_fcport->loop_id = exist_fcport->loop_id;
+				remote_fcport->d_id.b24 =
+				    exist_fcport->d_id.b24;
+			}
+
+			/* Logout the old loopid. */
+			if (!reuse &&
+			    exist_fcport->loop_id != remote_fcport->loop_id &&
+			    exist_fcport->loop_id != FC_NO_LOOP_ID) {
+				login_iodesc = qla2x00_alloc_iodesc(ha);
+				if (login_iodesc) {
+					DEBUG14(printk("scsi(%ld): Login IOCB "
+					    "-- issuing logout to free old "
+					    "loop id [%x/%02x%02x%02x].\n",
+					    ha->host_no, exist_fcport->loop_id,
+					    exist_fcport->d_id.b.domain,
+					    exist_fcport->d_id.b.area,
+					    exist_fcport->d_id.b.al_pa));
+
+					login_iodesc->cb_idx =
+					    LOGOUT_PORT_IOCB_CB;
+					login_iodesc->d_id.b24 =
+					    exist_fcport->d_id.b24;
+					login_iodesc->remote_fcport =
+					    exist_fcport;
+					exist_fcport->iodesc_idx_sent =
+					    login_iodesc->idx;
+					qla2x00_send_logout_iocb(ha,
+					    login_iodesc, 1);
+				} else {
+					/* Ran out of IO descriptiors. */
+					DEBUG14(printk("scsi(%ld): Login IOCB "
+					    "-- unable to logout to free old "
+					    "loop id [%x/%02x%02x%02x].\n",
+					    ha->host_no, exist_fcport->loop_id,
+					    exist_fcport->d_id.b.domain,
+					    exist_fcport->d_id.b.area,
+					    exist_fcport->d_id.b.al_pa));
+
+					exist_fcport->iodesc_idx_sent =
+					    IODESC_INVALID_INDEX;
+				}
+
+			}
+
+			/* Update existing fcport with remote fcport info. */
+			DEBUG14(printk("scsi(%ld): Login IOCB -- marking "
+			    "existing fcport [%x/%02x%02x%02x] online.\n",
+			    ha->host_no, remote_loopid, remote_did.b.domain,
+			    remote_did.b.area, remote_did.b.al_pa));
+
+			memcpy(exist_fcport->node_name,
+			    remote_fcport->node_name, WWN_SIZE);
+			exist_fcport->loop_id = remote_loopid;
+			exist_fcport->d_id.b24 = remote_did.b24;
+			qla2x00_update_login_fcport(ha, mbxstat, exist_fcport);
+
+			/* Finally, free the remote (RSCN) fcport. */
+			if (!reuse) {
+				DEBUG14(printk("scsi(%ld): Login IOCB -- "
+				    "Freeing RSCN fcport %p "
+				    "[%x/%02x%02x%02x].\n", ha->host_no,
+				    remote_fcport, remote_fcport->loop_id,
+				    remote_fcport->d_id.b.domain,
+				    remote_fcport->d_id.b.area,
+				    remote_fcport->d_id.b.al_pa));
+
+				list_del(&remote_fcport->list);
+				kfree(remote_fcport);
+			}
+
+			return (QLA_SUCCESS);
+		}
+
+		/*
+		 * A new device has been added, move the RSCN fcport to our
+		 * fcports list.
+		 */
+		DEBUG14(printk("scsi(%ld): Login IOCB -- adding RSCN fcport "
+		    "[%x/%02x%02x%02x] to fcports list.\n", ha->host_no,
+		    remote_fcport->loop_id, remote_fcport->d_id.b.domain,
+		    remote_fcport->d_id.b.area, remote_fcport->d_id.b.al_pa));
+
+		list_del(&remote_fcport->list);
+		remote_fcport->flags = (FCF_RLC_SUPPORT | FCF_RESCAN_NEEDED);
+		qla2x00_update_login_fcport(ha, mbxstat, remote_fcport);
+		list_add_tail(&remote_fcport->list, &ha->fcports);
+		set_bit(FCPORT_RESCAN_NEEDED, &ha->dpc_flags);
+	} else {
+		/* Handle login failure. */
+		if (remote_fcport->login_retry != 0) {
+			if (mb[0] == MBS_LOOP_ID_USED) {
+				inuse_did.b.domain = LSB(mb[1]);
+				inuse_did.b.area = MSB(mb[2]);
+				inuse_did.b.al_pa = LSB(mb[2]);
+
+				DEBUG14(printk("scsi(%ld): Login IOCB -- loop "
+				    "id [%x] used by port id [%02x%02x%02x].\n",
+				    ha->host_no, remote_fcport->loop_id,
+				    inuse_did.b.domain, inuse_did.b.area,
+				    inuse_did.b.al_pa));
+
+				if (remote_fcport->d_id.b24 ==
+				    INVALID_PORT_ID) {
+					/*
+					 * Invalid port id means we are trying
+					 * to login to a remote port with just
+					 * a loop id without knowing about the
+					 * port id.  Copy the port id and try
+					 * again.
+					 */
+					remote_fcport->d_id.b24 = inuse_did.b24;
+					iodesc->d_id.b24 = inuse_did.b24;
+				} else {
+					remote_fcport->loop_id++;
+					rval = qla2x00_find_new_loop_id(ha,
+					    remote_fcport);
+					if (rval == QLA_FUNCTION_FAILED) {
+						/* No more loop ids. */
+						return (QLA_SUCCESS);
+					}
+				}
+			} else if (mb[0] == MBS_PORT_ID_USED) {
+				/*
+				 * Device has another loop ID.  The firmware
+				 * group recommends the driver perform an
+				 * implicit login with the specified ID.
+				 */
+				DEBUG14(printk("scsi(%ld): Login IOCB -- port "
+				    "id [%02x%02x%02x] already assigned to "
+				    "loop id [%x].\n", ha->host_no,
+				    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+				    iodesc->d_id.b.al_pa, mb[1]));
+
+				remote_fcport->loop_id = mb[1];
+
+			} else {
+				/* Unable to perform login, try again. */
+				DEBUG14(printk("scsi(%ld): Login IOCB -- "
+				    "failed login [%x/%02x%02x%02x], status=%x "
+				    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
+				    ha->host_no, remote_fcport->loop_id,
+				    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+				    iodesc->d_id.b.al_pa, status, mb[0], mb[1],
+				    mb[2], mb[6], mb[7]));
+			}
+
+			/* Reissue Login with the same IO descriptor. */
+			iodesc->signature =
+			    qla2x00_iodesc_to_handle(iodesc);
+			iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
+			iodesc->d_id.b24 = remote_fcport->d_id.b24;
+			remote_fcport->iodesc_idx_sent = iodesc->idx;
+			remote_fcport->login_retry--;
+
+			DEBUG14(printk("scsi(%ld): Login IOCB -- retrying "
+			    "login to [%x/%02x%02x%02x] (%d).\n", ha->host_no,
+			    remote_fcport->loop_id,
+			    remote_fcport->d_id.b.domain,
+			    remote_fcport->d_id.b.area,
+			    remote_fcport->d_id.b.al_pa,
+			    remote_fcport->login_retry));
+
+			qla2x00_send_login_iocb(ha, iodesc,
+			    &remote_fcport->d_id, 1);
+
+			return (QLA_FUNCTION_FAILED);
+		} else {
+			/* No more logins, mark device dead. */
+			DEBUG14(printk("scsi(%ld): Login IOCB -- failed "
+			    "login [%x/%02x%02x%02x] after retries, status=%x "
+			    "mb0=%x mb1=%x mb2=%x mb6=%x mb7=%x.\n",
+			    ha->host_no, remote_fcport->loop_id,
+			    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+			    iodesc->d_id.b.al_pa, status, mb[0], mb[1],
+			    mb[2], mb[6], mb[7]));
+
+			atomic_set(&remote_fcport->state, FCS_DEVICE_DEAD);
+			if (remote_fcport->port_type == FCT_RSCN) {
+				DEBUG14(printk("scsi(%ld): Login IOCB -- "
+				    "Freeing dead RSCN fcport %p "
+				    "[%x/%02x%02x%02x].\n", ha->host_no,
+				    remote_fcport, remote_fcport->loop_id,
+				    remote_fcport->d_id.b.domain,
+				    remote_fcport->d_id.b.area,
+				    remote_fcport->d_id.b.al_pa));
+
+				list_del(&remote_fcport->list);
+				kfree(remote_fcport);
+			}
+		}
+	}
+
+	return (QLA_SUCCESS);
+}
+
+
+/** 
+ * IO descriptor processing routines.
+ **/
+
+/**
+ * qla2x00_alloc_rscn_fcport() - Allocate an RSCN type fcport.
+ * @ha: HA context
+ * @flags: allocation flags
+ *
+ * Returns a pointer to the allocated RSCN fcport, or NULL, if none available.
+ */
+fc_port_t *
+qla2x00_alloc_rscn_fcport(scsi_qla_host_t *ha, int flags)
+{
+	fc_port_t *fcport;
+
+	fcport = qla2x00_alloc_fcport(ha, flags);
+	if (fcport == NULL)
+		return (fcport);
+
+	/* Setup RSCN fcport structure. */
+	fcport->port_type = FCT_RSCN;
+
+	return (fcport);
+}
+
+/**
+ * qla2x00_handle_port_rscn() - Handle port RSCN.
+ * @ha: HA context
+ * @rscn_entry: RSCN entry
+ * @fcport: fcport entry to updated
+ *
+ * Returns QLA_SUCCESS if the port RSCN was handled.
+ */
+int
+qla2x00_handle_port_rscn(scsi_qla_host_t *ha, uint32_t rscn_entry,
+    fc_port_t *known_fcport, int ha_locked)
+{
+	int	rval;
+	port_id_t rscn_pid;
+	fc_port_t *fcport, *remote_fcport, *rscn_fcport;
+	struct io_descriptor *iodesc;
+
+	remote_fcport = NULL;
+	rscn_fcport = NULL;
+
+	/* Prepare port id based on incoming entries. */
+	if (known_fcport) {
+		rscn_pid.b24 = known_fcport->d_id.b24;
+		remote_fcport = known_fcport;
+
+		DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
+		    "fcport [%02x%02x%02x].\n", ha->host_no,
+		    remote_fcport->d_id.b.domain, remote_fcport->d_id.b.area,
+		    remote_fcport->d_id.b.al_pa));
+	} else {
+		rscn_pid.b.domain = LSB(MSW(rscn_entry));
+		rscn_pid.b.area = MSB(LSW(rscn_entry));
+		rscn_pid.b.al_pa = LSB(LSW(rscn_entry));
+
+		DEBUG14(printk("scsi(%ld): Handle RSCN -- process RSCN for "
+		    "port id [%02x%02x%02x].\n", ha->host_no,
+		    rscn_pid.b.domain, rscn_pid.b.area, rscn_pid.b.al_pa));
+
+		/*
+		 * Search fcport lists for a known entry at the specified port
+		 * ID.
+		 */
+		list_for_each_entry(fcport, &ha->fcports, list) {
+		    if (rscn_pid.b24 == fcport->d_id.b24) {
+			    remote_fcport = fcport;
+			    break;
+		    }
+		}
+		list_for_each_entry(fcport, &ha->rscn_fcports, list) {
+		    if (rscn_pid.b24 == fcport->d_id.b24) {
+			    rscn_fcport = fcport;
+			    break;
+		    }
+		}
+		if (remote_fcport == NULL)
+		    remote_fcport = rscn_fcport;
+	}
+
+	/* 
+	 * If the port is already in our fcport list and online, send an ADISC
+	 * to see if it's still alive.  Issue login if a new fcport or the known
+	 * fcport is currently offline.
+	 */
+	if (remote_fcport) {
+		/*
+		 * No need to send request if the remote fcport is currently
+		 * waiting for an available io descriptor.
+		 */
+		if (known_fcport == NULL &&
+		    (remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
+		    remote_fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED)) {
+			/*
+			 * If previous waiting io descriptor is an ADISC, then
+			 * the new RSCN may come from a new remote fcport being
+			 * plugged into the same location.
+			 */
+			if (remote_fcport->port_type == FCT_RSCN) {
+			    remote_fcport->iodesc_idx_sent =
+				IODESC_LOGIN_NEEDED;
+			} else if (remote_fcport->iodesc_idx_sent ==
+			    IODESC_ADISC_NEEDED) {
+				fc_port_t *new_fcport;
+
+				remote_fcport->iodesc_idx_sent =
+				    IODESC_INVALID_INDEX;
+
+				/* Create new fcport for later login. */
+				new_fcport = qla2x00_alloc_rscn_fcport(ha,
+				    ha_locked ? GFP_ATOMIC: GFP_KERNEL);
+				if (new_fcport) {
+					DEBUG14(printk("scsi(%ld): Handle RSCN "
+					    "-- creating RSCN fcport %p for "
+					    "future login.\n", ha->host_no,
+					    new_fcport));
+
+					new_fcport->d_id.b24 =
+					    remote_fcport->d_id.b24;
+					new_fcport->iodesc_idx_sent =
+					    IODESC_LOGIN_NEEDED;
+
+					list_add_tail(&new_fcport->list,
+					    &ha->rscn_fcports);
+					set_bit(IODESC_PROCESS_NEEDED,
+					    &ha->dpc_flags);
+				} else {
+					DEBUG14(printk("scsi(%ld): Handle RSCN "
+					    "-- unable to allocate RSCN fcport "
+					    "for future login.\n",
+					    ha->host_no));
+				}
+			}
+			return (QLA_SUCCESS);
+		}
+		
+		/* Send ADISC if the fcport is online */
+		if (atomic_read(&remote_fcport->state) == FCS_ONLINE ||
+		    remote_fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED) {
+
+			atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
+
+			iodesc = qla2x00_alloc_iodesc(ha);
+			if (iodesc == NULL) {
+				/* Mark fcport for later adisc processing */
+				DEBUG14(printk("scsi(%ld): Handle RSCN -- not "
+				    "enough IO descriptors for Adisc, flag "
+				    "for later processing.\n", ha->host_no));
+
+				remote_fcport->iodesc_idx_sent =
+				    IODESC_ADISC_NEEDED;
+				set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
+
+				return (QLA_SUCCESS);
+			}
+
+			iodesc->cb_idx = ADISC_PORT_IOCB_CB;
+			iodesc->d_id.b24 = rscn_pid.b24;
+			iodesc->remote_fcport = remote_fcport;
+			remote_fcport->iodesc_idx_sent = iodesc->idx;
+			qla2x00_send_adisc_iocb(ha, iodesc, ha_locked);
+
+			return (QLA_SUCCESS);
+		} else if (remote_fcport->iodesc_idx_sent <
+		    MAX_IO_DESCRIPTORS &&
+		    ha->io_descriptors[remote_fcport->iodesc_idx_sent].cb_idx ==
+		    ADISC_PORT_IOCB_CB) {
+			/*
+			 * Receiving another RSCN while an ADISC is pending,
+			 * abort the IOCB.  Use the same descriptor for the
+			 * abort.
+			 */
+			uint32_t handle_to_abort;
+			
+			iodesc = &ha->io_descriptors[
+				remote_fcport->iodesc_idx_sent];
+			qla2x00_remove_iodesc_timer(iodesc);
+			handle_to_abort = iodesc->signature;
+			iodesc->signature = qla2x00_iodesc_to_handle(iodesc);
+			iodesc->cb_idx = ABORT_IOCB_CB;
+			iodesc->d_id.b24 = remote_fcport->d_id.b24;
+			iodesc->remote_fcport = remote_fcport;
+			remote_fcport->iodesc_idx_sent = iodesc->idx;
+
+			DEBUG14(printk("scsi(%ld): Handle RSCN -- issuing "
+			    "abort to outstanding Adisc [%x/%02x%02x%02x].\n",
+			    ha->host_no, remote_fcport->loop_id,
+			    iodesc->d_id.b.domain, iodesc->d_id.b.area,
+			    iodesc->d_id.b.al_pa));
+
+			qla2x00_send_abort_iocb(ha, iodesc, handle_to_abort,
+			    ha_locked);
+		}
+	}
+
+	/* We need to login to the remote port, find it. */
+	if (known_fcport) {
+		remote_fcport = known_fcport;
+	} else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
+	    rscn_fcport->iodesc_idx_sent < MAX_IO_DESCRIPTORS &&
+	    ha->io_descriptors[rscn_fcport->iodesc_idx_sent].cb_idx ==
+	    LOGIN_PORT_IOCB_CB) {
+		/*
+		 * Ignore duplicate RSCN on fcport which has already
+		 * initiated a login IOCB.
+		 */
+		DEBUG14(printk("scsi(%ld): Handle RSCN -- ignoring, login "
+		    "already sent to [%02x%02x%02x].\n", ha->host_no,
+		    rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
+		    rscn_fcport->d_id.b.al_pa));
+
+		return (QLA_SUCCESS);
+	} else if (rscn_fcport && rscn_fcport->d_id.b24 != INVALID_PORT_ID &&
+	    rscn_fcport != remote_fcport) {
+		/* Reuse same rscn fcport. */
+		DEBUG14(printk("scsi(%ld): Handle RSCN -- reusing RSCN fcport "
+		    "[%02x%02x%02x].\n", ha->host_no,
+		    rscn_fcport->d_id.b.domain, rscn_fcport->d_id.b.area,
+		    rscn_fcport->d_id.b.al_pa));
+
+		remote_fcport = rscn_fcport;
+	} else {
+		/* Create new fcport for later login. */
+		remote_fcport = qla2x00_alloc_rscn_fcport(ha,
+		    ha_locked ? GFP_ATOMIC: GFP_KERNEL);
+		list_add_tail(&remote_fcport->list, &ha->rscn_fcports);
+	}
+	if (remote_fcport == NULL)
+		return (QLA_SUCCESS);
+
+	/* Prepare fcport for login. */
+	atomic_set(&remote_fcport->state, FCS_DEVICE_LOST);
+	remote_fcport->login_retry = 3; /* ha->login_retry_count; */
+	remote_fcport->d_id.b24 = rscn_pid.b24;
+
+	iodesc = qla2x00_alloc_iodesc(ha);
+	if (iodesc == NULL) {
+		/* Mark fcport for later adisc processing. */
+		DEBUG14(printk("scsi(%ld): Handle RSCN -- not enough IO "
+		    "descriptors for Login, flag for later processing.\n",
+		    ha->host_no));
+
+		remote_fcport->iodesc_idx_sent = IODESC_LOGIN_NEEDED;
+		set_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
+
+		return (QLA_SUCCESS);
+	}
+
+	if (known_fcport == NULL || rscn_pid.b24 != INVALID_PORT_ID) {
+		remote_fcport->loop_id = ha->min_external_loopid;
+
+		rval = qla2x00_find_new_loop_id(ha, remote_fcport);
+		if (rval == QLA_FUNCTION_FAILED) {
+			/* No more loop ids, failed. */
+			DEBUG14(printk("scsi(%ld): Handle RSCN -- no available "
+			    "loop id to perform Login, failed.\n",
+			    ha->host_no));
+
+			return (rval);
+		}
+	}
+
+	iodesc->cb_idx = LOGIN_PORT_IOCB_CB;
+	iodesc->d_id.b24 = rscn_pid.b24;
+	iodesc->remote_fcport = remote_fcport;
+	remote_fcport->iodesc_idx_sent = iodesc->idx;
+
+	DEBUG14(printk("scsi(%ld): Handle RSCN -- attempting login to "
+	    "[%x/%02x%02x%02x].\n", ha->host_no, remote_fcport->loop_id,
+	    iodesc->d_id.b.domain, iodesc->d_id.b.area, iodesc->d_id.b.al_pa));
+
+	qla2x00_send_login_iocb(ha, iodesc, &rscn_pid, ha_locked);
+
+	return (QLA_SUCCESS);
+}
+
+/**
+ * qla2x00_process_iodesc() - Complete IO descriptor processing.
+ * @ha: HA context
+ * @mbxstat: Mailbox IOCB status
+ */
+void
+qla2x00_process_iodesc(scsi_qla_host_t *ha, struct mbx_entry *mbxstat)
+{
+	int rval;
+	uint32_t signature;
+	fc_port_t *fcport;
+	struct io_descriptor *iodesc;
+
+	signature = mbxstat->handle;
+
+	DEBUG14(printk("scsi(%ld): Process IODesc -- processing %08x.\n",
+	    ha->host_no, signature));
+
+	/* Retrieve proper IO descriptor. */
+	iodesc = qla2x00_handle_to_iodesc(ha, signature);
+	if (iodesc == NULL) {
+		DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
+		    "incorrect signature %08x.\n", ha->host_no, signature));
+
+		return;
+	}
+
+	/* Stop IO descriptor timer. */
+	qla2x00_remove_iodesc_timer(iodesc);
+
+	/* Verify signature match. */
+	if (iodesc->signature != signature) {
+		DEBUG14(printk("scsi(%ld): Process IODesc -- ignoring, "
+		    "signature mismatch, sent %08x, received %08x.\n",
+		    ha->host_no, iodesc->signature, signature));
+
+		return;
+	}
+
+	/* Go with IOCB callback. */
+	rval = iocb_function_cb_list[iodesc->cb_idx](ha, iodesc, mbxstat);
+	if (rval != QLA_SUCCESS) {
+		/* IO descriptor reused by callback. */
+		return;
+	}
+
+	qla2x00_free_iodesc(iodesc);
+
+	if (test_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags)) {
+		/* Scan our fcports list for any RSCN requests. */
+		list_for_each_entry(fcport, &ha->fcports, list) {
+			if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
+			    fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
+				qla2x00_handle_port_rscn(ha, 0, fcport, 1);
+				return;
+			}
+		}
+
+		/* Scan our RSCN fcports list for any RSCN requests. */
+		list_for_each_entry(fcport, &ha->rscn_fcports, list) {
+			if (fcport->iodesc_idx_sent == IODESC_ADISC_NEEDED ||
+			    fcport->iodesc_idx_sent == IODESC_LOGIN_NEEDED) {
+				qla2x00_handle_port_rscn(ha, 0, fcport, 1);
+				return;
+			}
+		}
+	}
+	clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
+}
+
+/**
+ * qla2x00_cancel_io_descriptors() - Cancel all outstanding io descriptors.
+ * @ha: HA context
+ *
+ * This routine will also delete any RSCN entries related to the outstanding
+ * IO descriptors.
+ */
+void
+qla2x00_cancel_io_descriptors(scsi_qla_host_t *ha)
+{
+	fc_port_t *fcport, *fcptemp;
+
+	clear_bit(IODESC_PROCESS_NEEDED, &ha->dpc_flags);
+
+	/* Abort all IO descriptors. */
+	qla2x00_init_io_descriptors(ha);
+
+	/* Reset all pending IO descriptors in fcports list. */
+	list_for_each_entry(fcport, &ha->fcports, list) {
+		fcport->iodesc_idx_sent = IODESC_INVALID_INDEX;
+	}
+
+	/* Reset all pending IO descriptors in rscn fcports list. */
+	list_for_each_entry_safe(fcport, fcptemp, &ha->rscn_fcports, list) {
+		DEBUG14(printk("scsi(%ld): Cancel IOs -- Freeing RSCN fcport "
+		    "%p [%x/%02x%02x%02x].\n", ha->host_no, fcport,
+		    fcport->loop_id, fcport->d_id.b.domain, fcport->d_id.b.area,
+		    fcport->d_id.b.al_pa));
+
+		list_del(&fcport->list);
+		kfree(fcport);
+	}
+}
diff --git a/drivers/scsi/qla2xxx/qla_settings.h b/drivers/scsi/qla2xxx/qla_settings.h
new file mode 100644
index 0000000..c58f5fa
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_settings.h
@@ -0,0 +1,64 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+/*
+ * Compile time Options:
+ *     0 - Disable and 1 - Enable
+ */
+#define DEBUG_QLA2100		0	/* For Debug of qla2x00 */
+
+#define STOP_ON_RESET		0
+#define USE_ABORT_TGT		1	/* Use Abort Target mbx cmd */
+
+#define VSA			0	/* Volume Set Addressing */
+
+/* Failover options */
+#define MAX_RECOVERYTIME	10	/*
+					 * Max suspend time for a lun recovery
+					 * time
+					 */
+#define MAX_FAILBACKTIME	5	/* Max suspend time before fail back */
+
+#define QLA_CMD_TIMER_DELTA	3
+
+/* 
+ * When a lun is suspended for the "Not Ready" condition then it will suspend
+ * the lun for increments of 6 sec delays.  SUSPEND_COUNT is that count.
+ */
+#define SUSPEND_COUNT		10	/* 6 secs * 10 retries = 60 secs */
+
+/*
+ * Defines the time in seconds that the driver extends the command timeout to
+ * get around the problem where the mid-layer only allows 5 retries for
+ * commands that return BUS_BUSY
+ */
+#define EXTEND_CMD_TIMEOUT	60
+
+#define MAX_RETRIES_OF_ISP_ABORT	5
+
+/* Max time to wait for the loop to be in LOOP_READY state */
+#define MAX_LOOP_TIMEOUT	(60 * 5)
+#define EH_ACTIVE		1	/* Error handler active */
+
+/*
+ * Some vendor subsystems do not recover properly after a device reset.  Define
+ * the following to force a logout after a successful device reset.
+ */
+#undef LOGOUT_AFTER_DEVICE_RESET
+
+#include "qla_version.h"
diff --git a/drivers/scsi/qla2xxx/qla_sup.c b/drivers/scsi/qla2xxx/qla_sup.c
new file mode 100644
index 0000000..0e75fbb
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_sup.c
@@ -0,0 +1,296 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+
+#include "qla_def.h"
+
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+static uint16_t qla2x00_nvram_request(scsi_qla_host_t *, uint32_t);
+static void qla2x00_nv_deselect(scsi_qla_host_t *);
+static void qla2x00_nv_write(scsi_qla_host_t *, uint16_t);
+
+/*
+ * NVRAM support routines
+ */
+
+/**
+ * qla2x00_lock_nvram_access() - 
+ * @ha: HA context
+ */
+void
+qla2x00_lock_nvram_access(scsi_qla_host_t *ha)
+{
+	uint16_t data;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
+		data = RD_REG_WORD(&reg->nvram);
+		while (data & NVR_BUSY) {
+			udelay(100);
+			data = RD_REG_WORD(&reg->nvram);
+		}
+
+		/* Lock resource */
+		WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0x1);
+		RD_REG_WORD(&reg->u.isp2300.host_semaphore);
+		udelay(5);
+		data = RD_REG_WORD(&reg->u.isp2300.host_semaphore);
+		while ((data & BIT_0) == 0) {
+			/* Lock failed */
+			udelay(100);
+			WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0x1);
+			RD_REG_WORD(&reg->u.isp2300.host_semaphore);
+			udelay(5);
+			data = RD_REG_WORD(&reg->u.isp2300.host_semaphore);
+		}
+	}
+}
+
+/**
+ * qla2x00_unlock_nvram_access() - 
+ * @ha: HA context
+ */
+void
+qla2x00_unlock_nvram_access(scsi_qla_host_t *ha)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+
+	if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
+		WRT_REG_WORD(&reg->u.isp2300.host_semaphore, 0);
+		RD_REG_WORD(&reg->u.isp2300.host_semaphore);
+	}
+}
+
+/**
+ * qla2x00_release_nvram_protection() - 
+ * @ha: HA context
+ */
+void
+qla2x00_release_nvram_protection(scsi_qla_host_t *ha)
+{
+	device_reg_t *reg;
+	uint32_t word;
+
+	reg = ha->iobase;
+
+	/* Release NVRAM write protection. */
+	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
+		/* Write enable. */
+		qla2x00_nv_write(ha, NVR_DATA_OUT);
+		qla2x00_nv_write(ha, 0);
+		qla2x00_nv_write(ha, 0);
+		for (word = 0; word < 8; word++)
+			qla2x00_nv_write(ha, NVR_DATA_OUT);
+
+		qla2x00_nv_deselect(ha);
+
+		/* Enable protection register. */
+		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+		qla2x00_nv_write(ha, NVR_PR_ENABLE);
+		qla2x00_nv_write(ha, NVR_PR_ENABLE);
+		for (word = 0; word < 8; word++)
+			qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
+
+		qla2x00_nv_deselect(ha);
+
+		/* Clear protection register (ffff is cleared). */
+		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
+		for (word = 0; word < 8; word++)
+			qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
+
+		qla2x00_nv_deselect(ha);
+
+		/* Wait for NVRAM to become ready. */
+		WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+		do {
+			NVRAM_DELAY();
+			word = RD_REG_WORD(&reg->nvram);
+		} while ((word & NVR_DATA_IN) == 0);
+	}
+}
+
+/**
+ * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
+ *	request routine to get the word from NVRAM.
+ * @ha: HA context
+ * @addr: Address in NVRAM to read
+ *
+ * Returns the word read from nvram @addr.
+ */
+uint16_t
+qla2x00_get_nvram_word(scsi_qla_host_t *ha, uint32_t addr)
+{
+	uint16_t	data;
+	uint32_t	nv_cmd;
+
+	nv_cmd = addr << 16;
+	nv_cmd |= NV_READ_OP;
+	data = qla2x00_nvram_request(ha, nv_cmd);
+
+	return (data);
+}
+
+/**
+ * qla2x00_write_nvram_word() - Write NVRAM data.
+ * @ha: HA context
+ * @addr: Address in NVRAM to write
+ * @data: word to program
+ */
+void
+qla2x00_write_nvram_word(scsi_qla_host_t *ha, uint32_t addr, uint16_t data)
+{
+	int count;
+	uint16_t word;
+	uint32_t nv_cmd;
+	device_reg_t __iomem *reg = ha->iobase;
+
+	qla2x00_nv_write(ha, NVR_DATA_OUT);
+	qla2x00_nv_write(ha, 0);
+	qla2x00_nv_write(ha, 0);
+
+	for (word = 0; word < 8; word++)
+		qla2x00_nv_write(ha, NVR_DATA_OUT);
+
+	qla2x00_nv_deselect(ha);
+
+	/* Write data */
+	nv_cmd = (addr << 16) | NV_WRITE_OP;
+	nv_cmd |= data;
+	nv_cmd <<= 5;
+	for (count = 0; count < 27; count++) {
+		if (nv_cmd & BIT_31)
+			qla2x00_nv_write(ha, NVR_DATA_OUT);
+		else
+			qla2x00_nv_write(ha, 0);
+
+		nv_cmd <<= 1;
+	}
+
+	qla2x00_nv_deselect(ha);
+
+	/* Wait for NVRAM to become ready */
+	WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+	do {
+		NVRAM_DELAY();
+		word = RD_REG_WORD(&reg->nvram);
+	} while ((word & NVR_DATA_IN) == 0);
+
+	qla2x00_nv_deselect(ha);
+
+	/* Disable writes */
+	qla2x00_nv_write(ha, NVR_DATA_OUT);
+	for (count = 0; count < 10; count++)
+		qla2x00_nv_write(ha, 0);
+
+	qla2x00_nv_deselect(ha);
+}
+
+/**
+ * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
+ *	NVRAM.
+ * @ha: HA context
+ * @nv_cmd: NVRAM command
+ *
+ * Bit definitions for NVRAM command:
+ *
+ *	Bit 26     = start bit
+ *	Bit 25, 24 = opcode
+ *	Bit 23-16  = address
+ *	Bit 15-0   = write data
+ *
+ * Returns the word read from nvram @addr.
+ */
+static uint16_t
+qla2x00_nvram_request(scsi_qla_host_t *ha, uint32_t nv_cmd)
+{
+	uint8_t		cnt;
+	device_reg_t __iomem *reg = ha->iobase;
+	uint16_t	data = 0;
+	uint16_t	reg_data;
+
+	/* Send command to NVRAM. */
+	nv_cmd <<= 5;
+	for (cnt = 0; cnt < 11; cnt++) {
+		if (nv_cmd & BIT_31)
+			qla2x00_nv_write(ha, NVR_DATA_OUT);
+		else
+			qla2x00_nv_write(ha, 0);
+		nv_cmd <<= 1;
+	}
+
+	/* Read data from NVRAM. */
+	for (cnt = 0; cnt < 16; cnt++) {
+		WRT_REG_WORD(&reg->nvram, NVR_SELECT | NVR_CLOCK);
+		NVRAM_DELAY();
+		data <<= 1;
+		reg_data = RD_REG_WORD(&reg->nvram);
+		if (reg_data & NVR_DATA_IN)
+			data |= BIT_0;
+		WRT_REG_WORD(&reg->nvram, NVR_SELECT);
+		RD_REG_WORD(&reg->nvram);	/* PCI Posting. */
+		NVRAM_DELAY();
+	}
+
+	/* Deselect chip. */
+	WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
+	NVRAM_DELAY();
+
+	return (data);
+}
+
+/**
+ * qla2x00_nv_write() - Clean NVRAM operations.
+ * @ha: HA context
+ */
+static void
+qla2x00_nv_deselect(scsi_qla_host_t *ha)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+
+	WRT_REG_WORD(&reg->nvram, NVR_DESELECT);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
+	NVRAM_DELAY();
+}
+
+/**
+ * qla2x00_nv_write() - Prepare for NVRAM read/write operation.
+ * @ha: HA context
+ * @data: Serial interface selector
+ */
+static void
+qla2x00_nv_write(scsi_qla_host_t *ha, uint16_t data)
+{
+	device_reg_t __iomem *reg = ha->iobase;
+
+	WRT_REG_WORD(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
+	NVRAM_DELAY();
+	WRT_REG_WORD(&reg->nvram, data | NVR_SELECT| NVR_CLOCK |
+	    NVR_WRT_ENABLE);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
+	NVRAM_DELAY();
+	WRT_REG_WORD(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
+	RD_REG_WORD(&reg->nvram);		/* PCI Posting. */
+	NVRAM_DELAY();
+}
+
diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h
new file mode 100644
index 0000000..73ff88b
--- /dev/null
+++ b/drivers/scsi/qla2xxx/qla_version.h
@@ -0,0 +1,27 @@
+/******************************************************************************
+ *                  QLOGIC LINUX SOFTWARE
+ *
+ * QLogic ISP2x00 device driver for Linux 2.6.x
+ * Copyright (C) 2003-2004 QLogic Corporation
+ * (www.qlogic.com)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ ******************************************************************************/
+/*
+ * Driver version 
+ */
+#define QLA2XXX_VERSION      "8.00.02b4-k"
+
+#define QLA_DRIVER_MAJOR_VER	8
+#define QLA_DRIVER_MINOR_VER	0
+#define QLA_DRIVER_PATCH_VER	2
+#define QLA_DRIVER_BETA_VER	4
diff --git a/drivers/scsi/qlogicfas.c b/drivers/scsi/qlogicfas.c
new file mode 100644
index 0000000..a1adb38
--- /dev/null
+++ b/drivers/scsi/qlogicfas.c
@@ -0,0 +1,230 @@
+/*
+ * Qlogic FAS408 ISA card driver
+ *
+ * Copyright 1994, Tom Zerucha.   
+ * tz@execpc.com
+ * 
+ * Redistributable under terms of the GNU General Public License
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * Check qlogicfas408.c for more credits and info.
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>		/* to get disk capacity */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "qlogicfas408.h"
+
+/* Set the following to 2 to use normal interrupt (active high/totempole-
+ * tristate), otherwise use 0 (REQUIRED FOR PCMCIA) for active low, open
+ * drain
+ */
+#define INT_TYPE	2
+
+static char qlogicfas_name[] = "qlogicfas";
+
+/*
+ *	Look for qlogic card and init if found 
+ */
+ 
+static struct Scsi_Host *__qlogicfas_detect(Scsi_Host_Template *host,
+								int qbase,
+								int qlirq)
+{
+	int qltyp;		/* type of chip */
+	int qinitid;
+	struct Scsi_Host *hreg;	/* registered host structure */
+	struct qlogicfas408_priv *priv;
+
+	/*	Qlogic Cards only exist at 0x230 or 0x330 (the chip itself
+	 *	decodes the address - I check 230 first since MIDI cards are
+	 *	typically at 0x330
+	 *
+	 *	Theoretically, two Qlogic cards can coexist in the same system.
+	 *	This should work by simply using this as a loadable module for
+	 *	the second card, but I haven't tested this.
+	 */
+
+	if (!qbase || qlirq == -1)
+		goto err;
+
+	if (!request_region(qbase, 0x10, qlogicfas_name)) {
+		printk(KERN_INFO "%s: address %#x is busy\n", qlogicfas_name,
+							      qbase);
+		goto err;
+	}
+
+	if (!qlogicfas408_detect(qbase, INT_TYPE)) {
+		printk(KERN_WARNING "%s: probe failed for %#x\n",
+								qlogicfas_name,
+								qbase);
+		goto err_release_mem;
+	}
+
+	printk(KERN_INFO "%s: Using preset base address of %03x,"
+			 " IRQ %d\n", qlogicfas_name, qbase, qlirq);
+
+	qltyp = qlogicfas408_get_chip_type(qbase, INT_TYPE);
+	qinitid = host->this_id;
+	if (qinitid < 0)
+		qinitid = 7;	/* if no ID, use 7 */
+
+	qlogicfas408_setup(qbase, qinitid, INT_TYPE);
+
+	hreg = scsi_host_alloc(host, sizeof(struct qlogicfas408_priv));
+	if (!hreg)
+		goto err_release_mem;
+	priv = get_priv_by_host(hreg);
+	hreg->io_port = qbase;
+	hreg->n_io_port = 16;
+	hreg->dma_channel = -1;
+	if (qlirq != -1)
+		hreg->irq = qlirq;
+	priv->qbase = qbase;
+	priv->qlirq = qlirq;
+	priv->qinitid = qinitid;
+	priv->shost = hreg;
+	priv->int_type = INT_TYPE;
+
+	sprintf(priv->qinfo,
+		"Qlogicfas Driver version 0.46, chip %02X at %03X, IRQ %d, TPdma:%d",
+		qltyp, qbase, qlirq, QL_TURBO_PDMA);
+	host->name = qlogicfas_name;
+
+	if (request_irq(qlirq, qlogicfas408_ihandl, 0, qlogicfas_name, hreg))
+		goto free_scsi_host;
+
+	if (scsi_add_host(hreg, NULL))
+		goto free_interrupt;
+
+	scsi_scan_host(hreg);
+
+	return hreg;
+
+free_interrupt:
+	free_irq(qlirq, hreg);
+
+free_scsi_host:
+	scsi_host_put(hreg);
+
+err_release_mem:
+	release_region(qbase, 0x10);
+err:
+	return NULL;
+}
+
+#define MAX_QLOGICFAS	8
+static struct qlogicfas408_priv *cards;
+static int iobase[MAX_QLOGICFAS];
+static int irq[MAX_QLOGICFAS] = { [0 ... MAX_QLOGICFAS-1] = -1 };
+module_param_array(iobase, int, NULL, 0);
+module_param_array(irq, int, NULL, 0);
+MODULE_PARM_DESC(iobase, "I/O address");
+MODULE_PARM_DESC(irq, "IRQ");
+
+static int __devinit qlogicfas_detect(Scsi_Host_Template *sht)
+{
+	struct Scsi_Host *shost;
+	struct qlogicfas408_priv *priv;
+	int num;
+
+	for (num = 0; num < MAX_QLOGICFAS; num++) {
+		shost = __qlogicfas_detect(sht, iobase[num], irq[num]);
+		if (shost == NULL) {
+			/* no more devices */
+			break;
+		}
+		priv = get_priv_by_host(shost);
+		priv->next = cards;
+		cards = priv;
+	}
+
+	return num;
+}
+
+static int qlogicfas_release(struct Scsi_Host *shost)
+{
+	struct qlogicfas408_priv *priv = get_priv_by_host(shost);
+
+	if (shost->irq) {
+		qlogicfas408_disable_ints(priv);	
+		free_irq(shost->irq, shost);
+	}
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_remove_host(shost);
+	scsi_host_put(shost);
+
+	return 0;
+}
+
+/*
+ *	The driver template is also needed for PCMCIA
+ */
+static Scsi_Host_Template qlogicfas_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= qlogicfas_name,
+	.proc_name		= qlogicfas_name,
+	.info			= qlogicfas408_info,
+	.queuecommand		= qlogicfas408_queuecommand,
+	.eh_abort_handler	= qlogicfas408_abort,
+	.eh_bus_reset_handler	= qlogicfas408_bus_reset,
+	.eh_device_reset_handler= qlogicfas408_device_reset,
+	.eh_host_reset_handler	= qlogicfas408_host_reset,
+	.bios_param		= qlogicfas408_biosparam,
+	.can_queue		= 1,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+static __init int qlogicfas_init(void)
+{
+	if (!qlogicfas_detect(&qlogicfas_driver_template)) {
+		/* no cards found */
+		printk(KERN_INFO "%s: no cards were found, please specify "
+				 "I/O address and IRQ using iobase= and irq= "
+				 "options", qlogicfas_name);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+static __exit void qlogicfas_exit(void)
+{
+	struct qlogicfas408_priv *priv;
+
+	for (priv = cards; priv != NULL; priv = priv->next)
+		qlogicfas_release(priv->shost);
+}
+
+MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
+MODULE_DESCRIPTION("Driver for the Qlogic FAS408 based ISA card");
+MODULE_LICENSE("GPL");
+module_init(qlogicfas_init);
+module_exit(qlogicfas_exit);
+
diff --git a/drivers/scsi/qlogicfas408.c b/drivers/scsi/qlogicfas408.c
new file mode 100644
index 0000000..5b6ce0a
--- /dev/null
+++ b/drivers/scsi/qlogicfas408.c
@@ -0,0 +1,637 @@
+/*----------------------------------------------------------------*/
+/*
+   Qlogic linux driver - work in progress. No Warranty express or implied.
+   Use at your own risk.  Support Tort Reform so you won't have to read all
+   these silly disclaimers.
+
+   Copyright 1994, Tom Zerucha.   
+   tz@execpc.com
+   
+   Additional Code, and much appreciated help by
+   Michael A. Griffith
+   grif@cs.ucr.edu
+
+   Thanks to Eric Youngdale and Dave Hinds for loadable module and PCMCIA
+   help respectively, and for suffering through my foolishness during the
+   debugging process.
+
+   Reference Qlogic FAS408 Technical Manual, 53408-510-00A, May 10, 1994
+   (you can reference it, but it is incomplete and inaccurate in places)
+
+   Version 0.46 1/30/97 - kernel 1.2.0+
+
+   Functions as standalone, loadable, and PCMCIA driver, the latter from
+   Dave Hinds' PCMCIA package.
+   
+   Cleaned up 26/10/2002 by Alan Cox <alan@redhat.com> as part of the 2.5
+   SCSI driver cleanup and audit. This driver still needs work on the
+   following
+   	-	Non terminating hardware waits
+   	-	Some layering violations with its pcmcia stub
+
+   Redistributable under terms of the GNU General Public License
+
+   For the avoidance of doubt the "preferred form" of this code is one which
+   is in an open non patent encumbered format. Where cryptographic key signing
+   forms part of the process of creating an executable the information
+   including keys needed to generate an equivalently functional executable
+   are deemed to be part of the source code.
+
+*/
+
+#include <linux/module.h>
+#include <linux/blkdev.h>		/* to get disk capacity */
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "qlogicfas408.h"
+
+/*----------------------------------------------------------------*/
+static int qlcfg5 = (XTALFREQ << 5);	/* 15625/512 */
+static int qlcfg6 = SYNCXFRPD;
+static int qlcfg7 = SYNCOFFST;
+static int qlcfg8 = (SLOWCABLE << 7) | (QL_ENABLE_PARITY << 4);
+static int qlcfg9 = ((XTALFREQ + 4) / 5);
+static int qlcfgc = (FASTCLK << 3) | (FASTSCSI << 4);
+
+/*----------------------------------------------------------------*/
+
+/*----------------------------------------------------------------*/
+/* local functions */
+/*----------------------------------------------------------------*/
+
+/* error recovery - reset everything */
+
+static void ql_zap(struct qlogicfas408_priv *priv)
+{
+	int x;
+	int qbase = priv->qbase;
+	int int_type = priv->int_type;
+
+	x = inb(qbase + 0xd);
+	REG0;
+	outb(3, qbase + 3);	/* reset SCSI */
+	outb(2, qbase + 3);	/* reset chip */
+	if (x & 0x80)
+		REG1;
+}
+
+/*
+ *	Do a pseudo-dma tranfer
+ */
+ 
+static int ql_pdma(struct qlogicfas408_priv *priv, int phase, char *request, int reqlen)
+{
+	int j;
+	int qbase = priv->qbase;
+	j = 0;
+	if (phase & 1) {	/* in */
+#if QL_TURBO_PDMA
+		rtrc(4)
+		/* empty fifo in large chunks */
+		if (reqlen >= 128 && (inb(qbase + 8) & 2)) {	/* full */
+			insl(qbase + 4, request, 32);
+			reqlen -= 128;
+			request += 128;
+		}
+		while (reqlen >= 84 && !(j & 0xc0))	/* 2/3 */
+			if ((j = inb(qbase + 8)) & 4) 
+			{
+				insl(qbase + 4, request, 21);
+				reqlen -= 84;
+				request += 84;
+			}
+		if (reqlen >= 44 && (inb(qbase + 8) & 8)) {	/* 1/3 */
+			insl(qbase + 4, request, 11);
+			reqlen -= 44;
+			request += 44;
+		}
+#endif
+		/* until both empty and int (or until reclen is 0) */
+		rtrc(7)
+		j = 0;
+		while (reqlen && !((j & 0x10) && (j & 0xc0))) 
+		{
+			/* while bytes to receive and not empty */
+			j &= 0xc0;
+			while (reqlen && !((j = inb(qbase + 8)) & 0x10)) 
+			{
+				*request++ = inb(qbase + 4);
+				reqlen--;
+			}
+			if (j & 0x10)
+				j = inb(qbase + 8);
+
+		}
+	} else {		/* out */
+#if QL_TURBO_PDMA
+		rtrc(4)
+		    if (reqlen >= 128 && inb(qbase + 8) & 0x10) {	/* empty */
+			outsl(qbase + 4, request, 32);
+			reqlen -= 128;
+			request += 128;
+		}
+		while (reqlen >= 84 && !(j & 0xc0))	/* 1/3 */
+			if (!((j = inb(qbase + 8)) & 8)) {
+				outsl(qbase + 4, request, 21);
+				reqlen -= 84;
+				request += 84;
+			}
+		if (reqlen >= 40 && !(inb(qbase + 8) & 4)) {	/* 2/3 */
+			outsl(qbase + 4, request, 10);
+			reqlen -= 40;
+			request += 40;
+		}
+#endif
+		/* until full and int (or until reclen is 0) */
+		rtrc(7)
+		    j = 0;
+		while (reqlen && !((j & 2) && (j & 0xc0))) {
+			/* while bytes to send and not full */
+			while (reqlen && !((j = inb(qbase + 8)) & 2)) 
+			{
+				outb(*request++, qbase + 4);
+				reqlen--;
+			}
+			if (j & 2)
+				j = inb(qbase + 8);
+		}
+	}
+	/* maybe return reqlen */
+	return inb(qbase + 8) & 0xc0;
+}
+
+/*
+ *	Wait for interrupt flag (polled - not real hardware interrupt) 
+ */
+
+static int ql_wai(struct qlogicfas408_priv *priv)
+{
+	int k;
+	int qbase = priv->qbase;
+	unsigned long i;
+
+	k = 0;
+	i = jiffies + WATCHDOG;
+	while (time_before(jiffies, i) && !priv->qabort &&
+					!((k = inb(qbase + 4)) & 0xe0)) {
+		barrier();
+		cpu_relax();
+	}
+	if (time_after_eq(jiffies, i))
+		return (DID_TIME_OUT);
+	if (priv->qabort)
+		return (priv->qabort == 1 ? DID_ABORT : DID_RESET);
+	if (k & 0x60)
+		ql_zap(priv);
+	if (k & 0x20)
+		return (DID_PARITY);
+	if (k & 0x40)
+		return (DID_ERROR);
+	return 0;
+}
+
+/*
+ *	Initiate scsi command - queueing handler 
+ *	caller must hold host lock
+ */
+
+static void ql_icmd(Scsi_Cmnd * cmd)
+{
+	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+	int 	qbase = priv->qbase;
+	int	int_type = priv->int_type;
+	unsigned int i;
+
+	priv->qabort = 0;
+
+	REG0;
+	/* clearing of interrupts and the fifo is needed */
+
+	inb(qbase + 5);		/* clear interrupts */
+	if (inb(qbase + 5))	/* if still interrupting */
+		outb(2, qbase + 3);	/* reset chip */
+	else if (inb(qbase + 7) & 0x1f)
+		outb(1, qbase + 3);	/* clear fifo */
+	while (inb(qbase + 5));	/* clear ints */
+	REG1;
+	outb(1, qbase + 8);	/* set for PIO pseudo DMA */
+	outb(0, qbase + 0xb);	/* disable ints */
+	inb(qbase + 8);		/* clear int bits */
+	REG0;
+	outb(0x40, qbase + 0xb);	/* enable features */
+
+	/* configurables */
+	outb(qlcfgc, qbase + 0xc);
+	/* config: no reset interrupt, (initiator) bus id */
+	outb(0x40 | qlcfg8 | priv->qinitid, qbase + 8);
+	outb(qlcfg7, qbase + 7);
+	outb(qlcfg6, qbase + 6);
+	 /**/ outb(qlcfg5, qbase + 5);	/* select timer */
+	outb(qlcfg9 & 7, qbase + 9);	/* prescaler */
+/*	outb(0x99, qbase + 5);	*/
+	outb(cmd->device->id, qbase + 4);
+
+	for (i = 0; i < cmd->cmd_len; i++)
+		outb(cmd->cmnd[i], qbase + 2);
+
+	priv->qlcmd = cmd;
+	outb(0x41, qbase + 3);	/* select and send command */
+}
+
+/*
+ *	Process scsi command - usually after interrupt 
+ */
+
+static unsigned int ql_pcmd(Scsi_Cmnd * cmd)
+{
+	unsigned int i, j;
+	unsigned long k;
+	unsigned int result;	/* ultimate return result */
+	unsigned int status;	/* scsi returned status */
+	unsigned int message;	/* scsi returned message */
+	unsigned int phase;	/* recorded scsi phase */
+	unsigned int reqlen;	/* total length of transfer */
+	struct scatterlist *sglist;	/* scatter-gather list pointer */
+	unsigned int sgcount;	/* sg counter */
+	char *buf;
+	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+	int qbase = priv->qbase;
+	int int_type = priv->int_type;
+
+	rtrc(1)
+	j = inb(qbase + 6);
+	i = inb(qbase + 5);
+	if (i == 0x20) {
+		return (DID_NO_CONNECT << 16);
+	}
+	i |= inb(qbase + 5);	/* the 0x10 bit can be set after the 0x08 */
+	if (i != 0x18) {
+		printk(KERN_ERR "Ql:Bad Interrupt status:%02x\n", i);
+		ql_zap(priv);
+		return (DID_BAD_INTR << 16);
+	}
+	j &= 7;			/* j = inb( qbase + 7 ) >> 5; */
+
+	/* correct status is supposed to be step 4 */
+	/* it sometimes returns step 3 but with 0 bytes left to send */
+	/* We can try stuffing the FIFO with the max each time, but we will get a
+	   sequence of 3 if any bytes are left (but we do flush the FIFO anyway */
+
+	if (j != 3 && j != 4) {
+		printk(KERN_ERR "Ql:Bad sequence for command %d, int %02X, cmdleft = %d\n",
+		     j, i, inb(qbase + 7) & 0x1f);
+		ql_zap(priv);
+		return (DID_ERROR << 16);
+	}
+	result = DID_OK;
+	if (inb(qbase + 7) & 0x1f)	/* if some bytes in fifo */
+		outb(1, qbase + 3);	/* clear fifo */
+	/* note that request_bufflen is the total xfer size when sg is used */
+	reqlen = cmd->request_bufflen;
+	/* note that it won't work if transfers > 16M are requested */
+	if (reqlen && !((phase = inb(qbase + 4)) & 6)) {	/* data phase */
+		rtrc(2)
+		outb(reqlen, qbase);	/* low-mid xfer cnt */
+		outb(reqlen >> 8, qbase + 1);	/* low-mid xfer cnt */
+		outb(reqlen >> 16, qbase + 0xe);	/* high xfer cnt */
+		outb(0x90, qbase + 3);	/* command do xfer */
+		/* PIO pseudo DMA to buffer or sglist */
+		REG1;
+		if (!cmd->use_sg)
+			ql_pdma(priv, phase, cmd->request_buffer,
+				cmd->request_bufflen);
+		else {
+			sgcount = cmd->use_sg;
+			sglist = cmd->request_buffer;
+			while (sgcount--) {
+				if (priv->qabort) {
+					REG0;
+					return ((priv->qabort == 1 ?
+						DID_ABORT : DID_RESET) << 16);
+				}
+				buf = page_address(sglist->page) + sglist->offset;
+				if (ql_pdma(priv, phase, buf, sglist->length))
+					break;
+				sglist++;
+			}
+		}
+		REG0;
+		rtrc(2)
+		/*
+		 *	Wait for irq (split into second state of irq handler
+		 *	if this can take time) 
+		 */
+		if ((k = ql_wai(priv)))
+			return (k << 16);
+		k = inb(qbase + 5);	/* should be 0x10, bus service */
+	}
+
+	/*
+	 *	Enter Status (and Message In) Phase 
+	 */
+	 
+	k = jiffies + WATCHDOG;
+
+	while (time_before(jiffies, k) && !priv->qabort &&
+						!(inb(qbase + 4) & 6))
+		cpu_relax();	/* wait for status phase */
+
+	if (time_after_eq(jiffies, k)) {
+		ql_zap(priv);
+		return (DID_TIME_OUT << 16);
+	}
+
+	/* FIXME: timeout ?? */
+	while (inb(qbase + 5))
+		cpu_relax();	/* clear pending ints */
+
+	if (priv->qabort)
+		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+
+	outb(0x11, qbase + 3);	/* get status and message */
+	if ((k = ql_wai(priv)))
+		return (k << 16);
+	i = inb(qbase + 5);	/* get chip irq stat */
+	j = inb(qbase + 7) & 0x1f;	/* and bytes rec'd */
+	status = inb(qbase + 2);
+	message = inb(qbase + 2);
+
+	/*
+	 *	Should get function complete int if Status and message, else 
+	 *	bus serv if only status 
+	 */
+	if (!((i == 8 && j == 2) || (i == 0x10 && j == 1))) {
+		printk(KERN_ERR "Ql:Error during status phase, int=%02X, %d bytes recd\n", i, j);
+		result = DID_ERROR;
+	}
+	outb(0x12, qbase + 3);	/* done, disconnect */
+	rtrc(1)
+	if ((k = ql_wai(priv)))
+		return (k << 16);
+
+	/*
+	 *	Should get bus service interrupt and disconnect interrupt 
+	 */
+	 
+	i = inb(qbase + 5);	/* should be bus service */
+	while (!priv->qabort && ((i & 0x20) != 0x20)) {
+		barrier();
+		cpu_relax();
+		i |= inb(qbase + 5);
+	}
+	rtrc(0)
+
+	if (priv->qabort)
+		return ((priv->qabort == 1 ? DID_ABORT : DID_RESET) << 16);
+		
+	return (result << 16) | (message << 8) | (status & STATUS_MASK);
+}
+
+/*
+ *	Interrupt handler 
+ */
+
+static void ql_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+{
+	Scsi_Cmnd *icmd;
+	struct Scsi_Host *host = (struct Scsi_Host *)dev_id;
+	struct qlogicfas408_priv *priv = get_priv_by_host(host);
+	int qbase = priv->qbase;
+	REG0;
+
+	if (!(inb(qbase + 4) & 0x80))	/* false alarm? */
+		return;
+
+	if (priv->qlcmd == NULL) {	/* no command to process? */
+		int i;
+		i = 16;
+		while (i-- && inb(qbase + 5));	/* maybe also ql_zap() */
+		return;
+	}
+	icmd = priv->qlcmd;
+	icmd->result = ql_pcmd(icmd);
+	priv->qlcmd = NULL;
+	/*
+	 *	If result is CHECK CONDITION done calls qcommand to request 
+	 *	sense 
+	 */
+	(icmd->scsi_done) (icmd);
+}
+
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *host = dev_id;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	ql_ihandl(irq, dev_id, regs);
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+/*
+ *	Queued command
+ */
+
+int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+	if (cmd->device->id == priv->qinitid) {
+		cmd->result = DID_BAD_TARGET << 16;
+		done(cmd);
+		return 0;
+	}
+
+	cmd->scsi_done = done;
+	/* wait for the last command's interrupt to finish */
+	while (priv->qlcmd != NULL) {
+		barrier();
+		cpu_relax();
+	}
+	ql_icmd(cmd);
+	return 0;
+}
+
+/* 
+ *	Return bios parameters 
+ */
+
+int qlogicfas408_biosparam(struct scsi_device * disk,
+		        struct block_device *dev,
+			sector_t capacity, int ip[])
+{
+/* This should mimic the DOS Qlogic driver's behavior exactly */
+	ip[0] = 0x40;
+	ip[1] = 0x20;
+	ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
+	if (ip[2] > 1024) {
+		ip[0] = 0xff;
+		ip[1] = 0x3f;
+		ip[2] = (unsigned long) capacity / (ip[0] * ip[1]);
+#if 0
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+#endif
+	}
+	return 0;
+}
+
+/*
+ *	Abort a command in progress
+ */
+ 
+int qlogicfas408_abort(Scsi_Cmnd * cmd)
+{
+	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+	priv->qabort = 1;
+	ql_zap(priv);
+	return SUCCESS;
+}
+
+/* 
+ *	Reset SCSI bus
+ *	FIXME: This function is invoked with cmd = NULL directly by
+ *	the PCMCIA qlogic_stub code. This wants fixing
+ */
+
+int qlogicfas408_bus_reset(Scsi_Cmnd * cmd)
+{
+	struct qlogicfas408_priv *priv = get_priv_by_cmd(cmd);
+	priv->qabort = 2;
+	ql_zap(priv);
+	return SUCCESS;
+}
+
+/* 
+ *	Reset SCSI host controller
+ */
+
+int qlogicfas408_host_reset(Scsi_Cmnd * cmd)
+{
+	return FAILED;
+}
+
+/* 
+ *	Reset SCSI device
+ */
+
+int qlogicfas408_device_reset(Scsi_Cmnd * cmd)
+{
+	return FAILED;
+}
+
+/*
+ *	Return info string
+ */
+
+const char *qlogicfas408_info(struct Scsi_Host *host)
+{
+	struct qlogicfas408_priv *priv = get_priv_by_host(host);
+	return priv->qinfo;
+}
+
+/*
+ *	Get type of chip
+ */
+
+int qlogicfas408_get_chip_type(int qbase, int int_type)
+{
+	REG1;
+	return inb(qbase + 0xe) & 0xf8;
+}
+
+/*
+ *	Perform initialization tasks
+ */
+
+void qlogicfas408_setup(int qbase, int id, int int_type)
+{
+	outb(1, qbase + 8);	/* set for PIO pseudo DMA */
+	REG0;
+	outb(0x40 | qlcfg8 | id, qbase + 8);	/* (ini) bus id, disable scsi rst */
+	outb(qlcfg5, qbase + 5);	/* select timer */
+	outb(qlcfg9, qbase + 9);	/* prescaler */
+
+#if QL_RESET_AT_START
+	outb(3, qbase + 3);
+
+	REG1;
+	/* FIXME: timeout */
+	while (inb(qbase + 0xf) & 4)
+		cpu_relax();
+
+	REG0;
+#endif
+}
+
+/*
+ *	Checks if this is a QLogic FAS 408
+ */
+
+int qlogicfas408_detect(int qbase, int int_type)
+{
+        REG1;
+	return (((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7) &&
+	       ((inb(qbase + 0xe) ^ inb(qbase + 0xe)) == 7));		
+}
+
+/*
+ *	Disable interrupts
+ */
+
+void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv)
+{
+	int qbase = priv->qbase;
+	int int_type = priv->int_type;
+
+	REG1;
+	outb(0, qbase + 0xb);	/* disable ints */
+}
+
+/*
+ *	Init and exit functions
+ */
+
+static int __init qlogicfas408_init(void)
+{
+	return 0;
+}
+
+static void __exit qlogicfas408_exit(void)
+{
+
+}
+
+MODULE_AUTHOR("Tom Zerucha, Michael Griffith");
+MODULE_DESCRIPTION("Driver for the Qlogic FAS SCSI controllers");
+MODULE_LICENSE("GPL");
+module_init(qlogicfas408_init);
+module_exit(qlogicfas408_exit);
+
+EXPORT_SYMBOL(qlogicfas408_info);
+EXPORT_SYMBOL(qlogicfas408_queuecommand);
+EXPORT_SYMBOL(qlogicfas408_abort);
+EXPORT_SYMBOL(qlogicfas408_bus_reset);
+EXPORT_SYMBOL(qlogicfas408_device_reset);
+EXPORT_SYMBOL(qlogicfas408_host_reset);
+EXPORT_SYMBOL(qlogicfas408_biosparam);
+EXPORT_SYMBOL(qlogicfas408_ihandl);
+EXPORT_SYMBOL(qlogicfas408_get_chip_type);
+EXPORT_SYMBOL(qlogicfas408_setup);
+EXPORT_SYMBOL(qlogicfas408_detect);
+EXPORT_SYMBOL(qlogicfas408_disable_ints);
+
diff --git a/drivers/scsi/qlogicfas408.h b/drivers/scsi/qlogicfas408.h
new file mode 100644
index 0000000..f01cbd6
--- /dev/null
+++ b/drivers/scsi/qlogicfas408.h
@@ -0,0 +1,120 @@
+/* to be used by qlogicfas and qlogic_cs */
+#ifndef __QLOGICFAS408_H
+#define __QLOGICFAS408_H
+
+/*----------------------------------------------------------------*/
+/* Configuration */
+
+/* Set the following to max out the speed of the PIO PseudoDMA transfers,
+   again, 0 tends to be slower, but more stable.  */
+
+#define QL_TURBO_PDMA 1
+
+/* This should be 1 to enable parity detection */
+
+#define QL_ENABLE_PARITY 1
+
+/* This will reset all devices when the driver is initialized (during bootup).
+   The other linux drivers don't do this, but the DOS drivers do, and after
+   using DOS or some kind of crash or lockup this will bring things back
+   without requiring a cold boot.  It does take some time to recover from a
+   reset, so it is slower, and I have seen timeouts so that devices weren't
+   recognized when this was set. */
+
+#define QL_RESET_AT_START 0
+
+/* crystal frequency in megahertz (for offset 5 and 9)
+   Please set this for your card.  Most Qlogic cards are 40 Mhz.  The
+   Control Concepts ISA (not VLB) is 24 Mhz */
+
+#define XTALFREQ	40
+
+/**********/
+/* DANGER! modify these at your own risk */
+/* SLOWCABLE can usually be reset to zero if you have a clean setup and
+   proper termination.  The rest are for synchronous transfers and other
+   advanced features if your device can transfer faster than 5Mb/sec.
+   If you are really curious, email me for a quick howto until I have
+   something official */
+/**********/
+
+/*****/
+/* config register 1 (offset 8) options */
+/* This needs to be set to 1 if your cabling is long or noisy */
+#define SLOWCABLE 1
+
+/*****/
+/* offset 0xc */
+/* This will set fast (10Mhz) synchronous timing when set to 1
+   For this to have an effect, FASTCLK must also be 1 */
+#define FASTSCSI 0
+
+/* This when set to 1 will set a faster sync transfer rate */
+#define FASTCLK 0	/*(XTALFREQ>25?1:0)*/
+
+/*****/
+/* offset 6 */
+/* This is the sync transfer divisor, XTALFREQ/X will be the maximum
+   achievable data rate (assuming the rest of the system is capable
+   and set properly) */
+#define SYNCXFRPD 5	/*(XTALFREQ/5)*/
+
+/*****/
+/* offset 7 */
+/* This is the count of how many synchronous transfers can take place
+	i.e. how many reqs can occur before an ack is given.
+	The maximum value for this is 15, the upper bits can modify
+	REQ/ACK assertion and deassertion during synchronous transfers
+	If this is 0, the bus will only transfer asynchronously */
+#define SYNCOFFST 0
+/* for the curious, bits 7&6 control the deassertion delay in 1/2 cycles
+	of the 40Mhz clock. If FASTCLK is 1, specifying 01 (1/2) will
+	cause the deassertion to be early by 1/2 clock.  Bits 5&4 control
+	the assertion delay, also in 1/2 clocks (FASTCLK is ignored here). */
+
+/*----------------------------------------------------------------*/
+
+struct qlogicfas408_priv {
+	 int		qbase;		/* Port */
+	 int		qinitid;	/* initiator ID */
+	 int		qabort;		/* Flag to cause an abort */
+	 int		qlirq;		/* IRQ being used */
+	 int		int_type;	/* type of irq, 2 for ISA board, 0 for PCMCIA */
+	 char		qinfo[80];	/* description */
+	 Scsi_Cmnd 	*qlcmd;		/* current command being processed */
+	 struct Scsi_Host *shost;	/* pointer back to host */
+	 struct qlogicfas408_priv *next; /* next private struct */
+};
+
+/* The qlogic card uses two register maps - These macros select which one */
+#define REG0 ( outb( inb( qbase + 0xd ) & 0x7f , qbase + 0xd ), outb( 4 , qbase + 0xd ))
+#define REG1 ( outb( inb( qbase + 0xd ) | 0x80 , qbase + 0xd ), outb( 0xb4 | int_type, qbase + 0xd ))
+
+/* following is watchdog timeout in microseconds */
+#define WATCHDOG 5000000
+
+/*----------------------------------------------------------------*/
+/* the following will set the monitor border color (useful to find
+   where something crashed or gets stuck at and as a simple profiler) */
+
+#define rtrc(i) {}
+
+#define get_priv_by_cmd(x) (struct qlogicfas408_priv *)&((x)->device->host->hostdata[0])
+#define get_priv_by_host(x) (struct qlogicfas408_priv *)&((x)->hostdata[0])
+
+irqreturn_t qlogicfas408_ihandl(int irq, void *dev_id, struct pt_regs *regs);
+int qlogicfas408_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *));
+int qlogicfas408_biosparam(struct scsi_device * disk,
+		        struct block_device *dev,
+			sector_t capacity, int ip[]);
+int qlogicfas408_abort(Scsi_Cmnd * cmd);
+int qlogicfas408_bus_reset(Scsi_Cmnd * cmd);
+int qlogicfas408_host_reset(Scsi_Cmnd * cmd);
+int qlogicfas408_device_reset(Scsi_Cmnd * cmd);
+const char *qlogicfas408_info(struct Scsi_Host *host);
+int qlogicfas408_get_chip_type(int qbase, int int_type);
+void qlogicfas408_setup(int qbase, int id, int int_type);
+int qlogicfas408_detect(int qbase, int int_type);
+void qlogicfas408_disable_ints(struct qlogicfas408_priv *priv);
+#endif	/* __QLOGICFAS408_H */
+
diff --git a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
new file mode 100644
index 0000000..24c1174
--- /dev/null
+++ b/drivers/scsi/qlogicfc.c
@@ -0,0 +1,2227 @@
+/*
+ * QLogic ISP2x00 SCSI-FCP
+ * Written by Erik H. Moe, ehm@cris.com
+ * Copyright 1995, Erik H. Moe
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+/* Renamed and updated to 1.3.x by Michael Griffith <grif@cs.ucr.edu> */
+
+/* This is a version of the isp1020 driver which was modified by
+ * Chris Loveland <cwl@iol.unh.edu> to support the isp2100 and isp2200
+ *
+ * Big endian support and dynamic DMA mapping added
+ * by Jakub Jelinek <jakub@redhat.com>.
+ *
+ * Conversion to final pci64 DMA interfaces
+ * by David S. Miller <davem@redhat.com>.
+ */
+
+/*
+ * $Date: 1995/09/22 02:23:15 $
+ * $Revision: 0.5 $
+ *
+ * $Log: isp1020.c,v $
+ * Revision 0.5  1995/09/22  02:23:15  root
+ * do auto request sense
+ *
+ * Revision 0.4  1995/08/07  04:44:33  root
+ * supply firmware with driver.
+ * numerous bug fixes/general cleanup of code.
+ *
+ * Revision 0.3  1995/07/16  16:15:39  root
+ * added reset/abort code.
+ *
+ * Revision 0.2  1995/06/29  03:14:19  root
+ * fixed biosparam.
+ * added queue protocol.
+ *
+ * Revision 0.1  1995/06/25  01:55:45  root
+ * Initial release.
+ *
+ */
+
+#include <linux/blkdev.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+#define pci64_dma_hi32(a) ((u32) (0xffffffff & (((u64)(a))>>32)))
+#define pci64_dma_lo32(a) ((u32) (0xffffffff & (((u64)(a)))))
+#define pci64_dma_build(hi,lo) \
+	((dma_addr_t)(((u64)(lo))|(((u64)(hi))<<32)))
+
+/*
+ * With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 2 scatter/gather entries.  If we need more
+ * than 2 entries, continuation entries can be used that hold
+ * another 5 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+
+#define DATASEGS_PER_COMMAND 2
+#define DATASEGS_PER_CONT 5
+
+#define QLOGICFC_REQ_QUEUE_LEN 255     /* must be power of two - 1 */
+#define QLOGICFC_MAX_SG(ql)	(DATASEGS_PER_COMMAND + (((ql) > 0) ? DATASEGS_PER_CONT*((ql) - 1) : 0))
+#define QLOGICFC_CMD_PER_LUN    8
+
+/* Configuration section **************************************************** */
+
+/* Set the following macro to 1 to reload the ISP2x00's firmware.  This is
+   version 1.17.30 of the isp2100's firmware and version 2.00.40 of the 
+   isp2200's firmware. 
+*/
+
+#define USE_NVRAM_DEFAULTS      1
+
+#define ISP2x00_PORTDB          1
+
+/* Set the following to 1 to include fabric support, fabric support is 
+ * currently not as well tested as the other aspects of the driver */
+
+#define ISP2x00_FABRIC          1
+
+/*  Macros used for debugging */
+#define DEBUG_ISP2x00		0
+#define DEBUG_ISP2x00_INT	0
+#define DEBUG_ISP2x00_INTR	0
+#define DEBUG_ISP2x00_SETUP	0
+#define DEBUG_ISP2x00_FABRIC    0
+#define TRACE_ISP 		0 
+
+
+#define DEFAULT_LOOP_COUNT	1000000000
+
+#define ISP_TIMEOUT (2*HZ)
+/* End Configuration section ************************************************ */
+
+#include <linux/module.h>
+
+#if TRACE_ISP
+
+#define TRACE_BUF_LEN	(32*1024)
+
+struct {
+	u_long next;
+	struct {
+		u_long time;
+		u_int index;
+		u_int addr;
+		u_char *name;
+	} buf[TRACE_BUF_LEN];
+} trace;
+
+#define TRACE(w, i, a)						\
+{								\
+	unsigned long flags;					\
+								\
+	save_flags(flags);					\
+	cli();							\
+	trace.buf[trace.next].name  = (w);			\
+	trace.buf[trace.next].time  = jiffies;			\
+	trace.buf[trace.next].index = (i);			\
+	trace.buf[trace.next].addr  = (long) (a);		\
+	trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1);	\
+	restore_flags(flags);					\
+}
+
+#else
+#define TRACE(w, i, a)
+#endif
+
+#if DEBUG_ISP2x00_FABRIC
+#define DEBUG_FABRIC(x)	x
+#else
+#define DEBUG_FABRIC(x)
+#endif				/* DEBUG_ISP2x00_FABRIC */
+
+
+#if DEBUG_ISP2x00
+#define ENTER(x)	printk("isp2x00 : entering %s()\n", x);
+#define LEAVE(x)	printk("isp2x00 : leaving %s()\n", x);
+#define DEBUG(x)	x
+#else
+#define ENTER(x)
+#define LEAVE(x)
+#define DEBUG(x)
+#endif				/* DEBUG_ISP2x00 */
+
+#if DEBUG_ISP2x00_INTR
+#define ENTER_INTR(x)	printk("isp2x00 : entering %s()\n", x);
+#define LEAVE_INTR(x)	printk("isp2x00 : leaving %s()\n", x);
+#define DEBUG_INTR(x)	x
+#else
+#define ENTER_INTR(x)
+#define LEAVE_INTR(x)
+#define DEBUG_INTR(x)
+#endif				/* DEBUG ISP2x00_INTR */
+
+
+#define ISP2100_REV_ID1	       1
+#define ISP2100_REV_ID3        3
+#define ISP2200_REV_ID5        5
+
+/* host configuration and control registers */
+#define HOST_HCCR	0xc0	/* host command and control */
+
+/* pci bus interface registers */
+#define FLASH_BIOS_ADDR	0x00
+#define FLASH_BIOS_DATA	0x02
+#define ISP_CTRL_STATUS	0x06	/* configuration register #1 */
+#define PCI_INTER_CTL	0x08	/* pci interrupt control */
+#define PCI_INTER_STS	0x0a	/* pci interrupt status */
+#define PCI_SEMAPHORE	0x0c	/* pci semaphore */
+#define PCI_NVRAM	0x0e	/* pci nvram interface */
+
+/* mailbox registers */
+#define MBOX0		0x10	/* mailbox 0 */
+#define MBOX1		0x12	/* mailbox 1 */
+#define MBOX2		0x14	/* mailbox 2 */
+#define MBOX3		0x16	/* mailbox 3 */
+#define MBOX4		0x18	/* mailbox 4 */
+#define MBOX5		0x1a	/* mailbox 5 */
+#define MBOX6		0x1c	/* mailbox 6 */
+#define MBOX7		0x1e	/* mailbox 7 */
+
+/* mailbox command complete status codes */
+#define MBOX_COMMAND_COMPLETE		0x4000
+#define INVALID_COMMAND			0x4001
+#define HOST_INTERFACE_ERROR		0x4002
+#define TEST_FAILED			0x4003
+#define COMMAND_ERROR			0x4005
+#define COMMAND_PARAM_ERROR		0x4006
+#define PORT_ID_USED                    0x4007
+#define LOOP_ID_USED                    0x4008
+#define ALL_IDS_USED                    0x4009
+
+/* async event status codes */
+#define RESET_DETECTED  		0x8001
+#define SYSTEM_ERROR			0x8002
+#define REQUEST_TRANSFER_ERROR		0x8003
+#define RESPONSE_TRANSFER_ERROR		0x8004
+#define REQUEST_QUEUE_WAKEUP		0x8005
+#define LIP_OCCURRED                     0x8010
+#define LOOP_UP                         0x8011
+#define LOOP_DOWN                       0x8012
+#define LIP_RECEIVED                    0x8013
+#define PORT_DB_CHANGED                 0x8014
+#define CHANGE_NOTIFICATION             0x8015
+#define SCSI_COMMAND_COMPLETE           0x8020
+#define POINT_TO_POINT_UP               0x8030
+#define CONNECTION_MODE                 0x8036
+
+struct Entry_header {
+	u_char entry_type;
+	u_char entry_cnt;
+	u_char sys_def_1;
+	u_char flags;
+};
+
+/* entry header type commands */
+#define ENTRY_COMMAND		0x19
+#define ENTRY_CONTINUATION	0x0a
+
+#define ENTRY_STATUS		0x03
+#define ENTRY_MARKER		0x04
+
+
+/* entry header flag definitions */
+#define EFLAG_BUSY		2
+#define EFLAG_BAD_HEADER	4
+#define EFLAG_BAD_PAYLOAD	8
+
+struct dataseg {
+	u_int d_base;
+	u_int d_base_hi;
+	u_int d_count;
+};
+
+struct Command_Entry {
+	struct Entry_header hdr;
+	u_int handle;
+	u_char target_lun;
+	u_char target_id;
+	u_short expanded_lun;
+	u_short control_flags;
+	u_short rsvd2;
+	u_short time_out;
+	u_short segment_cnt;
+	u_char cdb[16];
+	u_int total_byte_cnt;
+	struct dataseg dataseg[DATASEGS_PER_COMMAND];
+};
+
+/* command entry control flag definitions */
+#define CFLAG_NODISC		0x01
+#define CFLAG_HEAD_TAG		0x02
+#define CFLAG_ORDERED_TAG	0x04
+#define CFLAG_SIMPLE_TAG	0x08
+#define CFLAG_TAR_RTN		0x10
+#define CFLAG_READ		0x20
+#define CFLAG_WRITE		0x40
+
+struct Continuation_Entry {
+	struct Entry_header hdr;
+	struct dataseg dataseg[DATASEGS_PER_CONT];
+};
+
+struct Marker_Entry {
+	struct Entry_header hdr;
+	u_int reserved;
+	u_char target_lun;
+	u_char target_id;
+	u_char modifier;
+	u_char expanded_lun;
+	u_char rsvds[52];
+};
+
+/* marker entry modifier definitions */
+#define SYNC_DEVICE	0
+#define SYNC_TARGET	1
+#define SYNC_ALL	2
+
+struct Status_Entry {
+	struct Entry_header hdr;
+	u_int handle;
+	u_short scsi_status;
+	u_short completion_status;
+	u_short state_flags;
+	u_short status_flags;
+	u_short res_info_len;
+	u_short req_sense_len;
+	u_int residual;
+	u_char res_info[8];
+	u_char req_sense_data[32];
+};
+
+/* status entry completion status definitions */
+#define CS_COMPLETE			0x0000
+#define CS_DMA_ERROR			0x0002
+#define CS_RESET_OCCURRED		0x0004
+#define CS_ABORTED			0x0005
+#define CS_TIMEOUT			0x0006
+#define CS_DATA_OVERRUN			0x0007
+#define CS_DATA_UNDERRUN		0x0015
+#define CS_QUEUE_FULL			0x001c
+#define CS_PORT_UNAVAILABLE             0x0028
+#define CS_PORT_LOGGED_OUT              0x0029
+#define CS_PORT_CONFIG_CHANGED		0x002a
+
+/* status entry state flag definitions */
+#define SF_SENT_CDB			0x0400
+#define SF_TRANSFERRED_DATA		0x0800
+#define SF_GOT_STATUS			0x1000
+
+/* status entry status flag definitions */
+#define STF_BUS_RESET			0x0008
+#define STF_DEVICE_RESET		0x0010
+#define STF_ABORTED			0x0020
+#define STF_TIMEOUT			0x0040
+
+/* interrupt control commands */
+#define ISP_EN_INT			0x8000
+#define ISP_EN_RISC			0x0008
+
+/* host control commands */
+#define HCCR_NOP			0x0000
+#define HCCR_RESET			0x1000
+#define HCCR_PAUSE			0x2000
+#define HCCR_RELEASE			0x3000
+#define HCCR_SINGLE_STEP		0x4000
+#define HCCR_SET_HOST_INTR		0x5000
+#define HCCR_CLEAR_HOST_INTR		0x6000
+#define HCCR_CLEAR_RISC_INTR		0x7000
+#define HCCR_BP_ENABLE			0x8000
+#define HCCR_BIOS_DISABLE		0x9000
+#define HCCR_TEST_MODE			0xf000
+
+#define RISC_BUSY			0x0004
+
+/* mailbox commands */
+#define MBOX_NO_OP			0x0000
+#define MBOX_LOAD_RAM			0x0001
+#define MBOX_EXEC_FIRMWARE		0x0002
+#define MBOX_DUMP_RAM			0x0003
+#define MBOX_WRITE_RAM_WORD		0x0004
+#define MBOX_READ_RAM_WORD		0x0005
+#define MBOX_MAILBOX_REG_TEST		0x0006
+#define MBOX_VERIFY_CHECKSUM		0x0007
+#define MBOX_ABOUT_FIRMWARE		0x0008
+#define MBOX_LOAD_RISC_RAM              0x0009
+#define MBOX_DUMP_RISC_RAM              0x000a
+#define MBOX_CHECK_FIRMWARE		0x000e
+#define MBOX_INIT_REQ_QUEUE		0x0010
+#define MBOX_INIT_RES_QUEUE		0x0011
+#define MBOX_EXECUTE_IOCB		0x0012
+#define MBOX_WAKE_UP			0x0013
+#define MBOX_STOP_FIRMWARE		0x0014
+#define MBOX_ABORT_IOCB			0x0015
+#define MBOX_ABORT_DEVICE		0x0016
+#define MBOX_ABORT_TARGET		0x0017
+#define MBOX_BUS_RESET			0x0018
+#define MBOX_STOP_QUEUE			0x0019
+#define MBOX_START_QUEUE		0x001a
+#define MBOX_SINGLE_STEP_QUEUE		0x001b
+#define MBOX_ABORT_QUEUE		0x001c
+#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
+#define MBOX_GET_FIRMWARE_STATUS	0x001f
+#define MBOX_GET_INIT_SCSI_ID		0x0020
+#define MBOX_GET_RETRY_COUNT		0x0022
+#define MBOX_GET_TARGET_PARAMS		0x0028
+#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
+#define MBOX_SET_RETRY_COUNT		0x0032
+#define MBOX_SET_TARGET_PARAMS		0x0038
+#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
+#define MBOX_EXECUTE_IOCB64             0x0054
+#define MBOX_INIT_FIRMWARE              0x0060
+#define MBOX_GET_INIT_CB                0x0061
+#define MBOX_INIT_LIP			0x0062
+#define MBOX_GET_POS_MAP                0x0063
+#define MBOX_GET_PORT_DB                0x0064
+#define MBOX_CLEAR_ACA                  0x0065
+#define MBOX_TARGET_RESET               0x0066
+#define MBOX_CLEAR_TASK_SET             0x0067
+#define MBOX_ABORT_TASK_SET             0x0068
+#define MBOX_GET_FIRMWARE_STATE         0x0069
+#define MBOX_GET_PORT_NAME              0x006a
+#define MBOX_SEND_SNS                   0x006e
+#define MBOX_PORT_LOGIN                 0x006f
+#define MBOX_SEND_CHANGE_REQUEST        0x0070
+#define MBOX_PORT_LOGOUT                0x0071
+
+/*
+ *	Firmware if needed (note this is a hack, it belongs in a separate
+ *	module.
+ */
+ 
+#ifdef CONFIG_SCSI_QLOGIC_FC_FIRMWARE
+#include "qlogicfc_asm.c"
+#else
+static unsigned short risc_code_addr01 = 0x1000 ;
+#endif
+
+/* Each element in mbox_param is an 8 bit bitmap where each bit indicates
+   if that mbox should be copied as input.  For example 0x2 would mean
+   only copy mbox1. */
+
+static const u_char mbox_param[] =
+{
+	0x01,			/* MBOX_NO_OP */
+	0x1f,			/* MBOX_LOAD_RAM */
+	0x03,			/* MBOX_EXEC_FIRMWARE */
+	0x1f,			/* MBOX_DUMP_RAM */
+	0x07,			/* MBOX_WRITE_RAM_WORD */
+	0x03,			/* MBOX_READ_RAM_WORD */
+	0xff,			/* MBOX_MAILBOX_REG_TEST */
+	0x03,			/* MBOX_VERIFY_CHECKSUM */
+	0x01,			/* MBOX_ABOUT_FIRMWARE */
+	0xff,			/* MBOX_LOAD_RISC_RAM */
+	0xff,			/* MBOX_DUMP_RISC_RAM */
+	0x00,			/* 0x000b */
+	0x00,			/* 0x000c */
+	0x00,			/* 0x000d */
+	0x01,			/* MBOX_CHECK_FIRMWARE */
+	0x00,			/* 0x000f */
+	0x1f,			/* MBOX_INIT_REQ_QUEUE */
+	0x2f,			/* MBOX_INIT_RES_QUEUE */
+	0x0f,			/* MBOX_EXECUTE_IOCB */
+	0x03,			/* MBOX_WAKE_UP */
+	0x01,			/* MBOX_STOP_FIRMWARE */
+	0x0f,			/* MBOX_ABORT_IOCB */
+	0x03,			/* MBOX_ABORT_DEVICE */
+	0x07,			/* MBOX_ABORT_TARGET */
+	0x03,			/* MBOX_BUS_RESET */
+	0x03,			/* MBOX_STOP_QUEUE */
+	0x03,			/* MBOX_START_QUEUE */
+	0x03,			/* MBOX_SINGLE_STEP_QUEUE */
+	0x03,			/* MBOX_ABORT_QUEUE */
+	0x03,			/* MBOX_GET_DEV_QUEUE_STATUS */
+	0x00,			/* 0x001e */
+	0x01,			/* MBOX_GET_FIRMWARE_STATUS */
+	0x01,			/* MBOX_GET_INIT_SCSI_ID */
+	0x00,			/* 0x0021 */
+	0x01,			/* MBOX_GET_RETRY_COUNT */
+	0x00,			/* 0x0023 */
+	0x00,			/* 0x0024 */
+	0x00,			/* 0x0025 */
+	0x00,			/* 0x0026 */
+	0x00,			/* 0x0027 */
+	0x03,			/* MBOX_GET_TARGET_PARAMS */
+	0x03,			/* MBOX_GET_DEV_QUEUE_PARAMS */
+	0x00,			/* 0x002a */
+	0x00,			/* 0x002b */
+	0x00,			/* 0x002c */
+	0x00,			/* 0x002d */
+	0x00,			/* 0x002e */
+	0x00,			/* 0x002f */
+	0x00,			/* 0x0030 */
+	0x00,			/* 0x0031 */
+	0x07,			/* MBOX_SET_RETRY_COUNT */
+	0x00,			/* 0x0033 */
+	0x00,			/* 0x0034 */
+	0x00,			/* 0x0035 */
+	0x00,			/* 0x0036 */
+	0x00,			/* 0x0037 */
+	0x0f,			/* MBOX_SET_TARGET_PARAMS */
+	0x0f,			/* MBOX_SET_DEV_QUEUE_PARAMS */
+	0x00,			/* 0x003a */
+	0x00,			/* 0x003b */
+	0x00,			/* 0x003c */
+	0x00,			/* 0x003d */
+	0x00,			/* 0x003e */
+	0x00,			/* 0x003f */
+	0x00,			/* 0x0040 */
+	0x00,			/* 0x0041 */
+	0x00,			/* 0x0042 */
+	0x00,			/* 0x0043 */
+	0x00,			/* 0x0044 */
+	0x00,			/* 0x0045 */
+	0x00,			/* 0x0046 */
+	0x00,			/* 0x0047 */
+	0x00,			/* 0x0048 */
+	0x00,			/* 0x0049 */
+	0x00,			/* 0x004a */
+	0x00,			/* 0x004b */
+	0x00,			/* 0x004c */
+	0x00,			/* 0x004d */
+	0x00,			/* 0x004e */
+	0x00,			/* 0x004f */
+	0x00,			/* 0x0050 */
+	0x00,			/* 0x0051 */
+	0x00,			/* 0x0052 */
+	0x00,			/* 0x0053 */
+	0xcf,			/* MBOX_EXECUTE_IOCB64 */
+	0x00,			/* 0x0055 */
+	0x00,			/* 0x0056 */
+	0x00,			/* 0x0057 */
+	0x00,			/* 0x0058 */
+	0x00,			/* 0x0059 */
+	0x00,			/* 0x005a */
+	0x00,			/* 0x005b */
+	0x00,			/* 0x005c */
+	0x00,			/* 0x005d */
+	0x00,			/* 0x005e */
+	0x00,			/* 0x005f */
+	0xff,			/* MBOX_INIT_FIRMWARE */
+	0xcd,			/* MBOX_GET_INIT_CB */
+	0x01,			/* MBOX_INIT_LIP */
+	0xcd,			/* MBOX_GET_POS_MAP */
+	0xcf,			/* MBOX_GET_PORT_DB */
+	0x03,			/* MBOX_CLEAR_ACA */
+	0x03,			/* MBOX_TARGET_RESET */
+	0x03,			/* MBOX_CLEAR_TASK_SET */
+	0x03,			/* MBOX_ABORT_TASK_SET */
+	0x01,			/* MBOX_GET_FIRMWARE_STATE */
+	0x03,			/* MBOX_GET_PORT_NAME */
+	0x00,			/* 0x006b */
+	0x00,			/* 0x006c */
+	0x00,			/* 0x006d */
+	0xcf,			/* MBOX_SEND_SNS */
+	0x0f,			/* MBOX_PORT_LOGIN */
+	0x03,			/* MBOX_SEND_CHANGE_REQUEST */
+	0x03,			/* MBOX_PORT_LOGOUT */
+};
+
+#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
+
+
+struct id_name_map {
+	u64 wwn;
+	u_char loop_id;
+};
+
+struct sns_cb {
+	u_short len;
+	u_short res1;
+	u_int response_low;
+	u_int response_high;
+	u_short sub_len;
+	u_short res2;
+	u_char data[44];
+};
+
+/* address of instance of this struct is passed to adapter to initialize things
+ */
+struct init_cb {
+	u_char version;
+	u_char reseverd1[1];
+	u_short firm_opts;
+	u_short max_frame_len;
+	u_short max_iocb;
+	u_short exec_throttle;
+	u_char retry_cnt;
+	u_char retry_delay;
+	u_short node_name[4];
+	u_short hard_addr;
+	u_char reserved2[10];
+	u_short req_queue_out;
+	u_short res_queue_in;
+	u_short req_queue_len;
+	u_short res_queue_len;
+	u_int req_queue_addr_lo;
+	u_int req_queue_addr_high;
+	u_int res_queue_addr_lo;
+	u_int res_queue_addr_high;
+        /* the rest of this structure only applies to the isp2200 */
+        u_short lun_enables;
+        u_char cmd_resource_cnt;
+        u_char notify_resource_cnt;
+        u_short timeout;
+        u_short reserved3;
+        u_short add_firm_opts;
+        u_char res_accum_timer;
+        u_char irq_delay_timer;
+        u_short special_options;
+        u_short reserved4[13];
+};
+
+/*
+ * The result queue can be quite a bit smaller since continuation entries
+ * do not show up there:
+ */
+#define RES_QUEUE_LEN		((QLOGICFC_REQ_QUEUE_LEN + 1) / 8 - 1)
+#define QUEUE_ENTRY_LEN		64
+
+#if ISP2x00_FABRIC
+#define QLOGICFC_MAX_ID    0xff
+#else
+#define QLOGICFC_MAX_ID    0x7d
+#endif
+
+#define QLOGICFC_MAX_LUN	128
+#define QLOGICFC_MAX_LOOP_ID	0x7d
+
+/* the following connection options only apply to the 2200.  i have only
+ * had success with LOOP_ONLY and P2P_ONLY.
+ */
+
+#define LOOP_ONLY              0
+#define P2P_ONLY               1
+#define LOOP_PREFERED          2
+#define P2P_PREFERED           3
+
+#define CONNECTION_PREFERENCE  LOOP_ONLY
+
+/* adapter_state values */
+#define AS_FIRMWARE_DEAD      -1
+#define AS_LOOP_DOWN           0
+#define AS_LOOP_GOOD           1
+#define AS_REDO_FABRIC_PORTDB  2
+#define AS_REDO_LOOP_PORTDB    4
+
+#define RES_SIZE	((RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)
+#define REQ_SIZE	((QLOGICFC_REQ_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN)
+
+struct isp2x00_hostdata {
+	u_char revision;
+	struct pci_dev *pci_dev;
+	/* result and request queues (shared with isp2x00): */
+	u_int req_in_ptr;	/* index of next request slot */
+	u_int res_out_ptr;	/* index of next result slot */
+
+	/* this is here so the queues are nicely aligned */
+	long send_marker;	/* do we need to send a marker? */
+
+	char * res;
+	char * req;
+	struct init_cb control_block;
+	int adapter_state;
+	unsigned long int tag_ages[QLOGICFC_MAX_ID + 1];
+	Scsi_Cmnd *handle_ptrs[QLOGICFC_REQ_QUEUE_LEN + 1];
+	unsigned long handle_serials[QLOGICFC_REQ_QUEUE_LEN + 1];
+	struct id_name_map port_db[QLOGICFC_MAX_ID + 1];
+	u_char mbox_done;
+	u64 wwn;
+	u_int port_id;
+	u_char queued;
+	u_char host_id;
+        struct timer_list explore_timer;
+	struct id_name_map tempmap[QLOGICFC_MAX_ID + 1];
+};
+
+
+/* queue length's _must_ be power of two: */
+#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
+#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
+						    QLOGICFC_REQ_QUEUE_LEN)
+#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
+
+static void isp2x00_enable_irqs(struct Scsi_Host *);
+static void isp2x00_disable_irqs(struct Scsi_Host *);
+static int isp2x00_init(struct Scsi_Host *);
+static int isp2x00_reset_hardware(struct Scsi_Host *);
+static int isp2x00_mbox_command(struct Scsi_Host *, u_short[]);
+static int isp2x00_return_status(Scsi_Cmnd *, struct Status_Entry *);
+static void isp2x00_intr_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_isp2x00_intr_handler(int, void *, struct pt_regs *);
+static int isp2x00_make_portdb(struct Scsi_Host *);
+
+#if ISP2x00_FABRIC
+static int isp2x00_init_fabric(struct Scsi_Host *, struct id_name_map *, int);
+#endif
+
+#if USE_NVRAM_DEFAULTS
+static int isp2x00_get_nvram_defaults(struct Scsi_Host *, struct init_cb *);
+static u_short isp2x00_read_nvram_word(struct Scsi_Host *, u_short);
+#endif
+
+#if DEBUG_ISP2x00
+static void isp2x00_print_scsi_cmd(Scsi_Cmnd *);
+#endif
+
+#if DEBUG_ISP2x00_INTR
+static void isp2x00_print_status_entry(struct Status_Entry *);
+#endif
+
+static inline void isp2x00_enable_irqs(struct Scsi_Host *host)
+{
+	outw(ISP_EN_INT | ISP_EN_RISC, host->io_port + PCI_INTER_CTL);
+}
+
+
+static inline void isp2x00_disable_irqs(struct Scsi_Host *host)
+{
+	outw(0x0, host->io_port + PCI_INTER_CTL);
+}
+
+
+static int isp2x00_detect(Scsi_Host_Template * tmpt)
+{
+	int hosts = 0;
+	unsigned long wait_time;
+	struct Scsi_Host *host = NULL;
+	struct isp2x00_hostdata *hostdata;
+	struct pci_dev *pdev;
+	unsigned short device_ids[2];
+	dma_addr_t busaddr;
+	int i;
+
+
+	ENTER("isp2x00_detect");
+
+       	device_ids[0] = PCI_DEVICE_ID_QLOGIC_ISP2100;
+	device_ids[1] = PCI_DEVICE_ID_QLOGIC_ISP2200;
+
+	tmpt->proc_name = "isp2x00";
+
+	for (i=0; i<2; i++){
+		pdev = NULL;
+	        while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, device_ids[i], pdev))) {
+			if (pci_enable_device(pdev))
+				continue;
+
+			/* Try to configure DMA attributes. */
+			if (pci_set_dma_mask(pdev, 0xffffffffffffffffULL) &&
+			    pci_set_dma_mask(pdev, 0xffffffffULL))
+					continue;
+
+		        host = scsi_register(tmpt, sizeof(struct isp2x00_hostdata));
+			if (!host) {
+			        printk("qlogicfc%d : could not register host.\n", hosts);
+				continue;
+			}
+ 			scsi_set_device(host, &pdev->dev);
+			host->max_id = QLOGICFC_MAX_ID + 1;
+			host->max_lun = QLOGICFC_MAX_LUN;
+			hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+			memset(hostdata, 0, sizeof(struct isp2x00_hostdata));
+			hostdata->pci_dev = pdev;
+			hostdata->res = pci_alloc_consistent(pdev, RES_SIZE + REQ_SIZE, &busaddr);
+
+			if (!hostdata->res){
+			        printk("qlogicfc%d : could not allocate memory for request and response queue.\n", hosts);
+			        scsi_unregister(host);
+				continue;
+			}
+			hostdata->req = hostdata->res + (RES_QUEUE_LEN + 1)*QUEUE_ENTRY_LEN;
+			hostdata->queued = 0;
+			/* set up the control block */
+			hostdata->control_block.version = 0x1;
+			hostdata->control_block.firm_opts = cpu_to_le16(0x800e);
+			hostdata->control_block.max_frame_len = cpu_to_le16(2048);
+			hostdata->control_block.max_iocb = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN);
+			hostdata->control_block.exec_throttle = cpu_to_le16(QLOGICFC_CMD_PER_LUN);
+			hostdata->control_block.retry_delay = 5;
+			hostdata->control_block.retry_cnt = 1;
+			hostdata->control_block.node_name[0] = cpu_to_le16(0x0020);
+			hostdata->control_block.node_name[1] = cpu_to_le16(0xE000);
+			hostdata->control_block.node_name[2] = cpu_to_le16(0x008B);
+			hostdata->control_block.node_name[3] = cpu_to_le16(0x0000);
+			hostdata->control_block.hard_addr = cpu_to_le16(0x0003);
+			hostdata->control_block.req_queue_len = cpu_to_le16(QLOGICFC_REQ_QUEUE_LEN + 1);
+			hostdata->control_block.res_queue_len = cpu_to_le16(RES_QUEUE_LEN + 1);
+			hostdata->control_block.res_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr));
+			hostdata->control_block.res_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr));
+			hostdata->control_block.req_queue_addr_lo = cpu_to_le32(pci64_dma_lo32(busaddr + RES_SIZE));
+			hostdata->control_block.req_queue_addr_high = cpu_to_le32(pci64_dma_hi32(busaddr + RES_SIZE));
+
+
+			hostdata->control_block.add_firm_opts |= cpu_to_le16(CONNECTION_PREFERENCE<<4);
+			hostdata->adapter_state = AS_LOOP_DOWN;
+			hostdata->explore_timer.data = 1;
+			hostdata->host_id = hosts;
+
+			if (isp2x00_init(host) || isp2x00_reset_hardware(host)) {
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+			        scsi_unregister(host);
+				continue;
+			}
+			host->this_id = 0;
+
+			if (request_irq(host->irq, do_isp2x00_intr_handler, SA_INTERRUPT | SA_SHIRQ, "qlogicfc", host)) {
+			        printk("qlogicfc%d : interrupt %d already in use\n",
+				       hostdata->host_id, host->irq);
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				scsi_unregister(host);
+				continue;
+			}
+			if (!request_region(host->io_port, 0xff, "qlogicfc")) {
+			        printk("qlogicfc%d : i/o region 0x%lx-0x%lx already "
+				       "in use\n",
+				       hostdata->host_id, host->io_port, host->io_port + 0xff);
+				free_irq(host->irq, host);
+				pci_free_consistent (pdev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+				scsi_unregister(host);
+				continue;
+			}
+
+			outw(0x0, host->io_port + PCI_SEMAPHORE);
+			outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+			isp2x00_enable_irqs(host);
+			/* wait for the loop to come up */
+			for (wait_time = jiffies + 10 * HZ; time_before(jiffies, wait_time) && hostdata->adapter_state == AS_LOOP_DOWN;) {
+			        barrier();
+				cpu_relax();
+			}
+			if (hostdata->adapter_state == AS_LOOP_DOWN) {
+			        printk("qlogicfc%d : link is not up\n", hostdata->host_id);
+			}
+			hosts++;
+			hostdata->explore_timer.data = 0;
+		}
+	}
+
+
+	/* this busy loop should not be needed but the isp2x00 seems to need 
+	   some time before recognizing it is attached to a fabric */
+
+#if ISP2x00_FABRIC
+	if (hosts) {
+		for (wait_time = jiffies + 5 * HZ; time_before(jiffies, wait_time);) {
+			barrier();
+			cpu_relax();
+		}
+	}
+#endif
+
+	LEAVE("isp2x00_detect");
+
+	return hosts;
+}
+
+
+static int isp2x00_make_portdb(struct Scsi_Host *host)
+{
+
+	short param[8];
+	int i, j;
+	struct isp2x00_hostdata *hostdata;
+
+	isp2x00_disable_irqs(host);
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+	memset(hostdata->tempmap, 0, sizeof(hostdata->tempmap));
+
+#if ISP2x00_FABRIC
+	for (i = 0x81; i < QLOGICFC_MAX_ID; i++) {
+		param[0] = MBOX_PORT_LOGOUT;
+		param[1] = i << 8;
+		param[2] = 0;
+		param[3] = 0;
+
+		isp2x00_mbox_command(host, param);
+
+		if (param[0] != MBOX_COMMAND_COMPLETE) {
+
+			DEBUG_FABRIC(printk("qlogicfc%d : logout failed %x  %x\n", hostdata->host_id, i, param[0]));
+		}
+	}
+#endif
+
+
+	param[0] = MBOX_GET_INIT_SCSI_ID;
+
+	isp2x00_mbox_command(host, param);
+
+	if (param[0] == MBOX_COMMAND_COMPLETE) {
+		hostdata->port_id = ((u_int) param[3]) << 16;
+		hostdata->port_id |= param[2];
+		hostdata->tempmap[0].loop_id = param[1];
+		hostdata->tempmap[0].wwn = hostdata->wwn;
+	}
+	else {
+	        printk("qlogicfc%d : error getting scsi id.\n", hostdata->host_id);
+	}
+
+        for (i = 0; i <=QLOGICFC_MAX_ID; i++)
+                hostdata->tempmap[i].loop_id = hostdata->tempmap[0].loop_id;
+   
+        for (i = 0, j = 1; i <= QLOGICFC_MAX_LOOP_ID; i++) {
+                param[0] = MBOX_GET_PORT_NAME;
+		param[1] = (i << 8) & 0xff00;
+
+		isp2x00_mbox_command(host, param);
+
+		if (param[0] == MBOX_COMMAND_COMPLETE) {
+			hostdata->tempmap[j].loop_id = i;
+			hostdata->tempmap[j].wwn = ((u64) (param[2] & 0xff)) << 56;
+			hostdata->tempmap[j].wwn |= ((u64) ((param[2] >> 8) & 0xff)) << 48;
+			hostdata->tempmap[j].wwn |= ((u64) (param[3] & 0xff)) << 40;
+			hostdata->tempmap[j].wwn |= ((u64) ((param[3] >> 8) & 0xff)) << 32;
+			hostdata->tempmap[j].wwn |= ((u64) (param[6] & 0xff)) << 24;
+			hostdata->tempmap[j].wwn |= ((u64) ((param[6] >> 8) & 0xff)) << 16;
+			hostdata->tempmap[j].wwn |= ((u64) (param[7] & 0xff)) << 8;
+			hostdata->tempmap[j].wwn |= ((u64) ((param[7] >> 8) & 0xff));
+
+			j++;
+
+		}
+	}
+
+
+#if ISP2x00_FABRIC
+	isp2x00_init_fabric(host, hostdata->tempmap, j);
+#endif
+
+	for (i = 0; i <= QLOGICFC_MAX_ID; i++) {
+		if (hostdata->tempmap[i].wwn != hostdata->port_db[i].wwn) {
+			for (j = 0; j <= QLOGICFC_MAX_ID; j++) {
+				if (hostdata->tempmap[j].wwn == hostdata->port_db[i].wwn) {
+					hostdata->port_db[i].loop_id = hostdata->tempmap[j].loop_id;
+					break;
+				}
+			}
+			if (j == QLOGICFC_MAX_ID + 1)
+				hostdata->port_db[i].loop_id = hostdata->tempmap[0].loop_id;
+
+			for (j = 0; j <= QLOGICFC_MAX_ID; j++) {
+				if (hostdata->port_db[j].wwn == hostdata->tempmap[i].wwn || !hostdata->port_db[j].wwn) {
+					break;
+				}
+			}
+			if (j == QLOGICFC_MAX_ID + 1)
+				printk("qlogicfc%d : Too many scsi devices, no more room in port map.\n", hostdata->host_id);
+			if (!hostdata->port_db[j].wwn) {
+				hostdata->port_db[j].loop_id = hostdata->tempmap[i].loop_id;
+				hostdata->port_db[j].wwn = hostdata->tempmap[i].wwn;
+			}
+		} else
+			hostdata->port_db[i].loop_id = hostdata->tempmap[i].loop_id;
+
+	}
+
+	isp2x00_enable_irqs(host);
+
+	return 0;
+}
+
+
+#if ISP2x00_FABRIC
+
+#define FABRIC_PORT          0x7e
+#define FABRIC_CONTROLLER    0x7f
+#define FABRIC_SNS           0x80
+
+int isp2x00_init_fabric(struct Scsi_Host *host, struct id_name_map *port_db, int cur_scsi_id)
+{
+
+	u_short param[8];
+	u64 wwn;
+	int done = 0;
+	u_short loop_id = 0x81;
+	u_short scsi_id = cur_scsi_id;
+	u_int port_id;
+	struct sns_cb *req;
+	u_char *sns_response;
+	dma_addr_t busaddr;
+	struct isp2x00_hostdata *hostdata;
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+	
+	DEBUG_FABRIC(printk("qlogicfc%d : Checking for a fabric.\n", hostdata->host_id));
+	param[0] = MBOX_GET_PORT_NAME;
+	param[1] = (u16)FABRIC_PORT << 8;
+
+	isp2x00_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		DEBUG_FABRIC(printk("qlogicfc%d : fabric check result %x\n", hostdata->host_id, param[0]));
+		return 0;
+	}
+	printk("qlogicfc%d : Fabric found.\n", hostdata->host_id);
+
+	req = (struct sns_cb *)pci_alloc_consistent(hostdata->pci_dev, sizeof(*req) + 608, &busaddr);
+	
+	if (!req){
+		printk("qlogicfc%d : Could not allocate DMA resources for fabric initialization\n", hostdata->host_id);
+		return 0;
+	}
+	sns_response = (u_char *)(req + 1);
+
+	if (hostdata->adapter_state & AS_REDO_LOOP_PORTDB){
+	        memset(req, 0, sizeof(*req));
+	
+		req->len = cpu_to_le16(8);
+		req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req)));
+		req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req)));
+		req->sub_len = cpu_to_le16(22);
+		req->data[0] = 0x17;
+		req->data[1] = 0x02;
+		req->data[8] = (u_char) (hostdata->port_id & 0xff);
+		req->data[9] = (u_char) (hostdata->port_id >> 8 & 0xff);
+		req->data[10] = (u_char) (hostdata->port_id >> 16 & 0xff);
+		req->data[13] = 0x01;
+		param[0] = MBOX_SEND_SNS;
+		param[1] = 30;
+		param[2] = pci64_dma_lo32(busaddr) >> 16;
+		param[3] = pci64_dma_lo32(busaddr);
+		param[6] = pci64_dma_hi32(busaddr) >> 16;
+		param[7] = pci64_dma_hi32(busaddr);
+
+		isp2x00_mbox_command(host, param);
+	
+		if (param[0] != MBOX_COMMAND_COMPLETE)
+		        printk("qlogicfc%d : error sending RFC-4\n", hostdata->host_id);
+	}
+
+	port_id = hostdata->port_id;
+	while (!done) {
+		memset(req, 0, sizeof(*req));
+
+		req->len = cpu_to_le16(304);
+		req->response_low = cpu_to_le32(pci64_dma_lo32(busaddr + sizeof(*req)));
+		req->response_high = cpu_to_le32(pci64_dma_hi32(busaddr + sizeof(*req)));
+		req->sub_len = cpu_to_le16(6);
+		req->data[0] = 0x00;
+		req->data[1] = 0x01;
+		req->data[8] = (u_char) (port_id & 0xff);
+		req->data[9] = (u_char) (port_id >> 8 & 0xff);
+		req->data[10] = (u_char) (port_id >> 16 & 0xff);
+
+		param[0] = MBOX_SEND_SNS;
+		param[1] = 14;
+		param[2] = pci64_dma_lo32(busaddr) >> 16;
+		param[3] = pci64_dma_lo32(busaddr);
+		param[6] = pci64_dma_hi32(busaddr) >> 16;
+		param[7] = pci64_dma_hi32(busaddr);
+
+		isp2x00_mbox_command(host, param);
+
+		if (param[0] == MBOX_COMMAND_COMPLETE) {
+			DEBUG_FABRIC(printk("qlogicfc%d : found node %02x%02x%02x%02x%02x%02x%02x%02x ", hostdata->host_id, sns_response[20], sns_response[21], sns_response[22], sns_response[23], sns_response[24], sns_response[25], sns_response[26], sns_response[27]));
+			DEBUG_FABRIC(printk("  port id: %02x%02x%02x\n", sns_response[17], sns_response[18], sns_response[19]));
+			port_id = ((u_int) sns_response[17]) << 16;
+			port_id |= ((u_int) sns_response[18]) << 8;
+			port_id |= ((u_int) sns_response[19]);
+			wwn = ((u64) sns_response[20]) << 56;
+			wwn |= ((u64) sns_response[21]) << 48;
+			wwn |= ((u64) sns_response[22]) << 40;
+			wwn |= ((u64) sns_response[23]) << 32;
+			wwn |= ((u64) sns_response[24]) << 24;
+			wwn |= ((u64) sns_response[25]) << 16;
+			wwn |= ((u64) sns_response[26]) << 8;
+			wwn |= ((u64) sns_response[27]);
+			if (hostdata->port_id >> 8 != port_id >> 8) {
+				DEBUG_FABRIC(printk("qlogicfc%d : adding a fabric port: %x\n", hostdata->host_id, port_id));
+				param[0] = MBOX_PORT_LOGIN;
+				param[1] = loop_id << 8;
+				param[2] = (u_short) (port_id >> 16);
+				param[3] = (u_short) (port_id);
+
+				isp2x00_mbox_command(host, param);
+
+				if (param[0] == MBOX_COMMAND_COMPLETE) {
+					port_db[scsi_id].wwn = wwn;
+					port_db[scsi_id].loop_id = loop_id;
+					loop_id++;
+					scsi_id++;
+				} else {
+					printk("qlogicfc%d : Error performing port login %x\n", hostdata->host_id, param[0]);
+					DEBUG_FABRIC(printk("qlogicfc%d : loop_id: %x\n", hostdata->host_id, loop_id));
+					param[0] = MBOX_PORT_LOGOUT;
+					param[1] = loop_id << 8;
+					param[2] = 0;
+					param[3] = 0;
+
+					isp2x00_mbox_command(host, param);
+					
+				}
+
+			}
+			if (hostdata->port_id == port_id)
+				done = 1;
+		} else {
+			printk("qlogicfc%d : Get All Next failed %x.\n", hostdata->host_id, param[0]);
+			pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
+			return 0;
+		}
+	}
+
+	pci_free_consistent(hostdata->pci_dev, sizeof(*req) + 608, req, busaddr);
+	return 1;
+}
+
+#endif				/* ISP2x00_FABRIC */
+
+
+static int isp2x00_release(struct Scsi_Host *host)
+{
+	struct isp2x00_hostdata *hostdata;
+	dma_addr_t busaddr;
+
+	ENTER("isp2x00_release");
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+	outw(0x0, host->io_port + PCI_INTER_CTL);
+	free_irq(host->irq, host);
+
+	release_region(host->io_port, 0xff);
+
+	busaddr = pci64_dma_build(le32_to_cpu(hostdata->control_block.res_queue_addr_high),
+				  le32_to_cpu(hostdata->control_block.res_queue_addr_lo));
+	pci_free_consistent(hostdata->pci_dev, RES_SIZE + REQ_SIZE, hostdata->res, busaddr);
+
+	LEAVE("isp2x00_release");
+
+	return 0;
+}
+
+
+static const char *isp2x00_info(struct Scsi_Host *host)
+{
+	static char buf[80];
+	struct isp2x00_hostdata *hostdata;
+	ENTER("isp2x00_info");
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+	sprintf(buf,
+		"QLogic ISP%04x SCSI on PCI bus %02x device %02x irq %d base 0x%lx",
+		hostdata->pci_dev->device, hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
+		host->io_port);
+
+
+	LEAVE("isp2x00_info");
+
+	return buf;
+}
+
+
+/*
+ * The middle SCSI layer ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (though the
+ * interrupt handler may call this routine as part of
+ * request-completion handling).
+ */
+static int isp2x00_queuecommand(Scsi_Cmnd * Cmnd, void (*done) (Scsi_Cmnd *))
+{
+	int i, sg_count, n, num_free;
+	u_int in_ptr, out_ptr;
+	struct dataseg *ds;
+	struct scatterlist *sg;
+	struct Command_Entry *cmd;
+	struct Continuation_Entry *cont;
+	struct Scsi_Host *host;
+	struct isp2x00_hostdata *hostdata;
+
+	ENTER("isp2x00_queuecommand");
+
+	host = Cmnd->device->host;
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+	Cmnd->scsi_done = done;
+
+	DEBUG(isp2x00_print_scsi_cmd(Cmnd));
+
+	if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) {
+		isp2x00_make_portdb(host);
+		hostdata->adapter_state = AS_LOOP_GOOD;
+		printk("qlogicfc%d : Port Database\n", hostdata->host_id);
+		for (i = 0; hostdata->port_db[i].wwn != 0; i++) {
+			printk("wwn: %08x%08x  scsi_id: %x  loop_id: ", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i);
+			if (hostdata->port_db[i].loop_id != hostdata->port_db[0].loop_id || i == 0)
+			        printk("%x", hostdata->port_db[i].loop_id);
+			else
+			        printk("Not Available");
+			printk("\n");
+		}
+	}
+	if (hostdata->adapter_state == AS_FIRMWARE_DEAD) {
+		printk("qlogicfc%d : The firmware is dead, just return.\n", hostdata->host_id);
+		host->max_id = 0;
+		return 0;
+	}
+
+	out_ptr = inw(host->io_port + MBOX4);
+	in_ptr = hostdata->req_in_ptr;
+
+	DEBUG(printk("qlogicfc%d : request queue depth %d\n", hostdata->host_id,
+		     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
+
+	cmd = (struct Command_Entry *) &hostdata->req[in_ptr*QUEUE_ENTRY_LEN];
+	in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
+	if (in_ptr == out_ptr) {
+		DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
+		return 1;
+	}
+	if (hostdata->send_marker) {
+		struct Marker_Entry *marker;
+
+		TRACE("queue marker", in_ptr, 0);
+
+		DEBUG(printk("qlogicfc%d : adding marker entry\n", hostdata->host_id));
+		marker = (struct Marker_Entry *) cmd;
+		memset(marker, 0, sizeof(struct Marker_Entry));
+
+		marker->hdr.entry_type = ENTRY_MARKER;
+		marker->hdr.entry_cnt = 1;
+		marker->modifier = SYNC_ALL;
+
+		hostdata->send_marker = 0;
+
+		if (((in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN) == out_ptr) {
+			outw(in_ptr, host->io_port + MBOX4);
+			hostdata->req_in_ptr = in_ptr;
+			DEBUG(printk("qlogicfc%d : request queue overflow\n", hostdata->host_id));
+			return 1;
+		}
+		cmd = (struct Command_Entry *) &hostdata->req[in_ptr*QUEUE_ENTRY_LEN];
+		in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
+	}
+	TRACE("queue command", in_ptr, Cmnd);
+
+	memset(cmd, 0, sizeof(struct Command_Entry));
+
+	/* find a free handle mapping slot */
+	for (i = in_ptr; i != (in_ptr - 1) && hostdata->handle_ptrs[i]; i = ((i + 1) % (QLOGICFC_REQ_QUEUE_LEN + 1)));
+
+	if (!hostdata->handle_ptrs[i]) {
+		cmd->handle = cpu_to_le32(i);
+		hostdata->handle_ptrs[i] = Cmnd;
+		hostdata->handle_serials[i] = Cmnd->serial_number;
+	} else {
+		printk("qlogicfc%d : no handle slots, this should not happen.\n", hostdata->host_id);
+		printk("hostdata->queued is %x, in_ptr: %x\n", hostdata->queued, in_ptr);
+		for (i = 0; i <= QLOGICFC_REQ_QUEUE_LEN; i++){
+			if (!hostdata->handle_ptrs[i]){
+				printk("slot %d has %p\n", i, hostdata->handle_ptrs[i]);
+			}
+		}
+		return 1;
+	}
+
+	cmd->hdr.entry_type = ENTRY_COMMAND;
+	cmd->hdr.entry_cnt = 1;
+	cmd->target_lun = Cmnd->device->lun;
+	cmd->expanded_lun = cpu_to_le16(Cmnd->device->lun);
+#if ISP2x00_PORTDB
+	cmd->target_id = hostdata->port_db[Cmnd->device->id].loop_id;
+#else
+	cmd->target_id = Cmnd->target;
+#endif
+	cmd->total_byte_cnt = cpu_to_le32(Cmnd->request_bufflen);
+	cmd->time_out = 0;
+	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
+
+	if (Cmnd->use_sg) {
+		sg = (struct scatterlist *) Cmnd->request_buffer;
+		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg, scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		cmd->segment_cnt = cpu_to_le16(sg_count);
+		ds = cmd->dataseg;
+		/* fill in first two sg entries: */
+		n = sg_count;
+		if (n > DATASEGS_PER_COMMAND)
+			n = DATASEGS_PER_COMMAND;
+
+		for (i = 0; i < n; i++) {
+			ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg)));
+			ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg)));
+			ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
+			++sg;
+		}
+		sg_count -= DATASEGS_PER_COMMAND;
+
+		while (sg_count > 0) {
+			++cmd->hdr.entry_cnt;
+			cont = (struct Continuation_Entry *)
+			    &hostdata->req[in_ptr*QUEUE_ENTRY_LEN];
+			memset(cont, 0, sizeof(struct Continuation_Entry));
+			in_ptr = (in_ptr + 1) & QLOGICFC_REQ_QUEUE_LEN;
+			if (in_ptr == out_ptr) {
+				DEBUG(printk("qlogicfc%d : unexpected request queue overflow\n", hostdata->host_id));
+				return 1;
+			}
+			TRACE("queue continuation", in_ptr, 0);
+			cont->hdr.entry_type = ENTRY_CONTINUATION;
+			ds = cont->dataseg;
+			n = sg_count;
+			if (n > DATASEGS_PER_CONT)
+				n = DATASEGS_PER_CONT;
+			for (i = 0; i < n; ++i) {
+				ds[i].d_base = cpu_to_le32(pci64_dma_lo32(sg_dma_address(sg)));
+				ds[i].d_base_hi = cpu_to_le32(pci64_dma_hi32(sg_dma_address(sg)));
+				ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
+				++sg;
+			}
+			sg_count -= n;
+		}
+	} else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE) {
+		struct page *page = virt_to_page(Cmnd->request_buffer);
+		unsigned long offset = offset_in_page(Cmnd->request_buffer);
+		dma_addr_t busaddr = pci_map_page(hostdata->pci_dev,
+						  page, offset,
+						  Cmnd->request_bufflen,
+						  scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		Cmnd->SCp.dma_handle = busaddr;
+
+		cmd->dataseg[0].d_base = cpu_to_le32(pci64_dma_lo32(busaddr));
+		cmd->dataseg[0].d_base_hi = cpu_to_le32(pci64_dma_hi32(busaddr));
+		cmd->dataseg[0].d_count = cpu_to_le32(Cmnd->request_bufflen);
+		cmd->segment_cnt = cpu_to_le16(1);
+	} else {
+		cmd->dataseg[0].d_base = 0;
+		cmd->dataseg[0].d_base_hi = 0;
+		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
+	}
+
+	if (Cmnd->sc_data_direction == SCSI_DATA_WRITE)
+		cmd->control_flags = cpu_to_le16(CFLAG_WRITE);
+	else 
+		cmd->control_flags = cpu_to_le16(CFLAG_READ);
+
+	if (Cmnd->device->tagged_supported) {
+		if ((jiffies - hostdata->tag_ages[Cmnd->device->id]) > (2 * ISP_TIMEOUT)) {
+			cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
+			hostdata->tag_ages[Cmnd->device->id] = jiffies;
+		} else
+			switch (Cmnd->tag) {
+			case HEAD_OF_QUEUE_TAG:
+				cmd->control_flags |= cpu_to_le16(CFLAG_HEAD_TAG);
+				break;
+			case ORDERED_QUEUE_TAG:
+				cmd->control_flags |= cpu_to_le16(CFLAG_ORDERED_TAG);
+				break;
+			default:
+				cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG);
+				break;
+		}
+	}
+	/*
+	 * TEST_UNIT_READY commands from scsi_scan will fail due to "overlapped
+	 * commands attempted" unless we setup at least a simple queue (midlayer 
+	 * will embelish this once it can do an INQUIRY command to the device)
+	 */
+	else
+		cmd->control_flags |= cpu_to_le16(CFLAG_SIMPLE_TAG);
+	outw(in_ptr, host->io_port + MBOX4);
+	hostdata->req_in_ptr = in_ptr;
+
+	hostdata->queued++;
+
+	num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+	num_free = (num_free > 2) ? num_free - 2 : 0;
+       host->can_queue = host->host_busy + num_free;
+	if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN)
+		host->can_queue = QLOGICFC_REQ_QUEUE_LEN;
+	host->sg_tablesize = QLOGICFC_MAX_SG(num_free);
+
+	LEAVE("isp2x00_queuecommand");
+
+	return 0;
+}
+
+
+/* we have received an event, such as a lip or an RSCN, which may mean that
+ * our port database is incorrect so the port database must be recreated.
+ */
+static void redo_port_db(unsigned long arg)
+{
+
+        struct Scsi_Host * host = (struct Scsi_Host *) arg;
+	struct isp2x00_hostdata * hostdata;
+	unsigned long flags;
+	int i;
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+	hostdata->explore_timer.data = 0;
+	del_timer(&hostdata->explore_timer);
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	if (hostdata->adapter_state & AS_REDO_FABRIC_PORTDB || hostdata->adapter_state & AS_REDO_LOOP_PORTDB) {
+		isp2x00_make_portdb(host);
+		printk("qlogicfc%d : Port Database\n", hostdata->host_id);
+		for (i = 0; hostdata->port_db[i].wwn != 0; i++) {
+			printk("wwn: %08x%08x  scsi_id: %x  loop_id: ", (u_int) (hostdata->port_db[i].wwn >> 32), (u_int) hostdata->port_db[i].wwn, i);
+			if (hostdata->port_db[i].loop_id != hostdata->port_db[0].loop_id || i == 0)
+			        printk("%x", hostdata->port_db[i].loop_id);
+			else
+			        printk("Not Available");
+			printk("\n");
+		}
+		
+	        for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++){ 
+		        if (hostdata->handle_ptrs[i] && (hostdata->port_db[hostdata->handle_ptrs[i]->device->id].loop_id > QLOGICFC_MAX_LOOP_ID || hostdata->adapter_state & AS_REDO_LOOP_PORTDB)){
+                                if (hostdata->port_db[hostdata->handle_ptrs[i]->device->id].loop_id != hostdata->port_db[0].loop_id){
+					Scsi_Cmnd *Cmnd = hostdata->handle_ptrs[i];
+
+					 if (Cmnd->use_sg)
+						 pci_unmap_sg(hostdata->pci_dev,
+							      (struct scatterlist *)Cmnd->buffer,
+							      Cmnd->use_sg,
+							      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					 else if (Cmnd->request_bufflen &&
+						  Cmnd->sc_data_direction != PCI_DMA_NONE) {
+						 pci_unmap_page(hostdata->pci_dev,
+								Cmnd->SCp.dma_handle,
+								Cmnd->request_bufflen,
+								scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+					 }
+
+					 hostdata->handle_ptrs[i]->result = DID_SOFT_ERROR << 16;
+
+					 if (hostdata->handle_ptrs[i]->scsi_done){
+					   (*hostdata->handle_ptrs[i]->scsi_done) (hostdata->handle_ptrs[i]);
+					 }
+					 else printk("qlogicfc%d : done is null?\n", hostdata->host_id);
+					 hostdata->handle_ptrs[i] = NULL;
+					 hostdata->handle_serials[i] = 0;
+				}
+			}
+		}
+		
+		hostdata->adapter_state = AS_LOOP_GOOD;
+	}
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+}
+
+#define ASYNC_EVENT_INTERRUPT	0x01
+
+irqreturn_t do_isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *host = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	isp2x00_intr_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void isp2x00_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	Scsi_Cmnd *Cmnd;
+	struct Status_Entry *sts;
+	struct Scsi_Host *host = dev_id;
+	struct isp2x00_hostdata *hostdata;
+	u_int in_ptr, out_ptr, handle, num_free;
+	u_short status;
+
+	ENTER_INTR("isp2x00_intr_handler");
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+	DEBUG_INTR(printk("qlogicfc%d : interrupt on line %d\n", hostdata->host_id, irq));
+
+	if (!(inw(host->io_port + PCI_INTER_STS) & 0x08)) {
+		/* spurious interrupts can happen legally */
+		DEBUG_INTR(printk("qlogicfc%d : got spurious interrupt\n", hostdata->host_id));
+		return;
+	}
+	in_ptr = inw(host->io_port + MBOX5);
+	out_ptr = hostdata->res_out_ptr;
+
+	if ((inw(host->io_port + PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
+		status = inw(host->io_port + MBOX0);
+
+		DEBUG_INTR(printk("qlogicfc%d : mbox completion status: %x\n",
+				  hostdata->host_id, status));
+
+		switch (status) {
+		case LOOP_UP:
+		case POINT_TO_POINT_UP:
+		        printk("qlogicfc%d : Link is Up\n", hostdata->host_id);
+			hostdata->adapter_state = AS_REDO_FABRIC_PORTDB | AS_REDO_LOOP_PORTDB;
+			break;
+		case LOOP_DOWN:
+		        printk("qlogicfc%d : Link is Down\n", hostdata->host_id);
+			hostdata->adapter_state = AS_LOOP_DOWN;
+			break;
+		case CONNECTION_MODE:
+		        printk("received CONNECTION_MODE irq %x\n", inw(host->io_port + MBOX1));
+			break;
+		case CHANGE_NOTIFICATION:
+		        printk("qlogicfc%d : RSCN Received\n", hostdata->host_id);
+			if (hostdata->adapter_state == AS_LOOP_GOOD)
+				hostdata->adapter_state = AS_REDO_FABRIC_PORTDB;
+			break;		        
+		case LIP_OCCURRED:
+		case LIP_RECEIVED:
+		        printk("qlogicfc%d : Loop Reinitialized\n", hostdata->host_id);
+			if (hostdata->adapter_state == AS_LOOP_GOOD)
+				hostdata->adapter_state = AS_REDO_LOOP_PORTDB;
+			break;
+		case SYSTEM_ERROR:
+			printk("qlogicfc%d : The firmware just choked.\n", hostdata->host_id);
+			hostdata->adapter_state = AS_FIRMWARE_DEAD;
+			break;
+		case SCSI_COMMAND_COMPLETE:
+			handle = inw(host->io_port + MBOX1) | (inw(host->io_port + MBOX2) << 16);
+			Cmnd = hostdata->handle_ptrs[handle];
+			hostdata->handle_ptrs[handle] = NULL;
+			hostdata->handle_serials[handle] = 0;
+			hostdata->queued--;
+			if (Cmnd != NULL) {
+				if (Cmnd->use_sg)
+					pci_unmap_sg(hostdata->pci_dev,
+						     (struct scatterlist *)Cmnd->buffer,
+						     Cmnd->use_sg,
+						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				else if (Cmnd->request_bufflen &&
+					 Cmnd->sc_data_direction != PCI_DMA_NONE)
+					pci_unmap_page(hostdata->pci_dev,
+						       Cmnd->SCp.dma_handle,
+						       Cmnd->request_bufflen,
+						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				Cmnd->result = 0x0;
+				(*Cmnd->scsi_done) (Cmnd);
+			} else
+				printk("qlogicfc%d.c : got a null value out of handle_ptrs, this sucks\n", hostdata->host_id);
+			break;
+		case MBOX_COMMAND_COMPLETE:
+		case INVALID_COMMAND:
+		case HOST_INTERFACE_ERROR:
+		case TEST_FAILED:
+		case COMMAND_ERROR:
+		case COMMAND_PARAM_ERROR:
+		case PORT_ID_USED:
+		case LOOP_ID_USED:
+		case ALL_IDS_USED:
+			hostdata->mbox_done = 1;
+			outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+			return;
+		default:
+			printk("qlogicfc%d : got an unknown status? %x\n", hostdata->host_id, status);
+		}
+		if ((hostdata->adapter_state & AS_REDO_LOOP_PORTDB || hostdata->adapter_state & AS_REDO_FABRIC_PORTDB) && hostdata->explore_timer.data == 0){
+                        hostdata->explore_timer.function = redo_port_db;
+			hostdata->explore_timer.data = (unsigned long)host;
+			hostdata->explore_timer.expires = jiffies + (HZ/4);
+			init_timer(&hostdata->explore_timer);
+			add_timer(&hostdata->explore_timer);
+		}
+		outw(0x0, host->io_port + PCI_SEMAPHORE);
+	} else {
+		DEBUG_INTR(printk("qlogicfc%d : response queue update\n", hostdata->host_id));
+		DEBUG_INTR(printk("qlogicfc%d : response queue depth %d\n", hostdata->host_id, RES_QUEUE_DEPTH(in_ptr, out_ptr)));
+
+		while (out_ptr != in_ptr) {
+			unsigned le_hand;
+			sts = (struct Status_Entry *) &hostdata->res[out_ptr*QUEUE_ENTRY_LEN];
+			out_ptr = (out_ptr + 1) & RES_QUEUE_LEN;
+                 
+			TRACE("done", out_ptr, Cmnd);
+			DEBUG_INTR(isp2x00_print_status_entry(sts));
+			le_hand = le32_to_cpu(sts->handle);
+			if (sts->hdr.entry_type == ENTRY_STATUS && (Cmnd = hostdata->handle_ptrs[le_hand])) {
+				Cmnd->result = isp2x00_return_status(Cmnd, sts);
+				hostdata->queued--;
+
+				if (Cmnd->use_sg)
+					pci_unmap_sg(hostdata->pci_dev,
+						     (struct scatterlist *)Cmnd->buffer, Cmnd->use_sg,
+						     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+				else if (Cmnd->request_bufflen && Cmnd->sc_data_direction != PCI_DMA_NONE)
+					pci_unmap_page(hostdata->pci_dev,
+						       Cmnd->SCp.dma_handle,
+						       Cmnd->request_bufflen,
+						       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+				/* 
+				 * if any of the following are true we do not
+				 * call scsi_done.  if the status is CS_ABORTED
+				 * we don't have to call done because the upper
+				 * level should already know its aborted.
+				 */
+				if (hostdata->handle_serials[le_hand] != Cmnd->serial_number 
+				    || le16_to_cpu(sts->completion_status) == CS_ABORTED){
+					hostdata->handle_serials[le_hand] = 0;
+					hostdata->handle_ptrs[le_hand] = NULL;
+					outw(out_ptr, host->io_port + MBOX5);
+					continue;
+				}
+				/*
+				 * if we get back an error indicating the port
+				 * is not there or if the link is down and 
+				 * this is a device that used to be there 
+				 * allow the command to timeout.
+				 * the device may well be back in a couple of
+				 * seconds.
+				 */
+				if ((hostdata->adapter_state == AS_LOOP_DOWN || sts->completion_status == cpu_to_le16(CS_PORT_UNAVAILABLE) || sts->completion_status == cpu_to_le16(CS_PORT_LOGGED_OUT) || sts->completion_status == cpu_to_le16(CS_PORT_CONFIG_CHANGED)) && hostdata->port_db[Cmnd->device->id].wwn){
+					outw(out_ptr, host->io_port + MBOX5);
+					continue;
+				}
+			} else {
+				outw(out_ptr, host->io_port + MBOX5);
+				continue;
+			}
+
+			hostdata->handle_ptrs[le_hand] = NULL;
+
+			if (sts->completion_status == cpu_to_le16(CS_RESET_OCCURRED)
+			    || (sts->status_flags & cpu_to_le16(STF_BUS_RESET)))
+				hostdata->send_marker = 1;
+
+			if (le16_to_cpu(sts->scsi_status) & 0x0200)
+				memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+				       sizeof(Cmnd->sense_buffer));
+
+			outw(out_ptr, host->io_port + MBOX5);
+
+			if (Cmnd->scsi_done != NULL) {
+				(*Cmnd->scsi_done) (Cmnd);
+			} else
+				printk("qlogicfc%d : Ouch, scsi done is NULL\n", hostdata->host_id);
+		}
+		hostdata->res_out_ptr = out_ptr;
+	}
+
+
+	out_ptr = inw(host->io_port + MBOX4);
+	in_ptr = hostdata->req_in_ptr;
+
+	num_free = QLOGICFC_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+	num_free = (num_free > 2) ? num_free - 2 : 0;
+       host->can_queue = host->host_busy + num_free;
+	if (host->can_queue > QLOGICFC_REQ_QUEUE_LEN)
+		host->can_queue = QLOGICFC_REQ_QUEUE_LEN;
+	host->sg_tablesize = QLOGICFC_MAX_SG(num_free);
+
+	outw(HCCR_CLEAR_RISC_INTR, host->io_port + HOST_HCCR);
+	LEAVE_INTR("isp2x00_intr_handler");
+}
+
+
+static int isp2x00_return_status(Scsi_Cmnd *Cmnd, struct Status_Entry *sts)
+{
+	int host_status = DID_ERROR;
+#if DEBUG_ISP2x00_INTR
+	static char *reason[] =
+	{
+		"DID_OK",
+		"DID_NO_CONNECT",
+		"DID_BUS_BUSY",
+		"DID_TIME_OUT",
+		"DID_BAD_TARGET",
+		"DID_ABORT",
+		"DID_PARITY",
+		"DID_ERROR",
+		"DID_RESET",
+		"DID_BAD_INTR"
+	};
+#endif				/* DEBUG_ISP2x00_INTR */
+
+	ENTER("isp2x00_return_status");
+
+	DEBUG(printk("qlogicfc : completion status = 0x%04x\n",
+		     le16_to_cpu(sts->completion_status)));
+
+	switch (le16_to_cpu(sts->completion_status)) {
+	case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+	case CS_DMA_ERROR:
+		host_status = DID_ERROR;
+		break;
+	case CS_RESET_OCCURRED:
+		host_status = DID_RESET;
+		break;
+	case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+	case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+	case CS_DATA_OVERRUN:
+		host_status = DID_ERROR;
+		break;
+	case CS_DATA_UNDERRUN:
+	        if (Cmnd->underflow <= (Cmnd->request_bufflen - le32_to_cpu(sts->residual)))
+		        host_status = DID_OK;
+		else
+		        host_status = DID_ERROR;
+		break;
+	case CS_PORT_UNAVAILABLE:
+	case CS_PORT_LOGGED_OUT:
+	case CS_PORT_CONFIG_CHANGED:
+		host_status = DID_BAD_TARGET;
+		break;
+	case CS_QUEUE_FULL:
+		host_status = DID_ERROR;
+		break;
+	default:
+		printk("qlogicfc : unknown completion status 0x%04x\n",
+		       le16_to_cpu(sts->completion_status));
+		host_status = DID_ERROR;
+		break;
+	}
+
+	DEBUG_INTR(printk("qlogicfc : host status (%s) scsi status %x\n",
+			  reason[host_status], le16_to_cpu(sts->scsi_status)));
+
+	LEAVE("isp2x00_return_status");
+
+	return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);
+}
+
+
+static int isp2x00_abort(Scsi_Cmnd * Cmnd)
+{
+	u_short param[8];
+	int i;
+	struct Scsi_Host *host;
+	struct isp2x00_hostdata *hostdata;
+	int return_status = SUCCESS;
+
+	ENTER("isp2x00_abort");
+
+	host = Cmnd->device->host;
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+	for (i = 0; i < QLOGICFC_REQ_QUEUE_LEN; i++)
+		if (hostdata->handle_ptrs[i] == Cmnd)
+			break;
+
+	if (i == QLOGICFC_REQ_QUEUE_LEN){
+		return SUCCESS;
+	}
+
+	isp2x00_disable_irqs(host);
+
+	param[0] = MBOX_ABORT_IOCB;
+#if ISP2x00_PORTDB
+	param[1] = (((u_short) hostdata->port_db[Cmnd->device->id].loop_id) << 8) | Cmnd->device->lun;
+#else
+	param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun;
+#endif
+	param[2] = i & 0xffff;
+	param[3] = i >> 16;
+
+	isp2x00_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicfc%d : scsi abort failure: %x\n", hostdata->host_id, param[0]);
+		if (param[0] == 0x4005)
+			Cmnd->result = DID_ERROR << 16;
+		if (param[0] == 0x4006)
+			Cmnd->result = DID_BAD_TARGET << 16;
+		return_status = FAILED;
+	}
+
+	if (return_status != SUCCESS){
+		param[0] = MBOX_GET_FIRMWARE_STATE;
+		isp2x00_mbox_command(host, param);
+		printk("qlogicfc%d : abort failed\n", hostdata->host_id);
+		printk("qlogicfc%d : firmware status is %x %x\n", hostdata->host_id, param[0], param[1]);
+	}
+
+	isp2x00_enable_irqs(host);
+
+	LEAVE("isp2x00_abort");
+
+	return return_status;
+}
+
+
+static int isp2x00_biosparam(struct scsi_device *sdev, struct block_device *n,
+		sector_t capacity, int ip[])
+{
+	int size = capacity;
+
+	ENTER("isp2x00_biosparam");
+
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+	}
+	LEAVE("isp2x00_biosparam");
+
+	return 0;
+}
+
+static int isp2x00_reset_hardware(struct Scsi_Host *host)
+{
+	u_short param[8];
+	struct isp2x00_hostdata *hostdata;
+	int loop_count;
+	dma_addr_t busaddr;
+
+	ENTER("isp2x00_reset_hardware");
+
+	hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+	/*
+	 *	This cannot be right - PCI writes are posted
+	 *	(apparently this is hardware design flaw not software ?)
+	 */
+	 
+	outw(0x01, host->io_port + ISP_CTRL_STATUS);
+	udelay(100);
+	outw(HCCR_RESET, host->io_port + HOST_HCCR);
+	udelay(100);
+	outw(HCCR_RELEASE, host->io_port + HOST_HCCR);
+	outw(HCCR_BIOS_DISABLE, host->io_port + HOST_HCCR);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + HOST_HCCR) == RISC_BUSY) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicfc%d : reset_hardware loop timeout\n", hostdata->host_id);
+
+
+
+#if DEBUG_ISP2x00
+	printk("qlogicfc%d : mbox 0 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX0));
+	printk("qlogicfc%d : mbox 1 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX1));
+	printk("qlogicfc%d : mbox 2 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX2));
+	printk("qlogicfc%d : mbox 3 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX3));
+	printk("qlogicfc%d : mbox 4 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX4));
+	printk("qlogicfc%d : mbox 5 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX5));
+	printk("qlogicfc%d : mbox 6 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX6));
+	printk("qlogicfc%d : mbox 7 0x%04x \n", hostdata->host_id,  inw(host->io_port + MBOX7));
+#endif				/* DEBUG_ISP2x00 */
+
+	DEBUG(printk("qlogicfc%d : verifying checksum\n", hostdata->host_id));
+
+#if defined(CONFIG_SCSI_QLOGIC_FC_FIRMWARE)
+	{
+		int i;
+		unsigned short * risc_code = NULL;
+		unsigned short risc_code_len = 0;
+		if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2100){
+		        risc_code = risc_code2100;
+			risc_code_len = risc_code_length2100;
+		}
+		else if (hostdata->pci_dev->device == PCI_DEVICE_ID_QLOGIC_ISP2200){
+		        risc_code = risc_code2200;
+			risc_code_len = risc_code_length2200;
+		}
+
+		for (i = 0; i < risc_code_len; i++) {
+			param[0] = MBOX_WRITE_RAM_WORD;
+			param[1] = risc_code_addr01 + i;
+			param[2] = risc_code[i];
+
+			isp2x00_mbox_command(host, param);
+
+			if (param[0] != MBOX_COMMAND_COMPLETE) {
+				printk("qlogicfc%d : firmware load failure\n", hostdata->host_id);
+				return 1;
+			}
+		}
+	}
+#endif				/* RELOAD_FIRMWARE */
+
+	param[0] = MBOX_VERIFY_CHECKSUM;
+	param[1] = risc_code_addr01;
+
+	isp2x00_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicfc%d : ram checksum failure\n", hostdata->host_id);
+		return 1;
+	}
+	DEBUG(printk("qlogicfc%d : executing firmware\n", hostdata->host_id));
+
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr01;
+
+	isp2x00_mbox_command(host, param);
+
+	param[0] = MBOX_ABOUT_FIRMWARE;
+
+	isp2x00_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicfc%d : about firmware failure\n", hostdata->host_id);
+		return 1;
+	}
+	DEBUG(printk("qlogicfc%d : firmware major revision %d\n", hostdata->host_id,  param[1]));
+	DEBUG(printk("qlogicfc%d : firmware minor revision %d\n", hostdata->host_id,  param[2]));
+
+#ifdef USE_NVRAM_DEFAULTS
+
+	if (isp2x00_get_nvram_defaults(host, &hostdata->control_block) != 0) {
+		printk("qlogicfc%d : Could not read from NVRAM\n", hostdata->host_id);
+	}
+#endif
+
+	hostdata->wwn = (u64) (cpu_to_le16(hostdata->control_block.node_name[0])) << 56;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[0]) & 0xff00) << 48;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0xff00) << 24;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[1]) & 0x00ff) << 48;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0x00ff) << 24;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[2]) & 0xff00) << 8;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0x00ff) << 8;
+	hostdata->wwn |= (u64) (cpu_to_le16(hostdata->control_block.node_name[3]) & 0xff00) >> 8;
+
+	/* FIXME: If the DMA transfer goes one way only, this should use
+	 *        PCI_DMA_TODEVICE and below as well.
+	 */
+	busaddr = pci_map_page(hostdata->pci_dev,
+			       virt_to_page(&hostdata->control_block),
+			       offset_in_page(&hostdata->control_block),
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
+
+	param[0] = MBOX_INIT_FIRMWARE;
+	param[2] = (u_short) (pci64_dma_lo32(busaddr) >> 16);
+	param[3] = (u_short) (pci64_dma_lo32(busaddr) & 0xffff);
+	param[4] = 0;
+	param[5] = 0;
+	param[6] = (u_short) (pci64_dma_hi32(busaddr) >> 16);
+	param[7] = (u_short) (pci64_dma_hi32(busaddr) & 0xffff);
+	isp2x00_mbox_command(host, param);
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicfc%d.c: Ouch 0x%04x\n", hostdata->host_id,  param[0]);
+		pci_unmap_page(hostdata->pci_dev, busaddr,
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
+		return 1;
+	}
+	param[0] = MBOX_GET_FIRMWARE_STATE;
+	isp2x00_mbox_command(host, param);
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicfc%d.c: 0x%04x\n", hostdata->host_id,  param[0]);
+		pci_unmap_page(hostdata->pci_dev, busaddr,
+			       sizeof(hostdata->control_block),
+			       PCI_DMA_BIDIRECTIONAL);
+		return 1;
+	}
+
+	pci_unmap_page(hostdata->pci_dev, busaddr,
+		       sizeof(hostdata->control_block),
+		       PCI_DMA_BIDIRECTIONAL);
+	LEAVE("isp2x00_reset_hardware");
+
+	return 0;
+}
+
+#ifdef USE_NVRAM_DEFAULTS
+
+static int isp2x00_get_nvram_defaults(struct Scsi_Host *host, struct init_cb *control_block)
+{
+
+	u_short value;
+	if (isp2x00_read_nvram_word(host, 0) != 0x5349)
+		return 1;
+
+	value = isp2x00_read_nvram_word(host, 8);
+	control_block->node_name[0] = cpu_to_le16(isp2x00_read_nvram_word(host, 9));
+	control_block->node_name[1] = cpu_to_le16(isp2x00_read_nvram_word(host, 10));
+	control_block->node_name[2] = cpu_to_le16(isp2x00_read_nvram_word(host, 11));
+	control_block->node_name[3] = cpu_to_le16(isp2x00_read_nvram_word(host, 12));
+	control_block->hard_addr = cpu_to_le16(isp2x00_read_nvram_word(host, 13));
+
+	return 0;
+
+}
+
+#endif
+
+static int isp2x00_init(struct Scsi_Host *sh)
+{
+	u_long io_base;
+	struct isp2x00_hostdata *hostdata;
+	u_char revision;
+	u_int irq;
+	u_short command;
+	struct pci_dev *pdev;
+
+
+	ENTER("isp2x00_init");
+
+	hostdata = (struct isp2x00_hostdata *) sh->hostdata;
+	pdev = hostdata->pci_dev;
+
+	if (pci_read_config_word(pdev, PCI_COMMAND, &command)
+	  || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision)) {
+		printk("qlogicfc%d : error reading PCI configuration\n", hostdata->host_id);
+		return 1;
+	}
+	io_base = pci_resource_start(pdev, 0);
+	irq = pdev->irq;
+
+
+	if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
+		printk("qlogicfc%d : 0x%04x is not QLogic vendor ID\n", hostdata->host_id, 
+		       pdev->vendor);
+		return 1;
+	}
+	if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2100 && pdev->device != PCI_DEVICE_ID_QLOGIC_ISP2200) {
+		printk("qlogicfc%d : 0x%04x does not match ISP2100 or ISP2200 device id\n", hostdata->host_id, 
+		       pdev->device);
+		return 1;
+	}
+	if (!(command & PCI_COMMAND_IO) ||
+	    !(pdev->resource[0].flags & IORESOURCE_IO)) {
+		printk("qlogicfc%d : i/o mapping is disabled\n", hostdata->host_id);
+		return 1;
+	}
+
+	pci_set_master(pdev);
+	if (revision != ISP2100_REV_ID1 && revision != ISP2100_REV_ID3 && revision != ISP2200_REV_ID5)
+		printk("qlogicfc%d : new isp2x00 revision ID (%d)\n", hostdata->host_id,  revision);
+
+
+	hostdata->revision = revision;
+
+	sh->irq = irq;
+	sh->io_port = io_base;
+
+	LEAVE("isp2x00_init");
+
+	return 0;
+}
+
+#if USE_NVRAM_DEFAULTS
+
+#define NVRAM_DELAY() udelay(10)	/* 10 microsecond delay */
+
+
+u_short isp2x00_read_nvram_word(struct Scsi_Host * host, u_short byte)
+{
+	int i;
+	u_short value, output, input;
+
+	outw(0x2, host->io_port + PCI_NVRAM);
+	NVRAM_DELAY();
+	outw(0x3, host->io_port + PCI_NVRAM);
+	NVRAM_DELAY();
+
+	byte &= 0xff;
+	byte |= 0x0600;
+	for (i = 10; i >= 0; i--) {
+		output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
+		outw(output | 0x2, host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+		outw(output | 0x3, host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+		outw(output | 0x2, host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+	}
+
+	for (i = 0xf, value = 0; i >= 0; i--) {
+		value <<= 1;
+		outw(0x3, host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+		input = inw(host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+		outw(0x2, host->io_port + PCI_NVRAM);
+		NVRAM_DELAY();
+		if (input & 0x8)
+			value |= 1;
+	}
+
+	outw(0x0, host->io_port + PCI_NVRAM);
+	NVRAM_DELAY();
+
+	return value;
+}
+
+
+#endif				/* USE_NVRAM_DEFAULTS */
+
+
+
+/*
+ * currently, this is only called during initialization or abort/reset,
+ * at which times interrupts are disabled, so polling is OK, I guess...
+ */
+static int isp2x00_mbox_command(struct Scsi_Host *host, u_short param[])
+{
+	int loop_count;
+	struct isp2x00_hostdata *hostdata = (struct isp2x00_hostdata *) host->hostdata;
+
+	if (mbox_param[param[0]] == 0 || hostdata->adapter_state == AS_FIRMWARE_DEAD)
+		return 1;
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + HOST_HCCR) & 0x0080) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count) {
+		printk("qlogicfc%d : mbox_command loop timeout #1\n", hostdata->host_id);
+		param[0] = 0x4006;
+		hostdata->adapter_state = AS_FIRMWARE_DEAD;
+		return 1;
+	}
+	hostdata->mbox_done = 0;
+
+	if (mbox_param[param[0]] == 0)
+		printk("qlogicfc%d : invalid mbox command\n", hostdata->host_id);
+
+	if (mbox_param[param[0]] & 0x80)
+		outw(param[7], host->io_port + MBOX7);
+	if (mbox_param[param[0]] & 0x40)
+		outw(param[6], host->io_port + MBOX6);
+	if (mbox_param[param[0]] & 0x20)
+		outw(param[5], host->io_port + MBOX5);
+	if (mbox_param[param[0]] & 0x10)
+		outw(param[4], host->io_port + MBOX4);
+	if (mbox_param[param[0]] & 0x08)
+		outw(param[3], host->io_port + MBOX3);
+	if (mbox_param[param[0]] & 0x04)
+		outw(param[2], host->io_port + MBOX2);
+	if (mbox_param[param[0]] & 0x02)
+		outw(param[1], host->io_port + MBOX1);
+	if (mbox_param[param[0]] & 0x01)
+		outw(param[0], host->io_port + MBOX0);
+
+
+	outw(HCCR_SET_HOST_INTR, host->io_port + HOST_HCCR);
+
+	while (1) {
+		loop_count = DEFAULT_LOOP_COUNT;
+		while (--loop_count && !(inw(host->io_port + PCI_INTER_STS) & 0x08)) { 
+			barrier();
+			cpu_relax();
+		}
+
+		if (!loop_count) {
+			hostdata->adapter_state = AS_FIRMWARE_DEAD;
+			printk("qlogicfc%d : mbox_command loop timeout #2\n", hostdata->host_id);
+			break;
+		}
+		isp2x00_intr_handler(host->irq, host, NULL);
+
+		if (hostdata->mbox_done == 1)
+			break;
+
+	}
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && inw(host->io_port + MBOX0) == 0x04) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicfc%d : mbox_command loop timeout #3\n", hostdata->host_id);
+
+	param[7] = inw(host->io_port + MBOX7);
+	param[6] = inw(host->io_port + MBOX6);
+	param[5] = inw(host->io_port + MBOX5);
+	param[4] = inw(host->io_port + MBOX4);
+	param[3] = inw(host->io_port + MBOX3);
+	param[2] = inw(host->io_port + MBOX2);
+	param[1] = inw(host->io_port + MBOX1);
+	param[0] = inw(host->io_port + MBOX0);
+
+
+	outw(0x0, host->io_port + PCI_SEMAPHORE);
+
+	if (inw(host->io_port + HOST_HCCR) & 0x0080) {
+		hostdata->adapter_state = AS_FIRMWARE_DEAD;
+		printk("qlogicfc%d : mbox op is still pending\n", hostdata->host_id);
+	}
+	return 0;
+}
+
+#if DEBUG_ISP2x00_INTR
+
+void isp2x00_print_status_entry(struct Status_Entry *status)
+{
+	printk("qlogicfc : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n", 
+	status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
+	printk("qlogicfc : scsi status = 0x%04x, completion status = 0x%04x\n",
+	       le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status));
+	printk("qlogicfc : state flags = 0x%04x, status flags = 0x%04x\n", 
+	       le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags));
+	printk("qlogicfc : response info length = 0x%04x, request sense length = 0x%04x\n",
+	       le16_to_cpu(status->res_info_len), le16_to_cpu(status->req_sense_len));
+	printk("qlogicfc : residual transfer length = 0x%08x, response = 0x%02x\n", le32_to_cpu(status->residual), status->res_info[3]);
+
+}
+
+#endif                         /* DEBUG_ISP2x00_INTR */
+
+
+#if DEBUG_ISP2x00
+
+void isp2x00_print_scsi_cmd(Scsi_Cmnd * cmd)
+{
+	int i;
+
+	printk("qlogicfc : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n", 
+	       cmd->target, cmd->lun, cmd->cmd_len);
+	printk("qlogicfc : command = ");
+	for (i = 0; i < cmd->cmd_len; i++)
+		printk("0x%02x ", cmd->cmnd[i]);
+	printk("\n");
+}
+
+#endif				/* DEBUG_ISP2x00 */
+
+MODULE_LICENSE("GPL");
+
+static Scsi_Host_Template driver_template = {
+        .detect                 = isp2x00_detect,
+        .release                = isp2x00_release,
+        .info                   = isp2x00_info,
+        .queuecommand           = isp2x00_queuecommand,
+        .eh_abort_handler       = isp2x00_abort,
+        .bios_param             = isp2x00_biosparam,
+        .can_queue              = QLOGICFC_REQ_QUEUE_LEN,
+        .this_id                = -1,
+        .sg_tablesize           = QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN),
+	.cmd_per_lun		= QLOGICFC_CMD_PER_LUN,
+        .use_clustering         = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/qlogicfc_asm.c b/drivers/scsi/qlogicfc_asm.c
new file mode 100644
index 0000000..b1d4510
--- /dev/null
+++ b/drivers/scsi/qlogicfc_asm.c
@@ -0,0 +1,9751 @@
+/************************************************************************
+ *									*
+ * 	 --- ISP2100 Fabric Initiator/Target Firmware ---               *
+ *                   with expanded LUN addressing                       *
+ *                   and FcTape (FCP-2) support                         *
+ *									*
+ *									*
+ ************************************************************************
+  Copyright (C) 2000 and 2001 Qlogic Corporation 
+  (www.qlogic.com)
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+************************************************************************/
+
+/*
+ *	Firmware Version 1.19.16 (10:36 Nov 02, 2000)
+ */
+
+static unsigned short risc_code_addr01 = 0x1000 ;
+
+static unsigned short risc_code_length2100 = 0x9260;
+static unsigned short risc_code2100[] = {
+	0x0078, 0x102d, 0x0000, 0x9260, 0x0000, 0x0001, 0x0013, 0x0010,
+	0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939,
+	0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3231, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x312e, 0x3139, 0x2020, 0x2020, 0x2400, 0x2091, 0x2000, 0x20c1,
+	0x0021, 0x2039, 0xffff, 0x2019, 0xaaaa, 0x2760, 0x2069, 0x7fff,
+	0x20c1, 0x0020, 0x2c2c, 0x2d34, 0x2762, 0x236a, 0x2c24, 0x2d04,
+	0x266a, 0x2562, 0xa406, 0x00c0, 0x1052, 0x20c1, 0x0021, 0x2c2c,
+	0x2362, 0x2c04, 0x2562, 0xa306, 0x0040, 0x1052, 0x20c1, 0x0020,
+	0x2039, 0x8fff, 0x20a1, 0xaa00, 0x2708, 0x810d, 0x810d, 0x810d,
+	0x810d, 0xa18c, 0x000f, 0x2001, 0x000a, 0xa112, 0xa00e, 0x21a8,
+	0x41a4, 0x3400, 0x8211, 0x00c0, 0x105f, 0x2708, 0x3400, 0xa102,
+	0x0040, 0x106f, 0x0048, 0x106f, 0x20a8, 0xa00e, 0x41a4, 0x20a1,
+	0xa260, 0x2009, 0x0000, 0x20a9, 0x07a0, 0x41a4, 0x3400, 0x20c9,
+	0xa7ff, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x255d,
+	0x2051, 0xa300, 0x2a70, 0x775e, 0xa786, 0x8fff, 0x0040, 0x1092,
+	0x705b, 0xca00, 0x7057, 0xc9f1, 0x7063, 0x0200, 0x7067, 0x0200,
+	0x0078, 0x109a, 0x7057, 0xba01, 0x7063, 0x0100, 0x7067, 0x0100,
+	0x705b, 0xba00, 0x1078, 0x12df, 0x1078, 0x13c0, 0x1078, 0x1569,
+	0x1078, 0x1ca4, 0x1078, 0x4229, 0x1078, 0x74cf, 0x1078, 0x134b,
+	0x1078, 0x2a3f, 0x1078, 0x4da2, 0x1078, 0x48b2, 0x1078, 0x57df,
+	0x1078, 0x21f7, 0x1078, 0x5abf, 0x1078, 0x5369, 0x1078, 0x210d,
+	0x1078, 0x21d4, 0x2091, 0x3009, 0x7823, 0x0000, 0x0090, 0x10cf,
+	0x7820, 0xa086, 0x0002, 0x00c0, 0x10cf, 0x7823, 0x4000, 0x0068,
+	0x10c7, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70,
+	0x7003, 0x0000, 0x2001, 0x017f, 0x2003, 0x0000, 0x2a70, 0x7000,
+	0xa08e, 0x0003, 0x00c0, 0x10ef, 0x1078, 0x35bc, 0x1078, 0x2a67,
+	0x1078, 0x4df2, 0x1078, 0x4a75, 0x2009, 0x0100, 0x2104, 0xa082,
+	0x0002, 0x0048, 0x10f3, 0x1078, 0x57fb, 0x0078, 0x10d6, 0x1079,
+	0x10f7, 0x0078, 0x10dc, 0x1078, 0x6fa9, 0x0078, 0x10eb, 0x1101,
+	0x1102, 0x11be, 0x10ff, 0x1246, 0x12dc, 0x12dd, 0x12de, 0x1078,
+	0x1328, 0x007c, 0x127e, 0x0f7e, 0x2091, 0x8000, 0x7000, 0xa086,
+	0x0001, 0x00c0, 0x1198, 0x1078, 0x3a43, 0x2079, 0x0100, 0x7844,
+	0xa005, 0x00c0, 0x1198, 0x2011, 0x4129, 0x1078, 0x58d4, 0x1078,
+	0x1ab1, 0x780f, 0x00ff, 0x7840, 0xa084, 0xfffb, 0x7842, 0x2011,
+	0x8010, 0x73c0, 0x1078, 0x3579, 0x2001, 0xffff, 0x1078, 0x5975,
+	0x7238, 0xc284, 0x723a, 0x2001, 0xa30c, 0x2014, 0xc2ac, 0x2202,
+	0x1078, 0x6db5, 0x2011, 0x0004, 0x1078, 0x8a59, 0x1078, 0x47ce,
+	0x1078, 0x4211, 0x0040, 0x1144, 0x7083, 0x0001, 0x70bb, 0x0000,
+	0x1078, 0x3bf5, 0x0078, 0x1198, 0x1078, 0x4897, 0x0040, 0x114d,
+	0x7a0c, 0xc2b4, 0x7a0e, 0x0078, 0x1159, 0x1078, 0x8ddf, 0x70c8,
+	0xd09c, 0x00c0, 0x1159, 0x7094, 0xa005, 0x0040, 0x1159, 0x1078,
+	0x41f5, 0x70d3, 0x0000, 0x70cf, 0x0000, 0x72c8, 0x2079, 0xa351,
+	0x7804, 0xd0ac, 0x0040, 0x1165, 0xc295, 0x72ca, 0xa296, 0x0004,
+	0x0040, 0x1186, 0x2011, 0x0001, 0x1078, 0x8a59, 0x708f, 0x0000,
+	0x7093, 0xffff, 0x7003, 0x0002, 0x0f7f, 0x1078, 0x260d, 0x2011,
+	0x0005, 0x1078, 0x6ef2, 0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100,
+	0x60e3, 0x0008, 0x0c7f, 0x127f, 0x0078, 0x119a, 0x708f, 0x0000,
+	0x7093, 0xffff, 0x7003, 0x0002, 0x2011, 0x0005, 0x1078, 0x6ef2,
+	0x1078, 0x6109, 0x0c7e, 0x2061, 0x0100, 0x60e3, 0x0008, 0x0c7f,
+	0x0f7f, 0x127f, 0x007c, 0x0c7e, 0x20a9, 0x0082, 0x2009, 0x007e,
+	0x017e, 0x027e, 0x037e, 0x2110, 0x027e, 0x2019, 0x0029, 0x1078,
+	0x71e0, 0x027f, 0x1078, 0xa190, 0x037f, 0x027f, 0x017f, 0x1078,
+	0x2921, 0x8108, 0x00f0, 0x11a0, 0x0c7f, 0x706b, 0x0000, 0x706c,
+	0xa084, 0x00ff, 0x706e, 0x7097, 0x0000, 0x007c, 0x127e, 0x2091,
+	0x8000, 0x7000, 0xa086, 0x0002, 0x00c0, 0x1244, 0x7090, 0xa086,
+	0xffff, 0x0040, 0x11d1, 0x1078, 0x260d, 0x1078, 0x6109, 0x0078,
+	0x1244, 0x70c8, 0xd09c, 0x0040, 0x11fd, 0xd084, 0x0040, 0x11fd,
+	0x0f7e, 0x2079, 0x0100, 0x790c, 0xc1b5, 0x790e, 0x0f7f, 0xd08c,
+	0x0040, 0x11fd, 0x70cc, 0xa086, 0xffff, 0x0040, 0x11f9, 0x1078,
+	0x278a, 0x1078, 0x6109, 0x70c8, 0xd094, 0x00c0, 0x1244, 0x2011,
+	0x0001, 0x2019, 0x0000, 0x1078, 0x27c2, 0x1078, 0x6109, 0x0078,
+	0x1244, 0x70d0, 0xa005, 0x00c0, 0x1244, 0x708c, 0xa005, 0x00c0,
+	0x1244, 0x1078, 0x4897, 0x00c0, 0x1244, 0x2001, 0xa352, 0x2004,
+	0xd0ac, 0x0040, 0x1227, 0x157e, 0x0c7e, 0x20a9, 0x007f, 0x2009,
+	0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x121a, 0x6000, 0xd0ec,
+	0x00c0, 0x1222, 0x017f, 0x8108, 0x00f0, 0x1211, 0x0c7f, 0x157f,
+	0x0078, 0x1227, 0x017f, 0x0c7f, 0x157f, 0x0078, 0x1244, 0x7003,
+	0x0003, 0x7093, 0xffff, 0x2001, 0x0000, 0x1078, 0x2480, 0x1078,
+	0x35f7, 0x2001, 0xa5ac, 0x2004, 0xa086, 0x0005, 0x00c0, 0x123c,
+	0x2011, 0x0000, 0x1078, 0x6ef2, 0x2011, 0x0000, 0x1078, 0x6efc,
+	0x1078, 0x6109, 0x1078, 0x61d3, 0x127f, 0x007c, 0x017e, 0x0f7e,
+	0x127e, 0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0x00f7, 0x1078,
+	0x41de, 0x7940, 0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0040,
+	0x125b, 0x7827, 0x0040, 0xd19c, 0x0040, 0x1260, 0x7827, 0x0008,
+	0x007e, 0x037e, 0x157e, 0xa006, 0x1078, 0x5975, 0x7900, 0xa18a,
+	0x0003, 0x0050, 0x1289, 0x7954, 0xd1ac, 0x00c0, 0x1289, 0x2009,
+	0x00f8, 0x1078, 0x41de, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9,
+	0x09c4, 0x7820, 0xd09c, 0x00c0, 0x1281, 0x7824, 0xd0ac, 0x00c0,
+	0x12ca, 0x00f0, 0x1279, 0x2001, 0x0001, 0x1078, 0x2480, 0x0078,
+	0x12d5, 0x7853, 0x0000, 0x782f, 0x0020, 0x20a9, 0x0050, 0x00e0,
+	0x128f, 0x2091, 0x6000, 0x00f0, 0x128f, 0x7853, 0x0400, 0x782f,
+	0x0000, 0x2009, 0x00f8, 0x1078, 0x41de, 0x20a9, 0x000e, 0x0005,
+	0x00f0, 0x129f, 0x7853, 0x1400, 0x7843, 0x0090, 0x7843, 0x0010,
+	0x2019, 0x61a8, 0x7854, 0x0005, 0x0005, 0xd08c, 0x0040, 0x12b4,
+	0x7824, 0xd0ac, 0x00c0, 0x12ca, 0x8319, 0x00c0, 0x12aa, 0x2009,
+	0xa331, 0x2104, 0x8000, 0x200a, 0xa084, 0xfff0, 0x0040, 0x12c4,
+	0x200b, 0x0000, 0x1078, 0x251e, 0x2001, 0x0001, 0x1078, 0x2480,
+	0x0078, 0x12d3, 0x2001, 0xa331, 0x2003, 0x0000, 0x7828, 0xc09d,
+	0x782a, 0x7827, 0x0048, 0x7853, 0x0400, 0x157f, 0x037f, 0x007f,
+	0x127f, 0x0f7f, 0x017f, 0x007c, 0x007c, 0x007c, 0x007c, 0x2a70,
+	0x2009, 0x0100, 0x2104, 0xa082, 0x0002, 0x0048, 0x12eb, 0x704f,
+	0xffff, 0x0078, 0x12ed, 0x704f, 0x0000, 0x7053, 0xffff, 0x706b,
+	0x0000, 0x706f, 0x0000, 0x1078, 0x8ddf, 0x2061, 0xa58c, 0x6003,
+	0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200, 0x6013,
+	0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0, 0x2061,
+	0xa594, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000, 0x600f,
+	0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001, 0x601f,
+	0x0000, 0x2061, 0xa5a3, 0x6003, 0x514c, 0x6007, 0x4f47, 0x600b,
+	0x4943, 0x600f, 0x2020, 0x2001, 0xa325, 0x2003, 0x0000, 0x007c,
+	0x2091, 0x8000, 0x0068, 0x132a, 0x007e, 0x017e, 0x2079, 0x0000,
+	0x7818, 0xd084, 0x00c0, 0x1330, 0x017f, 0x792e, 0x007f, 0x782a,
+	0x007f, 0x7826, 0x3900, 0x783a, 0x7823, 0x8002, 0x781b, 0x0001,
+	0x2091, 0x5000, 0x2091, 0x4080, 0x2079, 0xa300, 0x7803, 0x0005,
+	0x0078, 0x1348, 0x007c, 0x2071, 0xa300, 0x7158, 0x712e, 0x2021,
+	0x0001, 0xa190, 0x002d, 0xa298, 0x002d, 0x0048, 0x1361, 0x705c,
+	0xa302, 0x00c8, 0x1361, 0x220a, 0x2208, 0x2310, 0x8420, 0x0078,
+	0x1353, 0x200b, 0x0000, 0x74a6, 0x74aa, 0x007c, 0x0e7e, 0x127e,
+	0x2091, 0x8000, 0x2071, 0xa300, 0x70a8, 0xa0ea, 0x0010, 0x00c8,
+	0x1374, 0xa06e, 0x0078, 0x137e, 0x8001, 0x70aa, 0x702c, 0x2068,
+	0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f, 0x0e7f,
+	0x007c, 0x0e7e, 0x2071, 0xa300, 0x127e, 0x2091, 0x8000, 0x70a8,
+	0x8001, 0x00c8, 0x138e, 0xa06e, 0x0078, 0x1397, 0x70aa, 0x702c,
+	0x2068, 0x2d04, 0x702e, 0x206b, 0x0000, 0x6807, 0x0000, 0x127f,
+	0x0e7f, 0x007c, 0x0e7e, 0x127e, 0x2091, 0x8000, 0x2071, 0xa300,
+	0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa, 0x127f,
+	0x0e7f, 0x007c, 0x8dff, 0x0040, 0x13b6, 0x6804, 0x6807, 0x0000,
+	0x007e, 0x1078, 0x139a, 0x0d7f, 0x0078, 0x13aa, 0x007c, 0x0e7e,
+	0x2071, 0xa300, 0x70a8, 0xa08a, 0x0010, 0xa00d, 0x0e7f, 0x007c,
+	0x0e7e, 0x2071, 0xa5d0, 0x7007, 0x0000, 0x701b, 0x0000, 0x701f,
+	0x0000, 0x2071, 0x0000, 0x7010, 0xa085, 0x8004, 0x7012, 0x0e7f,
+	0x007c, 0x0e7e, 0x2270, 0x700b, 0x0000, 0x2071, 0xa5d0, 0x7018,
+	0xa088, 0xa5d9, 0x220a, 0x8000, 0xa084, 0x0007, 0x701a, 0x7004,
+	0xa005, 0x00c0, 0x13e9, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa,
+	0x0f7f, 0x0e7f, 0x007c, 0x0e7e, 0x2071, 0xa5d0, 0x7004, 0xa005,
+	0x00c0, 0x13f8, 0x0f7e, 0x2079, 0x0010, 0x1078, 0x13fa, 0x0f7f,
+	0x0e7f, 0x007c, 0x7000, 0x0079, 0x13fd, 0x1401, 0x146b, 0x1488,
+	0x1488, 0x7018, 0x711c, 0xa106, 0x00c0, 0x1409, 0x7007, 0x0000,
+	0x007c, 0x0d7e, 0xa180, 0xa5d9, 0x2004, 0x700a, 0x2068, 0x8108,
+	0xa18c, 0x0007, 0x711e, 0x7803, 0x0026, 0x6824, 0x7832, 0x6828,
+	0x7836, 0x682c, 0x783a, 0x6830, 0x783e, 0x6810, 0x700e, 0x680c,
+	0x7016, 0x6804, 0x0d7f, 0xd084, 0x0040, 0x142b, 0x7007, 0x0001,
+	0x1078, 0x1430, 0x007c, 0x7007, 0x0002, 0x1078, 0x1446, 0x007c,
+	0x017e, 0x027e, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8,
+	0x143b, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822, 0x7803,
+	0x0020, 0x7803, 0x0041, 0x027f, 0x017f, 0x007c, 0x017e, 0x027e,
+	0x137e, 0x147e, 0x157e, 0x7014, 0x2098, 0x20a1, 0x0014, 0x7803,
+	0x0026, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x00c8, 0x145a,
+	0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803,
+	0x0020, 0x3300, 0x7016, 0x7803, 0x0001, 0x157f, 0x147f, 0x137f,
+	0x027f, 0x017f, 0x007c, 0x137e, 0x147e, 0x157e, 0x2099, 0xa3f9,
+	0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e,
+	0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084,
+	0x7002, 0x700b, 0xa3f4, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c,
+	0x137e, 0x147e, 0x157e, 0x2001, 0xa428, 0x209c, 0x20a1, 0x0014,
+	0x7803, 0x0026, 0x2001, 0xa429, 0x20ac, 0x53a6, 0x2099, 0xa42a,
+	0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x127e,
+	0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c,
+	0x7002, 0x700b, 0xa425, 0x127f, 0x157f, 0x147f, 0x137f, 0x007c,
+	0x017e, 0x0e7e, 0x2071, 0xa5d0, 0x0f7e, 0x2079, 0x0010, 0x7904,
+	0x7803, 0x0002, 0xd1fc, 0x0040, 0x14c2, 0xa18c, 0x0700, 0x7004,
+	0x1079, 0x14c6, 0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x13fa, 0x14ce,
+	0x14fb, 0x1523, 0x1556, 0x14cc, 0x0078, 0x14cc, 0xa18c, 0x0700,
+	0x00c0, 0x14f4, 0x137e, 0x147e, 0x157e, 0x7014, 0x20a0, 0x2099,
+	0x0014, 0x7803, 0x0040, 0x7010, 0x20a8, 0x53a5, 0x3400, 0x7016,
+	0x157f, 0x147f, 0x137f, 0x700c, 0xa005, 0x0040, 0x1510, 0x1078,
+	0x1430, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007,
+	0x0000, 0x1078, 0x13fa, 0x007c, 0x7008, 0xa080, 0x0002, 0x2003,
+	0x0200, 0x0078, 0x14ef, 0xa18c, 0x0700, 0x00c0, 0x1506, 0x700c,
+	0xa005, 0x0040, 0x1510, 0x1078, 0x1446, 0x007c, 0x7008, 0xa080,
+	0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x1078, 0x13fa, 0x007c,
+	0x0d7e, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838,
+	0x682e, 0x783c, 0x6832, 0x680b, 0x0100, 0x0d7f, 0x7007, 0x0000,
+	0x1078, 0x13fa, 0x007c, 0xa18c, 0x0700, 0x00c0, 0x1550, 0x137e,
+	0x147e, 0x157e, 0x2001, 0xa3f7, 0x2004, 0xa080, 0x000d, 0x20a0,
+	0x2099, 0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001,
+	0xa3f9, 0x2004, 0xd0bc, 0x0040, 0x1546, 0x2001, 0xa402, 0x2004,
+	0xa080, 0x000d, 0x20a0, 0x20a9, 0x0020, 0x53a5, 0x157f, 0x147f,
+	0x137f, 0x7007, 0x0000, 0x1078, 0x4e9b, 0x1078, 0x13fa, 0x007c,
+	0x2011, 0x8003, 0x1078, 0x3579, 0x0078, 0x1554, 0xa18c, 0x0700,
+	0x00c0, 0x1563, 0x2001, 0xa427, 0x2003, 0x0100, 0x7007, 0x0000,
+	0x1078, 0x13fa, 0x007c, 0x2011, 0x8004, 0x1078, 0x3579, 0x0078,
+	0x1567, 0x127e, 0x2091, 0x2100, 0x2079, 0x0030, 0x2071, 0xa5e1,
+	0x7803, 0x0004, 0x7003, 0x0000, 0x700f, 0xa5e7, 0x7013, 0xa5e7,
+	0x780f, 0x0076, 0x7803, 0x0004, 0x127f, 0x007c, 0x6934, 0xa184,
+	0x0007, 0x0079, 0x1583, 0x158b, 0x15d1, 0x158b, 0x158b, 0x158b,
+	0x15b6, 0x159a, 0x158f, 0xa085, 0x0001, 0x0078, 0x15eb, 0x684c,
+	0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858,
+	0x0078, 0x15d9, 0xa18c, 0x00ff, 0xa186, 0x001e, 0x00c0, 0x158b,
+	0x684c, 0xd0bc, 0x0040, 0x158b, 0x6860, 0x682e, 0x685c, 0x682a,
+	0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080,
+	0x2015, 0x2004, 0x6832, 0x6858, 0x0078, 0x15e1, 0xa18c, 0x00ff,
+	0xa186, 0x0015, 0x00c0, 0x158b, 0x684c, 0xd0ac, 0x0040, 0x158b,
+	0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080,
+	0x2015, 0x2004, 0x6832, 0xa006, 0x682e, 0x682a, 0x6858, 0x0078,
+	0x15e1, 0x684c, 0xd0ac, 0x0040, 0x158b, 0xa006, 0x682e, 0x682a,
+	0x6858, 0xa18c, 0x000f, 0xa188, 0x2015, 0x210c, 0x6932, 0x2d08,
+	0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c,
+	0x6912, 0x6980, 0x6916, 0x007c, 0x20e1, 0x0007, 0x20e1, 0x2000,
+	0x2001, 0x020a, 0x2004, 0x82ff, 0x0040, 0x160e, 0xa280, 0x0004,
+	0x0d7e, 0x206c, 0x684c, 0xd0dc, 0x00c0, 0x160a, 0x1078, 0x157e,
+	0x0040, 0x160a, 0x0d7f, 0xa280, 0x0000, 0x2003, 0x0002, 0xa016,
+	0x0078, 0x160e, 0x6808, 0x8000, 0x680a, 0x0d7f, 0x127e, 0x047e,
+	0x037e, 0x027e, 0x2091, 0x2100, 0x027f, 0x037f, 0x047f, 0x7000,
+	0xa005, 0x00c0, 0x1622, 0x7206, 0x2001, 0x1643, 0x007e, 0x2260,
+	0x0078, 0x17be, 0x710c, 0x220a, 0x8108, 0x230a, 0x8108, 0x240a,
+	0x8108, 0xa182, 0xa602, 0x0048, 0x162f, 0x2009, 0xa5e7, 0x710e,
+	0x7010, 0xa102, 0xa082, 0x0009, 0x0040, 0x163a, 0xa080, 0x001b,
+	0x00c0, 0x163d, 0x2009, 0x0138, 0x200a, 0x7000, 0xa005, 0x00c0,
+	0x1643, 0x1078, 0x179f, 0x127f, 0x007c, 0x127e, 0x027e, 0x037e,
+	0x0c7e, 0x007e, 0x2091, 0x2100, 0x007f, 0x047f, 0x037f, 0x027f,
+	0x0d7e, 0x0c7e, 0x2460, 0x6110, 0x2168, 0x6a62, 0x6b5e, 0xa005,
+	0x0040, 0x16cf, 0x6808, 0xa005, 0x0040, 0x173c, 0x7000, 0xa005,
+	0x00c0, 0x1664, 0x0078, 0x16c4, 0x700c, 0x7110, 0xa106, 0x00c0,
+	0x1745, 0x7004, 0xa406, 0x00c0, 0x16c4, 0x2001, 0x0005, 0x2004,
+	0xd08c, 0x0040, 0x1681, 0x047e, 0x1078, 0x18e2, 0x047f, 0x2460,
+	0x6010, 0xa080, 0x0002, 0x2004, 0xa005, 0x0040, 0x173c, 0x0078,
+	0x165e, 0x2001, 0x0207, 0x2004, 0xd09c, 0x00c0, 0x166d, 0x7804,
+	0xa084, 0x6000, 0x0040, 0x1692, 0xa086, 0x6000, 0x0040, 0x1692,
+	0x0078, 0x166d, 0x7100, 0xa186, 0x0002, 0x00c0, 0x16b2, 0x0e7e,
+	0x2b68, 0x6818, 0x2060, 0x1078, 0x1fea, 0x2804, 0xac70, 0x6034,
+	0xd09c, 0x00c0, 0x16a7, 0x7108, 0x720c, 0x0078, 0x16a9, 0x7110,
+	0x7214, 0x6810, 0xa100, 0x6812, 0x6814, 0xa201, 0x6816, 0x0e7f,
+	0x0078, 0x16b6, 0xa186, 0x0001, 0x00c0, 0x16be, 0x7820, 0x6910,
+	0xa100, 0x6812, 0x7824, 0x6914, 0xa101, 0x6816, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004, 0x00c0,
+	0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0078, 0x1745, 0x6808,
+	0xa005, 0x0040, 0x173c, 0x7000, 0xa005, 0x00c0, 0x16d9, 0x0078,
+	0x173c, 0x700c, 0x7110, 0xa106, 0x00c0, 0x16e2, 0x7004, 0xa406,
+	0x00c0, 0x173c, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0040, 0x16f6,
+	0x047e, 0x1078, 0x18e2, 0x047f, 0x2460, 0x6010, 0xa080, 0x0002,
+	0x2004, 0xa005, 0x0040, 0x173c, 0x0078, 0x16d3, 0x2001, 0x0207,
+	0x2004, 0xd09c, 0x00c0, 0x16e2, 0x2001, 0x0005, 0x2004, 0xd08c,
+	0x00c0, 0x16e8, 0x7804, 0xa084, 0x6000, 0x0040, 0x170d, 0xa086,
+	0x6000, 0x0040, 0x170d, 0x0078, 0x16e2, 0x7007, 0x0000, 0xa016,
+	0x2218, 0x7000, 0xa08e, 0x0001, 0x0040, 0x172e, 0xa08e, 0x0002,
+	0x00c0, 0x173c, 0x0c7e, 0x0e7e, 0x6818, 0x2060, 0x1078, 0x1fea,
+	0x2804, 0xac70, 0x6034, 0xd09c, 0x00c0, 0x172a, 0x7308, 0x720c,
+	0x0078, 0x172c, 0x7310, 0x7214, 0x0e7f, 0x0c7f, 0x7820, 0xa318,
+	0x7824, 0xa211, 0x6810, 0xa300, 0x6812, 0x6814, 0xa201, 0x6816,
+	0x7803, 0x0004, 0x7003, 0x0000, 0x6100, 0xa18e, 0x0004, 0x00c0,
+	0x1745, 0x2009, 0x0048, 0x1078, 0x756c, 0x0c7f, 0x0d7f, 0x127f,
+	0x007c, 0x0f7e, 0x0e7e, 0x027e, 0x037e, 0x047e, 0x1078, 0x1af7,
+	0x027e, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0000, 0x0040, 0x1790,
+	0x7004, 0xac06, 0x00c0, 0x1781, 0x2079, 0x0030, 0x7000, 0xa086,
+	0x0003, 0x0040, 0x1781, 0x7804, 0xd0fc, 0x00c0, 0x177d, 0x2001,
+	0x0207, 0x2004, 0xd09c, 0x00c0, 0x1763, 0x7803, 0x0004, 0x7804,
+	0xd0ac, 0x00c0, 0x176f, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003,
+	0x0003, 0x7007, 0x0000, 0x0078, 0x1781, 0x1078, 0x18e2, 0x0078,
+	0x1753, 0x157e, 0x20a9, 0x0009, 0x2009, 0xa5e7, 0x2104, 0xac06,
+	0x00c0, 0x178b, 0x200a, 0xa188, 0x0003, 0x00f0, 0x1786, 0x157f,
+	0x027f, 0x2001, 0x015d, 0x201c, 0x831a, 0x2302, 0x2001, 0x0138,
+	0x2202, 0x047f, 0x037f, 0x027f, 0x0e7f, 0x0f7f, 0x007c, 0x700c,
+	0x7110, 0xa106, 0x00c0, 0x17a7, 0x7003, 0x0000, 0x007c, 0x2104,
+	0x7006, 0x2060, 0x8108, 0x211c, 0x8108, 0x2124, 0x8108, 0xa182,
+	0xa602, 0x0048, 0x17b5, 0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106,
+	0x00c0, 0x17be, 0x2001, 0x0138, 0x2003, 0x0008, 0x8cff, 0x00c0,
+	0x17c5, 0x1078, 0x1b22, 0x0078, 0x1823, 0x6010, 0x2068, 0x2d58,
+	0x6828, 0xa406, 0x00c0, 0x17d0, 0x682c, 0xa306, 0x0040, 0x17fe,
+	0x601c, 0xa086, 0x0008, 0x0040, 0x17fe, 0x6024, 0xd0f4, 0x00c0,
+	0x17fa, 0xd0d4, 0x0040, 0x17f6, 0x6038, 0xa402, 0x6034, 0xa303,
+	0x0040, 0x17e4, 0x00c8, 0x17f6, 0x643a, 0x6336, 0x6c2a, 0x6b2e,
+	0x047e, 0x037e, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80,
+	0xa303, 0x6816, 0x037f, 0x047f, 0x0078, 0x17fa, 0x1078, 0x8d8e,
+	0x0040, 0x17c1, 0x1078, 0x2035, 0x00c0, 0x17c1, 0x0c7e, 0x7004,
+	0x2060, 0x6024, 0xc0d4, 0x6026, 0x0c7f, 0x684c, 0xd0f4, 0x0040,
+	0x180f, 0x6817, 0xffff, 0x6813, 0xffff, 0x0078, 0x17c1, 0x6824,
+	0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034, 0xa0cc, 0x000f,
+	0x2009, 0x0011, 0x1078, 0x1824, 0x0040, 0x1822, 0x2009, 0x0001,
+	0x1078, 0x1824, 0x2d58, 0x007c, 0x8aff, 0x0040, 0x18bb, 0xa03e,
+	0x2730, 0x6850, 0xd0fc, 0x00c0, 0x1846, 0xd0f4, 0x00c0, 0x1856,
+	0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1836, 0x189d, 0x185d,
+	0x185d, 0x189d, 0x189d, 0x1895, 0x189d, 0x185d, 0x189d, 0x1863,
+	0x1863, 0x189d, 0x189d, 0x189d, 0x188c, 0x1863, 0xc0fc, 0x6852,
+	0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x0d7e, 0xd99c, 0x0040, 0x18a0,
+	0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x18a0, 0xc0f4, 0x6852,
+	0x6b6c, 0x6a70, 0x0d7e, 0x0078, 0x18a7, 0x6b08, 0x6a0c, 0x6d00,
+	0x6c04, 0x0078, 0x18a0, 0x7b0c, 0xd3bc, 0x0040, 0x1884, 0x7004,
+	0x0e7e, 0x2070, 0x701c, 0x0e7f, 0xa086, 0x0008, 0x00c0, 0x1884,
+	0x7b08, 0xa39c, 0x0fff, 0x2d20, 0x0d7f, 0x0d7e, 0x6a14, 0x82ff,
+	0x00c0, 0x187f, 0x6810, 0xa302, 0x0048, 0x187f, 0x6b10, 0x2011,
+	0x0000, 0x2468, 0x0078, 0x1886, 0x6b10, 0x6a14, 0x6d00, 0x6c04,
+	0x6f08, 0x6e0c, 0x0078, 0x18a0, 0x0d7f, 0x0d7e, 0x6834, 0xa084,
+	0x00ff, 0xa086, 0x001e, 0x00c0, 0x189d, 0x0d7f, 0x1078, 0x1fd1,
+	0x00c0, 0x1824, 0xa00e, 0x0078, 0x18bb, 0x0d7f, 0x1078, 0x1328,
+	0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e, 0x7902, 0x7000,
+	0x8000, 0x7002, 0x0d7f, 0x6828, 0xa300, 0x682a, 0x682c, 0xa201,
+	0x682e, 0x2300, 0x6b10, 0xa302, 0x6812, 0x2200, 0x6a14, 0xa203,
+	0x6816, 0x1078, 0x1fd1, 0x007c, 0x1078, 0x1328, 0x1078, 0x1c52,
+	0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x7003, 0x0000, 0x1078,
+	0x1ac6, 0x1078, 0x8a44, 0x0040, 0x18db, 0x6808, 0x8001, 0x680a,
+	0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff, 0x682f, 0xffff,
+	0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758, 0x0078, 0x1aad,
+	0x1078, 0x1328, 0x127e, 0x2091, 0x2100, 0x007e, 0x017e, 0x2b68,
+	0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184, 0x0700, 0x00c0,
+	0x18be, 0xa184, 0x0003, 0xa086, 0x0003, 0x0040, 0x18e0, 0x7000,
+	0x0079, 0x18fa, 0x1902, 0x1904, 0x1a06, 0x1a84, 0x1a9b, 0x1902,
+	0x1902, 0x1902, 0x1078, 0x1328, 0x8001, 0x7002, 0xa184, 0x0880,
+	0x00c0, 0x1919, 0x8aff, 0x0040, 0x199b, 0x2009, 0x0001, 0x1078,
+	0x1824, 0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078,
+	0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0xd1bc, 0x00c0, 0x1979,
+	0x027e, 0x037e, 0x7808, 0xd0ec, 0x00c0, 0x1930, 0x7c20, 0x7d24,
+	0x7e30, 0x7f34, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1932,
+	0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x2400, 0x686e, 0xa31a, 0x2500,
+	0x6872, 0xa213, 0x6b2a, 0x6a2e, 0x0c7e, 0x7004, 0x2060, 0x6024,
+	0xd0f4, 0x00c0, 0x1945, 0x633a, 0x6236, 0x0c7f, 0x2400, 0x6910,
+	0xa100, 0x6812, 0x2500, 0x6914, 0xa101, 0x6816, 0x037f, 0x027f,
+	0x2600, 0x681e, 0x2700, 0x6822, 0x1078, 0x1fea, 0x2a00, 0x6826,
+	0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852, 0x6808,
+	0x8001, 0x680a, 0x00c0, 0x196e, 0x684c, 0xd0e4, 0x0040, 0x196e,
+	0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x7000, 0xa086,
+	0x0004, 0x0040, 0x1aad, 0x7003, 0x0000, 0x1078, 0x179f, 0x0078,
+	0x1aad, 0x057e, 0x7d0c, 0xd5bc, 0x00c0, 0x1980, 0x1078, 0xa20c,
+	0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078, 0x4893,
+	0x0040, 0x198d, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b, 0xffff,
+	0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912, 0x6980,
+	0x6916, 0x0078, 0x1aad, 0x7004, 0x0c7e, 0x2060, 0x6024, 0x0c7f,
+	0xd0f4, 0x0040, 0x19a8, 0x6808, 0x8001, 0x680a, 0x0078, 0x1aad,
+	0x684c, 0xc0f5, 0x684e, 0x7814, 0xa005, 0x00c0, 0x19c0, 0x7003,
+	0x0000, 0x6808, 0x8001, 0x680a, 0x00c0, 0x19bc, 0x7004, 0x2060,
+	0x2009, 0x0048, 0x1078, 0x756c, 0x1078, 0x179f, 0x0078, 0x1aad,
+	0x7814, 0x6910, 0xa102, 0x6812, 0x6914, 0xa183, 0x0000, 0x6816,
+	0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214,
+	0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b,
+	0x810b, 0x1078, 0x1b4d, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803,
+	0x0001, 0x7804, 0xd0fc, 0x0040, 0x19e1, 0x7803, 0x0002, 0x7803,
+	0x0004, 0x780f, 0x0076, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009,
+	0x0048, 0x1078, 0x756c, 0x1078, 0x1b81, 0x0040, 0x19bc, 0x7908,
+	0xd1ec, 0x00c0, 0x19ff, 0x2009, 0x0009, 0x0078, 0x1a01, 0x2009,
+	0x0019, 0x7902, 0x7003, 0x0003, 0x0078, 0x1aad, 0x8001, 0x7002,
+	0xd194, 0x0040, 0x1a18, 0x7804, 0xd0fc, 0x00c0, 0x18ea, 0x8aff,
+	0x0040, 0x1aad, 0x2009, 0x0001, 0x1078, 0x1824, 0x0078, 0x1aad,
+	0xa184, 0x0880, 0x00c0, 0x1a25, 0x8aff, 0x0040, 0x1aad, 0x2009,
+	0x0001, 0x1078, 0x1824, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003,
+	0x0000, 0xd1bc, 0x00c0, 0x1a65, 0x027e, 0x037e, 0x7808, 0xd0ec,
+	0x00c0, 0x1a38, 0x7803, 0x0009, 0x7003, 0x0004, 0x0078, 0x1a3a,
+	0x1078, 0x1b9f, 0x6b28, 0x6a2c, 0x1078, 0x1fea, 0x0d7e, 0x0f7e,
+	0x2d78, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1a55, 0x6808,
+	0x2008, 0xa31a, 0x680c, 0xa213, 0x7810, 0xa100, 0x7812, 0x690c,
+	0x7814, 0xa101, 0x7816, 0x0078, 0x1a61, 0x6810, 0x2008, 0xa31a,
+	0x6814, 0xa213, 0x7810, 0xa100, 0x7812, 0x6914, 0x7814, 0xa101,
+	0x7816, 0x0f7f, 0x0d7f, 0x0078, 0x1934, 0x057e, 0x7d0c, 0x1078,
+	0xa20c, 0x057f, 0x1078, 0x1ac6, 0x0f7e, 0x7004, 0x2078, 0x1078,
+	0x4893, 0x0040, 0x1a76, 0x7824, 0xc0f5, 0x7826, 0x0f7f, 0x682b,
+	0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c, 0x6912,
+	0x6980, 0x6916, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000,
+	0x7004, 0xa00d, 0x0040, 0x1a97, 0x6808, 0x8001, 0x680a, 0x00c0,
+	0x1a97, 0x7004, 0x2060, 0x2009, 0x0048, 0x1078, 0x756c, 0x1078,
+	0x179f, 0x0078, 0x1aad, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004,
+	0x2060, 0x6010, 0xa005, 0x0040, 0x1a97, 0x2068, 0x6808, 0x8000,
+	0x680a, 0x6c28, 0x6b2c, 0x1078, 0x17be, 0x017f, 0x007f, 0x127f,
+	0x007c, 0x127e, 0x2091, 0x2100, 0x7000, 0xa086, 0x0003, 0x00c0,
+	0x1ac4, 0x700c, 0x7110, 0xa106, 0x0040, 0x1ac4, 0x20e1, 0x9028,
+	0x700f, 0xa5e7, 0x7013, 0xa5e7, 0x127f, 0x007c, 0x0c7e, 0x1078,
+	0x1af7, 0x20e1, 0x9028, 0x700c, 0x7110, 0xa106, 0x0040, 0x1aed,
+	0x2104, 0xa005, 0x0040, 0x1ada, 0x2060, 0x6010, 0x2060, 0x6008,
+	0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xa602, 0x0048, 0x1ae2,
+	0x2009, 0xa5e7, 0x7112, 0x700c, 0xa106, 0x00c0, 0x1acb, 0x2001,
+	0x0138, 0x2003, 0x0008, 0x0078, 0x1acb, 0x2001, 0x015d, 0x200c,
+	0x810a, 0x2102, 0x2001, 0x0138, 0x2202, 0x0c7f, 0x007c, 0x2001,
+	0x0138, 0x2014, 0x2003, 0x0000, 0x2021, 0xb015, 0x2001, 0x0141,
+	0x201c, 0xd3dc, 0x00c0, 0x1b14, 0x2001, 0x0109, 0x201c, 0xa39c,
+	0x0048, 0x00c0, 0x1b14, 0x2001, 0x0111, 0x201c, 0x83ff, 0x00c0,
+	0x1b14, 0x8421, 0x00c0, 0x1afe, 0x007c, 0x2011, 0x0201, 0x2009,
+	0x003c, 0x2204, 0xa005, 0x00c0, 0x1b21, 0x8109, 0x00c0, 0x1b19,
+	0x007c, 0x007c, 0x1078, 0x1b15, 0x0040, 0x1b4a, 0x7908, 0xd1ec,
+	0x00c0, 0x1b3a, 0x1078, 0x1b81, 0x0040, 0x1b3a, 0x7803, 0x0009,
+	0x7904, 0xd1fc, 0x0040, 0x1b30, 0x7803, 0x0006, 0x1078, 0x1b15,
+	0x0040, 0x1b4a, 0x780c, 0xd0a4, 0x00c0, 0x1b4a, 0x7007, 0x0000,
+	0x1078, 0x1b81, 0x0040, 0x1b4c, 0x7803, 0x0019, 0x7003, 0x0003,
+	0x0078, 0x1b4c, 0x1078, 0x1ac6, 0x007c, 0x0e7e, 0x2071, 0x0200,
+	0x7808, 0xa084, 0xf000, 0xa10d, 0x1078, 0x1af7, 0x2019, 0x5000,
+	0x8319, 0x0040, 0x1b6b, 0x2001, 0xa602, 0x2004, 0xa086, 0x0000,
+	0x0040, 0x1b6b, 0x2001, 0x0021, 0xd0fc, 0x0040, 0x1b58, 0x1078,
+	0x1e5d, 0x0078, 0x1b56, 0x20e1, 0x7000, 0x7324, 0x7420, 0x7028,
+	0x7028, 0x7426, 0x7037, 0x0001, 0x810f, 0x712e, 0x702f, 0x0100,
+	0x7037, 0x0008, 0x7326, 0x7422, 0x2001, 0x0138, 0x2202, 0x0e7f,
+	0x007c, 0x7908, 0xa18c, 0x0fff, 0xa182, 0x0009, 0x0048, 0x1b8c,
+	0xa085, 0x0001, 0x0078, 0x1b9e, 0x2001, 0x020a, 0x81ff, 0x0040,
+	0x1b97, 0x20e1, 0x6000, 0x200c, 0x200c, 0x200c, 0x200c, 0x20e1,
+	0x7000, 0x200c, 0x200c, 0x7003, 0x0000, 0xa006, 0x007c, 0x7c20,
+	0x7d24, 0x7e30, 0x7f34, 0x700c, 0x7110, 0xa106, 0x0040, 0x1c24,
+	0x7004, 0x017e, 0x210c, 0xa106, 0x017f, 0x0040, 0x1c24, 0x0d7e,
+	0x0c7e, 0x216c, 0x2d00, 0xa005, 0x0040, 0x1c22, 0x6824, 0xd0d4,
+	0x00c0, 0x1c22, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x0040, 0x1bec,
+	0x8108, 0x2104, 0x6b2c, 0xa306, 0x00c0, 0x1c22, 0x8108, 0x2104,
+	0x6a28, 0xa206, 0x00c0, 0x1c22, 0x6850, 0xc0fc, 0xc0f5, 0x6852,
+	0x686c, 0x7822, 0x6870, 0x7826, 0x681c, 0x7832, 0x6820, 0x7836,
+	0x6818, 0x2060, 0x6034, 0xd09c, 0x0040, 0x1be7, 0x6830, 0x2004,
+	0xac68, 0x6808, 0x783a, 0x680c, 0x783e, 0x0078, 0x1c20, 0xa006,
+	0x783a, 0x783e, 0x0078, 0x1c20, 0x8108, 0x2104, 0xa005, 0x00c0,
+	0x1c22, 0x8108, 0x2104, 0xa005, 0x00c0, 0x1c22, 0x6850, 0xc0f5,
+	0x6852, 0x6830, 0x2004, 0x6918, 0xa160, 0xa180, 0x000d, 0x2004,
+	0xd09c, 0x00c0, 0x1c12, 0x6008, 0x7822, 0x686e, 0x600c, 0x7826,
+	0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0xa006, 0x783a, 0x783e,
+	0x0078, 0x1c20, 0x6010, 0x7822, 0x686e, 0x6014, 0x7826, 0x6872,
+	0x6000, 0x7832, 0x6004, 0x7836, 0x6008, 0x783a, 0x600c, 0x783e,
+	0x7803, 0x0011, 0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e, 0x017e,
+	0x027e, 0x2071, 0xa5e1, 0x2079, 0x0030, 0x2011, 0x0050, 0x7000,
+	0xa086, 0x0000, 0x0040, 0x1c4d, 0x8211, 0x0040, 0x1c4b, 0x2001,
+	0x0005, 0x2004, 0xd08c, 0x0040, 0x1c34, 0x7904, 0xa18c, 0x0780,
+	0x017e, 0x1078, 0x18e2, 0x017f, 0x81ff, 0x00c0, 0x1c4b, 0x2011,
+	0x0050, 0x0078, 0x1c2f, 0xa085, 0x0001, 0x027f, 0x017f, 0x0e7f,
+	0x0f7f, 0x007c, 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac,
+	0x0040, 0x1ca3, 0x8109, 0x00c0, 0x1c56, 0x2009, 0x0100, 0x210c,
+	0xa18a, 0x0003, 0x1048, 0x1328, 0x1078, 0x1f75, 0x0e7e, 0x0f7e,
+	0x2071, 0xa5d0, 0x2079, 0x0010, 0x7004, 0xa086, 0x0000, 0x0040,
+	0x1c9b, 0x7800, 0x007e, 0x7820, 0x007e, 0x7830, 0x007e, 0x7834,
+	0x007e, 0x7838, 0x007e, 0x783c, 0x007e, 0x7803, 0x0004, 0x7823,
+	0x0000, 0x0005, 0x0005, 0x2079, 0x0030, 0x7804, 0xd0ac, 0x10c0,
+	0x1328, 0x2079, 0x0010, 0x007f, 0x783e, 0x007f, 0x783a, 0x007f,
+	0x7836, 0x007f, 0x7832, 0x007f, 0x7822, 0x007f, 0x7802, 0x0f7f,
+	0x0e7f, 0x0078, 0x1ca1, 0x0f7f, 0x0e7f, 0x7804, 0xd0ac, 0x10c0,
+	0x1328, 0x1078, 0x61d3, 0x007c, 0x0e7e, 0x2071, 0xa602, 0x7003,
+	0x0000, 0x0e7f, 0x007c, 0x0d7e, 0xa280, 0x0004, 0x206c, 0x694c,
+	0xd1dc, 0x00c0, 0x1d26, 0x6934, 0xa184, 0x0007, 0x0079, 0x1cb8,
+	0x1cc0, 0x1d11, 0x1cc0, 0x1cc0, 0x1cc0, 0x1cf6, 0x1cd3, 0x1cc2,
+	0x1078, 0x1328, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e,
+	0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e,
+	0x6958, 0x0078, 0x1d19, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e,
+	0x00c0, 0x1cc0, 0x684c, 0xd0b4, 0x0040, 0x1e34, 0x6860, 0x682e,
+	0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880, 0x680e,
+	0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080,
+	0x2015, 0x2004, 0x6832, 0x6958, 0x0078, 0x1d22, 0xa18c, 0x00ff,
+	0xa186, 0x0015, 0x00c0, 0x1d26, 0x684c, 0xd0b4, 0x0040, 0x1e34,
+	0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080,
+	0x2015, 0x2004, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0078,
+	0x1d22, 0x684c, 0xd0b4, 0x0040, 0x18bc, 0x6958, 0xa006, 0x682e,
+	0x682a, 0x2d00, 0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x2015,
+	0x2004, 0x6832, 0x6926, 0x684c, 0xc0dd, 0x684e, 0x0d7f, 0x007c,
+	0x0f7e, 0x2079, 0x0020, 0x7804, 0xd0fc, 0x10c0, 0x1e5d, 0x0e7e,
+	0x0d7e, 0x2071, 0xa602, 0x7000, 0xa005, 0x00c0, 0x1dab, 0x0c7e,
+	0x7206, 0xa280, 0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004,
+	0x6818, 0x0d7e, 0x2068, 0x686c, 0x7812, 0x6890, 0x0f7e, 0x20e1,
+	0x9040, 0x2079, 0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6,
+	0x0f7f, 0x0d7f, 0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830,
+	0x2040, 0x6034, 0xa0cc, 0x000f, 0x6908, 0x2001, 0x04fd, 0x2004,
+	0xa086, 0x0007, 0x0040, 0x1d6d, 0xa184, 0x0007, 0x0040, 0x1d6d,
+	0x017e, 0x2009, 0x0008, 0xa102, 0x017f, 0xa108, 0x791a, 0x7116,
+	0x701e, 0x680c, 0xa081, 0x0000, 0x781e, 0x701a, 0xa006, 0x700e,
+	0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x00c0, 0x1d84, 0x6928,
+	0x6810, 0xa106, 0x0040, 0x1d91, 0x037e, 0x047e, 0x6b14, 0x6c10,
+	0x1078, 0x2035, 0x047f, 0x037f, 0x0040, 0x1d91, 0x0c7f, 0x0078,
+	0x1dab, 0x8aff, 0x00c0, 0x1d99, 0x0c7f, 0xa085, 0x0001, 0x0078,
+	0x1dab, 0x127e, 0x2091, 0x8000, 0x2079, 0x0020, 0x2009, 0x0001,
+	0x1078, 0x1daf, 0x0040, 0x1da8, 0x2009, 0x0001, 0x1078, 0x1daf,
+	0x127f, 0x0c7f, 0xa006, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x077e,
+	0x067e, 0x057e, 0x047e, 0x037e, 0x027e, 0x8aff, 0x0040, 0x1e2d,
+	0x700c, 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0048, 0x1e2c,
+	0xa705, 0x0040, 0x1e2c, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x00c0,
+	0x1ddf, 0x0d7e, 0x2804, 0xac68, 0x2900, 0x0079, 0x1dcf, 0x1e0e,
+	0x1def, 0x1def, 0x1e0e, 0x1e0e, 0x1e06, 0x1e0e, 0x1def, 0x1e0e,
+	0x1df5, 0x1df5, 0x1e0e, 0x1e0e, 0x1e0e, 0x1dfd, 0x1df5, 0xc0fc,
+	0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0040, 0x1e12,
+	0x0d7e, 0x2804, 0xac68, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x6b08,
+	0x6a0c, 0x6d00, 0x6c04, 0x0078, 0x1e11, 0x6b10, 0x6a14, 0x6d00,
+	0x6c04, 0x6f08, 0x6e0c, 0x0078, 0x1e11, 0x0d7f, 0x0d7e, 0x6834,
+	0xa084, 0x00ff, 0xa086, 0x001e, 0x00c0, 0x1e0e, 0x0d7f, 0x1078,
+	0x1fd1, 0x00c0, 0x1db5, 0xa00e, 0x0078, 0x1e2d, 0x0d7f, 0x1078,
+	0x1328, 0x0d7f, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a, 0x7e3e,
+	0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a, 0x682c,
+	0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201, 0x7012,
+	0x1078, 0x1fd1, 0x0078, 0x1e2d, 0xa006, 0x027f, 0x037f, 0x047f,
+	0x057f, 0x067f, 0x077f, 0x007c, 0x1078, 0x1328, 0x027e, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x7004, 0x2060, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44,
+	0x0040, 0x1e4d, 0x6850, 0xc0bd, 0x6852, 0x0d7f, 0x1078, 0x8758,
+	0x20e1, 0x9040, 0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc,
+	0x1078, 0x61d3, 0x027f, 0x0078, 0x1f29, 0x127e, 0x2091, 0x2200,
+	0x007e, 0x017e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x2079, 0x0020,
+	0x2071, 0xa602, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002,
+	0xa184, 0x0700, 0x00c0, 0x1e36, 0x7000, 0x0079, 0x1e77, 0x1f29,
+	0x1e7b, 0x1ef6, 0x1f27, 0x8001, 0x7002, 0xd19c, 0x00c0, 0x1e8f,
+	0x8aff, 0x0040, 0x1eae, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0040,
+	0x1f29, 0x2009, 0x0001, 0x1078, 0x1daf, 0x0078, 0x1f29, 0x7803,
+	0x0004, 0xd194, 0x0040, 0x1e9f, 0x6850, 0xc0fc, 0x6852, 0x8aff,
+	0x00c0, 0x1ea4, 0x684c, 0xc0f5, 0x684e, 0x0078, 0x1ea4, 0x1078,
+	0x1fea, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826, 0x2c00, 0x681a,
+	0x2800, 0x6832, 0x7003, 0x0000, 0x0078, 0x1f29, 0x711c, 0x81ff,
+	0x0040, 0x1ec4, 0x7918, 0x7922, 0x7827, 0x0000, 0x7803, 0x0001,
+	0x7000, 0x8000, 0x7002, 0x700c, 0xa100, 0x700e, 0x7010, 0xa081,
+	0x0000, 0x7012, 0x0078, 0x1f29, 0x0f7e, 0x027e, 0x781c, 0x007e,
+	0x7818, 0x007e, 0x2079, 0x0100, 0x7a14, 0xa284, 0x0004, 0xa085,
+	0x0012, 0x7816, 0x037e, 0x2019, 0x1000, 0x8319, 0x1040, 0x1328,
+	0x7820, 0xd0bc, 0x00c0, 0x1ed5, 0x037f, 0x79c8, 0x007f, 0xa102,
+	0x017f, 0x007e, 0x017e, 0x79c4, 0x007f, 0xa103, 0x78c6, 0x007f,
+	0x78ca, 0xa284, 0x0004, 0xa085, 0x0012, 0x7816, 0x027f, 0x0f7f,
+	0x7803, 0x0008, 0x7003, 0x0000, 0x0078, 0x1f29, 0x8001, 0x7002,
+	0xd194, 0x0040, 0x1f0b, 0x7804, 0xd0fc, 0x00c0, 0x1e6d, 0xd19c,
+	0x00c0, 0x1f25, 0x8aff, 0x0040, 0x1f29, 0x2009, 0x0001, 0x1078,
+	0x1daf, 0x0078, 0x1f29, 0x027e, 0x037e, 0x6b28, 0x6a2c, 0x1078,
+	0x1fea, 0x0d7e, 0x2804, 0xac68, 0x6034, 0xd09c, 0x00c0, 0x1f1e,
+	0x6808, 0xa31a, 0x680c, 0xa213, 0x0078, 0x1f22, 0x6810, 0xa31a,
+	0x6814, 0xa213, 0x0d7f, 0x0078, 0x1e9f, 0x0078, 0x1e9f, 0x1078,
+	0x1328, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x017f, 0x007f, 0x127f,
+	0x007c, 0x0f7e, 0x0e7e, 0x2071, 0xa602, 0x7000, 0xa086, 0x0000,
+	0x0040, 0x1f72, 0x2079, 0x0020, 0x017e, 0x2009, 0x0207, 0x210c,
+	0xd194, 0x0040, 0x1f4f, 0x2009, 0x020c, 0x210c, 0xa184, 0x0003,
+	0x0040, 0x1f4f, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102, 0x2009,
+	0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x00c0, 0x1f5a,
+	0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0040, 0x1f3d, 0x1078, 0x1e5d,
+	0x7000, 0xa086, 0x0000, 0x00c0, 0x1f3d, 0x017f, 0x7803, 0x0004,
+	0x7804, 0xd0ac, 0x00c0, 0x1f68, 0x20e1, 0x9040, 0x7803, 0x0002,
+	0x7003, 0x0000, 0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x0c7e, 0x0d7e,
+	0x0e7e, 0x0f7e, 0x2071, 0xa602, 0x2079, 0x0020, 0x7000, 0xa086,
+	0x0000, 0x0040, 0x1fae, 0x7004, 0x2060, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x1f98, 0x6850, 0xc0b5, 0x6852, 0x680c, 0x7a1c,
+	0xa206, 0x00c0, 0x1f98, 0x6808, 0x7a18, 0xa206, 0x0040, 0x1fb4,
+	0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004,
+	0x7003, 0x0000, 0x7004, 0x2060, 0x1078, 0x8758, 0x20e1, 0x9040,
+	0x1078, 0x719a, 0x2011, 0x0000, 0x1078, 0x6efc, 0x0f7f, 0x0e7f,
+	0x0d7f, 0x0c7f, 0x027f, 0x007c, 0x6810, 0x6a14, 0xa205, 0x00c0,
+	0x1f98, 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x1078, 0x1cab, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x2069, 0xa5ab, 0x6833, 0x0000, 0x683f, 0x0000, 0x0078,
+	0x1fae, 0x8840, 0x2804, 0xa005, 0x00c0, 0x1fe5, 0x6004, 0xa005,
+	0x0040, 0x1fe7, 0x681a, 0x2060, 0x6034, 0xa084, 0x000f, 0xa080,
+	0x2015, 0x2044, 0x88ff, 0x1040, 0x1328, 0x8a51, 0x007c, 0x2051,
+	0x0000, 0x007c, 0x8a50, 0x8841, 0x2804, 0xa005, 0x00c0, 0x2004,
+	0x2c00, 0xad06, 0x0040, 0x1ff9, 0x6000, 0xa005, 0x00c0, 0x1ff9,
+	0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080, 0x2025,
+	0x2044, 0x88ff, 0x1040, 0x1328, 0x007c, 0x0000, 0x0011, 0x0015,
+	0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f, 0x0015,
+	0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x200a, 0x2006,
+	0x0000, 0x0000, 0x2014, 0x0000, 0x200a, 0x0000, 0x2011, 0x200e,
+	0x0000, 0x0000, 0x0000, 0x2014, 0x2011, 0x0000, 0x200c, 0x200c,
+	0x0000, 0x0000, 0x2014, 0x0000, 0x200c, 0x0000, 0x2012, 0x2012,
+	0x0000, 0x0000, 0x0000, 0x2014, 0x2012, 0x0a7e, 0x097e, 0x087e,
+	0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0040, 0x20d8, 0x2d60, 0x6034,
+	0xa0cc, 0x000f, 0xa9c0, 0x2015, 0xa986, 0x0007, 0x0040, 0x2050,
+	0xa986, 0x000e, 0x0040, 0x2050, 0xa986, 0x000f, 0x00c0, 0x2054,
+	0x605c, 0xa422, 0x6060, 0xa31a, 0x2804, 0xa045, 0x00c0, 0x2062,
+	0x0050, 0x205c, 0x0078, 0x20d8, 0x6004, 0xa065, 0x0040, 0x20d8,
+	0x0078, 0x203f, 0x2804, 0xa005, 0x0040, 0x2080, 0xac68, 0xd99c,
+	0x00c0, 0x2070, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0078, 0x2074,
+	0x6810, 0xa422, 0x6814, 0xa31b, 0x0048, 0x209f, 0x2300, 0xa405,
+	0x0040, 0x2086, 0x8a51, 0x0040, 0x20d8, 0x8840, 0x0078, 0x2062,
+	0x6004, 0xa065, 0x0040, 0x20d8, 0x0078, 0x203f, 0x8a51, 0x0040,
+	0x20d8, 0x8840, 0x2804, 0xa005, 0x00c0, 0x2099, 0x6004, 0xa065,
+	0x0040, 0x20d8, 0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x2015, 0x2804,
+	0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852, 0x0078, 0x20cc, 0x8422,
+	0x8420, 0x831a, 0xa399, 0x0000, 0x0d7e, 0x2b68, 0x6c6e, 0x6b72,
+	0x0d7f, 0xd99c, 0x00c0, 0x20ba, 0x6908, 0x2400, 0xa122, 0x690c,
+	0x2300, 0xa11b, 0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319,
+	0x0078, 0x20c6, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b,
+	0x1048, 0x1328, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e,
+	0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832,
+	0x2a00, 0x6826, 0x007f, 0x007f, 0x007f, 0xa006, 0x0078, 0x20dd,
+	0x087f, 0x097f, 0x0a7f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0005,
+	0x2004, 0xa084, 0x0007, 0x0079, 0x20e5, 0x20ed, 0x20ee, 0x20f1,
+	0x20f4, 0x20f9, 0x20fc, 0x2101, 0x2106, 0x007c, 0x1078, 0x1e5d,
+	0x007c, 0x1078, 0x18e2, 0x007c, 0x1078, 0x18e2, 0x1078, 0x1e5d,
+	0x007c, 0x1078, 0x14b0, 0x007c, 0x1078, 0x1e5d, 0x1078, 0x14b0,
+	0x007c, 0x1078, 0x18e2, 0x1078, 0x14b0, 0x007c, 0x1078, 0x18e2,
+	0x1078, 0x1e5d, 0x1078, 0x14b0, 0x007c, 0x127e, 0x2091, 0x2300,
+	0x2079, 0x0200, 0x2071, 0xa880, 0x2069, 0xa300, 0x2009, 0x0004,
+	0x7912, 0x7817, 0x0004, 0x1078, 0x24b5, 0x781b, 0x0002, 0x20e1,
+	0x8700, 0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x781c, 0xa084,
+	0x0007, 0x0079, 0x212b, 0x214f, 0x2133, 0x2137, 0x213b, 0x2141,
+	0x2145, 0x2149, 0x214d, 0x1078, 0x5372, 0x0078, 0x214f, 0x1078,
+	0x53b3, 0x0078, 0x214f, 0x1078, 0x5372, 0x1078, 0x53b3, 0x0078,
+	0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x0078,
+	0x214f, 0x1078, 0x2151, 0x0078, 0x214f, 0x1078, 0x2151, 0x127f,
+	0x007c, 0x007e, 0x017e, 0x027e, 0x7930, 0xa184, 0x0003, 0x0040,
+	0x215d, 0x20e1, 0x9040, 0x0078, 0x2186, 0xa184, 0x0030, 0x0040,
+	0x216e, 0x6a00, 0xa286, 0x0003, 0x00c0, 0x2168, 0x0078, 0x216a,
+	0x1078, 0x4171, 0x20e1, 0x9010, 0x0078, 0x2186, 0xa184, 0x00c0,
+	0x0040, 0x2180, 0x0e7e, 0x037e, 0x047e, 0x057e, 0x2071, 0xa5e1,
+	0x1078, 0x1ac6, 0x057f, 0x047f, 0x037f, 0x0e7f, 0x0078, 0x2186,
+	0xa184, 0x0300, 0x0040, 0x2186, 0x20e1, 0x9020, 0x7932, 0x027f,
+	0x017f, 0x007f, 0x007c, 0x017e, 0x0e7e, 0x0f7e, 0x2071, 0xa300,
+	0x7128, 0x2001, 0xa58f, 0x2102, 0x2001, 0xa597, 0x2102, 0xa182,
+	0x0211, 0x00c8, 0x219f, 0x2009, 0x0008, 0x0078, 0x21c9, 0xa182,
+	0x0259, 0x00c8, 0x21a7, 0x2009, 0x0007, 0x0078, 0x21c9, 0xa182,
+	0x02c1, 0x00c8, 0x21af, 0x2009, 0x0006, 0x0078, 0x21c9, 0xa182,
+	0x0349, 0x00c8, 0x21b7, 0x2009, 0x0005, 0x0078, 0x21c9, 0xa182,
+	0x0421, 0x00c8, 0x21bf, 0x2009, 0x0004, 0x0078, 0x21c9, 0xa182,
+	0x0581, 0x00c8, 0x21c7, 0x2009, 0x0003, 0x0078, 0x21c9, 0x2009,
+	0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x1078, 0x24b5,
+	0x0f7f, 0x0e7f, 0x017f, 0x007c, 0x127e, 0x2091, 0x2200, 0x2061,
+	0x0100, 0x2071, 0xa300, 0x6024, 0x6026, 0x6053, 0x0030, 0x6033,
+	0x00ef, 0x60e7, 0x0000, 0x60eb, 0x00ef, 0x60e3, 0x0008, 0x604b,
+	0xf7f7, 0x6043, 0x0000, 0x602f, 0x0080, 0x602f, 0x0000, 0x6007,
+	0x0eaf, 0x600f, 0x00ff, 0x602b, 0x002f, 0x127f, 0x007c, 0x2001,
+	0xa32f, 0x2003, 0x0000, 0x2001, 0xa32e, 0x2003, 0x0001, 0x007c,
+	0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e, 0x6124, 0xa184,
+	0x002c, 0x00c0, 0x220f, 0xa184, 0x0007, 0x0079, 0x2215, 0xa195,
+	0x0004, 0xa284, 0x0007, 0x0079, 0x2215, 0x2241, 0x221d, 0x2221,
+	0x2225, 0x222b, 0x222f, 0x2235, 0x223b, 0x1078, 0x5ad2, 0x0078,
+	0x2241, 0x1078, 0x5bc1, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078,
+	0x5ad2, 0x0078, 0x2241, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078,
+	0x5ad2, 0x1078, 0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078,
+	0x2246, 0x0078, 0x2241, 0x1078, 0x5bc1, 0x1078, 0x5ad2, 0x1078,
+	0x2246, 0x027f, 0x017f, 0x007f, 0x127f, 0x007c, 0x6124, 0xd1ac,
+	0x0040, 0x2342, 0x017e, 0x047e, 0x0c7e, 0x644c, 0xa486, 0xf0f0,
+	0x00c0, 0x2259, 0x2061, 0x0100, 0x644a, 0x6043, 0x0090, 0x6043,
+	0x0010, 0x74c2, 0xa48c, 0xff00, 0x7034, 0xd084, 0x0040, 0x2271,
+	0xa186, 0xf800, 0x00c0, 0x2271, 0x7038, 0xd084, 0x00c0, 0x2271,
+	0xc085, 0x703a, 0x037e, 0x2418, 0x2011, 0x8016, 0x1078, 0x3579,
+	0x037f, 0xa196, 0xff00, 0x0040, 0x22b3, 0x6030, 0xa084, 0x00ff,
+	0x810f, 0xa116, 0x0040, 0x22b3, 0x7130, 0xd184, 0x00c0, 0x22b3,
+	0x2011, 0xa352, 0x2214, 0xd2ec, 0x0040, 0x228e, 0xc18d, 0x7132,
+	0x2011, 0xa352, 0x2214, 0xd2ac, 0x00c0, 0x22b3, 0x6240, 0xa294,
+	0x0010, 0x0040, 0x229a, 0x6248, 0xa294, 0xff00, 0xa296, 0xff00,
+	0x0040, 0x22b3, 0x7030, 0xd08c, 0x0040, 0x2305, 0x7034, 0xd08c,
+	0x00c0, 0x22aa, 0x2001, 0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305,
+	0xc1ad, 0x2102, 0x037e, 0x73c0, 0x2011, 0x8013, 0x1078, 0x3579,
+	0x037f, 0x0078, 0x2305, 0x7034, 0xd08c, 0x00c0, 0x22bf, 0x2001,
+	0xa30c, 0x200c, 0xd1ac, 0x00c0, 0x2305, 0xc1ad, 0x2102, 0x037e,
+	0x73c0, 0x2011, 0x8013, 0x1078, 0x3579, 0x037f, 0x7130, 0xc185,
+	0x7132, 0x2011, 0xa352, 0x220c, 0xd1a4, 0x0040, 0x22e9, 0x017e,
+	0x2009, 0x0001, 0x2011, 0x0100, 0x1078, 0x5a6d, 0x2019, 0x000e,
+	0x1078, 0x9e3b, 0xa484, 0x00ff, 0xa080, 0x293f, 0x200c, 0xa18c,
+	0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x1078, 0x9ec0,
+	0x017f, 0xd1ac, 0x00c0, 0x22f6, 0x017e, 0x2009, 0x0000, 0x2019,
+	0x0004, 0x1078, 0x27e2, 0x017f, 0x0078, 0x2305, 0x157e, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0x1078, 0x4501, 0x00c0, 0x2301, 0x1078,
+	0x4235, 0x8108, 0x00f0, 0x22fb, 0x157f, 0x0c7f, 0x047f, 0x0f7e,
+	0x2079, 0xa5be, 0x783c, 0xa086, 0x0000, 0x0040, 0x2317, 0x6027,
+	0x0004, 0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x0000, 0x0f7f,
+	0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011, 0x0002, 0x1078, 0x6efc,
+	0x1078, 0x6dda, 0x1078, 0x595a, 0x037e, 0x2019, 0x0000, 0x1078,
+	0x6e6c, 0x037f, 0x60e3, 0x0000, 0x017f, 0x2001, 0xa300, 0x2014,
+	0xa296, 0x0004, 0x00c0, 0x233a, 0xd19c, 0x00c0, 0x233a, 0x6228,
+	0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xa321, 0x2003, 0x0000,
+	0x6027, 0x0020, 0xd194, 0x0040, 0x2426, 0x0f7e, 0x2079, 0xa5be,
+	0x783c, 0xa086, 0x0001, 0x00c0, 0x2366, 0x017e, 0x6027, 0x0004,
+	0x783f, 0x0000, 0x2079, 0x0140, 0x7803, 0x1000, 0x7803, 0x0000,
+	0x2079, 0xa5ab, 0x7807, 0x0000, 0x7833, 0x0000, 0x1078, 0x6109,
+	0x1078, 0x61d3, 0x017f, 0x0f7f, 0x0078, 0x2426, 0x0f7f, 0x017e,
+	0x3900, 0xa082, 0xa6cd, 0x00c8, 0x2371, 0x017e, 0x1078, 0x728a,
+	0x017f, 0x6220, 0xd2b4, 0x0040, 0x23dc, 0x1078, 0x595a, 0x1078,
+	0x6c41, 0x6027, 0x0004, 0x0f7e, 0x2019, 0xa5b4, 0x2304, 0xa07d,
+	0x0040, 0x23b2, 0x7804, 0xa086, 0x0032, 0x00c0, 0x23b2, 0x0d7e,
+	0x0c7e, 0x0e7e, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e,
+	0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x00c0,
+	0x2396, 0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e,
+	0x628a, 0x1078, 0x6010, 0x1078, 0x6109, 0x7810, 0x2070, 0x7037,
+	0x0103, 0x2f60, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0d7f, 0x0f7f,
+	0x017f, 0x007c, 0x0f7f, 0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084,
+	0x4000, 0x0040, 0x23bf, 0x6803, 0x1000, 0x6803, 0x0000, 0x0d7f,
+	0x0c7e, 0x2061, 0xa5ab, 0x6028, 0xa09a, 0x00c8, 0x00c8, 0x23cf,
+	0x8000, 0x602a, 0x0c7f, 0x1078, 0x6c33, 0x0078, 0x2425, 0x2019,
+	0xa5b4, 0x2304, 0xa065, 0x0040, 0x23d9, 0x2009, 0x0027, 0x1078,
+	0x756c, 0x0c7f, 0x0078, 0x2425, 0xd2bc, 0x0040, 0x2425, 0x1078,
+	0x5967, 0x6017, 0x0010, 0x6027, 0x0004, 0x0d7e, 0x2069, 0x0140,
+	0x6804, 0xa084, 0x4000, 0x0040, 0x23f1, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x0d7f, 0x0c7e, 0x2061, 0xa5ab, 0x6044, 0xa09a, 0x00c8,
+	0x00c8, 0x2414, 0x8000, 0x6046, 0x603c, 0x0c7f, 0xa005, 0x0040,
+	0x2425, 0x2009, 0x07d0, 0x1078, 0x595f, 0xa080, 0x0007, 0x2004,
+	0xa086, 0x0006, 0x00c0, 0x2410, 0x6017, 0x0012, 0x0078, 0x2425,
+	0x6017, 0x0016, 0x0078, 0x2425, 0x037e, 0x2019, 0x0001, 0x1078,
+	0x6e6c, 0x037f, 0x2019, 0xa5ba, 0x2304, 0xa065, 0x0040, 0x2424,
+	0x2009, 0x004f, 0x1078, 0x756c, 0x0c7f, 0x017f, 0xd19c, 0x0040,
+	0x247c, 0x7034, 0xd0ac, 0x00c0, 0x2457, 0x017e, 0x157e, 0x6027,
+	0x0008, 0x602f, 0x0020, 0x20a9, 0x000a, 0x00f0, 0x2435, 0x602f,
+	0x0000, 0x6150, 0xa185, 0x1400, 0x6052, 0x20a9, 0x0320, 0x00e0,
+	0x243f, 0x2091, 0x6000, 0x6020, 0xd09c, 0x00c0, 0x244e, 0x157f,
+	0x6152, 0x017f, 0x6027, 0x0008, 0x0078, 0x247c, 0x1078, 0x250d,
+	0x00f0, 0x243f, 0x157f, 0x6152, 0x017f, 0x6027, 0x0008, 0x017e,
+	0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x1078, 0x6ef2, 0x2011,
+	0x0002, 0x1078, 0x6efc, 0x1078, 0x6dda, 0x1078, 0x595a, 0x037e,
+	0x2019, 0x0000, 0x1078, 0x6e6c, 0x037f, 0x60e3, 0x0000, 0x1078,
+	0xa22a, 0x1078, 0xa248, 0x2001, 0xa300, 0x2003, 0x0004, 0x6027,
+	0x0008, 0x1078, 0x1246, 0x017f, 0xa18c, 0xffd0, 0x6126, 0x007c,
+	0x007e, 0x017e, 0x027e, 0x0e7e, 0x0f7e, 0x127e, 0x2091, 0x8000,
+	0x2071, 0xa300, 0x71b8, 0x70ba, 0xa116, 0x0040, 0x24ae, 0x81ff,
+	0x0040, 0x2498, 0x2011, 0x8011, 0x1078, 0x3579, 0x0078, 0x24ae,
+	0x2011, 0x8012, 0x1078, 0x3579, 0x2001, 0xa371, 0x2004, 0xd0fc,
+	0x00c0, 0x24ae, 0x037e, 0x0c7e, 0x2061, 0x0100, 0x2019, 0x0028,
+	0x2009, 0x0000, 0x1078, 0x27e2, 0x0c7f, 0x037f, 0x127f, 0x0f7f,
+	0x0e7f, 0x027f, 0x017f, 0x007f, 0x007c, 0x0c7e, 0x0f7e, 0x007e,
+	0x027e, 0x2061, 0x0100, 0xa190, 0x24d1, 0x2204, 0x60f2, 0x2011,
+	0x24de, 0x6000, 0xa082, 0x0003, 0x00c8, 0x24ca, 0x2001, 0x00ff,
+	0x0078, 0x24cb, 0x2204, 0x60ee, 0x027f, 0x007f, 0x0f7f, 0x0c7f,
+	0x007c, 0x0840, 0x0840, 0x0840, 0x0580, 0x0420, 0x0348, 0x02c0,
+	0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8, 0x01a8, 0x0140, 0x00f8,
+	0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c, 0x00ff, 0x2130, 0xa094,
+	0xff00, 0x00c0, 0x24ee, 0x81ff, 0x0040, 0x24f2, 0x1078, 0x5623,
+	0x0078, 0x24f9, 0xa080, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f,
+	0xa006, 0x007c, 0xa080, 0x293f, 0x200c, 0xa18c, 0x00ff, 0x007c,
+	0x0c7e, 0x2061, 0xa300, 0x6030, 0x0040, 0x2509, 0xc09d, 0x0078,
+	0x250a, 0xc09c, 0x6032, 0x0c7f, 0x007c, 0x007e, 0x157e, 0x0f7e,
+	0x2079, 0x0100, 0x20a9, 0x000a, 0x7854, 0xd08c, 0x00c0, 0x251a,
+	0x00f0, 0x2514, 0x0f7f, 0x157f, 0x007f, 0x007c, 0x0c7e, 0x007e,
+	0x2061, 0x0100, 0x6030, 0x007e, 0x6048, 0x007e, 0x60e4, 0x007e,
+	0x60e8, 0x007e, 0x6050, 0x007e, 0x60f0, 0x007e, 0x60ec, 0x007e,
+	0x600c, 0x007e, 0x6004, 0x007e, 0x6028, 0x007e, 0x60e0, 0x007e,
+	0x602f, 0x0100, 0x602f, 0x0000, 0x0005, 0x0005, 0x0005, 0x0005,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x007f, 0x60e2, 0x007f, 0x602a,
+	0x007f, 0x6006, 0x007f, 0x600e, 0x007f, 0x60ee, 0x007f, 0x60f2,
+	0x007f, 0x6052, 0x007f, 0x60ea, 0x007f, 0x60e6, 0x007f, 0x604a,
+	0x007f, 0x6032, 0x007f, 0x0c7f, 0x007c, 0x257d, 0x2581, 0x2585,
+	0x258b, 0x2591, 0x2597, 0x259d, 0x25a5, 0x25ad, 0x25b3, 0x25b9,
+	0x25c1, 0x25c9, 0x25d1, 0x25d9, 0x25e3, 0x25ed, 0x25ed, 0x25ed,
+	0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed,
+	0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x25ed, 0x107e, 0x007e, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078,
+	0x2200, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e,
+	0x007e, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078,
+	0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078,
+	0x2200, 0x1078, 0x20de, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078,
+	0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2123, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x2123, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x20de, 0x1078, 0x2123, 0x0078,
+	0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078, 0x20de, 0x1078,
+	0x2123, 0x0078, 0x2606, 0x107e, 0x007e, 0x1078, 0x2200, 0x1078,
+	0x20de, 0x1078, 0x2123, 0x0078, 0x2606, 0x0005, 0x0078, 0x25ed,
+	0xb084, 0x003c, 0x8004, 0x8004, 0x0079, 0x25f6, 0x2606, 0x2583,
+	0x2587, 0x258d, 0x2593, 0x2599, 0x259f, 0x25a7, 0x25af, 0x25b5,
+	0x25bb, 0x25c3, 0x25cb, 0x25d3, 0x25db, 0x25e5, 0x0008, 0x25f0,
+	0x007f, 0x107f, 0x2091, 0x8001, 0x007c, 0x0c7e, 0x027e, 0x047e,
+	0x2021, 0x0000, 0x1078, 0x4897, 0x00c0, 0x2705, 0x70c8, 0xd09c,
+	0x0040, 0x2624, 0xd084, 0x00c0, 0x2624, 0xd0bc, 0x00c0, 0x2705,
+	0x1078, 0x2709, 0x0078, 0x2705, 0xd094, 0x0040, 0x262b, 0x7093,
+	0xffff, 0x0078, 0x2705, 0x2001, 0x010c, 0x203c, 0x7280, 0xd284,
+	0x0040, 0x2694, 0xd28c, 0x00c0, 0x2694, 0x037e, 0x7390, 0xa38e,
+	0xffff, 0x0040, 0x263e, 0x83ff, 0x00c0, 0x2640, 0x2019, 0x0001,
+	0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xa38c, 0x0001, 0x0040, 0x264d,
+	0xa084, 0xff00, 0x8007, 0x0078, 0x264f, 0xa084, 0x00ff, 0xa70e,
+	0x0040, 0x2689, 0xa08e, 0x0000, 0x0040, 0x2689, 0xa08e, 0x00ff,
+	0x00c0, 0x2666, 0x7230, 0xd284, 0x00c0, 0x268f, 0x7280, 0xc28d,
+	0x7282, 0x7093, 0xffff, 0x037f, 0x0078, 0x2694, 0x2009, 0x0000,
+	0x1078, 0x24e3, 0x1078, 0x4499, 0x00c0, 0x268c, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x00c0, 0x2683, 0x7030, 0xd08c, 0x0040,
+	0x267d, 0x6000, 0xd0bc, 0x0040, 0x2683, 0x1078, 0x271f, 0x0040,
+	0x268c, 0x0078, 0x2689, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040,
+	0x268c, 0x8318, 0x0078, 0x2640, 0x7392, 0x0078, 0x2691, 0x7093,
+	0xffff, 0x037f, 0x0078, 0x2705, 0xa780, 0x293f, 0x203c, 0xa7bc,
+	0xff00, 0x873f, 0x2041, 0x007e, 0x7090, 0xa096, 0xffff, 0x00c0,
+	0x26a6, 0x2009, 0x0000, 0x28a8, 0x0078, 0x26b2, 0xa812, 0x0048,
+	0x26ae, 0x2008, 0xa802, 0x20a8, 0x0078, 0x26b2, 0x7093, 0xffff,
+	0x0078, 0x2705, 0x2700, 0x157e, 0x017e, 0xa106, 0x0040, 0x26f9,
+	0xc484, 0x1078, 0x4501, 0x0040, 0x26c3, 0x1078, 0x4499, 0x00c0,
+	0x2702, 0x0078, 0x26c4, 0xc485, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x00c0, 0x26d3, 0x7030, 0xd08c, 0x0040, 0x26f1, 0x6000,
+	0xd0bc, 0x00c0, 0x26f1, 0x7280, 0xd28c, 0x0040, 0x26e9, 0x6004,
+	0xa084, 0x00ff, 0xa082, 0x0006, 0x0048, 0x26f9, 0xd484, 0x00c0,
+	0x26e5, 0x1078, 0x44bc, 0x0078, 0x26e7, 0x1078, 0x2921, 0x0078,
+	0x26f9, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040, 0x2702, 0x0078,
+	0x26f9, 0x1078, 0x28ec, 0x0040, 0x26f9, 0x1078, 0x271f, 0x0040,
+	0x2702, 0x017f, 0x8108, 0x157f, 0x00f0, 0x26b2, 0x7093, 0xffff,
+	0x0078, 0x2705, 0x017f, 0x157f, 0x7192, 0x047f, 0x027f, 0x0c7f,
+	0x007c, 0x0c7e, 0x017e, 0x7093, 0x0000, 0x2009, 0x007e, 0x1078,
+	0x4499, 0x00c0, 0x271c, 0x1078, 0x2857, 0x1078, 0x274c, 0x0040,
+	0x271c, 0x70c8, 0xc0bd, 0x70ca, 0x017f, 0x0c7f, 0x007c, 0x017e,
+	0x077e, 0x0d7e, 0x0c7e, 0x2c68, 0x2001, 0xa356, 0x2004, 0xa084,
+	0x00ff, 0x6842, 0x1078, 0x74d7, 0x0040, 0x2747, 0x2d00, 0x601a,
+	0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0000,
+	0x1078, 0x443f, 0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e,
+	0x127f, 0x2009, 0x0004, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f,
+	0x0d7f, 0x077f, 0x017f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e,
+	0x2c68, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x1078,
+	0x74d7, 0x0040, 0x2785, 0x2d00, 0x601a, 0x6800, 0xc0c4, 0x6802,
+	0x68a0, 0xa086, 0x007e, 0x0040, 0x276e, 0x6804, 0xa084, 0x00ff,
+	0xa086, 0x0006, 0x00c0, 0x276e, 0x1078, 0x2813, 0x601f, 0x0001,
+	0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f,
+	0x127e, 0x2091, 0x8000, 0x708c, 0x8000, 0x708e, 0x127f, 0x2009,
+	0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f,
+	0x017f, 0x007c, 0x0c7e, 0x027e, 0x2009, 0x0080, 0x1078, 0x4499,
+	0x00c0, 0x2798, 0x1078, 0x279b, 0x0040, 0x2798, 0x70cf, 0xffff,
+	0x027f, 0x0c7f, 0x007c, 0x017e, 0x077e, 0x0d7e, 0x0c7e, 0x2c68,
+	0x1078, 0x74d7, 0x0040, 0x27bd, 0x2d00, 0x601a, 0x601f, 0x0001,
+	0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f,
+	0x127e, 0x2091, 0x8000, 0x70d0, 0x8000, 0x70d2, 0x127f, 0x2009,
+	0x0002, 0x1078, 0x756c, 0xa085, 0x0001, 0x0c7f, 0x0d7f, 0x077f,
+	0x017f, 0x007c, 0x0c7e, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2009,
+	0x007f, 0x1078, 0x4499, 0x00c0, 0x27de, 0x2c68, 0x1078, 0x74d7,
+	0x0040, 0x27de, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a,
+	0x2009, 0x0022, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0d7f,
+	0x0c7f, 0x007c, 0x0e7e, 0x0c7e, 0x067e, 0x037e, 0x027e, 0x1078,
+	0x5d60, 0x1078, 0x5d02, 0x1078, 0x7ddf, 0x2130, 0x81ff, 0x0040,
+	0x27f7, 0x20a9, 0x007e, 0x2009, 0x0000, 0x0078, 0x27fb, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0, 0x2804,
+	0x1078, 0x471b, 0x1078, 0x4235, 0x017f, 0x8108, 0x00f0, 0x27fb,
+	0x86ff, 0x00c0, 0x280d, 0x1078, 0x119b, 0x027f, 0x037f, 0x067f,
+	0x0c7f, 0x0e7f, 0x007c, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e,
+	0x6218, 0x2270, 0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53,
+	0x077e, 0x2039, 0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38,
+	0x077f, 0x017f, 0x2e60, 0x1078, 0x471b, 0x6210, 0x6314, 0x1078,
+	0x4235, 0x6212, 0x6316, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f,
+	0x007c, 0x0e7e, 0x007e, 0x6018, 0xa080, 0x0028, 0x2004, 0xd0bc,
+	0x00c0, 0x284d, 0x2071, 0xa300, 0x708c, 0xa005, 0x0040, 0x284a,
+	0x8001, 0x708e, 0x007f, 0x0e7f, 0x007c, 0x2071, 0xa300, 0x70d0,
+	0xa005, 0x0040, 0x284a, 0x8001, 0x70d2, 0x0078, 0x284a, 0x6000,
+	0xc08c, 0x6002, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x037e, 0x027e,
+	0x017e, 0x157e, 0x2178, 0x81ff, 0x00c0, 0x286a, 0x20a9, 0x0001,
+	0x0078, 0x2885, 0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x2881,
+	0xd0a4, 0x0040, 0x2881, 0x047e, 0x6018, 0xa080, 0x0028, 0x2024,
+	0xa4a4, 0x00ff, 0x8427, 0xa006, 0x2009, 0x002d, 0x1078, 0x9ec0,
+	0x047f, 0x20a9, 0x00ff, 0x2011, 0x0000, 0x027e, 0xa28e, 0x007e,
+	0x0040, 0x28c9, 0xa28e, 0x007f, 0x0040, 0x28c9, 0xa28e, 0x0080,
+	0x0040, 0x28c9, 0xa288, 0xa434, 0x210c, 0x81ff, 0x0040, 0x28c9,
+	0x8fff, 0x1040, 0x28d5, 0x0c7e, 0x2160, 0x2001, 0x0001, 0x1078,
+	0x48a2, 0x0c7f, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039,
+	0x0000, 0x1078, 0x5c78, 0x0c7e, 0x027e, 0x2160, 0x6204, 0xa294,
+	0x00ff, 0xa286, 0x0006, 0x00c0, 0x28b9, 0x6007, 0x0404, 0x0078,
+	0x28be, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206, 0x027f, 0x0c7f,
+	0x017e, 0x2c08, 0x1078, 0x9c38, 0x017f, 0x077f, 0x2160, 0x1078,
+	0x471b, 0x027f, 0x8210, 0x00f0, 0x2885, 0x157f, 0x017f, 0x027f,
+	0x037f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x047e, 0x027e, 0x017e,
+	0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x28e8, 0xd0a4, 0x0040,
+	0x28e8, 0xa006, 0x2220, 0x8427, 0x2009, 0x0029, 0x1078, 0x9ec0,
+	0x017f, 0x027f, 0x047f, 0x007c, 0x017e, 0x027e, 0x037e, 0x0c7e,
+	0x7280, 0x82ff, 0x0040, 0x291a, 0xa290, 0xa352, 0x2214, 0xd2ac,
+	0x00c0, 0x291a, 0x2100, 0x1078, 0x24fa, 0x81ff, 0x0040, 0x291c,
+	0x2019, 0x0001, 0x8314, 0xa2e0, 0xa9c0, 0x2c04, 0xd384, 0x0040,
+	0x290e, 0xa084, 0xff00, 0x8007, 0x0078, 0x2910, 0xa084, 0x00ff,
+	0xa116, 0x0040, 0x291c, 0xa096, 0x00ff, 0x0040, 0x291a, 0x8318,
+	0x0078, 0x2902, 0xa085, 0x0001, 0x0c7f, 0x037f, 0x027f, 0x017f,
+	0x007c, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0xa180, 0xa434,
+	0x2004, 0xa065, 0x0040, 0x293b, 0x017e, 0x0c7e, 0x1078, 0x8ec0,
+	0x017f, 0x1040, 0x1328, 0x611a, 0x1078, 0x2813, 0x1078, 0x753d,
+	0x017f, 0x1078, 0x44bc, 0x127f, 0x0c7f, 0x017f, 0x007c, 0x7eef,
+	0x7de8, 0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9,
+	0x80d6, 0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd,
+	0x80cc, 0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3,
+	0x80bc, 0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2,
+	0x80b1, 0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7,
+	0x6da6, 0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098,
+	0x6797, 0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080,
+	0x617c, 0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072,
+	0x8071, 0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067,
+	0x5a66, 0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055,
+	0x5454, 0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b,
+	0x4e4a, 0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a,
+	0x8039, 0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e,
+	0x472d, 0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025,
+	0x4123, 0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010,
+	0x3b0f, 0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800,
+	0x3700, 0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000,
+	0x8000, 0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000,
+	0x8000, 0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000,
+	0x2700, 0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000,
+	0x2100, 0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000,
+	0x1b00, 0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000,
+	0x1400, 0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000,
+	0x0e00, 0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000,
+	0x0800, 0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500,
+	0x0400, 0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071,
+	0xa381, 0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e,
+	0x7033, 0xa391, 0x7037, 0xa391, 0x7007, 0x0001, 0x2061, 0xa3d1,
+	0x6003, 0x0002, 0x007c, 0x0090, 0x2a66, 0x0068, 0x2a66, 0x2071,
+	0xa381, 0x2b78, 0x7818, 0xd084, 0x00c0, 0x2a66, 0x2a60, 0x7820,
+	0xa08e, 0x0069, 0x00c0, 0x2b56, 0x0079, 0x2aea, 0x007c, 0x2071,
+	0xa381, 0x7004, 0x0079, 0x2a6c, 0x2a70, 0x2a71, 0x2a7b, 0x2a8d,
+	0x007c, 0x0090, 0x2a7a, 0x0068, 0x2a7a, 0x2b78, 0x7818, 0xd084,
+	0x0040, 0x2a99, 0x007c, 0x2b78, 0x2061, 0xa3d1, 0x6008, 0xa08e,
+	0x0100, 0x0040, 0x2a88, 0xa086, 0x0200, 0x0040, 0x2b4e, 0x007c,
+	0x7014, 0x2068, 0x2a60, 0x7018, 0x007a, 0x7010, 0x2068, 0x6834,
+	0xa086, 0x0103, 0x0040, 0x2a95, 0x007c, 0x2a60, 0x2b78, 0x7018,
+	0x007a, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x00c8, 0x2aa2, 0x61b8,
+	0x0079, 0x2aaa, 0x2100, 0xa08a, 0x003f, 0x00c8, 0x2b4a, 0x61b8,
+	0x0079, 0x2aea, 0x2b2c, 0x2b5e, 0x2b66, 0x2b6a, 0x2b72, 0x2b78,
+	0x2b7c, 0x2b88, 0x2b8c, 0x2b96, 0x2b9a, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b9e, 0x2b4a, 0x2bae, 0x2bc5, 0x2bdc, 0x2c58, 0x2c5d, 0x2c8a,
+	0x2ce4, 0x2cf5, 0x2d13, 0x2d54, 0x2d5e, 0x2d6b, 0x2d7e, 0x2d9d,
+	0x2da6, 0x2de3, 0x2de9, 0x2b4a, 0x2e05, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2e0c, 0x2e16, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2e1e, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2e30, 0x2e47, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2e59, 0x2eb0, 0x2f0e, 0x2f1f, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x38f1, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2b96, 0x2b9a, 0x2f36, 0x2b4a, 0x2f43, 0x397d,
+	0x39da, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a,
+	0x2b4a, 0x2b4a, 0x2f90, 0x30c5, 0x30e1, 0x30ed, 0x3150, 0x31a9,
+	0x31b4, 0x31f3, 0x3202, 0x3211, 0x3214, 0x2f47, 0x3238, 0x3284,
+	0x3291, 0x33a2, 0x34cd, 0x34f7, 0x3604, 0x3614, 0x3621, 0x365b,
+	0x372a, 0x2b4a, 0x2b4a, 0x2b4a, 0x2b4a, 0x3792, 0x37ae, 0x3828,
+	0x38e2, 0x713c, 0x0078, 0x2b2c, 0x2021, 0x4000, 0x1078, 0x3553,
+	0x127e, 0x2091, 0x8000, 0x0068, 0x2b39, 0x7818, 0xd084, 0x0040,
+	0x2b3c, 0x127f, 0x0078, 0x2b30, 0x7c22, 0x7926, 0x7a2a, 0x7b2e,
+	0x781b, 0x0001, 0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000,
+	0x127f, 0x007c, 0x2021, 0x4001, 0x0078, 0x2b2e, 0x2021, 0x4002,
+	0x0078, 0x2b2e, 0x2021, 0x4003, 0x0078, 0x2b2e, 0x2021, 0x4005,
+	0x0078, 0x2b2e, 0x2021, 0x4006, 0x0078, 0x2b2e, 0xa02e, 0x2520,
+	0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0078, 0x3562, 0x7823, 0x0004,
+	0x7824, 0x007a, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930,
+	0x0078, 0x3566, 0x7924, 0x7828, 0x2114, 0x200a, 0x0078, 0x2b2c,
+	0x7924, 0x2114, 0x0078, 0x2b2c, 0x2099, 0x0009, 0x20a1, 0x0009,
+	0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0078, 0x2b2c,
+	0x7824, 0x2060, 0x0078, 0x2ba0, 0x2009, 0x0001, 0x2011, 0x0013,
+	0x2019, 0x0010, 0x783b, 0x0017, 0x0078, 0x2b2c, 0x7d38, 0x7c3c,
+	0x0078, 0x2b60, 0x7d38, 0x7c3c, 0x0078, 0x2b6c, 0x2061, 0x1000,
+	0x610c, 0xa006, 0x2c14, 0xa200, 0x8c60, 0x8109, 0x00c0, 0x2ba2,
+	0x2010, 0xa005, 0x0040, 0x2b2c, 0x0078, 0x2b52, 0x2069, 0xa351,
+	0x7824, 0x7930, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a,
+	0x684a, 0x6942, 0x782c, 0x6852, 0x7828, 0x6856, 0xa006, 0x685a,
+	0x685e, 0x1078, 0x4dbd, 0x0078, 0x2b2c, 0x2069, 0xa351, 0x7824,
+	0x7934, 0xa11a, 0x00c8, 0x2b5a, 0x8019, 0x0040, 0x2b5a, 0x684e,
+	0x6946, 0x782c, 0x6862, 0x7828, 0x6866, 0xa006, 0x686a, 0x686e,
+	0x1078, 0x494d, 0x0078, 0x2b2c, 0xa02e, 0x2520, 0x81ff, 0x00c0,
+	0x2b56, 0x7924, 0x7b28, 0x7a2c, 0x20a9, 0x0005, 0x20a1, 0xa388,
+	0x41a1, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0020, 0x1078,
+	0x3562, 0x701b, 0x2bf4, 0x007c, 0x6834, 0x2008, 0xa084, 0x00ff,
+	0xa096, 0x0011, 0x0040, 0x2c00, 0xa096, 0x0019, 0x00c0, 0x2b56,
+	0x810f, 0xa18c, 0x00ff, 0x0040, 0x2b56, 0x710e, 0x700c, 0x8001,
+	0x0040, 0x2c31, 0x700e, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009,
+	0x0020, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530, 0xa290,
+	0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x1078,
+	0x3562, 0x701b, 0x2c24, 0x007c, 0x6834, 0xa084, 0x00ff, 0xa096,
+	0x0002, 0x0040, 0x2c2f, 0xa096, 0x000a, 0x00c0, 0x2b56, 0x0078,
+	0x2c06, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x436e,
+	0x00c0, 0x2c3f, 0x7007, 0x0003, 0x701b, 0x2c41, 0x007c, 0x1078,
+	0x4a60, 0x127e, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xa388,
+	0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+	0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x127f, 0x0078, 0x3566,
+	0x61a0, 0x7824, 0x60a2, 0x0078, 0x2b2c, 0x2091, 0x8000, 0x7823,
+	0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009,
+	0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200,
+	0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd,
+	0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080,
+	0x2071, 0x0010, 0x20c1, 0x00f0, 0xa08a, 0x0003, 0x00c8, 0x0427,
+	0x0078, 0x0423, 0x81ff, 0x00c0, 0x2b56, 0x7924, 0x810f, 0xa18c,
+	0x00ff, 0x1078, 0x4501, 0x00c0, 0x2b5a, 0x7e38, 0xa684, 0x3fff,
+	0xa082, 0x4000, 0x0048, 0x2c9e, 0x0078, 0x2b5a, 0x7c28, 0x7d2c,
+	0x1078, 0x46d6, 0xd28c, 0x00c0, 0x2ca9, 0x1078, 0x466a, 0x0078,
+	0x2cab, 0x1078, 0x46a4, 0x00c0, 0x2cd5, 0x2061, 0xaa00, 0x127e,
+	0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0040, 0x2cc3, 0x6010,
+	0xa06d, 0x0040, 0x2cc3, 0x683c, 0xa406, 0x00c0, 0x2cc3, 0x6840,
+	0xa506, 0x0040, 0x2cce, 0x127f, 0xace0, 0x0010, 0x2001, 0xa315,
+	0x2004, 0xac02, 0x00c8, 0x2b56, 0x0078, 0x2caf, 0x1078, 0x8758,
+	0x127f, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0xa00e, 0x2001, 0x0005,
+	0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cc0, 0x1078,
+	0x4982, 0x127f, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078,
+	0x3530, 0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078,
+	0x46e4, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56,
+	0x1078, 0x3542, 0x0040, 0x2b5a, 0x1078, 0x475f, 0x0040, 0x2b56,
+	0x2019, 0x0005, 0x1078, 0x4705, 0x0040, 0x2b56, 0x7828, 0xa08a,
+	0x1000, 0x00c8, 0x2b5a, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078,
+	0x58e1, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x81ff, 0x0040,
+	0x2d1d, 0x2009, 0x0001, 0x0078, 0x2d4e, 0x2029, 0x00ff, 0x644c,
+	0x2400, 0xa506, 0x0040, 0x2d48, 0x2508, 0x1078, 0x4501, 0x00c0,
+	0x2d48, 0x1078, 0x475f, 0x00c0, 0x2d33, 0x2009, 0x0002, 0x62a8,
+	0x2518, 0x0078, 0x2d4e, 0x2019, 0x0004, 0x1078, 0x4705, 0x00c0,
+	0x2d3d, 0x2009, 0x0006, 0x0078, 0x2d4e, 0x7824, 0xa08a, 0x1000,
+	0x00c8, 0x2d51, 0x8003, 0x800b, 0x810b, 0xa108, 0x1078, 0x58e1,
+	0x8529, 0x00c8, 0x2d20, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078,
+	0x2b56, 0x127f, 0x0078, 0x2b5a, 0x1078, 0x3530, 0x0040, 0x2b5a,
+	0x1078, 0x461b, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0,
+	0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a, 0x1078, 0x460a, 0x1078,
+	0x46d6, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530,
+	0x0040, 0x2b5a, 0x1078, 0x46a7, 0x0040, 0x2b56, 0x1078, 0x43c1,
+	0x1078, 0x4663, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530,
+	0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x62a0, 0x2019,
+	0x0005, 0x0c7e, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e,
+	0x2039, 0x0000, 0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38,
+	0x077f, 0x1078, 0x46d6, 0x0078, 0x2b2c, 0x1078, 0x3530, 0x0040,
+	0x2b5a, 0x1078, 0x46d6, 0x2208, 0x0078, 0x2b2c, 0x157e, 0x0d7e,
+	0x0e7e, 0x2069, 0xa413, 0x6810, 0x6914, 0xa10a, 0x00c8, 0x2db2,
+	0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019, 0x0000, 0x20a9,
+	0x00ff, 0x2069, 0xa434, 0x2d04, 0xa075, 0x0040, 0x2dc7, 0x704c,
+	0x1078, 0x2dd1, 0xa210, 0x7080, 0x1078, 0x2dd1, 0xa318, 0x8d68,
+	0x00f0, 0x2dbb, 0x2300, 0xa218, 0x0e7f, 0x0d7f, 0x157f, 0x0078,
+	0x2b2c, 0x0f7e, 0x017e, 0xa07d, 0x0040, 0x2de0, 0x2001, 0x0000,
+	0x8000, 0x2f0c, 0x81ff, 0x0040, 0x2de0, 0x2178, 0x0078, 0x2dd8,
+	0x017f, 0x0f7f, 0x007c, 0x2069, 0xa413, 0x6910, 0x62a4, 0x0078,
+	0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x614c, 0xa190, 0x293f, 0x2214,
+	0xa294, 0x00ff, 0x606c, 0xa084, 0xff00, 0xa215, 0x6368, 0x67c8,
+	0xd79c, 0x0040, 0x2dff, 0x2031, 0x0001, 0x0078, 0x2e01, 0x2031,
+	0x0000, 0x7e3a, 0x7f3e, 0x0078, 0x2b2c, 0x613c, 0x6240, 0x2019,
+	0xa5a0, 0x231c, 0x0078, 0x2b2c, 0x127e, 0x2091, 0x8000, 0x6134,
+	0xa006, 0x2010, 0x2018, 0x127f, 0x0078, 0x2b2c, 0x1078, 0x3542,
+	0x0040, 0x2b5a, 0x6244, 0x6338, 0x0078, 0x2b2c, 0x613c, 0x6240,
+	0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xa351, 0x831f, 0xa305,
+	0x6816, 0x782c, 0x2069, 0xa5a0, 0x2d1c, 0x206a, 0x0078, 0x2b2c,
+	0x017e, 0x127e, 0x2091, 0x8000, 0x7824, 0x6036, 0xd094, 0x0040,
+	0x2e43, 0x7828, 0xa085, 0x0001, 0x2009, 0xa5a9, 0x200a, 0x2001,
+	0xffff, 0x1078, 0x5975, 0x127f, 0x017f, 0x0078, 0x2b2c, 0x1078,
+	0x3542, 0x0040, 0x2b5a, 0x7828, 0xa00d, 0x0040, 0x2b5a, 0x782c,
+	0xa005, 0x0040, 0x2b5a, 0x6244, 0x6146, 0x6338, 0x603a, 0x0078,
+	0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56,
+	0x0c7e, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196,
+	0x00ff, 0x00c0, 0x2e70, 0x6030, 0xa085, 0xff00, 0x0078, 0x2e7f,
+	0xa182, 0x007f, 0x00c8, 0x2ea9, 0xa188, 0x293f, 0x210c, 0xa18c,
+	0x00ff, 0x6030, 0xa116, 0x0040, 0x2ea9, 0x810f, 0xa105, 0x127e,
+	0x2091, 0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2ea5,
+	0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040,
+	0x2eac, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032,
+	0x1078, 0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078,
+	0x2b56, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2ea5,
+	0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0c7e,
+	0x2061, 0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff,
+	0x00c0, 0x2ec7, 0x6030, 0xa085, 0xff00, 0x0078, 0x2ed6, 0xa182,
+	0x007f, 0x00c8, 0x2f00, 0xa188, 0x293f, 0x210c, 0xa18c, 0x00ff,
+	0x6030, 0xa116, 0x0040, 0x2f00, 0x810f, 0xa105, 0x127e, 0x2091,
+	0x8000, 0x007e, 0x1078, 0x74d7, 0x007f, 0x0040, 0x2efc, 0x601a,
+	0x600b, 0xbc05, 0x601f, 0x0001, 0x1078, 0x3518, 0x0040, 0x2f03,
+	0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x701b, 0x2f07, 0x2d00, 0x6012, 0x2009, 0x0032, 0x1078,
+	0x756c, 0x127f, 0x0c7f, 0x007c, 0x127f, 0x0c7f, 0x0078, 0x2b56,
+	0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x753d, 0x0078, 0x2efc, 0x6830,
+	0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x2061, 0xa62d,
+	0x127e, 0x2091, 0x8000, 0x6000, 0xd084, 0x0040, 0x2f1c, 0x6104,
+	0x6208, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x81ff,
+	0x00c0, 0x2b56, 0x127e, 0x2091, 0x8000, 0x6244, 0x6060, 0xa202,
+	0x0048, 0x2f33, 0xa085, 0x0001, 0x1078, 0x2500, 0x1078, 0x3bf5,
+	0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b5a, 0x127e, 0x2091,
+	0x8000, 0x20a9, 0x0011, 0x2001, 0xa340, 0x20a0, 0xa006, 0x40a4,
+	0x127f, 0x0078, 0x2b2c, 0x7d38, 0x7c3c, 0x0078, 0x2bde, 0x7824,
+	0xa09c, 0x00ff, 0xa39a, 0x0003, 0x00c8, 0x2b56, 0x624c, 0xa084,
+	0xff00, 0x8007, 0xa206, 0x00c0, 0x2f5f, 0x2001, 0xa340, 0x2009,
+	0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566, 0x81ff,
+	0x00c0, 0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518,
+	0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a,
+	0x1078, 0x8b85, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x2f81,
+	0x007c, 0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0xad80, 0x000e,
+	0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078, 0x3566,
+	0x1078, 0x3518, 0x0040, 0x2b56, 0x1078, 0x421a, 0x2009, 0x001c,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x2fa1,
+	0x007c, 0xade8, 0x000d, 0x6800, 0xa005, 0x0040, 0x2b5a, 0x6804,
+	0xd0ac, 0x0040, 0x2fae, 0xd0a4, 0x0040, 0x2b5a, 0xd094, 0x0040,
+	0x2fb9, 0x0c7e, 0x2061, 0x0100, 0x6104, 0xa18c, 0xffdf, 0x6106,
+	0x0c7f, 0xd08c, 0x0040, 0x2fc4, 0x0c7e, 0x2061, 0x0100, 0x6104,
+	0xa18d, 0x0010, 0x6106, 0x0c7f, 0x2009, 0x0100, 0x210c, 0xa18a,
+	0x0002, 0x0048, 0x2fd9, 0xd084, 0x0040, 0x2fd9, 0x6a28, 0xa28a,
+	0x007f, 0x00c8, 0x2b5a, 0xa288, 0x293f, 0x210c, 0xa18c, 0x00ff,
+	0x6152, 0xd0dc, 0x0040, 0x2fe2, 0x6828, 0xa08a, 0x007f, 0x00c8,
+	0x2b5a, 0x604e, 0x6808, 0xa08a, 0x0100, 0x0048, 0x2b5a, 0xa08a,
+	0x0841, 0x00c8, 0x2b5a, 0xa084, 0x0007, 0x00c0, 0x2b5a, 0x680c,
+	0xa005, 0x0040, 0x2b5a, 0x6810, 0xa005, 0x0040, 0x2b5a, 0x6848,
+	0x6940, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x684c,
+	0x6944, 0xa10a, 0x00c8, 0x2b5a, 0x8001, 0x0040, 0x2b5a, 0x6804,
+	0xd0fc, 0x0040, 0x3038, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009,
+	0x0014, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0xa290, 0x0038, 0xa399,
+	0x0000, 0x1078, 0x3562, 0x701b, 0x301e, 0x007c, 0xade8, 0x000d,
+	0x20a9, 0x0014, 0x2d98, 0x2069, 0xa36d, 0x2da0, 0x53a3, 0x7010,
+	0xa0e8, 0x000d, 0x2001, 0xa371, 0x200c, 0xd1e4, 0x0040, 0x3038,
+	0x0c7e, 0x2061, 0x0100, 0x6004, 0xa085, 0x0b00, 0x6006, 0x0c7f,
+	0x20a9, 0x001c, 0x2d98, 0x2069, 0xa351, 0x2da0, 0x53a3, 0x6814,
+	0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084, 0x00ff, 0x6042, 0x1078,
+	0x4dbd, 0x1078, 0x48dd, 0x1078, 0x494d, 0x6000, 0xa086, 0x0000,
+	0x00c0, 0x30c3, 0x6808, 0x602a, 0x1078, 0x218b, 0x6818, 0x691c,
+	0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a,
+	0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0040, 0x3070, 0x6830, 0x6934,
+	0x6a38, 0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0078, 0x3072,
+	0xa084, 0xf0ff, 0x6006, 0x610a, 0x620e, 0x6312, 0x1078, 0x59a8,
+	0x6904, 0xd1fc, 0x0040, 0x30a5, 0x0c7e, 0x2009, 0x0000, 0x20a9,
+	0x0001, 0x6b70, 0xd384, 0x0040, 0x30a2, 0x0078, 0x308c, 0x839d,
+	0x00c8, 0x30a2, 0x3508, 0x8109, 0x1078, 0x5364, 0x6878, 0x6016,
+	0x6874, 0x2008, 0xa084, 0xff00, 0x8007, 0x600a, 0xa184, 0x00ff,
+	0x6006, 0x8108, 0x00c0, 0x30a0, 0x6003, 0x0003, 0x0078, 0x30a2,
+	0x6003, 0x0001, 0x00f0, 0x3087, 0x0c7f, 0x0c7e, 0x2061, 0x0100,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x0c7f, 0x1078, 0x3784, 0x0040,
+	0x30b3, 0x1078, 0x2500, 0x60bc, 0xa005, 0x0040, 0x30bf, 0x6003,
+	0x0001, 0x2091, 0x301d, 0x1078, 0x4171, 0x0078, 0x30c3, 0x6003,
+	0x0004, 0x2091, 0x301d, 0x0078, 0x2b2c, 0x6000, 0xa086, 0x0000,
+	0x0040, 0x2b56, 0x2069, 0xa351, 0x7830, 0x6842, 0x7834, 0x6846,
+	0x6804, 0xd0fc, 0x0040, 0x30d8, 0x2009, 0x0030, 0x0078, 0x30da,
+	0x2009, 0x001c, 0x2d00, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078,
+	0x3566, 0xa006, 0x1078, 0x2500, 0x81ff, 0x00c0, 0x2b56, 0x1078,
+	0x421a, 0x1078, 0x4171, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56,
+	0x6180, 0x81ff, 0x0040, 0x3107, 0x703f, 0x0000, 0x2001, 0xa9c0,
+	0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x3566, 0x701b, 0x2b29, 0x127f, 0x007c, 0x703f,
+	0x0001, 0x0d7e, 0x2069, 0xa9c0, 0x20a9, 0x0040, 0x20a1, 0xa9c0,
+	0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x293f, 0x210c, 0xa18c,
+	0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100, 0xa506, 0x0040,
+	0x3139, 0x1078, 0x4501, 0x00c0, 0x3139, 0x6014, 0x821c, 0x0048,
+	0x3131, 0xa398, 0xa9c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0078,
+	0x3138, 0xa398, 0xa9c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a,
+	0x8210, 0x8108, 0xa182, 0x0080, 0x00c8, 0x3140, 0x0078, 0x311d,
+	0x8201, 0x8007, 0x2d0c, 0xa105, 0x206a, 0x0d7f, 0x20a9, 0x0040,
+	0x20a1, 0xa9c0, 0x2099, 0xa9c0, 0x1078, 0x41be, 0x0078, 0x30f6,
+	0x1078, 0x3542, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f,
+	0x00c0, 0x315e, 0x2009, 0x0002, 0x0078, 0x2b56, 0x2001, 0xa352,
+	0x2004, 0xd0b4, 0x0040, 0x3185, 0x6000, 0xd08c, 0x00c0, 0x3185,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3185, 0x6837,
+	0x0000, 0x6838, 0xc0fd, 0x683a, 0x1078, 0x8bd9, 0x00c0, 0x317c,
+	0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3181,
+	0x007c, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x20a9, 0x002b, 0x2c98,
+	0xade8, 0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006,
+	0x2098, 0xad80, 0x0006, 0x20a0, 0x1078, 0x41be, 0x20a9, 0x0004,
+	0xac80, 0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, 0x1078, 0x41be,
+	0x2d00, 0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0078,
+	0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040, 0x2b5a,
+	0x1078, 0x46ef, 0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x7828,
+	0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x1078, 0x3542, 0x0040, 0x2b5a,
+	0x1078, 0x475f, 0x0040, 0x2b56, 0x2019, 0x0004, 0x1078, 0x4705,
+	0x7924, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x0078, 0x2b2c, 0xa186,
+	0x00ff, 0x0040, 0x31d7, 0x1078, 0x31e7, 0x0078, 0x31e6, 0x2029,
+	0x007e, 0x2061, 0xa300, 0x644c, 0x2400, 0xa506, 0x0040, 0x31e3,
+	0x2508, 0x1078, 0x31e7, 0x8529, 0x00c8, 0x31dc, 0x007c, 0x1078,
+	0x4501, 0x00c0, 0x31f2, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108,
+	0x1078, 0x58e1, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530,
+	0x0040, 0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46fa,
+	0x0078, 0x2b2c, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040,
+	0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x46e4, 0x0078,
+	0x2b2c, 0x6100, 0x0078, 0x2b2c, 0x1078, 0x3542, 0x0040, 0x2b5a,
+	0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x0d7e,
+	0xace8, 0x000a, 0x7924, 0xd184, 0x0040, 0x3228, 0xace8, 0x0006,
+	0x680c, 0x8007, 0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f,
+	0x6a00, 0x8217, 0x0d7f, 0x6100, 0xa18c, 0x0200, 0x0078, 0x2b2c,
+	0xa006, 0x1078, 0x2500, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff,
+	0x0040, 0x3245, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x421a, 0x7828,
+	0xa08a, 0x1000, 0x00c8, 0x2b5a, 0x7924, 0xa18c, 0xff00, 0x810f,
+	0xa186, 0x00ff, 0x0040, 0x325b, 0xa182, 0x007f, 0x00c8, 0x2b5a,
+	0x2100, 0x1078, 0x24fa, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000,
+	0x2061, 0xa5be, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0x0100,
+	0x6030, 0xa084, 0x00ff, 0x810f, 0xa105, 0x604a, 0x6043, 0x0090,
+	0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078, 0x596c,
+	0x7924, 0xa18c, 0xff00, 0x810f, 0x7a28, 0x1078, 0x31cf, 0x127f,
+	0x0c7f, 0x027f, 0x0078, 0x2b2c, 0x7924, 0xa18c, 0xff00, 0x810f,
+	0x0c7e, 0x1078, 0x4499, 0x2c08, 0x0c7f, 0x00c0, 0x2b5a, 0x0078,
+	0x2b2c, 0x81ff, 0x0040, 0x3298, 0x2009, 0x0001, 0x0078, 0x2b56,
+	0x60c8, 0xd09c, 0x00c0, 0x32a0, 0x2009, 0x0005, 0x0078, 0x2b56,
+	0x1078, 0x3518, 0x00c0, 0x32a8, 0x2009, 0x0002, 0x0078, 0x2b56,
+	0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b,
+	0x32b2, 0x007c, 0x2009, 0x0080, 0x1078, 0x4501, 0x00c0, 0x32bf,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x32c3, 0x2021,
+	0x400a, 0x0078, 0x2b2e, 0x0d7e, 0xade8, 0x000d, 0x6900, 0x6a08,
+	0x6b0c, 0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0040,
+	0x3336, 0xa0be, 0x0112, 0x0040, 0x3336, 0xa0be, 0x0113, 0x0040,
+	0x3336, 0xa0be, 0x0114, 0x0040, 0x3336, 0xa0be, 0x0117, 0x0040,
+	0x3336, 0xa0be, 0x011a, 0x0040, 0x3336, 0xa0be, 0x0121, 0x0040,
+	0x332c, 0xa0be, 0x0131, 0x0040, 0x332c, 0xa0be, 0x0171, 0x0040,
+	0x3336, 0xa0be, 0x0173, 0x0040, 0x3336, 0xa0be, 0x01a1, 0x00c0,
+	0x32fe, 0x6830, 0x8007, 0x6832, 0x0078, 0x333c, 0xa0be, 0x0212,
+	0x0040, 0x3332, 0xa0be, 0x0213, 0x0040, 0x3332, 0xa0be, 0x0214,
+	0x0040, 0x3324, 0xa0be, 0x0217, 0x0040, 0x331e, 0xa0be, 0x021a,
+	0x00c0, 0x3317, 0x6838, 0x8007, 0x683a, 0x0078, 0x3336, 0xa0be,
+	0x0300, 0x0040, 0x3336, 0x0d7f, 0x0078, 0x2b5a, 0xad80, 0x0010,
+	0x20a9, 0x0007, 0x1078, 0x337e, 0xad80, 0x000e, 0x20a9, 0x0001,
+	0x1078, 0x337e, 0x0078, 0x3336, 0xad80, 0x000c, 0x1078, 0x338c,
+	0x0078, 0x333c, 0xad80, 0x000e, 0x1078, 0x338c, 0xad80, 0x000c,
+	0x20a9, 0x0001, 0x1078, 0x337e, 0x0c7e, 0x1078, 0x3518, 0x0040,
+	0x336f, 0x6838, 0xc0fd, 0x683a, 0x6837, 0x0119, 0x6853, 0x0000,
+	0x684f, 0x0020, 0x685b, 0x0001, 0x810b, 0x697e, 0x6883, 0x0000,
+	0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996, 0x689b, 0x0000, 0x0c7f,
+	0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000,
+	0x6804, 0x2068, 0x1078, 0x8ba1, 0x00c0, 0x336a, 0x2009, 0x0003,
+	0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3375, 0x007c, 0x0c7f,
+	0x0d7f, 0x2009, 0x0002, 0x0078, 0x2b56, 0x6820, 0xa086, 0x8001,
+	0x00c0, 0x2b2c, 0x2009, 0x0004, 0x0078, 0x2b56, 0x017e, 0x2008,
+	0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108, 0x280a, 0x8108,
+	0x00f0, 0x3380, 0x017f, 0x007c, 0x017e, 0x0a7e, 0x0b7e, 0x2008,
+	0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000, 0x205c, 0x2b0a,
+	0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a, 0x0b7f, 0x0a7f,
+	0x017f, 0x007c, 0x81ff, 0x0040, 0x33a9, 0x2009, 0x0001, 0x0078,
+	0x2b56, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0xa182, 0x0080,
+	0x0048, 0x2b5a, 0xa182, 0x00ff, 0x00c8, 0x2b5a, 0x7a2c, 0x7b28,
+	0x6068, 0xa306, 0x00c0, 0x33c4, 0x606c, 0xa24e, 0x0040, 0x2b5a,
+	0xa9cc, 0xff00, 0x0040, 0x2b5a, 0x0c7e, 0x1078, 0x346d, 0x2c68,
+	0x0c7f, 0x0040, 0x33fc, 0xa0c6, 0x4000, 0x00c0, 0x33e2, 0x0c7e,
+	0x007e, 0x2d60, 0x2009, 0x0000, 0x1078, 0x47cb, 0x00c0, 0x33d9,
+	0xc185, 0x6000, 0xd0bc, 0x0040, 0x33de, 0xc18d, 0x007f, 0x0c7f,
+	0x0078, 0x33f9, 0xa0c6, 0x4007, 0x00c0, 0x33e9, 0x2408, 0x0078,
+	0x33f9, 0xa0c6, 0x4008, 0x00c0, 0x33f1, 0x2708, 0x2610, 0x0078,
+	0x33f9, 0xa0c6, 0x4009, 0x00c0, 0x33f7, 0x0078, 0x33f9, 0x2001,
+	0x4006, 0x2020, 0x0078, 0x2b2e, 0x2d00, 0x7022, 0x017e, 0x0b7e,
+	0x0c7e, 0x0e7e, 0x2c70, 0x1078, 0x74d7, 0x0040, 0x3442, 0x2d00,
+	0x601a, 0x2001, 0xa356, 0x2004, 0xa084, 0x00ff, 0x6842, 0x2e58,
+	0x0e7f, 0x0e7e, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2b70, 0x00c0,
+	0x3423, 0x1078, 0x753d, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x2009,
+	0x0002, 0x0078, 0x2b56, 0x6837, 0x0000, 0x2d00, 0x6012, 0x6833,
+	0x0000, 0x6838, 0xc0fd, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x2813, 0x127f, 0x601f, 0x0001, 0x2001, 0x0000, 0x1078, 0x442b,
+	0x2001, 0x0002, 0x1078, 0x443f, 0x2009, 0x0002, 0x1078, 0x756c,
+	0xa085, 0x0001, 0x0e7f, 0x0c7f, 0x0b7f, 0x017f, 0x00c0, 0x344c,
+	0x2009, 0x0003, 0x0078, 0x2b56, 0x7007, 0x0003, 0x701b, 0x3451,
+	0x007c, 0x6830, 0xa086, 0x0100, 0x7020, 0x2060, 0x00c0, 0x345f,
+	0x2009, 0x0004, 0x6204, 0xa294, 0x00ff, 0x0078, 0x2b56, 0x2009,
+	0x0000, 0x1078, 0x47cb, 0x00c0, 0x3466, 0xc185, 0x6000, 0xd0bc,
+	0x0040, 0x346b, 0xc18d, 0x0078, 0x2b2c, 0x0e7e, 0x0d7e, 0x2029,
+	0x0000, 0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xa4b4, 0x2e04,
+	0xa005, 0x00c0, 0x3482, 0x2100, 0xa406, 0x00c0, 0x34b3, 0x2428,
+	0x0078, 0x34b3, 0x2068, 0x6f10, 0x2700, 0xa306, 0x00c0, 0x34a4,
+	0x6e14, 0x2600, 0xa206, 0x00c0, 0x34a4, 0x2400, 0xa106, 0x00c0,
+	0x34a0, 0x2d60, 0xd884, 0x0040, 0x34c8, 0x6004, 0xa084, 0x00ff,
+	0xa086, 0x0006, 0x00c0, 0x34c8, 0x2001, 0x4000, 0x0078, 0x34c9,
+	0x2001, 0x4007, 0x0078, 0x34c9, 0x2400, 0xa106, 0x00c0, 0x34b3,
+	0x6e14, 0x87ff, 0x00c0, 0x34af, 0x86ff, 0x0040, 0x347f, 0x2001,
+	0x4008, 0x0078, 0x34c9, 0x8420, 0x8e70, 0x00f0, 0x3477, 0x85ff,
+	0x00c0, 0x34c2, 0x2001, 0x4009, 0x0078, 0x34c9, 0x2001, 0x0001,
+	0x0078, 0x34c9, 0x1078, 0x4499, 0x00c0, 0x34be, 0x6312, 0x6216,
+	0xa006, 0xa005, 0x0d7f, 0x0e7f, 0x007c, 0x81ff, 0x00c0, 0x2b56,
+	0x1078, 0x3518, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x7824, 0xa005, 0x0040, 0x2b5a, 0xa096, 0x00ff, 0x0040,
+	0x34e5, 0xa092, 0x0004, 0x00c8, 0x2b5a, 0x2010, 0x2d18, 0x1078,
+	0x27c2, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x34f0, 0x007c,
+	0x6830, 0xa086, 0x0100, 0x0040, 0x2b56, 0x0078, 0x2b2c, 0x7924,
+	0xa18c, 0xff00, 0x810f, 0xa182, 0x0080, 0x0048, 0x2b5a, 0xa182,
+	0x00ff, 0x00c8, 0x2b5a, 0x127e, 0x2091, 0x8000, 0x1078, 0x8a89,
+	0x00c0, 0x3515, 0xa190, 0xa434, 0x2204, 0xa065, 0x0040, 0x3515,
+	0x1078, 0x4235, 0x127f, 0x0078, 0x2b2c, 0x127f, 0x0078, 0x2b56,
+	0x1078, 0x1381, 0x0040, 0x352f, 0xa006, 0x6802, 0x7010, 0xa005,
+	0x00c0, 0x3527, 0x2d00, 0x7012, 0x7016, 0x0078, 0x352d, 0x7014,
+	0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80, 0x000d, 0x007c,
+	0x7924, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501, 0x00c0, 0x353f,
+	0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0048, 0x3540, 0xa066,
+	0x8cff, 0x007c, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x1078, 0x4501,
+	0x00c0, 0x3550, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0048, 0x3551,
+	0xa066, 0x8cff, 0x007c, 0x017e, 0x7110, 0x81ff, 0x0040, 0x355e,
+	0x2168, 0x6904, 0x1078, 0x139a, 0x0078, 0x3555, 0x7112, 0x7116,
+	0x017f, 0x007c, 0x2031, 0x0001, 0x0078, 0x3568, 0x2031, 0x0000,
+	0x2061, 0xa3d1, 0x6606, 0x6112, 0x600e, 0x6226, 0x632a, 0x642e,
+	0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x2b2c,
+	0x007c, 0x0f7e, 0x127e, 0x2091, 0x8000, 0x2079, 0x0000, 0x2001,
+	0xa38f, 0x2004, 0xa005, 0x00c0, 0x3594, 0x0068, 0x3594, 0x7818,
+	0xd084, 0x00c0, 0x3594, 0x7a22, 0x7b26, 0x7c2a, 0x781b, 0x0001,
+	0x2091, 0x4080, 0x0078, 0x35b9, 0x017e, 0x0c7e, 0x0e7e, 0x2071,
+	0xa381, 0x7138, 0xa182, 0x0008, 0x0048, 0x35a2, 0x7030, 0x2060,
+	0x0078, 0x35b3, 0x7030, 0xa0e0, 0x0008, 0xac82, 0xa3d1, 0x0048,
+	0x35ab, 0x2061, 0xa391, 0x2c00, 0x7032, 0x81ff, 0x00c0, 0x35b1,
+	0x7036, 0x8108, 0x713a, 0x2262, 0x6306, 0x640a, 0x0e7f, 0x0c7f,
+	0x017f, 0x127f, 0x0f7f, 0x007c, 0x0e7e, 0x2071, 0xa381, 0x7038,
+	0xa005, 0x0040, 0x35f5, 0x127e, 0x2091, 0x8000, 0x0068, 0x35f4,
+	0x0f7e, 0x2079, 0x0000, 0x7818, 0xd084, 0x00c0, 0x35f3, 0x0c7e,
+	0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826, 0x6008, 0x782a,
+	0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001, 0x703a, 0xa005,
+	0x00c0, 0x35e9, 0x7033, 0xa391, 0x7037, 0xa391, 0x0c7f, 0x0078,
+	0x35f3, 0xac80, 0x0008, 0xa0fa, 0xa3d1, 0x0048, 0x35f1, 0x2001,
+	0xa391, 0x7036, 0x0c7f, 0x0f7f, 0x127f, 0x0e7f, 0x007c, 0x027e,
+	0x2001, 0xa352, 0x2004, 0xd0c4, 0x0040, 0x3602, 0x2011, 0x8014,
+	0x1078, 0x3579, 0x027f, 0x007c, 0x81ff, 0x00c0, 0x2b56, 0x127e,
+	0x2091, 0x8000, 0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x1078,
+	0x4171, 0x127f, 0x0078, 0x2b2c, 0x7824, 0x2008, 0xa18c, 0xfffd,
+	0x00c0, 0x361f, 0x61d4, 0xa10d, 0x61d6, 0x0078, 0x2b2c, 0x0078,
+	0x2b5a, 0x81ff, 0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x00c0,
+	0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x2b56, 0x1078,
+	0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006,
+	0x00c0, 0x363e, 0x7828, 0xa005, 0x0040, 0x2b2c, 0x0c7e, 0x1078,
+	0x3518, 0x0c7f, 0x0040, 0x2b56, 0x6837, 0x0000, 0x6833, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x1078, 0x8c4d, 0x0040, 0x2b56, 0x7007,
+	0x0003, 0x701b, 0x3654, 0x007c, 0x6830, 0xa086, 0x0100, 0x0040,
+	0x2b56, 0x0078, 0x2b2c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003,
+	0x00c0, 0x2b56, 0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x1078,
+	0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023,
+	0x0000, 0x702f, 0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x1078,
+	0x4501, 0x00c0, 0x36d8, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006,
+	0x0040, 0x3688, 0xa0c4, 0xff00, 0xa8c6, 0x0600, 0x00c0, 0x36d8,
+	0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x3695, 0x1078, 0x47cb,
+	0x00c0, 0x3695, 0xd79c, 0x0040, 0x36d8, 0xd794, 0x00c0, 0x369b,
+	0xd784, 0x0040, 0x36a7, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9,
+	0x0004, 0x53a3, 0x1078, 0x338c, 0xd794, 0x0040, 0x36b0, 0xac80,
+	0x000a, 0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x1078, 0x338c,
+	0x21a2, 0xd794, 0x0040, 0x36d0, 0xac80, 0x0000, 0x2098, 0x94a0,
+	0x20a9, 0x0002, 0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80,
+	0x0004, 0x2098, 0x3400, 0x20a9, 0x0002, 0x53a3, 0x1078, 0x337e,
+	0xac80, 0x0026, 0x2098, 0x20a9, 0x0002, 0x53a3, 0x0078, 0x36d1,
+	0x94a0, 0xd794, 0x0040, 0x36d6, 0xa6b0, 0x000b, 0xa6b0, 0x0005,
+	0x8108, 0xd78c, 0x0040, 0x36e2, 0xa186, 0x0100, 0x0040, 0x36f3,
+	0x0078, 0x36e6, 0xa186, 0x007e, 0x0040, 0x36f3, 0xd794, 0x0040,
+	0x36ed, 0xa686, 0x0020, 0x0078, 0x36ef, 0xa686, 0x0028, 0x0040,
+	0x36fc, 0x0078, 0x3677, 0x86ff, 0x00c0, 0x36fa, 0x7120, 0x810b,
+	0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa600, 0x7022,
+	0x772a, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6612, 0x7024, 0x600e,
+	0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x1078, 0x13d1, 0x7007,
+	0x0002, 0x701b, 0x3714, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3726,
+	0x711c, 0x7024, 0x20a0, 0x7728, 0x2031, 0x0000, 0x2061, 0xa3d1,
+	0x6224, 0x6328, 0x642c, 0x6530, 0x0078, 0x3677, 0x7120, 0x810b,
+	0x0078, 0x2b2c, 0x2029, 0x007e, 0x7924, 0x7a28, 0x7b2c, 0x7c38,
+	0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502,
+	0x0048, 0x2b5a, 0xa184, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a,
+	0xa502, 0x0048, 0x2b5a, 0xa284, 0xff00, 0x8007, 0xa0e2, 0x0020,
+	0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa284, 0x00ff, 0xa0e2,
+	0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a, 0xa384, 0xff00,
+	0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048, 0x2b5a,
+	0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0048, 0x2b5a, 0xa502, 0x0048,
+	0x2b5a, 0xa484, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0048, 0x2b5a,
+	0xa502, 0x0048, 0x2b5a, 0xa484, 0x00ff, 0xa0e2, 0x0020, 0x0048,
+	0x2b5a, 0xa502, 0x0048, 0x2b5a, 0x2061, 0xa5a3, 0x6102, 0x6206,
+	0x630a, 0x640e, 0x0078, 0x2b2c, 0x007e, 0x2001, 0xa352, 0x2004,
+	0xd0cc, 0x007f, 0x007c, 0x007e, 0x2001, 0xa371, 0x2004, 0xd0bc,
+	0x007f, 0x007c, 0x6160, 0x7a24, 0x6300, 0x82ff, 0x00c0, 0x379b,
+	0x7926, 0x0078, 0x2b2c, 0x83ff, 0x00c0, 0x2b5a, 0x2001, 0xfff0,
+	0xa200, 0x00c8, 0x2b5a, 0x2019, 0xffff, 0x6064, 0xa302, 0xa200,
+	0x0048, 0x2b5a, 0x7926, 0x6262, 0x0078, 0x2b2c, 0x2001, 0xa300,
+	0x2004, 0xa086, 0x0003, 0x00c0, 0x2b56, 0x7c28, 0x7d24, 0x7e38,
+	0x7f2c, 0x1078, 0x3518, 0x0040, 0x2b56, 0x2009, 0x0000, 0x2019,
+	0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80, 0x0003, 0x7026,
+	0x20a0, 0xa1e0, 0xa434, 0x2c64, 0x8cff, 0x0040, 0x37e8, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x0040, 0x37dd, 0x6004, 0xa084,
+	0xff00, 0xa086, 0x0600, 0x00c0, 0x37e8, 0x6014, 0x20a2, 0x94a0,
+	0x6010, 0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002,
+	0x8108, 0xa182, 0x00ff, 0x0040, 0x37f3, 0xa386, 0x002a, 0x0040,
+	0x37fc, 0x0078, 0x37c9, 0x83ff, 0x00c0, 0x37fa, 0x7120, 0x810c,
+	0x0078, 0x2b2c, 0x702f, 0x0001, 0x711e, 0x7020, 0xa300, 0x7022,
+	0x2061, 0xa3d1, 0x6007, 0x0000, 0x6312, 0x7024, 0x600e, 0x6426,
+	0x652a, 0x662e, 0x6732, 0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002,
+	0x701b, 0x3813, 0x007c, 0x702c, 0xa005, 0x00c0, 0x3824, 0x711c,
+	0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xa3d1, 0x6424, 0x6528,
+	0x662c, 0x6730, 0x0078, 0x37c9, 0x7120, 0x810c, 0x0078, 0x2b2c,
+	0x81ff, 0x00c0, 0x2b56, 0x60c8, 0xd09c, 0x0040, 0x2b56, 0x1078,
+	0x3518, 0x0040, 0x2b56, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x1078, 0x3562, 0x701b, 0x383d, 0x007c, 0x0d7e, 0xade8, 0x000d,
+	0x6828, 0xa0be, 0x7000, 0x0040, 0x3850, 0xa0be, 0x7100, 0x0040,
+	0x3850, 0xa0be, 0x7200, 0x0040, 0x3850, 0x0d7f, 0x0078, 0x2b5a,
+	0x6820, 0x6924, 0x1078, 0x24e3, 0x00c0, 0x387b, 0x1078, 0x4499,
+	0x00c0, 0x387b, 0x7122, 0x6612, 0x6516, 0x6e18, 0x0c7e, 0x1078,
+	0x3518, 0x0040, 0x387b, 0x1078, 0x3518, 0x0040, 0x387b, 0x0c7f,
+	0x0d7f, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000,
+	0x6804, 0x2068, 0x1078, 0x8bbd, 0x0040, 0x2b56, 0x7007, 0x0003,
+	0x701b, 0x387e, 0x007c, 0x0d7f, 0x0078, 0x2b56, 0x7120, 0x1078,
+	0x2921, 0x6820, 0xa086, 0x8001, 0x0040, 0x2b56, 0x2d00, 0x701e,
+	0x6804, 0xa080, 0x0002, 0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0,
+	0x1078, 0x41be, 0x007f, 0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10,
+	0x6d14, 0x2061, 0xa3d1, 0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6,
+	0x7000, 0x00c0, 0x38a5, 0x0078, 0x38a9, 0xa7c6, 0x7100, 0x00c0,
+	0x38b1, 0xa6c2, 0x0004, 0x0048, 0x2b5a, 0x2009, 0x0004, 0x0078,
+	0x3566, 0xa7c6, 0x7200, 0x00c0, 0x2b5a, 0xa6c2, 0x0054, 0x0048,
+	0x2b5a, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a, 0x642e, 0x6532,
+	0x2c10, 0x1078, 0x13d1, 0x7007, 0x0002, 0x701b, 0x38c8, 0x007c,
+	0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002,
+	0x007e, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x1078, 0x41be, 0x007f,
+	0x2009, 0x002a, 0x2061, 0xa3d1, 0x6224, 0x6328, 0x642c, 0x6530,
+	0x0078, 0x3566, 0x81ff, 0x00c0, 0x2b56, 0x1078, 0x3530, 0x0040,
+	0x2b5a, 0x1078, 0x45a7, 0x0040, 0x2b56, 0x1078, 0x4710, 0x0078,
+	0x2b2c, 0x7824, 0xd084, 0x0040, 0x3150, 0x1078, 0x3542, 0x0040,
+	0x2b5a, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x00c0, 0x3903, 0x2009,
+	0x0002, 0x0078, 0x2b56, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006,
+	0x0040, 0x3910, 0xa08e, 0x0004, 0x0040, 0x3910, 0xa08e, 0x0005,
+	0x00c0, 0x3934, 0x2001, 0xa352, 0x2004, 0xd0b4, 0x0040, 0x3185,
+	0x6000, 0xd08c, 0x00c0, 0x3185, 0x6837, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x1078, 0x8bd9, 0x00c0, 0x3929, 0x2009, 0x0003, 0x0078,
+	0x2b56, 0x7007, 0x0003, 0x701b, 0x392e, 0x007c, 0x1078, 0x3542,
+	0x0040, 0x2b5a, 0x0078, 0x3185, 0x2009, 0xa32e, 0x210c, 0x81ff,
+	0x0040, 0x393e, 0x2009, 0x0001, 0x0078, 0x2b56, 0x2001, 0xa300,
+	0x2004, 0xa086, 0x0003, 0x0040, 0x3949, 0x2009, 0x0007, 0x0078,
+	0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x0040, 0x3953, 0x2009,
+	0x0008, 0x0078, 0x2b56, 0x609c, 0xd0a4, 0x00c0, 0x395a, 0xd0ac,
+	0x00c0, 0x3185, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x1078, 0x8c4d, 0x00c0, 0x3969, 0x2009, 0x0003, 0x0078,
+	0x2b56, 0x7007, 0x0003, 0x701b, 0x396e, 0x007c, 0x6830, 0xa086,
+	0x0100, 0x00c0, 0x3977, 0x2009, 0x0004, 0x0078, 0x2b56, 0x1078,
+	0x3542, 0x0040, 0x2b5a, 0x0078, 0x3912, 0x81ff, 0x2009, 0x0001,
+	0x00c0, 0x2b56, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x00c0,
+	0x2b56, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x00c0,
+	0x2b56, 0x1078, 0x3542, 0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff,
+	0xa086, 0x0006, 0x2009, 0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078,
+	0x3518, 0x0c7f, 0x2009, 0x0002, 0x0040, 0x2b56, 0x6837, 0x0000,
+	0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00,
+	0xa18c, 0x00ff, 0xa006, 0x82ff, 0x00c0, 0x39bc, 0xc0ed, 0x6952,
+	0x792c, 0x6956, 0x0078, 0x39c5, 0xa28e, 0x0100, 0x00c0, 0x2b5a,
+	0xc0e5, 0x6853, 0x0000, 0x6857, 0x0000, 0x683e, 0x1078, 0x8df6,
+	0x2009, 0x0003, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b, 0x39d1,
+	0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040, 0x2b56,
+	0x0078, 0x2b2c, 0x81ff, 0x2009, 0x0001, 0x00c0, 0x2b56, 0x6000,
+	0xa086, 0x0003, 0x2009, 0x0007, 0x00c0, 0x2b56, 0x1078, 0x3542,
+	0x0040, 0x2b5a, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x2009,
+	0x0009, 0x00c0, 0x2b56, 0x0c7e, 0x1078, 0x3518, 0x0c7f, 0x2009,
+	0x0002, 0x0040, 0x2b56, 0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c,
+	0x7b28, 0x7c3c, 0x7d38, 0x1078, 0x3562, 0x701b, 0x3a08, 0x007c,
+	0x0d7e, 0xade8, 0x000f, 0x6800, 0xa086, 0x0500, 0x00c0, 0x3a1b,
+	0x6804, 0xa005, 0x00c0, 0x3a1b, 0x6808, 0xa084, 0xff00, 0x00c0,
+	0x3a1b, 0x0078, 0x3a1e, 0x0d7f, 0x00c0, 0x2b5a, 0x0d7f, 0x6837,
+	0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x0c7e, 0x1078,
+	0x3542, 0x00c0, 0x3a2e, 0x0c7f, 0x0078, 0x2b5a, 0x1078, 0x8e52,
+	0x2009, 0x0003, 0x0c7f, 0x0040, 0x2b56, 0x7007, 0x0003, 0x701b,
+	0x3a3a, 0x007c, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0040,
+	0x2b56, 0x0078, 0x2b2c, 0x127e, 0x0c7e, 0x0e7e, 0x2061, 0x0100,
+	0x2071, 0xa300, 0x6044, 0xd0a4, 0x00c0, 0x3a6c, 0xd084, 0x0040,
+	0x3a55, 0x1078, 0x3bcc, 0x0078, 0x3a68, 0xd08c, 0x0040, 0x3a5c,
+	0x1078, 0x3ae3, 0x0078, 0x3a68, 0xd094, 0x0040, 0x3a63, 0x1078,
+	0x3ab7, 0x0078, 0x3a68, 0xd09c, 0x0040, 0x3a68, 0x1078, 0x3a76,
+	0x0e7f, 0x0c7f, 0x127f, 0x007c, 0x017e, 0x6128, 0xd19c, 0x00c0,
+	0x3a73, 0xc19d, 0x612a, 0x017f, 0x0078, 0x3a68, 0x624c, 0xa286,
+	0xf0f0, 0x00c0, 0x3a87, 0x6048, 0xa086, 0xf0f0, 0x0040, 0x3a87,
+	0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0078, 0x3ab6, 0xa294,
+	0xff00, 0xa296, 0xf700, 0x0040, 0x3a9c, 0x7134, 0xd1a4, 0x00c0,
+	0x3a9c, 0x6240, 0xa294, 0x0010, 0x0040, 0x3a9c, 0x2009, 0x00f7,
+	0x1078, 0x41de, 0x0078, 0x3ab6, 0x6043, 0x0040, 0x6043, 0x0000,
+	0x7073, 0x0000, 0x708b, 0x0001, 0x70af, 0x0000, 0x70cb, 0x0000,
+	0x2009, 0xa9c0, 0x200b, 0x0000, 0x7083, 0x0000, 0x7077, 0x000f,
+	0x2009, 0x000f, 0x2011, 0x4122, 0x1078, 0x596c, 0x007c, 0x157e,
+	0x7074, 0xa005, 0x00c0, 0x3ae1, 0x2011, 0x4122, 0x1078, 0x58d4,
+	0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9, 0x00c8,
+	0x6044, 0xd08c, 0x00c0, 0x3ada, 0x00f0, 0x3ac8, 0x6242, 0x7087,
+	0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242,
+	0x0078, 0x3ae1, 0x6242, 0x7087, 0x0000, 0x707b, 0x0000, 0x0078,
+	0x3ae1, 0x157f, 0x007c, 0x7078, 0xa08a, 0x0003, 0x00c8, 0x3aec,
+	0x1079, 0x3aef, 0x0078, 0x3aee, 0x1078, 0x1328, 0x007c, 0x3af2,
+	0x3b41, 0x3bcb, 0x0f7e, 0x707b, 0x0001, 0x20e1, 0xa000, 0x20e1,
+	0x8700, 0x1078, 0x218b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2079,
+	0xa800, 0x207b, 0x2200, 0x7807, 0x00ef, 0x780b, 0x0000, 0x780f,
+	0x00ef, 0x7813, 0x0138, 0x7817, 0x0000, 0x781b, 0x0000, 0x781f,
+	0x0000, 0x7823, 0xffff, 0x7827, 0xffff, 0x782b, 0x0000, 0x782f,
+	0x0000, 0x2079, 0xa80c, 0x207b, 0x1101, 0x7807, 0x0000, 0x2099,
+	0xa305, 0x20a1, 0xa80e, 0x20a9, 0x0004, 0x53a3, 0x2079, 0xa812,
+	0x207b, 0x0000, 0x7807, 0x0000, 0x2099, 0xa800, 0x20a1, 0x020b,
+	0x20a9, 0x0014, 0x53a6, 0x60c3, 0x000c, 0x600f, 0x0000, 0x1078,
+	0x4158, 0x0f7f, 0x707f, 0x0000, 0x6043, 0x0008, 0x6043, 0x0000,
+	0x007c, 0x0d7e, 0x707c, 0x707f, 0x0000, 0xa025, 0x0040, 0x3bb5,
+	0x6020, 0xd0b4, 0x00c0, 0x3bb3, 0x7188, 0x81ff, 0x0040, 0x3ba2,
+	0xa486, 0x000c, 0x00c0, 0x3bad, 0xa480, 0x0018, 0x8004, 0x20a8,
+	0x2011, 0xa880, 0x2019, 0xa800, 0x220c, 0x2304, 0xa106, 0x00c0,
+	0x3b79, 0x8210, 0x8318, 0x00f0, 0x3b5c, 0x6043, 0x0004, 0x608b,
+	0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006, 0x707b, 0x0002, 0x7087,
+	0x0002, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c, 0x0078,
+	0x3bb3, 0x2069, 0xa880, 0x6930, 0xa18e, 0x1101, 0x00c0, 0x3bad,
+	0x6834, 0xa005, 0x00c0, 0x3bad, 0x6900, 0xa18c, 0x00ff, 0x00c0,
+	0x3b8d, 0x6804, 0xa005, 0x0040, 0x3ba2, 0x2011, 0xa88e, 0x2019,
+	0xa305, 0x20a9, 0x0004, 0x220c, 0x2304, 0xa102, 0x0048, 0x3ba0,
+	0x00c0, 0x3bad, 0x8210, 0x8318, 0x00f0, 0x3b93, 0x0078, 0x3bad,
+	0x708b, 0x0000, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880,
+	0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x6043, 0x0008, 0x6043,
+	0x0000, 0x0078, 0x3bb5, 0x0d7f, 0x007c, 0x6020, 0xd0b4, 0x00c0,
+	0x3bb3, 0x60c3, 0x000c, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f,
+	0x0000, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x1078,
+	0x6c38, 0x0078, 0x3bb3, 0x007c, 0x7084, 0xa08a, 0x001d, 0x00c8,
+	0x3bd5, 0x1079, 0x3bd8, 0x0078, 0x3bd7, 0x1078, 0x1328, 0x007c,
+	0x3c02, 0x3c11, 0x3c40, 0x3c59, 0x3c85, 0x3cb1, 0x3cdd, 0x3d13,
+	0x3d3f, 0x3d67, 0x3daa, 0x3dd4, 0x3df6, 0x3e0c, 0x3e32, 0x3e45,
+	0x3e4e, 0x3e7e, 0x3eaa, 0x3ed6, 0x3f02, 0x3f38, 0x3f7d, 0x3fac,
+	0x3fce, 0x4010, 0x4036, 0x404f, 0x4050, 0x0c7e, 0x2061, 0xa300,
+	0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9, 0x6006,
+	0x0c7f, 0x007c, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0002,
+	0x7087, 0x0001, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c,
+	0x007c, 0x0f7e, 0x707c, 0xa086, 0x0014, 0x00c0, 0x3c3e, 0x6043,
+	0x0000, 0x6020, 0xd0b4, 0x00c0, 0x3c3e, 0x2079, 0xa880, 0x7a30,
+	0xa296, 0x1102, 0x00c0, 0x3c3c, 0x7834, 0xa005, 0x00c0, 0x3c3c,
+	0x7a38, 0xd2fc, 0x0040, 0x3c32, 0x70ac, 0xa005, 0x00c0, 0x3c32,
+	0x70af, 0x0001, 0x2011, 0x4129, 0x1078, 0x58d4, 0x7087, 0x0010,
+	0x1078, 0x3e4e, 0x0078, 0x3c3e, 0x1078, 0x4171, 0x0f7f, 0x007c,
+	0x7087, 0x0003, 0x6043, 0x0004, 0x2011, 0x4129, 0x1078, 0x58d4,
+	0x1078, 0x41c6, 0x20a3, 0x1102, 0x20a3, 0x0000, 0x20a9, 0x000a,
+	0x20a3, 0x0000, 0x00f0, 0x3c50, 0x60c3, 0x0014, 0x1078, 0x4158,
+	0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3c83, 0x2011, 0x4129,
+	0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3c81, 0x2079, 0xa880,
+	0x7a30, 0xa296, 0x1102, 0x00c0, 0x3c81, 0x7834, 0xa005, 0x00c0,
+	0x3c81, 0x7a38, 0xd2fc, 0x0040, 0x3c7b, 0x70ac, 0xa005, 0x00c0,
+	0x3c7b, 0x70af, 0x0001, 0x7087, 0x0004, 0x1078, 0x3c85, 0x0078,
+	0x3c83, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0005, 0x1078,
+	0x41c6, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e,
+	0x1078, 0x4211, 0x00c0, 0x3ca3, 0x7070, 0xa005, 0x00c0, 0x3ca3,
+	0x714c, 0xa186, 0xffff, 0x0040, 0x3ca3, 0x1078, 0x40ea, 0x0040,
+	0x3ca3, 0x1078, 0x41f5, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158,
+	0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3cdb, 0x2011, 0x4129,
+	0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3cd9, 0x2079, 0xa880,
+	0x7a30, 0xa296, 0x1103, 0x00c0, 0x3cd9, 0x7834, 0xa005, 0x00c0,
+	0x3cd9, 0x7a38, 0xd2fc, 0x0040, 0x3cd3, 0x70ac, 0xa005, 0x00c0,
+	0x3cd3, 0x70af, 0x0001, 0x7087, 0x0006, 0x1078, 0x3cdd, 0x0078,
+	0x3cdb, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0007, 0x1078,
+	0x41c6, 0x20a3, 0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e,
+	0x1078, 0x4211, 0x00c0, 0x3d05, 0x7070, 0xa005, 0x00c0, 0x3d05,
+	0x7150, 0xa186, 0xffff, 0x0040, 0x3d05, 0xa180, 0x293f, 0x200c,
+	0xa18c, 0xff00, 0x810f, 0x1078, 0x40ea, 0x0040, 0x3d05, 0x1078,
+	0x378b, 0x0040, 0x3d05, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2298,
+	0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040, 0x3d3d,
+	0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0014, 0x00c0, 0x3d3b,
+	0x2079, 0xa880, 0x7a30, 0xa296, 0x1104, 0x00c0, 0x3d3b, 0x7834,
+	0xa005, 0x00c0, 0x3d3b, 0x7a38, 0xd2fc, 0x0040, 0x3d35, 0x70ac,
+	0xa005, 0x00c0, 0x3d35, 0x70af, 0x0001, 0x7087, 0x0008, 0x1078,
+	0x3d3f, 0x0078, 0x3d3d, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087,
+	0x0009, 0x1078, 0x41c6, 0x20a3, 0x1105, 0x20a3, 0x0100, 0x3430,
+	0x1078, 0x4211, 0x00c0, 0x3d58, 0x7070, 0xa005, 0x00c0, 0x3d58,
+	0x1078, 0x4051, 0x00c0, 0x3d62, 0xa085, 0x0001, 0x1078, 0x2500,
+	0x20a9, 0x0008, 0x2099, 0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e,
+	0x707c, 0xa005, 0x0040, 0x3da8, 0x2011, 0x4129, 0x1078, 0x58d4,
+	0xa086, 0x0014, 0x00c0, 0x3da6, 0x2079, 0xa880, 0x7a30, 0xa296,
+	0x1105, 0x00c0, 0x3da6, 0x7834, 0x2011, 0x0100, 0xa21e, 0x00c0,
+	0x3d91, 0x7a38, 0xd2fc, 0x0040, 0x3d8b, 0x70ac, 0xa005, 0x00c0,
+	0x3d8b, 0x70af, 0x0001, 0x7087, 0x000a, 0x1078, 0x3daa, 0x0078,
+	0x3da8, 0xa005, 0x00c0, 0x3da6, 0x7a38, 0xd2fc, 0x0040, 0x3d9e,
+	0x70ac, 0xa005, 0x00c0, 0x3d9e, 0x70af, 0x0001, 0x7083, 0x0000,
+	0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3da8, 0x1078, 0x4171,
+	0x0f7f, 0x007c, 0x7087, 0x000b, 0x2011, 0xa80e, 0x22a0, 0x20a9,
+	0x0040, 0x2019, 0xffff, 0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000,
+	0x41a4, 0x1078, 0x41c6, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x1078,
+	0x4211, 0x0040, 0x3dc7, 0x2013, 0x0000, 0x0078, 0x3dcb, 0x6030,
+	0xa085, 0x0100, 0x2012, 0x2298, 0x20a9, 0x0042, 0x53a6, 0x60c3,
+	0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040,
+	0x3df4, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0,
+	0x3df2, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3df2,
+	0x7834, 0xa005, 0x00c0, 0x3df2, 0x7087, 0x000c, 0x1078, 0x3df6,
+	0x0078, 0x3df4, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x000d,
+	0x1078, 0x41c6, 0x20a3, 0x1107, 0x20a3, 0x0000, 0x2099, 0xa88e,
+	0x20a9, 0x0040, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0084, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040,
+	0x3e30, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0,
+	0x3e2e, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1107, 0x00c0, 0x3e2e,
+	0x7834, 0xa005, 0x00c0, 0x3e2e, 0x7083, 0x0001, 0x1078, 0x41b8,
+	0x7087, 0x000e, 0x1078, 0x3e32, 0x0078, 0x3e30, 0x1078, 0x4171,
+	0x0f7f, 0x007c, 0x7087, 0x000f, 0x707f, 0x0000, 0x608b, 0xbc85,
+	0x608f, 0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0,
+	0x2011, 0x4129, 0x1078, 0x58c7, 0x007c, 0x707c, 0xa005, 0x0040,
+	0x3e4d, 0x2011, 0x4129, 0x1078, 0x58d4, 0x007c, 0x7087, 0x0011,
+	0x1078, 0x4211, 0x00c0, 0x3e67, 0x7168, 0x81ff, 0x0040, 0x3e67,
+	0x2009, 0x0000, 0x706c, 0xa084, 0x00ff, 0x1078, 0x24e3, 0xa186,
+	0x0080, 0x0040, 0x3e67, 0x2011, 0xa88e, 0x1078, 0x40ea, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x747c,
+	0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004, 0x20a8,
+	0x53a6, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c,
+	0xa005, 0x0040, 0x3ea8, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086,
+	0x0014, 0x00c0, 0x3ea6, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1103,
+	0x00c0, 0x3ea6, 0x7834, 0xa005, 0x00c0, 0x3ea6, 0x7a38, 0xd2fc,
+	0x0040, 0x3ea0, 0x70ac, 0xa005, 0x00c0, 0x3ea0, 0x70af, 0x0001,
+	0x7087, 0x0012, 0x1078, 0x3eaa, 0x0078, 0x3ea8, 0x1078, 0x4171,
+	0x0f7f, 0x007c, 0x7087, 0x0013, 0x1078, 0x41d2, 0x20a3, 0x1103,
+	0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0,
+	0x3ec8, 0x7070, 0xa005, 0x00c0, 0x3ec8, 0x714c, 0xa186, 0xffff,
+	0x0040, 0x3ec8, 0x1078, 0x40ea, 0x0040, 0x3ec8, 0x1078, 0x41f5,
+	0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c,
+	0xa005, 0x0040, 0x3f00, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086,
+	0x0014, 0x00c0, 0x3efe, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1104,
+	0x00c0, 0x3efe, 0x7834, 0xa005, 0x00c0, 0x3efe, 0x7a38, 0xd2fc,
+	0x0040, 0x3ef8, 0x70ac, 0xa005, 0x00c0, 0x3ef8, 0x70af, 0x0001,
+	0x7087, 0x0014, 0x1078, 0x3f02, 0x0078, 0x3f00, 0x1078, 0x4171,
+	0x0f7f, 0x007c, 0x7087, 0x0015, 0x1078, 0x41d2, 0x20a3, 0x1104,
+	0x20a3, 0x0000, 0x3430, 0x2011, 0xa88e, 0x1078, 0x4211, 0x00c0,
+	0x3f2a, 0x7070, 0xa005, 0x00c0, 0x3f2a, 0x7150, 0xa186, 0xffff,
+	0x0040, 0x3f2a, 0xa180, 0x293f, 0x200c, 0xa18c, 0xff00, 0x810f,
+	0x1078, 0x40ea, 0x0040, 0x3f2a, 0x1078, 0x378b, 0x0040, 0x3f2a,
+	0x1078, 0x2500, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x4158, 0x007c,
+	0x0f7e, 0x707c, 0xa005, 0x0040, 0x3f7b, 0x2011, 0x4129, 0x1078,
+	0x58d4, 0xa086, 0x0014, 0x00c0, 0x3f79, 0x2079, 0xa880, 0x7a30,
+	0xa296, 0x1105, 0x00c0, 0x3f79, 0x7834, 0x2011, 0x0100, 0xa21e,
+	0x00c0, 0x3f5e, 0x7a38, 0xd2fc, 0x0040, 0x3f5c, 0x70ac, 0xa005,
+	0x00c0, 0x3f5c, 0x70af, 0x0001, 0x0078, 0x3f6d, 0xa005, 0x00c0,
+	0x3f79, 0x7a38, 0xd2fc, 0x0040, 0x3f6b, 0x70ac, 0xa005, 0x00c0,
+	0x3f6b, 0x70af, 0x0001, 0x7083, 0x0000, 0x7a38, 0xd2f4, 0x0040,
+	0x3f73, 0x70cb, 0x0008, 0x7087, 0x0016, 0x1078, 0x3f7d, 0x0078,
+	0x3f7b, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x2099, 0xa880, 0x20a1, 0x020b, 0x20a9, 0x000e, 0x53a6,
+	0x3430, 0x2011, 0xa88e, 0x7087, 0x0017, 0x1078, 0x4211, 0x00c0,
+	0x3f9d, 0x7070, 0xa005, 0x00c0, 0x3f9d, 0x1078, 0x4051, 0x00c0,
+	0x3fa7, 0xa085, 0x0001, 0x1078, 0x2500, 0x20a9, 0x0008, 0x2099,
+	0xa88e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x1078, 0x4158, 0x007c, 0x0f7e, 0x707c, 0xa005, 0x0040,
+	0x3fcc, 0x2011, 0x4129, 0x1078, 0x58d4, 0xa086, 0x0084, 0x00c0,
+	0x3fca, 0x2079, 0xa880, 0x7a30, 0xa296, 0x1106, 0x00c0, 0x3fca,
+	0x7834, 0xa005, 0x00c0, 0x3fca, 0x7087, 0x0018, 0x1078, 0x3fce,
+	0x0078, 0x3fcc, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x0019,
+	0x1078, 0x41d2, 0x20a3, 0x1106, 0x20a3, 0x0000, 0x3430, 0x2099,
+	0xa88e, 0x2039, 0xa80e, 0x27a0, 0x20a9, 0x0040, 0x53a3, 0x1078,
+	0x4211, 0x00c0, 0x4002, 0x2728, 0x2514, 0x8207, 0xa084, 0x00ff,
+	0x8000, 0x2018, 0xa294, 0x00ff, 0x8007, 0xa205, 0x202a, 0x6030,
+	0x2310, 0x8214, 0xa2a0, 0xa80e, 0x2414, 0xa38c, 0x0001, 0x0040,
+	0x3ffd, 0xa294, 0xff00, 0x0078, 0x4000, 0xa294, 0x00ff, 0x8007,
+	0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c,
+	0x0f7e, 0x707c, 0xa005, 0x0040, 0x4034, 0x2011, 0x4129, 0x1078,
+	0x58d4, 0xa086, 0x0084, 0x00c0, 0x4032, 0x2079, 0xa880, 0x7a30,
+	0xa296, 0x1107, 0x00c0, 0x4032, 0x7834, 0xa005, 0x00c0, 0x4032,
+	0x7083, 0x0001, 0x1078, 0x41b8, 0x7087, 0x001a, 0x1078, 0x4036,
+	0x0078, 0x4034, 0x1078, 0x4171, 0x0f7f, 0x007c, 0x7087, 0x001b,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880, 0x20a1, 0x020b,
+	0x747c, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084, 0x03f8, 0x8004,
+	0x20a8, 0x53a6, 0x60c3, 0x0084, 0x1078, 0x4158, 0x007c, 0x007c,
+	0x007c, 0x087e, 0x097e, 0x2029, 0xa352, 0x252c, 0x20a9, 0x0008,
+	0x2041, 0xa80e, 0x28a0, 0x2099, 0xa88e, 0x53a3, 0x20a9, 0x0008,
+	0x2011, 0x0007, 0xd5d4, 0x0040, 0x4067, 0x2011, 0x0000, 0x2800,
+	0xa200, 0x200c, 0xa1a6, 0xffff, 0x00c0, 0x4079, 0xd5d4, 0x0040,
+	0x4074, 0x8210, 0x0078, 0x4075, 0x8211, 0x00f0, 0x4067, 0x0078,
+	0x40e1, 0x82ff, 0x00c0, 0x408b, 0xd5d4, 0x0040, 0x4085, 0xa1a6,
+	0x3fff, 0x0040, 0x4071, 0x0078, 0x4089, 0xa1a6, 0x3fff, 0x0040,
+	0x40e1, 0xa18d, 0xc000, 0x20a9, 0x0010, 0x2019, 0x0001, 0xd5d4,
+	0x0040, 0x4094, 0x2019, 0x0010, 0x2120, 0xd5d4, 0x0040, 0x409b,
+	0x8423, 0x0078, 0x409c, 0x8424, 0x00c8, 0x40a9, 0xd5d4, 0x0040,
+	0x40a4, 0x8319, 0x0078, 0x40a5, 0x8318, 0x00f0, 0x4095, 0x0078,
+	0x40e1, 0x23a8, 0x2021, 0x0001, 0x8426, 0x8425, 0x00f0, 0x40ad,
+	0x2328, 0x8529, 0xa2be, 0x0007, 0x0040, 0x40c1, 0x007e, 0x2039,
+	0x0007, 0x2200, 0xa73a, 0x007f, 0x27a8, 0xa5a8, 0x0010, 0x00f0,
+	0x40bd, 0x754e, 0xa5c8, 0x293f, 0x292c, 0xa5ac, 0x00ff, 0x6532,
+	0x60e7, 0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x2018, 0x2304,
+	0xa405, 0x201a, 0x7073, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0078,
+	0x40e7, 0xa006, 0x0078, 0x40e7, 0xa006, 0x1078, 0x1328, 0x097f,
+	0x087f, 0x007c, 0x2118, 0x2021, 0x0000, 0x2001, 0x0007, 0xa39a,
+	0x0010, 0x0048, 0x40f7, 0x8420, 0x8001, 0x0078, 0x40ef, 0x2118,
+	0x84ff, 0x0040, 0x4100, 0xa39a, 0x0010, 0x8421, 0x00c0, 0x40fb,
+	0x2021, 0x0001, 0x83ff, 0x0040, 0x4109, 0x8423, 0x8319, 0x00c0,
+	0x4105, 0xa238, 0x2704, 0xa42c, 0x00c0, 0x4121, 0xa405, 0x203a,
+	0x714e, 0xa1a0, 0x293f, 0x242c, 0xa5ac, 0x00ff, 0x6532, 0x60e7,
+	0x0000, 0x65ea, 0x706b, 0x0000, 0x756e, 0x7073, 0x0001, 0xa084,
+	0x0000, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x7077, 0x0000, 0x0e7f,
+	0x007c, 0x0e7e, 0x0f7e, 0x2001, 0x0002, 0x1078, 0x5975, 0x2079,
+	0x0100, 0x2071, 0x0140, 0x1078, 0x6c41, 0x7004, 0xa084, 0x4000,
+	0x0040, 0x413e, 0x7003, 0x1000, 0x7003, 0x0000, 0x127e, 0x2091,
+	0x8000, 0x2071, 0xa321, 0x2073, 0x0000, 0x7840, 0x027e, 0x017e,
+	0x2009, 0x00f7, 0x1078, 0x41de, 0x017f, 0xa094, 0x0010, 0xa285,
+	0x0080, 0x7842, 0x7a42, 0x027f, 0x127f, 0x0f7f, 0x0e7f, 0x007c,
+	0x127e, 0x2091, 0x8000, 0x2011, 0xa5b5, 0x2013, 0x0000, 0x707f,
+	0x0000, 0x127f, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575,
+	0x1078, 0x6c38, 0x2009, 0x07d0, 0x2011, 0x4129, 0x1078, 0x596c,
+	0x007c, 0x017e, 0x027e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x2009,
+	0x00f7, 0x1078, 0x41de, 0x2061, 0xa5be, 0x601b, 0x0000, 0x601f,
+	0x0000, 0x2061, 0xa300, 0x6003, 0x0001, 0x2061, 0x0100, 0x6043,
+	0x0090, 0x6043, 0x0010, 0x2009, 0x002d, 0x2011, 0x4196, 0x1078,
+	0x58c7, 0x127f, 0x0c7f, 0x027f, 0x017f, 0x007c, 0x0e7e, 0x007e,
+	0x127e, 0x2091, 0x8000, 0x2001, 0x0001, 0x1078, 0x5975, 0x2071,
+	0x0100, 0x1078, 0x6c41, 0x2071, 0x0140, 0x7004, 0xa084, 0x4000,
+	0x0040, 0x41ae, 0x7003, 0x1000, 0x7003, 0x0000, 0x2001, 0x0001,
+	0x1078, 0x2480, 0x1078, 0x4171, 0x127f, 0x007f, 0x0e7f, 0x007c,
+	0x20a9, 0x0040, 0x20a1, 0xa9c0, 0x2099, 0xa88e, 0x3304, 0x8007,
+	0x20a2, 0x9398, 0x94a0, 0x00f0, 0x41be, 0x007c, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x2099, 0xa800, 0x20a1, 0x020b, 0x20a9, 0x000c,
+	0x53a6, 0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xa880,
+	0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x007c, 0x0c7e, 0x007e,
+	0x2061, 0x0100, 0x810f, 0x2001, 0xa32e, 0x2004, 0xa005, 0x00c0,
+	0x41ef, 0x6030, 0xa084, 0x00ff, 0xa105, 0x0078, 0x41f1, 0xa185,
+	0x00f7, 0x604a, 0x007f, 0x0c7f, 0x007c, 0x017e, 0x047e, 0x2001,
+	0xa352, 0x2004, 0xd0a4, 0x0040, 0x4208, 0xa006, 0x2020, 0x2009,
+	0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195, 0x2102,
+	0x2019, 0x002a, 0x2009, 0x0000, 0x1078, 0x27e2, 0x047f, 0x017f,
+	0x007c, 0x007e, 0x2001, 0xa30c, 0x2004, 0xd09c, 0x0040, 0x4218,
+	0x007f, 0x007c, 0x007e, 0x017e, 0x127e, 0x2091, 0x8000, 0x2001,
+	0x0101, 0x200c, 0xa18d, 0x0006, 0x2102, 0x127f, 0x017f, 0x007f,
+	0x007c, 0x157e, 0x20a9, 0x00ff, 0x2009, 0xa434, 0xa006, 0x200a,
+	0x8108, 0x00f0, 0x422f, 0x157f, 0x007c, 0x0d7e, 0x037e, 0x157e,
+	0x137e, 0x147e, 0x2069, 0xa351, 0xa006, 0x6002, 0x6007, 0x0707,
+	0x600a, 0x600e, 0x6012, 0xa198, 0x293f, 0x231c, 0xa39c, 0x00ff,
+	0x6316, 0x20a9, 0x0004, 0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9,
+	0x0004, 0xac98, 0x000a, 0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e,
+	0x6052, 0x6056, 0x605a, 0x605e, 0x6062, 0x6066, 0x606a, 0x606e,
+	0x6072, 0x6076, 0x607a, 0x607e, 0x6082, 0x6086, 0x608a, 0x608e,
+	0x6092, 0x6096, 0x609a, 0x609e, 0x60ae, 0x61a2, 0x0d7e, 0x60a4,
+	0xa06d, 0x0040, 0x4275, 0x1078, 0x139a, 0x60a7, 0x0000, 0x60a8,
+	0xa06d, 0x0040, 0x427d, 0x1078, 0x139a, 0x60ab, 0x0000, 0x0d7f,
+	0xa006, 0x604a, 0x6810, 0x603a, 0x680c, 0x6046, 0x6814, 0xa084,
+	0x00ff, 0x6042, 0x147f, 0x137f, 0x157f, 0x037f, 0x0d7f, 0x007c,
+	0x127e, 0x2091, 0x8000, 0x6944, 0x6e48, 0xa684, 0x3fff, 0xa082,
+	0x4000, 0x00c8, 0x4361, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff,
+	0x00c8, 0x4367, 0x2001, 0xa30c, 0x2004, 0xa084, 0x0003, 0x0040,
+	0x42c2, 0x2001, 0xa30c, 0x2004, 0xd084, 0x00c0, 0x4342, 0xa188,
+	0xa434, 0x2104, 0xa065, 0x0040, 0x4342, 0x6004, 0xa084, 0x00ff,
+	0xa08e, 0x0006, 0x00c0, 0x4342, 0x6000, 0xd0c4, 0x0040, 0x4342,
+	0x0078, 0x42cf, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4326,
+	0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x00c0, 0x432c, 0x60a4,
+	0xa00d, 0x0040, 0x42d7, 0x1078, 0x4749, 0x0040, 0x4320, 0x60a8,
+	0xa00d, 0x0040, 0x42f1, 0x1078, 0x479a, 0x00c0, 0x42f1, 0x694c,
+	0xd1fc, 0x00c0, 0x42e7, 0x1078, 0x441c, 0x0078, 0x431b, 0x1078,
+	0x43d6, 0x694c, 0xd1ec, 0x00c0, 0x431b, 0x1078, 0x460a, 0x0078,
+	0x431b, 0x694c, 0xa184, 0xa000, 0x0040, 0x430b, 0xd1ec, 0x0040,
+	0x4304, 0xd1fc, 0x0040, 0x4300, 0x1078, 0x461b, 0x0078, 0x4307,
+	0x1078, 0x461b, 0x0078, 0x430b, 0xd1fc, 0x0040, 0x430b, 0x1078,
+	0x43d6, 0x0078, 0x431b, 0x6050, 0xa00d, 0x0040, 0x4316, 0x2d00,
+	0x200a, 0x6803, 0x0000, 0x6052, 0x0078, 0x431b, 0x2d00, 0x6052,
+	0x604e, 0x6803, 0x0000, 0x1078, 0x5c17, 0xa006, 0x127f, 0x007c,
+	0x2001, 0x0005, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001, 0x0028,
+	0x2009, 0x0000, 0x0078, 0x436b, 0xa082, 0x0006, 0x00c8, 0x4342,
+	0x60a0, 0xd0bc, 0x00c0, 0x433e, 0x6100, 0xd1fc, 0x0040, 0x42cf,
+	0x2001, 0x0029, 0x2009, 0x1000, 0x0078, 0x436b, 0x2001, 0x0028,
+	0x0078, 0x435d, 0x2009, 0xa30c, 0x210c, 0xd18c, 0x0040, 0x434c,
+	0x2001, 0x0004, 0x0078, 0x435d, 0xd184, 0x0040, 0x4353, 0x2001,
+	0x0004, 0x0078, 0x435d, 0x2001, 0x0029, 0x6100, 0xd1fc, 0x0040,
+	0x435d, 0x2009, 0x1000, 0x0078, 0x436b, 0x2009, 0x0000, 0x0078,
+	0x436b, 0x2001, 0x0029, 0x2009, 0x0000, 0x0078, 0x436b, 0x2001,
+	0x0029, 0x2009, 0x0000, 0xa005, 0x127f, 0x007c, 0x6944, 0x6e48,
+	0xa684, 0x3fff, 0xa082, 0x4000, 0x00c8, 0x43bb, 0xa18c, 0xff00,
+	0x810f, 0xa182, 0x00ff, 0x00c8, 0x43a1, 0xa188, 0xa434, 0x2104,
+	0xa065, 0x0040, 0x43a1, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006,
+	0x00c0, 0x43a7, 0x684c, 0xd0ec, 0x0040, 0x4394, 0x1078, 0x461b,
+	0x1078, 0x43d6, 0x0078, 0x439c, 0x1078, 0x43d6, 0x684c, 0xd0fc,
+	0x0040, 0x439c, 0x1078, 0x460a, 0x1078, 0x4663, 0xa006, 0x0078,
+	0x43bf, 0x2001, 0x0028, 0x2009, 0x0000, 0x0078, 0x43bf, 0xa082,
+	0x0006, 0x00c8, 0x43b5, 0x6100, 0xd1fc, 0x0040, 0x438a, 0x2001,
+	0x0029, 0x2009, 0x1000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009,
+	0x0000, 0x0078, 0x43bf, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005,
+	0x007c, 0x127e, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0040, 0x43cf,
+	0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x127f, 0x007c, 0x2d00,
+	0x6052, 0x604e, 0x6803, 0x0000, 0x0078, 0x43cd, 0x127e, 0x2091,
+	0x8000, 0x604c, 0xa005, 0x0040, 0x43ec, 0x0e7e, 0x2071, 0xa5ab,
+	0x7004, 0xa086, 0x0002, 0x0040, 0x43f3, 0x0e7f, 0x604c, 0x6802,
+	0x2d00, 0x604e, 0x127f, 0x007c, 0x2d00, 0x6052, 0x604e, 0x6803,
+	0x0000, 0x0078, 0x43ea, 0x701c, 0xac06, 0x00c0, 0x43e5, 0x604c,
+	0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x0e7f, 0x127f, 0x007c,
+	0x127e, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0040, 0x440e, 0x6800,
+	0xa005, 0x00c0, 0x440c, 0x6052, 0x604e, 0xad05, 0x127f, 0x007c,
+	0x604c, 0xa06d, 0x0040, 0x441b, 0x6800, 0xa005, 0x00c0, 0x4419,
+	0x6052, 0x604e, 0xad05, 0x007c, 0x6803, 0x0000, 0x6084, 0xa00d,
+	0x0040, 0x4426, 0x2d00, 0x200a, 0x6086, 0x007c, 0x2d00, 0x6086,
+	0x6082, 0x0078, 0x4425, 0x127e, 0x0c7e, 0x027e, 0x2091, 0x8000,
+	0x6218, 0x2260, 0x6200, 0xa005, 0x0040, 0x4439, 0xc285, 0x0078,
+	0x443a, 0xc284, 0x6202, 0x027f, 0x0c7f, 0x127f, 0x007c, 0x127e,
+	0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0x007e, 0xa086,
+	0x0006, 0x00c0, 0x445e, 0x609c, 0xd0ac, 0x0040, 0x445e, 0x2001,
+	0xa352, 0x2004, 0xd0a4, 0x0040, 0x445e, 0xa284, 0xff00, 0x8007,
+	0xa086, 0x0007, 0x00c0, 0x445e, 0x2011, 0x0600, 0x007f, 0xa294,
+	0xff00, 0xa215, 0x6206, 0x007e, 0xa086, 0x0006, 0x00c0, 0x446e,
+	0x6290, 0x82ff, 0x00c0, 0x446e, 0x1078, 0x1328, 0x007f, 0x0c7f,
+	0x127f, 0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x6218, 0x2260,
+	0x6204, 0x007e, 0xa086, 0x0006, 0x00c0, 0x4490, 0x609c, 0xd0a4,
+	0x0040, 0x4490, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x4490,
+	0xa284, 0x00ff, 0xa086, 0x0007, 0x00c0, 0x4490, 0x2011, 0x0006,
+	0x007f, 0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x0c7f, 0x127f,
+	0x007c, 0x027e, 0xa182, 0x00ff, 0x0048, 0x44a2, 0xa085, 0x0001,
+	0x0078, 0x44ba, 0xa190, 0xa434, 0x2204, 0xa065, 0x00c0, 0x44b9,
+	0x017e, 0x0d7e, 0x1078, 0x1366, 0x2d60, 0x0d7f, 0x017f, 0x0040,
+	0x449e, 0x2c00, 0x2012, 0x60a7, 0x0000, 0x60ab, 0x0000, 0x1078,
+	0x4235, 0xa006, 0x027f, 0x007c, 0x127e, 0x2091, 0x8000, 0x027e,
+	0xa182, 0x00ff, 0x0048, 0x44c8, 0xa085, 0x0001, 0x0078, 0x44fe,
+	0x0d7e, 0xa190, 0xa434, 0x2204, 0xa06d, 0x0040, 0x44fc, 0x2013,
+	0x0000, 0x0d7e, 0x0c7e, 0x2d60, 0x60a4, 0xa06d, 0x0040, 0x44da,
+	0x1078, 0x139a, 0x60a8, 0xa06d, 0x0040, 0x44e0, 0x1078, 0x139a,
+	0x0c7f, 0x0d7f, 0x0d7e, 0x0c7e, 0x68ac, 0x2060, 0x8cff, 0x0040,
+	0x44f8, 0x600c, 0x007e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040,
+	0x44f3, 0x1078, 0x13aa, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x44e6,
+	0x0c7f, 0x0d7f, 0x1078, 0x139a, 0x0d7f, 0xa006, 0x027f, 0x127f,
+	0x007c, 0x017e, 0xa182, 0x00ff, 0x0048, 0x450a, 0xa085, 0x0001,
+	0x0078, 0x4511, 0xa188, 0xa434, 0x2104, 0xa065, 0x0040, 0x4506,
+	0xa006, 0x017f, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x600b,
+	0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x2069, 0xa88e,
+	0x6808, 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a, 0x0048, 0x4529,
+	0x603a, 0x6814, 0x6066, 0x2099, 0xa896, 0xac88, 0x000a, 0x21a0,
+	0x20a9, 0x0004, 0x53a3, 0x2099, 0xa89a, 0xac88, 0x0006, 0x21a0,
+	0x20a9, 0x0004, 0x53a3, 0x2069, 0xa8ae, 0x6808, 0x606a, 0x690c,
+	0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0xa182, 0x0211, 0x00c8,
+	0x454d, 0x2009, 0x0008, 0x0078, 0x4577, 0xa182, 0x0259, 0x00c8,
+	0x4555, 0x2009, 0x0007, 0x0078, 0x4577, 0xa182, 0x02c1, 0x00c8,
+	0x455d, 0x2009, 0x0006, 0x0078, 0x4577, 0xa182, 0x0349, 0x00c8,
+	0x4565, 0x2009, 0x0005, 0x0078, 0x4577, 0xa182, 0x0421, 0x00c8,
+	0x456d, 0x2009, 0x0004, 0x0078, 0x4577, 0xa182, 0x0581, 0x00c8,
+	0x4575, 0x2009, 0x0003, 0x0078, 0x4577, 0x2009, 0x0002, 0x6192,
+	0x147f, 0x137f, 0x157f, 0x0d7f, 0x007c, 0x017e, 0x027e, 0x0e7e,
+	0x2071, 0xa88d, 0x2e04, 0x6896, 0x2071, 0xa88e, 0x7004, 0x689a,
+	0x701c, 0x689e, 0x6a00, 0x2009, 0xa371, 0x210c, 0xd0bc, 0x0040,
+	0x4597, 0xd1ec, 0x0040, 0x4597, 0xc2ad, 0x0078, 0x4598, 0xc2ac,
+	0xd0c4, 0x0040, 0x45a1, 0xd1e4, 0x0040, 0x45a1, 0xc2bd, 0x0078,
+	0x45a2, 0xc2bc, 0x6a02, 0x0e7f, 0x027f, 0x017f, 0x007c, 0x0d7e,
+	0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x0040, 0x45cb, 0x6900,
+	0x81ff, 0x00c0, 0x45df, 0x6a04, 0xa282, 0x0010, 0x00c8, 0x45e4,
+	0xad88, 0x0004, 0x20a9, 0x0010, 0x2104, 0xa086, 0xffff, 0x0040,
+	0x45c6, 0x8108, 0x00f0, 0x45bc, 0x1078, 0x1328, 0x260a, 0x8210,
+	0x6a06, 0x0078, 0x45df, 0x1078, 0x1381, 0x0040, 0x45e4, 0x2d00,
+	0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b,
+	0xffff, 0x8108, 0x00f0, 0x45d7, 0x6807, 0x0001, 0x6e12, 0xa085,
+	0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006, 0x0078, 0x45e1, 0x127e,
+	0x2091, 0x8000, 0x0d7e, 0x60a4, 0xa00d, 0x0040, 0x4607, 0x2168,
+	0x6800, 0xa005, 0x00c0, 0x4603, 0x1078, 0x4749, 0x00c0, 0x4607,
+	0x200b, 0xffff, 0x6804, 0xa08a, 0x0002, 0x0048, 0x4603, 0x8001,
+	0x6806, 0x0078, 0x4607, 0x1078, 0x139a, 0x60a7, 0x0000, 0x0d7f,
+	0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x47af, 0x0078,
+	0x4613, 0x1078, 0x43c1, 0x1078, 0x46a7, 0x00c0, 0x4611, 0x1078,
+	0x4663, 0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a8,
+	0xa06d, 0x0040, 0x463f, 0x6950, 0x81ff, 0x00c0, 0x4653, 0x6a54,
+	0xa282, 0x0010, 0x00c8, 0x4660, 0xad88, 0x0018, 0x20a9, 0x0010,
+	0x2104, 0xa086, 0xffff, 0x0040, 0x463a, 0x8108, 0x00f0, 0x4630,
+	0x1078, 0x1328, 0x260a, 0x8210, 0x6a56, 0x0078, 0x4653, 0x1078,
+	0x1381, 0x0040, 0x4660, 0x2d00, 0x60aa, 0x6853, 0x0000, 0xad88,
+	0x0018, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108, 0x00f0, 0x464b,
+	0x6857, 0x0001, 0x6e62, 0x0078, 0x4657, 0x1078, 0x441c, 0x1078,
+	0x466d, 0x00c0, 0x4655, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c,
+	0xa006, 0x0078, 0x465d, 0x127e, 0x2091, 0x8000, 0x1078, 0x5c17,
+	0x127f, 0x007c, 0xa01e, 0x0078, 0x466f, 0x2019, 0x0001, 0xa00e,
+	0x127e, 0x2091, 0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x00c0,
+	0x468d, 0x8dff, 0x0040, 0x46a2, 0x83ff, 0x0040, 0x4685, 0x6848,
+	0xa606, 0x0040, 0x4692, 0x0078, 0x468d, 0x683c, 0xa406, 0x00c0,
+	0x468d, 0x6840, 0xa506, 0x0040, 0x4692, 0x2d08, 0x6800, 0x2068,
+	0x0078, 0x4679, 0x6a00, 0x604c, 0xad06, 0x00c0, 0x469a, 0x624e,
+	0x0078, 0x469d, 0xa180, 0x0000, 0x2202, 0x82ff, 0x00c0, 0x46a2,
+	0x6152, 0x8dff, 0x127f, 0x007c, 0xa01e, 0x0078, 0x46a9, 0x2019,
+	0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x0040, 0x46d5, 0x83ff,
+	0x0040, 0x46b8, 0x6848, 0xa606, 0x0040, 0x46c5, 0x0078, 0x46c0,
+	0x683c, 0xa406, 0x00c0, 0x46c0, 0x6840, 0xa506, 0x0040, 0x46c5,
+	0x2d08, 0x6800, 0x2068, 0x0078, 0x46ac, 0x6a00, 0x6080, 0xad06,
+	0x00c0, 0x46cd, 0x6282, 0x0078, 0x46d0, 0xa180, 0x0000, 0x2202,
+	0x82ff, 0x00c0, 0x46d5, 0x6186, 0x8dff, 0x007c, 0xa016, 0x1078,
+	0x4742, 0x00c0, 0x46dd, 0x2011, 0x0001, 0x1078, 0x4793, 0x00c0,
+	0x46e3, 0xa295, 0x0002, 0x007c, 0x1078, 0x47cb, 0x0040, 0x46ec,
+	0x1078, 0x8b12, 0x0078, 0x46ee, 0xa085, 0x0001, 0x007c, 0x1078,
+	0x47cb, 0x0040, 0x46f7, 0x1078, 0x8aaa, 0x0078, 0x46f9, 0xa085,
+	0x0001, 0x007c, 0x1078, 0x47cb, 0x0040, 0x4702, 0x1078, 0x8af4,
+	0x0078, 0x4704, 0xa085, 0x0001, 0x007c, 0x1078, 0x47cb, 0x0040,
+	0x470d, 0x1078, 0x8ac6, 0x0078, 0x470f, 0xa085, 0x0001, 0x007c,
+	0x1078, 0x47cb, 0x0040, 0x4718, 0x1078, 0x8b30, 0x0078, 0x471a,
+	0xa085, 0x0001, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x8000,
+	0x6080, 0xa06d, 0x0040, 0x473a, 0x6800, 0x007e, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x007e, 0x6000, 0xd0fc,
+	0x0040, 0x4734, 0x1078, 0xa18c, 0x007f, 0x1078, 0x4982, 0x007f,
+	0x0078, 0x4721, 0x6083, 0x0000, 0x6087, 0x0000, 0x0d7f, 0x007f,
+	0x127f, 0x007c, 0x60a4, 0xa00d, 0x00c0, 0x4749, 0xa085, 0x0001,
+	0x007c, 0x0e7e, 0x2170, 0x7000, 0xa005, 0x00c0, 0x475c, 0x20a9,
+	0x0010, 0xae88, 0x0004, 0x2104, 0xa606, 0x0040, 0x475c, 0x8108,
+	0x00f0, 0x4753, 0xa085, 0x0001, 0xa006, 0x0e7f, 0x007c, 0x0d7e,
+	0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d, 0x00c0, 0x476d, 0x1078,
+	0x1381, 0x0040, 0x477f, 0x2d00, 0x60a6, 0x6803, 0x0001, 0x6807,
+	0x0000, 0xad88, 0x0004, 0x20a9, 0x0010, 0x200b, 0xffff, 0x8108,
+	0x00f0, 0x4775, 0xa085, 0x0001, 0x127f, 0x0d7f, 0x007c, 0xa006,
+	0x0078, 0x477c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x60a4, 0xa06d,
+	0x0040, 0x4790, 0x60a7, 0x0000, 0x1078, 0x139a, 0xa085, 0x0001,
+	0x127f, 0x0d7f, 0x007c, 0x60a8, 0xa00d, 0x00c0, 0x479a, 0xa085,
+	0x0001, 0x007c, 0x0e7e, 0x2170, 0x7050, 0xa005, 0x00c0, 0x47ad,
+	0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0040, 0x47ad,
+	0x8108, 0x00f0, 0x47a4, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x4793, 0x00c0, 0x47c9, 0x200b, 0xffff,
+	0x0d7e, 0x60a8, 0x2068, 0x6854, 0xa08a, 0x0002, 0x0048, 0x47c4,
+	0x8001, 0x6856, 0x0078, 0x47c8, 0x1078, 0x139a, 0x60ab, 0x0000,
+	0x0d7f, 0x127f, 0x007c, 0x609c, 0xd0a4, 0x007c, 0x0f7e, 0x71ac,
+	0x81ff, 0x00c0, 0x47e9, 0x71c8, 0xd19c, 0x0040, 0x47e9, 0x2001,
+	0x007e, 0xa080, 0xa434, 0x2004, 0xa07d, 0x0040, 0x47e9, 0x7804,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x47e9, 0x7800, 0xc0ed,
+	0x7802, 0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x480f, 0x157e,
+	0x0c7e, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501,
+	0x00c0, 0x4809, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004,
+	0x0040, 0x4806, 0xa086, 0x0006, 0x00c0, 0x4809, 0x6000, 0xc0ed,
+	0x6002, 0x017f, 0x8108, 0x00f0, 0x47f5, 0x0c7f, 0x157f, 0x1078,
+	0x4897, 0x0040, 0x4818, 0x2001, 0xa59f, 0x200c, 0x0078, 0x4820,
+	0x2079, 0xa351, 0x7804, 0xd0a4, 0x0040, 0x4824, 0x2009, 0x07d0,
+	0x2011, 0x4826, 0x1078, 0x596c, 0x0f7f, 0x007c, 0x2011, 0x4826,
+	0x1078, 0x58d4, 0x1078, 0x4897, 0x0040, 0x484e, 0x2001, 0xa4b2,
+	0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102, 0x2001, 0xa352,
+	0x2004, 0xd0a4, 0x0040, 0x4842, 0x2009, 0x07d0, 0x2011, 0x4826,
+	0x1078, 0x596c, 0x0e7e, 0x2071, 0xa300, 0x706b, 0x0000, 0x706f,
+	0x0000, 0x1078, 0x260d, 0x0e7f, 0x0078, 0x4886, 0x157e, 0x0c7e,
+	0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x1078, 0x4501, 0x00c0,
+	0x4880, 0x6000, 0xd0ec, 0x0040, 0x4880, 0x047e, 0x62a0, 0xa294,
+	0x00ff, 0x8227, 0xa006, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6000,
+	0xc0e5, 0xc0ec, 0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700,
+	0x6006, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000,
+	0x1078, 0x5c78, 0x2009, 0x0000, 0x1078, 0x9c38, 0x077f, 0x047f,
+	0x017f, 0x8108, 0x00f0, 0x4854, 0x0c7f, 0x157f, 0x007c, 0x0c7e,
+	0x6018, 0x2060, 0x6000, 0xc0ec, 0x6002, 0x0c7f, 0x007c, 0x7818,
+	0x2004, 0xd0ac, 0x007c, 0x7818, 0x2004, 0xd0bc, 0x007c, 0x0f7e,
+	0x2001, 0xa4b2, 0x2004, 0xa07d, 0x0040, 0x48a0, 0x7800, 0xd0ec,
+	0x0f7f, 0x007c, 0x127e, 0x027e, 0x2091, 0x8000, 0x6200, 0xa005,
+	0x0040, 0x48ad, 0xc2fd, 0x0078, 0x48ae, 0xc2fc, 0x6202, 0x027f,
+	0x127f, 0x007c, 0x2071, 0xa413, 0x7003, 0x0001, 0x7007, 0x0000,
+	0x7013, 0x0000, 0x7017, 0x0000, 0x701b, 0x0000, 0x701f, 0x0000,
+	0x700b, 0x0000, 0x704b, 0x0001, 0x704f, 0x0000, 0x705b, 0x0020,
+	0x705f, 0x0040, 0x707f, 0x0000, 0x2071, 0xa57c, 0x7003, 0xa413,
+	0x7007, 0x0000, 0x700b, 0x0000, 0x700f, 0xa55c, 0x7013, 0x0020,
+	0x7017, 0x0040, 0x7037, 0x0000, 0x007c, 0x017e, 0x0e7e, 0x2071,
+	0xa534, 0xa00e, 0x7186, 0x718a, 0x7097, 0x0001, 0x2001, 0xa352,
+	0x2004, 0xd0fc, 0x00c0, 0x48f7, 0x2001, 0xa352, 0x2004, 0xa00e,
+	0xd09c, 0x0040, 0x48f4, 0x8108, 0x7102, 0x0078, 0x494a, 0x2001,
+	0xa371, 0x200c, 0xa184, 0x000f, 0x2009, 0xa372, 0x210c, 0x0079,
+	0x4901, 0x48ec, 0x4922, 0x492a, 0x4935, 0x493b, 0x48ec, 0x48ec,
+	0x48ec, 0x4911, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec, 0x48ec,
+	0x48ec, 0x7003, 0x0004, 0x137e, 0x147e, 0x157e, 0x2099, 0xa375,
+	0x20a1, 0xa585, 0x20a9, 0x0004, 0x53a3, 0x157f, 0x147f, 0x137f,
+	0x0078, 0x494a, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002,
+	0x0078, 0x4930, 0x708f, 0x0002, 0x7007, 0x0121, 0x2001, 0x0003,
+	0x7002, 0x7097, 0x0001, 0x0078, 0x4947, 0x7007, 0x0122, 0x2001,
+	0x0002, 0x0078, 0x493f, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002,
+	0xa006, 0x7096, 0x708e, 0xa184, 0xff00, 0x8007, 0x709a, 0xa184,
+	0x00ff, 0x7092, 0x0e7f, 0x017f, 0x007c, 0x0e7e, 0x2071, 0xa413,
+	0x684c, 0xa005, 0x00c0, 0x495b, 0x7028, 0xc085, 0x702a, 0xa085,
+	0x0001, 0x0078, 0x4980, 0x6a60, 0x7236, 0x6b64, 0x733a, 0x6868,
+	0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c, 0x702e, 0x6844,
+	0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000, 0x8007, 0x8006,
+	0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319,
+	0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0xa006,
+	0x0e7f, 0x007c, 0x0e7e, 0x027e, 0x6838, 0xd0fc, 0x00c0, 0x49d8,
+	0x6804, 0xa00d, 0x0040, 0x499e, 0x0d7e, 0x2071, 0xa300, 0xa016,
+	0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00, 0x81ff, 0x00c0,
+	0x4991, 0x702e, 0x70a8, 0xa200, 0x70aa, 0x0d7f, 0x2071, 0xa413,
+	0x701c, 0xa005, 0x00c0, 0x49ea, 0x0068, 0x49e8, 0x2071, 0xa534,
+	0x7200, 0x82ff, 0x0040, 0x49e8, 0x6934, 0xa186, 0x0103, 0x00c0,
+	0x49fb, 0x6948, 0x6844, 0xa105, 0x00c0, 0x49db, 0x2009, 0x8020,
+	0x2200, 0x0079, 0x49bb, 0x49e8, 0x49c0, 0x4a18, 0x4a26, 0x49e8,
+	0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x49e8, 0x7122, 0x683c,
+	0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x2071,
+	0xa300, 0x702c, 0x206a, 0x2d00, 0x702e, 0x70a8, 0x8000, 0x70aa,
+	0x027f, 0x0e7f, 0x007c, 0x6844, 0xa086, 0x0100, 0x00c0, 0x49e8,
+	0x6868, 0xa005, 0x00c0, 0x49e8, 0x2009, 0x8020, 0x0078, 0x49b8,
+	0x2071, 0xa413, 0x2d08, 0x206b, 0x0000, 0x7010, 0x8000, 0x7012,
+	0x7018, 0xa06d, 0x711a, 0x0040, 0x49f8, 0x6902, 0x0078, 0x49f9,
+	0x711e, 0x0078, 0x49d8, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0040,
+	0x4a09, 0xa186, 0x001e, 0x0040, 0x4a09, 0xa18e, 0x001f, 0x00c0,
+	0x49e8, 0x684c, 0xd0cc, 0x0040, 0x49e8, 0x6850, 0xa084, 0x00ff,
+	0xa086, 0x0001, 0x00c0, 0x49e8, 0x2009, 0x8021, 0x0078, 0x49b8,
+	0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x49e8, 0x7186, 0xae90,
+	0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x4a36, 0x7084, 0x8008,
+	0xa092, 0x000f, 0x00c8, 0x49e8, 0x7186, 0xae90, 0x0003, 0x8003,
+	0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a,
+	0x0048, 0x49cf, 0x718c, 0x7084, 0xa10a, 0x0048, 0x49cf, 0x2071,
+	0x0000, 0x7018, 0xd084, 0x00c0, 0x49cf, 0x2071, 0xa534, 0x7000,
+	0xa086, 0x0002, 0x00c0, 0x4a56, 0x1078, 0x4cd2, 0x2071, 0x0000,
+	0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf, 0x1078, 0x4cfd,
+	0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x49cf,
+	0x007e, 0x684c, 0x007e, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80,
+	0x0011, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x007f, 0xa084, 0x00ff,
+	0x684e, 0x007f, 0x684a, 0x6952, 0x007c, 0x2071, 0xa413, 0x7004,
+	0x0079, 0x4a7a, 0x4a84, 0x4a95, 0x4ca3, 0x4ca4, 0x4ccb, 0x4cd1,
+	0x4a85, 0x4c91, 0x4c32, 0x4cb4, 0x007c, 0x127e, 0x2091, 0x8000,
+	0x0068, 0x4a94, 0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080,
+	0x7007, 0x0001, 0x700b, 0x0000, 0x127f, 0x2069, 0xa5be, 0x6844,
+	0xa005, 0x0050, 0x4abd, 0x00c0, 0x4abd, 0x127e, 0x2091, 0x8000,
+	0x2069, 0x0000, 0x6934, 0x2001, 0xa41f, 0x2004, 0xa10a, 0x0040,
+	0x4ab8, 0x0068, 0x4abc, 0x2069, 0x0000, 0x6818, 0xd084, 0x00c0,
+	0x4abc, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080,
+	0x2069, 0xa5be, 0x6847, 0xffff, 0x127f, 0x2069, 0xa300, 0x6844,
+	0x6960, 0xa102, 0x2069, 0xa534, 0x688a, 0x6984, 0x701c, 0xa06d,
+	0x0040, 0x4acf, 0x81ff, 0x0040, 0x4b17, 0x0078, 0x4ae5, 0x81ff,
+	0x0040, 0x4be9, 0x2071, 0xa534, 0x7184, 0x7088, 0xa10a, 0x00c8,
+	0x4ae5, 0x7190, 0x2071, 0xa5be, 0x7040, 0xa005, 0x0040, 0x4ae5,
+	0x00d0, 0x4be9, 0x7142, 0x0078, 0x4be9, 0x2071, 0xa534, 0x718c,
+	0x127e, 0x2091, 0x8000, 0x7084, 0xa10a, 0x0048, 0x4c06, 0x0068,
+	0x4b9b, 0x2071, 0x0000, 0x7018, 0xd084, 0x00c0, 0x4b9b, 0x2001,
+	0xffff, 0x2071, 0xa5be, 0x7042, 0x2071, 0xa534, 0x7000, 0xa086,
+	0x0002, 0x00c0, 0x4b0d, 0x1078, 0x4cd2, 0x2071, 0x0000, 0x701b,
+	0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x1078, 0x4cfd, 0x2071,
+	0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0078, 0x4b9b, 0x2071,
+	0xa534, 0x7000, 0xa005, 0x0040, 0x4bc8, 0x6934, 0xa186, 0x0103,
+	0x00c0, 0x4b9e, 0x684c, 0xd0bc, 0x00c0, 0x4bc8, 0x6948, 0x6844,
+	0xa105, 0x00c0, 0x4bbb, 0x2009, 0x8020, 0x2071, 0xa534, 0x7000,
+	0x0079, 0x4b32, 0x4bc8, 0x4b80, 0x4b58, 0x4b6a, 0x4b37, 0x137e,
+	0x147e, 0x157e, 0x2099, 0xa375, 0x20a1, 0xa585, 0x20a9, 0x0004,
+	0x53a3, 0x157f, 0x147f, 0x137f, 0x2071, 0xa57c, 0xad80, 0x000f,
+	0x700e, 0x7013, 0x0002, 0x7007, 0x0002, 0x700b, 0x0000, 0x2e10,
+	0x1078, 0x13d1, 0x2071, 0xa413, 0x7007, 0x0009, 0x0078, 0x4be9,
+	0x7084, 0x8008, 0xa092, 0x001e, 0x00c8, 0x4be9, 0xae90, 0x0003,
+	0xa210, 0x683c, 0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b,
+	0x0078, 0x4be9, 0x7084, 0x8008, 0xa092, 0x000f, 0x00c8, 0x4be9,
+	0xae90, 0x0003, 0x8003, 0xa210, 0x683c, 0x2012, 0x8210, 0x6840,
+	0x2012, 0x7186, 0x2071, 0xa413, 0x1078, 0x4d5b, 0x0078, 0x4be9,
+	0x127e, 0x2091, 0x8000, 0x0068, 0x4b9b, 0x2071, 0x0000, 0x7018,
+	0xd084, 0x00c0, 0x4b9b, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a,
+	0x701b, 0x0001, 0x2091, 0x4080, 0x127f, 0x2071, 0xa413, 0x1078,
+	0x4d5b, 0x0078, 0x4be9, 0x127f, 0x0078, 0x4be9, 0xa18c, 0x00ff,
+	0xa186, 0x0017, 0x0040, 0x4bac, 0xa186, 0x001e, 0x0040, 0x4bac,
+	0xa18e, 0x001f, 0x00c0, 0x4bc8, 0x684c, 0xd0cc, 0x0040, 0x4bc8,
+	0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x00c0, 0x4bc8, 0x2009,
+	0x8021, 0x0078, 0x4b2d, 0x6844, 0xa086, 0x0100, 0x00c0, 0x4bc8,
+	0x6868, 0xa005, 0x00c0, 0x4bc8, 0x2009, 0x8020, 0x0078, 0x4b2d,
+	0x2071, 0xa413, 0x1078, 0x4d6f, 0x0040, 0x4be9, 0x2071, 0xa413,
+	0x700f, 0x0001, 0x6934, 0xa184, 0x00ff, 0xa086, 0x0003, 0x00c0,
+	0x4be0, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0040, 0x4be0, 0x710e,
+	0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100, 0x0040,
+	0x4ca4, 0x127e, 0x2091, 0x8000, 0x2071, 0xa413, 0x7008, 0xa086,
+	0x0001, 0x00c0, 0x4c04, 0x0068, 0x4c04, 0x2009, 0x000d, 0x7030,
+	0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, 0x0006,
+	0x00c0, 0x4c04, 0x7007, 0x0001, 0x127f, 0x007c, 0x2071, 0xa413,
+	0x1078, 0x4d6f, 0x0040, 0x4c2f, 0x2071, 0xa534, 0x7084, 0x700a,
+	0x20a9, 0x0020, 0x2099, 0xa535, 0x20a1, 0xa55c, 0x53a3, 0x7087,
+	0x0000, 0x2071, 0xa413, 0x2069, 0xa57c, 0x706c, 0x6826, 0x7070,
+	0x682a, 0x7074, 0x682e, 0x7078, 0x6832, 0x2d10, 0x1078, 0x13d1,
+	0x7007, 0x0008, 0x2001, 0xffff, 0x2071, 0xa5be, 0x7042, 0x127f,
+	0x0078, 0x4be9, 0x2069, 0xa57c, 0x6808, 0xa08e, 0x0000, 0x0040,
+	0x4c90, 0xa08e, 0x0200, 0x0040, 0x4c8e, 0xa08e, 0x0100, 0x00c0,
+	0x4c90, 0x127e, 0x2091, 0x8000, 0x0068, 0x4c8b, 0x2069, 0x0000,
+	0x6818, 0xd084, 0x00c0, 0x4c8b, 0x702c, 0x7130, 0x8108, 0xa102,
+	0x0048, 0x4c59, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0078,
+	0x4c63, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4c63, 0x7070,
+	0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b, 0x0000, 0x2001,
+	0xa559, 0x2004, 0xa005, 0x00c0, 0x4c82, 0x6934, 0x2069, 0xa534,
+	0x689c, 0x699e, 0x2069, 0xa5be, 0xa102, 0x00c0, 0x4c7b, 0x6844,
+	0xa005, 0x00d0, 0x4c89, 0x2001, 0xa55a, 0x200c, 0x810d, 0x6946,
+	0x0078, 0x4c89, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091,
+	0x4080, 0x7007, 0x0001, 0x127f, 0x0078, 0x4c90, 0x7007, 0x0005,
+	0x007c, 0x701c, 0xa06d, 0x0040, 0x4ca2, 0x1078, 0x4d6f, 0x0040,
+	0x4ca2, 0x7007, 0x0003, 0x1078, 0x4d8f, 0x7050, 0xa086, 0x0100,
+	0x0040, 0x4ca4, 0x007c, 0x007c, 0x7050, 0xa09e, 0x0100, 0x00c0,
+	0x4cad, 0x7007, 0x0004, 0x0078, 0x4ccb, 0xa086, 0x0200, 0x00c0,
+	0x4cb3, 0x7007, 0x0005, 0x007c, 0x2001, 0xa57e, 0x2004, 0xa08e,
+	0x0100, 0x00c0, 0x4cc0, 0x7007, 0x0001, 0x1078, 0x4d5b, 0x007c,
+	0xa08e, 0x0000, 0x0040, 0x4cbf, 0xa08e, 0x0200, 0x00c0, 0x4cbf,
+	0x7007, 0x0005, 0x007c, 0x1078, 0x4d25, 0x7006, 0x1078, 0x4d5b,
+	0x007c, 0x007c, 0x0e7e, 0x157e, 0x2071, 0xa534, 0x7184, 0x81ff,
+	0x0040, 0x4cfa, 0xa006, 0x7086, 0xae80, 0x0003, 0x2071, 0x0000,
+	0x21a8, 0x2014, 0x7226, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x722a,
+	0x8000, 0x0070, 0x4cf7, 0x2014, 0x722e, 0x8000, 0x0070, 0x4cf7,
+	0x2014, 0x723a, 0x8000, 0x0070, 0x4cf7, 0x2014, 0x723e, 0xa180,
+	0x8030, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x0e7e, 0x157e, 0x2071,
+	0xa534, 0x7184, 0x81ff, 0x0040, 0x4d22, 0xa006, 0x7086, 0xae80,
+	0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x2014,
+	0x722a, 0x8000, 0x0070, 0x4d1b, 0x2014, 0x723a, 0x8000, 0x2014,
+	0x723e, 0x0078, 0x4d1f, 0x2001, 0x8020, 0x0078, 0x4d21, 0x2001,
+	0x8042, 0x7022, 0x157f, 0x0e7f, 0x007c, 0x702c, 0x7130, 0x8108,
+	0xa102, 0x0048, 0x4d32, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072,
+	0x0078, 0x4d3c, 0x706c, 0xa080, 0x0040, 0x706e, 0x00c8, 0x4d3c,
+	0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x700c, 0x8001, 0x700e,
+	0x00c0, 0x4d52, 0x127e, 0x2091, 0x8000, 0x0068, 0x4d55, 0x2001,
+	0x000d, 0x2102, 0x2091, 0x4080, 0x2001, 0x0001, 0x700b, 0x0000,
+	0x127f, 0x007c, 0x2001, 0x0007, 0x007c, 0x2001, 0x0006, 0x700b,
+	0x0001, 0x127f, 0x007c, 0x701c, 0xa06d, 0x0040, 0x4d6e, 0x127e,
+	0x2091, 0x8000, 0x7010, 0x8001, 0x7012, 0x2d04, 0x701e, 0xa005,
+	0x00c0, 0x4d6b, 0x701a, 0x127f, 0x1078, 0x139a, 0x007c, 0x2019,
+	0x000d, 0x2304, 0x230c, 0xa10e, 0x0040, 0x4d7e, 0x2304, 0x230c,
+	0xa10e, 0x0040, 0x4d7e, 0xa006, 0x0078, 0x4d8e, 0x732c, 0x8319,
+	0x7130, 0xa102, 0x00c0, 0x4d88, 0x2300, 0xa005, 0x0078, 0x4d8e,
+	0x0048, 0x4d8d, 0xa302, 0x0078, 0x4d8e, 0x8002, 0x007c, 0x2d00,
+	0x7026, 0xa080, 0x000d, 0x7056, 0x7053, 0x0000, 0x127e, 0x2091,
+	0x8000, 0x2009, 0xa5d0, 0x2104, 0xc08d, 0x200a, 0x127f, 0x1078,
+	0x13eb, 0x007c, 0x2071, 0xa3e1, 0x7003, 0x0000, 0x7007, 0x0000,
+	0x700f, 0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001,
+	0x705f, 0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000,
+	0x708f, 0x0001, 0x70bf, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa3e1,
+	0x6848, 0xa005, 0x00c0, 0x4dcb, 0x7028, 0xc085, 0x702a, 0xa085,
+	0x0001, 0x0078, 0x4df0, 0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858,
+	0x703e, 0x707a, 0x685c, 0x7042, 0x707e, 0x6848, 0x702e, 0x6840,
+	0x7032, 0x2009, 0x000c, 0x200a, 0x8007, 0x8006, 0x8006, 0xa08c,
+	0x003f, 0xa084, 0xffc0, 0xa210, 0x2100, 0xa319, 0x7272, 0x7376,
+	0x7028, 0xc084, 0x702a, 0x7007, 0x0001, 0x700f, 0x0000, 0xa006,
+	0x0e7f, 0x007c, 0x2b78, 0x2071, 0xa3e1, 0x7004, 0x1079, 0x4e50,
+	0x700c, 0x0079, 0x4dfb, 0x4e00, 0x4df5, 0x4df5, 0x4df5, 0x4df5,
+	0x007c, 0x700c, 0x0079, 0x4e04, 0x4e09, 0x4e4e, 0x4e4e, 0x4e4f,
+	0x4e4f, 0x7830, 0x7930, 0xa106, 0x0040, 0x4e13, 0x7830, 0x7930,
+	0xa106, 0x00c0, 0x4e39, 0x7030, 0xa10a, 0x0040, 0x4e39, 0x00c8,
+	0x4e1b, 0x712c, 0xa10a, 0xa18a, 0x0002, 0x00c8, 0x4e3a, 0x1078,
+	0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a, 0x7063, 0x0040, 0x2001,
+	0x0003, 0x7057, 0x0000, 0x127e, 0x007e, 0x2091, 0x8000, 0x2009,
+	0xa5d0, 0x2104, 0xc085, 0x200a, 0x007f, 0x700e, 0x127f, 0x1078,
+	0x13eb, 0x007c, 0x1078, 0x1366, 0x0040, 0x4e39, 0x2d00, 0x705a,
+	0x1078, 0x1366, 0x00c0, 0x4e46, 0x0078, 0x4e25, 0x2d00, 0x7086,
+	0x7063, 0x0080, 0x2001, 0x0004, 0x0078, 0x4e29, 0x007c, 0x007c,
+	0x4e61, 0x4e62, 0x4e99, 0x4e9a, 0x4e4e, 0x4ed0, 0x4ed5, 0x4f0c,
+	0x4f0d, 0x4f28, 0x4f29, 0x4f2a, 0x4f2b, 0x4f2c, 0x4f2d, 0x4fad,
+	0x4fd7, 0x007c, 0x700c, 0x0079, 0x4e65, 0x4e6a, 0x4e6d, 0x4e7d,
+	0x4e98, 0x4e98, 0x1078, 0x4e01, 0x007c, 0x127e, 0x8001, 0x700e,
+	0x7058, 0x007e, 0x1078, 0x5348, 0x0040, 0x4e7a, 0x2091, 0x8000,
+	0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4e86, 0x127e, 0x8001, 0x700e,
+	0x1078, 0x5348, 0x7058, 0x2068, 0x7084, 0x705a, 0x6803, 0x0000,
+	0x6807, 0x0000, 0x6834, 0xa084, 0x00ff, 0xa08a, 0x0020, 0x00c8,
+	0x4e95, 0x1079, 0x4eb0, 0x127f, 0x007c, 0x127f, 0x1078, 0x4f2e,
+	0x007c, 0x007c, 0x007c, 0x0e7e, 0x2071, 0xa3e1, 0x700c, 0x0079,
+	0x4ea1, 0x4ea6, 0x4ea6, 0x4ea6, 0x4ea8, 0x4eac, 0x0e7f, 0x007c,
+	0x700f, 0x0001, 0x0078, 0x4eae, 0x700f, 0x0002, 0x0e7f, 0x007c,
+	0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x5080, 0x4f2e, 0x4f2e, 0x4f2e,
+	0x4f2e, 0x4f2e, 0x4f4a, 0x50ca, 0x5117, 0x5170, 0x5186, 0x4f2e,
+	0x4f2e, 0x4f66, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f87, 0x5245, 0x5263,
+	0x4f2e, 0x4f66, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f7c, 0x5263,
+	0x7020, 0x2068, 0x1078, 0x139a, 0x007c, 0x700c, 0x0079, 0x4ed8,
+	0x4edd, 0x4ee0, 0x4ef0, 0x4f0b, 0x4f0b, 0x1078, 0x4e01, 0x007c,
+	0x127e, 0x8001, 0x700e, 0x7058, 0x007e, 0x1078, 0x5348, 0x0040,
+	0x4eed, 0x2091, 0x8000, 0x1078, 0x4e01, 0x0d7f, 0x0078, 0x4ef9,
+	0x127e, 0x8001, 0x700e, 0x1078, 0x5348, 0x7058, 0x2068, 0x7084,
+	0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff,
+	0xa08a, 0x001a, 0x00c8, 0x4f08, 0x1079, 0x4f0e, 0x127f, 0x007c,
+	0x127f, 0x1078, 0x4f2e, 0x007c, 0x007c, 0x007c, 0x4f2e, 0x4f4a,
+	0x506a, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a,
+	0x506a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f4a, 0x4f2e, 0x4f4a,
+	0x506a, 0x4f2e, 0x4f2e, 0x4f4a, 0x4f2e, 0x4f2e, 0x4f2e, 0x4f4a,
+	0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x007c, 0x7007, 0x0001,
+	0x6838, 0xa084, 0x00ff, 0xc0d5, 0x683a, 0x127e, 0x2091, 0x8000,
+	0x1078, 0x4982, 0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084,
+	0x00ff, 0xc0e5, 0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982,
+	0x127f, 0x007c, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed,
+	0x683a, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c,
+	0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0dd, 0x683a, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x4982, 0x127f, 0x007c, 0x6834, 0x8007,
+	0xa084, 0x00ff, 0x0040, 0x4f3c, 0x8001, 0x00c0, 0x4f73, 0x7007,
+	0x0001, 0x0078, 0x5049, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016,
+	0x701a, 0x704b, 0x5049, 0x007c, 0x684c, 0xa084, 0x00c0, 0xa086,
+	0x00c0, 0x00c0, 0x4f87, 0x7007, 0x0001, 0x0078, 0x5280, 0x2d00,
+	0x7016, 0x701a, 0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1,
+	0xa40c, 0x53a3, 0x6858, 0x7012, 0xa082, 0x0401, 0x00c8, 0x4f58,
+	0x6884, 0xa08a, 0x0002, 0x00c8, 0x4f58, 0x82ff, 0x00c0, 0x4fa9,
+	0x6888, 0x698c, 0xa105, 0x0040, 0x4fa9, 0x2001, 0x5019, 0x0078,
+	0x4fac, 0xa280, 0x500f, 0x2004, 0x70c6, 0x7010, 0xa015, 0x0040,
+	0x4ff7, 0x1078, 0x1366, 0x00c0, 0x4fb8, 0x7007, 0x000f, 0x007c,
+	0x2d00, 0x7022, 0x70c4, 0x2060, 0x6000, 0x6836, 0x6004, 0xad00,
+	0x7096, 0x6008, 0xa20a, 0x00c8, 0x4fc7, 0xa00e, 0x2200, 0x7112,
+	0x620c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0040, 0x4fd0, 0xa108,
+	0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x1078, 0x13d1, 0x7090,
+	0xa08e, 0x0100, 0x0040, 0x4feb, 0xa086, 0x0200, 0x0040, 0x4fe3,
+	0x7007, 0x0010, 0x007c, 0x7020, 0x2068, 0x1078, 0x139a, 0x7014,
+	0x2068, 0x0078, 0x4f58, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807,
+	0x0000, 0x2d08, 0x2068, 0x6906, 0x711a, 0x0078, 0x4fad, 0x7014,
+	0x2068, 0x7007, 0x0001, 0x6884, 0xa005, 0x00c0, 0x5006, 0x6888,
+	0x698c, 0xa105, 0x0040, 0x5006, 0x1078, 0x501d, 0x6834, 0xa084,
+	0x00ff, 0xa086, 0x001e, 0x0040, 0x5280, 0x0078, 0x5049, 0x5011,
+	0x5015, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a, 0x000f, 0x0005,
+	0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x0f7e, 0x0e7e, 0x0c7e,
+	0x077e, 0x067e, 0x6f88, 0x6e8c, 0x6804, 0x2060, 0xacf0, 0x0021,
+	0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816, 0x7008, 0x7812,
+	0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a, 0x8109, 0x0040,
+	0x503f, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0078, 0x502c, 0x6004,
+	0xa065, 0x00c0, 0x5026, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x0f7f,
+	0x007c, 0x2009, 0xa32e, 0x210c, 0x81ff, 0x00c0, 0x5064, 0x6838,
+	0xa084, 0x00ff, 0x683a, 0x1078, 0x4290, 0x00c0, 0x5058, 0x007c,
+	0x1078, 0x4a60, 0x127e, 0x2091, 0x8000, 0x1078, 0x8cb8, 0x1078,
+	0x4982, 0x127f, 0x0078, 0x5057, 0x2001, 0x0028, 0x2009, 0x0000,
+	0x0078, 0x5058, 0x7018, 0x6802, 0x2d08, 0x2068, 0x6906, 0x711a,
+	0x7010, 0x8001, 0x7012, 0x0040, 0x5079, 0x7007, 0x0006, 0x0078,
+	0x507f, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048, 0x107a, 0x007c,
+	0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x6848, 0xa084,
+	0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x0040, 0x50a9, 0x2009,
+	0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0040, 0x50a9, 0xa005,
+	0x00c0, 0x50bc, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x1078, 0x4501,
+	0x00c0, 0x50bc, 0x067e, 0x6e50, 0x1078, 0x45e7, 0x067f, 0x0078,
+	0x50bc, 0x047e, 0x2011, 0xa30c, 0x2224, 0xc484, 0xc48c, 0x2412,
+	0x047f, 0x0c7e, 0x1078, 0x4501, 0x00c0, 0x50b8, 0x1078, 0x4782,
+	0x8108, 0x00f0, 0x50b2, 0x0c7f, 0x684c, 0xd084, 0x00c0, 0x50c3,
+	0x1078, 0x139a, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078, 0x4982,
+	0x127f, 0x007c, 0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2001,
+	0xa352, 0x2004, 0xd0a4, 0x0040, 0x510e, 0x2061, 0xa62d, 0x6100,
+	0xd184, 0x0040, 0x50ee, 0x6858, 0xa084, 0x00ff, 0x00c0, 0x5111,
+	0x6000, 0xd084, 0x0040, 0x510e, 0x6004, 0xa005, 0x00c0, 0x5114,
+	0x6003, 0x0000, 0x600b, 0x0000, 0x0078, 0x510b, 0x2011, 0x0001,
+	0x6860, 0xa005, 0x00c0, 0x50f6, 0x2001, 0x001e, 0x8000, 0x6016,
+	0x6858, 0xa084, 0x00ff, 0x0040, 0x510e, 0x6006, 0x6858, 0x8007,
+	0xa084, 0x00ff, 0x0040, 0x510e, 0x600a, 0x6858, 0x8000, 0x00c0,
+	0x510a, 0xc28d, 0x6202, 0x127f, 0x0078, 0x5337, 0x127f, 0x0078,
+	0x532f, 0x127f, 0x0078, 0x5327, 0x127f, 0x0078, 0x532b, 0x127e,
+	0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xa352, 0x2004, 0xd0a4,
+	0x0040, 0x516d, 0x2061, 0xa62d, 0x6000, 0xd084, 0x0040, 0x516d,
+	0x6204, 0x6308, 0xd08c, 0x00c0, 0x515f, 0x6c48, 0xa484, 0x0003,
+	0x0040, 0x5145, 0x6958, 0xa18c, 0x00ff, 0x8001, 0x00c0, 0x513e,
+	0x2100, 0xa210, 0x0048, 0x516a, 0x0078, 0x5145, 0x8001, 0x00c0,
+	0x516a, 0x2100, 0xa212, 0x0048, 0x516a, 0xa484, 0x000c, 0x0040,
+	0x515f, 0x6958, 0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x00c0,
+	0x5157, 0x2100, 0xa318, 0x0048, 0x516a, 0x0078, 0x515f, 0xa082,
+	0x0004, 0x00c0, 0x516a, 0x2100, 0xa31a, 0x0048, 0x516a, 0x6860,
+	0xa005, 0x0040, 0x5165, 0x8000, 0x6016, 0x6206, 0x630a, 0x127f,
+	0x0078, 0x5337, 0x127f, 0x0078, 0x5333, 0x127f, 0x0078, 0x532f,
+	0x127e, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xa62d, 0x6300,
+	0xd38c, 0x00c0, 0x5180, 0x6308, 0x8318, 0x0048, 0x5183, 0x630a,
+	0x127f, 0x0078, 0x5345, 0x127f, 0x0078, 0x5333, 0x127e, 0x0c7e,
+	0x2091, 0x8000, 0x7007, 0x0001, 0x684c, 0xd0ac, 0x0040, 0x519a,
+	0x0c7e, 0x2061, 0xa62d, 0x6000, 0xa084, 0xfcff, 0x6002, 0x0c7f,
+	0x0078, 0x51c9, 0x6858, 0xa005, 0x0040, 0x51e0, 0x685c, 0xa065,
+	0x0040, 0x51dc, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x51ac,
+	0x1078, 0x8c01, 0x0078, 0x51ba, 0x6013, 0x0400, 0x6037, 0x0000,
+	0x694c, 0xd1a4, 0x0040, 0x51b6, 0x6950, 0x6136, 0x2009, 0x0041,
+	0x1078, 0x756c, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, 0x00c0,
+	0x51c9, 0x027e, 0x2009, 0x0000, 0x2011, 0xfdff, 0x1078, 0x5a6d,
+	0x027f, 0x684c, 0xd0c4, 0x0040, 0x51d8, 0x2061, 0xa62d, 0x6000,
+	0xd08c, 0x00c0, 0x51d8, 0x6008, 0x8000, 0x0048, 0x51dc, 0x600a,
+	0x0c7f, 0x127f, 0x0078, 0x5337, 0x0c7f, 0x127f, 0x0078, 0x532f,
+	0x6954, 0xa186, 0x0045, 0x0040, 0x5213, 0xa186, 0x002a, 0x00c0,
+	0x51f0, 0x2001, 0xa30c, 0x200c, 0xc194, 0x2102, 0x0078, 0x51c9,
+	0xa186, 0x0020, 0x0040, 0x5209, 0xa186, 0x0029, 0x0040, 0x51fc,
+	0xa186, 0x002d, 0x00c0, 0x51dc, 0x6944, 0xa18c, 0xff00, 0x810f,
+	0x1078, 0x4501, 0x00c0, 0x51c9, 0x6000, 0xc0e4, 0x6002, 0x0078,
+	0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x2001, 0xa5a1, 0x2004,
+	0x6016, 0x0078, 0x51c9, 0x685c, 0xa065, 0x0040, 0x51dc, 0x0e7e,
+	0x6860, 0xa075, 0x2001, 0xa32e, 0x2004, 0xa005, 0x0040, 0x522b,
+	0x1078, 0x8c01, 0x8eff, 0x0040, 0x5228, 0x2e60, 0x1078, 0x8c01,
+	0x0e7f, 0x0078, 0x51c9, 0x6024, 0xc0dc, 0xc0d5, 0x6026, 0x2e60,
+	0x6007, 0x003a, 0x6870, 0xa005, 0x0040, 0x523c, 0x6007, 0x003b,
+	0x6874, 0x602a, 0x6878, 0x6012, 0x6003, 0x0001, 0x1078, 0x5bf8,
+	0x1078, 0x6109, 0x0e7f, 0x0078, 0x51c9, 0x2061, 0xa62d, 0x6000,
+	0xd084, 0x0040, 0x525f, 0xd08c, 0x00c0, 0x5345, 0x2091, 0x8000,
+	0x6204, 0x8210, 0x0048, 0x5259, 0x6206, 0x2091, 0x8001, 0x0078,
+	0x5345, 0x2091, 0x8001, 0x6853, 0x0016, 0x0078, 0x533e, 0x6853,
+	0x0007, 0x0078, 0x533e, 0x6834, 0x8007, 0xa084, 0x00ff, 0x00c0,
+	0x526d, 0x1078, 0x4f3c, 0x0078, 0x527f, 0x2030, 0x8001, 0x00c0,
+	0x5277, 0x7007, 0x0001, 0x1078, 0x5280, 0x0078, 0x527f, 0x7007,
+	0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5280, 0x007c,
+	0x0e7e, 0x127e, 0x2091, 0x8000, 0x2009, 0xa32e, 0x210c, 0x81ff,
+	0x00c0, 0x530b, 0x2009, 0xa30c, 0x210c, 0xd194, 0x00c0, 0x5315,
+	0x6848, 0x2070, 0xae82, 0xaa00, 0x0048, 0x52fb, 0x2001, 0xa315,
+	0x2004, 0xae02, 0x00c8, 0x52fb, 0x2061, 0xa62d, 0x6100, 0xa184,
+	0x0301, 0xa086, 0x0001, 0x00c0, 0x52de, 0x711c, 0xa186, 0x0006,
+	0x00c0, 0x52e6, 0x7018, 0xa005, 0x0040, 0x530b, 0x2004, 0xd0e4,
+	0x00c0, 0x530f, 0x7024, 0xd0dc, 0x00c0, 0x5319, 0x6853, 0x0000,
+	0x6803, 0x0000, 0x2d08, 0x7010, 0xa005, 0x00c0, 0x52ca, 0x7112,
+	0x684c, 0xd0f4, 0x00c0, 0x531d, 0x2e60, 0x1078, 0x59b6, 0x127f,
+	0x0e7f, 0x007c, 0x2068, 0x6800, 0xa005, 0x00c0, 0x52ca, 0x6902,
+	0x2168, 0x684c, 0xd0f4, 0x00c0, 0x531d, 0x127f, 0x0e7f, 0x007c,
+	0x127f, 0x0e7f, 0x6853, 0x0006, 0x0078, 0x533e, 0xd184, 0x0040,
+	0x52d8, 0xd1c4, 0x00c0, 0x52ff, 0x0078, 0x5303, 0x6944, 0xa18c,
+	0xff00, 0x810f, 0x1078, 0x4501, 0x00c0, 0x530f, 0x6000, 0xd0e4,
+	0x00c0, 0x530f, 0x711c, 0xa186, 0x0007, 0x00c0, 0x52fb, 0x6853,
+	0x0002, 0x0078, 0x5311, 0x6853, 0x0008, 0x0078, 0x5311, 0x6853,
+	0x000e, 0x0078, 0x5311, 0x6853, 0x0017, 0x0078, 0x5311, 0x6853,
+	0x0035, 0x0078, 0x5311, 0x6853, 0x0028, 0x0078, 0x5311, 0x6853,
+	0x0029, 0x127f, 0x0e7f, 0x0078, 0x533e, 0x6853, 0x002a, 0x0078,
+	0x5311, 0x6853, 0x0045, 0x0078, 0x5311, 0x2e60, 0x2019, 0x0002,
+	0x6017, 0x0014, 0x1078, 0x9a6a, 0x127f, 0x0e7f, 0x007c, 0x2009,
+	0x003e, 0x0078, 0x5339, 0x2009, 0x0004, 0x0078, 0x5339, 0x2009,
+	0x0006, 0x0078, 0x5339, 0x2009, 0x0016, 0x0078, 0x5339, 0x2009,
+	0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x2091, 0x8000,
+	0x1078, 0x4982, 0x2091, 0x8001, 0x007c, 0x1078, 0x139a, 0x007c,
+	0x702c, 0x7130, 0x8108, 0xa102, 0x0048, 0x5355, 0xa00e, 0x7034,
+	0x7072, 0x7038, 0x7076, 0x0078, 0x5361, 0x7070, 0xa080, 0x0040,
+	0x7072, 0x00c8, 0x5361, 0x7074, 0xa081, 0x0000, 0x7076, 0xa085,
+	0x0001, 0x7932, 0x7132, 0x007c, 0x0d7e, 0x1078, 0x59ad, 0x0d7f,
+	0x007c, 0x0d7e, 0x2011, 0x0004, 0x2204, 0xa085, 0x8002, 0x2012,
+	0x0d7f, 0x007c, 0x20e1, 0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00,
+	0xa084, 0x7000, 0x0040, 0x5380, 0xa086, 0x1000, 0x00c0, 0x53ac,
+	0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00, 0x8217, 0xa084, 0xf000,
+	0xa086, 0x3000, 0x00c0, 0x5390, 0x1078, 0x5570, 0x0078, 0x53a7,
+	0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x00c0, 0x5397, 0x3e60, 0xac84,
+	0x000f, 0x00c0, 0x53ac, 0xac82, 0xaa00, 0x0048, 0x53ac, 0x6854,
+	0xac02, 0x00c8, 0x53ac, 0x2009, 0x0047, 0x1078, 0x756c, 0x7a1c,
+	0xd284, 0x00c0, 0x5372, 0x007c, 0xa016, 0x1078, 0x15ec, 0x0078,
+	0x53a7, 0x0078, 0x53ac, 0x781c, 0xd08c, 0x0040, 0x53db, 0x157e,
+	0x137e, 0x147e, 0x20e1, 0x3000, 0x3d20, 0x3e28, 0xa584, 0x0076,
+	0x00c0, 0x53f1, 0xa484, 0x7000, 0xa086, 0x1000, 0x00c0, 0x53e0,
+	0x1078, 0x540c, 0x0040, 0x53f1, 0x20e1, 0x3000, 0x7828, 0x7828,
+	0x1078, 0x542a, 0x147f, 0x137f, 0x157f, 0x2009, 0xa5b3, 0x2104,
+	0xa005, 0x00c0, 0x53dc, 0x007c, 0x1078, 0x6109, 0x0078, 0x53db,
+	0xa484, 0x7000, 0x00c0, 0x53f1, 0x1078, 0x540c, 0x0040, 0x5403,
+	0x7000, 0xa084, 0xff00, 0xa086, 0x8100, 0x0040, 0x53cc, 0x0078,
+	0x5403, 0x1078, 0xa1ee, 0xd5a4, 0x0040, 0x53ff, 0x1078, 0x1af7,
+	0x20e1, 0x9010, 0x2001, 0x0138, 0x2202, 0x0078, 0x5407, 0x1078,
+	0x540c, 0x687f, 0x0000, 0x20e1, 0x3000, 0x7828, 0x7828, 0x147f,
+	0x137f, 0x157f, 0x0078, 0x53db, 0xa484, 0x01ff, 0x687e, 0xa005,
+	0x0040, 0x541e, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac, 0x20e1,
+	0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x007c, 0x20a9, 0x000c,
+	0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085, 0x0001,
+	0x0078, 0x541d, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007,
+	0xa196, 0x0000, 0x00c0, 0x5437, 0x0078, 0x567c, 0x007c, 0xa196,
+	0x2000, 0x00c0, 0x5448, 0x6900, 0xa18e, 0x0001, 0x00c0, 0x5444,
+	0x1078, 0x3a43, 0x0078, 0x5436, 0x1078, 0x5450, 0x0078, 0x5436,
+	0xa196, 0x8000, 0x00c0, 0x5436, 0x1078, 0x570c, 0x0078, 0x5436,
+	0x0c7e, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa196, 0x0001, 0x0040,
+	0x545d, 0xa196, 0x0023, 0x00c0, 0x5568, 0xa08e, 0x0023, 0x00c0,
+	0x5492, 0x1078, 0x57b2, 0x0040, 0x5568, 0x7124, 0x610a, 0x7030,
+	0xa08e, 0x0200, 0x00c0, 0x5476, 0x7034, 0xa005, 0x00c0, 0x5568,
+	0x2009, 0x0015, 0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0214,
+	0x0040, 0x547e, 0xa08e, 0x0210, 0x00c0, 0x5484, 0x2009, 0x0015,
+	0x1078, 0x756c, 0x0078, 0x5568, 0xa08e, 0x0100, 0x00c0, 0x5568,
+	0x7034, 0xa005, 0x00c0, 0x5568, 0x2009, 0x0016, 0x1078, 0x756c,
+	0x0078, 0x5568, 0xa08e, 0x0022, 0x00c0, 0x5568, 0x7030, 0xa08e,
+	0x0300, 0x00c0, 0x54a3, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009,
+	0x0017, 0x0078, 0x5534, 0xa08e, 0x0500, 0x00c0, 0x54af, 0x7034,
+	0xa005, 0x00c0, 0x5568, 0x2009, 0x0018, 0x0078, 0x5534, 0xa08e,
+	0x2010, 0x00c0, 0x54b7, 0x2009, 0x0019, 0x0078, 0x5534, 0xa08e,
+	0x2110, 0x00c0, 0x54bf, 0x2009, 0x001a, 0x0078, 0x5534, 0xa08e,
+	0x5200, 0x00c0, 0x54cb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009,
+	0x001b, 0x0078, 0x5534, 0xa08e, 0x5000, 0x00c0, 0x54d7, 0x7034,
+	0xa005, 0x00c0, 0x5568, 0x2009, 0x001c, 0x0078, 0x5534, 0xa08e,
+	0x1300, 0x00c0, 0x54df, 0x2009, 0x0034, 0x0078, 0x5534, 0xa08e,
+	0x1200, 0x00c0, 0x54eb, 0x7034, 0xa005, 0x00c0, 0x5568, 0x2009,
+	0x0024, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e, 0x2400, 0x00c0,
+	0x54f5, 0x2009, 0x002d, 0x0078, 0x5534, 0xa08c, 0xff00, 0xa18e,
+	0x5300, 0x00c0, 0x54ff, 0x2009, 0x002a, 0x0078, 0x5534, 0xa08e,
+	0x0f00, 0x00c0, 0x5507, 0x2009, 0x0020, 0x0078, 0x5534, 0xa08e,
+	0x5300, 0x00c0, 0x550d, 0x0078, 0x552a, 0xa08e, 0x6104, 0x00c0,
+	0x552a, 0x2011, 0xa88d, 0x8208, 0x2204, 0xa082, 0x0004, 0x20a8,
+	0x95ac, 0x95ac, 0x2011, 0x8015, 0x211c, 0x8108, 0x047e, 0x2124,
+	0x1078, 0x3579, 0x047f, 0x8108, 0x00f0, 0x551a, 0x2009, 0x0023,
+	0x0078, 0x5534, 0xa08e, 0x6000, 0x00c0, 0x5532, 0x2009, 0x003f,
+	0x0078, 0x5534, 0x2009, 0x001d, 0x017e, 0x2011, 0xa883, 0x2204,
+	0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x556a, 0x1078, 0x4499,
+	0x00c0, 0x556a, 0x6612, 0x6516, 0x86ff, 0x0040, 0x555a, 0x017f,
+	0x017e, 0xa186, 0x0017, 0x00c0, 0x555a, 0x6868, 0xa606, 0x00c0,
+	0x555a, 0x686c, 0xa506, 0xa084, 0xff00, 0x00c0, 0x555a, 0x6000,
+	0xc0f5, 0x6002, 0x0c7e, 0x1078, 0x74d7, 0x0040, 0x556d, 0x017f,
+	0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x017f, 0x1078, 0x756c,
+	0x0c7f, 0x007c, 0x017f, 0x0078, 0x5568, 0x0c7f, 0x0078, 0x556a,
+	0x0c7e, 0x1078, 0x55d4, 0x00c0, 0x55d2, 0xa184, 0xff00, 0x8007,
+	0xa086, 0x0008, 0x00c0, 0x55d2, 0xa28e, 0x0033, 0x00c0, 0x55a3,
+	0x1078, 0x57b2, 0x0040, 0x55d2, 0x7124, 0x610a, 0x7030, 0xa08e,
+	0x0200, 0x00c0, 0x5595, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009,
+	0x0015, 0x1078, 0x756c, 0x0078, 0x55d2, 0xa08e, 0x0100, 0x00c0,
+	0x55d2, 0x7034, 0xa005, 0x00c0, 0x55d2, 0x2009, 0x0016, 0x1078,
+	0x756c, 0x0078, 0x55d2, 0xa28e, 0x0032, 0x00c0, 0x55d2, 0x7030,
+	0xa08e, 0x1400, 0x00c0, 0x55d2, 0x2009, 0x0038, 0x017e, 0x2011,
+	0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x55d1,
+	0x1078, 0x4499, 0x00c0, 0x55d1, 0x6612, 0x6516, 0x0c7e, 0x1078,
+	0x74d7, 0x0040, 0x55d0, 0x017f, 0x611a, 0x601f, 0x0004, 0x7120,
+	0x610a, 0x017f, 0x1078, 0x756c, 0x1078, 0x6109, 0x0078, 0x55d2,
+	0x0c7f, 0x017f, 0x0c7f, 0x007c, 0x0f7e, 0x0d7e, 0x027e, 0x017e,
+	0x137e, 0x147e, 0x157e, 0x3c00, 0x007e, 0x2079, 0x0030, 0x2069,
+	0x0200, 0x1078, 0x1c25, 0x00c0, 0x5615, 0x1078, 0x1b15, 0x0040,
+	0x561f, 0x7908, 0xa18c, 0x1fff, 0xa182, 0x0011, 0x00c8, 0x561f,
+	0x20a9, 0x000c, 0x20e1, 0x0000, 0x2ea0, 0x2099, 0x020a, 0x53a5,
+	0x20e1, 0x2000, 0x2001, 0x020a, 0x2004, 0x7a0c, 0x7808, 0xa080,
+	0x0007, 0xa084, 0x1ff8, 0xa08a, 0x0140, 0x10c8, 0x1328, 0x80ac,
+	0x20e1, 0x6000, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828,
+	0x6828, 0x7803, 0x0004, 0xa294, 0x0070, 0x007f, 0x20e0, 0x157f,
+	0x147f, 0x137f, 0x017f, 0x027f, 0x0d7f, 0x0f7f, 0x007c, 0xa085,
+	0x0001, 0x0078, 0x5615, 0x047e, 0x0e7e, 0x0d7e, 0x2028, 0x2130,
+	0xa696, 0x00ff, 0x00c0, 0x5644, 0xa596, 0xfffd, 0x00c0, 0x5634,
+	0x2009, 0x007f, 0x0078, 0x5677, 0xa596, 0xfffe, 0x00c0, 0x563c,
+	0x2009, 0x007e, 0x0078, 0x5677, 0xa596, 0xfffc, 0x00c0, 0x5644,
+	0x2009, 0x0080, 0x0078, 0x5677, 0x2011, 0x0000, 0x2021, 0x0081,
+	0x20a9, 0x007e, 0x2071, 0xa4b5, 0x2e1c, 0x83ff, 0x00c0, 0x5656,
+	0x82ff, 0x00c0, 0x566b, 0x2410, 0x0078, 0x566b, 0x2368, 0x6f10,
+	0x007e, 0x2100, 0xa706, 0x007f, 0x6b14, 0x00c0, 0x5665, 0xa346,
+	0x00c0, 0x5665, 0x2408, 0x0078, 0x5677, 0x87ff, 0x00c0, 0x566b,
+	0x83ff, 0x0040, 0x5650, 0x8420, 0x8e70, 0x00f0, 0x564c, 0x82ff,
+	0x00c0, 0x5676, 0xa085, 0x0001, 0x0078, 0x5678, 0x2208, 0xa006,
+	0x0d7f, 0x0e7f, 0x047f, 0x007c, 0xa084, 0x0007, 0x0079, 0x5681,
+	0x007c, 0x5689, 0x5689, 0x5689, 0x57c8, 0x5689, 0x568a, 0x56a3,
+	0x56f3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x56a2, 0x7120, 0x2160,
+	0xac8c, 0x000f, 0x00c0, 0x56a2, 0xac8a, 0xaa00, 0x0048, 0x56a2,
+	0x6854, 0xac02, 0x00c8, 0x56a2, 0x7124, 0x610a, 0x2009, 0x0046,
+	0x1078, 0x756c, 0x007c, 0x0c7e, 0x7110, 0xd1bc, 0x00c0, 0x56f1,
+	0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0,
+	0x56f1, 0x1078, 0x4499, 0x00c0, 0x56f1, 0x6612, 0x6516, 0x6000,
+	0xd0ec, 0x00c0, 0x56f1, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286,
+	0x0006, 0x00c0, 0x56d6, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040,
+	0x56f1, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6122,
+	0x2009, 0x0044, 0x1078, 0x756c, 0x0078, 0x56f1, 0x0c7e, 0x1078,
+	0x74d7, 0x017f, 0x0040, 0x56f1, 0x611a, 0x601f, 0x0004, 0x7120,
+	0x610a, 0xa286, 0x0004, 0x00c0, 0x56e9, 0x6007, 0x0005, 0x0078,
+	0x56eb, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078,
+	0x6109, 0x0c7f, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x570b, 0x7020,
+	0x2060, 0xac84, 0x000f, 0x00c0, 0x570b, 0xac82, 0xaa00, 0x0048,
+	0x570b, 0x6854, 0xac02, 0x00c8, 0x570b, 0x7124, 0x610a, 0x2009,
+	0x0045, 0x1078, 0x756c, 0x007c, 0x7110, 0xa18c, 0xff00, 0x810f,
+	0xa18e, 0x0000, 0x00c0, 0x571c, 0xa084, 0x000f, 0xa08a, 0x0006,
+	0x00c8, 0x571c, 0x1079, 0x571d, 0x007c, 0x5723, 0x5724, 0x5723,
+	0x5723, 0x5794, 0x57a3, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x572c,
+	0x702c, 0xd084, 0x0040, 0x5793, 0x700c, 0x7108, 0x1078, 0x24e3,
+	0x00c0, 0x5793, 0x1078, 0x4499, 0x00c0, 0x5793, 0x6612, 0x6516,
+	0x6204, 0x7110, 0xd1bc, 0x0040, 0x575e, 0xa28c, 0x00ff, 0xa186,
+	0x0004, 0x0040, 0x5747, 0xa186, 0x0006, 0x00c0, 0x5784, 0x0c7e,
+	0x1078, 0x57b2, 0x0c7f, 0x0040, 0x5793, 0x0c7e, 0x1078, 0x74d7,
+	0x017f, 0x0040, 0x5793, 0x611a, 0x601f, 0x0002, 0x7120, 0x610a,
+	0x2009, 0x0088, 0x1078, 0x756c, 0x0078, 0x5793, 0xa28c, 0x00ff,
+	0xa186, 0x0006, 0x0040, 0x5773, 0xa186, 0x0004, 0x0040, 0x5773,
+	0xa294, 0xff00, 0x8217, 0xa286, 0x0004, 0x0040, 0x5773, 0xa286,
+	0x0006, 0x00c0, 0x5784, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040,
+	0x5793, 0x611a, 0x601f, 0x0005, 0x7120, 0x610a, 0x2009, 0x0088,
+	0x1078, 0x756c, 0x0078, 0x5793, 0x0c7e, 0x1078, 0x74d7, 0x017f,
+	0x0040, 0x5793, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x2009,
+	0x0001, 0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57a2,
+	0x1078, 0x57b2, 0x0040, 0x57a2, 0x7124, 0x610a, 0x2009, 0x0089,
+	0x1078, 0x756c, 0x007c, 0x7110, 0xd1bc, 0x0040, 0x57b1, 0x1078,
+	0x57b2, 0x0040, 0x57b1, 0x7124, 0x610a, 0x2009, 0x008a, 0x1078,
+	0x756c, 0x007c, 0x7020, 0x2060, 0xac84, 0x000f, 0x00c0, 0x57c5,
+	0xac82, 0xaa00, 0x0048, 0x57c5, 0x2001, 0xa315, 0x2004, 0xac02,
+	0x00c8, 0x57c5, 0xa085, 0x0001, 0x007c, 0xa006, 0x0078, 0x57c4,
+	0x7110, 0xd1bc, 0x00c0, 0x57de, 0x7024, 0x2060, 0xac84, 0x000f,
+	0x00c0, 0x57de, 0xac82, 0xaa00, 0x0048, 0x57de, 0x6854, 0xac02,
+	0x00c8, 0x57de, 0x2009, 0x0051, 0x1078, 0x756c, 0x007c, 0x2071,
+	0xa5be, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012,
+	0x7017, 0xaa00, 0x7007, 0x0000, 0x7026, 0x702b, 0x6c4e, 0x7032,
+	0x7037, 0x6ca0, 0x703b, 0x0002, 0x703f, 0x0000, 0x7043, 0xffff,
+	0x7047, 0xffff, 0x007c, 0x2071, 0xa5be, 0x00e0, 0x58c1, 0x2091,
+	0x6000, 0x700c, 0x8001, 0x700e, 0x00c0, 0x5873, 0x700f, 0x0361,
+	0x7007, 0x0001, 0x127e, 0x2091, 0x8000, 0x7138, 0x8109, 0x713a,
+	0x00c0, 0x5871, 0x703b, 0x0002, 0x2009, 0x0100, 0x2104, 0xa082,
+	0x0003, 0x00c8, 0x5871, 0x703c, 0xa086, 0x0001, 0x00c0, 0x584e,
+	0x0d7e, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000, 0x0040, 0x582c,
+	0x6803, 0x1000, 0x0078, 0x5833, 0x6804, 0xa084, 0x1000, 0x0040,
+	0x5833, 0x6803, 0x0100, 0x6803, 0x0000, 0x703f, 0x0000, 0x2069,
+	0xa5ab, 0x6804, 0xa082, 0x0006, 0x00c0, 0x5840, 0x6807, 0x0000,
+	0x6830, 0xa082, 0x0003, 0x00c0, 0x5847, 0x6833, 0x0000, 0x1078,
+	0x6109, 0x1078, 0x61d3, 0x0d7f, 0x0078, 0x5871, 0x0d7e, 0x2069,
+	0xa300, 0x6944, 0x6860, 0xa102, 0x00c8, 0x5870, 0x2069, 0xa5ab,
+	0x6804, 0xa086, 0x0000, 0x00c0, 0x5870, 0x6830, 0xa086, 0x0000,
+	0x00c0, 0x5870, 0x703f, 0x0001, 0x6807, 0x0006, 0x6833, 0x0003,
+	0x2069, 0x0100, 0x6830, 0x689e, 0x2069, 0x0140, 0x6803, 0x0600,
+	0x0d7f, 0x0078, 0x5876, 0x127e, 0x2091, 0x8000, 0x7024, 0xa00d,
+	0x0040, 0x588e, 0x7020, 0x8001, 0x7022, 0x00c0, 0x588e, 0x7023,
+	0x0009, 0x8109, 0x7126, 0xa186, 0x03e8, 0x00c0, 0x5889, 0x7028,
+	0x107a, 0x81ff, 0x00c0, 0x588e, 0x7028, 0x107a, 0x7030, 0xa00d,
+	0x0040, 0x589f, 0x702c, 0x8001, 0x702e, 0x00c0, 0x589f, 0x702f,
+	0x0009, 0x8109, 0x7132, 0x00c0, 0x589f, 0x7034, 0x107a, 0x7040,
+	0xa005, 0x0040, 0x58a7, 0x0050, 0x58a7, 0x8001, 0x7042, 0x7044,
+	0xa005, 0x0040, 0x58af, 0x0050, 0x58af, 0x8001, 0x7046, 0x7018,
+	0xa00d, 0x0040, 0x58c0, 0x7008, 0x8001, 0x700a, 0x00c0, 0x58c0,
+	0x700b, 0x0009, 0x8109, 0x711a, 0x00c0, 0x58c0, 0x701c, 0x107a,
+	0x127f, 0x7004, 0x0079, 0x58c4, 0x58eb, 0x58ec, 0x5908, 0x0e7e,
+	0x2071, 0xa5be, 0x7018, 0xa005, 0x00c0, 0x58d2, 0x711a, 0x721e,
+	0x700b, 0x0009, 0x0e7f, 0x007c, 0x0e7e, 0x007e, 0x2071, 0xa5be,
+	0x701c, 0xa206, 0x00c0, 0x58de, 0x701a, 0x701e, 0x007f, 0x0e7f,
+	0x007c, 0x0e7e, 0x2071, 0xa5be, 0x6088, 0xa102, 0x0048, 0x58e9,
+	0x618a, 0x0e7f, 0x007c, 0x007c, 0x7110, 0x1078, 0x4501, 0x00c0,
+	0x58fe, 0x6088, 0x8001, 0x0048, 0x58fe, 0x608a, 0x00c0, 0x58fe,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x8108, 0xa182,
+	0x00ff, 0x0048, 0x5906, 0xa00e, 0x7007, 0x0002, 0x7112, 0x007c,
+	0x7014, 0x2060, 0x127e, 0x2091, 0x8000, 0x603c, 0xa005, 0x0040,
+	0x5917, 0x8001, 0x603e, 0x00c0, 0x5917, 0x1078, 0x8cd7, 0x6014,
+	0xa005, 0x0040, 0x5941, 0x8001, 0x6016, 0x00c0, 0x5941, 0x611c,
+	0xa186, 0x0003, 0x0040, 0x5928, 0xa186, 0x0006, 0x00c0, 0x593f,
+	0x6010, 0x2068, 0x6854, 0xa08a, 0x199a, 0x0048, 0x593f, 0xa082,
+	0x1999, 0x6856, 0xa08a, 0x199a, 0x0048, 0x5938, 0x2001, 0x1999,
+	0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x0078, 0x5941, 0x1078,
+	0x8810, 0x127f, 0xac88, 0x0010, 0x7116, 0x2001, 0xca00, 0xa102,
+	0x0048, 0x594e, 0x7017, 0xaa00, 0x7007, 0x0000, 0x007c, 0x0e7e,
+	0x2071, 0xa5be, 0x7027, 0x07d0, 0x7023, 0x0009, 0x703b, 0x0002,
+	0x0e7f, 0x007c, 0x2001, 0xa5c7, 0x2003, 0x0000, 0x007c, 0x0e7e,
+	0x2071, 0xa5be, 0x7132, 0x702f, 0x0009, 0x0e7f, 0x007c, 0x2011,
+	0xa5ca, 0x2013, 0x0000, 0x007c, 0x0e7e, 0x2071, 0xa5be, 0x711a,
+	0x721e, 0x700b, 0x0009, 0x0e7f, 0x007c, 0x027e, 0x0e7e, 0x0f7e,
+	0x2079, 0xa300, 0x7a34, 0xd294, 0x0040, 0x59a4, 0x2071, 0xa5aa,
+	0x2e14, 0xa0fe, 0x0000, 0x0040, 0x5991, 0xa0fe, 0x0001, 0x0040,
+	0x5995, 0xa0fe, 0x0002, 0x00c0, 0x59a0, 0xa292, 0x0085, 0x0078,
+	0x5997, 0xa292, 0x0005, 0x0078, 0x5997, 0xa292, 0x0002, 0x2272,
+	0x0040, 0x599c, 0x00c8, 0x59a4, 0x2011, 0x8037, 0x1078, 0x3579,
+	0x2011, 0xa5a9, 0x2204, 0x2072, 0x0f7f, 0x0e7f, 0x027f, 0x007c,
+	0x0c7e, 0x2061, 0xa62d, 0x0c7f, 0x007c, 0xa184, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa080, 0xa62d, 0x2060, 0x007c, 0x6854, 0xa08a,
+	0x199a, 0x0048, 0x59bd, 0x2001, 0x1999, 0xa005, 0x00c0, 0x59cc,
+	0x0c7e, 0x2061, 0xa62d, 0x6014, 0x0c7f, 0xa005, 0x00c0, 0x59d1,
+	0x2001, 0x001e, 0x0078, 0x59d1, 0xa08e, 0xffff, 0x00c0, 0x59d1,
+	0xa006, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c,
+	0x00c0, 0xa18e, 0x00c0, 0x0040, 0x5a24, 0xd0b4, 0x00c0, 0x59e8,
+	0xd0bc, 0x00c0, 0x5a14, 0x2009, 0x0006, 0x1078, 0x5a43, 0x007c,
+	0xd0fc, 0x0040, 0x59f3, 0xa084, 0x0003, 0x0040, 0x59f3, 0xa086,
+	0x0003, 0x00c0, 0x5a3c, 0x6024, 0xd0d4, 0x0040, 0x59fd, 0xc0d4,
+	0x6026, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xa373, 0x2104,
+	0xd084, 0x0040, 0x5a0f, 0x6118, 0xa188, 0x0027, 0x2104, 0xd08c,
+	0x00c0, 0x5a0f, 0x2009, 0x0042, 0x1078, 0x756c, 0x007c, 0x2009,
+	0x0043, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a1f, 0xa084,
+	0x0003, 0x0040, 0x5a1f, 0xa086, 0x0003, 0x00c0, 0x5a3c, 0x2009,
+	0x0042, 0x1078, 0x756c, 0x007c, 0xd0fc, 0x0040, 0x5a32, 0xa084,
+	0x0003, 0xa08e, 0x0002, 0x0040, 0x5a36, 0x2009, 0x0041, 0x1078,
+	0x756c, 0x007c, 0x1078, 0x5a41, 0x0078, 0x5a31, 0x2009, 0x0043,
+	0x1078, 0x756c, 0x0078, 0x5a31, 0x2009, 0x0004, 0x1078, 0x5a43,
+	0x007c, 0x2009, 0x0001, 0x0d7e, 0x6010, 0xa0ec, 0xf000, 0x0040,
+	0x5a6b, 0x2068, 0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x00c0,
+	0x5a65, 0x694c, 0xa18c, 0x8100, 0xa18e, 0x8100, 0x00c0, 0x5a65,
+	0x0c7e, 0x2061, 0xa62d, 0x6200, 0xd28c, 0x00c0, 0x5a64, 0x6204,
+	0x8210, 0x0048, 0x5a64, 0x6206, 0x0c7f, 0x1078, 0x4982, 0x6010,
+	0xa06d, 0x10c0, 0x59b6, 0x0d7f, 0x007c, 0x157e, 0x0c7e, 0x2061,
+	0xa62d, 0x6000, 0x81ff, 0x0040, 0x5a78, 0xa205, 0x0078, 0x5a79,
+	0xa204, 0x6002, 0x0c7f, 0x157f, 0x007c, 0x6800, 0xd08c, 0x00c0,
+	0x5a89, 0x6808, 0xa005, 0x0040, 0x5a89, 0x8001, 0x680a, 0xa085,
+	0x0001, 0x007c, 0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e,
+	0x00c8, 0x5a93, 0xa200, 0x00f0, 0x5a8e, 0x8086, 0x818e, 0x007c,
+	0x157e, 0x20a9, 0x0010, 0xa005, 0x0040, 0x5ab9, 0xa11a, 0x00c8,
+	0x5ab9, 0x8213, 0x818d, 0x0048, 0x5aac, 0xa11a, 0x00c8, 0x5aad,
+	0x00f0, 0x5aa1, 0x0078, 0x5ab1, 0xa11a, 0x2308, 0x8210, 0x00f0,
+	0x5aa1, 0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f,
+	0x007c, 0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x5ab5, 0x127e,
+	0x2091, 0x2200, 0x2079, 0xa5ab, 0x127f, 0x0d7e, 0x2069, 0xa5ab,
+	0x6803, 0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a,
+	0x0d7f, 0x007c, 0x0c7e, 0x6027, 0x0001, 0x7804, 0xa084, 0x0007,
+	0x0079, 0x5ada, 0x5ae4, 0x5b09, 0x5b64, 0x5aea, 0x5b09, 0x5ae4,
+	0x5ae2, 0x5ae2, 0x1078, 0x1328, 0x1078, 0x595a, 0x1078, 0x6109,
+	0x0c7f, 0x007c, 0x62c0, 0x82ff, 0x00c0, 0x5af0, 0x0c7f, 0x007c,
+	0x2011, 0x4129, 0x1078, 0x58d4, 0x7828, 0xa092, 0x00c8, 0x00c8,
+	0x5aff, 0x8000, 0x782a, 0x1078, 0x4168, 0x0078, 0x5aee, 0x1078,
+	0x4129, 0x7807, 0x0003, 0x7827, 0x0000, 0x782b, 0x0000, 0x0078,
+	0x5aee, 0x1078, 0x595a, 0x3c00, 0x007e, 0x2011, 0x0209, 0x20e1,
+	0x4000, 0x2214, 0x007f, 0x20e0, 0x82ff, 0x0040, 0x5b27, 0x62c0,
+	0x82ff, 0x00c0, 0x5b27, 0x782b, 0x0000, 0x7824, 0xa065, 0x1040,
+	0x1328, 0x2009, 0x0013, 0x1078, 0x756c, 0x0c7f, 0x007c, 0x3900,
+	0xa082, 0xa6cd, 0x00c8, 0x5b2e, 0x1078, 0x728a, 0x0c7e, 0x7824,
+	0xa065, 0x1040, 0x1328, 0x7804, 0xa086, 0x0004, 0x0040, 0x5ba9,
+	0x7828, 0xa092, 0x2710, 0x00c8, 0x5b44, 0x8000, 0x782a, 0x0c7f,
+	0x1078, 0x6c33, 0x0078, 0x5b25, 0x6104, 0xa186, 0x0003, 0x00c0,
+	0x5b5b, 0x0e7e, 0x2071, 0xa300, 0x70d4, 0x0e7f, 0xd08c, 0x0040,
+	0x5b5b, 0x0c7e, 0x0e7e, 0x2061, 0x0100, 0x2071, 0xa300, 0x1078,
+	0x4171, 0x0e7f, 0x0c7f, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078,
+	0x756c, 0x0c7f, 0x0078, 0x5b25, 0x2001, 0xa5c7, 0x2003, 0x0000,
+	0x62c0, 0x82ff, 0x00c0, 0x5b78, 0x782b, 0x0000, 0x7824, 0xa065,
+	0x1040, 0x1328, 0x2009, 0x0013, 0x1078, 0x75c3, 0x0c7f, 0x007c,
+	0x0c7e, 0x0d7e, 0x3900, 0xa082, 0xa6cd, 0x00c8, 0x5b81, 0x1078,
+	0x728a, 0x7824, 0xa005, 0x1040, 0x1328, 0x781c, 0xa06d, 0x1040,
+	0x1328, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, 0x1078, 0x753d,
+	0x693c, 0x81ff, 0x1040, 0x1328, 0x8109, 0x693e, 0x6854, 0xa015,
+	0x0040, 0x5b9d, 0x7a1e, 0x0078, 0x5b9f, 0x7918, 0x791e, 0x7807,
+	0x0000, 0x7827, 0x0000, 0x0d7f, 0x0c7f, 0x1078, 0x6109, 0x0078,
+	0x5b76, 0x6104, 0xa186, 0x0002, 0x0040, 0x5bb4, 0xa186, 0x0004,
+	0x0040, 0x5bb4, 0x0078, 0x5b38, 0x7808, 0xac06, 0x0040, 0x5b38,
+	0x1078, 0x6010, 0x1078, 0x5c45, 0x0c7f, 0x1078, 0x6109, 0x0078,
+	0x5b25, 0x0c7e, 0x6027, 0x0002, 0x62c8, 0x82ff, 0x00c0, 0x5bdb,
+	0x62c4, 0x82ff, 0x00c0, 0x5bdb, 0x793c, 0xa1e5, 0x0000, 0x0040,
+	0x5bd5, 0x2009, 0x0049, 0x1078, 0x756c, 0x2011, 0xa5ca, 0x2013,
+	0x0000, 0x0c7f, 0x007c, 0x3908, 0xa192, 0xa6cd, 0x00c8, 0x5be2,
+	0x1078, 0x728a, 0x6017, 0x0010, 0x793c, 0x81ff, 0x0040, 0x5bd5,
+	0x793c, 0xa188, 0x0007, 0x210c, 0xa18e, 0x0006, 0x00c0, 0x5bf4,
+	0x6017, 0x0012, 0x0078, 0x5bd9, 0x6017, 0x0016, 0x0078, 0x5bd9,
+	0x007e, 0x017e, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x600f, 0x0000,
+	0x2c08, 0x2061, 0xa5ab, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005,
+	0x0040, 0x5c13, 0xa080, 0x0003, 0x2102, 0x6112, 0x127f, 0x0c7f,
+	0x017f, 0x007f, 0x007c, 0x6116, 0x6112, 0x0078, 0x5c0e, 0x0d7e,
+	0x2069, 0xa5ab, 0x6000, 0xd0d4, 0x0040, 0x5c2c, 0x6820, 0x8000,
+	0x6822, 0xa086, 0x0001, 0x00c0, 0x5c27, 0x2c00, 0x681e, 0x6804,
+	0xa084, 0x0007, 0x0079, 0x6111, 0xc0d5, 0x6002, 0x6818, 0xa005,
+	0x0040, 0x5c3e, 0x6056, 0x605b, 0x0000, 0x007e, 0x2c00, 0x681a,
+	0x0d7f, 0x685a, 0x2069, 0xa5ab, 0x0078, 0x5c1e, 0x6056, 0x605a,
+	0x2c00, 0x681a, 0x681e, 0x0078, 0x5c1e, 0x007e, 0x017e, 0x0c7e,
+	0x127e, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061, 0xa5ab,
+	0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0040, 0x5c60, 0xa080,
+	0x0003, 0x2102, 0x610a, 0x127f, 0x0c7f, 0x017f, 0x007f, 0x007c,
+	0x610e, 0x610a, 0x0078, 0x5c5b, 0x0c7e, 0x600f, 0x0000, 0x2c08,
+	0x2061, 0xa5ab, 0x6034, 0xa005, 0x0040, 0x5c74, 0xa080, 0x0003,
+	0x2102, 0x6136, 0x0c7f, 0x007c, 0x613a, 0x6136, 0x0078, 0x5c72,
+	0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x027e, 0x017e, 0x007e,
+	0x127e, 0x2071, 0xa5ab, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000,
+	0x8cff, 0x0040, 0x5ced, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206,
+	0x00c0, 0x5ce8, 0x87ff, 0x0040, 0x5c99, 0x6020, 0xa106, 0x00c0,
+	0x5ce8, 0x703c, 0xac06, 0x00c0, 0x5cab, 0x037e, 0x2019, 0x0001,
+	0x1078, 0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000,
+	0x7047, 0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x5cb1, 0x660c,
+	0x763a, 0x7034, 0xac36, 0x00c0, 0x5cbf, 0x2c00, 0xaf36, 0x0040,
+	0x5cbd, 0x2f00, 0x7036, 0x0078, 0x5cbf, 0x7037, 0x0000, 0x660c,
+	0x067e, 0x2c00, 0xaf06, 0x0040, 0x5cc8, 0x7e0e, 0x0078, 0x5cc9,
+	0x2678, 0x600f, 0x0000, 0x1078, 0x8a44, 0x0040, 0x5ce3, 0x6010,
+	0x2068, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5cf7, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078,
+	0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5c88,
+	0x2c78, 0x600c, 0x2060, 0x0078, 0x5c88, 0x127f, 0x007f, 0x017f,
+	0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x601c,
+	0xa086, 0x0006, 0x00c0, 0x5cd6, 0x1078, 0xa181, 0x1078, 0x9e70,
+	0x0078, 0x5ce3, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x0f7e, 0x2031,
+	0x0000, 0x127e, 0x2091, 0x8000, 0x2079, 0xa5ab, 0x7838, 0xa065,
+	0x0040, 0x5d41, 0x600c, 0x007e, 0x600f, 0x0000, 0x783c, 0xac06,
+	0x00c0, 0x5d28, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x7833,
+	0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000, 0x037f,
+	0x1078, 0x8a44, 0x0040, 0x5d3c, 0x6010, 0x2068, 0x601c, 0xa086,
+	0x0003, 0x00c0, 0x5d4a, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x007f, 0x0078,
+	0x5d0f, 0x7e3a, 0x7e36, 0x127f, 0x0f7f, 0x0d7f, 0x0c7f, 0x067f,
+	0x007f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5d33, 0x1078,
+	0x9e70, 0x0078, 0x5d3c, 0x017e, 0x027e, 0x087e, 0x2041, 0x0000,
+	0x1078, 0x5d6d, 0x1078, 0x5e21, 0x087f, 0x027f, 0x017f, 0x007c,
+	0x0f7e, 0x127e, 0x2079, 0xa5ab, 0x2091, 0x8000, 0x1078, 0x5ebc,
+	0x1078, 0x5f32, 0x127f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e, 0x0d7e,
+	0x0c7e, 0x067e, 0x017e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071,
+	0xa5ab, 0x7614, 0x2660, 0x2678, 0x8cff, 0x0040, 0x5e01, 0x6018,
+	0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x5dfc, 0x88ff, 0x0040,
+	0x5d8d, 0x6020, 0xa106, 0x00c0, 0x5dfc, 0x7024, 0xac06, 0x00c0,
+	0x5dbd, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040, 0x5db8, 0x1078,
+	0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188, 0x7027,
+	0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0040,
+	0x5dad, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824,
+	0xd084, 0x0040, 0x5db5, 0x6827, 0x0001, 0x037f, 0x0078, 0x5dbd,
+	0x6003, 0x0009, 0x630a, 0x0078, 0x5dfc, 0x7014, 0xac36, 0x00c0,
+	0x5dc3, 0x660c, 0x7616, 0x7010, 0xac36, 0x00c0, 0x5dd1, 0x2c00,
+	0xaf36, 0x0040, 0x5dcf, 0x2f00, 0x7012, 0x0078, 0x5dd1, 0x7013,
+	0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040, 0x5dda, 0x7e0e,
+	0x0078, 0x5ddb, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x5df5, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5e0a,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078,
+	0xa181, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078,
+	0x7045, 0x0c7f, 0x0078, 0x5d7c, 0x2c78, 0x600c, 0x2060, 0x0078,
+	0x5d7c, 0x127f, 0x007f, 0x017f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f,
+	0x0f7f, 0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x5e15, 0x1078,
+	0xa181, 0x1078, 0x9e70, 0x0078, 0x5df5, 0x601c, 0xa086, 0x0002,
+	0x00c0, 0x5df5, 0x6004, 0xa086, 0x0085, 0x0040, 0x5de8, 0x0078,
+	0x5df5, 0x0c7e, 0x007e, 0x127e, 0x2091, 0x8000, 0xa280, 0xa434,
+	0x2004, 0xa065, 0x0040, 0x5eb8, 0x0f7e, 0x0e7e, 0x0d7e, 0x067e,
+	0x2071, 0xa5ab, 0x6654, 0x7018, 0xac06, 0x00c0, 0x5e38, 0x761a,
+	0x701c, 0xac06, 0x00c0, 0x5e44, 0x86ff, 0x00c0, 0x5e43, 0x7018,
+	0x701e, 0x0078, 0x5e44, 0x761e, 0x6058, 0xa07d, 0x0040, 0x5e49,
+	0x7e56, 0xa6ed, 0x0000, 0x0040, 0x5e4f, 0x2f00, 0x685a, 0x6057,
+	0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078,
+	0x4410, 0x0040, 0x5eb4, 0x7624, 0x86ff, 0x0040, 0x5ea2, 0xa680,
+	0x0004, 0x2004, 0xad06, 0x00c0, 0x5ea2, 0x0d7e, 0x2069, 0x0100,
+	0x68c0, 0xa005, 0x0040, 0x5e99, 0x1078, 0x595a, 0x1078, 0x6c41,
+	0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069,
+	0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5e82, 0x6803, 0x0100,
+	0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5e8a,
+	0x6827, 0x0001, 0x037f, 0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040,
+	0x5e93, 0x8001, 0x603e, 0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078,
+	0x5ea2, 0x0d7f, 0x0c7e, 0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f,
+	0x0078, 0x5e57, 0x8dff, 0x0040, 0x5eb0, 0x6837, 0x0103, 0x6b4a,
+	0x6847, 0x0000, 0x1078, 0x8cb8, 0x1078, 0xa181, 0x1078, 0x4982,
+	0x1078, 0x7045, 0x0078, 0x5e57, 0x067f, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x127f, 0x007f, 0x0c7f, 0x007c, 0x007e, 0x067e, 0x0c7e, 0x0d7e,
+	0x2031, 0x0000, 0x7814, 0xa065, 0x0040, 0x5f16, 0x600c, 0x007e,
+	0x600f, 0x0000, 0x7824, 0xac06, 0x00c0, 0x5efb, 0x2069, 0x0100,
+	0x68c0, 0xa005, 0x0040, 0x5ef5, 0x1078, 0x595a, 0x1078, 0x6c41,
+	0x68c3, 0x0000, 0x1078, 0x7188, 0x7827, 0x0000, 0x037e, 0x2069,
+	0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x5eea, 0x6803, 0x0100,
+	0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x5ef2,
+	0x6827, 0x0001, 0x037f, 0x0078, 0x5efb, 0x6003, 0x0009, 0x630a,
+	0x2c30, 0x0078, 0x5f13, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040,
+	0x5f0f, 0x601c, 0xa086, 0x0003, 0x00c0, 0x5f1d, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078,
+	0x8c01, 0x1078, 0x7045, 0x007f, 0x0078, 0x5ec3, 0x7e16, 0x7e12,
+	0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x601c, 0xa086, 0x0006,
+	0x00c0, 0x5f26, 0x1078, 0x9e70, 0x0078, 0x5f0f, 0x601c, 0xa086,
+	0x0002, 0x00c0, 0x5f0f, 0x6004, 0xa086, 0x0085, 0x0040, 0x5f06,
+	0x0078, 0x5f0f, 0x007e, 0x067e, 0x0c7e, 0x0d7e, 0x7818, 0xa065,
+	0x0040, 0x5fa0, 0x6054, 0x007e, 0x6057, 0x0000, 0x605b, 0x0000,
+	0x6000, 0xc0d4, 0xc0dc, 0x6002, 0x1078, 0x4410, 0x0040, 0x5f9d,
+	0x7e24, 0x86ff, 0x0040, 0x5f8f, 0xa680, 0x0004, 0x2004, 0xad06,
+	0x00c0, 0x5f8f, 0x0d7e, 0x2069, 0x0100, 0x68c0, 0xa005, 0x0040,
+	0x5f86, 0x1078, 0x595a, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078,
+	0x7188, 0x7827, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384,
+	0x1000, 0x0040, 0x5f6f, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069,
+	0x0100, 0x6824, 0xd084, 0x0040, 0x5f77, 0x6827, 0x0001, 0x037f,
+	0x0d7f, 0x0c7e, 0x603c, 0xa005, 0x0040, 0x5f80, 0x8001, 0x603e,
+	0x2660, 0x1078, 0x8c01, 0x0c7f, 0x0078, 0x5f8f, 0x0d7f, 0x0c7e,
+	0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x5f44, 0x8dff,
+	0x0040, 0x5f99, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078,
+	0x4982, 0x1078, 0x7045, 0x0078, 0x5f44, 0x007f, 0x0078, 0x5f37,
+	0x781e, 0x781a, 0x0d7f, 0x0c7f, 0x067f, 0x007f, 0x007c, 0x0e7e,
+	0x0d7e, 0x067e, 0x6000, 0xd0dc, 0x0040, 0x5fc4, 0x604c, 0xa06d,
+	0x0040, 0x5fc4, 0x6848, 0xa606, 0x00c0, 0x5fc4, 0x2071, 0xa5ab,
+	0x7024, 0xa035, 0x0040, 0x5fc4, 0xa080, 0x0004, 0x2004, 0xad06,
+	0x00c0, 0x5fc4, 0x1078, 0x5fc8, 0x067f, 0x0d7f, 0x0e7f, 0x007c,
+	0x0f7e, 0x2079, 0x0100, 0x78c0, 0xa005, 0x00c0, 0x5fd7, 0x0c7e,
+	0x2660, 0x6003, 0x0009, 0x630a, 0x0c7f, 0x0078, 0x600e, 0x1078,
+	0x6c41, 0x78c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e,
+	0x2079, 0x0140, 0x7b04, 0xa384, 0x1000, 0x0040, 0x5feb, 0x7803,
+	0x0100, 0x7803, 0x0000, 0x2079, 0x0100, 0x7824, 0xd084, 0x0040,
+	0x5ff3, 0x7827, 0x0001, 0x1078, 0x7188, 0x037f, 0x1078, 0x4410,
+	0x0c7e, 0x603c, 0xa005, 0x0040, 0x5fff, 0x8001, 0x603e, 0x2660,
+	0x1078, 0x753d, 0x0c7f, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x1078, 0x8cb8, 0x1078, 0x4982, 0x1078, 0x7045, 0x0f7f, 0x007c,
+	0x0e7e, 0x0c7e, 0x2071, 0xa5ab, 0x7004, 0xa084, 0x0007, 0x0079,
+	0x6019, 0x6023, 0x6026, 0x603f, 0x605b, 0x60a0, 0x6023, 0x6023,
+	0x6021, 0x1078, 0x1328, 0x0c7f, 0x0e7f, 0x007c, 0x7024, 0xa065,
+	0x0040, 0x6034, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015, 0x0040,
+	0x603b, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000,
+	0x0c7f, 0x0e7f, 0x007c, 0x7216, 0x7212, 0x0078, 0x6034, 0x6018,
+	0x2060, 0x1078, 0x4410, 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001,
+	0x7022, 0x0040, 0x6050, 0x6054, 0xa015, 0x0040, 0x6057, 0x721e,
+	0x7007, 0x0000, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x7218,
+	0x721e, 0x0078, 0x6050, 0x7024, 0xa065, 0x0040, 0x609d, 0x700c,
+	0xac06, 0x00c0, 0x6072, 0x1078, 0x7045, 0x600c, 0xa015, 0x0040,
+	0x606e, 0x720e, 0x600f, 0x0000, 0x0078, 0x609b, 0x720e, 0x720a,
+	0x0078, 0x609b, 0x7014, 0xac06, 0x00c0, 0x6085, 0x1078, 0x7045,
+	0x600c, 0xa015, 0x0040, 0x6081, 0x7216, 0x600f, 0x0000, 0x0078,
+	0x609b, 0x7216, 0x7212, 0x0078, 0x609b, 0x6018, 0x2060, 0x1078,
+	0x4410, 0x6000, 0xc0dc, 0x6002, 0x1078, 0x7045, 0x701c, 0xa065,
+	0x0040, 0x609b, 0x6054, 0xa015, 0x0040, 0x6099, 0x721e, 0x0078,
+	0x609b, 0x7218, 0x721e, 0x7027, 0x0000, 0x0c7f, 0x0e7f, 0x007c,
+	0x7024, 0xa065, 0x0040, 0x60ad, 0x1078, 0x7045, 0x600c, 0xa015,
+	0x0040, 0x60b4, 0x720e, 0x600f, 0x0000, 0x1078, 0x7188, 0x7027,
+	0x0000, 0x0c7f, 0x0e7f, 0x007c, 0x720e, 0x720a, 0x0078, 0x60ad,
+	0x0d7e, 0x2069, 0xa5ab, 0x6830, 0xa084, 0x0003, 0x0079, 0x60c0,
+	0x60c6, 0x60c8, 0x60ee, 0x60c6, 0x1078, 0x1328, 0x0d7f, 0x007c,
+	0x0c7e, 0x6840, 0xa086, 0x0001, 0x0040, 0x60e4, 0x683c, 0xa065,
+	0x0040, 0x60d9, 0x600c, 0xa015, 0x0040, 0x60e0, 0x6a3a, 0x600f,
+	0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x0c7f, 0x0d7f, 0x007c,
+	0x683a, 0x6836, 0x0078, 0x60d9, 0x6843, 0x0000, 0x6838, 0xa065,
+	0x0040, 0x60d9, 0x6003, 0x0003, 0x0078, 0x60d9, 0x0c7e, 0x6843,
+	0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0040, 0x6106, 0x600c,
+	0xa015, 0x0040, 0x6102, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000,
+	0x0078, 0x6106, 0x683f, 0x0000, 0x683a, 0x6836, 0x0c7f, 0x0d7f,
+	0x007c, 0x0d7e, 0x2069, 0xa5ab, 0x6804, 0xa084, 0x0007, 0x0079,
+	0x6111, 0x611b, 0x61c2, 0x61c2, 0x61c2, 0x61c2, 0x61c4, 0x61c2,
+	0x6119, 0x1078, 0x1328, 0x6820, 0xa005, 0x00c0, 0x6121, 0x0d7f,
+	0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040, 0x6130, 0x6807, 0x0004,
+	0x6826, 0x682b, 0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c,
+	0x6814, 0xa065, 0x0040, 0x613e, 0x6807, 0x0001, 0x6826, 0x682b,
+	0x0000, 0x1078, 0x620a, 0x0c7f, 0x0d7f, 0x007c, 0x0e7e, 0x037e,
+	0x6a1c, 0xa2f5, 0x0000, 0x0040, 0x61bd, 0x704c, 0xa00d, 0x0040,
+	0x614d, 0x7088, 0xa005, 0x0040, 0x6165, 0x7054, 0xa075, 0x0040,
+	0x6156, 0xa20e, 0x0040, 0x61bd, 0x0078, 0x615b, 0x6818, 0xa20e,
+	0x0040, 0x61bd, 0x2070, 0x704c, 0xa00d, 0x0040, 0x614d, 0x7088,
+	0xa005, 0x00c0, 0x614d, 0x2e00, 0x681e, 0x733c, 0x7038, 0xa302,
+	0x00c8, 0x614d, 0x1078, 0x750c, 0x0040, 0x61bd, 0x8318, 0x733e,
+	0x6112, 0x2e10, 0x621a, 0xa180, 0x0014, 0x2004, 0xa084, 0x00ff,
+	0x6032, 0xa180, 0x0014, 0x2003, 0x0000, 0xa180, 0x0015, 0x2004,
+	0xa08a, 0x199a, 0x0048, 0x6186, 0x2001, 0x1999, 0x8003, 0x801b,
+	0x831b, 0xa318, 0x6316, 0x037f, 0x0f7e, 0x2c78, 0x71a0, 0xd1bc,
+	0x0040, 0x619f, 0x7100, 0xd1f4, 0x0040, 0x619b, 0x7114, 0xa18c,
+	0x00ff, 0x0078, 0x61a4, 0x2009, 0x0000, 0x0078, 0x61a4, 0xa1e0,
+	0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0x1078,
+	0x679b, 0x7300, 0xc3dd, 0x7302, 0x6807, 0x0002, 0x2f18, 0x6b26,
+	0x682b, 0x0000, 0x781f, 0x0003, 0x7803, 0x0001, 0x7807, 0x0040,
+	0x0f7f, 0x0e7f, 0x0c7f, 0x0d7f, 0x007c, 0x037f, 0x0e7f, 0x0c7f,
+	0x0078, 0x61bb, 0x0d7f, 0x007c, 0x0c7e, 0x680c, 0xa065, 0x0040,
+	0x61d0, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x1078, 0x620a,
+	0x0c7f, 0x0d7f, 0x007c, 0x0f7e, 0x0d7e, 0x2069, 0xa5ab, 0x6830,
+	0xa086, 0x0000, 0x00c0, 0x61f1, 0x6838, 0xa07d, 0x0040, 0x61f1,
+	0x6833, 0x0001, 0x683e, 0x6847, 0x0000, 0x127e, 0x0f7e, 0x2091,
+	0x2200, 0x027f, 0x1078, 0x1d28, 0x00c0, 0x61f4, 0x127f, 0x1078,
+	0x6ae5, 0x0d7f, 0x0f7f, 0x007c, 0x127f, 0x6843, 0x0000, 0x7803,
+	0x0002, 0x780c, 0xa015, 0x0040, 0x6206, 0x6a3a, 0x780f, 0x0000,
+	0x6833, 0x0000, 0x683f, 0x0000, 0x0078, 0x61f1, 0x683a, 0x6836,
+	0x0078, 0x6200, 0x601c, 0xa084, 0x000f, 0x1079, 0x6210, 0x007c,
+	0x6219, 0x621e, 0x663f, 0x6758, 0x621e, 0x663f, 0x6758, 0x6219,
+	0x621e, 0x1078, 0x6010, 0x1078, 0x6109, 0x007c, 0x157e, 0x137e,
+	0x147e, 0x0c7e, 0x0f7e, 0x6004, 0xa08a, 0x0044, 0x10c8, 0x1328,
+	0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x623b, 0x7900, 0xd1f4,
+	0x0040, 0x6237, 0x7914, 0xa18c, 0x00ff, 0x0078, 0x6240, 0x2009,
+	0x0000, 0x0078, 0x6240, 0xa1f8, 0x293f, 0x2f0c, 0xa18c, 0x00ff,
+	0x2c78, 0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x00c8, 0x6292,
+	0x1079, 0x6250, 0x0f7f, 0x0c7f, 0x147f, 0x137f, 0x157f, 0x007c,
+	0x62f8, 0x6340, 0x6368, 0x6403, 0x6433, 0x643b, 0x6462, 0x6473,
+	0x6484, 0x648c, 0x64a4, 0x648c, 0x650f, 0x6473, 0x6530, 0x6538,
+	0x6484, 0x6538, 0x6549, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290,
+	0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6290, 0x6d05, 0x6d2a,
+	0x6d3f, 0x6d62, 0x6d83, 0x6462, 0x6290, 0x6462, 0x648c, 0x6290,
+	0x6368, 0x6403, 0x6290, 0x72ac, 0x648c, 0x6290, 0x72cc, 0x648c,
+	0x6290, 0x6290, 0x62f3, 0x62a1, 0x6290, 0x72f1, 0x7368, 0x7450,
+	0x6290, 0x7461, 0x645c, 0x747d, 0x6290, 0x6d98, 0x6290, 0x6290,
+	0x1078, 0x1328, 0x2100, 0x1079, 0x629b, 0x0f7f, 0x0c7f, 0x147f,
+	0x137f, 0x157f, 0x007c, 0x629f, 0x629f, 0x629f, 0x62d5, 0x1078,
+	0x1328, 0x0d7e, 0x20a1, 0x020b, 0x1078, 0x6567, 0x7810, 0x2068,
+	0x20a3, 0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x683c, 0x20a2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x6850, 0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0018, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x0d7e, 0x7818,
+	0x2068, 0x68a0, 0xa082, 0x007e, 0x0048, 0x62d2, 0xa085, 0x0001,
+	0x0d7f, 0x007c, 0xa006, 0x0078, 0x62d0, 0x0d7e, 0x20a1, 0x020b,
+	0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x7810, 0xa0e8,
+	0x000f, 0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, 0x20a2, 0x6814,
+	0x20a2, 0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, 0x0010, 0x1078,
+	0x6c2d, 0x0d7f, 0x007c, 0x6030, 0x609a, 0x1078, 0x6c2d, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x5200, 0x20a3, 0x0000,
+	0x0d7e, 0x2069, 0xa351, 0x6804, 0xd084, 0x0040, 0x6312, 0x6828,
+	0x20a3, 0x0000, 0x017e, 0x1078, 0x24fa, 0x21a2, 0x017f, 0x0d7f,
+	0x0078, 0x6317, 0x0d7f, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a9,
+	0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301,
+	0x53a6, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048,
+	0x6331, 0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078,
+	0x6337, 0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x0500, 0x20a3, 0x0000,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0048, 0x6358,
+	0x2001, 0xa31a, 0x20a6, 0x2001, 0xa31b, 0x20a6, 0x0078, 0x635e,
+	0x20a3, 0x0000, 0x6030, 0xa084, 0x00ff, 0x20a2, 0x20a9, 0x0004,
+	0x2099, 0xa305, 0x53a6, 0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x6567, 0x0c7e, 0x7818, 0x2060, 0x2001,
+	0x0000, 0x1078, 0x48a2, 0x0c7f, 0x7818, 0xa080, 0x0028, 0x2004,
+	0xa086, 0x007e, 0x00c0, 0x6383, 0x20a3, 0x0400, 0x620c, 0xc2b4,
+	0x620e, 0x0078, 0x6385, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x00c0, 0x63d2, 0x2099,
+	0xa58c, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0xa084, 0x3fff,
+	0x20a2, 0x9398, 0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a9, 0x0004, 0x2099, 0xa305, 0x53a6,
+	0x20a9, 0x0004, 0x2099, 0xa301, 0x53a6, 0x20a9, 0x0010, 0x20a3,
+	0x0000, 0x00f0, 0x63af, 0x2099, 0xa594, 0x3304, 0xc0dd, 0x20a2,
+	0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040, 0x63ca, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x9398, 0x9398, 0x9398, 0x33a6, 0x20a9, 0x0004,
+	0x0078, 0x63cc, 0x20a9, 0x0007, 0x20a3, 0x0000, 0x00f0, 0x63cc,
+	0x0078, 0x63f2, 0x2099, 0xa58c, 0x20a9, 0x0008, 0x53a6, 0x20a9,
+	0x0004, 0x2099, 0xa305, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xa301,
+	0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e3, 0x20a9,
+	0x0008, 0x20a3, 0x0000, 0x00f0, 0x63e9, 0x2099, 0xa594, 0x20a9,
+	0x0008, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x00f0, 0x63f4,
+	0x20a9, 0x000a, 0x20a3, 0x0000, 0x00f0, 0x63fa, 0x60c3, 0x0074,
+	0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3,
+	0x2010, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351,
+	0x7904, 0x0f7f, 0xd1ac, 0x00c0, 0x641f, 0xa085, 0x0020, 0xd1a4,
+	0x0040, 0x6424, 0xa085, 0x0010, 0xa085, 0x0002, 0x0d7e, 0x0078,
+	0x64ed, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3,
+	0x5000, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3,
+	0x2110, 0x20a3, 0x0014, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65ef,
+	0x0078, 0x6466, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0004,
+	0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3,
+	0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3,
+	0x0008, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8,
+	0x20a3, 0x0200, 0x0078, 0x6385, 0x20a1, 0x020b, 0x1078, 0x65f8,
+	0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0xa005, 0x0040, 0x649b,
+	0x20a2, 0x0078, 0x649d, 0x20a3, 0x0003, 0x7810, 0x20a2, 0x60c3,
+	0x0008, 0x1078, 0x6c2d, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078,
+	0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800, 0x7818,
+	0x2068, 0x6894, 0xa086, 0x0014, 0x00c0, 0x64ca, 0x6998, 0xa184,
+	0xc000, 0x00c0, 0x64c6, 0xd1ec, 0x0040, 0x64c2, 0x20a3, 0x2100,
+	0x0078, 0x64cc, 0x20a3, 0x0100, 0x0078, 0x64cc, 0x20a3, 0x0400,
+	0x0078, 0x64cc, 0x20a3, 0x0700, 0xa006, 0x20a2, 0x20a2, 0x20a2,
+	0x20a2, 0x20a2, 0x0f7e, 0x2079, 0xa351, 0x7904, 0x0f7f, 0xd1ac,
+	0x00c0, 0x64dc, 0xa085, 0x0020, 0xd1a4, 0x0040, 0x64e1, 0xa085,
+	0x0010, 0x2009, 0xa373, 0x210c, 0xd184, 0x0040, 0x64eb, 0x699c,
+	0xd18c, 0x0040, 0x64ed, 0xa085, 0x0002, 0x027e, 0x2009, 0xa371,
+	0x210c, 0xd1e4, 0x0040, 0x64fb, 0xc0c5, 0xa094, 0x0030, 0xa296,
+	0x0010, 0x0040, 0x6505, 0xd1ec, 0x0040, 0x6505, 0xa094, 0x0030,
+	0xa296, 0x0010, 0x0040, 0x6505, 0xc0bd, 0x027f, 0x20a2, 0x20a2,
+	0x20a2, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1,
+	0x020b, 0x1078, 0x65f8, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3,
+	0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x1078, 0x6c2d, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x0078, 0x62fe,
+	0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x1078, 0x6c2d,
+	0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x1078,
+	0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3,
+	0x0000, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x027e, 0x037e,
+	0x047e, 0x2019, 0x3200, 0x2021, 0x0800, 0x0078, 0x656e, 0x027e,
+	0x037e, 0x047e, 0x2019, 0x2200, 0x2021, 0x0100, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e,
+	0x00c0, 0x6581, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, 0x0078,
+	0x65b6, 0xa286, 0x007f, 0x00c0, 0x658d, 0x0d7e, 0xa385, 0x00ff,
+	0x20a2, 0x20a3, 0xfffd, 0x0078, 0x65a4, 0xd2bc, 0x0040, 0x65ac,
+	0xa286, 0x0080, 0x0d7e, 0x00c0, 0x659c, 0xa385, 0x00ff, 0x20a2,
+	0x20a3, 0xfffc, 0x0078, 0x65a4, 0xa2e8, 0xa434, 0x2d6c, 0x6810,
+	0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68,
+	0x2da6, 0x0d7f, 0x0078, 0x65ba, 0x0d7e, 0xa2e8, 0xa434, 0x2d6c,
+	0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000,
+	0x6230, 0x22a2, 0xa485, 0x0029, 0x20a2, 0x047f, 0x037f, 0x20a3,
+	0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x20a3,
+	0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x027e,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a3, 0x02ff, 0x2011, 0xfffc,
+	0x22a2, 0x0d7e, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f,
+	0x20a3, 0x2029, 0x20a3, 0x0000, 0x0078, 0x65c1, 0x20a3, 0x0100,
+	0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3, 0x0000, 0x007c, 0x027e,
+	0x037e, 0x047e, 0x2019, 0x3300, 0x2021, 0x0800, 0x0078, 0x65ff,
+	0x027e, 0x037e, 0x047e, 0x2019, 0x2300, 0x2021, 0x0100, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092,
+	0x007e, 0x0048, 0x661c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810,
+	0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68,
+	0x2da6, 0x0d7f, 0x0078, 0x662a, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c,
+	0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000,
+	0x6230, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3, 0x0000, 0x047f,
+	0x037f, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2,
+	0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0c7e,
+	0x0f7e, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a, 0x008c,
+	0x10c8, 0x1328, 0x6118, 0x2178, 0x79a0, 0xd1bc, 0x0040, 0x665d,
+	0x7900, 0xd1f4, 0x0040, 0x6659, 0x7914, 0xa18c, 0x00ff, 0x0078,
+	0x6662, 0x2009, 0x0000, 0x0078, 0x6662, 0xa1f8, 0x293f, 0x2f0c,
+	0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a, 0xa082, 0x0085,
+	0x1079, 0x666d, 0x0f7f, 0x0c7f, 0x007c, 0x6676, 0x6681, 0x669c,
+	0x6674, 0x6674, 0x6674, 0x6676, 0x1078, 0x1328, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x66af, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f,
+	0x007c, 0x147e, 0x20a1, 0x020b, 0x1078, 0x66e3, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c,
+	0x1078, 0x6c2d, 0x147f, 0x007c, 0x147e, 0x20a1, 0x020b, 0x1078,
+	0x6724, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0004, 0x1078, 0x6c2d, 0x147f, 0x007c, 0x027e,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004,
+	0xa092, 0x007e, 0x0048, 0x66ce, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c,
+	0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x66dd, 0x0d7e, 0xa0e8,
+	0xa434, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2, 0x6814, 0x20a2,
+	0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0009, 0x20a3,
+	0x0000, 0x0078, 0x65c1, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048, 0x6702,
+	0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8400, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f,
+	0x0078, 0x6711, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085,
+	0x8400, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230,
+	0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2,
+	0x20a3, 0x0000, 0x7a08, 0x22a2, 0x7a10, 0x22a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x027f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa092, 0x007e, 0x0048,
+	0x6743, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x8500,
+	0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6,
+	0x0d7f, 0x0078, 0x6752, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810,
+	0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000,
+	0x6230, 0x22a2, 0x20a3, 0x0099, 0x20a3, 0x0000, 0x0078, 0x6715,
+	0x0c7e, 0x0f7e, 0x2c78, 0x7804, 0xa08a, 0x0040, 0x1048, 0x1328,
+	0xa08a, 0x0053, 0x10c8, 0x1328, 0x7918, 0x2160, 0x61a0, 0xd1bc,
+	0x0040, 0x6777, 0x6100, 0xd1f4, 0x0040, 0x6773, 0x6114, 0xa18c,
+	0x00ff, 0x0078, 0x677c, 0x2009, 0x0000, 0x0078, 0x677c, 0xa1e0,
+	0x293f, 0x2c0c, 0xa18c, 0x00ff, 0x2061, 0x0100, 0x619a, 0xa082,
+	0x0040, 0x1079, 0x6786, 0x0f7f, 0x0c7f, 0x007c, 0x679b, 0x68a9,
+	0x684a, 0x6a59, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799, 0x6799,
+	0x6799, 0x6f5e, 0x6f6f, 0x6f80, 0x6f91, 0x6799, 0x748e, 0x6799,
+	0x6f4d, 0x1078, 0x1328, 0x0d7e, 0x157e, 0x147e, 0x780b, 0xffff,
+	0x20a1, 0x020b, 0x1078, 0x6806, 0x7910, 0x2168, 0x6948, 0x7922,
+	0x21a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x694c, 0xa184, 0x000f,
+	0x00c0, 0x67b6, 0x2001, 0x0005, 0x0078, 0x67c0, 0xd184, 0x0040,
+	0x67bd, 0x2001, 0x0004, 0x0078, 0x67c0, 0xa084, 0x0006, 0x8004,
+	0x017e, 0x2008, 0x7830, 0xa084, 0x00ff, 0x8007, 0xa105, 0x017f,
+	0x20a2, 0xd1ac, 0x0040, 0x67d0, 0x20a3, 0x0002, 0x0078, 0x67dc,
+	0xd1b4, 0x0040, 0x67d7, 0x20a3, 0x0001, 0x0078, 0x67dc, 0x20a3,
+	0x0000, 0x2230, 0x0078, 0x67de, 0x6a80, 0x6e7c, 0x20a9, 0x0008,
+	0xad80, 0x0017, 0x200c, 0x810f, 0x21a2, 0x8000, 0x00f0, 0x67e2,
+	0x22a2, 0x26a2, 0x60c3, 0x0020, 0x20e1, 0x9080, 0x6014, 0xa084,
+	0x0004, 0xa085, 0x0009, 0x6016, 0x2001, 0xa5c7, 0x2003, 0x07d0,
+	0x2001, 0xa5c6, 0x2003, 0x0009, 0x2001, 0xa5cc, 0x2003, 0x0002,
+	0x1078, 0x157e, 0x147f, 0x157f, 0x0d7f, 0x007c, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294,
+	0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc,
+	0x0040, 0x682c, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085,
+	0x0600, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68,
+	0x2da6, 0x0d7f, 0x0078, 0x683b, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c,
+	0x6810, 0xa085, 0x0600, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3,
+	0x0000, 0x6130, 0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2,
+	0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x20a1, 0x020b,
+	0x1078, 0x686a, 0x7810, 0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2,
+	0x6880, 0x20a2, 0x687c, 0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2,
+	0x20a2, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x147f, 0x137f, 0x157f,
+	0x0d7f, 0x007c, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6888, 0x0d7e, 0xa0e8,
+	0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6897,
+	0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2,
+	0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3,
+	0x0889, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000,
+	0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f,
+	0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x7810, 0xa06d, 0x1078,
+	0x488f, 0x0040, 0x68bd, 0x684c, 0xa084, 0x2020, 0xa086, 0x2020,
+	0x00c0, 0x68bd, 0x7824, 0xc0cd, 0x7826, 0x20a1, 0x020b, 0x1078,
+	0x6a12, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810,
+	0xa084, 0xf000, 0x00c0, 0x68d4, 0x7810, 0xa084, 0x0700, 0x8007,
+	0x1079, 0x68dc, 0x0078, 0x68d7, 0xa006, 0x1079, 0x68dc, 0x147f,
+	0x137f, 0x157f, 0x0d7f, 0x007c, 0x68e6, 0x697e, 0x6989, 0x69b3,
+	0x69c7, 0x69e3, 0x69ee, 0x68e4, 0x1078, 0x1328, 0x017e, 0x037e,
+	0x694c, 0xa18c, 0x0003, 0x0040, 0x68f1, 0xa186, 0x0003, 0x00c0,
+	0x6900, 0x6b78, 0x7824, 0xd0cc, 0x0040, 0x68f7, 0xc3e5, 0x23a2,
+	0x6868, 0x20a2, 0x6864, 0x20a2, 0x037f, 0x017f, 0x0078, 0x69be,
+	0xa186, 0x0001, 0x10c0, 0x1328, 0x6b78, 0x7824, 0xd0cc, 0x0040,
+	0x690a, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2,
+	0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384,
+	0x0300, 0x0040, 0x6978, 0xd3c4, 0x0040, 0x6920, 0x687c, 0xa108,
+	0xd3cc, 0x0040, 0x6925, 0x6874, 0xa108, 0x157e, 0x20a9, 0x000d,
+	0xad80, 0x0020, 0x201c, 0x831f, 0x23a2, 0x8000, 0x00f0, 0x692a,
+	0x157f, 0x22a2, 0x22a2, 0x22a2, 0xa184, 0x0003, 0x0040, 0x6978,
+	0x20a1, 0x020b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x007e, 0x7818,
+	0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6958, 0x0d7e, 0xa0e8,
+	0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6967,
+	0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2,
+	0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x007f,
+	0x7b24, 0xd3cc, 0x0040, 0x6970, 0x20a3, 0x0889, 0x0078, 0x6972,
+	0x20a3, 0x0898, 0x20a2, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000,
+	0x61c2, 0x037f, 0x017f, 0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008,
+	0x7824, 0xd0cc, 0x0040, 0x6985, 0xc2e5, 0x22a2, 0xa016, 0x0078,
+	0x69bc, 0x2011, 0x0302, 0x7824, 0xd0cc, 0x0040, 0x6990, 0xc2e5,
+	0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2,
+	0x20a3, 0x0008, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000,
+	0x20a3, 0x0500, 0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3,
+	0x2500, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032,
+	0x1078, 0x6c2d, 0x007c, 0x2011, 0x0028, 0x7824, 0xd0cc, 0x0040,
+	0x69ba, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2,
+	0x22a2, 0x22a2, 0x60c3, 0x0018, 0x1078, 0x6c2d, 0x007c, 0x2011,
+	0x0100, 0x7824, 0xd0cc, 0x0040, 0x69ce, 0xc2e5, 0x22a2, 0xa016,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0008, 0x22a2,
+	0x7834, 0xa084, 0x00ff, 0x20a2, 0x22a2, 0x22a2, 0x60c3, 0x0020,
+	0x1078, 0x6c2d, 0x007c, 0x2011, 0x0008, 0x7824, 0xd0cc, 0x0040,
+	0x69ea, 0xc2e5, 0x22a2, 0xa016, 0x0078, 0x69bc, 0x037e, 0x7b10,
+	0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001, 0x00c0, 0x6a01,
+	0x7824, 0xd0cc, 0x0040, 0x69fd, 0xc2e5, 0x22a2, 0x037f, 0x0078,
+	0x69bc, 0x047e, 0x2021, 0x0800, 0x007e, 0x7824, 0xd0cc, 0x007f,
+	0x0040, 0x6a0b, 0xc4e5, 0x24a2, 0x047f, 0x22a2, 0x20a2, 0x037f,
+	0x0078, 0x69be, 0x027e, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040, 0x6a30, 0x0d7e, 0xa0e8,
+	0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2, 0x6814, 0x20a2,
+	0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x6a3f,
+	0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2,
+	0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x7824,
+	0xd0cc, 0x0040, 0x6a47, 0x20a3, 0x0889, 0x0078, 0x6a49, 0x20a3,
+	0x0898, 0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000,
+	0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x027f,
+	0x007c, 0x0d7e, 0x157e, 0x137e, 0x147e, 0x017e, 0x037e, 0x7810,
+	0xa084, 0x0700, 0x8007, 0x1079, 0x6a6c, 0x037f, 0x017f, 0x147f,
+	0x137f, 0x157f, 0x0d7f, 0x007c, 0x6a74, 0x6a74, 0x6a76, 0x6a74,
+	0x6a74, 0x6a74, 0x6a9b, 0x6a74, 0x1078, 0x1328, 0x7910, 0xa18c,
+	0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003,
+	0x1078, 0x6aa5, 0x0d7e, 0x2069, 0xa351, 0x6804, 0xd0bc, 0x0040,
+	0x6a90, 0x682c, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x0078, 0x6a92,
+	0x20a3, 0x3f00, 0x0d7f, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001,
+	0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x2009, 0x0003, 0x1078,
+	0x6aa5, 0x20a3, 0x7f00, 0x0078, 0x6a93, 0x027e, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004, 0xd0bc, 0x0040,
+	0x6ac3, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810, 0xa085, 0x0100,
+	0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a, 0x2da6, 0x8d68, 0x2da6,
+	0x0d7f, 0x0078, 0x6ad2, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c, 0x6810,
+	0xa085, 0x0100, 0x20a2, 0x6814, 0x20a2, 0x0d7f, 0x20a3, 0x0000,
+	0x6230, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x1078,
+	0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x0c7e,
+	0x057e, 0x047e, 0x037e, 0x2061, 0x0100, 0x2071, 0xa300, 0x6130,
+	0x7818, 0x2068, 0x68a0, 0x2028, 0xd0bc, 0x00c0, 0x6afc, 0x6910,
+	0x6a14, 0x6430, 0x0078, 0x6b00, 0x6910, 0x6a14, 0x7368, 0x746c,
+	0x781c, 0xa086, 0x0006, 0x0040, 0x6b5f, 0xd5bc, 0x0040, 0x6b10,
+	0xa185, 0x0100, 0x6062, 0x6266, 0x636a, 0x646e, 0x0078, 0x6b17,
+	0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x6073,
+	0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086,
+	0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6,
+	0x7008, 0x60ca, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5,
+	0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6b49, 0x6a00, 0xd2f4,
+	0x0040, 0x6b47, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6b49, 0x2011,
+	0x0000, 0x629e, 0x6017, 0x0016, 0x2009, 0x07d0, 0x60c4, 0xa084,
+	0xfff0, 0xa005, 0x0040, 0x6b56, 0x2009, 0x1b58, 0x1078, 0x595f,
+	0x037f, 0x047f, 0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7810,
+	0x2070, 0x704c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0040, 0x6bb7,
+	0xd5bc, 0x0040, 0x6b73, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a,
+	0x646e, 0x0078, 0x6b7a, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b,
+	0x0000, 0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000,
+	0xa084, 0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00,
+	0x6086, 0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080,
+	0x60c6, 0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080,
+	0x7928, 0xa109, 0x792a, 0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af,
+	0x95d5, 0x60d7, 0x0000, 0xa582, 0x0080, 0x0048, 0x6bb2, 0x6a00,
+	0xd2f4, 0x0040, 0x6bb0, 0x6a14, 0xa294, 0x00ff, 0x0078, 0x6bb2,
+	0x2011, 0x0000, 0x629e, 0x6017, 0x0012, 0x0078, 0x6b4c, 0xd5bc,
+	0x0040, 0x6bc2, 0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e,
+	0x0078, 0x6bc9, 0xa185, 0x0700, 0x6062, 0x6266, 0x606b, 0x0000,
+	0x646e, 0x1078, 0x488f, 0x0040, 0x6bdf, 0x0d7e, 0x7810, 0xa06d,
+	0x684c, 0x0d7f, 0xa084, 0x2020, 0xa086, 0x2020, 0x00c0, 0x6bdf,
+	0x7824, 0xc0cd, 0x7826, 0x6073, 0x0889, 0x0078, 0x6be1, 0x6073,
+	0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086, 0x7808, 0x6082,
+	0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6, 0x7008, 0x60ca,
+	0x686c, 0x60ce, 0x60ab, 0x0036, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0xa582, 0x0080, 0x0048, 0x6c0f, 0x6a00, 0xd2f4, 0x0040, 0x6c0d,
+	0x6a14, 0xa294, 0x00ff, 0x0078, 0x6c0f, 0x2011, 0x0000, 0x629e,
+	0x7824, 0xd0cc, 0x0040, 0x6c18, 0x6017, 0x0016, 0x0078, 0x6b4c,
+	0x6017, 0x0012, 0x0078, 0x6b4c, 0x7a18, 0xa280, 0x0023, 0x2014,
+	0x8210, 0xa294, 0x00ff, 0x2202, 0x8217, 0x007c, 0x0d7e, 0x2069,
+	0xa5ab, 0x6843, 0x0001, 0x0d7f, 0x007c, 0x20e1, 0x9080, 0x60a3,
+	0x0056, 0x60a7, 0x9575, 0x1078, 0x6c38, 0x1078, 0x594f, 0x007c,
+	0x007e, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009, 0x6016, 0x007f,
+	0x007c, 0x007e, 0x0c7e, 0x2061, 0x0100, 0x6014, 0xa084, 0x0004,
+	0xa085, 0x0008, 0x6016, 0x0c7f, 0x007f, 0x007c, 0x0c7e, 0x0d7e,
+	0x017e, 0x027e, 0x2061, 0x0100, 0x2069, 0x0140, 0x6904, 0xa194,
+	0x4000, 0x0040, 0x6c89, 0x1078, 0x6c41, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x0c7e, 0x2061, 0xa5ab, 0x6128, 0xa192, 0x00c8, 0x00c8,
+	0x6c76, 0x8108, 0x612a, 0x6124, 0x0c7f, 0x81ff, 0x0040, 0x6c84,
+	0x1078, 0x594f, 0x1078, 0x6c38, 0x0078, 0x6c84, 0x6124, 0xa1e5,
+	0x0000, 0x0040, 0x6c81, 0x1078, 0xa241, 0x2009, 0x0014, 0x1078,
+	0x756c, 0x0c7f, 0x0078, 0x6c84, 0x027f, 0x017f, 0x0d7f, 0x0c7f,
+	0x007c, 0x2001, 0xa5c7, 0x2004, 0xa005, 0x00c0, 0x6c84, 0x0c7e,
+	0x2061, 0xa5ab, 0x6128, 0xa192, 0x0003, 0x00c8, 0x6c76, 0x8108,
+	0x612a, 0x0c7f, 0x1078, 0x594f, 0x1078, 0x4171, 0x0078, 0x6c84,
+	0x0c7e, 0x0d7e, 0x0e7e, 0x017e, 0x027e, 0x1078, 0x5967, 0x2071,
+	0xa5ab, 0x713c, 0x81ff, 0x0040, 0x6cca, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x6904, 0xa194, 0x4000, 0x0040, 0x6cd0, 0x6803, 0x1000,
+	0x6803, 0x0000, 0x037e, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x037f,
+	0x713c, 0x2160, 0x1078, 0xa241, 0x2009, 0x004a, 0x1078, 0x756c,
+	0x0078, 0x6cca, 0x027f, 0x017f, 0x0e7f, 0x0d7f, 0x0c7f, 0x007c,
+	0x0078, 0x6cba, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x057e, 0x047e,
+	0x007e, 0x127e, 0x2091, 0x8000, 0x6018, 0x2068, 0x6ca0, 0x2071,
+	0xa5ab, 0x7018, 0x2068, 0x8dff, 0x0040, 0x6cfc, 0x68a0, 0xa406,
+	0x0040, 0x6cee, 0x6854, 0x2068, 0x0078, 0x6ce3, 0x6010, 0x2060,
+	0x643c, 0x6540, 0x6e48, 0x2d60, 0x1078, 0x466a, 0x0040, 0x6cfc,
+	0x1078, 0x7045, 0xa085, 0x0001, 0x127f, 0x007f, 0x047f, 0x057f,
+	0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x6567, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c,
+	0xa086, 0x0004, 0x00c0, 0x6d17, 0x6098, 0x0078, 0x6d18, 0x6030,
+	0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006,
+	0x20a2, 0x00f0, 0x6d20, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x1078,
+	0x6c2d, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6567,
+	0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2,
+	0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c, 0x157e,
+	0x147e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0200, 0x20a3,
+	0x0000, 0x20a9, 0x0006, 0x2011, 0xa340, 0x2019, 0xa341, 0x23a6,
+	0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x00f0, 0x6d4f, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x1078, 0x6c2d, 0x147f,
+	0x157f, 0x007c, 0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b,
+	0x1078, 0x65cf, 0x1078, 0x65e6, 0x7810, 0xa080, 0x0000, 0x2004,
+	0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6,
+	0xa080, 0x0004, 0x8003, 0x60c2, 0x1078, 0x6c2d, 0x027f, 0x017f,
+	0x147f, 0x157f, 0x007c, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078,
+	0x6567, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808,
+	0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x147f, 0x157f, 0x007c,
+	0x157e, 0x147e, 0x017e, 0x027e, 0x20a1, 0x020b, 0x1078, 0x6567,
+	0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808,
+	0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x1078, 0x6c2d,
+	0x027f, 0x017f, 0x147f, 0x157f, 0x007c, 0x0e7e, 0x0c7e, 0x007e,
+	0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x700c, 0x2060, 0x8cff,
+	0x0040, 0x6dd1, 0x1078, 0x8c3b, 0x00c0, 0x6dc8, 0x1078, 0x7a05,
+	0x600c, 0x007e, 0x1078, 0x753d, 0x1078, 0x7045, 0x0c7f, 0x0078,
+	0x6dbf, 0x700f, 0x0000, 0x700b, 0x0000, 0x127f, 0x007f, 0x0c7f,
+	0x0e7f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e,
+	0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079,
+	0x0140, 0x2071, 0xa5ab, 0x7024, 0x2060, 0x8cff, 0x0040, 0x6e2a,
+	0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x595a, 0x2009, 0x0013,
+	0x1078, 0x756c, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0040, 0x6e0d,
+	0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6e1f, 0x7803,
+	0x1000, 0x7803, 0x0000, 0x0078, 0x6e1f, 0xd084, 0x0040, 0x6e14,
+	0x6827, 0x0001, 0x0078, 0x6e16, 0x00f0, 0x6dfc, 0x7804, 0xa084,
+	0x1000, 0x0040, 0x6e1f, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824,
+	0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f,
+	0x127f, 0x007c, 0x2001, 0xa300, 0x2004, 0xa096, 0x0001, 0x0040,
+	0x6e62, 0xa096, 0x0004, 0x0040, 0x6e62, 0x6817, 0x0008, 0x68c3,
+	0x0000, 0x2011, 0x4129, 0x1078, 0x58d4, 0x20a9, 0x01f4, 0x6824,
+	0xd094, 0x0040, 0x6e50, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000,
+	0x0040, 0x6e62, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0x6e62,
+	0xd084, 0x0040, 0x6e57, 0x6827, 0x0001, 0x0078, 0x6e59, 0x00f0,
+	0x6e3f, 0x7804, 0xa084, 0x1000, 0x0040, 0x6e62, 0x7803, 0x0100,
+	0x7803, 0x0000, 0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f,
+	0x0f7f, 0x157f, 0x127f, 0x007c, 0x127e, 0x157e, 0x0f7e, 0x0e7e,
+	0x0d7e, 0x0c7e, 0x027e, 0x017e, 0x007e, 0x2091, 0x8000, 0x2069,
+	0x0100, 0x2079, 0x0140, 0x2071, 0xa5ab, 0x703c, 0x2060, 0x8cff,
+	0x0040, 0x6ee8, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x00c0,
+	0x6e86, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x1078, 0x5967, 0x1078,
+	0x1f31, 0x047e, 0x057e, 0x2009, 0x017f, 0x212c, 0x200b, 0x00a5,
+	0x2021, 0x0169, 0x2404, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0,
+	0x6eb7, 0x68c7, 0x0000, 0x68cb, 0x0008, 0x0e7e, 0x0f7e, 0x2079,
+	0x0020, 0x2071, 0xa602, 0x6814, 0xa084, 0x0004, 0xa085, 0x0012,
+	0x6816, 0x7803, 0x0008, 0x7003, 0x0000, 0x0f7f, 0x0e7f, 0x250a,
+	0x057f, 0x047f, 0xa39d, 0x0000, 0x00c0, 0x6ec2, 0x2009, 0x0049,
+	0x1078, 0x756c, 0x20a9, 0x03e8, 0x6824, 0xd094, 0x0040, 0x6ed5,
+	0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x0040, 0x6ee7, 0x7803,
+	0x1000, 0x7803, 0x0000, 0x0078, 0x6ee7, 0xd08c, 0x0040, 0x6edc,
+	0x6827, 0x0002, 0x0078, 0x6ede, 0x00f0, 0x6ec4, 0x7804, 0xa084,
+	0x1000, 0x0040, 0x6ee7, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824,
+	0x007f, 0x017f, 0x027f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x157f,
+	0x127f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000, 0x2069, 0xa5ab,
+	0x6a06, 0x127f, 0x0d7f, 0x007c, 0x0d7e, 0x127e, 0x2091, 0x8000,
+	0x2069, 0xa5ab, 0x6a32, 0x127f, 0x0d7f, 0x007c, 0x0f7e, 0x0e7e,
+	0x0c7e, 0x067e, 0x007e, 0x127e, 0x2071, 0xa5ab, 0x7614, 0x2660,
+	0x2678, 0x2091, 0x8000, 0x8cff, 0x0040, 0x6f46, 0x601c, 0xa206,
+	0x00c0, 0x6f41, 0x7014, 0xac36, 0x00c0, 0x6f20, 0x660c, 0x7616,
+	0x7010, 0xac36, 0x00c0, 0x6f2e, 0x2c00, 0xaf36, 0x0040, 0x6f2c,
+	0x2f00, 0x7012, 0x0078, 0x6f2e, 0x7013, 0x0000, 0x660c, 0x067e,
+	0x2c00, 0xaf06, 0x0040, 0x6f37, 0x7e0e, 0x0078, 0x6f38, 0x2678,
+	0x600f, 0x0000, 0x1078, 0x8c01, 0x1078, 0x7045, 0x0c7f, 0x0078,
+	0x6f13, 0x2c78, 0x600c, 0x2060, 0x0078, 0x6f13, 0x127f, 0x007f,
+	0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0x157e, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2, 0x20a2,
+	0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0078, 0x6fa0, 0x157e, 0x147e,
+	0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000, 0x0078, 0x6fa0, 0x157e,
+	0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000, 0x0078, 0x6fa0,
+	0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810, 0x20a2,
+	0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400, 0x0078,
+	0x6fa0, 0x157e, 0x147e, 0x20a1, 0x020b, 0x1078, 0x6806, 0x7810,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200,
+	0x1078, 0x7050, 0x60c3, 0x0020, 0x1078, 0x6c2d, 0x147f, 0x157f,
+	0x007c, 0x127e, 0x0c7e, 0x2091, 0x8000, 0x2061, 0x0100, 0x6120,
+	0xd1b4, 0x00c0, 0x6fb8, 0xd1bc, 0x00c0, 0x7002, 0x0078, 0x7042,
+	0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e, 0x0d7e, 0x2069,
+	0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804, 0xa084, 0x4000,
+	0x0040, 0x6ff9, 0x6020, 0xd0b4, 0x0040, 0x6ff9, 0x6024, 0xd094,
+	0x00c0, 0x6ff9, 0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0,
+	0x6ff9, 0x00f0, 0x6fc5, 0x027e, 0x6198, 0xa18c, 0x00ff, 0x8107,
+	0x6130, 0xa18c, 0x00ff, 0xa10d, 0x6088, 0x628c, 0x618e, 0x608b,
+	0xbc91, 0x6043, 0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6024,
+	0xd094, 0x00c0, 0x6ff8, 0x6a04, 0xa294, 0x4000, 0x00c0, 0x6fef,
+	0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f, 0x200b, 0x0000,
+	0x0078, 0x7042, 0x2009, 0x017f, 0x200b, 0x00a1, 0x157e, 0x007e,
+	0x0d7e, 0x2069, 0x0140, 0x20a9, 0x001e, 0x2009, 0x0169, 0x6804,
+	0xa084, 0x4000, 0x0040, 0x703b, 0x6020, 0xd0bc, 0x0040, 0x703b,
+	0x2104, 0xa084, 0x000f, 0xa086, 0x0004, 0x00c0, 0x703b, 0x00f0,
+	0x700f, 0x027e, 0x6164, 0xa18c, 0x00ff, 0x8107, 0x6130, 0xa18c,
+	0x00ff, 0xa10d, 0x6088, 0x628c, 0x608b, 0xbc91, 0x618e, 0x6043,
+	0x0001, 0x6043, 0x0000, 0x608a, 0x628e, 0x6a04, 0xa294, 0x4000,
+	0x00c0, 0x7035, 0x027f, 0x0d7f, 0x007f, 0x157f, 0x2009, 0x017f,
+	0x200b, 0x0000, 0x0c7f, 0x127f, 0x007c, 0x0e7e, 0x2071, 0xa5ab,
+	0x7020, 0xa005, 0x0040, 0x704e, 0x8001, 0x7022, 0x0e7f, 0x007c,
+	0x20a9, 0x0008, 0x20a2, 0x00f0, 0x7052, 0x20a2, 0x20a2, 0x007c,
+	0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x077e, 0x067e, 0x007e, 0x127e,
+	0x2091, 0x8000, 0x2071, 0xa5ab, 0x7614, 0x2660, 0x2678, 0x2039,
+	0x0001, 0x87ff, 0x0040, 0x70f4, 0x8cff, 0x0040, 0x70f4, 0x601c,
+	0xa086, 0x0006, 0x00c0, 0x70ef, 0x88ff, 0x0040, 0x707f, 0x2800,
+	0xac06, 0x00c0, 0x70ef, 0x2039, 0x0000, 0x0078, 0x708a, 0x6018,
+	0xa206, 0x00c0, 0x70ef, 0x85ff, 0x0040, 0x708a, 0x6020, 0xa106,
+	0x00c0, 0x70ef, 0x7024, 0xac06, 0x00c0, 0x70ba, 0x2069, 0x0100,
+	0x68c0, 0xa005, 0x0040, 0x70b5, 0x1078, 0x595a, 0x6817, 0x0008,
+	0x68c3, 0x0000, 0x1078, 0x7188, 0x7027, 0x0000, 0x037e, 0x2069,
+	0x0140, 0x6b04, 0xa384, 0x1000, 0x0040, 0x70aa, 0x6803, 0x0100,
+	0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0040, 0x70b2,
+	0x6827, 0x0001, 0x037f, 0x0078, 0x70ba, 0x6003, 0x0009, 0x630a,
+	0x0078, 0x70ef, 0x7014, 0xac36, 0x00c0, 0x70c0, 0x660c, 0x7616,
+	0x7010, 0xac36, 0x00c0, 0x70ce, 0x2c00, 0xaf36, 0x0040, 0x70cc,
+	0x2f00, 0x7012, 0x0078, 0x70ce, 0x7013, 0x0000, 0x660c, 0x067e,
+	0x2c00, 0xaf06, 0x0040, 0x70d7, 0x7e0e, 0x0078, 0x70d8, 0x2678,
+	0x89ff, 0x00c0, 0x70e7, 0x600f, 0x0000, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x70e5, 0x1078, 0x9e70, 0x1078, 0x8c01, 0x1078,
+	0x7045, 0x88ff, 0x00c0, 0x70fe, 0x0c7f, 0x0078, 0x7069, 0x2c78,
+	0x600c, 0x2060, 0x0078, 0x7069, 0xa006, 0x127f, 0x007f, 0x067f,
+	0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f, 0x007c, 0x6017, 0x0000,
+	0x0c7f, 0xa8c5, 0x0001, 0x0078, 0x70f5, 0x0f7e, 0x0e7e, 0x0d7e,
+	0x0c7e, 0x067e, 0x027e, 0x007e, 0x127e, 0x2091, 0x8000, 0x2071,
+	0xa5ab, 0x7638, 0x2660, 0x2678, 0x8cff, 0x0040, 0x7177, 0x601c,
+	0xa086, 0x0006, 0x00c0, 0x7172, 0x87ff, 0x0040, 0x7125, 0x2700,
+	0xac06, 0x00c0, 0x7172, 0x0078, 0x7130, 0x6018, 0xa206, 0x00c0,
+	0x7172, 0x85ff, 0x0040, 0x7130, 0x6020, 0xa106, 0x00c0, 0x7172,
+	0x703c, 0xac06, 0x00c0, 0x7142, 0x037e, 0x2019, 0x0001, 0x1078,
+	0x6e6c, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000, 0x7047,
+	0x0000, 0x037f, 0x7038, 0xac36, 0x00c0, 0x7148, 0x660c, 0x763a,
+	0x7034, 0xac36, 0x00c0, 0x7156, 0x2c00, 0xaf36, 0x0040, 0x7154,
+	0x2f00, 0x7036, 0x0078, 0x7156, 0x7037, 0x0000, 0x660c, 0x067e,
+	0x2c00, 0xaf06, 0x0040, 0x715f, 0x7e0e, 0x0078, 0x7160, 0x2678,
+	0x600f, 0x0000, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x716a,
+	0x1078, 0x9e70, 0x1078, 0x8c01, 0x87ff, 0x00c0, 0x7181, 0x0c7f,
+	0x0078, 0x7114, 0x2c78, 0x600c, 0x2060, 0x0078, 0x7114, 0xa006,
+	0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x007c, 0x6017, 0x0000, 0x0c7f, 0xa7bd, 0x0001, 0x0078, 0x7178,
+	0x0e7e, 0x2071, 0xa5ab, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002,
+	0x00c0, 0x7196, 0x7007, 0x0005, 0x0078, 0x7198, 0x7007, 0x0000,
+	0x0e7f, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x067e, 0x027e, 0x007e,
+	0x127e, 0x2091, 0x8000, 0x2071, 0xa5ab, 0x2c10, 0x7638, 0x2660,
+	0x2678, 0x8cff, 0x0040, 0x71d8, 0x2200, 0xac06, 0x00c0, 0x71d3,
+	0x7038, 0xac36, 0x00c0, 0x71b6, 0x660c, 0x763a, 0x7034, 0xac36,
+	0x00c0, 0x71c4, 0x2c00, 0xaf36, 0x0040, 0x71c2, 0x2f00, 0x7036,
+	0x0078, 0x71c4, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0040,
+	0x71cc, 0x7e0e, 0x0078, 0x71cd, 0x2678, 0x600f, 0x0000, 0xa085,
+	0x0001, 0x0078, 0x71d8, 0x2c78, 0x600c, 0x2060, 0x0078, 0x71a9,
+	0x127f, 0x007f, 0x027f, 0x067f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c,
+	0x0f7e, 0x0e7e, 0x0d7e, 0x0c7e, 0x067e, 0x007e, 0x127e, 0x2091,
+	0x8000, 0x2071, 0xa5ab, 0x760c, 0x2660, 0x2678, 0x8cff, 0x0040,
+	0x7279, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x00c0, 0x7274,
+	0x7024, 0xac06, 0x00c0, 0x721f, 0x2069, 0x0100, 0x68c0, 0xa005,
+	0x0040, 0x724d, 0x1078, 0x6c41, 0x68c3, 0x0000, 0x1078, 0x7188,
+	0x7027, 0x0000, 0x037e, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000,
+	0x0040, 0x7216, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100,
+	0x6824, 0xd084, 0x0040, 0x721e, 0x6827, 0x0001, 0x037f, 0x700c,
+	0xac36, 0x00c0, 0x7225, 0x660c, 0x760e, 0x7008, 0xac36, 0x00c0,
+	0x7233, 0x2c00, 0xaf36, 0x0040, 0x7231, 0x2f00, 0x700a, 0x0078,
+	0x7233, 0x700b, 0x0000, 0x660c, 0x067e, 0x2c00, 0xaf06, 0x0040,
+	0x723c, 0x7e0e, 0x0078, 0x723d, 0x2678, 0x600f, 0x0000, 0x1078,
+	0x8c27, 0x00c0, 0x7251, 0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0,
+	0x726d, 0x1078, 0x7a05, 0x0078, 0x726d, 0x1078, 0x7188, 0x0078,
+	0x721f, 0x1078, 0x8c3b, 0x00c0, 0x7259, 0x1078, 0x7a05, 0x0078,
+	0x726d, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x726d, 0x601c,
+	0xa086, 0x0003, 0x00c0, 0x7281, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x1078, 0x8c01, 0x1078,
+	0x7045, 0x0c7f, 0x0078, 0x71ee, 0x2c78, 0x600c, 0x2060, 0x0078,
+	0x71ee, 0x127f, 0x007f, 0x067f, 0x0c7f, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x007c, 0x601c, 0xa086, 0x0006, 0x00c0, 0x726d, 0x1078, 0x9e70,
+	0x0078, 0x726d, 0x037e, 0x157e, 0x137e, 0x147e, 0x3908, 0xa006,
+	0xa190, 0x0020, 0x221c, 0xa39e, 0x260c, 0x00c0, 0x729b, 0x8210,
+	0x8000, 0x0078, 0x7292, 0xa005, 0x0040, 0x72a7, 0x20a9, 0x0020,
+	0x2198, 0x8211, 0xa282, 0x0020, 0x20c8, 0x20a0, 0x53a3, 0x147f,
+	0x137f, 0x157f, 0x037f, 0x007c, 0x0d7e, 0x20a1, 0x020b, 0x1078,
+	0x65f8, 0x20a3, 0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x2099, 0xa5a3, 0x20a9, 0x0004, 0x53a6,
+	0x20a3, 0x0004, 0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x1078, 0x6c2d, 0x0d7f, 0x007c, 0x20a1, 0x020b, 0x1078, 0x65f8,
+	0x20a3, 0x0214, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084,
+	0xff00, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0018, 0x1078, 0x6c2d,
+	0x007c, 0x0d7e, 0x017e, 0x2f68, 0x2009, 0x0035, 0x1078, 0x8ef5,
+	0x00c0, 0x7361, 0x20a1, 0x020b, 0x1078, 0x6567, 0x20a3, 0x1300,
+	0x20a3, 0x0000, 0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0040,
+	0x733d, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x00c0,
+	0x7317, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0078, 0x7352, 0xa286,
+	0x007f, 0x00c0, 0x7321, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0078,
+	0x7352, 0xd2bc, 0x0040, 0x7337, 0xa286, 0x0080, 0x00c0, 0x732e,
+	0x20a3, 0x00ff, 0x20a3, 0xfffc, 0x0078, 0x7352, 0xa2e8, 0xa434,
+	0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2, 0x0078, 0x7352, 0x20a3,
+	0x0000, 0x6098, 0x20a2, 0x0078, 0x7352, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa082, 0x007e, 0x0048, 0x734e, 0x0d7e, 0x2069, 0xa31a,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x7352, 0x20a3, 0x0000,
+	0x6030, 0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x000c, 0x1078, 0x6c2d, 0x017f, 0x0d7f,
+	0x007c, 0x7817, 0x0001, 0x7803, 0x0006, 0x017f, 0x0d7f, 0x007c,
+	0x0d7e, 0x027e, 0x7928, 0x2168, 0x691c, 0xa186, 0x0006, 0x0040,
+	0x738a, 0xa186, 0x0003, 0x0040, 0x73e5, 0xa186, 0x0005, 0x0040,
+	0x73c8, 0xa186, 0x0004, 0x0040, 0x73b8, 0xa186, 0x0008, 0x0040,
+	0x73d2, 0x7807, 0x0037, 0x7813, 0x1700, 0x1078, 0x7450, 0x027f,
+	0x0d7f, 0x007c, 0x1078, 0x740d, 0x2009, 0x4000, 0x6800, 0x0079,
+	0x7391, 0x73a4, 0x73b2, 0x73a6, 0x73b2, 0x73ad, 0x73a4, 0x73a4,
+	0x73b2, 0x73b2, 0x73b2, 0x73b2, 0x73a4, 0x73a4, 0x73a4, 0x73a4,
+	0x73a4, 0x73b2, 0x73a4, 0x73b2, 0x1078, 0x1328, 0x6824, 0xd0e4,
+	0x0040, 0x73ad, 0xd0cc, 0x0040, 0x73b0, 0xa00e, 0x0078, 0x73b2,
+	0x2009, 0x2000, 0x6828, 0x20a2, 0x682c, 0x20a2, 0x0078, 0x7403,
+	0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0x6a00, 0xa286, 0x0002, 0x00c0, 0x73c6, 0xa00e, 0x0078, 0x7403,
+	0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000,
+	0x0078, 0x7403, 0x1078, 0x740d, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x2009, 0x4000, 0xa286, 0x0005, 0x0040, 0x73e2, 0xa286, 0x0002,
+	0x00c0, 0x73e3, 0xa00e, 0x0078, 0x7403, 0x1078, 0x740d, 0x6810,
+	0x2068, 0x697c, 0x6810, 0xa112, 0x6980, 0x6814, 0xa103, 0x20a2,
+	0x22a2, 0x7928, 0xa180, 0x0000, 0x2004, 0xa08e, 0x0002, 0x0040,
+	0x7401, 0xa08e, 0x0004, 0x0040, 0x7401, 0x2009, 0x4000, 0x0078,
+	0x7403, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000, 0x60c3, 0x0018,
+	0x1078, 0x6c2d, 0x027f, 0x0d7f, 0x007c, 0x037e, 0x047e, 0x057e,
+	0x067e, 0x20a1, 0x020b, 0x1078, 0x65f8, 0xa006, 0x20a3, 0x0200,
+	0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xa092, 0x007e, 0x0048, 0x7433, 0x0d7e, 0x2069, 0xa31a,
+	0x2d2c, 0x8d68, 0x2d34, 0xa0e8, 0xa434, 0x2d6c, 0x6b10, 0x6c14,
+	0x0d7f, 0x0078, 0x7439, 0x2019, 0x0000, 0x6498, 0x2029, 0x0000,
+	0x6630, 0x7828, 0xa080, 0x0007, 0x2004, 0xa086, 0x0003, 0x00c0,
+	0x7447, 0x25a2, 0x26a2, 0x23a2, 0x24a2, 0x0078, 0x744b, 0x23a2,
+	0x24a2, 0x25a2, 0x26a2, 0x067f, 0x057f, 0x047f, 0x037f, 0x007c,
+	0x20a1, 0x020b, 0x1078, 0x65f8, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d,
+	0x007c, 0x20a1, 0x020b, 0x1078, 0x655e, 0x20a3, 0x1400, 0x20a3,
+	0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x7828, 0x20a2, 0x782c,
+	0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007, 0x20a2, 0x20a3, 0x0000,
+	0x60c3, 0x0010, 0x1078, 0x6c2d, 0x007c, 0x20a1, 0x020b, 0x1078,
+	0x65ef, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828, 0x20a2, 0x7810,
+	0x20a2, 0x60c3, 0x0008, 0x1078, 0x6c2d, 0x007c, 0x147e, 0x20a1,
+	0x020b, 0x1078, 0x7499, 0x60c3, 0x0000, 0x1078, 0x6c2d, 0x147f,
+	0x007c, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0xd0bc, 0x0040, 0x74b6, 0x0d7e, 0xa0e8, 0xa434, 0x2d6c,
+	0x6810, 0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xa31a,
+	0x2da6, 0x8d68, 0x2da6, 0x0d7f, 0x0078, 0x74be, 0x20a3, 0x0300,
+	0x6298, 0x22a2, 0x20a3, 0x0000, 0x6230, 0x22a2, 0x20a3, 0x0819,
+	0x20a3, 0x0000, 0x1078, 0x6c1c, 0x22a2, 0x20a3, 0x0000, 0x2fa2,
+	0x7a08, 0x22a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x007c, 0x2061,
+	0xaa00, 0x2a70, 0x7060, 0x7046, 0x704b, 0xaa00, 0x007c, 0x0e7e,
+	0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582, 0x0010,
+	0x0048, 0x7509, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0040,
+	0x74f5, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x74f1, 0x0078,
+	0x74e4, 0x2061, 0xaa00, 0x0078, 0x74e4, 0x6003, 0x0008, 0x8529,
+	0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x7505, 0x754a,
+	0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00, 0x0078,
+	0x7500, 0xa006, 0x0078, 0x7502, 0x0e7e, 0x2071, 0xa300, 0x7544,
+	0xa582, 0x0010, 0x0048, 0x753a, 0x7048, 0x2060, 0x6000, 0xa086,
+	0x0000, 0x0040, 0x7527, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8,
+	0x7523, 0x0078, 0x7516, 0x2061, 0xaa00, 0x0078, 0x7516, 0x6003,
+	0x0008, 0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8,
+	0x7536, 0x754a, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x704b, 0xaa00,
+	0x0078, 0x7532, 0xa006, 0x0078, 0x7534, 0xac82, 0xaa00, 0x1048,
+	0x1328, 0x2001, 0xa315, 0x2004, 0xac02, 0x10c8, 0x1328, 0xa006,
+	0x6006, 0x600a, 0x600e, 0x6012, 0x6016, 0x601a, 0x601f, 0x0000,
+	0x6003, 0x0000, 0x6022, 0x6026, 0x602a, 0x602e, 0x6032, 0x6036,
+	0x603a, 0x603e, 0x2061, 0xa300, 0x6044, 0x8000, 0x6046, 0xa086,
+	0x0001, 0x0040, 0x7564, 0x007c, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x6109, 0x127f, 0x0078, 0x7563, 0x601c, 0xa084, 0x000f, 0x0079,
+	0x7571, 0x757a, 0x758b, 0x75a7, 0x75c3, 0x8f2d, 0x8f49, 0x8f65,
+	0x757a, 0x758b, 0xa186, 0x0013, 0x00c0, 0x7583, 0x1078, 0x6010,
+	0x1078, 0x6109, 0x007c, 0xa18e, 0x0047, 0x00c0, 0x758a, 0xa016,
+	0x1078, 0x15ec, 0x007c, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8,
+	0x1328, 0x1079, 0x7595, 0x067f, 0x007c, 0x75a5, 0x7891, 0x7a34,
+	0x75a5, 0x7ab8, 0x75df, 0x75a5, 0x75a5, 0x7823, 0x7e6d, 0x75a5,
+	0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x75a5, 0x1078, 0x1328, 0x067e,
+	0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079, 0x75b1, 0x067f,
+	0x007c, 0x75c1, 0x8522, 0x75c1, 0x75c1, 0x75c1, 0x75c1, 0x75c1,
+	0x75c1, 0x84c5, 0x86a8, 0x75c1, 0x8552, 0x85d8, 0x8552, 0x85d8,
+	0x75c1, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8,
+	0x1328, 0x1079, 0x75cd, 0x067f, 0x007c, 0x75dd, 0x7eb4, 0x7f81,
+	0x80c6, 0x8242, 0x75dd, 0x75dd, 0x75dd, 0x7e8d, 0x846d, 0x8471,
+	0x75dd, 0x75dd, 0x75dd, 0x75dd, 0x84a1, 0x1078, 0x1328, 0xa1b6,
+	0x0015, 0x00c0, 0x75e7, 0x1078, 0x753d, 0x0078, 0x75ed, 0xa1b6,
+	0x0016, 0x10c0, 0x1328, 0x1078, 0x753d, 0x007c, 0x20a9, 0x000e,
+	0x2e98, 0x6010, 0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420,
+	0x9398, 0x94a0, 0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002,
+	0xa5a8, 0x0002, 0xa398, 0x0002, 0xa4a0, 0x0002, 0x00f0, 0x75fc,
+	0x0e7e, 0x1078, 0x8a44, 0x0040, 0x7613, 0x6010, 0x2070, 0x7007,
+	0x0000, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c, 0x0d7e,
+	0x037e, 0x7330, 0xa386, 0x0200, 0x00c0, 0x7624, 0x6018, 0x2068,
+	0x6813, 0x00ff, 0x6817, 0xfffd, 0x6010, 0xa005, 0x0040, 0x762e,
+	0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6b32, 0x1078, 0x753d,
+	0x037f, 0x0d7f, 0x007c, 0x017e, 0x20a9, 0x002a, 0xae80, 0x000c,
+	0x2098, 0x6010, 0xa080, 0x0002, 0x20a0, 0x53a3, 0x20a9, 0x002a,
+	0x6010, 0xa080, 0x0001, 0x2004, 0xa080, 0x0002, 0x20a0, 0x53a3,
+	0x0e7e, 0x6010, 0x2004, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078,
+	0x753d, 0x017f, 0x007c, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2c68,
+	0x017e, 0x2009, 0x0035, 0x1078, 0x8ef5, 0x017f, 0x00c0, 0x766f,
+	0x027e, 0x6228, 0x2268, 0x027f, 0x2071, 0xa88c, 0x6b1c, 0xa386,
+	0x0003, 0x0040, 0x7673, 0xa386, 0x0006, 0x0040, 0x7677, 0x1078,
+	0x753d, 0x0078, 0x7679, 0x1078, 0x767c, 0x0078, 0x7679, 0x1078,
+	0x771e, 0x0d7f, 0x0e7f, 0x007c, 0x0f7e, 0x6810, 0x2078, 0xa186,
+	0x0015, 0x0040, 0x7705, 0xa18e, 0x0016, 0x00c0, 0x771c, 0x700c,
+	0xa084, 0xff00, 0xa086, 0x1700, 0x00c0, 0x76e0, 0x8fff, 0x0040,
+	0x771a, 0x6808, 0xa086, 0xffff, 0x00c0, 0x7709, 0x784c, 0xa084,
+	0x0060, 0xa086, 0x0020, 0x00c0, 0x76a7, 0x797c, 0x7810, 0xa106,
+	0x00c0, 0x7709, 0x7980, 0x7814, 0xa106, 0x00c0, 0x7709, 0x1078,
+	0x8bf4, 0x6830, 0x7852, 0x784c, 0xc0dc, 0xc0f4, 0xc0d4, 0x784e,
+	0x027e, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x1078, 0x5a98, 0x7854,
+	0xa20a, 0x0048, 0x76bc, 0x8011, 0x7a56, 0x82ff, 0x027f, 0x00c0,
+	0x76c8, 0x0c7e, 0x2d60, 0x1078, 0x8832, 0x0c7f, 0x0078, 0x771a,
+	0x0c7e, 0x0d7e, 0x2f68, 0x6838, 0xd0fc, 0x00c0, 0x76d3, 0x1078,
+	0x4290, 0x0078, 0x76d5, 0x1078, 0x436e, 0x0d7f, 0x0c7f, 0x00c0,
+	0x7709, 0x0c7e, 0x2d60, 0x1078, 0x753d, 0x0c7f, 0x0078, 0x771a,
+	0x7008, 0xa086, 0x000b, 0x00c0, 0x76fa, 0x6018, 0x200c, 0xc1bc,
+	0x2102, 0x0c7e, 0x2d60, 0x7853, 0x0003, 0x6007, 0x0085, 0x6003,
+	0x000b, 0x601f, 0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f,
+	0x0078, 0x771a, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x7709, 0x2001,
+	0xa5a2, 0x2004, 0x683e, 0x0078, 0x771a, 0x1078, 0x7739, 0x0078,
+	0x771c, 0x8fff, 0x1040, 0x1328, 0x0c7e, 0x0d7e, 0x2d60, 0x2f68,
+	0x684b, 0x0003, 0x1078, 0x8726, 0x1078, 0x8bf4, 0x1078, 0x8c01,
+	0x0d7f, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0xa186, 0x0015,
+	0x00c0, 0x7728, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x7736,
+	0xa18e, 0x0016, 0x00c0, 0x7738, 0x0c7e, 0x2d00, 0x2060, 0x1078,
+	0xa134, 0x1078, 0x5a41, 0x1078, 0x753d, 0x0c7f, 0x1078, 0x753d,
+	0x007c, 0x027e, 0x037e, 0x047e, 0x7228, 0x7c80, 0x7b7c, 0xd2f4,
+	0x0040, 0x7748, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x0078, 0x77ac,
+	0x0c7e, 0x2d60, 0x1078, 0x874a, 0x0c7f, 0x6804, 0xa086, 0x0050,
+	0x00c0, 0x7760, 0x0c7e, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007,
+	0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x77ac,
+	0x6800, 0xa086, 0x000f, 0x0040, 0x7782, 0x8fff, 0x1040, 0x1328,
+	0x6824, 0xd0dc, 0x00c0, 0x7782, 0x6800, 0xa086, 0x0004, 0x00c0,
+	0x7787, 0x784c, 0xd0ac, 0x0040, 0x7787, 0x784c, 0xc0dc, 0xc0f4,
+	0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852, 0x2001, 0x0001, 0x682e,
+	0x0078, 0x77a6, 0x2001, 0x0007, 0x682e, 0x0078, 0x77a6, 0x784c,
+	0xd0b4, 0x00c0, 0x7794, 0xd0ac, 0x0040, 0x7782, 0x784c, 0xd0f4,
+	0x00c0, 0x7782, 0x0078, 0x7775, 0xd2ec, 0x00c0, 0x7782, 0x7024,
+	0xa306, 0x00c0, 0x779f, 0x7020, 0xa406, 0x0040, 0x7782, 0x7020,
+	0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e, 0x1078, 0x8d2b,
+	0x1078, 0x6109, 0x0078, 0x77ae, 0x1078, 0x753d, 0x047f, 0x037f,
+	0x027f, 0x007c, 0x0e7e, 0x0d7e, 0x027e, 0x6034, 0x2068, 0x6a1c,
+	0xa286, 0x0007, 0x0040, 0x7806, 0xa286, 0x0002, 0x0040, 0x7806,
+	0xa286, 0x0000, 0x0040, 0x7806, 0x6808, 0x6338, 0xa306, 0x00c0,
+	0x7806, 0x2071, 0xa88c, 0xa186, 0x0015, 0x0040, 0x7800, 0xa18e,
+	0x0016, 0x00c0, 0x77e8, 0x6030, 0xa084, 0x00ff, 0xa086, 0x0001,
+	0x00c0, 0x77e8, 0x700c, 0xa086, 0x2a00, 0x00c0, 0x77e8, 0x6034,
+	0xa080, 0x0009, 0x200c, 0xc1dd, 0xc1f5, 0x2102, 0x0078, 0x7800,
+	0x0c7e, 0x6034, 0x2060, 0x6010, 0x2068, 0x1078, 0x8a44, 0x1040,
+	0x1328, 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f,
+	0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7f, 0x0078, 0x7806,
+	0x6034, 0x2068, 0x2001, 0xa5a2, 0x2004, 0x683e, 0x1078, 0x753d,
+	0x027f, 0x0d7f, 0x0e7f, 0x007c, 0x0d7e, 0x20a9, 0x000e, 0x2e98,
+	0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x00c0, 0x7820, 0x6018,
+	0x2068, 0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802,
+	0x0d7f, 0x0078, 0x7608, 0x2100, 0xa1b2, 0x0044, 0x10c8, 0x1328,
+	0xa1b2, 0x0040, 0x00c8, 0x7888, 0x0079, 0x782e, 0x787c, 0x7870,
+	0x787c, 0x787c, 0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e,
+	0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e,
+	0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e,
+	0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x787c,
+	0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x787c, 0x786e,
+	0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e,
+	0x787c, 0x787c, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e, 0x786e,
+	0x786e, 0x786e, 0x786e, 0x787c, 0x786e, 0x786e, 0x1078, 0x1328,
+	0x6003, 0x0001, 0x6106, 0x1078, 0x5c45, 0x127e, 0x2091, 0x8000,
+	0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078,
+	0x5c45, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c,
+	0x2600, 0x0079, 0x788b, 0x788f, 0x788f, 0x788f, 0x787c, 0x1078,
+	0x1328, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328, 0xa1b6, 0x0013,
+	0x00c0, 0x78a1, 0xa0b2, 0x0040, 0x00c8, 0x79fb, 0x2008, 0x0079,
+	0x7941, 0xa1b6, 0x0027, 0x00c0, 0x78fe, 0x1078, 0x6010, 0x6004,
+	0x1078, 0x8c27, 0x0040, 0x78be, 0x1078, 0x8c3b, 0x0040, 0x78f6,
+	0xa08e, 0x0021, 0x0040, 0x78fa, 0xa08e, 0x0022, 0x0040, 0x78f6,
+	0xa08e, 0x003d, 0x0040, 0x78fa, 0x0078, 0x78f1, 0x1078, 0x2839,
+	0x2001, 0x0007, 0x1078, 0x443f, 0x6018, 0xa080, 0x0028, 0x200c,
+	0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x78d3, 0x2001, 0xa332,
+	0x2014, 0xc285, 0x2202, 0x017e, 0x027e, 0x037e, 0x2110, 0x2019,
+	0x0028, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078, 0x5c78,
+	0x0c7e, 0x6018, 0xa065, 0x0040, 0x78e7, 0x1078, 0x471b, 0x0c7f,
+	0x2c08, 0x1078, 0x9c38, 0x077f, 0x037f, 0x027f, 0x017f, 0x1078,
+	0x44bc, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x7a05,
+	0x0078, 0x78f1, 0x1078, 0x7a28, 0x0078, 0x78f1, 0xa186, 0x0014,
+	0x00c0, 0x78f5, 0x1078, 0x6010, 0x1078, 0x2813, 0x1078, 0x8c27,
+	0x00c0, 0x791d, 0x1078, 0x2839, 0x6018, 0xa080, 0x0028, 0x200c,
+	0x1078, 0x7a05, 0xa186, 0x007e, 0x00c0, 0x791b, 0x2001, 0xa332,
+	0x200c, 0xc185, 0x2102, 0x0078, 0x78f1, 0x1078, 0x8c3b, 0x00c0,
+	0x7925, 0x1078, 0x7a05, 0x0078, 0x78f1, 0x6004, 0xa08e, 0x0032,
+	0x00c0, 0x7936, 0x0e7e, 0x0f7e, 0x2071, 0xa381, 0x2079, 0x0000,
+	0x1078, 0x2b56, 0x0f7f, 0x0e7f, 0x0078, 0x78f1, 0x6004, 0xa08e,
+	0x0021, 0x0040, 0x7921, 0xa08e, 0x0022, 0x1040, 0x7a05, 0x0078,
+	0x78f1, 0x7983, 0x7985, 0x7989, 0x798d, 0x7991, 0x7995, 0x7981,
+	0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981,
+	0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981,
+	0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981, 0x7999,
+	0x79ab, 0x7981, 0x79ad, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981,
+	0x7981, 0x79ab, 0x79ab, 0x7981, 0x7981, 0x7981, 0x7981, 0x7981,
+	0x7981, 0x7981, 0x7981, 0x79de, 0x79ab, 0x7981, 0x79a5, 0x7981,
+	0x7981, 0x7981, 0x79a7, 0x7981, 0x7981, 0x7981, 0x79ab, 0x7981,
+	0x7981, 0x1078, 0x1328, 0x0078, 0x79ab, 0x2001, 0x000b, 0x0078,
+	0x79b8, 0x2001, 0x0003, 0x0078, 0x79b8, 0x2001, 0x0005, 0x0078,
+	0x79b8, 0x2001, 0x0001, 0x0078, 0x79b8, 0x2001, 0x0009, 0x0078,
+	0x79b8, 0x1078, 0x6010, 0x6003, 0x0005, 0x2001, 0xa5a2, 0x2004,
+	0x603e, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0078, 0x79ab, 0x0078,
+	0x79ab, 0x1078, 0x443f, 0x0078, 0x79f0, 0x1078, 0x6010, 0x6003,
+	0x0004, 0x2001, 0xa5a0, 0x2004, 0x6016, 0x1078, 0x6109, 0x007c,
+	0x1078, 0x443f, 0x1078, 0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e,
+	0x6003, 0x0002, 0x037e, 0x2019, 0xa35c, 0x2304, 0xa084, 0xff00,
+	0x00c0, 0x79cf, 0x2019, 0xa5a0, 0x231c, 0x0078, 0x79d8, 0x8007,
+	0xa09a, 0x0004, 0x0048, 0x79ca, 0x8003, 0x801b, 0x831b, 0xa318,
+	0x6316, 0x037f, 0x1078, 0x6109, 0x0078, 0x79b7, 0x0e7e, 0x0f7e,
+	0x2071, 0xa381, 0x2079, 0x0000, 0x1078, 0x2b56, 0x0f7f, 0x0e7f,
+	0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x0078, 0x79b7,
+	0x1078, 0x6010, 0x6003, 0x0002, 0x2001, 0xa5a0, 0x2004, 0x6016,
+	0x1078, 0x6109, 0x007c, 0x2600, 0x2008, 0x0079, 0x79ff, 0x7a03,
+	0x7a03, 0x7a03, 0x79f0, 0x1078, 0x1328, 0x0e7e, 0x1078, 0x8a44,
+	0x0040, 0x7a21, 0x6010, 0x2070, 0x7038, 0xd0fc, 0x0040, 0x7a21,
+	0x7007, 0x0000, 0x017e, 0x6004, 0xa08e, 0x0021, 0x0040, 0x7a23,
+	0xa08e, 0x003d, 0x0040, 0x7a23, 0x017f, 0x7037, 0x0103, 0x7033,
+	0x0100, 0x0e7f, 0x007c, 0x017f, 0x1078, 0x7a28, 0x0078, 0x7a21,
+	0x0e7e, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037, 0x0103,
+	0x7023, 0x8001, 0x0e7f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804,
+	0xa084, 0x00ff, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0x6604,
+	0xa6b6, 0x0043, 0x00c0, 0x7a48, 0x1078, 0x8e6d, 0x0078, 0x7aa7,
+	0x6604, 0xa6b6, 0x0033, 0x00c0, 0x7a51, 0x1078, 0x8e11, 0x0078,
+	0x7aa7, 0x6604, 0xa6b6, 0x0028, 0x00c0, 0x7a5a, 0x1078, 0x8c6a,
+	0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0029, 0x00c0, 0x7a63, 0x1078,
+	0x8c84, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x001f, 0x00c0, 0x7a6c,
+	0x1078, 0x75ee, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0000, 0x00c0,
+	0x7a75, 0x1078, 0x780c, 0x0078, 0x7aa7, 0x6604, 0xa6b6, 0x0022,
+	0x00c0, 0x7a7e, 0x1078, 0x7617, 0x0078, 0x7aa7, 0x6604, 0xa6b6,
+	0x0035, 0x00c0, 0x7a87, 0x1078, 0x7653, 0x0078, 0x7aa7, 0x6604,
+	0xa6b6, 0x0039, 0x00c0, 0x7a90, 0x1078, 0x77b2, 0x0078, 0x7aa7,
+	0x6604, 0xa6b6, 0x003d, 0x00c0, 0x7a99, 0x1078, 0x7633, 0x0078,
+	0x7aa7, 0xa1b6, 0x0015, 0x00c0, 0x7aa1, 0x1079, 0x7aac, 0x0078,
+	0x7aa7, 0xa1b6, 0x0016, 0x00c0, 0x7aa8, 0x1079, 0x7bfd, 0x007c,
+	0x1078, 0x7583, 0x0078, 0x7aa7, 0x7ad0, 0x7ad3, 0x7ad0, 0x7b1e,
+	0x7ad0, 0x7b91, 0x7c09, 0x7ad0, 0x7ad0, 0x7bd5, 0x7ad0, 0x7beb,
+	0xa1b6, 0x0048, 0x0040, 0x7ac4, 0x20e1, 0x0005, 0x3d18, 0x3e20,
+	0x2c10, 0x1078, 0x15ec, 0x007c, 0x0e7e, 0xacf0, 0x0004, 0x2e74,
+	0x7000, 0x2070, 0x7037, 0x0103, 0x0e7f, 0x1078, 0x753d, 0x007c,
+	0x0005, 0x0005, 0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086,
+	0x0074, 0x00c0, 0x7b07, 0x1078, 0x9c0c, 0x00c0, 0x7af9, 0x0d7e,
+	0x6018, 0x2068, 0x7030, 0xd08c, 0x0040, 0x7aec, 0x6800, 0xd0bc,
+	0x0040, 0x7aec, 0xc0c5, 0x6802, 0x1078, 0x7b0b, 0x0d7f, 0x2001,
+	0x0006, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078,
+	0x7b09, 0x2001, 0x000a, 0x1078, 0x443f, 0x1078, 0x2839, 0x6003,
+	0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7b09, 0x1078,
+	0x7b81, 0x0e7f, 0x007c, 0x6800, 0xd084, 0x0040, 0x7b1d, 0x2001,
+	0x0000, 0x1078, 0x442b, 0x2069, 0xa351, 0x6804, 0xd0a4, 0x0040,
+	0x7b1d, 0x2001, 0x0006, 0x1078, 0x4472, 0x007c, 0x0d7e, 0x2011,
+	0xa31f, 0x2204, 0xa086, 0x0074, 0x00c0, 0x7b7d, 0x6018, 0x2068,
+	0x6aa0, 0xa286, 0x007e, 0x00c0, 0x7b31, 0x1078, 0x7d17, 0x0078,
+	0x7b7f, 0x1078, 0x7d0d, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014,
+	0xa286, 0x0080, 0x00c0, 0x7b55, 0x6813, 0x00ff, 0x6817, 0xfffc,
+	0x6010, 0xa005, 0x0040, 0x7b4b, 0x2068, 0x6807, 0x0000, 0x6837,
+	0x0103, 0x6833, 0x0200, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078,
+	0x2839, 0x1078, 0x753d, 0x0078, 0x7b7f, 0x0e7e, 0x2071, 0xa332,
+	0x2e04, 0xd09c, 0x0040, 0x7b70, 0x2071, 0xa880, 0x7108, 0x720c,
+	0xa18c, 0x00ff, 0x00c0, 0x7b68, 0xa284, 0xff00, 0x0040, 0x7b70,
+	0x6018, 0x2070, 0x70a0, 0xd0bc, 0x00c0, 0x7b70, 0x7112, 0x7216,
+	0x0e7f, 0x2001, 0x0004, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007,
+	0x0003, 0x1078, 0x5c45, 0x0078, 0x7b7f, 0x1078, 0x7b81, 0x0d7f,
+	0x007c, 0x2001, 0xa300, 0x2004, 0xa086, 0x0003, 0x0040, 0x7b8c,
+	0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x2839, 0x1078, 0x753d,
+	0x007c, 0x0e7e, 0x2071, 0xa300, 0x707c, 0xa086, 0x0014, 0x00c0,
+	0x7bcf, 0x7000, 0xa086, 0x0003, 0x00c0, 0x7ba4, 0x6010, 0xa005,
+	0x00c0, 0x7ba4, 0x1078, 0x35f7, 0x0d7e, 0x6018, 0x2068, 0x1078,
+	0x457d, 0x1078, 0x7b0b, 0x0d7f, 0x1078, 0x7dba, 0x00c0, 0x7bcf,
+	0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f, 0xa005, 0x0040, 0x7bcf,
+	0x2001, 0x0006, 0x1078, 0x443f, 0x0e7e, 0x6010, 0xa005, 0x0040,
+	0x7bc8, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103, 0x7033, 0x0200,
+	0x0e7f, 0x1078, 0x2839, 0x1078, 0x753d, 0x0078, 0x7bd3, 0x1078,
+	0x7a05, 0x1078, 0x7b81, 0x0e7f, 0x007c, 0x2011, 0xa31f, 0x2204,
+	0xa086, 0x0014, 0x00c0, 0x7be8, 0x2001, 0x0002, 0x1078, 0x443f,
+	0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7bea,
+	0x1078, 0x7b81, 0x007c, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0004,
+	0x00c0, 0x7bfa, 0x2001, 0x0007, 0x1078, 0x443f, 0x1078, 0x753d,
+	0x0078, 0x7bfc, 0x1078, 0x7b81, 0x007c, 0x7ad0, 0x7c11, 0x7ad0,
+	0x7c4e, 0x7ad0, 0x7cc0, 0x7c09, 0x7ad0, 0x7ad0, 0x7cd5, 0x7ad0,
+	0x7ce8, 0x6604, 0xa6b6, 0x001e, 0x00c0, 0x7c10, 0x1078, 0x753d,
+	0x007c, 0x0d7e, 0x0c7e, 0x1078, 0x7cfb, 0x00c0, 0x7c27, 0x2001,
+	0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003,
+	0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x0078, 0x7c4b, 0x2009,
+	0xa88e, 0x2104, 0xa086, 0x0009, 0x00c0, 0x7c3c, 0x6018, 0x2068,
+	0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x7c49, 0x8001, 0x6842,
+	0x6017, 0x000a, 0x0078, 0x7c4b, 0x2009, 0xa88f, 0x2104, 0xa084,
+	0xff00, 0xa086, 0x1900, 0x00c0, 0x7c49, 0x1078, 0x753d, 0x0078,
+	0x7c4b, 0x1078, 0x7b81, 0x0c7f, 0x0d7f, 0x007c, 0x1078, 0x7d0a,
+	0x00c0, 0x7c62, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002,
+	0x1078, 0x443f, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078, 0x5c45,
+	0x0078, 0x7c8e, 0x1078, 0x7a05, 0x2009, 0xa88e, 0x2134, 0xa6b4,
+	0x00ff, 0xa686, 0x0005, 0x0040, 0x7c8f, 0xa686, 0x000b, 0x0040,
+	0x7c8c, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0x00c0, 0x7c7c,
+	0xa686, 0x0009, 0x0040, 0x7c8f, 0xa086, 0x1900, 0x00c0, 0x7c8c,
+	0xa686, 0x0009, 0x0040, 0x7c8f, 0x2001, 0x0004, 0x1078, 0x443f,
+	0x1078, 0x753d, 0x0078, 0x7c8e, 0x1078, 0x7b81, 0x007c, 0x0d7e,
+	0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x7c9d, 0x6838, 0xd0fc,
+	0x0040, 0x7c9d, 0x0d7f, 0x0078, 0x7c8c, 0x6018, 0x2068, 0x6840,
+	0xa084, 0x00ff, 0xa005, 0x0040, 0x7cae, 0x8001, 0x6842, 0x6017,
+	0x000a, 0x6007, 0x0016, 0x0d7f, 0x0078, 0x7c8e, 0x68a0, 0xa086,
+	0x007e, 0x00c0, 0x7cbb, 0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5,
+	0x0e7f, 0x0078, 0x7cbd, 0x1078, 0x2813, 0x0d7f, 0x0078, 0x7c8c,
+	0x1078, 0x7d0a, 0x00c0, 0x7cd0, 0x2001, 0x0004, 0x1078, 0x443f,
+	0x6003, 0x0001, 0x6007, 0x0003, 0x1078, 0x5c45, 0x0078, 0x7cd4,
+	0x1078, 0x7a05, 0x1078, 0x7b81, 0x007c, 0x1078, 0x7d0a, 0x00c0,
+	0x7ce5, 0x2001, 0x0008, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007,
+	0x0005, 0x1078, 0x5c45, 0x0078, 0x7ce7, 0x1078, 0x7b81, 0x007c,
+	0x1078, 0x7d0a, 0x00c0, 0x7cf8, 0x2001, 0x000a, 0x1078, 0x443f,
+	0x6003, 0x0001, 0x6007, 0x0001, 0x1078, 0x5c45, 0x0078, 0x7cfa,
+	0x1078, 0x7b81, 0x007c, 0x2009, 0xa88e, 0x2104, 0xa086, 0x0003,
+	0x00c0, 0x7d09, 0x2009, 0xa88f, 0x2104, 0xa084, 0xff00, 0xa086,
+	0x2a00, 0x007c, 0xa085, 0x0001, 0x007c, 0x0c7e, 0x017e, 0xac88,
+	0x0006, 0x2164, 0x1078, 0x4513, 0x017f, 0x0c7f, 0x007c, 0x0f7e,
+	0x0e7e, 0x0d7e, 0x037e, 0x017e, 0x6018, 0x2068, 0x2071, 0xa332,
+	0x2e04, 0xa085, 0x0003, 0x2072, 0x1078, 0x7d8b, 0x0040, 0x7d50,
+	0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x7d39, 0xa006, 0x2020,
+	0x2009, 0x002a, 0x1078, 0x9ec0, 0x2001, 0xa30c, 0x200c, 0xc195,
+	0x2102, 0x2019, 0x002a, 0x2009, 0x0001, 0x1078, 0x27e2, 0x2071,
+	0xa300, 0x1078, 0x260d, 0x0c7e, 0x157e, 0x20a9, 0x0081, 0x2009,
+	0x007f, 0x1078, 0x2921, 0x8108, 0x00f0, 0x7d49, 0x157f, 0x0c7f,
+	0x1078, 0x7d0d, 0x6813, 0x00ff, 0x6817, 0xfffe, 0x2071, 0xa880,
+	0x2079, 0x0100, 0x2e04, 0xa084, 0x00ff, 0x2069, 0xa31a, 0x206a,
+	0x78e6, 0x007e, 0x8e70, 0x2e04, 0x2069, 0xa31b, 0x206a, 0x78ea,
+	0xa084, 0xff00, 0x017f, 0xa105, 0x2009, 0xa325, 0x200a, 0x2069,
+	0xa88e, 0x2071, 0xa59c, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818,
+	0x700a, 0x681c, 0x700e, 0x1078, 0x8da9, 0x2001, 0x0006, 0x1078,
+	0x443f, 0x1078, 0x2839, 0x1078, 0x753d, 0x017f, 0x037f, 0x0d7f,
+	0x0e7f, 0x0f7f, 0x007c, 0x027e, 0x037e, 0x0e7e, 0x157e, 0x2019,
+	0xa325, 0x231c, 0x83ff, 0x0040, 0x7db5, 0x2071, 0xa880, 0x2e14,
+	0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x00c0,
+	0x7db5, 0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078,
+	0x7e55, 0x00c0, 0x7db5, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9,
+	0x0004, 0x1078, 0x7e55, 0x00c0, 0x7db5, 0x157f, 0x0e7f, 0x037f,
+	0x027f, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7004, 0xa086, 0x0014,
+	0x00c0, 0x7ddd, 0x7008, 0xa086, 0x0800, 0x00c0, 0x7ddd, 0x700c,
+	0xd0ec, 0x0040, 0x7ddb, 0xa084, 0x0f00, 0xa086, 0x0100, 0x00c0,
+	0x7ddb, 0x7024, 0xd0a4, 0x00c0, 0x7dd8, 0xd0ac, 0x0040, 0x7ddb,
+	0xa006, 0x0078, 0x7ddd, 0xa085, 0x0001, 0x0e7f, 0x007c, 0x0e7e,
+	0x0d7e, 0x0c7e, 0x077e, 0x057e, 0x047e, 0x027e, 0x007e, 0x127e,
+	0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba, 0x2424,
+	0x2061, 0xaa00, 0x2071, 0xa300, 0x7244, 0x7060, 0xa202, 0x00c8,
+	0x7e43, 0x1078, 0x9ee5, 0x0040, 0x7e3b, 0x671c, 0xa786, 0x0001,
+	0x0040, 0x7e3b, 0xa786, 0x0007, 0x0040, 0x7e3b, 0x2500, 0xac06,
+	0x0040, 0x7e3b, 0x2400, 0xac06, 0x0040, 0x7e3b, 0x0c7e, 0x6000,
+	0xa086, 0x0004, 0x00c0, 0x7e16, 0x1078, 0x1749, 0xa786, 0x0008,
+	0x00c0, 0x7e25, 0x1078, 0x8c3b, 0x00c0, 0x7e25, 0x0c7f, 0x1078,
+	0x7a05, 0x1078, 0x8c01, 0x0078, 0x7e3b, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x7e38, 0xa786, 0x0003, 0x00c0, 0x7e4d, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4,
+	0x1078, 0x8c01, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8,
+	0x7e43, 0x0078, 0x7df4, 0x127f, 0x007f, 0x027f, 0x047f, 0x057f,
+	0x077f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0,
+	0x7e2f, 0x1078, 0x9e70, 0x0078, 0x7e38, 0x220c, 0x2304, 0xa106,
+	0x00c0, 0x7e60, 0x8210, 0x8318, 0x00f0, 0x7e55, 0xa006, 0x007c,
+	0x2304, 0xa102, 0x0048, 0x7e68, 0x2001, 0x0001, 0x0078, 0x7e6a,
+	0x2001, 0x0000, 0xa18d, 0x0001, 0x007c, 0x6004, 0xa08a, 0x0044,
+	0x10c8, 0x1328, 0x1078, 0x8c27, 0x0040, 0x7e7c, 0x1078, 0x8c3b,
+	0x0040, 0x7e89, 0x0078, 0x7e82, 0x1078, 0x2839, 0x1078, 0x8c3b,
+	0x0040, 0x7e89, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109,
+	0x007c, 0x1078, 0x7a05, 0x0078, 0x7e82, 0xa182, 0x0040, 0x0079,
+	0x7e91, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4,
+	0x7ea4, 0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x7ea6, 0x7ea6, 0x7ea6,
+	0x7ea4, 0x7ea4, 0x7ea4, 0x7ea6, 0x1078, 0x1328, 0x600b, 0xffff,
+	0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000,
+	0x1078, 0x6109, 0x127f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x7ebd,
+	0x6004, 0xa082, 0x0040, 0x0079, 0x7f48, 0xa186, 0x0027, 0x00c0,
+	0x7edf, 0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168,
+	0x1078, 0x8a44, 0x0040, 0x7ed9, 0x6837, 0x0103, 0x684b, 0x0029,
+	0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e, 0x1078, 0x4982, 0x1078,
+	0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0xa186,
+	0x0014, 0x00c0, 0x7ee8, 0x6004, 0xa082, 0x0040, 0x0079, 0x7f10,
+	0xa186, 0x0046, 0x0040, 0x7ef4, 0xa186, 0x0045, 0x0040, 0x7ef4,
+	0xa186, 0x0047, 0x10c0, 0x1328, 0x2001, 0x0109, 0x2004, 0xd084,
+	0x0040, 0x7f0d, 0x127e, 0x2091, 0x2200, 0x007e, 0x017e, 0x027e,
+	0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f, 0x6000, 0xa086,
+	0x0002, 0x00c0, 0x7f0d, 0x0078, 0x7f81, 0x1078, 0x7583, 0x007c,
+	0x7f25, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23, 0x7f23,
+	0x7f23, 0x7f23, 0x7f23, 0x7f41, 0x7f41, 0x7f41, 0x7f41, 0x7f23,
+	0x7f41, 0x7f23, 0x7f41, 0x1078, 0x1328, 0x1078, 0x6010, 0x0d7e,
+	0x6110, 0x2168, 0x1078, 0x8a44, 0x0040, 0x7f3b, 0x6837, 0x0103,
+	0x684b, 0x0006, 0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, 0x1078,
+	0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109,
+	0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109, 0x007c,
+	0x7f5d, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b, 0x7f5b,
+	0x7f5b, 0x7f5b, 0x7f5b, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f6f, 0x7f5b,
+	0x7f7a, 0x7f5b, 0x7f6f, 0x1078, 0x1328, 0x1078, 0x6010, 0x2001,
+	0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x6109, 0x6010,
+	0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x007c, 0x1078,
+	0x6010, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x000f, 0x1078,
+	0x6109, 0x007c, 0x1078, 0x6010, 0x1078, 0x753d, 0x1078, 0x6109,
+	0x007c, 0xa182, 0x0040, 0x0079, 0x7f85, 0x7f98, 0x7f98, 0x7f98,
+	0x7f98, 0x7f98, 0x7f9a, 0x8095, 0x80b7, 0x7f98, 0x7f98, 0x7f98,
+	0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98, 0x7f98,
+	0x1078, 0x1328, 0x0e7e, 0x0d7e, 0x603f, 0x0000, 0x2071, 0xa880,
+	0x7124, 0x610a, 0x2071, 0xa88c, 0x6110, 0x2168, 0x7614, 0xa6b4,
+	0x0fff, 0x86ff, 0x0040, 0x8058, 0xa68c, 0x0c00, 0x0040, 0x7fd1,
+	0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x7fcd, 0x684c,
+	0xd0ac, 0x0040, 0x7fcd, 0x6024, 0xd0dc, 0x00c0, 0x7fcd, 0x6850,
+	0xd0bc, 0x00c0, 0x7fcd, 0x7318, 0x6814, 0xa306, 0x00c0, 0x806f,
+	0x731c, 0x6810, 0xa306, 0x00c0, 0x806f, 0x7318, 0x6b62, 0x731c,
+	0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x8004, 0xa186,
+	0x0028, 0x00c0, 0x7fe1, 0x1078, 0x8c15, 0x684b, 0x001c, 0x0078,
+	0x8006, 0xd6dc, 0x0040, 0x7ffd, 0x684b, 0x0015, 0x684c, 0xd0ac,
+	0x0040, 0x7ffb, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040, 0x7ffb,
+	0x7018, 0xa106, 0x00c0, 0x7ff8, 0x701c, 0xa206, 0x0040, 0x7ffb,
+	0x6962, 0x6a5e, 0xc6dc, 0x0078, 0x8006, 0xd6d4, 0x0040, 0x8004,
+	0x684b, 0x0007, 0x0078, 0x8006, 0x684b, 0x0000, 0x6837, 0x0103,
+	0x6e46, 0xa01e, 0xd6c4, 0x0040, 0x802f, 0xa686, 0x0100, 0x00c0,
+	0x801a, 0x2001, 0xa899, 0x2004, 0xa005, 0x00c0, 0x801a, 0xc6c4,
+	0x0078, 0x7fa9, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x802f,
+	0xa38a, 0x0009, 0x0048, 0x8026, 0x2019, 0x0008, 0x037e, 0x2308,
+	0x2019, 0xa898, 0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc,
+	0x0040, 0x8085, 0x7124, 0x695a, 0x81ff, 0x0040, 0x8085, 0xa192,
+	0x0021, 0x00c8, 0x8046, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18,
+	0xad90, 0x001d, 0x1078, 0x8739, 0x0078, 0x8085, 0x6838, 0xd0fc,
+	0x0040, 0x804f, 0x2009, 0x0020, 0x695a, 0x0078, 0x803b, 0x0f7e,
+	0x2d78, 0x1078, 0x86d1, 0x0f7f, 0x1078, 0x8726, 0x0078, 0x8087,
+	0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8075, 0x684c,
+	0xd0ac, 0x0040, 0x8075, 0x6024, 0xd0dc, 0x00c0, 0x8075, 0x6850,
+	0xd0bc, 0x00c0, 0x8075, 0x684c, 0xd0f4, 0x00c0, 0x8075, 0x1078,
+	0x8cfa, 0x0d7f, 0x0e7f, 0x0078, 0x8094, 0x684b, 0x0000, 0x6837,
+	0x0103, 0x6e46, 0x684c, 0xd0ac, 0x0040, 0x8085, 0x6810, 0x6914,
+	0xa115, 0x0040, 0x8085, 0x1078, 0x8233, 0x1078, 0x4982, 0x6218,
+	0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x1078, 0x8cc4, 0x0d7f, 0x0e7f,
+	0x00c0, 0x8094, 0x1078, 0x753d, 0x007c, 0x0f7e, 0x6003, 0x0003,
+	0x2079, 0xa88c, 0x7c04, 0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078,
+	0x784c, 0xd0ac, 0x0040, 0x80a8, 0x6003, 0x0002, 0x0f7f, 0x007c,
+	0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x0f7f, 0x603f, 0x0000, 0x2c10,
+	0x1078, 0x1cab, 0x1078, 0x5c64, 0x1078, 0x61d3, 0x007c, 0x2001,
+	0xa5a2, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110, 0x20e1, 0x0005,
+	0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0xa182, 0x0040,
+	0x0079, 0x80ca, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80dd, 0x80df,
+	0x8182, 0x80dd, 0x80dd, 0x8198, 0x8209, 0x80dd, 0x80dd, 0x80dd,
+	0x80dd, 0x8218, 0x80dd, 0x80dd, 0x80dd, 0x1078, 0x1328, 0x077e,
+	0x0f7e, 0x0e7e, 0x0d7e, 0x2071, 0xa88c, 0x6110, 0x2178, 0x7614,
+	0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218, 0x2268,
+	0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0040, 0x817d, 0xa694, 0xff00,
+	0xa284, 0x0c00, 0x0040, 0x8100, 0x7018, 0x7862, 0x701c, 0x785e,
+	0xa284, 0x0300, 0x0040, 0x817d, 0x1078, 0x1381, 0x1040, 0x1328,
+	0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838,
+	0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00,
+	0x0040, 0x811e, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff,
+	0xa186, 0x0002, 0x0040, 0x813a, 0xa186, 0x0028, 0x00c0, 0x812c,
+	0x684b, 0x001c, 0x0078, 0x813c, 0xd6dc, 0x0040, 0x8133, 0x684b,
+	0x0015, 0x0078, 0x813c, 0xd6d4, 0x0040, 0x813a, 0x684b, 0x0007,
+	0x0078, 0x813c, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854,
+	0x6856, 0xa01e, 0xd6c4, 0x0040, 0x815a, 0x7328, 0x732c, 0x6b56,
+	0x83ff, 0x0040, 0x815a, 0xa38a, 0x0009, 0x0048, 0x8151, 0x2019,
+	0x0008, 0x037e, 0x2308, 0x2019, 0xa898, 0xad90, 0x0019, 0x1078,
+	0x8739, 0x037f, 0xd6cc, 0x0040, 0x817d, 0x7124, 0x695a, 0x81ff,
+	0x0040, 0x817d, 0xa192, 0x0021, 0x00c8, 0x8171, 0x2071, 0xa898,
+	0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x1078, 0x8739, 0x0078,
+	0x817d, 0x7838, 0xd0fc, 0x0040, 0x817a, 0x2009, 0x0020, 0x695a,
+	0x0078, 0x8166, 0x2d78, 0x1078, 0x86d1, 0x0d7f, 0x0e7f, 0x0f7f,
+	0x077f, 0x007c, 0x0f7e, 0x6003, 0x0003, 0x2079, 0xa88c, 0x7c04,
+	0x7b00, 0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a,
+	0x7d0e, 0x0f7f, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x6c26, 0x007c,
+	0x0d7e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x81a4,
+	0x2001, 0xa5a2, 0x2004, 0x603e, 0x6003, 0x0002, 0x1078, 0x60b8,
+	0x1078, 0x61d3, 0x6110, 0x2168, 0x694c, 0xd1e4, 0x0040, 0x8207,
+	0xd1cc, 0x0040, 0x81de, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x81d6,
+	0x017e, 0x684c, 0x007e, 0x6850, 0x007e, 0xad90, 0x000d, 0xa198,
+	0x000d, 0x2009, 0x0020, 0x157e, 0x21a8, 0x2304, 0x2012, 0x8318,
+	0x8210, 0x00f0, 0x81c5, 0x157f, 0x007f, 0x6852, 0x007f, 0x684e,
+	0x017f, 0x2168, 0x1078, 0x13aa, 0x0078, 0x8201, 0x017e, 0x1078,
+	0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8201, 0x6837, 0x0103,
+	0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040, 0x81fd, 0xa086,
+	0x0028, 0x00c0, 0x81ef, 0x684b, 0x001c, 0x0078, 0x81ff, 0xd1dc,
+	0x0040, 0x81f6, 0x684b, 0x0015, 0x0078, 0x81ff, 0xd1d4, 0x0040,
+	0x81fd, 0x684b, 0x0007, 0x0078, 0x81ff, 0x684b, 0x0000, 0x1078,
+	0x4982, 0x1078, 0x8cc4, 0x00c0, 0x8207, 0x1078, 0x753d, 0x0d7f,
+	0x007c, 0x2019, 0x0001, 0x1078, 0x6e6c, 0x6003, 0x0002, 0x2001,
+	0xa5a2, 0x2004, 0x603e, 0x1078, 0x60b8, 0x1078, 0x61d3, 0x007c,
+	0x1078, 0x60b8, 0x1078, 0x2813, 0x0d7e, 0x6110, 0x2168, 0x1078,
+	0x8a44, 0x0040, 0x822d, 0x6837, 0x0103, 0x684b, 0x0029, 0x6847,
+	0x0000, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d,
+	0x1078, 0x61d3, 0x007c, 0x684b, 0x0015, 0xd1fc, 0x0040, 0x823f,
+	0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962,
+	0x685e, 0x007c, 0xa182, 0x0040, 0x0079, 0x8246, 0x8259, 0x8259,
+	0x8259, 0x8259, 0x8259, 0x825b, 0x8259, 0x8333, 0x833f, 0x8259,
+	0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259, 0x8259,
+	0x8259, 0x1078, 0x1328, 0x077e, 0x0f7e, 0x0e7e, 0x0d7e, 0x2071,
+	0xa88c, 0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x0f7e, 0x2c78,
+	0x1078, 0x4893, 0x0f7f, 0x0040, 0x827e, 0xa684, 0x00ff, 0x00c0,
+	0x827e, 0x6024, 0xd0f4, 0x00c0, 0x827a, 0x7808, 0xa086, 0x0000,
+	0x00c0, 0x827e, 0x1078, 0x8cfa, 0x0078, 0x832e, 0x7e46, 0x7f4c,
+	0xc7e5, 0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff,
+	0x0040, 0x8323, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0040, 0x8294,
+	0x7018, 0x7862, 0x701c, 0x785e, 0xa284, 0x0300, 0x0040, 0x8320,
+	0xa686, 0x0100, 0x00c0, 0x82a6, 0x2001, 0xa899, 0x2004, 0xa005,
+	0x00c0, 0x82a6, 0xc6c4, 0x7e46, 0x0078, 0x8287, 0x1078, 0x1381,
+	0x1040, 0x1328, 0x2d00, 0x784a, 0x7f4c, 0xa7bd, 0x0200, 0x7f4e,
+	0x6837, 0x0103, 0x7838, 0x683a, 0x783c, 0x683e, 0x7840, 0x6842,
+	0x6e46, 0xa68c, 0x0c00, 0x0040, 0x82c1, 0x7318, 0x6b62, 0x731c,
+	0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0040, 0x82dd, 0xa186,
+	0x0028, 0x00c0, 0x82cf, 0x684b, 0x001c, 0x0078, 0x82df, 0xd6dc,
+	0x0040, 0x82d6, 0x684b, 0x0015, 0x0078, 0x82df, 0xd6d4, 0x0040,
+	0x82dd, 0x684b, 0x0007, 0x0078, 0x82df, 0x684b, 0x0000, 0x6f4e,
+	0x7850, 0x6852, 0x7854, 0x6856, 0xa01e, 0xd6c4, 0x0040, 0x82fd,
+	0x7328, 0x732c, 0x6b56, 0x83ff, 0x0040, 0x82fd, 0xa38a, 0x0009,
+	0x0048, 0x82f4, 0x2019, 0x0008, 0x037e, 0x2308, 0x2019, 0xa898,
+	0xad90, 0x0019, 0x1078, 0x8739, 0x037f, 0xd6cc, 0x0040, 0x8320,
+	0x7124, 0x695a, 0x81ff, 0x0040, 0x8320, 0xa192, 0x0021, 0x00c8,
+	0x8314, 0x2071, 0xa898, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d,
+	0x1078, 0x8739, 0x0078, 0x8320, 0x7838, 0xd0fc, 0x0040, 0x831d,
+	0x2009, 0x0020, 0x695a, 0x0078, 0x8309, 0x2d78, 0x1078, 0x86d1,
+	0xd6dc, 0x00c0, 0x8326, 0xa006, 0x0078, 0x832c, 0x2001, 0x0001,
+	0x2071, 0xa88c, 0x7218, 0x731c, 0x1078, 0x1645, 0x0d7f, 0x0e7f,
+	0x0f7f, 0x077f, 0x007c, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x20e1,
+	0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x2001,
+	0xa5a2, 0x2004, 0x603e, 0x0d7e, 0x6003, 0x0002, 0x6110, 0x2168,
+	0x694c, 0xd1e4, 0x0040, 0x846b, 0x603f, 0x0000, 0x0f7e, 0x2c78,
+	0x1078, 0x4893, 0x0f7f, 0x0040, 0x8385, 0x6814, 0x6910, 0xa115,
+	0x0040, 0x8385, 0x6a60, 0xa206, 0x00c0, 0x8362, 0x685c, 0xa106,
+	0x0040, 0x8385, 0x684c, 0xc0e4, 0x684e, 0x6847, 0x0000, 0x6863,
+	0x0000, 0x685f, 0x0000, 0x6024, 0xd0f4, 0x00c0, 0x837a, 0x697c,
+	0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6024,
+	0xc0f5, 0x6026, 0x0d7e, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e,
+	0x0d7f, 0x1078, 0x8cfa, 0x0078, 0x846b, 0x694c, 0xd1cc, 0x0040,
+	0x8430, 0x6948, 0x6838, 0xd0fc, 0x0040, 0x83ea, 0x017e, 0x684c,
+	0x007e, 0x6850, 0x007e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff,
+	0xa0b6, 0x0002, 0x0040, 0x83bf, 0xa086, 0x0028, 0x00c0, 0x83a6,
+	0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x83ca, 0xd1dc, 0x0040,
+	0x83b6, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040,
+	0x83b4, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x83ca, 0xd1d4, 0x0040,
+	0x83bf, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x83ca, 0x684c,
+	0xd0ac, 0x0040, 0x83ca, 0x6810, 0x6914, 0xa115, 0x0040, 0x83ca,
+	0x1078, 0x8233, 0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e,
+	0xad90, 0x000d, 0xaf98, 0x000d, 0x2009, 0x0020, 0x157e, 0x21a8,
+	0x2304, 0x2012, 0x8318, 0x8210, 0x00f0, 0x83d8, 0x157f, 0x0f7f,
+	0x007f, 0x6852, 0x007f, 0x684e, 0x017f, 0x2168, 0x1078, 0x13aa,
+	0x0078, 0x8465, 0x017e, 0x0f7e, 0x2178, 0x7944, 0xa184, 0x00ff,
+	0xa0b6, 0x0002, 0x0040, 0x8417, 0xa086, 0x0028, 0x00c0, 0x83fe,
+	0x684b, 0x001c, 0x784b, 0x001c, 0x0078, 0x8422, 0xd1dc, 0x0040,
+	0x840e, 0x684b, 0x0015, 0x784b, 0x0015, 0x1078, 0x8ea5, 0x0040,
+	0x840c, 0x7944, 0xc1dc, 0x7946, 0x0078, 0x8422, 0xd1d4, 0x0040,
+	0x8417, 0x684b, 0x0007, 0x784b, 0x0007, 0x0078, 0x8422, 0x684c,
+	0xd0ac, 0x0040, 0x8422, 0x6810, 0x6914, 0xa115, 0x0040, 0x8422,
+	0x1078, 0x8233, 0x6860, 0x7862, 0x685c, 0x785e, 0x684c, 0x784e,
+	0x0f7f, 0x1078, 0x13aa, 0x0d7f, 0x1078, 0x8726, 0x0078, 0x8465,
+	0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0040,
+	0x8456, 0xa086, 0x0028, 0x00c0, 0x8441, 0x684b, 0x001c, 0x0078,
+	0x8463, 0xd1dc, 0x0040, 0x844f, 0x684b, 0x0015, 0x1078, 0x8ea5,
+	0x0040, 0x844d, 0x6944, 0xc1dc, 0x6946, 0x0078, 0x8463, 0xd1d4,
+	0x0040, 0x8456, 0x684b, 0x0007, 0x0078, 0x8463, 0x684b, 0x0000,
+	0x684c, 0xd0ac, 0x0040, 0x8463, 0x6810, 0x6914, 0xa115, 0x0040,
+	0x8463, 0x1078, 0x8233, 0x1078, 0x4982, 0x1078, 0x8cc4, 0x00c0,
+	0x846b, 0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x6010, 0x0078,
+	0x8473, 0x1078, 0x60b8, 0x1078, 0x8a44, 0x0040, 0x8492, 0x0d7e,
+	0x6110, 0x2168, 0x6837, 0x0103, 0x2009, 0xa30c, 0x210c, 0xd18c,
+	0x00c0, 0x849d, 0xd184, 0x00c0, 0x8499, 0x6108, 0x694a, 0xa18e,
+	0x0029, 0x00c0, 0x848d, 0x1078, 0xa181, 0x6847, 0x0000, 0x1078,
+	0x4982, 0x0d7f, 0x1078, 0x753d, 0x1078, 0x6109, 0x1078, 0x61d3,
+	0x007c, 0x684b, 0x0004, 0x0078, 0x848d, 0x684b, 0x0004, 0x0078,
+	0x848d, 0xa182, 0x0040, 0x0079, 0x84a5, 0x84b8, 0x84b8, 0x84b8,
+	0x84b8, 0x84b8, 0x84ba, 0x84b8, 0x84bd, 0x84b8, 0x84b8, 0x84b8,
+	0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8, 0x84b8,
+	0x1078, 0x1328, 0x1078, 0x753d, 0x007c, 0x007e, 0x027e, 0xa016,
+	0x1078, 0x15ec, 0x027f, 0x007f, 0x007c, 0xa182, 0x0085, 0x0079,
+	0x84c9, 0x84d2, 0x84d0, 0x84d0, 0x84de, 0x84d0, 0x84d0, 0x84d0,
+	0x1078, 0x1328, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x057e,
+	0x0d7e, 0x0e7e, 0x2071, 0xa880, 0x7224, 0x6212, 0x7220, 0x1078,
+	0x8a30, 0x0040, 0x8503, 0x2268, 0x6800, 0xa086, 0x0000, 0x0040,
+	0x8503, 0x6018, 0x6d18, 0xa52e, 0x00c0, 0x8503, 0x0c7e, 0x2d60,
+	0x1078, 0x874a, 0x0c7f, 0x0040, 0x8503, 0x6803, 0x0002, 0x6007,
+	0x0086, 0x0078, 0x8505, 0x6007, 0x0087, 0x6003, 0x0001, 0x1078,
+	0x5bf8, 0x1078, 0x6109, 0x0f7e, 0x2278, 0x1078, 0x4893, 0x0f7f,
+	0x0040, 0x851d, 0x6824, 0xd0ec, 0x0040, 0x851d, 0x0c7e, 0x2260,
+	0x603f, 0x0000, 0x1078, 0x8cfa, 0x0c7f, 0x0e7f, 0x0d7f, 0x057f,
+	0x027f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x8533, 0x6004, 0xa08a,
+	0x0085, 0x1048, 0x1328, 0xa08a, 0x008c, 0x10c8, 0x1328, 0xa082,
+	0x0085, 0x0079, 0x8542, 0xa186, 0x0027, 0x0040, 0x853b, 0xa186,
+	0x0014, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078,
+	0x6109, 0x007c, 0x8549, 0x854b, 0x854b, 0x8549, 0x8549, 0x8549,
+	0x8549, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078,
+	0x6109, 0x007c, 0xa186, 0x0013, 0x00c0, 0x855c, 0x6004, 0xa082,
+	0x0085, 0x2008, 0x0078, 0x8597, 0xa186, 0x0027, 0x00c0, 0x857f,
+	0x1078, 0x6010, 0x1078, 0x2813, 0x0d7e, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b,
+	0x0029, 0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d,
+	0x1078, 0x6109, 0x007c, 0x1078, 0x7583, 0x0078, 0x857a, 0xa186,
+	0x0014, 0x00c0, 0x857b, 0x1078, 0x6010, 0x0d7e, 0x6010, 0x2068,
+	0x1078, 0x8a44, 0x0040, 0x8575, 0x6837, 0x0103, 0x6847, 0x0000,
+	0x684b, 0x0006, 0x6850, 0xc0ec, 0x6852, 0x0078, 0x8571, 0x0079,
+	0x8599, 0x85a2, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85a0, 0x85bd,
+	0x1078, 0x1328, 0x1078, 0x6010, 0x6030, 0xa08c, 0xff00, 0x810f,
+	0xa186, 0x0039, 0x0040, 0x85b0, 0xa186, 0x0035, 0x00c0, 0x85b4,
+	0x2001, 0xa5a0, 0x0078, 0x85b6, 0x2001, 0xa5a1, 0x2004, 0x6016,
+	0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x6030,
+	0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0040, 0x85cb, 0xa186,
+	0x0035, 0x00c0, 0x85cf, 0x2001, 0xa5a0, 0x0078, 0x85d1, 0x2001,
+	0xa5a1, 0x2004, 0x6016, 0x6003, 0x000e, 0x1078, 0x6109, 0x007c,
+	0xa182, 0x008c, 0x00c8, 0x85e2, 0xa182, 0x0085, 0x0048, 0x85e2,
+	0x0079, 0x85e5, 0x1078, 0x7583, 0x007c, 0x85ec, 0x85ec, 0x85ec,
+	0x85ec, 0x85ee, 0x8643, 0x85ec, 0x1078, 0x1328, 0x0f7e, 0x2c78,
+	0x1078, 0x4893, 0x0f7f, 0x0040, 0x8601, 0x6030, 0xa08c, 0xff00,
+	0x810f, 0xa186, 0x0039, 0x0040, 0x865a, 0xa186, 0x0035, 0x0040,
+	0x865a, 0x0d7e, 0x1078, 0x8bf4, 0x1078, 0x8a44, 0x0040, 0x8625,
+	0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0040, 0x8616,
+	0x684b, 0x0006, 0xc0ec, 0x6852, 0x0078, 0x8621, 0xd0bc, 0x0040,
+	0x861d, 0x684b, 0x0002, 0x0078, 0x8621, 0x684b, 0x0005, 0x1078,
+	0x8cc0, 0x6847, 0x0000, 0x1078, 0x4982, 0x2c68, 0x1078, 0x74d7,
+	0x0040, 0x863e, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xa88e,
+	0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x6918, 0x611a,
+	0x6920, 0x6122, 0x601f, 0x0001, 0x1078, 0x5bf8, 0x2d60, 0x1078,
+	0x753d, 0x0d7f, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f,
+	0x0040, 0x8680, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035,
+	0x0040, 0x865a, 0xa186, 0x001e, 0x0040, 0x865a, 0xa186, 0x0039,
+	0x00c0, 0x8680, 0x0d7e, 0x2c68, 0x1078, 0x8ef5, 0x00c0, 0x86a4,
+	0x1078, 0x74d7, 0x0040, 0x867d, 0x6106, 0x6003, 0x0001, 0x601f,
+	0x0001, 0x6918, 0x611a, 0x6928, 0x612a, 0x692c, 0x612e, 0x6930,
+	0xa18c, 0x00ff, 0x6132, 0x6934, 0x6136, 0x6938, 0x613a, 0x6920,
+	0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x2d60, 0x0078, 0x86a4,
+	0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86a4, 0x6837,
+	0x0103, 0x6850, 0xd0b4, 0x0040, 0x8693, 0xc0ec, 0x6852, 0x684b,
+	0x0006, 0x0078, 0x869e, 0xd0bc, 0x0040, 0x869a, 0x684b, 0x0002,
+	0x0078, 0x869e, 0x684b, 0x0005, 0x1078, 0x8cc0, 0x6847, 0x0000,
+	0x1078, 0x4982, 0x1078, 0x8bf4, 0x0d7f, 0x1078, 0x753d, 0x007c,
+	0x017e, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x86b8,
+	0x6837, 0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x1078, 0x4982,
+	0x0d7f, 0x017f, 0xa186, 0x0013, 0x0040, 0x86ca, 0xa186, 0x0014,
+	0x0040, 0x86ca, 0xa186, 0x0027, 0x0040, 0x86ca, 0x1078, 0x7583,
+	0x0078, 0x86d0, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109,
+	0x007c, 0x057e, 0x067e, 0x0d7e, 0x0f7e, 0x2029, 0x0001, 0xa182,
+	0x0101, 0x00c8, 0x86dd, 0x0078, 0x86df, 0x2009, 0x0100, 0x2130,
+	0x2069, 0xa898, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020, 0xaf90,
+	0x001d, 0x1078, 0x8739, 0xa6b2, 0x0020, 0x7804, 0xa06d, 0x0040,
+	0x86f3, 0x1078, 0x13aa, 0x1078, 0x1381, 0x0040, 0x871d, 0x8528,
+	0x6837, 0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d,
+	0x00c8, 0x8709, 0x2608, 0xad90, 0x000f, 0x1078, 0x8739, 0x0078,
+	0x871d, 0xa6b2, 0x003c, 0x2009, 0x003c, 0x2d78, 0xad90, 0x000f,
+	0x1078, 0x8739, 0x0078, 0x86f3, 0x0f7f, 0x852f, 0xa5ad, 0x0003,
+	0x7d36, 0xa5ac, 0x0000, 0x0078, 0x8722, 0x0f7f, 0x852f, 0xa5ad,
+	0x0003, 0x7d36, 0x0d7f, 0x067f, 0x057f, 0x007c, 0x0f7e, 0x8dff,
+	0x0040, 0x8737, 0x6804, 0xa07d, 0x0040, 0x8735, 0x6807, 0x0000,
+	0x1078, 0x4982, 0x2f68, 0x0078, 0x872a, 0x1078, 0x4982, 0x0f7f,
+	0x007c, 0x157e, 0xa184, 0x0001, 0x0040, 0x873f, 0x8108, 0x810c,
+	0x21a8, 0x2304, 0x8007, 0x2012, 0x8318, 0x8210, 0x00f0, 0x8741,
+	0x157f, 0x007c, 0x067e, 0x127e, 0x2091, 0x8000, 0x2031, 0x0001,
+	0x601c, 0xa084, 0x000f, 0x1079, 0x8766, 0x127f, 0x067f, 0x007c,
+	0x127e, 0x2091, 0x8000, 0x067e, 0x2031, 0x0000, 0x601c, 0xa084,
+	0x000f, 0x1079, 0x8766, 0x067f, 0x127f, 0x007c, 0x8780, 0x876e,
+	0x877b, 0x879c, 0x876e, 0x877b, 0x879c, 0x877b, 0x1078, 0x1328,
+	0x037e, 0x2019, 0x0010, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003,
+	0x0007, 0x037f, 0x007c, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c,
+	0x0d7e, 0x86ff, 0x00c0, 0x8797, 0x6010, 0x2068, 0x1078, 0x8a44,
+	0x0040, 0x8799, 0xa00e, 0x2001, 0x0005, 0x1078, 0x4a60, 0x1078,
+	0x8cc0, 0x1078, 0x4982, 0x1078, 0x753d, 0xa085, 0x0001, 0x0d7f,
+	0x007c, 0xa006, 0x0078, 0x8797, 0x6000, 0xa08a, 0x0010, 0x10c8,
+	0x1328, 0x1079, 0x87a4, 0x007c, 0x87b4, 0x87d4, 0x87b6, 0x87f7,
+	0x87d0, 0x87b4, 0x877b, 0x8780, 0x8780, 0x877b, 0x877b, 0x877b,
+	0x877b, 0x877b, 0x877b, 0x877b, 0x1078, 0x1328, 0x86ff, 0x00c0,
+	0x87cd, 0x0d7e, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x87c2,
+	0x1078, 0x8cc0, 0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f,
+	0x0002, 0x1078, 0x5bf8, 0x1078, 0x6109, 0xa085, 0x0001, 0x007c,
+	0x1078, 0x1749, 0x0078, 0x87b6, 0x0e7e, 0x2071, 0xa5ab, 0x7024,
+	0xac06, 0x00c0, 0x87dd, 0x1078, 0x6dda, 0x601c, 0xa084, 0x000f,
+	0xa086, 0x0006, 0x00c0, 0x87ef, 0x087e, 0x097e, 0x2049, 0x0001,
+	0x2c40, 0x1078, 0x7058, 0x097f, 0x087f, 0x0078, 0x87f1, 0x1078,
+	0x6cd2, 0x0e7f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c, 0x037e,
+	0x0e7e, 0x2071, 0xa5ab, 0x703c, 0xac06, 0x00c0, 0x8807, 0x2019,
+	0x0000, 0x1078, 0x6e6c, 0x0e7f, 0x037f, 0x0078, 0x87b6, 0x1078,
+	0x719a, 0x0e7f, 0x037f, 0x00c0, 0x87b6, 0x1078, 0x877b, 0x007c,
+	0x0c7e, 0x601c, 0xa084, 0x000f, 0x1079, 0x8818, 0x0c7f, 0x007c,
+	0x8827, 0x8895, 0x89cd, 0x8832, 0x8c01, 0x8827, 0x9a5b, 0x753d,
+	0x8895, 0x1078, 0x8c3b, 0x00c0, 0x8827, 0x1078, 0x7a05, 0x007c,
+	0x1078, 0x6010, 0x1078, 0x6109, 0x1078, 0x753d, 0x007c, 0x6017,
+	0x0001, 0x007c, 0x6010, 0xa080, 0x0019, 0x2c02, 0x6000, 0xa08a,
+	0x0010, 0x10c8, 0x1328, 0x1079, 0x883e, 0x007c, 0x884e, 0x8850,
+	0x8872, 0x8884, 0x8891, 0x884e, 0x8827, 0x8827, 0x8827, 0x8884,
+	0x8884, 0x884e, 0x884e, 0x884e, 0x884e, 0x888e, 0x1078, 0x1328,
+	0x0e7e, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071, 0xa5ab,
+	0x7024, 0xac06, 0x0040, 0x886e, 0x1078, 0x6cd2, 0x6007, 0x0085,
+	0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xa5a1, 0x2004, 0x6016,
+	0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x6017, 0x0001,
+	0x0078, 0x886c, 0x0d7e, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852,
+	0x0d7f, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x1078,
+	0x5bf8, 0x1078, 0x6109, 0x007c, 0x0d7e, 0x6017, 0x0001, 0x6010,
+	0x2068, 0x6850, 0xc0b5, 0x6852, 0x0d7f, 0x007c, 0x1078, 0x753d,
+	0x007c, 0x1078, 0x1749, 0x0078, 0x8872, 0x6000, 0xa08a, 0x0010,
+	0x10c8, 0x1328, 0x1079, 0x889d, 0x007c, 0x88ad, 0x882f, 0x88af,
+	0x88ad, 0x88af, 0x88af, 0x8828, 0x88ad, 0x8821, 0x8821, 0x88ad,
+	0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x88ad, 0x1078, 0x1328, 0x0d7e,
+	0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f, 0xa08a, 0x000c,
+	0x10c8, 0x1328, 0x1079, 0x88bd, 0x007c, 0x88c9, 0x8971, 0x88cb,
+	0x890b, 0x88cb, 0x890b, 0x88cb, 0x88d8, 0x88c9, 0x890b, 0x88c9,
+	0x88f5, 0x1078, 0x1328, 0x6004, 0xa08e, 0x0016, 0x0040, 0x8906,
+	0xa08e, 0x0004, 0x0040, 0x8906, 0xa08e, 0x0002, 0x0040, 0x8906,
+	0x6004, 0x1078, 0x8c3b, 0x0040, 0x898c, 0xa08e, 0x0021, 0x0040,
+	0x8990, 0xa08e, 0x0022, 0x0040, 0x898c, 0xa08e, 0x003d, 0x0040,
+	0x8990, 0xa08e, 0x0039, 0x0040, 0x8994, 0xa08e, 0x0035, 0x0040,
+	0x8994, 0xa08e, 0x001e, 0x0040, 0x8908, 0xa08e, 0x0001, 0x00c0,
+	0x8904, 0x0d7e, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x0d7f,
+	0xa086, 0x0006, 0x0040, 0x8906, 0x1078, 0x2813, 0x1078, 0x7a05,
+	0x1078, 0x8c01, 0x007c, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016,
+	0x0040, 0x8961, 0xa186, 0x0002, 0x00c0, 0x8934, 0x6018, 0x2068,
+	0x68a0, 0xd0bc, 0x00c0, 0x89b8, 0x6840, 0xa084, 0x00ff, 0xa005,
+	0x0040, 0x8934, 0x8001, 0x6842, 0x6013, 0x0000, 0x601f, 0x0007,
+	0x6017, 0x0398, 0x1078, 0x74d7, 0x0040, 0x8934, 0x2d00, 0x601a,
+	0x601f, 0x0001, 0x0078, 0x8961, 0x0d7f, 0x0c7f, 0x6004, 0xa08e,
+	0x0002, 0x00c0, 0x8952, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086,
+	0x007e, 0x00c0, 0x8952, 0x2009, 0xa332, 0x2104, 0xc085, 0x200a,
+	0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x0e7f, 0x1078, 0x7a05,
+	0x0078, 0x8956, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x2839, 0x127f, 0x0e7f, 0x1078, 0x8c01,
+	0x007c, 0x2001, 0x0002, 0x1078, 0x443f, 0x6003, 0x0001, 0x6007,
+	0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0d7f, 0x0c7f, 0x0078,
+	0x8960, 0x0c7e, 0x0d7e, 0x6104, 0xa186, 0x0016, 0x0040, 0x8961,
+	0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0040, 0x8934,
+	0x8001, 0x6842, 0x6003, 0x0001, 0x1078, 0x5c45, 0x1078, 0x6109,
+	0x0d7f, 0x0c7f, 0x0078, 0x8960, 0x1078, 0x7a05, 0x0078, 0x8908,
+	0x1078, 0x7a28, 0x0078, 0x8908, 0x0d7e, 0x2c68, 0x6104, 0x1078,
+	0x8ef5, 0x0d7f, 0x0040, 0x89a0, 0x1078, 0x753d, 0x0078, 0x89b7,
+	0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038, 0x600a, 0x2001,
+	0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c,
+	0x0d7f, 0x0c7f, 0x1078, 0x7a05, 0x1078, 0x2813, 0x0e7e, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x2839, 0x6013, 0x0000, 0x601f, 0x0007,
+	0x6017, 0x0398, 0x127f, 0x0e7f, 0x007c, 0x6000, 0xa08a, 0x0010,
+	0x10c8, 0x1328, 0x1079, 0x89d5, 0x007c, 0x89e5, 0x89e5, 0x89e5,
+	0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x89e5, 0x8827, 0x89e5,
+	0x882f, 0x89e7, 0x882f, 0x89f5, 0x89e5, 0x1078, 0x1328, 0x6004,
+	0xa086, 0x008b, 0x0040, 0x89f5, 0x6007, 0x008b, 0x6003, 0x000d,
+	0x1078, 0x5bf8, 0x1078, 0x6109, 0x007c, 0x1078, 0x8bf4, 0x1078,
+	0x8a44, 0x0040, 0x8a2d, 0x1078, 0x2813, 0x0d7e, 0x1078, 0x8a44,
+	0x0040, 0x8a0f, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006,
+	0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x1078, 0x4982, 0x2c68,
+	0x1078, 0x74d7, 0x0040, 0x8a1d, 0x6818, 0x601a, 0x0c7e, 0x2d60,
+	0x1078, 0x8c01, 0x0c7f, 0x0078, 0x8a1e, 0x2d60, 0x0d7f, 0x6013,
+	0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078,
+	0x5c45, 0x1078, 0x6109, 0x0078, 0x8a2f, 0x1078, 0x8c01, 0x007c,
+	0xa284, 0x000f, 0x00c0, 0x8a41, 0xa282, 0xaa00, 0x0048, 0x8a41,
+	0x2001, 0xa315, 0x2004, 0xa202, 0x00c8, 0x8a41, 0xa085, 0x0001,
+	0x007c, 0xa006, 0x0078, 0x8a40, 0x027e, 0x0e7e, 0x2071, 0xa300,
+	0x6210, 0x7058, 0xa202, 0x0048, 0x8a56, 0x705c, 0xa202, 0x00c8,
+	0x8a56, 0xa085, 0x0001, 0x0e7f, 0x027f, 0x007c, 0xa006, 0x0078,
+	0x8a53, 0x0e7e, 0x0c7e, 0x037e, 0x007e, 0x127e, 0x2091, 0x8000,
+	0x2061, 0xaa00, 0x2071, 0xa300, 0x7344, 0x7060, 0xa302, 0x00c8,
+	0x8a83, 0x601c, 0xa206, 0x00c0, 0x8a7b, 0x1078, 0x8d66, 0x0040,
+	0x8a7b, 0x1078, 0x8c3b, 0x00c0, 0x8a77, 0x1078, 0x7a05, 0x0c7e,
+	0x1078, 0x753d, 0x0c7f, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8,
+	0x8a83, 0x0078, 0x8a64, 0x127f, 0x007f, 0x037f, 0x0c7f, 0x0e7f,
+	0x007c, 0x0e7e, 0x0c7e, 0x017e, 0xa188, 0xa434, 0x210c, 0x81ff,
+	0x0040, 0x8aa1, 0x2061, 0xaa00, 0x2071, 0xa300, 0x017e, 0x1078,
+	0x74d7, 0x017f, 0x0040, 0x8aa4, 0x611a, 0x1078, 0x2813, 0x1078,
+	0x753d, 0xa006, 0x0078, 0x8aa6, 0xa085, 0x0001, 0x017f, 0x0c7f,
+	0x0e7f, 0x007c, 0x0c7e, 0x057e, 0x127e, 0x2091, 0x8000, 0x0c7e,
+	0x1078, 0x74d7, 0x057f, 0x0040, 0x8ac3, 0x6612, 0x651a, 0x601f,
+	0x0003, 0x2009, 0x004b, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f,
+	0x057f, 0x0c7f, 0x007c, 0xa006, 0x0078, 0x8abf, 0x0c7e, 0x057e,
+	0x127e, 0x2091, 0x8000, 0x62a0, 0x0c7e, 0x1078, 0x74d7, 0x057f,
+	0x0040, 0x8af1, 0x6013, 0x0000, 0x651a, 0x601f, 0x0003, 0x0c7e,
+	0x2560, 0x1078, 0x471b, 0x0c7f, 0x1078, 0x5d53, 0x077e, 0x2039,
+	0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2009,
+	0x004c, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x057f, 0x0c7f,
+	0x007c, 0xa006, 0x0078, 0x8aed, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e,
+	0x1078, 0x74d7, 0x2c78, 0x0c7f, 0x0040, 0x8b0e, 0x7e12, 0x2c00,
+	0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60,
+	0x2009, 0x004d, 0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f,
+	0x0f7f, 0x007c, 0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7,
+	0x2c78, 0x0c7f, 0x0040, 0x8b2c, 0x7e12, 0x2c00, 0x781a, 0x781f,
+	0x0003, 0x2021, 0x0005, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x004e,
+	0x1078, 0x756c, 0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c,
+	0x0f7e, 0x0c7e, 0x047e, 0x0c7e, 0x1078, 0x74d7, 0x2c78, 0x0c7f,
+	0x0040, 0x8b4a, 0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021,
+	0x0004, 0x1078, 0x8b4e, 0x2f60, 0x2009, 0x0052, 0x1078, 0x756c,
+	0xa085, 0x0001, 0x047f, 0x0c7f, 0x0f7f, 0x007c, 0x097e, 0x077e,
+	0x127e, 0x2091, 0x8000, 0x1078, 0x46a7, 0x0040, 0x8b5b, 0x2001,
+	0x8b53, 0x0078, 0x8b61, 0x1078, 0x466d, 0x0040, 0x8b6a, 0x2001,
+	0x8b5b, 0x007e, 0xa00e, 0x2400, 0x1078, 0x4a60, 0x1078, 0x4982,
+	0x007f, 0x007a, 0x2418, 0x1078, 0x5fa7, 0x62a0, 0x087e, 0x2041,
+	0x0001, 0x2039, 0x0001, 0x2608, 0x1078, 0x5d6d, 0x087f, 0x1078,
+	0x5c78, 0x2f08, 0x2648, 0x1078, 0x9c38, 0x613c, 0x81ff, 0x1040,
+	0x5e21, 0x127f, 0x077f, 0x097f, 0x007c, 0x0c7e, 0x127e, 0x2091,
+	0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8b9e, 0x660a,
+	0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x001f, 0x1078,
+	0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078,
+	0x8b9b, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7,
+	0x017f, 0x0040, 0x8bba, 0x660a, 0x611a, 0x601f, 0x0008, 0x2d00,
+	0x6012, 0x2009, 0x0021, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f,
+	0x0c7f, 0x007c, 0xa006, 0x0078, 0x8bb7, 0x0c7e, 0x127e, 0x2091,
+	0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8bd6, 0x660a,
+	0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x003d, 0x1078,
+	0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078,
+	0x8bd3, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7,
+	0x017f, 0x0040, 0x8bf1, 0x611a, 0x601f, 0x0001, 0x2d00, 0x6012,
+	0x2009, 0x0000, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f,
+	0x007c, 0xa006, 0x0078, 0x8bee, 0x027e, 0x0d7e, 0x6218, 0x2268,
+	0x6a3c, 0x82ff, 0x0040, 0x8bfe, 0x8211, 0x6a3e, 0x0d7f, 0x027f,
+	0x007c, 0x007e, 0x6000, 0xa086, 0x0000, 0x0040, 0x8c13, 0x6013,
+	0x0000, 0x601f, 0x0007, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078,
+	0xa134, 0x603f, 0x0000, 0x007f, 0x007c, 0x067e, 0x0c7e, 0x0d7e,
+	0x2031, 0xa352, 0x2634, 0xd6e4, 0x0040, 0x8c23, 0x6618, 0x2660,
+	0x6e48, 0x1078, 0x461b, 0x0d7f, 0x0c7f, 0x067f, 0x007c, 0x007e,
+	0x017e, 0x6004, 0xa08e, 0x0002, 0x0040, 0x8c38, 0xa08e, 0x0003,
+	0x0040, 0x8c38, 0xa08e, 0x0004, 0x0040, 0x8c38, 0xa085, 0x0001,
+	0x017f, 0x007f, 0x007c, 0x007e, 0x0d7e, 0x6010, 0xa06d, 0x0040,
+	0x8c48, 0x6838, 0xd0fc, 0x0040, 0x8c48, 0xa006, 0x0078, 0x8c4a,
+	0xa085, 0x0001, 0x0d7f, 0x007f, 0x007c, 0x0c7e, 0x127e, 0x2091,
+	0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8c67, 0x611a,
+	0x601f, 0x0001, 0x2d00, 0x6012, 0x1078, 0x2813, 0x2009, 0x0028,
+	0x1078, 0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006,
+	0x0078, 0x8c64, 0xa186, 0x0015, 0x00c0, 0x8c7f, 0x2011, 0xa31f,
+	0x2204, 0xa086, 0x0074, 0x00c0, 0x8c7f, 0x1078, 0x7d0d, 0x6003,
+	0x0001, 0x6007, 0x0029, 0x1078, 0x5c45, 0x0078, 0x8c83, 0x1078,
+	0x7a05, 0x1078, 0x753d, 0x007c, 0xa186, 0x0016, 0x00c0, 0x8c8e,
+	0x2001, 0x0004, 0x1078, 0x443f, 0x0078, 0x8caf, 0xa186, 0x0015,
+	0x00c0, 0x8cb3, 0x2011, 0xa31f, 0x2204, 0xa086, 0x0014, 0x00c0,
+	0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x1078, 0x457d, 0x0d7f, 0x1078,
+	0x7dba, 0x00c0, 0x8cb3, 0x0d7e, 0x6018, 0x2068, 0x6890, 0x0d7f,
+	0xa005, 0x0040, 0x8cb3, 0x2001, 0x0006, 0x1078, 0x443f, 0x1078,
+	0x7608, 0x0078, 0x8cb7, 0x1078, 0x7a05, 0x1078, 0x753d, 0x007c,
+	0x6848, 0xa086, 0x0005, 0x00c0, 0x8cbf, 0x1078, 0x8cc0, 0x007c,
+	0x6850, 0xc0ad, 0x6852, 0x007c, 0x0e7e, 0x2071, 0xa88c, 0x7014,
+	0xd0e4, 0x0040, 0x8cd5, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007,
+	0x0050, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x007c, 0x0c7e,
+	0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x0040, 0x8ce4, 0x601c,
+	0xa084, 0x000f, 0x1079, 0x8ce6, 0x0c7f, 0x007c, 0x8827, 0x8cf1,
+	0x8cf4, 0x8cf7, 0x9f00, 0x9f1c, 0x9f1f, 0x8827, 0x8827, 0x1078,
+	0x1328, 0x0005, 0x0005, 0x007c, 0x0005, 0x0005, 0x007c, 0x1078,
+	0x8cfa, 0x007c, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0040, 0x8d29,
+	0x1078, 0x74d7, 0x00c0, 0x8d0a, 0x2001, 0xa5a2, 0x2004, 0x783e,
+	0x0078, 0x8d29, 0x7818, 0x601a, 0x781c, 0xa086, 0x0003, 0x0040,
+	0x8d17, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0078, 0x8d1b, 0x7808,
+	0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007, 0x0035,
+	0x6003, 0x0001, 0x7920, 0x6122, 0x1078, 0x5bf8, 0x1078, 0x6109,
+	0x2f60, 0x0f7f, 0x007c, 0x017e, 0x0f7e, 0x682c, 0x6032, 0xa08e,
+	0x0001, 0x0040, 0x8d3c, 0xa086, 0x0005, 0x0040, 0x8d40, 0xa006,
+	0x602a, 0x602e, 0x0078, 0x8d51, 0x6824, 0xc0f4, 0xc0d5, 0x6826,
+	0x6810, 0x2078, 0x787c, 0x6938, 0xa102, 0x7880, 0x6934, 0xa103,
+	0x00c8, 0x8d37, 0x6834, 0x602a, 0x6838, 0xa084, 0xfffc, 0x683a,
+	0x602e, 0x2d00, 0x6036, 0x6808, 0x603a, 0x6918, 0x611a, 0x6920,
+	0x6122, 0x601f, 0x0001, 0x6007, 0x0039, 0x6003, 0x0001, 0x1078,
+	0x5bf8, 0x6803, 0x0002, 0x0f7f, 0x017f, 0x007c, 0x007e, 0x017e,
+	0x6004, 0xa08e, 0x0034, 0x0040, 0x8d8b, 0xa08e, 0x0035, 0x0040,
+	0x8d8b, 0xa08e, 0x0036, 0x0040, 0x8d8b, 0xa08e, 0x0037, 0x0040,
+	0x8d8b, 0xa08e, 0x0038, 0x0040, 0x8d8b, 0xa08e, 0x0039, 0x0040,
+	0x8d8b, 0xa08e, 0x003a, 0x0040, 0x8d8b, 0xa08e, 0x003b, 0x0040,
+	0x8d8b, 0xa085, 0x0001, 0x017f, 0x007f, 0x007c, 0x0f7e, 0x2c78,
+	0x1078, 0x4893, 0x00c0, 0x8d98, 0xa085, 0x0001, 0x0078, 0x8da7,
+	0x6024, 0xd0f4, 0x00c0, 0x8da6, 0xc0f5, 0x6026, 0x6010, 0x2078,
+	0x7828, 0x603a, 0x782c, 0x6036, 0x1078, 0x1749, 0xa006, 0x0f7f,
+	0x007c, 0x007e, 0x017e, 0x027e, 0x037e, 0x0e7e, 0x2001, 0xa59c,
+	0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x1078, 0x5a98, 0x2001,
+	0xa5a0, 0x82ff, 0x00c0, 0x8dbe, 0x2011, 0x0002, 0x2202, 0x2001,
+	0xa59e, 0x200c, 0x8000, 0x2014, 0x2071, 0xa58c, 0x711a, 0x721e,
+	0x2001, 0x0064, 0x1078, 0x5a98, 0x2001, 0xa5a1, 0x82ff, 0x00c0,
+	0x8dd3, 0x2011, 0x0002, 0x2202, 0x2009, 0xa5a2, 0xa280, 0x000a,
+	0x200a, 0x0e7f, 0x037f, 0x027f, 0x017f, 0x007f, 0x007c, 0x007e,
+	0x0e7e, 0x2001, 0xa5a0, 0x2003, 0x0028, 0x2001, 0xa5a1, 0x2003,
+	0x0014, 0x2071, 0xa58c, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001,
+	0xa5a2, 0x2003, 0x001e, 0x0e7f, 0x007f, 0x007c, 0x0c7e, 0x127e,
+	0x2091, 0x8000, 0x0c7e, 0x1078, 0x74d7, 0x017f, 0x0040, 0x8e0e,
+	0x611a, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033, 0x1078,
+	0x756c, 0xa085, 0x0001, 0x127f, 0x0c7f, 0x007c, 0xa006, 0x0078,
+	0x8e0b, 0x0d7e, 0x0e7e, 0x0f7e, 0x2071, 0xa300, 0xa186, 0x0015,
+	0x00c0, 0x8e40, 0x707c, 0xa086, 0x0018, 0x00c0, 0x8e40, 0x6010,
+	0x2068, 0x6a3c, 0xd2e4, 0x00c0, 0x8e34, 0x2c78, 0x1078, 0x62c6,
+	0x0040, 0x8e48, 0x7068, 0x6a50, 0xa206, 0x00c0, 0x8e3c, 0x706c,
+	0x6a54, 0xa206, 0x00c0, 0x8e3c, 0x6218, 0xa290, 0x0028, 0x2214,
+	0x2009, 0x0000, 0x1078, 0x285b, 0x1078, 0x7608, 0x0078, 0x8e44,
+	0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f, 0x0e7f, 0x0d7f, 0x007c,
+	0x704c, 0xa080, 0x293f, 0x2004, 0x6a54, 0xa206, 0x0040, 0x8e34,
+	0x0078, 0x8e3c, 0x0c7e, 0x127e, 0x2091, 0x8000, 0x0c7e, 0x1078,
+	0x74d7, 0x017f, 0x0040, 0x8e6a, 0x611a, 0x601f, 0x0001, 0x2d00,
+	0x6012, 0x2009, 0x0043, 0x1078, 0x756c, 0xa085, 0x0001, 0x127f,
+	0x0c7f, 0x007c, 0xa006, 0x0078, 0x8e67, 0x0d7e, 0x0e7e, 0x0f7e,
+	0x2071, 0xa300, 0xa186, 0x0015, 0x00c0, 0x8e93, 0x707c, 0xa086,
+	0x0004, 0x00c0, 0x8e93, 0x6010, 0xa0e8, 0x000f, 0x2c78, 0x1078,
+	0x62c6, 0x0040, 0x8e9b, 0x7068, 0x6a08, 0xa206, 0x00c0, 0x8e8f,
+	0x706c, 0x6a0c, 0xa206, 0x00c0, 0x8e8f, 0x1078, 0x2813, 0x1078,
+	0x7608, 0x0078, 0x8e97, 0x1078, 0x7a05, 0x1078, 0x753d, 0x0f7f,
+	0x0e7f, 0x0d7f, 0x007c, 0x704c, 0xa080, 0x293f, 0x2004, 0x6a0c,
+	0xa206, 0x0040, 0x8e8d, 0x0078, 0x8e8f, 0x017e, 0x027e, 0x684c,
+	0xd0ac, 0x0040, 0x8ebd, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0040,
+	0x8ebd, 0x6860, 0xa106, 0x00c0, 0x8eb9, 0x685c, 0xa206, 0x0040,
+	0x8ebd, 0x6962, 0x6a5e, 0xa085, 0x0001, 0x027f, 0x017f, 0x007c,
+	0x0e7e, 0x127e, 0x2071, 0xa300, 0x2091, 0x8000, 0x7544, 0xa582,
+	0x0001, 0x0048, 0x8ef2, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000,
+	0x0040, 0x8ede, 0xace0, 0x0010, 0x7054, 0xac02, 0x00c8, 0x8eda,
+	0x0078, 0x8ecd, 0x2061, 0xaa00, 0x0078, 0x8ecd, 0x6003, 0x0008,
+	0x8529, 0x7546, 0xaca8, 0x0010, 0x7054, 0xa502, 0x00c8, 0x8eee,
+	0x754a, 0xa085, 0x0001, 0x127f, 0x0e7f, 0x007c, 0x704b, 0xaa00,
+	0x0078, 0x8ee9, 0xa006, 0x0078, 0x8eeb, 0x0c7e, 0x027e, 0x017e,
+	0xa186, 0x0035, 0x0040, 0x8eff, 0x6a34, 0x0078, 0x8f00, 0x6a28,
+	0x1078, 0x8a30, 0x0040, 0x8f29, 0x2260, 0x611c, 0xa186, 0x0003,
+	0x0040, 0x8f0e, 0xa186, 0x0006, 0x00c0, 0x8f25, 0x6834, 0xa206,
+	0x0040, 0x8f1d, 0x6838, 0xa206, 0x00c0, 0x8f25, 0x6108, 0x6834,
+	0xa106, 0x00c0, 0x8f25, 0x0078, 0x8f22, 0x6008, 0x6938, 0xa106,
+	0x00c0, 0x8f25, 0x6018, 0x6918, 0xa106, 0x017f, 0x027f, 0x0c7f,
+	0x007c, 0xa085, 0x0001, 0x0078, 0x8f25, 0x067e, 0x6000, 0xa0b2,
+	0x0010, 0x10c8, 0x1328, 0x1079, 0x8f37, 0x067f, 0x007c, 0x8f47,
+	0x93bb, 0x94d3, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f81,
+	0x955e, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x8f47, 0x1078,
+	0x1328, 0x067e, 0x6000, 0xa0b2, 0x0010, 0x10c8, 0x1328, 0x1079,
+	0x8f53, 0x067f, 0x007c, 0x8f63, 0x99f6, 0x8f63, 0x8f63, 0x8f63,
+	0x8f63, 0x8f63, 0x8f63, 0x99b4, 0x9a44, 0x8f63, 0xa053, 0xa087,
+	0xa053, 0xa087, 0x8f63, 0x1078, 0x1328, 0x067e, 0x6000, 0xa0b2,
+	0x0010, 0x10c8, 0x1328, 0x1079, 0x8f6f, 0x067f, 0x007c, 0x8f7f,
+	0x969f, 0x976a, 0x9798, 0x9813, 0x8f7f, 0x9919, 0x98c1, 0x956a,
+	0x9988, 0x999e, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x8f7f, 0x1078,
+	0x1328, 0xa1b2, 0x0044, 0x10c8, 0x1328, 0x2100, 0x0079, 0x8f88,
+	0x8fc8, 0x919a, 0x8fc8, 0x8fc8, 0x8fc8, 0x91a2, 0x8fc8, 0x8fc8,
+	0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8,
+	0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fca,
+	0x902d, 0x9038, 0x9081, 0x909c, 0x911b, 0x918b, 0x8fc8, 0x8fc8,
+	0x91a6, 0x8fc8, 0x8fc8, 0x91b5, 0x91bc, 0x8fc8, 0x8fc8, 0x8fc8,
+	0x8fc8, 0x8fc8, 0x91ea, 0x8fc8, 0x8fc8, 0x91f5, 0x8fc8, 0x8fc8,
+	0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x920a, 0x8fc8, 0x8fc8, 0x8fc8,
+	0x9291, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x8fc8, 0x9305,
+	0x1078, 0x1328, 0x1078, 0x4897, 0x00c0, 0x8fd7, 0x2001, 0xa332,
+	0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x8fdf, 0x6007,
+	0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195, 0x1078,
+	0x4887, 0x0e7e, 0x0c7e, 0x037e, 0x027e, 0x017e, 0x6218, 0x2270,
+	0x72a0, 0x027e, 0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039,
+	0x0000, 0x1078, 0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x017f,
+	0x2e60, 0x1078, 0x471b, 0x017f, 0x027f, 0x037f, 0x0c7f, 0x0e7f,
+	0x6618, 0x0c7e, 0x2660, 0x1078, 0x4513, 0x0c7f, 0xa6b0, 0x0001,
+	0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0048, 0x901f, 0x1078,
+	0x9b6c, 0x00c0, 0x907b, 0x1078, 0x9afd, 0x00c0, 0x901b, 0x6007,
+	0x0008, 0x0078, 0x9195, 0x6007, 0x0009, 0x0078, 0x9195, 0x1078,
+	0x9d45, 0x0040, 0x9029, 0x1078, 0x9b6c, 0x0040, 0x9013, 0x0078,
+	0x907b, 0x6013, 0x1900, 0x0078, 0x901b, 0x6106, 0x1078, 0x9aa8,
+	0x6007, 0x0006, 0x0078, 0x9195, 0x6007, 0x0007, 0x0078, 0x9195,
+	0x1078, 0xa0bf, 0x00c0, 0x9340, 0x0d7e, 0x6618, 0x2668, 0x6e04,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x905d, 0xa686,
+	0x0004, 0x0040, 0x905d, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006,
+	0x0040, 0x905d, 0xa686, 0x0004, 0x0040, 0x905d, 0xa686, 0x0005,
+	0x0040, 0x905d, 0x0d7f, 0x0078, 0x907b, 0x1078, 0x9bd2, 0x00c0,
+	0x9076, 0xa686, 0x0006, 0x00c0, 0x906f, 0x027e, 0x6218, 0xa290,
+	0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f, 0x1078,
+	0x457d, 0x6007, 0x000a, 0x0d7f, 0x0078, 0x9195, 0x6007, 0x000b,
+	0x0d7f, 0x0078, 0x9195, 0x1078, 0x2813, 0x6007, 0x0001, 0x0078,
+	0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x6618, 0x0d7e, 0x2668,
+	0x6e04, 0x0d7f, 0xa686, 0x0707, 0x0040, 0x907b, 0x027e, 0x6218,
+	0xa290, 0x0028, 0x2214, 0x2009, 0x0000, 0x1078, 0x285b, 0x027f,
+	0x6007, 0x000c, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x90a9,
+	0x2001, 0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0,
+	0x90b1, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078,
+	0x9195, 0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684,
+	0x00ff, 0xa082, 0x0006, 0x0048, 0x90f5, 0xa6b4, 0xff00, 0x8637,
+	0xa686, 0x0004, 0x0040, 0x90c8, 0xa686, 0x0006, 0x00c0, 0x907b,
+	0x1078, 0x9be1, 0x00c0, 0x90d0, 0x6007, 0x000e, 0x0078, 0x9195,
+	0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff, 0x8427,
+	0x047e, 0x1078, 0x2813, 0x047f, 0x017e, 0xa006, 0x2009, 0xa352,
+	0x210c, 0xd1a4, 0x0040, 0x90ef, 0x2009, 0x0029, 0x1078, 0x9ec0,
+	0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x0d7f, 0x017f,
+	0x047f, 0x6007, 0x0001, 0x0078, 0x9195, 0x2001, 0x0001, 0x1078,
+	0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019,
+	0xa305, 0x2011, 0xa890, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f,
+	0x157f, 0xa005, 0x0040, 0x9115, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0006, 0x0040, 0x90c8, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007,
+	0x0009, 0x0078, 0x9195, 0x1078, 0x4897, 0x00c0, 0x9128, 0x2001,
+	0xa332, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008, 0x00c0, 0x9130,
+	0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0078, 0x9195,
+	0x1078, 0x4887, 0x6618, 0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff,
+	0xa082, 0x0006, 0x0048, 0x9178, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0004, 0x0040, 0x9147, 0xa686, 0x0006, 0x00c0, 0x907b, 0x1078,
+	0x9c0c, 0x00c0, 0x9153, 0x1078, 0x9afd, 0x00c0, 0x9153, 0x6007,
+	0x0010, 0x0078, 0x9195, 0x047e, 0x6418, 0xa4a0, 0x0028, 0x2424,
+	0xa4a4, 0x00ff, 0x8427, 0x047e, 0x1078, 0x2813, 0x047f, 0x017e,
+	0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040, 0x9172, 0x2009,
+	0x0029, 0x1078, 0x9ec0, 0x6018, 0x0d7e, 0x2068, 0x6800, 0xc0e5,
+	0x6802, 0x0d7f, 0x017f, 0x047f, 0x6007, 0x0001, 0x0078, 0x9195,
+	0x1078, 0x9d45, 0x0040, 0x9185, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0006, 0x0040, 0x9147, 0x0078, 0x907b, 0x6013, 0x1900, 0x6007,
+	0x0009, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0, 0x9340, 0x1078,
+	0x9343, 0x00c0, 0x907b, 0x6007, 0x0012, 0x6003, 0x0001, 0x1078,
+	0x5c45, 0x007c, 0x6007, 0x0001, 0x6003, 0x0001, 0x1078, 0x5c45,
+	0x0078, 0x9199, 0x6007, 0x0005, 0x0078, 0x919c, 0x1078, 0xa0bf,
+	0x00c0, 0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6007, 0x0020,
+	0x6003, 0x0001, 0x1078, 0x5c45, 0x007c, 0x6007, 0x0023, 0x6003,
+	0x0001, 0x1078, 0x5c45, 0x007c, 0x1078, 0xa0bf, 0x00c0, 0x9340,
+	0x1078, 0x9343, 0x00c0, 0x907b, 0x017e, 0x027e, 0x2011, 0xa890,
+	0x2214, 0x2c08, 0x1078, 0x9e8c, 0x00c0, 0x91de, 0x2160, 0x6007,
+	0x0026, 0x6013, 0x1700, 0x2011, 0xa889, 0x2214, 0xa296, 0xffff,
+	0x00c0, 0x91e3, 0x6007, 0x0025, 0x0078, 0x91e3, 0x1078, 0x753d,
+	0x2160, 0x6007, 0x0025, 0x6003, 0x0001, 0x1078, 0x5c45, 0x027f,
+	0x017f, 0x007c, 0x6106, 0x1078, 0x9363, 0x6007, 0x002b, 0x0078,
+	0x9195, 0x6007, 0x002c, 0x0078, 0x9195, 0x1078, 0xa0bf, 0x00c0,
+	0x9340, 0x1078, 0x9343, 0x00c0, 0x907b, 0x6106, 0x1078, 0x9368,
+	0x00c0, 0x9206, 0x6007, 0x002e, 0x0078, 0x9195, 0x6007, 0x002f,
+	0x0078, 0x9195, 0x0e7e, 0x0d7e, 0x0c7e, 0x6018, 0xa080, 0x0001,
+	0x200c, 0xa184, 0x00ff, 0xa086, 0x0006, 0x0040, 0x9223, 0xa184,
+	0xff00, 0x8007, 0xa086, 0x0006, 0x0040, 0x9223, 0x0c7f, 0x0d7f,
+	0x0e7f, 0x0078, 0x919a, 0x2001, 0xa371, 0x2004, 0xd0e4, 0x0040,
+	0x928d, 0x2071, 0xa88c, 0x7010, 0x6036, 0x7014, 0x603a, 0x7108,
+	0x720c, 0x2001, 0xa352, 0x2004, 0xd0a4, 0x0040, 0x9241, 0x6018,
+	0x2068, 0x6810, 0xa106, 0x00c0, 0x9241, 0x6814, 0xa206, 0x0040,
+	0x9265, 0x2001, 0xa352, 0x2004, 0xd0ac, 0x00c0, 0x9281, 0x2069,
+	0xa300, 0x686c, 0xa206, 0x00c0, 0x9281, 0x6868, 0xa106, 0x00c0,
+	0x9281, 0x7210, 0x1078, 0x8a30, 0x0040, 0x9287, 0x1078, 0x9f31,
+	0x0040, 0x9287, 0x622a, 0x6007, 0x0036, 0x6003, 0x0001, 0x1078,
+	0x5bf8, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x7214, 0xa286, 0xffff,
+	0x0040, 0x9277, 0x1078, 0x8a30, 0x0040, 0x9287, 0xa280, 0x0002,
+	0x2004, 0x7110, 0xa106, 0x00c0, 0x9287, 0x0078, 0x9252, 0x7210,
+	0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x2160, 0x0040, 0x9287, 0x0078,
+	0x9252, 0x6007, 0x0037, 0x6013, 0x1500, 0x0078, 0x925d, 0x6007,
+	0x0037, 0x6013, 0x1700, 0x0078, 0x925d, 0x6007, 0x0012, 0x0078,
+	0x925d, 0x6018, 0xa080, 0x0001, 0x2004, 0xa084, 0xff00, 0x8007,
+	0xa086, 0x0006, 0x00c0, 0x919a, 0x0e7e, 0x0d7e, 0x0c7e, 0x2001,
+	0xa371, 0x2004, 0xd0e4, 0x0040, 0x92fd, 0x2069, 0xa300, 0x2071,
+	0xa88c, 0x7008, 0x6036, 0x720c, 0x623a, 0xa286, 0xffff, 0x00c0,
+	0x92ba, 0x7208, 0x0c7e, 0x2c08, 0x1078, 0x9e8c, 0x2c10, 0x0c7f,
+	0x0040, 0x92f1, 0x1078, 0x8a30, 0x0040, 0x92f1, 0x0c7e, 0x027e,
+	0x2260, 0x1078, 0x874a, 0x027f, 0x0c7f, 0x7118, 0xa18c, 0xff00,
+	0x810f, 0xa186, 0x0001, 0x0040, 0x92db, 0xa186, 0x0005, 0x0040,
+	0x92d5, 0xa186, 0x0007, 0x00c0, 0x92e5, 0xa280, 0x0004, 0x2004,
+	0xa005, 0x0040, 0x92e5, 0x057e, 0x7510, 0x7614, 0x1078, 0x9f46,
+	0x057f, 0x0c7f, 0x0d7f, 0x0e7f, 0x007c, 0x6007, 0x003b, 0x602b,
+	0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x0078,
+	0x92e1, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x1700, 0x6003,
+	0x0001, 0x1078, 0x5bf8, 0x0078, 0x92e1, 0x6007, 0x003b, 0x602b,
+	0x000b, 0x6013, 0x0000, 0x0078, 0x925d, 0x0e7e, 0x027e, 0x1078,
+	0x4897, 0x0040, 0x933a, 0x1078, 0x4887, 0x1078, 0xa148, 0x00c0,
+	0x9338, 0x2071, 0xa300, 0x70c8, 0xc085, 0x70ca, 0x0f7e, 0x2079,
+	0x0100, 0x7294, 0xa284, 0x00ff, 0x706a, 0x78e6, 0xa284, 0xff00,
+	0x726c, 0xa205, 0x706e, 0x78ea, 0x0f7f, 0x70d3, 0x0000, 0x2001,
+	0xa352, 0x2004, 0xd0a4, 0x0040, 0x9331, 0x2011, 0xa5c4, 0x2013,
+	0x07d0, 0xd0ac, 0x00c0, 0x933a, 0x1078, 0x260d, 0x0078, 0x933a,
+	0x1078, 0xa178, 0x027f, 0x0e7f, 0x1078, 0x753d, 0x0078, 0x9199,
+	0x1078, 0x753d, 0x007c, 0x0d7e, 0x067e, 0x6618, 0x2668, 0x6e04,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x9360, 0xa686,
+	0x0004, 0x0040, 0x9360, 0x6e04, 0xa6b4, 0x00ff, 0xa686, 0x0006,
+	0x0040, 0x9360, 0xa686, 0x0004, 0x0040, 0x9360, 0xa085, 0x0001,
+	0x067f, 0x0d7f, 0x007c, 0x0d7e, 0x1078, 0x9397, 0x0d7f, 0x007c,
+	0x0d7e, 0x1078, 0x93a6, 0x00c0, 0x9390, 0x680c, 0xa08c, 0xff00,
+	0x6820, 0xa084, 0x00ff, 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4,
+	0x0040, 0x937e, 0x2009, 0x0001, 0x0078, 0x938c, 0xd1ec, 0x0040,
+	0x9390, 0x6920, 0xa18c, 0x00ff, 0x6824, 0x1078, 0x24e3, 0x00c0,
+	0x9390, 0x2110, 0x2009, 0x0000, 0x1078, 0x285b, 0x0078, 0x9394,
+	0xa085, 0x0001, 0x0078, 0x9395, 0xa006, 0x0d7f, 0x007c, 0x2069,
+	0xa88d, 0x6800, 0xa082, 0x0010, 0x00c8, 0x93a4, 0x6013, 0x0000,
+	0xa085, 0x0001, 0x0078, 0x93a5, 0xa006, 0x007c, 0x6013, 0x0000,
+	0x2069, 0xa88c, 0x6808, 0xa084, 0xff00, 0xa086, 0x0800, 0x00c0,
+	0x93ba, 0x6800, 0xa084, 0x00ff, 0xa08e, 0x0014, 0x0040, 0x93ba,
+	0xa08e, 0x0010, 0x007c, 0x6004, 0xa0b2, 0x0044, 0x10c8, 0x1328,
+	0xa1b6, 0x0013, 0x00c0, 0x93c7, 0x2008, 0x0079, 0x93da, 0xa1b6,
+	0x0027, 0x0040, 0x93cf, 0xa1b6, 0x0014, 0x10c0, 0x1328, 0x2001,
+	0x0007, 0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078,
+	0x6109, 0x007c, 0x941a, 0x941c, 0x941a, 0x941a, 0x941a, 0x941c,
+	0x9424, 0x94ae, 0x9471, 0x94ae, 0x9485, 0x94ae, 0x9424, 0x94ae,
+	0x94a6, 0x94ae, 0x94a6, 0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a,
+	0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a,
+	0x941c, 0x941a, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x941a, 0x94ae,
+	0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a,
+	0x94ae, 0x94ae, 0x941a, 0x941a, 0x941a, 0x941a, 0x941a, 0x941c,
+	0x94ae, 0x94ae, 0x941a, 0x941a, 0x94ae, 0x94ae, 0x941a, 0x941a,
+	0x941a, 0x941a, 0x1078, 0x1328, 0x1078, 0x6010, 0x6003, 0x0002,
+	0x1078, 0x6109, 0x0078, 0x94b4, 0x0f7e, 0x2079, 0xa351, 0x7804,
+	0x0f7f, 0xd0ac, 0x00c0, 0x94ae, 0x2001, 0x0000, 0x1078, 0x442b,
+	0x6018, 0xa080, 0x0004, 0x2004, 0xa086, 0x00ff, 0x0040, 0x94ae,
+	0x0c7e, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x00c0, 0x9448, 0x6010,
+	0xa005, 0x0040, 0x9448, 0x0c7f, 0x1078, 0x35f7, 0x0078, 0x94ae,
+	0x0c7f, 0x2001, 0xa300, 0x2004, 0xa086, 0x0002, 0x00c0, 0x9457,
+	0x0f7e, 0x2079, 0xa300, 0x788c, 0x8000, 0x788e, 0x0f7f, 0x2001,
+	0x0002, 0x1078, 0x443f, 0x1078, 0x6010, 0x601f, 0x0001, 0x6003,
+	0x0001, 0x6007, 0x0002, 0x1078, 0x5c45, 0x1078, 0x6109, 0x0c7e,
+	0x6118, 0x2160, 0x2009, 0x0001, 0x1078, 0x58e1, 0x0c7f, 0x0078,
+	0x94b4, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0xa686, 0x0004, 0x0040,
+	0x94ae, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0xa300, 0x2004,
+	0xa086, 0x0003, 0x00c0, 0x948e, 0x1078, 0x35f7, 0x2001, 0x0006,
+	0x1078, 0x94b5, 0x6618, 0x0d7e, 0x2668, 0x6e04, 0x0d7f, 0xa6b4,
+	0xff00, 0x8637, 0xa686, 0x0006, 0x0040, 0x94ae, 0x2001, 0x0006,
+	0x0078, 0x94ac, 0x2001, 0x0004, 0x0078, 0x94ac, 0x2001, 0x0006,
+	0x1078, 0x94b5, 0x0078, 0x94ae, 0x1078, 0x4472, 0x1078, 0x6010,
+	0x1078, 0x753d, 0x1078, 0x6109, 0x007c, 0x017e, 0x0d7e, 0x6118,
+	0x2168, 0x6900, 0xd184, 0x0040, 0x94d0, 0x6104, 0xa18e, 0x000a,
+	0x00c0, 0x94c8, 0x699c, 0xd1a4, 0x00c0, 0x94c8, 0x2001, 0x0007,
+	0x1078, 0x443f, 0x2001, 0x0000, 0x1078, 0x442b, 0x1078, 0x2839,
+	0x0d7f, 0x017f, 0x007c, 0x0d7e, 0x6618, 0x2668, 0x6804, 0xa084,
+	0xff00, 0x8007, 0x0d7f, 0xa0b2, 0x000c, 0x10c8, 0x1328, 0xa1b6,
+	0x0015, 0x00c0, 0x94e7, 0x1079, 0x94ee, 0x0078, 0x94ed, 0xa1b6,
+	0x0016, 0x10c0, 0x1328, 0x1079, 0x94fa, 0x007c, 0x7ad0, 0x7ad0,
+	0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x9547, 0x9506, 0x7ad0, 0x7ad0,
+	0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0,
+	0x9547, 0x954f, 0x7ad0, 0x7ad0, 0x7ad0, 0x7ad0, 0x0f7e, 0x2079,
+	0xa351, 0x7804, 0xd0ac, 0x00c0, 0x952d, 0x6018, 0xa07d, 0x0040,
+	0x952d, 0x7800, 0xd0f4, 0x00c0, 0x9519, 0x7810, 0xa005, 0x00c0,
+	0x952d, 0x2001, 0x0000, 0x1078, 0x442b, 0x2001, 0x0002, 0x1078,
+	0x443f, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x1078,
+	0x5c45, 0x1078, 0x6109, 0x0078, 0x9545, 0x2011, 0xa883, 0x2204,
+	0x8211, 0x220c, 0x1078, 0x24e3, 0x00c0, 0x9545, 0x0c7e, 0x1078,
+	0x4501, 0x0040, 0x9540, 0x0c7f, 0x1078, 0x753d, 0x0078, 0x9545,
+	0x1078, 0x4235, 0x0c7f, 0x1078, 0x753d, 0x0f7f, 0x007c, 0x6604,
+	0xa6b6, 0x001e, 0x00c0, 0x954e, 0x1078, 0x753d, 0x007c, 0x1078,
+	0x7d0a, 0x00c0, 0x955b, 0x6003, 0x0001, 0x6007, 0x0001, 0x1078,
+	0x5c45, 0x0078, 0x955d, 0x1078, 0x753d, 0x007c, 0x6004, 0xa08a,
+	0x0044, 0x10c8, 0x1328, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078,
+	0x6109, 0x007c, 0xa182, 0x0040, 0x0079, 0x956e, 0x9581, 0x9581,
+	0x9581, 0x9581, 0x9583, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581,
+	0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581, 0x9581,
+	0x9581, 0x1078, 0x1328, 0x0d7e, 0x0e7e, 0x0f7e, 0x157e, 0x047e,
+	0x027e, 0x6218, 0xa280, 0x002b, 0x2004, 0xa005, 0x0040, 0x9594,
+	0x2021, 0x0000, 0x1078, 0xa111, 0x6106, 0x2071, 0xa880, 0x7444,
+	0xa4a4, 0xff00, 0x0040, 0x95eb, 0xa486, 0x2000, 0x00c0, 0x95a6,
+	0x2009, 0x0001, 0x2011, 0x0200, 0x1078, 0x5a6d, 0x1078, 0x1381,
+	0x1040, 0x1328, 0x6003, 0x0007, 0x2d00, 0x6837, 0x010d, 0x6803,
+	0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e, 0x6008, 0x68b2,
+	0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a, 0x017e, 0xa084,
+	0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036, 0x1078, 0x4982,
+	0x017f, 0xa486, 0x2000, 0x00c0, 0x95d3, 0x2019, 0x0017, 0x1078,
+	0x9e3b, 0x0078, 0x9645, 0xa486, 0x0400, 0x00c0, 0x95dd, 0x2019,
+	0x0002, 0x1078, 0x9dec, 0x0078, 0x9645, 0xa486, 0x0200, 0x00c0,
+	0x95e3, 0x1078, 0x9dd1, 0xa486, 0x1000, 0x00c0, 0x95e9, 0x1078,
+	0x9e20, 0x0078, 0x9645, 0x2069, 0xa62d, 0x6a00, 0xd284, 0x0040,
+	0x969b, 0xa284, 0x0300, 0x00c0, 0x9693, 0x6804, 0xa005, 0x0040,
+	0x9683, 0x2d78, 0x6003, 0x0007, 0x1078, 0x1366, 0x0040, 0x964c,
+	0x7800, 0xd08c, 0x00c0, 0x9607, 0x7804, 0x8001, 0x7806, 0x6013,
+	0x0000, 0x6803, 0x0000, 0x6837, 0x0116, 0x683b, 0x0000, 0x6008,
+	0x68b2, 0x2c00, 0x684a, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130,
+	0x6986, 0x6846, 0x6853, 0x003d, 0x7244, 0xa294, 0x0003, 0xa286,
+	0x0002, 0x00c0, 0x9627, 0x684f, 0x0040, 0x0078, 0x9631, 0xa286,
+	0x0001, 0x00c0, 0x962f, 0x684f, 0x0080, 0x0078, 0x9631, 0x684f,
+	0x0000, 0x20a9, 0x000a, 0x2001, 0xa890, 0xad90, 0x0015, 0x200c,
+	0x810f, 0x2112, 0x8000, 0x8210, 0x00f0, 0x9637, 0x200c, 0x6982,
+	0x8000, 0x200c, 0x697e, 0x1078, 0x4982, 0x027f, 0x047f, 0x157f,
+	0x0f7f, 0x0e7f, 0x0d7f, 0x007c, 0x6013, 0x0100, 0x6003, 0x0001,
+	0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645,
+	0x2069, 0xa892, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x00c0,
+	0x9677, 0x2069, 0xa880, 0x686c, 0xa084, 0x00ff, 0x017e, 0x6110,
+	0xa18c, 0x0700, 0xa10d, 0x6112, 0x017f, 0x6003, 0x0001, 0x6007,
+	0x0043, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0078, 0x9645, 0x6013,
+	0x0200, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078,
+	0x6109, 0x0078, 0x9645, 0x6013, 0x0300, 0x0078, 0x9689, 0x6013,
+	0x0100, 0x6003, 0x0001, 0x6007, 0x0041, 0x1078, 0x5bf8, 0x1078,
+	0x6109, 0x0078, 0x9645, 0x6013, 0x0500, 0x0078, 0x9689, 0x6013,
+	0x0600, 0x0078, 0x9658, 0x6013, 0x0200, 0x0078, 0x9658, 0xa186,
+	0x0013, 0x00c0, 0x96b1, 0x6004, 0xa08a, 0x0040, 0x1048, 0x1328,
+	0xa08a, 0x0053, 0x10c8, 0x1328, 0xa082, 0x0040, 0x2008, 0x0079,
+	0x9725, 0xa186, 0x0051, 0x0040, 0x96be, 0xa186, 0x0047, 0x00c0,
+	0x96d7, 0x6004, 0xa086, 0x0041, 0x0040, 0x96e5, 0x2001, 0x0109,
+	0x2004, 0xd084, 0x0040, 0x96e5, 0x127e, 0x2091, 0x2200, 0x007e,
+	0x017e, 0x027e, 0x1078, 0x5ad2, 0x027f, 0x017f, 0x007f, 0x127f,
+	0x6000, 0xa086, 0x0002, 0x00c0, 0x96e5, 0x0078, 0x976a, 0xa186,
+	0x0027, 0x0040, 0x96df, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6004,
+	0xa082, 0x0040, 0x2008, 0x0079, 0x96e8, 0x1078, 0x7583, 0x007c,
+	0x96fb, 0x96fd, 0x96fd, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb,
+	0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb, 0x96fb,
+	0x96fb, 0x96fb, 0x96fb, 0x1078, 0x1328, 0x1078, 0x6010, 0x1078,
+	0x6109, 0x037e, 0x0d7e, 0x6010, 0xa06d, 0x0040, 0x9722, 0xad84,
+	0xf000, 0x0040, 0x9722, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc,
+	0x00c0, 0x9722, 0x2019, 0x0004, 0x1078, 0x9e70, 0x6013, 0x0000,
+	0x6014, 0xa005, 0x00c0, 0x9720, 0x2001, 0xa5a1, 0x2004, 0x6016,
+	0x6003, 0x0007, 0x0d7f, 0x037f, 0x007c, 0x9738, 0x9757, 0x9741,
+	0x9764, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738,
+	0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738, 0x9738,
+	0x1078, 0x1328, 0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400,
+	0x200a, 0x1078, 0x6010, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4,
+	0x0040, 0x9752, 0x6003, 0x0007, 0x2009, 0x0043, 0x1078, 0x756c,
+	0x0078, 0x9754, 0x6003, 0x0002, 0x1078, 0x6109, 0x007c, 0x1078,
+	0x6010, 0x1078, 0xa0c6, 0x00c0, 0x9761, 0x1078, 0x5a41, 0x1078,
+	0x753d, 0x1078, 0x6109, 0x007c, 0x1078, 0x6010, 0x2009, 0x0041,
+	0x0078, 0x98c1, 0xa182, 0x0040, 0x0079, 0x976e, 0x9781, 0x9783,
+	0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9784, 0x9781, 0x9781,
+	0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x9781, 0x978f,
+	0x9781, 0x1078, 0x1328, 0x007c, 0x6003, 0x0004, 0x6110, 0x20e1,
+	0x0005, 0x3d18, 0x3e20, 0x2c10, 0x1078, 0x15ec, 0x007c, 0x0d7e,
+	0x1078, 0x5a41, 0x0d7f, 0x1078, 0xa134, 0x1078, 0x753d, 0x007c,
+	0xa182, 0x0040, 0x0079, 0x979c, 0x97af, 0x97af, 0x97af, 0x97af,
+	0x97af, 0x97af, 0x97af, 0x97b1, 0x97af, 0x97b4, 0x97df, 0x97af,
+	0x97af, 0x97af, 0x97af, 0x97df, 0x97af, 0x97af, 0x97af, 0x1078,
+	0x1328, 0x1078, 0x7583, 0x007c, 0x1078, 0x60b8, 0x1078, 0x61d3,
+	0x6010, 0x0d7e, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x97ca, 0xa08c,
+	0x0003, 0xa18e, 0x0002, 0x0040, 0x97d2, 0x2009, 0x0041, 0x0d7f,
+	0x0078, 0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41,
+	0x0d7f, 0x007c, 0x1078, 0xa0c6, 0x0040, 0x97d8, 0x0d7f, 0x007c,
+	0x1078, 0x5a41, 0x1078, 0x753d, 0x0d7f, 0x0078, 0x97d1, 0x037e,
+	0x1078, 0x60b8, 0x1078, 0x61d3, 0x6010, 0x0d7e, 0x2068, 0x6018,
+	0x2004, 0xd0bc, 0x0040, 0x97ff, 0x684c, 0xa084, 0x0003, 0xa086,
+	0x0002, 0x0040, 0x97fb, 0x687c, 0x632c, 0xa31a, 0x632e, 0x6880,
+	0x6328, 0xa31b, 0x632a, 0x6003, 0x0002, 0x0078, 0x9810, 0x2019,
+	0x0004, 0x1078, 0x9e70, 0x6014, 0xa005, 0x00c0, 0x980c, 0x2001,
+	0xa5a1, 0x2004, 0x8003, 0x6016, 0x6013, 0x0000, 0x6003, 0x0007,
+	0x0d7f, 0x037f, 0x007c, 0xa186, 0x0013, 0x00c0, 0x9821, 0x6004,
+	0xa086, 0x0042, 0x10c0, 0x1328, 0x1078, 0x6010, 0x1078, 0x6109,
+	0x007c, 0xa186, 0x0027, 0x0040, 0x9829, 0xa186, 0x0014, 0x00c0,
+	0x9839, 0x6004, 0xa086, 0x0042, 0x10c0, 0x1328, 0x2001, 0x0007,
+	0x1078, 0x4472, 0x1078, 0x6010, 0x1078, 0x8c01, 0x1078, 0x6109,
+	0x007c, 0xa182, 0x0040, 0x0079, 0x983d, 0x9850, 0x9850, 0x9850,
+	0x9850, 0x9850, 0x9850, 0x9850, 0x9852, 0x985e, 0x9850, 0x9850,
+	0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850, 0x9850,
+	0x1078, 0x1328, 0x037e, 0x047e, 0x20e1, 0x0005, 0x3d18, 0x3e20,
+	0x2c10, 0x1078, 0x15ec, 0x047f, 0x037f, 0x007c, 0x6010, 0x0d7e,
+	0x2068, 0x6810, 0x6a14, 0x6118, 0x210c, 0xd1bc, 0x0040, 0x987d,
+	0x6124, 0xd1f4, 0x00c0, 0x987d, 0x007e, 0x047e, 0x057e, 0x6c7c,
+	0xa422, 0x6d80, 0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028,
+	0xa529, 0x652a, 0x057f, 0x047f, 0x007f, 0xa20d, 0x00c0, 0x9891,
+	0x684c, 0xd0fc, 0x0040, 0x9889, 0x2009, 0x0041, 0x0d7f, 0x0078,
+	0x98c1, 0x6003, 0x0007, 0x6017, 0x0000, 0x1078, 0x5a41, 0x0d7f,
+	0x007c, 0x007e, 0x0f7e, 0x2c78, 0x1078, 0x4893, 0x0f7f, 0x007f,
+	0x0040, 0x989e, 0x6003, 0x0002, 0x0d7f, 0x007c, 0x2009, 0xa30d,
+	0x210c, 0xd19c, 0x0040, 0x98a8, 0x6003, 0x0007, 0x0078, 0x98aa,
+	0x6003, 0x0006, 0x1078, 0x98b0, 0x1078, 0x5a43, 0x0d7f, 0x007c,
+	0xd2fc, 0x0040, 0x98bc, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000,
+	0x2009, 0x0009, 0x0078, 0x98be, 0x2009, 0x0015, 0x6a6a, 0x6866,
+	0x007c, 0xa182, 0x0040, 0x0048, 0x98c7, 0x0079, 0x98d4, 0xa186,
+	0x0013, 0x0040, 0x98cf, 0xa186, 0x0014, 0x10c0, 0x1328, 0x6024,
+	0xd0dc, 0x1040, 0x1328, 0x007c, 0x98e7, 0x98ee, 0x98fa, 0x9906,
+	0x98e7, 0x98e7, 0x98e7, 0x9915, 0x98e7, 0x98e9, 0x98e9, 0x98e7,
+	0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x98e7, 0x1078,
+	0x1328, 0x6024, 0xd0dc, 0x1040, 0x1328, 0x007c, 0x6003, 0x0001,
+	0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091, 0x8000, 0x1078, 0x6109,
+	0x127f, 0x007c, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x127e,
+	0x2091, 0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x6003, 0x0003,
+	0x6106, 0x2c10, 0x1078, 0x1cab, 0x127e, 0x2091, 0x8000, 0x1078,
+	0x5c64, 0x1078, 0x61d3, 0x127f, 0x007c, 0xa016, 0x1078, 0x15ec,
+	0x007c, 0x127e, 0x2091, 0x8000, 0x037e, 0x0d7e, 0xa182, 0x0040,
+	0x1079, 0x9926, 0x0d7f, 0x037f, 0x127f, 0x007c, 0x9936, 0x9938,
+	0x994d, 0x996c, 0x9936, 0x9936, 0x9936, 0x9984, 0x9936, 0x9936,
+	0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x9936, 0x1078, 0x1328,
+	0x6010, 0x2068, 0x684c, 0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003,
+	0xa39e, 0x0003, 0x0040, 0x9962, 0x6003, 0x0001, 0x6106, 0x1078,
+	0x5bf8, 0x1078, 0x6109, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c,
+	0xd0fc, 0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040,
+	0x9962, 0x6003, 0x0001, 0x6106, 0x1078, 0x5bf8, 0x1078, 0x6109,
+	0x0078, 0x9987, 0x6013, 0x0000, 0x6017, 0x0000, 0x2019, 0x0004,
+	0x1078, 0x9e70, 0x0078, 0x9987, 0x6010, 0x2068, 0x684c, 0xd0fc,
+	0x0040, 0x9962, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0040, 0x9962,
+	0x6003, 0x0003, 0x6106, 0x2c10, 0x1078, 0x1cab, 0x1078, 0x5c64,
+	0x1078, 0x61d3, 0x0078, 0x9987, 0xa016, 0x1078, 0x15ec, 0x007c,
+	0x1078, 0x6010, 0x6110, 0x81ff, 0x0040, 0x9999, 0x0d7e, 0x2168,
+	0x1078, 0xa181, 0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f,
+	0x0d7f, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x1078, 0x60b8,
+	0x6110, 0x81ff, 0x0040, 0x99af, 0x0d7e, 0x2168, 0x1078, 0xa181,
+	0x037e, 0x2019, 0x0029, 0x1078, 0x9e70, 0x037f, 0x0d7f, 0x1078,
+	0x8c01, 0x1078, 0x61d3, 0x007c, 0xa182, 0x0085, 0x0079, 0x99b8,
+	0x99c1, 0x99bf, 0x99bf, 0x99cd, 0x99bf, 0x99bf, 0x99bf, 0x1078,
+	0x1328, 0x6003, 0x000b, 0x6106, 0x1078, 0x5bf8, 0x127e, 0x2091,
+	0x8000, 0x1078, 0x6109, 0x127f, 0x007c, 0x027e, 0x0e7e, 0x1078,
+	0xa0bf, 0x0040, 0x99d7, 0x1078, 0x753d, 0x0078, 0x99f3, 0x2071,
+	0xa880, 0x7224, 0x6212, 0x7220, 0x1078, 0x9d10, 0x0040, 0x99e4,
+	0x6007, 0x0086, 0x0078, 0x99ed, 0x6007, 0x0087, 0x7224, 0xa296,
+	0xffff, 0x00c0, 0x99ed, 0x6007, 0x0086, 0x6003, 0x0001, 0x1078,
+	0x5bf8, 0x1078, 0x6109, 0x0e7f, 0x027f, 0x007c, 0xa186, 0x0013,
+	0x00c0, 0x9a07, 0x6004, 0xa08a, 0x0085, 0x1048, 0x1328, 0xa08a,
+	0x008c, 0x10c8, 0x1328, 0xa082, 0x0085, 0x0079, 0x9a1e, 0xa186,
+	0x0027, 0x0040, 0x9a13, 0xa186, 0x0014, 0x0040, 0x9a13, 0x1078,
+	0x7583, 0x0078, 0x9a1d, 0x2001, 0x0007, 0x1078, 0x4472, 0x1078,
+	0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0x9a25, 0x9a27,
+	0x9a27, 0x9a25, 0x9a25, 0x9a25, 0x9a25, 0x1078, 0x1328, 0x1078,
+	0x6010, 0x1078, 0x8c01, 0x1078, 0x6109, 0x007c, 0xa182, 0x0085,
+	0x1048, 0x1328, 0xa182, 0x008c, 0x10c8, 0x1328, 0xa182, 0x0085,
+	0x0079, 0x9a3a, 0x9a41, 0x9a41, 0x9a41, 0x9a43, 0x9a41, 0x9a41,
+	0x9a41, 0x1078, 0x1328, 0x007c, 0xa186, 0x0013, 0x0040, 0x9a54,
+	0xa186, 0x0014, 0x0040, 0x9a54, 0xa186, 0x0027, 0x0040, 0x9a54,
+	0x1078, 0x7583, 0x0078, 0x9a5a, 0x1078, 0x6010, 0x1078, 0x8c01,
+	0x1078, 0x6109, 0x007c, 0x037e, 0x1078, 0xa134, 0x603f, 0x0000,
+	0x2019, 0x000b, 0x1078, 0x9a6a, 0x601f, 0x0006, 0x6003, 0x0007,
+	0x037f, 0x007c, 0x127e, 0x037e, 0x2091, 0x8000, 0x087e, 0x2c40,
+	0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x00c0,
+	0x9aa5, 0x077e, 0x2c38, 0x1078, 0x7105, 0x077f, 0x00c0, 0x9aa5,
+	0x6000, 0xa086, 0x0000, 0x0040, 0x9aa5, 0x601c, 0xa086, 0x0007,
+	0x0040, 0x9aa5, 0x0d7e, 0x6000, 0xa086, 0x0004, 0x00c0, 0x9a96,
+	0x1078, 0xa134, 0x601f, 0x0007, 0x1078, 0x1749, 0x6010, 0x2068,
+	0x1078, 0x8a44, 0x0040, 0x9a9e, 0x1078, 0x9e70, 0x0d7f, 0x6013,
+	0x0000, 0x1078, 0xa134, 0x601f, 0x0007, 0x037f, 0x127f, 0x007c,
+	0x0f7e, 0x0c7e, 0x037e, 0x157e, 0x2079, 0xa880, 0x7938, 0x783c,
+	0x1078, 0x24e3, 0x00c0, 0x9af6, 0x017e, 0x0c7e, 0x1078, 0x4501,
+	0x00c0, 0x9af6, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9, 0x0004,
+	0x1078, 0x7e55, 0x00c0, 0x9af6, 0x017f, 0x027f, 0x027e, 0x017e,
+	0x2019, 0x0029, 0x1078, 0x71e0, 0x1078, 0x5d53, 0x077e, 0x2039,
+	0x0000, 0x1078, 0x5c78, 0x077f, 0x017f, 0x077e, 0x2039, 0x0000,
+	0x1078, 0x9c38, 0x077f, 0x1078, 0x471b, 0x027e, 0x6204, 0xa294,
+	0xff00, 0x8217, 0xa286, 0x0006, 0x0040, 0x9aea, 0xa286, 0x0004,
+	0x00c0, 0x9aed, 0x62a0, 0x1078, 0x28d5, 0x027f, 0x017f, 0x1078,
+	0x4235, 0x6612, 0x6516, 0xa006, 0x0078, 0x9af8, 0x0c7f, 0x017f,
+	0x157f, 0x037f, 0x0c7f, 0x0f7f, 0x007c, 0x0c7e, 0x0d7e, 0x0e7e,
+	0x017e, 0x2009, 0xa31f, 0x2104, 0xa086, 0x0074, 0x00c0, 0x9b60,
+	0x2069, 0xa88e, 0x690c, 0xa182, 0x0100, 0x0048, 0x9b50, 0x6908,
+	0xa184, 0x8000, 0x0040, 0x9b5c, 0x6018, 0x2070, 0x7010, 0xa084,
+	0x00ff, 0x0040, 0x9b1f, 0x7000, 0xd0f4, 0x0040, 0x9b23, 0xa184,
+	0x0800, 0x0040, 0x9b5c, 0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54,
+	0x6914, 0x2069, 0xa8ae, 0x6904, 0x81ff, 0x00c0, 0x9b48, 0x690c,
+	0xa182, 0x0100, 0x0048, 0x9b50, 0x6908, 0x81ff, 0x00c0, 0x9b4c,
+	0x6910, 0xa18a, 0x0001, 0x0048, 0x9b54, 0x6918, 0xa18a, 0x0001,
+	0x0048, 0x9b5c, 0x0078, 0x9b66, 0x6013, 0x0100, 0x0078, 0x9b62,
+	0x6013, 0x0300, 0x0078, 0x9b62, 0x6013, 0x0500, 0x0078, 0x9b62,
+	0x6013, 0x0700, 0x0078, 0x9b62, 0x6013, 0x0900, 0x0078, 0x9b62,
+	0x6013, 0x0b00, 0x0078, 0x9b62, 0x6013, 0x0f00, 0x0078, 0x9b62,
+	0x6013, 0x2d00, 0xa085, 0x0001, 0x0078, 0x9b67, 0xa006, 0x017f,
+	0x0e7f, 0x0d7f, 0x0c7f, 0x007c, 0x0c7e, 0x0d7e, 0x027e, 0x037e,
+	0x157e, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff, 0xa286, 0x0006,
+	0x0040, 0x9b90, 0xa286, 0x0004, 0x0040, 0x9b90, 0xa394, 0xff00,
+	0x8217, 0xa286, 0x0006, 0x0040, 0x9b90, 0xa286, 0x0004, 0x0040,
+	0x9b90, 0x0c7e, 0x2d60, 0x1078, 0x4513, 0x0c7f, 0x0078, 0x9bcb,
+	0x2011, 0xa896, 0xad98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55,
+	0x00c0, 0x9bcc, 0x2011, 0xa89a, 0xad98, 0x0006, 0x20a9, 0x0004,
+	0x1078, 0x7e55, 0x00c0, 0x9bcc, 0x047e, 0x017e, 0x6aa0, 0xa294,
+	0x00ff, 0x8227, 0xa006, 0x2009, 0xa352, 0x210c, 0xd1a4, 0x0040,
+	0x9bb8, 0x2009, 0x0029, 0x1078, 0x9ec0, 0x6800, 0xc0e5, 0x6802,
+	0x2019, 0x0029, 0x1078, 0x5d53, 0x077e, 0x2039, 0x0000, 0x1078,
+	0x5c78, 0x2c08, 0x1078, 0x9c38, 0x077f, 0x2001, 0x0007, 0x1078,
+	0x4472, 0x017f, 0x047f, 0xa006, 0x157f, 0x037f, 0x027f, 0x0d7f,
+	0x0c7f, 0x007c, 0x0d7e, 0x2069, 0xa88e, 0x6800, 0xa086, 0x0800,
+	0x0040, 0x9bde, 0x6013, 0x0000, 0x0078, 0x9bdf, 0xa006, 0x0d7f,
+	0x007c, 0x0c7e, 0x0f7e, 0x017e, 0x027e, 0x037e, 0x157e, 0x2079,
+	0xa88c, 0x7930, 0x7834, 0x1078, 0x24e3, 0x00c0, 0x9c05, 0x1078,
+	0x4501, 0x00c0, 0x9c05, 0x2011, 0xa890, 0xac98, 0x000a, 0x20a9,
+	0x0004, 0x1078, 0x7e55, 0x00c0, 0x9c05, 0x2011, 0xa894, 0xac98,
+	0x0006, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x157f, 0x037f, 0x027f,
+	0x017f, 0x0f7f, 0x0c7f, 0x007c, 0x0c7e, 0x007e, 0x017e, 0x027e,
+	0x037e, 0x157e, 0x2011, 0xa883, 0x2204, 0x8211, 0x220c, 0x1078,
+	0x24e3, 0x00c0, 0x9c31, 0x1078, 0x4501, 0x00c0, 0x9c31, 0x2011,
+	0xa896, 0xac98, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0,
+	0x9c31, 0x2011, 0xa89a, 0xac98, 0x0006, 0x20a9, 0x0004, 0x1078,
+	0x7e55, 0x157f, 0x037f, 0x027f, 0x017f, 0x007f, 0x0c7f, 0x007c,
+	0x0e7e, 0x0c7e, 0x087e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e,
+	0x127e, 0x2091, 0x8000, 0x2740, 0x2029, 0xa5b4, 0x252c, 0x2021,
+	0xa5ba, 0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060,
+	0x81ff, 0x0040, 0x9c59, 0x8001, 0xa602, 0x00c8, 0x9cc3, 0x0078,
+	0x9c5c, 0xa606, 0x0040, 0x9cc3, 0x2100, 0xac06, 0x0040, 0x9cb9,
+	0x1078, 0x9ee5, 0x0040, 0x9cb9, 0x671c, 0xa786, 0x0001, 0x0040,
+	0x9cde, 0xa786, 0x0004, 0x0040, 0x9cde, 0xa786, 0x0007, 0x0040,
+	0x9cb9, 0x2500, 0xac06, 0x0040, 0x9cb9, 0x2400, 0xac06, 0x0040,
+	0x9cb9, 0x1078, 0x9ef9, 0x00c0, 0x9cb9, 0x88ff, 0x0040, 0x9c84,
+	0x6020, 0xa906, 0x00c0, 0x9cb9, 0x0d7e, 0x6000, 0xa086, 0x0004,
+	0x00c0, 0x9c8e, 0x017e, 0x1078, 0x1749, 0x017f, 0xa786, 0x0008,
+	0x00c0, 0x9c9d, 0x1078, 0x8c3b, 0x00c0, 0x9c9d, 0x1078, 0x7a05,
+	0x0d7f, 0x1078, 0x8c01, 0x0078, 0x9cb9, 0x6010, 0x2068, 0x1078,
+	0x8a44, 0x0040, 0x9cb6, 0xa786, 0x0003, 0x00c0, 0x9ccd, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x1078, 0xa181, 0x017e, 0x1078,
+	0x8cb8, 0x1078, 0x4982, 0x017f, 0x1078, 0x8bf4, 0x0d7f, 0x1078,
+	0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8,
+	0x9cc3, 0x0078, 0x9c4c, 0x127f, 0x027f, 0x047f, 0x057f, 0x067f,
+	0x077f, 0x087f, 0x0c7f, 0x0e7f, 0x007c, 0xa786, 0x0006, 0x00c0,
+	0x9ca7, 0xa386, 0x0005, 0x0040, 0x9cdb, 0x1078, 0xa181, 0x1078,
+	0x9e70, 0x0078, 0x9cb6, 0x0d7f, 0x0078, 0x9cb9, 0x1078, 0x9ef9,
+	0x00c0, 0x9cb9, 0x81ff, 0x0040, 0x9cb9, 0xa180, 0x0001, 0x2004,
+	0xa086, 0x0018, 0x0040, 0x9cf3, 0xa180, 0x0001, 0x2004, 0xa086,
+	0x002d, 0x00c0, 0x9cb9, 0x6000, 0xa086, 0x0002, 0x00c0, 0x9cb9,
+	0x1078, 0x8c27, 0x0040, 0x9d04, 0x1078, 0x8c3b, 0x00c0, 0x9cb9,
+	0x1078, 0x7a05, 0x0078, 0x9d0c, 0x1078, 0x2839, 0x1078, 0x8c3b,
+	0x00c0, 0x9d0c, 0x1078, 0x7a05, 0x1078, 0x8c01, 0x0078, 0x9cb9,
+	0x0c7e, 0x0e7e, 0x017e, 0x2c08, 0x2170, 0x1078, 0x9e8c, 0x017f,
+	0x0040, 0x9d1f, 0x601c, 0xa084, 0x000f, 0x1079, 0x9d22, 0x0e7f,
+	0x0c7f, 0x007c, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a, 0x9d2a,
+	0x9d2c, 0x9d2a, 0xa006, 0x007c, 0x047e, 0x017e, 0x7018, 0xa080,
+	0x0028, 0x2024, 0xa4a4, 0x00ff, 0x8427, 0x2c00, 0x2009, 0x0020,
+	0x1078, 0x9ec0, 0x017f, 0x047f, 0x037e, 0x2019, 0x0002, 0x1078,
+	0x9a6a, 0x037f, 0xa085, 0x0001, 0x007c, 0x2001, 0x0001, 0x1078,
+	0x442b, 0x157e, 0x017e, 0x027e, 0x037e, 0x20a9, 0x0004, 0x2019,
+	0xa305, 0x2011, 0xa896, 0x1078, 0x7e55, 0x037f, 0x027f, 0x017f,
+	0x157f, 0xa005, 0x007c, 0x0f7e, 0x0e7e, 0x0c7e, 0x087e, 0x077e,
+	0x067e, 0x027e, 0x127e, 0x2091, 0x8000, 0x2740, 0x2061, 0xaa00,
+	0x2079, 0x0001, 0x8fff, 0x0040, 0x9dc3, 0x2071, 0xa300, 0x7644,
+	0x7060, 0x8001, 0xa602, 0x00c8, 0x9dc3, 0x88ff, 0x0040, 0x9d7e,
+	0x2800, 0xac06, 0x00c0, 0x9db9, 0x2079, 0x0000, 0x1078, 0x9ee5,
+	0x0040, 0x9db9, 0x2400, 0xac06, 0x0040, 0x9db9, 0x671c, 0xa786,
+	0x0006, 0x00c0, 0x9db9, 0xa786, 0x0007, 0x0040, 0x9db9, 0x88ff,
+	0x00c0, 0x9d9d, 0x6018, 0xa206, 0x00c0, 0x9db9, 0x85ff, 0x0040,
+	0x9d9d, 0x6020, 0xa106, 0x00c0, 0x9db9, 0x0d7e, 0x6000, 0xa086,
+	0x0004, 0x00c0, 0x9da9, 0x1078, 0xa134, 0x601f, 0x0007, 0x1078,
+	0x1749, 0x6010, 0x2068, 0x1078, 0x8a44, 0x0040, 0x9db3, 0x047e,
+	0x1078, 0x9e70, 0x047f, 0x0d7f, 0x1078, 0x8c01, 0x88ff, 0x00c0,
+	0x9dcd, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02, 0x00c8,
+	0x9dc3, 0x0078, 0x9d6a, 0xa006, 0x127f, 0x027f, 0x067f, 0x077f,
+	0x087f, 0x0c7f, 0x0e7f, 0x0f7f, 0x007c, 0xa8c5, 0x0001, 0x0078,
+	0x9dc4, 0x077e, 0x057e, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001,
+	0x2c20, 0x2019, 0x0002, 0x6218, 0x097e, 0x2049, 0x0000, 0x1078,
+	0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x1078,
+	0x9d5b, 0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e,
+	0x0c7e, 0x157e, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0x017e, 0x037e, 0x1078, 0x4501, 0x00c0, 0x9e14, 0x2c10, 0x057e,
+	0x087e, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x097e, 0x2049,
+	0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000, 0x1078,
+	0x7105, 0x1078, 0x9d5b, 0x057f, 0x037f, 0x017f, 0x8108, 0x00f0,
+	0x9df8, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c,
+	0x077e, 0x057e, 0x6218, 0x087e, 0x2041, 0x0000, 0x2029, 0x0001,
+	0x2019, 0x0048, 0x097e, 0x2049, 0x0000, 0x1078, 0x7058, 0x097f,
+	0x087f, 0x2039, 0x0000, 0x1078, 0x7105, 0x2c20, 0x1078, 0x9d5b,
+	0x057f, 0x077f, 0x007c, 0x027e, 0x047e, 0x057e, 0x077e, 0x0c7e,
+	0x157e, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x017e, 0x037e,
+	0x1078, 0x4501, 0x00c0, 0x9e64, 0x2c10, 0x087e, 0x2041, 0x0000,
+	0x2828, 0x047e, 0x2021, 0x0001, 0x1078, 0xa111, 0x047f, 0x097e,
+	0x2049, 0x0000, 0x1078, 0x7058, 0x097f, 0x087f, 0x2039, 0x0000,
+	0x1078, 0x7105, 0x1078, 0x9d5b, 0x037f, 0x017f, 0x8108, 0x00f0,
+	0x9e46, 0x157f, 0x0c7f, 0x077f, 0x057f, 0x047f, 0x027f, 0x007c,
+	0x017e, 0x0f7e, 0xad82, 0xca00, 0x0048, 0x9e89, 0xad82, 0xffff,
+	0x00c8, 0x9e89, 0x6800, 0xa07d, 0x0040, 0x9e86, 0x6803, 0x0000,
+	0x6b52, 0x1078, 0x4982, 0x2f68, 0x0078, 0x9e7a, 0x6b52, 0x1078,
+	0x4982, 0x0f7f, 0x017f, 0x007c, 0x0e7e, 0x047e, 0x037e, 0x2061,
+	0xaa00, 0x2071, 0xa300, 0x7444, 0x7060, 0x8001, 0xa402, 0x00c8,
+	0x9ebb, 0x2100, 0xac06, 0x0040, 0x9ead, 0x6000, 0xa086, 0x0000,
+	0x0040, 0x9ead, 0x6008, 0xa206, 0x00c0, 0x9ead, 0x6018, 0xa1a0,
+	0x0006, 0x2424, 0xa406, 0x0040, 0x9eb7, 0xace0, 0x0010, 0x2001,
+	0xa315, 0x2004, 0xac02, 0x00c8, 0x9ebb, 0x0078, 0x9e91, 0xa085,
+	0x0001, 0x0078, 0x9ebc, 0xa006, 0x037f, 0x047f, 0x0e7f, 0x007c,
+	0x0d7e, 0x007e, 0x1078, 0x1381, 0x007f, 0x1040, 0x1328, 0x6837,
+	0x010d, 0x685e, 0x027e, 0x2010, 0x1078, 0x8a30, 0x2001, 0x0000,
+	0x0040, 0x9ed6, 0x2200, 0xa080, 0x0008, 0x2004, 0x027f, 0x684a,
+	0x6956, 0x6c46, 0x684f, 0x0000, 0xa006, 0x68b2, 0x6802, 0x683a,
+	0x685a, 0x1078, 0x4982, 0x0d7f, 0x007c, 0x6700, 0xa786, 0x0000,
+	0x0040, 0x9ef8, 0xa786, 0x0001, 0x0040, 0x9ef8, 0xa786, 0x000a,
+	0x0040, 0x9ef8, 0xa786, 0x0009, 0x0040, 0x9ef8, 0xa085, 0x0001,
+	0x007c, 0x0e7e, 0x6018, 0x2070, 0x70a0, 0xa206, 0x0e7f, 0x007c,
+	0x017e, 0x6004, 0xa08e, 0x001e, 0x00c0, 0x9f1a, 0x8007, 0x6130,
+	0xa18c, 0x00ff, 0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x601f, 0x0005, 0x2001, 0xa5a1, 0x2004, 0x6016, 0x1078, 0x5bf8,
+	0x1078, 0x6109, 0x017f, 0x007c, 0x0005, 0x0005, 0x007c, 0x6024,
+	0xd0e4, 0x0040, 0x9f30, 0xd0cc, 0x0040, 0x9f2a, 0x1078, 0x8cfa,
+	0x0078, 0x9f30, 0x1078, 0xa134, 0x1078, 0x5a41, 0x1078, 0x753d,
+	0x007c, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f, 0x0079, 0x9f38,
+	0x9f41, 0x9f41, 0x9f41, 0x9f43, 0x9f41, 0x9f43, 0x9f43, 0x9f41,
+	0x9f43, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa280, 0x0007,
+	0x2004, 0xa084, 0x000f, 0x0079, 0x9f4d, 0x9f56, 0x9f56, 0x9f56,
+	0x9f56, 0x9f56, 0x9f56, 0x9f61, 0x9f56, 0x9f56, 0x6007, 0x003b,
+	0x602b, 0x0009, 0x6013, 0x2a00, 0x6003, 0x0001, 0x1078, 0x5bf8,
+	0x007c, 0x0c7e, 0x2260, 0x1078, 0xa134, 0x603f, 0x0000, 0x6024,
+	0xc0f4, 0xc0cc, 0x6026, 0x0c7f, 0x0d7e, 0x2268, 0xa186, 0x0007,
+	0x00c0, 0x9fc2, 0x6810, 0xa005, 0x0040, 0x9f7f, 0xa080, 0x0013,
+	0x2004, 0xd0fc, 0x00c0, 0x9f7f, 0x0d7f, 0x0078, 0x9f56, 0x6007,
+	0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109, 0x0c7e,
+	0x2d60, 0x6100, 0xa186, 0x0002, 0x00c0, 0xa050, 0x6010, 0xa005,
+	0x00c0, 0x9f99, 0x6000, 0xa086, 0x0007, 0x10c0, 0x1328, 0x0078,
+	0xa050, 0xa08c, 0xf000, 0x00c0, 0x9fa5, 0x0078, 0x9fa5, 0x2068,
+	0x6800, 0xa005, 0x00c0, 0x9f9f, 0x2d00, 0xa080, 0x0013, 0x2004,
+	0xa084, 0x0003, 0xa086, 0x0002, 0x00c0, 0x9fbe, 0x6010, 0x2068,
+	0x684c, 0xc0dc, 0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852,
+	0x2009, 0x0043, 0x1078, 0x98c1, 0x0078, 0xa050, 0x2009, 0x0041,
+	0x0078, 0xa04a, 0xa186, 0x0005, 0x00c0, 0xa009, 0x6810, 0xa080,
+	0x0013, 0x2004, 0xd0bc, 0x00c0, 0x9fd0, 0x0d7f, 0x0078, 0x9f56,
+	0xd0b4, 0x0040, 0x9fd8, 0xd0fc, 0x1040, 0x1328, 0x0078, 0x9f72,
+	0x6007, 0x003a, 0x6003, 0x0001, 0x1078, 0x5bf8, 0x1078, 0x6109,
+	0x0c7e, 0x2d60, 0x6100, 0xa186, 0x0002, 0x0040, 0x9feb, 0xa186,
+	0x0004, 0x00c0, 0xa050, 0x2071, 0xa5e1, 0x7000, 0xa086, 0x0003,
+	0x00c0, 0x9ff8, 0x7004, 0xac06, 0x00c0, 0x9ff8, 0x7003, 0x0000,
+	0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000,
+	0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0078,
+	0xa04a, 0x037e, 0x0d7e, 0x0d7e, 0x1078, 0x1381, 0x037f, 0x1040,
+	0x1328, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b,
+	0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872,
+	0x2360, 0x6024, 0xc0dd, 0x6026, 0x6018, 0xa080, 0x0028, 0x2004,
+	0xa084, 0x00ff, 0x8007, 0x6320, 0x6b4a, 0x6846, 0x684f, 0x0000,
+	0x6d6a, 0x6e66, 0x686f, 0x0001, 0x1078, 0x4982, 0x2019, 0x0045,
+	0x6008, 0x2068, 0x1078, 0x9a6a, 0x2d00, 0x600a, 0x601f, 0x0006,
+	0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x0d7f, 0x037f,
+	0x0078, 0xa051, 0x603f, 0x0000, 0x6003, 0x0007, 0x1078, 0x98c1,
+	0x0c7f, 0x0d7f, 0x007c, 0xa186, 0x0013, 0x00c0, 0xa05d, 0x6004,
+	0xa082, 0x0085, 0x2008, 0x0079, 0xa077, 0xa186, 0x0027, 0x00c0,
+	0xa070, 0x1078, 0x6010, 0x037e, 0x0d7e, 0x6010, 0x2068, 0x2019,
+	0x0004, 0x1078, 0x9e70, 0x0d7f, 0x037f, 0x1078, 0x6109, 0x007c,
+	0xa186, 0x0014, 0x0040, 0xa061, 0x1078, 0x7583, 0x007c, 0xa080,
+	0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa07e, 0xa080, 0x1078, 0x1328,
+	0x1078, 0x6010, 0x6003, 0x000c, 0x1078, 0x6109, 0x007c, 0xa182,
+	0x008c, 0x00c8, 0xa091, 0xa182, 0x0085, 0x0048, 0xa091, 0x0079,
+	0xa094, 0x1078, 0x7583, 0x007c, 0xa09b, 0xa09b, 0xa09b, 0xa09b,
+	0xa09d, 0xa0bc, 0xa09b, 0x1078, 0x1328, 0x0d7e, 0x2c68, 0x1078,
+	0x74d7, 0x0040, 0xa0b7, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009,
+	0xa88e, 0x210c, 0x6136, 0x2009, 0xa88f, 0x210c, 0x613a, 0x600b,
+	0xffff, 0x6918, 0x611a, 0x601f, 0x0004, 0x1078, 0x5bf8, 0x2d60,
+	0x1078, 0x753d, 0x0d7f, 0x007c, 0x1078, 0x753d, 0x007c, 0x0e7e,
+	0x6018, 0x2070, 0x7000, 0xd0ec, 0x0e7f, 0x007c, 0x6010, 0xa080,
+	0x0013, 0x200c, 0xd1ec, 0x0040, 0xa110, 0x2001, 0xa371, 0x2004,
+	0xd0ec, 0x0040, 0xa110, 0x6003, 0x0002, 0x6024, 0xc0e5, 0x6026,
+	0xd1ac, 0x0040, 0xa0ee, 0x0f7e, 0x2c78, 0x1078, 0x488f, 0x0f7f,
+	0x0040, 0xa0ee, 0x2001, 0xa5a2, 0x2004, 0x603e, 0x2009, 0xa371,
+	0x210c, 0xd1f4, 0x00c0, 0xa10e, 0x0078, 0xa100, 0x2009, 0xa371,
+	0x210c, 0xd1f4, 0x0040, 0xa0fa, 0x6024, 0xc0e4, 0x6026, 0xa006,
+	0x0078, 0xa110, 0x2001, 0xa5a2, 0x200c, 0x8103, 0xa100, 0x603e,
+	0x6018, 0xa088, 0x002b, 0x2104, 0xa005, 0x0040, 0xa10b, 0xa088,
+	0x0003, 0x0078, 0xa103, 0x2c0a, 0x600f, 0x0000, 0xa085, 0x0001,
+	0x007c, 0x017e, 0x0c7e, 0x0e7e, 0x6120, 0xa2f0, 0x002b, 0x2e04,
+	0x2060, 0x8cff, 0x0040, 0xa130, 0x84ff, 0x00c0, 0xa123, 0x6020,
+	0xa106, 0x00c0, 0xa12b, 0x600c, 0x2072, 0x1078, 0x5a41, 0x1078,
+	0x753d, 0x0078, 0xa12d, 0xacf0, 0x0003, 0x2e64, 0x0078, 0xa119,
+	0x0e7f, 0x0c7f, 0x017f, 0x007c, 0x0d7e, 0x6018, 0xa0e8, 0x002b,
+	0x2d04, 0xa005, 0x0040, 0xa146, 0xac06, 0x0040, 0xa144, 0x2d04,
+	0xa0e8, 0x0003, 0x0078, 0xa138, 0x600c, 0x206a, 0x0d7f, 0x007c,
+	0x027e, 0x037e, 0x157e, 0x2011, 0xa325, 0x2204, 0xa084, 0x00ff,
+	0x2019, 0xa88e, 0x2334, 0xa636, 0x00c0, 0xa174, 0x8318, 0x2334,
+	0x2204, 0xa084, 0xff00, 0xa636, 0x00c0, 0xa174, 0x2011, 0xa890,
+	0x6018, 0xa098, 0x000a, 0x20a9, 0x0004, 0x1078, 0x7e55, 0x00c0,
+	0xa174, 0x2011, 0xa894, 0x6018, 0xa098, 0x0006, 0x20a9, 0x0004,
+	0x1078, 0x7e55, 0x00c0, 0xa174, 0x157f, 0x037f, 0x027f, 0x007c,
+	0x0e7e, 0x2071, 0xa300, 0x1078, 0x41f5, 0x1078, 0x260d, 0x0e7f,
+	0x007c, 0x0e7e, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0040, 0xa18a,
+	0x1078, 0xa18c, 0x0e7f, 0x007c, 0x6850, 0xc0e5, 0x6852, 0x007c,
+	0x0e7e, 0x0c7e, 0x077e, 0x067e, 0x057e, 0x047e, 0x027e, 0x017e,
+	0x127e, 0x2091, 0x8000, 0x2029, 0xa5b4, 0x252c, 0x2021, 0xa5ba,
+	0x2424, 0x2061, 0xaa00, 0x2071, 0xa300, 0x7644, 0x7060, 0xa606,
+	0x0040, 0xa1e4, 0x671c, 0xa786, 0x0001, 0x0040, 0xa1b3, 0xa786,
+	0x0008, 0x00c0, 0xa1da, 0x2500, 0xac06, 0x0040, 0xa1da, 0x2400,
+	0xac06, 0x0040, 0xa1da, 0x1078, 0x9ee5, 0x0040, 0xa1da, 0x1078,
+	0x9ef9, 0x00c0, 0xa1da, 0x6000, 0xa086, 0x0004, 0x00c0, 0xa1cc,
+	0x017e, 0x1078, 0x1749, 0x017f, 0x1078, 0x8c27, 0x00c0, 0xa1d2,
+	0x1078, 0x2839, 0x1078, 0x8c3b, 0x00c0, 0xa1d8, 0x1078, 0x7a05,
+	0x1078, 0x8c01, 0xace0, 0x0010, 0x2001, 0xa315, 0x2004, 0xac02,
+	0x00c8, 0xa1e4, 0x0078, 0xa1a3, 0x127f, 0x017f, 0x027f, 0x047f,
+	0x057f, 0x067f, 0x077f, 0x0c7f, 0x0e7f, 0x007c, 0x127e, 0x007e,
+	0x0e7e, 0x2091, 0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa1fb,
+	0x7034, 0x8000, 0x7036, 0xd5b4, 0x0040, 0xa201, 0x7030, 0x8000,
+	0x7032, 0xd5ac, 0x0040, 0xa208, 0x2071, 0xa34a, 0x1078, 0xa237,
+	0x0e7f, 0x007f, 0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091,
+	0x8000, 0x2071, 0xa340, 0xd5a4, 0x0040, 0xa219, 0x7034, 0x8000,
+	0x7036, 0xd5b4, 0x0040, 0xa21f, 0x7030, 0x8000, 0x7032, 0xd5ac,
+	0x0040, 0xa226, 0x2071, 0xa34a, 0x1078, 0xa237, 0x0e7f, 0x007f,
+	0x127f, 0x007c, 0x127e, 0x007e, 0x0e7e, 0x2091, 0x8000, 0x2071,
+	0xa342, 0x1078, 0xa237, 0x0e7f, 0x007f, 0x127f, 0x007c, 0x2e04,
+	0x8000, 0x2072, 0x00c8, 0xa240, 0x8e70, 0x2e04, 0x8000, 0x2072,
+	0x007c, 0x0e7e, 0x2071, 0xa340, 0x1078, 0xa237, 0x0e7f, 0x007c,
+	0x0e7e, 0x2071, 0xa344, 0x1078, 0xa237, 0x0e7f, 0x007c, 0x0001,
+	0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100,
+	0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x6286
+};
+
+/************************************************************************
+ *									*
+ *               --- ISP2200 Initiator/Target Firmware ---              *
+ *             with Fabric (Public Loop), Point-point, and              *
+ *             expanded LUN addressing for FCTAPE                       *
+ *									*
+ ************************************************************************
+  Copyright (C) 2000 and 2100 Qlogic Corporation 
+  (www.qlogic.com)
+
+  This program is distributed in the hope that it will be useful, but
+  WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+************************************************************************/
+
+/*
+ *	Firmware Version 2.01.27 (11:07 Dec 18, 2000)
+ */
+
+static unsigned short risc_code_length2200 = 0x9cbf;
+static unsigned short risc_code2200[] = { 
+	0x0470, 0x0000, 0x0000, 0x9cbf, 0x0000, 0x0002, 0x0001, 0x001b,
+	0x0017, 0x2043, 0x4f50, 0x5952, 0x4947, 0x4854, 0x2031, 0x3939,
+	0x3920, 0x514c, 0x4f47, 0x4943, 0x2043, 0x4f52, 0x504f, 0x5241,
+	0x5449, 0x4f4e, 0x2049, 0x5350, 0x3232, 0x3030, 0x2046, 0x6972,
+	0x6d77, 0x6172, 0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030,
+	0x322e, 0x3031, 0x2e32, 0x3720, 0x2020, 0x2020, 0x2400, 0x20c1,
+	0x0005, 0x2001, 0x017f, 0x2003, 0x0000, 0x20c9, 0xb1ff, 0x2091,
+	0x2000, 0x2059, 0x0000, 0x2b78, 0x7823, 0x0004, 0x2089, 0x27b5,
+	0x2051, 0xad00, 0x2a70, 0x2029, 0xe400, 0x2031, 0xffff, 0x2039,
+	0xe3e9, 0x2021, 0x0200, 0x0804, 0x1449, 0x20a1, 0xacbf, 0xa00e,
+	0x20a9, 0x0741, 0x41a4, 0x3400, 0x755e, 0x7662, 0x775a, 0x7466,
+	0x746a, 0x20a1, 0xb400, 0x7160, 0x810d, 0x810d, 0x810d, 0x810d,
+	0xa18c, 0x000f, 0x2001, 0x000b, 0xa112, 0xa00e, 0x21a8, 0x41a4,
+	0x3400, 0x8211, 0x1dd8, 0x7160, 0x3400, 0xa102, 0x0120, 0x0218,
+	0x20a8, 0xa00e, 0x41a4, 0x3800, 0xd08c, 0x01d8, 0x2009, 0xad00,
+	0x810d, 0x810d, 0x810d, 0x810d, 0xa18c, 0x000f, 0x2001, 0x0001,
+	0xa112, 0x20a1, 0x1000, 0xa00e, 0x21a8, 0x41a4, 0x8211, 0x1de0,
+	0x2009, 0xad00, 0x3400, 0xa102, 0x0120, 0x0218, 0x20a8, 0xa00e,
+	0x41a4, 0x080c, 0x13fc, 0x080c, 0x1613, 0x080c, 0x17ac, 0x080c,
+	0x1e67, 0x080c, 0x492e, 0x080c, 0x801a, 0x080c, 0x159c, 0x080c,
+	0x2ce6, 0x080c, 0x5a01, 0x080c, 0x5045, 0x080c, 0x6487, 0x080c,
+	0x236a, 0x080c, 0x6686, 0x080c, 0x5fae, 0x080c, 0x226b, 0x080c,
+	0x2338, 0x2091, 0x3009, 0x7823, 0x0000, 0x1004, 0x10c5, 0x7820,
+	0xa086, 0x0002, 0x1150, 0x7823, 0x4000, 0x0e04, 0x10bd, 0x781b,
+	0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x2a70, 0x7003, 0x0000,
+	0x2a70, 0x7000, 0xa08e, 0x0003, 0x1158, 0x080c, 0x3c98, 0x080c,
+	0x2d0d, 0x080c, 0x5a4f, 0x080c, 0x51f4, 0x080c, 0x64a2, 0x0c80,
+	0x000b, 0x0c98, 0x10e4, 0x10e5, 0x1203, 0x10e2, 0x12cc, 0x13f9,
+	0x13fa, 0x13fb, 0x080c, 0x14f6, 0x0005, 0x0126, 0x00f6, 0x2091,
+	0x8000, 0x7000, 0xa086, 0x0001, 0x1904, 0x11d1, 0x080c, 0x1569,
+	0x080c, 0x574f, 0x0150, 0x080c, 0x5775, 0x1580, 0x2079, 0x0100,
+	0x7828, 0xa085, 0x1800, 0x782a, 0x0448, 0x080c, 0x569a, 0x7000,
+	0xa086, 0x0001, 0x1904, 0x11d1, 0x7088, 0xa086, 0x0028, 0x1904,
+	0x11d1, 0x2079, 0x0100, 0x7827, 0xffff, 0x7a28, 0xa295, 0x1e2f,
+	0x7a2a, 0x2011, 0x566e, 0x080c, 0x650d, 0x2011, 0x567b, 0x080c,
+	0x650d, 0x2011, 0x481b, 0x080c, 0x650d, 0x2011, 0x8030, 0x2019,
+	0x0000, 0x7087, 0x0000, 0x080c, 0x1d0f, 0x00e8, 0x080c, 0x41d1,
+	0x2079, 0x0100, 0x7844, 0xa005, 0x1904, 0x11d1, 0x2011, 0x481b,
+	0x080c, 0x650d, 0x2011, 0x567b, 0x080c, 0x650d, 0x080c, 0x1d0f,
+	0x2001, 0xaf8c, 0x2004, 0x780e, 0x7840, 0xa084, 0xfffb, 0x7842,
+	0x2011, 0x8010, 0x73c8, 0x080c, 0x3c5c, 0x7238, 0xc284, 0x723a,
+	0x2001, 0xad0c, 0x200c, 0xc1ac, 0x2102, 0x080c, 0x79bd, 0x2011,
+	0x0004, 0x080c, 0x959c, 0x080c, 0x4f71, 0x080c, 0x574f, 0x0158,
+	0x080c, 0x4917, 0x0140, 0x7087, 0x0001, 0x70c3, 0x0000, 0x080c,
+	0x436e, 0x0804, 0x11d1, 0x080c, 0x502d, 0x0120, 0x7a0c, 0xc2b4,
+	0x7a0e, 0x0050, 0x080c, 0x9937, 0x70d0, 0xd09c, 0x1128, 0x709c,
+	0xa005, 0x0110, 0x080c, 0x48f5, 0x70db, 0x0000, 0x70d7, 0x0000,
+	0x72d0, 0x080c, 0x574f, 0x1178, 0x2011, 0x0000, 0x0016, 0x080c,
+	0x2744, 0x2019, 0xaf8e, 0x211a, 0x001e, 0x704f, 0xffff, 0x7053,
+	0x00ef, 0x7073, 0x0000, 0x2079, 0xad51, 0x7804, 0xd0ac, 0x0108,
+	0xc295, 0x72d2, 0x080c, 0x574f, 0x0118, 0xa296, 0x0004, 0x0508,
+	0x2011, 0x0001, 0x080c, 0x959c, 0x7097, 0x0000, 0x709b, 0xffff,
+	0x7003, 0x0002, 0x00fe, 0x080c, 0x28fa, 0x2011, 0x0005, 0x080c,
+	0x7adf, 0x080c, 0x6c50, 0x080c, 0x574f, 0x0148, 0x00c6, 0x2061,
+	0x0100, 0x0016, 0x080c, 0x2744, 0x61e2, 0x001e, 0x00ce, 0x012e,
+	0x00d0, 0x7097, 0x0000, 0x709b, 0xffff, 0x7003, 0x0002, 0x2011,
+	0x0005, 0x080c, 0x7adf, 0x080c, 0x6c50, 0x080c, 0x574f, 0x0148,
+	0x00c6, 0x2061, 0x0100, 0x0016, 0x080c, 0x2744, 0x61e2, 0x001e,
+	0x00ce, 0x00fe, 0x012e, 0x0005, 0x00c6, 0x080c, 0x574f, 0x1118,
+	0x20a9, 0x0100, 0x0010, 0x20a9, 0x0082, 0x080c, 0x574f, 0x1118,
+	0x2009, 0x0000, 0x0010, 0x2009, 0x007e, 0x0016, 0x0026, 0x0036,
+	0x2110, 0x0026, 0x2019, 0x0029, 0x080c, 0x7cf4, 0x002e, 0x080c,
+	0xac07, 0x003e, 0x002e, 0x001e, 0x080c, 0x2bc9, 0x8108, 0x1f04,
+	0x11e5, 0x00ce, 0x706f, 0x0000, 0x7070, 0xa084, 0x00ff, 0x7072,
+	0x709f, 0x0000, 0x0005, 0x0126, 0x2091, 0x8000, 0x7000, 0xa086,
+	0x0002, 0x1904, 0x12ca, 0x7098, 0xa086, 0xffff, 0x0130, 0x080c,
+	0x28fa, 0x080c, 0x6c50, 0x0804, 0x12ca, 0x70d0, 0xd0ac, 0x1110,
+	0xd09c, 0x0540, 0xd084, 0x0530, 0x0006, 0x0016, 0x2001, 0x0103,
+	0x2009, 0xaf8c, 0x210c, 0x2102, 0x001e, 0x000e, 0xd08c, 0x01d0,
+	0x70d4, 0xa086, 0xffff, 0x0190, 0x080c, 0x2a56, 0x080c, 0x6c50,
+	0x70d0, 0xd094, 0x1904, 0x12ca, 0x2011, 0x0001, 0x2019, 0x0000,
+	0x080c, 0x2a8c, 0x080c, 0x6c50, 0x0804, 0x12ca, 0x70d8, 0xa005,
+	0x1904, 0x12ca, 0x7094, 0xa005, 0x1904, 0x12ca, 0x70d0, 0xd0a4,
+	0x0118, 0xd0b4, 0x0904, 0x12ca, 0x080c, 0x502d, 0x1904, 0x12ca,
+	0x2001, 0xad52, 0x2004, 0xd0ac, 0x01c8, 0x0156, 0x00c6, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1118, 0x6000,
+	0xd0ec, 0x1138, 0x001e, 0x8108, 0x1f04, 0x125b, 0x00ce, 0x015e,
+	0x0028, 0x001e, 0x00ce, 0x015e, 0x0804, 0x12ca, 0x0006, 0x0016,
+	0x2001, 0x0103, 0x2009, 0xaf8c, 0x210c, 0x2102, 0x001e, 0x000e,
+	0xa006, 0x2009, 0x0700, 0x20a9, 0x0002, 0x20a1, 0xafb5, 0x40a1,
+	0x706c, 0x8007, 0x7170, 0x810f, 0x20a9, 0x0002, 0x40a1, 0x2009,
+	0x0000, 0x080c, 0x14dc, 0x2001, 0x0000, 0x810f, 0x20a9, 0x0002,
+	0x40a1, 0xa006, 0x2009, 0x0200, 0x20a9, 0x0002, 0x20a1, 0xafc5,
+	0x40a1, 0x7030, 0xc08c, 0x7032, 0x7003, 0x0003, 0x709b, 0xffff,
+	0x080c, 0x1562, 0xa006, 0x080c, 0x261e, 0x080c, 0x3cce, 0x00f6,
+	0x2079, 0x0100, 0x080c, 0x5775, 0x0150, 0x080c, 0x574f, 0x7828,
+	0x0118, 0xa084, 0xe1ff, 0x0010, 0xa084, 0xffdf, 0x782a, 0x00fe,
+	0x2001, 0xafc8, 0x2004, 0xa086, 0x0005, 0x1120, 0x2011, 0x0000,
+	0x080c, 0x7adf, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x080c, 0x6c50,
+	0x080c, 0x6d0d, 0x012e, 0x0005, 0x0016, 0x0046, 0x00f6, 0x0126,
+	0x2091, 0x8000, 0x2079, 0x0100, 0x2009, 0xad33, 0x2104, 0xa005,
+	0x1110, 0x080c, 0x2770, 0x2009, 0x00f7, 0x080c, 0x48de, 0x7940,
+	0xa18c, 0x0010, 0x7942, 0x7924, 0xd1b4, 0x0110, 0x7827, 0x0040,
+	0xd19c, 0x0110, 0x7827, 0x0008, 0x0006, 0x0036, 0x0156, 0x7954,
+	0xd1ac, 0x1904, 0x133a, 0x080c, 0x5761, 0x0158, 0x080c, 0x5775,
+	0x1128, 0x2001, 0xaf9d, 0x2003, 0x0000, 0x0070, 0x080c, 0x5757,
+	0x0dc0, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003,
+	0x0001, 0x080c, 0x569a, 0x0058, 0x080c, 0x574f, 0x0140, 0x2009,
+	0x00f8, 0x080c, 0x48de, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9,
+	0x09c4, 0x7820, 0xd09c, 0x1138, 0x080c, 0x574f, 0x0138, 0x7824,
+	0xd0ac, 0x1904, 0x13e0, 0x1f04, 0x1319, 0x0070, 0x7824, 0x080c,
+	0x576b, 0x0118, 0xd0ac, 0x1904, 0x13e0, 0xa084, 0x1800, 0x0d98,
+	0x7003, 0x0001, 0x0804, 0x13e0, 0x2001, 0x0001, 0x080c, 0x261e,
+	0x0804, 0x13ef, 0x7850, 0xa084, 0x0180, 0x7852, 0x782f, 0x0020,
+	0x20a9, 0x0046, 0x1d04, 0x1342, 0x2091, 0x6000, 0x1f04, 0x1342,
+	0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x782f, 0x0000,
+	0x080c, 0x5761, 0x0158, 0x080c, 0x5775, 0x1128, 0x2001, 0xaf9d,
+	0x2003, 0x0000, 0x0070, 0x080c, 0x5757, 0x0dc0, 0x2001, 0xaf9d,
+	0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x080c, 0x569a,
+	0x0020, 0x2009, 0x00f8, 0x080c, 0x48de, 0x20a9, 0x000e, 0xe000,
+	0x1f04, 0x136f, 0x7850, 0xa084, 0x0180, 0xa085, 0x1400, 0x7852,
+	0x080c, 0x574f, 0x0120, 0x7843, 0x0090, 0x7843, 0x0010, 0x2021,
+	0xe678, 0x2019, 0xea60, 0x7820, 0xd09c, 0x1558, 0x080c, 0x574f,
+	0x05b8, 0x7824, 0xd0ac, 0x1904, 0x13e0, 0x080c, 0x5775, 0x1508,
+	0x0046, 0x2021, 0x0190, 0x8421, 0x1df0, 0x004e, 0x8421, 0x11c8,
+	0x7827, 0x0048, 0x20a9, 0x01f4, 0x1d04, 0x139c, 0x2091, 0x6000,
+	0x1f04, 0x139c, 0x7824, 0xa084, 0x0068, 0x15a8, 0x2001, 0xaf9d,
+	0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x7003, 0x0001,
+	0x0478, 0x8319, 0x1980, 0x2009, 0xad33, 0x2104, 0x8000, 0x200a,
+	0xa084, 0xfff0, 0x0120, 0x200b, 0x0000, 0x080c, 0x2770, 0x00d8,
+	0x080c, 0x5761, 0x1140, 0xa4a2, 0x0064, 0x1128, 0x080c, 0x5726,
+	0x7003, 0x0001, 0x00a8, 0x7827, 0x1800, 0xe000, 0xe000, 0x7824,
+	0x080c, 0x576b, 0x0110, 0xd0ac, 0x1158, 0xa084, 0x1800, 0x09c8,
+	0x7003, 0x0001, 0x0028, 0x2001, 0x0001, 0x080c, 0x261e, 0x0048,
+	0x2001, 0xad33, 0x2003, 0x0000, 0x7827, 0x0048, 0x7828, 0xc09d,
+	0x782a, 0x7850, 0xa084, 0x0180, 0xa085, 0x0400, 0x7852, 0x015e,
+	0x003e, 0x000e, 0x080c, 0x1539, 0x012e, 0x00fe, 0x004e, 0x001e,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x2a70, 0x2001, 0xaf9d, 0x2003,
+	0x0000, 0x7087, 0x0000, 0x2009, 0x0100, 0x2104, 0xa082, 0x0002,
+	0x0218, 0x704f, 0xffff, 0x0010, 0x704f, 0x0000, 0x7057, 0xffff,
+	0x706f, 0x0000, 0x7073, 0x0000, 0x080c, 0x9937, 0x2061, 0xaf8d,
+	0x6003, 0x0909, 0x6007, 0x0000, 0x600b, 0x8800, 0x600f, 0x0200,
+	0x6013, 0x00ff, 0x6017, 0x0003, 0x601b, 0x0000, 0x601f, 0x07d0,
+	0x2061, 0xaf95, 0x6003, 0x8000, 0x6007, 0x0000, 0x600b, 0x0000,
+	0x600f, 0x0200, 0x6013, 0x00ff, 0x6017, 0x0000, 0x601b, 0x0001,
+	0x601f, 0x0000, 0x2061, 0xafa6, 0x6003, 0x514c, 0x6007, 0x4f47,
+	0x600b, 0x4943, 0x600f, 0x2020, 0x2001, 0xad27, 0x2003, 0x0000,
+	0x0005, 0x04a0, 0x2011, 0x0000, 0x81ff, 0x0570, 0xa186, 0x0001,
+	0x1148, 0x2031, 0x8fff, 0x2039, 0xcc01, 0x2021, 0x0100, 0x2029,
+	0xcc00, 0x00e8, 0xa186, 0x0002, 0x1118, 0x2011, 0x0000, 0x00b8,
+	0xa186, 0x0005, 0x1118, 0x2011, 0x0001, 0x0088, 0xa186, 0x0009,
+	0x1118, 0x2011, 0x0002, 0x0058, 0xa186, 0x000a, 0x1118, 0x2011,
+	0x0002, 0x0028, 0xa186, 0x0055, 0x1110, 0x2011, 0x0003, 0x3800,
+	0xa084, 0xfffc, 0xa205, 0x20c0, 0x0804, 0x104d, 0xa00e, 0x2011,
+	0x0003, 0x2019, 0x1485, 0x0804, 0x14d6, 0x2019, 0xaaaa, 0x2061,
+	0xffff, 0x2c14, 0x2362, 0xe000, 0xe000, 0x2c04, 0xa306, 0x2262,
+	0x1110, 0xc1b5, 0xc1a5, 0x2011, 0x0000, 0x2019, 0x1498, 0x04f0,
+	0x2019, 0xaaaa, 0x2061, 0xffff, 0x2c14, 0x2362, 0xe000, 0xe000,
+	0x2c1c, 0x2061, 0x7fff, 0xe000, 0xe000, 0x2c04, 0x2061, 0xffff,
+	0x2262, 0xa306, 0x0110, 0xc18d, 0x0008, 0xc185, 0x2011, 0x0002,
+	0x2019, 0x14b3, 0x0418, 0x2061, 0xffff, 0x2019, 0xaaaa, 0x2c14,
+	0x2362, 0xe000, 0xe000, 0x2c04, 0x2262, 0xa306, 0x1180, 0x2c14,
+	0x2362, 0xe000, 0xe000, 0x2c1c, 0x2061, 0x7fff, 0x2c04, 0x2061,
+	0xffff, 0x2262, 0xa306, 0x1110, 0xc195, 0x0008, 0xc19d, 0x2011,
+	0x0001, 0x2019, 0x14d4, 0x0010, 0x0804, 0x144a, 0x3800, 0xa084,
+	0xfffc, 0xa205, 0x20c0, 0x0837, 0x2011, 0x0000, 0x080c, 0x4cdc,
+	0x1178, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0128, 0xa0c4,
+	0xff00, 0xa8c6, 0x0600, 0x1120, 0xa186, 0x0080, 0x0108, 0x8210,
+	0x8108, 0xa186, 0x0100, 0x1d50, 0x2208, 0x0005, 0x2091, 0x8000,
+	0x0e04, 0x14f8, 0x0006, 0x0016, 0x2079, 0x0000, 0x7818, 0xd084,
+	0x1de8, 0x001e, 0x792e, 0x000e, 0x782a, 0x000e, 0x7826, 0x3900,
+	0x783a, 0x7823, 0x8002, 0x781b, 0x0001, 0x2091, 0x5000, 0x0126,
+	0x0156, 0x0146, 0x20a9, 0x0010, 0x20a1, 0xb0c8, 0x2091, 0x2000,
+	0x40a1, 0x20a9, 0x0010, 0x2091, 0x2200, 0x40a1, 0x20a9, 0x0010,
+	0x2091, 0x2400, 0x40a1, 0x20a9, 0x0010, 0x2091, 0x2600, 0x40a1,
+	0x20a9, 0x0010, 0x2091, 0x2800, 0x40a1, 0x014e, 0x015e, 0x012e,
+	0x2079, 0xad00, 0x7803, 0x0005, 0x2091, 0x4080, 0x04c9, 0x0cf8,
+	0x0005, 0x0006, 0x080c, 0x1584, 0x1518, 0x00f6, 0x2079, 0xad23,
+	0x2f04, 0x8000, 0x207a, 0xa082, 0x000f, 0x0258, 0xa006, 0x207a,
+	0x2079, 0xad25, 0x2f04, 0xa084, 0x0001, 0xa086, 0x0001, 0x207a,
+	0x0070, 0x2079, 0xad25, 0x2f7c, 0x8fff, 0x1128, 0x2001, 0x0c03,
+	0x2003, 0x0040, 0x0020, 0x2001, 0x0c03, 0x2003, 0x00c0, 0x00fe,
+	0x000e, 0x0005, 0x0409, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0080,
+	0x0005, 0x00d1, 0x1120, 0x2001, 0x0c03, 0x2003, 0x0040, 0x0005,
+	0x0006, 0x0091, 0x1178, 0x2001, 0x0c03, 0x2003, 0x0040, 0x2009,
+	0x0fff, 0x00a1, 0x2001, 0x0c03, 0x2003, 0x0080, 0x2009, 0x0fff,
+	0x0069, 0x0c88, 0x000e, 0x0005, 0x00c6, 0x2061, 0x0c00, 0x2c04,
+	0xa084, 0x00ff, 0xa086, 0x00aa, 0x00ce, 0x0005, 0x0156, 0x0126,
+	0xa18c, 0x0fff, 0x21a8, 0x1d04, 0x1593, 0x2091, 0x6000, 0x1f04,
+	0x1593, 0x012e, 0x015e, 0x0005, 0x2071, 0xad00, 0x715c, 0x712e,
+	0x2021, 0x0001, 0xa190, 0x0030, 0xa298, 0x0030, 0x0240, 0x7060,
+	0xa302, 0x1228, 0x220a, 0x2208, 0x2310, 0x8420, 0x0ca8, 0x3800,
+	0xd08c, 0x0148, 0x7060, 0xa086, 0xad00, 0x0128, 0x7063, 0xad00,
+	0x2011, 0x1000, 0x0c48, 0x200b, 0x0000, 0x74ae, 0x74b2, 0x0005,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00, 0x70b0, 0xa0ea,
+	0x0010, 0x0268, 0x8001, 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e,
+	0x206b, 0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e,
+	0x0cd8, 0x00e6, 0x2071, 0xad00, 0x0126, 0x2091, 0x8000, 0x70b0,
+	0x8001, 0x0260, 0x70b2, 0x702c, 0x2068, 0x2d04, 0x702e, 0x206b,
+	0x0000, 0x6807, 0x0000, 0x012e, 0x00ee, 0x0005, 0xa06e, 0x0cd8,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00, 0x702c, 0x206a,
+	0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x012e, 0x00ee, 0x0005,
+	0x8dff, 0x0138, 0x6804, 0x6807, 0x0000, 0x0006, 0x0c49, 0x00de,
+	0x0cb8, 0x0005, 0x00e6, 0x2071, 0xad00, 0x70b0, 0xa08a, 0x0010,
+	0xa00d, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xafec, 0x7007, 0x0000,
+	0x701b, 0x0000, 0x701f, 0x0000, 0x2071, 0x0000, 0x7010, 0xa085,
+	0x8004, 0x7012, 0x00ee, 0x0005, 0x00e6, 0x2270, 0x700b, 0x0000,
+	0x2071, 0xafec, 0x7018, 0xa088, 0xaff5, 0x220a, 0x8000, 0xa084,
+	0x0007, 0x701a, 0x7004, 0xa005, 0x1128, 0x00f6, 0x2079, 0x0010,
+	0x0081, 0x00fe, 0x00ee, 0x0005, 0x00e6, 0x2071, 0xafec, 0x7004,
+	0xa005, 0x1128, 0x00f6, 0x2079, 0x0010, 0x0019, 0x00fe, 0x00ee,
+	0x0005, 0x7000, 0x0002, 0x164f, 0x16b3, 0x16d0, 0x16d0, 0x7018,
+	0x711c, 0xa106, 0x1118, 0x7007, 0x0000, 0x0005, 0x00d6, 0xa180,
+	0xaff5, 0x2004, 0x700a, 0x2068, 0x8108, 0xa18c, 0x0007, 0x711e,
+	0x7803, 0x0026, 0x6824, 0x7832, 0x6828, 0x7836, 0x682c, 0x783a,
+	0x6830, 0x783e, 0x6810, 0x700e, 0x680c, 0x7016, 0x6804, 0x00de,
+	0xd084, 0x0120, 0x7007, 0x0001, 0x0029, 0x0005, 0x7007, 0x0002,
+	0x00b1, 0x0005, 0x0016, 0x0026, 0x710c, 0x2011, 0x0040, 0xa182,
+	0x0040, 0x1210, 0x2110, 0xa006, 0x700e, 0x7212, 0x8203, 0x7822,
+	0x7803, 0x0020, 0x7803, 0x0041, 0x002e, 0x001e, 0x0005, 0x0016,
+	0x0026, 0x0136, 0x0146, 0x0156, 0x7014, 0x2098, 0x20a1, 0x0014,
+	0x7803, 0x0026, 0x710c, 0x2011, 0x0040, 0xa182, 0x0040, 0x1210,
+	0x2110, 0xa006, 0x700e, 0x22a8, 0x53a6, 0x8203, 0x7822, 0x7803,
+	0x0020, 0x3300, 0x7016, 0x7803, 0x0001, 0x015e, 0x014e, 0x013e,
+	0x002e, 0x001e, 0x0005, 0x0136, 0x0146, 0x0156, 0x2099, 0xadf9,
+	0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126,
+	0x2091, 0x8000, 0x7803, 0x0041, 0x7007, 0x0003, 0x7000, 0xc084,
+	0x7002, 0x700b, 0xadf4, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005,
+	0x0136, 0x0146, 0x0156, 0x2001, 0xae28, 0x209c, 0x20a1, 0x0014,
+	0x7803, 0x0026, 0x2001, 0xae29, 0x20ac, 0x53a6, 0x2099, 0xae2a,
+	0x20a1, 0x0018, 0x20a9, 0x0008, 0x53a3, 0x7803, 0x0020, 0x0126,
+	0x2091, 0x8000, 0x7803, 0x0001, 0x7007, 0x0004, 0x7000, 0xc08c,
+	0x7002, 0x700b, 0xae25, 0x012e, 0x015e, 0x014e, 0x013e, 0x0005,
+	0x0016, 0x00e6, 0x2071, 0xafec, 0x00f6, 0x2079, 0x0010, 0x7904,
+	0x7803, 0x0002, 0xd1fc, 0x0120, 0xa18c, 0x0700, 0x7004, 0x0023,
+	0x00fe, 0x00ee, 0x001e, 0x0005, 0x1649, 0x1713, 0x1741, 0x176b,
+	0x179b, 0x1712, 0x0cf8, 0xa18c, 0x0700, 0x1528, 0x0136, 0x0146,
+	0x0156, 0x7014, 0x20a0, 0x2099, 0x0014, 0x7803, 0x0040, 0x7010,
+	0x20a8, 0x53a5, 0x3400, 0x7016, 0x015e, 0x014e, 0x013e, 0x700c,
+	0xa005, 0x0570, 0x7830, 0x7832, 0x7834, 0x7836, 0x080c, 0x167a,
+	0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0100, 0x7007, 0x0000,
+	0x080c, 0x1649, 0x0005, 0x7008, 0xa080, 0x0002, 0x2003, 0x0200,
+	0x0ca8, 0xa18c, 0x0700, 0x1150, 0x700c, 0xa005, 0x0188, 0x7830,
+	0x7832, 0x7834, 0x7836, 0x080c, 0x168f, 0x0005, 0x7008, 0xa080,
+	0x0002, 0x2003, 0x0200, 0x7007, 0x0000, 0x080c, 0x1649, 0x0005,
+	0x00d6, 0x7008, 0x2068, 0x7830, 0x6826, 0x7834, 0x682a, 0x7838,
+	0x682e, 0x783c, 0x6832, 0x680b, 0x0100, 0x00de, 0x7007, 0x0000,
+	0x080c, 0x1649, 0x0005, 0xa18c, 0x0700, 0x1540, 0x0136, 0x0146,
+	0x0156, 0x2001, 0xadf7, 0x2004, 0xa080, 0x000d, 0x20a0, 0x2099,
+	0x0014, 0x7803, 0x0040, 0x20a9, 0x0020, 0x53a5, 0x2001, 0xadf9,
+	0x2004, 0xd0bc, 0x0148, 0x2001, 0xae02, 0x2004, 0xa080, 0x000d,
+	0x20a0, 0x20a9, 0x0020, 0x53a5, 0x015e, 0x014e, 0x013e, 0x7007,
+	0x0000, 0x080c, 0x5ae6, 0x080c, 0x1649, 0x0005, 0x2011, 0x8003,
+	0x080c, 0x3c5c, 0x0cf8, 0xa18c, 0x0700, 0x1148, 0x2001, 0xae27,
+	0x2003, 0x0100, 0x7007, 0x0000, 0x080c, 0x1649, 0x0005, 0x2011,
+	0x8004, 0x080c, 0x3c5c, 0x0cf8, 0x0126, 0x2091, 0x2200, 0x2079,
+	0x0030, 0x2071, 0xaffd, 0x7003, 0x0000, 0x700f, 0xb003, 0x7013,
+	0xb003, 0x780f, 0x00f6, 0x7803, 0x0004, 0x012e, 0x0005, 0x6934,
+	0xa184, 0x0007, 0x0002, 0x17cb, 0x1809, 0x17cb, 0x17cb, 0x17cb,
+	0x17f1, 0x17d8, 0x17cf, 0xa085, 0x0001, 0x0804, 0x1823, 0x684c,
+	0xd0bc, 0x0dc8, 0x6860, 0x682e, 0x685c, 0x682a, 0x6858, 0x04c8,
+	0xa18c, 0x00ff, 0xa186, 0x001e, 0x1d70, 0x684c, 0xd0bc, 0x0d58,
+	0x6860, 0x682e, 0x685c, 0x682a, 0x6804, 0x681a, 0xa080, 0x000d,
+	0x2004, 0xa084, 0x000f, 0xa080, 0x2186, 0x2005, 0x6832, 0x6858,
+	0x0440, 0xa18c, 0x00ff, 0xa186, 0x0015, 0x19a8, 0x684c, 0xd0ac,
+	0x0990, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f,
+	0xa080, 0x2186, 0x2005, 0x6832, 0xa006, 0x682e, 0x682a, 0x6858,
+	0x0080, 0x684c, 0xd0ac, 0x0904, 0x17cb, 0xa006, 0x682e, 0x682a,
+	0x6858, 0xa18c, 0x000f, 0xa188, 0x2186, 0x210d, 0x6932, 0x2d08,
+	0x691a, 0x6826, 0x684c, 0xc0dd, 0x684e, 0xa006, 0x680a, 0x697c,
+	0x6912, 0x6980, 0x6916, 0x0005, 0x20e1, 0x0007, 0x20e1, 0x2000,
+	0x2001, 0x020a, 0x2004, 0x82ff, 0x01a8, 0xa280, 0x0004, 0x00d6,
+	0x206c, 0x684c, 0xd0dc, 0x1150, 0x080c, 0x17bf, 0x0138, 0x00de,
+	0xa280, 0x0000, 0x2003, 0x0002, 0xa016, 0x0020, 0x6808, 0x8000,
+	0x680a, 0x00de, 0x0126, 0x0046, 0x0036, 0x0026, 0x2091, 0x2200,
+	0x002e, 0x003e, 0x004e, 0x7000, 0xa005, 0x01d0, 0x710c, 0x220a,
+	0x8108, 0x230a, 0x8108, 0x240a, 0x8108, 0xa182, 0xb01e, 0x0210,
+	0x2009, 0xb003, 0x710e, 0x7010, 0xa102, 0xa082, 0x0009, 0x0118,
+	0xa080, 0x001b, 0x1118, 0x2009, 0x0138, 0x200a, 0x012e, 0x0005,
+	0x7206, 0x2001, 0x1866, 0x0006, 0x2260, 0x0804, 0x197a, 0x0126,
+	0x0026, 0x0036, 0x00c6, 0x0006, 0x2091, 0x2200, 0x000e, 0x004e,
+	0x003e, 0x002e, 0x00d6, 0x00c6, 0x2460, 0x6110, 0x2168, 0x6a62,
+	0x6b5e, 0xa005, 0x0904, 0x18c8, 0x6808, 0xa005, 0x0904, 0x18ff,
+	0x7000, 0xa005, 0x1108, 0x0488, 0x700c, 0x7110, 0xa106, 0x1904,
+	0x1907, 0x7004, 0xa406, 0x1548, 0x2001, 0x0005, 0x2004, 0xd08c,
+	0x0168, 0x0046, 0x080c, 0x1a6c, 0x004e, 0x2460, 0x6010, 0xa080,
+	0x0002, 0x2004, 0xa005, 0x0904, 0x18ff, 0x0c10, 0x2001, 0x0207,
+	0x2004, 0xd09c, 0x1d48, 0x7804, 0xa084, 0x6000, 0x0120, 0xa086,
+	0x6000, 0x0108, 0x0c08, 0x7818, 0x6812, 0x781c, 0x6816, 0x7803,
+	0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x6100, 0xa18e, 0x0004,
+	0x1904, 0x1907, 0x2009, 0x0048, 0x080c, 0x80a7, 0x0804, 0x1907,
+	0x6808, 0xa005, 0x05a0, 0x7000, 0xa005, 0x0588, 0x700c, 0x7110,
+	0xa106, 0x1118, 0x7004, 0xa406, 0x1550, 0x2001, 0x0005, 0x2004,
+	0xd08c, 0x0160, 0x0046, 0x080c, 0x1a6c, 0x004e, 0x2460, 0x6010,
+	0xa080, 0x0002, 0x2004, 0xa005, 0x01d0, 0x0c28, 0x2001, 0x0207,
+	0x2004, 0xd09c, 0x1d50, 0x2001, 0x0005, 0x2004, 0xd08c, 0x1d50,
+	0x7804, 0xa084, 0x6000, 0x0118, 0xa086, 0x6000, 0x19f0, 0x7818,
+	0x6812, 0x781c, 0x6816, 0x7803, 0x0004, 0x7003, 0x0000, 0x6100,
+	0xa18e, 0x0004, 0x1120, 0x2009, 0x0048, 0x080c, 0x80a7, 0x00ce,
+	0x00de, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x0026, 0x0036, 0x0046,
+	0x0056, 0x080c, 0x1d86, 0x0026, 0x0056, 0x2071, 0xaffd, 0x7000,
+	0xa086, 0x0000, 0x0580, 0x7004, 0xac06, 0x11f8, 0x2079, 0x0030,
+	0x7000, 0xa086, 0x0003, 0x01c8, 0x7804, 0xd0fc, 0x1198, 0x2001,
+	0x0207, 0x2004, 0xd09c, 0x1dc0, 0x7803, 0x0004, 0x7804, 0xd0ac,
+	0x1de8, 0x7803, 0x0002, 0x7803, 0x0009, 0x7003, 0x0003, 0x7007,
+	0x0000, 0x0018, 0x080c, 0x1a6c, 0x08d0, 0x0156, 0x20a9, 0x0009,
+	0x2009, 0xb003, 0x2104, 0xac06, 0x1108, 0x200a, 0xa188, 0x0003,
+	0x1f04, 0x1942, 0x015e, 0x005e, 0x002e, 0x2001, 0x015d, 0x201c,
+	0x831a, 0x2302, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202,
+	0x005e, 0x004e, 0x003e, 0x002e, 0x00ee, 0x00fe, 0x0005, 0x700c,
+	0x7110, 0xa106, 0x0904, 0x19dd, 0x2104, 0x7006, 0x2060, 0x8108,
+	0x211c, 0x8108, 0x2124, 0x8108, 0xa182, 0xb01e, 0x0210, 0x2009,
+	0xb003, 0x7112, 0x700c, 0xa106, 0x1128, 0x080c, 0x2744, 0x2001,
+	0x0138, 0x2102, 0x8cff, 0x0588, 0x6010, 0x2068, 0x2d58, 0x6828,
+	0xa406, 0x1580, 0x682c, 0xa306, 0x1568, 0x7004, 0x2060, 0x6020,
+	0xc0d4, 0x6022, 0x684c, 0xd0f4, 0x0128, 0x6817, 0xffff, 0x6813,
+	0xffff, 0x00d8, 0x6850, 0xd0f4, 0x1130, 0x7803, 0x0004, 0x6810,
+	0x781a, 0x6814, 0x781e, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830,
+	0x2040, 0x6034, 0xa0cc, 0x000f, 0x2009, 0x0011, 0x04c9, 0x0118,
+	0x2009, 0x0001, 0x04a9, 0x2d58, 0x0005, 0x080c, 0x1ced, 0x0904,
+	0x195f, 0x0cd0, 0x6020, 0xd0d4, 0x01b8, 0x6038, 0xa402, 0x6034,
+	0xa303, 0x0108, 0x1288, 0x643a, 0x6336, 0x6c2a, 0x6b2e, 0x0046,
+	0x0036, 0x2400, 0x6c7c, 0xa402, 0x6812, 0x2300, 0x6b80, 0xa303,
+	0x6816, 0x003e, 0x004e, 0x0018, 0x080c, 0x98cb, 0x09f0, 0x601c,
+	0xa08e, 0x0008, 0x0904, 0x1985, 0xa08e, 0x000a, 0x0904, 0x1985,
+	0x080c, 0x21a6, 0x1990, 0x0804, 0x1985, 0x7003, 0x0000, 0x0005,
+	0x8aff, 0x0904, 0x1a46, 0xa03e, 0x2730, 0x6850, 0xd0fc, 0x11b8,
+	0xd0f4, 0x1528, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x1a30,
+	0x1a15, 0x1a15, 0x1a30, 0x1a30, 0x1a29, 0x1a30, 0x1a15, 0x1a30,
+	0x1a1a, 0x1a1a, 0x1a30, 0x1a30, 0x1a30, 0x1a21, 0x1a1a, 0x7803,
+	0x0004, 0xc0fc, 0x6852, 0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0x00d6,
+	0xd99c, 0x0548, 0x2805, 0xac68, 0x6f08, 0x6e0c, 0x0420, 0xc0f4,
+	0x6852, 0x6b6c, 0x6a70, 0x00d6, 0x0428, 0x6b08, 0x6a0c, 0x6d00,
+	0x6c04, 0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c,
+	0x0090, 0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e,
+	0x1138, 0x00de, 0x080c, 0x2148, 0x1904, 0x19e0, 0xa00e, 0x00b0,
+	0x00de, 0x080c, 0x14f6, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a,
+	0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x00de, 0x6828, 0xa300,
+	0x682a, 0x682c, 0xa201, 0x682e, 0x080c, 0x2148, 0x0005, 0x080c,
+	0x14f6, 0x080c, 0x1e1a, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068,
+	0x7003, 0x0000, 0x080c, 0x1d22, 0x080c, 0x9596, 0x0170, 0x6808,
+	0x8001, 0x680a, 0x697c, 0x6912, 0x6980, 0x6916, 0x682b, 0xffff,
+	0x682f, 0xffff, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x929c,
+	0x0804, 0x1c5e, 0x080c, 0x14f6, 0x0126, 0x2091, 0x2200, 0x0006,
+	0x0016, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184,
+	0x0700, 0x1978, 0xa184, 0x0003, 0xa086, 0x0003, 0x0d58, 0x7000,
+	0x0002, 0x1a89, 0x1a8f, 0x1b92, 0x1c39, 0x1c4d, 0x1a89, 0x1a89,
+	0x1a89, 0x7804, 0xd09c, 0x1904, 0x1c5e, 0x080c, 0x14f6, 0x8001,
+	0x7002, 0xa184, 0x0880, 0x1190, 0xd19c, 0x1904, 0x1b20, 0x8aff,
+	0x0904, 0x1b20, 0x2009, 0x0001, 0x080c, 0x19e0, 0x0904, 0x1c5e,
+	0x2009, 0x0001, 0x080c, 0x19e0, 0x0804, 0x1c5e, 0x7803, 0x0004,
+	0x7003, 0x0000, 0xd1bc, 0x1904, 0x1b00, 0x0026, 0x0036, 0x7c20,
+	0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816, 0x2001,
+	0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128, 0x7803,
+	0x0009, 0x7003, 0x0004, 0x0010, 0x080c, 0x1c62, 0x6b28, 0x6a2c,
+	0x2400, 0x686e, 0xa31a, 0x2500, 0x6872, 0xa213, 0x6b2a, 0x6a2e,
+	0x00c6, 0x7004, 0x2060, 0x6020, 0xd0f4, 0x1110, 0x633a, 0x6236,
+	0x00ce, 0x003e, 0x002e, 0x6e1e, 0x6f22, 0x080c, 0x215e, 0x2a00,
+	0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6850, 0xc0fd, 0x6852,
+	0x6808, 0x8001, 0x680a, 0x1148, 0x684c, 0xd0e4, 0x0130, 0x7004,
+	0x2060, 0x2009, 0x0048, 0x080c, 0x80a7, 0x7000, 0xa086, 0x0004,
+	0x0904, 0x1c5e, 0x7003, 0x0000, 0x080c, 0x195f, 0x0804, 0x1c5e,
+	0x0056, 0x7d0c, 0xd5bc, 0x1110, 0x080c, 0xac73, 0x005e, 0x080c,
+	0x1d22, 0x00f6, 0x7004, 0x2078, 0x080c, 0x5029, 0x0118, 0x7820,
+	0xc0f5, 0x7822, 0x00fe, 0x682b, 0xffff, 0x682f, 0xffff, 0x6808,
+	0x8001, 0x680a, 0x697c, 0x791a, 0x6980, 0x791e, 0x0804, 0x1c5e,
+	0x7004, 0x00c6, 0x2060, 0x6020, 0x00ce, 0xd0f4, 0x0128, 0x6808,
+	0x8001, 0x680a, 0x0804, 0x1c5e, 0x7818, 0x6812, 0x7a1c, 0x6a16,
+	0xd19c, 0x0160, 0xa205, 0x0150, 0x7004, 0xa080, 0x0007, 0x2004,
+	0xa084, 0xfffd, 0xa086, 0x0008, 0x1904, 0x1aa6, 0x684c, 0xc0f5,
+	0x684e, 0x7814, 0xa005, 0x1180, 0x7003, 0x0000, 0x6808, 0x8001,
+	0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048, 0x080c, 0x80a7,
+	0x080c, 0x195f, 0x0804, 0x1c5e, 0x7818, 0x6812, 0x781c, 0x6816,
+	0x7814, 0x7908, 0xa18c, 0x0fff, 0xa188, 0x0007, 0x8114, 0x8214,
+	0x8214, 0xa10a, 0x8104, 0x8004, 0x8004, 0xa20a, 0x810b, 0x810b,
+	0x810b, 0x080c, 0x1da5, 0x7803, 0x0004, 0x780f, 0xffff, 0x7803,
+	0x0001, 0x7804, 0xd0fc, 0x0de8, 0x7803, 0x0002, 0x7803, 0x0004,
+	0x780f, 0x00f6, 0x7004, 0x7007, 0x0000, 0x2060, 0x2009, 0x0048,
+	0x080c, 0x80a7, 0x080c, 0x1dd7, 0x0958, 0x7908, 0xd1ec, 0x1118,
+	0x2009, 0x0009, 0x0010, 0x2009, 0x0019, 0x7902, 0x7003, 0x0003,
+	0x0804, 0x1c5e, 0x8001, 0x7002, 0xd194, 0x01a8, 0x7804, 0xd0fc,
+	0x1904, 0x1c2c, 0xd09c, 0x0130, 0x7804, 0xd0fc, 0x1904, 0x1a74,
+	0xd09c, 0x11a8, 0x8aff, 0x0904, 0x1c5e, 0x2009, 0x0001, 0x080c,
+	0x19e0, 0x0804, 0x1c5e, 0xa184, 0x0888, 0x1148, 0x8aff, 0x0904,
+	0x1c5e, 0x2009, 0x0001, 0x080c, 0x19e0, 0x0804, 0x1c5e, 0x7818,
+	0x6812, 0x7a1c, 0x6a16, 0xa205, 0x0904, 0x1b3e, 0x7803, 0x0004,
+	0x7003, 0x0000, 0xd1bc, 0x1904, 0x1c0f, 0x6834, 0xa084, 0x00ff,
+	0xa086, 0x0029, 0x1118, 0xd19c, 0x1904, 0x1b3e, 0x0026, 0x0036,
+	0x7c20, 0x7d24, 0x7e30, 0x7f34, 0x7818, 0x6812, 0x781c, 0x6816,
+	0x2001, 0x0201, 0x2004, 0xa005, 0x0140, 0x7808, 0xd0ec, 0x1128,
+	0x7803, 0x0009, 0x7003, 0x0004, 0x0020, 0x0016, 0x080c, 0x1c62,
+	0x001e, 0x6b28, 0x6a2c, 0x080c, 0x215e, 0x00d6, 0x2805, 0xac68,
+	0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c, 0xa213, 0x0020,
+	0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0xd194, 0x0904, 0x1ac8,
+	0x2a00, 0x6826, 0x2c00, 0x681a, 0x2800, 0x6832, 0x6808, 0x8001,
+	0x680a, 0x6b2a, 0x6a2e, 0x003e, 0x002e, 0x0804, 0x1b50, 0x0056,
+	0x7d0c, 0x080c, 0xac73, 0x005e, 0x080c, 0x1d22, 0x00f6, 0x7004,
+	0x2078, 0x080c, 0x5029, 0x0118, 0x7820, 0xc0f5, 0x7822, 0x00fe,
+	0x682b, 0xffff, 0x682f, 0xffff, 0x6808, 0x8001, 0x680a, 0x697c,
+	0x791a, 0x6980, 0x791e, 0x0490, 0x7804, 0xd09c, 0x0904, 0x1a74,
+	0x7c20, 0x7824, 0xa405, 0x1904, 0x1a74, 0x7803, 0x0002, 0x0804,
+	0x1bb7, 0x7803, 0x0004, 0x7003, 0x0000, 0x7004, 0xa00d, 0x0150,
+	0x6808, 0x8001, 0x680a, 0x1130, 0x7004, 0x2060, 0x2009, 0x0048,
+	0x080c, 0x80a7, 0x080c, 0x195f, 0x0088, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x7004, 0x2060, 0x6010, 0xa005, 0x0da0, 0x2068, 0x6808,
+	0x8000, 0x680a, 0x6c28, 0x6b2c, 0x080c, 0x197a, 0x001e, 0x000e,
+	0x012e, 0x0005, 0x700c, 0x7110, 0xa106, 0x0904, 0x1ce1, 0x7004,
+	0x0016, 0x210c, 0xa106, 0x001e, 0x0904, 0x1ce1, 0x00d6, 0x00c6,
+	0x216c, 0x2d00, 0xa005, 0x0904, 0x1cdf, 0x6820, 0xd0d4, 0x1904,
+	0x1cdf, 0x6810, 0x2068, 0x6850, 0xd0fc, 0x0558, 0x8108, 0x2104,
+	0x6b2c, 0xa306, 0x1904, 0x1cdf, 0x8108, 0x2104, 0x6a28, 0xa206,
+	0x1904, 0x1cdf, 0x6850, 0xc0fc, 0xc0f5, 0x6852, 0x686c, 0x7822,
+	0x6870, 0x7826, 0x681c, 0x7832, 0x6820, 0x7836, 0x6818, 0x2060,
+	0x6034, 0xd09c, 0x0150, 0x6830, 0x2005, 0x00d6, 0xac68, 0x6808,
+	0x783a, 0x680c, 0x783e, 0x00de, 0x04a0, 0xa006, 0x783a, 0x783e,
+	0x0480, 0x8108, 0x2104, 0xa005, 0x1590, 0x8108, 0x2104, 0xa005,
+	0x1570, 0x6850, 0xc0f5, 0x6852, 0x6830, 0x2005, 0x6918, 0xa160,
+	0xa180, 0x000d, 0x2004, 0xd09c, 0x1170, 0x6008, 0x7822, 0x686e,
+	0x600c, 0x7826, 0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0xa006,
+	0x783a, 0x783e, 0x0070, 0x6010, 0x7822, 0x686e, 0x6014, 0x7826,
+	0x6872, 0x6000, 0x7832, 0x6004, 0x7836, 0x6008, 0x783a, 0x600c,
+	0x783e, 0x6810, 0x781a, 0x6814, 0x781e, 0x7803, 0x0011, 0x00ce,
+	0x00de, 0x0005, 0x2011, 0x0201, 0x2009, 0x003c, 0x2204, 0xa005,
+	0x1118, 0x8109, 0x1dd8, 0x0005, 0x0005, 0x0ca1, 0x01e0, 0x7908,
+	0xd1ec, 0x1160, 0x080c, 0x1dd7, 0x0148, 0x7803, 0x0009, 0x7904,
+	0xd1fc, 0x0de8, 0x7803, 0x0006, 0x0c29, 0x0168, 0x780c, 0xd0a4,
+	0x1150, 0x7007, 0x0000, 0x080c, 0x1dd7, 0x0140, 0x7803, 0x0019,
+	0x7003, 0x0003, 0x0018, 0x00b1, 0xa085, 0x0001, 0x0005, 0x0126,
+	0x2091, 0x2200, 0x7000, 0xa086, 0x0003, 0x1150, 0x700c, 0x7110,
+	0xa106, 0x0130, 0x20e1, 0x9028, 0x700f, 0xb003, 0x7013, 0xb003,
+	0x012e, 0x0005, 0x00c6, 0x080c, 0x574f, 0x1550, 0x2001, 0x0160,
+	0x2003, 0x0000, 0x2001, 0x0138, 0x2003, 0x0000, 0x2011, 0x00c8,
+	0xe000, 0xe000, 0x8211, 0x1de0, 0x080c, 0x1d7e, 0x700c, 0x7110,
+	0xa106, 0x0190, 0x2104, 0xa005, 0x0130, 0x2060, 0x6010, 0x2060,
+	0x6008, 0x8001, 0x600a, 0xa188, 0x0003, 0xa182, 0xb01e, 0x0210,
+	0x2009, 0xb003, 0x7112, 0x0c50, 0x080c, 0x57d1, 0x00ce, 0x0005,
+	0x04a9, 0x20e1, 0x9028, 0x700c, 0x7110, 0xa106, 0x01d0, 0x2104,
+	0xa005, 0x0130, 0x2060, 0x6010, 0x2060, 0x6008, 0x8001, 0x600a,
+	0xa188, 0x0003, 0xa182, 0xb01e, 0x0210, 0x2009, 0xb003, 0x7112,
+	0x700c, 0xa106, 0x1d40, 0x080c, 0x2744, 0x2001, 0x0138, 0x2102,
+	0x0c10, 0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x2001, 0x0160,
+	0x2502, 0x2001, 0x0138, 0x2202, 0x00ce, 0x0005, 0x20e1, 0x9028,
+	0x2001, 0x015d, 0x200c, 0x810a, 0x2102, 0x0005, 0x2001, 0x0138,
+	0x2014, 0x2003, 0x0000, 0x2001, 0x0160, 0x202c, 0x2003, 0x0000,
+	0x2021, 0xb015, 0x2001, 0x0141, 0x201c, 0xd3dc, 0x1168, 0x2001,
+	0x0109, 0x201c, 0xa39c, 0x0048, 0x1138, 0x2001, 0x0111, 0x201c,
+	0x83ff, 0x1110, 0x8421, 0x1d70, 0x0005, 0x00e6, 0x2071, 0x0200,
+	0x7808, 0xa084, 0xf000, 0xa10d, 0x08c9, 0x2019, 0x5000, 0x8319,
+	0x0168, 0x2001, 0xb01e, 0x2004, 0xa086, 0x0000, 0x0138, 0x2001,
+	0x0021, 0xd0fc, 0x0da0, 0x080c, 0x1ff4, 0x0c78, 0x20e1, 0x7000,
+	0x7324, 0x7420, 0x7028, 0x7028, 0x7426, 0x7037, 0x0001, 0x810f,
+	0x712e, 0x702f, 0x0100, 0x7037, 0x0008, 0x7326, 0x7422, 0x2001,
+	0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x00ee, 0x0005, 0x7908,
+	0xa18c, 0x0fff, 0xa182, 0x0009, 0x0218, 0xa085, 0x0001, 0x0088,
+	0x2001, 0x020a, 0x81ff, 0x0130, 0x20e1, 0x6000, 0x200c, 0x200c,
+	0x200c, 0x200c, 0x20e1, 0x7000, 0x200c, 0x200c, 0x7003, 0x0000,
+	0xa006, 0x0005, 0x00f6, 0x00e6, 0x0016, 0x0026, 0x2071, 0xaffd,
+	0x2079, 0x0030, 0x2011, 0x0050, 0x7000, 0xa086, 0x0000, 0x01a8,
+	0x8211, 0x0188, 0x2001, 0x0005, 0x2004, 0xd08c, 0x0dc8, 0x7904,
+	0xa18c, 0x0780, 0x0016, 0x080c, 0x1a6c, 0x001e, 0x81ff, 0x1118,
+	0x2011, 0x0050, 0x0c48, 0xa085, 0x0001, 0x002e, 0x001e, 0x00ee,
+	0x00fe, 0x0005, 0x7803, 0x0004, 0x2009, 0x0064, 0x7804, 0xd0ac,
+	0x0904, 0x1e66, 0x8109, 0x1dd0, 0x2009, 0x0100, 0x210c, 0xa18a,
+	0x0003, 0x0a0c, 0x14f6, 0x080c, 0x20f2, 0x00e6, 0x00f6, 0x2071,
+	0xafec, 0x2079, 0x0010, 0x7004, 0xa086, 0x0000, 0x0538, 0x7800,
+	0x0006, 0x7820, 0x0006, 0x7830, 0x0006, 0x7834, 0x0006, 0x7838,
+	0x0006, 0x783c, 0x0006, 0x7803, 0x0004, 0xe000, 0xe000, 0x2079,
+	0x0030, 0x7804, 0xd0ac, 0x190c, 0x14f6, 0x2079, 0x0010, 0x000e,
+	0x783e, 0x000e, 0x783a, 0x000e, 0x7836, 0x000e, 0x7832, 0x000e,
+	0x7822, 0x000e, 0x7802, 0x00fe, 0x00ee, 0x0030, 0x00fe, 0x00ee,
+	0x7804, 0xd0ac, 0x190c, 0x14f6, 0x080c, 0x6d0d, 0x0005, 0x00e6,
+	0x2071, 0xb01e, 0x7003, 0x0000, 0x00ee, 0x0005, 0x00d6, 0xa280,
+	0x0004, 0x206c, 0x694c, 0xd1dc, 0x1904, 0x1ee4, 0x6934, 0xa184,
+	0x0007, 0x0002, 0x1e82, 0x1ecf, 0x1e82, 0x1e82, 0x1e82, 0x1eb6,
+	0x1e95, 0x1e84, 0x080c, 0x14f6, 0x684c, 0xd0b4, 0x0904, 0x1fcc,
+	0x6860, 0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a,
+	0x6880, 0x680e, 0x6958, 0x0804, 0x1ed7, 0x6834, 0xa084, 0x00ff,
+	0xa086, 0x001e, 0x1d38, 0x684c, 0xd0b4, 0x0904, 0x1fcc, 0x6860,
+	0x682e, 0x6816, 0x685c, 0x682a, 0x6812, 0x687c, 0x680a, 0x6880,
+	0x680e, 0x6804, 0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f,
+	0xa080, 0x2186, 0x2005, 0x6832, 0x6958, 0x0450, 0xa18c, 0x00ff,
+	0xa186, 0x0015, 0x1548, 0x684c, 0xd0b4, 0x0904, 0x1fcc, 0x6804,
+	0x681a, 0xa080, 0x000d, 0x2004, 0xa084, 0x000f, 0xa080, 0x2186,
+	0x2005, 0x6832, 0x6958, 0xa006, 0x682e, 0x682a, 0x0088, 0x684c,
+	0xd0b4, 0x0904, 0x1a47, 0x6958, 0xa006, 0x682e, 0x682a, 0x2d00,
+	0x681a, 0x6834, 0xa084, 0x000f, 0xa080, 0x2186, 0x2005, 0x6832,
+	0x6926, 0x684c, 0xc0dd, 0x684e, 0x00de, 0x0005, 0x00f6, 0x2079,
+	0x0020, 0x7804, 0xd0fc, 0x190c, 0x1ff4, 0x00e6, 0x00d6, 0x2071,
+	0xb01e, 0x7000, 0xa005, 0x1904, 0x1f4c, 0x00c6, 0x7206, 0xa280,
+	0x0004, 0x205c, 0x7004, 0x2068, 0x7803, 0x0004, 0x6818, 0x00d6,
+	0x2068, 0x686c, 0x7812, 0x6890, 0x00f6, 0x20e1, 0x9040, 0x2079,
+	0x0200, 0x781a, 0x2079, 0x0100, 0x8004, 0x78d6, 0x00fe, 0x00de,
+	0x2b68, 0x6824, 0x2050, 0x6818, 0x2060, 0x6830, 0x2040, 0x6034,
+	0xa0cc, 0x000f, 0x6908, 0x791a, 0x7116, 0x680c, 0x781e, 0x701a,
+	0xa006, 0x700e, 0x7012, 0x7004, 0x692c, 0x6814, 0xa106, 0x1120,
+	0x6928, 0x6810, 0xa106, 0x0158, 0x0036, 0x0046, 0x6b14, 0x6c10,
+	0x080c, 0x21a6, 0x004e, 0x003e, 0x0110, 0x00ce, 0x00a8, 0x8aff,
+	0x1120, 0x00ce, 0xa085, 0x0001, 0x0078, 0x0126, 0x2091, 0x8000,
+	0x2079, 0x0020, 0x2009, 0x0001, 0x0059, 0x0118, 0x2009, 0x0001,
+	0x0039, 0x012e, 0x00ce, 0xa006, 0x00de, 0x00ee, 0x00fe, 0x0005,
+	0x0076, 0x0066, 0x0056, 0x0046, 0x0036, 0x0026, 0x8aff, 0x0904,
+	0x1fc5, 0x700c, 0x7214, 0xa23a, 0x7010, 0x7218, 0xa203, 0x0a04,
+	0x1fc4, 0xa705, 0x0904, 0x1fc4, 0xa03e, 0x2730, 0x6850, 0xd0fc,
+	0x11a8, 0x00d6, 0x2805, 0xac68, 0x2900, 0x0002, 0x1fa7, 0x1f8c,
+	0x1f8c, 0x1fa7, 0x1fa7, 0x1fa0, 0x1fa7, 0x1f8c, 0x1fa7, 0x1f91,
+	0x1f91, 0x1fa7, 0x1fa7, 0x1fa7, 0x1f98, 0x1f91, 0xc0fc, 0x6852,
+	0x6b6c, 0x6a70, 0x6d1c, 0x6c20, 0xd99c, 0x0528, 0x00d6, 0x2805,
+	0xac68, 0x6f08, 0x6e0c, 0x00f0, 0x6b08, 0x6a0c, 0x6d00, 0x6c04,
+	0x00c8, 0x6b10, 0x6a14, 0x6d00, 0x6c04, 0x6f08, 0x6e0c, 0x0090,
+	0x00de, 0x00d6, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x1138,
+	0x00de, 0x080c, 0x2148, 0x1904, 0x1f56, 0xa00e, 0x00f0, 0x00de,
+	0x080c, 0x14f6, 0x00de, 0x7b22, 0x7a26, 0x7d32, 0x7c36, 0x7f3a,
+	0x7e3e, 0x7902, 0x7000, 0x8000, 0x7002, 0x6828, 0xa300, 0x682a,
+	0x682c, 0xa201, 0x682e, 0x700c, 0xa300, 0x700e, 0x7010, 0xa201,
+	0x7012, 0x080c, 0x2148, 0x0008, 0xa006, 0x002e, 0x003e, 0x004e,
+	0x005e, 0x006e, 0x007e, 0x0005, 0x080c, 0x14f6, 0x0026, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x7004, 0x2060, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9596,
+	0x0118, 0x6850, 0xc0bd, 0x6852, 0x00de, 0x080c, 0x929c, 0x20e1,
+	0x9040, 0x080c, 0x7cb8, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x080c,
+	0x6d0d, 0x002e, 0x0804, 0x20ad, 0x0126, 0x2091, 0x2400, 0x0006,
+	0x0016, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x2079, 0x0020, 0x2071,
+	0xb01e, 0x2b68, 0x6818, 0x2060, 0x7904, 0x7803, 0x0002, 0xa184,
+	0x0700, 0x1920, 0x7000, 0x0002, 0x20ad, 0x2010, 0x2080, 0x20ab,
+	0x8001, 0x7002, 0xd19c, 0x1170, 0x8aff, 0x05d0, 0x2009, 0x0001,
+	0x080c, 0x1f50, 0x0904, 0x20ad, 0x2009, 0x0001, 0x080c, 0x1f50,
+	0x0804, 0x20ad, 0x7803, 0x0004, 0xd194, 0x0148, 0x6850, 0xc0fc,
+	0x6852, 0x8aff, 0x11d8, 0x684c, 0xc0f5, 0x684e, 0x00b8, 0x0026,
+	0x0036, 0x6b28, 0x6a2c, 0x7820, 0x686e, 0xa31a, 0x7824, 0x6872,
+	0xa213, 0x7830, 0x681e, 0x7834, 0x6822, 0x6b2a, 0x6a2e, 0x003e,
+	0x002e, 0x080c, 0x215e, 0x6850, 0xc0fd, 0x6852, 0x2a00, 0x6826,
+	0x2c00, 0x681a, 0x2800, 0x6832, 0x7003, 0x0000, 0x0804, 0x20ad,
+	0x00f6, 0x0026, 0x781c, 0x0006, 0x7818, 0x0006, 0x2079, 0x0100,
+	0x7a14, 0xa284, 0x0184, 0xa085, 0x0012, 0x7816, 0x0036, 0x2019,
+	0x1000, 0x8319, 0x090c, 0x14f6, 0x7820, 0xd0bc, 0x1dd0, 0x003e,
+	0x79c8, 0x000e, 0xa102, 0x001e, 0x0006, 0x0016, 0x79c4, 0x000e,
+	0xa103, 0x78c6, 0x000e, 0x78ca, 0xa284, 0x0184, 0xa085, 0x0012,
+	0x7816, 0x002e, 0x00fe, 0x7803, 0x0008, 0x7003, 0x0000, 0x0468,
+	0x8001, 0x7002, 0xd194, 0x0168, 0x7804, 0xd0fc, 0x1904, 0x2004,
+	0xd19c, 0x11f8, 0x8aff, 0x0508, 0x2009, 0x0001, 0x080c, 0x1f50,
+	0x00e0, 0x0026, 0x0036, 0x6b28, 0x6a2c, 0x080c, 0x215e, 0x00d6,
+	0x2805, 0xac68, 0x6034, 0xd09c, 0x1128, 0x6808, 0xa31a, 0x680c,
+	0xa213, 0x0020, 0x6810, 0xa31a, 0x6814, 0xa213, 0x00de, 0x0804,
+	0x2033, 0x0804, 0x202f, 0x080c, 0x14f6, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x001e, 0x000e, 0x012e, 0x0005, 0x00f6, 0x00e6, 0x2071,
+	0xb01e, 0x7000, 0xa086, 0x0000, 0x0590, 0x2079, 0x0020, 0x0016,
+	0x2009, 0x0207, 0x210c, 0xd194, 0x0158, 0x2009, 0x020c, 0x210c,
+	0xa184, 0x0003, 0x0128, 0x20e1, 0x9040, 0x2001, 0x020c, 0x2102,
+	0x2009, 0x0206, 0x2104, 0x2009, 0x0203, 0x210c, 0xa106, 0x1110,
+	0x20e1, 0x9040, 0x7804, 0xd0fc, 0x0d18, 0x080c, 0x1ff4, 0x7000,
+	0xa086, 0x0000, 0x19e8, 0x001e, 0x7803, 0x0004, 0x7804, 0xd0ac,
+	0x1de8, 0x20e1, 0x9040, 0x7803, 0x0002, 0x7003, 0x0000, 0x00ee,
+	0x00fe, 0x0005, 0x0026, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2071,
+	0xb01e, 0x2079, 0x0020, 0x7000, 0xa086, 0x0000, 0x0540, 0x7004,
+	0x2060, 0x6010, 0x2068, 0x080c, 0x9596, 0x0158, 0x6850, 0xc0b5,
+	0x6852, 0x680c, 0x7a1c, 0xa206, 0x1120, 0x6808, 0x7a18, 0xa206,
+	0x01e0, 0x2001, 0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803,
+	0x0004, 0x7003, 0x0000, 0x7004, 0x2060, 0x080c, 0x929c, 0x20e1,
+	0x9040, 0x080c, 0x7cb8, 0x2011, 0x0000, 0x080c, 0x7ae9, 0x00fe,
+	0x00ee, 0x00de, 0x00ce, 0x002e, 0x0005, 0x6810, 0x6a14, 0xa205,
+	0x1d00, 0x684c, 0xc0dc, 0x684e, 0x2c10, 0x080c, 0x1e6e, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x20e1, 0x9040, 0x7803, 0x0004, 0x7003,
+	0x0000, 0x2069, 0xafc7, 0x6833, 0x0000, 0x683f, 0x0000, 0x08f8,
+	0x8840, 0x2805, 0xa005, 0x1170, 0x6004, 0xa005, 0x0168, 0x681a,
+	0x2060, 0x6034, 0xa084, 0x000f, 0xa080, 0x2186, 0x2045, 0x88ff,
+	0x090c, 0x14f6, 0x8a51, 0x0005, 0x2050, 0x0005, 0x8a50, 0x8841,
+	0x2805, 0xa005, 0x1190, 0x2c00, 0xad06, 0x0120, 0x6000, 0xa005,
+	0x1108, 0x2d00, 0x2060, 0x681a, 0x6034, 0xa084, 0x000f, 0xa080,
+	0x2196, 0x2045, 0x88ff, 0x090c, 0x14f6, 0x0005, 0x0000, 0x0011,
+	0x0015, 0x0019, 0x001d, 0x0021, 0x0025, 0x0029, 0x0000, 0x000f,
+	0x0015, 0x001b, 0x0021, 0x0027, 0x0000, 0x0000, 0x0000, 0x217b,
+	0x2177, 0x0000, 0x0000, 0x2185, 0x0000, 0x217b, 0x0000, 0x2182,
+	0x217f, 0x0000, 0x0000, 0x0000, 0x2185, 0x2182, 0x0000, 0x217d,
+	0x217d, 0x0000, 0x0000, 0x2185, 0x0000, 0x217d, 0x0000, 0x2183,
+	0x2183, 0x0000, 0x0000, 0x0000, 0x2185, 0x2183, 0x00a6, 0x0096,
+	0x0086, 0x6b2e, 0x6c2a, 0x6858, 0xa055, 0x0904, 0x2237, 0x2d60,
+	0x6034, 0xa0cc, 0x000f, 0xa9c0, 0x2186, 0xa986, 0x0007, 0x0130,
+	0xa986, 0x000e, 0x0118, 0xa986, 0x000f, 0x1120, 0x605c, 0xa422,
+	0x6060, 0xa31a, 0x2805, 0xa045, 0x1140, 0x0310, 0x0804, 0x2237,
+	0x6004, 0xa065, 0x0904, 0x2237, 0x0c18, 0x2805, 0xa005, 0x01a8,
+	0xac68, 0xd99c, 0x1128, 0x6808, 0xa422, 0x680c, 0xa31b, 0x0020,
+	0x6810, 0xa422, 0x6814, 0xa31b, 0x0620, 0x2300, 0xa405, 0x0150,
+	0x8a51, 0x0904, 0x2237, 0x8840, 0x0c40, 0x6004, 0xa065, 0x0904,
+	0x2237, 0x0830, 0x8a51, 0x0904, 0x2237, 0x8840, 0x2805, 0xa005,
+	0x1158, 0x6004, 0xa065, 0x0904, 0x2237, 0x6034, 0xa0cc, 0x000f,
+	0xa9c0, 0x2186, 0x2805, 0x2040, 0x2b68, 0x6850, 0xc0fc, 0x6852,
+	0x0458, 0x8422, 0x8420, 0x831a, 0xa399, 0x0000, 0x00d6, 0x2b68,
+	0x6c6e, 0x6b72, 0x00de, 0xd99c, 0x1168, 0x6908, 0x2400, 0xa122,
+	0x690c, 0x2300, 0xa11b, 0x0a0c, 0x14f6, 0x6800, 0xa420, 0x6804,
+	0xa319, 0x0060, 0x6910, 0x2400, 0xa122, 0x6914, 0x2300, 0xa11b,
+	0x0a0c, 0x14f6, 0x6800, 0xa420, 0x6804, 0xa319, 0x2b68, 0x6c1e,
+	0x6b22, 0x6850, 0xc0fd, 0x6852, 0x2c00, 0x681a, 0x2800, 0x6832,
+	0x2a00, 0x6826, 0x000e, 0x000e, 0x000e, 0xa006, 0x0028, 0x008e,
+	0x009e, 0x00ae, 0xa085, 0x0001, 0x0005, 0x2001, 0x0005, 0x2004,
+	0xa084, 0x0007, 0x0002, 0x224b, 0x224c, 0x224f, 0x2252, 0x2257,
+	0x225a, 0x225f, 0x2264, 0x0005, 0x080c, 0x1ff4, 0x0005, 0x080c,
+	0x1a6c, 0x0005, 0x080c, 0x1a6c, 0x080c, 0x1ff4, 0x0005, 0x080c,
+	0x16f8, 0x0005, 0x080c, 0x1ff4, 0x080c, 0x16f8, 0x0005, 0x080c,
+	0x1a6c, 0x080c, 0x16f8, 0x0005, 0x080c, 0x1a6c, 0x080c, 0x1ff4,
+	0x080c, 0x16f8, 0x0005, 0x0126, 0x2091, 0x2600, 0x2079, 0x0200,
+	0x2071, 0xb280, 0x2069, 0xad00, 0x2009, 0x0004, 0x7912, 0x7817,
+	0x0004, 0x080c, 0x2651, 0x781b, 0x0002, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x20a9, 0x0080, 0x782f, 0x0000, 0x1f04, 0x2283, 0x20e1,
+	0x9080, 0x783b, 0x001f, 0x20e1, 0x8700, 0x012e, 0x0005, 0x0126,
+	0x2091, 0x2600, 0x781c, 0xd0a4, 0x190c, 0x2335, 0xa084, 0x0007,
+	0x0002, 0x22b3, 0x22a1, 0x22a4, 0x22a7, 0x22ac, 0x22ae, 0x22b0,
+	0x22b2, 0x080c, 0x5fb7, 0x0078, 0x080c, 0x5ff0, 0x0060, 0x080c,
+	0x5fb7, 0x080c, 0x5ff0, 0x0038, 0x0041, 0x0028, 0x0031, 0x0018,
+	0x0021, 0x0008, 0x0011, 0x012e, 0x0005, 0x0006, 0x0016, 0x0026,
+	0x7930, 0xa184, 0x0003, 0x0118, 0x20e1, 0x9040, 0x04a0, 0xa184,
+	0x0030, 0x01e0, 0x6a00, 0xa286, 0x0003, 0x1108, 0x00a0, 0x080c,
+	0x574f, 0x1178, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00,
+	0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a,
+	0x0010, 0x080c, 0x485e, 0x20e1, 0x9010, 0x00a8, 0xa184, 0x00c0,
+	0x0168, 0x00e6, 0x0036, 0x0046, 0x0056, 0x2071, 0xaffd, 0x080c,
+	0x1d22, 0x005e, 0x004e, 0x003e, 0x00ee, 0x0028, 0xa184, 0x0300,
+	0x0110, 0x20e1, 0x9020, 0x7932, 0x002e, 0x001e, 0x000e, 0x0005,
+	0x0016, 0x00e6, 0x00f6, 0x2071, 0xad00, 0x7128, 0x2001, 0xaf90,
+	0x2102, 0x2001, 0xaf98, 0x2102, 0xa182, 0x0211, 0x1218, 0x2009,
+	0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009, 0x0007, 0x00d0,
+	0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0, 0xa182, 0x0349,
+	0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421, 0x1218, 0x2009,
+	0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009, 0x0003, 0x0010,
+	0x2009, 0x0002, 0x2079, 0x0200, 0x7912, 0x7817, 0x0004, 0x080c,
+	0x2651, 0x00fe, 0x00ee, 0x001e, 0x0005, 0x7938, 0x080c, 0x14f6,
+	0x0126, 0x2091, 0x2800, 0x2061, 0x0100, 0x2071, 0xad00, 0x6024,
+	0x6026, 0x6053, 0x0030, 0x080c, 0x2690, 0x6050, 0xa084, 0xfe7f,
+	0x6052, 0x2009, 0x00ef, 0x6132, 0x6136, 0x080c, 0x26a0, 0x60e7,
+	0x0000, 0x61ea, 0x60e3, 0x0008, 0x604b, 0xf7f7, 0x6043, 0x0000,
+	0x602f, 0x0080, 0x602f, 0x0000, 0x6007, 0x0e9f, 0x601b, 0x001e,
+	0x600f, 0x00ff, 0x2001, 0xaf8c, 0x2003, 0x00ff, 0x602b, 0x002f,
+	0x012e, 0x0005, 0x2001, 0xad31, 0x2003, 0x0000, 0x2001, 0xad30,
+	0x2003, 0x0001, 0x0005, 0x0126, 0x2091, 0x2800, 0x0006, 0x0016,
+	0x0026, 0x6124, 0xa184, 0x1e2c, 0x1118, 0xa184, 0x0007, 0x002a,
+	0xa195, 0x0004, 0xa284, 0x0007, 0x0002, 0x23a7, 0x238d, 0x2390,
+	0x2393, 0x2398, 0x239a, 0x239e, 0x23a2, 0x080c, 0x6699, 0x00b8,
+	0x080c, 0x6774, 0x00a0, 0x080c, 0x6774, 0x080c, 0x6699, 0x0078,
+	0x0099, 0x0068, 0x080c, 0x6699, 0x0079, 0x0048, 0x080c, 0x6774,
+	0x0059, 0x0028, 0x080c, 0x6774, 0x080c, 0x6699, 0x0029, 0x002e,
+	0x001e, 0x000e, 0x012e, 0x0005, 0x6124, 0xd19c, 0x1904, 0x25bf,
+	0x080c, 0x574f, 0x0578, 0x7000, 0xa086, 0x0003, 0x0198, 0x6024,
+	0xa084, 0x1800, 0x0178, 0x080c, 0x5775, 0x0118, 0x080c, 0x5761,
+	0x1148, 0x6027, 0x0020, 0x6043, 0x0000, 0x2001, 0xaf9d, 0x2003,
+	0xaaaa, 0x0458, 0x080c, 0x5775, 0x15d0, 0x6024, 0xa084, 0x1800,
+	0x1108, 0x04a8, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e,
+	0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c, 0x569a,
+	0x0804, 0x25bf, 0xd1ac, 0x1518, 0x6024, 0xd0dc, 0x1170, 0xd0e4,
+	0x1188, 0xd0d4, 0x11a0, 0xd0cc, 0x0130, 0x7088, 0xa086, 0x0028,
+	0x1110, 0x080c, 0x58da, 0x0804, 0x25bf, 0x2001, 0xaf9e, 0x2003,
+	0x0000, 0x0048, 0x2001, 0xaf9e, 0x2003, 0x0002, 0x0020, 0x080c,
+	0x584d, 0x0804, 0x25bf, 0x080c, 0x597a, 0x0804, 0x25bf, 0xd1ac,
+	0x0904, 0x2507, 0x080c, 0x574f, 0x11d8, 0x6027, 0x0020, 0x0006,
+	0x0026, 0x0036, 0x080c, 0x576b, 0x1170, 0x2001, 0xaf9e, 0x2003,
+	0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c, 0x569a, 0x003e,
+	0x002e, 0x000e, 0x0005, 0x003e, 0x002e, 0x000e, 0x080c, 0x5726,
+	0x0016, 0x0046, 0x00c6, 0x644c, 0xa486, 0xf0f0, 0x1138, 0x2061,
+	0x0100, 0x644a, 0x6043, 0x0090, 0x6043, 0x0010, 0x74ca, 0xa48c,
+	0xff00, 0x7034, 0xd084, 0x0178, 0xa186, 0xf800, 0x1160, 0x7038,
+	0xd084, 0x1148, 0xc085, 0x703a, 0x0036, 0x2418, 0x2011, 0x8016,
+	0x080c, 0x3c5c, 0x003e, 0xa196, 0xff00, 0x05b8, 0x7050, 0xa084,
+	0x00ff, 0x810f, 0xa116, 0x0588, 0x7130, 0xd184, 0x1570, 0x2011,
+	0xad52, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011, 0xad52,
+	0x2214, 0xd2ac, 0x1510, 0x6240, 0xa294, 0x0010, 0x0130, 0x6248,
+	0xa294, 0xff00, 0xa296, 0xff00, 0x01c0, 0x7030, 0xd08c, 0x0904,
+	0x24d2, 0x7034, 0xd08c, 0x1140, 0x2001, 0xad0c, 0x200c, 0xd1ac,
+	0x1904, 0x24d2, 0xc1ad, 0x2102, 0x0036, 0x73c8, 0x2011, 0x8013,
+	0x080c, 0x3c5c, 0x003e, 0x0804, 0x24d2, 0x7034, 0xd08c, 0x1140,
+	0x2001, 0xad0c, 0x200c, 0xd1ac, 0x1904, 0x24d2, 0xc1ad, 0x2102,
+	0x0036, 0x73c8, 0x2011, 0x8013, 0x080c, 0x3c5c, 0x003e, 0x7130,
+	0xc185, 0x7132, 0x2011, 0xad52, 0x220c, 0xd1a4, 0x01d0, 0x0016,
+	0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x663f, 0x2019, 0x000e,
+	0x080c, 0xa8eb, 0xa484, 0x00ff, 0xa080, 0x2be6, 0x200d, 0xa18c,
+	0xff00, 0x810f, 0x8127, 0xa006, 0x2009, 0x000e, 0x080c, 0xa96c,
+	0x001e, 0xd1ac, 0x1148, 0x0016, 0x2009, 0x0000, 0x2019, 0x0004,
+	0x080c, 0x2aac, 0x001e, 0x0070, 0x0156, 0x20a9, 0x007f, 0x2009,
+	0x0000, 0x080c, 0x4cdc, 0x1110, 0x080c, 0x493a, 0x8108, 0x1f04,
+	0x24c9, 0x015e, 0x00ce, 0x004e, 0x2011, 0x0003, 0x080c, 0x7adf,
+	0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581,
+	0x0036, 0x2019, 0x0000, 0x080c, 0x7a64, 0x003e, 0x60e3, 0x0000,
+	0x001e, 0x2001, 0xad00, 0x2014, 0xa296, 0x0004, 0x1128, 0xd19c,
+	0x1118, 0x6228, 0xc29d, 0x622a, 0x2003, 0x0001, 0x2001, 0xad22,
+	0x2003, 0x0000, 0x6027, 0x0020, 0x080c, 0x5775, 0x1140, 0x0016,
+	0x2009, 0x07d0, 0x2011, 0x567b, 0x080c, 0x6593, 0x001e, 0xd194,
+	0x0904, 0x25bf, 0x0016, 0x6220, 0xd2b4, 0x0904, 0x2570, 0x080c,
+	0x6581, 0x080c, 0x7834, 0x6027, 0x0004, 0x00f6, 0x2019, 0xafd0,
+	0x2304, 0xa07d, 0x0570, 0x7804, 0xa086, 0x0032, 0x1550, 0x00d6,
+	0x00c6, 0x00e6, 0x2069, 0x0140, 0x618c, 0x6288, 0x7818, 0x608e,
+	0x7808, 0x608a, 0x6043, 0x0002, 0x2001, 0x0003, 0x8001, 0x1df0,
+	0x6043, 0x0000, 0x6803, 0x1000, 0x6803, 0x0000, 0x618e, 0x628a,
+	0x080c, 0x6b73, 0x080c, 0x6c50, 0x7810, 0x2070, 0x7037, 0x0103,
+	0x2f60, 0x080c, 0x8078, 0x00ee, 0x00ce, 0x00de, 0x00fe, 0x001e,
+	0x0005, 0x00fe, 0x00d6, 0x2069, 0x0140, 0x6804, 0xa084, 0x4000,
+	0x0120, 0x6803, 0x1000, 0x6803, 0x0000, 0x00de, 0x00c6, 0x2061,
+	0xafc7, 0x6028, 0xa09a, 0x00c8, 0x1238, 0x8000, 0x602a, 0x00ce,
+	0x080c, 0x7827, 0x0804, 0x25be, 0x2019, 0xafd0, 0x2304, 0xa065,
+	0x0120, 0x2009, 0x0027, 0x080c, 0x80a7, 0x00ce, 0x0804, 0x25be,
+	0xd2bc, 0x0904, 0x25be, 0x080c, 0x658e, 0x6014, 0xa084, 0x0184,
+	0xa085, 0x0010, 0x6016, 0x6027, 0x0004, 0x00d6, 0x2069, 0x0140,
+	0x6804, 0xa084, 0x4000, 0x0120, 0x6803, 0x1000, 0x6803, 0x0000,
+	0x00de, 0x00c6, 0x2061, 0xafc7, 0x6044, 0xa09a, 0x00c8, 0x12f0,
+	0x8000, 0x6046, 0x603c, 0x00ce, 0xa005, 0x0540, 0x2009, 0x07d0,
+	0x080c, 0x6586, 0xa080, 0x0007, 0x2004, 0xa086, 0x0006, 0x1138,
+	0x6114, 0xa18c, 0x0184, 0xa18d, 0x0012, 0x6116, 0x00b8, 0x6114,
+	0xa18c, 0x0184, 0xa18d, 0x0016, 0x6116, 0x0080, 0x0036, 0x2019,
+	0x0001, 0x080c, 0x7a64, 0x003e, 0x2019, 0xafd6, 0x2304, 0xa065,
+	0x0120, 0x2009, 0x004f, 0x080c, 0x80a7, 0x00ce, 0x001e, 0xd19c,
+	0x0904, 0x261a, 0x7034, 0xd0ac, 0x1560, 0x0016, 0x0156, 0x6027,
+	0x0008, 0x602f, 0x0020, 0x20a9, 0x0006, 0x1d04, 0x25cd, 0x2091,
+	0x6000, 0x1f04, 0x25cd, 0x602f, 0x0000, 0x6150, 0xa185, 0x1400,
+	0x6052, 0x20a9, 0x0366, 0x1d04, 0x25db, 0x2091, 0x6000, 0x6020,
+	0xd09c, 0x1130, 0x015e, 0x6152, 0x001e, 0x6027, 0x0008, 0x0490,
+	0x080c, 0x2760, 0x1f04, 0x25db, 0x015e, 0x6152, 0x001e, 0x6027,
+	0x0008, 0x0016, 0x6028, 0xc09c, 0x602a, 0x2011, 0x0003, 0x080c,
+	0x7adf, 0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c, 0x79e1, 0x080c,
+	0x6581, 0x0036, 0x2019, 0x0000, 0x080c, 0x7a64, 0x003e, 0x60e3,
+	0x0000, 0x080c, 0xac8d, 0x080c, 0xaca8, 0xa085, 0x0001, 0x080c,
+	0x5793, 0x2001, 0xad00, 0x2003, 0x0004, 0x6027, 0x0008, 0x080c,
+	0x12cc, 0x001e, 0xa18c, 0xffd0, 0x6126, 0x0005, 0x0006, 0x0016,
+	0x0026, 0x00e6, 0x00f6, 0x0126, 0x2091, 0x8000, 0x2071, 0xad00,
+	0x71c0, 0x70c2, 0xa116, 0x01f0, 0x81ff, 0x0128, 0x2011, 0x8011,
+	0x080c, 0x3c5c, 0x00b8, 0x2011, 0x8012, 0x080c, 0x3c5c, 0x2001,
+	0xad71, 0x2004, 0xd0fc, 0x1170, 0x0036, 0x00c6, 0x080c, 0x26eb,
+	0x2061, 0x0100, 0x2019, 0x0028, 0x2009, 0x0000, 0x080c, 0x2aac,
+	0x00ce, 0x003e, 0x012e, 0x00fe, 0x00ee, 0x002e, 0x001e, 0x000e,
+	0x0005, 0x00c6, 0x00f6, 0x0006, 0x0026, 0x2061, 0x0100, 0xa190,
+	0x2664, 0x2205, 0x60f2, 0x2011, 0x2671, 0x2205, 0x60ee, 0x002e,
+	0x000e, 0x00fe, 0x00ce, 0x0005, 0x0840, 0x0840, 0x0840, 0x0580,
+	0x0420, 0x0348, 0x02c0, 0x0258, 0x0210, 0x01a8, 0x01a8, 0x01a8,
+	0x01a8, 0x0140, 0x00f8, 0x00d0, 0x00b0, 0x00a0, 0x2028, 0xa18c,
+	0x00ff, 0x2130, 0xa094, 0xff00, 0x1110, 0x81ff, 0x0118, 0x080c,
+	0x6278, 0x0038, 0xa080, 0x2be6, 0x200d, 0xa18c, 0xff00, 0x810f,
+	0xa006, 0x0005, 0xa080, 0x2be6, 0x200d, 0xa18c, 0x00ff, 0x0005,
+	0x00d6, 0x2069, 0x0140, 0x2001, 0xad14, 0x2003, 0x00ef, 0x20a9,
+	0x0010, 0xa006, 0x6852, 0x6856, 0x1f04, 0x269b, 0x00de, 0x0005,
+	0x0006, 0x00d6, 0x0026, 0x2069, 0x0140, 0x2001, 0xad14, 0x2102,
+	0x8114, 0x8214, 0x8214, 0x8214, 0x20a9, 0x0010, 0x6853, 0x0000,
+	0xa006, 0x82ff, 0x1128, 0xa184, 0x000f, 0xa080, 0xacae, 0x2005,
+	0x6856, 0x8211, 0x1f04, 0x26b0, 0x002e, 0x00de, 0x000e, 0x0005,
+	0x00c6, 0x2061, 0xad00, 0x6030, 0x0110, 0xc09d, 0x0008, 0xc09c,
+	0x6032, 0x00ce, 0x0005, 0x0156, 0x00d6, 0x0026, 0x0016, 0x0006,
+	0x2069, 0x0140, 0x6980, 0xa116, 0x0180, 0xa112, 0x1230, 0x8212,
+	0x8210, 0x22a8, 0x2001, 0x0402, 0x0018, 0x22a8, 0x2001, 0x0404,
+	0x680e, 0x1f04, 0x26e0, 0x680f, 0x0000, 0x000e, 0x001e, 0x002e,
+	0x00de, 0x015e, 0x0005, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0150,
+	0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002e, 0x080c,
+	0xa96c, 0x004e, 0x0005, 0x00f6, 0x0016, 0x0026, 0x2079, 0x0140,
+	0x78c4, 0xd0dc, 0x0548, 0xa084, 0x0700, 0xa08e, 0x0300, 0x1520,
+	0x2011, 0x0000, 0x2009, 0x0002, 0x2300, 0xa080, 0x0020, 0x2018,
+	0x2300, 0x080c, 0x6665, 0x2011, 0x0030, 0x2200, 0x8007, 0xa085,
+	0x004c, 0x78c2, 0x2009, 0x0204, 0x210c, 0x2200, 0xa100, 0x2009,
+	0x0138, 0x200a, 0x080c, 0x574f, 0x1118, 0x2009, 0xaf8e, 0x200a,
+	0x002e, 0x001e, 0x00fe, 0x0005, 0x78c3, 0x0000, 0x0cc8, 0x0126,
+	0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x2001, 0x0170, 0x200c,
+	0x8000, 0x2014, 0xa184, 0x0003, 0x0110, 0x0804, 0x1a6a, 0x002e,
+	0x001e, 0x000e, 0x012e, 0x0005, 0x0006, 0x2001, 0x0100, 0x2004,
+	0xa082, 0x0005, 0x000e, 0x0268, 0x2001, 0x0170, 0x200c, 0xa18c,
+	0x00ff, 0xa18e, 0x004c, 0x1128, 0x200c, 0xa18c, 0xff00, 0x810f,
+	0x0010, 0x2009, 0x0000, 0x2001, 0x0204, 0x2004, 0xa108, 0x0005,
+	0x0006, 0x0156, 0x00f6, 0x2079, 0x0100, 0x20a9, 0x000a, 0x7854,
+	0xd08c, 0x1110, 0x1f04, 0x2767, 0x00fe, 0x015e, 0x000e, 0x0005,
+	0x0016, 0x00c6, 0x0006, 0x2061, 0x0100, 0x6030, 0x0006, 0x6048,
+	0x0006, 0x60e4, 0x0006, 0x60e8, 0x0006, 0x6050, 0x0006, 0x60f0,
+	0x0006, 0x60ec, 0x0006, 0x600c, 0x0006, 0x6004, 0x0006, 0x6028,
+	0x0006, 0x60e0, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000, 0xe000,
+	0xe000, 0xe000, 0xe000, 0x602f, 0x0040, 0x602f, 0x0000, 0x000e,
+	0x60e2, 0x000e, 0x602a, 0x000e, 0x6006, 0x000e, 0x600e, 0x000e,
+	0x60ee, 0x000e, 0x60f2, 0x000e, 0x6052, 0x000e, 0x60ea, 0x000e,
+	0x60e6, 0x000e, 0x604a, 0x000e, 0x6032, 0x6036, 0x2008, 0x080c,
+	0x26a0, 0x000e, 0x00ce, 0x001e, 0x0005, 0x2845, 0x2849, 0x284d,
+	0x2853, 0x2859, 0x285f, 0x2865, 0x286d, 0x2875, 0x287b, 0x2881,
+	0x2889, 0x2891, 0x2899, 0x28a1, 0x28ab, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b7, 0x28b7, 0x28bc,
+	0x28bc, 0x28c3, 0x28c3, 0x28ca, 0x28ca, 0x28d3, 0x28d3, 0x28da,
+	0x28da, 0x28e3, 0x28e3, 0x28ec, 0x28ec, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5,
+	0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x28b5, 0x0106, 0x0006, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c,
+	0x2373, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106,
+	0x0006, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c,
+	0x2373, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c,
+	0x2373, 0x080c, 0x223d, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c,
+	0x228f, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x228f, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x228f, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x228f, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x080c, 0x228f, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x223d, 0x080c, 0x228f, 0x0804,
+	0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c, 0x223d, 0x080c,
+	0x228f, 0x0804, 0x28f7, 0x0106, 0x0006, 0x080c, 0x2373, 0x080c,
+	0x223d, 0x080c, 0x228f, 0x0804, 0x28f7, 0xe000, 0x0cf0, 0x0106,
+	0x0006, 0x080c, 0x272f, 0x04d8, 0x0106, 0x0006, 0x080c, 0x272f,
+	0x080c, 0x2373, 0x04a0, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c,
+	0x223d, 0x0468, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, 0x2373,
+	0x080c, 0x223d, 0x0420, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c,
+	0x228f, 0x00e8, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c, 0x2373,
+	0x080c, 0x228f, 0x00a0, 0x0106, 0x0006, 0x080c, 0x272f, 0x080c,
+	0x223d, 0x080c, 0x228f, 0x0058, 0x0106, 0x0006, 0x080c, 0x272f,
+	0x080c, 0x2373, 0x080c, 0x223d, 0x080c, 0x228f, 0x0000, 0x000e,
+	0x010e, 0x000d, 0x00c6, 0x0026, 0x0046, 0x2021, 0x0000, 0x080c,
+	0x502d, 0x1904, 0x29d4, 0x72d0, 0x2001, 0xaf9d, 0x2004, 0xa005,
+	0x1110, 0xd29c, 0x0148, 0xd284, 0x1138, 0xd2bc, 0x1904, 0x29d4,
+	0x080c, 0x29d8, 0x0804, 0x29d4, 0x080c, 0x574f, 0x1120, 0x709b,
+	0xffff, 0x0804, 0x29d4, 0xd294, 0x0120, 0x709b, 0xffff, 0x0804,
+	0x29d4, 0x2001, 0xad14, 0x203c, 0x7284, 0xd284, 0x0904, 0x2976,
+	0xd28c, 0x1904, 0x2976, 0x0036, 0x7398, 0xa38e, 0xffff, 0x1110,
+	0x2019, 0x0001, 0x8314, 0xa2e0, 0xb3c0, 0x2c04, 0xa38c, 0x0001,
+	0x0120, 0xa084, 0xff00, 0x8007, 0x0010, 0xa084, 0x00ff, 0xa70e,
+	0x0560, 0xa08e, 0x0000, 0x0548, 0xa08e, 0x00ff, 0x1150, 0x7230,
+	0xd284, 0x1538, 0x7284, 0xc28d, 0x7286, 0x709b, 0xffff, 0x003e,
+	0x0428, 0x2009, 0x0000, 0x080c, 0x2676, 0x080c, 0x4c80, 0x11b8,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1150, 0x7030, 0xd08c,
+	0x0118, 0x6000, 0xd0bc, 0x0120, 0x080c, 0x29eb, 0x0140, 0x0028,
+	0x080c, 0x2b1a, 0x080c, 0x2a19, 0x0110, 0x8318, 0x0818, 0x739a,
+	0x0010, 0x709b, 0xffff, 0x003e, 0x0804, 0x29d4, 0xa780, 0x2be6,
+	0x203d, 0xa7bc, 0xff00, 0x873f, 0x2041, 0x007e, 0x7098, 0xa096,
+	0xffff, 0x1120, 0x2009, 0x0000, 0x28a8, 0x0050, 0xa812, 0x0220,
+	0x2008, 0xa802, 0x20a8, 0x0020, 0x709b, 0xffff, 0x0804, 0x29d4,
+	0x2700, 0x0156, 0x0016, 0xa106, 0x05a0, 0xc484, 0x080c, 0x4cdc,
+	0x0120, 0x080c, 0x4c80, 0x15a8, 0x0008, 0xc485, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x1130, 0x7030, 0xd08c, 0x01e8, 0x6000,
+	0xd0bc, 0x11d0, 0x7284, 0xd28c, 0x0188, 0x6004, 0xa084, 0x00ff,
+	0xa082, 0x0006, 0x02b0, 0xd484, 0x1118, 0x080c, 0x4c9f, 0x0028,
+	0x080c, 0x2b9c, 0x0170, 0x080c, 0x2bc9, 0x0058, 0x080c, 0x2b1a,
+	0x080c, 0x2a19, 0x0170, 0x0028, 0x080c, 0x2b9c, 0x0110, 0x0419,
+	0x0140, 0x001e, 0x8108, 0x015e, 0x1f04, 0x2990, 0x709b, 0xffff,
+	0x0018, 0x001e, 0x015e, 0x719a, 0x004e, 0x002e, 0x00ce, 0x0005,
+	0x00c6, 0x0016, 0x709b, 0x0000, 0x2009, 0x007e, 0x080c, 0x4c80,
+	0x1138, 0x080c, 0x2b1a, 0x04a9, 0x0118, 0x70d0, 0xc0bd, 0x70d2,
+	0x001e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68,
+	0x2001, 0xad56, 0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9807,
+	0x01d8, 0x2d00, 0x601a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2001,
+	0x0000, 0x080c, 0x4c1e, 0x2001, 0x0000, 0x080c, 0x4c30, 0x0126,
+	0x2091, 0x8000, 0x7094, 0x8000, 0x7096, 0x012e, 0x2009, 0x0004,
+	0x080c, 0x80a7, 0xa085, 0x0001, 0x00ce, 0x00de, 0x007e, 0x001e,
+	0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6, 0x2c68, 0x2001, 0xad56,
+	0x2004, 0xa084, 0x00ff, 0x6842, 0x080c, 0x9807, 0x0550, 0x2d00,
+	0x601a, 0x6800, 0xc0c4, 0x6802, 0x68a0, 0xa086, 0x007e, 0x0140,
+	0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1110, 0x080c, 0x2ad9,
+	0x080c, 0x9956, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e,
+	0x2001, 0x0002, 0x080c, 0x4c30, 0x0126, 0x2091, 0x8000, 0x7094,
+	0x8000, 0x7096, 0x012e, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085,
+	0x0001, 0x00ce, 0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x0026,
+	0x2009, 0x0080, 0x080c, 0x4c80, 0x1120, 0x0031, 0x0110, 0x70d7,
+	0xffff, 0x002e, 0x00ce, 0x0005, 0x0016, 0x0076, 0x00d6, 0x00c6,
+	0x2c68, 0x080c, 0x8022, 0x01d8, 0x2d00, 0x601a, 0x080c, 0x9956,
+	0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002,
+	0x080c, 0x4c30, 0x0126, 0x2091, 0x8000, 0x70d8, 0x8000, 0x70da,
+	0x012e, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085, 0x0001, 0x00ce,
+	0x00de, 0x007e, 0x001e, 0x0005, 0x00c6, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x2009, 0x007f, 0x080c, 0x4c80, 0x1190, 0x2c68, 0x080c,
+	0x8022, 0x0170, 0x2d00, 0x601a, 0x6312, 0x601f, 0x0001, 0x620a,
+	0x080c, 0x9956, 0x2009, 0x0022, 0x080c, 0x80a7, 0xa085, 0x0001,
+	0x012e, 0x00de, 0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0066, 0x0036,
+	0x0026, 0x080c, 0x68f3, 0x080c, 0x689d, 0x080c, 0x8a15, 0x2130,
+	0x81ff, 0x0128, 0x20a9, 0x007e, 0x2009, 0x0000, 0x0020, 0x20a9,
+	0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1120, 0x080c,
+	0x4ecf, 0x080c, 0x493a, 0x001e, 0x8108, 0x1f04, 0x2ac3, 0x86ff,
+	0x1110, 0x080c, 0x11d4, 0x002e, 0x003e, 0x006e, 0x00ce, 0x00ee,
+	0x0005, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016, 0x6218, 0x2270,
+	0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, 0x68e7, 0x0076, 0x2039,
+	0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712, 0x007e, 0x001e,
+	0x2e60, 0x080c, 0x4ecf, 0x6210, 0x6314, 0x080c, 0x493a, 0x6212,
+	0x6316, 0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6,
+	0x0006, 0x6018, 0xa080, 0x0028, 0x2004, 0xa086, 0x0080, 0x0150,
+	0x2071, 0xad00, 0x7094, 0xa005, 0x0110, 0x8001, 0x7096, 0x000e,
+	0x00ee, 0x0005, 0x2071, 0xad00, 0x70d8, 0xa005, 0x0dc0, 0x8001,
+	0x70da, 0x0ca8, 0x6000, 0xc08c, 0x6002, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x0036, 0x0026, 0x0016, 0x0156, 0x2178, 0x81ff, 0x1118,
+	0x20a9, 0x0001, 0x0098, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0150,
+	0xd0a4, 0x0140, 0xa006, 0x0046, 0x2020, 0x2009, 0x002d, 0x080c,
+	0xa96c, 0x004e, 0x20a9, 0x00ff, 0x2011, 0x0000, 0x0026, 0xa28e,
+	0x007e, 0x05c8, 0xa28e, 0x007f, 0x05b0, 0xa28e, 0x0080, 0x0598,
+	0xa288, 0xae34, 0x210c, 0x81ff, 0x0570, 0x8fff, 0x05c1, 0x00c6,
+	0x2160, 0x2001, 0x0001, 0x080c, 0x5037, 0x00ce, 0x2019, 0x0029,
+	0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x00c6,
+	0x0026, 0x2160, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x1118,
+	0x6007, 0x0404, 0x0028, 0x2001, 0x0004, 0x8007, 0xa215, 0x6206,
+	0x002e, 0x00ce, 0x0016, 0x2c08, 0x080c, 0xa712, 0x001e, 0x007e,
+	0x2160, 0x080c, 0x4ecf, 0x002e, 0x8210, 0x1f04, 0x2b3e, 0x015e,
+	0x001e, 0x002e, 0x003e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x0046,
+	0x0026, 0x0016, 0x2001, 0xad52, 0x2004, 0xd0c4, 0x0148, 0xd0a4,
+	0x0138, 0xa006, 0x2220, 0x8427, 0x2009, 0x0029, 0x080c, 0xa96c,
+	0x001e, 0x002e, 0x004e, 0x0005, 0x0016, 0x0026, 0x0036, 0x00c6,
+	0x7284, 0x82ff, 0x01f8, 0x2011, 0xad52, 0x2214, 0xd2ac, 0x11d0,
+	0x2100, 0x080c, 0x268a, 0x81ff, 0x01b8, 0x2019, 0x0001, 0x8314,
+	0xa2e0, 0xb3c0, 0x2c04, 0xd384, 0x0120, 0xa084, 0xff00, 0x8007,
+	0x0010, 0xa084, 0x00ff, 0xa116, 0x0138, 0xa096, 0x00ff, 0x0110,
+	0x8318, 0x0c68, 0xa085, 0x0001, 0x00ce, 0x003e, 0x002e, 0x001e,
+	0x0005, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0xa180, 0xae34,
+	0x2004, 0xa065, 0x0178, 0x0016, 0x00c6, 0x080c, 0x9807, 0x001e,
+	0x090c, 0x14f6, 0x611a, 0x080c, 0x2ad9, 0x080c, 0x8078, 0x001e,
+	0x080c, 0x4c9f, 0x012e, 0x00ce, 0x001e, 0x0005, 0x7eef, 0x7de8,
+	0x7ce4, 0x80e2, 0x7be1, 0x80e0, 0x80dc, 0x80da, 0x7ad9, 0x80d6,
+	0x80d5, 0x80d4, 0x80d3, 0x80d2, 0x80d1, 0x79ce, 0x78cd, 0x80cc,
+	0x80cb, 0x80ca, 0x80c9, 0x80c7, 0x80c6, 0x77c5, 0x76c3, 0x80bc,
+	0x80ba, 0x75b9, 0x80b6, 0x74b5, 0x73b4, 0x72b3, 0x80b2, 0x80b1,
+	0x80ae, 0x71ad, 0x80ac, 0x70ab, 0x6faa, 0x6ea9, 0x80a7, 0x6da6,
+	0x6ca5, 0x6ba3, 0x6a9f, 0x699e, 0x689d, 0x809b, 0x8098, 0x6797,
+	0x6690, 0x658f, 0x6488, 0x6384, 0x6282, 0x8081, 0x8080, 0x617c,
+	0x607a, 0x8079, 0x5f76, 0x8075, 0x8074, 0x8073, 0x8072, 0x8071,
+	0x806e, 0x5e6d, 0x806c, 0x5d6b, 0x5c6a, 0x5b69, 0x8067, 0x5a66,
+	0x5965, 0x5863, 0x575c, 0x565a, 0x5559, 0x8056, 0x8055, 0x5454,
+	0x5353, 0x5252, 0x5151, 0x504e, 0x4f4d, 0x804c, 0x804b, 0x4e4a,
+	0x4d49, 0x8047, 0x4c46, 0x8045, 0x8043, 0x803c, 0x803a, 0x8039,
+	0x8036, 0x4b35, 0x8034, 0x4a33, 0x4932, 0x4831, 0x802e, 0x472d,
+	0x462c, 0x452b, 0x442a, 0x4329, 0x4227, 0x8026, 0x8025, 0x4123,
+	0x401f, 0x3f1e, 0x3e1d, 0x3d1b, 0x3c18, 0x8017, 0x8010, 0x3b0f,
+	0x3a08, 0x8004, 0x3902, 0x8001, 0x8000, 0x8000, 0x3800, 0x3700,
+	0x3600, 0x8000, 0x3500, 0x8000, 0x8000, 0x8000, 0x3400, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3300, 0x3200, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x3100, 0x3000, 0x8000,
+	0x8000, 0x2f00, 0x8000, 0x2e00, 0x2d00, 0x2c00, 0x8000, 0x8000,
+	0x8000, 0x2b00, 0x8000, 0x2a00, 0x2900, 0x2800, 0x8000, 0x2700,
+	0x2600, 0x2500, 0x2400, 0x2300, 0x2200, 0x8000, 0x8000, 0x2100,
+	0x2000, 0x1f00, 0x1e00, 0x1d00, 0x1c00, 0x8000, 0x8000, 0x1b00,
+	0x1a00, 0x8000, 0x1900, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x1800, 0x8000, 0x1700, 0x1600, 0x1500, 0x8000, 0x1400,
+	0x1300, 0x1200, 0x1100, 0x1000, 0x0f00, 0x8000, 0x8000, 0x0e00,
+	0x0d00, 0x0c00, 0x0b00, 0x0a00, 0x0900, 0x8000, 0x8000, 0x0800,
+	0x0700, 0x8000, 0x0600, 0x8000, 0x8000, 0x8000, 0x0500, 0x0400,
+	0x0300, 0x8000, 0x0200, 0x8000, 0x8000, 0x8000, 0x0100, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x0000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000,
+	0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x2071, 0xad81,
+	0x7003, 0x0002, 0xa006, 0x7012, 0x7016, 0x703a, 0x703e, 0x7033,
+	0xad91, 0x7037, 0xad91, 0x7007, 0x0001, 0x2061, 0xadd1, 0x6003,
+	0x0002, 0x0005, 0x1004, 0x2d0c, 0x0e04, 0x2d0c, 0x2071, 0xad81,
+	0x2b78, 0x7818, 0xd084, 0x1140, 0x2a60, 0x7820, 0xa08e, 0x0069,
+	0x1904, 0x2df1, 0x0804, 0x2d8a, 0x0005, 0x2071, 0xad81, 0x7004,
+	0x0002, 0x2d15, 0x2d16, 0x2d1f, 0x2d30, 0x0005, 0x1004, 0x2d1e,
+	0x0e04, 0x2d1e, 0x2b78, 0x7818, 0xd084, 0x01e8, 0x0005, 0x2b78,
+	0x2061, 0xadd1, 0x6008, 0xa08e, 0x0100, 0x0128, 0xa086, 0x0200,
+	0x0904, 0x2deb, 0x0005, 0x7014, 0x2068, 0x2a60, 0x7018, 0x0807,
+	0x7010, 0x2068, 0x6834, 0xa086, 0x0103, 0x0108, 0x0005, 0x2a60,
+	0x2b78, 0x7018, 0x0807, 0x2a60, 0x7820, 0xa08a, 0x0040, 0x1210,
+	0x61c0, 0x0042, 0x2100, 0xa08a, 0x003f, 0x1a04, 0x2de8, 0x61c0,
+	0x0804, 0x2d8a, 0x2dcc, 0x2df7, 0x2dff, 0x2e03, 0x2e0b, 0x2e11,
+	0x2e15, 0x2e21, 0x2e24, 0x2e2e, 0x2e31, 0x2de8, 0x2de8, 0x2de8,
+	0x2e34, 0x2de8, 0x2e43, 0x2e5a, 0x2e71, 0x2ee8, 0x2eed, 0x2f16,
+	0x2f67, 0x2f78, 0x2f96, 0x2fcd, 0x2fd7, 0x2fe4, 0x2ff7, 0x3018,
+	0x3021, 0x3057, 0x305d, 0x2de8, 0x3086, 0x2de8, 0x2de8, 0x2de8,
+	0x2de8, 0x2de8, 0x308d, 0x3097, 0x2de8, 0x2de8, 0x2de8, 0x2de8,
+	0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x309f, 0x2de8, 0x2de8, 0x2de8,
+	0x2de8, 0x2de8, 0x30b1, 0x30b9, 0x2de8, 0x2de8, 0x2de8, 0x2de8,
+	0x2de8, 0x2de8, 0x0002, 0x30cb, 0x311f, 0x317a, 0x318a, 0x2de8,
+	0x31a4, 0x35cb, 0x3fbb, 0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x2de8,
+	0x2de8, 0x2de8, 0x2de8, 0x2e2e, 0x2e31, 0x35cd, 0x2de8, 0x35da,
+	0x403c, 0x4097, 0x40fb, 0x2de8, 0x415a, 0x4180, 0x419f, 0x2de8,
+	0x2de8, 0x2de8, 0x2de8, 0x35de, 0x376b, 0x3785, 0x37a3, 0x3804,
+	0x3858, 0x3863, 0x389a, 0x38a9, 0x38b8, 0x38bb, 0x38de, 0x3928,
+	0x398e, 0x399b, 0x3a9c, 0x3bb3, 0x3bdc, 0x3cda, 0x3cfc, 0x3d08,
+	0x3d41, 0x3e05, 0x2de8, 0x2de8, 0x2de8, 0x2de8, 0x3e6d, 0x3e88,
+	0x3efa, 0x3fac, 0x713c, 0x0000, 0x2021, 0x4000, 0x080c, 0x3c39,
+	0x0126, 0x2091, 0x8000, 0x0e04, 0x2dd8, 0x7818, 0xd084, 0x0110,
+	0x012e, 0x0cb0, 0x7c22, 0x7926, 0x7a2a, 0x7b2e, 0x781b, 0x0001,
+	0x2091, 0x4080, 0x7007, 0x0001, 0x2091, 0x5000, 0x012e, 0x0005,
+	0x2021, 0x4001, 0x0c18, 0x2021, 0x4002, 0x0c00, 0x2021, 0x4003,
+	0x08e8, 0x2021, 0x4005, 0x08d0, 0x2021, 0x4006, 0x08b8, 0xa02e,
+	0x2520, 0x7b28, 0x7a2c, 0x7824, 0x7930, 0x0804, 0x3c46, 0x7823,
+	0x0004, 0x7824, 0x0807, 0xa02e, 0x2520, 0x7b28, 0x7a2c, 0x7824,
+	0x7930, 0x0804, 0x3c49, 0x7924, 0x7828, 0x2114, 0x200a, 0x0804,
+	0x2dcc, 0x7924, 0x2114, 0x0804, 0x2dcc, 0x2099, 0x0009, 0x20a1,
+	0x0009, 0x20a9, 0x0007, 0x53a3, 0x7924, 0x7a28, 0x7b2c, 0x0804,
+	0x2dcc, 0x7824, 0x2060, 0x0090, 0x2009, 0x0002, 0x2011, 0x0001,
+	0x2019, 0x001b, 0x783b, 0x0017, 0x0804, 0x2dcc, 0x7d38, 0x7c3c,
+	0x0840, 0x7d38, 0x7c3c, 0x0888, 0x2061, 0x1000, 0xe10c, 0xa006,
+	0x2c15, 0xa200, 0x8c60, 0x8109, 0x1dd8, 0x2010, 0xa005, 0x0904,
+	0x2dcc, 0x0804, 0x2dee, 0x2069, 0xad51, 0x7824, 0x7930, 0xa11a,
+	0x1a04, 0x2df4, 0x8019, 0x0904, 0x2df4, 0x684a, 0x6942, 0x782c,
+	0x6852, 0x7828, 0x6856, 0xa006, 0x685a, 0x685e, 0x080c, 0x5a1c,
+	0x0804, 0x2dcc, 0x2069, 0xad51, 0x7824, 0x7934, 0xa11a, 0x1a04,
+	0x2df4, 0x8019, 0x0904, 0x2df4, 0x684e, 0x6946, 0x782c, 0x6862,
+	0x7828, 0x6866, 0xa006, 0x686a, 0x686e, 0x080c, 0x50d9, 0x0804,
+	0x2dcc, 0xa02e, 0x2520, 0x81ff, 0x1904, 0x2df1, 0x7924, 0x7b28,
+	0x7a2c, 0x20a9, 0x0005, 0x20a1, 0xad88, 0x41a1, 0x080c, 0x3c05,
+	0x0904, 0x2df1, 0x2009, 0x0020, 0x080c, 0x3c46, 0x701b, 0x2e89,
+	0x0005, 0x6834, 0x2008, 0xa084, 0x00ff, 0xa096, 0x0011, 0x0120,
+	0xa096, 0x0019, 0x1904, 0x2df1, 0x810f, 0xa18c, 0x00ff, 0x0904,
+	0x2df1, 0x710e, 0x700c, 0x8001, 0x0528, 0x700e, 0x080c, 0x3c05,
+	0x0904, 0x2df1, 0x2009, 0x0020, 0x2061, 0xadd1, 0x6224, 0x6328,
+	0x642c, 0x6530, 0xa290, 0x0040, 0xa399, 0x0000, 0xa4a1, 0x0000,
+	0xa5a9, 0x0000, 0x080c, 0x3c46, 0x701b, 0x2eb7, 0x0005, 0x6834,
+	0xa084, 0x00ff, 0xa096, 0x0002, 0x0120, 0xa096, 0x000a, 0x1904,
+	0x2df1, 0x08c0, 0x7010, 0x2068, 0x6838, 0xc0fd, 0x683a, 0x080c,
+	0x4b7c, 0x1128, 0x7007, 0x0003, 0x701b, 0x2ed1, 0x0005, 0x080c,
+	0x51df, 0x0126, 0x2091, 0x8000, 0x20a9, 0x0005, 0x2099, 0xad88,
+	0x530a, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+	0x0000, 0xad80, 0x000d, 0x2009, 0x0020, 0x012e, 0x0804, 0x3c49,
+	0x61a8, 0x7824, 0x60aa, 0x0804, 0x2dcc, 0x2091, 0x8000, 0x7823,
+	0x4000, 0x7827, 0x4953, 0x782b, 0x5020, 0x782f, 0x2020, 0x2009,
+	0x017f, 0x2104, 0x7832, 0x3f00, 0x7836, 0x2061, 0x0100, 0x6200,
+	0x2061, 0x0200, 0x603c, 0x8007, 0xa205, 0x783a, 0x2009, 0x04fd,
+	0x2104, 0x783e, 0x781b, 0x0001, 0x2091, 0x5000, 0x2091, 0x4080,
+	0x2071, 0x0010, 0x20c1, 0x00f0, 0x0804, 0x0427, 0x81ff, 0x1904,
+	0x2df1, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, 0x1904,
+	0x2df4, 0x7e38, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0210, 0x0804,
+	0x2df4, 0x7c28, 0x7d2c, 0x080c, 0x4e96, 0xd28c, 0x1118, 0x080c,
+	0x4e41, 0x0010, 0x080c, 0x4e6f, 0x1518, 0x2061, 0xb400, 0x0126,
+	0x2091, 0x8000, 0x6000, 0xa086, 0x0000, 0x0148, 0x6010, 0xa06d,
+	0x0130, 0x683c, 0xa406, 0x1118, 0x6840, 0xa506, 0x0150, 0x012e,
+	0xace0, 0x0018, 0x2001, 0xad16, 0x2004, 0xac02, 0x1a04, 0x2df1,
+	0x0c30, 0x080c, 0x929c, 0x012e, 0x0904, 0x2df1, 0x0804, 0x2dcc,
+	0xa00e, 0x2001, 0x0005, 0x080c, 0x51df, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x9803, 0x080c, 0x510c, 0x012e, 0x0804, 0x2dcc, 0x81ff,
+	0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96,
+	0x0904, 0x2df1, 0x080c, 0x4ea2, 0x0904, 0x2df1, 0x0804, 0x2dcc,
+	0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x080c,
+	0x4f0d, 0x0904, 0x2df1, 0x2019, 0x0005, 0x080c, 0x4ebd, 0x0904,
+	0x2df1, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2df4, 0x8003, 0x800b,
+	0x810b, 0xa108, 0x080c, 0x6519, 0x0804, 0x2dcc, 0x0126, 0x2091,
+	0x8000, 0x81ff, 0x0118, 0x2009, 0x0001, 0x0448, 0x2029, 0x00ff,
+	0x644c, 0x2400, 0xa506, 0x01f0, 0x2508, 0x080c, 0x4cdc, 0x11d0,
+	0x080c, 0x4f0d, 0x1128, 0x2009, 0x0002, 0x62b0, 0x2518, 0x00b8,
+	0x2019, 0x0004, 0x080c, 0x4ebd, 0x1118, 0x2009, 0x0006, 0x0078,
+	0x7824, 0xa08a, 0x1000, 0x1270, 0x8003, 0x800b, 0x810b, 0xa108,
+	0x080c, 0x6519, 0x8529, 0x1ae8, 0x012e, 0x0804, 0x2dcc, 0x012e,
+	0x0804, 0x2df1, 0x012e, 0x0804, 0x2df4, 0x080c, 0x3c1a, 0x0904,
+	0x2df4, 0x080c, 0x4dfc, 0x080c, 0x4e96, 0x0804, 0x2dcc, 0x81ff,
+	0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4ded,
+	0x080c, 0x4e96, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c,
+	0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4e71, 0x0904, 0x2df1, 0x080c,
+	0x4bc0, 0x080c, 0x4e3a, 0x080c, 0x4e96, 0x0804, 0x2dcc, 0x080c,
+	0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x62a0,
+	0x2019, 0x0005, 0x00c6, 0x080c, 0x4ecf, 0x2061, 0x0000, 0x080c,
+	0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2009, 0x0000,
+	0x080c, 0xa712, 0x007e, 0x00ce, 0x080c, 0x4e96, 0x0804, 0x2dcc,
+	0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4e96, 0x2208, 0x0804,
+	0x2dcc, 0x0156, 0x00d6, 0x00e6, 0x2069, 0xae13, 0x6810, 0x6914,
+	0xa10a, 0x1210, 0x2009, 0x0000, 0x6816, 0x2011, 0x0000, 0x2019,
+	0x0000, 0x20a9, 0x007e, 0x2069, 0xae34, 0x2d04, 0xa075, 0x0130,
+	0x704c, 0x0071, 0xa210, 0x7080, 0x0059, 0xa318, 0x8d68, 0x1f04,
+	0x3035, 0x2300, 0xa218, 0x00ee, 0x00de, 0x015e, 0x0804, 0x2dcc,
+	0x00f6, 0x0016, 0xa07d, 0x0140, 0x2001, 0x0000, 0x8000, 0x2f0c,
+	0x81ff, 0x0110, 0x2178, 0x0cd0, 0x001e, 0x00fe, 0x0005, 0x2069,
+	0xae13, 0x6910, 0x62ac, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1,
+	0x614c, 0xa190, 0x2be6, 0x2215, 0xa294, 0x00ff, 0x636c, 0x83ff,
+	0x0108, 0x6270, 0x67d0, 0xd79c, 0x0118, 0x2031, 0x0001, 0x0090,
+	0xd7ac, 0x0118, 0x2031, 0x0003, 0x0068, 0xd7a4, 0x0118, 0x2031,
+	0x0002, 0x0040, 0x080c, 0x574f, 0x1118, 0x2031, 0x0004, 0x0010,
+	0x2031, 0x0000, 0x7e3a, 0x7f3e, 0x0804, 0x2dcc, 0x613c, 0x6240,
+	0x2019, 0xafa3, 0x231c, 0x0804, 0x2dcc, 0x0126, 0x2091, 0x8000,
+	0x6134, 0xa006, 0x2010, 0x2018, 0x012e, 0x0804, 0x2dcc, 0x080c,
+	0x3c2a, 0x0904, 0x2df4, 0x6244, 0x6338, 0x0804, 0x2dcc, 0x613c,
+	0x6240, 0x7824, 0x603e, 0x7b28, 0x6342, 0x2069, 0xad51, 0x831f,
+	0xa305, 0x6816, 0x782c, 0x2069, 0xafa3, 0x2d1c, 0x206a, 0x0804,
+	0x2dcc, 0x0126, 0x2091, 0x8000, 0x7824, 0x6036, 0x012e, 0x0804,
+	0x2dcc, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x7828, 0xa00d, 0x0904,
+	0x2df4, 0x782c, 0xa005, 0x0904, 0x2df4, 0x6244, 0x6146, 0x6338,
+	0x603a, 0x0804, 0x2dcc, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003,
+	0x1904, 0x2df1, 0x00c6, 0x2061, 0x0100, 0x7924, 0x810f, 0xa18c,
+	0x00ff, 0xa196, 0x00ff, 0x1130, 0x2001, 0xad14, 0x2004, 0xa085,
+	0xff00, 0x0078, 0xa182, 0x007f, 0x16a0, 0xa188, 0x2be6, 0x210d,
+	0xa18c, 0x00ff, 0x2001, 0xad14, 0x2004, 0xa116, 0x0550, 0x810f,
+	0xa105, 0x0126, 0x2091, 0x8000, 0x0006, 0x080c, 0x8022, 0x000e,
+	0x01e0, 0x601a, 0x600b, 0xbc09, 0x601f, 0x0001, 0x080c, 0x3c05,
+	0x01d8, 0x6837, 0x0000, 0x7007, 0x0003, 0x6833, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x701b, 0x3173, 0x2d00, 0x6012, 0x2009, 0x0032,
+	0x080c, 0x80a7, 0x012e, 0x00ce, 0x0005, 0x012e, 0x00ce, 0x0804,
+	0x2df1, 0x00ce, 0x0804, 0x2df4, 0x080c, 0x8078, 0x0cb0, 0x2001,
+	0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x00c6, 0x2061,
+	0x0100, 0x7924, 0x810f, 0xa18c, 0x00ff, 0xa196, 0x00ff, 0x1130,
+	0x2001, 0xad14, 0x2004, 0xa085, 0xff00, 0x0078, 0xa182, 0x007f,
+	0x16a0, 0xa188, 0x2be6, 0x210d, 0xa18c, 0x00ff, 0x2001, 0xad14,
+	0x2004, 0xa116, 0x0550, 0x810f, 0xa105, 0x0126, 0x2091, 0x8000,
+	0x0006, 0x080c, 0x8022, 0x000e, 0x01e0, 0x601a, 0x600b, 0xbc05,
+	0x601f, 0x0001, 0x080c, 0x3c05, 0x01d8, 0x6837, 0x0000, 0x7007,
+	0x0003, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x701b, 0x3173,
+	0x2d00, 0x6012, 0x2009, 0x0032, 0x080c, 0x80a7, 0x012e, 0x00ce,
+	0x0005, 0x012e, 0x00ce, 0x0804, 0x2df1, 0x00ce, 0x0804, 0x2df4,
+	0x080c, 0x8078, 0x0cb0, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1,
+	0x0804, 0x2dcc, 0x2061, 0xb048, 0x0126, 0x2091, 0x8000, 0x6000,
+	0xd084, 0x0128, 0x6104, 0x6208, 0x012e, 0x0804, 0x2dcc, 0x012e,
+	0x0804, 0x2df4, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x0904,
+	0x2df1, 0x0126, 0x2091, 0x8000, 0x6244, 0x6064, 0xa202, 0x0248,
+	0xa085, 0x0001, 0x080c, 0x26c0, 0x080c, 0x436e, 0x012e, 0x0804,
+	0x2dcc, 0x012e, 0x0804, 0x2df4, 0x0126, 0x2091, 0x8000, 0x7824,
+	0xa084, 0x0007, 0x0002, 0x31b6, 0x31bf, 0x31c6, 0x31b3, 0x31b3,
+	0x31b3, 0x31b3, 0x31b3, 0x012e, 0x0804, 0x2df4, 0x2009, 0x0114,
+	0x2104, 0xa085, 0x0800, 0x200a, 0x080c, 0x332f, 0x0070, 0x2009,
+	0x010b, 0x200b, 0x0010, 0x080c, 0x332f, 0x0038, 0x81ff, 0x0128,
+	0x012e, 0x2021, 0x400b, 0x0804, 0x2dce, 0x0086, 0x0096, 0x00a6,
+	0x00b6, 0x00c6, 0x00d6, 0x00e6, 0x00f6, 0x2009, 0x0101, 0x210c,
+	0x0016, 0x2001, 0x0138, 0x200c, 0x2003, 0x0001, 0x0016, 0x2001,
+	0x007a, 0x2034, 0x2001, 0x007b, 0x202c, 0xa006, 0x2048, 0x2050,
+	0x2058, 0x080c, 0x3570, 0x080c, 0x34da, 0xa03e, 0x2720, 0x00f6,
+	0x00e6, 0x00c6, 0x2d60, 0x2071, 0xb01e, 0x2079, 0x0020, 0x00d6,
+	0x2069, 0x0000, 0x6824, 0xd0b4, 0x0140, 0x2001, 0x007d, 0x2004,
+	0x783e, 0x2001, 0x007c, 0x2004, 0x783a, 0x00de, 0x2011, 0x0001,
+	0x080c, 0x3486, 0x080c, 0x3486, 0x00ce, 0x00ee, 0x00fe, 0x080c,
+	0x33d5, 0x080c, 0x34ae, 0x080c, 0x342b, 0x080c, 0x3394, 0x080c,
+	0x33c5, 0x00f6, 0x2079, 0x0100, 0x7824, 0xd094, 0x0530, 0x7814,
+	0xa084, 0x0184, 0xa085, 0x0010, 0x7816, 0x2079, 0x0140, 0x080c,
+	0x330d, 0x1110, 0x00fe, 0x0430, 0x7804, 0xd0dc, 0x0dc0, 0x2079,
+	0x0100, 0x7827, 0x0086, 0x7814, 0xa084, 0x0184, 0xa085, 0x0032,
+	0x7816, 0x080c, 0x330d, 0x1110, 0x00fe, 0x00a0, 0x7824, 0xd0bc,
+	0x0dc0, 0x7827, 0x0080, 0xa026, 0x7c16, 0x7824, 0xd0ac, 0x0130,
+	0x8b58, 0x080c, 0x3317, 0x00fe, 0x0804, 0x32d7, 0x00fe, 0x080c,
+	0x330d, 0x1150, 0x8948, 0x2001, 0x007a, 0x2602, 0x2001, 0x007b,
+	0x2502, 0x080c, 0x3317, 0x0088, 0x87ff, 0x0140, 0x2001, 0x0201,
+	0x2004, 0xa005, 0x1904, 0x3211, 0x8739, 0x0038, 0x2001, 0xaffd,
+	0x2004, 0xa086, 0x0000, 0x1904, 0x3211, 0x2001, 0x0033, 0x2003,
+	0x00f6, 0x8631, 0x1208, 0x8529, 0x2500, 0xa605, 0x0904, 0x32d7,
+	0x7824, 0xd0bc, 0x0128, 0x2900, 0xaa05, 0xab05, 0x1904, 0x32d7,
+	0x6033, 0x000d, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824, 0xd0ac,
+	0x1148, 0x2001, 0xaffd, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003,
+	0x0009, 0x0040, 0x6027, 0x0001, 0x2001, 0x0075, 0x2004, 0xa005,
+	0x0108, 0x6026, 0x2c00, 0x601a, 0x20e1, 0x9040, 0x2d00, 0x681a,
+	0x6833, 0x000d, 0x7824, 0xd0a4, 0x1180, 0x6827, 0x0000, 0x00c6,
+	0x20a9, 0x0004, 0x2061, 0x0020, 0x6003, 0x0008, 0x2001, 0x0203,
+	0x2004, 0x1f04, 0x32ac, 0x00ce, 0x0040, 0x6827, 0x0001, 0x2001,
+	0x0074, 0x2004, 0xa005, 0x0108, 0x6826, 0x00f6, 0x00c6, 0x2079,
+	0x0100, 0x2061, 0x0020, 0x7827, 0x0002, 0x2001, 0x0072, 0x2004,
+	0xa084, 0xfff8, 0x601a, 0x0006, 0x2001, 0x0073, 0x2004, 0x601e,
+	0x78c6, 0x000e, 0x78ca, 0x00ce, 0x00fe, 0x0804, 0x31ef, 0x2061,
+	0x0100, 0x6027, 0x0002, 0x001e, 0x61e2, 0x001e, 0x6106, 0x7824,
+	0xa084, 0x0003, 0xa086, 0x0002, 0x0188, 0x20e1, 0x9028, 0x6050,
+	0xa084, 0xf7ef, 0x6052, 0x602f, 0x0000, 0x602c, 0xc0ac, 0x602e,
+	0x604b, 0xf7f7, 0x6043, 0x0090, 0x6043, 0x0010, 0x2908, 0x2a10,
+	0x2b18, 0x2b00, 0xaa05, 0xa905, 0x00fe, 0x00ee, 0x00de, 0x00ce,
+	0x00be, 0x00ae, 0x009e, 0x008e, 0x1118, 0x012e, 0x0804, 0x2dcc,
+	0x012e, 0x2021, 0x400c, 0x0804, 0x2dce, 0xa085, 0x0001, 0x1d04,
+	0x3316, 0x2091, 0x6000, 0x8420, 0xa486, 0x0064, 0x0005, 0x2001,
+	0x0105, 0x2003, 0x0010, 0x2001, 0x0030, 0x2003, 0x0004, 0x2001,
+	0x0020, 0x2003, 0x0004, 0x2001, 0xaffd, 0x2003, 0x0000, 0x2001,
+	0xb01e, 0x2003, 0x0000, 0x20e1, 0xf000, 0xa026, 0x0005, 0x00f6,
+	0x2079, 0x0100, 0x2001, 0xad14, 0x200c, 0x7932, 0x7936, 0x080c,
+	0x26a0, 0x7850, 0xa084, 0x0980, 0xa085, 0x0030, 0x7852, 0x2019,
+	0x01f4, 0x8319, 0x1df0, 0xa084, 0x0980, 0x7852, 0x782c, 0xc0ad,
+	0x782e, 0x20a9, 0x0046, 0x1d04, 0x334b, 0x2091, 0x6000, 0x1f04,
+	0x334b, 0x7850, 0xa085, 0x0400, 0x7852, 0x2001, 0x0009, 0x2004,
+	0xa084, 0x0003, 0xa086, 0x0001, 0x1118, 0x782c, 0xc0ac, 0x782e,
+	0x784b, 0xf7f7, 0x7843, 0x0090, 0x7843, 0x0010, 0x20a9, 0x000e,
+	0xe000, 0x1f04, 0x3368, 0x7850, 0xa085, 0x1400, 0x7852, 0x2019,
+	0x61a8, 0x7854, 0xe000, 0xe000, 0xd08c, 0x1110, 0x8319, 0x1dc8,
+	0x7827, 0x0048, 0x7850, 0xa085, 0x0400, 0x7852, 0x7843, 0x0040,
+	0x2019, 0x01f4, 0xe000, 0xe000, 0x8319, 0x1de0, 0x2001, 0x0140,
+	0x2003, 0x0100, 0x7827, 0x0020, 0x7843, 0x0000, 0x2003, 0x0000,
+	0x7827, 0x0048, 0x00fe, 0x0005, 0x7824, 0xd0ac, 0x11c8, 0x00f6,
+	0x00e6, 0x2071, 0xaffd, 0x2079, 0x0030, 0x2001, 0x0201, 0x2004,
+	0xa005, 0x0160, 0x7000, 0xa086, 0x0000, 0x1140, 0x0051, 0xd0bc,
+	0x0108, 0x8738, 0x7003, 0x0003, 0x7803, 0x0019, 0x00ee, 0x00fe,
+	0x0005, 0x780c, 0xa08c, 0x0070, 0x0178, 0x2009, 0x007a, 0x260a,
+	0x2009, 0x007b, 0x250a, 0xd0b4, 0x0108, 0x8a50, 0xd0ac, 0x0108,
+	0x8948, 0xd0a4, 0x0108, 0x8b58, 0x0005, 0x00f6, 0x2079, 0x0200,
+	0x781c, 0xd084, 0x0140, 0x20e1, 0x0007, 0x20e1, 0x2000, 0x2001,
+	0x020a, 0x2004, 0x0ca8, 0x00fe, 0x0005, 0x00e6, 0x2071, 0x0100,
+	0x2009, 0xad14, 0x210c, 0x716e, 0x7063, 0x0100, 0x7166, 0x719e,
+	0x706b, 0x0000, 0x7073, 0x0809, 0x7077, 0x0008, 0x7078, 0xa080,
+	0x0100, 0x707a, 0x7080, 0x8000, 0x7082, 0x7087, 0xaaaa, 0xa006,
+	0x708a, 0x708e, 0x707e, 0x70d6, 0x70ab, 0x0036, 0x70af, 0x95d5,
+	0x7027, 0x0080, 0x7014, 0xa084, 0x0184, 0xa085, 0x0032, 0x7016,
+	0x080c, 0x34ae, 0x080c, 0x330d, 0x1110, 0x8421, 0x0028, 0x7024,
+	0xd0bc, 0x0db0, 0x7027, 0x0080, 0x00f6, 0x00e6, 0x2071, 0xaffd,
+	0x2079, 0x0030, 0x00d6, 0x2069, 0x0000, 0x6824, 0xd0b4, 0x0120,
+	0x683c, 0x783e, 0x6838, 0x783a, 0x00de, 0x2011, 0x0011, 0x080c,
+	0x3486, 0x2011, 0x0001, 0x080c, 0x3486, 0x00ee, 0x00fe, 0x7017,
+	0x0000, 0x00ee, 0x0005, 0x00f6, 0x00e6, 0x2071, 0xaffd, 0x2079,
+	0x0030, 0x7904, 0xd1fc, 0x0904, 0x3483, 0x7803, 0x0002, 0xa026,
+	0xd19c, 0x1904, 0x347f, 0x7000, 0x0002, 0x3483, 0x3441, 0x3465,
+	0x347f, 0xd1bc, 0x1150, 0xd1dc, 0x1150, 0x8001, 0x7002, 0x2011,
+	0x0001, 0x04e1, 0x05c0, 0x04d1, 0x04b0, 0x780f, 0x0000, 0x7820,
+	0x7924, 0x7803, 0x0004, 0x7822, 0x7926, 0x2001, 0x0201, 0x200c,
+	0x81ff, 0x0de8, 0x080c, 0x33b1, 0x2009, 0x0001, 0x7808, 0xd0ec,
+	0x0110, 0x2009, 0x0011, 0x7902, 0x00f0, 0x8001, 0x7002, 0xa184,
+	0x0880, 0x1138, 0x7804, 0xd0fc, 0x1940, 0x2011, 0x0001, 0x00b1,
+	0x0090, 0x6030, 0xa092, 0x0004, 0xa086, 0x0009, 0x1120, 0x6000,
+	0x601a, 0x2011, 0x0025, 0x6232, 0xd1dc, 0x1988, 0x0870, 0x7803,
+	0x0004, 0x7003, 0x0000, 0x00ee, 0x00fe, 0x0005, 0x6024, 0xa005,
+	0x0520, 0x8001, 0x6026, 0x6018, 0x6130, 0xa140, 0x2804, 0x7832,
+	0x8840, 0x2804, 0x7836, 0x8840, 0x2804, 0x7822, 0x8840, 0x2804,
+	0x7826, 0x8840, 0x7a02, 0x7000, 0x8000, 0x7002, 0x6018, 0xa802,
+	0xa08a, 0x0029, 0x1138, 0x6018, 0xa080, 0x0001, 0x2004, 0x601a,
+	0x2001, 0x000d, 0x6032, 0xa085, 0x0001, 0x0005, 0x00f6, 0x00e6,
+	0x00c6, 0x2071, 0xb01e, 0x2079, 0x0020, 0x7904, 0xd1fc, 0x01f0,
+	0x7803, 0x0002, 0x2d60, 0xa026, 0x7000, 0x0002, 0x34d6, 0x34c1,
+	0x34cd, 0x8001, 0x7002, 0xd19c, 0x1188, 0x2011, 0x0001, 0x080c,
+	0x3486, 0x0160, 0x080c, 0x3486, 0x0048, 0x8001, 0x7002, 0x7804,
+	0xd0fc, 0x1d30, 0x2011, 0x0001, 0x080c, 0x3486, 0x00ce, 0x00ee,
+	0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x2061, 0x0200, 0x601b,
+	0x0004, 0x2061, 0x0100, 0x60cf, 0x0400, 0x6004, 0xc0ac, 0xa085,
+	0x0200, 0x6006, 0x2001, 0x0074, 0x2004, 0xa005, 0x01f8, 0x2038,
+	0x2001, 0x0076, 0x2024, 0x2001, 0x0077, 0x201c, 0x080c, 0x3c05,
+	0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220,
+	0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080,
+	0x000d, 0x04a1, 0x1d90, 0x2d00, 0x681a, 0x0088, 0x080c, 0x3c05,
+	0x6833, 0x000d, 0x2070, 0x6827, 0x0001, 0x2d00, 0x681a, 0x2001,
+	0x0076, 0x2004, 0x2072, 0x2001, 0x0077, 0x2004, 0x7006, 0x2061,
+	0x0020, 0x2079, 0x0100, 0x6013, 0x0400, 0x20e1, 0x9040, 0x2001,
+	0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x601a, 0x0006, 0x2001,
+	0x0073, 0x2004, 0x700e, 0x601e, 0x78c6, 0x000e, 0x78ca, 0xa006,
+	0x603a, 0x603e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00e6, 0x2071,
+	0x0010, 0x20a0, 0x2099, 0x0014, 0x7003, 0x0026, 0x7432, 0x7336,
+	0xa006, 0x703a, 0x703e, 0x810b, 0x810b, 0x21a8, 0x810b, 0x7122,
+	0x7003, 0x0041, 0x7004, 0xd0fc, 0x0de8, 0x7003, 0x0002, 0x7003,
+	0x0040, 0x53a5, 0x7430, 0x7334, 0x87ff, 0x0180, 0x00c6, 0x00d6,
+	0x2d60, 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x6018, 0x2070, 0x2d00,
+	0x7006, 0x601a, 0x00de, 0x00ce, 0xa085, 0x0001, 0x00ee, 0x0005,
+	0x00e6, 0x2001, 0x0075, 0x2004, 0xa005, 0x0508, 0x2038, 0x2001,
+	0x0078, 0x2024, 0x2001, 0x0079, 0x201c, 0x080c, 0x3c05, 0x2d60,
+	0x6833, 0x000d, 0x6f26, 0x2d00, 0x681a, 0xa78a, 0x0007, 0x0220,
+	0x2138, 0x2009, 0x0007, 0x0010, 0x2708, 0xa03e, 0x6818, 0xa080,
+	0x000d, 0x080c, 0x353e, 0x1d88, 0x2d00, 0x681a, 0x00e0, 0x080c,
+	0x3c05, 0x2d60, 0x6033, 0x000d, 0x2070, 0x6027, 0x0001, 0x2c00,
+	0x601a, 0x2001, 0x0078, 0x2004, 0x2072, 0x2001, 0x0079, 0x2004,
+	0x7006, 0x2001, 0x0072, 0x2004, 0xa084, 0xfff8, 0x700a, 0x2001,
+	0x0073, 0x2004, 0x700e, 0x2001, 0x0030, 0x2003, 0x0004, 0x7824,
+	0xd0ac, 0x1178, 0x2001, 0x0101, 0x200c, 0xc1ed, 0x2102, 0x6027,
+	0x0000, 0x2001, 0xaffd, 0x2003, 0x0003, 0x2001, 0x0030, 0x2003,
+	0x0009, 0x00ee, 0x0005, 0x0804, 0x2dcc, 0x0126, 0x2091, 0x8000,
+	0x20a9, 0x0011, 0x2001, 0xad40, 0x20a0, 0xa006, 0x40a4, 0x012e,
+	0x0804, 0x2dcc, 0x7d38, 0x7c3c, 0x0804, 0x2e73, 0x080c, 0x3c05,
+	0x0904, 0x2df1, 0x080c, 0x574f, 0x0110, 0x080c, 0x491f, 0x2009,
+	0x001c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46, 0x701b,
+	0x35f2, 0x0005, 0xade8, 0x000d, 0x6800, 0xa005, 0x0904, 0x2df4,
+	0x6804, 0xd0ac, 0x0118, 0xd0a4, 0x0904, 0x2df4, 0xd094, 0x00c6,
+	0x2061, 0x0100, 0x6104, 0x0138, 0x6200, 0xa292, 0x0005, 0x0218,
+	0xa18c, 0xffdf, 0x0010, 0xa18d, 0x0020, 0x6106, 0x00ce, 0xd08c,
+	0x00c6, 0x2061, 0x0100, 0x6104, 0x0118, 0xa18d, 0x0010, 0x0010,
+	0xa18c, 0xffef, 0x6106, 0x00ce, 0x2009, 0x0100, 0x210c, 0xa18a,
+	0x0002, 0x0268, 0xd084, 0x0158, 0x6a28, 0xa28a, 0x007f, 0x1a04,
+	0x2df4, 0xa288, 0x2be6, 0x210d, 0xa18c, 0x00ff, 0x6156, 0xd0dc,
+	0x0130, 0x6828, 0xa08a, 0x007f, 0x1a04, 0x2df4, 0x604e, 0x6808,
+	0xa08a, 0x0100, 0x0a04, 0x2df4, 0xa08a, 0x0841, 0x1a04, 0x2df4,
+	0xa084, 0x0007, 0x1904, 0x2df4, 0x680c, 0xa005, 0x0904, 0x2df4,
+	0x6810, 0xa005, 0x0904, 0x2df4, 0x6848, 0x6940, 0xa10a, 0x1a04,
+	0x2df4, 0x8001, 0x0904, 0x2df4, 0x684c, 0x6944, 0xa10a, 0x1a04,
+	0x2df4, 0x8001, 0x0904, 0x2df4, 0x6804, 0xd0fc, 0x0560, 0x080c,
+	0x3c05, 0x0904, 0x2df1, 0x2009, 0x0014, 0x7a2c, 0x7b28, 0x7c3c,
+	0x7d38, 0xa290, 0x0038, 0xa399, 0x0000, 0x080c, 0x3c46, 0x701b,
+	0x3672, 0x0005, 0xade8, 0x000d, 0x20a9, 0x0014, 0x2d98, 0x2069,
+	0xad6d, 0x2da0, 0x53a3, 0x7010, 0xa0e8, 0x000d, 0x2001, 0xad71,
+	0x200c, 0xd1e4, 0x0140, 0x00c6, 0x2061, 0x0100, 0x6004, 0xa085,
+	0x0b00, 0x6006, 0x00ce, 0x20a9, 0x001c, 0x2d98, 0x2069, 0xad51,
+	0x2da0, 0x53a3, 0x6814, 0xa08c, 0x00ff, 0x613e, 0x8007, 0xa084,
+	0x00ff, 0x6042, 0x080c, 0x5a1c, 0x080c, 0x5070, 0x080c, 0x50d9,
+	0x6000, 0xa086, 0x0000, 0x1904, 0x3755, 0x6808, 0x602a, 0x080c,
+	0x22f8, 0x0006, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x000e,
+	0x0268, 0x2009, 0x0170, 0x200b, 0x0080, 0xe000, 0xe000, 0x200b,
+	0x0000, 0x0036, 0x6b08, 0x080c, 0x26fb, 0x003e, 0x6818, 0x691c,
+	0x6a20, 0x6b24, 0x8007, 0x810f, 0x8217, 0x831f, 0x6016, 0x611a,
+	0x621e, 0x6322, 0x6c04, 0xd4f4, 0x0148, 0x6830, 0x6934, 0x6a38,
+	0x6b3c, 0x8007, 0x810f, 0x8217, 0x831f, 0x0010, 0xa084, 0xf0ff,
+	0x6006, 0x610a, 0x620e, 0x6312, 0x8007, 0x810f, 0x8217, 0x831f,
+	0x20a9, 0x0004, 0x20a1, 0xafad, 0x40a1, 0x080c, 0x659c, 0x6904,
+	0xd1fc, 0x0520, 0x00c6, 0x2009, 0x0000, 0x20a9, 0x0001, 0x6b70,
+	0xd384, 0x01c8, 0x0020, 0x839d, 0x12b0, 0x3508, 0x8109, 0x080c,
+	0x5fa9, 0x6878, 0x6016, 0x6874, 0x2008, 0xa084, 0xff00, 0x8007,
+	0x600a, 0xa184, 0x00ff, 0x6006, 0x8108, 0x1118, 0x6003, 0x0003,
+	0x0010, 0x6003, 0x0001, 0x1f04, 0x36f3, 0x00ce, 0x2069, 0xad51,
+	0x2001, 0xaf9d, 0x6a80, 0xa294, 0x0030, 0xa28e, 0x0000, 0x0170,
+	0xa28e, 0x0010, 0x0118, 0xa28e, 0x0020, 0x0140, 0x2003, 0xaaaa,
+	0x080c, 0x2744, 0x2001, 0xaf8e, 0x2102, 0x0008, 0x2102, 0x00c6,
+	0x2061, 0x0100, 0x602f, 0x0040, 0x602f, 0x0000, 0x00ce, 0x080c,
+	0x574f, 0x0128, 0x080c, 0x3e5f, 0x0110, 0x080c, 0x26c0, 0x60c4,
+	0xa005, 0x01b0, 0x6003, 0x0001, 0x2009, 0x373f, 0x00c0, 0x080c,
+	0x574f, 0x1158, 0x2011, 0x566e, 0x080c, 0x650d, 0x2001, 0xaf9e,
+	0x2003, 0x0000, 0x080c, 0x569a, 0x0040, 0x080c, 0x485e, 0x0028,
+	0x6003, 0x0004, 0x2009, 0x3755, 0x0010, 0x0804, 0x2dcc, 0x2001,
+	0x0100, 0x2004, 0xa082, 0x0005, 0x0258, 0x2001, 0x0170, 0x2004,
+	0xa084, 0x00ff, 0xa086, 0x004c, 0x1118, 0x2091, 0x309d, 0x0817,
+	0x2091, 0x301d, 0x0817, 0x6000, 0xa086, 0x0000, 0x0904, 0x2df1,
+	0x2069, 0xad51, 0x7830, 0x6842, 0x7834, 0x6846, 0x6804, 0xd0fc,
+	0x0118, 0x2009, 0x0030, 0x0010, 0x2009, 0x001c, 0x2d00, 0x7a2c,
+	0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0xa006, 0x080c, 0x26c0,
+	0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x1178, 0x2001, 0xaf9e,
+	0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0xa085, 0x0001,
+	0x080c, 0x5793, 0x080c, 0x569a, 0x0020, 0x080c, 0x491f, 0x080c,
+	0x485e, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f,
+	0x1110, 0x0804, 0x2df1, 0x6184, 0x81ff, 0x0198, 0x703f, 0x0000,
+	0x2001, 0xb3c0, 0x2009, 0x0040, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x3c49, 0x701b, 0x2dca, 0x012e,
+	0x0005, 0x703f, 0x0001, 0x00d6, 0x2069, 0xb3c0, 0x20a9, 0x0040,
+	0x20a1, 0xb3c0, 0x2019, 0xffff, 0x43a4, 0x654c, 0xa588, 0x2be6,
+	0x210d, 0xa18c, 0x00ff, 0x216a, 0xa00e, 0x2011, 0x0002, 0x2100,
+	0xa506, 0x01a8, 0x080c, 0x4cdc, 0x1190, 0x6014, 0x821c, 0x0238,
+	0xa398, 0xb3c0, 0xa085, 0xff00, 0x8007, 0x201a, 0x0038, 0xa398,
+	0xb3c0, 0x2324, 0xa4a4, 0xff00, 0xa405, 0x201a, 0x8210, 0x8108,
+	0xa182, 0x0080, 0x1208, 0x0c18, 0x8201, 0x8007, 0x2d0c, 0xa105,
+	0x206a, 0x00de, 0x20a9, 0x0040, 0x20a1, 0xb3c0, 0x2099, 0xb3c0,
+	0x080c, 0x48be, 0x0804, 0x37b0, 0x080c, 0x3c2a, 0x0904, 0x2df4,
+	0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x2df1, 0x2001, 0xad52, 0x2004, 0xd0b4, 0x01f0, 0x6000, 0xd08c,
+	0x11d8, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x11a8, 0x6837,
+	0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x970b, 0x1120, 0x2009,
+	0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3830, 0x0005,
+	0x080c, 0x3c2a, 0x0904, 0x2df4, 0x20a9, 0x002b, 0x2c98, 0xade8,
+	0x0002, 0x2da0, 0x53a3, 0x20a9, 0x0004, 0xac80, 0x0006, 0x2098,
+	0xad80, 0x0006, 0x20a0, 0x080c, 0x48be, 0x20a9, 0x0004, 0xac80,
+	0x000a, 0x2098, 0xad80, 0x000a, 0x20a0, 0x080c, 0x48be, 0x2d00,
+	0x2009, 0x002b, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49,
+	0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4, 0x080c,
+	0x4eab, 0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x7828, 0xa08a,
+	0x1000, 0x1a04, 0x2df4, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x080c,
+	0x4f0d, 0x0904, 0x2df1, 0x2019, 0x0004, 0x080c, 0x4ebd, 0x7924,
+	0x810f, 0x7a28, 0x0011, 0x0804, 0x2dcc, 0xa186, 0x00ff, 0x0110,
+	0x0071, 0x0060, 0x2029, 0x007e, 0x2061, 0xad00, 0x644c, 0x2400,
+	0xa506, 0x0110, 0x2508, 0x0019, 0x8529, 0x1ec8, 0x0005, 0x080c,
+	0x4cdc, 0x1138, 0x2200, 0x8003, 0x800b, 0x810b, 0xa108, 0x080c,
+	0x6519, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904,
+	0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c, 0x4eb4, 0x0804,
+	0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c1a, 0x0904, 0x2df4,
+	0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c, 0x4ea2, 0x0804, 0x2dcc,
+	0x6100, 0x0804, 0x2dcc, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x2001,
+	0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x00d6, 0xace8,
+	0x000a, 0x7924, 0xd184, 0x0110, 0xace8, 0x0006, 0x680c, 0x8007,
+	0x783e, 0x6808, 0x8007, 0x783a, 0x6b04, 0x831f, 0x6a00, 0x8217,
+	0x00de, 0x6100, 0xa18c, 0x0200, 0x0804, 0x2dcc, 0x7824, 0xa09c,
+	0x00ff, 0xa39a, 0x0003, 0x1a04, 0x2df1, 0x624c, 0xa294, 0x00ff,
+	0xa084, 0xff00, 0x8007, 0xa206, 0x1150, 0x2001, 0xad40, 0x2009,
+	0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0x81ff,
+	0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x1904, 0x2df1, 0x00c6, 0x080c, 0x3c05,
+	0x00ce, 0x0904, 0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a,
+	0x080c, 0x96b7, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3919,
+	0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1, 0xad80, 0x000e,
+	0x2009, 0x000c, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49,
+	0xa006, 0x080c, 0x26c0, 0x7824, 0xa084, 0x00ff, 0xa086, 0x00ff,
+	0x0118, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x574f, 0x0110, 0x080c,
+	0x491f, 0x7828, 0xa08a, 0x1000, 0x1a04, 0x2df4, 0x7924, 0xa18c,
+	0xff00, 0x810f, 0xa186, 0x00ff, 0x0138, 0xa182, 0x007f, 0x1a04,
+	0x2df4, 0x2100, 0x080c, 0x268a, 0x0026, 0x00c6, 0x0126, 0x2091,
+	0x8000, 0x2061, 0xafda, 0x601b, 0x0000, 0x601f, 0x0000, 0x080c,
+	0x574f, 0x1178, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00,
+	0x2003, 0x0001, 0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a,
+	0x00a0, 0x2061, 0x0100, 0x2001, 0xad14, 0x2004, 0xa084, 0x00ff,
+	0x810f, 0xa105, 0x604a, 0x6043, 0x0090, 0x6043, 0x0010, 0x2009,
+	0x002d, 0x2011, 0x4883, 0x080c, 0x6593, 0x7924, 0xa18c, 0xff00,
+	0x810f, 0x080c, 0x574f, 0x1110, 0x2009, 0x00ff, 0x7a28, 0x080c,
+	0x387d, 0x012e, 0x00ce, 0x002e, 0x0804, 0x2dcc, 0x7924, 0xa18c,
+	0xff00, 0x810f, 0x00c6, 0x080c, 0x4c80, 0x2c08, 0x00ce, 0x1904,
+	0x2df4, 0x0804, 0x2dcc, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x2df1, 0x60d0, 0xd0ac, 0x1130, 0xd09c, 0x1120, 0x2009, 0x0005,
+	0x0804, 0x2df1, 0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x2df1, 0x7924, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46,
+	0x701b, 0x39bb, 0x0005, 0x2009, 0x0080, 0x080c, 0x4cdc, 0x1130,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0120, 0x2021, 0x400a,
+	0x0804, 0x2dce, 0x00d6, 0xade8, 0x000d, 0x6900, 0x6a08, 0x6b0c,
+	0x6c10, 0x6d14, 0x6e18, 0x6820, 0xa0be, 0x0100, 0x0904, 0x3a32,
+	0xa0be, 0x0112, 0x0904, 0x3a32, 0xa0be, 0x0113, 0x0904, 0x3a32,
+	0xa0be, 0x0114, 0x0904, 0x3a32, 0xa0be, 0x0117, 0x0904, 0x3a32,
+	0xa0be, 0x011a, 0x0904, 0x3a32, 0xa0be, 0x011c, 0x0904, 0x3a32,
+	0xa0be, 0x0121, 0x05b0, 0xa0be, 0x0131, 0x0598, 0xa0be, 0x0171,
+	0x05c8, 0xa0be, 0x0173, 0x05b0, 0xa0be, 0x01a1, 0x1120, 0x6830,
+	0x8007, 0x6832, 0x04a8, 0xa0be, 0x0212, 0x0540, 0xa0be, 0x0213,
+	0x0528, 0xa0be, 0x0214, 0x01b0, 0xa0be, 0x0217, 0x0168, 0xa0be,
+	0x021a, 0x1120, 0x6838, 0x8007, 0x683a, 0x00e0, 0xa0be, 0x0300,
+	0x01c8, 0x00de, 0x0804, 0x2df4, 0xad80, 0x0010, 0x20a9, 0x0007,
+	0x080c, 0x3a78, 0xad80, 0x000e, 0x20a9, 0x0001, 0x080c, 0x3a78,
+	0x0048, 0xad80, 0x000c, 0x080c, 0x3a86, 0x0050, 0xad80, 0x000e,
+	0x080c, 0x3a86, 0xad80, 0x000c, 0x20a9, 0x0001, 0x080c, 0x3a78,
+	0x00c6, 0x080c, 0x3c05, 0x0568, 0x6838, 0xc0fd, 0x683a, 0x6837,
+	0x0119, 0x6853, 0x0000, 0x684f, 0x0020, 0x685b, 0x0001, 0x810b,
+	0x697e, 0x6883, 0x0000, 0x6a86, 0x6b8a, 0x6c8e, 0x6d92, 0x6996,
+	0x689b, 0x0000, 0x00ce, 0x00de, 0x6837, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c, 0x96d3, 0x1120,
+	0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3a6f,
+	0x0005, 0x00ce, 0x00de, 0x2009, 0x0002, 0x0804, 0x2df1, 0x6820,
+	0xa086, 0x8001, 0x1904, 0x2dcc, 0x2009, 0x0004, 0x0804, 0x2df1,
+	0x0016, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x290a, 0x8108,
+	0x280a, 0x8108, 0x1f04, 0x3a7a, 0x001e, 0x0005, 0x0016, 0x00a6,
+	0x00b6, 0x2008, 0x2044, 0x8000, 0x204c, 0x8000, 0x2054, 0x8000,
+	0x205c, 0x2b0a, 0x8108, 0x2a0a, 0x8108, 0x290a, 0x8108, 0x280a,
+	0x00be, 0x00ae, 0x001e, 0x0005, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x2df1, 0x7924, 0x2140, 0xa18c, 0xff00, 0x810f, 0x60d0,
+	0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2df4, 0xa182, 0x00ff,
+	0x1a04, 0x2df4, 0x7a2c, 0x7b28, 0x606c, 0xa306, 0x1140, 0x6070,
+	0xa24e, 0x0904, 0x2df4, 0xa9cc, 0xff00, 0x0904, 0x2df4, 0x00c6,
+	0x080c, 0x3b58, 0x2c68, 0x00ce, 0x0538, 0xa0c6, 0x4000, 0x1180,
+	0x00c6, 0x0006, 0x2d60, 0x2009, 0x0000, 0x080c, 0x4f6e, 0x1108,
+	0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x000e, 0x00ce, 0x0088,
+	0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008, 0x1118,
+	0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010, 0x2001,
+	0x4006, 0x2020, 0x0804, 0x2dce, 0x2d00, 0x7022, 0x0016, 0x00b6,
+	0x00c6, 0x00e6, 0x2c70, 0x080c, 0x8022, 0x05d8, 0x2d00, 0x601a,
+	0x080c, 0x9956, 0x2e58, 0x00ee, 0x00e6, 0x00c6, 0x080c, 0x3c05,
+	0x00ce, 0x2b70, 0x1150, 0x080c, 0x8078, 0x00ee, 0x00ce, 0x00be,
+	0x001e, 0x2009, 0x0002, 0x0804, 0x2df1, 0x6837, 0x0000, 0x683b,
+	0x0000, 0x2d00, 0x6012, 0x6833, 0x0000, 0x6838, 0xc0fd, 0xd88c,
+	0x0108, 0xc0f5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x2ad9,
+	0x012e, 0x601f, 0x0001, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001,
+	0x0002, 0x080c, 0x4c30, 0x2009, 0x0002, 0x080c, 0x80a7, 0xa085,
+	0x0001, 0x00ee, 0x00ce, 0x00be, 0x001e, 0x1120, 0x2009, 0x0003,
+	0x0804, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3b3f, 0x0005, 0x6830,
+	0xa086, 0x0100, 0x7020, 0x2060, 0x1138, 0x2009, 0x0004, 0x6204,
+	0xa294, 0x00ff, 0x0804, 0x2df1, 0x2009, 0x0000, 0x080c, 0x4f6e,
+	0x1108, 0xc185, 0x6000, 0xd0bc, 0x0108, 0xc18d, 0x0804, 0x2dcc,
+	0x00e6, 0x00d6, 0x2029, 0x0000, 0x2001, 0xad34, 0x2004, 0xd0ac,
+	0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, 0xae34, 0x0030,
+	0x2021, 0x0080, 0x20a9, 0x007f, 0x2071, 0xaeb4, 0x2e04, 0xa005,
+	0x1130, 0x2100, 0xa406, 0x1548, 0x2428, 0xc5fd, 0x0430, 0x2068,
+	0x6f10, 0x2700, 0xa306, 0x11b0, 0x6e14, 0x2600, 0xa206, 0x1190,
+	0x2400, 0xa106, 0x1160, 0x2d60, 0xd884, 0x0540, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x1510, 0x2001, 0x4000, 0x0400, 0x2001,
+	0x4007, 0x00e8, 0x2400, 0xa106, 0x1140, 0x6e14, 0x87ff, 0x1110,
+	0x86ff, 0x09d0, 0x2001, 0x4008, 0x0090, 0x8420, 0x8e70, 0x1f04,
+	0x3b6e, 0x85ff, 0x1130, 0x2001, 0x4009, 0x0048, 0x2001, 0x0001,
+	0x0030, 0x080c, 0x4c80, 0x1dd0, 0x6312, 0x6216, 0xa006, 0xa005,
+	0x00de, 0x00ee, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x080c, 0x3c05,
+	0x0904, 0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x7824,
+	0xa005, 0x0904, 0x2df4, 0xa096, 0x00ff, 0x0120, 0xa092, 0x0004,
+	0x1a04, 0x2df4, 0x2010, 0x2d18, 0x080c, 0x2a8c, 0x0904, 0x2df1,
+	0x7007, 0x0003, 0x701b, 0x3bd5, 0x0005, 0x6830, 0xa086, 0x0100,
+	0x0904, 0x2df1, 0x0804, 0x2dcc, 0x7924, 0xa18c, 0xff00, 0x810f,
+	0x60d0, 0xd0ac, 0x1120, 0xa182, 0x0080, 0x0a04, 0x2df4, 0xa182,
+	0x00ff, 0x1a04, 0x2df4, 0x0126, 0x2091, 0x8000, 0x080c, 0x95c6,
+	0x1188, 0xa190, 0xae34, 0x2204, 0xa065, 0x0160, 0x080c, 0x493a,
+	0x2001, 0xad34, 0x2004, 0xd0ac, 0x0110, 0x6017, 0x0000, 0x012e,
+	0x0804, 0x2dcc, 0x012e, 0x0804, 0x2df1, 0x080c, 0x15d9, 0x0188,
+	0xa006, 0x6802, 0x7010, 0xa005, 0x1120, 0x2d00, 0x7012, 0x7016,
+	0x0030, 0x7014, 0x6802, 0x2060, 0x2d00, 0x6006, 0x7016, 0xad80,
+	0x000d, 0x0005, 0x7924, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc,
+	0x1130, 0x7e28, 0xa684, 0x3fff, 0xa082, 0x4000, 0x0208, 0xa066,
+	0x8cff, 0x0005, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0x080c, 0x4cdc,
+	0x1128, 0xa6b4, 0x00ff, 0xa682, 0x4000, 0x0208, 0xa066, 0x8cff,
+	0x0005, 0x0016, 0x7110, 0x81ff, 0x0128, 0x2168, 0x6904, 0x080c,
+	0x15f0, 0x0cc8, 0x7112, 0x7116, 0x001e, 0x0005, 0x2031, 0x0001,
+	0x0010, 0x2031, 0x0000, 0x2061, 0xadd1, 0x6606, 0x6112, 0x600e,
+	0x6226, 0x632a, 0x642e, 0x6532, 0x2c10, 0x080c, 0x1624, 0x7007,
+	0x0002, 0x701b, 0x2dcc, 0x0005, 0x00f6, 0x0126, 0x2091, 0x8000,
+	0x2079, 0x0000, 0x2001, 0xad8f, 0x2004, 0xa005, 0x1168, 0x0e04,
+	0x3c74, 0x7818, 0xd084, 0x1140, 0x7a22, 0x7b26, 0x7c2a, 0x781b,
+	0x0001, 0x2091, 0x4080, 0x0408, 0x0016, 0x00c6, 0x00e6, 0x2071,
+	0xad81, 0x7138, 0xa182, 0x0010, 0x0218, 0x7030, 0x2060, 0x0078,
+	0x7030, 0xa0e0, 0x0004, 0xac82, 0xadd1, 0x0210, 0x2061, 0xad91,
+	0x2c00, 0x7032, 0x81ff, 0x1108, 0x7036, 0x8108, 0x713a, 0x2262,
+	0x6306, 0x640a, 0x00ee, 0x00ce, 0x001e, 0x012e, 0x00fe, 0x0005,
+	0x00e6, 0x2071, 0xad81, 0x7038, 0xa005, 0x0570, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x3ccb, 0x00f6, 0x2079, 0x0000, 0x7818, 0xd084,
+	0x1508, 0x00c6, 0x7034, 0x2060, 0x2c04, 0x7822, 0x6004, 0x7826,
+	0x6008, 0x782a, 0x781b, 0x0001, 0x2091, 0x4080, 0x7038, 0x8001,
+	0x703a, 0xa005, 0x1130, 0x7033, 0xad91, 0x7037, 0xad91, 0x00ce,
+	0x0048, 0xac80, 0x0004, 0xa0fa, 0xadd1, 0x0210, 0x2001, 0xad91,
+	0x7036, 0x00ce, 0x00fe, 0x012e, 0x00ee, 0x0005, 0x0026, 0x2001,
+	0xad52, 0x2004, 0xd0c4, 0x0120, 0x2011, 0x8014, 0x080c, 0x3c5c,
+	0x002e, 0x0005, 0x81ff, 0x1904, 0x2df1, 0x0126, 0x2091, 0x8000,
+	0x6030, 0xc08d, 0xc085, 0xc0ac, 0x6032, 0x080c, 0x574f, 0x1178,
+	0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001,
+	0xa085, 0x0001, 0x080c, 0x5793, 0x080c, 0x569a, 0x0010, 0x080c,
+	0x485e, 0x012e, 0x0804, 0x2dcc, 0x7824, 0x2008, 0xa18c, 0xfffd,
+	0x1128, 0x61dc, 0xa10d, 0x61de, 0x0804, 0x2dcc, 0x0804, 0x2df4,
+	0x81ff, 0x1904, 0x2df1, 0x6000, 0xa086, 0x0003, 0x1904, 0x2df1,
+	0x2001, 0xad52, 0x2004, 0xd0ac, 0x1904, 0x2df1, 0x080c, 0x3c2a,
+	0x0904, 0x2df4, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1120,
+	0x7828, 0xa005, 0x0904, 0x2dcc, 0x00c6, 0x080c, 0x3c05, 0x00ce,
+	0x0904, 0x2df1, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd,
+	0x683a, 0x080c, 0x979c, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b,
+	0x3d3a, 0x0005, 0x6830, 0xa086, 0x0100, 0x0904, 0x2df1, 0x0804,
+	0x2dcc, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1,
+	0x7f24, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c05, 0x0904,
+	0x2df1, 0x2009, 0x0000, 0x2031, 0x0000, 0x7023, 0x0000, 0x702f,
+	0x0000, 0xad80, 0x0005, 0x7026, 0x20a0, 0x080c, 0x4cdc, 0x1904,
+	0x3db4, 0x6004, 0xa0c4, 0x00ff, 0xa8c6, 0x0006, 0x0130, 0xa0c4,
+	0xff00, 0xa8c6, 0x0600, 0x1904, 0x3db4, 0x2001, 0xad52, 0x2004,
+	0xd0ac, 0x1128, 0x080c, 0x4f6e, 0x1110, 0xd79c, 0x05e8, 0xd794,
+	0x1110, 0xd784, 0x0158, 0xac80, 0x0006, 0x2098, 0x3400, 0x20a9,
+	0x0004, 0x53a3, 0x080c, 0x3a86, 0xd794, 0x0148, 0xac80, 0x000a,
+	0x2098, 0x3400, 0x20a9, 0x0004, 0x53a3, 0x080c, 0x3a86, 0x21a2,
+	0xd794, 0x01d8, 0xac80, 0x0000, 0x2098, 0x94a0, 0x20a9, 0x0002,
+	0x53a3, 0xac80, 0x0003, 0x20a6, 0x94a0, 0xac80, 0x0004, 0x2098,
+	0x3400, 0x20a9, 0x0002, 0x53a3, 0x080c, 0x3a78, 0xac80, 0x0026,
+	0x2098, 0x20a9, 0x0002, 0x53a3, 0x0008, 0x94a0, 0xd794, 0x0110,
+	0xa6b0, 0x000b, 0xa6b0, 0x0005, 0x8108, 0x2001, 0xad34, 0x2004,
+	0xd0ac, 0x0118, 0xa186, 0x0100, 0x0040, 0xd78c, 0x0120, 0xa186,
+	0x0100, 0x0170, 0x0018, 0xa186, 0x007e, 0x0150, 0xd794, 0x0118,
+	0xa686, 0x0020, 0x0010, 0xa686, 0x0028, 0x0150, 0x0804, 0x3d5d,
+	0x86ff, 0x1120, 0x7120, 0x810b, 0x0804, 0x2dcc, 0x702f, 0x0001,
+	0x711e, 0x7020, 0xa600, 0x7022, 0x772a, 0x2061, 0xadd1, 0x6007,
+	0x0000, 0x6612, 0x7024, 0x600e, 0x6226, 0x632a, 0x642e, 0x6532,
+	0x2c10, 0x080c, 0x1624, 0x7007, 0x0002, 0x701b, 0x3df0, 0x0005,
+	0x702c, 0xa005, 0x1170, 0x711c, 0x7024, 0x20a0, 0x7728, 0x2031,
+	0x0000, 0x2061, 0xadd1, 0x6224, 0x6328, 0x642c, 0x6530, 0x0804,
+	0x3d5d, 0x7120, 0x810b, 0x0804, 0x2dcc, 0x2029, 0x007e, 0x7924,
+	0x7a28, 0x7b2c, 0x7c38, 0xa184, 0xff00, 0x8007, 0xa0e2, 0x0020,
+	0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa184, 0x00ff, 0xa0e2,
+	0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa284, 0xff00,
+	0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4,
+	0xa284, 0x00ff, 0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04,
+	0x2df4, 0xa384, 0xff00, 0x8007, 0xa0e2, 0x0020, 0x0a04, 0x2df4,
+	0xa502, 0x0a04, 0x2df4, 0xa384, 0x00ff, 0xa0e2, 0x0020, 0x0a04,
+	0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa484, 0xff00, 0x8007, 0xa0e2,
+	0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0xa484, 0x00ff,
+	0xa0e2, 0x0020, 0x0a04, 0x2df4, 0xa502, 0x0a04, 0x2df4, 0x2061,
+	0xafa6, 0x6102, 0x6206, 0x630a, 0x640e, 0x0804, 0x2dcc, 0x0006,
+	0x2001, 0xad52, 0x2004, 0xd0cc, 0x000e, 0x0005, 0x0006, 0x2001,
+	0xad71, 0x2004, 0xd0bc, 0x000e, 0x0005, 0x6164, 0x7a24, 0x6300,
+	0x82ff, 0x1118, 0x7926, 0x0804, 0x2dcc, 0x83ff, 0x1904, 0x2df4,
+	0x2001, 0xfff0, 0xa200, 0x1a04, 0x2df4, 0x2019, 0xffff, 0x6068,
+	0xa302, 0xa200, 0x0a04, 0x2df4, 0x7926, 0x6266, 0x0804, 0x2dcc,
+	0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1904, 0x2df1, 0x7c28,
+	0x7d24, 0x7e38, 0x7f2c, 0x080c, 0x3c05, 0x0904, 0x2df1, 0x2009,
+	0x0000, 0x2019, 0x0000, 0x7023, 0x0000, 0x702f, 0x0000, 0xad80,
+	0x0003, 0x7026, 0x20a0, 0xa1e0, 0xae34, 0x2c64, 0x8cff, 0x01b8,
+	0x6004, 0xa084, 0x00ff, 0xa086, 0x0006, 0x0130, 0x6004, 0xa084,
+	0xff00, 0xa086, 0x0600, 0x1158, 0x6014, 0x20a2, 0x94a0, 0x6010,
+	0x8007, 0xa105, 0x8007, 0x20a2, 0x94a0, 0xa398, 0x0002, 0x8108,
+	0xa182, 0x00ff, 0x0120, 0xa386, 0x002a, 0x0148, 0x08e0, 0x83ff,
+	0x1120, 0x7120, 0x810c, 0x0804, 0x2dcc, 0x702f, 0x0001, 0x711e,
+	0x7020, 0xa300, 0x7022, 0x2061, 0xadd1, 0x6007, 0x0000, 0x6312,
+	0x7024, 0x600e, 0x6426, 0x652a, 0x662e, 0x6732, 0x2c10, 0x080c,
+	0x1624, 0x7007, 0x0002, 0x701b, 0x3ee6, 0x0005, 0x702c, 0xa005,
+	0x1168, 0x711c, 0x7024, 0x20a0, 0x2019, 0x0000, 0x2061, 0xadd1,
+	0x6424, 0x6528, 0x662c, 0x6730, 0x0804, 0x3ea3, 0x7120, 0x810c,
+	0x0804, 0x2dcc, 0x81ff, 0x1904, 0x2df1, 0x60d0, 0xd0ac, 0x1118,
+	0xd09c, 0x0904, 0x2df1, 0x080c, 0x3c05, 0x0904, 0x2df1, 0x7924,
+	0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x080c, 0x3c46, 0x701b, 0x3f11,
+	0x0005, 0x00d6, 0xade8, 0x000d, 0x6828, 0xa0be, 0x7000, 0x0148,
+	0xa0be, 0x7100, 0x0130, 0xa0be, 0x7200, 0x0118, 0x00de, 0x0804,
+	0x2df4, 0x6820, 0x6924, 0x080c, 0x2676, 0x1510, 0x080c, 0x4c80,
+	0x11f8, 0x7122, 0x6612, 0x6516, 0x6e18, 0x00c6, 0x080c, 0x3c05,
+	0x01b8, 0x080c, 0x3c05, 0x01a0, 0x00ce, 0x00de, 0x6837, 0x0000,
+	0x6838, 0xc0fd, 0x683a, 0x6823, 0x0000, 0x6804, 0x2068, 0x080c,
+	0x96ef, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b, 0x3f4b, 0x0005,
+	0x00de, 0x0804, 0x2df1, 0x7120, 0x080c, 0x2bc9, 0x6820, 0xa086,
+	0x8001, 0x0904, 0x2df1, 0x2d00, 0x701e, 0x6804, 0xa080, 0x0002,
+	0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c, 0x48be, 0x000e,
+	0xade8, 0x000d, 0x6a08, 0x6b0c, 0x6c10, 0x6d14, 0x2061, 0xadd1,
+	0x6007, 0x0000, 0x6e00, 0x6f28, 0xa7c6, 0x7000, 0x1108, 0x0018,
+	0xa7c6, 0x7100, 0x1140, 0xa6c2, 0x0004, 0x0a04, 0x2df4, 0x2009,
+	0x0004, 0x0804, 0x3c49, 0xa7c6, 0x7200, 0x1904, 0x2df4, 0xa6c2,
+	0x0054, 0x0a04, 0x2df4, 0x600e, 0x6013, 0x002a, 0x6226, 0x632a,
+	0x642e, 0x6532, 0x2c10, 0x080c, 0x1624, 0x7007, 0x0002, 0x701b,
+	0x3f92, 0x0005, 0x701c, 0x2068, 0x6804, 0xa080, 0x0001, 0x2004,
+	0xa080, 0x0002, 0x0006, 0x20a9, 0x002a, 0x2098, 0x20a0, 0x080c,
+	0x48be, 0x000e, 0x2009, 0x002a, 0x2061, 0xadd1, 0x6224, 0x6328,
+	0x642c, 0x6530, 0x0804, 0x3c49, 0x81ff, 0x1904, 0x2df1, 0x080c,
+	0x3c1a, 0x0904, 0x2df4, 0x080c, 0x4d96, 0x0904, 0x2df1, 0x080c,
+	0x4ec6, 0x0804, 0x2dcc, 0x7824, 0xd084, 0x0904, 0x3804, 0x080c,
+	0x3c2a, 0x0904, 0x2df4, 0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120,
+	0x2009, 0x0002, 0x0804, 0x2df1, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x0128, 0xa08e, 0x0004, 0x0110, 0xa08e, 0x0005, 0x1508,
+	0x2001, 0xad52, 0x2004, 0xd0b4, 0x0904, 0x3834, 0x6000, 0xd08c,
+	0x1904, 0x3834, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c,
+	0x970b, 0x1120, 0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003,
+	0x701b, 0x3ff3, 0x0005, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x0804,
+	0x3834, 0x2009, 0xad30, 0x210c, 0x81ff, 0x0120, 0x2009, 0x0001,
+	0x0804, 0x2df1, 0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x0120,
+	0x2009, 0x0007, 0x0804, 0x2df1, 0x2001, 0xad52, 0x2004, 0xd0ac,
+	0x0120, 0x2009, 0x0008, 0x0804, 0x2df1, 0x609c, 0xd0a4, 0x1118,
+	0xd0ac, 0x1904, 0x3834, 0x6837, 0x0000, 0x6833, 0x0000, 0x6838,
+	0xc0fd, 0x683a, 0x080c, 0x979c, 0x1120, 0x2009, 0x0003, 0x0804,
+	0x2df1, 0x7007, 0x0003, 0x701b, 0x402e, 0x0005, 0x6830, 0xa086,
+	0x0100, 0x1120, 0x2009, 0x0004, 0x0804, 0x2df1, 0x080c, 0x3c2a,
+	0x0904, 0x2df4, 0x0804, 0x3fd8, 0x81ff, 0x2009, 0x0001, 0x1904,
+	0x2df1, 0x6000, 0xa086, 0x0003, 0x2009, 0x0007, 0x1904, 0x2df1,
+	0x2001, 0xad52, 0x2004, 0xd0ac, 0x2009, 0x0008, 0x1904, 0x2df1,
+	0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x2009, 0x0009, 0x1904, 0x2df1, 0x00c6, 0x080c, 0x3c05,
+	0x00ce, 0x2009, 0x0002, 0x0904, 0x2df1, 0x6837, 0x0000, 0x6833,
+	0x0000, 0x6838, 0xc0fd, 0x683a, 0x7928, 0xa194, 0xff00, 0xa18c,
+	0x00ff, 0xa006, 0x82ff, 0x1128, 0xc0ed, 0x6952, 0x792c, 0x6956,
+	0x0048, 0xa28e, 0x0100, 0x1904, 0x2df4, 0xc0e5, 0x6853, 0x0000,
+	0x6857, 0x0000, 0x683e, 0x080c, 0x9957, 0x2009, 0x0003, 0x0904,
+	0x2df1, 0x7007, 0x0003, 0x701b, 0x408e, 0x0005, 0x6830, 0xa086,
+	0x0100, 0x2009, 0x0004, 0x0904, 0x2df1, 0x0804, 0x2dcc, 0x81ff,
+	0x2009, 0x0001, 0x1904, 0x2df1, 0x6000, 0xa086, 0x0003, 0x2009,
+	0x0007, 0x1904, 0x2df1, 0x080c, 0x3c2a, 0x0904, 0x2df4, 0x6004,
+	0xa084, 0x00ff, 0xa086, 0x0006, 0x2009, 0x0009, 0x1904, 0x2df1,
+	0x00c6, 0x080c, 0x3c05, 0x00ce, 0x2009, 0x0002, 0x0904, 0x2df1,
+	0xad80, 0x000f, 0x2009, 0x0008, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x080c, 0x3c46, 0x701b, 0x40c5, 0x0005, 0x00d6, 0xade8, 0x000f,
+	0x6800, 0xa086, 0x0500, 0x1140, 0x6804, 0xa005, 0x1128, 0x6808,
+	0xa084, 0xff00, 0x1108, 0x0018, 0x00de, 0x1904, 0x2df4, 0x00de,
+	0x6837, 0x0000, 0x6833, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x00c6,
+	0x080c, 0x3c2a, 0x1118, 0x00ce, 0x0804, 0x2df4, 0x080c, 0x99a6,
+	0x2009, 0x0003, 0x00ce, 0x0904, 0x2df1, 0x7007, 0x0003, 0x701b,
+	0x40f2, 0x0005, 0x6830, 0xa086, 0x0100, 0x2009, 0x0004, 0x0904,
+	0x2df1, 0x0804, 0x2dcc, 0x81ff, 0x0120, 0x2009, 0x0001, 0x0804,
+	0x2df1, 0x6000, 0xa086, 0x0003, 0x0120, 0x2009, 0x0007, 0x0804,
+	0x2df1, 0x7e24, 0x860f, 0xa18c, 0x00ff, 0xa6b4, 0x00ff, 0x080c,
+	0x4cdc, 0x1904, 0x2df4, 0xa186, 0x007f, 0x0150, 0x6004, 0xa084,
+	0x00ff, 0xa086, 0x0006, 0x0120, 0x2009, 0x0009, 0x0804, 0x2df1,
+	0x00c6, 0x080c, 0x3c05, 0x00ce, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x2df1, 0x6837, 0x0000, 0x6838, 0xc0fd, 0x683a, 0x080c, 0x9726,
+	0x1120, 0x2009, 0x0003, 0x0804, 0x2df1, 0x7007, 0x0003, 0x701b,
+	0x413a, 0x0005, 0x6808, 0x8007, 0xa086, 0x0100, 0x1120, 0x2009,
+	0x0004, 0x0804, 0x2df1, 0x68b0, 0x6836, 0x6810, 0x8007, 0xa084,
+	0x00ff, 0x808e, 0x6814, 0x8007, 0xa084, 0x00ff, 0x8086, 0xa080,
+	0x0002, 0xa108, 0xad80, 0x0004, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38,
+	0x0804, 0x3c49, 0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804,
+	0x2df1, 0x7924, 0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff,
+	0x0110, 0x0804, 0x2df4, 0x2009, 0x001a, 0x7a2c, 0x7b28, 0x7c3c,
+	0x7d38, 0x080c, 0x3c46, 0x701b, 0x4176, 0x0005, 0xad80, 0x000d,
+	0x2098, 0x20a9, 0x001a, 0x20a1, 0xafad, 0x53a3, 0x0804, 0x2dcc,
+	0x080c, 0x3c05, 0x1120, 0x2009, 0x0002, 0x0804, 0x2df1, 0x7924,
+	0xa194, 0xff00, 0xa18c, 0x00ff, 0x8217, 0x82ff, 0x0110, 0x0804,
+	0x2df4, 0x2099, 0xafad, 0x20a0, 0x20a9, 0x001a, 0x53a3, 0x2009,
+	0x001a, 0x7a2c, 0x7b28, 0x7c3c, 0x7d38, 0x0804, 0x3c49, 0x7824,
+	0xa08a, 0x1000, 0x1a04, 0x2df4, 0x0126, 0x2091, 0x8000, 0x8003,
+	0x800b, 0x810b, 0xa108, 0x00c6, 0x2061, 0xafda, 0x6142, 0x00ce,
+	0x012e, 0x0804, 0x2dcc, 0x00c6, 0x080c, 0x574f, 0x1188, 0x2001,
+	0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0xa085,
+	0x0001, 0x080c, 0x5793, 0x080c, 0x569a, 0x080c, 0x14f6, 0x0038,
+	0x2061, 0xad00, 0x6030, 0xc09d, 0x6032, 0x080c, 0x485e, 0x00ce,
+	0x0005, 0x0126, 0x00c6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00,
+	0x6044, 0xd0a4, 0x11b0, 0xd084, 0x0118, 0x080c, 0x4348, 0x0068,
+	0xd08c, 0x0118, 0x080c, 0x4269, 0x0040, 0xd094, 0x0118, 0x080c,
+	0x423a, 0x0018, 0xd09c, 0x0108, 0x0061, 0x00ee, 0x00ce, 0x012e,
+	0x0005, 0x0016, 0x6128, 0xd19c, 0x1110, 0xc19d, 0x612a, 0x001e,
+	0x0ca0, 0x624c, 0xa286, 0xf0f0, 0x1150, 0x6048, 0xa086, 0xf0f0,
+	0x0130, 0x624a, 0x6043, 0x0090, 0x6043, 0x0010, 0x0490, 0xa294,
+	0xff00, 0xa296, 0xf700, 0x0178, 0x7134, 0xd1a4, 0x1160, 0x6240,
+	0xa295, 0x0100, 0x6242, 0xa294, 0x0010, 0x0128, 0x2009, 0x00f7,
+	0x080c, 0x48de, 0x00f0, 0x6040, 0xa084, 0x0010, 0xa085, 0x0040,
+	0x6042, 0x6043, 0x0000, 0x7077, 0x0000, 0x7093, 0x0001, 0x70b7,
+	0x0000, 0x70d3, 0x0000, 0x2009, 0xb3c0, 0x200b, 0x0000, 0x7087,
+	0x0000, 0x707b, 0x000a, 0x2009, 0x000a, 0x2011, 0x4814, 0x080c,
+	0x6593, 0x0005, 0x0156, 0x2001, 0xad73, 0x2004, 0xd08c, 0x0110,
+	0x704f, 0xffff, 0x7078, 0xa005, 0x1510, 0x2011, 0x4814, 0x080c,
+	0x650d, 0x6040, 0xa094, 0x0010, 0xa285, 0x0020, 0x6042, 0x20a9,
+	0x00c8, 0x6044, 0xd08c, 0x1168, 0x1f04, 0x4251, 0x6242, 0x708b,
+	0x0000, 0x6040, 0xa094, 0x0010, 0xa285, 0x0080, 0x6042, 0x6242,
+	0x0030, 0x6242, 0x708b, 0x0000, 0x707f, 0x0000, 0x0000, 0x015e,
+	0x0005, 0x707c, 0xa08a, 0x0003, 0x1210, 0x0023, 0x0010, 0x080c,
+	0x14f6, 0x0005, 0x4275, 0x42c5, 0x4347, 0x00f6, 0x707f, 0x0001,
+	0x20e1, 0xa000, 0xe000, 0x20e1, 0x8700, 0x080c, 0x22f8, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x2079, 0xb200, 0x207b, 0x2200, 0x7807,
+	0x00ef, 0x780b, 0x0000, 0x780f, 0x00ef, 0x7813, 0x0138, 0x7817,
+	0x0000, 0x781b, 0x0000, 0x781f, 0x0000, 0x7823, 0xffff, 0x7827,
+	0xffff, 0x782b, 0x0000, 0x782f, 0x0000, 0x2079, 0xb20c, 0x207b,
+	0x1101, 0x7807, 0x0000, 0x2099, 0xad05, 0x20a1, 0xb20e, 0x20a9,
+	0x0004, 0x53a3, 0x2079, 0xb212, 0x207b, 0x0000, 0x7807, 0x0000,
+	0x2099, 0xb200, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6, 0x60c3,
+	0x000c, 0x600f, 0x0000, 0x080c, 0x4845, 0x00fe, 0x7083, 0x0000,
+	0x6043, 0x0008, 0x6043, 0x0000, 0x0005, 0x00d6, 0x7080, 0x7083,
+	0x0000, 0xa025, 0x0904, 0x432f, 0x6020, 0xd0b4, 0x1904, 0x432d,
+	0x7190, 0x81ff, 0x0904, 0x431d, 0xa486, 0x000c, 0x1904, 0x4328,
+	0xa480, 0x0018, 0x8004, 0x20a8, 0x2011, 0xb280, 0x2019, 0xb200,
+	0x220c, 0x2304, 0xa106, 0x11b8, 0x8210, 0x8318, 0x1f04, 0x42e0,
+	0x6043, 0x0004, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043, 0x0006,
+	0x707f, 0x0002, 0x708b, 0x0002, 0x2009, 0x07d0, 0x2011, 0x481b,
+	0x080c, 0x6593, 0x0490, 0x2069, 0xb280, 0x6930, 0xa18e, 0x1101,
+	0x1538, 0x6834, 0xa005, 0x1520, 0x6900, 0xa18c, 0x00ff, 0x1118,
+	0x6804, 0xa005, 0x0190, 0x2011, 0xb28e, 0x2019, 0xad05, 0x20a9,
+	0x0004, 0x220c, 0x2304, 0xa102, 0x0230, 0x1190, 0x8210, 0x8318,
+	0x1f04, 0x4311, 0x0068, 0x7093, 0x0000, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x2099, 0xb280, 0x20a1, 0x020b, 0x20a9, 0x0014, 0x53a6,
+	0x6043, 0x0008, 0x6043, 0x0000, 0x0010, 0x00de, 0x0005, 0x6040,
+	0xa085, 0x0100, 0x6042, 0x6020, 0xd0b4, 0x1db8, 0x60c3, 0x000c,
+	0x2011, 0xafd1, 0x2013, 0x0000, 0x7083, 0x0000, 0x20e1, 0x9080,
+	0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x782b, 0x0c30, 0x0005,
+	0x7088, 0xa08a, 0x001d, 0x1210, 0x0023, 0x0010, 0x080c, 0x14f6,
+	0x0005, 0x437b, 0x438a, 0x43b2, 0x43cb, 0x43ef, 0x4417, 0x443b,
+	0x446c, 0x4490, 0x44b8, 0x44ef, 0x4517, 0x4533, 0x4549, 0x4569,
+	0x457c, 0x4584, 0x45b1, 0x45d5, 0x45fd, 0x4621, 0x4652, 0x468f,
+	0x46be, 0x46da, 0x4719, 0x4739, 0x4752, 0x4753, 0x00c6, 0x2061,
+	0xad00, 0x6003, 0x0007, 0x2061, 0x0100, 0x6004, 0xa084, 0xfff9,
+	0x6006, 0x00ce, 0x0005, 0x608b, 0xbc94, 0x608f, 0xf0f0, 0x6043,
+	0x0002, 0x708b, 0x0001, 0x2009, 0x07d0, 0x2011, 0x481b, 0x080c,
+	0x6593, 0x0005, 0x00f6, 0x7080, 0xa086, 0x0014, 0x1508, 0x6043,
+	0x0000, 0x6020, 0xd0b4, 0x11e0, 0x2079, 0xb280, 0x7a30, 0xa296,
+	0x1102, 0x11a0, 0x7834, 0xa005, 0x1188, 0x7a38, 0xd2fc, 0x0128,
+	0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x2011, 0x481b, 0x080c,
+	0x650d, 0x708b, 0x0010, 0x080c, 0x4584, 0x0010, 0x080c, 0x485e,
+	0x00fe, 0x0005, 0x708b, 0x0003, 0x6043, 0x0004, 0x2011, 0x481b,
+	0x080c, 0x650d, 0x080c, 0x48c6, 0x20a3, 0x1102, 0x20a3, 0x0000,
+	0x20a9, 0x000a, 0x20a3, 0x0000, 0x1f04, 0x43c2, 0x60c3, 0x0014,
+	0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011,
+	0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb280,
+	0x7a30, 0xa296, 0x1102, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38,
+	0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b,
+	0x0004, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b,
+	0x0005, 0x080c, 0x48c6, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430,
+	0x2011, 0xb28e, 0x080c, 0x4917, 0x1160, 0x7074, 0xa005, 0x1148,
+	0x714c, 0xa186, 0xffff, 0x0128, 0x080c, 0x47df, 0x0110, 0x080c,
+	0x48f5, 0x20a9, 0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x4845, 0x0005, 0x00f6,
+	0x7080, 0xa005, 0x01f0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086,
+	0x0014, 0x11a8, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1103, 0x1178,
+	0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005,
+	0x1110, 0x70b7, 0x0001, 0x708b, 0x0006, 0x0029, 0x0010, 0x080c,
+	0x485e, 0x00fe, 0x0005, 0x708b, 0x0007, 0x080c, 0x48c6, 0x20a3,
+	0x1104, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb28e, 0x080c, 0x4917,
+	0x11a8, 0x7074, 0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170,
+	0xa180, 0x2be6, 0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x47df,
+	0x0128, 0x080c, 0x3e66, 0x0110, 0x080c, 0x26c0, 0x20a9, 0x0008,
+	0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0014, 0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0,
+	0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8, 0x2079,
+	0xb280, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834, 0xa005, 0x1160,
+	0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001,
+	0x708b, 0x0008, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005,
+	0x708b, 0x0009, 0x080c, 0x48c6, 0x20a3, 0x1105, 0x20a3, 0x0100,
+	0x3430, 0x080c, 0x4917, 0x1150, 0x7074, 0xa005, 0x1138, 0x080c,
+	0x4754, 0x1170, 0xa085, 0x0001, 0x080c, 0x26c0, 0x20a9, 0x0008,
+	0x2099, 0xb28e, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0014, 0x080c, 0x4845, 0x0010, 0x080c, 0x436e, 0x0005,
+	0x00f6, 0x7080, 0xa005, 0x0588, 0x2011, 0x481b, 0x080c, 0x650d,
+	0xa086, 0x0014, 0x1540, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1105,
+	0x1510, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1160, 0x7a38, 0xd2fc,
+	0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x000a,
+	0x00b1, 0x0098, 0xa005, 0x1178, 0x7a38, 0xd2fc, 0x0128, 0x70b4,
+	0xa005, 0x1110, 0x70b7, 0x0001, 0x7087, 0x0000, 0x708b, 0x000e,
+	0x080c, 0x4569, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b,
+	0x000b, 0x2011, 0xb20e, 0x22a0, 0x20a9, 0x0040, 0x2019, 0xffff,
+	0x43a4, 0x20a9, 0x0002, 0x2009, 0x0000, 0x41a4, 0x080c, 0x48c6,
+	0x20a3, 0x1106, 0x20a3, 0x0000, 0x080c, 0x4917, 0x0118, 0x2013,
+	0x0000, 0x0020, 0x7050, 0xa085, 0x0100, 0x2012, 0x2298, 0x20a9,
+	0x0042, 0x53a6, 0x60c3, 0x0084, 0x080c, 0x4845, 0x0005, 0x00f6,
+	0x7080, 0xa005, 0x01b0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086,
+	0x0084, 0x1168, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1106, 0x1138,
+	0x7834, 0xa005, 0x1120, 0x708b, 0x000c, 0x0029, 0x0010, 0x080c,
+	0x485e, 0x00fe, 0x0005, 0x708b, 0x000d, 0x080c, 0x48c6, 0x20a3,
+	0x1107, 0x20a3, 0x0000, 0x2099, 0xb28e, 0x20a9, 0x0040, 0x53a6,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4845,
+	0x0005, 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x481b, 0x080c,
+	0x650d, 0xa086, 0x0084, 0x1188, 0x2079, 0xb280, 0x7a30, 0xa296,
+	0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c,
+	0x48b8, 0x708b, 0x000e, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe,
+	0x0005, 0x708b, 0x000f, 0x7083, 0x0000, 0x608b, 0xbc85, 0x608f,
+	0xb5b5, 0x6043, 0x0005, 0x6043, 0x0004, 0x2009, 0x07d0, 0x2011,
+	0x481b, 0x080c, 0x6501, 0x0005, 0x7080, 0xa005, 0x0120, 0x2011,
+	0x481b, 0x080c, 0x650d, 0x0005, 0x708b, 0x0011, 0x080c, 0x4917,
+	0x1188, 0x716c, 0x81ff, 0x0170, 0x2009, 0x0000, 0x7070, 0xa084,
+	0x00ff, 0x080c, 0x2676, 0xa186, 0x0080, 0x0120, 0x2011, 0xb28e,
+	0x080c, 0x47df, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb280,
+	0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007, 0xa084,
+	0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0014, 0x080c, 0x4845,
+	0x0005, 0x00f6, 0x7080, 0xa005, 0x01f0, 0x2011, 0x481b, 0x080c,
+	0x650d, 0xa086, 0x0014, 0x11a8, 0x2079, 0xb280, 0x7a30, 0xa296,
+	0x1103, 0x1178, 0x7834, 0xa005, 0x1160, 0x7a38, 0xd2fc, 0x0128,
+	0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001, 0x708b, 0x0012, 0x0029,
+	0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x708b, 0x0013, 0x080c,
+	0x48d2, 0x20a3, 0x1103, 0x20a3, 0x0000, 0x3430, 0x2011, 0xb28e,
+	0x080c, 0x4917, 0x1160, 0x7074, 0xa005, 0x1148, 0x714c, 0xa186,
+	0xffff, 0x0128, 0x080c, 0x47df, 0x0110, 0x080c, 0x48f5, 0x20a9,
+	0x0008, 0x2298, 0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x60c3, 0x0014, 0x080c, 0x4845, 0x0005, 0x00f6, 0x7080, 0xa005,
+	0x01f0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0014, 0x11a8,
+	0x2079, 0xb280, 0x7a30, 0xa296, 0x1104, 0x1178, 0x7834, 0xa005,
+	0x1160, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7,
+	0x0001, 0x708b, 0x0014, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe,
+	0x0005, 0x708b, 0x0015, 0x080c, 0x48d2, 0x20a3, 0x1104, 0x20a3,
+	0x0000, 0x3430, 0x2011, 0xb28e, 0x080c, 0x4917, 0x11a8, 0x7074,
+	0xa005, 0x1190, 0x7154, 0xa186, 0xffff, 0x0170, 0xa180, 0x2be6,
+	0x200d, 0xa18c, 0xff00, 0x810f, 0x080c, 0x47df, 0x0128, 0x080c,
+	0x3e66, 0x0110, 0x080c, 0x26c0, 0x20a9, 0x0008, 0x2298, 0x26a0,
+	0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c,
+	0x4845, 0x0005, 0x00f6, 0x7080, 0xa005, 0x05b8, 0x2011, 0x481b,
+	0x080c, 0x650d, 0xa086, 0x0014, 0x1570, 0x2079, 0xb280, 0x7a30,
+	0xa296, 0x1105, 0x1540, 0x7834, 0x2011, 0x0100, 0xa21e, 0x1148,
+	0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005, 0x1110, 0x70b7, 0x0001,
+	0x0060, 0xa005, 0x11c0, 0x7a38, 0xd2fc, 0x0128, 0x70b4, 0xa005,
+	0x1110, 0x70b7, 0x0001, 0x7087, 0x0000, 0x7a38, 0xd2f4, 0x0138,
+	0x2001, 0xad73, 0x2004, 0xd0a4, 0x1110, 0x70d3, 0x0008, 0x708b,
+	0x0016, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe, 0x0005, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x2099, 0xb280, 0x20a1, 0x020b, 0x20a9,
+	0x000e, 0x53a6, 0x3430, 0x2011, 0xb28e, 0x708b, 0x0017, 0x080c,
+	0x4917, 0x1150, 0x7074, 0xa005, 0x1138, 0x080c, 0x4754, 0x1170,
+	0xa085, 0x0001, 0x080c, 0x26c0, 0x20a9, 0x0008, 0x2099, 0xb28e,
+	0x26a0, 0x53a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014,
+	0x080c, 0x4845, 0x0010, 0x080c, 0x436e, 0x0005, 0x00f6, 0x7080,
+	0xa005, 0x01b0, 0x2011, 0x481b, 0x080c, 0x650d, 0xa086, 0x0084,
+	0x1168, 0x2079, 0xb280, 0x7a30, 0xa296, 0x1106, 0x1138, 0x7834,
+	0xa005, 0x1120, 0x708b, 0x0018, 0x0029, 0x0010, 0x080c, 0x485e,
+	0x00fe, 0x0005, 0x708b, 0x0019, 0x080c, 0x48d2, 0x20a3, 0x1106,
+	0x20a3, 0x0000, 0x3430, 0x2099, 0xb28e, 0x2039, 0xb20e, 0x27a0,
+	0x20a9, 0x0040, 0x53a3, 0x080c, 0x4917, 0x11e8, 0x2728, 0x2514,
+	0x8207, 0xa084, 0x00ff, 0x8000, 0x2018, 0xa294, 0x00ff, 0x8007,
+	0xa205, 0x202a, 0x7050, 0x2310, 0x8214, 0xa2a0, 0xb20e, 0x2414,
+	0xa38c, 0x0001, 0x0118, 0xa294, 0xff00, 0x0018, 0xa294, 0x00ff,
+	0x8007, 0xa215, 0x2222, 0x2798, 0x26a0, 0x20a9, 0x0040, 0x53a6,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x0084, 0x080c, 0x4845,
+	0x0005, 0x00f6, 0x7080, 0xa005, 0x01d0, 0x2011, 0x481b, 0x080c,
+	0x650d, 0xa086, 0x0084, 0x1188, 0x2079, 0xb280, 0x7a30, 0xa296,
+	0x1107, 0x1158, 0x7834, 0xa005, 0x1140, 0x7087, 0x0001, 0x080c,
+	0x48b8, 0x708b, 0x001a, 0x0029, 0x0010, 0x080c, 0x485e, 0x00fe,
+	0x0005, 0x708b, 0x001b, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099,
+	0xb280, 0x20a1, 0x020b, 0x7480, 0xa480, 0x0018, 0xa080, 0x0007,
+	0xa084, 0x03f8, 0x8004, 0x20a8, 0x53a6, 0x60c3, 0x0084, 0x080c,
+	0x4845, 0x0005, 0x0005, 0x0005, 0x0086, 0x0096, 0x2029, 0xad52,
+	0x252c, 0x20a9, 0x0008, 0x2041, 0xb20e, 0x28a0, 0x2099, 0xb28e,
+	0x53a3, 0x20a9, 0x0008, 0x2011, 0x0007, 0xd5d4, 0x0110, 0x2011,
+	0x0000, 0x2800, 0xa200, 0x200c, 0xa1a6, 0xffff, 0x1148, 0xd5d4,
+	0x0110, 0x8210, 0x0008, 0x8211, 0x1f04, 0x4769, 0x0804, 0x47d7,
+	0x82ff, 0x1160, 0xd5d4, 0x0120, 0xa1a6, 0x3fff, 0x0d90, 0x0020,
+	0xa1a6, 0x3fff, 0x0904, 0x47d7, 0xa18d, 0xc000, 0x20a9, 0x0010,
+	0x2019, 0x0001, 0xd5d4, 0x0110, 0x2019, 0x0010, 0x2120, 0xd5d4,
+	0x0110, 0x8423, 0x0008, 0x8424, 0x1240, 0xd5d4, 0x0110, 0x8319,
+	0x0008, 0x8318, 0x1f04, 0x478f, 0x04d0, 0x23a8, 0x2021, 0x0001,
+	0x8426, 0x8425, 0x1f04, 0x47a1, 0x2328, 0x8529, 0xa2be, 0x0007,
+	0x0158, 0x0006, 0x2039, 0x0007, 0x2200, 0xa73a, 0x000e, 0x27a8,
+	0xa5a8, 0x0010, 0x1f04, 0x47b0, 0x754e, 0xa5c8, 0x2be6, 0x292d,
+	0xa5ac, 0x00ff, 0x7572, 0x6532, 0x6536, 0x0016, 0x2508, 0x080c,
+	0x26a0, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x2018, 0x2304, 0xa405,
+	0x201a, 0x7077, 0x0001, 0x26a0, 0x2898, 0x20a9, 0x0008, 0x53a6,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0xa085, 0x0001, 0x0028, 0xa006,
+	0x0018, 0xa006, 0x080c, 0x14f6, 0x009e, 0x008e, 0x0005, 0x2118,
+	0x2021, 0x0000, 0x2001, 0x0007, 0xa39a, 0x0010, 0x0218, 0x8420,
+	0x8001, 0x0cd0, 0x2118, 0x84ff, 0x0120, 0xa39a, 0x0010, 0x8421,
+	0x1de0, 0x2021, 0x0001, 0x83ff, 0x0118, 0x8423, 0x8319, 0x1de8,
+	0xa238, 0x2704, 0xa42c, 0x11b8, 0xa405, 0x203a, 0x714e, 0xa1a0,
+	0x2be6, 0x242d, 0xa5ac, 0x00ff, 0x7572, 0x6532, 0x6536, 0x0016,
+	0x2508, 0x080c, 0x26a0, 0x001e, 0x60e7, 0x0000, 0x65ea, 0x7077,
+	0x0001, 0xa084, 0x0000, 0x0005, 0x00e6, 0x2071, 0xad00, 0x707b,
+	0x0000, 0x00ee, 0x0005, 0x00e6, 0x00f6, 0x2079, 0x0100, 0x2071,
+	0x0140, 0x080c, 0x7834, 0x7004, 0xa084, 0x4000, 0x0120, 0x7003,
+	0x1000, 0x7003, 0x0000, 0x0126, 0x2091, 0x8000, 0x2071, 0xad22,
+	0x2073, 0x0000, 0x7840, 0x0026, 0x0016, 0x2009, 0x00f7, 0x080c,
+	0x48de, 0x001e, 0xa094, 0x0010, 0xa285, 0x0080, 0x7842, 0x7a42,
+	0x002e, 0x012e, 0x00fe, 0x00ee, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x2011, 0xafd1, 0x2013, 0x0000, 0x7083, 0x0000, 0x012e, 0x20e1,
+	0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x080c, 0x782b, 0x2009,
+	0x07d0, 0x2011, 0x481b, 0x080c, 0x6593, 0x0005, 0x0016, 0x0026,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x2009, 0x00f7, 0x080c, 0x48de,
+	0x2061, 0xafda, 0x601b, 0x0000, 0x601f, 0x0000, 0x2061, 0xad00,
+	0x6003, 0x0001, 0x2061, 0x0100, 0x6043, 0x0090, 0x6043, 0x0010,
+	0x2009, 0x002d, 0x2011, 0x4883, 0x080c, 0x6501, 0x012e, 0x00ce,
+	0x002e, 0x001e, 0x0005, 0x00e6, 0x0006, 0x0126, 0x2091, 0x8000,
+	0x2071, 0x0100, 0x080c, 0x7834, 0x2071, 0x0140, 0x7004, 0xa084,
+	0x4000, 0x0120, 0x7003, 0x1000, 0x7003, 0x0000, 0x080c, 0x5757,
+	0x01a8, 0x080c, 0x5775, 0x1190, 0x2001, 0xaf9d, 0x2003, 0xaaaa,
+	0x0016, 0x080c, 0x2744, 0x2001, 0xaf8e, 0x2102, 0x001e, 0x2001,
+	0xaf9e, 0x2003, 0x0000, 0x080c, 0x569a, 0x0030, 0x2001, 0x0001,
+	0x080c, 0x261e, 0x080c, 0x485e, 0x012e, 0x000e, 0x00ee, 0x0005,
+	0x20a9, 0x0040, 0x20a1, 0xb3c0, 0x2099, 0xb28e, 0x3304, 0x8007,
+	0x20a2, 0x9398, 0x94a0, 0x1f04, 0x48be, 0x0005, 0x20e1, 0x9080,
+	0x20e1, 0x4000, 0x2099, 0xb200, 0x20a1, 0x020b, 0x20a9, 0x000c,
+	0x53a6, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x2099, 0xb280,
+	0x20a1, 0x020b, 0x20a9, 0x000c, 0x53a6, 0x0005, 0x00c6, 0x0006,
+	0x2061, 0x0100, 0x810f, 0x2001, 0xad30, 0x2004, 0xa005, 0x1138,
+	0x2001, 0xad14, 0x2004, 0xa084, 0x00ff, 0xa105, 0x0010, 0xa185,
+	0x00f7, 0x604a, 0x000e, 0x00ce, 0x0005, 0x0016, 0x0046, 0x2001,
+	0xad52, 0x2004, 0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a,
+	0x080c, 0xa96c, 0x2001, 0xad0c, 0x200c, 0xc195, 0x2102, 0x2019,
+	0x002a, 0x2009, 0x0000, 0x080c, 0x2aac, 0x004e, 0x001e, 0x0005,
+	0x080c, 0x485e, 0x708b, 0x0000, 0x7083, 0x0000, 0x0005, 0x0006,
+	0x2001, 0xad0c, 0x2004, 0xd09c, 0x0100, 0x000e, 0x0005, 0x0006,
+	0x0016, 0x0126, 0x2091, 0x8000, 0x2001, 0x0101, 0x200c, 0xa18d,
+	0x0006, 0x2102, 0x012e, 0x001e, 0x000e, 0x0005, 0x0156, 0x20a9,
+	0x00ff, 0x2009, 0xae34, 0xa006, 0x200a, 0x8108, 0x1f04, 0x4934,
+	0x015e, 0x0005, 0x00d6, 0x0036, 0x0156, 0x0136, 0x0146, 0x2069,
+	0xad51, 0xa006, 0x6002, 0x6007, 0x0707, 0x600a, 0x600e, 0x6012,
+	0xa198, 0x2be6, 0x231d, 0xa39c, 0x00ff, 0x6316, 0x20a9, 0x0004,
+	0xac98, 0x0006, 0x23a0, 0x40a4, 0x20a9, 0x0004, 0xac98, 0x000a,
+	0x23a0, 0x40a4, 0x603e, 0x6042, 0x604e, 0x6052, 0x6056, 0x605a,
+	0x605e, 0x6062, 0x6066, 0x606a, 0x606e, 0x6072, 0x6076, 0x607a,
+	0x607e, 0x6082, 0x6086, 0x608a, 0x608e, 0x6092, 0x6096, 0x609a,
+	0x609e, 0x60ae, 0x61a2, 0x00d6, 0x60a4, 0xa06d, 0x0110, 0x080c,
+	0x15f0, 0x60a7, 0x0000, 0x60a8, 0xa06d, 0x0110, 0x080c, 0x15f0,
+	0x60ab, 0x0000, 0x00de, 0xa006, 0x604a, 0x6810, 0x603a, 0x680c,
+	0x6046, 0x6814, 0xa084, 0x00ff, 0x6042, 0x014e, 0x013e, 0x015e,
+	0x003e, 0x00de, 0x0005, 0x0126, 0x2091, 0x8000, 0x6944, 0x6e48,
+	0xa684, 0x3fff, 0xa082, 0x4000, 0x1a04, 0x4a49, 0xa18c, 0xff00,
+	0x810f, 0xa182, 0x00ff, 0x1a04, 0x4a4e, 0x2001, 0xad0c, 0x2004,
+	0xa084, 0x0003, 0x01c0, 0x2001, 0xad0c, 0x2004, 0xd084, 0x1904,
+	0x4a31, 0xa188, 0xae34, 0x2104, 0xa065, 0x0904, 0x4a31, 0x6004,
+	0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4a31, 0x6000, 0xd0c4,
+	0x0904, 0x4a31, 0x0068, 0xa188, 0xae34, 0x2104, 0xa065, 0x0904,
+	0x4a15, 0x6004, 0xa084, 0x00ff, 0xa08e, 0x0006, 0x1904, 0x4a1a,
+	0x60a4, 0xa00d, 0x0118, 0x080c, 0x4ef9, 0x05d0, 0x60a8, 0xa00d,
+	0x0188, 0x080c, 0x4f43, 0x1170, 0x694c, 0xd1fc, 0x1118, 0x080c,
+	0x4c11, 0x0448, 0x080c, 0x4bd3, 0x694c, 0xd1ec, 0x1520, 0x080c,
+	0x4ded, 0x0408, 0x694c, 0xa184, 0xa000, 0x0178, 0xd1ec, 0x0140,
+	0xd1fc, 0x0118, 0x080c, 0x4dfc, 0x0028, 0x080c, 0x4dfc, 0x0028,
+	0xd1fc, 0x0118, 0x080c, 0x4bd3, 0x0070, 0x6050, 0xa00d, 0x0130,
+	0x2d00, 0x200a, 0x6803, 0x0000, 0x6052, 0x0028, 0x2d00, 0x6052,
+	0x604e, 0x6803, 0x0000, 0x080c, 0x67c5, 0xa006, 0x012e, 0x0005,
+	0x2001, 0x0005, 0x2009, 0x0000, 0x04e8, 0x2001, 0x0028, 0x2009,
+	0x0000, 0x04c0, 0xa082, 0x0006, 0x12a0, 0x2001, 0xad34, 0x2004,
+	0xd0ac, 0x1160, 0x60a0, 0xd0bc, 0x1148, 0x6100, 0xd1fc, 0x0904,
+	0x49d0, 0x2001, 0x0029, 0x2009, 0x1000, 0x0420, 0x2001, 0x0028,
+	0x00a8, 0x2009, 0xad0c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004,
+	0x0068, 0xd184, 0x0118, 0x2001, 0x0004, 0x0040, 0x2001, 0x0029,
+	0x6100, 0xd1fc, 0x0118, 0x2009, 0x1000, 0x0060, 0x2009, 0x0000,
+	0x0048, 0x2001, 0x0029, 0x2009, 0x0000, 0x0020, 0x2001, 0x0029,
+	0x2009, 0x0000, 0xa005, 0x012e, 0x0005, 0x00e6, 0x0126, 0x2091,
+	0x8000, 0x6844, 0x8007, 0xa084, 0x00ff, 0x2008, 0xa182, 0x00ff,
+	0x1a04, 0x4aa8, 0xa188, 0xae34, 0x2104, 0xa065, 0x01c0, 0x6004,
+	0xa084, 0x00ff, 0xa08e, 0x0006, 0x11a8, 0x2c70, 0x080c, 0x8022,
+	0x05e8, 0x2e00, 0x601a, 0x2d00, 0x6012, 0x600b, 0xffff, 0x601f,
+	0x000a, 0x2009, 0x0003, 0x080c, 0x80a7, 0xa006, 0x0460, 0x2001,
+	0x0028, 0x0440, 0xa082, 0x0006, 0x1298, 0x2001, 0xad34, 0x2004,
+	0xd0ac, 0x1158, 0x60a0, 0xd0bc, 0x1140, 0x6100, 0xd1fc, 0x09e8,
+	0x2001, 0x0029, 0x2009, 0x1000, 0x00a8, 0x2001, 0x0028, 0x0090,
+	0x2009, 0xad0c, 0x210c, 0xd18c, 0x0118, 0x2001, 0x0004, 0x0050,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0028, 0x2001, 0x0029, 0x0010,
+	0x2001, 0x0029, 0xa005, 0x012e, 0x00ee, 0x0005, 0x2001, 0x002c,
+	0x0cc8, 0x00f6, 0x00e6, 0x0126, 0x2091, 0x8000, 0x2011, 0x0000,
+	0x2079, 0xad00, 0x6944, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff,
+	0x1a04, 0x4b77, 0x2001, 0xad0c, 0x2004, 0xa084, 0x0003, 0x1904,
+	0x4b65, 0x080c, 0x4cdc, 0x1180, 0x6004, 0xa084, 0x00ff, 0xa082,
+	0x0006, 0x1250, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1904, 0x4b60,
+	0x60a0, 0xd0bc, 0x1904, 0x4b60, 0x6864, 0xa0c6, 0x006f, 0x0118,
+	0x2008, 0x0804, 0x4b28, 0x6968, 0x2140, 0xa18c, 0xff00, 0x810f,
+	0x78d0, 0xd0ac, 0x1118, 0xa182, 0x0080, 0x06d0, 0xa182, 0x00ff,
+	0x16b8, 0x6a70, 0x6b6c, 0x786c, 0xa306, 0x1160, 0x7870, 0xa24e,
+	0x1118, 0x2208, 0x2310, 0x0460, 0xa9cc, 0xff00, 0x1118, 0x2208,
+	0x2310, 0x0430, 0x080c, 0x3b58, 0x2c70, 0x0550, 0x2009, 0x0000,
+	0x2011, 0x0000, 0xa0c6, 0x4000, 0x1160, 0x0006, 0x2e60, 0x080c,
+	0x4f6e, 0x1108, 0xc185, 0x7000, 0xd0bc, 0x0108, 0xc18d, 0x000e,
+	0x0088, 0xa0c6, 0x4007, 0x1110, 0x2408, 0x0060, 0xa0c6, 0x4008,
+	0x1118, 0x2708, 0x2610, 0x0030, 0xa0c6, 0x4009, 0x1108, 0x0010,
+	0x2001, 0x4006, 0x6866, 0x696a, 0x6a6e, 0x2001, 0x0030, 0x0458,
+	0x080c, 0x8022, 0x1138, 0x2001, 0x4005, 0x2009, 0x0003, 0x2011,
+	0x0000, 0x0c80, 0x2e00, 0x601a, 0x080c, 0x9956, 0x2d00, 0x6012,
+	0x601f, 0x0001, 0xa006, 0xd88c, 0x0110, 0x2001, 0x4000, 0x683a,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x2ad9, 0x012e, 0x2001, 0x0000,
+	0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c, 0x4c30, 0x2009, 0x0002,
+	0x080c, 0x80a7, 0xa006, 0xa005, 0x012e, 0x00ee, 0x00fe, 0x0005,
+	0x2001, 0x0028, 0x2009, 0x0000, 0x0cb0, 0x2009, 0xad0c, 0x210c,
+	0xd18c, 0x0118, 0x2001, 0x0004, 0x0038, 0xd184, 0x0118, 0x2001,
+	0x0004, 0x0010, 0x2001, 0x0029, 0x2009, 0x0000, 0x0c20, 0x2001,
+	0x0029, 0x2009, 0x0000, 0x08f8, 0x6944, 0x6e48, 0xa684, 0x3fff,
+	0xa082, 0x4000, 0x16b8, 0xa18c, 0xff00, 0x810f, 0xa182, 0x00ff,
+	0x12e0, 0xa188, 0xae34, 0x2104, 0xa065, 0x01b8, 0x6004, 0xa084,
+	0x00ff, 0xa08e, 0x0006, 0x11b0, 0x684c, 0xd0ec, 0x0120, 0x080c,
+	0x4dfc, 0x04c9, 0x0030, 0x04b9, 0x684c, 0xd0fc, 0x0110, 0x080c,
+	0x4ded, 0x080c, 0x4e3a, 0xa006, 0x00c8, 0x2001, 0x0028, 0x2009,
+	0x0000, 0x00a0, 0xa082, 0x0006, 0x1240, 0x6100, 0xd1fc, 0x0d20,
+	0x2001, 0x0029, 0x2009, 0x1000, 0x0048, 0x2001, 0x0029, 0x2009,
+	0x0000, 0x0020, 0x2001, 0x0029, 0x2009, 0x0000, 0xa005, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x6050, 0xa00d, 0x0138, 0x2d00, 0x200a,
+	0x6803, 0x0000, 0x6052, 0x012e, 0x0005, 0x2d00, 0x6052, 0x604e,
+	0x6803, 0x0000, 0x0cc0, 0x0126, 0x2091, 0x8000, 0x604c, 0xa005,
+	0x0170, 0x00e6, 0x2071, 0xafc7, 0x7004, 0xa086, 0x0002, 0x0168,
+	0x00ee, 0x604c, 0x6802, 0x2d00, 0x604e, 0x012e, 0x0005, 0x2d00,
+	0x6052, 0x604e, 0x6803, 0x0000, 0x0cc0, 0x701c, 0xac06, 0x1d80,
+	0x604c, 0x2070, 0x7000, 0x6802, 0x2d00, 0x7002, 0x00ee, 0x012e,
+	0x0005, 0x0126, 0x2091, 0x8000, 0x604c, 0xa06d, 0x0130, 0x6800,
+	0xa005, 0x1108, 0x6052, 0x604e, 0xad05, 0x012e, 0x0005, 0x604c,
+	0xa06d, 0x0130, 0x6800, 0xa005, 0x1108, 0x6052, 0x604e, 0xad05,
+	0x0005, 0x6803, 0x0000, 0x6084, 0xa00d, 0x0120, 0x2d00, 0x200a,
+	0x6086, 0x0005, 0x2d00, 0x6086, 0x6082, 0x0cd8, 0x0126, 0x00c6,
+	0x0026, 0x2091, 0x8000, 0x6218, 0x2260, 0x6200, 0xa005, 0x0110,
+	0xc285, 0x0008, 0xc284, 0x6202, 0x002e, 0x00ce, 0x012e, 0x0005,
+	0x0126, 0x00c6, 0x2091, 0x8000, 0x6218, 0x2260, 0x6204, 0x0006,
+	0xa086, 0x0006, 0x1180, 0x609c, 0xd0ac, 0x0168, 0x2001, 0xad52,
+	0x2004, 0xd0a4, 0x0140, 0xa284, 0xff00, 0x8007, 0xa086, 0x0007,
+	0x1110, 0x2011, 0x0600, 0x000e, 0xa294, 0xff00, 0xa215, 0x6206,
+	0x0006, 0xa086, 0x0006, 0x1128, 0x6290, 0x82ff, 0x1110, 0x080c,
+	0x14f6, 0x000e, 0x00ce, 0x012e, 0x0005, 0x0126, 0x00c6, 0x2091,
+	0x8000, 0x6218, 0x2260, 0x6204, 0x0006, 0xa086, 0x0006, 0x1178,
+	0x609c, 0xd0a4, 0x0160, 0x2001, 0xad52, 0x2004, 0xd0ac, 0x1138,
+	0xa284, 0x00ff, 0xa086, 0x0007, 0x1110, 0x2011, 0x0006, 0x000e,
+	0xa294, 0x00ff, 0x8007, 0xa215, 0x6206, 0x00ce, 0x012e, 0x0005,
+	0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001, 0x00b0, 0xa190,
+	0xae34, 0x2204, 0xa065, 0x1180, 0x0016, 0x00d6, 0x080c, 0x15c0,
+	0x2d60, 0x00de, 0x001e, 0x0d80, 0x2c00, 0x2012, 0x60a7, 0x0000,
+	0x60ab, 0x0000, 0x080c, 0x493a, 0xa006, 0x002e, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x0026, 0xa182, 0x00ff, 0x0218, 0xa085, 0x0001,
+	0x0480, 0x00d6, 0xa190, 0xae34, 0x2204, 0xa06d, 0x0540, 0x2013,
+	0x0000, 0x00d6, 0x00c6, 0x2d60, 0x60a4, 0xa06d, 0x0110, 0x080c,
+	0x15f0, 0x60a8, 0xa06d, 0x0110, 0x080c, 0x15f0, 0x00ce, 0x00de,
+	0x00d6, 0x00c6, 0x68ac, 0x2060, 0x8cff, 0x0168, 0x600c, 0x0006,
+	0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0x1600, 0x080c,
+	0x8078, 0x00ce, 0x0c88, 0x00ce, 0x00de, 0x080c, 0x15f0, 0x00de,
+	0xa006, 0x002e, 0x012e, 0x0005, 0x0016, 0xa182, 0x00ff, 0x0218,
+	0xa085, 0x0001, 0x0030, 0xa188, 0xae34, 0x2104, 0xa065, 0x0dc0,
+	0xa006, 0x001e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x600b,
+	0x0000, 0x600f, 0x0000, 0x6000, 0xc08c, 0x6002, 0x080c, 0x574f,
+	0x1538, 0x60a0, 0xa086, 0x007e, 0x2069, 0xb290, 0x0130, 0x2001,
+	0xad34, 0x2004, 0xd0ac, 0x11e0, 0x0098, 0x2d04, 0xd0e4, 0x01c0,
+	0x00d6, 0x2069, 0xb28e, 0x00c6, 0x2061, 0xaf9f, 0x6810, 0x2062,
+	0x6814, 0x6006, 0x6818, 0x600a, 0x681c, 0x600e, 0x00ce, 0x00de,
+	0x8d69, 0x2d04, 0x2069, 0x0140, 0x6886, 0x2069, 0xad00, 0x68a2,
+	0x2069, 0xb28e, 0x6808, 0x605e, 0x6810, 0x6062, 0x6138, 0xa10a,
+	0x0208, 0x603a, 0x6814, 0x6066, 0x2099, 0xb296, 0xac88, 0x000a,
+	0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2099, 0xb29a, 0xac88, 0x0006,
+	0x21a0, 0x20a9, 0x0004, 0x53a3, 0x2069, 0xb2ae, 0x6808, 0x606a,
+	0x690c, 0x616e, 0x6810, 0x6072, 0x6818, 0x6076, 0xa182, 0x0211,
+	0x1218, 0x2009, 0x0008, 0x0400, 0xa182, 0x0259, 0x1218, 0x2009,
+	0x0007, 0x00d0, 0xa182, 0x02c1, 0x1218, 0x2009, 0x0006, 0x00a0,
+	0xa182, 0x0349, 0x1218, 0x2009, 0x0005, 0x0070, 0xa182, 0x0421,
+	0x1218, 0x2009, 0x0004, 0x0040, 0xa182, 0x0581, 0x1218, 0x2009,
+	0x0003, 0x0010, 0x2009, 0x0002, 0x6192, 0x014e, 0x013e, 0x015e,
+	0x00de, 0x0005, 0x0016, 0x0026, 0x00e6, 0x2071, 0xb28d, 0x2e04,
+	0x6896, 0x2071, 0xb28e, 0x7004, 0x689a, 0x701c, 0x689e, 0x6a00,
+	0x2009, 0xad71, 0x210c, 0xd0bc, 0x0120, 0xd1ec, 0x0110, 0xc2ad,
+	0x0008, 0xc2ac, 0xd0c4, 0x0120, 0xd1e4, 0x0110, 0xc2bd, 0x0008,
+	0xc2bc, 0x6a02, 0x00ee, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0126,
+	0x2091, 0x8000, 0x60a4, 0xa06d, 0x01c0, 0x6900, 0x81ff, 0x1540,
+	0x6a04, 0xa282, 0x0010, 0x1648, 0xad88, 0x0004, 0x20a9, 0x0010,
+	0x2104, 0xa086, 0xffff, 0x0128, 0x8108, 0x1f04, 0x4da8, 0x080c,
+	0x14f6, 0x260a, 0x8210, 0x6a06, 0x0098, 0x080c, 0x15d9, 0x01a8,
+	0x2d00, 0x60a6, 0x6803, 0x0000, 0xad88, 0x0004, 0x20a9, 0x0010,
+	0x200b, 0xffff, 0x8108, 0x1f04, 0x4dc0, 0x6807, 0x0001, 0x6e12,
+	0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x0126,
+	0x2091, 0x8000, 0x00d6, 0x60a4, 0xa00d, 0x01a0, 0x2168, 0x6800,
+	0xa005, 0x1160, 0x080c, 0x4ef9, 0x1168, 0x200b, 0xffff, 0x6804,
+	0xa08a, 0x0002, 0x0218, 0x8001, 0x6806, 0x0020, 0x080c, 0x15f0,
+	0x60a7, 0x0000, 0x00de, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x4f56, 0x0010, 0x080c, 0x4bc0, 0x080c, 0x4e71, 0x1dd8,
+	0x080c, 0x4e3a, 0x012e, 0x0005, 0x00d6, 0x0126, 0x2091, 0x8000,
+	0x60a8, 0xa06d, 0x01c0, 0x6950, 0x81ff, 0x1540, 0x6a54, 0xa282,
+	0x0010, 0x1670, 0xad88, 0x0018, 0x20a9, 0x0010, 0x2104, 0xa086,
+	0xffff, 0x0128, 0x8108, 0x1f04, 0x4e0e, 0x080c, 0x14f6, 0x260a,
+	0x8210, 0x6a56, 0x0098, 0x080c, 0x15d9, 0x01d0, 0x2d00, 0x60aa,
+	0x6853, 0x0000, 0xad88, 0x0018, 0x20a9, 0x0010, 0x200b, 0xffff,
+	0x8108, 0x1f04, 0x4e26, 0x6857, 0x0001, 0x6e62, 0x0010, 0x080c,
+	0x4c11, 0x0089, 0x1de0, 0xa085, 0x0001, 0x012e, 0x00de, 0x0005,
+	0xa006, 0x0cd8, 0x0126, 0x2091, 0x8000, 0x080c, 0x67c5, 0x012e,
+	0x0005, 0xa01e, 0x0010, 0x2019, 0x0001, 0xa00e, 0x0126, 0x2091,
+	0x8000, 0x604c, 0x2068, 0x6000, 0xd0dc, 0x1170, 0x8dff, 0x01e8,
+	0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406,
+	0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70,
+	0x6a00, 0x604c, 0xad06, 0x1110, 0x624e, 0x0018, 0xa180, 0x0000,
+	0x2202, 0x82ff, 0x1110, 0x6152, 0x8dff, 0x012e, 0x0005, 0xa01e,
+	0x0010, 0x2019, 0x0001, 0xa00e, 0x6080, 0x2068, 0x8dff, 0x01e8,
+	0x83ff, 0x0120, 0x6848, 0xa606, 0x0158, 0x0030, 0x683c, 0xa406,
+	0x1118, 0x6840, 0xa506, 0x0120, 0x2d08, 0x6800, 0x2068, 0x0c70,
+	0x6a00, 0x6080, 0xad06, 0x1110, 0x6282, 0x0018, 0xa180, 0x0000,
+	0x2202, 0x82ff, 0x1110, 0x6186, 0x8dff, 0x0005, 0xa016, 0x080c,
+	0x4ef3, 0x1110, 0x2011, 0x0001, 0x080c, 0x4f3d, 0x1110, 0xa295,
+	0x0002, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c, 0x964b, 0x0010,
+	0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c, 0x95e4,
+	0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118, 0x080c,
+	0x962e, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e, 0x0118,
+	0x080c, 0x9600, 0x0010, 0xa085, 0x0001, 0x0005, 0x080c, 0x4f6e,
+	0x0118, 0x080c, 0x9667, 0x0010, 0xa085, 0x0001, 0x0005, 0x0126,
+	0x0006, 0x00d6, 0x2091, 0x8000, 0x6080, 0xa06d, 0x01a0, 0x6800,
+	0x0006, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd,
+	0x0006, 0x6000, 0xd0fc, 0x0110, 0x080c, 0xac03, 0x000e, 0x080c,
+	0x510c, 0x000e, 0x0c50, 0x6083, 0x0000, 0x6087, 0x0000, 0x00de,
+	0x000e, 0x012e, 0x0005, 0x60a4, 0xa00d, 0x1118, 0xa085, 0x0001,
+	0x0005, 0x00e6, 0x2170, 0x7000, 0xa005, 0x1160, 0x20a9, 0x0010,
+	0xae88, 0x0004, 0x2104, 0xa606, 0x0128, 0x8108, 0x1f04, 0x4f02,
+	0xa085, 0x0001, 0xa006, 0x00ee, 0x0005, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x60a4, 0xa06d, 0x1128, 0x080c, 0x15d9, 0x01a0, 0x2d00,
+	0x60a6, 0x6803, 0x0001, 0x6807, 0x0000, 0xad88, 0x0004, 0x20a9,
+	0x0010, 0x200b, 0xffff, 0x8108, 0x1f04, 0x4f21, 0xa085, 0x0001,
+	0x012e, 0x00de, 0x0005, 0xa006, 0x0cd8, 0x00d6, 0x0126, 0x2091,
+	0x8000, 0x60a4, 0xa06d, 0x0130, 0x60a7, 0x0000, 0x080c, 0x15f0,
+	0xa085, 0x0001, 0x012e, 0x00de, 0x0005, 0x60a8, 0xa00d, 0x1118,
+	0xa085, 0x0001, 0x0005, 0x00e6, 0x2170, 0x7050, 0xa005, 0x1160,
+	0x20a9, 0x0010, 0xae88, 0x0018, 0x2104, 0xa606, 0x0128, 0x8108,
+	0x1f04, 0x4f4c, 0xa085, 0x0001, 0x00ee, 0x0005, 0x0126, 0x2091,
+	0x8000, 0x0c19, 0x1188, 0x200b, 0xffff, 0x00d6, 0x60a8, 0x2068,
+	0x6854, 0xa08a, 0x0002, 0x0218, 0x8001, 0x6856, 0x0020, 0x080c,
+	0x15f0, 0x60ab, 0x0000, 0x00de, 0x012e, 0x0005, 0x609c, 0xd0a4,
+	0x0005, 0x00f6, 0x080c, 0x574f, 0x01b0, 0x71b4, 0x81ff, 0x1198,
+	0x71d0, 0xd19c, 0x0180, 0x2001, 0x007e, 0xa080, 0xae34, 0x2004,
+	0xa07d, 0x0148, 0x7804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x1118,
+	0x7800, 0xc0ed, 0x7802, 0x2079, 0xad51, 0x7804, 0xd0a4, 0x01e8,
+	0x0156, 0x00c6, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c,
+	0x4cdc, 0x1168, 0x6004, 0xa084, 0xff00, 0x8007, 0xa096, 0x0004,
+	0x0118, 0xa086, 0x0006, 0x1118, 0x6000, 0xc0ed, 0x6002, 0x001e,
+	0x8108, 0x1f04, 0x4f96, 0x00ce, 0x015e, 0x080c, 0x502d, 0x0120,
+	0x2001, 0xafa2, 0x200c, 0x0038, 0x2079, 0xad51, 0x7804, 0xd0a4,
+	0x0130, 0x2009, 0x07d0, 0x2011, 0x4fc1, 0x080c, 0x6593, 0x00fe,
+	0x0005, 0x2011, 0x4fc1, 0x080c, 0x650d, 0x080c, 0x502d, 0x01f0,
+	0x2001, 0xaeb2, 0x2004, 0xa080, 0x0000, 0x200c, 0xc1ec, 0x2102,
+	0x2001, 0xad52, 0x2004, 0xd0a4, 0x0130, 0x2009, 0x07d0, 0x2011,
+	0x4fc1, 0x080c, 0x6593, 0x00e6, 0x2071, 0xad00, 0x706f, 0x0000,
+	0x7073, 0x0000, 0x080c, 0x28fa, 0x00ee, 0x04b0, 0x0156, 0x00c6,
+	0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x080c, 0x4cdc, 0x1530,
+	0x6000, 0xd0ec, 0x0518, 0x0046, 0x62a0, 0xa294, 0x00ff, 0x8227,
+	0xa006, 0x2009, 0x0029, 0x080c, 0xa96c, 0x6000, 0xc0e5, 0xc0ec,
+	0x6002, 0x6004, 0xa084, 0x00ff, 0xa085, 0x0700, 0x6006, 0x2019,
+	0x0029, 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d,
+	0x2009, 0x0000, 0x080c, 0xa712, 0x007e, 0x004e, 0x001e, 0x8108,
+	0x1f04, 0x4fec, 0x00ce, 0x015e, 0x0005, 0x00c6, 0x6018, 0x2060,
+	0x6000, 0xc0ec, 0x6002, 0x00ce, 0x0005, 0x7818, 0x2004, 0xd0ac,
+	0x0005, 0x7818, 0x2004, 0xd0bc, 0x0005, 0x00f6, 0x2001, 0xaeb2,
+	0x2004, 0xa07d, 0x0110, 0x7800, 0xd0ec, 0x00fe, 0x0005, 0x0126,
+	0x0026, 0x2091, 0x8000, 0x6200, 0xa005, 0x0110, 0xc2fd, 0x0008,
+	0xc2fc, 0x6202, 0x002e, 0x012e, 0x0005, 0x2071, 0xae13, 0x7003,
+	0x0001, 0x7007, 0x0000, 0x7013, 0x0000, 0x7017, 0x0000, 0x701b,
+	0x0000, 0x701f, 0x0000, 0x700b, 0x0000, 0x704b, 0x0001, 0x704f,
+	0x0000, 0x705b, 0x0020, 0x705f, 0x0040, 0x707f, 0x0000, 0x2071,
+	0xaf7c, 0x7003, 0xae13, 0x7007, 0x0000, 0x700b, 0x0000, 0x700f,
+	0xaf5c, 0x7013, 0x0020, 0x7017, 0x0040, 0x7037, 0x0000, 0x0005,
+	0x0016, 0x00e6, 0x2071, 0xaf34, 0xa00e, 0x7186, 0x718a, 0x7097,
+	0x0001, 0x2001, 0xad52, 0x2004, 0xd0fc, 0x1150, 0x2001, 0xad52,
+	0x2004, 0xa00e, 0xd09c, 0x0108, 0x8108, 0x7102, 0x0804, 0x50d6,
+	0x2001, 0xad71, 0x200c, 0xa184, 0x000f, 0x2009, 0xad72, 0x210c,
+	0x0002, 0x507e, 0x50b1, 0x50b8, 0x50c2, 0x50c7, 0x507e, 0x507e,
+	0x507e, 0x50a1, 0x507e, 0x507e, 0x507e, 0x507e, 0x507e, 0x507e,
+	0x507e, 0x7003, 0x0004, 0x0136, 0x0146, 0x0156, 0x2099, 0xad75,
+	0x20a1, 0xaf85, 0x20a9, 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e,
+	0x0428, 0x708f, 0x0005, 0x7007, 0x0122, 0x2001, 0x0002, 0x0030,
+	0x708f, 0x0002, 0x7007, 0x0121, 0x2001, 0x0003, 0x7002, 0x7097,
+	0x0001, 0x0088, 0x7007, 0x0122, 0x2001, 0x0002, 0x0020, 0x7007,
+	0x0121, 0x2001, 0x0003, 0x7002, 0xa006, 0x7096, 0x708e, 0xa184,
+	0xff00, 0x8007, 0x709a, 0xa184, 0x00ff, 0x7092, 0x00ee, 0x001e,
+	0x0005, 0x00e6, 0x2071, 0xae13, 0x684c, 0xa005, 0x1130, 0x7028,
+	0xc085, 0x702a, 0xa085, 0x0001, 0x0428, 0x6a60, 0x7236, 0x6b64,
+	0x733a, 0x6868, 0x703e, 0x7076, 0x686c, 0x7042, 0x707a, 0x684c,
+	0x702e, 0x6844, 0x7032, 0x2009, 0x000d, 0x200a, 0x700b, 0x0000,
+	0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0, 0xa210,
+	0x2100, 0xa319, 0x726e, 0x7372, 0x7028, 0xc084, 0x702a, 0x7007,
+	0x0001, 0xa006, 0x00ee, 0x0005, 0x0156, 0x00e6, 0x0026, 0x6838,
+	0xd0fc, 0x1904, 0x5165, 0x6804, 0xa00d, 0x0188, 0x00d6, 0x2071,
+	0xad00, 0xa016, 0x702c, 0x2168, 0x6904, 0x206a, 0x8210, 0x2d00,
+	0x81ff, 0x1dc8, 0x702e, 0x70b0, 0xa200, 0x70b2, 0x00de, 0x2071,
+	0xae13, 0x701c, 0xa005, 0x1904, 0x5175, 0x20a9, 0x0032, 0x0f04,
+	0x5173, 0x0e04, 0x512f, 0x2071, 0xaf34, 0x7200, 0x82ff, 0x05d8,
+	0x6934, 0xa186, 0x0103, 0x1904, 0x5183, 0x6948, 0x6844, 0xa105,
+	0x1540, 0x2009, 0x8020, 0x2200, 0x0002, 0x5173, 0x514a, 0x519b,
+	0x51a7, 0x5173, 0x2071, 0x0000, 0x20a9, 0x0032, 0x0f04, 0x5173,
+	0x7018, 0xd084, 0x1dd8, 0x7122, 0x683c, 0x7026, 0x6840, 0x702a,
+	0x701b, 0x0001, 0x2091, 0x4080, 0x2071, 0xad00, 0x702c, 0x206a,
+	0x2d00, 0x702e, 0x70b0, 0x8000, 0x70b2, 0x002e, 0x00ee, 0x015e,
+	0x0005, 0x6844, 0xa086, 0x0100, 0x1130, 0x6868, 0xa005, 0x1118,
+	0x2009, 0x8020, 0x0880, 0x2071, 0xae13, 0x2d08, 0x206b, 0x0000,
+	0x7010, 0x8000, 0x7012, 0x7018, 0xa06d, 0x711a, 0x0110, 0x6902,
+	0x0008, 0x711e, 0x0c10, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130,
+	0xa186, 0x001e, 0x0118, 0xa18e, 0x001f, 0x1d28, 0x684c, 0xd0cc,
+	0x0d10, 0x6850, 0xa084, 0x00ff, 0xa086, 0x0001, 0x19e0, 0x2009,
+	0x8021, 0x0804, 0x5143, 0x7084, 0x8008, 0xa092, 0x001e, 0x1a98,
+	0x7186, 0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x0078, 0x7084,
+	0x8008, 0xa092, 0x000f, 0x1a38, 0x7186, 0xae90, 0x0003, 0x8003,
+	0xa210, 0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7088, 0xa10a,
+	0x0a04, 0x515c, 0x718c, 0x7084, 0xa10a, 0x0a04, 0x515c, 0x2071,
+	0x0000, 0x7018, 0xd084, 0x1904, 0x515c, 0x2071, 0xaf34, 0x7000,
+	0xa086, 0x0002, 0x1150, 0x080c, 0x5426, 0x2071, 0x0000, 0x701b,
+	0x0001, 0x2091, 0x4080, 0x0804, 0x515c, 0x080c, 0x5450, 0x2071,
+	0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x0804, 0x515c, 0x0006,
+	0x684c, 0x0006, 0x6837, 0x0103, 0x20a9, 0x001c, 0xad80, 0x0011,
+	0x20a0, 0x2001, 0x0000, 0x40a4, 0x000e, 0xa084, 0x00ff, 0x684e,
+	0x000e, 0x684a, 0x6952, 0x0005, 0x2071, 0xae13, 0x7004, 0x0002,
+	0x5202, 0x5213, 0x5411, 0x5412, 0x541f, 0x5425, 0x5203, 0x5402,
+	0x5398, 0x53ee, 0x0005, 0x0126, 0x2091, 0x8000, 0x0e04, 0x5212,
+	0x2009, 0x000d, 0x7030, 0x200a, 0x2091, 0x4080, 0x7007, 0x0001,
+	0x700b, 0x0000, 0x012e, 0x2069, 0xafda, 0x683c, 0xa005, 0x03f8,
+	0x11f0, 0x0126, 0x2091, 0x8000, 0x2069, 0x0000, 0x6934, 0x2001,
+	0xae1f, 0x2004, 0xa10a, 0x0170, 0x0e04, 0x5236, 0x2069, 0x0000,
+	0x6818, 0xd084, 0x1158, 0x2009, 0x8040, 0x6922, 0x681b, 0x0001,
+	0x2091, 0x4080, 0x2069, 0xafda, 0x683f, 0xffff, 0x012e, 0x2069,
+	0xad00, 0x6844, 0x6964, 0xa102, 0x2069, 0xaf34, 0x688a, 0x6984,
+	0x701c, 0xa06d, 0x0120, 0x81ff, 0x0904, 0x528c, 0x00a0, 0x81ff,
+	0x0904, 0x5352, 0x2071, 0xaf34, 0x7184, 0x7088, 0xa10a, 0x1258,
+	0x7190, 0x2071, 0xafda, 0x7038, 0xa005, 0x0128, 0x1b04, 0x5352,
+	0x713a, 0x0804, 0x5352, 0x2071, 0xaf34, 0x718c, 0x0126, 0x2091,
+	0x8000, 0x7084, 0xa10a, 0x0a04, 0x536d, 0x0e04, 0x530e, 0x2071,
+	0x0000, 0x7018, 0xd084, 0x1904, 0x530e, 0x2001, 0xffff, 0x2071,
+	0xafda, 0x703a, 0x2071, 0xaf34, 0x7000, 0xa086, 0x0002, 0x1150,
+	0x080c, 0x5426, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x0804, 0x530e, 0x080c, 0x5450, 0x2071, 0x0000, 0x701b, 0x0001,
+	0x2091, 0x4080, 0x0804, 0x530e, 0x2071, 0xaf34, 0x7000, 0xa005,
+	0x0904, 0x5334, 0x6934, 0xa186, 0x0103, 0x1904, 0x5311, 0x684c,
+	0xd0bc, 0x1904, 0x5334, 0x6948, 0x6844, 0xa105, 0x1904, 0x5329,
+	0x2009, 0x8020, 0x2071, 0xaf34, 0x7000, 0x0002, 0x5334, 0x52f4,
+	0x52cc, 0x52de, 0x52ab, 0x0136, 0x0146, 0x0156, 0x2099, 0xad75,
+	0x20a1, 0xaf85, 0x20a9, 0x0004, 0x53a3, 0x015e, 0x014e, 0x013e,
+	0x2071, 0xaf7c, 0xad80, 0x000f, 0x700e, 0x7013, 0x0002, 0x7007,
+	0x0002, 0x700b, 0x0000, 0x2e10, 0x080c, 0x1624, 0x2071, 0xae13,
+	0x7007, 0x0009, 0x0804, 0x5352, 0x7084, 0x8008, 0xa092, 0x001e,
+	0x1a04, 0x5352, 0xae90, 0x0003, 0xa210, 0x683c, 0x2012, 0x7186,
+	0x2071, 0xae13, 0x080c, 0x54a7, 0x0804, 0x5352, 0x7084, 0x8008,
+	0xa092, 0x000f, 0x1a04, 0x5352, 0xae90, 0x0003, 0x8003, 0xa210,
+	0x683c, 0x2012, 0x8210, 0x6840, 0x2012, 0x7186, 0x2071, 0xae13,
+	0x080c, 0x54a7, 0x0804, 0x5352, 0x0126, 0x2091, 0x8000, 0x0e04,
+	0x530e, 0x2071, 0x0000, 0x7018, 0xd084, 0x1180, 0x7122, 0x683c,
+	0x7026, 0x6840, 0x702a, 0x701b, 0x0001, 0x2091, 0x4080, 0x012e,
+	0x2071, 0xae13, 0x080c, 0x54a7, 0x0804, 0x5352, 0x012e, 0x0804,
+	0x5352, 0xa18c, 0x00ff, 0xa186, 0x0017, 0x0130, 0xa186, 0x001e,
+	0x0118, 0xa18e, 0x001f, 0x11c0, 0x684c, 0xd0cc, 0x01a8, 0x6850,
+	0xa084, 0x00ff, 0xa086, 0x0001, 0x1178, 0x2009, 0x8021, 0x0804,
+	0x52a2, 0x6844, 0xa086, 0x0100, 0x1138, 0x6868, 0xa005, 0x1120,
+	0x2009, 0x8020, 0x0804, 0x52a2, 0x2071, 0xae13, 0x080c, 0x54b9,
+	0x01c8, 0x2071, 0xae13, 0x700f, 0x0001, 0x6934, 0xa184, 0x00ff,
+	0xa086, 0x0003, 0x1130, 0x810f, 0xa18c, 0x00ff, 0x8101, 0x0108,
+	0x710e, 0x7007, 0x0003, 0x080c, 0x54d2, 0x7050, 0xa086, 0x0100,
+	0x0904, 0x5412, 0x0126, 0x2091, 0x8000, 0x2071, 0xae13, 0x7008,
+	0xa086, 0x0001, 0x1180, 0x0e04, 0x536b, 0x2009, 0x000d, 0x7030,
+	0x200a, 0x2091, 0x4080, 0x700b, 0x0000, 0x7004, 0xa086, 0x0006,
+	0x1110, 0x7007, 0x0001, 0x012e, 0x0005, 0x2071, 0xae13, 0x080c,
+	0x54b9, 0x0518, 0x2071, 0xaf34, 0x7084, 0x700a, 0x20a9, 0x0020,
+	0x2099, 0xaf35, 0x20a1, 0xaf5c, 0x53a3, 0x7087, 0x0000, 0x2071,
+	0xae13, 0x2069, 0xaf7c, 0x706c, 0x6826, 0x7070, 0x682a, 0x7074,
+	0x682e, 0x7078, 0x6832, 0x2d10, 0x080c, 0x1624, 0x7007, 0x0008,
+	0x2001, 0xffff, 0x2071, 0xafda, 0x703a, 0x012e, 0x0804, 0x5352,
+	0x2069, 0xaf7c, 0x6808, 0xa08e, 0x0000, 0x0904, 0x53ed, 0xa08e,
+	0x0200, 0x0904, 0x53eb, 0xa08e, 0x0100, 0x1904, 0x53ed, 0x0126,
+	0x2091, 0x8000, 0x0e04, 0x53e9, 0x2069, 0x0000, 0x6818, 0xd084,
+	0x15c0, 0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034,
+	0x706e, 0x7038, 0x7072, 0x0048, 0x706c, 0xa080, 0x0040, 0x706e,
+	0x1220, 0x7070, 0xa081, 0x0000, 0x7072, 0x7132, 0x6936, 0x700b,
+	0x0000, 0x2001, 0xaf59, 0x2004, 0xa005, 0x1190, 0x6934, 0x2069,
+	0xaf34, 0x689c, 0x699e, 0x2069, 0xafda, 0xa102, 0x1118, 0x683c,
+	0xa005, 0x1368, 0x2001, 0xaf5a, 0x200c, 0x810d, 0x693e, 0x0038,
+	0x2009, 0x8040, 0x6922, 0x681b, 0x0001, 0x2091, 0x4080, 0x7007,
+	0x0001, 0x012e, 0x0010, 0x7007, 0x0005, 0x0005, 0x2001, 0xaf7e,
+	0x2004, 0xa08e, 0x0100, 0x1128, 0x7007, 0x0001, 0x080c, 0x54a7,
+	0x0005, 0xa08e, 0x0000, 0x0de0, 0xa08e, 0x0200, 0x1dc8, 0x7007,
+	0x0005, 0x0005, 0x701c, 0xa06d, 0x0158, 0x080c, 0x54b9, 0x0140,
+	0x7007, 0x0003, 0x080c, 0x54d2, 0x7050, 0xa086, 0x0100, 0x0110,
+	0x0005, 0x0005, 0x7050, 0xa09e, 0x0100, 0x1118, 0x7007, 0x0004,
+	0x0030, 0xa086, 0x0200, 0x1110, 0x7007, 0x0005, 0x0005, 0x080c,
+	0x5475, 0x7006, 0x080c, 0x54a7, 0x0005, 0x0005, 0x00e6, 0x0156,
+	0x2071, 0xaf34, 0x7184, 0x81ff, 0x0500, 0xa006, 0x7086, 0xae80,
+	0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226, 0x8000, 0x0f04,
+	0x544a, 0x2014, 0x722a, 0x8000, 0x0f04, 0x544a, 0x2014, 0x722e,
+	0x8000, 0x0f04, 0x544a, 0x2014, 0x723a, 0x8000, 0x0f04, 0x544a,
+	0x2014, 0x723e, 0xa180, 0x8030, 0x7022, 0x015e, 0x00ee, 0x0005,
+	0x00e6, 0x0156, 0x2071, 0xaf34, 0x7184, 0x81ff, 0x01d8, 0xa006,
+	0x7086, 0xae80, 0x0003, 0x2071, 0x0000, 0x21a8, 0x2014, 0x7226,
+	0x8000, 0x2014, 0x722a, 0x8000, 0x0f04, 0x546c, 0x2014, 0x723a,
+	0x8000, 0x2014, 0x723e, 0x0018, 0x2001, 0x8020, 0x0010, 0x2001,
+	0x8042, 0x7022, 0x015e, 0x00ee, 0x0005, 0x702c, 0x7130, 0x8108,
+	0xa102, 0x0230, 0xa00e, 0x7034, 0x706e, 0x7038, 0x7072, 0x0048,
+	0x706c, 0xa080, 0x0040, 0x706e, 0x1220, 0x7070, 0xa081, 0x0000,
+	0x7072, 0x7132, 0x700c, 0x8001, 0x700e, 0x1180, 0x0126, 0x2091,
+	0x8000, 0x0e04, 0x54a1, 0x2001, 0x000d, 0x2102, 0x2091, 0x4080,
+	0x2001, 0x0001, 0x700b, 0x0000, 0x012e, 0x0005, 0x2001, 0x0007,
+	0x0005, 0x2001, 0x0006, 0x700b, 0x0001, 0x012e, 0x0005, 0x701c,
+	0xa06d, 0x0170, 0x0126, 0x2091, 0x8000, 0x7010, 0x8001, 0x7012,
+	0x2d04, 0x701e, 0xa005, 0x1108, 0x701a, 0x012e, 0x080c, 0x15f0,
+	0x0005, 0x2019, 0x000d, 0x2304, 0x230c, 0xa10e, 0x0130, 0x2304,
+	0x230c, 0xa10e, 0x0110, 0xa006, 0x0060, 0x732c, 0x8319, 0x7130,
+	0xa102, 0x1118, 0x2300, 0xa005, 0x0020, 0x0210, 0xa302, 0x0008,
+	0x8002, 0x0005, 0x2d00, 0x7026, 0xa080, 0x000d, 0x7056, 0x7053,
+	0x0000, 0x0126, 0x2091, 0x8000, 0x2009, 0xafec, 0x2104, 0xc08d,
+	0x200a, 0x012e, 0x080c, 0x163c, 0x0005, 0x7088, 0xa08a, 0x0029,
+	0x1220, 0xa082, 0x001d, 0x0033, 0x0010, 0x080c, 0x14f6, 0x6027,
+	0x1e00, 0x0005, 0x55c1, 0x555b, 0x5571, 0x5595, 0x55b4, 0x55e6,
+	0x55f8, 0x5571, 0x55d2, 0x54ff, 0x552d, 0x54fe, 0x0005, 0x00d6,
+	0x2069, 0x0200, 0x6804, 0xa005, 0x1180, 0x6808, 0xa005, 0x1518,
+	0x708b, 0x0028, 0x2069, 0xafac, 0x2d04, 0x7002, 0x080c, 0x584d,
+	0x6028, 0xa085, 0x0600, 0x602a, 0x00b0, 0x708b, 0x0028, 0x2069,
+	0xafac, 0x2d04, 0x7002, 0x6028, 0xa085, 0x0600, 0x602a, 0x00e6,
+	0x0036, 0x0046, 0x0056, 0x2071, 0xaffd, 0x080c, 0x1d22, 0x005e,
+	0x004e, 0x003e, 0x00ee, 0x00de, 0x0005, 0x00d6, 0x2069, 0x0200,
+	0x6804, 0xa005, 0x1180, 0x6808, 0xa005, 0x1518, 0x708b, 0x0028,
+	0x2069, 0xafac, 0x2d04, 0x7002, 0x080c, 0x58da, 0x6028, 0xa085,
+	0x0600, 0x602a, 0x00b0, 0x708b, 0x0028, 0x2069, 0xafac, 0x2d04,
+	0x7002, 0x6028, 0xa085, 0x0600, 0x602a, 0x00e6, 0x0036, 0x0046,
+	0x0056, 0x2071, 0xaffd, 0x080c, 0x1d22, 0x005e, 0x004e, 0x003e,
+	0x00ee, 0x00de, 0x0005, 0x6803, 0x0090, 0x6124, 0xd1e4, 0x1180,
+	0x080c, 0x5663, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1cc, 0x0140,
+	0x708b, 0x0020, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f,
+	0x0005, 0x6803, 0x0088, 0x6124, 0xd1cc, 0x11c8, 0xd1dc, 0x11a0,
+	0xd1e4, 0x1178, 0xa184, 0x1e00, 0x11b8, 0x60e3, 0x0001, 0x600c,
+	0xc0b4, 0x600e, 0x080c, 0x577f, 0x6803, 0x0080, 0x708b, 0x0028,
+	0x0058, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d, 0x0028, 0x708b,
+	0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x60e3, 0x0001, 0x600c,
+	0xc0b4, 0x600e, 0x080c, 0x577f, 0x6803, 0x0080, 0x6124, 0xd1d4,
+	0x1180, 0xd1dc, 0x1158, 0xd1e4, 0x1130, 0xa184, 0x1e00, 0x1158,
+	0x708b, 0x0028, 0x0040, 0x708b, 0x001e, 0x0028, 0x708b, 0x001d,
+	0x0010, 0x708b, 0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1dc,
+	0x1128, 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b, 0x001d,
+	0x0005, 0x080c, 0x568d, 0x6124, 0xd1dc, 0x1158, 0x080c, 0x5663,
+	0xd1d4, 0x1128, 0xd1e4, 0x0128, 0x708b, 0x001e, 0x0010, 0x708b,
+	0x001f, 0x0005, 0x6803, 0x00a0, 0x6124, 0xd1d4, 0x1160, 0xd1cc,
+	0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b, 0x001e, 0x0028,
+	0x708b, 0x001d, 0x0010, 0x708b, 0x0021, 0x0005, 0x080c, 0x568d,
+	0x6124, 0xd1d4, 0x1150, 0xd1dc, 0x1128, 0xd1e4, 0x0140, 0x708b,
+	0x001e, 0x0028, 0x708b, 0x001d, 0x0010, 0x708b, 0x001f, 0x0005,
+	0x6803, 0x0090, 0x6124, 0xd1d4, 0x1178, 0xd1cc, 0x1150, 0xd1dc,
+	0x1128, 0xd1e4, 0x0158, 0x708b, 0x001e, 0x0040, 0x708b, 0x001d,
+	0x0028, 0x708b, 0x0020, 0x0010, 0x708b, 0x001f, 0x0005, 0x0016,
+	0x00c6, 0x00d6, 0x00e6, 0x0126, 0x2061, 0x0100, 0x2069, 0x0140,
+	0x2071, 0xad00, 0x2091, 0x8000, 0x080c, 0x574f, 0x11e8, 0x2001,
+	0xad0c, 0x200c, 0xd1b4, 0x01c0, 0xc1b4, 0x2102, 0x6027, 0x0200,
+	0xe000, 0xe000, 0x6024, 0xd0cc, 0x0158, 0x6803, 0x00a0, 0x2001,
+	0xaf9e, 0x2003, 0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x0428,
+	0x6028, 0xc0cd, 0x602a, 0x0408, 0x080c, 0x576b, 0x0150, 0x080c,
+	0x5761, 0x1138, 0x2001, 0x0001, 0x080c, 0x261e, 0x080c, 0x5726,
+	0x00a0, 0x080c, 0x568a, 0x0178, 0x2001, 0x0001, 0x080c, 0x261e,
+	0x7088, 0xa086, 0x001e, 0x0120, 0x7088, 0xa086, 0x0022, 0x1118,
+	0x708b, 0x0025, 0x0010, 0x708b, 0x0021, 0x012e, 0x00ee, 0x00de,
+	0x00ce, 0x001e, 0x0005, 0x0016, 0x0026, 0x2009, 0x0064, 0x2011,
+	0x566e, 0x080c, 0x6501, 0x002e, 0x001e, 0x0005, 0x00e6, 0x00f6,
+	0x0016, 0x080c, 0x7834, 0x2071, 0xad00, 0x080c, 0x560f, 0x001e,
+	0x00fe, 0x00ee, 0x0005, 0x2001, 0xad00, 0x2004, 0xa086, 0x0004,
+	0x0140, 0x2001, 0xaf9d, 0x2003, 0xaaaa, 0x2001, 0xaf9e, 0x2003,
+	0x0000, 0x0005, 0x6020, 0xd09c, 0x0005, 0x6803, 0x00c0, 0x0156,
+	0x20a9, 0x002d, 0x1d04, 0x5692, 0x2091, 0x6000, 0x1f04, 0x5692,
+	0x015e, 0x0005, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x2071, 0xad00, 0x2001, 0xaf9e, 0x200c, 0xa186, 0x0000,
+	0x0158, 0xa186, 0x0001, 0x0158, 0xa186, 0x0002, 0x0158, 0xa186,
+	0x0003, 0x0158, 0x0804, 0x5714, 0x708b, 0x0022, 0x0040, 0x708b,
+	0x0021, 0x0028, 0x708b, 0x0023, 0x0020, 0x708b, 0x0024, 0x6043,
+	0x0000, 0x60e3, 0x0000, 0x6887, 0x0001, 0x2001, 0x0001, 0x080c,
+	0x26cb, 0x0026, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002,
+	0x080c, 0x7ae9, 0x002e, 0x7000, 0xa08e, 0x0004, 0x0118, 0x602b,
+	0x0028, 0x0010, 0x602b, 0x0020, 0x0156, 0x0126, 0x2091, 0x8000,
+	0x20a9, 0x0005, 0x6024, 0xd0ac, 0x0118, 0x012e, 0x015e, 0x04d0,
+	0x6800, 0xa084, 0x00a0, 0xc0bd, 0x6802, 0x6904, 0xd1d4, 0x1130,
+	0x6803, 0x0100, 0x1f04, 0x56e2, 0x080c, 0x57a0, 0x012e, 0x015e,
+	0x080c, 0x5761, 0x01a8, 0x6044, 0xa005, 0x0168, 0x6050, 0x0006,
+	0xa085, 0x0020, 0x6052, 0x080c, 0x57a0, 0xa006, 0x8001, 0x1df0,
+	0x000e, 0x6052, 0x0028, 0x6804, 0xd0d4, 0x1110, 0x080c, 0x57a0,
+	0x2001, 0xaf9e, 0x2003, 0x0004, 0x080c, 0x54e5, 0x080c, 0x5761,
+	0x0148, 0x6804, 0xd0d4, 0x1130, 0xd0dc, 0x1100, 0x2001, 0xaf9e,
+	0x2003, 0x0000, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xad00, 0x2001,
+	0xaf9d, 0x2003, 0x0000, 0x2001, 0xaf8e, 0x2003, 0x0000, 0x708b,
+	0x0000, 0x60e3, 0x0000, 0x6887, 0x0000, 0x2001, 0x0000, 0x080c,
+	0x26cb, 0x6803, 0x0000, 0x6043, 0x0090, 0x6043, 0x0010, 0x6027,
+	0xffff, 0x602b, 0x182f, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0006,
+	0x2001, 0xaf9d, 0x2004, 0xa086, 0xaaaa, 0x000e, 0x0005, 0x0006,
+	0x2001, 0xad71, 0x2004, 0xa084, 0x0030, 0xa086, 0x0000, 0x000e,
+	0x0005, 0x0006, 0x2001, 0xad71, 0x2004, 0xa084, 0x0030, 0xa086,
+	0x0030, 0x000e, 0x0005, 0x0006, 0x2001, 0xad71, 0x2004, 0xa084,
+	0x0030, 0xa086, 0x0010, 0x000e, 0x0005, 0x0006, 0x2001, 0xad71,
+	0x2004, 0xa084, 0x0030, 0xa086, 0x0020, 0x000e, 0x0005, 0x2001,
+	0xad0c, 0x2004, 0xd0a4, 0x0170, 0x080c, 0x26eb, 0x0036, 0x0016,
+	0x2009, 0x0000, 0x2019, 0x0028, 0x080c, 0x2aac, 0x001e, 0x003e,
+	0xa006, 0x0009, 0x0005, 0x00e6, 0x2071, 0xad0c, 0x2e04, 0x0118,
+	0xa085, 0x0010, 0x0010, 0xa084, 0xffef, 0x2072, 0x00ee, 0x0005,
+	0x6050, 0x0006, 0x60f0, 0x0006, 0x60ec, 0x0006, 0x600c, 0x0006,
+	0x6004, 0x0006, 0x6028, 0x0006, 0x602f, 0x0100, 0x602f, 0x0000,
+	0x602f, 0x0040, 0x602f, 0x0000, 0x000e, 0x602a, 0x000e, 0x6006,
+	0x000e, 0x600e, 0x000e, 0x60ee, 0x000e, 0x60f2, 0x60e3, 0x0000,
+	0x6887, 0x0001, 0x2001, 0x0001, 0x080c, 0x26cb, 0x6800, 0xa084,
+	0x00a0, 0xc0bd, 0x6802, 0x6803, 0x00a0, 0x000e, 0x6052, 0x6050,
+	0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6, 0x00e6,
+	0x2061, 0x0100, 0x2069, 0x0140, 0x2071, 0xad00, 0x6020, 0xa084,
+	0x0080, 0x0138, 0x2001, 0xad0c, 0x200c, 0xc1bd, 0x2102, 0x0804,
+	0x5845, 0x2001, 0xad0c, 0x200c, 0xc1bc, 0x2102, 0x6028, 0xa084,
+	0xe1ff, 0x602a, 0x6027, 0x0200, 0x6803, 0x0090, 0x20a9, 0x0384,
+	0x6024, 0xd0cc, 0x1518, 0x1d04, 0x57f8, 0x2091, 0x6000, 0x1f04,
+	0x57f8, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c,
+	0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c,
+	0x7a64, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001,
+	0xad00, 0x2003, 0x0001, 0xa085, 0x0001, 0x0438, 0x60e3, 0x0000,
+	0x2001, 0xaf8e, 0x2004, 0x080c, 0x26cb, 0x60e2, 0x6803, 0x0080,
+	0x20a9, 0x0384, 0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024,
+	0xa10c, 0x0138, 0x1d04, 0x582a, 0x2091, 0x6000, 0x1f04, 0x582a,
+	0x0840, 0x6028, 0xa085, 0x1e00, 0x602a, 0x70a0, 0xa005, 0x1118,
+	0x6887, 0x0001, 0x0008, 0x6886, 0xa006, 0x00ee, 0x00de, 0x00ce,
+	0x003e, 0x002e, 0x001e, 0x015e, 0x0005, 0x0156, 0x0016, 0x0026,
+	0x0036, 0x00c6, 0x00d6, 0x00e6, 0x2061, 0x0100, 0x2071, 0xad00,
+	0x2069, 0x0140, 0x6020, 0xa084, 0x00c0, 0x0120, 0x6884, 0xa005,
+	0x1904, 0x58a1, 0x6803, 0x0088, 0x60e3, 0x0000, 0x6887, 0x0000,
+	0x2001, 0x0000, 0x080c, 0x26cb, 0x2069, 0x0200, 0x6804, 0xa005,
+	0x1118, 0x6808, 0xa005, 0x01c0, 0x6028, 0xa084, 0xfbff, 0x602a,
+	0x6027, 0x0400, 0x2069, 0xafac, 0x7000, 0x206a, 0x708b, 0x0026,
+	0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x5884, 0x2091, 0x6000,
+	0x1f04, 0x5884, 0x0804, 0x58d2, 0x2069, 0x0140, 0x20a9, 0x0384,
+	0x6027, 0x1e00, 0x2009, 0x1e00, 0xe000, 0x6024, 0xa10c, 0x0530,
+	0xa084, 0x1a00, 0x1518, 0x1d04, 0x5890, 0x2091, 0x6000, 0x1f04,
+	0x5890, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c,
+	0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c,
+	0x7a64, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003, 0x0001, 0x2001,
+	0xad00, 0x2003, 0x0001, 0xa085, 0x0001, 0x00a0, 0x6803, 0x0080,
+	0x2069, 0x0140, 0x60e3, 0x0000, 0x70a0, 0xa005, 0x1118, 0x6887,
+	0x0001, 0x0008, 0x6886, 0x2001, 0xaf8e, 0x2004, 0x080c, 0x26cb,
+	0x60e2, 0xa006, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x00c6, 0x00d6,
+	0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, 0x6020, 0xa084, 0x00c0,
+	0x01f0, 0x2011, 0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c,
+	0x7ae9, 0x080c, 0x79e1, 0x080c, 0x6581, 0x2019, 0x0000, 0x080c,
+	0x7a64, 0x2069, 0x0140, 0x6803, 0x00a0, 0x2001, 0xaf9e, 0x2003,
+	0x0001, 0x2001, 0xad00, 0x2003, 0x0001, 0x0804, 0x5972, 0x2001,
+	0xad0c, 0x200c, 0xd1b4, 0x1150, 0xc1b5, 0x2102, 0x080c, 0x5663,
+	0x2069, 0x0140, 0x6803, 0x0080, 0x60e3, 0x0000, 0x2069, 0x0200,
+	0x6804, 0xa005, 0x1118, 0x6808, 0xa005, 0x01b8, 0x6028, 0xa084,
+	0xfdff, 0x602a, 0x6027, 0x0200, 0x2069, 0xafac, 0x7000, 0x206a,
+	0x708b, 0x0027, 0x7003, 0x0001, 0x20a9, 0x0002, 0x1d04, 0x592e,
+	0x2091, 0x6000, 0x1f04, 0x592e, 0x04e8, 0x6027, 0x1e00, 0x2009,
+	0x1e00, 0xe000, 0x6024, 0xa10c, 0x01c8, 0xa084, 0x1c00, 0x11b0,
+	0x1d04, 0x5935, 0x0006, 0x0016, 0x00c6, 0x00d6, 0x00e6, 0x080c,
+	0x64a2, 0x00ee, 0x00de, 0x00ce, 0x001e, 0x000e, 0x00e6, 0x2071,
+	0xafda, 0x7018, 0x00ee, 0xa005, 0x1d00, 0x01e0, 0x0026, 0x2011,
+	0x566e, 0x080c, 0x650d, 0x002e, 0x2069, 0x0140, 0x60e3, 0x0000,
+	0x70a0, 0xa005, 0x1118, 0x6887, 0x0001, 0x0008, 0x6886, 0x2001,
+	0xaf8e, 0x2004, 0x080c, 0x26cb, 0x60e2, 0x2001, 0xad0c, 0x200c,
+	0xc1b4, 0x2102, 0x00ee, 0x00de, 0x00ce, 0x003e, 0x002e, 0x001e,
+	0x015e, 0x0005, 0x0156, 0x0016, 0x0026, 0x0036, 0x0046, 0x00c6,
+	0x00e6, 0x2061, 0x0100, 0x2071, 0xad00, 0x7130, 0xd184, 0x1180,
+	0x2011, 0xad52, 0x2214, 0xd2ec, 0x0138, 0xc18d, 0x7132, 0x2011,
+	0xad52, 0x2214, 0xd2ac, 0x1120, 0x7030, 0xd08c, 0x0904, 0x59df,
+	0x7130, 0xc185, 0x7132, 0x2011, 0xad52, 0x220c, 0xd1a4, 0x0530,
+	0x0016, 0x2009, 0x0001, 0x2011, 0x0100, 0x080c, 0x663f, 0x2019,
+	0x000e, 0x080c, 0xa8eb, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000,
+	0xa186, 0x007e, 0x0170, 0xa186, 0x0080, 0x0158, 0x080c, 0x4cdc,
+	0x1140, 0x8127, 0xa006, 0x0016, 0x2009, 0x000e, 0x080c, 0xa96c,
+	0x001e, 0x8108, 0x1f04, 0x59b0, 0x015e, 0x001e, 0xd1ac, 0x1148,
+	0x0016, 0x2009, 0x0000, 0x2019, 0x0004, 0x080c, 0x2aac, 0x001e,
+	0x0070, 0x0156, 0x20a9, 0x007f, 0x2009, 0x0000, 0x080c, 0x4cdc,
+	0x1110, 0x080c, 0x493a, 0x8108, 0x1f04, 0x59d6, 0x015e, 0x2011,
+	0x0003, 0x080c, 0x7adf, 0x2011, 0x0002, 0x080c, 0x7ae9, 0x080c,
+	0x79e1, 0x080c, 0x6581, 0x0036, 0x2019, 0x0000, 0x080c, 0x7a64,
+	0x003e, 0x60e3, 0x0000, 0x2001, 0xad00, 0x2003, 0x0001, 0x080c,
+	0x569a, 0x00ee, 0x00ce, 0x004e, 0x003e, 0x002e, 0x001e, 0x015e,
+	0x0005, 0x2071, 0xade1, 0x7003, 0x0000, 0x7007, 0x0000, 0x700f,
+	0x0000, 0x702b, 0x0001, 0x704f, 0x0000, 0x7053, 0x0001, 0x705f,
+	0x0020, 0x7063, 0x0040, 0x7083, 0x0000, 0x708b, 0x0000, 0x708f,
+	0x0001, 0x70bf, 0x0000, 0x0005, 0x00e6, 0x2071, 0xade1, 0x6848,
+	0xa005, 0x1130, 0x7028, 0xc085, 0x702a, 0xa085, 0x0001, 0x0428,
+	0x6a50, 0x7236, 0x6b54, 0x733a, 0x6858, 0x703e, 0x707a, 0x685c,
+	0x7042, 0x707e, 0x6848, 0x702e, 0x6840, 0x7032, 0x2009, 0x000c,
+	0x200a, 0x8007, 0x8006, 0x8006, 0xa08c, 0x003f, 0xa084, 0xffc0,
+	0xa210, 0x2100, 0xa319, 0x7272, 0x7376, 0x7028, 0xc084, 0x702a,
+	0x7007, 0x0001, 0x700f, 0x0000, 0xa006, 0x00ee, 0x0005, 0x2b78,
+	0x2071, 0xade1, 0x7004, 0x0043, 0x700c, 0x0002, 0x5a5b, 0x5a52,
+	0x5a52, 0x5a52, 0x5a52, 0x0005, 0x5ab1, 0x5ab2, 0x5ae4, 0x5ae5,
+	0x5aaf, 0x5b33, 0x5b38, 0x5b69, 0x5b6a, 0x5b85, 0x5b86, 0x5b87,
+	0x5b88, 0x5b89, 0x5b8a, 0x5c40, 0x5c67, 0x700c, 0x0002, 0x5a74,
+	0x5aaf, 0x5aaf, 0x5ab0, 0x5ab0, 0x7830, 0x7930, 0xa106, 0x0120,
+	0x7830, 0x7930, 0xa106, 0x1510, 0x7030, 0xa10a, 0x01f8, 0x1210,
+	0x712c, 0xa10a, 0xa18a, 0x0002, 0x12d0, 0x080c, 0x15c0, 0x01b0,
+	0x2d00, 0x705a, 0x7063, 0x0040, 0x2001, 0x0003, 0x7057, 0x0000,
+	0x0126, 0x0006, 0x2091, 0x8000, 0x2009, 0xafec, 0x2104, 0xc085,
+	0x200a, 0x000e, 0x700e, 0x012e, 0x080c, 0x163c, 0x0005, 0x080c,
+	0x15c0, 0x0de0, 0x2d00, 0x705a, 0x080c, 0x15c0, 0x1108, 0x0c10,
+	0x2d00, 0x7086, 0x7063, 0x0080, 0x2001, 0x0004, 0x08f8, 0x0005,
+	0x0005, 0x0005, 0x700c, 0x0002, 0x5ab9, 0x5abc, 0x5aca, 0x5ae3,
+	0x5ae3, 0x080c, 0x5a6d, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058,
+	0x0006, 0x080c, 0x5f90, 0x0120, 0x2091, 0x8000, 0x080c, 0x5a6d,
+	0x00de, 0x0048, 0x0126, 0x8001, 0x700e, 0x080c, 0x5f90, 0x7058,
+	0x2068, 0x7084, 0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834,
+	0xa084, 0x00ff, 0xa08a, 0x003a, 0x1218, 0x00db, 0x012e, 0x0005,
+	0x012e, 0x080c, 0x5b8b, 0x0005, 0x0005, 0x0005, 0x00e6, 0x2071,
+	0xade1, 0x700c, 0x0002, 0x5af0, 0x5af0, 0x5af0, 0x5af2, 0x5af5,
+	0x00ee, 0x0005, 0x700f, 0x0001, 0x0010, 0x700f, 0x0002, 0x00ee,
+	0x0005, 0x5b8b, 0x5b8b, 0x5ba7, 0x5b8b, 0x5d22, 0x5b8b, 0x5b8b,
+	0x5b8b, 0x5b8b, 0x5b8b, 0x5ba7, 0x5d64, 0x5da7, 0x5df0, 0x5e04,
+	0x5b8b, 0x5b8b, 0x5bc3, 0x5ba7, 0x5b8b, 0x5b8b, 0x5c1d, 0x5ead,
+	0x5ec8, 0x5b8b, 0x5bc3, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5c13,
+	0x5ec8, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b,
+	0x5b8b, 0x5b8b, 0x5bd7, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b,
+	0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b, 0x5b8b,
+	0x5b8b, 0x5b8b, 0x5bec, 0x7020, 0x2068, 0x080c, 0x15f0, 0x0005,
+	0x700c, 0x0002, 0x5b3f, 0x5b42, 0x5b50, 0x5b68, 0x5b68, 0x080c,
+	0x5a6d, 0x0005, 0x0126, 0x8001, 0x700e, 0x7058, 0x0006, 0x080c,
+	0x5f90, 0x0120, 0x2091, 0x8000, 0x080c, 0x5a6d, 0x00de, 0x0048,
+	0x0126, 0x8001, 0x700e, 0x080c, 0x5f90, 0x7058, 0x2068, 0x7084,
+	0x705a, 0x6803, 0x0000, 0x6807, 0x0000, 0x6834, 0xa084, 0x00ff,
+	0xa08a, 0x001a, 0x1218, 0x003b, 0x012e, 0x0005, 0x012e, 0x0419,
+	0x0005, 0x0005, 0x0005, 0x5b8b, 0x5ba7, 0x5d0e, 0x5b8b, 0x5ba7,
+	0x5b8b, 0x5ba7, 0x5ba7, 0x5b8b, 0x5ba7, 0x5d0e, 0x5ba7, 0x5ba7,
+	0x5ba7, 0x5ba7, 0x5ba7, 0x5b8b, 0x5ba7, 0x5d0e, 0x5b8b, 0x5b8b,
+	0x5ba7, 0x5b8b, 0x5b8b, 0x5b8b, 0x5ba7, 0x0005, 0x0005, 0x0005,
+	0x0005, 0x0005, 0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff,
+	0xc0d5, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c, 0x510c, 0x012e,
+	0x0005, 0x7007, 0x0001, 0x6838, 0xa084, 0x00ff, 0xc0e5, 0x683a,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x7007,
+	0x0001, 0x6838, 0xa084, 0x00ff, 0xc0ed, 0x683a, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x7007, 0x0001, 0x6838,
+	0xa084, 0x00ff, 0xc0dd, 0x683a, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x510c, 0x012e, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff, 0x0988,
+	0x8001, 0x1120, 0x7007, 0x0001, 0x0804, 0x5cd0, 0x7007, 0x0006,
+	0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5cd0, 0x0005, 0x6834,
+	0x8007, 0xa084, 0x00ff, 0x0904, 0x5b99, 0x8001, 0x1120, 0x7007,
+	0x0001, 0x0804, 0x5ced, 0x7007, 0x0006, 0x7012, 0x2d00, 0x7016,
+	0x701a, 0x704b, 0x5ced, 0x0005, 0x6834, 0x8007, 0xa084, 0x00ff,
+	0xa086, 0x0001, 0x1904, 0x5b99, 0x7007, 0x0001, 0x2009, 0xad30,
+	0x210c, 0x81ff, 0x11a8, 0x6838, 0xa084, 0x00ff, 0x683a, 0x6853,
+	0x0000, 0x080c, 0x4ab1, 0x1108, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x6837, 0x0139, 0x684a, 0x6952, 0x080c, 0x510c, 0x012e, 0x0ca0,
+	0x2001, 0x0028, 0x0c90, 0x684c, 0xa084, 0x00c0, 0xa086, 0x00c0,
+	0x1120, 0x7007, 0x0001, 0x0804, 0x5ee0, 0x2d00, 0x7016, 0x701a,
+	0x20a9, 0x0004, 0xa080, 0x0024, 0x2098, 0x20a1, 0xae0c, 0x53a3,
+	0x6858, 0x7012, 0xa082, 0x0401, 0x1a04, 0x5bb5, 0x6a84, 0xa28a,
+	0x0002, 0x1a04, 0x5bb5, 0x82ff, 0x1138, 0x6888, 0x698c, 0xa105,
+	0x0118, 0x2001, 0x5ca3, 0x0018, 0xa280, 0x5c99, 0x2005, 0x70c6,
+	0x7010, 0xa015, 0x0904, 0x5c85, 0x080c, 0x15c0, 0x1118, 0x7007,
+	0x000f, 0x0005, 0x2d00, 0x7022, 0x70c4, 0x2060, 0x2c05, 0x6836,
+	0xe004, 0xad00, 0x7096, 0xe008, 0xa20a, 0x1210, 0xa00e, 0x2200,
+	0x7112, 0xe20c, 0x8003, 0x800b, 0xa296, 0x0004, 0x0108, 0xa108,
+	0x719a, 0x810b, 0x719e, 0xae90, 0x0022, 0x080c, 0x1624, 0x7090,
+	0xa08e, 0x0100, 0x0170, 0xa086, 0x0200, 0x0118, 0x7007, 0x0010,
+	0x0005, 0x7020, 0x2068, 0x080c, 0x15f0, 0x7014, 0x2068, 0x0804,
+	0x5bb5, 0x7020, 0x2068, 0x7018, 0x6802, 0x6807, 0x0000, 0x2d08,
+	0x2068, 0x6906, 0x711a, 0x0804, 0x5c40, 0x7014, 0x2068, 0x7007,
+	0x0001, 0x6884, 0xa005, 0x1128, 0x6888, 0x698c, 0xa105, 0x0108,
+	0x00b1, 0x6834, 0xa084, 0x00ff, 0xa086, 0x001e, 0x0904, 0x5ee0,
+	0x04b8, 0x5c9b, 0x5c9f, 0x0002, 0x0011, 0x0007, 0x0004, 0x000a,
+	0x000f, 0x0005, 0x0006, 0x000a, 0x0011, 0x0005, 0x0004, 0x00f6,
+	0x00e6, 0x00c6, 0x0076, 0x0066, 0x6f88, 0x6e8c, 0x6804, 0x2060,
+	0xacf0, 0x0021, 0xacf8, 0x0027, 0x2009, 0x0005, 0x700c, 0x7816,
+	0x7008, 0x7812, 0x7004, 0x7806, 0x7000, 0x7802, 0x7e0e, 0x7f0a,
+	0x8109, 0x0128, 0xaef2, 0x0004, 0xaffa, 0x0006, 0x0c78, 0x6004,
+	0xa065, 0x1d30, 0x006e, 0x007e, 0x00ce, 0x00ee, 0x00fe, 0x0005,
+	0x2009, 0xad30, 0x210c, 0x81ff, 0x1198, 0x6838, 0xa084, 0x00ff,
+	0x683a, 0x080c, 0x4993, 0x1108, 0x0005, 0x080c, 0x51df, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x97fd, 0x080c, 0x510c, 0x012e, 0x0ca0,
+	0x2001, 0x0028, 0x2009, 0x0000, 0x0c80, 0x2009, 0xad30, 0x210c,
+	0x81ff, 0x11b0, 0x6858, 0xa005, 0x01b0, 0x6838, 0xa084, 0x00ff,
+	0x683a, 0x6853, 0x0000, 0x080c, 0x4a55, 0x1108, 0x0005, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x51df, 0x080c, 0x510c, 0x012e, 0x0cb0,
+	0x2001, 0x0028, 0x0ca0, 0x2001, 0x0000, 0x0c88, 0x7018, 0x6802,
+	0x2d08, 0x2068, 0x6906, 0x711a, 0x7010, 0x8001, 0x7012, 0x0118,
+	0x7007, 0x0006, 0x0030, 0x7014, 0x2068, 0x7007, 0x0001, 0x7048,
+	0x080f, 0x0005, 0x7007, 0x0001, 0x6944, 0x810f, 0xa18c, 0x00ff,
+	0x6848, 0xa084, 0x00ff, 0x20a9, 0x0001, 0xa096, 0x0001, 0x01b0,
+	0x2009, 0x0000, 0x20a9, 0x00ff, 0xa096, 0x0002, 0x0178, 0xa005,
+	0x11f0, 0x6944, 0x810f, 0xa18c, 0x00ff, 0x080c, 0x4cdc, 0x11b8,
+	0x0066, 0x6e50, 0x080c, 0x4dcf, 0x006e, 0x0088, 0x0046, 0x2011,
+	0xad0c, 0x2224, 0xc484, 0x2412, 0x004e, 0x00c6, 0x080c, 0x4cdc,
+	0x1110, 0x080c, 0x4f2d, 0x8108, 0x1f04, 0x5d4e, 0x00ce, 0x684c,
+	0xd084, 0x1118, 0x080c, 0x15f0, 0x0005, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x510c, 0x012e, 0x0005, 0x0126, 0x2091, 0x8000, 0x7007,
+	0x0001, 0x2001, 0xad52, 0x2004, 0xd0a4, 0x0580, 0x2061, 0xb048,
+	0x6100, 0xd184, 0x0178, 0x6858, 0xa084, 0x00ff, 0x1550, 0x6000,
+	0xd084, 0x0520, 0x6004, 0xa005, 0x1538, 0x6003, 0x0000, 0x600b,
+	0x0000, 0x00c8, 0x2011, 0x0001, 0x6860, 0xa005, 0x1110, 0x2001,
+	0x001e, 0x8000, 0x6016, 0x6858, 0xa084, 0x00ff, 0x0178, 0x6006,
+	0x6858, 0x8007, 0xa084, 0x00ff, 0x0148, 0x600a, 0x6858, 0x8000,
+	0x1108, 0xc28d, 0x6202, 0x012e, 0x0804, 0x5f7f, 0x012e, 0x0804,
+	0x5f79, 0x012e, 0x0804, 0x5f73, 0x012e, 0x0804, 0x5f76, 0x0126,
+	0x2091, 0x8000, 0x7007, 0x0001, 0x2001, 0xad52, 0x2004, 0xd0a4,
+	0x05e0, 0x2061, 0xb048, 0x6000, 0xd084, 0x05b8, 0x6204, 0x6308,
+	0xd08c, 0x1530, 0x6c48, 0xa484, 0x0003, 0x0170, 0x6958, 0xa18c,
+	0x00ff, 0x8001, 0x1120, 0x2100, 0xa210, 0x0620, 0x0028, 0x8001,
+	0x1508, 0x2100, 0xa212, 0x02f0, 0xa484, 0x000c, 0x0188, 0x6958,
+	0x810f, 0xa18c, 0x00ff, 0xa082, 0x0004, 0x1120, 0x2100, 0xa318,
+	0x0288, 0x0030, 0xa082, 0x0004, 0x1168, 0x2100, 0xa31a, 0x0250,
+	0x6860, 0xa005, 0x0110, 0x8000, 0x6016, 0x6206, 0x630a, 0x012e,
+	0x0804, 0x5f7f, 0x012e, 0x0804, 0x5f7c, 0x012e, 0x0804, 0x5f79,
+	0x0126, 0x2091, 0x8000, 0x7007, 0x0001, 0x2061, 0xb048, 0x6300,
+	0xd38c, 0x1120, 0x6308, 0x8318, 0x0220, 0x630a, 0x012e, 0x0804,
+	0x5f8d, 0x012e, 0x0804, 0x5f7c, 0x0126, 0x00c6, 0x2091, 0x8000,
+	0x7007, 0x0001, 0x684c, 0xd0ac, 0x0148, 0x00c6, 0x2061, 0xb048,
+	0x6000, 0xa084, 0xfcff, 0x6002, 0x00ce, 0x0448, 0x6858, 0xa005,
+	0x05d0, 0x685c, 0xa065, 0x0598, 0x2001, 0xad30, 0x2004, 0xa005,
+	0x0118, 0x080c, 0x974e, 0x0068, 0x6013, 0x0400, 0x6057, 0x0000,
+	0x694c, 0xd1a4, 0x0110, 0x6950, 0x6156, 0x2009, 0x0041, 0x080c,
+	0x80a7, 0x6958, 0xa18c, 0xff00, 0xa186, 0x2000, 0x1140, 0x0026,
+	0x2009, 0x0000, 0x2011, 0xfdff, 0x080c, 0x663f, 0x002e, 0x684c,
+	0xd0c4, 0x0148, 0x2061, 0xb048, 0x6000, 0xd08c, 0x1120, 0x6008,
+	0x8000, 0x0208, 0x600a, 0x00ce, 0x012e, 0x0804, 0x5f7f, 0x00ce,
+	0x012e, 0x0804, 0x5f79, 0x6954, 0xa186, 0x002e, 0x0d40, 0xa186,
+	0x002d, 0x0d28, 0xa186, 0x0045, 0x0510, 0xa186, 0x002a, 0x1130,
+	0x2001, 0xad0c, 0x200c, 0xc194, 0x2102, 0x08c8, 0xa186, 0x0020,
+	0x0170, 0xa186, 0x0029, 0x1d18, 0x6944, 0xa18c, 0xff00, 0x810f,
+	0x080c, 0x4cdc, 0x1960, 0x6000, 0xc0e4, 0x6002, 0x0840, 0x685c,
+	0xa065, 0x09a8, 0x2001, 0xafa3, 0x2004, 0x6016, 0x0800, 0x685c,
+	0xa065, 0x0968, 0x00e6, 0x6860, 0xa075, 0x2001, 0xad30, 0x2004,
+	0xa005, 0x0150, 0x080c, 0x974e, 0x8eff, 0x0118, 0x2e60, 0x080c,
+	0x974e, 0x00ee, 0x0804, 0x5e3f, 0x6020, 0xc0dc, 0xc0d5, 0x6022,
+	0x2e60, 0x6007, 0x003a, 0x6870, 0xa005, 0x0130, 0x6007, 0x003b,
+	0x6874, 0x602a, 0x6878, 0x6012, 0x6003, 0x0001, 0x080c, 0x67a8,
+	0x080c, 0x6c50, 0x00ee, 0x0804, 0x5e3f, 0x2061, 0xb048, 0x6000,
+	0xd084, 0x0190, 0xd08c, 0x1904, 0x5f8d, 0x0126, 0x2091, 0x8000,
+	0x6204, 0x8210, 0x0220, 0x6206, 0x012e, 0x0804, 0x5f8d, 0x012e,
+	0x6853, 0x0016, 0x0804, 0x5f86, 0x6853, 0x0007, 0x0804, 0x5f86,
+	0x6834, 0x8007, 0xa084, 0x00ff, 0x1118, 0x080c, 0x5b99, 0x0078,
+	0x2030, 0x8001, 0x1120, 0x7007, 0x0001, 0x0051, 0x0040, 0x7007,
+	0x0006, 0x7012, 0x2d00, 0x7016, 0x701a, 0x704b, 0x5ee0, 0x0005,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x2009, 0xad30, 0x210c, 0x81ff,
+	0x1904, 0x5f5b, 0x2009, 0xad0c, 0x210c, 0xd194, 0x1904, 0x5f63,
+	0x6848, 0x2070, 0xae82, 0xb400, 0x0a04, 0x5f4f, 0x2001, 0xad16,
+	0x2004, 0xae02, 0x1a04, 0x5f4f, 0x2061, 0xb048, 0x6100, 0xa184,
+	0x0301, 0xa086, 0x0001, 0x15a8, 0x711c, 0xa186, 0x0006, 0x15b0,
+	0x7018, 0xa005, 0x0904, 0x5f5b, 0x2004, 0xd0e4, 0x1904, 0x5f5e,
+	0x7020, 0xd0dc, 0x1904, 0x5f66, 0x6853, 0x0000, 0x6803, 0x0000,
+	0x2d08, 0x7010, 0xa005, 0x1158, 0x7112, 0x684c, 0xd0f4, 0x1904,
+	0x5f69, 0x2e60, 0x080c, 0x65aa, 0x012e, 0x00ee, 0x0005, 0x2068,
+	0x6800, 0xa005, 0x1de0, 0x6902, 0x2168, 0x684c, 0xd0f4, 0x15c8,
+	0x012e, 0x00ee, 0x0005, 0x012e, 0x00ee, 0x6853, 0x0006, 0x0804,
+	0x5f86, 0xd184, 0x0dc0, 0xd1c4, 0x11a8, 0x00b8, 0x6944, 0xa18c,
+	0xff00, 0x810f, 0x080c, 0x4cdc, 0x11c8, 0x6000, 0xd0e4, 0x11b0,
+	0x711c, 0xa186, 0x0007, 0x1118, 0x6853, 0x0002, 0x0088, 0x6853,
+	0x0008, 0x0070, 0x6853, 0x000e, 0x0058, 0x6853, 0x0017, 0x0040,
+	0x6853, 0x0035, 0x0028, 0x6853, 0x0028, 0x0010, 0x6853, 0x0029,
+	0x012e, 0x00ee, 0x0418, 0x6853, 0x002a, 0x0cd0, 0x6853, 0x0045,
+	0x0cb8, 0x2e60, 0x2019, 0x0002, 0x6017, 0x0014, 0x080c, 0xa566,
+	0x012e, 0x00ee, 0x0005, 0x2009, 0x003e, 0x0058, 0x2009, 0x0004,
+	0x0040, 0x2009, 0x0006, 0x0028, 0x2009, 0x0016, 0x0010, 0x2009,
+	0x0001, 0x6854, 0xa084, 0xff00, 0xa105, 0x6856, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x510c, 0x012e, 0x0005, 0x080c, 0x15f0, 0x0005,
+	0x702c, 0x7130, 0x8108, 0xa102, 0x0230, 0xa00e, 0x7034, 0x7072,
+	0x7038, 0x7076, 0x0058, 0x7070, 0xa080, 0x0040, 0x7072, 0x1230,
+	0x7074, 0xa081, 0x0000, 0x7076, 0xa085, 0x0001, 0x7932, 0x7132,
+	0x0005, 0x00d6, 0x080c, 0x65a1, 0x00de, 0x0005, 0x00d6, 0x2011,
+	0x0004, 0x2204, 0xa085, 0x8002, 0x2012, 0x00de, 0x0005, 0x20e1,
+	0x0002, 0x3d08, 0x20e1, 0x2000, 0x3d00, 0xa084, 0x7000, 0x0118,
+	0xa086, 0x1000, 0x1540, 0x20e1, 0x0000, 0x3d00, 0xa094, 0xff00,
+	0x8217, 0xa084, 0xf000, 0xa086, 0x3000, 0x1118, 0x080c, 0x61c6,
+	0x00b0, 0x20e1, 0x0004, 0x3d60, 0xd1bc, 0x1108, 0x3e60, 0xac84,
+	0x0007, 0x1188, 0xac82, 0xb400, 0x0270, 0x6858, 0xac02, 0x1258,
+	0x6120, 0xd1f4, 0x1160, 0x2009, 0x0047, 0x080c, 0x80a7, 0x7a1c,
+	0xd284, 0x1968, 0x0005, 0xa016, 0x080c, 0x1824, 0x0cc0, 0x0cd8,
+	0x781c, 0xd08c, 0x0500, 0x0156, 0x0136, 0x0146, 0x20e1, 0x3000,
+	0x3d20, 0x3e28, 0xa584, 0x0076, 0x1530, 0xa484, 0x7000, 0xa086,
+	0x1000, 0x11a8, 0x080c, 0x604e, 0x01f0, 0x20e1, 0x3000, 0x7828,
+	0x7828, 0x080c, 0x606a, 0x014e, 0x013e, 0x015e, 0x2009, 0xafcf,
+	0x2104, 0xa005, 0x1108, 0x0005, 0x080c, 0x6c50, 0x0ce0, 0xa484,
+	0x7000, 0x1518, 0x0499, 0x01b8, 0x7000, 0xa084, 0xff00, 0xa086,
+	0x8100, 0x0d18, 0x0080, 0xd5a4, 0x0158, 0x080c, 0x1d86, 0x20e1,
+	0x9010, 0x2001, 0x0160, 0x2502, 0x2001, 0x0138, 0x2202, 0x0048,
+	0x00e9, 0x6883, 0x0000, 0x080c, 0xac59, 0x20e1, 0x3000, 0x7828,
+	0x7828, 0x014e, 0x013e, 0x015e, 0x08b0, 0x0081, 0x1130, 0x7000,
+	0xa084, 0xff00, 0xa086, 0x8100, 0x1d70, 0x080c, 0xac59, 0x20e1,
+	0x3000, 0x7828, 0x7828, 0x080c, 0x642d, 0x0c58, 0xa484, 0x01ff,
+	0x6882, 0xa005, 0x0160, 0xa080, 0x001f, 0xa084, 0x03f8, 0x80ac,
+	0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0x0005, 0x20a9,
+	0x000c, 0x20e1, 0x1000, 0x2ea0, 0x2099, 0x020a, 0x53a5, 0xa085,
+	0x0001, 0x0ca0, 0x7000, 0xa084, 0xff00, 0xa08c, 0xf000, 0x8007,
+	0xa196, 0x0000, 0x1118, 0x0804, 0x62cf, 0x0005, 0xa196, 0x2000,
+	0x1148, 0x6900, 0xa18e, 0x0001, 0x1118, 0x080c, 0x41d1, 0x0ca8,
+	0x0039, 0x0c98, 0xa196, 0x8000, 0x1d80, 0x080c, 0x6372, 0x0c68,
+	0x00c6, 0x6a80, 0x82ff, 0x0904, 0x61c0, 0x7110, 0xa18c, 0xff00,
+	0x810f, 0xa196, 0x0001, 0x0120, 0xa196, 0x0023, 0x1904, 0x61c0,
+	0xa08e, 0x0023, 0x1570, 0x080c, 0x6408, 0x0904, 0x61c0, 0x7124,
+	0x610a, 0x7030, 0xa08e, 0x0200, 0x1150, 0x7034, 0xa005, 0x1904,
+	0x61c0, 0x2009, 0x0015, 0x080c, 0x80a7, 0x0804, 0x61c0, 0xa08e,
+	0x0214, 0x0118, 0xa08e, 0x0210, 0x1130, 0x2009, 0x0015, 0x080c,
+	0x80a7, 0x0804, 0x61c0, 0xa08e, 0x0100, 0x1904, 0x61c0, 0x7034,
+	0xa005, 0x1904, 0x61c0, 0x2009, 0x0016, 0x080c, 0x80a7, 0x0804,
+	0x61c0, 0xa08e, 0x0022, 0x1904, 0x61c0, 0x7030, 0xa08e, 0x0300,
+	0x1580, 0x68d0, 0xd0a4, 0x0528, 0xc0b5, 0x68d2, 0x7100, 0xa18c,
+	0x00ff, 0x696e, 0x7004, 0x6872, 0x00f6, 0x2079, 0x0100, 0x79e6,
+	0x78ea, 0x0006, 0xa084, 0x00ff, 0x0016, 0x2008, 0x080c, 0x26a0,
+	0x7932, 0x7936, 0x001e, 0x000e, 0x00fe, 0x080c, 0x2676, 0x694e,
+	0x703c, 0x00e6, 0x2071, 0x0140, 0x7086, 0x2071, 0xad00, 0x70a2,
+	0x00ee, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0017, 0x0804,
+	0x6193, 0xa08e, 0x0400, 0x1158, 0x7034, 0xa005, 0x1904, 0x61c0,
+	0x68d0, 0xc0a5, 0x68d2, 0x2009, 0x0030, 0x0804, 0x6193, 0xa08e,
+	0x0500, 0x1140, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0018,
+	0x0804, 0x6193, 0xa08e, 0x2010, 0x1120, 0x2009, 0x0019, 0x0804,
+	0x6193, 0xa08e, 0x2110, 0x1120, 0x2009, 0x001a, 0x0804, 0x6193,
+	0xa08e, 0x5200, 0x1140, 0x7034, 0xa005, 0x1904, 0x61c0, 0x2009,
+	0x001b, 0x0804, 0x6193, 0xa08e, 0x5000, 0x1140, 0x7034, 0xa005,
+	0x1904, 0x61c0, 0x2009, 0x001c, 0x0804, 0x6193, 0xa08e, 0x1300,
+	0x1120, 0x2009, 0x0034, 0x0804, 0x6193, 0xa08e, 0x1200, 0x1140,
+	0x7034, 0xa005, 0x1904, 0x61c0, 0x2009, 0x0024, 0x0804, 0x6193,
+	0xa08c, 0xff00, 0xa18e, 0x2400, 0x1118, 0x2009, 0x002d, 0x04d8,
+	0xa08c, 0xff00, 0xa18e, 0x5300, 0x1118, 0x2009, 0x002a, 0x0498,
+	0xa08e, 0x0f00, 0x1118, 0x2009, 0x0020, 0x0468, 0xa08e, 0x5300,
+	0x1108, 0x00d8, 0xa08e, 0x6104, 0x11c0, 0x2011, 0xb28d, 0x8208,
+	0x2204, 0xa082, 0x0004, 0x20a8, 0x95ac, 0x95ac, 0x2011, 0x8015,
+	0x211c, 0x8108, 0x0046, 0x2124, 0x080c, 0x3c5c, 0x004e, 0x8108,
+	0x1f04, 0x6176, 0x2009, 0x0023, 0x0070, 0xa08e, 0x6000, 0x1118,
+	0x2009, 0x003f, 0x0040, 0xa08e, 0x7800, 0x1118, 0x2009, 0x0045,
+	0x0010, 0x2009, 0x001d, 0x0016, 0x2011, 0xb283, 0x2204, 0x8211,
+	0x220c, 0x080c, 0x2676, 0x1530, 0x080c, 0x4c80, 0x1518, 0x6612,
+	0x6516, 0x86ff, 0x0180, 0x001e, 0x0016, 0xa186, 0x0017, 0x1158,
+	0x686c, 0xa606, 0x1140, 0x6870, 0xa506, 0xa084, 0xff00, 0x1118,
+	0x6000, 0xc0f5, 0x6002, 0x00c6, 0x080c, 0x8022, 0x0168, 0x001e,
+	0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c, 0x80a7,
+	0x00ce, 0x0005, 0x001e, 0x0ce0, 0x00ce, 0x0ce0, 0x00c6, 0x0046,
+	0x080c, 0x6221, 0x1904, 0x621e, 0xa184, 0xff00, 0x8007, 0xa086,
+	0x0008, 0x1904, 0x621e, 0xa28e, 0x0033, 0x11e8, 0x080c, 0x6408,
+	0x0904, 0x621e, 0x7124, 0x610a, 0x7030, 0xa08e, 0x0200, 0x1140,
+	0x7034, 0xa005, 0x15d8, 0x2009, 0x0015, 0x080c, 0x80a7, 0x04b0,
+	0xa08e, 0x0100, 0x1598, 0x7034, 0xa005, 0x1580, 0x2009, 0x0016,
+	0x080c, 0x80a7, 0x0458, 0xa28e, 0x0032, 0x1540, 0x7030, 0xa08e,
+	0x1400, 0x1520, 0x2009, 0x0038, 0x0016, 0x2011, 0xb283, 0x2204,
+	0x8211, 0x220c, 0x080c, 0x2676, 0x11c0, 0x080c, 0x4c80, 0x11a8,
+	0x6612, 0x6516, 0x00c6, 0x080c, 0x8022, 0x0170, 0x001e, 0x611a,
+	0x080c, 0x9956, 0x601f, 0x0004, 0x7120, 0x610a, 0x001e, 0x080c,
+	0x80a7, 0x080c, 0x6c50, 0x0010, 0x00ce, 0x001e, 0x004e, 0x00ce,
+	0x0005, 0x00f6, 0x00d6, 0x0026, 0x0016, 0x0136, 0x0146, 0x0156,
+	0x3c00, 0x0006, 0x2079, 0x0030, 0x2069, 0x0200, 0x080c, 0x1df2,
+	0x1590, 0x080c, 0x1ce2, 0x05c8, 0x04d9, 0x1130, 0x7908, 0xa18c,
+	0x1fff, 0xa182, 0x0011, 0x1688, 0x20a9, 0x000c, 0x20e1, 0x0000,
+	0x2ea0, 0x2099, 0x020a, 0x53a5, 0x20e1, 0x2000, 0x2001, 0x020a,
+	0x2004, 0x7a0c, 0x7808, 0xa080, 0x0007, 0xa084, 0x1ff8, 0x0401,
+	0x1120, 0xa08a, 0x0140, 0x1a0c, 0x14f6, 0x80ac, 0x20e1, 0x6000,
+	0x2099, 0x020a, 0x53a5, 0x20e1, 0x7000, 0x6828, 0x6828, 0x7803,
+	0x0004, 0xa294, 0x0070, 0x000e, 0x20e0, 0x015e, 0x014e, 0x013e,
+	0x001e, 0x002e, 0x00de, 0x00fe, 0x0005, 0xa085, 0x0001, 0x0c98,
+	0x0006, 0x2001, 0x0111, 0x2004, 0xa084, 0x0003, 0x000e, 0x0005,
+	0x0046, 0x00e6, 0x00d6, 0x2028, 0x2130, 0xa696, 0x00ff, 0x1198,
+	0xa596, 0xfffd, 0x1120, 0x2009, 0x007f, 0x0804, 0x62ca, 0xa596,
+	0xfffe, 0x1118, 0x2009, 0x007e, 0x04e8, 0xa596, 0xfffc, 0x1118,
+	0x2009, 0x0080, 0x04b8, 0x2011, 0x0000, 0x2019, 0xad34, 0x231c,
+	0xd3ac, 0x0138, 0x2021, 0x0000, 0x20a9, 0x00ff, 0x2071, 0xae34,
+	0x0030, 0x2021, 0x0081, 0x20a9, 0x007e, 0x2071, 0xaeb5, 0x2e1c,
+	0x83ff, 0x1128, 0x82ff, 0x1198, 0x2410, 0xc2fd, 0x0080, 0x2368,
+	0x6f10, 0x0006, 0x2100, 0xa706, 0x000e, 0x6b14, 0x1120, 0xa346,
+	0x1110, 0x2408, 0x0078, 0x87ff, 0x1110, 0x83ff, 0x0d58, 0x8420,
+	0x8e70, 0x1f04, 0x62a7, 0x82ff, 0x1118, 0xa085, 0x0001, 0x0018,
+	0xc2fc, 0x2208, 0xa006, 0x00de, 0x00ee, 0x004e, 0x0005, 0xa084,
+	0x0007, 0x000a, 0x0005, 0x62db, 0x62db, 0x62db, 0x641a, 0x62db,
+	0x62dc, 0x62f1, 0x635d, 0x0005, 0x7110, 0xd1bc, 0x0188, 0x7120,
+	0x2160, 0xac8c, 0x0007, 0x1160, 0xac8a, 0xb400, 0x0248, 0x6858,
+	0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0046, 0x080c, 0x80a7,
+	0x0005, 0x00c6, 0x7110, 0xd1bc, 0x1904, 0x6344, 0x2011, 0xb283,
+	0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x1904, 0x6344, 0x080c,
+	0x4c80, 0x1904, 0x6344, 0x6612, 0x6516, 0x6000, 0xd0ec, 0x15e0,
+	0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006, 0x0160, 0x080c,
+	0x574f, 0x11d0, 0x6204, 0xa294, 0x00ff, 0xa286, 0x0006, 0x11a0,
+	0xa295, 0x0600, 0x6206, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0530,
+	0x611a, 0x601f, 0x0006, 0x7120, 0x610a, 0x7130, 0x6152, 0x2009,
+	0x0044, 0x080c, 0x80a7, 0x00c0, 0x00c6, 0x080c, 0x8022, 0x001e,
+	0x0198, 0x611a, 0x601f, 0x0004, 0x7120, 0x610a, 0xa286, 0x0004,
+	0x1118, 0x6007, 0x0005, 0x0010, 0x6007, 0x0001, 0x6003, 0x0001,
+	0x080c, 0x67ee, 0x080c, 0x6c50, 0x00ce, 0x0005, 0x00c6, 0x080c,
+	0x9807, 0x001e, 0x0dc8, 0x611a, 0x601f, 0x0006, 0x7120, 0x610a,
+	0x7130, 0x6152, 0x6013, 0x0300, 0x6003, 0x0001, 0x6007, 0x0041,
+	0x080c, 0x67a8, 0x080c, 0x6c50, 0x0c38, 0x7110, 0xd1bc, 0x0188,
+	0x7020, 0x2060, 0xac84, 0x0007, 0x1160, 0xac82, 0xb400, 0x0248,
+	0x6858, 0xac02, 0x1230, 0x7124, 0x610a, 0x2009, 0x0045, 0x080c,
+	0x80a7, 0x0005, 0x7110, 0xa18c, 0xff00, 0x810f, 0xa18e, 0x0000,
+	0x1130, 0xa084, 0x000f, 0xa08a, 0x0006, 0x1208, 0x000b, 0x0005,
+	0x6386, 0x6387, 0x6386, 0x6386, 0x63f0, 0x63fc, 0x0005, 0x7110,
+	0xd1bc, 0x0120, 0x702c, 0xd084, 0x0904, 0x63ef, 0x700c, 0x7108,
+	0x080c, 0x2676, 0x1904, 0x63ef, 0x080c, 0x4c80, 0x1904, 0x63ef,
+	0x6612, 0x6516, 0x6204, 0x7110, 0xd1bc, 0x01f8, 0xa28c, 0x00ff,
+	0xa186, 0x0004, 0x0118, 0xa186, 0x0006, 0x15c8, 0x00c6, 0x080c,
+	0x6408, 0x00ce, 0x0904, 0x63ef, 0x00c6, 0x080c, 0x8022, 0x001e,
+	0x05f0, 0x611a, 0x080c, 0x9956, 0x601f, 0x0002, 0x7120, 0x610a,
+	0x2009, 0x0088, 0x080c, 0x80a7, 0x0490, 0xa28c, 0x00ff, 0xa186,
+	0x0006, 0x0160, 0xa186, 0x0004, 0x0148, 0xa294, 0xff00, 0x8217,
+	0xa286, 0x0004, 0x0118, 0xa286, 0x0006, 0x1188, 0x00c6, 0x080c,
+	0x8022, 0x001e, 0x01e0, 0x611a, 0x080c, 0x9956, 0x601f, 0x0005,
+	0x7120, 0x610a, 0x2009, 0x0088, 0x080c, 0x80a7, 0x0080, 0x00c6,
+	0x080c, 0x8022, 0x001e, 0x0158, 0x611a, 0x080c, 0x9956, 0x601f,
+	0x0004, 0x7120, 0x610a, 0x2009, 0x0001, 0x080c, 0x80a7, 0x0005,
+	0x7110, 0xd1bc, 0x0140, 0x00a1, 0x0130, 0x7124, 0x610a, 0x2009,
+	0x0089, 0x080c, 0x80a7, 0x0005, 0x7110, 0xd1bc, 0x0140, 0x0041,
+	0x0130, 0x7124, 0x610a, 0x2009, 0x008a, 0x080c, 0x80a7, 0x0005,
+	0x7020, 0x2060, 0xac84, 0x0007, 0x1158, 0xac82, 0xb400, 0x0240,
+	0x2001, 0xad16, 0x2004, 0xac02, 0x1218, 0xa085, 0x0001, 0x0005,
+	0xa006, 0x0ce8, 0x7110, 0xd1bc, 0x1178, 0x7024, 0x2060, 0xac84,
+	0x0007, 0x1150, 0xac82, 0xb400, 0x0238, 0x6858, 0xac02, 0x1220,
+	0x2009, 0x0051, 0x080c, 0x80a7, 0x0005, 0x2031, 0x0105, 0x0069,
+	0x0005, 0x2031, 0x0206, 0x0049, 0x0005, 0x2031, 0x0207, 0x0029,
+	0x0005, 0x2031, 0x0213, 0x0009, 0x0005, 0x00c6, 0x00d6, 0x00f6,
+	0x7000, 0xa084, 0xf000, 0xa086, 0xc000, 0x05b0, 0x080c, 0x8022,
+	0x0598, 0x0066, 0x00c6, 0x0046, 0x2011, 0xb283, 0x2204, 0x8211,
+	0x220c, 0x080c, 0x2676, 0x1580, 0x080c, 0x4c80, 0x1568, 0x6612,
+	0x6516, 0x2c00, 0x004e, 0x00ce, 0x601a, 0x080c, 0x9956, 0x080c,
+	0x15d9, 0x01f0, 0x2d00, 0x6056, 0x6803, 0x0000, 0x6837, 0x0000,
+	0x6c3a, 0xadf8, 0x000f, 0x20a9, 0x000e, 0x2fa0, 0x2e98, 0x53a3,
+	0x006e, 0x6612, 0x6007, 0x003e, 0x601f, 0x0001, 0x6003, 0x0001,
+	0x080c, 0x67ee, 0x080c, 0x6c50, 0x00fe, 0x00de, 0x00ce, 0x0005,
+	0x080c, 0x8078, 0x006e, 0x0cc0, 0x004e, 0x00ce, 0x0cc8, 0x2071,
+	0xafda, 0x7003, 0x0003, 0x700f, 0x0361, 0xa006, 0x701a, 0x7012,
+	0x7017, 0xb400, 0x7007, 0x0000, 0x7026, 0x702b, 0x7841, 0x7032,
+	0x7037, 0x789d, 0x703b, 0xffff, 0x703f, 0xffff, 0x7042, 0x7047,
+	0x41b3, 0x0005, 0x2071, 0xafda, 0x1d04, 0x64fc, 0x2091, 0x6000,
+	0x700c, 0x8001, 0x700e, 0x1180, 0x700f, 0x0361, 0x7007, 0x0001,
+	0x0126, 0x2091, 0x8000, 0x7040, 0xa00d, 0x0148, 0x8109, 0x7142,
+	0x1130, 0x7044, 0x080f, 0x0018, 0x0126, 0x2091, 0x8000, 0x7024,
+	0xa00d, 0x0188, 0x7020, 0x8001, 0x7022, 0x1168, 0x7023, 0x0009,
+	0x8109, 0x7126, 0xa186, 0x03e8, 0x1110, 0x7028, 0x080f, 0x81ff,
+	0x1110, 0x7028, 0x080f, 0x7030, 0xa00d, 0x0158, 0x702c, 0x8001,
+	0x702e, 0x1138, 0x702f, 0x0009, 0x8109, 0x7132, 0x1110, 0x7034,
+	0x080f, 0x7038, 0xa005, 0x0118, 0x0310, 0x8001, 0x703a, 0x703c,
+	0xa005, 0x0118, 0x0310, 0x8001, 0x703e, 0x7018, 0xa00d, 0x0158,
+	0x7008, 0x8001, 0x700a, 0x1138, 0x700b, 0x0009, 0x8109, 0x711a,
+	0x1110, 0x701c, 0x080f, 0x012e, 0x7004, 0x0002, 0x6522, 0x6523,
+	0x653b, 0x00e6, 0x2071, 0xafda, 0x7018, 0xa005, 0x1120, 0x711a,
+	0x721e, 0x700b, 0x0009, 0x00ee, 0x0005, 0x00e6, 0x0006, 0x2071,
+	0xafda, 0x701c, 0xa206, 0x1110, 0x701a, 0x701e, 0x000e, 0x00ee,
+	0x0005, 0x00e6, 0x2071, 0xafda, 0x6088, 0xa102, 0x0208, 0x618a,
+	0x00ee, 0x0005, 0x0005, 0x7110, 0x080c, 0x4cdc, 0x1158, 0x6088,
+	0x8001, 0x0240, 0x608a, 0x1130, 0x0126, 0x2091, 0x8000, 0x080c,
+	0x6c50, 0x012e, 0x8108, 0xa182, 0x00ff, 0x0218, 0xa00e, 0x7007,
+	0x0002, 0x7112, 0x0005, 0x7014, 0x2060, 0x0126, 0x2091, 0x8000,
+	0x603c, 0xa005, 0x0128, 0x8001, 0x603e, 0x1110, 0x080c, 0x9846,
+	0x6014, 0xa005, 0x0500, 0x8001, 0x6016, 0x11e8, 0x611c, 0xa186,
+	0x0003, 0x0118, 0xa186, 0x0006, 0x11a0, 0x6010, 0x2068, 0x6854,
+	0xa08a, 0x199a, 0x0270, 0xa082, 0x1999, 0x6856, 0xa08a, 0x199a,
+	0x0210, 0x2001, 0x1999, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116,
+	0x0010, 0x080c, 0x9350, 0x012e, 0xac88, 0x0018, 0x7116, 0x2001,
+	0xe400, 0xa102, 0x0220, 0x7017, 0xb400, 0x7007, 0x0000, 0x0005,
+	0x00e6, 0x2071, 0xafda, 0x7027, 0x07d0, 0x7023, 0x0009, 0x00ee,
+	0x0005, 0x2001, 0xafe3, 0x2003, 0x0000, 0x0005, 0x00e6, 0x2071,
+	0xafda, 0x7132, 0x702f, 0x0009, 0x00ee, 0x0005, 0x2011, 0xafe6,
+	0x2013, 0x0000, 0x0005, 0x00e6, 0x2071, 0xafda, 0x711a, 0x721e,
+	0x700b, 0x0009, 0x00ee, 0x0005, 0x00c6, 0x2061, 0xb048, 0x00ce,
+	0x0005, 0xa184, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0xb048,
+	0x2060, 0x0005, 0x6854, 0xa08a, 0x199a, 0x0210, 0x2001, 0x1999,
+	0xa005, 0x1150, 0x00c6, 0x2061, 0xb048, 0x6014, 0x00ce, 0xa005,
+	0x1138, 0x2001, 0x001e, 0x0020, 0xa08e, 0xffff, 0x1108, 0xa006,
+	0x8003, 0x800b, 0x810b, 0xa108, 0x6116, 0x684c, 0xa08c, 0x00c0,
+	0xa18e, 0x00c0, 0x05b0, 0xd0b4, 0x1138, 0xd0bc, 0x1528, 0x2009,
+	0x0006, 0x080c, 0x661a, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003,
+	0x0118, 0xa086, 0x0003, 0x15c0, 0x6020, 0xd0d4, 0x0130, 0xc0d4,
+	0x6022, 0x6860, 0x602a, 0x685c, 0x602e, 0x2009, 0xad73, 0x2104,
+	0xd084, 0x0128, 0x2009, 0x0042, 0x080c, 0x80a7, 0x0005, 0x2009,
+	0x0043, 0x080c, 0x80a7, 0x0005, 0xd0fc, 0x0130, 0xa084, 0x0003,
+	0x0118, 0xa086, 0x0003, 0x11c0, 0x2009, 0x0042, 0x080c, 0x80a7,
+	0x0005, 0xd0fc, 0x0150, 0xa084, 0x0003, 0xa08e, 0x0002, 0x0138,
+	0x2009, 0x0041, 0x080c, 0x80a7, 0x0005, 0x0051, 0x0ce8, 0x2009,
+	0x0043, 0x080c, 0x80a7, 0x0cc0, 0x2009, 0x0004, 0x0019, 0x0005,
+	0x2009, 0x0001, 0x00d6, 0x6010, 0xa0ec, 0xf000, 0x01f0, 0x2068,
+	0x6952, 0x6800, 0x6012, 0xa186, 0x0001, 0x1188, 0x694c, 0xa18c,
+	0x8100, 0xa18e, 0x8100, 0x1158, 0x00c6, 0x2061, 0xb048, 0x6200,
+	0xd28c, 0x1120, 0x6204, 0x8210, 0x0208, 0x6206, 0x00ce, 0x080c,
+	0x510c, 0x6010, 0xa06d, 0x190c, 0x65aa, 0x00de, 0x0005, 0x0156,
+	0x00c6, 0x2061, 0xb048, 0x6000, 0x81ff, 0x0110, 0xa205, 0x0008,
+	0xa204, 0x6002, 0x00ce, 0x015e, 0x0005, 0x6800, 0xd08c, 0x1138,
+	0x6808, 0xa005, 0x0120, 0x8001, 0x680a, 0xa085, 0x0001, 0x0005,
+	0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x1208, 0xa200,
+	0x1f04, 0x665c, 0x8086, 0x818e, 0x0005, 0x0156, 0x20a9, 0x0010,
+	0xa005, 0x01b8, 0xa11a, 0x12a8, 0x8213, 0x818d, 0x0228, 0xa11a,
+	0x1220, 0x1f04, 0x666c, 0x0028, 0xa11a, 0x2308, 0x8210, 0x1f04,
+	0x666c, 0x0006, 0x3200, 0xa084, 0xefff, 0x2080, 0x000e, 0x015e,
+	0x0005, 0x0006, 0x3200, 0xa085, 0x1000, 0x0cb8, 0x0126, 0x2091,
+	0x2800, 0x2079, 0xafc7, 0x012e, 0x00d6, 0x2069, 0xafc7, 0x6803,
+	0x0005, 0x2069, 0x0004, 0x2d04, 0xa085, 0x8001, 0x206a, 0x00de,
+	0x0005, 0x00c6, 0x6027, 0x0001, 0x7804, 0xa084, 0x0007, 0x0002,
+	0x66aa, 0x66cb, 0x671e, 0x66b0, 0x66cb, 0x66aa, 0x66a8, 0x66a8,
+	0x080c, 0x14f6, 0x080c, 0x6581, 0x080c, 0x6c50, 0x00ce, 0x0005,
+	0x62c0, 0x82ff, 0x1110, 0x00ce, 0x0005, 0x2011, 0x481b, 0x080c,
+	0x650d, 0x7828, 0xa092, 0x00c8, 0x1228, 0x8000, 0x782a, 0x080c,
+	0x4855, 0x0c88, 0x080c, 0x481b, 0x7807, 0x0003, 0x7827, 0x0000,
+	0x782b, 0x0000, 0x0c40, 0x080c, 0x6581, 0x3c00, 0x0006, 0x2011,
+	0x0209, 0x20e1, 0x4000, 0x2214, 0x000e, 0x20e0, 0x82ff, 0x0178,
+	0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824, 0xa065, 0x090c,
+	0x14f6, 0x2009, 0x0013, 0x080c, 0x80a7, 0x00ce, 0x0005, 0x3900,
+	0xa082, 0xb0e8, 0x1210, 0x080c, 0x7d8d, 0x00c6, 0x7824, 0xa065,
+	0x090c, 0x14f6, 0x7804, 0xa086, 0x0004, 0x0904, 0x675e, 0x7828,
+	0xa092, 0x2710, 0x1230, 0x8000, 0x782a, 0x00ce, 0x080c, 0x7827,
+	0x0c20, 0x6104, 0xa186, 0x0003, 0x1188, 0x00e6, 0x2071, 0xad00,
+	0x70dc, 0x00ee, 0xd08c, 0x0150, 0x00c6, 0x00e6, 0x2061, 0x0100,
+	0x2071, 0xad00, 0x080c, 0x485e, 0x00ee, 0x00ce, 0x080c, 0xaca2,
+	0x2009, 0x0014, 0x080c, 0x80a7, 0x00ce, 0x0838, 0x2001, 0xafe3,
+	0x2003, 0x0000, 0x62c0, 0x82ff, 0x1160, 0x782b, 0x0000, 0x7824,
+	0xa065, 0x090c, 0x14f6, 0x2009, 0x0013, 0x080c, 0x80fb, 0x00ce,
+	0x0005, 0x00c6, 0x00d6, 0x3900, 0xa082, 0xb0e8, 0x1210, 0x080c,
+	0x7d8d, 0x7824, 0xa005, 0x090c, 0x14f6, 0x781c, 0xa06d, 0x090c,
+	0x14f6, 0x6800, 0xc0dc, 0x6802, 0x7924, 0x2160, 0x080c, 0x8078,
+	0x693c, 0x81ff, 0x090c, 0x14f6, 0x8109, 0x693e, 0x6854, 0xa015,
+	0x0110, 0x7a1e, 0x0010, 0x7918, 0x791e, 0x7807, 0x0000, 0x7827,
+	0x0000, 0x00de, 0x00ce, 0x080c, 0x6c50, 0x0888, 0x6104, 0xa186,
+	0x0002, 0x0128, 0xa186, 0x0004, 0x0110, 0x0804, 0x66f7, 0x7808,
+	0xac06, 0x0904, 0x66f7, 0x080c, 0x6b73, 0x080c, 0x67ee, 0x00ce,
+	0x080c, 0x6c50, 0x0804, 0x66e5, 0x00c6, 0x6027, 0x0002, 0x62c8,
+	0x60c4, 0xa205, 0x1178, 0x793c, 0xa1e5, 0x0000, 0x0130, 0x2009,
+	0x0049, 0x080c, 0x80a7, 0x00ce, 0x0005, 0x2011, 0xafe6, 0x2013,
+	0x0000, 0x0cc8, 0x3908, 0xa192, 0xb0e8, 0x1210, 0x080c, 0x7d8d,
+	0x793c, 0x81ff, 0x0d90, 0x793c, 0xa188, 0x0007, 0x210c, 0xa18e,
+	0x0006, 0x1138, 0x6014, 0xa084, 0x0184, 0xa085, 0x0012, 0x6016,
+	0x0c10, 0x6014, 0xa084, 0x0184, 0xa085, 0x0016, 0x6016, 0x08d8,
+	0x0006, 0x0016, 0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000,
+	0x2c08, 0x2061, 0xafc7, 0x6020, 0x8000, 0x6022, 0x6010, 0xa005,
+	0x0148, 0xa080, 0x0003, 0x2102, 0x6112, 0x012e, 0x00ce, 0x001e,
+	0x000e, 0x0005, 0x6116, 0x6112, 0x0cc0, 0x00d6, 0x2069, 0xafc7,
+	0x6000, 0xd0d4, 0x0168, 0x6820, 0x8000, 0x6822, 0xa086, 0x0001,
+	0x1110, 0x2c00, 0x681e, 0x6804, 0xa084, 0x0007, 0x0804, 0x6c56,
+	0xc0d5, 0x6002, 0x6818, 0xa005, 0x0158, 0x6056, 0x605b, 0x0000,
+	0x0006, 0x2c00, 0x681a, 0x00de, 0x685a, 0x2069, 0xafc7, 0x0c18,
+	0x6056, 0x605a, 0x2c00, 0x681a, 0x681e, 0x08e8, 0x0006, 0x0016,
+	0x00c6, 0x0126, 0x2091, 0x8000, 0x600f, 0x0000, 0x2c08, 0x2061,
+	0xafc7, 0x6020, 0x8000, 0x6022, 0x6008, 0xa005, 0x0148, 0xa080,
+	0x0003, 0x2102, 0x610a, 0x012e, 0x00ce, 0x001e, 0x000e, 0x0005,
+	0x610e, 0x610a, 0x0cc0, 0x00c6, 0x600f, 0x0000, 0x2c08, 0x2061,
+	0xafc7, 0x6034, 0xa005, 0x0130, 0xa080, 0x0003, 0x2102, 0x6136,
+	0x00ce, 0x0005, 0x613a, 0x6136, 0x0cd8, 0x00f6, 0x00e6, 0x00d6,
+	0x00c6, 0x0076, 0x0066, 0x0026, 0x0016, 0x0006, 0x0126, 0x2071,
+	0xafc7, 0x7638, 0x2660, 0x2678, 0x2091, 0x8000, 0x8cff, 0x0904,
+	0x6889, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904, 0x6884,
+	0x87ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6884, 0x703c, 0xac06,
+	0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x7033, 0x0000,
+	0x703f, 0x0000, 0x7043, 0x0000, 0x7047, 0x0000, 0x003e, 0x7038,
+	0xac36, 0x1110, 0x660c, 0x763a, 0x7034, 0xac36, 0x1140, 0x2c00,
+	0xaf36, 0x0118, 0x2f00, 0x7036, 0x0010, 0x7037, 0x0000, 0x660c,
+	0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f,
+	0x0000, 0x080c, 0x9596, 0x0198, 0x6010, 0x2068, 0x601c, 0xa086,
+	0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c,
+	0x97fd, 0x080c, 0xabfa, 0x080c, 0x510c, 0x080c, 0x9742, 0x080c,
+	0x974e, 0x00ce, 0x0804, 0x682e, 0x2c78, 0x600c, 0x2060, 0x0804,
+	0x682e, 0x012e, 0x000e, 0x001e, 0x002e, 0x006e, 0x007e, 0x00ce,
+	0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086, 0x0006, 0x19d0,
+	0x080c, 0xabfa, 0x080c, 0xa91f, 0x0c10, 0x0006, 0x0066, 0x00c6,
+	0x00d6, 0x00f6, 0x2031, 0x0000, 0x0126, 0x2091, 0x8000, 0x2079,
+	0xafc7, 0x7838, 0xa065, 0x0558, 0x600c, 0x0006, 0x600f, 0x0000,
+	0x783c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64,
+	0x7833, 0x0000, 0x783f, 0x0000, 0x7843, 0x0000, 0x7847, 0x0000,
+	0x003e, 0x080c, 0x9596, 0x0178, 0x6010, 0x2068, 0x601c, 0xa086,
+	0x0003, 0x11b0, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c,
+	0x510c, 0x080c, 0x9742, 0x080c, 0x974e, 0x000e, 0x0898, 0x7e3a,
+	0x7e36, 0x012e, 0x00fe, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005,
+	0x601c, 0xa086, 0x0006, 0x1d30, 0x080c, 0xa91f, 0x0c60, 0x0016,
+	0x0026, 0x0086, 0x2041, 0x0000, 0x0099, 0x080c, 0x69a9, 0x008e,
+	0x002e, 0x001e, 0x0005, 0x00f6, 0x0126, 0x2079, 0xafc7, 0x2091,
+	0x8000, 0x080c, 0x6a36, 0x080c, 0x6aa8, 0x012e, 0x00fe, 0x0005,
+	0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0066, 0x0016, 0x0006, 0x0126,
+	0x2091, 0x8000, 0x2071, 0xafc7, 0x7614, 0x2660, 0x2678, 0x8cff,
+	0x0904, 0x6985, 0x6018, 0xa080, 0x0028, 0x2004, 0xa206, 0x1904,
+	0x6980, 0x88ff, 0x0120, 0x6050, 0xa106, 0x1904, 0x6980, 0x7024,
+	0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c,
+	0x6581, 0x080c, 0x7834, 0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7027,
+	0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384, 0x1000, 0x0120,
+	0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100, 0x6824, 0xd084,
+	0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003, 0x0009, 0x630a,
+	0x04b8, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616, 0x7010, 0xac36,
+	0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012, 0x0010, 0x7013,
+	0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008,
+	0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c, 0x9596, 0x0188,
+	0x601c, 0xa086, 0x0003, 0x1510, 0x6837, 0x0103, 0x6b4a, 0x6847,
+	0x0000, 0x080c, 0x97fd, 0x080c, 0xabfa, 0x080c, 0x510c, 0x080c,
+	0x9742, 0x080c, 0x974e, 0x080c, 0x7b88, 0x00ce, 0x0804, 0x690f,
+	0x2c78, 0x600c, 0x2060, 0x0804, 0x690f, 0x012e, 0x000e, 0x001e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086,
+	0x0006, 0x1128, 0x080c, 0xabfa, 0x080c, 0xa91f, 0x0c10, 0x601c,
+	0xa086, 0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x0968, 0x08c8,
+	0x601c, 0xa086, 0x0005, 0x19a8, 0x6004, 0xa086, 0x0085, 0x0d50,
+	0x0880, 0x00c6, 0x0006, 0x0126, 0x2091, 0x8000, 0xa280, 0xae34,
+	0x2004, 0xa065, 0x0904, 0x6a32, 0x00f6, 0x00e6, 0x00d6, 0x0066,
+	0x2071, 0xafc7, 0x6654, 0x7018, 0xac06, 0x1108, 0x761a, 0x701c,
+	0xac06, 0x1130, 0x86ff, 0x1118, 0x7018, 0x701e, 0x0008, 0x761e,
+	0x6058, 0xa07d, 0x0108, 0x7e56, 0xa6ed, 0x0000, 0x0110, 0x2f00,
+	0x685a, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4, 0xc0dc,
+	0x6002, 0x080c, 0x4c07, 0x0904, 0x6a2e, 0x7624, 0x86ff, 0x05e8,
+	0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069, 0x0100,
+	0x68c0, 0xa005, 0x0548, 0x080c, 0x6581, 0x080c, 0x7834, 0x68c3,
+	0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140,
+	0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e, 0x2660,
+	0x080c, 0x974e, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660, 0x6003,
+	0x0009, 0x630a, 0x00ce, 0x0804, 0x69d9, 0x8dff, 0x0158, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd, 0x080c, 0xabfa,
+	0x080c, 0x510c, 0x080c, 0x7b88, 0x0804, 0x69d9, 0x006e, 0x00de,
+	0x00ee, 0x00fe, 0x012e, 0x000e, 0x00ce, 0x0005, 0x0006, 0x0066,
+	0x00c6, 0x00d6, 0x2031, 0x0000, 0x7814, 0xa065, 0x0904, 0x6a88,
+	0x600c, 0x0006, 0x600f, 0x0000, 0x7824, 0xac06, 0x1540, 0x2069,
+	0x0100, 0x68c0, 0xa005, 0x01f0, 0x080c, 0x6581, 0x080c, 0x7834,
+	0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7827, 0x0000, 0x0036, 0x2069,
+	0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803,
+	0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001,
+	0x003e, 0x0028, 0x6003, 0x0009, 0x630a, 0x2c30, 0x00b0, 0x6010,
+	0x2068, 0x080c, 0x9596, 0x0168, 0x601c, 0xa086, 0x0003, 0x11b8,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c,
+	0x9742, 0x080c, 0x974e, 0x080c, 0x7b88, 0x000e, 0x0804, 0x6a3d,
+	0x7e16, 0x7e12, 0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x601c,
+	0xa086, 0x0006, 0x1118, 0x080c, 0xa91f, 0x0c58, 0x601c, 0xa086,
+	0x0002, 0x1128, 0x6004, 0xa086, 0x0085, 0x09d0, 0x0c10, 0x601c,
+	0xa086, 0x0005, 0x19f0, 0x6004, 0xa086, 0x0085, 0x0d60, 0x08c8,
+	0x0006, 0x0066, 0x00c6, 0x00d6, 0x7818, 0xa065, 0x0904, 0x6b0e,
+	0x6054, 0x0006, 0x6057, 0x0000, 0x605b, 0x0000, 0x6000, 0xc0d4,
+	0xc0dc, 0x6002, 0x080c, 0x4c07, 0x0904, 0x6b0b, 0x7e24, 0x86ff,
+	0x05e8, 0xa680, 0x0004, 0x2004, 0xad06, 0x15c0, 0x00d6, 0x2069,
+	0x0100, 0x68c0, 0xa005, 0x0548, 0x080c, 0x6581, 0x080c, 0x7834,
+	0x68c3, 0x0000, 0x080c, 0x7ca8, 0x7827, 0x0000, 0x0036, 0x2069,
+	0x0140, 0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803,
+	0x0000, 0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001,
+	0x003e, 0x00de, 0x00c6, 0x603c, 0xa005, 0x0110, 0x8001, 0x603e,
+	0x2660, 0x080c, 0x974e, 0x00ce, 0x0048, 0x00de, 0x00c6, 0x2660,
+	0x6003, 0x0009, 0x630a, 0x00ce, 0x0804, 0x6aba, 0x8dff, 0x0138,
+	0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c,
+	0x7b88, 0x0804, 0x6aba, 0x000e, 0x0804, 0x6aad, 0x781e, 0x781a,
+	0x00de, 0x00ce, 0x006e, 0x000e, 0x0005, 0x00e6, 0x00d6, 0x0066,
+	0x6000, 0xd0dc, 0x0188, 0x604c, 0xa06d, 0x0170, 0x6848, 0xa606,
+	0x1158, 0x2071, 0xafc7, 0x7024, 0xa035, 0x0130, 0xa080, 0x0004,
+	0x2004, 0xad06, 0x1108, 0x0021, 0x006e, 0x00de, 0x00ee, 0x0005,
+	0x00f6, 0x2079, 0x0100, 0x78c0, 0xa005, 0x1138, 0x00c6, 0x2660,
+	0x6003, 0x0009, 0x630a, 0x00ce, 0x04a0, 0x080c, 0x7834, 0x78c3,
+	0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2079, 0x0140,
+	0x7b04, 0xa384, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000,
+	0x2079, 0x0100, 0x7824, 0xd084, 0x0110, 0x7827, 0x0001, 0x080c,
+	0x7ca8, 0x003e, 0x080c, 0x4c07, 0x00c6, 0x603c, 0xa005, 0x0110,
+	0x8001, 0x603e, 0x2660, 0x080c, 0x8078, 0x00ce, 0x6837, 0x0103,
+	0x6b4a, 0x6847, 0x0000, 0x080c, 0x97fd, 0x080c, 0x510c, 0x080c,
+	0x7b88, 0x00fe, 0x0005, 0x00e6, 0x00c6, 0x2071, 0xafc7, 0x7004,
+	0xa084, 0x0007, 0x0002, 0x6b85, 0x6b88, 0x6b9e, 0x6bb7, 0x6bf0,
+	0x6b85, 0x6b83, 0x6b83, 0x080c, 0x14f6, 0x00ce, 0x00ee, 0x0005,
+	0x7024, 0xa065, 0x0148, 0x7020, 0x8001, 0x7022, 0x600c, 0xa015,
+	0x0150, 0x7216, 0x600f, 0x0000, 0x7007, 0x0000, 0x7027, 0x0000,
+	0x00ce, 0x00ee, 0x0005, 0x7216, 0x7212, 0x0cb0, 0x6018, 0x2060,
+	0x080c, 0x4c07, 0x6000, 0xc0dc, 0x6002, 0x7020, 0x8001, 0x7022,
+	0x0120, 0x6054, 0xa015, 0x0140, 0x721e, 0x7007, 0x0000, 0x7027,
+	0x0000, 0x00ce, 0x00ee, 0x0005, 0x7218, 0x721e, 0x0cb0, 0x7024,
+	0xa065, 0x0598, 0x700c, 0xac06, 0x1160, 0x080c, 0x7b88, 0x600c,
+	0xa015, 0x0120, 0x720e, 0x600f, 0x0000, 0x0428, 0x720e, 0x720a,
+	0x0410, 0x7014, 0xac06, 0x1160, 0x080c, 0x7b88, 0x600c, 0xa015,
+	0x0120, 0x7216, 0x600f, 0x0000, 0x00b0, 0x7216, 0x7212, 0x0098,
+	0x6018, 0x2060, 0x080c, 0x4c07, 0x6000, 0xc0dc, 0x6002, 0x080c,
+	0x7b88, 0x701c, 0xa065, 0x0138, 0x6054, 0xa015, 0x0110, 0x721e,
+	0x0010, 0x7218, 0x721e, 0x7027, 0x0000, 0x00ce, 0x00ee, 0x0005,
+	0x7024, 0xa065, 0x0140, 0x080c, 0x7b88, 0x600c, 0xa015, 0x0150,
+	0x720e, 0x600f, 0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x00ce,
+	0x00ee, 0x0005, 0x720e, 0x720a, 0x0cb0, 0x00d6, 0x2069, 0xafc7,
+	0x6830, 0xa084, 0x0003, 0x0002, 0x6c12, 0x6c14, 0x6c38, 0x6c10,
+	0x080c, 0x14f6, 0x00de, 0x0005, 0x00c6, 0x6840, 0xa086, 0x0001,
+	0x01b8, 0x683c, 0xa065, 0x0130, 0x600c, 0xa015, 0x0170, 0x6a3a,
+	0x600f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000, 0x2011, 0xafe6,
+	0x2013, 0x0000, 0x00ce, 0x00de, 0x0005, 0x683a, 0x6836, 0x0c90,
+	0x6843, 0x0000, 0x6838, 0xa065, 0x0d68, 0x6003, 0x0003, 0x0c50,
+	0x00c6, 0x6843, 0x0000, 0x6847, 0x0000, 0x683c, 0xa065, 0x0168,
+	0x600c, 0xa015, 0x0130, 0x6a3a, 0x600f, 0x0000, 0x683f, 0x0000,
+	0x0020, 0x683f, 0x0000, 0x683a, 0x6836, 0x00ce, 0x00de, 0x0005,
+	0x00d6, 0x2069, 0xafc7, 0x6804, 0xa084, 0x0007, 0x0002, 0x6c61,
+	0x6cfd, 0x6cfd, 0x6cfd, 0x6cfd, 0x6cff, 0x6c5f, 0x6c5f, 0x080c,
+	0x14f6, 0x6820, 0xa005, 0x1110, 0x00de, 0x0005, 0x00c6, 0x680c,
+	0xa065, 0x0150, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000, 0x080c,
+	0x6d49, 0x00ce, 0x00de, 0x0005, 0x6814, 0xa065, 0x0150, 0x6807,
+	0x0001, 0x6826, 0x682b, 0x0000, 0x080c, 0x6d49, 0x00ce, 0x00de,
+	0x0005, 0x00e6, 0x0036, 0x6a1c, 0xa2f5, 0x0000, 0x0904, 0x6cf9,
+	0x704c, 0xa00d, 0x0118, 0x7088, 0xa005, 0x01a0, 0x7054, 0xa075,
+	0x0120, 0xa20e, 0x0904, 0x6cf9, 0x0028, 0x6818, 0xa20e, 0x0904,
+	0x6cf9, 0x2070, 0x704c, 0xa00d, 0x0d88, 0x7088, 0xa005, 0x1d70,
+	0x2e00, 0x681e, 0x733c, 0x7038, 0xa302, 0x1e40, 0x080c, 0x804f,
+	0x0904, 0x6cf9, 0x8318, 0x733e, 0x6112, 0x2e10, 0x621a, 0xa180,
+	0x0014, 0x2004, 0xa084, 0x00ff, 0x605a, 0xa180, 0x0014, 0x2003,
+	0x0000, 0xa180, 0x0015, 0x2004, 0xa08a, 0x199a, 0x0210, 0x2001,
+	0x1999, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x00f6,
+	0x2c78, 0x71a0, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1110, 0xd1bc,
+	0x0150, 0x7100, 0xd1f4, 0x0120, 0x7114, 0xa18c, 0x00ff, 0x0040,
+	0x2009, 0x0000, 0x0028, 0xa1e0, 0x2be6, 0x2c0d, 0xa18c, 0x00ff,
+	0x2061, 0x0100, 0x619a, 0x080c, 0x736f, 0x7300, 0xc3dd, 0x7302,
+	0x6807, 0x0002, 0x2f18, 0x6b26, 0x682b, 0x0000, 0x781f, 0x0003,
+	0x7803, 0x0001, 0x7807, 0x0040, 0x00fe, 0x00ee, 0x00ce, 0x00de,
+	0x0005, 0x003e, 0x00ee, 0x00ce, 0x0cd0, 0x00de, 0x0005, 0x00c6,
+	0x680c, 0xa065, 0x0138, 0x6807, 0x0004, 0x6826, 0x682b, 0x0000,
+	0x080c, 0x6d49, 0x00ce, 0x00de, 0x0005, 0x00f6, 0x00d6, 0x2069,
+	0xafc7, 0x6830, 0xa086, 0x0000, 0x11c0, 0x2001, 0xad0c, 0x200c,
+	0xd1bc, 0x1550, 0x6838, 0xa07d, 0x0180, 0x6833, 0x0001, 0x683e,
+	0x6847, 0x0000, 0x0126, 0x00f6, 0x2091, 0x2400, 0x002e, 0x080c,
+	0x1ee6, 0x1130, 0x012e, 0x080c, 0x76a5, 0x00de, 0x00fe, 0x0005,
+	0x012e, 0xe000, 0x6843, 0x0000, 0x7803, 0x0002, 0x780c, 0xa015,
+	0x0140, 0x6a3a, 0x780f, 0x0000, 0x6833, 0x0000, 0x683f, 0x0000,
+	0x0c60, 0x683a, 0x6836, 0x0cc0, 0xc1bc, 0x2102, 0x080c, 0x57d1,
+	0x0888, 0x601c, 0xa084, 0x000f, 0x000b, 0x0005, 0x6d57, 0x6d5c,
+	0x7210, 0x732c, 0x6d5c, 0x7210, 0x732c, 0x6d57, 0x6d5c, 0x080c,
+	0x6b73, 0x080c, 0x6c50, 0x0005, 0x0156, 0x0136, 0x0146, 0x00c6,
+	0x00f6, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6, 0x6118, 0x2178,
+	0x79a0, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150,
+	0x7900, 0xd1f4, 0x0120, 0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009,
+	0x0000, 0x0028, 0xa1f8, 0x2be6, 0x2f0d, 0xa18c, 0x00ff, 0x2c78,
+	0x2061, 0x0100, 0x619a, 0xa08a, 0x0040, 0x1a04, 0x6dd0, 0x0033,
+	0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005, 0x6e7c, 0x6ec7,
+	0x6ef4, 0x6fc1, 0x6fef, 0x6ff7, 0x701d, 0x702e, 0x703f, 0x7047,
+	0x705d, 0x7047, 0x70b7, 0x702e, 0x70d8, 0x70e0, 0x703f, 0x70e0,
+	0x70f1, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x6dce,
+	0x6dce, 0x6dce, 0x6dce, 0x6dce, 0x790d, 0x7932, 0x7947, 0x796a,
+	0x798b, 0x701d, 0x6dce, 0x701d, 0x7047, 0x6dce, 0x6ef4, 0x6fc1,
+	0x6dce, 0x7daa, 0x7047, 0x6dce, 0x7dca, 0x7047, 0x6dce, 0x703f,
+	0x6e75, 0x6de0, 0x6dce, 0x7def, 0x7e64, 0x7f3b, 0x6dce, 0x7f4c,
+	0x7018, 0x7f68, 0x6dce, 0x79a0, 0x7fc3, 0x6dce, 0x080c, 0x14f6,
+	0x2100, 0x0033, 0x00fe, 0x00ce, 0x014e, 0x013e, 0x015e, 0x0005,
+	0x6dde, 0x6dde, 0x6dde, 0x6e14, 0x6e32, 0x6e48, 0x080c, 0x14f6,
+	0x00d6, 0x20a1, 0x020b, 0x080c, 0x710e, 0x7810, 0x2068, 0x20a3,
+	0x2414, 0x20a3, 0x0018, 0x20a3, 0x0800, 0x683c, 0x20a2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x6850,
+	0x20a2, 0x6854, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3,
+	0x0018, 0x080c, 0x7821, 0x00de, 0x0005, 0x00d6, 0x7818, 0x2068,
+	0x68a0, 0x2069, 0xad00, 0x6ad0, 0xd2ac, 0x1110, 0xd0bc, 0x0110,
+	0xa085, 0x0001, 0x00de, 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c,
+	0x710e, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x7810, 0xa0e8, 0x000f,
+	0x6808, 0x20a2, 0x680c, 0x20a2, 0x6810, 0x20a2, 0x6814, 0x20a2,
+	0x6818, 0x20a2, 0x681c, 0x20a2, 0x60c3, 0x0010, 0x080c, 0x7821,
+	0x00de, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x710e,
+	0x20a3, 0x7800, 0x20a3, 0x0000, 0x7808, 0x8007, 0x20a2, 0x20a3,
+	0x0000, 0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005,
+	0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200,
+	0x20a3, 0x0000, 0x20a3, 0xdf10, 0x20a3, 0x0034, 0x2099, 0xad05,
+	0x20a9, 0x0004, 0x53a6, 0x2099, 0xad01, 0x20a9, 0x0004, 0x53a6,
+	0x2099, 0xafad, 0x20a9, 0x001a, 0x3304, 0x8007, 0x20a2, 0x9398,
+	0x1f04, 0x6e64, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x004c,
+	0x080c, 0x7821, 0x014e, 0x015e, 0x0005, 0x2001, 0xad14, 0x2004,
+	0x609a, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x710e,
+	0x20a3, 0x5200, 0x20a3, 0x0000, 0x00d6, 0x2069, 0xad51, 0x6804,
+	0xd084, 0x0150, 0x6828, 0x20a3, 0x0000, 0x0016, 0x080c, 0x268a,
+	0x21a2, 0x001e, 0x00de, 0x0028, 0x00de, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x20a9, 0x0004,
+	0x2099, 0xad01, 0x53a6, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1138,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa082, 0x007f, 0x0238, 0x2001,
+	0xad1b, 0x20a6, 0x2001, 0xad1c, 0x20a6, 0x0040, 0x20a3, 0x0000,
+	0x2001, 0xad14, 0x2004, 0xa084, 0x00ff, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7821, 0x0005, 0x20a1,
+	0x020b, 0x080c, 0x710e, 0x20a3, 0x0500, 0x20a3, 0x0000, 0x2001,
+	0xad34, 0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004,
+	0xa082, 0x007f, 0x0238, 0x2001, 0xad1b, 0x20a6, 0x2001, 0xad1c,
+	0x20a6, 0x0040, 0x20a3, 0x0000, 0x2001, 0xad14, 0x2004, 0xa084,
+	0x00ff, 0x20a2, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x60c3,
+	0x0010, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x710e,
+	0x00c6, 0x7818, 0x2060, 0x2001, 0x0000, 0x080c, 0x5037, 0x00ce,
+	0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1130, 0x20a3,
+	0x0400, 0x620c, 0xc2b4, 0x620e, 0x0010, 0x20a3, 0x0300, 0x20a3,
+	0x0000, 0x7818, 0xa080, 0x0028, 0x2004, 0xa086, 0x007e, 0x1904,
+	0x6f83, 0x2001, 0xad34, 0x2004, 0xd0a4, 0x01c8, 0x2099, 0xaf8d,
+	0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, 0x3304, 0xa084, 0x2000,
+	0x20a2, 0x9398, 0x33a6, 0x9398, 0x20a3, 0x0000, 0x9398, 0x2001,
+	0x2710, 0x20a2, 0x9398, 0x33a6, 0x9398, 0x33a6, 0x00d0, 0x2099,
+	0xaf8d, 0x33a6, 0x9398, 0x33a6, 0x9398, 0x3304, 0x080c, 0x574f,
+	0x1118, 0xa084, 0x37ff, 0x0010, 0xa084, 0x3fff, 0x20a2, 0x9398,
+	0x33a6, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a9, 0x0004, 0x2099, 0xad05, 0x53a6, 0x20a9, 0x0004,
+	0x2099, 0xad01, 0x53a6, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04,
+	0x6f5d, 0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x6f63, 0x2099,
+	0xaf95, 0x3304, 0xc0dd, 0x20a2, 0x2001, 0xad71, 0x2004, 0xd0e4,
+	0x0158, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x9398, 0x9398, 0x9398,
+	0x33a6, 0x20a9, 0x0004, 0x0010, 0x20a9, 0x0007, 0x20a3, 0x0000,
+	0x1f04, 0x6f7e, 0x0468, 0x2001, 0xad34, 0x2004, 0xd0a4, 0x0140,
+	0x2001, 0xaf8e, 0x2004, 0x60e3, 0x0000, 0x080c, 0x26cb, 0x60e2,
+	0x2099, 0xaf8d, 0x20a9, 0x0008, 0x53a6, 0x20a9, 0x0004, 0x2099,
+	0xad05, 0x53a6, 0x20a9, 0x0004, 0x2099, 0xad01, 0x53a6, 0x20a9,
+	0x0008, 0x20a3, 0x0000, 0x1f04, 0x6fa1, 0x20a9, 0x0008, 0x20a3,
+	0x0000, 0x1f04, 0x6fa7, 0x2099, 0xaf95, 0x20a9, 0x0008, 0x53a6,
+	0x20a9, 0x0008, 0x20a3, 0x0000, 0x1f04, 0x6fb2, 0x20a9, 0x000a,
+	0x20a3, 0x0000, 0x1f04, 0x6fb8, 0x60c3, 0x0074, 0x080c, 0x7821,
+	0x0005, 0x20a1, 0x020b, 0x080c, 0x710e, 0x20a3, 0x2010, 0x20a3,
+	0x0014, 0x20a3, 0x0800, 0x20a3, 0x2000, 0xa006, 0x20a2, 0x20a2,
+	0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0xad51, 0x7904, 0x00fe,
+	0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110, 0xa085, 0x0010,
+	0xa085, 0x0002, 0x00d6, 0x0804, 0x7099, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005, 0x20a1,
+	0x020b, 0x080c, 0x710e, 0x20a3, 0x5000, 0x0804, 0x6f0f, 0x20a1,
+	0x020b, 0x080c, 0x710e, 0x20a3, 0x2110, 0x20a3, 0x0014, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x71a2, 0x0020, 0x20a1, 0x020b, 0x080c,
+	0x71aa, 0x20a3, 0x0200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0004, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b,
+	0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0003,
+	0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x20a1,
+	0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x0804, 0x6f0f, 0x20a1,
+	0x020b, 0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x7828,
+	0xa005, 0x0110, 0x20a2, 0x0010, 0x20a3, 0x0003, 0x7810, 0x20a2,
+	0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x00d6, 0x20a1, 0x020b,
+	0x080c, 0x71aa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3, 0x0800,
+	0x7818, 0x2068, 0x6894, 0xa086, 0x0014, 0x1178, 0x6998, 0xa184,
+	0xc000, 0x1140, 0xd1ec, 0x0118, 0x20a3, 0x2100, 0x0040, 0x20a3,
+	0x0100, 0x0028, 0x20a3, 0x0400, 0x0010, 0x20a3, 0x0700, 0xa006,
+	0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x00f6, 0x2079, 0xad51,
+	0x7904, 0x00fe, 0xd1ac, 0x1110, 0xa085, 0x0020, 0xd1a4, 0x0110,
+	0xa085, 0x0010, 0x2009, 0xad73, 0x210c, 0xd184, 0x1110, 0xa085,
+	0x0002, 0x0026, 0x2009, 0xad71, 0x210c, 0xd1e4, 0x0130, 0xc0c5,
+	0xa094, 0x0030, 0xa296, 0x0010, 0x0140, 0xd1ec, 0x0130, 0xa094,
+	0x0030, 0xa296, 0x0010, 0x0108, 0xc0bd, 0x002e, 0x20a2, 0x20a2,
+	0x20a2, 0x60c3, 0x0014, 0x080c, 0x7821, 0x00de, 0x0005, 0x20a1,
+	0x020b, 0x080c, 0x71aa, 0x20a3, 0x0210, 0x20a3, 0x0014, 0x20a3,
+	0x0000, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x0014, 0x080c, 0x7821, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x0804, 0x6e82,
+	0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x20a3, 0x0003, 0x20a3, 0x2a00, 0x60c3, 0x0008, 0x080c, 0x7821,
+	0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x20a1, 0x020b, 0x080c,
+	0x71aa, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0x000b, 0x20a3,
+	0x0000, 0x60c3, 0x0008, 0x080c, 0x7821, 0x0005, 0x0026, 0x0036,
+	0x0046, 0x2019, 0x3200, 0x2021, 0x0800, 0x0038, 0x0026, 0x0036,
+	0x0046, 0x2019, 0x2200, 0x2021, 0x0100, 0x20e1, 0x9080, 0x20e1,
+	0x4000, 0x7818, 0xa080, 0x0028, 0x2014, 0xa286, 0x007e, 0x11a0,
+	0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffe, 0x20a3, 0x0000, 0x2011,
+	0xad14, 0x2214, 0x2001, 0xaf9d, 0x2004, 0xa005, 0x0118, 0x2011,
+	0xad1c, 0x2214, 0x22a2, 0x04d0, 0xa286, 0x007f, 0x1138, 0x00d6,
+	0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffd, 0x00c8, 0x2001, 0xad34,
+	0x2004, 0xd0ac, 0x1110, 0xd2bc, 0x01c8, 0xa286, 0x0080, 0x00d6,
+	0x1130, 0xa385, 0x00ff, 0x20a2, 0x20a3, 0xfffc, 0x0040, 0xa2e8,
+	0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x2069,
+	0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6, 0xa2e8,
+	0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x00de,
+	0x20a3, 0x0000, 0x2011, 0xad14, 0x2214, 0x22a2, 0xa485, 0x0029,
+	0x20a2, 0x004e, 0x003e, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2,
+	0x20a3, 0x0000, 0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x002e, 0x0005, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000,
+	0x20a3, 0x02ff, 0x2011, 0xfffc, 0x22a2, 0x00d6, 0x2069, 0xad1b,
+	0x2da6, 0x8d68, 0x2da6, 0x00de, 0x20a3, 0x2029, 0x20a3, 0x0000,
+	0x08e0, 0x20a3, 0x0100, 0x20a3, 0x0000, 0x20a3, 0xfc02, 0x20a3,
+	0x0000, 0x0005, 0x0026, 0x0036, 0x0046, 0x2019, 0x3300, 0x2021,
+	0x0800, 0x0038, 0x0026, 0x0036, 0x0046, 0x2019, 0x2300, 0x2021,
+	0x0100, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e,
+	0x02d8, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa305, 0x20a2,
+	0x6814, 0x20a2, 0x6810, 0xa005, 0x1140, 0x6814, 0xa005, 0x1128,
+	0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x0028, 0x2069, 0xad1b, 0x2da6,
+	0x8d68, 0x2da6, 0x00de, 0x0080, 0x00d6, 0xa0e8, 0xae34, 0x2d6c,
+	0x6810, 0xa305, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000,
+	0x2011, 0xad14, 0x2214, 0x22a2, 0xa485, 0x0098, 0x20a2, 0x20a3,
+	0x0000, 0x004e, 0x003e, 0x080c, 0x7810, 0x22a2, 0x20a3, 0x0000,
+	0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e,
+	0x0005, 0x080c, 0x7810, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2,
+	0x7810, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x002e, 0x0005,
+	0x00c6, 0x00f6, 0x6004, 0xa08a, 0x0085, 0x0a0c, 0x14f6, 0xa08a,
+	0x008c, 0x1a0c, 0x14f6, 0x6118, 0x2178, 0x79a0, 0x2011, 0xad34,
+	0x2214, 0xd2ac, 0x1110, 0xd1bc, 0x0150, 0x7900, 0xd1f4, 0x0120,
+	0x7914, 0xa18c, 0x00ff, 0x0040, 0x2009, 0x0000, 0x0028, 0xa1f8,
+	0x2be6, 0x2f0d, 0xa18c, 0x00ff, 0x2c78, 0x2061, 0x0100, 0x619a,
+	0xa082, 0x0085, 0x001b, 0x00fe, 0x00ce, 0x0005, 0x7247, 0x7251,
+	0x726c, 0x7245, 0x7245, 0x7245, 0x7247, 0x080c, 0x14f6, 0x0146,
+	0x20a1, 0x020b, 0x04a1, 0x60c3, 0x0000, 0x080c, 0x7821, 0x014e,
+	0x0005, 0x0146, 0x20a1, 0x020b, 0x080c, 0x72b8, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x7808, 0x20a2, 0x7810, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c,
+	0x080c, 0x7821, 0x014e, 0x0005, 0x0146, 0x20a1, 0x020b, 0x080c,
+	0x72f2, 0x20a3, 0x0003, 0x20a3, 0x0300, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x60c3, 0x0004, 0x080c, 0x7821, 0x014e, 0x0005, 0x0026,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004,
+	0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e, 0x0288,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8100, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de,
+	0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8100,
+	0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14,
+	0x2214, 0x22a2, 0x20a3, 0x0009, 0x20a3, 0x0000, 0x0804, 0x7175,
+	0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118, 0xa092, 0x007e,
+	0x0288, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x8400,
+	0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6,
+	0x00de, 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085,
+	0x8400, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011,
+	0xad14, 0x2214, 0x22a2, 0x2001, 0x0099, 0x20a2, 0x20a3, 0x0000,
+	0x0804, 0x7201, 0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118,
+	0xa092, 0x007e, 0x0288, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810,
+	0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6,
+	0x8d68, 0x2da6, 0x00de, 0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c,
+	0x6810, 0xa085, 0x8500, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3,
+	0x0000, 0x2011, 0xad14, 0x2214, 0x22a2, 0x2001, 0x0099, 0x20a2,
+	0x20a3, 0x0000, 0x0804, 0x7201, 0x00c6, 0x00f6, 0x2c78, 0x7804,
+	0xa08a, 0x0040, 0x0a0c, 0x14f6, 0xa08a, 0x0053, 0x1a0c, 0x14f6,
+	0x7918, 0x2160, 0x61a0, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110,
+	0xd1bc, 0x0150, 0x6100, 0xd1f4, 0x0120, 0x6114, 0xa18c, 0x00ff,
+	0x0040, 0x2009, 0x0000, 0x0028, 0xa1e0, 0x2be6, 0x2c0d, 0xa18c,
+	0x00ff, 0x2061, 0x0100, 0x619a, 0xa082, 0x0040, 0x001b, 0x00fe,
+	0x00ce, 0x0005, 0x736f, 0x747b, 0x7418, 0x761a, 0x736d, 0x736d,
+	0x736d, 0x736d, 0x736d, 0x736d, 0x736d, 0x7b41, 0x7b51, 0x7b61,
+	0x7b71, 0x736d, 0x7f79, 0x736d, 0x7b30, 0x080c, 0x14f6, 0x00d6,
+	0x0156, 0x0146, 0x780b, 0xffff, 0x20a1, 0x020b, 0x080c, 0x73cf,
+	0x7910, 0x2168, 0x6948, 0x7952, 0x21a2, 0xa016, 0x22a2, 0x22a2,
+	0x22a2, 0x694c, 0xa184, 0x000f, 0x1118, 0x2001, 0x0005, 0x0040,
+	0xd184, 0x0118, 0x2001, 0x0004, 0x0018, 0xa084, 0x0006, 0x8004,
+	0x0016, 0x2008, 0x7858, 0xa084, 0x00ff, 0x8007, 0xa105, 0x001e,
+	0x20a2, 0xd1ac, 0x0118, 0x20a3, 0x0002, 0x0048, 0xd1b4, 0x0118,
+	0x20a3, 0x0001, 0x0020, 0x20a3, 0x0000, 0x2230, 0x0010, 0x6a80,
+	0x6e7c, 0x20a9, 0x0008, 0x0136, 0xad88, 0x0017, 0x2198, 0x20a1,
+	0x021b, 0x53a6, 0x013e, 0x20a1, 0x020b, 0x22a2, 0x26a2, 0x60c3,
+	0x0020, 0x20e1, 0x9080, 0x6014, 0xa084, 0x0004, 0xa085, 0x0009,
+	0x6016, 0x2001, 0xafe3, 0x2003, 0x07d0, 0x2001, 0xafe2, 0x2003,
+	0x0009, 0x080c, 0x17bf, 0x014e, 0x015e, 0x00de, 0x0005, 0x20e1,
+	0x9080, 0x20e1, 0x4000, 0x7a18, 0xa280, 0x0023, 0x2014, 0x8210,
+	0xa294, 0x00ff, 0x2202, 0x8217, 0x7818, 0xa080, 0x0028, 0x2004,
+	0x2019, 0xad34, 0x231c, 0xd3ac, 0x1110, 0xd0bc, 0x0188, 0x00d6,
+	0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2, 0x6814,
+	0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0600, 0x20a2,
+	0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2009, 0xad14, 0x210c,
+	0x21a2, 0x20a3, 0x0829, 0x20a3, 0x0000, 0x22a2, 0x20a3, 0x0000,
+	0x2fa2, 0x20a3, 0xffff, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x0005,
+	0x00d6, 0x0156, 0x0136, 0x0146, 0x20a1, 0x020b, 0x00c1, 0x7810,
+	0x2068, 0x6860, 0x20a2, 0x685c, 0x20a2, 0x6880, 0x20a2, 0x687c,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x60c3, 0x000c,
+	0x080c, 0x7821, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005, 0x0026,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028, 0x2004,
+	0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188, 0x00d6,
+	0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2, 0x6814,
+	0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de, 0x0088,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0500, 0x20a2,
+	0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14, 0x2214,
+	0x22a2, 0x20a3, 0x0889, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2,
+	0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x7810,
+	0xa06d, 0x080c, 0x5025, 0x0148, 0x684c, 0xa084, 0x2020, 0xa086,
+	0x2020, 0x1118, 0x7820, 0xc0cd, 0x7822, 0x20a1, 0x020b, 0x080c,
+	0x75d0, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x7810,
+	0xa084, 0xf000, 0x1130, 0x7810, 0xa084, 0x0700, 0x8007, 0x0043,
+	0x0010, 0xa006, 0x002b, 0x014e, 0x013e, 0x015e, 0x00de, 0x0005,
+	0x74b2, 0x7547, 0x7550, 0x7579, 0x758c, 0x75a7, 0x75b0, 0x74b0,
+	0x080c, 0x14f6, 0x0016, 0x0036, 0x694c, 0xa18c, 0x0003, 0x0118,
+	0xa186, 0x0003, 0x1170, 0x6b78, 0x7820, 0xd0cc, 0x0108, 0xc3e5,
+	0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x003e, 0x001e, 0x0804,
+	0x7583, 0xa186, 0x0001, 0x190c, 0x14f6, 0x6b78, 0x7820, 0xd0cc,
+	0x0108, 0xc3e5, 0x23a2, 0x6868, 0x20a2, 0x6864, 0x20a2, 0x22a2,
+	0x6874, 0x20a2, 0x22a2, 0x687c, 0x20a2, 0x2009, 0x0018, 0xa384,
+	0x0300, 0x0904, 0x7541, 0xd3c4, 0x0110, 0x687c, 0xa108, 0xd3cc,
+	0x0110, 0x6874, 0xa108, 0x0156, 0x20a9, 0x000d, 0xad80, 0x0020,
+	0x201c, 0x831f, 0x23a2, 0x8000, 0x1f04, 0x74f0, 0x015e, 0x22a2,
+	0x22a2, 0x22a2, 0xa184, 0x0003, 0x0904, 0x7541, 0x20a1, 0x020b,
+	0x20e1, 0x9080, 0x20e1, 0x4000, 0x0006, 0x7818, 0xa080, 0x0028,
+	0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de,
+	0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700,
+	0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14,
+	0x2214, 0x22a2, 0x000e, 0x7b20, 0xd3cc, 0x0118, 0x20a3, 0x0889,
+	0x0010, 0x20a3, 0x0898, 0x20a2, 0x080c, 0x7810, 0x22a2, 0x20a3,
+	0x0000, 0x61c2, 0x003e, 0x001e, 0x080c, 0x7821, 0x0005, 0x2011,
+	0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0488,
+	0x2011, 0x0302, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016,
+	0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x0012, 0x22a2, 0x20a3, 0x0008,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x20a3, 0x7000, 0x20a3, 0x0500,
+	0x22a2, 0x20a3, 0x000a, 0x22a2, 0x22a2, 0x20a3, 0x2500, 0x22a2,
+	0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0032, 0x080c, 0x7821,
+	0x0005, 0x2011, 0x0028, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2,
+	0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x22a2, 0x60c3,
+	0x0018, 0x080c, 0x7821, 0x0005, 0x2011, 0x0100, 0x7820, 0xd0cc,
+	0x0108, 0xc2e5, 0x22a2, 0xa016, 0x22a2, 0x22a2, 0x22a2, 0x22a2,
+	0x22a2, 0x20a3, 0x0008, 0x22a2, 0x7854, 0xa084, 0x00ff, 0x20a2,
+	0x22a2, 0x22a2, 0x60c3, 0x0020, 0x080c, 0x7821, 0x0005, 0x2011,
+	0x0008, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0xa016, 0x0888,
+	0x0036, 0x7b10, 0xa384, 0xff00, 0x7812, 0xa384, 0x00ff, 0x8001,
+	0x1138, 0x7820, 0xd0cc, 0x0108, 0xc2e5, 0x22a2, 0x003e, 0x0808,
+	0x0046, 0x2021, 0x0800, 0x0006, 0x7820, 0xd0cc, 0x000e, 0x0108,
+	0xc4e5, 0x24a2, 0x004e, 0x22a2, 0x20a2, 0x003e, 0x0804, 0x7583,
+	0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de,
+	0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0700,
+	0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14,
+	0x2214, 0x22a2, 0x7820, 0xd0cc, 0x0118, 0x20a3, 0x0889, 0x0010,
+	0x20a3, 0x0898, 0x20a3, 0x0000, 0x080c, 0x7810, 0x22a2, 0x20a3,
+	0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x002e, 0x0005, 0x00d6, 0x0156, 0x0136, 0x0146, 0x0016, 0x0036,
+	0x7810, 0xa084, 0x0700, 0x8007, 0x003b, 0x003e, 0x001e, 0x014e,
+	0x013e, 0x015e, 0x00de, 0x0005, 0x7634, 0x7634, 0x7636, 0x7634,
+	0x7634, 0x7634, 0x7658, 0x7634, 0x080c, 0x14f6, 0x7910, 0xa18c,
+	0xf8ff, 0xa18d, 0x0600, 0x7912, 0x20a1, 0x020b, 0x2009, 0x0003,
+	0x00f9, 0x00d6, 0x2069, 0xad51, 0x6804, 0xd0bc, 0x0130, 0x682c,
+	0xa084, 0x00ff, 0x8007, 0x20a2, 0x0010, 0x20a3, 0x3f00, 0x00de,
+	0x22a2, 0x22a2, 0x22a2, 0x60c3, 0x0001, 0x080c, 0x7821, 0x0005,
+	0x20a1, 0x020b, 0x2009, 0x0003, 0x0019, 0x20a3, 0x7f00, 0x0c80,
+	0x0026, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818, 0xa080, 0x0028,
+	0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110, 0xd0bc, 0x0188,
+	0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0100, 0x20a2,
+	0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6, 0x00de,
+	0x0088, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085, 0x0100,
+	0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000, 0x2011, 0xad14,
+	0x2214, 0x22a2, 0x20a3, 0x0888, 0xa18d, 0x0008, 0x21a2, 0x080c,
+	0x7810, 0x22a2, 0x20a3, 0x0000, 0x7a08, 0x22a2, 0x2fa2, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x00c6,
+	0x0056, 0x0046, 0x0036, 0x2061, 0x0100, 0x2071, 0xad00, 0x7150,
+	0x7818, 0x2068, 0x68a0, 0x2028, 0x76d0, 0xd6ac, 0x1130, 0xd0bc,
+	0x1120, 0x6910, 0x6a14, 0x7450, 0x0020, 0x6910, 0x6a14, 0x736c,
+	0x7470, 0x781c, 0xa0be, 0x0006, 0x0904, 0x775b, 0xa0be, 0x000a,
+	0x15e8, 0xa185, 0x0200, 0x6062, 0x6266, 0x636a, 0x646e, 0x6073,
+	0x2029, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084, 0x00ff, 0x688e,
+	0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082, 0x7808, 0x6086,
+	0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6,
+	0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0x609f, 0x0000, 0x080c, 0x8014, 0x2009, 0x07d0, 0x60c4, 0xa084,
+	0xfff0, 0xa005, 0x0110, 0x2009, 0x1b58, 0x080c, 0x6586, 0x003e,
+	0x004e, 0x005e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x70d0, 0xd0ac,
+	0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a,
+	0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000,
+	0x646e, 0x6073, 0x0809, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084,
+	0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6082,
+	0x7808, 0x6086, 0x7810, 0x2070, 0x7014, 0x608a, 0x7010, 0x608e,
+	0x700c, 0x60c6, 0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5,
+	0x60d7, 0x0000, 0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120,
+	0x6a14, 0xa294, 0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c,
+	0x8014, 0x2009, 0x07d0, 0x60c4, 0xa084, 0xfff0, 0xa005, 0x0110,
+	0x2009, 0x1b58, 0x080c, 0x6586, 0x003e, 0x004e, 0x005e, 0x00ce,
+	0x00de, 0x00ee, 0x0005, 0x7810, 0x2070, 0x704c, 0xa084, 0x0003,
+	0xa086, 0x0002, 0x0904, 0x77b1, 0x2001, 0xad34, 0x2004, 0xd0ac,
+	0x1110, 0xd5bc, 0x0138, 0xa185, 0x0100, 0x6062, 0x6266, 0x636a,
+	0x646e, 0x0038, 0xa185, 0x0100, 0x6062, 0x6266, 0x606b, 0x0000,
+	0x646e, 0x6073, 0x0880, 0x6077, 0x0008, 0x688c, 0x8000, 0xa084,
+	0x00ff, 0x688e, 0x8007, 0x607a, 0x7834, 0x607e, 0x2f00, 0x6086,
+	0x7808, 0x6082, 0x7060, 0x608a, 0x705c, 0x608e, 0x7080, 0x60c6,
+	0x707c, 0x60ca, 0x707c, 0x792c, 0xa108, 0x792e, 0x7080, 0x7928,
+	0xa109, 0x792a, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294,
+	0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x080c, 0x8011, 0x0804,
+	0x7749, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x1110, 0xd5bc, 0x0138,
+	0xa185, 0x0700, 0x6062, 0x6266, 0x636a, 0x646e, 0x0038, 0xa185,
+	0x0700, 0x6062, 0x6266, 0x606b, 0x0000, 0x646e, 0x080c, 0x5025,
+	0x0180, 0x00d6, 0x7810, 0xa06d, 0x684c, 0x00de, 0xa084, 0x2020,
+	0xa086, 0x2020, 0x1130, 0x7820, 0xc0cd, 0x7822, 0x6073, 0x0889,
+	0x0010, 0x6073, 0x0898, 0x6077, 0x0000, 0x688c, 0x8000, 0xa084,
+	0x00ff, 0x688e, 0x8007, 0x607a, 0x607f, 0x0000, 0x2f00, 0x6086,
+	0x7808, 0x6082, 0x7014, 0x608a, 0x7010, 0x608e, 0x700c, 0x60c6,
+	0x7008, 0x60ca, 0x686c, 0x60ce, 0x60af, 0x95d5, 0x60d7, 0x0000,
+	0xa582, 0x0080, 0x0248, 0x6a00, 0xd2f4, 0x0120, 0x6a14, 0xa294,
+	0x00ff, 0x0010, 0x2011, 0x0000, 0x629e, 0x7820, 0xd0cc, 0x0120,
+	0x080c, 0x8014, 0x0804, 0x7749, 0x080c, 0x8011, 0x0804, 0x7749,
+	0x7a18, 0xa280, 0x0023, 0x2014, 0x8210, 0xa294, 0x00ff, 0x2202,
+	0x8217, 0x0005, 0x00d6, 0x2069, 0xafc7, 0x6843, 0x0001, 0x00de,
+	0x0005, 0x20e1, 0x9080, 0x60a3, 0x0056, 0x60a7, 0x9575, 0x0019,
+	0x080c, 0x6578, 0x0005, 0x0006, 0x6014, 0xa084, 0x0004, 0xa085,
+	0x0009, 0x6016, 0x000e, 0x0005, 0x0006, 0x00c6, 0x2061, 0x0100,
+	0x6014, 0xa084, 0x0004, 0xa085, 0x0008, 0x6016, 0x00ce, 0x000e,
+	0x0005, 0x00c6, 0x00d6, 0x0016, 0x0026, 0x2061, 0x0100, 0x2069,
+	0x0140, 0x080c, 0x574f, 0x1178, 0x2001, 0xafe3, 0x2004, 0xa005,
+	0x1598, 0x080c, 0x57d1, 0x1118, 0x080c, 0x6578, 0x0468, 0x00c6,
+	0x2061, 0xafc7, 0x00d8, 0x6904, 0xa194, 0x4000, 0x0550, 0x08a1,
+	0x6803, 0x1000, 0x6803, 0x0000, 0x00c6, 0x2061, 0xafc7, 0x6128,
+	0xa192, 0x00c8, 0x1258, 0x8108, 0x612a, 0x6124, 0x00ce, 0x81ff,
+	0x0198, 0x080c, 0x6578, 0x080c, 0x782b, 0x0070, 0x6124, 0xa1e5,
+	0x0000, 0x0140, 0x080c, 0xaca2, 0x2009, 0x0014, 0x080c, 0x80a7,
+	0x080c, 0x6581, 0x00ce, 0x0000, 0x002e, 0x001e, 0x00de, 0x00ce,
+	0x0005, 0x2001, 0xafe3, 0x2004, 0xa005, 0x1db0, 0x00c6, 0x2061,
+	0xafc7, 0x6128, 0xa192, 0x0003, 0x1e08, 0x8108, 0x612a, 0x00ce,
+	0x080c, 0x6578, 0x080c, 0x485e, 0x0c38, 0x00c6, 0x00d6, 0x00e6,
+	0x0016, 0x0026, 0x080c, 0x658e, 0x2071, 0xafc7, 0x713c, 0x81ff,
+	0x0570, 0x2061, 0x0100, 0x2069, 0x0140, 0x080c, 0x574f, 0x1188,
+	0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x003e, 0x713c, 0x2160,
+	0x080c, 0xaca2, 0x2009, 0x004a, 0x080c, 0x80a7, 0x080c, 0x57d1,
+	0x00b0, 0x6904, 0xa194, 0x4000, 0x01c0, 0x6803, 0x1000, 0x6803,
+	0x0000, 0x0036, 0x2019, 0x0001, 0x080c, 0x7a64, 0x003e, 0x713c,
+	0x2160, 0x080c, 0xaca2, 0x2009, 0x004a, 0x080c, 0x80a7, 0x002e,
+	0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x0c58, 0x00e6, 0x00d6,
+	0x00c6, 0x0066, 0x0056, 0x0046, 0x0006, 0x0126, 0x2091, 0x8000,
+	0x6018, 0x2068, 0x6ca0, 0x2071, 0xafc7, 0x7018, 0x2068, 0x8dff,
+	0x0198, 0x68a0, 0xa406, 0x0118, 0x6854, 0x2068, 0x0cc0, 0x6010,
+	0x2060, 0x643c, 0x6540, 0x6e48, 0x2d60, 0x080c, 0x4e41, 0x0120,
+	0x080c, 0x7b88, 0xa085, 0x0001, 0x012e, 0x000e, 0x004e, 0x005e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0x20a1, 0x020b, 0x080c,
+	0x710e, 0x20a3, 0x1200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x781c,
+	0xa086, 0x0004, 0x1110, 0x6098, 0x0018, 0x2001, 0xad14, 0x2004,
+	0x20a2, 0x7834, 0x20a2, 0x7838, 0x20a2, 0x20a9, 0x0010, 0xa006,
+	0x20a2, 0x1f04, 0x7928, 0x20a2, 0x20a2, 0x60c3, 0x002c, 0x080c,
+	0x7821, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x710e,
+	0x20a3, 0x0f00, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808, 0x20a2,
+	0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005, 0x0156,
+	0x0146, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0200, 0x20a3,
+	0x0000, 0x20a9, 0x0006, 0x2011, 0xad40, 0x2019, 0xad41, 0x23a6,
+	0x22a6, 0xa398, 0x0002, 0xa290, 0x0002, 0x1f04, 0x7957, 0x20a3,
+	0x0000, 0x20a3, 0x0000, 0x60c3, 0x001c, 0x080c, 0x7821, 0x014e,
+	0x015e, 0x0005, 0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b,
+	0x080c, 0x7183, 0x080c, 0x7199, 0x7810, 0xa080, 0x0000, 0x2004,
+	0xa080, 0x0015, 0x2098, 0x7808, 0xa088, 0x0002, 0x21a8, 0x53a6,
+	0xa080, 0x0004, 0x8003, 0x60c2, 0x080c, 0x7821, 0x002e, 0x001e,
+	0x014e, 0x015e, 0x0005, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c,
+	0x710e, 0x20a3, 0x6200, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x7808,
+	0x20a2, 0x60c3, 0x0008, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005,
+	0x0156, 0x0146, 0x0016, 0x0026, 0x20a1, 0x020b, 0x080c, 0x710e,
+	0x7810, 0xa080, 0x0000, 0x2004, 0xa080, 0x0017, 0x2098, 0x7808,
+	0xa088, 0x0002, 0x21a8, 0x53a6, 0x8003, 0x60c2, 0x080c, 0x7821,
+	0x002e, 0x001e, 0x014e, 0x015e, 0x0005, 0x00e6, 0x00c6, 0x0006,
+	0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x700c, 0x2060, 0x8cff,
+	0x0178, 0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x600c, 0x0006,
+	0x080c, 0x994e, 0x080c, 0x8078, 0x080c, 0x7b88, 0x00ce, 0x0c78,
+	0x700f, 0x0000, 0x700b, 0x0000, 0x012e, 0x000e, 0x00ce, 0x00ee,
+	0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0026,
+	0x0016, 0x0006, 0x2091, 0x8000, 0x2069, 0x0100, 0x2079, 0x0140,
+	0x2071, 0xafc7, 0x7024, 0x2060, 0x8cff, 0x05a0, 0x080c, 0x7834,
+	0x68c3, 0x0000, 0x080c, 0x6581, 0x2009, 0x0013, 0x080c, 0x80a7,
+	0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158, 0x6827, 0x0004, 0x7804,
+	0xa084, 0x4000, 0x01a0, 0x7803, 0x1000, 0x7803, 0x0000, 0x0078,
+	0xd084, 0x0118, 0x6827, 0x0001, 0x0010, 0x1f04, 0x7a02, 0x7804,
+	0xa084, 0x1000, 0x0120, 0x7803, 0x0100, 0x7803, 0x0000, 0x6824,
+	0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e,
+	0x012e, 0x0005, 0x2001, 0xad00, 0x2004, 0xa096, 0x0001, 0x0550,
+	0xa096, 0x0004, 0x0538, 0x6817, 0x0008, 0x68c3, 0x0000, 0x2011,
+	0x481b, 0x080c, 0x650d, 0x20a9, 0x01f4, 0x6824, 0xd094, 0x0158,
+	0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0, 0x7803, 0x1000,
+	0x7803, 0x0000, 0x0078, 0xd084, 0x0118, 0x6827, 0x0001, 0x0010,
+	0x1f04, 0x7a3d, 0x7804, 0xa084, 0x1000, 0x0120, 0x7803, 0x0100,
+	0x7803, 0x0000, 0x000e, 0x001e, 0x002e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x015e, 0x012e, 0x0005, 0x0126, 0x0156, 0x00f6, 0x00e6,
+	0x00d6, 0x00c6, 0x0026, 0x0016, 0x0006, 0x2091, 0x8000, 0x2069,
+	0x0100, 0x2079, 0x0140, 0x2071, 0xafc7, 0x703c, 0x2060, 0x8cff,
+	0x0904, 0x7ad5, 0x6817, 0x0010, 0x2009, 0x00fa, 0x8109, 0x1df0,
+	0x68c7, 0x0000, 0x68cb, 0x0008, 0x080c, 0x658e, 0x080c, 0x20b5,
+	0x0046, 0x2009, 0x017f, 0x200b, 0x00a5, 0x2021, 0x0169, 0x2404,
+	0xa084, 0x000f, 0xa086, 0x0004, 0x11b0, 0x68c7, 0x0000, 0x68cb,
+	0x0008, 0x00e6, 0x00f6, 0x2079, 0x0020, 0x2071, 0xb01e, 0x6814,
+	0xa084, 0x0184, 0xa085, 0x0012, 0x6816, 0x7803, 0x0008, 0x7003,
+	0x0000, 0x00fe, 0x00ee, 0x200b, 0x0000, 0x004e, 0xa39d, 0x0000,
+	0x1120, 0x2009, 0x0049, 0x080c, 0x80a7, 0x20a9, 0x03e8, 0x6824,
+	0xd094, 0x0158, 0x6827, 0x0004, 0x7804, 0xa084, 0x4000, 0x01a0,
+	0x7803, 0x1000, 0x7803, 0x0000, 0x0078, 0xd08c, 0x0118, 0x6827,
+	0x0002, 0x0010, 0x1f04, 0x7ab7, 0x7804, 0xa084, 0x1000, 0x0120,
+	0x7803, 0x0100, 0x7803, 0x0000, 0x6824, 0x000e, 0x001e, 0x002e,
+	0x00ce, 0x00de, 0x00ee, 0x00fe, 0x015e, 0x012e, 0x0005, 0x00d6,
+	0x0126, 0x2091, 0x8000, 0x2069, 0xafc7, 0x6a06, 0x012e, 0x00de,
+	0x0005, 0x00d6, 0x0126, 0x2091, 0x8000, 0x2069, 0xafc7, 0x6a32,
+	0x012e, 0x00de, 0x0005, 0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0006,
+	0x0126, 0x2071, 0xafc7, 0x7614, 0x2660, 0x2678, 0x2091, 0x8000,
+	0x8cff, 0x0538, 0x601c, 0xa206, 0x1500, 0x7014, 0xac36, 0x1110,
+	0x660c, 0x7616, 0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118,
+	0x2f00, 0x7012, 0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00,
+	0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x080c,
+	0x974e, 0x080c, 0x7b88, 0x00ce, 0x08d8, 0x2c78, 0x600c, 0x2060,
+	0x08b8, 0x012e, 0x000e, 0x006e, 0x00ce, 0x00ee, 0x00fe, 0x0005,
+	0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810, 0x20a2,
+	0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x1000, 0x0804,
+	0x7b80, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x4000,
+	0x0478, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x2000,
+	0x00f8, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0400,
+	0x0078, 0x0156, 0x0146, 0x20a1, 0x020b, 0x080c, 0x73cf, 0x7810,
+	0x20a2, 0xa006, 0x20a2, 0x20a2, 0x20a2, 0x20a2, 0x20a3, 0x0200,
+	0x0089, 0x60c3, 0x0020, 0x080c, 0x7821, 0x014e, 0x015e, 0x0005,
+	0x00e6, 0x2071, 0xafc7, 0x7020, 0xa005, 0x0110, 0x8001, 0x7022,
+	0x00ee, 0x0005, 0x20a9, 0x0008, 0x20a2, 0x1f04, 0x7b94, 0x20a2,
+	0x20a2, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6, 0x0076, 0x0066,
+	0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x7614, 0x2660,
+	0x2678, 0x2039, 0x0001, 0x87ff, 0x0904, 0x7c24, 0x8cff, 0x0904,
+	0x7c24, 0x601c, 0xa086, 0x0006, 0x1904, 0x7c1f, 0x88ff, 0x0138,
+	0x2800, 0xac06, 0x1904, 0x7c1f, 0x2039, 0x0000, 0x0050, 0x6018,
+	0xa206, 0x1904, 0x7c1f, 0x85ff, 0x0120, 0x6050, 0xa106, 0x1904,
+	0x7c1f, 0x7024, 0xac06, 0x1538, 0x2069, 0x0100, 0x68c0, 0xa005,
+	0x01f0, 0x080c, 0x6581, 0x6817, 0x0008, 0x68c3, 0x0000, 0x080c,
+	0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140, 0x6b04, 0xa384,
+	0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000, 0x2069, 0x0100,
+	0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e, 0x0020, 0x6003,
+	0x0009, 0x630a, 0x0460, 0x7014, 0xac36, 0x1110, 0x660c, 0x7616,
+	0x7010, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7012,
+	0x0010, 0x7013, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x89ff, 0x1158, 0x600f, 0x0000, 0x6010,
+	0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0xa91f, 0x080c, 0x974e,
+	0x080c, 0x7b88, 0x88ff, 0x1190, 0x00ce, 0x0804, 0x7bab, 0x2c78,
+	0x600c, 0x2060, 0x0804, 0x7bab, 0xa006, 0x012e, 0x000e, 0x006e,
+	0x007e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x6017, 0x0000,
+	0x00ce, 0xa8c5, 0x0001, 0x0c88, 0x00f6, 0x00e6, 0x00d6, 0x00c6,
+	0x0066, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7,
+	0x7638, 0x2660, 0x2678, 0x8cff, 0x0904, 0x7c98, 0x601c, 0xa086,
+	0x0006, 0x1904, 0x7c93, 0x87ff, 0x0128, 0x2700, 0xac06, 0x1904,
+	0x7c93, 0x0040, 0x6018, 0xa206, 0x15f0, 0x85ff, 0x0118, 0x6050,
+	0xa106, 0x15c8, 0x703c, 0xac06, 0x1170, 0x0036, 0x2019, 0x0001,
+	0x080c, 0x7a64, 0x7033, 0x0000, 0x703f, 0x0000, 0x7043, 0x0000,
+	0x7047, 0x0000, 0x003e, 0x7038, 0xac36, 0x1110, 0x660c, 0x763a,
+	0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00, 0x7036,
+	0x0010, 0x7037, 0x0000, 0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0x6010, 0x2068, 0x080c,
+	0x9596, 0x0110, 0x080c, 0xa91f, 0x080c, 0x974e, 0x87ff, 0x1190,
+	0x00ce, 0x0804, 0x7c43, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7c43,
+	0xa006, 0x012e, 0x000e, 0x002e, 0x006e, 0x00ce, 0x00de, 0x00ee,
+	0x00fe, 0x0005, 0x6017, 0x0000, 0x00ce, 0xa7bd, 0x0001, 0x0c88,
+	0x00e6, 0x2071, 0xafc7, 0x2001, 0xad00, 0x2004, 0xa086, 0x0002,
+	0x1118, 0x7007, 0x0005, 0x0010, 0x7007, 0x0000, 0x00ee, 0x0005,
+	0x00f6, 0x00e6, 0x00c6, 0x0066, 0x0026, 0x0006, 0x0126, 0x2091,
+	0x8000, 0x2071, 0xafc7, 0x2c10, 0x7638, 0x2660, 0x2678, 0x8cff,
+	0x0518, 0x2200, 0xac06, 0x11e0, 0x7038, 0xac36, 0x1110, 0x660c,
+	0x763a, 0x7034, 0xac36, 0x1140, 0x2c00, 0xaf36, 0x0118, 0x2f00,
+	0x7036, 0x0010, 0x7037, 0x0000, 0x660c, 0x2c00, 0xaf06, 0x0110,
+	0x7e0e, 0x0008, 0x2678, 0x600f, 0x0000, 0xa085, 0x0001, 0x0020,
+	0x2c78, 0x600c, 0x2060, 0x08d8, 0x012e, 0x000e, 0x002e, 0x006e,
+	0x00ce, 0x00ee, 0x00fe, 0x0005, 0x00f6, 0x00e6, 0x00d6, 0x00c6,
+	0x0066, 0x0006, 0x0126, 0x2091, 0x8000, 0x2071, 0xafc7, 0x760c,
+	0x2660, 0x2678, 0x8cff, 0x0904, 0x7d7e, 0x6018, 0xa080, 0x0028,
+	0x2004, 0xa206, 0x1904, 0x7d79, 0x7024, 0xac06, 0x1508, 0x2069,
+	0x0100, 0x68c0, 0xa005, 0x0904, 0x7d55, 0x080c, 0x7834, 0x68c3,
+	0x0000, 0x080c, 0x7ca8, 0x7027, 0x0000, 0x0036, 0x2069, 0x0140,
+	0x6b04, 0xa384, 0x1000, 0x0120, 0x6803, 0x0100, 0x6803, 0x0000,
+	0x2069, 0x0100, 0x6824, 0xd084, 0x0110, 0x6827, 0x0001, 0x003e,
+	0x700c, 0xac36, 0x1110, 0x660c, 0x760e, 0x7008, 0xac36, 0x1140,
+	0x2c00, 0xaf36, 0x0118, 0x2f00, 0x700a, 0x0010, 0x700b, 0x0000,
+	0x660c, 0x0066, 0x2c00, 0xaf06, 0x0110, 0x7e0e, 0x0008, 0x2678,
+	0x600f, 0x0000, 0x080c, 0x9778, 0x1158, 0x080c, 0x2aff, 0x080c,
+	0x9789, 0x11f0, 0x080c, 0x85f3, 0x00d8, 0x080c, 0x7ca8, 0x08c0,
+	0x080c, 0x9789, 0x1118, 0x080c, 0x85f3, 0x0090, 0x6010, 0x2068,
+	0x080c, 0x9596, 0x0168, 0x601c, 0xa086, 0x0003, 0x11f8, 0x6837,
+	0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c, 0x080c, 0x9742,
+	0x080c, 0x994e, 0x080c, 0x974e, 0x080c, 0x7b88, 0x00ce, 0x0804,
+	0x7d02, 0x2c78, 0x600c, 0x2060, 0x0804, 0x7d02, 0x012e, 0x000e,
+	0x006e, 0x00ce, 0x00de, 0x00ee, 0x00fe, 0x0005, 0x601c, 0xa086,
+	0x0006, 0x1d30, 0x080c, 0xa91f, 0x0c18, 0x0036, 0x0156, 0x0136,
+	0x0146, 0x3908, 0xa006, 0xa190, 0x0020, 0x221c, 0xa39e, 0x28f9,
+	0x1118, 0x8210, 0x8000, 0x0cc8, 0xa005, 0x0138, 0x20a9, 0x0020,
+	0x2198, 0xa110, 0x22a0, 0x22c8, 0x53a3, 0x014e, 0x013e, 0x015e,
+	0x003e, 0x0005, 0x00d6, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3,
+	0x0200, 0x20a3, 0x0014, 0x60c3, 0x0014, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x2099, 0xafa6, 0x20a9, 0x0004, 0x53a6, 0x20a3, 0x0004,
+	0x20a3, 0x7878, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x080c, 0x7821,
+	0x00de, 0x0005, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3, 0x0214,
+	0x20a3, 0x0018, 0x20a3, 0x0800, 0x7810, 0xa084, 0xff00, 0x20a2,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x20a3, 0x0000,
+	0x7810, 0xa084, 0x00ff, 0x20a2, 0x7828, 0x20a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x60c3, 0x0018, 0x080c, 0x7821, 0x0005, 0x00d6,
+	0x0016, 0x2f68, 0x2009, 0x0035, 0x080c, 0x9a34, 0x1904, 0x7e5d,
+	0x20a1, 0x020b, 0x080c, 0x710e, 0x20a3, 0x1300, 0x20a3, 0x0000,
+	0x7828, 0x2068, 0x681c, 0xa086, 0x0003, 0x0580, 0x7818, 0xa080,
+	0x0028, 0x2014, 0x2001, 0xad34, 0x2004, 0xd0ac, 0x11d0, 0xa286,
+	0x007e, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffe, 0x04b8, 0xa286,
+	0x007f, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffd, 0x0478, 0xd2bc,
+	0x0180, 0xa286, 0x0080, 0x1128, 0x20a3, 0x00ff, 0x20a3, 0xfffc,
+	0x0428, 0xa2e8, 0xae34, 0x2d6c, 0x6810, 0x20a2, 0x6814, 0x20a2,
+	0x00e8, 0x20a3, 0x0000, 0x6098, 0x20a2, 0x00c0, 0x2001, 0xad34,
+	0x2004, 0xd0ac, 0x1138, 0x7818, 0xa080, 0x0028, 0x2004, 0xa082,
+	0x007e, 0x0240, 0x00d6, 0x2069, 0xad1b, 0x2da6, 0x8d68, 0x2da6,
+	0x00de, 0x0020, 0x20a3, 0x0000, 0x6034, 0x20a2, 0x7834, 0x20a2,
+	0x7838, 0x20a2, 0x20a3, 0x0000, 0x20a3, 0x0000, 0x60c3, 0x000c,
+	0x080c, 0x7821, 0x001e, 0x00de, 0x0005, 0x7817, 0x0001, 0x7803,
+	0x0006, 0x001e, 0x00de, 0x0005, 0x00d6, 0x0026, 0x7928, 0x2168,
+	0x691c, 0xa186, 0x0006, 0x01c0, 0xa186, 0x0003, 0x0904, 0x7ed3,
+	0xa186, 0x0005, 0x0904, 0x7ebc, 0xa186, 0x0004, 0x05b8, 0xa186,
+	0x0008, 0x0904, 0x7ec4, 0x7807, 0x0037, 0x7813, 0x1700, 0x080c,
+	0x7f3b, 0x002e, 0x00de, 0x0005, 0x080c, 0x7ef7, 0x2009, 0x4000,
+	0x6800, 0x0002, 0x7e9d, 0x7ea8, 0x7e9f, 0x7ea8, 0x7ea4, 0x7e9d,
+	0x7e9d, 0x7ea8, 0x7ea8, 0x7ea8, 0x7ea8, 0x7e9d, 0x7e9d, 0x7e9d,
+	0x7e9d, 0x7e9d, 0x7ea8, 0x7e9d, 0x7ea8, 0x080c, 0x14f6, 0x6820,
+	0xd0e4, 0x0110, 0xd0cc, 0x0110, 0xa00e, 0x0010, 0x2009, 0x2000,
+	0x6828, 0x20a2, 0x682c, 0x20a2, 0x0804, 0x7eed, 0x080c, 0x7ef7,
+	0x20a3, 0x0000, 0x20a3, 0x0000, 0x2009, 0x4000, 0x6a00, 0xa286,
+	0x0002, 0x1108, 0xa00e, 0x0488, 0x04d1, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x2009, 0x4000, 0x0448, 0x0491, 0x20a3, 0x0000, 0x20a3,
+	0x0000, 0x2009, 0x4000, 0xa286, 0x0005, 0x0118, 0xa286, 0x0002,
+	0x1108, 0xa00e, 0x00d0, 0x0419, 0x6810, 0x2068, 0x697c, 0x6810,
+	0xa112, 0x6980, 0x6814, 0xa103, 0x20a2, 0x22a2, 0x7928, 0xa180,
+	0x0000, 0x2004, 0xa08e, 0x0002, 0x0130, 0xa08e, 0x0004, 0x0118,
+	0x2009, 0x4000, 0x0010, 0x2009, 0x0000, 0x21a2, 0x20a3, 0x0000,
+	0x60c3, 0x0018, 0x080c, 0x7821, 0x002e, 0x00de, 0x0005, 0x0036,
+	0x0046, 0x0056, 0x0066, 0x20a1, 0x020b, 0x080c, 0x71aa, 0xa006,
+	0x20a3, 0x0200, 0x20a2, 0x7934, 0x21a2, 0x7938, 0x21a2, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1118,
+	0xa092, 0x007e, 0x0268, 0x00d6, 0x2069, 0xad1b, 0x2d2c, 0x8d68,
+	0x2d34, 0xa0e8, 0xae34, 0x2d6c, 0x6b10, 0x6c14, 0x00de, 0x0030,
+	0x2019, 0x0000, 0x6498, 0x2029, 0x0000, 0x6634, 0x7828, 0xa080,
+	0x0007, 0x2004, 0xa086, 0x0003, 0x1128, 0x25a2, 0x26a2, 0x23a2,
+	0x24a2, 0x0020, 0x23a2, 0x24a2, 0x25a2, 0x26a2, 0x006e, 0x005e,
+	0x004e, 0x003e, 0x0005, 0x20a1, 0x020b, 0x080c, 0x71aa, 0x20a3,
+	0x0100, 0x20a3, 0x0000, 0x20a3, 0x0009, 0x7810, 0x20a2, 0x60c3,
+	0x0008, 0x080c, 0x7821, 0x0005, 0x20a1, 0x020b, 0x080c, 0x7106,
+	0x20a3, 0x1400, 0x20a3, 0x0000, 0x7834, 0x20a2, 0x7838, 0x20a2,
+	0x7828, 0x20a2, 0x782c, 0x20a2, 0x7830, 0xa084, 0x00ff, 0x8007,
+	0x20a2, 0x20a3, 0x0000, 0x60c3, 0x0010, 0x080c, 0x7821, 0x0005,
+	0x20a1, 0x020b, 0x080c, 0x71a2, 0x20a3, 0x0100, 0x20a3, 0x0000,
+	0x7828, 0x20a2, 0x7810, 0x20a2, 0x60c3, 0x0008, 0x080c, 0x7821,
+	0x0005, 0x0146, 0x20a1, 0x020b, 0x0031, 0x60c3, 0x0000, 0x080c,
+	0x7821, 0x014e, 0x0005, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7818,
+	0xa080, 0x0028, 0x2004, 0x2011, 0xad34, 0x2214, 0xd2ac, 0x1110,
+	0xd0bc, 0x0188, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810, 0xa085,
+	0x0300, 0x20a2, 0x6814, 0x20a2, 0x2069, 0xad1b, 0x2da6, 0x8d68,
+	0x2da6, 0x00de, 0x0078, 0x00d6, 0xa0e8, 0xae34, 0x2d6c, 0x6810,
+	0xa085, 0x0300, 0x20a2, 0x6814, 0x20a2, 0x00de, 0x20a3, 0x0000,
+	0x6234, 0x22a2, 0x20a3, 0x0819, 0x20a3, 0x0000, 0x080c, 0x7810,
+	0x22a2, 0x20a3, 0x0000, 0x2fa2, 0x7a08, 0x22a2, 0x20a3, 0x0000,
+	0x20a3, 0x0000, 0x0005, 0x20a1, 0x020b, 0x0079, 0x7910, 0x21a2,
+	0x20a3, 0x0000, 0x60c3, 0x0000, 0x20e1, 0x9080, 0x60a7, 0x9575,
+	0x080c, 0x782b, 0x080c, 0x6578, 0x0005, 0x0156, 0x0136, 0x0036,
+	0x00d6, 0x00e6, 0x20e1, 0x9080, 0x20e1, 0x4000, 0x7854, 0x2068,
+	0xadf0, 0x000f, 0x7210, 0xa296, 0x00c0, 0xa294, 0xfffd, 0x7212,
+	0x7214, 0xa294, 0x0300, 0x7216, 0x7100, 0xa194, 0x00ff, 0x7308,
+	0xa384, 0x00ff, 0xa08d, 0xc200, 0x7102, 0xa384, 0xff00, 0xa215,
+	0x720a, 0x7004, 0x720c, 0x700e, 0x7206, 0x20a9, 0x000a, 0x2e98,
+	0x53a6, 0x60a3, 0x0035, 0x6a38, 0xa294, 0x7000, 0xa286, 0x3000,
+	0x0110, 0x60a3, 0x0037, 0x00ee, 0x00de, 0x003e, 0x013e, 0x015e,
+	0x0005, 0x2009, 0x0092, 0x0010, 0x2009, 0x0096, 0x60ab, 0x0036,
+	0x6116, 0x0005, 0x2061, 0xb400, 0x2a70, 0x7064, 0x7046, 0x704b,
+	0xb400, 0x0005, 0x00e6, 0x0126, 0x2071, 0xad00, 0x2091, 0x8000,
+	0x7544, 0xa582, 0x0010, 0x0608, 0x7048, 0x2060, 0x6000, 0xa086,
+	0x0000, 0x0148, 0xace0, 0x0018, 0x7058, 0xac02, 0x1208, 0x0cb0,
+	0x2061, 0xb400, 0x0c98, 0x6003, 0x0008, 0x8529, 0x7546, 0xaca8,
+	0x0018, 0x7058, 0xa502, 0x1230, 0x754a, 0xa085, 0x0001, 0x012e,
+	0x00ee, 0x0005, 0x704b, 0xb400, 0x0cc0, 0xa006, 0x0cc0, 0x00e6,
+	0x2071, 0xad00, 0x7544, 0xa582, 0x0010, 0x0600, 0x7048, 0x2060,
+	0x6000, 0xa086, 0x0000, 0x0148, 0xace0, 0x0018, 0x7058, 0xac02,
+	0x1208, 0x0cb0, 0x2061, 0xb400, 0x0c98, 0x6003, 0x0008, 0x8529,
+	0x7546, 0xaca8, 0x0018, 0x7058, 0xa502, 0x1228, 0x754a, 0xa085,
+	0x0001, 0x00ee, 0x0005, 0x704b, 0xb400, 0x0cc8, 0xa006, 0x0cc8,
+	0xac82, 0xb400, 0x0a0c, 0x14f6, 0x2001, 0xad16, 0x2004, 0xac02,
+	0x1a0c, 0x14f6, 0xa006, 0x6006, 0x600a, 0x600e, 0x6012, 0x6016,
+	0x601a, 0x601f, 0x0000, 0x6003, 0x0000, 0x6052, 0x6056, 0x6022,
+	0x6026, 0x602a, 0x602e, 0x6032, 0x6036, 0x603a, 0x603e, 0x2061,
+	0xad00, 0x6044, 0x8000, 0x6046, 0xa086, 0x0001, 0x0108, 0x0005,
+	0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0cc0, 0x601c,
+	0xa084, 0x000f, 0x0002, 0x80b6, 0x80c5, 0x80e0, 0x80fb, 0x9a61,
+	0x9a7c, 0x9a97, 0x80b6, 0x80c5, 0x80b6, 0x8116, 0xa186, 0x0013,
+	0x1128, 0x080c, 0x6b73, 0x080c, 0x6c50, 0x0005, 0xa18e, 0x0047,
+	0x1118, 0xa016, 0x080c, 0x1824, 0x0005, 0x0066, 0x6000, 0xa0b2,
+	0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x80de, 0x8478,
+	0x862d, 0x80de, 0x86a2, 0x81cf, 0x80de, 0x80de, 0x840a, 0x8a91,
+	0x80de, 0x80de, 0x80de, 0x80de, 0x80de, 0x80de, 0x080c, 0x14f6,
+	0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e,
+	0x0005, 0x80f9, 0x909a, 0x80f9, 0x80f9, 0x80f9, 0x80f9, 0x80f9,
+	0x80f9, 0x9045, 0x9200, 0x80f9, 0x90c7, 0x913e, 0x90c7, 0x913e,
+	0x80f9, 0x080c, 0x14f6, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c,
+	0x14f6, 0x0013, 0x006e, 0x0005, 0x8114, 0x8ad2, 0x8b98, 0x8cb8,
+	0x8e12, 0x8114, 0x8114, 0x8114, 0x8aac, 0x8ff5, 0x8ff8, 0x8114,
+	0x8114, 0x8114, 0x8114, 0x9022, 0x080c, 0x14f6, 0x0066, 0x6000,
+	0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x812f,
+	0x812f, 0x812f, 0x8152, 0x81a5, 0x812f, 0x812f, 0x812f, 0x8131,
+	0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x812f, 0x080c,
+	0x14f6, 0xa186, 0x0003, 0x190c, 0x14f6, 0x00d6, 0x6003, 0x0003,
+	0x6106, 0x6010, 0x2068, 0x684f, 0x0040, 0x687c, 0x680a, 0x6880,
+	0x680e, 0x6813, 0x0000, 0x6817, 0x0000, 0x00de, 0x2c10, 0x080c,
+	0x1e6e, 0x080c, 0x680b, 0x0126, 0x2091, 0x8000, 0x080c, 0x6d0d,
+	0x012e, 0x0005, 0xa182, 0x0047, 0x0002, 0x815e, 0x815e, 0x8160,
+	0x817f, 0x815e, 0x815e, 0x815e, 0x815e, 0x8191, 0x080c, 0x14f6,
+	0x00d6, 0x0016, 0x080c, 0x6c05, 0x080c, 0x6d0d, 0x6003, 0x0004,
+	0x6110, 0x2168, 0x6854, 0x8003, 0x800b, 0x810b, 0xa108, 0x6116,
+	0x684f, 0x0020, 0x685c, 0x685a, 0x6874, 0x687e, 0x6878, 0x6882,
+	0x6897, 0x0000, 0x689b, 0x0000, 0x001e, 0x00de, 0x0005, 0x080c,
+	0x6c05, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9596, 0x0120, 0x684b,
+	0x0006, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x080c, 0x6d0d,
+	0x0005, 0x080c, 0x6c05, 0x080c, 0x2ad9, 0x00d6, 0x6110, 0x2168,
+	0x080c, 0x9596, 0x0120, 0x684b, 0x0029, 0x080c, 0x510c, 0x00de,
+	0x080c, 0x8078, 0x080c, 0x6d0d, 0x0005, 0xa182, 0x0047, 0x0002,
+	0x81b3, 0x81c2, 0x81b1, 0x81b1, 0x81b1, 0x81b1, 0x81b1, 0x81b1,
+	0x81b1, 0x080c, 0x14f6, 0x00d6, 0x6010, 0x2068, 0x684c, 0xc0f4,
+	0x684e, 0x00de, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c,
+	0x1824, 0x0005, 0x00d6, 0x6110, 0x2168, 0x684b, 0x0000, 0x6853,
+	0x0000, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x0005, 0xa1b6,
+	0x0015, 0x1118, 0x080c, 0x8078, 0x0030, 0xa1b6, 0x0016, 0x190c,
+	0x14f6, 0x080c, 0x8078, 0x0005, 0x20a9, 0x000e, 0x2e98, 0x6010,
+	0x20a0, 0x53a3, 0x20a9, 0x0006, 0x3310, 0x3420, 0x9398, 0x94a0,
+	0x3318, 0x3428, 0x222e, 0x2326, 0xa290, 0x0002, 0xa5a8, 0x0002,
+	0xa398, 0x0002, 0xa4a0, 0x0002, 0x1f04, 0x81ea, 0x00e6, 0x080c,
+	0x9596, 0x0130, 0x6010, 0x2070, 0x7007, 0x0000, 0x7037, 0x0103,
+	0x00ee, 0x080c, 0x8078, 0x0005, 0x00d6, 0x0036, 0x7330, 0xa386,
+	0x0200, 0x1130, 0x6018, 0x2068, 0x6813, 0x00ff, 0x6817, 0xfffd,
+	0x6010, 0xa005, 0x0130, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103,
+	0x6b32, 0x080c, 0x8078, 0x003e, 0x00de, 0x0005, 0x0016, 0x20a9,
+	0x002a, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0,
+	0x53a3, 0x20a9, 0x002a, 0x6010, 0xa080, 0x0001, 0x2004, 0xa080,
+	0x0002, 0x20a0, 0x53a3, 0x00e6, 0x6010, 0x2004, 0x2070, 0x7037,
+	0x0103, 0x00ee, 0x080c, 0x8078, 0x001e, 0x0005, 0x0016, 0x2009,
+	0x0000, 0x7030, 0xa086, 0x0100, 0x0140, 0x7038, 0xa084, 0x00ff,
+	0x808e, 0x703c, 0xa084, 0x00ff, 0x8086, 0xa080, 0x0004, 0xa108,
+	0x21a8, 0xae80, 0x000c, 0x2098, 0x6010, 0xa080, 0x0002, 0x20a0,
+	0x080c, 0x48be, 0x00e6, 0x080c, 0x9596, 0x0140, 0x6010, 0x2070,
+	0x7007, 0x0000, 0x7034, 0x70b2, 0x7037, 0x0103, 0x00ee, 0x080c,
+	0x8078, 0x001e, 0x0005, 0x00e6, 0x00d6, 0x603f, 0x0000, 0x2c68,
+	0x0016, 0x2009, 0x0035, 0x080c, 0x9a34, 0x001e, 0x1168, 0x0026,
+	0x6228, 0x2268, 0x002e, 0x2071, 0xb28c, 0x6b1c, 0xa386, 0x0003,
+	0x0130, 0xa386, 0x0006, 0x0128, 0x080c, 0x8078, 0x0020, 0x0031,
+	0x0010, 0x080c, 0x8323, 0x00de, 0x00ee, 0x0005, 0x00f6, 0x6810,
+	0x2078, 0xa186, 0x0015, 0x0904, 0x830c, 0xa18e, 0x0016, 0x1904,
+	0x8321, 0x700c, 0xa084, 0xff00, 0xa086, 0x1700, 0x1904, 0x82eb,
+	0x8fff, 0x0904, 0x831f, 0x6808, 0xa086, 0xffff, 0x1904, 0x830e,
+	0x784c, 0xa084, 0x0060, 0xa086, 0x0020, 0x1150, 0x797c, 0x7810,
+	0xa106, 0x1904, 0x830e, 0x7980, 0x7814, 0xa106, 0x1904, 0x830e,
+	0x080c, 0x9742, 0x6858, 0x7852, 0x784c, 0xc0dc, 0xc0f4, 0xc0d4,
+	0x784e, 0x0026, 0xa00e, 0x6a14, 0x2001, 0x000a, 0x080c, 0x6665,
+	0x7854, 0xa20a, 0x0208, 0x8011, 0x7a56, 0x82ff, 0x002e, 0x1138,
+	0x00c6, 0x2d60, 0x080c, 0x9374, 0x00ce, 0x0804, 0x831f, 0x00c6,
+	0x00d6, 0x2f68, 0x6838, 0xd0fc, 0x1118, 0x080c, 0x4993, 0x0010,
+	0x080c, 0x4b7c, 0x00de, 0x00ce, 0x1548, 0x00c6, 0x2d60, 0x080c,
+	0x8078, 0x00ce, 0x04a0, 0x7008, 0xa086, 0x000b, 0x11a0, 0x6018,
+	0x200c, 0xc1bc, 0x2102, 0x00c6, 0x2d60, 0x7853, 0x0003, 0x6007,
+	0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x67a8, 0x080c,
+	0x6c50, 0x00ce, 0x00e0, 0x700c, 0xa086, 0x2a00, 0x1138, 0x2001,
+	0xafa5, 0x2004, 0x683e, 0x0098, 0x0471, 0x0098, 0x8fff, 0x090c,
+	0x14f6, 0x00c6, 0x00d6, 0x2d60, 0x2f68, 0x684b, 0x0003, 0x080c,
+	0x926f, 0x080c, 0x9742, 0x080c, 0x974e, 0x00de, 0x00ce, 0x080c,
+	0x8078, 0x00fe, 0x0005, 0xa186, 0x0015, 0x1128, 0x2001, 0xafa5,
+	0x2004, 0x683e, 0x0068, 0xa18e, 0x0016, 0x1160, 0x00c6, 0x2d00,
+	0x2060, 0x080c, 0xabb4, 0x080c, 0x6618, 0x080c, 0x8078, 0x00ce,
+	0x080c, 0x8078, 0x0005, 0x0026, 0x0036, 0x0046, 0x7228, 0x7c80,
+	0x7b7c, 0xd2f4, 0x0130, 0x2001, 0xafa5, 0x2004, 0x683e, 0x0804,
+	0x839d, 0x00c6, 0x2d60, 0x080c, 0x928f, 0x00ce, 0x6804, 0xa086,
+	0x0050, 0x1168, 0x00c6, 0x2d00, 0x2060, 0x6003, 0x0001, 0x6007,
+	0x0050, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ce, 0x04f0, 0x6800,
+	0xa086, 0x000f, 0x01c8, 0x8fff, 0x090c, 0x14f6, 0x6820, 0xd0dc,
+	0x1198, 0x6800, 0xa086, 0x0004, 0x1198, 0x784c, 0xd0ac, 0x0180,
+	0x784c, 0xc0dc, 0xc0f4, 0x784e, 0x7850, 0xc0f4, 0xc0fc, 0x7852,
+	0x2001, 0x0001, 0x682e, 0x00e0, 0x2001, 0x0007, 0x682e, 0x00c0,
+	0x784c, 0xd0b4, 0x1130, 0xd0ac, 0x0db8, 0x784c, 0xd0f4, 0x1da0,
+	0x0c38, 0xd2ec, 0x1d88, 0x7024, 0xa306, 0x1118, 0x7020, 0xa406,
+	0x0d58, 0x7020, 0x6836, 0x7024, 0x683a, 0x2001, 0x0005, 0x682e,
+	0x080c, 0x9894, 0x080c, 0x6c50, 0x0010, 0x080c, 0x8078, 0x004e,
+	0x003e, 0x002e, 0x0005, 0x00e6, 0x00d6, 0x0026, 0x6034, 0x2068,
+	0x6a1c, 0xa286, 0x0007, 0x0904, 0x83ee, 0xa286, 0x0002, 0x05f0,
+	0xa286, 0x0000, 0x05d8, 0x6808, 0x6338, 0xa306, 0x15b8, 0x2071,
+	0xb28c, 0xa186, 0x0015, 0x0560, 0xa18e, 0x0016, 0x1190, 0x6030,
+	0xa084, 0x00ff, 0xa086, 0x0001, 0x1160, 0x700c, 0xa086, 0x2a00,
+	0x1140, 0x6034, 0xa080, 0x0008, 0x200c, 0xc1dd, 0xc1f5, 0x2102,
+	0x00b8, 0x00c6, 0x6034, 0x2060, 0x6010, 0x2068, 0x080c, 0x9596,
+	0x090c, 0x14f6, 0x6853, 0x0003, 0x6007, 0x0085, 0x6003, 0x000b,
+	0x601f, 0x0002, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ce, 0x0030,
+	0x6034, 0x2070, 0x2001, 0xafa5, 0x2004, 0x703e, 0x080c, 0x8078,
+	0x002e, 0x00de, 0x00ee, 0x0005, 0x00d6, 0x20a9, 0x000e, 0x2e98,
+	0x6010, 0x20a0, 0x53a3, 0xa1b6, 0x0015, 0x1148, 0x6018, 0x2068,
+	0x7038, 0x680a, 0x703c, 0x680e, 0x6800, 0xc08d, 0x6802, 0x00de,
+	0x0804, 0x81f6, 0x2100, 0xa1b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b2,
+	0x0040, 0x1a04, 0x846e, 0x0002, 0x8462, 0x8456, 0x8462, 0x8462,
+	0x8462, 0x8462, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454,
+	0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454,
+	0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454,
+	0x8454, 0x8454, 0x8454, 0x8462, 0x8454, 0x8462, 0x8462, 0x8454,
+	0x8454, 0x8454, 0x8454, 0x8454, 0x8462, 0x8454, 0x8454, 0x8454,
+	0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8462, 0x8462,
+	0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454, 0x8454,
+	0x8454, 0x8462, 0x8454, 0x8454, 0x080c, 0x14f6, 0x6003, 0x0001,
+	0x6106, 0x080c, 0x67ee, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50,
+	0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c, 0x67ee, 0x0126,
+	0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0005, 0x2600, 0x0002,
+	0x8462, 0x8476, 0x8476, 0x8462, 0x8462, 0x8476, 0x080c, 0x14f6,
+	0x6004, 0xa0b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b6, 0x0013, 0x0904,
+	0x8518, 0xa1b6, 0x0027, 0x1904, 0x84de, 0x080c, 0x6b73, 0x6004,
+	0x080c, 0x9778, 0x0188, 0x080c, 0x9789, 0x0904, 0x84d8, 0xa08e,
+	0x0021, 0x0904, 0x84db, 0xa08e, 0x0022, 0x0904, 0x84d8, 0xa08e,
+	0x003d, 0x0904, 0x84db, 0x04a8, 0x080c, 0x2aff, 0x2001, 0x0007,
+	0x080c, 0x4c30, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x85f3,
+	0xa186, 0x007e, 0x1148, 0x2001, 0xad34, 0x2014, 0xc285, 0x080c,
+	0x574f, 0x1108, 0xc2ad, 0x2202, 0x0016, 0x0026, 0x0036, 0x2110,
+	0x2019, 0x0028, 0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c,
+	0x681d, 0x00c6, 0x6018, 0xa065, 0x0110, 0x080c, 0x4ecf, 0x00ce,
+	0x2c08, 0x080c, 0xa712, 0x007e, 0x003e, 0x002e, 0x001e, 0x080c,
+	0x4c9f, 0x080c, 0x994e, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005,
+	0x080c, 0x85f3, 0x0cb0, 0x080c, 0x8621, 0x0c98, 0xa186, 0x0014,
+	0x1db0, 0x080c, 0x6b73, 0x080c, 0x2ad9, 0x080c, 0x9778, 0x1188,
+	0x080c, 0x2aff, 0x6018, 0xa080, 0x0028, 0x200c, 0x080c, 0x85f3,
+	0xa186, 0x007e, 0x1128, 0x2001, 0xad34, 0x200c, 0xc185, 0x2102,
+	0x08c0, 0x080c, 0x9789, 0x1118, 0x080c, 0x85f3, 0x0890, 0x6004,
+	0xa08e, 0x0032, 0x1158, 0x00e6, 0x00f6, 0x2071, 0xad81, 0x2079,
+	0x0000, 0x080c, 0x2df1, 0x00fe, 0x00ee, 0x0818, 0x6004, 0xa08e,
+	0x0021, 0x0d50, 0xa08e, 0x0022, 0x090c, 0x85f3, 0x0804, 0x84d1,
+	0xa0b2, 0x0040, 0x1a04, 0x85db, 0x2008, 0x0002, 0x8560, 0x8561,
+	0x8564, 0x8567, 0x856a, 0x856d, 0x855e, 0x855e, 0x855e, 0x855e,
+	0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e,
+	0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e,
+	0x855e, 0x855e, 0x855e, 0x855e, 0x8570, 0x857f, 0x855e, 0x8581,
+	0x857f, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x857f, 0x857f,
+	0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e, 0x855e,
+	0x85bb, 0x857f, 0x855e, 0x857b, 0x855e, 0x855e, 0x855e, 0x857c,
+	0x855e, 0x855e, 0x855e, 0x857f, 0x85b2, 0x855e, 0x080c, 0x14f6,
+	0x00f0, 0x2001, 0x000b, 0x0460, 0x2001, 0x0003, 0x0448, 0x2001,
+	0x0005, 0x0430, 0x2001, 0x0001, 0x0418, 0x2001, 0x0009, 0x0400,
+	0x080c, 0x6b73, 0x6003, 0x0005, 0x2001, 0xafa5, 0x2004, 0x603e,
+	0x080c, 0x6c50, 0x00a0, 0x0018, 0x0010, 0x080c, 0x4c30, 0x0804,
+	0x85cc, 0x080c, 0x6b73, 0x2001, 0xafa3, 0x2004, 0x6016, 0x2001,
+	0xafa5, 0x2004, 0x603e, 0x6003, 0x0004, 0x080c, 0x6c50, 0x0005,
+	0x080c, 0x4c30, 0x080c, 0x6b73, 0x6003, 0x0002, 0x2001, 0xafa5,
+	0x2004, 0x603e, 0x0036, 0x2019, 0xad5c, 0x2304, 0xa084, 0xff00,
+	0x1120, 0x2001, 0xafa3, 0x201c, 0x0040, 0x8007, 0xa09a, 0x0004,
+	0x0ec0, 0x8003, 0x801b, 0x831b, 0xa318, 0x6316, 0x003e, 0x080c,
+	0x6c50, 0x08e8, 0x080c, 0x6b73, 0x080c, 0x994e, 0x080c, 0x8078,
+	0x080c, 0x6c50, 0x08a0, 0x00e6, 0x00f6, 0x2071, 0xad81, 0x2079,
+	0x0000, 0x080c, 0x2df1, 0x00fe, 0x00ee, 0x080c, 0x6b73, 0x080c,
+	0x8078, 0x080c, 0x6c50, 0x0818, 0x080c, 0x6b73, 0x2001, 0xafa5,
+	0x2004, 0x603e, 0x6003, 0x0002, 0x2001, 0xafa3, 0x2004, 0x6016,
+	0x080c, 0x6c50, 0x0005, 0x2600, 0x2008, 0x0002, 0x85e6, 0x85e4,
+	0x85e4, 0x85cc, 0x85cc, 0x85e4, 0x080c, 0x14f6, 0x080c, 0x6b73,
+	0x00d6, 0x6010, 0x2068, 0x080c, 0x15f0, 0x00de, 0x080c, 0x8078,
+	0x080c, 0x6c50, 0x0005, 0x00e6, 0x0026, 0x0016, 0x080c, 0x9596,
+	0x0508, 0x6010, 0x2070, 0x7034, 0xa086, 0x0139, 0x1148, 0x2001,
+	0x0030, 0x2009, 0x0000, 0x2011, 0x4005, 0x080c, 0x9a05, 0x0090,
+	0x7038, 0xd0fc, 0x0178, 0x7007, 0x0000, 0x0016, 0x6004, 0xa08e,
+	0x0021, 0x0160, 0xa08e, 0x003d, 0x0148, 0x001e, 0x7037, 0x0103,
+	0x7033, 0x0100, 0x001e, 0x002e, 0x00ee, 0x0005, 0x001e, 0x0009,
+	0x0cc8, 0x00e6, 0xacf0, 0x0004, 0x2e74, 0x7000, 0x2070, 0x7037,
+	0x0103, 0x7023, 0x8001, 0x00ee, 0x0005, 0x00d6, 0x6618, 0x2668,
+	0x6804, 0xa084, 0x00ff, 0x00de, 0xa0b2, 0x000c, 0x1a0c, 0x14f6,
+	0x6604, 0xa6b6, 0x0043, 0x1120, 0x080c, 0x99c1, 0x0804, 0x8692,
+	0x6604, 0xa6b6, 0x0033, 0x1120, 0x080c, 0x9971, 0x0804, 0x8692,
+	0x6604, 0xa6b6, 0x0028, 0x1120, 0x080c, 0x97b9, 0x0804, 0x8692,
+	0x6604, 0xa6b6, 0x0029, 0x1118, 0x080c, 0x97d0, 0x04d8, 0x6604,
+	0xa6b6, 0x001f, 0x1118, 0x080c, 0x81dc, 0x04a0, 0x6604, 0xa6b6,
+	0x0000, 0x1118, 0x080c, 0x83f4, 0x0468, 0x6604, 0xa6b6, 0x0022,
+	0x1118, 0x080c, 0x8204, 0x0430, 0x6604, 0xa6b6, 0x0035, 0x1118,
+	0x080c, 0x826b, 0x00f8, 0x6604, 0xa6b6, 0x0039, 0x1118, 0x080c,
+	0x83a3, 0x00c0, 0x6604, 0xa6b6, 0x003d, 0x1118, 0x080c, 0x821e,
+	0x0088, 0x6604, 0xa6b6, 0x0044, 0x1118, 0x080c, 0x823e, 0x0050,
+	0xa1b6, 0x0015, 0x1110, 0x0053, 0x0028, 0xa1b6, 0x0016, 0x1118,
+	0x0804, 0x883f, 0x0005, 0x080c, 0x80be, 0x0ce0, 0x86b9, 0x86bc,
+	0x86b9, 0x86fe, 0x86b9, 0x87cc, 0x884d, 0x86b9, 0x86b9, 0x881b,
+	0x86b9, 0x882f, 0xa1b6, 0x0048, 0x0140, 0x20e1, 0x0005, 0x3d18,
+	0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005, 0x00e6, 0xacf0, 0x0004,
+	0x2e74, 0x7000, 0x2070, 0x7037, 0x0103, 0x00ee, 0x080c, 0x8078,
+	0x0005, 0xe000, 0xe000, 0x0005, 0x00e6, 0x2071, 0xad00, 0x7080,
+	0xa086, 0x0074, 0x1530, 0x080c, 0xa6e9, 0x11b0, 0x00d6, 0x6018,
+	0x2068, 0x7030, 0xd08c, 0x0128, 0x6800, 0xd0bc, 0x0110, 0xc0c5,
+	0x6802, 0x00d9, 0x00de, 0x2001, 0x0006, 0x080c, 0x4c30, 0x080c,
+	0x2aff, 0x080c, 0x8078, 0x0078, 0x2001, 0x000a, 0x080c, 0x4c30,
+	0x080c, 0x2aff, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee,
+	0x0010, 0x080c, 0x87bd, 0x00ee, 0x0005, 0x6800, 0xd084, 0x0168,
+	0x2001, 0x0000, 0x080c, 0x4c1e, 0x2069, 0xad51, 0x6804, 0xd0a4,
+	0x0120, 0x2001, 0x0006, 0x080c, 0x4c5d, 0x0005, 0x00d6, 0x2011,
+	0xad20, 0x2204, 0xa086, 0x0074, 0x1904, 0x87ba, 0x6018, 0x2068,
+	0x6aa0, 0xa286, 0x007e, 0x1120, 0x080c, 0x894d, 0x0804, 0x875e,
+	0x080c, 0x8943, 0x6018, 0x2068, 0xa080, 0x0028, 0x2014, 0xa286,
+	0x0080, 0x11c0, 0x6813, 0x00ff, 0x6817, 0xfffc, 0x6010, 0xa005,
+	0x0138, 0x2068, 0x6807, 0x0000, 0x6837, 0x0103, 0x6833, 0x0200,
+	0x2001, 0x0006, 0x080c, 0x4c30, 0x080c, 0x2aff, 0x080c, 0x8078,
+	0x0804, 0x87bb, 0x00e6, 0x2071, 0xad34, 0x2e04, 0xd09c, 0x0188,
+	0x2071, 0xb280, 0x7108, 0x720c, 0xa18c, 0x00ff, 0x1118, 0xa284,
+	0xff00, 0x0138, 0x6018, 0x2070, 0x70a0, 0xd0bc, 0x1110, 0x7112,
+	0x7216, 0x00ee, 0x6010, 0xa005, 0x0128, 0x2068, 0x6838, 0xd0f4,
+	0x0108, 0x0880, 0x2001, 0x0004, 0x080c, 0x4c30, 0x6003, 0x0001,
+	0x6007, 0x0003, 0x080c, 0x67ee, 0x0804, 0x87bb, 0x685c, 0xd0e4,
+	0x01d0, 0x080c, 0x9903, 0x080c, 0x574f, 0x0110, 0xd0dc, 0x1900,
+	0x2011, 0xad34, 0x2204, 0xc0ad, 0x2012, 0x2001, 0xaf8e, 0x2004,
+	0x00f6, 0x2079, 0x0100, 0x78e3, 0x0000, 0x080c, 0x26cb, 0x78e2,
+	0x00fe, 0x0804, 0x8728, 0x080c, 0x9937, 0x2011, 0xad34, 0x2204,
+	0xc0a5, 0x2012, 0x0006, 0x080c, 0xa801, 0x000e, 0x1904, 0x8728,
+	0xc0b5, 0x2012, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x00c6, 0x2009,
+	0x00ef, 0x00f6, 0x2079, 0x0100, 0x79ea, 0x7932, 0x7936, 0x00fe,
+	0x080c, 0x26a0, 0x00f6, 0x2079, 0xad00, 0x7972, 0x2100, 0x2009,
+	0x0000, 0x080c, 0x2676, 0x794e, 0x00fe, 0x8108, 0x080c, 0x4c80,
+	0x2c00, 0x00ce, 0x1904, 0x8728, 0x601a, 0x2001, 0x0002, 0x080c,
+	0x4c30, 0x601f, 0x0001, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c,
+	0x67ee, 0x0008, 0x0011, 0x00de, 0x0005, 0x2001, 0xad00, 0x2004,
+	0xa086, 0x0003, 0x0120, 0x2001, 0x0007, 0x080c, 0x4c30, 0x080c,
+	0x2aff, 0x080c, 0x8078, 0x0005, 0x00e6, 0x0026, 0x0016, 0x2071,
+	0xad00, 0x7080, 0xa086, 0x0014, 0x15f0, 0x7000, 0xa086, 0x0003,
+	0x1128, 0x6010, 0xa005, 0x1110, 0x080c, 0x3cce, 0x00d6, 0x6018,
+	0x2068, 0x080c, 0x4d72, 0x080c, 0x86ed, 0x00de, 0x080c, 0x89f7,
+	0x1550, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005, 0x0518,
+	0x2001, 0x0006, 0x080c, 0x4c30, 0x00e6, 0x6010, 0xa075, 0x01a8,
+	0x7034, 0xa084, 0x00ff, 0xa086, 0x0039, 0x1148, 0x2001, 0x0000,
+	0x2009, 0x0000, 0x2011, 0x4000, 0x080c, 0x9a05, 0x0030, 0x7007,
+	0x0000, 0x7037, 0x0103, 0x7033, 0x0200, 0x00ee, 0x080c, 0x2aff,
+	0x080c, 0x8078, 0x0020, 0x080c, 0x85f3, 0x080c, 0x87bd, 0x001e,
+	0x002e, 0x00ee, 0x0005, 0x2011, 0xad20, 0x2204, 0xa086, 0x0014,
+	0x1158, 0x2001, 0x0002, 0x080c, 0x4c30, 0x6003, 0x0001, 0x6007,
+	0x0001, 0x080c, 0x67ee, 0x0010, 0x080c, 0x87bd, 0x0005, 0x2011,
+	0xad20, 0x2204, 0xa086, 0x0004, 0x1138, 0x2001, 0x0007, 0x080c,
+	0x4c30, 0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x0005, 0x000b,
+	0x0005, 0x86b9, 0x8854, 0x86b9, 0x888a, 0x86b9, 0x88ff, 0x884d,
+	0x86b9, 0x86b9, 0x8912, 0x86b9, 0x8922, 0x6604, 0xa6b6, 0x001e,
+	0x1110, 0x080c, 0x8078, 0x0005, 0x00d6, 0x00c6, 0x080c, 0x8932,
+	0x1178, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c,
+	0x4c30, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x00f8,
+	0x2009, 0xb28e, 0x2104, 0xa086, 0x0009, 0x1160, 0x6018, 0x2068,
+	0x6840, 0xa084, 0x00ff, 0xa005, 0x0180, 0x8001, 0x6842, 0x6017,
+	0x000a, 0x0068, 0x2009, 0xb28f, 0x2104, 0xa084, 0xff00, 0xa086,
+	0x1900, 0x1118, 0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x00ce,
+	0x00de, 0x0005, 0x080c, 0x8940, 0x00d6, 0x2069, 0xaf9d, 0x2d04,
+	0xa005, 0x0168, 0x6018, 0x2068, 0x68a0, 0xa086, 0x007e, 0x1138,
+	0x2069, 0xad1c, 0x2d04, 0x8000, 0x206a, 0x00de, 0x0010, 0x00de,
+	0x0078, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x2001, 0x0002, 0x080c,
+	0x4c30, 0x6003, 0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x0428,
+	0x080c, 0x85f3, 0x2009, 0xb28e, 0x2134, 0xa6b4, 0x00ff, 0xa686,
+	0x0005, 0x01e0, 0xa686, 0x000b, 0x01b0, 0x2009, 0xb28f, 0x2104,
+	0xa084, 0xff00, 0x1118, 0xa686, 0x0009, 0x0180, 0xa086, 0x1900,
+	0x1150, 0xa686, 0x0009, 0x0150, 0x2001, 0x0004, 0x080c, 0x4c30,
+	0x080c, 0x8078, 0x0010, 0x080c, 0x87bd, 0x0005, 0x00d6, 0x6010,
+	0x2068, 0x080c, 0x9596, 0x0128, 0x6838, 0xd0fc, 0x0110, 0x00de,
+	0x0c90, 0x6018, 0x2068, 0x6840, 0xa084, 0x00ff, 0xa005, 0x0140,
+	0x8001, 0x6842, 0x6017, 0x000a, 0x6007, 0x0016, 0x00de, 0x0c28,
+	0x68a0, 0xa086, 0x007e, 0x1138, 0x00e6, 0x2071, 0xad00, 0x080c,
+	0x48f5, 0x00ee, 0x0010, 0x080c, 0x2ad9, 0x00de, 0x08a0, 0x080c,
+	0x8940, 0x1158, 0x2001, 0x0004, 0x080c, 0x4c30, 0x6003, 0x0001,
+	0x6007, 0x0003, 0x080c, 0x67ee, 0x0020, 0x080c, 0x85f3, 0x080c,
+	0x87bd, 0x0005, 0x0469, 0x1158, 0x2001, 0x0008, 0x080c, 0x4c30,
+	0x6003, 0x0001, 0x6007, 0x0005, 0x080c, 0x67ee, 0x0010, 0x080c,
+	0x87bd, 0x0005, 0x00e9, 0x1158, 0x2001, 0x000a, 0x080c, 0x4c30,
+	0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee, 0x0010, 0x080c,
+	0x87bd, 0x0005, 0x2009, 0xb28e, 0x2104, 0xa086, 0x0003, 0x1138,
+	0x2009, 0xb28f, 0x2104, 0xa084, 0xff00, 0xa086, 0x2a00, 0x0005,
+	0xa085, 0x0001, 0x0005, 0x00c6, 0x0016, 0xac88, 0x0006, 0x2164,
+	0x080c, 0x4ceb, 0x001e, 0x00ce, 0x0005, 0x00f6, 0x00e6, 0x00d6,
+	0x0036, 0x0016, 0x6018, 0x2068, 0x2071, 0xad34, 0x2e04, 0xa085,
+	0x0003, 0x2072, 0x080c, 0x89cc, 0x0538, 0x2001, 0xad52, 0x2004,
+	0xd0a4, 0x0158, 0xa006, 0x2020, 0x2009, 0x002a, 0x080c, 0xa96c,
+	0x2001, 0xad0c, 0x200c, 0xc195, 0x2102, 0x2019, 0x002a, 0x2009,
+	0x0001, 0x080c, 0x2aac, 0x2071, 0xad00, 0x080c, 0x28fa, 0x00c6,
+	0x0156, 0x20a9, 0x0081, 0x2009, 0x007f, 0x080c, 0x2bc9, 0x8108,
+	0x1f04, 0x897d, 0x015e, 0x00ce, 0x080c, 0x8943, 0x6813, 0x00ff,
+	0x6817, 0xfffe, 0x2071, 0xb280, 0x2079, 0x0100, 0x2e04, 0xa084,
+	0x00ff, 0x2069, 0xad1b, 0x206a, 0x78e6, 0x0006, 0x8e70, 0x2e04,
+	0x2069, 0xad1c, 0x206a, 0x78ea, 0x7832, 0x7836, 0x2010, 0xa084,
+	0xff00, 0x001e, 0xa105, 0x2009, 0xad27, 0x200a, 0x2200, 0xa084,
+	0x00ff, 0x2008, 0x080c, 0x26a0, 0x080c, 0x574f, 0x0170, 0x2069,
+	0xb28e, 0x2071, 0xaf9f, 0x6810, 0x2072, 0x6814, 0x7006, 0x6818,
+	0x700a, 0x681c, 0x700e, 0x080c, 0x9903, 0x0040, 0x2001, 0x0006,
+	0x080c, 0x4c30, 0x080c, 0x2aff, 0x080c, 0x8078, 0x001e, 0x003e,
+	0x00de, 0x00ee, 0x00fe, 0x0005, 0x0026, 0x0036, 0x00e6, 0x0156,
+	0x2019, 0xad27, 0x231c, 0x83ff, 0x01e8, 0x2071, 0xb280, 0x2e14,
+	0xa294, 0x00ff, 0x7004, 0xa084, 0xff00, 0xa205, 0xa306, 0x1190,
+	0x2011, 0xb296, 0xad98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c,
+	0x1148, 0x2011, 0xb29a, 0xad98, 0x0006, 0x20a9, 0x0004, 0x080c,
+	0x8a7c, 0x1100, 0x015e, 0x00ee, 0x003e, 0x002e, 0x0005, 0x00e6,
+	0x2071, 0xb28c, 0x7004, 0xa086, 0x0014, 0x11a8, 0x7008, 0xa086,
+	0x0800, 0x1188, 0x700c, 0xd0ec, 0x0160, 0xa084, 0x0f00, 0xa086,
+	0x0100, 0x1138, 0x7024, 0xd0a4, 0x1110, 0xd0ac, 0x0110, 0xa006,
+	0x0010, 0xa085, 0x0001, 0x00ee, 0x0005, 0x00e6, 0x00d6, 0x00c6,
+	0x0076, 0x0056, 0x0046, 0x0026, 0x0006, 0x0126, 0x2091, 0x8000,
+	0x2029, 0xafd0, 0x252c, 0x2021, 0xafd6, 0x2424, 0x2061, 0xb400,
+	0x2071, 0xad00, 0x7244, 0x7064, 0xa202, 0x16f0, 0x080c, 0xa990,
+	0x05a0, 0x671c, 0xa786, 0x0001, 0x0580, 0xa786, 0x0007, 0x0568,
+	0x2500, 0xac06, 0x0550, 0x2400, 0xac06, 0x0538, 0x00c6, 0x6000,
+	0xa086, 0x0004, 0x1110, 0x080c, 0x190b, 0xa786, 0x0008, 0x1148,
+	0x080c, 0x9789, 0x1130, 0x00ce, 0x080c, 0x85f3, 0x080c, 0x974e,
+	0x00a0, 0x6010, 0x2068, 0x080c, 0x9596, 0x0160, 0xa786, 0x0003,
+	0x11e8, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000, 0x080c, 0x510c,
+	0x080c, 0x9742, 0x080c, 0x974e, 0x00ce, 0xace0, 0x0018, 0x7058,
+	0xac02, 0x1210, 0x0804, 0x8a2a, 0x012e, 0x000e, 0x002e, 0x004e,
+	0x005e, 0x007e, 0x00ce, 0x00de, 0x00ee, 0x0005, 0xa786, 0x0006,
+	0x1d00, 0x080c, 0xa91f, 0x0c30, 0x220c, 0x2304, 0xa106, 0x1130,
+	0x8210, 0x8318, 0x1f04, 0x8a7c, 0xa006, 0x0005, 0x2304, 0xa102,
+	0x0218, 0x2001, 0x0001, 0x0010, 0x2001, 0x0000, 0xa18d, 0x0001,
+	0x0005, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6, 0x080c, 0x9778,
+	0x0120, 0x080c, 0x9789, 0x0168, 0x0028, 0x080c, 0x2aff, 0x080c,
+	0x9789, 0x0138, 0x080c, 0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50,
+	0x0005, 0x080c, 0x85f3, 0x0cb0, 0xa182, 0x0040, 0x0002, 0x8ac2,
+	0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2, 0x8ac2,
+	0x8ac2, 0x8ac2, 0x8ac4, 0x8ac4, 0x8ac4, 0x8ac4, 0x8ac2, 0x8ac2,
+	0x8ac2, 0x8ac4, 0x080c, 0x14f6, 0x600b, 0xffff, 0x6003, 0x0001,
+	0x6106, 0x080c, 0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50,
+	0x012e, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0040,
+	0x0804, 0x8b5e, 0xa186, 0x0027, 0x11e8, 0x080c, 0x6b73, 0x080c,
+	0x2ad9, 0x00d6, 0x6110, 0x2168, 0x080c, 0x9596, 0x0168, 0x6837,
+	0x0103, 0x684b, 0x0029, 0x6847, 0x0000, 0x694c, 0xc1c5, 0x694e,
+	0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, 0x8078, 0x080c,
+	0x6c50, 0x0005, 0xa186, 0x0014, 0x1120, 0x6004, 0xa082, 0x0040,
+	0x0428, 0xa186, 0x0046, 0x0138, 0xa186, 0x0045, 0x0120, 0xa186,
+	0x0047, 0x190c, 0x14f6, 0x2001, 0x0109, 0x2004, 0xd084, 0x0198,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6699,
+	0x002e, 0x001e, 0x000e, 0x012e, 0xe000, 0x6000, 0xa086, 0x0002,
+	0x1110, 0x0804, 0x8b98, 0x080c, 0x80be, 0x0005, 0x0002, 0x8b3c,
+	0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a, 0x8b3a,
+	0x8b3a, 0x8b3a, 0x8b57, 0x8b57, 0x8b57, 0x8b57, 0x8b3a, 0x8b57,
+	0x8b3a, 0x8b57, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x00d6, 0x6110,
+	0x2168, 0x080c, 0x9596, 0x0168, 0x6837, 0x0103, 0x684b, 0x0006,
+	0x6847, 0x0000, 0x6850, 0xc0ec, 0x6852, 0x080c, 0x510c, 0x080c,
+	0x9742, 0x00de, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x080c,
+	0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x0002, 0x8b74,
+	0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72, 0x8b72,
+	0x8b72, 0x8b72, 0x8b86, 0x8b86, 0x8b86, 0x8b86, 0x8b72, 0x8b91,
+	0x8b72, 0x8b86, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x2001, 0xafa5,
+	0x2004, 0x603e, 0x6003, 0x0002, 0x080c, 0x6c50, 0x6010, 0xa088,
+	0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x0005, 0x080c, 0x6b73,
+	0x2001, 0xafa5, 0x2004, 0x603e, 0x6003, 0x000f, 0x080c, 0x6c50,
+	0x0005, 0x080c, 0x6b73, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005,
+	0xa182, 0x0040, 0x0002, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae,
+	0x8bb0, 0x8c88, 0x8ca9, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae,
+	0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x8bae, 0x080c, 0x14f6,
+	0x00e6, 0x00d6, 0x603f, 0x0000, 0x2071, 0xb280, 0x7124, 0x610a,
+	0x2071, 0xb28c, 0x6110, 0x2168, 0x7614, 0xa6b4, 0x0fff, 0x86ff,
+	0x0904, 0x8c54, 0xa68c, 0x0c00, 0x01e8, 0x00f6, 0x2c78, 0x080c,
+	0x5029, 0x00fe, 0x0198, 0x684c, 0xd0ac, 0x0180, 0x6020, 0xd0dc,
+	0x1168, 0x6850, 0xd0bc, 0x1150, 0x7318, 0x6814, 0xa306, 0x1904,
+	0x8c66, 0x731c, 0x6810, 0xa306, 0x1904, 0x8c66, 0x7318, 0x6b62,
+	0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0518, 0xa186,
+	0x0028, 0x1128, 0x080c, 0x9767, 0x684b, 0x001c, 0x00e8, 0xd6dc,
+	0x01a0, 0x684b, 0x0015, 0x684c, 0xd0ac, 0x0170, 0x6914, 0x6a10,
+	0x2100, 0xa205, 0x0148, 0x7018, 0xa106, 0x1118, 0x701c, 0xa206,
+	0x0118, 0x6962, 0x6a5e, 0xc6dc, 0x0038, 0xd6d4, 0x0118, 0x684b,
+	0x0007, 0x0010, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46, 0xa01e,
+	0xd6c4, 0x01f0, 0xa686, 0x0100, 0x1140, 0x2001, 0xb299, 0x2004,
+	0xa005, 0x1118, 0xc6c4, 0x0804, 0x8bbf, 0x7328, 0x732c, 0x6b56,
+	0x83ff, 0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036,
+	0x2308, 0x2019, 0xb298, 0xad90, 0x0019, 0x080c, 0x927f, 0x003e,
+	0xd6cc, 0x0904, 0x8c79, 0x7124, 0x695a, 0x81ff, 0x0904, 0x8c79,
+	0xa192, 0x0021, 0x1250, 0x2071, 0xb298, 0x831c, 0x2300, 0xae18,
+	0xad90, 0x001d, 0x080c, 0x927f, 0x04a0, 0x6838, 0xd0fc, 0x0120,
+	0x2009, 0x0020, 0x695a, 0x0c78, 0x00f6, 0x2d78, 0x080c, 0x9224,
+	0x00fe, 0x080c, 0x926f, 0x0438, 0x00f6, 0x2c78, 0x080c, 0x5029,
+	0x00fe, 0x0188, 0x684c, 0xd0ac, 0x0170, 0x6020, 0xd0dc, 0x1158,
+	0x6850, 0xd0bc, 0x1140, 0x684c, 0xd0f4, 0x1128, 0x080c, 0x9866,
+	0x00de, 0x00ee, 0x00e0, 0x684b, 0x0000, 0x6837, 0x0103, 0x6e46,
+	0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c,
+	0x8e04, 0x080c, 0x510c, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e,
+	0x080c, 0x9834, 0x00de, 0x00ee, 0x1110, 0x080c, 0x8078, 0x0005,
+	0x00f6, 0x6003, 0x0003, 0x2079, 0xb28c, 0x7c04, 0x7b00, 0x7e0c,
+	0x7d08, 0x6010, 0x2078, 0x784c, 0xd0ac, 0x0120, 0x6003, 0x0002,
+	0x00fe, 0x0005, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e, 0x00fe, 0x603f,
+	0x0000, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x680b, 0x080c, 0x6d0d,
+	0x0005, 0x2001, 0xafa5, 0x2004, 0x603e, 0x6003, 0x0004, 0x6110,
+	0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005,
+	0xa182, 0x0040, 0x0002, 0x8cce, 0x8cce, 0x8cce, 0x8cce, 0x8cce,
+	0x8cd0, 0x8d61, 0x8cce, 0x8cce, 0x8d77, 0x8ddb, 0x8cce, 0x8cce,
+	0x8cce, 0x8cce, 0x8dea, 0x8cce, 0x8cce, 0x8cce, 0x080c, 0x14f6,
+	0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xb28c, 0x6110, 0x2178,
+	0x7614, 0xa6b4, 0x0fff, 0x7e46, 0x7f4c, 0xc7e5, 0x7f4e, 0x6218,
+	0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904, 0x8d5c, 0xa694,
+	0xff00, 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862, 0x701c, 0x785e,
+	0xa284, 0x0300, 0x0904, 0x8d5c, 0x080c, 0x15d9, 0x090c, 0x14f6,
+	0x2d00, 0x784a, 0x7f4c, 0xc7cd, 0x7f4e, 0x6837, 0x0103, 0x7838,
+	0x683a, 0x783c, 0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00,
+	0x0120, 0x7318, 0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186,
+	0x0002, 0x0180, 0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060,
+	0xd6dc, 0x0118, 0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b,
+	0x0007, 0x0010, 0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854,
+	0x6856, 0xa01e, 0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff,
+	0x0170, 0xa38a, 0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308,
+	0x2019, 0xb298, 0xad90, 0x0019, 0x080c, 0x927f, 0x003e, 0xd6cc,
+	0x01d8, 0x7124, 0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250,
+	0x2071, 0xb298, 0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c,
+	0x927f, 0x0050, 0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a,
+	0x0c78, 0x2d78, 0x080c, 0x9224, 0x00de, 0x00ee, 0x00fe, 0x007e,
+	0x0005, 0x00f6, 0x6003, 0x0003, 0x2079, 0xb28c, 0x7c04, 0x7b00,
+	0x7e0c, 0x7d08, 0x6010, 0x2078, 0x7c12, 0x7b16, 0x7e0a, 0x7d0e,
+	0x00fe, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x781a, 0x0005, 0x00d6,
+	0x00f6, 0x2c78, 0x080c, 0x5029, 0x00fe, 0x0120, 0x2001, 0xafa5,
+	0x2004, 0x603e, 0x6003, 0x0002, 0x080c, 0x6c05, 0x080c, 0x6d0d,
+	0x6110, 0x2168, 0x694c, 0xd1e4, 0x0904, 0x8dd9, 0xd1cc, 0x0540,
+	0x6948, 0x6838, 0xd0fc, 0x01e8, 0x0016, 0x684c, 0x0006, 0x6850,
+	0x0006, 0xad90, 0x000d, 0xa198, 0x000d, 0x2009, 0x0020, 0x0156,
+	0x21a8, 0x2304, 0x2012, 0x8318, 0x8210, 0x1f04, 0x8da1, 0x015e,
+	0x000e, 0x6852, 0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x1600,
+	0x0418, 0x0016, 0x080c, 0x1600, 0x00de, 0x080c, 0x926f, 0x00e0,
+	0x6837, 0x0103, 0x6944, 0xa184, 0x00ff, 0xa0b6, 0x0002, 0x0180,
+	0xa086, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd1dc, 0x0118,
+	0x684b, 0x0015, 0x0038, 0xd1d4, 0x0118, 0x684b, 0x0007, 0x0010,
+	0x684b, 0x0000, 0x080c, 0x510c, 0x080c, 0x9834, 0x1110, 0x080c,
+	0x8078, 0x00de, 0x0005, 0x2019, 0x0001, 0x080c, 0x7a64, 0x6003,
+	0x0002, 0x2001, 0xafa5, 0x2004, 0x603e, 0x080c, 0x6c05, 0x080c,
+	0x6d0d, 0x0005, 0x080c, 0x6c05, 0x080c, 0x2ad9, 0x00d6, 0x6110,
+	0x2168, 0x080c, 0x9596, 0x0150, 0x6837, 0x0103, 0x684b, 0x0029,
+	0x6847, 0x0000, 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c,
+	0x8078, 0x080c, 0x6d0d, 0x0005, 0x684b, 0x0015, 0xd1fc, 0x0138,
+	0x684b, 0x0007, 0x8002, 0x8000, 0x810a, 0xa189, 0x0000, 0x6962,
+	0x685e, 0x0005, 0xa182, 0x0040, 0x0002, 0x8e28, 0x8e28, 0x8e28,
+	0x8e28, 0x8e28, 0x8e2a, 0x8e28, 0x8ee3, 0x8eef, 0x8e28, 0x8e28,
+	0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28, 0x8e28,
+	0x080c, 0x14f6, 0x0076, 0x00f6, 0x00e6, 0x00d6, 0x2071, 0xb28c,
+	0x6110, 0x2178, 0x7614, 0xa6b4, 0x0fff, 0x00f6, 0x2c78, 0x080c,
+	0x5029, 0x00fe, 0x0150, 0xa684, 0x00ff, 0x1138, 0x6020, 0xd0f4,
+	0x0120, 0x080c, 0x9866, 0x0804, 0x8ede, 0x7e46, 0x7f4c, 0xc7e5,
+	0x7f4e, 0x6218, 0x2268, 0x6a3c, 0x8211, 0x6a3e, 0x86ff, 0x0904,
+	0x8ed4, 0xa694, 0xff00, 0xa284, 0x0c00, 0x0120, 0x7018, 0x7862,
+	0x701c, 0x785e, 0xa284, 0x0300, 0x0904, 0x8ed2, 0xa686, 0x0100,
+	0x1140, 0x2001, 0xb299, 0x2004, 0xa005, 0x1118, 0xc6c4, 0x7e46,
+	0x0c28, 0x080c, 0x15d9, 0x090c, 0x14f6, 0x2d00, 0x784a, 0x7f4c,
+	0xa7bd, 0x0200, 0x7f4e, 0x6837, 0x0103, 0x7838, 0x683a, 0x783c,
+	0x683e, 0x7840, 0x6842, 0x6e46, 0xa68c, 0x0c00, 0x0120, 0x7318,
+	0x6b62, 0x731c, 0x6b5e, 0xa68c, 0x00ff, 0xa186, 0x0002, 0x0180,
+	0xa186, 0x0028, 0x1118, 0x684b, 0x001c, 0x0060, 0xd6dc, 0x0118,
+	0x684b, 0x0015, 0x0038, 0xd6d4, 0x0118, 0x684b, 0x0007, 0x0010,
+	0x684b, 0x0000, 0x6f4e, 0x7850, 0x6852, 0x7854, 0x6856, 0xa01e,
+	0xd6c4, 0x0198, 0x7328, 0x732c, 0x6b56, 0x83ff, 0x0170, 0xa38a,
+	0x0009, 0x0210, 0x2019, 0x0008, 0x0036, 0x2308, 0x2019, 0xb298,
+	0xad90, 0x0019, 0x080c, 0x927f, 0x003e, 0xd6cc, 0x01d8, 0x7124,
+	0x695a, 0x81ff, 0x01b8, 0xa192, 0x0021, 0x1250, 0x2071, 0xb298,
+	0x831c, 0x2300, 0xae18, 0xad90, 0x001d, 0x080c, 0x927f, 0x0050,
+	0x7838, 0xd0fc, 0x0120, 0x2009, 0x0020, 0x695a, 0x0c78, 0x2d78,
+	0x080c, 0x9224, 0xd6dc, 0x1110, 0xa006, 0x0030, 0x2001, 0x0001,
+	0x2071, 0xb28c, 0x7218, 0x731c, 0x080c, 0x186f, 0x00de, 0x00ee,
+	0x00fe, 0x007e, 0x0005, 0x2001, 0xafa5, 0x2004, 0x603e, 0x20e1,
+	0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824, 0x0005, 0x2001,
+	0xafa5, 0x2004, 0x603e, 0x00d6, 0x6003, 0x0002, 0x6110, 0x2168,
+	0x694c, 0xd1e4, 0x0904, 0x8ff3, 0x603f, 0x0000, 0x00f6, 0x2c78,
+	0x080c, 0x5029, 0x00fe, 0x0548, 0x6814, 0x6910, 0xa115, 0x0528,
+	0x6a60, 0xa206, 0x1118, 0x685c, 0xa106, 0x01f8, 0x684c, 0xc0e4,
+	0x684e, 0x6847, 0x0000, 0x6863, 0x0000, 0x685f, 0x0000, 0x697c,
+	0x6810, 0xa102, 0x603a, 0x6980, 0x6814, 0xa103, 0x6036, 0x6020,
+	0xc0f5, 0x6022, 0x00d6, 0x6018, 0x2068, 0x683c, 0x8000, 0x683e,
+	0x00de, 0x080c, 0x9866, 0x0804, 0x8ff3, 0x694c, 0xd1cc, 0x0904,
+	0x8fc3, 0x6948, 0x6838, 0xd0fc, 0x0904, 0x8f88, 0x0016, 0x684c,
+	0x0006, 0x6850, 0x0006, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff,
+	0xa0b6, 0x0002, 0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c,
+	0x784b, 0x001c, 0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b,
+	0x0015, 0x080c, 0x99ee, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080,
+	0xd1d4, 0x0128, 0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c,
+	0xd0ac, 0x0130, 0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x8e04,
+	0x6848, 0x784a, 0x6860, 0x7862, 0x685c, 0x785e, 0xad90, 0x000d,
+	0xaf98, 0x000d, 0x2009, 0x0020, 0x0156, 0x21a8, 0x2304, 0x2012,
+	0x8318, 0x8210, 0x1f04, 0x8f76, 0x015e, 0x00fe, 0x000e, 0x6852,
+	0x000e, 0x684e, 0x001e, 0x2168, 0x080c, 0x1600, 0x0804, 0x8fee,
+	0x0016, 0x00f6, 0x2178, 0x7944, 0xa184, 0x00ff, 0xa0b6, 0x0002,
+	0x01e0, 0xa086, 0x0028, 0x1128, 0x684b, 0x001c, 0x784b, 0x001c,
+	0x00e8, 0xd1dc, 0x0158, 0x684b, 0x0015, 0x784b, 0x0015, 0x080c,
+	0x99ee, 0x0118, 0x7944, 0xc1dc, 0x7946, 0x0080, 0xd1d4, 0x0128,
+	0x684b, 0x0007, 0x784b, 0x0007, 0x0048, 0x684c, 0xd0ac, 0x0130,
+	0x6810, 0x6914, 0xa115, 0x0110, 0x080c, 0x8e04, 0x6860, 0x7862,
+	0x685c, 0x785e, 0x684c, 0x784e, 0x00fe, 0x080c, 0x1600, 0x00de,
+	0x080c, 0x926f, 0x0458, 0x6837, 0x0103, 0x6944, 0xa184, 0x00ff,
+	0xa0b6, 0x0002, 0x01b0, 0xa086, 0x0028, 0x1118, 0x684b, 0x001c,
+	0x00d8, 0xd1dc, 0x0148, 0x684b, 0x0015, 0x080c, 0x99ee, 0x0118,
+	0x6944, 0xc1dc, 0x6946, 0x0080, 0xd1d4, 0x0118, 0x684b, 0x0007,
+	0x0058, 0x684b, 0x0000, 0x684c, 0xd0ac, 0x0130, 0x6810, 0x6914,
+	0xa115, 0x0110, 0x080c, 0x8e04, 0x080c, 0x510c, 0x080c, 0x9834,
+	0x1110, 0x080c, 0x8078, 0x00de, 0x0005, 0x080c, 0x6b73, 0x0010,
+	0x080c, 0x6c05, 0x080c, 0x9596, 0x01c0, 0x00d6, 0x6110, 0x2168,
+	0x6837, 0x0103, 0x2009, 0xad0c, 0x210c, 0xd18c, 0x11c0, 0xd184,
+	0x1198, 0x6108, 0x694a, 0xa18e, 0x0029, 0x1110, 0x080c, 0xabfa,
+	0x6847, 0x0000, 0x080c, 0x510c, 0x00de, 0x080c, 0x8078, 0x080c,
+	0x6c50, 0x080c, 0x6d0d, 0x0005, 0x684b, 0x0004, 0x0c88, 0x684b,
+	0x0004, 0x0c70, 0xa182, 0x0040, 0x0002, 0x9038, 0x9038, 0x9038,
+	0x9038, 0x9038, 0x903a, 0x9038, 0x903d, 0x9038, 0x9038, 0x9038,
+	0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038, 0x9038,
+	0x080c, 0x14f6, 0x080c, 0x8078, 0x0005, 0x0006, 0x0026, 0xa016,
+	0x080c, 0x1824, 0x002e, 0x000e, 0x0005, 0xa182, 0x0085, 0x0002,
+	0x9051, 0x904f, 0x904f, 0x905d, 0x904f, 0x904f, 0x904f, 0x080c,
+	0x14f6, 0x6003, 0x0001, 0x6106, 0x080c, 0x67a8, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x6c50, 0x012e, 0x0005, 0x0026, 0x0056, 0x00d6,
+	0x00e6, 0x2071, 0xb280, 0x7224, 0x6212, 0x7220, 0x080c, 0x9586,
+	0x01a0, 0x2268, 0x6800, 0xa086, 0x0000, 0x0178, 0x6018, 0x6d18,
+	0xa52e, 0x1158, 0x00c6, 0x2d60, 0x080c, 0x928f, 0x00ce, 0x0128,
+	0x6803, 0x0002, 0x6007, 0x0086, 0x0010, 0x6007, 0x0087, 0x6003,
+	0x0001, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x00f6, 0x2278, 0x080c,
+	0x5029, 0x00fe, 0x0150, 0x6820, 0xd0ec, 0x0138, 0x00c6, 0x2260,
+	0x603f, 0x0000, 0x080c, 0x9866, 0x00ce, 0x00ee, 0x00de, 0x005e,
+	0x002e, 0x0005, 0xa186, 0x0013, 0x1160, 0x6004, 0xa08a, 0x0085,
+	0x0a0c, 0x14f6, 0xa08a, 0x008c, 0x1a0c, 0x14f6, 0xa082, 0x0085,
+	0x0072, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c, 0x14f6,
+	0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0x90be,
+	0x90c0, 0x90c0, 0x90be, 0x90be, 0x90be, 0x90be, 0x080c, 0x14f6,
+	0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0xa186,
+	0x0013, 0x1128, 0x6004, 0xa082, 0x0085, 0x2008, 0x04a8, 0xa186,
+	0x0027, 0x11e8, 0x080c, 0x6b73, 0x080c, 0x2ad9, 0x00d6, 0x6010,
+	0x2068, 0x080c, 0x9596, 0x0150, 0x6837, 0x0103, 0x6847, 0x0000,
+	0x684b, 0x0029, 0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c,
+	0x8078, 0x080c, 0x6c50, 0x0005, 0x080c, 0x80be, 0x0ce0, 0xa186,
+	0x0014, 0x1dd0, 0x080c, 0x6b73, 0x00d6, 0x6010, 0x2068, 0x080c,
+	0x9596, 0x0d60, 0x6837, 0x0103, 0x6847, 0x0000, 0x684b, 0x0006,
+	0x6850, 0xc0ec, 0x6852, 0x08f0, 0x0002, 0x910e, 0x910c, 0x910c,
+	0x910c, 0x910c, 0x910c, 0x9126, 0x080c, 0x14f6, 0x080c, 0x6b73,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x2001, 0xafa3, 0x0010, 0x2001, 0xafa4, 0x2004,
+	0x6016, 0x6003, 0x000c, 0x080c, 0x6c50, 0x0005, 0x080c, 0x6b73,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x2001, 0xafa3, 0x0010, 0x2001, 0xafa4, 0x2004,
+	0x6016, 0x6003, 0x000e, 0x080c, 0x6c50, 0x0005, 0xa182, 0x008c,
+	0x1220, 0xa182, 0x0085, 0x0208, 0x001a, 0x080c, 0x80be, 0x0005,
+	0x914f, 0x914f, 0x914f, 0x914f, 0x9151, 0x91a4, 0x914f, 0x080c,
+	0x14f6, 0x00d6, 0x00f6, 0x2c78, 0x080c, 0x5029, 0x00fe, 0x0168,
+	0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0039, 0x0118, 0xa186,
+	0x0035, 0x1118, 0x00de, 0x0804, 0x91b7, 0x080c, 0x9742, 0x080c,
+	0x9596, 0x01c8, 0x6010, 0x2068, 0x6837, 0x0103, 0x6850, 0xd0b4,
+	0x0128, 0x684b, 0x0006, 0xc0ec, 0x6852, 0x0048, 0xd0bc, 0x0118,
+	0x684b, 0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9803, 0x6847,
+	0x0000, 0x080c, 0x510c, 0x2c68, 0x080c, 0x8022, 0x01c0, 0x6003,
+	0x0001, 0x6007, 0x001e, 0x600b, 0xffff, 0x2009, 0xb28e, 0x210c,
+	0x6136, 0x2009, 0xb28f, 0x210c, 0x613a, 0x6918, 0x611a, 0x080c,
+	0x9956, 0x6950, 0x6152, 0x601f, 0x0001, 0x080c, 0x67a8, 0x2d60,
+	0x080c, 0x8078, 0x00de, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5029,
+	0x00fe, 0x0598, 0x6030, 0xa08c, 0xff00, 0x810f, 0xa186, 0x0035,
+	0x0130, 0xa186, 0x001e, 0x0118, 0xa186, 0x0039, 0x1530, 0x00d6,
+	0x2c68, 0x080c, 0x9a34, 0x1904, 0x91fc, 0x080c, 0x8022, 0x01d8,
+	0x6106, 0x6003, 0x0001, 0x601f, 0x0001, 0x6918, 0x611a, 0x6928,
+	0x612a, 0x692c, 0x612e, 0x6930, 0xa18c, 0x00ff, 0x6132, 0x6934,
+	0x6136, 0x6938, 0x613a, 0x6950, 0x6152, 0x080c, 0x9956, 0x080c,
+	0x67a8, 0x080c, 0x6c50, 0x2d60, 0x00f8, 0x00d6, 0x6010, 0x2068,
+	0x080c, 0x9596, 0x01c8, 0x6837, 0x0103, 0x6850, 0xd0b4, 0x0128,
+	0xc0ec, 0x6852, 0x684b, 0x0006, 0x0048, 0xd0bc, 0x0118, 0x684b,
+	0x0002, 0x0020, 0x684b, 0x0005, 0x080c, 0x9803, 0x6847, 0x0000,
+	0x080c, 0x510c, 0x080c, 0x9742, 0x00de, 0x080c, 0x8078, 0x0005,
+	0x0016, 0x00d6, 0x6010, 0x2068, 0x080c, 0x9596, 0x0140, 0x6837,
+	0x0103, 0x684b, 0x0028, 0x6847, 0x0000, 0x080c, 0x510c, 0x00de,
+	0x001e, 0xa186, 0x0013, 0x0148, 0xa186, 0x0014, 0x0130, 0xa186,
+	0x0027, 0x0118, 0x080c, 0x80be, 0x0030, 0x080c, 0x6b73, 0x080c,
+	0x974e, 0x080c, 0x6c50, 0x0005, 0x0056, 0x0066, 0x00d6, 0x00f6,
+	0x2029, 0x0001, 0xa182, 0x0101, 0x1208, 0x0010, 0x2009, 0x0100,
+	0x2130, 0x2069, 0xb298, 0x831c, 0x2300, 0xad18, 0x2009, 0x0020,
+	0xaf90, 0x001d, 0x080c, 0x927f, 0xa6b2, 0x0020, 0x7804, 0xa06d,
+	0x0110, 0x080c, 0x1600, 0x080c, 0x15d9, 0x0500, 0x8528, 0x6837,
+	0x0110, 0x683b, 0x0000, 0x2d20, 0x7c06, 0xa68a, 0x003d, 0x1228,
+	0x2608, 0xad90, 0x000f, 0x0459, 0x0088, 0xa6b2, 0x003c, 0x2009,
+	0x003c, 0x2d78, 0xad90, 0x000f, 0x0411, 0x0c28, 0x00fe, 0x852f,
+	0xa5ad, 0x0003, 0x7d36, 0xa5ac, 0x0000, 0x0028, 0x00fe, 0x852f,
+	0xa5ad, 0x0003, 0x7d36, 0x00de, 0x006e, 0x005e, 0x0005, 0x00f6,
+	0x8dff, 0x0158, 0x6804, 0xa07d, 0x0130, 0x6807, 0x0000, 0x080c,
+	0x510c, 0x2f68, 0x0cb8, 0x080c, 0x510c, 0x00fe, 0x0005, 0x0156,
+	0xa184, 0x0001, 0x0108, 0x8108, 0x810c, 0x21a8, 0x2304, 0x8007,
+	0x2012, 0x8318, 0x8210, 0x1f04, 0x9286, 0x015e, 0x0005, 0x0066,
+	0x0126, 0x2091, 0x8000, 0x2031, 0x0001, 0x601c, 0xa084, 0x000f,
+	0x0083, 0x012e, 0x006e, 0x0005, 0x0126, 0x2091, 0x8000, 0x0066,
+	0x2031, 0x0000, 0x601c, 0xa084, 0x000f, 0x001b, 0x006e, 0x012e,
+	0x0005, 0x92c3, 0x92c3, 0x92be, 0x92e5, 0x92b1, 0x92be, 0x92e5,
+	0x92be, 0x080c, 0x14f6, 0x0036, 0x2019, 0x0010, 0x080c, 0xa566,
+	0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0xa006, 0x0005,
+	0xa085, 0x0001, 0x0005, 0x00d6, 0x86ff, 0x11d8, 0x6010, 0x2068,
+	0x080c, 0x9596, 0x01c0, 0x6834, 0xa086, 0x0139, 0x1128, 0x684b,
+	0x0005, 0x6853, 0x0000, 0x0028, 0xa00e, 0x2001, 0x0005, 0x080c,
+	0x51df, 0x080c, 0x9803, 0x080c, 0x510c, 0x080c, 0x8078, 0xa085,
+	0x0001, 0x00de, 0x0005, 0xa006, 0x0ce0, 0x6000, 0xa08a, 0x0010,
+	0x1a0c, 0x14f6, 0x000b, 0x0005, 0x92fc, 0x9319, 0x92fe, 0x9338,
+	0x9316, 0x92fc, 0x92be, 0x92c3, 0x92c3, 0x92be, 0x92be, 0x92be,
+	0x92be, 0x92be, 0x92be, 0x92be, 0x080c, 0x14f6, 0x86ff, 0x1198,
+	0x00d6, 0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0x9803,
+	0x00de, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c,
+	0x67a8, 0x080c, 0x6c50, 0xa085, 0x0001, 0x0005, 0x080c, 0x190b,
+	0x0c28, 0x00e6, 0x2071, 0xafc7, 0x7024, 0xac06, 0x1110, 0x080c,
+	0x79e1, 0x601c, 0xa084, 0x000f, 0xa086, 0x0006, 0x1150, 0x0086,
+	0x0096, 0x2049, 0x0001, 0x2c40, 0x080c, 0x7b9a, 0x009e, 0x008e,
+	0x0010, 0x080c, 0x78de, 0x00ee, 0x1948, 0x080c, 0x92be, 0x0005,
+	0x0036, 0x00e6, 0x2071, 0xafc7, 0x703c, 0xac06, 0x1140, 0x2019,
+	0x0000, 0x080c, 0x7a64, 0x00ee, 0x003e, 0x0804, 0x92fe, 0x080c,
+	0x7cb8, 0x00ee, 0x003e, 0x1904, 0x92fe, 0x080c, 0x92be, 0x0005,
+	0x00c6, 0x601c, 0xa084, 0x000f, 0x0013, 0x00ce, 0x0005, 0x9369,
+	0x93d3, 0x9501, 0x9374, 0x974e, 0x9369, 0xa558, 0x8078, 0x93d3,
+	0x9362, 0x955f, 0x080c, 0x14f6, 0x080c, 0x9789, 0x1110, 0x080c,
+	0x85f3, 0x0005, 0x080c, 0x6b73, 0x080c, 0x6c50, 0x080c, 0x8078,
+	0x0005, 0x6017, 0x0001, 0x0005, 0x6010, 0xa080, 0x0019, 0x2c02,
+	0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005, 0x938f,
+	0x9391, 0x93b1, 0x93c3, 0x93d0, 0x938f, 0x9369, 0x9369, 0x9369,
+	0x93c3, 0x93c3, 0x938f, 0x938f, 0x938f, 0x938f, 0x93cd, 0x080c,
+	0x14f6, 0x00e6, 0x6010, 0x2070, 0x7050, 0xc0b5, 0x7052, 0x2071,
+	0xafc7, 0x7024, 0xac06, 0x0190, 0x080c, 0x78de, 0x6007, 0x0085,
+	0x6003, 0x000b, 0x601f, 0x0002, 0x2001, 0xafa4, 0x2004, 0x6016,
+	0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ee, 0x0005, 0x6017, 0x0001,
+	0x0cd8, 0x00d6, 0x6010, 0x2068, 0x6850, 0xc0b5, 0x6852, 0x00de,
+	0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x080c, 0x67a8,
+	0x080c, 0x6c50, 0x0005, 0x00d6, 0x6017, 0x0001, 0x6010, 0x2068,
+	0x6850, 0xc0b5, 0x6852, 0x00de, 0x0005, 0x080c, 0x8078, 0x0005,
+	0x080c, 0x190b, 0x08f0, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6,
+	0x000b, 0x0005, 0x93ea, 0x9371, 0x93ec, 0x93ea, 0x93ec, 0x93ec,
+	0x936a, 0x93ea, 0x9364, 0x9364, 0x93ea, 0x93ea, 0x93ea, 0x93ea,
+	0x93ea, 0x93ea, 0x080c, 0x14f6, 0x00d6, 0x6018, 0x2068, 0x6804,
+	0xa084, 0x00ff, 0x00de, 0xa08a, 0x000c, 0x1a0c, 0x14f6, 0x000b,
+	0x0005, 0x9405, 0x94a7, 0x9407, 0x9441, 0x9407, 0x9441, 0x9407,
+	0x9411, 0x9405, 0x9441, 0x9405, 0x942d, 0x080c, 0x14f6, 0x6004,
+	0xa08e, 0x0016, 0x0588, 0xa08e, 0x0004, 0x0570, 0xa08e, 0x0002,
+	0x0558, 0x6004, 0x080c, 0x9789, 0x0904, 0x94c0, 0xa08e, 0x0021,
+	0x0904, 0x94c4, 0xa08e, 0x0022, 0x0904, 0x94c0, 0xa08e, 0x003d,
+	0x0904, 0x94c4, 0xa08e, 0x0039, 0x0904, 0x94c8, 0xa08e, 0x0035,
+	0x0904, 0x94c8, 0xa08e, 0x001e, 0x0188, 0xa08e, 0x0001, 0x1150,
+	0x00d6, 0x6018, 0x2068, 0x6804, 0xa084, 0x00ff, 0x00de, 0xa086,
+	0x0006, 0x0110, 0x080c, 0x2ad9, 0x080c, 0x85f3, 0x080c, 0x974e,
+	0x0005, 0x00c6, 0x00d6, 0x6104, 0xa186, 0x0016, 0x0904, 0x9498,
+	0xa186, 0x0002, 0x1518, 0x6018, 0x2068, 0x2001, 0xad34, 0x2004,
+	0xd0ac, 0x1904, 0x94ea, 0x68a0, 0xd0bc, 0x1904, 0x94ea, 0x6840,
+	0xa084, 0x00ff, 0xa005, 0x0190, 0x8001, 0x6842, 0x6013, 0x0000,
+	0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x080c, 0x8022,
+	0x0128, 0x2d00, 0x601a, 0x601f, 0x0001, 0x0450, 0x00de, 0x00ce,
+	0x6004, 0xa08e, 0x0002, 0x11a8, 0x6018, 0xa080, 0x0028, 0x2004,
+	0xa086, 0x007e, 0x1170, 0x2009, 0xad34, 0x2104, 0xc085, 0x200a,
+	0x00e6, 0x2071, 0xad00, 0x080c, 0x48f5, 0x00ee, 0x080c, 0x85f3,
+	0x0020, 0x080c, 0x85f3, 0x080c, 0x2ad9, 0x00e6, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x2aff, 0x012e, 0x00ee, 0x080c, 0x974e, 0x0005,
+	0x2001, 0x0002, 0x080c, 0x4c30, 0x6003, 0x0001, 0x6007, 0x0002,
+	0x080c, 0x67ee, 0x080c, 0x6c50, 0x00de, 0x00ce, 0x0c80, 0x00c6,
+	0x00d6, 0x6104, 0xa186, 0x0016, 0x0d58, 0x6018, 0x2068, 0x6840,
+	0xa084, 0x00ff, 0xa005, 0x0904, 0x946e, 0x8001, 0x6842, 0x6003,
+	0x0001, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00de, 0x00ce, 0x08b8,
+	0x080c, 0x85f3, 0x0804, 0x943e, 0x080c, 0x8621, 0x0804, 0x943e,
+	0x00d6, 0x2c68, 0x6104, 0x080c, 0x9a34, 0x00de, 0x0118, 0x080c,
+	0x8078, 0x00b8, 0x6004, 0x8007, 0x6130, 0xa18c, 0x00ff, 0xa105,
+	0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0002, 0x6038,
+	0x600a, 0x2001, 0xafa4, 0x2004, 0x6016, 0x080c, 0x67a8, 0x080c,
+	0x6c50, 0x0005, 0x00de, 0x00ce, 0x080c, 0x85f3, 0x080c, 0x2ad9,
+	0x00e6, 0x0126, 0x2091, 0x8000, 0x080c, 0x2aff, 0x6013, 0x0000,
+	0x601f, 0x0007, 0x6017, 0x0398, 0x603f, 0x0000, 0x012e, 0x00ee,
+	0x0005, 0x6000, 0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005,
+	0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518, 0x9518,
+	0x9518, 0x9369, 0x9518, 0x9371, 0x951a, 0x9371, 0x9527, 0x9518,
+	0x080c, 0x14f6, 0x6004, 0xa086, 0x008b, 0x0148, 0x6007, 0x008b,
+	0x6003, 0x000d, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0005, 0x080c,
+	0x9742, 0x080c, 0x9596, 0x0580, 0x080c, 0x2ad9, 0x00d6, 0x080c,
+	0x9596, 0x0168, 0x6010, 0x2068, 0x6837, 0x0103, 0x684b, 0x0006,
+	0x6847, 0x0000, 0x6850, 0xc0ed, 0x6852, 0x080c, 0x510c, 0x2c68,
+	0x080c, 0x8022, 0x0150, 0x6818, 0x601a, 0x080c, 0x9956, 0x00c6,
+	0x2d60, 0x080c, 0x974e, 0x00ce, 0x0008, 0x2d60, 0x00de, 0x6013,
+	0x0000, 0x601f, 0x0001, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x67ee, 0x080c, 0x6c50, 0x0010, 0x080c, 0x974e, 0x0005, 0x6000,
+	0xa08a, 0x0010, 0x1a0c, 0x14f6, 0x000b, 0x0005, 0x9576, 0x9576,
+	0x9576, 0x9578, 0x9579, 0x9576, 0x9576, 0x9576, 0x9576, 0x9576,
+	0x9576, 0x9576, 0x9576, 0x9576, 0x9576, 0x9576, 0x080c, 0x14f6,
+	0x0005, 0x080c, 0x7cb8, 0x190c, 0x14f6, 0x6110, 0x2168, 0x684b,
+	0x0006, 0x080c, 0x510c, 0x080c, 0x8078, 0x0005, 0xa284, 0x0007,
+	0x1158, 0xa282, 0xb400, 0x0240, 0x2001, 0xad16, 0x2004, 0xa202,
+	0x1218, 0xa085, 0x0001, 0x0005, 0xa006, 0x0ce8, 0x0026, 0x6210,
+	0xa294, 0xf000, 0x002e, 0x0005, 0x00e6, 0x00c6, 0x0036, 0x0006,
+	0x0126, 0x2091, 0x8000, 0x2061, 0xb400, 0x2071, 0xad00, 0x7344,
+	0x7064, 0xa302, 0x12a8, 0x601c, 0xa206, 0x1160, 0x080c, 0x98e3,
+	0x0148, 0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x00c6, 0x080c,
+	0x8078, 0x00ce, 0xace0, 0x0018, 0x7058, 0xac02, 0x1208, 0x0c38,
+	0x012e, 0x000e, 0x003e, 0x00ce, 0x00ee, 0x0005, 0x00e6, 0x00c6,
+	0x0016, 0xa188, 0xae34, 0x210c, 0x81ff, 0x0170, 0x2061, 0xb400,
+	0x2071, 0xad00, 0x0016, 0x080c, 0x8022, 0x001e, 0x0138, 0x611a,
+	0x080c, 0x2ad9, 0x080c, 0x8078, 0xa006, 0x0010, 0xa085, 0x0001,
+	0x001e, 0x00ce, 0x00ee, 0x0005, 0x00c6, 0x0056, 0x0126, 0x2091,
+	0x8000, 0x00c6, 0x080c, 0x8022, 0x005e, 0x0180, 0x6612, 0x651a,
+	0x080c, 0x9956, 0x601f, 0x0003, 0x2009, 0x004b, 0x080c, 0x80a7,
+	0xa085, 0x0001, 0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0,
+	0x00c6, 0x0056, 0x0126, 0x2091, 0x8000, 0x62a0, 0x00c6, 0x080c,
+	0x8022, 0x005e, 0x0508, 0x6013, 0x0000, 0x651a, 0x080c, 0x9956,
+	0x601f, 0x0003, 0x00c6, 0x2560, 0x080c, 0x4ecf, 0x00ce, 0x080c,
+	0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c,
+	0xa712, 0x007e, 0x2009, 0x004c, 0x080c, 0x80a7, 0xa085, 0x0001,
+	0x012e, 0x005e, 0x00ce, 0x0005, 0xa006, 0x0cd0, 0x00f6, 0x00c6,
+	0x0046, 0x00c6, 0x080c, 0x8022, 0x2c78, 0x00ce, 0x0180, 0x7e12,
+	0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0005, 0x080c, 0x9683,
+	0x2f60, 0x2009, 0x004d, 0x080c, 0x80a7, 0xa085, 0x0001, 0x004e,
+	0x00ce, 0x00fe, 0x0005, 0x00f6, 0x00c6, 0x0046, 0x00c6, 0x080c,
+	0x8022, 0x2c78, 0x00ce, 0x0178, 0x7e12, 0x2c00, 0x781a, 0x781f,
+	0x0003, 0x2021, 0x0005, 0x0439, 0x2f60, 0x2009, 0x004e, 0x080c,
+	0x80a7, 0xa085, 0x0001, 0x004e, 0x00ce, 0x00fe, 0x0005, 0x00f6,
+	0x00c6, 0x0046, 0x00c6, 0x080c, 0x8022, 0x2c78, 0x00ce, 0x0178,
+	0x7e12, 0x2c00, 0x781a, 0x781f, 0x0003, 0x2021, 0x0004, 0x0059,
+	0x2f60, 0x2009, 0x0052, 0x080c, 0x80a7, 0xa085, 0x0001, 0x004e,
+	0x00ce, 0x00fe, 0x0005, 0x0096, 0x0076, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x4e71, 0x0118, 0x2001, 0x9688, 0x0028, 0x080c, 0x4e43,
+	0x0158, 0x2001, 0x968e, 0x0006, 0xa00e, 0x2400, 0x080c, 0x51df,
+	0x080c, 0x510c, 0x000e, 0x0807, 0x2418, 0x080c, 0x6b15, 0x62a0,
+	0x0086, 0x2041, 0x0001, 0x2039, 0x0001, 0x2608, 0x080c, 0x6900,
+	0x008e, 0x080c, 0x681d, 0x2f08, 0x2648, 0x080c, 0xa712, 0x613c,
+	0x81ff, 0x090c, 0x69a9, 0x012e, 0x007e, 0x009e, 0x0005, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188,
+	0x660a, 0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012,
+	0x2009, 0x001f, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6,
+	0x080c, 0x8022, 0x001e, 0x0188, 0x660a, 0x611a, 0x080c, 0x9956,
+	0x601f, 0x0008, 0x2d00, 0x6012, 0x2009, 0x0021, 0x080c, 0x80a7,
+	0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188,
+	0x660a, 0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012,
+	0x2009, 0x003d, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce,
+	0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126, 0x2091, 0x8000, 0x00c6,
+	0x080c, 0x9807, 0x001e, 0x0180, 0x611a, 0x080c, 0x9956, 0x601f,
+	0x0001, 0x2d00, 0x6012, 0x2009, 0x0000, 0x080c, 0x80a7, 0xa085,
+	0x0001, 0x012e, 0x00ce, 0x0005, 0xa006, 0x0cd8, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0188, 0x660a,
+	0x611a, 0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009,
+	0x0044, 0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005,
+	0xa006, 0x0cd8, 0x0026, 0x00d6, 0x6218, 0x2268, 0x6a3c, 0x82ff,
+	0x0110, 0x8211, 0x6a3e, 0x00de, 0x002e, 0x0005, 0x0006, 0x6000,
+	0xa086, 0x0000, 0x0190, 0x6013, 0x0000, 0x601f, 0x0007, 0x2001,
+	0xafa3, 0x2004, 0x0006, 0xa082, 0x0051, 0x000e, 0x0208, 0x8004,
+	0x6016, 0x080c, 0xabb4, 0x603f, 0x0000, 0x000e, 0x0005, 0x0066,
+	0x00c6, 0x00d6, 0x2031, 0xad52, 0x2634, 0xd6e4, 0x0128, 0x6618,
+	0x2660, 0x6e48, 0x080c, 0x4dfc, 0x00de, 0x00ce, 0x006e, 0x0005,
+	0x0006, 0x0016, 0x6004, 0xa08e, 0x0002, 0x0140, 0xa08e, 0x0003,
+	0x0128, 0xa08e, 0x0004, 0x0110, 0xa085, 0x0001, 0x001e, 0x000e,
+	0x0005, 0x0006, 0x00d6, 0x6010, 0xa06d, 0x0148, 0x6834, 0xa086,
+	0x0139, 0x0138, 0x6838, 0xd0fc, 0x0110, 0xa006, 0x0010, 0xa085,
+	0x0001, 0x00de, 0x000e, 0x0005, 0x00c6, 0x0126, 0x2091, 0x8000,
+	0x00c6, 0x080c, 0x8022, 0x001e, 0x0190, 0x611a, 0x080c, 0x9956,
+	0x601f, 0x0001, 0x2d00, 0x6012, 0x080c, 0x2ad9, 0x2009, 0x0028,
+	0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006,
+	0x0cd8, 0xa186, 0x0015, 0x1178, 0x2011, 0xad20, 0x2204, 0xa086,
+	0x0074, 0x1148, 0x080c, 0x8943, 0x6003, 0x0001, 0x6007, 0x0029,
+	0x080c, 0x67ee, 0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x0005,
+	0xa186, 0x0016, 0x1128, 0x2001, 0x0004, 0x080c, 0x4c30, 0x00e8,
+	0xa186, 0x0015, 0x11e8, 0x2011, 0xad20, 0x2204, 0xa086, 0x0014,
+	0x11b8, 0x00d6, 0x6018, 0x2068, 0x080c, 0x4d72, 0x00de, 0x080c,
+	0x89f7, 0x1170, 0x00d6, 0x6018, 0x2068, 0x6890, 0x00de, 0xa005,
+	0x0138, 0x2001, 0x0006, 0x080c, 0x4c30, 0x080c, 0x81f6, 0x0020,
+	0x080c, 0x85f3, 0x080c, 0x8078, 0x0005, 0x6848, 0xa086, 0x0005,
+	0x1108, 0x0009, 0x0005, 0x6850, 0xc0ad, 0x6852, 0x0005, 0x00e6,
+	0x0126, 0x2071, 0xad00, 0x2091, 0x8000, 0x7544, 0xa582, 0x0001,
+	0x0608, 0x7048, 0x2060, 0x6000, 0xa086, 0x0000, 0x0148, 0xace0,
+	0x0018, 0x7058, 0xac02, 0x1208, 0x0cb0, 0x2061, 0xb400, 0x0c98,
+	0x6003, 0x0008, 0x8529, 0x7546, 0xaca8, 0x0018, 0x7058, 0xa502,
+	0x1230, 0x754a, 0xa085, 0x0001, 0x012e, 0x00ee, 0x0005, 0x704b,
+	0xb400, 0x0cc0, 0xa006, 0x0cc0, 0x00e6, 0x2071, 0xb28c, 0x7014,
+	0xd0e4, 0x0150, 0x6013, 0x0000, 0x6003, 0x0001, 0x6007, 0x0050,
+	0x080c, 0x67a8, 0x080c, 0x6c50, 0x00ee, 0x0005, 0x00c6, 0x00f6,
+	0x2c78, 0x080c, 0x5029, 0x00fe, 0x0120, 0x601c, 0xa084, 0x000f,
+	0x0013, 0x00ce, 0x0005, 0x9369, 0x985e, 0x9861, 0x9864, 0xa9a7,
+	0xa9c2, 0xa9c5, 0x9369, 0x9369, 0x080c, 0x14f6, 0xe000, 0xe000,
+	0x0005, 0xe000, 0xe000, 0x0005, 0x0009, 0x0005, 0x00f6, 0x2c78,
+	0x080c, 0x5029, 0x0538, 0x080c, 0x8022, 0x1128, 0x2001, 0xafa5,
+	0x2004, 0x783e, 0x00f8, 0x7818, 0x601a, 0x080c, 0x9956, 0x781c,
+	0xa086, 0x0003, 0x0128, 0x7808, 0x6036, 0x2f00, 0x603a, 0x0020,
+	0x7808, 0x603a, 0x2f00, 0x6036, 0x602a, 0x601f, 0x0001, 0x6007,
+	0x0035, 0x6003, 0x0001, 0x7950, 0x6152, 0x080c, 0x67a8, 0x080c,
+	0x6c50, 0x2f60, 0x00fe, 0x0005, 0x0016, 0x00f6, 0x682c, 0x6032,
+	0xa08e, 0x0001, 0x0138, 0xa086, 0x0005, 0x0140, 0xa006, 0x602a,
+	0x602e, 0x00a0, 0x6820, 0xc0f4, 0xc0d5, 0x6822, 0x6810, 0x2078,
+	0x787c, 0x6938, 0xa102, 0x7880, 0x6934, 0xa103, 0x1e78, 0x6834,
+	0x602a, 0x6838, 0xa084, 0xfffc, 0x683a, 0x602e, 0x2d00, 0x6036,
+	0x6808, 0x603a, 0x6918, 0x611a, 0x6950, 0x6152, 0x601f, 0x0001,
+	0x6007, 0x0039, 0x6003, 0x0001, 0x080c, 0x67a8, 0x6803, 0x0002,
+	0x00fe, 0x001e, 0x0005, 0x00f6, 0x2c78, 0x080c, 0x5029, 0x1118,
+	0xa085, 0x0001, 0x0070, 0x6020, 0xd0f4, 0x1150, 0xc0f5, 0x6022,
+	0x6010, 0x2078, 0x7828, 0x603a, 0x782c, 0x6036, 0x080c, 0x190b,
+	0xa006, 0x00fe, 0x0005, 0x0006, 0x0016, 0x6004, 0xa08e, 0x0034,
+	0x01b8, 0xa08e, 0x0035, 0x01a0, 0xa08e, 0x0036, 0x0188, 0xa08e,
+	0x0037, 0x0170, 0xa08e, 0x0038, 0x0158, 0xa08e, 0x0039, 0x0140,
+	0xa08e, 0x003a, 0x0128, 0xa08e, 0x003b, 0x0110, 0xa085, 0x0001,
+	0x001e, 0x000e, 0x0005, 0x0006, 0x0016, 0x0026, 0x0036, 0x00e6,
+	0x2001, 0xaf9f, 0x200c, 0x8000, 0x2014, 0x2001, 0x0032, 0x080c,
+	0x6665, 0x2001, 0xafa3, 0x82ff, 0x1110, 0x2011, 0x0002, 0x2202,
+	0x2001, 0xafa1, 0x200c, 0x8000, 0x2014, 0x2071, 0xaf8d, 0x711a,
+	0x721e, 0x2001, 0x0064, 0x080c, 0x6665, 0x2001, 0xafa4, 0x82ff,
+	0x1110, 0x2011, 0x0002, 0x2202, 0x2009, 0xafa5, 0xa280, 0x000a,
+	0x200a, 0x00ee, 0x003e, 0x002e, 0x001e, 0x000e, 0x0005, 0x0006,
+	0x00e6, 0x2001, 0xafa3, 0x2003, 0x0028, 0x2001, 0xafa4, 0x2003,
+	0x0014, 0x2071, 0xaf8d, 0x701b, 0x0000, 0x701f, 0x07d0, 0x2001,
+	0xafa5, 0x2003, 0x001e, 0x00ee, 0x000e, 0x0005, 0x00d6, 0x6054,
+	0xa06d, 0x0110, 0x080c, 0x15f0, 0x00de, 0x0005, 0x0005, 0x00c6,
+	0x0126, 0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0178,
+	0x611a, 0x0ca1, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0033,
+	0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006,
+	0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xad00, 0xa186, 0x0015,
+	0x1500, 0x7080, 0xa086, 0x0018, 0x11e0, 0x6010, 0x2068, 0x6a3c,
+	0xd2e4, 0x1160, 0x2c78, 0x080c, 0x6e05, 0x01d8, 0x706c, 0x6a50,
+	0xa206, 0x1160, 0x7070, 0x6a54, 0xa206, 0x1140, 0x6218, 0xa290,
+	0x0028, 0x2214, 0x2009, 0x0000, 0x080c, 0x2b1e, 0x080c, 0x81f6,
+	0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x00fe, 0x00ee, 0x00de,
+	0x0005, 0x7050, 0x6a54, 0xa206, 0x0d48, 0x0c80, 0x00c6, 0x0126,
+	0x2091, 0x8000, 0x00c6, 0x080c, 0x8022, 0x001e, 0x0180, 0x611a,
+	0x080c, 0x9956, 0x601f, 0x0001, 0x2d00, 0x6012, 0x2009, 0x0043,
+	0x080c, 0x80a7, 0xa085, 0x0001, 0x012e, 0x00ce, 0x0005, 0xa006,
+	0x0cd8, 0x00d6, 0x00e6, 0x00f6, 0x2071, 0xad00, 0xa186, 0x0015,
+	0x11c0, 0x7080, 0xa086, 0x0004, 0x11a0, 0x6010, 0xa0e8, 0x000f,
+	0x2c78, 0x080c, 0x6e05, 0x01a8, 0x706c, 0x6a08, 0xa206, 0x1130,
+	0x7070, 0x6a0c, 0xa206, 0x1110, 0x080c, 0x2ad9, 0x080c, 0x81f6,
+	0x0020, 0x080c, 0x85f3, 0x080c, 0x8078, 0x00fe, 0x00ee, 0x00de,
+	0x0005, 0x7050, 0x6a0c, 0xa206, 0x0d78, 0x0c80, 0x0016, 0x0026,
+	0x684c, 0xd0ac, 0x0178, 0x6914, 0x6a10, 0x2100, 0xa205, 0x0150,
+	0x6860, 0xa106, 0x1118, 0x685c, 0xa206, 0x0120, 0x6962, 0x6a5e,
+	0xa085, 0x0001, 0x002e, 0x001e, 0x0005, 0x00d6, 0x0036, 0x6310,
+	0x2368, 0x684a, 0x6952, 0xa29e, 0x4000, 0x1188, 0x00c6, 0x6318,
+	0x2360, 0x2009, 0x0000, 0x080c, 0x4f6e, 0x1108, 0xc185, 0x6000,
+	0xd0bc, 0x0108, 0xc18d, 0x6a66, 0x696a, 0x00ce, 0x0080, 0x6a66,
+	0x3918, 0xa398, 0x0006, 0x231c, 0x686b, 0x0004, 0x6b72, 0x00c6,
+	0x6318, 0x2360, 0x6004, 0xa084, 0x00ff, 0x686e, 0x00ce, 0x080c,
+	0x510c, 0x003e, 0x00de, 0x0005, 0x00c6, 0x0026, 0x0016, 0xa186,
+	0x0035, 0x0110, 0x6a34, 0x0008, 0x6a28, 0x080c, 0x9586, 0x01f0,
+	0x2260, 0x611c, 0xa186, 0x0003, 0x0118, 0xa186, 0x0006, 0x1190,
+	0x6834, 0xa206, 0x0140, 0x6838, 0xa206, 0x1160, 0x6108, 0x6834,
+	0xa106, 0x1140, 0x0020, 0x6008, 0x6938, 0xa106, 0x1118, 0x6018,
+	0x6918, 0xa106, 0x001e, 0x002e, 0x00ce, 0x0005, 0xa085, 0x0001,
+	0x0cc8, 0x0066, 0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013,
+	0x006e, 0x0005, 0x9a7a, 0x9eff, 0xa027, 0x9a7a, 0x9a7a, 0x9a7a,
+	0x9a7a, 0x9a7a, 0x9ab2, 0xa0a3, 0x9a7a, 0x9a7a, 0x9a7a, 0x9a7a,
+	0x9a7a, 0x9a7a, 0x080c, 0x14f6, 0x0066, 0x6000, 0xa0b2, 0x0010,
+	0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005, 0x9a95, 0xa4fd, 0x9a95,
+	0x9a95, 0x9a95, 0x9a95, 0x9a95, 0x9a95, 0xa4c1, 0xa545, 0x9a95,
+	0xaaea, 0xab1a, 0xaaea, 0xab1a, 0x9a95, 0x080c, 0x14f6, 0x0066,
+	0x6000, 0xa0b2, 0x0010, 0x1a0c, 0x14f6, 0x0013, 0x006e, 0x0005,
+	0x9ab0, 0xa1d8, 0xa295, 0xa2c2, 0xa346, 0x9ab0, 0xa433, 0xa3de,
+	0xa0af, 0xa497, 0xa4ac, 0x9ab0, 0x9ab0, 0x9ab0, 0x9ab0, 0x9ab0,
+	0x080c, 0x14f6, 0xa1b2, 0x0080, 0x1a0c, 0x14f6, 0x2100, 0xa1b2,
+	0x0040, 0x1a04, 0x9e79, 0x0002, 0x9afc, 0x9cab, 0x9afc, 0x9afc,
+	0x9afc, 0x9cb2, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc,
+	0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc,
+	0x9afc, 0x9afc, 0x9afc, 0x9afe, 0x9b5a, 0x9b65, 0x9ba6, 0x9bc0,
+	0x9c3e, 0x9c9c, 0x9afc, 0x9afc, 0x9cb5, 0x9afc, 0x9afc, 0x9cc4,
+	0x9ccb, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9afc, 0x9d42, 0x9afc,
+	0x9afc, 0x9d4d, 0x9afc, 0x9afc, 0x9d18, 0x9afc, 0x9afc, 0x9afc,
+	0x9d61, 0x9afc, 0x9afc, 0x9afc, 0x9dd5, 0x9afc, 0x9afc, 0x9afc,
+	0x9afc, 0x9afc, 0x9afc, 0x9e40, 0x080c, 0x14f6, 0x080c, 0x502d,
+	0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008,
+	0x1140, 0x6007, 0x0009, 0x602b, 0x0009, 0x6013, 0x0000, 0x0804,
+	0x9ca6, 0x080c, 0x501d, 0x00e6, 0x00c6, 0x0036, 0x0026, 0x0016,
+	0x6218, 0x2270, 0x72a0, 0x0026, 0x2019, 0x0029, 0x080c, 0x68e7,
+	0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712,
+	0x007e, 0x001e, 0x2e60, 0x080c, 0x4ecf, 0x001e, 0x002e, 0x003e,
+	0x00ce, 0x00ee, 0x6618, 0x00c6, 0x2660, 0x080c, 0x4ceb, 0x00ce,
+	0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x0278,
+	0x080c, 0xa656, 0x1904, 0x9ba0, 0x080c, 0xa5f6, 0x1120, 0x6007,
+	0x0008, 0x0804, 0x9ca6, 0x6007, 0x0009, 0x0804, 0x9ca6, 0x080c,
+	0xa801, 0x0128, 0x080c, 0xa656, 0x0d78, 0x0804, 0x9ba0, 0x6013,
+	0x1900, 0x0c88, 0x6106, 0x080c, 0xa5a6, 0x6007, 0x0006, 0x0804,
+	0x9ca6, 0x6007, 0x0007, 0x0804, 0x9ca6, 0x080c, 0xab4e, 0x1904,
+	0x9e76, 0x00d6, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637,
+	0xa686, 0x0006, 0x0188, 0xa686, 0x0004, 0x0170, 0x6e04, 0xa6b4,
+	0x00ff, 0xa686, 0x0006, 0x0140, 0xa686, 0x0004, 0x0128, 0xa686,
+	0x0005, 0x0110, 0x00de, 0x00e0, 0x080c, 0xa6b4, 0x11a0, 0xa686,
+	0x0006, 0x1150, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009,
+	0x0000, 0x080c, 0x2b1e, 0x002e, 0x080c, 0x4d72, 0x6007, 0x000a,
+	0x00de, 0x0804, 0x9ca6, 0x6007, 0x000b, 0x00de, 0x0804, 0x9ca6,
+	0x080c, 0x2ad9, 0x6007, 0x0001, 0x0804, 0x9ca6, 0x080c, 0xab4e,
+	0x1904, 0x9e76, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de, 0xa686,
+	0x0707, 0x0d70, 0x0026, 0x6218, 0xa290, 0x0028, 0x2214, 0x2009,
+	0x0000, 0x080c, 0x2b1e, 0x002e, 0x6007, 0x000c, 0x0804, 0x9ca6,
+	0x080c, 0x502d, 0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009,
+	0xa086, 0x0008, 0x1110, 0x0804, 0x9b09, 0x080c, 0x501d, 0x6618,
+	0xa6b0, 0x0001, 0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06e8,
+	0x1138, 0x0026, 0x2001, 0x0006, 0x080c, 0x4c5d, 0x002e, 0x0050,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006,
+	0x1904, 0x9ba0, 0x080c, 0xa6c1, 0x1120, 0x6007, 0x000e, 0x0804,
+	0x9ca6, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff,
+	0x8427, 0x0046, 0x080c, 0x2ad9, 0x004e, 0x0016, 0xa006, 0x2009,
+	0xad52, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xa96c,
+	0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x0804, 0x9ca6, 0x2001, 0x0001, 0x080c,
+	0x4c1e, 0x0156, 0x0016, 0x0026, 0x0036, 0x20a9, 0x0004, 0x2019,
+	0xad05, 0x2011, 0xb290, 0x080c, 0x8a7c, 0x003e, 0x002e, 0x001e,
+	0x015e, 0xa005, 0x0168, 0xa6b4, 0xff00, 0x8637, 0xa682, 0x0004,
+	0x0a04, 0x9ba0, 0xa682, 0x0007, 0x0a04, 0x9bea, 0x0804, 0x9ba0,
+	0x6013, 0x1900, 0x6007, 0x0009, 0x0804, 0x9ca6, 0x080c, 0x502d,
+	0x1140, 0x2001, 0xad34, 0x2004, 0xa084, 0x0009, 0xa086, 0x0008,
+	0x1110, 0x0804, 0x9b09, 0x080c, 0x501d, 0x6618, 0xa6b0, 0x0001,
+	0x2634, 0xa684, 0x00ff, 0xa082, 0x0006, 0x06b0, 0xa6b4, 0xff00,
+	0x8637, 0xa686, 0x0004, 0x0120, 0xa686, 0x0006, 0x1904, 0x9ba0,
+	0x080c, 0xa6e9, 0x1130, 0x080c, 0xa5f6, 0x1118, 0x6007, 0x0010,
+	0x04e8, 0x0046, 0x6418, 0xa4a0, 0x0028, 0x2424, 0xa4a4, 0x00ff,
+	0x8427, 0x0046, 0x080c, 0x2ad9, 0x004e, 0x0016, 0xa006, 0x2009,
+	0xad52, 0x210c, 0xd1a4, 0x0158, 0x2009, 0x0029, 0x080c, 0xa96c,
+	0x6018, 0x00d6, 0x2068, 0x6800, 0xc0e5, 0x6802, 0x00de, 0x001e,
+	0x004e, 0x6007, 0x0001, 0x00d0, 0x080c, 0xa801, 0x0140, 0xa6b4,
+	0xff00, 0x8637, 0xa686, 0x0006, 0x0958, 0x0804, 0x9ba0, 0x6013,
+	0x1900, 0x6007, 0x0009, 0x0050, 0x080c, 0xab4e, 0x1904, 0x9e76,
+	0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6007, 0x0012, 0x6003, 0x0001,
+	0x080c, 0x67ee, 0x0005, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c,
+	0x67ee, 0x0cc0, 0x6007, 0x0005, 0x0cc0, 0x080c, 0xab4e, 0x1904,
+	0x9e76, 0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6007, 0x0020, 0x6003,
+	0x0001, 0x080c, 0x67ee, 0x0005, 0x6007, 0x0023, 0x6003, 0x0001,
+	0x080c, 0x67ee, 0x0005, 0x080c, 0xab4e, 0x1904, 0x9e76, 0x080c,
+	0x9e98, 0x1904, 0x9ba0, 0x0016, 0x0026, 0x2011, 0xb291, 0x2214,
+	0xa286, 0xffff, 0x0190, 0x2c08, 0x080c, 0x9586, 0x01d8, 0x2260,
+	0x2011, 0xb290, 0x2214, 0x6008, 0xa206, 0x11a0, 0x6018, 0xa190,
+	0x0006, 0x2214, 0xa206, 0x01e0, 0x0068, 0x2011, 0xb290, 0x2214,
+	0x2c08, 0x080c, 0xa940, 0x11a0, 0x2011, 0xb291, 0x2214, 0xa286,
+	0xffff, 0x01a0, 0x2160, 0x6007, 0x0026, 0x6013, 0x1700, 0x2011,
+	0xb289, 0x2214, 0xa296, 0xffff, 0x1160, 0x6007, 0x0025, 0x0048,
+	0x601c, 0xa086, 0x0007, 0x1d70, 0x080c, 0x8078, 0x2160, 0x6007,
+	0x0025, 0x6003, 0x0001, 0x080c, 0x67ee, 0x002e, 0x001e, 0x0005,
+	0x2001, 0x0001, 0x080c, 0x4c1e, 0x0156, 0x0016, 0x0026, 0x0036,
+	0x20a9, 0x0004, 0x2019, 0xad05, 0x2011, 0xb296, 0x080c, 0x8a7c,
+	0x003e, 0x002e, 0x001e, 0x015e, 0x0120, 0x6007, 0x0031, 0x0804,
+	0x9ca6, 0x080c, 0x87bd, 0x080c, 0x574f, 0x1158, 0x0006, 0x0026,
+	0x0036, 0x080c, 0x576b, 0x0110, 0x080c, 0x5726, 0x003e, 0x002e,
+	0x000e, 0x0005, 0x6106, 0x080c, 0x9eb4, 0x6007, 0x002b, 0x0804,
+	0x9ca6, 0x6007, 0x002c, 0x0804, 0x9ca6, 0x080c, 0xab4e, 0x1904,
+	0x9e76, 0x080c, 0x9e98, 0x1904, 0x9ba0, 0x6106, 0x080c, 0x9eb8,
+	0x1120, 0x6007, 0x002e, 0x0804, 0x9ca6, 0x6007, 0x002f, 0x0804,
+	0x9ca6, 0x00e6, 0x00d6, 0x00c6, 0x6018, 0xa080, 0x0001, 0x200c,
+	0xa184, 0x00ff, 0xa086, 0x0006, 0x0158, 0xa184, 0xff00, 0x8007,
+	0xa086, 0x0006, 0x0128, 0x00ce, 0x00de, 0x00ee, 0x0804, 0x9cab,
+	0x2001, 0xad71, 0x2004, 0xd0e4, 0x0904, 0x9dd2, 0x2071, 0xb28c,
+	0x7010, 0x6036, 0x7014, 0x603a, 0x7108, 0x720c, 0x2001, 0xad52,
+	0x2004, 0xd0a4, 0x0140, 0x6018, 0x2068, 0x6810, 0xa106, 0x1118,
+	0x6814, 0xa206, 0x01f8, 0x2001, 0xad52, 0x2004, 0xd0ac, 0x1580,
+	0x2069, 0xad00, 0x6870, 0xa206, 0x1558, 0x686c, 0xa106, 0x1540,
+	0x7210, 0x080c, 0x9586, 0x0548, 0x080c, 0xa9d4, 0x0530, 0x622a,
+	0x6007, 0x0036, 0x6003, 0x0001, 0x080c, 0x67a8, 0x00ce, 0x00de,
+	0x00ee, 0x0005, 0x7214, 0xa286, 0xffff, 0x0150, 0x080c, 0x9586,
+	0x01a0, 0xa280, 0x0002, 0x2004, 0x7110, 0xa106, 0x1170, 0x0c08,
+	0x7210, 0x2c08, 0x080c, 0xa940, 0x2c10, 0x2160, 0x0130, 0x08c8,
+	0x6007, 0x0037, 0x6013, 0x1500, 0x08e8, 0x6007, 0x0037, 0x6013,
+	0x1700, 0x08c0, 0x6007, 0x0012, 0x08a8, 0x6018, 0xa080, 0x0001,
+	0x2004, 0xa084, 0xff00, 0x8007, 0xa086, 0x0006, 0x1904, 0x9cab,
+	0x00e6, 0x00d6, 0x00c6, 0x2001, 0xad71, 0x2004, 0xd0e4, 0x0904,
+	0x9e38, 0x2069, 0xad00, 0x2071, 0xb28c, 0x7008, 0x6036, 0x720c,
+	0x623a, 0xa286, 0xffff, 0x1140, 0x7208, 0x00c6, 0x2c08, 0x080c,
+	0xa940, 0x2c10, 0x00ce, 0x0588, 0x080c, 0x9586, 0x0570, 0x00c6,
+	0x0026, 0x2260, 0x080c, 0x928f, 0x002e, 0x00ce, 0x7118, 0xa18c,
+	0xff00, 0x810f, 0xa186, 0x0001, 0x0158, 0xa186, 0x0005, 0x0118,
+	0xa186, 0x0007, 0x1178, 0xa280, 0x0004, 0x2004, 0xa005, 0x0150,
+	0x0056, 0x7510, 0x7614, 0x080c, 0xa9eb, 0x005e, 0x00ce, 0x00de,
+	0x00ee, 0x0005, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00,
+	0x6003, 0x0001, 0x080c, 0x67a8, 0x0c88, 0x6007, 0x003b, 0x602b,
+	0x0009, 0x6013, 0x1700, 0x6003, 0x0001, 0x080c, 0x67a8, 0x0c30,
+	0x6007, 0x003b, 0x602b, 0x000b, 0x6013, 0x0000, 0x0804, 0x9daa,
+	0x00e6, 0x0026, 0x080c, 0x502d, 0x0558, 0x080c, 0x501d, 0x080c,
+	0xabc5, 0x1520, 0x2071, 0xad00, 0x70d0, 0xc085, 0x70d2, 0x00f6,
+	0x2079, 0x0100, 0x729c, 0xa284, 0x00ff, 0x706e, 0x78e6, 0xa284,
+	0xff00, 0x7270, 0xa205, 0x7072, 0x78ea, 0x00fe, 0x70db, 0x0000,
+	0x2001, 0xad52, 0x2004, 0xd0a4, 0x0120, 0x2011, 0xafe0, 0x2013,
+	0x07d0, 0xd0ac, 0x1128, 0x080c, 0x28fa, 0x0010, 0x080c, 0xabf1,
+	0x002e, 0x00ee, 0x080c, 0x8078, 0x0804, 0x9caa, 0x080c, 0x8078,
+	0x0005, 0x2600, 0x0002, 0x9e81, 0x9e81, 0x9e81, 0x9e81, 0x9e81,
+	0x9e83, 0x080c, 0x14f6, 0x080c, 0xab4e, 0x1d80, 0x0089, 0x1138,
+	0x6007, 0x0045, 0x6003, 0x0001, 0x080c, 0x67ee, 0x0005, 0x080c,
+	0x2ad9, 0x6007, 0x0001, 0x6003, 0x0001, 0x080c, 0x67ee, 0x0005,
+	0x00d6, 0x0066, 0x6618, 0x2668, 0x6e04, 0xa6b4, 0xff00, 0x8637,
+	0xa686, 0x0006, 0x0170, 0xa686, 0x0004, 0x0158, 0x6e04, 0xa6b4,
+	0x00ff, 0xa686, 0x0006, 0x0128, 0xa686, 0x0004, 0x0110, 0xa085,
+	0x0001, 0x006e, 0x00de, 0x0005, 0x00d6, 0x0449, 0x00de, 0x0005,
+	0x00d6, 0x0491, 0x11f0, 0x680c, 0xa08c, 0xff00, 0x6820, 0xa084,
+	0x00ff, 0xa115, 0x6212, 0x6824, 0x602a, 0xd1e4, 0x0118, 0x2009,
+	0x0001, 0x0060, 0xd1ec, 0x0168, 0x6920, 0xa18c, 0x00ff, 0x6824,
+	0x080c, 0x2676, 0x1130, 0x2110, 0x2009, 0x0000, 0x080c, 0x2b1e,
+	0x0018, 0xa085, 0x0001, 0x0008, 0xa006, 0x00de, 0x0005, 0x2069,
+	0xb28d, 0x6800, 0xa082, 0x0010, 0x1228, 0x6013, 0x0000, 0xa085,
+	0x0001, 0x0008, 0xa006, 0x0005, 0x6013, 0x0000, 0x2069, 0xb28c,
+	0x6808, 0xa084, 0xff00, 0xa086, 0x0800, 0x1140, 0x6800, 0xa084,
+	0x00ff, 0xa08e, 0x0014, 0x0110, 0xa08e, 0x0010, 0x0005, 0x6004,
+	0xa0b2, 0x0080, 0x1a0c, 0x14f6, 0xa1b6, 0x0013, 0x1130, 0x2008,
+	0xa1b2, 0x0040, 0x1a04, 0x9ffb, 0x0092, 0xa1b6, 0x0027, 0x0120,
+	0xa1b6, 0x0014, 0x190c, 0x14f6, 0x2001, 0x0007, 0x080c, 0x4c5d,
+	0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0x9f5f,
+	0x9f61, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f61, 0x9f6f, 0x9ff4, 0x9fbf,
+	0x9ff4, 0x9fd0, 0x9ff4, 0x9f6f, 0x9ff4, 0x9fec, 0x9ff4, 0x9fec,
+	0x9ff4, 0x9ff4, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f,
+	0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f61, 0x9f5f, 0x9ff4,
+	0x9f5f, 0x9f5f, 0x9ff4, 0x9f5f, 0x9ff1, 0x9ff4, 0x9f5f, 0x9f5f,
+	0x9f5f, 0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f,
+	0x9f69, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x9ff0, 0x9ff4, 0x9f5f,
+	0x9f5f, 0x9ff4, 0x9ff4, 0x9f5f, 0x9f5f, 0x9f5f, 0x9f5f, 0x080c,
+	0x14f6, 0x080c, 0x6b73, 0x6003, 0x0002, 0x080c, 0x6c50, 0x0804,
+	0x9ffa, 0x2001, 0x0000, 0x080c, 0x4c1e, 0x0804, 0x9ff4, 0x00f6,
+	0x2079, 0xad51, 0x7804, 0x00fe, 0xd0ac, 0x1904, 0x9ff4, 0x2001,
+	0x0000, 0x080c, 0x4c1e, 0x6018, 0xa080, 0x0004, 0x2004, 0xa086,
+	0x00ff, 0x1140, 0x00f6, 0x2079, 0xad00, 0x7894, 0x8000, 0x7896,
+	0x00fe, 0x00e0, 0x00c6, 0x6018, 0x2060, 0x6000, 0xd0f4, 0x1140,
+	0x6010, 0xa005, 0x0128, 0x00ce, 0x080c, 0x3cce, 0x0804, 0x9ff4,
+	0x00ce, 0x2001, 0xad00, 0x2004, 0xa086, 0x0002, 0x1138, 0x00f6,
+	0x2079, 0xad00, 0x7894, 0x8000, 0x7896, 0x00fe, 0x2001, 0x0002,
+	0x080c, 0x4c30, 0x080c, 0x6b73, 0x601f, 0x0001, 0x6003, 0x0001,
+	0x6007, 0x0002, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00c6, 0x6118,
+	0x2160, 0x2009, 0x0001, 0x080c, 0x6519, 0x00ce, 0x04d8, 0x6618,
+	0x00d6, 0x2668, 0x6e04, 0x00de, 0xa6b4, 0xff00, 0x8637, 0xa686,
+	0x0006, 0x0550, 0xa686, 0x0004, 0x0538, 0x2001, 0x0004, 0x0410,
+	0x2001, 0xad00, 0x2004, 0xa086, 0x0003, 0x1110, 0x080c, 0x3cce,
+	0x2001, 0x0006, 0x0489, 0x6618, 0x00d6, 0x2668, 0x6e04, 0x00de,
+	0xa6b4, 0xff00, 0x8637, 0xa686, 0x0006, 0x0170, 0x2001, 0x0006,
+	0x0048, 0x2001, 0x0004, 0x0030, 0x2001, 0x0006, 0x00e9, 0x0020,
+	0x0018, 0x0010, 0x080c, 0x4c5d, 0x080c, 0x6b73, 0x080c, 0x8078,
+	0x080c, 0x6c50, 0x0005, 0x2600, 0x0002, 0xa003, 0xa003, 0xa003,
+	0xa003, 0xa003, 0xa005, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x080c,
+	0x8078, 0x080c, 0x6c50, 0x0005, 0x0016, 0x00d6, 0x6118, 0x2168,
+	0x6900, 0xd184, 0x0188, 0x6104, 0xa18e, 0x000a, 0x1128, 0x699c,
+	0xd1a4, 0x1110, 0x2001, 0x0007, 0x080c, 0x4c30, 0x2001, 0x0000,
+	0x080c, 0x4c1e, 0x080c, 0x2aff, 0x00de, 0x001e, 0x0005, 0x00d6,
+	0x6618, 0x2668, 0x6804, 0xa084, 0xff00, 0x8007, 0x00de, 0xa0b2,
+	0x000c, 0x1a0c, 0x14f6, 0xa1b6, 0x0015, 0x1110, 0x003b, 0x0028,
+	0xa1b6, 0x0016, 0x190c, 0x14f6, 0x006b, 0x0005, 0x86b9, 0x86b9,
+	0x86b9, 0x86b9, 0x86b9, 0x86b9, 0xa08f, 0xa056, 0x86b9, 0x86b9,
+	0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x86b9,
+	0xa08f, 0xa096, 0x86b9, 0x86b9, 0x86b9, 0x86b9, 0x00f6, 0x2079,
+	0xad51, 0x7804, 0xd0ac, 0x11e0, 0x6018, 0xa07d, 0x01c8, 0x7800,
+	0xd0f4, 0x1118, 0x7810, 0xa005, 0x1198, 0x2001, 0x0000, 0x080c,
+	0x4c1e, 0x2001, 0x0002, 0x080c, 0x4c30, 0x601f, 0x0001, 0x6003,
+	0x0001, 0x6007, 0x0002, 0x080c, 0x67ee, 0x080c, 0x6c50, 0x00a8,
+	0x2011, 0xb283, 0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x1168,
+	0x00c6, 0x080c, 0x4cdc, 0x0120, 0x00ce, 0x080c, 0x8078, 0x0028,
+	0x080c, 0x493a, 0x00ce, 0x080c, 0x8078, 0x00fe, 0x0005, 0x6604,
+	0xa6b6, 0x001e, 0x1110, 0x080c, 0x8078, 0x0005, 0x080c, 0x8940,
+	0x1138, 0x6003, 0x0001, 0x6007, 0x0001, 0x080c, 0x67ee, 0x0010,
+	0x080c, 0x8078, 0x0005, 0x6004, 0xa08a, 0x0080, 0x1a0c, 0x14f6,
+	0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005, 0xa182,
+	0x0040, 0x0002, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c7, 0xa0c5,
+	0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5,
+	0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0xa0c5, 0x080c, 0x14f6, 0x00d6,
+	0x00e6, 0x00f6, 0x0156, 0x0046, 0x0026, 0x6218, 0xa280, 0x002b,
+	0x2004, 0xa005, 0x0120, 0x2021, 0x0000, 0x080c, 0xab96, 0x6106,
+	0x2071, 0xb280, 0x7444, 0xa4a4, 0xff00, 0x0904, 0xa129, 0xa486,
+	0x2000, 0x1130, 0x2009, 0x0001, 0x2011, 0x0200, 0x080c, 0x663f,
+	0x080c, 0x15d9, 0x090c, 0x14f6, 0x6003, 0x0007, 0x2d00, 0x6837,
+	0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x6c5a, 0x2c00, 0x685e,
+	0x6008, 0x68b2, 0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x694a,
+	0x0016, 0xa084, 0xff00, 0x6846, 0x684f, 0x0000, 0x6857, 0x0036,
+	0x080c, 0x510c, 0x001e, 0xa486, 0x2000, 0x1130, 0x2019, 0x0017,
+	0x080c, 0xa8eb, 0x0804, 0xa186, 0xa486, 0x0400, 0x1130, 0x2019,
+	0x0002, 0x080c, 0xa89d, 0x0804, 0xa186, 0xa486, 0x0200, 0x1110,
+	0x080c, 0xa882, 0xa486, 0x1000, 0x1110, 0x080c, 0xa8d0, 0x0804,
+	0xa186, 0x2069, 0xb048, 0x6a00, 0xd284, 0x0904, 0xa1d5, 0xa284,
+	0x0300, 0x1904, 0xa1cf, 0x6804, 0xa005, 0x0904, 0xa1c0, 0x2d78,
+	0x6003, 0x0007, 0x080c, 0x15c0, 0x0904, 0xa18d, 0x7800, 0xd08c,
+	0x1118, 0x7804, 0x8001, 0x7806, 0x6013, 0x0000, 0x6803, 0x0000,
+	0x6837, 0x0116, 0x683b, 0x0000, 0x6008, 0x68b2, 0x2c00, 0x684a,
+	0x6018, 0x2078, 0x78a0, 0x8007, 0x7130, 0x6986, 0x6846, 0x7928,
+	0x698a, 0x792c, 0x698e, 0x7930, 0x6992, 0x7934, 0x6996, 0x6853,
+	0x003d, 0x7244, 0xa294, 0x0003, 0xa286, 0x0002, 0x1118, 0x684f,
+	0x0040, 0x0040, 0xa286, 0x0001, 0x1118, 0x684f, 0x0080, 0x0010,
+	0x684f, 0x0000, 0x20a9, 0x000a, 0x2001, 0xb290, 0xad90, 0x0015,
+	0x200c, 0x810f, 0x2112, 0x8000, 0x8210, 0x1f04, 0xa178, 0x200c,
+	0x6982, 0x8000, 0x200c, 0x697e, 0x080c, 0x510c, 0x002e, 0x004e,
+	0x015e, 0x00fe, 0x00ee, 0x00de, 0x0005, 0x6013, 0x0100, 0x6003,
+	0x0001, 0x6007, 0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0c70,
+	0x2069, 0xb292, 0x2d04, 0xa084, 0xff00, 0xa086, 0x1200, 0x11a8,
+	0x2069, 0xb280, 0x686c, 0xa084, 0x00ff, 0x0016, 0x6110, 0xa18c,
+	0x0700, 0xa10d, 0x6112, 0x001e, 0x6003, 0x0001, 0x6007, 0x0043,
+	0x080c, 0x67a8, 0x080c, 0x6c50, 0x0888, 0x6013, 0x0200, 0x6003,
+	0x0001, 0x6007, 0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0830,
+	0x6013, 0x0300, 0x0010, 0x6013, 0x0100, 0x6003, 0x0001, 0x6007,
+	0x0041, 0x080c, 0x67a8, 0x080c, 0x6c50, 0x0804, 0xa186, 0x6013,
+	0x0500, 0x0c98, 0x6013, 0x0600, 0x0818, 0x6013, 0x0200, 0x0800,
+	0xa186, 0x0013, 0x1170, 0x6004, 0xa08a, 0x0040, 0x0a0c, 0x14f6,
+	0xa08a, 0x0053, 0x1a0c, 0x14f6, 0xa082, 0x0040, 0x2008, 0x0804,
+	0xa252, 0xa186, 0x0051, 0x0138, 0xa186, 0x0047, 0x11d8, 0x6004,
+	0xa086, 0x0041, 0x0518, 0x2001, 0x0109, 0x2004, 0xd084, 0x01f0,
+	0x0126, 0x2091, 0x2800, 0x0006, 0x0016, 0x0026, 0x080c, 0x6699,
+	0x002e, 0x001e, 0x000e, 0x012e, 0x6000, 0xa086, 0x0002, 0x1170,
+	0x0804, 0xa295, 0xa186, 0x0027, 0x0120, 0xa186, 0x0014, 0x190c,
+	0x14f6, 0x6004, 0xa082, 0x0040, 0x2008, 0x001a, 0x080c, 0x80be,
+	0x0005, 0xa22c, 0xa22e, 0xa22e, 0xa22c, 0xa22c, 0xa22c, 0xa22c,
+	0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c, 0xa22c,
+	0xa22c, 0xa22c, 0xa22c, 0xa22c, 0x080c, 0x14f6, 0x080c, 0x6b73,
+	0x080c, 0x6c50, 0x0036, 0x00d6, 0x6010, 0xa06d, 0x01c0, 0xad84,
+	0xf000, 0x01a8, 0x6003, 0x0002, 0x6018, 0x2004, 0xd0bc, 0x1178,
+	0x2019, 0x0004, 0x080c, 0xa91f, 0x6013, 0x0000, 0x6014, 0xa005,
+	0x1120, 0x2001, 0xafa4, 0x2004, 0x6016, 0x6003, 0x0007, 0x00de,
+	0x003e, 0x0005, 0x0002, 0xa266, 0xa283, 0xa26f, 0xa28f, 0xa266,
+	0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266,
+	0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0xa266, 0x080c, 0x14f6,
+	0x6010, 0xa088, 0x0013, 0x2104, 0xa085, 0x0400, 0x200a, 0x080c,
+	0x6b73, 0x6010, 0xa080, 0x0013, 0x2004, 0xd0b4, 0x0138, 0x6003,
+	0x0007, 0x2009, 0x0043, 0x080c, 0x80a7, 0x0010, 0x6003, 0x0002,
+	0x080c, 0x6c50, 0x0005, 0x080c, 0x6b73, 0x080c, 0xab55, 0x1120,
+	0x080c, 0x6618, 0x080c, 0x8078, 0x080c, 0x6c50, 0x0005, 0x080c,
+	0x6b73, 0x2009, 0x0041, 0x0804, 0xa3de, 0xa182, 0x0040, 0x0002,
+	0xa2ab, 0xa2ad, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ae,
+	0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab, 0xa2ab,
+	0xa2ab, 0xa2b9, 0xa2ab, 0x080c, 0x14f6, 0x0005, 0x6003, 0x0004,
+	0x6110, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10, 0x080c, 0x1824,
+	0x0005, 0x00d6, 0x080c, 0x6618, 0x00de, 0x080c, 0xabb4, 0x080c,
+	0x8078, 0x0005, 0xa182, 0x0040, 0x0002, 0xa2d8, 0xa2d8, 0xa2d8,
+	0xa2d8, 0xa2d8, 0xa2d8, 0xa2d8, 0xa2da, 0xa2d8, 0xa2dd, 0xa316,
+	0xa2d8, 0xa2d8, 0xa2d8, 0xa2d8, 0xa316, 0xa2d8, 0xa2d8, 0xa2d8,
+	0x080c, 0x14f6, 0x080c, 0x80be, 0x0005, 0x2001, 0xad71, 0x2004,
+	0xd0e4, 0x0158, 0x2001, 0x0100, 0x2004, 0xa082, 0x0005, 0x0228,
+	0x2001, 0x011f, 0x2004, 0x6036, 0x0010, 0x6037, 0x0000, 0x080c,
+	0x6c05, 0x080c, 0x6d0d, 0x6010, 0x00d6, 0x2068, 0x684c, 0xd0fc,
+	0x0150, 0xa08c, 0x0003, 0xa18e, 0x0002, 0x0168, 0x2009, 0x0041,
+	0x00de, 0x0804, 0xa3de, 0x6003, 0x0007, 0x6017, 0x0000, 0x080c,
+	0x6618, 0x00de, 0x0005, 0x080c, 0xab55, 0x0110, 0x00de, 0x0005,
+	0x080c, 0x6618, 0x080c, 0x8078, 0x00de, 0x0ca0, 0x0036, 0x080c,
+	0x6c05, 0x080c, 0x6d0d, 0x6010, 0x00d6, 0x2068, 0x6018, 0x2004,
+	0xd0bc, 0x0188, 0x684c, 0xa084, 0x0003, 0xa086, 0x0002, 0x0140,
+	0x687c, 0x632c, 0xa31a, 0x632e, 0x6880, 0x6328, 0xa31b, 0x632a,
+	0x6003, 0x0002, 0x0080, 0x2019, 0x0004, 0x080c, 0xa91f, 0x6014,
+	0xa005, 0x1128, 0x2001, 0xafa4, 0x2004, 0x8003, 0x6016, 0x6013,
+	0x0000, 0x6003, 0x0007, 0x00de, 0x003e, 0x0005, 0xa186, 0x0013,
+	0x1150, 0x6004, 0xa086, 0x0042, 0x190c, 0x14f6, 0x080c, 0x6b73,
+	0x080c, 0x6c50, 0x0005, 0xa186, 0x0027, 0x0118, 0xa186, 0x0014,
+	0x1180, 0x6004, 0xa086, 0x0042, 0x190c, 0x14f6, 0x2001, 0x0007,
+	0x080c, 0x4c5d, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50,
+	0x0005, 0xa182, 0x0040, 0x0002, 0xa37f, 0xa37f, 0xa37f, 0xa37f,
+	0xa37f, 0xa37f, 0xa37f, 0xa381, 0xa38d, 0xa37f, 0xa37f, 0xa37f,
+	0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0xa37f, 0x080c,
+	0x14f6, 0x0036, 0x0046, 0x20e1, 0x0005, 0x3d18, 0x3e20, 0x2c10,
+	0x080c, 0x1824, 0x004e, 0x003e, 0x0005, 0x6010, 0x00d6, 0x2068,
+	0x6810, 0x6a14, 0x0006, 0x0046, 0x0056, 0x6c7c, 0xa422, 0x6d80,
+	0x2200, 0xa52b, 0x602c, 0xa420, 0x642e, 0x6028, 0xa529, 0x652a,
+	0x005e, 0x004e, 0x000e, 0xa20d, 0x1178, 0x684c, 0xd0fc, 0x0120,
+	0x2009, 0x0041, 0x00de, 0x0490, 0x6003, 0x0007, 0x6017, 0x0000,
+	0x080c, 0x6618, 0x00de, 0x0005, 0x0006, 0x00f6, 0x2c78, 0x080c,
+	0x5029, 0x00fe, 0x000e, 0x0120, 0x6003, 0x0002, 0x00de, 0x0005,
+	0x2009, 0xad0d, 0x210c, 0xd19c, 0x0118, 0x6003, 0x0007, 0x0010,
+	0x6003, 0x0006, 0x0021, 0x080c, 0x661a, 0x00de, 0x0005, 0xd2fc,
+	0x0140, 0x8002, 0x8000, 0x8212, 0xa291, 0x0000, 0x2009, 0x0009,
+	0x0010, 0x2009, 0x0015, 0x6a6a, 0x6866, 0x0005, 0xa182, 0x0040,
+	0x0208, 0x0062, 0xa186, 0x0013, 0x0120, 0xa186, 0x0014, 0x190c,
+	0x14f6, 0x6020, 0xd0dc, 0x090c, 0x14f6, 0x0005, 0xa401, 0xa408,
+	0xa414, 0xa420, 0xa401, 0xa401, 0xa401, 0xa42f, 0xa401, 0xa403,
+	0xa403, 0xa401, 0xa401, 0xa401, 0xa401, 0xa403, 0xa401, 0xa403,
+	0xa401, 0x080c, 0x14f6, 0x6020, 0xd0dc, 0x090c, 0x14f6, 0x0005,
+	0x6003, 0x0001, 0x6106, 0x080c, 0x67a8, 0x0126, 0x2091, 0x8000,
+	0x080c, 0x6c50, 0x012e, 0x0005, 0x6003, 0x0001, 0x6106, 0x080c,
+	0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e, 0x0005,
+	0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1e6e, 0x0126, 0x2091,
+	0x8000, 0x080c, 0x680b, 0x080c, 0x6d0d, 0x012e, 0x0005, 0xa016,
+	0x080c, 0x1824, 0x0005, 0x0126, 0x2091, 0x8000, 0x0036, 0x00d6,
+	0xa182, 0x0040, 0x0023, 0x00de, 0x003e, 0x012e, 0x0005, 0xa44f,
+	0xa451, 0xa463, 0xa47e, 0xa44f, 0xa44f, 0xa44f, 0xa493, 0xa44f,
+	0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0xa44f, 0x080c,
+	0x14f6, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x01f8, 0xa09c, 0x0003,
+	0xa39e, 0x0003, 0x01d0, 0x6003, 0x0001, 0x6106, 0x080c, 0x67a8,
+	0x080c, 0x6c50, 0x0498, 0x6010, 0x2068, 0x684c, 0xd0fc, 0x0168,
+	0xa09c, 0x0003, 0xa39e, 0x0003, 0x0140, 0x6003, 0x0001, 0x6106,
+	0x080c, 0x67a8, 0x080c, 0x6c50, 0x0408, 0x6013, 0x0000, 0x6017,
+	0x0000, 0x2019, 0x0004, 0x080c, 0xa91f, 0x00c0, 0x6010, 0x2068,
+	0x684c, 0xd0fc, 0x0d90, 0xa09c, 0x0003, 0xa39e, 0x0003, 0x0d68,
+	0x6003, 0x0003, 0x6106, 0x2c10, 0x080c, 0x1e6e, 0x080c, 0x680b,
+	0x080c, 0x6d0d, 0x0018, 0xa016, 0x080c, 0x1824, 0x0005, 0x080c,
+	0x6b73, 0x6110, 0x81ff, 0x0158, 0x00d6, 0x2168, 0x080c, 0xabfa,
+	0x0036, 0x2019, 0x0029, 0x080c, 0xa91f, 0x003e, 0x00de, 0x080c,
+	0x974e, 0x080c, 0x6c50, 0x0005, 0x080c, 0x6c05, 0x6110, 0x81ff,
+	0x0158, 0x00d6, 0x2168, 0x080c, 0xabfa, 0x0036, 0x2019, 0x0029,
+	0x080c, 0xa91f, 0x003e, 0x00de, 0x080c, 0x974e, 0x080c, 0x6d0d,
+	0x0005, 0xa182, 0x0085, 0x0002, 0xa4cd, 0xa4cb, 0xa4cb, 0xa4d9,
+	0xa4cb, 0xa4cb, 0xa4cb, 0x080c, 0x14f6, 0x6003, 0x000b, 0x6106,
+	0x080c, 0x67a8, 0x0126, 0x2091, 0x8000, 0x080c, 0x6c50, 0x012e,
+	0x0005, 0x0026, 0x00e6, 0x080c, 0xab4e, 0x0118, 0x080c, 0x8078,
+	0x00c8, 0x2071, 0xb280, 0x7224, 0x6212, 0x7220, 0x080c, 0xa7ce,
+	0x0118, 0x6007, 0x0086, 0x0040, 0x6007, 0x0087, 0x7224, 0xa296,
+	0xffff, 0x1110, 0x6007, 0x0086, 0x6003, 0x0001, 0x080c, 0x67a8,
+	0x080c, 0x6c50, 0x00ee, 0x002e, 0x0005, 0xa186, 0x0013, 0x1160,
+	0x6004, 0xa08a, 0x0085, 0x0a0c, 0x14f6, 0xa08a, 0x008c, 0x1a0c,
+	0x14f6, 0xa082, 0x0085, 0x00a2, 0xa186, 0x0027, 0x0130, 0xa186,
+	0x0014, 0x0118, 0x080c, 0x80be, 0x0050, 0x2001, 0x0007, 0x080c,
+	0x4c5d, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005,
+	0xa527, 0xa529, 0xa529, 0xa527, 0xa527, 0xa527, 0xa527, 0x080c,
+	0x14f6, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005,
+	0xa182, 0x0085, 0x0a0c, 0x14f6, 0xa182, 0x008c, 0x1a0c, 0x14f6,
+	0xa182, 0x0085, 0x0002, 0xa542, 0xa542, 0xa542, 0xa544, 0xa542,
+	0xa542, 0xa542, 0x080c, 0x14f6, 0x0005, 0xa186, 0x0013, 0x0148,
+	0xa186, 0x0014, 0x0130, 0xa186, 0x0027, 0x0118, 0x080c, 0x80be,
+	0x0030, 0x080c, 0x6b73, 0x080c, 0x974e, 0x080c, 0x6c50, 0x0005,
+	0x0036, 0x080c, 0xabb4, 0x603f, 0x0000, 0x2019, 0x000b, 0x0031,
+	0x601f, 0x0006, 0x6003, 0x0007, 0x003e, 0x0005, 0x0126, 0x0036,
+	0x2091, 0x8000, 0x0086, 0x2c40, 0x0096, 0x2049, 0x0000, 0x080c,
+	0x7b9a, 0x009e, 0x008e, 0x1578, 0x0076, 0x2c38, 0x080c, 0x7c34,
+	0x007e, 0x1548, 0x6000, 0xa086, 0x0000, 0x0528, 0x601c, 0xa086,
+	0x0007, 0x0508, 0x00d6, 0x6000, 0xa086, 0x0004, 0x1150, 0x080c,
+	0xabb4, 0x601f, 0x0007, 0x2001, 0xafa3, 0x2004, 0x6016, 0x080c,
+	0x190b, 0x6010, 0x2068, 0x080c, 0x9596, 0x0110, 0x080c, 0xa91f,
+	0x00de, 0x6013, 0x0000, 0x080c, 0xabb4, 0x601f, 0x0007, 0x2001,
+	0xafa3, 0x2004, 0x6016, 0x003e, 0x012e, 0x0005, 0x00f6, 0x00c6,
+	0x0036, 0x0156, 0x2079, 0xb280, 0x7938, 0x783c, 0x080c, 0x2676,
+	0x1904, 0xa5f1, 0x0016, 0x00c6, 0x080c, 0x4cdc, 0x15c0, 0x2011,
+	0xb290, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1578,
+	0x001e, 0x002e, 0x0026, 0x0016, 0x2019, 0x0029, 0x080c, 0x7cf4,
+	0x080c, 0x68e7, 0x0076, 0x2039, 0x0000, 0x080c, 0x681d, 0x007e,
+	0x001e, 0x0076, 0x2039, 0x0000, 0x080c, 0xa712, 0x007e, 0x080c,
+	0x4ecf, 0x0026, 0x6204, 0xa294, 0xff00, 0x8217, 0xa286, 0x0006,
+	0x0118, 0xa286, 0x0004, 0x1118, 0x62a0, 0x080c, 0x2b87, 0x002e,
+	0x001e, 0x080c, 0x493a, 0x6612, 0x6516, 0xa006, 0x0010, 0x00ce,
+	0x001e, 0x015e, 0x003e, 0x00ce, 0x00fe, 0x0005, 0x00c6, 0x00d6,
+	0x00e6, 0x0016, 0x2009, 0xad20, 0x2104, 0xa086, 0x0074, 0x1904,
+	0xa64b, 0x2069, 0xb28e, 0x690c, 0xa182, 0x0100, 0x06c0, 0x6908,
+	0xa184, 0x8000, 0x05e8, 0x2001, 0xaf9d, 0x2004, 0xa005, 0x1160,
+	0x6018, 0x2070, 0x7010, 0xa084, 0x00ff, 0x0118, 0x7000, 0xd0f4,
+	0x0118, 0xa184, 0x0800, 0x0560, 0x6910, 0xa18a, 0x0001, 0x0610,
+	0x6914, 0x2069, 0xb2ae, 0x6904, 0x81ff, 0x1198, 0x690c, 0xa182,
+	0x0100, 0x02a8, 0x6908, 0x81ff, 0x1178, 0x6910, 0xa18a, 0x0001,
+	0x0288, 0x6918, 0xa18a, 0x0001, 0x0298, 0x00d0, 0x6013, 0x0100,
+	0x00a0, 0x6013, 0x0300, 0x0088, 0x6013, 0x0500, 0x0070, 0x6013,
+	0x0700, 0x0058, 0x6013, 0x0900, 0x0040, 0x6013, 0x0b00, 0x0028,
+	0x6013, 0x0f00, 0x0010, 0x6013, 0x2d00, 0xa085, 0x0001, 0x0008,
+	0xa006, 0x001e, 0x00ee, 0x00de, 0x00ce, 0x0005, 0x00c6, 0x00d6,
+	0x0026, 0x0036, 0x0156, 0x6218, 0x2268, 0x6b04, 0xa394, 0x00ff,
+	0xa286, 0x0006, 0x0190, 0xa286, 0x0004, 0x0178, 0xa394, 0xff00,
+	0x8217, 0xa286, 0x0006, 0x0148, 0xa286, 0x0004, 0x0130, 0x00c6,
+	0x2d60, 0x080c, 0x4ceb, 0x00ce, 0x04c0, 0x2011, 0xb296, 0xad98,
+	0x000a, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1580, 0x2011, 0xb29a,
+	0xad98, 0x0006, 0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1538, 0x0046,
+	0x0016, 0x6aa0, 0xa294, 0x00ff, 0x8227, 0xa006, 0x2009, 0xad52,
+	0x210c, 0xd1a4, 0x0138, 0x2009, 0x0029, 0x080c, 0xa96c, 0x6800,
+	0xc0e5, 0x6802, 0x2019, 0x0029, 0x080c, 0x68e7, 0x0076, 0x2039,
+	0x0000, 0x080c, 0x681d, 0x2c08, 0x080c, 0xa712, 0x007e, 0x2001,
+	0x0007, 0x080c, 0x4c5d, 0x001e, 0x004e, 0xa006, 0x015e, 0x003e,
+	0x002e, 0x00de, 0x00ce, 0x0005, 0x00d6, 0x2069, 0xb28e, 0x6800,
+	0xa086, 0x0800, 0x0118, 0x6013, 0x0000, 0x0008, 0xa006, 0x00de,
+	0x0005, 0x00c6, 0x00f6, 0x0016, 0x0026, 0x0036, 0x0156, 0x2079,
+	0xb28c, 0x7930, 0x7834, 0x080c, 0x2676, 0x11a0, 0x080c, 0x4cdc,
+	0x1188, 0x2011, 0xb290, 0xac98, 0x000a, 0x20a9, 0x0004, 0x080c,
+	0x8a7c, 0x1140, 0x2011, 0xb294, 0xac98, 0x0006, 0x20a9, 0x0004,
+	0x080c, 0x8a7c, 0x015e, 0x003e, 0x002e, 0x001e, 0x00fe, 0x00ce,
+	0x0005, 0x00c6, 0x0006, 0x0016, 0x0026, 0x0036, 0x0156, 0x2011,
+	0xb283, 0x2204, 0x8211, 0x220c, 0x080c, 0x2676, 0x11a0, 0x080c,
+	0x4cdc, 0x1188, 0x2011, 0xb296, 0xac98, 0x000a, 0x20a9, 0x0004,
+	0x080c, 0x8a7c, 0x1140, 0x2011, 0xb29a, 0xac98, 0x0006, 0x20a9,
+	0x0004, 0x080c, 0x8a7c, 0x015e, 0x003e, 0x002e, 0x001e, 0x000e,
+	0x00ce, 0x0005, 0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0056,
+	0x0046, 0x0026, 0x0126, 0x2091, 0x8000, 0x2740, 0x2029, 0xafd0,
+	0x252c, 0x2021, 0xafd6, 0x2424, 0x2061, 0xb400, 0x2071, 0xad00,
+	0x7644, 0x7064, 0x81ff, 0x0128, 0x8001, 0xa602, 0x1a04, 0xa78e,
+	0x0018, 0xa606, 0x0904, 0xa78e, 0x2100, 0xac06, 0x0904, 0xa785,
+	0x080c, 0xa990, 0x0904, 0xa785, 0x671c, 0xa786, 0x0001, 0x0904,
+	0xa7a5, 0xa786, 0x0004, 0x0904, 0xa7a5, 0xa786, 0x0007, 0x05e8,
+	0x2500, 0xac06, 0x05d0, 0x2400, 0xac06, 0x05b8, 0x080c, 0xa9a0,
+	0x15a0, 0x88ff, 0x0118, 0x6050, 0xa906, 0x1578, 0x00d6, 0x6000,
+	0xa086, 0x0004, 0x1120, 0x0016, 0x080c, 0x190b, 0x001e, 0xa786,
+	0x0008, 0x1148, 0x080c, 0x9789, 0x1130, 0x080c, 0x85f3, 0x00de,
+	0x080c, 0x974e, 0x00d0, 0x6010, 0x2068, 0x080c, 0x9596, 0x0190,
+	0xa786, 0x0003, 0x1528, 0x6837, 0x0103, 0x6b4a, 0x6847, 0x0000,
+	0x080c, 0xabfa, 0x0016, 0x080c, 0x97fd, 0x080c, 0x510c, 0x001e,
+	0x080c, 0x9742, 0x00de, 0x080c, 0x974e, 0xace0, 0x0018, 0x2001,
+	0xad16, 0x2004, 0xac02, 0x1210, 0x0804, 0xa726, 0x012e, 0x002e,
+	0x004e, 0x005e, 0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x0005,
+	0xa786, 0x0006, 0x19c0, 0xa386, 0x0005, 0x0128, 0x080c, 0xabfa,
+	0x080c, 0xa91f, 0x08f8, 0x00de, 0x0c00, 0x080c, 0xa9a0, 0x19e8,
+	0x81ff, 0x09d8, 0xa180, 0x0001, 0x2004, 0xa086, 0x0018, 0x0130,
+	0xa180, 0x0001, 0x2004, 0xa086, 0x002d, 0x1978, 0x6000, 0xa086,
+	0x0002, 0x1958, 0x080c, 0x9778, 0x0130, 0x080c, 0x9789, 0x1928,
+	0x080c, 0x85f3, 0x0038, 0x080c, 0x2aff, 0x080c, 0x9789, 0x1110,
+	0x080c, 0x85f3, 0x080c, 0x974e, 0x0804, 0xa785, 0x00c6, 0x00e6,
+	0x0016, 0x2c08, 0x2170, 0x080c, 0xa940, 0x001e, 0x0120, 0x601c,
+	0xa084, 0x000f, 0x001b, 0x00ee, 0x00ce, 0x0005, 0xa7e6, 0xa7e6,
+	0xa7e6, 0xa7e6, 0xa7e6, 0xa7e6, 0xa7e8, 0xa7e6, 0xa006, 0x0005,
+	0x0046, 0x0016, 0x7018, 0xa080, 0x0028, 0x2024, 0xa4a4, 0x00ff,
+	0x8427, 0x2c00, 0x2009, 0x0020, 0x080c, 0xa96c, 0x001e, 0x004e,
+	0x0036, 0x2019, 0x0002, 0x080c, 0xa566, 0x003e, 0xa085, 0x0001,
+	0x0005, 0x2001, 0x0001, 0x080c, 0x4c1e, 0x0156, 0x0016, 0x0026,
+	0x0036, 0x20a9, 0x0004, 0x2019, 0xad05, 0x2011, 0xb296, 0x080c,
+	0x8a7c, 0x003e, 0x002e, 0x001e, 0x015e, 0xa005, 0x0005, 0x00f6,
+	0x00e6, 0x00c6, 0x0086, 0x0076, 0x0066, 0x0026, 0x0126, 0x2091,
+	0x8000, 0x2740, 0x2061, 0xb400, 0x2079, 0x0001, 0x8fff, 0x0904,
+	0xa875, 0x2071, 0xad00, 0x7644, 0x7064, 0x8001, 0xa602, 0x1a04,
+	0xa875, 0x88ff, 0x0128, 0x2800, 0xac06, 0x15b0, 0x2079, 0x0000,
+	0x080c, 0xa990, 0x0588, 0x2400, 0xac06, 0x0570, 0x671c, 0xa786,
+	0x0006, 0x1550, 0xa786, 0x0007, 0x0538, 0x88ff, 0x1140, 0x6018,
+	0xa206, 0x1510, 0x85ff, 0x0118, 0x6050, 0xa106, 0x11e8, 0x00d6,
+	0x6000, 0xa086, 0x0004, 0x1150, 0x080c, 0xabb4, 0x601f, 0x0007,
+	0x2001, 0xafa3, 0x2004, 0x6016, 0x080c, 0x190b, 0x6010, 0x2068,
+	0x080c, 0x9596, 0x0120, 0x0046, 0x080c, 0xa91f, 0x004e, 0x00de,
+	0x080c, 0x974e, 0x88ff, 0x1198, 0xace0, 0x0018, 0x2001, 0xad16,
+	0x2004, 0xac02, 0x1210, 0x0804, 0xa826, 0xa006, 0x012e, 0x002e,
+	0x006e, 0x007e, 0x008e, 0x00ce, 0x00ee, 0x00fe, 0x0005, 0xa8c5,
+	0x0001, 0x0ca0, 0x0076, 0x0056, 0x0086, 0x2041, 0x0000, 0x2029,
+	0x0001, 0x2c20, 0x2019, 0x0002, 0x6218, 0x0096, 0x2049, 0x0000,
+	0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c, 0x7c34,
+	0x080c, 0xa817, 0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056,
+	0x0076, 0x00c6, 0x0156, 0x2c20, 0x2128, 0x20a9, 0x007f, 0x2009,
+	0x0000, 0x0016, 0x0036, 0x080c, 0x4cdc, 0x11b0, 0x2c10, 0x0056,
+	0x0086, 0x2041, 0x0000, 0x2508, 0x2029, 0x0001, 0x0096, 0x2049,
+	0x0000, 0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c,
+	0x7c34, 0x080c, 0xa817, 0x005e, 0x003e, 0x001e, 0x8108, 0x1f04,
+	0xa8a9, 0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005,
+	0x0076, 0x0056, 0x6218, 0x0086, 0x2041, 0x0000, 0x2029, 0x0001,
+	0x2019, 0x0048, 0x0096, 0x2049, 0x0000, 0x080c, 0x7b9a, 0x009e,
+	0x008e, 0x2039, 0x0000, 0x080c, 0x7c34, 0x2c20, 0x080c, 0xa817,
+	0x005e, 0x007e, 0x0005, 0x0026, 0x0046, 0x0056, 0x0076, 0x00c6,
+	0x0156, 0x2c20, 0x20a9, 0x007f, 0x2009, 0x0000, 0x0016, 0x0036,
+	0x080c, 0x4cdc, 0x11c0, 0x2c10, 0x0086, 0x2041, 0x0000, 0x2828,
+	0x0046, 0x2021, 0x0001, 0x080c, 0xab96, 0x004e, 0x0096, 0x2049,
+	0x0000, 0x080c, 0x7b9a, 0x009e, 0x008e, 0x2039, 0x0000, 0x080c,
+	0x7c34, 0x080c, 0xa817, 0x003e, 0x001e, 0x8108, 0x1f04, 0xa8f6,
+	0x015e, 0x00ce, 0x007e, 0x005e, 0x004e, 0x002e, 0x0005, 0x0016,
+	0x00f6, 0x3800, 0xd08c, 0x0130, 0xad82, 0x1000, 0x02b0, 0xad82,
+	0xad00, 0x0230, 0xad82, 0xe400, 0x0280, 0xad82, 0xffff, 0x1268,
+	0x6800, 0xa07d, 0x0138, 0x6803, 0x0000, 0x6b52, 0x080c, 0x510c,
+	0x2f68, 0x0cb0, 0x6b52, 0x080c, 0x510c, 0x00fe, 0x001e, 0x0005,
+	0x00e6, 0x0046, 0x0036, 0x2061, 0xb400, 0x2071, 0xad00, 0x7444,
+	0x7064, 0x8001, 0xa402, 0x12d8, 0x2100, 0xac06, 0x0168, 0x6000,
+	0xa086, 0x0000, 0x0148, 0x6008, 0xa206, 0x1130, 0x6018, 0xa1a0,
+	0x0006, 0x2424, 0xa406, 0x0140, 0xace0, 0x0018, 0x2001, 0xad16,
+	0x2004, 0xac02, 0x1220, 0x0c08, 0xa085, 0x0001, 0x0008, 0xa006,
+	0x003e, 0x004e, 0x00ee, 0x0005, 0x00d6, 0x0006, 0x080c, 0x15d9,
+	0x000e, 0x090c, 0x14f6, 0x6837, 0x010d, 0x685e, 0x0026, 0x2010,
+	0x080c, 0x9586, 0x2001, 0x0000, 0x0120, 0x2200, 0xa080, 0x0014,
+	0x2004, 0x002e, 0x684a, 0x6956, 0x6c46, 0x684f, 0x0000, 0xa006,
+	0x68b2, 0x6802, 0x683a, 0x685a, 0x080c, 0x510c, 0x00de, 0x0005,
+	0x6700, 0xa786, 0x0000, 0x0158, 0xa786, 0x0001, 0x0140, 0xa786,
+	0x000a, 0x0128, 0xa786, 0x0009, 0x0110, 0xa085, 0x0001, 0x0005,
+	0x00e6, 0x6018, 0x2070, 0x70a0, 0xa206, 0x00ee, 0x0005, 0x0016,
+	0x6004, 0xa08e, 0x001e, 0x11a0, 0x8007, 0x6130, 0xa18c, 0x00ff,
+	0xa105, 0x6032, 0x6007, 0x0085, 0x6003, 0x000b, 0x601f, 0x0005,
+	0x2001, 0xafa4, 0x2004, 0x6016, 0x080c, 0x67a8, 0x080c, 0x6c50,
+	0x001e, 0x0005, 0xe000, 0xe000, 0x0005, 0x6020, 0xd0e4, 0x0158,
+	0xd0cc, 0x0118, 0x080c, 0x9866, 0x0030, 0x080c, 0xabb4, 0x080c,
+	0x6618, 0x080c, 0x8078, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084,
+	0x000f, 0x0002, 0xa9e3, 0xa9e3, 0xa9e3, 0xa9e8, 0xa9e3, 0xa9e5,
+	0xa9e5, 0xa9e3, 0xa9e5, 0xa006, 0x0005, 0x00c6, 0x2260, 0x00ce,
+	0xa085, 0x0001, 0x0005, 0xa280, 0x0007, 0x2004, 0xa084, 0x000f,
+	0x0002, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xa9fa, 0xaa05,
+	0xa9fa, 0xa9fa, 0x6007, 0x003b, 0x602b, 0x0009, 0x6013, 0x2a00,
+	0x6003, 0x0001, 0x080c, 0x67a8, 0x0005, 0x00c6, 0x2260, 0x080c,
+	0xabb4, 0x603f, 0x0000, 0x6020, 0xc0f4, 0xc0cc, 0x6022, 0x6037,
+	0x0000, 0x00ce, 0x00d6, 0x2268, 0xa186, 0x0007, 0x1904, 0xaa60,
+	0x6810, 0xa005, 0x0138, 0xa080, 0x0013, 0x2004, 0xd0fc, 0x1110,
+	0x00de, 0x08c0, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c, 0x67a8,
+	0x080c, 0x6c50, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002, 0x1904,
+	0xaae7, 0x6010, 0xa005, 0x1138, 0x6000, 0xa086, 0x0007, 0x190c,
+	0x14f6, 0x0804, 0xaae7, 0xa08c, 0xf000, 0x1130, 0x0028, 0x2068,
+	0x6800, 0xa005, 0x1de0, 0x2d00, 0xa080, 0x0013, 0x2004, 0xa084,
+	0x0003, 0xa086, 0x0002, 0x1180, 0x6010, 0x2068, 0x684c, 0xc0dc,
+	0xc0f4, 0x684e, 0x6850, 0xc0f4, 0xc0fc, 0x6852, 0x2009, 0x0043,
+	0x080c, 0xa3de, 0x0804, 0xaae7, 0x2009, 0x0041, 0x0804, 0xaae1,
+	0xa186, 0x0005, 0x15f0, 0x6810, 0xa080, 0x0013, 0x2004, 0xd0bc,
+	0x1118, 0x00de, 0x0804, 0xa9fa, 0xd0b4, 0x0128, 0xd0fc, 0x090c,
+	0x14f6, 0x0804, 0xaa18, 0x6007, 0x003a, 0x6003, 0x0001, 0x080c,
+	0x67a8, 0x080c, 0x6c50, 0x00c6, 0x2d60, 0x6100, 0xa186, 0x0002,
+	0x0120, 0xa186, 0x0004, 0x1904, 0xaae7, 0x2071, 0xaffd, 0x7000,
+	0xa086, 0x0003, 0x1128, 0x7004, 0xac06, 0x1110, 0x7003, 0x0000,
+	0x6810, 0xa080, 0x0013, 0x200c, 0xc1f4, 0xc1dc, 0x2102, 0x8000,
+	0x200c, 0xc1f4, 0xc1fc, 0xc1bc, 0x2102, 0x2009, 0x0042, 0x0804,
+	0xaae1, 0x0036, 0x00d6, 0x00d6, 0x080c, 0x15d9, 0x003e, 0x090c,
+	0x14f6, 0x6837, 0x010d, 0x6803, 0x0000, 0x683b, 0x0000, 0x685b,
+	0x0000, 0x6b5e, 0x6857, 0x0045, 0x2c00, 0x6862, 0x6034, 0x6872,
+	0x2360, 0x6020, 0xc0dd, 0x6022, 0x6018, 0xa080, 0x0028, 0x2004,
+	0xa084, 0x00ff, 0x8007, 0x6350, 0x6b4a, 0x6846, 0x684f, 0x0000,
+	0x6d6a, 0x6e66, 0x686f, 0x0001, 0x080c, 0x510c, 0x2019, 0x0045,
+	0x6008, 0x2068, 0x080c, 0xa566, 0x2d00, 0x600a, 0x601f, 0x0006,
+	0x6003, 0x0007, 0x6017, 0x0000, 0x603f, 0x0000, 0x00de, 0x003e,
+	0x0038, 0x603f, 0x0000, 0x6003, 0x0007, 0x080c, 0xa3de, 0x00ce,
+	0x00de, 0x0005, 0xa186, 0x0013, 0x1128, 0x6004, 0xa082, 0x0085,
+	0x2008, 0x00c2, 0xa186, 0x0027, 0x1178, 0x080c, 0x6b73, 0x0036,
+	0x00d6, 0x6010, 0x2068, 0x2019, 0x0004, 0x080c, 0xa91f, 0x00de,
+	0x003e, 0x080c, 0x6c50, 0x0005, 0xa186, 0x0014, 0x0d70, 0x080c,
+	0x80be, 0x0005, 0xab13, 0xab11, 0xab11, 0xab11, 0xab11, 0xab11,
+	0xab13, 0x080c, 0x14f6, 0x080c, 0x6b73, 0x6003, 0x000c, 0x080c,
+	0x6c50, 0x0005, 0xa182, 0x008c, 0x1220, 0xa182, 0x0085, 0x0208,
+	0x001a, 0x080c, 0x80be, 0x0005, 0xab2b, 0xab2b, 0xab2b, 0xab2b,
+	0xab2d, 0xab4b, 0xab2b, 0x080c, 0x14f6, 0x00d6, 0x2c68, 0x080c,
+	0x8022, 0x01a0, 0x6003, 0x0001, 0x6007, 0x001e, 0x2009, 0xb28e,
+	0x210c, 0x6136, 0x2009, 0xb28f, 0x210c, 0x613a, 0x600b, 0xffff,
+	0x6918, 0x611a, 0x601f, 0x0004, 0x080c, 0x67a8, 0x2d60, 0x080c,
+	0x8078, 0x00de, 0x0005, 0x080c, 0x8078, 0x0005, 0x00e6, 0x6018,
+	0x2070, 0x7000, 0xd0ec, 0x00ee, 0x0005, 0x6010, 0xa080, 0x0013,
+	0x200c, 0xd1ec, 0x05d0, 0x2001, 0xad71, 0x2004, 0xd0ec, 0x05a8,
+	0x6003, 0x0002, 0x6020, 0xc0e5, 0x6022, 0xd1ac, 0x0180, 0x00f6,
+	0x2c78, 0x080c, 0x5025, 0x00fe, 0x0150, 0x2001, 0xafa5, 0x2004,
+	0x603e, 0x2009, 0xad71, 0x210c, 0xd1f4, 0x11e8, 0x0080, 0x2009,
+	0xad71, 0x210c, 0xd1f4, 0x0128, 0x6020, 0xc0e4, 0x6022, 0xa006,
+	0x00a0, 0x2001, 0xafa5, 0x200c, 0x8103, 0xa100, 0x603e, 0x6018,
+	0xa088, 0x002b, 0x2104, 0xa005, 0x0118, 0xa088, 0x0003, 0x0cd0,
+	0x2c0a, 0x600f, 0x0000, 0xa085, 0x0001, 0x0005, 0x0016, 0x00c6,
+	0x00e6, 0x6150, 0xa2f0, 0x002b, 0x2e04, 0x2060, 0x8cff, 0x0180,
+	0x84ff, 0x1118, 0x6050, 0xa106, 0x1138, 0x600c, 0x2072, 0x080c,
+	0x6618, 0x080c, 0x8078, 0x0010, 0xacf0, 0x0003, 0x2e64, 0x0c70,
+	0x00ee, 0x00ce, 0x001e, 0x0005, 0x00d6, 0x6018, 0xa0e8, 0x002b,
+	0x2d04, 0xa005, 0x0140, 0xac06, 0x0120, 0x2d04, 0xa0e8, 0x0003,
+	0x0cb8, 0x600c, 0x206a, 0x00de, 0x0005, 0x0026, 0x0036, 0x0156,
+	0x2011, 0xad27, 0x2204, 0xa084, 0x00ff, 0x2019, 0xb28e, 0x2334,
+	0xa636, 0x11d8, 0x8318, 0x2334, 0x2204, 0xa084, 0xff00, 0xa636,
+	0x11a0, 0x2011, 0xb290, 0x6018, 0xa098, 0x000a, 0x20a9, 0x0004,
+	0x080c, 0x8a7c, 0x1150, 0x2011, 0xb294, 0x6018, 0xa098, 0x0006,
+	0x20a9, 0x0004, 0x080c, 0x8a7c, 0x1100, 0x015e, 0x003e, 0x002e,
+	0x0005, 0x00e6, 0x2071, 0xad00, 0x080c, 0x48f5, 0x080c, 0x28fa,
+	0x00ee, 0x0005, 0x00e6, 0x6018, 0x2070, 0x7000, 0xd0fc, 0x0108,
+	0x0011, 0x00ee, 0x0005, 0x6850, 0xc0e5, 0x6852, 0x0005, 0x00e6,
+	0x00c6, 0x0076, 0x0066, 0x0056, 0x0046, 0x0026, 0x0016, 0x0126,
+	0x2091, 0x8000, 0x2029, 0xafd0, 0x252c, 0x2021, 0xafd6, 0x2424,
+	0x2061, 0xb400, 0x2071, 0xad00, 0x7644, 0x7064, 0xa606, 0x0578,
+	0x671c, 0xa786, 0x0001, 0x0118, 0xa786, 0x0008, 0x1500, 0x2500,
+	0xac06, 0x01e8, 0x2400, 0xac06, 0x01d0, 0x080c, 0xa990, 0x01b8,
+	0x080c, 0xa9a0, 0x11a0, 0x6000, 0xa086, 0x0004, 0x1120, 0x0016,
+	0x080c, 0x190b, 0x001e, 0x080c, 0x9778, 0x1110, 0x080c, 0x2aff,
+	0x080c, 0x9789, 0x1110, 0x080c, 0x85f3, 0x080c, 0x974e, 0xace0,
+	0x0018, 0x2001, 0xad16, 0x2004, 0xac02, 0x1208, 0x0858, 0x012e,
+	0x001e, 0x002e, 0x004e, 0x005e, 0x006e, 0x007e, 0x00ce, 0x00ee,
+	0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000, 0x2071, 0xad40,
+	0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4, 0x0118, 0x7030,
+	0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0xad4a, 0x0451, 0x00ee,
+	0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6, 0x2091, 0x8000,
+	0x2071, 0xad40, 0xd5a4, 0x0118, 0x7034, 0x8000, 0x7036, 0xd5b4,
+	0x0118, 0x7030, 0x8000, 0x7032, 0xd5ac, 0x0118, 0x2071, 0xad4a,
+	0x0081, 0x00ee, 0x000e, 0x012e, 0x0005, 0x0126, 0x0006, 0x00e6,
+	0x2091, 0x8000, 0x2071, 0xad42, 0x0021, 0x00ee, 0x000e, 0x012e,
+	0x0005, 0x2e04, 0x8000, 0x2072, 0x1220, 0x8e70, 0x2e04, 0x8000,
+	0x2072, 0x0005, 0x00e6, 0x2071, 0xad40, 0x0c99, 0x00ee, 0x0005,
+	0x00e6, 0x2071, 0xad44, 0x0c69, 0x00ee, 0x0005, 0x0001, 0x0002,
+	0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, 0x0100, 0x0200,
+	0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000, 0x8529
+};
+
diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
new file mode 100644
index 0000000..71d597a
--- /dev/null
+++ b/drivers/scsi/qlogicisp.c
@@ -0,0 +1,1935 @@
+/*
+ * QLogic ISP1020 Intelligent SCSI Processor Driver (PCI)
+ * Written by Erik H. Moe, ehm@cris.com
+ * Copyright 1995, Erik H. Moe
+ * Copyright 1996, 1997  Michael A. Griffith <grif@acm.org>
+ * Copyright 2000, Jayson C. Vantuyl <vantuyl@csc.smsu.edu>
+ *             and Bryon W. Roche    <bryon@csc.smsu.edu>
+ *
+ * 64-bit addressing added by Kanoj Sarcar <kanoj@sgi.com>
+ * 			   and Leo Dagum    <dagum@sgi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/blkdev.h>
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/byteorder.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+
+/*
+ * With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 4 scatter/gather entries.  If we need more
+ * than 4 entries, continuation entries can be used that hold
+ * another 7 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+#define QLOGICISP_REQ_QUEUE_LEN	63	/* must be power of two - 1 */
+#define QLOGICISP_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
+
+/* Configuration section *****************************************************/
+
+/* Set the following macro to 1 to reload the ISP1020's firmware.  This is
+   the latest firmware provided by QLogic.  This may be an earlier/later
+   revision than supplied by your board. */
+
+#define RELOAD_FIRMWARE		1
+
+/* Set the following macro to 1 to reload the ISP1020's defaults from nvram.
+   If you are not sure of your settings, leave this alone, the driver will
+   use a set of 'safe' defaults */
+
+#define USE_NVRAM_DEFAULTS	0
+
+/*  Macros used for debugging */
+
+#define DEBUG_ISP1020		0
+#define DEBUG_ISP1020_INTR	0
+#define DEBUG_ISP1020_SETUP	0
+#define TRACE_ISP		0
+
+#define DEFAULT_LOOP_COUNT	1000000
+
+/* End Configuration section *************************************************/
+
+#include <linux/module.h>
+
+#if TRACE_ISP
+
+# define TRACE_BUF_LEN	(32*1024)
+
+struct {
+	u_long		next;
+	struct {
+		u_long		time;
+		u_int		index;
+		u_int		addr;
+		u_char *	name;
+	} buf[TRACE_BUF_LEN];
+} trace;
+
+#define TRACE(w, i, a)						\
+{								\
+	unsigned long flags;					\
+								\
+	trace.buf[trace.next].name  = (w);			\
+	trace.buf[trace.next].time  = jiffies;			\
+	trace.buf[trace.next].index = (i);			\
+	trace.buf[trace.next].addr  = (long) (a);		\
+	trace.next = (trace.next + 1) & (TRACE_BUF_LEN - 1);	\
+}
+
+#else
+# define TRACE(w, i, a)
+#endif
+
+#if DEBUG_ISP1020
+#define ENTER(x)	printk("isp1020 : entering %s()\n", x);
+#define LEAVE(x)	printk("isp1020 : leaving %s()\n", x);
+#define DEBUG(x)	x
+#else
+#define ENTER(x)
+#define LEAVE(x)
+#define DEBUG(x)
+#endif /* DEBUG_ISP1020 */
+
+#if DEBUG_ISP1020_INTR
+#define ENTER_INTR(x)	printk("isp1020 : entering %s()\n", x);
+#define LEAVE_INTR(x)	printk("isp1020 : leaving %s()\n", x);
+#define DEBUG_INTR(x)	x
+#else
+#define ENTER_INTR(x)
+#define LEAVE_INTR(x)
+#define DEBUG_INTR(x)
+#endif /* DEBUG ISP1020_INTR */
+
+#define ISP1020_REV_ID	1
+
+#define MAX_TARGETS	16
+#define MAX_LUNS	8
+
+/* host configuration and control registers */
+#define HOST_HCCR	0xc0	/* host command and control */
+
+/* pci bus interface registers */
+#define PCI_ID_LOW	0x00	/* vendor id */
+#define PCI_ID_HIGH	0x02	/* device id */
+#define ISP_CFG0	0x04	/* configuration register #0 */
+#define  ISP_CFG0_HWMSK  0x000f	/* Hardware revision mask */
+#define  ISP_CFG0_1020	 0x0001 /* ISP1020 */
+#define  ISP_CFG0_1020A	 0x0002 /* ISP1020A */
+#define  ISP_CFG0_1040	 0x0003 /* ISP1040 */
+#define  ISP_CFG0_1040A	 0x0004 /* ISP1040A */
+#define  ISP_CFG0_1040B	 0x0005 /* ISP1040B */
+#define  ISP_CFG0_1040C	 0x0006 /* ISP1040C */
+#define ISP_CFG1	0x06	/* configuration register #1 */
+#define  ISP_CFG1_F128	 0x0040	/* 128-byte FIFO threshold */
+#define  ISP_CFG1_F64	 0x0030	/* 128-byte FIFO threshold */
+#define  ISP_CFG1_F32	 0x0020	/* 128-byte FIFO threshold */
+#define  ISP_CFG1_F16	 0x0010	/* 128-byte FIFO threshold */
+#define  ISP_CFG1_BENAB	 0x0004	/* Global Bus burst enable */
+#define  ISP_CFG1_SXP	 0x0001	/* SXP register select */
+#define PCI_INTF_CTL	0x08	/* pci interface control */
+#define PCI_INTF_STS	0x0a	/* pci interface status */
+#define PCI_SEMAPHORE	0x0c	/* pci semaphore */
+#define PCI_NVRAM	0x0e	/* pci nvram interface */
+#define CDMA_CONF	0x20	/* Command DMA Config */
+#define DDMA_CONF	0x40	/* Data DMA Config */
+#define  DMA_CONF_SENAB	 0x0008	/* SXP to DMA Data enable */
+#define  DMA_CONF_RIRQ	 0x0004	/* RISC interrupt enable */
+#define  DMA_CONF_BENAB	 0x0002	/* Bus burst enable */
+#define  DMA_CONF_DIR	 0x0001	/* DMA direction (0=fifo->host 1=host->fifo) */
+
+/* mailbox registers */
+#define MBOX0		0x70	/* mailbox 0 */
+#define MBOX1		0x72	/* mailbox 1 */
+#define MBOX2		0x74	/* mailbox 2 */
+#define MBOX3		0x76	/* mailbox 3 */
+#define MBOX4		0x78	/* mailbox 4 */
+#define MBOX5		0x7a	/* mailbox 5 */
+#define MBOX6           0x7c    /* mailbox 6 */
+#define MBOX7           0x7e    /* mailbox 7 */
+
+/* mailbox command complete status codes */
+#define MBOX_COMMAND_COMPLETE		0x4000
+#define INVALID_COMMAND			0x4001
+#define HOST_INTERFACE_ERROR		0x4002
+#define TEST_FAILED			0x4003
+#define COMMAND_ERROR			0x4005
+#define COMMAND_PARAM_ERROR		0x4006
+
+/* async event status codes */
+#define ASYNC_SCSI_BUS_RESET		0x8001
+#define SYSTEM_ERROR			0x8002
+#define REQUEST_TRANSFER_ERROR		0x8003
+#define RESPONSE_TRANSFER_ERROR		0x8004
+#define REQUEST_QUEUE_WAKEUP		0x8005
+#define EXECUTION_TIMEOUT_RESET		0x8006
+
+#ifdef CONFIG_QL_ISP_A64
+#define IOCB_SEGS                       2
+#define CONTINUATION_SEGS               5
+#define MAX_CONTINUATION_ENTRIES        254
+#else
+#define IOCB_SEGS                       4
+#define CONTINUATION_SEGS               7
+#endif /* CONFIG_QL_ISP_A64 */
+
+struct Entry_header {
+	u_char	entry_type;
+	u_char	entry_cnt;
+	u_char	sys_def_1;
+	u_char	flags;
+};
+
+/* entry header type commands */
+#ifdef CONFIG_QL_ISP_A64
+#define ENTRY_COMMAND           9
+#define ENTRY_CONTINUATION      0xa
+#else
+#define ENTRY_COMMAND		1
+#define ENTRY_CONTINUATION	2
+#endif /* CONFIG_QL_ISP_A64 */
+
+#define ENTRY_STATUS		3
+#define ENTRY_MARKER		4
+#define ENTRY_EXTENDED_COMMAND	5
+
+/* entry header flag definitions */
+#define EFLAG_CONTINUATION	1
+#define EFLAG_BUSY		2
+#define EFLAG_BAD_HEADER	4
+#define EFLAG_BAD_PAYLOAD	8
+
+struct dataseg {
+	u_int			d_base;
+#ifdef CONFIG_QL_ISP_A64
+	u_int                   d_base_hi;
+#endif
+	u_int			d_count;
+};
+
+struct Command_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_char			target_lun;
+	u_char			target_id;
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[12];
+#ifdef CONFIG_QL_ISP_A64
+	u_int                   rsvd1;
+	u_int                   rsvd2;
+#endif
+	struct dataseg		dataseg[IOCB_SEGS];
+};
+
+/* command entry control flag definitions */
+#define CFLAG_NODISC		0x01
+#define CFLAG_HEAD_TAG		0x02
+#define CFLAG_ORDERED_TAG	0x04
+#define CFLAG_SIMPLE_TAG	0x08
+#define CFLAG_TAR_RTN		0x10
+#define CFLAG_READ		0x20
+#define CFLAG_WRITE		0x40
+
+struct Ext_Command_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_char			target_lun;
+	u_char			target_id;
+	u_short			cdb_length;
+	u_short			control_flags;
+	u_short			rsvd;
+	u_short			time_out;
+	u_short			segment_cnt;
+	u_char			cdb[44];
+};
+
+struct Continuation_Entry {
+	struct Entry_header	hdr;
+#ifndef CONFIG_QL_ISP_A64
+	u_int			reserved;
+#endif
+	struct dataseg		dataseg[CONTINUATION_SEGS];
+};
+
+struct Marker_Entry {
+	struct Entry_header	hdr;
+	u_int			reserved;
+	u_char			target_lun;
+	u_char			target_id;
+	u_char			modifier;
+	u_char			rsvd;
+	u_char			rsvds[52];
+};
+
+/* marker entry modifier definitions */
+#define SYNC_DEVICE	0
+#define SYNC_TARGET	1
+#define SYNC_ALL	2
+
+struct Status_Entry {
+	struct Entry_header	hdr;
+	u_int			handle;
+	u_short			scsi_status;
+	u_short			completion_status;
+	u_short			state_flags;
+	u_short			status_flags;
+	u_short			time;
+	u_short			req_sense_len;
+	u_int			residual;
+	u_char			rsvd[8];
+	u_char			req_sense_data[32];
+};
+
+/* status entry completion status definitions */
+#define CS_COMPLETE			0x0000
+#define CS_INCOMPLETE			0x0001
+#define CS_DMA_ERROR			0x0002
+#define CS_TRANSPORT_ERROR		0x0003
+#define CS_RESET_OCCURRED		0x0004
+#define CS_ABORTED			0x0005
+#define CS_TIMEOUT			0x0006
+#define CS_DATA_OVERRUN			0x0007
+#define CS_COMMAND_OVERRUN		0x0008
+#define CS_STATUS_OVERRUN		0x0009
+#define CS_BAD_MESSAGE			0x000a
+#define CS_NO_MESSAGE_OUT		0x000b
+#define CS_EXT_ID_FAILED		0x000c
+#define CS_IDE_MSG_FAILED		0x000d
+#define CS_ABORT_MSG_FAILED		0x000e
+#define CS_REJECT_MSG_FAILED		0x000f
+#define CS_NOP_MSG_FAILED		0x0010
+#define CS_PARITY_ERROR_MSG_FAILED	0x0011
+#define CS_DEVICE_RESET_MSG_FAILED	0x0012
+#define CS_ID_MSG_FAILED		0x0013
+#define CS_UNEXP_BUS_FREE		0x0014
+#define CS_DATA_UNDERRUN		0x0015
+
+/* status entry state flag definitions */
+#define SF_GOT_BUS			0x0100
+#define SF_GOT_TARGET			0x0200
+#define SF_SENT_CDB			0x0400
+#define SF_TRANSFERRED_DATA		0x0800
+#define SF_GOT_STATUS			0x1000
+#define SF_GOT_SENSE			0x2000
+
+/* status entry status flag definitions */
+#define STF_DISCONNECT			0x0001
+#define STF_SYNCHRONOUS			0x0002
+#define STF_PARITY_ERROR		0x0004
+#define STF_BUS_RESET			0x0008
+#define STF_DEVICE_RESET		0x0010
+#define STF_ABORTED			0x0020
+#define STF_TIMEOUT			0x0040
+#define STF_NEGOTIATION			0x0080
+
+/* interface control commands */
+#define ISP_RESET			0x0001
+#define ISP_EN_INT			0x0002
+#define ISP_EN_RISC			0x0004
+
+/* host control commands */
+#define HCCR_NOP			0x0000
+#define HCCR_RESET			0x1000
+#define HCCR_PAUSE			0x2000
+#define HCCR_RELEASE			0x3000
+#define HCCR_SINGLE_STEP		0x4000
+#define HCCR_SET_HOST_INTR		0x5000
+#define HCCR_CLEAR_HOST_INTR		0x6000
+#define HCCR_CLEAR_RISC_INTR		0x7000
+#define HCCR_BP_ENABLE			0x8000
+#define HCCR_BIOS_DISABLE		0x9000
+#define HCCR_TEST_MODE			0xf000
+
+#define RISC_BUSY			0x0004
+
+/* mailbox commands */
+#define MBOX_NO_OP			0x0000
+#define MBOX_LOAD_RAM			0x0001
+#define MBOX_EXEC_FIRMWARE		0x0002
+#define MBOX_DUMP_RAM			0x0003
+#define MBOX_WRITE_RAM_WORD		0x0004
+#define MBOX_READ_RAM_WORD		0x0005
+#define MBOX_MAILBOX_REG_TEST		0x0006
+#define MBOX_VERIFY_CHECKSUM		0x0007
+#define MBOX_ABOUT_FIRMWARE		0x0008
+#define MBOX_CHECK_FIRMWARE		0x000e
+#define MBOX_INIT_REQ_QUEUE		0x0010
+#define MBOX_INIT_RES_QUEUE		0x0011
+#define MBOX_EXECUTE_IOCB		0x0012
+#define MBOX_WAKE_UP			0x0013
+#define MBOX_STOP_FIRMWARE		0x0014
+#define MBOX_ABORT			0x0015
+#define MBOX_ABORT_DEVICE		0x0016
+#define MBOX_ABORT_TARGET		0x0017
+#define MBOX_BUS_RESET			0x0018
+#define MBOX_STOP_QUEUE			0x0019
+#define MBOX_START_QUEUE		0x001a
+#define MBOX_SINGLE_STEP_QUEUE		0x001b
+#define MBOX_ABORT_QUEUE		0x001c
+#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
+#define MBOX_GET_FIRMWARE_STATUS	0x001f
+#define MBOX_GET_INIT_SCSI_ID		0x0020
+#define MBOX_GET_SELECT_TIMEOUT		0x0021
+#define MBOX_GET_RETRY_COUNT		0x0022
+#define MBOX_GET_TAG_AGE_LIMIT		0x0023
+#define MBOX_GET_CLOCK_RATE		0x0024
+#define MBOX_GET_ACT_NEG_STATE		0x0025
+#define MBOX_GET_ASYNC_DATA_SETUP_TIME	0x0026
+#define MBOX_GET_PCI_PARAMS		0x0027
+#define MBOX_GET_TARGET_PARAMS		0x0028
+#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
+#define MBOX_SET_INIT_SCSI_ID		0x0030
+#define MBOX_SET_SELECT_TIMEOUT		0x0031
+#define MBOX_SET_RETRY_COUNT		0x0032
+#define MBOX_SET_TAG_AGE_LIMIT		0x0033
+#define MBOX_SET_CLOCK_RATE		0x0034
+#define MBOX_SET_ACTIVE_NEG_STATE	0x0035
+#define MBOX_SET_ASYNC_DATA_SETUP_TIME	0x0036
+#define MBOX_SET_PCI_CONTROL_PARAMS	0x0037
+#define MBOX_SET_TARGET_PARAMS		0x0038
+#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
+#define MBOX_RETURN_BIOS_BLOCK_ADDR	0x0040
+#define MBOX_WRITE_FOUR_RAM_WORDS	0x0041
+#define MBOX_EXEC_BIOS_IOCB		0x0042
+
+#ifdef CONFIG_QL_ISP_A64
+#define MBOX_CMD_INIT_REQUEST_QUEUE_64      0x0052
+#define MBOX_CMD_INIT_RESPONSE_QUEUE_64     0x0053
+#endif /* CONFIG_QL_ISP_A64 */
+
+#include "qlogicisp_asm.c"
+
+#define PACKB(a, b)			(((a)<<4)|(b))
+
+static const u_char mbox_param[] = {
+	PACKB(1, 1),	/* MBOX_NO_OP */
+	PACKB(5, 5),	/* MBOX_LOAD_RAM */
+	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
+	PACKB(5, 5),	/* MBOX_DUMP_RAM */
+	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
+	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
+	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
+	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
+	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
+	PACKB(0, 0),	/* 0x0009 */
+	PACKB(0, 0),	/* 0x000a */
+	PACKB(0, 0),	/* 0x000b */
+	PACKB(0, 0),	/* 0x000c */
+	PACKB(0, 0),	/* 0x000d */
+	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
+	PACKB(0, 0),	/* 0x000f */
+	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
+	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
+	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
+	PACKB(2, 2),	/* MBOX_WAKE_UP	*/
+	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
+	PACKB(4, 4),	/* MBOX_ABORT */
+	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
+	PACKB(3, 3),	/* MBOX_ABORT_TARGET */
+	PACKB(2, 2),	/* MBOX_BUS_RESET */
+	PACKB(2, 3),	/* MBOX_STOP_QUEUE */
+	PACKB(2, 3),	/* MBOX_START_QUEUE */
+	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
+	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
+	PACKB(0, 0),	/* 0x001e */
+	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
+	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
+	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
+	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
+	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
+	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
+	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
+	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
+	PACKB(1, 3),	/* MBOX_GET_PCI_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x002a */
+	PACKB(0, 0),	/* 0x002b */
+	PACKB(0, 0),	/* 0x002c */
+	PACKB(0, 0),	/* 0x002d */
+	PACKB(0, 0),	/* 0x002e */
+	PACKB(0, 0),	/* 0x002f */
+	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
+	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
+	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
+	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
+	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
+	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
+	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
+	PACKB(3, 3),	/* MBOX_SET_PCI_CONTROL_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x003a */
+	PACKB(0, 0),	/* 0x003b */
+	PACKB(0, 0),	/* 0x003c */
+	PACKB(0, 0),	/* 0x003d */
+	PACKB(0, 0),	/* 0x003e */
+	PACKB(0, 0),	/* 0x003f */
+	PACKB(1, 2),	/* MBOX_RETURN_BIOS_BLOCK_ADDR */
+	PACKB(6, 1),	/* MBOX_WRITE_FOUR_RAM_WORDS */
+	PACKB(2, 3)	/* MBOX_EXEC_BIOS_IOCB */
+#ifdef CONFIG_QL_ISP_A64
+	,PACKB(0, 0),	/* 0x0043 */
+	PACKB(0, 0),	/* 0x0044 */
+	PACKB(0, 0),	/* 0x0045 */
+	PACKB(0, 0),	/* 0x0046 */
+	PACKB(0, 0),	/* 0x0047 */
+	PACKB(0, 0),	/* 0x0048 */
+	PACKB(0, 0),	/* 0x0049 */
+	PACKB(0, 0),	/* 0x004a */
+	PACKB(0, 0),	/* 0x004b */
+	PACKB(0, 0),	/* 0x004c */
+	PACKB(0, 0),	/* 0x004d */
+	PACKB(0, 0),	/* 0x004e */
+	PACKB(0, 0),	/* 0x004f */
+	PACKB(0, 0),	/* 0x0050 */
+	PACKB(0, 0),	/* 0x0051 */
+	PACKB(8, 8),	/* MBOX_CMD_INIT_REQUEST_QUEUE_64 (0x0052) */
+	PACKB(8, 8)	/* MBOX_CMD_INIT_RESPONSE_QUEUE_64 (0x0053) */
+#endif /* CONFIG_QL_ISP_A64 */
+};
+
+#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
+
+struct host_param {
+	u_short		fifo_threshold;
+	u_short		host_adapter_enable;
+	u_short		initiator_scsi_id;
+	u_short		bus_reset_delay;
+	u_short		retry_count;
+	u_short		retry_delay;
+	u_short		async_data_setup_time;
+	u_short		req_ack_active_negation;
+	u_short		data_line_active_negation;
+	u_short		data_dma_burst_enable;
+	u_short		command_dma_burst_enable;
+	u_short		tag_aging;
+	u_short		selection_timeout;
+	u_short		max_queue_depth;
+};
+
+/*
+ * Device Flags:
+ *
+ * Bit  Name
+ * ---------
+ *  7   Disconnect Privilege
+ *  6   Parity Checking
+ *  5   Wide Data Transfers
+ *  4   Synchronous Data Transfers
+ *  3   Tagged Queuing
+ *  2   Automatic Request Sense
+ *  1   Stop Queue on Check Condition
+ *  0   Renegotiate on Error
+ */
+
+struct dev_param {
+	u_short		device_flags;
+	u_short		execution_throttle;
+	u_short		synchronous_period;
+	u_short		synchronous_offset;
+	u_short		device_enable;
+	u_short		reserved; /* pad */
+};
+
+/*
+ * The result queue can be quite a bit smaller since continuation entries
+ * do not show up there:
+ */
+#define RES_QUEUE_LEN		((QLOGICISP_REQ_QUEUE_LEN + 1) / 8 - 1)
+#define QUEUE_ENTRY_LEN		64
+#define QSIZE(entries)  (((entries) + 1) * QUEUE_ENTRY_LEN)
+
+struct isp_queue_entry {
+	char __opaque[QUEUE_ENTRY_LEN];
+};
+
+struct isp1020_hostdata {
+	void __iomem *memaddr;
+	u_char	revision;
+	struct	host_param host_param;
+	struct	dev_param dev_param[MAX_TARGETS];
+	struct	pci_dev *pci_dev;
+	
+	struct isp_queue_entry *res_cpu; /* CPU-side address of response queue. */
+	struct isp_queue_entry *req_cpu; /* CPU-size address of request queue. */
+
+	/* result and request queues (shared with isp1020): */
+	u_int	req_in_ptr;		/* index of next request slot */
+	u_int	res_out_ptr;		/* index of next result slot */
+
+	/* this is here so the queues are nicely aligned */
+	long	send_marker;		/* do we need to send a marker? */
+
+	/* The cmd->handle has a fixed size, and is only 32-bits.  We
+	 * need to take care to handle 64-bit systems correctly thus what
+	 * we actually place in cmd->handle is an index to the following
+	 * table.  Kudos to Matt Jacob for the technique.  -DaveM
+	 */
+	Scsi_Cmnd *cmd_slots[QLOGICISP_REQ_QUEUE_LEN + 1];
+
+	dma_addr_t res_dma;	/* PCI side view of response queue */
+	dma_addr_t req_dma;	/* PCI side view of request queue */
+};
+
+/* queue length's _must_ be power of two: */
+#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
+#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
+						    QLOGICISP_REQ_QUEUE_LEN)
+#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
+
+static void	isp1020_enable_irqs(struct Scsi_Host *);
+static void	isp1020_disable_irqs(struct Scsi_Host *);
+static int	isp1020_init(struct Scsi_Host *);
+static int	isp1020_reset_hardware(struct Scsi_Host *);
+static int	isp1020_set_defaults(struct Scsi_Host *);
+static int	isp1020_load_parameters(struct Scsi_Host *);
+static int	isp1020_mbox_command(struct Scsi_Host *, u_short []); 
+static int	isp1020_return_status(struct Status_Entry *);
+static void	isp1020_intr_handler(int, void *, struct pt_regs *);
+static irqreturn_t do_isp1020_intr_handler(int, void *, struct pt_regs *);
+
+#if USE_NVRAM_DEFAULTS
+static int	isp1020_get_defaults(struct Scsi_Host *);
+static int	isp1020_verify_nvram(struct Scsi_Host *);
+static u_short	isp1020_read_nvram_word(struct Scsi_Host *, u_short);
+#endif
+
+#if DEBUG_ISP1020
+static void	isp1020_print_scsi_cmd(Scsi_Cmnd *);
+#endif
+#if DEBUG_ISP1020_INTR
+static void	isp1020_print_status_entry(struct Status_Entry *);
+#endif
+
+/* memaddr should be used to determine if memmapped port i/o is being used
+ * non-null memaddr == mmap'd
+ * JV 7-Jan-2000
+ */
+static inline u_short isp_inw(struct Scsi_Host *host, long offset)
+{
+	struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
+	if (h->memaddr)
+		return readw(h->memaddr + offset);
+	else
+		return inw(host->io_port + offset);
+}
+
+static inline void isp_outw(u_short val, struct Scsi_Host *host, long offset)
+{
+	struct isp1020_hostdata *h = (struct isp1020_hostdata *)host->hostdata;
+	if (h->memaddr)
+		writew(val, h->memaddr + offset);
+	else
+		outw(val, host->io_port + offset);
+}
+
+static inline void isp1020_enable_irqs(struct Scsi_Host *host)
+{
+	isp_outw(ISP_EN_INT|ISP_EN_RISC, host, PCI_INTF_CTL);
+}
+
+
+static inline void isp1020_disable_irqs(struct Scsi_Host *host)
+{
+	isp_outw(0x0, host, PCI_INTF_CTL);
+}
+
+
+static int isp1020_detect(Scsi_Host_Template *tmpt)
+{
+	int hosts = 0;
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+	struct pci_dev *pdev = NULL;
+
+	ENTER("isp1020_detect");
+
+	tmpt->proc_name = "isp1020";
+
+	while ((pdev = pci_find_device(PCI_VENDOR_ID_QLOGIC, PCI_DEVICE_ID_QLOGIC_ISP1020, pdev)))
+	{
+		if (pci_enable_device(pdev))
+			continue;
+
+		host = scsi_register(tmpt, sizeof(struct isp1020_hostdata));
+		if (!host)
+			continue;
+
+		hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+		memset(hostdata, 0, sizeof(struct isp1020_hostdata));
+
+		hostdata->pci_dev = pdev;
+		scsi_set_device(host, &pdev->dev);
+
+		if (isp1020_init(host))
+			goto fail_and_unregister;
+
+		if (isp1020_reset_hardware(host)
+#if USE_NVRAM_DEFAULTS
+		    || isp1020_get_defaults(host)
+#else
+		    || isp1020_set_defaults(host)
+#endif /* USE_NVRAM_DEFAULTS */
+		    || isp1020_load_parameters(host)) {
+			goto fail_uninit;
+		}
+
+		host->this_id = hostdata->host_param.initiator_scsi_id;
+		host->max_sectors = 64;
+
+		if (request_irq(host->irq, do_isp1020_intr_handler, SA_INTERRUPT | SA_SHIRQ,
+				"qlogicisp", host))
+		{
+			printk("qlogicisp : interrupt %d already in use\n",
+			       host->irq);
+			goto fail_uninit;
+		}
+
+		isp_outw(0x0, host, PCI_SEMAPHORE);
+		isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
+		isp1020_enable_irqs(host);
+
+		hosts++;
+		continue;
+
+	fail_uninit:
+		iounmap(hostdata->memaddr);
+		release_region(host->io_port, 0xff);
+	fail_and_unregister:
+		if (hostdata->res_cpu)
+			pci_free_consistent(hostdata->pci_dev,
+					    QSIZE(RES_QUEUE_LEN),
+					    hostdata->res_cpu,
+					    hostdata->res_dma);
+		if (hostdata->req_cpu)
+			pci_free_consistent(hostdata->pci_dev,
+					    QSIZE(QLOGICISP_REQ_QUEUE_LEN),
+					    hostdata->req_cpu,
+					    hostdata->req_dma);
+		scsi_unregister(host);
+	}
+
+	LEAVE("isp1020_detect");
+
+	return hosts;
+}
+
+
+static int isp1020_release(struct Scsi_Host *host)
+{
+	struct isp1020_hostdata *hostdata;
+
+	ENTER("isp1020_release");
+
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+	isp_outw(0x0, host, PCI_INTF_CTL);
+	free_irq(host->irq, host);
+
+	iounmap(hostdata->memaddr);
+
+	release_region(host->io_port, 0xff);
+
+	LEAVE("isp1020_release");
+
+	return 0;
+}
+
+
+static const char *isp1020_info(struct Scsi_Host *host)
+{
+	static char buf[80];
+	struct isp1020_hostdata *hostdata;
+
+	ENTER("isp1020_info");
+
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+	sprintf(buf,
+		"QLogic ISP1020 SCSI on PCI bus %02x device %02x irq %d %s base 0x%lx",
+		hostdata->pci_dev->bus->number, hostdata->pci_dev->devfn, host->irq,
+		(hostdata->memaddr ? "MEM" : "I/O"),
+		(hostdata->memaddr ? (unsigned long)hostdata->memaddr : host->io_port));
+
+	LEAVE("isp1020_info");
+
+	return buf;
+}
+
+
+/*
+ * The middle SCSI layer ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (though the
+ * interrupt handler may call this routine as part of
+ * request-completion handling).
+ */
+static int isp1020_queuecommand(Scsi_Cmnd *Cmnd, void (*done)(Scsi_Cmnd *))
+{
+	int i, n, num_free;
+	u_int in_ptr, out_ptr;
+	struct dataseg * ds;
+	struct scatterlist *sg;
+	struct Command_Entry *cmd;
+	struct Continuation_Entry *cont;
+	struct Scsi_Host *host;
+	struct isp1020_hostdata *hostdata;
+	dma_addr_t	dma_addr;
+
+	ENTER("isp1020_queuecommand");
+
+	host = Cmnd->device->host;
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+	Cmnd->scsi_done = done;
+
+	DEBUG(isp1020_print_scsi_cmd(Cmnd));
+
+	out_ptr = isp_inw(host, + MBOX4);
+	in_ptr  = hostdata->req_in_ptr;
+
+	DEBUG(printk("qlogicisp : request queue depth %d\n",
+		     REQ_QUEUE_DEPTH(in_ptr, out_ptr)));
+
+	cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
+	in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+	if (in_ptr == out_ptr) {
+		printk("qlogicisp : request queue overflow\n");
+		return 1;
+	}
+
+	if (hostdata->send_marker) {
+		struct Marker_Entry *marker;
+
+		TRACE("queue marker", in_ptr, 0);
+
+		DEBUG(printk("qlogicisp : adding marker entry\n"));
+		marker = (struct Marker_Entry *) cmd;
+		memset(marker, 0, sizeof(struct Marker_Entry));
+
+		marker->hdr.entry_type = ENTRY_MARKER;
+		marker->hdr.entry_cnt = 1;
+		marker->modifier = SYNC_ALL;
+
+		hostdata->send_marker = 0;
+
+		if (((in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN) == out_ptr) {
+			isp_outw(in_ptr, host, MBOX4);
+			hostdata->req_in_ptr = in_ptr;
+			printk("qlogicisp : request queue overflow\n");
+			return 1;
+		}
+		cmd = (struct Command_Entry *) &hostdata->req_cpu[in_ptr];
+		in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+	}
+
+	TRACE("queue command", in_ptr, Cmnd);
+
+	memset(cmd, 0, sizeof(struct Command_Entry));
+
+	cmd->hdr.entry_type = ENTRY_COMMAND;
+	cmd->hdr.entry_cnt = 1;
+
+	cmd->target_lun = Cmnd->device->lun;
+	cmd->target_id = Cmnd->device->id;
+	cmd->cdb_length = cpu_to_le16(Cmnd->cmd_len);
+	cmd->control_flags = cpu_to_le16(CFLAG_READ | CFLAG_WRITE);
+	cmd->time_out = cpu_to_le16(30);
+
+	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
+
+	if (Cmnd->use_sg) {
+		int sg_count;
+
+		sg = (struct scatterlist *) Cmnd->request_buffer;
+		ds = cmd->dataseg;
+
+		sg_count = pci_map_sg(hostdata->pci_dev, sg, Cmnd->use_sg,
+				      scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+		cmd->segment_cnt = cpu_to_le16(sg_count);
+
+		/* fill in first four sg entries: */
+		n = sg_count;
+		if (n > IOCB_SEGS)
+			n = IOCB_SEGS;
+		for (i = 0; i < n; i++) {
+			dma_addr = sg_dma_address(sg);
+			ds[i].d_base  = cpu_to_le32((u32) dma_addr);
+#ifdef CONFIG_QL_ISP_A64
+			ds[i].d_base_hi = cpu_to_le32((u32) (dma_addr>>32));
+#endif /* CONFIG_QL_ISP_A64 */
+			ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
+			++sg;
+		}
+		sg_count -= IOCB_SEGS;
+
+		while (sg_count > 0) {
+			++cmd->hdr.entry_cnt;
+			cont = (struct Continuation_Entry *)
+				&hostdata->req_cpu[in_ptr];
+			in_ptr = (in_ptr + 1) & QLOGICISP_REQ_QUEUE_LEN;
+			if (in_ptr == out_ptr) {
+				printk("isp1020: unexpected request queue "
+				       "overflow\n");
+				return 1;
+			}
+			TRACE("queue continuation", in_ptr, 0);
+			cont->hdr.entry_type = ENTRY_CONTINUATION;
+			cont->hdr.entry_cnt  = 0;
+			cont->hdr.sys_def_1  = 0;
+			cont->hdr.flags      = 0;
+#ifndef CONFIG_QL_ISP_A64
+			cont->reserved = 0;
+#endif
+			ds = cont->dataseg;
+			n = sg_count;
+			if (n > CONTINUATION_SEGS)
+				n = CONTINUATION_SEGS;
+			for (i = 0; i < n; ++i) {
+				dma_addr = sg_dma_address(sg);
+				ds[i].d_base = cpu_to_le32((u32) dma_addr);
+#ifdef CONFIG_QL_ISP_A64
+				ds[i].d_base_hi = cpu_to_le32((u32)(dma_addr>>32));
+#endif /* CONFIG_QL_ISP_A64 */
+				ds[i].d_count = cpu_to_le32(sg_dma_len(sg));
+				++sg;
+			}
+			sg_count -= n;
+		}
+	} else if (Cmnd->request_bufflen) {
+		/*Cmnd->SCp.ptr = (char *)(unsigned long)*/
+		dma_addr = pci_map_single(hostdata->pci_dev,
+				       Cmnd->request_buffer,
+				       Cmnd->request_bufflen,
+				       scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		Cmnd->SCp.ptr = (char *)(unsigned long) dma_addr;
+
+		cmd->dataseg[0].d_base =
+			cpu_to_le32((u32) dma_addr);
+#ifdef CONFIG_QL_ISP_A64
+		cmd->dataseg[0].d_base_hi =
+			cpu_to_le32((u32) (dma_addr>>32));
+#endif /* CONFIG_QL_ISP_A64 */
+		cmd->dataseg[0].d_count =
+			cpu_to_le32((u32)Cmnd->request_bufflen);
+		cmd->segment_cnt = cpu_to_le16(1);
+	} else {
+		cmd->dataseg[0].d_base = 0;
+#ifdef CONFIG_QL_ISP_A64
+		cmd->dataseg[0].d_base_hi = 0;
+#endif /* CONFIG_QL_ISP_A64 */
+		cmd->dataseg[0].d_count = 0;
+		cmd->segment_cnt = cpu_to_le16(1); /* Shouldn't this be 0? */
+	}
+
+	/* Committed, record Scsi_Cmd so we can find it later. */
+	cmd->handle = in_ptr;
+	hostdata->cmd_slots[in_ptr] = Cmnd;
+
+	isp_outw(in_ptr, host, MBOX4);
+	hostdata->req_in_ptr = in_ptr;
+
+	num_free = QLOGICISP_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr);
+	host->can_queue = host->host_busy + num_free;
+	host->sg_tablesize = QLOGICISP_MAX_SG(num_free);
+
+	LEAVE("isp1020_queuecommand");
+
+	return 0;
+}
+
+
+#define ASYNC_EVENT_INTERRUPT	0x01
+
+irqreturn_t do_isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host *host = dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	isp1020_intr_handler(irq, dev_id, regs);
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+void isp1020_intr_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	Scsi_Cmnd *Cmnd;
+	struct Status_Entry *sts;
+	struct Scsi_Host *host = dev_id;
+	struct isp1020_hostdata *hostdata;
+	u_int in_ptr, out_ptr;
+	u_short status;
+
+	ENTER_INTR("isp1020_intr_handler");
+
+	hostdata = (struct isp1020_hostdata *) host->hostdata;
+
+	DEBUG_INTR(printk("qlogicisp : interrupt on line %d\n", irq));
+
+	if (!(isp_inw(host, PCI_INTF_STS) & 0x04)) {
+		/* spurious interrupts can happen legally */
+		DEBUG_INTR(printk("qlogicisp: got spurious interrupt\n"));
+		return;
+	}
+	in_ptr = isp_inw(host, MBOX5);
+	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
+
+	if ((isp_inw(host, PCI_SEMAPHORE) & ASYNC_EVENT_INTERRUPT)) {
+		status = isp_inw(host, MBOX0);
+
+		DEBUG_INTR(printk("qlogicisp : mbox completion status: %x\n",
+				  status));
+
+		switch (status) {
+		      case ASYNC_SCSI_BUS_RESET:
+		      case EXECUTION_TIMEOUT_RESET:
+			hostdata->send_marker = 1;
+			break;
+		      case INVALID_COMMAND:
+		      case HOST_INTERFACE_ERROR:
+		      case COMMAND_ERROR:
+		      case COMMAND_PARAM_ERROR:
+			printk("qlogicisp : bad mailbox return status\n");
+			break;
+		}
+		isp_outw(0x0, host, PCI_SEMAPHORE);
+	}
+	out_ptr = hostdata->res_out_ptr;
+
+	DEBUG_INTR(printk("qlogicisp : response queue update\n"));
+	DEBUG_INTR(printk("qlogicisp : response queue depth %d\n",
+			  QUEUE_DEPTH(in_ptr, out_ptr, RES_QUEUE_LEN)));
+
+	while (out_ptr != in_ptr) {
+		u_int cmd_slot;
+
+		sts = (struct Status_Entry *) &hostdata->res_cpu[out_ptr];
+		out_ptr = (out_ptr + 1) & RES_QUEUE_LEN;
+
+		cmd_slot = sts->handle;
+		Cmnd = hostdata->cmd_slots[cmd_slot];
+		hostdata->cmd_slots[cmd_slot] = NULL;
+
+		TRACE("done", out_ptr, Cmnd);
+
+		if (le16_to_cpu(sts->completion_status) == CS_RESET_OCCURRED
+		    || le16_to_cpu(sts->completion_status) == CS_ABORTED
+		    || (le16_to_cpu(sts->status_flags) & STF_BUS_RESET))
+			hostdata->send_marker = 1;
+
+		if (le16_to_cpu(sts->state_flags) & SF_GOT_SENSE)
+			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+			       sizeof(Cmnd->sense_buffer));
+
+		DEBUG_INTR(isp1020_print_status_entry(sts));
+
+		if (sts->hdr.entry_type == ENTRY_STATUS)
+			Cmnd->result = isp1020_return_status(sts);
+		else
+			Cmnd->result = DID_ERROR << 16;
+
+		if (Cmnd->use_sg)
+			pci_unmap_sg(hostdata->pci_dev,
+				     (struct scatterlist *)Cmnd->buffer,
+				     Cmnd->use_sg,
+				     scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+		else if (Cmnd->request_bufflen)
+			pci_unmap_single(hostdata->pci_dev,
+#ifdef CONFIG_QL_ISP_A64
+					 (dma_addr_t)((long)Cmnd->SCp.ptr),
+#else
+					 (u32)((long)Cmnd->SCp.ptr),
+#endif
+					 Cmnd->request_bufflen,
+					 scsi_to_pci_dma_dir(Cmnd->sc_data_direction));
+
+		isp_outw(out_ptr, host, MBOX5);
+		(*Cmnd->scsi_done)(Cmnd);
+	}
+	hostdata->res_out_ptr = out_ptr;
+
+	LEAVE_INTR("isp1020_intr_handler");
+}
+
+
+static int isp1020_return_status(struct Status_Entry *sts)
+{
+	int host_status = DID_ERROR;
+#if DEBUG_ISP1020_INTR
+	static char *reason[] = {
+		"DID_OK",
+		"DID_NO_CONNECT",
+		"DID_BUS_BUSY",
+		"DID_TIME_OUT",
+		"DID_BAD_TARGET",
+		"DID_ABORT",
+		"DID_PARITY",
+		"DID_ERROR",
+		"DID_RESET",
+		"DID_BAD_INTR"
+	};
+#endif /* DEBUG_ISP1020_INTR */
+
+	ENTER("isp1020_return_status");
+
+	DEBUG(printk("qlogicisp : completion status = 0x%04x\n",
+		     le16_to_cpu(sts->completion_status)));
+
+	switch(le16_to_cpu(sts->completion_status)) {
+	      case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+	      case CS_INCOMPLETE:
+		if (!(le16_to_cpu(sts->state_flags) & SF_GOT_BUS))
+			host_status = DID_NO_CONNECT;
+		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_TARGET))
+			host_status = DID_BAD_TARGET;
+		else if (!(le16_to_cpu(sts->state_flags) & SF_SENT_CDB))
+			host_status = DID_ERROR;
+		else if (!(le16_to_cpu(sts->state_flags) & SF_TRANSFERRED_DATA))
+			host_status = DID_ERROR;
+		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_STATUS))
+			host_status = DID_ERROR;
+		else if (!(le16_to_cpu(sts->state_flags) & SF_GOT_SENSE))
+			host_status = DID_ERROR;
+		break;
+	      case CS_DMA_ERROR:
+	      case CS_TRANSPORT_ERROR:
+		host_status = DID_ERROR;
+		break;
+	      case CS_RESET_OCCURRED:
+		host_status = DID_RESET;
+		break;
+	      case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+	      case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+	      case CS_DATA_OVERRUN:
+	      case CS_COMMAND_OVERRUN:
+	      case CS_STATUS_OVERRUN:
+	      case CS_BAD_MESSAGE:
+	      case CS_NO_MESSAGE_OUT:
+	      case CS_EXT_ID_FAILED:
+	      case CS_IDE_MSG_FAILED:
+	      case CS_ABORT_MSG_FAILED:
+	      case CS_NOP_MSG_FAILED:
+	      case CS_PARITY_ERROR_MSG_FAILED:
+	      case CS_DEVICE_RESET_MSG_FAILED:
+	      case CS_ID_MSG_FAILED:
+	      case CS_UNEXP_BUS_FREE:
+		host_status = DID_ERROR;
+		break;
+	      case CS_DATA_UNDERRUN:
+		host_status = DID_OK;
+		break;
+	      default:
+		printk("qlogicisp : unknown completion status 0x%04x\n",
+		       le16_to_cpu(sts->completion_status));
+		host_status = DID_ERROR;
+		break;
+	}
+
+	DEBUG_INTR(printk("qlogicisp : host status (%s) scsi status %x\n",
+			  reason[host_status], le16_to_cpu(sts->scsi_status)));
+
+	LEAVE("isp1020_return_status");
+
+	return (le16_to_cpu(sts->scsi_status) & STATUS_MASK) | (host_status << 16);
+}
+
+
+static int isp1020_biosparam(struct scsi_device *sdev, struct block_device *n,
+		sector_t capacity, int ip[])
+{
+	int size = capacity;
+
+	ENTER("isp1020_biosparam");
+
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = size >> 11;
+	if (ip[2] > 1024) {
+		ip[0] = 255;
+		ip[1] = 63;
+		ip[2] = size / (ip[0] * ip[1]);
+#if 0
+		if (ip[2] > 1023)
+			ip[2] = 1023;
+#endif			
+	}
+
+	LEAVE("isp1020_biosparam");
+
+	return 0;
+}
+
+
+static int isp1020_reset_hardware(struct Scsi_Host *host)
+{
+	u_short param[6];
+	int loop_count;
+
+	ENTER("isp1020_reset_hardware");
+
+	isp_outw(ISP_RESET, host, PCI_INTF_CTL);
+	udelay(100);
+	isp_outw(HCCR_RESET, host, HOST_HCCR);
+	udelay(100);
+	isp_outw(HCCR_RELEASE, host, HOST_HCCR);
+	isp_outw(HCCR_BIOS_DISABLE, host, HOST_HCCR);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && isp_inw(host, HOST_HCCR) == RISC_BUSY) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicisp: reset_hardware loop timeout\n");
+
+	isp_outw(0, host, ISP_CFG1);
+
+#if DEBUG_ISP1020
+	printk("qlogicisp : mbox 0 0x%04x \n", isp_inw(host, MBOX0));
+	printk("qlogicisp : mbox 1 0x%04x \n", isp_inw(host, MBOX1));
+	printk("qlogicisp : mbox 2 0x%04x \n", isp_inw(host, MBOX2));
+	printk("qlogicisp : mbox 3 0x%04x \n", isp_inw(host, MBOX3));
+	printk("qlogicisp : mbox 4 0x%04x \n", isp_inw(host, MBOX4));
+	printk("qlogicisp : mbox 5 0x%04x \n", isp_inw(host, MBOX5));
+#endif /* DEBUG_ISP1020 */
+
+	param[0] = MBOX_NO_OP;
+	isp1020_mbox_command(host, param);
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : NOP test failed\n");
+		return 1;
+	}
+
+	DEBUG(printk("qlogicisp : loading risc ram\n"));
+
+#if RELOAD_FIRMWARE
+	for (loop_count = 0; loop_count < risc_code_length01; loop_count++) {
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = risc_code_addr01 + loop_count;
+		param[2] = risc_code01[loop_count];
+		isp1020_mbox_command(host, param);
+		if (param[0] != MBOX_COMMAND_COMPLETE) {
+			printk("qlogicisp : firmware load failure at %d\n",
+			    loop_count);
+			return 1;
+		}
+	}
+#endif /* RELOAD_FIRMWARE */
+
+	DEBUG(printk("qlogicisp : verifying checksum\n"));
+
+	param[0] = MBOX_VERIFY_CHECKSUM;
+	param[1] = risc_code_addr01;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : ram checksum failure\n");
+		return 1;
+	}
+
+	DEBUG(printk("qlogicisp : executing firmware\n"));
+
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr01;
+
+	isp1020_mbox_command(host, param);
+
+	param[0] = MBOX_ABOUT_FIRMWARE;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : about firmware failure\n");
+		return 1;
+	}
+
+	DEBUG(printk("qlogicisp : firmware major revision %d\n", param[1]));
+	DEBUG(printk("qlogicisp : firmware minor revision %d\n", param[2]));
+
+	LEAVE("isp1020_reset_hardware");
+
+	return 0;
+}
+
+
+static int isp1020_init(struct Scsi_Host *sh)
+{
+	u_long io_base, mem_base, io_flags, mem_flags;
+	struct isp1020_hostdata *hostdata;
+	u_char revision;
+	u_int irq;
+	u_short command;
+	struct pci_dev *pdev;
+
+	ENTER("isp1020_init");
+
+	hostdata = (struct isp1020_hostdata *) sh->hostdata;
+	pdev = hostdata->pci_dev;
+
+	if (pci_read_config_word(pdev, PCI_COMMAND, &command)
+	    || pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision))
+	{
+		printk("qlogicisp : error reading PCI configuration\n");
+		return 1;
+	}
+
+	io_base = pci_resource_start(pdev, 0);
+	mem_base = pci_resource_start(pdev, 1);
+	io_flags = pci_resource_flags(pdev, 0);
+	mem_flags = pci_resource_flags(pdev, 1);
+	irq = pdev->irq;
+
+	if (pdev->vendor != PCI_VENDOR_ID_QLOGIC) {
+		printk("qlogicisp : 0x%04x is not QLogic vendor ID\n",
+		       pdev->vendor);
+		return 1;
+	}
+
+	if (pdev->device != PCI_DEVICE_ID_QLOGIC_ISP1020) {
+		printk("qlogicisp : 0x%04x does not match ISP1020 device id\n",
+		       pdev->device);
+		return 1;
+	}
+
+#ifdef __alpha__
+	/* Force ALPHA to use bus I/O and not bus MEM.
+	   This is to avoid having to use HAE_MEM registers,
+	   which is broken on some platforms and with SMP.  */
+	command &= ~PCI_COMMAND_MEMORY; 
+#endif
+
+	sh->io_port = io_base;
+
+	if (!request_region(sh->io_port, 0xff, "qlogicisp")) {
+		printk("qlogicisp : i/o region 0x%lx-0x%lx already "
+		       "in use\n",
+		       sh->io_port, sh->io_port + 0xff);
+		return 1;
+	}
+
+ 	if ((command & PCI_COMMAND_MEMORY) &&
+ 	    ((mem_flags & 1) == 0)) {
+ 		hostdata->memaddr = ioremap(mem_base, PAGE_SIZE);
+		if (!hostdata->memaddr) {
+ 			printk("qlogicisp : i/o remapping failed.\n");
+			goto out_release;
+		}
+ 	} else {
+		if (command & PCI_COMMAND_IO && (io_flags & 3) != 1) {
+			printk("qlogicisp : i/o mapping is disabled\n");
+			goto out_release;
+ 		}
+ 		hostdata->memaddr = NULL; /* zero to signify no i/o mapping */
+ 		mem_base = 0;
+	}
+
+	if (revision != ISP1020_REV_ID)
+		printk("qlogicisp : new isp1020 revision ID (%d)\n", revision);
+
+	if (isp_inw(sh,  PCI_ID_LOW) != PCI_VENDOR_ID_QLOGIC
+	    || isp_inw(sh, PCI_ID_HIGH) != PCI_DEVICE_ID_QLOGIC_ISP1020)
+	{
+		printk("qlogicisp : can't decode %s address space 0x%lx\n",
+		       (io_base ? "I/O" : "MEM"),
+		       (io_base ? io_base : mem_base));
+		goto out_unmap;
+	}
+
+	hostdata->revision = revision;
+
+	sh->irq = irq;
+	sh->max_id = MAX_TARGETS;
+	sh->max_lun = MAX_LUNS;
+
+	hostdata->res_cpu = pci_alloc_consistent(hostdata->pci_dev,
+						 QSIZE(RES_QUEUE_LEN),
+						 &hostdata->res_dma);
+	if (hostdata->res_cpu == NULL) {
+		printk("qlogicisp : can't allocate response queue\n");
+		goto out_unmap;
+	}
+
+	hostdata->req_cpu = pci_alloc_consistent(hostdata->pci_dev,
+						 QSIZE(QLOGICISP_REQ_QUEUE_LEN),
+						 &hostdata->req_dma);
+	if (hostdata->req_cpu == NULL) {
+		pci_free_consistent(hostdata->pci_dev,
+				    QSIZE(RES_QUEUE_LEN),
+				    hostdata->res_cpu,
+				    hostdata->res_dma);
+		printk("qlogicisp : can't allocate request queue\n");
+		goto out_unmap;
+	}
+
+	pci_set_master(pdev);
+
+	LEAVE("isp1020_init");
+
+	return 0;
+
+out_unmap:
+	iounmap(hostdata->memaddr);
+out_release:
+	release_region(sh->io_port, 0xff);
+	return 1;
+}
+
+
+#if USE_NVRAM_DEFAULTS
+
+static int isp1020_get_defaults(struct Scsi_Host *host)
+{
+	int i;
+	u_short value;
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
+
+	ENTER("isp1020_get_defaults");
+
+	if (!isp1020_verify_nvram(host)) {
+		printk("qlogicisp : nvram checksum failure\n");
+		printk("qlogicisp : attempting to use default parameters\n");
+		return isp1020_set_defaults(host);
+	}
+
+	value = isp1020_read_nvram_word(host, 2);
+	hostdata->host_param.fifo_threshold = (value >> 8) & 0x03;
+	hostdata->host_param.host_adapter_enable = (value >> 11) & 0x01;
+	hostdata->host_param.initiator_scsi_id = (value >> 12) & 0x0f;
+
+	value = isp1020_read_nvram_word(host, 3);
+	hostdata->host_param.bus_reset_delay = value & 0xff;
+	hostdata->host_param.retry_count = value >> 8;
+
+	value = isp1020_read_nvram_word(host, 4);
+	hostdata->host_param.retry_delay = value & 0xff;
+	hostdata->host_param.async_data_setup_time = (value >> 8) & 0x0f;
+	hostdata->host_param.req_ack_active_negation = (value >> 12) & 0x01;
+	hostdata->host_param.data_line_active_negation = (value >> 13) & 0x01;
+	hostdata->host_param.data_dma_burst_enable = (value >> 14) & 0x01;
+	hostdata->host_param.command_dma_burst_enable = (value >> 15);
+
+	value = isp1020_read_nvram_word(host, 5);
+	hostdata->host_param.tag_aging = value & 0xff;
+
+	value = isp1020_read_nvram_word(host, 6);
+	hostdata->host_param.selection_timeout = value & 0xffff;
+
+	value = isp1020_read_nvram_word(host, 7);
+	hostdata->host_param.max_queue_depth = value & 0xffff;
+
+#if DEBUG_ISP1020_SETUP
+	printk("qlogicisp : fifo threshold=%d\n",
+	       hostdata->host_param.fifo_threshold);
+	printk("qlogicisp : initiator scsi id=%d\n",
+	       hostdata->host_param.initiator_scsi_id);
+	printk("qlogicisp : bus reset delay=%d\n",
+	       hostdata->host_param.bus_reset_delay);
+	printk("qlogicisp : retry count=%d\n",
+	       hostdata->host_param.retry_count);
+	printk("qlogicisp : retry delay=%d\n",
+	       hostdata->host_param.retry_delay);
+	printk("qlogicisp : async data setup time=%d\n",
+	       hostdata->host_param.async_data_setup_time);
+	printk("qlogicisp : req/ack active negation=%d\n",
+	       hostdata->host_param.req_ack_active_negation);
+	printk("qlogicisp : data line active negation=%d\n",
+	       hostdata->host_param.data_line_active_negation);
+	printk("qlogicisp : data DMA burst enable=%d\n",
+	       hostdata->host_param.data_dma_burst_enable);
+	printk("qlogicisp : command DMA burst enable=%d\n",
+	       hostdata->host_param.command_dma_burst_enable);
+	printk("qlogicisp : tag age limit=%d\n",
+	       hostdata->host_param.tag_aging);
+	printk("qlogicisp : selection timeout limit=%d\n",
+	       hostdata->host_param.selection_timeout);
+	printk("qlogicisp : max queue depth=%d\n",
+	       hostdata->host_param.max_queue_depth);
+#endif /* DEBUG_ISP1020_SETUP */
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+
+		value = isp1020_read_nvram_word(host, 14 + i * 3);
+		hostdata->dev_param[i].device_flags = value & 0xff;
+		hostdata->dev_param[i].execution_throttle = value >> 8;
+
+		value = isp1020_read_nvram_word(host, 15 + i * 3);
+		hostdata->dev_param[i].synchronous_period = value & 0xff;
+		hostdata->dev_param[i].synchronous_offset = (value >> 8) & 0x0f;
+		hostdata->dev_param[i].device_enable = (value >> 12) & 0x01;
+
+#if DEBUG_ISP1020_SETUP
+		printk("qlogicisp : target 0x%02x\n", i);
+		printk("qlogicisp :     device flags=0x%02x\n",
+		       hostdata->dev_param[i].device_flags);
+		printk("qlogicisp :     execution throttle=%d\n",
+		       hostdata->dev_param[i].execution_throttle);
+		printk("qlogicisp :     synchronous period=%d\n",
+		       hostdata->dev_param[i].synchronous_period);
+		printk("qlogicisp :     synchronous offset=%d\n",
+		       hostdata->dev_param[i].synchronous_offset);
+		printk("qlogicisp :     device enable=%d\n",
+		       hostdata->dev_param[i].device_enable);
+#endif /* DEBUG_ISP1020_SETUP */
+	}
+
+	LEAVE("isp1020_get_defaults");
+
+	return 0;
+}
+
+
+#define ISP1020_NVRAM_LEN	0x40
+#define ISP1020_NVRAM_SIG1	0x5349
+#define ISP1020_NVRAM_SIG2	0x2050
+
+static int isp1020_verify_nvram(struct Scsi_Host *host)
+{
+	int	i;
+	u_short value;
+	u_char checksum = 0;
+
+	for (i = 0; i < ISP1020_NVRAM_LEN; i++) {
+		value = isp1020_read_nvram_word(host, i);
+
+		switch (i) {
+		      case 0:
+			if (value != ISP1020_NVRAM_SIG1) return 0;
+			break;
+		      case 1:
+			if (value != ISP1020_NVRAM_SIG2) return 0;
+			break;
+		      case 2:
+			if ((value & 0xff) != 0x02) return 0;
+			break;
+		}
+		checksum += value & 0xff;
+		checksum += value >> 8;
+	}
+
+	return (checksum == 0);
+}
+
+#define NVRAM_DELAY() udelay(2) /* 2 microsecond delay */
+
+
+u_short isp1020_read_nvram_word(struct Scsi_Host *host, u_short byte)
+{
+	int i;
+	u_short value, output, input;
+
+	byte &= 0x3f; byte |= 0x0180;
+
+	for (i = 8; i >= 0; i--) {
+		output = ((byte >> i) & 0x1) ? 0x4 : 0x0;
+		isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
+		isp_outw(output | 0x3, host, PCI_NVRAM); NVRAM_DELAY();
+		isp_outw(output | 0x2, host, PCI_NVRAM); NVRAM_DELAY();
+	}
+
+	for (i = 0xf, value = 0; i >= 0; i--) {
+		value <<= 1;
+		isp_outw(0x3, host, PCI_NVRAM); NVRAM_DELAY();
+		input = isp_inw(host, PCI_NVRAM); NVRAM_DELAY();
+		isp_outw(0x2, host, PCI_NVRAM); NVRAM_DELAY();
+		if (input & 0x8) value |= 1;
+	}
+
+	isp_outw(0x0, host, PCI_NVRAM); NVRAM_DELAY();
+
+	return value;
+}
+
+#endif /* USE_NVRAM_DEFAULTS */
+
+
+static int isp1020_set_defaults(struct Scsi_Host *host)
+{
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
+	int i;
+
+	ENTER("isp1020_set_defaults");
+
+	hostdata->host_param.fifo_threshold = 2;
+	hostdata->host_param.host_adapter_enable = 1;
+	hostdata->host_param.initiator_scsi_id = 7;
+	hostdata->host_param.bus_reset_delay = 3;
+	hostdata->host_param.retry_count = 0;
+	hostdata->host_param.retry_delay = 1;
+	hostdata->host_param.async_data_setup_time = 6;
+	hostdata->host_param.req_ack_active_negation = 1;
+	hostdata->host_param.data_line_active_negation = 1;
+	hostdata->host_param.data_dma_burst_enable = 1;
+	hostdata->host_param.command_dma_burst_enable = 1;
+	hostdata->host_param.tag_aging = 8;
+	hostdata->host_param.selection_timeout = 250;
+	hostdata->host_param.max_queue_depth = 256;
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+		hostdata->dev_param[i].device_flags = 0xfd;
+		hostdata->dev_param[i].execution_throttle = 16;
+		hostdata->dev_param[i].synchronous_period = 25;
+		hostdata->dev_param[i].synchronous_offset = 12;
+		hostdata->dev_param[i].device_enable = 1;
+	}
+
+	LEAVE("isp1020_set_defaults");
+
+	return 0;
+}
+
+
+static int isp1020_load_parameters(struct Scsi_Host *host)
+{
+	int i, k;
+#ifdef CONFIG_QL_ISP_A64
+	u_long queue_addr;
+	u_short param[8];
+#else
+	u_int queue_addr;
+	u_short param[6];
+#endif
+	u_short isp_cfg1, hwrev;
+	struct isp1020_hostdata *hostdata =
+		(struct isp1020_hostdata *) host->hostdata;
+
+	ENTER("isp1020_load_parameters");
+
+	hwrev = isp_inw(host, ISP_CFG0) & ISP_CFG0_HWMSK;
+	isp_cfg1 = ISP_CFG1_F64 | ISP_CFG1_BENAB;
+	if (hwrev == ISP_CFG0_1040A) {
+		/* Busted fifo, says mjacob. */
+		isp_cfg1 &= ISP_CFG1_BENAB;
+	}
+
+	isp_outw(isp_inw(host, ISP_CFG1) | isp_cfg1, host, ISP_CFG1);
+	isp_outw(isp_inw(host, CDMA_CONF) | DMA_CONF_BENAB, host, CDMA_CONF);
+	isp_outw(isp_inw(host, DDMA_CONF) | DMA_CONF_BENAB, host, DDMA_CONF);
+
+	param[0] = MBOX_SET_INIT_SCSI_ID;
+	param[1] = hostdata->host_param.initiator_scsi_id;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set initiator id failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_RETRY_COUNT;
+	param[1] = hostdata->host_param.retry_count;
+	param[2] = hostdata->host_param.retry_delay;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set retry count failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_ASYNC_DATA_SETUP_TIME;
+	param[1] = hostdata->host_param.async_data_setup_time;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : async data setup time failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_ACTIVE_NEG_STATE;
+	param[1] = (hostdata->host_param.req_ack_active_negation << 4)
+		| (hostdata->host_param.data_line_active_negation << 5);
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set active negation state failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_PCI_CONTROL_PARAMS;
+	param[1] = hostdata->host_param.data_dma_burst_enable << 1;
+	param[2] = hostdata->host_param.command_dma_burst_enable << 1;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set pci control parameter failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_TAG_AGE_LIMIT;
+	param[1] = hostdata->host_param.tag_aging;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set tag age limit failure\n");
+		return 1;
+	}
+
+	param[0] = MBOX_SET_SELECT_TIMEOUT;
+	param[1] = hostdata->host_param.selection_timeout;
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set selection timeout failure\n");
+		return 1;
+	}
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+
+		if (!hostdata->dev_param[i].device_enable)
+			continue;
+
+		param[0] = MBOX_SET_TARGET_PARAMS;
+		param[1] = i << 8;
+		param[2] = hostdata->dev_param[i].device_flags << 8;
+		param[3] = (hostdata->dev_param[i].synchronous_offset << 8)
+			| hostdata->dev_param[i].synchronous_period;
+
+		isp1020_mbox_command(host, param);
+
+		if (param[0] != MBOX_COMMAND_COMPLETE) {
+			printk("qlogicisp : set target parameter failure\n");
+			return 1;
+		}
+
+		for (k = 0; k < MAX_LUNS; k++) {
+
+			param[0] = MBOX_SET_DEV_QUEUE_PARAMS;
+			param[1] = (i << 8) | k;
+			param[2] = hostdata->host_param.max_queue_depth;
+			param[3] = hostdata->dev_param[i].execution_throttle;
+
+			isp1020_mbox_command(host, param);
+
+			if (param[0] != MBOX_COMMAND_COMPLETE) {
+				printk("qlogicisp : set device queue "
+				       "parameter failure\n");
+				return 1;
+			}
+		}
+	}
+
+	queue_addr = hostdata->res_dma;
+#ifdef CONFIG_QL_ISP_A64
+	param[0] = MBOX_CMD_INIT_RESPONSE_QUEUE_64;
+#else
+	param[0] = MBOX_INIT_RES_QUEUE;
+#endif
+	param[1] = RES_QUEUE_LEN + 1;
+	param[2] = (u_short) (queue_addr >> 16);
+	param[3] = (u_short) (queue_addr & 0xffff);
+	param[4] = 0;
+	param[5] = 0;
+#ifdef CONFIG_QL_ISP_A64
+	param[6] = (u_short) (queue_addr >> 48);
+	param[7] = (u_short) (queue_addr >> 32);
+#endif
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set response queue failure\n");
+		return 1;
+	}
+
+	queue_addr = hostdata->req_dma;
+#ifdef CONFIG_QL_ISP_A64
+	param[0] = MBOX_CMD_INIT_REQUEST_QUEUE_64;
+#else
+	param[0] = MBOX_INIT_REQ_QUEUE;
+#endif
+	param[1] = QLOGICISP_REQ_QUEUE_LEN + 1;
+	param[2] = (u_short) (queue_addr >> 16);
+	param[3] = (u_short) (queue_addr & 0xffff);
+	param[4] = 0;
+
+#ifdef CONFIG_QL_ISP_A64
+	param[5] = 0;
+	param[6] = (u_short) (queue_addr >> 48);
+	param[7] = (u_short) (queue_addr >> 32);
+#endif
+
+	isp1020_mbox_command(host, param);
+
+	if (param[0] != MBOX_COMMAND_COMPLETE) {
+		printk("qlogicisp : set request queue failure\n");
+		return 1;
+	}
+
+	LEAVE("isp1020_load_parameters");
+
+	return 0;
+}
+
+
+/*
+ * currently, this is only called during initialization or abort/reset,
+ * at which times interrupts are disabled, so polling is OK, I guess...
+ */
+static int isp1020_mbox_command(struct Scsi_Host *host, u_short param[])
+{
+	int loop_count;
+
+	if (mbox_param[param[0]] == 0)
+		return 1;
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && isp_inw(host, HOST_HCCR) & 0x0080) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #1\n");
+
+	switch(mbox_param[param[0]] >> 4) {
+	      case 8: isp_outw(param[7], host, MBOX7);
+	      case 7: isp_outw(param[6], host, MBOX6);
+	      case 6: isp_outw(param[5], host, MBOX5);
+	      case 5: isp_outw(param[4], host, MBOX4);
+	      case 4: isp_outw(param[3], host, MBOX3);
+	      case 3: isp_outw(param[2], host, MBOX2);
+	      case 2: isp_outw(param[1], host, MBOX1);
+	      case 1: isp_outw(param[0], host, MBOX0);
+	}
+
+	isp_outw(0x0, host, PCI_SEMAPHORE);
+	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
+	isp_outw(HCCR_SET_HOST_INTR, host, HOST_HCCR);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && !(isp_inw(host, PCI_INTF_STS) & 0x04)) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #2\n");
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && isp_inw(host, MBOX0) == 0x04) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk("qlogicisp: mbox_command loop timeout #3\n");
+
+	switch(mbox_param[param[0]] & 0xf) {
+	      case 8: param[7] = isp_inw(host, MBOX7);
+	      case 7: param[6] = isp_inw(host, MBOX6);
+	      case 6: param[5] = isp_inw(host, MBOX5);
+	      case 5: param[4] = isp_inw(host, MBOX4);
+	      case 4: param[3] = isp_inw(host, MBOX3);
+	      case 3: param[2] = isp_inw(host, MBOX2);
+	      case 2: param[1] = isp_inw(host, MBOX1);
+	      case 1: param[0] = isp_inw(host, MBOX0);
+	}
+
+	isp_outw(0x0, host, PCI_SEMAPHORE);
+	isp_outw(HCCR_CLEAR_RISC_INTR, host, HOST_HCCR);
+
+	return 0;
+}
+
+
+#if DEBUG_ISP1020_INTR
+
+void isp1020_print_status_entry(struct Status_Entry *status)
+{
+	int i;
+
+	printk("qlogicisp : entry count = 0x%02x, type = 0x%02x, flags = 0x%02x\n",
+	       status->hdr.entry_cnt, status->hdr.entry_type, status->hdr.flags);
+	printk("qlogicisp : scsi status = 0x%04x, completion status = 0x%04x\n",
+	       le16_to_cpu(status->scsi_status), le16_to_cpu(status->completion_status));
+	printk("qlogicisp : state flags = 0x%04x, status flags = 0x%04x\n",
+	       le16_to_cpu(status->state_flags), le16_to_cpu(status->status_flags));
+	printk("qlogicisp : time = 0x%04x, request sense length = 0x%04x\n",
+	       le16_to_cpu(status->time), le16_to_cpu(status->req_sense_len));
+	printk("qlogicisp : residual transfer length = 0x%08x\n",
+	       le32_to_cpu(status->residual));
+
+	for (i = 0; i < le16_to_cpu(status->req_sense_len); i++)
+		printk("qlogicisp : sense data = 0x%02x\n", status->req_sense_data[i]);
+}
+
+#endif /* DEBUG_ISP1020_INTR */
+
+
+#if DEBUG_ISP1020
+
+void isp1020_print_scsi_cmd(Scsi_Cmnd *cmd)
+{
+	int i;
+
+	printk("qlogicisp : target = 0x%02x, lun = 0x%02x, cmd_len = 0x%02x\n",
+	       cmd->target, cmd->lun, cmd->cmd_len);
+	printk("qlogicisp : command = ");
+	for (i = 0; i < cmd->cmd_len; i++)
+		printk("0x%02x ", cmd->cmnd[i]);
+	printk("\n");
+}
+
+#endif /* DEBUG_ISP1020 */
+
+MODULE_LICENSE("GPL");
+
+static Scsi_Host_Template driver_template = {
+	.detect			= isp1020_detect,
+	.release		= isp1020_release,
+	.info			= isp1020_info,	
+	.queuecommand		= isp1020_queuecommand,
+	.bios_param		= isp1020_biosparam,
+	.can_queue		= QLOGICISP_REQ_QUEUE_LEN,
+	.this_id		= -1,
+	.sg_tablesize		= QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN),
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/qlogicisp_asm.c b/drivers/scsi/qlogicisp_asm.c
new file mode 100644
index 0000000..9ea4bec
--- /dev/null
+++ b/drivers/scsi/qlogicisp_asm.c
@@ -0,0 +1,2034 @@
+/*
+ *      Firmware Version 7.63.00 (12:07 Jan 27, 1999)
+ */
+static const unsigned short risc_code_version = 7*1024+63;
+
+static const unsigned short risc_code_addr01 = 0x1000 ;
+
+#if RELOAD_FIRMWARE
+
+static const unsigned short risc_code01[] = {
+	0x0078, 0x103a, 0x0000, 0x3f14, 0x0000, 0x2043, 0x4f50, 0x5952,
+	0x4947, 0x4854, 0x2031, 0x3939, 0x3520, 0x514c, 0x4f47, 0x4943,
+	0x2043, 0x4f52, 0x504f, 0x5241, 0x5449, 0x4f4e, 0x2049, 0x5350,
+	0x3130, 0x3230, 0x2049, 0x2f54, 0x2046, 0x6972, 0x6d77, 0x6172,
+	0x6520, 0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x372e, 0x3633,
+	0x2020, 0x2043, 0x7573, 0x746f, 0x6d65, 0x7220, 0x4e6f, 0x2e20,
+	0x3030, 0x2050, 0x726f, 0x6475, 0x6374, 0x204e, 0x6f2e, 0x2020,
+	0x3031, 0x2024, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x0048,
+	0x1045, 0x0038, 0x104b, 0x0078, 0x1047, 0x0028, 0x104b, 0x20b9,
+	0x1212, 0x0078, 0x104d, 0x20b9, 0x2222, 0x20c1, 0x0008, 0x2071,
+	0x0010, 0x70c3, 0x0004, 0x20c9, 0x76ff, 0x2089, 0x1186, 0x70c7,
+	0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3, 0x0007, 0x3f00,
+	0x70d6, 0x20c1, 0x0008, 0x2019, 0x0000, 0x2009, 0xfeff, 0x2100,
+	0x200b, 0xa5a5, 0xa1ec, 0x7fff, 0x2d64, 0x206b, 0x0a0a, 0xaddc,
+	0x3fff, 0x2b54, 0x205b, 0x5050, 0x2114, 0xa286, 0xa5a5, 0x0040,
+	0x10bf, 0xa386, 0x000f, 0x0040, 0x1085, 0x2c6a, 0x2a5a, 0x20c1,
+	0x0000, 0x2019, 0x000f, 0x0078, 0x1065, 0x2c6a, 0x2a5a, 0x20c1,
+	0x0008, 0x2009, 0x7fff, 0x2148, 0x2944, 0x204b, 0x0a0a, 0xa9bc,
+	0x3fff, 0x2734, 0x203b, 0x5050, 0x2114, 0xa286, 0x0a0a, 0x0040,
+	0x10a9, 0x284a, 0x263a, 0x20c1, 0x0004, 0x2009, 0x3fff, 0x2134,
+	0x200b, 0x5050, 0x2114, 0xa286, 0x5050, 0x0040, 0x10aa, 0x0078,
+	0x118e, 0x284a, 0x263a, 0x98c0, 0xa188, 0x1000, 0x212c, 0x200b,
+	0xa5a5, 0x2114, 0xa286, 0xa5a5, 0x0040, 0x10bc, 0x250a, 0xa18a,
+	0x1000, 0x98c1, 0x0078, 0x10c1, 0x250a, 0x0078, 0x10c1, 0x2c6a,
+	0x2a5a, 0x2130, 0xa18a, 0x0040, 0x2128, 0xa1a2, 0x5000, 0x8424,
+	0x8424, 0x8424, 0x8424, 0x8424, 0x8424, 0xa192, 0x7700, 0x2009,
+	0x0000, 0x2001, 0x0031, 0x1078, 0x1c9d, 0x2218, 0x2079, 0x5000,
+	0x2fa0, 0x2408, 0x2011, 0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109,
+	0x00c0, 0x10dc, 0x7ef2, 0x8528, 0x7de6, 0x7cea, 0x7bee, 0x7883,
+	0x0000, 0x2031, 0x0030, 0x78cf, 0x0101, 0x780b, 0x0002, 0x780f,
+	0x0002, 0x784f, 0x0003, 0x2069, 0x5040, 0x2001, 0x04fd, 0x2004,
+	0xa082, 0x0005, 0x0048, 0x1104, 0x0038, 0x1100, 0x0078, 0x1108,
+	0x681b, 0x003c, 0x0078, 0x110a, 0x00a8, 0x1108, 0x681b, 0x003c,
+	0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa, 0x680f, 0x0008,
+	0x6813, 0x0005, 0x6823, 0x0000, 0x6827, 0x0006, 0x6817, 0x0008,
+	0x682b, 0x0000, 0x681f, 0x0019, 0x2069, 0x5280, 0x2011, 0x0020,
+	0x2009, 0x0010, 0x680b, 0x080c, 0x680f, 0x0019, 0x6803, 0xfd00,
+	0x6807, 0x0018, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
+	0x8109, 0x00c0, 0x1122, 0x2069, 0x5300, 0x2009, 0x0002, 0x20a9,
+	0x0100, 0x6837, 0x0000, 0x680b, 0x0040, 0x7bf0, 0xa386, 0xfeff,
+	0x00c0, 0x1148, 0x6817, 0x0100, 0x681f, 0x0064, 0x0078, 0x114c,
+	0x6817, 0x0064, 0x681f, 0x0002, 0xade8, 0x0010, 0x0070, 0x1152,
+	0x0078, 0x1139, 0x8109, 0x00c0, 0x1137, 0x1078, 0x21e9, 0x1078,
+	0x46e9, 0x1078, 0x1946, 0x1078, 0x4bdf, 0x3200, 0xa085, 0x000d,
+	0x2090, 0x70c3, 0x0000, 0x0090, 0x116c, 0x70c0, 0xa086, 0x0002,
+	0x00c0, 0x116c, 0x1078, 0x1284, 0x1078, 0x1196, 0x78cc, 0xa005,
+	0x00c0, 0x117a, 0x1078, 0x1cc6, 0x0010, 0x1180, 0x0068, 0x1180,
+	0x1078, 0x20c8, 0x0010, 0x1180, 0x0068, 0x1180, 0x1078, 0x1a2b,
+	0x00e0, 0x116c, 0x1078, 0x4a66, 0x0078, 0x116c, 0x118e, 0x1190,
+	0x23ea, 0x23ea, 0x476a, 0x476a, 0x23ea, 0x23ea, 0x0078, 0x118e,
+	0x0078, 0x1190, 0x0078, 0x1192, 0x0078, 0x1194, 0x0068, 0x1201,
+	0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x00c0, 0x1201, 0x7814,
+	0xa005, 0x00c0, 0x11a7, 0x0010, 0x1202, 0x0078, 0x1201, 0x2009,
+	0x505b, 0x2104, 0xa005, 0x00c0, 0x1201, 0x2009, 0x5064, 0x200b,
+	0x0000, 0x7914, 0xa186, 0x0042, 0x00c0, 0x11cc, 0x7816, 0x2009,
+	0x5062, 0x2164, 0x200b, 0x0000, 0x6018, 0x70c6, 0x6014, 0x70ca,
+	0x611c, 0xa18c, 0xff00, 0x6020, 0xa084, 0x00ff, 0xa105, 0x70ce,
+	0x1078, 0x192b, 0x0078, 0x11ff, 0x7814, 0xa086, 0x0018, 0x00c0,
+	0x11d3, 0x1078, 0x165a, 0x7817, 0x0000, 0x2009, 0x5062, 0x2104,
+	0xa065, 0x0040, 0x11ef, 0x0c7e, 0x609c, 0x2060, 0x1078, 0x1996,
+	0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c, 0x6007,
+	0x0103, 0x1078, 0x1907, 0x00c0, 0x11fb, 0x1078, 0x192b, 0x2009,
+	0x5062, 0x200b, 0x0000, 0x2009, 0x505c, 0x2104, 0x200b, 0x0000,
+	0xa005, 0x0040, 0x11ff, 0x2001, 0x4005, 0x0078, 0x1286, 0x0078,
+	0x1284, 0x007c, 0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000,
+	0x70cf, 0x0000, 0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1252, 0x2038,
+	0x0079, 0x1212, 0x1284, 0x12e5, 0x12a9, 0x12fe, 0x130d, 0x1313,
+	0x12a0, 0x1748, 0x1317, 0x1298, 0x12ad, 0x12af, 0x12b1, 0x12b3,
+	0x174d, 0x1298, 0x1329, 0x1360, 0x1672, 0x1742, 0x12b5, 0x1591,
+	0x15ad, 0x15c9, 0x15f4, 0x154a, 0x1558, 0x156c, 0x1580, 0x13df,
+	0x1298, 0x138d, 0x1393, 0x1398, 0x139d, 0x13a3, 0x13a8, 0x13ad,
+	0x13b2, 0x13b7, 0x13bb, 0x13d0, 0x13dc, 0x1298, 0x1298, 0x1298,
+	0x1298, 0x13eb, 0x13f4, 0x1403, 0x1429, 0x1433, 0x143a, 0x1480,
+	0x148f, 0x149e, 0x14b0, 0x152a, 0x153a, 0x1298, 0x1298, 0x1298,
+	0x1298, 0x153f, 0xa0bc, 0xffa0, 0x00c0, 0x1298, 0x2038, 0xa084,
+	0x001f, 0x0079, 0x125b, 0x1786, 0x1789, 0x1799, 0x1298, 0x1298,
+	0x18d8, 0x18f5, 0x1298, 0x1298, 0x1298, 0x18f9, 0x1901, 0x1298,
+	0x1298, 0x1298, 0x1298, 0x12db, 0x12f4, 0x131f, 0x1356, 0x1668,
+	0x1764, 0x1778, 0x1298, 0x1829, 0x1298, 0x18b4, 0x18be, 0x18c2,
+	0x18d0, 0x1298, 0x1298, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078,
+	0x1286, 0x73ce, 0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x0068,
+	0x1287, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091, 0x5000, 0x00e0,
+	0x128f, 0x00e0, 0x1291, 0x0068, 0x1291, 0x2091, 0x4080, 0x007c,
+	0x70c3, 0x4001, 0x0078, 0x1287, 0x70c3, 0x4006, 0x0078, 0x1287,
+	0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005, 0x53a3, 0x0078,
+	0x1284, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078, 0x1284, 0x0078,
+	0x1284, 0x0078, 0x1284, 0x0078, 0x1284, 0x2091, 0x8000, 0x70c3,
+	0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf, 0x2020, 0x70d3,
+	0x0007, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b, 0x0001, 0x2031,
+	0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051, 0x0470, 0x2061,
+	0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091, 0x5000, 0x2091,
+	0x4080, 0x0078, 0x0455, 0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8,
+	0x74dc, 0x75da, 0x74de, 0x0078, 0x12e8, 0x2029, 0x0000, 0x2520,
+	0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1a70, 0x0040, 0x1284,
+	0x70c3, 0x4002, 0x0078, 0x1284, 0x1078, 0x1b36, 0x00c0, 0x129c,
+	0x75d8, 0x74dc, 0x75da, 0x74de, 0x0078, 0x1301, 0x2029, 0x0000,
+	0x2520, 0x71d0, 0x73c8, 0x72cc, 0x70c4, 0x1078, 0x1ad0, 0x0040,
+	0x1284, 0x70c3, 0x4002, 0x0078, 0x1284, 0x71c4, 0x70c8, 0x2114,
+	0x200a, 0x0078, 0x1282, 0x71c4, 0x2114, 0x0078, 0x1282, 0x70c7,
+	0x0007, 0x70cb, 0x003f, 0x70cf, 0x0000, 0x0078, 0x1284, 0x1078,
+	0x1b36, 0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078,
+	0x132c, 0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d0,
+	0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005, 0x0040, 0x1350, 0x8001,
+	0x7892, 0xa084, 0xfc00, 0x0040, 0x1345, 0x78cc, 0xa085, 0x0001,
+	0x78ce, 0x2001, 0x4005, 0x0078, 0x1286, 0x7a9a, 0x7b9e, 0x7da2,
+	0x7ea6, 0x7c96, 0x78cc, 0xa084, 0xfffc, 0x78ce, 0x0078, 0x1354,
+	0x78cc, 0xa085, 0x0001, 0x78ce, 0x0078, 0x1284, 0x1078, 0x1b36,
+	0x00c0, 0x129c, 0x75d8, 0x76dc, 0x75da, 0x76de, 0x0078, 0x1363,
+	0x2029, 0x0000, 0x2530, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6,
+	0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1387, 0x8001, 0x78ae,
+	0xa084, 0xfc00, 0x0040, 0x137c, 0x78cc, 0xa085, 0x0100, 0x78ce,
+	0x2001, 0x4005, 0x0078, 0x1286, 0x7ab6, 0x7bba, 0x7dbe, 0x7ec2,
+	0x7cb2, 0x78cc, 0xa084, 0xfcff, 0x78ce, 0x0078, 0x138b, 0x78cc,
+	0xa085, 0x0100, 0x78ce, 0x0078, 0x1284, 0x2009, 0x5061, 0x210c,
+	0x7aec, 0x0078, 0x1282, 0x2009, 0x5041, 0x210c, 0x0078, 0x1283,
+	0x2009, 0x5042, 0x210c, 0x0078, 0x1283, 0x2061, 0x5040, 0x610c,
+	0x6210, 0x0078, 0x1282, 0x2009, 0x5045, 0x210c, 0x0078, 0x1283,
+	0x2009, 0x5046, 0x210c, 0x0078, 0x1283, 0x2009, 0x5048, 0x210c,
+	0x0078, 0x1283, 0x2009, 0x5049, 0x210c, 0x0078, 0x1283, 0x7908,
+	0x7a0c, 0x0078, 0x1282, 0x71c4, 0x8107, 0xa084, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa0e8, 0x5280, 0x6a00, 0x6804, 0xa084, 0x0008,
+	0x0040, 0x13cd, 0x6b08, 0x0078, 0x13ce, 0x6b0c, 0x0078, 0x1281,
+	0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6b1c, 0x6a14, 0x2091,
+	0x8001, 0x2708, 0x0078, 0x1281, 0x794c, 0x0078, 0x1283, 0x77c4,
+	0x1078, 0x1956, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091,
+	0x8001, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x127c,
+	0x1078, 0x22c1, 0x0078, 0x1281, 0x71c4, 0xa182, 0x0010, 0x00c8,
+	0x127c, 0x2011, 0x5041, 0x2204, 0x007e, 0x2112, 0x1078, 0x227a,
+	0x017f, 0x0078, 0x1283, 0x71c4, 0x2011, 0x1421, 0x20a9, 0x0008,
+	0x2204, 0xa106, 0x0040, 0x1413, 0x8210, 0x0070, 0x1411, 0x0078,
+	0x1408, 0x0078, 0x127c, 0xa292, 0x1421, 0x027e, 0x2011, 0x5042,
+	0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x2286, 0x017f, 0x0078,
+	0x1283, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032,
+	0x004b, 0x2061, 0x5040, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8,
+	0x6012, 0x0078, 0x1282, 0x2061, 0x5040, 0x6114, 0x70c4, 0x6016,
+	0x0078, 0x1283, 0x2061, 0x5040, 0x71c4, 0x2011, 0x0004, 0x601f,
+	0x0019, 0x2019, 0x1212, 0xa186, 0x0028, 0x0040, 0x145b, 0x2011,
+	0x0005, 0x601f, 0x0019, 0x2019, 0x1212, 0xa186, 0x0032, 0x0040,
+	0x145b, 0x2011, 0x0006, 0x601f, 0x000c, 0x2019, 0x2222, 0xa186,
+	0x003c, 0x00c0, 0x127c, 0x6018, 0x007e, 0x611a, 0x7800, 0xa084,
+	0x0001, 0x00c0, 0x1476, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+	0x0048, 0x146e, 0x0038, 0x1472, 0x0078, 0x1476, 0x0028, 0x1472,
+	0x0078, 0x1476, 0x2019, 0x2222, 0x0078, 0x1478, 0x2019, 0x1212,
+	0x23b8, 0x1078, 0x2297, 0x1078, 0x4bdf, 0x017f, 0x0078, 0x1283,
+	0x71c4, 0xa184, 0xffcf, 0x00c0, 0x127c, 0x2011, 0x5048, 0x2204,
+	0x2112, 0x007e, 0x1078, 0x22b9, 0x017f, 0x0078, 0x1283, 0x71c4,
+	0xa182, 0x0010, 0x00c8, 0x127c, 0x2011, 0x5049, 0x2204, 0x007e,
+	0x2112, 0x1078, 0x22a8, 0x017f, 0x0078, 0x1283, 0x71c4, 0x72c8,
+	0xa184, 0xfffd, 0x00c0, 0x127b, 0xa284, 0xfffd, 0x00c0, 0x127b,
+	0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x1282,
+	0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8,
+	0x5280, 0x2019, 0x0000, 0x72c8, 0xa284, 0x0080, 0x0040, 0x14c6,
+	0x6c14, 0x84ff, 0x00c0, 0x14c6, 0x6817, 0x0040, 0xa284, 0x0040,
+	0x0040, 0x14d0, 0x6c10, 0x84ff, 0x00c0, 0x14d0, 0x6813, 0x0001,
+	0x6800, 0x007e, 0xa226, 0x0040, 0x14f3, 0x6a02, 0xa484, 0x2000,
+	0x0040, 0x14dc, 0xa39d, 0x0010, 0xa484, 0x1000, 0x0040, 0x14e2,
+	0xa39d, 0x0008, 0xa484, 0x4000, 0x0040, 0x14f3, 0x810f, 0xa284,
+	0x4000, 0x0040, 0x14ef, 0x1078, 0x22db, 0x0078, 0x14f3, 0x1078,
+	0x22cd, 0x0078, 0x14f3, 0x72cc, 0x6808, 0xa206, 0x0040, 0x1522,
+	0xa2a4, 0x00ff, 0x2061, 0x5040, 0x6118, 0xa186, 0x0028, 0x0040,
+	0x1509, 0xa186, 0x0032, 0x0040, 0x150f, 0xa186, 0x003c, 0x0040,
+	0x1515, 0xa482, 0x0064, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482,
+	0x0050, 0x0048, 0x151f, 0x0078, 0x1519, 0xa482, 0x0043, 0x0048,
+	0x151f, 0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x127d, 0x6a0a,
+	0xa39d, 0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4,
+	0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a14,
+	0x6b1c, 0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708,
+	0x0078, 0x1281, 0x70c4, 0x794c, 0x784e, 0x0078, 0x1283, 0x71c4,
+	0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x127c, 0x1078, 0x22e9,
+	0x0078, 0x1281, 0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08,
+	0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+	0x77c4, 0x1078, 0x1956, 0x2091, 0x8000, 0x6a08, 0xa294, 0xfff9,
+	0x6a0a, 0x6804, 0xa005, 0x0040, 0x1567, 0x1078, 0x21b1, 0x2091,
+	0x8001, 0x2708, 0x0078, 0x1282, 0x77c4, 0x1078, 0x1956, 0x2091,
+	0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804, 0xa005, 0x0040,
+	0x157b, 0x1078, 0x21b1, 0x2091, 0x8001, 0x2708, 0x0078, 0x1282,
+	0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091,
+	0x8000, 0x1078, 0x1963, 0x2091, 0x8001, 0x2708, 0x6a08, 0x0078,
+	0x1282, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca, 0x73ce, 0x1078,
+	0x19c4, 0x00c0, 0x15a9, 0x6818, 0xa005, 0x0040, 0x15a9, 0x2708,
+	0x1078, 0x22f9, 0x00c0, 0x15a9, 0x7817, 0x0015, 0x2091, 0x8001,
+	0x007c, 0x2091, 0x8001, 0x0078, 0x1284, 0x77c4, 0x77c6, 0x2041,
+	0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
+	0x1963, 0x2061, 0x5040, 0x606f, 0x0003, 0x6782, 0x6093, 0x000f,
+	0x6073, 0x0000, 0x7817, 0x0016, 0x1078, 0x21b1, 0x2091, 0x8001,
+	0x007c, 0x77c8, 0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091,
+	0x8000, 0x2061, 0x5040, 0x606f, 0x0002, 0x6073, 0x0000, 0x6782,
+	0x6093, 0x000f, 0x7817, 0x0017, 0x1078, 0x21b1, 0x2091, 0x8001,
+	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0010, 0x2091, 0x8000,
+	0x1078, 0x1963, 0x70c8, 0x6836, 0x8738, 0xa784, 0x001f, 0x00c0,
+	0x15e8, 0x2091, 0x8001, 0x007c, 0x78cc, 0xa084, 0x0003, 0x00c0,
+	0x1618, 0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051,
+	0x0008, 0x1078, 0x1956, 0x2091, 0x8000, 0x6808, 0xa80d, 0x690a,
+	0x2091, 0x8001, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1601, 0xa7bc,
+	0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1601,
+	0x2091, 0x8000, 0x2069, 0x0100, 0x6830, 0xa084, 0x0040, 0x0040,
+	0x1641, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004,
+	0x0040, 0x162e, 0x0070, 0x162e, 0x0078, 0x1625, 0x684b, 0x0009,
+	0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x163b, 0x0070,
+	0x163b, 0x0078, 0x1632, 0x20a9, 0x00fa, 0x0070, 0x1641, 0x0078,
+	0x163d, 0x2079, 0x5000, 0x7817, 0x0018, 0x2061, 0x5040, 0x606f,
+	0x0001, 0x6073, 0x0000, 0x6093, 0x000f, 0x78cc, 0xa085, 0x0002,
+	0x78ce, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2091,
+	0x8001, 0x007c, 0x78cc, 0xa084, 0xfffd, 0x78ce, 0xa084, 0x0001,
+	0x00c0, 0x1664, 0x1078, 0x1a0e, 0x71c4, 0x71c6, 0x794a, 0x007c,
+	0x1078, 0x1b36, 0x00c0, 0x129c, 0x75d8, 0x74dc, 0x75da, 0x74de,
+	0x0078, 0x1675, 0x2029, 0x0000, 0x2520, 0x71c4, 0x73c8, 0x72cc,
+	0x71c6, 0x73ca, 0x72ce, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078,
+	0x1911, 0x2091, 0x8001, 0x0040, 0x172c, 0x20a9, 0x0005, 0x20a1,
+	0x5018, 0x2091, 0x8000, 0x41a1, 0x2091, 0x8001, 0x2009, 0x0020,
+	0x1078, 0x190c, 0x0040, 0x1698, 0x1078, 0x192b, 0x0078, 0x172c,
+	0x6004, 0xa084, 0xff00, 0x8007, 0x8009, 0x0040, 0x16fb, 0x0c7e,
+	0x2c68, 0x2091, 0x8000, 0x1078, 0x1911, 0x2091, 0x8001, 0x0040,
+	0x16cc, 0x2c00, 0x689e, 0x8109, 0x00c0, 0x16a0, 0x609f, 0x0000,
+	0x0c7f, 0x0c7e, 0x7218, 0x731c, 0x7420, 0x7524, 0x2c68, 0x689c,
+	0xa065, 0x0040, 0x16fa, 0x2009, 0x0020, 0x1078, 0x190c, 0x00c0,
+	0x16e3, 0x6004, 0xa084, 0x00ff, 0xa086, 0x0002, 0x00c0, 0x16cc,
+	0x2d00, 0x6002, 0x0078, 0x16b2, 0x0c7f, 0x0c7e, 0x609c, 0x2060,
+	0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009,
+	0x000c, 0x6008, 0xa085, 0x0200, 0x600a, 0x1078, 0x1907, 0x1078,
+	0x192b, 0x0078, 0x172c, 0x0c7f, 0x0c7e, 0x609c, 0x2060, 0x1078,
+	0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078, 0x1730, 0x2009, 0x000c,
+	0x6007, 0x0103, 0x601b, 0x0003, 0x1078, 0x1907, 0x1078, 0x192b,
+	0x0078, 0x172c, 0x0c7f, 0x74c4, 0x73c8, 0x72cc, 0x6014, 0x2091,
+	0x8000, 0x7817, 0x0012, 0x0e7e, 0x2071, 0x5040, 0x706f, 0x0005,
+	0x7073, 0x0000, 0x7376, 0x727a, 0x747e, 0x7082, 0x7087, 0x0000,
+	0x2c00, 0x708a, 0x708f, 0x0000, 0xa02e, 0x2530, 0x611c, 0x61a2,
+	0xa184, 0x0060, 0x0040, 0x171e, 0x1078, 0x467f, 0x0e7f, 0x6596,
+	0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3, 0x0000, 0x1078,
+	0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078, 0x1287,
+	0x20a9, 0x0005, 0x2099, 0x5018, 0x2091, 0x8000, 0x530a, 0x2091,
+	0x8001, 0x2100, 0xa210, 0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9,
+	0x0000, 0x007c, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x1284,
+	0x71c4, 0x71c6, 0x2168, 0x0078, 0x174f, 0x2069, 0x1000, 0x690c,
+	0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1751, 0xa285,
+	0x0000, 0x00c0, 0x175f, 0x70c3, 0x4000, 0x0078, 0x1761, 0x70c3,
+	0x4003, 0x70ca, 0x0078, 0x1287, 0x2011, 0x5067, 0x220c, 0x70c4,
+	0x8003, 0x0048, 0x1771, 0x1078, 0x3b49, 0xa184, 0x7fff, 0x0078,
+	0x1775, 0x1078, 0x3b3c, 0xa185, 0x8000, 0x2012, 0x0078, 0x1283,
+	0x71c4, 0x1078, 0x3b33, 0x6100, 0x2001, 0x5067, 0x2004, 0xa084,
+	0x8000, 0xa10d, 0x6204, 0x6308, 0x0078, 0x1281, 0x79e4, 0x0078,
+	0x1283, 0x71c4, 0x71c6, 0x2198, 0x20a1, 0x0042, 0x20a9, 0x0004,
+	0x53a3, 0x21a0, 0x2099, 0x0042, 0x20a9, 0x0004, 0x53a3, 0x0078,
+	0x1284, 0x70c4, 0x2068, 0x2079, 0x5000, 0x2091, 0x8000, 0x1078,
+	0x1911, 0x2091, 0x8001, 0x0040, 0x1825, 0x6007, 0x0001, 0x600b,
+	0x0000, 0x602b, 0x0000, 0x601b, 0x0006, 0x6a10, 0xa28c, 0x000f,
+	0xa284, 0x00f0, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0x6016,
+	0xa284, 0x0800, 0x0040, 0x17c0, 0x601b, 0x000a, 0x0078, 0x17c6,
+	0xa284, 0x1000, 0x0040, 0x17c6, 0x601b, 0x000c, 0xa284, 0x0300,
+	0x0040, 0x17cf, 0x602b, 0x0001, 0x8004, 0x8004, 0x8004, 0xa085,
+	0x0001, 0x601e, 0x6023, 0x0000, 0x6027, 0x0000, 0xa284, 0x0400,
+	0x0040, 0x17dc, 0x602b, 0x0000, 0x20a9, 0x0006, 0xac80, 0x000b,
+	0x20a0, 0xad80, 0x0005, 0x2098, 0x53a3, 0xa284, 0x0300, 0x00c0,
+	0x17f1, 0x6046, 0x604a, 0x604e, 0x6052, 0x6096, 0x609a, 0x0078,
+	0x17fb, 0x6800, 0x6046, 0x6804, 0x604a, 0x6e08, 0x664e, 0x6d0c,
+	0x6552, 0x6596, 0x669a, 0x6014, 0x2091, 0x8000, 0x7817, 0x0042,
+	0x2c08, 0x2061, 0x5040, 0x606f, 0x0005, 0x6073, 0x0000, 0x6077,
+	0x0000, 0x607b, 0x0000, 0x607f, 0x0000, 0x6082, 0x618a, 0xa284,
+	0x0400, 0x608e, 0x2091, 0x8001, 0x0e7e, 0x2071, 0x0020, 0x7007,
+	0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x0e7f, 0x2091, 0x8000,
+	0x1078, 0x21b1, 0x2091, 0x8001, 0x007c, 0x70c3, 0x4005, 0x0078,
+	0x1287, 0x0c7e, 0x0d7e, 0x0e7e, 0x0f7e, 0x2091, 0x8000, 0x2071,
+	0x5040, 0x2079, 0x0100, 0x2061, 0x0010, 0x70a0, 0xa06d, 0x0040,
+	0x18aa, 0x6a04, 0xa294, 0x00ff, 0xa286, 0x0007, 0x0040, 0x1844,
+	0xa286, 0x000f, 0x00c0, 0x18aa, 0x691c, 0xa184, 0x0080, 0x00c0,
+	0x18aa, 0x6824, 0xa18c, 0xff00, 0xa085, 0x0019, 0x6826, 0x71b0,
+	0x81ff, 0x0040, 0x1865, 0x0d7e, 0x2069, 0x0020, 0x6908, 0x6808,
+	0xa106, 0x00c0, 0x1856, 0x690c, 0x680c, 0xa106, 0x00c0, 0x185b,
+	0xa184, 0x00ff, 0x00c0, 0x185b, 0x0d7f, 0x78b8, 0xa084, 0x801f,
+	0x00c0, 0x1865, 0x7848, 0xa085, 0x000c, 0x784a, 0x71b0, 0x81ff,
+	0x0040, 0x1888, 0x70b3, 0x0000, 0x0d7e, 0x2069, 0x0020, 0x6807,
+	0x0008, 0x6804, 0xa084, 0x0008, 0x00c0, 0x1879, 0x6807, 0x0008,
+	0x6804, 0xa084, 0x0008, 0x00c0, 0x1880, 0x6807, 0x0002, 0x0d7f,
+	0x61c4, 0x62c8, 0x63cc, 0x61c6, 0x62ca, 0x63ce, 0x0e7e, 0x2071,
+	0x5000, 0x7266, 0x736a, 0xae80, 0x0019, 0x0e7f, 0x1078, 0x4598,
+	0x78a3, 0x0000, 0x7858, 0xa084, 0xedff, 0x785a, 0x70b4, 0xa080,
+	0x00da, 0x781a, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001,
+	0x0078, 0x1284, 0x0f7f, 0x0e7f, 0x0d7f, 0x0c7f, 0x2091, 0x8001,
+	0x2001, 0x4005, 0x0078, 0x1286, 0x7980, 0x71c6, 0x71c4, 0xa182,
+	0x0003, 0x00c8, 0x127c, 0x7982, 0x0078, 0x1284, 0x7980, 0x71c6,
+	0x0078, 0x1284, 0x7974, 0x71c6, 0x71c4, 0x7976, 0x7978, 0x71ca,
+	0x71c8, 0x797a, 0x797c, 0x71ce, 0x71cc, 0x797e, 0x0078, 0x1284,
+	0x7974, 0x71c6, 0x7978, 0x71ca, 0x797c, 0x71ce, 0x0078, 0x1284,
+	0x7900, 0x71c6, 0x71c4, 0x7902, 0x2001, 0x04fd, 0x2004, 0xa082,
+	0x0005, 0x0048, 0x18e7, 0x0038, 0x18e9, 0x0078, 0x18f3, 0x00a8,
+	0x18f3, 0xa18c, 0x0001, 0x00c0, 0x18f1, 0x20b9, 0x2222, 0x0078,
+	0x18f3, 0x20b9, 0x1212, 0x0078, 0x1284, 0x7900, 0x71c6, 0x0078,
+	0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x70c4, 0x200a, 0x0078,
+	0x1284, 0x2009, 0x5074, 0x2104, 0x70c6, 0x0078, 0x1284, 0xac80,
+	0x0001, 0x1078, 0x1af2, 0x007c, 0xac80, 0x0001, 0x1078, 0x1a92,
+	0x007c, 0x7850, 0xa065, 0x0040, 0x1919, 0x2c04, 0x7852, 0x2063,
+	0x0000, 0x007c, 0x0f7e, 0x2079, 0x5000, 0x7850, 0xa06d, 0x0040,
+	0x1929, 0x2d04, 0x7852, 0x6803, 0x0000, 0x6807, 0x0000, 0x680b,
+	0x0000, 0x0f7f, 0x007c, 0x2091, 0x8000, 0x0f7e, 0x2079, 0x5000,
+	0x7850, 0x2062, 0x2c00, 0xa005, 0x00c0, 0x1938, 0x1078, 0x23ca,
+	0x7852, 0x0f7f, 0x2091, 0x8001, 0x007c, 0x0f7e, 0x2079, 0x5000,
+	0x7850, 0x206a, 0x2d00, 0x7852, 0x0f7f, 0x007c, 0x2011, 0x7700,
+	0x7a52, 0x7bec, 0x8319, 0x0040, 0x1953, 0xa280, 0x0031, 0x2012,
+	0x2010, 0x0078, 0x194a, 0x2013, 0x0000, 0x007c, 0xa784, 0x0f00,
+	0x800b, 0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105,
+	0xa0e8, 0x5300, 0x007c, 0x1078, 0x1956, 0x2900, 0x682a, 0x2a00,
+	0x682e, 0x6808, 0xa084, 0xffef, 0xa80d, 0x690a, 0x2009, 0x5052,
+	0x210c, 0x6804, 0xa005, 0x0040, 0x1995, 0xa116, 0x00c0, 0x1980,
+	0x2060, 0x6000, 0x6806, 0x017e, 0x200b, 0x0000, 0x0078, 0x1983,
+	0x2009, 0x0000, 0x017e, 0x6804, 0xa065, 0x0040, 0x1992, 0x6000,
+	0x6806, 0x1078, 0x19a3, 0x1078, 0x1c42, 0x6810, 0x8001, 0x6812,
+	0x00c0, 0x1983, 0x017f, 0x6902, 0x6906, 0x007c, 0xa065, 0x0040,
+	0x19a2, 0x609c, 0x609f, 0x0000, 0x2008, 0x1078, 0x192b, 0x2100,
+	0x0078, 0x1996, 0x007c, 0x6007, 0x0103, 0x608f, 0x0000, 0x20a9,
+	0x001c, 0xac80, 0x0005, 0x20a0, 0x2001, 0x0000, 0x40a4, 0x6828,
+	0x601a, 0x682c, 0x6022, 0x007c, 0x0e7e, 0x2071, 0x5040, 0x704c,
+	0xa08c, 0x0200, 0x00c0, 0x19c2, 0xa088, 0x5080, 0x2d0a, 0x8000,
+	0x704e, 0xa006, 0x0e7f, 0x007c, 0x1078, 0x1956, 0x2091, 0x8000,
+	0x6804, 0x781e, 0xa065, 0x0040, 0x1a0d, 0x0078, 0x19d5, 0x2c00,
+	0x781e, 0x6000, 0xa065, 0x0040, 0x1a0d, 0x600c, 0xa306, 0x00c0,
+	0x19cf, 0x6010, 0xa206, 0x00c0, 0x19cf, 0x2c28, 0x2001, 0x5052,
+	0x2004, 0xac06, 0x00c0, 0x19e6, 0x0078, 0x1a0b, 0x6804, 0xac06,
+	0x00c0, 0x19f3, 0x6000, 0xa065, 0x6806, 0x00c0, 0x19fd, 0x6803,
+	0x0000, 0x0078, 0x19fd, 0x6400, 0x781c, 0x2060, 0x6402, 0xa486,
+	0x0000, 0x00c0, 0x19fd, 0x2c00, 0x6802, 0x2560, 0x1078, 0x19a3,
+	0x601b, 0x0005, 0x6023, 0x0020, 0x1078, 0x1c42, 0x6810, 0x8001,
+	0x1050, 0x23ca, 0x6812, 0xa085, 0xffff, 0x007c, 0x2039, 0x0000,
+	0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x2091, 0x8000,
+	0x1078, 0x1963, 0x8738, 0xa784, 0x001f, 0x00c0, 0x1a18, 0xa7bc,
+	0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00, 0x00c0, 0x1a18,
+	0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018, 0xa084, 0x0001,
+	0x00c0, 0x1a3c, 0x2091, 0x8000, 0x78e0, 0x78e3, 0x0000, 0x2091,
+	0x8001, 0xa005, 0x00c0, 0x1a3d, 0x007c, 0xa08c, 0xfff0, 0x0040,
+	0x1a43, 0x1078, 0x23ca, 0x0079, 0x1a45, 0x1a55, 0x1a58, 0x1a5e,
+	0x1a62, 0x1a56, 0x1a66, 0x1a6c, 0x1a56, 0x1a56, 0x1c0c, 0x1c30,
+	0x1c34, 0x1a56, 0x1a56, 0x1a56, 0x1a56, 0x007c, 0x1078, 0x23ca,
+	0x1078, 0x1a0e, 0x2001, 0x8001, 0x0078, 0x1c3a, 0x2001, 0x8003,
+	0x0078, 0x1c3a, 0x2001, 0x8004, 0x0078, 0x1c3a, 0x1078, 0x1a0e,
+	0x2001, 0x8006, 0x0078, 0x1c3a, 0x2001, 0x8007, 0x0078, 0x1c3a,
+	0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1a78, 0x2009, 0x0020,
+	0x2600, 0x1078, 0x1a92, 0x00c0, 0x1a91, 0xa7ba, 0x0020, 0x0048,
+	0x1a90, 0x0040, 0x1a90, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040,
+	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1a72,
+	0xa006, 0x007c, 0x81ff, 0x0040, 0x1acd, 0x2099, 0x0030, 0x20a0,
+	0x700c, 0xa084, 0x00ff, 0x0040, 0x1aa4, 0x7007, 0x0004, 0x7004,
+	0xa084, 0x0004, 0x00c0, 0x1a9f, 0x21a8, 0x7017, 0x0000, 0x810b,
+	0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0001,
+	0x7002, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005,
+	0x00c8, 0x1ac1, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000, 0x00c0,
+	0x1ab3, 0x7008, 0x800b, 0x00c8, 0x1ab3, 0x7007, 0x0002, 0xa08c,
+	0x01e0, 0x00c0, 0x1acd, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c,
+	0x2030, 0x2138, 0xa782, 0x0021, 0x0048, 0x1ad8, 0x2009, 0x0020,
+	0x2600, 0x1078, 0x1af2, 0x00c0, 0x1af1, 0xa7ba, 0x0020, 0x0048,
+	0x1af0, 0x0040, 0x1af0, 0x2708, 0xa6b0, 0x0020, 0xa290, 0x0040,
+	0xa399, 0x0000, 0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x0078, 0x1ad2,
+	0xa006, 0x007c, 0x81ff, 0x0040, 0x1b33, 0x2098, 0x20a1, 0x0030,
+	0x700c, 0xa084, 0x00ff, 0x0040, 0x1b04, 0x7007, 0x0004, 0x7004,
+	0xa084, 0x0004, 0x00c0, 0x1aff, 0x21a8, 0x7017, 0x0000, 0x810b,
+	0x7112, 0x721a, 0x731e, 0x7422, 0x7526, 0x780c, 0xa085, 0x0000,
+	0x7002, 0x53a6, 0x7007, 0x0001, 0x2001, 0x04fd, 0x2004, 0xa082,
+	0x0005, 0x00c8, 0x1b22, 0x2009, 0x0022, 0x2104, 0xa084, 0x4000,
+	0x00c0, 0x1b14, 0x7010, 0xa084, 0xf000, 0x0040, 0x1b2b, 0x7007,
+	0x0008, 0x0078, 0x1b2f, 0x7108, 0x8103, 0x00c8, 0x1b14, 0x7007,
+	0x0002, 0xa184, 0x01e0, 0x7003, 0x0000, 0x007c, 0x2001, 0x04fd,
+	0x2004, 0xa082, 0x0004, 0x00c8, 0x1b3f, 0x0078, 0x1b42, 0xa006,
+	0x0078, 0x1b44, 0xa085, 0x0001, 0x007c, 0x0e7e, 0x2071, 0x5000,
+	0x2d08, 0x7058, 0x6802, 0xa005, 0x00c0, 0x1b4f, 0x715e, 0x715a,
+	0x0e7f, 0x007c, 0x2c08, 0x7858, 0x6002, 0xa005, 0x00c0, 0x1b59,
+	0x795e, 0x795a, 0x007c, 0x2091, 0x8000, 0x6003, 0x0000, 0x2c08,
+	0x785c, 0xa065, 0x00c0, 0x1b67, 0x795a, 0x0078, 0x1b68, 0x6102,
+	0x795e, 0x2091, 0x8001, 0x1078, 0x21ce, 0x007c, 0x0e7e, 0x2071,
+	0x5000, 0x7058, 0xa06d, 0x0040, 0x1b7c, 0x6800, 0x705a, 0xa005,
+	0x00c0, 0x1b7b, 0x705e, 0x8dff, 0x0e7f, 0x007c, 0x0d7e, 0x0c7e,
+	0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060, 0x6000, 0xa005,
+	0x0040, 0x1bac, 0x2068, 0x6814, 0xa306, 0x00c0, 0x1b95, 0x6828,
+	0xa084, 0x00ff, 0xa406, 0x0040, 0x1b98, 0x2d60, 0x0078, 0x1b86,
+	0x6800, 0xa005, 0x6002, 0x00c0, 0x1ba4, 0xaf80, 0x0016, 0xac06,
+	0x0040, 0x1ba3, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040,
+	0x1bab, 0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005,
+	0x007c, 0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016,
+	0x2060, 0x6000, 0xa005, 0x0040, 0x1bdb, 0x2068, 0x6814, 0xa084,
+	0x00ff, 0xa306, 0x0040, 0x1bc7, 0x2d60, 0x0078, 0x1bb9, 0x6800,
+	0xa005, 0x6002, 0x00c0, 0x1bd3, 0xaf80, 0x0016, 0xac06, 0x0040,
+	0x1bd2, 0x2c00, 0x785e, 0x0d7e, 0x689c, 0xa005, 0x0040, 0x1bda,
+	0x1078, 0x1996, 0x007f, 0x0f7f, 0x0c7f, 0x0d7f, 0xa005, 0x007c,
+	0x0d7e, 0x0c7e, 0x0f7e, 0x2079, 0x5000, 0xaf80, 0x0016, 0x2060,
+	0x6000, 0xa06d, 0x0040, 0x1c07, 0x6814, 0xa306, 0x0040, 0x1bf3,
+	0x2d60, 0x0078, 0x1be8, 0x6800, 0xa005, 0x6002, 0x00c0, 0x1bff,
+	0xaf80, 0x0016, 0xac06, 0x0040, 0x1bfe, 0x2c00, 0x785e, 0x0d7e,
+	0x689c, 0xa005, 0x0040, 0x1c06, 0x1078, 0x1996, 0x007f, 0x0f7f,
+	0x0c7f, 0x0d7f, 0xa005, 0x007c, 0x2091, 0x8000, 0x2069, 0x5040,
+	0x6800, 0xa086, 0x0000, 0x0040, 0x1c1a, 0x2091, 0x8001, 0x78e3,
+	0x0009, 0x007c, 0x6880, 0xa0bc, 0xff00, 0x2041, 0x0021, 0x2049,
+	0x0004, 0x2051, 0x0010, 0x1078, 0x1963, 0x8738, 0xa784, 0x001f,
+	0x00c0, 0x1c23, 0x2091, 0x8001, 0x2001, 0x800a, 0x0078, 0x1c3a,
+	0x2001, 0x800c, 0x0078, 0x1c3a, 0x1078, 0x1a0e, 0x2001, 0x800d,
+	0x0078, 0x1c3a, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001, 0x2091,
+	0x4080, 0x007c, 0x6004, 0x2c08, 0x2063, 0x0000, 0x7884, 0x8000,
+	0x7886, 0x7888, 0xa005, 0x798a, 0x0040, 0x1c51, 0x2c02, 0x0078,
+	0x1c52, 0x798e, 0x007c, 0x6807, 0x0103, 0x0c7e, 0x2061, 0x5000,
+	0x2d08, 0x206b, 0x0000, 0x6084, 0x8000, 0x6086, 0x6088, 0xa005,
+	0x618a, 0x0040, 0x1c66, 0x2d02, 0x0078, 0x1c67, 0x618e, 0x0c7f,
+	0x007c, 0x1078, 0x1c7a, 0x0040, 0x1c79, 0x0c7e, 0x609c, 0xa065,
+	0x0040, 0x1c74, 0x1078, 0x1996, 0x0c7f, 0x609f, 0x0000, 0x1078,
+	0x192b, 0x007c, 0x788c, 0xa065, 0x0040, 0x1c8c, 0x2091, 0x8000,
+	0x7884, 0x8001, 0x7886, 0x2c04, 0x788e, 0xa005, 0x00c0, 0x1c8a,
+	0x788a, 0x8000, 0x2091, 0x8001, 0x007c, 0x20a9, 0x0010, 0xa006,
+	0x8004, 0x8086, 0x818e, 0x00c8, 0x1c96, 0xa200, 0x0070, 0x1c9a,
+	0x0078, 0x1c91, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9, 0x0010,
+	0xa005, 0x0040, 0x1cc0, 0xa11a, 0x00c8, 0x1cc0, 0x8213, 0x818d,
+	0x0048, 0x1cb1, 0xa11a, 0x00c8, 0x1cb2, 0x0070, 0x1cb8, 0x0078,
+	0x1ca6, 0xa11a, 0x2308, 0x8210, 0x0070, 0x1cb8, 0x0078, 0x1ca6,
+	0x007e, 0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c,
+	0x007e, 0x3200, 0xa085, 0x0800, 0x0078, 0x1cbc, 0x7994, 0x70d0,
+	0xa106, 0x0040, 0x1d34, 0x2091, 0x8000, 0x2071, 0x0020, 0x7004,
+	0xa005, 0x00c0, 0x1d34, 0x7008, 0x7208, 0xa206, 0x00c0, 0x1d34,
+	0xa286, 0x0008, 0x00c0, 0x1d34, 0x2071, 0x0010, 0x1078, 0x1911,
+	0x0040, 0x1d34, 0x7a9c, 0x7b98, 0x7ca4, 0x7da0, 0xa184, 0xff00,
+	0x0040, 0x1d02, 0x2031, 0x0000, 0x810b, 0x86b5, 0x810b, 0x86b5,
+	0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5, 0x810b, 0x86b5,
+	0x2100, 0xa210, 0x2600, 0xa319, 0xa4a1, 0x0000, 0xa5a9, 0x0000,
+	0x0078, 0x1d0c, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000,
+	0xa4a1, 0x0000, 0xa5a9, 0x0000, 0x2009, 0x0020, 0x1078, 0x190c,
+	0x2091, 0x8001, 0x0040, 0x1d2b, 0x1078, 0x192b, 0x78a8, 0x8000,
+	0x78aa, 0xa086, 0x0002, 0x00c0, 0x1d34, 0x2091, 0x8000, 0x78e3,
+	0x0002, 0x78ab, 0x0000, 0x78cc, 0xa085, 0x0003, 0x78ce, 0x2091,
+	0x8001, 0x0078, 0x1d34, 0x78ab, 0x0000, 0x1078, 0x208b, 0x6004,
+	0xa084, 0x000f, 0x0079, 0x1d39, 0x2071, 0x0010, 0x2091, 0x8001,
+	0x007c, 0x1d49, 0x1d6b, 0x1d91, 0x1d49, 0x1dae, 0x1d58, 0x1f0d,
+	0x1f28, 0x1d49, 0x1d65, 0x1d8b, 0x1df6, 0x1e63, 0x1eb3, 0x1ec5,
+	0x1f24, 0x2039, 0x0400, 0x78dc, 0xa705, 0x78de, 0x6008, 0xa705,
+	0x600a, 0x1078, 0x1fa6, 0x609c, 0x78da, 0x1078, 0x2073, 0x007c,
+	0x78dc, 0xa084, 0x0100, 0x0040, 0x1d5f, 0x0078, 0x1d49, 0x601c,
+	0xa085, 0x0080, 0x601e, 0x0078, 0x1d72, 0x1078, 0x1b36, 0x00c0,
+	0x1d49, 0x1078, 0x20a5, 0x78dc, 0xa084, 0x0100, 0x0040, 0x1d72,
+	0x0078, 0x1d49, 0x78df, 0x0000, 0x6004, 0x8007, 0xa084, 0x00ff,
+	0x78d2, 0x8001, 0x609f, 0x0000, 0x0040, 0x1d88, 0x1078, 0x1fa6,
+	0x0040, 0x1d88, 0x78dc, 0xa085, 0x0100, 0x78de, 0x0078, 0x1d8a,
+	0x1078, 0x1fca, 0x007c, 0x1078, 0x1b36, 0x00c0, 0x1d49, 0x1078,
+	0x20a1, 0x78dc, 0xa08c, 0x0e00, 0x00c0, 0x1d9a, 0xa084, 0x0100,
+	0x00c0, 0x1d9c, 0x0078, 0x1d49, 0x1078, 0x1fa6, 0x00c0, 0x1dad,
+	0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x1f63, 0xa186,
+	0x000f, 0x0040, 0x1f63, 0x1078, 0x1fca, 0x007c, 0x78dc, 0xa084,
+	0x0100, 0x0040, 0x1db5, 0x0078, 0x1d49, 0x78df, 0x0000, 0x6714,
+	0x2011, 0x0001, 0x20a9, 0x0001, 0x6018, 0xa084, 0x00ff, 0xa005,
+	0x0040, 0x1dd8, 0x2011, 0x0001, 0xa7bc, 0xff00, 0x20a9, 0x0020,
+	0xa08e, 0x0001, 0x0040, 0x1dd8, 0x2039, 0x0000, 0x2011, 0x0002,
+	0x20a9, 0x0100, 0xa08e, 0x0002, 0x0040, 0x1dd8, 0x0078, 0x1df3,
+	0x1078, 0x1956, 0x2091, 0x8000, 0x682b, 0x0000, 0x682f, 0x0000,
+	0x6808, 0xa084, 0xffde, 0x680a, 0xade8, 0x0010, 0x2091, 0x8001,
+	0x0070, 0x1dec, 0x0078, 0x1dda, 0x8211, 0x0040, 0x1df3, 0x20a9,
+	0x0100, 0x0078, 0x1dda, 0x1078, 0x192b, 0x007c, 0x2001, 0x5067,
+	0x2004, 0xa084, 0x8000, 0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2,
+	0x6900, 0xa184, 0x0001, 0x0040, 0x1e17, 0x6028, 0xa084, 0x00ff,
+	0x00c0, 0x1f83, 0x6800, 0xa084, 0x0001, 0x0040, 0x1f8b, 0x6803,
+	0x0000, 0x680b, 0x0000, 0x6807, 0x0000, 0x0078, 0x1f93, 0x2011,
+	0x0001, 0x6020, 0xa084, 0x4000, 0x0040, 0x1e20, 0xa295, 0x0002,
+	0x6020, 0xa084, 0x0100, 0x0040, 0x1e27, 0xa295, 0x0008, 0x601c,
+	0xa084, 0x0002, 0x0040, 0x1e2e, 0xa295, 0x0004, 0x602c, 0xa08c,
+	0x00ff, 0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8,
+	0x1f8f, 0x0040, 0x1f8f, 0x690e, 0x602c, 0x8007, 0xa08c, 0x00ff,
+	0xa182, 0x0002, 0x0048, 0x1f8f, 0xa182, 0x001b, 0x00c8, 0x1f8f,
+	0x0040, 0x1f8f, 0x6912, 0x6030, 0xa005, 0x00c0, 0x1e51, 0x2001,
+	0x001e, 0x8000, 0x6816, 0x6028, 0xa084, 0x00ff, 0x0040, 0x1f8b,
+	0x6806, 0x6028, 0x8007, 0xa084, 0x00ff, 0x0040, 0x1f8b, 0x680a,
+	0x6a02, 0x0078, 0x1f93, 0x2001, 0x5067, 0x2004, 0xa084, 0x8000,
+	0x0040, 0x1f8b, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000, 0x6a04,
+	0x6b08, 0x6418, 0xa484, 0x0003, 0x0040, 0x1e89, 0x6128, 0xa18c,
+	0x00ff, 0x8001, 0x00c0, 0x1e82, 0x2100, 0xa210, 0x0048, 0x1eaf,
+	0x0078, 0x1e89, 0x8001, 0x00c0, 0x1eaf, 0x2100, 0xa212, 0x0048,
+	0x1eaf, 0xa484, 0x000c, 0x0040, 0x1ea3, 0x6128, 0x810f, 0xa18c,
+	0x00ff, 0xa082, 0x0004, 0x00c0, 0x1e9b, 0x2100, 0xa318, 0x0048,
+	0x1eaf, 0x0078, 0x1ea3, 0xa082, 0x0004, 0x00c0, 0x1eaf, 0x2100,
+	0xa31a, 0x0048, 0x1eaf, 0x6030, 0xa005, 0x0040, 0x1ea9, 0x8000,
+	0x6816, 0x6a06, 0x6b0a, 0x2091, 0x8001, 0x0078, 0x1f93, 0x2091,
+	0x8001, 0x0078, 0x1f8f, 0x6114, 0x1078, 0x20c2, 0x2091, 0x8000,
+	0x6b08, 0x8318, 0x0048, 0x1ec1, 0x6b0a, 0x2091, 0x8001, 0x0078,
+	0x1fa2, 0x2091, 0x8001, 0x0078, 0x1f8f, 0x6024, 0x8007, 0xa084,
+	0x00ff, 0x0040, 0x1ee3, 0xa086, 0x0080, 0x00c0, 0x1f0b, 0x20a9,
+	0x0008, 0x2069, 0x7410, 0x2091, 0x8000, 0x6800, 0xa084, 0xfcff,
+	0x6802, 0xade8, 0x0008, 0x0070, 0x1edf, 0x0078, 0x1ed5, 0x2091,
+	0x8001, 0x0078, 0x1f93, 0x6028, 0xa015, 0x0040, 0x1f0b, 0x6114,
+	0x1078, 0x20c2, 0x0d7e, 0xade8, 0x0007, 0x2091, 0x8000, 0x6800,
+	0xa00d, 0x0040, 0x1f08, 0xa206, 0x0040, 0x1ef9, 0x2168, 0x0078,
+	0x1eef, 0x0c7e, 0x2160, 0x6000, 0x6802, 0x1078, 0x192b, 0x0c7f,
+	0x0d7f, 0x6808, 0x8000, 0x680a, 0x2091, 0x8001, 0x0078, 0x1fa2,
+	0x2091, 0x8001, 0x0d7f, 0x0078, 0x1f8b, 0x6114, 0x1078, 0x20c2,
+	0x6800, 0xa084, 0x0001, 0x0040, 0x1f7b, 0x2091, 0x8000, 0x6a04,
+	0x8210, 0x0048, 0x1f20, 0x6a06, 0x2091, 0x8001, 0x0078, 0x1fa2,
+	0x2091, 0x8001, 0x0078, 0x1f8f, 0x1078, 0x1b36, 0x00c0, 0x1d49,
+	0x6114, 0x1078, 0x20c2, 0x60be, 0x6900, 0xa184, 0x0008, 0x0040,
+	0x1f35, 0x6020, 0xa085, 0x0100, 0x6022, 0xa184, 0x0001, 0x0040,
+	0x1f8b, 0xa184, 0x0100, 0x00c0, 0x1f77, 0xa184, 0x0200, 0x00c0,
+	0x1f73, 0x681c, 0xa005, 0x00c0, 0x1f7f, 0x6004, 0xa084, 0x00ff,
+	0xa086, 0x000f, 0x00c0, 0x1f4e, 0x1078, 0x20a5, 0x78df, 0x0000,
+	0x6004, 0x8007, 0xa084, 0x00ff, 0x78d2, 0x8001, 0x609f, 0x0000,
+	0x0040, 0x1f63, 0x1078, 0x1fa6, 0x0040, 0x1f63, 0x78dc, 0xa085,
+	0x0100, 0x78de, 0x007c, 0x78d7, 0x0000, 0x78db, 0x0000, 0x6024,
+	0xa084, 0xff00, 0x6026, 0x1078, 0x39aa, 0x0040, 0x1cc6, 0x1078,
+	0x1b5b, 0x0078, 0x1cc6, 0x2009, 0x0017, 0x0078, 0x1f95, 0x2009,
+	0x000e, 0x0078, 0x1f95, 0x2009, 0x0007, 0x0078, 0x1f95, 0x2009,
+	0x0035, 0x0078, 0x1f95, 0x2009, 0x003e, 0x0078, 0x1f95, 0x2009,
+	0x0004, 0x0078, 0x1f95, 0x2009, 0x0006, 0x0078, 0x1f95, 0x2009,
+	0x0016, 0x0078, 0x1f95, 0x2009, 0x0001, 0x6024, 0xa084, 0xff00,
+	0xa105, 0x6026, 0x2091, 0x8000, 0x1078, 0x1c42, 0x2091, 0x8001,
+	0x0078, 0x1cc6, 0x1078, 0x192b, 0x0078, 0x1cc6, 0x78d4, 0xa06d,
+	0x00c0, 0x1fb1, 0x2c00, 0x78d6, 0x78da, 0x609f, 0x0000, 0x0078,
+	0x1fbd, 0x2c00, 0x689e, 0x609f, 0x0000, 0x78d6, 0x2d00, 0x6002,
+	0x78d8, 0xad06, 0x00c0, 0x1fbd, 0x6002, 0x78d0, 0x8001, 0x78d2,
+	0x00c0, 0x1fc9, 0x78dc, 0xa084, 0xfeff, 0x78de, 0x78d8, 0x2060,
+	0xa006, 0x007c, 0xa02e, 0x2530, 0x611c, 0x61a2, 0xa184, 0xe1ff,
+	0x601e, 0xa184, 0x0060, 0x0040, 0x1fd9, 0x0e7e, 0x1078, 0x467f,
+	0x0e7f, 0x6596, 0x65a6, 0x669a, 0x66aa, 0x60af, 0x0000, 0x60b3,
+	0x0000, 0x6714, 0x1078, 0x1956, 0x2091, 0x8000, 0x60a0, 0xa084,
+	0x8000, 0x00c0, 0x2000, 0x6808, 0xa084, 0x0001, 0x0040, 0x2000,
+	0x2091, 0x8001, 0x1078, 0x19a3, 0x2091, 0x8000, 0x1078, 0x1c42,
+	0x2091, 0x8001, 0x78d7, 0x0000, 0x78db, 0x0000, 0x0078, 0x2072,
+	0x6024, 0xa096, 0x0001, 0x00c0, 0x2007, 0x8000, 0x6026, 0x6a10,
+	0x6814, 0x2091, 0x8001, 0xa202, 0x0048, 0x2016, 0x0040, 0x2016,
+	0x2039, 0x0200, 0x1078, 0x2073, 0x0078, 0x2072, 0x2c08, 0x2091,
+	0x8000, 0x60a0, 0xa084, 0x8000, 0x0040, 0x2043, 0x6800, 0xa065,
+	0x0040, 0x2048, 0x6a04, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa084,
+	0x0001, 0x0040, 0x203d, 0x7048, 0xa206, 0x00c0, 0x203d, 0x6b04,
+	0x231c, 0x2160, 0x6302, 0x2300, 0xa005, 0x00c0, 0x2038, 0x6902,
+	0x2260, 0x6102, 0x0e7f, 0x0078, 0x204f, 0x2160, 0x6202, 0x6906,
+	0x0e7f, 0x0078, 0x204f, 0x6800, 0xa065, 0x0040, 0x2048, 0x6102,
+	0x6902, 0x00c0, 0x204c, 0x6906, 0x2160, 0x6003, 0x0000, 0x2160,
+	0x60a0, 0xa084, 0x8000, 0x0040, 0x2059, 0x6808, 0xa084, 0xfffc,
+	0x680a, 0x6810, 0x8000, 0x6812, 0x2091, 0x8001, 0x6808, 0xa08c,
+	0x0040, 0x0040, 0x2068, 0xa086, 0x0040, 0x680a, 0x1078, 0x19b4,
+	0x2091, 0x8000, 0x1078, 0x21b1, 0x2091, 0x8001, 0x78db, 0x0000,
+	0x78d7, 0x0000, 0x007c, 0x6008, 0xa705, 0x600a, 0x2091, 0x8000,
+	0x1078, 0x1c42, 0x2091, 0x8001, 0x78d8, 0xa065, 0x0040, 0x2086,
+	0x609c, 0x78da, 0x609f, 0x0000, 0x0078, 0x2076, 0x78d7, 0x0000,
+	0x78db, 0x0000, 0x007c, 0x7990, 0x7894, 0x8000, 0xa10a, 0x00c8,
+	0x2092, 0xa006, 0x7896, 0x70d2, 0x7804, 0xa005, 0x0040, 0x20a0,
+	0x8001, 0x7806, 0x00c0, 0x20a0, 0x0068, 0x20a0, 0x2091, 0x4080,
+	0x007c, 0x2039, 0x20b9, 0x0078, 0x20a7, 0x2039, 0x20bf, 0x2704,
+	0xa005, 0x0040, 0x20b8, 0xac00, 0x2068, 0x6b08, 0x6c0c, 0x6910,
+	0x6a14, 0x690a, 0x6a0e, 0x6b12, 0x6c16, 0x8738, 0x0078, 0x20a7,
+	0x007c, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b, 0x0000, 0x0015,
+	0x001b, 0x0000, 0x0c7e, 0x1078, 0x3b33, 0x2c68, 0x0c7f, 0x007c,
+	0x0010, 0x2139, 0x0068, 0x2139, 0x2029, 0x0000, 0x78cb, 0x0000,
+	0x788c, 0xa065, 0x0040, 0x2132, 0x2009, 0x5074, 0x2104, 0xa084,
+	0x0001, 0x0040, 0x2100, 0x6004, 0xa086, 0x0103, 0x00c0, 0x2100,
+	0x6018, 0xa005, 0x00c0, 0x2100, 0x6014, 0xa005, 0x00c0, 0x2100,
+	0x0d7e, 0x2069, 0x0000, 0x6818, 0xa084, 0x0001, 0x00c0, 0x20ff,
+	0x600c, 0x70c6, 0x6010, 0x70ca, 0x70c3, 0x8020, 0x681b, 0x0001,
+	0x2091, 0x4080, 0x0d7f, 0x1078, 0x1c69, 0x0078, 0x2137, 0x0d7f,
+	0x1078, 0x213a, 0x0040, 0x2132, 0x6204, 0xa294, 0x00ff, 0xa296,
+	0x0003, 0x0040, 0x2112, 0x6204, 0xa296, 0x0110, 0x00c0, 0x2120,
+	0x78cb, 0x0001, 0x6204, 0xa294, 0xff00, 0x8217, 0x8211, 0x0040,
+	0x2120, 0x85ff, 0x00c0, 0x2132, 0x8210, 0xa202, 0x00c8, 0x2132,
+	0x057e, 0x1078, 0x2149, 0x057f, 0x0040, 0x212d, 0x78e0, 0xa086,
+	0x0003, 0x0040, 0x2132, 0x0078, 0x2120, 0x8528, 0x78c8, 0xa005,
+	0x0040, 0x20d0, 0x85ff, 0x0040, 0x2139, 0x2091, 0x4080, 0x78b0,
+	0x70d6, 0x007c, 0x7bac, 0x79b0, 0x70d4, 0xa102, 0x00c0, 0x2143,
+	0x2300, 0xa005, 0x007c, 0x0048, 0x2147, 0xa302, 0x007c, 0x8002,
+	0x007c, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x2163,
+	0x2091, 0x8000, 0x2071, 0x0020, 0x7004, 0xa005, 0x00c0, 0x2198,
+	0x7008, 0x7208, 0xa206, 0x00c0, 0x2198, 0xa286, 0x0008, 0x00c0,
+	0x2198, 0x2071, 0x0010, 0x1078, 0x219d, 0x2009, 0x0020, 0x6004,
+	0xa086, 0x0103, 0x00c0, 0x2172, 0x6028, 0xa005, 0x00c0, 0x2172,
+	0x2009, 0x000c, 0x1078, 0x1907, 0x0040, 0x218b, 0x78c4, 0x8000,
+	0x78c6, 0xa086, 0x0002, 0x00c0, 0x2198, 0x2091, 0x8000, 0x78e3,
+	0x0003, 0x78c7, 0x0000, 0x78cc, 0xa085, 0x0300, 0x78ce, 0x2091,
+	0x8001, 0x0078, 0x2198, 0x78c7, 0x0000, 0x1078, 0x1c69, 0x79ac,
+	0x78b0, 0x8000, 0xa10a, 0x00c8, 0x2196, 0xa006, 0x78b2, 0xa006,
+	0x2071, 0x0010, 0x2091, 0x8001, 0x007c, 0x8107, 0x8004, 0x8004,
+	0x7ab8, 0x7bb4, 0x7cc0, 0x7dbc, 0xa210, 0xa399, 0x0000, 0xa4a1,
+	0x0000, 0xa5a9, 0x0000, 0x007c, 0x2009, 0x505b, 0x2091, 0x8000,
+	0x200a, 0x0f7e, 0x0e7e, 0x2071, 0x5040, 0x7000, 0xa086, 0x0000,
+	0x00c0, 0x21cb, 0x2009, 0x5012, 0x2104, 0xa005, 0x00c0, 0x21cb,
+	0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21cb, 0x0018,
+	0x21cb, 0x781b, 0x004b, 0x0e7f, 0x0f7f, 0x007c, 0x0f7e, 0x0e7e,
+	0x2071, 0x5040, 0x2091, 0x8000, 0x7000, 0xa086, 0x0000, 0x00c0,
+	0x21e4, 0x2079, 0x0100, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x21e4,
+	0x0018, 0x21e4, 0x781b, 0x004d, 0x2091, 0x8001, 0x0e7f, 0x0f7f,
+	0x007c, 0x127e, 0x2091, 0x2300, 0x2071, 0x5040, 0x2079, 0x0100,
+	0x784b, 0x000f, 0x0098, 0x21f7, 0x7838, 0x0078, 0x21f0, 0x20a9,
+	0x0040, 0x7800, 0xa082, 0x0004, 0x0048, 0x2200, 0x20a9, 0x0060,
+	0x789b, 0x0000, 0x78af, 0x0000, 0x78af, 0x0000, 0x0070, 0x220a,
+	0x0078, 0x2202, 0x7800, 0xa082, 0x0004, 0x0048, 0x2219, 0x70b7,
+	0x009b, 0x2019, 0x4da4, 0x1078, 0x2255, 0x702f, 0x8001, 0x0078,
+	0x2225, 0x70b7, 0x0000, 0x2019, 0x4c1c, 0x1078, 0x2255, 0x2019,
+	0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7003, 0x0000, 0x1078,
+	0x235e, 0x7004, 0xa084, 0x000f, 0x017e, 0x2009, 0x04fd, 0x210c,
+	0xa18a, 0x0005, 0x0048, 0x223a, 0x0038, 0x2240, 0xa085, 0x6280,
+	0x0078, 0x2242, 0x0028, 0x2240, 0xa085, 0x6280, 0x0078, 0x2242,
+	0xa085, 0x62c0, 0x017f, 0x7806, 0x780f, 0xb204, 0x7843, 0x00d8,
+	0x7853, 0x0080, 0x780b, 0x0008, 0x7047, 0x0008, 0x7053, 0x507f,
+	0x704f, 0x0000, 0x127f, 0x2000, 0x007c, 0x137e, 0x147e, 0x157e,
+	0x047e, 0x20a1, 0x012b, 0x2304, 0xa005, 0x789a, 0x0040, 0x2275,
+	0x8318, 0x2324, 0x8318, 0x2398, 0x24a8, 0xa484, 0xff00, 0x0040,
+	0x226d, 0xa482, 0x0100, 0x20a9, 0x0100, 0x2020, 0x53a6, 0xa005,
+	0x00c0, 0x2264, 0x3318, 0x0078, 0x225b, 0x047f, 0x157f, 0x147f,
+	0x137f, 0x007c, 0xa18c, 0x000f, 0x2011, 0x0101, 0x2204, 0xa084,
+	0xfff0, 0xa105, 0x2012, 0x1078, 0x235e, 0x007c, 0x2011, 0x0101,
+	0x20a9, 0x0009, 0x810b, 0x0070, 0x228f, 0x0078, 0x228a, 0xa18c,
+	0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105, 0x2012, 0x007c, 0x2009,
+	0x0101, 0x20a9, 0x0005, 0x8213, 0x0070, 0x22a0, 0x0078, 0x229b,
+	0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f, 0xa205, 0x200a, 0x007c,
+	0x2011, 0x0101, 0x20a9, 0x000c, 0x810b, 0x0070, 0x22b1, 0x0078,
+	0x22ac, 0xa18c, 0xf000, 0x2204, 0xa084, 0x0fff, 0xa105, 0x2012,
+	0x007c, 0x2011, 0x0102, 0x2204, 0xa084, 0xffcf, 0xa105, 0x2012,
+	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
+	0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080,
+	0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa084, 0xffdf,
+	0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e,
+	0x2061, 0x0100, 0x609a, 0x60a4, 0xa085, 0x0020, 0x60ae, 0x0c7f,
+	0x007c, 0x8103, 0x8003, 0xa080, 0x0020, 0x0c7e, 0x2061, 0x0100,
+	0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4, 0x63ae, 0x2018, 0x0c7f,
+	0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e, 0x6818, 0xa005, 0x0040,
+	0x233c, 0x2061, 0x7400, 0x1078, 0x2344, 0x0040, 0x2328, 0x20a9,
+	0x0000, 0x2061, 0x7300, 0x0c7e, 0x1078, 0x2344, 0x0040, 0x2318,
+	0x0c7f, 0x8c60, 0x0070, 0x2316, 0x0078, 0x230b, 0x0078, 0x233c,
+	0x007f, 0xa082, 0x7300, 0x2071, 0x5040, 0x7086, 0x7182, 0x2001,
+	0x0004, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac, 0x0078, 0x2338,
+	0x60c0, 0xa005, 0x00c0, 0x233c, 0x2071, 0x5040, 0x7182, 0x2c00,
+	0x708a, 0x2001, 0x0006, 0x706e, 0x7093, 0x000f, 0x1078, 0x21ac,
+	0x2001, 0x0000, 0x0078, 0x233e, 0x2001, 0x0001, 0x2091, 0x8001,
+	0xa005, 0x0e7f, 0x0c7f, 0x007c, 0x2c04, 0xa005, 0x0040, 0x235b,
+	0x2060, 0x600c, 0xa306, 0x00c0, 0x2358, 0x6010, 0xa206, 0x00c0,
+	0x2358, 0x6014, 0xa106, 0x00c0, 0x2358, 0xa006, 0x0078, 0x235d,
+	0x6000, 0x0078, 0x2345, 0xa085, 0x0001, 0x007c, 0x2011, 0x5041,
+	0x220c, 0xa18c, 0x000f, 0x2011, 0x013b, 0x2204, 0xa084, 0x0100,
+	0x0040, 0x2374, 0x2021, 0xff04, 0x2122, 0x810b, 0x810b, 0x810b,
+	0x810b, 0xa18d, 0x0f00, 0x2104, 0x007c, 0x0e7e, 0x68e4, 0xa08c,
+	0x0020, 0x0040, 0x23c8, 0xa084, 0x0006, 0x00c0, 0x23c8, 0x6014,
+	0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x5280,
+	0x7004, 0xa084, 0x000a, 0x00c0, 0x23c8, 0x7108, 0xa194, 0xff00,
+	0x0040, 0x23c8, 0xa18c, 0x00ff, 0x2001, 0x000c, 0xa106, 0x0040,
+	0x23af, 0x2001, 0x0012, 0xa106, 0x0040, 0x23b3, 0x2001, 0x0014,
+	0xa106, 0x0040, 0x23b7, 0x2001, 0x0019, 0xa106, 0x0040, 0x23bb,
+	0x2001, 0x0032, 0xa106, 0x0040, 0x23bf, 0x0078, 0x23c3, 0x2009,
+	0x0012, 0x0078, 0x23c5, 0x2009, 0x0014, 0x0078, 0x23c5, 0x2009,
+	0x0019, 0x0078, 0x23c5, 0x2009, 0x0020, 0x0078, 0x23c5, 0x2009,
+	0x003f, 0x0078, 0x23c5, 0x2011, 0x0000, 0x2100, 0xa205, 0x700a,
+	0x0e7f, 0x007c, 0x0068, 0x23ca, 0x2091, 0x8000, 0x2071, 0x0000,
+	0x007e, 0x7018, 0xa084, 0x0001, 0x00c0, 0x23d1, 0x007f, 0x2071,
+	0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002, 0x70db, 0x073f,
+	0x70df, 0x0000, 0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080,
+	0x0078, 0x23e8, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300, 0x7f3c,
+	0x7e58, 0x7c30, 0x7d38, 0x77c2, 0x74c6, 0x76ca, 0x75ce, 0xa594,
+	0x003f, 0xa49c, 0x0003, 0xa484, 0x000f, 0x0079, 0x23ff, 0x2411,
+	0x2411, 0x2411, 0x274b, 0x3907, 0x240f, 0x2440, 0x244a, 0x240f,
+	0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x240f, 0x1078,
+	0x23ca, 0x8507, 0xa084, 0x001f, 0x0079, 0x2416, 0x2454, 0x274b,
+	0x2905, 0x2a02, 0x2a2a, 0x2cc3, 0x2f6e, 0x2fb1, 0x2ffc, 0x3081,
+	0x3139, 0x31e2, 0x2440, 0x2827, 0x2f43, 0x2436, 0x3c78, 0x3c98,
+	0x3e5e, 0x3e6a, 0x3f3f, 0x2436, 0x2436, 0x4012, 0x4016, 0x3c76,
+	0x2436, 0x3dc9, 0x2436, 0x3b56, 0x244a, 0x2436, 0x1078, 0x23ca,
+	0x0018, 0x23ef, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c,
+	0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f, 0x0001, 0x781b, 0x004f,
+	0x0078, 0x2438, 0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000,
+	0x781b, 0x00d5, 0x0078, 0x2438, 0x7242, 0x2009, 0x500f, 0x200b,
+	0x0000, 0xa584, 0x0001, 0x00c0, 0x3b6a, 0x0040, 0x2471, 0x1078,
+	0x23ca, 0x7003, 0x0000, 0x704b, 0x0000, 0x7043, 0x0000, 0x7037,
+	0x0000, 0x1078, 0x38de, 0x0018, 0x23ef, 0x2009, 0x500f, 0x200b,
+	0x0000, 0x7068, 0xa005, 0x00c0, 0x253c, 0x706c, 0xa084, 0x0007,
+	0x0079, 0x247a, 0x2573, 0x2482, 0x248e, 0x24ab, 0x24cd, 0x251a,
+	0x24f3, 0x2482, 0x1078, 0x38c6, 0x2009, 0x0048, 0x1078, 0x2e0f,
+	0x00c0, 0x248c, 0x7003, 0x0004, 0x0078, 0x2438, 0x1078, 0x38c6,
+	0x00c0, 0x24a9, 0x7080, 0x8007, 0x7882, 0x789b, 0x0010, 0x78ab,
+	0x000c, 0x789b, 0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009,
+	0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24a9, 0x7003, 0x0004, 0x7093,
+	0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x24cb, 0x7180,
+	0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0,
+	0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b,
+	0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24cb, 0x7003,
+	0x0004, 0x7093, 0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0,
+	0x24f1, 0x7180, 0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f,
+	0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0020, 0x7184, 0x79aa, 0x78ab,
+	0x000d, 0x789b, 0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009,
+	0x00e5, 0x1078, 0x2e03, 0x00c0, 0x24f1, 0x7003, 0x0004, 0x7093,
+	0x000f, 0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2518, 0x7180,
+	0x8107, 0x7882, 0x789b, 0x0010, 0xa18c, 0x001f, 0xa18d, 0x00c0,
+	0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab, 0x0002, 0x785b,
+	0x0004, 0x2009, 0x00e5, 0x1078, 0x2e03, 0x00c0, 0x2518, 0x7088,
+	0x708b, 0x0000, 0x2068, 0x704a, 0x7003, 0x0002, 0x7093, 0x000f,
+	0x0078, 0x2438, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x7088, 0x2068,
+	0x6f14, 0x1078, 0x37bd, 0x2c50, 0x1078, 0x3978, 0x789b, 0x0010,
+	0x6814, 0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x6e1c, 0x2041,
+	0x0001, 0x708c, 0xa084, 0x0400, 0x2001, 0x0004, 0x0040, 0x253a,
+	0x2001, 0x0006, 0x0078, 0x265b, 0x1078, 0x38c6, 0x00c0, 0x2438,
+	0x789b, 0x0010, 0x7068, 0x2068, 0x6f14, 0x1078, 0x37bd, 0x2c50,
+	0x1078, 0x3978, 0x6008, 0xa085, 0x0010, 0x600a, 0x6824, 0xa005,
+	0x0040, 0x255a, 0xa082, 0x0006, 0x0048, 0x2558, 0x0078, 0x255a,
+	0x6827, 0x0005, 0x6b14, 0xa39c, 0x001f, 0xa39d, 0x00c0, 0x7058,
+	0xa084, 0x8000, 0x0040, 0x2568, 0xa684, 0x0001, 0x0040, 0x256a,
+	0xa39c, 0xffbf, 0x7baa, 0x2031, 0x0020, 0x2041, 0x0001, 0x2001,
+	0x0003, 0x0078, 0x265b, 0x0018, 0x23ef, 0x744c, 0xa485, 0x0000,
+	0x0040, 0x258d, 0xa080, 0x5080, 0x2030, 0x7150, 0x8108, 0xa12a,
+	0x0048, 0x2584, 0x2009, 0x5080, 0x2164, 0x6504, 0x85ff, 0x00c0,
+	0x259e, 0x8421, 0x00c0, 0x257e, 0x7152, 0x7003, 0x0000, 0x704b,
+	0x0000, 0x7040, 0xa005, 0x0040, 0x3b6a, 0x0078, 0x2438, 0x764c,
+	0xa6b0, 0x5080, 0x7150, 0x2600, 0x0078, 0x2589, 0x7152, 0x2568,
+	0x2558, 0x754a, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x259b,
+	0x6708, 0x773a, 0xa784, 0x033f, 0x0040, 0x25d4, 0xa784, 0x0021,
+	0x00c0, 0x259b, 0xa784, 0x0002, 0x0040, 0x25bd, 0xa784, 0x0004,
+	0x0040, 0x259b, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0,
+	0x259b, 0xa784, 0x0010, 0x00c0, 0x259b, 0xa784, 0x0200, 0x00c0,
+	0x259b, 0xa784, 0x0100, 0x0040, 0x25d4, 0x6018, 0xa005, 0x00c0,
+	0x259b, 0xa7bc, 0xfeff, 0x670a, 0x6823, 0x0000, 0x6e1c, 0xa684,
+	0x000e, 0x6118, 0x0040, 0x25e4, 0x601c, 0xa102, 0x0048, 0x25e7,
+	0x0040, 0x25e7, 0x0078, 0x2597, 0x81ff, 0x00c0, 0x2597, 0x68c3,
+	0x0000, 0xa784, 0x0080, 0x00c0, 0x25ef, 0x700c, 0x6022, 0xa7bc,
+	0xff7f, 0x670a, 0x1078, 0x3978, 0x0018, 0x23ef, 0x789b, 0x0010,
+	0xa046, 0x1078, 0x38c6, 0x00c0, 0x2438, 0x6b14, 0xa39c, 0x001f,
+	0xa39d, 0x00c0, 0x7058, 0xa084, 0x8000, 0x0040, 0x260b, 0xa684,
+	0x0001, 0x0040, 0x260d, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040,
+	0x2613, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0,
+	0x261e, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x2659, 0x7158, 0xa18c,
+	0x0800, 0x0040, 0x33d7, 0x2011, 0x0020, 0xa684, 0x0008, 0x00c0,
+	0x262f, 0x8210, 0xa684, 0x0002, 0x00c0, 0x262f, 0x8210, 0x7aaa,
+	0x8840, 0x1078, 0x38de, 0x6a14, 0x610c, 0x8108, 0xa18c, 0x00ff,
+	0xa1e0, 0x7300, 0x2c64, 0x8cff, 0x0040, 0x2650, 0x6014, 0xa206,
+	0x00c0, 0x263a, 0x60b8, 0x8001, 0x60ba, 0x00c0, 0x2635, 0x0c7e,
+	0x2a60, 0x6008, 0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x2573,
+	0x1078, 0x38c6, 0x00c0, 0x2438, 0x2a60, 0x610e, 0x79aa, 0x8840,
+	0x7132, 0x2001, 0x0001, 0x007e, 0x715c, 0xa184, 0x0018, 0x0040,
+	0x2676, 0xa184, 0x0010, 0x0040, 0x2669, 0x1078, 0x35d6, 0x00c0,
+	0x2699, 0xa184, 0x0008, 0x0040, 0x2676, 0x69a0, 0xa184, 0x0600,
+	0x00c0, 0x2676, 0x1078, 0x34c7, 0x0078, 0x2699, 0x69a0, 0xa184,
+	0x0800, 0x0040, 0x268d, 0x0c7e, 0x027e, 0x2960, 0x6000, 0xa085,
+	0x2000, 0x6002, 0x6104, 0xa18d, 0x0010, 0x6106, 0x027f, 0x0c7f,
+	0x1078, 0x35d6, 0x00c0, 0x2699, 0x69a0, 0xa184, 0x0200, 0x0040,
+	0x2695, 0x1078, 0x3516, 0x0078, 0x2699, 0xa184, 0x0400, 0x00c0,
+	0x2672, 0x69a0, 0xa184, 0x1000, 0x0040, 0x26a4, 0x6914, 0xa18c,
+	0xff00, 0x810f, 0x1078, 0x22cd, 0x007f, 0x7002, 0xa68c, 0x00e0,
+	0xa684, 0x0060, 0x0040, 0x26b2, 0xa086, 0x0060, 0x00c0, 0x26b2,
+	0xa18d, 0x4000, 0x88ff, 0x0040, 0x26b7, 0xa18d, 0x0004, 0x795a,
+	0x69b6, 0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6818,
+	0xa08d, 0x8000, 0xa084, 0x7fff, 0x691a, 0xa68c, 0x0080, 0x0040,
+	0x26d6, 0x7097, 0x0000, 0xa08a, 0x000d, 0x0050, 0x26d4, 0xa08a,
+	0x000c, 0x7196, 0x2001, 0x000c, 0x800c, 0x719a, 0x78aa, 0x8008,
+	0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0, 0x33dd, 0x157e,
+	0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac,
+	0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6814,
+	0x8007, 0x7882, 0x6d94, 0x7dd6, 0x7dde, 0x6e98, 0x7ed2, 0x7eda,
+	0x1078, 0x38c6, 0x00c0, 0x270d, 0x702c, 0x8003, 0x0048, 0x2706,
+	0x2019, 0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x7830, 0xa084,
+	0x00c0, 0x00c0, 0x270d, 0x0098, 0x2715, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x38de, 0x0078, 0x2461, 0x7200, 0xa284, 0x0007,
+	0xa086, 0x0001, 0x00c0, 0x2722, 0x781b, 0x004f, 0x1078, 0x38de,
+	0x0078, 0x2733, 0x6ab4, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x004f,
+	0x1078, 0x38de, 0x7200, 0x2500, 0xa605, 0x0040, 0x2733, 0xa284,
+	0x0007, 0x1079, 0x2741, 0xad80, 0x0009, 0x7036, 0xa284, 0x0007,
+	0xa086, 0x0001, 0x00c0, 0x2438, 0x6018, 0x8000, 0x601a, 0x0078,
+	0x2438, 0x2749, 0x48f7, 0x48f7, 0x48e6, 0x48f7, 0x2749, 0x48e6,
+	0x2749, 0x1078, 0x23ca, 0x1078, 0x38c6, 0x0f7e, 0x2079, 0x5000,
+	0x78cc, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x276f, 0x706c, 0xa086,
+	0x0001, 0x00c0, 0x275e, 0x706e, 0x0078, 0x2802, 0x706c, 0xa086,
+	0x0005, 0x00c0, 0x276d, 0x7088, 0x2068, 0x681b, 0x0004, 0x6817,
+	0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x706f, 0x0000, 0x2011,
+	0x0004, 0x716c, 0xa186, 0x0001, 0x0040, 0x2790, 0xa186, 0x0007,
+	0x00c0, 0x2780, 0x2009, 0x5038, 0x200b, 0x0005, 0x0078, 0x2790,
+	0x2009, 0x5013, 0x2104, 0x2009, 0x5012, 0x200a, 0x2009, 0x5038,
+	0x200b, 0x0001, 0x706f, 0x0000, 0x7073, 0x0001, 0x0078, 0x2792,
+	0x706f, 0x0000, 0x1078, 0x4633, 0x157e, 0x20a9, 0x0010, 0x2039,
+	0x0000, 0x1078, 0x36b0, 0xa7b8, 0x0100, 0x0070, 0x27a1, 0x0078,
+	0x2799, 0x157f, 0x7000, 0x0079, 0x27a5, 0x27d3, 0x27ba, 0x27ba,
+	0x27ad, 0x27d3, 0x27d3, 0x27d3, 0x27d3, 0x2021, 0x505a, 0x2404,
+	0xa005, 0x0040, 0x27d3, 0xad06, 0x00c0, 0x27ba, 0x6800, 0x2022,
+	0x0078, 0x27ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x27c6, 0x6f14,
+	0x1078, 0x37bd, 0x1078, 0x33ae, 0x0078, 0x27ca, 0x7060, 0x2060,
+	0x6800, 0x6002, 0x6a1a, 0x6817, 0x0000, 0x6820, 0xa085, 0x0008,
+	0x6822, 0x1078, 0x1c53, 0x2021, 0x7400, 0x1078, 0x280f, 0x2021,
+	0x505a, 0x1078, 0x280f, 0x157e, 0x20a9, 0x0000, 0x2021, 0x7300,
+	0x1078, 0x280f, 0x8420, 0x0070, 0x27e7, 0x0078, 0x27e0, 0x2061,
+	0x5300, 0x2021, 0x0002, 0x20a9, 0x0100, 0x6018, 0x6110, 0x81ff,
+	0x0040, 0x27f6, 0xa102, 0x0050, 0x27f6, 0x6012, 0x601b, 0x0000,
+	0xace0, 0x0010, 0x0070, 0x27fe, 0x0078, 0x27ed, 0x8421, 0x00c0,
+	0x27eb, 0x157f, 0x709c, 0xa084, 0x8000, 0x0040, 0x2809, 0x1078,
+	0x39cc, 0x7003, 0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x047e,
+	0x2404, 0xa005, 0x0040, 0x2823, 0x2068, 0x6800, 0x007e, 0x6a1a,
+	0x6817, 0x0000, 0x6820, 0xa085, 0x0008, 0x6822, 0x1078, 0x1c53,
+	0x007f, 0x0078, 0x2811, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282,
+	0x0003, 0x0050, 0x282d, 0x1078, 0x23ca, 0x2300, 0x0079, 0x2830,
+	0x2833, 0x28a6, 0x28c3, 0xa282, 0x0002, 0x0040, 0x2839, 0x1078,
+	0x23ca, 0x706c, 0x706f, 0x0000, 0x7093, 0x0000, 0x0079, 0x2840,
+	0x2848, 0x2848, 0x284a, 0x287e, 0x33e3, 0x2848, 0x287e, 0x2848,
+	0x1078, 0x23ca, 0x7780, 0x1078, 0x36b0, 0x7780, 0xa7bc, 0x0f00,
+	0x1078, 0x37bd, 0x6018, 0xa005, 0x0040, 0x2875, 0x2021, 0x7400,
+	0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x28de, 0x0040, 0x2875,
+	0x157e, 0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0004,
+	0x2011, 0x0010, 0x1078, 0x28de, 0x047f, 0x0040, 0x2874, 0x8420,
+	0x0070, 0x2874, 0x0078, 0x2865, 0x157f, 0x8738, 0xa784, 0x001f,
+	0x00c0, 0x2850, 0x0078, 0x2461, 0x0078, 0x2461, 0x7780, 0x1078,
+	0x37bd, 0x6018, 0xa005, 0x0040, 0x28a4, 0x2021, 0x7400, 0x2009,
+	0x0005, 0x2011, 0x0020, 0x1078, 0x28de, 0x0040, 0x28a4, 0x157e,
+	0x20a9, 0x0000, 0x2021, 0x7300, 0x047e, 0x2009, 0x0005, 0x2011,
+	0x0020, 0x1078, 0x28de, 0x047f, 0x0040, 0x28a3, 0x8420, 0x0070,
+	0x28a3, 0x0078, 0x2894, 0x157f, 0x0078, 0x2461, 0x2200, 0x0079,
+	0x28a9, 0x28ac, 0x28ae, 0x28ae, 0x1078, 0x23ca, 0x2009, 0x0012,
+	0x706c, 0xa086, 0x0002, 0x0040, 0x28b7, 0x2009, 0x000e, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x28bd, 0x691a, 0x706f, 0x0000, 0x7073,
+	0x0001, 0x0078, 0x3854, 0x2200, 0x0079, 0x28c6, 0x28cb, 0x28ae,
+	0x28c9, 0x1078, 0x23ca, 0x1078, 0x4633, 0x7000, 0xa086, 0x0001,
+	0x00c0, 0x3373, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a,
+	0x1078, 0x3366, 0x0040, 0x3373, 0x0078, 0x2573, 0x2404, 0xa005,
+	0x0040, 0x2901, 0x2068, 0x2d04, 0x007e, 0x6814, 0xa706, 0x0040,
+	0x28ed, 0x2d20, 0x007f, 0x0078, 0x28df, 0x007f, 0x2022, 0x691a,
+	0x6817, 0x0000, 0x6820, 0xa205, 0x6822, 0x1078, 0x1c53, 0x6010,
+	0x8001, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x33c4,
+	0x007c, 0xa085, 0x0001, 0x0078, 0x2900, 0x2300, 0x0079, 0x2908,
+	0x290d, 0x290b, 0x29a6, 0x1078, 0x23ca, 0x78ec, 0xa084, 0x0001,
+	0x00c0, 0x2921, 0x7000, 0xa086, 0x0004, 0x00c0, 0x2919, 0x0078,
+	0x2944, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x0078,
+	0x3373, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018, 0x2438, 0x2008,
+	0xa084, 0x0030, 0x00c0, 0x2930, 0x781b, 0x004f, 0x0078, 0x2438,
+	0x78ec, 0xa084, 0x0003, 0x0040, 0x292c, 0x2100, 0xa084, 0x0007,
+	0x0079, 0x293a, 0x297d, 0x2988, 0x296e, 0x2942, 0x38b9, 0x38b9,
+	0x2942, 0x2997, 0x1078, 0x23ca, 0x7000, 0xa086, 0x0004, 0x00c0,
+	0x295e, 0x706c, 0xa086, 0x0002, 0x00c0, 0x2954, 0x2011, 0x0002,
+	0x2019, 0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040,
+	0x294e, 0x706c, 0xa086, 0x0004, 0x0040, 0x294e, 0x79e4, 0xa184,
+	0x0030, 0x0040, 0x2968, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x296a,
+	0x0078, 0x2f43, 0x2001, 0x0003, 0x0078, 0x2cd7, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x2975, 0x681b, 0x001d, 0x1078, 0x368f, 0x782b,
+	0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x2984, 0x681b, 0x001d, 0x1078, 0x368f, 0x0078, 0x3884,
+	0x6818, 0xa084, 0x8000, 0x0040, 0x298f, 0x681b, 0x001d, 0x1078,
+	0x368f, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x6818,
+	0xa084, 0x8000, 0x0040, 0x299e, 0x681b, 0x001d, 0x1078, 0x368f,
+	0x782b, 0x3008, 0x781b, 0x0093, 0x0078, 0x2438, 0xa584, 0x000f,
+	0x00c0, 0x29c3, 0x7000, 0x0079, 0x29ad, 0x2461, 0x29b7, 0x29b5,
+	0x3373, 0x3373, 0x3373, 0x3373, 0x29b5, 0x1078, 0x23ca, 0x1078,
+	0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078, 0x3366, 0x0040,
+	0x3373, 0x0078, 0x2573, 0x78e4, 0xa005, 0x00d0, 0x2944, 0x0018,
+	0x2944, 0x2008, 0xa084, 0x0030, 0x00c0, 0x29d2, 0x781b, 0x004f,
+	0x0078, 0x2438, 0x78ec, 0xa084, 0x0003, 0x0040, 0x29ce, 0x2100,
+	0xa184, 0x0007, 0x0079, 0x29dc, 0x29ee, 0x29f2, 0x29e6, 0x29e4,
+	0x38b9, 0x38b9, 0x29e4, 0x38af, 0x1078, 0x23ca, 0x1078, 0x3697,
+	0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x1078, 0x3697,
+	0x0078, 0x3884, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x00d2,
+	0x0078, 0x2438, 0x1078, 0x3697, 0x782b, 0x3008, 0x781b, 0x0093,
+	0x0078, 0x2438, 0x2300, 0x0079, 0x2a05, 0x2a0a, 0x2a08, 0x2a0c,
+	0x1078, 0x23ca, 0x0078, 0x3081, 0x681b, 0x0008, 0x78a3, 0x0000,
+	0x79e4, 0xa184, 0x0030, 0x0040, 0x3081, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x3081, 0xa184, 0x0007, 0x0079, 0x2a1e, 0x2a26, 0x29f2,
+	0x296e, 0x3854, 0x38b9, 0x38b9, 0x2a26, 0x38af, 0x1078, 0x3868,
+	0x0078, 0x2438, 0xa282, 0x0005, 0x0050, 0x2a30, 0x1078, 0x23ca,
+	0x2300, 0x0079, 0x2a33, 0x2a36, 0x2c84, 0x2c92, 0x2200, 0x0079,
+	0x2a39, 0x2a53, 0x2a40, 0x2a53, 0x2a3e, 0x2c69, 0x1078, 0x23ca,
+	0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048,
+	0x366b, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2a4f, 0x366b,
+	0x366b, 0x366b, 0x3619, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080,
+	0x0040, 0x2a64, 0x0078, 0x366b, 0x7000, 0xa005, 0x00c0, 0x2a5a,
+	0x2011, 0x0004, 0x0078, 0x31f5, 0xa184, 0x00ff, 0xa08a, 0x0010,
+	0x00c8, 0x366b, 0x0079, 0x2a6c, 0x2a7e, 0x2a7c, 0x2a96, 0x2a9a,
+	0x2b55, 0x366b, 0x366b, 0x2b57, 0x366b, 0x366b, 0x2c65, 0x2c65,
+	0x366b, 0x366b, 0x366b, 0x2c67, 0x1078, 0x23ca, 0xa684, 0x1000,
+	0x0040, 0x2a8b, 0x2001, 0x0500, 0x8000, 0x8000, 0x783a, 0x781b,
+	0x0091, 0x0078, 0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x2a94,
+	0x681b, 0x001d, 0x0078, 0x2a82, 0x0078, 0x3854, 0x681b, 0x001d,
+	0x0078, 0x367b, 0x6920, 0x6922, 0xa684, 0x1800, 0x00c0, 0x2adb,
+	0x6820, 0xa084, 0x0001, 0x00c0, 0x2ae1, 0x6818, 0xa086, 0x0008,
+	0x00c0, 0x2aac, 0x681b, 0x0000, 0xa684, 0x0400, 0x0040, 0x2b51,
+	0xa684, 0x0080, 0x0040, 0x2ad7, 0x7097, 0x0000, 0x6818, 0xa084,
+	0x003f, 0xa08a, 0x000d, 0x0050, 0x2ad7, 0xa08a, 0x000c, 0x7196,
+	0x2001, 0x000c, 0x800c, 0x719a, 0x789b, 0x0061, 0x78aa, 0x157e,
+	0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8000, 0x80ac,
+	0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x781b,
+	0x0058, 0x0078, 0x2438, 0xa684, 0x1000, 0x0040, 0x2ae1, 0x0078,
+	0x2438, 0xa684, 0x0060, 0x0040, 0x2b4d, 0xa684, 0x0800, 0x0040,
+	0x2b4d, 0xa684, 0x8000, 0x00c0, 0x2aef, 0x0078, 0x2b09, 0xa6b4,
+	0x7fff, 0x7e5a, 0x6eb6, 0x789b, 0x0076, 0x7aac, 0x79ac, 0x78ac,
+	0x801b, 0x00c8, 0x2afc, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291,
+	0x0000, 0x6b98, 0x2100, 0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303,
+	0x68ae, 0xa684, 0x4000, 0x0040, 0x2b11, 0xa6b4, 0xbfff, 0x7e5a,
+	0x6eb6, 0x7000, 0xa086, 0x0003, 0x00c0, 0x2b1e, 0x1078, 0x46e9,
+	0x1078, 0x48e6, 0x781b, 0x0064, 0x0078, 0x2438, 0xa006, 0x1078,
+	0x49ed, 0x6ab0, 0x69ac, 0x6c98, 0x6b94, 0x2200, 0xa105, 0x0040,
+	0x2b2d, 0x2200, 0xa422, 0x2100, 0xa31b, 0x6caa, 0x7cd2, 0x7cda,
+	0x6ba6, 0x7bd6, 0x7bde, 0x2300, 0xa405, 0x00c0, 0x2b3f, 0xa6b5,
+	0x4000, 0x7e5a, 0x6eb6, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b,
+	0x0064, 0x2200, 0xa115, 0x00c0, 0x2b49, 0x1078, 0x48f7, 0x0078,
+	0x2438, 0x1078, 0x4942, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078,
+	0x2438, 0x781b, 0x0058, 0x0078, 0x2438, 0x1078, 0x23ca, 0x0078,
+	0x2bb8, 0x6920, 0xa184, 0x0100, 0x0040, 0x2b6f, 0xa18c, 0xfeff,
+	0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000, 0xa084, 0xefff, 0x6002,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x0078, 0x2ba7, 0xa184,
+	0x0200, 0x0040, 0x2ba7, 0xa18c, 0xfdff, 0x6922, 0x0c7e, 0x7054,
+	0x2060, 0x6000, 0xa084, 0xdfff, 0x6002, 0x6004, 0xa084, 0xffef,
+	0x6006, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7,
+	0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b,
+	0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
+	0x0400, 0x00c0, 0x2ba1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078,
+	0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58,
+	0xa684, 0x0400, 0x00c0, 0x2bb0, 0x781b, 0x0058, 0x0078, 0x2438,
+	0x781b, 0x0065, 0x0078, 0x2438, 0x0078, 0x3673, 0x0078, 0x3673,
+	0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x2bb6, 0x789b,
+	0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0, 0x2bf6,
+	0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x2bee, 0x0048,
+	0x2bd3, 0x0078, 0x2bf0, 0xa380, 0x0002, 0xa102, 0x00c8, 0x2bee,
+	0x6920, 0xa18c, 0xfcff, 0x6922, 0x0c7e, 0x7054, 0x2060, 0x6000,
+	0xa084, 0xefef, 0x6002, 0x6004, 0xa084, 0xffe5, 0x6006, 0x0c7f,
+	0x7e58, 0xa6b4, 0xfffb, 0x7e5a, 0x0078, 0x2ba8, 0x0078, 0x2b59,
+	0x24a8, 0x7aa8, 0x00f0, 0x2bf0, 0x0078, 0x2bc1, 0xa284, 0x00f0,
+	0xa086, 0x0020, 0x00c0, 0x2c56, 0x8318, 0x8318, 0x2300, 0xa102,
+	0x0040, 0x2c06, 0x0048, 0x2c06, 0x0078, 0x2c53, 0xa286, 0x0023,
+	0x0040, 0x2bb6, 0x681c, 0xa084, 0xfff1, 0x681e, 0x7e58, 0xa684,
+	0xfff1, 0xa085, 0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010,
+	0x600a, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f,
+	0xa184, 0x0010, 0x0040, 0x2c2a, 0x1078, 0x37b9, 0x1078, 0x35d6,
+	0x0078, 0x2c39, 0x0c7e, 0x7054, 0x2060, 0x6004, 0x2008, 0x2c48,
+	0x0c7f, 0xa184, 0x0008, 0x0040, 0x2ba7, 0x1078, 0x37b9, 0x1078,
+	0x34c7, 0x88ff, 0x0040, 0x2ba7, 0x789b, 0x0060, 0x2800, 0x78aa,
+	0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2c4d, 0x782b,
+	0x3008, 0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x7aa8, 0x0078, 0x2bc1, 0x8318, 0x2300,
+	0xa102, 0x0040, 0x2c5f, 0x0048, 0x2c5f, 0x0078, 0x2bc1, 0xa284,
+	0x0080, 0x00c0, 0x367b, 0x0078, 0x3673, 0x0078, 0x367b, 0x0078,
+	0x366b, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff, 0xa08e, 0x0001,
+	0x0040, 0x2c74, 0x1078, 0x23ca, 0x7aa8, 0xa294, 0x00ff, 0x78a8,
+	0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x366b, 0x0079, 0x2c80,
+	0x366b, 0x3414, 0x366b, 0x356b, 0xa282, 0x0000, 0x00c0, 0x2c8a,
+	0x1078, 0x23ca, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065,
+	0x0078, 0x2438, 0xa282, 0x0003, 0x00c0, 0x2c98, 0x1078, 0x23ca,
+	0xa484, 0x8000, 0x00c0, 0x2cbb, 0x706c, 0xa005, 0x0040, 0x2ca2,
+	0x1078, 0x23ca, 0x6f14, 0x7782, 0xa7bc, 0x0f00, 0x1078, 0x37bd,
+	0x6008, 0xa085, 0x0021, 0x600a, 0x8738, 0xa784, 0x001f, 0x00c0,
+	0x2ca6, 0x1078, 0x3693, 0x706f, 0x0002, 0x2009, 0x5038, 0x200b,
+	0x0009, 0x0078, 0x2cbd, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b,
+	0x0065, 0x0078, 0x2438, 0xa282, 0x0004, 0x0050, 0x2cc9, 0x1078,
+	0x23ca, 0x2300, 0x0079, 0x2ccc, 0x2ccf, 0x2db8, 0x2deb, 0xa286,
+	0x0003, 0x0040, 0x2cd5, 0x1078, 0x23ca, 0x2001, 0x0000, 0x007e,
+	0x68c0, 0xa005, 0x0040, 0x2cde, 0x7003, 0x0003, 0x68a0, 0xa084,
+	0x2000, 0x0040, 0x2ce7, 0x6008, 0xa085, 0x0002, 0x600a, 0x007f,
+	0x703e, 0x7000, 0xa084, 0x0007, 0x0079, 0x2cee, 0x2461, 0x2cf8,
+	0x2cf8, 0x2eed, 0x2f29, 0x2461, 0x2f29, 0x2cf6, 0x1078, 0x23ca,
+	0xa684, 0x1000, 0x00c0, 0x2d00, 0x1078, 0x4633, 0x0040, 0x2d92,
+	0x7868, 0xa08c, 0x00ff, 0x0040, 0x2d48, 0xa186, 0x0008, 0x00c0,
+	0x2d17, 0x1078, 0x33c4, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+	0x3366, 0x0040, 0x2d48, 0x1078, 0x4633, 0x0078, 0x2d2f, 0xa186,
+	0x0028, 0x00c0, 0x2d48, 0x1078, 0x4633, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x6018, 0xa005, 0x0040, 0x2d2f, 0x8001, 0x601a, 0xa005,
+	0x0040, 0x2d2f, 0x8001, 0xa005, 0x0040, 0x2d2f, 0x601e, 0x6820,
+	0xa084, 0x0001, 0x0040, 0x2461, 0x6820, 0xa084, 0xfffe, 0x6822,
+	0x7060, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f, 0x6004, 0x6802,
+	0xa005, 0x2d00, 0x00c0, 0x2d45, 0x6002, 0x6006, 0x0078, 0x2461,
+	0x017e, 0x1078, 0x2e1c, 0x017f, 0xa684, 0xdf00, 0x681e, 0x682b,
+	0x0000, 0x6f14, 0x81ff, 0x0040, 0x2d92, 0xa186, 0x0002, 0x00c0,
+	0x2d92, 0xa684, 0x0800, 0x00c0, 0x2d65, 0xa684, 0x0060, 0x0040,
+	0x2d65, 0x78d8, 0x7adc, 0x682e, 0x6a32, 0x6820, 0xa084, 0x0800,
+	0x00c0, 0x2d92, 0x8717, 0xa294, 0x000f, 0x8213, 0x8213, 0x8213,
+	0xa290, 0x5280, 0xa290, 0x0000, 0x221c, 0xa384, 0x0100, 0x00c0,
+	0x2d7b, 0x0078, 0x2d81, 0x8210, 0x2204, 0xa085, 0x0018, 0x2012,
+	0x8211, 0xa384, 0x0400, 0x0040, 0x2d8e, 0x68a0, 0xa084, 0x0100,
+	0x00c0, 0x2d8e, 0x1078, 0x2ea0, 0x0078, 0x2461, 0x6008, 0xa085,
+	0x0002, 0x600a, 0x6916, 0x6818, 0xa084, 0x8000, 0x0040, 0x2d9a,
+	0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x1078, 0x33b5, 0x1078,
+	0x33c4, 0x00c0, 0x2da7, 0x6008, 0xa084, 0xffef, 0x600a, 0x6820,
+	0xa084, 0x0001, 0x00c0, 0x2db0, 0x1078, 0x33ae, 0x0078, 0x2db4,
+	0x7060, 0x2060, 0x6800, 0x6002, 0x1078, 0x1c53, 0x0078, 0x2461,
+	0xa282, 0x0004, 0x0048, 0x2dbe, 0x1078, 0x23ca, 0x2200, 0x0079,
+	0x2dc1, 0x2dbc, 0x2dc5, 0x2dd2, 0x2dc5, 0x7000, 0xa086, 0x0005,
+	0x0040, 0x2dce, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b, 0x0065,
+	0x0078, 0x2438, 0x7890, 0x8007, 0x8001, 0xa084, 0x0007, 0xa080,
+	0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff, 0xa186, 0x0003, 0x0040,
+	0x2de7, 0xa186, 0x0000, 0x0040, 0x2de7, 0x0078, 0x366b, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822, 0x82ff,
+	0x00c0, 0x2df6, 0x1078, 0x368f, 0x0078, 0x2dfd, 0x8211, 0x0040,
+	0x2dfb, 0x1078, 0x23ca, 0x1078, 0x369f, 0x782b, 0x3008, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x702c, 0x8003, 0x0048, 0x2e0d, 0x2019,
+	0x4c5b, 0x1078, 0x2255, 0x702f, 0x8000, 0x1078, 0x38de, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x2e19, 0x0018, 0x2e19, 0x791a, 0xa006,
+	0x007c, 0xa085, 0x0001, 0x007c, 0xa684, 0x0060, 0x00c0, 0x2e26,
+	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e9f, 0xa684, 0x0800,
+	0x00c0, 0x2e48, 0x68b4, 0xa084, 0x4800, 0xa635, 0xa684, 0x0800,
+	0x00c0, 0x2e48, 0x6998, 0x6a94, 0x692e, 0x6a32, 0x703c, 0xa005,
+	0x00c0, 0x2e40, 0x2200, 0xa105, 0x0040, 0x2e47, 0x703f, 0x0015,
+	0x7000, 0xa086, 0x0006, 0x0040, 0x2e47, 0x1078, 0x4633, 0x007c,
+	0xa684, 0x0020, 0x0040, 0x2e6a, 0xa684, 0x4000, 0x0040, 0x2e56,
+	0x682f, 0x0000, 0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084,
+	0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x2e50, 0x703c, 0xa005,
+	0x00c0, 0x2e64, 0x703f, 0x0015, 0x79d8, 0x7adc, 0x692e, 0x6a32,
+	0x0078, 0x2e40, 0xa684, 0x4000, 0x0040, 0x2e74, 0x682f, 0x0000,
+	0x6833, 0x0000, 0x0078, 0x2e40, 0x68b4, 0xa084, 0x4800, 0xa635,
+	0xa684, 0x4000, 0x00c0, 0x2e6e, 0x703c, 0xa005, 0x00c0, 0x2e82,
+	0x703f, 0x0015, 0x79d8, 0x7adc, 0x78d0, 0x80fb, 0x00c8, 0x2e89,
+	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a32,
+	0x2100, 0xa205, 0x00c0, 0x2e96, 0x0078, 0x2e40, 0x7000, 0xa086,
+	0x0006, 0x0040, 0x2e9f, 0x1078, 0x49ed, 0x0078, 0x2e40, 0x007c,
+	0x6008, 0xa085, 0x0200, 0x600a, 0xa384, 0x0200, 0x0040, 0x2eac,
+	0x6008, 0xa085, 0x0002, 0x600a, 0x681b, 0x0006, 0x688f, 0x0000,
+	0x6893, 0x0000, 0x6a30, 0x692c, 0x6a3e, 0x6942, 0x682f, 0x0003,
+	0x6833, 0x0000, 0x6837, 0x0020, 0x6897, 0x0000, 0x689b, 0x0020,
+	0x68b3, 0x0000, 0x68af, 0x0000, 0x7000, 0x0079, 0x2ec7, 0x2461,
+	0x2ed1, 0x2eda, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x2ecf, 0x1078,
+	0x23ca, 0x6820, 0xa084, 0x0001, 0x00c0, 0x2eda, 0x1078, 0x33ae,
+	0x0078, 0x2ee0, 0x7060, 0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60,
+	0x2021, 0x505a, 0x2404, 0xa005, 0x0040, 0x2ee9, 0x2020, 0x0078,
+	0x2ee2, 0x2d22, 0x206b, 0x0000, 0x007c, 0x1078, 0x33b5, 0x1078,
+	0x33c4, 0x6008, 0xa084, 0xfdff, 0x600a, 0x682b, 0x0000, 0x789b,
+	0x000e, 0x6f14, 0x6817, 0x0002, 0x1078, 0x4a35, 0xa684, 0x0800,
+	0x0040, 0x2f06, 0x691c, 0xa18d, 0x2000, 0x691e, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x2f16, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x2f14,
+	0x681b, 0x001e, 0x0078, 0x2f16, 0x681b, 0x0000, 0x2021, 0x505a,
+	0x2404, 0xad06, 0x0040, 0x2f1d, 0x7460, 0x6800, 0x2022, 0x68c3,
+	0x0000, 0x6a3c, 0x6940, 0x6a32, 0x692e, 0x1078, 0x1c53, 0x0078,
+	0x2461, 0x1078, 0x2e1c, 0x682b, 0x0000, 0x2001, 0x000e, 0x6f14,
+	0x1078, 0x38e4, 0xa08c, 0x00ff, 0x6916, 0x6818, 0xa084, 0x8000,
+	0x0040, 0x2f3c, 0x703c, 0x681a, 0xa68c, 0xdf00, 0x691e, 0x706f,
+	0x0000, 0x0078, 0x2461, 0x7000, 0xa005, 0x00c0, 0x2f49, 0x0078,
+	0x2461, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000, 0x681b, 0x0014,
+	0xa68c, 0xdf00, 0x691e, 0x682b, 0x0000, 0x6820, 0xa085, 0x00ff,
+	0x6822, 0x7000, 0x0079, 0x2f5c, 0x2461, 0x2f66, 0x2f66, 0x2f68,
+	0x2f68, 0x2f68, 0x2f68, 0x2f64, 0x1078, 0x23ca, 0x1078, 0x33c4,
+	0x6008, 0xa084, 0xffef, 0x600a, 0x0078, 0x337e, 0x2300, 0x0079,
+	0x2f71, 0x2f74, 0x2f76, 0x2faf, 0x1078, 0x23ca, 0x7000, 0x0079,
+	0x2f79, 0x2461, 0x2f83, 0x2f83, 0x2f9e, 0x2f83, 0x2fab, 0x2f9e,
+	0x2f81, 0x1078, 0x23ca, 0xa684, 0x0060, 0xa086, 0x0060, 0x00c0,
+	0x2f9a, 0xa6b4, 0xffdf, 0xa6b4, 0xbfff, 0xa6b5, 0x2000, 0x7e5a,
+	0x681c, 0xa084, 0xffdf, 0x681e, 0x1078, 0x4633, 0x1078, 0x48f7,
+	0x0078, 0x3854, 0xa684, 0x2000, 0x0040, 0x2f8d, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x2fab, 0x681b, 0x0015, 0xa684, 0x4000, 0x0040,
+	0x2fab, 0x681b, 0x0007, 0x1078, 0x3868, 0x0078, 0x2438, 0x1078,
+	0x23ca, 0x2300, 0x0079, 0x2fb4, 0x2fb7, 0x2fb9, 0x2fec, 0x1078,
+	0x23ca, 0x7000, 0x0079, 0x2fbc, 0x2461, 0x2fc6, 0x2fc6, 0x2fe1,
+	0x2fc6, 0x2fe8, 0x2fe1, 0x2fc4, 0x1078, 0x23ca, 0xa684, 0x0060,
+	0xa086, 0x0060, 0x00c0, 0x2fdd, 0xa6b4, 0xffbf, 0xa6b4, 0xbfff,
+	0xa6b5, 0x2000, 0x7e5a, 0x681c, 0xa084, 0xffbf, 0x681e, 0x1078,
+	0x4633, 0x1078, 0x48f7, 0x0078, 0x3854, 0xa684, 0x2000, 0x0040,
+	0x2fd0, 0x6818, 0xa084, 0x8000, 0x0040, 0x2fe8, 0x681b, 0x0007,
+	0x781b, 0x00d2, 0x0078, 0x2438, 0x6820, 0xa085, 0x0004, 0x6822,
+	0x1078, 0x381f, 0xa6b5, 0x0800, 0x1078, 0x368f, 0x782b, 0x3008,
+	0x781b, 0x0065, 0x0078, 0x2438, 0x2300, 0x0079, 0x2fff, 0x3002,
+	0x3004, 0x3006, 0x1078, 0x23ca, 0x0078, 0x367b, 0xa684, 0x0400,
+	0x00c0, 0x302f, 0x79e4, 0xa184, 0x0020, 0x0040, 0x3016, 0x78ec,
+	0xa084, 0x0003, 0x0040, 0x3016, 0x782b, 0x3009, 0x789b, 0x0060,
+	0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x79e4, 0xa184, 0x0020,
+	0x0040, 0x3027, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x302b, 0x2001,
+	0x0014, 0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x3067, 0x7a90,
+	0xa294, 0x0007, 0x789b, 0x0060, 0x79a8, 0x81ff, 0x0040, 0x3065,
+	0x789b, 0x0010, 0x7ba8, 0xa384, 0x0001, 0x00c0, 0x3056, 0x7ba8,
+	0x7ba8, 0xa386, 0x0001, 0x00c0, 0x3049, 0x2009, 0xfff7, 0x0078,
+	0x304f, 0xa386, 0x0003, 0x00c0, 0x3056, 0x2009, 0xffef, 0x0c7e,
+	0x7054, 0x2060, 0x6004, 0xa104, 0x6006, 0x0c7f, 0x789b, 0x0060,
+	0x78ab, 0x0000, 0xa684, 0xfffb, 0x785a, 0x782b, 0x3009, 0x6920,
+	0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078, 0x3854, 0x297d,
+	0x2988, 0x3071, 0x3079, 0x306f, 0x306f, 0x3854, 0x3854, 0x1078,
+	0x23ca, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
+	0x385e, 0x6920, 0xa18c, 0xfdff, 0xa18c, 0xfeff, 0x6922, 0x0078,
+	0x3854, 0x79e4, 0xa184, 0x0030, 0x0040, 0x308b, 0x78ec, 0xa084,
+	0x0003, 0x00c0, 0x30b2, 0x7000, 0xa086, 0x0004, 0x00c0, 0x30a5,
+	0x706c, 0xa086, 0x0002, 0x00c0, 0x309b, 0x2011, 0x0002, 0x2019,
+	0x0000, 0x0078, 0x2827, 0x706c, 0xa086, 0x0006, 0x0040, 0x3095,
+	0x706c, 0xa086, 0x0004, 0x0040, 0x3095, 0x7000, 0xa086, 0x0000,
+	0x0040, 0x2438, 0x6818, 0xa085, 0x8000, 0x681a, 0x2001, 0x0014,
+	0x0078, 0x2cd7, 0xa184, 0x0007, 0x0079, 0x30b6, 0x3854, 0x3854,
+	0x30be, 0x3854, 0x38b9, 0x38b9, 0x3854, 0x3854, 0xa684, 0x0080,
+	0x0040, 0x30ed, 0x7194, 0x81ff, 0x0040, 0x30ed, 0xa182, 0x000d,
+	0x00d0, 0x30ce, 0x7097, 0x0000, 0x0078, 0x30d3, 0xa182, 0x000c,
+	0x7096, 0x2009, 0x000c, 0x789b, 0x0061, 0x79aa, 0x157e, 0x137e,
+	0x147e, 0x7098, 0x8114, 0xa210, 0x729a, 0xa080, 0x000b, 0xad00,
+	0x2098, 0x20a1, 0x012b, 0x789b, 0x0000, 0x8108, 0x81ac, 0x53a6,
+	0x147f, 0x137f, 0x157f, 0x0078, 0x385e, 0xa684, 0x0400, 0x00c0,
+	0x312e, 0x6820, 0xa084, 0x0001, 0x0040, 0x385e, 0xa68c, 0x0060,
+	0xa684, 0x0060, 0x0040, 0x3102, 0xa086, 0x0060, 0x00c0, 0x3102,
+	0xa18d, 0x4000, 0xa18c, 0xfffb, 0x795a, 0x69b6, 0x789b, 0x0060,
+	0x78ab, 0x0000, 0x789b, 0x0061, 0x6818, 0xa085, 0x8000, 0x681a,
+	0x78aa, 0x8008, 0x810c, 0x0040, 0x33dd, 0xa18c, 0x00f8, 0x00c0,
+	0x33dd, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012b, 0x789b, 0x0000,
+	0x8000, 0x80ac, 0xad80, 0x000b, 0x2098, 0x53a6, 0x147f, 0x137f,
+	0x157f, 0x6814, 0x8007, 0x7882, 0x0078, 0x385e, 0x6818, 0xa084,
+	0x8000, 0x0040, 0x3135, 0x681b, 0x0008, 0x781b, 0x00c8, 0x0078,
+	0x2438, 0x2300, 0x0079, 0x313c, 0x3141, 0x31e0, 0x313f, 0x1078,
+	0x23ca, 0x7000, 0xa084, 0x0007, 0x0079, 0x3146, 0x2461, 0x3150,
+	0x3185, 0x315b, 0x314e, 0x2461, 0x314e, 0x314e, 0x1078, 0x23ca,
+	0x681c, 0xa084, 0x2000, 0x0040, 0x3169, 0x6008, 0xa085, 0x0002,
+	0x600a, 0x0078, 0x3169, 0x68c0, 0xa005, 0x00c0, 0x3185, 0x6920,
+	0xa18d, 0x0001, 0x6922, 0x68c3, 0x0001, 0x6800, 0x706a, 0x0078,
+	0x317f, 0x6920, 0xa18d, 0x0001, 0x6922, 0x6800, 0x6006, 0xa005,
+	0x00c0, 0x3173, 0x6002, 0x681c, 0xa084, 0x000e, 0x0040, 0x317f,
+	0x7014, 0x68ba, 0x7130, 0xa188, 0x7300, 0x0078, 0x3181, 0x2009,
+	0x7400, 0x2104, 0x6802, 0x2d0a, 0x7162, 0x6eb6, 0xa684, 0x0060,
+	0x0040, 0x31de, 0xa684, 0x0800, 0x00c0, 0x3199, 0xa684, 0x7fff,
+	0x68b6, 0x6894, 0x68a6, 0x6898, 0x68aa, 0x1078, 0x4633, 0x0078,
+	0x31de, 0xa684, 0x0020, 0x0040, 0x31ae, 0x68c0, 0xa005, 0x0040,
+	0x31a5, 0x1078, 0x4a35, 0x0078, 0x31a8, 0xa006, 0x1078, 0x49ed,
+	0x79d8, 0x7adc, 0x69aa, 0x6aa6, 0x0078, 0x31b4, 0x1078, 0x37ca,
+	0x69aa, 0x6aa6, 0x1078, 0x49ed, 0xa684, 0x8000, 0x0040, 0x31de,
+	0xa684, 0x7fff, 0x68b6, 0x2001, 0x0076, 0x1078, 0x38e4, 0x2010,
+	0x2001, 0x0078, 0x1078, 0x38e4, 0x2008, 0xa684, 0x0020, 0x00c0,
+	0x31d6, 0x2001, 0x007a, 0x1078, 0x38e4, 0x801b, 0x00c8, 0x31d1,
+	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x6b98, 0x2100,
+	0xa302, 0x68b2, 0x6b94, 0x2200, 0xa303, 0x68ae, 0x0078, 0x2461,
+	0x0078, 0x367b, 0x7037, 0x0000, 0xa282, 0x0006, 0x0050, 0x31ea,
+	0x1078, 0x23ca, 0x7000, 0xa084, 0x0007, 0x10c0, 0x398a, 0x2300,
+	0x0079, 0x31f2, 0x31f5, 0x321e, 0x3232, 0x2200, 0x0079, 0x31f8,
+	0x321c, 0x367b, 0x31fe, 0x321c, 0x324e, 0x3290, 0x7003, 0x0005,
+	0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031, 0x2003,
+	0x0000, 0x8000, 0x0070, 0x320e, 0x0078, 0x3207, 0x157f, 0xad80,
+	0x0009, 0x7036, 0x6817, 0x0000, 0x68b7, 0x0700, 0x6823, 0x0800,
+	0x6827, 0x0003, 0x0078, 0x366b, 0x1078, 0x23ca, 0x7003, 0x0005,
+	0x2001, 0x7510, 0x2068, 0x704a, 0xad80, 0x0009, 0x7036, 0x2200,
+	0x0079, 0x322a, 0x367b, 0x3230, 0x3230, 0x324e, 0x3230, 0x367b,
+	0x1078, 0x23ca, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a,
+	0xad80, 0x0009, 0x7036, 0x2200, 0x0079, 0x323e, 0x3246, 0x3244,
+	0x3244, 0x3246, 0x3244, 0x3246, 0x1078, 0x23ca, 0x1078, 0x369f,
+	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7003, 0x0002,
+	0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8, 0xa484, 0x001f,
+	0xa215, 0x2069, 0x7400, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005,
+	0x0040, 0x3269, 0x6814, 0xa206, 0x0040, 0x3285, 0x6800, 0x0078,
+	0x325c, 0x7003, 0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x7036,
+	0x157e, 0x20a9, 0x0031, 0x2003, 0x0000, 0x8000, 0x0070, 0x327a,
+	0x0078, 0x3273, 0x157f, 0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7,
+	0x0700, 0x6823, 0x0800, 0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820,
+	0xa084, 0x0c00, 0x0040, 0x32df, 0x1078, 0x3697, 0x0078, 0x32df,
+	0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b, 0x0018, 0x7ca8,
+	0xa484, 0x001f, 0xa215, 0x79a8, 0x79a8, 0xa18c, 0x00ff, 0xa1e8,
+	0x7300, 0x2d04, 0x2d08, 0x7162, 0x2068, 0xa005, 0x0040, 0x32af,
+	0x6814, 0xa206, 0x0040, 0x32ca, 0x6800, 0x0078, 0x32a2, 0x7003,
+	0x0005, 0x2001, 0x7510, 0x2068, 0x704a, 0x157e, 0x20a9, 0x0031,
+	0x2003, 0x0000, 0x8000, 0x0070, 0x32bf, 0x0078, 0x32b8, 0x157f,
+	0xad80, 0x0009, 0x7036, 0x6a16, 0x68b7, 0x0700, 0x6823, 0x0800,
+	0x6827, 0x0003, 0x6eb4, 0x7e5a, 0x6820, 0xa084, 0x0c00, 0x0040,
+	0x32df, 0xa084, 0x0800, 0x0040, 0x32d9, 0x1078, 0x369b, 0x0078,
+	0x32df, 0x1078, 0x3697, 0x708b, 0x0000, 0x0078, 0x32df, 0x027e,
+	0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x5280,
+	0x2060, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e, 0xa684, 0x0060,
+	0x0040, 0x3337, 0x6b98, 0x6c94, 0x69ac, 0x68b0, 0xa105, 0x00c0,
+	0x3319, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a,
+	0xa684, 0x0060, 0xa086, 0x0060, 0x0040, 0x3337, 0x68c0, 0xa005,
+	0x0040, 0x3312, 0x7003, 0x0003, 0x682b, 0x0000, 0x1078, 0x48e6,
+	0x0078, 0x3314, 0x1078, 0x48f7, 0xa6b5, 0x2000, 0x7e5a, 0x0078,
+	0x3337, 0x68b0, 0xa31a, 0x2100, 0xa423, 0x2400, 0xa305, 0x0040,
+	0x3337, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0x68b0, 0xa6b4, 0xbfff,
+	0x7e5a, 0x007e, 0x68c0, 0xa005, 0x007f, 0x0040, 0x3335, 0x7003,
+	0x0003, 0x1078, 0x48e6, 0x0078, 0x3337, 0x1078, 0x4942, 0x077f,
+	0x1078, 0x37bd, 0x2009, 0x0065, 0xa684, 0x0004, 0x0040, 0x3358,
+	0x78e4, 0xa084, 0x0030, 0x0040, 0x3350, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x3350, 0x782b, 0x3008, 0x2009, 0x0065, 0x0078, 0x3358,
+	0x0f7e, 0x2079, 0x5000, 0x1078, 0x4633, 0x0f7f, 0x0040, 0x2461,
+	0x791a, 0x2d00, 0x704a, 0x8207, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa080, 0x5280, 0x2048, 0x0078, 0x2438, 0x6020, 0xa005,
+	0x0040, 0x3372, 0x8001, 0x6022, 0x6008, 0xa085, 0x0008, 0x600a,
+	0x7010, 0x6026, 0x007c, 0xa006, 0x1078, 0x4633, 0x6817, 0x0000,
+	0x681b, 0x0001, 0x6823, 0x0040, 0x681f, 0x0100, 0x7000, 0xa084,
+	0x0007, 0x0079, 0x3383, 0x2461, 0x338d, 0x338d, 0x33aa, 0x3395,
+	0x3393, 0x3395, 0x338b, 0x1078, 0x23ca, 0x1078, 0x33b5, 0x1078,
+	0x33ae, 0x1078, 0x1c53, 0x0078, 0x2461, 0x706c, 0x706f, 0x0000,
+	0x7093, 0x0000, 0x0079, 0x339c, 0x33a6, 0x33a6, 0x33a4, 0x33a4,
+	0x33a4, 0x33a6, 0x33a4, 0x33a6, 0x0079, 0x2840, 0x706f, 0x0000,
+	0x0078, 0x2461, 0x681b, 0x0000, 0x0078, 0x2eed, 0x6800, 0xa005,
+	0x00c0, 0x33b3, 0x6002, 0x6006, 0x007c, 0x6010, 0xa005, 0x0040,
+	0x33be, 0x8001, 0x00d0, 0x33be, 0x1078, 0x23ca, 0x6012, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x007c, 0x6018, 0xa005, 0x0040, 0x33ca,
+	0x8001, 0x601a, 0x007c, 0x1078, 0x38de, 0x681b, 0x0018, 0x0078,
+	0x3401, 0x1078, 0x38de, 0x681b, 0x0019, 0x0078, 0x3401, 0x1078,
+	0x38de, 0x681b, 0x001a, 0x0078, 0x3401, 0x1078, 0x38de, 0x681b,
+	0x0003, 0x0078, 0x3401, 0x7780, 0x1078, 0x37bd, 0x7184, 0xa18c,
+	0x00ff, 0xa1e8, 0x7300, 0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0,
+	0x33f3, 0x0078, 0x2461, 0x6814, 0x7280, 0xa206, 0x0040, 0x33fb,
+	0x6800, 0x0078, 0x33ec, 0x6800, 0x200a, 0x681b, 0x0005, 0x708b,
+	0x0000, 0x1078, 0x33b5, 0x6820, 0xa084, 0x0001, 0x00c0, 0x340a,
+	0x1078, 0x33ae, 0x1078, 0x33c4, 0x681f, 0x0000, 0x6823, 0x0020,
+	0x1078, 0x1c53, 0x0078, 0x2461, 0xa282, 0x0003, 0x00c0, 0x366b,
+	0x7da8, 0xa5ac, 0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0x6920, 0xa18d,
+	0x0080, 0x6922, 0xa184, 0x0100, 0x0040, 0x3478, 0xa18c, 0xfeff,
+	0x6922, 0xa4a4, 0x00ff, 0x0040, 0x3462, 0xa482, 0x000c, 0x0048,
+	0x3435, 0x0040, 0x3435, 0x2021, 0x000c, 0x852b, 0x852b, 0x1078,
+	0x372e, 0x0040, 0x343f, 0x1078, 0x3531, 0x0078, 0x346b, 0x1078,
+	0x36e9, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006, 0x1078,
+	0x3558, 0x0c7f, 0x6920, 0xa18d, 0x0100, 0x6922, 0x7e58, 0xa6b5,
+	0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x345c, 0x782b, 0x3008,
+	0x781b, 0x0056, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0065,
+	0x0078, 0x2438, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5, 0x6006,
+	0x1078, 0x3558, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0, 0x3474,
+	0x781b, 0x0058, 0x0078, 0x2438, 0x781b, 0x0065, 0x0078, 0x2438,
+	0x0c7e, 0x7054, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040, 0x34b8,
+	0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000c, 0x0048, 0x348c,
+	0x0040, 0x348c, 0x2011, 0x000c, 0x2400, 0xa202, 0x00c8, 0x3491,
+	0x2220, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0,
+	0x34a1, 0xa282, 0x0019, 0x00c8, 0x34a7, 0x2011, 0x0019, 0x0078,
+	0x34a7, 0xa282, 0x000c, 0x00c8, 0x34a7, 0x2011, 0x000c, 0x2200,
+	0xa502, 0x00c8, 0x34ac, 0x2228, 0x1078, 0x36ed, 0x852b, 0x852b,
+	0x1078, 0x372e, 0x0040, 0x34b8, 0x1078, 0x3531, 0x0078, 0x34bc,
+	0x1078, 0x36e9, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a,
+	0x0c7f, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e,
+	0x2960, 0x6000, 0xa084, 0x1000, 0x00c0, 0x34df, 0x6010, 0xa084,
+	0x000f, 0x00c0, 0x34d9, 0x6104, 0xa18c, 0xfff5, 0x6106, 0x0c7f,
+	0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078, 0x3506, 0x68a0,
+	0xa084, 0x0200, 0x00c0, 0x34d9, 0x6208, 0xa294, 0x00ff, 0x7018,
+	0xa086, 0x0028, 0x00c0, 0x34f4, 0xa282, 0x0019, 0x00c8, 0x34fa,
+	0x2011, 0x0019, 0x0078, 0x34fa, 0xa282, 0x000c, 0x00c8, 0x34fa,
+	0x2011, 0x000c, 0x6308, 0x831f, 0xa39c, 0x00ff, 0xa382, 0x000c,
+	0x0048, 0x3506, 0x0040, 0x3506, 0x2019, 0x000c, 0x78ab, 0x0001,
+	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005,
+	0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f, 0x007c, 0x0c7e, 0x2960,
+	0xa18c, 0xfff5, 0x6106, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078,
+	0x3521, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7aaa,
+	0x7baa, 0xa8c0, 0x0005, 0x6820, 0xa085, 0x0100, 0x6822, 0x0c7f,
+	0x007c, 0x0c7e, 0x7154, 0x2160, 0x1078, 0x3538, 0x0c7f, 0x007c,
+	0x2008, 0xa084, 0xfff0, 0xa425, 0x7c86, 0x6018, 0x789a, 0x7cae,
+	0x6412, 0x78a4, 0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6,
+	0x6016, 0x788a, 0xa4a4, 0x000f, 0x8427, 0x8204, 0x8004, 0xa084,
+	0x00ff, 0xa405, 0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x007c,
+	0x0c7e, 0x7054, 0x2060, 0x1078, 0x355f, 0x0c7f, 0x007c, 0x6018,
+	0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6, 0x6012, 0x7884, 0xa084,
+	0xfff0, 0x7886, 0x007c, 0xa282, 0x0002, 0x00c0, 0x366b, 0x7aa8,
+	0x6920, 0xa18d, 0x0080, 0x6922, 0xa184, 0x0200, 0x0040, 0x35b4,
+	0xa18c, 0xfdff, 0x6922, 0xa294, 0x00ff, 0xa282, 0x0002, 0x00c8,
+	0x366b, 0x1078, 0x35fd, 0x1078, 0x3558, 0xa980, 0x0001, 0x200c,
+	0x1078, 0x37b9, 0x1078, 0x34c7, 0x88ff, 0x0040, 0x35a7, 0x789b,
+	0x0060, 0x2800, 0x78aa, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
+	0x0400, 0x00c0, 0x35a1, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078,
+	0x2438, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x7e58,
+	0xa684, 0x0400, 0x00c0, 0x35b0, 0x781b, 0x0058, 0x0078, 0x2438,
+	0x781b, 0x0065, 0x0078, 0x2438, 0xa282, 0x0002, 0x00c8, 0x35bc,
+	0xa284, 0x0001, 0x0040, 0x35c6, 0x7154, 0xa188, 0x0000, 0x210c,
+	0xa18c, 0x2000, 0x00c0, 0x35c6, 0x2011, 0x0000, 0x1078, 0x36db,
+	0x1078, 0x35fd, 0x1078, 0x3558, 0x7858, 0xa085, 0x0004, 0x785a,
+	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x0c7e, 0x027e,
+	0x2960, 0x6000, 0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x35ed,
+	0x6014, 0xa084, 0x0040, 0x00c0, 0x35eb, 0xa18c, 0xffef, 0x6106,
+	0xa006, 0x0078, 0x35fa, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab,
+	0x0002, 0x78ab, 0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x6820, 0xa085,
+	0x0200, 0x6822, 0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7054, 0x2060,
+	0x1078, 0x3604, 0x0c7f, 0x007c, 0x82ff, 0x0040, 0x3609, 0x2011,
+	0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4, 0xa084, 0xffbf,
+	0xa205, 0x78a6, 0x788a, 0x6016, 0x6004, 0xa084, 0xffef, 0x6006,
+	0x007c, 0x007e, 0x7000, 0xa086, 0x0003, 0x0040, 0x3622, 0x007f,
+	0x0078, 0x3625, 0x007f, 0x0078, 0x3667, 0xa684, 0x0020, 0x0040,
+	0x3667, 0x7888, 0xa084, 0x0040, 0x0040, 0x3667, 0x7bb8, 0xa384,
+	0x003f, 0x831b, 0x00c8, 0x3635, 0x8000, 0xa005, 0x0040, 0x364b,
+	0x831b, 0x00c8, 0x363e, 0x8001, 0x0040, 0x3663, 0xa684, 0x4000,
+	0x0040, 0x364b, 0x78b8, 0x801b, 0x00c8, 0x3647, 0x8000, 0xa084,
+	0x003f, 0x00c0, 0x3663, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc,
+	0x2001, 0x0001, 0xa108, 0x00c8, 0x3657, 0xa291, 0x0000, 0x79d2,
+	0x79da, 0x7ad6, 0x7ade, 0x1078, 0x49ed, 0x781b, 0x0064, 0x1078,
+	0x4872, 0x0078, 0x2438, 0x781b, 0x0064, 0x0078, 0x2438, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x1078, 0x36a3, 0x782b, 0x3008, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x1078, 0x368f, 0x782b, 0x3008, 0x781b,
+	0x0065, 0x0078, 0x2438, 0x6827, 0x0002, 0x1078, 0x3697, 0x78e4,
+	0xa084, 0x0030, 0x0040, 0x2461, 0x78ec, 0xa084, 0x0003, 0x0040,
+	0x2461, 0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x2001,
+	0x0005, 0x0078, 0x36a5, 0x2001, 0x000c, 0x0078, 0x36a5, 0x2001,
+	0x0006, 0x0078, 0x36a5, 0x2001, 0x000d, 0x0078, 0x36a5, 0x2001,
+	0x0009, 0x0078, 0x36a5, 0x2001, 0x0007, 0x789b, 0x0010, 0x78aa,
+	0x789b, 0x0060, 0x78ab, 0x0001, 0xa6b5, 0x0004, 0x7e5a, 0x007c,
+	0x077e, 0x873f, 0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0,
+	0x5280, 0xa7b8, 0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040,
+	0x36c9, 0xa184, 0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008,
+	0x6006, 0x8738, 0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040,
+	0x36d9, 0xa184, 0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010,
+	0x6006, 0x077f, 0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab,
+	0x0002, 0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004,
+	0x007c, 0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab,
+	0x0001, 0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b,
+	0x0060, 0x78ab, 0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff,
+	0x8003, 0x8003, 0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0,
+	0x2001, 0x5046, 0x2004, 0xa082, 0x0028, 0x0040, 0x3717, 0x2021,
+	0x37a0, 0x2019, 0x0014, 0x20a9, 0x000c, 0x0078, 0x371d, 0x2021,
+	0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404,
+	0xa084, 0xfff0, 0xa106, 0x0040, 0x372c, 0x8420, 0x2300, 0xa210,
+	0x0070, 0x372c, 0x0078, 0x371f, 0x157f, 0x007c, 0x157e, 0x2009,
+	0x5046, 0x210c, 0xa182, 0x0032, 0x0048, 0x3742, 0x0040, 0x3746,
+	0x2009, 0x3792, 0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032,
+	0x0078, 0x3758, 0xa182, 0x0028, 0x0040, 0x3750, 0x2009, 0x37a0,
+	0x2019, 0x0014, 0x20a9, 0x000c, 0x2011, 0x0064, 0x0078, 0x3758,
+	0x2009, 0x37ac, 0x2019, 0x0019, 0x20a9, 0x000d, 0x2011, 0x0064,
+	0x2200, 0xa502, 0x0040, 0x3768, 0x0048, 0x3768, 0x8108, 0x2300,
+	0xa210, 0x0070, 0x3765, 0x0078, 0x3758, 0x157f, 0xa006, 0x007c,
+	0x157f, 0xa582, 0x0064, 0x00c8, 0x3777, 0x7808, 0xa085, 0x0070,
+	0x780a, 0x7044, 0xa085, 0x0070, 0x7046, 0x0078, 0x3777, 0x78ec,
+	0xa084, 0x0300, 0x0040, 0x377f, 0x2104, 0x0078, 0x3790, 0x2104,
+	0xa09e, 0x1102, 0x00c0, 0x3790, 0x2001, 0x04fd, 0x2004, 0xa082,
+	0x0005, 0x0048, 0x378f, 0x2001, 0x1201, 0x0078, 0x3790, 0x2104,
+	0xa005, 0x007c, 0x1102, 0x3002, 0x3202, 0x4203, 0x4403, 0x5404,
+	0x5604, 0x6605, 0x6805, 0x7806, 0x7a06, 0x0c07, 0x0c07, 0x0e07,
+	0x3202, 0x4202, 0x5202, 0x6202, 0x7202, 0x6605, 0x7605, 0x7805,
+	0x7a05, 0x7c05, 0x7e05, 0x7f05, 0x2202, 0x3202, 0x4202, 0x5202,
+	0x5404, 0x6404, 0x7404, 0x7604, 0x7804, 0x7a04, 0x7c04, 0x7e04,
+	0x7f04, 0x789b, 0x0010, 0xa046, 0x007c, 0xa784, 0x0f00, 0x800b,
+	0xa784, 0x001f, 0x8003, 0x8003, 0x8003, 0x8003, 0xa105, 0xa0e0,
+	0x5300, 0x007c, 0x79d8, 0x7adc, 0x78d0, 0x801b, 0x00c8, 0x37d1,
+	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x007c, 0x0f7e,
+	0x2079, 0x0100, 0x2009, 0x5040, 0x2091, 0x8000, 0x2104, 0x0079,
+	0x37e1, 0x3817, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb, 0x37eb,
+	0x381b, 0x1078, 0x23ca, 0x784b, 0x0004, 0x7848, 0xa084, 0x0004,
+	0x00c0, 0x37ed, 0x784b, 0x0008, 0x7848, 0xa084, 0x0008, 0x00c0,
+	0x37f4, 0x68b4, 0xa085, 0x4000, 0x68b6, 0x7858, 0xa085, 0x4000,
+	0x785a, 0x7830, 0xa084, 0x0080, 0x00c0, 0x3817, 0x0018, 0x3817,
+	0x681c, 0xa084, 0x0020, 0x00c0, 0x3815, 0x0e7e, 0x2071, 0x5040,
+	0x1078, 0x3868, 0x0e7f, 0x0078, 0x3817, 0x781b, 0x00d2, 0x2091,
+	0x8001, 0x0f7f, 0x007c, 0x1078, 0x3a42, 0x0078, 0x3817, 0x0c7e,
+	0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0,
+	0x5280, 0x6004, 0xa084, 0x000a, 0x00c0, 0x3852, 0x6108, 0xa194,
+	0xff00, 0x0040, 0x3852, 0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106,
+	0x0040, 0x3841, 0x2001, 0x0032, 0xa106, 0x0040, 0x3845, 0x0078,
+	0x3849, 0x2009, 0x0020, 0x0078, 0x384b, 0x2009, 0x003f, 0x0078,
+	0x384b, 0x2011, 0x0000, 0x2100, 0xa205, 0x600a, 0x6004, 0xa085,
+	0x0002, 0x6006, 0x0c7f, 0x007c, 0x781b, 0x0065, 0x0078, 0x2438,
+	0x782b, 0x3008, 0x781b, 0x0065, 0x0078, 0x2438, 0x781b, 0x0058,
+	0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0056, 0x0078, 0x2438,
+	0x2009, 0x5020, 0x210c, 0xa186, 0x0000, 0x0040, 0x387c, 0xa186,
+	0x0001, 0x0040, 0x387f, 0x2009, 0x5038, 0x200b, 0x000b, 0x706f,
+	0x0001, 0x781b, 0x0048, 0x007c, 0x781b, 0x00cc, 0x007c, 0x2009,
+	0x5038, 0x200b, 0x000a, 0x007c, 0x2009, 0x5020, 0x210c, 0xa186,
+	0x0000, 0x0040, 0x389f, 0xa186, 0x0001, 0x0040, 0x3899, 0x2009,
+	0x5038, 0x200b, 0x000b, 0x706f, 0x0001, 0x781b, 0x0048, 0x0078,
+	0x2438, 0x2009, 0x5038, 0x200b, 0x000a, 0x0078, 0x2438, 0x782b,
+	0x3008, 0x781b, 0x00cc, 0x0078, 0x2438, 0x781b, 0x00d2, 0x0078,
+	0x2438, 0x782b, 0x3008, 0x781b, 0x00d2, 0x0078, 0x2438, 0x781b,
+	0x0093, 0x0078, 0x2438, 0x782b, 0x3008, 0x781b, 0x0093, 0x0078,
+	0x2438, 0x6818, 0xa084, 0x8000, 0x0040, 0x38c0, 0x681b, 0x001d,
+	0x706f, 0x0001, 0x781b, 0x0048, 0x0078, 0x2438, 0x007e, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x38dc, 0x7808, 0xa084, 0xfffc, 0x780a,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+	0x38dc, 0x7044, 0x780a, 0xa005, 0x007f, 0x007c, 0x7044, 0xa085,
+	0x0002, 0x7046, 0x780a, 0x007c, 0x007e, 0x7830, 0xa084, 0x0040,
+	0x00c0, 0x38e5, 0x0098, 0x38f0, 0x007f, 0x789a, 0x78ac, 0x007c,
+	0x7808, 0xa084, 0xfffd, 0x780a, 0x0005, 0x0005, 0x0005, 0x0005,
+	0x78ec, 0xa084, 0x0021, 0x0040, 0x38ff, 0x0098, 0x38fd, 0x007f,
+	0x789a, 0x78ac, 0x007e, 0x7044, 0x780a, 0x007f, 0x007c, 0x78ec,
+	0xa084, 0x0002, 0x00c0, 0x461d, 0xa784, 0x007d, 0x00c0, 0x3913,
+	0x2700, 0x1078, 0x23ca, 0xa784, 0x0001, 0x00c0, 0x2f43, 0xa784,
+	0x0070, 0x0040, 0x3923, 0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x2375,
+	0x2d78, 0x2c68, 0x0c7f, 0xa784, 0x0008, 0x0040, 0x3930, 0x784b,
+	0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461, 0x0078, 0x3854,
+	0xa784, 0x0004, 0x0040, 0x3963, 0x78b8, 0xa084, 0x4001, 0x0040,
+	0x3963, 0x784b, 0x0008, 0x78ec, 0xa084, 0x0003, 0x0040, 0x2461,
+	0x78e4, 0xa084, 0x0007, 0xa086, 0x0001, 0x00c0, 0x3963, 0x78c0,
+	0xa085, 0x4800, 0x2030, 0x7e5a, 0x781b, 0x00d2, 0x0078, 0x2438,
+	0x784b, 0x0008, 0x6818, 0xa084, 0x8000, 0x0040, 0x395f, 0x681b,
+	0x0015, 0xa684, 0x4000, 0x0040, 0x395f, 0x681b, 0x0007, 0x1078,
+	0x3868, 0x0078, 0x2438, 0x681b, 0x0003, 0x7858, 0xa084, 0x3f00,
+	0x681e, 0x682f, 0x0000, 0x6833, 0x0000, 0x784b, 0x0008, 0x78ec,
+	0xa084, 0x0003, 0x0040, 0x2944, 0x0018, 0x2438, 0x0078, 0x3673,
+	0x6b14, 0x8307, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080,
+	0x5280, 0x2060, 0x2048, 0x7056, 0x6000, 0x705a, 0x6004, 0x705e,
+	0x2a60, 0x007c, 0x0079, 0x398c, 0x3994, 0x3995, 0x3994, 0x3997,
+	0x3994, 0x3994, 0x3994, 0x399c, 0x007c, 0x1078, 0x33c4, 0x1078,
+	0x4633, 0x7038, 0x600a, 0x007c, 0x70a0, 0xa005, 0x0040, 0x39a9,
+	0x2068, 0x1078, 0x1b45, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x70a3,
+	0x0000, 0x007c, 0x0e7e, 0x2091, 0x8000, 0x2071, 0x5040, 0x7000,
+	0xa086, 0x0007, 0x00c0, 0x39c0, 0x6110, 0x70bc, 0xa106, 0x00c0,
+	0x39c0, 0x0e7f, 0x1078, 0x1b52, 0x1078, 0x39c6, 0xa006, 0x007c,
+	0x2091, 0x8001, 0x0e7f, 0xa085, 0x0001, 0x007c, 0x0f7e, 0x0e7e,
+	0x2071, 0x5040, 0x0078, 0x21d9, 0x785b, 0x0000, 0x70af, 0x000e,
+	0x2009, 0x0100, 0x017e, 0x70a0, 0xa06d, 0x0040, 0x39db, 0x70a3,
+	0x0000, 0x0078, 0x39e1, 0x70b3, 0x0000, 0x1078, 0x1b6e, 0x0040,
+	0x39e7, 0x70ac, 0x6826, 0x1078, 0x3ac2, 0x0078, 0x39db, 0x017f,
+	0x157e, 0x0c7e, 0x0d7e, 0x20a9, 0x0008, 0x2061, 0x7410, 0x6000,
+	0xa105, 0x6002, 0x601c, 0xa06d, 0x0040, 0x39ff, 0x6800, 0x601e,
+	0x1078, 0x193d, 0x6008, 0x8000, 0x600a, 0x0078, 0x39f2, 0x6018,
+	0xa06d, 0x0040, 0x3a09, 0x6800, 0x601a, 0x1078, 0x193d, 0x0078,
+	0x39ff, 0xace0, 0x0008, 0x0070, 0x3a0f, 0x0078, 0x39ef, 0x709c,
+	0xa084, 0x8000, 0x0040, 0x3a16, 0x1078, 0x3b3c, 0x0d7f, 0x0c7f,
+	0x157f, 0x007c, 0x127e, 0x2091, 0x2300, 0x6804, 0xa084, 0x000f,
+	0x0079, 0x3a22, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32,
+	0x3a34, 0x3a3a, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a32, 0x3a3c,
+	0x3a32, 0x3a34, 0x1078, 0x23ca, 0x1078, 0x4466, 0x1078, 0x193d,
+	0x0078, 0x3a40, 0x6827, 0x000b, 0x1078, 0x4466, 0x1078, 0x3ac2,
+	0x127f, 0x007c, 0x127e, 0x2091, 0x2300, 0x0098, 0x3a5e, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x3a5e, 0x0d7e, 0x1078, 0x45c5, 0x2d00,
+	0x682e, 0x2009, 0x0004, 0x2001, 0x0000, 0x6827, 0x0084, 0x1078,
+	0x457e, 0x1078, 0x3ac2, 0x0d7f, 0x0078, 0x3a90, 0x7948, 0xa185,
+	0x4000, 0x784a, 0x0098, 0x3a67, 0x794a, 0x0078, 0x3a4c, 0x7828,
+	0xa086, 0x1834, 0x00c0, 0x3a70, 0xa185, 0x0004, 0x0078, 0x3a77,
+	0x7828, 0xa186, 0x1814, 0x00c0, 0x3a64, 0xa185, 0x000c, 0x784a,
+	0x789b, 0x000e, 0x78ab, 0x0002, 0x7858, 0xa084, 0x00ff, 0xa085,
+	0x0400, 0x785a, 0x70b4, 0xa080, 0x0091, 0x781a, 0x6827, 0x0002,
+	0x6827, 0x0084, 0x2009, 0x0004, 0x2001, 0x0000, 0x1078, 0x457e,
+	0x127f, 0x007c, 0x0d7e, 0x6b14, 0x1078, 0x1be0, 0x0040, 0x3a9f,
+	0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3a94, 0x0d7f,
+	0x007c, 0x0d7e, 0x6b14, 0x6c28, 0xa4a4, 0x00ff, 0x1078, 0x1b7e,
+	0x0040, 0x3aaf, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0d7f,
+	0x007c, 0x0d7e, 0x6b14, 0xa39c, 0x00ff, 0x1078, 0x1bb1, 0x0040,
+	0x3ac0, 0x2068, 0x6827, 0x0002, 0x1078, 0x3ac2, 0x0078, 0x3ab5,
+	0x0d7f, 0x007c, 0x0c7e, 0x6914, 0x1078, 0x3b33, 0x6904, 0xa18c,
+	0x00ff, 0xa186, 0x0006, 0x0040, 0x3add, 0xa186, 0x000d, 0x0040,
+	0x3afc, 0xa186, 0x0017, 0x00c0, 0x3ad9, 0x1078, 0x193d, 0x0078,
+	0x3adb, 0x1078, 0x1c55, 0x0c7f, 0x007c, 0x6004, 0x8001, 0x0048,
+	0x3afa, 0x6006, 0x2009, 0x0000, 0xa684, 0x0001, 0x00c0, 0x3aea,
+	0xa18d, 0x8000, 0xa684, 0x0004, 0x0040, 0x3af0, 0xa18d, 0x0002,
+	0x691e, 0x6823, 0x0000, 0x7104, 0x810f, 0x6818, 0xa105, 0x681a,
+	0x0078, 0x3ad9, 0x1078, 0x23ca, 0x6018, 0xa005, 0x00c0, 0x3b0b,
+	0x6008, 0x8001, 0x0048, 0x3b0b, 0x600a, 0x601c, 0x6802, 0x2d00,
+	0x601e, 0x0078, 0x3b21, 0xac88, 0x0006, 0x2104, 0xa005, 0x0040,
+	0x3b14, 0x2008, 0x0078, 0x3b0d, 0x6802, 0x2d0a, 0x6008, 0x8001,
+	0x0048, 0x3adb, 0x600a, 0x6018, 0x2068, 0x6800, 0x601a, 0x0078,
+	0x3b05, 0x157e, 0x137e, 0x147e, 0x0c7e, 0x0d7e, 0x1078, 0x191a,
+	0x2da0, 0x137f, 0x20a9, 0x0031, 0x53a3, 0x0c7f, 0x147f, 0x137f,
+	0x157f, 0x0078, 0x3ad9, 0xa184, 0x001f, 0x8003, 0x8003, 0x8003,
+	0xa080, 0x7410, 0x2060, 0x007c, 0x2019, 0x5051, 0x2304, 0xa085,
+	0x0001, 0x201a, 0x2019, 0x0102, 0x2304, 0xa085, 0x0001, 0x201a,
+	0x007c, 0x2019, 0x5051, 0x2304, 0xa084, 0xfffe, 0x201a, 0x2019,
+	0x0102, 0x2304, 0xa084, 0xfffe, 0x201a, 0x007c, 0x7990, 0xa18c,
+	0xfff8, 0x7992, 0x70b4, 0xa080, 0x00d8, 0x781a, 0x0078, 0x2438,
+	0x70a3, 0x0000, 0x7003, 0x0000, 0x7043, 0x0001, 0x7037, 0x0000,
+	0x0018, 0x23ef, 0x1078, 0x1b6e, 0x0040, 0x3b91, 0x2009, 0x500f,
+	0x200b, 0x0000, 0x68bc, 0x2060, 0x6100, 0xa184, 0x0300, 0x0040,
+	0x3b85, 0x6827, 0x000e, 0xa084, 0x0200, 0x0040, 0x3b81, 0x6827,
+	0x0017, 0x1078, 0x3ac2, 0x0078, 0x3b60, 0x7000, 0xa086, 0x0007,
+	0x00c0, 0x3be3, 0x2d00, 0x70a2, 0xad80, 0x000f, 0x7036, 0x0078,
+	0x3b98, 0x7040, 0xa086, 0x0001, 0x0040, 0x2471, 0x0078, 0x2438,
+	0x2031, 0x0000, 0x691c, 0xa184, 0x0002, 0x0040, 0x3ba1, 0xa6b5,
+	0x0004, 0xa184, 0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72,
+	0x2004, 0xa635, 0x6820, 0xa084, 0x0400, 0x0040, 0x3bb9, 0x789b,
+	0x0018, 0x78ab, 0x0003, 0x789b, 0x0081, 0x78ab, 0x0001, 0xa6b5,
+	0x1000, 0x6820, 0xa084, 0x8000, 0x0040, 0x3bc5, 0xa6b5, 0x0400,
+	0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0xa684, 0x0200, 0x0040,
+	0x3bdf, 0x682c, 0x78d2, 0x6830, 0x78d6, 0xa684, 0x0100, 0x0040,
+	0x3bdd, 0x682c, 0xa084, 0x0001, 0x0040, 0x3bdd, 0x7888, 0xa084,
+	0x0040, 0x0040, 0x3bdd, 0xa6b5, 0x8000, 0x1078, 0x45ad, 0x7e5a,
+	0x6eb6, 0x0078, 0x45e4, 0x1078, 0x38c6, 0x00c0, 0x3c6c, 0x702c,
+	0x8004, 0x0048, 0x3bf1, 0x2019, 0x4cfd, 0x1078, 0x2255, 0x702f,
+	0x0001, 0x2011, 0x0001, 0x2031, 0x1000, 0x789b, 0x0018, 0x6814,
+	0xa084, 0x001f, 0xa085, 0x0080, 0x78aa, 0x691c, 0xa184, 0x0002,
+	0x0040, 0x3c0a, 0xa6b5, 0x0004, 0x78ab, 0x0020, 0x6828, 0x78aa,
+	0xa290, 0x0002, 0x6820, 0xa084, 0x8000, 0x0040, 0x3c18, 0xa6b5,
+	0x0400, 0x789b, 0x000e, 0x6824, 0x8007, 0x78aa, 0x0078, 0x3c26,
+	0x681c, 0xa084, 0x8000, 0x00c0, 0x3c26, 0xa6b5, 0x0800, 0x6820,
+	0xa084, 0x0100, 0x0040, 0x3c26, 0xa6b5, 0x4000, 0x681c, 0xa084,
+	0x00c0, 0x8003, 0x8003, 0x8007, 0xa080, 0x3c72, 0x2004, 0xa635,
+	0xa684, 0x0100, 0x0040, 0x3c40, 0x682c, 0xa084, 0x0001, 0x0040,
+	0x3c40, 0x7888, 0xa084, 0x0040, 0x0040, 0x3c40, 0xa6b5, 0x8000,
+	0x789b, 0x007e, 0x7eae, 0x6eb6, 0x6814, 0x8007, 0x78aa, 0x7882,
+	0x7aaa, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x3c6c, 0x0018, 0x3c6c,
+	0x70b4, 0xa080, 0x00dd, 0x781a, 0x1078, 0x38de, 0xa684, 0x0200,
+	0x0040, 0x3c60, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad,
+	0x2d00, 0x70a2, 0x704a, 0x6810, 0x70be, 0x7003, 0x0007, 0xad80,
+	0x000f, 0x7036, 0x0078, 0x2438, 0x1078, 0x1b45, 0x1078, 0x38de,
+	0x0078, 0x2438, 0x0000, 0x0300, 0x0200, 0x0000, 0x1078, 0x23ca,
+	0x2300, 0x0079, 0x3c7b, 0x3c7e, 0x3c7e, 0x3c80, 0x1078, 0x23ca,
+	0x1078, 0x45bc, 0x6924, 0xa184, 0x00ff, 0xa086, 0x000a, 0x0040,
+	0x3c92, 0xa184, 0xff00, 0xa085, 0x000a, 0x6826, 0x1078, 0x1b45,
+	0x0078, 0x3b60, 0x2001, 0x000a, 0x1078, 0x454c, 0x0078, 0x3b60,
+	0xa282, 0x0005, 0x0050, 0x3c9e, 0x1078, 0x23ca, 0x7000, 0xa084,
+	0x0007, 0x10c0, 0x398a, 0x1078, 0x191a, 0x00c0, 0x3cbd, 0xa684,
+	0x0004, 0x0040, 0x3caf, 0x2001, 0x2800, 0x0078, 0x3cb1, 0x2001,
+	0x0800, 0x71b4, 0xa188, 0x0091, 0x789b, 0x000e, 0x78aa, 0x2031,
+	0x0400, 0x7e5a, 0x791a, 0x0078, 0x2438, 0x6807, 0x0106, 0x680b,
+	0x0000, 0x689f, 0x0000, 0x6827, 0x0000, 0xa386, 0x0002, 0x00c0,
+	0x3cde, 0xa286, 0x0002, 0x00c0, 0x3cde, 0x78a0, 0xa005, 0x00c0,
+	0x3cde, 0xa484, 0x8000, 0x00c0, 0x3cde, 0x78e4, 0xa084, 0x0008,
+	0x0040, 0x3cde, 0xa6b5, 0x0008, 0x2019, 0x0000, 0x1078, 0x40d3,
+	0x2d00, 0x70a2, 0x704a, 0x7003, 0x0007, 0x7037, 0x0000, 0x6824,
+	0xa084, 0x0080, 0x0040, 0x3cf0, 0x1078, 0x4180, 0x0078, 0x2438,
+	0x2300, 0x0079, 0x3cf3, 0x3cf6, 0x3d77, 0x3d96, 0x2200, 0x0079,
+	0x3cf9, 0x3cfe, 0x3d0e, 0x3d34, 0x3d40, 0x3d63, 0x2029, 0x0001,
+	0xa026, 0x2011, 0x0000, 0x1078, 0x428d, 0x0079, 0x3d07, 0x3d0c,
+	0x2438, 0x3b60, 0x3d0c, 0x3d0c, 0x1078, 0x23ca, 0x7990, 0xa18c,
+	0x0007, 0x00c0, 0x3d15, 0x2009, 0x0008, 0x2011, 0x0001, 0xa684,
+	0x0004, 0x0040, 0x3d1d, 0x2011, 0x0003, 0x2220, 0xa12a, 0x2011,
+	0x0001, 0x1078, 0x428d, 0x0079, 0x3d25, 0x3d2a, 0x2438, 0x3b60,
+	0x3d32, 0x3d2c, 0x0078, 0x45ea, 0x70ab, 0x3d30, 0x0078, 0x2438,
+	0x0078, 0x3d2a, 0x1078, 0x23ca, 0xa684, 0x0010, 0x0040, 0x3d3e,
+	0x1078, 0x414f, 0x0040, 0x3d3e, 0x0078, 0x2438, 0x0078, 0x41bc,
+	0x6000, 0xa084, 0x0002, 0x0040, 0x3d5d, 0x70b4, 0xa080, 0x00cd,
+	0x781a, 0x0d7e, 0x1078, 0x45c5, 0x2d00, 0x682e, 0x6827, 0x0000,
+	0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x193d, 0x7003, 0x0000, 0x7037,
+	0x0000, 0x704b, 0x0000, 0x0078, 0x3b60, 0xa684, 0x0004, 0x00c0,
+	0x3d63, 0x0078, 0x45ea, 0x6000, 0xa084, 0x0004, 0x00c0, 0x3d75,
+	0x6000, 0xa084, 0x0001, 0x0040, 0x3d75, 0x70ab, 0x3d75, 0x2001,
+	0x0007, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x2200,
+	0x0079, 0x3d7a, 0x3d7f, 0x3d7f, 0x3d7f, 0x3d81, 0x3d7f, 0x1078,
+	0x23ca, 0x70a7, 0x3d85, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078,
+	0x4287, 0x0079, 0x3d8b, 0x3d90, 0x2438, 0x3b60, 0x3d92, 0x3d94,
+	0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x2200, 0x0079,
+	0x3d99, 0x3d9e, 0x3da0, 0x3da0, 0x3d9e, 0x3d9e, 0x1078, 0x23ca,
+	0x78e4, 0xa084, 0x0008, 0x0040, 0x3db5, 0x70a7, 0x3da9, 0x0078,
+	0x45f6, 0x2011, 0x0004, 0x1078, 0x4287, 0x0079, 0x3daf, 0x3db5,
+	0x2438, 0x3b60, 0x3db5, 0x3dbf, 0x3dc3, 0x70ab, 0x3dbd, 0x2001,
+	0x0003, 0x1078, 0x4544, 0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab,
+	0x3db5, 0x0078, 0x2438, 0x70ab, 0x3dc7, 0x0078, 0x2438, 0x0078,
+	0x3dbd, 0xa282, 0x0003, 0x0050, 0x3dcf, 0x1078, 0x23ca, 0xa386,
+	0x0002, 0x00c0, 0x3de8, 0xa286, 0x0002, 0x00c0, 0x3dee, 0x78a0,
+	0xa005, 0x00c0, 0x3dee, 0xa484, 0x8000, 0x00c0, 0x3dee, 0x78e4,
+	0xa084, 0x0008, 0x0040, 0x3de8, 0xa6b5, 0x0008, 0x2019, 0x0000,
+	0xa684, 0x0008, 0x0040, 0x3dee, 0x1078, 0x412c, 0x6810, 0x70be,
+	0x7003, 0x0007, 0x2300, 0x0079, 0x3df5, 0x3df8, 0x3e25, 0x3e2d,
+	0x2200, 0x0079, 0x3dfb, 0x3e00, 0x3dfe, 0x3e19, 0x1078, 0x23ca,
+	0x7990, 0xa1ac, 0x0007, 0xa026, 0x2011, 0x0001, 0x1078, 0x428d,
+	0x0079, 0x3e0a, 0x3e0f, 0x2438, 0x3b60, 0x3e17, 0x3e11, 0x0078,
+	0x45ea, 0x70ab, 0x3e15, 0x0078, 0x2438, 0x0078, 0x3e0f, 0x1078,
+	0x23ca, 0xa684, 0x0010, 0x0040, 0x3e23, 0x1078, 0x414f, 0x0040,
+	0x3e23, 0x0078, 0x2438, 0x0078, 0x41bc, 0x2200, 0x0079, 0x3e28,
+	0x3e2b, 0x3e2b, 0x3e2b, 0x1078, 0x23ca, 0x2200, 0x0079, 0x3e30,
+	0x3e33, 0x3e35, 0x3e35, 0x1078, 0x23ca, 0x78e4, 0xa084, 0x0008,
+	0x0040, 0x3e4a, 0x70a7, 0x3e3e, 0x0078, 0x45f6, 0x2011, 0x0004,
+	0x1078, 0x4287, 0x0079, 0x3e44, 0x3e4a, 0x2438, 0x3b60, 0x3e4a,
+	0x3e54, 0x3e58, 0x70ab, 0x3e52, 0x2001, 0x0003, 0x1078, 0x4544,
+	0x0078, 0x45f0, 0x0078, 0x45ea, 0x70ab, 0x3e4a, 0x0078, 0x2438,
+	0x70ab, 0x3e5c, 0x0078, 0x2438, 0x0078, 0x3e52, 0x2300, 0x0079,
+	0x3e61, 0x3e66, 0x3e68, 0x3e64, 0x1078, 0x23ca, 0x70a4, 0x007a,
+	0x70a4, 0x007a, 0xa282, 0x0002, 0x0050, 0x3e70, 0x1078, 0x23ca,
+	0xa684, 0x0200, 0x0040, 0x3e7a, 0x1078, 0x45b5, 0x1078, 0x426f,
+	0x1078, 0x45bc, 0x2300, 0x0079, 0x3e7d, 0x3e80, 0x3ea4, 0x3f0a,
+	0xa286, 0x0001, 0x0040, 0x3e86, 0x1078, 0x23ca, 0xa684, 0x0200,
+	0x0040, 0x3e8e, 0x1078, 0x45b5, 0x1078, 0x45bc, 0x2001, 0x0001,
+	0x1078, 0x454c, 0x78b8, 0xa084, 0xc001, 0x0040, 0x3ea0, 0x7848,
+	0xa085, 0x0008, 0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3e9b,
+	0x7003, 0x0000, 0x0078, 0x3b60, 0x2200, 0x0079, 0x3ea7, 0x3ea9,
+	0x3eda, 0x70a7, 0x3ead, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078,
+	0x4287, 0x0079, 0x3eb3, 0x3eba, 0x2438, 0x3b60, 0x3ec2, 0x3eca,
+	0x3ed0, 0x3ed2, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x0078, 0x45e4, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x0078, 0x45e4, 0x70ab, 0x3ece, 0x0078, 0x2438, 0x0078, 0x3eba,
+	0x1078, 0x23ca, 0x70ab, 0x3ed6, 0x0078, 0x2438, 0x1078, 0x45fc,
+	0x0078, 0x2438, 0x70a7, 0x3ede, 0x0078, 0x45f6, 0x2011, 0x0012,
+	0x1078, 0x4287, 0x0079, 0x3ee4, 0x3eea, 0x2438, 0x3b60, 0x3ef6,
+	0x3efe, 0x3f04, 0xa6b4, 0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a,
+	0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff,
+	0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab, 0x3f02,
+	0x0078, 0x2438, 0x0078, 0x3eea, 0x70ab, 0x3f08, 0x0078, 0x2438,
+	0x0078, 0x3ef6, 0xa286, 0x0001, 0x0040, 0x3f10, 0x1078, 0x23ca,
+	0x70a7, 0x3f14, 0x0078, 0x45f6, 0x2011, 0x0015, 0x1078, 0x4287,
+	0x0079, 0x3f1a, 0x3f1f, 0x2438, 0x3b60, 0x3f2d, 0x3f39, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0400, 0x6eb6, 0x7e5a, 0x783b, 0x1301, 0x70b4,
+	0xa080, 0x00b5, 0x781a, 0x0078, 0x2438, 0xa6b4, 0x00ff, 0xa6b5,
+	0x0400, 0x6eb6, 0x7e5a, 0x70b4, 0xa080, 0x00a5, 0x781a, 0x0078,
+	0x2438, 0x70ab, 0x3f3d, 0x0078, 0x2438, 0x0078, 0x3f1f, 0xa282,
+	0x0003, 0x0050, 0x3f45, 0x1078, 0x23ca, 0x2300, 0x0079, 0x3f48,
+	0x3f4b, 0x3f82, 0x3fdd, 0xa286, 0x0001, 0x0040, 0x3f51, 0x1078,
+	0x23ca, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0, 0x3f5e,
+	0x1078, 0x3ac2, 0x7003, 0x0000, 0x0078, 0x3b60, 0x683b, 0x0000,
+	0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x3f6c, 0x1078, 0x45b5,
+	0x1078, 0x426f, 0x1078, 0x45bc, 0x2001, 0x0001, 0x1078, 0x454c,
+	0x78b8, 0xa084, 0xc001, 0x0040, 0x3f7e, 0x7848, 0xa085, 0x0008,
+	0x784a, 0x7848, 0xa084, 0x0008, 0x00c0, 0x3f79, 0x7003, 0x0000,
+	0x0078, 0x3b60, 0x2200, 0x0079, 0x3f85, 0x3f87, 0x3fb8, 0x70a7,
+	0x3f8b, 0x0078, 0x45f6, 0x2011, 0x000d, 0x1078, 0x4287, 0x0079,
+	0x3f91, 0x3f98, 0x2438, 0x3b60, 0x3fa0, 0x3fa8, 0x3fae, 0x3fb0,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
+	0x70ab, 0x3fac, 0x0078, 0x2438, 0x0078, 0x3f98, 0x1078, 0x23ca,
+	0x70ab, 0x3fb4, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078, 0x2438,
+	0x70a7, 0x3fbc, 0x0078, 0x45f6, 0x2011, 0x0005, 0x1078, 0x4287,
+	0x0079, 0x3fc2, 0x3fc7, 0x2438, 0x3b60, 0x3fcf, 0x3fd7, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0xa6b4,
+	0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4, 0x70ab,
+	0x3fdb, 0x0078, 0x2438, 0x0078, 0x3fc7, 0xa286, 0x0001, 0x0040,
+	0x3fe3, 0x1078, 0x23ca, 0x70a7, 0x3fe7, 0x0078, 0x45f6, 0x2011,
+	0x0006, 0x1078, 0x4287, 0x0079, 0x3fed, 0x3ff2, 0x2438, 0x3b60,
+	0x3ff8, 0x4002, 0xa6b5, 0x0800, 0x6eb6, 0x7e5a, 0x0078, 0x45e4,
+	0xa6b4, 0x00ff, 0xa6b5, 0x0800, 0x6eb6, 0xa6b5, 0x4000, 0x7e5a,
+	0x0078, 0x45e4, 0x70ab, 0x4006, 0x0078, 0x2438, 0x0078, 0x3ff2,
+	0x2300, 0x0079, 0x400b, 0x4010, 0x400e, 0x400e, 0x1078, 0x23ca,
+	0x1078, 0x23ca, 0x2300, 0x71a8, 0xa005, 0x017a, 0x6810, 0x70be,
+	0xa282, 0x0003, 0x0050, 0x401e, 0x1078, 0x23ca, 0x2300, 0x0079,
+	0x4021, 0x4024, 0x4037, 0x4059, 0x82ff, 0x00c0, 0x4029, 0x1078,
+	0x23ca, 0xa684, 0x0200, 0x0040, 0x4031, 0x1078, 0x45b5, 0x1078,
+	0x45bc, 0x2001, 0x0001, 0x1078, 0x454c, 0x0078, 0x2438, 0xa296,
+	0x0002, 0x0040, 0x4040, 0x82ff, 0x0040, 0x4040, 0x1078, 0x23ca,
+	0x70a7, 0x4044, 0x0078, 0x45f6, 0x2011, 0x0018, 0x1078, 0x4287,
+	0x0079, 0x404a, 0x404f, 0x2438, 0x3b60, 0x4051, 0x4053, 0x0078,
+	0x45e4, 0x0078, 0x45e4, 0x70ab, 0x4057, 0x0078, 0x2438, 0x0078,
+	0x404f, 0x2200, 0x0079, 0x405c, 0x405e, 0x4077, 0x70a7, 0x4062,
+	0x0078, 0x45f6, 0x2011, 0x0017, 0x1078, 0x4287, 0x0079, 0x4068,
+	0x406d, 0x2438, 0x3b60, 0x406f, 0x4071, 0x0078, 0x45e4, 0x0078,
+	0x45e4, 0x70ab, 0x4075, 0x0078, 0x2438, 0x0078, 0x406d, 0xa484,
+	0x8000, 0x00c0, 0x40c1, 0xa684, 0x0100, 0x0040, 0x408b, 0x1078,
+	0x45b5, 0x1078, 0x426f, 0x1078, 0x45bc, 0x7848, 0xa085, 0x000c,
+	0x784a, 0x0078, 0x408f, 0x78d8, 0x78d2, 0x78dc, 0x78d6, 0xa6b4,
+	0xefff, 0x7e5a, 0x70a7, 0x4096, 0x0078, 0x45f6, 0x2011, 0x000d,
+	0x1078, 0x4287, 0x0079, 0x409c, 0x40a3, 0x2438, 0x3b60, 0x40a3,
+	0x40b1, 0x40b7, 0x40b9, 0xa684, 0x0100, 0x0040, 0x40af, 0x1078,
+	0x4573, 0x682c, 0x78d2, 0x6830, 0x78d6, 0x1078, 0x45ad, 0x0078,
+	0x45e4, 0x70ab, 0x40b5, 0x0078, 0x2438, 0x0078, 0x40a3, 0x1078,
+	0x23ca, 0x70ab, 0x40bd, 0x0078, 0x2438, 0x1078, 0x45fc, 0x0078,
+	0x2438, 0x1078, 0x45bc, 0x70ab, 0x40cb, 0x2001, 0x0003, 0x1078,
+	0x4544, 0x0078, 0x45f0, 0x1078, 0x45ad, 0x682c, 0x78d2, 0x6830,
+	0x78d6, 0x0078, 0x45e4, 0x70b8, 0x6812, 0x70be, 0x8000, 0x70ba,
+	0x681b, 0x0000, 0xa684, 0x0008, 0x0040, 0x40f6, 0x157e, 0x137e,
+	0x147e, 0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f,
+	0x681a, 0x80ac, 0x789b, 0x0000, 0xaf80, 0x002b, 0x2098, 0xad80,
+	0x000b, 0x20a0, 0x53a5, 0x147f, 0x137f, 0x157f, 0xa6c4, 0x0f00,
+	0xa684, 0x0002, 0x00c0, 0x4102, 0x692c, 0x810d, 0x810d, 0x810d,
+	0x0078, 0x410f, 0x789b, 0x0010, 0x79ac, 0x0078, 0x410f, 0x017e,
+	0x2009, 0x0005, 0x2001, 0x3d00, 0x1078, 0x457e, 0x017f, 0xa184,
+	0x001f, 0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0xa684, 0x0004,
+	0x0040, 0x4120, 0xa18c, 0xff00, 0x78a8, 0xa084, 0x00ff, 0xa105,
+	0x682a, 0xa6b4, 0x00ff, 0x6000, 0xa084, 0x0008, 0x0040, 0x412a,
+	0xa6b5, 0x4000, 0x6eb6, 0x007c, 0x157e, 0x137e, 0x147e, 0x6918,
+	0x7890, 0x8004, 0x8004, 0x8004, 0x8004, 0xa084, 0x000f, 0x007e,
+	0xa100, 0x681a, 0x007f, 0x8000, 0x8004, 0x0040, 0x414b, 0x20a8,
+	0x8104, 0xa080, 0x000b, 0xad00, 0x20a0, 0x789b, 0x0000, 0xaf80,
+	0x002b, 0x2098, 0x53a5, 0x147f, 0x137f, 0x157f, 0x007c, 0x682c,
+	0xa084, 0x0020, 0x00c0, 0x4157, 0x620c, 0x0078, 0x4158, 0x6210,
+	0x6b18, 0x2300, 0xa202, 0x0040, 0x4178, 0x2018, 0xa382, 0x000e,
+	0x0048, 0x4168, 0x0040, 0x4168, 0x2019, 0x000e, 0x0078, 0x416c,
+	0x7858, 0xa084, 0xffef, 0x785a, 0x783b, 0x1b01, 0x7893, 0x0000,
+	0x7ba2, 0x70b4, 0xa080, 0x008e, 0x781a, 0xa085, 0x0001, 0x007c,
+	0x7858, 0xa084, 0xffef, 0x785a, 0x7893, 0x0000, 0xa006, 0x007c,
+	0x6904, 0xa18c, 0x00ff, 0xa196, 0x0007, 0x0040, 0x418d, 0xa196,
+	0x000f, 0x0040, 0x418d, 0x6807, 0x0117, 0x6914, 0x1078, 0x3b33,
+	0x6100, 0x8104, 0x00c8, 0x41a8, 0x601c, 0xa005, 0x0040, 0x419c,
+	0x2001, 0x0800, 0x0078, 0x41aa, 0x0d7e, 0x6824, 0x007e, 0x1078,
+	0x45c5, 0x007f, 0x6826, 0x2d00, 0x682e, 0x1078, 0x3ac2, 0x0d7f,
+	0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
+	0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a, 0x71b4,
+	0xa188, 0x0091, 0x791a, 0x007c, 0xa6c4, 0x0f00, 0xa684, 0x0002,
+	0x00c0, 0x41cf, 0x692c, 0x810d, 0x810d, 0x810d, 0xa184, 0x001f,
+	0xa805, 0x6816, 0x1078, 0x3b33, 0x68be, 0x0078, 0x41d2, 0x6914,
+	0x1078, 0x3b33, 0x6100, 0x8104, 0x00c8, 0x421c, 0xa184, 0x0300,
+	0x0040, 0x41de, 0x6807, 0x0117, 0x0078, 0x41fc, 0x6004, 0xa005,
+	0x00c0, 0x4205, 0x6807, 0x0117, 0x601c, 0xa005, 0x00c0, 0x41f2,
+	0x0d7e, 0x1078, 0x45c5, 0x6827, 0x0034, 0x2d00, 0x682e, 0x1078,
+	0x3ac2, 0x0d7f, 0xa684, 0x0004, 0x0040, 0x41fc, 0x2031, 0x0400,
+	0x2001, 0x2800, 0x0078, 0x4200, 0x2031, 0x0400, 0x2001, 0x0800,
+	0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x6018, 0xa005, 0x00c0,
+	0x41f2, 0x601c, 0xa005, 0x00c0, 0x41f2, 0x689f, 0x0000, 0x6827,
+	0x003d, 0xa684, 0x0001, 0x0040, 0x4258, 0xa6b5, 0x0800, 0x71b4,
+	0xa188, 0x00ae, 0x0078, 0x4253, 0x6807, 0x0117, 0x2031, 0x0400,
+	0x692c, 0xa18c, 0x00ff, 0xa186, 0x0012, 0x00c0, 0x422d, 0x2001,
+	0x4265, 0x2009, 0x0001, 0x0078, 0x423e, 0xa186, 0x0003, 0x00c0,
+	0x4237, 0x2001, 0x4266, 0x2009, 0x0012, 0x0078, 0x423e, 0x2001,
+	0x0200, 0x71b4, 0xa188, 0x0091, 0x0078, 0x424a, 0x1078, 0x4598,
+	0x78a3, 0x0000, 0x681c, 0xa085, 0x0040, 0x681e, 0x71b4, 0xa188,
+	0x00da, 0xa006, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa, 0x6820,
+	0xa085, 0x8000, 0x6822, 0x6eb6, 0x7e5a, 0x791a, 0x0078, 0x2438,
+	0x6eb6, 0x1078, 0x3ac2, 0x6810, 0x70be, 0x7003, 0x0007, 0x70a3,
+	0x0000, 0x704b, 0x0000, 0x0078, 0x2438, 0x0023, 0x0070, 0x0005,
+	0x0000, 0x0a00, 0x0000, 0x0000, 0x0025, 0x0000, 0x0000, 0x683b,
+	0x0000, 0x6837, 0x0000, 0xa684, 0x0200, 0x0040, 0x4286, 0x78b8,
+	0xa08c, 0x001f, 0xa084, 0x8000, 0x0040, 0x427f, 0x8108, 0x78d8,
+	0xa100, 0x6836, 0x78dc, 0xa081, 0x0000, 0x683a, 0x007c, 0x7990,
+	0x810f, 0xa5ac, 0x0007, 0x2021, 0x0000, 0xa480, 0x0010, 0x789a,
+	0x79a8, 0xa18c, 0x00ff, 0xa184, 0x0080, 0x00c0, 0x42b5, 0xa182,
+	0x0020, 0x00c8, 0x42cf, 0xa182, 0x0012, 0x00c8, 0x4536, 0x2100,
+	0x1079, 0x42a3, 0x007c, 0x4536, 0x447e, 0x4536, 0x4536, 0x42dc,
+	0x42df, 0x4319, 0x434f, 0x4381, 0x4384, 0x4536, 0x4536, 0x433a,
+	0x43a8, 0x43e2, 0x4536, 0x4536, 0x4409, 0xa18c, 0x001f, 0x6814,
+	0xa084, 0x001f, 0xa106, 0x0040, 0x42cc, 0x70b4, 0xa080, 0x00cd,
+	0x781a, 0x2001, 0x0014, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003,
+	0x0000, 0x2001, 0x0002, 0x007c, 0x2001, 0x0000, 0x007c, 0xa182,
+	0x0024, 0x00c8, 0x4536, 0xa184, 0x0003, 0x1079, 0x42a3, 0x007c,
+	0x4536, 0x4536, 0x4536, 0x4536, 0x1078, 0x4536, 0x007c, 0x2200,
+	0x0079, 0x42e2, 0x440c, 0x440c, 0x4306, 0x4306, 0x4306, 0x4306,
+	0x4306, 0x4306, 0x4306, 0x4306, 0x4304, 0x4306, 0x42fb, 0x4306,
+	0x4306, 0x4306, 0x4306, 0x4306, 0x430e, 0x4311, 0x440c, 0x4311,
+	0x4306, 0x4306, 0x4306, 0x0c7e, 0x077e, 0x6f14, 0x1078, 0x36b0,
+	0x077f, 0x0c7f, 0x0078, 0x4306, 0x1078, 0x44d1, 0x6827, 0x02b3,
+	0x2009, 0x000b, 0x2001, 0x4800, 0x0078, 0x4440, 0x1078, 0x452b,
+	0x007c, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4800, 0x0078,
+	0x4428, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+	0x4323, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827,
+	0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3a92, 0x1078,
+	0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001,
+	0x0002, 0x007c, 0x1078, 0x4466, 0x2001, 0x0017, 0x1078, 0x454c,
+	0x70a3, 0x0000, 0x2009, 0x5038, 0x200b, 0x0006, 0x70af, 0x0017,
+	0x2009, 0x0200, 0x1078, 0x39d2, 0x2001, 0x0001, 0x007c, 0x2200,
+	0x0079, 0x4352, 0x440c, 0x443d, 0x443d, 0x443d, 0x4373, 0x444d,
+	0x4379, 0x444d, 0x444d, 0x4450, 0x4450, 0x4455, 0x4455, 0x436b,
+	0x436b, 0x443d, 0x443d, 0x444d, 0x443d, 0x4379, 0x440c, 0x4379,
+	0x4379, 0x4379, 0x4379, 0x6827, 0x0084, 0x2009, 0x000b, 0x2001,
+	0x4300, 0x0078, 0x445f, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078,
+	0x4440, 0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078,
+	0x4428, 0x2001, 0x0000, 0x007c, 0x2200, 0x0079, 0x4387, 0x440c,
+	0x43a0, 0x43a0, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d,
+	0x444d, 0x444d, 0x444d, 0x444d, 0x43a0, 0x43a0, 0x43a0, 0x43a0,
+	0x444d, 0x43a0, 0x43a0, 0x444d, 0x444d, 0x444d, 0x444d, 0x440c,
+	0x6827, 0x0093, 0x2009, 0x000b, 0x2001, 0x4300, 0x0078, 0x4428,
+	0xa684, 0x0004, 0x00c0, 0x43bc, 0x6804, 0xa084, 0x00ff, 0xa086,
+	0x0006, 0x00c0, 0x4536, 0x1078, 0x4466, 0x6807, 0x0117, 0x1078,
+	0x3ac2, 0x2001, 0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040,
+	0x4536, 0x2d58, 0x6804, 0xa084, 0x00ff, 0xa086, 0x0006, 0x00c0,
+	0x43cb, 0x6807, 0x0117, 0x6827, 0x0002, 0x1078, 0x45c5, 0x6827,
+	0x0036, 0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3aa1, 0x1078,
+	0x4466, 0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001,
+	0x0002, 0x007c, 0x6000, 0xa084, 0x0004, 0x0040, 0x4536, 0x2d58,
+	0x6a04, 0xa294, 0x00ff, 0xa286, 0x0006, 0x00c0, 0x43f1, 0x6807,
+	0x0117, 0x6827, 0x0002, 0x2d58, 0x1078, 0x45c5, 0x6827, 0x0036,
+	0x6932, 0x2d00, 0x682e, 0x0d7e, 0x1078, 0x3ab1, 0x1078, 0x4466,
+	0x2b68, 0x1078, 0x3ac2, 0x0d7f, 0x1078, 0x3ac2, 0x2001, 0x0002,
+	0x007c, 0x1078, 0x4536, 0x007c, 0x70b4, 0xa080, 0x00cd, 0x781a,
+	0x2001, 0x0001, 0x1078, 0x454c, 0x1078, 0x45bc, 0x7003, 0x0000,
+	0x2001, 0x0002, 0x007c, 0x1078, 0x457e, 0x1078, 0x45b5, 0x1078,
+	0x426f, 0x1078, 0x4180, 0x1078, 0x45bc, 0x2001, 0x0001, 0x007c,
+	0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080,
+	0x00cd, 0x781a, 0x2001, 0x0013, 0x1078, 0x454c, 0x1078, 0x45bc,
+	0x7003, 0x0000, 0x2001, 0x0002, 0x007c, 0x1078, 0x4536, 0x007c,
+	0x1078, 0x457e, 0x1078, 0x45b5, 0x1078, 0x426f, 0x1078, 0x4180,
+	0x1078, 0x45bc, 0x2001, 0x0001, 0x007c, 0x2001, 0x0003, 0x007c,
+	0x1078, 0x44d1, 0x2001, 0x0000, 0x007c, 0x0c7e, 0x077e, 0x6f14,
+	0x1078, 0x36b0, 0x077f, 0x0c7f, 0x2001, 0x0000, 0x007c, 0x1078,
+	0x457e, 0x1078, 0x4536, 0x2001, 0x0006, 0x007c, 0x6904, 0xa18c,
+	0x00ff, 0xa186, 0x0007, 0x0040, 0x4471, 0xa186, 0x000f, 0x00c0,
+	0x4475, 0x1078, 0x45b5, 0x1078, 0x426f, 0x70b4, 0xa080, 0x00cd,
+	0x781a, 0x1078, 0x45bc, 0x7003, 0x0000, 0x007c, 0x7aa8, 0xa294,
+	0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x4536,
+	0x1079, 0x448b, 0x007c, 0x4536, 0x448f, 0x4536, 0x44df, 0xa282,
+	0x0003, 0x0040, 0x4496, 0x1078, 0x4536, 0x007c, 0x7da8, 0xa5ac,
+	0x00ff, 0x7ca8, 0xa4a4, 0x00ff, 0xa482, 0x000c, 0x0048, 0x44a4,
+	0x0040, 0x44a4, 0x2021, 0x000c, 0x701c, 0xa502, 0x00c8, 0x44a9,
+	0x751c, 0x1078, 0x451c, 0x852b, 0x852b, 0x1078, 0x372e, 0x0040,
+	0x44b5, 0x1078, 0x44c3, 0x0078, 0x44b9, 0x1078, 0x4518, 0x1078,
+	0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9, 0x781a,
+	0x2001, 0x0004, 0x007c, 0x0c7e, 0x6914, 0x810f, 0xa18c, 0x000f,
+	0x810b, 0x810b, 0x810b, 0xa1e0, 0x5280, 0x1078, 0x3538, 0x0c7f,
+	0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084, 0x000f, 0x8003, 0x8003,
+	0x8003, 0xa0e0, 0x5280, 0x1078, 0x355f, 0x0c7f, 0x007c, 0xa282,
+	0x0002, 0x00c0, 0x4536, 0x7aa8, 0xa294, 0x00ff, 0xa284, 0xfffe,
+	0x0040, 0x44ec, 0x2011, 0x0001, 0x1078, 0x450a, 0x1078, 0x44fc,
+	0x1078, 0x44d1, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9,
+	0x781a, 0x2001, 0x0004, 0x007c, 0x0c7e, 0x6814, 0x8007, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xa0e0, 0x5280, 0x1078, 0x3604,
+	0x0c7f, 0x007c, 0x789b, 0x0018, 0x78ab, 0x0001, 0x78ab, 0x0002,
+	0x78ab, 0x0003, 0x7aaa, 0x789b, 0x0081, 0x78ab, 0x0004, 0x007c,
+	0x2021, 0x0000, 0x2029, 0x0032, 0x789b, 0x0018, 0x78ab, 0x0001,
+	0x78ab, 0x0003, 0x78ab, 0x0001, 0x7daa, 0x7caa, 0x789b, 0x0081,
+	0x78ab, 0x0005, 0x007c, 0x2001, 0x0003, 0x1078, 0x4544, 0x70b4,
+	0xa080, 0x00b9, 0x781a, 0x2001, 0x0005, 0x007c, 0x2001, 0x0007,
+	0x1078, 0x4544, 0xa6b5, 0x1000, 0x7e5a, 0x70b4, 0xa080, 0x00b9,
+	0x781a, 0x2001, 0x0004, 0x007c, 0x789b, 0x0018, 0x78aa, 0x789b,
+	0x0081, 0x78ab, 0x0001, 0x007c, 0x6904, 0xa18c, 0x00ff, 0xa196,
+	0x0007, 0x0040, 0x455a, 0xa196, 0x000f, 0x0040, 0x455a, 0x1078,
+	0x193d, 0x007c, 0x6924, 0xa194, 0x003f, 0x00c0, 0x4563, 0xa18c,
+	0xffc0, 0xa105, 0x6826, 0x1078, 0x3ac2, 0x691c, 0xa184, 0x0100,
+	0x0040, 0x4572, 0x1078, 0x1b7e, 0x6914, 0x1078, 0x3b33, 0x6204,
+	0x8210, 0x6206, 0x007c, 0x692c, 0x6834, 0x682e, 0xa112, 0x6930,
+	0x6838, 0x6832, 0xa11b, 0xa200, 0xa301, 0x007c, 0x0c7e, 0xade0,
+	0x0018, 0x6003, 0x0070, 0x6106, 0x600b, 0x0000, 0x600f, 0x0a00,
+	0x6013, 0x0000, 0x6017, 0x0000, 0x8007, 0x601a, 0x601f, 0x0000,
+	0x6023, 0x0000, 0x0c7f, 0x6824, 0xa085, 0x0080, 0x6826, 0x007c,
+	0x157e, 0x137e, 0x147e, 0x2098, 0xaf80, 0x002d, 0x20a0, 0x81ac,
+	0x0040, 0x45a3, 0x53a6, 0xa184, 0x0001, 0x0040, 0x45a9, 0x3304,
+	0x78be, 0x147f, 0x137f, 0x157f, 0x007c, 0x70b0, 0xa005, 0x10c0,
+	0x23ca, 0x70b3, 0x8000, 0x0078, 0x48f7, 0x71b0, 0x81ff, 0x0040,
+	0x45bb, 0x1078, 0x49ed, 0x007c, 0x71b0, 0x81ff, 0x0040, 0x45c4,
+	0x70b3, 0x0000, 0x1078, 0x4633, 0x007c, 0x0c7e, 0x0d7e, 0x1078,
+	0x191a, 0x0c7f, 0x157e, 0x137e, 0x147e, 0x2da0, 0x2c98, 0x20a9,
+	0x0031, 0x53a3, 0x147f, 0x137f, 0x157f, 0x6807, 0x010d, 0x680b,
+	0x0000, 0x7004, 0x8007, 0x681a, 0x6823, 0x0000, 0x681f, 0x0000,
+	0x689f, 0x0000, 0x0c7f, 0x007c, 0x70b4, 0xa080, 0x0091, 0x781a,
+	0x0078, 0x2438, 0x70b4, 0xa080, 0x0081, 0x781a, 0x0078, 0x2438,
+	0x70b4, 0xa080, 0x00b9, 0x781a, 0x0078, 0x2438, 0x70b4, 0xa080,
+	0x00c3, 0x781a, 0x0078, 0x2438, 0x6904, 0xa18c, 0x00ff, 0xa196,
+	0x0007, 0x0040, 0x4609, 0xa196, 0x000f, 0x0040, 0x4609, 0x6807,
+	0x0117, 0x2001, 0x0200, 0x6826, 0x8007, 0x789b, 0x000e, 0x78aa,
+	0x6820, 0xa085, 0x8000, 0x6822, 0x2031, 0x0400, 0x6eb6, 0x7e5a,
+	0x71b4, 0xa188, 0x0091, 0x791a, 0x007c, 0x1078, 0x45bc, 0x7848,
+	0xa085, 0x000c, 0x784a, 0x70b4, 0xa080, 0x00cd, 0x781a, 0x2009,
+	0x000b, 0x2001, 0x4400, 0x1078, 0x457e, 0x2001, 0x0013, 0x1078,
+	0x454c, 0x0078, 0x3b60, 0x127e, 0x2091, 0x2200, 0x2049, 0x4633,
+	0x7000, 0x7204, 0xa205, 0x720c, 0xa215, 0x7008, 0xa084, 0xfff7,
+	0xa205, 0x0040, 0x4645, 0x0078, 0x464a, 0x7003, 0x0000, 0x127f,
+	0x2000, 0x007c, 0x7000, 0xa084, 0x0001, 0x00c0, 0x4678, 0x7108,
+	0x8103, 0x00c8, 0x4657, 0x1078, 0x477a, 0x0078, 0x464f, 0x700c,
+	0xa08c, 0x00ff, 0x0040, 0x4678, 0x7004, 0x8004, 0x00c8, 0x466f,
+	0x7014, 0xa005, 0x00c0, 0x466b, 0x7010, 0xa005, 0x0040, 0x466f,
+	0xa102, 0x00c8, 0x464f, 0x7007, 0x0010, 0x0078, 0x4678, 0x8aff,
+	0x0040, 0x4678, 0x1078, 0x49c4, 0x00c0, 0x4672, 0x0040, 0x464f,
+	0x1078, 0x4703, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x017e,
+	0x6104, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x468b, 0xa18e,
+	0x000f, 0x00c0, 0x468e, 0x6040, 0x0078, 0x468f, 0x6428, 0x017f,
+	0x84ff, 0x0040, 0x46b9, 0x2c70, 0x7004, 0xa0bc, 0x000f, 0xa7b8,
+	0x46c9, 0x273c, 0x87fb, 0x00c0, 0x46a7, 0x0048, 0x46a1, 0x1078,
+	0x23ca, 0x609c, 0xa075, 0x0040, 0x46b9, 0x0078, 0x4694, 0x2704,
+	0xae68, 0x6808, 0xa630, 0x680c, 0xa529, 0x8421, 0x0040, 0x46b9,
+	0x8738, 0x2704, 0xa005, 0x00c0, 0x46a8, 0x709c, 0xa075, 0x00c0,
+	0x4694, 0x007c, 0x0000, 0x0005, 0x0009, 0x000d, 0x0011, 0x0015,
+	0x0019, 0x001d, 0x0000, 0x0003, 0x0009, 0x000f, 0x0015, 0x001b,
+	0x0000, 0x0000, 0x46be, 0x46bb, 0x0000, 0x0000, 0x8000, 0x0000,
+	0x46be, 0x0000, 0x46c6, 0x46c3, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x46c6, 0x0000, 0x46c1, 0x46c1, 0x0000, 0x0000, 0x8000, 0x0000,
+	0x46c1, 0x0000, 0x46c7, 0x46c7, 0x0000, 0x0000, 0x0000, 0x0000,
+	0x46c7, 0x127e, 0x2091, 0x2200, 0x2079, 0x5000, 0x2071, 0x0010,
+	0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2071, 0x0020,
+	0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2049, 0x0000,
+	0x127f, 0x2000, 0x007c, 0x2049, 0x4703, 0x2019, 0x0000, 0x7004,
+	0x8004, 0x00c8, 0x4756, 0x7007, 0x0012, 0x7108, 0x7008, 0xa106,
+	0x00c0, 0x470d, 0xa184, 0x01e0, 0x0040, 0x4718, 0x1078, 0x23ca,
+	0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8, 0x4723, 0xa184,
+	0x4000, 0x00c0, 0x470d, 0xa19c, 0x300c, 0xa386, 0x2004, 0x0040,
+	0x4731, 0xa386, 0x0008, 0x0040, 0x473c, 0xa386, 0x200c, 0x00c0,
+	0x470d, 0x7200, 0x8204, 0x0048, 0x473c, 0x730c, 0xa384, 0x00ff,
+	0x0040, 0x473c, 0x1078, 0x23ca, 0x7007, 0x0012, 0x7000, 0xa084,
+	0x0001, 0x00c0, 0x4756, 0x7008, 0xa084, 0x01e0, 0x00c0, 0x4756,
+	0x7310, 0x7014, 0xa305, 0x0040, 0x4756, 0x710c, 0xa184, 0x0300,
+	0x00c0, 0x4756, 0xa184, 0x00ff, 0x00c0, 0x4703, 0x7007, 0x0012,
+	0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0, 0x475a, 0x7007,
+	0x0012, 0x7108, 0x8103, 0x0048, 0x475f, 0x7003, 0x0000, 0x2049,
+	0x0000, 0x007c, 0x107e, 0x007e, 0x127e, 0x157e, 0x2091, 0x2200,
+	0x7108, 0x1078, 0x477a, 0x157f, 0x127f, 0x2091, 0x8001, 0x007f,
+	0x107f, 0x007c, 0x7204, 0x7500, 0x730c, 0xa384, 0x0300, 0x00c0,
+	0x47a1, 0xa184, 0x01e0, 0x00c0, 0x47c5, 0x7108, 0xa184, 0x01e0,
+	0x00c0, 0x47c5, 0x2001, 0x04fd, 0x2004, 0xa082, 0x0005, 0x00c8,
+	0x4795, 0xa184, 0x4000, 0x00c0, 0x4785, 0xa184, 0x0007, 0x0079,
+	0x4799, 0x47a3, 0x47b5, 0x47a1, 0x47b5, 0x47a1, 0x4801, 0x47a1,
+	0x47ff, 0x1078, 0x23ca, 0x7004, 0xa084, 0x0010, 0xa085, 0x0002,
+	0x7006, 0x8aff, 0x00c0, 0x47b0, 0x2049, 0x0000, 0x0078, 0x47b4,
+	0x1078, 0x49c4, 0x00c0, 0x47b0, 0x007c, 0x7004, 0xa084, 0x0010,
+	0xa085, 0x0002, 0x7006, 0x8aff, 0x00c0, 0x47c0, 0x0078, 0x47c4,
+	0x1078, 0x49c4, 0x00c0, 0x47c0, 0x007c, 0x7007, 0x0012, 0x7108,
+	0x00e0, 0x47c8, 0x2091, 0x6000, 0x00e0, 0x47cc, 0x2091, 0x6000,
+	0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084, 0x0008, 0x00c0,
+	0x47d4, 0x7007, 0x0012, 0x7108, 0x8103, 0x0048, 0x47d9, 0x7003,
+	0x0000, 0x7000, 0xa005, 0x00c0, 0x47ed, 0x7004, 0xa005, 0x00c0,
+	0x47ed, 0x700c, 0xa005, 0x0040, 0x47ef, 0x0078, 0x47d0, 0x2049,
+	0x0000, 0x1078, 0x37d7, 0x6818, 0xa084, 0x8000, 0x0040, 0x47fa,
+	0x681b, 0x0002, 0x007c, 0x1078, 0x23ca, 0x1078, 0x23ca, 0x1078,
+	0x485d, 0x7210, 0x7114, 0x700c, 0xa09c, 0x00ff, 0x2800, 0xa300,
+	0xa211, 0xa189, 0x0000, 0x1078, 0x485d, 0x2704, 0x2c58, 0xac60,
+	0x6308, 0x2200, 0xa322, 0x630c, 0x2100, 0xa31b, 0x2400, 0xa305,
+	0x0040, 0x4824, 0x00c8, 0x4824, 0x8412, 0x8210, 0x830a, 0xa189,
+	0x0000, 0x2b60, 0x0078, 0x480b, 0x2b60, 0x8a07, 0x007e, 0x6004,
+	0xa084, 0x0008, 0x0040, 0x4830, 0xa7ba, 0x46c3, 0x0078, 0x4832,
+	0xa7ba, 0x46bb, 0x007f, 0xa73d, 0x2c00, 0x6886, 0x6f8a, 0x6c92,
+	0x6b8e, 0x7007, 0x0012, 0x1078, 0x4703, 0x007c, 0x8738, 0x2704,
+	0xa005, 0x00c0, 0x4851, 0x609c, 0xa005, 0x0040, 0x485a, 0x2060,
+	0x6004, 0xa084, 0x000f, 0xa080, 0x46c9, 0x203c, 0x87fb, 0x1040,
+	0x23ca, 0x8a51, 0x0040, 0x4859, 0x7008, 0xa084, 0x0003, 0xa086,
+	0x0003, 0x007c, 0x2051, 0x0000, 0x007c, 0x8a50, 0x8739, 0x2704,
+	0xa004, 0x00c0, 0x4871, 0x6000, 0xa064, 0x00c0, 0x4868, 0x2d60,
+	0x6004, 0xa084, 0x000f, 0xa080, 0x46d9, 0x203c, 0x87fb, 0x1040,
+	0x23ca, 0x007c, 0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x6884,
+	0x2060, 0x6888, 0x6b8c, 0x6c90, 0x8057, 0xaad4, 0x00ff, 0xa084,
+	0x00ff, 0x007e, 0x6804, 0xa084, 0x0008, 0x007f, 0x0040, 0x488c,
+	0xa0b8, 0x46c3, 0x0078, 0x488e, 0xa0b8, 0x46bb, 0x7e08, 0xa6b5,
+	0x000c, 0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x489c,
+	0xa18e, 0x000f, 0x00c0, 0x48a5, 0x681c, 0xa084, 0x0040, 0x0040,
+	0x48ac, 0xa6b5, 0x0001, 0x0078, 0x48ac, 0x681c, 0xa084, 0x0040,
+	0x0040, 0x48ac, 0xa6b5, 0x0001, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x48ae, 0x2400, 0xa305, 0x00c0, 0x48b9, 0x0078,
+	0x48df, 0x2c58, 0x2704, 0x6104, 0xac60, 0x6000, 0xa400, 0x701a,
+	0x6004, 0xa301, 0x701e, 0xa184, 0x0008, 0x0040, 0x48cf, 0x6010,
+	0xa081, 0x0000, 0x7022, 0x6014, 0xa081, 0x0000, 0x7026, 0x6208,
+	0x2400, 0xa202, 0x7012, 0x620c, 0x2300, 0xa203, 0x7016, 0x7602,
+	0x7007, 0x0001, 0x2b60, 0x1078, 0x483e, 0x0078, 0x48e1, 0x1078,
+	0x49c4, 0x00c0, 0x48df, 0x127f, 0x2000, 0x007c, 0x127e, 0x0d7e,
+	0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084, 0x0004,
+	0x00c0, 0x48ed, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c, 0x127e,
+	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x48f7, 0x7007, 0x0004,
+	0x7004, 0xa084, 0x0004, 0x00c0, 0x4900, 0x7e08, 0xa6b5, 0x000c,
+	0x6904, 0xa18c, 0x00ff, 0xa186, 0x0007, 0x0040, 0x4913, 0xa18e,
+	0x000f, 0x00c0, 0x491e, 0x681c, 0xa084, 0x0040, 0x0040, 0x491a,
+	0xa6b5, 0x0001, 0x6840, 0x2050, 0x0078, 0x4927, 0x681c, 0xa084,
+	0x0020, 0x00c0, 0x4925, 0xa6b5, 0x0001, 0x6828, 0x2050, 0x2d60,
+	0x6004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb, 0x00c0,
+	0x493b, 0x0048, 0x4935, 0x1078, 0x23ca, 0x689c, 0xa065, 0x0040,
+	0x493f, 0x0078, 0x4928, 0x1078, 0x49c4, 0x00c0, 0x493b, 0x127f,
+	0x2000, 0x007c, 0x127e, 0x007e, 0x017e, 0x0d7e, 0x2091, 0x2200,
+	0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5, 0x000c, 0x6904, 0xa18c,
+	0x00ff, 0xa186, 0x0007, 0x0040, 0x4959, 0xa18e, 0x000f, 0x00c0,
+	0x4962, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5, 0x0001,
+	0x0078, 0x4969, 0x681c, 0xa084, 0x0040, 0x0040, 0x4969, 0xa6b5,
+	0x0001, 0x2049, 0x4942, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186,
+	0x0007, 0x0040, 0x4977, 0xa18e, 0x000f, 0x00c0, 0x497a, 0x6840,
+	0x0078, 0x497b, 0x6828, 0x017f, 0xa055, 0x0040, 0x49c1, 0x2d70,
+	0x2e60, 0x7004, 0xa0bc, 0x000f, 0xa7b8, 0x46c9, 0x273c, 0x87fb,
+	0x00c0, 0x4995, 0x0048, 0x498e, 0x1078, 0x23ca, 0x709c, 0xa075,
+	0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x2704, 0xae68, 0x6808,
+	0xa422, 0x680c, 0xa31b, 0x0048, 0x49ae, 0x8a51, 0x00c0, 0x49a2,
+	0x1078, 0x23ca, 0x8738, 0x2704, 0xa005, 0x00c0, 0x4996, 0x709c,
+	0xa075, 0x2060, 0x0040, 0x49c1, 0x0078, 0x4981, 0x8422, 0x8420,
+	0x831a, 0xa399, 0x0000, 0x6908, 0x2400, 0xa122, 0x690c, 0x2300,
+	0xa11b, 0x00c8, 0x49bd, 0x1078, 0x23ca, 0x2071, 0x0020, 0x0078,
+	0x48ac, 0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x0003, 0xa086,
+	0x0003, 0x0040, 0x49ec, 0x2704, 0xac08, 0x2104, 0x701a, 0x8108,
+	0x2104, 0x701e, 0x8108, 0x2104, 0x7012, 0x8108, 0x2104, 0x7016,
+	0x6004, 0xa084, 0x0008, 0x0040, 0x49e3, 0x8108, 0x2104, 0x7022,
+	0x8108, 0x2104, 0x7026, 0x7602, 0x7004, 0xa084, 0x0010, 0xa085,
+	0x0001, 0x7006, 0x1078, 0x483e, 0x007c, 0x127e, 0x007e, 0x0d7e,
+	0x2091, 0x2200, 0x2049, 0x49ed, 0x0d7f, 0x087f, 0x7108, 0xa184,
+	0x0003, 0x00c0, 0x4a17, 0x017e, 0x6904, 0xa18c, 0x00ff, 0xa186,
+	0x0007, 0x0040, 0x4a07, 0xa18e, 0x000f, 0x00c0, 0x4a0a, 0x6840,
+	0x0078, 0x4a0b, 0x6828, 0x017f, 0xa005, 0x0040, 0x4a25, 0x0078,
+	0x464a, 0x0020, 0x4a17, 0x1078, 0x4801, 0x0078, 0x4a25, 0x00a0,
+	0x4a1e, 0x7108, 0x1078, 0x477a, 0x0078, 0x49f6, 0x7007, 0x0010,
+	0x00a0, 0x4a20, 0x7108, 0x1078, 0x477a, 0x7008, 0xa086, 0x0008,
+	0x00c0, 0x49f6, 0x7000, 0xa005, 0x00c0, 0x49f6, 0x7003, 0x0000,
+	0x2049, 0x0000, 0x127f, 0x2000, 0x007c, 0x127e, 0x147e, 0x137e,
+	0x157e, 0x0c7e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x4a35,
+	0xad80, 0x0011, 0x20a0, 0x2099, 0x0031, 0x700c, 0xa084, 0x00ff,
+	0x682a, 0x7007, 0x0008, 0x7007, 0x0002, 0x7003, 0x0001, 0x0040,
+	0x4a54, 0x8000, 0x80ac, 0x53a5, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x4a56, 0x0c7f, 0x2049, 0x0000, 0x7003, 0x0000,
+	0x157f, 0x137f, 0x147f, 0x127f, 0x2000, 0x007c, 0x2091, 0x6000,
+	0x2091, 0x8000, 0x78cc, 0xa005, 0x0040, 0x4a7d, 0x7994, 0x70d0,
+	0xa106, 0x00c0, 0x4a7d, 0x7804, 0xa005, 0x0040, 0x4a7d, 0x7807,
+	0x0000, 0x0068, 0x4a7d, 0x2091, 0x4080, 0x7820, 0x8001, 0x7822,
+	0x00c0, 0x4ad8, 0x7824, 0x7822, 0x2069, 0x5040, 0x6800, 0xa084,
+	0x0007, 0x0040, 0x4a9b, 0xa086, 0x0002, 0x0040, 0x4a9b, 0x6834,
+	0xa00d, 0x0040, 0x4a9b, 0x2104, 0xa005, 0x0040, 0x4a9b, 0x8001,
+	0x200a, 0x0040, 0x4b80, 0x7848, 0xa005, 0x0040, 0x4aa9, 0x8001,
+	0x784a, 0x00c0, 0x4aa9, 0x2009, 0x0102, 0x6844, 0x200a, 0x1078,
+	0x21b1, 0x6890, 0xa005, 0x0040, 0x4ab5, 0x8001, 0x6892, 0x00c0,
+	0x4ab5, 0x686f, 0x0000, 0x6873, 0x0001, 0x2061, 0x5300, 0x20a9,
+	0x0100, 0x2009, 0x0002, 0x6034, 0xa005, 0x0040, 0x4acb, 0x8001,
+	0x6036, 0x00c0, 0x4acb, 0x6010, 0xa005, 0x0040, 0x4acb, 0x017e,
+	0x1078, 0x21b1, 0x017f, 0xace0, 0x0010, 0x0070, 0x4ad1, 0x0078,
+	0x4abb, 0x8109, 0x0040, 0x4ad8, 0x20a9, 0x0100, 0x0078, 0x4abb,
+	0x1078, 0x4ae5, 0x1078, 0x4b0a, 0x2009, 0x5051, 0x2104, 0x2009,
+	0x0102, 0x200a, 0x2091, 0x8001, 0x007c, 0x7834, 0x8001, 0x7836,
+	0x00c0, 0x4b09, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005,
+	0x00c0, 0x4af4, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x7300,
+	0x2040, 0x2004, 0xa065, 0x0040, 0x4b09, 0x6024, 0xa005, 0x0040,
+	0x4b05, 0x8001, 0x6026, 0x0040, 0x4b39, 0x6000, 0x2c40, 0x0078,
+	0x4afa, 0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x4b38, 0x782c,
+	0x782a, 0x7830, 0xa005, 0x00c0, 0x4b17, 0x2001, 0x0200, 0x8001,
+	0x7832, 0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x5300, 0xa298,
+	0x0002, 0x2304, 0xa084, 0x0008, 0x0040, 0x4b38, 0xa290, 0x0009,
+	0x2204, 0xa005, 0x0040, 0x4b30, 0x8001, 0x2012, 0x00c0, 0x4b38,
+	0x2304, 0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x21b1,
+	0x007c, 0x2069, 0x5040, 0x6800, 0xa005, 0x0040, 0x4b43, 0x6848,
+	0xac06, 0x0040, 0x4b80, 0x601b, 0x0006, 0x60b4, 0xa084, 0x3f00,
+	0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0060, 0x6022, 0x6000,
+	0x2042, 0x6714, 0x6f82, 0x1078, 0x1956, 0x6818, 0xa005, 0x0040,
+	0x4b5b, 0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810,
+	0x8001, 0x00d0, 0x4b65, 0x1078, 0x23ca, 0x6812, 0x602f, 0x0000,
+	0x6033, 0x0000, 0x2c68, 0x1078, 0x1c53, 0x2069, 0x5040, 0x7944,
+	0xa184, 0x0100, 0x2001, 0x0006, 0x686e, 0x00c0, 0x4b7b, 0x6986,
+	0x2001, 0x0004, 0x686e, 0x1078, 0x21ac, 0x2091, 0x8001, 0x007c,
+	0x2069, 0x0100, 0x2009, 0x5040, 0x2104, 0xa084, 0x0007, 0x0040,
+	0x4bdc, 0xa086, 0x0007, 0x00c0, 0x4b96, 0x0d7e, 0x2009, 0x5052,
+	0x216c, 0x1078, 0x3a1a, 0x0d7f, 0x0078, 0x4bdc, 0x2009, 0x5052,
+	0x2164, 0x1078, 0x2375, 0x601b, 0x0006, 0x6858, 0xa084, 0x3f00,
+	0x601e, 0x6020, 0xa084, 0x00ff, 0xa085, 0x0048, 0x6022, 0x602f,
+	0x0000, 0x6033, 0x0000, 0x6830, 0xa084, 0x0040, 0x0040, 0x4bd0,
+	0x684b, 0x0004, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0004, 0x0040,
+	0x4bbd, 0x0070, 0x4bbd, 0x0078, 0x4bb4, 0x684b, 0x0009, 0x20a9,
+	0x0014, 0x6848, 0xa084, 0x0001, 0x0040, 0x4bca, 0x0070, 0x4bca,
+	0x0078, 0x4bc1, 0x20a9, 0x00fa, 0x0070, 0x4bd0, 0x0078, 0x4bcc,
+	0x6808, 0xa084, 0xfffd, 0x680a, 0x681b, 0x0048, 0x2009, 0x505b,
+	0x200b, 0x0007, 0x784c, 0x784a, 0x2091, 0x8001, 0x007c, 0x2079,
+	0x5000, 0x1078, 0x4c0a, 0x1078, 0x4bee, 0x1078, 0x4bfc, 0x7833,
+	0x0000, 0x7847, 0x0000, 0x784b, 0x0000, 0x007c, 0x2019, 0x0003,
+	0x2011, 0x5046, 0x2204, 0xa086, 0x003c, 0x0040, 0x4bf9, 0x2019,
+	0x0002, 0x7b2a, 0x7b2e, 0x007c, 0x2019, 0x0039, 0x2011, 0x5046,
+	0x2204, 0xa086, 0x003c, 0x0040, 0x4c07, 0x2019, 0x0027, 0x7b36,
+	0x7b3a, 0x007c, 0x2019, 0x3971, 0x2011, 0x5046, 0x2204, 0xa086,
+	0x003c, 0x0040, 0x4c15, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x783f,
+	0x0000, 0x7843, 0x000a, 0x007c, 0x0020, 0x002b, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014,
+	0x0014, 0x9849, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014, 0x0014,
+	0x0014, 0x0080, 0x000f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120,
+	0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014,
+	0xa200, 0x0214, 0x0000, 0x006c, 0x0002, 0x0014, 0x98d5, 0x009e,
+	0x009b, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864, 0x9889,
+	0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a, 0x8300,
+	0x1856, 0x883a, 0x9865, 0x28f2, 0x9c95, 0x9858, 0x300c, 0x28e1,
+	0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814, 0x883b,
+	0x782c, 0x786d, 0x9879, 0x282b, 0xa207, 0x64a0, 0x67a0, 0x6fc0,
+	0x1814, 0x883b, 0x7822, 0x883e, 0x987d, 0x8576, 0x8677, 0x206b,
+	0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0x9865, 0xa209,
+	0x2901, 0x9891, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a, 0x883c,
+	0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014, 0xa204,
+	0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb, 0x872e,
+	0x87a9, 0x883f, 0x08e6, 0x9895, 0xf881, 0x9890, 0xc801, 0x0014,
+	0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2, 0x0014,
+	0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6, 0x0014,
+	0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160, 0x842a,
+	0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011, 0x20d5,
+	0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0x98c8, 0x8000, 0xa000,
+	0x2802, 0x1011, 0x98ce, 0x9865, 0x283e, 0x1011, 0x98d2, 0xa20b,
+	0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210, 0x98df,
+	0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014, 0xa20d,
+	0x3806, 0x0210, 0x9cbb, 0x0704, 0x0000, 0x006c, 0x0002, 0x984f,
+	0x0014, 0x009e, 0x00a0, 0x0017, 0x60ff, 0x300c, 0x8720, 0xa211,
+	0x9cd0, 0x8772, 0x8837, 0x2101, 0x987a, 0x10d2, 0x78e2, 0x9cd3,
+	0x9859, 0xd984, 0xf0e2, 0xf0a1, 0x98cd, 0x0014, 0x8831, 0xd166,
+	0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820, 0x987a, 0x2301,
+	0x987a, 0x10d2, 0x78e4, 0x9cd3, 0x8821, 0x8820, 0x9859, 0xf123,
+	0xf142, 0xf101, 0x98c6, 0x10d2, 0x70f6, 0x8832, 0x8203, 0x870c,
+	0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b, 0x9cd0, 0x2001,
+	0x98c5, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834, 0x8001, 0x988d,
+	0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218, 0x6981, 0x9cbc,
+	0x6b2a, 0x6902, 0x1834, 0x989d, 0x1814, 0x8010, 0x8592, 0x8026,
+	0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9ca9, 0x694b, 0xa213,
+	0x1462, 0xa213, 0x8000, 0x16e1, 0x98b5, 0x8023, 0x16e1, 0x8001,
+	0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002, 0x14e1, 0x8004,
+	0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217, 0x9cbc, 0x0014,
+	0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c, 0x0016, 0xa212,
+	0x9cd0, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424, 0xcc1a, 0x9cd3,
+	0x98c5, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4, 0x0016, 0x11c2,
+	0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016, 0xa21c, 0x1035,
+	0x9891, 0xa210, 0xa000, 0x8010, 0x8592, 0x853b, 0xd044, 0x8022,
+	0x3807, 0x84bb, 0x98ea, 0x8021, 0x3807, 0x84b9, 0x300c, 0x817e,
+	0x872b, 0x8772, 0x9891, 0x0000, 0x0020, 0x002b, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0014,
+	0x0014, 0x9849, 0x0014, 0x0014, 0x98ea, 0x98d5, 0x0014, 0x0014,
+	0x0014, 0x0080, 0x013f, 0x0000, 0x0201, 0x0604, 0x0c08, 0x2120,
+	0x4022, 0xf880, 0x0018, 0x300b, 0xa201, 0x0014, 0xa200, 0x0014,
+	0xa200, 0x0214, 0xa202, 0x8838, 0x3806, 0x8839, 0x20c3, 0x0864,
+	0xa833, 0x28c1, 0x9cb6, 0xa203, 0x300c, 0x2846, 0x8161, 0x846a,
+	0x8300, 0x1856, 0x883a, 0xa804, 0x28f2, 0x9c95, 0xa8f4, 0x300c,
+	0x28e1, 0x9c95, 0x2809, 0xa206, 0x64c0, 0x67a0, 0x6fc0, 0x1814,
+	0x883b, 0x782c, 0x786d, 0xa808, 0x282b, 0xa207, 0x64a0, 0x67a0,
+	0x6fc0, 0x1814, 0x883b, 0x7822, 0x883e, 0xa802, 0x8576, 0x8677,
+	0x206b, 0x28c1, 0x9cb6, 0x2044, 0x2103, 0x20a2, 0x2081, 0xa8e0,
+	0xa209, 0x2901, 0xa809, 0x0014, 0xa205, 0xa300, 0x1872, 0x879a,
+	0x883c, 0x1fe2, 0xc601, 0xa20a, 0x856e, 0x0704, 0x9c95, 0x0014,
+	0xa204, 0xa300, 0x3009, 0x19e2, 0xf868, 0x8176, 0x86eb, 0x85eb,
+	0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f3, 0xf881, 0xa8ec, 0xc801,
+	0x0014, 0xf8c1, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfb02, 0x1de2,
+	0x0014, 0x8532, 0xf241, 0x0014, 0x1de2, 0x84a8, 0xd7a0, 0x1fe6,
+	0x0014, 0xa208, 0x6043, 0x8008, 0x1dc1, 0x0016, 0x8300, 0x8160,
+	0x842a, 0xf041, 0x3008, 0x84a8, 0x11d6, 0x7042, 0x20dd, 0x0011,
+	0x20d5, 0x8822, 0x0016, 0x8000, 0x2847, 0x1011, 0xa8fc, 0x8000,
+	0xa000, 0x2802, 0x1011, 0xa8fd, 0xa893, 0x283e, 0x1011, 0xa8fd,
+	0xa20b, 0x0017, 0x300c, 0xa300, 0x1de2, 0xdb81, 0x0014, 0x0210,
+	0xa801, 0x0014, 0x26e0, 0x873a, 0xfb02, 0x19f2, 0x1fe2, 0x0014,
+	0xa20d, 0x3806, 0x0210, 0x9cbb, 0x0704, 0x0017, 0x60ff, 0x300c,
+	0x8720, 0xa211, 0x9d6b, 0x8772, 0x8837, 0x2101, 0xa821, 0x10d2,
+	0x78e2, 0x9d6e, 0xa8fc, 0xd984, 0xf0e2, 0xf0a1, 0xa86c, 0x0014,
+	0x8831, 0xd166, 0x8830, 0x800f, 0x9401, 0xb520, 0xc802, 0x8820,
+	0xa80f, 0x2301, 0xa80d, 0x10d2, 0x78e4, 0x9d6e, 0x8821, 0x8820,
+	0xa8e6, 0xf123, 0xf142, 0xf101, 0xa84f, 0x10d2, 0x70f6, 0x8832,
+	0x8203, 0x870c, 0xd99e, 0x6001, 0x0014, 0x6845, 0x0214, 0xa21b,
+	0x9d6b, 0x2001, 0xa840, 0x8201, 0x1852, 0xd184, 0xd163, 0x8834,
+	0x8001, 0xa801, 0x3027, 0x84a8, 0x1a56, 0x8833, 0x0014, 0xa218,
+	0x6981, 0x9d57, 0x6b2a, 0x6902, 0x1834, 0xa805, 0x1814, 0x8010,
+	0x8592, 0x8026, 0x84b9, 0x7021, 0x0014, 0xa300, 0x69e1, 0x9d44,
+	0x694b, 0xa213, 0x1462, 0xa213, 0x8000, 0x16e1, 0xa80c, 0x8023,
+	0x16e1, 0x8001, 0x10f1, 0x0016, 0x6969, 0xa214, 0x61c2, 0x8002,
+	0x14e1, 0x8004, 0x16e1, 0x0101, 0x300a, 0x8827, 0x0014, 0xa217,
+	0x9d57, 0x0014, 0xa300, 0x8181, 0x842a, 0x84a8, 0x1ce6, 0x882c,
+	0x0016, 0xa212, 0x9d6b, 0x10d2, 0x70e4, 0x0004, 0x8007, 0x9424,
+	0xcc1a, 0x9d6e, 0xa8f8, 0x8827, 0x300a, 0x0013, 0x8000, 0x84a4,
+	0x0016, 0x11c2, 0x211e, 0x870e, 0xa21d, 0x0014, 0x878e, 0x0016,
+	0xa21c, 0x1035, 0xa8b4, 0xa210, 0x3807, 0x300c, 0x817e, 0x872b,
+	0x8772, 0xa8ad, 0x0000, 0x8ec6
+};
+
+#endif /* RELOAD_FIRMWARE */
+
+static const unsigned short risc_code_length01 = 0x3f14;
diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c
new file mode 100644
index 0000000..a917ab7
--- /dev/null
+++ b/drivers/scsi/qlogicpti.c
@@ -0,0 +1,1541 @@
+/* qlogicpti.c: Performance Technologies QlogicISP sbus card driver.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ *
+ * A lot of this driver was directly stolen from Erik H. Moe's PCI
+ * Qlogic ISP driver.  Mucho kudos to him for this code.
+ *
+ * An even bigger kudos to John Grana at Performance Technologies
+ * for providing me with the hardware to write this driver, you rule
+ * John you really do.
+ *
+ * May, 2, 1997: Added support for QLGC,isp --jj
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+
+#include <asm/byteorder.h>
+
+#include "qlogicpti.h"
+
+#include <asm/sbus.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/ptrace.h>
+#include <asm/pgtable.h>
+#include <asm/oplib.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_host.h>
+
+
+
+#define MAX_TARGETS	16
+#define MAX_LUNS	8	/* 32 for 1.31 F/W */
+
+#define DEFAULT_LOOP_COUNT	10000
+
+#include "qlogicpti_asm.c"
+
+static struct qlogicpti *qptichain = NULL;
+static DEFINE_SPINLOCK(qptichain_lock);
+static int qptis_running = 0;
+
+#define PACKB(a, b)			(((a)<<4)|(b))
+
+static const u_char mbox_param[] = {
+	PACKB(1, 1),	/* MBOX_NO_OP */
+	PACKB(5, 5),	/* MBOX_LOAD_RAM */
+	PACKB(2, 0),	/* MBOX_EXEC_FIRMWARE */
+	PACKB(5, 5),	/* MBOX_DUMP_RAM */
+	PACKB(3, 3),	/* MBOX_WRITE_RAM_WORD */
+	PACKB(2, 3),	/* MBOX_READ_RAM_WORD */
+	PACKB(6, 6),	/* MBOX_MAILBOX_REG_TEST */
+	PACKB(2, 3),	/* MBOX_VERIFY_CHECKSUM	*/
+	PACKB(1, 3),	/* MBOX_ABOUT_FIRMWARE */
+	PACKB(0, 0),	/* 0x0009 */
+	PACKB(0, 0),	/* 0x000a */
+	PACKB(0, 0),	/* 0x000b */
+	PACKB(0, 0),	/* 0x000c */
+	PACKB(0, 0),	/* 0x000d */
+	PACKB(1, 2),	/* MBOX_CHECK_FIRMWARE */
+	PACKB(0, 0),	/* 0x000f */
+	PACKB(5, 5),	/* MBOX_INIT_REQ_QUEUE */
+	PACKB(6, 6),	/* MBOX_INIT_RES_QUEUE */
+	PACKB(4, 4),	/* MBOX_EXECUTE_IOCB */
+	PACKB(2, 2),	/* MBOX_WAKE_UP	*/
+	PACKB(1, 6),	/* MBOX_STOP_FIRMWARE */
+	PACKB(4, 4),	/* MBOX_ABORT */
+	PACKB(2, 2),	/* MBOX_ABORT_DEVICE */
+	PACKB(3, 3),	/* MBOX_ABORT_TARGET */
+	PACKB(2, 2),	/* MBOX_BUS_RESET */
+	PACKB(2, 3),	/* MBOX_STOP_QUEUE */
+	PACKB(2, 3),	/* MBOX_START_QUEUE */
+	PACKB(2, 3),	/* MBOX_SINGLE_STEP_QUEUE */
+	PACKB(2, 3),	/* MBOX_ABORT_QUEUE */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_STATUS */
+	PACKB(0, 0),	/* 0x001e */
+	PACKB(1, 3),	/* MBOX_GET_FIRMWARE_STATUS */
+	PACKB(1, 2),	/* MBOX_GET_INIT_SCSI_ID */
+	PACKB(1, 2),	/* MBOX_GET_SELECT_TIMEOUT */
+	PACKB(1, 3),	/* MBOX_GET_RETRY_COUNT	*/
+	PACKB(1, 2),	/* MBOX_GET_TAG_AGE_LIMIT */
+	PACKB(1, 2),	/* MBOX_GET_CLOCK_RATE */
+	PACKB(1, 2),	/* MBOX_GET_ACT_NEG_STATE */
+	PACKB(1, 2),	/* MBOX_GET_ASYNC_DATA_SETUP_TIME */
+	PACKB(1, 3),	/* MBOX_GET_SBUS_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_TARGET_PARAMS */
+	PACKB(2, 4),	/* MBOX_GET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x002a */
+	PACKB(0, 0),	/* 0x002b */
+	PACKB(0, 0),	/* 0x002c */
+	PACKB(0, 0),	/* 0x002d */
+	PACKB(0, 0),	/* 0x002e */
+	PACKB(0, 0),	/* 0x002f */
+	PACKB(2, 2),	/* MBOX_SET_INIT_SCSI_ID */
+	PACKB(2, 2),	/* MBOX_SET_SELECT_TIMEOUT */
+	PACKB(3, 3),	/* MBOX_SET_RETRY_COUNT	*/
+	PACKB(2, 2),	/* MBOX_SET_TAG_AGE_LIMIT */
+	PACKB(2, 2),	/* MBOX_SET_CLOCK_RATE */
+	PACKB(2, 2),	/* MBOX_SET_ACTIVE_NEG_STATE */
+	PACKB(2, 2),	/* MBOX_SET_ASYNC_DATA_SETUP_TIME */
+	PACKB(3, 3),	/* MBOX_SET_SBUS_CONTROL_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_TARGET_PARAMS */
+	PACKB(4, 4),	/* MBOX_SET_DEV_QUEUE_PARAMS */
+	PACKB(0, 0),	/* 0x003a */
+	PACKB(0, 0),	/* 0x003b */
+	PACKB(0, 0),	/* 0x003c */
+	PACKB(0, 0),	/* 0x003d */
+	PACKB(0, 0),	/* 0x003e */
+	PACKB(0, 0),	/* 0x003f */
+	PACKB(0, 0),	/* 0x0040 */
+	PACKB(0, 0),	/* 0x0041 */
+	PACKB(0, 0)	/* 0x0042 */
+};
+
+#define MAX_MBOX_COMMAND	(sizeof(mbox_param)/sizeof(u_short))
+
+/* queue length's _must_ be power of two: */
+#define QUEUE_DEPTH(in, out, ql)	((in - out) & (ql))
+#define REQ_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, 		     \
+						    QLOGICPTI_REQ_QUEUE_LEN)
+#define RES_QUEUE_DEPTH(in, out)	QUEUE_DEPTH(in, out, RES_QUEUE_LEN)
+
+static inline void qlogicpti_enable_irqs(struct qlogicpti *qpti)
+{
+	sbus_writew(SBUS_CTRL_ERIRQ | SBUS_CTRL_GENAB,
+		    qpti->qregs + SBUS_CTRL);
+}
+
+static inline void qlogicpti_disable_irqs(struct qlogicpti *qpti)
+{
+	sbus_writew(0, qpti->qregs + SBUS_CTRL);
+}
+
+static inline void set_sbus_cfg1(struct qlogicpti *qpti)
+{
+	u16 val;
+	u8 bursts = qpti->bursts;
+
+#if 0	/* It appears that at least PTI cards do not support
+	 * 64-byte bursts and that setting the B64 bit actually
+	 * is a nop and the chip ends up using the smallest burst
+	 * size. -DaveM
+	 */
+	if (sbus_can_burst64(qpti->sdev) && (bursts & DMA_BURST64)) {
+		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B64);
+	} else
+#endif
+	if (bursts & DMA_BURST32) {
+		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B32);
+	} else if (bursts & DMA_BURST16) {
+		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B16);
+	} else if (bursts & DMA_BURST8) {
+		val = (SBUS_CFG1_BENAB | SBUS_CFG1_B8);
+	} else {
+		val = 0; /* No sbus bursts for you... */
+	}
+	sbus_writew(val, qpti->qregs + SBUS_CFG1);
+}
+
+static int qlogicpti_mbox_command(struct qlogicpti *qpti, u_short param[], int force)
+{
+	int loop_count;
+	u16 tmp;
+
+	if (mbox_param[param[0]] == 0)
+		return 1;
+
+	/* Set SBUS semaphore. */
+	tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE);
+	tmp |= SBUS_SEMAPHORE_LCK;
+	sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE);
+
+	/* Wait for host IRQ bit to clear. */
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_HIRQ)) {
+		barrier();
+		cpu_relax();
+	}
+	if (!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command loop timeout #1\n");
+
+	/* Write mailbox command registers. */
+	switch (mbox_param[param[0]] >> 4) {
+	case 6: sbus_writew(param[5], qpti->qregs + MBOX5);
+	case 5: sbus_writew(param[4], qpti->qregs + MBOX4);
+	case 4: sbus_writew(param[3], qpti->qregs + MBOX3);
+	case 3: sbus_writew(param[2], qpti->qregs + MBOX2);
+	case 2: sbus_writew(param[1], qpti->qregs + MBOX1);
+	case 1: sbus_writew(param[0], qpti->qregs + MBOX0);
+	}
+
+	/* Clear RISC interrupt. */
+	tmp = sbus_readw(qpti->qregs + HCCTRL);
+	tmp |= HCCTRL_CRIRQ;
+	sbus_writew(tmp, qpti->qregs + HCCTRL);
+
+	/* Clear SBUS semaphore. */
+	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);
+
+	/* Set HOST interrupt. */
+	tmp = sbus_readw(qpti->qregs + HCCTRL);
+	tmp |= HCCTRL_SHIRQ;
+	sbus_writew(tmp, qpti->qregs + HCCTRL);
+
+	/* Wait for HOST interrupt clears. */
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count &&
+	       (sbus_readw(qpti->qregs + HCCTRL) & HCCTRL_CRIRQ))
+		udelay(20);
+	if (!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #2\n",
+		       param[0]);
+
+	/* Wait for SBUS semaphore to get set. */
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count &&
+	       !(sbus_readw(qpti->qregs + SBUS_SEMAPHORE) & SBUS_SEMAPHORE_LCK)) {
+		udelay(20);
+
+		/* Workaround for some buggy chips. */
+		if (sbus_readw(qpti->qregs + MBOX0) & 0x4000)
+			break;
+	}
+	if (!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #3\n",
+		       param[0]);
+
+	/* Wait for MBOX busy condition to go away. */
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && (sbus_readw(qpti->qregs + MBOX0) == 0x04))
+		udelay(20);
+	if (!loop_count)
+		printk(KERN_EMERG "qlogicpti: mbox_command[%04x] loop timeout #4\n",
+		       param[0]);
+
+	/* Read back output parameters. */
+	switch (mbox_param[param[0]] & 0xf) {
+	case 6: param[5] = sbus_readw(qpti->qregs + MBOX5);
+	case 5: param[4] = sbus_readw(qpti->qregs + MBOX4);
+	case 4: param[3] = sbus_readw(qpti->qregs + MBOX3);
+	case 3: param[2] = sbus_readw(qpti->qregs + MBOX2);
+	case 2: param[1] = sbus_readw(qpti->qregs + MBOX1);
+	case 1: param[0] = sbus_readw(qpti->qregs + MBOX0);
+	}
+
+	/* Clear RISC interrupt. */
+	tmp = sbus_readw(qpti->qregs + HCCTRL);
+	tmp |= HCCTRL_CRIRQ;
+	sbus_writew(tmp, qpti->qregs + HCCTRL);
+
+	/* Release SBUS semaphore. */
+	tmp = sbus_readw(qpti->qregs + SBUS_SEMAPHORE);
+	tmp &= ~(SBUS_SEMAPHORE_LCK);
+	sbus_writew(tmp, qpti->qregs + SBUS_SEMAPHORE);
+
+	/* We're done. */
+	return 0;
+}
+
+static inline void qlogicpti_set_hostdev_defaults(struct qlogicpti *qpti)
+{
+	int i;
+
+	qpti->host_param.initiator_scsi_id = qpti->scsi_id;
+	qpti->host_param.bus_reset_delay = 3;
+	qpti->host_param.retry_count = 0;
+	qpti->host_param.retry_delay = 5;
+	qpti->host_param.async_data_setup_time = 3;
+	qpti->host_param.req_ack_active_negation = 1;
+	qpti->host_param.data_line_active_negation = 1;
+	qpti->host_param.data_dma_burst_enable = 1;
+	qpti->host_param.command_dma_burst_enable = 1;
+	qpti->host_param.tag_aging = 8;
+	qpti->host_param.selection_timeout = 250;
+	qpti->host_param.max_queue_depth = 256;
+
+	for(i = 0; i < MAX_TARGETS; i++) {
+		/*
+		 * disconnect, parity, arq, reneg on reset, and, oddly enough
+		 * tags...the midlayer's notion of tagged support has to match
+		 * our device settings, and since we base whether we enable a
+		 * tag on a  per-cmnd basis upon what the midlayer sez, we
+		 * actually enable the capability here.
+		 */
+		qpti->dev_param[i].device_flags = 0xcd;
+		qpti->dev_param[i].execution_throttle = 16;
+		if (qpti->ultra) {
+			qpti->dev_param[i].synchronous_period = 12;
+			qpti->dev_param[i].synchronous_offset = 8;
+		} else {
+			qpti->dev_param[i].synchronous_period = 25;
+			qpti->dev_param[i].synchronous_offset = 12;
+		}
+		qpti->dev_param[i].device_enable = 1;
+	}
+	/* this is very important to set! */
+	qpti->sbits = 1 << qpti->scsi_id;
+}
+
+static int qlogicpti_reset_hardware(struct Scsi_Host *host)
+{
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	u_short param[6];
+	unsigned short risc_code_addr;
+	int loop_count, i;
+	unsigned long flags;
+
+	risc_code_addr = 0x1000;	/* all load addresses are at 0x1000 */
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);
+
+	/* Only reset the scsi bus if it is not free. */
+	if (sbus_readw(qpti->qregs + CPU_PCTRL) & CPU_PCTRL_BSY) {
+		sbus_writew(CPU_ORIDE_RMOD, qpti->qregs + CPU_ORIDE);
+		sbus_writew(CPU_CMD_BRESET, qpti->qregs + CPU_CMD);
+		udelay(400);
+	}
+
+	sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL);
+	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL);
+	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL);
+
+	loop_count = DEFAULT_LOOP_COUNT;
+	while (--loop_count && ((sbus_readw(qpti->qregs + MBOX0) & 0xff) == 0x04))
+		udelay(20);
+	if (!loop_count)
+		printk(KERN_EMERG "qlogicpti: reset_hardware loop timeout\n");
+
+	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);
+	set_sbus_cfg1(qpti);
+	qlogicpti_enable_irqs(qpti);
+
+	if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) {
+		qpti->ultra = 1;
+		sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA),
+			    qpti->qregs + RISC_MTREG);
+	} else {
+		qpti->ultra = 0;
+		sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT),
+			    qpti->qregs + RISC_MTREG);
+	}
+
+	/* reset adapter and per-device default values. */
+	/* do it after finding out whether we're ultra mode capable */
+	qlogicpti_set_hostdev_defaults(qpti);
+
+	/* Release the RISC processor. */
+	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);
+
+	/* Get RISC to start executing the firmware code. */
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr;
+	if (qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot execute ISP firmware.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	/* Set initiator scsi ID. */
+	param[0] = MBOX_SET_INIT_SCSI_ID;
+	param[1] = qpti->host_param.initiator_scsi_id;
+	if (qlogicpti_mbox_command(qpti, param, 1) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot set initiator SCSI ID.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	/* Initialize state of the queues, both hw and sw. */
+	qpti->req_in_ptr = qpti->res_out_ptr = 0;
+
+	param[0] = MBOX_INIT_RES_QUEUE;
+	param[1] = RES_QUEUE_LEN + 1;
+	param[2] = (u_short) (qpti->res_dvma >> 16);
+	param[3] = (u_short) (qpti->res_dvma & 0xffff);
+	param[4] = param[5] = 0;
+	if (qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot init response queue.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	param[0] = MBOX_INIT_REQ_QUEUE;
+	param[1] = QLOGICPTI_REQ_QUEUE_LEN + 1;
+	param[2] = (u_short) (qpti->req_dvma >> 16);
+	param[3] = (u_short) (qpti->req_dvma & 0xffff);
+	param[4] = param[5] = 0;
+	if (qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot init request queue.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	param[0] = MBOX_SET_RETRY_COUNT;
+	param[1] = qpti->host_param.retry_count;
+	param[2] = qpti->host_param.retry_delay;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	param[0] = MBOX_SET_TAG_AGE_LIMIT;
+	param[1] = qpti->host_param.tag_aging;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+		param[0] = MBOX_GET_DEV_QUEUE_PARAMS;
+		param[1] = (i << 8);
+		qlogicpti_mbox_command(qpti, param, 0);
+	}
+
+	param[0] = MBOX_GET_FIRMWARE_STATUS;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	param[0] = MBOX_SET_SELECT_TIMEOUT;
+	param[1] = qpti->host_param.selection_timeout;
+	qlogicpti_mbox_command(qpti, param, 0);
+
+	for (i = 0; i < MAX_TARGETS; i++) {
+		param[0] = MBOX_SET_TARGET_PARAMS;
+		param[1] = (i << 8);
+		param[2] = (qpti->dev_param[i].device_flags << 8);
+		/*
+		 * Since we're now loading 1.31 f/w, force narrow/async.
+		 */
+		param[2] |= 0xc0;
+		param[3] = 0;	/* no offset, we do not have sync mode yet */
+		qlogicpti_mbox_command(qpti, param, 0);
+	}
+
+	/*
+	 * Always (sigh) do an initial bus reset (kicks f/w).
+	 */
+	param[0] = MBOX_BUS_RESET;
+	param[1] = qpti->host_param.bus_reset_delay;
+	qlogicpti_mbox_command(qpti, param, 0);
+	qpti->send_marker = 1;
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return 0;
+}
+
+#define PTI_RESET_LIMIT 400
+
+static int __init qlogicpti_load_firmware(struct qlogicpti *qpti)
+{
+	struct Scsi_Host *host = qpti->qhost;
+	unsigned short csum = 0;
+	unsigned short param[6];
+	unsigned short *risc_code, risc_code_addr, risc_code_length;
+	unsigned long flags;
+	int i, timeout;
+
+	risc_code = &sbus_risc_code01[0];
+	risc_code_addr = 0x1000;	/* all f/w modules load at 0x1000 */
+	risc_code_length = sbus_risc_code_length01;
+
+	spin_lock_irqsave(host->host_lock, flags);
+
+	/* Verify the checksum twice, one before loading it, and once
+	 * afterwards via the mailbox commands.
+	 */
+	for (i = 0; i < risc_code_length; i++)
+		csum += risc_code[i];
+	if (csum) {
+		spin_unlock_irqrestore(host->host_lock, flags);
+		printk(KERN_EMERG "qlogicpti%d: Aieee, firmware checksum failed!",
+		       qpti->qpti_id);
+		return 1;
+	}		
+	sbus_writew(SBUS_CTRL_RESET, qpti->qregs + SBUS_CTRL);
+	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + CMD_DMA_CTRL);
+	sbus_writew((DMA_CTRL_CCLEAR | DMA_CTRL_CIRQ), qpti->qregs + DATA_DMA_CTRL);
+	timeout = PTI_RESET_LIMIT;
+	while (--timeout && (sbus_readw(qpti->qregs + SBUS_CTRL) & SBUS_CTRL_RESET))
+		udelay(20);
+	if (!timeout) {
+		spin_unlock_irqrestore(host->host_lock, flags);
+		printk(KERN_EMERG "qlogicpti%d: Cannot reset the ISP.", qpti->qpti_id);
+		return 1;
+	}
+
+	sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL);
+	mdelay(1);
+
+	sbus_writew((SBUS_CTRL_GENAB | SBUS_CTRL_ERIRQ), qpti->qregs + SBUS_CTRL);
+	set_sbus_cfg1(qpti);
+	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);
+
+	if (sbus_readw(qpti->qregs + RISC_PSR) & RISC_PSR_ULTRA) {
+		qpti->ultra = 1;
+		sbus_writew((RISC_MTREG_P0ULTRA | RISC_MTREG_P1ULTRA),
+			    qpti->qregs + RISC_MTREG);
+	} else {
+		qpti->ultra = 0;
+		sbus_writew((RISC_MTREG_P0DFLT | RISC_MTREG_P1DFLT),
+			    qpti->qregs + RISC_MTREG);
+	}
+
+	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);
+
+	/* Pin lines are only stable while RISC is paused. */
+	sbus_writew(HCCTRL_PAUSE, qpti->qregs + HCCTRL);
+	if (sbus_readw(qpti->qregs + CPU_PDIFF) & CPU_PDIFF_MODE)
+		qpti->differential = 1;
+	else
+		qpti->differential = 0;
+	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);
+
+	/* This shouldn't be necessary- we've reset things so we should be
+	   running from the ROM now.. */
+
+	param[0] = MBOX_STOP_FIRMWARE;
+	param[1] = param[2] = param[3] = param[4] = param[5] = 0;
+	if (qlogicpti_mbox_command(qpti, param, 1)) {
+		printk(KERN_EMERG "qlogicpti%d: Cannot stop firmware for reload.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}		
+
+	/* Load it up.. */
+	for (i = 0; i < risc_code_length; i++) {
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = risc_code_addr + i;
+		param[2] = risc_code[i];
+		if (qlogicpti_mbox_command(qpti, param, 1) ||
+		    param[0] != MBOX_COMMAND_COMPLETE) {
+			printk("qlogicpti%d: Firmware dload failed, I'm bolixed!\n",
+			       qpti->qpti_id);
+			spin_unlock_irqrestore(host->host_lock, flags);
+			return 1;
+		}
+	}
+
+	/* Reset the ISP again. */
+	sbus_writew(HCCTRL_RESET, qpti->qregs + HCCTRL);
+	mdelay(1);
+
+	qlogicpti_enable_irqs(qpti);
+	sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);
+	sbus_writew(HCCTRL_REL, qpti->qregs + HCCTRL);
+
+	/* Ask ISP to verify the checksum of the new code. */
+	param[0] = MBOX_VERIFY_CHECKSUM;
+	param[1] = risc_code_addr;
+	if (qlogicpti_mbox_command(qpti, param, 1) ||
+	    (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: New firmware csum failure!\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	/* Start using newly downloaded firmware. */
+	param[0] = MBOX_EXEC_FIRMWARE;
+	param[1] = risc_code_addr;
+	qlogicpti_mbox_command(qpti, param, 1);
+
+	param[0] = MBOX_ABOUT_FIRMWARE;
+	if (qlogicpti_mbox_command(qpti, param, 1) ||
+	    (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: AboutFirmware cmd fails.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	/* Snag the major and minor revisions from the result. */
+	qpti->fware_majrev = param[1];
+	qpti->fware_minrev = param[2];
+	qpti->fware_micrev = param[3];
+
+	/* Set the clock rate */
+	param[0] = MBOX_SET_CLOCK_RATE;
+	param[1] = qpti->clock;
+	if (qlogicpti_mbox_command(qpti, param, 1) ||
+	    (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti%d: could not set clock rate.\n",
+		       qpti->qpti_id);
+		spin_unlock_irqrestore(host->host_lock, flags);
+		return 1;
+	}
+
+	if (qpti->is_pti != 0) {
+		/* Load scsi initiator ID and interrupt level into sbus static ram. */
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = 0xff80;
+		param[2] = (unsigned short) qpti->scsi_id;
+		qlogicpti_mbox_command(qpti, param, 1);
+
+		param[0] = MBOX_WRITE_RAM_WORD;
+		param[1] = 0xff00;
+		param[2] = (unsigned short) 3;
+		qlogicpti_mbox_command(qpti, param, 1);
+	}
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return 0;
+}
+
+static int qlogicpti_verify_tmon(struct qlogicpti *qpti)
+{
+	int curstat = sbus_readb(qpti->sreg);
+
+	curstat &= 0xf0;
+	if (!(curstat & SREG_FUSE) && (qpti->swsreg & SREG_FUSE))
+		printk("qlogicpti%d: Fuse returned to normal state.\n", qpti->qpti_id);
+	if (!(curstat & SREG_TPOWER) && (qpti->swsreg & SREG_TPOWER))
+		printk("qlogicpti%d: termpwr back to normal state.\n", qpti->qpti_id);
+	if (curstat != qpti->swsreg) {
+		int error = 0;
+		if (curstat & SREG_FUSE) {
+			error++;
+			printk("qlogicpti%d: Fuse is open!\n", qpti->qpti_id);
+		}
+		if (curstat & SREG_TPOWER) {
+			error++;
+			printk("qlogicpti%d: termpwr failure\n", qpti->qpti_id);
+		}
+		if (qpti->differential &&
+		    (curstat & SREG_DSENSE) != SREG_DSENSE) {
+			error++;
+			printk("qlogicpti%d: You have a single ended device on a "
+			       "differential bus!  Please fix!\n", qpti->qpti_id);
+		}
+		qpti->swsreg = curstat;
+		return error;
+	}
+	return 0;
+}
+
+static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs);
+
+static void __init qpti_chain_add(struct qlogicpti *qpti)
+{
+	spin_lock_irq(&qptichain_lock);
+	if (qptichain != NULL) {
+		struct qlogicpti *qlink = qptichain;
+
+		while(qlink->next)
+			qlink = qlink->next;
+		qlink->next = qpti;
+	} else {
+		qptichain = qpti;
+	}
+	qpti->next = NULL;
+	spin_unlock_irq(&qptichain_lock);
+}
+
+static void __init qpti_chain_del(struct qlogicpti *qpti)
+{
+	spin_lock_irq(&qptichain_lock);
+	if (qptichain == qpti) {
+		qptichain = qpti->next;
+	} else {
+		struct qlogicpti *qlink = qptichain;
+		while(qlink->next != qpti)
+			qlink = qlink->next;
+		qlink->next = qpti->next;
+	}
+	qpti->next = NULL;
+	spin_unlock_irq(&qptichain_lock);
+}
+
+static int __init qpti_map_regs(struct qlogicpti *qpti)
+{
+	struct sbus_dev *sdev = qpti->sdev;
+
+	qpti->qregs = sbus_ioremap(&sdev->resource[0], 0,
+				   sdev->reg_addrs[0].reg_size,
+				   "PTI Qlogic/ISP");
+	if (!qpti->qregs) {
+		printk("PTI: Qlogic/ISP registers are unmappable\n");
+		return -1;
+	}
+	if (qpti->is_pti) {
+		qpti->sreg = sbus_ioremap(&sdev->resource[0], (16 * 4096),
+					  sizeof(unsigned char),
+					  "PTI Qlogic/ISP statreg");
+		if (!qpti->sreg) {
+			printk("PTI: Qlogic/ISP status register is unmappable\n");
+			return -1;
+		}
+	}
+	return 0;
+}
+
+static int __init qpti_register_irq(struct qlogicpti *qpti)
+{
+	struct sbus_dev *sdev = qpti->sdev;
+
+	qpti->qhost->irq = qpti->irq = sdev->irqs[0];
+
+	/* We used to try various overly-clever things to
+	 * reduce the interrupt processing overhead on
+	 * sun4c/sun4m when multiple PTI's shared the
+	 * same IRQ.  It was too complex and messy to
+	 * sanely maintain.
+	 */
+	if (request_irq(qpti->irq, qpti_intr,
+			SA_SHIRQ, "Qlogic/PTI", qpti))
+		goto fail;
+
+	printk("qpti%d: IRQ %s ", qpti->qpti_id, __irq_itoa(qpti->irq));
+
+	return 0;
+
+fail:
+	printk("qpti%d: Cannot acquire irq line\n", qpti->qpti_id);
+	return -1;
+}
+
+static void __init qpti_get_scsi_id(struct qlogicpti *qpti)
+{
+	qpti->scsi_id = prom_getintdefault(qpti->prom_node,
+					   "initiator-id",
+					   -1);
+	if (qpti->scsi_id == -1)
+		qpti->scsi_id = prom_getintdefault(qpti->prom_node,
+						   "scsi-initiator-id",
+						   -1);
+	if (qpti->scsi_id == -1)
+		qpti->scsi_id =
+			prom_getintdefault(qpti->sdev->bus->prom_node,
+					   "scsi-initiator-id", 7);
+	qpti->qhost->this_id = qpti->scsi_id;
+	qpti->qhost->max_sectors = 64;
+
+	printk("SCSI ID %d ", qpti->scsi_id);
+}
+
+static void qpti_get_bursts(struct qlogicpti *qpti)
+{
+	struct sbus_dev *sdev = qpti->sdev;
+	u8 bursts, bmask;
+
+	bursts = prom_getintdefault(qpti->prom_node, "burst-sizes", 0xff);
+	bmask = prom_getintdefault(sdev->bus->prom_node,
+				   "burst-sizes", 0xff);
+	if (bmask != 0xff)
+		bursts &= bmask;
+	if (bursts == 0xff ||
+	    (bursts & DMA_BURST16) == 0 ||
+	    (bursts & DMA_BURST32) == 0)
+		bursts = (DMA_BURST32 - 1);
+
+	qpti->bursts = bursts;
+}
+
+static void qpti_get_clock(struct qlogicpti *qpti)
+{
+	unsigned int cfreq;
+
+	/* Check for what the clock input to this card is.
+	 * Default to 40Mhz.
+	 */
+	cfreq = prom_getintdefault(qpti->prom_node,"clock-frequency",40000000);
+	qpti->clock = (cfreq + 500000)/1000000;
+	if (qpti->clock == 0) /* bullshit */
+		qpti->clock = 40;
+}
+
+/* The request and response queues must each be aligned
+ * on a page boundary.
+ */
+static int __init qpti_map_queues(struct qlogicpti *qpti)
+{
+	struct sbus_dev *sdev = qpti->sdev;
+
+#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
+	qpti->res_cpu = sbus_alloc_consistent(sdev,
+					      QSIZE(RES_QUEUE_LEN),
+					      &qpti->res_dvma);
+	if (qpti->res_cpu == NULL ||
+	    qpti->res_dvma == 0) {
+		printk("QPTI: Cannot map response queue.\n");
+		return -1;
+	}
+
+	qpti->req_cpu = sbus_alloc_consistent(sdev,
+					      QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+					      &qpti->req_dvma);
+	if (qpti->req_cpu == NULL ||
+	    qpti->req_dvma == 0) {
+		sbus_free_consistent(sdev, QSIZE(RES_QUEUE_LEN),
+				     qpti->res_cpu, qpti->res_dvma);
+		printk("QPTI: Cannot map request queue.\n");
+		return -1;
+	}
+	memset(qpti->res_cpu, 0, QSIZE(RES_QUEUE_LEN));
+	memset(qpti->req_cpu, 0, QSIZE(QLOGICPTI_REQ_QUEUE_LEN));
+	return 0;
+}
+
+/* Detect all PTI Qlogic ISP's in the machine. */
+static int __init qlogicpti_detect(struct scsi_host_template *tpnt)
+{
+	struct qlogicpti *qpti;
+	struct Scsi_Host *qpti_host;
+	struct sbus_bus *sbus;
+	struct sbus_dev *sdev;
+	int nqptis = 0, nqptis_in_use = 0;
+
+	tpnt->proc_name = "qlogicpti";
+	for_each_sbus(sbus) {
+		for_each_sbusdev(sdev, sbus) {
+			/* Is this a red snapper? */
+			if (strcmp(sdev->prom_name, "ptisp") &&
+			    strcmp(sdev->prom_name, "PTI,ptisp") &&
+			    strcmp(sdev->prom_name, "QLGC,isp") &&
+			    strcmp(sdev->prom_name, "SUNW,isp"))
+				continue;
+
+			/* Sometimes Antares cards come up not completely
+			 * setup, and we get a report of a zero IRQ.
+			 * Skip over them in such cases so we survive.
+			 */
+			if (sdev->irqs[0] == 0) {
+				printk("qpti%d: Adapter reports no interrupt, "
+				       "skipping over this card.", nqptis);
+				continue;
+			}
+
+			/* Yep, register and allocate software state. */
+			qpti_host = scsi_register(tpnt, sizeof(struct qlogicpti));
+			if (!qpti_host) {
+				printk("QPTI: Cannot register PTI Qlogic ISP SCSI host");
+				continue;
+			}
+			qpti = (struct qlogicpti *) qpti_host->hostdata;
+
+			/* We are wide capable, 16 targets. */
+			qpti_host->max_id = MAX_TARGETS;
+
+			/* Setup back pointers and misc. state. */
+			qpti->qhost = qpti_host;
+			qpti->sdev = sdev;
+			qpti->qpti_id = nqptis++;
+			qpti->prom_node = sdev->prom_node;
+			prom_getstring(qpti->prom_node, "name",
+				       qpti->prom_name,
+				       sizeof(qpti->prom_name));
+
+			/* This is not correct, actually. There's a switch
+			 * on the PTI cards that put them into "emulation"
+			 * mode- i.e., report themselves as QLGC,isp
+			 * instead of PTI,ptisp. The only real substantive
+			 * difference between non-pti and pti cards is
+			 * the tmon register. Which is possibly even
+			 * there for Qlogic cards, but non-functional.
+			 */
+			qpti->is_pti = (strcmp (qpti->prom_name, "QLGC,isp") != 0);
+
+			qpti_chain_add(qpti);
+			if (qpti_map_regs(qpti) < 0)
+				goto fail_unlink;
+
+			if (qpti_register_irq(qpti) < 0)
+				goto fail_unmap_regs;
+
+			qpti_get_scsi_id(qpti);
+			qpti_get_bursts(qpti);
+			qpti_get_clock(qpti);
+
+			/* Clear out scsi_cmnd array. */
+			memset(qpti->cmd_slots, 0, sizeof(qpti->cmd_slots));
+
+			if (qpti_map_queues(qpti) < 0)
+				goto fail_free_irq;
+
+			/* Load the firmware. */
+			if (qlogicpti_load_firmware(qpti))
+				goto fail_unmap_queues;
+			if (qpti->is_pti) {
+				/* Check the PTI status reg. */
+				if (qlogicpti_verify_tmon(qpti))
+					goto fail_unmap_queues;
+			}
+
+			/* Reset the ISP and init res/req queues. */
+			if (qlogicpti_reset_hardware(qpti_host))
+				goto fail_unmap_queues;
+
+			printk("(Firmware v%d.%d.%d)", qpti->fware_majrev,
+			    qpti->fware_minrev, qpti->fware_micrev);
+			{
+				char buffer[60];
+				
+				prom_getstring (qpti->prom_node,
+						"isp-fcode", buffer, 60);
+				if (buffer[0])
+					printk("(Firmware %s)", buffer);
+				if (prom_getbool(qpti->prom_node, "differential"))
+					qpti->differential = 1;
+			}
+			
+			printk (" [%s Wide, using %s interface]\n",
+			       (qpti->ultra ? "Ultra" : "Fast"),
+			       (qpti->differential ? "differential" : "single ended"));
+
+			nqptis_in_use++;
+			continue;
+
+		fail_unmap_queues:
+#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
+			sbus_free_consistent(qpti->sdev,
+					     QSIZE(RES_QUEUE_LEN),
+					     qpti->res_cpu, qpti->res_dvma);
+			sbus_free_consistent(qpti->sdev,
+					     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+					     qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+		fail_free_irq:
+			free_irq(qpti->irq, qpti);
+
+		fail_unmap_regs:
+			sbus_iounmap(qpti->qregs,
+				     qpti->sdev->reg_addrs[0].reg_size);
+			if (qpti->is_pti)
+				sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+		fail_unlink:
+			qpti_chain_del(qpti);
+			scsi_unregister(qpti->qhost);
+		}
+	}
+	if (nqptis)
+		printk("QPTI: Total of %d PTI Qlogic/ISP hosts found, %d actually in use.\n",
+		       nqptis, nqptis_in_use);
+	qptis_running = nqptis_in_use;
+	return nqptis;
+}
+
+static int qlogicpti_release(struct Scsi_Host *host)
+{
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+
+	/* Remove visibility from IRQ handlers. */
+	qpti_chain_del(qpti);
+
+	/* Shut up the card. */
+	sbus_writew(0, qpti->qregs + SBUS_CTRL);
+
+	/* Free IRQ handler and unmap Qlogic,ISP and PTI status regs. */
+	free_irq(qpti->irq, qpti);
+
+#define QSIZE(entries)	(((entries) + 1) * QUEUE_ENTRY_LEN)
+	sbus_free_consistent(qpti->sdev,
+			     QSIZE(RES_QUEUE_LEN),
+			     qpti->res_cpu, qpti->res_dvma);
+	sbus_free_consistent(qpti->sdev,
+			     QSIZE(QLOGICPTI_REQ_QUEUE_LEN),
+			     qpti->req_cpu, qpti->req_dvma);
+#undef QSIZE
+
+	sbus_iounmap(qpti->qregs, qpti->sdev->reg_addrs[0].reg_size);
+	if (qpti->is_pti)
+		sbus_iounmap(qpti->sreg, sizeof(unsigned char));
+
+	return 0;
+}
+
+const char *qlogicpti_info(struct Scsi_Host *host)
+{
+	static char buf[80];
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+
+	sprintf(buf, "PTI Qlogic,ISP SBUS SCSI irq %s regs at %p",
+		__irq_itoa(qpti->qhost->irq), qpti->qregs);
+	return buf;
+}
+
+/* I am a certified frobtronicist. */
+static inline void marker_frob(struct Command_Entry *cmd)
+{
+	struct Marker_Entry *marker = (struct Marker_Entry *) cmd;
+
+	memset(marker, 0, sizeof(struct Marker_Entry));
+	marker->hdr.entry_cnt = 1;
+	marker->hdr.entry_type = ENTRY_MARKER;
+	marker->modifier = SYNC_ALL;
+	marker->rsvd = 0;
+}
+
+static inline void cmd_frob(struct Command_Entry *cmd, struct scsi_cmnd *Cmnd,
+			    struct qlogicpti *qpti)
+{
+	memset(cmd, 0, sizeof(struct Command_Entry));
+	cmd->hdr.entry_cnt = 1;
+	cmd->hdr.entry_type = ENTRY_COMMAND;
+	cmd->target_id = Cmnd->device->id;
+	cmd->target_lun = Cmnd->device->lun;
+	cmd->cdb_length = Cmnd->cmd_len;
+	cmd->control_flags = 0;
+	if (Cmnd->device->tagged_supported) {
+		if (qpti->cmd_count[Cmnd->device->id] == 0)
+			qpti->tag_ages[Cmnd->device->id] = jiffies;
+		if ((jiffies - qpti->tag_ages[Cmnd->device->id]) > (5*HZ)) {
+			cmd->control_flags = CFLAG_ORDERED_TAG;
+			qpti->tag_ages[Cmnd->device->id] = jiffies;
+		} else
+			cmd->control_flags = CFLAG_SIMPLE_TAG;
+	}
+	if ((Cmnd->cmnd[0] == WRITE_6) ||
+	    (Cmnd->cmnd[0] == WRITE_10) ||
+	    (Cmnd->cmnd[0] == WRITE_12))
+		cmd->control_flags |= CFLAG_WRITE;
+	else
+		cmd->control_flags |= CFLAG_READ;
+	cmd->time_out = 30;
+	memcpy(cmd->cdb, Cmnd->cmnd, Cmnd->cmd_len);
+}
+
+/* Do it to it baby. */
+static inline int load_cmd(struct scsi_cmnd *Cmnd, struct Command_Entry *cmd,
+			   struct qlogicpti *qpti, u_int in_ptr, u_int out_ptr)
+{
+	struct dataseg *ds;
+	struct scatterlist *sg;
+	int i, n;
+
+	if (Cmnd->use_sg) {
+		int sg_count;
+
+		sg = (struct scatterlist *) Cmnd->buffer;
+		sg_count = sbus_map_sg(qpti->sdev, sg, Cmnd->use_sg, Cmnd->sc_data_direction);
+
+		ds = cmd->dataseg;
+		cmd->segment_cnt = sg_count;
+
+		/* Fill in first four sg entries: */
+		n = sg_count;
+		if (n > 4)
+			n = 4;
+		for (i = 0; i < n; i++, sg++) {
+			ds[i].d_base = sg_dma_address(sg);
+			ds[i].d_count = sg_dma_len(sg);
+		}
+		sg_count -= 4;
+		while (sg_count > 0) {
+			struct Continuation_Entry *cont;
+
+			++cmd->hdr.entry_cnt;
+			cont = (struct Continuation_Entry *) &qpti->req_cpu[in_ptr];
+			in_ptr = NEXT_REQ_PTR(in_ptr);
+			if (in_ptr == out_ptr)
+				return -1;
+
+			cont->hdr.entry_type = ENTRY_CONTINUATION;
+			cont->hdr.entry_cnt = 0;
+			cont->hdr.sys_def_1 = 0;
+			cont->hdr.flags = 0;
+			cont->reserved = 0;
+			ds = cont->dataseg;
+			n = sg_count;
+			if (n > 7)
+				n = 7;
+			for (i = 0; i < n; i++, sg++) {
+				ds[i].d_base = sg_dma_address(sg);
+				ds[i].d_count = sg_dma_len(sg);
+			}
+			sg_count -= n;
+		}
+	} else if (Cmnd->request_bufflen) {
+		Cmnd->SCp.ptr = (char *)(unsigned long)
+			sbus_map_single(qpti->sdev,
+					Cmnd->request_buffer,
+					Cmnd->request_bufflen,
+					Cmnd->sc_data_direction);
+
+		cmd->dataseg[0].d_base = (u32) ((unsigned long)Cmnd->SCp.ptr);
+		cmd->dataseg[0].d_count = Cmnd->request_bufflen;
+		cmd->segment_cnt = 1;
+	} else {
+		cmd->dataseg[0].d_base = 0;
+		cmd->dataseg[0].d_count = 0;
+		cmd->segment_cnt = 1; /* Shouldn't this be 0? */
+	}
+
+	/* Committed, record Scsi_Cmd so we can find it later. */
+	cmd->handle = in_ptr;
+	qpti->cmd_slots[in_ptr] = Cmnd;
+
+	qpti->cmd_count[Cmnd->device->id]++;
+	sbus_writew(in_ptr, qpti->qregs + MBOX4);
+	qpti->req_in_ptr = in_ptr;
+
+	return in_ptr;
+}
+
+static inline void update_can_queue(struct Scsi_Host *host, u_int in_ptr, u_int out_ptr)
+{
+	/* Temporary workaround until bug is found and fixed (one bug has been found
+	   already, but fixing it makes things even worse) -jj */
+	int num_free = QLOGICPTI_REQ_QUEUE_LEN - REQ_QUEUE_DEPTH(in_ptr, out_ptr) - 64;
+	host->can_queue = host->host_busy + num_free;
+	host->sg_tablesize = QLOGICPTI_MAX_SG(num_free);
+}
+
+/*
+ * Until we scan the entire bus with inquiries, go throught this fella...
+ */
+static void ourdone(struct scsi_cmnd *Cmnd)
+{
+	struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
+	int tgt = Cmnd->device->id;
+	void (*done) (struct scsi_cmnd *);
+
+	/* This grot added by DaveM, blame him for ugliness.
+	 * The issue is that in the 2.3.x driver we use the
+	 * host_scribble portion of the scsi command as a
+	 * completion linked list at interrupt service time,
+	 * so we have to store the done function pointer elsewhere.
+	 */
+	done = (void (*)(struct scsi_cmnd *))
+		(((unsigned long) Cmnd->SCp.Message)
+#ifdef __sparc_v9__
+		 | ((unsigned long) Cmnd->SCp.Status << 32UL)
+#endif
+		 );
+
+	if ((qpti->sbits & (1 << tgt)) == 0) {
+		int ok = host_byte(Cmnd->result) == DID_OK;
+		if (Cmnd->cmnd[0] == 0x12 && ok) {
+			unsigned char *iqd;
+
+			if (Cmnd->use_sg != 0)
+				BUG();
+
+			iqd = ((unsigned char *)Cmnd->buffer);
+
+			/* tags handled in midlayer */
+			/* enable sync mode? */
+			if (iqd[7] & 0x10) {
+				qpti->dev_param[tgt].device_flags |= 0x10;
+			} else {
+				qpti->dev_param[tgt].synchronous_offset = 0;
+				qpti->dev_param[tgt].synchronous_period = 0;
+			}
+			/* are we wide capable? */
+			if (iqd[7] & 0x20) {
+				qpti->dev_param[tgt].device_flags |= 0x20;
+			}
+			qpti->sbits |= (1 << tgt);
+		} else if (!ok) {
+			qpti->sbits |= (1 << tgt);
+		}
+	}
+	done(Cmnd);
+}
+
+static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *));
+
+static int qlogicpti_queuecommand_slow(struct scsi_cmnd *Cmnd,
+				       void (*done)(struct scsi_cmnd *))
+{
+	struct qlogicpti *qpti = (struct qlogicpti *) Cmnd->device->host->hostdata;
+
+	/*
+	 * done checking this host adapter?
+	 * If not, then rewrite the command
+	 * to finish through ourdone so we
+	 * can peek at Inquiry data results.
+	 */
+	if (qpti->sbits && qpti->sbits != 0xffff) {
+		/* See above about in ourdone this ugliness... */
+		Cmnd->SCp.Message = ((unsigned long)done) & 0xffffffff;
+#ifdef CONFIG_SPARC64
+		Cmnd->SCp.Status = ((unsigned long)done >> 32UL) & 0xffffffff;
+#endif
+		return qlogicpti_queuecommand(Cmnd, ourdone);
+	}
+
+	/*
+	 * We've peeked at all targets for this bus- time
+	 * to set parameters for devices for real now.
+	 */
+	if (qpti->sbits == 0xffff) {
+		int i;
+		for(i = 0; i < MAX_TARGETS; i++) {
+			u_short param[6];
+			param[0] = MBOX_SET_TARGET_PARAMS;
+			param[1] = (i << 8);
+			param[2] = (qpti->dev_param[i].device_flags << 8);
+			if (qpti->dev_param[i].device_flags & 0x10) {
+				param[3] = (qpti->dev_param[i].synchronous_offset << 8) |
+					qpti->dev_param[i].synchronous_period;
+			} else {
+				param[3] = 0;
+			}
+			(void) qlogicpti_mbox_command(qpti, param, 0);
+		}
+		/*
+		 * set to zero so any traverse through ourdone
+		 * doesn't start the whole process again,
+		 */
+		qpti->sbits = 0;
+	}
+
+	/* check to see if we're done with all adapters... */
+	for (qpti = qptichain; qpti != NULL; qpti = qpti->next) {
+		if (qpti->sbits) {
+			break;
+		}
+	}
+
+	/*
+	 * if we hit the end of the chain w/o finding adapters still
+	 * capability-configuring, then we're done with all adapters
+	 * and can rock on..
+	 */
+	if (qpti == NULL)
+		Cmnd->device->host->hostt->queuecommand = qlogicpti_queuecommand;
+
+	return qlogicpti_queuecommand(Cmnd, done);
+}
+
+/*
+ * The middle SCSI layer ensures that queuecommand never gets invoked
+ * concurrently with itself or the interrupt handler (though the
+ * interrupt handler may call this routine as part of
+ * request-completion handling).
+ *
+ * "This code must fly." -davem
+ */
+static int qlogicpti_queuecommand(struct scsi_cmnd *Cmnd, void (*done)(struct scsi_cmnd *))
+{
+	struct Scsi_Host *host = Cmnd->device->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	struct Command_Entry *cmd;
+	u_int out_ptr;
+	int in_ptr;
+
+	Cmnd->scsi_done = done;
+
+	in_ptr = qpti->req_in_ptr;
+	cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr];
+	out_ptr = sbus_readw(qpti->qregs + MBOX4);
+	in_ptr = NEXT_REQ_PTR(in_ptr);
+	if (in_ptr == out_ptr)
+		goto toss_command;
+
+	if (qpti->send_marker) {
+		marker_frob(cmd);
+		qpti->send_marker = 0;
+		if (NEXT_REQ_PTR(in_ptr) == out_ptr) {
+			sbus_writew(in_ptr, qpti->qregs + MBOX4);
+			qpti->req_in_ptr = in_ptr;
+			goto toss_command;
+		}
+		cmd = (struct Command_Entry *) &qpti->req_cpu[in_ptr];
+		in_ptr = NEXT_REQ_PTR(in_ptr);
+	}
+	cmd_frob(cmd, Cmnd, qpti);
+	if ((in_ptr = load_cmd(Cmnd, cmd, qpti, in_ptr, out_ptr)) == -1)
+		goto toss_command;
+
+	update_can_queue(host, in_ptr, out_ptr);
+
+	return 0;
+
+toss_command:
+	printk(KERN_EMERG "qlogicpti%d: request queue overflow\n",
+	       qpti->qpti_id);
+
+	/* Unfortunately, unless you use the new EH code, which
+	 * we don't, the midlayer will ignore the return value,
+	 * which is insane.  We pick up the pieces like this.
+	 */
+	Cmnd->result = DID_BUS_BUSY;
+	done(Cmnd);
+	return 1;
+}
+
+static int qlogicpti_return_status(struct Status_Entry *sts, int id)
+{
+	int host_status = DID_ERROR;
+
+	switch (sts->completion_status) {
+	      case CS_COMPLETE:
+		host_status = DID_OK;
+		break;
+	      case CS_INCOMPLETE:
+		if (!(sts->state_flags & SF_GOT_BUS))
+			host_status = DID_NO_CONNECT;
+		else if (!(sts->state_flags & SF_GOT_TARGET))
+			host_status = DID_BAD_TARGET;
+		else if (!(sts->state_flags & SF_SENT_CDB))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_TRANSFERRED_DATA))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_STATUS))
+			host_status = DID_ERROR;
+		else if (!(sts->state_flags & SF_GOT_SENSE))
+			host_status = DID_ERROR;
+		break;
+	      case CS_DMA_ERROR:
+	      case CS_TRANSPORT_ERROR:
+		host_status = DID_ERROR;
+		break;
+	      case CS_RESET_OCCURRED:
+	      case CS_BUS_RESET:
+		host_status = DID_RESET;
+		break;
+	      case CS_ABORTED:
+		host_status = DID_ABORT;
+		break;
+	      case CS_TIMEOUT:
+		host_status = DID_TIME_OUT;
+		break;
+	      case CS_DATA_OVERRUN:
+	      case CS_COMMAND_OVERRUN:
+	      case CS_STATUS_OVERRUN:
+	      case CS_BAD_MESSAGE:
+	      case CS_NO_MESSAGE_OUT:
+	      case CS_EXT_ID_FAILED:
+	      case CS_IDE_MSG_FAILED:
+	      case CS_ABORT_MSG_FAILED:
+	      case CS_NOP_MSG_FAILED:
+	      case CS_PARITY_ERROR_MSG_FAILED:
+	      case CS_DEVICE_RESET_MSG_FAILED:
+	      case CS_ID_MSG_FAILED:
+	      case CS_UNEXP_BUS_FREE:
+		host_status = DID_ERROR;
+		break;
+	      case CS_DATA_UNDERRUN:
+		host_status = DID_OK;
+		break;
+	      default:
+		printk(KERN_EMERG "qpti%d: unknown completion status 0x%04x\n",
+		       id, sts->completion_status);
+		host_status = DID_ERROR;
+		break;
+	}
+
+	return (sts->scsi_status & STATUS_MASK) | (host_status << 16);
+}
+
+static struct scsi_cmnd *qlogicpti_intr_handler(struct qlogicpti *qpti)
+{
+	struct scsi_cmnd *Cmnd, *done_queue = NULL;
+	struct Status_Entry *sts;
+	u_int in_ptr, out_ptr;
+
+	if (!(sbus_readw(qpti->qregs + SBUS_STAT) & SBUS_STAT_RINT))
+		return NULL;
+		
+	in_ptr = sbus_readw(qpti->qregs + MBOX5);
+	sbus_writew(HCCTRL_CRIRQ, qpti->qregs + HCCTRL);
+	if (sbus_readw(qpti->qregs + SBUS_SEMAPHORE) & SBUS_SEMAPHORE_LCK) {
+		switch (sbus_readw(qpti->qregs + MBOX0)) {
+		case ASYNC_SCSI_BUS_RESET:
+		case EXECUTION_TIMEOUT_RESET:
+			qpti->send_marker = 1;
+			break;
+		case INVALID_COMMAND:
+		case HOST_INTERFACE_ERROR:
+		case COMMAND_ERROR:
+		case COMMAND_PARAM_ERROR:
+			break;
+		};
+		sbus_writew(0, qpti->qregs + SBUS_SEMAPHORE);
+	}
+
+	/* This looks like a network driver! */
+	out_ptr = qpti->res_out_ptr;
+	while (out_ptr != in_ptr) {
+		u_int cmd_slot;
+
+		sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr];
+		out_ptr = NEXT_RES_PTR(out_ptr);
+
+		/* We store an index in the handle, not the pointer in
+		 * some form.  This avoids problems due to the fact
+		 * that the handle provided is only 32-bits. -DaveM
+		 */
+		cmd_slot = sts->handle;
+		Cmnd = qpti->cmd_slots[cmd_slot];
+		qpti->cmd_slots[cmd_slot] = NULL;
+
+		if (sts->completion_status == CS_RESET_OCCURRED ||
+		    sts->completion_status == CS_ABORTED ||
+		    (sts->status_flags & STF_BUS_RESET))
+			qpti->send_marker = 1;
+
+		if (sts->state_flags & SF_GOT_SENSE)
+			memcpy(Cmnd->sense_buffer, sts->req_sense_data,
+			       sizeof(Cmnd->sense_buffer));
+
+		if (sts->hdr.entry_type == ENTRY_STATUS)
+			Cmnd->result =
+			    qlogicpti_return_status(sts, qpti->qpti_id);
+		else
+			Cmnd->result = DID_ERROR << 16;
+
+		if (Cmnd->use_sg) {
+			sbus_unmap_sg(qpti->sdev,
+				      (struct scatterlist *)Cmnd->buffer,
+				      Cmnd->use_sg,
+				      Cmnd->sc_data_direction);
+		} else {
+			sbus_unmap_single(qpti->sdev,
+					  (__u32)((unsigned long)Cmnd->SCp.ptr),
+					  Cmnd->request_bufflen,
+					  Cmnd->sc_data_direction);
+		}
+		qpti->cmd_count[Cmnd->device->id]--;
+		sbus_writew(out_ptr, qpti->qregs + MBOX5);
+		Cmnd->host_scribble = (unsigned char *) done_queue;
+		done_queue = Cmnd;
+	}
+	qpti->res_out_ptr = out_ptr;
+
+	return done_queue;
+}
+
+static irqreturn_t qpti_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct qlogicpti *qpti = dev_id;
+	unsigned long flags;
+	struct scsi_cmnd *dq;
+
+	spin_lock_irqsave(qpti->qhost->host_lock, flags);
+	dq = qlogicpti_intr_handler(qpti);
+
+	if (dq != NULL) {
+		do {
+			struct scsi_cmnd *next;
+
+			next = (struct scsi_cmnd *) dq->host_scribble;
+			dq->scsi_done(dq);
+			dq = next;
+		} while (dq != NULL);
+	}
+	spin_unlock_irqrestore(qpti->qhost->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static int qlogicpti_abort(struct scsi_cmnd *Cmnd)
+{
+	u_short param[6];
+	struct Scsi_Host *host = Cmnd->device->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	int return_status = SUCCESS;
+	u32 cmd_cookie;
+	int i;
+
+	printk(KERN_WARNING "qlogicpti : Aborting cmd for tgt[%d] lun[%d]\n",
+	       (int)Cmnd->device->id, (int)Cmnd->device->lun);
+
+	qlogicpti_disable_irqs(qpti);
+
+	/* Find the 32-bit cookie we gave to the firmware for
+	 * this command.
+	 */
+	for (i = 0; i < QLOGICPTI_REQ_QUEUE_LEN + 1; i++)
+		if (qpti->cmd_slots[i] == Cmnd)
+			break;
+	cmd_cookie = i;
+
+	param[0] = MBOX_ABORT;
+	param[1] = (((u_short) Cmnd->device->id) << 8) | Cmnd->device->lun;
+	param[2] = cmd_cookie >> 16;
+	param[3] = cmd_cookie & 0xffff;
+	if (qlogicpti_mbox_command(qpti, param, 0) ||
+	    (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]);
+		return_status = FAILED;
+	}
+
+	qlogicpti_enable_irqs(qpti);
+
+	return return_status;
+}
+
+static int qlogicpti_reset(struct scsi_cmnd *Cmnd)
+{
+	u_short param[6];
+	struct Scsi_Host *host = Cmnd->device->host;
+	struct qlogicpti *qpti = (struct qlogicpti *) host->hostdata;
+	int return_status = SUCCESS;
+
+	printk(KERN_WARNING "qlogicpti : Resetting SCSI bus!\n");
+
+	qlogicpti_disable_irqs(qpti);
+
+	param[0] = MBOX_BUS_RESET;
+	param[1] = qpti->host_param.bus_reset_delay;
+	if (qlogicpti_mbox_command(qpti, param, 0) ||
+	   (param[0] != MBOX_COMMAND_COMPLETE)) {
+		printk(KERN_EMERG "qlogicisp : scsi bus reset failure: %x\n", param[0]);
+		return_status = FAILED;
+	}
+
+	qlogicpti_enable_irqs(qpti);
+
+	return return_status;
+}
+
+static struct scsi_host_template driver_template = {
+	.detect			= qlogicpti_detect,
+	.release		= qlogicpti_release,
+	.info			= qlogicpti_info,
+	.queuecommand		= qlogicpti_queuecommand_slow,
+	.eh_abort_handler	= qlogicpti_abort,
+	.eh_bus_reset_handler	= qlogicpti_reset,
+	.can_queue		= QLOGICPTI_REQ_QUEUE_LEN,
+	.this_id		= 7,
+	.sg_tablesize		= QLOGICPTI_MAX_SG(QLOGICPTI_REQ_QUEUE_LEN),
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
new file mode 100644
index 0000000..6cd1c07
--- /dev/null
+++ b/drivers/scsi/qlogicpti.h
@@ -0,0 +1,508 @@
+/* qlogicpti.h: Performance Technologies QlogicISP sbus card defines.
+ *
+ * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu)
+ */
+
+#ifndef _QLOGICPTI_H
+#define _QLOGICPTI_H
+
+/* Qlogic/SBUS controller registers. */
+#define SBUS_CFG1	0x006UL
+#define SBUS_CTRL	0x008UL
+#define SBUS_STAT	0x00aUL
+#define SBUS_SEMAPHORE	0x00cUL
+#define CMD_DMA_CTRL	0x022UL
+#define DATA_DMA_CTRL	0x042UL
+#define MBOX0		0x080UL
+#define MBOX1		0x082UL
+#define MBOX2		0x084UL
+#define MBOX3		0x086UL
+#define MBOX4		0x088UL
+#define MBOX5		0x08aUL
+#define CPU_CMD		0x214UL
+#define CPU_ORIDE	0x224UL
+#define CPU_PCTRL	0x272UL
+#define CPU_PDIFF	0x276UL
+#define RISC_PSR	0x420UL
+#define RISC_MTREG	0x42EUL
+#define HCCTRL		0x440UL
+
+/* SCSI parameters for this driver. */
+#define MAX_TARGETS	16
+#define MAX_LUNS	8
+
+/* With the qlogic interface, every queue slot can hold a SCSI
+ * command with up to 4 scatter/gather entries.  If we need more
+ * than 4 entries, continuation entries can be used that hold
+ * another 7 entries each.  Unlike for other drivers, this means
+ * that the maximum number of scatter/gather entries we can
+ * support at any given time is a function of the number of queue
+ * slots available.  That is, host->can_queue and host->sg_tablesize
+ * are dynamic and _not_ independent.  This all works fine because
+ * requests are queued serially and the scatter/gather limit is
+ * determined for each queue request anew.
+ */
+#define QLOGICPTI_REQ_QUEUE_LEN	255	/* must be power of two - 1 */
+#define QLOGICPTI_MAX_SG(ql)	(4 + ((ql) > 0) ? 7*((ql) - 1) : 0)
+
+/* mailbox command complete status codes */
+#define MBOX_COMMAND_COMPLETE		0x4000
+#define INVALID_COMMAND			0x4001
+#define HOST_INTERFACE_ERROR		0x4002
+#define TEST_FAILED			0x4003
+#define COMMAND_ERROR			0x4005
+#define COMMAND_PARAM_ERROR		0x4006
+
+/* async event status codes */
+#define ASYNC_SCSI_BUS_RESET		0x8001
+#define SYSTEM_ERROR			0x8002
+#define REQUEST_TRANSFER_ERROR		0x8003
+#define RESPONSE_TRANSFER_ERROR		0x8004
+#define REQUEST_QUEUE_WAKEUP		0x8005
+#define EXECUTION_TIMEOUT_RESET		0x8006
+
+/* Am I fucking pedantic or what? */
+struct Entry_header {
+#ifdef __BIG_ENDIAN
+	u8	entry_cnt;
+	u8	entry_type;
+	u8	flags;
+	u8	sys_def_1;
+#else /* __LITTLE_ENDIAN */
+	u8	entry_type;
+	u8	entry_cnt;
+	u8	sys_def_1;
+	u8	flags;
+#endif
+};
+
+/* entry header type commands */
+#define ENTRY_COMMAND		1
+#define ENTRY_CONTINUATION	2
+#define ENTRY_STATUS		3
+#define ENTRY_MARKER		4
+#define ENTRY_EXTENDED_COMMAND	5
+
+/* entry header flag definitions */
+#define EFLAG_CONTINUATION	1
+#define EFLAG_BUSY		2
+#define EFLAG_BAD_HEADER	4
+#define EFLAG_BAD_PAYLOAD	8
+
+struct dataseg {
+	u32	d_base;
+	u32	d_count;
+};
+
+struct Command_Entry {
+	struct Entry_header	hdr;
+	u32			handle;
+#ifdef __BIG_ENDIAN
+	u8			target_id;
+	u8			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u8			target_lun;
+	u8			target_id;
+#endif
+	u16			cdb_length;
+	u16			control_flags;
+	u16			rsvd;
+	u16			time_out;
+	u16			segment_cnt;
+	u8			cdb[12];
+	struct dataseg		dataseg[4];
+};
+
+/* command entry control flag definitions */
+#define CFLAG_NODISC		0x01
+#define CFLAG_HEAD_TAG		0x02
+#define CFLAG_ORDERED_TAG	0x04
+#define CFLAG_SIMPLE_TAG	0x08
+#define CFLAG_TAR_RTN		0x10
+#define CFLAG_READ		0x20
+#define CFLAG_WRITE		0x40
+
+struct Ext_Command_Entry {
+	struct Entry_header	hdr;
+	u32			handle;
+#ifdef __BIG_ENDIAN
+	u8			target_id;
+	u8			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u8			target_lun;
+	u8			target_id;
+#endif
+	u16			cdb_length;
+	u16			control_flags;
+	u16			rsvd;
+	u16			time_out;
+	u16			segment_cnt;
+	u8			cdb[44];
+};
+
+struct Continuation_Entry {
+	struct Entry_header	hdr;
+	u32			reserved;
+	struct dataseg		dataseg[7];
+};
+
+struct Marker_Entry {
+	struct Entry_header	hdr;
+	u32			reserved;
+#ifdef __BIG_ENDIAN
+	u8			target_id;
+	u8			target_lun;
+#else /* __LITTLE_ENDIAN */
+	u8			target_lun;
+	u8			target_id;
+#endif
+#ifdef __BIG_ENDIAN
+	u8			rsvd;
+	u8			modifier;
+#else /* __LITTLE_ENDIAN */
+	u8			modifier;
+	u8			rsvd;
+#endif
+	u8			rsvds[52];
+};
+
+/* marker entry modifier definitions */
+#define SYNC_DEVICE	0
+#define SYNC_TARGET	1
+#define SYNC_ALL	2
+
+struct Status_Entry {
+	struct Entry_header	hdr;
+	u32			handle;
+	u16			scsi_status;
+	u16			completion_status;
+	u16			state_flags;
+	u16			status_flags;
+	u16			time;
+	u16			req_sense_len;
+	u32			residual;
+	u8			rsvd[8];
+	u8			req_sense_data[32];
+};
+
+/* status entry completion status definitions */
+#define CS_COMPLETE			0x0000
+#define CS_INCOMPLETE			0x0001
+#define CS_DMA_ERROR			0x0002
+#define CS_TRANSPORT_ERROR		0x0003
+#define CS_RESET_OCCURRED		0x0004
+#define CS_ABORTED			0x0005
+#define CS_TIMEOUT			0x0006
+#define CS_DATA_OVERRUN			0x0007
+#define CS_COMMAND_OVERRUN		0x0008
+#define CS_STATUS_OVERRUN		0x0009
+#define CS_BAD_MESSAGE			0x000a
+#define CS_NO_MESSAGE_OUT		0x000b
+#define CS_EXT_ID_FAILED		0x000c
+#define CS_IDE_MSG_FAILED		0x000d
+#define CS_ABORT_MSG_FAILED		0x000e
+#define CS_REJECT_MSG_FAILED		0x000f
+#define CS_NOP_MSG_FAILED		0x0010
+#define CS_PARITY_ERROR_MSG_FAILED	0x0011
+#define CS_DEVICE_RESET_MSG_FAILED	0x0012
+#define CS_ID_MSG_FAILED		0x0013
+#define CS_UNEXP_BUS_FREE		0x0014
+#define CS_DATA_UNDERRUN		0x0015
+#define CS_BUS_RESET			0x001c
+
+/* status entry state flag definitions */
+#define SF_GOT_BUS			0x0100
+#define SF_GOT_TARGET			0x0200
+#define SF_SENT_CDB			0x0400
+#define SF_TRANSFERRED_DATA		0x0800
+#define SF_GOT_STATUS			0x1000
+#define SF_GOT_SENSE			0x2000
+
+/* status entry status flag definitions */
+#define STF_DISCONNECT			0x0001
+#define STF_SYNCHRONOUS			0x0002
+#define STF_PARITY_ERROR		0x0004
+#define STF_BUS_RESET			0x0008
+#define STF_DEVICE_RESET		0x0010
+#define STF_ABORTED			0x0020
+#define STF_TIMEOUT			0x0040
+#define STF_NEGOTIATION			0x0080
+
+/* mailbox commands */
+#define MBOX_NO_OP			0x0000
+#define MBOX_LOAD_RAM			0x0001
+#define MBOX_EXEC_FIRMWARE		0x0002
+#define MBOX_DUMP_RAM			0x0003
+#define MBOX_WRITE_RAM_WORD		0x0004
+#define MBOX_READ_RAM_WORD		0x0005
+#define MBOX_MAILBOX_REG_TEST		0x0006
+#define MBOX_VERIFY_CHECKSUM		0x0007
+#define MBOX_ABOUT_FIRMWARE		0x0008
+#define MBOX_CHECK_FIRMWARE		0x000e
+#define MBOX_INIT_REQ_QUEUE		0x0010
+#define MBOX_INIT_RES_QUEUE		0x0011
+#define MBOX_EXECUTE_IOCB		0x0012
+#define MBOX_WAKE_UP			0x0013
+#define MBOX_STOP_FIRMWARE		0x0014
+#define MBOX_ABORT			0x0015
+#define MBOX_ABORT_DEVICE		0x0016
+#define MBOX_ABORT_TARGET		0x0017
+#define MBOX_BUS_RESET			0x0018
+#define MBOX_STOP_QUEUE			0x0019
+#define MBOX_START_QUEUE		0x001a
+#define MBOX_SINGLE_STEP_QUEUE		0x001b
+#define MBOX_ABORT_QUEUE		0x001c
+#define MBOX_GET_DEV_QUEUE_STATUS	0x001d
+#define MBOX_GET_FIRMWARE_STATUS	0x001f
+#define MBOX_GET_INIT_SCSI_ID		0x0020
+#define MBOX_GET_SELECT_TIMEOUT		0x0021
+#define MBOX_GET_RETRY_COUNT		0x0022
+#define MBOX_GET_TAG_AGE_LIMIT		0x0023
+#define MBOX_GET_CLOCK_RATE		0x0024
+#define MBOX_GET_ACT_NEG_STATE		0x0025
+#define MBOX_GET_ASYNC_DATA_SETUP_TIME	0x0026
+#define MBOX_GET_SBUS_PARAMS		0x0027
+#define MBOX_GET_TARGET_PARAMS		0x0028
+#define MBOX_GET_DEV_QUEUE_PARAMS	0x0029
+#define MBOX_SET_INIT_SCSI_ID		0x0030
+#define MBOX_SET_SELECT_TIMEOUT		0x0031
+#define MBOX_SET_RETRY_COUNT		0x0032
+#define MBOX_SET_TAG_AGE_LIMIT		0x0033
+#define MBOX_SET_CLOCK_RATE		0x0034
+#define MBOX_SET_ACTIVE_NEG_STATE	0x0035
+#define MBOX_SET_ASYNC_DATA_SETUP_TIME	0x0036
+#define MBOX_SET_SBUS_CONTROL_PARAMS	0x0037
+#define MBOX_SET_TARGET_PARAMS		0x0038
+#define MBOX_SET_DEV_QUEUE_PARAMS	0x0039
+
+struct host_param {
+	u_short		initiator_scsi_id;
+	u_short		bus_reset_delay;
+	u_short		retry_count;
+	u_short		retry_delay;
+	u_short		async_data_setup_time;
+	u_short		req_ack_active_negation;
+	u_short		data_line_active_negation;
+	u_short		data_dma_burst_enable;
+	u_short		command_dma_burst_enable;
+	u_short		tag_aging;
+	u_short		selection_timeout;
+	u_short		max_queue_depth;
+};
+
+/*
+ * Device Flags:
+ *
+ * Bit  Name
+ * ---------
+ *  7   Disconnect Privilege
+ *  6   Parity Checking
+ *  5   Wide Data Transfers
+ *  4   Synchronous Data Transfers
+ *  3   Tagged Queuing
+ *  2   Automatic Request Sense
+ *  1   Stop Queue on Check Condition
+ *  0   Renegotiate on Error
+ */
+
+struct dev_param {
+	u_short		device_flags;
+	u_short		execution_throttle;
+	u_short		synchronous_period;
+	u_short		synchronous_offset;
+	u_short		device_enable;
+	u_short		reserved; /* pad */
+};
+
+/*
+ * The result queue can be quite a bit smaller since continuation entries
+ * do not show up there:
+ */
+#define RES_QUEUE_LEN		255	/* Must be power of two - 1 */
+#define QUEUE_ENTRY_LEN		64
+
+#define NEXT_REQ_PTR(wheee)   (((wheee) + 1) & QLOGICPTI_REQ_QUEUE_LEN)
+#define NEXT_RES_PTR(wheee)   (((wheee) + 1) & RES_QUEUE_LEN)
+#define PREV_REQ_PTR(wheee)   (((wheee) - 1) & QLOGICPTI_REQ_QUEUE_LEN)
+#define PREV_RES_PTR(wheee)   (((wheee) - 1) & RES_QUEUE_LEN)
+
+struct pti_queue_entry {
+	char __opaque[QUEUE_ENTRY_LEN];
+};
+
+struct scsi_cmnd;
+
+/* Software state for the driver. */
+struct qlogicpti {
+	/* These are the hot elements in the cache, so they come first. */
+	void __iomem             *qregs;                /* Adapter registers          */
+	struct pti_queue_entry   *res_cpu;              /* Ptr to RESPONSE bufs (CPU) */
+	struct pti_queue_entry   *req_cpu;              /* Ptr to REQUEST bufs (CPU)  */
+
+	u_int	                  req_in_ptr;		/* index of next request slot */
+	u_int	                  res_out_ptr;		/* index of next result slot  */
+	long	                  send_marker;		/* must we send a marker?     */
+	struct sbus_dev		 *sdev;
+	unsigned long		  __pad;
+
+	int                       cmd_count[MAX_TARGETS];
+	unsigned long             tag_ages[MAX_TARGETS];
+
+	/* The cmd->handler is only 32-bits, so that things work even on monster
+	 * Ex000 sparc64 machines with >4GB of ram we just keep track of the
+	 * scsi command pointers here.  This is essentially what Matt Jacob does. -DaveM
+	 */
+	struct scsi_cmnd         *cmd_slots[QLOGICPTI_REQ_QUEUE_LEN + 1];
+
+	/* The rest of the elements are unimportant for performance. */
+	struct qlogicpti         *next;
+	__u32                     res_dvma;             /* Ptr to RESPONSE bufs (DVMA)*/
+	__u32                     req_dvma;             /* Ptr to REQUEST bufs (DVMA) */
+	u_char	                  fware_majrev, fware_minrev, fware_micrev;
+	struct Scsi_Host         *qhost;
+	int                       qpti_id;
+	int                       scsi_id;
+	int                       prom_node;
+	char                      prom_name[64];
+	int                       irq;
+	char                      differential, ultra, clock;
+	unsigned char             bursts;
+	struct	host_param        host_param;
+	struct	dev_param         dev_param[MAX_TARGETS];
+
+	void __iomem              *sreg;
+#define SREG_TPOWER               0x80   /* State of termpwr           */
+#define SREG_FUSE                 0x40   /* State of on board fuse     */
+#define SREG_PDISAB               0x20   /* Disable state for power on */
+#define SREG_DSENSE               0x10   /* Sense for differential     */
+#define SREG_IMASK                0x0c   /* Interrupt level            */
+#define SREG_SPMASK               0x03   /* Mask for switch pack       */
+	unsigned char             swsreg;
+	unsigned int	
+		gotirq	:	1,	/* this instance got an irq */
+		is_pti	: 	1,	/* Non-zero if this is a PTI board. */
+		sbits	:	16;	/* syncmode known bits */
+};
+
+/* How to twiddle them bits... */
+
+/* SBUS config register one. */
+#define SBUS_CFG1_EPAR          0x0100      /* Enable parity checking           */
+#define SBUS_CFG1_FMASK         0x00f0      /* Forth code cycle mask            */
+#define SBUS_CFG1_BENAB         0x0004      /* Burst dvma enable                */
+#define SBUS_CFG1_B64           0x0003      /* Enable 64byte bursts             */
+#define SBUS_CFG1_B32           0x0002      /* Enable 32byte bursts             */
+#define SBUS_CFG1_B16           0x0001      /* Enable 16byte bursts             */
+#define SBUS_CFG1_B8            0x0008      /* Enable 8byte bursts              */
+
+/* SBUS control register */
+#define SBUS_CTRL_EDIRQ         0x0020      /* Enable Data DVMA Interrupts      */
+#define SBUS_CTRL_ECIRQ         0x0010      /* Enable Command DVMA Interrupts   */
+#define SBUS_CTRL_ESIRQ         0x0008      /* Enable SCSI Processor Interrupts */
+#define SBUS_CTRL_ERIRQ         0x0004      /* Enable RISC Processor Interrupts */
+#define SBUS_CTRL_GENAB         0x0002      /* Global Interrupt Enable          */
+#define SBUS_CTRL_RESET         0x0001      /* Soft Reset                       */
+
+/* SBUS status register */
+#define SBUS_STAT_DINT          0x0020      /* Data DVMA IRQ pending            */
+#define SBUS_STAT_CINT          0x0010      /* Command DVMA IRQ pending         */
+#define SBUS_STAT_SINT          0x0008      /* SCSI Processor IRQ pending       */
+#define SBUS_STAT_RINT          0x0004      /* RISC Processor IRQ pending       */
+#define SBUS_STAT_GINT          0x0002      /* Global IRQ pending               */
+
+/* SBUS semaphore register */
+#define SBUS_SEMAPHORE_STAT     0x0002      /* Semaphore status bit             */
+#define SBUS_SEMAPHORE_LCK      0x0001      /* Semaphore lock bit               */
+
+/* DVMA control register */
+#define DMA_CTRL_CSUSPEND       0x0010      /* DMA channel suspend              */
+#define DMA_CTRL_CCLEAR         0x0008      /* DMA channel clear and reset      */
+#define DMA_CTRL_FCLEAR         0x0004      /* DMA fifo clear                   */
+#define DMA_CTRL_CIRQ           0x0002      /* DMA irq clear                    */
+#define DMA_CTRL_DMASTART       0x0001      /* DMA transfer start               */
+
+/* SCSI processor override register */
+#define CPU_ORIDE_ETRIG         0x8000      /* External trigger enable          */
+#define CPU_ORIDE_STEP          0x4000      /* Single step mode enable          */
+#define CPU_ORIDE_BKPT          0x2000      /* Breakpoint reg enable            */
+#define CPU_ORIDE_PWRITE        0x1000      /* SCSI pin write enable            */
+#define CPU_ORIDE_OFORCE        0x0800      /* Force outputs on                 */
+#define CPU_ORIDE_LBACK         0x0400      /* SCSI loopback enable             */
+#define CPU_ORIDE_PTEST         0x0200      /* Parity test enable               */
+#define CPU_ORIDE_TENAB         0x0100      /* SCSI pins tristate enable        */
+#define CPU_ORIDE_TPINS         0x0080      /* SCSI pins enable                 */
+#define CPU_ORIDE_FRESET        0x0008      /* FIFO reset                       */
+#define CPU_ORIDE_CTERM         0x0004      /* Command terminate                */
+#define CPU_ORIDE_RREG          0x0002      /* Reset SCSI processor regs        */
+#define CPU_ORIDE_RMOD          0x0001      /* Reset SCSI processor module      */
+
+/* SCSI processor commands */
+#define CPU_CMD_BRESET          0x300b      /* Reset SCSI bus                   */
+
+/* SCSI processor pin control register */
+#define CPU_PCTRL_PVALID        0x8000      /* Phase bits are valid             */
+#define CPU_PCTRL_PHI           0x0400      /* Parity bit high                  */
+#define CPU_PCTRL_PLO           0x0200      /* Parity bit low                   */
+#define CPU_PCTRL_REQ           0x0100      /* REQ bus signal                   */
+#define CPU_PCTRL_ACK           0x0080      /* ACK bus signal                   */
+#define CPU_PCTRL_RST           0x0040      /* RST bus signal                   */
+#define CPU_PCTRL_BSY           0x0020      /* BSY bus signal                   */
+#define CPU_PCTRL_SEL           0x0010      /* SEL bus signal                   */
+#define CPU_PCTRL_ATN           0x0008      /* ATN bus signal                   */
+#define CPU_PCTRL_MSG           0x0004      /* MSG bus signal                   */
+#define CPU_PCTRL_CD            0x0002      /* CD bus signal                    */
+#define CPU_PCTRL_IO            0x0001      /* IO bus signal                    */
+
+/* SCSI processor differential pins register */
+#define CPU_PDIFF_SENSE         0x0200      /* Differential sense               */
+#define CPU_PDIFF_MODE          0x0100      /* Differential mode                */
+#define CPU_PDIFF_OENAB         0x0080      /* Outputs enable                   */
+#define CPU_PDIFF_PMASK         0x007c      /* Differential control pins        */
+#define CPU_PDIFF_TGT           0x0002      /* Target mode enable               */
+#define CPU_PDIFF_INIT          0x0001      /* Initiator mode enable            */
+
+/* RISC processor status register */
+#define RISC_PSR_FTRUE          0x8000      /* Force true                       */
+#define RISC_PSR_LCD            0x4000      /* Loop counter shows done status   */
+#define RISC_PSR_RIRQ           0x2000      /* RISC irq status                  */
+#define RISC_PSR_TOFLOW         0x1000      /* Timer overflow (rollover)        */
+#define RISC_PSR_AOFLOW         0x0800      /* Arithmetic overflow              */
+#define RISC_PSR_AMSB           0x0400      /* Arithmetic big endian            */
+#define RISC_PSR_ACARRY         0x0200      /* Arithmetic carry                 */
+#define RISC_PSR_AZERO          0x0100      /* Arithmetic zero                  */
+#define RISC_PSR_ULTRA          0x0020      /* Ultra mode                       */
+#define RISC_PSR_DIRQ           0x0010      /* DVMA interrupt                   */
+#define RISC_PSR_SIRQ           0x0008      /* SCSI processor interrupt         */
+#define RISC_PSR_HIRQ           0x0004      /* Host interrupt                   */
+#define RISC_PSR_IPEND          0x0002      /* Interrupt pending                */
+#define RISC_PSR_FFALSE         0x0001      /* Force false                      */
+
+/* RISC processor memory timing register */
+#define RISC_MTREG_P1DFLT       0x1200      /* Default read/write timing, pg1   */
+#define RISC_MTREG_P0DFLT       0x0012      /* Default read/write timing, pg0   */
+#define RISC_MTREG_P1ULTRA      0x2300      /* Ultra-mode rw timing, pg1        */
+#define RISC_MTREG_P0ULTRA      0x0023      /* Ultra-mode rw timing, pg0        */
+
+/* Host command/ctrl register */
+#define HCCTRL_NOP              0x0000      /* CMD: No operation                */
+#define HCCTRL_RESET            0x1000      /* CMD: Reset RISC cpu              */
+#define HCCTRL_PAUSE            0x2000      /* CMD: Pause RISC cpu              */
+#define HCCTRL_REL              0x3000      /* CMD: Release paused RISC cpu     */
+#define HCCTRL_STEP             0x4000      /* CMD: Single step RISC cpu        */
+#define HCCTRL_SHIRQ            0x5000      /* CMD: Set host irq                */
+#define HCCTRL_CHIRQ            0x6000      /* CMD: Clear host irq              */
+#define HCCTRL_CRIRQ            0x7000      /* CMD: Clear RISC cpu irq          */
+#define HCCTRL_BKPT             0x8000      /* CMD: Breakpoint enables change   */
+#define HCCTRL_TMODE            0xf000      /* CMD: Enable test mode            */
+#define HCCTRL_HIRQ             0x0080      /* Host IRQ pending                 */
+#define HCCTRL_RRIP             0x0040      /* RISC cpu reset in happening now  */
+#define HCCTRL_RPAUSED          0x0020      /* RISC cpu is paused now           */
+#define HCCTRL_EBENAB           0x0010      /* External breakpoint enable       */
+#define HCCTRL_B1ENAB           0x0008      /* Breakpoint 1 enable              */
+#define HCCTRL_B0ENAB           0x0004      /* Breakpoint 0 enable              */
+
+/* For our interrupt engine. */
+#define for_each_qlogicpti(qp) \
+        for((qp) = qptichain; (qp); (qp) = (qp)->next)
+
+#endif /* !(_QLOGICPTI_H) */
diff --git a/drivers/scsi/qlogicpti_asm.c b/drivers/scsi/qlogicpti_asm.c
new file mode 100644
index 0000000..1545b30
--- /dev/null
+++ b/drivers/scsi/qlogicpti_asm.c
@@ -0,0 +1,1160 @@
+/* Version 1.31.00 ISP1000 Initiator RISC firmware */
+unsigned short sbus_risc_code01[] __initdata = {
+	0x0078, 0x1030, 0x0000, 0x2419, 0x0000, 0x12ff, 0x2043, 0x4f50,
+	0x5952, 0x4947, 0x4854, 0x2031, 0x3939, 0x312c, 0x3139, 0x3932,
+	0x2c31, 0x3939, 0x332c, 0x3139, 0x3934, 0x2051, 0x4c4f, 0x4749,
+	0x4320, 0x434f, 0x5250, 0x4f52, 0x4154, 0x494f, 0x4e00, 0x2049,
+	0x5350, 0x3130, 0x3030, 0x2046, 0x6972, 0x6d77, 0x6172, 0x6520,
+	0x2056, 0x6572, 0x7369, 0x6f6e, 0x2030, 0x312e, 0x3331, 0x2020,
+	0x20b9, 0x1212, 0x20c1, 0x0008, 0x2071, 0x0010, 0x70c3, 0x0004,
+	0x20c9, 0x3fff, 0x2089, 0x10c8, 0x70c7, 0x4953, 0x70cb, 0x5020,
+	0x70cf, 0x2020, 0x70d3, 0x0001, 0x3f00, 0x70d6, 0x2031, 0x0030,
+	0x2079, 0x3500, 0x7863, 0x0000, 0x2fa0, 0x2009, 0x0327, 0x2011,
+	0x0000, 0x20a9, 0x0040, 0x42a4, 0x8109, 0x00c0, 0x1051, 0x789b,
+	0x0101, 0x780b, 0x0002, 0x780f, 0x0002, 0x784f, 0x0bb8, 0x2069,
+	0x3540, 0x00a8, 0x106a, 0x681b, 0x003c, 0x2009, 0x1313, 0x21b8,
+	0x0078, 0x106c, 0x681b, 0x0028, 0x6807, 0x0007, 0x680b, 0x00fa,
+	0x680f, 0x0008, 0x6813, 0x0005, 0x681f, 0x0000, 0x6823, 0x0006,
+	0x6817, 0x0008, 0x6827, 0x0000, 0x2069, 0x3600, 0x2011, 0x0020,
+	0x2009, 0x0010, 0x680b, 0x0c19, 0x680f, 0x0019, 0x6803, 0xdd00,
+	0x6807, 0x001a, 0x6a1a, 0x2d00, 0xa0e8, 0x0008, 0xa290, 0x0004,
+	0x8109, 0x00c0, 0x1082, 0x2069, 0x3680, 0x20a9, 0x0080, 0x6837,
+	0x0000, 0x680b, 0x0040, 0x6817, 0x0100, 0x681f, 0x0064, 0xade8,
+	0x0010, 0x0070, 0x10a5, 0x0078, 0x1097, 0x1078, 0x1a38, 0x1078,
+	0x2f3a, 0x1078, 0x1681, 0x1078, 0x33ba, 0x3200, 0xa085, 0x000d,
+	0x2090, 0x70c3, 0x0000, 0x0090, 0x10bc, 0x70c0, 0xa086, 0x0002,
+	0x00c0, 0x10bc, 0x1078, 0x11ba, 0x1078, 0x10ec, 0x1078, 0x1817,
+	0x1078, 0x19a8, 0x1078, 0x327d, 0x1078, 0x177d, 0x0078, 0x10bc,
+	0x10d0, 0x10d2, 0x1bc3, 0x1bc3, 0x2f98, 0x2f98, 0x1bc3, 0x1bc3,
+	0x0078, 0x10d0, 0x0078, 0x10d2, 0x0078, 0x10d4, 0x0078, 0x10d6,
+	0x7008, 0x800c, 0x00c8, 0x10e7, 0x7007, 0x0002, 0xa08c, 0x000c,
+	0x00c0, 0x10e8, 0x8004, 0x8004, 0x00c8, 0x10e7, 0x087a, 0x097a,
+	0x70c3, 0x4002, 0x0078, 0x11bd, 0x7814, 0xa005, 0x00c0, 0x10f4,
+	0x0010, 0x1130, 0x0078, 0x112f, 0x2009, 0x3568, 0x2104, 0xa005,
+	0x00c0, 0x112f, 0x7814, 0xa086, 0x0001, 0x00c0, 0x1101, 0x1078,
+	0x1536, 0x7817, 0x0000, 0x2009, 0x356f, 0x2104, 0xa065, 0x0040,
+	0x111d, 0x2009, 0x356a, 0x211c, 0x8108, 0x2114, 0x8108, 0x2104,
+	0xa210, 0xa399, 0x0000, 0x2009, 0x001c, 0x6083, 0x0103, 0x1078,
+	0x1611, 0x00c0, 0x1129, 0x1078, 0x1678, 0x2009, 0x356f, 0x200b,
+	0x0000, 0x2009, 0x3569, 0x2104, 0x200b, 0x0000, 0xa005, 0x0040,
+	0x112d, 0x2001, 0x4005, 0x0078, 0x11bc, 0x0078, 0x11ba, 0x007c,
+	0x2061, 0x0000, 0x6018, 0xa084, 0x0001, 0x0040, 0x1138, 0x007c,
+	0x70c3, 0x0000, 0x70c7, 0x0000, 0x70cb, 0x0000, 0x70cf, 0x0000,
+	0x70c0, 0xa0bc, 0xffc0, 0x00c0, 0x1188, 0x2038, 0x0079, 0x1148,
+	0x11ba, 0x1205, 0x11d3, 0x1205, 0x1256, 0x1256, 0x11ca, 0x1590,
+	0x1261, 0x11c6, 0x11d7, 0x11d9, 0x11db, 0x11dd, 0x1595, 0x11c6,
+	0x1267, 0x1283, 0x1544, 0x158a, 0x11df, 0x146b, 0x148d, 0x14a7,
+	0x14d0, 0x1424, 0x1432, 0x1446, 0x145a, 0x12ef, 0x11c6, 0x129f,
+	0x12a6, 0x12ab, 0x12b0, 0x12b6, 0x12bb, 0x12c0, 0x12c5, 0x12ca,
+	0x12ce, 0x12e3, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x12fb,
+	0x1304, 0x1313, 0x1339, 0x1343, 0x134a, 0x1370, 0x137f, 0x138e,
+	0x13a0, 0x1409, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x1419,
+	0xa0bc, 0xffa0, 0x00c0, 0x11c6, 0x2038, 0xa084, 0x001f, 0x0079,
+	0x1191, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6,
+	0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6,
+	0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6, 0x11c6,
+	0x11c6, 0x11c6, 0x11c6, 0x15ed, 0x15f7, 0x15fb, 0x1609, 0x11c6,
+	0x11c6, 0x72ca, 0x71c6, 0x2001, 0x4006, 0x0078, 0x11bc, 0x73ce,
+	0x72ca, 0x71c6, 0x2001, 0x4000, 0x70c2, 0x2061, 0x0000, 0x601b,
+	0x0001, 0x2091, 0x5000, 0x2091, 0x4080, 0x007c, 0x70c3, 0x4001,
+	0x0078, 0x11bd, 0x2099, 0x0041, 0x20a1, 0x0041, 0x20a9, 0x0005,
+	0x53a3, 0x0078, 0x11ba, 0x70c4, 0x70c3, 0x0004, 0x007a, 0x0078,
+	0x11ba, 0x0078, 0x11ba, 0x0078, 0x11ba, 0x0078, 0x11ba, 0x2091,
+	0x8000, 0x70c3, 0x0000, 0x70c7, 0x4953, 0x70cb, 0x5020, 0x70cf,
+	0x2020, 0x70d3, 0x0001, 0x3f00, 0x70d6, 0x2079, 0x0000, 0x781b,
+	0x0001, 0x2031, 0x0030, 0x2059, 0x1000, 0x2029, 0x0457, 0x2051,
+	0x0470, 0x2061, 0x0472, 0x20b9, 0xffff, 0x20c1, 0x0000, 0x2091,
+	0x5000, 0x2091, 0x4080, 0x0078, 0x0455, 0x71d0, 0x72c8, 0x73cc,
+	0x70c4, 0x20a0, 0x2098, 0x2031, 0x0030, 0x81ff, 0x0040, 0x11ba,
+	0x7007, 0x0004, 0x731a, 0x721e, 0x2051, 0x0012, 0x2049, 0x1234,
+	0x2041, 0x11ba, 0x7003, 0x0002, 0xa786, 0x0001, 0x00c0, 0x1226,
+	0x2049, 0x1242, 0x2041, 0x124e, 0x7003, 0x0003, 0x7017, 0x0000,
+	0x810b, 0x7112, 0x00c8, 0x122e, 0x7017, 0x0001, 0x7007, 0x0001,
+	0xa786, 0x0001, 0x0040, 0x1242, 0x700c, 0xa084, 0x007f, 0x8004,
+	0x2009, 0x0020, 0xa102, 0x0942, 0x094a, 0x20a8, 0x26a0, 0x53a6,
+	0x0078, 0x10d8, 0x700c, 0xa084, 0x007f, 0x0040, 0x1242, 0x80ac,
+	0x0048, 0x1242, 0x2698, 0x53a5, 0x0078, 0x10d8, 0x700c, 0xa084,
+	0x007f, 0x80ac, 0x2698, 0x53a5, 0x0078, 0x11ba, 0x71c4, 0x70c8,
+	0x2114, 0xa79e, 0x0004, 0x00c0, 0x125e, 0x200a, 0x72ca, 0x0078,
+	0x11b9, 0x70c7, 0x0001, 0x70cb, 0x001f, 0x0078, 0x11ba, 0x70c4,
+	0x72c8, 0x73cc, 0x74d0, 0x70c6, 0x72ca, 0x73ce, 0x74d2, 0xa005,
+	0x0040, 0x127d, 0x8001, 0x7872, 0x7a7a, 0x7b7e, 0x7c76, 0x7898,
+	0xa084, 0xfffc, 0x789a, 0x0078, 0x1281, 0x7898, 0xa085, 0x0001,
+	0x789a, 0x0078, 0x11ba, 0x70c4, 0x72c8, 0x73cc, 0x74d4, 0x70c6,
+	0x72ca, 0x73ce, 0x74d6, 0xa005, 0x0040, 0x1299, 0x8001, 0x7886,
+	0x7a8e, 0x7b92, 0x7c8a, 0x7898, 0xa084, 0xfcff, 0x789a, 0x0078,
+	0x129d, 0x7898, 0xa085, 0x0100, 0x789a, 0x0078, 0x11ba, 0x2009,
+	0x3559, 0x210c, 0x2011, 0x0410, 0x0078, 0x11b8, 0x2009, 0x3541,
+	0x210c, 0x0078, 0x11b9, 0x2009, 0x3542, 0x210c, 0x0078, 0x11b9,
+	0x2061, 0x3540, 0x610c, 0x6210, 0x0078, 0x11b8, 0x2009, 0x3545,
+	0x210c, 0x0078, 0x11b9, 0x2009, 0x3546, 0x210c, 0x0078, 0x11b9,
+	0x2009, 0x3547, 0x210c, 0x0078, 0x11b9, 0x2009, 0x3548, 0x210c,
+	0x0078, 0x11b9, 0x7908, 0x7a0c, 0x0078, 0x11b8, 0x71c4, 0x8107,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8, 0x3600, 0x6a00,
+	0x6804, 0xa084, 0x0008, 0x0040, 0x12e0, 0x6b08, 0x0078, 0x12e1,
+	0x6b0c, 0x0078, 0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000,
+	0x6b1c, 0x6a14, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b7, 0x77c4,
+	0x1078, 0x1692, 0x2091, 0x8000, 0x6908, 0x6a18, 0x6b10, 0x2091,
+	0x8001, 0x0078, 0x11b7, 0x71c4, 0xa182, 0x0010, 0x00c8, 0x11b2,
+	0x1078, 0x1abc, 0x0078, 0x11b7, 0x71c4, 0xa182, 0x0010, 0x00c8,
+	0x11b2, 0x2011, 0x3541, 0x2204, 0x007e, 0x2112, 0x1078, 0x1a75,
+	0x017f, 0x0078, 0x11b9, 0x71c4, 0x2011, 0x1331, 0x20a9, 0x0008,
+	0x2204, 0xa106, 0x0040, 0x1323, 0x8210, 0x0070, 0x1321, 0x0078,
+	0x1318, 0x0078, 0x11b2, 0xa292, 0x1331, 0x027e, 0x2011, 0x3542,
+	0x2204, 0x2112, 0x017f, 0x007e, 0x1078, 0x1a81, 0x017f, 0x0078,
+	0x11b9, 0x03e8, 0x00fa, 0x01f4, 0x02ee, 0x0064, 0x0019, 0x0032,
+	0x004b, 0x2061, 0x3540, 0x610c, 0x6210, 0x70c4, 0x600e, 0x70c8,
+	0x6012, 0x0078, 0x11b8, 0x2061, 0x3540, 0x6114, 0x70c4, 0x6016,
+	0x0078, 0x11b9, 0x71c4, 0x2011, 0x0004, 0x2019, 0x1212, 0xa186,
+	0x0028, 0x0040, 0x1363, 0x2011, 0x0005, 0x2019, 0x1212, 0xa186,
+	0x0032, 0x0040, 0x1363, 0x2011, 0x0006, 0x2019, 0x1313, 0xa186,
+	0x003c, 0x00c0, 0x11b2, 0x2061, 0x3540, 0x6018, 0x007e, 0x611a,
+	0x23b8, 0x1078, 0x1a92, 0x1078, 0x33ba, 0x017f, 0x0078, 0x11b9,
+	0x71c4, 0xa184, 0xffcf, 0x00c0, 0x11b2, 0x2011, 0x3547, 0x2204,
+	0x2112, 0x007e, 0x1078, 0x1ab4, 0x017f, 0x0078, 0x11b9, 0x71c4,
+	0xa182, 0x0010, 0x00c8, 0x11b2, 0x2011, 0x3548, 0x2204, 0x007e,
+	0x2112, 0x1078, 0x1aa3, 0x017f, 0x0078, 0x11b9, 0x71c4, 0x72c8,
+	0xa184, 0xfffd, 0x00c0, 0x11b1, 0xa284, 0xfffd, 0x00c0, 0x11b1,
+	0x2100, 0x7908, 0x780a, 0x2200, 0x7a0c, 0x780e, 0x0078, 0x11b8,
+	0x71c4, 0x8107, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa0e8,
+	0x3600, 0x2019, 0x0000, 0x72c8, 0x6800, 0x007e, 0xa226, 0x0040,
+	0x13cf, 0x6a02, 0xa484, 0x2000, 0x0040, 0x13b8, 0xa39d, 0x0010,
+	0xa484, 0x1000, 0x0040, 0x13be, 0xa39d, 0x0008, 0xa484, 0x4000,
+	0x0040, 0x13cf, 0x810f, 0xa284, 0x4000, 0x0040, 0x13cb, 0x1078,
+	0x1ad6, 0x0078, 0x13cf, 0x1078, 0x1ac8, 0x0078, 0x13cf, 0x72cc,
+	0x82ff, 0x0040, 0x1401, 0x6808, 0xa206, 0x0040, 0x1401, 0xa2a4,
+	0x00ff, 0x2061, 0x3540, 0x6118, 0xa186, 0x0028, 0x0040, 0x13e8,
+	0xa186, 0x0032, 0x0040, 0x13ee, 0xa186, 0x003c, 0x0040, 0x13f4,
+	0xa482, 0x0064, 0x0048, 0x13fe, 0x0078, 0x13f8, 0xa482, 0x0050,
+	0x0048, 0x13fe, 0x0078, 0x13f8, 0xa482, 0x0043, 0x0048, 0x13fe,
+	0x71c4, 0x71c6, 0x027f, 0x72ca, 0x0078, 0x11b3, 0x6a0a, 0xa39d,
+	0x000a, 0x6804, 0xa305, 0x6806, 0x027f, 0x6b0c, 0x71c4, 0x0078,
+	0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000, 0x6a14, 0x6b1c,
+	0x2091, 0x8001, 0x70c8, 0x6816, 0x70cc, 0x681e, 0x2708, 0x0078,
+	0x11b7, 0x71c4, 0x72c8, 0x73cc, 0xa182, 0x0010, 0x00c8, 0x11b2,
+	0x1078, 0x1ae4, 0x0078, 0x11b7, 0x77c4, 0x1078, 0x1692, 0x2091,
+	0x8000, 0x6a08, 0xa295, 0x0002, 0x6a0a, 0x2091, 0x8001, 0x2708,
+	0x0078, 0x11b8, 0x77c4, 0x1078, 0x1692, 0x2091, 0x8000, 0x6a08,
+	0xa294, 0xfff9, 0x6a0a, 0x6804, 0xa005, 0x0040, 0x1441, 0x1078,
+	0x1a19, 0x2091, 0x8001, 0x2708, 0x0078, 0x11b8, 0x77c4, 0x1078,
+	0x1692, 0x2091, 0x8000, 0x6a08, 0xa295, 0x0004, 0x6a0a, 0x6804,
+	0xa005, 0x0040, 0x1455, 0x1078, 0x1a19, 0x2091, 0x8001, 0x2708,
+	0x0078, 0x11b8, 0x77c4, 0x2041, 0x0001, 0x2049, 0x0005, 0x2051,
+	0x0020, 0x2091, 0x8000, 0x1078, 0x169f, 0x2091, 0x8001, 0x2708,
+	0x6a08, 0x0078, 0x11b8, 0x77c4, 0x72c8, 0x73cc, 0x77c6, 0x72ca,
+	0x73ce, 0x1078, 0x1718, 0x00c0, 0x1489, 0x6818, 0xa005, 0x0040,
+	0x1483, 0x2708, 0x1078, 0x1af4, 0x00c0, 0x1483, 0x7817, 0xffff,
+	0x2091, 0x8001, 0x007c, 0x2091, 0x8001, 0x2001, 0x4005, 0x0078,
+	0x11bc, 0x2091, 0x8001, 0x0078, 0x11ba, 0x77c4, 0x77c6, 0x2041,
+	0x0021, 0x2049, 0x0005, 0x2051, 0x0020, 0x2091, 0x8000, 0x1078,
+	0x169f, 0x2061, 0x3540, 0x60a3, 0x0003, 0x67b6, 0x60a7, 0x0000,
+	0x7817, 0xffff, 0x2091, 0x8001, 0x1078, 0x1a19, 0x007c, 0x77c8,
+	0x77ca, 0x77c4, 0x77c6, 0xa7bc, 0xff00, 0x2091, 0x8000, 0x2061,
+	0x3540, 0x60a3, 0x0002, 0x60a7, 0x0000, 0x67b6, 0x7817, 0xffff,
+	0x1078, 0x1a19, 0x2091, 0x8001, 0x2041, 0x0021, 0x2049, 0x0004,
+	0x2051, 0x0010, 0x2091, 0x8000, 0x1078, 0x169f, 0x70c8, 0x6836,
+	0x8738, 0xa784, 0x0007, 0x00c0, 0x14c4, 0x2091, 0x8001, 0x007c,
+	0x7898, 0xa084, 0x0003, 0x00c0, 0x14f4, 0x2039, 0x0000, 0x2041,
+	0x0021, 0x2049, 0x0004, 0x2051, 0x0008, 0x1078, 0x1692, 0x2091,
+	0x8000, 0x6808, 0xa80d, 0x690a, 0x2091, 0x8001, 0x8738, 0xa784,
+	0x0007, 0x00c0, 0x14dd, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f,
+	0xa784, 0x0f00, 0x00c0, 0x14dd, 0x2091, 0x8000, 0x2069, 0x0100,
+	0x6830, 0xa084, 0x0040, 0x0040, 0x151d, 0x684b, 0x0004, 0x20a9,
+	0x0014, 0x6848, 0xa084, 0x0004, 0x0040, 0x150a, 0x0070, 0x150a,
+	0x0078, 0x1501, 0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084,
+	0x0001, 0x0040, 0x1517, 0x0070, 0x1517, 0x0078, 0x150e, 0x20a9,
+	0x00fa, 0x0070, 0x151d, 0x0078, 0x1519, 0x2079, 0x3500, 0x7817,
+	0x0001, 0x2061, 0x3540, 0x60a3, 0x0001, 0x60a7, 0x0000, 0x60c3,
+	0x000f, 0x7898, 0xa085, 0x0002, 0x789a, 0x6808, 0xa084, 0xfffd,
+	0x680a, 0x681b, 0x0046, 0x2091, 0x8001, 0x007c, 0x7898, 0xa084,
+	0xfffd, 0x789a, 0xa084, 0x0001, 0x00c0, 0x1540, 0x1078, 0x1760,
+	0x71c4, 0x71c6, 0x794a, 0x007c, 0x74c4, 0x73c8, 0x72cc, 0x74c6,
+	0x73ca, 0x72ce, 0x2079, 0x3500, 0x2009, 0x0040, 0x1078, 0x166f,
+	0x0040, 0x1586, 0x1078, 0x163f, 0x0040, 0x155a, 0x1078, 0x1678,
+	0x0078, 0x1586, 0x6010, 0x2091, 0x8001, 0x7817, 0xffff, 0x2009,
+	0x3568, 0x200b, 0x0005, 0x8108, 0x200b, 0x0000, 0x8108, 0x230a,
+	0x8108, 0x220a, 0x8108, 0x240a, 0x8108, 0x200a, 0x8108, 0x200b,
+	0x0000, 0x8108, 0x2c0a, 0xa02e, 0x2530, 0x0e7e, 0x1078, 0x2f13,
+	0x0e7f, 0x6592, 0x65a2, 0x6696, 0x66a6, 0x60ab, 0x0000, 0x60af,
+	0x0000, 0x2091, 0x8001, 0x1078, 0x1a19, 0x007c, 0x70c3, 0x4005,
+	0x0078, 0x11bd, 0x71c4, 0x70c7, 0x0000, 0x7906, 0x0078, 0x11ba,
+	0x71c4, 0x71c6, 0x2168, 0x0078, 0x1597, 0x2069, 0x1000, 0x690c,
+	0xa016, 0x2d04, 0xa210, 0x8d68, 0x8109, 0x00c0, 0x1599, 0xa285,
+	0x0000, 0x00c0, 0x15a7, 0x70c3, 0x4000, 0x0078, 0x15a9, 0x70c3,
+	0x4003, 0x70ca, 0x0078, 0x11bd, 0x71c4, 0x72c8, 0x73cc, 0x2100,
+	0xa184, 0xfffc, 0x00c0, 0x11c6, 0x2100, 0x0079, 0x15b7, 0x15ce,
+	0x15e3, 0x15e5, 0x15e7, 0x70c3, 0x4003, 0x71ce, 0x72d2, 0x73d6,
+	0x0078, 0x15ca, 0x70c3, 0x4000, 0x70cf, 0x0000, 0x70d3, 0x0000,
+	0x70d7, 0x0000, 0x77c6, 0x71ca, 0x0078, 0x11ba, 0x2031, 0x15e9,
+	0x2624, 0x8630, 0x2412, 0x2204, 0xa446, 0x00c0, 0x15bb, 0xa484,
+	0xffff, 0x00c0, 0x15d0, 0x2031, 0x15e9, 0x8210, 0x8319, 0xa384,
+	0xffff, 0x00c0, 0x15d0, 0x0078, 0x15c2, 0x0078, 0x15c2, 0x0078,
+	0x15c2, 0x5555, 0xaaaa, 0xffff, 0x0000, 0x7960, 0x71c6, 0x71c4,
+	0xa182, 0x0003, 0x00c8, 0x11b2, 0x7962, 0x0078, 0x11ba, 0x7960,
+	0x71c6, 0x0078, 0x11ba, 0x7954, 0x71c6, 0x71c4, 0x7956, 0x7958,
+	0x71ca, 0x71c8, 0x795a, 0x795c, 0x71ce, 0x71cc, 0x795e, 0x0078,
+	0x11ba, 0x7954, 0x71c6, 0x7958, 0x71ca, 0x795c, 0x71ce, 0x0078,
+	0x11ba, 0x700c, 0xa084, 0x007f, 0x0040, 0x161d, 0x7007, 0x0004,
+	0x7004, 0xa084, 0x0004, 0x00c0, 0x1618, 0x7017, 0x0000, 0x7112,
+	0x721a, 0x731e, 0x8108, 0x810c, 0x81a9, 0x8c98, 0x20a1, 0x0030,
+	0x6080, 0x20a2, 0x53a6, 0x780c, 0xa085, 0x0000, 0x7002, 0x7007,
+	0x0001, 0x7108, 0x8104, 0x00c8, 0x1631, 0x7007, 0x0002, 0xa184,
+	0x000c, 0x710c, 0xa184, 0x0300, 0x7003, 0x0000, 0x007c, 0x700c,
+	0xa084, 0x007f, 0x0040, 0x164b, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x1646, 0x7017, 0x0000, 0x7112, 0x721a, 0x731e,
+	0x2099, 0x0030, 0x8108, 0x81ac, 0x780c, 0xa085, 0x0001, 0x7002,
+	0x7007, 0x0001, 0x7008, 0x800c, 0x00c8, 0x165a, 0x7007, 0x0002,
+	0xa08c, 0x000c, 0x00c0, 0x166c, 0x710c, 0xa184, 0x0300, 0x00c0,
+	0x166c, 0x2ca0, 0x53a5, 0xa006, 0x7003, 0x0000, 0x007c, 0x7850,
+	0xa065, 0x0040, 0x1677, 0x2c04, 0x7852, 0x2063, 0x0000, 0x007c,
+	0x0f7e, 0x2079, 0x3500, 0x7850, 0x2062, 0x2c00, 0x7852, 0x0f7f,
+	0x007c, 0x2011, 0x4000, 0x7a52, 0x2019, 0x0410, 0x8319, 0x0040,
+	0x168f, 0xa280, 0x002f, 0x2012, 0x2010, 0x0078, 0x1686, 0x2013,
+	0x0000, 0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003,
+	0x8003, 0x8003, 0x8003, 0xa105, 0xa0e8, 0x3680, 0x007c, 0x1078,
+	0x1692, 0x2900, 0x682a, 0x2a00, 0x682e, 0x6808, 0xa084, 0xffef,
+	0xa80d, 0x690a, 0x2009, 0x354f, 0x210c, 0x6804, 0xa005, 0x0040,
+	0x16bc, 0xa116, 0x00c0, 0x16bc, 0x2060, 0x6000, 0x6806, 0x017e,
+	0x200b, 0x0000, 0x0078, 0x16bf, 0x2009, 0x0000, 0x017e, 0x6804,
+	0xa065, 0x0040, 0x16ce, 0x6000, 0x6806, 0x1078, 0x16df, 0x1078,
+	0x17cb, 0x6810, 0x8001, 0x6812, 0x00c0, 0x16bf, 0x017f, 0x6902,
+	0x6906, 0x007c, 0xa065, 0x0040, 0x16de, 0x6098, 0x609b, 0x0000,
+	0x2008, 0x1078, 0x1678, 0x2100, 0x0078, 0x16d2, 0x007c, 0x6003,
+	0x0103, 0x20a9, 0x001c, 0xac80, 0x0004, 0x20a0, 0x2001, 0x0000,
+	0x40a4, 0x6828, 0x6016, 0x682c, 0x601e, 0x007c, 0x0e7e, 0x2071,
+	0x3540, 0x7040, 0xa08c, 0x0080, 0x00c0, 0x16fc, 0xa088, 0x3580,
+	0x2d0a, 0x8000, 0x7042, 0xa006, 0x0e7f, 0x007c, 0x0e7e, 0x2071,
+	0x3540, 0x2009, 0x3580, 0x7240, 0x8221, 0x8211, 0x0048, 0x1716,
+	0x2104, 0x8108, 0xad06, 0x00c0, 0x1705, 0x8119, 0x211e, 0x8108,
+	0x8318, 0x8211, 0x00c8, 0x170e, 0x7442, 0xa006, 0x0e7f, 0x007c,
+	0x1078, 0x1692, 0x2091, 0x8000, 0x6804, 0x781e, 0xa065, 0x0040,
+	0x175f, 0x0078, 0x1729, 0x2c00, 0x781e, 0x6000, 0xa065, 0x0040,
+	0x175f, 0x600c, 0xa306, 0x00c0, 0x1723, 0x6008, 0xa206, 0x00c0,
+	0x1723, 0x2c28, 0x2001, 0x354f, 0x2004, 0xac06, 0x0040, 0x175f,
+	0x6804, 0xac06, 0x00c0, 0x1746, 0x6000, 0x2060, 0x6806, 0xa005,
+	0x00c0, 0x1746, 0x6803, 0x0000, 0x0078, 0x1750, 0x6400, 0x781c,
+	0x2060, 0x6402, 0xa486, 0x0000, 0x00c0, 0x1750, 0x2c00, 0x6802,
+	0x2560, 0x1078, 0x16df, 0x6017, 0x0005, 0x601f, 0x0020, 0x1078,
+	0x17cb, 0x6810, 0x8001, 0x6812, 0x2001, 0xffff, 0xa005, 0x007c,
+	0x2039, 0x0000, 0x2041, 0x0021, 0x2049, 0x0004, 0x2051, 0x0008,
+	0x2091, 0x8000, 0x1078, 0x169f, 0x8738, 0xa784, 0x0007, 0x00c0,
+	0x176a, 0xa7bc, 0xff00, 0x873f, 0x8738, 0x873f, 0xa784, 0x0f00,
+	0x00c0, 0x176a, 0x2091, 0x8001, 0x007c, 0x2061, 0x0000, 0x6018,
+	0xa084, 0x0001, 0x00c0, 0x178a, 0x78ac, 0x78af, 0x0000, 0xa005,
+	0x00c0, 0x178b, 0x007c, 0xa08c, 0xfff0, 0x0040, 0x1791, 0x1078,
+	0x1ba5, 0x0079, 0x1793, 0x17a3, 0x17a5, 0x17ab, 0x17af, 0x17a3,
+	0x17b3, 0x17a3, 0x17a3, 0x17a3, 0x17a3, 0x17b9, 0x17bd, 0x17a3,
+	0x17a3, 0x17a3, 0x17a3, 0x1078, 0x1ba5, 0x1078, 0x1760, 0x2001,
+	0x8001, 0x0078, 0x17c3, 0x2001, 0x8003, 0x0078, 0x17c3, 0x2001,
+	0x8004, 0x0078, 0x17c3, 0x1078, 0x1760, 0x2001, 0x8006, 0x0078,
+	0x17c3, 0x2001, 0x800c, 0x0078, 0x17c3, 0x1078, 0x1760, 0x2001,
+	0x800d, 0x0078, 0x17c3, 0x70c2, 0x2061, 0x0000, 0x601b, 0x0001,
+	0x2091, 0x4080, 0x007c, 0x2c04, 0x6082, 0x2c08, 0x2063, 0x0000,
+	0x7864, 0x8000, 0x7866, 0x7868, 0xa005, 0x796a, 0x0040, 0x17db,
+	0x2c02, 0x0078, 0x17dc, 0x796e, 0x007c, 0x0c7e, 0x2061, 0x3500,
+	0x6883, 0x0103, 0x2d08, 0x206b, 0x0000, 0x6064, 0x8000, 0x6066,
+	0x6068, 0xa005, 0x616a, 0x0040, 0x17f0, 0x2d02, 0x0078, 0x17f1,
+	0x616e, 0x0c7f, 0x007c, 0x1078, 0x1804, 0x0040, 0x1803, 0x0c7e,
+	0x6098, 0xa065, 0x0040, 0x17fe, 0x1078, 0x16d2, 0x0c7f, 0x609b,
+	0x0000, 0x1078, 0x1678, 0x007c, 0x786c, 0xa065, 0x0040, 0x1816,
+	0x2091, 0x8000, 0x7864, 0x8001, 0x7866, 0x2c04, 0x786e, 0xa005,
+	0x00c0, 0x1814, 0x786a, 0x8000, 0x2091, 0x8001, 0x007c, 0x7898,
+	0xa005, 0x00c0, 0x1865, 0x7974, 0x70d0, 0x0005, 0x0005, 0x72d0,
+	0xa206, 0x00c0, 0x181c, 0x2200, 0xa106, 0x00c0, 0x1833, 0x7804,
+	0xa005, 0x0040, 0x1865, 0x7807, 0x0000, 0x0068, 0x1865, 0x2091,
+	0x4080, 0x0078, 0x1865, 0x1078, 0x166f, 0x0040, 0x1865, 0x7a7c,
+	0x7b78, 0x8107, 0x8004, 0x8004, 0xa210, 0xa399, 0x0000, 0x2009,
+	0x0040, 0x1078, 0x163f, 0x0040, 0x185c, 0x1078, 0x1678, 0x7880,
+	0x8000, 0x7882, 0xa086, 0x0002, 0x00c0, 0x1865, 0x2091, 0x8000,
+	0x78af, 0x0002, 0x7883, 0x0000, 0x7898, 0xa085, 0x0003, 0x789a,
+	0x2091, 0x8001, 0x0078, 0x1865, 0x7883, 0x0000, 0x1078, 0x1992,
+	0x6000, 0xa084, 0x0007, 0x0079, 0x1866, 0x007c, 0x186e, 0x187d,
+	0x189d, 0x186e, 0x18af, 0x186e, 0x186e, 0x186e, 0x2039, 0x0400,
+	0x78a8, 0xa705, 0x78aa, 0x6004, 0xa705, 0x6006, 0x1078, 0x18ed,
+	0x6018, 0x78a6, 0x1078, 0x197a, 0x007c, 0x78a8, 0xa084, 0x0100,
+	0x0040, 0x1884, 0x0078, 0x186e, 0x78ab, 0x0000, 0x6000, 0x8007,
+	0xa084, 0x00ff, 0x789e, 0x8001, 0x609b, 0x0000, 0x0040, 0x189a,
+	0x1078, 0x18ed, 0x0040, 0x189a, 0x78a8, 0xa085, 0x0100, 0x78aa,
+	0x0078, 0x189c, 0x1078, 0x1911, 0x007c, 0x78a8, 0xa08c, 0x0e00,
+	0x00c0, 0x18a6, 0xa084, 0x0100, 0x00c0, 0x18a8, 0x0078, 0x186e,
+	0x1078, 0x18ed, 0x00c0, 0x18ae, 0x1078, 0x1911, 0x007c, 0x78a8,
+	0xa084, 0x0100, 0x0040, 0x18b6, 0x0078, 0x186e, 0x78ab, 0x0000,
+	0x6710, 0x20a9, 0x0001, 0x6014, 0xa084, 0x00ff, 0xa005, 0x0040,
+	0x18d3, 0xa7bc, 0xff00, 0x20a9, 0x0008, 0xa08e, 0x0001, 0x0040,
+	0x18d3, 0x2039, 0x0000, 0x20a9, 0x0080, 0xa08e, 0x0002, 0x0040,
+	0x18d3, 0x0078, 0x18ea, 0x1078, 0x1692, 0x2d00, 0x2091, 0x8000,
+	0x682b, 0x0000, 0x682f, 0x0000, 0x6808, 0xa084, 0xffde, 0x680a,
+	0x2d00, 0xa080, 0x0010, 0x2068, 0x2091, 0x8001, 0x0070, 0x18ea,
+	0x0078, 0x18d6, 0x1078, 0x1678, 0x007c, 0x78a0, 0xa06d, 0x00c0,
+	0x18f8, 0x2c00, 0x78a2, 0x78a6, 0x609b, 0x0000, 0x0078, 0x1904,
+	0x2c00, 0x689a, 0x609b, 0x0000, 0x78a2, 0x2d00, 0x6002, 0x78a4,
+	0xad06, 0x00c0, 0x1904, 0x6002, 0x789c, 0x8001, 0x789e, 0x00c0,
+	0x1910, 0x78a8, 0xa084, 0x0000, 0x78aa, 0x78a4, 0x2060, 0xa006,
+	0x007c, 0xa02e, 0x2530, 0x6118, 0xa184, 0x0060, 0x619e, 0x0040,
+	0x191d, 0x0e7e, 0x1078, 0x2f13, 0x0e7f, 0x6592, 0x65a2, 0x6696,
+	0x66a6, 0x60ab, 0x0000, 0x60af, 0x0000, 0x6710, 0x1078, 0x1692,
+	0x2091, 0x8000, 0x6808, 0xa084, 0x0001, 0x0040, 0x193f, 0x2091,
+	0x8001, 0x1078, 0x16df, 0x2091, 0x8000, 0x1078, 0x17cb, 0x2091,
+	0x8001, 0x78a3, 0x0000, 0x78a7, 0x0000, 0x0078, 0x1979, 0x6020,
+	0xa096, 0x0001, 0x00c0, 0x1946, 0x8000, 0x6022, 0x6a10, 0x6814,
+	0x2091, 0x8001, 0xa202, 0x0048, 0x1955, 0x0040, 0x1955, 0x2039,
+	0x0200, 0x1078, 0x197a, 0x0078, 0x1979, 0x2c08, 0x2091, 0x8000,
+	0x6800, 0xa065, 0x0040, 0x195d, 0x6102, 0x6902, 0x00c0, 0x1961,
+	0x6906, 0x2160, 0x6003, 0x0000, 0x6810, 0x8000, 0x6812, 0x2091,
+	0x8001, 0x6808, 0xa08c, 0x0040, 0x0040, 0x1973, 0xa086, 0x0040,
+	0x680a, 0x1078, 0x16ee, 0x1078, 0x1a19, 0x78a7, 0x0000, 0x78a3,
+	0x0000, 0x007c, 0x6004, 0xa705, 0x6006, 0x2091, 0x8000, 0x1078,
+	0x17cb, 0x2091, 0x8001, 0x78a4, 0xa065, 0x0040, 0x198d, 0x6098,
+	0x78a6, 0x609b, 0x0000, 0x0078, 0x197d, 0x78a3, 0x0000, 0x78a7,
+	0x0000, 0x007c, 0x7970, 0x7874, 0x8000, 0xa10a, 0x00c8, 0x1999,
+	0xa006, 0x7876, 0x70d2, 0x7804, 0xa005, 0x0040, 0x19a7, 0x8001,
+	0x7806, 0x00c0, 0x19a7, 0x0068, 0x19a7, 0x2091, 0x4080, 0x007c,
+	0x0068, 0x19c2, 0x2029, 0x0000, 0x786c, 0xa065, 0x0040, 0x19bd,
+	0x1078, 0x19c3, 0x0040, 0x19bd, 0x057e, 0x1078, 0x19d9, 0x057f,
+	0x00c0, 0x19bd, 0x8528, 0x0078, 0x19ac, 0x85ff, 0x0040, 0x19c2,
+	0x2091, 0x4080, 0x007c, 0x7b84, 0x7988, 0x72d4, 0x0005, 0x0005,
+	0x70d4, 0xa206, 0x00c0, 0x19c5, 0x2200, 0xa102, 0x00c0, 0x19d3,
+	0x2300, 0xa005, 0x007c, 0x0048, 0x19d7, 0xa302, 0x007c, 0x8002,
+	0x007c, 0x1078, 0x1a0b, 0x2009, 0x001c, 0x6024, 0xa005, 0x0040,
+	0x19e3, 0x2009, 0x0040, 0x1078, 0x1611, 0x0040, 0x19fc, 0x7894,
+	0x8000, 0x7896, 0xa086, 0x0002, 0x00c0, 0x1a0a, 0x2091, 0x8000,
+	0x78af, 0x0003, 0x7897, 0x0000, 0x7898, 0xa085, 0x0300, 0x789a,
+	0x2091, 0x8001, 0x0078, 0x1a0a, 0x7897, 0x0000, 0x1078, 0x17f3,
+	0x7984, 0x7888, 0x8000, 0xa10a, 0x00c8, 0x1a07, 0xa006, 0x788a,
+	0x70d6, 0xa006, 0x007c, 0x8107, 0x8004, 0x8004, 0x7a90, 0x7b8c,
+	0xa210, 0xa399, 0x0000, 0x007c, 0x2009, 0x3568, 0x2091, 0x8000,
+	0x200a, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3540, 0x2091, 0x8000,
+	0x2104, 0xa086, 0x0000, 0x00c0, 0x1a34, 0x2009, 0x3512, 0x2104,
+	0xa005, 0x00c0, 0x1a34, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x1a34,
+	0x0018, 0x1a34, 0x781b, 0x0044, 0x2091, 0x8001, 0x0f7f, 0x007c,
+	0x127e, 0x2091, 0x2300, 0x2071, 0x3540, 0x2079, 0x0100, 0x2019,
+	0x2dd8, 0x20a1, 0x012b, 0x2304, 0xa005, 0x0040, 0x1a50, 0x789a,
+	0x8318, 0x23ac, 0x8318, 0x2398, 0x53a6, 0x3318, 0x0078, 0x1a43,
+	0x789b, 0x0020, 0x20a9, 0x0010, 0x78af, 0x0000, 0x78af, 0x0220,
+	0x0070, 0x1a5c, 0x0078, 0x1a54, 0x7003, 0x0000, 0x1078, 0x1b5b,
+	0x7004, 0xa084, 0x000f, 0xa085, 0x6280, 0x7806, 0x780f, 0x9200,
+	0x7843, 0x00d8, 0x7853, 0x0080, 0x780b, 0x0038, 0x7047, 0x357f,
+	0x7043, 0x0000, 0x127f, 0x2000, 0x007c, 0xa18c, 0x000f, 0x2011,
+	0x0101, 0x2204, 0xa084, 0xfff0, 0xa105, 0x2012, 0x1078, 0x1b5b,
+	0x007c, 0x2011, 0x0101, 0x20a9, 0x0009, 0x810b, 0x0070, 0x1a8a,
+	0x0078, 0x1a85, 0xa18c, 0x0e00, 0x2204, 0xa084, 0xf1ff, 0xa105,
+	0x2012, 0x007c, 0x2009, 0x0101, 0x20a9, 0x0005, 0x8213, 0x0070,
+	0x1a9b, 0x0078, 0x1a96, 0xa294, 0x00e0, 0x2104, 0xa084, 0xff1f,
+	0xa205, 0x200a, 0x007c, 0x2011, 0x0101, 0x20a9, 0x000c, 0x810b,
+	0x0070, 0x1aac, 0x0078, 0x1aa7, 0xa18c, 0xf000, 0x2204, 0xa084,
+	0x0fff, 0xa105, 0x2012, 0x007c, 0x2011, 0x0102, 0x2204, 0xa084,
+	0xffcf, 0xa105, 0x2012, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020,
+	0x0c7e, 0x2061, 0x0100, 0x609a, 0x62ac, 0x63ac, 0x0c7f, 0x007c,
+	0x8103, 0x8003, 0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a,
+	0x60a4, 0xa084, 0xffdf, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003,
+	0xa080, 0x0022, 0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0xa085,
+	0x0020, 0x60ae, 0x0c7f, 0x007c, 0x8103, 0x8003, 0xa080, 0x0020,
+	0x0c7e, 0x2061, 0x0100, 0x609a, 0x60a4, 0x62ae, 0x2010, 0x60a4,
+	0x63ae, 0x2018, 0x0c7f, 0x007c, 0x2091, 0x8000, 0x0c7e, 0x0e7e,
+	0x6818, 0xa005, 0x0040, 0x1b39, 0x2061, 0x3f80, 0x1078, 0x1b41,
+	0x0040, 0x1b27, 0x20a9, 0x0000, 0x2061, 0x3e80, 0x0c7e, 0x1078,
+	0x1b41, 0x0040, 0x1b13, 0x0c7f, 0x8c60, 0x0070, 0x1b11, 0x0078,
+	0x1b06, 0x0078, 0x1b39, 0x007f, 0xa082, 0x3e80, 0x2071, 0x3540,
+	0x70ba, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, 0x60a7, 0x0000,
+	0x2001, 0x0004, 0x70a2, 0x1078, 0x1a14, 0x0078, 0x1b35, 0x2071,
+	0x3540, 0x601c, 0xa085, 0x0800, 0x601e, 0x71b6, 0x60a7, 0x0000,
+	0x2001, 0x0006, 0x70a2, 0x1078, 0x1a14, 0x2001, 0x0000, 0x0078,
+	0x1b3b, 0x2001, 0x0001, 0x2091, 0x8001, 0xa005, 0x0e7f, 0x0c7f,
+	0x007c, 0x2c04, 0xa005, 0x0040, 0x1b58, 0x2060, 0x600c, 0xa306,
+	0x00c0, 0x1b55, 0x6008, 0xa206, 0x00c0, 0x1b55, 0x6010, 0xa106,
+	0x00c0, 0x1b55, 0xa006, 0x0078, 0x1b5a, 0x6000, 0x0078, 0x1b42,
+	0xa085, 0x0001, 0x007c, 0x2011, 0x3541, 0x220c, 0xa18c, 0x000f,
+	0x2011, 0x013b, 0x2204, 0xa084, 0x0100, 0x0040, 0x1b6a, 0x2021,
+	0xff80, 0x2122, 0x007c, 0x0e7e, 0x68e4, 0xa08c, 0x0020, 0x0040,
+	0x1ba3, 0xa084, 0x0006, 0x00c0, 0x1ba3, 0x6010, 0x8007, 0xa084,
+	0x000f, 0x8003, 0x8003, 0x8003, 0xa0f0, 0x3600, 0x7004, 0xa084,
+	0x000a, 0x00c0, 0x1ba3, 0x7108, 0xa194, 0xff00, 0x0040, 0x1ba3,
+	0xa18c, 0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x1b96, 0x2001,
+	0x0032, 0xa106, 0x0040, 0x1b9a, 0x0078, 0x1b9e, 0x2009, 0x0020,
+	0x0078, 0x1ba0, 0x2009, 0x003f, 0x0078, 0x1ba0, 0x2011, 0x0000,
+	0x2100, 0xa205, 0x700a, 0x0e7f, 0x007c, 0x0068, 0x1ba5, 0x007e,
+	0x2071, 0x0000, 0x7018, 0xa084, 0x0001, 0x00c0, 0x1baa, 0x007f,
+	0x2e08, 0x2071, 0x0010, 0x70ca, 0x007f, 0x70c6, 0x70c3, 0x8002,
+	0x2071, 0x0000, 0x701b, 0x0001, 0x2091, 0x4080, 0x007f, 0x2070,
+	0x007f, 0x0078, 0x1bc1, 0x107e, 0x007e, 0x127e, 0x2091, 0x2300,
+	0x7f3c, 0x7e58, 0x7c30, 0x7d38, 0xa594, 0x003f, 0xa484, 0x4000,
+	0x0040, 0x1bd8, 0xa784, 0x007c, 0x00c0, 0x2d9c, 0x1078, 0x1ba5,
+	0xa49c, 0x000f, 0xa382, 0x0004, 0x0050, 0x1be0, 0x1078, 0x1ba5,
+	0x8507, 0xa084, 0x000f, 0x0079, 0x1be5, 0x1fea, 0x209a, 0x20c0,
+	0x22e6, 0x256b, 0x25b3, 0x25ea, 0x2665, 0x26bf, 0x2744, 0x1c0b,
+	0x1bf5, 0x1e53, 0x1f1d, 0x254a, 0x1bf5, 0x1078, 0x1ba5, 0x0018,
+	0x1bc8, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c, 0x7003,
+	0x0000, 0x703f, 0x0000, 0x7030, 0xa005, 0x0040, 0x1c09, 0x7033,
+	0x0000, 0x0018, 0x1bc8, 0x705c, 0xa005, 0x00c0, 0x1cb6, 0x70a0,
+	0xa084, 0x0007, 0x0079, 0x1c14, 0x1cd6, 0x1c1c, 0x1c2a, 0x1c4b,
+	0x1c71, 0x1c9d, 0x1c9b, 0x1c1c, 0x7808, 0xa084, 0xfffd, 0x780a,
+	0x2009, 0x0046, 0x1078, 0x2412, 0x00c0, 0x1c28, 0x7003, 0x0004,
+	0x0078, 0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c49, 0x70b4, 0x8007,
+	0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0x78ab, 0x000c, 0x789b,
+	0x0060, 0x78ab, 0x0001, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078,
+	0x2410, 0x00c0, 0x1c49, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033,
+	0x3570, 0x0078, 0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c6f, 0x71b4,
+	0x8107, 0x789b, 0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c, 0x0007,
+	0xa18d, 0x00c0, 0x79aa, 0x78ab, 0x0006, 0x789b, 0x0060, 0x78ab,
+	0x0002, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078, 0x2410, 0x00c0,
+	0x1c6f, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033, 0x3570, 0x0078,
+	0x1bf7, 0x1078, 0x2d5e, 0x00c0, 0x1c99, 0x71b4, 0x8107, 0x789b,
+	0x007e, 0x78aa, 0x789b, 0x0010, 0xa18c, 0x0007, 0xa18d, 0x00c0,
+	0x79aa, 0x78ab, 0x0020, 0x71b8, 0x79aa, 0x78ab, 0x000d, 0x789b,
+	0x0060, 0x78ab, 0x0004, 0x785b, 0x0004, 0x2009, 0x00f7, 0x1078,
+	0x2410, 0x00c0, 0x1c99, 0x7003, 0x0004, 0x70c3, 0x000f, 0x7033,
+	0x3570, 0x0078, 0x1bf7, 0x0078, 0x1c4b, 0x1078, 0x2d5e, 0x00c0,
+	0x1bf7, 0x70bc, 0x2068, 0x789b, 0x0010, 0x6f10, 0x1078, 0x2ca1,
+	0x2c50, 0x6810, 0xa084, 0x0007, 0xa085, 0x0080, 0x78aa, 0x6e18,
+	0x2041, 0x0001, 0x2001, 0x0004, 0x0078, 0x1dde, 0x1078, 0x2d5e,
+	0x00c0, 0x1bf7, 0x789b, 0x0010, 0x705c, 0x2068, 0x6f10, 0x1078,
+	0x2ca1, 0x2c50, 0x6008, 0xa085, 0x0010, 0x600a, 0x6810, 0xa084,
+	0x0007, 0xa085, 0x0080, 0x78aa, 0x2031, 0x0020, 0x2041, 0x0001,
+	0x1078, 0x2dc5, 0x2001, 0x0003, 0x0078, 0x1dc9, 0x0018, 0x1bc8,
+	0x7440, 0xa485, 0x0000, 0x0040, 0x1cf0, 0xa080, 0x3580, 0x2030,
+	0x7144, 0x8108, 0xa12a, 0x0048, 0x1ce7, 0x2009, 0x3580, 0x2164,
+	0x6504, 0x85ff, 0x00c0, 0x1cfd, 0x8421, 0x00c0, 0x1ce1, 0x7146,
+	0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1bf7, 0x7640, 0xa6b0,
+	0x3580, 0x7144, 0x2600, 0x0078, 0x1cec, 0x7146, 0x2568, 0x2558,
+	0x753e, 0x2c50, 0x6034, 0xa085, 0x0000, 0x00c0, 0x1cfa, 0x6708,
+	0x7736, 0xa784, 0x013f, 0x0040, 0x1d2f, 0xa784, 0x0021, 0x00c0,
+	0x1cfa, 0xa784, 0x0002, 0x0040, 0x1d1c, 0xa784, 0x0004, 0x0040,
+	0x1cfa, 0xa7bc, 0xfffb, 0x670a, 0xa784, 0x0008, 0x00c0, 0x1cfa,
+	0xa784, 0x0010, 0x00c0, 0x1cfa, 0xa784, 0x0100, 0x0040, 0x1d2f,
+	0x6018, 0xa005, 0x00c0, 0x1cfa, 0xa7bc, 0xfeff, 0x670a, 0x681f,
+	0x0000, 0x6e18, 0xa684, 0x000e, 0x6118, 0x0040, 0x1d3f, 0x601c,
+	0xa102, 0x0048, 0x1d42, 0x0040, 0x1d42, 0x0078, 0x1cf6, 0x81ff,
+	0x00c0, 0x1cf6, 0xa784, 0x0080, 0x00c0, 0x1d48, 0x700c, 0x6022,
+	0xa7bc, 0xff7f, 0x670a, 0x6b10, 0x8307, 0xa084, 0x000f, 0x8003,
+	0x8003, 0x8003, 0xa080, 0x3600, 0x2060, 0x2048, 0x704a, 0x6000,
+	0x704e, 0x6004, 0x7052, 0x2a60, 0x0018, 0x1bc8, 0x789b, 0x0010,
+	0xa046, 0x1078, 0x2d5e, 0x00c0, 0x1bf7, 0x6b10, 0xa39c, 0x0007,
+	0xa39d, 0x00c0, 0x704c, 0xa084, 0x8000, 0x0040, 0x1d73, 0xa684,
+	0x0001, 0x0040, 0x1d75, 0xa39c, 0xffbf, 0xa684, 0x0010, 0x0040,
+	0x1d7b, 0xa39d, 0x0020, 0x7baa, 0x8840, 0xa684, 0x000e, 0x00c0,
+	0x1d86, 0xa7bd, 0x0010, 0x670a, 0x0078, 0x1dc7, 0x714c, 0xa18c,
+	0x0800, 0x0040, 0x2902, 0x2011, 0x0021, 0x8004, 0x8004, 0x0048,
+	0x1d9d, 0x2011, 0x0022, 0x8004, 0x0048, 0x1d9d, 0x2011, 0x0020,
+	0x8004, 0x0048, 0x1d9d, 0x0040, 0x1dc7, 0x7aaa, 0x8840, 0x1078,
+	0x2d77, 0x6a10, 0x610c, 0x8108, 0xa18c, 0x00ff, 0xa1e0, 0x3e80,
+	0x2c64, 0x8cff, 0x0040, 0x1dbe, 0x6010, 0xa206, 0x00c0, 0x1da8,
+	0x60b4, 0x8001, 0x60b6, 0x00c0, 0x1da3, 0x0c7e, 0x2a60, 0x6008,
+	0xa085, 0x0100, 0x600a, 0x0c7f, 0x0078, 0x1cd6, 0x1078, 0x2d5e,
+	0x00c0, 0x1bf7, 0x2a60, 0x610e, 0x79aa, 0x8840, 0x712e, 0x2001,
+	0x0001, 0x007e, 0x7150, 0xa184, 0x0018, 0x0040, 0x1ddd, 0xa184,
+	0x0010, 0x0040, 0x1dd7, 0x1078, 0x2acc, 0x00c0, 0x1ddd, 0xa184,
+	0x0008, 0x0040, 0x1ddd, 0x1078, 0x29e6, 0x007f, 0x7002, 0xa68c,
+	0x0060, 0x88ff, 0x0040, 0x1de6, 0xa18d, 0x0004, 0x795a, 0x69b2,
+	0x789b, 0x0060, 0x2800, 0x78aa, 0x789b, 0x0061, 0x6814, 0xa085,
+	0x8000, 0x6816, 0x78aa, 0x157e, 0x137e, 0x147e, 0x20a1, 0x012c,
+	0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000a, 0x2098, 0x53a6,
+	0x147f, 0x137f, 0x157f, 0x6810, 0x8007, 0x789b, 0x007e, 0x78aa,
+	0x6d90, 0x7dd6, 0x7dde, 0x6e94, 0x7ed2, 0x7eda, 0x7830, 0xa084,
+	0x00c0, 0x00c0, 0x1e15, 0x0098, 0x1e1d, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x2d77, 0x0078, 0x1bff, 0x7200, 0xa284, 0x0007,
+	0xa086, 0x0001, 0x00c0, 0x1e2a, 0x781b, 0x0049, 0x1078, 0x2d77,
+	0x0078, 0x1e3b, 0x6ab0, 0xa295, 0x2000, 0x7a5a, 0x781b, 0x0049,
+	0x1078, 0x2d77, 0x7200, 0x2500, 0xa605, 0x0040, 0x1e3b, 0xa284,
+	0x0007, 0x1079, 0x1e49, 0xad80, 0x0008, 0x7032, 0xa284, 0x0007,
+	0xa086, 0x0001, 0x00c0, 0x1e47, 0x6018, 0x8000, 0x601a, 0x0078,
+	0x1bf7, 0x1e51, 0x30f0, 0x30f0, 0x30df, 0x30f0, 0x1e51, 0x1e51,
+	0x1e51, 0x1078, 0x1ba5, 0x7808, 0xa084, 0xfffd, 0x780a, 0x0f7e,
+	0x2079, 0x3500, 0x7898, 0x0f7f, 0xa084, 0x0001, 0x0040, 0x1e79,
+	0x70a0, 0xa086, 0x0001, 0x00c0, 0x1e68, 0x70a2, 0x0078, 0x1f01,
+	0x70a0, 0xa086, 0x0005, 0x00c0, 0x1e77, 0x70bc, 0x2068, 0x6817,
+	0x0004, 0x6813, 0x0000, 0x681c, 0xa085, 0x0008, 0x681e, 0x70a3,
+	0x0000, 0x157e, 0x2011, 0x0004, 0x71a0, 0xa186, 0x0001, 0x0040,
+	0x1e9b, 0xa186, 0x0007, 0x00c0, 0x1e8b, 0x2009, 0x352b, 0x200b,
+	0x0005, 0x0078, 0x1e9b, 0x2009, 0x3513, 0x2104, 0x2009, 0x3512,
+	0x200a, 0x2009, 0x352b, 0x200b, 0x0001, 0x70a3, 0x0000, 0x70a7,
+	0x0001, 0x0078, 0x1e9d, 0x70a3, 0x0000, 0x1078, 0x2ec7, 0x20a9,
+	0x0010, 0x2039, 0x0000, 0x1078, 0x2ba6, 0xa7b8, 0x0100, 0x0070,
+	0x1eab, 0x0078, 0x1ea3, 0x7000, 0x2020, 0x0079, 0x1eaf, 0x1edd,
+	0x1ec6, 0x1ec6, 0x1eb9, 0x1edd, 0x1edd, 0x1eb7, 0x1eb7, 0x1078,
+	0x1ba5, 0x2021, 0x3557, 0x2404, 0xa005, 0x0040, 0x1ec6, 0xad06,
+	0x00c0, 0x1ec6, 0x6800, 0x2022, 0x0078, 0x1ed6, 0x681c, 0xa084,
+	0x0001, 0x00c0, 0x1ed2, 0x6f10, 0x1078, 0x2ca1, 0x1078, 0x28d9,
+	0x0078, 0x1ed6, 0x7054, 0x2060, 0x6800, 0x6002, 0x6a16, 0x681c,
+	0xa085, 0x0008, 0x681e, 0x1078, 0x17dd, 0x2021, 0x3f80, 0x1078,
+	0x1f07, 0x2021, 0x3557, 0x1078, 0x1f07, 0x20a9, 0x0000, 0x2021,
+	0x3e80, 0x1078, 0x1f07, 0x8420, 0x0070, 0x1ef0, 0x0078, 0x1ee9,
+	0x20a9, 0x0080, 0x2061, 0x3680, 0x6018, 0x6110, 0xa102, 0x6012,
+	0x601b, 0x0000, 0xace0, 0x0010, 0x0070, 0x1f00, 0x0078, 0x1ef4,
+	0x157f, 0x7003, 0x0000, 0x703f, 0x0000, 0x0078, 0x1bf7, 0x047e,
+	0x2404, 0xa005, 0x0040, 0x1f19, 0x2068, 0x6800, 0x007e, 0x6a16,
+	0x681c, 0xa085, 0x0008, 0x681e, 0x1078, 0x17dd, 0x007f, 0x0078,
+	0x1f09, 0x047f, 0x2023, 0x0000, 0x007c, 0xa282, 0x0003, 0x0050,
+	0x1f23, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x1f26, 0x1f29, 0x1f9c,
+	0x1faa, 0xa282, 0x0002, 0x0040, 0x1f2f, 0x1078, 0x1ba5, 0x70a0,
+	0x70a3, 0x0000, 0x70c3, 0x0000, 0x0079, 0x1f36, 0x1f3e, 0x1f3e,
+	0x1f40, 0x1f74, 0x2908, 0x1f3e, 0x1f74, 0x1f3e, 0x1078, 0x1ba5,
+	0x77b4, 0x1078, 0x2ba6, 0x77b4, 0xa7bc, 0x0f00, 0x1078, 0x2ca1,
+	0x6018, 0xa005, 0x0040, 0x1f6b, 0x2021, 0x3f80, 0x2009, 0x0004,
+	0x2011, 0x0010, 0x1078, 0x1fc5, 0x0040, 0x1f6b, 0x157e, 0x20a9,
+	0x0000, 0x2021, 0x3e80, 0x047e, 0x2009, 0x0004, 0x2011, 0x0010,
+	0x1078, 0x1fc5, 0x047f, 0x0040, 0x1f6a, 0x8420, 0x0070, 0x1f6a,
+	0x0078, 0x1f5b, 0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, 0x1f46,
+	0x0078, 0x1bff, 0x0078, 0x1bff, 0x77b4, 0x1078, 0x2ca1, 0x6018,
+	0xa005, 0x0040, 0x1f9a, 0x2021, 0x3f80, 0x2009, 0x0005, 0x2011,
+	0x0020, 0x1078, 0x1fc5, 0x0040, 0x1f9a, 0x157e, 0x20a9, 0x0000,
+	0x2021, 0x3e80, 0x047e, 0x2009, 0x0005, 0x2011, 0x0020, 0x1078,
+	0x1fc5, 0x047f, 0x0040, 0x1f99, 0x8420, 0x0070, 0x1f99, 0x0078,
+	0x1f8a, 0x157f, 0x0078, 0x1bff, 0x2200, 0x0079, 0x1f9f, 0x1fa2,
+	0x1fa4, 0x1fa4, 0x1078, 0x1ba5, 0x70a3, 0x0000, 0x70a7, 0x0001,
+	0x0078, 0x1bf7, 0x2200, 0x0079, 0x1fad, 0x1fb2, 0x1fa4, 0x1fb0,
+	0x1078, 0x1ba5, 0x1078, 0x241f, 0x7000, 0xa086, 0x0001, 0x00c0,
+	0x28af, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef, 0x600a, 0x1078,
+	0x28a2, 0x0040, 0x28af, 0x0078, 0x1cd6, 0x2404, 0xa005, 0x0040,
+	0x1fe6, 0x2068, 0x2d04, 0x007e, 0x6810, 0xa706, 0x0040, 0x1fd4,
+	0x2d20, 0x007f, 0x0078, 0x1fc6, 0x007f, 0x2022, 0x6916, 0x681c,
+	0xa205, 0x681e, 0x1078, 0x17dd, 0x6010, 0x8001, 0x6012, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x1078, 0x28ef, 0x007c, 0xa085, 0x0001,
+	0x0078, 0x1fe5, 0x2300, 0x0079, 0x1fed, 0x1ff2, 0x1ff0, 0x2035,
+	0x1078, 0x1ba5, 0x78e4, 0xa005, 0x00d0, 0x2015, 0x0018, 0x2015,
+	0x2008, 0xa084, 0x0030, 0x00c0, 0x2001, 0x781b, 0x0049, 0x0078,
+	0x1bf7, 0x78ec, 0xa084, 0x0003, 0x0040, 0x1ffd, 0x2100, 0xa084,
+	0x0007, 0x0079, 0x200b, 0x2023, 0x2029, 0x201d, 0x2013, 0x2d58,
+	0x2d58, 0x2013, 0x202f, 0x1078, 0x1ba5, 0x7000, 0xa005, 0x0040,
+	0x1bff, 0x2001, 0x0003, 0x0078, 0x22fa, 0x1078, 0x2b89, 0x781b,
+	0x0055, 0x0078, 0x1bf7, 0x1078, 0x2b89, 0x781b, 0x00dc, 0x0078,
+	0x1bf7, 0x1078, 0x2b89, 0x781b, 0x00e3, 0x0078, 0x1bf7, 0x1078,
+	0x2b89, 0x781b, 0x009d, 0x0078, 0x1bf7, 0xa584, 0x000f, 0x00c0,
+	0x205f, 0x1078, 0x241f, 0x7000, 0x0079, 0x203e, 0x2046, 0x2053,
+	0x2046, 0x28af, 0x2048, 0x28af, 0x2046, 0x2046, 0x1078, 0x1ba5,
+	0x71a0, 0x70a3, 0x0000, 0xa186, 0x0004, 0x00c0, 0x2051, 0x0078,
+	0x2908, 0x0078, 0x28af, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x28a2, 0x0040, 0x28af, 0x0078, 0x1cd6, 0x78e4,
+	0xa005, 0x00d0, 0x2015, 0x0018, 0x2015, 0x2008, 0xa084, 0x0030,
+	0x00c0, 0x206e, 0x781b, 0x0049, 0x0078, 0x1bf7, 0x78ec, 0xa084,
+	0x0003, 0x0040, 0x206a, 0x2100, 0xa184, 0x0007, 0x0079, 0x2078,
+	0x2088, 0x208e, 0x2082, 0x2080, 0x2d58, 0x2d58, 0x2080, 0x2d50,
+	0x1078, 0x1ba5, 0x1078, 0x2b91, 0x781b, 0x0055, 0x0078, 0x1bf7,
+	0x1078, 0x2b91, 0x781b, 0x00dc, 0x0078, 0x1bf7, 0x1078, 0x2b91,
+	0x781b, 0x00e3, 0x0078, 0x1bf7, 0x1078, 0x2b91, 0x781b, 0x009d,
+	0x0078, 0x1bf7, 0x2300, 0x0079, 0x209d, 0x20a2, 0x20a0, 0x20a4,
+	0x1078, 0x1ba5, 0x0078, 0x2665, 0x6817, 0x0008, 0x78a3, 0x0000,
+	0x79e4, 0xa184, 0x0030, 0x0040, 0x2665, 0x78ec, 0xa084, 0x0003,
+	0x0040, 0x2665, 0xa184, 0x0007, 0x0079, 0x20b6, 0x2023, 0x2029,
+	0x201d, 0x2d30, 0x2d58, 0x2d58, 0x20be, 0x2d50, 0x1078, 0x1ba5,
+	0xa282, 0x0005, 0x0050, 0x20c6, 0x1078, 0x1ba5, 0x2300, 0x0079,
+	0x20c9, 0x20cc, 0x22ce, 0x22da, 0x2200, 0x0079, 0x20cf, 0x20d4,
+	0x20d6, 0x20e9, 0x20d4, 0x22b3, 0x1078, 0x1ba5, 0x789b, 0x0018,
+	0x78a8, 0xa084, 0x00ff, 0xa082, 0x0020, 0x0048, 0x2b6a, 0xa08a,
+	0x0004, 0x00c8, 0x2b6a, 0x0079, 0x20e5, 0x2b6a, 0x2b6a, 0x2b6a,
+	0x2b0c, 0x789b, 0x0018, 0x79a8, 0xa184, 0x0080, 0x0040, 0x20fe,
+	0xa184, 0x0018, 0x0040, 0x20fa, 0x0078, 0x2b6a, 0x7000, 0xa005,
+	0x00c0, 0x20f4, 0x2011, 0x0003, 0x0078, 0x2752, 0xa184, 0x00ff,
+	0xa08a, 0x0010, 0x00c8, 0x2b6a, 0x0079, 0x2106, 0x2118, 0x2116,
+	0x212e, 0x2130, 0x21c2, 0x2b6a, 0x2b6a, 0x21c4, 0x2b6a, 0x2b6a,
+	0x22af, 0x22af, 0x2b6a, 0x2b6a, 0x2b6a, 0x22b1, 0x1078, 0x1ba5,
+	0xa684, 0x1000, 0x0040, 0x2125, 0x2001, 0x0300, 0x8000, 0x8000,
+	0x783a, 0x781b, 0x009a, 0x0078, 0x1bf7, 0x6814, 0xa084, 0x8000,
+	0x0040, 0x212c, 0x6817, 0x0003, 0x0078, 0x2d30, 0x1078, 0x1ba5,
+	0x691c, 0x691e, 0xa684, 0x1800, 0x00c0, 0x214a, 0x681c, 0xa084,
+	0x0001, 0x00c0, 0x2152, 0x6814, 0xa086, 0x0008, 0x00c0, 0x2142,
+	0x6817, 0x0000, 0xa684, 0x0400, 0x0040, 0x21be, 0x781b, 0x0058,
+	0x0078, 0x1bf7, 0xa684, 0x1000, 0x0040, 0x2152, 0x781b, 0x0058,
+	0x0078, 0x1bf7, 0xa684, 0x0060, 0x0040, 0x21ba, 0xa684, 0x0800,
+	0x0040, 0x21ba, 0xa684, 0x8000, 0x00c0, 0x2160, 0x0078, 0x217a,
+	0xa6b4, 0x7fff, 0x7e5a, 0x6eb2, 0x789b, 0x0074, 0x7aac, 0x79ac,
+	0x78ac, 0x801b, 0x00c8, 0x216d, 0x8000, 0xa084, 0x003f, 0xa108,
+	0xa291, 0x0000, 0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200,
+	0xa303, 0x68aa, 0xa684, 0x4000, 0x0040, 0x2182, 0xa6b4, 0xbfff,
+	0x7e5a, 0x6eb2, 0x7000, 0xa086, 0x0003, 0x00c0, 0x218f, 0x1078,
+	0x2f3a, 0x1078, 0x30df, 0x781b, 0x0067, 0x0078, 0x1bf7, 0xa006,
+	0x1078, 0x3194, 0x6aac, 0x69a8, 0x6c94, 0x6b90, 0x2200, 0xa105,
+	0x0040, 0x219e, 0x2200, 0xa422, 0x2100, 0xa31b, 0x7cd2, 0x7bd6,
+	0x2300, 0xa405, 0x00c0, 0x21ac, 0xa6b5, 0x4000, 0x7e5a, 0x6eb2,
+	0x781b, 0x0067, 0x0078, 0x1bf7, 0x781b, 0x0067, 0x2200, 0xa115,
+	0x00c0, 0x21b6, 0x1078, 0x30f0, 0x0078, 0x1bf7, 0x1078, 0x311d,
+	0x0078, 0x1bf7, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x781b, 0x0058,
+	0x0078, 0x1bf7, 0x1078, 0x1ba5, 0x0078, 0x2221, 0x691c, 0xa184,
+	0x0100, 0x0040, 0x21dc, 0xa18c, 0xfeff, 0x691e, 0x0c7e, 0x7048,
+	0x2060, 0x6000, 0xa084, 0xefff, 0x6002, 0x6004, 0xa084, 0xfff5,
+	0x6006, 0x0c7f, 0x0078, 0x2210, 0xa184, 0x0200, 0x0040, 0x2210,
+	0xa18c, 0xfdff, 0x691e, 0x0c7e, 0x7048, 0x2060, 0x6000, 0xa084,
+	0xdfff, 0x6002, 0x6004, 0xa084, 0xffef, 0x6006, 0x2008, 0x2c48,
+	0x0c7f, 0xa184, 0x0008, 0x0040, 0x2210, 0x1078, 0x2c9d, 0x1078,
+	0x29e6, 0x88ff, 0x0040, 0x2210, 0x789b, 0x0060, 0x2800, 0x78aa,
+	0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x220c,
+	0x781b, 0x0055, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7,
+	0x7e58, 0xa684, 0x0400, 0x00c0, 0x2219, 0x781b, 0x0058, 0x0078,
+	0x1bf7, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x0078, 0x2b70, 0x0078,
+	0x2b70, 0x2019, 0x0000, 0x7990, 0xa18c, 0x0007, 0x0040, 0x221f,
+	0x789b, 0x0010, 0x78a8, 0xa094, 0x00ff, 0xa286, 0x0001, 0x00c0,
+	0x2244, 0x2300, 0x7ca8, 0xa400, 0x2018, 0xa102, 0x0040, 0x223c,
+	0x0048, 0x223c, 0x0078, 0x223e, 0x0078, 0x21c6, 0x24a8, 0x7aa8,
+	0x00f0, 0x223e, 0x0078, 0x222a, 0xa284, 0x00f0, 0xa086, 0x0020,
+	0x00c0, 0x22a0, 0x8318, 0x8318, 0x2300, 0xa102, 0x0040, 0x2254,
+	0x0048, 0x2254, 0x0078, 0x229d, 0xa286, 0x0023, 0x0040, 0x221f,
+	0x6818, 0xa084, 0xfff1, 0x681a, 0x7e58, 0xa684, 0xfff1, 0xa085,
+	0x0010, 0x2030, 0x7e5a, 0x6008, 0xa085, 0x0010, 0x600a, 0x0c7e,
+	0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184, 0x0010,
+	0x0040, 0x2278, 0x1078, 0x2c9d, 0x1078, 0x2acc, 0x0078, 0x2287,
+	0x0c7e, 0x7048, 0x2060, 0x6004, 0x2008, 0x2c48, 0x0c7f, 0xa184,
+	0x0008, 0x0040, 0x2210, 0x1078, 0x2c9d, 0x1078, 0x29e6, 0x88ff,
+	0x0040, 0x2210, 0x789b, 0x0060, 0x2800, 0x78aa, 0xa6b5, 0x0004,
+	0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2299, 0x781b, 0x0055, 0x0078,
+	0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x7aa8, 0x0078, 0x222a,
+	0x8318, 0x2300, 0xa102, 0x0040, 0x22a9, 0x0048, 0x22a9, 0x0078,
+	0x222a, 0xa284, 0x0080, 0x00c0, 0x2b76, 0x0078, 0x2b70, 0x0078,
+	0x2b76, 0x0078, 0x2b6a, 0x789b, 0x0018, 0x78a8, 0xa084, 0x00ff,
+	0xa08e, 0x0001, 0x0040, 0x22be, 0x1078, 0x1ba5, 0x7aa8, 0xa294,
+	0x00ff, 0x78a8, 0xa084, 0x00ff, 0xa08a, 0x0004, 0x00c8, 0x2b6a,
+	0x0079, 0x22ca, 0x2b6a, 0x2939, 0x2b6a, 0x2a67, 0xa282, 0x0000,
+	0x00c0, 0x22d4, 0x1078, 0x1ba5, 0x1078, 0x2b89, 0x781b, 0x0069,
+	0x0078, 0x1bf7, 0xa282, 0x0003, 0x00c0, 0x22e0, 0x1078, 0x1ba5,
+	0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7, 0xa282, 0x0004,
+	0x0050, 0x22ec, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x22ef, 0x22f2,
+	0x23c9, 0x23fa, 0xa286, 0x0003, 0x0040, 0x22f8, 0x1078, 0x1ba5,
+	0x2001, 0x0000, 0x703a, 0x7000, 0xa084, 0x0007, 0x0079, 0x2300,
+	0x2308, 0x230a, 0x230a, 0x2508, 0x2530, 0x24d2, 0x2308, 0x2308,
+	0x1078, 0x1ba5, 0xa684, 0x1000, 0x00c0, 0x2312, 0x1078, 0x2ec7,
+	0x0040, 0x23a3, 0x7868, 0xa08c, 0x00ff, 0x0040, 0x235a, 0xa186,
+	0x0008, 0x00c0, 0x2329, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x1078, 0x28a2, 0x0040, 0x235a, 0x1078, 0x2ec7, 0x0078,
+	0x2341, 0xa186, 0x0028, 0x00c0, 0x235a, 0x1078, 0x2ec7, 0x6008,
+	0xa084, 0xffef, 0x600a, 0x6018, 0xa005, 0x0040, 0x2341, 0x8001,
+	0x601a, 0xa005, 0x0040, 0x2341, 0x8001, 0xa005, 0x0040, 0x2341,
+	0x601e, 0x681c, 0xa084, 0x0001, 0x0040, 0x1bff, 0x681c, 0xa084,
+	0xfffe, 0x681e, 0x7054, 0x0c7e, 0x2060, 0x6800, 0x6002, 0x0c7f,
+	0x6004, 0x6802, 0xa005, 0x2d00, 0x00c0, 0x2357, 0x6002, 0x6006,
+	0x0078, 0x1bff, 0x017e, 0x1078, 0x241f, 0x017f, 0xa684, 0xdf00,
+	0x681a, 0x6827, 0x0000, 0x6f10, 0x81ff, 0x0040, 0x23a3, 0xa186,
+	0x0002, 0x00c0, 0x239b, 0xa684, 0x0800, 0x00c0, 0x2377, 0xa684,
+	0x0060, 0x0040, 0x2377, 0x78d8, 0x7adc, 0x682e, 0x6a2a, 0x8717,
+	0xa294, 0x000f, 0x8213, 0x8213, 0x8213, 0xa290, 0x3600, 0xa290,
+	0x0000, 0x221c, 0xa384, 0x0100, 0x00c0, 0x2388, 0x0078, 0x238e,
+	0x8210, 0x2204, 0xa085, 0x0018, 0x2012, 0x8211, 0xa384, 0x0400,
+	0x0040, 0x239b, 0x689c, 0xa084, 0x0100, 0x00c0, 0x239b, 0x1078,
+	0x2491, 0x0078, 0x1bff, 0xa186, 0x0018, 0x0040, 0x23a3, 0xa186,
+	0x0014, 0x0040, 0x1bff, 0x6912, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x23ab, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x1078, 0x28e0,
+	0x1078, 0x28ef, 0x00c0, 0x23b8, 0x6008, 0xa084, 0xffef, 0x600a,
+	0x681c, 0xa084, 0x0001, 0x00c0, 0x23c1, 0x1078, 0x28d9, 0x0078,
+	0x23c5, 0x7054, 0x2060, 0x6800, 0x6002, 0x1078, 0x17dd, 0x0078,
+	0x1bff, 0xa282, 0x0004, 0x0048, 0x23cf, 0x1078, 0x1ba5, 0x2200,
+	0x0079, 0x23d2, 0x23d6, 0x23d8, 0x23e5, 0x23d8, 0x1078, 0x1ba5,
+	0x7000, 0xa086, 0x0005, 0x0040, 0x23e1, 0x1078, 0x2b89, 0x781b,
+	0x0069, 0x781b, 0x006a, 0x0078, 0x1bf7, 0x7890, 0x8007, 0x8001,
+	0xa084, 0x0007, 0xa080, 0x0018, 0x789a, 0x79a8, 0xa18c, 0x00ff,
+	0xa186, 0x0003, 0x0040, 0x23f6, 0x0078, 0x2b6a, 0x781b, 0x006a,
+	0x0078, 0x1bf7, 0x681c, 0xa085, 0x0004, 0x681e, 0x82ff, 0x00c0,
+	0x2405, 0x1078, 0x2b89, 0x0078, 0x240c, 0x8211, 0x0040, 0x240a,
+	0x1078, 0x1ba5, 0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7,
+	0x1078, 0x2d77, 0x7830, 0xa084, 0x00c0, 0x00c0, 0x241c, 0x0018,
+	0x241c, 0x791a, 0xa006, 0x007c, 0xa085, 0x0001, 0x007c, 0xa684,
+	0x0060, 0x00c0, 0x2429, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078,
+	0x2490, 0xa684, 0x0800, 0x00c0, 0x2438, 0x68b0, 0xa084, 0x4800,
+	0xa635, 0xa684, 0x0800, 0x00c0, 0x2438, 0x1078, 0x2ec7, 0x007c,
+	0xa684, 0x0020, 0x0040, 0x2462, 0x78d0, 0x8003, 0x00c8, 0x2446,
+	0xa006, 0x1078, 0x3194, 0x78d4, 0x1078, 0x31f9, 0xa684, 0x4000,
+	0x0040, 0x2450, 0x682f, 0x0000, 0x682b, 0x0000, 0x0078, 0x2435,
+	0x68b0, 0xa084, 0x4800, 0xa635, 0xa684, 0x4000, 0x00c0, 0x244a,
+	0x7038, 0xa005, 0x00c0, 0x245c, 0x79d8, 0x7adc, 0x692e, 0x6a2a,
+	0x0078, 0x2435, 0xa684, 0x4000, 0x0040, 0x246c, 0x682f, 0x0000,
+	0x682b, 0x0000, 0x0078, 0x2435, 0x68b0, 0xa084, 0x4800, 0xa635,
+	0xa684, 0x4000, 0x00c0, 0x2466, 0x7038, 0xa005, 0x00c0, 0x247a,
+	0x703b, 0x0007, 0x79d8, 0x7adc, 0x78d0, 0x80f3, 0x00c8, 0x2481,
+	0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000, 0x692e, 0x6a2a,
+	0x2100, 0xa205, 0x00c0, 0x248e, 0x0078, 0x2435, 0x1078, 0x3194,
+	0x007c, 0xa384, 0x0200, 0x0040, 0x2499, 0x6008, 0xa085, 0x0002,
+	0x600a, 0x6817, 0x0006, 0x6a28, 0x692c, 0x6a3a, 0x693e, 0x682b,
+	0x0300, 0x682f, 0x0000, 0x6833, 0x2000, 0x6893, 0x0000, 0x6897,
+	0x0020, 0x7000, 0x0079, 0x24ac, 0x24b4, 0x24b6, 0x24bf, 0x24b4,
+	0x24b4, 0x24b4, 0x24b4, 0x24b4, 0x1078, 0x1ba5, 0x681c, 0xa084,
+	0x0001, 0x00c0, 0x24bf, 0x1078, 0x28d9, 0x0078, 0x24c5, 0x7054,
+	0x2c50, 0x2060, 0x6800, 0x6002, 0x2a60, 0x2021, 0x3557, 0x2404,
+	0xa005, 0x0040, 0x24ce, 0x2020, 0x0078, 0x24c7, 0x2d22, 0x206b,
+	0x0000, 0x007c, 0x77b4, 0x1078, 0x2ba6, 0xa7bc, 0x0f00, 0x1078,
+	0x2ca1, 0x6018, 0xa005, 0x0040, 0x2501, 0x0d7e, 0x2001, 0x3f90,
+	0x2068, 0x0d7f, 0x2021, 0x3f80, 0x2009, 0x0004, 0x2011, 0x0010,
+	0x1078, 0x1fc5, 0x0040, 0x2501, 0x157e, 0x20a9, 0x0000, 0x2021,
+	0x3e80, 0x047e, 0x2009, 0x0004, 0x2011, 0x0010, 0x1078, 0x1fc5,
+	0x047f, 0x0040, 0x2500, 0x8420, 0x0070, 0x2500, 0x0078, 0x24f1,
+	0x157f, 0x8738, 0xa784, 0x0007, 0x00c0, 0x24d7, 0x0078, 0x1bff,
+	0x1078, 0x28e0, 0x1078, 0x28ef, 0x6827, 0x0000, 0x789b, 0x000e,
+	0x6f10, 0x6813, 0x0002, 0x1078, 0x31ca, 0xa684, 0x0800, 0x0040,
+	0x251d, 0x6918, 0xa18d, 0x2000, 0x691a, 0x6814, 0xa084, 0x8000,
+	0x0040, 0x2524, 0x6817, 0x0000, 0x2021, 0x3557, 0x6800, 0x2022,
+	0x6a38, 0x693c, 0x6a2a, 0x692e, 0x1078, 0x17dd, 0x0078, 0x1bff,
+	0x1078, 0x241f, 0x6827, 0x0000, 0x789b, 0x000e, 0x6f10, 0x1078,
+	0x2d7c, 0xa08c, 0x00ff, 0x6912, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x2543, 0x7038, 0x6816, 0xa68c, 0xdf00, 0x691a, 0x70a3, 0x0000,
+	0x0078, 0x1bff, 0xa006, 0x1078, 0x2ec7, 0x6813, 0x0000, 0x6817,
+	0x0001, 0xa68c, 0xdf00, 0x691a, 0x6827, 0x0000, 0x7000, 0x0079,
+	0x2559, 0x2561, 0x2563, 0x2563, 0x2565, 0x2565, 0x2565, 0x2561,
+	0x2561, 0x1078, 0x1ba5, 0x1078, 0x28ef, 0x6008, 0xa084, 0xffef,
+	0x600a, 0x0078, 0x28ba, 0x2300, 0x0079, 0x256e, 0x2571, 0x2573,
+	0x25b1, 0x1078, 0x1ba5, 0x7000, 0x0079, 0x2576, 0x257e, 0x2580,
+	0x2580, 0x258b, 0x2580, 0x2592, 0x257e, 0x257e, 0x1078, 0x1ba5,
+	0xa684, 0x2000, 0x00c0, 0x258b, 0xa6b5, 0x2000, 0x7e5a, 0x1078,
+	0x30f0, 0x0078, 0x2d30, 0x6814, 0xa084, 0x8000, 0x0040, 0x2592,
+	0x6817, 0x0007, 0x2009, 0x3518, 0x210c, 0xa186, 0x0000, 0x0040,
+	0x25a7, 0xa186, 0x0001, 0x0040, 0x25ab, 0x2009, 0x352b, 0x200b,
+	0x000b, 0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, 0x1bf7, 0x781b,
+	0x00dd, 0x0078, 0x1bf7, 0x2009, 0x352b, 0x200b, 0x000a, 0x0078,
+	0x1bf7, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x25b6, 0x25b9, 0x25bb,
+	0x25de, 0x1078, 0x1ba5, 0x7000, 0x0079, 0x25be, 0x25c6, 0x25c8,
+	0x25c8, 0x25d3, 0x25c8, 0x25da, 0x25c6, 0x25c6, 0x1078, 0x1ba5,
+	0xa684, 0x2000, 0x00c0, 0x25d3, 0xa6b5, 0x2000, 0x7e5a, 0x1078,
+	0x30f0, 0x0078, 0x2d30, 0x6814, 0xa084, 0x8000, 0x0040, 0x25da,
+	0x6817, 0x0007, 0x781b, 0x00e4, 0x0078, 0x1bf7, 0x681c, 0xa085,
+	0x0004, 0x681e, 0xa6b5, 0x0800, 0x1078, 0x2b89, 0x781b, 0x0069,
+	0x0078, 0x1bf7, 0x2300, 0x0079, 0x25ed, 0x25f0, 0x25f2, 0x25f4,
+	0x1078, 0x1ba5, 0x1078, 0x1ba5, 0xa684, 0x0400, 0x00c0, 0x2613,
+	0x782b, 0x3009, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb,
+	0x785a, 0x79e4, 0xa184, 0x0020, 0x0040, 0x260b, 0x78ec, 0xa084,
+	0x0003, 0x00c0, 0x260f, 0x2001, 0x0014, 0x0078, 0x22fa, 0xa184,
+	0x0007, 0x0079, 0x264b, 0x7a90, 0xa294, 0x0007, 0x789b, 0x0060,
+	0x79a8, 0x81ff, 0x0040, 0x2649, 0x789b, 0x0010, 0x7ba8, 0xa384,
+	0x0001, 0x00c0, 0x263a, 0x7ba8, 0x7ba8, 0xa386, 0x0001, 0x00c0,
+	0x262d, 0x2009, 0xfff7, 0x0078, 0x2633, 0xa386, 0x0003, 0x00c0,
+	0x263a, 0x2009, 0xffef, 0x0c7e, 0x7048, 0x2060, 0x6004, 0xa104,
+	0x6006, 0x0c7f, 0x789b, 0x0060, 0x78ab, 0x0000, 0xa684, 0xfffb,
+	0x785a, 0x782b, 0x3009, 0x691c, 0xa18c, 0xfdff, 0xa18c, 0xfeff,
+	0x691e, 0x0078, 0x2d30, 0x2023, 0x2029, 0x2655, 0x265d, 0x2653,
+	0x2653, 0x2653, 0x2d30, 0x1078, 0x1ba5, 0x691c, 0xa18c, 0xfdff,
+	0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d38, 0x691c, 0xa18c, 0xfdff,
+	0xa18c, 0xfeff, 0x691e, 0x0078, 0x2d30, 0x79e4, 0xa184, 0x0030,
+	0x0040, 0x266f, 0x78ec, 0xa084, 0x0003, 0x00c0, 0x2677, 0x6814,
+	0xa085, 0x8000, 0x6816, 0x2001, 0x0014, 0x0078, 0x22fa, 0xa184,
+	0x0007, 0x0079, 0x267b, 0x2d30, 0x2d30, 0x2683, 0x2d30, 0x2d58,
+	0x2d58, 0x2d30, 0x2d30, 0xa684, 0x0400, 0x00c0, 0x26b4, 0x681c,
+	0xa084, 0x0001, 0x0040, 0x2d38, 0xa68c, 0x2060, 0xa18c, 0xfffb,
+	0x795a, 0x69b2, 0x789b, 0x0060, 0x78ab, 0x0000, 0x789b, 0x0061,
+	0x6814, 0xa085, 0x8000, 0x6816, 0x78aa, 0x157e, 0x137e, 0x147e,
+	0x20a1, 0x012c, 0x789b, 0x0000, 0x8000, 0x80ac, 0xad80, 0x000a,
+	0x2098, 0x53a6, 0x147f, 0x137f, 0x157f, 0x6810, 0x8007, 0x789b,
+	0x007e, 0x78aa, 0x0078, 0x2d38, 0x6814, 0xa084, 0x8000, 0x0040,
+	0x26bb, 0x6817, 0x0008, 0x781b, 0x00d8, 0x0078, 0x1bf7, 0x2300,
+	0x0079, 0x26c2, 0x26c7, 0x2742, 0x26c5, 0x1078, 0x1ba5, 0x7000,
+	0xa084, 0x0007, 0x0079, 0x26cc, 0x26d4, 0x26d6, 0x26f2, 0x26d4,
+	0x26d4, 0x24d2, 0x26d4, 0x26d4, 0x1078, 0x1ba5, 0x691c, 0xa18d,
+	0x0001, 0x691e, 0x6800, 0x6006, 0xa005, 0x00c0, 0x26e0, 0x6002,
+	0x6818, 0xa084, 0x000e, 0x0040, 0x26ec, 0x7014, 0x68b6, 0x712c,
+	0xa188, 0x3e80, 0x0078, 0x26ee, 0x2009, 0x3f80, 0x2104, 0x6802,
+	0x2d0a, 0x7156, 0x6eb2, 0xa684, 0x0060, 0x0040, 0x2740, 0xa684,
+	0x0800, 0x00c0, 0x2704, 0xa684, 0x7fff, 0x68b2, 0x6890, 0x6894,
+	0x1078, 0x2ec7, 0x0078, 0x2740, 0xa684, 0x0020, 0x0040, 0x2716,
+	0xa006, 0x1078, 0x3194, 0x78d0, 0x8003, 0x00c8, 0x2712, 0x78d4,
+	0x1078, 0x31f9, 0x79d8, 0x7adc, 0x0078, 0x271a, 0x1078, 0x2cae,
+	0x1078, 0x3194, 0xa684, 0x8000, 0x0040, 0x2740, 0xa684, 0x7fff,
+	0x68b2, 0x789b, 0x0074, 0x1078, 0x2d7c, 0x2010, 0x1078, 0x2d7c,
+	0x2008, 0xa684, 0x0020, 0x00c0, 0x2738, 0x1078, 0x2d7c, 0x801b,
+	0x00c8, 0x2733, 0x8000, 0xa084, 0x003f, 0xa108, 0xa291, 0x0000,
+	0x6b94, 0x2100, 0xa302, 0x68ae, 0x6b90, 0x2200, 0xa303, 0x68aa,
+	0x0078, 0x1bff, 0x0078, 0x2b76, 0x7033, 0x0000, 0xa282, 0x0005,
+	0x0050, 0x274c, 0x1078, 0x1ba5, 0x2300, 0x0079, 0x274f, 0x2752,
+	0x275c, 0x277f, 0x2200, 0x0079, 0x2755, 0x275a, 0x2b76, 0x275a,
+	0x27a8, 0x27f9, 0x1078, 0x1ba5, 0x7000, 0xa086, 0x0001, 0x00c0,
+	0x2769, 0x1078, 0x28ef, 0x1078, 0x2ec7, 0x7034, 0x600a, 0x0078,
+	0x276e, 0x7000, 0xa086, 0x0003, 0x0040, 0x2763, 0x7003, 0x0005,
+	0x2001, 0x3f90, 0x2068, 0x703e, 0x7032, 0x2200, 0x0079, 0x2778,
+	0x2b76, 0x277d, 0x27a8, 0x277d, 0x2b76, 0x1078, 0x1ba5, 0x7000,
+	0xa086, 0x0001, 0x00c0, 0x278c, 0x1078, 0x28ef, 0x1078, 0x2ec7,
+	0x7034, 0x600a, 0x0078, 0x2791, 0x7000, 0xa086, 0x0003, 0x0040,
+	0x2786, 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e, 0x7032,
+	0x2200, 0x0079, 0x279b, 0x27a2, 0x27a0, 0x27a2, 0x27a0, 0x27a2,
+	0x1078, 0x1ba5, 0x1078, 0x2b99, 0x781b, 0x0069, 0x0078, 0x1bf7,
+	0x7000, 0xa086, 0x0001, 0x00c0, 0x27b5, 0x1078, 0x28ef, 0x1078,
+	0x2ec7, 0x7034, 0x600a, 0x0078, 0x27ba, 0x7000, 0xa086, 0x0003,
+	0x0040, 0x27af, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00, 0x789b,
+	0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x2069, 0x3f80, 0x2d04,
+	0x2d08, 0x7156, 0x2068, 0xa005, 0x0040, 0x27d5, 0x6810, 0xa206,
+	0x0040, 0x27ee, 0x6800, 0x0078, 0x27c8, 0x7003, 0x0005, 0x2001,
+	0x3f90, 0x2068, 0x703e, 0x7032, 0x157e, 0x20a9, 0x002f, 0x2003,
+	0x0000, 0x8000, 0x0070, 0x27e6, 0x0078, 0x27df, 0x157f, 0x6a12,
+	0x68b3, 0x0700, 0x681f, 0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a,
+	0x681c, 0xa084, 0x0c00, 0x0040, 0x284f, 0x1078, 0x2b91, 0x0078,
+	0x284f, 0x7000, 0xa086, 0x0001, 0x00c0, 0x2806, 0x1078, 0x28ef,
+	0x1078, 0x2ec7, 0x7034, 0x600a, 0x0078, 0x280b, 0x7000, 0xa086,
+	0x0003, 0x0040, 0x2800, 0x7003, 0x0002, 0x7a80, 0xa294, 0x0f00,
+	0x789b, 0x0018, 0x7ca8, 0xa484, 0x0007, 0xa215, 0x79a8, 0x79a8,
+	0xa18c, 0x00ff, 0xa1e8, 0x3e80, 0x2d04, 0x2d08, 0x7156, 0x2068,
+	0xa005, 0x0040, 0x282a, 0x6810, 0xa206, 0x0040, 0x2843, 0x6800,
+	0x0078, 0x281d, 0x7003, 0x0005, 0x2001, 0x3f90, 0x2068, 0x703e,
+	0x7032, 0x157e, 0x20a9, 0x002f, 0x2003, 0x0000, 0x8000, 0x0070,
+	0x283b, 0x0078, 0x2834, 0x157f, 0x6a12, 0x68b3, 0x0700, 0x681f,
+	0x0800, 0x6823, 0x0003, 0x6eb0, 0x7e5a, 0x681c, 0xa084, 0x0c00,
+	0x0040, 0x284f, 0x1078, 0x2b8d, 0x7e58, 0x0078, 0x284f, 0x027e,
+	0x8207, 0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600,
+	0x2060, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0xa684, 0x0060,
+	0x0040, 0x2886, 0x6b94, 0x6c90, 0x69a8, 0x68ac, 0xa105, 0x00c0,
+	0x2874, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde, 0xa6b4, 0xb7ff, 0x7e5a,
+	0x1078, 0x30f0, 0x0078, 0x2886, 0x68ac, 0xa31a, 0x2100, 0xa423,
+	0x2400, 0xa305, 0x0040, 0x2886, 0x7bd2, 0x7bda, 0x7cd6, 0x7cde,
+	0x68ac, 0xa6b4, 0xbfff, 0x7e5a, 0x1078, 0x311d, 0x077f, 0x1078,
+	0x2ca1, 0x2009, 0x006a, 0xa684, 0x0008, 0x0040, 0x2891, 0x2009,
+	0x0069, 0xa6b5, 0x2000, 0x7e5a, 0x791a, 0x2d00, 0x703e, 0x8207,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2048,
+	0x0078, 0x1bf7, 0x6020, 0xa005, 0x0040, 0x28ae, 0x8001, 0x6022,
+	0x6008, 0xa085, 0x0008, 0x600a, 0x7010, 0x6026, 0x007c, 0xa006,
+	0x1078, 0x2ec7, 0x6813, 0x0000, 0x6817, 0x0001, 0x681f, 0x0040,
+	0x681b, 0x0100, 0x7000, 0xa084, 0x0007, 0x0079, 0x28bf, 0x28c7,
+	0x28c9, 0x28c9, 0x28d5, 0x28d1, 0x28c7, 0x28c7, 0x28c7, 0x1078,
+	0x1ba5, 0x1078, 0x28e0, 0x1078, 0x28d9, 0x1078, 0x17dd, 0x0078,
+	0x1bff, 0x70a3, 0x0000, 0x0078, 0x1bff, 0x6817, 0x0000, 0x0078,
+	0x2508, 0x6800, 0xa005, 0x00c0, 0x28de, 0x6002, 0x6006, 0x007c,
+	0x6010, 0xa005, 0x0040, 0x28e9, 0x8001, 0x00d0, 0x28e9, 0x1078,
+	0x1ba5, 0x6012, 0x6008, 0xa084, 0xffef, 0x600a, 0x007c, 0x6018,
+	0xa005, 0x0040, 0x28f5, 0x8001, 0x601a, 0x007c, 0x1078, 0x2d77,
+	0x6817, 0x0018, 0x0078, 0x2926, 0x1078, 0x2d77, 0x6817, 0x0019,
+	0x0078, 0x2926, 0x1078, 0x2d77, 0x6817, 0x001a, 0x0078, 0x2926,
+	0x77b4, 0x1078, 0x2ca1, 0x71b8, 0xa18c, 0x00ff, 0xa1e8, 0x3e80,
+	0x2d04, 0x2d08, 0x2068, 0xa005, 0x00c0, 0x2918, 0x0078, 0x1bff,
+	0x6810, 0x72b4, 0xa206, 0x0040, 0x2920, 0x6800, 0x0078, 0x2911,
+	0x6800, 0x200a, 0x6817, 0x0005, 0x70bf, 0x0000, 0x1078, 0x28e0,
+	0x681c, 0xa084, 0x0001, 0x00c0, 0x292f, 0x1078, 0x28d9, 0x1078,
+	0x28ef, 0x681b, 0x0000, 0x681f, 0x0020, 0x1078, 0x17dd, 0x0078,
+	0x1bff, 0xa282, 0x0003, 0x00c0, 0x2b6a, 0x7da8, 0xa5ac, 0x00ff,
+	0x7ea8, 0xa6b4, 0x00ff, 0x691c, 0xa18d, 0x0080, 0x691e, 0xa184,
+	0x0100, 0x0040, 0x2999, 0xa18c, 0xfeff, 0x691e, 0xa6b4, 0x00ff,
+	0x0040, 0x2983, 0xa682, 0x000f, 0x0048, 0x295a, 0x0040, 0x295a,
+	0x2031, 0x000f, 0x852b, 0x852b, 0x1078, 0x2c24, 0x0040, 0x2964,
+	0x1078, 0x2a33, 0x0078, 0x298c, 0x1078, 0x2bdf, 0x0c7e, 0x2960,
+	0x6004, 0xa084, 0xfff5, 0x6006, 0x1078, 0x2a57, 0x0c7f, 0x691c,
+	0xa18d, 0x0100, 0x691e, 0x7e58, 0xa6b5, 0x0004, 0x7e5a, 0xa684,
+	0x0400, 0x00c0, 0x297f, 0x781b, 0x0055, 0x0078, 0x1bf7, 0x781b,
+	0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x2960, 0x6004, 0xa084, 0xfff5,
+	0x6006, 0x1078, 0x2a57, 0x0c7f, 0x7e58, 0xa684, 0x0400, 0x00c0,
+	0x2995, 0x781b, 0x0058, 0x0078, 0x1bf7, 0x781b, 0x006a, 0x0078,
+	0x1bf7, 0x0c7e, 0x7048, 0x2060, 0x6100, 0xa18c, 0x1000, 0x0040,
+	0x29d9, 0x6208, 0x8217, 0xa294, 0x00ff, 0xa282, 0x000f, 0x0048,
+	0x29ad, 0x0040, 0x29ad, 0x2011, 0x000f, 0x2600, 0xa202, 0x00c8,
+	0x29b2, 0x2230, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028,
+	0x00c0, 0x29c2, 0xa282, 0x0019, 0x00c8, 0x29c8, 0x2011, 0x0019,
+	0x0078, 0x29c8, 0xa282, 0x000c, 0x00c8, 0x29c8, 0x2011, 0x000c,
+	0x2200, 0xa502, 0x00c8, 0x29cd, 0x2228, 0x1078, 0x2be3, 0x852b,
+	0x852b, 0x1078, 0x2c24, 0x0040, 0x29d9, 0x1078, 0x2a33, 0x0078,
+	0x29dd, 0x1078, 0x2bdf, 0x1078, 0x2a57, 0x7858, 0xa085, 0x0004,
+	0x785a, 0x0c7f, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x2960,
+	0x6000, 0xa084, 0x1000, 0x00c0, 0x2a01, 0x6010, 0xa084, 0x000f,
+	0x00c0, 0x29fb, 0xa18c, 0x0002, 0x00c0, 0x29fb, 0xa18c, 0xfff5,
+	0x6106, 0x0c7f, 0x007c, 0x2011, 0x0032, 0x2019, 0x0000, 0x0078,
+	0x2a23, 0x6208, 0xa294, 0x00ff, 0x7018, 0xa086, 0x0028, 0x00c0,
+	0x2a11, 0xa282, 0x0019, 0x00c8, 0x2a17, 0x2011, 0x0019, 0x0078,
+	0x2a17, 0xa282, 0x000c, 0x00c8, 0x2a17, 0x2011, 0x000c, 0x6308,
+	0x831f, 0xa39c, 0x00ff, 0xa382, 0x000f, 0x0048, 0x2a23, 0x0040,
+	0x2a23, 0x2019, 0x000f, 0x78ab, 0x0001, 0x78ab, 0x0003, 0x78ab,
+	0x0001, 0x7aaa, 0x7baa, 0xa8c0, 0x0005, 0x681c, 0xa085, 0x0100,
+	0x681e, 0x0c7f, 0x007c, 0x0c7e, 0x7148, 0x2160, 0x2008, 0xa084,
+	0xfff0, 0xa635, 0x7e86, 0x6018, 0x789a, 0x7eae, 0x6612, 0x78a4,
+	0xa084, 0xfff8, 0xa18c, 0x0007, 0xa105, 0x78a6, 0x6016, 0x788a,
+	0xa6b4, 0x000f, 0x8637, 0x8204, 0x8004, 0xa084, 0x00ff, 0xa605,
+	0x600e, 0x6004, 0xa084, 0xfff5, 0x6006, 0x0c7f, 0x007c, 0x0c7e,
+	0x7048, 0x2060, 0x6018, 0x789a, 0x78a4, 0xa084, 0xfff0, 0x78a6,
+	0x6012, 0x7884, 0xa084, 0xfff0, 0x7886, 0x0c7f, 0x007c, 0xa282,
+	0x0002, 0x00c0, 0x2b6a, 0x7aa8, 0x691c, 0xa18d, 0x0080, 0x691e,
+	0xa184, 0x0200, 0x0040, 0x2aac, 0xa18c, 0xfdff, 0x691e, 0xa294,
+	0x00ff, 0xa282, 0x0002, 0x00c8, 0x2b6a, 0x1078, 0x2af3, 0x1078,
+	0x2a57, 0xa980, 0x0001, 0x200c, 0x1078, 0x2c9d, 0x1078, 0x29e6,
+	0x88ff, 0x0040, 0x2a9f, 0x789b, 0x0060, 0x2800, 0x78aa, 0x7e58,
+	0xa6b5, 0x0004, 0x7e5a, 0xa684, 0x0400, 0x00c0, 0x2a9b, 0x781b,
+	0x0055, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x7e58,
+	0xa684, 0x0400, 0x00c0, 0x2aa8, 0x781b, 0x0058, 0x0078, 0x1bf7,
+	0x781b, 0x006a, 0x0078, 0x1bf7, 0xa282, 0x0002, 0x00c8, 0x2ab4,
+	0xa284, 0x0001, 0x0040, 0x2abe, 0x7148, 0xa188, 0x0000, 0x210c,
+	0xa18c, 0x2000, 0x00c0, 0x2abe, 0x2011, 0x0000, 0x1078, 0x2bd1,
+	0x1078, 0x2af3, 0x1078, 0x2a57, 0x7858, 0xa085, 0x0004, 0x785a,
+	0x781b, 0x0069, 0x0078, 0x1bf7, 0x0c7e, 0x027e, 0x2960, 0x6000,
+	0x2011, 0x0001, 0xa084, 0x2000, 0x00c0, 0x2ae3, 0x6014, 0xa084,
+	0x0040, 0x00c0, 0x2ae1, 0xa18c, 0xffef, 0x6106, 0xa006, 0x0078,
+	0x2af0, 0x2011, 0x0000, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+	0x0003, 0x7aaa, 0xa8c0, 0x0004, 0x681c, 0xa085, 0x0200, 0x681e,
+	0x027f, 0x0c7f, 0x007c, 0x0c7e, 0x7048, 0x2060, 0x82ff, 0x0040,
+	0x2afb, 0x2011, 0x0040, 0x6018, 0xa080, 0x0002, 0x789a, 0x78a4,
+	0xa084, 0xffbf, 0xa205, 0x78a6, 0x6016, 0x788a, 0x6004, 0xa084,
+	0xffef, 0x6006, 0x0c7f, 0x007c, 0x007e, 0x7000, 0xa086, 0x0003,
+	0x0040, 0x2b15, 0x007f, 0x0078, 0x2b18, 0x007f, 0x0078, 0x2b66,
+	0xa684, 0x0020, 0x0040, 0x2b66, 0x7888, 0xa084, 0x0040, 0x0040,
+	0x2b66, 0x78a8, 0x8001, 0x0040, 0x2b25, 0x7bb8, 0xa384, 0x003f,
+	0x831b, 0x00c8, 0x2b2c, 0x8000, 0xa005, 0x0040, 0x2b4d, 0x831b,
+	0x00c8, 0x2b35, 0x8001, 0x0040, 0x2b62, 0xa006, 0x1078, 0x3194,
+	0x78b4, 0x1078, 0x31f9, 0x0078, 0x2b66, 0xa684, 0x4000, 0x0040,
+	0x2b4d, 0x78b8, 0x801b, 0x00c8, 0x2b46, 0x8000, 0xa084, 0x003f,
+	0x00c0, 0x2b62, 0xa6b4, 0xbfff, 0x7e5a, 0x79d8, 0x7adc, 0x2001,
+	0x0001, 0xa108, 0x00c8, 0x2b56, 0xa291, 0x0000, 0x79d2, 0x79da,
+	0x7ad6, 0x7ade, 0x1078, 0x3194, 0x781b, 0x0067, 0x1078, 0x305e,
+	0x0078, 0x1bf7, 0x781b, 0x0067, 0x0078, 0x1bf7, 0x781b, 0x006a,
+	0x0078, 0x1bf7, 0x1078, 0x2b9d, 0x781b, 0x0069, 0x0078, 0x1bf7,
+	0x1078, 0x2b89, 0x781b, 0x0069, 0x0078, 0x1bf7, 0x6823, 0x0002,
+	0x1078, 0x2b91, 0x691c, 0xa18d, 0x0020, 0x691e, 0x6814, 0xa084,
+	0x8000, 0x0040, 0x2b85, 0x6817, 0x0005, 0x781b, 0x0069, 0x0078,
+	0x1bf7, 0x2001, 0x0005, 0x0078, 0x2b9f, 0x2001, 0x000c, 0x0078,
+	0x2b9f, 0x2001, 0x0006, 0x0078, 0x2b9f, 0x2001, 0x000d, 0x0078,
+	0x2b9f, 0x2001, 0x0009, 0x0078, 0x2b9f, 0x2001, 0x0007, 0x789b,
+	0x007f, 0x78aa, 0xa6b5, 0x0008, 0x7e5a, 0x007c, 0x077e, 0x873f,
+	0xa7bc, 0x000f, 0x873b, 0x873b, 0x8703, 0xa0e0, 0x3600, 0xa7b8,
+	0x0020, 0x7f9a, 0x79a4, 0xa184, 0x000f, 0x0040, 0x2bbf, 0xa184,
+	0xfff0, 0x78a6, 0x6012, 0x6004, 0xa085, 0x0008, 0x6006, 0x8738,
+	0x8738, 0x7f9a, 0x79a4, 0xa184, 0x0040, 0x0040, 0x2bcf, 0xa184,
+	0xffbf, 0x78a6, 0x6016, 0x6004, 0xa085, 0x0010, 0x6006, 0x077f,
+	0x007c, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab, 0x0002, 0x78ab,
+	0x0003, 0x7aaa, 0x789b, 0x0060, 0x78ab, 0x0004, 0x007c, 0x2031,
+	0x0000, 0x2029, 0x0032, 0x789b, 0x0010, 0x78ab, 0x0001, 0x78ab,
+	0x0003, 0x78ab, 0x0001, 0x7daa, 0x7eaa, 0x789b, 0x0060, 0x78ab,
+	0x0005, 0x007c, 0x157e, 0x8007, 0xa084, 0x00ff, 0x8003, 0x8003,
+	0xa080, 0x0020, 0x789a, 0x79a4, 0xa18c, 0xfff0, 0x2001, 0x3546,
+	0x2004, 0xa082, 0x0028, 0x0040, 0x2c0d, 0x2021, 0x2c84, 0x2019,
+	0x0014, 0x20a9, 0x000c, 0x0078, 0x2c13, 0x2021, 0x2c90, 0x2019,
+	0x0019, 0x20a9, 0x000d, 0x2011, 0x0064, 0x2404, 0xa084, 0xfff0,
+	0xa106, 0x0040, 0x2c22, 0x8420, 0x2300, 0xa210, 0x0070, 0x2c22,
+	0x0078, 0x2c15, 0x157f, 0x007c, 0x157e, 0x2011, 0x3546, 0x2214,
+	0xa282, 0x0032, 0x0048, 0x2c38, 0x0040, 0x2c3c, 0x2021, 0x2c76,
+	0x2019, 0x0011, 0x20a9, 0x000e, 0x2011, 0x0032, 0x0078, 0x2c4c,
+	0xa282, 0x0028, 0x0040, 0x2c44, 0x2021, 0x2c84, 0x2019, 0x0014,
+	0x20a9, 0x000c, 0x0078, 0x2c4a, 0x2021, 0x2c90, 0x2019, 0x0019,
+	0x20a9, 0x000d, 0x2011, 0x0064, 0x2200, 0xa502, 0x0040, 0x2c5c,
+	0x0048, 0x2c5c, 0x8420, 0x2300, 0xa210, 0x0070, 0x2c59, 0x0078,
+	0x2c4c, 0x157f, 0xa006, 0x007c, 0x157f, 0xa582, 0x0064, 0x00c8,
+	0x2c65, 0x7808, 0xa085, 0x0070, 0x780a, 0x78ec, 0xa084, 0x0300,
+	0x0040, 0x2c73, 0x2404, 0xa09e, 0x1201, 0x00c0, 0x2c73, 0x2001,
+	0x2101, 0x0078, 0x2c74, 0x2404, 0xa005, 0x007c, 0x1201, 0x3002,
+	0x3202, 0x4203, 0x4403, 0x5404, 0x5604, 0x6605, 0x6805, 0x7806,
+	0x7a06, 0x0a07, 0x0c07, 0x0e07, 0x3202, 0x4202, 0x5202, 0x6202,
+	0x7202, 0x6605, 0x7605, 0x7805, 0x7a05, 0x7c05, 0x7e05, 0x7f05,
+	0x2202, 0x3202, 0x4202, 0x5202, 0x5404, 0x6404, 0x7404, 0x7604,
+	0x7804, 0x7a04, 0x7c04, 0x7e04, 0x7f04, 0x789b, 0x0010, 0xa046,
+	0x007c, 0xa784, 0x0f00, 0x800c, 0xa784, 0x0007, 0x8003, 0x8003,
+	0x8003, 0x8003, 0xa105, 0xa0e0, 0x3680, 0x007c, 0x79d8, 0x7adc,
+	0x78d0, 0x801b, 0x00c8, 0x2cb5, 0x8000, 0xa084, 0x003f, 0xa108,
+	0xa291, 0x0000, 0x007c, 0x0f7e, 0x2079, 0x0100, 0x2009, 0x3540,
+	0x2091, 0x8000, 0x2104, 0x0079, 0x2cc5, 0x2cf7, 0x2ccf, 0x2ccf,
+	0x2ccf, 0x2ccf, 0x2ccf, 0x2ccd, 0x2ccd, 0x1078, 0x1ba5, 0x784b,
+	0x0004, 0x7848, 0xa084, 0x0004, 0x00c0, 0x2cd1, 0x784b, 0x0008,
+	0x7848, 0xa084, 0x0008, 0x00c0, 0x2cd8, 0x68b0, 0xa085, 0x4000,
+	0x68b2, 0x7858, 0xa085, 0x4000, 0x785a, 0x7830, 0xa084, 0x0080,
+	0x00c0, 0x2cf7, 0x0018, 0x2cf7, 0x6818, 0xa084, 0x0020, 0x00c0,
+	0x2cf5, 0x781b, 0x00dd, 0x0078, 0x2cf7, 0x781b, 0x00e4, 0x2091,
+	0x8001, 0x0f7f, 0x007c, 0x0c7e, 0x6810, 0x8007, 0xa084, 0x000f,
+	0x8003, 0x8003, 0x8003, 0xa0e0, 0x3600, 0x6004, 0xa084, 0x000a,
+	0x00c0, 0x2d2e, 0x6108, 0xa194, 0xff00, 0x0040, 0x2d2e, 0xa18c,
+	0x00ff, 0x2001, 0x0019, 0xa106, 0x0040, 0x2d1d, 0x2001, 0x0032,
+	0xa106, 0x0040, 0x2d21, 0x0078, 0x2d25, 0x2009, 0x0020, 0x0078,
+	0x2d27, 0x2009, 0x003f, 0x0078, 0x2d27, 0x2011, 0x0000, 0x2100,
+	0xa205, 0x600a, 0x6004, 0xa085, 0x0002, 0x6006, 0x0c7f, 0x007c,
+	0x781b, 0x006a, 0x0078, 0x1bf7, 0x781b, 0x0069, 0x0078, 0x1bf7,
+	0x781b, 0x0058, 0x0078, 0x1bf7, 0x781b, 0x0055, 0x0078, 0x1bf7,
+	0x781b, 0x00dd, 0x0078, 0x1bf7, 0x781b, 0x00dc, 0x0078, 0x1bf7,
+	0x781b, 0x00e4, 0x0078, 0x1bf7, 0x781b, 0x00e3, 0x0078, 0x1bf7,
+	0x781b, 0x009e, 0x0078, 0x1bf7, 0x781b, 0x009d, 0x0078, 0x1bf7,
+	0x70a3, 0x0001, 0x781b, 0x0046, 0x0078, 0x1bf7, 0x007e, 0x7830,
+	0xa084, 0x00c0, 0x00c0, 0x2d75, 0x7808, 0xa084, 0xfffd, 0x780a,
+	0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021, 0x0040,
+	0x2d75, 0x7808, 0xa085, 0x0002, 0x780a, 0x007f, 0x007c, 0x7808,
+	0xa085, 0x0002, 0x780a, 0x007c, 0x7830, 0xa084, 0x0040, 0x00c0,
+	0x2d7c, 0x0098, 0x2d85, 0x78ac, 0x007c, 0x7808, 0xa084, 0xfffd,
+	0x780a, 0x0005, 0x0005, 0x0005, 0x0005, 0x78ec, 0xa084, 0x0021,
+	0x0040, 0x2d94, 0x0098, 0x2d92, 0x78ac, 0x007e, 0x7808, 0xa085,
+	0x0002, 0x780a, 0x007f, 0x007c, 0xa784, 0x0070, 0x0040, 0x2da8,
+	0x0c7e, 0x2d60, 0x2f68, 0x1078, 0x1b6b, 0x2d78, 0x2c68, 0x0c7f,
+	0x6817, 0x0003, 0x7858, 0xa084, 0x3f00, 0x681a, 0x682f, 0x0000,
+	0x682b, 0x0000, 0x784b, 0x0008, 0x78e4, 0xa005, 0x00d0, 0x2015,
+	0xa084, 0x0020, 0x0040, 0x2015, 0x78ec, 0xa084, 0x0003, 0x0040,
+	0x2015, 0x0018, 0x2015, 0x0078, 0x2b70, 0x0c7e, 0x6810, 0x8007,
+	0xa084, 0x000f, 0x8003, 0x8003, 0x8003, 0xa080, 0x3600, 0x2060,
+	0x2048, 0x704a, 0x6000, 0x704e, 0x6004, 0x7052, 0x0c7f, 0x007c,
+	0x0020, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020, 0x0000, 0x0020,
+	0x0000, 0x0020, 0x0062, 0x0009, 0x0014, 0x0014, 0x9847, 0x0014,
+	0x0014, 0x98f5, 0x98e7, 0x0014, 0x0014, 0x0080, 0x00bf, 0x0100,
+	0x0402, 0x2008, 0xf880, 0xa20a, 0x0014, 0x300b, 0xa20c, 0x0014,
+	0xa200, 0x8838, 0x817e, 0x842a, 0x84a0, 0x3806, 0x8839, 0x28c2,
+	0x9cc3, 0xa805, 0x0864, 0xa83b, 0x3008, 0x28c1, 0x9cc3, 0xa201,
+	0x300c, 0x2847, 0x8161, 0x846a, 0x8000, 0x84a4, 0x1856, 0x883a,
+	0xa808, 0x28e2, 0x9ca0, 0xa8f3, 0x0864, 0xa829, 0x300c, 0xa801,
+	0x3008, 0x28e1, 0x9ca0, 0x280d, 0xa204, 0x64c0, 0x67a0, 0x6fc0,
+	0x1814, 0x883b, 0x7023, 0x8576, 0x8677, 0xa80f, 0x786e, 0x883e,
+	0xa80c, 0x282b, 0xa205, 0x64a0, 0x67a0, 0x6fc0, 0x1814, 0x883b,
+	0x7023, 0x8576, 0x8677, 0xa801, 0x883e, 0x2069, 0x28c1, 0x9cc3,
+	0x2044, 0x2103, 0x20a2, 0x2081, 0xa8dc, 0xa207, 0x0014, 0xa203,
+	0x8000, 0x84a8, 0x85a4, 0x1872, 0x849a, 0x883c, 0x1fe2, 0xf601,
+	0xa208, 0x856e, 0x866f, 0x0704, 0x3008, 0x9ca0, 0x0014, 0xa202,
+	0x8000, 0x85a4, 0x3009, 0x84a8, 0x19e2, 0xf848, 0x8174, 0x86eb,
+	0x85eb, 0x872e, 0x87a9, 0x883f, 0x08e6, 0xa8f1, 0xf861, 0xa8e8,
+	0xf801, 0x0014, 0xf881, 0x0016, 0x85b2, 0x80f0, 0x9532, 0xfaa2,
+	0x1de2, 0x0014, 0x8532, 0xf221, 0x0014, 0x1de2, 0x84a8, 0xd6e0,
+	0x1fe6, 0x0014, 0xa206, 0x6865, 0x817f, 0x842a, 0x1dc1, 0x8823,
+	0x0016, 0x6042, 0x8008, 0xa8fa, 0x8000, 0x84a4, 0x8160, 0x842a,
+	0xf021, 0x3008, 0x84a8, 0x1dc6, 0x20d7, 0x8822, 0x0016, 0x8000,
+	0x2848, 0x1011, 0xa8fc, 0x3008, 0x8000, 0xa000, 0x2802, 0x1011,
+	0xa8fd, 0xa887, 0x3008, 0x283d, 0x1011, 0xa8fd, 0xa209, 0x0017,
+	0x300c, 0x8000, 0x85a4, 0x1de2, 0xdac1, 0x0014, 0x26e0, 0x873a,
+	0xfaa2, 0x19f2, 0x1fe2, 0x0014, 0xa20b, 0x0014, 0xa20d, 0x817e,
+	0x842a, 0x84a0, 0x3806, 0x0210, 0x9ccd, 0x0704, 0x0000, 0x127e,
+	0x2091, 0x2200, 0x2049, 0x2ec7, 0x7000, 0x7204, 0xa205, 0x720c,
+	0xa215, 0x7008, 0xa084, 0xfffd, 0xa205, 0x0040, 0x2ed9, 0x0078,
+	0x2ede, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c, 0x7000, 0xa084,
+	0x0001, 0x00c0, 0x2f0c, 0x7108, 0x8104, 0x00c8, 0x2eeb, 0x1078,
+	0x2fa8, 0x0078, 0x2ee3, 0x700c, 0xa08c, 0x007f, 0x0040, 0x2f0c,
+	0x7004, 0x8004, 0x00c8, 0x2f03, 0x7014, 0xa005, 0x00c0, 0x2eff,
+	0x7010, 0xa005, 0x0040, 0x2f03, 0xa102, 0x00c8, 0x2ee3, 0x7007,
+	0x0010, 0x0078, 0x2f0c, 0x8aff, 0x0040, 0x2f0c, 0x1078, 0x316b,
+	0x00c0, 0x2f06, 0x0040, 0x2ee3, 0x1078, 0x2f56, 0x7003, 0x0000,
+	0x127f, 0x2000, 0x007c, 0x6424, 0x84ff, 0x0040, 0x2f30, 0x2c70,
+	0x2039, 0x2f35, 0x2704, 0xae68, 0x680c, 0xa630, 0x6808, 0xa529,
+	0x8421, 0x0040, 0x2f30, 0x8738, 0x2704, 0xa005, 0x00c0, 0x2f1b,
+	0x7098, 0xa075, 0x0040, 0x2f30, 0x2039, 0x2f32, 0x0078, 0x2f1a,
+	0x007c, 0x0000, 0x0004, 0x0008, 0x000c, 0x0010, 0x0014, 0x0018,
+	0x001c, 0x0000, 0x127e, 0x2091, 0x2200, 0x2079, 0x3500, 0x2071,
+	0x0010, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2071,
+	0x0020, 0x7007, 0x000a, 0x7007, 0x0002, 0x7003, 0x0000, 0x2049,
+	0x0000, 0x78b3, 0x0000, 0x127f, 0x2000, 0x007c, 0x2049, 0x2f56,
+	0x7004, 0x8004, 0x00c8, 0x2f82, 0x7007, 0x0012, 0x7108, 0x7008,
+	0xa106, 0x00c0, 0x2f5e, 0xa184, 0x0030, 0x0040, 0x2f6b, 0xa086,
+	0x0030, 0x00c0, 0x2f5e, 0x7000, 0xa084, 0x0001, 0x00c0, 0x2f82,
+	0x7008, 0xa084, 0x000c, 0x00c0, 0x2f80, 0x710c, 0xa184, 0x0300,
+	0x00c0, 0x2f80, 0xa184, 0x007f, 0x00c0, 0x2f56, 0x0078, 0x2f82,
+	0x6817, 0x0003, 0x7007, 0x0012, 0x7007, 0x0008, 0x7004, 0xa084,
+	0x0008, 0x00c0, 0x2f86, 0x7007, 0x0012, 0x7108, 0x8104, 0x0048,
+	0x2f8b, 0x78b3, 0x0000, 0x7003, 0x0000, 0x2049, 0x0000, 0x007c,
+	0x107e, 0x007e, 0x127e, 0x157e, 0x2091, 0x2200, 0x7108, 0x1078,
+	0x2fa8, 0x157f, 0x127f, 0x2091, 0x8001, 0x007f, 0x107f, 0x007c,
+	0x7204, 0x2118, 0x7108, 0x700c, 0xa084, 0x0300, 0x00c0, 0x2fea,
+	0xa184, 0x000c, 0x00c0, 0x2fea, 0x8213, 0x8213, 0x8213, 0x8213,
+	0xa284, 0x0100, 0xa10d, 0x810b, 0x810b, 0x810f, 0xa184, 0x0007,
+	0x0079, 0x2fc2, 0x2fcc, 0x2fdc, 0x2fea, 0x2fdc, 0x2ffe, 0x2ffe,
+	0x2fea, 0x2ffc, 0x1078, 0x1ba5, 0x7007, 0x0002, 0x8aff, 0x00c0,
+	0x2fd5, 0x2049, 0x0000, 0x0078, 0x2fd9, 0x1078, 0x316b, 0x00c0,
+	0x2fd5, 0x78b3, 0x0000, 0x007c, 0x7007, 0x0002, 0x8aff, 0x00c0,
+	0x2fe3, 0x0078, 0x2fe7, 0x1078, 0x316b, 0x00c0, 0x2fe3, 0x78b3,
+	0x0000, 0x007c, 0x7007, 0x0002, 0x1078, 0x2f56, 0x1078, 0x2cbb,
+	0x6814, 0xa084, 0x8000, 0x0040, 0x2ff7, 0x6817, 0x0002, 0x007c,
+	0x1078, 0x1ba5, 0x1078, 0x1ba5, 0x1078, 0x3050, 0x7210, 0x7114,
+	0x700c, 0xa09c, 0x007f, 0x2800, 0xa300, 0xa211, 0xa189, 0x0000,
+	0x78b0, 0xa005, 0x0040, 0x3010, 0x78b3, 0x0000, 0x0078, 0x3033,
+	0x1078, 0x3050, 0x2704, 0x2c58, 0xac60, 0x630c, 0x2200, 0xa322,
+	0x6308, 0x2100, 0xa31b, 0x2400, 0xa305, 0x0040, 0x3029, 0x00c8,
+	0x3029, 0x8412, 0x8210, 0x830a, 0xa189, 0x0000, 0x2b60, 0x0078,
+	0x3010, 0x2b60, 0x8a07, 0xa7ba, 0x2f32, 0xa73d, 0x2c00, 0x6882,
+	0x6f86, 0x6c8e, 0x6b8a, 0x7007, 0x0012, 0x1078, 0x2f56, 0x007c,
+	0x8738, 0x2704, 0xa005, 0x00c0, 0x3044, 0x6098, 0xa005, 0x0040,
+	0x304d, 0x2060, 0x2039, 0x2f32, 0x8a51, 0x0040, 0x304c, 0x7008,
+	0xa084, 0x00c0, 0xa086, 0x00c0, 0x007c, 0x2051, 0x0000, 0x007c,
+	0x8a50, 0x8739, 0x2704, 0xa004, 0x00c0, 0x305d, 0x2039, 0x2f38,
+	0x6000, 0xa064, 0x00c0, 0x305d, 0x2d60, 0x007c, 0x127e, 0x0d7e,
+	0x2091, 0x2200, 0x0d7f, 0x6880, 0x2060, 0x6884, 0x6b88, 0x6c8c,
+	0x8057, 0xaad4, 0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2f32, 0x7e08,
+	0xa6b5, 0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x3079, 0xa6b5,
+	0x0001, 0x0f7e, 0x2079, 0x0100, 0x7858, 0x0f7f, 0xa084, 0x0040,
+	0x0040, 0x3088, 0xa684, 0x0001, 0x00c0, 0x3088, 0xa6b5, 0x0001,
+	0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x308a, 0x7000,
+	0xa005, 0x0040, 0x3095, 0x1078, 0x1ba5, 0x2400, 0xa305, 0x00c0,
+	0x309b, 0x0078, 0x30d8, 0x2c58, 0x2704, 0xac60, 0x6004, 0xa400,
+	0x007e, 0x701a, 0x6000, 0xa301, 0x701e, 0x2009, 0x04fd, 0x2104,
+	0xa086, 0x04fd, 0x007f, 0x00c0, 0x30c8, 0xa084, 0x0001, 0x0040,
+	0x30c8, 0xa684, 0x0001, 0x00c0, 0x30c8, 0x7013, 0x0001, 0x7017,
+	0x0000, 0x7602, 0x7007, 0x0001, 0x78b3, 0x0001, 0xa4a0, 0x0001,
+	0xa399, 0x0000, 0x6004, 0xa400, 0x701a, 0x6000, 0xa301, 0x701e,
+	0x620c, 0x2400, 0xa202, 0x7012, 0x6208, 0x2300, 0xa203, 0x7016,
+	0x7602, 0x7007, 0x0001, 0x2b60, 0x1078, 0x3038, 0x0078, 0x30da,
+	0x1078, 0x316b, 0x00c0, 0x30d8, 0x127f, 0x2000, 0x007c, 0x127e,
+	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x7007, 0x0004, 0x7004, 0xa084,
+	0x0004, 0x00c0, 0x30e6, 0x7003, 0x0008, 0x127f, 0x2000, 0x007c,
+	0x127e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049, 0x30f0, 0x7007,
+	0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x30f9, 0x7000, 0xa005,
+	0x0040, 0x3104, 0x1078, 0x1ba5, 0x7e08, 0xa6b5, 0x000c, 0x6818,
+	0xa084, 0x0040, 0x0040, 0x310e, 0xa6b5, 0x0001, 0x6824, 0xa005,
+	0x0040, 0x311a, 0x2050, 0x2039, 0x2f35, 0x2d60, 0x1078, 0x316b,
+	0x00c0, 0x3116, 0x127f, 0x2000, 0x007c, 0x127e, 0x007e, 0x017e,
+	0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x037f, 0x047f, 0x7e08, 0xa6b5,
+	0x000c, 0x6818, 0xa084, 0x0040, 0x0040, 0x3130, 0xa6b5, 0x0001,
+	0x2049, 0x311d, 0x6824, 0xa055, 0x0040, 0x3168, 0x2d70, 0x2e60,
+	0x2039, 0x2f35, 0x2704, 0xae68, 0x680c, 0xa422, 0x6808, 0xa31b,
+	0x0048, 0x3155, 0x8a51, 0x00c0, 0x3147, 0x1078, 0x1ba5, 0x8738,
+	0x2704, 0xa005, 0x00c0, 0x313b, 0x7098, 0xa075, 0x2060, 0x0040,
+	0x3168, 0x2039, 0x2f32, 0x0078, 0x313a, 0x8422, 0x8420, 0x831a,
+	0xa399, 0x0000, 0x690c, 0x2400, 0xa122, 0x6908, 0x2300, 0xa11b,
+	0x00c8, 0x3164, 0x1078, 0x1ba5, 0x2071, 0x0020, 0x0078, 0x3088,
+	0x127f, 0x2000, 0x007c, 0x7008, 0xa084, 0x00c0, 0xa086, 0x00c0,
+	0x0040, 0x3193, 0x2704, 0xac08, 0x2104, 0x701e, 0x8108, 0x2104,
+	0x701a, 0x8108, 0x2104, 0x7016, 0x8108, 0x2104, 0x7012, 0x0f7e,
+	0x2079, 0x0100, 0x7858, 0x0f7f, 0xa084, 0x0040, 0x0040, 0x318e,
+	0xa684, 0x0001, 0x00c0, 0x318e, 0xa6b5, 0x0001, 0x7602, 0x7007,
+	0x0001, 0x1078, 0x3038, 0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091,
+	0x2200, 0x2049, 0x3194, 0x0d7f, 0x087f, 0x7108, 0xa184, 0x00c0,
+	0x00c0, 0x31aa, 0x6824, 0xa005, 0x0040, 0x31ba, 0x0078, 0x2ede,
+	0x0078, 0x31ba, 0x7108, 0x8104, 0x00c8, 0x31b2, 0x1078, 0x2fa8,
+	0x0078, 0x319d, 0x7007, 0x0010, 0x7108, 0x8104, 0x00c8, 0x31b4,
+	0x1078, 0x2fa8, 0x7008, 0xa086, 0x0002, 0x00c0, 0x319d, 0x7000,
+	0xa005, 0x00c0, 0x319d, 0x7003, 0x0000, 0x2049, 0x0000, 0x127f,
+	0x2000, 0x007c, 0x127e, 0x147e, 0x137e, 0x157e, 0x0d7e, 0x2091,
+	0x2200, 0x0d7f, 0x2049, 0x31ca, 0xad80, 0x0010, 0x20a0, 0x2099,
+	0x0031, 0x700c, 0xa084, 0x007f, 0x6826, 0x7007, 0x0008, 0x7007,
+	0x0002, 0x7003, 0x0001, 0x0040, 0x31e8, 0x8000, 0x80ac, 0x53a5,
+	0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x31ea, 0x2049,
+	0x0000, 0x7003, 0x0000, 0x157f, 0x137f, 0x147f, 0x127f, 0x2000,
+	0x007c, 0x127e, 0x007e, 0x0d7e, 0x2091, 0x2200, 0x0d7f, 0x2049,
+	0x31f9, 0x6880, 0x2060, 0x6884, 0x6b88, 0x6c8c, 0x8057, 0xaad4,
+	0x00ff, 0xa084, 0x00ff, 0xa0b8, 0x2f32, 0x7e08, 0xa6b5, 0x0004,
+	0x7007, 0x0004, 0x7004, 0xa084, 0x0004, 0x00c0, 0x3212, 0x2c58,
+	0x2704, 0xac60, 0x6004, 0xa400, 0x701a, 0x6000, 0xa301, 0x701e,
+	0x7013, 0x0001, 0x7017, 0x0000, 0x7602, 0x7007, 0x0001, 0x007f,
+	0x8007, 0x2009, 0x0031, 0x200a, 0x00a0, 0x322c, 0x7108, 0x7007,
+	0x0002, 0x810c, 0x00c8, 0x322c, 0x810c, 0x0048, 0x3239, 0x0078,
+	0x2fea, 0xa4a0, 0x0001, 0xa399, 0x0000, 0x6b8a, 0x6c8e, 0x7007,
+	0x0004, 0x2049, 0x0000, 0x7003, 0x0000, 0x127f, 0x2000, 0x007c,
+	0x20a9, 0x0010, 0xa006, 0x8004, 0x8086, 0x818e, 0x00c8, 0x3251,
+	0xa200, 0x00f0, 0x324c, 0x8086, 0x818e, 0x007c, 0x157e, 0x20a9,
+	0x0010, 0xa005, 0x0040, 0x3277, 0xa11a, 0x00c8, 0x3277, 0x8213,
+	0x818d, 0x0048, 0x326a, 0xa11a, 0x00c8, 0x326b, 0x00f0, 0x325f,
+	0x0078, 0x326f, 0xa11a, 0x2308, 0x8210, 0x00f0, 0x325f, 0x007e,
+	0x3200, 0xa084, 0xf7ff, 0x2080, 0x007f, 0x157f, 0x007c, 0x007e,
+	0x3200, 0xa085, 0x0800, 0x0078, 0x3273, 0x00e0, 0x32bf, 0x2091,
+	0x6000, 0x7820, 0x8001, 0x7822, 0x00c0, 0x32b9, 0x7824, 0x7822,
+	0x2091, 0x8000, 0x2069, 0x3540, 0x6800, 0xa084, 0x0007, 0x0040,
+	0x32a1, 0xa086, 0x0002, 0x0040, 0x32a1, 0x6830, 0xa00d, 0x0040,
+	0x32a1, 0x2104, 0xa005, 0x0040, 0x32a1, 0x8001, 0x200a, 0x0040,
+	0x336f, 0x2061, 0x3680, 0x20a9, 0x0080, 0x6034, 0xa005, 0x0040,
+	0x32b3, 0x8001, 0x6036, 0x00c0, 0x32b3, 0x6010, 0xa005, 0x0040,
+	0x32b3, 0x1078, 0x1a19, 0xace0, 0x0010, 0x0070, 0x32b9, 0x0078,
+	0x32a5, 0x1078, 0x32d4, 0x1078, 0x32c2, 0x1078, 0x32f9, 0x2091,
+	0x8001, 0x007c, 0x783c, 0x8001, 0x783e, 0x00c0, 0x32d3, 0x7840,
+	0x783e, 0x7848, 0xa005, 0x0040, 0x32d3, 0x8001, 0x784a, 0x00c0,
+	0x32d3, 0x1078, 0x1a19, 0x007c, 0x7834, 0x8001, 0x7836, 0x00c0,
+	0x32f8, 0x7838, 0x7836, 0x2091, 0x8000, 0x7844, 0xa005, 0x00c0,
+	0x32e3, 0x2001, 0x0101, 0x8001, 0x7846, 0xa080, 0x3e80, 0x2040,
+	0x2004, 0xa065, 0x0040, 0x32f8, 0x6020, 0xa005, 0x0040, 0x32f4,
+	0x8001, 0x6022, 0x0040, 0x3328, 0x6000, 0x2c40, 0x0078, 0x32e9,
+	0x007c, 0x7828, 0x8001, 0x782a, 0x00c0, 0x3327, 0x782c, 0x782a,
+	0x7830, 0xa005, 0x00c0, 0x3306, 0x2001, 0x0080, 0x8001, 0x7832,
+	0x8003, 0x8003, 0x8003, 0x8003, 0xa090, 0x3680, 0xa298, 0x0002,
+	0x2304, 0xa084, 0x0008, 0x0040, 0x3327, 0xa290, 0x0009, 0x2204,
+	0xa005, 0x0040, 0x331f, 0x8001, 0x2012, 0x00c0, 0x3327, 0x2304,
+	0xa084, 0xfff7, 0xa085, 0x0080, 0x201a, 0x1078, 0x1a19, 0x007c,
+	0x2069, 0x3540, 0x6800, 0xa005, 0x0040, 0x3332, 0x683c, 0xac06,
+	0x0040, 0x336f, 0x6017, 0x0006, 0x60b0, 0xa084, 0x3f00, 0x601a,
+	0x601c, 0xa084, 0x00ff, 0xa085, 0x0060, 0x601e, 0x6000, 0x2042,
+	0x6710, 0x6fb6, 0x1078, 0x1692, 0x6818, 0xa005, 0x0040, 0x334a,
+	0x8001, 0x681a, 0x6808, 0xa084, 0xffef, 0x680a, 0x6810, 0x8001,
+	0x00d0, 0x3354, 0x1078, 0x1ba5, 0x6812, 0x602f, 0x0000, 0x602b,
+	0x0000, 0x2c68, 0x1078, 0x17dd, 0x2069, 0x3540, 0x2001, 0x0006,
+	0x68a2, 0x7944, 0xa184, 0x0100, 0x00c0, 0x336a, 0x69ba, 0x2001,
+	0x0004, 0x68a2, 0x1078, 0x1a14, 0x2091, 0x8001, 0x007c, 0x2009,
+	0x354f, 0x2164, 0x2069, 0x0100, 0x1078, 0x1b6b, 0x6017, 0x0006,
+	0x6858, 0xa084, 0x3f00, 0x601a, 0x601c, 0xa084, 0x00ff, 0xa085,
+	0x0048, 0x601e, 0x602f, 0x0000, 0x602b, 0x0000, 0x6830, 0xa084,
+	0x0040, 0x0040, 0x33ab, 0x684b, 0x0004, 0x20a9, 0x0014, 0x6848,
+	0xa084, 0x0004, 0x0040, 0x3398, 0x0070, 0x3398, 0x0078, 0x338f,
+	0x684b, 0x0009, 0x20a9, 0x0014, 0x6848, 0xa084, 0x0001, 0x0040,
+	0x33a5, 0x0070, 0x33a5, 0x0078, 0x339c, 0x20a9, 0x00fa, 0x0070,
+	0x33ab, 0x0078, 0x33a7, 0x6808, 0xa084, 0xfffd, 0x680a, 0x681b,
+	0x0046, 0x2009, 0x3568, 0x200b, 0x0007, 0x784c, 0x784a, 0x2091,
+	0x8001, 0x007c, 0x2079, 0x3500, 0x1078, 0x3403, 0x1078, 0x33cb,
+	0x1078, 0x33e0, 0x1078, 0x33f5, 0x7833, 0x0000, 0x7847, 0x0000,
+	0x784b, 0x0000, 0x007c, 0x2019, 0x000a, 0x2011, 0x3546, 0x2204,
+	0xa086, 0x0032, 0x0040, 0x33dd, 0x2019, 0x000c, 0x2204, 0xa086,
+	0x003c, 0x0040, 0x33dd, 0x2019, 0x0008, 0x7b2a, 0x7b2e, 0x007c,
+	0x2019, 0x0030, 0x2011, 0x3546, 0x2204, 0xa086, 0x0032, 0x0040,
+	0x33f2, 0x2019, 0x0039, 0x2204, 0xa086, 0x003c, 0x0040, 0x33f2,
+	0x2019, 0x0027, 0x7b36, 0x7b3a, 0x007c, 0x2019, 0x000d, 0x2011,
+	0x3546, 0x2204, 0xa086, 0x003c, 0x0040, 0x3400, 0x2019, 0x000a,
+	0x7b3e, 0x7b42, 0x007c, 0x2019, 0x2faf, 0x2011, 0x3546, 0x2204,
+	0xa086, 0x0032, 0x0040, 0x3415, 0x2019, 0x3971, 0x2204, 0xa086,
+	0x003c, 0x0040, 0x3415, 0x2019, 0x2626, 0x7b22, 0x7b26, 0x007c,
+	0x92a7
+};
+unsigned short sbus_risc_code_length01 = 0x2419;
diff --git a/drivers/scsi/sata_nv.c b/drivers/scsi/sata_nv.c
new file mode 100644
index 0000000..69009f8
--- /dev/null
+++ b/drivers/scsi/sata_nv.c
@@ -0,0 +1,570 @@
+/*
+ *  sata_nv.c - NVIDIA nForce SATA
+ *
+ *  Copyright 2004 NVIDIA Corp.  All rights reserved.
+ *  Copyright 2004 Andrew Chew
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ *  0.06
+ *     - Added generic SATA support by using a pci_device_id that filters on
+ *       the IDE storage class code.
+ *
+ *  0.03
+ *     - Fixed a bug where the hotplug handlers for non-CK804/MCP04 were using
+ *       mmio_base, which is only set for the CK804/MCP04 case.
+ *
+ *  0.02
+ *     - Added support for CK804 SATA controller.
+ *
+ *  0.01
+ *     - Initial revision.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME			"sata_nv"
+#define DRV_VERSION			"0.6"
+
+#define NV_PORTS			2
+#define NV_PIO_MASK			0x1f
+#define NV_MWDMA_MASK			0x07
+#define NV_UDMA_MASK			0x7f
+#define NV_PORT0_SCR_REG_OFFSET		0x00
+#define NV_PORT1_SCR_REG_OFFSET		0x40
+
+#define NV_INT_STATUS			0x10
+#define NV_INT_STATUS_CK804		0x440
+#define NV_INT_STATUS_PDEV_INT		0x01
+#define NV_INT_STATUS_PDEV_PM		0x02
+#define NV_INT_STATUS_PDEV_ADDED	0x04
+#define NV_INT_STATUS_PDEV_REMOVED	0x08
+#define NV_INT_STATUS_SDEV_INT		0x10
+#define NV_INT_STATUS_SDEV_PM		0x20
+#define NV_INT_STATUS_SDEV_ADDED	0x40
+#define NV_INT_STATUS_SDEV_REMOVED	0x80
+#define NV_INT_STATUS_PDEV_HOTPLUG	(NV_INT_STATUS_PDEV_ADDED | \
+					NV_INT_STATUS_PDEV_REMOVED)
+#define NV_INT_STATUS_SDEV_HOTPLUG	(NV_INT_STATUS_SDEV_ADDED | \
+					NV_INT_STATUS_SDEV_REMOVED)
+#define NV_INT_STATUS_HOTPLUG		(NV_INT_STATUS_PDEV_HOTPLUG | \
+					NV_INT_STATUS_SDEV_HOTPLUG)
+
+#define NV_INT_ENABLE			0x11
+#define NV_INT_ENABLE_CK804		0x441
+#define NV_INT_ENABLE_PDEV_MASK		0x01
+#define NV_INT_ENABLE_PDEV_PM		0x02
+#define NV_INT_ENABLE_PDEV_ADDED	0x04
+#define NV_INT_ENABLE_PDEV_REMOVED	0x08
+#define NV_INT_ENABLE_SDEV_MASK		0x10
+#define NV_INT_ENABLE_SDEV_PM		0x20
+#define NV_INT_ENABLE_SDEV_ADDED	0x40
+#define NV_INT_ENABLE_SDEV_REMOVED	0x80
+#define NV_INT_ENABLE_PDEV_HOTPLUG	(NV_INT_ENABLE_PDEV_ADDED | \
+					NV_INT_ENABLE_PDEV_REMOVED)
+#define NV_INT_ENABLE_SDEV_HOTPLUG	(NV_INT_ENABLE_SDEV_ADDED | \
+					NV_INT_ENABLE_SDEV_REMOVED)
+#define NV_INT_ENABLE_HOTPLUG		(NV_INT_ENABLE_PDEV_HOTPLUG | \
+					NV_INT_ENABLE_SDEV_HOTPLUG)
+
+#define NV_INT_CONFIG			0x12
+#define NV_INT_CONFIG_METHD		0x01 // 0 = INT, 1 = SMI
+
+// For PCI config register 20
+#define NV_MCP_SATA_CFG_20		0x50
+#define NV_MCP_SATA_CFG_20_SATA_SPACE_EN	0x04
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t nv_interrupt (int irq, void *dev_instance,
+				 struct pt_regs *regs);
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void nv_host_stop (struct ata_host_set *host_set);
+static void nv_enable_hotplug(struct ata_probe_ent *probe_ent);
+static void nv_disable_hotplug(struct ata_host_set *host_set);
+static void nv_check_hotplug(struct ata_host_set *host_set);
+static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent);
+static void nv_disable_hotplug_ck804(struct ata_host_set *host_set);
+static void nv_check_hotplug_ck804(struct ata_host_set *host_set);
+
+enum nv_host_type
+{
+	GENERIC,
+	NFORCE2,
+	NFORCE3,
+	CK804
+};
+
+static struct pci_device_id nv_pci_tbl[] = {
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE3 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_CK804_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 },
+	{ PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID,
+		PCI_ANY_ID, PCI_ANY_ID,
+		PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC },
+	{ 0, } /* terminate list */
+};
+
+#define NV_HOST_FLAGS_SCR_MMIO	0x00000001
+
+struct nv_host_desc
+{
+	enum nv_host_type	host_type;
+	void			(*enable_hotplug)(struct ata_probe_ent *probe_ent);
+	void			(*disable_hotplug)(struct ata_host_set *host_set);
+	void			(*check_hotplug)(struct ata_host_set *host_set);
+
+};
+static struct nv_host_desc nv_device_tbl[] = {
+	{
+		.host_type	= GENERIC,
+		.enable_hotplug	= NULL,
+		.disable_hotplug= NULL,
+		.check_hotplug	= NULL,
+	},
+	{
+		.host_type	= NFORCE2,
+		.enable_hotplug	= nv_enable_hotplug,
+		.disable_hotplug= nv_disable_hotplug,
+		.check_hotplug	= nv_check_hotplug,
+	},
+	{
+		.host_type	= NFORCE3,
+		.enable_hotplug	= nv_enable_hotplug,
+		.disable_hotplug= nv_disable_hotplug,
+		.check_hotplug	= nv_check_hotplug,
+	},
+	{	.host_type	= CK804,
+		.enable_hotplug	= nv_enable_hotplug_ck804,
+		.disable_hotplug= nv_disable_hotplug_ck804,
+		.check_hotplug	= nv_check_hotplug_ck804,
+	},
+};
+
+struct nv_host
+{
+	struct nv_host_desc	*host_desc;
+	unsigned long		host_flags;
+};
+
+static struct pci_driver nv_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= nv_pci_tbl,
+	.probe			= nv_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template nv_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations nv_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup		= ata_bmdma_setup,
+	.bmdma_start		= ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= nv_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= nv_scr_read,
+	.scr_write		= nv_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+	.host_stop		= nv_host_stop,
+};
+
+/* FIXME: The hardware provides the necessary SATA PHY controls
+ * to support ATA_FLAG_SATA_RESET.  However, it is currently
+ * necessary to disable that flag, to solve misdetection problems.
+ * See http://bugme.osdl.org/show_bug.cgi?id=3352 for more info.
+ *
+ * This problem really needs to be investigated further.  But in the
+ * meantime, we avoid ATA_FLAG_SATA_RESET to get people working.
+ */
+static struct ata_port_info nv_port_info = {
+	.sht		= &nv_sht,
+	.host_flags	= ATA_FLAG_SATA |
+			  /* ATA_FLAG_SATA_RESET | */
+			  ATA_FLAG_SRST |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask	= NV_PIO_MASK,
+	.mwdma_mask	= NV_MWDMA_MASK,
+	.udma_mask	= NV_UDMA_MASK,
+	.port_ops	= &nv_ops,
+};
+
+MODULE_AUTHOR("NVIDIA");
+MODULE_DESCRIPTION("low-level driver for NVIDIA nForce SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, nv_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static irqreturn_t nv_interrupt (int irq, void *dev_instance,
+				 struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct nv_host *host = host_set->private_data;
+	unsigned int i;
+	unsigned int handled = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&host_set->lock, flags);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		struct ata_port *ap;
+
+		ap = host_set->ports[i];
+		if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+				handled += ata_host_intr(ap, qc);
+		}
+
+	}
+
+	if (host->host_desc->check_hotplug)
+		host->host_desc->check_hotplug(host_set);
+
+	spin_unlock_irqrestore(&host_set->lock, flags);
+
+	return IRQ_RETVAL(handled);
+}
+
+static u32 nv_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	struct nv_host *host = host_set->private_data;
+
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+		return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4));
+	else
+		return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	struct nv_host *host = host_set->private_data;
+
+	if (sc_reg > SCR_CONTROL)
+		return;
+
+	if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+		writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4));
+	else
+		outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void nv_host_stop (struct ata_host_set *host_set)
+{
+	struct nv_host *host = host_set->private_data;
+
+	// Disable hotplug event interrupts.
+	if (host->host_desc->disable_hotplug)
+		host->host_desc->disable_hotplug(host_set);
+
+	kfree(host);
+}
+
+static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version = 0;
+	struct nv_host *host;
+	struct ata_port_info *ppi;
+	struct ata_probe_ent *probe_ent;
+	int pci_dev_busy = 0;
+	int rc;
+	u32 bar;
+
+        // Make sure this is a SATA controller by counting the number of bars
+        // (NVIDIA SATA controllers will always have six bars).  Otherwise,
+        // it's an IDE controller and we ignore it.
+	for (bar=0; bar<6; bar++)
+		if (pci_resource_start(pdev, bar) == 0)
+			return -ENODEV;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		goto err_out;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out_disable;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	rc = -ENOMEM;
+
+	ppi = &nv_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	if (!probe_ent)
+		goto err_out_regions;
+
+	host = kmalloc(sizeof(struct nv_host), GFP_KERNEL);
+	if (!host)
+		goto err_out_free_ent;
+
+	memset(host, 0, sizeof(struct nv_host));
+	host->host_desc = &nv_device_tbl[ent->driver_data];
+
+	probe_ent->private_data = host;
+
+	if (pci_resource_flags(pdev, 5) & IORESOURCE_MEM)
+		host->host_flags |= NV_HOST_FLAGS_SCR_MMIO;
+
+	if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) {
+		unsigned long base;
+
+		probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5),
+				pci_resource_len(pdev, 5));
+		if (probe_ent->mmio_base == NULL) {
+			rc = -EIO;
+			goto err_out_free_host;
+		}
+
+		base = (unsigned long)probe_ent->mmio_base;
+
+		probe_ent->port[0].scr_addr =
+			base + NV_PORT0_SCR_REG_OFFSET;
+		probe_ent->port[1].scr_addr =
+			base + NV_PORT1_SCR_REG_OFFSET;
+	} else {
+
+		probe_ent->port[0].scr_addr =
+			pci_resource_start(pdev, 5) | NV_PORT0_SCR_REG_OFFSET;
+		probe_ent->port[1].scr_addr =
+			pci_resource_start(pdev, 5) | NV_PORT1_SCR_REG_OFFSET;
+	}
+
+	pci_set_master(pdev);
+
+	rc = ata_device_add(probe_ent);
+	if (rc != NV_PORTS)
+		goto err_out_iounmap;
+
+	// Enable hotplug event interrupts.
+	if (host->host_desc->enable_hotplug)
+		host->host_desc->enable_hotplug(probe_ent);
+
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_iounmap:
+	if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO)
+		iounmap(probe_ent->mmio_base);
+err_out_free_host:
+	kfree(host);
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out_disable:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+err_out:
+	return rc;
+}
+
+static void nv_enable_hotplug(struct ata_probe_ent *probe_ent)
+{
+	u8 intr_mask;
+
+	outb(NV_INT_STATUS_HOTPLUG,
+		probe_ent->port[0].scr_addr + NV_INT_STATUS);
+
+	intr_mask = inb(probe_ent->port[0].scr_addr + NV_INT_ENABLE);
+	intr_mask |= NV_INT_ENABLE_HOTPLUG;
+
+	outb(intr_mask, probe_ent->port[0].scr_addr + NV_INT_ENABLE);
+}
+
+static void nv_disable_hotplug(struct ata_host_set *host_set)
+{
+	u8 intr_mask;
+
+	intr_mask = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
+
+	intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
+
+	outb(intr_mask, host_set->ports[0]->ioaddr.scr_addr + NV_INT_ENABLE);
+}
+
+static void nv_check_hotplug(struct ata_host_set *host_set)
+{
+	u8 intr_status;
+
+	intr_status = inb(host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+
+	// Clear interrupt status.
+	outb(0xff, host_set->ports[0]->ioaddr.scr_addr + NV_INT_STATUS);
+
+	if (intr_status & NV_INT_STATUS_HOTPLUG) {
+		if (intr_status & NV_INT_STATUS_PDEV_ADDED)
+			printk(KERN_WARNING "nv_sata: "
+				"Primary device added\n");
+
+		if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
+			printk(KERN_WARNING "nv_sata: "
+				"Primary device removed\n");
+
+		if (intr_status & NV_INT_STATUS_SDEV_ADDED)
+			printk(KERN_WARNING "nv_sata: "
+				"Secondary device added\n");
+
+		if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
+			printk(KERN_WARNING "nv_sata: "
+				"Secondary device removed\n");
+	}
+}
+
+static void nv_enable_hotplug_ck804(struct ata_probe_ent *probe_ent)
+{
+	struct pci_dev *pdev = to_pci_dev(probe_ent->dev);
+	u8 intr_mask;
+	u8 regval;
+
+	pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+	regval |= NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+	pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+
+	writeb(NV_INT_STATUS_HOTPLUG, probe_ent->mmio_base + NV_INT_STATUS_CK804);
+
+	intr_mask = readb(probe_ent->mmio_base + NV_INT_ENABLE_CK804);
+	intr_mask |= NV_INT_ENABLE_HOTPLUG;
+
+	writeb(intr_mask, probe_ent->mmio_base + NV_INT_ENABLE_CK804);
+}
+
+static void nv_disable_hotplug_ck804(struct ata_host_set *host_set)
+{
+	struct pci_dev *pdev = to_pci_dev(host_set->dev);
+	u8 intr_mask;
+	u8 regval;
+
+	intr_mask = readb(host_set->mmio_base + NV_INT_ENABLE_CK804);
+
+	intr_mask &= ~(NV_INT_ENABLE_HOTPLUG);
+
+	writeb(intr_mask, host_set->mmio_base + NV_INT_ENABLE_CK804);
+
+	pci_read_config_byte(pdev, NV_MCP_SATA_CFG_20, &regval);
+	regval &= ~NV_MCP_SATA_CFG_20_SATA_SPACE_EN;
+	pci_write_config_byte(pdev, NV_MCP_SATA_CFG_20, regval);
+}
+
+static void nv_check_hotplug_ck804(struct ata_host_set *host_set)
+{
+	u8 intr_status;
+
+	intr_status = readb(host_set->mmio_base + NV_INT_STATUS_CK804);
+
+	// Clear interrupt status.
+	writeb(0xff, host_set->mmio_base + NV_INT_STATUS_CK804);
+
+	if (intr_status & NV_INT_STATUS_HOTPLUG) {
+		if (intr_status & NV_INT_STATUS_PDEV_ADDED)
+			printk(KERN_WARNING "nv_sata: "
+				"Primary device added\n");
+
+		if (intr_status & NV_INT_STATUS_PDEV_REMOVED)
+			printk(KERN_WARNING "nv_sata: "
+				"Primary device removed\n");
+
+		if (intr_status & NV_INT_STATUS_SDEV_ADDED)
+			printk(KERN_WARNING "nv_sata: "
+				"Secondary device added\n");
+
+		if (intr_status & NV_INT_STATUS_SDEV_REMOVED)
+			printk(KERN_WARNING "nv_sata: "
+				"Secondary device removed\n");
+	}
+}
+
+static int __init nv_init(void)
+{
+	return pci_module_init(&nv_pci_driver);
+}
+
+static void __exit nv_exit(void)
+{
+	pci_unregister_driver(&nv_pci_driver);
+}
+
+module_init(nv_init);
+module_exit(nv_exit);
diff --git a/drivers/scsi/sata_promise.c b/drivers/scsi/sata_promise.c
new file mode 100644
index 0000000..19a13e3
--- /dev/null
+++ b/drivers/scsi/sata_promise.c
@@ -0,0 +1,682 @@
+/*
+ *  sata_promise.c - Promise SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME	"sata_promise"
+#define DRV_VERSION	"1.01"
+
+
+enum {
+	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
+	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
+	PDC_TBG_MODE		= 0x41,	/* TBG mode */
+	PDC_FLASH_CTL		= 0x44, /* Flash control register */
+	PDC_PCI_CTL		= 0x48, /* PCI control and status register */
+	PDC_GLOBAL_CTL		= 0x48, /* Global control/status (per port) */
+	PDC_CTLSTAT		= 0x60,	/* IDE control and status (per port) */
+	PDC_SATA_PLUG_CSR	= 0x6C, /* SATA Plug control/status reg */
+	PDC_SLEW_CTL		= 0x470, /* slew rate control reg */
+
+	PDC_ERR_MASK		= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+				  (1<<8) | (1<<9) | (1<<10),
+
+	board_2037x		= 0,	/* FastTrak S150 TX2plus */
+	board_20319		= 1,	/* FastTrak S150 TX4 */
+
+	PDC_HAS_PATA		= (1 << 1), /* PDC20375 has PATA */
+
+	PDC_RESET		= (1 << 11), /* HDMA reset */
+};
+
+
+struct pdc_port_priv {
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+};
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc_phy_reset(struct ata_port *ap);
+static void pdc_qc_prep(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_irq_clear(struct ata_port *ap);
+static int pdc_qc_issue_prot(struct ata_queued_cmd *qc);
+
+static Scsi_Host_Template pdc_ata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations pdc_ata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= pdc_tf_load_mmio,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= pdc_exec_command_mmio,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= pdc_phy_reset,
+	.qc_prep		= pdc_qc_prep,
+	.qc_issue		= pdc_qc_issue_prot,
+	.eng_timeout		= pdc_eng_timeout,
+	.irq_handler		= pdc_interrupt,
+	.irq_clear		= pdc_irq_clear,
+	.scr_read		= pdc_sata_scr_read,
+	.scr_write		= pdc_sata_scr_write,
+	.port_start		= pdc_port_start,
+	.port_stop		= pdc_port_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+	/* board_2037x */
+	{
+		.sht		= &pdc_ata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_ata_ops,
+	},
+
+	/* board_20319 */
+	{
+		.sht		= &pdc_ata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_ata_ops,
+	},
+};
+
+static struct pci_device_id pdc_ata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3375, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3376, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3574, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+	{ PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2037x },
+
+	{ PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
+	{ PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
+	{ PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20319 },
+
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver pdc_ata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pdc_ata_pci_tbl,
+	.probe			= pdc_ata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int pdc_port_start(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct pdc_port_priv *pp;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	ap->private_data = pp;
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct pdc_port_priv *pp = ap->private_data;
+
+	ap->private_data = NULL;
+	dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+
+static void pdc_reset_port(struct ata_port *ap)
+{
+	void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT;
+	unsigned int i;
+	u32 tmp;
+
+	for (i = 11; i > 0; i--) {
+		tmp = readl(mmio);
+		if (tmp & PDC_RESET)
+			break;
+
+		udelay(100);
+
+		tmp |= PDC_RESET;
+		writel(tmp, mmio);
+	}
+
+	tmp &= ~PDC_RESET;
+	writel(tmp, mmio);
+	readl(mmio);	/* flush */
+}
+
+static void pdc_phy_reset(struct ata_port *ap)
+{
+	pdc_reset_port(ap);
+	sata_phy_reset(ap);
+}
+
+static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void pdc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void pdc_qc_prep(struct ata_queued_cmd *qc)
+{
+	struct pdc_port_priv *pp = qc->ap->private_data;
+	unsigned int i;
+
+	VPRINTK("ENTER\n");
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		ata_qc_prep(qc);
+		/* fall through */
+
+	case ATA_PROT_NODATA:
+		i = pdc_pkt_header(&qc->tf, qc->ap->prd_dma,
+				   qc->dev->devno, pp->pkt);
+
+		if (qc->tf.flags & ATA_TFLAG_LBA48)
+			i = pdc_prep_lba48(&qc->tf, pp->pkt, i);
+		else
+			i = pdc_prep_lba28(&qc->tf, pp->pkt, i);
+
+		pdc_pkt_footer(&qc->tf, pp->pkt, i);
+		break;
+
+	default:
+		break;
+	}
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+	u8 drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+static inline unsigned int pdc_host_intr( struct ata_port *ap,
+                                          struct ata_queued_cmd *qc)
+{
+	u8 status;
+	unsigned int handled = 0, have_err = 0;
+	u32 tmp;
+	void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL;
+
+	tmp = readl(mmio);
+	if (tmp & PDC_ERR_MASK) {
+		have_err = 1;
+		pdc_reset_port(ap);
+	}
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		status = ata_wait_idle(ap);
+		if (have_err)
+			status |= ATA_ERR;
+		ata_qc_complete(qc, status);
+		handled = 1;
+		break;
+
+        default:
+                ap->stats.idle_irq++;
+                break;
+        }
+
+        return handled;
+}
+
+static void pdc_irq_clear(struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	readl(mmio + PDC_INT_SEQMASK);
+}
+
+static irqreturn_t pdc_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ata_port *ap;
+	u32 mask = 0;
+	unsigned int i, tmp;
+	unsigned int handled = 0;
+	void *mmio_base;
+
+	VPRINTK("ENTER\n");
+
+	if (!host_set || !host_set->mmio_base) {
+		VPRINTK("QUICK EXIT\n");
+		return IRQ_NONE;
+	}
+
+	mmio_base = host_set->mmio_base;
+
+	/* reading should also clear interrupts */
+	mask = readl(mmio_base + PDC_INT_SEQMASK);
+
+	if (mask == 0xffffffff) {
+		VPRINTK("QUICK EXIT 2\n");
+		return IRQ_NONE;
+	}
+	mask &= 0xffff;		/* only 16 tags possible */
+	if (!mask) {
+		VPRINTK("QUICK EXIT 3\n");
+		return IRQ_NONE;
+	}
+
+	spin_lock(&host_set->lock);
+
+	writel(mask, mmio_base + PDC_INT_SEQMASK);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		VPRINTK("port %u\n", i);
+		ap = host_set->ports[i];
+		tmp = mask & (1 << (i + 1));
+		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+				handled += pdc_host_intr(ap, qc);
+		}
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static inline void pdc_packet_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	unsigned int port_no = ap->port_no;
+	u8 seq = (u8) (port_no + 1);
+
+	VPRINTK("ENTER, ap %p\n", ap);
+
+	writel(0x00000001, ap->host_set->mmio_base + (seq * 4));
+	readl(ap->host_set->mmio_base + (seq * 4));	/* flush */
+
+	pp->pkt[2] = seq;
+	wmb();			/* flush PRD, pkt writes */
+	writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+	readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */
+}
+
+static int pdc_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		pdc_packet_start(qc);
+		return 0;
+
+	case ATA_PROT_ATAPI_DMA:
+		BUG();
+		break;
+
+	default:
+		break;
+	}
+
+	return ata_qc_issue_prot(qc);
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_tf_load(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_exec_command(ap, tf);
+}
+
+
+static void pdc_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base;
+	port->data_addr		= base;
+	port->feature_addr	=
+	port->error_addr	= base + 0x4;
+	port->nsect_addr	= base + 0x8;
+	port->lbal_addr		= base + 0xc;
+	port->lbam_addr		= base + 0x10;
+	port->lbah_addr		= base + 0x14;
+	port->device_addr	= base + 0x18;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x38;
+}
+
+
+static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+{
+	void *mmio = pe->mmio_base;
+	u32 tmp;
+
+	/*
+	 * Except for the hotplug stuff, this is voodoo from the
+	 * Promise driver.  Label this entire section
+	 * "TODO: figure out why we do this"
+	 */
+
+	/* change FIFO_SHD to 8 dwords, enable BMR_BURST */
+	tmp = readl(mmio + PDC_FLASH_CTL);
+	tmp |= 0x12000;	/* bit 16 (fifo 8 dw) and 13 (bmr burst?) */
+	writel(tmp, mmio + PDC_FLASH_CTL);
+
+	/* clear plug/unplug flags for all ports */
+	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
+	writel(tmp | 0xff, mmio + PDC_SATA_PLUG_CSR);
+
+	/* mask plug/unplug ints */
+	tmp = readl(mmio + PDC_SATA_PLUG_CSR);
+	writel(tmp | 0xff0000, mmio + PDC_SATA_PLUG_CSR);
+
+	/* reduce TBG clock to 133 Mhz. */
+	tmp = readl(mmio + PDC_TBG_MODE);
+	tmp &= ~0x30000; /* clear bit 17, 16*/
+	tmp |= 0x10000;  /* set bit 17:16 = 0:1 */
+	writel(tmp, mmio + PDC_TBG_MODE);
+
+	readl(mmio + PDC_TBG_MODE);	/* flush */
+	msleep(10);
+
+	/* adjust slew rate control register. */
+	tmp = readl(mmio + PDC_SLEW_CTL);
+	tmp &= 0xFFFFF03F; /* clear bit 11 ~ 6 */
+	tmp  |= 0x00000900; /* set bit 11-9 = 100b , bit 8-6 = 100 */
+	writel(tmp, mmio + PDC_SLEW_CTL);
+}
+
+static int pdc_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int pci_dev_busy = 0;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 3),
+		            pci_resource_len(pdev, 3));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	probe_ent->sht		= pdc_port_info[board_idx].sht;
+	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;
+	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	pdc_ata_setup_port(&probe_ent->port[0], base + 0x200);
+	pdc_ata_setup_port(&probe_ent->port[1], base + 0x280);
+
+	probe_ent->port[0].scr_addr = base + 0x400;
+	probe_ent->port[1].scr_addr = base + 0x500;
+
+	/* notice 4-port boards */
+	switch (board_idx) {
+	case board_20319:
+       		probe_ent->n_ports = 4;
+
+		pdc_ata_setup_port(&probe_ent->port[2], base + 0x300);
+		pdc_ata_setup_port(&probe_ent->port[3], base + 0x380);
+
+		probe_ent->port[2].scr_addr = base + 0x600;
+		probe_ent->port[3].scr_addr = base + 0x700;
+		break;
+	case board_2037x:
+       		probe_ent->n_ports = 2;
+		break;
+	default:
+		BUG();
+		break;
+	}
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	pdc_host_init(board_idx, probe_ent);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init pdc_ata_init(void)
+{
+	return pci_module_init(&pdc_ata_pci_driver);
+}
+
+
+static void __exit pdc_ata_exit(void)
+{
+	pci_unregister_driver(&pdc_ata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA TX2/TX4 low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_ata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_ata_init);
+module_exit(pdc_ata_exit);
diff --git a/drivers/scsi/sata_promise.h b/drivers/scsi/sata_promise.h
new file mode 100644
index 0000000..6e7e96b
--- /dev/null
+++ b/drivers/scsi/sata_promise.h
@@ -0,0 +1,154 @@
+/*
+ *  sata_promise.h - Promise SATA common definitions and inline funcs
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#ifndef __SATA_PROMISE_H__
+#define __SATA_PROMISE_H__
+
+#include <linux/ata.h>
+
+enum pdc_packet_bits {
+	PDC_PKT_READ		= (1 << 2),
+	PDC_PKT_NODATA		= (1 << 3),
+
+	PDC_PKT_SIZEMASK	= (1 << 7) | (1 << 6) | (1 << 5),
+	PDC_PKT_CLEAR_BSY	= (1 << 4),
+	PDC_PKT_WAIT_DRDY	= (1 << 3) | (1 << 4),
+	PDC_LAST_REG		= (1 << 3),
+
+	PDC_REG_DEVCTL		= (1 << 3) | (1 << 2) | (1 << 1),
+};
+
+static inline unsigned int pdc_pkt_header(struct ata_taskfile *tf,
+					  dma_addr_t sg_table,
+					  unsigned int devno, u8 *buf)
+{
+	u8 dev_reg;
+	u32 *buf32 = (u32 *) buf;
+
+	/* set control bits (byte 0), zero delay seq id (byte 3),
+	 * and seq id (byte 2)
+	 */
+	switch (tf->protocol) {
+	case ATA_PROT_DMA:
+		if (!(tf->flags & ATA_TFLAG_WRITE))
+			buf32[0] = cpu_to_le32(PDC_PKT_READ);
+		else
+			buf32[0] = 0;
+		break;
+
+	case ATA_PROT_NODATA:
+		buf32[0] = cpu_to_le32(PDC_PKT_NODATA);
+		break;
+
+	default:
+		BUG();
+		break;
+	}
+
+	buf32[1] = cpu_to_le32(sg_table);	/* S/G table addr */
+	buf32[2] = 0;				/* no next-packet */
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[12] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[13] = dev_reg;
+
+	/* device control register */
+	buf[14] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[15] = tf->ctl;
+
+	return 16; 	/* offset of next byte */
+}
+
+static inline unsigned int pdc_pkt_footer(struct ata_taskfile *tf, u8 *buf,
+				  unsigned int i)
+{
+	if (tf->flags & ATA_TFLAG_DEVICE) {
+		buf[i++] = (1 << 5) | ATA_REG_DEVICE;
+		buf[i++] = tf->device;
+	}
+
+	/* and finally the command itself; also includes end-of-pkt marker */
+	buf[i++] = (1 << 5) | PDC_LAST_REG | ATA_REG_CMD;
+	buf[i++] = tf->command;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba28(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(1 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (1 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (1 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (1 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+static inline unsigned int pdc_prep_lba48(struct ata_taskfile *tf, u8 *buf, unsigned int i)
+{
+	/* the "(2 << 5)" should be read "(count << 5)" */
+
+	/* ATA command block registers */
+	buf[i++] = (2 << 5) | ATA_REG_FEATURE;
+	buf[i++] = tf->hob_feature;
+	buf[i++] = tf->feature;
+
+	buf[i++] = (2 << 5) | ATA_REG_NSECT;
+	buf[i++] = tf->hob_nsect;
+	buf[i++] = tf->nsect;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAL;
+	buf[i++] = tf->hob_lbal;
+	buf[i++] = tf->lbal;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAM;
+	buf[i++] = tf->hob_lbam;
+	buf[i++] = tf->lbam;
+
+	buf[i++] = (2 << 5) | ATA_REG_LBAH;
+	buf[i++] = tf->hob_lbah;
+	buf[i++] = tf->lbah;
+
+	return i;
+}
+
+
+#endif /* __SATA_PROMISE_H__ */
diff --git a/drivers/scsi/sata_qstor.c b/drivers/scsi/sata_qstor.c
new file mode 100644
index 0000000..dfd3621
--- /dev/null
+++ b/drivers/scsi/sata_qstor.c
@@ -0,0 +1,718 @@
+/*
+ *  sata_qstor.c - Pacific Digital Corporation QStor SATA
+ *
+ *  Maintained by:  Mark Lord <mlord@pobox.com>
+ *
+ *  Copyright 2005 Pacific Digital Corporation.
+ *  (OSL/GPL code release authorized by Jalil Fadavi).
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <asm/io.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_qstor"
+#define DRV_VERSION	"0.04"
+
+enum {
+	QS_PORTS		= 4,
+	QS_MAX_PRD		= LIBATA_MAX_PRD,
+	QS_CPB_ORDER		= 6,
+	QS_CPB_BYTES		= (1 << QS_CPB_ORDER),
+	QS_PRD_BYTES		= QS_MAX_PRD * 16,
+	QS_PKT_BYTES		= QS_CPB_BYTES + QS_PRD_BYTES,
+
+	QS_DMA_BOUNDARY		= ~0UL,
+
+	/* global register offsets */
+	QS_HCF_CNFG3		= 0x0003, /* host configuration offset */
+	QS_HID_HPHY		= 0x0004, /* host physical interface info */
+	QS_HCT_CTRL		= 0x00e4, /* global interrupt mask offset */
+	QS_HST_SFF		= 0x0100, /* host status fifo offset */
+	QS_HVS_SERD3		= 0x0393, /* PHY enable offset */
+
+	/* global control bits */
+	QS_HPHY_64BIT		= (1 << 1), /* 64-bit bus detected */
+	QS_CNFG3_GSRST		= 0x01,     /* global chip reset */
+	QS_SERD3_PHY_ENA	= 0xf0,     /* PHY detection ENAble*/
+
+	/* per-channel register offsets */
+	QS_CCF_CPBA		= 0x0710, /* chan CPB base address */
+	QS_CCF_CSEP		= 0x0718, /* chan CPB separation factor */
+	QS_CFC_HUFT		= 0x0800, /* host upstream fifo threshold */
+	QS_CFC_HDFT		= 0x0804, /* host downstream fifo threshold */
+	QS_CFC_DUFT		= 0x0808, /* dev upstream fifo threshold */
+	QS_CFC_DDFT		= 0x080c, /* dev downstream fifo threshold */
+	QS_CCT_CTR0		= 0x0900, /* chan control-0 offset */
+	QS_CCT_CTR1		= 0x0901, /* chan control-1 offset */
+	QS_CCT_CFF		= 0x0a00, /* chan command fifo offset */
+
+	/* channel control bits */
+	QS_CTR0_REG		= (1 << 1),   /* register mode (vs. pkt mode) */
+	QS_CTR0_CLER		= (1 << 2),   /* clear channel errors */
+	QS_CTR1_RDEV		= (1 << 1),   /* sata phy/comms reset */
+	QS_CTR1_RCHN		= (1 << 4),   /* reset channel logic */
+	QS_CCF_RUN_PKT		= 0x107,      /* RUN a new dma PKT */
+
+	/* pkt sub-field headers */
+	QS_HCB_HDR		= 0x01,   /* Host Control Block header */
+	QS_DCB_HDR		= 0x02,   /* Device Control Block header */
+
+	/* pkt HCB flag bits */
+	QS_HF_DIRO		= (1 << 0),   /* data DIRection Out */
+	QS_HF_DAT		= (1 << 3),   /* DATa pkt */
+	QS_HF_IEN		= (1 << 4),   /* Interrupt ENable */
+	QS_HF_VLD		= (1 << 5),   /* VaLiD pkt */
+
+	/* pkt DCB flag bits */
+	QS_DF_PORD		= (1 << 2),   /* Pio OR Dma */
+	QS_DF_ELBA		= (1 << 3),   /* Extended LBA (lba48) */
+
+	/* PCI device IDs */
+	board_2068_idx		= 0,	/* QStor 4-port SATA/RAID */
+};
+
+typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t;
+
+struct qs_port_priv {
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+	qs_state_t		state;
+};
+
+static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static int qs_ata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t qs_intr (int irq, void *dev_instance, struct pt_regs *regs);
+static int qs_port_start(struct ata_port *ap);
+static void qs_host_stop(struct ata_host_set *host_set);
+static void qs_port_stop(struct ata_port *ap);
+static void qs_phy_reset(struct ata_port *ap);
+static void qs_qc_prep(struct ata_queued_cmd *qc);
+static int qs_qc_issue(struct ata_queued_cmd *qc);
+static int qs_check_atapi_dma(struct ata_queued_cmd *qc);
+static void qs_bmdma_stop(struct ata_port *ap);
+static u8 qs_bmdma_status(struct ata_port *ap);
+static void qs_irq_clear(struct ata_port *ap);
+static void qs_eng_timeout(struct ata_port *ap);
+
+static Scsi_Host_Template qs_ata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= QS_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	//FIXME .use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= QS_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+};
+
+static struct ata_port_operations qs_ata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.check_atapi_dma	= qs_check_atapi_dma,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= qs_phy_reset,
+	.qc_prep		= qs_qc_prep,
+	.qc_issue		= qs_qc_issue,
+	.eng_timeout		= qs_eng_timeout,
+	.irq_handler		= qs_intr,
+	.irq_clear		= qs_irq_clear,
+	.scr_read		= qs_scr_read,
+	.scr_write		= qs_scr_write,
+	.port_start		= qs_port_start,
+	.port_stop		= qs_port_stop,
+	.host_stop		= qs_host_stop,
+	.bmdma_stop		= qs_bmdma_stop,
+	.bmdma_status		= qs_bmdma_status,
+};
+
+static struct ata_port_info qs_port_info[] = {
+	/* board_2068_idx */
+	{
+		.sht		= &qs_ata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SATA_RESET |
+				  //FIXME ATA_FLAG_SRST |
+				  ATA_FLAG_MMIO,
+		.pio_mask	= 0x10, /* pio4 */
+		.udma_mask	= 0x7f, /* udma0-6 */
+		.port_ops	= &qs_ata_ops,
+	},
+};
+
+static struct pci_device_id qs_ata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_2068_idx },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver qs_ata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= qs_ata_pci_tbl,
+	.probe			= qs_ata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static int qs_check_atapi_dma(struct ata_queued_cmd *qc)
+{
+	return 1;	/* ATAPI DMA not supported */
+}
+
+static void qs_bmdma_stop(struct ata_port *ap)
+{
+	/* nothing */
+}
+
+static u8 qs_bmdma_status(struct ata_port *ap)
+{
+	return 0;
+}
+
+static void qs_irq_clear(struct ata_port *ap)
+{
+	/* nothing */
+}
+
+static inline void qs_enter_reg_mode(struct ata_port *ap)
+{
+	u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+
+	writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+	readb(chan + QS_CCT_CTR0);        /* flush */
+}
+
+static inline void qs_reset_channel_logic(struct ata_port *ap)
+{
+	u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+
+	writeb(QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+	readb(chan + QS_CCT_CTR0);        /* flush */
+	qs_enter_reg_mode(ap);
+}
+
+static void qs_phy_reset(struct ata_port *ap)
+{
+	struct qs_port_priv *pp = ap->private_data;
+
+	pp->state = qs_state_idle;
+	qs_reset_channel_logic(ap);
+	sata_phy_reset(ap);
+}
+
+static void qs_eng_timeout(struct ata_port *ap)
+{
+	struct qs_port_priv *pp = ap->private_data;
+
+	if (pp->state != qs_state_idle) /* healthy paranoia */
+		pp->state = qs_state_mmio;
+	qs_reset_channel_logic(ap);
+	ata_eng_timeout(ap);
+}
+
+static u32 qs_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return ~0U;
+	return readl((void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+}
+
+static void qs_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8)));
+}
+
+static void qs_fill_sg(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct qs_port_priv *pp = ap->private_data;
+	unsigned int nelem;
+	u8 *prd = pp->pkt + QS_CPB_BYTES;
+
+	assert(sg != NULL);
+	assert(qc->n_elem > 0);
+
+	for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) {
+		u64 addr;
+		u32 len;
+
+		addr = sg_dma_address(sg);
+		*(__le64 *)prd = cpu_to_le64(addr);
+		prd += sizeof(u64);
+
+		len = sg_dma_len(sg);
+		*(__le32 *)prd = cpu_to_le32(len);
+		prd += sizeof(u64);
+
+		VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem,
+					(unsigned long long)addr, len);
+	}
+}
+
+static void qs_qc_prep(struct ata_queued_cmd *qc)
+{
+	struct qs_port_priv *pp = qc->ap->private_data;
+	u8 dflags = QS_DF_PORD, *buf = pp->pkt;
+	u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD;
+	u64 addr;
+
+	VPRINTK("ENTER\n");
+
+	qs_enter_reg_mode(qc->ap);
+	if (qc->tf.protocol != ATA_PROT_DMA) {
+		ata_qc_prep(qc);
+		return;
+	}
+
+	qs_fill_sg(qc);
+
+	if ((qc->tf.flags & ATA_TFLAG_WRITE))
+		hflags |= QS_HF_DIRO;
+	if ((qc->tf.flags & ATA_TFLAG_LBA48))
+		dflags |= QS_DF_ELBA;
+
+	/* host control block (HCB) */
+	buf[ 0] = QS_HCB_HDR;
+	buf[ 1] = hflags;
+	*(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE);
+	*(__le32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem);
+	addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES;
+	*(__le64 *)(&buf[16]) = cpu_to_le64(addr);
+
+	/* device control block (DCB) */
+	buf[24] = QS_DCB_HDR;
+	buf[28] = dflags;
+
+	/* frame information structure (FIS) */
+	ata_tf_to_fis(&qc->tf, &buf[32], 0);
+}
+
+static inline void qs_packet_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	u8 __iomem *chan = ap->host_set->mmio_base + (ap->port_no * 0x4000);
+
+	VPRINTK("ENTER, ap %p\n", ap);
+
+	writeb(QS_CTR0_CLER, chan + QS_CCT_CTR0);
+	wmb();                             /* flush PRDs and pkt to memory */
+	writel(QS_CCF_RUN_PKT, chan + QS_CCT_CFF);
+	readl(chan + QS_CCT_CFF);          /* flush */
+}
+
+static int qs_qc_issue(struct ata_queued_cmd *qc)
+{
+	struct qs_port_priv *pp = qc->ap->private_data;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+
+		pp->state = qs_state_pkt;
+		qs_packet_start(qc);
+		return 0;
+
+	case ATA_PROT_ATAPI_DMA:
+		BUG();
+		break;
+
+	default:
+		break;
+	}
+
+	pp->state = qs_state_mmio;
+	return ata_qc_issue_prot(qc);
+}
+
+static inline unsigned int qs_intr_pkt(struct ata_host_set *host_set)
+{
+	unsigned int handled = 0;
+	u8 sFFE;
+	u8 __iomem *mmio_base = host_set->mmio_base;
+
+	do {
+		u32 sff0 = readl(mmio_base + QS_HST_SFF);
+		u32 sff1 = readl(mmio_base + QS_HST_SFF + 4);
+		u8 sEVLD = (sff1 >> 30) & 0x01;	/* valid flag */
+		sFFE  = sff1 >> 31;		/* empty flag */
+
+		if (sEVLD) {
+			u8 sDST = sff0 >> 16;	/* dev status */
+			u8 sHST = sff1 & 0x3f;	/* host status */
+			unsigned int port_no = (sff1 >> 8) & 0x03;
+			struct ata_port *ap = host_set->ports[port_no];
+
+			DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n",
+					sff1, sff0, port_no, sHST, sDST);
+			handled = 1;
+			if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+				struct ata_queued_cmd *qc;
+				struct qs_port_priv *pp = ap->private_data;
+				if (!pp || pp->state != qs_state_pkt)
+					continue;
+				qc = ata_qc_from_tag(ap, ap->active_tag);
+				if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+					switch (sHST) {
+					case 0: /* sucessful CPB */
+					case 3: /* device error */
+						pp->state = qs_state_idle;
+						qs_enter_reg_mode(qc->ap);
+						ata_qc_complete(qc, sDST);
+						break;
+					default:
+						break;
+					}
+				}
+			}
+		}
+	} while (!sFFE);
+	return handled;
+}
+
+static inline unsigned int qs_intr_mmio(struct ata_host_set *host_set)
+{
+	unsigned int handled = 0, port_no;
+
+	for (port_no = 0; port_no < host_set->n_ports; ++port_no) {
+		struct ata_port *ap;
+		ap = host_set->ports[port_no];
+		if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+			struct qs_port_priv *pp = ap->private_data;
+			if (!pp || pp->state != qs_state_mmio)
+				continue;
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN))) {
+
+				/* check main status, clearing INTRQ */
+				u8 status = ata_chk_status(ap);
+				if ((status & ATA_BUSY))
+					continue;
+				DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n",
+					ap->id, qc->tf.protocol, status);
+		
+				/* complete taskfile transaction */
+				pp->state = qs_state_idle;
+				ata_qc_complete(qc, status);
+				handled = 1;
+			}
+		}
+	}
+	return handled;
+}
+
+static irqreturn_t qs_intr(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int handled = 0;
+
+	VPRINTK("ENTER\n");
+
+	spin_lock(&host_set->lock);
+	handled  = qs_intr_pkt(host_set) | qs_intr_mmio(host_set);
+	spin_unlock(&host_set->lock);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static void qs_ata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		=
+	port->data_addr		= base + 0x400;
+	port->error_addr	=
+	port->feature_addr	= base + 0x408; /* hob_feature = 0x409 */
+	port->nsect_addr	= base + 0x410; /* hob_nsect   = 0x411 */
+	port->lbal_addr		= base + 0x418; /* hob_lbal    = 0x419 */
+	port->lbam_addr		= base + 0x420; /* hob_lbam    = 0x421 */
+	port->lbah_addr		= base + 0x428; /* hob_lbah    = 0x429 */
+	port->device_addr	= base + 0x430;
+	port->status_addr	=
+	port->command_addr	= base + 0x438;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x440;
+	port->scr_addr		= base + 0xc00;
+}
+
+static int qs_port_start(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct qs_port_priv *pp;
+	void __iomem *mmio_base = ap->host_set->mmio_base;
+	void __iomem *chan = mmio_base + (ap->port_no * 0x4000);
+	u64 addr;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+	qs_enter_reg_mode(ap);
+	pp = kcalloc(1, sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	pp->pkt = dma_alloc_coherent(dev, QS_PKT_BYTES, &pp->pkt_dma,
+								GFP_KERNEL);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+	memset(pp->pkt, 0, QS_PKT_BYTES);
+	ap->private_data = pp;
+
+	addr = (u64)pp->pkt_dma;
+	writel((u32) addr,        chan + QS_CCF_CPBA);
+	writel((u32)(addr >> 32), chan + QS_CCF_CPBA + 4);
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+static void qs_port_stop(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct qs_port_priv *pp = ap->private_data;
+
+	if (pp != NULL) {
+		ap->private_data = NULL;
+		if (pp->pkt != NULL)
+			dma_free_coherent(dev, QS_PKT_BYTES, pp->pkt,
+								pp->pkt_dma);
+		kfree(pp);
+	}
+	ata_port_stop(ap);
+}
+
+static void qs_host_stop(struct ata_host_set *host_set)
+{
+	void __iomem *mmio_base = host_set->mmio_base;
+
+	writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+	writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+}
+
+static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe)
+{
+	void __iomem *mmio_base = pe->mmio_base;
+	unsigned int port_no;
+
+	writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */
+	writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */
+
+	/* reset each channel in turn */
+	for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+		u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+		writeb(QS_CTR1_RDEV|QS_CTR1_RCHN, chan + QS_CCT_CTR1);
+		writeb(QS_CTR0_REG, chan + QS_CCT_CTR0);
+		readb(chan + QS_CCT_CTR0);        /* flush */
+	}
+	writeb(QS_SERD3_PHY_ENA, mmio_base + QS_HVS_SERD3); /* enable phy */
+
+	for (port_no = 0; port_no < pe->n_ports; ++port_no) {
+		u8 __iomem *chan = mmio_base + (port_no * 0x4000);
+		/* set FIFO depths to same settings as Windows driver */
+		writew(32, chan + QS_CFC_HUFT);
+		writew(32, chan + QS_CFC_HDFT);
+		writew(10, chan + QS_CFC_DUFT);
+		writew( 8, chan + QS_CFC_DDFT);
+		/* set CPB size in bytes, as a power of two */
+		writeb(QS_CPB_ORDER,    chan + QS_CCF_CSEP);
+	}
+	writeb(1, mmio_base + QS_HCT_CTRL); /* enable host interrupts */
+}
+
+/*
+ * The QStor understands 64-bit buses, and uses 64-bit fields
+ * for DMA pointers regardless of bus width.  We just have to
+ * make sure our DMA masks are set appropriately for whatever
+ * bridge lies between us and the QStor, and then the DMA mapping
+ * code will ensure we only ever "see" appropriate buffer addresses.
+ * If we're 32-bit limited somewhere, then our 64-bit fields will
+ * just end up with zeros in the upper 32-bits, without any special
+ * logic required outside of this routine (below).
+ */
+static int qs_set_dma_masks(struct pci_dev *pdev, void __iomem *mmio_base)
+{
+	u32 bus_info = readl(mmio_base + QS_HID_HPHY);
+	int rc, have_64bit_bus = (bus_info & QS_HPHY_64BIT);
+
+	if (have_64bit_bus &&
+	    !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) {
+		rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK);
+		if (rc) {
+			rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+			if (rc) {
+				printk(KERN_ERR DRV_NAME
+					"(%s): 64-bit DMA enable failed\n",
+					pci_name(pdev));
+				return rc;
+			}
+		}
+	} else {
+		rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME
+				"(%s): 32-bit DMA enable failed\n",
+				pci_name(pdev));
+			return rc;
+		}
+		rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+		if (rc) {
+			printk(KERN_ERR DRV_NAME
+				"(%s): 32-bit consistent DMA enable failed\n",
+				pci_name(pdev));
+			return rc;
+		}
+	}
+	return 0;
+}
+
+static int qs_ata_init_one(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	void __iomem *mmio_base;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int rc, port_no;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc)
+		goto err_out;
+
+	if ((pci_resource_flags(pdev, 4) & IORESOURCE_MEM) == 0) {
+		rc = -ENODEV;
+		goto err_out_regions;
+	}
+
+	mmio_base = ioremap(pci_resource_start(pdev, 4),
+		            pci_resource_len(pdev, 4));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	rc = qs_set_dma_masks(pdev, mmio_base);
+	if (rc)
+		goto err_out_iounmap;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	probe_ent->sht		= qs_port_info[board_idx].sht;
+	probe_ent->host_flags	= qs_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= qs_port_info[board_idx].pio_mask;
+	probe_ent->mwdma_mask	= qs_port_info[board_idx].mwdma_mask;
+	probe_ent->udma_mask	= qs_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= qs_port_info[board_idx].port_ops;
+
+	probe_ent->irq		= pdev->irq;
+	probe_ent->irq_flags	= SA_SHIRQ;
+	probe_ent->mmio_base	= mmio_base;
+	probe_ent->n_ports	= QS_PORTS;
+
+	for (port_no = 0; port_no < probe_ent->n_ports; ++port_no) {
+		unsigned long chan = (unsigned long)mmio_base +
+							(port_no * 0x4000);
+		qs_ata_setup_port(&probe_ent->port[port_no], chan);
+	}
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	qs_host_init(board_idx, probe_ent);
+
+	rc = ata_device_add(probe_ent);
+	kfree(probe_ent);
+	if (rc != QS_PORTS)
+		goto err_out_iounmap;
+	return 0;
+
+err_out_iounmap:
+	iounmap(mmio_base);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	pci_disable_device(pdev);
+	return rc;
+}
+
+static int __init qs_ata_init(void)
+{
+	return pci_module_init(&qs_ata_pci_driver);
+}
+
+static void __exit qs_ata_exit(void)
+{
+	pci_unregister_driver(&qs_ata_pci_driver);
+}
+
+MODULE_AUTHOR("Mark Lord");
+MODULE_DESCRIPTION("Pacific Digital Corporation QStor SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, qs_ata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(qs_ata_init);
+module_exit(qs_ata_exit);
diff --git a/drivers/scsi/sata_sil.c b/drivers/scsi/sata_sil.c
new file mode 100644
index 0000000..f0489dc
--- /dev/null
+++ b/drivers/scsi/sata_sil.c
@@ -0,0 +1,494 @@
+/*
+ *  sata_sil.c - Silicon Image SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003 Red Hat, Inc.
+ *  Copyright 2003 Benjamin Herrenschmidt
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_sil"
+#define DRV_VERSION	"0.9"
+
+enum {
+	sil_3112		= 0,
+	sil_3114		= 1,
+
+	SIL_FIFO_R0		= 0x40,
+	SIL_FIFO_W0		= 0x41,
+	SIL_FIFO_R1		= 0x44,
+	SIL_FIFO_W1		= 0x45,
+	SIL_FIFO_R2		= 0x240,
+	SIL_FIFO_W2		= 0x241,
+	SIL_FIFO_R3		= 0x244,
+	SIL_FIFO_W3		= 0x245,
+
+	SIL_SYSCFG		= 0x48,
+	SIL_MASK_IDE0_INT	= (1 << 22),
+	SIL_MASK_IDE1_INT	= (1 << 23),
+	SIL_MASK_IDE2_INT	= (1 << 24),
+	SIL_MASK_IDE3_INT	= (1 << 25),
+	SIL_MASK_2PORT		= SIL_MASK_IDE0_INT | SIL_MASK_IDE1_INT,
+	SIL_MASK_4PORT		= SIL_MASK_2PORT |
+				  SIL_MASK_IDE2_INT | SIL_MASK_IDE3_INT,
+
+	SIL_IDE2_BMDMA		= 0x200,
+
+	SIL_INTR_STEERING	= (1 << 1),
+	SIL_QUIRK_MOD15WRITE	= (1 << 0),
+	SIL_QUIRK_UDMA5MAX	= (1 << 1),
+};
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev);
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+static void sil_post_set_mode (struct ata_port *ap);
+
+static struct pci_device_id sil_pci_tbl[] = {
+	{ 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 },
+	{ 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 },
+	{ }	/* terminate list */
+};
+
+
+/* TODO firmware versions should be added - eric */
+static const struct sil_drivelist {
+	const char * product;
+	unsigned int quirk;
+} sil_blacklist [] = {
+	{ "ST320012AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST330013AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST340017AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST360015AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST380013AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST380023AS",		SIL_QUIRK_MOD15WRITE },
+	{ "ST3120023AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3160023AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3120026AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3200822AS",	SIL_QUIRK_MOD15WRITE },
+	{ "ST340014ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST360014ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST380011ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3120022ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "ST3160021ASL",	SIL_QUIRK_MOD15WRITE },
+	{ "Maxtor 4D060H3",	SIL_QUIRK_UDMA5MAX },
+	{ }
+};
+
+static struct pci_driver sil_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= sil_pci_tbl,
+	.probe			= sil_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template sil_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations sil_ops = {
+	.port_disable		= ata_port_disable,
+	.dev_config		= sil_dev_config,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.post_set_mode		= sil_post_set_mode,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= sil_scr_read,
+	.scr_write		= sil_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info sil_port_info[] = {
+	/* sil_3112 */
+	{
+		.sht		= &sil_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f,			/* pio0-4 */
+		.mwdma_mask	= 0x07,			/* mwdma0-2 */
+		.udma_mask	= 0x3f,			/* udma0-5 */
+		.port_ops	= &sil_ops,
+	}, /* sil_3114 */
+	{
+		.sht		= &sil_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f,			/* pio0-4 */
+		.mwdma_mask	= 0x07,			/* mwdma0-2 */
+		.udma_mask	= 0x3f,			/* udma0-5 */
+		.port_ops	= &sil_ops,
+	},
+};
+
+/* per-port register offsets */
+/* TODO: we can probably calculate rather than use a table */
+static const struct {
+	unsigned long tf;	/* ATA taskfile register block */
+	unsigned long ctl;	/* ATA control/altstatus register block */
+	unsigned long bmdma;	/* DMA register block */
+	unsigned long scr;	/* SATA control register block */
+	unsigned long sien;	/* SATA Interrupt Enable register */
+	unsigned long xfer_mode;/* data transfer mode register */
+} sil_port[] = {
+	/* port 0 ... */
+	{ 0x80, 0x8A, 0x00, 0x100, 0x148, 0xb4 },
+	{ 0xC0, 0xCA, 0x08, 0x180, 0x1c8, 0xf4 },
+	{ 0x280, 0x28A, 0x200, 0x300, 0x348, 0x2b4 },
+	{ 0x2C0, 0x2CA, 0x208, 0x380, 0x3c8, 0x2f4 },
+	/* ... port 3 */
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("low-level driver for Silicon Image SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sil_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned char sil_get_device_cache_line(struct pci_dev *pdev)
+{
+	u8 cache_line = 0;
+	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cache_line);
+	return cache_line;
+}
+
+static void sil_post_set_mode (struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	struct ata_device *dev;
+	void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode;
+	u32 tmp, dev_mode[2];
+	unsigned int i;
+
+	for (i = 0; i < 2; i++) {
+		dev = &ap->device[i];
+		if (!ata_dev_present(dev))
+			dev_mode[i] = 0;	/* PIO0/1/2 */
+		else if (dev->flags & ATA_DFLAG_PIO)
+			dev_mode[i] = 1;	/* PIO3/4 */
+		else
+			dev_mode[i] = 3;	/* UDMA */
+		/* value 2 indicates MDMA */
+	}
+
+	tmp = readl(addr);
+	tmp &= ~((1<<5) | (1<<4) | (1<<1) | (1<<0));
+	tmp |= dev_mode[0];
+	tmp |= (dev_mode[1] << 4);
+	writel(tmp, addr);
+	readl(addr);	/* flush */
+}
+
+static inline unsigned long sil_scr_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+	unsigned long offset = ap->ioaddr.scr_addr;
+
+	switch (sc_reg) {
+	case SCR_STATUS:
+		return offset + 4;
+	case SCR_ERROR:
+		return offset + 8;
+	case SCR_CONTROL:
+		return offset;
+	default:
+		/* do nothing */
+		break;
+	}
+
+	return 0;
+}
+
+static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	void *mmio = (void *) sil_scr_addr(ap, sc_reg);
+	if (mmio)
+		return readl(mmio);
+	return 0xffffffffU;
+}
+
+static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	void *mmio = (void *) sil_scr_addr(ap, sc_reg);
+	if (mmio)
+		writel(val, mmio);
+}
+
+/**
+ *	sil_dev_config - Apply device/host-specific errata fixups
+ *	@ap: Port containing device to be examined
+ *	@dev: Device to be examined
+ *
+ *	After the IDENTIFY [PACKET] DEVICE step is complete, and a
+ *	device is known to be present, this function is called.
+ *	We apply two errata fixups which are specific to Silicon Image,
+ *	a Seagate and a Maxtor fixup.
+ *
+ *	For certain Seagate devices, we must limit the maximum sectors
+ *	to under 8K.
+ *
+ *	For certain Maxtor devices, we must not program the drive
+ *	beyond udma5.
+ *
+ *	Both fixups are unfairly pessimistic.  As soon as I get more
+ *	information on these errata, I will create a more exhaustive
+ *	list, and apply the fixups to only the specific
+ *	devices/hosts/firmwares that need it.
+ *
+ *	20040111 - Seagate drives affected by the Mod15Write bug are blacklisted
+ *	The Maxtor quirk is in the blacklist, but I'm keeping the original
+ *	pessimistic fix for the following reasons...
+ *	- There seems to be less info on it, only one device gleaned off the
+ *	Windows	driver, maybe only one is affected.  More info would be greatly
+ *	appreciated.
+ *	- But then again UDMA5 is hardly anything to complain about
+ */
+static void sil_dev_config(struct ata_port *ap, struct ata_device *dev)
+{
+	unsigned int n, quirks = 0;
+	unsigned char model_num[40];
+	const char *s;
+	unsigned int len;
+
+	ata_dev_id_string(dev->id, model_num, ATA_ID_PROD_OFS,
+			  sizeof(model_num));
+	s = &model_num[0];
+	len = strnlen(s, sizeof(model_num));
+
+	/* ATAPI specifies that empty space is blank-filled; remove blanks */
+	while ((len > 0) && (s[len - 1] == ' '))
+		len--;
+
+	for (n = 0; sil_blacklist[n].product; n++) 
+		if (!memcmp(sil_blacklist[n].product, s,
+			    strlen(sil_blacklist[n].product))) {
+			quirks = sil_blacklist[n].quirk;
+			break;
+		}
+	
+	/* limit requests to 15 sectors */
+	if (quirks & SIL_QUIRK_MOD15WRITE) {
+		printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n",
+		       ap->id, dev->devno);
+		ap->host->max_sectors = 15;
+		ap->host->hostt->max_sectors = 15;
+		dev->flags |= ATA_DFLAG_LOCK_SECTORS;
+		return;
+	}
+
+	/* limit to udma5 */
+	if (quirks & SIL_QUIRK_UDMA5MAX) {
+		printk(KERN_INFO "ata%u(%u): applying Maxtor errata fix %s\n",
+		       ap->id, dev->devno, s);
+		ap->udma_mask &= ATA_UDMA5;
+		return;
+	}
+}
+
+static int sil_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int rc;
+	unsigned int i;
+	int pci_dev_busy = 0;
+	u32 tmp, irq_mask;
+	u8 cls;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	INIT_LIST_HEAD(&probe_ent->node);
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	probe_ent->port_ops = sil_port_info[ent->driver_data].port_ops;
+	probe_ent->sht = sil_port_info[ent->driver_data].sht;
+	probe_ent->n_ports = (ent->driver_data == sil_3114) ? 4 : 2;
+	probe_ent->pio_mask = sil_port_info[ent->driver_data].pio_mask;
+	probe_ent->mwdma_mask = sil_port_info[ent->driver_data].mwdma_mask;
+	probe_ent->udma_mask = sil_port_info[ent->driver_data].udma_mask;
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags;
+
+	mmio_base = ioremap(pci_resource_start(pdev, 5),
+		            pci_resource_len(pdev, 5));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+
+	probe_ent->mmio_base = mmio_base;
+
+	base = (unsigned long) mmio_base;
+
+	for (i = 0; i < probe_ent->n_ports; i++) {
+		probe_ent->port[i].cmd_addr = base + sil_port[i].tf;
+		probe_ent->port[i].altstatus_addr =
+		probe_ent->port[i].ctl_addr = base + sil_port[i].ctl;
+		probe_ent->port[i].bmdma_addr = base + sil_port[i].bmdma;
+		probe_ent->port[i].scr_addr = base + sil_port[i].scr;
+		ata_std_ports(&probe_ent->port[i]);
+	}
+
+	/* Initialize FIFO PCI bus arbitration */
+	cls = sil_get_device_cache_line(pdev);
+	if (cls) {
+		cls >>= 3;
+		cls++;  /* cls = (line_size/8)+1 */
+		writeb(cls, mmio_base + SIL_FIFO_R0);
+		writeb(cls, mmio_base + SIL_FIFO_W0);
+		writeb(cls, mmio_base + SIL_FIFO_R1);
+		writeb(cls, mmio_base + SIL_FIFO_W2);
+	} else
+		printk(KERN_WARNING DRV_NAME "(%s): cache line size not set.  Driver may not function\n",
+			pci_name(pdev));
+
+	if (ent->driver_data == sil_3114) {
+		irq_mask = SIL_MASK_4PORT;
+
+		/* flip the magic "make 4 ports work" bit */
+		tmp = readl(mmio_base + SIL_IDE2_BMDMA);
+		if ((tmp & SIL_INTR_STEERING) == 0)
+			writel(tmp | SIL_INTR_STEERING,
+			       mmio_base + SIL_IDE2_BMDMA);
+
+	} else {
+		irq_mask = SIL_MASK_2PORT;
+	}
+
+	/* make sure IDE0/1/2/3 interrupts are not masked */
+	tmp = readl(mmio_base + SIL_SYSCFG);
+	if (tmp & irq_mask) {
+		tmp &= ~irq_mask;
+		writel(tmp, mmio_base + SIL_SYSCFG);
+		readl(mmio_base + SIL_SYSCFG);	/* flush */
+	}
+
+	/* mask all SATA phy-related interrupts */
+	/* TODO: unmask bit 6 (SError N bit) for hotplug */
+	for (i = 0; i < probe_ent->n_ports; i++)
+		writel(0, mmio_base + sil_port[i].sien);
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+static int __init sil_init(void)
+{
+	return pci_module_init(&sil_pci_driver);
+}
+
+static void __exit sil_exit(void)
+{
+	pci_unregister_driver(&sil_pci_driver);
+}
+
+
+module_init(sil_init);
+module_exit(sil_exit);
diff --git a/drivers/scsi/sata_sis.c b/drivers/scsi/sata_sis.c
new file mode 100644
index 0000000..5105ddd
--- /dev/null
+++ b/drivers/scsi/sata_sis.c
@@ -0,0 +1,286 @@
+/*
+ *  sata_sis.c - Silicon Integrated Systems SATA
+ *
+ *  Maintained by:  Uwe Koziolek
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2004 Uwe Koziolek
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_sis"
+#define DRV_VERSION	"0.5"
+
+enum {
+	sis_180			= 0,
+	SIS_SCR_PCI_BAR		= 5,
+
+	/* PCI configuration registers */
+	SIS_GENCTL		= 0x54, /* IDE General Control register */
+	SIS_SCR_BASE		= 0xc0, /* sata0 phy SCR registers */
+	SIS_SATA1_OFS		= 0x10, /* offset from sata0->sata1 phy regs */
+
+	/* random bits */
+	SIS_FLAG_CFGSCR		= (1 << 30), /* host flag: SCRs via PCI cfg */
+
+	GENCTL_IOMAPPED_SCR	= (1 << 26), /* if set, SCRs are in IO space */
+};
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static struct pci_device_id sis_pci_tbl[] = {
+	{ PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver sis_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= sis_pci_tbl,
+	.probe			= sis_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template sis_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= ATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations sis_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= sis_scr_read,
+	.scr_write		= sis_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info sis_port_info = {
+	.sht		= &sis_sht,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x7,
+	.udma_mask	= 0x7f,
+	.port_ops	= &sis_ops,
+};
+
+
+MODULE_AUTHOR("Uwe Koziolek");
+MODULE_DESCRIPTION("low-level driver for Silicon Integratad Systems SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, sis_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg)
+{
+	unsigned int addr = SIS_SCR_BASE + (4 * sc_reg);
+
+	if (port_no)
+		addr += SIS_SATA1_OFS;
+	return addr;
+}
+
+static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg);
+	u32 val;
+
+	if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return 0xffffffff;
+	pci_read_config_dword(pdev, cfg_addr, &val);
+	return val;
+}
+
+static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr);
+
+	if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */
+		return;
+	pci_write_config_dword(pdev, cfg_addr, val);
+}
+
+static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	if (ap->flags & SIS_FLAG_CFGSCR)
+		return sis_scr_cfg_read(ap, sc_reg);
+	return inl(ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+
+	if (ap->flags & SIS_FLAG_CFGSCR)
+		sis_scr_cfg_write(ap, sc_reg, val);
+	else
+		outl(val, ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct ata_probe_ent *probe_ent = NULL;
+	int rc;
+	u32 genctl;
+	struct ata_port_info *ppi;
+	int pci_dev_busy = 0;
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	ppi = &sis_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	/* check and see if the SCRs are in IO space or PCI cfg space */
+	pci_read_config_dword(pdev, SIS_GENCTL, &genctl);
+	if ((genctl & GENCTL_IOMAPPED_SCR) == 0)
+		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+	
+	/* if hardware thinks SCRs are in IO space, but there are
+	 * no IO resources assigned, change to PCI cfg space.
+	 */
+	if ((!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) &&
+	    ((pci_resource_start(pdev, SIS_SCR_PCI_BAR) == 0) ||
+	     (pci_resource_len(pdev, SIS_SCR_PCI_BAR) < 128))) {
+		genctl &= ~GENCTL_IOMAPPED_SCR;
+		pci_write_config_dword(pdev, SIS_GENCTL, genctl);
+		probe_ent->host_flags |= SIS_FLAG_CFGSCR;
+	}
+
+	if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) {
+		probe_ent->port[0].scr_addr =
+			pci_resource_start(pdev, SIS_SCR_PCI_BAR);
+		probe_ent->port[1].scr_addr =
+			pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64;
+	}
+
+	pci_set_master(pdev);
+	pci_enable_intx(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+
+}
+
+static int __init sis_init(void)
+{
+	return pci_module_init(&sis_pci_driver);
+}
+
+static void __exit sis_exit(void)
+{
+	pci_unregister_driver(&sis_pci_driver);
+}
+
+module_init(sis_init);
+module_exit(sis_exit);
+
diff --git a/drivers/scsi/sata_svw.c b/drivers/scsi/sata_svw.c
new file mode 100644
index 0000000..8d1a5d2
--- /dev/null
+++ b/drivers/scsi/sata_svw.c
@@ -0,0 +1,483 @@
+/*
+ *  sata_svw.c - ServerWorks / Apple K2 SATA
+ *
+ *  Maintained by: Benjamin Herrenschmidt <benh@kernel.crashing.org> and
+ *		   Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  This driver probably works with non-Apple versions of the
+ *  Broadcom chipset...
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#ifdef CONFIG_PPC_OF
+#include <asm/prom.h>
+#include <asm/pci-bridge.h>
+#endif /* CONFIG_PPC_OF */
+
+#define DRV_NAME	"sata_svw"
+#define DRV_VERSION	"1.05"
+
+/* Taskfile registers offsets */
+#define K2_SATA_TF_CMD_OFFSET		0x00
+#define K2_SATA_TF_DATA_OFFSET		0x00
+#define K2_SATA_TF_ERROR_OFFSET		0x04
+#define K2_SATA_TF_NSECT_OFFSET		0x08
+#define K2_SATA_TF_LBAL_OFFSET		0x0c
+#define K2_SATA_TF_LBAM_OFFSET		0x10
+#define K2_SATA_TF_LBAH_OFFSET		0x14
+#define K2_SATA_TF_DEVICE_OFFSET	0x18
+#define K2_SATA_TF_CMDSTAT_OFFSET      	0x1c
+#define K2_SATA_TF_CTL_OFFSET		0x20
+
+/* DMA base */
+#define K2_SATA_DMA_CMD_OFFSET		0x30
+
+/* SCRs base */
+#define K2_SATA_SCR_STATUS_OFFSET	0x40
+#define K2_SATA_SCR_ERROR_OFFSET	0x44
+#define K2_SATA_SCR_CONTROL_OFFSET	0x48
+
+/* Others */
+#define K2_SATA_SICR1_OFFSET		0x80
+#define K2_SATA_SICR2_OFFSET		0x84
+#define K2_SATA_SIM_OFFSET		0x88
+
+/* Port stride */
+#define K2_SATA_PORT_OFFSET		0x100
+
+
+static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	if (tf->ctl != ap->last_ctl) {
+		writeb(tf->ctl, ioaddr->ctl_addr);
+		ap->last_ctl = tf->ctl;
+		ata_wait_idle(ap);
+	}
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+	} else if (is_addr) {
+		writew(tf->feature, ioaddr->feature_addr);
+		writew(tf->nsect, ioaddr->nsect_addr);
+		writew(tf->lbal, ioaddr->lbal_addr);
+		writew(tf->lbam, ioaddr->lbam_addr);
+		writew(tf->lbah, ioaddr->lbah_addr);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		writeb(tf->device, ioaddr->device_addr);
+
+	ata_wait_idle(ap);
+}
+
+
+static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u16 nsect, lbal, lbam, lbah;
+
+	nsect = tf->nsect = readw(ioaddr->nsect_addr);
+	lbal = tf->lbal = readw(ioaddr->lbal_addr);
+	lbam = tf->lbam = readw(ioaddr->lbam_addr);
+	lbah = tf->lbah = readw(ioaddr->lbah_addr);
+	tf->device = readw(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		tf->hob_feature = readw(ioaddr->error_addr) >> 8;
+		tf->hob_nsect = nsect >> 8;
+		tf->hob_lbal = lbal >> 8;
+		tf->hob_lbam = lbam >> 8;
+		tf->hob_lbah = lbah >> 8;
+        }
+}
+
+/**
+ *	k2_bmdma_setup_mmio - Set up PCI IDE BMDMA transaction (MMIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void k2_bmdma_setup_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 dmactl;
+	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	/* load PRD table addr. */
+	mb();	/* make sure PRD table writes are visible to controller */
+	writel(ap->prd_dma, mmio + ATA_DMA_TABLE_OFS);
+
+	/* specify data direction, triple-check start bit is clear */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	dmactl &= ~(ATA_DMA_WR | ATA_DMA_START);
+	if (!rw)
+		dmactl |= ATA_DMA_WR;
+	writeb(dmactl, mmio + ATA_DMA_CMD);
+
+	/* issue r/w command if this is not a ATA DMA command*/
+	if (qc->tf.protocol != ATA_PROT_DMA)
+		ap->ops->exec_command(ap, &qc->tf);
+}
+
+/**
+ *	k2_bmdma_start_mmio - Start a PCI IDE BMDMA transaction (MMIO)
+ *	@qc: Info associated with this ATA transaction.
+ *
+ *	LOCKING:
+ *	spin_lock_irqsave(host_set lock)
+ */
+
+static void k2_bmdma_start_mmio (struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	void *mmio = (void *) ap->ioaddr.bmdma_addr;
+	u8 dmactl;
+
+	/* start host DMA transaction */
+	dmactl = readb(mmio + ATA_DMA_CMD);
+	writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD);
+	/* There is a race condition in certain SATA controllers that can 
+	   be seen when the r/w command is given to the controller before the 
+	   host DMA is started. On a Read command, the controller would initiate
+	   the command to the drive even before it sees the DMA start. When there
+	   are very fast drives connected to the controller, or when the data request 
+	   hits in the drive cache, there is the possibility that the drive returns a part
+	   or all of the requested data to the controller before the DMA start is issued.
+	   In this case, the controller would become confused as to what to do with the data.
+	   In the worst case when all the data is returned back to the controller, the
+	   controller could hang. In other cases it could return partial data returning
+	   in data corruption. This problem has been seen in PPC systems and can also appear
+	   on an system with very fast disks, where the SATA controller is sitting behind a 
+	   number of bridges, and hence there is significant latency between the r/w command
+	   and the start command. */
+	/* issue r/w command if the access is to ATA*/
+	if (qc->tf.protocol == ATA_PROT_DMA)
+		ap->ops->exec_command(ap, &qc->tf);
+}
+
+									      
+static u8 k2_stat_check_status(struct ata_port *ap)
+{
+       	return readl((void *) ap->ioaddr.status_addr);
+}
+
+#ifdef CONFIG_PPC_OF
+/*
+ * k2_sata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the
+ *	   variables
+ * buffer: If inout==FALSE data is being written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file
+ *	   from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer
+ *	   else number of bytes in the buffer
+ */
+static int k2_sata_proc_info(struct Scsi_Host *shost, char *page, char **start,
+			     off_t offset, int count, int inout)
+{
+	struct ata_port *ap;
+	struct device_node *np;
+	int len, index;
+
+	/* Find  the ata_port */
+	ap = (struct ata_port *) &shost->hostdata[0];
+	if (ap == NULL)
+		return 0;
+
+	/* Find the OF node for the PCI device proper */
+	np = pci_device_to_OF_node(to_pci_dev(ap->host_set->dev));
+	if (np == NULL)
+		return 0;
+
+	/* Match it to a port node */
+	index = (ap == ap->host_set->ports[0]) ? 0 : 1;
+	for (np = np->child; np != NULL; np = np->sibling) {
+		u32 *reg = (u32 *)get_property(np, "reg", NULL);
+		if (!reg)
+			continue;
+		if (index == *reg)
+			break;
+	}
+	if (np == NULL)
+		return 0;
+
+	len = sprintf(page, "devspec: %s\n", np->full_name);
+
+	return len;
+}
+#endif /* CONFIG_PPC_OF */
+
+
+static Scsi_Host_Template k2_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+#ifdef CONFIG_PPC_OF
+	.proc_info		= k2_sata_proc_info,
+#endif
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+
+static struct ata_port_operations k2_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= k2_sata_tf_load,
+	.tf_read		= k2_sata_tf_read,
+	.check_status		= k2_stat_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup		= k2_bmdma_setup_mmio,
+	.bmdma_start		= k2_bmdma_start_mmio,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= k2_sata_scr_read,
+	.scr_write		= k2_sata_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base + K2_SATA_TF_CMD_OFFSET;
+	port->data_addr		= base + K2_SATA_TF_DATA_OFFSET;
+	port->feature_addr	=
+	port->error_addr	= base + K2_SATA_TF_ERROR_OFFSET;
+	port->nsect_addr	= base + K2_SATA_TF_NSECT_OFFSET;
+	port->lbal_addr		= base + K2_SATA_TF_LBAL_OFFSET;
+	port->lbam_addr		= base + K2_SATA_TF_LBAM_OFFSET;
+	port->lbah_addr		= base + K2_SATA_TF_LBAH_OFFSET;
+	port->device_addr	= base + K2_SATA_TF_DEVICE_OFFSET;
+	port->command_addr	=
+	port->status_addr	= base + K2_SATA_TF_CMDSTAT_OFFSET;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + K2_SATA_TF_CTL_OFFSET;
+	port->bmdma_addr	= base + K2_SATA_DMA_CMD_OFFSET;
+	port->scr_addr		= base + K2_SATA_SCR_STATUS_OFFSET;
+}
+
+
+static int k2_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base;
+	int pci_dev_busy = 0;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+	/*
+	 * Check if we have resources mapped at all (second function may
+	 * have been disabled by firmware)
+	 */
+	if (pci_resource_len(pdev, 5) == 0)
+		return -ENODEV;
+
+	/* Request PCI regions */
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 5),
+		            pci_resource_len(pdev, 5));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	/* Clear a magic bit in SCR1 according to Darwin, those help
+	 * some funky seagate drives (though so far, those were already
+	 * set by the firmware on the machines I had access to
+	 */
+	writel(readl(mmio_base + K2_SATA_SICR1_OFFSET) & ~0x00040000,
+	       mmio_base + K2_SATA_SICR1_OFFSET);
+
+	/* Clear SATA error & interrupts we don't use */
+	writel(0xffffffff, mmio_base + K2_SATA_SCR_ERROR_OFFSET);
+	writel(0x0, mmio_base + K2_SATA_SIM_OFFSET);
+
+	probe_ent->sht = &k2_sata_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+				ATA_FLAG_NO_LEGACY | ATA_FLAG_MMIO;
+	probe_ent->port_ops = &k2_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x7;
+	probe_ent->udma_mask = 0x7f;
+
+	/* We have 4 ports per PCI function */
+	k2_sata_setup_port(&probe_ent->port[0], base + 0 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[1], base + 1 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[2], base + 2 * K2_SATA_PORT_OFFSET);
+	k2_sata_setup_port(&probe_ent->port[3], base + 3 * K2_SATA_PORT_OFFSET);
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+
+static struct pci_device_id k2_sata_pci_tbl[] = {
+	{ 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+
+
+static struct pci_driver k2_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= k2_sata_pci_tbl,
+	.probe			= k2_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int __init k2_sata_init(void)
+{
+	return pci_module_init(&k2_sata_pci_driver);
+}
+
+
+static void __exit k2_sata_exit(void)
+{
+	pci_unregister_driver(&k2_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Benjamin Herrenschmidt");
+MODULE_DESCRIPTION("low-level driver for K2 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, k2_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(k2_sata_init);
+module_exit(k2_sata_exit);
diff --git a/drivers/scsi/sata_sx4.c b/drivers/scsi/sata_sx4.c
new file mode 100644
index 0000000..7011865
--- /dev/null
+++ b/drivers/scsi/sata_sx4.c
@@ -0,0 +1,1503 @@
+/*
+ *  sata_sx4.c - Promise SATA
+ *
+ *  Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+ *  		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2003-2004 Red Hat, Inc.
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+#include "sata_promise.h"
+
+#define DRV_NAME	"sata_sx4"
+#define DRV_VERSION	"0.7"
+
+
+enum {
+	PDC_PRD_TBL		= 0x44,	/* Direct command DMA table addr */
+
+	PDC_PKT_SUBMIT		= 0x40, /* Command packet pointer addr */
+	PDC_HDMA_PKT_SUBMIT	= 0x100, /* Host DMA packet pointer addr */
+	PDC_INT_SEQMASK		= 0x40,	/* Mask of asserted SEQ INTs */
+	PDC_HDMA_CTLSTAT	= 0x12C, /* Host DMA control / status */
+
+	PDC_20621_SEQCTL	= 0x400,
+	PDC_20621_SEQMASK	= 0x480,
+	PDC_20621_GENERAL_CTL	= 0x484,
+	PDC_20621_PAGE_SIZE	= (32 * 1024),
+
+	/* chosen, not constant, values; we design our own DIMM mem map */
+	PDC_20621_DIMM_WINDOW	= 0x0C,	/* page# for 32K DIMM window */
+	PDC_20621_DIMM_BASE	= 0x00200000,
+	PDC_20621_DIMM_DATA	= (64 * 1024),
+	PDC_DIMM_DATA_STEP	= (256 * 1024),
+	PDC_DIMM_WINDOW_STEP	= (8 * 1024),
+	PDC_DIMM_HOST_PRD	= (6 * 1024),
+	PDC_DIMM_HOST_PKT	= (128 * 0),
+	PDC_DIMM_HPKT_PRD	= (128 * 1),
+	PDC_DIMM_ATA_PKT	= (128 * 2),
+	PDC_DIMM_APKT_PRD	= (128 * 3),
+	PDC_DIMM_HEADER_SZ	= PDC_DIMM_APKT_PRD + 128,
+	PDC_PAGE_WINDOW		= 0x40,
+	PDC_PAGE_DATA		= PDC_PAGE_WINDOW +
+				  (PDC_20621_DIMM_DATA / PDC_20621_PAGE_SIZE),
+	PDC_PAGE_SET		= PDC_DIMM_DATA_STEP / PDC_20621_PAGE_SIZE,
+
+	PDC_CHIP0_OFS		= 0xC0000, /* offset of chip #0 */
+
+	PDC_20621_ERR_MASK	= (1<<19) | (1<<20) | (1<<21) | (1<<22) |
+				  (1<<23),
+
+	board_20621		= 0,	/* FastTrak S150 SX4 */
+
+	PDC_RESET		= (1 << 11), /* HDMA reset */
+
+	PDC_MAX_HDMA		= 32,
+	PDC_HDMA_Q_MASK		= (PDC_MAX_HDMA - 1),
+
+	PDC_DIMM0_SPD_DEV_ADDRESS     = 0x50,
+	PDC_DIMM1_SPD_DEV_ADDRESS     = 0x51,
+	PDC_MAX_DIMM_MODULE           = 0x02,
+	PDC_I2C_CONTROL_OFFSET        = 0x48,
+	PDC_I2C_ADDR_DATA_OFFSET      = 0x4C,
+	PDC_DIMM0_CONTROL_OFFSET      = 0x80,
+	PDC_DIMM1_CONTROL_OFFSET      = 0x84,
+	PDC_SDRAM_CONTROL_OFFSET      = 0x88,
+	PDC_I2C_WRITE                 = 0x00000000,
+	PDC_I2C_READ                  = 0x00000040,	
+	PDC_I2C_START                 = 0x00000080,
+	PDC_I2C_MASK_INT              = 0x00000020,
+	PDC_I2C_COMPLETE              = 0x00010000,
+	PDC_I2C_NO_ACK                = 0x00100000,
+	PDC_DIMM_SPD_SUBADDRESS_START = 0x00,
+	PDC_DIMM_SPD_SUBADDRESS_END   = 0x7F,
+	PDC_DIMM_SPD_ROW_NUM          = 3,
+	PDC_DIMM_SPD_COLUMN_NUM       = 4,
+	PDC_DIMM_SPD_MODULE_ROW       = 5,
+	PDC_DIMM_SPD_TYPE             = 11,
+	PDC_DIMM_SPD_FRESH_RATE       = 12,         
+	PDC_DIMM_SPD_BANK_NUM         = 17,	
+	PDC_DIMM_SPD_CAS_LATENCY      = 18,
+	PDC_DIMM_SPD_ATTRIBUTE        = 21,    
+	PDC_DIMM_SPD_ROW_PRE_CHARGE   = 27,
+	PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28,      
+	PDC_DIMM_SPD_RAS_CAS_DELAY    = 29,
+	PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30,
+	PDC_DIMM_SPD_SYSTEM_FREQ      = 126,
+	PDC_CTL_STATUS		      = 0x08,	
+	PDC_DIMM_WINDOW_CTLR	      = 0x0C,
+	PDC_TIME_CONTROL              = 0x3C,
+	PDC_TIME_PERIOD               = 0x40,
+	PDC_TIME_COUNTER              = 0x44,
+	PDC_GENERAL_CTLR	      = 0x484,
+	PCI_PLL_INIT                  = 0x8A531824,
+	PCI_X_TCOUNT                  = 0xEE1E5CFF
+};
+
+
+struct pdc_port_priv {
+	u8			dimm_buf[(ATA_PRD_SZ * ATA_MAX_PRD) + 512];
+	u8			*pkt;
+	dma_addr_t		pkt_dma;
+};
+
+struct pdc_host_priv {
+	void			*dimm_mmio;
+
+	unsigned int		doing_hdma;
+	unsigned int		hdma_prod;
+	unsigned int		hdma_cons;
+	struct {
+		struct ata_queued_cmd *qc;
+		unsigned int	seq;
+		unsigned long	pkt_ofs;
+	} hdma[32];
+};
+
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs);
+static void pdc_eng_timeout(struct ata_port *ap);
+static void pdc_20621_phy_reset (struct ata_port *ap);
+static int pdc_port_start(struct ata_port *ap);
+static void pdc_port_stop(struct ata_port *ap);
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc);
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf);
+static void pdc20621_host_stop(struct ata_host_set *host_set);
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe);
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe);
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, 
+				      u32 device, u32 subaddr, u32 *pdata);
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe);
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe);
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, 
+				   void *psource, u32 offset, u32 size);
+#endif
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, 
+				 void *psource, u32 offset, u32 size);
+static void pdc20621_irq_clear(struct ata_port *ap);
+static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc);
+
+
+static Scsi_Host_Template pdc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations pdc_20621_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= pdc_tf_load_mmio,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= pdc_exec_command_mmio,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= pdc_20621_phy_reset,
+	.qc_prep		= pdc20621_qc_prep,
+	.qc_issue		= pdc20621_qc_issue_prot,
+	.eng_timeout		= pdc_eng_timeout,
+	.irq_handler		= pdc20621_interrupt,
+	.irq_clear		= pdc20621_irq_clear,
+	.port_start		= pdc_port_start,
+	.port_stop		= pdc_port_stop,
+	.host_stop		= pdc20621_host_stop,
+};
+
+static struct ata_port_info pdc_port_info[] = {
+	/* board_20621 */
+	{
+		.sht		= &pdc_sata_sht,
+		.host_flags	= ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				  ATA_FLAG_SRST | ATA_FLAG_MMIO,
+		.pio_mask	= 0x1f, /* pio0-4 */
+		.mwdma_mask	= 0x07, /* mwdma0-2 */
+		.udma_mask	= 0x7f, /* udma0-6 ; FIXME */
+		.port_ops	= &pdc_20621_ops,
+	},
+
+};
+
+static struct pci_device_id pdc_sata_pci_tbl[] = {
+	{ PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+	  board_20621 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver pdc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= pdc_sata_pci_tbl,
+	.probe			= pdc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static void pdc20621_host_stop(struct ata_host_set *host_set)
+{
+	struct pdc_host_priv *hpriv = host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	iounmap(dimm_mmio);
+	kfree(hpriv);
+}
+
+static int pdc_port_start(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct pdc_port_priv *pp;
+	int rc;
+
+	rc = ata_port_start(ap);
+	if (rc)
+		return rc;
+
+	pp = kmalloc(sizeof(*pp), GFP_KERNEL);
+	if (!pp) {
+		rc = -ENOMEM;
+		goto err_out;
+	}
+	memset(pp, 0, sizeof(*pp));
+
+	pp->pkt = dma_alloc_coherent(dev, 128, &pp->pkt_dma, GFP_KERNEL);
+	if (!pp->pkt) {
+		rc = -ENOMEM;
+		goto err_out_kfree;
+	}
+
+	ap->private_data = pp;
+
+	return 0;
+
+err_out_kfree:
+	kfree(pp);
+err_out:
+	ata_port_stop(ap);
+	return rc;
+}
+
+
+static void pdc_port_stop(struct ata_port *ap)
+{
+	struct device *dev = ap->host_set->dev;
+	struct pdc_port_priv *pp = ap->private_data;
+
+	ap->private_data = NULL;
+	dma_free_coherent(dev, 128, pp->pkt, pp->pkt_dma);
+	kfree(pp);
+	ata_port_stop(ap);
+}
+
+
+static void pdc_20621_phy_reset (struct ata_port *ap)
+{
+	VPRINTK("ENTER\n");
+        ap->cbl = ATA_CBL_SATA;
+        ata_port_probe(ap);
+        ata_bus_reset(ap);
+}
+
+static inline void pdc20621_ata_sg(struct ata_taskfile *tf, u8 *buf,
+				    	   unsigned int portno,
+					   unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_APKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output ATA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+	VPRINTK("ATA sg addr 0x%x, %d\n", addr, addr);
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("ATA PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_APKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline void pdc20621_host_sg(struct ata_taskfile *tf, u8 *buf,
+				    	    unsigned int portno,
+					    unsigned int total_len)
+{
+	u32 addr;
+	unsigned int dw = PDC_DIMM_HPKT_PRD >> 2;
+	u32 *buf32 = (u32 *) buf;
+
+	/* output Host DMA packet S/G table */
+	addr = PDC_20621_DIMM_BASE + PDC_20621_DIMM_DATA +
+	       (PDC_DIMM_DATA_STEP * portno);
+
+	buf32[dw] = cpu_to_le32(addr);
+	buf32[dw + 1] = cpu_to_le32(total_len | ATA_PRD_EOT);
+
+	VPRINTK("HOST PSG @ %x == (0x%x, 0x%x)\n",
+		PDC_20621_DIMM_BASE +
+		       (PDC_DIMM_WINDOW_STEP * portno) +
+		       PDC_DIMM_HPKT_PRD,
+		buf32[dw], buf32[dw + 1]);
+}
+
+static inline unsigned int pdc20621_ata_pkt(struct ata_taskfile *tf,
+					    unsigned int devno, u8 *buf,
+					    unsigned int portno)
+{
+	unsigned int i, dw;
+	u32 *buf32 = (u32 *) buf;
+	u8 dev_reg;
+
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_APKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+
+	i = PDC_DIMM_ATA_PKT;
+
+	/*
+	 * Set up ATA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		buf[i++] = PDC_PKT_READ;
+	else if (tf->protocol == ATA_PROT_NODATA)
+		buf[i++] = PDC_PKT_NODATA;
+	else
+		buf[i++] = 0;
+	buf[i++] = 0;			/* reserved */
+	buf[i++] = portno + 1;		/* seq. id */
+	buf[i++] = 0xff;		/* delay seq. id */
+
+	/* dimm dma S/G, and next-pkt */
+	dw = i >> 2;
+	if (tf->protocol == ATA_PROT_NODATA)
+		buf32[dw] = 0;
+	else
+		buf32[dw] = cpu_to_le32(dimm_sg);
+	buf32[dw + 1] = 0;
+	i += 8;
+
+	if (devno == 0)
+		dev_reg = ATA_DEVICE_OBS;
+	else
+		dev_reg = ATA_DEVICE_OBS | ATA_DEV1;
+
+	/* select device */
+	buf[i++] = (1 << 5) | PDC_PKT_CLEAR_BSY | ATA_REG_DEVICE;
+	buf[i++] = dev_reg;
+
+	/* device control register */
+	buf[i++] = (1 << 5) | PDC_REG_DEVCTL;
+	buf[i++] = tf->ctl;
+
+	return i;
+}
+
+static inline void pdc20621_host_pkt(struct ata_taskfile *tf, u8 *buf,
+				     unsigned int portno)
+{
+	unsigned int dw;
+	u32 tmp, *buf32 = (u32 *) buf;
+
+	unsigned int host_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HOST_PRD;
+	unsigned int dimm_sg = PDC_20621_DIMM_BASE +
+			       (PDC_DIMM_WINDOW_STEP * portno) +
+			       PDC_DIMM_HPKT_PRD;
+	VPRINTK("ENTER, dimm_sg == 0x%x, %d\n", dimm_sg, dimm_sg);
+	VPRINTK("host_sg == 0x%x, %d\n", host_sg, host_sg);
+
+	dw = PDC_DIMM_HOST_PKT >> 2;
+
+	/*
+	 * Set up Host DMA packet
+	 */
+	if ((tf->protocol == ATA_PROT_DMA) && (!(tf->flags & ATA_TFLAG_WRITE)))
+		tmp = PDC_PKT_READ;
+	else
+		tmp = 0;
+	tmp |= ((portno + 1 + 4) << 16);	/* seq. id */
+	tmp |= (0xff << 24);			/* delay seq. id */
+	buf32[dw + 0] = cpu_to_le32(tmp);
+	buf32[dw + 1] = cpu_to_le32(host_sg);
+	buf32[dw + 2] = cpu_to_le32(dimm_sg);
+	buf32[dw + 3] = 0;
+
+	VPRINTK("HOST PKT @ %x == (0x%x 0x%x 0x%x 0x%x)\n",
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * portno) +
+			PDC_DIMM_HOST_PKT,
+		buf32[dw + 0],
+		buf32[dw + 1],
+		buf32[dw + 2],
+		buf32[dw + 3]);
+}
+
+static void pdc20621_dma_prep(struct ata_queued_cmd *qc)
+{
+	struct scatterlist *sg = qc->sg;
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+	unsigned int portno = ap->port_no;
+	unsigned int i, last, idx, total_len = 0, sgt_len;
+	u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ];
+
+	assert(qc->flags & ATA_QCFLAG_DMAMAP);
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Build S/G table
+	 */
+	last = qc->n_elem;
+	idx = 0;
+	for (i = 0; i < last; i++) {
+		buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i]));
+		buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i]));
+		total_len += sg[i].length;
+	}
+	buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT);
+	sgt_len = idx * 4;
+
+	/*
+	 * Build ATA, host DMA packets
+	 */
+	pdc20621_host_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	pdc20621_host_pkt(&qc->tf, &pp->dimm_buf[0], portno);
+
+	pdc20621_ata_sg(&qc->tf, &pp->dimm_buf[0], portno, total_len);
+	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+	else
+		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+	/* copy three S/G tables and two packets to DIMM MMIO window */
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP) +
+		    PDC_DIMM_HOST_PRD,
+		    &pp->dimm_buf[PDC_DIMM_HEADER_SZ], sgt_len);
+
+	/* force host FIFO dump */
+	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+	readl(dimm_mmio);	/* MMIO PCI posting flush */
+
+	VPRINTK("ata pkt buf ofs %u, prd size %u, mmio copied\n", i, sgt_len);
+}
+
+static void pdc20621_nodata_prep(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_port_priv *pp = ap->private_data;
+	void *mmio = ap->host_set->mmio_base;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+	unsigned int portno = ap->port_no;
+	unsigned int i;
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	i = pdc20621_ata_pkt(&qc->tf, qc->dev->devno, &pp->dimm_buf[0], portno);
+
+	if (qc->tf.flags & ATA_TFLAG_LBA48)
+		i = pdc_prep_lba48(&qc->tf, &pp->dimm_buf[0], i);
+	else
+		i = pdc_prep_lba28(&qc->tf, &pp->dimm_buf[0], i);
+
+	pdc_pkt_footer(&qc->tf, &pp->dimm_buf[0], i);
+
+	/* copy three S/G tables and two packets to DIMM MMIO window */
+	memcpy_toio(dimm_mmio + (portno * PDC_DIMM_WINDOW_STEP),
+		    &pp->dimm_buf, PDC_DIMM_HEADER_SZ);
+
+	/* force host FIFO dump */
+	writel(0x00000001, mmio + PDC_20621_GENERAL_CTL);
+
+	readl(dimm_mmio);	/* MMIO PCI posting flush */
+
+	VPRINTK("ata pkt buf ofs %u, mmio copied\n", i);
+}
+
+static void pdc20621_qc_prep(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+		pdc20621_dma_prep(qc);
+		break;
+	case ATA_PROT_NODATA:
+		pdc20621_nodata_prep(qc);
+		break;
+	default:
+		break;
+	}
+}
+
+static void __pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				 unsigned int seq,
+				 u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+	readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+	writel(pkt_ofs, mmio + PDC_HDMA_PKT_SUBMIT);
+	readl(mmio + PDC_HDMA_PKT_SUBMIT);	/* flush */
+}
+
+static void pdc20621_push_hdma(struct ata_queued_cmd *qc,
+				unsigned int seq,
+				u32 pkt_ofs)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_prod & PDC_HDMA_Q_MASK;
+
+	if (!pp->doing_hdma) {
+		__pdc20621_push_hdma(qc, seq, pkt_ofs);
+		pp->doing_hdma = 1;
+		return;
+	}
+
+	pp->hdma[idx].qc = qc;
+	pp->hdma[idx].seq = seq;
+	pp->hdma[idx].pkt_ofs = pkt_ofs;
+	pp->hdma_prod++;
+}
+
+static void pdc20621_pop_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct pdc_host_priv *pp = ap->host_set->private_data;
+	unsigned int idx = pp->hdma_cons & PDC_HDMA_Q_MASK;
+
+	/* if nothing on queue, we're done */
+	if (pp->hdma_prod == pp->hdma_cons) {
+		pp->doing_hdma = 0;
+		return;
+	}
+
+	__pdc20621_push_hdma(pp->hdma[idx].qc, pp->hdma[idx].seq,
+			     pp->hdma[idx].pkt_ofs);
+	pp->hdma_cons++;
+}
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_dump_hdma(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	unsigned int port_no = ap->port_no;
+	struct pdc_host_priv *hpriv = ap->host_set->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	dimm_mmio += (port_no * PDC_DIMM_WINDOW_STEP);
+	dimm_mmio += PDC_DIMM_HOST_PKT;
+
+	printk(KERN_ERR "HDMA[0] == 0x%08X\n", readl(dimm_mmio));
+	printk(KERN_ERR "HDMA[1] == 0x%08X\n", readl(dimm_mmio + 4));
+	printk(KERN_ERR "HDMA[2] == 0x%08X\n", readl(dimm_mmio + 8));
+	printk(KERN_ERR "HDMA[3] == 0x%08X\n", readl(dimm_mmio + 12));
+}
+#else
+static inline void pdc20621_dump_hdma(struct ata_queued_cmd *qc) { }
+#endif /* ATA_VERBOSE_DEBUG */
+
+static void pdc20621_packet_start(struct ata_queued_cmd *qc)
+{
+	struct ata_port *ap = qc->ap;
+	struct ata_host_set *host_set = ap->host_set;
+	unsigned int port_no = ap->port_no;
+	void *mmio = host_set->mmio_base;
+	unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE);
+	u8 seq = (u8) (port_no + 1);
+	unsigned int port_ofs;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	VPRINTK("ata%u: ENTER\n", ap->id);
+
+	wmb();			/* flush PRD, pkt writes */
+
+	port_ofs = PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+
+	/* if writing, we (1) DMA to DIMM, then (2) do ATA command */
+	if (rw && qc->tf.protocol == ATA_PROT_DMA) {
+		seq += 4;
+
+		pdc20621_dump_hdma(qc);
+		pdc20621_push_hdma(qc, seq, port_ofs + PDC_DIMM_HOST_PKT);
+		VPRINTK("queued ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_HOST_PKT,
+			port_ofs + PDC_DIMM_HOST_PKT,
+			seq);
+	} else {
+		writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+		readl(mmio + PDC_20621_SEQCTL + (seq * 4));	/* flush */
+
+		writel(port_ofs + PDC_DIMM_ATA_PKT,
+		       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		VPRINTK("submitted ofs 0x%x (%u), seq %u\n",
+			port_ofs + PDC_DIMM_ATA_PKT,
+			port_ofs + PDC_DIMM_ATA_PKT,
+			seq);
+	}
+}
+
+static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc)
+{
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		pdc20621_packet_start(qc);
+		return 0;
+
+	case ATA_PROT_ATAPI_DMA:
+		BUG();
+		break;
+
+	default:
+		break;
+	}
+
+	return ata_qc_issue_prot(qc);
+}
+
+static inline unsigned int pdc20621_host_intr( struct ata_port *ap,
+                                          struct ata_queued_cmd *qc,
+					  unsigned int doing_hdma,
+					  void *mmio)
+{
+	unsigned int port_no = ap->port_no;
+	unsigned int port_ofs =
+		PDC_20621_DIMM_BASE + (PDC_DIMM_WINDOW_STEP * port_no);
+	u8 status;
+	unsigned int handled = 0;
+
+	VPRINTK("ENTER\n");
+
+	if ((qc->tf.protocol == ATA_PROT_DMA) &&	/* read */
+	    (!(qc->tf.flags & ATA_TFLAG_WRITE))) {
+
+		/* step two - DMA from DIMM to host */
+		if (doing_hdma) {
+			VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			/* get drive status; clear intr; complete txn */
+			ata_qc_complete(qc, ata_wait_idle(ap));
+			pdc20621_pop_hdma(qc);
+		}
+
+		/* step one - exec ATA command */
+		else {
+			u8 seq = (u8) (port_no + 1 + 4);
+			VPRINTK("ata%u: read ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit hdma pkt */
+			pdc20621_dump_hdma(qc);
+			pdc20621_push_hdma(qc, seq,
+					   port_ofs + PDC_DIMM_HOST_PKT);
+		}
+		handled = 1;
+
+	} else if (qc->tf.protocol == ATA_PROT_DMA) {	/* write */
+
+		/* step one - DMA from host to DIMM */
+		if (doing_hdma) {
+			u8 seq = (u8) (port_no + 1);
+			VPRINTK("ata%u: write hdma, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+
+			/* submit ata pkt */
+			writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4));
+			readl(mmio + PDC_20621_SEQCTL + (seq * 4));
+			writel(port_ofs + PDC_DIMM_ATA_PKT,
+			       (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+			readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT);
+		}
+
+		/* step two - execute ATA command */
+		else {
+			VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id,
+				readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT));
+			/* get drive status; clear intr; complete txn */
+			ata_qc_complete(qc, ata_wait_idle(ap));
+			pdc20621_pop_hdma(qc);
+		}
+		handled = 1;
+
+	/* command completion, but no data xfer */
+	} else if (qc->tf.protocol == ATA_PROT_NODATA) {
+
+		status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+		DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status);
+		ata_qc_complete(qc, status);
+		handled = 1;
+
+	} else {
+		ap->stats.idle_irq++;
+	}
+
+	return handled;
+}
+
+static void pdc20621_irq_clear(struct ata_port *ap)
+{
+	struct ata_host_set *host_set = ap->host_set;
+	void *mmio = host_set->mmio_base;
+
+	mmio += PDC_CHIP0_OFS;
+
+	readl(mmio + PDC_20621_SEQMASK);
+}
+
+static irqreturn_t pdc20621_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	struct ata_port *ap;
+	u32 mask = 0;
+	unsigned int i, tmp, port_no;
+	unsigned int handled = 0;
+	void *mmio_base;
+
+	VPRINTK("ENTER\n");
+
+	if (!host_set || !host_set->mmio_base) {
+		VPRINTK("QUICK EXIT\n");
+		return IRQ_NONE;
+	}
+
+	mmio_base = host_set->mmio_base;
+
+	/* reading should also clear interrupts */
+	mmio_base += PDC_CHIP0_OFS;
+	mask = readl(mmio_base + PDC_20621_SEQMASK);
+	VPRINTK("mask == 0x%x\n", mask);
+
+	if (mask == 0xffffffff) {
+		VPRINTK("QUICK EXIT 2\n");
+		return IRQ_NONE;
+	}
+	mask &= 0xffff;		/* only 16 tags possible */
+	if (!mask) {
+		VPRINTK("QUICK EXIT 3\n");
+		return IRQ_NONE;
+	}
+
+        spin_lock(&host_set->lock);
+
+        for (i = 1; i < 9; i++) {
+		port_no = i - 1;
+		if (port_no > 3)
+			port_no -= 4;
+		if (port_no >= host_set->n_ports)
+			ap = NULL;
+		else
+			ap = host_set->ports[port_no];
+		tmp = mask & (1 << i);
+		VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp);
+		if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+			struct ata_queued_cmd *qc;
+
+			qc = ata_qc_from_tag(ap, ap->active_tag);
+			if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+				handled += pdc20621_host_intr(ap, qc, (i > 4),
+							      mmio_base);
+		}
+	}
+
+        spin_unlock(&host_set->lock);
+
+	VPRINTK("mask == 0x%x\n", mask);
+
+	VPRINTK("EXIT\n");
+
+	return IRQ_RETVAL(handled);
+}
+
+static void pdc_eng_timeout(struct ata_port *ap)
+{
+	u8 drv_stat;
+	struct ata_queued_cmd *qc;
+
+	DPRINTK("ENTER\n");
+
+	qc = ata_qc_from_tag(ap, ap->active_tag);
+	if (!qc) {
+		printk(KERN_ERR "ata%u: BUG: timeout without command\n",
+		       ap->id);
+		goto out;
+	}
+
+	/* hack alert!  We cannot use the supplied completion
+	 * function from inside the ->eh_strategy_handler() thread.
+	 * libata is the only user of ->eh_strategy_handler() in
+	 * any kernel, so the default scsi_done() assumes it is
+	 * not being called from the SCSI EH.
+	 */
+	qc->scsidone = scsi_finish_command;
+
+	switch (qc->tf.protocol) {
+	case ATA_PROT_DMA:
+	case ATA_PROT_NODATA:
+		printk(KERN_ERR "ata%u: command timeout\n", ap->id);
+		ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR);
+		break;
+
+	default:
+		drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000);
+
+		printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n",
+		       ap->id, qc->tf.command, drv_stat);
+
+		ata_qc_complete(qc, drv_stat);
+		break;
+	}
+
+out:
+	DPRINTK("EXIT\n");
+}
+
+static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_tf_load(ap, tf);
+}
+
+
+static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	WARN_ON (tf->protocol == ATA_PROT_DMA ||
+		 tf->protocol == ATA_PROT_NODATA);
+	ata_exec_command(ap, tf);
+}
+
+
+static void pdc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base;
+	port->data_addr		= base;
+	port->feature_addr	=
+	port->error_addr	= base + 0x4;
+	port->nsect_addr	= base + 0x8;
+	port->lbal_addr		= base + 0xc;
+	port->lbam_addr		= base + 0x10;
+	port->lbah_addr		= base + 0x14;
+	port->device_addr	= base + 0x18;
+	port->command_addr	=
+	port->status_addr	= base + 0x1c;
+	port->altstatus_addr	=
+	port->ctl_addr		= base + 0x38;
+}
+
+
+#ifdef ATA_VERBOSE_DEBUG
+static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, 
+				   u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4; /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size); 
+
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+
+	offset -= (idx * window_size);
+	idx++;
+	dist = ((long) (window_size - (offset + size))) >= 0 ? size : 
+		(long) (window_size - offset);
+	memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), 
+		      dist);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      window_size / 4);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+
+	if (size) {
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_fromio((char *) psource, (char *) (dimm_mmio), 
+			      size / 4);
+	}
+}
+#endif
+
+
+static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, 
+				 u32 offset, u32 size)
+{
+	u32 window_size;
+	u16 idx;
+	u8 page_mask;
+	long dist;
+	void *mmio = pe->mmio_base;
+	struct pdc_host_priv *hpriv = pe->private_data;
+	void *dimm_mmio = hpriv->dimm_mmio;
+
+	/* hard-code chip #0 */   
+	mmio += PDC_CHIP0_OFS;
+
+	page_mask = 0x00;	
+   	window_size = 0x2000 * 4;       /* 32K byte uchar size */  
+	idx = (u16) (offset / window_size);
+
+	writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+	readl(mmio + PDC_DIMM_WINDOW_CTLR);
+	offset -= (idx * window_size); 
+	idx++;
+	dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size :
+		(long) (window_size - offset);
+	memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist);
+	writel(0x01, mmio + PDC_GENERAL_CTLR);
+	readl(mmio + PDC_GENERAL_CTLR);
+
+	psource += dist;    
+	size -= dist;
+	for (; (long) size >= (long) window_size ;) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, 
+			    window_size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+		psource += window_size;
+		size -= window_size;
+		idx ++;
+	}
+    
+	if (size) {
+		writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR);
+		readl(mmio + PDC_DIMM_WINDOW_CTLR);
+		memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4);
+		writel(0x01, mmio + PDC_GENERAL_CTLR);
+		readl(mmio + PDC_GENERAL_CTLR);
+	}
+}
+
+
+static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, 
+				      u32 subaddr, u32 *pdata)
+{
+	void *mmio = pe->mmio_base;
+	u32 i2creg  = 0;
+	u32 status;     
+	u32 count =0;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	i2creg |= device << 24;
+	i2creg |= subaddr << 16;
+
+	/* Set the device and subaddress */
+	writel(i2creg, mmio + PDC_I2C_ADDR_DATA_OFFSET);
+	readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+
+	/* Write Control to perform read operation, mask int */
+	writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, 
+	       mmio + PDC_I2C_CONTROL_OFFSET);
+
+	for (count = 0; count <= 1000; count ++) {
+		status = readl(mmio + PDC_I2C_CONTROL_OFFSET);
+		if (status & PDC_I2C_COMPLETE) {
+			status = readl(mmio + PDC_I2C_ADDR_DATA_OFFSET);
+			break;
+		} else if (count == 1000)
+			return 0;
+	}
+
+	*pdata = (status >> 8) & 0x000000ff;
+	return 1;           
+}
+
+
+static int pdc20621_detect_dimm(struct ata_probe_ent *pe)
+{
+	u32 data=0 ;
+  	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			     PDC_DIMM_SPD_SYSTEM_FREQ, &data)) {
+   		if (data == 100)
+			return 100;
+  	} else
+		return 0;
+ 	
+   	if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) {
+		if(data <= 0x75) 
+			return 133;
+   	} else
+		return 0;
+   	
+   	return 0;
+}
+
+
+static int pdc20621_prog_dimm0(struct ata_probe_ent *pe)
+{
+	u32 spd0[50];
+	u32 data = 0;
+   	int size, i;
+   	u8 bdimmsize; 
+   	void *mmio = pe->mmio_base;
+	static const struct {
+		unsigned int reg;
+		unsigned int ofs;
+	} pdc_i2c_read_data [] = {
+		{ PDC_DIMM_SPD_TYPE, 11 },		
+		{ PDC_DIMM_SPD_FRESH_RATE, 12 },
+		{ PDC_DIMM_SPD_COLUMN_NUM, 4 }, 
+		{ PDC_DIMM_SPD_ATTRIBUTE, 21 },
+		{ PDC_DIMM_SPD_ROW_NUM, 3 },
+		{ PDC_DIMM_SPD_BANK_NUM, 17 },
+		{ PDC_DIMM_SPD_MODULE_ROW, 5 },
+		{ PDC_DIMM_SPD_ROW_PRE_CHARGE, 27 },
+		{ PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 },
+		{ PDC_DIMM_SPD_RAS_CAS_DELAY, 29 },
+		{ PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 },
+		{ PDC_DIMM_SPD_CAS_LATENCY, 18 },       
+	};
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	for(i=0; i<ARRAY_SIZE(pdc_i2c_read_data); i++)
+		pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS,
+				  pdc_i2c_read_data[i].reg, 
+				  &spd0[pdc_i2c_read_data[i].ofs]);
+  
+   	data |= (spd0[4] - 8) | ((spd0[21] != 0) << 3) | ((spd0[3]-11) << 4);
+   	data |= ((spd0[17] / 4) << 6) | ((spd0[5] / 2) << 7) | 
+		((((spd0[27] + 9) / 10) - 1) << 8) ;
+   	data |= (((((spd0[29] > spd0[28]) 
+		    ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; 
+   	data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12;
+   
+   	if (spd0[18] & 0x08) 
+		data |= ((0x03) << 14);
+   	else if (spd0[18] & 0x04)
+		data |= ((0x02) << 14);
+   	else if (spd0[18] & 0x01)
+		data |= ((0x01) << 14);
+   	else
+		data |= (0 << 14);
+
+  	/* 
+	   Calculate the size of bDIMMSize (power of 2) and
+	   merge the DIMM size by program start/end address.
+	*/
+
+   	bdimmsize = spd0[4] + (spd0[5] / 2) + spd0[3] + (spd0[17] / 2) + 3;
+   	size = (1 << bdimmsize) >> 20;	/* size = xxx(MB) */
+   	data |= (((size / 16) - 1) << 16);
+   	data |= (0 << 23);
+	data |= 8;
+   	writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); 
+	readl(mmio + PDC_DIMM0_CONTROL_OFFSET);
+   	return size;                          
+}
+
+
+static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe)
+{
+	u32 data, spd0;
+   	int error, i;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+   	/*
+	  Set To Default : DIMM Module Global Control Register (0x022259F1)
+	  DIMM Arbitration Disable (bit 20)
+	  DIMM Data/Control Output Driving Selection (bit12 - bit15)
+	  Refresh Enable (bit 17)
+	*/
+
+	data = 0x022259F1;   
+	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+	readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+	/* Turn on for ECC */
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		data |= (0x01 << 16);
+		writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+		readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		printk(KERN_ERR "Local DIMM ECC Enabled\n");
+   	}
+
+   	/* DIMM Initialization Select/Enable (bit 18/19) */
+   	data &= (~(1<<18));
+   	data |= (1<<19);
+   	writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET);
+
+   	error = 1;                     
+   	for (i = 1; i <= 10; i++) {   /* polling ~5 secs */
+		data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET);
+		if (!(data & (1<<19))) {
+	   		error = 0;
+	   		break;     
+		}
+		msleep(i*100);
+   	}
+   	return error;
+}
+	
+
+static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe)
+{
+	int speed, size, length; 
+	u32 addr,spd0,pci_status;
+	u32 tmp=0;
+	u32 time_period=0;
+	u32 tcount=0;
+	u32 ticks=0;
+	u32 clock=0;
+	u32 fparam=0;
+   	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+   	mmio += PDC_CHIP0_OFS;
+
+	/* Initialize PLL based upon PCI Bus Frequency */
+
+	/* Initialize Time Period Register */
+	writel(0xffffffff, mmio + PDC_TIME_PERIOD);
+	time_period = readl(mmio + PDC_TIME_PERIOD);
+	VPRINTK("Time Period Register (0x40): 0x%x\n", time_period);
+
+	/* Enable timer */
+	writel(0x00001a0, mmio + PDC_TIME_CONTROL);
+	readl(mmio + PDC_TIME_CONTROL);
+
+	/* Wait 3 seconds */
+	msleep(3000);
+
+	/* 
+	   When timer is enabled, counter is decreased every internal
+	   clock cycle.
+	*/
+
+	tcount = readl(mmio + PDC_TIME_COUNTER);
+	VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount);
+
+	/* 
+	   If SX4 is on PCI-X bus, after 3 seconds, the timer counter
+	   register should be >= (0xffffffff - 3x10^8).
+	*/
+	if(tcount >= PCI_X_TCOUNT) {
+		ticks = (time_period - tcount);
+		VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks);
+	
+		clock = (ticks / 300000);
+		VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock);
+		
+		clock = (clock * 33);
+		VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock);
+
+		/* PLL F Param (bit 22:16) */
+		fparam = (1400000 / clock) - 2;
+		VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam);
+		
+		/* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */
+		pci_status = (0x8a001824 | (fparam << 16));
+	} else
+		pci_status = PCI_PLL_INIT;
+
+	/* Initialize PLL. */
+	VPRINTK("pci_status: 0x%x\n", pci_status);
+	writel(pci_status, mmio + PDC_CTL_STATUS);
+	readl(mmio + PDC_CTL_STATUS);
+
+	/* 
+	   Read SPD of DIMM by I2C interface,
+	   and program the DIMM Module Controller.
+	*/
+ 	if (!(speed = pdc20621_detect_dimm(pe))) {
+		printk(KERN_ERR "Detect Local DIMM Fail\n");  
+		return 1;	/* DIMM error */
+   	}
+   	VPRINTK("Local DIMM Speed = %d\n", speed);
+
+   	/* Programming DIMM0 Module Control Register (index_CID0:80h) */ 
+   	size = pdc20621_prog_dimm0(pe);
+   	VPRINTK("Local DIMM Size = %dMB\n",size);
+
+   	/* Programming DIMM Module Global Control Register (index_CID0:88h) */ 
+   	if (pdc20621_prog_dimm_global(pe)) {
+		printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n");
+		return 1;
+   	}
+
+#ifdef ATA_VERBOSE_DEBUG
+	{
+		u8 test_parttern1[40] = {0x55,0xAA,'P','r','o','m','i','s','e',' ',
+  				'N','o','t',' ','Y','e','t',' ','D','e','f','i','n','e','d',' ',
+ 				 '1','.','1','0',
+  				'9','8','0','3','1','6','1','2',0,0};
+		u8 test_parttern2[40] = {0};
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x10040, 40);
+		pdc20621_put_to_dimm(pe, (void *) test_parttern2, 0x40, 40);
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 
+				       40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+
+		pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40);
+		pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40);
+		printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], 
+		       test_parttern2[1], &(test_parttern2[2]));
+	}
+#endif
+
+	/* ECC initiliazation. */
+
+	pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 
+			  PDC_DIMM_SPD_TYPE, &spd0);
+	if (spd0 == 0x02) {
+		VPRINTK("Start ECC initialization\n");
+		addr = 0;
+		length = size * 1024 * 1024;
+		while (addr < length) {
+			pdc20621_put_to_dimm(pe, (void *) &tmp, addr, 
+					     sizeof(u32));
+			addr += sizeof(u32);
+		}
+		VPRINTK("Finish ECC initialization\n");
+	}
+	return 0;
+}
+
+
+static void pdc_20621_init(struct ata_probe_ent *pe)
+{
+	u32 tmp;
+	void *mmio = pe->mmio_base;
+
+	/* hard-code chip #0 */
+	mmio += PDC_CHIP0_OFS;
+
+	/*
+	 * Select page 0x40 for our 32k DIMM window
+	 */
+	tmp = readl(mmio + PDC_20621_DIMM_WINDOW) & 0xffff0000;
+	tmp |= PDC_PAGE_WINDOW;	/* page 40h; arbitrarily selected */
+	writel(tmp, mmio + PDC_20621_DIMM_WINDOW);
+
+	/*
+	 * Reset Host DMA
+	 */
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp |= PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+
+	udelay(10);
+
+	tmp = readl(mmio + PDC_HDMA_CTLSTAT);
+	tmp &= ~PDC_RESET;
+	writel(tmp, mmio + PDC_HDMA_CTLSTAT);
+	readl(mmio + PDC_HDMA_CTLSTAT);		/* flush */
+}
+
+static int pdc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	void *mmio_base, *dimm_mmio = NULL;
+	struct pdc_host_priv *hpriv = NULL;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int pci_dev_busy = 0;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	/*
+	 * If this driver happens to only be useful on Apple's K2, then
+	 * we should check that here as it has a normal Serverworks ID
+	 */
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 3),
+		            pci_resource_len(pdev, 3));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	hpriv = kmalloc(sizeof(*hpriv), GFP_KERNEL);
+	if (!hpriv) {
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+	memset(hpriv, 0, sizeof(*hpriv));
+
+	dimm_mmio = ioremap(pci_resource_start(pdev, 4),
+			    pci_resource_len(pdev, 4));
+	if (!dimm_mmio) {
+		kfree(hpriv);
+		rc = -ENOMEM;
+		goto err_out_iounmap;
+	}
+
+	hpriv->dimm_mmio = dimm_mmio;
+
+	probe_ent->sht		= pdc_port_info[board_idx].sht;
+	probe_ent->host_flags	= pdc_port_info[board_idx].host_flags;
+	probe_ent->pio_mask	= pdc_port_info[board_idx].pio_mask;
+	probe_ent->mwdma_mask	= pdc_port_info[board_idx].mwdma_mask;
+	probe_ent->udma_mask	= pdc_port_info[board_idx].udma_mask;
+	probe_ent->port_ops	= pdc_port_info[board_idx].port_ops;
+
+       	probe_ent->irq = pdev->irq;
+       	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	probe_ent->private_data = hpriv;
+	base += PDC_CHIP0_OFS;
+
+	probe_ent->n_ports = 4;
+	pdc_sata_setup_port(&probe_ent->port[0], base + 0x200);
+	pdc_sata_setup_port(&probe_ent->port[1], base + 0x280);
+	pdc_sata_setup_port(&probe_ent->port[2], base + 0x300);
+	pdc_sata_setup_port(&probe_ent->port[3], base + 0x380);
+
+	pci_set_master(pdev);
+
+	/* initialize adapter */
+	/* initialize local dimm */
+	if (pdc20621_dimm_init(probe_ent)) {
+		rc = -ENOMEM;
+		goto err_out_iounmap_dimm;
+	}
+	pdc_20621_init(probe_ent);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_iounmap_dimm:		/* only get to this label if 20621 */
+	kfree(hpriv);
+	iounmap(dimm_mmio);
+err_out_iounmap:
+	iounmap(mmio_base);
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+
+static int __init pdc_sata_init(void)
+{
+	return pci_module_init(&pdc_sata_pci_driver);
+}
+
+
+static void __exit pdc_sata_exit(void)
+{
+	pci_unregister_driver(&pdc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("Promise SATA low-level driver");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, pdc_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pdc_sata_init);
+module_exit(pdc_sata_exit);
diff --git a/drivers/scsi/sata_uli.c b/drivers/scsi/sata_uli.c
new file mode 100644
index 0000000..0bff4f4
--- /dev/null
+++ b/drivers/scsi/sata_uli.c
@@ -0,0 +1,287 @@
+/*
+ *  sata_uli.c - ULi Electronics SATA
+ *
+ *  The contents of this file are subject to the Open
+ *  Software License version 1.1 that can be found at
+ *  http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+ *  by reference.
+ *
+ *  Alternatively, the contents of this file may be used under the terms
+ *  of the GNU General Public License version 2 (the "GPL") as distributed
+ *  in the kernel source COPYING file, in which case the provisions of
+ *  the GPL are applicable instead of the above.  If you wish to allow
+ *  the use of your version of this file only under the terms of the
+ *  GPL and not to allow others to use your version of this file under
+ *  the OSL, indicate your decision by deleting the provisions above and
+ *  replace them with the notice and other provisions required by the GPL.
+ *  If you do not delete the provisions above, a recipient may use your
+ *  version of this file under either the OSL or the GPL.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_uli"
+#define DRV_VERSION	"0.5"
+
+enum {
+	uli_5289		= 0,
+	uli_5287		= 1,
+	uli_5281		= 2,
+
+	/* PCI configuration registers */
+	ULI5287_BASE		= 0x90, /* sata0 phy SCR registers */
+	ULI5287_OFFS		= 0x10, /* offset from sata0->sata1 phy regs */
+	ULI5281_BASE		= 0x60, /* sata0 phy SCR  registers */
+	ULI5281_OFFS		= 0x60, /* offset from sata0->sata1 phy regs */
+};
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static struct pci_device_id uli_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 },
+	{ PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 },
+	{ PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 },
+	{ }	/* terminate list */
+};
+
+
+static struct pci_driver uli_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= uli_pci_tbl,
+	.probe			= uli_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template uli_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations uli_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.phy_reset		= sata_phy_reset,
+
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.scr_read		= uli_scr_read,
+	.scr_write		= uli_scr_write,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info uli_port_info = {
+	.sht            = &uli_sht,
+	.host_flags     = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+			  ATA_FLAG_NO_LEGACY,
+	.pio_mask       = 0x03,		//support pio mode 4 (FIXME)
+	.udma_mask      = 0x7f,		//support udma mode 6
+	.port_ops       = &uli_ops,
+};
+
+
+MODULE_AUTHOR("Peer Chen");
+MODULE_DESCRIPTION("low-level driver for ULi Electronics SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, uli_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static unsigned int get_scr_cfg_addr(struct ata_port *ap, unsigned int sc_reg)
+{
+	return ap->ioaddr.scr_addr + (4 * sc_reg);
+}
+
+static u32 uli_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, sc_reg);
+	u32 val;
+
+	pci_read_config_dword(pdev, cfg_addr, &val);
+	return val;
+}
+
+static void uli_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val)
+{
+	struct pci_dev *pdev = to_pci_dev(ap->host_set->dev);
+	unsigned int cfg_addr = get_scr_cfg_addr(ap, scr);
+
+	pci_write_config_dword(pdev, cfg_addr, val);
+}
+
+static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+
+	return uli_scr_cfg_read(ap, sc_reg);
+}
+
+static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)	//SCR_CONTROL=2, SCR_ERROR=1, SCR_STATUS=0
+		return;
+
+	uli_scr_cfg_write(ap, sc_reg, val);
+}
+
+/* move to PCI layer, integrate w/ MSI stuff */
+static void pci_enable_intx(struct pci_dev *pdev)
+{
+	u16 pci_command;
+
+	pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+	if (pci_command & PCI_COMMAND_INTX_DISABLE) {
+		pci_command &= ~PCI_COMMAND_INTX_DISABLE;
+		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+	}
+}
+
+static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	struct ata_probe_ent *probe_ent;
+	struct ata_port_info *ppi;
+	int rc;
+	unsigned int board_idx = (unsigned int) ent->driver_data;
+	int pci_dev_busy = 0;
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	ppi = &uli_port_info;
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	if (!probe_ent) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	
+	switch (board_idx) {
+	case uli_5287:
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+       		probe_ent->n_ports = 4;
+
+       		probe_ent->port[2].cmd_addr = pci_resource_start(pdev, 0) + 8;
+		probe_ent->port[2].altstatus_addr =
+		probe_ent->port[2].ctl_addr =
+			(pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS) + 4;
+		probe_ent->port[2].bmdma_addr = pci_resource_start(pdev, 4) + 16;
+		probe_ent->port[2].scr_addr = ULI5287_BASE + ULI5287_OFFS*4;
+
+		probe_ent->port[3].cmd_addr = pci_resource_start(pdev, 2) + 8;
+		probe_ent->port[3].altstatus_addr =
+		probe_ent->port[3].ctl_addr =
+			(pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS) + 4;
+		probe_ent->port[3].bmdma_addr = pci_resource_start(pdev, 4) + 24;
+		probe_ent->port[3].scr_addr = ULI5287_BASE + ULI5287_OFFS*5;
+
+		ata_std_ports(&probe_ent->port[2]);
+		ata_std_ports(&probe_ent->port[3]);
+		break;
+
+	case uli_5289:
+		probe_ent->port[0].scr_addr = ULI5287_BASE;
+		probe_ent->port[1].scr_addr = ULI5287_BASE + ULI5287_OFFS;
+		break;
+
+	case uli_5281:
+		probe_ent->port[0].scr_addr = ULI5281_BASE;
+		probe_ent->port[1].scr_addr = ULI5281_BASE + ULI5281_OFFS;
+		break;
+
+	default:
+		BUG();
+		break;
+	}
+
+	pci_set_master(pdev);
+	pci_enable_intx(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+
+}
+
+static int __init uli_init(void)
+{
+	return pci_module_init(&uli_pci_driver);
+}
+
+static void __exit uli_exit(void)
+{
+	pci_unregister_driver(&uli_pci_driver);
+}
+
+
+module_init(uli_init);
+module_exit(uli_exit);
diff --git a/drivers/scsi/sata_via.c b/drivers/scsi/sata_via.c
new file mode 100644
index 0000000..3a78306
--- /dev/null
+++ b/drivers/scsi/sata_via.c
@@ -0,0 +1,387 @@
+/*
+   sata_via.c - VIA Serial ATA controllers
+
+   Maintained by:  Jeff Garzik <jgarzik@pobox.com>
+   		   Please ALWAYS copy linux-ide@vger.kernel.org
+ 		   on emails.
+
+   Copyright 2003-2004 Red Hat, Inc.  All rights reserved.
+   Copyright 2003-2004 Jeff Garzik
+
+   The contents of this file are subject to the Open
+   Software License version 1.1 that can be found at
+   http://www.opensource.org/licenses/osl-1.1.txt and is included herein
+   by reference.
+
+   Alternatively, the contents of this file may be used under the terms
+   of the GNU General Public License version 2 (the "GPL") as distributed
+   in the kernel source COPYING file, in which case the provisions of
+   the GPL are applicable instead of the above.  If you wish to allow
+   the use of your version of this file only under the terms of the
+   GPL and not to allow others to use your version of this file under
+   the OSL, indicate your decision by deleting the provisions above and
+   replace them with the notice and other provisions required by the GPL.
+   If you do not delete the provisions above, a recipient may use your
+   version of this file under either the OSL or the GPL.
+
+   ----------------------------------------------------------------------
+
+   To-do list:
+   * VT6421 PATA support
+
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+#include <asm/io.h>
+
+#define DRV_NAME	"sata_via"
+#define DRV_VERSION	"1.1"
+
+enum board_ids_enum {
+	vt6420,
+	vt6421,
+};
+
+enum {
+	SATA_CHAN_ENAB		= 0x40, /* SATA channel enable */
+	SATA_INT_GATE		= 0x41, /* SATA interrupt gating */
+	SATA_NATIVE_MODE	= 0x42, /* Native mode enable */
+	SATA_PATA_SHARING	= 0x49, /* PATA/SATA sharing func ctrl */
+
+	PORT0			= (1 << 1),
+	PORT1			= (1 << 0),
+	ALL_PORTS		= PORT0 | PORT1,
+	N_PORTS			= 2,
+
+	NATIVE_MODE_ALL		= (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4),
+
+	SATA_EXT_PHY		= (1 << 6), /* 0==use PATA, 1==ext phy */
+	SATA_2DEV		= (1 << 5), /* SATA is master/slave */
+};
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent);
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg);
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val);
+
+static struct pci_device_id svia_pci_tbl[] = {
+	{ 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 },
+	{ 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 },
+
+	{ }	/* terminate list */
+};
+
+static struct pci_driver svia_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= svia_pci_tbl,
+	.probe			= svia_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+static Scsi_Host_Template svia_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+static struct ata_port_operations svia_sata_ops = {
+	.port_disable		= ata_port_disable,
+
+	.tf_load		= ata_tf_load,
+	.tf_read		= ata_tf_read,
+	.check_status		= ata_check_status,
+	.exec_command		= ata_exec_command,
+	.dev_select		= ata_std_dev_select,
+
+	.phy_reset		= sata_phy_reset,
+
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+
+	.eng_timeout		= ata_eng_timeout,
+
+	.irq_handler		= ata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+
+	.scr_read		= svia_scr_read,
+	.scr_write		= svia_scr_write,
+
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static struct ata_port_info svia_port_info = {
+	.sht		= &svia_sht,
+	.host_flags	= ATA_FLAG_SATA | ATA_FLAG_SRST | ATA_FLAG_NO_LEGACY,
+	.pio_mask	= 0x1f,
+	.mwdma_mask	= 0x07,
+	.udma_mask	= 0x7f,
+	.port_ops	= &svia_sata_ops,
+};
+
+MODULE_AUTHOR("Jeff Garzik");
+MODULE_DESCRIPTION("SCSI low-level driver for VIA SATA controllers");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, svia_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return inl(ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	outl(val, ap->ioaddr.scr_addr + (4 * sc_reg));
+}
+
+static const unsigned int svia_bar_sizes[] = {
+	8, 4, 8, 4, 16, 256
+};
+
+static const unsigned int vt6421_bar_sizes[] = {
+	16, 16, 16, 16, 32, 128
+};
+
+static unsigned long svia_scr_addr(unsigned long addr, unsigned int port)
+{
+	return addr + (port * 128);
+}
+
+static unsigned long vt6421_scr_addr(unsigned long addr, unsigned int port)
+{
+	return addr + (port * 64);
+}
+
+static void vt6421_init_addrs(struct ata_probe_ent *probe_ent,
+			      struct pci_dev *pdev,
+			      unsigned int port)
+{
+	unsigned long reg_addr = pci_resource_start(pdev, port);
+	unsigned long bmdma_addr = pci_resource_start(pdev, 4) + (port * 8);
+	unsigned long scr_addr;
+
+	probe_ent->port[port].cmd_addr = reg_addr;
+	probe_ent->port[port].altstatus_addr =
+	probe_ent->port[port].ctl_addr = (reg_addr + 8) | ATA_PCI_CTL_OFS;
+	probe_ent->port[port].bmdma_addr = bmdma_addr;
+
+	scr_addr = vt6421_scr_addr(pci_resource_start(pdev, 5), port);
+	probe_ent->port[port].scr_addr = scr_addr;
+
+	ata_std_ports(&probe_ent->port[port]);
+}
+
+static struct ata_probe_ent *vt6420_init_probe_ent(struct pci_dev *pdev)
+{
+	struct ata_probe_ent *probe_ent;
+	struct ata_port_info *ppi = &svia_port_info;
+
+	probe_ent = ata_pci_init_native_mode(pdev, &ppi);
+	if (!probe_ent)
+		return NULL;
+
+	probe_ent->port[0].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 0);
+	probe_ent->port[1].scr_addr =
+		svia_scr_addr(pci_resource_start(pdev, 5), 1);
+
+	return probe_ent;
+}
+
+static struct ata_probe_ent *vt6421_init_probe_ent(struct pci_dev *pdev)
+{
+	struct ata_probe_ent *probe_ent;
+	unsigned int i;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (!probe_ent)
+		return NULL;
+
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	probe_ent->sht		= &svia_sht;
+	probe_ent->host_flags	= ATA_FLAG_SATA | ATA_FLAG_SATA_RESET |
+				  ATA_FLAG_NO_LEGACY;
+	probe_ent->port_ops	= &svia_sata_ops;
+	probe_ent->n_ports	= N_PORTS;
+	probe_ent->irq		= pdev->irq;
+	probe_ent->irq_flags	= SA_SHIRQ;
+	probe_ent->pio_mask	= 0x1f;
+	probe_ent->mwdma_mask	= 0x07;
+	probe_ent->udma_mask	= 0x7f;
+
+	for (i = 0; i < N_PORTS; i++)
+		vt6421_init_addrs(probe_ent, pdev, i);
+
+	return probe_ent;
+}
+
+static void svia_configure(struct pci_dev *pdev)
+{
+	u8 tmp8;
+
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8);
+	printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n",
+	       pci_name(pdev),
+	       (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f);
+
+	/* make sure SATA channels are enabled */
+	pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8);
+	if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= ALL_PORTS;
+		pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8);
+	}
+
+	/* make sure interrupts for each channel sent to us */
+	pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8);
+	if ((tmp8 & ALL_PORTS) != ALL_PORTS) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= ALL_PORTS;
+		pci_write_config_byte(pdev, SATA_INT_GATE, tmp8);
+	}
+
+	/* make sure native mode is enabled */
+	pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8);
+	if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) {
+		printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n",
+		       pci_name(pdev), (int) tmp8);
+		tmp8 |= NATIVE_MODE_ALL;
+		pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8);
+	}
+}
+
+static int svia_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	unsigned int i;
+	int rc;
+	struct ata_probe_ent *probe_ent;
+	int board_id = (int) ent->driver_data;
+	const int *bar_sizes;
+	int pci_dev_busy = 0;
+	u8 tmp8;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	if (board_id == vt6420) {
+		pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8);
+		if (tmp8 & SATA_2DEV) {
+			printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n",
+		       	pci_name(pdev), (int) tmp8);
+			rc = -EIO;
+			goto err_out_regions;
+		}
+
+		bar_sizes = &svia_bar_sizes[0];
+	} else {
+		bar_sizes = &vt6421_bar_sizes[0];
+	}
+
+	for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++)
+		if ((pci_resource_start(pdev, i) == 0) ||
+		    (pci_resource_len(pdev, i) < bar_sizes[i])) {
+			printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n",
+			       pci_name(pdev), i,
+			       pci_resource_start(pdev, i),
+			       pci_resource_len(pdev, i));
+			rc = -ENODEV;
+			goto err_out_regions;
+		}
+
+	rc = pci_set_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	if (board_id == vt6420)
+		probe_ent = vt6420_init_probe_ent(pdev);
+	else
+		probe_ent = vt6421_init_probe_ent(pdev);
+	
+	if (!probe_ent) {
+		printk(KERN_ERR DRV_NAME "(%s): out of memory\n",
+		       pci_name(pdev));
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+
+	svia_configure(pdev);
+
+	pci_set_master(pdev);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+static int __init svia_init(void)
+{
+	return pci_module_init(&svia_pci_driver);
+}
+
+static void __exit svia_exit(void)
+{
+	pci_unregister_driver(&svia_pci_driver);
+}
+
+module_init(svia_init);
+module_exit(svia_exit);
+
diff --git a/drivers/scsi/sata_vsc.c b/drivers/scsi/sata_vsc.c
new file mode 100644
index 0000000..2c28f0a
--- /dev/null
+++ b/drivers/scsi/sata_vsc.c
@@ -0,0 +1,407 @@
+/*
+ *  sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
+ *
+ *  Maintained by:  Jeremy Higdon @ SGI
+ * 		    Please ALWAYS copy linux-ide@vger.kernel.org
+ *		    on emails.
+ *
+ *  Copyright 2004 SGI
+ *
+ *  Bits from Jeff Garzik, Copyright RedHat, Inc.
+ *
+ *  This file is subject to the terms and conditions of the GNU General Public
+ *  License.  See the file "COPYING" in the main directory of this archive
+ *  for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <linux/libata.h>
+
+#define DRV_NAME	"sata_vsc"
+#define DRV_VERSION	"1.0"
+
+/* Interrupt register offsets (from chip base address) */
+#define VSC_SATA_INT_STAT_OFFSET	0x00
+#define VSC_SATA_INT_MASK_OFFSET	0x04
+
+/* Taskfile registers offsets */
+#define VSC_SATA_TF_CMD_OFFSET		0x00
+#define VSC_SATA_TF_DATA_OFFSET		0x00
+#define VSC_SATA_TF_ERROR_OFFSET	0x04
+#define VSC_SATA_TF_FEATURE_OFFSET	0x06
+#define VSC_SATA_TF_NSECT_OFFSET	0x08
+#define VSC_SATA_TF_LBAL_OFFSET		0x0c
+#define VSC_SATA_TF_LBAM_OFFSET		0x10
+#define VSC_SATA_TF_LBAH_OFFSET		0x14
+#define VSC_SATA_TF_DEVICE_OFFSET	0x18
+#define VSC_SATA_TF_STATUS_OFFSET	0x1c
+#define VSC_SATA_TF_COMMAND_OFFSET	0x1d
+#define VSC_SATA_TF_ALTSTATUS_OFFSET	0x28
+#define VSC_SATA_TF_CTL_OFFSET		0x29
+
+/* DMA base */
+#define VSC_SATA_UP_DESCRIPTOR_OFFSET	0x64
+#define VSC_SATA_UP_DATA_BUFFER_OFFSET	0x6C
+#define VSC_SATA_DMA_CMD_OFFSET		0x70
+
+/* SCRs base */
+#define VSC_SATA_SCR_STATUS_OFFSET	0x100
+#define VSC_SATA_SCR_ERROR_OFFSET	0x104
+#define VSC_SATA_SCR_CONTROL_OFFSET	0x108
+
+/* Port stride */
+#define VSC_SATA_PORT_OFFSET		0x200
+
+
+static u32 vsc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg)
+{
+	if (sc_reg > SCR_CONTROL)
+		return 0xffffffffU;
+	return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_sata_scr_write (struct ata_port *ap, unsigned int sc_reg,
+			       u32 val)
+{
+	if (sc_reg > SCR_CONTROL)
+		return;
+	writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4));
+}
+
+
+static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl)
+{
+	unsigned long mask_addr;
+	u8 mask;
+
+	mask_addr = (unsigned long) ap->host_set->mmio_base +
+		VSC_SATA_INT_MASK_OFFSET + ap->port_no;
+	mask = readb(mask_addr);
+	if (ctl & ATA_NIEN)
+		mask |= 0x80;
+	else
+		mask &= 0x7F;
+	writeb(mask, mask_addr);
+}
+
+
+static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR;
+
+	/*
+	 * The only thing the ctl register is used for is SRST.
+	 * That is not enabled or disabled via tf_load.
+	 * However, if ATA_NIEN is changed, then we need to change the interrupt register.
+	 */
+	if ((tf->ctl & ATA_NIEN) != (ap->last_ctl & ATA_NIEN)) {
+		ap->last_ctl = tf->ctl;
+		vsc_intr_mask_update(ap, tf->ctl & ATA_NIEN);
+	}
+	if (is_addr && (tf->flags & ATA_TFLAG_LBA48)) {
+		writew(tf->feature | (((u16)tf->hob_feature) << 8), ioaddr->feature_addr);
+		writew(tf->nsect | (((u16)tf->hob_nsect) << 8), ioaddr->nsect_addr);
+		writew(tf->lbal | (((u16)tf->hob_lbal) << 8), ioaddr->lbal_addr);
+		writew(tf->lbam | (((u16)tf->hob_lbam) << 8), ioaddr->lbam_addr);
+		writew(tf->lbah | (((u16)tf->hob_lbah) << 8), ioaddr->lbah_addr);
+	} else if (is_addr) {
+		writew(tf->feature, ioaddr->feature_addr);
+		writew(tf->nsect, ioaddr->nsect_addr);
+		writew(tf->lbal, ioaddr->lbal_addr);
+		writew(tf->lbam, ioaddr->lbam_addr);
+		writew(tf->lbah, ioaddr->lbah_addr);
+	}
+
+	if (tf->flags & ATA_TFLAG_DEVICE)
+		writeb(tf->device, ioaddr->device_addr);
+
+	ata_wait_idle(ap);
+}
+
+
+static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf)
+{
+	struct ata_ioports *ioaddr = &ap->ioaddr;
+	u16 nsect, lbal, lbam, lbah;
+
+	nsect = tf->nsect = readw(ioaddr->nsect_addr);
+	lbal = tf->lbal = readw(ioaddr->lbal_addr);
+	lbam = tf->lbam = readw(ioaddr->lbam_addr);
+	lbah = tf->lbah = readw(ioaddr->lbah_addr);
+	tf->device = readw(ioaddr->device_addr);
+
+	if (tf->flags & ATA_TFLAG_LBA48) {
+		tf->hob_feature = readb(ioaddr->error_addr);
+		tf->hob_nsect = nsect >> 8;
+		tf->hob_lbal = lbal >> 8;
+		tf->hob_lbam = lbam >> 8;
+		tf->hob_lbah = lbah >> 8;
+        }
+}
+
+
+/*
+ * vsc_sata_interrupt
+ *
+ * Read the interrupt register and process for the devices that have them pending.
+ */
+static irqreturn_t vsc_sata_interrupt (int irq, void *dev_instance,
+				       struct pt_regs *regs)
+{
+	struct ata_host_set *host_set = dev_instance;
+	unsigned int i;
+	unsigned int handled = 0;
+	u32 int_status;
+
+	spin_lock(&host_set->lock);
+
+	int_status = readl(host_set->mmio_base + VSC_SATA_INT_STAT_OFFSET);
+
+	for (i = 0; i < host_set->n_ports; i++) {
+		if (int_status & ((u32) 0xFF << (8 * i))) {
+			struct ata_port *ap;
+
+			ap = host_set->ports[i];
+			if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) {
+				struct ata_queued_cmd *qc;
+
+				qc = ata_qc_from_tag(ap, ap->active_tag);
+				if (qc && (!(qc->tf.ctl & ATA_NIEN)))
+					handled += ata_host_intr(ap, qc);
+			}
+		}
+	}
+
+	spin_unlock(&host_set->lock);
+
+	return IRQ_RETVAL(handled);
+}
+
+
+static Scsi_Host_Template vsc_sata_sht = {
+	.module			= THIS_MODULE,
+	.name			= DRV_NAME,
+	.ioctl			= ata_scsi_ioctl,
+	.queuecommand		= ata_scsi_queuecmd,
+	.eh_strategy_handler	= ata_scsi_error,
+	.can_queue		= ATA_DEF_QUEUE,
+	.this_id		= ATA_SHT_THIS_ID,
+	.sg_tablesize		= LIBATA_MAX_PRD,
+	.max_sectors		= ATA_MAX_SECTORS,
+	.cmd_per_lun		= ATA_SHT_CMD_PER_LUN,
+	.emulated		= ATA_SHT_EMULATED,
+	.use_clustering		= ATA_SHT_USE_CLUSTERING,
+	.proc_name		= DRV_NAME,
+	.dma_boundary		= ATA_DMA_BOUNDARY,
+	.slave_configure	= ata_scsi_slave_config,
+	.bios_param		= ata_std_bios_param,
+	.ordered_flush		= 1,
+};
+
+
+static struct ata_port_operations vsc_sata_ops = {
+	.port_disable		= ata_port_disable,
+	.tf_load		= vsc_sata_tf_load,
+	.tf_read		= vsc_sata_tf_read,
+	.exec_command		= ata_exec_command,
+	.check_status		= ata_check_status,
+	.dev_select		= ata_std_dev_select,
+	.phy_reset		= sata_phy_reset,
+	.bmdma_setup            = ata_bmdma_setup,
+	.bmdma_start            = ata_bmdma_start,
+	.bmdma_stop		= ata_bmdma_stop,
+	.bmdma_status		= ata_bmdma_status,
+	.qc_prep		= ata_qc_prep,
+	.qc_issue		= ata_qc_issue_prot,
+	.eng_timeout		= ata_eng_timeout,
+	.irq_handler		= vsc_sata_interrupt,
+	.irq_clear		= ata_bmdma_irq_clear,
+	.scr_read		= vsc_sata_scr_read,
+	.scr_write		= vsc_sata_scr_write,
+	.port_start		= ata_port_start,
+	.port_stop		= ata_port_stop,
+};
+
+static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base)
+{
+	port->cmd_addr		= base + VSC_SATA_TF_CMD_OFFSET;
+	port->data_addr		= base + VSC_SATA_TF_DATA_OFFSET;
+	port->error_addr	= base + VSC_SATA_TF_ERROR_OFFSET;
+	port->feature_addr	= base + VSC_SATA_TF_FEATURE_OFFSET;
+	port->nsect_addr	= base + VSC_SATA_TF_NSECT_OFFSET;
+	port->lbal_addr		= base + VSC_SATA_TF_LBAL_OFFSET;
+	port->lbam_addr		= base + VSC_SATA_TF_LBAM_OFFSET;
+	port->lbah_addr		= base + VSC_SATA_TF_LBAH_OFFSET;
+	port->device_addr	= base + VSC_SATA_TF_DEVICE_OFFSET;
+	port->status_addr	= base + VSC_SATA_TF_STATUS_OFFSET;
+	port->command_addr	= base + VSC_SATA_TF_COMMAND_OFFSET;
+	port->altstatus_addr	= base + VSC_SATA_TF_ALTSTATUS_OFFSET;
+	port->ctl_addr		= base + VSC_SATA_TF_CTL_OFFSET;
+	port->bmdma_addr	= base + VSC_SATA_DMA_CMD_OFFSET;
+	port->scr_addr		= base + VSC_SATA_SCR_STATUS_OFFSET;
+	writel(0, base + VSC_SATA_UP_DESCRIPTOR_OFFSET);
+	writel(0, base + VSC_SATA_UP_DATA_BUFFER_OFFSET);
+}
+
+
+static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	static int printed_version;
+	struct ata_probe_ent *probe_ent = NULL;
+	unsigned long base;
+	int pci_dev_busy = 0;
+	void *mmio_base;
+	int rc;
+
+	if (!printed_version++)
+		printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n");
+
+	rc = pci_enable_device(pdev);
+	if (rc)
+		return rc;
+
+	/*
+	 * Check if we have needed resource mapped.
+	 */
+	if (pci_resource_len(pdev, 0) == 0) {
+		rc = -ENODEV;
+		goto err_out;
+	}
+
+	rc = pci_request_regions(pdev, DRV_NAME);
+	if (rc) {
+		pci_dev_busy = 1;
+		goto err_out;
+	}
+
+	/*
+	 * Use 32 bit DMA mask, because 64 bit address support is poor.
+	 */
+	rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+	if (rc)
+		goto err_out_regions;
+	rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+	if (rc)
+		goto err_out_regions;
+
+	probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL);
+	if (probe_ent == NULL) {
+		rc = -ENOMEM;
+		goto err_out_regions;
+	}
+	memset(probe_ent, 0, sizeof(*probe_ent));
+	probe_ent->dev = pci_dev_to_dev(pdev);
+	INIT_LIST_HEAD(&probe_ent->node);
+
+	mmio_base = ioremap(pci_resource_start(pdev, 0),
+		            pci_resource_len(pdev, 0));
+	if (mmio_base == NULL) {
+		rc = -ENOMEM;
+		goto err_out_free_ent;
+	}
+	base = (unsigned long) mmio_base;
+
+	/*
+	 * Due to a bug in the chip, the default cache line size can't be used
+	 */
+	pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x80);
+
+	probe_ent->sht = &vsc_sata_sht;
+	probe_ent->host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY |
+				ATA_FLAG_MMIO | ATA_FLAG_SATA_RESET;
+	probe_ent->port_ops = &vsc_sata_ops;
+	probe_ent->n_ports = 4;
+	probe_ent->irq = pdev->irq;
+	probe_ent->irq_flags = SA_SHIRQ;
+	probe_ent->mmio_base = mmio_base;
+
+	/* We don't care much about the PIO/UDMA masks, but the core won't like us
+	 * if we don't fill these
+	 */
+	probe_ent->pio_mask = 0x1f;
+	probe_ent->mwdma_mask = 0x07;
+	probe_ent->udma_mask = 0x7f;
+
+	/* We have 4 ports per PCI function */
+	vsc_sata_setup_port(&probe_ent->port[0], base + 1 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[1], base + 2 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[2], base + 3 * VSC_SATA_PORT_OFFSET);
+	vsc_sata_setup_port(&probe_ent->port[3], base + 4 * VSC_SATA_PORT_OFFSET);
+
+	pci_set_master(pdev);
+
+	/* 
+	 * Config offset 0x98 is "Extended Control and Status Register 0"
+	 * Default value is (1 << 28).  All bits except bit 28 are reserved in
+	 * DPA mode.  If bit 28 is set, LED 0 reflects all ports' activity.
+	 * If bit 28 is clear, each port has its own LED.
+	 */
+	pci_write_config_dword(pdev, 0x98, 0);
+
+	/* FIXME: check ata_device_add return value */
+	ata_device_add(probe_ent);
+	kfree(probe_ent);
+
+	return 0;
+
+err_out_free_ent:
+	kfree(probe_ent);
+err_out_regions:
+	pci_release_regions(pdev);
+err_out:
+	if (!pci_dev_busy)
+		pci_disable_device(pdev);
+	return rc;
+}
+
+
+/*
+ * 0x1725/0x7174 is the Vitesse VSC-7174
+ * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical
+ * compatibility is untested as of yet
+ */
+static struct pci_device_id vsc_sata_pci_tbl[] = {
+	{ 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 },
+	{ }
+};
+
+
+static struct pci_driver vsc_sata_pci_driver = {
+	.name			= DRV_NAME,
+	.id_table		= vsc_sata_pci_tbl,
+	.probe			= vsc_sata_init_one,
+	.remove			= ata_pci_remove_one,
+};
+
+
+static int __init vsc_sata_init(void)
+{
+	return pci_module_init(&vsc_sata_pci_driver);
+}
+
+
+static void __exit vsc_sata_exit(void)
+{
+	pci_unregister_driver(&vsc_sata_pci_driver);
+}
+
+
+MODULE_AUTHOR("Jeremy Higdon");
+MODULE_DESCRIPTION("low-level driver for Vitesse VSC7174 SATA controller");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(pci, vsc_sata_pci_tbl);
+MODULE_VERSION(DRV_VERSION);
+
+module_init(vsc_sata_init);
+module_exit(vsc_sata_exit);
diff --git a/drivers/scsi/script_asm.pl b/drivers/scsi/script_asm.pl
new file mode 100644
index 0000000..7d651d9
--- /dev/null
+++ b/drivers/scsi/script_asm.pl
@@ -0,0 +1,984 @@
+#!/usr/bin/perl -s
+
+# NCR 53c810 script assembler
+# Sponsored by 
+#       iX Multiuser Multitasking Magazine
+#
+# Copyright 1993, Drew Eckhardt
+#      Visionary Computing 
+#      (Unix and Linux consulting and custom programming)
+#      drew@Colorado.EDU
+#      +1 (303) 786-7975 
+#
+#   Support for 53c710 (via -ncr7x0_family switch) added by Richard
+#   Hirst <richard@sleepie.demon.co.uk> - 15th March 1997
+#
+#   This program is free software; you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation; either version 2 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+# TolerANT and SCSI SCRIPTS are registered trademarks of NCR Corporation.
+#
+
+# 
+# Basically, I follow the NCR syntax documented in the NCR53c710 
+# Programmer's guide, with the new instructions, registers, etc.
+# from the NCR53c810.
+#
+# Differences between this assembler and NCR's are that 
+# 1.  PASS, REL (data, JUMPs work fine), and the option to start a new 
+#	script,  are unimplemented, since I didn't use them in my scripts.
+# 
+# 2.  I also emit a script_u.h file, which will undefine all of 
+# 	the A_*, E_*, etc. symbols defined in the script.  This 
+#	makes including multiple scripts in one program easier
+# 	
+# 3.  This is a single pass assembler, which only emits 
+#	.h files.
+#
+
+
+# XXX - set these with command line options
+$debug = 0;		# Print general debugging messages
+$debug_external = 0;	# Print external/forward reference messages
+$list_in_array = 1;	# Emit original SCRIPTS assembler in comments in
+			# script.h
+#$prefix;		# (set by perl -s)
+                        # define all arrays having this prefix so we 
+			# don't have name space collisions after 
+			# assembling this file in different ways for
+			# different host adapters
+
+# Constants
+
+
+# Table of the SCSI phase encodings
+%scsi_phases = ( 			
+    'DATA_OUT', 0x00_00_00_00, 'DATA_IN', 0x01_00_00_00, 'CMD', 0x02_00_00_00,
+    'STATUS', 0x03_00_00_00, 'MSG_OUT', 0x06_00_00_00, 'MSG_IN', 0x07_00_00_00
+);
+
+# XXX - replace references to the *_810 constants with general constants
+# assigned at compile time based on chip type.
+
+# Table of operator encodings
+# XXX - NCR53c710 only implements 
+# 	move (nop) = 0x00_00_00_00
+#	or = 0x02_00_00_00
+# 	and = 0x04_00_00_00
+# 	add = 0x06_00_00_00
+
+if ($ncr7x0_family) {
+  %operators = (
+    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00,
+    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00,
+    '+', 0x06_00_00_00
+  );
+}
+else {
+  %operators = (
+    'SHL',  0x01_00_00_00, 
+    '|', 0x02_00_00_00, 'OR', 0x02_00_00_00, 
+    'XOR', 0x03_00_00_00, 
+    '&', 0x04_00_00_00, 'AND', 0x04_00_00_00, 
+    'SHR', 0x05_00_00_00, 
+    # Note : low bit of the operator bit should be set for add with 
+    # carry.
+    '+', 0x06_00_00_00 
+  );
+}
+
+# Table of register addresses
+
+if ($ncr7x0_family) {
+  %registers = (
+    'SCNTL0', 0, 'SCNTL1', 1, 'SDID', 2, 'SIEN', 3,
+    'SCID', 4, 'SXFER', 5, 'SODL', 6, 'SOCL', 7,
+    'SFBR', 8, 'SIDL', 9, 'SBDL', 10, 'SBCL', 11,
+    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
+    'CTEST0', 20, 'CTEST1', 21, 'CTEST2', 22, 'CTEST3', 23,
+    'CTEST4', 24, 'CTEST5', 25, 'CTEST6', 26, 'CTEST7', 27,
+    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+    'DFIFO', 32, 'ISTAT', 33, 'CTEST8', 34, 'LCRC', 35,
+    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
+    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
+  );
+}
+else {
+  %registers = (
+    'SCNTL0', 0, 'SCNTL1', 1, 'SCNTL2', 2, 'SCNTL3', 3,
+    'SCID', 4, 'SXFER', 5, 'SDID', 6, 'GPREG', 7,
+    'SFBR', 8, 'SOCL', 9, 'SSID', 10, 'SBCL', 11,
+    'DSTAT', 12, 'SSTAT0', 13, 'SSTAT1', 14, 'SSTAT2', 15,
+    'DSA0', 16, 'DSA1', 17, 'DSA2', 18, 'DSA3', 19,
+    'ISTAT', 20,
+    'CTEST0', 24, 'CTEST1', 25, 'CTEST2', 26, 'CTEST3', 27,
+    'TEMP0', 28, 'TEMP1', 29, 'TEMP2', 30, 'TEMP3', 31,
+    'DFIFO', 32, 'CTEST4', 33, 'CTEST5', 34, 'CTEST6', 35,
+    'DBC0', 36, 'DBC1', 37, 'DBC2', 38, 'DCMD', 39,
+    'DNAD0', 40, 'DNAD1', 41, 'DNAD2', 42, 'DNAD3', 43,
+    'DSP0', 44, 'DSP1', 45, 'DSP2', 46, 'DSP3', 47,
+    'DSPS0', 48, 'DSPS1', 49, 'DSPS2', 50, 'DSPS3', 51,
+    'SCRATCH0', 52, 'SCRATCH1', 53, 'SCRATCH2', 54, 'SCRATCH3', 55,
+    'SCRATCHA0', 52, 'SCRATCHA1', 53, 'SCRATCHA2', 54, 'SCRATCHA3', 55,
+    'DMODE', 56, 'DIEN', 57, 'DWT', 58, 'DCNTL', 59,
+    'ADDER0', 60, 'ADDER1', 61, 'ADDER2', 62, 'ADDER3', 63,
+    'SIEN0', 64, 'SIEN1', 65, 'SIST0', 66, 'SIST1', 67,
+    'SLPAR', 68, 	      'MACNTL', 70, 'GPCNTL', 71,
+    'STIME0', 72, 'STIME1', 73, 'RESPID', 74, 
+    'STEST0', 76, 'STEST1', 77, 'STEST2', 78, 'STEST3', 79,
+    'SIDL', 80,
+    'SODL', 84,
+    'SBDL', 88,
+    'SCRATCHB0', 92, 'SCRATCHB1', 93, 'SCRATCHB2', 94, 'SCRATCHB3', 95
+  );
+}
+
+# Parsing regular expressions
+$identifier = '[A-Za-z_][A-Za-z_0-9]*';		
+$decnum = '-?\\d+';
+$hexnum = '0[xX][0-9A-Fa-f]+';		
+$constant = "$hexnum|$decnum";
+
+# yucky - since we can't control grouping of # $constant, we need to 
+# expand out each alternative for $value.
+
+$value = "$identifier|$identifier\\s*[+\-]\\s*$decnum|".
+    "$identifier\\s*[+-]\s*$hexnum|$constant";
+
+print STDERR "value regex = $value\n" if ($debug);
+
+$phase = join ('|', keys %scsi_phases);
+print STDERR "phase regex = $phase\n" if ($debug);
+$register = join ('|', keys %registers);
+
+# yucky - since %operators includes meta-characters which must
+# be escaped, I can't use the join() trick I used for the register
+# regex
+
+if ($ncr7x0_family) {
+  $operator = '\||OR|AND|\&|\+';
+}
+else {
+  $operator = '\||OR|AND|XOR|\&|\+';
+}
+
+# Global variables
+
+%symbol_values = (%registers) ;		# Traditional symbol table
+
+%symbol_references = () ;		# Table of symbol references, where
+					# the index is the symbol name, 
+					# and the contents a white space 
+					# delimited list of address,size
+					# tuples where size is in bytes.
+
+@code = ();				# Array of 32 bit words for SIOP 
+
+@entry = ();				# Array of entry point names
+
+@label = ();				# Array of label names
+
+@absolute = ();				# Array of absolute names
+
+@relative = ();				# Array of relative names
+
+@external = ();				# Array of external names
+
+$address = 0;				# Address of current instruction
+
+$lineno = 0;				# Line number we are parsing
+
+$output = 'script.h';			# Output file
+$outputu = 'scriptu.h';
+
+# &patch ($address, $offset, $length, $value) patches $code[$address]
+# 	so that the $length bytes at $offset have $value added to
+# 	them.  
+
+@inverted_masks = (0x00_00_00_00, 0x00_00_00_ff, 0x00_00_ff_ff, 0x00_ff_ff_ff, 
+    0xff_ff_ff_ff);
+
+sub patch {
+    local ($address, $offset, $length, $value) = @_;
+    if ($debug) {
+	print STDERR "Patching $address at offset $offset, length $length to $value\n";
+	printf STDERR "Old code : %08x\n", $code[$address];
+     }
+
+    $mask = ($inverted_masks[$length] << ($offset * 8));
+   
+    $code[$address] = ($code[$address] & ~$mask) | 
+	(($code[$address] & $mask) + ($value << ($offset * 8)) & 
+	$mask);
+    
+    printf STDERR "New code : %08x\n", $code[$address] if ($debug);
+}
+
+# &parse_value($value, $word, $offset, $length) where $value is 
+# 	an identifier or constant, $word is the word offset relative to 
+#	$address, $offset is the starting byte within that word, and 
+#	$length is the length of the field in bytes.
+#
+# Side effects are that the bytes are combined into the @code array
+#	relative to $address, and that the %symbol_references table is 
+# 	updated as appropriate.
+
+sub parse_value {
+    local ($value, $word, $offset, $length) = @_;
+    local ($tmp);
+
+    $symbol = '';
+
+    if ($value =~ /^REL\s*\(\s*($identifier)\s*\)\s*(.*)/i) {
+	$relative = 'REL';
+	$symbol = $1;
+	$value = $2;
+print STDERR "Relative reference $symbol\n" if ($debug);
+    } elsif ($value =~ /^($identifier)\s*(.*)/) {
+	$relative = 'ABS';
+	$symbol = $1;
+	$value = $2;
+print STDERR "Absolute reference $symbol\n" if ($debug);
+    } 
+
+    if ($symbol ne '') {
+print STDERR "Referencing symbol $1, length = $length in $_\n" if ($debug);
+     	$tmp = ($address + $word) * 4 + $offset;
+	if ($symbol_references{$symbol} ne undef) {
+	    $symbol_references{$symbol} = 
+		"$symbol_references{$symbol} $relative,$tmp,$length";
+	} else {
+	    if (!defined($symbol_values{$symbol})) {
+print STDERR "forward $1\n" if ($debug_external);
+		$forward{$symbol} = "line $lineno : $_";
+	    } 
+	    $symbol_references{$symbol} = "$relative,$tmp,$length";
+	}
+    } 
+
+    $value = eval $value;
+    &patch ($address + $word, $offset, $length, $value);
+}
+
+# &parse_conditional ($conditional) where $conditional is the conditional
+# clause from a transfer control instruction (RETURN, CALL, JUMP, INT).
+
+sub parse_conditional {
+    local ($conditional) = @_;
+    if ($conditional =~ /^\s*(IF|WHEN)\s*(.*)/i) {
+	$if = $1;
+	$conditional = $2;
+	if ($if =~ /WHEN/i) {
+	    $allow_atn = 0;
+	    $code[$address] |= 0x00_01_00_00;
+	    $allow_atn = 0;
+	    print STDERR "$0 : parsed WHEN\n" if ($debug);
+	} else {
+	    $allow_atn = 1;
+	    print STDERR "$0 : parsed IF\n" if ($debug);
+	}
+    } else {
+	    die "$0 : syntax error in line $lineno : $_
+	expected IF or WHEN
+";
+    }
+
+    if ($conditional =~ /^NOT\s+(.*)$/i) {
+	$not = 'NOT ';
+	$other = 'OR';
+	$conditional = $1;
+	print STDERR "$0 : parsed NOT\n" if ($debug);
+    } else {
+	$code[$address] |= 0x00_08_00_00;
+	$not = '';
+	$other = 'AND'
+    }
+
+    $need_data = 0;
+    if ($conditional =~ /^ATN\s*(.*)/i) {#
+	die "$0 : syntax error in line $lineno : $_
+	WHEN conditional is incompatible with ATN 
+" if (!$allow_atn);
+	$code[$address] |= 0x00_02_00_00;
+	$conditional = $1;
+	print STDERR "$0 : parsed ATN\n" if ($debug);
+    } elsif ($conditional =~ /^($phase)\s*(.*)/i) {
+	$phase_index = "\U$1\E";
+	$p = $scsi_phases{$phase_index};
+	$code[$address] |= $p | 0x00_02_00_00;
+	$conditional = $2;
+	print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
+    } else {
+	$other = '';
+	$need_data = 1;
+    }
+
+print STDERR "Parsing conjunction, expecting $other\n" if ($debug);
+    if ($conditional =~ /^(AND|OR)\s*(.*)/i) {
+	$conjunction = $1;
+	$conditional = $2;
+	$need_data = 1;
+	die "$0 : syntax error in line $lineno : $_
+	    Illegal use of $1.  Valid uses are 
+	    ".$not."<phase> $1 data
+	    ".$not."ATN $1 data
+" if ($other eq '');
+	die "$0 : syntax error in line $lineno : $_
+	Illegal use of $conjunction.  Valid syntaxes are 
+		NOT <phase>|ATN OR data
+		<phase>|ATN AND data
+" if ($conjunction !~ /\s*$other\s*/i);
+	print STDERR "$0 : parsed $1\n" if ($debug);
+    }
+
+    if ($need_data) {
+print STDERR "looking for data in $conditional\n" if ($debug);
+	if ($conditional=~ /^($value)\s*(.*)/i) {
+	    $code[$address] |= 0x00_04_00_00;
+	    $conditional = $2;
+	    &parse_value($1, 0, 0, 1);
+	    print STDERR "$0 : parsed data\n" if ($debug);
+	} else {
+	die "$0 : syntax error in line $lineno : $_
+	expected <data>.
+";
+	}
+    }
+
+    if ($conditional =~ /^\s*,\s*(.*)/) {
+	$conditional = $1;
+	if ($conditional =~ /^AND\s\s*MASK\s\s*($value)\s*(.*)/i) {
+	    &parse_value ($1, 0, 1, 1);
+	    print STDERR "$0 parsed AND MASK $1\n" if ($debug);
+	    die "$0 : syntax error in line $lineno : $_
+	expected end of line, not \"$2\"
+" if ($2 ne '');
+	} else {
+	    die "$0 : syntax error in line $lineno : $_
+	expected \",AND MASK <data>\", not \"$2\"
+";
+	}
+    } elsif ($conditional !~ /^\s*$/) { 
+	die "$0 : syntax error in line $lineno : $_
+	expected end of line" . (($need_data) ? " or \"AND MASK <data>\"" : "") . "
+	not \"$conditional\"
+";
+    }
+}
+
+# Parse command line
+$output = shift;
+$outputu = shift;
+
+    
+# Main loop
+while (<STDIN>) {
+    $lineno = $lineno + 1;
+    $list[$address] = $list[$address].$_;
+    s/;.*$//;				# Strip comments
+
+
+    chop;				# Leave new line out of error messages
+
+# Handle symbol definitions of the form label:
+    if (/^\s*($identifier)\s*:(.*)/) {
+	if (!defined($symbol_values{$1})) {
+	    $symbol_values{$1} = $address * 4;	# Address is an index into
+	    delete $forward{$1};		# an array of longs
+	    push (@label, $1);
+	    $_ = $2;
+	} else {
+	    die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
+	}
+    }
+
+# Handle symbol definitions of the form ABSOLUTE or RELATIVE identifier = 
+# value
+    if (/^\s*(ABSOLUTE|RELATIVE)\s+(.*)/i) {
+	$is_absolute = $1;
+	$rest = $2;
+	foreach $rest (split (/\s*,\s*/, $rest)) {
+	    if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
+	        local ($id, $cnst) = ($1, $2);
+		if ($symbol_values{$id} eq undef) {
+		    $symbol_values{$id} = eval $cnst;
+		    delete $forward{$id};
+		    if ($is_absolute =~ /ABSOLUTE/i) {
+			push (@absolute , $id);
+		    } else {
+			push (@relative, $id);
+		    }
+		} else {
+		    die "$0 : redefinition of symbol $id in line $lineno : $_\n";
+		}
+	    } else {
+		die 
+"$0 : syntax error in line $lineno : $_
+	    expected <identifier> = <value>
+";
+	    }
+	}
+    } elsif (/^\s*EXTERNAL\s+(.*)/i) {
+	$externals = $1;
+	foreach $external (split (/,/,$externals)) {
+	    if ($external =~ /\s*($identifier)\s*$/) {
+		$external = $1;
+		push (@external, $external);
+		delete $forward{$external};
+		if (defined($symbol_values{$external})) {
+			die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
+		}
+		$symbol_values{$external} = $external;
+print STDERR "defined external $1 to $external\n" if ($debug_external);
+	    } else {
+		die 
+"$0 : syntax error in line $lineno : $_
+	expected <identifier>, got $external
+";
+	    }
+	}
+# Process ENTRY identifier declarations
+    } elsif (/^\s*ENTRY\s+(.*)/i) {
+	if ($1 =~ /^($identifier)\s*$/) {
+	    push (@entry, $1);
+	} else {
+	    die
+"$0 : syntax error in line $lineno : $_
+	expected ENTRY <identifier>
+";
+	}
+# Process MOVE length, address, WITH|WHEN phase instruction
+    } elsif (/^\s*MOVE\s+(.*)/i) {
+	$rest = $1;
+	if ($rest =~ /^FROM\s+($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
+	    $transfer_addr = $1;
+	    $with_when = $2;
+	    $scsi_phase = $3;
+print STDERR "Parsing MOVE FROM $transfer_addr, $with_when $3\n" if ($debug);
+	    $code[$address] = 0x18_00_00_00 | (($with_when =~ /WITH/i) ? 
+		0x00_00_00_00 : 0x08_00_00_00) | $scsi_phases{$scsi_phase};
+	    &parse_value ($transfer_addr, 1, 0, 4);
+	    $address += 2;
+	} elsif ($rest =~ /^($value)\s*,\s*(PTR\s+|)($value)\s*,\s*(WITH|WHEN)\s+($phase)\s*$/i) {
+	    $transfer_len = $1;
+	    $ptr = $2;
+	    $transfer_addr = $3;
+	    $with_when = $4;
+	    $scsi_phase = $5;
+	    $code[$address] = (($with_when =~ /WITH/i) ? 0x00_00_00_00 : 
+		0x08_00_00_00)  | (($ptr =~ /PTR/i) ? (1 << 29) : 0) | 
+		$scsi_phases{$scsi_phase};
+	    &parse_value ($transfer_len, 0, 0, 3);
+	    &parse_value ($transfer_addr, 1, 0, 4);
+	    $address += 2;
+	} elsif ($rest =~ /^MEMORY\s+(.*)/i) {
+	    $rest = $1;
+	    $code[$address] = 0xc0_00_00_00; 
+	    if ($rest =~ /^($value)\s*,\s*($value)\s*,\s*($value)\s*$/) {
+		$count = $1;
+		$source = $2;
+		$dest =  $3;
+print STDERR "Parsing MOVE MEMORY $count, $source, $dest\n" if ($debug);
+		&parse_value ($count, 0, 0, 3);
+		&parse_value ($source, 1, 0, 4);
+		&parse_value ($dest, 2, 0, 4);
+printf STDERR "Move memory instruction = %08x,%08x,%08x\n", 
+		$code[$address], $code[$address+1], $code[$address +2] if
+		($debug);
+		$address += 3;
+	
+	    } else {
+		die 
+"$0 : syntax error in line $lineno : $_
+	expected <count>, <source>, <destination>
+"
+	    }
+	} elsif ($1 =~ /^(.*)\s+(TO|SHL|SHR)\s+(.*)/i) {
+print STDERR "Parsing register to register move\n" if ($debug);
+	    $src = $1;
+	    $op = "\U$2\E";
+	    $rest = $3;
+
+	    $code[$address] = 0x40_00_00_00;
+	
+	    $force = ($op !~ /TO/i); 
+
+
+print STDERR "Forcing register source \n" if ($force && $debug);
+
+	    if (!$force && $src =~ 
+		/^($register)\s+(-|$operator)\s+($value)\s*$/i) {
+print STDERR "register operand  data8 source\n" if ($debug);
+		$src_reg = "\U$1\E";
+		$op = "\U$2\E";
+		if ($op ne '-') {
+		    $data8 = $3;
+		} else {
+		    die "- is not implemented yet.\n"
+		}
+	    } elsif ($src =~ /^($register)\s*$/i) {
+print STDERR "register source\n" if ($debug);
+		$src_reg = "\U$1\E";
+		# Encode register to register move as a register | 0 
+		# move to register.
+		if (!$force) {
+		    $op = '|';
+		}
+		$data8 = 0;
+	    } elsif (!$force && $src =~ /^($value)\s*$/i) {
+print STDERR "data8 source\n" if ($debug);
+		$src_reg = undef;
+		$op = 'NONE';
+		$data8 = $1;
+	    } else {
+		if (!$force) {
+		    die 
+"$0 : syntax error in line $lineno : $_
+	expected <register>
+		<data8>
+		<register> <operand> <data8>
+";
+		} else {
+		    die
+"$0 : syntax error in line $lineno : $_
+	expected <register>
+";
+		}
+	    }
+	    if ($rest =~ /^($register)\s*(.*)$/i) {
+		$dst_reg = "\U$1\E";
+		$rest = $2;
+	    } else {
+	    die 
+"$0 : syntax error in $lineno : $_
+	expected <register>, got $rest
+";
+	    }
+
+	    if ($rest =~ /^WITH\s+CARRY\s*(.*)/i) {
+		$rest = $1;
+		if ($op eq '+') {
+		    $code[$address] |= 0x01_00_00_00;
+		} else {
+		    die
+"$0 : syntax error in $lineno : $_
+	WITH CARRY option is incompatible with the $op operator.
+";
+		}
+	    }
+
+	    if ($rest !~ /^\s*$/) {
+		die
+"$0 : syntax error in $lineno : $_
+	Expected end of line, got $rest
+";
+	    }
+
+	    print STDERR "source = $src_reg, data = $data8 , destination = $dst_reg\n"
+		if ($debug);
+	    # Note that Move data8 to reg is encoded as a read-modify-write
+	    # instruction.
+	    if (($src_reg eq undef) || ($src_reg eq $dst_reg)) {
+		$code[$address] |= 0x38_00_00_00 | 
+		    ($registers{$dst_reg} << 16);
+	    } elsif ($dst_reg =~ /SFBR/i) {
+		$code[$address] |= 0x30_00_00_00 |
+		    ($registers{$src_reg} << 16);
+	    } elsif ($src_reg =~ /SFBR/i) {
+		$code[$address] |= 0x28_00_00_00 |
+		    ($registers{$dst_reg} << 16);
+	    } else {
+		die
+"$0 : Illegal combination of registers in line $lineno : $_
+	Either source and destination registers must be the same,
+	or either source or destination register must be SFBR.
+";
+	    }
+
+	    $code[$address] |= $operators{$op};
+	    
+	    &parse_value ($data8, 0, 1, 1);
+	    $code[$address] |= $operators{$op};
+	    $code[$address + 1] = 0x00_00_00_00;# Reserved
+	    $address += 2;
+	} else {
+	    die 
+"$0 : syntax error in line $lineno : $_
+	expected (initiator) <length>, <address>, WHEN <phase>
+		 (target) <length>, <address>, WITH <phase>
+		 MEMORY <length>, <source>, <destination>
+		 <expression> TO <register>
+";
+	}
+# Process SELECT {ATN|} id, fail_address
+    } elsif (/^\s*(SELECT|RESELECT)\s+(.*)/i) {
+	$rest = $2;
+	if ($rest =~ /^(ATN|)\s*($value)\s*,\s*($identifier)\s*$/i) {
+	    $atn = $1;
+	    $id = $2;
+	    $alt_addr = $3;
+	    $code[$address] = 0x40_00_00_00 | 
+		(($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
+	    $code[$address + 1] = 0x00_00_00_00;
+	    &parse_value($id, 0, 2, 1);
+	    &parse_value($alt_addr, 1, 0, 4);
+	    $address += 2;
+	} elsif ($rest =~ /^(ATN|)\s*FROM\s+($value)\s*,\s*($identifier)\s*$/i) {
+	    $atn = $1;
+	    $addr = $2;
+	    $alt_addr = $3;
+	    $code[$address] = 0x42_00_00_00 | 
+		(($atn =~ /ATN/i) ? 0x01_00_00_00 : 0);
+	    $code[$address + 1] = 0x00_00_00_00;
+	    &parse_value($addr, 0, 0, 3);
+	    &parse_value($alt_addr, 1, 0, 4);
+	    $address += 2;
+        } else {
+	    die 
+"$0 : syntax error in line $lineno : $_
+	expected SELECT id, alternate_address or 
+		SELECT FROM address, alternate_address or 
+		RESELECT id, alternate_address or
+		RESELECT FROM address, alternate_address
+";
+	}
+    } elsif (/^\s*WAIT\s+(.*)/i) {
+	    $rest = $1;
+print STDERR "Parsing WAIT $rest\n" if ($debug);
+	if ($rest =~ /^DISCONNECT\s*$/i) {
+	    $code[$address] = 0x48_00_00_00;
+	    $code[$address + 1] = 0x00_00_00_00;
+	    $address += 2;
+	} elsif ($rest =~ /^(RESELECT|SELECT)\s+($identifier)\s*$/i) {
+	    $alt_addr = $2;
+	    $code[$address] = 0x50_00_00_00;
+	    &parse_value ($alt_addr, 1, 0, 4);
+	    $address += 2;
+	} else {
+	    die
+"$0 : syntax error in line $lineno : $_
+	expected (initiator) WAIT DISCONNECT or 
+		 (initiator) WAIT RESELECT alternate_address or
+		 (target) WAIT SELECT alternate_address
+";
+	}
+# Handle SET and CLEAR instructions.  Note that we should also do something
+# with this syntax to set target mode.
+    } elsif (/^\s*(SET|CLEAR)\s+(.*)/i) {
+	$set = $1;
+	$list = $2;
+	$code[$address] = ($set =~ /SET/i) ?  0x58_00_00_00 : 
+	    0x60_00_00_00;
+	foreach $arg (split (/\s+AND\s+/i,$list)) {
+	    if ($arg =~ /ATN/i) {
+		$code[$address] |= 0x00_00_00_08;
+	    } elsif ($arg =~ /ACK/i) {
+		$code[$address] |= 0x00_00_00_40;
+	    } elsif ($arg =~ /TARGET/i) {
+		$code[$address] |= 0x00_00_02_00;
+	    } elsif ($arg =~ /CARRY/i) {
+		$code[$address] |= 0x00_00_04_00;
+	    } else {
+		die 
+"$0 : syntax error in line $lineno : $_
+	expected $set followed by a AND delimited list of one or 
+	more strings from the list ACK, ATN, CARRY, TARGET.
+";
+	    }
+	}
+	$code[$address + 1] = 0x00_00_00_00;
+	$address += 2;
+    } elsif (/^\s*(JUMP|CALL|INT)\s+(.*)/i) {
+	$instruction = $1;
+	$rest = $2;
+	if ($instruction =~ /JUMP/i) {
+	    $code[$address] = 0x80_00_00_00;
+	} elsif ($instruction =~ /CALL/i) {
+	    $code[$address] = 0x88_00_00_00;
+	} else {
+	    $code[$address] = 0x98_00_00_00;
+	}
+print STDERR "parsing JUMP, rest = $rest\n" if ($debug);
+
+# Relative jump. 
+	if ($rest =~ /^(REL\s*\(\s*$identifier\s*\))\s*(.*)/i) { 
+	    $addr = $1;
+	    $rest = $2;
+print STDERR "parsing JUMP REL, addr = $addr, rest = $rest\n" if ($debug);
+	    $code[$address]  |= 0x00_80_00_00;
+	    &parse_value($addr, 1, 0, 4);
+# Absolute jump, requires no more gunk
+	} elsif ($rest =~ /^($value)\s*(.*)/) {
+	    $addr = $1;
+	    $rest = $2;
+	    &parse_value($addr, 1, 0, 4);
+	} else {
+	    die
+"$0 : syntax error in line $lineno : $_
+	expected <address> or REL (address)
+";
+	}
+
+	if ($rest =~ /^,\s*(.*)/) {
+	    &parse_conditional($1);
+	} elsif ($rest =~ /^\s*$/) {
+	    $code[$address] |= (1 << 19);
+	} else {
+	    die
+"$0 : syntax error in line $lineno : $_
+	expected , <conditional> or end of line, got $1
+";
+	}
+	
+	$address += 2;
+    } elsif (/^\s*(RETURN|INTFLY)\s*(.*)/i) {
+	$instruction = $1;
+	$conditional = $2; 
+print STDERR "Parsing $instruction\n" if ($debug);
+	$code[$address] = ($instruction =~ /RETURN/i) ? 0x90_00_00_00 :
+	    0x98_10_00_00;
+	if ($conditional =~ /^,\s*(.*)/) {
+	    $conditional = $1;
+	    &parse_conditional ($conditional);
+	} elsif ($conditional !~ /^\s*$/) {
+	    die
+"$0 : syntax error in line $lineno : $_
+	expected , <conditional> 
+";
+	} else {
+	    $code[$address] |= 0x00_08_00_00;
+	}
+	   
+	$code[$address + 1] = 0x00_00_00_00;
+	$address += 2;
+    } elsif (/^\s*DISCONNECT\s*$/) {
+	$code[$address] = 0x48_00_00_00;
+	$code[$address + 1] = 0x00_00_00_00;
+	$address += 2;
+# I'm not sure that I should be including this extension, but 
+# what the hell?
+    } elsif (/^\s*NOP\s*$/i) {
+	$code[$address] = 0x80_88_00_00;
+	$code[$address + 1] = 0x00_00_00_00;
+	$address += 2;
+# Ignore lines consisting entirely of white space
+    } elsif (/^\s*$/) {
+    } else {
+	die 
+"$0 : syntax error in line $lineno: $_
+	expected label:, ABSOLUTE, CLEAR, DISCONNECT, EXTERNAL, MOVE, RESELECT,
+	    SELECT SET, or WAIT
+";
+    }
+}
+
+# Fill in label references
+
+@undefined = keys %forward;
+if ($#undefined >= 0) {
+    print STDERR "Undefined symbols : \n";
+    foreach $undef (@undefined) {
+	print STDERR "$undef in $forward{$undef}\n";
+    }
+    exit 1;
+}
+
+@label_patches = ();
+
+@external_patches = ();
+
+@absolute = sort @absolute;
+
+foreach $i (@absolute) {
+    foreach $j (split (/\s+/,$symbol_references{$i})) {
+	$j =~ /(REL|ABS),(.*),(.*)/;
+	$type = $1;
+	$address = $2;
+	$length = $3;
+	die 
+"$0 : $symbol $i has invalid relative reference at address $address,
+    size $length\n"
+	if ($type eq 'REL');
+	    
+	&patch ($address / 4, $address % 4, $length, $symbol_values{$i});
+    }
+}
+
+foreach $external (@external) {
+print STDERR "checking external $external \n" if ($debug_external);
+    if ($symbol_references{$external} ne undef) {
+	for $reference (split(/\s+/,$symbol_references{$external})) {
+	    $reference =~ /(REL|ABS),(.*),(.*)/;
+	    $type = $1;
+	    $address = $2;
+	    $length = $3;
+	    
+	    die 
+"$0 : symbol $label is external, has invalid relative reference at $address,
+    size $length\n"
+		if ($type eq 'REL');
+
+	    die 
+"$0 : symbol $label has invalid reference at $address, size $length\n"
+		if ((($address % 4) !=0) || ($length != 4));
+
+	    $symbol = $symbol_values{$external};
+	    $add = $code[$address / 4];
+	    if ($add eq 0) {
+		$code[$address / 4] = $symbol;
+	    } else {
+		$add = sprintf ("0x%08x", $add);
+		$code[$address / 4] = "$symbol + $add";
+	    }
+		
+print STDERR "referenced external $external at $1\n" if ($debug_external);
+	}
+    }
+}
+
+foreach $label (@label) {
+    if ($symbol_references{$label} ne undef) {
+	for $reference (split(/\s+/,$symbol_references{$label})) {
+	    $reference =~ /(REL|ABS),(.*),(.*)/;
+	    $type = $1;
+	    $address = $2;
+	    $length = $3;
+
+	    if ((($address % 4) !=0) || ($length != 4)) {
+		die "$0 : symbol $label has invalid reference at $1, size $2\n";
+	    }
+
+	    if ($type eq 'ABS') {
+		$code[$address / 4] += $symbol_values{$label};
+		push (@label_patches, $address / 4);
+	    } else {
+# 
+# - The address of the reference should be in the second and last word
+#	of an instruction
+# - Relative jumps, etc. are relative to the DSP of the _next_ instruction
+#
+# So, we need to add four to the address of the reference, to get 
+# the address of the next instruction, when computing the reference.
+  
+		$tmp = $symbol_values{$label} - 
+		    ($address + 4);
+		die 
+# Relative addressing is limited to 24 bits.
+"$0 : symbol $label is too far ($tmp) from $address to reference as 
+    relative/\n" if (($tmp >= 0x80_00_00) || ($tmp < -0x80_00_00));
+		$code[$address / 4] = $tmp & 0x00_ff_ff_ff;
+	    }
+	}
+    }
+}
+
+# Output SCRIPT[] array, one instruction per line.  Optionally 
+# print the original code too.
+
+open (OUTPUT, ">$output") || die "$0 : can't open $output for writing\n";
+open (OUTPUTU, ">$outputu") || die "$0 : can't open $outputu for writing\n";
+
+($_ = $0) =~ s:.*/::;
+print OUTPUT "/* DO NOT EDIT - Generated automatically by ".$_." */\n";
+print OUTPUT "static u32 ".$prefix."SCRIPT[] = {\n";
+$instructions = 0;
+for ($i = 0; $i < $#code; ) {
+    if ($list_in_array) {
+	printf OUTPUT "/*\n$list[$i]\nat 0x%08x : */", $i;
+    }
+    printf OUTPUT "\t0x%08x,", $code[$i];
+    printf STDERR "Address $i = %x\n", $code[$i] if ($debug);
+    if ($code[$i + 1] =~ /\s*($identifier)(.*)$/) {
+	push (@external_patches, $i+1, $1);
+	printf OUTPUT "0%s,", $2
+    } else {
+	printf OUTPUT "0x%08x,",$code[$i+1];
+    }
+
+    if (($code[$i] & 0xff_00_00_00) == 0xc0_00_00_00) {
+	if ($code[$i + 2] =~ /$identifier/) {
+	    push (@external_patches, $i+2, $code[$i+2]);
+	    printf OUTPUT "0,\n";
+	} else {
+	    printf OUTPUT "0x%08x,\n",$code[$i+2];
+	}
+	$i += 3;
+    } else {
+	printf OUTPUT "\n";
+	$i += 2;
+    }
+    $instructions += 1;
+}
+print OUTPUT "};\n\n";
+
+foreach $i (@absolute) {
+    printf OUTPUT "#define A_$i\t0x%08x\n", $symbol_values{$i};
+    if (defined($prefix) && $prefix ne '') {
+	printf OUTPUT "#define A_".$i."_used ".$prefix."A_".$i."_used\n";
+	printf OUTPUTU "#undef A_".$i."_used\n";
+    }
+    printf OUTPUTU "#undef A_$i\n";
+
+    printf OUTPUT "static u32 A_".$i."_used\[\] __attribute((unused)) = {\n";
+printf STDERR "$i is used $symbol_references{$i}\n" if ($debug);
+    foreach $j (split (/\s+/,$symbol_references{$i})) {
+	$j =~ /(ABS|REL),(.*),(.*)/;
+	if ($1 eq 'ABS') {
+	    $address = $2;
+	    $length = $3;
+	    printf OUTPUT "\t0x%08x,\n", $address / 4;
+	}
+    }
+    printf OUTPUT "};\n\n";
+}
+
+foreach $i (sort @entry) {
+    printf OUTPUT "#define Ent_$i\t0x%08x\n", $symbol_values{$i};
+    printf OUTPUTU "#undef Ent_$i\n", $symbol_values{$i};
+}
+
+#
+# NCR assembler outputs label patches in the form of indices into 
+# the code.
+#
+printf OUTPUT "static u32 ".$prefix."LABELPATCHES[] __attribute((unused)) = {\n";
+for $patch (sort {$a <=> $b} @label_patches) {
+    printf OUTPUT "\t0x%08x,\n", $patch;
+}
+printf OUTPUT "};\n\n";
+
+$num_external_patches = 0;
+printf OUTPUT "static struct {\n\tu32\toffset;\n\tvoid\t\t*address;\n".
+    "} ".$prefix."EXTERNAL_PATCHES[] __attribute((unused)) = {\n";
+while ($ident = pop(@external_patches)) {
+    $off = pop(@external_patches);
+    printf OUTPUT "\t{0x%08x, &%s},\n", $off, $ident;
+    ++$num_external_patches;
+}
+printf OUTPUT "};\n\n";
+
+printf OUTPUT "static u32 ".$prefix."INSTRUCTIONS __attribute((unused))\t= %d;\n", 
+    $instructions;
+printf OUTPUT "static u32 ".$prefix."PATCHES __attribute((unused))\t= %d;\n", 
+    $#label_patches+1;
+printf OUTPUT "static u32 ".$prefix."EXTERNAL_PATCHES_LEN __attribute((unused))\t= %d;\n",
+    $num_external_patches;
+close OUTPUT;
+close OUTPUTU;
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
new file mode 100644
index 0000000..2e7ab3a
--- /dev/null
+++ b/drivers/scsi/scsi.c
@@ -0,0 +1,1375 @@
+/*
+ *  scsi.c Copyright (C) 1992 Drew Eckhardt
+ *         Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
+ *         Copyright (C) 2002, 2003 Christoph Hellwig
+ *
+ *  generic mid-level SCSI driver
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
+ *
+ *  <drew@colorado.edu>
+ *
+ *  Bug correction thanks go to :
+ *      Rik Faith <faith@cs.unc.edu>
+ *      Tommy Thorn <tthorn>
+ *      Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ *
+ *  Modified by Eric Youngdale eric@andante.org or ericy@gnu.ai.mit.edu to
+ *  add scatter-gather, multiple outstanding request, and other
+ *  enhancements.
+ *
+ *  Native multichannel, wide scsi, /proc/scsi and hot plugging
+ *  support added by Michael Neuffer <mike@i-connect.net>
+ *
+ *  Added request_module("scsi_hostadapter") for kerneld:
+ *  (Put an "alias scsi_hostadapter your_hostadapter" in /etc/modprobe.conf)
+ *  Bjorn Ekwall  <bj0rn@blox.se>
+ *  (changed to kmod)
+ *
+ *  Major improvements to the timeout, abort, and reset processing,
+ *  as well as performance modifications for large queue depths by
+ *  Leonard N. Zubkoff <lnz@dandelion.com>
+ *
+ *  Converted cli() code to spinlocks, Ingo Molnar
+ *
+ *  Jiffies wrap fixes (host->resetting), 3 Dec 1998 Andrea Arcangeli
+ *
+ *  out_of_space hacks, D. Gilbert (dpg) 990608
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/completion.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/unistd.h>
+#include <linux/spinlock.h>
+#include <linux/kmod.h>
+#include <linux/interrupt.h>
+#include <linux/notifier.h>
+#include <linux/cpu.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_request.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
+/*
+ * Definitions and constants.
+ */
+
+#define MIN_RESET_DELAY (2*HZ)
+
+/* Do not call reset on error if we just did a reset within 15 sec. */
+#define MIN_RESET_PERIOD (15*HZ)
+
+/*
+ * Macro to determine the size of SCSI command. This macro takes vendor
+ * unique commands into account. SCSI commands in groups 6 and 7 are
+ * vendor unique and we will depend upon the command length being
+ * supplied correctly in cmd_len.
+ */
+#define CDB_SIZE(cmd)	(((((cmd)->cmnd[0] >> 5) & 7) < 6) ? \
+				COMMAND_SIZE((cmd)->cmnd[0]) : (cmd)->cmd_len)
+
+/*
+ * Note - the initial logging level can be set here to log events at boot time.
+ * After the system is up, you may enable logging via the /proc interface.
+ */
+unsigned int scsi_logging_level;
+#if defined(CONFIG_SCSI_LOGGING)
+EXPORT_SYMBOL(scsi_logging_level);
+#endif
+
+const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] = {
+	"Direct-Access    ",
+	"Sequential-Access",
+	"Printer          ",
+	"Processor        ",
+	"WORM             ",
+	"CD-ROM           ",
+	"Scanner          ",
+	"Optical Device   ",
+	"Medium Changer   ",
+	"Communications   ",
+	"Unknown          ",
+	"Unknown          ",
+	"RAID             ",
+	"Enclosure        ",
+};
+EXPORT_SYMBOL(scsi_device_types);
+
+/*
+ * Function:    scsi_allocate_request
+ *
+ * Purpose:     Allocate a request descriptor.
+ *
+ * Arguments:   device		- device for which we want a request
+ *		gfp_mask	- allocation flags passed to kmalloc
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ *
+ * Returns:     Pointer to request block.
+ */
+struct scsi_request *scsi_allocate_request(struct scsi_device *sdev,
+					   int gfp_mask)
+{
+	const int offset = ALIGN(sizeof(struct scsi_request), 4);
+	const int size = offset + sizeof(struct request);
+	struct scsi_request *sreq;
+  
+	sreq = kmalloc(size, gfp_mask);
+	if (likely(sreq != NULL)) {
+		memset(sreq, 0, size);
+		sreq->sr_request = (struct request *)(((char *)sreq) + offset);
+		sreq->sr_device = sdev;
+		sreq->sr_host = sdev->host;
+		sreq->sr_magic = SCSI_REQ_MAGIC;
+		sreq->sr_data_direction = DMA_BIDIRECTIONAL;
+	}
+
+	return sreq;
+}
+EXPORT_SYMBOL(scsi_allocate_request);
+
+void __scsi_release_request(struct scsi_request *sreq)
+{
+	struct request *req = sreq->sr_request;
+
+	/* unlikely because the tag was usually ended earlier by the
+	 * mid-layer. However, for layering reasons ULD's don't end
+	 * the tag of commands they generate. */
+	if (unlikely(blk_rq_tagged(req))) {
+		unsigned long flags;
+		struct request_queue *q = req->q;
+
+		spin_lock_irqsave(q->queue_lock, flags);
+		blk_queue_end_tag(q, req);
+		spin_unlock_irqrestore(q->queue_lock, flags);
+	}
+
+
+	if (likely(sreq->sr_command != NULL)) {
+		struct scsi_cmnd *cmd = sreq->sr_command;
+
+		sreq->sr_command = NULL;
+		scsi_next_command(cmd);
+	}
+}
+
+/*
+ * Function:    scsi_release_request
+ *
+ * Purpose:     Release a request descriptor.
+ *
+ * Arguments:   sreq    - request to release
+ *
+ * Lock status: No locks assumed to be held.  This function is SMP-safe.
+ */
+void scsi_release_request(struct scsi_request *sreq)
+{
+	__scsi_release_request(sreq);
+	kfree(sreq);
+}
+EXPORT_SYMBOL(scsi_release_request);
+
+struct scsi_host_cmd_pool {
+	kmem_cache_t	*slab;
+	unsigned int	users;
+	char		*name;
+	unsigned int	slab_flags;
+	unsigned int	gfp_mask;
+};
+
+static struct scsi_host_cmd_pool scsi_cmd_pool = {
+	.name		= "scsi_cmd_cache",
+	.slab_flags	= SLAB_HWCACHE_ALIGN,
+};
+
+static struct scsi_host_cmd_pool scsi_cmd_dma_pool = {
+	.name		= "scsi_cmd_cache(DMA)",
+	.slab_flags	= SLAB_HWCACHE_ALIGN|SLAB_CACHE_DMA,
+	.gfp_mask	= __GFP_DMA,
+};
+
+static DECLARE_MUTEX(host_cmd_pool_mutex);
+
+static struct scsi_cmnd *__scsi_get_command(struct Scsi_Host *shost,
+					    int gfp_mask)
+{
+	struct scsi_cmnd *cmd;
+
+	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
+			gfp_mask | shost->cmd_pool->gfp_mask);
+
+	if (unlikely(!cmd)) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&shost->free_list_lock, flags);
+		if (likely(!list_empty(&shost->free_list))) {
+			cmd = list_entry(shost->free_list.next,
+					 struct scsi_cmnd, list);
+			list_del_init(&cmd->list);
+		}
+		spin_unlock_irqrestore(&shost->free_list_lock, flags);
+	}
+
+	return cmd;
+}
+
+/*
+ * Function:	scsi_get_command()
+ *
+ * Purpose:	Allocate and setup a scsi command block
+ *
+ * Arguments:	dev	- parent scsi device
+ *		gfp_mask- allocator flags
+ *
+ * Returns:	The allocated scsi command structure.
+ */
+struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int gfp_mask)
+{
+	struct scsi_cmnd *cmd;
+
+	/* Bail if we can't get a reference to the device */
+	if (!get_device(&dev->sdev_gendev))
+		return NULL;
+
+	cmd = __scsi_get_command(dev->host, gfp_mask);
+
+	if (likely(cmd != NULL)) {
+		unsigned long flags;
+
+		memset(cmd, 0, sizeof(*cmd));
+		cmd->device = dev;
+		cmd->state = SCSI_STATE_UNUSED;
+		cmd->owner = SCSI_OWNER_NOBODY;
+		init_timer(&cmd->eh_timeout);
+		INIT_LIST_HEAD(&cmd->list);
+		spin_lock_irqsave(&dev->list_lock, flags);
+		list_add_tail(&cmd->list, &dev->cmd_list);
+		spin_unlock_irqrestore(&dev->list_lock, flags);
+	} else
+		put_device(&dev->sdev_gendev);
+
+	return cmd;
+}				
+EXPORT_SYMBOL(scsi_get_command);
+
+/*
+ * Function:	scsi_put_command()
+ *
+ * Purpose:	Free a scsi command block
+ *
+ * Arguments:	cmd	- command block to free
+ *
+ * Returns:	Nothing.
+ *
+ * Notes:	The command must not belong to any lists.
+ */
+void scsi_put_command(struct scsi_cmnd *cmd)
+{
+	struct scsi_device *sdev = cmd->device;
+	struct Scsi_Host *shost = sdev->host;
+	unsigned long flags;
+	
+	/* serious error if the command hasn't come from a device list */
+	spin_lock_irqsave(&cmd->device->list_lock, flags);
+	BUG_ON(list_empty(&cmd->list));
+	list_del_init(&cmd->list);
+	spin_unlock(&cmd->device->list_lock);
+	/* changing locks here, don't need to restore the irq state */
+	spin_lock(&shost->free_list_lock);
+	if (unlikely(list_empty(&shost->free_list))) {
+		list_add(&cmd->list, &shost->free_list);
+		cmd = NULL;
+	}
+	spin_unlock_irqrestore(&shost->free_list_lock, flags);
+
+	if (likely(cmd != NULL))
+		kmem_cache_free(shost->cmd_pool->slab, cmd);
+
+	put_device(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL(scsi_put_command);
+
+/*
+ * Function:	scsi_setup_command_freelist()
+ *
+ * Purpose:	Setup the command freelist for a scsi host.
+ *
+ * Arguments:	shost	- host to allocate the freelist for.
+ *
+ * Returns:	Nothing.
+ */
+int scsi_setup_command_freelist(struct Scsi_Host *shost)
+{
+	struct scsi_host_cmd_pool *pool;
+	struct scsi_cmnd *cmd;
+
+	spin_lock_init(&shost->free_list_lock);
+	INIT_LIST_HEAD(&shost->free_list);
+
+	/*
+	 * Select a command slab for this host and create it if not
+	 * yet existant.
+	 */
+	down(&host_cmd_pool_mutex);
+	pool = (shost->unchecked_isa_dma ? &scsi_cmd_dma_pool : &scsi_cmd_pool);
+	if (!pool->users) {
+		pool->slab = kmem_cache_create(pool->name,
+				sizeof(struct scsi_cmnd), 0,
+				pool->slab_flags, NULL, NULL);
+		if (!pool->slab)
+			goto fail;
+	}
+
+	pool->users++;
+	shost->cmd_pool = pool;
+	up(&host_cmd_pool_mutex);
+
+	/*
+	 * Get one backup command for this host.
+	 */
+	cmd = kmem_cache_alloc(shost->cmd_pool->slab,
+			GFP_KERNEL | shost->cmd_pool->gfp_mask);
+	if (!cmd)
+		goto fail2;
+	list_add(&cmd->list, &shost->free_list);		
+	return 0;
+
+ fail2:
+	if (!--pool->users)
+		kmem_cache_destroy(pool->slab);
+	return -ENOMEM;
+ fail:
+	up(&host_cmd_pool_mutex);
+	return -ENOMEM;
+
+}
+
+/*
+ * Function:	scsi_destroy_command_freelist()
+ *
+ * Purpose:	Release the command freelist for a scsi host.
+ *
+ * Arguments:	shost	- host that's freelist is going to be destroyed
+ */
+void scsi_destroy_command_freelist(struct Scsi_Host *shost)
+{
+	while (!list_empty(&shost->free_list)) {
+		struct scsi_cmnd *cmd;
+
+		cmd = list_entry(shost->free_list.next, struct scsi_cmnd, list);
+		list_del_init(&cmd->list);
+		kmem_cache_free(shost->cmd_pool->slab, cmd);
+	}
+
+	down(&host_cmd_pool_mutex);
+	if (!--shost->cmd_pool->users)
+		kmem_cache_destroy(shost->cmd_pool->slab);
+	up(&host_cmd_pool_mutex);
+}
+
+#ifdef CONFIG_SCSI_LOGGING
+void scsi_log_send(struct scsi_cmnd *cmd)
+{
+	unsigned int level;
+	struct scsi_device *sdev;
+
+	/*
+	 * If ML QUEUE log level is greater than or equal to:
+	 *
+	 * 1: nothing (match completion)
+	 *
+	 * 2: log opcode + command of all commands
+	 *
+	 * 3: same as 2 plus dump cmd address
+	 *
+	 * 4: same as 3 plus dump extra junk
+	 */
+	if (unlikely(scsi_logging_level)) {
+		level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
+				       SCSI_LOG_MLQUEUE_BITS);
+		if (level > 1) {
+			sdev = cmd->device;
+			printk(KERN_INFO "scsi <%d:%d:%d:%d> send ",
+			       sdev->host->host_no, sdev->channel, sdev->id,
+			       sdev->lun);
+			if (level > 2)
+				printk("0x%p ", cmd);
+			/*
+			 * spaces to match disposition and cmd->result
+			 * output in scsi_log_completion.
+			 */
+			printk("                 ");
+			scsi_print_command(cmd);
+			if (level > 3) {
+				printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
+				       " done = 0x%p, queuecommand 0x%p\n",
+					cmd->buffer, cmd->bufflen,
+					cmd->done,
+					sdev->host->hostt->queuecommand);
+
+			}
+		}
+	}
+}
+
+void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
+{
+	unsigned int level;
+	struct scsi_device *sdev;
+
+	/*
+	 * If ML COMPLETE log level is greater than or equal to:
+	 *
+	 * 1: log disposition, result, opcode + command, and conditionally
+	 * sense data for failures or non SUCCESS dispositions.
+	 *
+	 * 2: same as 1 but for all command completions.
+	 *
+	 * 3: same as 2 plus dump cmd address
+	 *
+	 * 4: same as 3 plus dump extra junk
+	 */
+	if (unlikely(scsi_logging_level)) {
+		level = SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT,
+				       SCSI_LOG_MLCOMPLETE_BITS);
+		if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
+		    (level > 1)) {
+			sdev = cmd->device;
+			printk(KERN_INFO "scsi <%d:%d:%d:%d> done ",
+			       sdev->host->host_no, sdev->channel, sdev->id,
+			       sdev->lun);
+			if (level > 2)
+				printk("0x%p ", cmd);
+			/*
+			 * Dump truncated values, so we usually fit within
+			 * 80 chars.
+			 */
+			switch (disposition) {
+			case SUCCESS:
+				printk("SUCCESS");
+				break;
+			case NEEDS_RETRY:
+				printk("RETRY  ");
+				break;
+			case ADD_TO_MLQUEUE:
+				printk("MLQUEUE");
+				break;
+			case FAILED:
+				printk("FAILED ");
+				break;
+			case TIMEOUT_ERROR:
+				/* 
+				 * If called via scsi_times_out.
+				 */
+				printk("TIMEOUT");
+				break;
+			default:
+				printk("UNKNOWN");
+			}
+			printk(" %8x ", cmd->result);
+			scsi_print_command(cmd);
+			if (status_byte(cmd->result) & CHECK_CONDITION) {
+				/*
+				 * XXX The print_sense formatting/prefix
+				 * doesn't match this function.
+				 */
+				scsi_print_sense("", cmd);
+			}
+			if (level > 3) {
+				printk(KERN_INFO "scsi host busy %d failed %d\n",
+				       sdev->host->host_busy,
+				       sdev->host->host_failed);
+			}
+		}
+	}
+}
+#endif
+
+/* 
+ * Assign a serial number and pid to the request for error recovery
+ * and debugging purposes.  Protected by the Host_Lock of host.
+ */
+static inline void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
+{
+	cmd->serial_number = host->cmd_serial_number++;
+	if (cmd->serial_number == 0) 
+		cmd->serial_number = host->cmd_serial_number++;
+	
+	cmd->pid = host->cmd_pid++;
+	if (cmd->pid == 0)
+		cmd->pid = host->cmd_pid++;
+}
+
+/*
+ * Function:    scsi_dispatch_command
+ *
+ * Purpose:     Dispatch a command to the low-level driver.
+ *
+ * Arguments:   cmd - command block we are dispatching.
+ *
+ * Notes:
+ */
+int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+{
+	struct Scsi_Host *host = cmd->device->host;
+	unsigned long flags = 0;
+	unsigned long timeout;
+	int rtn = 0;
+
+	/* check if the device is still usable */
+	if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
+		/* in SDEV_DEL we error all commands. DID_NO_CONNECT
+		 * returns an immediate error upwards, and signals
+		 * that the device is no longer present */
+		cmd->result = DID_NO_CONNECT << 16;
+		atomic_inc(&cmd->device->iorequest_cnt);
+		scsi_done(cmd);
+		/* return 0 (because the command has been processed) */
+		goto out;
+	}
+
+	/* Check to see if the scsi lld put this device into state SDEV_BLOCK. */
+	if (unlikely(cmd->device->sdev_state == SDEV_BLOCK)) {
+		/* 
+		 * in SDEV_BLOCK, the command is just put back on the device
+		 * queue.  The suspend state has already blocked the queue so
+		 * future requests should not occur until the device 
+		 * transitions out of the suspend state.
+		 */
+		scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+
+		SCSI_LOG_MLQUEUE(3, printk("queuecommand : device blocked \n"));
+
+		/*
+		 * NOTE: rtn is still zero here because we don't need the
+		 * queue to be plugged on return (it's already stopped)
+		 */
+		goto out;
+	}
+
+	/* 
+	 * If SCSI-2 or lower, store the LUN value in cmnd.
+	 */
+	if (cmd->device->scsi_level <= SCSI_2) {
+		cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
+			       (cmd->device->lun << 5 & 0xe0);
+	}
+
+	/*
+	 * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+	 * we can avoid the drive not being ready.
+	 */
+	timeout = host->last_reset + MIN_RESET_DELAY;
+
+	if (host->resetting && time_before(jiffies, timeout)) {
+		int ticks_remaining = timeout - jiffies;
+		/*
+		 * NOTE: This may be executed from within an interrupt
+		 * handler!  This is bad, but for now, it'll do.  The irq
+		 * level of the interrupt handler has been masked out by the
+		 * platform dependent interrupt handling code already, so the
+		 * sti() here will not cause another call to the SCSI host's
+		 * interrupt handler (assuming there is one irq-level per
+		 * host).
+		 */
+		while (--ticks_remaining >= 0)
+			mdelay(1 + 999 / HZ);
+		host->resetting = 0;
+	}
+
+	/* 
+	 * AK: unlikely race here: for some reason the timer could
+	 * expire before the serial number is set up below.
+	 */
+	scsi_add_timer(cmd, cmd->timeout_per_command, scsi_times_out);
+
+	scsi_log_send(cmd);
+
+	/*
+	 * We will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+
+	cmd->state = SCSI_STATE_QUEUED;
+	cmd->owner = SCSI_OWNER_LOWLEVEL;
+
+	atomic_inc(&cmd->device->iorequest_cnt);
+
+	/*
+	 * Before we queue this command, check if the command
+	 * length exceeds what the host adapter can handle.
+	 */
+	if (CDB_SIZE(cmd) > cmd->device->host->max_cmd_len) {
+		SCSI_LOG_MLQUEUE(3,
+				printk("queuecommand : command too long.\n"));
+		cmd->result = (DID_ABORT << 16);
+
+		scsi_done(cmd);
+		goto out;
+	}
+
+	spin_lock_irqsave(host->host_lock, flags);
+	scsi_cmd_get_serial(host, cmd); 
+
+	if (unlikely(test_bit(SHOST_CANCEL, &host->shost_state))) {
+		cmd->result = (DID_NO_CONNECT << 16);
+		scsi_done(cmd);
+	} else {
+		rtn = host->hostt->queuecommand(cmd, scsi_done);
+	}
+	spin_unlock_irqrestore(host->host_lock, flags);
+	if (rtn) {
+		atomic_inc(&cmd->device->iodone_cnt);
+		scsi_queue_insert(cmd,
+				(rtn == SCSI_MLQUEUE_DEVICE_BUSY) ?
+				 rtn : SCSI_MLQUEUE_HOST_BUSY);
+		SCSI_LOG_MLQUEUE(3,
+		    printk("queuecommand : request rejected\n"));
+	}
+
+ out:
+	SCSI_LOG_MLQUEUE(3, printk("leaving scsi_dispatch_cmnd()\n"));
+	return rtn;
+}
+
+/*
+ * Function:    scsi_init_cmd_from_req
+ *
+ * Purpose:     Queue a SCSI command
+ * Purpose:     Initialize a struct scsi_cmnd from a struct scsi_request
+ *
+ * Arguments:   cmd       - command descriptor.
+ *              sreq      - Request from the queue.
+ *
+ * Lock status: None needed.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:       Mainly transfer data from the request structure to the
+ *              command structure.  The request structure is allocated
+ *              using the normal memory allocator, and requests can pile
+ *              up to more or less any depth.  The command structure represents
+ *              a consumable resource, as these are allocated into a pool
+ *              when the SCSI subsystem initializes.  The preallocation is
+ *              required so that in low-memory situations a disk I/O request
+ *              won't cause the memory manager to try and write out a page.
+ *              The request structure is generally used by ioctls and character
+ *              devices.
+ */
+void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq)
+{
+	sreq->sr_command = cmd;
+
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+	cmd->cmd_len = sreq->sr_cmd_len;
+	cmd->use_sg = sreq->sr_use_sg;
+
+	cmd->request = sreq->sr_request;
+	memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd));
+	cmd->serial_number = 0;
+	cmd->serial_number_at_timeout = 0;
+	cmd->bufflen = sreq->sr_bufflen;
+	cmd->buffer = sreq->sr_buffer;
+	cmd->retries = 0;
+	cmd->allowed = sreq->sr_allowed;
+	cmd->done = sreq->sr_done;
+	cmd->timeout_per_command = sreq->sr_timeout_per_command;
+	cmd->sc_data_direction = sreq->sr_data_direction;
+	cmd->sglist_len = sreq->sr_sglist_len;
+	cmd->underflow = sreq->sr_underflow;
+	cmd->sc_request = sreq;
+	memcpy(cmd->cmnd, sreq->sr_cmnd, sizeof(sreq->sr_cmnd));
+
+	/*
+	 * Zero the sense buffer.  Some host adapters automatically request
+	 * sense on error.  0 is not a valid sense code.
+	 */
+	memset(cmd->sense_buffer, 0, sizeof(sreq->sr_sense_buffer));
+	cmd->request_buffer = sreq->sr_buffer;
+	cmd->request_bufflen = sreq->sr_bufflen;
+	cmd->old_use_sg = cmd->use_sg;
+	if (cmd->cmd_len == 0)
+		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+	cmd->old_cmd_len = cmd->cmd_len;
+	cmd->sc_old_data_direction = cmd->sc_data_direction;
+	cmd->old_underflow = cmd->underflow;
+
+	/*
+	 * Start the timer ticking.
+	 */
+	cmd->internal_timeout = NORMAL_TIMEOUT;
+	cmd->abort_reason = 0;
+	cmd->result = 0;
+
+	SCSI_LOG_MLQUEUE(3, printk("Leaving scsi_init_cmd_from_req()\n"));
+}
+
+/*
+ * Per-CPU I/O completion queue.
+ */
+static DEFINE_PER_CPU(struct list_head, scsi_done_q);
+
+/**
+ * scsi_done - Enqueue the finished SCSI command into the done queue.
+ * @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
+ * ownership back to SCSI Core -- i.e. the LLDD has finished with it.
+ *
+ * This function is the mid-level's (SCSI Core) interrupt routine, which
+ * regains ownership of the SCSI command (de facto) from a LLDD, and enqueues
+ * the command to the done queue for further processing.
+ *
+ * This is the producer of the done queue who enqueues at the tail.
+ *
+ * This function is interrupt context safe.
+ */
+void scsi_done(struct scsi_cmnd *cmd)
+{
+	/*
+	 * We don't have to worry about this one timing out any more.
+	 * If we are unable to remove the timer, then the command
+	 * has already timed out.  In which case, we have no choice but to
+	 * let the timeout function run, as we have no idea where in fact
+	 * that function could really be.  It might be on another processor,
+	 * etc, etc.
+	 */
+	if (!scsi_delete_timer(cmd))
+		return;
+	__scsi_done(cmd);
+}
+
+/* Private entry to scsi_done() to complete a command when the timer
+ * isn't running --- used by scsi_times_out */
+void __scsi_done(struct scsi_cmnd *cmd)
+{
+	unsigned long flags;
+
+	/*
+	 * Set the serial numbers back to zero
+	 */
+	cmd->serial_number = 0;
+	cmd->serial_number_at_timeout = 0;
+	cmd->state = SCSI_STATE_BHQUEUE;
+	cmd->owner = SCSI_OWNER_BH_HANDLER;
+
+	atomic_inc(&cmd->device->iodone_cnt);
+	if (cmd->result)
+		atomic_inc(&cmd->device->ioerr_cnt);
+
+	/*
+	 * Next, enqueue the command into the done queue.
+	 * It is a per-CPU queue, so we just disable local interrupts
+	 * and need no spinlock.
+	 */
+	local_irq_save(flags);
+	list_add_tail(&cmd->eh_entry, &__get_cpu_var(scsi_done_q));
+	raise_softirq_irqoff(SCSI_SOFTIRQ);
+	local_irq_restore(flags);
+}
+
+/**
+ * scsi_softirq - Perform post-interrupt processing of finished SCSI commands.
+ *
+ * This is the consumer of the done queue.
+ *
+ * This is called with all interrupts enabled.  This should reduce
+ * interrupt latency, stack depth, and reentrancy of the low-level
+ * drivers.
+ */
+static void scsi_softirq(struct softirq_action *h)
+{
+	int disposition;
+	LIST_HEAD(local_q);
+
+	local_irq_disable();
+	list_splice_init(&__get_cpu_var(scsi_done_q), &local_q);
+	local_irq_enable();
+
+	while (!list_empty(&local_q)) {
+		struct scsi_cmnd *cmd = list_entry(local_q.next,
+						   struct scsi_cmnd, eh_entry);
+		list_del_init(&cmd->eh_entry);
+
+		disposition = scsi_decide_disposition(cmd);
+		scsi_log_completion(cmd, disposition);
+		switch (disposition) {
+		case SUCCESS:
+			scsi_finish_command(cmd);
+			break;
+		case NEEDS_RETRY:
+			scsi_retry_command(cmd);
+			break;
+		case ADD_TO_MLQUEUE:
+			scsi_queue_insert(cmd, SCSI_MLQUEUE_DEVICE_BUSY);
+			break;
+		default:
+			if (!scsi_eh_scmd_add(cmd, 0))
+				scsi_finish_command(cmd);
+		}
+	}
+}
+
+/*
+ * Function:    scsi_retry_command
+ *
+ * Purpose:     Send a command back to the low level to be retried.
+ *
+ * Notes:       This command is always executed in the context of the
+ *              bottom half handler, or the error handler thread. Low
+ *              level drivers should not become re-entrant as a result of
+ *              this.
+ */
+int scsi_retry_command(struct scsi_cmnd *cmd)
+{
+	/*
+	 * Restore the SCSI command state.
+	 */
+	scsi_setup_cmd_retry(cmd);
+
+        /*
+         * Zero the sense information from the last time we tried
+         * this command.
+         */
+	memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+	return scsi_queue_insert(cmd, SCSI_MLQUEUE_EH_RETRY);
+}
+
+/*
+ * Function:    scsi_finish_command
+ *
+ * Purpose:     Pass command off to upper layer for finishing of I/O
+ *              request, waking processes that are waiting on results,
+ *              etc.
+ */
+void scsi_finish_command(struct scsi_cmnd *cmd)
+{
+	struct scsi_device *sdev = cmd->device;
+	struct Scsi_Host *shost = sdev->host;
+	struct scsi_request *sreq;
+
+	scsi_device_unbusy(sdev);
+
+        /*
+         * Clear the flags which say that the device/host is no longer
+         * capable of accepting new commands.  These are set in scsi_queue.c
+         * for both the queue full condition on a device, and for a
+         * host full condition on the host.
+	 *
+	 * XXX(hch): What about locking?
+         */
+        shost->host_blocked = 0;
+        sdev->device_blocked = 0;
+
+	/*
+	 * If we have valid sense information, then some kind of recovery
+	 * must have taken place.  Make a note of this.
+	 */
+	if (SCSI_SENSE_VALID(cmd))
+		cmd->result |= (DRIVER_SENSE << 24);
+
+	SCSI_LOG_MLCOMPLETE(4, printk("Notifying upper driver of completion "
+				"for device %d %x\n", sdev->id, cmd->result));
+
+	cmd->owner = SCSI_OWNER_HIGHLEVEL;
+	cmd->state = SCSI_STATE_FINISHED;
+
+	/*
+	 * We can get here with use_sg=0, causing a panic in the upper level
+	 */
+	cmd->use_sg = cmd->old_use_sg;
+
+	/*
+	 * If there is an associated request structure, copy the data over
+	 * before we call the completion function.
+	 */
+	sreq = cmd->sc_request;
+	if (sreq) {
+	       sreq->sr_result = sreq->sr_command->result;
+	       if (sreq->sr_result) {
+		       memcpy(sreq->sr_sense_buffer,
+			      sreq->sr_command->sense_buffer,
+			      sizeof(sreq->sr_sense_buffer));
+	       }
+	}
+
+	cmd->done(cmd);
+}
+EXPORT_SYMBOL(scsi_finish_command);
+
+/*
+ * Function:	scsi_adjust_queue_depth()
+ *
+ * Purpose:	Allow low level drivers to tell us to change the queue depth
+ * 		on a specific SCSI device
+ *
+ * Arguments:	sdev	- SCSI Device in question
+ * 		tagged	- Do we use tagged queueing (non-0) or do we treat
+ * 			  this device as an untagged device (0)
+ * 		tags	- Number of tags allowed if tagged queueing enabled,
+ * 			  or number of commands the low level driver can
+ * 			  queue up in non-tagged mode (as per cmd_per_lun).
+ *
+ * Returns:	Nothing
+ *
+ * Lock Status:	None held on entry
+ *
+ * Notes:	Low level drivers may call this at any time and we will do
+ * 		the right thing depending on whether or not the device is
+ * 		currently active and whether or not it even has the
+ * 		command blocks built yet.
+ */
+void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
+{
+	unsigned long flags;
+
+	/*
+	 * refuse to set tagged depth to an unworkable size
+	 */
+	if (tags <= 0)
+		return;
+
+	spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
+
+	/* Check to see if the queue is managed by the block layer
+	 * if it is, and we fail to adjust the depth, exit */
+	if (blk_queue_tagged(sdev->request_queue) &&
+	    blk_queue_resize_tags(sdev->request_queue, tags) != 0)
+		goto out;
+
+	sdev->queue_depth = tags;
+	switch (tagged) {
+		case MSG_ORDERED_TAG:
+			sdev->ordered_tags = 1;
+			sdev->simple_tags = 1;
+			break;
+		case MSG_SIMPLE_TAG:
+			sdev->ordered_tags = 0;
+			sdev->simple_tags = 1;
+			break;
+		default:
+			printk(KERN_WARNING "(scsi%d:%d:%d:%d) "
+				"scsi_adjust_queue_depth, bad queue type, "
+				"disabled\n", sdev->host->host_no,
+				sdev->channel, sdev->id, sdev->lun); 
+		case 0:
+			sdev->ordered_tags = sdev->simple_tags = 0;
+			sdev->queue_depth = tags;
+			break;
+	}
+ out:
+	spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+}
+EXPORT_SYMBOL(scsi_adjust_queue_depth);
+
+/*
+ * Function:	scsi_track_queue_full()
+ *
+ * Purpose:	This function will track successive QUEUE_FULL events on a
+ * 		specific SCSI device to determine if and when there is a
+ * 		need to adjust the queue depth on the device.
+ *
+ * Arguments:	sdev	- SCSI Device in question
+ * 		depth	- Current number of outstanding SCSI commands on
+ * 			  this device, not counting the one returned as
+ * 			  QUEUE_FULL.
+ *
+ * Returns:	0 - No change needed
+ * 		>0 - Adjust queue depth to this new depth
+ * 		-1 - Drop back to untagged operation using host->cmd_per_lun
+ * 			as the untagged command depth
+ *
+ * Lock Status:	None held on entry
+ *
+ * Notes:	Low level drivers may call this at any time and we will do
+ * 		"The Right Thing."  We are interrupt context safe.
+ */
+int scsi_track_queue_full(struct scsi_device *sdev, int depth)
+{
+	if ((jiffies >> 4) == sdev->last_queue_full_time)
+		return 0;
+
+	sdev->last_queue_full_time = (jiffies >> 4);
+	if (sdev->last_queue_full_depth != depth) {
+		sdev->last_queue_full_count = 1;
+		sdev->last_queue_full_depth = depth;
+	} else {
+		sdev->last_queue_full_count++;
+	}
+
+	if (sdev->last_queue_full_count <= 10)
+		return 0;
+	if (sdev->last_queue_full_depth < 8) {
+		/* Drop back to untagged */
+		scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+		return -1;
+	}
+	
+	if (sdev->ordered_tags)
+		scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
+	else
+		scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+	return depth;
+}
+EXPORT_SYMBOL(scsi_track_queue_full);
+
+/**
+ * scsi_device_get  -  get an addition reference to a scsi_device
+ * @sdev:	device to get a reference to
+ *
+ * Gets a reference to the scsi_device and increments the use count
+ * of the underlying LLDD module.  You must hold host_lock of the
+ * parent Scsi_Host or already have a reference when calling this.
+ */
+int scsi_device_get(struct scsi_device *sdev)
+{
+	if (sdev->sdev_state == SDEV_DEL || sdev->sdev_state == SDEV_CANCEL)
+		return -ENXIO;
+	if (!get_device(&sdev->sdev_gendev))
+		return -ENXIO;
+	if (!try_module_get(sdev->host->hostt->module)) {
+		put_device(&sdev->sdev_gendev);
+		return -ENXIO;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(scsi_device_get);
+
+/**
+ * scsi_device_put  -  release a reference to a scsi_device
+ * @sdev:	device to release a reference on.
+ *
+ * Release a reference to the scsi_device and decrements the use count
+ * of the underlying LLDD module.  The device is freed once the last
+ * user vanishes.
+ */
+void scsi_device_put(struct scsi_device *sdev)
+{
+	module_put(sdev->host->hostt->module);
+	put_device(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL(scsi_device_put);
+
+/* helper for shost_for_each_device, thus not documented */
+struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *shost,
+					   struct scsi_device *prev)
+{
+	struct list_head *list = (prev ? &prev->siblings : &shost->__devices);
+	struct scsi_device *next = NULL;
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	while (list->next != &shost->__devices) {
+		next = list_entry(list->next, struct scsi_device, siblings);
+		/* skip devices that we can't get a reference to */
+		if (!scsi_device_get(next))
+			break;
+		next = NULL;
+		list = list->next;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	if (prev)
+		scsi_device_put(prev);
+	return next;
+}
+EXPORT_SYMBOL(__scsi_iterate_devices);
+
+/**
+ * starget_for_each_device  -  helper to walk all devices of a target
+ * @starget:	target whose devices we want to iterate over.
+ *
+ * This traverses over each devices of @shost.  The devices have
+ * a reference that must be released by scsi_host_put when breaking
+ * out of the loop.
+ */
+void starget_for_each_device(struct scsi_target *starget, void * data,
+		     void (*fn)(struct scsi_device *, void *))
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct scsi_device *sdev;
+
+	shost_for_each_device(sdev, shost) {
+		if ((sdev->channel == starget->channel) &&
+		    (sdev->id == starget->id))
+			fn(sdev, data);
+	}
+}
+EXPORT_SYMBOL(starget_for_each_device);
+
+/**
+ * __scsi_device_lookup_by_target - find a device given the target (UNLOCKED)
+ * @starget:	SCSI target pointer
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @lun for a give
+ * @starget. The returned scsi_device does not have an additional
+ * reference.  You must hold the host's host_lock over this call and
+ * any access to the returned scsi_device.
+ *
+ * Note:  The only reason why drivers would want to use this is because
+ * they're need to access the device list in irq context.  Otherwise you
+ * really want to use scsi_device_lookup_by_target instead.
+ **/
+struct scsi_device *__scsi_device_lookup_by_target(struct scsi_target *starget,
+						   uint lun)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &starget->devices, same_target_siblings) {
+		if (sdev->lun ==lun)
+			return sdev;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(__scsi_device_lookup_by_target);
+
+/**
+ * scsi_device_lookup_by_target - find a device given the target
+ * @starget:	SCSI target pointer
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @channel, @id, @lun for a
+ * give host.  The returned scsi_device has an additional reference that
+ * needs to be release with scsi_host_put once you're done with it.
+ **/
+struct scsi_device *scsi_device_lookup_by_target(struct scsi_target *starget,
+						 uint lun)
+{
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	sdev = __scsi_device_lookup_by_target(starget, lun);
+	if (sdev && scsi_device_get(sdev))
+		sdev = NULL;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	return sdev;
+}
+EXPORT_SYMBOL(scsi_device_lookup_by_target);
+
+/**
+ * scsi_device_lookup - find a device given the host (UNLOCKED)
+ * @shost:	SCSI host pointer
+ * @channel:	SCSI channel (zero if only one channel)
+ * @pun:	SCSI target number (physical unit number)
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @channel, @id, @lun for a
+ * give host. The returned scsi_device does not have an additional reference.
+ * You must hold the host's host_lock over this call and any access to the
+ * returned scsi_device.
+ *
+ * Note:  The only reason why drivers would want to use this is because
+ * they're need to access the device list in irq context.  Otherwise you
+ * really want to use scsi_device_lookup instead.
+ **/
+struct scsi_device *__scsi_device_lookup(struct Scsi_Host *shost,
+		uint channel, uint id, uint lun)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &shost->__devices, siblings) {
+		if (sdev->channel == channel && sdev->id == id &&
+				sdev->lun ==lun)
+			return sdev;
+	}
+
+	return NULL;
+}
+EXPORT_SYMBOL(__scsi_device_lookup);
+
+/**
+ * scsi_device_lookup - find a device given the host
+ * @shost:	SCSI host pointer
+ * @channel:	SCSI channel (zero if only one channel)
+ * @id:		SCSI target number (physical unit number)
+ * @lun:	SCSI Logical Unit Number
+ *
+ * Looks up the scsi_device with the specified @channel, @id, @lun for a
+ * give host.  The returned scsi_device has an additional reference that
+ * needs to be release with scsi_host_put once you're done with it.
+ **/
+struct scsi_device *scsi_device_lookup(struct Scsi_Host *shost,
+		uint channel, uint id, uint lun)
+{
+	struct scsi_device *sdev;
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	sdev = __scsi_device_lookup(shost, channel, id, lun);
+	if (sdev && scsi_device_get(sdev))
+		sdev = NULL;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	return sdev;
+}
+EXPORT_SYMBOL(scsi_device_lookup);
+
+/**
+ * scsi_device_cancel - cancel outstanding IO to this device
+ * @sdev:	Pointer to struct scsi_device
+ * @recovery:	Boolean instructing function to recover device or not.
+ *
+ **/
+int scsi_device_cancel(struct scsi_device *sdev, int recovery)
+{
+	struct scsi_cmnd *scmd;
+	LIST_HEAD(active_list);
+	struct list_head *lh, *lh_sf;
+	unsigned long flags;
+
+	scsi_device_set_state(sdev, SDEV_CANCEL);
+
+	spin_lock_irqsave(&sdev->list_lock, flags);
+	list_for_each_entry(scmd, &sdev->cmd_list, list) {
+		if (scmd->request && scmd->request->rq_status != RQ_INACTIVE) {
+			/*
+			 * If we are unable to remove the timer, it means
+			 * that the command has already timed out or
+			 * finished.
+			 */
+			if (!scsi_delete_timer(scmd))
+				continue;
+			list_add_tail(&scmd->eh_entry, &active_list);
+		}
+	}
+	spin_unlock_irqrestore(&sdev->list_lock, flags);
+
+	if (!list_empty(&active_list)) {
+		list_for_each_safe(lh, lh_sf, &active_list) {
+			scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+			list_del_init(lh);
+			if (recovery) {
+				scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD);
+			} else {
+				scmd->result = (DID_ABORT << 16);
+				scsi_finish_command(scmd);
+			}
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(scsi_device_cancel);
+
+#ifdef CONFIG_HOTPLUG_CPU
+static int scsi_cpu_notify(struct notifier_block *self,
+			   unsigned long action, void *hcpu)
+{
+	int cpu = (unsigned long)hcpu;
+
+	switch(action) {
+	case CPU_DEAD:
+		/* Drain scsi_done_q. */
+		local_irq_disable();
+		list_splice_init(&per_cpu(scsi_done_q, cpu),
+				 &__get_cpu_var(scsi_done_q));
+		raise_softirq_irqoff(SCSI_SOFTIRQ);
+		local_irq_enable();
+		break;
+	default:
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block __devinitdata scsi_cpu_nb = {
+	.notifier_call	= scsi_cpu_notify,
+};
+
+#define register_scsi_cpu() register_cpu_notifier(&scsi_cpu_nb)
+#define unregister_scsi_cpu() unregister_cpu_notifier(&scsi_cpu_nb)
+#else
+#define register_scsi_cpu()
+#define unregister_scsi_cpu()
+#endif /* CONFIG_HOTPLUG_CPU */
+
+MODULE_DESCRIPTION("SCSI core");
+MODULE_LICENSE("GPL");
+
+module_param(scsi_logging_level, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(scsi_logging_level, "a bit mask of logging levels");
+
+static int __init init_scsi(void)
+{
+	int error, i;
+
+	error = scsi_init_queue();
+	if (error)
+		return error;
+	error = scsi_init_procfs();
+	if (error)
+		goto cleanup_queue;
+	error = scsi_init_devinfo();
+	if (error)
+		goto cleanup_procfs;
+	error = scsi_init_hosts();
+	if (error)
+		goto cleanup_devlist;
+	error = scsi_init_sysctl();
+	if (error)
+		goto cleanup_hosts;
+	error = scsi_sysfs_register();
+	if (error)
+		goto cleanup_sysctl;
+
+	for (i = 0; i < NR_CPUS; i++)
+		INIT_LIST_HEAD(&per_cpu(scsi_done_q, i));
+
+	devfs_mk_dir("scsi");
+	open_softirq(SCSI_SOFTIRQ, scsi_softirq, NULL);
+	register_scsi_cpu();
+	printk(KERN_NOTICE "SCSI subsystem initialized\n");
+	return 0;
+
+cleanup_sysctl:
+	scsi_exit_sysctl();
+cleanup_hosts:
+	scsi_exit_hosts();
+cleanup_devlist:
+	scsi_exit_devinfo();
+cleanup_procfs:
+	scsi_exit_procfs();
+cleanup_queue:
+	scsi_exit_queue();
+	printk(KERN_ERR "SCSI subsystem failed to initialize, error = %d\n",
+	       -error);
+	return error;
+}
+
+static void __exit exit_scsi(void)
+{
+	scsi_sysfs_unregister();
+	scsi_exit_sysctl();
+	scsi_exit_hosts();
+	scsi_exit_devinfo();
+	devfs_remove("scsi");
+	scsi_exit_procfs();
+	scsi_exit_queue();
+	unregister_scsi_cpu();
+}
+
+subsys_initcall(init_scsi);
+module_exit(exit_scsi);
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
new file mode 100644
index 0000000..cb6b5fb
--- /dev/null
+++ b/drivers/scsi/scsi.h
@@ -0,0 +1,109 @@
+/*
+ *  scsi.h Copyright (C) 1992 Drew Eckhardt 
+ *         Copyright (C) 1993, 1994, 1995, 1998, 1999 Eric Youngdale
+ *  generic SCSI package header file by
+ *      Initial versions: Drew Eckhardt
+ *      Subsequent revisions: Eric Youngdale
+ *
+ *  <drew@colorado.edu>
+ *
+ *       Modified by Eric Youngdale eric@andante.org to
+ *       add scatter-gather, multiple outstanding request, and other
+ *       enhancements.
+ */
+/*
+ * NOTE:  this file only contains compatibility glue for old drivers.  All
+ * these wrappers will be removed sooner or later.  For new code please use
+ * the interfaces declared in the headers in include/scsi/
+ */
+
+#ifndef _SCSI_H
+#define _SCSI_H
+
+#include <linux/config.h>	    /* for CONFIG_SCSI_LOGGING */
+
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi.h>
+
+/*
+ * Some defs, in case these are not defined elsewhere.
+ */
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+struct Scsi_Host;
+struct scsi_cmnd;
+struct scsi_device;
+struct scsi_target;
+struct scatterlist;
+
+/*
+ * Legacy dma direction interfaces.
+ *
+ * This assumes the pci/sbus dma mapping flags have the same numercial
+ * values as the generic dma-mapping ones.  Currently they have but there's
+ * no way to check.  Better don't use these interfaces!
+ */
+#define SCSI_DATA_UNKNOWN	(DMA_BIDIRECTIONAL)
+#define SCSI_DATA_WRITE		(DMA_TO_DEVICE)
+#define SCSI_DATA_READ		(DMA_FROM_DEVICE)
+#define SCSI_DATA_NONE		(DMA_NONE)
+
+#define scsi_to_pci_dma_dir(scsi_dir)	((int)(scsi_dir))
+#define scsi_to_sbus_dma_dir(scsi_dir)	((int)(scsi_dir))
+
+/*
+ * Old names for debug prettyprinting functions.
+ */
+static inline void print_Scsi_Cmnd(struct scsi_cmnd *cmd)
+{
+	return scsi_print_command(cmd);
+}
+static inline void print_command(unsigned char *cdb)
+{
+	return __scsi_print_command(cdb);
+}
+static inline void print_sense(const char *devclass, struct scsi_cmnd *cmd)
+{
+	return scsi_print_sense(devclass, cmd);
+}
+static inline void print_req_sense(const char *devclass, struct scsi_request *req)
+{
+	return scsi_print_req_sense(devclass, req);
+}
+static inline void print_driverbyte(int scsiresult)
+{
+	return scsi_print_driverbyte(scsiresult);
+}
+static inline void print_hostbyte(int scsiresult)
+{
+	return scsi_print_hostbyte(scsiresult);
+}
+static inline void print_status(unsigned char status)
+{
+	return scsi_print_status(status);
+}
+static inline int print_msg(const unsigned char *msg)
+{
+	return scsi_print_msg(msg);
+}
+
+/*
+ * This is the crap from the old error handling code.  We have it in a special
+ * place so that we can more easily delete it later on.
+ */
+#include "scsi_obsolete.h"
+
+/* obsolete typedef junk. */
+#include "scsi_typedefs.h"
+
+#endif /* _SCSI_H */
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
new file mode 100644
index 0000000..e020888
--- /dev/null
+++ b/drivers/scsi/scsi_debug.c
@@ -0,0 +1,1976 @@
+/*
+ *  linux/kernel/scsi_debug.c
+ * vvvvvvvvvvvvvvvvvvvvvvv Original vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+ *  Copyright (C) 1992  Eric Youngdale
+ *  Simulate a host adapter with 2 disks attached.  Do a lot of checking
+ *  to make sure that we are not getting blocks mixed up, and PANIC if
+ *  anything out of the ordinary is seen.
+ * ^^^^^^^^^^^^^^^^^^^^^^^ Original ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ *
+ *  This version is more generic, simulating a variable number of disk
+ *  (or disk like devices) sharing a common amount of RAM
+ *
+ *
+ *  For documentation see http://www.torque.net/sg/sdebug26.html
+ *
+ *   D. Gilbert (dpg) work for Magneto-Optical device test [20010421]
+ *   dpg: work for devfs large number of disks [20010809]
+ *        forked for lk 2.5 series [20011216, 20020101]
+ *        use vmalloc() more inquiry+mode_sense [20020302]
+ *        add timers for delayed responses [20020721]
+ *   Patrick Mansfield <patmans@us.ibm.com> max_luns+scsi_level [20021031]
+ *   Mike Anderson <andmike@us.ibm.com> sysfs work [20021118]
+ *   dpg: change style of boot options to "scsi_debug.num_tgts=2" and
+ *        module options to "modprobe scsi_debug num_tgts=2" [20021221]
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/genhd.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/vmalloc.h>
+#include <linux/moduleparam.h>
+
+#include <linux/blkdev.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsicam.h>
+
+#include <linux/stat.h>
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif
+
+#include "scsi_logging.h"
+#include "scsi_debug.h"
+
+#define SCSI_DEBUG_VERSION "1.75"
+static const char * scsi_debug_version_date = "20050113";
+
+/* Additional Sense Code (ASC) used */
+#define NO_ADDED_SENSE 0x0
+#define UNRECOVERED_READ_ERR 0x11
+#define INVALID_OPCODE 0x20
+#define ADDR_OUT_OF_RANGE 0x21
+#define INVALID_FIELD_IN_CDB 0x24
+#define POWERON_RESET 0x29
+#define SAVING_PARAMS_UNSUP 0x39
+#define THRESHHOLD_EXCEEDED 0x5d
+
+#define SDEBUG_TAGGED_QUEUING 0 /* 0 | MSG_SIMPLE_TAG | MSG_ORDERED_TAG */
+
+/* Default values for driver parameters */
+#define DEF_NUM_HOST   1
+#define DEF_NUM_TGTS   1
+#define DEF_MAX_LUNS   1
+/* With these defaults, this driver will make 1 host with 1 target
+ * (id 0) containing 1 logical unit (lun 0). That is 1 device.
+ */
+#define DEF_DELAY   1
+#define DEF_DEV_SIZE_MB   8
+#define DEF_EVERY_NTH   0
+#define DEF_NUM_PARTS   0
+#define DEF_OPTS   0
+#define DEF_SCSI_LEVEL   5    /* INQUIRY, byte2 [5->SPC-3] */
+#define DEF_PTYPE   0
+#define DEF_D_SENSE   0
+
+/* bit mask values for scsi_debug_opts */
+#define SCSI_DEBUG_OPT_NOISE   1
+#define SCSI_DEBUG_OPT_MEDIUM_ERR   2
+#define SCSI_DEBUG_OPT_TIMEOUT   4
+#define SCSI_DEBUG_OPT_RECOVERED_ERR   8
+/* When "every_nth" > 0 then modulo "every_nth" commands:
+ *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
+ *   - a RECOVERED_ERROR is simulated on successful read and write
+ *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ *
+ * When "every_nth" < 0 then after "- every_nth" commands:
+ *   - a no response is simulated if SCSI_DEBUG_OPT_TIMEOUT is set
+ *   - a RECOVERED_ERROR is simulated on successful read and write
+ *     commands if SCSI_DEBUG_OPT_RECOVERED_ERR is set.
+ * This will continue until some other action occurs (e.g. the user
+ * writing a new value (other than -1 or 1) to every_nth via sysfs).
+ */
+
+/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
+ * sector on read commands: */
+#define OPT_MEDIUM_ERR_ADDR   0x1234 /* that's sector 4660 in decimal */
+
+/* If REPORT LUNS has luns >= 256 it can choose "flat space" (value 1)
+ * or "peripheral device" addressing (value 0) */
+#define SAM2_LUN_ADDRESS_METHOD 0
+
+static int scsi_debug_add_host = DEF_NUM_HOST;
+static int scsi_debug_delay = DEF_DELAY;
+static int scsi_debug_dev_size_mb = DEF_DEV_SIZE_MB;
+static int scsi_debug_every_nth = DEF_EVERY_NTH;
+static int scsi_debug_max_luns = DEF_MAX_LUNS;
+static int scsi_debug_num_parts = DEF_NUM_PARTS;
+static int scsi_debug_num_tgts = DEF_NUM_TGTS; /* targets per host */
+static int scsi_debug_opts = DEF_OPTS;
+static int scsi_debug_scsi_level = DEF_SCSI_LEVEL;
+static int scsi_debug_ptype = DEF_PTYPE; /* SCSI peripheral type (0==disk) */
+static int scsi_debug_dsense = DEF_D_SENSE;
+
+static int scsi_debug_cmnd_count = 0;
+
+#define DEV_READONLY(TGT)      (0)
+#define DEV_REMOVEABLE(TGT)    (0)
+
+static unsigned long sdebug_store_size;	/* in bytes */
+static sector_t sdebug_capacity;	/* in sectors */
+
+/* old BIOS stuff, kernel may get rid of them but some mode sense pages
+   may still need them */
+static int sdebug_heads;		/* heads per disk */
+static int sdebug_cylinders_per;	/* cylinders per surface */
+static int sdebug_sectors_per;		/* sectors per cylinder */
+
+/* default sector size is 512 bytes, 2**9 bytes */
+#define POW2_SECT_SIZE 9
+#define SECT_SIZE (1 << POW2_SECT_SIZE)
+#define SECT_SIZE_PER(TGT) SECT_SIZE
+
+#define SDEBUG_MAX_PARTS 4
+
+#define SDEBUG_SENSE_LEN 32
+
+struct sdebug_dev_info {
+	struct list_head dev_list;
+	unsigned char sense_buff[SDEBUG_SENSE_LEN];	/* weak nexus */
+	unsigned int channel;
+	unsigned int target;
+	unsigned int lun;
+	struct sdebug_host_info *sdbg_host;
+	char reset;
+	char used;
+};
+
+struct sdebug_host_info {
+	struct list_head host_list;
+	struct Scsi_Host *shost;
+	struct device dev;
+	struct list_head dev_info_list;
+};
+
+#define to_sdebug_host(d)	\
+	container_of(d, struct sdebug_host_info, dev)
+
+static LIST_HEAD(sdebug_host_list);
+static DEFINE_SPINLOCK(sdebug_host_list_lock);
+
+typedef void (* done_funct_t) (struct scsi_cmnd *);
+
+struct sdebug_queued_cmd {
+	int in_use;
+	struct timer_list cmnd_timer;
+	done_funct_t done_funct;
+	struct scsi_cmnd * a_cmnd;
+	int scsi_result;
+};
+static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
+
+static Scsi_Host_Template sdebug_driver_template = {
+	.proc_info =		scsi_debug_proc_info,
+	.name =			"SCSI DEBUG",
+	.info =			scsi_debug_info,
+	.slave_alloc =		scsi_debug_slave_alloc,
+	.slave_configure =	scsi_debug_slave_configure,
+	.slave_destroy =	scsi_debug_slave_destroy,
+	.ioctl =		scsi_debug_ioctl,
+	.queuecommand =		scsi_debug_queuecommand,
+	.eh_abort_handler =	scsi_debug_abort,
+	.eh_bus_reset_handler = scsi_debug_bus_reset,
+	.eh_device_reset_handler = scsi_debug_device_reset,
+	.eh_host_reset_handler = scsi_debug_host_reset,
+	.bios_param =		scsi_debug_biosparam,
+	.can_queue =		SCSI_DEBUG_CANQUEUE,
+	.this_id =		7,
+	.sg_tablesize =		64,
+	.cmd_per_lun =		3,
+	.max_sectors =		4096,
+	.unchecked_isa_dma = 	0,
+	.use_clustering = 	DISABLE_CLUSTERING,
+	.module =		THIS_MODULE,
+};
+
+static unsigned char * fake_storep;	/* ramdisk storage */
+
+static int num_aborts = 0;
+static int num_dev_resets = 0;
+static int num_bus_resets = 0;
+static int num_host_resets = 0;
+
+static DEFINE_SPINLOCK(queued_arr_lock);
+static DEFINE_RWLOCK(atomic_rw);
+
+static char sdebug_proc_name[] = "scsi_debug";
+
+static int sdebug_driver_probe(struct device *);
+static int sdebug_driver_remove(struct device *);
+static struct bus_type pseudo_lld_bus;
+
+static struct device_driver sdebug_driverfs_driver = {
+	.name 		= sdebug_proc_name,
+	.bus		= &pseudo_lld_bus,
+	.probe          = sdebug_driver_probe,
+	.remove         = sdebug_driver_remove,
+};
+
+static const int check_condition_result =
+		(DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION;
+
+/* function declarations */
+static int resp_inquiry(struct scsi_cmnd * SCpnt, int target,
+			struct sdebug_dev_info * devip);
+static int resp_requests(struct scsi_cmnd * SCpnt,
+			 struct sdebug_dev_info * devip);
+static int resp_readcap(struct scsi_cmnd * SCpnt,
+			struct sdebug_dev_info * devip);
+static int resp_mode_sense(struct scsi_cmnd * SCpnt, int target,
+			   struct sdebug_dev_info * devip);
+static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		     int num, struct sdebug_dev_info * devip);
+static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		      int num, struct sdebug_dev_info * devip);
+static int resp_report_luns(struct scsi_cmnd * SCpnt,
+			    struct sdebug_dev_info * devip);
+static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+                                int arr_len);
+static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+                               int max_arr_len);
+static void timer_intr_handler(unsigned long);
+static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev);
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
+			    int asc, int asq);
+static int check_reset(struct scsi_cmnd * SCpnt,
+		       struct sdebug_dev_info * devip);
+static int schedule_resp(struct scsi_cmnd * cmnd,
+			 struct sdebug_dev_info * devip,
+			 done_funct_t done, int scsi_result, int delta_jiff);
+static void __init sdebug_build_parts(unsigned char * ramp);
+static void __init init_all_queued(void);
+static void stop_all_queued(void);
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd);
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
+                           const char * dev_id_str, int dev_id_str_len);
+static void do_create_driverfs_files(void);
+static void do_remove_driverfs_files(void);
+
+static int sdebug_add_adapter(void);
+static void sdebug_remove_adapter(void);
+static void sdebug_max_tgts_luns(void);
+
+static struct device pseudo_primary;
+static struct bus_type pseudo_lld_bus;
+
+
+static
+int scsi_debug_queuecommand(struct scsi_cmnd * SCpnt, done_funct_t done)
+{
+	unsigned char *cmd = (unsigned char *) SCpnt->cmnd;
+	int block, upper_blk, num, k;
+	int errsts = 0;
+	int target = SCpnt->device->id;
+	struct sdebug_dev_info * devip = NULL;
+	int inj_recovered = 0;
+
+	if (done == NULL)
+		return 0;	/* assume mid level reprocessing command */
+
+	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmd) {
+		printk(KERN_INFO "scsi_debug: cmd ");
+		for (k = 0, num = SCpnt->cmd_len; k < num; ++k)
+			printk("%02x ", (int)cmd[k]);
+		printk("\n");
+	}
+        if(target == sdebug_driver_template.this_id) {
+		printk(KERN_INFO "scsi_debug: initiator's id used as "
+		       "target!\n");
+		return schedule_resp(SCpnt, NULL, done,
+				     DID_NO_CONNECT << 16, 0);
+        }
+
+	if (SCpnt->device->lun >= scsi_debug_max_luns)
+		return schedule_resp(SCpnt, NULL, done,
+				     DID_NO_CONNECT << 16, 0);
+	devip = devInfoReg(SCpnt->device);
+	if (NULL == devip)
+		return schedule_resp(SCpnt, NULL, done,
+				     DID_NO_CONNECT << 16, 0);
+
+        if ((scsi_debug_every_nth != 0) &&
+            (++scsi_debug_cmnd_count >= abs(scsi_debug_every_nth))) {
+                scsi_debug_cmnd_count = 0;
+		if (scsi_debug_every_nth < -1)
+			scsi_debug_every_nth = -1;
+		if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
+			return 0; /* ignore command causing timeout */
+		else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
+			inj_recovered = 1; /* to reads and writes below */
+        }
+
+	switch (*cmd) {
+	case INQUIRY:     /* mandatory, ignore unit attention */
+		errsts = resp_inquiry(SCpnt, target, devip);
+		break;
+	case REQUEST_SENSE:	/* mandatory, ignore unit attention */
+		errsts = resp_requests(SCpnt, devip);
+		break;
+	case REZERO_UNIT:	/* actually this is REWIND for SSC */
+	case START_STOP:
+		errsts = check_reset(SCpnt, devip);
+		break;
+	case ALLOW_MEDIUM_REMOVAL:
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: Medium removal %s\n",
+			        cmd[4] ? "inhibited" : "enabled");
+		break;
+	case SEND_DIAGNOSTIC:     /* mandatory */
+		errsts = check_reset(SCpnt, devip);
+		break;
+	case TEST_UNIT_READY:     /* mandatory */
+		errsts = check_reset(SCpnt, devip);
+		break;
+        case RESERVE:
+		errsts = check_reset(SCpnt, devip);
+                break;
+        case RESERVE_10:
+		errsts = check_reset(SCpnt, devip);
+                break;
+        case RELEASE:
+		errsts = check_reset(SCpnt, devip);
+                break;
+        case RELEASE_10:
+		errsts = check_reset(SCpnt, devip);
+                break;
+	case READ_CAPACITY:
+		errsts = resp_readcap(SCpnt, devip);
+		break;
+	case READ_16:
+	case READ_12:
+	case READ_10:
+	case READ_6:
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		upper_blk = 0;
+		if ((*cmd) == READ_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) +
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) +
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) +
+				(cmd[11] << 16) + (cmd[10] << 24);
+		} else if ((*cmd) == READ_12) {
+			block = cmd[5] + (cmd[4] << 8) +
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) +
+				(cmd[7] << 16) + (cmd[6] << 24);
+		} else if ((*cmd) == READ_10) {
+			block = cmd[5] + (cmd[4] << 8) +
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		} else {
+			block = cmd[3] + (cmd[2] << 8) +
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		errsts = resp_read(SCpnt, upper_blk, block, num, devip);
+		if (inj_recovered && (0 == errsts)) {
+			mk_sense_buffer(devip, RECOVERED_ERROR,
+					THRESHHOLD_EXCEEDED, 0);
+			errsts = check_condition_result;
+		}
+		break;
+	case REPORT_LUNS:	/* mandatory, ignore unit attention */
+		errsts = resp_report_luns(SCpnt, devip);
+		break;
+	case VERIFY:		/* 10 byte SBC-2 command */
+		errsts = check_reset(SCpnt, devip);
+		break;
+	case WRITE_16:
+	case WRITE_12:
+	case WRITE_10:
+	case WRITE_6:
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;
+		upper_blk = 0;
+		if ((*cmd) == WRITE_16) {
+			upper_blk = cmd[5] + (cmd[4] << 8) +
+				    (cmd[3] << 16) + (cmd[2] << 24);
+			block = cmd[9] + (cmd[8] << 8) +
+				(cmd[7] << 16) + (cmd[6] << 24);
+			num = cmd[13] + (cmd[12] << 8) +
+				(cmd[11] << 16) + (cmd[10] << 24);
+		} else if ((*cmd) == WRITE_12) {
+			block = cmd[5] + (cmd[4] << 8) +
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[9] + (cmd[8] << 8) +
+				(cmd[7] << 16) + (cmd[6] << 24);
+		} else if ((*cmd) == WRITE_10) {
+			block = cmd[5] + (cmd[4] << 8) +
+				(cmd[3] << 16) + (cmd[2] << 24);
+			num = cmd[8] + (cmd[7] << 8);
+		} else {
+			block = cmd[3] + (cmd[2] << 8) +
+				((cmd[1] & 0x1f) << 16);
+			num = cmd[4];
+		}
+		errsts = resp_write(SCpnt, upper_blk, block, num, devip);
+		if (inj_recovered && (0 == errsts)) {
+			mk_sense_buffer(devip, RECOVERED_ERROR,
+					THRESHHOLD_EXCEEDED, 0);
+			errsts = check_condition_result;
+		}
+		break;
+	case MODE_SENSE:
+	case MODE_SENSE_10:
+		errsts = resp_mode_sense(SCpnt, target, devip);
+		break;
+	case SYNCHRONIZE_CACHE:
+		errsts = check_reset(SCpnt, devip);
+		break;
+	default:
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: Opcode: 0x%x not "
+			       "supported\n", *cmd);
+		if ((errsts = check_reset(SCpnt, devip)))
+			break;	/* Unit attention takes precedence */
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
+		errsts = check_condition_result;
+		break;
+	}
+	return schedule_resp(SCpnt, devip, done, errsts, scsi_debug_delay);
+}
+
+static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
+{
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug: ioctl: cmd=0x%x\n", cmd);
+	}
+	return -EINVAL;
+	/* return -ENOTTY; // correct return but upsets fdisk */
+}
+
+static int check_reset(struct scsi_cmnd * SCpnt, struct sdebug_dev_info * devip)
+{
+	if (devip->reset) {
+		if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+			printk(KERN_INFO "scsi_debug: Reporting Unit "
+			       "attention: power on reset\n");
+		devip->reset = 0;
+		mk_sense_buffer(devip, UNIT_ATTENTION, POWERON_RESET, 0);
+		return check_condition_result;
+	}
+	return 0;
+}
+
+/* Returns 0 if ok else (DID_ERROR << 16). Sets scp->resid . */
+static int fill_from_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+				int arr_len)
+{
+	int k, req_len, act_len, len, active;
+	void * kaddr;
+	void * kaddr_off;
+	struct scatterlist * sgpnt;
+
+	if (0 == scp->request_bufflen)
+		return 0;
+	if (NULL == scp->request_buffer)
+		return (DID_ERROR << 16);
+	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+	      (scp->sc_data_direction == DMA_FROM_DEVICE)))
+		return (DID_ERROR << 16);
+	if (0 == scp->use_sg) {
+		req_len = scp->request_bufflen;
+		act_len = (req_len < arr_len) ? req_len : arr_len;
+		memcpy(scp->request_buffer, arr, act_len);
+		scp->resid = req_len - act_len;
+		return 0;
+	}
+	sgpnt = (struct scatterlist *)scp->request_buffer;
+	active = 1;
+	for (k = 0, req_len = 0, act_len = 0; k < scp->use_sg; ++k, ++sgpnt) {
+		if (active) {
+			kaddr = (unsigned char *)
+				kmap_atomic(sgpnt->page, KM_USER0);
+			if (NULL == kaddr)
+				return (DID_ERROR << 16);
+			kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+			len = sgpnt->length;
+			if ((req_len + len) > arr_len) {
+				active = 0;
+				len = arr_len - req_len;
+			}
+			memcpy(kaddr_off, arr + req_len, len);
+			kunmap_atomic(kaddr, KM_USER0);
+			act_len += len;
+		}
+		req_len += sgpnt->length;
+	}
+	scp->resid = req_len - act_len;
+	return 0;
+}
+
+/* Returns number of bytes fetched into 'arr' or -1 if error. */
+static int fetch_to_dev_buffer(struct scsi_cmnd * scp, unsigned char * arr,
+			       int max_arr_len)
+{
+	int k, req_len, len, fin;
+	void * kaddr;
+	void * kaddr_off;
+	struct scatterlist * sgpnt;
+
+	if (0 == scp->request_bufflen)
+		return 0;
+	if (NULL == scp->request_buffer)
+		return -1;
+	if (! ((scp->sc_data_direction == DMA_BIDIRECTIONAL) ||
+	      (scp->sc_data_direction == DMA_TO_DEVICE)))
+		return -1;
+	if (0 == scp->use_sg) {
+		req_len = scp->request_bufflen;
+		len = (req_len < max_arr_len) ? req_len : max_arr_len;
+		memcpy(arr, scp->request_buffer, len);
+		return len;
+	}
+	sgpnt = (struct scatterlist *)scp->request_buffer;
+	for (k = 0, req_len = 0, fin = 0; k < scp->use_sg; ++k, ++sgpnt) {
+		kaddr = (unsigned char *)kmap_atomic(sgpnt->page, KM_USER0);
+		if (NULL == kaddr)
+			return -1;
+		kaddr_off = (unsigned char *)kaddr + sgpnt->offset;
+		len = sgpnt->length;
+		if ((req_len + len) > max_arr_len) {
+			len = max_arr_len - req_len;
+			fin = 1;
+		}
+		memcpy(arr + req_len, kaddr_off, len);
+		kunmap_atomic(kaddr, KM_USER0);
+		if (fin)
+			return req_len + len;
+		req_len += sgpnt->length;
+	}
+	return req_len;
+}
+
+
+static const char * inq_vendor_id = "Linux   ";
+static const char * inq_product_id = "scsi_debug      ";
+static const char * inq_product_rev = "0004";
+
+static int inquiry_evpd_83(unsigned char * arr, int dev_id_num,
+			   const char * dev_id_str, int dev_id_str_len)
+{
+	int num;
+
+	/* Two identification descriptors: */
+	/* T10 vendor identifier field format (faked) */
+	arr[0] = 0x2;	/* ASCII */
+	arr[1] = 0x1;
+	arr[2] = 0x0;
+	memcpy(&arr[4], inq_vendor_id, 8);
+	memcpy(&arr[12], inq_product_id, 16);
+	memcpy(&arr[28], dev_id_str, dev_id_str_len);
+	num = 8 + 16 + dev_id_str_len;
+	arr[3] = num;
+	num += 4;
+	/* NAA IEEE registered identifier (faked) */
+	arr[num] = 0x1;	/* binary */
+	arr[num + 1] = 0x3;
+	arr[num + 2] = 0x0;
+	arr[num + 3] = 0x8;
+	arr[num + 4] = 0x51;	/* ieee company id=0x123456 (faked) */
+	arr[num + 5] = 0x23;
+	arr[num + 6] = 0x45;
+	arr[num + 7] = 0x60;
+	arr[num + 8] = (dev_id_num >> 24);
+	arr[num + 9] = (dev_id_num >> 16) & 0xff;
+	arr[num + 10] = (dev_id_num >> 8) & 0xff;
+	arr[num + 11] = dev_id_num & 0xff;
+	return num + 12;
+}
+
+
+#define SDEBUG_LONG_INQ_SZ 96
+#define SDEBUG_MAX_INQ_ARR_SZ 128
+
+static int resp_inquiry(struct scsi_cmnd * scp, int target,
+			struct sdebug_dev_info * devip)
+{
+	unsigned char pq_pdt;
+	unsigned char arr[SDEBUG_MAX_INQ_ARR_SZ];
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+	int alloc_len;
+
+	alloc_len = (cmd[3] << 8) + cmd[4];
+	memset(arr, 0, SDEBUG_MAX_INQ_ARR_SZ);
+	pq_pdt = (scsi_debug_ptype & 0x1f);
+	arr[0] = pq_pdt;
+	if (0x2 & cmd[1]) {  /* CMDDT bit set */
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+			       	0);
+		return check_condition_result;
+	} else if (0x1 & cmd[1]) {  /* EVPD bit set */
+		int dev_id_num, len;
+		char dev_id_str[6];
+		
+		dev_id_num = ((devip->sdbg_host->shost->host_no + 1) * 2000) +
+			     (devip->target * 1000) + devip->lun;
+		len = scnprintf(dev_id_str, 6, "%d", dev_id_num);
+		if (0 == cmd[2]) { /* supported vital product data pages */
+			arr[3] = 3;
+			arr[4] = 0x0; /* this page */
+			arr[5] = 0x80; /* unit serial number */
+			arr[6] = 0x83; /* device identification */
+		} else if (0x80 == cmd[2]) { /* unit serial number */
+			arr[1] = 0x80;
+			arr[3] = len;
+			memcpy(&arr[4], dev_id_str, len);
+		} else if (0x83 == cmd[2]) { /* device identification */
+			arr[1] = 0x83;
+			arr[3] = inquiry_evpd_83(&arr[4], dev_id_num,
+						 dev_id_str, len);
+		} else {
+			/* Illegal request, invalid field in cdb */
+			mk_sense_buffer(devip, ILLEGAL_REQUEST,
+					INVALID_FIELD_IN_CDB, 0);
+			return check_condition_result;
+		}
+		return fill_from_dev_buffer(scp, arr,
+			    min(alloc_len, SDEBUG_MAX_INQ_ARR_SZ));
+	}
+	/* drops through here for a standard inquiry */
+	arr[1] = DEV_REMOVEABLE(target) ? 0x80 : 0;	/* Removable disk */
+	arr[2] = scsi_debug_scsi_level;
+	arr[3] = 2;    /* response_data_format==2 */
+	arr[4] = SDEBUG_LONG_INQ_SZ - 5;
+	arr[6] = 0x1; /* claim: ADDR16 */
+	/* arr[6] |= 0x40; ... claim: EncServ (enclosure services) */
+	arr[7] = 0x3a; /* claim: WBUS16, SYNC, LINKED + CMDQUE */
+	memcpy(&arr[8], inq_vendor_id, 8);
+	memcpy(&arr[16], inq_product_id, 16);
+	memcpy(&arr[32], inq_product_rev, 4);
+	/* version descriptors (2 bytes each) follow */
+	arr[58] = 0x0; arr[59] = 0x40; /* SAM-2 */
+	arr[60] = 0x3; arr[61] = 0x0;  /* SPC-3 */
+	if (scsi_debug_ptype == 0) {
+		arr[62] = 0x1; arr[63] = 0x80; /* SBC */
+	} else if (scsi_debug_ptype == 1) {
+		arr[62] = 0x2; arr[63] = 0x00; /* SSC */
+	}
+	return fill_from_dev_buffer(scp, arr,
+			    min(alloc_len, SDEBUG_LONG_INQ_SZ));
+}
+
+static int resp_requests(struct scsi_cmnd * scp,
+			 struct sdebug_dev_info * devip)
+{
+	unsigned char * sbuff;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+	unsigned char arr[SDEBUG_SENSE_LEN];
+	int len = 18;
+
+	memset(arr, 0, SDEBUG_SENSE_LEN);
+	if (devip->reset == 1)
+		mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+	sbuff = devip->sense_buff;
+	if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
+		/* DESC bit set and sense_buff in fixed format */
+		arr[0] = 0x72;
+		arr[1] = sbuff[2];     /* sense key */
+		arr[2] = sbuff[12];    /* asc */
+		arr[3] = sbuff[13];    /* ascq */
+		len = 8;
+	} else
+		memcpy(arr, sbuff, SDEBUG_SENSE_LEN);
+	mk_sense_buffer(devip, 0, NO_ADDED_SENSE, 0);
+	return fill_from_dev_buffer(scp, arr, len);
+}
+
+#define SDEBUG_READCAP_ARR_SZ 8
+static int resp_readcap(struct scsi_cmnd * scp,
+			struct sdebug_dev_info * devip)
+{
+	unsigned char arr[SDEBUG_READCAP_ARR_SZ];
+	unsigned long capac;
+	int errsts;
+
+	if ((errsts = check_reset(scp, devip)))
+		return errsts;
+	memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
+	capac = (unsigned long)sdebug_capacity - 1;
+	arr[0] = (capac >> 24);
+	arr[1] = (capac >> 16) & 0xff;
+	arr[2] = (capac >> 8) & 0xff;
+	arr[3] = capac & 0xff;
+	arr[6] = (SECT_SIZE_PER(target) >> 8) & 0xff;
+	arr[7] = SECT_SIZE_PER(target) & 0xff;
+	return fill_from_dev_buffer(scp, arr, SDEBUG_READCAP_ARR_SZ);
+}
+
+/* <<Following mode page info copied from ST318451LW>> */
+
+static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
+{	/* Read-Write Error Recovery page for mode_sense */
+	unsigned char err_recov_pg[] = {0x1, 0xa, 0xc0, 11, 240, 0, 0, 0,
+					5, 0, 0xff, 0xff};
+
+	memcpy(p, err_recov_pg, sizeof(err_recov_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(err_recov_pg) - 2);
+	return sizeof(err_recov_pg);
+}
+
+static int resp_disconnect_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Disconnect-Reconnect page for mode_sense */
+	unsigned char disconnect_pg[] = {0x2, 0xe, 128, 128, 0, 10, 0, 0,
+					 0, 0, 0, 0, 0, 0, 0, 0};
+
+	memcpy(p, disconnect_pg, sizeof(disconnect_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(disconnect_pg) - 2);
+	return sizeof(disconnect_pg);
+}
+
+static int resp_format_pg(unsigned char * p, int pcontrol, int target)
+{       /* Format device page for mode_sense */
+        unsigned char format_pg[] = {0x3, 0x16, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0, 0, 0, 0,
+                                     0, 0, 0, 0, 0x40, 0, 0, 0};
+
+        memcpy(p, format_pg, sizeof(format_pg));
+        p[10] = (sdebug_sectors_per >> 8) & 0xff;
+        p[11] = sdebug_sectors_per & 0xff;
+        p[12] = (SECT_SIZE >> 8) & 0xff;
+        p[13] = SECT_SIZE & 0xff;
+        if (DEV_REMOVEABLE(target))
+                p[20] |= 0x20; /* should agree with INQUIRY */
+        if (1 == pcontrol)
+                memset(p + 2, 0, sizeof(format_pg) - 2);
+        return sizeof(format_pg);
+}
+
+static int resp_caching_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Caching page for mode_sense */
+	unsigned char caching_pg[] = {0x8, 18, 0x14, 0, 0xff, 0xff, 0, 0,
+		0xff, 0xff, 0xff, 0xff, 0x80, 0x14, 0, 0,     0, 0, 0, 0};
+
+	memcpy(p, caching_pg, sizeof(caching_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(caching_pg) - 2);
+	return sizeof(caching_pg);
+}
+
+static int resp_ctrl_m_pg(unsigned char * p, int pcontrol, int target)
+{ 	/* Control mode page for mode_sense */
+	unsigned char ctrl_m_pg[] = {0xa, 10, 2, 0, 0, 0, 0, 0,
+				     0, 0, 0x2, 0x4b};
+
+	if (scsi_debug_dsense)
+		ctrl_m_pg[2] |= 0x4;
+	memcpy(p, ctrl_m_pg, sizeof(ctrl_m_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(ctrl_m_pg) - 2);
+	return sizeof(ctrl_m_pg);
+}
+
+static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
+{	/* Informational Exceptions control mode page for mode_sense */
+	unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+				    0, 0, 0x0, 0x0};
+	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(iec_m_pg) - 2);
+	return sizeof(iec_m_pg);
+}
+
+#define SDEBUG_MAX_MSENSE_SZ 256
+
+static int resp_mode_sense(struct scsi_cmnd * scp, int target,
+			   struct sdebug_dev_info * devip)
+{
+	unsigned char dbd;
+	int pcontrol, pcode, subpcode;
+	unsigned char dev_spec;
+	int alloc_len, msense_6, offset, len, errsts;
+	unsigned char * ap;
+	unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+
+	if ((errsts = check_reset(scp, devip)))
+		return errsts;
+	dbd = cmd[1] & 0x8;
+	pcontrol = (cmd[2] & 0xc0) >> 6;
+	pcode = cmd[2] & 0x3f;
+	subpcode = cmd[3];
+	msense_6 = (MODE_SENSE == cmd[0]);
+	alloc_len = msense_6 ? cmd[4] : ((cmd[7] << 8) | cmd[8]);
+	memset(arr, 0, SDEBUG_MAX_MSENSE_SZ);
+	if (0x3 == pcontrol) {  /* Saving values not supported */
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, SAVING_PARAMS_UNSUP,
+			       	0);
+		return check_condition_result;
+	}
+	dev_spec = DEV_READONLY(target) ? 0x80 : 0x0;
+	if (msense_6) {
+		arr[2] = dev_spec;
+		offset = 4;
+	} else {
+		arr[3] = dev_spec;
+		offset = 8;
+	}
+	ap = arr + offset;
+
+	if (0 != subpcode) { /* TODO: Control Extension page */
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+			       	0);
+		return check_condition_result;
+	}
+	switch (pcode) {
+	case 0x1:	/* Read-Write error recovery page, direct access */
+		len = resp_err_recov_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x2:	/* Disconnect-Reconnect page, all devices */
+		len = resp_disconnect_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+        case 0x3:       /* Format device page, direct access */
+                len = resp_format_pg(ap, pcontrol, target);
+                offset += len;
+                break;
+	case 0x8:	/* Caching page, direct access */
+		len = resp_caching_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0xa:	/* Control Mode page, all devices */
+		len = resp_ctrl_m_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x1c:	/* Informational Exceptions Mode page, all devices */
+		len = resp_iec_m_pg(ap, pcontrol, target);
+		offset += len;
+		break;
+	case 0x3f:	/* Read all Mode pages */
+		len = resp_err_recov_pg(ap, pcontrol, target);
+		len += resp_disconnect_pg(ap + len, pcontrol, target);
+		len += resp_format_pg(ap + len, pcontrol, target);
+		len += resp_caching_pg(ap + len, pcontrol, target);
+		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
+		len += resp_iec_m_pg(ap + len, pcontrol, target);
+		offset += len;
+		break;
+	default:
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+			       	0);
+		return check_condition_result;
+	}
+	if (msense_6)
+		arr[0] = offset - 1;
+	else {
+		arr[0] = ((offset - 2) >> 8) & 0xff;
+		arr[1] = (offset - 2) & 0xff;
+	}
+	return fill_from_dev_buffer(scp, arr, min(alloc_len, offset));
+}
+
+static int resp_read(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		     int num, struct sdebug_dev_info * devip)
+{
+	unsigned long iflags;
+	int ret;
+
+	if (upper_blk || (block + num > sdebug_capacity)) {
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
+				0);
+		return check_condition_result;
+	}
+	if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
+	    (block <= OPT_MEDIUM_ERR_ADDR) &&
+	    ((block + num) > OPT_MEDIUM_ERR_ADDR)) {
+		mk_sense_buffer(devip, MEDIUM_ERROR, UNRECOVERED_READ_ERR,
+				0);
+		/* claim unrecoverable read error */
+		return check_condition_result;
+	}
+	read_lock_irqsave(&atomic_rw, iflags);
+	ret = fill_from_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
+			   	   num * SECT_SIZE);
+	read_unlock_irqrestore(&atomic_rw, iflags);
+	return ret;
+}
+
+static int resp_write(struct scsi_cmnd * SCpnt, int upper_blk, int block,
+		      int num, struct sdebug_dev_info * devip)
+{
+	unsigned long iflags;
+	int res;
+
+	if (upper_blk || (block + num > sdebug_capacity)) {
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE,
+			       	0);
+		return check_condition_result;
+	}
+
+	write_lock_irqsave(&atomic_rw, iflags);
+	res = fetch_to_dev_buffer(SCpnt, fake_storep + (block * SECT_SIZE),
+			   	  num * SECT_SIZE);
+	write_unlock_irqrestore(&atomic_rw, iflags);
+	if (-1 == res)
+		return (DID_ERROR << 16);
+	else if ((res < (num * SECT_SIZE)) &&
+		 (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+		printk(KERN_INFO "scsi_debug: write: cdb indicated=%d, "
+		       " IO sent=%d bytes\n", num * SECT_SIZE, res);
+	return 0;
+}
+
+#define SDEBUG_RLUN_ARR_SZ 128
+
+static int resp_report_luns(struct scsi_cmnd * scp,
+			    struct sdebug_dev_info * devip)
+{
+	unsigned int alloc_len;
+	int lun_cnt, i, upper;
+	unsigned char *cmd = (unsigned char *)scp->cmnd;
+	int select_report = (int)cmd[2];
+	struct scsi_lun *one_lun;
+	unsigned char arr[SDEBUG_RLUN_ARR_SZ];
+
+	alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
+	if ((alloc_len < 16) || (select_report > 2)) {
+		mk_sense_buffer(devip, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
+			       	0);
+		return check_condition_result;
+	}
+	/* can produce response with up to 16k luns (lun 0 to lun 16383) */
+	memset(arr, 0, SDEBUG_RLUN_ARR_SZ);
+	lun_cnt = scsi_debug_max_luns;
+	arr[2] = ((sizeof(struct scsi_lun) * lun_cnt) >> 8) & 0xff;
+	arr[3] = (sizeof(struct scsi_lun) * lun_cnt) & 0xff;
+	lun_cnt = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
+			    sizeof(struct scsi_lun)), lun_cnt);
+	one_lun = (struct scsi_lun *) &arr[8];
+	for (i = 0; i < lun_cnt; i++) {
+		upper = (i >> 8) & 0x3f;
+		if (upper)
+			one_lun[i].scsi_lun[0] =
+			    (upper | (SAM2_LUN_ADDRESS_METHOD << 6));
+		one_lun[i].scsi_lun[1] = i & 0xff;
+	}
+	return fill_from_dev_buffer(scp, arr,
+				    min((int)alloc_len, SDEBUG_RLUN_ARR_SZ));
+}
+
+/* When timer goes off this function is called. */
+static void timer_intr_handler(unsigned long indx)
+{
+	struct sdebug_queued_cmd * sqcp;
+	unsigned long iflags;
+
+	if (indx >= SCSI_DEBUG_CANQUEUE) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
+		       "large\n");
+		return;
+	}
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	sqcp = &queued_arr[(int)indx];
+	if (! sqcp->in_use) {
+		printk(KERN_ERR "scsi_debug:timer_intr_handler: Unexpected "
+		       "interrupt\n");
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		return;
+	}
+	sqcp->in_use = 0;
+	if (sqcp->done_funct) {
+		sqcp->a_cmnd->result = sqcp->scsi_result;
+		sqcp->done_funct(sqcp->a_cmnd); /* callback to mid level */
+	}
+	sqcp->done_funct = NULL;
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+static int scsi_debug_slave_alloc(struct scsi_device * sdp)
+{
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: slave_alloc <%u %u %u %u>\n",
+		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	return 0;
+}
+
+static int scsi_debug_slave_configure(struct scsi_device * sdp)
+{
+	struct sdebug_dev_info * devip;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: slave_configure <%u %u %u %u>\n",
+		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	if (sdp->host->max_cmd_len != SCSI_DEBUG_MAX_CMD_LEN)
+		sdp->host->max_cmd_len = SCSI_DEBUG_MAX_CMD_LEN;
+	devip = devInfoReg(sdp);
+	sdp->hostdata = devip;
+	if (sdp->host->cmd_per_lun)
+		scsi_adjust_queue_depth(sdp, SDEBUG_TAGGED_QUEUING,
+					sdp->host->cmd_per_lun);
+	return 0;
+}
+
+static void scsi_debug_slave_destroy(struct scsi_device * sdp)
+{
+	struct sdebug_dev_info * devip =
+				(struct sdebug_dev_info *)sdp->hostdata;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: slave_destroy <%u %u %u %u>\n",
+		       sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
+	if (devip) {
+		/* make this slot avaliable for re-use */
+		devip->used = 0;
+		sdp->hostdata = NULL;
+	}
+}
+
+static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
+{
+	struct sdebug_host_info * sdbg_host;
+	struct sdebug_dev_info * open_devip = NULL;
+	struct sdebug_dev_info * devip =
+			(struct sdebug_dev_info *)sdev->hostdata;
+
+	if (devip)
+		return devip;
+	sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
+        if(! sdbg_host) {
+                printk(KERN_ERR "Host info NULL\n");
+		return NULL;
+        }
+	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
+		if ((devip->used) && (devip->channel == sdev->channel) &&
+                    (devip->target == sdev->id) &&
+                    (devip->lun == sdev->lun))
+                        return devip;
+		else {
+			if ((!devip->used) && (!open_devip))
+				open_devip = devip;
+		}
+	}
+	if (NULL == open_devip) { /* try and make a new one */
+		open_devip = kmalloc(sizeof(*open_devip),GFP_KERNEL);
+		if (NULL == open_devip) {
+			printk(KERN_ERR "%s: out of memory at line %d\n",
+				__FUNCTION__, __LINE__);
+			return NULL;
+		}
+		memset(open_devip, 0, sizeof(*open_devip));
+		open_devip->sdbg_host = sdbg_host;
+		list_add_tail(&open_devip->dev_list,
+		&sdbg_host->dev_info_list);
+	}
+        if (open_devip) {
+		open_devip->channel = sdev->channel;
+		open_devip->target = sdev->id;
+		open_devip->lun = sdev->lun;
+		open_devip->sdbg_host = sdbg_host;
+		open_devip->reset = 1;
+		open_devip->used = 1;
+		memset(open_devip->sense_buff, 0, SDEBUG_SENSE_LEN);
+		if (scsi_debug_dsense)
+			open_devip->sense_buff[0] = 0x72;
+		else {
+			open_devip->sense_buff[0] = 0x70;
+			open_devip->sense_buff[7] = 0xa;
+		}
+		return open_devip;
+        }
+        return NULL;
+}
+
+static void mk_sense_buffer(struct sdebug_dev_info * devip, int key,
+			    int asc, int asq)
+{
+	unsigned char * sbuff;
+
+	sbuff = devip->sense_buff;
+	memset(sbuff, 0, SDEBUG_SENSE_LEN);
+	if (scsi_debug_dsense) {
+		sbuff[0] = 0x72;  /* descriptor, current */
+		sbuff[1] = key;
+		sbuff[2] = asc;
+		sbuff[3] = asq;
+	} else {
+		sbuff[0] = 0x70;  /* fixed, current */
+		sbuff[2] = key;
+		sbuff[7] = 0xa;	  /* implies 18 byte sense buffer */
+		sbuff[12] = asc;
+		sbuff[13] = asq;
+	}
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug:    [sense_key,asc,ascq]: "
+		      "[0x%x,0x%x,0x%x]\n", key, asc, asq);
+}
+
+static int scsi_debug_abort(struct scsi_cmnd * SCpnt)
+{
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: abort\n");
+	++num_aborts;
+	stop_queued_cmnd(SCpnt);
+	return SUCCESS;
+}
+
+static int scsi_debug_biosparam(struct scsi_device *sdev,
+		struct block_device * bdev, sector_t capacity, int *info)
+{
+	int res;
+	unsigned char *buf;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: biosparam\n");
+	buf = scsi_bios_ptable(bdev);
+	if (buf) {
+		res = scsi_partsize(buf, capacity,
+				    &info[2], &info[0], &info[1]);
+		kfree(buf);
+		if (! res)
+			return res;
+	}
+	info[0] = sdebug_heads;
+	info[1] = sdebug_sectors_per;
+	info[2] = sdebug_cylinders_per;
+	return 0;
+}
+
+static int scsi_debug_device_reset(struct scsi_cmnd * SCpnt)
+{
+	struct sdebug_dev_info * devip;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: device_reset\n");
+	++num_dev_resets;
+	if (SCpnt) {
+		devip = devInfoReg(SCpnt->device);
+		if (devip)
+			devip->reset = 1;
+	}
+	return SUCCESS;
+}
+
+static int scsi_debug_bus_reset(struct scsi_cmnd * SCpnt)
+{
+	struct sdebug_host_info *sdbg_host;
+        struct sdebug_dev_info * dev_info;
+        struct scsi_device * sdp;
+        struct Scsi_Host * hp;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: bus_reset\n");
+	++num_bus_resets;
+	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
+		sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
+		if (sdbg_host) {
+			list_for_each_entry(dev_info,
+                                            &sdbg_host->dev_info_list,
+                                            dev_list)
+				dev_info->reset = 1;
+		}
+	}
+	return SUCCESS;
+}
+
+static int scsi_debug_host_reset(struct scsi_cmnd * SCpnt)
+{
+	struct sdebug_host_info * sdbg_host;
+        struct sdebug_dev_info * dev_info;
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: host_reset\n");
+	++num_host_resets;
+        spin_lock(&sdebug_host_list_lock);
+        list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
+                list_for_each_entry(dev_info, &sdbg_host->dev_info_list,
+                                    dev_list)
+                        dev_info->reset = 1;
+        }
+        spin_unlock(&sdebug_host_list_lock);
+	stop_all_queued();
+	return SUCCESS;
+}
+
+/* Returns 1 if found 'cmnd' and deleted its timer. else returns 0 */
+static int stop_queued_cmnd(struct scsi_cmnd * cmnd)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && (cmnd == sqcp->a_cmnd)) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+	return (k < SCSI_DEBUG_CANQUEUE) ? 1 : 0;
+}
+
+/* Deletes (stops) timers of all queued commands */
+static void stop_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		if (sqcp->in_use && sqcp->a_cmnd) {
+			del_timer_sync(&sqcp->cmnd_timer);
+			sqcp->in_use = 0;
+			sqcp->a_cmnd = NULL;
+		}
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+/* Initializes timers in queued array */
+static void __init init_all_queued(void)
+{
+	unsigned long iflags;
+	int k;
+	struct sdebug_queued_cmd * sqcp;
+
+	spin_lock_irqsave(&queued_arr_lock, iflags);
+	for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+		sqcp = &queued_arr[k];
+		init_timer(&sqcp->cmnd_timer);
+		sqcp->in_use = 0;
+		sqcp->a_cmnd = NULL;
+	}
+	spin_unlock_irqrestore(&queued_arr_lock, iflags);
+}
+
+static void __init sdebug_build_parts(unsigned char * ramp)
+{
+	struct partition * pp;
+	int starts[SDEBUG_MAX_PARTS + 2];
+	int sectors_per_part, num_sectors, k;
+	int heads_by_sects, start_sec, end_sec;
+
+	/* assume partition table already zeroed */
+	if ((scsi_debug_num_parts < 1) || (sdebug_store_size < 1048576))
+		return;
+	if (scsi_debug_num_parts > SDEBUG_MAX_PARTS) {
+		scsi_debug_num_parts = SDEBUG_MAX_PARTS;
+		printk(KERN_WARNING "scsi_debug:build_parts: reducing "
+				    "partitions to %d\n", SDEBUG_MAX_PARTS);
+	}
+	num_sectors = (int)(sdebug_store_size / SECT_SIZE);
+	sectors_per_part = (num_sectors - sdebug_sectors_per)
+			   / scsi_debug_num_parts;
+	heads_by_sects = sdebug_heads * sdebug_sectors_per;
+        starts[0] = sdebug_sectors_per;
+	for (k = 1; k < scsi_debug_num_parts; ++k)
+		starts[k] = ((k * sectors_per_part) / heads_by_sects)
+			    * heads_by_sects;
+	starts[scsi_debug_num_parts] = num_sectors;
+	starts[scsi_debug_num_parts + 1] = 0;
+
+	ramp[510] = 0x55;	/* magic partition markings */
+	ramp[511] = 0xAA;
+	pp = (struct partition *)(ramp + 0x1be);
+	for (k = 0; starts[k + 1]; ++k, ++pp) {
+		start_sec = starts[k];
+		end_sec = starts[k + 1] - 1;
+		pp->boot_ind = 0;
+
+		pp->cyl = start_sec / heads_by_sects;
+		pp->head = (start_sec - (pp->cyl * heads_by_sects))
+			   / sdebug_sectors_per;
+		pp->sector = (start_sec % sdebug_sectors_per) + 1;
+
+		pp->end_cyl = end_sec / heads_by_sects;
+		pp->end_head = (end_sec - (pp->end_cyl * heads_by_sects))
+			       / sdebug_sectors_per;
+		pp->end_sector = (end_sec % sdebug_sectors_per) + 1;
+
+		pp->start_sect = start_sec;
+		pp->nr_sects = end_sec - start_sec + 1;
+		pp->sys_ind = 0x83;	/* plain Linux partition */
+	}
+}
+
+static int schedule_resp(struct scsi_cmnd * cmnd,
+			 struct sdebug_dev_info * devip,
+			 done_funct_t done, int scsi_result, int delta_jiff)
+{
+	if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) && cmnd) {
+		if (scsi_result) {
+			struct scsi_device * sdp = cmnd->device;
+
+			printk(KERN_INFO "scsi_debug:    <%u %u %u %u> "
+			       "non-zero result=0x%x\n", sdp->host->host_no,
+			       sdp->channel, sdp->id, sdp->lun, scsi_result);
+		}
+	}
+	if (cmnd && devip) {
+		/* simulate autosense by this driver */
+		if (SAM_STAT_CHECK_CONDITION == (scsi_result & 0xff))
+			memcpy(cmnd->sense_buffer, devip->sense_buff,
+			       (SCSI_SENSE_BUFFERSIZE > SDEBUG_SENSE_LEN) ?
+			       SDEBUG_SENSE_LEN : SCSI_SENSE_BUFFERSIZE);
+	}
+	if (delta_jiff <= 0) {
+		if (cmnd)
+			cmnd->result = scsi_result;
+		if (done)
+			done(cmnd);
+		return 0;
+	} else {
+		unsigned long iflags;
+		int k;
+		struct sdebug_queued_cmd * sqcp = NULL;
+
+		spin_lock_irqsave(&queued_arr_lock, iflags);
+		for (k = 0; k < SCSI_DEBUG_CANQUEUE; ++k) {
+			sqcp = &queued_arr[k];
+			if (! sqcp->in_use)
+				break;
+		}
+		if (k >= SCSI_DEBUG_CANQUEUE) {
+			spin_unlock_irqrestore(&queued_arr_lock, iflags);
+			printk(KERN_WARNING "scsi_debug: can_queue exceeded\n");
+			return 1;	/* report busy to mid level */
+		}
+		sqcp->in_use = 1;
+		sqcp->a_cmnd = cmnd;
+		sqcp->scsi_result = scsi_result;
+		sqcp->done_funct = done;
+		sqcp->cmnd_timer.function = timer_intr_handler;
+		sqcp->cmnd_timer.data = k;
+		sqcp->cmnd_timer.expires = jiffies + delta_jiff;
+		add_timer(&sqcp->cmnd_timer);
+		spin_unlock_irqrestore(&queued_arr_lock, iflags);
+		if (cmnd)
+			cmnd->result = 0;
+		return 0;
+	}
+}
+
+/* Set 'perm' (4th argument) to 0 to disable module_param's definition
+ * of sysfs parameters (which module_param doesn't yet support).
+ * Sysfs parameters defined explicitly below.
+ */
+module_param_named(add_host, scsi_debug_add_host, int, 0); /* perm=0644 */
+module_param_named(delay, scsi_debug_delay, int, 0); /* perm=0644 */
+module_param_named(dev_size_mb, scsi_debug_dev_size_mb, int, 0);
+module_param_named(dsense, scsi_debug_dsense, int, 0);
+module_param_named(every_nth, scsi_debug_every_nth, int, 0);
+module_param_named(max_luns, scsi_debug_max_luns, int, 0);
+module_param_named(num_parts, scsi_debug_num_parts, int, 0);
+module_param_named(num_tgts, scsi_debug_num_tgts, int, 0);
+module_param_named(opts, scsi_debug_opts, int, 0); /* perm=0644 */
+module_param_named(ptype, scsi_debug_ptype, int, 0);
+module_param_named(scsi_level, scsi_debug_scsi_level, int, 0);
+
+MODULE_AUTHOR("Eric Youngdale + Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI debug adapter driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SCSI_DEBUG_VERSION);
+
+MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
+MODULE_PARM_DESC(delay, "# of jiffies to delay response(def=1)");
+MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs");
+MODULE_PARM_DESC(dsense, "use descriptor sense format(def: fixed)");
+MODULE_PARM_DESC(every_nth, "timeout every nth command(def=100)");
+MODULE_PARM_DESC(max_luns, "number of SCSI LUNs per target to simulate");
+MODULE_PARM_DESC(num_parts, "number of partitions(def=0)");
+MODULE_PARM_DESC(num_tgts, "number of SCSI targets per host to simulate");
+MODULE_PARM_DESC(opts, "1->noise, 2->medium_error, 4->...");
+MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
+MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=5[SPC-3])");
+
+
+static char sdebug_info[256];
+
+static const char * scsi_debug_info(struct Scsi_Host * shp)
+{
+	sprintf(sdebug_info, "scsi_debug, version %s [%s], "
+		"dev_size_mb=%d, opts=0x%x", SCSI_DEBUG_VERSION,
+		scsi_debug_version_date, scsi_debug_dev_size_mb,
+		scsi_debug_opts);
+	return sdebug_info;
+}
+
+/* scsi_debug_proc_info
+ * Used if the driver currently has no own support for /proc/scsi
+ */
+static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset,
+				int length, int inout)
+{
+	int len, pos, begin;
+	int orig_length;
+
+	orig_length = length;
+
+	if (inout == 1) {
+		char arr[16];
+		int minLen = length > 15 ? 15 : length;
+
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		memcpy(arr, buffer, minLen);
+		arr[minLen] = '\0';
+		if (1 != sscanf(arr, "%d", &pos))
+			return -EINVAL;
+		scsi_debug_opts = pos;
+		if (scsi_debug_every_nth != 0)
+                        scsi_debug_cmnd_count = 0;
+		return length;
+	}
+	begin = 0;
+	pos = len = sprintf(buffer, "scsi_debug adapter driver, version "
+	    "%s [%s]\n"
+	    "num_tgts=%d, shared (ram) size=%d MB, opts=0x%x, "
+	    "every_nth=%d(curr:%d)\n"
+	    "delay=%d, max_luns=%d, scsi_level=%d\n"
+	    "sector_size=%d bytes, cylinders=%d, heads=%d, sectors=%d\n"
+	    "number of aborts=%d, device_reset=%d, bus_resets=%d, "
+	    "host_resets=%d\n",
+	    SCSI_DEBUG_VERSION, scsi_debug_version_date, scsi_debug_num_tgts,
+	    scsi_debug_dev_size_mb, scsi_debug_opts, scsi_debug_every_nth,
+	    scsi_debug_cmnd_count, scsi_debug_delay,
+	    scsi_debug_max_luns, scsi_debug_scsi_level,
+	    SECT_SIZE, sdebug_cylinders_per, sdebug_heads, sdebug_sectors_per,
+	    num_aborts, num_dev_resets, num_bus_resets, num_host_resets);
+	if (pos < offset) {
+		len = 0;
+		begin = pos;
+	}
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);
+	if (len > length)
+		len = length;
+	return len;
+}
+
+static ssize_t sdebug_delay_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_delay);
+}
+
+static ssize_t sdebug_delay_store(struct device_driver * ddp,
+				  const char * buf, size_t count)
+{
+        int delay;
+	char work[20];
+
+        if (1 == sscanf(buf, "%10s", work)) {
+		if ((1 == sscanf(work, "%d", &delay)) && (delay >= 0)) {
+			scsi_debug_delay = delay;
+			return count;
+		}
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(delay, S_IRUGO | S_IWUSR, sdebug_delay_show,
+	    sdebug_delay_store);
+
+static ssize_t sdebug_opts_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "0x%x\n", scsi_debug_opts);
+}
+
+static ssize_t sdebug_opts_store(struct device_driver * ddp,
+				 const char * buf, size_t count)
+{
+        int opts;
+	char work[20];
+
+        if (1 == sscanf(buf, "%10s", work)) {
+		if (0 == strnicmp(work,"0x", 2)) {
+			if (1 == sscanf(&work[2], "%x", &opts))
+				goto opts_done;
+		} else {
+			if (1 == sscanf(work, "%d", &opts))
+				goto opts_done;
+		}
+	}
+	return -EINVAL;
+opts_done:
+	scsi_debug_opts = opts;
+	scsi_debug_cmnd_count = 0;
+	return count;
+}
+DRIVER_ATTR(opts, S_IRUGO | S_IWUSR, sdebug_opts_show,
+	    sdebug_opts_store);
+
+static ssize_t sdebug_ptype_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_ptype);
+}
+static ssize_t sdebug_ptype_store(struct device_driver * ddp,
+				  const char * buf, size_t count)
+{
+        int n;
+
+	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+		scsi_debug_ptype = n;
+		return count;
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(ptype, S_IRUGO | S_IWUSR, sdebug_ptype_show, sdebug_ptype_store);
+
+static ssize_t sdebug_dsense_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dsense);
+}
+static ssize_t sdebug_dsense_store(struct device_driver * ddp,
+				  const char * buf, size_t count)
+{
+        int n;
+
+	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+		scsi_debug_dsense = n;
+		return count;
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(dsense, S_IRUGO | S_IWUSR, sdebug_dsense_show,
+	    sdebug_dsense_store);
+
+static ssize_t sdebug_num_tgts_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_tgts);
+}
+static ssize_t sdebug_num_tgts_store(struct device_driver * ddp,
+				     const char * buf, size_t count)
+{
+        int n;
+
+	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+		scsi_debug_num_tgts = n;
+		sdebug_max_tgts_luns();
+		return count;
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(num_tgts, S_IRUGO | S_IWUSR, sdebug_num_tgts_show,
+	    sdebug_num_tgts_store);
+
+static ssize_t sdebug_dev_size_mb_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_dev_size_mb);
+}
+DRIVER_ATTR(dev_size_mb, S_IRUGO, sdebug_dev_size_mb_show, NULL);
+
+static ssize_t sdebug_num_parts_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_num_parts);
+}
+DRIVER_ATTR(num_parts, S_IRUGO, sdebug_num_parts_show, NULL);
+
+static ssize_t sdebug_every_nth_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_every_nth);
+}
+static ssize_t sdebug_every_nth_store(struct device_driver * ddp,
+				      const char * buf, size_t count)
+{
+        int nth;
+
+	if ((count > 0) && (1 == sscanf(buf, "%d", &nth))) {
+		scsi_debug_every_nth = nth;
+		scsi_debug_cmnd_count = 0;
+		return count;
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(every_nth, S_IRUGO | S_IWUSR, sdebug_every_nth_show,
+	    sdebug_every_nth_store);
+
+static ssize_t sdebug_max_luns_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_max_luns);
+}
+static ssize_t sdebug_max_luns_store(struct device_driver * ddp,
+				     const char * buf, size_t count)
+{
+        int n;
+
+	if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+		scsi_debug_max_luns = n;
+		sdebug_max_tgts_luns();
+		return count;
+	}
+	return -EINVAL;
+}
+DRIVER_ATTR(max_luns, S_IRUGO | S_IWUSR, sdebug_max_luns_show,
+	    sdebug_max_luns_store);
+
+static ssize_t sdebug_scsi_level_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_scsi_level);
+}
+DRIVER_ATTR(scsi_level, S_IRUGO, sdebug_scsi_level_show, NULL);
+
+static ssize_t sdebug_add_host_show(struct device_driver * ddp, char * buf)
+{
+        return scnprintf(buf, PAGE_SIZE, "%d\n", scsi_debug_add_host);
+}
+
+static ssize_t sdebug_add_host_store(struct device_driver * ddp,
+				     const char * buf, size_t count)
+{
+        int delta_hosts;
+	char work[20];
+
+        if (1 != sscanf(buf, "%10s", work))
+		return -EINVAL;
+	{	/* temporary hack around sscanf() problem with -ve nums */
+		int neg = 0;
+
+		if ('-' == *work)
+			neg = 1;
+		if (1 != sscanf(work + neg, "%d", &delta_hosts))
+			return -EINVAL;
+		if (neg)
+			delta_hosts = -delta_hosts;
+	}
+	if (delta_hosts > 0) {
+		do {
+			sdebug_add_adapter();
+		} while (--delta_hosts);
+	} else if (delta_hosts < 0) {
+		do {
+			sdebug_remove_adapter();
+		} while (++delta_hosts);
+	}
+	return count;
+}
+DRIVER_ATTR(add_host, S_IRUGO | S_IWUSR, sdebug_add_host_show, 
+	    sdebug_add_host_store);
+
+static void do_create_driverfs_files(void)
+{
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_add_host);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_delay);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_opts);
+	driver_create_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+}
+
+static void do_remove_driverfs_files(void)
+{
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_scsi_level);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_opts);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_ptype);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_parts);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_num_tgts);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_max_luns);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_every_nth);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dsense);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_dev_size_mb);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_delay);
+	driver_remove_file(&sdebug_driverfs_driver, &driver_attr_add_host);
+}
+
+static int __init scsi_debug_init(void)
+{
+	unsigned long sz;
+	int host_to_add;
+	int k;
+
+	if (scsi_debug_dev_size_mb < 1)
+		scsi_debug_dev_size_mb = 1;  /* force minimum 1 MB ramdisk */
+	sdebug_store_size = (unsigned long)scsi_debug_dev_size_mb * 1048576;
+	sdebug_capacity = sdebug_store_size / SECT_SIZE;
+
+	/* play around with geometry, don't waste too much on track 0 */
+	sdebug_heads = 8;
+	sdebug_sectors_per = 32;
+	if (scsi_debug_dev_size_mb >= 16)
+		sdebug_heads = 32;
+	else if (scsi_debug_dev_size_mb >= 256)
+		sdebug_heads = 64;
+	sdebug_cylinders_per = (unsigned long)sdebug_capacity /
+			       (sdebug_sectors_per * sdebug_heads);
+	if (sdebug_cylinders_per >= 1024) {
+		/* other LLDs do this; implies >= 1GB ram disk ... */
+		sdebug_heads = 255;
+		sdebug_sectors_per = 63;
+		sdebug_cylinders_per = (unsigned long)sdebug_capacity /
+			       (sdebug_sectors_per * sdebug_heads);
+	}
+
+	sz = sdebug_store_size;
+	fake_storep = vmalloc(sz);
+	if (NULL == fake_storep) {
+		printk(KERN_ERR "scsi_debug_init: out of memory, 1\n");
+		return -ENOMEM;
+	}
+	memset(fake_storep, 0, sz);
+	if (scsi_debug_num_parts > 0)
+		sdebug_build_parts(fake_storep);
+
+	init_all_queued();
+
+	device_register(&pseudo_primary);
+	bus_register(&pseudo_lld_bus);
+	driver_register(&sdebug_driverfs_driver);
+	do_create_driverfs_files();
+
+	sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
+
+	host_to_add = scsi_debug_add_host;
+        scsi_debug_add_host = 0;
+
+        for (k = 0; k < host_to_add; k++) {
+                if (sdebug_add_adapter()) {
+                        printk(KERN_ERR "scsi_debug_init: "
+                               "sdebug_add_adapter failed k=%d\n", k);
+                        break;
+                }
+        }
+
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) {
+		printk(KERN_INFO "scsi_debug_init: built %d host(s)\n",
+		       scsi_debug_add_host);
+	}
+	return 0;
+}
+
+static void __exit scsi_debug_exit(void)
+{
+	int k = scsi_debug_add_host;
+
+	stop_all_queued();
+	for (; k; k--)
+		sdebug_remove_adapter();
+	do_remove_driverfs_files();
+	driver_unregister(&sdebug_driverfs_driver);
+	bus_unregister(&pseudo_lld_bus);
+	device_unregister(&pseudo_primary);
+
+	vfree(fake_storep);
+}
+
+device_initcall(scsi_debug_init);
+module_exit(scsi_debug_exit);
+
+void pseudo_0_release(struct device * dev)
+{
+	if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+		printk(KERN_INFO "scsi_debug: pseudo_0_release() called\n");
+}
+
+static struct device pseudo_primary = {
+	.bus_id		= "pseudo_0",
+	.release	= pseudo_0_release,
+};
+
+static int pseudo_lld_bus_match(struct device *dev,
+                          struct device_driver *dev_driver)
+{
+        return 1;
+}
+
+static struct bus_type pseudo_lld_bus = {
+        .name = "pseudo",
+        .match = pseudo_lld_bus_match,
+};
+
+static void sdebug_release_adapter(struct device * dev)
+{
+        struct sdebug_host_info *sdbg_host;
+
+	sdbg_host = to_sdebug_host(dev);
+        kfree(sdbg_host);
+}
+
+static int sdebug_add_adapter(void)
+{
+	int k, devs_per_host;
+        int error = 0;
+        struct sdebug_host_info *sdbg_host;
+        struct sdebug_dev_info *sdbg_devinfo;
+        struct list_head *lh, *lh_sf;
+
+        sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL);
+
+        if (NULL == sdbg_host) {
+                printk(KERN_ERR "%s: out of memory at line %d\n",
+                       __FUNCTION__, __LINE__);
+                return -ENOMEM;
+        }
+
+        memset(sdbg_host, 0, sizeof(*sdbg_host));
+        INIT_LIST_HEAD(&sdbg_host->dev_info_list);
+
+	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
+        for (k = 0; k < devs_per_host; k++) {
+                sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
+                if (NULL == sdbg_devinfo) {
+                        printk(KERN_ERR "%s: out of memory at line %d\n",
+                               __FUNCTION__, __LINE__);
+                        error = -ENOMEM;
+			goto clean;
+                }
+                memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo));
+                sdbg_devinfo->sdbg_host = sdbg_host;
+                list_add_tail(&sdbg_devinfo->dev_list,
+                              &sdbg_host->dev_info_list);
+        }
+
+        spin_lock(&sdebug_host_list_lock);
+        list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
+        spin_unlock(&sdebug_host_list_lock);
+
+        sdbg_host->dev.bus = &pseudo_lld_bus;
+        sdbg_host->dev.parent = &pseudo_primary;
+        sdbg_host->dev.release = &sdebug_release_adapter;
+        sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
+
+        error = device_register(&sdbg_host->dev);
+
+        if (error)
+		goto clean;
+
+	++scsi_debug_add_host;
+        return error;
+
+clean:
+	list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
+		sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
+					  dev_list);
+		list_del(&sdbg_devinfo->dev_list);
+		kfree(sdbg_devinfo);
+	}
+
+	kfree(sdbg_host);
+        return error;
+}
+
+static void sdebug_remove_adapter(void)
+{
+        struct sdebug_host_info * sdbg_host = NULL;
+
+        spin_lock(&sdebug_host_list_lock);
+        if (!list_empty(&sdebug_host_list)) {
+                sdbg_host = list_entry(sdebug_host_list.prev,
+                                       struct sdebug_host_info, host_list);
+		list_del(&sdbg_host->host_list);
+	}
+        spin_unlock(&sdebug_host_list_lock);
+
+	if (!sdbg_host)
+		return;
+
+        device_unregister(&sdbg_host->dev);
+        --scsi_debug_add_host;
+}
+
+static int sdebug_driver_probe(struct device * dev)
+{
+        int error = 0;
+        struct sdebug_host_info *sdbg_host;
+        struct Scsi_Host *hpnt;
+
+	sdbg_host = to_sdebug_host(dev);
+
+        hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
+        if (NULL == hpnt) {
+                printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
+                error = -ENODEV;
+		return error;
+        }
+
+        sdbg_host->shost = hpnt;
+	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
+	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
+		hpnt->max_id = scsi_debug_num_tgts + 1;
+	else
+		hpnt->max_id = scsi_debug_num_tgts;
+	hpnt->max_lun = scsi_debug_max_luns;
+
+        error = scsi_add_host(hpnt, &sdbg_host->dev);
+        if (error) {
+                printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
+                error = -ENODEV;
+		scsi_host_put(hpnt);
+        } else
+		scsi_scan_host(hpnt);
+
+
+        return error;
+}
+
+static int sdebug_driver_remove(struct device * dev)
+{
+        struct list_head *lh, *lh_sf;
+        struct sdebug_host_info *sdbg_host;
+        struct sdebug_dev_info *sdbg_devinfo;
+
+	sdbg_host = to_sdebug_host(dev);
+
+	if (!sdbg_host) {
+		printk(KERN_ERR "%s: Unable to locate host info\n",
+		       __FUNCTION__);
+		return -ENODEV;
+	}
+
+        scsi_remove_host(sdbg_host->shost);
+
+        list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
+                sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
+                                          dev_list);
+                list_del(&sdbg_devinfo->dev_list);
+                kfree(sdbg_devinfo);
+        }
+
+        scsi_host_put(sdbg_host->shost);
+        return 0;
+}
+
+static void sdebug_max_tgts_luns(void)
+{
+	struct sdebug_host_info * sdbg_host;
+	struct Scsi_Host *hpnt;
+
+	spin_lock(&sdebug_host_list_lock);
+	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
+		hpnt = sdbg_host->shost;
+		if ((hpnt->this_id >= 0) &&
+		    (scsi_debug_num_tgts > hpnt->this_id))
+			hpnt->max_id = scsi_debug_num_tgts + 1;
+		else
+			hpnt->max_id = scsi_debug_num_tgts;
+		hpnt->max_lun = scsi_debug_max_luns;
+	}
+	spin_unlock(&sdebug_host_list_lock);
+}
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
new file mode 100644
index 0000000..965dd5e
--- /dev/null
+++ b/drivers/scsi/scsi_debug.h
@@ -0,0 +1,24 @@
+#ifndef _SCSI_DEBUG_H
+
+#include <linux/types.h>
+
+static int scsi_debug_slave_alloc(struct scsi_device *);
+static int scsi_debug_slave_configure(struct scsi_device *);
+static void scsi_debug_slave_destroy(struct scsi_device *);
+static int scsi_debug_queuecommand(struct scsi_cmnd *,
+				   void (*done) (struct scsi_cmnd *));
+static int scsi_debug_ioctl(struct scsi_device *, int, void __user *);
+static int scsi_debug_biosparam(struct scsi_device *, struct block_device *,
+		sector_t, int[]);
+static int scsi_debug_abort(struct scsi_cmnd *);
+static int scsi_debug_bus_reset(struct scsi_cmnd *);
+static int scsi_debug_device_reset(struct scsi_cmnd *);
+static int scsi_debug_host_reset(struct scsi_cmnd *);
+static int scsi_debug_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+static const char * scsi_debug_info(struct Scsi_Host *);
+
+#define SCSI_DEBUG_CANQUEUE  255 	/* needs to be >= 1 */
+
+#define SCSI_DEBUG_MAX_CMD_LEN 16
+
+#endif
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
new file mode 100644
index 0000000..6121dc1
--- /dev/null
+++ b/drivers/scsi/scsi_devinfo.c
@@ -0,0 +1,564 @@
+
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_devinfo.h>
+
+#include "scsi_priv.h"
+
+
+/*
+ * scsi_dev_info_list: structure to hold black/white listed devices.
+ */
+struct scsi_dev_info_list {
+	struct list_head dev_info_list;
+	char vendor[8];
+	char model[16];
+	unsigned flags;
+	unsigned compatible; /* for use with scsi_static_device_list entries */
+};
+
+
+static const char spaces[] = "                "; /* 16 of them */
+static unsigned scsi_default_dev_flags;
+static LIST_HEAD(scsi_dev_info_list);
+static char scsi_dev_flags[256];
+
+/*
+ * scsi_static_device_list: deprecated list of devices that require
+ * settings that differ from the default, includes black-listed (broken)
+ * devices. The entries here are added to the tail of scsi_dev_info_list
+ * via scsi_dev_info_list_init.
+ *
+ * Do not add to this list, use the command line or proc interface to add
+ * to the scsi_dev_info_list. This table will eventually go away.
+ */
+static struct {
+	char *vendor;
+	char *model;
+	char *revision;	/* revision known to be bad, unused */
+	unsigned flags;
+} scsi_static_device_list[] __initdata = {
+	/*
+	 * The following devices are known not to tolerate a lun != 0 scan
+	 * for one reason or another. Some will respond to all luns,
+	 * others will lock up.
+	 */
+	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* locks up */
+	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* locks up */
+	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},	/* responds to all lun */
+	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},	/* responds to all lun */
+	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* locks up */
+	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* responds to all lun */
+	{"MICROTEK", "ScanMakerIII", "2.30", BLIST_NOLUN},	/* responds to all lun */
+	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
+	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* responds to all lun */
+	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* locks up */
+	{"SUN", "SENA", NULL, BLIST_NOLUN},		/* responds to all luns */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},
+	{"SEAGATE", "ST296", "921", BLIST_NOLUN},	/* responds to all lun */
+	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},	/* responds to all lun */
+	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN},
+	{"SONY", "SDT-5000", "3.17", BLIST_SELECT_NO_ATN},
+	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},	/* locks up */
+	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},	/* locks up */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* responds to all lun */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
+	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
+	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
+	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
+	{"NEC", "D3856", "0009", BLIST_NOLUN},
+	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* locks up */
+	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
+	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},	/* locks up */
+
+	/*
+	 * Other types of devices that have special flags.
+	 * Note that all USB devices should have the BLIST_INQUIRY_36 flag.
+	 */
+	{"3PARdata", "VV", NULL, BLIST_REPORTLUN2},
+	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
+	{"AFT PRO", "-IX CF", "0.0>", BLIST_FORCELUN},
+	{"BELKIN", "USB 2 HS-CF", "1.95",  BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
+	{"CBOX3", "USB Storage-SMC", "300A", BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
+	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
+	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
+	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"COMPAQ", "HSV110", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
+	{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
+	{"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD},
+	{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
+	{"DELL", "PV660F   PSEUDO", NULL, BLIST_SPARSELUN},
+	{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN},	/* Dell PV 530F */
+	{"DELL", "PV530F", NULL, BLIST_SPARSELUN},
+	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
+	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
+	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
+	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"Generic", "USB SD Reader", "1.00", BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"Generic", "USB Storage-SMC", "0180", BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"Generic", "USB Storage-SMC", "0207", BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
+	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
+	{"HP", "HSV100", NULL, BLIST_REPORTLUN2 | BLIST_NOSTARTONADD},
+	{"HP", "C1557A", NULL, BLIST_FORCELUN},
+	{"HP", "C3323-300", "4269", BLIST_NOTQ},
+	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
+	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"IBM", "2105", NULL, BLIST_RETRY_HWERROR},
+	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
+	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
+	{"INSITE", "I325VM", NULL, BLIST_KEY},
+	{"iRiver", "iFP Mass Driver", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
+	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"MATSHITA", "DMC-LC5", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
+	{"MATSHITA", "DMC-LC40", NULL, BLIST_NOT_LOCKABLE | BLIST_INQUIRY_36},
+	{"Medion", "Flash XL  MMC/SD", "2.6D", BLIST_FORCELUN},
+	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
+	{"MICROP", "4110", NULL, BLIST_NOTQ},
+	{"MYLEX", "DACARMRB", "*", BLIST_REPORTLUN2},
+	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
+	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN},
+	{"SEAGATE", "ST34555N", "0930", BLIST_NOTQ},	/* Chokes on tagged INQUIRY */
+	{"SEAGATE", "ST3390N", "9546", BLIST_NOTQ},
+	{"SGI", "RAID3", "*", BLIST_SPARSELUN},
+	{"SGI", "RAID5", "*", BLIST_SPARSELUN},
+	{"SGI", "TP9100", "*", BLIST_REPORTLUN2},
+	{"SGI", "Universal Xport", "*", BLIST_NO_ULD_ATTACH},
+	{"SMSC", "USB 2 HS-CF", NULL, BLIST_SPARSELUN | BLIST_INQUIRY_36},
+	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
+	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
+	{"ST650211", "CF", NULL, BLIST_RETRY_HWERROR},
+	{"SUN", "T300", "*", BLIST_SPARSELUN},
+	{"SUN", "T4", "*", BLIST_SPARSELUN},
+	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
+	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+	{"USB2.0", "SMARTMEDIA/XD", NULL, BLIST_FORCELUN | BLIST_INQUIRY_36},
+	{"WangDAT", "Model 2600", "01.7", BLIST_SELECT_NO_ATN},
+	{"WangDAT", "Model 3200", "02.2", BLIST_SELECT_NO_ATN},
+	{"WangDAT", "Model 1300", "02.4", BLIST_SELECT_NO_ATN},
+	{"WDC WD25", "00JB-00FUA0", NULL, BLIST_NOREPORTLUN},
+	{"XYRATEX", "RS", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
+	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
+	{ NULL, NULL, NULL, 0 },
+};
+
+/*
+ * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into
+ * devinfo vendor and model strings.
+ */
+static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
+				char *from, int compatible)
+{
+	size_t from_length;
+
+	from_length = strlen(from);
+	strncpy(to, from, min(to_length, from_length));
+	if (from_length < to_length) {
+		if (compatible) {
+			/*
+			 * NUL terminate the string if it is short.
+			 */
+			to[from_length] = '\0';
+		} else {
+			/* 
+			 * space pad the string if it is short. 
+			 */
+			strncpy(&to[from_length], spaces,
+				to_length - from_length);
+		}
+	}
+	if (from_length > to_length)
+		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
+			__FUNCTION__, name, from);
+}
+
+/**
+ * scsi_dev_info_list_add: add one dev_info list entry.
+ * @vendor:	vendor string
+ * @model:	model (product) string
+ * @strflags:	integer string
+ * @flag:	if strflags NULL, use this flag value
+ *
+ * Description:
+ * 	Create and add one dev_info entry for @vendor, @model, @strflags or
+ * 	@flag. If @compatible, add to the tail of the list, do not space
+ * 	pad, and set devinfo->compatible. The scsi_static_device_list entries
+ * 	are added with @compatible 1 and @clfags NULL.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
+			    char *strflags, int flags)
+{
+	struct scsi_dev_info_list *devinfo;
+
+	devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
+	if (!devinfo) {
+		printk(KERN_ERR "%s: no memory\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor),
+			    vendor, compatible);
+	scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model),
+			    model, compatible);
+
+	if (strflags)
+		devinfo->flags = simple_strtoul(strflags, NULL, 0);
+	else
+		devinfo->flags = flags;
+
+	devinfo->compatible = compatible;
+
+	if (compatible)
+		list_add_tail(&devinfo->dev_info_list, &scsi_dev_info_list);
+	else
+		list_add(&devinfo->dev_info_list, &scsi_dev_info_list);
+
+	return 0;
+}
+
+/**
+ * scsi_dev_info_list_add_str: parse dev_list and add to the
+ * scsi_dev_info_list.
+ * @dev_list:	string of device flags to add
+ *
+ * Description:
+ * 	Parse dev_list, and add entries to the scsi_dev_info_list.
+ * 	dev_list is of the form "vendor:product:flag,vendor:product:flag".
+ * 	dev_list is modified via strsep. Can be called for command line
+ * 	addition, for proc or mabye a sysfs interface.
+ *
+ * Returns: 0 if OK, -error on failure.
+ **/
+static int scsi_dev_info_list_add_str(char *dev_list)
+{
+	char *vendor, *model, *strflags, *next;
+	char *next_check;
+	int res = 0;
+
+	next = dev_list;
+	if (next && next[0] == '"') {
+		/*
+		 * Ignore both the leading and trailing quote.
+		 */
+		next++;
+		next_check = ",\"";
+	} else {
+		next_check = ",";
+	}
+
+	/*
+	 * For the leading and trailing '"' case, the for loop comes
+	 * through the last time with vendor[0] == '\0'.
+	 */
+	for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0')
+	     && (res == 0); vendor = strsep(&next, ":")) {
+		strflags = NULL;
+		model = strsep(&next, ":");
+		if (model)
+			strflags = strsep(&next, next_check);
+		if (!model || !strflags) {
+			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
+			       " '%s'\n", __FUNCTION__, vendor, model,
+			       strflags);
+			res = -EINVAL;
+		} else
+			res = scsi_dev_info_list_add(0 /* compatible */, vendor,
+						     model, strflags, 0);
+	}
+	return res;
+}
+
+/**
+ * get_device_flags - get device specific flags from the dynamic device
+ * list. Called during scan time.
+ * @vendor:	vendor name
+ * @model:	model name
+ *
+ * Description:
+ *     Search the scsi_dev_info_list for an entry matching @vendor and
+ *     @model, if found, return the matching flags value, else return
+ *     the host or global default settings.
+ **/
+int scsi_get_device_flags(struct scsi_device *sdev, unsigned char *vendor,
+			  unsigned char *model)
+{
+	struct scsi_dev_info_list *devinfo;
+	unsigned int bflags;
+
+	bflags = sdev->sdev_bflags;
+	if (!bflags)
+		bflags = scsi_default_dev_flags;
+
+	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+		if (devinfo->compatible) {
+			/*
+			 * Behave like the older version of get_device_flags.
+			 */
+			size_t max;
+			/*
+			 * XXX why skip leading spaces? If an odd INQUIRY
+			 * value, that should have been part of the
+			 * scsi_static_device_list[] entry, such as "  FOO"
+			 * rather than "FOO". Since this code is already
+			 * here, and we don't know what device it is
+			 * trying to work with, leave it as-is.
+			 */
+			max = 8;	/* max length of vendor */
+			while ((max > 0) && *vendor == ' ') {
+				max--;
+				vendor++;
+			}
+			/*
+			 * XXX removing the following strlen() would be
+			 * good, using it means that for a an entry not in
+			 * the list, we scan every byte of every vendor
+			 * listed in scsi_static_device_list[], and never match
+			 * a single one (and still have to compare at
+			 * least the first byte of each vendor).
+			 */
+			if (memcmp(devinfo->vendor, vendor,
+				    min(max, strlen(devinfo->vendor))))
+				continue;
+			/*
+			 * Skip spaces again.
+			 */
+			max = 16;	/* max length of model */
+			while ((max > 0) && *model == ' ') {
+				max--;
+				model++;
+			}
+			if (memcmp(devinfo->model, model,
+				   min(max, strlen(devinfo->model))))
+				continue;
+			return devinfo->flags;
+		} else {
+			if (!memcmp(devinfo->vendor, vendor,
+				     sizeof(devinfo->vendor)) &&
+			     !memcmp(devinfo->model, model,
+				      sizeof(devinfo->model)))
+				return devinfo->flags;
+		}
+	}
+	return bflags;
+}
+
+#ifdef CONFIG_SCSI_PROC_FS
+/* 
+ * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
+ * /proc/scsi/device_info
+ */
+static int proc_scsi_devinfo_read(char *buffer, char **start,
+				  off_t offset, int length)
+{
+	struct scsi_dev_info_list *devinfo;
+	int size, len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
+
+	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+		size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+			devinfo->vendor, devinfo->model, devinfo->flags);
+		len += size;
+		pos = begin + len;
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			goto stop_output;
+	}
+
+stop_output:
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);	/* Start slop */
+	if (len > length)
+		len = length;	/* Ending slop */
+	return (len);
+}
+
+/* 
+ * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
+ * /proc.
+ *
+ * Use: echo "vendor:model:flag" > /proc/scsi/device_info
+ *
+ * To add a black/white list entry for vendor and model with an integer
+ * value of flag to the scsi device info list.
+ */
+static int proc_scsi_devinfo_write(struct file *file, const char __user *buf,
+				   unsigned long length, void *data)
+{
+	char *buffer;
+	int err = length;
+
+	if (!buf || length>PAGE_SIZE)
+		return -EINVAL;
+	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if (copy_from_user(buffer, buf, length)) {
+		err =-EFAULT;
+		goto out;
+	}
+
+	if (length < PAGE_SIZE)
+		buffer[length] = '\0';
+	else if (buffer[PAGE_SIZE-1]) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	scsi_dev_info_list_add_str(buffer);
+
+out:
+	free_page((unsigned long)buffer);
+	return err;
+}
+#endif /* CONFIG_SCSI_PROC_FS */
+
+module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0);
+MODULE_PARM_DESC(dev_flags,
+	 "Given scsi_dev_flags=vendor:model:flags[,v:m:f] add black/white"
+	 " list entries for vendor and model with an integer value of flags"
+	 " to the scsi device info list");
+
+module_param_named(default_dev_flags, scsi_default_dev_flags, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(default_dev_flags,
+		 "scsi default device flag integer value");
+
+/**
+ * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
+ * 	the scsi_dev_info_list.
+ **/
+void scsi_exit_devinfo(void)
+{
+	struct list_head *lh, *lh_next;
+	struct scsi_dev_info_list *devinfo;
+
+#ifdef CONFIG_SCSI_PROC_FS
+	remove_proc_entry("scsi/device_info", NULL);
+#endif
+
+	list_for_each_safe(lh, lh_next, &scsi_dev_info_list) {
+		devinfo = list_entry(lh, struct scsi_dev_info_list,
+				     dev_info_list);
+		kfree(devinfo);
+	}
+}
+
+/**
+ * scsi_dev_list_init: set up the dynamic device list.
+ * @dev_list:	string of device flags to add
+ *
+ * Description:
+ * 	Add command line @dev_list entries, then add
+ * 	scsi_static_device_list entries to the scsi device info list.
+ **/
+int __init scsi_init_devinfo(void)
+{
+#ifdef CONFIG_SCSI_PROC_FS
+	struct proc_dir_entry *p;
+#endif
+	int error, i;
+
+	error = scsi_dev_info_list_add_str(scsi_dev_flags);
+	if (error)
+		return error;
+
+	for (i = 0; scsi_static_device_list[i].vendor; i++) {
+		error = scsi_dev_info_list_add(1 /* compatibile */,
+				scsi_static_device_list[i].vendor,
+				scsi_static_device_list[i].model,
+				NULL,
+				scsi_static_device_list[i].flags);
+		if (error)
+			goto out;
+	}
+
+#ifdef CONFIG_SCSI_PROC_FS
+	p = create_proc_entry("scsi/device_info", 0, NULL);
+	if (!p) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	p->owner = THIS_MODULE;
+	p->get_info = proc_scsi_devinfo_read;
+	p->write_proc = proc_scsi_devinfo_write;
+#endif /* CONFIG_SCSI_PROC_FS */
+
+ out:
+	if (error)
+		scsi_exit_devinfo();
+	return error;
+}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
new file mode 100644
index 0000000..9bc597b
--- /dev/null
+++ b/drivers/scsi/scsi_error.c
@@ -0,0 +1,2050 @@
+/*
+ *  scsi_error.c Copyright (C) 1997 Eric Youngdale
+ *
+ *  SCSI error/timeout handling
+ *      Initial versions: Eric Youngdale.  Based upon conversations with
+ *                        Leonard Zubkoff and David Miller at Linux Expo, 
+ *                        ideas originating from all over the place.
+ *
+ *	Restructured scsi_unjam_host and associated functions.
+ *	September 04, 2002 Mike Anderson (andmike@us.ibm.com)
+ *
+ *	Forward port of Russell King's (rmk@arm.linux.org.uk) changes and
+ *	minor  cleanups.
+ *	September 30, 2002 Mike Anderson (andmike@us.ibm.com)
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+#define SENSE_TIMEOUT		(10*HZ)
+#define START_UNIT_TIMEOUT	(30*HZ)
+
+/*
+ * These should *probably* be handled by the host itself.
+ * Since it is allowed to sleep, it probably should.
+ */
+#define BUS_RESET_SETTLE_TIME   (10)
+#define HOST_RESET_SETTLE_TIME  (10)
+
+/* called with shost->host_lock held */
+void scsi_eh_wakeup(struct Scsi_Host *shost)
+{
+	if (shost->host_busy == shost->host_failed) {
+		up(shost->eh_wait);
+		SCSI_LOG_ERROR_RECOVERY(5,
+				printk("Waking error handler thread\n"));
+	}
+}
+
+/**
+ * scsi_eh_scmd_add - add scsi cmd to error handling.
+ * @scmd:	scmd to run eh on.
+ * @eh_flag:	optional SCSI_EH flag.
+ *
+ * Return value:
+ *	0 on failure.
+ **/
+int scsi_eh_scmd_add(struct scsi_cmnd *scmd, int eh_flag)
+{
+	struct Scsi_Host *shost = scmd->device->host;
+	unsigned long flags;
+
+	if (shost->eh_wait == NULL)
+		return 0;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	scsi_eh_eflags_set(scmd, eh_flag);
+	/*
+	 * FIXME: Can we stop setting owner and state.
+	 */
+	scmd->owner = SCSI_OWNER_ERROR_HANDLER;
+	scmd->state = SCSI_STATE_FAILED;
+	/*
+	 * Set the serial_number_at_timeout to the current
+	 * serial_number
+	 */
+	scmd->serial_number_at_timeout = scmd->serial_number;
+	list_add_tail(&scmd->eh_entry, &shost->eh_cmd_q);
+	set_bit(SHOST_RECOVERY, &shost->shost_state);
+	shost->host_failed++;
+	scsi_eh_wakeup(shost);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	return 1;
+}
+
+/**
+ * scsi_add_timer - Start timeout timer for a single scsi command.
+ * @scmd:	scsi command that is about to start running.
+ * @timeout:	amount of time to allow this command to run.
+ * @complete:	timeout function to call if timer isn't canceled.
+ *
+ * Notes:
+ *    This should be turned into an inline function.  Each scsi command
+ *    has its own timer, and as it is added to the queue, we set up the
+ *    timer.  When the command completes, we cancel the timer.
+ **/
+void scsi_add_timer(struct scsi_cmnd *scmd, int timeout,
+		    void (*complete)(struct scsi_cmnd *))
+{
+
+	/*
+	 * If the clock was already running for this command, then
+	 * first delete the timer.  The timer handling code gets rather
+	 * confused if we don't do this.
+	 */
+	if (scmd->eh_timeout.function)
+		del_timer(&scmd->eh_timeout);
+
+	scmd->eh_timeout.data = (unsigned long)scmd;
+	scmd->eh_timeout.expires = jiffies + timeout;
+	scmd->eh_timeout.function = (void (*)(unsigned long)) complete;
+
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p, time:"
+					  " %d, (%p)\n", __FUNCTION__,
+					  scmd, timeout, complete));
+
+	add_timer(&scmd->eh_timeout);
+}
+EXPORT_SYMBOL(scsi_add_timer);
+
+/**
+ * scsi_delete_timer - Delete/cancel timer for a given function.
+ * @scmd:	Cmd that we are canceling timer for
+ *
+ * Notes:
+ *     This should be turned into an inline function.
+ *
+ * Return value:
+ *     1 if we were able to detach the timer.  0 if we blew it, and the
+ *     timer function has already started to run.
+ **/
+int scsi_delete_timer(struct scsi_cmnd *scmd)
+{
+	int rtn;
+
+	rtn = del_timer(&scmd->eh_timeout);
+
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: scmd: %p,"
+					 " rtn: %d\n", __FUNCTION__,
+					 scmd, rtn));
+
+	scmd->eh_timeout.data = (unsigned long)NULL;
+	scmd->eh_timeout.function = NULL;
+
+	return rtn;
+}
+EXPORT_SYMBOL(scsi_delete_timer);
+
+/**
+ * scsi_times_out - Timeout function for normal scsi commands.
+ * @scmd:	Cmd that is timing out.
+ *
+ * Notes:
+ *     We do not need to lock this.  There is the potential for a race
+ *     only in that the normal completion handling might run, but if the
+ *     normal completion function determines that the timer has already
+ *     fired, then it mustn't do anything.
+ **/
+void scsi_times_out(struct scsi_cmnd *scmd)
+{
+	scsi_log_completion(scmd, TIMEOUT_ERROR);
+
+	if (scmd->device->host->hostt->eh_timed_out)
+		switch (scmd->device->host->hostt->eh_timed_out(scmd)) {
+		case EH_HANDLED:
+			__scsi_done(scmd);
+			return;
+		case EH_RESET_TIMER:
+			/* This allows a single retry even of a command
+			 * with allowed == 0 */
+			if (scmd->retries++ > scmd->allowed)
+				break;
+			scsi_add_timer(scmd, scmd->timeout_per_command,
+				       scsi_times_out);
+			return;
+		case EH_NOT_HANDLED:
+			break;
+		}
+
+	if (unlikely(!scsi_eh_scmd_add(scmd, SCSI_EH_CANCEL_CMD))) {
+		panic("Error handler thread not present at %p %p %s %d",
+		      scmd, scmd->device->host, __FILE__, __LINE__);
+	}
+}
+
+/**
+ * scsi_block_when_processing_errors - Prevent cmds from being queued.
+ * @sdev:	Device on which we are performing recovery.
+ *
+ * Description:
+ *     We block until the host is out of error recovery, and then check to
+ *     see whether the host or the device is offline.
+ *
+ * Return value:
+ *     0 when dev was taken offline by error recovery. 1 OK to proceed.
+ **/
+int scsi_block_when_processing_errors(struct scsi_device *sdev)
+{
+	int online;
+
+	wait_event(sdev->host->host_wait, (!test_bit(SHOST_RECOVERY, &sdev->host->shost_state)));
+
+	online = scsi_device_online(sdev);
+
+	SCSI_LOG_ERROR_RECOVERY(5, printk("%s: rtn: %d\n", __FUNCTION__,
+					  online));
+
+	return online;
+}
+EXPORT_SYMBOL(scsi_block_when_processing_errors);
+
+#ifdef CONFIG_SCSI_LOGGING
+/**
+ * scsi_eh_prt_fail_stats - Log info on failures.
+ * @shost:	scsi host being recovered.
+ * @work_q:	Queue of scsi cmds to process.
+ **/
+static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
+					  struct list_head *work_q)
+{
+	struct scsi_cmnd *scmd;
+	struct scsi_device *sdev;
+	int total_failures = 0;
+	int cmd_failed = 0;
+	int cmd_cancel = 0;
+	int devices_failed = 0;
+
+	shost_for_each_device(sdev, shost) {
+		list_for_each_entry(scmd, work_q, eh_entry) {
+			if (scmd->device == sdev) {
+				++total_failures;
+				if (scsi_eh_eflags_chk(scmd,
+						       SCSI_EH_CANCEL_CMD))
+					++cmd_cancel;
+				else 
+					++cmd_failed;
+			}
+		}
+
+		if (cmd_cancel || cmd_failed) {
+			SCSI_LOG_ERROR_RECOVERY(3,
+				printk("%s: %d:%d:%d:%d cmds failed: %d,"
+				       " cancel: %d\n",
+				       __FUNCTION__, shost->host_no,
+				       sdev->channel, sdev->id, sdev->lun,
+				       cmd_failed, cmd_cancel));
+			cmd_cancel = 0;
+			cmd_failed = 0;
+			++devices_failed;
+		}
+	}
+
+	SCSI_LOG_ERROR_RECOVERY(2, printk("Total of %d commands on %d"
+					  " devices require eh work\n",
+				  total_failures, devices_failed));
+}
+#endif
+
+/**
+ * scsi_check_sense - Examine scsi cmd sense
+ * @scmd:	Cmd to have sense checked.
+ *
+ * Return value:
+ * 	SUCCESS or FAILED or NEEDS_RETRY
+ *
+ * Notes:
+ *	When a deferred error is detected the current command has
+ *	not been executed and needs retrying.
+ **/
+static int scsi_check_sense(struct scsi_cmnd *scmd)
+{
+	struct scsi_sense_hdr sshdr;
+
+	if (! scsi_command_normalize_sense(scmd, &sshdr))
+		return FAILED;	/* no valid sense data */
+
+	if (scsi_sense_is_deferred(&sshdr))
+		return NEEDS_RETRY;
+
+	/*
+	 * Previous logic looked for FILEMARK, EOM or ILI which are
+	 * mainly associated with tapes and returned SUCCESS.
+	 */
+	if (sshdr.response_code == 0x70) {
+		/* fixed format */
+		if (scmd->sense_buffer[2] & 0xe0)
+			return SUCCESS;
+	} else {
+		/*
+		 * descriptor format: look for "stream commands sense data
+		 * descriptor" (see SSC-3). Assume single sense data
+		 * descriptor. Ignore ILI from SBC-2 READ LONG and WRITE LONG.
+		 */
+		if ((sshdr.additional_length > 3) &&
+		    (scmd->sense_buffer[8] == 0x4) &&
+		    (scmd->sense_buffer[11] & 0xe0))
+			return SUCCESS;
+	}
+
+	switch (sshdr.sense_key) {
+	case NO_SENSE:
+		return SUCCESS;
+	case RECOVERED_ERROR:
+		return /* soft_error */ SUCCESS;
+
+	case ABORTED_COMMAND:
+		return NEEDS_RETRY;
+	case NOT_READY:
+	case UNIT_ATTENTION:
+		/*
+		 * if we are expecting a cc/ua because of a bus reset that we
+		 * performed, treat this just as a retry.  otherwise this is
+		 * information that we should pass up to the upper-level driver
+		 * so that we can deal with it there.
+		 */
+		if (scmd->device->expecting_cc_ua) {
+			scmd->device->expecting_cc_ua = 0;
+			return NEEDS_RETRY;
+		}
+		/*
+		 * if the device is in the process of becoming ready, we 
+		 * should retry.
+		 */
+		if ((sshdr.asc == 0x04) && (sshdr.ascq == 0x01))
+			return NEEDS_RETRY;
+		/*
+		 * if the device is not started, we need to wake
+		 * the error handler to start the motor
+		 */
+		if (scmd->device->allow_restart &&
+		    (sshdr.asc == 0x04) && (sshdr.ascq == 0x02))
+			return FAILED;
+		return SUCCESS;
+
+		/* these three are not supported */
+	case COPY_ABORTED:
+	case VOLUME_OVERFLOW:
+	case MISCOMPARE:
+		return SUCCESS;
+
+	case MEDIUM_ERROR:
+		return NEEDS_RETRY;
+
+	case HARDWARE_ERROR:
+		if (scmd->device->retry_hwerror)
+			return NEEDS_RETRY;
+		else
+			return SUCCESS;
+
+	case ILLEGAL_REQUEST:
+	case BLANK_CHECK:
+	case DATA_PROTECT:
+	default:
+		return SUCCESS;
+	}
+}
+
+/**
+ * scsi_eh_completed_normally - Disposition a eh cmd on return from LLD.
+ * @scmd:	SCSI cmd to examine.
+ *
+ * Notes:
+ *    This is *only* called when we are examining the status of commands
+ *    queued during error recovery.  the main difference here is that we
+ *    don't allow for the possibility of retries here, and we are a lot
+ *    more restrictive about what we consider acceptable.
+ **/
+static int scsi_eh_completed_normally(struct scsi_cmnd *scmd)
+{
+	/*
+	 * first check the host byte, to see if there is anything in there
+	 * that would indicate what we need to do.
+	 */
+	if (host_byte(scmd->result) == DID_RESET) {
+		/*
+		 * rats.  we are already in the error handler, so we now
+		 * get to try and figure out what to do next.  if the sense
+		 * is valid, we have a pretty good idea of what to do.
+		 * if not, we mark it as FAILED.
+		 */
+		return scsi_check_sense(scmd);
+	}
+	if (host_byte(scmd->result) != DID_OK)
+		return FAILED;
+
+	/*
+	 * next, check the message byte.
+	 */
+	if (msg_byte(scmd->result) != COMMAND_COMPLETE)
+		return FAILED;
+
+	/*
+	 * now, check the status byte to see if this indicates
+	 * anything special.
+	 */
+	switch (status_byte(scmd->result)) {
+	case GOOD:
+	case COMMAND_TERMINATED:
+		return SUCCESS;
+	case CHECK_CONDITION:
+		return scsi_check_sense(scmd);
+	case CONDITION_GOOD:
+	case INTERMEDIATE_GOOD:
+	case INTERMEDIATE_C_GOOD:
+		/*
+		 * who knows?  FIXME(eric)
+		 */
+		return SUCCESS;
+	case BUSY:
+	case QUEUE_FULL:
+	case RESERVATION_CONFLICT:
+	default:
+		return FAILED;
+	}
+	return FAILED;
+}
+
+/**
+ * scsi_eh_times_out - timeout function for error handling.
+ * @scmd:	Cmd that is timing out.
+ *
+ * Notes:
+ *    During error handling, the kernel thread will be sleeping waiting
+ *    for some action to complete on the device.  our only job is to
+ *    record that it timed out, and to wake up the thread.
+ **/
+static void scsi_eh_times_out(struct scsi_cmnd *scmd)
+{
+	scsi_eh_eflags_set(scmd, SCSI_EH_REC_TIMEOUT);
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd:%p\n", __FUNCTION__,
+					  scmd));
+
+	if (scmd->device->host->eh_action)
+		up(scmd->device->host->eh_action);
+}
+
+/**
+ * scsi_eh_done - Completion function for error handling.
+ * @scmd:	Cmd that is done.
+ **/
+static void scsi_eh_done(struct scsi_cmnd *scmd)
+{
+	/*
+	 * if the timeout handler is already running, then just set the
+	 * flag which says we finished late, and return.  we have no
+	 * way of stopping the timeout handler from running, so we must
+	 * always defer to it.
+	 */
+	if (del_timer(&scmd->eh_timeout)) {
+		scmd->request->rq_status = RQ_SCSI_DONE;
+		scmd->owner = SCSI_OWNER_ERROR_HANDLER;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s scmd: %p result: %x\n",
+					   __FUNCTION__, scmd, scmd->result));
+
+		if (scmd->device->host->eh_action)
+			up(scmd->device->host->eh_action);
+	}
+}
+
+/**
+ * scsi_send_eh_cmnd  - send a cmd to a device as part of error recovery.
+ * @scmd:	SCSI Cmd to send.
+ * @timeout:	Timeout for cmd.
+ *
+ * Notes:
+ *    The initialization of the structures is quite a bit different in
+ *    this case, and furthermore, there is a different completion handler
+ *    vs scsi_dispatch_cmd.
+ * Return value:
+ *    SUCCESS or FAILED or NEEDS_RETRY
+ **/
+static int scsi_send_eh_cmnd(struct scsi_cmnd *scmd, int timeout)
+{
+	struct Scsi_Host *host = scmd->device->host;
+	DECLARE_MUTEX_LOCKED(sem);
+	unsigned long flags;
+	int rtn = SUCCESS;
+
+	/*
+	 * we will use a queued command if possible, otherwise we will
+	 * emulate the queuing and calling of completion function ourselves.
+	 */
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+
+	if (scmd->device->scsi_level <= SCSI_2)
+		scmd->cmnd[1] = (scmd->cmnd[1] & 0x1f) |
+			(scmd->device->lun << 5 & 0xe0);
+
+	scsi_add_timer(scmd, timeout, scsi_eh_times_out);
+
+	/*
+	 * set up the semaphore so we wait for the command to complete.
+	 */
+	scmd->device->host->eh_action = &sem;
+	scmd->request->rq_status = RQ_SCSI_BUSY;
+
+	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	scsi_log_send(scmd);
+	host->hostt->queuecommand(scmd, scsi_eh_done);
+	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+
+	down(&sem);
+	scsi_log_completion(scmd, SUCCESS);
+
+	scmd->device->host->eh_action = NULL;
+
+	/*
+	 * see if timeout.  if so, tell the host to forget about it.
+	 * in other words, we don't want a callback any more.
+	 */
+	if (scsi_eh_eflags_chk(scmd, SCSI_EH_REC_TIMEOUT)) {
+		scsi_eh_eflags_clr(scmd,  SCSI_EH_REC_TIMEOUT);
+		scmd->owner = SCSI_OWNER_LOWLEVEL;
+
+		/*
+		 * as far as the low level driver is
+		 * concerned, this command is still active, so
+		 * we must give the low level driver a chance
+		 * to abort it. (db) 
+		 *
+		 * FIXME(eric) - we are not tracking whether we could
+		 * abort a timed out command or not.  not sure how
+		 * we should treat them differently anyways.
+		 */
+		spin_lock_irqsave(scmd->device->host->host_lock, flags);
+		if (scmd->device->host->hostt->eh_abort_handler)
+			scmd->device->host->hostt->eh_abort_handler(scmd);
+		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+			
+		scmd->request->rq_status = RQ_SCSI_DONE;
+		scmd->owner = SCSI_OWNER_ERROR_HANDLER;
+			
+		rtn = FAILED;
+	}
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd: %p, rtn:%x\n",
+					  __FUNCTION__, scmd, rtn));
+
+	/*
+	 * now examine the actual status codes to see whether the command
+	 * actually did complete normally.
+	 */
+	if (rtn == SUCCESS) {
+		rtn = scsi_eh_completed_normally(scmd);
+		SCSI_LOG_ERROR_RECOVERY(3,
+			printk("%s: scsi_eh_completed_normally %x\n",
+			       __FUNCTION__, rtn));
+		switch (rtn) {
+		case SUCCESS:
+		case NEEDS_RETRY:
+		case FAILED:
+			break;
+		default:
+			rtn = FAILED;
+			break;
+		}
+	}
+
+	return rtn;
+}
+
+/**
+ * scsi_request_sense - Request sense data from a particular target.
+ * @scmd:	SCSI cmd for request sense.
+ *
+ * Notes:
+ *    Some hosts automatically obtain this information, others require
+ *    that we obtain it on our own. This function will *not* return until
+ *    the command either times out, or it completes.
+ **/
+static int scsi_request_sense(struct scsi_cmnd *scmd)
+{
+	static unsigned char generic_sense[6] =
+	{REQUEST_SENSE, 0, 0, 0, 252, 0};
+	unsigned char *scsi_result;
+	int saved_result;
+	int rtn;
+
+	memcpy(scmd->cmnd, generic_sense, sizeof(generic_sense));
+
+	scsi_result = kmalloc(252, GFP_ATOMIC | (scmd->device->host->hostt->unchecked_isa_dma) ? __GFP_DMA : 0);
+
+
+	if (unlikely(!scsi_result)) {
+		printk(KERN_ERR "%s: cannot allocate scsi_result.\n",
+		       __FUNCTION__);
+		return FAILED;
+	}
+
+	/*
+	 * zero the sense buffer.  some host adapters automatically always
+	 * request sense, so it is not a good idea that
+	 * scmd->request_buffer and scmd->sense_buffer point to the same
+	 * address (db).  0 is not a valid sense code. 
+	 */
+	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+	memset(scsi_result, 0, 252);
+
+	saved_result = scmd->result;
+	scmd->request_buffer = scsi_result;
+	scmd->request_bufflen = 252;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->sc_data_direction = DMA_FROM_DEVICE;
+	scmd->underflow = 0;
+
+	rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
+
+	/* last chance to have valid sense data */
+	if(!SCSI_SENSE_VALID(scmd)) {
+		memcpy(scmd->sense_buffer, scmd->request_buffer,
+		       sizeof(scmd->sense_buffer));
+	}
+
+	kfree(scsi_result);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	scsi_setup_cmd_retry(scmd);
+	scmd->result = saved_result;
+	return rtn;
+}
+
+/**
+ * scsi_eh_finish_cmd - Handle a cmd that eh is finished with.
+ * @scmd:	Original SCSI cmd that eh has finished.
+ * @done_q:	Queue for processed commands.
+ *
+ * Notes:
+ *    We don't want to use the normal command completion while we are are
+ *    still handling errors - it may cause other commands to be queued,
+ *    and that would disturb what we are doing.  thus we really want to
+ *    keep a list of pending commands for final completion, and once we
+ *    are ready to leave error handling we handle completion for real.
+ **/
+static void scsi_eh_finish_cmd(struct scsi_cmnd *scmd,
+			       struct list_head *done_q)
+{
+	scmd->device->host->host_failed--;
+	scmd->state = SCSI_STATE_BHQUEUE;
+
+	scsi_eh_eflags_clr_all(scmd);
+
+	/*
+	 * set this back so that the upper level can correctly free up
+	 * things.
+	 */
+	scsi_setup_cmd_retry(scmd);
+	list_move_tail(&scmd->eh_entry, done_q);
+}
+
+/**
+ * scsi_eh_get_sense - Get device sense data.
+ * @work_q:	Queue of commands to process.
+ * @done_q:	Queue of proccessed commands..
+ *
+ * Description:
+ *    See if we need to request sense information.  if so, then get it
+ *    now, so we have a better idea of what to do.  
+ *
+ * Notes:
+ *    This has the unfortunate side effect that if a shost adapter does
+ *    not automatically request sense information, that we end up shutting
+ *    it down before we request it.
+ *
+ *    All drivers should request sense information internally these days,
+ *    so for now all I have to say is tough noogies if you end up in here.
+ *
+ *    XXX: Long term this code should go away, but that needs an audit of
+ *         all LLDDs first.
+ **/
+static int scsi_eh_get_sense(struct list_head *work_q,
+			     struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+	int rtn;
+
+	list_for_each_safe(lh, lh_sf, work_q) {
+		scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+		if (scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD) ||
+		    SCSI_SENSE_VALID(scmd))
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(2, printk("%s: requesting sense"
+						  " for id: %d\n",
+						  current->comm,
+						  scmd->device->id));
+		rtn = scsi_request_sense(scmd);
+		if (rtn != SUCCESS)
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("sense requested for %p"
+						  " result %x\n", scmd,
+						  scmd->result));
+		SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense("bh", scmd));
+
+		rtn = scsi_decide_disposition(scmd);
+
+		/*
+		 * if the result was normal, then just pass it along to the
+		 * upper level.
+		 */
+		if (rtn == SUCCESS)
+			/* we don't want this command reissued, just
+			 * finished with the sense data, so set
+			 * retries to the max allowed to ensure it
+			 * won't get reissued */
+			scmd->retries = scmd->allowed;
+		else if (rtn != NEEDS_RETRY)
+			continue;
+
+		scsi_eh_finish_cmd(scmd, done_q);
+	}
+
+	return list_empty(work_q);
+}
+
+/**
+ * scsi_try_to_abort_cmd - Ask host to abort a running command.
+ * @scmd:	SCSI cmd to abort from Lower Level.
+ *
+ * Notes:
+ *    This function will not return until the user's completion function
+ *    has been called.  there is no timeout on this operation.  if the
+ *    author of the low-level driver wishes this operation to be timed,
+ *    they can provide this facility themselves.  helper functions in
+ *    scsi_error.c can be supplied to make this easier to do.
+ **/
+static int scsi_try_to_abort_cmd(struct scsi_cmnd *scmd)
+{
+	unsigned long flags;
+	int rtn = FAILED;
+
+	if (!scmd->device->host->hostt->eh_abort_handler)
+		return rtn;
+
+	/*
+	 * scsi_done was called just after the command timed out and before
+	 * we had a chance to process it. (db)
+	 */
+	if (scmd->serial_number == 0)
+		return SUCCESS;
+
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+
+	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	rtn = scmd->device->host->hostt->eh_abort_handler(scmd);
+	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+
+	return rtn;
+}
+
+/**
+ * scsi_eh_tur - Send TUR to device.
+ * @scmd:	Scsi cmd to send TUR
+ *
+ * Return value:
+ *    0 - Device is ready. 1 - Device NOT ready.
+ **/
+static int scsi_eh_tur(struct scsi_cmnd *scmd)
+{
+	static unsigned char tur_command[6] = {TEST_UNIT_READY, 0, 0, 0, 0, 0};
+	int retry_cnt = 1, rtn;
+
+retry_tur:
+	memcpy(scmd->cmnd, tur_command, sizeof(tur_command));
+
+	/*
+	 * zero the sense buffer.  the scsi spec mandates that any
+	 * untransferred sense data should be interpreted as being zero.
+	 */
+	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
+	scmd->request_buffer = NULL;
+	scmd->request_bufflen = 0;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->underflow = 0;
+	scmd->sc_data_direction = DMA_NONE;
+
+	rtn = scsi_send_eh_cmnd(scmd, SENSE_TIMEOUT);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	scsi_setup_cmd_retry(scmd);
+
+	/*
+	 * hey, we are done.  let's look to see what happened.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
+		__FUNCTION__, scmd, rtn));
+	if (rtn == SUCCESS)
+		return 0;
+	else if (rtn == NEEDS_RETRY)
+		if (retry_cnt--)
+			goto retry_tur;
+	return 1;
+}
+
+/**
+ * scsi_eh_abort_cmds - abort canceled commands.
+ * @shost:	scsi host being recovered.
+ * @eh_done_q:	list_head for processed commands.
+ *
+ * Decription:
+ *    Try and see whether or not it makes sense to try and abort the
+ *    running command.  this only works out to be the case if we have one
+ *    command that has timed out.  if the command simply failed, it makes
+ *    no sense to try and abort the command, since as far as the shost
+ *    adapter is concerned, it isn't running.
+ **/
+static int scsi_eh_abort_cmds(struct list_head *work_q,
+			      struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+	int rtn;
+
+	list_for_each_safe(lh, lh_sf, work_q) {
+		scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+		if (!scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD))
+			continue;
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting cmd:"
+						  "0x%p\n", current->comm,
+						  scmd));
+		rtn = scsi_try_to_abort_cmd(scmd);
+		if (rtn == SUCCESS) {
+			scsi_eh_eflags_clr(scmd,  SCSI_EH_CANCEL_CMD);
+			if (!scsi_device_online(scmd->device) ||
+			    !scsi_eh_tur(scmd)) {
+				scsi_eh_finish_cmd(scmd, done_q);
+			}
+				
+		} else
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: aborting"
+							  " cmd failed:"
+							  "0x%p\n",
+							  current->comm,
+							  scmd));
+	}
+
+	return list_empty(work_q);
+}
+
+/**
+ * scsi_try_bus_device_reset - Ask host to perform a BDR on a dev
+ * @scmd:	SCSI cmd used to send BDR	
+ *
+ * Notes:
+ *    There is no timeout for this operation.  if this operation is
+ *    unreliable for a given host, then the host itself needs to put a
+ *    timer on it, and set the host back to a consistent state prior to
+ *    returning.
+ **/
+static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
+{
+	unsigned long flags;
+	int rtn = FAILED;
+
+	if (!scmd->device->host->hostt->eh_device_reset_handler)
+		return rtn;
+
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+
+	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	rtn = scmd->device->host->hostt->eh_device_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+
+	if (rtn == SUCCESS) {
+		scmd->device->was_reset = 1;
+		scmd->device->expecting_cc_ua = 1;
+	}
+
+	return rtn;
+}
+
+/**
+ * scsi_eh_try_stu - Send START_UNIT to device.
+ * @scmd:	Scsi cmd to send START_UNIT
+ *
+ * Return value:
+ *    0 - Device is ready. 1 - Device NOT ready.
+ **/
+static int scsi_eh_try_stu(struct scsi_cmnd *scmd)
+{
+	static unsigned char stu_command[6] = {START_STOP, 0, 0, 0, 1, 0};
+	int rtn;
+
+	if (!scmd->device->allow_restart)
+		return 1;
+
+	memcpy(scmd->cmnd, stu_command, sizeof(stu_command));
+
+	/*
+	 * zero the sense buffer.  the scsi spec mandates that any
+	 * untransferred sense data should be interpreted as being zero.
+	 */
+	memset(scmd->sense_buffer, 0, sizeof(scmd->sense_buffer));
+
+	scmd->request_buffer = NULL;
+	scmd->request_bufflen = 0;
+	scmd->use_sg = 0;
+	scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]);
+	scmd->underflow = 0;
+	scmd->sc_data_direction = DMA_NONE;
+
+	rtn = scsi_send_eh_cmnd(scmd, START_UNIT_TIMEOUT);
+
+	/*
+	 * when we eventually call scsi_finish, we really wish to complete
+	 * the original request, so let's restore the original data. (db)
+	 */
+	scsi_setup_cmd_retry(scmd);
+
+	/*
+	 * hey, we are done.  let's look to see what happened.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: scmd %p rtn %x\n",
+		__FUNCTION__, scmd, rtn));
+	if (rtn == SUCCESS)
+		return 0;
+	return 1;
+}
+
+ /**
+ * scsi_eh_stu - send START_UNIT if needed
+ * @shost:	scsi host being recovered.
+ * @eh_done_q:	list_head for processed commands.
+ *
+ * Notes:
+ *    If commands are failing due to not ready, initializing command required,
+ *	try revalidating the device, which will end up sending a start unit. 
+ **/
+static int scsi_eh_stu(struct Scsi_Host *shost,
+			      struct list_head *work_q,
+			      struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd, *stu_scmd;
+	struct scsi_device *sdev;
+
+	shost_for_each_device(sdev, shost) {
+		stu_scmd = NULL;
+		list_for_each_entry(scmd, work_q, eh_entry)
+			if (scmd->device == sdev && SCSI_SENSE_VALID(scmd) &&
+			    scsi_check_sense(scmd) == FAILED ) {
+				stu_scmd = scmd;
+				break;
+			}
+
+		if (!stu_scmd)
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending START_UNIT to sdev:"
+						  " 0x%p\n", current->comm, sdev));
+
+		if (!scsi_eh_try_stu(stu_scmd)) {
+			if (!scsi_device_online(sdev) ||
+			    !scsi_eh_tur(stu_scmd)) {
+				list_for_each_safe(lh, lh_sf, work_q) {
+					scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+					if (scmd->device == sdev)
+						scsi_eh_finish_cmd(scmd, done_q);
+				}
+			}
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3,
+						printk("%s: START_UNIT failed to sdev:"
+						       " 0x%p\n", current->comm, sdev));
+		}
+	}
+
+	return list_empty(work_q);
+}
+
+
+/**
+ * scsi_eh_bus_device_reset - send bdr if needed
+ * @shost:	scsi host being recovered.
+ * @eh_done_q:	list_head for processed commands.
+ *
+ * Notes:
+ *    Try a bus device reset.  still, look to see whether we have multiple
+ *    devices that are jammed or not - if we have multiple devices, it
+ *    makes no sense to try bus_device_reset - we really would need to try
+ *    a bus_reset instead. 
+ **/
+static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
+				    struct list_head *work_q,
+				    struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd, *bdr_scmd;
+	struct scsi_device *sdev;
+	int rtn;
+
+	shost_for_each_device(sdev, shost) {
+		bdr_scmd = NULL;
+		list_for_each_entry(scmd, work_q, eh_entry)
+			if (scmd->device == sdev) {
+				bdr_scmd = scmd;
+				break;
+			}
+
+		if (!bdr_scmd)
+			continue;
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BDR sdev:"
+						  " 0x%p\n", current->comm,
+						  sdev));
+		rtn = scsi_try_bus_device_reset(bdr_scmd);
+		if (rtn == SUCCESS) {
+			if (!scsi_device_online(sdev) ||
+			    !scsi_eh_tur(bdr_scmd)) {
+				list_for_each_safe(lh, lh_sf,
+						   work_q) {
+					scmd = list_entry(lh, struct
+							  scsi_cmnd,
+							  eh_entry);
+					if (scmd->device == sdev)
+						scsi_eh_finish_cmd(scmd,
+								   done_q);
+				}
+			}
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BDR"
+							  " failed sdev:"
+							  "0x%p\n",
+							  current->comm,
+							   sdev));
+		}
+	}
+
+	return list_empty(work_q);
+}
+
+/**
+ * scsi_try_bus_reset - ask host to perform a bus reset
+ * @scmd:	SCSI cmd to send bus reset.
+ **/
+static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
+{
+	unsigned long flags;
+	int rtn;
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Bus RST\n",
+					  __FUNCTION__));
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->serial_number_at_timeout = scmd->serial_number;
+
+	if (!scmd->device->host->hostt->eh_bus_reset_handler)
+		return FAILED;
+
+	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	rtn = scmd->device->host->hostt->eh_bus_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+
+	if (rtn == SUCCESS) {
+		if (!scmd->device->host->hostt->skip_settle_delay)
+			ssleep(BUS_RESET_SETTLE_TIME);
+		spin_lock_irqsave(scmd->device->host->host_lock, flags);
+		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
+		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+	}
+
+	return rtn;
+}
+
+/**
+ * scsi_try_host_reset - ask host adapter to reset itself
+ * @scmd:	SCSI cmd to send hsot reset.
+ **/
+static int scsi_try_host_reset(struct scsi_cmnd *scmd)
+{
+	unsigned long flags;
+	int rtn;
+
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Snd Host RST\n",
+					  __FUNCTION__));
+	scmd->owner = SCSI_OWNER_LOWLEVEL;
+	scmd->serial_number_at_timeout = scmd->serial_number;
+
+	if (!scmd->device->host->hostt->eh_host_reset_handler)
+		return FAILED;
+
+	spin_lock_irqsave(scmd->device->host->host_lock, flags);
+	rtn = scmd->device->host->hostt->eh_host_reset_handler(scmd);
+	spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+
+	if (rtn == SUCCESS) {
+		if (!scmd->device->host->hostt->skip_settle_delay)
+			ssleep(HOST_RESET_SETTLE_TIME);
+		spin_lock_irqsave(scmd->device->host->host_lock, flags);
+		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
+		spin_unlock_irqrestore(scmd->device->host->host_lock, flags);
+	}
+
+	return rtn;
+}
+
+/**
+ * scsi_eh_bus_reset - send a bus reset 
+ * @shost:	scsi host being recovered.
+ * @eh_done_q:	list_head for processed commands.
+ **/
+static int scsi_eh_bus_reset(struct Scsi_Host *shost,
+			     struct list_head *work_q,
+			     struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+	struct scsi_cmnd *chan_scmd;
+	unsigned int channel;
+	int rtn;
+
+	/*
+	 * we really want to loop over the various channels, and do this on
+	 * a channel by channel basis.  we should also check to see if any
+	 * of the failed commands are on soft_reset devices, and if so, skip
+	 * the reset.  
+	 */
+
+	for (channel = 0; channel <= shost->max_channel; channel++) {
+		chan_scmd = NULL;
+		list_for_each_entry(scmd, work_q, eh_entry) {
+			if (channel == scmd->device->channel) {
+				chan_scmd = scmd;
+				break;
+				/*
+				 * FIXME add back in some support for
+				 * soft_reset devices.
+				 */
+			}
+		}
+
+		if (!chan_scmd)
+			continue;
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending BRST chan:"
+						  " %d\n", current->comm,
+						  channel));
+		rtn = scsi_try_bus_reset(chan_scmd);
+		if (rtn == SUCCESS) {
+			list_for_each_safe(lh, lh_sf, work_q) {
+				scmd = list_entry(lh, struct scsi_cmnd,
+						  eh_entry);
+				if (channel == scmd->device->channel)
+					if (!scsi_device_online(scmd->device) ||
+					    !scsi_eh_tur(scmd))
+						scsi_eh_finish_cmd(scmd,
+								   done_q);
+			}
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: BRST"
+							  " failed chan: %d\n",
+							  current->comm,
+							  channel));
+		}
+	}
+	return list_empty(work_q);
+}
+
+/**
+ * scsi_eh_host_reset - send a host reset 
+ * @work_q:	list_head for processed commands.
+ * @done_q:	list_head for processed commands.
+ **/
+static int scsi_eh_host_reset(struct list_head *work_q,
+			      struct list_head *done_q)
+{
+	int rtn;
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+
+	if (!list_empty(work_q)) {
+		scmd = list_entry(work_q->next,
+				  struct scsi_cmnd, eh_entry);
+
+		SCSI_LOG_ERROR_RECOVERY(3, printk("%s: Sending HRST\n"
+						  , current->comm));
+
+		rtn = scsi_try_host_reset(scmd);
+		if (rtn == SUCCESS) {
+			list_for_each_safe(lh, lh_sf, work_q) {
+				scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+				if (!scsi_device_online(scmd->device) ||
+				    (!scsi_eh_try_stu(scmd) && !scsi_eh_tur(scmd)) ||
+				    !scsi_eh_tur(scmd))
+					scsi_eh_finish_cmd(scmd, done_q);
+			}
+		} else {
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: HRST"
+							  " failed\n",
+							  current->comm));
+		}
+	}
+	return list_empty(work_q);
+}
+
+/**
+ * scsi_eh_offline_sdevs - offline scsi devices that fail to recover
+ * @work_q:	list_head for processed commands.
+ * @done_q:	list_head for processed commands.
+ *
+ **/
+static void scsi_eh_offline_sdevs(struct list_head *work_q,
+				  struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+
+	list_for_each_safe(lh, lh_sf, work_q) {
+		scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+		printk(KERN_INFO "scsi: Device offlined - not"
+		       		" ready after error recovery: host"
+				" %d channel %d id %d lun %d\n",
+				scmd->device->host->host_no,
+				scmd->device->channel,
+				scmd->device->id,
+				scmd->device->lun);
+		scsi_device_set_state(scmd->device, SDEV_OFFLINE);
+		if (scsi_eh_eflags_chk(scmd, SCSI_EH_CANCEL_CMD)) {
+			/*
+			 * FIXME: Handle lost cmds.
+			 */
+		}
+		scsi_eh_finish_cmd(scmd, done_q);
+	}
+	return;
+}
+
+/**
+ * scsi_decide_disposition - Disposition a cmd on return from LLD.
+ * @scmd:	SCSI cmd to examine.
+ *
+ * Notes:
+ *    This is *only* called when we are examining the status after sending
+ *    out the actual data command.  any commands that are queued for error
+ *    recovery (e.g. test_unit_ready) do *not* come through here.
+ *
+ *    When this routine returns failed, it means the error handler thread
+ *    is woken.  In cases where the error code indicates an error that
+ *    doesn't require the error handler read (i.e. we don't need to
+ *    abort/reset), this function should return SUCCESS.
+ **/
+int scsi_decide_disposition(struct scsi_cmnd *scmd)
+{
+	int rtn;
+
+	/*
+	 * if the device is offline, then we clearly just pass the result back
+	 * up to the top level.
+	 */
+	if (!scsi_device_online(scmd->device)) {
+		SCSI_LOG_ERROR_RECOVERY(5, printk("%s: device offline - report"
+						  " as SUCCESS\n",
+						  __FUNCTION__));
+		return SUCCESS;
+	}
+
+	/*
+	 * first check the host byte, to see if there is anything in there
+	 * that would indicate what we need to do.
+	 */
+	switch (host_byte(scmd->result)) {
+	case DID_PASSTHROUGH:
+		/*
+		 * no matter what, pass this through to the upper layer.
+		 * nuke this special code so that it looks like we are saying
+		 * did_ok.
+		 */
+		scmd->result &= 0xff00ffff;
+		return SUCCESS;
+	case DID_OK:
+		/*
+		 * looks good.  drop through, and check the next byte.
+		 */
+		break;
+	case DID_NO_CONNECT:
+	case DID_BAD_TARGET:
+	case DID_ABORT:
+		/*
+		 * note - this means that we just report the status back
+		 * to the top level driver, not that we actually think
+		 * that it indicates SUCCESS.
+		 */
+		return SUCCESS;
+		/*
+		 * when the low level driver returns did_soft_error,
+		 * it is responsible for keeping an internal retry counter 
+		 * in order to avoid endless loops (db)
+		 *
+		 * actually this is a bug in this function here.  we should
+		 * be mindful of the maximum number of retries specified
+		 * and not get stuck in a loop.
+		 */
+	case DID_SOFT_ERROR:
+		goto maybe_retry;
+	case DID_IMM_RETRY:
+		return NEEDS_RETRY;
+
+	case DID_ERROR:
+		if (msg_byte(scmd->result) == COMMAND_COMPLETE &&
+		    status_byte(scmd->result) == RESERVATION_CONFLICT)
+			/*
+			 * execute reservation conflict processing code
+			 * lower down
+			 */
+			break;
+		/* fallthrough */
+
+	case DID_BUS_BUSY:
+	case DID_PARITY:
+		goto maybe_retry;
+	case DID_TIME_OUT:
+		/*
+		 * when we scan the bus, we get timeout messages for
+		 * these commands if there is no device available.
+		 * other hosts report did_no_connect for the same thing.
+		 */
+		if ((scmd->cmnd[0] == TEST_UNIT_READY ||
+		     scmd->cmnd[0] == INQUIRY)) {
+			return SUCCESS;
+		} else {
+			return FAILED;
+		}
+	case DID_RESET:
+		return SUCCESS;
+	default:
+		return FAILED;
+	}
+
+	/*
+	 * next, check the message byte.
+	 */
+	if (msg_byte(scmd->result) != COMMAND_COMPLETE)
+		return FAILED;
+
+	/*
+	 * check the status byte to see if this indicates anything special.
+	 */
+	switch (status_byte(scmd->result)) {
+	case QUEUE_FULL:
+		/*
+		 * the case of trying to send too many commands to a
+		 * tagged queueing device.
+		 */
+	case BUSY:
+		/*
+		 * device can't talk to us at the moment.  Should only
+		 * occur (SAM-3) when the task queue is empty, so will cause
+		 * the empty queue handling to trigger a stall in the
+		 * device.
+		 */
+		return ADD_TO_MLQUEUE;
+	case GOOD:
+	case COMMAND_TERMINATED:
+	case TASK_ABORTED:
+		return SUCCESS;
+	case CHECK_CONDITION:
+		rtn = scsi_check_sense(scmd);
+		if (rtn == NEEDS_RETRY)
+			goto maybe_retry;
+		/* if rtn == FAILED, we have no sense information;
+		 * returning FAILED will wake the error handler thread
+		 * to collect the sense and redo the decide
+		 * disposition */
+		return rtn;
+	case CONDITION_GOOD:
+	case INTERMEDIATE_GOOD:
+	case INTERMEDIATE_C_GOOD:
+	case ACA_ACTIVE:
+		/*
+		 * who knows?  FIXME(eric)
+		 */
+		return SUCCESS;
+
+	case RESERVATION_CONFLICT:
+		printk(KERN_INFO "scsi: reservation conflict: host"
+                                " %d channel %d id %d lun %d\n",
+		       scmd->device->host->host_no, scmd->device->channel,
+		       scmd->device->id, scmd->device->lun);
+		return SUCCESS; /* causes immediate i/o error */
+	default:
+		return FAILED;
+	}
+	return FAILED;
+
+      maybe_retry:
+
+	/* we requeue for retry because the error was retryable, and
+	 * the request was not marked fast fail.  Note that above,
+	 * even if the request is marked fast fail, we still requeue
+	 * for queue congestion conditions (QUEUE_FULL or BUSY) */
+	if ((++scmd->retries) < scmd->allowed 
+	    && !blk_noretry_request(scmd->request)) {
+		return NEEDS_RETRY;
+	} else {
+		/*
+		 * no more retries - report this one back to upper level.
+		 */
+		return SUCCESS;
+	}
+}
+
+/**
+ * scsi_eh_lock_done - done function for eh door lock request
+ * @scmd:	SCSI command block for the door lock request
+ *
+ * Notes:
+ * 	We completed the asynchronous door lock request, and it has either
+ * 	locked the door or failed.  We must free the command structures
+ * 	associated with this request.
+ **/
+static void scsi_eh_lock_done(struct scsi_cmnd *scmd)
+{
+	struct scsi_request *sreq = scmd->sc_request;
+
+	scsi_release_request(sreq);
+}
+
+
+/**
+ * scsi_eh_lock_door - Prevent medium removal for the specified device
+ * @sdev:	SCSI device to prevent medium removal
+ *
+ * Locking:
+ * 	We must be called from process context; scsi_allocate_request()
+ * 	may sleep.
+ *
+ * Notes:
+ * 	We queue up an asynchronous "ALLOW MEDIUM REMOVAL" request on the
+ * 	head of the devices request queue, and continue.
+ *
+ * Bugs:
+ * 	scsi_allocate_request() may sleep waiting for existing requests to
+ * 	be processed.  However, since we haven't kicked off any request
+ * 	processing for this host, this may deadlock.
+ *
+ *	If scsi_allocate_request() fails for what ever reason, we
+ *	completely forget to lock the door.
+ **/
+static void scsi_eh_lock_door(struct scsi_device *sdev)
+{
+	struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+
+	if (unlikely(!sreq)) {
+		printk(KERN_ERR "%s: request allocate failed,"
+		       "prevent media removal cmd not sent\n", __FUNCTION__);
+		return;
+	}
+
+	sreq->sr_cmnd[0] = ALLOW_MEDIUM_REMOVAL;
+	sreq->sr_cmnd[1] = 0;
+	sreq->sr_cmnd[2] = 0;
+	sreq->sr_cmnd[3] = 0;
+	sreq->sr_cmnd[4] = SCSI_REMOVAL_PREVENT;
+	sreq->sr_cmnd[5] = 0;
+	sreq->sr_data_direction = DMA_NONE;
+	sreq->sr_bufflen = 0;
+	sreq->sr_buffer = NULL;
+	sreq->sr_allowed = 5;
+	sreq->sr_done = scsi_eh_lock_done;
+	sreq->sr_timeout_per_command = 10 * HZ;
+	sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+	scsi_insert_special_req(sreq, 1);
+}
+
+
+/**
+ * scsi_restart_operations - restart io operations to the specified host.
+ * @shost:	Host we are restarting.
+ *
+ * Notes:
+ *    When we entered the error handler, we blocked all further i/o to
+ *    this device.  we need to 'reverse' this process.
+ **/
+static void scsi_restart_operations(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+
+	/*
+	 * If the door was locked, we need to insert a door lock request
+	 * onto the head of the SCSI request queue for the device.  There
+	 * is no point trying to lock the door of an off-line device.
+	 */
+	shost_for_each_device(sdev, shost) {
+		if (scsi_device_online(sdev) && sdev->locked)
+			scsi_eh_lock_door(sdev);
+	}
+
+	/*
+	 * next free up anything directly waiting upon the host.  this
+	 * will be requests for character device operations, and also for
+	 * ioctls to queued block devices.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("%s: waking up host to restart\n",
+					  __FUNCTION__));
+
+	clear_bit(SHOST_RECOVERY, &shost->shost_state);
+
+	wake_up(&shost->host_wait);
+
+	/*
+	 * finally we need to re-initiate requests that may be pending.  we will
+	 * have had everything blocked while error handling is taking place, and
+	 * now that error recovery is done, we will need to ensure that these
+	 * requests are started.
+	 */
+	scsi_run_host_queues(shost);
+}
+
+/**
+ * scsi_eh_ready_devs - check device ready state and recover if not.
+ * @shost: 	host to be recovered.
+ * @eh_done_q:	list_head for processed commands.
+ *
+ **/
+static void scsi_eh_ready_devs(struct Scsi_Host *shost,
+			       struct list_head *work_q,
+			       struct list_head *done_q)
+{
+	if (!scsi_eh_stu(shost, work_q, done_q))
+		if (!scsi_eh_bus_device_reset(shost, work_q, done_q))
+			if (!scsi_eh_bus_reset(shost, work_q, done_q))
+				if (!scsi_eh_host_reset(work_q, done_q))
+					scsi_eh_offline_sdevs(work_q, done_q);
+}
+
+/**
+ * scsi_eh_flush_done_q - finish processed commands or retry them.
+ * @done_q:	list_head of processed commands.
+ *
+ **/
+static void scsi_eh_flush_done_q(struct list_head *done_q)
+{
+	struct list_head *lh, *lh_sf;
+	struct scsi_cmnd *scmd;
+
+	list_for_each_safe(lh, lh_sf, done_q) {
+		scmd = list_entry(lh, struct scsi_cmnd, eh_entry);
+		list_del_init(lh);
+		if (scsi_device_online(scmd->device) &&
+		    !blk_noretry_request(scmd->request) &&
+		    (++scmd->retries < scmd->allowed)) {
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush"
+							  " retry cmd: %p\n",
+							  current->comm,
+							  scmd));
+				scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
+		} else {
+			if (!scmd->result)
+				scmd->result |= (DRIVER_TIMEOUT << 24);
+			SCSI_LOG_ERROR_RECOVERY(3, printk("%s: flush finish"
+							" cmd: %p\n",
+							current->comm, scmd));
+			scsi_finish_command(scmd);
+		}
+	}
+}
+
+/**
+ * scsi_unjam_host - Attempt to fix a host which has a cmd that failed.
+ * @shost:	Host to unjam.
+ *
+ * Notes:
+ *    When we come in here, we *know* that all commands on the bus have
+ *    either completed, failed or timed out.  we also know that no further
+ *    commands are being sent to the host, so things are relatively quiet
+ *    and we have freedom to fiddle with things as we wish.
+ *
+ *    This is only the *default* implementation.  it is possible for
+ *    individual drivers to supply their own version of this function, and
+ *    if the maintainer wishes to do this, it is strongly suggested that
+ *    this function be taken as a template and modified.  this function
+ *    was designed to correctly handle problems for about 95% of the
+ *    different cases out there, and it should always provide at least a
+ *    reasonable amount of error recovery.
+ *
+ *    Any command marked 'failed' or 'timeout' must eventually have
+ *    scsi_finish_cmd() called for it.  we do all of the retry stuff
+ *    here, so when we restart the host after we return it should have an
+ *    empty queue.
+ **/
+static void scsi_unjam_host(struct Scsi_Host *shost)
+{
+	unsigned long flags;
+	LIST_HEAD(eh_work_q);
+	LIST_HEAD(eh_done_q);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_splice_init(&shost->eh_cmd_q, &eh_work_q);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	SCSI_LOG_ERROR_RECOVERY(1, scsi_eh_prt_fail_stats(shost, &eh_work_q));
+
+	if (!scsi_eh_get_sense(&eh_work_q, &eh_done_q))
+		if (!scsi_eh_abort_cmds(&eh_work_q, &eh_done_q))
+			scsi_eh_ready_devs(shost, &eh_work_q, &eh_done_q);
+
+	scsi_eh_flush_done_q(&eh_done_q);
+}
+
+/**
+ * scsi_error_handler - Handle errors/timeouts of SCSI cmds.
+ * @data:	Host for which we are running.
+ *
+ * Notes:
+ *    This is always run in the context of a kernel thread.  The idea is
+ *    that we start this thing up when the kernel starts up (one per host
+ *    that we detect), and it immediately goes to sleep and waits for some
+ *    event (i.e. failure).  When this takes place, we have the job of
+ *    trying to unjam the bus and restarting things.
+ **/
+int scsi_error_handler(void *data)
+{
+	struct Scsi_Host *shost = (struct Scsi_Host *) data;
+	int rtn;
+	DECLARE_MUTEX_LOCKED(sem);
+
+	/*
+	 *    Flush resources
+	 */
+
+	daemonize("scsi_eh_%d", shost->host_no);
+
+	current->flags |= PF_NOFREEZE;
+
+	shost->eh_wait = &sem;
+	shost->ehandler = current;
+
+	/*
+	 * Wake up the thread that created us.
+	 */
+	SCSI_LOG_ERROR_RECOVERY(3, printk("Wake up parent of"
+					  " scsi_eh_%d\n",shost->host_no));
+
+	complete(shost->eh_notify);
+
+	while (1) {
+		/*
+		 * If we get a signal, it means we are supposed to go
+		 * away and die.  This typically happens if the user is
+		 * trying to unload a module.
+		 */
+		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
+						  " scsi_eh_%d"
+						  " sleeping\n",shost->host_no));
+
+		/*
+		 * Note - we always use down_interruptible with the semaphore
+		 * even if the module was loaded as part of the kernel.  The
+		 * reason is that down() will cause this thread to be counted
+		 * in the load average as a running process, and down
+		 * interruptible doesn't.  Given that we need to allow this
+		 * thread to die if the driver was loaded as a module, using
+		 * semaphores isn't unreasonable.
+		 */
+		down_interruptible(&sem);
+		if (shost->eh_kill)
+			break;
+
+		SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler"
+						  " scsi_eh_%d waking"
+						  " up\n",shost->host_no));
+
+		shost->eh_active = 1;
+
+		/*
+		 * We have a host that is failing for some reason.  Figure out
+		 * what we need to do to get it up and online again (if we can).
+		 * If we fail, we end up taking the thing offline.
+		 */
+		if (shost->hostt->eh_strategy_handler) 
+			rtn = shost->hostt->eh_strategy_handler(shost);
+		else
+			scsi_unjam_host(shost);
+
+		shost->eh_active = 0;
+
+		/*
+		 * Note - if the above fails completely, the action is to take
+		 * individual devices offline and flush the queue of any
+		 * outstanding requests that may have been pending.  When we
+		 * restart, we restart any I/O to any other devices on the bus
+		 * which are still online.
+		 */
+		scsi_restart_operations(shost);
+
+	}
+
+	SCSI_LOG_ERROR_RECOVERY(1, printk("Error handler scsi_eh_%d"
+					  " exiting\n",shost->host_no));
+
+	/*
+	 * Make sure that nobody tries to wake us up again.
+	 */
+	shost->eh_wait = NULL;
+
+	/*
+	 * Knock this down too.  From this point on, the host is flying
+	 * without a pilot.  If this is because the module is being unloaded,
+	 * that's fine.  If the user sent a signal to this thing, we are
+	 * potentially in real danger.
+	 */
+	shost->eh_active = 0;
+	shost->ehandler = NULL;
+
+	/*
+	 * If anyone is waiting for us to exit (i.e. someone trying to unload
+	 * a driver), then wake up that process to let them know we are on
+	 * the way out the door.
+	 */
+	complete_and_exit(shost->eh_notify, 0);
+	return 0;
+}
+
+/*
+ * Function:    scsi_report_bus_reset()
+ *
+ * Purpose:     Utility function used by low-level drivers to report that
+ *		they have observed a bus reset on the bus being handled.
+ *
+ * Arguments:   shost       - Host in question
+ *		channel     - channel on which reset was observed.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: Host lock must be held.
+ *
+ * Notes:       This only needs to be called if the reset is one which
+ *		originates from an unknown location.  Resets originated
+ *		by the mid-level itself don't need to call this, but there
+ *		should be no harm.
+ *
+ *		The main purpose of this is to make sure that a CHECK_CONDITION
+ *		is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
+{
+	struct scsi_device *sdev;
+
+	__shost_for_each_device(sdev, shost) {
+		if (channel == sdev->channel) {
+			sdev->was_reset = 1;
+			sdev->expecting_cc_ua = 1;
+		}
+	}
+}
+EXPORT_SYMBOL(scsi_report_bus_reset);
+
+/*
+ * Function:    scsi_report_device_reset()
+ *
+ * Purpose:     Utility function used by low-level drivers to report that
+ *		they have observed a device reset on the device being handled.
+ *
+ * Arguments:   shost       - Host in question
+ *		channel     - channel on which reset was observed
+ *		target	    - target on which reset was observed
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: Host lock must be held
+ *
+ * Notes:       This only needs to be called if the reset is one which
+ *		originates from an unknown location.  Resets originated
+ *		by the mid-level itself don't need to call this, but there
+ *		should be no harm.
+ *
+ *		The main purpose of this is to make sure that a CHECK_CONDITION
+ *		is properly treated.
+ */
+void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
+{
+	struct scsi_device *sdev;
+
+	__shost_for_each_device(sdev, shost) {
+		if (channel == sdev->channel &&
+		    target == sdev->id) {
+			sdev->was_reset = 1;
+			sdev->expecting_cc_ua = 1;
+		}
+	}
+}
+EXPORT_SYMBOL(scsi_report_device_reset);
+
+static void
+scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
+{
+}
+
+/*
+ * Function:	scsi_reset_provider
+ *
+ * Purpose:	Send requested reset to a bus or device at any phase.
+ *
+ * Arguments:	device	- device to send reset to
+ *		flag - reset type (see scsi.h)
+ *
+ * Returns:	SUCCESS/FAILURE.
+ *
+ * Notes:	This is used by the SCSI Generic driver to provide
+ *		Bus/Device reset capability.
+ */
+int
+scsi_reset_provider(struct scsi_device *dev, int flag)
+{
+	struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
+	struct request req;
+	int rtn;
+
+	scmd->request = &req;
+	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
+	scmd->request->rq_status      	= RQ_SCSI_BUSY;
+	scmd->state                   	= SCSI_STATE_INITIALIZING;
+	scmd->owner	     		= SCSI_OWNER_MIDLEVEL;
+    
+	memset(&scmd->cmnd, '\0', sizeof(scmd->cmnd));
+    
+	scmd->scsi_done		= scsi_reset_provider_done_command;
+	scmd->done			= NULL;
+	scmd->buffer			= NULL;
+	scmd->bufflen			= 0;
+	scmd->request_buffer		= NULL;
+	scmd->request_bufflen		= 0;
+	scmd->internal_timeout		= NORMAL_TIMEOUT;
+	scmd->abort_reason		= DID_ABORT;
+
+	scmd->cmd_len			= 0;
+
+	scmd->sc_data_direction		= DMA_BIDIRECTIONAL;
+	scmd->sc_request		= NULL;
+	scmd->sc_magic			= SCSI_CMND_MAGIC;
+
+	init_timer(&scmd->eh_timeout);
+
+	/*
+	 * Sometimes the command can get back into the timer chain,
+	 * so use the pid as an identifier.
+	 */
+	scmd->pid			= 0;
+
+	switch (flag) {
+	case SCSI_TRY_RESET_DEVICE:
+		rtn = scsi_try_bus_device_reset(scmd);
+		if (rtn == SUCCESS)
+			break;
+		/* FALLTHROUGH */
+	case SCSI_TRY_RESET_BUS:
+		rtn = scsi_try_bus_reset(scmd);
+		if (rtn == SUCCESS)
+			break;
+		/* FALLTHROUGH */
+	case SCSI_TRY_RESET_HOST:
+		rtn = scsi_try_host_reset(scmd);
+		break;
+	default:
+		rtn = FAILED;
+	}
+
+	scsi_delete_timer(scmd);
+	scsi_next_command(scmd);
+	return rtn;
+}
+EXPORT_SYMBOL(scsi_reset_provider);
+
+/**
+ * scsi_normalize_sense - normalize main elements from either fixed or
+ *			descriptor sense data format into a common format.
+ *
+ * @sense_buffer:	byte array containing sense data returned by device
+ * @sb_len:		number of valid bytes in sense_buffer
+ * @sshdr:		pointer to instance of structure that common
+ *			elements are written to.
+ *
+ * Notes:
+ *	The "main elements" from sense data are: response_code, sense_key,
+ *	asc, ascq and additional_length (only for descriptor format).
+ *
+ *	Typically this function can be called after a device has
+ *	responded to a SCSI command with the CHECK_CONDITION status.
+ *
+ * Return value:
+ *	1 if valid sense data information found, else 0;
+ **/
+int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+                         struct scsi_sense_hdr *sshdr)
+{
+	if (!sense_buffer || !sb_len || (sense_buffer[0] & 0x70) != 0x70)
+		return 0;
+
+	memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
+
+	sshdr->response_code = (sense_buffer[0] & 0x7f);
+	if (sshdr->response_code >= 0x72) {
+		/*
+		 * descriptor format
+		 */
+		if (sb_len > 1)
+			sshdr->sense_key = (sense_buffer[1] & 0xf);
+		if (sb_len > 2)
+			sshdr->asc = sense_buffer[2];
+		if (sb_len > 3)
+			sshdr->ascq = sense_buffer[3];
+		if (sb_len > 7)
+			sshdr->additional_length = sense_buffer[7];
+	} else {
+		/* 
+		 * fixed format
+		 */
+		if (sb_len > 2)
+			sshdr->sense_key = (sense_buffer[2] & 0xf);
+		if (sb_len > 7) {
+			sb_len = (sb_len < (sense_buffer[7] + 8)) ?
+					 sb_len : (sense_buffer[7] + 8);
+			if (sb_len > 12)
+				sshdr->asc = sense_buffer[12];
+			if (sb_len > 13)
+				sshdr->ascq = sense_buffer[13];
+		}
+	}
+
+	return 1;
+}
+EXPORT_SYMBOL(scsi_normalize_sense);
+
+int scsi_request_normalize_sense(struct scsi_request *sreq,
+				 struct scsi_sense_hdr *sshdr)
+{
+	return scsi_normalize_sense(sreq->sr_sense_buffer,
+			sizeof(sreq->sr_sense_buffer), sshdr);
+}
+EXPORT_SYMBOL(scsi_request_normalize_sense);
+
+int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
+				 struct scsi_sense_hdr *sshdr)
+{
+	return scsi_normalize_sense(cmd->sense_buffer,
+			sizeof(cmd->sense_buffer), sshdr);
+}
+EXPORT_SYMBOL(scsi_command_normalize_sense);
+
+/**
+ * scsi_sense_desc_find - search for a given descriptor type in
+ *			descriptor sense data format.
+ *
+ * @sense_buffer:	byte array of descriptor format sense data
+ * @sb_len:		number of valid bytes in sense_buffer
+ * @desc_type:		value of descriptor type to find
+ *			(e.g. 0 -> information)
+ *
+ * Notes:
+ *	only valid when sense data is in descriptor format
+ *
+ * Return value:
+ *	pointer to start of (first) descriptor if found else NULL
+ **/
+const u8 * scsi_sense_desc_find(const u8 * sense_buffer, int sb_len,
+				int desc_type)
+{
+	int add_sen_len, add_len, desc_len, k;
+	const u8 * descp;
+
+	if ((sb_len < 8) || (0 == (add_sen_len = sense_buffer[7])))
+		return NULL;
+	if ((sense_buffer[0] < 0x72) || (sense_buffer[0] > 0x73))
+		return NULL;
+	add_sen_len = (add_sen_len < (sb_len - 8)) ?
+			add_sen_len : (sb_len - 8);
+	descp = &sense_buffer[8];
+	for (desc_len = 0, k = 0; k < add_sen_len; k += desc_len) {
+		descp += desc_len;
+		add_len = (k < (add_sen_len - 1)) ? descp[1]: -1;
+		desc_len = add_len + 2;
+		if (descp[0] == desc_type)
+			return descp;
+		if (add_len < 0) // short descriptor ??
+			break;
+	}
+	return NULL;
+}
+EXPORT_SYMBOL(scsi_sense_desc_find);
+
+/**
+ * scsi_get_sense_info_fld - attempts to get information field from
+ *			sense data (either fixed or descriptor format)
+ *
+ * @sense_buffer:	byte array of sense data
+ * @sb_len:		number of valid bytes in sense_buffer
+ * @info_out:		pointer to 64 integer where 8 or 4 byte information
+ *			field will be placed if found.
+ *
+ * Return value:
+ *	1 if information field found, 0 if not found.
+ **/
+int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
+			    u64 * info_out)
+{
+	int j;
+	const u8 * ucp;
+	u64 ull;
+
+	if (sb_len < 7)
+		return 0;
+	switch (sense_buffer[0] & 0x7f) {
+	case 0x70:
+	case 0x71:
+		if (sense_buffer[0] & 0x80) {
+			*info_out = (sense_buffer[3] << 24) +
+				    (sense_buffer[4] << 16) +
+				    (sense_buffer[5] << 8) + sense_buffer[6];
+			return 1;
+		} else
+			return 0;
+	case 0x72:
+	case 0x73:
+		ucp = scsi_sense_desc_find(sense_buffer, sb_len,
+					   0 /* info desc */);
+		if (ucp && (0xa == ucp[1])) {
+			ull = 0;
+			for (j = 0; j < 8; ++j) {
+				if (j > 0)
+					ull <<= 8;
+				ull |= ucp[4 + j];
+			}
+			*info_out = ull;
+			return 1;
+		} else
+			return 0;
+	default:
+		return 0;
+	}
+}
+EXPORT_SYMBOL(scsi_get_sense_info_fld);
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
new file mode 100644
index 0000000..68c9728
--- /dev/null
+++ b/drivers/scsi/scsi_ioctl.c
@@ -0,0 +1,516 @@
+/*
+ * Changes:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> 08/23/2000
+ * - get rid of some verify_areas and use __copy*user and __get/put_user
+ *   for the ones that remain
+ */
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+#include <scsi/sg.h>
+#include <scsi/scsi_dbg.h>
+
+#include "scsi_logging.h"
+
+#define NORMAL_RETRIES			5
+#define IOCTL_NORMAL_TIMEOUT			(10 * HZ)
+#define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
+#define START_STOP_TIMEOUT		(60 * HZ)
+#define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
+#define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
+#define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )  /* ZIP-250 on parallel port takes as long! */
+
+#define MAX_BUF PAGE_SIZE
+
+/*
+ * If we are told to probe a host, we will return 0 if  the host is not
+ * present, 1 if the host is present, and will return an identifying
+ * string at *arg, if arg is non null, filling to the length stored at
+ * (int *) arg
+ */
+
+static int ioctl_probe(struct Scsi_Host *host, void __user *buffer)
+{
+	unsigned int len, slen;
+	const char *string;
+	int temp = host->hostt->present;
+
+	if (temp && buffer) {
+		if (get_user(len, (unsigned int __user *) buffer))
+			return -EFAULT;
+
+		if (host->hostt->info)
+			string = host->hostt->info(host);
+		else
+			string = host->hostt->name;
+		if (string) {
+			slen = strlen(string);
+			if (len > slen)
+				len = slen + 1;
+			if (copy_to_user(buffer, string, len))
+				return -EFAULT;
+		}
+	}
+	return temp;
+}
+
+/*
+
+ * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host.
+ * The IOCTL_NORMAL_TIMEOUT and NORMAL_RETRIES  variables are used.  
+ * 
+ * dev is the SCSI device struct ptr, *(int *) arg is the length of the
+ * input data, if any, not including the command string & counts, 
+ * *((int *)arg + 1) is the output buffer size in bytes.
+ * 
+ * *(char *) ((int *) arg)[2] the actual command byte.   
+ * 
+ * Note that if more than MAX_BUF bytes are requested to be transferred,
+ * the ioctl will fail with error EINVAL.
+ * 
+ * This size *does not* include the initial lengths that were passed.
+ * 
+ * The SCSI command is read from the memory location immediately after the
+ * length words, and the input data is right after the command.  The SCSI
+ * routines know the command size based on the opcode decode.  
+ * 
+ * The output area is then filled in starting from the command byte. 
+ */
+
+static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
+				  int timeout, int retries)
+{
+	struct scsi_request *sreq;
+	int result;
+	struct scsi_sense_hdr sshdr;
+
+	SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", *cmd));
+
+	sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	if (!sreq) {
+		printk(KERN_WARNING "SCSI internal ioctl failed, no memory\n");
+		return -ENOMEM;
+	}
+
+	sreq->sr_data_direction = DMA_NONE;
+        scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
+
+	SCSI_LOG_IOCTL(2, printk("Ioctl returned  0x%x\n", sreq->sr_result));
+
+	if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
+	    (scsi_request_normalize_sense(sreq, &sshdr))) {
+		switch (sshdr.sense_key) {
+		case ILLEGAL_REQUEST:
+			if (cmd[0] == ALLOW_MEDIUM_REMOVAL)
+				sdev->lockable = 0;
+			else
+				printk(KERN_INFO "ioctl_internal_command: "
+				       "ILLEGAL REQUEST asc=0x%x ascq=0x%x\n",
+				       sshdr.asc, sshdr.ascq);
+			break;
+		case NOT_READY:	/* This happens if there is no disc in drive */
+			if (sdev->removable && (cmd[0] != TEST_UNIT_READY)) {
+				printk(KERN_INFO "Device not ready. Make sure"
+				       " there is a disc in the drive.\n");
+				break;
+			}
+		case UNIT_ATTENTION:
+			if (sdev->removable) {
+				sdev->changed = 1;
+				sreq->sr_result = 0;	/* This is no longer considered an error */
+				break;
+			}
+		default:	/* Fall through for non-removable media */
+			printk(KERN_INFO "ioctl_internal_command: <%d %d %d "
+			       "%d> return code = %x\n",
+			       sdev->host->host_no,
+			       sdev->channel,
+			       sdev->id,
+			       sdev->lun,
+			       sreq->sr_result);
+			scsi_print_req_sense("   ", sreq);
+			break;
+		}
+	}
+
+	result = sreq->sr_result;
+	SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
+	scsi_release_request(sreq);
+	return result;
+}
+
+int scsi_set_medium_removal(struct scsi_device *sdev, char state)
+{
+	char scsi_cmd[MAX_COMMAND_SIZE];
+	int ret;
+
+	if (!sdev->removable || !sdev->lockable)
+	       return 0;
+
+	scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+	scsi_cmd[1] = 0;
+	scsi_cmd[2] = 0;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = state;
+	scsi_cmd[5] = 0;
+
+	ret = ioctl_internal_command(sdev, scsi_cmd,
+			IOCTL_NORMAL_TIMEOUT, NORMAL_RETRIES);
+	if (ret == 0)
+		sdev->locked = (state == SCSI_REMOVAL_PREVENT);
+	return ret;
+}
+EXPORT_SYMBOL(scsi_set_medium_removal);
+
+/*
+ * This interface is deprecated - users should use the scsi generic (sg)
+ * interface instead, as this is a more flexible approach to performing
+ * generic SCSI commands on a device.
+ *
+ * The structure that we are passed should look like:
+ *
+ * struct sdata {
+ *  unsigned int inlen;      [i] Length of data to be written to device 
+ *  unsigned int outlen;     [i] Length of data to be read from device 
+ *  unsigned char cmd[x];    [i] SCSI command (6 <= x <= 12).
+ *                           [o] Data read from device starts here.
+ *                           [o] On error, sense buffer starts here.
+ *  unsigned char wdata[y];  [i] Data written to device starts here.
+ * };
+ * Notes:
+ *   -  The SCSI command length is determined by examining the 1st byte
+ *      of the given command. There is no way to override this.
+ *   -  Data transfers are limited to PAGE_SIZE (4K on i386, 8K on alpha).
+ *   -  The length (x + y) must be at least OMAX_SB_LEN bytes long to
+ *      accommodate the sense buffer when an error occurs.
+ *      The sense buffer is truncated to OMAX_SB_LEN (16) bytes so that
+ *      old code will not be surprised.
+ *   -  If a Unix error occurs (e.g. ENOMEM) then the user will receive
+ *      a negative return and the Unix error code in 'errno'. 
+ *      If the SCSI command succeeds then 0 is returned.
+ *      Positive numbers returned are the compacted SCSI error codes (4 
+ *      bytes in one int) where the lowest byte is the SCSI status.
+ *      See the drivers/scsi/scsi.h file for more information on this.
+ *
+ */
+#define OMAX_SB_LEN 16		/* Old sense buffer length */
+
+int scsi_ioctl_send_command(struct scsi_device *sdev,
+			    struct scsi_ioctl_command __user *sic)
+{
+	char *buf;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	char __user *cmd_in;
+	struct scsi_request *sreq;
+	unsigned char opcode;
+	unsigned int inlen, outlen, cmdlen;
+	unsigned int needed, buf_needed;
+	int timeout, retries, result;
+	int data_direction, gfp_mask = GFP_KERNEL;
+
+	if (!sic)
+		return -EINVAL;
+
+	if (sdev->host->unchecked_isa_dma)
+		gfp_mask |= GFP_DMA;
+
+	/*
+	 * Verify that we can read at least this much.
+	 */
+	if (!access_ok(VERIFY_READ, sic, sizeof(Scsi_Ioctl_Command)))
+		return -EFAULT;
+
+	if(__get_user(inlen, &sic->inlen))
+		return -EFAULT;
+		
+	if(__get_user(outlen, &sic->outlen))
+		return -EFAULT;
+
+	/*
+	 * We do not transfer more than MAX_BUF with this interface.
+	 * If the user needs to transfer more data than this, they
+	 * should use scsi_generics (sg) instead.
+	 */
+	if (inlen > MAX_BUF)
+		return -EINVAL;
+	if (outlen > MAX_BUF)
+		return -EINVAL;
+
+	cmd_in = sic->data;
+	if(get_user(opcode, cmd_in))
+		return -EFAULT;
+
+	needed = buf_needed = (inlen > outlen ? inlen : outlen);
+	if (buf_needed) {
+		buf_needed = (buf_needed + 511) & ~511;
+		if (buf_needed > MAX_BUF)
+			buf_needed = MAX_BUF;
+		buf = kmalloc(buf_needed, gfp_mask);
+		if (!buf)
+			return -ENOMEM;
+		memset(buf, 0, buf_needed);
+		if (inlen == 0) {
+			data_direction = DMA_FROM_DEVICE;
+		} else if (outlen == 0 ) {
+			data_direction = DMA_TO_DEVICE;
+		} else {
+			/*
+			 * Can this ever happen?
+			 */
+			data_direction = DMA_BIDIRECTIONAL;
+		}
+
+	} else {
+		buf = NULL;
+		data_direction = DMA_NONE;
+	}
+
+	/*
+	 * Obtain the command from the user's address space.
+	 */
+	cmdlen = COMMAND_SIZE(opcode);
+	
+	result = -EFAULT;
+
+	if (!access_ok(VERIFY_READ, cmd_in, cmdlen + inlen))
+		goto error;
+
+	if(__copy_from_user(cmd, cmd_in, cmdlen))
+		goto error;
+
+	/*
+	 * Obtain the data to be sent to the device (if any).
+	 */
+
+	if(copy_from_user(buf, cmd_in + cmdlen, inlen))
+		goto error;
+
+	switch (opcode) {
+	case SEND_DIAGNOSTIC:
+	case FORMAT_UNIT:
+		timeout = FORMAT_UNIT_TIMEOUT;
+		retries = 1;
+		break;
+	case START_STOP:
+		timeout = START_STOP_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case MOVE_MEDIUM:
+		timeout = MOVE_MEDIUM_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case READ_ELEMENT_STATUS:
+		timeout = READ_ELEMENT_STATUS_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	case READ_DEFECT_DATA:
+		timeout = READ_DEFECT_DATA_TIMEOUT;
+		retries = 1;
+		break;
+	default:
+		timeout = IOCTL_NORMAL_TIMEOUT;
+		retries = NORMAL_RETRIES;
+		break;
+	}
+
+	sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+        if (!sreq) {
+                result = -EINTR;
+                goto error;
+        }
+
+	sreq->sr_data_direction = data_direction;
+        scsi_wait_req(sreq, cmd, buf, needed, timeout, retries);
+
+	/* 
+	 * If there was an error condition, pass the info back to the user. 
+	 */
+	result = sreq->sr_result;
+	if (result) {
+		int sb_len = sizeof(sreq->sr_sense_buffer);
+
+		sb_len = (sb_len > OMAX_SB_LEN) ? OMAX_SB_LEN : sb_len;
+		if (copy_to_user(cmd_in, sreq->sr_sense_buffer, sb_len))
+			result = -EFAULT;
+	} else {
+		if (copy_to_user(cmd_in, buf, outlen))
+			result = -EFAULT;
+	}	
+
+	scsi_release_request(sreq);
+error:
+	kfree(buf);
+	return result;
+}
+EXPORT_SYMBOL(scsi_ioctl_send_command);
+
+/*
+ * The scsi_ioctl_get_pci() function places into arg the value
+ * pci_dev::slot_name (8 characters) for the PCI device (if any).
+ * Returns: 0 on success
+ *          -ENXIO if there isn't a PCI device pointer
+ *                 (could be because the SCSI driver hasn't been
+ *                  updated yet, or because it isn't a SCSI
+ *                  device)
+ *          any copy_to_user() error on failure there
+ */
+static int scsi_ioctl_get_pci(struct scsi_device *sdev, void __user *arg)
+{
+	struct device *dev = scsi_get_device(sdev->host);
+
+        if (!dev)
+		return -ENXIO;
+        return copy_to_user(arg, dev->bus_id, sizeof(dev->bus_id))? -EFAULT: 0;
+}
+
+
+/*
+ * the scsi_ioctl() function differs from most ioctls in that it does
+ * not take a major/minor number as the dev field.  Rather, it takes
+ * a pointer to a scsi_devices[] element, a structure. 
+ */
+int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
+{
+	char scsi_cmd[MAX_COMMAND_SIZE];
+
+	/* No idea how this happens.... */
+	if (!sdev)
+		return -ENXIO;
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(sdev))
+		return -ENODEV;
+
+	/* Check for deprecated ioctls ... all the ioctls which don't
+	 * follow the new unique numbering scheme are deprecated */
+	switch (cmd) {
+	case SCSI_IOCTL_SEND_COMMAND:
+	case SCSI_IOCTL_TEST_UNIT_READY:
+	case SCSI_IOCTL_BENCHMARK_COMMAND:
+	case SCSI_IOCTL_SYNC:
+	case SCSI_IOCTL_START_UNIT:
+	case SCSI_IOCTL_STOP_UNIT:
+		printk(KERN_WARNING "program %s is using a deprecated SCSI "
+		       "ioctl, please convert it to SG_IO\n", current->comm);
+		break;
+	default:
+		break;
+	}
+
+	switch (cmd) {
+	case SCSI_IOCTL_GET_IDLUN:
+		if (!access_ok(VERIFY_WRITE, arg, sizeof(struct scsi_idlun)))
+			return -EFAULT;
+
+		__put_user((sdev->id & 0xff)
+			 + ((sdev->lun & 0xff) << 8)
+			 + ((sdev->channel & 0xff) << 16)
+			 + ((sdev->host->host_no & 0xff) << 24),
+			 &((struct scsi_idlun __user *)arg)->dev_id);
+		__put_user(sdev->host->unique_id,
+			 &((struct scsi_idlun __user *)arg)->host_unique_id);
+		return 0;
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+		return put_user(sdev->host->host_no, (int __user *)arg);
+	case SCSI_IOCTL_PROBE_HOST:
+		return ioctl_probe(sdev->host, arg);
+	case SCSI_IOCTL_SEND_COMMAND:
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return scsi_ioctl_send_command(sdev, arg);
+	case SCSI_IOCTL_DOORLOCK:
+		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
+	case SCSI_IOCTL_DOORUNLOCK:
+		return scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
+	case SCSI_IOCTL_TEST_UNIT_READY:
+		return scsi_test_unit_ready(sdev, IOCTL_NORMAL_TIMEOUT,
+					    NORMAL_RETRIES);
+	case SCSI_IOCTL_START_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = 0;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 1;
+		return ioctl_internal_command(sdev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+	case SCSI_IOCTL_STOP_UNIT:
+		scsi_cmd[0] = START_STOP;
+		scsi_cmd[1] = 0;
+		scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+		scsi_cmd[4] = 0;
+		return ioctl_internal_command(sdev, scsi_cmd,
+				     START_STOP_TIMEOUT, NORMAL_RETRIES);
+        case SCSI_IOCTL_GET_PCI:
+                return scsi_ioctl_get_pci(sdev, arg);
+	default:
+		if (sdev->host->hostt->ioctl)
+			return sdev->host->hostt->ioctl(sdev, cmd, arg);
+	}
+	return -EINVAL;
+}
+EXPORT_SYMBOL(scsi_ioctl);
+
+/*
+ * the scsi_nonblock_ioctl() function is designed for ioctls which may
+ * be executed even if the device is in recovery.
+ */
+int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
+			    void __user *arg, struct file *filp)
+{
+	int val, result;
+
+	/* The first set of iocts may be executed even if we're doing
+	 * error processing, as long as the device was opened
+	 * non-blocking */
+	if (filp && filp->f_flags & O_NONBLOCK) {
+		if (test_bit(SHOST_RECOVERY,
+			     &sdev->host->shost_state))
+			return -ENODEV;
+	} else if (!scsi_block_when_processing_errors(sdev))
+		return -ENODEV;
+
+	switch (cmd) {
+	case SG_SCSI_RESET:
+		result = get_user(val, (int __user *)arg);
+		if (result)
+			return result;
+		if (val == SG_SCSI_RESET_NOTHING)
+			return 0;
+		switch (val) {
+		case SG_SCSI_RESET_DEVICE:
+			val = SCSI_TRY_RESET_DEVICE;
+			break;
+		case SG_SCSI_RESET_BUS:
+			val = SCSI_TRY_RESET_BUS;
+			break;
+		case SG_SCSI_RESET_HOST:
+			val = SCSI_TRY_RESET_HOST;
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return (scsi_reset_provider(sdev, val) ==
+			SUCCESS) ? 0 : -EIO;
+	}
+	return -ENODEV;
+}
+EXPORT_SYMBOL(scsi_nonblockable_ioctl);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
new file mode 100644
index 0000000..7cbc412
--- /dev/null
+++ b/drivers/scsi/scsi_lib.c
@@ -0,0 +1,2023 @@
+/*
+ *  scsi_lib.c Copyright (C) 1999 Eric Youngdale
+ *
+ *  SCSI queueing library.
+ *      Initial versions: Eric Youngdale (eric@andante.org).
+ *                        Based upon conversations with large numbers
+ *                        of people at Linux Expo.
+ */
+
+#include <linux/bio.h>
+#include <linux/blkdev.h>
+#include <linux/completion.h>
+#include <linux/kernel.h>
+#include <linux/mempool.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_request.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
+#define SG_MEMPOOL_NR		(sizeof(scsi_sg_pools)/sizeof(struct scsi_host_sg_pool))
+#define SG_MEMPOOL_SIZE		32
+
+struct scsi_host_sg_pool {
+	size_t		size;
+	char		*name; 
+	kmem_cache_t	*slab;
+	mempool_t	*pool;
+};
+
+#if (SCSI_MAX_PHYS_SEGMENTS < 32)
+#error SCSI_MAX_PHYS_SEGMENTS is too small
+#endif
+
+#define SP(x) { x, "sgpool-" #x } 
+struct scsi_host_sg_pool scsi_sg_pools[] = { 
+	SP(8),
+	SP(16),
+	SP(32),
+#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+	SP(64),
+#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+	SP(128),
+#if (SCSI_MAX_PHYS_SEGMENTS > 128)
+	SP(256),
+#if (SCSI_MAX_PHYS_SEGMENTS > 256)
+#error SCSI_MAX_PHYS_SEGMENTS is too large
+#endif
+#endif
+#endif
+#endif
+}; 	
+#undef SP
+
+
+/*
+ * Function:    scsi_insert_special_req()
+ *
+ * Purpose:     Insert pre-formed request into request queue.
+ *
+ * Arguments:   sreq	- request that is ready to be queued.
+ *              at_head	- boolean.  True if we should insert at head
+ *                        of queue, false if we should insert at tail.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       This function is called from character device and from
+ *              ioctl types of functions where the caller knows exactly
+ *              what SCSI command needs to be issued.   The idea is that
+ *              we merely inject the command into the queue (at the head
+ *              for now), and then call the queue request function to actually
+ *              process it.
+ */
+int scsi_insert_special_req(struct scsi_request *sreq, int at_head)
+{
+	/*
+	 * Because users of this function are apt to reuse requests with no
+	 * modification, we have to sanitise the request flags here
+	 */
+	sreq->sr_request->flags &= ~REQ_DONTPREP;
+	blk_insert_request(sreq->sr_device->request_queue, sreq->sr_request,
+		       	   at_head, sreq, 0);
+	return 0;
+}
+
+/*
+ * Function:    scsi_queue_insert()
+ *
+ * Purpose:     Insert a command in the midlevel queue.
+ *
+ * Arguments:   cmd    - command that we are adding to queue.
+ *              reason - why we are inserting command to queue.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:       We do this for one of two cases.  Either the host is busy
+ *              and it cannot accept any more commands for the time being,
+ *              or the device returned QUEUE_FULL and can accept no more
+ *              commands.
+ * Notes:       This could be called either from an interrupt context or a
+ *              normal process context.
+ */
+int scsi_queue_insert(struct scsi_cmnd *cmd, int reason)
+{
+	struct Scsi_Host *host = cmd->device->host;
+	struct scsi_device *device = cmd->device;
+
+	SCSI_LOG_MLQUEUE(1,
+		 printk("Inserting command %p into mlqueue\n", cmd));
+
+	/*
+	 * We are inserting the command into the ml queue.  First, we
+	 * cancel the timer, so it doesn't time out.
+	 */
+	scsi_delete_timer(cmd);
+
+	/*
+	 * Next, set the appropriate busy bit for the device/host.
+	 *
+	 * If the host/device isn't busy, assume that something actually
+	 * completed, and that we should be able to queue a command now.
+	 *
+	 * Note that the prior mid-layer assumption that any host could
+	 * always queue at least one command is now broken.  The mid-layer
+	 * will implement a user specifiable stall (see
+	 * scsi_host.max_host_blocked and scsi_device.max_device_blocked)
+	 * if a command is requeued with no other commands outstanding
+	 * either for the device or for the host.
+	 */
+	if (reason == SCSI_MLQUEUE_HOST_BUSY)
+		host->host_blocked = host->max_host_blocked;
+	else if (reason == SCSI_MLQUEUE_DEVICE_BUSY)
+		device->device_blocked = device->max_device_blocked;
+
+	/*
+	 * Register the fact that we own the thing for now.
+	 */
+	cmd->state = SCSI_STATE_MLQUEUE;
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+
+	/*
+	 * Decrement the counters, since these commands are no longer
+	 * active on the host/device.
+	 */
+	scsi_device_unbusy(device);
+
+	/*
+	 * Insert this command at the head of the queue for it's device.
+	 * It will go before all other commands that are already in the queue.
+	 *
+	 * NOTE: there is magic here about the way the queue is plugged if
+	 * we have no outstanding commands.
+	 * 
+	 * Although this *doesn't* plug the queue, it does call the request
+	 * function.  The SCSI request function detects the blocked condition
+	 * and plugs the queue appropriately.
+	 */
+	blk_insert_request(device->request_queue, cmd->request, 1, cmd, 1);
+	return 0;
+}
+
+/*
+ * Function:    scsi_do_req
+ *
+ * Purpose:     Queue a SCSI request
+ *
+ * Arguments:   sreq	  - command descriptor.
+ *              cmnd      - actual SCSI command to be performed.
+ *              buffer    - data buffer.
+ *              bufflen   - size of data buffer.
+ *              done      - completion function to be run.
+ *              timeout   - how long to let it run before timeout.
+ *              retries   - number of retries we allow.
+ *
+ * Lock status: No locks held upon entry.
+ *
+ * Returns:     Nothing.
+ *
+ * Notes:	This function is only used for queueing requests for things
+ *		like ioctls and character device requests - this is because
+ *		we essentially just inject a request into the queue for the
+ *		device.
+ *
+ *		In order to support the scsi_device_quiesce function, we
+ *		now inject requests on the *head* of the device queue
+ *		rather than the tail.
+ */
+void scsi_do_req(struct scsi_request *sreq, const void *cmnd,
+		 void *buffer, unsigned bufflen,
+		 void (*done)(struct scsi_cmnd *),
+		 int timeout, int retries)
+{
+	/*
+	 * If the upper level driver is reusing these things, then
+	 * we should release the low-level block now.  Another one will
+	 * be allocated later when this request is getting queued.
+	 */
+	__scsi_release_request(sreq);
+
+	/*
+	 * Our own function scsi_done (which marks the host as not busy,
+	 * disables the timeout counter, etc) will be called by us or by the
+	 * scsi_hosts[host].queuecommand() function needs to also call
+	 * the completion function for the high level driver.
+	 */
+	memcpy(sreq->sr_cmnd, cmnd, sizeof(sreq->sr_cmnd));
+	sreq->sr_bufflen = bufflen;
+	sreq->sr_buffer = buffer;
+	sreq->sr_allowed = retries;
+	sreq->sr_done = done;
+	sreq->sr_timeout_per_command = timeout;
+
+	if (sreq->sr_cmd_len == 0)
+		sreq->sr_cmd_len = COMMAND_SIZE(sreq->sr_cmnd[0]);
+
+	/*
+	 * head injection *required* here otherwise quiesce won't work
+	 */
+	scsi_insert_special_req(sreq, 1);
+}
+EXPORT_SYMBOL(scsi_do_req);
+
+static void scsi_wait_done(struct scsi_cmnd *cmd)
+{
+	struct request *req = cmd->request;
+	struct request_queue *q = cmd->device->request_queue;
+	unsigned long flags;
+
+	req->rq_status = RQ_SCSI_DONE;	/* Busy, but indicate request done */
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	if (blk_rq_tagged(req))
+		blk_queue_end_tag(q, req);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	if (req->waiting)
+		complete(req->waiting);
+}
+
+/* This is the end routine we get to if a command was never attached
+ * to the request.  Simply complete the request without changing
+ * rq_status; this will cause a DRIVER_ERROR. */
+static void scsi_wait_req_end_io(struct request *req)
+{
+	BUG_ON(!req->waiting);
+
+	complete(req->waiting);
+}
+
+void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
+		   unsigned bufflen, int timeout, int retries)
+{
+	DECLARE_COMPLETION(wait);
+	
+	sreq->sr_request->waiting = &wait;
+	sreq->sr_request->rq_status = RQ_SCSI_BUSY;
+	sreq->sr_request->end_io = scsi_wait_req_end_io;
+	scsi_do_req(sreq, cmnd, buffer, bufflen, scsi_wait_done,
+			timeout, retries);
+	wait_for_completion(&wait);
+	sreq->sr_request->waiting = NULL;
+	if (sreq->sr_request->rq_status != RQ_SCSI_DONE)
+		sreq->sr_result |= (DRIVER_ERROR << 24);
+
+	__scsi_release_request(sreq);
+}
+EXPORT_SYMBOL(scsi_wait_req);
+
+/*
+ * Function:    scsi_init_cmd_errh()
+ *
+ * Purpose:     Initialize cmd fields related to error handling.
+ *
+ * Arguments:   cmd	- command that is ready to be queued.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       This function has the job of initializing a number of
+ *              fields related to error handling.   Typically this will
+ *              be called once for each command, as required.
+ */
+static int scsi_init_cmd_errh(struct scsi_cmnd *cmd)
+{
+	cmd->owner = SCSI_OWNER_MIDLEVEL;
+	cmd->serial_number = 0;
+	cmd->serial_number_at_timeout = 0;
+	cmd->abort_reason = 0;
+
+	memset(cmd->sense_buffer, 0, sizeof cmd->sense_buffer);
+
+	if (cmd->cmd_len == 0)
+		cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+	/*
+	 * We need saved copies of a number of fields - this is because
+	 * error handling may need to overwrite these with different values
+	 * to run different commands, and once error handling is complete,
+	 * we will need to restore these values prior to running the actual
+	 * command.
+	 */
+	cmd->old_use_sg = cmd->use_sg;
+	cmd->old_cmd_len = cmd->cmd_len;
+	cmd->sc_old_data_direction = cmd->sc_data_direction;
+	cmd->old_underflow = cmd->underflow;
+	memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
+	cmd->buffer = cmd->request_buffer;
+	cmd->bufflen = cmd->request_bufflen;
+	cmd->internal_timeout = NORMAL_TIMEOUT;
+	cmd->abort_reason = 0;
+
+	return 1;
+}
+
+/*
+ * Function:   scsi_setup_cmd_retry()
+ *
+ * Purpose:    Restore the command state for a retry
+ *
+ * Arguments:  cmd	- command to be restored
+ *
+ * Returns:    Nothing
+ *
+ * Notes:      Immediately prior to retrying a command, we need
+ *             to restore certain fields that we saved above.
+ */
+void scsi_setup_cmd_retry(struct scsi_cmnd *cmd)
+{
+	memcpy(cmd->cmnd, cmd->data_cmnd, sizeof(cmd->data_cmnd));
+	cmd->request_buffer = cmd->buffer;
+	cmd->request_bufflen = cmd->bufflen;
+	cmd->use_sg = cmd->old_use_sg;
+	cmd->cmd_len = cmd->old_cmd_len;
+	cmd->sc_data_direction = cmd->sc_old_data_direction;
+	cmd->underflow = cmd->old_underflow;
+}
+
+void scsi_device_unbusy(struct scsi_device *sdev)
+{
+	struct Scsi_Host *shost = sdev->host;
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	shost->host_busy--;
+	if (unlikely(test_bit(SHOST_RECOVERY, &shost->shost_state) &&
+		     shost->host_failed))
+		scsi_eh_wakeup(shost);
+	spin_unlock(shost->host_lock);
+	spin_lock(&sdev->sdev_lock);
+	sdev->device_busy--;
+	spin_unlock_irqrestore(&sdev->sdev_lock, flags);
+}
+
+/*
+ * Called for single_lun devices on IO completion. Clear starget_sdev_user,
+ * and call blk_run_queue for all the scsi_devices on the target -
+ * including current_sdev first.
+ *
+ * Called with *no* scsi locks held.
+ */
+static void scsi_single_lun_run(struct scsi_device *current_sdev)
+{
+	struct Scsi_Host *shost = current_sdev->host;
+	struct scsi_device *sdev, *tmp;
+	struct scsi_target *starget = scsi_target(current_sdev);
+	unsigned long flags;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	starget->starget_sdev_user = NULL;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	/*
+	 * Call blk_run_queue for all LUNs on the target, starting with
+	 * current_sdev. We race with others (to set starget_sdev_user),
+	 * but in most cases, we will be first. Ideally, each LU on the
+	 * target would get some limited time or requests on the target.
+	 */
+	blk_run_queue(current_sdev->request_queue);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	if (starget->starget_sdev_user)
+		goto out;
+	list_for_each_entry_safe(sdev, tmp, &starget->devices,
+			same_target_siblings) {
+		if (sdev == current_sdev)
+			continue;
+		if (scsi_device_get(sdev))
+			continue;
+
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		blk_run_queue(sdev->request_queue);
+		spin_lock_irqsave(shost->host_lock, flags);
+	
+		scsi_device_put(sdev);
+	}
+ out:
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Function:	scsi_run_queue()
+ *
+ * Purpose:	Select a proper request queue to serve next
+ *
+ * Arguments:	q	- last request's queue
+ *
+ * Returns:     Nothing
+ *
+ * Notes:	The previous command was completely finished, start
+ *		a new one if possible.
+ */
+static void scsi_run_queue(struct request_queue *q)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct Scsi_Host *shost = sdev->host;
+	unsigned long flags;
+
+	if (sdev->single_lun)
+		scsi_single_lun_run(sdev);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	while (!list_empty(&shost->starved_list) &&
+	       !shost->host_blocked && !shost->host_self_blocked &&
+		!((shost->can_queue > 0) &&
+		  (shost->host_busy >= shost->can_queue))) {
+		/*
+		 * As long as shost is accepting commands and we have
+		 * starved queues, call blk_run_queue. scsi_request_fn
+		 * drops the queue_lock and can add us back to the
+		 * starved_list.
+		 *
+		 * host_lock protects the starved_list and starved_entry.
+		 * scsi_request_fn must get the host_lock before checking
+		 * or modifying starved_list or starved_entry.
+		 */
+		sdev = list_entry(shost->starved_list.next,
+					  struct scsi_device, starved_entry);
+		list_del_init(&sdev->starved_entry);
+		spin_unlock_irqrestore(shost->host_lock, flags);
+
+		blk_run_queue(sdev->request_queue);
+
+		spin_lock_irqsave(shost->host_lock, flags);
+		if (unlikely(!list_empty(&sdev->starved_entry)))
+			/*
+			 * sdev lost a race, and was put back on the
+			 * starved list. This is unlikely but without this
+			 * in theory we could loop forever.
+			 */
+			break;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	blk_run_queue(q);
+}
+
+/*
+ * Function:	scsi_requeue_command()
+ *
+ * Purpose:	Handle post-processing of completed commands.
+ *
+ * Arguments:	q	- queue to operate on
+ *		cmd	- command that may need to be requeued.
+ *
+ * Returns:	Nothing
+ *
+ * Notes:	After command completion, there may be blocks left
+ *		over which weren't finished by the previous command
+ *		this can be for a number of reasons - the main one is
+ *		I/O errors in the middle of the request, in which case
+ *		we need to request the blocks that come after the bad
+ *		sector.
+ */
+static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
+{
+	cmd->request->flags &= ~REQ_DONTPREP;
+	blk_insert_request(q, cmd->request, 1, cmd, 1);
+
+	scsi_run_queue(q);
+}
+
+void scsi_next_command(struct scsi_cmnd *cmd)
+{
+	struct request_queue *q = cmd->device->request_queue;
+
+	scsi_put_command(cmd);
+	scsi_run_queue(q);
+}
+
+void scsi_run_host_queues(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+
+	shost_for_each_device(sdev, shost)
+		scsi_run_queue(sdev->request_queue);
+}
+
+/*
+ * Function:    scsi_end_request()
+ *
+ * Purpose:     Post-processing of completed commands (usually invoked at end
+ *		of upper level post-processing and scsi_io_completion).
+ *
+ * Arguments:   cmd	 - command that is complete.
+ *              uptodate - 1 if I/O indicates success, <= 0 for I/O error.
+ *              bytes    - number of bytes of completed I/O
+ *		requeue  - indicates whether we should requeue leftovers.
+ *
+ * Lock status: Assumed that lock is not held upon entry.
+ *
+ * Returns:     cmd if requeue done or required, NULL otherwise
+ *
+ * Notes:       This is called for block device requests in order to
+ *              mark some number of sectors as complete.
+ * 
+ *		We are guaranteeing that the request queue will be goosed
+ *		at some point during this call.
+ */
+static struct scsi_cmnd *scsi_end_request(struct scsi_cmnd *cmd, int uptodate,
+					  int bytes, int requeue)
+{
+	request_queue_t *q = cmd->device->request_queue;
+	struct request *req = cmd->request;
+	unsigned long flags;
+
+	/*
+	 * If there are blocks left over at the end, set up the command
+	 * to queue the remainder of them.
+	 */
+	if (end_that_request_chunk(req, uptodate, bytes)) {
+		int leftover = (req->hard_nr_sectors << 9);
+
+		if (blk_pc_request(req))
+			leftover = req->data_len;
+
+		/* kill remainder if no retrys */
+		if (!uptodate && blk_noretry_request(req))
+			end_that_request_chunk(req, 0, leftover);
+		else {
+			if (requeue)
+				/*
+				 * Bleah.  Leftovers again.  Stick the
+				 * leftovers in the front of the
+				 * queue, and goose the queue again.
+				 */
+				scsi_requeue_command(q, cmd);
+
+			return cmd;
+		}
+	}
+
+	add_disk_randomness(req->rq_disk);
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	if (blk_rq_tagged(req))
+		blk_queue_end_tag(q, req);
+	end_that_request_last(req);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	/*
+	 * This will goose the queue request function at the end, so we don't
+	 * need to worry about launching another command.
+	 */
+	scsi_next_command(cmd);
+	return NULL;
+}
+
+static struct scatterlist *scsi_alloc_sgtable(struct scsi_cmnd *cmd, int gfp_mask)
+{
+	struct scsi_host_sg_pool *sgp;
+	struct scatterlist *sgl;
+
+	BUG_ON(!cmd->use_sg);
+
+	switch (cmd->use_sg) {
+	case 1 ... 8:
+		cmd->sglist_len = 0;
+		break;
+	case 9 ... 16:
+		cmd->sglist_len = 1;
+		break;
+	case 17 ... 32:
+		cmd->sglist_len = 2;
+		break;
+#if (SCSI_MAX_PHYS_SEGMENTS > 32)
+	case 33 ... 64:
+		cmd->sglist_len = 3;
+		break;
+#if (SCSI_MAX_PHYS_SEGMENTS > 64)
+	case 65 ... 128:
+		cmd->sglist_len = 4;
+		break;
+#if (SCSI_MAX_PHYS_SEGMENTS  > 128)
+	case 129 ... 256:
+		cmd->sglist_len = 5;
+		break;
+#endif
+#endif
+#endif
+	default:
+		return NULL;
+	}
+
+	sgp = scsi_sg_pools + cmd->sglist_len;
+	sgl = mempool_alloc(sgp->pool, gfp_mask);
+	if (sgl)
+		memset(sgl, 0, sgp->size);
+	return sgl;
+}
+
+static void scsi_free_sgtable(struct scatterlist *sgl, int index)
+{
+	struct scsi_host_sg_pool *sgp;
+
+	BUG_ON(index > SG_MEMPOOL_NR);
+
+	sgp = scsi_sg_pools + index;
+	mempool_free(sgl, sgp->pool);
+}
+
+/*
+ * Function:    scsi_release_buffers()
+ *
+ * Purpose:     Completion processing for block device I/O requests.
+ *
+ * Arguments:   cmd	- command that we are bailing.
+ *
+ * Lock status: Assumed that no lock is held upon entry.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       In the event that an upper level driver rejects a
+ *		command, we must release resources allocated during
+ *		the __init_io() function.  Primarily this would involve
+ *		the scatter-gather table, and potentially any bounce
+ *		buffers.
+ */
+static void scsi_release_buffers(struct scsi_cmnd *cmd)
+{
+	struct request *req = cmd->request;
+
+	/*
+	 * Free up any indirection buffers we allocated for DMA purposes. 
+	 */
+	if (cmd->use_sg)
+		scsi_free_sgtable(cmd->request_buffer, cmd->sglist_len);
+	else if (cmd->request_buffer != req->buffer)
+		kfree(cmd->request_buffer);
+
+	/*
+	 * Zero these out.  They now point to freed memory, and it is
+	 * dangerous to hang onto the pointers.
+	 */
+	cmd->buffer  = NULL;
+	cmd->bufflen = 0;
+	cmd->request_buffer = NULL;
+	cmd->request_bufflen = 0;
+}
+
+/*
+ * Function:    scsi_io_completion()
+ *
+ * Purpose:     Completion processing for block device I/O requests.
+ *
+ * Arguments:   cmd   - command that is finished.
+ *
+ * Lock status: Assumed that no lock is held upon entry.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:       This function is matched in terms of capabilities to
+ *              the function that created the scatter-gather list.
+ *              In other words, if there are no bounce buffers
+ *              (the normal case for most drivers), we don't need
+ *              the logic to deal with cleaning up afterwards.
+ *
+ *		We must do one of several things here:
+ *
+ *		a) Call scsi_end_request.  This will finish off the
+ *		   specified number of sectors.  If we are done, the
+ *		   command block will be released, and the queue
+ *		   function will be goosed.  If we are not done, then
+ *		   scsi_end_request will directly goose the queue.
+ *
+ *		b) We can just use scsi_requeue_command() here.  This would
+ *		   be used if we just wanted to retry, for example.
+ */
+void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes,
+			unsigned int block_bytes)
+{
+	int result = cmd->result;
+	int this_count = cmd->bufflen;
+	request_queue_t *q = cmd->device->request_queue;
+	struct request *req = cmd->request;
+	int clear_errors = 1;
+	struct scsi_sense_hdr sshdr;
+	int sense_valid = 0;
+	int sense_deferred = 0;
+
+	if (blk_complete_barrier_rq(q, req, good_bytes >> 9))
+		return;
+
+	/*
+	 * Free up any indirection buffers we allocated for DMA purposes. 
+	 * For the case of a READ, we need to copy the data out of the
+	 * bounce buffer and into the real buffer.
+	 */
+	if (cmd->use_sg)
+		scsi_free_sgtable(cmd->buffer, cmd->sglist_len);
+	else if (cmd->buffer != req->buffer) {
+		if (rq_data_dir(req) == READ) {
+			unsigned long flags;
+			char *to = bio_kmap_irq(req->bio, &flags);
+			memcpy(to, cmd->buffer, cmd->bufflen);
+			bio_kunmap_irq(to, &flags);
+		}
+		kfree(cmd->buffer);
+	}
+
+	if (result) {
+		sense_valid = scsi_command_normalize_sense(cmd, &sshdr);
+		if (sense_valid)
+			sense_deferred = scsi_sense_is_deferred(&sshdr);
+	}
+	if (blk_pc_request(req)) { /* SG_IO ioctl from block level */
+		req->errors = result;
+		if (result) {
+			clear_errors = 0;
+			if (sense_valid && req->sense) {
+				/*
+				 * SG_IO wants current and deferred errors
+				 */
+				int len = 8 + cmd->sense_buffer[7];
+
+				if (len > SCSI_SENSE_BUFFERSIZE)
+					len = SCSI_SENSE_BUFFERSIZE;
+				memcpy(req->sense, cmd->sense_buffer,  len);
+				req->sense_len = len;
+			}
+		} else
+			req->data_len = cmd->resid;
+	}
+
+	/*
+	 * Zero these out.  They now point to freed memory, and it is
+	 * dangerous to hang onto the pointers.
+	 */
+	cmd->buffer  = NULL;
+	cmd->bufflen = 0;
+	cmd->request_buffer = NULL;
+	cmd->request_bufflen = 0;
+
+	/*
+	 * Next deal with any sectors which we were able to correctly
+	 * handle.
+	 */
+	if (good_bytes >= 0) {
+		SCSI_LOG_HLCOMPLETE(1, printk("%ld sectors total, %d bytes done.\n",
+					      req->nr_sectors, good_bytes));
+		SCSI_LOG_HLCOMPLETE(1, printk("use_sg is %d\n", cmd->use_sg));
+
+		if (clear_errors)
+			req->errors = 0;
+		/*
+		 * If multiple sectors are requested in one buffer, then
+		 * they will have been finished off by the first command.
+		 * If not, then we have a multi-buffer command.
+		 *
+		 * If block_bytes != 0, it means we had a medium error
+		 * of some sort, and that we want to mark some number of
+		 * sectors as not uptodate.  Thus we want to inhibit
+		 * requeueing right here - we will requeue down below
+		 * when we handle the bad sectors.
+		 */
+		cmd = scsi_end_request(cmd, 1, good_bytes, result == 0);
+
+		/*
+		 * If the command completed without error, then either finish off the
+		 * rest of the command, or start a new one.
+		 */
+		if (result == 0 || cmd == NULL ) {
+			return;
+		}
+	}
+	/*
+	 * Now, if we were good little boys and girls, Santa left us a request
+	 * sense buffer.  We can extract information from this, so we
+	 * can choose a block to remap, etc.
+	 */
+	if (sense_valid && !sense_deferred) {
+		switch (sshdr.sense_key) {
+		case UNIT_ATTENTION:
+			if (cmd->device->removable) {
+				/* detected disc change.  set a bit 
+				 * and quietly refuse further access.
+				 */
+				cmd->device->changed = 1;
+				cmd = scsi_end_request(cmd, 0,
+						this_count, 1);
+				return;
+			} else {
+				/*
+				* Must have been a power glitch, or a
+				* bus reset.  Could not have been a
+				* media change, so we just retry the
+				* request and see what happens.  
+				*/
+				scsi_requeue_command(q, cmd);
+				return;
+			}
+			break;
+		case ILLEGAL_REQUEST:
+			/*
+		 	* If we had an ILLEGAL REQUEST returned, then we may
+		 	* have performed an unsupported command.  The only
+		 	* thing this should be would be a ten byte read where
+			* only a six byte read was supported.  Also, on a
+			* system where READ CAPACITY failed, we may have read
+			* past the end of the disk.
+		 	*/
+			if (cmd->device->use_10_for_rw &&
+			    (cmd->cmnd[0] == READ_10 ||
+			     cmd->cmnd[0] == WRITE_10)) {
+				cmd->device->use_10_for_rw = 0;
+				/*
+				 * This will cause a retry with a 6-byte
+				 * command.
+				 */
+				scsi_requeue_command(q, cmd);
+				result = 0;
+			} else {
+				cmd = scsi_end_request(cmd, 0, this_count, 1);
+				return;
+			}
+			break;
+		case NOT_READY:
+			/*
+			 * If the device is in the process of becoming ready,
+			 * retry.
+			 */
+			if (sshdr.asc == 0x04 && sshdr.ascq == 0x01) {
+				scsi_requeue_command(q, cmd);
+				return;
+			}
+			printk(KERN_INFO "Device %s not ready.\n",
+			       req->rq_disk ? req->rq_disk->disk_name : "");
+			cmd = scsi_end_request(cmd, 0, this_count, 1);
+			return;
+		case VOLUME_OVERFLOW:
+			printk(KERN_INFO "Volume overflow <%d %d %d %d> CDB: ",
+			       cmd->device->host->host_no,
+			       (int)cmd->device->channel,
+			       (int)cmd->device->id, (int)cmd->device->lun);
+			__scsi_print_command(cmd->data_cmnd);
+			scsi_print_sense("", cmd);
+			cmd = scsi_end_request(cmd, 0, block_bytes, 1);
+			return;
+		default:
+			break;
+		}
+	}			/* driver byte != 0 */
+	if (host_byte(result) == DID_RESET) {
+		/*
+		 * Third party bus reset or reset for error
+		 * recovery reasons.  Just retry the request
+		 * and see what happens.  
+		 */
+		scsi_requeue_command(q, cmd);
+		return;
+	}
+	if (result) {
+		printk(KERN_INFO "SCSI error : <%d %d %d %d> return code "
+		       "= 0x%x\n", cmd->device->host->host_no,
+		       cmd->device->channel,
+		       cmd->device->id,
+		       cmd->device->lun, result);
+
+		if (driver_byte(result) & DRIVER_SENSE)
+			scsi_print_sense("", cmd);
+		/*
+		 * Mark a single buffer as not uptodate.  Queue the remainder.
+		 * We sometimes get this cruft in the event that a medium error
+		 * isn't properly reported.
+		 */
+		block_bytes = req->hard_cur_sectors << 9;
+		if (!block_bytes)
+			block_bytes = req->data_len;
+		cmd = scsi_end_request(cmd, 0, block_bytes, 1);
+	}
+}
+EXPORT_SYMBOL(scsi_io_completion);
+
+/*
+ * Function:    scsi_init_io()
+ *
+ * Purpose:     SCSI I/O initialize function.
+ *
+ * Arguments:   cmd   - Command descriptor we wish to initialize
+ *
+ * Returns:     0 on success
+ *		BLKPREP_DEFER if the failure is retryable
+ *		BLKPREP_KILL if the failure is fatal
+ */
+static int scsi_init_io(struct scsi_cmnd *cmd)
+{
+	struct request     *req = cmd->request;
+	struct scatterlist *sgpnt;
+	int		   count;
+
+	/*
+	 * if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
+	 */
+	if ((req->flags & REQ_BLOCK_PC) && !req->bio) {
+		cmd->request_bufflen = req->data_len;
+		cmd->request_buffer = req->data;
+		req->buffer = req->data;
+		cmd->use_sg = 0;
+		return 0;
+	}
+
+	/*
+	 * we used to not use scatter-gather for single segment request,
+	 * but now we do (it makes highmem I/O easier to support without
+	 * kmapping pages)
+	 */
+	cmd->use_sg = req->nr_phys_segments;
+
+	/*
+	 * if sg table allocation fails, requeue request later.
+	 */
+	sgpnt = scsi_alloc_sgtable(cmd, GFP_ATOMIC);
+	if (unlikely(!sgpnt)) {
+		req->flags |= REQ_SPECIAL;
+		return BLKPREP_DEFER;
+	}
+
+	cmd->request_buffer = (char *) sgpnt;
+	cmd->request_bufflen = req->nr_sectors << 9;
+	if (blk_pc_request(req))
+		cmd->request_bufflen = req->data_len;
+	req->buffer = NULL;
+
+	/* 
+	 * Next, walk the list, and fill in the addresses and sizes of
+	 * each segment.
+	 */
+	count = blk_rq_map_sg(req->q, req, cmd->request_buffer);
+
+	/*
+	 * mapped well, send it off
+	 */
+	if (likely(count <= cmd->use_sg)) {
+		cmd->use_sg = count;
+		return 0;
+	}
+
+	printk(KERN_ERR "Incorrect number of segments after building list\n");
+	printk(KERN_ERR "counted %d, received %d\n", count, cmd->use_sg);
+	printk(KERN_ERR "req nr_sec %lu, cur_nr_sec %u\n", req->nr_sectors,
+			req->current_nr_sectors);
+
+	/* release the command and kill it */
+	scsi_release_buffers(cmd);
+	scsi_put_command(cmd);
+	return BLKPREP_KILL;
+}
+
+static int scsi_prepare_flush_fn(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_driver *drv;
+
+	if (sdev->sdev_state == SDEV_RUNNING) {
+		drv = *(struct scsi_driver **) rq->rq_disk->private_data;
+
+		if (drv->prepare_flush)
+			return drv->prepare_flush(q, rq);
+	}
+
+	return 0;
+}
+
+static void scsi_end_flush_fn(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct request *flush_rq = rq->end_io_data;
+	struct scsi_driver *drv;
+
+	if (flush_rq->errors) {
+		printk("scsi: barrier error, disabling flush support\n");
+		blk_queue_ordered(q, QUEUE_ORDERED_NONE);
+	}
+
+	if (sdev->sdev_state == SDEV_RUNNING) {
+		drv = *(struct scsi_driver **) rq->rq_disk->private_data;
+		drv->end_flush(q, rq);
+	}
+}
+
+static int scsi_issue_flush_fn(request_queue_t *q, struct gendisk *disk,
+			       sector_t *error_sector)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_driver *drv;
+
+	if (sdev->sdev_state != SDEV_RUNNING)
+		return -ENXIO;
+
+	drv = *(struct scsi_driver **) disk->private_data;
+	if (drv->issue_flush)
+		return drv->issue_flush(&sdev->sdev_gendev, error_sector);
+
+	return -EOPNOTSUPP;
+}
+
+static int scsi_prep_fn(struct request_queue *q, struct request *req)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_cmnd *cmd;
+	int specials_only = 0;
+
+	/*
+	 * Just check to see if the device is online.  If it isn't, we
+	 * refuse to process any commands.  The device must be brought
+	 * online before trying any recovery commands
+	 */
+	if (unlikely(!scsi_device_online(sdev))) {
+		printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
+		       sdev->host->host_no, sdev->id, sdev->lun);
+		return BLKPREP_KILL;
+	}
+	if (unlikely(sdev->sdev_state != SDEV_RUNNING)) {
+		/* OK, we're not in a running state don't prep
+		 * user commands */
+		if (sdev->sdev_state == SDEV_DEL) {
+			/* Device is fully deleted, no commands
+			 * at all allowed down */
+			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to dead device\n",
+			       sdev->host->host_no, sdev->id, sdev->lun);
+			return BLKPREP_KILL;
+		}
+		/* OK, we only allow special commands (i.e. not
+		 * user initiated ones */
+		specials_only = sdev->sdev_state;
+	}
+
+	/*
+	 * Find the actual device driver associated with this command.
+	 * The SPECIAL requests are things like character device or
+	 * ioctls, which did not originate from ll_rw_blk.  Note that
+	 * the special field is also used to indicate the cmd for
+	 * the remainder of a partially fulfilled request that can 
+	 * come up when there is a medium error.  We have to treat
+	 * these two cases differently.  We differentiate by looking
+	 * at request->cmd, as this tells us the real story.
+	 */
+	if (req->flags & REQ_SPECIAL) {
+		struct scsi_request *sreq = req->special;
+
+		if (sreq->sr_magic == SCSI_REQ_MAGIC) {
+			cmd = scsi_get_command(sreq->sr_device, GFP_ATOMIC);
+			if (unlikely(!cmd))
+				goto defer;
+			scsi_init_cmd_from_req(cmd, sreq);
+		} else
+			cmd = req->special;
+	} else if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+
+		if(unlikely(specials_only)) {
+			if(specials_only == SDEV_QUIESCE ||
+					specials_only == SDEV_BLOCK)
+				return BLKPREP_DEFER;
+			
+			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to device being removed\n",
+			       sdev->host->host_no, sdev->id, sdev->lun);
+			return BLKPREP_KILL;
+		}
+			
+			
+		/*
+		 * Now try and find a command block that we can use.
+		 */
+		if (!req->special) {
+			cmd = scsi_get_command(sdev, GFP_ATOMIC);
+			if (unlikely(!cmd))
+				goto defer;
+		} else
+			cmd = req->special;
+		
+		/* pull a tag out of the request if we have one */
+		cmd->tag = req->tag;
+	} else {
+		blk_dump_rq_flags(req, "SCSI bad req");
+		return BLKPREP_KILL;
+	}
+	
+	/* note the overloading of req->special.  When the tag
+	 * is active it always means cmd.  If the tag goes
+	 * back for re-queueing, it may be reset */
+	req->special = cmd;
+	cmd->request = req;
+	
+	/*
+	 * FIXME: drop the lock here because the functions below
+	 * expect to be called without the queue lock held.  Also,
+	 * previously, we dequeued the request before dropping the
+	 * lock.  We hope REQ_STARTED prevents anything untoward from
+	 * happening now.
+	 */
+	if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) {
+		struct scsi_driver *drv;
+		int ret;
+
+		/*
+		 * This will do a couple of things:
+		 *  1) Fill in the actual SCSI command.
+		 *  2) Fill in any other upper-level specific fields
+		 * (timeout).
+		 *
+		 * If this returns 0, it means that the request failed
+		 * (reading past end of disk, reading offline device,
+		 * etc).   This won't actually talk to the device, but
+		 * some kinds of consistency checking may cause the	
+		 * request to be rejected immediately.
+		 */
+
+		/* 
+		 * This sets up the scatter-gather table (allocating if
+		 * required).
+		 */
+		ret = scsi_init_io(cmd);
+		if (ret)	/* BLKPREP_KILL return also releases the command */
+			return ret;
+		
+		/*
+		 * Initialize the actual SCSI command for this request.
+		 */
+		drv = *(struct scsi_driver **)req->rq_disk->private_data;
+		if (unlikely(!drv->init_command(cmd))) {
+			scsi_release_buffers(cmd);
+			scsi_put_command(cmd);
+			return BLKPREP_KILL;
+		}
+	}
+
+	/*
+	 * The request is now prepped, no need to come back here
+	 */
+	req->flags |= REQ_DONTPREP;
+	return BLKPREP_OK;
+
+ defer:
+	/* If we defer, the elv_next_request() returns NULL, but the
+	 * queue must be restarted, so we plug here if no returning
+	 * command will automatically do that. */
+	if (sdev->device_busy == 0)
+		blk_plug_device(q);
+	return BLKPREP_DEFER;
+}
+
+/*
+ * scsi_dev_queue_ready: if we can send requests to sdev, return 1 else
+ * return 0.
+ *
+ * Called with the queue_lock held.
+ */
+static inline int scsi_dev_queue_ready(struct request_queue *q,
+				  struct scsi_device *sdev)
+{
+	if (sdev->device_busy >= sdev->queue_depth)
+		return 0;
+	if (sdev->device_busy == 0 && sdev->device_blocked) {
+		/*
+		 * unblock after device_blocked iterates to zero
+		 */
+		if (--sdev->device_blocked == 0) {
+			SCSI_LOG_MLQUEUE(3,
+				printk("scsi%d (%d:%d) unblocking device at"
+				       " zero depth\n", sdev->host->host_no,
+				       sdev->id, sdev->lun));
+		} else {
+			blk_plug_device(q);
+			return 0;
+		}
+	}
+	if (sdev->device_blocked)
+		return 0;
+
+	return 1;
+}
+
+/*
+ * scsi_host_queue_ready: if we can send requests to shost, return 1 else
+ * return 0. We must end up running the queue again whenever 0 is
+ * returned, else IO can hang.
+ *
+ * Called with host_lock held.
+ */
+static inline int scsi_host_queue_ready(struct request_queue *q,
+				   struct Scsi_Host *shost,
+				   struct scsi_device *sdev)
+{
+	if (test_bit(SHOST_RECOVERY, &shost->shost_state))
+		return 0;
+	if (shost->host_busy == 0 && shost->host_blocked) {
+		/*
+		 * unblock after host_blocked iterates to zero
+		 */
+		if (--shost->host_blocked == 0) {
+			SCSI_LOG_MLQUEUE(3,
+				printk("scsi%d unblocking host at zero depth\n",
+					shost->host_no));
+		} else {
+			blk_plug_device(q);
+			return 0;
+		}
+	}
+	if ((shost->can_queue > 0 && shost->host_busy >= shost->can_queue) ||
+	    shost->host_blocked || shost->host_self_blocked) {
+		if (list_empty(&sdev->starved_entry))
+			list_add_tail(&sdev->starved_entry, &shost->starved_list);
+		return 0;
+	}
+
+	/* We're OK to process the command, so we can't be starved */
+	if (!list_empty(&sdev->starved_entry))
+		list_del_init(&sdev->starved_entry);
+
+	return 1;
+}
+
+/*
+ * Kill requests for a dead device
+ */
+static void scsi_kill_requests(request_queue_t *q)
+{
+	struct request *req;
+
+	while ((req = elv_next_request(q)) != NULL) {
+		blkdev_dequeue_request(req);
+		req->flags |= REQ_QUIET;
+		while (end_that_request_first(req, 0, req->nr_sectors))
+			;
+		end_that_request_last(req);
+	}
+}
+
+/*
+ * Function:    scsi_request_fn()
+ *
+ * Purpose:     Main strategy routine for SCSI.
+ *
+ * Arguments:   q       - Pointer to actual queue.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: IO request lock assumed to be held when called.
+ */
+static void scsi_request_fn(struct request_queue *q)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct Scsi_Host *shost;
+	struct scsi_cmnd *cmd;
+	struct request *req;
+
+	if (!sdev) {
+		printk("scsi: killing requests for dead queue\n");
+		scsi_kill_requests(q);
+		return;
+	}
+
+	if(!get_device(&sdev->sdev_gendev))
+		/* We must be tearing the block queue down already */
+		return;
+
+	/*
+	 * To start with, we keep looping until the queue is empty, or until
+	 * the host is no longer able to accept any more requests.
+	 */
+	shost = sdev->host;
+	while (!blk_queue_plugged(q)) {
+		int rtn;
+		/*
+		 * get next queueable request.  We do this early to make sure
+		 * that the request is fully prepared even if we cannot 
+		 * accept it.
+		 */
+		req = elv_next_request(q);
+		if (!req || !scsi_dev_queue_ready(q, sdev))
+			break;
+
+		if (unlikely(!scsi_device_online(sdev))) {
+			printk(KERN_ERR "scsi%d (%d:%d): rejecting I/O to offline device\n",
+			       sdev->host->host_no, sdev->id, sdev->lun);
+			blkdev_dequeue_request(req);
+			req->flags |= REQ_QUIET;
+			while (end_that_request_first(req, 0, req->nr_sectors))
+				;
+			end_that_request_last(req);
+			continue;
+		}
+
+
+		/*
+		 * Remove the request from the request list.
+		 */
+		if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
+			blkdev_dequeue_request(req);
+		sdev->device_busy++;
+
+		spin_unlock(q->queue_lock);
+		spin_lock(shost->host_lock);
+
+		if (!scsi_host_queue_ready(q, shost, sdev))
+			goto not_ready;
+		if (sdev->single_lun) {
+			if (scsi_target(sdev)->starget_sdev_user &&
+			    scsi_target(sdev)->starget_sdev_user != sdev)
+				goto not_ready;
+			scsi_target(sdev)->starget_sdev_user = sdev;
+		}
+		shost->host_busy++;
+
+		/*
+		 * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will
+		 *		take the lock again.
+		 */
+		spin_unlock_irq(shost->host_lock);
+
+		cmd = req->special;
+		if (unlikely(cmd == NULL)) {
+			printk(KERN_CRIT "impossible request in %s.\n"
+					 "please mail a stack trace to "
+					 "linux-scsi@vger.kernel.org",
+					 __FUNCTION__);
+			BUG();
+		}
+
+		/*
+		 * Finally, initialize any error handling parameters, and set up
+		 * the timers for timeouts.
+		 */
+		scsi_init_cmd_errh(cmd);
+
+		/*
+		 * Dispatch the command to the low-level driver.
+		 */
+		rtn = scsi_dispatch_cmd(cmd);
+		spin_lock_irq(q->queue_lock);
+		if(rtn) {
+			/* we're refusing the command; because of
+			 * the way locks get dropped, we need to 
+			 * check here if plugging is required */
+			if(sdev->device_busy == 0)
+				blk_plug_device(q);
+
+			break;
+		}
+	}
+
+	goto out;
+
+ not_ready:
+	spin_unlock_irq(shost->host_lock);
+
+	/*
+	 * lock q, handle tag, requeue req, and decrement device_busy. We
+	 * must return with queue_lock held.
+	 *
+	 * Decrementing device_busy without checking it is OK, as all such
+	 * cases (host limits or settings) should run the queue at some
+	 * later time.
+	 */
+	spin_lock_irq(q->queue_lock);
+	blk_requeue_request(q, req);
+	sdev->device_busy--;
+	if(sdev->device_busy == 0)
+		blk_plug_device(q);
+ out:
+	/* must be careful here...if we trigger the ->remove() function
+	 * we cannot be holding the q lock */
+	spin_unlock_irq(q->queue_lock);
+	put_device(&sdev->sdev_gendev);
+	spin_lock_irq(q->queue_lock);
+}
+
+u64 scsi_calculate_bounce_limit(struct Scsi_Host *shost)
+{
+	struct device *host_dev;
+	u64 bounce_limit = 0xffffffff;
+
+	if (shost->unchecked_isa_dma)
+		return BLK_BOUNCE_ISA;
+	/*
+	 * Platforms with virtual-DMA translation
+	 * hardware have no practical limit.
+	 */
+	if (!PCI_DMA_BUS_IS_PHYS)
+		return BLK_BOUNCE_ANY;
+
+	host_dev = scsi_get_device(shost);
+	if (host_dev && host_dev->dma_mask)
+		bounce_limit = *host_dev->dma_mask;
+
+	return bounce_limit;
+}
+EXPORT_SYMBOL(scsi_calculate_bounce_limit);
+
+struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
+{
+	struct Scsi_Host *shost = sdev->host;
+	struct request_queue *q;
+
+	q = blk_init_queue(scsi_request_fn, &sdev->sdev_lock);
+	if (!q)
+		return NULL;
+
+	blk_queue_prep_rq(q, scsi_prep_fn);
+
+	blk_queue_max_hw_segments(q, shost->sg_tablesize);
+	blk_queue_max_phys_segments(q, SCSI_MAX_PHYS_SEGMENTS);
+	blk_queue_max_sectors(q, shost->max_sectors);
+	blk_queue_bounce_limit(q, scsi_calculate_bounce_limit(shost));
+	blk_queue_segment_boundary(q, shost->dma_boundary);
+	blk_queue_issue_flush_fn(q, scsi_issue_flush_fn);
+
+	/*
+	 * ordered tags are superior to flush ordering
+	 */
+	if (shost->ordered_tag)
+		blk_queue_ordered(q, QUEUE_ORDERED_TAG);
+	else if (shost->ordered_flush) {
+		blk_queue_ordered(q, QUEUE_ORDERED_FLUSH);
+		q->prepare_flush_fn = scsi_prepare_flush_fn;
+		q->end_flush_fn = scsi_end_flush_fn;
+	}
+
+	if (!shost->use_clustering)
+		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
+	return q;
+}
+
+void scsi_free_queue(struct request_queue *q)
+{
+	blk_cleanup_queue(q);
+}
+
+/*
+ * Function:    scsi_block_requests()
+ *
+ * Purpose:     Utility function used by low-level drivers to prevent further
+ *		commands from being queued to the device.
+ *
+ * Arguments:   shost       - Host in question
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       There is no timer nor any other means by which the requests
+ *		get unblocked other than the low-level driver calling
+ *		scsi_unblock_requests().
+ */
+void scsi_block_requests(struct Scsi_Host *shost)
+{
+	shost->host_self_blocked = 1;
+}
+EXPORT_SYMBOL(scsi_block_requests);
+
+/*
+ * Function:    scsi_unblock_requests()
+ *
+ * Purpose:     Utility function used by low-level drivers to allow further
+ *		commands from being queued to the device.
+ *
+ * Arguments:   shost       - Host in question
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       There is no timer nor any other means by which the requests
+ *		get unblocked other than the low-level driver calling
+ *		scsi_unblock_requests().
+ *
+ *		This is done as an API function so that changes to the
+ *		internals of the scsi mid-layer won't require wholesale
+ *		changes to drivers that use this feature.
+ */
+void scsi_unblock_requests(struct Scsi_Host *shost)
+{
+	shost->host_self_blocked = 0;
+	scsi_run_host_queues(shost);
+}
+EXPORT_SYMBOL(scsi_unblock_requests);
+
+int __init scsi_init_queue(void)
+{
+	int i;
+
+	for (i = 0; i < SG_MEMPOOL_NR; i++) {
+		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
+		int size = sgp->size * sizeof(struct scatterlist);
+
+		sgp->slab = kmem_cache_create(sgp->name, size, 0,
+				SLAB_HWCACHE_ALIGN, NULL, NULL);
+		if (!sgp->slab) {
+			printk(KERN_ERR "SCSI: can't init sg slab %s\n",
+					sgp->name);
+		}
+
+		sgp->pool = mempool_create(SG_MEMPOOL_SIZE,
+				mempool_alloc_slab, mempool_free_slab,
+				sgp->slab);
+		if (!sgp->pool) {
+			printk(KERN_ERR "SCSI: can't init sg mempool %s\n",
+					sgp->name);
+		}
+	}
+
+	return 0;
+}
+
+void scsi_exit_queue(void)
+{
+	int i;
+
+	for (i = 0; i < SG_MEMPOOL_NR; i++) {
+		struct scsi_host_sg_pool *sgp = scsi_sg_pools + i;
+		mempool_destroy(sgp->pool);
+		kmem_cache_destroy(sgp->slab);
+	}
+}
+/**
+ *	__scsi_mode_sense - issue a mode sense, falling back from 10 to 
+ *		six bytes if necessary.
+ *	@sreq:	SCSI request to fill in with the MODE_SENSE
+ *	@dbd:	set if mode sense will allow block descriptors to be returned
+ *	@modepage: mode page being requested
+ *	@buffer: request buffer (may not be smaller than eight bytes)
+ *	@len:	length of request buffer.
+ *	@timeout: command timeout
+ *	@retries: number of retries before failing
+ *	@data: returns a structure abstracting the mode header data
+ *
+ *	Returns zero if unsuccessful, or the header offset (either 4
+ *	or 8 depending on whether a six or ten byte command was
+ *	issued) if successful.
+ **/
+int
+__scsi_mode_sense(struct scsi_request *sreq, int dbd, int modepage,
+		  unsigned char *buffer, int len, int timeout, int retries,
+		  struct scsi_mode_data *data) {
+	unsigned char cmd[12];
+	int use_10_for_ms;
+	int header_length;
+
+	memset(data, 0, sizeof(*data));
+	memset(&cmd[0], 0, 12);
+	cmd[1] = dbd & 0x18;	/* allows DBD and LLBA bits */
+	cmd[2] = modepage;
+
+ retry:
+	use_10_for_ms = sreq->sr_device->use_10_for_ms;
+
+	if (use_10_for_ms) {
+		if (len < 8)
+			len = 8;
+
+		cmd[0] = MODE_SENSE_10;
+		cmd[8] = len;
+		header_length = 8;
+	} else {
+		if (len < 4)
+			len = 4;
+
+		cmd[0] = MODE_SENSE;
+		cmd[4] = len;
+		header_length = 4;
+	}
+
+	sreq->sr_cmd_len = 0;
+	memset(sreq->sr_sense_buffer, 0, sizeof(sreq->sr_sense_buffer));
+	sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+	memset(buffer, 0, len);
+
+	scsi_wait_req(sreq, cmd, buffer, len, timeout, retries);
+
+	/* This code looks awful: what it's doing is making sure an
+	 * ILLEGAL REQUEST sense return identifies the actual command
+	 * byte as the problem.  MODE_SENSE commands can return
+	 * ILLEGAL REQUEST if the code page isn't supported */
+
+	if (use_10_for_ms && !scsi_status_is_good(sreq->sr_result) &&
+	    (driver_byte(sreq->sr_result) & DRIVER_SENSE)) {
+		struct scsi_sense_hdr sshdr;
+
+		if (scsi_request_normalize_sense(sreq, &sshdr)) {
+			if ((sshdr.sense_key == ILLEGAL_REQUEST) &&
+			    (sshdr.asc == 0x20) && (sshdr.ascq == 0)) {
+				/* 
+				 * Invalid command operation code
+				 */
+				sreq->sr_device->use_10_for_ms = 0;
+				goto retry;
+			}
+		}
+	}
+
+	if(scsi_status_is_good(sreq->sr_result)) {
+		data->header_length = header_length;
+		if(use_10_for_ms) {
+			data->length = buffer[0]*256 + buffer[1] + 2;
+			data->medium_type = buffer[2];
+			data->device_specific = buffer[3];
+			data->longlba = buffer[4] & 0x01;
+			data->block_descriptor_length = buffer[6]*256
+				+ buffer[7];
+		} else {
+			data->length = buffer[0] + 1;
+			data->medium_type = buffer[1];
+			data->device_specific = buffer[2];
+			data->block_descriptor_length = buffer[3];
+		}
+	}
+
+	return sreq->sr_result;
+}
+EXPORT_SYMBOL(__scsi_mode_sense);
+
+/**
+ *	scsi_mode_sense - issue a mode sense, falling back from 10 to 
+ *		six bytes if necessary.
+ *	@sdev:	scsi device to send command to.
+ *	@dbd:	set if mode sense will disable block descriptors in the return
+ *	@modepage: mode page being requested
+ *	@buffer: request buffer (may not be smaller than eight bytes)
+ *	@len:	length of request buffer.
+ *	@timeout: command timeout
+ *	@retries: number of retries before failing
+ *
+ *	Returns zero if unsuccessful, or the header offset (either 4
+ *	or 8 depending on whether a six or ten byte command was
+ *	issued) if successful.
+ **/
+int
+scsi_mode_sense(struct scsi_device *sdev, int dbd, int modepage,
+		unsigned char *buffer, int len, int timeout, int retries,
+		struct scsi_mode_data *data)
+{
+	struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	int ret;
+
+	if (!sreq)
+		return -1;
+
+	ret = __scsi_mode_sense(sreq, dbd, modepage, buffer, len,
+				timeout, retries, data);
+
+	scsi_release_request(sreq);
+
+	return ret;
+}
+EXPORT_SYMBOL(scsi_mode_sense);
+
+int
+scsi_test_unit_ready(struct scsi_device *sdev, int timeout, int retries)
+{
+	struct scsi_request *sreq;
+	char cmd[] = {
+		TEST_UNIT_READY, 0, 0, 0, 0, 0,
+	};
+	int result;
+	
+	sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	if (!sreq)
+		return -ENOMEM;
+
+	sreq->sr_data_direction = DMA_NONE;
+	scsi_wait_req(sreq, cmd, NULL, 0, timeout, retries);
+
+	if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) && sdev->removable) {
+		struct scsi_sense_hdr sshdr;
+
+		if ((scsi_request_normalize_sense(sreq, &sshdr)) &&
+		    ((sshdr.sense_key == UNIT_ATTENTION) ||
+		     (sshdr.sense_key == NOT_READY))) {
+			sdev->changed = 1;
+			sreq->sr_result = 0;
+		}
+	}
+	result = sreq->sr_result;
+	scsi_release_request(sreq);
+	return result;
+}
+EXPORT_SYMBOL(scsi_test_unit_ready);
+
+/**
+ *	scsi_device_set_state - Take the given device through the device
+ *		state model.
+ *	@sdev:	scsi device to change the state of.
+ *	@state:	state to change to.
+ *
+ *	Returns zero if unsuccessful or an error if the requested 
+ *	transition is illegal.
+ **/
+int
+scsi_device_set_state(struct scsi_device *sdev, enum scsi_device_state state)
+{
+	enum scsi_device_state oldstate = sdev->sdev_state;
+
+	if (state == oldstate)
+		return 0;
+
+	switch (state) {
+	case SDEV_CREATED:
+		/* There are no legal states that come back to
+		 * created.  This is the manually initialised start
+		 * state */
+		goto illegal;
+			
+	case SDEV_RUNNING:
+		switch (oldstate) {
+		case SDEV_CREATED:
+		case SDEV_OFFLINE:
+		case SDEV_QUIESCE:
+		case SDEV_BLOCK:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_QUIESCE:
+		switch (oldstate) {
+		case SDEV_RUNNING:
+		case SDEV_OFFLINE:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_OFFLINE:
+		switch (oldstate) {
+		case SDEV_CREATED:
+		case SDEV_RUNNING:
+		case SDEV_QUIESCE:
+		case SDEV_BLOCK:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_BLOCK:
+		switch (oldstate) {
+		case SDEV_CREATED:
+		case SDEV_RUNNING:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_CANCEL:
+		switch (oldstate) {
+		case SDEV_CREATED:
+		case SDEV_RUNNING:
+		case SDEV_OFFLINE:
+		case SDEV_BLOCK:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	case SDEV_DEL:
+		switch (oldstate) {
+		case SDEV_CANCEL:
+			break;
+		default:
+			goto illegal;
+		}
+		break;
+
+	}
+	sdev->sdev_state = state;
+	return 0;
+
+ illegal:
+	SCSI_LOG_ERROR_RECOVERY(1, 
+				dev_printk(KERN_ERR, &sdev->sdev_gendev,
+					   "Illegal state transition %s->%s\n",
+					   scsi_device_state_name(oldstate),
+					   scsi_device_state_name(state))
+				);
+	return -EINVAL;
+}
+EXPORT_SYMBOL(scsi_device_set_state);
+
+/**
+ *	scsi_device_quiesce - Block user issued commands.
+ *	@sdev:	scsi device to quiesce.
+ *
+ *	This works by trying to transition to the SDEV_QUIESCE state
+ *	(which must be a legal transition).  When the device is in this
+ *	state, only special requests will be accepted, all others will
+ *	be deferred.  Since special requests may also be requeued requests,
+ *	a successful return doesn't guarantee the device will be 
+ *	totally quiescent.
+ *
+ *	Must be called with user context, may sleep.
+ *
+ *	Returns zero if unsuccessful or an error if not.
+ **/
+int
+scsi_device_quiesce(struct scsi_device *sdev)
+{
+	int err = scsi_device_set_state(sdev, SDEV_QUIESCE);
+	if (err)
+		return err;
+
+	scsi_run_queue(sdev->request_queue);
+	while (sdev->device_busy) {
+		msleep_interruptible(200);
+		scsi_run_queue(sdev->request_queue);
+	}
+	return 0;
+}
+EXPORT_SYMBOL(scsi_device_quiesce);
+
+/**
+ *	scsi_device_resume - Restart user issued commands to a quiesced device.
+ *	@sdev:	scsi device to resume.
+ *
+ *	Moves the device from quiesced back to running and restarts the
+ *	queues.
+ *
+ *	Must be called with user context, may sleep.
+ **/
+void
+scsi_device_resume(struct scsi_device *sdev)
+{
+	if(scsi_device_set_state(sdev, SDEV_RUNNING))
+		return;
+	scsi_run_queue(sdev->request_queue);
+}
+EXPORT_SYMBOL(scsi_device_resume);
+
+static void
+device_quiesce_fn(struct scsi_device *sdev, void *data)
+{
+	scsi_device_quiesce(sdev);
+}
+
+void
+scsi_target_quiesce(struct scsi_target *starget)
+{
+	starget_for_each_device(starget, NULL, device_quiesce_fn);
+}
+EXPORT_SYMBOL(scsi_target_quiesce);
+
+static void
+device_resume_fn(struct scsi_device *sdev, void *data)
+{
+	scsi_device_resume(sdev);
+}
+
+void
+scsi_target_resume(struct scsi_target *starget)
+{
+	starget_for_each_device(starget, NULL, device_resume_fn);
+}
+EXPORT_SYMBOL(scsi_target_resume);
+
+/**
+ * scsi_internal_device_block - internal function to put a device
+ *				temporarily into the SDEV_BLOCK state
+ * @sdev:	device to block
+ *
+ * Block request made by scsi lld's to temporarily stop all
+ * scsi commands on the specified device.  Called from interrupt
+ * or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:       
+ *	This routine transitions the device to the SDEV_BLOCK state
+ *	(which must be a legal transition).  When the device is in this
+ *	state, all commands are deferred until the scsi lld reenables
+ *	the device with scsi_device_unblock or device_block_tmo fires.
+ *	This routine assumes the host_lock is held on entry.
+ **/
+int
+scsi_internal_device_block(struct scsi_device *sdev)
+{
+	request_queue_t *q = sdev->request_queue;
+	unsigned long flags;
+	int err = 0;
+
+	err = scsi_device_set_state(sdev, SDEV_BLOCK);
+	if (err)
+		return err;
+
+	/* 
+	 * The device has transitioned to SDEV_BLOCK.  Stop the
+	 * block layer from calling the midlayer with this device's
+	 * request queue. 
+	 */
+	spin_lock_irqsave(q->queue_lock, flags);
+	blk_stop_queue(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_block);
+ 
+/**
+ * scsi_internal_device_unblock - resume a device after a block request
+ * @sdev:	device to resume
+ *
+ * Called by scsi lld's or the midlayer to restart the device queue
+ * for the previously suspended scsi device.  Called from interrupt or
+ * normal process context.
+ *
+ * Returns zero if successful or error if not.
+ *
+ * Notes:       
+ *	This routine transitions the device to the SDEV_RUNNING state
+ *	(which must be a legal transition) allowing the midlayer to
+ *	goose the queue for this device.  This routine assumes the 
+ *	host_lock is held upon entry.
+ **/
+int
+scsi_internal_device_unblock(struct scsi_device *sdev)
+{
+	request_queue_t *q = sdev->request_queue; 
+	int err;
+	unsigned long flags;
+	
+	/* 
+	 * Try to transition the scsi device to SDEV_RUNNING
+	 * and goose the device queue if successful.  
+	 */
+	err = scsi_device_set_state(sdev, SDEV_RUNNING);
+	if (err)
+		return err;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	blk_start_queue(q);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(scsi_internal_device_unblock);
+
+static void
+device_block(struct scsi_device *sdev, void *data)
+{
+	scsi_internal_device_block(sdev);
+}
+
+static int
+target_block(struct device *dev, void *data)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_block);
+	return 0;
+}
+
+void
+scsi_target_block(struct device *dev)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_block);
+	else
+		device_for_each_child(dev, NULL, target_block);
+}
+EXPORT_SYMBOL_GPL(scsi_target_block);
+
+static void
+device_unblock(struct scsi_device *sdev, void *data)
+{
+	scsi_internal_device_unblock(sdev);
+}
+
+static int
+target_unblock(struct device *dev, void *data)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_unblock);
+	return 0;
+}
+
+void
+scsi_target_unblock(struct device *dev)
+{
+	if (scsi_is_target_device(dev))
+		starget_for_each_device(to_scsi_target(dev), NULL,
+					device_unblock);
+	else
+		device_for_each_child(dev, NULL, target_unblock);
+}
+EXPORT_SYMBOL_GPL(scsi_target_unblock);
diff --git a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h
new file mode 100644
index 0000000..e1722ba
--- /dev/null
+++ b/drivers/scsi/scsi_logging.h
@@ -0,0 +1,82 @@
+#ifndef _SCSI_LOGGING_H
+#define _SCSI_LOGGING_H
+
+#include <linux/config.h>
+
+/*
+ * This defines the scsi logging feature.  It is a means by which the user
+ * can select how much information they get about various goings on, and it
+ * can be really useful for fault tracing.  The logging word is divided into
+ * 8 nibbles, each of which describes a loglevel.  The division of things is
+ * somewhat arbitrary, and the division of the word could be changed if it
+ * were really needed for any reason.  The numbers below are the only place
+ * where these are specified.  For a first go-around, 3 bits is more than
+ * enough, since this gives 8 levels of logging (really 7, since 0 is always
+ * off).  Cutting to 2 bits might be wise at some point.
+ */
+
+#define SCSI_LOG_ERROR_SHIFT              0
+#define SCSI_LOG_TIMEOUT_SHIFT            3
+#define SCSI_LOG_SCAN_SHIFT               6
+#define SCSI_LOG_MLQUEUE_SHIFT            9
+#define SCSI_LOG_MLCOMPLETE_SHIFT         12
+#define SCSI_LOG_LLQUEUE_SHIFT            15
+#define SCSI_LOG_LLCOMPLETE_SHIFT         18
+#define SCSI_LOG_HLQUEUE_SHIFT            21
+#define SCSI_LOG_HLCOMPLETE_SHIFT         24
+#define SCSI_LOG_IOCTL_SHIFT              27
+
+#define SCSI_LOG_ERROR_BITS               3
+#define SCSI_LOG_TIMEOUT_BITS             3
+#define SCSI_LOG_SCAN_BITS                3
+#define SCSI_LOG_MLQUEUE_BITS             3
+#define SCSI_LOG_MLCOMPLETE_BITS          3
+#define SCSI_LOG_LLQUEUE_BITS             3
+#define SCSI_LOG_LLCOMPLETE_BITS          3
+#define SCSI_LOG_HLQUEUE_BITS             3
+#define SCSI_LOG_HLCOMPLETE_BITS          3
+#define SCSI_LOG_IOCTL_BITS               3
+
+extern unsigned int scsi_logging_level;
+
+#ifdef CONFIG_SCSI_LOGGING
+
+#define SCSI_LOG_LEVEL(SHIFT, BITS)				\
+        ((scsi_logging_level >> (SHIFT)) & ((1 << (BITS)) - 1))
+
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)		\
+{								\
+        if (unlikely((SCSI_LOG_LEVEL(SHIFT, BITS)) > (LEVEL)))	\
+		(CMD);						\
+}
+#else
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
+#endif /* CONFIG_SCSI_LOGGING */
+
+/*
+ * These are the macros that are actually used throughout the code to
+ * log events.  If logging isn't enabled, they are no-ops and will be
+ * completely absent from the user's code.
+ */
+#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
+#define SCSI_LOG_TIMEOUT(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
+#define SCSI_LOG_SCAN_BUS(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_IOCTL(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
+
+#endif /* _SCSI_LOGGING_H */
diff --git a/drivers/scsi/scsi_module.c b/drivers/scsi/scsi_module.c
new file mode 100644
index 0000000..4891758
--- /dev/null
+++ b/drivers/scsi/scsi_module.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003 Christoph Hellwig.
+ *	Released under GPL v2.
+ *
+ * Support for old-style host templates.
+ *
+ * NOTE:  Do not use this for new drivers ever.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <scsi/scsi_host.h>
+
+
+static int __init init_this_scsi_driver(void)
+{
+	struct scsi_host_template *sht = &driver_template;
+	struct Scsi_Host *shost;
+	struct list_head *l;
+	int error;
+
+	if (!sht->release) {
+		printk(KERN_ERR
+		    "scsi HBA driver %s didn't set a release method.\n",
+		    sht->name);
+		return -EINVAL;
+	}
+
+	sht->module = THIS_MODULE;
+	INIT_LIST_HEAD(&sht->legacy_hosts);
+
+	sht->detect(sht);
+	if (list_empty(&sht->legacy_hosts))
+		return -ENODEV;
+
+	list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list) {
+		error = scsi_add_host(shost, NULL);
+		if (error)
+			goto fail;
+		scsi_scan_host(shost);
+	}
+	return 0;
+ fail:
+	l = &shost->sht_legacy_list;
+	while ((l = l->prev) != &sht->legacy_hosts)
+		scsi_remove_host(list_entry(l, struct Scsi_Host, sht_legacy_list));
+	return error;
+}
+
+static void __exit exit_this_scsi_driver(void)
+{
+	struct scsi_host_template *sht = &driver_template;
+	struct Scsi_Host *shost, *s;
+
+	list_for_each_entry(shost, &sht->legacy_hosts, sht_legacy_list)
+		scsi_remove_host(shost);
+	list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list)
+		sht->release(shost);
+
+	if (list_empty(&sht->legacy_hosts))
+		return;
+
+	printk(KERN_WARNING "%s did not call scsi_unregister\n", sht->name);
+	dump_stack();
+
+	list_for_each_entry_safe(shost, s, &sht->legacy_hosts, sht_legacy_list)
+		scsi_unregister(shost);
+}
+
+module_init(init_this_scsi_driver);
+module_exit(exit_this_scsi_driver);
diff --git a/drivers/scsi/scsi_obsolete.h b/drivers/scsi/scsi_obsolete.h
new file mode 100644
index 0000000..abeacb9
--- /dev/null
+++ b/drivers/scsi/scsi_obsolete.h
@@ -0,0 +1,106 @@
+/*
+ *  scsi_obsolete.h Copyright (C) 1997 Eric Youngdale
+ *
+ */
+
+#ifndef _SCSI_OBSOLETE_H
+#define _SCSI_OBSOLETE_H
+
+/*
+ * These are the return codes for the abort and reset functions.  The mid-level
+ * code uses these to decide what to do next.  Each of the low level abort
+ * and reset functions must correctly indicate what it has done.
+ * The descriptions are written from the point of view of the mid-level code,
+ * so that the return code is telling the mid-level drivers exactly what
+ * the low level driver has already done, and what remains to be done.
+ */
+
+/* We did not do anything.  
+ * Wait some more for this command to complete, and if this does not work, 
+ * try something more serious. */
+#define SCSI_ABORT_SNOOZE 0
+
+/* This means that we were able to abort the command.  We have already
+ * called the mid-level done function, and do not expect an interrupt that 
+ * will lead to another call to the mid-level done function for this command */
+#define SCSI_ABORT_SUCCESS 1
+
+/* We called for an abort of this command, and we should get an interrupt 
+ * when this succeeds.  Thus we should not restore the timer for this
+ * command in the mid-level abort function. */
+#define SCSI_ABORT_PENDING 2
+
+/* Unable to abort - command is currently on the bus.  Grin and bear it. */
+#define SCSI_ABORT_BUSY 3
+
+/* The command is not active in the low level code. Command probably
+ * finished. */
+#define SCSI_ABORT_NOT_RUNNING 4
+
+/* Something went wrong.  The low level driver will indicate the correct
+ * error condition when it calls scsi_done, so the mid-level abort function
+ * can simply wait until this comes through */
+#define SCSI_ABORT_ERROR 5
+
+/* We do not know how to reset the bus, or we do not want to.  Bummer.
+ * Anyway, just wait a little more for the command in question, and hope that
+ * it eventually finishes.  If it never finishes, the SCSI device could
+ * hang, so use this with caution. */
+#define SCSI_RESET_SNOOZE 0
+
+/* We do not know how to reset the bus, or we do not want to.  Bummer.
+ * We have given up on this ever completing.  The mid-level code will
+ * request sense information to decide how to proceed from here. */
+#define SCSI_RESET_PUNT 1
+
+/* This means that we were able to reset the bus.  We have restarted all of
+ * the commands that should be restarted, and we should be able to continue
+ * on normally from here.  We do not expect any interrupts that will return
+ * DID_RESET to any of the other commands in the host_queue, and the mid-level
+ * code does not need to do anything special to keep the commands alive. 
+ * If a hard reset was performed then all outstanding commands on the
+ * bus have been restarted. */
+#define SCSI_RESET_SUCCESS 2
+
+/* We called for a reset of this bus, and we should get an interrupt 
+ * when this succeeds.  Each command should get its own status
+ * passed up to scsi_done, but this has not happened yet. 
+ * If a hard reset was performed, then we expect an interrupt
+ * for *each* of the outstanding commands that will have the
+ * effect of restarting the commands.
+ */
+#define SCSI_RESET_PENDING 3
+
+/* We did a reset, but do not expect an interrupt to signal DID_RESET.
+ * This tells the upper level code to request the sense info, and this
+ * should keep the command alive. */
+#define SCSI_RESET_WAKEUP 4
+
+/* The command is not active in the low level code. Command probably
+   finished. */
+#define SCSI_RESET_NOT_RUNNING 5
+
+/* Something went wrong, and we do not know how to fix it. */
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS		0x01
+#define SCSI_RESET_ASYNCHRONOUS		0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET	0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET	0x08
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a hard reset.
+ */
+#define SCSI_RESET_BUS_RESET 0x100
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a host adapter reset.
+ */
+#define SCSI_RESET_HOST_RESET 0x200
+/*
+ * Used to mask off bits and to obtain the basic action that was
+ * performed.  
+ */
+#define SCSI_RESET_ACTION   0xff
+
+#endif				/* SCSI_OBSOLETE_H */
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
new file mode 100644
index 0000000..aca3b39
--- /dev/null
+++ b/drivers/scsi/scsi_priv.h
@@ -0,0 +1,165 @@
+#ifndef _SCSI_PRIV_H
+#define _SCSI_PRIV_H
+
+#include <linux/config.h>
+#include <linux/device.h>
+
+struct request_queue;
+struct scsi_cmnd;
+struct scsi_device;
+struct scsi_host_template;
+struct scsi_request;
+struct Scsi_Host;
+
+
+/*
+ * These are the values that the owner field can take.
+ * They are used as an indication of who the command belongs to.
+ */
+#define SCSI_OWNER_HIGHLEVEL      0x100
+#define SCSI_OWNER_MIDLEVEL       0x101
+#define SCSI_OWNER_LOWLEVEL       0x102
+#define SCSI_OWNER_ERROR_HANDLER  0x103
+#define SCSI_OWNER_BH_HANDLER     0x104
+#define SCSI_OWNER_NOBODY         0x105
+
+/*
+ * Magic values for certain scsi structs. Shouldn't ever be used.
+ */
+#define SCSI_CMND_MAGIC		0xE25C23A5
+#define SCSI_REQ_MAGIC		0x75F6D354
+
+/*
+ *  Flag bit for the internal_timeout array
+ */
+#define NORMAL_TIMEOUT		0
+
+/*
+ * Scsi Error Handler Flags
+ */
+#define scsi_eh_eflags_chk(scp, flags) \
+	((scp)->eh_eflags & (flags))
+#define scsi_eh_eflags_set(scp, flags) \
+	do { (scp)->eh_eflags |= (flags); } while(0)
+#define scsi_eh_eflags_clr(scp, flags) \
+	do { (scp)->eh_eflags &= ~(flags); } while(0)
+#define scsi_eh_eflags_clr_all(scp) \
+	(scp->eh_eflags = 0)
+
+#define SCSI_EH_CANCEL_CMD	0x0001	/* Cancel this cmd */
+#define SCSI_EH_REC_TIMEOUT	0x0002	/* EH retry timed out */
+
+#define SCSI_SENSE_VALID(scmd) \
+	(((scmd)->sense_buffer[0] & 0x70) == 0x70)
+
+/*
+ * Special value for scanning to specify scanning or rescanning of all
+ * possible channels, (target) ids, or luns on a given shost.
+ */
+#define SCAN_WILD_CARD	~0
+
+/* hosts.c */
+extern int scsi_init_hosts(void);
+extern void scsi_exit_hosts(void);
+
+/* scsi.c */
+extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
+extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
+extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
+extern void scsi_done(struct scsi_cmnd *cmd);
+extern int scsi_retry_command(struct scsi_cmnd *cmd);
+extern int scsi_insert_special_req(struct scsi_request *sreq, int);
+extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
+		struct scsi_request *sreq);
+extern void __scsi_release_request(struct scsi_request *sreq);
+extern void __scsi_done(struct scsi_cmnd *cmd);
+#ifdef CONFIG_SCSI_LOGGING
+void scsi_log_send(struct scsi_cmnd *cmd);
+void scsi_log_completion(struct scsi_cmnd *cmd, int disposition);
+#else
+static inline void scsi_log_send(struct scsi_cmnd *cmd) 
+	{ };
+static inline void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
+	{ };
+#endif
+
+/* scsi_devinfo.c */
+extern int scsi_get_device_flags(struct scsi_device *sdev,
+				 unsigned char *vendor, unsigned char *model);
+extern int __init scsi_init_devinfo(void);
+extern void scsi_exit_devinfo(void);
+
+/* scsi_error.c */
+extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern int scsi_error_handler(void *host);
+extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
+extern void scsi_eh_wakeup(struct Scsi_Host *shost);
+extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
+
+/* scsi_lib.c */
+extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
+extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
+extern void scsi_device_unbusy(struct scsi_device *sdev);
+extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_next_command(struct scsi_cmnd *cmd);
+extern void scsi_run_host_queues(struct Scsi_Host *shost);
+extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
+extern void scsi_free_queue(struct request_queue *q);
+extern int scsi_init_queue(void);
+extern void scsi_exit_queue(void);
+
+/* scsi_proc.c */
+#ifdef CONFIG_SCSI_PROC_FS
+extern void scsi_proc_hostdir_add(struct scsi_host_template *);
+extern void scsi_proc_hostdir_rm(struct scsi_host_template *);
+extern void scsi_proc_host_add(struct Scsi_Host *);
+extern void scsi_proc_host_rm(struct Scsi_Host *);
+extern int scsi_init_procfs(void);
+extern void scsi_exit_procfs(void);
+#else
+# define scsi_proc_hostdir_add(sht)	do { } while (0)
+# define scsi_proc_hostdir_rm(sht)	do { } while (0)
+# define scsi_proc_host_add(shost)	do { } while (0)
+# define scsi_proc_host_rm(shost)	do { } while (0)
+# define scsi_init_procfs()		(0)
+# define scsi_exit_procfs()		do { } while (0)
+#endif /* CONFIG_PROC_FS */
+
+/* scsi_scan.c */
+extern int scsi_scan_host_selected(struct Scsi_Host *, unsigned int,
+				   unsigned int, unsigned int, int);
+extern void scsi_forget_host(struct Scsi_Host *);
+extern void scsi_rescan_device(struct device *);
+
+/* scsi_sysctl.c */
+#ifdef CONFIG_SYSCTL
+extern int scsi_init_sysctl(void);
+extern void scsi_exit_sysctl(void);
+#else
+# define scsi_init_sysctl()		(0)
+# define scsi_exit_sysctl()		do { } while (0)
+#endif /* CONFIG_SYSCTL */
+
+/* scsi_sysfs.c */
+extern void scsi_device_dev_release(struct device *);
+extern int scsi_sysfs_add_sdev(struct scsi_device *);
+extern int scsi_sysfs_add_host(struct Scsi_Host *);
+extern int scsi_sysfs_register(void);
+extern void scsi_sysfs_unregister(void);
+extern void scsi_sysfs_device_initialize(struct scsi_device *);
+extern int scsi_sysfs_target_initialize(struct scsi_device *);
+extern struct scsi_transport_template blank_transport_template;
+
+extern struct class sdev_class;
+extern struct bus_type scsi_bus_type;
+
+/* 
+ * internal scsi timeout functions: for use by mid-layer and transport
+ * classes.
+ */
+
+#define SCSI_DEVICE_BLOCK_MAX_TIMEOUT	(HZ*60)
+extern int scsi_internal_device_block(struct scsi_device *sdev);
+extern int scsi_internal_device_unblock(struct scsi_device *sdev);
+
+#endif /* _SCSI_PRIV_H */
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
new file mode 100644
index 0000000..a50958b
--- /dev/null
+++ b/drivers/scsi/scsi_proc.c
@@ -0,0 +1,336 @@
+/*
+ * linux/drivers/scsi/scsi_proc.c
+ *
+ * The functions in this file provide an interface between
+ * the PROC file system and the SCSI device drivers
+ * It is mainly used for debugging, statistics and to pass 
+ * information directly to the lowlevel driver.
+ *
+ * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de 
+ * Version: 0.99.8   last change: 95/09/13
+ * 
+ * generic command parser provided by: 
+ * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ *
+ * generic_proc_info() support of xxxx_info() by:
+ * Michael A. Griffith <grif@acm.org>
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include <linux/blkdev.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
+/* 4K page size, but our output routines, use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
+
+static struct proc_dir_entry *proc_scsi;
+
+/* Protect sht->present and sht->proc_dir */
+static DECLARE_MUTEX(global_host_template_sem);
+
+static int proc_scsi_read(char *buffer, char **start, off_t offset,
+			  int length, int *eof, void *data)
+{
+	struct Scsi_Host *shost = data;
+	int n;
+
+	n = shost->hostt->proc_info(shost, buffer, start, offset, length, 0);
+	*eof = (n < length);
+
+	return n;
+}
+
+static int proc_scsi_write_proc(struct file *file, const char __user *buf,
+                           unsigned long count, void *data)
+{
+	struct Scsi_Host *shost = data;
+	ssize_t ret = -ENOMEM;
+	char *page;
+	char *start;
+    
+	if (count > PROC_BLOCK_SIZE)
+		return -EOVERFLOW;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (page) {
+		ret = -EFAULT;
+		if (copy_from_user(page, buf, count))
+			goto out;
+		ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1);
+	}
+out:
+	free_page((unsigned long)page);
+	return ret;
+}
+
+void scsi_proc_hostdir_add(struct scsi_host_template *sht)
+{
+	if (!sht->proc_info)
+		return;
+
+	down(&global_host_template_sem);
+	if (!sht->present++) {
+		sht->proc_dir = proc_mkdir(sht->proc_name, proc_scsi);
+        	if (!sht->proc_dir)
+			printk(KERN_ERR "%s: proc_mkdir failed for %s\n",
+			       __FUNCTION__, sht->proc_name);
+		else
+			sht->proc_dir->owner = sht->module;
+	}
+	up(&global_host_template_sem);
+}
+
+void scsi_proc_hostdir_rm(struct scsi_host_template *sht)
+{
+	if (!sht->proc_info)
+		return;
+
+	down(&global_host_template_sem);
+	if (!--sht->present && sht->proc_dir) {
+		remove_proc_entry(sht->proc_name, proc_scsi);
+		sht->proc_dir = NULL;
+	}
+	up(&global_host_template_sem);
+}
+
+void scsi_proc_host_add(struct Scsi_Host *shost)
+{
+	struct scsi_host_template *sht = shost->hostt;
+	struct proc_dir_entry *p;
+	char name[10];
+
+	if (!sht->proc_dir)
+		return;
+
+	sprintf(name,"%d", shost->host_no);
+	p = create_proc_read_entry(name, S_IFREG | S_IRUGO | S_IWUSR,
+			sht->proc_dir, proc_scsi_read, shost);
+	if (!p) {
+		printk(KERN_ERR "%s: Failed to register host %d in"
+		       "%s\n", __FUNCTION__, shost->host_no,
+		       sht->proc_name);
+		return;
+	} 
+
+	p->write_proc = proc_scsi_write_proc;
+	p->owner = sht->module;
+}
+
+void scsi_proc_host_rm(struct Scsi_Host *shost)
+{
+	char name[10];
+
+	if (!shost->hostt->proc_dir)
+		return;
+
+	sprintf(name,"%d", shost->host_no);
+	remove_proc_entry(name, shost->hostt->proc_dir);
+}
+
+static int proc_print_scsidevice(struct device *dev, void *data)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct seq_file *s = data;
+	int i;
+
+	seq_printf(s,
+		"Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n  Vendor: ",
+		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
+	for (i = 0; i < 8; i++) {
+		if (sdev->vendor[i] >= 0x20)
+			seq_printf(s, "%c", sdev->vendor[i]);
+		else
+			seq_printf(s, " ");
+	}
+
+	seq_printf(s, " Model: ");
+	for (i = 0; i < 16; i++) {
+		if (sdev->model[i] >= 0x20)
+			seq_printf(s, "%c", sdev->model[i]);
+		else
+			seq_printf(s, " ");
+	}
+
+	seq_printf(s, " Rev: ");
+	for (i = 0; i < 4; i++) {
+		if (sdev->rev[i] >= 0x20)
+			seq_printf(s, "%c", sdev->rev[i]);
+		else
+			seq_printf(s, " ");
+	}
+
+	seq_printf(s, "\n");
+
+	seq_printf(s, "  Type:   %s ",
+		     sdev->type < MAX_SCSI_DEVICE_CODE ?
+	       scsi_device_types[(int) sdev->type] : "Unknown          ");
+	seq_printf(s, "               ANSI"
+		     " SCSI revision: %02x", (sdev->scsi_level - 1) ?
+		     sdev->scsi_level - 1 : 1);
+	if (sdev->scsi_level == 2)
+		seq_printf(s, " CCS\n");
+	else
+		seq_printf(s, "\n");
+
+	return 0;
+}
+
+static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
+{
+	struct Scsi_Host *shost;
+	int error = -ENXIO;
+
+	shost = scsi_host_lookup(host);
+	if (IS_ERR(shost))
+		return PTR_ERR(shost);
+
+	error = scsi_scan_host_selected(shost, channel, id, lun, 1);
+	scsi_host_put(shost);
+	return error;
+}
+
+static int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
+{
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost;
+	int error = -ENXIO;
+
+	shost = scsi_host_lookup(host);
+	if (IS_ERR(shost))
+		return PTR_ERR(shost);
+	sdev = scsi_device_lookup(shost, channel, id, lun);
+	if (sdev) {
+		scsi_remove_device(sdev);
+		scsi_device_put(sdev);
+		error = 0;
+	}
+
+	scsi_host_put(shost);
+	return error;
+}
+
+static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
+			       size_t length, loff_t *ppos)
+{
+	int host, channel, id, lun;
+	char *buffer, *p;
+	int err;
+
+	if (!buf || length > PAGE_SIZE)
+		return -EINVAL;
+
+	buffer = (char *)__get_free_page(GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	err = -EFAULT;
+	if (copy_from_user(buffer, buf, length))
+		goto out;
+
+	err = -EINVAL;
+	if (length < PAGE_SIZE)
+		buffer[length] = '\0';
+	else if (buffer[PAGE_SIZE-1])
+		goto out;
+
+	/*
+	 * Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
+	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+	 */
+	if (!strncmp("scsi add-single-device", buffer, 22)) {
+		p = buffer + 23;
+
+		host = simple_strtoul(p, &p, 0);
+		channel = simple_strtoul(p + 1, &p, 0);
+		id = simple_strtoul(p + 1, &p, 0);
+		lun = simple_strtoul(p + 1, &p, 0);
+
+		err = scsi_add_single_device(host, channel, id, lun);
+		if (err >= 0)
+			err = length;
+
+	/*
+	 * Usage: echo "scsi remove-single-device 0 1 2 3" >/proc/scsi/scsi
+	 * with  "0 1 2 3" replaced by your "Host Channel Id Lun".
+	 */
+	} else if (!strncmp("scsi remove-single-device", buffer, 25)) {
+		p = buffer + 26;
+
+		host = simple_strtoul(p, &p, 0);
+		channel = simple_strtoul(p + 1, &p, 0);
+		id = simple_strtoul(p + 1, &p, 0);
+		lun = simple_strtoul(p + 1, &p, 0);
+
+		err = scsi_remove_single_device(host, channel, id, lun);
+	}
+
+ out:
+	free_page((unsigned long)buffer);
+	return err;
+}
+
+static int proc_scsi_show(struct seq_file *s, void *p)
+{
+	seq_printf(s, "Attached devices:\n");
+	bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice);
+	return 0;
+}
+
+static int proc_scsi_open(struct inode *inode, struct file *file)
+{
+	/*
+	 * We don't really needs this for the write case but it doesn't
+	 * harm either.
+	 */
+	return single_open(file, proc_scsi_show, NULL);
+}
+
+static struct file_operations proc_scsi_operations = {
+	.open		= proc_scsi_open,
+	.read		= seq_read,
+	.write		= proc_scsi_write,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+};
+
+int __init scsi_init_procfs(void)
+{
+	struct proc_dir_entry *pde;
+
+	proc_scsi = proc_mkdir("scsi", NULL);
+	if (!proc_scsi)
+		goto err1;
+
+	pde = create_proc_entry("scsi/scsi", 0, NULL);
+	if (!pde)
+		goto err2;
+	pde->proc_fops = &proc_scsi_operations;
+
+	return 0;
+
+err2:
+	remove_proc_entry("scsi", NULL);
+err1:
+	return -ENOMEM;
+}
+
+void scsi_exit_procfs(void)
+{
+	remove_proc_entry("scsi/scsi", NULL);
+	remove_proc_entry("scsi", NULL);
+}
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
new file mode 100644
index 0000000..a8a37a3
--- /dev/null
+++ b/drivers/scsi/scsi_scan.c
@@ -0,0 +1,1473 @@
+/*
+ * scsi_scan.c
+ *
+ * Copyright (C) 2000 Eric Youngdale,
+ * Copyright (C) 2002 Patrick Mansfield
+ *
+ * The general scanning/probing algorithm is as follows, exceptions are
+ * made to it depending on device specific flags, compilation options, and
+ * global variable (boot or module load time) settings.
+ *
+ * A specific LUN is scanned via an INQUIRY command; if the LUN has a
+ * device attached, a Scsi_Device is allocated and setup for it.
+ *
+ * For every id of every channel on the given host:
+ *
+ * 	Scan LUN 0; if the target responds to LUN 0 (even if there is no
+ * 	device or storage attached to LUN 0):
+ *
+ * 		If LUN 0 has a device attached, allocate and setup a
+ * 		Scsi_Device for it.
+ *
+ * 		If target is SCSI-3 or up, issue a REPORT LUN, and scan
+ * 		all of the LUNs returned by the REPORT LUN; else,
+ * 		sequentially scan LUNs up until some maximum is reached,
+ * 		or a LUN is seen that cannot have a device attached to it.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <asm/semaphore.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_devinfo.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_eh.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+#define ALLOC_FAILURE_MSG	KERN_ERR "%s: Allocation failure during" \
+	" SCSI scanning, some SCSI devices might not be configured\n"
+
+/*
+ * Default timeout
+ */
+#define SCSI_TIMEOUT (2*HZ)
+
+/*
+ * Prefix values for the SCSI id's (stored in driverfs name field)
+ */
+#define SCSI_UID_SER_NUM 'S'
+#define SCSI_UID_UNKNOWN 'Z'
+
+/*
+ * Return values of some of the scanning functions.
+ *
+ * SCSI_SCAN_NO_RESPONSE: no valid response received from the target, this
+ * includes allocation or general failures preventing IO from being sent.
+ *
+ * SCSI_SCAN_TARGET_PRESENT: target responded, but no device is available
+ * on the given LUN.
+ *
+ * SCSI_SCAN_LUN_PRESENT: target responded, and a device is available on a
+ * given LUN.
+ */
+#define SCSI_SCAN_NO_RESPONSE		0
+#define SCSI_SCAN_TARGET_PRESENT	1
+#define SCSI_SCAN_LUN_PRESENT		2
+
+static char *scsi_null_device_strs = "nullnullnullnull";
+
+#define MAX_SCSI_LUNS	512
+
+#ifdef CONFIG_SCSI_MULTI_LUN
+static unsigned int max_scsi_luns = MAX_SCSI_LUNS;
+#else
+static unsigned int max_scsi_luns = 1;
+#endif
+
+module_param_named(max_luns, max_scsi_luns, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(max_luns,
+		 "last scsi LUN (should be between 1 and 2^32-1)");
+
+/*
+ * max_scsi_report_luns: the maximum number of LUNS that will be
+ * returned from the REPORT LUNS command. 8 times this value must
+ * be allocated. In theory this could be up to an 8 byte value, but
+ * in practice, the maximum number of LUNs suppored by any device
+ * is about 16k.
+ */
+static unsigned int max_scsi_report_luns = 511;
+
+module_param_named(max_report_luns, max_scsi_report_luns, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(max_report_luns,
+		 "REPORT LUNS maximum number of LUNS received (should be"
+		 " between 1 and 16384)");
+
+static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ+3;
+
+module_param_named(inq_timeout, scsi_inq_timeout, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(inq_timeout, 
+		 "Timeout (in seconds) waiting for devices to answer INQUIRY."
+		 " Default is 5. Some non-compliant devices need more.");
+
+/**
+ * scsi_unlock_floptical - unlock device via a special MODE SENSE command
+ * @sreq:	used to send the command
+ * @result:	area to store the result of the MODE SENSE
+ *
+ * Description:
+ *     Send a vendor specific MODE SENSE (not a MODE SELECT) command using
+ *     @sreq to unlock a device, storing the (unused) results into result.
+ *     Called for BLIST_KEY devices.
+ **/
+static void scsi_unlock_floptical(struct scsi_request *sreq,
+				  unsigned char *result)
+{
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+
+	printk(KERN_NOTICE "scsi: unlocking floptical drive\n");
+	scsi_cmd[0] = MODE_SENSE;
+	scsi_cmd[1] = 0;
+	scsi_cmd[2] = 0x2e;
+	scsi_cmd[3] = 0;
+	scsi_cmd[4] = 0x2a;	/* size */
+	scsi_cmd[5] = 0;
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_FROM_DEVICE;
+	scsi_wait_req(sreq, scsi_cmd, result, 0x2a /* size */, SCSI_TIMEOUT, 3);
+}
+
+/**
+ * print_inquiry - printk the inquiry information
+ * @inq_result:	printk this SCSI INQUIRY
+ *
+ * Description:
+ *     printk the vendor, model, and other information found in the
+ *     INQUIRY data in @inq_result.
+ *
+ * Notes:
+ *     Remove this, and replace with a hotplug event that logs any
+ *     relevant information.
+ **/
+static void print_inquiry(unsigned char *inq_result)
+{
+	int i;
+
+	printk(KERN_NOTICE "  Vendor: ");
+	for (i = 8; i < 16; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
+		else
+			printk(" ");
+
+	printk("  Model: ");
+	for (i = 16; i < 32; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
+		else
+			printk(" ");
+
+	printk("  Rev: ");
+	for (i = 32; i < 36; i++)
+		if (inq_result[i] >= 0x20 && i < inq_result[4] + 5)
+			printk("%c", inq_result[i]);
+		else
+			printk(" ");
+
+	printk("\n");
+
+	i = inq_result[0] & 0x1f;
+
+	printk(KERN_NOTICE "  Type:   %s ",
+	       i <
+	       MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] :
+	       "Unknown          ");
+	printk("                 ANSI SCSI revision: %02x",
+	       inq_result[2] & 0x07);
+	if ((inq_result[2] & 0x07) == 1 && (inq_result[3] & 0x0f) == 1)
+		printk(" CCS\n");
+	else
+		printk("\n");
+}
+
+/**
+ * scsi_alloc_sdev - allocate and setup a scsi_Device
+ *
+ * Description:
+ *     Allocate, initialize for io, and return a pointer to a scsi_Device.
+ *     Stores the @shost, @channel, @id, and @lun in the scsi_Device, and
+ *     adds scsi_Device to the appropriate list.
+ *
+ * Return value:
+ *     scsi_Device pointer, or NULL on failure.
+ **/
+static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
+					   unsigned int lun, void *hostdata)
+{
+	struct scsi_device *sdev;
+	int display_failure_msg = 1, ret;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+
+	sdev = kmalloc(sizeof(*sdev) + shost->transportt->device_size,
+		       GFP_ATOMIC);
+	if (!sdev)
+		goto out;
+
+	memset(sdev, 0, sizeof(*sdev));
+	sdev->vendor = scsi_null_device_strs;
+	sdev->model = scsi_null_device_strs;
+	sdev->rev = scsi_null_device_strs;
+	sdev->host = shost;
+	sdev->id = starget->id;
+	sdev->lun = lun;
+	sdev->channel = starget->channel;
+	sdev->sdev_state = SDEV_CREATED;
+	INIT_LIST_HEAD(&sdev->siblings);
+	INIT_LIST_HEAD(&sdev->same_target_siblings);
+	INIT_LIST_HEAD(&sdev->cmd_list);
+	INIT_LIST_HEAD(&sdev->starved_entry);
+	spin_lock_init(&sdev->list_lock);
+
+	sdev->sdev_gendev.parent = get_device(&starget->dev);
+	sdev->sdev_target = starget;
+
+	/* usually NULL and set by ->slave_alloc instead */
+	sdev->hostdata = hostdata;
+
+	/* if the device needs this changing, it may do so in the
+	 * slave_configure function */
+	sdev->max_device_blocked = SCSI_DEFAULT_DEVICE_BLOCKED;
+
+	/*
+	 * Some low level driver could use device->type
+	 */
+	sdev->type = -1;
+
+	/*
+	 * Assume that the device will have handshaking problems,
+	 * and then fix this field later if it turns out it
+	 * doesn't
+	 */
+	sdev->borken = 1;
+
+	spin_lock_init(&sdev->sdev_lock);
+	sdev->request_queue = scsi_alloc_queue(sdev);
+	if (!sdev->request_queue) {
+		/* release fn is set up in scsi_sysfs_device_initialise, so
+		 * have to free and put manually here */
+		put_device(&starget->dev);
+		goto out;
+	}
+
+	sdev->request_queue->queuedata = sdev;
+	scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+
+	scsi_sysfs_device_initialize(sdev);
+
+	if (shost->hostt->slave_alloc) {
+		ret = shost->hostt->slave_alloc(sdev);
+		if (ret) {
+			/*
+			 * if LLDD reports slave not present, don't clutter
+			 * console with alloc failure messages
+
+
+			 */
+			if (ret == -ENXIO)
+				display_failure_msg = 0;
+			goto out_device_destroy;
+		}
+	}
+
+	return sdev;
+
+out_device_destroy:
+	transport_destroy_device(&sdev->sdev_gendev);
+	scsi_free_queue(sdev->request_queue);
+	put_device(&sdev->sdev_gendev);
+out:
+	if (display_failure_msg)
+		printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+	return NULL;
+}
+
+static void scsi_target_dev_release(struct device *dev)
+{
+	struct device *parent = dev->parent;
+	struct scsi_target *starget = to_scsi_target(dev);
+	kfree(starget);
+	put_device(parent);
+}
+
+int scsi_is_target_device(const struct device *dev)
+{
+	return dev->release == scsi_target_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_target_device);
+
+static struct scsi_target *__scsi_find_target(struct device *parent,
+					      int channel, uint id)
+{
+	struct scsi_target *starget, *found_starget = NULL;
+	struct Scsi_Host *shost = dev_to_shost(parent);
+	/*
+	 * Search for an existing target for this sdev.
+	 */
+	list_for_each_entry(starget, &shost->__targets, siblings) {
+		if (starget->id == id &&
+		    starget->channel == channel) {
+			found_starget = starget;
+			break;
+		}
+	}
+	if (found_starget)
+		get_device(&found_starget->dev);
+
+	return found_starget;
+}
+
+static struct scsi_target *scsi_alloc_target(struct device *parent,
+					     int channel, uint id)
+{
+	struct Scsi_Host *shost = dev_to_shost(parent);
+	struct device *dev = NULL;
+	unsigned long flags;
+	const int size = sizeof(struct scsi_target)
+		+ shost->transportt->target_size;
+	struct scsi_target *starget = kmalloc(size, GFP_ATOMIC);
+	struct scsi_target *found_target;
+
+	if (!starget) {
+		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		return NULL;
+	}
+	memset(starget, 0, size);
+	dev = &starget->dev;
+	device_initialize(dev);
+	starget->reap_ref = 1;
+	dev->parent = get_device(parent);
+	dev->release = scsi_target_dev_release;
+	sprintf(dev->bus_id, "target%d:%d:%d",
+		shost->host_no, channel, id);
+	starget->id = id;
+	starget->channel = channel;
+	INIT_LIST_HEAD(&starget->siblings);
+	INIT_LIST_HEAD(&starget->devices);
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	found_target = __scsi_find_target(parent, channel, id);
+	if (found_target)
+		goto found;
+
+	list_add_tail(&starget->siblings, &shost->__targets);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	/* allocate and add */
+	transport_setup_device(&starget->dev);
+	device_add(&starget->dev);
+	transport_add_device(&starget->dev);
+	return starget;
+
+ found:
+	found_target->reap_ref++;
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(parent);
+	kfree(starget);
+	return found_target;
+}
+
+/**
+ * scsi_target_reap - check to see if target is in use and destroy if not
+ *
+ * @starget: target to be checked
+ *
+ * This is used after removing a LUN or doing a last put of the target
+ * it checks atomically that nothing is using the target and removes
+ * it if so.
+ */
+void scsi_target_reap(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	if (--starget->reap_ref == 0 && list_empty(&starget->devices)) {
+		list_del_init(&starget->siblings);
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		device_del(&starget->dev);
+		transport_unregister_device(&starget->dev);
+		put_device(&starget->dev);
+		return;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/**
+ * scsi_probe_lun - probe a single LUN using a SCSI INQUIRY
+ * @sreq:	used to send the INQUIRY
+ * @inq_result:	area to store the INQUIRY result
+ * @bflags:	store any bflags found here
+ *
+ * Description:
+ *     Probe the lun associated with @sreq using a standard SCSI INQUIRY;
+ *
+ *     If the INQUIRY is successful, sreq->sr_result is zero and: the
+ *     INQUIRY data is in @inq_result; the scsi_level and INQUIRY length
+ *     are copied to the Scsi_Device at @sreq->sr_device (sdev);
+ *     any flags value is stored in *@bflags.
+ **/
+static void scsi_probe_lun(struct scsi_request *sreq, char *inq_result,
+			   int *bflags)
+{
+	struct scsi_device *sdev = sreq->sr_device;	/* a bit ugly */
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+	int first_inquiry_len, try_inquiry_len, next_inquiry_len;
+	int response_len = 0;
+	int pass, count;
+	struct scsi_sense_hdr sshdr;
+
+	*bflags = 0;
+
+	/* Perform up to 3 passes.  The first pass uses a conservative
+	 * transfer length of 36 unless sdev->inquiry_len specifies a
+	 * different value. */
+	first_inquiry_len = sdev->inquiry_len ? sdev->inquiry_len : 36;
+	try_inquiry_len = first_inquiry_len;
+	pass = 1;
+
+ next_pass:
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY pass %d "
+			"to host %d channel %d id %d lun %d, length %d\n",
+			pass, sdev->host->host_no, sdev->channel,
+			sdev->id, sdev->lun, try_inquiry_len));
+
+	/* Each pass gets up to three chances to ignore Unit Attention */
+	for (count = 0; count < 3; ++count) {
+		memset(scsi_cmd, 0, 6);
+		scsi_cmd[0] = INQUIRY;
+		scsi_cmd[4] = (unsigned char) try_inquiry_len;
+		sreq->sr_cmd_len = 0;
+		sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+		memset(inq_result, 0, try_inquiry_len);
+		scsi_wait_req(sreq, (void *) scsi_cmd, (void *) inq_result,
+				try_inquiry_len,
+				HZ/2 + HZ*scsi_inq_timeout, 3);
+
+		SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: INQUIRY %s "
+				"with code 0x%x\n",
+				sreq->sr_result ? "failed" : "successful",
+				sreq->sr_result));
+
+		if (sreq->sr_result) {
+			/*
+			 * not-ready to ready transition [asc/ascq=0x28/0x0]
+			 * or power-on, reset [asc/ascq=0x29/0x0], continue.
+			 * INQUIRY should not yield UNIT_ATTENTION
+			 * but many buggy devices do so anyway. 
+			 */
+			if ((driver_byte(sreq->sr_result) & DRIVER_SENSE) &&
+			    scsi_request_normalize_sense(sreq, &sshdr)) {
+				if ((sshdr.sense_key == UNIT_ATTENTION) &&
+				    ((sshdr.asc == 0x28) ||
+				     (sshdr.asc == 0x29)) &&
+				    (sshdr.ascq == 0))
+					continue;
+			}
+		}
+		break;
+	}
+
+	if (sreq->sr_result == 0) {
+		response_len = (unsigned char) inq_result[4] + 5;
+		if (response_len > 255)
+			response_len = first_inquiry_len;	/* sanity */
+
+		/*
+		 * Get any flags for this device.
+		 *
+		 * XXX add a bflags to Scsi_Device, and replace the
+		 * corresponding bit fields in Scsi_Device, so bflags
+		 * need not be passed as an argument.
+		 */
+		*bflags = scsi_get_device_flags(sdev, &inq_result[8],
+				&inq_result[16]);
+
+		/* When the first pass succeeds we gain information about
+		 * what larger transfer lengths might work. */
+		if (pass == 1) {
+			if (BLIST_INQUIRY_36 & *bflags)
+				next_inquiry_len = 36;
+			else if (BLIST_INQUIRY_58 & *bflags)
+				next_inquiry_len = 58;
+			else if (sdev->inquiry_len)
+				next_inquiry_len = sdev->inquiry_len;
+			else
+				next_inquiry_len = response_len;
+
+			/* If more data is available perform the second pass */
+			if (next_inquiry_len > try_inquiry_len) {
+				try_inquiry_len = next_inquiry_len;
+				pass = 2;
+				goto next_pass;
+			}
+		}
+
+	} else if (pass == 2) {
+		printk(KERN_INFO "scsi scan: %d byte inquiry failed.  "
+				"Consider BLIST_INQUIRY_36 for this device\n",
+				try_inquiry_len);
+
+		/* If this pass failed, the third pass goes back and transfers
+		 * the same amount as we successfully got in the first pass. */
+		try_inquiry_len = first_inquiry_len;
+		pass = 3;
+		goto next_pass;
+	}
+
+	/* If the last transfer attempt got an error, assume the
+	 * peripheral doesn't exist or is dead. */
+	if (sreq->sr_result)
+		return;
+
+	/* Don't report any more data than the device says is valid */
+	sdev->inquiry_len = min(try_inquiry_len, response_len);
+
+	/*
+	 * XXX Abort if the response length is less than 36? If less than
+	 * 32, the lookup of the device flags (above) could be invalid,
+	 * and it would be possible to take an incorrect action - we do
+	 * not want to hang because of a short INQUIRY. On the flip side,
+	 * if the device is spun down or becoming ready (and so it gives a
+	 * short INQUIRY), an abort here prevents any further use of the
+	 * device, including spin up.
+	 *
+	 * Related to the above issue:
+	 *
+	 * XXX Devices (disk or all?) should be sent a TEST UNIT READY,
+	 * and if not ready, sent a START_STOP to start (maybe spin up) and
+	 * then send the INQUIRY again, since the INQUIRY can change after
+	 * a device is initialized.
+	 *
+	 * Ideally, start a device if explicitly asked to do so.  This
+	 * assumes that a device is spun up on power on, spun down on
+	 * request, and then spun up on request.
+	 */
+
+	/*
+	 * The scanning code needs to know the scsi_level, even if no
+	 * device is attached at LUN 0 (SCSI_SCAN_TARGET_PRESENT) so
+	 * non-zero LUNs can be scanned.
+	 */
+	sdev->scsi_level = inq_result[2] & 0x07;
+	if (sdev->scsi_level >= 2 ||
+	    (sdev->scsi_level == 1 && (inq_result[3] & 0x0f) == 1))
+		sdev->scsi_level++;
+
+	return;
+}
+
+/**
+ * scsi_add_lun - allocate and fully initialze a Scsi_Device
+ * @sdevscan:	holds information to be stored in the new Scsi_Device
+ * @sdevnew:	store the address of the newly allocated Scsi_Device
+ * @inq_result:	holds the result of a previous INQUIRY to the LUN
+ * @bflags:	black/white list flag
+ *
+ * Description:
+ *     Allocate and initialize a Scsi_Device matching sdevscan. Optionally
+ *     set fields based on values in *@bflags. If @sdevnew is not
+ *     NULL, store the address of the new Scsi_Device in *@sdevnew (needed
+ *     when scanning a particular LUN).
+ *
+ * Return:
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ **/
+static int scsi_add_lun(struct scsi_device *sdev, char *inq_result, int *bflags)
+{
+	/*
+	 * XXX do not save the inquiry, since it can change underneath us,
+	 * save just vendor/model/rev.
+	 *
+	 * Rather than save it and have an ioctl that retrieves the saved
+	 * value, have an ioctl that executes the same INQUIRY code used
+	 * in scsi_probe_lun, let user level programs doing INQUIRY
+	 * scanning run at their own risk, or supply a user level program
+	 * that can correctly scan.
+	 */
+	sdev->inquiry = kmalloc(sdev->inquiry_len, GFP_ATOMIC);
+	if (sdev->inquiry == NULL) {
+		return SCSI_SCAN_NO_RESPONSE;
+	}
+
+	memcpy(sdev->inquiry, inq_result, sdev->inquiry_len);
+	sdev->vendor = (char *) (sdev->inquiry + 8);
+	sdev->model = (char *) (sdev->inquiry + 16);
+	sdev->rev = (char *) (sdev->inquiry + 32);
+
+	if (*bflags & BLIST_ISROM) {
+		/*
+		 * It would be better to modify sdev->type, and set
+		 * sdev->removable, but then the print_inquiry() output
+		 * would not show TYPE_ROM; if print_inquiry() is removed
+		 * the issue goes away.
+		 */
+		inq_result[0] = TYPE_ROM;
+		inq_result[1] |= 0x80;	/* removable */
+	} else if (*bflags & BLIST_NO_ULD_ATTACH)
+		sdev->no_uld_attach = 1;
+
+	switch (sdev->type = (inq_result[0] & 0x1f)) {
+	case TYPE_TAPE:
+	case TYPE_DISK:
+	case TYPE_PRINTER:
+	case TYPE_MOD:
+	case TYPE_PROCESSOR:
+	case TYPE_SCANNER:
+	case TYPE_MEDIUM_CHANGER:
+	case TYPE_ENCLOSURE:
+	case TYPE_COMM:
+		sdev->writeable = 1;
+		break;
+	case TYPE_WORM:
+	case TYPE_ROM:
+		sdev->writeable = 0;
+		break;
+	default:
+		printk(KERN_INFO "scsi: unknown device type %d\n", sdev->type);
+	}
+
+	print_inquiry(inq_result);
+
+	/*
+	 * For a peripheral qualifier (PQ) value of 1 (001b), the SCSI
+	 * spec says: The device server is capable of supporting the
+	 * specified peripheral device type on this logical unit. However,
+	 * the physical device is not currently connected to this logical
+	 * unit.
+	 *
+	 * The above is vague, as it implies that we could treat 001 and
+	 * 011 the same. Stay compatible with previous code, and create a
+	 * Scsi_Device for a PQ of 1
+	 *
+	 * Don't set the device offline here; rather let the upper
+	 * level drivers eval the PQ to decide whether they should
+	 * attach. So remove ((inq_result[0] >> 5) & 7) == 1 check.
+	 */ 
+
+	sdev->inq_periph_qual = (inq_result[0] >> 5) & 7;
+	sdev->removable = (0x80 & inq_result[1]) >> 7;
+	sdev->lockable = sdev->removable;
+	sdev->soft_reset = (inq_result[7] & 1) && ((inq_result[3] & 7) == 2);
+
+	if (sdev->scsi_level >= SCSI_3 || (sdev->inquiry_len > 56 &&
+		inq_result[56] & 0x04))
+		sdev->ppr = 1;
+	if (inq_result[7] & 0x60)
+		sdev->wdtr = 1;
+	if (inq_result[7] & 0x10)
+		sdev->sdtr = 1;
+
+	sprintf(sdev->devfs_name, "scsi/host%d/bus%d/target%d/lun%d",
+				sdev->host->host_no, sdev->channel,
+				sdev->id, sdev->lun);
+
+	/*
+	 * End driverfs/devfs code.
+	 */
+
+	if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
+	    !(*bflags & BLIST_NOTQ))
+		sdev->tagged_supported = 1;
+	/*
+	 * Some devices (Texel CD ROM drives) have handshaking problems
+	 * when used with the Seagate controllers. borken is initialized
+	 * to 1, and then set it to 0 here.
+	 */
+	if ((*bflags & BLIST_BORKEN) == 0)
+		sdev->borken = 0;
+
+	/*
+	 * Apparently some really broken devices (contrary to the SCSI
+	 * standards) need to be selected without asserting ATN
+	 */
+	if (*bflags & BLIST_SELECT_NO_ATN)
+		sdev->select_no_atn = 1;
+
+	/*
+	 * Some devices may not want to have a start command automatically
+	 * issued when a device is added.
+	 */
+	if (*bflags & BLIST_NOSTARTONADD)
+		sdev->no_start_on_add = 1;
+
+	if (*bflags & BLIST_SINGLELUN)
+		sdev->single_lun = 1;
+
+
+	sdev->use_10_for_rw = 1;
+
+	if (*bflags & BLIST_MS_SKIP_PAGE_08)
+		sdev->skip_ms_page_8 = 1;
+
+	if (*bflags & BLIST_MS_SKIP_PAGE_3F)
+		sdev->skip_ms_page_3f = 1;
+
+	if (*bflags & BLIST_USE_10_BYTE_MS)
+		sdev->use_10_for_ms = 1;
+
+	/* set the device running here so that slave configure
+	 * may do I/O */
+	scsi_device_set_state(sdev, SDEV_RUNNING);
+
+	if (*bflags & BLIST_MS_192_BYTES_FOR_3F)
+		sdev->use_192_bytes_for_3f = 1;
+
+	if (*bflags & BLIST_NOT_LOCKABLE)
+		sdev->lockable = 0;
+
+	if (*bflags & BLIST_RETRY_HWERROR)
+		sdev->retry_hwerror = 1;
+
+	transport_configure_device(&sdev->sdev_gendev);
+
+	if (sdev->host->hostt->slave_configure)
+		sdev->host->hostt->slave_configure(sdev);
+
+	/*
+	 * Ok, the device is now all set up, we can
+	 * register it and tell the rest of the kernel
+	 * about it.
+	 */
+	scsi_sysfs_add_sdev(sdev);
+
+	return SCSI_SCAN_LUN_PRESENT;
+}
+
+/**
+ * scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
+ * @starget:	pointer to target device structure
+ * @lun:	LUN of target device
+ * @sdevscan:	probe the LUN corresponding to this Scsi_Device
+ * @sdevnew:	store the value of any new Scsi_Device allocated
+ * @bflagsp:	store bflags here if not NULL
+ *
+ * Description:
+ *     Call scsi_probe_lun, if a LUN with an attached device is found,
+ *     allocate and set it up by calling scsi_add_lun.
+ *
+ * Return:
+ *     SCSI_SCAN_NO_RESPONSE: could not allocate or setup a Scsi_Device
+ *     SCSI_SCAN_TARGET_PRESENT: target responded, but no device is
+ *         attached at the LUN
+ *     SCSI_SCAN_LUN_PRESENT: a new Scsi_Device was allocated and initialized
+ **/
+static int scsi_probe_and_add_lun(struct scsi_target *starget,
+				  uint lun, int *bflagsp,
+				  struct scsi_device **sdevp, int rescan,
+				  void *hostdata)
+{
+	struct scsi_device *sdev;
+	struct scsi_request *sreq;
+	unsigned char *result;
+	int bflags, res = SCSI_SCAN_NO_RESPONSE;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+
+	/*
+	 * The rescan flag is used as an optimization, the first scan of a
+	 * host adapter calls into here with rescan == 0.
+	 */
+	if (rescan) {
+		sdev = scsi_device_lookup_by_target(starget, lun);
+		if (sdev) {
+			SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+				"scsi scan: device exists on %s\n",
+				sdev->sdev_gendev.bus_id));
+			if (sdevp)
+				*sdevp = sdev;
+			else
+				scsi_device_put(sdev);
+
+			if (bflagsp)
+				*bflagsp = scsi_get_device_flags(sdev,
+								 sdev->vendor,
+								 sdev->model);
+			return SCSI_SCAN_LUN_PRESENT;
+		}
+	}
+
+	sdev = scsi_alloc_sdev(starget, lun, hostdata);
+	if (!sdev)
+		goto out;
+	sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
+	if (!sreq)
+		goto out_free_sdev;
+	result = kmalloc(256, GFP_ATOMIC |
+			(shost->unchecked_isa_dma) ? __GFP_DMA : 0);
+	if (!result)
+		goto out_free_sreq;
+
+	scsi_probe_lun(sreq, result, &bflags);
+	if (sreq->sr_result)
+		goto out_free_result;
+
+	/*
+	 * result contains valid SCSI INQUIRY data.
+	 */
+	if ((result[0] >> 5) == 3) {
+		/*
+		 * For a Peripheral qualifier 3 (011b), the SCSI
+		 * spec says: The device server is not capable of
+		 * supporting a physical device on this logical
+		 * unit.
+		 *
+		 * For disks, this implies that there is no
+		 * logical disk configured at sdev->lun, but there
+		 * is a target id responding.
+		 */
+		SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO
+					"scsi scan: peripheral qualifier of 3,"
+					" no device added\n"));
+		res = SCSI_SCAN_TARGET_PRESENT;
+		goto out_free_result;
+	}
+
+	res = scsi_add_lun(sdev, result, &bflags);
+	if (res == SCSI_SCAN_LUN_PRESENT) {
+		if (bflags & BLIST_KEY) {
+			sdev->lockable = 0;
+			scsi_unlock_floptical(sreq, result);
+		}
+		if (bflagsp)
+			*bflagsp = bflags;
+	}
+
+ out_free_result:
+	kfree(result);
+ out_free_sreq:
+	scsi_release_request(sreq);
+ out_free_sdev:
+	if (res == SCSI_SCAN_LUN_PRESENT) {
+		if (sdevp) {
+			scsi_device_get(sdev);
+			*sdevp = sdev;
+		}
+	} else {
+		if (sdev->host->hostt->slave_destroy)
+			sdev->host->hostt->slave_destroy(sdev);
+		transport_destroy_device(&sdev->sdev_gendev);
+		put_device(&sdev->sdev_gendev);
+	}
+ out:
+	return res;
+}
+
+/**
+ * scsi_sequential_lun_scan - sequentially scan a SCSI target
+ * @starget:	pointer to target structure to scan
+ * @bflags:	black/white list flag for LUN 0
+ * @lun0_res:	result of scanning LUN 0
+ *
+ * Description:
+ *     Generally, scan from LUN 1 (LUN 0 is assumed to already have been
+ *     scanned) to some maximum lun until a LUN is found with no device
+ *     attached. Use the bflags to figure out any oddities.
+ *
+ *     Modifies sdevscan->lun.
+ **/
+static void scsi_sequential_lun_scan(struct scsi_target *starget,
+				     int bflags, int lun0_res, int scsi_level,
+				     int rescan)
+{
+	unsigned int sparse_lun, lun, max_dev_lun;
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+
+	SCSI_LOG_SCAN_BUS(3, printk(KERN_INFO "scsi scan: Sequential scan of"
+				    "%s\n", starget->dev.bus_id));
+
+	max_dev_lun = min(max_scsi_luns, shost->max_lun);
+	/*
+	 * If this device is known to support sparse multiple units,
+	 * override the other settings, and scan all of them. Normally,
+	 * SCSI-3 devices should be scanned via the REPORT LUNS.
+	 */
+	if (bflags & BLIST_SPARSELUN) {
+		max_dev_lun = shost->max_lun;
+		sparse_lun = 1;
+	} else
+		sparse_lun = 0;
+
+	/*
+	 * If not sparse lun and no device attached at LUN 0 do not scan
+	 * any further.
+	 */
+	if (!sparse_lun && (lun0_res != SCSI_SCAN_LUN_PRESENT))
+		return;
+
+	/*
+	 * If less than SCSI_1_CSS, and no special lun scaning, stop
+	 * scanning; this matches 2.4 behaviour, but could just be a bug
+	 * (to continue scanning a SCSI_1_CSS device).
+	 *
+	 * This test is broken.  We might not have any device on lun0 for
+	 * a sparselun device, and if that's the case then how would we
+	 * know the real scsi_level, eh?  It might make sense to just not
+	 * scan any SCSI_1 device for non-0 luns, but that check would best
+	 * go into scsi_alloc_sdev() and just have it return null when asked
+	 * to alloc an sdev for lun > 0 on an already found SCSI_1 device.
+	 *
+	if ((sdevscan->scsi_level < SCSI_1_CCS) &&
+	    ((bflags & (BLIST_FORCELUN | BLIST_SPARSELUN | BLIST_MAX5LUN))
+	     == 0))
+		return;
+	 */
+	/*
+	 * If this device is known to support multiple units, override
+	 * the other settings, and scan all of them.
+	 */
+	if (bflags & BLIST_FORCELUN)
+		max_dev_lun = shost->max_lun;
+	/*
+	 * REGAL CDC-4X: avoid hang after LUN 4
+	 */
+	if (bflags & BLIST_MAX5LUN)
+		max_dev_lun = min(5U, max_dev_lun);
+	/*
+	 * Do not scan SCSI-2 or lower device past LUN 7, unless
+	 * BLIST_LARGELUN.
+	 */
+	if (scsi_level < SCSI_3 && !(bflags & BLIST_LARGELUN))
+		max_dev_lun = min(8U, max_dev_lun);
+
+	/*
+	 * We have already scanned LUN 0, so start at LUN 1. Keep scanning
+	 * until we reach the max, or no LUN is found and we are not
+	 * sparse_lun.
+	 */
+	for (lun = 1; lun < max_dev_lun; ++lun)
+		if ((scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan,
+					    NULL) != SCSI_SCAN_LUN_PRESENT) &&
+		    !sparse_lun)
+			return;
+}
+
+/**
+ * scsilun_to_int: convert a scsi_lun to an int
+ * @scsilun:	struct scsi_lun to be converted.
+ *
+ * Description:
+ *     Convert @scsilun from a struct scsi_lun to a four byte host byte-ordered
+ *     integer, and return the result. The caller must check for
+ *     truncation before using this function.
+ *
+ * Notes:
+ *     The struct scsi_lun is assumed to be four levels, with each level
+ *     effectively containing a SCSI byte-ordered (big endian) short; the
+ *     addressing bits of each level are ignored (the highest two bits).
+ *     For a description of the LUN format, post SCSI-3 see the SCSI
+ *     Architecture Model, for SCSI-3 see the SCSI Controller Commands.
+ *
+ *     Given a struct scsi_lun of: 0a 04 0b 03 00 00 00 00, this function returns
+ *     the integer: 0x0b030a04
+ **/
+static int scsilun_to_int(struct scsi_lun *scsilun)
+{
+	int i;
+	unsigned int lun;
+
+	lun = 0;
+	for (i = 0; i < sizeof(lun); i += 2)
+		lun = lun | (((scsilun->scsi_lun[i] << 8) |
+			      scsilun->scsi_lun[i + 1]) << (i * 8));
+	return lun;
+}
+
+/**
+ * scsi_report_lun_scan - Scan using SCSI REPORT LUN results
+ * @sdevscan:	scan the host, channel, and id of this Scsi_Device
+ *
+ * Description:
+ *     If @sdevscan is for a SCSI-3 or up device, send a REPORT LUN
+ *     command, and scan the resulting list of LUNs by calling
+ *     scsi_probe_and_add_lun.
+ *
+ *     Modifies sdevscan->lun.
+ *
+ * Return:
+ *     0: scan completed (or no memory, so further scanning is futile)
+ *     1: no report lun scan, or not configured
+ **/
+static int scsi_report_lun_scan(struct scsi_device *sdev, int bflags,
+				int rescan)
+{
+	char devname[64];
+	unsigned char scsi_cmd[MAX_COMMAND_SIZE];
+	unsigned int length;
+	unsigned int lun;
+	unsigned int num_luns;
+	unsigned int retries;
+	struct scsi_lun *lunp, *lun_data;
+	struct scsi_request *sreq;
+	u8 *data;
+	struct scsi_sense_hdr sshdr;
+	struct scsi_target *starget = scsi_target(sdev);
+
+	/*
+	 * Only support SCSI-3 and up devices if BLIST_NOREPORTLUN is not set.
+	 * Also allow SCSI-2 if BLIST_REPORTLUN2 is set and host adapter does
+	 * support more than 8 LUNs.
+	 */
+	if ((bflags & BLIST_NOREPORTLUN) || 
+	     sdev->scsi_level < SCSI_2 ||
+	    (sdev->scsi_level < SCSI_3 && 
+	     (!(bflags & BLIST_REPORTLUN2) || sdev->host->max_lun <= 8)) )
+		return 1;
+	if (bflags & BLIST_NOLUN)
+		return 0;
+
+	sreq = scsi_allocate_request(sdev, GFP_ATOMIC);
+	if (!sreq)
+		goto out;
+
+	sprintf(devname, "host %d channel %d id %d",
+		sdev->host->host_no, sdev->channel, sdev->id);
+
+	/*
+	 * Allocate enough to hold the header (the same size as one scsi_lun)
+	 * plus the max number of luns we are requesting.
+	 *
+	 * Reallocating and trying again (with the exact amount we need)
+	 * would be nice, but then we need to somehow limit the size
+	 * allocated based on the available memory and the limits of
+	 * kmalloc - we don't want a kmalloc() failure of a huge value to
+	 * prevent us from finding any LUNs on this target.
+	 */
+	length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
+	lun_data = kmalloc(length, GFP_ATOMIC |
+			   (sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
+	if (!lun_data)
+		goto out_release_request;
+
+	scsi_cmd[0] = REPORT_LUNS;
+
+	/*
+	 * bytes 1 - 5: reserved, set to zero.
+	 */
+	memset(&scsi_cmd[1], 0, 5);
+
+	/*
+	 * bytes 6 - 9: length of the command.
+	 */
+	scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff;
+	scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff;
+	scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff;
+	scsi_cmd[9] = (unsigned char) length & 0xff;
+
+	scsi_cmd[10] = 0;	/* reserved */
+	scsi_cmd[11] = 0;	/* control */
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+	/*
+	 * We can get a UNIT ATTENTION, for example a power on/reset, so
+	 * retry a few times (like sd.c does for TEST UNIT READY).
+	 * Experience shows some combinations of adapter/devices get at
+	 * least two power on/resets.
+	 *
+	 * Illegal requests (for devices that do not support REPORT LUNS)
+	 * should come through as a check condition, and will not generate
+	 * a retry.
+	 */
+	for (retries = 0; retries < 3; retries++) {
+		SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: Sending"
+				" REPORT LUNS to %s (try %d)\n", devname,
+				retries));
+		scsi_wait_req(sreq, scsi_cmd, lun_data, length,
+				SCSI_TIMEOUT + 4*HZ, 3);
+		SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUNS"
+				" %s (try %d) result 0x%x\n", sreq->sr_result
+				?  "failed" : "successful", retries,
+				sreq->sr_result));
+		if (sreq->sr_result == 0)
+			break;
+		else if (scsi_request_normalize_sense(sreq, &sshdr)) {
+			if (sshdr.sense_key != UNIT_ATTENTION)
+				break;
+		}
+	}
+
+	if (sreq->sr_result) {
+		/*
+		 * The device probably does not support a REPORT LUN command
+		 */
+		kfree(lun_data);
+		scsi_release_request(sreq);
+		return 1;
+	}
+	scsi_release_request(sreq);
+
+	/*
+	 * Get the length from the first four bytes of lun_data.
+	 */
+	data = (u8 *) lun_data->scsi_lun;
+	length = ((data[0] << 24) | (data[1] << 16) |
+		  (data[2] << 8) | (data[3] << 0));
+
+	num_luns = (length / sizeof(struct scsi_lun));
+	if (num_luns > max_scsi_report_luns) {
+		printk(KERN_WARNING "scsi: On %s only %d (max_scsi_report_luns)"
+		       " of %d luns reported, try increasing"
+		       " max_scsi_report_luns.\n", devname,
+		       max_scsi_report_luns, num_luns);
+		num_luns = max_scsi_report_luns;
+	}
+
+	SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "scsi scan: REPORT LUN scan of"
+			" host %d channel %d id %d\n", sdev->host->host_no,
+			sdev->channel, sdev->id));
+
+	/*
+	 * Scan the luns in lun_data. The entry at offset 0 is really
+	 * the header, so start at 1 and go up to and including num_luns.
+	 */
+	for (lunp = &lun_data[1]; lunp <= &lun_data[num_luns]; lunp++) {
+		lun = scsilun_to_int(lunp);
+
+		/*
+		 * Check if the unused part of lunp is non-zero, and so
+		 * does not fit in lun.
+		 */
+		if (memcmp(&lunp->scsi_lun[sizeof(lun)], "\0\0\0\0", 4)) {
+			int i;
+
+			/*
+			 * Output an error displaying the LUN in byte order,
+			 * this differs from what linux would print for the
+			 * integer LUN value.
+			 */
+			printk(KERN_WARNING "scsi: %s lun 0x", devname);
+			data = (char *)lunp->scsi_lun;
+			for (i = 0; i < sizeof(struct scsi_lun); i++)
+				printk("%02x", data[i]);
+			printk(" has a LUN larger than currently supported.\n");
+		} else if (lun == 0) {
+			/*
+			 * LUN 0 has already been scanned.
+			 */
+		} else if (lun > sdev->host->max_lun) {
+			printk(KERN_WARNING "scsi: %s lun%d has a LUN larger"
+			       " than allowed by the host adapter\n",
+			       devname, lun);
+		} else {
+			int res;
+
+			res = scsi_probe_and_add_lun(starget,
+				lun, NULL, NULL, rescan, NULL);
+			if (res == SCSI_SCAN_NO_RESPONSE) {
+				/*
+				 * Got some results, but now none, abort.
+				 */
+				printk(KERN_ERR "scsi: Unexpected response"
+				       " from %s lun %d while scanning, scan"
+				       " aborted\n", devname, lun);
+				break;
+			}
+		}
+	}
+
+	kfree(lun_data);
+	return 0;
+
+ out_release_request:
+	scsi_release_request(sreq);
+ out:
+	/*
+	 * We are out of memory, don't try scanning any further.
+	 */
+	printk(ALLOC_FAILURE_MSG, __FUNCTION__);
+	return 0;
+}
+
+struct scsi_device *__scsi_add_device(struct Scsi_Host *shost, uint channel,
+				      uint id, uint lun, void *hostdata)
+{
+	struct scsi_device *sdev;
+	struct device *parent = &shost->shost_gendev;
+	int res;
+	struct scsi_target *starget = scsi_alloc_target(parent, channel, id);
+
+	if (!starget)
+		return ERR_PTR(-ENOMEM);
+
+	down(&shost->scan_mutex);
+	res = scsi_probe_and_add_lun(starget, lun, NULL, &sdev, 1, hostdata);
+	if (res != SCSI_SCAN_LUN_PRESENT)
+		sdev = ERR_PTR(-ENODEV);
+	up(&shost->scan_mutex);
+	scsi_target_reap(starget);
+	put_device(&starget->dev);
+
+	return sdev;
+}
+EXPORT_SYMBOL(__scsi_add_device);
+
+void scsi_rescan_device(struct device *dev)
+{
+	struct scsi_driver *drv;
+	
+	if (!dev->driver)
+		return;
+
+	drv = to_scsi_driver(dev->driver);
+	if (try_module_get(drv->owner)) {
+		if (drv->rescan)
+			drv->rescan(dev);
+		module_put(drv->owner);
+	}
+}
+EXPORT_SYMBOL(scsi_rescan_device);
+
+/**
+ * scsi_scan_target - scan a target id, possibly including all LUNs on the
+ *     target.
+ * @sdevsca:	Scsi_Device handle for scanning
+ * @shost:	host to scan
+ * @channel:	channel to scan
+ * @id:		target id to scan
+ *
+ * Description:
+ *     Scan the target id on @shost, @channel, and @id. Scan at least LUN
+ *     0, and possibly all LUNs on the target id.
+ *
+ *     Use the pre-allocated @sdevscan as a handle for the scanning. This
+ *     function sets sdevscan->host, sdevscan->id and sdevscan->lun; the
+ *     scanning functions modify sdevscan->lun.
+ *
+ *     First try a REPORT LUN scan, if that does not scan the target, do a
+ *     sequential scan of LUNs on the target id.
+ **/
+void scsi_scan_target(struct device *parent, unsigned int channel,
+		      unsigned int id, unsigned int lun, int rescan)
+{
+	struct Scsi_Host *shost = dev_to_shost(parent);
+	int bflags = 0;
+	int res;
+	struct scsi_device *sdev = NULL;
+	struct scsi_target *starget;
+
+	if (shost->this_id == id)
+		/*
+		 * Don't scan the host adapter
+		 */
+		return;
+
+
+	starget = scsi_alloc_target(parent, channel, id);
+
+	if (!starget)
+		return;
+
+	get_device(&starget->dev);
+	if (lun != SCAN_WILD_CARD) {
+		/*
+		 * Scan for a specific host/chan/id/lun.
+		 */
+		scsi_probe_and_add_lun(starget, lun, NULL, NULL, rescan, NULL);
+		goto out_reap;
+	}
+
+	/*
+	 * Scan LUN 0, if there is some response, scan further. Ideally, we
+	 * would not configure LUN 0 until all LUNs are scanned.
+	 */
+	res = scsi_probe_and_add_lun(starget, 0, &bflags, &sdev, rescan, NULL);
+	if (res == SCSI_SCAN_LUN_PRESENT) {
+		if (scsi_report_lun_scan(sdev, bflags, rescan) != 0)
+			/*
+			 * The REPORT LUN did not scan the target,
+			 * do a sequential scan.
+			 */
+			scsi_sequential_lun_scan(starget, bflags,
+				       	res, sdev->scsi_level, rescan);
+	} else if (res == SCSI_SCAN_TARGET_PRESENT) {
+		/*
+		 * There's a target here, but lun 0 is offline so we
+		 * can't use the report_lun scan.  Fall back to a
+		 * sequential lun scan with a bflags of SPARSELUN and
+		 * a default scsi level of SCSI_2
+		 */
+		scsi_sequential_lun_scan(starget, BLIST_SPARSELUN,
+				SCSI_SCAN_TARGET_PRESENT, SCSI_2, rescan);
+	}
+	if (sdev)
+		scsi_device_put(sdev);
+
+ out_reap:
+	/* now determine if the target has any children at all
+	 * and if not, nuke it */
+	scsi_target_reap(starget);
+
+	put_device(&starget->dev);
+}
+EXPORT_SYMBOL(scsi_scan_target);
+
+static void scsi_scan_channel(struct Scsi_Host *shost, unsigned int channel,
+			      unsigned int id, unsigned int lun, int rescan)
+{
+	uint order_id;
+
+	if (id == SCAN_WILD_CARD)
+		for (id = 0; id < shost->max_id; ++id) {
+			/*
+			 * XXX adapter drivers when possible (FCP, iSCSI)
+			 * could modify max_id to match the current max,
+			 * not the absolute max.
+			 *
+			 * XXX add a shost id iterator, so for example,
+			 * the FC ID can be the same as a target id
+			 * without a huge overhead of sparse id's.
+			 */
+			if (shost->reverse_ordering)
+				/*
+				 * Scan from high to low id.
+				 */
+				order_id = shost->max_id - id - 1;
+			else
+				order_id = id;
+			scsi_scan_target(&shost->shost_gendev, channel, order_id, lun, rescan);
+		}
+	else
+		scsi_scan_target(&shost->shost_gendev, channel, id, lun, rescan);
+}
+
+int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
+			    unsigned int id, unsigned int lun, int rescan)
+{
+	SCSI_LOG_SCAN_BUS(3, printk (KERN_INFO "%s: <%u:%u:%u:%u>\n",
+		__FUNCTION__, shost->host_no, channel, id, lun));
+
+	if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
+	    ((id != SCAN_WILD_CARD) && (id > shost->max_id)) ||
+	    ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+		return -EINVAL;
+
+	down(&shost->scan_mutex);
+	if (channel == SCAN_WILD_CARD) 
+		for (channel = 0; channel <= shost->max_channel; channel++)
+			scsi_scan_channel(shost, channel, id, lun, rescan);
+	else
+		scsi_scan_channel(shost, channel, id, lun, rescan);
+	up(&shost->scan_mutex);
+
+	return 0;
+}
+
+/**
+ * scsi_scan_host - scan the given adapter
+ * @shost:	adapter to scan
+ **/
+void scsi_scan_host(struct Scsi_Host *shost)
+{
+	scsi_scan_host_selected(shost, SCAN_WILD_CARD, SCAN_WILD_CARD,
+				SCAN_WILD_CARD, 0);
+}
+EXPORT_SYMBOL(scsi_scan_host);
+
+/**
+ * scsi_scan_single_target - scan the given SCSI target
+ * @shost:         adapter to scan
+ * @chan:          channel to scan
+ * @id:            target id to scan
+ **/
+void scsi_scan_single_target(struct Scsi_Host *shost, 
+	unsigned int chan, unsigned int id)
+{
+	scsi_scan_host_selected(shost, chan, id, SCAN_WILD_CARD, 1);
+}
+EXPORT_SYMBOL(scsi_scan_single_target);
+
+void scsi_forget_host(struct Scsi_Host *shost)
+{
+	struct scsi_target *starget, *tmp;
+	unsigned long flags;
+
+	/*
+	 * Ok, this look a bit strange.  We always look for the first device
+	 * on the list as scsi_remove_device removes them from it - thus we
+	 * also have to release the lock.
+	 * We don't need to get another reference to the device before
+	 * releasing the lock as we already own the reference from
+	 * scsi_register_device that's release in scsi_remove_device.  And
+	 * after that we don't look at sdev anymore.
+	 */
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_for_each_entry_safe(starget, tmp, &shost->__targets, siblings) {
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		scsi_remove_target(&starget->dev);
+		spin_lock_irqsave(shost->host_lock, flags);
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+/*
+ * Function:    scsi_get_host_dev()
+ *
+ * Purpose:     Create a Scsi_Device that points to the host adapter itself.
+ *
+ * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ *
+ * Lock status: None assumed.
+ *
+ * Returns:     The Scsi_Device or NULL
+ *
+ * Notes:
+ *	Attach a single Scsi_Device to the Scsi_Host - this should
+ *	be made to look like a "pseudo-device" that points to the
+ *	HA itself.
+ *
+ *	Note - this device is not accessible from any high-level
+ *	drivers (including generics), which is probably not
+ *	optimal.  We can add hooks later to attach 
+ */
+struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+	struct scsi_target *starget;
+
+	starget = scsi_alloc_target(&shost->shost_gendev, 0, shost->this_id);
+	if (!starget)
+		return NULL;
+
+	sdev = scsi_alloc_sdev(starget, 0, NULL);
+	if (sdev) {
+		sdev->sdev_gendev.parent = get_device(&starget->dev);
+		sdev->borken = 0;
+	}
+	put_device(&starget->dev);
+	return sdev;
+}
+EXPORT_SYMBOL(scsi_get_host_dev);
+
+/*
+ * Function:    scsi_free_host_dev()
+ *
+ * Purpose:     Free a scsi_device that points to the host adapter itself.
+ *
+ * Arguments:   SHpnt   - Host that needs a Scsi_Device
+ *
+ * Lock status: None assumed.
+ *
+ * Returns:     Nothing
+ *
+ * Notes:
+ */
+void scsi_free_host_dev(struct scsi_device *sdev)
+{
+	BUG_ON(sdev->id != sdev->host->this_id);
+
+	if (sdev->host->hostt->slave_destroy)
+		sdev->host->hostt->slave_destroy(sdev);
+	transport_destroy_device(&sdev->sdev_gendev);
+	put_device(&sdev->sdev_gendev);
+}
+EXPORT_SYMBOL(scsi_free_host_dev);
+
diff --git a/drivers/scsi/scsi_sysctl.c b/drivers/scsi/scsi_sysctl.c
new file mode 100644
index 0000000..04d06c2
--- /dev/null
+++ b/drivers/scsi/scsi_sysctl.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2003 Christoph Hellwig.
+ *	Released under GPL v2.
+ */
+
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
+
+#include "scsi_logging.h"
+
+
+static ctl_table scsi_table[] = {
+	{ .ctl_name	= DEV_SCSI_LOGGING_LEVEL,
+	  .procname	= "logging_level",
+	  .data		= &scsi_logging_level,
+	  .maxlen	= sizeof(scsi_logging_level),
+	  .mode		= 0644,
+	  .proc_handler	= &proc_dointvec },
+	{ }
+};
+
+static ctl_table scsi_dir_table[] = {
+	{ .ctl_name	= DEV_SCSI,
+	  .procname	= "scsi",
+	  .mode		= 0555,
+	  .child	= scsi_table },
+	{ }
+};
+
+static ctl_table scsi_root_table[] = {
+	{ .ctl_name	= CTL_DEV,
+	  .procname	= "dev",
+	  .mode		= 0555,
+	  .child	= scsi_dir_table },
+	{ }
+};
+
+static struct ctl_table_header *scsi_table_header;
+
+int __init scsi_init_sysctl(void)
+{
+	scsi_table_header = register_sysctl_table(scsi_root_table, 1);
+	if (!scsi_table_header)
+		return -ENOMEM;
+	return 0;
+}
+
+void scsi_exit_sysctl(void)
+{
+	unregister_sysctl_table(scsi_table_header);
+}
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
new file mode 100644
index 0000000..134d3a3
--- /dev/null
+++ b/drivers/scsi/scsi_sysfs.c
@@ -0,0 +1,816 @@
+/*
+ * scsi_sysfs.c
+ *
+ * SCSI sysfs interface routines.
+ *
+ * Created to pull SCSI mid layer sysfs routines into one file.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/device.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_transport.h>
+
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+static struct {
+	enum scsi_device_state	value;
+	char			*name;
+} sdev_states[] = {
+	{ SDEV_CREATED, "created" },
+	{ SDEV_RUNNING, "running" },
+	{ SDEV_CANCEL, "cancel" },
+	{ SDEV_DEL, "deleted" },
+	{ SDEV_QUIESCE, "quiesce" },
+	{ SDEV_OFFLINE,	"offline" },
+	{ SDEV_BLOCK,	"blocked" },
+};
+
+const char *scsi_device_state_name(enum scsi_device_state state)
+{
+	int i;
+	char *name = NULL;
+
+	for (i = 0; i < sizeof(sdev_states)/sizeof(sdev_states[0]); i++) {
+		if (sdev_states[i].value == state) {
+			name = sdev_states[i].name;
+			break;
+		}
+	}
+	return name;
+}
+
+static int check_set(unsigned int *val, char *src)
+{
+	char *last;
+
+	if (strncmp(src, "-", 20) == 0) {
+		*val = SCAN_WILD_CARD;
+	} else {
+		/*
+		 * Doesn't check for int overflow
+		 */
+		*val = simple_strtoul(src, &last, 0);
+		if (*last != '\0')
+			return 1;
+	}
+	return 0;
+}
+
+static int scsi_scan(struct Scsi_Host *shost, const char *str)
+{
+	char s1[15], s2[15], s3[15], junk;
+	unsigned int channel, id, lun;
+	int res;
+
+	res = sscanf(str, "%10s %10s %10s %c", s1, s2, s3, &junk);
+	if (res != 3)
+		return -EINVAL;
+	if (check_set(&channel, s1))
+		return -EINVAL;
+	if (check_set(&id, s2))
+		return -EINVAL;
+	if (check_set(&lun, s3))
+		return -EINVAL;
+	res = scsi_scan_host_selected(shost, channel, id, lun, 1);
+	return res;
+}
+
+/*
+ * shost_show_function: macro to create an attr function that can be used to
+ * show a non-bit field.
+ */
+#define shost_show_function(name, field, format_string)			\
+static ssize_t								\
+show_##name (struct class_device *class_dev, char *buf)			\
+{									\
+	struct Scsi_Host *shost = class_to_shost(class_dev);		\
+	return snprintf (buf, 20, format_string, shost->field);		\
+}
+
+/*
+ * shost_rd_attr: macro to create a function and attribute variable for a
+ * read only field.
+ */
+#define shost_rd_attr2(name, field, format_string)			\
+	shost_show_function(name, field, format_string)			\
+static CLASS_DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
+
+#define shost_rd_attr(field, format_string) \
+shost_rd_attr2(field, field, format_string)
+
+/*
+ * Create the actual show/store functions and data structures.
+ */
+
+static ssize_t store_scan(struct class_device *class_dev, const char *buf,
+			  size_t count)
+{
+	struct Scsi_Host *shost = class_to_shost(class_dev);
+	int res;
+
+	res = scsi_scan(shost, buf);
+	if (res == 0)
+		res = count;
+	return res;
+};
+static CLASS_DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
+
+shost_rd_attr(unique_id, "%u\n");
+shost_rd_attr(host_busy, "%hu\n");
+shost_rd_attr(cmd_per_lun, "%hd\n");
+shost_rd_attr(sg_tablesize, "%hu\n");
+shost_rd_attr(unchecked_isa_dma, "%d\n");
+shost_rd_attr2(proc_name, hostt->proc_name, "%s\n");
+
+static struct class_device_attribute *scsi_sysfs_shost_attrs[] = {
+	&class_device_attr_unique_id,
+	&class_device_attr_host_busy,
+	&class_device_attr_cmd_per_lun,
+	&class_device_attr_sg_tablesize,
+	&class_device_attr_unchecked_isa_dma,
+	&class_device_attr_proc_name,
+	&class_device_attr_scan,
+	NULL
+};
+
+static void scsi_device_cls_release(struct class_device *class_dev)
+{
+	struct scsi_device *sdev;
+
+	sdev = class_to_sdev(class_dev);
+	put_device(&sdev->sdev_gendev);
+}
+
+void scsi_device_dev_release(struct device *dev)
+{
+	struct scsi_device *sdev;
+	struct device *parent;
+	struct scsi_target *starget;
+	unsigned long flags;
+
+	parent = dev->parent;
+	sdev = to_scsi_device(dev);
+	starget = to_scsi_target(parent);
+
+	spin_lock_irqsave(sdev->host->host_lock, flags);
+	starget->reap_ref++;
+	list_del(&sdev->siblings);
+	list_del(&sdev->same_target_siblings);
+	list_del(&sdev->starved_entry);
+	spin_unlock_irqrestore(sdev->host->host_lock, flags);
+
+	if (sdev->request_queue) {
+		sdev->request_queue->queuedata = NULL;
+		scsi_free_queue(sdev->request_queue);
+	}
+
+	scsi_target_reap(scsi_target(sdev));
+
+	kfree(sdev->inquiry);
+	kfree(sdev);
+
+	if (parent)
+		put_device(parent);
+}
+
+struct class sdev_class = {
+	.name		= "scsi_device",
+	.release	= scsi_device_cls_release,
+};
+
+/* all probing is done in the individual ->probe routines */
+static int scsi_bus_match(struct device *dev, struct device_driver *gendrv)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	if (sdp->no_uld_attach)
+		return 0;
+	return (sdp->inq_periph_qual == SCSI_INQ_PQ_CON)? 1: 0;
+}
+
+struct bus_type scsi_bus_type = {
+        .name		= "scsi",
+        .match		= scsi_bus_match,
+};
+
+int scsi_sysfs_register(void)
+{
+	int error;
+
+	error = bus_register(&scsi_bus_type);
+	if (!error) {
+		error = class_register(&sdev_class);
+		if (error)
+			bus_unregister(&scsi_bus_type);
+	}
+
+	return error;
+}
+
+void scsi_sysfs_unregister(void)
+{
+	class_unregister(&sdev_class);
+	bus_unregister(&scsi_bus_type);
+}
+
+/*
+ * sdev_show_function: macro to create an attr function that can be used to
+ * show a non-bit field.
+ */
+#define sdev_show_function(field, format_string)				\
+static ssize_t								\
+sdev_show_##field (struct device *dev, char *buf)				\
+{									\
+	struct scsi_device *sdev;					\
+	sdev = to_scsi_device(dev);					\
+	return snprintf (buf, 20, format_string, sdev->field);		\
+}									\
+
+/*
+ * sdev_rd_attr: macro to create a function and attribute variable for a
+ * read only field.
+ */
+#define sdev_rd_attr(field, format_string)				\
+	sdev_show_function(field, format_string)			\
+static DEVICE_ATTR(field, S_IRUGO, sdev_show_##field, NULL);
+
+
+/*
+ * sdev_rd_attr: create a function and attribute variable for a
+ * read/write field.
+ */
+#define sdev_rw_attr(field, format_string)				\
+	sdev_show_function(field, format_string)				\
+									\
+static ssize_t								\
+sdev_store_##field (struct device *dev, const char *buf, size_t count)	\
+{									\
+	struct scsi_device *sdev;					\
+	sdev = to_scsi_device(dev);					\
+	snscanf (buf, 20, format_string, &sdev->field);			\
+	return count;							\
+}									\
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
+
+/* Currently we don't export bit fields, but we might in future,
+ * so leave this code in */
+#if 0
+/*
+ * sdev_rd_attr: create a function and attribute variable for a
+ * read/write bit field.
+ */
+#define sdev_rw_attr_bit(field)						\
+	sdev_show_function(field, "%d\n")					\
+									\
+static ssize_t								\
+sdev_store_##field (struct device *dev, const char *buf, size_t count)	\
+{									\
+	int ret;							\
+	struct scsi_device *sdev;					\
+	ret = scsi_sdev_check_buf_bit(buf);				\
+	if (ret >= 0)	{						\
+		sdev = to_scsi_device(dev);				\
+		sdev->field = ret;					\
+		ret = count;						\
+	}								\
+	return ret;							\
+}									\
+static DEVICE_ATTR(field, S_IRUGO | S_IWUSR, sdev_show_##field, sdev_store_##field);
+
+/*
+ * scsi_sdev_check_buf_bit: return 0 if buf is "0", return 1 if buf is "1",
+ * else return -EINVAL.
+ */
+static int scsi_sdev_check_buf_bit(const char *buf)
+{
+	if ((buf[1] == '\0') || ((buf[1] == '\n') && (buf[2] == '\0'))) {
+		if (buf[0] == '1')
+			return 1;
+		else if (buf[0] == '0')
+			return 0;
+		else 
+			return -EINVAL;
+	} else
+		return -EINVAL;
+}
+#endif
+/*
+ * Create the actual show/store functions and data structures.
+ */
+sdev_rd_attr (device_blocked, "%d\n");
+sdev_rd_attr (queue_depth, "%d\n");
+sdev_rd_attr (type, "%d\n");
+sdev_rd_attr (scsi_level, "%d\n");
+sdev_rd_attr (vendor, "%.8s\n");
+sdev_rd_attr (model, "%.16s\n");
+sdev_rd_attr (rev, "%.4s\n");
+
+static ssize_t
+sdev_show_timeout (struct device *dev, char *buf)
+{
+	struct scsi_device *sdev;
+	sdev = to_scsi_device(dev);
+	return snprintf (buf, 20, "%d\n", sdev->timeout / HZ);
+}
+
+static ssize_t
+sdev_store_timeout (struct device *dev, const char *buf, size_t count)
+{
+	struct scsi_device *sdev;
+	int timeout;
+	sdev = to_scsi_device(dev);
+	sscanf (buf, "%d\n", &timeout);
+	sdev->timeout = timeout * HZ;
+	return count;
+}
+static DEVICE_ATTR(timeout, S_IRUGO | S_IWUSR, sdev_show_timeout, sdev_store_timeout);
+
+static ssize_t
+store_rescan_field (struct device *dev, const char *buf, size_t count) 
+{
+	scsi_rescan_device(dev);
+	return count;
+}
+static DEVICE_ATTR(rescan, S_IWUSR, NULL, store_rescan_field);
+
+static ssize_t sdev_store_delete(struct device *dev, const char *buf,
+				 size_t count)
+{
+	scsi_remove_device(to_scsi_device(dev));
+	return count;
+};
+static DEVICE_ATTR(delete, S_IWUSR, NULL, sdev_store_delete);
+
+static ssize_t
+store_state_field(struct device *dev, const char *buf, size_t count)
+{
+	int i;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	enum scsi_device_state state = 0;
+
+	for (i = 0; i < sizeof(sdev_states)/sizeof(sdev_states[0]); i++) {
+		const int len = strlen(sdev_states[i].name);
+		if (strncmp(sdev_states[i].name, buf, len) == 0 &&
+		   buf[len] == '\n') {
+			state = sdev_states[i].value;
+			break;
+		}
+	}
+	if (!state)
+		return -EINVAL;
+
+	if (scsi_device_set_state(sdev, state))
+		return -EINVAL;
+	return count;
+}
+
+static ssize_t
+show_state_field(struct device *dev, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	const char *name = scsi_device_state_name(sdev->sdev_state);
+
+	if (!name)
+		return -EINVAL;
+
+	return snprintf(buf, 20, "%s\n", name);
+}
+
+static DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field);
+
+static ssize_t
+show_queue_type_field(struct device *dev, char *buf)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	const char *name = "none";
+
+	if (sdev->ordered_tags)
+		name = "ordered";
+	else if (sdev->simple_tags)
+		name = "simple";
+
+	return snprintf(buf, 20, "%s\n", name);
+}
+
+static DEVICE_ATTR(queue_type, S_IRUGO, show_queue_type_field, NULL);
+
+static ssize_t
+show_iostat_counterbits(struct device *dev, char *buf)
+{
+	return snprintf(buf, 20, "%d\n", (int)sizeof(atomic_t) * 8);
+}
+
+static DEVICE_ATTR(iocounterbits, S_IRUGO, show_iostat_counterbits, NULL);
+
+#define show_sdev_iostat(field)						\
+static ssize_t								\
+show_iostat_##field(struct device *dev, char *buf)			\
+{									\
+	struct scsi_device *sdev = to_scsi_device(dev);			\
+	unsigned long long count = atomic_read(&sdev->field);		\
+	return snprintf(buf, 20, "0x%llx\n", count);			\
+}									\
+static DEVICE_ATTR(field, S_IRUGO, show_iostat_##field, NULL)
+
+show_sdev_iostat(iorequest_cnt);
+show_sdev_iostat(iodone_cnt);
+show_sdev_iostat(ioerr_cnt);
+
+
+/* Default template for device attributes.  May NOT be modified */
+static struct device_attribute *scsi_sysfs_sdev_attrs[] = {
+	&dev_attr_device_blocked,
+	&dev_attr_queue_depth,
+	&dev_attr_queue_type,
+	&dev_attr_type,
+	&dev_attr_scsi_level,
+	&dev_attr_vendor,
+	&dev_attr_model,
+	&dev_attr_rev,
+	&dev_attr_rescan,
+	&dev_attr_delete,
+	&dev_attr_state,
+	&dev_attr_timeout,
+	&dev_attr_iocounterbits,
+	&dev_attr_iorequest_cnt,
+	&dev_attr_iodone_cnt,
+	&dev_attr_ioerr_cnt,
+	NULL
+};
+
+static ssize_t sdev_store_queue_depth_rw(struct device *dev, const char *buf,
+					 size_t count)
+{
+	int depth, retval;
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_host_template *sht = sdev->host->hostt;
+
+	if (!sht->change_queue_depth)
+		return -EINVAL;
+
+	depth = simple_strtoul(buf, NULL, 0);
+
+	if (depth < 1)
+		return -EINVAL;
+
+	retval = sht->change_queue_depth(sdev, depth);
+	if (retval < 0)
+		return retval;
+
+	return count;
+}
+
+static struct device_attribute sdev_attr_queue_depth_rw =
+	__ATTR(queue_depth, S_IRUGO | S_IWUSR, sdev_show_queue_depth,
+	       sdev_store_queue_depth_rw);
+
+static ssize_t sdev_store_queue_type_rw(struct device *dev, const char *buf,
+					size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_host_template *sht = sdev->host->hostt;
+	int tag_type = 0, retval;
+	int prev_tag_type = scsi_get_tag_type(sdev);
+
+	if (!sdev->tagged_supported || !sht->change_queue_type)
+		return -EINVAL;
+
+	if (strncmp(buf, "ordered", 7) == 0)
+		tag_type = MSG_ORDERED_TAG;
+	else if (strncmp(buf, "simple", 6) == 0)
+		tag_type = MSG_SIMPLE_TAG;
+	else if (strncmp(buf, "none", 4) != 0)
+		return -EINVAL;
+
+	if (tag_type == prev_tag_type)
+		return count;
+
+	retval = sht->change_queue_type(sdev, tag_type);
+	if (retval < 0)
+		return retval;
+
+	return count;
+}
+
+static struct device_attribute sdev_attr_queue_type_rw =
+	__ATTR(queue_type, S_IRUGO | S_IWUSR, show_queue_type_field,
+	       sdev_store_queue_type_rw);
+
+static struct device_attribute *attr_changed_internally(
+		struct Scsi_Host *shost,
+		struct device_attribute * attr)
+{
+	if (!strcmp("queue_depth", attr->attr.name)
+	    && shost->hostt->change_queue_depth)
+		return &sdev_attr_queue_depth_rw;
+	else if (!strcmp("queue_type", attr->attr.name)
+	    && shost->hostt->change_queue_type)
+		return &sdev_attr_queue_type_rw;
+	return attr;
+}
+
+
+static struct device_attribute *attr_overridden(
+		struct device_attribute **attrs,
+		struct device_attribute *attr)
+{
+	int i;
+
+	if (!attrs)
+		return NULL;
+	for (i = 0; attrs[i]; i++)
+		if (!strcmp(attrs[i]->attr.name, attr->attr.name))
+			return attrs[i];
+	return NULL;
+}
+
+static int attr_add(struct device *dev, struct device_attribute *attr)
+{
+	struct device_attribute *base_attr;
+
+	/*
+	 * Spare the caller from having to copy things it's not interested in.
+	 */
+	base_attr = attr_overridden(scsi_sysfs_sdev_attrs, attr);
+	if (base_attr) {
+		/* extend permissions */
+		attr->attr.mode |= base_attr->attr.mode;
+
+		/* override null show/store with default */
+		if (!attr->show)
+			attr->show = base_attr->show;
+		if (!attr->store)
+			attr->store = base_attr->store;
+	}
+
+	return device_create_file(dev, attr);
+}
+
+/**
+ * scsi_sysfs_add_sdev - add scsi device to sysfs
+ * @sdev:	scsi_device to add
+ *
+ * Return value:
+ * 	0 on Success / non-zero on Failure
+ **/
+int scsi_sysfs_add_sdev(struct scsi_device *sdev)
+{
+	int error, i;
+
+	if ((error = scsi_device_set_state(sdev, SDEV_RUNNING)) != 0)
+		return error;
+
+	error = device_add(&sdev->sdev_gendev);
+	if (error) {
+		put_device(sdev->sdev_gendev.parent);
+		printk(KERN_INFO "error 1\n");
+		return error;
+	}
+	error = class_device_add(&sdev->sdev_classdev);
+	if (error) {
+		printk(KERN_INFO "error 2\n");
+		goto clean_device;
+	}
+
+	/* take a reference for the sdev_classdev; this is
+	 * released by the sdev_class .release */
+	get_device(&sdev->sdev_gendev);
+	if (sdev->host->hostt->sdev_attrs) {
+		for (i = 0; sdev->host->hostt->sdev_attrs[i]; i++) {
+			error = attr_add(&sdev->sdev_gendev,
+					sdev->host->hostt->sdev_attrs[i]);
+			if (error) {
+				scsi_remove_device(sdev);
+				goto out;
+			}
+		}
+	}
+	
+	for (i = 0; scsi_sysfs_sdev_attrs[i]; i++) {
+		if (!attr_overridden(sdev->host->hostt->sdev_attrs,
+					scsi_sysfs_sdev_attrs[i])) {
+			struct device_attribute * attr = 
+				attr_changed_internally(sdev->host, 
+							scsi_sysfs_sdev_attrs[i]);
+			error = device_create_file(&sdev->sdev_gendev, attr);
+			if (error) {
+				scsi_remove_device(sdev);
+				goto out;
+			}
+		}
+	}
+
+	transport_add_device(&sdev->sdev_gendev);
+ out:
+	return error;
+
+ clean_device:
+	scsi_device_set_state(sdev, SDEV_CANCEL);
+
+	device_del(&sdev->sdev_gendev);
+	transport_destroy_device(&sdev->sdev_gendev);
+	put_device(&sdev->sdev_gendev);
+
+	return error;
+}
+
+/**
+ * scsi_remove_device - unregister a device from the scsi bus
+ * @sdev:	scsi_device to unregister
+ **/
+void scsi_remove_device(struct scsi_device *sdev)
+{
+	struct Scsi_Host *shost = sdev->host;
+
+	down(&shost->scan_mutex);
+	if (scsi_device_set_state(sdev, SDEV_CANCEL) != 0)
+		goto out;
+
+	class_device_unregister(&sdev->sdev_classdev);
+	device_del(&sdev->sdev_gendev);
+	scsi_device_set_state(sdev, SDEV_DEL);
+	if (sdev->host->hostt->slave_destroy)
+		sdev->host->hostt->slave_destroy(sdev);
+	transport_unregister_device(&sdev->sdev_gendev);
+	put_device(&sdev->sdev_gendev);
+out:
+	up(&shost->scan_mutex);
+}
+EXPORT_SYMBOL(scsi_remove_device);
+
+void __scsi_remove_target(struct scsi_target *starget)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	unsigned long flags;
+	struct scsi_device *sdev, *tmp;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	starget->reap_ref++;
+	list_for_each_entry_safe(sdev, tmp, &shost->__devices, siblings) {
+		if (sdev->channel != starget->channel ||
+		    sdev->id != starget->id)
+			continue;
+		spin_unlock_irqrestore(shost->host_lock, flags);
+		scsi_remove_device(sdev);
+		spin_lock_irqsave(shost->host_lock, flags);
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	scsi_target_reap(starget);
+}
+
+/**
+ * scsi_remove_target - try to remove a target and all its devices
+ * @dev: generic starget or parent of generic stargets to be removed
+ *
+ * Note: This is slightly racy.  It is possible that if the user
+ * requests the addition of another device then the target won't be
+ * removed.
+ */
+void scsi_remove_target(struct device *dev)
+{
+	struct device *rdev, *idev, *next;
+
+	if (scsi_is_target_device(dev)) {
+		__scsi_remove_target(to_scsi_target(dev));
+		return;
+	}
+
+	rdev = get_device(dev);
+	list_for_each_entry_safe(idev, next, &dev->children, node) {
+		if (scsi_is_target_device(idev))
+			__scsi_remove_target(to_scsi_target(idev));
+	}
+	put_device(rdev);
+}
+EXPORT_SYMBOL(scsi_remove_target);
+
+int scsi_register_driver(struct device_driver *drv)
+{
+	drv->bus = &scsi_bus_type;
+
+	return driver_register(drv);
+}
+EXPORT_SYMBOL(scsi_register_driver);
+
+int scsi_register_interface(struct class_interface *intf)
+{
+	intf->class = &sdev_class;
+
+	return class_interface_register(intf);
+}
+EXPORT_SYMBOL(scsi_register_interface);
+
+
+static struct class_device_attribute *class_attr_overridden(
+		struct class_device_attribute **attrs,
+		struct class_device_attribute *attr)
+{
+	int i;
+
+	if (!attrs)
+		return NULL;
+	for (i = 0; attrs[i]; i++)
+		if (!strcmp(attrs[i]->attr.name, attr->attr.name))
+			return attrs[i];
+	return NULL;
+}
+
+static int class_attr_add(struct class_device *classdev,
+		struct class_device_attribute *attr)
+{
+	struct class_device_attribute *base_attr;
+
+	/*
+	 * Spare the caller from having to copy things it's not interested in.
+	 */
+	base_attr = class_attr_overridden(scsi_sysfs_shost_attrs, attr);
+	if (base_attr) {
+		/* extend permissions */
+		attr->attr.mode |= base_attr->attr.mode;
+
+		/* override null show/store with default */
+		if (!attr->show)
+			attr->show = base_attr->show;
+		if (!attr->store)
+			attr->store = base_attr->store;
+	}
+
+	return class_device_create_file(classdev, attr);
+}
+
+/**
+ * scsi_sysfs_add_host - add scsi host to subsystem
+ * @shost:     scsi host struct to add to subsystem
+ * @dev:       parent struct device pointer
+ **/
+int scsi_sysfs_add_host(struct Scsi_Host *shost)
+{
+	int error, i;
+
+	if (shost->hostt->shost_attrs) {
+		for (i = 0; shost->hostt->shost_attrs[i]; i++) {
+			error = class_attr_add(&shost->shost_classdev,
+					shost->hostt->shost_attrs[i]);
+			if (error)
+				return error;
+		}
+	}
+
+	for (i = 0; scsi_sysfs_shost_attrs[i]; i++) {
+		if (!class_attr_overridden(shost->hostt->shost_attrs,
+					scsi_sysfs_shost_attrs[i])) {
+			error = class_device_create_file(&shost->shost_classdev,
+					scsi_sysfs_shost_attrs[i]);
+			if (error)
+				return error;
+		}
+	}
+
+	transport_register_device(&shost->shost_gendev);
+	return 0;
+}
+
+void scsi_sysfs_device_initialize(struct scsi_device *sdev)
+{
+	unsigned long flags;
+	struct Scsi_Host *shost = sdev->host;
+	struct scsi_target  *starget = sdev->sdev_target;
+
+	device_initialize(&sdev->sdev_gendev);
+	sdev->sdev_gendev.bus = &scsi_bus_type;
+	sdev->sdev_gendev.release = scsi_device_dev_release;
+	sprintf(sdev->sdev_gendev.bus_id,"%d:%d:%d:%d",
+		sdev->host->host_no, sdev->channel, sdev->id,
+		sdev->lun);
+	
+	class_device_initialize(&sdev->sdev_classdev);
+	sdev->sdev_classdev.dev = &sdev->sdev_gendev;
+	sdev->sdev_classdev.class = &sdev_class;
+	snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE,
+		 "%d:%d:%d:%d", sdev->host->host_no,
+		 sdev->channel, sdev->id, sdev->lun);
+	sdev->scsi_level = SCSI_2;
+	transport_setup_device(&sdev->sdev_gendev);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_add_tail(&sdev->same_target_siblings, &starget->devices);
+	list_add_tail(&sdev->siblings, &shost->__devices);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+}
+
+int scsi_is_sdev_device(const struct device *dev)
+{
+	return dev->release == scsi_device_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_sdev_device);
+
+/* A blank transport template that is used in drivers that don't
+ * yet implement Transport Attributes */
+struct scsi_transport_template blank_transport_template = { { { {NULL, }, }, }, };
diff --git a/drivers/scsi/scsi_transport_fc.c b/drivers/scsi/scsi_transport_fc.c
new file mode 100644
index 0000000..35d1c1e
--- /dev/null
+++ b/drivers/scsi/scsi_transport_fc.c
@@ -0,0 +1,1665 @@
+/* 
+ *  FiberChannel transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *  ========
+ *
+ *  Copyright (C) 2004-2005   James Smart, Emulex Corporation
+ *    Rewrite for host, target, device, and remote port attributes,
+ *    statistics, and service functions...
+ *
+ */
+#include <linux/module.h>
+#include <linux/init.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_fc.h>
+#include "scsi_priv.h"
+
+#define FC_PRINTK(x, l, f, a...)	printk(l "scsi(%d:%d:%d:%d): " f, (x)->host->host_no, (x)->channel, (x)->id, (x)->lun , ##a)
+
+/*
+ * Redefine so that we can have same named attributes in the
+ * sdev/starget/host objects.
+ */
+#define FC_CLASS_DEVICE_ATTR(_prefix,_name,_mode,_show,_store)		\
+struct class_device_attribute class_device_attr_##_prefix##_##_name = 	\
+	__ATTR(_name,_mode,_show,_store)
+
+#define fc_enum_name_search(title, table_type, table)			\
+static const char *get_fc_##title##_name(enum table_type table_key)	\
+{									\
+	int i;								\
+	char *name = NULL;						\
+									\
+	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {		\
+		if (table[i].value == table_key) {			\
+			name = table[i].name;				\
+			break;						\
+		}							\
+	}								\
+	return name;							\
+}
+
+#define fc_enum_name_match(title, table_type, table)			\
+static int get_fc_##title##_match(const char *table_key,		\
+		enum table_type *value)					\
+{									\
+	int i;								\
+									\
+	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {		\
+		if (strncmp(table_key, table[i].name,			\
+				table[i].matchlen) == 0) {		\
+			*value = table[i].value;			\
+			return 0; /* success */				\
+		}							\
+	}								\
+	return 1; /* failure */						\
+}
+
+
+/* Convert fc_port_type values to ascii string name */
+static struct {
+	enum fc_port_type	value;
+	char			*name;
+} fc_port_type_names[] = {
+	{ FC_PORTTYPE_UNKNOWN,		"Unknown" },
+	{ FC_PORTTYPE_OTHER,		"Other" },
+	{ FC_PORTTYPE_NOTPRESENT,	"Not Present" },
+	{ FC_PORTTYPE_NPORT,	"NPort (fabric via point-to-point)" },
+	{ FC_PORTTYPE_NLPORT,	"NLPort (fabric via loop)" },
+	{ FC_PORTTYPE_LPORT,	"LPort (private loop)" },
+	{ FC_PORTTYPE_PTP,	"Point-To-Point (direct nport connection" },
+};
+fc_enum_name_search(port_type, fc_port_type, fc_port_type_names)
+#define FC_PORTTYPE_MAX_NAMELEN		50
+
+
+/* Convert fc_port_state values to ascii string name */
+static struct {
+	enum fc_port_state	value;
+	char			*name;
+} fc_port_state_names[] = {
+	{ FC_PORTSTATE_UNKNOWN,		"Unknown" },
+	{ FC_PORTSTATE_NOTPRESENT,	"Not Present" },
+	{ FC_PORTSTATE_ONLINE,		"Online" },
+	{ FC_PORTSTATE_OFFLINE,		"Offline" },
+	{ FC_PORTSTATE_BLOCKED,		"Blocked" },
+	{ FC_PORTSTATE_BYPASSED,	"Bypassed" },
+	{ FC_PORTSTATE_DIAGNOSTICS,	"Diagnostics" },
+	{ FC_PORTSTATE_LINKDOWN,	"Linkdown" },
+	{ FC_PORTSTATE_ERROR,		"Error" },
+	{ FC_PORTSTATE_LOOPBACK,	"Loopback" },
+};
+fc_enum_name_search(port_state, fc_port_state, fc_port_state_names)
+#define FC_PORTSTATE_MAX_NAMELEN	20
+
+
+/* Convert fc_tgtid_binding_type values to ascii string name */
+static struct {
+	enum fc_tgtid_binding_type	value;
+	char				*name;
+	int				matchlen;
+} fc_tgtid_binding_type_names[] = {
+	{ FC_TGTID_BIND_NONE, "none", 4 },
+	{ FC_TGTID_BIND_BY_WWPN, "wwpn (World Wide Port Name)", 4 },
+	{ FC_TGTID_BIND_BY_WWNN, "wwnn (World Wide Node Name)", 4 },
+	{ FC_TGTID_BIND_BY_ID, "port_id (FC Address)", 7 },
+};
+fc_enum_name_search(tgtid_bind_type, fc_tgtid_binding_type,
+		fc_tgtid_binding_type_names)
+fc_enum_name_match(tgtid_bind_type, fc_tgtid_binding_type,
+		fc_tgtid_binding_type_names)
+#define FC_BINDTYPE_MAX_NAMELEN	30
+
+
+#define fc_bitfield_name_search(title, table)			\
+static ssize_t							\
+get_fc_##title##_names(u32 table_key, char *buf)		\
+{								\
+	char *prefix = "";					\
+	ssize_t len = 0;					\
+	int i;							\
+								\
+	for (i = 0; i < sizeof(table)/sizeof(table[0]); i++) {	\
+		if (table[i].value & table_key) {		\
+			len += sprintf(buf + len, "%s%s",	\
+				prefix, table[i].name);		\
+			prefix = ", ";				\
+		}						\
+	}							\
+	len += sprintf(buf + len, "\n");			\
+	return len;						\
+}
+
+
+/* Convert FC_COS bit values to ascii string name */
+static struct {
+	u32 			value;
+	char			*name;
+} fc_cos_names[] = {
+	{ FC_COS_CLASS1,	"Class 1" },
+	{ FC_COS_CLASS2,	"Class 2" },
+	{ FC_COS_CLASS3,	"Class 3" },
+	{ FC_COS_CLASS4,	"Class 4" },
+	{ FC_COS_CLASS6,	"Class 6" },
+};
+fc_bitfield_name_search(cos, fc_cos_names)
+
+
+/* Convert FC_PORTSPEED bit values to ascii string name */
+static struct {
+	u32 			value;
+	char			*name;
+} fc_port_speed_names[] = {
+	{ FC_PORTSPEED_1GBIT,		"1 Gbit" },
+	{ FC_PORTSPEED_2GBIT,		"2 Gbit" },
+	{ FC_PORTSPEED_4GBIT,		"4 Gbit" },
+	{ FC_PORTSPEED_10GBIT,		"10 Gbit" },
+	{ FC_PORTSPEED_NOT_NEGOTIATED,	"Not Negotiated" },
+};
+fc_bitfield_name_search(port_speed, fc_port_speed_names)
+
+
+static int
+show_fc_fc4s (char *buf, u8 *fc4_list)
+{
+	int i, len=0;
+
+	for (i = 0; i < FC_FC4_LIST_SIZE; i++, fc4_list++)
+		len += sprintf(buf + len , "0x%02x ", *fc4_list);
+	len += sprintf(buf + len, "\n");
+	return len;
+}
+
+
+/* Convert FC_RPORT_ROLE bit values to ascii string name */
+static struct {
+	u32 			value;
+	char			*name;
+} fc_remote_port_role_names[] = {
+	{ FC_RPORT_ROLE_FCP_TARGET,	"FCP Target" },
+	{ FC_RPORT_ROLE_FCP_INITIATOR,	"FCP Initiator" },
+	{ FC_RPORT_ROLE_IP_PORT,	"IP Port" },
+};
+fc_bitfield_name_search(remote_port_roles, fc_remote_port_role_names)
+
+/*
+ * Define roles that are specific to port_id. Values are relative to ROLE_MASK.
+ */
+#define FC_WELLKNOWN_PORTID_MASK	0xfffff0
+#define FC_WELLKNOWN_ROLE_MASK  	0x00000f
+#define FC_FPORT_PORTID			0x00000e
+#define FC_FABCTLR_PORTID		0x00000d
+#define FC_DIRSRVR_PORTID		0x00000c
+#define FC_TIMESRVR_PORTID		0x00000b
+#define FC_MGMTSRVR_PORTID		0x00000a
+
+
+static void fc_timeout_blocked_rport(void *data);
+static void fc_scsi_scan_rport(void *data);
+static void fc_rport_terminate(struct fc_rport  *rport);
+
+/*
+ * Attribute counts pre object type...
+ * Increase these values if you add attributes
+ */
+#define FC_STARGET_NUM_ATTRS 	3
+#define FC_RPORT_NUM_ATTRS	9
+#define FC_HOST_NUM_ATTRS	15
+
+struct fc_internal {
+	struct scsi_transport_template t;
+	struct fc_function_template *f;
+
+	/*
+	 * For attributes : each object has :
+	 *   An array of the actual attributes structures
+	 *   An array of null-terminated pointers to the attribute
+	 *     structures - used for mid-layer interaction.
+	 *
+	 * The attribute containers for the starget and host are are
+	 * part of the midlayer. As the remote port is specific to the
+	 * fc transport, we must provide the attribute container.
+	 */
+	struct class_device_attribute private_starget_attrs[
+							FC_STARGET_NUM_ATTRS];
+	struct class_device_attribute *starget_attrs[FC_STARGET_NUM_ATTRS + 1];
+
+	struct class_device_attribute private_host_attrs[FC_HOST_NUM_ATTRS];
+	struct class_device_attribute *host_attrs[FC_HOST_NUM_ATTRS + 1];
+
+	struct transport_container rport_attr_cont;
+	struct class_device_attribute private_rport_attrs[FC_RPORT_NUM_ATTRS];
+	struct class_device_attribute *rport_attrs[FC_RPORT_NUM_ATTRS + 1];
+};
+
+#define to_fc_internal(tmpl)	container_of(tmpl, struct fc_internal, t)
+
+static int fc_target_setup(struct device *dev)
+{
+	struct scsi_target *starget = to_scsi_target(dev);
+	struct fc_rport *rport = starget_to_rport(starget);
+
+	/*
+	 * if parent is remote port, use values from remote port.
+	 * Otherwise, this host uses the fc_transport, but not the
+	 * remote port interface. As such, initialize to known non-values.
+	 */
+	if (rport) {
+		fc_starget_node_name(starget) = rport->node_name;
+		fc_starget_port_name(starget) = rport->port_name;
+		fc_starget_port_id(starget) = rport->port_id;
+	} else {
+		fc_starget_node_name(starget) = -1;
+		fc_starget_port_name(starget) = -1;
+		fc_starget_port_id(starget) = -1;
+	}
+
+	return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(fc_transport_class,
+			       "fc_transport",
+			       fc_target_setup,
+			       NULL,
+			       NULL);
+
+static int fc_host_setup(struct device *dev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+
+	/* 
+	 * Set default values easily detected by the midlayer as
+	 * failure cases.  The scsi lldd is responsible for initializing
+	 * all transport attributes to valid values per host.
+	 */
+	fc_host_node_name(shost) = -1;
+	fc_host_port_name(shost) = -1;
+	fc_host_supported_classes(shost) = FC_COS_UNSPECIFIED;
+	memset(fc_host_supported_fc4s(shost), 0,
+		sizeof(fc_host_supported_fc4s(shost)));
+	memset(fc_host_symbolic_name(shost), 0,
+		sizeof(fc_host_symbolic_name(shost)));
+	fc_host_supported_speeds(shost) = FC_PORTSPEED_UNKNOWN;
+	fc_host_maxframe_size(shost) = -1;
+	memset(fc_host_serial_number(shost), 0,
+		sizeof(fc_host_serial_number(shost)));
+
+	fc_host_port_id(shost) = -1;
+	fc_host_port_type(shost) = FC_PORTTYPE_UNKNOWN;
+	fc_host_port_state(shost) = FC_PORTSTATE_UNKNOWN;
+	memset(fc_host_active_fc4s(shost), 0,
+		sizeof(fc_host_active_fc4s(shost)));
+	fc_host_speed(shost) = FC_PORTSPEED_UNKNOWN;
+	fc_host_fabric_name(shost) = -1;
+
+	fc_host_tgtid_bind_type(shost) = FC_TGTID_BIND_BY_WWPN;
+
+	INIT_LIST_HEAD(&fc_host_rports(shost));
+	INIT_LIST_HEAD(&fc_host_rport_bindings(shost));
+	fc_host_next_rport_number(shost) = 0;
+	fc_host_next_target_id(shost) = 0;
+
+	return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(fc_host_class,
+			       "fc_host",
+			       fc_host_setup,
+			       NULL,
+			       NULL);
+
+/*
+ * Setup and Remove actions for remote ports are handled
+ * in the service functions below.
+ */
+static DECLARE_TRANSPORT_CLASS(fc_rport_class,
+			       "fc_remote_ports",
+			       NULL,
+			       NULL,
+			       NULL);
+
+/*
+ * Module Parameters
+ */
+
+/*
+ * dev_loss_tmo: the default number of seconds that the FC transport
+ *   should insulate the loss of a remote port.
+ *   The maximum will be capped by the value of SCSI_DEVICE_BLOCK_MAX_TIMEOUT.
+ */
+static unsigned int fc_dev_loss_tmo = SCSI_DEVICE_BLOCK_MAX_TIMEOUT;
+
+module_param_named(dev_loss_tmo, fc_dev_loss_tmo, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(dev_loss_tmo,
+		 "Maximum number of seconds that the FC transport should"
+		 " insulate the loss of a remote port. Once this value is"
+		 " exceeded, the scsi target is removed. Value should be"
+		 " between 1 and SCSI_DEVICE_BLOCK_MAX_TIMEOUT.");
+
+
+static __init int fc_transport_init(void)
+{
+	int error = transport_class_register(&fc_host_class);
+	if (error)
+		return error;
+	error = transport_class_register(&fc_rport_class);
+	if (error)
+		return error;
+	return transport_class_register(&fc_transport_class);
+}
+
+static void __exit fc_transport_exit(void)
+{
+	transport_class_unregister(&fc_transport_class);
+	transport_class_unregister(&fc_rport_class);
+	transport_class_unregister(&fc_host_class);
+}
+
+/*
+ * FC Remote Port Attribute Management
+ */
+
+#define fc_rport_show_function(field, format_string, sz, cast)		\
+static ssize_t								\
+show_fc_rport_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	struct Scsi_Host *shost = rport_to_shost(rport);		\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	if (i->f->get_rport_##field)					\
+		i->f->get_rport_##field(rport);				\
+	return snprintf(buf, sz, format_string, cast rport->field); 	\
+}
+
+#define fc_rport_store_function(field)					\
+static ssize_t								\
+store_fc_rport_##field(struct class_device *cdev, const char *buf,	\
+			   size_t count)				\
+{									\
+	int val;							\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	struct Scsi_Host *shost = rport_to_shost(rport);		\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_rport_##field(rport, val);				\
+	return count;							\
+}
+
+#define fc_rport_rd_attr(field, format_string, sz)			\
+	fc_rport_show_function(field, format_string, sz, )		\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			 show_fc_rport_##field, NULL)
+
+#define fc_rport_rd_attr_cast(field, format_string, sz, cast)		\
+	fc_rport_show_function(field, format_string, sz, (cast))	\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			  show_fc_rport_##field, NULL)
+
+#define fc_rport_rw_attr(field, format_string, sz)			\
+	fc_rport_show_function(field, format_string, sz, )		\
+	fc_rport_store_function(field)					\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO | S_IWUSR,		\
+			show_fc_rport_##field,				\
+			store_fc_rport_##field)
+
+
+#define fc_private_rport_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+show_fc_rport_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	return snprintf(buf, sz, format_string, cast rport->field); 	\
+}
+
+#define fc_private_rport_rd_attr(field, format_string, sz)		\
+	fc_private_rport_show_function(field, format_string, sz, )	\
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			 show_fc_rport_##field, NULL)
+
+#define fc_private_rport_rd_attr_cast(field, format_string, sz, cast)	\
+	fc_private_rport_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(rport, field, S_IRUGO,			\
+			  show_fc_rport_##field, NULL)
+
+
+#define fc_private_rport_rd_enum_attr(title, maxlen)			\
+static ssize_t								\
+show_fc_rport_##title (struct class_device *cdev, char *buf)		\
+{									\
+	struct fc_rport *rport = transport_class_to_rport(cdev);	\
+	const char *name;						\
+	name = get_fc_##title##_name(rport->title);			\
+	if (!name)							\
+		return -EINVAL;						\
+	return snprintf(buf, maxlen, "%s\n", name);			\
+}									\
+static FC_CLASS_DEVICE_ATTR(rport, title, S_IRUGO,			\
+			show_fc_rport_##title, NULL)
+
+
+#define SETUP_RPORT_ATTRIBUTE_RD(field)					\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	i->private_rport_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_rport_attrs[count].store = NULL;			\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	if (i->f->show_rport_##field)					\
+		count++
+
+#define SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(field)				\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	i->private_rport_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_rport_attrs[count].store = NULL;			\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	count++
+
+#define SETUP_RPORT_ATTRIBUTE_RW(field)					\
+	i->private_rport_attrs[count] = class_device_attr_rport_##field; \
+	if (!i->f->set_rport_##field) {					\
+		i->private_rport_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_rport_attrs[count].store = NULL;		\
+	}								\
+	i->rport_attrs[count] = &i->private_rport_attrs[count];		\
+	if (i->f->show_rport_##field)					\
+		count++
+
+
+/* The FC Transport Remote Port Attributes: */
+
+/* Fixed Remote Port Attributes */
+
+fc_private_rport_rd_attr(maxframe_size, "%u bytes\n", 20);
+
+static ssize_t
+show_fc_rport_supported_classes (struct class_device *cdev, char *buf)
+{
+	struct fc_rport *rport = transport_class_to_rport(cdev);
+	if (rport->supported_classes == FC_COS_UNSPECIFIED)
+		return snprintf(buf, 20, "unspecified\n");
+	return get_fc_cos_names(rport->supported_classes, buf);
+}
+static FC_CLASS_DEVICE_ATTR(rport, supported_classes, S_IRUGO,
+		show_fc_rport_supported_classes, NULL);
+
+/* Dynamic Remote Port Attributes */
+
+fc_rport_rw_attr(dev_loss_tmo, "%d\n", 20);
+
+
+/* Private Remote Port Attributes */
+
+fc_private_rport_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_private_rport_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_private_rport_rd_attr(port_id, "0x%06x\n", 20);
+
+static ssize_t
+show_fc_rport_roles (struct class_device *cdev, char *buf)
+{
+	struct fc_rport *rport = transport_class_to_rport(cdev);
+
+	/* identify any roles that are port_id specific */
+	if ((rport->port_id != -1) &&
+	    (rport->port_id & FC_WELLKNOWN_PORTID_MASK) ==
+					FC_WELLKNOWN_PORTID_MASK) {
+		switch (rport->port_id & FC_WELLKNOWN_ROLE_MASK) {
+		case FC_FPORT_PORTID:
+			return snprintf(buf, 30, "Fabric Port\n");
+		case FC_FABCTLR_PORTID:
+			return snprintf(buf, 30, "Fabric Controller\n");
+		case FC_DIRSRVR_PORTID:
+			return snprintf(buf, 30, "Directory Server\n");
+		case FC_TIMESRVR_PORTID:
+			return snprintf(buf, 30, "Time Server\n");
+		case FC_MGMTSRVR_PORTID:
+			return snprintf(buf, 30, "Management Server\n");
+		default:
+			return snprintf(buf, 30, "Unknown Fabric Entity\n");
+		}
+	} else {
+		if (rport->roles == FC_RPORT_ROLE_UNKNOWN)
+			return snprintf(buf, 20, "unknown\n");
+		return get_fc_remote_port_roles_names(rport->roles, buf);
+	}
+}
+static FC_CLASS_DEVICE_ATTR(rport, roles, S_IRUGO,
+		show_fc_rport_roles, NULL);
+
+fc_private_rport_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
+fc_private_rport_rd_attr(scsi_target_id, "%d\n", 20);
+
+
+
+/*
+ * FC SCSI Target Attribute Management
+ */
+
+/*
+ * Note: in the target show function we recognize when the remote
+ *  port is in the heirarchy and do not allow the driver to get
+ *  involved in sysfs functions. The driver only gets involved if
+ *  it's the "old" style that doesn't use rports.
+ */
+#define fc_starget_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+show_fc_starget_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	struct fc_rport *rport = starget_to_rport(starget);		\
+	if (rport)							\
+		fc_starget_##field(starget) = rport->field;		\
+	else if (i->f->get_starget_##field)				\
+		i->f->get_starget_##field(starget);			\
+	return snprintf(buf, sz, format_string, 			\
+		cast fc_starget_##field(starget)); 			\
+}
+
+#define fc_starget_rd_attr(field, format_string, sz)			\
+	fc_starget_show_function(field, format_string, sz, )		\
+static FC_CLASS_DEVICE_ATTR(starget, field, S_IRUGO,			\
+			 show_fc_starget_##field, NULL)
+
+#define fc_starget_rd_attr_cast(field, format_string, sz, cast)		\
+	fc_starget_show_function(field, format_string, sz, (cast))	\
+static FC_CLASS_DEVICE_ATTR(starget, field, S_IRUGO,			\
+			  show_fc_starget_##field, NULL)
+
+#define SETUP_STARGET_ATTRIBUTE_RD(field)				\
+	i->private_starget_attrs[count] = class_device_attr_starget_##field; \
+	i->private_starget_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_starget_attrs[count].store = NULL;			\
+	i->starget_attrs[count] = &i->private_starget_attrs[count];	\
+	if (i->f->show_starget_##field)					\
+		count++
+
+#define SETUP_STARGET_ATTRIBUTE_RW(field)				\
+	i->private_starget_attrs[count] = class_device_attr_starget_##field; \
+	if (!i->f->set_starget_##field) {				\
+		i->private_starget_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_starget_attrs[count].store = NULL;		\
+	}								\
+	i->starget_attrs[count] = &i->private_starget_attrs[count];	\
+	if (i->f->show_starget_##field)					\
+		count++
+
+/* The FC Transport SCSI Target Attributes: */
+fc_starget_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_starget_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_starget_rd_attr(port_id, "0x%06x\n", 20);
+
+
+/*
+ * Host Attribute Management
+ */
+
+#define fc_host_show_function(field, format_string, sz, cast)		\
+static ssize_t								\
+show_fc_host_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	if (i->f->get_host_##field)					\
+		i->f->get_host_##field(shost);				\
+	return snprintf(buf, sz, format_string, cast fc_host_##field(shost)); \
+}
+
+#define fc_host_store_function(field)					\
+static ssize_t								\
+store_fc_host_##field(struct class_device *cdev, const char *buf,	\
+			   size_t count)				\
+{									\
+	int val;							\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+									\
+	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_host_##field(shost, val);				\
+	return count;							\
+}
+
+#define fc_host_rd_attr(field, format_string, sz)			\
+	fc_host_show_function(field, format_string, sz, )		\
+static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO,			\
+			 show_fc_host_##field, NULL)
+
+#define fc_host_rd_attr_cast(field, format_string, sz, cast)		\
+	fc_host_show_function(field, format_string, sz, (cast))		\
+static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO,			\
+			  show_fc_host_##field, NULL)
+
+#define fc_host_rw_attr(field, format_string, sz)			\
+	fc_host_show_function(field, format_string, sz, )		\
+	fc_host_store_function(field)					\
+static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO | S_IWUSR,		\
+			show_fc_host_##field,				\
+			store_fc_host_##field)
+
+#define fc_host_rd_enum_attr(title, maxlen)				\
+static ssize_t								\
+show_fc_host_##title (struct class_device *cdev, char *buf)		\
+{									\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct fc_internal *i = to_fc_internal(shost->transportt);	\
+	const char *name;						\
+	if (i->f->get_host_##title)					\
+		i->f->get_host_##title(shost);				\
+	name = get_fc_##title##_name(fc_host_##title(shost));		\
+	if (!name)							\
+		return -EINVAL;						\
+	return snprintf(buf, maxlen, "%s\n", name);			\
+}									\
+static FC_CLASS_DEVICE_ATTR(host, title, S_IRUGO, show_fc_host_##title, NULL)
+
+#define SETUP_HOST_ATTRIBUTE_RD(field)					\
+	i->private_host_attrs[count] = class_device_attr_host_##field;	\
+	i->private_host_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_host_attrs[count].store = NULL;			\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	if (i->f->show_host_##field)					\
+		count++
+
+#define SETUP_HOST_ATTRIBUTE_RW(field)					\
+	i->private_host_attrs[count] = class_device_attr_host_##field;	\
+	if (!i->f->set_host_##field) {					\
+		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_host_attrs[count].store = NULL;		\
+	}								\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	if (i->f->show_host_##field)					\
+		count++
+
+
+#define fc_private_host_show_function(field, format_string, sz, cast)	\
+static ssize_t								\
+show_fc_host_##field (struct class_device *cdev, char *buf)		\
+{									\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	return snprintf(buf, sz, format_string, cast fc_host_##field(shost)); \
+}
+
+#define fc_private_host_rd_attr(field, format_string, sz)		\
+	fc_private_host_show_function(field, format_string, sz, )	\
+static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO,			\
+			 show_fc_host_##field, NULL)
+
+#define fc_private_host_rd_attr_cast(field, format_string, sz, cast)	\
+	fc_private_host_show_function(field, format_string, sz, (cast)) \
+static FC_CLASS_DEVICE_ATTR(host, field, S_IRUGO,			\
+			  show_fc_host_##field, NULL)
+
+#define SETUP_PRIVATE_HOST_ATTRIBUTE_RD(field)			\
+	i->private_host_attrs[count] = class_device_attr_host_##field;	\
+	i->private_host_attrs[count].attr.mode = S_IRUGO;		\
+	i->private_host_attrs[count].store = NULL;			\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	count++
+
+#define SETUP_PRIVATE_HOST_ATTRIBUTE_RW(field)			\
+	i->private_host_attrs[count] = class_device_attr_host_##field;	\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	count++
+
+
+/* Fixed Host Attributes */
+
+static ssize_t
+show_fc_host_supported_classes (struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+	if (fc_host_supported_classes(shost) == FC_COS_UNSPECIFIED)
+		return snprintf(buf, 20, "unspecified\n");
+
+	return get_fc_cos_names(fc_host_supported_classes(shost), buf);
+}
+static FC_CLASS_DEVICE_ATTR(host, supported_classes, S_IRUGO,
+		show_fc_host_supported_classes, NULL);
+
+static ssize_t
+show_fc_host_supported_fc4s (struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	return (ssize_t)show_fc_fc4s(buf, fc_host_supported_fc4s(shost));
+}
+static FC_CLASS_DEVICE_ATTR(host, supported_fc4s, S_IRUGO,
+		show_fc_host_supported_fc4s, NULL);
+
+static ssize_t
+show_fc_host_supported_speeds (struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+
+	if (fc_host_supported_speeds(shost) == FC_PORTSPEED_UNKNOWN)
+		return snprintf(buf, 20, "unknown\n");
+
+	return get_fc_port_speed_names(fc_host_supported_speeds(shost), buf);
+}
+static FC_CLASS_DEVICE_ATTR(host, supported_speeds, S_IRUGO,
+		show_fc_host_supported_speeds, NULL);
+
+
+fc_private_host_rd_attr_cast(node_name, "0x%llx\n", 20, unsigned long long);
+fc_private_host_rd_attr_cast(port_name, "0x%llx\n", 20, unsigned long long);
+fc_private_host_rd_attr(symbolic_name, "%s\n", (FC_SYMBOLIC_NAME_SIZE +1));
+fc_private_host_rd_attr(maxframe_size, "%u bytes\n", 20);
+fc_private_host_rd_attr(serial_number, "%s\n", (FC_SERIAL_NUMBER_SIZE +1));
+
+
+/* Dynamic Host Attributes */
+
+static ssize_t
+show_fc_host_active_fc4s (struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+
+	if (i->f->get_host_active_fc4s)
+		i->f->get_host_active_fc4s(shost);
+
+	return (ssize_t)show_fc_fc4s(buf, fc_host_active_fc4s(shost));
+}
+static FC_CLASS_DEVICE_ATTR(host, active_fc4s, S_IRUGO,
+		show_fc_host_active_fc4s, NULL);
+
+static ssize_t
+show_fc_host_speed (struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+
+	if (i->f->get_host_speed)
+		i->f->get_host_speed(shost);
+
+	if (fc_host_speed(shost) == FC_PORTSPEED_UNKNOWN)
+		return snprintf(buf, 20, "unknown\n");
+
+	return get_fc_port_speed_names(fc_host_speed(shost), buf);
+}
+static FC_CLASS_DEVICE_ATTR(host, speed, S_IRUGO,
+		show_fc_host_speed, NULL);
+
+
+fc_host_rd_attr(port_id, "0x%06x\n", 20);
+fc_host_rd_enum_attr(port_type, FC_PORTTYPE_MAX_NAMELEN);
+fc_host_rd_enum_attr(port_state, FC_PORTSTATE_MAX_NAMELEN);
+fc_host_rd_attr_cast(fabric_name, "0x%llx\n", 20, unsigned long long);
+
+
+/* Private Host Attributes */
+
+static ssize_t
+show_fc_private_host_tgtid_bind_type(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	const char *name;
+
+	name = get_fc_tgtid_bind_type_name(fc_host_tgtid_bind_type(shost));
+	if (!name)
+		return -EINVAL;
+	return snprintf(buf, FC_BINDTYPE_MAX_NAMELEN, "%s\n", name);
+}
+
+static ssize_t
+store_fc_private_host_tgtid_bind_type(struct class_device *cdev,
+	const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct fc_rport *rport, *next_rport;
+ 	enum fc_tgtid_binding_type val;
+	unsigned long flags;
+
+	if (get_fc_tgtid_bind_type_match(buf, &val))
+		return -EINVAL;
+
+	/* if changing bind type, purge all unused consistent bindings */
+	if (val != fc_host_tgtid_bind_type(shost)) {
+		spin_lock_irqsave(shost->host_lock, flags);
+		list_for_each_entry_safe(rport, next_rport,
+				&fc_host_rport_bindings(shost), peers)
+			fc_rport_terminate(rport);
+		spin_unlock_irqrestore(shost->host_lock, flags);
+	}
+
+	fc_host_tgtid_bind_type(shost) = val;
+	return count;
+}
+
+static FC_CLASS_DEVICE_ATTR(host, tgtid_bind_type, S_IRUGO | S_IWUSR,
+			show_fc_private_host_tgtid_bind_type,
+			store_fc_private_host_tgtid_bind_type);
+
+/*
+ * Host Statistics Management
+ */
+
+/* Show a given an attribute in the statistics group */
+static ssize_t
+fc_stat_show(const struct class_device *cdev, char *buf, unsigned long offset)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+	struct fc_host_statistics *stats;
+	ssize_t ret = -ENOENT;
+
+	if (offset > sizeof(struct fc_host_statistics) ||
+	    offset % sizeof(u64) != 0)
+		WARN_ON(1);
+
+	if (i->f->get_fc_host_stats) {
+		stats = (i->f->get_fc_host_stats)(shost);
+		if (stats)
+			ret = snprintf(buf, 20, "0x%llx\n",
+			      (unsigned long long)*(u64 *)(((u8 *) stats) + offset));
+	}
+	return ret;
+}
+
+
+/* generate a read-only statistics attribute */
+#define fc_host_statistic(name)						\
+static ssize_t show_fcstat_##name(struct class_device *cd, char *buf) 	\
+{									\
+	return fc_stat_show(cd, buf, 					\
+			    offsetof(struct fc_host_statistics, name));	\
+}									\
+static FC_CLASS_DEVICE_ATTR(host, name, S_IRUGO, show_fcstat_##name, NULL)
+
+fc_host_statistic(seconds_since_last_reset);
+fc_host_statistic(tx_frames);
+fc_host_statistic(tx_words);
+fc_host_statistic(rx_frames);
+fc_host_statistic(rx_words);
+fc_host_statistic(lip_count);
+fc_host_statistic(nos_count);
+fc_host_statistic(error_frames);
+fc_host_statistic(dumped_frames);
+fc_host_statistic(link_failure_count);
+fc_host_statistic(loss_of_sync_count);
+fc_host_statistic(loss_of_signal_count);
+fc_host_statistic(prim_seq_protocol_err_count);
+fc_host_statistic(invalid_tx_word_count);
+fc_host_statistic(invalid_crc_count);
+fc_host_statistic(fcp_input_requests);
+fc_host_statistic(fcp_output_requests);
+fc_host_statistic(fcp_control_requests);
+fc_host_statistic(fcp_input_megabytes);
+fc_host_statistic(fcp_output_megabytes);
+
+static ssize_t
+fc_reset_statistics(struct class_device *cdev, const char *buf,
+			   size_t count)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct fc_internal *i = to_fc_internal(shost->transportt);
+
+	/* ignore any data value written to the attribute */
+	if (i->f->reset_fc_host_stats) {
+		i->f->reset_fc_host_stats(shost);
+		return count;
+	}
+
+	return -ENOENT;
+}
+static FC_CLASS_DEVICE_ATTR(host, reset_statistics, S_IWUSR, NULL,
+				fc_reset_statistics);
+
+
+static struct attribute *fc_statistics_attrs[] = {
+	&class_device_attr_host_seconds_since_last_reset.attr,
+	&class_device_attr_host_tx_frames.attr,
+	&class_device_attr_host_tx_words.attr,
+	&class_device_attr_host_rx_frames.attr,
+	&class_device_attr_host_rx_words.attr,
+	&class_device_attr_host_lip_count.attr,
+	&class_device_attr_host_nos_count.attr,
+	&class_device_attr_host_error_frames.attr,
+	&class_device_attr_host_dumped_frames.attr,
+	&class_device_attr_host_link_failure_count.attr,
+	&class_device_attr_host_loss_of_sync_count.attr,
+	&class_device_attr_host_loss_of_signal_count.attr,
+	&class_device_attr_host_prim_seq_protocol_err_count.attr,
+	&class_device_attr_host_invalid_tx_word_count.attr,
+	&class_device_attr_host_invalid_crc_count.attr,
+	&class_device_attr_host_fcp_input_requests.attr,
+	&class_device_attr_host_fcp_output_requests.attr,
+	&class_device_attr_host_fcp_control_requests.attr,
+	&class_device_attr_host_fcp_input_megabytes.attr,
+	&class_device_attr_host_fcp_output_megabytes.attr,
+	&class_device_attr_host_reset_statistics.attr,
+	NULL
+};
+
+static struct attribute_group fc_statistics_group = {
+	.name = "statistics",
+	.attrs = fc_statistics_attrs,
+};
+
+static int fc_host_match(struct attribute_container *cont,
+			  struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct fc_internal *i;
+
+	if (!scsi_is_host_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &fc_host_class.class)
+		return 0;
+
+	i = to_fc_internal(shost->transportt);
+
+	return &i->t.host_attrs.ac == cont;
+}
+
+static int fc_target_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct fc_internal *i;
+
+	if (!scsi_is_target_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &fc_host_class.class)
+		return 0;
+
+	i = to_fc_internal(shost->transportt);
+
+	return &i->t.target_attrs.ac == cont;
+}
+
+static void fc_rport_dev_release(struct device *dev)
+{
+	struct fc_rport *rport = dev_to_rport(dev);
+	put_device(dev->parent);
+	kfree(rport);
+}
+
+int scsi_is_fc_rport(const struct device *dev)
+{
+	return dev->release == fc_rport_dev_release;
+}
+EXPORT_SYMBOL(scsi_is_fc_rport);
+
+static int fc_rport_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct fc_internal *i;
+
+	if (!scsi_is_fc_rport(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &fc_host_class.class)
+		return 0;
+
+	i = to_fc_internal(shost->transportt);
+
+	return &i->rport_attr_cont.ac == cont;
+}
+
+struct scsi_transport_template *
+fc_attach_transport(struct fc_function_template *ft)
+{
+	struct fc_internal *i = kmalloc(sizeof(struct fc_internal),
+					GFP_KERNEL);
+	int count;
+
+	if (unlikely(!i))
+		return NULL;
+
+	memset(i, 0, sizeof(struct fc_internal));
+
+	i->t.target_attrs.ac.attrs = &i->starget_attrs[0];
+	i->t.target_attrs.ac.class = &fc_transport_class.class;
+	i->t.target_attrs.ac.match = fc_target_match;
+	i->t.target_size = sizeof(struct fc_starget_attrs);
+	transport_container_register(&i->t.target_attrs);
+
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.class = &fc_host_class.class;
+	i->t.host_attrs.ac.match = fc_host_match;
+	i->t.host_size = sizeof(struct fc_host_attrs);
+	if (ft->get_fc_host_stats)
+		i->t.host_attrs.statistics = &fc_statistics_group;
+	transport_container_register(&i->t.host_attrs);
+
+	i->rport_attr_cont.ac.attrs = &i->rport_attrs[0];
+	i->rport_attr_cont.ac.class = &fc_rport_class.class;
+	i->rport_attr_cont.ac.match = fc_rport_match;
+	transport_container_register(&i->rport_attr_cont);
+
+	i->f = ft;
+
+	/* Transport uses the shost workq for scsi scanning */
+	i->t.create_work_queue = 1;
+	
+	/*
+	 * Setup SCSI Target Attributes.
+	 */
+	count = 0;
+	SETUP_STARGET_ATTRIBUTE_RD(node_name);
+	SETUP_STARGET_ATTRIBUTE_RD(port_name);
+	SETUP_STARGET_ATTRIBUTE_RD(port_id);
+
+	BUG_ON(count > FC_STARGET_NUM_ATTRS);
+
+	i->starget_attrs[count] = NULL;
+
+
+	/*
+	 * Setup SCSI Host Attributes.
+	 */
+	count=0;
+	SETUP_HOST_ATTRIBUTE_RD(node_name);
+	SETUP_HOST_ATTRIBUTE_RD(port_name);
+	SETUP_HOST_ATTRIBUTE_RD(supported_classes);
+	SETUP_HOST_ATTRIBUTE_RD(supported_fc4s);
+	SETUP_HOST_ATTRIBUTE_RD(symbolic_name);
+	SETUP_HOST_ATTRIBUTE_RD(supported_speeds);
+	SETUP_HOST_ATTRIBUTE_RD(maxframe_size);
+	SETUP_HOST_ATTRIBUTE_RD(serial_number);
+
+	SETUP_HOST_ATTRIBUTE_RD(port_id);
+	SETUP_HOST_ATTRIBUTE_RD(port_type);
+	SETUP_HOST_ATTRIBUTE_RD(port_state);
+	SETUP_HOST_ATTRIBUTE_RD(active_fc4s);
+	SETUP_HOST_ATTRIBUTE_RD(speed);
+	SETUP_HOST_ATTRIBUTE_RD(fabric_name);
+
+	/* Transport-managed attributes */
+	SETUP_PRIVATE_HOST_ATTRIBUTE_RW(tgtid_bind_type);
+
+	BUG_ON(count > FC_HOST_NUM_ATTRS);
+
+	i->host_attrs[count] = NULL;
+
+	/*
+	 * Setup Remote Port Attributes.
+	 */
+	count=0;
+	SETUP_RPORT_ATTRIBUTE_RD(maxframe_size);
+	SETUP_RPORT_ATTRIBUTE_RD(supported_classes);
+	SETUP_RPORT_ATTRIBUTE_RW(dev_loss_tmo);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(node_name);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_name);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_id);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(roles);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(port_state);
+	SETUP_PRIVATE_RPORT_ATTRIBUTE_RD(scsi_target_id);
+
+	BUG_ON(count > FC_RPORT_NUM_ATTRS);
+
+	i->rport_attrs[count] = NULL;
+
+	return &i->t;
+}
+EXPORT_SYMBOL(fc_attach_transport);
+
+void fc_release_transport(struct scsi_transport_template *t)
+{
+	struct fc_internal *i = to_fc_internal(t);
+
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
+	transport_container_unregister(&i->rport_attr_cont);
+
+	kfree(i);
+}
+EXPORT_SYMBOL(fc_release_transport);
+
+
+/**
+ * fc_remove_host - called to terminate any fc_transport-related elements
+ *                  for a scsi host.
+ * @rport:	remote port to be unblocked.
+ *
+ * This routine is expected to be called immediately preceeding the
+ * a driver's call to scsi_remove_host().
+ *
+ * WARNING: A driver utilizing the fc_transport, which fails to call
+ *   this routine prior to scsi_remote_host(), will leave dangling
+ *   objects in /sys/class/fc_remote_ports. Access to any of these
+ *   objects can result in a system crash !!!
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+void
+fc_remove_host(struct Scsi_Host *shost)
+{
+	struct fc_rport *rport, *next_rport;
+
+	/* Remove any remote ports */
+	list_for_each_entry_safe(rport, next_rport,
+			&fc_host_rports(shost), peers)
+		fc_rport_terminate(rport);
+	list_for_each_entry_safe(rport, next_rport,
+			&fc_host_rport_bindings(shost), peers)
+		fc_rport_terminate(rport);
+}
+EXPORT_SYMBOL(fc_remove_host);
+
+/**
+ * fc_rport_create - allocates and creates a remote FC port.
+ * @shost:	scsi host the remote port is connected to.
+ * @channel:	Channel on shost port connected to.
+ * @ids:	The world wide names, fc address, and FC4 port
+ *		roles for the remote port.
+ *
+ * Allocates and creates the remoter port structure, including the
+ * class and sysfs creation.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+struct fc_rport *
+fc_rport_create(struct Scsi_Host *shost, int channel,
+	struct fc_rport_identifiers  *ids)
+{
+	struct fc_host_attrs *fc_host =
+			(struct fc_host_attrs *)shost->shost_data;
+	struct fc_internal *fci = to_fc_internal(shost->transportt);
+	struct fc_rport *rport;
+	struct device *dev;
+	unsigned long flags;
+	int error;
+	size_t size;
+
+	size = (sizeof(struct fc_rport) + fci->f->dd_fcrport_size);
+	rport = kmalloc(size, GFP_KERNEL);
+	if (unlikely(!rport)) {
+		printk(KERN_ERR "%s: allocation failure\n", __FUNCTION__);
+		return NULL;
+	}
+	memset(rport, 0, size);
+
+	rport->maxframe_size = -1;
+	rport->supported_classes = FC_COS_UNSPECIFIED;
+	rport->dev_loss_tmo = fc_dev_loss_tmo;
+	memcpy(&rport->node_name, &ids->node_name, sizeof(rport->node_name));
+	memcpy(&rport->port_name, &ids->port_name, sizeof(rport->port_name));
+	rport->port_id = ids->port_id;
+	rport->roles = ids->roles;
+	rport->port_state = FC_PORTSTATE_ONLINE;
+	if (fci->f->dd_fcrport_size)
+		rport->dd_data = &rport[1];
+	rport->channel = channel;
+
+	INIT_WORK(&rport->dev_loss_work, fc_timeout_blocked_rport, rport);
+	INIT_WORK(&rport->scan_work, fc_scsi_scan_rport, rport);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+
+	rport->number = fc_host->next_rport_number++;
+	if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+		rport->scsi_target_id = fc_host->next_target_id++;
+	else
+		rport->scsi_target_id = -1;
+	list_add_tail(&rport->peers, &fc_host_rports(shost));
+	get_device(&shost->shost_gendev);
+
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	dev = &rport->dev;
+	device_initialize(dev);
+	dev->parent = get_device(&shost->shost_gendev);
+	dev->release = fc_rport_dev_release;
+	sprintf(dev->bus_id, "rport-%d:%d-%d",
+		shost->host_no, channel, rport->number);
+	transport_setup_device(dev);
+
+	error = device_add(dev);
+	if (error) {
+		printk(KERN_ERR "FC Remote Port device_add failed\n");
+		goto delete_rport;
+	}
+	transport_add_device(dev);
+	transport_configure_device(dev);
+
+	if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+		/* initiate a scan of the target */
+		scsi_queue_work(shost, &rport->scan_work);
+
+	return rport;
+
+delete_rport:
+	transport_destroy_device(dev);
+	put_device(dev->parent);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_del(&rport->peers);
+	put_device(&shost->shost_gendev);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(dev->parent);
+	kfree(rport);
+	return NULL;
+}
+
+/**
+ * fc_remote_port_add - notifies the fc transport of the existence
+ *		of a remote FC port.
+ * @shost:	scsi host the remote port is connected to.
+ * @channel:	Channel on shost port connected to.
+ * @ids:	The world wide names, fc address, and FC4 port
+ *		roles for the remote port.
+ *
+ * The LLDD calls this routine to notify the transport of the existence
+ * of a remote port. The LLDD provides the unique identifiers (wwpn,wwn)
+ * of the port, it's FC address (port_id), and the FC4 roles that are
+ * active for the port.
+ *
+ * For ports that are FCP targets (aka scsi targets), the FC transport
+ * maintains consistent target id bindings on behalf of the LLDD.
+ * A consistent target id binding is an assignment of a target id to
+ * a remote port identifier, which persists while the scsi host is
+ * attached. The remote port can disappear, then later reappear, and
+ * it's target id assignment remains the same. This allows for shifts
+ * in FC addressing (if binding by wwpn or wwnn) with no apparent
+ * changes to the scsi subsystem which is based on scsi host number and
+ * target id values.  Bindings are only valid during the attachment of
+ * the scsi host. If the host detaches, then later re-attaches, target
+ * id bindings may change.
+ *
+ * This routine is responsible for returning a remote port structure.
+ * The routine will search the list of remote ports it maintains
+ * internally on behalf of consistent target id mappings. If found, the
+ * remote port structure will be reused. Otherwise, a new remote port
+ * structure will be allocated.
+ *
+ * Whenever a remote port is allocated, a new fc_remote_port class
+ * device is created.
+ *
+ * Should not be called from interrupt context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+struct fc_rport *
+fc_remote_port_add(struct Scsi_Host *shost, int channel,
+	struct fc_rport_identifiers  *ids)
+{
+	struct fc_rport *rport;
+	unsigned long flags;
+	int match = 0;
+
+	if (likely((ids->roles & FC_RPORT_ROLE_FCP_TARGET) &&
+		(fc_host_tgtid_bind_type(shost) != FC_TGTID_BIND_NONE))) {
+
+		/* search for a matching consistent binding */
+
+		spin_lock_irqsave(shost->host_lock, flags);
+
+		list_for_each_entry(rport, &fc_host_rport_bindings(shost),
+					peers) {
+			if (rport->channel != channel)
+				continue;
+
+			switch (fc_host_tgtid_bind_type(shost)) {
+			case FC_TGTID_BIND_BY_WWPN:
+				if (rport->port_name == ids->port_name)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_BY_WWNN:
+				if (rport->node_name == ids->node_name)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_BY_ID:
+				if (rport->port_id == ids->port_id)
+					match = 1;
+				break;
+			case FC_TGTID_BIND_NONE: /* to keep compiler happy */
+				break;
+			}
+
+			if (match) {
+				list_move_tail(&rport->peers,
+					&fc_host_rports(shost));
+				break;
+			}
+		}
+
+		spin_unlock_irqrestore(shost->host_lock, flags);
+
+		if (match) {
+			memcpy(&rport->node_name, &ids->node_name,
+				sizeof(rport->node_name));
+			memcpy(&rport->port_name, &ids->port_name,
+				sizeof(rport->port_name));
+			rport->port_id = ids->port_id;
+			rport->roles = ids->roles;
+			rport->port_state = FC_PORTSTATE_ONLINE;
+
+			if (rport->roles & FC_RPORT_ROLE_FCP_TARGET)
+				/* initiate a scan of the target */
+				scsi_queue_work(shost, &rport->scan_work);
+
+			return rport;
+		}
+	}
+
+	/* No consistent binding found - create new remote port entry */
+	rport = fc_rport_create(shost, channel, ids);
+
+	return rport;
+}
+EXPORT_SYMBOL(fc_remote_port_add);
+
+/*
+ * fc_rport_tgt_remove - Removes the scsi target on the remote port
+ * @rport:	The remote port to be operated on
+ */
+static void
+fc_rport_tgt_remove(struct fc_rport *rport)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+
+	scsi_target_unblock(&rport->dev);
+
+	/* Stop anything on the workq */
+	if (!cancel_delayed_work(&rport->dev_loss_work))
+		flush_scheduled_work();
+	scsi_flush_work(shost);
+
+	scsi_remove_target(&rport->dev);
+}
+
+/*
+ * fc_rport_terminate - this routine tears down and deallocates a remote port.
+ * @rport:	The remote port to be terminated
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ */
+static void
+fc_rport_terminate(struct fc_rport  *rport)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct device *dev = &rport->dev;
+	unsigned long flags;
+
+	fc_rport_tgt_remove(rport);
+
+	transport_remove_device(dev);
+	device_del(dev);
+	transport_destroy_device(dev);
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_del(&rport->peers);
+	spin_unlock_irqrestore(shost->host_lock, flags);
+	put_device(&shost->shost_gendev);
+}
+
+/**
+ * fc_remote_port_delete - notifies the fc transport that a remote
+ *		port is no longer in existence.
+ * @rport:	The remote port that no longer exists
+ *
+ * The LLDD calls this routine to notify the transport that a remote
+ * port is no longer part of the topology. Note: Although a port
+ * may no longer be part of the topology, it may persist in the remote
+ * ports displayed by the fc_host. This is done so that target id
+ * mappings (managed via the remote port structures), are always visible
+ * as long as the mapping is valid, regardless of port state,
+ *
+ * If the remote port is not an FCP Target, it will be fully torn down
+ * and deallocated, including the fc_remote_port class device.
+ *
+ * If the remote port is an FCP Target, the port structure will be
+ * marked as Not Present, but will remain as long as there is a valid
+ * SCSI target id mapping associated with the port structure. Validity
+ * is determined by the binding type. If binding by wwpn, then the port
+ * structure is always valid and will not be deallocated until the host
+ * is removed.  If binding by wwnn, then the port structure is valid
+ * until another port with the same node name is found in the topology.
+ * If binding by port id (fc address), then the port structure is valid
+ * valid until another port with the same address is identified.
+ *
+ * Called from interrupt or normal process context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+void
+fc_remote_port_delete(struct fc_rport  *rport)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	unsigned long flags;
+
+	/* If no scsi target id mapping or consistent binding type, delete it */
+	if ((rport->scsi_target_id == -1) ||
+	    (fc_host_tgtid_bind_type(shost) == FC_TGTID_BIND_NONE)) {
+		fc_rport_terminate(rport);
+		return;
+	}
+
+	fc_rport_tgt_remove(rport);
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	list_move_tail(&rport->peers, &fc_host_rport_bindings(shost));
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	/*
+	 * Note: We do not remove or clear the hostdata area. This allows
+	 *   host-specific target data to persist along with the
+	 *   scsi_target_id. It's up to the host to manage it's hostdata area.
+	 */
+
+	/*
+	 * Reinitialize port attributes that may change if the port comes back.
+	 */
+	rport->maxframe_size = -1;
+	rport->supported_classes = FC_COS_UNSPECIFIED;
+	rport->roles = FC_RPORT_ROLE_UNKNOWN;
+	rport->port_state = FC_PORTSTATE_NOTPRESENT;
+
+	/* remove the identifiers that aren't used in the consisting binding */
+	switch (fc_host_tgtid_bind_type(shost)) {
+	case FC_TGTID_BIND_BY_WWPN:
+		rport->node_name = -1;
+		rport->port_id = -1;
+		break;
+	case FC_TGTID_BIND_BY_WWNN:
+		rport->port_name = -1;
+		rport->port_id = -1;
+		break;
+	case FC_TGTID_BIND_BY_ID:
+		rport->node_name = -1;
+		rport->port_name = -1;
+		break;
+	case FC_TGTID_BIND_NONE:	/* to keep compiler happy */
+		break;
+	}
+}
+EXPORT_SYMBOL(fc_remote_port_delete);
+
+/**
+ * fc_remote_port_rolechg - notifies the fc transport that the roles
+ *		on a remote may have changed.
+ * @rport:	The remote port that changed.
+ *
+ * The LLDD calls this routine to notify the transport that the roles
+ * on a remote port may have changed. The largest effect of this is
+ * if a port now becomes a FCP Target, it must be allocated a
+ * scsi target id.  If the port is no longer a FCP target, any
+ * scsi target id value assigned to it will persist in case the
+ * role changes back to include FCP Target. No changes in the scsi
+ * midlayer will be invoked if the role changes (in the expectation
+ * that the role will be resumed. If it doesn't normal error processing
+ * will take place).
+ *
+ * Should not be called from interrupt context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+void
+fc_remote_port_rolechg(struct fc_rport  *rport, u32 roles)
+{
+	struct Scsi_Host *shost = rport_to_shost(rport);
+	struct fc_host_attrs *fc_host =
+			(struct fc_host_attrs *)shost->shost_data;
+	unsigned long flags;
+	int create = 0;
+
+	rport->roles = roles;
+
+	spin_lock_irqsave(shost->host_lock, flags);
+	if ((rport->scsi_target_id == -1) &&
+	    (rport->roles & FC_RPORT_ROLE_FCP_TARGET)) {
+		rport->scsi_target_id = fc_host->next_target_id++;
+		create = 1;
+	}
+	spin_unlock_irqrestore(shost->host_lock, flags);
+
+	if (create)
+		/* initiate a scan of the target */
+		scsi_queue_work(shost, &rport->scan_work);
+}
+EXPORT_SYMBOL(fc_remote_port_rolechg);
+
+/**
+ * fc_timeout_blocked_rport - Timeout handler for blocked remote port
+ *                       that fails to return in the alloted time.
+ * @data:	scsi target that failed to reappear in the alloted time.
+ **/
+static void
+fc_timeout_blocked_rport(void  *data)
+{
+	struct fc_rport *rport = (struct fc_rport *)data;
+
+	rport->port_state = FC_PORTSTATE_OFFLINE;
+
+	dev_printk(KERN_ERR, &rport->dev,
+		"blocked FC remote port time out: removing target\n");
+
+	/*
+	 * As this only occurs if the remote port (scsi target)
+	 * went away and didn't come back - we'll remove
+	 * all attached scsi devices.
+	 */
+	scsi_target_unblock(&rport->dev);
+	scsi_remove_target(&rport->dev);
+}
+
+/**
+ * fc_remote_port_block - temporarily block any scsi traffic to a remote port.
+ * @rport:	remote port to be blocked.
+ *
+ * scsi lldd's with a FC transport call this routine to temporarily stop
+ * all scsi traffic to a remote port. If the port is not a SCSI target,
+ * no action is taken. If the port is a SCSI target, all attached devices
+ * are placed into a SDEV_BLOCK state and a timer is started. The timer is
+ * represents the maximum amount of time the port may be blocked. If the
+ * timer expires, the port is considered non-existent and the attached
+ * scsi devices will be removed.
+ *
+ * Called from interrupt or normal process context.
+ *
+ * Returns zero if successful or error if not
+ *
+ * Notes:
+ *      This routine assumes no locks are held on entry.
+ *
+ *	The timeout and timer types are extracted from the fc transport 
+ *	attributes from the caller's rport pointer.
+ **/
+int
+fc_remote_port_block(struct fc_rport *rport)
+{
+	int timeout = rport->dev_loss_tmo;
+	struct work_struct *work = &rport->dev_loss_work;
+
+	if (timeout < 0 || timeout > SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
+		return -EINVAL;
+
+	scsi_target_block(&rport->dev);
+
+	/* cap the length the devices can be blocked */
+	schedule_delayed_work(work, timeout * HZ);
+
+	rport->port_state = FC_PORTSTATE_BLOCKED;
+	return 0;
+}
+EXPORT_SYMBOL(fc_remote_port_block);
+
+/**
+ * fc_remote_port_unblock - restart any blocked scsi traffic to a remote port.
+ * @rport:	remote port to be unblocked.
+ *
+ * scsi lld's with a FC transport call this routine to restart IO to all
+ * devices associated with the caller's scsi target following a fc_target_block
+ * request.  Called from interrupt or normal process context.
+ *
+ * Notes:
+ *	This routine assumes no locks are held on entry.
+ **/
+ void
+fc_remote_port_unblock(struct fc_rport *rport)
+{
+	struct work_struct *work = &rport->dev_loss_work;
+	struct Scsi_Host *shost = rport_to_shost(rport);
+
+	/*
+	 * Stop the target timer first. Take no action on the del_timer
+	 * failure as the state machine state change will validate the
+	 * transaction.
+	 */
+	if (!cancel_delayed_work(work))
+		flush_scheduled_work();
+
+	if (rport->port_state == FC_PORTSTATE_OFFLINE)
+		/*
+		 * initiate a scan of the target as the target has
+		 * been torn down.
+		 */
+		scsi_queue_work(shost, &rport->scan_work);
+	else
+		scsi_target_unblock(&rport->dev);
+
+	rport->port_state = FC_PORTSTATE_ONLINE;
+}
+EXPORT_SYMBOL(fc_remote_port_unblock);
+
+/**
+ * fc_scsi_scan_rport - called to perform a scsi scan on a remote port.
+ * @data:	remote port to be scanned.
+ **/
+static void
+fc_scsi_scan_rport(void *data)
+{
+	struct fc_rport *rport = (struct fc_rport *)data;
+
+	scsi_scan_target(&rport->dev, rport->channel, rport->scsi_target_id,
+			SCAN_WILD_CARD, 1);
+}
+
+
+MODULE_AUTHOR("Martin Hicks");
+MODULE_DESCRIPTION("FC Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(fc_transport_init);
+module_exit(fc_transport_exit);
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c
new file mode 100644
index 0000000..8bb8222
--- /dev/null
+++ b/drivers/scsi/scsi_transport_iscsi.c
@@ -0,0 +1,388 @@
+/* 
+ * iSCSI transport class definitions
+ *
+ * Copyright (C) IBM Corporation, 2004
+ * Copyright (C) Mike Christie, 2004
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+#include <linux/module.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_iscsi.h>
+
+#define ISCSI_SESSION_ATTRS 20
+#define ISCSI_HOST_ATTRS 2
+
+struct iscsi_internal {
+	struct scsi_transport_template t;
+	struct iscsi_function_template *fnt;
+	/*
+	 * We do not have any private or other attrs.
+	 */
+	struct class_device_attribute *session_attrs[ISCSI_SESSION_ATTRS + 1];
+	struct class_device_attribute *host_attrs[ISCSI_HOST_ATTRS + 1];
+};
+
+#define to_iscsi_internal(tmpl) container_of(tmpl, struct iscsi_internal, t)
+
+static DECLARE_TRANSPORT_CLASS(iscsi_transport_class,
+			       "iscsi_transport",
+			       NULL,
+			       NULL,
+			       NULL);
+
+static DECLARE_TRANSPORT_CLASS(iscsi_host_class,
+			       "iscsi_host",
+			       NULL,
+			       NULL,
+			       NULL);
+/*
+ * iSCSI target and session attrs
+ */
+#define iscsi_session_show_fn(field, format)				\
+									\
+static ssize_t								\
+show_session_##field(struct class_device *cdev, char *buf)		\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+									\
+	if (i->fnt->get_##field)					\
+		i->fnt->get_##field(starget);				\
+	return snprintf(buf, 20, format"\n", iscsi_##field(starget));	\
+}
+
+#define iscsi_session_rd_attr(field, format)				\
+	iscsi_session_show_fn(field, format)				\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_##field, NULL);
+
+iscsi_session_rd_attr(tpgt, "%hu");
+iscsi_session_rd_attr(tsih, "%2x");
+iscsi_session_rd_attr(max_recv_data_segment_len, "%u");
+iscsi_session_rd_attr(max_burst_len, "%u");
+iscsi_session_rd_attr(first_burst_len, "%u");
+iscsi_session_rd_attr(def_time2wait, "%hu");
+iscsi_session_rd_attr(def_time2retain, "%hu");
+iscsi_session_rd_attr(max_outstanding_r2t, "%hu");
+iscsi_session_rd_attr(erl, "%d");
+
+
+#define iscsi_session_show_bool_fn(field)				\
+									\
+static ssize_t								\
+show_session_bool_##field(struct class_device *cdev, char *buf)		\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+									\
+	if (i->fnt->get_##field)					\
+		i->fnt->get_##field(starget);				\
+									\
+	if (iscsi_##field(starget))					\
+		return sprintf(buf, "Yes\n");				\
+	return sprintf(buf, "No\n");					\
+}
+
+#define iscsi_session_rd_bool_attr(field)				\
+	iscsi_session_show_bool_fn(field)				\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_bool_##field, NULL);
+
+iscsi_session_rd_bool_attr(initial_r2t);
+iscsi_session_rd_bool_attr(immediate_data);
+iscsi_session_rd_bool_attr(data_pdu_in_order);
+iscsi_session_rd_bool_attr(data_sequence_in_order);
+
+#define iscsi_session_show_digest_fn(field)				\
+									\
+static ssize_t								\
+show_##field(struct class_device *cdev, char *buf)			\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+									\
+	if (i->fnt->get_##field)					\
+		i->fnt->get_##field(starget);				\
+									\
+	if (iscsi_##field(starget))					\
+		return sprintf(buf, "CRC32C\n");			\
+	return sprintf(buf, "None\n");					\
+}
+
+#define iscsi_session_rd_digest_attr(field)				\
+	iscsi_session_show_digest_fn(field)				\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
+
+iscsi_session_rd_digest_attr(header_digest);
+iscsi_session_rd_digest_attr(data_digest);
+
+static ssize_t
+show_port(struct class_device *cdev, char *buf)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+
+	if (i->fnt->get_port)
+		i->fnt->get_port(starget);
+
+	return snprintf(buf, 20, "%hu\n", ntohs(iscsi_port(starget)));
+}
+static CLASS_DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
+
+static ssize_t
+show_ip_address(struct class_device *cdev, char *buf)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+
+	if (i->fnt->get_ip_address)
+		i->fnt->get_ip_address(starget);
+
+	if (iscsi_addr_type(starget) == AF_INET)
+		return sprintf(buf, "%u.%u.%u.%u\n",
+			       NIPQUAD(iscsi_sin_addr(starget)));
+	else if(iscsi_addr_type(starget) == AF_INET6)
+		return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			       NIP6(iscsi_sin6_addr(starget)));
+	return -EINVAL;
+}
+static CLASS_DEVICE_ATTR(ip_address, S_IRUGO, show_ip_address, NULL);
+
+static ssize_t
+show_isid(struct class_device *cdev, char *buf)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt);
+
+	if (i->fnt->get_isid)
+		i->fnt->get_isid(starget);
+
+	return sprintf(buf, "%02x%02x%02x%02x%02x%02x\n",
+		       iscsi_isid(starget)[0], iscsi_isid(starget)[1],
+		       iscsi_isid(starget)[2], iscsi_isid(starget)[3],
+		       iscsi_isid(starget)[4], iscsi_isid(starget)[5]);
+}
+static CLASS_DEVICE_ATTR(isid, S_IRUGO, show_isid, NULL);
+
+/*
+ * This is used for iSCSI names. Normally, we follow
+ * the transport class convention of having the lld
+ * set the field, but in these cases the value is
+ * too large.
+ */
+#define iscsi_session_show_str_fn(field)				\
+									\
+static ssize_t								\
+show_session_str_##field(struct class_device *cdev, char *buf)		\
+{									\
+	ssize_t ret = 0;						\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+									\
+	if (i->fnt->get_##field)					\
+		ret = i->fnt->get_##field(starget, buf, PAGE_SIZE);	\
+	return ret;							\
+}
+
+#define iscsi_session_rd_str_attr(field)				\
+	iscsi_session_show_str_fn(field)				\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_session_str_##field, NULL);
+
+iscsi_session_rd_str_attr(target_name);
+iscsi_session_rd_str_attr(target_alias);
+
+/*
+ * iSCSI host attrs
+ */
+
+/*
+ * Again, this is used for iSCSI names. Normally, we follow
+ * the transport class convention of having the lld set
+ * the field, but in these cases the value is too large.
+ */
+#define iscsi_host_show_str_fn(field)					\
+									\
+static ssize_t								\
+show_host_str_##field(struct class_device *cdev, char *buf)		\
+{									\
+	int ret = 0;							\
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);	\
+	struct iscsi_internal *i = to_iscsi_internal(shost->transportt); \
+									\
+	if (i->fnt->get_##field)					\
+		ret = i->fnt->get_##field(shost, buf, PAGE_SIZE);	\
+	return ret;							\
+}
+
+#define iscsi_host_rd_str_attr(field)					\
+	iscsi_host_show_str_fn(field)					\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_host_str_##field, NULL);
+
+iscsi_host_rd_str_attr(initiator_name);
+iscsi_host_rd_str_attr(initiator_alias);
+
+#define SETUP_SESSION_RD_ATTR(field)					\
+	if (i->fnt->show_##field) {					\
+		i->session_attrs[count] = &class_device_attr_##field;	\
+		count++;						\
+	}
+
+#define SETUP_HOST_RD_ATTR(field)					\
+	if (i->fnt->show_##field) {					\
+		i->host_attrs[count] = &class_device_attr_##field;	\
+		count++;						\
+	}
+
+static int iscsi_host_match(struct attribute_container *cont,
+			  struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct iscsi_internal *i;
+
+	if (!scsi_is_host_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &iscsi_host_class.class)
+		return 0;
+
+	i = to_iscsi_internal(shost->transportt);
+	
+	return &i->t.host_attrs.ac == cont;
+}
+
+static int iscsi_target_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct iscsi_internal *i;
+
+	if (!scsi_is_target_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &iscsi_host_class.class)
+		return 0;
+
+	i = to_iscsi_internal(shost->transportt);
+	
+	return &i->t.target_attrs.ac == cont;
+}
+
+struct scsi_transport_template *
+iscsi_attach_transport(struct iscsi_function_template *fnt)
+{
+	struct iscsi_internal *i = kmalloc(sizeof(struct iscsi_internal),
+					   GFP_KERNEL);
+	int count = 0;
+
+	if (unlikely(!i))
+		return NULL;
+
+	memset(i, 0, sizeof(struct iscsi_internal));
+	i->fnt = fnt;
+
+	i->t.target_attrs.ac.attrs = &i->session_attrs[0];
+	i->t.target_attrs.ac.class = &iscsi_transport_class.class;
+	i->t.target_attrs.ac.match = iscsi_target_match;
+	transport_container_register(&i->t.target_attrs);
+	i->t.target_size = sizeof(struct iscsi_class_session);
+
+	SETUP_SESSION_RD_ATTR(tsih);
+	SETUP_SESSION_RD_ATTR(isid);
+	SETUP_SESSION_RD_ATTR(header_digest);
+	SETUP_SESSION_RD_ATTR(data_digest);
+	SETUP_SESSION_RD_ATTR(target_name);
+	SETUP_SESSION_RD_ATTR(target_alias);
+	SETUP_SESSION_RD_ATTR(port);
+	SETUP_SESSION_RD_ATTR(tpgt);
+	SETUP_SESSION_RD_ATTR(ip_address);
+	SETUP_SESSION_RD_ATTR(initial_r2t);
+	SETUP_SESSION_RD_ATTR(immediate_data);
+	SETUP_SESSION_RD_ATTR(max_recv_data_segment_len);
+	SETUP_SESSION_RD_ATTR(max_burst_len);
+	SETUP_SESSION_RD_ATTR(first_burst_len);
+	SETUP_SESSION_RD_ATTR(def_time2wait);
+	SETUP_SESSION_RD_ATTR(def_time2retain);
+	SETUP_SESSION_RD_ATTR(max_outstanding_r2t);
+	SETUP_SESSION_RD_ATTR(data_pdu_in_order);
+	SETUP_SESSION_RD_ATTR(data_sequence_in_order);
+	SETUP_SESSION_RD_ATTR(erl);
+
+	BUG_ON(count > ISCSI_SESSION_ATTRS);
+	i->session_attrs[count] = NULL;
+
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.class = &iscsi_host_class.class;
+	i->t.host_attrs.ac.match = iscsi_host_match;
+	transport_container_register(&i->t.host_attrs);
+	i->t.host_size = 0;
+
+	count = 0;
+	SETUP_HOST_RD_ATTR(initiator_name);
+	SETUP_HOST_RD_ATTR(initiator_alias);
+
+	BUG_ON(count > ISCSI_HOST_ATTRS);
+	i->host_attrs[count] = NULL;
+
+	return &i->t;
+}
+
+EXPORT_SYMBOL(iscsi_attach_transport);
+
+void iscsi_release_transport(struct scsi_transport_template *t)
+{
+	struct iscsi_internal *i = to_iscsi_internal(t);
+
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
+  
+	kfree(i);
+}
+
+EXPORT_SYMBOL(iscsi_release_transport);
+
+static __init int iscsi_transport_init(void)
+{
+	int err = transport_class_register(&iscsi_transport_class);
+
+	if (err)
+		return err;
+	return transport_class_register(&iscsi_host_class);
+}
+
+static void __exit iscsi_transport_exit(void)
+{
+	transport_class_unregister(&iscsi_host_class);
+	transport_class_unregister(&iscsi_transport_class);
+}
+
+module_init(iscsi_transport_init);
+module_exit(iscsi_transport_exit);
+
+MODULE_AUTHOR("Mike Christie");
+MODULE_DESCRIPTION("iSCSI Transport Attributes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
new file mode 100644
index 0000000..303d765
--- /dev/null
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -0,0 +1,1020 @@
+/* 
+ *  Parallel SCSI (SPI) transport specific attributes exported to sysfs.
+ *
+ *  Copyright (c) 2003 Silicon Graphics, Inc.  All rights reserved.
+ *  Copyright (c) 2004, 2005 James Bottomley <James.Bottomley@SteelEye.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/workqueue.h>
+#include <asm/semaphore.h>
+#include <scsi/scsi.h>
+#include "scsi_priv.h"
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#define SPI_PRINTK(x, l, f, a...)	dev_printk(l, &(x)->dev, f , ##a)
+
+#define SPI_NUM_ATTRS 10	/* increase this if you add attributes */
+#define SPI_OTHER_ATTRS 1	/* Increase this if you add "always
+				 * on" attributes */
+#define SPI_HOST_ATTRS	1
+
+#define SPI_MAX_ECHO_BUFFER_SIZE	4096
+
+/* Private data accessors (keep these out of the header file) */
+#define spi_dv_pending(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_pending)
+#define spi_dv_sem(x) (((struct spi_transport_attrs *)&(x)->starget_data)->dv_sem)
+
+struct spi_internal {
+	struct scsi_transport_template t;
+	struct spi_function_template *f;
+	/* The actual attributes */
+	struct class_device_attribute private_attrs[SPI_NUM_ATTRS];
+	/* The array of null terminated pointers to attributes 
+	 * needed by scsi_sysfs.c */
+	struct class_device_attribute *attrs[SPI_NUM_ATTRS + SPI_OTHER_ATTRS + 1];
+	struct class_device_attribute private_host_attrs[SPI_HOST_ATTRS];
+	struct class_device_attribute *host_attrs[SPI_HOST_ATTRS + 1];
+};
+
+#define to_spi_internal(tmpl)	container_of(tmpl, struct spi_internal, t)
+
+static const int ppr_to_ps[] = {
+	/* The PPR values 0-6 are reserved, fill them in when
+	 * the committee defines them */
+	-1,			/* 0x00 */
+	-1,			/* 0x01 */
+	-1,			/* 0x02 */
+	-1,			/* 0x03 */
+	-1,			/* 0x04 */
+	-1,			/* 0x05 */
+	-1,			/* 0x06 */
+	 3125,			/* 0x07 */
+	 6250,			/* 0x08 */
+	12500,			/* 0x09 */
+	25000,			/* 0x0a */
+	30300,			/* 0x0b */
+	50000,			/* 0x0c */
+};
+/* The PPR values at which you calculate the period in ns by multiplying
+ * by 4 */
+#define SPI_STATIC_PPR	0x0c
+
+static int sprint_frac(char *dest, int value, int denom)
+{
+	int frac = value % denom;
+	int result = sprintf(dest, "%d", value / denom);
+
+	if (frac == 0)
+		return result;
+	dest[result++] = '.';
+
+	do {
+		denom /= 10;
+		sprintf(dest + result, "%d", frac / denom);
+		result++;
+		frac %= denom;
+	} while (frac);
+
+	dest[result++] = '\0';
+	return result;
+}
+
+static struct {
+	enum spi_signal_type	value;
+	char			*name;
+} signal_types[] = {
+	{ SPI_SIGNAL_UNKNOWN, "unknown" },
+	{ SPI_SIGNAL_SE, "SE" },
+	{ SPI_SIGNAL_LVD, "LVD" },
+	{ SPI_SIGNAL_HVD, "HVD" },
+};
+
+static inline const char *spi_signal_to_string(enum spi_signal_type type)
+{
+	int i;
+
+	for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+		if (type == signal_types[i].value)
+			return signal_types[i].name;
+	}
+	return NULL;
+}
+static inline enum spi_signal_type spi_signal_to_value(const char *name)
+{
+	int i, len;
+
+	for (i = 0; i < sizeof(signal_types)/sizeof(signal_types[0]); i++) {
+		len =  strlen(signal_types[i].name);
+		if (strncmp(name, signal_types[i].name, len) == 0 &&
+		    (name[len] == '\n' || name[len] == '\0'))
+			return signal_types[i].value;
+	}
+	return SPI_SIGNAL_UNKNOWN;
+}
+
+static int spi_host_setup(struct device *dev)
+{
+	struct Scsi_Host *shost = dev_to_shost(dev);
+
+	spi_signalling(shost) = SPI_SIGNAL_UNKNOWN;
+
+	return 0;
+}
+
+static DECLARE_TRANSPORT_CLASS(spi_host_class,
+			       "spi_host",
+			       spi_host_setup,
+			       NULL,
+			       NULL);
+
+static int spi_host_match(struct attribute_container *cont,
+			  struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct spi_internal *i;
+
+	if (!scsi_is_host_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &spi_host_class.class)
+		return 0;
+
+	i = to_spi_internal(shost->transportt);
+	
+	return &i->t.host_attrs.ac == cont;
+}
+
+static int spi_device_configure(struct device *dev)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct scsi_target *starget = sdev->sdev_target;
+
+	/* Populate the target capability fields with the values
+	 * gleaned from the device inquiry */
+
+	spi_support_sync(starget) = scsi_device_sync(sdev);
+	spi_support_wide(starget) = scsi_device_wide(sdev);
+	spi_support_dt(starget) = scsi_device_dt(sdev);
+	spi_support_dt_only(starget) = scsi_device_dt_only(sdev);
+	spi_support_ius(starget) = scsi_device_ius(sdev);
+	spi_support_qas(starget) = scsi_device_qas(sdev);
+
+	return 0;
+}
+
+static int spi_setup_transport_attrs(struct device *dev)
+{
+	struct scsi_target *starget = to_scsi_target(dev);
+
+	spi_period(starget) = -1;	/* illegal value */
+	spi_offset(starget) = 0;	/* async */
+	spi_width(starget) = 0;	/* narrow */
+	spi_iu(starget) = 0;	/* no IU */
+	spi_dt(starget) = 0;	/* ST */
+	spi_qas(starget) = 0;
+	spi_wr_flow(starget) = 0;
+	spi_rd_strm(starget) = 0;
+	spi_rti(starget) = 0;
+	spi_pcomp_en(starget) = 0;
+	spi_dv_pending(starget) = 0;
+	spi_initial_dv(starget) = 0;
+	init_MUTEX(&spi_dv_sem(starget));
+
+	return 0;
+}
+
+#define spi_transport_show_function(field, format_string)		\
+									\
+static ssize_t								\
+show_spi_transport_##field(struct class_device *cdev, char *buf)	\
+{									\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct spi_transport_attrs *tp;					\
+	struct spi_internal *i = to_spi_internal(shost->transportt);	\
+	tp = (struct spi_transport_attrs *)&starget->starget_data;	\
+	if (i->f->get_##field)						\
+		i->f->get_##field(starget);				\
+	return snprintf(buf, 20, format_string, tp->field);		\
+}
+
+#define spi_transport_store_function(field, format_string)		\
+static ssize_t								\
+store_spi_transport_##field(struct class_device *cdev, const char *buf, \
+			    size_t count)				\
+{									\
+	int val;							\
+	struct scsi_target *starget = transport_class_to_starget(cdev);	\
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);	\
+	struct spi_internal *i = to_spi_internal(shost->transportt);	\
+									\
+	val = simple_strtoul(buf, NULL, 0);				\
+	i->f->set_##field(starget, val);				\
+	return count;							\
+}
+
+#define spi_transport_rd_attr(field, format_string)			\
+	spi_transport_show_function(field, format_string)		\
+	spi_transport_store_function(field, format_string)		\
+static CLASS_DEVICE_ATTR(field, S_IRUGO | S_IWUSR,			\
+			 show_spi_transport_##field,			\
+			 store_spi_transport_##field);
+
+/* The Parallel SCSI Tranport Attributes: */
+spi_transport_rd_attr(offset, "%d\n");
+spi_transport_rd_attr(width, "%d\n");
+spi_transport_rd_attr(iu, "%d\n");
+spi_transport_rd_attr(dt, "%d\n");
+spi_transport_rd_attr(qas, "%d\n");
+spi_transport_rd_attr(wr_flow, "%d\n");
+spi_transport_rd_attr(rd_strm, "%d\n");
+spi_transport_rd_attr(rti, "%d\n");
+spi_transport_rd_attr(pcomp_en, "%d\n");
+
+static ssize_t
+store_spi_revalidate(struct class_device *cdev, const char *buf, size_t count)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+
+	/* FIXME: we're relying on an awful lot of device internals
+	 * here.  We really need a function to get the first available
+	 * child */
+	struct device *dev = container_of(starget->dev.children.next, struct device, node);
+	struct scsi_device *sdev = to_scsi_device(dev);
+	spi_dv_device(sdev);
+	return count;
+}
+static CLASS_DEVICE_ATTR(revalidate, S_IWUSR, NULL, store_spi_revalidate);
+
+/* Translate the period into ns according to the current spec
+ * for SDTR/PPR messages */
+static ssize_t show_spi_transport_period(struct class_device *cdev, char *buf)
+
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct spi_transport_attrs *tp;
+	int len, picosec;
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+
+	tp = (struct spi_transport_attrs *)&starget->starget_data;
+
+	if (i->f->get_period)
+		i->f->get_period(starget);
+
+	if (tp->period < 0 || tp->period > 0xff) {
+		picosec = -1;
+	} else if (tp->period <= SPI_STATIC_PPR) {
+		picosec = ppr_to_ps[tp->period];
+	} else {
+		picosec = tp->period * 4000;
+	}
+
+	if (picosec == -1) {
+		len = sprintf(buf, "reserved");
+	} else {
+		len = sprint_frac(buf, picosec, 1000);
+	}
+
+	buf[len++] = '\n';
+	buf[len] = '\0';
+	return len;
+}
+
+static ssize_t
+store_spi_transport_period(struct class_device *cdev, const char *buf,
+			    size_t count)
+{
+	struct scsi_target *starget = transport_class_to_starget(cdev);
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+	int j, picosec, period = -1;
+	char *endp;
+
+	picosec = simple_strtoul(buf, &endp, 10) * 1000;
+	if (*endp == '.') {
+		int mult = 100;
+		do {
+			endp++;
+			if (!isdigit(*endp))
+				break;
+			picosec += (*endp - '0') * mult;
+			mult /= 10;
+		} while (mult > 0);
+	}
+
+	for (j = 0; j <= SPI_STATIC_PPR; j++) {
+		if (ppr_to_ps[j] < picosec)
+			continue;
+		period = j;
+		break;
+	}
+
+	if (period == -1)
+		period = picosec / 4000;
+
+	if (period > 0xff)
+		period = 0xff;
+
+	i->f->set_period(starget, period);
+
+	return count;
+}
+
+static CLASS_DEVICE_ATTR(period, S_IRUGO | S_IWUSR, 
+			 show_spi_transport_period,
+			 store_spi_transport_period);
+
+static ssize_t show_spi_host_signalling(struct class_device *cdev, char *buf)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+
+	if (i->f->get_signalling)
+		i->f->get_signalling(shost);
+
+	return sprintf(buf, "%s\n", spi_signal_to_string(spi_signalling(shost)));
+}
+static ssize_t store_spi_host_signalling(struct class_device *cdev,
+					 const char *buf, size_t count)
+{
+	struct Scsi_Host *shost = transport_class_to_shost(cdev);
+	struct spi_internal *i = to_spi_internal(shost->transportt);
+	enum spi_signal_type type = spi_signal_to_value(buf);
+
+	if (type != SPI_SIGNAL_UNKNOWN)
+		i->f->set_signalling(shost, type);
+
+	return count;
+}
+static CLASS_DEVICE_ATTR(signalling, S_IRUGO | S_IWUSR,
+			 show_spi_host_signalling,
+			 store_spi_host_signalling);
+
+#define DV_SET(x, y)			\
+	if(i->f->set_##x)		\
+		i->f->set_##x(sdev->sdev_target, y)
+
+#define DV_LOOPS	3
+#define DV_TIMEOUT	(10*HZ)
+#define DV_RETRIES	3	/* should only need at most 
+				 * two cc/ua clears */
+
+enum spi_compare_returns {
+	SPI_COMPARE_SUCCESS,
+	SPI_COMPARE_FAILURE,
+	SPI_COMPARE_SKIP_TEST,
+};
+
+
+/* This is for read/write Domain Validation:  If the device supports
+ * an echo buffer, we do read/write tests to it */
+static enum spi_compare_returns
+spi_dv_device_echo_buffer(struct scsi_request *sreq, u8 *buffer,
+			  u8 *ptr, const int retries)
+{
+	struct scsi_device *sdev = sreq->sr_device;
+	int len = ptr - buffer;
+	int j, k, r;
+	unsigned int pattern = 0x0000ffff;
+
+	const char spi_write_buffer[] = {
+		WRITE_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
+	};
+	const char spi_read_buffer[] = {
+		READ_BUFFER, 0x0a, 0, 0, 0, 0, 0, len >> 8, len & 0xff, 0
+	};
+
+	/* set up the pattern buffer.  Doesn't matter if we spill
+	 * slightly beyond since that's where the read buffer is */
+	for (j = 0; j < len; ) {
+
+		/* fill the buffer with counting (test a) */
+		for ( ; j < min(len, 32); j++)
+			buffer[j] = j;
+		k = j;
+		/* fill the buffer with alternating words of 0x0 and
+		 * 0xffff (test b) */
+		for ( ; j < min(len, k + 32); j += 2) {
+			u16 *word = (u16 *)&buffer[j];
+			
+			*word = (j & 0x02) ? 0x0000 : 0xffff;
+		}
+		k = j;
+		/* fill with crosstalk (alternating 0x5555 0xaaa)
+                 * (test c) */
+		for ( ; j < min(len, k + 32); j += 2) {
+			u16 *word = (u16 *)&buffer[j];
+
+			*word = (j & 0x02) ? 0x5555 : 0xaaaa;
+		}
+		k = j;
+		/* fill with shifting bits (test d) */
+		for ( ; j < min(len, k + 32); j += 4) {
+			u32 *word = (unsigned int *)&buffer[j];
+			u32 roll = (pattern & 0x80000000) ? 1 : 0;
+			
+			*word = pattern;
+			pattern = (pattern << 1) | roll;
+		}
+		/* don't bother with random data (test e) */
+	}
+
+	for (r = 0; r < retries; r++) {
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_TO_DEVICE;
+		scsi_wait_req(sreq, spi_write_buffer, buffer, len,
+			      DV_TIMEOUT, DV_RETRIES);
+		if(sreq->sr_result || !scsi_device_online(sdev)) {
+			struct scsi_sense_hdr sshdr;
+
+			scsi_device_set_state(sdev, SDEV_QUIESCE);
+			if (scsi_request_normalize_sense(sreq, &sshdr)
+			    && sshdr.sense_key == ILLEGAL_REQUEST
+			    /* INVALID FIELD IN CDB */
+			    && sshdr.asc == 0x24 && sshdr.ascq == 0x00)
+				/* This would mean that the drive lied
+				 * to us about supporting an echo
+				 * buffer (unfortunately some Western
+				 * Digital drives do precisely this)
+				 */
+				return SPI_COMPARE_SKIP_TEST;
+
+
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Write Buffer failure %x\n", sreq->sr_result);
+			return SPI_COMPARE_FAILURE;
+		}
+
+		memset(ptr, 0, len);
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_FROM_DEVICE;
+		scsi_wait_req(sreq, spi_read_buffer, ptr, len,
+			      DV_TIMEOUT, DV_RETRIES);
+		scsi_device_set_state(sdev, SDEV_QUIESCE);
+
+		if (memcmp(buffer, ptr, len) != 0)
+			return SPI_COMPARE_FAILURE;
+	}
+	return SPI_COMPARE_SUCCESS;
+}
+
+/* This is for the simplest form of Domain Validation: a read test
+ * on the inquiry data from the device */
+static enum spi_compare_returns
+spi_dv_device_compare_inquiry(struct scsi_request *sreq, u8 *buffer,
+			      u8 *ptr, const int retries)
+{
+	int r;
+	const int len = sreq->sr_device->inquiry_len;
+	struct scsi_device *sdev = sreq->sr_device;
+	const char spi_inquiry[] = {
+		INQUIRY, 0, 0, 0, len, 0
+	};
+
+	for (r = 0; r < retries; r++) {
+		sreq->sr_cmd_len = 0;	/* wait_req to fill in */
+		sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+		memset(ptr, 0, len);
+
+		scsi_wait_req(sreq, spi_inquiry, ptr, len,
+			      DV_TIMEOUT, DV_RETRIES);
+		
+		if(sreq->sr_result || !scsi_device_online(sdev)) {
+			scsi_device_set_state(sdev, SDEV_QUIESCE);
+			return SPI_COMPARE_FAILURE;
+		}
+
+		/* If we don't have the inquiry data already, the
+		 * first read gets it */
+		if (ptr == buffer) {
+			ptr += len;
+			--r;
+			continue;
+		}
+
+		if (memcmp(buffer, ptr, len) != 0)
+			/* failure */
+			return SPI_COMPARE_FAILURE;
+	}
+	return SPI_COMPARE_SUCCESS;
+}
+
+static enum spi_compare_returns
+spi_dv_retrain(struct scsi_request *sreq, u8 *buffer, u8 *ptr,
+	       enum spi_compare_returns 
+	       (*compare_fn)(struct scsi_request *, u8 *, u8 *, int))
+{
+	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
+	struct scsi_device *sdev = sreq->sr_device;
+	int period = 0, prevperiod = 0; 
+	enum spi_compare_returns retval;
+
+
+	for (;;) {
+		int newperiod;
+		retval = compare_fn(sreq, buffer, ptr, DV_LOOPS);
+
+		if (retval == SPI_COMPARE_SUCCESS
+		    || retval == SPI_COMPARE_SKIP_TEST)
+			break;
+
+		/* OK, retrain, fallback */
+		if (i->f->get_period)
+			i->f->get_period(sdev->sdev_target);
+		newperiod = spi_period(sdev->sdev_target);
+		period = newperiod > period ? newperiod : period;
+		if (period < 0x0d)
+			period++;
+		else
+			period += period >> 1;
+
+		if (unlikely(period > 0xff || period == prevperiod)) {
+			/* Total failure; set to async and return */
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Failure, dropping back to Asynchronous\n");
+			DV_SET(offset, 0);
+			return SPI_COMPARE_FAILURE;
+		}
+		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation detected failure, dropping back\n");
+		DV_SET(period, period);
+		prevperiod = period;
+	}
+	return retval;
+}
+
+static int
+spi_dv_device_get_echo_buffer(struct scsi_request *sreq, u8 *buffer)
+{
+	int l;
+
+	/* first off do a test unit ready.  This can error out 
+	 * because of reservations or some other reason.  If it
+	 * fails, the device won't let us write to the echo buffer
+	 * so just return failure */
+	
+	const char spi_test_unit_ready[] = {
+		TEST_UNIT_READY, 0, 0, 0, 0, 0
+	};
+
+	const char spi_read_buffer_descriptor[] = {
+		READ_BUFFER, 0x0b, 0, 0, 0, 0, 0, 0, 4, 0
+	};
+
+	
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_NONE;
+
+	/* We send a set of three TURs to clear any outstanding 
+	 * unit attention conditions if they exist (Otherwise the
+	 * buffer tests won't be happy).  If the TUR still fails
+	 * (reservation conflict, device not ready, etc) just
+	 * skip the write tests */
+	for (l = 0; ; l++) {
+		scsi_wait_req(sreq, spi_test_unit_ready, NULL, 0,
+			      DV_TIMEOUT, DV_RETRIES);
+
+		if(sreq->sr_result) {
+			if(l >= 3)
+				return 0;
+		} else {
+			/* TUR succeeded */
+			break;
+		}
+	}
+
+	sreq->sr_cmd_len = 0;
+	sreq->sr_data_direction = DMA_FROM_DEVICE;
+
+	scsi_wait_req(sreq, spi_read_buffer_descriptor, buffer, 4,
+		      DV_TIMEOUT, DV_RETRIES);
+
+	if (sreq->sr_result)
+		/* Device has no echo buffer */
+		return 0;
+
+	return buffer[3] + ((buffer[2] & 0x1f) << 8);
+}
+
+static void
+spi_dv_device_internal(struct scsi_request *sreq, u8 *buffer)
+{
+	struct spi_internal *i = to_spi_internal(sreq->sr_host->transportt);
+	struct scsi_device *sdev = sreq->sr_device;
+	int len = sdev->inquiry_len;
+	/* first set us up for narrow async */
+	DV_SET(offset, 0);
+	DV_SET(width, 0);
+	
+	if (spi_dv_device_compare_inquiry(sreq, buffer, buffer, DV_LOOPS)
+	    != SPI_COMPARE_SUCCESS) {
+		SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Domain Validation Initial Inquiry Failed\n");
+		/* FIXME: should probably offline the device here? */
+		return;
+	}
+
+	/* test width */
+	if (i->f->set_width && sdev->wdtr) {
+		i->f->set_width(sdev->sdev_target, 1);
+
+		if (spi_dv_device_compare_inquiry(sreq, buffer,
+						   buffer + len,
+						   DV_LOOPS)
+		    != SPI_COMPARE_SUCCESS) {
+			SPI_PRINTK(sdev->sdev_target, KERN_ERR, "Wide Transfers Fail\n");
+			i->f->set_width(sdev->sdev_target, 0);
+		}
+	}
+
+	if (!i->f->set_period)
+		return;
+
+	/* device can't handle synchronous */
+	if(!sdev->ppr && !sdev->sdtr)
+		return;
+
+	/* see if the device has an echo buffer.  If it does we can
+	 * do the SPI pattern write tests */
+
+	len = 0;
+	if (sdev->ppr)
+		len = spi_dv_device_get_echo_buffer(sreq, buffer);
+
+ retry:
+
+	/* now set up to the maximum */
+	DV_SET(offset, 255);
+	DV_SET(period, 1);
+
+	if (len == 0) {
+		SPI_PRINTK(sdev->sdev_target, KERN_INFO, "Domain Validation skipping write tests\n");
+		spi_dv_retrain(sreq, buffer, buffer + len,
+			       spi_dv_device_compare_inquiry);
+		return;
+	}
+
+	if (len > SPI_MAX_ECHO_BUFFER_SIZE) {
+		SPI_PRINTK(sdev->sdev_target, KERN_WARNING, "Echo buffer size %d is too big, trimming to %d\n", len, SPI_MAX_ECHO_BUFFER_SIZE);
+		len = SPI_MAX_ECHO_BUFFER_SIZE;
+	}
+
+	if (spi_dv_retrain(sreq, buffer, buffer + len,
+			   spi_dv_device_echo_buffer)
+	    == SPI_COMPARE_SKIP_TEST) {
+		/* OK, the stupid drive can't do a write echo buffer
+		 * test after all, fall back to the read tests */
+		len = 0;
+		goto retry;
+	}
+}
+
+
+/**	spi_dv_device - Do Domain Validation on the device
+ *	@sdev:		scsi device to validate
+ *
+ *	Performs the domain validation on the given device in the
+ *	current execution thread.  Since DV operations may sleep,
+ *	the current thread must have user context.  Also no SCSI
+ *	related locks that would deadlock I/O issued by the DV may
+ *	be held.
+ */
+void
+spi_dv_device(struct scsi_device *sdev)
+{
+	struct scsi_request *sreq = scsi_allocate_request(sdev, GFP_KERNEL);
+	struct scsi_target *starget = sdev->sdev_target;
+	u8 *buffer;
+	const int len = SPI_MAX_ECHO_BUFFER_SIZE*2;
+
+	if (unlikely(!sreq))
+		return;
+
+	if (unlikely(scsi_device_get(sdev)))
+		goto out_free_req;
+
+	buffer = kmalloc(len, GFP_KERNEL);
+
+	if (unlikely(!buffer))
+		goto out_put;
+
+	memset(buffer, 0, len);
+
+	/* We need to verify that the actual device will quiesce; the
+	 * later target quiesce is just a nice to have */
+	if (unlikely(scsi_device_quiesce(sdev)))
+		goto out_free;
+
+	scsi_target_quiesce(starget);
+
+	spi_dv_pending(starget) = 1;
+	down(&spi_dv_sem(starget));
+
+	SPI_PRINTK(starget, KERN_INFO, "Beginning Domain Validation\n");
+
+	spi_dv_device_internal(sreq, buffer);
+
+	SPI_PRINTK(starget, KERN_INFO, "Ending Domain Validation\n");
+
+	up(&spi_dv_sem(starget));
+	spi_dv_pending(starget) = 0;
+
+	scsi_target_resume(starget);
+
+	spi_initial_dv(starget) = 1;
+
+ out_free:
+	kfree(buffer);
+ out_put:
+	scsi_device_put(sdev);
+ out_free_req:
+	scsi_release_request(sreq);
+}
+EXPORT_SYMBOL(spi_dv_device);
+
+struct work_queue_wrapper {
+	struct work_struct	work;
+	struct scsi_device	*sdev;
+};
+
+static void
+spi_dv_device_work_wrapper(void *data)
+{
+	struct work_queue_wrapper *wqw = (struct work_queue_wrapper *)data;
+	struct scsi_device *sdev = wqw->sdev;
+
+	kfree(wqw);
+	spi_dv_device(sdev);
+	spi_dv_pending(sdev->sdev_target) = 0;
+	scsi_device_put(sdev);
+}
+
+
+/**
+ *	spi_schedule_dv_device - schedule domain validation to occur on the device
+ *	@sdev:	The device to validate
+ *
+ *	Identical to spi_dv_device() above, except that the DV will be
+ *	scheduled to occur in a workqueue later.  All memory allocations
+ *	are atomic, so may be called from any context including those holding
+ *	SCSI locks.
+ */
+void
+spi_schedule_dv_device(struct scsi_device *sdev)
+{
+	struct work_queue_wrapper *wqw =
+		kmalloc(sizeof(struct work_queue_wrapper), GFP_ATOMIC);
+
+	if (unlikely(!wqw))
+		return;
+
+	if (unlikely(spi_dv_pending(sdev->sdev_target))) {
+		kfree(wqw);
+		return;
+	}
+	/* Set pending early (dv_device doesn't check it, only sets it) */
+	spi_dv_pending(sdev->sdev_target) = 1;
+	if (unlikely(scsi_device_get(sdev))) {
+		kfree(wqw);
+		spi_dv_pending(sdev->sdev_target) = 0;
+		return;
+	}
+
+	INIT_WORK(&wqw->work, spi_dv_device_work_wrapper, wqw);
+	wqw->sdev = sdev;
+
+	schedule_work(&wqw->work);
+}
+EXPORT_SYMBOL(spi_schedule_dv_device);
+
+/**
+ * spi_display_xfer_agreement - Print the current target transfer agreement
+ * @starget: The target for which to display the agreement
+ *
+ * Each SPI port is required to maintain a transfer agreement for each
+ * other port on the bus.  This function prints a one-line summary of
+ * the current agreement; more detailed information is available in sysfs.
+ */
+void spi_display_xfer_agreement(struct scsi_target *starget)
+{
+	struct spi_transport_attrs *tp;
+	tp = (struct spi_transport_attrs *)&starget->starget_data;
+
+	if (tp->offset > 0 && tp->period > 0) {
+		unsigned int picosec, kb100;
+		char *scsi = "FAST-?";
+		char tmp[8];
+
+		if (tp->period <= SPI_STATIC_PPR) {
+			picosec = ppr_to_ps[tp->period];
+			switch (tp->period) {
+				case  7: scsi = "FAST-320"; break;
+				case  8: scsi = "FAST-160"; break;
+				case  9: scsi = "FAST-80"; break;
+				case 10:
+				case 11: scsi = "FAST-40"; break;
+				case 12: scsi = "FAST-20"; break;
+			}
+		} else {
+			picosec = tp->period * 4000;
+			if (tp->period < 25)
+				scsi = "FAST-20";
+			else if (tp->period < 50)
+				scsi = "FAST-10";
+			else
+				scsi = "FAST-5";
+		}
+
+		kb100 = (10000000 + picosec / 2) / picosec;
+		if (tp->width)
+			kb100 *= 2;
+		sprint_frac(tmp, picosec, 1000);
+
+		dev_info(&starget->dev,
+			"%s %sSCSI %d.%d MB/s %s%s%s (%s ns, offset %d)\n",
+			scsi, tp->width ? "WIDE " : "", kb100/10, kb100 % 10,
+			tp->dt ? "DT" : "ST", tp->iu ? " IU" : "",
+			tp->qas  ? " QAS" : "", tmp, tp->offset);
+	} else {
+		dev_info(&starget->dev, "%sasynchronous.\n",
+				tp->width ? "wide " : "");
+	}
+}
+EXPORT_SYMBOL(spi_display_xfer_agreement);
+
+#define SETUP_ATTRIBUTE(field)						\
+	i->private_attrs[count] = class_device_attr_##field;		\
+	if (!i->f->set_##field) {					\
+		i->private_attrs[count].attr.mode = S_IRUGO;		\
+		i->private_attrs[count].store = NULL;			\
+	}								\
+	i->attrs[count] = &i->private_attrs[count];			\
+	if (i->f->show_##field)						\
+		count++
+
+#define SETUP_HOST_ATTRIBUTE(field)					\
+	i->private_host_attrs[count] = class_device_attr_##field;	\
+	if (!i->f->set_##field) {					\
+		i->private_host_attrs[count].attr.mode = S_IRUGO;	\
+		i->private_host_attrs[count].store = NULL;		\
+	}								\
+	i->host_attrs[count] = &i->private_host_attrs[count];		\
+	count++
+
+static int spi_device_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct scsi_device *sdev;
+	struct Scsi_Host *shost;
+
+	if (!scsi_is_sdev_device(dev))
+		return 0;
+
+	sdev = to_scsi_device(dev);
+	shost = sdev->host;
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &spi_host_class.class)
+		return 0;
+	/* Note: this class has no device attributes, so it has
+	 * no per-HBA allocation and thus we don't need to distinguish
+	 * the attribute containers for the device */
+	return 1;
+}
+
+static int spi_target_match(struct attribute_container *cont,
+			    struct device *dev)
+{
+	struct Scsi_Host *shost;
+	struct spi_internal *i;
+
+	if (!scsi_is_target_device(dev))
+		return 0;
+
+	shost = dev_to_shost(dev->parent);
+	if (!shost->transportt  || shost->transportt->host_attrs.ac.class
+	    != &spi_host_class.class)
+		return 0;
+
+	i = to_spi_internal(shost->transportt);
+	
+	return &i->t.target_attrs.ac == cont;
+}
+
+static DECLARE_TRANSPORT_CLASS(spi_transport_class,
+			       "spi_transport",
+			       spi_setup_transport_attrs,
+			       NULL,
+			       NULL);
+
+static DECLARE_ANON_TRANSPORT_CLASS(spi_device_class,
+				    spi_device_match,
+				    spi_device_configure);
+
+struct scsi_transport_template *
+spi_attach_transport(struct spi_function_template *ft)
+{
+	struct spi_internal *i = kmalloc(sizeof(struct spi_internal),
+					 GFP_KERNEL);
+	int count = 0;
+	if (unlikely(!i))
+		return NULL;
+
+	memset(i, 0, sizeof(struct spi_internal));
+
+
+	i->t.target_attrs.ac.class = &spi_transport_class.class;
+	i->t.target_attrs.ac.attrs = &i->attrs[0];
+	i->t.target_attrs.ac.match = spi_target_match;
+	transport_container_register(&i->t.target_attrs);
+	i->t.target_size = sizeof(struct spi_transport_attrs);
+	i->t.host_attrs.ac.class = &spi_host_class.class;
+	i->t.host_attrs.ac.attrs = &i->host_attrs[0];
+	i->t.host_attrs.ac.match = spi_host_match;
+	transport_container_register(&i->t.host_attrs);
+	i->t.host_size = sizeof(struct spi_host_attrs);
+	i->f = ft;
+
+	SETUP_ATTRIBUTE(period);
+	SETUP_ATTRIBUTE(offset);
+	SETUP_ATTRIBUTE(width);
+	SETUP_ATTRIBUTE(iu);
+	SETUP_ATTRIBUTE(dt);
+	SETUP_ATTRIBUTE(qas);
+	SETUP_ATTRIBUTE(wr_flow);
+	SETUP_ATTRIBUTE(rd_strm);
+	SETUP_ATTRIBUTE(rti);
+	SETUP_ATTRIBUTE(pcomp_en);
+
+	/* if you add an attribute but forget to increase SPI_NUM_ATTRS
+	 * this bug will trigger */
+	BUG_ON(count > SPI_NUM_ATTRS);
+
+	i->attrs[count++] = &class_device_attr_revalidate;
+
+	i->attrs[count] = NULL;
+
+	count = 0;
+	SETUP_HOST_ATTRIBUTE(signalling);
+
+	BUG_ON(count > SPI_HOST_ATTRS);
+
+	i->host_attrs[count] = NULL;
+
+	return &i->t;
+}
+EXPORT_SYMBOL(spi_attach_transport);
+
+void spi_release_transport(struct scsi_transport_template *t)
+{
+	struct spi_internal *i = to_spi_internal(t);
+
+	transport_container_unregister(&i->t.target_attrs);
+	transport_container_unregister(&i->t.host_attrs);
+
+	kfree(i);
+}
+EXPORT_SYMBOL(spi_release_transport);
+
+static __init int spi_transport_init(void)
+{
+	int error = transport_class_register(&spi_transport_class);
+	if (error)
+		return error;
+	error = anon_transport_class_register(&spi_device_class);
+	return transport_class_register(&spi_host_class);
+}
+
+static void __exit spi_transport_exit(void)
+{
+	transport_class_unregister(&spi_transport_class);
+	anon_transport_class_unregister(&spi_device_class);
+	transport_class_unregister(&spi_host_class);
+}
+
+MODULE_AUTHOR("Martin Hicks");
+MODULE_DESCRIPTION("SPI Transport Attributes");
+MODULE_LICENSE("GPL");
+
+module_init(spi_transport_init);
+module_exit(spi_transport_exit);
diff --git a/drivers/scsi/scsi_typedefs.h b/drivers/scsi/scsi_typedefs.h
new file mode 100644
index 0000000..6c43132
--- /dev/null
+++ b/drivers/scsi/scsi_typedefs.h
@@ -0,0 +1,6 @@
+
+typedef struct scsi_host_template Scsi_Host_Template;
+typedef struct scsi_device Scsi_Device;
+typedef struct scsi_cmnd Scsi_Cmnd;
+typedef struct scsi_request Scsi_Request;
+typedef struct scsi_pointer Scsi_Pointer;
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
new file mode 100644
index 0000000..b78354f
--- /dev/null
+++ b/drivers/scsi/scsicam.c
@@ -0,0 +1,245 @@
+/*
+ * scsicam.c - SCSI CAM support functions, use for HDIO_GETGEO, etc.
+ *
+ * Copyright 1993, 1994 Drew Eckhardt
+ *      Visionary Computing 
+ *      (Unix and Linux consulting and custom programming)
+ *      drew@Colorado.EDU
+ *      +1 (303) 786-7975
+ *
+ * For more information, please consult the SCSI-CAM draft.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/genhd.h>
+#include <linux/kernel.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>
+#include <asm/unaligned.h>
+
+#include <scsi/scsicam.h>
+
+
+static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
+		   unsigned int *secs);
+
+unsigned char *scsi_bios_ptable(struct block_device *dev)
+{
+	unsigned char *res = kmalloc(66, GFP_KERNEL);
+	if (res) {
+		struct block_device *bdev = dev->bd_contains;
+		Sector sect;
+		void *data = read_dev_sector(bdev, 0, &sect);
+		if (data) {
+			memcpy(res, data + 0x1be, 66);
+			put_dev_sector(sect);
+		} else {
+			kfree(res);
+			res = NULL;
+		}
+	}
+	return res;
+}
+EXPORT_SYMBOL(scsi_bios_ptable);
+
+/*
+ * Function : int scsicam_bios_param (struct block_device *bdev, ector_t capacity, int *ip)
+ *
+ * Purpose : to determine the BIOS mapping used for a drive in a 
+ *      SCSI-CAM system, storing the results in ip as required
+ *      by the HDIO_GETGEO ioctl().
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ */
+
+int scsicam_bios_param(struct block_device *bdev, sector_t capacity, int *ip)
+{
+	unsigned char *p;
+	int ret;
+
+	p = scsi_bios_ptable(bdev);
+	if (!p)
+		return -1;
+
+	/* try to infer mapping from partition table */
+	ret = scsi_partsize(p, (unsigned long)capacity, (unsigned int *)ip + 2,
+			       (unsigned int *)ip + 0, (unsigned int *)ip + 1);
+	kfree(p);
+
+	if (ret == -1) {
+		/* pick some standard mapping with at most 1024 cylinders,
+		   and at most 62 sectors per track - this works up to
+		   7905 MB */
+		ret = setsize((unsigned long)capacity, (unsigned int *)ip + 2,
+		       (unsigned int *)ip + 0, (unsigned int *)ip + 1);
+	}
+
+	/* if something went wrong, then apparently we have to return
+	   a geometry with more than 1024 cylinders */
+	if (ret || ip[0] > 255 || ip[1] > 63) {
+		if ((capacity >> 11) > 65534) {
+			ip[0] = 255;
+			ip[1] = 63;
+		} else {
+			ip[0] = 64;
+			ip[1] = 32;
+		}
+
+		if (capacity > 65535*63*255)
+			ip[2] = 65535;
+		else
+			ip[2] = (unsigned long)capacity / (ip[0] * ip[1]);
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL(scsicam_bios_param);
+
+/*
+ * Function : static int scsi_partsize(unsigned char *buf, unsigned long 
+ *     capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ *      table, storing the results in *cyls, *hds, and *secs 
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ */
+
+int scsi_partsize(unsigned char *buf, unsigned long capacity,
+	       unsigned int *cyls, unsigned int *hds, unsigned int *secs)
+{
+	struct partition *p = (struct partition *)buf, *largest = NULL;
+	int i, largest_cyl;
+	int cyl, ext_cyl, end_head, end_cyl, end_sector;
+	unsigned int logical_end, physical_end, ext_physical_end;
+
+
+	if (*(unsigned short *) (buf + 64) == 0xAA55) {
+		for (largest_cyl = -1, i = 0; i < 4; ++i, ++p) {
+			if (!p->sys_ind)
+				continue;
+#ifdef DEBUG
+			printk("scsicam_bios_param : partition %d has system \n",
+			       i);
+#endif
+			cyl = p->cyl + ((p->sector & 0xc0) << 2);
+			if (cyl > largest_cyl) {
+				largest_cyl = cyl;
+				largest = p;
+			}
+		}
+	}
+	if (largest) {
+		end_cyl = largest->end_cyl + ((largest->end_sector & 0xc0) << 2);
+		end_head = largest->end_head;
+		end_sector = largest->end_sector & 0x3f;
+
+		if (end_head + 1 == 0 || end_sector == 0)
+			return -1;
+
+#ifdef DEBUG
+		printk("scsicam_bios_param : end at h = %d, c = %d, s = %d\n",
+		       end_head, end_cyl, end_sector);
+#endif
+
+		physical_end = end_cyl * (end_head + 1) * end_sector +
+		    end_head * end_sector + end_sector;
+
+		/* This is the actual _sector_ number at the end */
+		logical_end = get_unaligned(&largest->start_sect)
+		    + get_unaligned(&largest->nr_sects);
+
+		/* This is for >1023 cylinders */
+		ext_cyl = (logical_end - (end_head * end_sector + end_sector))
+		    / (end_head + 1) / end_sector;
+		ext_physical_end = ext_cyl * (end_head + 1) * end_sector +
+		    end_head * end_sector + end_sector;
+
+#ifdef DEBUG
+		printk("scsicam_bios_param : logical_end=%d physical_end=%d ext_physical_end=%d ext_cyl=%d\n"
+		  ,logical_end, physical_end, ext_physical_end, ext_cyl);
+#endif
+
+		if ((logical_end == physical_end) ||
+		  (end_cyl == 1023 && ext_physical_end == logical_end)) {
+			*secs = end_sector;
+			*hds = end_head + 1;
+			*cyls = capacity / ((end_head + 1) * end_sector);
+			return 0;
+		}
+#ifdef DEBUG
+		printk("scsicam_bios_param : logical (%u) != physical (%u)\n",
+		       logical_end, physical_end);
+#endif
+	}
+	return -1;
+}
+EXPORT_SYMBOL(scsi_partsize);
+
+/*
+ * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
+ *      unsigned int *hds, unsigned int *secs);
+ *
+ * Purpose : to determine a near-optimal int 0x13 mapping for a
+ *      SCSI disk in terms of lost space of size capacity, storing
+ *      the results in *cyls, *hds, and *secs.
+ *
+ * Returns : -1 on failure, 0 on success.
+ *
+ * Extracted from
+ *
+ * WORKING                                                    X3T9.2
+ * DRAFT                                                        792D
+ *
+ *
+ *                                                        Revision 6
+ *                                                         10-MAR-94
+ * Information technology -
+ * SCSI-2 Common access method
+ * transport and SCSI interface module
+ * 
+ * ANNEX A :
+ *
+ * setsize() converts a read capacity value to int 13h
+ * head-cylinder-sector requirements. It minimizes the value for
+ * number of heads and maximizes the number of cylinders. This
+ * will support rather large disks before the number of heads
+ * will not fit in 4 bits (or 6 bits). This algorithm also
+ * minimizes the number of sectors that will be unused at the end
+ * of the disk while allowing for very large disks to be
+ * accommodated. This algorithm does not use physical geometry. 
+ */
+
+static int setsize(unsigned long capacity, unsigned int *cyls, unsigned int *hds,
+		   unsigned int *secs)
+{
+	unsigned int rv = 0;
+	unsigned long heads, sectors, cylinders, temp;
+
+	cylinders = 1024L;	/* Set number of cylinders to max */
+	sectors = 62L;		/* Maximize sectors per track */
+
+	temp = cylinders * sectors;	/* Compute divisor for heads */
+	heads = capacity / temp;	/* Compute value for number of heads */
+	if (capacity % temp) {	/* If no remainder, done! */
+		heads++;	/* Else, increment number of heads */
+		temp = cylinders * heads;	/* Compute divisor for sectors */
+		sectors = capacity / temp;	/* Compute value for sectors per
+						   track */
+		if (capacity % temp) {	/* If no remainder, done! */
+			sectors++;	/* Else, increment number of sectors */
+			temp = heads * sectors;		/* Compute divisor for cylinders */
+			cylinders = capacity / temp;	/* Compute number of cylinders */
+		}
+	}
+	if (cylinders == 0)
+		rv = (unsigned) -1;	/* Give error if 0 cylinders */
+
+	*cyls = (unsigned int) cylinders;	/* Stuff return values */
+	*secs = (unsigned int) sectors;
+	*hds = (unsigned int) heads;
+	return (rv);
+}
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
new file mode 100644
index 0000000..19afb25
--- /dev/null
+++ b/drivers/scsi/sd.c
@@ -0,0 +1,1740 @@
+/*
+ *      sd.c Copyright (C) 1992 Drew Eckhardt
+ *           Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
+ *
+ *      Linux scsi disk driver
+ *              Initial versions: Drew Eckhardt
+ *              Subsequent revisions: Eric Youngdale
+ *	Modification history:
+ *       - Drew Eckhardt <drew@colorado.edu> original
+ *       - Eric Youngdale <eric@andante.org> add scatter-gather, multiple 
+ *         outstanding request, and other enhancements.
+ *         Support loadable low-level scsi drivers.
+ *       - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using 
+ *         eight major numbers.
+ *       - Richard Gooch <rgooch@atnf.csiro.au> support devfs.
+ *	 - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in 
+ *	   sd_init and cleanups.
+ *	 - Alex Davis <letmein@erols.com> Fix problem where partition info
+ *	   not being read in sd_open. Fix problem where removable media 
+ *	   could be ejected after sd_open.
+ *	 - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5.x
+ *	 - Badari Pulavarty <pbadari@us.ibm.com>, Matthew Wilcox 
+ *	   <willy@debian.org>, Kurt Garloff <garloff@suse.de>: 
+ *	   Support 32k/1M disks.
+ *
+ *	Logging policy (needs CONFIG_SCSI_LOGGING defined):
+ *	 - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
+ *	 - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1
+ *	 - entering sd_ioctl: SCSI_LOG_IOCTL level 1
+ *	 - entering other commands: SCSI_LOG_HLQUEUE level 3
+ *	Note: when the logging level is set by the user, it must be greater
+ *	than the level indicated above to trigger output.	
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/kref.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+#include <scsi/scsicam.h>
+
+#include "scsi_logging.h"
+
+/*
+ * More than enough for everybody ;)  The huge number of majors
+ * is a leftover from 16bit dev_t days, we don't really need that
+ * much numberspace.
+ */
+#define SD_MAJORS	16
+
+/*
+ * This is limited by the naming scheme enforced in sd_probe,
+ * add another character to it if you really need more disks.
+ */
+#define SD_MAX_DISKS	(((26 * 26) + 26 + 1) * 26)
+
+/*
+ * Time out in seconds for disks and Magneto-opticals (which are slower).
+ */
+#define SD_TIMEOUT		(30 * HZ)
+#define SD_MOD_TIMEOUT		(75 * HZ)
+
+/*
+ * Number of allowed retries
+ */
+#define SD_MAX_RETRIES		5
+#define SD_PASSTHROUGH_RETRIES	1
+
+static void scsi_disk_release(struct kref *kref);
+
+struct scsi_disk {
+	struct scsi_driver *driver;	/* always &sd_template */
+	struct scsi_device *device;
+	struct kref	kref;
+	struct gendisk	*disk;
+	unsigned int	openers;	/* protected by BKL for now, yuck */
+	sector_t	capacity;	/* size in 512-byte sectors */
+	u32		index;
+	u8		media_present;
+	u8		write_prot;
+	unsigned	WCE : 1;	/* state of disk WCE bit */
+	unsigned	RCD : 1;	/* state of disk RCD bit, unused */
+};
+
+static DEFINE_IDR(sd_index_idr);
+static DEFINE_SPINLOCK(sd_index_lock);
+
+/* This semaphore is used to mediate the 0->1 reference get in the
+ * face of object destruction (i.e. we can't allow a get on an
+ * object after last put) */
+static DECLARE_MUTEX(sd_ref_sem);
+
+static int sd_revalidate_disk(struct gendisk *disk);
+static void sd_rw_intr(struct scsi_cmnd * SCpnt);
+
+static int sd_probe(struct device *);
+static int sd_remove(struct device *);
+static void sd_shutdown(struct device *dev);
+static void sd_rescan(struct device *);
+static int sd_init_command(struct scsi_cmnd *);
+static int sd_issue_flush(struct device *, sector_t *);
+static void sd_end_flush(request_queue_t *, struct request *);
+static int sd_prepare_flush(request_queue_t *, struct request *);
+static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
+		 struct scsi_request *SRpnt, unsigned char *buffer);
+
+static struct scsi_driver sd_template = {
+	.owner			= THIS_MODULE,
+	.gendrv = {
+		.name		= "sd",
+		.probe		= sd_probe,
+		.remove		= sd_remove,
+		.shutdown	= sd_shutdown,
+	},
+	.rescan			= sd_rescan,
+	.init_command		= sd_init_command,
+	.issue_flush		= sd_issue_flush,
+	.prepare_flush		= sd_prepare_flush,
+	.end_flush		= sd_end_flush,
+};
+
+/*
+ * Device no to disk mapping:
+ * 
+ *       major         disc2     disc  p1
+ *   |............|.............|....|....| <- dev_t
+ *    31        20 19          8 7  4 3  0
+ * 
+ * Inside a major, we have 16k disks, however mapped non-
+ * contiguously. The first 16 disks are for major0, the next
+ * ones with major1, ... Disk 256 is for major0 again, disk 272 
+ * for major1, ... 
+ * As we stay compatible with our numbering scheme, we can reuse 
+ * the well-know SCSI majors 8, 65--71, 136--143.
+ */
+static int sd_major(int major_idx)
+{
+	switch (major_idx) {
+	case 0:
+		return SCSI_DISK0_MAJOR;
+	case 1 ... 7:
+		return SCSI_DISK1_MAJOR + major_idx - 1;
+	case 8 ... 15:
+		return SCSI_DISK8_MAJOR + major_idx - 8;
+	default:
+		BUG();
+		return 0;	/* shut up gcc */
+	}
+}
+
+#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref)
+
+static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
+{
+	return container_of(disk->private_data, struct scsi_disk, driver);
+}
+
+static struct scsi_disk *scsi_disk_get(struct gendisk *disk)
+{
+	struct scsi_disk *sdkp = NULL;
+
+	down(&sd_ref_sem);
+	if (disk->private_data == NULL)
+		goto out;
+	sdkp = scsi_disk(disk);
+	kref_get(&sdkp->kref);
+	if (scsi_device_get(sdkp->device))
+		goto out_put;
+	up(&sd_ref_sem);
+	return sdkp;
+
+ out_put:
+	kref_put(&sdkp->kref, scsi_disk_release);
+	sdkp = NULL;
+ out:
+	up(&sd_ref_sem);
+	return sdkp;
+}
+
+static void scsi_disk_put(struct scsi_disk *sdkp)
+{
+	struct scsi_device *sdev = sdkp->device;
+
+	down(&sd_ref_sem);
+	kref_put(&sdkp->kref, scsi_disk_release);
+	scsi_device_put(sdev);
+	up(&sd_ref_sem);
+}
+
+/**
+ *	sd_init_command - build a scsi (read or write) command from
+ *	information in the request structure.
+ *	@SCpnt: pointer to mid-level's per scsi command structure that
+ *	contains request and into which the scsi command is written
+ *
+ *	Returns 1 if successful and 0 if error (or cannot be done now).
+ **/
+static int sd_init_command(struct scsi_cmnd * SCpnt)
+{
+	unsigned int this_count, timeout;
+	struct gendisk *disk;
+	sector_t block;
+	struct scsi_device *sdp = SCpnt->device;
+	struct request *rq = SCpnt->request;
+
+	timeout = sdp->timeout;
+
+	/*
+	 * SG_IO from block layer already setup, just copy cdb basically
+	 */
+	if (blk_pc_request(rq)) {
+		if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
+			return 0;
+
+		memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+		if (rq_data_dir(rq) == WRITE)
+			SCpnt->sc_data_direction = DMA_TO_DEVICE;
+		else if (rq->data_len)
+			SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+		else
+			SCpnt->sc_data_direction = DMA_NONE;
+
+		this_count = rq->data_len;
+		if (rq->timeout)
+			timeout = rq->timeout;
+
+		SCpnt->transfersize = rq->data_len;
+		SCpnt->allowed = SD_PASSTHROUGH_RETRIES;
+		goto queue;
+	}
+
+	/*
+	 * we only do REQ_CMD and REQ_BLOCK_PC
+	 */
+	if (!blk_fs_request(rq))
+		return 0;
+
+	disk = rq->rq_disk;
+	block = rq->sector;
+	this_count = SCpnt->request_bufflen >> 9;
+
+	SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "
+			    "count=%d\n", disk->disk_name,
+			 (unsigned long long)block, this_count));
+
+	if (!sdp || !scsi_device_online(sdp) ||
+ 	    block + rq->nr_sectors > get_capacity(disk)) {
+		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", 
+				 rq->nr_sectors));
+		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+		return 0;
+	}
+
+	if (sdp->changed) {
+		/*
+		 * quietly refuse to do anything to a changed disc until 
+		 * the changed bit has been reset
+		 */
+		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+		return 0;
+	}
+	SCSI_LOG_HLQUEUE(2, printk("%s : block=%llu\n",
+				   disk->disk_name, (unsigned long long)block));
+
+	/*
+	 * If we have a 1K hardware sectorsize, prevent access to single
+	 * 512 byte sectors.  In theory we could handle this - in fact
+	 * the scsi cdrom driver must be able to handle this because
+	 * we typically use 1K blocksizes, and cdroms typically have
+	 * 2K hardware sectorsizes.  Of course, things are simpler
+	 * with the cdrom, since it is read-only.  For performance
+	 * reasons, the filesystems should be able to handle this
+	 * and not force the scsi disk driver to use bounce buffers
+	 * for this.
+	 */
+	if (sdp->sector_size == 1024) {
+		if ((block & 1) || (rq->nr_sectors & 1)) {
+			printk(KERN_ERR "sd: Bad block number requested");
+			return 0;
+		} else {
+			block = block >> 1;
+			this_count = this_count >> 1;
+		}
+	}
+	if (sdp->sector_size == 2048) {
+		if ((block & 3) || (rq->nr_sectors & 3)) {
+			printk(KERN_ERR "sd: Bad block number requested");
+			return 0;
+		} else {
+			block = block >> 2;
+			this_count = this_count >> 2;
+		}
+	}
+	if (sdp->sector_size == 4096) {
+		if ((block & 7) || (rq->nr_sectors & 7)) {
+			printk(KERN_ERR "sd: Bad block number requested");
+			return 0;
+		} else {
+			block = block >> 3;
+			this_count = this_count >> 3;
+		}
+	}
+	if (rq_data_dir(rq) == WRITE) {
+		if (!sdp->writeable) {
+			return 0;
+		}
+		SCpnt->cmnd[0] = WRITE_6;
+		SCpnt->sc_data_direction = DMA_TO_DEVICE;
+	} else if (rq_data_dir(rq) == READ) {
+		SCpnt->cmnd[0] = READ_6;
+		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+	} else {
+		printk(KERN_ERR "sd: Unknown command %lx\n", rq->flags);
+/* overkill 	panic("Unknown sd command %lx\n", rq->flags); */
+		return 0;
+	}
+
+	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", 
+		disk->disk_name, (rq_data_dir(rq) == WRITE) ? 
+		"writing" : "reading", this_count, rq->nr_sectors));
+
+	SCpnt->cmnd[1] = 0;
+	
+	if (block > 0xffffffff) {
+		SCpnt->cmnd[0] += READ_16 - READ_6;
+		SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
+		SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
+		SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;
+		SCpnt->cmnd[5] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;
+		SCpnt->cmnd[6] = (unsigned char) (block >> 24) & 0xff;
+		SCpnt->cmnd[7] = (unsigned char) (block >> 16) & 0xff;
+		SCpnt->cmnd[8] = (unsigned char) (block >> 8) & 0xff;
+		SCpnt->cmnd[9] = (unsigned char) block & 0xff;
+		SCpnt->cmnd[10] = (unsigned char) (this_count >> 24) & 0xff;
+		SCpnt->cmnd[11] = (unsigned char) (this_count >> 16) & 0xff;
+		SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff;
+		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;
+		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;
+	} else if ((this_count > 0xff) || (block > 0x1fffff) ||
+		   SCpnt->device->use_10_for_rw) {
+		if (this_count > 0xffff)
+			this_count = 0xffff;
+
+		SCpnt->cmnd[0] += READ_10 - READ_6;
+		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+		SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+		SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
+		SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+		SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+	} else {
+		if (this_count > 0xff)
+			this_count = 0xff;
+
+		SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+		SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);
+		SCpnt->cmnd[3] = (unsigned char) block & 0xff;
+		SCpnt->cmnd[4] = (unsigned char) this_count;
+		SCpnt->cmnd[5] = 0;
+	}
+	SCpnt->request_bufflen = SCpnt->bufflen =
+			this_count * sdp->sector_size;
+
+	/*
+	 * We shouldn't disconnect in the middle of a sector, so with a dumb
+	 * host adapter, it's safe to assume that we can at least transfer
+	 * this many bytes between each connect / disconnect.
+	 */
+	SCpnt->transfersize = sdp->sector_size;
+	SCpnt->underflow = this_count << 9;
+	SCpnt->allowed = SD_MAX_RETRIES;
+
+queue:
+	SCpnt->timeout_per_command = timeout;
+
+	/*
+	 * This is the completion routine we use.  This is matched in terms
+	 * of capability to this function.
+	 */
+	SCpnt->done = sd_rw_intr;
+
+	/*
+	 * This indicates that the command is ready from our end to be
+	 * queued.
+	 */
+	return 1;
+}
+
+/**
+ *	sd_open - open a scsi disk device
+ *	@inode: only i_rdev member may be used
+ *	@filp: only f_mode and f_flags may be used
+ *
+ *	Returns 0 if successful. Returns a negated errno value in case 
+ *	of error.
+ *
+ *	Note: This can be called from a user context (e.g. fsck(1) )
+ *	or from within the kernel (e.g. as a result of a mount(1) ).
+ *	In the latter case @inode and @filp carry an abridged amount
+ *	of information as noted above.
+ **/
+static int sd_open(struct inode *inode, struct file *filp)
+{
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct scsi_disk *sdkp;
+	struct scsi_device *sdev;
+	int retval;
+
+	if (!(sdkp = scsi_disk_get(disk)))
+		return -ENXIO;
+
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));
+
+	sdev = sdkp->device;
+
+	/*
+	 * If the device is in error recovery, wait until it is done.
+	 * If the device is offline, then disallow any access to it.
+	 */
+	retval = -ENXIO;
+	if (!scsi_block_when_processing_errors(sdev))
+		goto error_out;
+
+	if (sdev->removable || sdkp->write_prot)
+		check_disk_change(inode->i_bdev);
+
+	/*
+	 * If the drive is empty, just let the open fail.
+	 */
+	retval = -ENOMEDIUM;
+	if (sdev->removable && !sdkp->media_present &&
+	    !(filp->f_flags & O_NDELAY))
+		goto error_out;
+
+	/*
+	 * If the device has the write protect tab set, have the open fail
+	 * if the user expects to be able to write to the thing.
+	 */
+	retval = -EROFS;
+	if (sdkp->write_prot && (filp->f_mode & FMODE_WRITE))
+		goto error_out;
+
+	/*
+	 * It is possible that the disk changing stuff resulted in
+	 * the device being taken offline.  If this is the case,
+	 * report this to the user, and don't pretend that the
+	 * open actually succeeded.
+	 */
+	retval = -ENXIO;
+	if (!scsi_device_online(sdev))
+		goto error_out;
+
+	if (!sdkp->openers++ && sdev->removable) {
+		if (scsi_block_when_processing_errors(sdev))
+			scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);
+	}
+
+	return 0;
+
+error_out:
+	scsi_disk_put(sdkp);
+	return retval;	
+}
+
+/**
+ *	sd_release - invoked when the (last) close(2) is called on this
+ *	scsi disk.
+ *	@inode: only i_rdev member may be used
+ *	@filp: only f_mode and f_flags may be used
+ *
+ *	Returns 0. 
+ *
+ *	Note: may block (uninterruptible) if error recovery is underway
+ *	on this disk.
+ **/
+static int sd_release(struct inode *inode, struct file *filp)
+{
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct scsi_device *sdev = sdkp->device;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));
+
+	if (!--sdkp->openers && sdev->removable) {
+		if (scsi_block_when_processing_errors(sdev))
+			scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);
+	}
+
+	/*
+	 * XXX and what if there are packets in flight and this close()
+	 * XXX is followed by a "rmmod sd_mod"?
+	 */
+	scsi_disk_put(sdkp);
+	return 0;
+}
+
+static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc)
+{
+	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);
+	struct scsi_device *sdp = sdkp->device;
+	struct Scsi_Host *host = sdp->host;
+	int diskinfo[4];
+
+	/* default to most commonly used values */
+        diskinfo[0] = 0x40;	/* 1 << 6 */
+       	diskinfo[1] = 0x20;	/* 1 << 5 */
+       	diskinfo[2] = sdkp->capacity >> 11;
+	
+	/* override with calculated, extended default, or driver values */
+	if (host->hostt->bios_param)
+		host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);
+	else
+		scsicam_bios_param(bdev, sdkp->capacity, diskinfo);
+
+	if (put_user(diskinfo[0], &loc->heads))
+		return -EFAULT;
+	if (put_user(diskinfo[1], &loc->sectors))
+		return -EFAULT;
+	if (put_user(diskinfo[2], &loc->cylinders))
+		return -EFAULT;
+	if (put_user((unsigned)get_start_sect(bdev),
+	             (unsigned long __user *)&loc->start))
+		return -EFAULT;
+	return 0;
+}
+
+/**
+ *	sd_ioctl - process an ioctl
+ *	@inode: only i_rdev/i_bdev members may be used
+ *	@filp: only f_mode and f_flags may be used
+ *	@cmd: ioctl command number
+ *	@arg: this is third argument given to ioctl(2) system call.
+ *	Often contains a pointer.
+ *
+ *	Returns 0 if successful (some ioctls return postive numbers on
+ *	success as well). Returns a negated errno value in case of error.
+ *
+ *	Note: most ioctls are forward onto the block subsystem or further
+ *	down in the scsi subsytem.
+ **/
+static int sd_ioctl(struct inode * inode, struct file * filp, 
+		    unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = inode->i_bdev;
+	struct gendisk *disk = bdev->bd_disk;
+	struct scsi_device *sdp = scsi_disk(disk)->device;
+	void __user *p = (void __user *)arg;
+	int error;
+    
+	SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n",
+						disk->disk_name, cmd));
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);
+	if (!scsi_block_when_processing_errors(sdp) || !error)
+		return error;
+
+	if (cmd == HDIO_GETGEO) {
+		if (!arg)
+			return -EINVAL;
+		return sd_hdio_getgeo(bdev, p);
+	}
+
+	/*
+	 * Send SCSI addressing ioctls directly to mid level, send other
+	 * ioctls to block level and then onto mid level if they can't be
+	 * resolved.
+	 */
+	switch (cmd) {
+		case SCSI_IOCTL_GET_IDLUN:
+		case SCSI_IOCTL_GET_BUS_NUMBER:
+			return scsi_ioctl(sdp, cmd, p);
+		default:
+			error = scsi_cmd_ioctl(filp, disk, cmd, p);
+			if (error != -ENOTTY)
+				return error;
+	}
+	return scsi_ioctl(sdp, cmd, p);
+}
+
+static void set_media_not_present(struct scsi_disk *sdkp)
+{
+	sdkp->media_present = 0;
+	sdkp->capacity = 0;
+	sdkp->device->changed = 1;
+}
+
+/**
+ *	sd_media_changed - check if our medium changed
+ *	@disk: kernel device descriptor 
+ *
+ *	Returns 0 if not applicable or no change; 1 if change
+ *
+ *	Note: this function is invoked from the block subsystem.
+ **/
+static int sd_media_changed(struct gendisk *disk)
+{
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct scsi_device *sdp = sdkp->device;
+	int retval;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_media_changed: disk=%s\n",
+						disk->disk_name));
+
+	if (!sdp->removable)
+		return 0;
+
+	/*
+	 * If the device is offline, don't send any commands - just pretend as
+	 * if the command failed.  If the device ever comes back online, we
+	 * can deal with it then.  It is only because of unrecoverable errors
+	 * that we would ever take a device offline in the first place.
+	 */
+	if (!scsi_device_online(sdp))
+		goto not_present;
+
+	/*
+	 * Using TEST_UNIT_READY enables differentiation between drive with
+	 * no cartridge loaded - NOT READY, drive with changed cartridge -
+	 * UNIT ATTENTION, or with same cartridge - GOOD STATUS.
+	 *
+	 * Drives that auto spin down. eg iomega jaz 1G, will be started
+	 * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever
+	 * sd_revalidate() is called.
+	 */
+	retval = -ENODEV;
+	if (scsi_block_when_processing_errors(sdp))
+		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);
+
+	/*
+	 * Unable to test, unit probably not ready.   This usually
+	 * means there is no disc in the drive.  Mark as changed,
+	 * and we will figure it out later once the drive is
+	 * available again.
+	 */
+	if (retval)
+		 goto not_present;
+
+	/*
+	 * For removable scsi disk we have to recognise the presence
+	 * of a disk in the drive. This is kept in the struct scsi_disk
+	 * struct and tested at open !  Daniel Roche (dan@lectra.fr)
+	 */
+	sdkp->media_present = 1;
+
+	retval = sdp->changed;
+	sdp->changed = 0;
+
+	return retval;
+
+not_present:
+	set_media_not_present(sdkp);
+	return 1;
+}
+
+static int sd_sync_cache(struct scsi_device *sdp)
+{
+	struct scsi_request *sreq;
+	int retries, res;
+
+	if (!scsi_device_online(sdp))
+		return -ENODEV;
+
+	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
+	if (!sreq) {
+		printk("FAILED\n  No memory for request\n");
+		return -ENOMEM;
+	}
+
+	sreq->sr_data_direction = DMA_NONE;
+	for (retries = 3; retries > 0; --retries) {
+		unsigned char cmd[10] = { 0 };
+
+		cmd[0] = SYNCHRONIZE_CACHE;
+		/*
+		 * Leave the rest of the command zero to indicate
+		 * flush everything.
+		 */
+		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);
+		if (sreq->sr_result == 0)
+			break;
+	}
+
+	res = sreq->sr_result;
+	if (res) {
+		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "
+				    "host = %d, driver = %02x\n  ",
+				    status_byte(res), msg_byte(res),
+				    host_byte(res), driver_byte(res));
+			if (driver_byte(res) & DRIVER_SENSE)
+				scsi_print_req_sense("sd", sreq);
+	}
+
+	scsi_release_request(sreq);
+	return res;
+}
+
+static int sd_issue_flush(struct device *dev, sector_t *error_sector)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+	if (!sdkp)
+               return -ENODEV;
+
+	if (!sdkp->WCE)
+		return 0;
+
+	return sd_sync_cache(sdp);
+}
+
+static void sd_end_flush(request_queue_t *q, struct request *flush_rq)
+{
+	struct request *rq = flush_rq->end_io_data;
+	struct scsi_cmnd *cmd = rq->special;
+	unsigned int bytes = rq->hard_nr_sectors << 9;
+
+	if (!flush_rq->errors) {
+		spin_unlock(q->queue_lock);
+		scsi_io_completion(cmd, bytes, 0);
+		spin_lock(q->queue_lock);
+	} else if (blk_barrier_postflush(rq)) {
+		spin_unlock(q->queue_lock);
+		scsi_io_completion(cmd, 0, bytes);
+		spin_lock(q->queue_lock);
+	} else {
+		/*
+		 * force journal abort of barriers
+		 */
+		end_that_request_first(rq, -EOPNOTSUPP, rq->hard_nr_sectors);
+		end_that_request_last(rq);
+	}
+}
+
+static int sd_prepare_flush(request_queue_t *q, struct request *rq)
+{
+	struct scsi_device *sdev = q->queuedata;
+	struct scsi_disk *sdkp = dev_get_drvdata(&sdev->sdev_gendev);
+
+	if (sdkp->WCE) {
+		memset(rq->cmd, 0, sizeof(rq->cmd));
+		rq->flags |= REQ_BLOCK_PC | REQ_SOFTBARRIER;
+		rq->timeout = SD_TIMEOUT;
+		rq->cmd[0] = SYNCHRONIZE_CACHE;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void sd_rescan(struct device *dev)
+{
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+	sd_revalidate_disk(sdkp->disk);
+}
+
+
+#ifdef CONFIG_COMPAT
+/* 
+ * This gets directly called from VFS. When the ioctl 
+ * is not recognized we go back to the other translation paths. 
+ */
+static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct block_device *bdev = file->f_dentry->d_inode->i_bdev;
+	struct gendisk *disk = bdev->bd_disk;
+	struct scsi_device *sdev = scsi_disk(disk)->device;
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(sdev))
+		return -ENODEV;
+	       
+	if (sdev->host->hostt->compat_ioctl) {
+		int ret;
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+
+		return ret;
+	}
+
+	/* 
+	 * Let the static ioctl translation table take care of it.
+	 */
+	return -ENOIOCTLCMD; 
+}
+#endif
+
+static struct block_device_operations sd_fops = {
+	.owner			= THIS_MODULE,
+	.open			= sd_open,
+	.release		= sd_release,
+	.ioctl			= sd_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl		= sd_compat_ioctl,
+#endif
+	.media_changed		= sd_media_changed,
+	.revalidate_disk	= sd_revalidate_disk,
+};
+
+/**
+ *	sd_rw_intr - bottom half handler: called when the lower level
+ *	driver has completed (successfully or otherwise) a scsi command.
+ *	@SCpnt: mid-level's per command structure.
+ *
+ *	Note: potentially run from within an ISR. Must not block.
+ **/
+static void sd_rw_intr(struct scsi_cmnd * SCpnt)
+{
+	int result = SCpnt->result;
+	int this_count = SCpnt->bufflen;
+	int good_bytes = (result == 0 ? this_count : 0);
+	sector_t block_sectors = 1;
+	u64 first_err_block;
+	sector_t error_sector;
+	struct scsi_sense_hdr sshdr;
+	int sense_valid = 0;
+	int sense_deferred = 0;
+	int info_valid;
+
+	if (result) {
+		sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);
+		if (sense_valid)
+			sense_deferred = scsi_sense_is_deferred(&sshdr);
+	}
+
+#ifdef CONFIG_SCSI_LOGGING
+	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
+				SCpnt->request->rq_disk->disk_name, result));
+	if (sense_valid) {
+		SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[respc,sk,asc,"
+				"ascq]=%x,%x,%x,%x\n", sshdr.response_code,
+				sshdr.sense_key, sshdr.asc, sshdr.ascq));
+	}
+#endif
+	/*
+	   Handle MEDIUM ERRORs that indicate partial success.  Since this is a
+	   relatively rare error condition, no care is taken to avoid
+	   unnecessary additional work such as memcpy's that could be avoided.
+	 */
+
+	/* 
+	 * If SG_IO from block layer then set good_bytes to stop retries;
+	 * else if errors, check them, and if necessary prepare for
+	 * (partial) retries.
+	 */
+	if (blk_pc_request(SCpnt->request))
+		good_bytes = this_count;
+	else if (driver_byte(result) != 0 &&
+		 sense_valid && !sense_deferred) {
+		switch (sshdr.sense_key) {
+		case MEDIUM_ERROR:
+			if (!blk_fs_request(SCpnt->request))
+				break;
+			info_valid = scsi_get_sense_info_fld(
+				SCpnt->sense_buffer, SCSI_SENSE_BUFFERSIZE,
+				&first_err_block);
+			/*
+			 * May want to warn and skip if following cast results
+			 * in actual truncation (if sector_t < 64 bits)
+			 */
+			error_sector = (sector_t)first_err_block;
+			if (SCpnt->request->bio != NULL)
+				block_sectors = bio_sectors(SCpnt->request->bio);
+			switch (SCpnt->device->sector_size) {
+			case 1024:
+				error_sector <<= 1;
+				if (block_sectors < 2)
+					block_sectors = 2;
+				break;
+			case 2048:
+				error_sector <<= 2;
+				if (block_sectors < 4)
+					block_sectors = 4;
+				break;
+			case 4096:
+				error_sector <<=3;
+				if (block_sectors < 8)
+					block_sectors = 8;
+				break;
+			case 256:
+				error_sector >>= 1;
+				break;
+			default:
+				break;
+			}
+
+			error_sector &= ~(block_sectors - 1);
+			good_bytes = (error_sector - SCpnt->request->sector) << 9;
+			if (good_bytes < 0 || good_bytes >= this_count)
+				good_bytes = 0;
+			break;
+
+		case RECOVERED_ERROR: /* an error occurred, but it recovered */
+		case NO_SENSE: /* LLDD got sense data */
+			/*
+			 * Inform the user, but make sure that it's not treated
+			 * as a hard error.
+			 */
+			scsi_print_sense("sd", SCpnt);
+			SCpnt->result = 0;
+			memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+			good_bytes = this_count;
+			break;
+
+		case ILLEGAL_REQUEST:
+			if (SCpnt->device->use_10_for_rw &&
+			    (SCpnt->cmnd[0] == READ_10 ||
+			     SCpnt->cmnd[0] == WRITE_10))
+				SCpnt->device->use_10_for_rw = 0;
+			if (SCpnt->device->use_10_for_ms &&
+			    (SCpnt->cmnd[0] == MODE_SENSE_10 ||
+			     SCpnt->cmnd[0] == MODE_SELECT_10))
+				SCpnt->device->use_10_for_ms = 0;
+			break;
+
+		default:
+			break;
+		}
+	}
+	/*
+	 * This calls the generic completion function, now that we know
+	 * how many actual sectors finished, and how many sectors we need
+	 * to say have failed.
+	 */
+	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+}
+
+static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp)
+{
+	struct scsi_sense_hdr sshdr;
+
+	if (!srp->sr_result)
+		return 0;
+	if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))
+		return 0;
+	/* not invoked for commands that could return deferred errors */
+	if (scsi_request_normalize_sense(srp, &sshdr)) {
+		if (sshdr.sense_key != NOT_READY &&
+		    sshdr.sense_key != UNIT_ATTENTION)
+			return 0;
+		if (sshdr.asc != 0x3A) /* medium not present */
+			return 0;
+	}
+	set_media_not_present(sdkp);
+	return 1;
+}
+
+/*
+ * spinup disk - called only in sd_revalidate_disk()
+ */
+static void
+sd_spinup_disk(struct scsi_disk *sdkp, char *diskname,
+	       struct scsi_request *SRpnt, unsigned char *buffer) {
+	unsigned char cmd[10];
+	unsigned long spintime_value = 0;
+	int retries, spintime;
+	unsigned int the_result;
+	struct scsi_sense_hdr sshdr;
+	int sense_valid = 0;
+
+	spintime = 0;
+
+	/* Spin up drives, as required.  Only do this at boot time */
+	/* Spinup needs to be done for module loads too. */
+	do {
+		retries = 0;
+
+		do {
+			cmd[0] = TEST_UNIT_READY;
+			memset((void *) &cmd[1], 0, 9);
+
+			SRpnt->sr_cmd_len = 0;
+			memset(SRpnt->sr_sense_buffer, 0,
+			       SCSI_SENSE_BUFFERSIZE);
+			SRpnt->sr_data_direction = DMA_NONE;
+
+			scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,
+				       0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);
+
+			the_result = SRpnt->sr_result;
+			if (the_result)
+				sense_valid = scsi_request_normalize_sense(
+							SRpnt, &sshdr);
+			retries++;
+		} while (retries < 3 && 
+			 (!scsi_status_is_good(the_result) ||
+			  ((driver_byte(the_result) & DRIVER_SENSE) &&
+			  sense_valid && sshdr.sense_key == UNIT_ATTENTION)));
+
+		/*
+		 * If the drive has indicated to us that it doesn't have
+		 * any media in it, don't bother with any of the rest of
+		 * this crap.
+		 */
+		if (media_not_present(sdkp, SRpnt))
+			return;
+
+		if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
+			/* no sense, TUR either succeeded or failed
+			 * with a status error */
+			if(!spintime && !scsi_status_is_good(the_result))
+				printk(KERN_NOTICE "%s: Unit Not Ready, "
+				       "error = 0x%x\n", diskname, the_result);
+			break;
+		}
+					
+		/*
+		 * The device does not want the automatic start to be issued.
+		 */
+		if (sdkp->device->no_start_on_add) {
+			break;
+		}
+
+		/*
+		 * If manual intervention is required, or this is an
+		 * absent USB storage device, a spinup is meaningless.
+		 */
+		if (sense_valid &&
+		    sshdr.sense_key == NOT_READY &&
+		    sshdr.asc == 4 && sshdr.ascq == 3) {
+			break;		/* manual intervention required */
+
+		/*
+		 * Issue command to spin up drive when not ready
+		 */
+		} else if (sense_valid && sshdr.sense_key == NOT_READY) {
+			if (!spintime) {
+				printk(KERN_NOTICE "%s: Spinning up disk...",
+				       diskname);
+				cmd[0] = START_STOP;
+				cmd[1] = 1;	/* Return immediately */
+				memset((void *) &cmd[2], 0, 8);
+				cmd[4] = 1;	/* Start spin cycle */
+				SRpnt->sr_cmd_len = 0;
+				memset(SRpnt->sr_sense_buffer, 0,
+					SCSI_SENSE_BUFFERSIZE);
+
+				SRpnt->sr_data_direction = DMA_NONE;
+				scsi_wait_req(SRpnt, (void *)cmd, 
+					      (void *) buffer, 0/*512*/, 
+					      SD_TIMEOUT, SD_MAX_RETRIES);
+				spintime_value = jiffies;
+			}
+			spintime = 1;
+			/* Wait 1 second for next try */
+			msleep(1000);
+			printk(".");
+		} else {
+			/* we don't understand the sense code, so it's
+			 * probably pointless to loop */
+			if(!spintime) {
+				printk(KERN_NOTICE "%s: Unit Not Ready, "
+					"sense:\n", diskname);
+				scsi_print_req_sense("", SRpnt);
+			}
+			break;
+		}
+				
+	} while (spintime &&
+		 time_after(spintime_value + 100 * HZ, jiffies));
+
+	if (spintime) {
+		if (scsi_status_is_good(the_result))
+			printk("ready\n");
+		else
+			printk("not responding...\n");
+	}
+}
+
+/*
+ * read disk capacity
+ */
+static void
+sd_read_capacity(struct scsi_disk *sdkp, char *diskname,
+		 struct scsi_request *SRpnt, unsigned char *buffer) {
+	unsigned char cmd[16];
+	struct scsi_device *sdp = sdkp->device;
+	int the_result, retries;
+	int sector_size = 0;
+	int longrc = 0;
+	struct scsi_sense_hdr sshdr;
+	int sense_valid = 0;
+
+repeat:
+	retries = 3;
+	do {
+		if (longrc) {
+			memset((void *) cmd, 0, 16);
+			cmd[0] = SERVICE_ACTION_IN;
+			cmd[1] = SAI_READ_CAPACITY_16;
+			cmd[13] = 12;
+			memset((void *) buffer, 0, 12);
+		} else {
+			cmd[0] = READ_CAPACITY;
+			memset((void *) &cmd[1], 0, 9);
+			memset((void *) buffer, 0, 8);
+		}
+		
+		SRpnt->sr_cmd_len = 0;
+		memset(SRpnt->sr_sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
+		SRpnt->sr_data_direction = DMA_FROM_DEVICE;
+
+		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
+			      longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES);
+
+		if (media_not_present(sdkp, SRpnt))
+			return;
+
+		the_result = SRpnt->sr_result;
+		if (the_result)
+			sense_valid = scsi_request_normalize_sense(SRpnt,
+								   &sshdr);
+		retries--;
+
+	} while (the_result && retries);
+
+	if (the_result && !longrc) {
+		printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"
+		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
+		       diskname, diskname,
+		       status_byte(the_result),
+		       msg_byte(the_result),
+		       host_byte(the_result),
+		       driver_byte(the_result));
+
+		if (driver_byte(the_result) & DRIVER_SENSE)
+			scsi_print_req_sense("sd", SRpnt);
+		else
+			printk("%s : sense not available. \n", diskname);
+
+		/* Set dirty bit for removable devices if not ready -
+		 * sometimes drives will not report this properly. */
+		if (sdp->removable &&
+		    sense_valid && sshdr.sense_key == NOT_READY)
+			sdp->changed = 1;
+
+		/* Either no media are present but the drive didn't tell us,
+		   or they are present but the read capacity command fails */
+		/* sdkp->media_present = 0; -- not always correct */
+		sdkp->capacity = 0x200000; /* 1 GB - random */
+
+		return;
+	} else if (the_result && longrc) {
+		/* READ CAPACITY(16) has been failed */
+		printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n"
+		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",
+		       diskname, diskname,
+		       status_byte(the_result),
+		       msg_byte(the_result),
+		       host_byte(the_result),
+		       driver_byte(the_result));
+		printk(KERN_NOTICE "%s : use 0xffffffff as device size\n",
+		       diskname);
+		
+		sdkp->capacity = 1 + (sector_t) 0xffffffff;		
+		goto got_data;
+	}	
+	
+	if (!longrc) {
+		sector_size = (buffer[4] << 24) |
+			(buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+		if (buffer[0] == 0xff && buffer[1] == 0xff &&
+		    buffer[2] == 0xff && buffer[3] == 0xff) {
+			if(sizeof(sdkp->capacity) > 4) {
+				printk(KERN_NOTICE "%s : very big device. try to use"
+				       " READ CAPACITY(16).\n", diskname);
+				longrc = 1;
+				goto repeat;
+			}
+			printk(KERN_ERR "%s: too big for this kernel.  Use a "
+			       "kernel compiled with support for large block "
+			       "devices.\n", diskname);
+			sdkp->capacity = 0;
+			goto got_data;
+		}
+		sdkp->capacity = 1 + (((sector_t)buffer[0] << 24) |
+			(buffer[1] << 16) |
+			(buffer[2] << 8) |
+			buffer[3]);			
+	} else {
+		sdkp->capacity = 1 + (((u64)buffer[0] << 56) |
+			((u64)buffer[1] << 48) |
+			((u64)buffer[2] << 40) |
+			((u64)buffer[3] << 32) |
+			((sector_t)buffer[4] << 24) |
+			((sector_t)buffer[5] << 16) |
+			((sector_t)buffer[6] << 8)  |
+			(sector_t)buffer[7]);
+			
+		sector_size = (buffer[8] << 24) |
+			(buffer[9] << 16) | (buffer[10] << 8) | buffer[11];
+	}	
+
+	/* Some devices return the total number of sectors, not the
+	 * highest sector number.  Make the necessary adjustment. */
+	if (sdp->fix_capacity)
+		--sdkp->capacity;
+
+got_data:
+	if (sector_size == 0) {
+		sector_size = 512;
+		printk(KERN_NOTICE "%s : sector size 0 reported, "
+		       "assuming 512.\n", diskname);
+	}
+
+	if (sector_size != 512 &&
+	    sector_size != 1024 &&
+	    sector_size != 2048 &&
+	    sector_size != 4096 &&
+	    sector_size != 256) {
+		printk(KERN_NOTICE "%s : unsupported sector size "
+		       "%d.\n", diskname, sector_size);
+		/*
+		 * The user might want to re-format the drive with
+		 * a supported sectorsize.  Once this happens, it
+		 * would be relatively trivial to set the thing up.
+		 * For this reason, we leave the thing in the table.
+		 */
+		sdkp->capacity = 0;
+		/*
+		 * set a bogus sector size so the normal read/write
+		 * logic in the block layer will eventually refuse any
+		 * request on this device without tripping over power
+		 * of two sector size assumptions
+		 */
+		sector_size = 512;
+	}
+	{
+		/*
+		 * The msdos fs needs to know the hardware sector size
+		 * So I have created this table. See ll_rw_blk.c
+		 * Jacques Gelinas (Jacques@solucorp.qc.ca)
+		 */
+		int hard_sector = sector_size;
+		sector_t sz = sdkp->capacity * (hard_sector/256);
+		request_queue_t *queue = sdp->request_queue;
+		sector_t mb;
+
+		blk_queue_hardsect_size(queue, hard_sector);
+		/* avoid 64-bit division on 32-bit platforms */
+		mb = sz >> 1;
+		sector_div(sz, 1250);
+		mb -= sz - 974;
+		sector_div(mb, 1950);
+
+		printk(KERN_NOTICE "SCSI device %s: "
+		       "%llu %d-byte hdwr sectors (%llu MB)\n",
+		       diskname, (unsigned long long)sdkp->capacity,
+		       hard_sector, (unsigned long long)mb);
+	}
+
+	/* Rescale capacity to 512-byte units */
+	if (sector_size == 4096)
+		sdkp->capacity <<= 3;
+	else if (sector_size == 2048)
+		sdkp->capacity <<= 2;
+	else if (sector_size == 1024)
+		sdkp->capacity <<= 1;
+	else if (sector_size == 256)
+		sdkp->capacity >>= 1;
+
+	sdkp->device->sector_size = sector_size;
+}
+
+/* called with buffer of length 512 */
+static inline int
+sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage,
+		 unsigned char *buffer, int len, struct scsi_mode_data *data)
+{
+	return __scsi_mode_sense(SRpnt, dbd, modepage, buffer, len,
+				 SD_TIMEOUT, SD_MAX_RETRIES, data);
+}
+
+/*
+ * read write protect setting, if possible - called only in sd_revalidate_disk()
+ * called with buffer of length 512
+ */
+static void
+sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname,
+		   struct scsi_request *SRpnt, unsigned char *buffer) {
+	int res;
+	struct scsi_mode_data data;
+
+	set_disk_ro(sdkp->disk, 0);
+	if (sdkp->device->skip_ms_page_3f) {
+		printk(KERN_NOTICE "%s: assuming Write Enabled\n", diskname);
+		return;
+	}
+
+	if (sdkp->device->use_192_bytes_for_3f) {
+		res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 192, &data);
+	} else {
+		/*
+		 * First attempt: ask for all pages (0x3F), but only 4 bytes.
+		 * We have to start carefully: some devices hang if we ask
+		 * for more than is available.
+		 */
+		res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4, &data);
+
+		/*
+		 * Second attempt: ask for page 0 When only page 0 is
+		 * implemented, a request for page 3F may return Sense Key
+		 * 5: Illegal Request, Sense Code 24: Invalid field in
+		 * CDB.
+		 */
+		if (!scsi_status_is_good(res))
+			res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4, &data);
+
+		/*
+		 * Third attempt: ask 255 bytes, as we did earlier.
+		 */
+		if (!scsi_status_is_good(res))
+			res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255,
+					       &data);
+	}
+
+	if (!scsi_status_is_good(res)) {
+		printk(KERN_WARNING
+		       "%s: test WP failed, assume Write Enabled\n", diskname);
+	} else {
+		sdkp->write_prot = ((data.device_specific & 0x80) != 0);
+		set_disk_ro(sdkp->disk, sdkp->write_prot);
+		printk(KERN_NOTICE "%s: Write Protect is %s\n", diskname,
+		       sdkp->write_prot ? "on" : "off");
+		printk(KERN_DEBUG "%s: Mode Sense: %02x %02x %02x %02x\n",
+		       diskname, buffer[0], buffer[1], buffer[2], buffer[3]);
+	}
+}
+
+/*
+ * sd_read_cache_type - called only from sd_revalidate_disk()
+ * called with buffer of length 512
+ */
+static void
+sd_read_cache_type(struct scsi_disk *sdkp, char *diskname,
+		   struct scsi_request *SRpnt, unsigned char *buffer) {
+	int len = 0, res;
+
+	const int dbd = 0;	   /* DBD */
+	const int modepage = 0x08; /* current values, cache page */
+	struct scsi_mode_data data;
+	struct scsi_sense_hdr sshdr;
+
+	if (sdkp->device->skip_ms_page_8)
+		goto defaults;
+
+	/* cautiously ask */
+	res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4, &data);
+
+	if (!scsi_status_is_good(res))
+		goto bad_sense;
+
+	/* that went OK, now ask for the proper length */
+	len = data.length;
+
+	/*
+	 * We're only interested in the first three bytes, actually.
+	 * But the data cache page is defined for the first 20.
+	 */
+	if (len < 3)
+		goto bad_sense;
+	if (len > 20)
+		len = 20;
+
+	/* Take headers and block descriptors into account */
+	len += data.header_length + data.block_descriptor_length;
+
+	/* Get the data */
+	res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len, &data);
+
+	if (scsi_status_is_good(res)) {
+		const char *types[] = {
+			"write through", "none", "write back",
+			"write back, no read (daft)"
+		};
+		int ct = 0;
+		int offset = data.header_length +
+			data.block_descriptor_length + 2;
+
+		sdkp->WCE = ((buffer[offset] & 0x04) != 0);
+		sdkp->RCD = ((buffer[offset] & 0x01) != 0);
+
+		ct =  sdkp->RCD + 2*sdkp->WCE;
+
+		printk(KERN_NOTICE "SCSI device %s: drive cache: %s\n",
+		       diskname, types[ct]);
+
+		return;
+	}
+
+bad_sense:
+	if (scsi_request_normalize_sense(SRpnt, &sshdr) &&
+	    sshdr.sense_key == ILLEGAL_REQUEST &&
+	    sshdr.asc == 0x24 && sshdr.ascq == 0x0)
+		printk(KERN_NOTICE "%s: cache data unavailable\n",
+		       diskname);	/* Invalid field in CDB */
+	else
+		printk(KERN_ERR "%s: asking for cache data failed\n",
+		       diskname);
+
+defaults:
+	printk(KERN_ERR "%s: assuming drive cache: write through\n",
+	       diskname);
+	sdkp->WCE = 0;
+	sdkp->RCD = 0;
+}
+
+/**
+ *	sd_revalidate_disk - called the first time a new disk is seen,
+ *	performs disk spin up, read_capacity, etc.
+ *	@disk: struct gendisk we care about
+ **/
+static int sd_revalidate_disk(struct gendisk *disk)
+{
+	struct scsi_disk *sdkp = scsi_disk(disk);
+	struct scsi_device *sdp = sdkp->device;
+	struct scsi_request *sreq;
+	unsigned char *buffer;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_revalidate_disk: disk=%s\n", disk->disk_name));
+
+	/*
+	 * If the device is offline, don't try and read capacity or any
+	 * of the other niceties.
+	 */
+	if (!scsi_device_online(sdp))
+		goto out;
+
+	sreq = scsi_allocate_request(sdp, GFP_KERNEL);
+	if (!sreq) {
+		printk(KERN_WARNING "(sd_revalidate_disk:) Request allocation "
+		       "failure.\n");
+		goto out;
+	}
+
+	buffer = kmalloc(512, GFP_KERNEL | __GFP_DMA);
+	if (!buffer) {
+		printk(KERN_WARNING "(sd_revalidate_disk:) Memory allocation "
+		       "failure.\n");
+		goto out_release_request;
+	}
+
+	/* defaults, until the device tells us otherwise */
+	sdp->sector_size = 512;
+	sdkp->capacity = 0;
+	sdkp->media_present = 1;
+	sdkp->write_prot = 0;
+	sdkp->WCE = 0;
+	sdkp->RCD = 0;
+
+	sd_spinup_disk(sdkp, disk->disk_name, sreq, buffer);
+
+	/*
+	 * Without media there is no reason to ask; moreover, some devices
+	 * react badly if we do.
+	 */
+	if (sdkp->media_present) {
+		sd_read_capacity(sdkp, disk->disk_name, sreq, buffer);
+		if (sdp->removable)
+			sd_read_write_protect_flag(sdkp, disk->disk_name,
+					sreq, buffer);
+		sd_read_cache_type(sdkp, disk->disk_name, sreq, buffer);
+	}
+		
+	set_capacity(disk, sdkp->capacity);
+	kfree(buffer);
+
+ out_release_request: 
+	scsi_release_request(sreq);
+ out:
+	return 0;
+}
+
+/**
+ *	sd_probe - called during driver initialization and whenever a
+ *	new scsi device is attached to the system. It is called once
+ *	for each scsi device (not just disks) present.
+ *	@dev: pointer to device object
+ *
+ *	Returns 0 if successful (or not interested in this scsi device 
+ *	(e.g. scanner)); 1 when there is an error.
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function sets up the mapping between a given 
+ *	<host,channel,id,lun> (found in sdp) and new device name 
+ *	(e.g. /dev/sda). More precisely it is the block device major 
+ *	and minor number that is chosen here.
+ *
+ *	Assume sd_attach is not re-entrant (for time being)
+ *	Also think about sd_attach() and sd_remove() running coincidentally.
+ **/
+static int sd_probe(struct device *dev)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_disk *sdkp;
+	struct gendisk *gd;
+	u32 index;
+	int error;
+
+	error = -ENODEV;
+	if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD))
+		goto out;
+
+	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
+			 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
+
+	error = -ENOMEM;
+	sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
+	if (!sdkp)
+		goto out;
+
+	memset (sdkp, 0, sizeof(*sdkp));
+	kref_init(&sdkp->kref);
+
+	gd = alloc_disk(16);
+	if (!gd)
+		goto out_free;
+
+	if (!idr_pre_get(&sd_index_idr, GFP_KERNEL))
+		goto out_put;
+
+	spin_lock(&sd_index_lock);
+	error = idr_get_new(&sd_index_idr, NULL, &index);
+	spin_unlock(&sd_index_lock);
+
+	if (index >= SD_MAX_DISKS)
+		error = -EBUSY;
+	if (error)
+		goto out_put;
+
+	sdkp->device = sdp;
+	sdkp->driver = &sd_template;
+	sdkp->disk = gd;
+	sdkp->index = index;
+	sdkp->openers = 0;
+
+	if (!sdp->timeout) {
+		if (sdp->type == TYPE_DISK)
+			sdp->timeout = SD_TIMEOUT;
+		else
+			sdp->timeout = SD_MOD_TIMEOUT;
+	}
+
+	gd->major = sd_major((index & 0xf0) >> 4);
+	gd->first_minor = ((index & 0xf) << 4) | (index & 0xfff00);
+	gd->minors = 16;
+	gd->fops = &sd_fops;
+
+	if (index < 26) {
+		sprintf(gd->disk_name, "sd%c", 'a' + index % 26);
+	} else if (index < (26 + 1) * 26) {
+		sprintf(gd->disk_name, "sd%c%c",
+			'a' + index / 26 - 1,'a' + index % 26);
+	} else {
+		const unsigned int m1 = (index / 26 - 1) / 26 - 1;
+		const unsigned int m2 = (index / 26 - 1) % 26;
+		const unsigned int m3 =  index % 26;
+		sprintf(gd->disk_name, "sd%c%c%c",
+			'a' + m1, 'a' + m2, 'a' + m3);
+	}
+
+	strcpy(gd->devfs_name, sdp->devfs_name);
+
+	gd->private_data = &sdkp->driver;
+
+	sd_revalidate_disk(gd);
+
+	gd->driverfs_dev = &sdp->sdev_gendev;
+	gd->flags = GENHD_FL_DRIVERFS;
+	if (sdp->removable)
+		gd->flags |= GENHD_FL_REMOVABLE;
+	gd->queue = sdkp->device->request_queue;
+
+	dev_set_drvdata(dev, sdkp);
+	add_disk(gd);
+
+	printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, "
+	       "id %d, lun %d\n", sdp->removable ? "removable " : "",
+	       gd->disk_name, sdp->host->host_no, sdp->channel,
+	       sdp->id, sdp->lun);
+
+	return 0;
+
+out_put:
+	put_disk(gd);
+out_free:
+	kfree(sdkp);
+out:
+	return error;
+}
+
+/**
+ *	sd_remove - called whenever a scsi disk (previously recognized by
+ *	sd_probe) is detached from the system. It is called (potentially
+ *	multiple times) during sd module unload.
+ *	@sdp: pointer to mid level scsi device object
+ *
+ *	Note: this function is invoked from the scsi mid-level.
+ *	This function potentially frees up a device name (e.g. /dev/sdc)
+ *	that could be re-used by a subsequent sd_probe().
+ *	This function is not called when the built-in sd driver is "exit-ed".
+ **/
+static int sd_remove(struct device *dev)
+{
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+	del_gendisk(sdkp->disk);
+	sd_shutdown(dev);
+	down(&sd_ref_sem);
+	kref_put(&sdkp->kref, scsi_disk_release);
+	up(&sd_ref_sem);
+
+	return 0;
+}
+
+/**
+ *	scsi_disk_release - Called to free the scsi_disk structure
+ *	@kref: pointer to embedded kref
+ *
+ *	sd_ref_sem must be held entering this routine.  Because it is
+ *	called on last put, you should always use the scsi_disk_get()
+ *	scsi_disk_put() helpers which manipulate the semaphore directly
+ *	and never do a direct kref_put().
+ **/
+static void scsi_disk_release(struct kref *kref)
+{
+	struct scsi_disk *sdkp = to_scsi_disk(kref);
+	struct gendisk *disk = sdkp->disk;
+	
+	spin_lock(&sd_index_lock);
+	idr_remove(&sd_index_idr, sdkp->index);
+	spin_unlock(&sd_index_lock);
+
+	disk->private_data = NULL;
+
+	put_disk(disk);
+
+	kfree(sdkp);
+}
+
+/*
+ * Send a SYNCHRONIZE CACHE instruction down to the device through
+ * the normal SCSI command structure.  Wait for the command to
+ * complete.
+ */
+static void sd_shutdown(struct device *dev)
+{
+	struct scsi_device *sdp = to_scsi_device(dev);
+	struct scsi_disk *sdkp = dev_get_drvdata(dev);
+
+	if (!sdkp)
+		return;         /* this can happen */
+
+	if (!sdkp->WCE)
+		return;
+
+	printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n",
+			sdkp->disk->disk_name);
+	sd_sync_cache(sdp);
+}	
+
+/**
+ *	init_sd - entry point for this driver (both when built in or when
+ *	a module).
+ *
+ *	Note: this function registers this driver with the scsi mid-level.
+ **/
+static int __init init_sd(void)
+{
+	int majors = 0, i;
+
+	SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n"));
+
+	for (i = 0; i < SD_MAJORS; i++)
+		if (register_blkdev(sd_major(i), "sd") == 0)
+			majors++;
+
+	if (!majors)
+		return -ENODEV;
+
+	return scsi_register_driver(&sd_template.gendrv);
+}
+
+/**
+ *	exit_sd - exit point for this driver (when it is a module).
+ *
+ *	Note: this function unregisters this driver from the scsi mid-level.
+ **/
+static void __exit exit_sd(void)
+{
+	int i;
+
+	SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
+
+	scsi_unregister_driver(&sd_template.gendrv);
+	for (i = 0; i < SD_MAJORS; i++)
+		unregister_blkdev(sd_major(i), "sd");
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Eric Youngdale");
+MODULE_DESCRIPTION("SCSI disk (sd) driver");
+
+module_init(init_sd);
+module_exit(exit_sd);
diff --git a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
new file mode 100644
index 0000000..b362ff2
--- /dev/null
+++ b/drivers/scsi/seagate.c
@@ -0,0 +1,1675 @@
+/*
+ *    seagate.c Copyright (C) 1992, 1993 Drew Eckhardt
+ *      low level scsi driver for ST01/ST02, Future Domain TMC-885,
+ *      TMC-950 by Drew Eckhardt <drew@colorado.edu>
+ *
+ *      Note : TMC-880 boards don't work because they have two bits in
+ *              the status register flipped, I'll fix this "RSN"
+ *	[why do I have strong feeling that above message is from 1993? :-)
+ *	        pavel@ucw.cz]
+ *
+ *      This card does all the I/O via memory mapped I/O, so there is no need
+ *      to check or allocate a region of the I/O address space.
+ */
+
+/* 1996 - to use new read{b,w,l}, write{b,w,l}, and phys_to_virt
+ * macros, replaced assembler routines with C. There's probably a
+ * performance hit, but I only have a cdrom and can't tell. Define
+ * SEAGATE_USE_ASM if you want the old assembler code -- SJT
+ *
+ * 1998-jul-29 - created DPRINTK macros and made it work under 
+ * linux 2.1.112, simplified some #defines etc. <pavel@ucw.cz>
+ *
+ * Aug 2000 - aeb - deleted seagate_st0x_biosparam(). It would try to
+ * read the physical disk geometry, a bad mistake. Of course it doesn't
+ * matter much what geometry one invents, but on large disks it
+ * returned 256 (or more) heads, causing all kind of failures.
+ * Of course this means that people might see a different geometry now,
+ * so boot parameters may be necessary in some cases.
+ */
+
+/*
+ * Configuration :
+ * To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
+ * -DIRQ will override the default of 5.
+ * Note: You can now set these options from the kernel's "command line".
+ * The syntax is:
+ *
+ *     st0x=ADDRESS,IRQ                (for a Seagate controller)
+ * or:
+ *     tmc8xx=ADDRESS,IRQ              (for a TMC-8xx or TMC-950 controller)
+ * eg:
+ *     tmc8xx=0xC8000,15
+ *
+ * will configure the driver for a TMC-8xx style controller using IRQ 15
+ * with a base address of 0xC8000.
+ *
+ * -DARBITRATE 
+ *      Will cause the host adapter to arbitrate for the
+ *      bus for better SCSI-II compatibility, rather than just
+ *      waiting for BUS FREE and then doing its thing.  Should
+ *      let us do one command per Lun when I integrate my
+ *      reorganization changes into the distribution sources.
+ *
+ * -DDEBUG=65535
+ *      Will activate debug code.
+ *
+ * -DFAST or -DFAST32 
+ *      Will use blind transfers where possible
+ *
+ * -DPARITY  
+ *      This will enable parity.
+ *
+ * -DSEAGATE_USE_ASM
+ *      Will use older seagate assembly code. should be (very small amount)
+ *      Faster.
+ *
+ * -DSLOW_RATE=50
+ *      Will allow compatibility with broken devices that don't
+ *      handshake fast enough (ie, some CD ROM's) for the Seagate
+ *      code.
+ *
+ *      50 is some number, It will let you specify a default
+ *      transfer rate if handshaking isn't working correctly.
+ *
+ * -DOLDCNTDATASCEME  There is a new sceme to set the CONTROL
+ *                    and DATA reigsters which complies more closely
+ *                    with the SCSI2 standard. This hopefully eliminates
+ *                    the need to swap the order these registers are
+ *                    'messed' with. It makes the following two options
+ *                    obsolete. To reenable the old sceme define this.
+ *
+ * The following to options are patches from the SCSI.HOWTO
+ *
+ * -DSWAPSTAT  This will swap the definitions for STAT_MSG and STAT_CD.
+ *
+ * -DSWAPCNTDATA  This will swap the order that seagate.c messes with
+ *                the CONTROL an DATA registers.
+ */
+
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/signal.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/blkdev.h>
+#include <linux/stat.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "seagate.h"
+
+#include <scsi/scsi_ioctl.h>
+
+#ifdef DEBUG
+#define DPRINTK( when, msg... ) do { if ( (DEBUG & (when)) == (when) ) printk( msg ); } while (0)
+#else
+#define DPRINTK( when, msg... ) do { } while (0)
+#endif
+#define DANY( msg... ) DPRINTK( 0xffff, msg );
+
+#ifndef IRQ
+#define IRQ 5
+#endif
+
+#ifdef FAST32
+#define FAST
+#endif
+
+#undef LINKED			/* Linked commands are currently broken! */
+
+#if defined(OVERRIDE) && !defined(CONTROLLER)
+#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type
+#endif
+
+#ifndef __i386__
+#undef SEAGATE_USE_ASM
+#endif
+
+/*
+	Thanks to Brian Antoine for the example code in his Messy-Loss ST-01
+		driver, and Mitsugu Suzuki for information on the ST-01
+		SCSI host.
+*/
+
+/*
+	CONTROL defines
+*/
+
+#define CMD_RST 		0x01
+#define CMD_SEL 		0x02
+#define CMD_BSY 		0x04
+#define CMD_ATTN    		0x08
+#define CMD_START_ARB		0x10
+#define CMD_EN_PARITY		0x20
+#define CMD_INTR		0x40
+#define CMD_DRVR_ENABLE		0x80
+
+/*
+	STATUS
+*/
+#ifdef SWAPSTAT
+#define STAT_MSG		0x08
+#define STAT_CD			0x02
+#else
+#define STAT_MSG		0x02
+#define STAT_CD			0x08
+#endif
+
+#define STAT_BSY		0x01
+#define STAT_IO			0x04
+#define STAT_REQ		0x10
+#define STAT_SEL		0x20
+#define STAT_PARITY		0x40
+#define STAT_ARB_CMPL		0x80
+
+/* 
+	REQUESTS
+*/
+
+#define REQ_MASK (STAT_CD |  STAT_IO | STAT_MSG)
+#define REQ_DATAOUT 0
+#define REQ_DATAIN STAT_IO
+#define REQ_CMDOUT STAT_CD
+#define REQ_STATIN (STAT_CD | STAT_IO)
+#define REQ_MSGOUT (STAT_MSG | STAT_CD)
+#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO)
+
+extern volatile int seagate_st0x_timeout;
+
+#ifdef PARITY
+#define BASE_CMD CMD_EN_PARITY
+#else
+#define BASE_CMD  0
+#endif
+
+/*
+	Debugging code
+*/
+
+#define PHASE_BUS_FREE 1
+#define PHASE_ARBITRATION 2
+#define PHASE_SELECTION 4
+#define PHASE_DATAIN 8
+#define PHASE_DATAOUT 0x10
+#define PHASE_CMDOUT 0x20
+#define PHASE_MSGIN 0x40
+#define PHASE_MSGOUT 0x80
+#define PHASE_STATUSIN 0x100
+#define PHASE_ETC (PHASE_DATAIN | PHASE_DATAOUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN)
+#define PRINT_COMMAND 0x200
+#define PHASE_EXIT 0x400
+#define PHASE_RESELECT 0x800
+#define DEBUG_FAST 0x1000
+#define DEBUG_SG   0x2000
+#define DEBUG_LINKED	0x4000
+#define DEBUG_BORKEN	0x8000
+
+/* 
+ *	Control options - these are timeouts specified in .01 seconds.
+ */
+
+/* 30, 20 work */
+#define ST0X_BUS_FREE_DELAY 25
+#define ST0X_SELECTION_DELAY 25
+
+#define SEAGATE 1		/* these determine the type of the controller */
+#define FD	2
+
+#define ST0X_ID_STR	"Seagate ST-01/ST-02"
+#define FD_ID_STR	"TMC-8XX/TMC-950"
+
+static int internal_command (unsigned char target, unsigned char lun,
+			     const void *cmnd,
+			     void *buff, int bufflen, int reselect);
+
+static int incommand;		/* set if arbitration has finished
+				   and we are in some command phase. */
+
+static unsigned int base_address = 0;	/* Where the card ROM starts, used to 
+					   calculate memory mapped register
+					   location.  */
+
+static void __iomem *st0x_cr_sr;	/* control register write, status
+					   register read.  256 bytes in
+					   length.
+					   Read is status of SCSI BUS, as per 
+					   STAT masks.  */
+
+static void __iomem *st0x_dr;	/* data register, read write 256
+				   bytes in length.  */
+
+static volatile int st0x_aborted = 0;	/* set when we are aborted, ie by a
+					   time out, etc.  */
+
+static unsigned char controller_type = 0;	/* set to SEAGATE for ST0x
+						   boards or FD for TMC-8xx
+						   boards */
+static int irq = IRQ;
+
+module_param(base_address, uint, 0);
+module_param(controller_type, byte, 0);
+module_param(irq, int, 0);
+MODULE_LICENSE("GPL");
+
+
+#define retcode(result) (((result) << 16) | (message << 8) | status)
+#define STATUS ((u8) readb(st0x_cr_sr))
+#define DATA ((u8) readb(st0x_dr))
+#define WRITE_CONTROL(d) { writeb((d), st0x_cr_sr); }
+#define WRITE_DATA(d) { writeb((d), st0x_dr); }
+
+#ifndef OVERRIDE
+static unsigned int seagate_bases[] = {
+	0xc8000, 0xca000, 0xcc000,
+	0xce000, 0xdc000, 0xde000
+};
+
+typedef struct {
+	const unsigned char *signature;
+	unsigned offset;
+	unsigned length;
+	unsigned char type;
+} Signature;
+
+static Signature __initdata signatures[] = {
+	{"ST01 v1.7  (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
+	{"SCSI BIOS 2.00  (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
+
+/*
+ * The following two lines are NOT mistakes.  One detects ROM revision
+ * 3.0.0, the other 3.2.  Since seagate has only one type of SCSI adapter,
+ * and this is not going to change, the "SEAGATE" and "SCSI" together
+ * are probably "good enough"
+ */
+
+	{"SEAGATE SCSI BIOS ", 16, 17, SEAGATE},
+	{"SEAGATE SCSI BIOS ", 17, 17, SEAGATE},
+
+/*
+ * However, future domain makes several incompatible SCSI boards, so specific
+ * signatures must be used.
+ */
+
+	{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
+	{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
+	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90", 5, 47, FD},
+	{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90", 5, 47, FD},
+	{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
+	{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
+	{"IBM F1 BIOS V1.1004/30/92", 5, 25, FD},
+	{"FUTURE DOMAIN TMC-950", 5, 21, FD},
+	/* Added for 2.2.16 by Matthias_Heidbrink@b.maus.de */
+	{"IBM F1 V1.2009/22/93", 5, 25, FD},
+};
+
+#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature))
+#endif				/* n OVERRIDE */
+
+/*
+ * hostno stores the hostnumber, as told to us by the init routine.
+ */
+
+static int hostno = -1;
+static void seagate_reconnect_intr (int, void *, struct pt_regs *);
+static irqreturn_t do_seagate_reconnect_intr (int, void *, struct pt_regs *);
+
+#ifdef FAST
+static int fast = 1;
+#else
+#define fast 0
+#endif
+
+#ifdef SLOW_RATE
+/*
+ * Support for broken devices :
+ * The Seagate board has a handshaking problem.  Namely, a lack
+ * thereof for slow devices.  You can blast 600K/second through
+ * it if you are polling for each byte, more if you do a blind
+ * transfer.  In the first case, with a fast device, REQ will
+ * transition high-low or high-low-high before your loop restarts
+ * and you'll have no problems.  In the second case, the board
+ * will insert wait states for up to 13.2 usecs for REQ to
+ * transition low->high, and everything will work.
+ *
+ * However, there's nothing in the state machine that says
+ * you *HAVE* to see a high-low-high set of transitions before
+ * sending the next byte, and slow things like the Trantor CD ROMS
+ * will break because of this.
+ *
+ * So, we need to slow things down, which isn't as simple as it
+ * seems.  We can't slow things down period, because then people
+ * who don't recompile their kernels will shoot me for ruining
+ * their performance.  We need to do it on a case per case basis.
+ *
+ * The best for performance will be to, only for borken devices
+ * (this is stored on a per-target basis in the scsi_devices array)
+ *
+ * Wait for a low->high transition before continuing with that
+ * transfer.  If we timeout, continue anyways.  We don't need
+ * a long timeout, because REQ should only be asserted until the
+ * corresponding ACK is received and processed.
+ *
+ * Note that we can't use the system timer for this, because of
+ * resolution, and we *really* can't use the timer chip since
+ * gettimeofday() and the beeper routines use that.  So,
+ * the best thing for us to do will be to calibrate a timing
+ * loop in the initialization code using the timer chip before
+ * gettimeofday() can screw with it.
+ *
+ * FIXME: this is broken (not borken :-). Empty loop costs less than
+ * loop with ISA access in it! -- pavel@ucw.cz
+ */
+
+static int borken_calibration = 0;
+
+static void __init borken_init (void)
+{
+	register int count = 0, start = jiffies + 1, stop = start + 25;
+
+	/* FIXME: There may be a better approach, this is a straight port for
+	   now */
+	preempt_disable();
+	while (time_before (jiffies, start))
+		cpu_relax();
+	for (; time_before (jiffies, stop); ++count)
+		cpu_relax();
+	preempt_enable();
+
+/*
+ * Ok, we now have a count for .25 seconds.  Convert to a
+ * count per second and divide by transfer rate in K.  */
+
+	borken_calibration = (count * 4) / (SLOW_RATE * 1024);
+
+	if (borken_calibration < 1)
+		borken_calibration = 1;
+}
+
+static inline void borken_wait (void)
+{
+	register int count;
+
+	for (count = borken_calibration; count && (STATUS & STAT_REQ); --count)
+		cpu_relax();
+	     	
+#if (DEBUG & DEBUG_BORKEN)
+	if (count)
+		printk ("scsi%d : borken timeout\n", hostno);
+#endif
+}
+
+#endif				/* def SLOW_RATE */
+
+/* These beasts only live on ISA, and ISA means 8MHz. Each ULOOP()
+ * contains at least one ISA access, which takes more than 0.125
+ * usec. So if we loop 8 times time in usec, we are safe.
+ */
+
+#define ULOOP( i ) for (clock = i*8;;)
+#define TIMEOUT (!(clock--))
+
+int __init seagate_st0x_detect (Scsi_Host_Template * tpnt)
+{
+	struct Scsi_Host *instance;
+	int i, j;
+	unsigned long cr, dr;
+
+	tpnt->proc_name = "seagate";
+/*
+ *	First, we try for the manual override.
+ */
+	DANY ("Autodetecting ST0x / TMC-8xx\n");
+
+	if (hostno != -1) {
+		printk (KERN_ERR "seagate_st0x_detect() called twice?!\n");
+		return 0;
+	}
+
+/* If the user specified the controller type from the command line,
+   controller_type will be non-zero, so don't try to detect one */
+
+	if (!controller_type) {
+#ifdef OVERRIDE
+		base_address = OVERRIDE;
+		controller_type = CONTROLLER;
+
+		DANY ("Base address overridden to %x, controller type is %s\n",
+		      base_address,
+		      controller_type == SEAGATE ? "SEAGATE" : "FD");
+#else				/* OVERRIDE */
+/*
+ * 	To detect this card, we simply look for the signature
+ *      from the BIOS version notice in all the possible locations
+ *      of the ROM's.  This has a nice side effect of not trashing
+ *      any register locations that might be used by something else.
+ *
+ * XXX - note that we probably should be probing the address
+ * space for the on-board RAM instead.
+ */
+
+		for (i = 0; i < (sizeof (seagate_bases) / sizeof (unsigned int)); ++i) {
+			void __iomem *p = ioremap(seagate_bases[i], 0x2000);
+			if (!p)
+				continue;
+			for (j = 0; j < NUM_SIGNATURES; ++j)
+				if (check_signature(p + signatures[j].offset, signatures[j].signature, signatures[j].length)) {
+					base_address = seagate_bases[i];
+					controller_type = signatures[j].type;
+					break;
+				}
+			iounmap(p);
+		}
+#endif				/* OVERRIDE */
+	}
+	/* (! controller_type) */
+	tpnt->this_id = (controller_type == SEAGATE) ? 7 : 6;
+	tpnt->name = (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR;
+
+	if (!base_address) {
+		printk(KERN_INFO "seagate: ST0x/TMC-8xx not detected.\n");
+		return 0;
+	}
+
+	cr = base_address + (controller_type == SEAGATE ? 0x1a00 : 0x1c00);
+	dr = cr + 0x200;
+	st0x_cr_sr = ioremap(cr, 0x100);
+	st0x_dr = ioremap(dr, 0x100);
+
+	DANY("%s detected. Base address = %x, cr = %x, dr = %x\n",
+	      tpnt->name, base_address, cr, dr);
+
+	/*
+	 *	At all times, we will use IRQ 5.  Should also check for IRQ3
+	 *	if we lose our first interrupt.
+	 */
+	instance = scsi_register (tpnt, 0);
+	if (instance == NULL)
+		return 0;
+
+	hostno = instance->host_no;
+	if (request_irq (irq, do_seagate_reconnect_intr, SA_INTERRUPT, (controller_type == SEAGATE) ? "seagate" : "tmc-8xx", instance)) {
+		printk(KERN_ERR "scsi%d : unable to allocate IRQ%d\n", hostno, irq);
+		return 0;
+	}
+	instance->irq = irq;
+	instance->io_port = base_address;
+#ifdef SLOW_RATE
+	printk(KERN_INFO "Calibrating borken timer... ");
+	borken_init();
+	printk(" %d cycles per transfer\n", borken_calibration);
+#endif
+	printk (KERN_INFO "This is one second... ");
+	{
+		int clock;
+		ULOOP (1 * 1000 * 1000) {
+			STATUS;
+			if (TIMEOUT)
+				break;
+		}
+	}
+
+	printk ("done, %s options:"
+#ifdef ARBITRATE
+		" ARBITRATE"
+#endif
+#ifdef DEBUG
+		" DEBUG"
+#endif
+#ifdef FAST
+		" FAST"
+#ifdef FAST32
+		"32"
+#endif
+#endif
+#ifdef LINKED
+		" LINKED"
+#endif
+#ifdef PARITY
+		" PARITY"
+#endif
+#ifdef SEAGATE_USE_ASM
+		" SEAGATE_USE_ASM"
+#endif
+#ifdef SLOW_RATE
+		" SLOW_RATE"
+#endif
+#ifdef SWAPSTAT
+		" SWAPSTAT"
+#endif
+#ifdef SWAPCNTDATA
+		" SWAPCNTDATA"
+#endif
+		"\n", tpnt->name);
+	return 1;
+}
+
+static const char *seagate_st0x_info (struct Scsi_Host *shpnt)
+{
+	static char buffer[64];
+
+	snprintf(buffer, 64, "%s at irq %d, address 0x%05X",
+		 (controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
+		 irq, base_address);
+	return buffer;
+}
+
+/*
+ * These are our saved pointers for the outstanding command that is
+ * waiting for a reconnect
+ */
+
+static unsigned char current_target, current_lun;
+static unsigned char *current_cmnd, *current_data;
+static int current_nobuffs;
+static struct scatterlist *current_buffer;
+static int current_bufflen;
+
+#ifdef LINKED
+/*
+ * linked_connected indicates whether or not we are currently connected to
+ * linked_target, linked_lun and in an INFORMATION TRANSFER phase,
+ * using linked commands.
+ */
+
+static int linked_connected = 0;
+static unsigned char linked_target, linked_lun;
+#endif
+
+static void (*done_fn) (Scsi_Cmnd *) = NULL;
+static Scsi_Cmnd *SCint = NULL;
+
+/*
+ * These control whether or not disconnect / reconnect will be attempted,
+ * or are being attempted.
+ */
+
+#define NO_RECONNECT    0
+#define RECONNECT_NOW   1
+#define CAN_RECONNECT   2
+
+/*
+ * LINKED_RIGHT indicates that we are currently connected to the correct target
+ * for this command, LINKED_WRONG indicates that we are connected to the wrong
+ * target. Note that these imply CAN_RECONNECT and require defined(LINKED).
+ */
+
+#define LINKED_RIGHT    3
+#define LINKED_WRONG    4
+
+/*
+ * This determines if we are expecting to reconnect or not.
+ */
+
+static int should_reconnect = 0;
+
+/*
+ * The seagate_reconnect_intr routine is called when a target reselects the
+ * host adapter.  This occurs on the interrupt triggered by the target
+ * asserting SEL.
+ */
+
+static irqreturn_t do_seagate_reconnect_intr(int irq, void *dev_id,
+						struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct Scsi_Host *dev = dev_id;
+	
+	spin_lock_irqsave (dev->host_lock, flags);
+	seagate_reconnect_intr (irq, dev_id, regs);
+	spin_unlock_irqrestore (dev->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static void seagate_reconnect_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+	int temp;
+	Scsi_Cmnd *SCtmp;
+
+	DPRINTK (PHASE_RESELECT, "scsi%d : seagate_reconnect_intr() called\n", hostno);
+
+	if (!should_reconnect)
+		printk(KERN_WARNING "scsi%d: unexpected interrupt.\n", hostno);
+	else {
+		should_reconnect = 0;
+
+		DPRINTK (PHASE_RESELECT, "scsi%d : internal_command(%d, %08x, %08x, RECONNECT_NOW\n", 
+			hostno, current_target, current_data, current_bufflen);
+
+		temp = internal_command (current_target, current_lun, current_cmnd, current_data, current_bufflen, RECONNECT_NOW);
+
+		if (msg_byte(temp) != DISCONNECT) {
+			if (done_fn) {
+				DPRINTK(PHASE_RESELECT, "scsi%d : done_fn(%d,%08x)", hostno, hostno, temp);
+				if (!SCint)
+					panic ("SCint == NULL in seagate");
+				SCtmp = SCint;
+				SCint = NULL;
+				SCtmp->result = temp;
+				done_fn(SCtmp);
+			} else
+				printk(KERN_ERR "done_fn() not defined.\n");
+		}
+	}
+}
+
+/*
+ * The seagate_st0x_queue_command() function provides a queued interface
+ * to the seagate SCSI driver.  Basically, it just passes control onto the
+ * seagate_command() function, after fixing it so that the done_fn()
+ * is set to the one passed to the function.  We have to be very careful,
+ * because there are some commands on some devices that do not disconnect,
+ * and if we simply call the done_fn when the command is done then another
+ * command is started and queue_command is called again...  We end up
+ * overflowing the kernel stack, and this tends not to be such a good idea.
+ */
+
+static int recursion_depth = 0;
+
+static int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done) (Scsi_Cmnd *))
+{
+	int result, reconnect;
+	Scsi_Cmnd *SCtmp;
+
+	DANY ("seagate: que_command");
+	done_fn = done;
+	current_target = SCpnt->device->id;
+	current_lun = SCpnt->device->lun;
+	current_cmnd = SCpnt->cmnd;
+	current_data = (unsigned char *) SCpnt->request_buffer;
+	current_bufflen = SCpnt->request_bufflen;
+	SCint = SCpnt;
+	if (recursion_depth)
+		return 1;
+	recursion_depth++;
+	do {
+#ifdef LINKED
+		/*
+		 * Set linked command bit in control field of SCSI command.
+		 */
+
+		current_cmnd[SCpnt->cmd_len] |= 0x01;
+		if (linked_connected) {
+			DPRINTK (DEBUG_LINKED, "scsi%d : using linked commands, current I_T_L nexus is ", hostno);
+			if (linked_target == current_target && linked_lun == current_lun) 
+			{
+				DPRINTK(DEBUG_LINKED, "correct\n");
+				reconnect = LINKED_RIGHT;
+			} else {
+				DPRINTK(DEBUG_LINKED, "incorrect\n");
+				reconnect = LINKED_WRONG;
+			}
+		} else
+#endif				/* LINKED */
+			reconnect = CAN_RECONNECT;
+
+		result = internal_command(SCint->device->id, SCint->device->lun, SCint->cmnd,
+				      SCint->request_buffer, SCint->request_bufflen, reconnect);
+		if (msg_byte(result) == DISCONNECT)
+			break;
+		SCtmp = SCint;
+		SCint = NULL;
+		SCtmp->result = result;
+		done_fn(SCtmp);
+	}
+	while (SCint);
+	recursion_depth--;
+	return 0;
+}
+
+static int internal_command (unsigned char target, unsigned char lun,
+		  const void *cmnd, void *buff, int bufflen, int reselect)
+{
+	unsigned char *data = NULL;
+	struct scatterlist *buffer = NULL;
+	int clock, temp, nobuffs = 0, done = 0, len = 0;
+#ifdef DEBUG
+	int transfered = 0, phase = 0, newphase;
+#endif
+	register unsigned char status_read;
+	unsigned char tmp_data, tmp_control, status = 0, message = 0;
+	unsigned transfersize = 0, underflow = 0;
+#ifdef SLOW_RATE
+	int borken = (int) SCint->device->borken;	/* Does the current target require
+							   Very Slow I/O ?  */
+#endif
+
+	incommand = 0;
+	st0x_aborted = 0;
+
+#if (DEBUG & PRINT_COMMAND)
+	printk("scsi%d : target = %d, command = ", hostno, target);
+	print_command((unsigned char *) cmnd);
+#endif
+
+#if (DEBUG & PHASE_RESELECT)
+	switch (reselect) {
+	case RECONNECT_NOW:
+		printk("scsi%d : reconnecting\n", hostno);
+		break;
+#ifdef LINKED
+	case LINKED_RIGHT:
+		printk("scsi%d : connected, can reconnect\n", hostno);
+		break;
+	case LINKED_WRONG:
+		printk("scsi%d : connected to wrong target, can reconnect\n",
+			hostno);
+		break;
+#endif
+	case CAN_RECONNECT:
+		printk("scsi%d : allowed to reconnect\n", hostno);
+		break;
+	default:
+		printk("scsi%d : not allowed to reconnect\n", hostno);
+	}
+#endif
+
+	if (target == (controller_type == SEAGATE ? 7 : 6))
+		return DID_BAD_TARGET;
+
+	/*
+	 *	We work it differently depending on if this is is "the first time,"
+	 *      or a reconnect.  If this is a reselect phase, then SEL will
+	 *      be asserted, and we must skip selection / arbitration phases.
+	 */
+
+	switch (reselect) {
+	case RECONNECT_NOW:
+		DPRINTK (PHASE_RESELECT, "scsi%d : phase RESELECT \n", hostno);
+		/*
+		 *	At this point, we should find the logical or of our ID
+		 *	and the original target's ID on the BUS, with BSY, SEL,
+		 *	and I/O signals asserted.
+		 *
+		 *      After ARBITRATION phase is completed, only SEL, BSY,
+		 *	and the target ID are asserted.  A valid initiator ID
+		 *	is not on the bus until IO is asserted, so we must wait
+		 *	for that.
+		 */
+		ULOOP (100 * 1000) {
+			temp = STATUS;
+			if ((temp & STAT_IO) && !(temp & STAT_BSY))
+				break;
+			if (TIMEOUT) {
+				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for IO .\n", hostno);
+				return (DID_BAD_INTR << 16);
+			}
+		}
+
+		/*
+		 *	After I/O is asserted by the target, we can read our ID
+		 *	and its ID off of the BUS.
+		 */
+
+		if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) {
+			DPRINTK (PHASE_RESELECT, "scsi%d : detected reconnect request to different target.\n\tData bus = %d\n", hostno, temp);
+			return (DID_BAD_INTR << 16);
+		}
+
+		if (!(temp & (1 << current_target))) {
+			printk(KERN_WARNING "scsi%d : Unexpected reselect interrupt.  Data bus = %d\n", hostno, temp);
+			return (DID_BAD_INTR << 16);
+		}
+
+		buffer = current_buffer;
+		cmnd = current_cmnd;	/* WDE add */
+		data = current_data;	/* WDE add */
+		len = current_bufflen;	/* WDE add */
+		nobuffs = current_nobuffs;
+
+		/*
+		 *	We have determined that we have been selected.  At this
+		 *	point, we must respond to the reselection by asserting
+		 *	BSY ourselves
+		 */
+
+#if 1
+		WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY);
+#else
+		WRITE_CONTROL (BASE_CMD | CMD_BSY);
+#endif
+
+		/*
+		 *	The target will drop SEL, and raise BSY, at which time
+		 *	we must drop BSY.
+		 */
+
+		ULOOP (100 * 1000) {
+			if (!(STATUS & STAT_SEL))
+				break;
+			if (TIMEOUT) {
+				WRITE_CONTROL (BASE_CMD | CMD_INTR);
+				DPRINTK (PHASE_RESELECT, "scsi%d : RESELECT timed out while waiting for SEL.\n", hostno);
+				return (DID_BAD_INTR << 16);
+			}
+		}
+		WRITE_CONTROL (BASE_CMD);
+		/*
+		 *	At this point, we have connected with the target
+		 *	and can get on with our lives.
+		 */
+		break;
+	case CAN_RECONNECT:
+#ifdef LINKED
+		/*
+		 * This is a bletcherous hack, just as bad as the Unix #!
+		 * interpreter stuff. If it turns out we are using the wrong
+		 * I_T_L nexus, the easiest way to deal with it is to go into
+		 *  our INFORMATION TRANSFER PHASE code, send a ABORT
+		 * message on MESSAGE OUT phase, and then loop back to here.
+		 */
+connect_loop:
+#endif
+		DPRINTK (PHASE_BUS_FREE, "scsi%d : phase = BUS FREE \n", hostno);
+
+		/*
+		 *    BUS FREE PHASE
+		 *
+		 *      On entry, we make sure that the BUS is in a BUS FREE
+		 *      phase, by insuring that both BSY and SEL are low for
+		 *      at least one bus settle delay.  Several reads help
+		 *      eliminate wire glitch.
+		 */
+
+#ifndef ARBITRATE
+#error FIXME: this is broken: we may not use jiffies here - we are under cli(). It will hardlock.
+		clock = jiffies + ST0X_BUS_FREE_DELAY;
+
+		while (((STATUS | STATUS | STATUS) & (STAT_BSY | STAT_SEL)) && (!st0x_aborted) && time_before (jiffies, clock))
+			cpu_relax();
+
+		if (time_after (jiffies, clock))
+			return retcode (DID_BUS_BUSY);
+		else if (st0x_aborted)
+			return retcode (st0x_aborted);
+#endif
+		DPRINTK (PHASE_SELECTION, "scsi%d : phase = SELECTION\n", hostno);
+
+		clock = jiffies + ST0X_SELECTION_DELAY;
+
+		/*
+		 * Arbitration/selection procedure :
+		 * 1.  Disable drivers
+		 * 2.  Write HOST adapter address bit
+		 * 3.  Set start arbitration.
+		 * 4.  We get either ARBITRATION COMPLETE or SELECT at this
+		 *     point.
+		 * 5.  OR our ID and targets on bus.
+		 * 6.  Enable SCSI drivers and asserted SEL and ATTN
+		 */
+
+#ifdef ARBITRATE
+		/* FIXME: verify host lock is always held here */
+		WRITE_CONTROL(0);
+		WRITE_DATA((controller_type == SEAGATE) ? 0x80 : 0x40);
+		WRITE_CONTROL(CMD_START_ARB);
+
+		ULOOP (ST0X_SELECTION_DELAY * 10000) {
+			status_read = STATUS;
+			if (status_read & STAT_ARB_CMPL)
+				break;
+			if (st0x_aborted)	/* FIXME: What? We are going to do something even after abort? */
+				break;
+			if (TIMEOUT || (status_read & STAT_SEL)) {
+				printk(KERN_WARNING "scsi%d : arbitration lost or timeout.\n", hostno);
+				WRITE_CONTROL (BASE_CMD);
+				return retcode (DID_NO_CONNECT);
+			}
+		}
+		DPRINTK (PHASE_SELECTION, "scsi%d : arbitration complete\n", hostno);
+#endif
+
+		/*
+		 *    When the SCSI device decides that we're gawking at it, 
+		 *    it will respond by asserting BUSY on the bus.
+		 *
+		 *    Note : the Seagate ST-01/02 product manual says that we
+		 *    should twiddle the DATA register before the control
+		 *    register. However, this does not work reliably so we do
+		 *    it the other way around.
+		 *
+		 *    Probably could be a problem with arbitration too, we
+		 *    really should try this with a SCSI protocol or logic 
+		 *    analyzer to see what is going on.
+		 */
+		tmp_data = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40));
+		tmp_control = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | (reselect ? CMD_ATTN : 0);
+
+		/* FIXME: verify host lock is always held here */
+#ifdef OLDCNTDATASCEME
+#ifdef SWAPCNTDATA
+		WRITE_CONTROL (tmp_control);
+		WRITE_DATA (tmp_data);
+#else
+		WRITE_DATA (tmp_data);
+		WRITE_CONTROL (tmp_control);
+#endif
+#else
+		tmp_control ^= CMD_BSY;	/* This is guesswork. What used to be in driver    */
+		WRITE_CONTROL (tmp_control);	/* could never work: it sent data into control     */
+		WRITE_DATA (tmp_data);	/* register and control info into data. Hopefully  */
+		tmp_control ^= CMD_BSY;	/* fixed, but order of first two may be wrong.     */
+		WRITE_CONTROL (tmp_control);	/* -- pavel@ucw.cz   */
+#endif
+
+		ULOOP (250 * 1000) {
+			if (st0x_aborted) {
+				/*
+				 *	If we have been aborted, and we have a
+				 *	command in progress, IE the target 
+				 *	still has BSY asserted, then we will
+				 *	reset the bus, and notify the midlevel
+				 *	driver to expect sense.
+				 */
+
+				WRITE_CONTROL (BASE_CMD);
+				if (STATUS & STAT_BSY) {
+					printk(KERN_WARNING "scsi%d : BST asserted after we've been aborted.\n", hostno);
+					seagate_st0x_bus_reset(NULL);
+					return retcode (DID_RESET);
+				}
+				return retcode (st0x_aborted);
+			}
+			if (STATUS & STAT_BSY)
+				break;
+			if (TIMEOUT) {
+				DPRINTK (PHASE_SELECTION, "scsi%d : NO CONNECT with target %d, stat = %x \n", hostno, target, STATUS);
+				return retcode (DID_NO_CONNECT);
+			}
+		}
+
+		/* Establish current pointers.  Take into account scatter / gather */
+
+		if ((nobuffs = SCint->use_sg)) {
+#if (DEBUG & DEBUG_SG)
+			{
+				int i;
+				printk("scsi%d : scatter gather requested, using %d buffers.\n", hostno, nobuffs);
+				for (i = 0; i < nobuffs; ++i)
+					printk("scsi%d : buffer %d address = %p length = %d\n",
+					     hostno, i,
+					     page_address(buffer[i].page) + buffer[i].offset,
+					     buffer[i].length);
+			}
+#endif
+
+			buffer = (struct scatterlist *) SCint->buffer;
+			len = buffer->length;
+			data = page_address(buffer->page) + buffer->offset;
+		} else {
+			DPRINTK (DEBUG_SG, "scsi%d : scatter gather not requested.\n", hostno);
+			buffer = NULL;
+			len = SCint->request_bufflen;
+			data = (unsigned char *) SCint->request_buffer;
+		}
+
+		DPRINTK (PHASE_DATAIN | PHASE_DATAOUT, "scsi%d : len = %d\n",
+			 hostno, len);
+
+		break;
+#ifdef LINKED
+	case LINKED_RIGHT:
+		break;
+	case LINKED_WRONG:
+		break;
+#endif
+	}			/* end of switch(reselect) */
+
+	/*
+	 *    There are several conditions under which we wish to send a message :
+	 *      1.  When we are allowing disconnect / reconnect, and need to
+	 *	establish the I_T_L nexus via an IDENTIFY with the DiscPriv bit
+	 *	set.
+	 *
+	 *      2.  When we are doing linked commands, are have the wrong I_T_L
+	 *	nexus established and want to send an ABORT message.
+	 */
+
+	/* GCC does not like an ifdef inside a macro, so do it the hard way. */
+#ifdef LINKED
+	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT)|| (reselect == LINKED_WRONG))? CMD_ATTN : 0));
+#else
+	WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE | (((reselect == CAN_RECONNECT))? CMD_ATTN : 0));
+#endif
+
+	/*
+	 *    INFORMATION TRANSFER PHASE
+	 *
+	 *      The nasty looking read / write inline assembler loops we use for
+	 *      DATAIN and DATAOUT phases are approximately 4-5 times as fast as
+	 *      the 'C' versions - since we're moving 1024 bytes of data, this
+	 *      really adds up.
+	 *
+	 *      SJT: The nasty-looking assembler is gone, so it's slower.
+	 *
+	 */
+
+	DPRINTK (PHASE_ETC, "scsi%d : phase = INFORMATION TRANSFER\n", hostno);
+
+	incommand = 1;
+	transfersize = SCint->transfersize;
+	underflow = SCint->underflow;
+
+	/*
+	 *	Now, we poll the device for status information,
+	 *      and handle any requests it makes.  Note that since we are unsure
+	 *	of how much data will be flowing across the system, etc and
+	 *	cannot make reasonable timeouts, that we will instead have the
+	 *	midlevel driver handle any timeouts that occur in this phase.
+	 */
+
+	while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) {
+#ifdef PARITY
+		if (status_read & STAT_PARITY) {
+			printk(KERN_ERR "scsi%d : got parity error\n", hostno);
+			st0x_aborted = DID_PARITY;
+		}
+#endif
+		if (status_read & STAT_REQ) {
+#if ((DEBUG & PHASE_ETC) == PHASE_ETC)
+			if ((newphase = (status_read & REQ_MASK)) != phase) {
+				phase = newphase;
+				switch (phase) {
+				case REQ_DATAOUT:
+					printk ("scsi%d : phase = DATA OUT\n", hostno);
+					break;
+				case REQ_DATAIN:
+					printk ("scsi%d : phase = DATA IN\n", hostno);
+					break;
+				case REQ_CMDOUT:
+					printk
+					    ("scsi%d : phase = COMMAND OUT\n", hostno);
+					break;
+				case REQ_STATIN:
+					printk ("scsi%d : phase = STATUS IN\n",	hostno);
+					break;
+				case REQ_MSGOUT:
+					printk
+					    ("scsi%d : phase = MESSAGE OUT\n", hostno);
+					break;
+				case REQ_MSGIN:
+					printk ("scsi%d : phase = MESSAGE IN\n", hostno);
+					break;
+				default:
+					printk ("scsi%d : phase = UNKNOWN\n", hostno);
+					st0x_aborted = DID_ERROR;
+				}
+			}
+#endif
+			switch (status_read & REQ_MASK) {
+			case REQ_DATAOUT:
+				/*
+				 * If we are in fast mode, then we simply splat
+				 * the data out in word-sized chunks as fast as
+				 * we can.
+				 */
+
+				if (!len) {
+#if 0
+					printk("scsi%d: underflow to target %d lun %d \n", hostno, target, lun);
+					st0x_aborted = DID_ERROR;
+					fast = 0;
+#endif
+					break;
+				}
+
+				if (fast && transfersize
+				    && !(len % transfersize)
+				    && (len >= transfersize)
+#ifdef FAST32
+				    && !(transfersize % 4)
+#endif
+				    ) {
+					DPRINTK (DEBUG_FAST,
+						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+						 "         len = %d, data = %08x\n",
+						 hostno, SCint->underflow,
+						 SCint->transfersize, len,
+						 data);
+
+			/* SJT: Start. Fast Write */
+#ifdef SEAGATE_USE_ASM
+					__asm__ ("cld\n\t"
+#ifdef FAST32
+						 "shr $2, %%ecx\n\t"
+						 "1:\t"
+						 "lodsl\n\t"
+						 "movl %%eax, (%%edi)\n\t"
+#else
+						 "1:\t"
+						 "lodsb\n\t"
+						 "movb %%al, (%%edi)\n\t"
+#endif
+						 "loop 1b;"
+				      /* output */ :
+				      /* input */ :"D" (st0x_dr),
+						 "S"
+						 (data),
+						 "c" (SCint->transfersize)
+/* clobbered */
+				      :	 "eax", "ecx",
+						 "esi");
+#else				/* SEAGATE_USE_ASM */
+					memcpy_toio(st0x_dr, data, transfersize);
+#endif				/* SEAGATE_USE_ASM */
+/* SJT: End */
+					len -= transfersize;
+					data += transfersize;
+					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
+				} else {
+					/*
+					 *    We loop as long as we are in a 
+					 *    data out phase, there is data to
+					 *    send, and BSY is still active.
+					 */
+
+/* SJT: Start. Slow Write. */
+#ifdef SEAGATE_USE_ASM
+
+					int __dummy_1, __dummy_2;
+
+/*
+ *      We loop as long as we are in a data out phase, there is data to send, 
+ *      and BSY is still active.
+ */
+/* Local variables : len = ecx , data = esi, 
+                     st0x_cr_sr = ebx, st0x_dr =  edi
+*/
+					__asm__ (
+							/* Test for any data here at all. */
+							"orl %%ecx, %%ecx\n\t"
+							"jz 2f\n\t" "cld\n\t"
+/*                    "movl st0x_cr_sr, %%ebx\n\t"  */
+/*                    "movl st0x_dr, %%edi\n\t"  */
+							"1:\t"
+							"movb (%%ebx), %%al\n\t"
+							/* Test for BSY */
+							"test $1, %%al\n\t"
+							"jz 2f\n\t"
+							/* Test for data out phase - STATUS & REQ_MASK should be 
+							   REQ_DATAOUT, which is 0. */
+							"test $0xe, %%al\n\t"
+							"jnz 2f\n\t"
+							/* Test for REQ */
+							"test $0x10, %%al\n\t"
+							"jz 1b\n\t"
+							"lodsb\n\t"
+							"movb %%al, (%%edi)\n\t"
+							"loop 1b\n\t" "2:\n"
+				      /* output */ :"=S" (data), "=c" (len),
+							"=b"
+							(__dummy_1),
+							"=D" (__dummy_2)
+/* input */
+				      :		"0" (data), "1" (len),
+							"2" (st0x_cr_sr),
+							"3" (st0x_dr)
+/* clobbered */
+				      :		"eax");
+#else				/* SEAGATE_USE_ASM */
+					while (len) {
+						unsigned char stat;
+
+						stat = STATUS;
+						if (!(stat & STAT_BSY)
+						    || ((stat & REQ_MASK) !=
+							REQ_DATAOUT))
+							break;
+						if (stat & STAT_REQ) {
+							WRITE_DATA (*data++);
+							--len;
+						}
+					}
+#endif				/* SEAGATE_USE_ASM */
+/* SJT: End. */
+				}
+
+				if (!len && nobuffs) {
+					--nobuffs;
+					++buffer;
+					len = buffer->length;
+					data = page_address(buffer->page) + buffer->offset;
+					DPRINTK (DEBUG_SG,
+						 "scsi%d : next scatter-gather buffer len = %d address = %08x\n",
+						 hostno, len, data);
+				}
+				break;
+
+			case REQ_DATAIN:
+#ifdef SLOW_RATE
+				if (borken) {
+#if (DEBUG & (PHASE_DATAIN))
+					transfered += len;
+#endif
+					for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | STAT_REQ); --len) {
+						*data++ = DATA;
+						borken_wait();
+					}
+#if (DEBUG & (PHASE_DATAIN))
+					transfered -= len;
+#endif
+				} else
+#endif
+
+					if (fast && transfersize
+					    && !(len % transfersize)
+					    && (len >= transfersize)
+#ifdef FAST32
+					    && !(transfersize % 4)
+#endif
+				    ) {
+					DPRINTK (DEBUG_FAST,
+						 "scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+						 "         len = %d, data = %08x\n",
+						 hostno, SCint->underflow,
+						 SCint->transfersize, len,
+						 data);
+
+/* SJT: Start. Fast Read */
+#ifdef SEAGATE_USE_ASM
+					__asm__ ("cld\n\t"
+#ifdef FAST32
+						 "shr $2, %%ecx\n\t"
+						 "1:\t"
+						 "movl (%%esi), %%eax\n\t"
+						 "stosl\n\t"
+#else
+						 "1:\t"
+						 "movb (%%esi), %%al\n\t"
+						 "stosb\n\t"
+#endif
+						 "loop 1b\n\t"
+				      /* output */ :
+				      /* input */ :"S" (st0x_dr),
+						 "D"
+						 (data),
+						 "c" (SCint->transfersize)
+/* clobbered */
+				      :	 "eax", "ecx",
+						 "edi");
+#else				/* SEAGATE_USE_ASM */
+					memcpy_fromio(data, st0x_dr, len);
+#endif				/* SEAGATE_USE_ASM */
+/* SJT: End */
+					len -= transfersize;
+					data += transfersize;
+#if (DEBUG & PHASE_DATAIN)
+					printk ("scsi%d: transfered += %d\n", hostno, transfersize);
+					transfered += transfersize;
+#endif
+
+					DPRINTK (DEBUG_FAST, "scsi%d : FAST transfer complete len = %d data = %08x\n", hostno, len, data);
+				} else {
+
+#if (DEBUG & PHASE_DATAIN)
+					printk ("scsi%d: transfered += %d\n", hostno, len);
+					transfered += len;	/* Assume we'll transfer it all, then
+								   subtract what we *didn't* transfer */
+#endif
+
+/*
+ *	We loop as long as we are in a data in phase, there is room to read,
+ *      and BSY is still active
+ */
+
+/* SJT: Start. */
+#ifdef SEAGATE_USE_ASM
+
+					int __dummy_3, __dummy_4;
+
+/* Dummy clobbering variables for the new gcc-2.95 */
+
+/*
+ *      We loop as long as we are in a data in phase, there is room to read, 
+ *      and BSY is still active
+ */
+					/* Local variables : ecx = len, edi = data
+					   esi = st0x_cr_sr, ebx = st0x_dr */
+					__asm__ (
+							/* Test for room to read */
+							"orl %%ecx, %%ecx\n\t"
+							"jz 2f\n\t" "cld\n\t"
+/*                "movl st0x_cr_sr, %%esi\n\t"  */
+/*                "movl st0x_dr, %%ebx\n\t"  */
+							"1:\t"
+							"movb (%%esi), %%al\n\t"
+							/* Test for BSY */
+							"test $1, %%al\n\t"
+							"jz 2f\n\t"
+							/* Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, 
+							   = STAT_IO, which is 4. */
+							"movb $0xe, %%ah\n\t"
+							"andb %%al, %%ah\n\t"
+							"cmpb $0x04, %%ah\n\t"
+							"jne 2f\n\t"
+							/* Test for REQ */
+							"test $0x10, %%al\n\t"
+							"jz 1b\n\t"
+							"movb (%%ebx), %%al\n\t"
+							"stosb\n\t"
+							"loop 1b\n\t" "2:\n"
+				      /* output */ :"=D" (data), "=c" (len),
+							"=S"
+							(__dummy_3),
+							"=b" (__dummy_4)
+/* input */
+				      :		"0" (data), "1" (len),
+							"2" (st0x_cr_sr),
+							"3" (st0x_dr)
+/* clobbered */
+				      :		"eax");
+#else				/* SEAGATE_USE_ASM */
+					while (len) {
+						unsigned char stat;
+
+						stat = STATUS;
+						if (!(stat & STAT_BSY)
+						    || ((stat & REQ_MASK) !=
+							REQ_DATAIN))
+							break;
+						if (stat & STAT_REQ) {
+							*data++ = DATA;
+							--len;
+						}
+					}
+#endif				/* SEAGATE_USE_ASM */
+/* SJT: End. */
+#if (DEBUG & PHASE_DATAIN)
+					printk ("scsi%d: transfered -= %d\n", hostno, len);
+					transfered -= len;	/* Since we assumed all of Len got  *
+								   transfered, correct our mistake */
+#endif
+				}
+
+				if (!len && nobuffs) {
+					--nobuffs;
+					++buffer;
+					len = buffer->length;
+					data = page_address(buffer->page) + buffer->offset;
+					DPRINTK (DEBUG_SG, "scsi%d : next scatter-gather buffer len = %d address = %08x\n", hostno, len, data);
+				}
+				break;
+
+			case REQ_CMDOUT:
+				while (((status_read = STATUS) & STAT_BSY) &&
+				       ((status_read & REQ_MASK) == REQ_CMDOUT))
+					if (status_read & STAT_REQ) {
+						WRITE_DATA (*(const unsigned char *) cmnd);
+						cmnd = 1 + (const unsigned char *)cmnd;
+#ifdef SLOW_RATE
+						if (borken)
+							borken_wait ();
+#endif
+					}
+				break;
+
+			case REQ_STATIN:
+				status = DATA;
+				break;
+
+			case REQ_MSGOUT:
+				/*
+				 *	We can only have sent a MSG OUT if we
+				 *	requested to do this by raising ATTN.
+				 *	So, we must drop ATTN.
+				 */
+				WRITE_CONTROL (BASE_CMD | CMD_DRVR_ENABLE);
+				/*
+				 *	If we are reconnecting, then we must 
+				 *	send an IDENTIFY message in response
+				 *	to MSGOUT.
+				 */
+				switch (reselect) {
+				case CAN_RECONNECT:
+					WRITE_DATA (IDENTIFY (1, lun));
+					DPRINTK (PHASE_RESELECT | PHASE_MSGOUT, "scsi%d : sent IDENTIFY message.\n", hostno);
+					break;
+#ifdef LINKED
+				case LINKED_WRONG:
+					WRITE_DATA (ABORT);
+					linked_connected = 0;
+					reselect = CAN_RECONNECT;
+					goto connect_loop;
+					DPRINTK (PHASE_MSGOUT | DEBUG_LINKED, "scsi%d : sent ABORT message to cancel incorrect I_T_L nexus.\n", hostno);
+#endif					/* LINKED */
+					DPRINTK (DEBUG_LINKED, "correct\n");
+				default:
+					WRITE_DATA (NOP);
+					printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target);
+				}
+				break;
+
+			case REQ_MSGIN:
+				switch (message = DATA) {
+				case DISCONNECT:
+					DANY("seagate: deciding to disconnect\n");
+					should_reconnect = 1;
+					current_data = data;	/* WDE add */
+					current_buffer = buffer;
+					current_bufflen = len;	/* WDE add */
+					current_nobuffs = nobuffs;
+#ifdef LINKED
+					linked_connected = 0;
+#endif
+					done = 1;
+					DPRINTK ((PHASE_RESELECT | PHASE_MSGIN), "scsi%d : disconnected.\n", hostno);
+					break;
+
+#ifdef LINKED
+				case LINKED_CMD_COMPLETE:
+				case LINKED_FLG_CMD_COMPLETE:
+#endif
+				case COMMAND_COMPLETE:
+					/*
+					 * Note : we should check for underflow here.
+					 */
+					DPRINTK(PHASE_MSGIN, "scsi%d : command complete.\n", hostno);
+					done = 1;
+					break;
+				case ABORT:
+					DPRINTK(PHASE_MSGIN, "scsi%d : abort message.\n", hostno);
+					done = 1;
+					break;
+				case SAVE_POINTERS:
+					current_buffer = buffer;
+					current_bufflen = len;	/* WDE add */
+					current_data = data;	/* WDE mod */
+					current_nobuffs = nobuffs;
+					DPRINTK (PHASE_MSGIN, "scsi%d : pointers saved.\n", hostno);
+					break;
+				case RESTORE_POINTERS:
+					buffer = current_buffer;
+					cmnd = current_cmnd;
+					data = current_data;	/* WDE mod */
+					len = current_bufflen;
+					nobuffs = current_nobuffs;
+					DPRINTK(PHASE_MSGIN, "scsi%d : pointers restored.\n", hostno);
+					break;
+				default:
+
+					/*
+					 *	IDENTIFY distinguishes itself
+					 *	from the other messages by 
+					 *	setting the high bit.
+					 *
+					 *      Note : we need to handle at 
+					 *	least one outstanding command
+					 *	per LUN, and need to hash the 
+					 *	SCSI command for that I_T_L
+					 *	nexus based on the known ID 
+					 *	(at this point) and LUN.
+					 */
+
+					if (message & 0x80) {
+						DPRINTK (PHASE_MSGIN, "scsi%d : IDENTIFY message received from id %d, lun %d.\n", hostno, target, message & 7);
+					} else {
+						/*
+						 *      We should go into a
+						 *	MESSAGE OUT phase, and
+						 *	send  a MESSAGE_REJECT
+						 *      if we run into a message 
+						 *	that we don't like.  The
+						 *	seagate driver needs 
+						 *	some serious 
+						 *	restructuring first
+						 *	though.
+						 */
+						DPRINTK (PHASE_MSGIN, "scsi%d : unknown message %d from target %d.\n", hostno, message, target);
+					}
+				}
+				break;
+			default:
+				printk(KERN_ERR "scsi%d : unknown phase.\n", hostno);
+				st0x_aborted = DID_ERROR;
+			}	/* end of switch (status_read &  REQ_MASK) */
+#ifdef SLOW_RATE
+			/*
+			 * I really don't care to deal with borken devices in
+			 * each single byte transfer case (ie, message in,
+			 * message out, status), so I'll do the wait here if 
+			 * necessary.
+			 */
+			if(borken)
+				borken_wait();
+#endif
+
+		}		/* if(status_read & STAT_REQ) ends */
+	}			/* while(((status_read = STATUS)...) ends */
+
+	DPRINTK(PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT, "scsi%d : Transfered %d bytes\n", hostno, transfered);
+
+#if (DEBUG & PHASE_EXIT)
+#if 0				/* Doesn't work for scatter/gather */
+	printk("Buffer : \n");
+	for(i = 0; i < 20; ++i)
+		printk("%02x  ", ((unsigned char *) data)[i]);	/* WDE mod */
+	printk("\n");
+#endif
+	printk("scsi%d : status = ", hostno);
+	print_status(status);
+	printk(" message = %02x\n", message);
+#endif
+
+	/* We shouldn't reach this until *after* BSY has been deasserted */
+
+#ifdef LINKED
+	else
+	{
+		/*
+		 * Fix the message byte so that unsuspecting high level drivers
+		 * don't puke when they see a LINKED COMMAND message in place of
+		 * the COMMAND COMPLETE they may be expecting.  Shouldn't be
+		 * necessary, but it's better to be on the safe side.
+		 *
+		 * A non LINKED* message byte will indicate that the command
+		 * completed, and we are now disconnected.
+		 */
+
+		switch (message) {
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+			message = COMMAND_COMPLETE;
+			linked_target = current_target;
+			linked_lun = current_lun;
+			linked_connected = 1;
+			DPRINTK (DEBUG_LINKED, "scsi%d : keeping I_T_L nexus established for linked command.\n", hostno);
+			/* We also will need to adjust status to accommodate intermediate
+			   conditions. */
+			if ((status == INTERMEDIATE_GOOD) || (status == INTERMEDIATE_C_GOOD))
+				status = GOOD;
+			break;
+			/*
+			 * We should also handle what are "normal" termination
+			 * messages here (ABORT, BUS_DEVICE_RESET?, and
+			 * COMMAND_COMPLETE individually, and flake if things
+			 * aren't right.
+			 */
+		default:
+			DPRINTK (DEBUG_LINKED, "scsi%d : closing I_T_L nexus.\n", hostno);
+			linked_connected = 0;
+		}
+	}
+#endif	/* LINKED */
+
+	if (should_reconnect) {
+		DPRINTK (PHASE_RESELECT, "scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", hostno);
+		WRITE_CONTROL (BASE_CMD | CMD_INTR);
+	} else
+		WRITE_CONTROL (BASE_CMD);
+
+	return retcode (st0x_aborted);
+}				/* end of internal_command */
+
+static int seagate_st0x_abort (Scsi_Cmnd * SCpnt)
+{
+	st0x_aborted = DID_ABORT;
+	return SUCCESS;
+}
+
+#undef ULOOP
+#undef TIMEOUT
+
+/*
+ * the seagate_st0x_reset function resets the SCSI bus 
+ *
+ * May be called with SCpnt = NULL
+ */
+
+static int seagate_st0x_bus_reset(Scsi_Cmnd * SCpnt)
+{
+	/* No timeouts - this command is going to fail because it was reset. */
+	DANY ("scsi%d: Reseting bus... ", hostno);
+
+	/* assert  RESET signal on SCSI bus.  */
+	WRITE_CONTROL (BASE_CMD | CMD_RST);
+
+	udelay (20 * 1000);
+
+	WRITE_CONTROL (BASE_CMD);
+	st0x_aborted = DID_RESET;
+
+	DANY ("done.\n");
+	return SUCCESS;
+}
+
+static int seagate_st0x_host_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int seagate_st0x_device_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int seagate_st0x_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, shost);
+	release_region(shost->io_port, shost->n_io_port);
+	return 0;
+}
+
+static Scsi_Host_Template driver_template = {
+	.detect         	= seagate_st0x_detect,
+	.release        	= seagate_st0x_release,
+	.info           	= seagate_st0x_info,
+	.queuecommand   	= seagate_st0x_queue_command,
+	.eh_abort_handler	= seagate_st0x_abort,
+	.eh_bus_reset_handler	= seagate_st0x_bus_reset,
+	.eh_host_reset_handler	= seagate_st0x_host_reset,
+	.eh_device_reset_handler = seagate_st0x_device_reset,
+	.can_queue      	= 1,
+	.this_id        	= 7,
+	.sg_tablesize   	= SG_ALL,
+	.cmd_per_lun    	= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
new file mode 100644
index 0000000..e49e8ec
--- /dev/null
+++ b/drivers/scsi/seagate.h
@@ -0,0 +1,21 @@
+/*
+ *	seagate.h Copyright (C) 1992 Drew Eckhardt 
+ *	low level scsi driver header for ST01/ST02 by
+ *		Drew Eckhardt 
+ *
+ *	<drew@colorado.edu>
+ */
+
+#ifndef _SEAGATE_H
+#define SEAGATE_H
+
+static int seagate_st0x_detect(Scsi_Host_Template *);
+static int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+static int seagate_st0x_abort(Scsi_Cmnd *);
+static const char *seagate_st0x_info(struct Scsi_Host *);
+static int seagate_st0x_bus_reset(Scsi_Cmnd *);
+static int seagate_st0x_device_reset(Scsi_Cmnd *);
+static int seagate_st0x_host_reset(Scsi_Cmnd *);
+
+#endif /* _SEAGATE_H */
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
new file mode 100644
index 0000000..fd72d73
--- /dev/null
+++ b/drivers/scsi/sg.c
@@ -0,0 +1,3092 @@
+/*
+ *  History:
+ *  Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
+ *           to allow user process control of SCSI devices.
+ *  Development Sponsored by Killy Corp. NY NY
+ *
+ * Original driver (sg.c):
+ *        Copyright (C) 1992 Lawrence Foard
+ * Version 2 and 3 extensions to driver:
+ *        Copyright (C) 1998 - 2005 Douglas Gilbert
+ *
+ *  Modified  19-JAN-1998  Richard Gooch <rgooch@atnf.csiro.au>  Devfs support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ */
+
+static int sg_version_num = 30532;	/* 2 digits for each component */
+#define SG_VERSION_STR "3.5.32"
+
+/*
+ *  D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes:
+ *      - scsi logging is available via SCSI_LOG_TIMEOUT macros. First
+ *        the kernel/module needs to be built with CONFIG_SCSI_LOGGING
+ *        (otherwise the macros compile to empty statements).
+ *
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+#include <linux/init.h>
+#include <linux/poll.h>
+#include <linux/smp_lock.h>
+#include <linux/moduleparam.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/cdev.h>
+#include <linux/seq_file.h>
+#include <linux/blkdev.h>
+#include <linux/delay.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
+
+#include "scsi_logging.h"
+
+#ifdef CONFIG_SCSI_PROC_FS
+#include <linux/proc_fs.h>
+static char *sg_version_date = "20050117";
+
+static int sg_proc_init(void);
+static void sg_proc_cleanup(void);
+#endif
+
+#ifndef LINUX_VERSION_CODE
+#include <linux/version.h>
+#endif				/* LINUX_VERSION_CODE */
+
+#define SG_ALLOW_DIO_DEF 0
+#define SG_ALLOW_DIO_CODE /* compile out by commenting this define */
+
+#define SG_MAX_DEVS 32768
+
+/*
+ * Suppose you want to calculate the formula muldiv(x,m,d)=int(x * m / d)
+ * Then when using 32 bit integers x * m may overflow during the calculation.
+ * Replacing muldiv(x) by muldiv(x)=((x % d) * m) / d + int(x / d) * m
+ * calculates the same, but prevents the overflow when both m and d
+ * are "small" numbers (like HZ and USER_HZ).
+ * Of course an overflow is inavoidable if the result of muldiv doesn't fit
+ * in 32 bits.
+ */
+#define MULDIV(X,MUL,DIV) ((((X % DIV) * MUL) / DIV) + ((X / DIV) * MUL))
+
+#define SG_DEFAULT_TIMEOUT MULDIV(SG_DEFAULT_TIMEOUT_USER, HZ, USER_HZ)
+
+int sg_big_buff = SG_DEF_RESERVED_SIZE;
+/* N.B. This variable is readable and writeable via
+   /proc/scsi/sg/def_reserved_size . Each time sg_open() is called a buffer
+   of this size (or less if there is not enough memory) will be reserved
+   for use by this file descriptor. [Deprecated usage: this variable is also
+   readable via /proc/sys/kernel/sg-big-buff if the sg driver is built into
+   the kernel (i.e. it is not a module).] */
+static int def_reserved_size = -1;	/* picks up init parameter */
+static int sg_allow_dio = SG_ALLOW_DIO_DEF;
+
+#define SG_SECTOR_SZ 512
+#define SG_SECTOR_MSK (SG_SECTOR_SZ - 1)
+
+#define SG_DEV_ARR_LUMP 32	/* amount to over allocate sg_dev_arr by */
+
+static int sg_add(struct class_device *);
+static void sg_remove(struct class_device *);
+
+static Scsi_Request *dummy_cmdp;	/* only used for sizeof */
+
+static DEFINE_RWLOCK(sg_dev_arr_lock);	/* Also used to lock
+							   file descriptor list for device */
+
+static struct class_interface sg_interface = {
+	.add		= sg_add,
+	.remove		= sg_remove,
+};
+
+typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */
+	unsigned short k_use_sg; /* Count of kernel scatter-gather pieces */
+	unsigned short sglist_len; /* size of malloc'd scatter-gather list ++ */
+	unsigned bufflen;	/* Size of (aggregate) data buffer */
+	unsigned b_malloc_len;	/* actual len malloc'ed in buffer */
+	void *buffer;		/* Data buffer or scatter list (k_use_sg>0) */
+	char dio_in_use;	/* 0->indirect IO (or mmap), 1->dio */
+	unsigned char cmd_opcode; /* first byte of command */
+} Sg_scatter_hold;
+
+struct sg_device;		/* forward declarations */
+struct sg_fd;
+
+typedef struct sg_request {	/* SG_MAX_QUEUE requests outstanding per file */
+	Scsi_Request *my_cmdp;	/* != 0  when request with lower levels */
+	struct sg_request *nextrp;	/* NULL -> tail request (slist) */
+	struct sg_fd *parentfp;	/* NULL -> not in use */
+	Sg_scatter_hold data;	/* hold buffer, perhaps scatter list */
+	sg_io_hdr_t header;	/* scsi command+info, see <scsi/sg.h> */
+	unsigned char sense_b[sizeof (dummy_cmdp->sr_sense_buffer)];
+	char res_used;		/* 1 -> using reserve buffer, 0 -> not ... */
+	char orphan;		/* 1 -> drop on sight, 0 -> normal */
+	char sg_io_owned;	/* 1 -> packet belongs to SG_IO */
+	volatile char done;	/* 0->before bh, 1->before read, 2->read */
+} Sg_request;
+
+typedef struct sg_fd {		/* holds the state of a file descriptor */
+	struct sg_fd *nextfp;	/* NULL when last opened fd on this device */
+	struct sg_device *parentdp;	/* owning device */
+	wait_queue_head_t read_wait;	/* queue read until command done */
+	rwlock_t rq_list_lock;	/* protect access to list in req_arr */
+	int timeout;		/* defaults to SG_DEFAULT_TIMEOUT      */
+	int timeout_user;	/* defaults to SG_DEFAULT_TIMEOUT_USER */
+	Sg_scatter_hold reserve;	/* buffer held for this file descriptor */
+	unsigned save_scat_len;	/* original length of trunc. scat. element */
+	Sg_request *headrp;	/* head of request slist, NULL->empty */
+	struct fasync_struct *async_qp;	/* used by asynchronous notification */
+	Sg_request req_arr[SG_MAX_QUEUE];	/* used as singly-linked list */
+	char low_dma;		/* as in parent but possibly overridden to 1 */
+	char force_packid;	/* 1 -> pack_id input to read(), 0 -> ignored */
+	volatile char closed;	/* 1 -> fd closed but request(s) outstanding */
+	char cmd_q;		/* 1 -> allow command queuing, 0 -> don't */
+	char next_cmd_len;	/* 0 -> automatic (def), >0 -> use on next write() */
+	char keep_orphan;	/* 0 -> drop orphan (def), 1 -> keep for read() */
+	char mmap_called;	/* 0 -> mmap() never called on this fd */
+} Sg_fd;
+
+typedef struct sg_device { /* holds the state of each scsi generic device */
+	struct scsi_device *device;
+	wait_queue_head_t o_excl_wait;	/* queue open() when O_EXCL in use */
+	int sg_tablesize;	/* adapter's max scatter-gather table size */
+	Sg_fd *headfp;		/* first open fd belonging to this device */
+	volatile char detached;	/* 0->attached, 1->detached pending removal */
+	volatile char exclude;	/* opened for exclusive access */
+	char sgdebug;		/* 0->off, 1->sense, 9->dump dev, 10-> all devs */
+	struct gendisk *disk;
+	struct cdev * cdev;	/* char_dev [sysfs: /sys/cdev/major/sg<n>] */
+} Sg_device;
+
+static int sg_fasync(int fd, struct file *filp, int mode);
+static void sg_cmd_done(Scsi_Cmnd * SCpnt);	/* tasklet or soft irq callback */
+static int sg_start_req(Sg_request * srp);
+static void sg_finish_rem_req(Sg_request * srp);
+static int sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size);
+static int sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp,
+			 int tablesize);
+static ssize_t sg_new_read(Sg_fd * sfp, char __user *buf, size_t count,
+			   Sg_request * srp);
+static ssize_t sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
+			    int blocking, int read_only, Sg_request ** o_srp);
+static int sg_common_write(Sg_fd * sfp, Sg_request * srp,
+			   unsigned char *cmnd, int timeout, int blocking);
+static int sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
+		      int wr_xf, int *countp, unsigned char __user **up);
+static int sg_write_xfer(Sg_request * srp);
+static int sg_read_xfer(Sg_request * srp);
+static int sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer);
+static void sg_remove_scat(Sg_scatter_hold * schp);
+static void sg_build_reserve(Sg_fd * sfp, int req_size);
+static void sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size);
+static void sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp);
+static char *sg_page_malloc(int rqSz, int lowDma, int *retSzp);
+static void sg_page_free(char *buff, int size);
+static Sg_fd *sg_add_sfp(Sg_device * sdp, int dev);
+static int sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
+static void __sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp);
+static Sg_request *sg_get_rq_mark(Sg_fd * sfp, int pack_id);
+static Sg_request *sg_add_request(Sg_fd * sfp);
+static int sg_remove_request(Sg_fd * sfp, Sg_request * srp);
+static int sg_res_in_use(Sg_fd * sfp);
+static int sg_allow_access(unsigned char opcode, char dev_type);
+static int sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len);
+static Sg_device *sg_get_dev(int dev);
+static inline unsigned char *sg_scatg2virt(const struct scatterlist *sclp);
+#ifdef CONFIG_SCSI_PROC_FS
+static int sg_last_dev(void);
+#endif
+
+static Sg_device **sg_dev_arr = NULL;
+static int sg_dev_max;
+static int sg_nr_dev;
+
+#define SZ_SG_HEADER sizeof(struct sg_header)
+#define SZ_SG_IO_HDR sizeof(sg_io_hdr_t)
+#define SZ_SG_IOVEC sizeof(sg_iovec_t)
+#define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
+
+static int
+sg_open(struct inode *inode, struct file *filp)
+{
+	int dev = iminor(inode);
+	int flags = filp->f_flags;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	int res;
+	int retval;
+
+	nonseekable_open(inode, filp);
+	SCSI_LOG_TIMEOUT(3, printk("sg_open: dev=%d, flags=0x%x\n", dev, flags));
+	sdp = sg_get_dev(dev);
+	if ((!sdp) || (!sdp->device))
+		return -ENXIO;
+	if (sdp->detached)
+		return -ENODEV;
+
+	/* This driver's module count bumped by fops_get in <linux/fs.h> */
+	/* Prevent the device driver from vanishing while we sleep */
+	retval = scsi_device_get(sdp->device);
+	if (retval)
+		return retval;
+
+	if (!((flags & O_NONBLOCK) ||
+	      scsi_block_when_processing_errors(sdp->device))) {
+		retval = -ENXIO;
+		/* we are in error recovery for this device */
+		goto error_out;
+	}
+
+	if (flags & O_EXCL) {
+		if (O_RDONLY == (flags & O_ACCMODE)) {
+			retval = -EPERM; /* Can't lock it with read only access */
+			goto error_out;
+		}
+		if (sdp->headfp && (flags & O_NONBLOCK)) {
+			retval = -EBUSY;
+			goto error_out;
+		}
+		res = 0;
+		__wait_event_interruptible(sdp->o_excl_wait,
+			((sdp->headfp || sdp->exclude) ? 0 : (sdp->exclude = 1)), res);
+		if (res) {
+			retval = res;	/* -ERESTARTSYS because signal hit process */
+			goto error_out;
+		}
+	} else if (sdp->exclude) {	/* some other fd has an exclusive lock on dev */
+		if (flags & O_NONBLOCK) {
+			retval = -EBUSY;
+			goto error_out;
+		}
+		res = 0;
+		__wait_event_interruptible(sdp->o_excl_wait, (!sdp->exclude),
+					   res);
+		if (res) {
+			retval = res;	/* -ERESTARTSYS because signal hit process */
+			goto error_out;
+		}
+	}
+	if (sdp->detached) {
+		retval = -ENODEV;
+		goto error_out;
+	}
+	if (!sdp->headfp) {	/* no existing opens on this device */
+		sdp->sgdebug = 0;
+		sdp->sg_tablesize = sdp->device->host->sg_tablesize;
+	}
+	if ((sfp = sg_add_sfp(sdp, dev)))
+		filp->private_data = sfp;
+	else {
+		if (flags & O_EXCL)
+			sdp->exclude = 0;	/* undo if error */
+		retval = -ENOMEM;
+		goto error_out;
+	}
+	return 0;
+
+      error_out:
+	scsi_device_put(sdp->device);
+	return retval;
+}
+
+/* Following function was formerly called 'sg_close' */
+static int
+sg_release(struct inode *inode, struct file *filp)
+{
+	Sg_device *sdp;
+	Sg_fd *sfp;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_release: %s\n", sdp->disk->disk_name));
+	sg_fasync(-1, filp, 0);	/* remove filp from async notification list */
+	if (0 == sg_remove_sfp(sdp, sfp)) {	/* Returns 1 when sdp gone */
+		if (!sdp->detached) {
+			scsi_device_put(sdp->device);
+		}
+		sdp->exclude = 0;
+		wake_up_interruptible(&sdp->o_excl_wait);
+	}
+	return 0;
+}
+
+static ssize_t
+sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
+{
+	int res;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	int req_pack_id = -1;
+	struct sg_header old_hdr;
+	sg_io_hdr_t new_hdr;
+	sg_io_hdr_t *hp;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_read: %s, count=%d\n",
+				   sdp->disk->disk_name, (int) count));
+	if (!access_ok(VERIFY_WRITE, buf, count))
+		return -EFAULT;
+	if (sfp->force_packid && (count >= SZ_SG_HEADER)) {
+		if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+			return -EFAULT;
+		if (old_hdr.reply_len < 0) {
+			if (count >= SZ_SG_IO_HDR) {
+				if (__copy_from_user
+				    (&new_hdr, buf, SZ_SG_IO_HDR))
+					return -EFAULT;
+				req_pack_id = new_hdr.pack_id;
+			}
+		} else
+			req_pack_id = old_hdr.pack_id;
+	}
+	srp = sg_get_rq_mark(sfp, req_pack_id);
+	if (!srp) {		/* now wait on packet to arrive */
+		if (sdp->detached)
+			return -ENODEV;
+		if (filp->f_flags & O_NONBLOCK)
+			return -EAGAIN;
+		while (1) {
+			res = 0;	/* following is a macro that beats race condition */
+			__wait_event_interruptible(sfp->read_wait,
+				(sdp->detached || (srp = sg_get_rq_mark(sfp, req_pack_id))), 
+						   res);
+			if (sdp->detached)
+				return -ENODEV;
+			if (0 == res)
+				break;
+			return res;	/* -ERESTARTSYS because signal hit process */
+		}
+	}
+	if (srp->header.interface_id != '\0')
+		return sg_new_read(sfp, buf, count, srp);
+
+	hp = &srp->header;
+	memset(&old_hdr, 0, SZ_SG_HEADER);
+	old_hdr.reply_len = (int) hp->timeout;
+	old_hdr.pack_len = old_hdr.reply_len; /* very old, strange behaviour */
+	old_hdr.pack_id = hp->pack_id;
+	old_hdr.twelve_byte =
+	    ((srp->data.cmd_opcode >= 0xc0) && (12 == hp->cmd_len)) ? 1 : 0;
+	old_hdr.target_status = hp->masked_status;
+	old_hdr.host_status = hp->host_status;
+	old_hdr.driver_status = hp->driver_status;
+	if ((CHECK_CONDITION & hp->masked_status) ||
+	    (DRIVER_SENSE & hp->driver_status))
+		memcpy(old_hdr.sense_buffer, srp->sense_b,
+		       sizeof (old_hdr.sense_buffer));
+	switch (hp->host_status) {
+	/* This setup of 'result' is for backward compatibility and is best
+	   ignored by the user who should use target, host + driver status */
+	case DID_OK:
+	case DID_PASSTHROUGH:
+	case DID_SOFT_ERROR:
+		old_hdr.result = 0;
+		break;
+	case DID_NO_CONNECT:
+	case DID_BUS_BUSY:
+	case DID_TIME_OUT:
+		old_hdr.result = EBUSY;
+		break;
+	case DID_BAD_TARGET:
+	case DID_ABORT:
+	case DID_PARITY:
+	case DID_RESET:
+	case DID_BAD_INTR:
+		old_hdr.result = EIO;
+		break;
+	case DID_ERROR:
+		old_hdr.result = (srp->sense_b[0] == 0 && 
+				  hp->masked_status == GOOD) ? 0 : EIO;
+		break;
+	default:
+		old_hdr.result = EIO;
+		break;
+	}
+
+	/* Now copy the result back to the user buffer.  */
+	if (count >= SZ_SG_HEADER) {
+		if (__copy_to_user(buf, &old_hdr, SZ_SG_HEADER))
+			return -EFAULT;
+		buf += SZ_SG_HEADER;
+		if (count > old_hdr.reply_len)
+			count = old_hdr.reply_len;
+		if (count > SZ_SG_HEADER) {
+			if ((res =
+			     sg_read_oxfer(srp, buf, count - SZ_SG_HEADER)))
+				return -EFAULT;
+		}
+	} else
+		count = (old_hdr.result == 0) ? 0 : -EIO;
+	sg_finish_rem_req(srp);
+	return count;
+}
+
+static ssize_t
+sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	int err = 0;
+	int len;
+
+	if (count < SZ_SG_IO_HDR) {
+		err = -EINVAL;
+		goto err_out;
+	}
+	hp->sb_len_wr = 0;
+	if ((hp->mx_sb_len > 0) && hp->sbp) {
+		if ((CHECK_CONDITION & hp->masked_status) ||
+		    (DRIVER_SENSE & hp->driver_status)) {
+			int sb_len = sizeof (dummy_cmdp->sr_sense_buffer);
+			sb_len = (hp->mx_sb_len > sb_len) ? sb_len : hp->mx_sb_len;
+			len = 8 + (int) srp->sense_b[7];	/* Additional sense length field */
+			len = (len > sb_len) ? sb_len : len;
+			if (copy_to_user(hp->sbp, srp->sense_b, len)) {
+				err = -EFAULT;
+				goto err_out;
+			}
+			hp->sb_len_wr = len;
+		}
+	}
+	if (hp->masked_status || hp->host_status || hp->driver_status)
+		hp->info |= SG_INFO_CHECK;
+	if (copy_to_user(buf, hp, SZ_SG_IO_HDR)) {
+		err = -EFAULT;
+		goto err_out;
+	}
+	err = sg_read_xfer(srp);
+      err_out:
+	sg_finish_rem_req(srp);
+	return (0 == err) ? count : err;
+}
+
+static ssize_t
+sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
+{
+	int mxsize, cmd_size, k;
+	int input_size, blocking;
+	unsigned char opcode;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	struct sg_header old_hdr;
+	sg_io_hdr_t *hp;
+	unsigned char cmnd[sizeof (dummy_cmdp->sr_cmnd)];
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_write: %s, count=%d\n",
+				   sdp->disk->disk_name, (int) count));
+	if (sdp->detached)
+		return -ENODEV;
+	if (!((filp->f_flags & O_NONBLOCK) ||
+	      scsi_block_when_processing_errors(sdp->device)))
+		return -ENXIO;
+
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
+	if (count < SZ_SG_HEADER)
+		return -EIO;
+	if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER))
+		return -EFAULT;
+	blocking = !(filp->f_flags & O_NONBLOCK);
+	if (old_hdr.reply_len < 0)
+		return sg_new_write(sfp, buf, count, blocking, 0, NULL);
+	if (count < (SZ_SG_HEADER + 6))
+		return -EIO;	/* The minimum scsi command length is 6 bytes. */
+
+	if (!(srp = sg_add_request(sfp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: queue full\n"));
+		return -EDOM;
+	}
+	buf += SZ_SG_HEADER;
+	__get_user(opcode, buf);
+	if (sfp->next_cmd_len > 0) {
+		if (sfp->next_cmd_len > MAX_COMMAND_SIZE) {
+			SCSI_LOG_TIMEOUT(1, printk("sg_write: command length too long\n"));
+			sfp->next_cmd_len = 0;
+			sg_remove_request(sfp, srp);
+			return -EIO;
+		}
+		cmd_size = sfp->next_cmd_len;
+		sfp->next_cmd_len = 0;	/* reset so only this write() effected */
+	} else {
+		cmd_size = COMMAND_SIZE(opcode);	/* based on SCSI command group */
+		if ((opcode >= 0xc0) && old_hdr.twelve_byte)
+			cmd_size = 12;
+	}
+	SCSI_LOG_TIMEOUT(4, printk(
+		"sg_write:   scsi opcode=0x%02x, cmd_size=%d\n", (int) opcode, cmd_size));
+/* Determine buffer size.  */
+	input_size = count - cmd_size;
+	mxsize = (input_size > old_hdr.reply_len) ? input_size : old_hdr.reply_len;
+	mxsize -= SZ_SG_HEADER;
+	input_size -= SZ_SG_HEADER;
+	if (input_size < 0) {
+		sg_remove_request(sfp, srp);
+		return -EIO;	/* User did not pass enough bytes for this command. */
+	}
+	hp = &srp->header;
+	hp->interface_id = '\0';	/* indicator of old interface tunnelled */
+	hp->cmd_len = (unsigned char) cmd_size;
+	hp->iovec_count = 0;
+	hp->mx_sb_len = 0;
+	if (input_size > 0)
+		hp->dxfer_direction = (old_hdr.reply_len > SZ_SG_HEADER) ?
+		    SG_DXFER_TO_FROM_DEV : SG_DXFER_TO_DEV;
+	else
+		hp->dxfer_direction = (mxsize > 0) ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
+	hp->dxfer_len = mxsize;
+	hp->dxferp = (char __user *)buf + cmd_size;
+	hp->sbp = NULL;
+	hp->timeout = old_hdr.reply_len;	/* structure abuse ... */
+	hp->flags = input_size;	/* structure abuse ... */
+	hp->pack_id = old_hdr.pack_id;
+	hp->usr_ptr = NULL;
+	if (__copy_from_user(cmnd, buf, cmd_size))
+		return -EFAULT;
+	/*
+	 * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV,
+	 * but is is possible that the app intended SG_DXFER_TO_DEV, because there
+	 * is a non-zero input_size, so emit a warning.
+	 */
+	if (hp->dxfer_direction == SG_DXFER_TO_FROM_DEV)
+		if (printk_ratelimit())
+			printk(KERN_WARNING
+			       "sg_write: data in/out %d/%d bytes for SCSI command 0x%x--"
+			       "guessing data in;\n" KERN_WARNING "   "
+			       "program %s not setting count and/or reply_len properly\n",
+			       old_hdr.reply_len - (int)SZ_SG_HEADER,
+			       input_size, (unsigned int) cmnd[0],
+			       current->comm);
+	k = sg_common_write(sfp, srp, cmnd, sfp->timeout, blocking);
+	return (k < 0) ? k : count;
+}
+
+static ssize_t
+sg_new_write(Sg_fd * sfp, const char __user *buf, size_t count,
+	     int blocking, int read_only, Sg_request ** o_srp)
+{
+	int k;
+	Sg_request *srp;
+	sg_io_hdr_t *hp;
+	unsigned char cmnd[sizeof (dummy_cmdp->sr_cmnd)];
+	int timeout;
+	unsigned long ul_timeout;
+
+	if (count < SZ_SG_IO_HDR)
+		return -EINVAL;
+	if (!access_ok(VERIFY_READ, buf, count))
+		return -EFAULT; /* protects following copy_from_user()s + get_user()s */
+
+	sfp->cmd_q = 1;	/* when sg_io_hdr seen, set command queuing on */
+	if (!(srp = sg_add_request(sfp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_new_write: queue full\n"));
+		return -EDOM;
+	}
+	hp = &srp->header;
+	if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) {
+		sg_remove_request(sfp, srp);
+		return -EFAULT;
+	}
+	if (hp->interface_id != 'S') {
+		sg_remove_request(sfp, srp);
+		return -ENOSYS;
+	}
+	if (hp->flags & SG_FLAG_MMAP_IO) {
+		if (hp->dxfer_len > sfp->reserve.bufflen) {
+			sg_remove_request(sfp, srp);
+			return -ENOMEM;	/* MMAP_IO size must fit in reserve buffer */
+		}
+		if (hp->flags & SG_FLAG_DIRECT_IO) {
+			sg_remove_request(sfp, srp);
+			return -EINVAL;	/* either MMAP_IO or DIRECT_IO (not both) */
+		}
+		if (sg_res_in_use(sfp)) {
+			sg_remove_request(sfp, srp);
+			return -EBUSY;	/* reserve buffer already being used */
+		}
+	}
+	ul_timeout = msecs_to_jiffies(srp->header.timeout);
+	timeout = (ul_timeout < INT_MAX) ? ul_timeout : INT_MAX;
+	if ((!hp->cmdp) || (hp->cmd_len < 6) || (hp->cmd_len > sizeof (cmnd))) {
+		sg_remove_request(sfp, srp);
+		return -EMSGSIZE;
+	}
+	if (!access_ok(VERIFY_READ, hp->cmdp, hp->cmd_len)) {
+		sg_remove_request(sfp, srp);
+		return -EFAULT;	/* protects following copy_from_user()s + get_user()s */
+	}
+	if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) {
+		sg_remove_request(sfp, srp);
+		return -EFAULT;
+	}
+	if (read_only &&
+	    (!sg_allow_access(cmnd[0], sfp->parentdp->device->type))) {
+		sg_remove_request(sfp, srp);
+		return -EPERM;
+	}
+	k = sg_common_write(sfp, srp, cmnd, timeout, blocking);
+	if (k < 0)
+		return k;
+	if (o_srp)
+		*o_srp = srp;
+	return count;
+}
+
+static int
+sg_common_write(Sg_fd * sfp, Sg_request * srp,
+		unsigned char *cmnd, int timeout, int blocking)
+{
+	int k;
+	Scsi_Request *SRpnt;
+	Sg_device *sdp = sfp->parentdp;
+	sg_io_hdr_t *hp = &srp->header;
+	request_queue_t *q;
+
+	srp->data.cmd_opcode = cmnd[0];	/* hold opcode of command */
+	hp->status = 0;
+	hp->masked_status = 0;
+	hp->msg_status = 0;
+	hp->info = 0;
+	hp->host_status = 0;
+	hp->driver_status = 0;
+	hp->resid = 0;
+	SCSI_LOG_TIMEOUT(4, printk("sg_common_write:  scsi opcode=0x%02x, cmd_size=%d\n",
+			  (int) cmnd[0], (int) hp->cmd_len));
+
+	if ((k = sg_start_req(srp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: start_req err=%d\n", k));
+		sg_finish_rem_req(srp);
+		return k;	/* probably out of space --> ENOMEM */
+	}
+	if ((k = sg_write_xfer(srp))) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: write_xfer, bad address\n"));
+		sg_finish_rem_req(srp);
+		return k;
+	}
+	if (sdp->detached) {
+		sg_finish_rem_req(srp);
+		return -ENODEV;
+	}
+	SRpnt = scsi_allocate_request(sdp->device, GFP_ATOMIC);
+	if (SRpnt == NULL) {
+		SCSI_LOG_TIMEOUT(1, printk("sg_write: no mem\n"));
+		sg_finish_rem_req(srp);
+		return -ENOMEM;
+	}
+
+	srp->my_cmdp = SRpnt;
+	q = SRpnt->sr_device->request_queue;
+	SRpnt->sr_request->rq_disk = sdp->disk;
+	SRpnt->sr_sense_buffer[0] = 0;
+	SRpnt->sr_cmd_len = hp->cmd_len;
+	SRpnt->sr_use_sg = srp->data.k_use_sg;
+	SRpnt->sr_sglist_len = srp->data.sglist_len;
+	SRpnt->sr_bufflen = srp->data.bufflen;
+	SRpnt->sr_underflow = 0;
+	SRpnt->sr_buffer = srp->data.buffer;
+	switch (hp->dxfer_direction) {
+	case SG_DXFER_TO_FROM_DEV:
+	case SG_DXFER_FROM_DEV:
+		SRpnt->sr_data_direction = SCSI_DATA_READ;
+		break;
+	case SG_DXFER_TO_DEV:
+		SRpnt->sr_data_direction = SCSI_DATA_WRITE;
+		break;
+	case SG_DXFER_UNKNOWN:
+		SRpnt->sr_data_direction = SCSI_DATA_UNKNOWN;
+		break;
+	default:
+		SRpnt->sr_data_direction = SCSI_DATA_NONE;
+		break;
+	}
+	SRpnt->upper_private_data = srp;
+	srp->data.k_use_sg = 0;
+	srp->data.sglist_len = 0;
+	srp->data.bufflen = 0;
+	srp->data.buffer = NULL;
+	hp->duration = jiffies;	/* unit jiffies now, millisecs after done */
+/* Now send everything of to mid-level. The next time we hear about this
+   packet is when sg_cmd_done() is called (i.e. a callback). */
+	scsi_do_req(SRpnt, (void *) cmnd,
+		    (void *) SRpnt->sr_buffer, hp->dxfer_len,
+		    sg_cmd_done, timeout, SG_DEFAULT_RETRIES);
+	/* dxfer_len overwrites SRpnt->sr_bufflen, hence need for b_malloc_len */
+	return 0;
+}
+
+static int
+sg_srp_done(Sg_request *srp, Sg_fd *sfp)
+{
+	unsigned long iflags;
+	int done;
+
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	done = srp->done;
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return done;
+}
+
+static int
+sg_ioctl(struct inode *inode, struct file *filp,
+	 unsigned int cmd_in, unsigned long arg)
+{
+	void __user *p = (void __user *)arg;
+	int __user *ip = p;
+	int result, val, read_only;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	unsigned long iflags;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_ioctl: %s, cmd=0x%x\n",
+				   sdp->disk->disk_name, (int) cmd_in));
+	read_only = (O_RDWR != (filp->f_flags & O_ACCMODE));
+
+	switch (cmd_in) {
+	case SG_IO:
+		{
+			int blocking = 1;	/* ignore O_NONBLOCK flag */
+
+			if (sdp->detached)
+				return -ENODEV;
+			if (!scsi_block_when_processing_errors(sdp->device))
+				return -ENXIO;
+			if (!access_ok(VERIFY_WRITE, p, SZ_SG_IO_HDR))
+				return -EFAULT;
+			result =
+			    sg_new_write(sfp, p, SZ_SG_IO_HDR,
+					 blocking, read_only, &srp);
+			if (result < 0)
+				return result;
+			srp->sg_io_owned = 1;
+			while (1) {
+				result = 0;	/* following macro to beat race condition */
+				__wait_event_interruptible(sfp->read_wait,
+					(sdp->detached || sfp->closed || sg_srp_done(srp, sfp)),
+							   result);
+				if (sdp->detached)
+					return -ENODEV;
+				if (sfp->closed)
+					return 0;	/* request packet dropped already */
+				if (0 == result)
+					break;
+				srp->orphan = 1;
+				return result;	/* -ERESTARTSYS because signal hit process */
+			}
+			write_lock_irqsave(&sfp->rq_list_lock, iflags);
+			srp->done = 2;
+			write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+			result = sg_new_read(sfp, p, SZ_SG_IO_HDR, srp);
+			return (result < 0) ? result : 0;
+		}
+	case SG_SET_TIMEOUT:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		if (val < 0)
+			return -EIO;
+		if (val >= MULDIV (INT_MAX, USER_HZ, HZ))
+		    val = MULDIV (INT_MAX, USER_HZ, HZ);
+		sfp->timeout_user = val;
+		sfp->timeout = MULDIV (val, HZ, USER_HZ);
+
+		return 0;
+	case SG_GET_TIMEOUT:	/* N.B. User receives timeout as return value */
+				/* strange ..., for backward compatibility */
+		return sfp->timeout_user;
+	case SG_SET_FORCE_LOW_DMA:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		if (val) {
+			sfp->low_dma = 1;
+			if ((0 == sfp->low_dma) && (0 == sg_res_in_use(sfp))) {
+				val = (int) sfp->reserve.bufflen;
+				sg_remove_scat(&sfp->reserve);
+				sg_build_reserve(sfp, val);
+			}
+		} else {
+			if (sdp->detached)
+				return -ENODEV;
+			sfp->low_dma = sdp->device->host->unchecked_isa_dma;
+		}
+		return 0;
+	case SG_GET_LOW_DMA:
+		return put_user((int) sfp->low_dma, ip);
+	case SG_GET_SCSI_ID:
+		if (!access_ok(VERIFY_WRITE, p, sizeof (sg_scsi_id_t)))
+			return -EFAULT;
+		else {
+			sg_scsi_id_t __user *sg_idp = p;
+
+			if (sdp->detached)
+				return -ENODEV;
+			__put_user((int) sdp->device->host->host_no,
+				   &sg_idp->host_no);
+			__put_user((int) sdp->device->channel,
+				   &sg_idp->channel);
+			__put_user((int) sdp->device->id, &sg_idp->scsi_id);
+			__put_user((int) sdp->device->lun, &sg_idp->lun);
+			__put_user((int) sdp->device->type, &sg_idp->scsi_type);
+			__put_user((short) sdp->device->host->cmd_per_lun,
+				   &sg_idp->h_cmd_per_lun);
+			__put_user((short) sdp->device->queue_depth,
+				   &sg_idp->d_queue_depth);
+			__put_user(0, &sg_idp->unused[0]);
+			__put_user(0, &sg_idp->unused[1]);
+			return 0;
+		}
+	case SG_SET_FORCE_PACK_ID:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		sfp->force_packid = val ? 1 : 0;
+		return 0;
+	case SG_GET_PACK_ID:
+		if (!access_ok(VERIFY_WRITE, ip, sizeof (int)))
+			return -EFAULT;
+		read_lock_irqsave(&sfp->rq_list_lock, iflags);
+		for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+			if ((1 == srp->done) && (!srp->sg_io_owned)) {
+				read_unlock_irqrestore(&sfp->rq_list_lock,
+						       iflags);
+				__put_user(srp->header.pack_id, ip);
+				return 0;
+			}
+		}
+		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+		__put_user(-1, ip);
+		return 0;
+	case SG_GET_NUM_WAITING:
+		read_lock_irqsave(&sfp->rq_list_lock, iflags);
+		for (val = 0, srp = sfp->headrp; srp; srp = srp->nextrp) {
+			if ((1 == srp->done) && (!srp->sg_io_owned))
+				++val;
+		}
+		read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+		return put_user(val, ip);
+	case SG_GET_SG_TABLESIZE:
+		return put_user(sdp->sg_tablesize, ip);
+	case SG_SET_RESERVED_SIZE:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+                if (val < 0)
+                        return -EINVAL;
+		if (val != sfp->reserve.bufflen) {
+			if (sg_res_in_use(sfp) || sfp->mmap_called)
+				return -EBUSY;
+			sg_remove_scat(&sfp->reserve);
+			sg_build_reserve(sfp, val);
+		}
+		return 0;
+	case SG_GET_RESERVED_SIZE:
+		val = (int) sfp->reserve.bufflen;
+		return put_user(val, ip);
+	case SG_SET_COMMAND_Q:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		sfp->cmd_q = val ? 1 : 0;
+		return 0;
+	case SG_GET_COMMAND_Q:
+		return put_user((int) sfp->cmd_q, ip);
+	case SG_SET_KEEP_ORPHAN:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		sfp->keep_orphan = val;
+		return 0;
+	case SG_GET_KEEP_ORPHAN:
+		return put_user((int) sfp->keep_orphan, ip);
+	case SG_NEXT_CMD_LEN:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		sfp->next_cmd_len = (val > 0) ? val : 0;
+		return 0;
+	case SG_GET_VERSION_NUM:
+		return put_user(sg_version_num, ip);
+	case SG_GET_ACCESS_COUNT:
+		/* faked - we don't have a real access count anymore */
+		val = (sdp->device ? 1 : 0);
+		return put_user(val, ip);
+	case SG_GET_REQUEST_TABLE:
+		if (!access_ok(VERIFY_WRITE, p, SZ_SG_REQ_INFO * SG_MAX_QUEUE))
+			return -EFAULT;
+		else {
+			sg_req_info_t rinfo[SG_MAX_QUEUE];
+			Sg_request *srp;
+			read_lock_irqsave(&sfp->rq_list_lock, iflags);
+			for (srp = sfp->headrp, val = 0; val < SG_MAX_QUEUE;
+			     ++val, srp = srp ? srp->nextrp : srp) {
+				memset(&rinfo[val], 0, SZ_SG_REQ_INFO);
+				if (srp) {
+					rinfo[val].req_state = srp->done + 1;
+					rinfo[val].problem =
+					    srp->header.masked_status & 
+					    srp->header.host_status & 
+					    srp->header.driver_status;
+					rinfo[val].duration =
+					    srp->done ? srp->header.duration :
+					    jiffies_to_msecs(
+						jiffies - srp->header.duration);
+					rinfo[val].orphan = srp->orphan;
+					rinfo[val].sg_io_owned = srp->sg_io_owned;
+					rinfo[val].pack_id = srp->header.pack_id;
+					rinfo[val].usr_ptr = srp->header.usr_ptr;
+				}
+			}
+			read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+			return (__copy_to_user(p, rinfo,
+			        SZ_SG_REQ_INFO * SG_MAX_QUEUE) ? -EFAULT : 0);
+		}
+	case SG_EMULATED_HOST:
+		if (sdp->detached)
+			return -ENODEV;
+		return put_user(sdp->device->host->hostt->emulated, ip);
+	case SG_SCSI_RESET:
+		if (sdp->detached)
+			return -ENODEV;
+		if (filp->f_flags & O_NONBLOCK) {
+			if (test_bit(SHOST_RECOVERY,
+				     &sdp->device->host->shost_state))
+				return -EBUSY;
+		} else if (!scsi_block_when_processing_errors(sdp->device))
+			return -EBUSY;
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		if (SG_SCSI_RESET_NOTHING == val)
+			return 0;
+		switch (val) {
+		case SG_SCSI_RESET_DEVICE:
+			val = SCSI_TRY_RESET_DEVICE;
+			break;
+		case SG_SCSI_RESET_BUS:
+			val = SCSI_TRY_RESET_BUS;
+			break;
+		case SG_SCSI_RESET_HOST:
+			val = SCSI_TRY_RESET_HOST;
+			break;
+		default:
+			return -EINVAL;
+		}
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			return -EACCES;
+		return (scsi_reset_provider(sdp->device, val) ==
+			SUCCESS) ? 0 : -EIO;
+	case SCSI_IOCTL_SEND_COMMAND:
+		if (sdp->detached)
+			return -ENODEV;
+		if (read_only) {
+			unsigned char opcode = WRITE_6;
+			Scsi_Ioctl_Command __user *siocp = p;
+
+			if (copy_from_user(&opcode, siocp->data, 1))
+				return -EFAULT;
+			if (!sg_allow_access(opcode, sdp->device->type))
+				return -EPERM;
+		}
+		return scsi_ioctl_send_command(sdp->device, p);
+	case SG_SET_DEBUG:
+		result = get_user(val, ip);
+		if (result)
+			return result;
+		sdp->sgdebug = (char) val;
+		return 0;
+	case SCSI_IOCTL_GET_IDLUN:
+	case SCSI_IOCTL_GET_BUS_NUMBER:
+	case SCSI_IOCTL_PROBE_HOST:
+	case SG_GET_TRANSFORM:
+		if (sdp->detached)
+			return -ENODEV;
+		return scsi_ioctl(sdp->device, cmd_in, p);
+	default:
+		if (read_only)
+			return -EPERM;	/* don't know so take safe approach */
+		return scsi_ioctl(sdp->device, cmd_in, p);
+	}
+}
+
+#ifdef CONFIG_COMPAT
+static long sg_compat_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
+{
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	struct scsi_device *sdev;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+
+	sdev = sdp->device;
+	if (sdev->host->hostt->compat_ioctl) { 
+		int ret;
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg);
+
+		return ret;
+	}
+	
+	return -ENOIOCTLCMD;
+}
+#endif
+
+static unsigned int
+sg_poll(struct file *filp, poll_table * wait)
+{
+	unsigned int res = 0;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+	Sg_request *srp;
+	int count = 0;
+	unsigned long iflags;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp))
+	    || sfp->closed)
+		return POLLERR;
+	poll_wait(filp, &sfp->read_wait, wait);
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (srp = sfp->headrp; srp; srp = srp->nextrp) {
+		/* if any read waiting, flag it */
+		if ((0 == res) && (1 == srp->done) && (!srp->sg_io_owned))
+			res = POLLIN | POLLRDNORM;
+		++count;
+	}
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+
+	if (sdp->detached)
+		res |= POLLHUP;
+	else if (!sfp->cmd_q) {
+		if (0 == count)
+			res |= POLLOUT | POLLWRNORM;
+	} else if (count < SG_MAX_QUEUE)
+		res |= POLLOUT | POLLWRNORM;
+	SCSI_LOG_TIMEOUT(3, printk("sg_poll: %s, res=0x%x\n",
+				   sdp->disk->disk_name, (int) res));
+	return res;
+}
+
+static int
+sg_fasync(int fd, struct file *filp, int mode)
+{
+	int retval;
+	Sg_device *sdp;
+	Sg_fd *sfp;
+
+	if ((!(sfp = (Sg_fd *) filp->private_data)) || (!(sdp = sfp->parentdp)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n",
+				   sdp->disk->disk_name, mode));
+
+	retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
+	return (retval < 0) ? retval : 0;
+}
+
+static inline unsigned char *
+sg_scatg2virt(const struct scatterlist *sclp)
+{
+	return (sclp && sclp->page) ?
+	    (unsigned char *) page_address(sclp->page) + sclp->offset : NULL;
+}
+
+/* When startFinish==1 increments page counts for pages other than the 
+   first of scatter gather elements obtained from __get_free_pages().
+   When startFinish==0 decrements ... */
+static void
+sg_rb_correct4mmap(Sg_scatter_hold * rsv_schp, int startFinish)
+{
+	void *page_ptr;
+	struct page *page;
+	int k, m;
+
+	SCSI_LOG_TIMEOUT(3, printk("sg_rb_correct4mmap: startFinish=%d, scatg=%d\n", 
+				   startFinish, rsv_schp->k_use_sg));
+	/* N.B. correction _not_ applied to base page of each allocation */
+	if (rsv_schp->k_use_sg) {	/* reserve buffer is a scatter gather list */
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+			for (m = PAGE_SIZE; m < sclp->length; m += PAGE_SIZE) {
+				page_ptr = sg_scatg2virt(sclp) + m;
+				page = virt_to_page(page_ptr);
+				if (startFinish)
+					get_page(page);
+				else {
+					if (page_count(page) > 0)
+						__put_page(page);
+				}
+			}
+		}
+	} else {		/* reserve buffer is just a single allocation */
+		for (m = PAGE_SIZE; m < rsv_schp->bufflen; m += PAGE_SIZE) {
+			page_ptr = (unsigned char *) rsv_schp->buffer + m;
+			page = virt_to_page(page_ptr);
+			if (startFinish)
+				get_page(page);
+			else {
+				if (page_count(page) > 0)
+					__put_page(page);
+			}
+		}
+	}
+}
+
+static struct page *
+sg_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)
+{
+	Sg_fd *sfp;
+	struct page *page = NOPAGE_SIGBUS;
+	void *page_ptr = NULL;
+	unsigned long offset;
+	Sg_scatter_hold *rsv_schp;
+
+	if ((NULL == vma) || (!(sfp = (Sg_fd *) vma->vm_private_data)))
+		return page;
+	rsv_schp = &sfp->reserve;
+	offset = addr - vma->vm_start;
+	if (offset >= rsv_schp->bufflen)
+		return page;
+	SCSI_LOG_TIMEOUT(3, printk("sg_vma_nopage: offset=%lu, scatg=%d\n",
+				   offset, rsv_schp->k_use_sg));
+	if (rsv_schp->k_use_sg) {	/* reserve buffer is a scatter gather list */
+		int k;
+		unsigned long sa = vma->vm_start;
+		unsigned long len;
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+		     ++k, ++sclp) {
+			len = vma->vm_end - sa;
+			len = (len < sclp->length) ? len : sclp->length;
+			if (offset < len) {
+				page_ptr = sg_scatg2virt(sclp) + offset;
+				page = virt_to_page(page_ptr);
+				get_page(page);	/* increment page count */
+				break;
+			}
+			sa += len;
+			offset -= len;
+		}
+	} else {		/* reserve buffer is just a single allocation */
+		page_ptr = (unsigned char *) rsv_schp->buffer + offset;
+		page = virt_to_page(page_ptr);
+		get_page(page);	/* increment page count */
+	}
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return page;
+}
+
+static struct vm_operations_struct sg_mmap_vm_ops = {
+	.nopage = sg_vma_nopage,
+};
+
+static int
+sg_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	Sg_fd *sfp;
+	unsigned long req_sz = vma->vm_end - vma->vm_start;
+	Sg_scatter_hold *rsv_schp;
+
+	if ((!filp) || (!vma) || (!(sfp = (Sg_fd *) filp->private_data)))
+		return -ENXIO;
+	SCSI_LOG_TIMEOUT(3, printk("sg_mmap starting, vm_start=%p, len=%d\n",
+				   (void *) vma->vm_start, (int) req_sz));
+	if (vma->vm_pgoff)
+		return -EINVAL;	/* want no offset */
+	rsv_schp = &sfp->reserve;
+	if (req_sz > rsv_schp->bufflen)
+		return -ENOMEM;	/* cannot map more than reserved buffer */
+
+	if (rsv_schp->k_use_sg) { /* reserve buffer is a scatter gather list */
+		int k;
+		unsigned long sa = vma->vm_start;
+		unsigned long len;
+		struct scatterlist *sclp = rsv_schp->buffer;
+
+		for (k = 0; (k < rsv_schp->k_use_sg) && (sa < vma->vm_end);
+		     ++k, ++sclp) {
+			if (0 != sclp->offset)
+				return -EFAULT;	/* non page aligned memory ?? */
+			len = vma->vm_end - sa;
+			len = (len < sclp->length) ? len : sclp->length;
+			sa += len;
+		}
+	} else {	/* reserve buffer is just a single allocation */
+		if ((unsigned long) rsv_schp->buffer & (PAGE_SIZE - 1))
+			return -EFAULT;	/* non page aligned memory ?? */
+	}
+	if (0 == sfp->mmap_called) {
+		sg_rb_correct4mmap(rsv_schp, 1);	/* do only once per fd lifetime */
+		sfp->mmap_called = 1;
+	}
+	vma->vm_flags |= (VM_RESERVED | VM_IO);
+	vma->vm_private_data = sfp;
+	vma->vm_ops = &sg_mmap_vm_ops;
+	return 0;
+}
+
+/* This function is a "bottom half" handler that is called by the
+ * mid level when a command is completed (or has failed). */
+static void
+sg_cmd_done(Scsi_Cmnd * SCpnt)
+{
+	Scsi_Request *SRpnt = NULL;
+	Sg_device *sdp = NULL;
+	Sg_fd *sfp;
+	Sg_request *srp = NULL;
+	unsigned long iflags;
+
+	if (SCpnt && (SRpnt = SCpnt->sc_request))
+		srp = (Sg_request *) SRpnt->upper_private_data;
+	if (NULL == srp) {
+		printk(KERN_ERR "sg_cmd_done: NULL request\n");
+		if (SRpnt)
+			scsi_release_request(SRpnt);
+		return;
+	}
+	sfp = srp->parentfp;
+	if (sfp)
+		sdp = sfp->parentdp;
+	if ((NULL == sdp) || sdp->detached) {
+		printk(KERN_INFO "sg_cmd_done: device detached\n");
+		scsi_release_request(SRpnt);
+		return;
+	}
+
+	/* First transfer ownership of data buffers to sg_device object. */
+	srp->data.k_use_sg = SRpnt->sr_use_sg;
+	srp->data.sglist_len = SRpnt->sr_sglist_len;
+	srp->data.bufflen = SRpnt->sr_bufflen;
+	srp->data.buffer = SRpnt->sr_buffer;
+	/* now clear out request structure */
+	SRpnt->sr_use_sg = 0;
+	SRpnt->sr_sglist_len = 0;
+	SRpnt->sr_bufflen = 0;
+	SRpnt->sr_buffer = NULL;
+	SRpnt->sr_underflow = 0;
+	SRpnt->sr_request->rq_disk = NULL; /* "sg" _disowns_ request blk */
+
+	srp->my_cmdp = NULL;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_cmd_done: %s, pack_id=%d, res=0x%x\n",
+		sdp->disk->disk_name, srp->header.pack_id, (int) SRpnt->sr_result));
+	srp->header.resid = SCpnt->resid;
+	/* N.B. unit of duration changes here from jiffies to millisecs */
+	srp->header.duration =
+	    jiffies_to_msecs(jiffies - srp->header.duration);
+	if (0 != SRpnt->sr_result) {
+		struct scsi_sense_hdr sshdr;
+
+		memcpy(srp->sense_b, SRpnt->sr_sense_buffer,
+		       sizeof (srp->sense_b));
+		srp->header.status = 0xff & SRpnt->sr_result;
+		srp->header.masked_status = status_byte(SRpnt->sr_result);
+		srp->header.msg_status = msg_byte(SRpnt->sr_result);
+		srp->header.host_status = host_byte(SRpnt->sr_result);
+		srp->header.driver_status = driver_byte(SRpnt->sr_result);
+		if ((sdp->sgdebug > 0) &&
+		    ((CHECK_CONDITION == srp->header.masked_status) ||
+		     (COMMAND_TERMINATED == srp->header.masked_status)))
+			print_req_sense("sg_cmd_done", SRpnt);
+
+		/* Following if statement is a patch supplied by Eric Youngdale */
+		if (driver_byte(SRpnt->sr_result) != 0
+		    && scsi_command_normalize_sense(SCpnt, &sshdr)
+		    && !scsi_sense_is_deferred(&sshdr)
+		    && sshdr.sense_key == UNIT_ATTENTION
+		    && sdp->device->removable) {
+			/* Detected possible disc change. Set the bit - this */
+			/* may be used if there are filesystems using this device */
+			sdp->device->changed = 1;
+		}
+	}
+	/* Rely on write phase to clean out srp status values, so no "else" */
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+	if (sfp->closed) {	/* whoops this fd already released, cleanup */
+		SCSI_LOG_TIMEOUT(1, printk("sg_cmd_done: already closed, freeing ...\n"));
+		sg_finish_rem_req(srp);
+		srp = NULL;
+		if (NULL == sfp->headrp) {
+			SCSI_LOG_TIMEOUT(1, printk("sg...bh: already closed, final cleanup\n"));
+			if (0 == sg_remove_sfp(sdp, sfp)) {	/* device still present */
+				scsi_device_put(sdp->device);
+			}
+			sfp = NULL;
+		}
+	} else if (srp && srp->orphan) {
+		if (sfp->keep_orphan)
+			srp->sg_io_owned = 0;
+		else {
+			sg_finish_rem_req(srp);
+			srp = NULL;
+		}
+	}
+	if (sfp && srp) {
+		/* Now wake up any sg_read() that is waiting for this packet. */
+		kill_fasync(&sfp->async_qp, SIGPOLL, POLL_IN);
+		write_lock_irqsave(&sfp->rq_list_lock, iflags);
+		srp->done = 1;
+		wake_up_interruptible(&sfp->read_wait);
+		write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	}
+}
+
+static struct file_operations sg_fops = {
+	.owner = THIS_MODULE,
+	.read = sg_read,
+	.write = sg_write,
+	.poll = sg_poll,
+	.ioctl = sg_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = sg_compat_ioctl,
+#endif
+	.open = sg_open,
+	.mmap = sg_mmap,
+	.release = sg_release,
+	.fasync = sg_fasync,
+};
+
+static struct class_simple * sg_sysfs_class;
+
+static int sg_sysfs_valid = 0;
+
+static int sg_alloc(struct gendisk *disk, struct scsi_device *scsidp)
+{
+	Sg_device *sdp;
+	unsigned long iflags;
+	void *old_sg_dev_arr = NULL;
+	int k, error;
+
+	sdp = kmalloc(sizeof(Sg_device), GFP_KERNEL);
+	if (!sdp) {
+		printk(KERN_WARNING "kmalloc Sg_device failure\n");
+		return -ENOMEM;
+	}
+
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	if (unlikely(sg_nr_dev >= sg_dev_max)) {	/* try to resize */
+		Sg_device **tmp_da;
+		int tmp_dev_max = sg_nr_dev + SG_DEV_ARR_LUMP;
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+
+		tmp_da = kmalloc(tmp_dev_max * sizeof(Sg_device *), GFP_KERNEL);
+		if (unlikely(!tmp_da))
+			goto expand_failed;
+
+		write_lock_irqsave(&sg_dev_arr_lock, iflags);
+		memset(tmp_da, 0, tmp_dev_max * sizeof(Sg_device *));
+		memcpy(tmp_da, sg_dev_arr, sg_dev_max * sizeof(Sg_device *));
+		old_sg_dev_arr = sg_dev_arr;
+		sg_dev_arr = tmp_da;
+		sg_dev_max = tmp_dev_max;
+	}
+
+	for (k = 0; k < sg_dev_max; k++)
+		if (!sg_dev_arr[k])
+			break;
+	if (unlikely(k >= SG_MAX_DEVS))
+		goto overflow;
+
+	memset(sdp, 0, sizeof(*sdp));
+	SCSI_LOG_TIMEOUT(3, printk("sg_alloc: dev=%d \n", k));
+	sprintf(disk->disk_name, "sg%d", k);
+	disk->first_minor = k;
+	sdp->disk = disk;
+	sdp->device = scsidp;
+	init_waitqueue_head(&sdp->o_excl_wait);
+	sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0;
+
+	sg_nr_dev++;
+	sg_dev_arr[k] = sdp;
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	error = k;
+
+ out:
+	if (error < 0)
+		kfree(sdp);
+	kfree(old_sg_dev_arr);
+	return error;
+
+ expand_failed:
+	printk(KERN_WARNING "sg_alloc: device array cannot be resized\n");
+	error = -ENOMEM;
+	goto out;
+
+ overflow:
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	printk(KERN_WARNING
+	       "Unable to attach sg device <%d, %d, %d, %d> type=%d, minor "
+	       "number exceeds %d\n", scsidp->host->host_no, scsidp->channel,
+	       scsidp->id, scsidp->lun, scsidp->type, SG_MAX_DEVS - 1);
+	error = -ENODEV;
+	goto out;
+}
+
+static int
+sg_add(struct class_device *cl_dev)
+{
+	struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
+	struct gendisk *disk;
+	Sg_device *sdp = NULL;
+	struct cdev * cdev = NULL;
+	int error, k;
+
+	disk = alloc_disk(1);
+	if (!disk) {
+		printk(KERN_WARNING "alloc_disk failed\n");
+		return -ENOMEM;
+	}
+	disk->major = SCSI_GENERIC_MAJOR;
+
+	error = -ENOMEM;
+	cdev = cdev_alloc();
+	if (!cdev) {
+		printk(KERN_WARNING "cdev_alloc failed\n");
+		goto out;
+	}
+	cdev->owner = THIS_MODULE;
+	cdev->ops = &sg_fops;
+
+	error = sg_alloc(disk, scsidp);
+	if (error < 0) {
+		printk(KERN_WARNING "sg_alloc failed\n");
+		goto out;
+	}
+	k = error;
+	sdp = sg_dev_arr[k];
+
+	devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
+			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
+			"%s/generic", scsidp->devfs_name);
+	error = cdev_add(cdev, MKDEV(SCSI_GENERIC_MAJOR, k), 1);
+	if (error) {
+		devfs_remove("%s/generic", scsidp->devfs_name);
+		goto out;
+	}
+	sdp->cdev = cdev;
+	if (sg_sysfs_valid) {
+		struct class_device * sg_class_member;
+
+		sg_class_member = class_simple_device_add(sg_sysfs_class, 
+				MKDEV(SCSI_GENERIC_MAJOR, k), 
+				cl_dev->dev, "%s", 
+				disk->disk_name);
+		if (IS_ERR(sg_class_member))
+			printk(KERN_WARNING "sg_add: "
+				"class_simple_device_add failed\n");
+		class_set_devdata(sg_class_member, sdp);
+		error = sysfs_create_link(&scsidp->sdev_gendev.kobj, 
+					  &sg_class_member->kobj, "generic");
+		if (error)
+			printk(KERN_ERR "sg_add: unable to make symlink "
+					"'generic' back to sg%d\n", k);
+	} else
+		printk(KERN_WARNING "sg_add: sg_sys INvalid\n");
+
+	printk(KERN_NOTICE
+	       "Attached scsi generic sg%d at scsi%d, channel"
+	       " %d, id %d, lun %d,  type %d\n", k,
+	       scsidp->host->host_no, scsidp->channel, scsidp->id,
+	       scsidp->lun, scsidp->type);
+
+	return 0;
+
+out:
+	put_disk(disk);
+	if (cdev)
+		cdev_del(cdev);
+	return error;
+}
+
+static void
+sg_remove(struct class_device *cl_dev)
+{
+	struct scsi_device *scsidp = to_scsi_device(cl_dev->dev);
+	Sg_device *sdp = NULL;
+	unsigned long iflags;
+	Sg_fd *sfp;
+	Sg_fd *tsfp;
+	Sg_request *srp;
+	Sg_request *tsrp;
+	int k, delay;
+
+	if (NULL == sg_dev_arr)
+		return;
+	delay = 0;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = 0; k < sg_dev_max; k++) {
+		sdp = sg_dev_arr[k];
+		if ((NULL == sdp) || (sdp->device != scsidp))
+			continue;	/* dirty but lowers nesting */
+		if (sdp->headfp) {
+			sdp->detached = 1;
+			for (sfp = sdp->headfp; sfp; sfp = tsfp) {
+				tsfp = sfp->nextfp;
+				for (srp = sfp->headrp; srp; srp = tsrp) {
+					tsrp = srp->nextrp;
+					if (sfp->closed || (0 == sg_srp_done(srp, sfp)))
+						sg_finish_rem_req(srp);
+				}
+				if (sfp->closed) {
+					scsi_device_put(sdp->device);
+					__sg_remove_sfp(sdp, sfp);
+				} else {
+					delay = 1;
+					wake_up_interruptible(&sfp->read_wait);
+					kill_fasync(&sfp->async_qp, SIGPOLL,
+						    POLL_HUP);
+				}
+			}
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d, dirty\n", k));
+			if (NULL == sdp->headfp) {
+				sg_dev_arr[k] = NULL;
+			}
+		} else {	/* nothing active, simple case */
+			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
+			sg_dev_arr[k] = NULL;
+		}
+		sg_nr_dev--;
+		break;
+	}
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+
+	if (sdp) {
+		sysfs_remove_link(&scsidp->sdev_gendev.kobj, "generic");
+		class_simple_device_remove(MKDEV(SCSI_GENERIC_MAJOR, k));
+		cdev_del(sdp->cdev);
+		sdp->cdev = NULL;
+		devfs_remove("%s/generic", scsidp->devfs_name);
+		put_disk(sdp->disk);
+		sdp->disk = NULL;
+		if (NULL == sdp->headfp)
+			kfree((char *) sdp);
+	}
+
+	if (delay)
+		msleep(10);	/* dirty detach so delay device destruction */
+}
+
+/* Set 'perm' (4th argument) to 0 to disable module_param's definition
+ * of sysfs parameters (which module_param doesn't yet support).
+ * Sysfs parameters defined explicitly below.
+ */
+module_param_named(def_reserved_size, def_reserved_size, int, S_IRUGO);
+module_param_named(allow_dio, sg_allow_dio, int, S_IRUGO | S_IWUSR);
+
+MODULE_AUTHOR("Douglas Gilbert");
+MODULE_DESCRIPTION("SCSI generic (sg) driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SG_VERSION_STR);
+
+MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd");
+MODULE_PARM_DESC(allow_dio, "allow direct I/O (default: 0 (disallow))");
+
+static int __init
+init_sg(void)
+{
+	int rc;
+
+	if (def_reserved_size >= 0)
+		sg_big_buff = def_reserved_size;
+
+	rc = register_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), 
+				    SG_MAX_DEVS, "sg");
+	if (rc)
+		return rc;
+        sg_sysfs_class = class_simple_create(THIS_MODULE, "scsi_generic");
+        if ( IS_ERR(sg_sysfs_class) ) {
+		rc = PTR_ERR(sg_sysfs_class);
+		goto err_out;
+        }
+	sg_sysfs_valid = 1;
+	rc = scsi_register_interface(&sg_interface);
+	if (0 == rc) {
+#ifdef CONFIG_SCSI_PROC_FS
+		sg_proc_init();
+#endif				/* CONFIG_SCSI_PROC_FS */
+		return 0;
+	}
+	class_simple_destroy(sg_sysfs_class);
+err_out:
+	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0), SG_MAX_DEVS);
+	return rc;
+}
+
+static void __exit
+exit_sg(void)
+{
+#ifdef CONFIG_SCSI_PROC_FS
+	sg_proc_cleanup();
+#endif				/* CONFIG_SCSI_PROC_FS */
+	scsi_unregister_interface(&sg_interface);
+	class_simple_destroy(sg_sysfs_class);
+	sg_sysfs_valid = 0;
+	unregister_chrdev_region(MKDEV(SCSI_GENERIC_MAJOR, 0),
+				 SG_MAX_DEVS);
+	if (sg_dev_arr != NULL) {
+		kfree((char *) sg_dev_arr);
+		sg_dev_arr = NULL;
+	}
+	sg_dev_max = 0;
+}
+
+static int
+sg_start_req(Sg_request * srp)
+{
+	int res;
+	Sg_fd *sfp = srp->parentfp;
+	sg_io_hdr_t *hp = &srp->header;
+	int dxfer_len = (int) hp->dxfer_len;
+	int dxfer_dir = hp->dxfer_direction;
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_start_req: dxfer_len=%d\n", dxfer_len));
+	if ((dxfer_len <= 0) || (dxfer_dir == SG_DXFER_NONE))
+		return 0;
+	if (sg_allow_dio && (hp->flags & SG_FLAG_DIRECT_IO) &&
+	    (dxfer_dir != SG_DXFER_UNKNOWN) && (0 == hp->iovec_count) &&
+	    (!sfp->parentdp->device->host->unchecked_isa_dma)) {
+		res = sg_build_direct(srp, sfp, dxfer_len);
+		if (res <= 0)	/* -ve -> error, 0 -> done, 1 -> try indirect */
+			return res;
+	}
+	if ((!sg_res_in_use(sfp)) && (dxfer_len <= rsv_schp->bufflen))
+		sg_link_reserve(sfp, srp, dxfer_len);
+	else {
+		res = sg_build_indirect(req_schp, sfp, dxfer_len);
+		if (res) {
+			sg_remove_scat(req_schp);
+			return res;
+		}
+	}
+	return 0;
+}
+
+static void
+sg_finish_rem_req(Sg_request * srp)
+{
+	Sg_fd *sfp = srp->parentfp;
+	Sg_scatter_hold *req_schp = &srp->data;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_finish_rem_req: res_used=%d\n", (int) srp->res_used));
+	if (srp->res_used)
+		sg_unlink_reserve(sfp, srp);
+	else
+		sg_remove_scat(req_schp);
+	sg_remove_request(sfp, srp);
+}
+
+static int
+sg_build_sgat(Sg_scatter_hold * schp, const Sg_fd * sfp, int tablesize)
+{
+	int ret_sz;
+	int elem_sz = sizeof (struct scatterlist);
+	int sg_bufflen = tablesize * elem_sz;
+	int mx_sc_elems = tablesize;
+
+	schp->buffer = sg_page_malloc(sg_bufflen, sfp->low_dma, &ret_sz);
+	if (!schp->buffer)
+		return -ENOMEM;
+	else if (ret_sz != sg_bufflen) {
+		sg_bufflen = ret_sz;
+		mx_sc_elems = sg_bufflen / elem_sz;
+	}
+	schp->sglist_len = sg_bufflen;
+	memset(schp->buffer, 0, sg_bufflen);
+	return mx_sc_elems;	/* number of scat_gath elements allocated */
+}
+
+#ifdef SG_ALLOW_DIO_CODE
+/* vvvvvvvv  following code borrowed from st driver's direct IO vvvvvvvvv */
+	/* hopefully this generic code will moved to a library */
+
+/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
+   - mapping of all pages not successful
+   - any page is above max_pfn
+   (i.e., either completely successful or fails)
+*/
+static int 
+st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+	          unsigned long uaddr, size_t count, int rw,
+	          unsigned long max_pfn)
+{
+	int res, i, j;
+	unsigned int nr_pages;
+	struct page **pages;
+
+	nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
+
+	/* User attempted Overflow! */
+	if ((uaddr + count) < uaddr)
+		return -EINVAL;
+
+	/* Too big */
+        if (nr_pages > max_pages)
+		return -ENOMEM;
+
+	/* Hmm? */
+	if (count == 0)
+		return 0;
+
+	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_ATOMIC)) == NULL)
+		return -ENOMEM;
+
+        /* Try to fault in all of the necessary pages */
+	down_read(&current->mm->mmap_sem);
+        /* rw==READ means read from drive, write into memory area */
+	res = get_user_pages(
+		current,
+		current->mm,
+		uaddr,
+		nr_pages,
+		rw == READ,
+		0, /* don't force */
+		pages,
+		NULL);
+	up_read(&current->mm->mmap_sem);
+
+	/* Errors and no page mapped should return here */
+	if (res < nr_pages)
+		goto out_unmap;
+
+        for (i=0; i < nr_pages; i++) {
+                /* FIXME: flush superflous for rw==READ,
+                 * probably wrong function for rw==WRITE
+                 */
+		flush_dcache_page(pages[i]);
+		if (page_to_pfn(pages[i]) > max_pfn)
+			goto out_unlock;
+		/* ?? Is locking needed? I don't think so */
+		/* if (TestSetPageLocked(pages[i]))
+		   goto out_unlock; */
+        }
+
+	/* Populate the scatter/gather list */
+	sgl[0].page = pages[0]; 
+	sgl[0].offset = uaddr & ~PAGE_MASK;
+	if (nr_pages > 1) {
+		sgl[0].length = PAGE_SIZE - sgl[0].offset;
+		count -= sgl[0].length;
+		for (i=1; i < nr_pages ; i++) {
+			sgl[i].offset = 0;
+			sgl[i].page = pages[i]; 
+			sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+			count -= PAGE_SIZE;
+		}
+	}
+	else {
+		sgl[0].length = count;
+	}
+
+	kfree(pages);
+	return nr_pages;
+
+ out_unlock:
+	/* for (j=0; j < i; j++)
+	   unlock_page(pages[j]); */
+	res = 0;
+ out_unmap:
+	if (res > 0)
+		for (j=0; j < res; j++)
+			page_cache_release(pages[j]);
+	kfree(pages);
+	return res;
+}
+
+
+/* And unmap them... */
+static int 
+st_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
+		    int dirtied)
+{
+	int i;
+
+	for (i=0; i < nr_pages; i++) {
+		if (dirtied && !PageReserved(sgl[i].page))
+			SetPageDirty(sgl[i].page);
+		/* unlock_page(sgl[i].page); */
+		/* FIXME: cache flush missing for rw==READ
+		 * FIXME: call the correct reference counting function
+		 */
+		page_cache_release(sgl[i].page);
+	}
+
+	return 0;
+}
+
+/* ^^^^^^^^  above code borrowed from st driver's direct IO ^^^^^^^^^ */
+#endif
+
+
+/* Returns: -ve -> error, 0 -> done, 1 -> try indirect */
+static int
+sg_build_direct(Sg_request * srp, Sg_fd * sfp, int dxfer_len)
+{
+#ifdef SG_ALLOW_DIO_CODE
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int sg_tablesize = sfp->parentdp->sg_tablesize;
+	struct scatterlist *sgl;
+	int mx_sc_elems, res;
+	struct scsi_device *sdev = sfp->parentdp->device;
+
+	if (((unsigned long)hp->dxferp &
+			queue_dma_alignment(sdev->request_queue)) != 0)
+		return 1;
+	mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
+        if (mx_sc_elems <= 0) {
+                return 1;
+        }
+	sgl = (struct scatterlist *)schp->buffer;
+	res = st_map_user_pages(sgl, mx_sc_elems, (unsigned long)hp->dxferp, dxfer_len, 
+				(SG_DXFER_TO_DEV == hp->dxfer_direction) ? 1 : 0, ULONG_MAX);
+	if (res <= 0)
+		return 1;
+	schp->k_use_sg = res;
+	schp->dio_in_use = 1;
+	hp->info |= SG_INFO_DIRECT_IO;
+	return 0;
+#else
+	return 1;
+#endif
+}
+
+static int
+sg_build_indirect(Sg_scatter_hold * schp, Sg_fd * sfp, int buff_size)
+{
+	int ret_sz;
+	int blk_size = buff_size;
+	unsigned char *p = NULL;
+
+	if ((blk_size < 0) || (!sfp))
+		return -EFAULT;
+	if (0 == blk_size)
+		++blk_size;	/* don't know why */
+/* round request up to next highest SG_SECTOR_SZ byte boundary */
+	blk_size = (blk_size + SG_SECTOR_MSK) & (~SG_SECTOR_MSK);
+	SCSI_LOG_TIMEOUT(4, printk("sg_build_indirect: buff_size=%d, blk_size=%d\n",
+				   buff_size, blk_size));
+	if (blk_size <= SG_SCATTER_SZ) {
+		p = sg_page_malloc(blk_size, sfp->low_dma, &ret_sz);
+		if (!p)
+			return -ENOMEM;
+		if (blk_size == ret_sz) {	/* got it on the first attempt */
+			schp->k_use_sg = 0;
+			schp->buffer = p;
+			schp->bufflen = blk_size;
+			schp->b_malloc_len = blk_size;
+			return 0;
+		}
+	} else {
+		p = sg_page_malloc(SG_SCATTER_SZ, sfp->low_dma, &ret_sz);
+		if (!p)
+			return -ENOMEM;
+	}
+/* Want some local declarations, so start new block ... */
+	{			/* lets try and build a scatter gather list */
+		struct scatterlist *sclp;
+		int k, rem_sz, num;
+		int mx_sc_elems;
+		int sg_tablesize = sfp->parentdp->sg_tablesize;
+		int first = 1;
+
+		/* N.B. ret_sz carried into this block ... */
+		mx_sc_elems = sg_build_sgat(schp, sfp, sg_tablesize);
+		if (mx_sc_elems < 0)
+			return mx_sc_elems;	/* most likely -ENOMEM */
+
+		for (k = 0, sclp = schp->buffer, rem_sz = blk_size;
+		     (rem_sz > 0) && (k < mx_sc_elems);
+		     ++k, rem_sz -= ret_sz, ++sclp) {
+			if (first)
+				first = 0;
+			else {
+				num =
+				    (rem_sz >
+				     SG_SCATTER_SZ) ? SG_SCATTER_SZ : rem_sz;
+				p = sg_page_malloc(num, sfp->low_dma, &ret_sz);
+				if (!p)
+					break;
+			}
+			sclp->page = virt_to_page(p);
+			sclp->offset = offset_in_page(p);
+			sclp->length = ret_sz;
+
+			SCSI_LOG_TIMEOUT(5, printk("sg_build_build: k=%d, a=0x%p, len=%d\n",
+					  k, sg_scatg2virt(sclp), ret_sz));
+		}		/* end of for loop */
+		schp->k_use_sg = k;
+		SCSI_LOG_TIMEOUT(5, printk("sg_build_indirect: k_use_sg=%d, rem_sz=%d\n", k, rem_sz));
+		schp->bufflen = blk_size;
+		if (rem_sz > 0)	/* must have failed */
+			return -ENOMEM;
+	}
+	return 0;
+}
+
+static int
+sg_write_xfer(Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int num_xfer = 0;
+	int j, k, onum, usglen, ksglen, res;
+	int iovec_count = (int) hp->iovec_count;
+	int dxfer_dir = hp->dxfer_direction;
+	unsigned char *p;
+	unsigned char __user *up;
+	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
+
+	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_TO_DEV == dxfer_dir) ||
+	    (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
+		num_xfer = (int) (new_interface ? hp->dxfer_len : hp->flags);
+		if (schp->bufflen < num_xfer)
+			num_xfer = schp->bufflen;
+	}
+	if ((num_xfer <= 0) || (schp->dio_in_use) ||
+	    (new_interface
+	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+		return 0;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_write_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
+			  num_xfer, iovec_count, schp->k_use_sg));
+	if (iovec_count) {
+		onum = iovec_count;
+		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
+			return -EFAULT;
+	} else
+		onum = 1;
+
+	if (0 == schp->k_use_sg) {	/* kernel has single buffer */
+		for (j = 0, p = schp->buffer; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
+			if (res)
+				return res;
+			usglen = (num_xfer > usglen) ? usglen : num_xfer;
+			if (__copy_from_user(p, up, usglen))
+				return -EFAULT;
+			p += usglen;
+			num_xfer -= usglen;
+			if (num_xfer <= 0)
+				return 0;
+		}
+	} else {		/* kernel using scatter gather list */
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		ksglen = (int) sclp->length;
+		p = sg_scatg2virt(sclp);
+		for (j = 0, k = 0; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 1, &usglen, &up);
+			if (res)
+				return res;
+
+			for (; p; ++sclp, ksglen = (int) sclp->length,
+				  p = sg_scatg2virt(sclp)) {
+				if (usglen <= 0)
+					break;
+				if (ksglen > usglen) {
+					if (usglen >= num_xfer) {
+						if (__copy_from_user
+						    (p, up, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_from_user(p, up, usglen))
+						return -EFAULT;
+					p += usglen;
+					ksglen -= usglen;
+					break;
+				} else {
+					if (ksglen >= num_xfer) {
+						if (__copy_from_user
+						    (p, up, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_from_user(p, up, ksglen))
+						return -EFAULT;
+					up += ksglen;
+					usglen -= ksglen;
+				}
+				++k;
+				if (k >= schp->k_use_sg)
+					return 0;
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+sg_u_iovec(sg_io_hdr_t * hp, int sg_num, int ind,
+	   int wr_xf, int *countp, unsigned char __user **up)
+{
+	int num_xfer = (int) hp->dxfer_len;
+	unsigned char __user *p = hp->dxferp;
+	int count;
+
+	if (0 == sg_num) {
+		if (wr_xf && ('\0' == hp->interface_id))
+			count = (int) hp->flags;	/* holds "old" input_size */
+		else
+			count = num_xfer;
+	} else {
+		sg_iovec_t iovec;
+		if (__copy_from_user(&iovec, p + ind*SZ_SG_IOVEC, SZ_SG_IOVEC))
+			return -EFAULT;
+		p = iovec.iov_base;
+		count = (int) iovec.iov_len;
+	}
+	if (!access_ok(wr_xf ? VERIFY_READ : VERIFY_WRITE, p, count))
+		return -EFAULT;
+	if (up)
+		*up = p;
+	if (countp)
+		*countp = count;
+	return 0;
+}
+
+static void
+sg_remove_scat(Sg_scatter_hold * schp)
+{
+	SCSI_LOG_TIMEOUT(4, printk("sg_remove_scat: k_use_sg=%d\n", schp->k_use_sg));
+	if (schp->buffer && (schp->sglist_len > 0)) {
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		if (schp->dio_in_use) {
+#ifdef SG_ALLOW_DIO_CODE
+			st_unmap_user_pages(sclp, schp->k_use_sg, TRUE);
+#endif
+		} else {
+			int k;
+
+			for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp);
+			     ++k, ++sclp) {
+				SCSI_LOG_TIMEOUT(5, printk(
+				    "sg_remove_scat: k=%d, a=0x%p, len=%d\n",
+				    k, sg_scatg2virt(sclp), sclp->length));
+				sg_page_free(sg_scatg2virt(sclp), sclp->length);
+				sclp->page = NULL;
+				sclp->offset = 0;
+				sclp->length = 0;
+			}
+		}
+		sg_page_free(schp->buffer, schp->sglist_len);
+	} else if (schp->buffer)
+		sg_page_free(schp->buffer, schp->b_malloc_len);
+	memset(schp, 0, sizeof (*schp));
+}
+
+static int
+sg_read_xfer(Sg_request * srp)
+{
+	sg_io_hdr_t *hp = &srp->header;
+	Sg_scatter_hold *schp = &srp->data;
+	int num_xfer = 0;
+	int j, k, onum, usglen, ksglen, res;
+	int iovec_count = (int) hp->iovec_count;
+	int dxfer_dir = hp->dxfer_direction;
+	unsigned char *p;
+	unsigned char __user *up;
+	int new_interface = ('\0' == hp->interface_id) ? 0 : 1;
+
+	if ((SG_DXFER_UNKNOWN == dxfer_dir) || (SG_DXFER_FROM_DEV == dxfer_dir)
+	    || (SG_DXFER_TO_FROM_DEV == dxfer_dir)) {
+		num_xfer = hp->dxfer_len;
+		if (schp->bufflen < num_xfer)
+			num_xfer = schp->bufflen;
+	}
+	if ((num_xfer <= 0) || (schp->dio_in_use) ||
+	    (new_interface
+	     && ((SG_FLAG_NO_DXFER | SG_FLAG_MMAP_IO) & hp->flags)))
+		return 0;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_read_xfer: num_xfer=%d, iovec_count=%d, k_use_sg=%d\n",
+			  num_xfer, iovec_count, schp->k_use_sg));
+	if (iovec_count) {
+		onum = iovec_count;
+		if (!access_ok(VERIFY_READ, hp->dxferp, SZ_SG_IOVEC * onum))
+			return -EFAULT;
+	} else
+		onum = 1;
+
+	if (0 == schp->k_use_sg) {	/* kernel has single buffer */
+		for (j = 0, p = schp->buffer; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
+			if (res)
+				return res;
+			usglen = (num_xfer > usglen) ? usglen : num_xfer;
+			if (__copy_to_user(up, p, usglen))
+				return -EFAULT;
+			p += usglen;
+			num_xfer -= usglen;
+			if (num_xfer <= 0)
+				return 0;
+		}
+	} else {		/* kernel using scatter gather list */
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		ksglen = (int) sclp->length;
+		p = sg_scatg2virt(sclp);
+		for (j = 0, k = 0; j < onum; ++j) {
+			res = sg_u_iovec(hp, iovec_count, j, 0, &usglen, &up);
+			if (res)
+				return res;
+
+			for (; p; ++sclp, ksglen = (int) sclp->length,
+				  p = sg_scatg2virt(sclp)) {
+				if (usglen <= 0)
+					break;
+				if (ksglen > usglen) {
+					if (usglen >= num_xfer) {
+						if (__copy_to_user
+						    (up, p, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_to_user(up, p, usglen))
+						return -EFAULT;
+					p += usglen;
+					ksglen -= usglen;
+					break;
+				} else {
+					if (ksglen >= num_xfer) {
+						if (__copy_to_user
+						    (up, p, num_xfer))
+							return -EFAULT;
+						return 0;
+					}
+					if (__copy_to_user(up, p, ksglen))
+						return -EFAULT;
+					up += ksglen;
+					usglen -= ksglen;
+				}
+				++k;
+				if (k >= schp->k_use_sg)
+					return 0;
+			}
+		}
+	}
+	return 0;
+}
+
+static int
+sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer)
+{
+	Sg_scatter_hold *schp = &srp->data;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_read_oxfer: num_read_xfer=%d\n",
+				   num_read_xfer));
+	if ((!outp) || (num_read_xfer <= 0))
+		return 0;
+	if (schp->k_use_sg > 0) {
+		int k, num;
+		struct scatterlist *sclp = (struct scatterlist *) schp->buffer;
+
+		for (k = 0; (k < schp->k_use_sg) && sg_scatg2virt(sclp);
+		     ++k, ++sclp) {
+			num = (int) sclp->length;
+			if (num > num_read_xfer) {
+				if (__copy_to_user
+				    (outp, sg_scatg2virt(sclp), num_read_xfer))
+					return -EFAULT;
+				break;
+			} else {
+				if (__copy_to_user
+				    (outp, sg_scatg2virt(sclp), num))
+					return -EFAULT;
+				num_read_xfer -= num;
+				if (num_read_xfer <= 0)
+					break;
+				outp += num;
+			}
+		}
+	} else {
+		if (__copy_to_user(outp, schp->buffer, num_read_xfer))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static void
+sg_build_reserve(Sg_fd * sfp, int req_size)
+{
+	Sg_scatter_hold *schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_build_reserve: req_size=%d\n", req_size));
+	do {
+		if (req_size < PAGE_SIZE)
+			req_size = PAGE_SIZE;
+		if (0 == sg_build_indirect(schp, sfp, req_size))
+			return;
+		else
+			sg_remove_scat(schp);
+		req_size >>= 1;	/* divide by 2 */
+	} while (req_size > (PAGE_SIZE / 2));
+}
+
+static void
+sg_link_reserve(Sg_fd * sfp, Sg_request * srp, int size)
+{
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	srp->res_used = 1;
+	SCSI_LOG_TIMEOUT(4, printk("sg_link_reserve: size=%d\n", size));
+	size = (size + 1) & (~1);	/* round to even for aha1542 */
+	if (rsv_schp->k_use_sg > 0) {
+		int k, num;
+		int rem = size;
+		struct scatterlist *sclp =
+		    (struct scatterlist *) rsv_schp->buffer;
+
+		for (k = 0; k < rsv_schp->k_use_sg; ++k, ++sclp) {
+			num = (int) sclp->length;
+			if (rem <= num) {
+				if (0 == k) {
+					req_schp->k_use_sg = 0;
+					req_schp->buffer = sg_scatg2virt(sclp);
+				} else {
+					sfp->save_scat_len = num;
+					sclp->length = (unsigned) rem;
+					req_schp->k_use_sg = k + 1;
+					req_schp->sglist_len =
+					    rsv_schp->sglist_len;
+					req_schp->buffer = rsv_schp->buffer;
+				}
+				req_schp->bufflen = size;
+				req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+				break;
+			} else
+				rem -= num;
+		}
+		if (k >= rsv_schp->k_use_sg)
+			SCSI_LOG_TIMEOUT(1, printk("sg_link_reserve: BAD size\n"));
+	} else {
+		req_schp->k_use_sg = 0;
+		req_schp->bufflen = size;
+		req_schp->buffer = rsv_schp->buffer;
+		req_schp->b_malloc_len = rsv_schp->b_malloc_len;
+	}
+}
+
+static void
+sg_unlink_reserve(Sg_fd * sfp, Sg_request * srp)
+{
+	Sg_scatter_hold *req_schp = &srp->data;
+	Sg_scatter_hold *rsv_schp = &sfp->reserve;
+
+	SCSI_LOG_TIMEOUT(4, printk("sg_unlink_reserve: req->k_use_sg=%d\n",
+				   (int) req_schp->k_use_sg));
+	if ((rsv_schp->k_use_sg > 0) && (req_schp->k_use_sg > 0)) {
+		struct scatterlist *sclp =
+		    (struct scatterlist *) rsv_schp->buffer;
+
+		if (sfp->save_scat_len > 0)
+			(sclp + (req_schp->k_use_sg - 1))->length =
+			    (unsigned) sfp->save_scat_len;
+		else
+			SCSI_LOG_TIMEOUT(1, printk ("sg_unlink_reserve: BAD save_scat_len\n"));
+	}
+	req_schp->k_use_sg = 0;
+	req_schp->bufflen = 0;
+	req_schp->buffer = NULL;
+	req_schp->sglist_len = 0;
+	sfp->save_scat_len = 0;
+	srp->res_used = 0;
+}
+
+static Sg_request *
+sg_get_rq_mark(Sg_fd * sfp, int pack_id)
+{
+	Sg_request *resp;
+	unsigned long iflags;
+
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (resp = sfp->headrp; resp; resp = resp->nextrp) {
+		/* look for requests that are ready + not SG_IO owned */
+		if ((1 == resp->done) && (!resp->sg_io_owned) &&
+		    ((-1 == pack_id) || (resp->header.pack_id == pack_id))) {
+			resp->done = 2;	/* guard against other readers */
+			break;
+		}
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
+}
+
+#ifdef CONFIG_SCSI_PROC_FS
+static Sg_request *
+sg_get_nth_request(Sg_fd * sfp, int nth)
+{
+	Sg_request *resp;
+	unsigned long iflags;
+	int k;
+
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (k = 0, resp = sfp->headrp; resp && (k < nth);
+	     ++k, resp = resp->nextrp) ;
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
+}
+#endif
+
+/* always adds to end of list */
+static Sg_request *
+sg_add_request(Sg_fd * sfp)
+{
+	int k;
+	unsigned long iflags;
+	Sg_request *resp;
+	Sg_request *rp = sfp->req_arr;
+
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	resp = sfp->headrp;
+	if (!resp) {
+		memset(rp, 0, sizeof (Sg_request));
+		rp->parentfp = sfp;
+		resp = rp;
+		sfp->headrp = resp;
+	} else {
+		if (0 == sfp->cmd_q)
+			resp = NULL;	/* command queuing disallowed */
+		else {
+			for (k = 0; k < SG_MAX_QUEUE; ++k, ++rp) {
+				if (!rp->parentfp)
+					break;
+			}
+			if (k < SG_MAX_QUEUE) {
+				memset(rp, 0, sizeof (Sg_request));
+				rp->parentfp = sfp;
+				while (resp->nextrp)
+					resp = resp->nextrp;
+				resp->nextrp = rp;
+				resp = rp;
+			} else
+				resp = NULL;
+		}
+	}
+	if (resp) {
+		resp->nextrp = NULL;
+		resp->header.duration = jiffies;
+		resp->my_cmdp = NULL;
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return resp;
+}
+
+/* Return of 1 for found; 0 for not found */
+static int
+sg_remove_request(Sg_fd * sfp, Sg_request * srp)
+{
+	Sg_request *prev_rp;
+	Sg_request *rp;
+	unsigned long iflags;
+	int res = 0;
+
+	if ((!sfp) || (!srp) || (!sfp->headrp))
+		return res;
+	write_lock_irqsave(&sfp->rq_list_lock, iflags);
+	prev_rp = sfp->headrp;
+	if (srp == prev_rp) {
+		sfp->headrp = prev_rp->nextrp;
+		prev_rp->parentfp = NULL;
+		res = 1;
+	} else {
+		while ((rp = prev_rp->nextrp)) {
+			if (srp == rp) {
+				prev_rp->nextrp = rp->nextrp;
+				rp->parentfp = NULL;
+				res = 1;
+				break;
+			}
+			prev_rp = rp;
+		}
+	}
+	write_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return res;
+}
+
+#ifdef CONFIG_SCSI_PROC_FS
+static Sg_fd *
+sg_get_nth_sfp(Sg_device * sdp, int nth)
+{
+	Sg_fd *resp;
+	unsigned long iflags;
+	int k;
+
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = 0, resp = sdp->headfp; resp && (k < nth);
+	     ++k, resp = resp->nextfp) ;
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	return resp;
+}
+#endif
+
+static Sg_fd *
+sg_add_sfp(Sg_device * sdp, int dev)
+{
+	Sg_fd *sfp;
+	unsigned long iflags;
+
+	sfp = (Sg_fd *) sg_page_malloc(sizeof (Sg_fd), 0, NULL);
+	if (!sfp)
+		return NULL;
+	memset(sfp, 0, sizeof (Sg_fd));
+	init_waitqueue_head(&sfp->read_wait);
+	rwlock_init(&sfp->rq_list_lock);
+
+	sfp->timeout = SG_DEFAULT_TIMEOUT;
+	sfp->timeout_user = SG_DEFAULT_TIMEOUT_USER;
+	sfp->force_packid = SG_DEF_FORCE_PACK_ID;
+	sfp->low_dma = (SG_DEF_FORCE_LOW_DMA == 0) ?
+	    sdp->device->host->unchecked_isa_dma : 1;
+	sfp->cmd_q = SG_DEF_COMMAND_Q;
+	sfp->keep_orphan = SG_DEF_KEEP_ORPHAN;
+	sfp->parentdp = sdp;
+	write_lock_irqsave(&sg_dev_arr_lock, iflags);
+	if (!sdp->headfp)
+		sdp->headfp = sfp;
+	else {			/* add to tail of existing list */
+		Sg_fd *pfp = sdp->headfp;
+		while (pfp->nextfp)
+			pfp = pfp->nextfp;
+		pfp->nextfp = sfp;
+	}
+	write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp: sfp=0x%p\n", sfp));
+	sg_build_reserve(sfp, sg_big_buff);
+	SCSI_LOG_TIMEOUT(3, printk("sg_add_sfp:   bufflen=%d, k_use_sg=%d\n",
+			   sfp->reserve.bufflen, sfp->reserve.k_use_sg));
+	return sfp;
+}
+
+static void
+__sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+{
+	Sg_fd *fp;
+	Sg_fd *prev_fp;
+
+	prev_fp = sdp->headfp;
+	if (sfp == prev_fp)
+		sdp->headfp = prev_fp->nextfp;
+	else {
+		while ((fp = prev_fp->nextfp)) {
+			if (sfp == fp) {
+				prev_fp->nextfp = fp->nextfp;
+				break;
+			}
+			prev_fp = fp;
+		}
+	}
+	if (sfp->reserve.bufflen > 0) {
+		SCSI_LOG_TIMEOUT(6, 
+			printk("__sg_remove_sfp:    bufflen=%d, k_use_sg=%d\n",
+			(int) sfp->reserve.bufflen, (int) sfp->reserve.k_use_sg));
+		if (sfp->mmap_called)
+			sg_rb_correct4mmap(&sfp->reserve, 0);	/* undo correction */
+		sg_remove_scat(&sfp->reserve);
+	}
+	sfp->parentdp = NULL;
+	SCSI_LOG_TIMEOUT(6, printk("__sg_remove_sfp:    sfp=0x%p\n", sfp));
+	sg_page_free((char *) sfp, sizeof (Sg_fd));
+}
+
+/* Returns 0 in normal case, 1 when detached and sdp object removed */
+static int
+sg_remove_sfp(Sg_device * sdp, Sg_fd * sfp)
+{
+	Sg_request *srp;
+	Sg_request *tsrp;
+	int dirty = 0;
+	int res = 0;
+
+	for (srp = sfp->headrp; srp; srp = tsrp) {
+		tsrp = srp->nextrp;
+		if (sg_srp_done(srp, sfp))
+			sg_finish_rem_req(srp);
+		else
+			++dirty;
+	}
+	if (0 == dirty) {
+		unsigned long iflags;
+
+		write_lock_irqsave(&sg_dev_arr_lock, iflags);
+		__sg_remove_sfp(sdp, sfp);
+		if (sdp->detached && (NULL == sdp->headfp)) {
+			int k, maxd;
+
+			maxd = sg_dev_max;
+			for (k = 0; k < maxd; ++k) {
+				if (sdp == sg_dev_arr[k])
+					break;
+			}
+			if (k < maxd)
+				sg_dev_arr[k] = NULL;
+			kfree((char *) sdp);
+			res = 1;
+		}
+		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	} else {
+		/* MOD_INC's to inhibit unloading sg and associated adapter driver */
+		/* only bump the access_count if we actually succeeded in
+		 * throwing another counter on the host module */
+		scsi_device_get(sdp->device);	/* XXX: retval ignored? */	
+		sfp->closed = 1;	/* flag dirty state on this fd */
+		SCSI_LOG_TIMEOUT(1, printk("sg_remove_sfp: worrisome, %d writes pending\n",
+				  dirty));
+	}
+	return res;
+}
+
+static int
+sg_res_in_use(Sg_fd * sfp)
+{
+	const Sg_request *srp;
+	unsigned long iflags;
+
+	read_lock_irqsave(&sfp->rq_list_lock, iflags);
+	for (srp = sfp->headrp; srp; srp = srp->nextrp)
+		if (srp->res_used)
+			break;
+	read_unlock_irqrestore(&sfp->rq_list_lock, iflags);
+	return srp ? 1 : 0;
+}
+
+/* If retSzp==NULL want exact size or fail */
+static char *
+sg_page_malloc(int rqSz, int lowDma, int *retSzp)
+{
+	char *resp = NULL;
+	int page_mask;
+	int order, a_size;
+	int resSz = rqSz;
+
+	if (rqSz <= 0)
+		return resp;
+
+	if (lowDma)
+		page_mask = GFP_ATOMIC | GFP_DMA | __GFP_NOWARN;
+	else
+		page_mask = GFP_ATOMIC | __GFP_NOWARN;
+
+	for (order = 0, a_size = PAGE_SIZE; a_size < rqSz;
+	     order++, a_size <<= 1) ;
+	resp = (char *) __get_free_pages(page_mask, order);
+	while ((!resp) && order && retSzp) {
+		--order;
+		a_size >>= 1;	/* divide by 2, until PAGE_SIZE */
+		resp = (char *) __get_free_pages(page_mask, order);	/* try half */
+		resSz = a_size;
+	}
+	if (resp) {
+		if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+			memset(resp, 0, resSz);
+		if (retSzp)
+			*retSzp = resSz;
+	}
+	return resp;
+}
+
+static void
+sg_page_free(char *buff, int size)
+{
+	int order, a_size;
+
+	if (!buff)
+		return;
+	for (order = 0, a_size = PAGE_SIZE; a_size < size;
+	     order++, a_size <<= 1) ;
+	free_pages((unsigned long) buff, order);
+}
+
+#ifndef MAINTENANCE_IN_CMD
+#define MAINTENANCE_IN_CMD 0xa3
+#endif
+
+static unsigned char allow_ops[] = { TEST_UNIT_READY, REQUEST_SENSE,
+	INQUIRY, READ_CAPACITY, READ_BUFFER, READ_6, READ_10, READ_12,
+	READ_16, MODE_SENSE, MODE_SENSE_10, LOG_SENSE, REPORT_LUNS,
+	SERVICE_ACTION_IN, RECEIVE_DIAGNOSTIC, READ_LONG, MAINTENANCE_IN_CMD
+};
+
+static int
+sg_allow_access(unsigned char opcode, char dev_type)
+{
+	int k;
+
+	if (TYPE_SCANNER == dev_type)	/* TYPE_ROM maybe burner */
+		return 1;
+	for (k = 0; k < sizeof (allow_ops); ++k) {
+		if (opcode == allow_ops[k])
+			return 1;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_SCSI_PROC_FS
+static int
+sg_last_dev(void)
+{
+	int k;
+	unsigned long iflags;
+
+	read_lock_irqsave(&sg_dev_arr_lock, iflags);
+	for (k = sg_dev_max - 1; k >= 0; --k)
+		if (sg_dev_arr[k] && sg_dev_arr[k]->device)
+			break;
+	read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	return k + 1;		/* origin 1 */
+}
+#endif
+
+static Sg_device *
+sg_get_dev(int dev)
+{
+	Sg_device *sdp = NULL;
+	unsigned long iflags;
+
+	if (sg_dev_arr && (dev >= 0)) {
+		read_lock_irqsave(&sg_dev_arr_lock, iflags);
+		if (dev < sg_dev_max)
+			sdp = sg_dev_arr[dev];
+		read_unlock_irqrestore(&sg_dev_arr_lock, iflags);
+	}
+	return sdp;
+}
+
+#ifdef CONFIG_SCSI_PROC_FS
+
+static struct proc_dir_entry *sg_proc_sgp = NULL;
+
+static char sg_proc_sg_dirname[] = "scsi/sg";
+
+static int sg_proc_seq_show_int(struct seq_file *s, void *v);
+
+static int sg_proc_single_open_adio(struct inode *inode, struct file *file);
+static ssize_t sg_proc_write_adio(struct file *filp, const char __user *buffer,
+			          size_t count, loff_t *off);
+static struct file_operations adio_fops = {
+	/* .owner, .read and .llseek added in sg_proc_init() */
+	.open = sg_proc_single_open_adio,
+	.write = sg_proc_write_adio,
+	.release = single_release,
+};
+
+static int sg_proc_single_open_dressz(struct inode *inode, struct file *file);
+static ssize_t sg_proc_write_dressz(struct file *filp, 
+		const char __user *buffer, size_t count, loff_t *off);
+static struct file_operations dressz_fops = {
+	.open = sg_proc_single_open_dressz,
+	.write = sg_proc_write_dressz,
+	.release = single_release,
+};
+
+static int sg_proc_seq_show_version(struct seq_file *s, void *v);
+static int sg_proc_single_open_version(struct inode *inode, struct file *file);
+static struct file_operations version_fops = {
+	.open = sg_proc_single_open_version,
+	.release = single_release,
+};
+
+static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v);
+static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file);
+static struct file_operations devhdr_fops = {
+	.open = sg_proc_single_open_devhdr,
+	.release = single_release,
+};
+
+static int sg_proc_seq_show_dev(struct seq_file *s, void *v);
+static int sg_proc_open_dev(struct inode *inode, struct file *file);
+static void * dev_seq_start(struct seq_file *s, loff_t *pos);
+static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos);
+static void dev_seq_stop(struct seq_file *s, void *v);
+static struct file_operations dev_fops = {
+	.open = sg_proc_open_dev,
+	.release = seq_release,
+};
+static struct seq_operations dev_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = sg_proc_seq_show_dev,
+};
+
+static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v);
+static int sg_proc_open_devstrs(struct inode *inode, struct file *file);
+static struct file_operations devstrs_fops = {
+	.open = sg_proc_open_devstrs,
+	.release = seq_release,
+};
+static struct seq_operations devstrs_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = sg_proc_seq_show_devstrs,
+};
+
+static int sg_proc_seq_show_debug(struct seq_file *s, void *v);
+static int sg_proc_open_debug(struct inode *inode, struct file *file);
+static struct file_operations debug_fops = {
+	.open = sg_proc_open_debug,
+	.release = seq_release,
+};
+static struct seq_operations debug_seq_ops = {
+	.start = dev_seq_start,
+	.next  = dev_seq_next,
+	.stop  = dev_seq_stop,
+	.show  = sg_proc_seq_show_debug,
+};
+
+
+struct sg_proc_leaf {
+	const char * name;
+	struct file_operations * fops;
+};
+
+static struct sg_proc_leaf sg_proc_leaf_arr[] = {
+	{"allow_dio", &adio_fops},
+	{"debug", &debug_fops},
+	{"def_reserved_size", &dressz_fops},
+	{"device_hdr", &devhdr_fops},
+	{"devices", &dev_fops},
+	{"device_strs", &devstrs_fops},
+	{"version", &version_fops}
+};
+
+static int
+sg_proc_init(void)
+{
+	int k, mask;
+	int num_leaves =
+	    sizeof (sg_proc_leaf_arr) / sizeof (sg_proc_leaf_arr[0]);
+	struct proc_dir_entry *pdep;
+	struct sg_proc_leaf * leaf;
+
+	sg_proc_sgp = create_proc_entry(sg_proc_sg_dirname,
+					S_IFDIR | S_IRUGO | S_IXUGO, NULL);
+	if (!sg_proc_sgp)
+		return 1;
+	for (k = 0; k < num_leaves; ++k) {
+		leaf = &sg_proc_leaf_arr[k];
+		mask = leaf->fops->write ? S_IRUGO | S_IWUSR : S_IRUGO;
+		pdep = create_proc_entry(leaf->name, mask, sg_proc_sgp);
+		if (pdep) {
+			leaf->fops->owner = THIS_MODULE,
+			leaf->fops->read = seq_read,
+			leaf->fops->llseek = seq_lseek,
+			pdep->proc_fops = leaf->fops;
+		}
+	}
+	return 0;
+}
+
+static void
+sg_proc_cleanup(void)
+{
+	int k;
+	int num_leaves =
+	    sizeof (sg_proc_leaf_arr) / sizeof (sg_proc_leaf_arr[0]);
+
+	if (!sg_proc_sgp)
+		return;
+	for (k = 0; k < num_leaves; ++k)
+		remove_proc_entry(sg_proc_leaf_arr[k].name, sg_proc_sgp);
+	remove_proc_entry(sg_proc_sg_dirname, NULL);
+}
+
+
+static int sg_proc_seq_show_int(struct seq_file *s, void *v)
+{
+	seq_printf(s, "%d\n", *((int *)s->private));
+	return 0;
+}
+
+static int sg_proc_single_open_adio(struct inode *inode, struct file *file)
+{
+	return single_open(file, sg_proc_seq_show_int, &sg_allow_dio);
+}
+
+static ssize_t 
+sg_proc_write_adio(struct file *filp, const char __user *buffer,
+		   size_t count, loff_t *off)
+{
+	int num;
+	char buff[11];
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		return -EACCES;
+	num = (count < 10) ? count : 10;
+	if (copy_from_user(buff, buffer, num))
+		return -EFAULT;
+	buff[num] = '\0';
+	sg_allow_dio = simple_strtoul(buff, NULL, 10) ? 1 : 0;
+	return count;
+}
+
+static int sg_proc_single_open_dressz(struct inode *inode, struct file *file)
+{
+	return single_open(file, sg_proc_seq_show_int, &sg_big_buff);
+}
+
+static ssize_t 
+sg_proc_write_dressz(struct file *filp, const char __user *buffer,
+		     size_t count, loff_t *off)
+{
+	int num;
+	unsigned long k = ULONG_MAX;
+	char buff[11];
+
+	if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+		return -EACCES;
+	num = (count < 10) ? count : 10;
+	if (copy_from_user(buff, buffer, num))
+		return -EFAULT;
+	buff[num] = '\0';
+	k = simple_strtoul(buff, NULL, 10);
+	if (k <= 1048576) {	/* limit "big buff" to 1 MB */
+		sg_big_buff = k;
+		return count;
+	}
+	return -ERANGE;
+}
+
+static int sg_proc_seq_show_version(struct seq_file *s, void *v)
+{
+	seq_printf(s, "%d\t%s [%s]\n", sg_version_num, SG_VERSION_STR,
+		   sg_version_date);
+	return 0;
+}
+
+static int sg_proc_single_open_version(struct inode *inode, struct file *file)
+{
+	return single_open(file, sg_proc_seq_show_version, NULL);
+}
+
+static int sg_proc_seq_show_devhdr(struct seq_file *s, void *v)
+{
+	seq_printf(s, "host\tchan\tid\tlun\ttype\topens\tqdepth\tbusy\t"
+		   "online\n");
+	return 0;
+}
+
+static int sg_proc_single_open_devhdr(struct inode *inode, struct file *file)
+{
+	return single_open(file, sg_proc_seq_show_devhdr, NULL);
+}
+
+struct sg_proc_deviter {
+	loff_t	index;
+	size_t	max;
+};
+
+static void * dev_seq_start(struct seq_file *s, loff_t *pos)
+{
+	struct sg_proc_deviter * it = kmalloc(sizeof(*it), GFP_KERNEL);
+
+	if (! it)
+		return NULL;
+	if (NULL == sg_dev_arr)
+		goto err1;
+	it->index = *pos;
+	it->max = sg_last_dev();
+	if (it->index >= it->max)
+		goto err1;
+	return it;
+err1:
+	kfree(it);
+	return NULL;
+}
+
+static void * dev_seq_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
+
+	*pos = ++it->index;
+	return (it->index < it->max) ? it : NULL;
+}
+
+static void dev_seq_stop(struct seq_file *s, void *v)
+{
+	kfree (v);
+}
+
+static int sg_proc_open_dev(struct inode *inode, struct file *file)
+{
+        return seq_open(file, &dev_seq_ops);
+}
+
+static int sg_proc_seq_show_dev(struct seq_file *s, void *v)
+{
+	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
+	Sg_device *sdp;
+	struct scsi_device *scsidp;
+
+	sdp = it ? sg_get_dev(it->index) : NULL;
+	if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+		seq_printf(s, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
+			      scsidp->host->host_no, scsidp->channel,
+			      scsidp->id, scsidp->lun, (int) scsidp->type,
+			      1,
+			      (int) scsidp->queue_depth,
+			      (int) scsidp->device_busy,
+			      (int) scsi_device_online(scsidp));
+	else
+		seq_printf(s, "-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\t-1\n");
+	return 0;
+}
+
+static int sg_proc_open_devstrs(struct inode *inode, struct file *file)
+{
+        return seq_open(file, &devstrs_seq_ops);
+}
+
+static int sg_proc_seq_show_devstrs(struct seq_file *s, void *v)
+{
+	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
+	Sg_device *sdp;
+	struct scsi_device *scsidp;
+
+	sdp = it ? sg_get_dev(it->index) : NULL;
+	if (sdp && (scsidp = sdp->device) && (!sdp->detached))
+		seq_printf(s, "%8.8s\t%16.16s\t%4.4s\n",
+			   scsidp->vendor, scsidp->model, scsidp->rev);
+	else
+		seq_printf(s, "<no active device>\n");
+	return 0;
+}
+
+static void sg_proc_debug_helper(struct seq_file *s, Sg_device * sdp)
+{
+	int k, m, new_interface, blen, usg;
+	Sg_request *srp;
+	Sg_fd *fp;
+	const sg_io_hdr_t *hp;
+	const char * cp;
+
+	for (k = 0; (fp = sg_get_nth_sfp(sdp, k)); ++k) {
+		seq_printf(s, "   FD(%d): timeout=%dms bufflen=%d "
+			   "(res)sgat=%d low_dma=%d\n", k + 1,
+			   jiffies_to_msecs(fp->timeout),
+			   fp->reserve.bufflen,
+			   (int) fp->reserve.k_use_sg,
+			   (int) fp->low_dma);
+		seq_printf(s, "   cmd_q=%d f_packid=%d k_orphan=%d closed=%d\n",
+			   (int) fp->cmd_q, (int) fp->force_packid,
+			   (int) fp->keep_orphan, (int) fp->closed);
+		for (m = 0; (srp = sg_get_nth_request(fp, m)); ++m) {
+			hp = &srp->header;
+			new_interface = (hp->interface_id == '\0') ? 0 : 1;
+			if (srp->res_used) {
+				if (new_interface && 
+				    (SG_FLAG_MMAP_IO & hp->flags))
+					cp = "     mmap>> ";
+				else
+					cp = "     rb>> ";
+			} else {
+				if (SG_INFO_DIRECT_IO_MASK & hp->info)
+					cp = "     dio>> ";
+				else
+					cp = "     ";
+			}
+			seq_printf(s, cp);
+			blen = srp->my_cmdp ? 
+				srp->my_cmdp->sr_bufflen : srp->data.bufflen;
+			usg = srp->my_cmdp ? 
+				srp->my_cmdp->sr_use_sg : srp->data.k_use_sg;
+			seq_printf(s, srp->done ? 
+				   ((1 == srp->done) ?  "rcv:" : "fin:")
+				   : (srp->my_cmdp ? "act:" : "prior:"));
+			seq_printf(s, " id=%d blen=%d",
+				   srp->header.pack_id, blen);
+			if (srp->done)
+				seq_printf(s, " dur=%d", hp->duration);
+			else
+				seq_printf(s, " t_o/elap=%d/%d",
+				  new_interface ? hp->timeout : jiffies_to_msecs(fp->timeout),
+				  jiffies_to_msecs(hp->duration ? (jiffies - hp->duration) : 0));
+			seq_printf(s, "ms sgat=%d op=0x%02x\n", usg,
+				   (int) srp->data.cmd_opcode);
+		}
+		if (0 == m)
+			seq_printf(s, "     No requests active\n");
+	}
+}
+
+static int sg_proc_open_debug(struct inode *inode, struct file *file)
+{
+        return seq_open(file, &debug_seq_ops);
+}
+
+static int sg_proc_seq_show_debug(struct seq_file *s, void *v)
+{
+	struct sg_proc_deviter * it = (struct sg_proc_deviter *) v;
+	Sg_device *sdp;
+
+	if (it && (0 == it->index)) {
+		seq_printf(s, "dev_max(currently)=%d max_active_device=%d "
+			   "(origin 1)\n", sg_dev_max, (int)it->max);
+		seq_printf(s, " def_reserved_size=%d\n", sg_big_buff);
+	}
+	sdp = it ? sg_get_dev(it->index) : NULL;
+	if (sdp) {
+		struct scsi_device *scsidp = sdp->device;
+
+		if (NULL == scsidp) {
+			seq_printf(s, "device %d detached ??\n", 
+				   (int)it->index);
+			return 0;
+		}
+
+		if (sg_get_nth_sfp(sdp, 0)) {
+			seq_printf(s, " >>> device=%s ",
+				sdp->disk->disk_name);
+			if (sdp->detached)
+				seq_printf(s, "detached pending close ");
+			else
+				seq_printf
+				    (s, "scsi%d chan=%d id=%d lun=%d   em=%d",
+				     scsidp->host->host_no,
+				     scsidp->channel, scsidp->id,
+				     scsidp->lun,
+				     scsidp->host->hostt->emulated);
+			seq_printf(s, " sg_tablesize=%d excl=%d\n",
+				   sdp->sg_tablesize, sdp->exclude);
+		}
+		sg_proc_debug_helper(s, sdp);
+	}
+	return 0;
+}
+
+#endif				/* CONFIG_SCSI_PROC_FS */
+
+module_init(init_sg);
+module_exit(exit_sg);
+MODULE_ALIAS_CHARDEV_MAJOR(SCSI_GENERIC_MAJOR);
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
new file mode 100644
index 0000000..270f2aa
--- /dev/null
+++ b/drivers/scsi/sgiwd93.c
@@ -0,0 +1,337 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ * Copyright (C) 1999 Andrew R. Baker (andrewb@uab.edu)
+ * Copyright (C) 2001 Florian Lohoff (flo@rfc822.org)
+ * Copyright (C) 2003 Ralf Baechle (ralf@linux-mips.org)
+ * 
+ * (In all truth, Jed Schimmel wrote all this code.)
+ */
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/spinlock.h>
+
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sgialib.h>
+#include <asm/sgi/sgi.h>
+#include <asm/sgi/mc.h>
+#include <asm/sgi/hpc3.h>
+#include <asm/sgi/ip22.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "wd33c93.h"
+#include "sgiwd93.h"
+
+#include <linux/stat.h>
+
+#if 0
+#define DPRINTK(args...)	printk(args)
+#else
+#define DPRINTK(args...)
+#endif
+
+#define HDATA(ptr) ((struct ip22_hostdata *)((ptr)->hostdata))
+
+struct ip22_hostdata {
+	struct WD33C93_hostdata wh;
+	struct hpc_data {
+		dma_addr_t      dma;
+		void            * cpu;
+	} hd;
+};
+
+struct hpc_chunk {
+	struct hpc_dma_desc desc;
+	u32 _padding;	/* align to quadword boundary */
+};
+
+struct Scsi_Host *sgiwd93_host;
+struct Scsi_Host *sgiwd93_host1;
+
+/* Wuff wuff, wuff, wd33c93.c, wuff wuff, object oriented, bow wow. */
+static inline void write_wd33c93_count(const wd33c93_regs regs,
+                                      unsigned long value)
+{
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	mb();
+	*regs.SCMD = ((value >> 16) & 0xff);
+	*regs.SCMD = ((value >>  8) & 0xff);
+	*regs.SCMD = ((value >>  0) & 0xff);
+	mb();
+}
+
+static inline unsigned long read_wd33c93_count(const wd33c93_regs regs)
+{
+	unsigned long value;
+
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	mb();
+	value =  ((*regs.SCMD & 0xff) << 16);
+	value |= ((*regs.SCMD & 0xff) <<  8);
+	value |= ((*regs.SCMD & 0xff) <<  0);
+	mb();
+	return value;
+}
+
+static irqreturn_t sgiwd93_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct Scsi_Host * host = (struct Scsi_Host *) dev_id;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	wd33c93_intr(host);
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	return IRQ_HANDLED;
+}
+
+static inline
+void fill_hpc_entries(struct hpc_chunk *hcp, Scsi_Cmnd *cmd, int datainp)
+{
+	unsigned long len = cmd->SCp.this_residual;
+	void *addr = cmd->SCp.ptr;
+	dma_addr_t physaddr;
+	unsigned long count;
+
+	physaddr = dma_map_single(NULL, addr, len, cmd->sc_data_direction);
+	cmd->SCp.dma_handle = physaddr;
+
+	while (len) {
+		/*
+		 * even cntinfo could be up to 16383, without
+		 * magic only 8192 works correctly
+		 */
+		count = len > 8192 ? 8192 : len;
+		hcp->desc.pbuf = physaddr;
+		hcp->desc.cntinfo = count;
+		hcp++;
+		len -= count;
+		physaddr += count;
+	}
+
+	/*
+	 * To make sure, if we trip an HPC bug, that we transfer every single
+	 * byte, we tag on an extra zero length dma descriptor at the end of
+	 * the chain.
+	 */
+	hcp->desc.pbuf = 0;
+	hcp->desc.cntinfo = HPCDMA_EOX;
+}
+
+static int dma_setup(Scsi_Cmnd *cmd, int datainp)
+{
+	struct ip22_hostdata *hdata = HDATA(cmd->device->host);
+	struct hpc3_scsiregs *hregs =
+		(struct hpc3_scsiregs *) cmd->device->host->base;
+	struct hpc_chunk *hcp = (struct hpc_chunk *) hdata->hd.cpu;
+
+	DPRINTK("dma_setup: datainp<%d> hcp<%p> ", datainp, hcp);
+
+	hdata->wh.dma_dir = datainp;
+
+	/*
+	 * wd33c93 shouldn't pass us bogus dma_setups, but it does:-(  The
+	 * other wd33c93 drivers deal with it the same way (which isn't that
+	 * obvious).  IMHO a better fix would be, not to do these dma setups
+	 * in the first place.
+	 */
+	if (cmd->SCp.ptr == NULL || cmd->SCp.this_residual == 0)
+		return 1;
+
+	fill_hpc_entries(hcp, cmd, datainp);
+
+	DPRINTK(" HPCGO\n");
+
+	/* Start up the HPC. */
+	hregs->ndptr = hdata->hd.dma;
+	if (datainp)
+		hregs->ctrl = HPC3_SCTRL_ACTIVE;
+	else
+		hregs->ctrl = HPC3_SCTRL_ACTIVE | HPC3_SCTRL_DIR;
+
+	return 0;
+}
+
+static void dma_stop(struct Scsi_Host *instance, Scsi_Cmnd *SCpnt,
+		     int status)
+{
+	struct ip22_hostdata *hdata = HDATA(instance);
+	struct hpc3_scsiregs *hregs;
+
+	if (!SCpnt)
+		return;
+
+	hregs = (struct hpc3_scsiregs *) SCpnt->device->host->base;
+
+	DPRINTK("dma_stop: status<%d> ", status);
+
+	/* First stop the HPC and flush it's FIFO. */
+	if (hdata->wh.dma_dir) {
+		hregs->ctrl |= HPC3_SCTRL_FLUSH;
+		while (hregs->ctrl & HPC3_SCTRL_ACTIVE)
+			barrier();
+	}
+	hregs->ctrl = 0;
+	dma_unmap_single(NULL, SCpnt->SCp.dma_handle, SCpnt->SCp.this_residual,
+	                 SCpnt->sc_data_direction);
+
+	DPRINTK("\n");
+}
+
+void sgiwd93_reset(unsigned long base)
+{
+	struct hpc3_scsiregs *hregs = (struct hpc3_scsiregs *) base;
+
+	hregs->ctrl = HPC3_SCTRL_CRESET;
+	udelay(50);
+	hregs->ctrl = 0;
+}
+
+static inline void init_hpc_chain(struct hpc_data *hd)
+{
+	struct hpc_chunk *hcp = (struct hpc_chunk *) hd->cpu;
+	struct hpc_chunk *dma = (struct hpc_chunk *) hd->dma;
+	unsigned long start, end;
+
+	start = (unsigned long) hcp;
+	end = start + PAGE_SIZE;
+	while (start < end) {
+		hcp->desc.pnext = (u32) (dma + 1);
+		hcp->desc.cntinfo = HPCDMA_EOX;
+		hcp++; dma++;
+		start += sizeof(struct hpc_chunk);
+	};
+	hcp--;
+	hcp->desc.pnext = hd->dma;
+}
+
+static struct Scsi_Host * __init sgiwd93_setup_scsi(
+	Scsi_Host_Template *SGIblows, int unit, int irq,
+	struct hpc3_scsiregs *hregs, unsigned char *wdregs)
+{
+	struct ip22_hostdata *hdata;
+	struct Scsi_Host *host;
+	wd33c93_regs regs;
+
+	host = scsi_register(SGIblows, sizeof(struct ip22_hostdata));
+	if (!host)
+		return NULL;
+
+	host->base = (unsigned long) hregs;
+	host->irq = irq;
+
+	hdata = HDATA(host);
+	hdata->hd.cpu = dma_alloc_coherent(NULL, PAGE_SIZE, &hdata->hd.dma,
+	                                   GFP_KERNEL);
+	if (!hdata->hd.cpu) {
+		printk(KERN_WARNING "sgiwd93: Could not allocate memory for "
+		       "host %d buffer.\n", unit);
+		goto out_unregister;
+	}
+	init_hpc_chain(&hdata->hd);
+
+	regs.SASR = wdregs + 3;
+	regs.SCMD = wdregs + 7;
+
+	wd33c93_init(host, regs, dma_setup, dma_stop, WD33C93_FS_16_20);
+
+	hdata->wh.no_sync = 0;
+
+	if (request_irq(irq, sgiwd93_intr, 0, "SGI WD93", (void *) host)) {
+		printk(KERN_WARNING "sgiwd93: Could not register irq %d "
+		       "for host %d.\n", irq, unit);
+		goto out_free;
+	}
+	return host;
+
+out_free:
+	dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	wd33c93_release();
+
+out_unregister:
+	scsi_unregister(host);
+
+	return NULL;
+}
+
+int __init sgiwd93_detect(Scsi_Host_Template *SGIblows)
+{
+	int found = 0;
+
+	SGIblows->proc_name = "SGIWD93";
+	sgiwd93_host = sgiwd93_setup_scsi(SGIblows, 0, SGI_WD93_0_IRQ,
+	                                  &hpc3c0->scsi_chan0,
+	                                  (unsigned char *)hpc3c0->scsi0_ext);
+	if (sgiwd93_host)
+		found++;
+
+	/* Set up second controller on the Indigo2 */
+	if (ip22_is_fullhouse()) {
+		sgiwd93_host1 = sgiwd93_setup_scsi(SGIblows, 1, SGI_WD93_1_IRQ,
+		                          &hpc3c0->scsi_chan1,
+		                          (unsigned char *)hpc3c0->scsi1_ext);
+		if (sgiwd93_host1)
+			found++;
+	}
+
+	return found;
+}
+
+int sgiwd93_release(struct Scsi_Host *instance)
+{
+	struct ip22_hostdata *hdata = HDATA(instance);
+	int irq = 0;
+
+	if (sgiwd93_host && sgiwd93_host == instance)
+		irq = SGI_WD93_0_IRQ;
+	else if (sgiwd93_host1 && sgiwd93_host1 == instance)
+		irq = SGI_WD93_1_IRQ;
+
+	free_irq(irq, sgiwd93_intr);
+	dma_free_coherent(NULL, PAGE_SIZE, hdata->hd.cpu, hdata->hd.dma);
+	wd33c93_release();
+
+	return 1;
+}
+
+static int sgiwd93_bus_reset(Scsi_Cmnd *cmd)
+{
+	/* FIXME perform bus-specific reset */
+	wd33c93_host_reset(cmd);
+	return SUCCESS;
+}
+
+/*
+ * Kludge alert - the SCSI code calls the abort and reset method with int
+ * arguments not with pointers.  So this is going to blow up beautyfully
+ * on 64-bit systems with memory outside the compat address spaces.
+ */
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "SGIWD93",
+	.name			= "SGI WD93",
+	.detect			= sgiwd93_detect,
+	.release		= sgiwd93_release,
+	.queuecommand		= wd33c93_queuecommand,
+	.eh_abort_handler	= wd33c93_abort,
+	.eh_bus_reset_handler	= sgiwd93_bus_reset,
+	.eh_host_reset_handler	= wd33c93_host_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/sgiwd93.h b/drivers/scsi/sgiwd93.h
new file mode 100644
index 0000000..981d0b7
--- /dev/null
+++ b/drivers/scsi/sgiwd93.h
@@ -0,0 +1,24 @@
+/* $Id: sgiwd93.h,v 1.5 1998/08/25 09:18:50 ralf Exp $
+ * sgiwd93.h: SGI WD93 scsi definitions.
+ *
+ * Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
+ */
+#ifndef _SGIWD93_H
+#define _SGIWD93_H
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 8
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE   16
+#endif
+
+int sgiwd93_detect(Scsi_Host_Template *);
+int sgiwd93_release(struct Scsi_Host *instance);
+const char *wd33c93_info(void);
+int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int wd33c93_abort(Scsi_Cmnd *);
+int wd33c93_host_reset(Scsi_Cmnd * SCpnt);
+
+#endif /* !(_SGIWD93_H) */
diff --git a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
new file mode 100644
index 0000000..63bf2ae
--- /dev/null
+++ b/drivers/scsi/sim710.c
@@ -0,0 +1,372 @@
+/*
+ * sim710.c - Copyright (C) 1999 Richard Hirst <richard@sleepie.demon.co.uk>
+ *
+ *----------------------------------------------------------------------------
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by 
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *----------------------------------------------------------------------------
+ *
+ * MCA card detection code by Trent McNair.
+ * Fixes to not explicitly nul bss data from Xavier Bestel.
+ * Some multiboard fixes from Rolf Eike Beer.
+ * Auto probing of EISA config space from Trevor Hemsley.
+ *
+ * Rewritten to use 53c700.c by James.Bottomley@SteelEye.com
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/blkdev.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/mca.h>
+#include <linux/eisa.h>
+#include <linux/interrupt.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+#include <scsi/scsi_transport_spi.h>
+
+#include "53c700.h"
+
+
+/* Must be enough for both EISA and MCA */
+#define MAX_SLOTS 8
+static __u8 __initdata id_array[MAX_SLOTS] = { [0 ... MAX_SLOTS-1] = 7 };
+
+static char *sim710;		/* command line passed by insmod */
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("Simple NCR53C710 driver");
+MODULE_LICENSE("GPL");
+
+module_param(sim710, charp, 0);
+
+#ifdef MODULE
+#define ARG_SEP ' '
+#else
+#define ARG_SEP ','
+#endif
+
+static __init int
+param_setup(char *str)
+{
+	char *pos = str, *next;
+	int slot = -1;
+
+	while(pos != NULL && (next = strchr(pos, ':')) != NULL) {
+		int val = (int)simple_strtoul(++next, NULL, 0);
+
+		if(!strncmp(pos, "slot:", 5))
+			slot = val;
+		else if(!strncmp(pos, "id:", 3)) {
+			if(slot == -1) {
+				printk(KERN_WARNING "sim710: Must specify slot for id parameter\n");
+			} else if(slot > MAX_SLOTS) {
+				printk(KERN_WARNING "sim710: Illegal slot %d for id %d\n", slot, val);
+			} else {
+				id_array[slot] = val;
+			}
+		}
+		if((pos = strchr(pos, ARG_SEP)) != NULL)
+			pos++;
+	}
+	return 1;
+}
+__setup("sim710=", param_setup);
+
+static struct scsi_host_template sim710_driver_template = {
+	.name			= "LSI (Symbios) 710 MCA/EISA",
+	.proc_name		= "sim710",
+	.this_id		= 7,
+	.module			= THIS_MODULE,
+};
+
+static __devinit int
+sim710_probe_common(struct device *dev, unsigned long base_addr,
+		    int irq, int clock, int differential, int scsi_id)
+{
+	struct Scsi_Host * host = NULL;
+	struct NCR_700_Host_Parameters *hostdata =
+		kmalloc(sizeof(struct NCR_700_Host_Parameters),	GFP_KERNEL);
+
+	printk(KERN_NOTICE "sim710: %s\n", dev->bus_id);
+	printk(KERN_NOTICE "sim710: irq = %d, clock = %d, base = 0x%lx, scsi_id = %d\n",
+	       irq, clock, base_addr, scsi_id);
+
+	if(hostdata == NULL) {
+		printk(KERN_ERR "sim710: Failed to allocate host data\n");
+		goto out;
+	}
+	memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
+
+	if(request_region(base_addr, 64, "sim710") == NULL) {
+		printk(KERN_ERR "sim710: Failed to reserve IO region 0x%lx\n",
+		       base_addr);
+		goto out_free;
+	}
+
+	/* Fill in the three required pieces of hostdata */
+	hostdata->base = base_addr;
+	hostdata->differential = differential;
+	hostdata->clock = clock;
+	hostdata->chip710 = 1;
+	NCR_700_set_io_mapped(hostdata);
+
+	/* and register the chip */
+	if((host = NCR_700_detect(&sim710_driver_template, hostdata, dev))
+	   == NULL) {
+		printk(KERN_ERR "sim710: No host detected; card configuration problem?\n");
+		goto out_release;
+	}
+	host->this_id = scsi_id;
+	host->irq = irq;
+	if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "sim710", host)) {
+		printk(KERN_ERR "sim710: request_irq failed\n");
+		goto out_put_host;
+	}
+
+	scsi_scan_host(host);
+
+	return 0;
+
+ out_put_host:
+	scsi_host_put(host);
+ out_release:
+	release_region(host->base, 64);
+ out_free:
+	kfree(hostdata);
+ out:
+	return -ENODEV;
+}
+
+static __devexit int
+sim710_device_remove(struct device *dev)
+{
+	struct Scsi_Host *host = dev_to_shost(dev);
+	struct NCR_700_Host_Parameters *hostdata =
+		(struct NCR_700_Host_Parameters *)host->hostdata[0];
+
+	scsi_remove_host(host);
+	NCR_700_release(host);
+	kfree(hostdata);
+	free_irq(host->irq, host);
+	return 0;
+}
+
+#ifdef CONFIG_MCA
+
+/* CARD ID 01BB and 01BA use the same pos values */
+#define MCA_01BB_IO_PORTS { 0x0000, 0x0000, 0x0800, 0x0C00, 0x1000, 0x1400, \
+			    0x1800, 0x1C00, 0x2000, 0x2400, 0x2800, \
+			    0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, \
+			    0x4000, 0x4400, 0x4800, 0x4C00, 0x5000  }
+
+#define MCA_01BB_IRQS { 3, 5, 11, 14 }
+
+/* CARD ID 004f */
+#define MCA_004F_IO_PORTS { 0x0000, 0x0200, 0x0300, 0x0400, 0x0500,  0x0600 }
+#define MCA_004F_IRQS { 5, 9, 14 }
+
+static short sim710_mca_id_table[] = { 0x01bb, 0x01ba, 0x004f, 0};
+
+static __init int
+sim710_mca_probe(struct device *dev)
+{
+	struct mca_device *mca_dev = to_mca_device(dev);
+	int slot = mca_dev->slot;
+	int pos[3];
+	unsigned int base;
+	int irq_vector;
+	short id = sim710_mca_id_table[mca_dev->index];
+	static int io_004f_by_pos[] = MCA_004F_IO_PORTS;
+	static int irq_004f_by_pos[] = MCA_004F_IRQS;
+	static int io_01bb_by_pos[] = MCA_01BB_IO_PORTS;
+	static int irq_01bb_by_pos[] = MCA_01BB_IRQS;
+	char *name;
+	int clock;
+
+	pos[0] = mca_device_read_stored_pos(mca_dev, 2);
+	pos[1] = mca_device_read_stored_pos(mca_dev, 3);
+	pos[2] = mca_device_read_stored_pos(mca_dev, 4);
+
+	/*
+	 * 01BB & 01BA port base by bits 7,6,5,4,3,2 in pos[2]
+	 *
+	 *    000000  <disabled>   001010  0x2800
+	 *    000001  <invalid>    001011  0x2C00
+	 *    000010  0x0800       001100  0x3000
+	 *    000011  0x0C00       001101  0x3400
+	 *    000100  0x1000       001110  0x3800
+	 *    000101  0x1400       001111  0x3C00
+	 *    000110  0x1800       010000  0x4000
+	 *    000111  0x1C00       010001  0x4400
+	 *    001000  0x2000       010010  0x4800
+	 *    001001  0x2400       010011  0x4C00
+	 *                         010100  0x5000
+	 *
+	 * 00F4 port base by bits 3,2,1 in pos[0]
+	 *
+	 *    000  <disabled>      001    0x200
+	 *    010  0x300           011    0x400
+	 *    100  0x500           101    0x600
+	 *
+	 * 01BB & 01BA IRQ is specified in pos[0] bits 7 and 6:
+	 *
+	 *    00   3               10   11
+	 *    01   5               11   14
+	 *
+	 * 00F4 IRQ specified by bits 6,5,4 in pos[0]
+	 *
+	 *    100   5              101    9
+	 *    110   14
+	 */
+
+	if (id == 0x01bb || id == 0x01ba) {
+		base = io_01bb_by_pos[(pos[2] & 0xFC) >> 2];
+		irq_vector =
+			irq_01bb_by_pos[((pos[0] & 0xC0) >> 6)];
+
+		clock = 50;
+		if (id == 0x01bb)
+			name = "NCR 3360/3430 SCSI SubSystem";
+		else
+			name = "NCR Dual SIOP SCSI Host Adapter Board";
+	} else if ( id == 0x004f ) {
+		base = io_004f_by_pos[((pos[0] & 0x0E) >> 1)];
+		irq_vector =
+			irq_004f_by_pos[((pos[0] & 0x70) >> 4) - 4];
+		clock = 50;
+		name = "NCR 53c710 SCSI Host Adapter Board";
+	} else {
+		return -ENODEV;
+	}
+	mca_device_set_name(mca_dev, name);
+	mca_device_set_claim(mca_dev, 1);
+	base = mca_device_transform_ioport(mca_dev, base);
+	irq_vector = mca_device_transform_irq(mca_dev, irq_vector);
+
+	return sim710_probe_common(dev, base, irq_vector, clock,
+				   0, id_array[slot]);
+}
+
+static struct mca_driver sim710_mca_driver = {
+	.id_table		= sim710_mca_id_table,
+	.driver = {
+		.name		= "sim710",
+		.bus		= &mca_bus_type,
+		.probe		= sim710_mca_probe,
+		.remove		= __devexit_p(sim710_device_remove),
+	},
+};
+
+#endif /* CONFIG_MCA */
+
+#ifdef CONFIG_EISA
+static struct eisa_device_id sim710_eisa_ids[] = {
+	{ "CPQ4410" },
+	{ "CPQ4411" },
+	{ "HWP0C80" },
+	{ "" }
+};
+
+static __init int
+sim710_eisa_probe(struct device *dev)
+{
+	struct eisa_device *edev = to_eisa_device(dev);
+	unsigned long io_addr = edev->base_addr;
+	char eisa_cpq_irqs[] = { 11, 14, 15, 10, 9, 0 };
+	char eisa_hwp_irqs[] = { 3, 4, 5, 7, 12, 10, 11, 0};
+	char *eisa_irqs;
+	unsigned char irq_index;
+	unsigned char irq, differential = 0, scsi_id = 7;
+
+	if(strcmp(edev->id.sig, "HWP0C80") == 0) {
+		__u8 val;
+		eisa_irqs =  eisa_hwp_irqs;
+		irq_index = (inb(io_addr + 0xc85) & 0x7) - 1;
+
+		val = inb(io_addr + 0x4);
+		scsi_id = ffs(val) - 1;
+
+		if(scsi_id > 7 || (val & ~(1<<scsi_id)) != 0) {
+			printk(KERN_ERR "sim710.c, EISA card %s has incorrect scsi_id, setting to 7\n", dev->bus_id);
+			scsi_id = 7;
+		}
+	} else {
+		eisa_irqs = eisa_cpq_irqs;
+		irq_index = inb(io_addr + 0xc88) & 0x07;
+	}
+
+	if(irq_index >= strlen(eisa_irqs)) {
+		printk("sim710.c: irq nasty\n");
+		return -ENODEV;
+	}
+
+	irq = eisa_irqs[irq_index];
+		
+	return sim710_probe_common(dev, io_addr, irq, 50,
+				   differential, scsi_id);
+}
+
+static struct eisa_driver sim710_eisa_driver = {
+	.id_table		= sim710_eisa_ids,
+	.driver = {
+		.name		= "sim710",
+		.probe		= sim710_eisa_probe,
+		.remove		= __devexit_p(sim710_device_remove),
+	},
+};
+#endif /* CONFIG_EISA */
+
+static int __init sim710_init(void)
+{
+	int err = -ENODEV;
+
+#ifdef MODULE
+	if (sim710)
+		param_setup(sim710);
+#endif
+
+#ifdef CONFIG_MCA
+	err = mca_register_driver(&sim710_mca_driver);
+#endif
+
+#ifdef CONFIG_EISA
+	err = eisa_driver_register(&sim710_eisa_driver);
+#endif
+	/* FIXME: what we'd really like to return here is -ENODEV if
+	 * no devices have actually been found.  Instead, the err
+	 * above actually only reports problems with kobject_register,
+	 * so for the moment return success */
+
+	return 0;
+}
+
+static void __exit sim710_exit(void)
+{
+#ifdef CONFIG_MCA
+	if (MCA_bus)
+		mca_unregister_driver(&sim710_mca_driver);
+#endif
+
+#ifdef CONFIG_EISA
+	eisa_driver_unregister(&sim710_eisa_driver);
+#endif
+}
+
+module_init(sim710_init);
+module_exit(sim710_exit);
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
new file mode 100644
index 0000000..2f259f2
--- /dev/null
+++ b/drivers/scsi/sr.c
@@ -0,0 +1,965 @@
+/*
+ *  sr.c Copyright (C) 1992 David Giller
+ *           Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
+ *
+ *  adapted from:
+ *      sd.c Copyright (C) 1992 Drew Eckhardt
+ *      Linux scsi disk driver by
+ *              Drew Eckhardt <drew@colorado.edu>
+ *
+ *	Modified by Eric Youngdale ericy@andante.org to
+ *	add scatter-gather, multiple outstanding request, and other
+ *	enhancements.
+ *
+ *      Modified by Eric Youngdale eric@andante.org to support loadable
+ *      low-level scsi drivers.
+ *
+ *      Modified by Thomas Quinot thomas@melchior.cuivre.fdn.fr to
+ *      provide auto-eject.
+ *
+ *      Modified by Gerd Knorr <kraxel@cs.tu-berlin.de> to support the
+ *      generic cdrom interface
+ *
+ *      Modified by Jens Axboe <axboe@suse.de> - Uniform sr_packet()
+ *      interface, capabilities probe additions, ioctl cleanups, etc.
+ *
+ *	Modified by Richard Gooch <rgooch@atnf.csiro.au> to support devfs
+ *
+ *	Modified by Jens Axboe <axboe@suse.de> - support DVD-RAM
+ *	transparently and lose the GHOST hack
+ *
+ *	Modified by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *	check resource allocation in sr_init and some cleanups
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/bio.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/cdrom.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>	/* For the door lock/unlock commands */
+#include <scsi/scsi_request.h>
+
+#include "scsi_logging.h"
+#include "sr.h"
+
+
+#define SR_DISKS	256
+
+#define MAX_RETRIES	3
+#define SR_TIMEOUT	(30 * HZ)
+#define SR_CAPABILITIES \
+	(CDC_CLOSE_TRAY|CDC_OPEN_TRAY|CDC_LOCK|CDC_SELECT_SPEED| \
+	 CDC_SELECT_DISC|CDC_MULTI_SESSION|CDC_MCN|CDC_MEDIA_CHANGED| \
+	 CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \
+	 CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_DVD_RAM|CDC_GENERIC_PACKET| \
+	 CDC_MRW|CDC_MRW_W|CDC_RAM)
+
+static int sr_probe(struct device *);
+static int sr_remove(struct device *);
+static int sr_init_command(struct scsi_cmnd *);
+
+static struct scsi_driver sr_template = {
+	.owner			= THIS_MODULE,
+	.gendrv = {
+		.name   	= "sr",
+		.probe		= sr_probe,
+		.remove		= sr_remove,
+	},
+	.init_command		= sr_init_command,
+};
+
+static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG];
+static DEFINE_SPINLOCK(sr_index_lock);
+
+/* This semaphore is used to mediate the 0->1 reference get in the
+ * face of object destruction (i.e. we can't allow a get on an
+ * object after last put) */
+static DECLARE_MUTEX(sr_ref_sem);
+
+static int sr_open(struct cdrom_device_info *, int);
+static void sr_release(struct cdrom_device_info *);
+
+static void get_sectorsize(struct scsi_cd *);
+static void get_capabilities(struct scsi_cd *);
+
+static int sr_media_change(struct cdrom_device_info *, int);
+static int sr_packet(struct cdrom_device_info *, struct packet_command *);
+
+static struct cdrom_device_ops sr_dops = {
+	.open			= sr_open,
+	.release	 	= sr_release,
+	.drive_status	 	= sr_drive_status,
+	.media_changed		= sr_media_change,
+	.tray_move		= sr_tray_move,
+	.lock_door		= sr_lock_door,
+	.select_speed		= sr_select_speed,
+	.get_last_session	= sr_get_last_session,
+	.get_mcn		= sr_get_mcn,
+	.reset			= sr_reset,
+	.audio_ioctl		= sr_audio_ioctl,
+	.dev_ioctl		= sr_dev_ioctl,
+	.capability		= SR_CAPABILITIES,
+	.generic_packet		= sr_packet,
+};
+
+static void sr_kref_release(struct kref *kref);
+
+static inline struct scsi_cd *scsi_cd(struct gendisk *disk)
+{
+	return container_of(disk->private_data, struct scsi_cd, driver);
+}
+
+/*
+ * The get and put routines for the struct scsi_cd.  Note this entity
+ * has a scsi_device pointer and owns a reference to this.
+ */
+static inline struct scsi_cd *scsi_cd_get(struct gendisk *disk)
+{
+	struct scsi_cd *cd = NULL;
+
+	down(&sr_ref_sem);
+	if (disk->private_data == NULL)
+		goto out;
+	cd = scsi_cd(disk);
+	kref_get(&cd->kref);
+	if (scsi_device_get(cd->device))
+		goto out_put;
+	goto out;
+
+ out_put:
+	kref_put(&cd->kref, sr_kref_release);
+	cd = NULL;
+ out:
+	up(&sr_ref_sem);
+	return cd;
+}
+
+static inline void scsi_cd_put(struct scsi_cd *cd)
+{
+	struct scsi_device *sdev = cd->device;
+
+	down(&sr_ref_sem);
+	kref_put(&cd->kref, sr_kref_release);
+	scsi_device_put(sdev);
+	up(&sr_ref_sem);
+}
+
+/*
+ * This function checks to see if the media has been changed in the
+ * CDROM drive.  It is possible that we have already sensed a change,
+ * or the drive may have sensed one and not yet reported it.  We must
+ * be ready for either case. This function always reports the current
+ * value of the changed bit.  If flag is 0, then the changed bit is reset.
+ * This function could be done as an ioctl, but we would need to have
+ * an inode for that to work, and we do not always have one.
+ */
+
+int sr_media_change(struct cdrom_device_info *cdi, int slot)
+{
+	struct scsi_cd *cd = cdi->handle;
+	int retval;
+
+	if (CDSL_CURRENT != slot) {
+		/* no changer support */
+		return -EINVAL;
+	}
+
+	retval = scsi_test_unit_ready(cd->device, SR_TIMEOUT, MAX_RETRIES);
+	if (retval) {
+		/* Unable to test, unit probably not ready.  This usually
+		 * means there is no disc in the drive.  Mark as changed,
+		 * and we will figure it out later once the drive is
+		 * available again.  */
+		cd->device->changed = 1;
+		return 1;	/* This will force a flush, if called from
+				 * check_disk_change */
+	};
+
+	retval = cd->device->changed;
+	cd->device->changed = 0;
+	/* If the disk changed, the capacity will now be different,
+	 * so we force a re-read of this information */
+	if (retval) {
+		/* check multisession offset etc */
+		sr_cd_check(cdi);
+
+		/* 
+		 * If the disk changed, the capacity will now be different,
+		 * so we force a re-read of this information 
+		 * Force 2048 for the sector size so that filesystems won't
+		 * be trying to use something that is too small if the disc
+		 * has changed.
+		 */
+		cd->needs_sector_size = 1;
+		cd->device->sector_size = 2048;
+	}
+	return retval;
+}
+ 
+/*
+ * rw_intr is the interrupt routine for the device driver.
+ *
+ * It will be notified on the end of a SCSI read / write, and will take on
+ * of several actions based on success or failure.
+ */
+static void rw_intr(struct scsi_cmnd * SCpnt)
+{
+	int result = SCpnt->result;
+	int this_count = SCpnt->bufflen;
+	int good_bytes = (result == 0 ? this_count : 0);
+	int block_sectors = 0;
+	long error_sector;
+	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+
+#ifdef DEBUG
+	printk("sr.c done: %x\n", result);
+#endif
+
+	/*
+	 * Handle MEDIUM ERRORs or VOLUME OVERFLOWs that indicate partial
+	 * success.  Since this is a relatively rare error condition, no
+	 * care is taken to avoid unnecessary additional work such as
+	 * memcpy's that could be avoided.
+	 */
+	if (driver_byte(result) != 0 &&		/* An error occurred */
+	    (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */
+		switch (SCpnt->sense_buffer[2]) {
+		case MEDIUM_ERROR:
+		case VOLUME_OVERFLOW:
+		case ILLEGAL_REQUEST:
+			if (!(SCpnt->sense_buffer[0] & 0x90))
+				break;
+			if (!blk_fs_request(SCpnt->request))
+				break;
+			error_sector = (SCpnt->sense_buffer[3] << 24) |
+				(SCpnt->sense_buffer[4] << 16) |
+				(SCpnt->sense_buffer[5] << 8) |
+				SCpnt->sense_buffer[6];
+			if (SCpnt->request->bio != NULL)
+				block_sectors =
+					bio_sectors(SCpnt->request->bio);
+			if (block_sectors < 4)
+				block_sectors = 4;
+			if (cd->device->sector_size == 2048)
+				error_sector <<= 2;
+			error_sector &= ~(block_sectors - 1);
+			good_bytes = (error_sector - SCpnt->request->sector) << 9;
+			if (good_bytes < 0 || good_bytes >= this_count)
+				good_bytes = 0;
+			/*
+			 * The SCSI specification allows for the value
+			 * returned by READ CAPACITY to be up to 75 2K
+			 * sectors past the last readable block.
+			 * Therefore, if we hit a medium error within the
+			 * last 75 2K sectors, we decrease the saved size
+			 * value.
+			 */
+			if (error_sector < get_capacity(cd->disk) &&
+			    cd->capacity - error_sector < 4 * 75)
+				set_capacity(cd->disk, error_sector);
+			break;
+
+		case RECOVERED_ERROR:
+
+			/*
+			 * An error occured, but it recovered.  Inform the
+			 * user, but make sure that it's not treated as a
+			 * hard error.
+			 */
+			scsi_print_sense("sr", SCpnt);
+			SCpnt->result = 0;
+			SCpnt->sense_buffer[0] = 0x0;
+			good_bytes = this_count;
+			break;
+
+		default:
+			break;
+		}
+	}
+
+	/*
+	 * This calls the generic completion function, now that we know
+	 * how many actual sectors finished, and how many sectors we need
+	 * to say have failed.
+	 */
+	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);
+}
+
+static int sr_init_command(struct scsi_cmnd * SCpnt)
+{
+	int block=0, this_count, s_size, timeout = SR_TIMEOUT;
+	struct scsi_cd *cd = scsi_cd(SCpnt->request->rq_disk);
+
+	SCSI_LOG_HLQUEUE(1, printk("Doing sr request, dev = %s, block = %d\n",
+				cd->disk->disk_name, block));
+
+	if (!cd->device || !scsi_device_online(cd->device)) {
+		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n",
+					SCpnt->request->nr_sectors));
+		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));
+		return 0;
+	}
+
+	if (cd->device->changed) {
+		/*
+		 * quietly refuse to do anything to a changed disc until the
+		 * changed bit has been reset
+		 */
+		return 0;
+	}
+
+	/*
+	 * these are already setup, just copy cdb basically
+	 */
+	if (SCpnt->request->flags & REQ_BLOCK_PC) {
+		struct request *rq = SCpnt->request;
+
+		if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
+			return 0;
+
+		memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+		if (!rq->data_len)
+			SCpnt->sc_data_direction = DMA_NONE;
+		else if (rq_data_dir(rq) == WRITE)
+			SCpnt->sc_data_direction = DMA_TO_DEVICE;
+		else
+			SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+
+		this_count = rq->data_len;
+		if (rq->timeout)
+			timeout = rq->timeout;
+
+		SCpnt->transfersize = rq->data_len;
+		goto queue;
+	}
+
+	if (!(SCpnt->request->flags & REQ_CMD)) {
+		blk_dump_rq_flags(SCpnt->request, "sr unsup command");
+		return 0;
+	}
+
+	/*
+	 * we do lazy blocksize switching (when reading XA sectors,
+	 * see CDROMREADMODE2 ioctl) 
+	 */
+	s_size = cd->device->sector_size;
+	if (s_size > 2048) {
+		if (!in_interrupt())
+			sr_set_blocklength(cd, 2048);
+		else
+			printk("sr: can't switch blocksize: in interrupt\n");
+	}
+
+	if (s_size != 512 && s_size != 1024 && s_size != 2048) {
+		printk("sr: bad sector size %d\n", s_size);
+		return 0;
+	}
+
+	if (rq_data_dir(SCpnt->request) == WRITE) {
+		if (!cd->device->writeable)
+			return 0;
+		SCpnt->cmnd[0] = WRITE_10;
+		SCpnt->sc_data_direction = DMA_TO_DEVICE;
+ 	 	cd->cdi.media_written = 1;
+	} else if (rq_data_dir(SCpnt->request) == READ) {
+		SCpnt->cmnd[0] = READ_10;
+		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+	} else {
+		blk_dump_rq_flags(SCpnt->request, "Unknown sr command");
+		return 0;
+	}
+
+	{
+		struct scatterlist *sg = SCpnt->request_buffer;
+		int i, size = 0;
+		for (i = 0; i < SCpnt->use_sg; i++)
+			size += sg[i].length;
+
+		if (size != SCpnt->request_bufflen && SCpnt->use_sg) {
+			printk(KERN_ERR "sr: mismatch count %d, bytes %d\n",
+					size, SCpnt->request_bufflen);
+			if (SCpnt->request_bufflen > size)
+				SCpnt->request_bufflen = SCpnt->bufflen = size;
+		}
+	}
+
+	/*
+	 * request doesn't start on hw block boundary, add scatter pads
+	 */
+	if (((unsigned int)SCpnt->request->sector % (s_size >> 9)) ||
+	    (SCpnt->request_bufflen % s_size)) {
+		printk("sr: unaligned transfer\n");
+		return 0;
+	}
+
+	this_count = (SCpnt->request_bufflen >> 9) / (s_size >> 9);
+
+
+	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",
+				cd->cdi.name,
+				(rq_data_dir(SCpnt->request) == WRITE) ?
+					"writing" : "reading",
+				this_count, SCpnt->request->nr_sectors));
+
+	SCpnt->cmnd[1] = 0;
+	block = (unsigned int)SCpnt->request->sector / (s_size >> 9);
+
+	if (this_count > 0xffff) {
+		this_count = 0xffff;
+		SCpnt->request_bufflen = SCpnt->bufflen =
+				this_count * s_size;
+	}
+
+	SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
+	SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
+	SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
+	SCpnt->cmnd[5] = (unsigned char) block & 0xff;
+	SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;
+	SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;
+	SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;
+
+	/*
+	 * We shouldn't disconnect in the middle of a sector, so with a dumb
+	 * host adapter, it's safe to assume that we can at least transfer
+	 * this many bytes between each connect / disconnect.
+	 */
+	SCpnt->transfersize = cd->device->sector_size;
+	SCpnt->underflow = this_count << 9;
+
+queue:
+	SCpnt->allowed = MAX_RETRIES;
+	SCpnt->timeout_per_command = timeout;
+
+	/*
+	 * This is the completion routine we use.  This is matched in terms
+	 * of capability to this function.
+	 */
+	SCpnt->done = rw_intr;
+
+	/*
+	 * This indicates that the command is ready from our end to be
+	 * queued.
+	 */
+	return 1;
+}
+
+static int sr_block_open(struct inode *inode, struct file *file)
+{
+	struct gendisk *disk = inode->i_bdev->bd_disk;
+	struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+	int ret = 0;
+
+	if(!(cd = scsi_cd_get(disk)))
+		return -ENXIO;
+
+	if((ret = cdrom_open(&cd->cdi, inode, file)) != 0)
+		scsi_cd_put(cd);
+
+	return ret;
+}
+
+static int sr_block_release(struct inode *inode, struct file *file)
+{
+	int ret;
+	struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+	ret = cdrom_release(&cd->cdi, file);
+	if(ret)
+		return ret;
+	
+	scsi_cd_put(cd);
+
+	return 0;
+}
+
+static int sr_block_ioctl(struct inode *inode, struct file *file, unsigned cmd,
+			  unsigned long arg)
+{
+	struct scsi_cd *cd = scsi_cd(inode->i_bdev->bd_disk);
+	struct scsi_device *sdev = cd->device;
+
+        /*
+         * Send SCSI addressing ioctls directly to mid level, send other
+         * ioctls to cdrom/block level.
+         */
+        switch (cmd) {
+                case SCSI_IOCTL_GET_IDLUN:
+                case SCSI_IOCTL_GET_BUS_NUMBER:
+                        return scsi_ioctl(sdev, cmd, (void __user *)arg);
+	}
+	return cdrom_ioctl(file, &cd->cdi, inode, cmd, arg);
+}
+
+static int sr_block_media_changed(struct gendisk *disk)
+{
+	struct scsi_cd *cd = scsi_cd(disk);
+	return cdrom_media_changed(&cd->cdi);
+}
+
+static struct block_device_operations sr_bdops =
+{
+	.owner		= THIS_MODULE,
+	.open		= sr_block_open,
+	.release	= sr_block_release,
+	.ioctl		= sr_block_ioctl,
+	.media_changed	= sr_block_media_changed,
+	/* 
+	 * No compat_ioctl for now because sr_block_ioctl never
+	 * seems to pass arbitary ioctls down to host drivers.
+	 */
+};
+
+static int sr_open(struct cdrom_device_info *cdi, int purpose)
+{
+	struct scsi_cd *cd = cdi->handle;
+	struct scsi_device *sdev = cd->device;
+	int retval;
+
+	/*
+	 * If the device is in error recovery, wait until it is done.
+	 * If the device is offline, then disallow any access to it.
+	 */
+	retval = -ENXIO;
+	if (!scsi_block_when_processing_errors(sdev))
+		goto error_out;
+
+	/*
+	 * If this device did not have media in the drive at boot time, then
+	 * we would have been unable to get the sector size.  Check to see if
+	 * this is the case, and try again.
+	 */
+	if (cd->needs_sector_size)
+		get_sectorsize(cd);
+	return 0;
+
+error_out:
+	return retval;	
+}
+
+static void sr_release(struct cdrom_device_info *cdi)
+{
+	struct scsi_cd *cd = cdi->handle;
+
+	if (cd->device->sector_size > 2048)
+		sr_set_blocklength(cd, 2048);
+
+}
+
+static int sr_probe(struct device *dev)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct gendisk *disk;
+	struct scsi_cd *cd;
+	int minor, error;
+
+	error = -ENODEV;
+	if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
+		goto fail;
+
+	error = -ENOMEM;
+	cd = kmalloc(sizeof(*cd), GFP_KERNEL);
+	if (!cd)
+		goto fail;
+	memset(cd, 0, sizeof(*cd));
+
+	kref_init(&cd->kref);
+
+	disk = alloc_disk(1);
+	if (!disk)
+		goto fail_free;
+
+	spin_lock(&sr_index_lock);
+	minor = find_first_zero_bit(sr_index_bits, SR_DISKS);
+	if (minor == SR_DISKS) {
+		spin_unlock(&sr_index_lock);
+		error = -EBUSY;
+		goto fail_put;
+	}
+	__set_bit(minor, sr_index_bits);
+	spin_unlock(&sr_index_lock);
+
+	disk->major = SCSI_CDROM_MAJOR;
+	disk->first_minor = minor;
+	sprintf(disk->disk_name, "sr%d", minor);
+	disk->fops = &sr_bdops;
+	disk->flags = GENHD_FL_CD;
+
+	cd->device = sdev;
+	cd->disk = disk;
+	cd->driver = &sr_template;
+	cd->disk = disk;
+	cd->capacity = 0x1fffff;
+	cd->needs_sector_size = 1;
+	cd->device->changed = 1;	/* force recheck CD type */
+	cd->use = 1;
+	cd->readcd_known = 0;
+	cd->readcd_cdda = 0;
+
+	cd->cdi.ops = &sr_dops;
+	cd->cdi.handle = cd;
+	cd->cdi.mask = 0;
+	cd->cdi.capacity = 1;
+	sprintf(cd->cdi.name, "sr%d", minor);
+
+	sdev->sector_size = 2048;	/* A guess, just in case */
+
+	/* FIXME: need to handle a get_capabilities failure properly ?? */
+	get_capabilities(cd);
+	sr_vendor_init(cd);
+
+	snprintf(disk->devfs_name, sizeof(disk->devfs_name),
+			"%s/cd", sdev->devfs_name);
+	disk->driverfs_dev = &sdev->sdev_gendev;
+	set_capacity(disk, cd->capacity);
+	disk->private_data = &cd->driver;
+	disk->queue = sdev->request_queue;
+	cd->cdi.disk = disk;
+
+	if (register_cdrom(&cd->cdi))
+		goto fail_put;
+
+	dev_set_drvdata(dev, cd);
+	disk->flags |= GENHD_FL_REMOVABLE;
+	add_disk(disk);
+
+	printk(KERN_DEBUG
+	    "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n",
+	    cd->cdi.name, sdev->host->host_no, sdev->channel,
+	    sdev->id, sdev->lun);
+	return 0;
+
+fail_put:
+	put_disk(disk);
+fail_free:
+	kfree(cd);
+fail:
+	return error;
+}
+
+
+static void get_sectorsize(struct scsi_cd *cd)
+{
+	unsigned char cmd[10];
+	unsigned char *buffer;
+	int the_result, retries = 3;
+	int sector_size;
+	struct scsi_request *SRpnt = NULL;
+	request_queue_t *queue;
+
+	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		goto Enomem;
+	SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);
+	if (!SRpnt)
+		goto Enomem;
+
+	do {
+		cmd[0] = READ_CAPACITY;
+		memset((void *) &cmd[1], 0, 9);
+		/* Mark as really busy */
+		SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
+		SRpnt->sr_cmd_len = 0;
+
+		memset(buffer, 0, 8);
+
+		/* Do the command and wait.. */
+		SRpnt->sr_data_direction = DMA_FROM_DEVICE;
+		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,
+			      8, SR_TIMEOUT, MAX_RETRIES);
+
+		the_result = SRpnt->sr_result;
+		retries--;
+
+	} while (the_result && retries);
+
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+
+	if (the_result) {
+		cd->capacity = 0x1fffff;
+		sector_size = 2048;	/* A guess, just in case */
+		cd->needs_sector_size = 1;
+	} else {
+#if 0
+		if (cdrom_get_last_written(&cd->cdi,
+					   &cd->capacity))
+#endif
+			cd->capacity = 1 + ((buffer[0] << 24) |
+						    (buffer[1] << 16) |
+						    (buffer[2] << 8) |
+						    buffer[3]);
+		sector_size = (buffer[4] << 24) |
+		    (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+		switch (sector_size) {
+			/*
+			 * HP 4020i CD-Recorder reports 2340 byte sectors
+			 * Philips CD-Writers report 2352 byte sectors
+			 *
+			 * Use 2k sectors for them..
+			 */
+		case 0:
+		case 2340:
+		case 2352:
+			sector_size = 2048;
+			/* fall through */
+		case 2048:
+			cd->capacity *= 4;
+			/* fall through */
+		case 512:
+			break;
+		default:
+			printk("%s: unsupported sector size %d.\n",
+			       cd->cdi.name, sector_size);
+			cd->capacity = 0;
+			cd->needs_sector_size = 1;
+		}
+
+		cd->device->sector_size = sector_size;
+
+		/*
+		 * Add this so that we have the ability to correctly gauge
+		 * what the device is capable of.
+		 */
+		cd->needs_sector_size = 0;
+		set_capacity(cd->disk, cd->capacity);
+	}
+
+	queue = cd->device->request_queue;
+	blk_queue_hardsect_size(queue, sector_size);
+out:
+	kfree(buffer);
+	return;
+
+Enomem:
+	cd->capacity = 0x1fffff;
+	sector_size = 2048;	/* A guess, just in case */
+	cd->needs_sector_size = 1;
+	if (SRpnt)
+		scsi_release_request(SRpnt);
+	goto out;
+}
+
+static void get_capabilities(struct scsi_cd *cd)
+{
+	unsigned char *buffer;
+	struct scsi_mode_data data;
+	struct scsi_request *SRpnt;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	unsigned int the_result;
+	int retries, rc, n;
+
+	static char *loadmech[] =
+	{
+		"caddy",
+		"tray",
+		"pop-up",
+		"",
+		"changer",
+		"cartridge changer",
+		"",
+		""
+	};
+
+	/* allocate a request for the TEST_UNIT_READY */
+	SRpnt = scsi_allocate_request(cd->device, GFP_KERNEL);
+	if (!SRpnt) {
+		printk(KERN_WARNING "(get_capabilities:) Request allocation "
+		       "failure.\n");
+		return;
+	}
+
+	/* allocate transfer buffer */
+	buffer = kmalloc(512, GFP_KERNEL | GFP_DMA);
+	if (!buffer) {
+		printk(KERN_ERR "sr: out of memory.\n");
+		scsi_release_request(SRpnt);
+		return;
+	}
+
+	/* issue TEST_UNIT_READY until the initial startup UNIT_ATTENTION
+	 * conditions are gone, or a timeout happens
+	 */
+	retries = 0;
+	do {
+		memset((void *)cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = TEST_UNIT_READY;
+
+		SRpnt->sr_cmd_len = 0;
+		SRpnt->sr_sense_buffer[0] = 0;
+		SRpnt->sr_sense_buffer[2] = 0;
+		SRpnt->sr_data_direction = DMA_NONE;
+
+		scsi_wait_req (SRpnt, (void *) cmd, buffer,
+			       0, SR_TIMEOUT, MAX_RETRIES);
+
+		the_result = SRpnt->sr_result;
+		retries++;
+	} while (retries < 5 && 
+		 (!scsi_status_is_good(the_result) ||
+		  ((driver_byte(the_result) & DRIVER_SENSE) &&
+		   SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));
+
+	/* ask for mode page 0x2a */
+	rc = scsi_mode_sense(cd->device, 0, 0x2a, buffer, 128,
+			     SR_TIMEOUT, 3, &data);
+
+	if (!scsi_status_is_good(rc)) {
+		/* failed, drive doesn't have capabilities mode page */
+		cd->cdi.speed = 1;
+		cd->cdi.mask |= (CDC_CD_R | CDC_CD_RW | CDC_DVD_R |
+					 CDC_DVD | CDC_DVD_RAM |
+					 CDC_SELECT_DISC | CDC_SELECT_SPEED);
+		scsi_release_request(SRpnt);
+		kfree(buffer);
+		printk("%s: scsi-1 drive\n", cd->cdi.name);
+		return;
+	}
+
+	n = data.header_length + data.block_descriptor_length;
+	cd->cdi.speed = ((buffer[n + 8] << 8) + buffer[n + 9]) / 176;
+	cd->readcd_known = 1;
+	cd->readcd_cdda = buffer[n + 5] & 0x01;
+	/* print some capability bits */
+	printk("%s: scsi3-mmc drive: %dx/%dx %s%s%s%s%s%s\n", cd->cdi.name,
+	       ((buffer[n + 14] << 8) + buffer[n + 15]) / 176,
+	       cd->cdi.speed,
+	       buffer[n + 3] & 0x01 ? "writer " : "", /* CD Writer */
+	       buffer[n + 3] & 0x20 ? "dvd-ram " : "",
+	       buffer[n + 2] & 0x02 ? "cd/rw " : "", /* can read rewriteable */
+	       buffer[n + 4] & 0x20 ? "xa/form2 " : "",	/* can read xa/from2 */
+	       buffer[n + 5] & 0x01 ? "cdda " : "", /* can read audio data */
+	       loadmech[buffer[n + 6] >> 5]);
+	if ((buffer[n + 6] >> 5) == 0)
+		/* caddy drives can't close tray... */
+		cd->cdi.mask |= CDC_CLOSE_TRAY;
+	if ((buffer[n + 2] & 0x8) == 0)
+		/* not a DVD drive */
+		cd->cdi.mask |= CDC_DVD;
+	if ((buffer[n + 3] & 0x20) == 0) 
+		/* can't write DVD-RAM media */
+		cd->cdi.mask |= CDC_DVD_RAM;
+	if ((buffer[n + 3] & 0x10) == 0)
+		/* can't write DVD-R media */
+		cd->cdi.mask |= CDC_DVD_R;
+	if ((buffer[n + 3] & 0x2) == 0)
+		/* can't write CD-RW media */
+		cd->cdi.mask |= CDC_CD_RW;
+	if ((buffer[n + 3] & 0x1) == 0)
+		/* can't write CD-R media */
+		cd->cdi.mask |= CDC_CD_R;
+	if ((buffer[n + 6] & 0x8) == 0)
+		/* can't eject */
+		cd->cdi.mask |= CDC_OPEN_TRAY;
+
+	if ((buffer[n + 6] >> 5) == mechtype_individual_changer ||
+	    (buffer[n + 6] >> 5) == mechtype_cartridge_changer)
+		cd->cdi.capacity =
+		    cdrom_number_of_slots(&cd->cdi);
+	if (cd->cdi.capacity <= 1)
+		/* not a changer */
+		cd->cdi.mask |= CDC_SELECT_DISC;
+	/*else    I don't think it can close its tray
+		cd->cdi.mask |= CDC_CLOSE_TRAY; */
+
+	/*
+	 * if DVD-RAM, MRW-W or CD-RW, we are randomly writable
+	 */
+	if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) !=
+			(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) {
+		cd->device->writeable = 1;
+	}
+
+	scsi_release_request(SRpnt);
+	kfree(buffer);
+}
+
+/*
+ * sr_packet() is the entry point for the generic commands generated
+ * by the Uniform CD-ROM layer. 
+ */
+static int sr_packet(struct cdrom_device_info *cdi,
+		struct packet_command *cgc)
+{
+	if (cgc->timeout <= 0)
+		cgc->timeout = IOCTL_TIMEOUT;
+
+	sr_do_ioctl(cdi->handle, cgc);
+
+	return cgc->stat;
+}
+
+/**
+ *	sr_kref_release - Called to free the scsi_cd structure
+ *	@kref: pointer to embedded kref
+ *
+ *	sr_ref_sem must be held entering this routine.  Because it is
+ *	called on last put, you should always use the scsi_cd_get()
+ *	scsi_cd_put() helpers which manipulate the semaphore directly
+ *	and never do a direct kref_put().
+ **/
+static void sr_kref_release(struct kref *kref)
+{
+	struct scsi_cd *cd = container_of(kref, struct scsi_cd, kref);
+	struct gendisk *disk = cd->disk;
+
+	spin_lock(&sr_index_lock);
+	clear_bit(disk->first_minor, sr_index_bits);
+	spin_unlock(&sr_index_lock);
+
+	unregister_cdrom(&cd->cdi);
+
+	disk->private_data = NULL;
+
+	put_disk(disk);
+
+	kfree(cd);
+}
+
+static int sr_remove(struct device *dev)
+{
+	struct scsi_cd *cd = dev_get_drvdata(dev);
+
+	del_gendisk(cd->disk);
+
+	down(&sr_ref_sem);
+	kref_put(&cd->kref, sr_kref_release);
+	up(&sr_ref_sem);
+
+	return 0;
+}
+
+static int __init init_sr(void)
+{
+	int rc;
+
+	rc = register_blkdev(SCSI_CDROM_MAJOR, "sr");
+	if (rc)
+		return rc;
+	return scsi_register_driver(&sr_template.gendrv);
+}
+
+static void __exit exit_sr(void)
+{
+	scsi_unregister_driver(&sr_template.gendrv);
+	unregister_blkdev(SCSI_CDROM_MAJOR, "sr");
+}
+
+module_init(init_sr);
+module_exit(exit_sr);
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
new file mode 100644
index 0000000..0b31780
--- /dev/null
+++ b/drivers/scsi/sr.h
@@ -0,0 +1,68 @@
+/*
+ *      sr.h by David Giller
+ *      CD-ROM disk driver header file
+ *      
+ *      adapted from:
+ *      sd.h Copyright (C) 1992 Drew Eckhardt 
+ *      SCSI disk driver header file by
+ *              Drew Eckhardt 
+ *
+ *      <drew@colorado.edu>
+ *
+ *       Modified by Eric Youngdale eric@andante.org to
+ *       add scatter-gather, multiple outstanding request, and other
+ *       enhancements.
+ */
+
+#ifndef _SR_H
+#define _SR_H
+
+#include <linux/genhd.h>
+#include <linux/kref.h>
+
+struct scsi_device;
+
+/* The CDROM is fairly slow, so we need a little extra time */
+/* In fact, it is very slow if it has to spin up first */
+#define IOCTL_TIMEOUT 30*HZ
+
+
+typedef struct scsi_cd {
+	struct scsi_driver *driver;
+	unsigned capacity;	/* size in blocks                       */
+	struct scsi_device *device;
+	unsigned int vendor;	/* vendor code, see sr_vendor.c         */
+	unsigned long ms_offset;	/* for reading multisession-CD's        */
+	unsigned needs_sector_size:1;	/* needs to get sector size */
+	unsigned use:1;		/* is this device still supportable     */
+	unsigned xa_flag:1;	/* CD has XA sectors ? */
+	unsigned readcd_known:1;	/* drive supports READ_CD (0xbe) */
+	unsigned readcd_cdda:1;	/* reading audio data using READ_CD */
+	struct cdrom_device_info cdi;
+	/* We hold gendisk and scsi_device references on probe and use
+	 * the refs on this kref to decide when to release them */
+	struct kref kref;
+	struct gendisk *disk;
+} Scsi_CD;
+
+int sr_do_ioctl(Scsi_CD *, struct packet_command *);
+
+int sr_lock_door(struct cdrom_device_info *, int);
+int sr_tray_move(struct cdrom_device_info *, int);
+int sr_drive_status(struct cdrom_device_info *, int);
+int sr_disk_status(struct cdrom_device_info *);
+int sr_get_last_session(struct cdrom_device_info *, struct cdrom_multisession *);
+int sr_get_mcn(struct cdrom_device_info *, struct cdrom_mcn *);
+int sr_reset(struct cdrom_device_info *);
+int sr_select_speed(struct cdrom_device_info *cdi, int speed);
+int sr_audio_ioctl(struct cdrom_device_info *, unsigned int, void *);
+int sr_dev_ioctl(struct cdrom_device_info *, unsigned int, unsigned long);
+
+int sr_is_xa(Scsi_CD *);
+
+/* sr_vendor.c */
+void sr_vendor_init(Scsi_CD *);
+int sr_cd_check(struct cdrom_device_info *);
+int sr_set_blocklength(Scsi_CD *, int blocklength);
+
+#endif
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
new file mode 100644
index 0000000..3471be0
--- /dev/null
+++ b/drivers/scsi/sr_ioctl.c
@@ -0,0 +1,568 @@
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/blkdev.h>
+#include <linux/blkpg.h>
+#include <linux/cdrom.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+
+#include "sr.h"
+
+#if 0
+#define DEBUG
+#endif
+
+/* The sr_is_xa() seems to trigger firmware bugs with some drives :-(
+ * It is off by default and can be turned on with this module parameter */
+static int xa_test = 0;
+
+module_param(xa_test, int, S_IRUGO | S_IWUSR);
+
+
+#define IOCTL_RETRIES 3
+
+/* ATAPI drives don't have a SCMD_PLAYAUDIO_TI command.  When these drives
+   are emulating a SCSI device via the idescsi module, they need to have
+   CDROMPLAYTRKIND commands translated into CDROMPLAYMSF commands for them */
+
+static int sr_fake_playtrkind(struct cdrom_device_info *cdi, struct cdrom_ti *ti)
+{
+	struct cdrom_tocentry trk0_te, trk1_te;
+	struct cdrom_tochdr tochdr;
+	struct packet_command cgc;
+	int ntracks, ret;
+
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &tochdr)))
+		return ret;
+
+	ntracks = tochdr.cdth_trk1 - tochdr.cdth_trk0 + 1;
+	
+	if (ti->cdti_trk1 == ntracks) 
+		ti->cdti_trk1 = CDROM_LEADOUT;
+	else if (ti->cdti_trk1 != CDROM_LEADOUT)
+		ti->cdti_trk1 ++;
+
+	trk0_te.cdte_track = ti->cdti_trk0;
+	trk0_te.cdte_format = CDROM_MSF;
+	trk1_te.cdte_track = ti->cdti_trk1;
+	trk1_te.cdte_format = CDROM_MSF;
+	
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk0_te)))
+		return ret;
+	if ((ret = sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &trk1_te)))
+		return ret;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_PLAY_AUDIO_MSF;
+	cgc.cmd[3] = trk0_te.cdte_addr.msf.minute;
+	cgc.cmd[4] = trk0_te.cdte_addr.msf.second;
+	cgc.cmd[5] = trk0_te.cdte_addr.msf.frame;
+	cgc.cmd[6] = trk1_te.cdte_addr.msf.minute;
+	cgc.cmd[7] = trk1_te.cdte_addr.msf.second;
+	cgc.cmd[8] = trk1_te.cdte_addr.msf.frame;
+	cgc.data_direction = DMA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cdi->handle, &cgc);
+}
+
+/* We do our own retries because we want to know what the specific
+   error code is.  Normally the UNIT_ATTENTION code will automatically
+   clear after one error */
+
+int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
+{
+	struct scsi_request *SRpnt;
+	struct scsi_device *SDev;
+        struct request *req;
+	int result, err = 0, retries = 0;
+
+	SDev = cd->device;
+	SRpnt = scsi_allocate_request(SDev, GFP_KERNEL);
+        if (!SRpnt) {
+                printk(KERN_ERR "Unable to allocate SCSI request in sr_do_ioctl");
+		err = -ENOMEM;
+		goto out;
+        }
+	SRpnt->sr_data_direction = cgc->data_direction;
+
+      retry:
+	if (!scsi_block_when_processing_errors(SDev)) {
+		err = -ENODEV;
+		goto out_free;
+	}
+
+	scsi_wait_req(SRpnt, cgc->cmd, cgc->buffer, cgc->buflen,
+		      cgc->timeout, IOCTL_RETRIES);
+
+	req = SRpnt->sr_request;
+	if (SRpnt->sr_buffer && req->buffer && SRpnt->sr_buffer != req->buffer) {
+		memcpy(req->buffer, SRpnt->sr_buffer, SRpnt->sr_bufflen);
+		kfree(SRpnt->sr_buffer);
+		SRpnt->sr_buffer = req->buffer;
+        }
+
+	result = SRpnt->sr_result;
+
+	/* Minimal error checking.  Ignore cases we know about, and report the rest. */
+	if (driver_byte(result) != 0) {
+		switch (SRpnt->sr_sense_buffer[2] & 0xf) {
+		case UNIT_ATTENTION:
+			SDev->changed = 1;
+			if (!cgc->quiet)
+				printk(KERN_INFO "%s: disc change detected.\n", cd->cdi.name);
+			if (retries++ < 10)
+				goto retry;
+			err = -ENOMEDIUM;
+			break;
+		case NOT_READY:	/* This happens if there is no disc in drive */
+			if (SRpnt->sr_sense_buffer[12] == 0x04 &&
+			    SRpnt->sr_sense_buffer[13] == 0x01) {
+				/* sense: Logical unit is in process of becoming ready */
+				if (!cgc->quiet)
+					printk(KERN_INFO "%s: CDROM not ready yet.\n", cd->cdi.name);
+				if (retries++ < 10) {
+					/* sleep 2 sec and try again */
+					ssleep(2);
+					goto retry;
+				} else {
+					/* 20 secs are enough? */
+					err = -ENOMEDIUM;
+					break;
+				}
+			}
+			if (!cgc->quiet)
+				printk(KERN_INFO "%s: CDROM not ready.  Make sure there is a disc in the drive.\n", cd->cdi.name);
+#ifdef DEBUG
+			scsi_print_req_sense("sr", SRpnt);
+#endif
+			err = -ENOMEDIUM;
+			break;
+		case ILLEGAL_REQUEST:
+			err = -EIO;
+			if (SRpnt->sr_sense_buffer[12] == 0x20 &&
+			    SRpnt->sr_sense_buffer[13] == 0x00)
+				/* sense: Invalid command operation code */
+				err = -EDRIVE_CANT_DO_THIS;
+#ifdef DEBUG
+			__scsi_print_command(cgc->cmd);
+			scsi_print_req_sense("sr", SRpnt);
+#endif
+			break;
+		default:
+			printk(KERN_ERR "%s: CDROM (ioctl) error, command: ", cd->cdi.name);
+			__scsi_print_command(cgc->cmd);
+			scsi_print_req_sense("sr", SRpnt);
+			err = -EIO;
+		}
+	}
+
+	if (cgc->sense)
+		memcpy(cgc->sense, SRpnt->sr_sense_buffer, sizeof(*cgc->sense));
+
+	/* Wake up a process waiting for device */
+      out_free:
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+      out:
+	cgc->stat = err;
+	return err;
+}
+
+/* ---------------------------------------------------------------------- */
+/* interface to cdrom.c                                                   */
+
+static int test_unit_ready(Scsi_CD *cd)
+{
+	struct packet_command cgc;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
+	cgc.quiet = 1;
+	cgc.data_direction = DMA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
+}
+
+int sr_tray_move(struct cdrom_device_info *cdi, int pos)
+{
+	Scsi_CD *cd = cdi->handle;
+	struct packet_command cgc;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_START_STOP_UNIT;
+	cgc.cmd[4] = (pos == 0) ? 0x03 /* close */ : 0x02 /* eject */ ;
+	cgc.data_direction = DMA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
+}
+
+int sr_lock_door(struct cdrom_device_info *cdi, int lock)
+{
+	Scsi_CD *cd = cdi->handle;
+
+	return scsi_set_medium_removal(cd->device, lock ?
+		       SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
+}
+
+int sr_drive_status(struct cdrom_device_info *cdi, int slot)
+{
+	if (CDSL_CURRENT != slot) {
+		/* we have no changer support */
+		return -EINVAL;
+	}
+	if (0 == test_unit_ready(cdi->handle))
+		return CDS_DISC_OK;
+
+	return CDS_TRAY_OPEN;
+}
+
+int sr_disk_status(struct cdrom_device_info *cdi)
+{
+	Scsi_CD *cd = cdi->handle;
+	struct cdrom_tochdr toc_h;
+	struct cdrom_tocentry toc_e;
+	int i, rc, have_datatracks = 0;
+
+	/* look for data tracks */
+	if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
+		return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
+
+	for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
+		toc_e.cdte_track = i;
+		toc_e.cdte_format = CDROM_LBA;
+		if (sr_audio_ioctl(cdi, CDROMREADTOCENTRY, &toc_e))
+			return CDS_NO_INFO;
+		if (toc_e.cdte_ctrl & CDROM_DATA_TRACK) {
+			have_datatracks = 1;
+			break;
+		}
+	}
+	if (!have_datatracks)
+		return CDS_AUDIO;
+
+	if (cd->xa_flag)
+		return CDS_XA_2_1;
+	else
+		return CDS_DATA_1;
+}
+
+int sr_get_last_session(struct cdrom_device_info *cdi,
+			struct cdrom_multisession *ms_info)
+{
+	Scsi_CD *cd = cdi->handle;
+
+	ms_info->addr.lba = cd->ms_offset;
+	ms_info->xa_flag = cd->xa_flag || cd->ms_offset > 0;
+
+	return 0;
+}
+
+/* primitive to determine whether we need to have GFP_DMA set based on
+ * the status of the unchecked_isa_dma flag in the host structure */
+#define SR_GFP_DMA(cd) (((cd)->device->host->unchecked_isa_dma) ? GFP_DMA : 0)
+
+int sr_get_mcn(struct cdrom_device_info *cdi, struct cdrom_mcn *mcn)
+{
+	Scsi_CD *cd = cdi->handle;
+	struct packet_command cgc;
+	char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+	int result;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_READ_SUBCHANNEL;
+	cgc.cmd[2] = 0x40;	/* I do want the subchannel info */
+	cgc.cmd[3] = 0x02;	/* Give me medium catalog number info */
+	cgc.cmd[8] = 24;
+	cgc.buffer = buffer;
+	cgc.buflen = 24;
+	cgc.data_direction = DMA_FROM_DEVICE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	result = sr_do_ioctl(cd, &cgc);
+
+	memcpy(mcn->medium_catalog_number, buffer + 9, 13);
+	mcn->medium_catalog_number[13] = 0;
+
+	kfree(buffer);
+	return result;
+}
+
+int sr_reset(struct cdrom_device_info *cdi)
+{
+	return 0;
+}
+
+int sr_select_speed(struct cdrom_device_info *cdi, int speed)
+{
+	Scsi_CD *cd = cdi->handle;
+	struct packet_command cgc;
+
+	if (speed == 0)
+		speed = 0xffff;	/* set to max */
+	else
+		speed *= 177;	/* Nx to kbyte/s */
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_SET_SPEED;	/* SET CD SPEED */
+	cgc.cmd[2] = (speed >> 8) & 0xff;	/* MSB for speed (in kbytes/sec) */
+	cgc.cmd[3] = speed & 0xff;	/* LSB */
+	cgc.data_direction = DMA_NONE;
+	cgc.timeout = IOCTL_TIMEOUT;
+
+	if (sr_do_ioctl(cd, &cgc))
+		return -EIO;
+	return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+/* this is called by the generic cdrom driver. arg is a _kernel_ pointer,  */
+/* because the generic cdrom driver does the user access stuff for us.     */
+/* only cdromreadtochdr and cdromreadtocentry are left - for use with the  */
+/* sr_disk_status interface for the generic cdrom driver.                  */
+
+int sr_audio_ioctl(struct cdrom_device_info *cdi, unsigned int cmd, void *arg)
+{
+	Scsi_CD *cd = cdi->handle;
+	struct packet_command cgc;
+	int result;
+	unsigned char *buffer = kmalloc(32, GFP_KERNEL | SR_GFP_DMA(cd));
+
+	if (!buffer)
+		return -ENOMEM;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.timeout = IOCTL_TIMEOUT;
+
+	switch (cmd) {
+	case CDROMREADTOCHDR:
+		{
+			struct cdrom_tochdr *tochdr = (struct cdrom_tochdr *) arg;
+
+			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			cgc.cmd[8] = 12;		/* LSB of length */
+			cgc.buffer = buffer;
+			cgc.buflen = 12;
+			cgc.quiet = 1;
+			cgc.data_direction = DMA_FROM_DEVICE;
+
+			result = sr_do_ioctl(cd, &cgc);
+
+			tochdr->cdth_trk0 = buffer[2];
+			tochdr->cdth_trk1 = buffer[3];
+
+			break;
+		}
+
+	case CDROMREADTOCENTRY:
+		{
+			struct cdrom_tocentry *tocentry = (struct cdrom_tocentry *) arg;
+
+			cgc.cmd[0] = GPCMD_READ_TOC_PMA_ATIP;
+			cgc.cmd[1] |= (tocentry->cdte_format == CDROM_MSF) ? 0x02 : 0;
+			cgc.cmd[6] = tocentry->cdte_track;
+			cgc.cmd[8] = 12;		/* LSB of length */
+			cgc.buffer = buffer;
+			cgc.buflen = 12;
+			cgc.data_direction = DMA_FROM_DEVICE;
+
+			result = sr_do_ioctl(cd, &cgc);
+
+			tocentry->cdte_ctrl = buffer[5] & 0xf;
+			tocentry->cdte_adr = buffer[5] >> 4;
+			tocentry->cdte_datamode = (tocentry->cdte_ctrl & 0x04) ? 1 : 0;
+			if (tocentry->cdte_format == CDROM_MSF) {
+				tocentry->cdte_addr.msf.minute = buffer[9];
+				tocentry->cdte_addr.msf.second = buffer[10];
+				tocentry->cdte_addr.msf.frame = buffer[11];
+			} else
+				tocentry->cdte_addr.lba = (((((buffer[8] << 8) + buffer[9]) << 8)
+					+ buffer[10]) << 8) + buffer[11];
+
+			break;
+		}
+
+	case CDROMPLAYTRKIND: {
+		struct cdrom_ti* ti = (struct cdrom_ti*)arg;
+
+		cgc.cmd[0] = GPCMD_PLAYAUDIO_TI;
+		cgc.cmd[4] = ti->cdti_trk0;
+		cgc.cmd[5] = ti->cdti_ind0;
+		cgc.cmd[7] = ti->cdti_trk1;
+		cgc.cmd[8] = ti->cdti_ind1;
+		cgc.data_direction = DMA_NONE;
+
+		result = sr_do_ioctl(cd, &cgc);
+		if (result == -EDRIVE_CANT_DO_THIS)
+			result = sr_fake_playtrkind(cdi, ti);
+
+		break;
+	}
+
+	default:
+		result = -EINVAL;
+	}
+
+#if 0
+	if (result)
+		printk("DEBUG: sr_audio: result for ioctl %x: %x\n", cmd, result);
+#endif
+
+	kfree(buffer);
+	return result;
+}
+
+/* -----------------------------------------------------------------------
+ * a function to read all sorts of funny cdrom sectors using the READ_CD
+ * scsi-3 mmc command
+ *
+ * lba:     linear block address
+ * format:  0 = data (anything)
+ *          1 = audio
+ *          2 = data (mode 1)
+ *          3 = data (mode 2)
+ *          4 = data (mode 2 form1)
+ *          5 = data (mode 2 form2)
+ * blksize: 2048 | 2336 | 2340 | 2352
+ */
+
+static int sr_read_cd(Scsi_CD *cd, unsigned char *dest, int lba, int format, int blksize)
+{
+	struct packet_command cgc;
+
+#ifdef DEBUG
+	printk("%s: sr_read_cd lba=%d format=%d blksize=%d\n",
+	       cd->cdi.name, lba, format, blksize);
+#endif
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_READ_CD;	/* READ_CD */
+	cgc.cmd[1] = ((format & 7) << 2);
+	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cgc.cmd[5] = (unsigned char) lba & 0xff;
+	cgc.cmd[8] = 1;
+	switch (blksize) {
+	case 2336:
+		cgc.cmd[9] = 0x58;
+		break;
+	case 2340:
+		cgc.cmd[9] = 0x78;
+		break;
+	case 2352:
+		cgc.cmd[9] = 0xf8;
+		break;
+	default:
+		cgc.cmd[9] = 0x10;
+		break;
+	}
+	cgc.buffer = dest;
+	cgc.buflen = blksize;
+	cgc.data_direction = DMA_FROM_DEVICE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	return sr_do_ioctl(cd, &cgc);
+}
+
+/*
+ * read sectors with blocksizes other than 2048
+ */
+
+static int sr_read_sector(Scsi_CD *cd, int lba, int blksize, unsigned char *dest)
+{
+	struct packet_command cgc;
+	int rc;
+
+	/* we try the READ CD command first... */
+	if (cd->readcd_known) {
+		rc = sr_read_cd(cd, dest, lba, 0, blksize);
+		if (-EDRIVE_CANT_DO_THIS != rc)
+			return rc;
+		cd->readcd_known = 0;
+		printk("CDROM does'nt support READ CD (0xbe) command\n");
+		/* fall & retry the other way */
+	}
+	/* ... if this fails, we switch the blocksize using MODE SELECT */
+	if (blksize != cd->device->sector_size) {
+		if (0 != (rc = sr_set_blocklength(cd, blksize)))
+			return rc;
+	}
+#ifdef DEBUG
+	printk("%s: sr_read_sector lba=%d blksize=%d\n", cd->cdi.name, lba, blksize);
+#endif
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = GPCMD_READ_10;
+	cgc.cmd[2] = (unsigned char) (lba >> 24) & 0xff;
+	cgc.cmd[3] = (unsigned char) (lba >> 16) & 0xff;
+	cgc.cmd[4] = (unsigned char) (lba >> 8) & 0xff;
+	cgc.cmd[5] = (unsigned char) lba & 0xff;
+	cgc.cmd[8] = 1;
+	cgc.buffer = dest;
+	cgc.buflen = blksize;
+	cgc.data_direction = DMA_FROM_DEVICE;
+	cgc.timeout = IOCTL_TIMEOUT;
+	rc = sr_do_ioctl(cd, &cgc);
+
+	return rc;
+}
+
+/*
+ * read a sector in raw mode to check the sector format
+ * ret: 1 == mode2 (XA), 0 == mode1, <0 == error 
+ */
+
+int sr_is_xa(Scsi_CD *cd)
+{
+	unsigned char *raw_sector;
+	int is_xa;
+
+	if (!xa_test)
+		return 0;
+
+	raw_sector = (unsigned char *) kmalloc(2048, GFP_KERNEL | SR_GFP_DMA(cd));
+	if (!raw_sector)
+		return -ENOMEM;
+	if (0 == sr_read_sector(cd, cd->ms_offset + 16,
+				CD_FRAMESIZE_RAW1, raw_sector)) {
+		is_xa = (raw_sector[3] == 0x02) ? 1 : 0;
+	} else {
+		/* read a raw sector failed for some reason. */
+		is_xa = -1;
+	}
+	kfree(raw_sector);
+#ifdef DEBUG
+	printk("%s: sr_is_xa: %d\n", cd->cdi.name, is_xa);
+#endif
+	return is_xa;
+}
+
+int sr_dev_ioctl(struct cdrom_device_info *cdi,
+		 unsigned int cmd, unsigned long arg)
+{
+	Scsi_CD *cd = cdi->handle;
+	int ret;
+	
+	ret = scsi_nonblockable_ioctl(cd->device, cmd,
+				      (void __user *)arg, NULL);
+	/*
+	 * ENODEV means that we didn't recognise the ioctl, or that we
+	 * cannot execute it in the current device state.  In either
+	 * case fall through to scsi_ioctl, which will return ENDOEV again
+	 * if it doesn't recognise the ioctl
+	 */
+	if (ret != -ENODEV)
+		return ret;
+	return scsi_ioctl(cd->device, cmd, (void __user *)arg);
+}
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
new file mode 100644
index 0000000..78274dc
--- /dev/null
+++ b/drivers/scsi/sr_vendor.c
@@ -0,0 +1,329 @@
+/* -*-linux-c-*-
+
+ * vendor-specific code for SCSI CD-ROM's goes here.
+ *
+ * This is needed becauce most of the new features (multisession and
+ * the like) are too new to be included into the SCSI-II standard (to
+ * be exact: there is'nt anything in my draft copy).
+ *
+ * Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
+ *           multisession using the READ TOC command (like SONY).
+ *
+ *           Rearranged stuff here: SCSI-3 is included allways, support
+ *           for NEC/TOSHIBA/HP commands is optional.
+ *
+ *   Gerd Knorr <kraxel@cs.tu-berlin.de> 
+ *
+ * --------------------------------------------------------------------------
+ *
+ * support for XA/multisession-CD's
+ * 
+ *   - NEC:     Detection and support of multisession CD's.
+ *     
+ *   - TOSHIBA: Detection and support of multisession CD's.
+ *              Some XA-Sector tweaking, required for older drives.
+ *
+ *   - SONY:    Detection and support of multisession CD's.
+ *              added by Thomas Quinot <thomas@cuivre.freenix.fr>
+ *
+ *   - PIONEER, HITACHI, PLEXTOR, MATSHITA, TEAC, PHILIPS: known to
+ *              work with SONY (SCSI3 now)  code.
+ *
+ *   - HP:      Much like SONY, but a little different... (Thomas)
+ *              HP-Writers only ??? Maybe other CD-Writers work with this too ?
+ *              HP 6020 writers now supported.
+ */
+
+#include <linux/config.h>
+#include <linux/cdrom.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/bcd.h>
+#include <linux/blkdev.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+
+#include "sr.h"
+
+#if 0
+#define DEBUG
+#endif
+
+/* here are some constants to sort the vendors into groups */
+
+#define VENDOR_SCSI3           1	/* default: scsi-3 mmc */
+
+#define VENDOR_NEC             2
+#define VENDOR_TOSHIBA         3
+#define VENDOR_WRITER          4	/* pre-scsi3 writers */
+
+#define VENDOR_TIMEOUT	30*HZ
+
+void sr_vendor_init(Scsi_CD *cd)
+{
+#ifndef CONFIG_BLK_DEV_SR_VENDOR
+	cd->vendor = VENDOR_SCSI3;
+#else
+	char *vendor = cd->device->vendor;
+	char *model = cd->device->model;
+	
+	/* default */
+	cd->vendor = VENDOR_SCSI3;
+	if (cd->readcd_known)
+		/* this is true for scsi3/mmc drives - no more checks */
+		return;
+
+	if (cd->device->type == TYPE_WORM) {
+		cd->vendor = VENDOR_WRITER;
+
+	} else if (!strncmp(vendor, "NEC", 3)) {
+		cd->vendor = VENDOR_NEC;
+		if (!strncmp(model, "CD-ROM DRIVE:25", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:36", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:83", 15) ||
+		    !strncmp(model, "CD-ROM DRIVE:84 ", 16)
+#if 0
+		/* my NEC 3x returns the read-raw data if a read-raw
+		   is followed by a read for the same sector - aeb */
+		    || !strncmp(model, "CD-ROM DRIVE:500", 16)
+#endif
+		    )
+			/* these can't handle multisession, may hang */
+			cd->cdi.mask |= CDC_MULTI_SESSION;
+
+	} else if (!strncmp(vendor, "TOSHIBA", 7)) {
+		cd->vendor = VENDOR_TOSHIBA;
+
+	}
+#endif
+}
+
+
+/* small handy function for switching block length using MODE SELECT,
+ * used by sr_read_sector() */
+
+int sr_set_blocklength(Scsi_CD *cd, int blocklength)
+{
+	unsigned char *buffer;	/* the buffer for the ioctl */
+	struct packet_command cgc;
+	struct ccs_modesel_head *modesel;
+	int rc, density = 0;
+
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+	if (cd->vendor == VENDOR_TOSHIBA)
+		density = (blocklength > 2048) ? 0x81 : 0x83;
+#endif
+
+	buffer = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+#ifdef DEBUG
+	printk("%s: MODE SELECT 0x%x/%d\n", cd->cdi.name, density, blocklength);
+#endif
+	memset(&cgc, 0, sizeof(struct packet_command));
+	cgc.cmd[0] = MODE_SELECT;
+	cgc.cmd[1] = (1 << 4);
+	cgc.cmd[4] = 12;
+	modesel = (struct ccs_modesel_head *) buffer;
+	memset(modesel, 0, sizeof(*modesel));
+	modesel->block_desc_length = 0x08;
+	modesel->density = density;
+	modesel->block_length_med = (blocklength >> 8) & 0xff;
+	modesel->block_length_lo = blocklength & 0xff;
+	cgc.buffer = buffer;
+	cgc.buflen = sizeof(*modesel);
+	cgc.data_direction = DMA_TO_DEVICE;
+	cgc.timeout = VENDOR_TIMEOUT;
+	if (0 == (rc = sr_do_ioctl(cd, &cgc))) {
+		cd->device->sector_size = blocklength;
+	}
+#ifdef DEBUG
+	else
+		printk("%s: switching blocklength to %d bytes failed\n",
+		       cd->cdi.name, blocklength);
+#endif
+	kfree(buffer);
+	return rc;
+}
+
+/* This function gets called after a media change. Checks if the CD is
+   multisession, asks for offset etc. */
+
+int sr_cd_check(struct cdrom_device_info *cdi)
+{
+	Scsi_CD *cd = cdi->handle;
+	unsigned long sector;
+	unsigned char *buffer;	/* the buffer for the ioctl */
+	struct packet_command cgc;
+	int rc, no_multi;
+
+	if (cd->cdi.mask & CDC_MULTI_SESSION)
+		return 0;
+
+	buffer = (unsigned char *) kmalloc(512, GFP_KERNEL | GFP_DMA);
+	if (!buffer)
+		return -ENOMEM;
+
+	sector = 0;		/* the multisession sector offset goes here  */
+	no_multi = 0;		/* flag: the drive can't handle multisession */
+	rc = 0;
+
+	memset(&cgc, 0, sizeof(struct packet_command));
+
+	switch (cd->vendor) {
+
+	case VENDOR_SCSI3:
+		cgc.cmd[0] = READ_TOC;
+		cgc.cmd[8] = 12;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 12;
+		cgc.quiet = 1;
+		cgc.data_direction = DMA_FROM_DEVICE;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
+		if (rc != 0)
+			break;
+		if ((buffer[0] << 8) + buffer[1] < 0x0a) {
+			printk(KERN_INFO "%s: Hmm, seems the drive "
+			   "doesn't support multisession CD's\n", cd->cdi.name);
+			no_multi = 1;
+			break;
+		}
+		sector = buffer[11] + (buffer[10] << 8) +
+		    (buffer[9] << 16) + (buffer[8] << 24);
+		if (buffer[6] <= 1) {
+			/* ignore sector offsets from first track */
+			sector = 0;
+		}
+		break;
+
+#ifdef CONFIG_BLK_DEV_SR_VENDOR
+	case VENDOR_NEC:{
+			unsigned long min, sec, frame;
+			cgc.cmd[0] = 0xde;
+			cgc.cmd[1] = 0x03;
+			cgc.cmd[2] = 0xb0;
+			cgc.buffer = buffer;
+			cgc.buflen = 0x16;
+			cgc.quiet = 1;
+			cgc.data_direction = DMA_FROM_DEVICE;
+			cgc.timeout = VENDOR_TIMEOUT;
+			rc = sr_do_ioctl(cd, &cgc);
+			if (rc != 0)
+				break;
+			if (buffer[14] != 0 && buffer[14] != 0xb0) {
+				printk(KERN_INFO "%s: Hmm, seems the cdrom "
+				       "doesn't support multisession CD's\n",
+				       cd->cdi.name);
+				no_multi = 1;
+				break;
+			}
+			min = BCD2BIN(buffer[15]);
+			sec = BCD2BIN(buffer[16]);
+			frame = BCD2BIN(buffer[17]);
+			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
+			break;
+		}
+
+	case VENDOR_TOSHIBA:{
+			unsigned long min, sec, frame;
+
+			/* we request some disc information (is it a XA-CD ?,
+			 * where starts the last session ?) */
+			cgc.cmd[0] = 0xc7;
+			cgc.cmd[1] = 0x03;
+			cgc.buffer = buffer;
+			cgc.buflen = 4;
+			cgc.quiet = 1;
+			cgc.data_direction = DMA_FROM_DEVICE;
+			cgc.timeout = VENDOR_TIMEOUT;
+			rc = sr_do_ioctl(cd, &cgc);
+			if (rc == -EINVAL) {
+				printk(KERN_INFO "%s: Hmm, seems the drive "
+				       "doesn't support multisession CD's\n",
+				       cd->cdi.name);
+				no_multi = 1;
+				break;
+			}
+			if (rc != 0)
+				break;
+			min = BCD2BIN(buffer[1]);
+			sec = BCD2BIN(buffer[2]);
+			frame = BCD2BIN(buffer[3]);
+			sector = min * CD_SECS * CD_FRAMES + sec * CD_FRAMES + frame;
+			if (sector)
+				sector -= CD_MSF_OFFSET;
+			sr_set_blocklength(cd, 2048);
+			break;
+		}
+
+	case VENDOR_WRITER:
+		cgc.cmd[0] = READ_TOC;
+		cgc.cmd[8] = 0x04;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 0x04;
+		cgc.quiet = 1;
+		cgc.data_direction = DMA_FROM_DEVICE;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
+		if (rc != 0) {
+			break;
+		}
+		if ((rc = buffer[2]) == 0) {
+			printk(KERN_WARNING
+			       "%s: No finished session\n", cd->cdi.name);
+			break;
+		}
+		cgc.cmd[0] = READ_TOC;	/* Read TOC */
+		cgc.cmd[6] = rc & 0x7f;	/* number of last session */
+		cgc.cmd[8] = 0x0c;
+		cgc.cmd[9] = 0x40;
+		cgc.buffer = buffer;
+		cgc.buflen = 12;
+		cgc.quiet = 1;
+		cgc.data_direction = DMA_FROM_DEVICE;
+		cgc.timeout = VENDOR_TIMEOUT;
+		rc = sr_do_ioctl(cd, &cgc);
+		if (rc != 0) {
+			break;
+		}
+		sector = buffer[11] + (buffer[10] << 8) +
+		    (buffer[9] << 16) + (buffer[8] << 24);
+		break;
+#endif				/* CONFIG_BLK_DEV_SR_VENDOR */
+
+	default:
+		/* should not happen */
+		printk(KERN_WARNING
+		   "%s: unknown vendor code (%i), not initialized ?\n",
+		       cd->cdi.name, cd->vendor);
+		sector = 0;
+		no_multi = 1;
+		break;
+	}
+	cd->ms_offset = sector;
+	cd->xa_flag = 0;
+	if (CDS_AUDIO != sr_disk_status(cdi) && 1 == sr_is_xa(cd))
+		cd->xa_flag = 1;
+
+	if (2048 != cd->device->sector_size) {
+		sr_set_blocklength(cd, 2048);
+	}
+	if (no_multi)
+		cdi->mask |= CDC_MULTI_SESSION;
+
+#ifdef DEBUG
+	if (sector)
+		printk(KERN_DEBUG "%s: multisession offset=%lu\n",
+		       cd->cdi.name, sector);
+#endif
+	kfree(buffer);
+	return rc;
+}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
new file mode 100644
index 0000000..265d1ee
--- /dev/null
+++ b/drivers/scsi/st.c
@@ -0,0 +1,4438 @@
+/*
+   SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying
+   file Documentation/scsi/st.txt for more information.
+
+   History:
+   Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
+   Contribution and ideas from several people including (in alphabetical
+   order) Klaus Ehrenfried, Eugene Exarevsky, Eric Lee Green, Wolfgang Denk,
+   Steve Hirsch, Andreas Koppenh"ofer, Michael Leodolter, Eyal Lebedinsky,
+   Michael Schaefer, J"org Weule, and Eric Youngdale.
+
+   Copyright 1992 - 2005 Kai Makisara
+   email Kai.Makisara@kolumbus.fi
+
+   Some small formal changes - aeb, 950809
+
+   Last modified: 18-JAN-1998 Richard Gooch <rgooch@atnf.csiro.au> Devfs support
+ */
+
+static char *verstr = "20050312";
+
+#include <linux/module.h>
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+#include <linux/spinlock.h>
+#include <linux/blkdev.h>
+#include <linux/moduleparam.h>
+#include <linux/devfs_fs_kernel.h>
+#include <linux/cdev.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_dbg.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_driver.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_ioctl.h>
+#include <scsi/scsi_request.h>
+
+
+/* The driver prints some debugging information on the console if DEBUG
+   is defined and non-zero. */
+#define DEBUG 0
+
+#if DEBUG
+/* The message level for the debug messages is currently set to KERN_NOTICE
+   so that people can easily see the messages. Later when the debugging messages
+   in the drivers are more widely classified, this may be changed to KERN_DEBUG. */
+#define ST_DEB_MSG  KERN_NOTICE
+#define DEB(a) a
+#define DEBC(a) if (debugging) { a ; }
+#else
+#define DEB(a)
+#define DEBC(a)
+#endif
+
+#define ST_KILOBYTE 1024
+
+#include "st_options.h"
+#include "st.h"
+
+static int buffer_kbs;
+static int max_sg_segs;
+static int try_direct_io = TRY_DIRECT_IO;
+static int try_rdio = 1;
+static int try_wdio = 1;
+
+static int st_dev_max;
+static int st_nr_dev;
+
+static struct class_simple *st_sysfs_class;
+
+MODULE_AUTHOR("Kai Makisara");
+MODULE_DESCRIPTION("SCSI Tape Driver");
+MODULE_LICENSE("GPL");
+
+/* Set 'perm' (4th argument) to 0 to disable module_param's definition
+ * of sysfs parameters (which module_param doesn't yet support).
+ * Sysfs parameters defined explicitly later.
+ */
+module_param_named(buffer_kbs, buffer_kbs, int, 0);
+MODULE_PARM_DESC(buffer_kbs, "Default driver buffer size for fixed block mode (KB; 32)");
+module_param_named(max_sg_segs, max_sg_segs, int, 0);
+MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
+module_param_named(try_direct_io, try_direct_io, int, 0);
+MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
+
+/* Extra parameters for testing */
+module_param_named(try_rdio, try_rdio, int, 0);
+MODULE_PARM_DESC(try_rdio, "Try direct read i/o when possible");
+module_param_named(try_wdio, try_wdio, int, 0);
+MODULE_PARM_DESC(try_wdio, "Try direct write i/o when possible");
+
+#ifndef MODULE
+static int write_threshold_kbs;  /* retained for compatibility */
+static struct st_dev_parm {
+	char *name;
+	int *val;
+} parms[] __initdata = {
+	{
+		"buffer_kbs", &buffer_kbs
+	},
+	{       /* Retained for compatibility with 2.4 */
+		"write_threshold_kbs", &write_threshold_kbs
+	},
+	{
+		"max_sg_segs", NULL
+	},
+	{
+		"try_direct_io", &try_direct_io
+	}
+};
+#endif
+
+/* Restrict the number of modes so that names for all are assigned */
+#if ST_NBR_MODES > 16
+#error "Maximum number of modes is 16"
+#endif
+/* Bit reversed order to get same names for same minors with all
+   mode counts */
+static char *st_formats[] = {
+	"",  "r", "k", "s", "l", "t", "o", "u",
+	"m", "v", "p", "x", "a", "y", "q", "z"}; 
+
+/* The default definitions have been moved to st_options.h */
+
+#define ST_FIXED_BUFFER_SIZE (ST_FIXED_BUFFER_BLOCKS * ST_KILOBYTE)
+
+/* The buffer size should fit into the 24 bits for length in the
+   6-byte SCSI read and write commands. */
+#if ST_FIXED_BUFFER_SIZE >= (2 << 24 - 1)
+#error "Buffer size should not exceed (2 << 24 - 1) bytes!"
+#endif
+
+static int debugging = DEBUG;
+
+#define MAX_RETRIES 0
+#define MAX_WRITE_RETRIES 0
+#define MAX_READY_RETRIES 0
+#define NO_TAPE  NOT_READY
+
+#define ST_TIMEOUT (900 * HZ)
+#define ST_LONG_TIMEOUT (14000 * HZ)
+
+/* Remove mode bits and auto-rewind bit (7) */
+#define TAPE_NR(x) ( ((iminor(x) & ~255) >> (ST_NBR_MODE_BITS + 1)) | \
+    (iminor(x) & ~(-1 << ST_MODE_SHIFT)) )
+#define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
+
+/* Construct the minor number from the device (d), mode (m), and non-rewind (n) data */
+#define TAPE_MINOR(d, m, n) (((d & ~(255 >> (ST_NBR_MODE_BITS + 1))) << (ST_NBR_MODE_BITS + 1)) | \
+  (d & (255 >> (ST_NBR_MODE_BITS + 1))) | (m << ST_MODE_SHIFT) | ((n != 0) << 7) )
+
+/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
+   24 bits) */
+#define SET_DENS_AND_BLK 0x10001
+
+static DEFINE_RWLOCK(st_dev_arr_lock);
+
+static int st_fixed_buffer_size = ST_FIXED_BUFFER_SIZE;
+static int st_max_sg_segs = ST_MAX_SG;
+
+static struct scsi_tape **scsi_tapes = NULL;
+
+static int modes_defined;
+
+static struct st_buffer *new_tape_buffer(int, int, int);
+static int enlarge_buffer(struct st_buffer *, int, int);
+static void normalize_buffer(struct st_buffer *);
+static int append_to_buffer(const char __user *, struct st_buffer *, int);
+static int from_buffer(struct st_buffer *, char __user *, int);
+static void move_buffer_data(struct st_buffer *, int);
+static void buf_to_sg(struct st_buffer *, unsigned int);
+
+static int st_map_user_pages(struct scatterlist *, const unsigned int, 
+			     unsigned long, size_t, int, unsigned long);
+static int sgl_map_user_pages(struct scatterlist *, const unsigned int, 
+			      unsigned long, size_t, int);
+static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int);
+
+static int st_probe(struct device *);
+static int st_remove(struct device *);
+static int st_init_command(struct scsi_cmnd *);
+
+static void do_create_driverfs_files(void);
+static void do_remove_driverfs_files(void);
+static void do_create_class_files(struct scsi_tape *, int, int);
+
+static struct scsi_driver st_template = {
+	.owner			= THIS_MODULE,
+	.gendrv = {
+		.name		= "st",
+		.probe		= st_probe,
+		.remove		= st_remove,
+	},
+	.init_command		= st_init_command,
+};
+
+static int st_compression(struct scsi_tape *, int);
+
+static int find_partition(struct scsi_tape *);
+static int switch_partition(struct scsi_tape *);
+
+static int st_int_ioctl(struct scsi_tape *, unsigned int, unsigned long);
+
+
+#include "osst_detect.h"
+#ifndef SIGS_FROM_OSST
+#define SIGS_FROM_OSST \
+	{"OnStream", "SC-", "", "osst"}, \
+	{"OnStream", "DI-", "", "osst"}, \
+	{"OnStream", "DP-", "", "osst"}, \
+	{"OnStream", "USB", "", "osst"}, \
+	{"OnStream", "FW-", "", "osst"}
+#endif
+
+struct st_reject_data {
+	char *vendor;
+	char *model;
+	char *rev;
+	char *driver_hint; /* Name of the correct driver, NULL if unknown */
+};
+
+static struct st_reject_data reject_list[] = {
+	/* {"XXX", "Yy-", "", NULL},  example */
+	SIGS_FROM_OSST,
+	{NULL, }};
+
+/* If the device signature is on the list of incompatible drives, the
+   function returns a pointer to the name of the correct driver (if known) */
+static char * st_incompatible(struct scsi_device* SDp)
+{
+	struct st_reject_data *rp;
+
+	for (rp=&(reject_list[0]); rp->vendor != NULL; rp++)
+		if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) &&
+		    !strncmp(rp->model, SDp->model, strlen(rp->model)) &&
+		    !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) {
+			if (rp->driver_hint)
+				return rp->driver_hint;
+			else
+				return "unknown";
+		}
+	return NULL;
+}
+
+
+static inline char *tape_name(struct scsi_tape *tape)
+{
+	return tape->disk->disk_name;
+}
+
+
+static void st_analyze_sense(struct scsi_request *SRpnt, struct st_cmdstatus *s)
+{
+	const u8 *ucp;
+	const u8 *sense = SRpnt->sr_sense_buffer;
+
+	s->have_sense = scsi_request_normalize_sense(SRpnt, &s->sense_hdr);
+	s->flags = 0;
+
+	if (s->have_sense) {
+		s->deferred = 0;
+		s->remainder_valid =
+			scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64);
+		switch (sense[0] & 0x7f) {
+		case 0x71:
+			s->deferred = 1;
+		case 0x70:
+			s->fixed_format = 1;
+			s->flags = sense[2] & 0xe0;
+			break;
+		case 0x73:
+			s->deferred = 1;
+		case 0x72:
+			s->fixed_format = 0;
+			ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4);
+			s->flags = ucp ? (ucp[3] & 0xe0) : 0;
+			break;
+		}
+	}
+}
+
+
+/* Convert the result to success code */
+static int st_chk_result(struct scsi_tape *STp, struct scsi_request * SRpnt)
+{
+	int result = SRpnt->sr_result;
+	u8 scode;
+	DEB(const char *stp;)
+	char *name = tape_name(STp);
+	struct st_cmdstatus *cmdstatp;
+
+	if (!result)
+		return 0;
+
+	cmdstatp = &STp->buffer->cmdstat;
+	st_analyze_sense(STp->buffer->last_SRpnt, cmdstatp);
+
+	if (cmdstatp->have_sense)
+		scode = STp->buffer->cmdstat.sense_hdr.sense_key;
+	else
+		scode = 0;
+
+        DEB(
+        if (debugging) {
+                printk(ST_DEB_MSG "%s: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
+		       name, result,
+		       SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
+		       SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
+		       SRpnt->sr_bufflen);
+		if (cmdstatp->have_sense)
+			scsi_print_req_sense("st", SRpnt);
+	} ) /* end DEB */
+	if (!debugging) { /* Abnormal conditions for tape */
+		if (!cmdstatp->have_sense)
+			printk(KERN_WARNING
+			       "%s: Error %x (sugg. bt 0x%x, driver bt 0x%x, host bt 0x%x).\n",
+			       name, result, suggestion(result),
+			       driver_byte(result) & DRIVER_MASK, host_byte(result));
+		else if (cmdstatp->have_sense &&
+			 scode != NO_SENSE &&
+			 scode != RECOVERED_ERROR &&
+			 /* scode != UNIT_ATTENTION && */
+			 scode != BLANK_CHECK &&
+			 scode != VOLUME_OVERFLOW &&
+			 SRpnt->sr_cmnd[0] != MODE_SENSE &&
+			 SRpnt->sr_cmnd[0] != TEST_UNIT_READY) {
+				printk(KERN_WARNING "%s: Error with sense data: ", name);
+				scsi_print_req_sense("st", SRpnt);
+		}
+	}
+
+	if (cmdstatp->fixed_format &&
+	    STp->cln_mode >= EXTENDED_SENSE_START) {  /* Only fixed format sense */
+		if (STp->cln_sense_value)
+			STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+					       STp->cln_sense_mask) == STp->cln_sense_value);
+		else
+			STp->cleaning_req |= ((SRpnt->sr_sense_buffer[STp->cln_mode] &
+					       STp->cln_sense_mask) != 0);
+	}
+	if (cmdstatp->have_sense &&
+	    cmdstatp->sense_hdr.asc == 0 && cmdstatp->sense_hdr.ascq == 0x17)
+		STp->cleaning_req = 1; /* ASC and ASCQ => cleaning requested */
+
+	STp->pos_unknown |= STp->device->was_reset;
+
+	if (cmdstatp->have_sense &&
+	    scode == RECOVERED_ERROR
+#if ST_RECOVERED_WRITE_FATAL
+	    && SRpnt->sr_cmnd[0] != WRITE_6
+	    && SRpnt->sr_cmnd[0] != WRITE_FILEMARKS
+#endif
+	    ) {
+		STp->recover_count++;
+		STp->recover_reg++;
+
+                DEB(
+		if (debugging) {
+			if (SRpnt->sr_cmnd[0] == READ_6)
+				stp = "read";
+			else if (SRpnt->sr_cmnd[0] == WRITE_6)
+				stp = "write";
+			else
+				stp = "ioctl";
+			printk(ST_DEB_MSG "%s: Recovered %s error (%d).\n", name, stp,
+			       STp->recover_count);
+		} ) /* end DEB */
+
+		if (cmdstatp->flags == 0)
+			return 0;
+	}
+	return (-EIO);
+}
+
+
+/* Wakeup from interrupt */
+static void st_sleep_done(struct scsi_cmnd * SCpnt)
+{
+	struct scsi_tape *STp = container_of(SCpnt->request->rq_disk->private_data,
+					     struct scsi_tape, driver);
+
+	(STp->buffer)->cmdstat.midlevel_result = SCpnt->result;
+	SCpnt->request->rq_status = RQ_SCSI_DONE;
+	(STp->buffer)->last_SRpnt = SCpnt->sc_request;
+	DEB( STp->write_pending = 0; )
+
+	complete(SCpnt->request->waiting);
+}
+
+/* Do the scsi command. Waits until command performed if do_wait is true.
+   Otherwise write_behind_check() is used to check that the command
+   has finished. */
+static struct scsi_request *
+st_do_scsi(struct scsi_request * SRpnt, struct scsi_tape * STp, unsigned char *cmd,
+	   int bytes, int direction, int timeout, int retries, int do_wait)
+{
+	unsigned char *bp;
+
+	if (SRpnt == NULL) {
+		SRpnt = scsi_allocate_request(STp->device, GFP_ATOMIC);
+		if (SRpnt == NULL) {
+			DEBC( printk(KERN_ERR "%s: Can't get SCSI request.\n",
+				     tape_name(STp)); );
+			if (signal_pending(current))
+				(STp->buffer)->syscall_result = (-EINTR);
+			else
+				(STp->buffer)->syscall_result = (-EBUSY);
+			return NULL;
+		}
+	}
+
+	init_completion(&STp->wait);
+	SRpnt->sr_use_sg = STp->buffer->do_dio || (bytes > (STp->buffer)->frp[0].length);
+	if (SRpnt->sr_use_sg) {
+		if (!STp->buffer->do_dio)
+			buf_to_sg(STp->buffer, bytes);
+		SRpnt->sr_use_sg = (STp->buffer)->sg_segs;
+		bp = (char *) &((STp->buffer)->sg[0]);
+	} else
+		bp = (STp->buffer)->b_data;
+	SRpnt->sr_data_direction = direction;
+	SRpnt->sr_cmd_len = 0;
+	SRpnt->sr_request->waiting = &(STp->wait);
+	SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
+	SRpnt->sr_request->rq_disk = STp->disk;
+	STp->buffer->cmdstat.have_sense = 0;
+
+	scsi_do_req(SRpnt, (void *) cmd, bp, bytes,
+		    st_sleep_done, timeout, retries);
+
+	if (do_wait) {
+		wait_for_completion(SRpnt->sr_request->waiting);
+		SRpnt->sr_request->waiting = NULL;
+		(STp->buffer)->syscall_result = st_chk_result(STp, SRpnt);
+	}
+	return SRpnt;
+}
+
+
+/* Handle the write-behind checking (waits for completion). Returns -ENOSPC if
+   write has been correct but EOM early warning reached, -EIO if write ended in
+   error or zero if write successful. Asynchronous writes are used only in
+   variable block mode. */
+static int write_behind_check(struct scsi_tape * STp)
+{
+	int retval = 0;
+	struct st_buffer *STbuffer;
+	struct st_partstat *STps;
+	struct st_cmdstatus *cmdstatp;
+
+	STbuffer = STp->buffer;
+	if (!STbuffer->writing)
+		return 0;
+
+        DEB(
+	if (STp->write_pending)
+		STp->nbr_waits++;
+	else
+		STp->nbr_finished++;
+        ) /* end DEB */
+
+	wait_for_completion(&(STp->wait));
+	(STp->buffer)->last_SRpnt->sr_request->waiting = NULL;
+
+	(STp->buffer)->syscall_result = st_chk_result(STp, (STp->buffer)->last_SRpnt);
+	scsi_release_request((STp->buffer)->last_SRpnt);
+
+	STbuffer->buffer_bytes -= STbuffer->writing;
+	STps = &(STp->ps[STp->partition]);
+	if (STps->drv_block >= 0) {
+		if (STp->block_size == 0)
+			STps->drv_block++;
+		else
+			STps->drv_block += STbuffer->writing / STp->block_size;
+	}
+
+	cmdstatp = &STbuffer->cmdstat;
+	if (STbuffer->syscall_result) {
+		retval = -EIO;
+		if (cmdstatp->have_sense && !cmdstatp->deferred &&
+		    (cmdstatp->flags & SENSE_EOM) &&
+		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR)) {
+			/* EOM at write-behind, has all data been written? */
+			if (!cmdstatp->remainder_valid ||
+			    cmdstatp->uremainder64 == 0)
+				retval = -ENOSPC;
+		}
+		if (retval == -EIO)
+			STps->drv_block = -1;
+	}
+	STbuffer->writing = 0;
+
+	DEB(if (debugging && retval)
+	    printk(ST_DEB_MSG "%s: Async write error %x, return value %d.\n",
+		   tape_name(STp), STbuffer->cmdstat.midlevel_result, retval);) /* end DEB */
+
+	return retval;
+}
+
+
+/* Step over EOF if it has been inadvertently crossed (ioctl not used because
+   it messes up the block number). */
+static int cross_eof(struct scsi_tape * STp, int forward)
+{
+	struct scsi_request *SRpnt;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+
+	cmd[0] = SPACE;
+	cmd[1] = 0x01;		/* Space FileMarks */
+	if (forward) {
+		cmd[2] = cmd[3] = 0;
+		cmd[4] = 1;
+	} else
+		cmd[2] = cmd[3] = cmd[4] = 0xff;	/* -1 filemarks */
+	cmd[5] = 0;
+
+        DEBC(printk(ST_DEB_MSG "%s: Stepping over filemark %s.\n",
+		   tape_name(STp), forward ? "forward" : "backward"));
+
+	SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+			   STp->device->timeout, MAX_RETRIES, 1);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+
+	if ((STp->buffer)->cmdstat.midlevel_result != 0)
+		printk(KERN_ERR "%s: Stepping over filemark %s failed.\n",
+		   tape_name(STp), forward ? "forward" : "backward");
+
+	return (STp->buffer)->syscall_result;
+}
+
+
+/* Flush the write buffer (never need to write if variable blocksize). */
+static int flush_write_buffer(struct scsi_tape * STp)
+{
+	int offset, transfer, blks;
+	int result;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	struct st_partstat *STps;
+
+	result = write_behind_check(STp);
+	if (result)
+		return result;
+
+	result = 0;
+	if (STp->dirty == 1) {
+
+		offset = (STp->buffer)->buffer_bytes;
+		transfer = ((offset + STp->block_size - 1) /
+			    STp->block_size) * STp->block_size;
+                DEBC(printk(ST_DEB_MSG "%s: Flushing %d bytes.\n",
+                               tape_name(STp), transfer));
+
+		memset((STp->buffer)->b_data + offset, 0, transfer - offset);
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_6;
+		cmd[1] = 1;
+		blks = transfer / STp->block_size;
+		cmd[2] = blks >> 16;
+		cmd[3] = blks >> 8;
+		cmd[4] = blks;
+
+		SRpnt = st_do_scsi(NULL, STp, cmd, transfer, DMA_TO_DEVICE,
+				   STp->device->timeout, MAX_WRITE_RETRIES, 1);
+		if (!SRpnt)
+			return (STp->buffer)->syscall_result;
+
+		STps = &(STp->ps[STp->partition]);
+		if ((STp->buffer)->syscall_result != 0) {
+			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+			if (cmdstatp->have_sense && !cmdstatp->deferred &&
+			    (cmdstatp->flags & SENSE_EOM) &&
+			    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+			     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+			    (!cmdstatp->remainder_valid ||
+			     cmdstatp->uremainder64 == 0)) { /* All written at EOM early warning */
+				STp->dirty = 0;
+				(STp->buffer)->buffer_bytes = 0;
+				if (STps->drv_block >= 0)
+					STps->drv_block += blks;
+				result = (-ENOSPC);
+			} else {
+				printk(KERN_ERR "%s: Error on flush.\n",
+                                       tape_name(STp));
+				STps->drv_block = (-1);
+				result = (-EIO);
+			}
+		} else {
+			if (STps->drv_block >= 0)
+				STps->drv_block += blks;
+			STp->dirty = 0;
+			(STp->buffer)->buffer_bytes = 0;
+		}
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+	}
+	return result;
+}
+
+
+/* Flush the tape buffer. The tape will be positioned correctly unless
+   seek_next is true. */
+static int flush_buffer(struct scsi_tape *STp, int seek_next)
+{
+	int backspace, result;
+	struct st_buffer *STbuffer;
+	struct st_partstat *STps;
+
+	STbuffer = STp->buffer;
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if (STp->pos_unknown)
+		return (-EIO);
+
+	if (STp->ready != ST_READY)
+		return 0;
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING)	/* Writing */
+		return flush_write_buffer(STp);
+
+	if (STp->block_size == 0)
+		return 0;
+
+	backspace = ((STp->buffer)->buffer_bytes +
+		     (STp->buffer)->read_pointer) / STp->block_size -
+	    ((STp->buffer)->read_pointer + STp->block_size - 1) /
+	    STp->block_size;
+	(STp->buffer)->buffer_bytes = 0;
+	(STp->buffer)->read_pointer = 0;
+	result = 0;
+	if (!seek_next) {
+		if (STps->eof == ST_FM_HIT) {
+			result = cross_eof(STp, 0);	/* Back over the EOF hit */
+			if (!result)
+				STps->eof = ST_NOEOF;
+			else {
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+			}
+		}
+		if (!result && backspace > 0)
+			result = st_int_ioctl(STp, MTBSR, backspace);
+	} else if (STps->eof == ST_FM_HIT) {
+		if (STps->drv_file >= 0)
+			STps->drv_file++;
+		STps->drv_block = 0;
+		STps->eof = ST_NOEOF;
+	}
+	return result;
+
+}
+
+/* Set the mode parameters */
+static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
+{
+	int set_it = 0;
+	unsigned long arg;
+	char *name = tape_name(STp);
+
+	if (!STp->density_changed &&
+	    STm->default_density >= 0 &&
+	    STm->default_density != STp->density) {
+		arg = STm->default_density;
+		set_it = 1;
+	} else
+		arg = STp->density;
+	arg <<= MT_ST_DENSITY_SHIFT;
+	if (!STp->blksize_changed &&
+	    STm->default_blksize >= 0 &&
+	    STm->default_blksize != STp->block_size) {
+		arg |= STm->default_blksize;
+		set_it = 1;
+	} else
+		arg |= STp->block_size;
+	if (set_it &&
+	    st_int_ioctl(STp, SET_DENS_AND_BLK, arg)) {
+		printk(KERN_WARNING
+		       "%s: Can't set default block size to %d bytes and density %x.\n",
+		       name, STm->default_blksize, STm->default_density);
+		if (modes_defined)
+			return (-EINVAL);
+	}
+	return 0;
+}
+
+
+/* Lock or unlock the drive door. Don't use when scsi_request allocated. */
+static int do_door_lock(struct scsi_tape * STp, int do_lock)
+{
+	int retval, cmd;
+	DEB(char *name = tape_name(STp);)
+
+
+	cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
+	DEBC(printk(ST_DEB_MSG "%s: %socking drive door.\n", name,
+		    do_lock ? "L" : "Unl"));
+	retval = scsi_ioctl(STp->device, cmd, NULL);
+	if (!retval) {
+		STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
+	}
+	else {
+		STp->door_locked = ST_LOCK_FAILS;
+	}
+	return retval;
+}
+
+
+/* Set the internal state after reset */
+static void reset_state(struct scsi_tape *STp)
+{
+	int i;
+	struct st_partstat *STps;
+
+	STp->pos_unknown = 0;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = 0;
+		STps->drv_block = -1;
+		STps->drv_file = -1;
+	}
+	if (STp->can_partitions) {
+		STp->partition = find_partition(STp);
+		if (STp->partition < 0)
+			STp->partition = 0;
+		STp->new_partition = STp->partition;
+	}
+}
+
+/* Test if the drive is ready. Returns either one of the codes below or a negative system
+   error code. */
+#define CHKRES_READY       0
+#define CHKRES_NEW_SESSION 1
+#define CHKRES_NOT_READY   2
+#define CHKRES_NO_TAPE     3
+
+#define MAX_ATTENTIONS    10
+
+static int test_ready(struct scsi_tape *STp, int do_wait)
+{
+	int attentions, waits, max_wait, scode;
+	int retval = CHKRES_READY, new_session = 0;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt = NULL;
+	struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+	max_wait = do_wait ? ST_BLOCK_SECONDS : 0;
+
+	for (attentions=waits=0; ; ) {
+		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+		cmd[0] = TEST_UNIT_READY;
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE,
+				   STp->long_timeout, MAX_READY_RETRIES, 1);
+
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			break;
+		}
+
+		if (cmdstatp->have_sense) {
+
+			scode = cmdstatp->sense_hdr.sense_key;
+
+			if (scode == UNIT_ATTENTION) { /* New media? */
+				new_session = 1;
+				if (attentions < MAX_ATTENTIONS) {
+					attentions++;
+					continue;
+				}
+				else {
+					retval = (-EIO);
+					break;
+				}
+			}
+
+			if (scode == NOT_READY) {
+				if (waits < max_wait) {
+					if (msleep_interruptible(1000)) {
+						retval = (-EINTR);
+						break;
+					}
+					waits++;
+					continue;
+				}
+				else {
+					if ((STp->device)->scsi_level >= SCSI_2 &&
+					    cmdstatp->sense_hdr.asc == 0x3a)	/* Check ASC */
+						retval = CHKRES_NO_TAPE;
+					else
+						retval = CHKRES_NOT_READY;
+					break;
+				}
+			}
+		}
+
+		retval = (STp->buffer)->syscall_result;
+		if (!retval)
+			retval = new_session ? CHKRES_NEW_SESSION : CHKRES_READY;
+		break;
+	}
+
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	return retval;
+}
+
+
+/* See if the drive is ready and gather information about the tape. Return values:
+   < 0   negative error code from errno.h
+   0     drive ready
+   1     drive not ready (possibly no tape)
+*/
+static int check_tape(struct scsi_tape *STp, struct file *filp)
+{
+	int i, retval, new_session = 0, do_wait;
+	unsigned char cmd[MAX_COMMAND_SIZE], saved_cleaning;
+	unsigned short st_flags = filp->f_flags;
+	struct scsi_request *SRpnt = NULL;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	char *name = tape_name(STp);
+	struct inode *inode = filp->f_dentry->d_inode;
+	int mode = TAPE_MODE(inode);
+
+	STp->ready = ST_READY;
+
+	if (mode != STp->current_mode) {
+                DEBC(printk(ST_DEB_MSG "%s: Mode change from %d to %d.\n",
+			       name, STp->current_mode, mode));
+		new_session = 1;
+		STp->current_mode = mode;
+	}
+	STm = &(STp->modes[STp->current_mode]);
+
+	saved_cleaning = STp->cleaning_req;
+	STp->cleaning_req = 0;
+
+	do_wait = ((filp->f_flags & O_NONBLOCK) == 0);
+	retval = test_ready(STp, do_wait);
+
+	if (retval < 0)
+	    goto err_out;
+
+	if (retval == CHKRES_NEW_SESSION) {
+		STp->pos_unknown = 0;
+		STp->partition = STp->new_partition = 0;
+		if (STp->can_partitions)
+			STp->nbr_partitions = 1; /* This guess will be updated later
+                                                    if necessary */
+		for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+			STps = &(STp->ps[i]);
+			STps->rw = ST_IDLE;
+			STps->eof = ST_NOEOF;
+			STps->at_sm = 0;
+			STps->last_block_valid = 0;
+			STps->drv_block = 0;
+			STps->drv_file = 0;
+		}
+		new_session = 1;
+	}
+	else {
+		STp->cleaning_req |= saved_cleaning;
+
+		if (retval == CHKRES_NOT_READY || retval == CHKRES_NO_TAPE) {
+			if (retval == CHKRES_NO_TAPE)
+				STp->ready = ST_NO_TAPE;
+			else
+				STp->ready = ST_NOT_READY;
+
+			STp->density = 0;	/* Clear the erroneous "residue" */
+			STp->write_prot = 0;
+			STp->block_size = 0;
+			STp->ps[0].drv_file = STp->ps[0].drv_block = (-1);
+			STp->partition = STp->new_partition = 0;
+			STp->door_locked = ST_UNLOCKED;
+			return CHKRES_NOT_READY;
+		}
+	}
+
+	if (STp->omit_blklims)
+		STp->min_block = STp->max_block = (-1);
+	else {
+		memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+		cmd[0] = READ_BLOCK_LIMITS;
+
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, 6, DMA_FROM_DEVICE,
+				   STp->device->timeout, MAX_READY_RETRIES, 1);
+		if (!SRpnt) {
+			retval = (STp->buffer)->syscall_result;
+			goto err_out;
+		}
+
+		if (!SRpnt->sr_result && !STp->buffer->cmdstat.have_sense) {
+			STp->max_block = ((STp->buffer)->b_data[1] << 16) |
+			    ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3];
+			STp->min_block = ((STp->buffer)->b_data[4] << 8) |
+			    (STp->buffer)->b_data[5];
+			if ( DEB( debugging || ) !STp->inited)
+				printk(KERN_WARNING
+                                       "%s: Block limits %d - %d bytes.\n", name,
+                                       STp->min_block, STp->max_block);
+		} else {
+			STp->min_block = STp->max_block = (-1);
+                        DEBC(printk(ST_DEB_MSG "%s: Can't read block limits.\n",
+                                       name));
+		}
+	}
+
+	memset((void *) &cmd[0], 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	cmd[4] = 12;
+
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, 12, DMA_FROM_DEVICE,
+			STp->device->timeout, MAX_READY_RETRIES, 1);
+	if (!SRpnt) {
+		retval = (STp->buffer)->syscall_result;
+		goto err_out;
+	}
+
+	if ((STp->buffer)->syscall_result != 0) {
+                DEBC(printk(ST_DEB_MSG "%s: No Mode Sense.\n", name));
+		STp->block_size = ST_DEFAULT_BLOCK;	/* Educated guess (?) */
+		(STp->buffer)->syscall_result = 0;	/* Prevent error propagation */
+		STp->drv_write_prot = 0;
+	} else {
+                DEBC(printk(ST_DEB_MSG
+                            "%s: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n",
+                            name,
+                            (STp->buffer)->b_data[0], (STp->buffer)->b_data[1],
+                            (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]));
+
+		if ((STp->buffer)->b_data[3] >= 8) {
+			STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7;
+			STp->density = (STp->buffer)->b_data[4];
+			STp->block_size = (STp->buffer)->b_data[9] * 65536 +
+			    (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11];
+                        DEBC(printk(ST_DEB_MSG
+                                    "%s: Density %x, tape length: %x, drv buffer: %d\n",
+                                    name, STp->density, (STp->buffer)->b_data[5] * 65536 +
+                                    (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7],
+                                    STp->drv_buffer));
+		}
+		STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
+	}
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+        STp->inited = 1;
+
+	if (STp->block_size > 0)
+		(STp->buffer)->buffer_blocks =
+                        (STp->buffer)->buffer_size / STp->block_size;
+	else
+		(STp->buffer)->buffer_blocks = 1;
+	(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
+
+        DEBC(printk(ST_DEB_MSG
+                       "%s: Block size: %d, buffer size: %d (%d blocks).\n", name,
+		       STp->block_size, (STp->buffer)->buffer_size,
+		       (STp->buffer)->buffer_blocks));
+
+	if (STp->drv_write_prot) {
+		STp->write_prot = 1;
+
+                DEBC(printk(ST_DEB_MSG "%s: Write protected\n", name));
+
+		if (do_wait &&
+		    ((st_flags & O_ACCMODE) == O_WRONLY ||
+		     (st_flags & O_ACCMODE) == O_RDWR)) {
+			retval = (-EROFS);
+			goto err_out;
+		}
+	}
+
+	if (STp->can_partitions && STp->nbr_partitions < 1) {
+		/* This code is reached when the device is opened for the first time
+		   after the driver has been initialized with tape in the drive and the
+		   partition support has been enabled. */
+                DEBC(printk(ST_DEB_MSG
+                            "%s: Updating partition number in status.\n", name));
+		if ((STp->partition = find_partition(STp)) < 0) {
+			retval = STp->partition;
+			goto err_out;
+		}
+		STp->new_partition = STp->partition;
+		STp->nbr_partitions = 1; /* This guess will be updated when necessary */
+	}
+
+	if (new_session) {	/* Change the drive parameters for the new mode */
+		STp->density_changed = STp->blksize_changed = 0;
+		STp->compression_changed = 0;
+		if (!(STm->defaults_for_writes) &&
+		    (retval = set_mode_densblk(STp, STm)) < 0)
+		    goto err_out;
+
+		if (STp->default_drvbuffer != 0xff) {
+			if (st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer))
+				printk(KERN_WARNING
+                                       "%s: Can't set default drive buffering to %d.\n",
+				       name, STp->default_drvbuffer);
+		}
+	}
+
+	return CHKRES_READY;
+
+ err_out:
+	return retval;
+}
+
+
+/* Open the device. Needs to be called with BKL only because of incrementing the SCSI host
+   module count. */
+static int st_open(struct inode *inode, struct file *filp)
+{
+	int i, retval = (-EIO);
+	struct scsi_tape *STp;
+	struct st_partstat *STps;
+	int dev = TAPE_NR(inode);
+	char *name;
+
+	/*
+	 * We really want to do nonseekable_open(inode, filp); here, but some
+	 * versions of tar incorrectly call lseek on tapes and bail out if that
+	 * fails.  So we disallow pread() and pwrite(), but permit lseeks.
+	 */
+	filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+
+	write_lock(&st_dev_arr_lock);
+	if (dev >= st_dev_max || scsi_tapes == NULL ||
+	    ((STp = scsi_tapes[dev]) == NULL)) {
+		write_unlock(&st_dev_arr_lock);
+		return (-ENXIO);
+	}
+	filp->private_data = STp;
+	name = tape_name(STp);
+
+	if (STp->in_use) {
+		write_unlock(&st_dev_arr_lock);
+		DEB( printk(ST_DEB_MSG "%s: Device already in use.\n", name); )
+		return (-EBUSY);
+	}
+
+	if(scsi_device_get(STp->device)) {
+		write_unlock(&st_dev_arr_lock);
+		return (-ENXIO);
+	}
+	STp->in_use = 1;
+	write_unlock(&st_dev_arr_lock);
+	STp->rew_at_close = STp->autorew_dev = (iminor(inode) & 0x80) == 0;
+
+	if (!scsi_block_when_processing_errors(STp->device)) {
+		retval = (-ENXIO);
+		goto err_out;
+	}
+
+	/* See that we have at least a one page buffer available */
+	if (!enlarge_buffer(STp->buffer, PAGE_SIZE, STp->restr_dma)) {
+		printk(KERN_WARNING "%s: Can't allocate one page tape buffer.\n",
+		       name);
+		retval = (-EOVERFLOW);
+		goto err_out;
+	}
+
+	(STp->buffer)->writing = 0;
+	(STp->buffer)->syscall_result = 0;
+
+	STp->write_prot = ((filp->f_flags & O_ACCMODE) == O_RDONLY);
+
+	STp->dirty = 0;
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(STp->ps[i]);
+		STps->rw = ST_IDLE;
+	}
+	STp->recover_count = 0;
+	DEB( STp->nbr_waits = STp->nbr_finished = 0;
+	     STp->nbr_requests = STp->nbr_dio = STp->nbr_pages = STp->nbr_combinable = 0; )
+
+	retval = check_tape(STp, filp);
+	if (retval < 0)
+		goto err_out;
+	if ((filp->f_flags & O_NONBLOCK) == 0 &&
+	    retval != CHKRES_READY) {
+		retval = (-EIO);
+		goto err_out;
+	}
+	return 0;
+
+ err_out:
+	normalize_buffer(STp->buffer);
+	STp->in_use = 0;
+	scsi_device_put(STp->device);
+	return retval;
+
+}
+
+
+/* Flush the tape buffer before close */
+static int st_flush(struct file *filp)
+{
+	int result = 0, result2;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	struct scsi_tape *STp = filp->private_data;
+	struct st_modedef *STm = &(STp->modes[STp->current_mode]);
+	struct st_partstat *STps = &(STp->ps[STp->partition]);
+	char *name = tape_name(STp);
+
+	if (file_count(filp) > 1)
+		return 0;
+
+	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
+		result = flush_write_buffer(STp);
+		if (result != 0 && result != (-ENOSPC))
+			goto out;
+	}
+
+	if (STp->can_partitions &&
+	    (result2 = switch_partition(STp)) < 0) {
+                DEBC(printk(ST_DEB_MSG
+                               "%s: switch_partition at close failed.\n", name));
+		if (result == 0)
+			result = result2;
+		goto out;
+	}
+
+	DEBC( if (STp->nbr_requests)
+		printk(KERN_WARNING "%s: Number of r/w requests %d, dio used in %d, pages %d (%d).\n",
+		       name, STp->nbr_requests, STp->nbr_dio, STp->nbr_pages, STp->nbr_combinable));
+
+	if (STps->rw == ST_WRITING && !STp->pos_unknown) {
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+                DEBC(printk(ST_DEB_MSG "%s: Async write waits %d, finished %d.\n",
+                            name, STp->nbr_waits, STp->nbr_finished);
+		)
+
+		memset(cmd, 0, MAX_COMMAND_SIZE);
+		cmd[0] = WRITE_FILEMARKS;
+		cmd[4] = 1 + STp->two_fm;
+
+		SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+				   STp->device->timeout, MAX_WRITE_RETRIES, 1);
+		if (!SRpnt) {
+			result = (STp->buffer)->syscall_result;
+			goto out;
+		}
+
+		if (STp->buffer->syscall_result == 0 ||
+		    (cmdstatp->have_sense && !cmdstatp->deferred &&
+		     (cmdstatp->flags & SENSE_EOM) &&
+		     (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		      cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+		     (!cmdstatp->remainder_valid || cmdstatp->uremainder64 == 0))) {
+			/* Write successful at EOM */
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+			STps->drv_block = 0;
+			if (STp->two_fm)
+				cross_eof(STp, 0);
+			STps->eof = ST_FM;
+		}
+		else { /* Write error */
+			scsi_release_request(SRpnt);
+			SRpnt = NULL;
+			printk(KERN_ERR "%s: Error on write filemark.\n", name);
+			if (result == 0)
+				result = (-EIO);
+		}
+
+                DEBC(printk(ST_DEB_MSG "%s: Buffer flushed, %d EOF(s) written\n",
+                            name, cmd[4]));
+	} else if (!STp->rew_at_close) {
+		STps = &(STp->ps[STp->partition]);
+		if (!STm->sysv || STps->rw != ST_READING) {
+			if (STp->can_bsr)
+				result = flush_buffer(STp, 0);
+			else if (STps->eof == ST_FM_HIT) {
+				result = cross_eof(STp, 0);
+				if (result) {
+					if (STps->drv_file >= 0)
+						STps->drv_file++;
+					STps->drv_block = 0;
+					STps->eof = ST_FM;
+				} else
+					STps->eof = ST_NOEOF;
+			}
+		} else if ((STps->eof == ST_NOEOF &&
+			    !(result = cross_eof(STp, 1))) ||
+			   STps->eof == ST_FM_HIT) {
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+			STps->drv_block = 0;
+			STps->eof = ST_FM;
+		}
+	}
+
+      out:
+	if (STp->rew_at_close) {
+		result2 = st_int_ioctl(STp, MTREW, 1);
+		if (result == 0)
+			result = result2;
+	}
+	return result;
+}
+
+
+/* Close the device and release it. BKL is not needed: this is the only thread
+   accessing this tape. */
+static int st_release(struct inode *inode, struct file *filp)
+{
+	int result = 0;
+	struct scsi_tape *STp = filp->private_data;
+
+	if (STp->door_locked == ST_LOCKED_AUTO)
+		do_door_lock(STp, 0);
+
+	normalize_buffer(STp->buffer);
+	write_lock(&st_dev_arr_lock);
+	STp->in_use = 0;
+	write_unlock(&st_dev_arr_lock);
+	scsi_device_put(STp->device);
+
+	return result;
+}
+
+/* The checks common to both reading and writing */
+static ssize_t rw_checks(struct scsi_tape *STp, struct file *filp, size_t count)
+{
+	ssize_t retval = 0;
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	if (!scsi_block_when_processing_errors(STp->device)) {
+		retval = (-ENXIO);
+		goto out;
+	}
+
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			retval = (-ENOMEDIUM);
+		else
+			retval = (-EIO);
+		goto out;
+	}
+
+	if (! STp->modes[STp->current_mode].defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
+
+
+	/*
+	 * If there was a bus reset, block further access
+	 * to this device.
+	 */
+	if (STp->pos_unknown) {
+		retval = (-EIO);
+		goto out;
+	}
+
+	if (count == 0)
+		goto out;
+
+        DEB(
+	if (!STp->in_use) {
+		printk(ST_DEB_MSG "%s: Incorrect device.\n", tape_name(STp));
+		retval = (-EIO);
+		goto out;
+	} ) /* end DEB */
+
+	if (STp->can_partitions &&
+	    (retval = switch_partition(STp)) < 0)
+		goto out;
+
+	if (STp->block_size == 0 && STp->max_block > 0 &&
+	    (count < STp->min_block || count > STp->max_block)) {
+		retval = (-EINVAL);
+		goto out;
+	}
+
+	if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
+	    !do_door_lock(STp, 1))
+		STp->door_locked = ST_LOCKED_AUTO;
+
+ out:
+	return retval;
+}
+
+
+static int setup_buffering(struct scsi_tape *STp, const char __user *buf,
+			   size_t count, int is_read)
+{
+	int i, bufsize, retval = 0;
+	struct st_buffer *STbp = STp->buffer;
+
+	if (is_read)
+		i = STp->try_dio && try_rdio;
+	else
+		i = STp->try_dio && try_wdio;
+	if (i && ((unsigned long)buf & queue_dma_alignment(
+					STp->device->request_queue)) == 0) {
+		i = st_map_user_pages(&(STbp->sg[0]), STbp->use_sg,
+				      (unsigned long)buf, count, (is_read ? READ : WRITE),
+				      STp->max_pfn);
+		if (i > 0) {
+			STbp->do_dio = i;
+			STbp->buffer_bytes = 0;   /* can be used as transfer counter */
+		}
+		else
+			STbp->do_dio = 0;  /* fall back to buffering with any error */
+		STbp->sg_segs = STbp->do_dio;
+		STbp->frp_sg_current = 0;
+		DEB(
+		     if (STbp->do_dio) {
+			STp->nbr_dio++;
+			STp->nbr_pages += STbp->do_dio;
+			for (i=1; i < STbp->do_dio; i++)
+				if (page_to_pfn(STbp->sg[i].page) == page_to_pfn(STbp->sg[i-1].page) + 1)
+					STp->nbr_combinable++;
+		     }
+		)
+	} else
+		STbp->do_dio = 0;
+	DEB( STp->nbr_requests++; )
+
+	if (!STbp->do_dio) {
+		if (STp->block_size)
+			bufsize = STp->block_size > st_fixed_buffer_size ?
+				STp->block_size : st_fixed_buffer_size;
+		else
+			bufsize = count;
+		if (bufsize > STbp->buffer_size &&
+		    !enlarge_buffer(STbp, bufsize, STp->restr_dma)) {
+			printk(KERN_WARNING "%s: Can't allocate %d byte tape buffer.\n",
+			       tape_name(STp), bufsize);
+			retval = (-EOVERFLOW);
+			goto out;
+		}
+		if (STp->block_size)
+			STbp->buffer_blocks = bufsize / STp->block_size;
+	}
+
+ out:
+	return retval;
+}
+
+
+/* Can be called more than once after each setup_buffer() */
+static void release_buffering(struct scsi_tape *STp)
+{
+	struct st_buffer *STbp;
+
+	STbp = STp->buffer;
+	if (STbp->do_dio) {
+		sgl_unmap_user_pages(&(STbp->sg[0]), STbp->do_dio, 0);
+		STbp->do_dio = 0;
+	}
+}
+
+
+/* Write command */
+static ssize_t
+st_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
+{
+	ssize_t total;
+	ssize_t i, do_count, blks, transfer;
+	ssize_t retval;
+	int undone, retry_eot = 0, scode;
+	int async_write;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	const char __user *b_point;
+	struct scsi_request *SRpnt = NULL;
+	struct scsi_tape *STp = filp->private_data;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	struct st_buffer *STbp;
+	char *name = tape_name(STp);
+
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
+	retval = rw_checks(STp, filp, count);
+	if (retval || count == 0)
+		goto out;
+
+	/* Write must be integral number of blocks */
+	if (STp->block_size != 0 && (count % STp->block_size) != 0) {
+		printk(KERN_WARNING "%s: Write not multiple of tape block size.\n",
+		       name);
+		retval = (-EINVAL);
+		goto out;
+	}
+
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
+
+	if (STp->write_prot) {
+		retval = (-EACCES);
+		goto out;
+	}
+
+
+	if (STps->rw == ST_READING) {
+		retval = flush_buffer(STp, 0);
+		if (retval)
+			goto out;
+		STps->rw = ST_WRITING;
+	} else if (STps->rw != ST_WRITING &&
+		   STps->drv_file == 0 && STps->drv_block == 0) {
+		if ((retval = set_mode_densblk(STp, STm)) < 0)
+			goto out;
+		if (STm->default_compression != ST_DONT_TOUCH &&
+		    !(STp->compression_changed)) {
+			if (st_compression(STp, (STm->default_compression == ST_YES))) {
+				printk(KERN_WARNING "%s: Can't set default compression.\n",
+				       name);
+				if (modes_defined) {
+					retval = (-EINVAL);
+					goto out;
+				}
+			}
+		}
+	}
+
+	STbp = STp->buffer;
+	i = write_behind_check(STp);
+	if (i) {
+		if (i == -ENOSPC)
+			STps->eof = ST_EOM_OK;
+		else
+			STps->eof = ST_EOM_ERROR;
+	}
+
+	if (STps->eof == ST_EOM_OK) {
+		STps->eof = ST_EOD_1;  /* allow next write */
+		retval = (-ENOSPC);
+		goto out;
+	}
+	else if (STps->eof == ST_EOM_ERROR) {
+		retval = (-EIO);
+		goto out;
+	}
+
+	/* Check the buffer readability in cases where copy_user might catch
+	   the problems after some tape movement. */
+	if (STp->block_size != 0 &&
+	    !STbp->do_dio &&
+	    (copy_from_user(&i, buf, 1) != 0 ||
+	     copy_from_user(&i, buf + count - 1, 1) != 0)) {
+		retval = (-EFAULT);
+		goto out;
+	}
+
+	retval = setup_buffering(STp, buf, count, 0);
+	if (retval)
+		goto out;
+
+	total = count;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = WRITE_6;
+	cmd[1] = (STp->block_size != 0);
+
+	STps->rw = ST_WRITING;
+
+	b_point = buf;
+	while (count > 0 && !retry_eot) {
+
+		if (STbp->do_dio) {
+			do_count = count;
+		}
+		else {
+			if (STp->block_size == 0)
+				do_count = count;
+			else {
+				do_count = STbp->buffer_blocks * STp->block_size -
+					STbp->buffer_bytes;
+				if (do_count > count)
+					do_count = count;
+			}
+
+			i = append_to_buffer(b_point, STbp, do_count);
+			if (i) {
+				retval = i;
+				goto out;
+			}
+		}
+		count -= do_count;
+		b_point += do_count;
+
+		async_write = STp->block_size == 0 && !STbp->do_dio &&
+			STm->do_async_writes && STps->eof < ST_EOM_OK;
+
+		if (STp->block_size != 0 && STm->do_buffer_writes &&
+		    !(STp->try_dio && try_wdio) && STps->eof < ST_EOM_OK &&
+		    STbp->buffer_bytes < STbp->buffer_size) {
+			STp->dirty = 1;
+			/* Don't write a buffer that is not full enough. */
+			if (!async_write && count == 0)
+				break;
+		}
+
+	retry_write:
+		if (STp->block_size == 0)
+			blks = transfer = do_count;
+		else {
+			if (!STbp->do_dio)
+				blks = STbp->buffer_bytes;
+			else
+				blks = do_count;
+			blks /= STp->block_size;
+			transfer = blks * STp->block_size;
+		}
+		cmd[2] = blks >> 16;
+		cmd[3] = blks >> 8;
+		cmd[4] = blks;
+
+		SRpnt = st_do_scsi(SRpnt, STp, cmd, transfer, DMA_TO_DEVICE,
+				   STp->device->timeout, MAX_WRITE_RETRIES, !async_write);
+		if (!SRpnt) {
+			retval = STbp->syscall_result;
+			goto out;
+		}
+		if (async_write) {
+			STbp->writing = transfer;
+			STp->dirty = !(STbp->writing ==
+				       STbp->buffer_bytes);
+			SRpnt = NULL;  /* Prevent releasing this request! */
+			DEB( STp->write_pending = 1; )
+			break;
+		}
+
+		if (STbp->syscall_result != 0) {
+			struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+                        DEBC(printk(ST_DEB_MSG "%s: Error on write:\n", name));
+			if (cmdstatp->have_sense && (cmdstatp->flags & SENSE_EOM)) {
+				scode = cmdstatp->sense_hdr.sense_key;
+				if (cmdstatp->remainder_valid)
+					undone = (int)cmdstatp->uremainder64;
+				else if (STp->block_size == 0 &&
+					 scode == VOLUME_OVERFLOW)
+					undone = transfer;
+				else
+					undone = 0;
+				if (STp->block_size != 0)
+					undone *= STp->block_size;
+				if (undone <= do_count) {
+					/* Only data from this write is not written */
+					count += undone;
+					do_count -= undone;
+					if (STp->block_size)
+						blks = (transfer - undone) / STp->block_size;
+					STps->eof = ST_EOM_OK;
+					/* Continue in fixed block mode if all written
+					   in this request but still something left to write
+					   (retval left to zero)
+					*/
+					if (STp->block_size == 0 ||
+					    undone > 0 || count == 0)
+						retval = (-ENOSPC); /* EOM within current request */
+                                        DEBC(printk(ST_DEB_MSG
+                                                       "%s: EOM with %d bytes unwritten.\n",
+						       name, (int)count));
+				} else {
+					/* EOT within data buffered earlier (possible only
+					   in fixed block mode without direct i/o) */
+					if (!retry_eot && !cmdstatp->deferred &&
+					    (scode == NO_SENSE || scode == RECOVERED_ERROR)) {
+						move_buffer_data(STp->buffer, transfer - undone);
+						retry_eot = 1;
+						if (STps->drv_block >= 0) {
+							STps->drv_block += (transfer - undone) /
+								STp->block_size;
+						}
+						STps->eof = ST_EOM_OK;
+						DEBC(printk(ST_DEB_MSG
+							    "%s: Retry write of %d bytes at EOM.\n",
+							    name, STp->buffer->buffer_bytes));
+						goto retry_write;
+					}
+					else {
+						/* Either error within data buffered by driver or
+						   failed retry */
+						count -= do_count;
+						blks = do_count = 0;
+						STps->eof = ST_EOM_ERROR;
+						STps->drv_block = (-1); /* Too cautious? */
+						retval = (-EIO);	/* EOM for old data */
+						DEBC(printk(ST_DEB_MSG
+							    "%s: EOM with lost data.\n",
+							    name));
+					}
+				}
+			} else {
+				count += do_count;
+				STps->drv_block = (-1);		/* Too cautious? */
+				retval = (-EIO);
+			}
+
+		}
+
+		if (STps->drv_block >= 0) {
+			if (STp->block_size == 0)
+				STps->drv_block += (do_count > 0);
+			else
+				STps->drv_block += blks;
+		}
+
+		STbp->buffer_bytes = 0;
+		STp->dirty = 0;
+
+		if (retval || retry_eot) {
+			if (count < total)
+				retval = total - count;
+			goto out;
+		}
+	}
+
+	if (STps->eof == ST_EOD_1)
+		STps->eof = ST_EOM_OK;
+	else if (STps->eof != ST_EOM_OK)
+		STps->eof = ST_NOEOF;
+	retval = total - count;
+
+ out:
+	if (SRpnt != NULL)
+		scsi_release_request(SRpnt);
+	release_buffering(STp);
+	up(&STp->lock);
+
+	return retval;
+}
+
+/* Read data from the tape. Returns zero in the normal case, one if the
+   eof status has changed, and the negative error code in case of a
+   fatal error. Otherwise updates the buffer and the eof state.
+
+   Does release user buffer mapping if it is set.
+*/
+static long read_tape(struct scsi_tape *STp, long count,
+		      struct scsi_request ** aSRpnt)
+{
+	int transfer, blks, bytes;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	struct st_buffer *STbp;
+	int retval = 0;
+	char *name = tape_name(STp);
+
+	if (count == 0)
+		return 0;
+
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
+	if (STps->eof == ST_FM_HIT)
+		return 1;
+	STbp = STp->buffer;
+
+	if (STp->block_size == 0)
+		blks = bytes = count;
+	else {
+		if (!(STp->try_dio && try_rdio) && STm->do_read_ahead) {
+			blks = (STp->buffer)->buffer_blocks;
+			bytes = blks * STp->block_size;
+		} else {
+			bytes = count;
+			if (!STbp->do_dio && bytes > (STp->buffer)->buffer_size)
+				bytes = (STp->buffer)->buffer_size;
+			blks = bytes / STp->block_size;
+			bytes = blks * STp->block_size;
+		}
+	}
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = READ_6;
+	cmd[1] = (STp->block_size != 0);
+	cmd[2] = blks >> 16;
+	cmd[3] = blks >> 8;
+	cmd[4] = blks;
+
+	SRpnt = *aSRpnt;
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, bytes, DMA_FROM_DEVICE,
+			   STp->device->timeout, MAX_RETRIES, 1);
+	release_buffering(STp);
+	*aSRpnt = SRpnt;
+	if (!SRpnt)
+		return STbp->syscall_result;
+
+	STbp->read_pointer = 0;
+	STps->at_sm = 0;
+
+	/* Something to check */
+	if (STbp->syscall_result) {
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+		retval = 1;
+		DEBC(printk(ST_DEB_MSG "%s: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n",
+                            name,
+                            SRpnt->sr_sense_buffer[0], SRpnt->sr_sense_buffer[1],
+                            SRpnt->sr_sense_buffer[2], SRpnt->sr_sense_buffer[3],
+                            SRpnt->sr_sense_buffer[4], SRpnt->sr_sense_buffer[5],
+                            SRpnt->sr_sense_buffer[6], SRpnt->sr_sense_buffer[7]));
+		if (cmdstatp->have_sense) {
+
+			if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
+				cmdstatp->flags &= 0xcf;	/* No need for EOM in this case */
+
+			if (cmdstatp->flags != 0) { /* EOF, EOM, or ILI */
+				/* Compute the residual count */
+				if (cmdstatp->remainder_valid)
+					transfer = (int)cmdstatp->uremainder64;
+				else
+					transfer = 0;
+				if (STp->block_size == 0 &&
+				    cmdstatp->sense_hdr.sense_key == MEDIUM_ERROR)
+					transfer = bytes;
+
+				if (cmdstatp->flags & SENSE_ILI) {	/* ILI */
+					if (STp->block_size == 0) {
+						if (transfer <= 0) {
+							if (transfer < 0)
+								printk(KERN_NOTICE
+								       "%s: Failed to read %d byte block with %d byte transfer.\n",
+								       name, bytes - transfer, bytes);
+							if (STps->drv_block >= 0)
+								STps->drv_block += 1;
+							STbp->buffer_bytes = 0;
+							return (-ENOMEM);
+						}
+						STbp->buffer_bytes = bytes - transfer;
+					} else {
+						scsi_release_request(SRpnt);
+						SRpnt = *aSRpnt = NULL;
+						if (transfer == blks) {	/* We did not get anything, error */
+							printk(KERN_NOTICE "%s: Incorrect block size.\n", name);
+							if (STps->drv_block >= 0)
+								STps->drv_block += blks - transfer + 1;
+							st_int_ioctl(STp, MTBSR, 1);
+							return (-EIO);
+						}
+						/* We have some data, deliver it */
+						STbp->buffer_bytes = (blks - transfer) *
+						    STp->block_size;
+                                                DEBC(printk(ST_DEB_MSG
+                                                            "%s: ILI but enough data received %ld %d.\n",
+                                                            name, count, STbp->buffer_bytes));
+						if (STps->drv_block >= 0)
+							STps->drv_block += 1;
+						if (st_int_ioctl(STp, MTBSR, 1))
+							return (-EIO);
+					}
+				} else if (cmdstatp->flags & SENSE_FMK) {	/* FM overrides EOM */
+					if (STps->eof != ST_FM_HIT)
+						STps->eof = ST_FM_HIT;
+					else
+						STps->eof = ST_EOD_2;
+					if (STp->block_size == 0)
+						STbp->buffer_bytes = 0;
+					else
+						STbp->buffer_bytes =
+						    bytes - transfer * STp->block_size;
+                                        DEBC(printk(ST_DEB_MSG
+                                                    "%s: EOF detected (%d bytes read).\n",
+                                                    name, STbp->buffer_bytes));
+				} else if (cmdstatp->flags & SENSE_EOM) {
+					if (STps->eof == ST_FM)
+						STps->eof = ST_EOD_1;
+					else
+						STps->eof = ST_EOM_OK;
+					if (STp->block_size == 0)
+						STbp->buffer_bytes = bytes - transfer;
+					else
+						STbp->buffer_bytes =
+						    bytes - transfer * STp->block_size;
+
+                                        DEBC(printk(ST_DEB_MSG "%s: EOM detected (%d bytes read).\n",
+                                                    name, STbp->buffer_bytes));
+				}
+			}
+			/* end of EOF, EOM, ILI test */ 
+			else {	/* nonzero sense key */
+                                DEBC(printk(ST_DEB_MSG
+                                            "%s: Tape error while reading.\n", name));
+				STps->drv_block = (-1);
+				if (STps->eof == ST_FM &&
+				    cmdstatp->sense_hdr.sense_key == BLANK_CHECK) {
+                                        DEBC(printk(ST_DEB_MSG
+                                                    "%s: Zero returned for first BLANK CHECK after EOF.\n",
+                                                    name));
+					STps->eof = ST_EOD_2;	/* First BLANK_CHECK after FM */
+				} else	/* Some other extended sense code */
+					retval = (-EIO);
+			}
+
+			if (STbp->buffer_bytes < 0)  /* Caused by bogus sense data */
+				STbp->buffer_bytes = 0;
+		}
+		/* End of extended sense test */ 
+		else {		/* Non-extended sense */
+			retval = STbp->syscall_result;
+		}
+
+	}
+	/* End of error handling */ 
+	else			/* Read successful */
+		STbp->buffer_bytes = bytes;
+
+	if (STps->drv_block >= 0) {
+		if (STp->block_size == 0)
+			STps->drv_block++;
+		else
+			STps->drv_block += STbp->buffer_bytes / STp->block_size;
+	}
+	return retval;
+}
+
+
+/* Read command */
+static ssize_t
+st_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos)
+{
+	ssize_t total;
+	ssize_t retval = 0;
+	ssize_t i, transfer;
+	int special, do_dio = 0;
+	struct scsi_request *SRpnt = NULL;
+	struct scsi_tape *STp = filp->private_data;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	struct st_buffer *STbp = STp->buffer;
+	DEB( char *name = tape_name(STp); )
+
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
+	retval = rw_checks(STp, filp, count);
+	if (retval || count == 0)
+		goto out;
+
+	STm = &(STp->modes[STp->current_mode]);
+	if (!(STm->do_read_ahead) && STp->block_size != 0 &&
+	    (count % STp->block_size) != 0) {
+		retval = (-EINVAL);	/* Read must be integral number of blocks */
+		goto out;
+	}
+
+	STps = &(STp->ps[STp->partition]);
+	if (STps->rw == ST_WRITING) {
+		retval = flush_buffer(STp, 0);
+		if (retval)
+			goto out;
+		STps->rw = ST_READING;
+	}
+        DEB(
+	if (debugging && STps->eof != ST_NOEOF)
+		printk(ST_DEB_MSG "%s: EOF/EOM flag up (%d). Bytes %d\n", name,
+		       STps->eof, STbp->buffer_bytes);
+        ) /* end DEB */
+
+	retval = setup_buffering(STp, buf, count, 1);
+	if (retval)
+		goto out;
+	do_dio = STbp->do_dio;
+
+	if (STbp->buffer_bytes == 0 &&
+	    STps->eof >= ST_EOD_1) {
+		if (STps->eof < ST_EOD) {
+			STps->eof += 1;
+			retval = 0;
+			goto out;
+		}
+		retval = (-EIO);	/* EOM or Blank Check */
+		goto out;
+	}
+
+	if (do_dio) {
+		/* Check the buffer writability before any tape movement. Don't alter
+		   buffer data. */
+		if (copy_from_user(&i, buf, 1) != 0 ||
+		    copy_to_user(buf, &i, 1) != 0 ||
+		    copy_from_user(&i, buf + count - 1, 1) != 0 ||
+		    copy_to_user(buf + count - 1, &i, 1) != 0) {
+			retval = (-EFAULT);
+			goto out;
+		}
+	}
+
+	STps->rw = ST_READING;
+
+
+	/* Loop until enough data in buffer or a special condition found */
+	for (total = 0, special = 0; total < count && !special;) {
+
+		/* Get new data if the buffer is empty */
+		if (STbp->buffer_bytes == 0) {
+			special = read_tape(STp, count - total, &SRpnt);
+			if (special < 0) {	/* No need to continue read */
+				retval = special;
+				goto out;
+			}
+		}
+
+		/* Move the data from driver buffer to user buffer */
+		if (STbp->buffer_bytes > 0) {
+                        DEB(
+			if (debugging && STps->eof != ST_NOEOF)
+				printk(ST_DEB_MSG
+                                       "%s: EOF up (%d). Left %d, needed %d.\n", name,
+				       STps->eof, STbp->buffer_bytes,
+                                       (int)(count - total));
+                        ) /* end DEB */
+			transfer = STbp->buffer_bytes < count - total ?
+			    STbp->buffer_bytes : count - total;
+			if (!do_dio) {
+				i = from_buffer(STbp, buf, transfer);
+				if (i) {
+					retval = i;
+					goto out;
+				}
+			}
+			buf += transfer;
+			total += transfer;
+		}
+
+		if (STp->block_size == 0)
+			break;	/* Read only one variable length block */
+
+	}			/* for (total = 0, special = 0;
+                                   total < count && !special; ) */
+
+	/* Change the eof state if no data from tape or buffer */
+	if (total == 0) {
+		if (STps->eof == ST_FM_HIT) {
+			STps->eof = ST_FM;
+			STps->drv_block = 0;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+		} else if (STps->eof == ST_EOD_1) {
+			STps->eof = ST_EOD_2;
+			STps->drv_block = 0;
+			if (STps->drv_file >= 0)
+				STps->drv_file++;
+		} else if (STps->eof == ST_EOD_2)
+			STps->eof = ST_EOD;
+	} else if (STps->eof == ST_FM)
+		STps->eof = ST_NOEOF;
+	retval = total;
+
+ out:
+	if (SRpnt != NULL) {
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+	}
+	if (do_dio) {
+		release_buffering(STp);
+		STbp->buffer_bytes = 0;
+	}
+	up(&STp->lock);
+
+	return retval;
+}
+
+
+
+DEB(
+/* Set the driver options */
+static void st_log_options(struct scsi_tape * STp, struct st_modedef * STm, char *name)
+{
+	if (debugging) {
+		printk(KERN_INFO
+		       "%s: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n",
+		       name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes,
+		       STm->do_read_ahead);
+		printk(KERN_INFO
+		       "%s:    can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n",
+		       name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock);
+		printk(KERN_INFO
+		       "%s:    defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n",
+		       name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions,
+		       STp->scsi2_logical);
+		printk(KERN_INFO
+		       "%s:    sysv: %d nowait: %d\n", name, STm->sysv, STp->immediate);
+		printk(KERN_INFO "%s:    debugging: %d\n",
+		       name, debugging);
+	}
+}
+	)
+
+
+static int st_set_options(struct scsi_tape *STp, long options)
+{
+	int value;
+	long code;
+	struct st_modedef *STm;
+	char *name = tape_name(STp);
+	struct cdev *cd0, *cd1;
+
+	STm = &(STp->modes[STp->current_mode]);
+	if (!STm->defined) {
+		cd0 = STm->cdevs[0]; cd1 = STm->cdevs[1];
+		memcpy(STm, &(STp->modes[0]), sizeof(struct st_modedef));
+		STm->cdevs[0] = cd0; STm->cdevs[1] = cd1;
+		modes_defined = 1;
+                DEBC(printk(ST_DEB_MSG
+                            "%s: Initialized mode %d definition from mode 0\n",
+                            name, STp->current_mode));
+	}
+
+	code = options & MT_ST_OPTIONS;
+	if (code == MT_ST_BOOLEANS) {
+		STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0;
+		STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
+		STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0;
+		STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
+		STp->two_fm = (options & MT_ST_TWO_FM) != 0;
+		STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
+		STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0;
+		STp->can_bsr = (options & MT_ST_CAN_BSR) != 0;
+		STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0;
+		if ((STp->device)->scsi_level >= SCSI_2)
+			STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0;
+		STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0;
+		STp->immediate = (options & MT_ST_NOWAIT) != 0;
+		STm->sysv = (options & MT_ST_SYSV) != 0;
+		DEB( debugging = (options & MT_ST_DEBUGGING) != 0;
+		     st_log_options(STp, STm, name); )
+	} else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) {
+		value = (code == MT_ST_SETBOOLEANS);
+		if ((options & MT_ST_BUFFER_WRITES) != 0)
+			STm->do_buffer_writes = value;
+		if ((options & MT_ST_ASYNC_WRITES) != 0)
+			STm->do_async_writes = value;
+		if ((options & MT_ST_DEF_WRITES) != 0)
+			STm->defaults_for_writes = value;
+		if ((options & MT_ST_READ_AHEAD) != 0)
+			STm->do_read_ahead = value;
+		if ((options & MT_ST_TWO_FM) != 0)
+			STp->two_fm = value;
+		if ((options & MT_ST_FAST_MTEOM) != 0)
+			STp->fast_mteom = value;
+		if ((options & MT_ST_AUTO_LOCK) != 0)
+			STp->do_auto_lock = value;
+		if ((options & MT_ST_CAN_BSR) != 0)
+			STp->can_bsr = value;
+		if ((options & MT_ST_NO_BLKLIMS) != 0)
+			STp->omit_blklims = value;
+		if ((STp->device)->scsi_level >= SCSI_2 &&
+		    (options & MT_ST_CAN_PARTITIONS) != 0)
+			STp->can_partitions = value;
+		if ((options & MT_ST_SCSI2LOGICAL) != 0)
+			STp->scsi2_logical = value;
+		if ((options & MT_ST_NOWAIT) != 0)
+			STp->immediate = value;
+		if ((options & MT_ST_SYSV) != 0)
+			STm->sysv = value;
+                DEB(
+		if ((options & MT_ST_DEBUGGING) != 0)
+			debugging = value;
+			st_log_options(STp, STm, name); )
+	} else if (code == MT_ST_WRITE_THRESHOLD) {
+		/* Retained for compatibility */
+	} else if (code == MT_ST_DEF_BLKSIZE) {
+		value = (options & ~MT_ST_OPTIONS);
+		if (value == ~MT_ST_OPTIONS) {
+			STm->default_blksize = (-1);
+			DEBC( printk(KERN_INFO "%s: Default block size disabled.\n", name));
+		} else {
+			STm->default_blksize = value;
+			DEBC( printk(KERN_INFO "%s: Default block size set to %d bytes.\n",
+			       name, STm->default_blksize));
+			if (STp->ready == ST_READY) {
+				STp->blksize_changed = 0;
+				set_mode_densblk(STp, STm);
+			}
+		}
+	} else if (code == MT_ST_TIMEOUTS) {
+		value = (options & ~MT_ST_OPTIONS);
+		if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) {
+			STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ;
+			DEBC( printk(KERN_INFO "%s: Long timeout set to %d seconds.\n", name,
+			       (value & ~MT_ST_SET_LONG_TIMEOUT)));
+		} else {
+			STp->device->timeout = value * HZ;
+			DEBC( printk(KERN_INFO "%s: Normal timeout set to %d seconds.\n",
+				name, value) );
+		}
+	} else if (code == MT_ST_SET_CLN) {
+		value = (options & ~MT_ST_OPTIONS) & 0xff;
+		if (value != 0 &&
+		    value < EXTENDED_SENSE_START && value >= SCSI_SENSE_BUFFERSIZE)
+			return (-EINVAL);
+		STp->cln_mode = value;
+		STp->cln_sense_mask = (options >> 8) & 0xff;
+		STp->cln_sense_value = (options >> 16) & 0xff;
+		printk(KERN_INFO
+		       "%s: Cleaning request mode %d, mask %02x, value %02x\n",
+		       name, value, STp->cln_sense_mask, STp->cln_sense_value);
+	} else if (code == MT_ST_DEF_OPTIONS) {
+		code = (options & ~MT_ST_CLEAR_DEFAULT);
+		value = (options & MT_ST_CLEAR_DEFAULT);
+		if (code == MT_ST_DEF_DENSITY) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_density = (-1);
+				DEBC( printk(KERN_INFO "%s: Density default disabled.\n",
+                                       name));
+			} else {
+				STm->default_density = value & 0xff;
+				DEBC( printk(KERN_INFO "%s: Density default set to %x\n",
+				       name, STm->default_density));
+				if (STp->ready == ST_READY) {
+					STp->density_changed = 0;
+					set_mode_densblk(STp, STm);
+				}
+			}
+		} else if (code == MT_ST_DEF_DRVBUFFER) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STp->default_drvbuffer = 0xff;
+				DEBC( printk(KERN_INFO
+                                       "%s: Drive buffer default disabled.\n", name));
+			} else {
+				STp->default_drvbuffer = value & 7;
+				DEBC( printk(KERN_INFO
+                                       "%s: Drive buffer default set to %x\n",
+				       name, STp->default_drvbuffer));
+				if (STp->ready == ST_READY)
+					st_int_ioctl(STp, MTSETDRVBUFFER, STp->default_drvbuffer);
+			}
+		} else if (code == MT_ST_DEF_COMPRESSION) {
+			if (value == MT_ST_CLEAR_DEFAULT) {
+				STm->default_compression = ST_DONT_TOUCH;
+				DEBC( printk(KERN_INFO
+                                       "%s: Compression default disabled.\n", name));
+			} else {
+				if ((value & 0xff00) != 0) {
+					STp->c_algo = (value & 0xff00) >> 8;
+					DEBC( printk(KERN_INFO "%s: Compression algorithm set to 0x%x.\n",
+					       name, STp->c_algo));
+				}
+				if ((value & 0xff) != 0xff) {
+					STm->default_compression = (value & 1 ? ST_YES : ST_NO);
+					DEBC( printk(KERN_INFO "%s: Compression default set to %x\n",
+					       name, (value & 1)));
+					if (STp->ready == ST_READY) {
+						STp->compression_changed = 0;
+						st_compression(STp, (STm->default_compression == ST_YES));
+					}
+				}
+			}
+		}
+	} else
+		return (-EIO);
+
+	return 0;
+}
+
+#define MODE_HEADER_LENGTH  4
+
+/* Mode header and page byte offsets */
+#define MH_OFF_DATA_LENGTH     0
+#define MH_OFF_MEDIUM_TYPE     1
+#define MH_OFF_DEV_SPECIFIC    2
+#define MH_OFF_BDESCS_LENGTH   3
+#define MP_OFF_PAGE_NBR        0
+#define MP_OFF_PAGE_LENGTH     1
+
+/* Mode header and page bit masks */
+#define MH_BIT_WP              0x80
+#define MP_MSK_PAGE_NBR        0x3f
+
+/* Don't return block descriptors */
+#define MODE_SENSE_OMIT_BDESCS 0x08
+
+#define MODE_SELECT_PAGE_FORMAT 0x10
+
+/* Read a mode page into the tape buffer. The block descriptors are included
+   if incl_block_descs is true. The page control is ored to the page number
+   parameter, if necessary. */
+static int read_mode_page(struct scsi_tape *STp, int page, int omit_block_descs)
+{
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt = NULL;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SENSE;
+	if (omit_block_descs)
+		cmd[1] = MODE_SENSE_OMIT_BDESCS;
+	cmd[2] = page;
+	cmd[4] = 255;
+
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE,
+			   STp->device->timeout, 0, 1);
+	if (SRpnt == NULL)
+		return (STp->buffer)->syscall_result;
+
+	scsi_release_request(SRpnt);
+
+	return (STp->buffer)->syscall_result;
+}
+
+
+/* Send the mode page in the tape buffer to the drive. Assumes that the mode data
+   in the buffer is correctly formatted. The long timeout is used if slow is non-zero. */
+static int write_mode_page(struct scsi_tape *STp, int page, int slow)
+{
+	int pgo;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt = NULL;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = MODE_SELECT;
+	cmd[1] = MODE_SELECT_PAGE_FORMAT;
+	pgo = MODE_HEADER_LENGTH + (STp->buffer)->b_data[MH_OFF_BDESCS_LENGTH];
+	cmd[4] = pgo + (STp->buffer)->b_data[pgo + MP_OFF_PAGE_LENGTH] + 2;
+
+	/* Clear reserved fields */
+	(STp->buffer)->b_data[MH_OFF_DATA_LENGTH] = 0;
+	(STp->buffer)->b_data[MH_OFF_MEDIUM_TYPE] = 0;
+	(STp->buffer)->b_data[MH_OFF_DEV_SPECIFIC] &= ~MH_BIT_WP;
+	(STp->buffer)->b_data[pgo + MP_OFF_PAGE_NBR] &= MP_MSK_PAGE_NBR;
+
+	SRpnt = st_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE,
+			   (slow ? STp->long_timeout : STp->device->timeout), 0, 1);
+	if (SRpnt == NULL)
+		return (STp->buffer)->syscall_result;
+
+	scsi_release_request(SRpnt);
+
+	return (STp->buffer)->syscall_result;
+}
+
+
+#define COMPRESSION_PAGE        0x0f
+#define COMPRESSION_PAGE_LENGTH 16
+
+#define CP_OFF_DCE_DCC          2
+#define CP_OFF_C_ALGO           7
+
+#define DCE_MASK  0x80
+#define DCC_MASK  0x40
+#define RED_MASK  0x60
+
+
+/* Control the compression with mode page 15. Algorithm not changed if zero.
+
+   The block descriptors are read and written because Sony SDT-7000 does not
+   work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+   Including block descriptors should not cause any harm to other drives. */
+
+static int st_compression(struct scsi_tape * STp, int state)
+{
+	int retval;
+	int mpoffs;  /* Offset to mode page start */
+	unsigned char *b_data = (STp->buffer)->b_data;
+	DEB( char *name = tape_name(STp); )
+
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	/* Read the current page contents */
+	retval = read_mode_page(STp, COMPRESSION_PAGE, 0);
+	if (retval) {
+                DEBC(printk(ST_DEB_MSG "%s: Compression mode page not supported.\n",
+                            name));
+		return (-EIO);
+	}
+
+	mpoffs = MODE_HEADER_LENGTH + b_data[MH_OFF_BDESCS_LENGTH];
+        DEBC(printk(ST_DEB_MSG "%s: Compression state is %d.\n", name,
+                    (b_data[mpoffs + CP_OFF_DCE_DCC] & DCE_MASK ? 1 : 0)));
+
+	/* Check if compression can be changed */
+	if ((b_data[mpoffs + CP_OFF_DCE_DCC] & DCC_MASK) == 0) {
+                DEBC(printk(ST_DEB_MSG "%s: Compression not supported.\n", name));
+		return (-EIO);
+	}
+
+	/* Do the change */
+	if (state) {
+		b_data[mpoffs + CP_OFF_DCE_DCC] |= DCE_MASK;
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = STp->c_algo;
+	}
+	else {
+		b_data[mpoffs + CP_OFF_DCE_DCC] &= ~DCE_MASK;
+		if (STp->c_algo != 0)
+			b_data[mpoffs + CP_OFF_C_ALGO] = 0; /* no compression */
+	}
+
+	retval = write_mode_page(STp, COMPRESSION_PAGE, 0);
+	if (retval) {
+                DEBC(printk(ST_DEB_MSG "%s: Compression change failed.\n", name));
+		return (-EIO);
+	}
+        DEBC(printk(ST_DEB_MSG "%s: Compression state changed to %d.\n",
+		       name, state));
+
+	STp->compression_changed = 1;
+	return 0;
+}
+
+
+/* Process the load and unload commands (does unload if the load code is zero) */
+static int do_load_unload(struct scsi_tape *STp, struct file *filp, int load_code)
+{
+	int retval = (-EIO), timeout;
+	DEB( char *name = tape_name(STp); )
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct st_partstat *STps;
+	struct scsi_request *SRpnt;
+
+	if (STp->ready != ST_READY && !load_code) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	cmd[0] = START_STOP;
+	if (load_code)
+		cmd[4] |= 1;
+	/*
+	 * If arg >= 1 && arg <= 6 Enhanced load/unload in HP C1553A
+	 */
+	if (load_code >= 1 + MT_ST_HPLOADER_OFFSET
+	    && load_code <= 6 + MT_ST_HPLOADER_OFFSET) {
+		DEBC(printk(ST_DEB_MSG "%s: Enhanced %sload slot %2d.\n",
+			    name, (cmd[4]) ? "" : "un",
+			    load_code - MT_ST_HPLOADER_OFFSET));
+		cmd[3] = load_code - MT_ST_HPLOADER_OFFSET; /* MediaID field of C1553A */
+	}
+	if (STp->immediate) {
+		cmd[1] = 1;	/* Don't wait for completion */
+		timeout = STp->device->timeout;
+	}
+	else
+		timeout = STp->long_timeout;
+
+	DEBC(
+		if (!load_code)
+		printk(ST_DEB_MSG "%s: Unloading tape.\n", name);
+		else
+		printk(ST_DEB_MSG "%s: Loading tape.\n", name);
+		);
+
+	SRpnt = st_do_scsi(NULL, STp, cmd, 0, DMA_NONE,
+			   timeout, MAX_RETRIES, 1);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
+
+	retval = (STp->buffer)->syscall_result;
+	scsi_release_request(SRpnt);
+
+	if (!retval) {	/* SCSI command successful */
+
+		if (!load_code) {
+			STp->rew_at_close = 0;
+			STp->ready = ST_NO_TAPE;
+		}
+		else {
+			STp->rew_at_close = STp->autorew_dev;
+			retval = check_tape(STp, filp);
+			if (retval > 0)
+				retval = 0;
+		}
+	}
+	else {
+		STps = &(STp->ps[STp->partition]);
+		STps->drv_file = STps->drv_block = (-1);
+	}
+
+	return retval;
+}
+
+#if DEBUG
+#define ST_DEB_FORWARD  0
+#define ST_DEB_BACKWARD 1
+static void deb_space_print(char *name, int direction, char *units, unsigned char *cmd)
+{
+	s32 sc;
+
+	sc = cmd[2] & 0x80 ? 0xff000000 : 0;
+	sc |= (cmd[2] << 16) | (cmd[3] << 8) | cmd[4];
+	if (direction)
+		sc = -sc;
+	printk(ST_DEB_MSG "%s: Spacing tape %s over %d %s.\n", name,
+	       direction ? "backward" : "forward", sc, units);
+}
+#endif
+
+
+/* Internal ioctl function */
+static int st_int_ioctl(struct scsi_tape *STp, unsigned int cmd_in, unsigned long arg)
+{
+	int timeout;
+	long ltmp;
+	int ioctl_result;
+	int chg_eof = 1;
+	unsigned char cmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	struct st_partstat *STps;
+	int fileno, blkno, at_sm, undone;
+	int datalen = 0, direction = DMA_NONE;
+	char *name = tape_name(STp);
+
+	WARN_ON(STp->buffer->do_dio != 0);
+	if (STp->ready != ST_READY) {
+		if (STp->ready == ST_NO_TAPE)
+			return (-ENOMEDIUM);
+		else
+			return (-EIO);
+	}
+	timeout = STp->long_timeout;
+	STps = &(STp->ps[STp->partition]);
+	fileno = STps->drv_file;
+	blkno = STps->drv_block;
+	at_sm = STps->at_sm;
+
+	memset(cmd, 0, MAX_COMMAND_SIZE);
+	switch (cmd_in) {
+	case MTFSFM:
+		chg_eof = 0;	/* Changed from the FSF after this */
+	case MTFSF:
+		cmd[0] = SPACE;
+		cmd[1] = 0x01;	/* Space FileMarks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "filemarks", cmd);)
+		if (fileno >= 0)
+			fileno += arg;
+		blkno = 0;
+		at_sm &= (arg == 0);
+		break;
+	case MTBSFM:
+		chg_eof = 0;	/* Changed from the FSF after this */
+	case MTBSF:
+		cmd[0] = SPACE;
+		cmd[1] = 0x01;	/* Space FileMarks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "filemarks", cmd);)
+		if (fileno >= 0)
+			fileno -= arg;
+		blkno = (-1);	/* We can't know the block number */
+		at_sm &= (arg == 0);
+		break;
+	case MTFSR:
+		cmd[0] = SPACE;
+		cmd[1] = 0x00;	/* Space Blocks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "blocks", cmd);)
+		if (blkno >= 0)
+			blkno += arg;
+		at_sm &= (arg == 0);
+		break;
+	case MTBSR:
+		cmd[0] = SPACE;
+		cmd[1] = 0x00;	/* Space Blocks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "blocks", cmd);)
+		if (blkno >= 0)
+			blkno -= arg;
+		at_sm &= (arg == 0);
+		break;
+	case MTFSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04;	/* Space Setmarks */
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+                DEBC(deb_space_print(name, ST_DEB_FORWARD, "setmarks", cmd);)
+		if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		}
+		break;
+	case MTBSS:
+		cmd[0] = SPACE;
+		cmd[1] = 0x04;	/* Space Setmarks */
+		ltmp = (-arg);
+		cmd[2] = (ltmp >> 16);
+		cmd[3] = (ltmp >> 8);
+		cmd[4] = ltmp;
+                DEBC(deb_space_print(name, ST_DEB_BACKWARD, "setmarks", cmd);)
+		if (arg != 0) {
+			blkno = fileno = (-1);
+			at_sm = 1;
+		}
+		break;
+	case MTWEOF:
+	case MTWSM:
+		if (STp->write_prot)
+			return (-EACCES);
+		cmd[0] = WRITE_FILEMARKS;
+		if (cmd_in == MTWSM)
+			cmd[1] = 2;
+		cmd[2] = (arg >> 16);
+		cmd[3] = (arg >> 8);
+		cmd[4] = arg;
+		timeout = STp->device->timeout;
+                DEBC(
+                     if (cmd_in == MTWEOF)
+                               printk(ST_DEB_MSG "%s: Writing %d filemarks.\n", name,
+				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+                     else
+				printk(ST_DEB_MSG "%s: Writing %d setmarks.\n", name,
+				 cmd[2] * 65536 + cmd[3] * 256 + cmd[4]);
+		)
+		if (fileno >= 0)
+			fileno += arg;
+		blkno = 0;
+		at_sm = (cmd_in == MTWSM);
+		break;
+	case MTREW:
+		cmd[0] = REZERO_UNIT;
+		if (STp->immediate) {
+			cmd[1] = 1;	/* Don't wait for completion */
+			timeout = STp->device->timeout;
+		}
+                DEBC(printk(ST_DEB_MSG "%s: Rewinding tape.\n", name));
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTNOP:
+                DEBC(printk(ST_DEB_MSG "%s: No op on tape.\n", name));
+		return 0;	/* Should do something ? */
+		break;
+	case MTRETEN:
+		cmd[0] = START_STOP;
+		if (STp->immediate) {
+			cmd[1] = 1;	/* Don't wait for completion */
+			timeout = STp->device->timeout;
+		}
+		cmd[4] = 3;
+                DEBC(printk(ST_DEB_MSG "%s: Retensioning tape.\n", name));
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTEOM:
+		if (!STp->fast_mteom) {
+			/* space to the end of tape */
+			ioctl_result = st_int_ioctl(STp, MTFSF, 0x7fffff);
+			fileno = STps->drv_file;
+			if (STps->eof >= ST_EOD_1)
+				return 0;
+			/* The next lines would hide the number of spaced FileMarks
+			   That's why I inserted the previous lines. I had no luck
+			   with detecting EOM with FSF, so we go now to EOM.
+			   Joerg Weule */
+		} else
+			fileno = (-1);
+		cmd[0] = SPACE;
+		cmd[1] = 3;
+                DEBC(printk(ST_DEB_MSG "%s: Spacing to end of recorded medium.\n",
+                            name));
+		blkno = -1;
+		at_sm = 0;
+		break;
+	case MTERASE:
+		if (STp->write_prot)
+			return (-EACCES);
+		cmd[0] = ERASE;
+		cmd[1] = (arg ? 1 : 0);	/* Long erase with non-zero argument */
+		if (STp->immediate) {
+			cmd[1] |= 2;	/* Don't wait for completion */
+			timeout = STp->device->timeout;
+		}
+		else
+			timeout = STp->long_timeout * 8;
+
+                DEBC(printk(ST_DEB_MSG "%s: Erasing tape.\n", name));
+		fileno = blkno = at_sm = 0;
+		break;
+	case MTSETBLK:		/* Set block length */
+	case MTSETDENSITY:	/* Set tape density */
+	case MTSETDRVBUFFER:	/* Set drive buffering */
+	case SET_DENS_AND_BLK:	/* Set density and block size */
+		chg_eof = 0;
+		if (STp->dirty || (STp->buffer)->buffer_bytes != 0)
+			return (-EIO);	/* Not allowed if data in buffer */
+		if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) &&
+		    (arg & MT_ST_BLKSIZE_MASK) != 0 &&
+		    STp->max_block > 0 &&
+		    ((arg & MT_ST_BLKSIZE_MASK) < STp->min_block ||
+		     (arg & MT_ST_BLKSIZE_MASK) > STp->max_block)) {
+			printk(KERN_WARNING "%s: Illegal block size.\n", name);
+			return (-EINVAL);
+		}
+		cmd[0] = MODE_SELECT;
+		if ((STp->use_pf & USE_PF))
+			cmd[1] = MODE_SELECT_PAGE_FORMAT;
+		cmd[4] = datalen = 12;
+		direction = DMA_TO_DEVICE;
+
+		memset((STp->buffer)->b_data, 0, 12);
+		if (cmd_in == MTSETDRVBUFFER)
+			(STp->buffer)->b_data[2] = (arg & 7) << 4;
+		else
+			(STp->buffer)->b_data[2] =
+			    STp->drv_buffer << 4;
+		(STp->buffer)->b_data[3] = 8;	/* block descriptor length */
+		if (cmd_in == MTSETDENSITY) {
+			(STp->buffer)->b_data[4] = arg;
+			STp->density_changed = 1;	/* At least we tried ;-) */
+		} else if (cmd_in == SET_DENS_AND_BLK)
+			(STp->buffer)->b_data[4] = arg >> 24;
+		else
+			(STp->buffer)->b_data[4] = STp->density;
+		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+			ltmp = arg & MT_ST_BLKSIZE_MASK;
+			if (cmd_in == MTSETBLK)
+				STp->blksize_changed = 1; /* At least we tried ;-) */
+		} else
+			ltmp = STp->block_size;
+		(STp->buffer)->b_data[9] = (ltmp >> 16);
+		(STp->buffer)->b_data[10] = (ltmp >> 8);
+		(STp->buffer)->b_data[11] = ltmp;
+		timeout = STp->device->timeout;
+                DEBC(
+			if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK)
+				printk(ST_DEB_MSG
+                                       "%s: Setting block size to %d bytes.\n", name,
+				       (STp->buffer)->b_data[9] * 65536 +
+				       (STp->buffer)->b_data[10] * 256 +
+				       (STp->buffer)->b_data[11]);
+			if (cmd_in == MTSETDENSITY || cmd_in == SET_DENS_AND_BLK)
+				printk(ST_DEB_MSG
+                                       "%s: Setting density code to %x.\n", name,
+				       (STp->buffer)->b_data[4]);
+			if (cmd_in == MTSETDRVBUFFER)
+				printk(ST_DEB_MSG
+                                       "%s: Setting drive buffer code to %d.\n", name,
+				    ((STp->buffer)->b_data[2] >> 4) & 7);
+		)
+		break;
+	default:
+		return (-ENOSYS);
+	}
+
+	SRpnt = st_do_scsi(NULL, STp, cmd, datalen, direction,
+			   timeout, MAX_RETRIES, 1);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
+
+	ioctl_result = (STp->buffer)->syscall_result;
+
+	if (!ioctl_result) {	/* SCSI command successful */
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+		STps->drv_block = blkno;
+		STps->drv_file = fileno;
+		STps->at_sm = at_sm;
+
+		if (cmd_in == MTBSFM)
+			ioctl_result = st_int_ioctl(STp, MTFSF, 1);
+		else if (cmd_in == MTFSFM)
+			ioctl_result = st_int_ioctl(STp, MTBSF, 1);
+
+		if (cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) {
+			int old_block_size = STp->block_size;
+			STp->block_size = arg & MT_ST_BLKSIZE_MASK;
+			if (STp->block_size != 0) {
+				if (old_block_size == 0)
+					normalize_buffer(STp->buffer);
+				(STp->buffer)->buffer_blocks =
+				    (STp->buffer)->buffer_size / STp->block_size;
+			}
+			(STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0;
+			if (cmd_in == SET_DENS_AND_BLK)
+				STp->density = arg >> MT_ST_DENSITY_SHIFT;
+		} else if (cmd_in == MTSETDRVBUFFER)
+			STp->drv_buffer = (arg & 7);
+		else if (cmd_in == MTSETDENSITY)
+			STp->density = arg;
+
+		if (cmd_in == MTEOM)
+			STps->eof = ST_EOD;
+		else if (cmd_in == MTFSF)
+			STps->eof = ST_FM;
+		else if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+		if (cmd_in == MTWEOF)
+			STps->rw = ST_IDLE;
+	} else { /* SCSI command was not completely successful. Don't return
+                    from this block without releasing the SCSI command block! */
+		struct st_cmdstatus *cmdstatp = &STp->buffer->cmdstat;
+
+		if (cmdstatp->flags & SENSE_EOM) {
+			if (cmd_in != MTBSF && cmd_in != MTBSFM &&
+			    cmd_in != MTBSR && cmd_in != MTBSS)
+				STps->eof = ST_EOM_OK;
+			STps->drv_block = 0;
+		}
+
+		if (cmdstatp->remainder_valid)
+			undone = (int)cmdstatp->uremainder64;
+		else
+			undone = 0;
+
+		if (cmd_in == MTWEOF &&
+		    cmdstatp->have_sense &&
+		    (cmdstatp->flags & SENSE_EOM) &&
+		    (cmdstatp->sense_hdr.sense_key == NO_SENSE ||
+		     cmdstatp->sense_hdr.sense_key == RECOVERED_ERROR) &&
+		    undone == 0) {
+			ioctl_result = 0;	/* EOF written succesfully at EOM */
+			if (fileno >= 0)
+				fileno++;
+			STps->drv_file = fileno;
+			STps->eof = ST_NOEOF;
+		} else if ((cmd_in == MTFSF) || (cmd_in == MTFSFM)) {
+			if (fileno >= 0)
+				STps->drv_file = fileno - undone;
+			else
+				STps->drv_file = fileno;
+			STps->drv_block = -1;
+			STps->eof = ST_NOEOF;
+		} else if ((cmd_in == MTBSF) || (cmd_in == MTBSFM)) {
+			if (arg > 0 && undone < 0)  /* Some drives get this wrong */
+				undone = (-undone);
+			if (STps->drv_file >= 0)
+				STps->drv_file = fileno + undone;
+			STps->drv_block = 0;
+			STps->eof = ST_NOEOF;
+		} else if (cmd_in == MTFSR) {
+			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
+				if (STps->drv_file >= 0)
+					STps->drv_file++;
+				STps->drv_block = 0;
+				STps->eof = ST_FM;
+			} else {
+				if (blkno >= undone)
+					STps->drv_block = blkno - undone;
+				else
+					STps->drv_block = (-1);
+				STps->eof = ST_NOEOF;
+			}
+		} else if (cmd_in == MTBSR) {
+			if (cmdstatp->flags & SENSE_FMK) {	/* Hit filemark */
+				STps->drv_file--;
+				STps->drv_block = (-1);
+			} else {
+				if (arg > 0 && undone < 0)  /* Some drives get this wrong */
+					undone = (-undone);
+				if (STps->drv_block >= 0)
+					STps->drv_block = blkno + undone;
+			}
+			STps->eof = ST_NOEOF;
+		} else if (cmd_in == MTEOM) {
+			STps->drv_file = (-1);
+			STps->drv_block = (-1);
+			STps->eof = ST_EOD;
+		} else if (cmd_in == MTSETBLK ||
+			   cmd_in == MTSETDENSITY ||
+			   cmd_in == MTSETDRVBUFFER ||
+			   cmd_in == SET_DENS_AND_BLK) {
+			if (cmdstatp->sense_hdr.sense_key == ILLEGAL_REQUEST &&
+			    !(STp->use_pf & PF_TESTED)) {
+				/* Try the other possible state of Page Format if not
+				   already tried */
+				STp->use_pf = !STp->use_pf | PF_TESTED;
+				scsi_release_request(SRpnt);
+				SRpnt = NULL;
+				return st_int_ioctl(STp, cmd_in, arg);
+			}
+		} else if (chg_eof)
+			STps->eof = ST_NOEOF;
+
+		if (cmdstatp->sense_hdr.sense_key == BLANK_CHECK)
+			STps->eof = ST_EOD;
+
+		scsi_release_request(SRpnt);
+		SRpnt = NULL;
+	}
+
+	return ioctl_result;
+}
+
+
+/* Get the tape position. If bt == 2, arg points into a kernel space mt_loc
+   structure. */
+
+static int get_location(struct scsi_tape *STp, unsigned int *block, int *partition,
+			int logical)
+{
+	int result;
+	unsigned char scmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	DEB( char *name = tape_name(STp); )
+
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	memset(scmd, 0, MAX_COMMAND_SIZE);
+	if ((STp->device)->scsi_level < SCSI_2) {
+		scmd[0] = QFA_REQUEST_BLOCK;
+		scmd[4] = 3;
+	} else {
+		scmd[0] = READ_POSITION;
+		if (!logical && !STp->scsi2_logical)
+			scmd[1] = 1;
+	}
+	SRpnt = st_do_scsi(NULL, STp, scmd, 20, DMA_FROM_DEVICE,
+			STp->device->timeout, MAX_READY_RETRIES, 1);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
+
+	if ((STp->buffer)->syscall_result != 0 ||
+	    (STp->device->scsi_level >= SCSI_2 &&
+	     ((STp->buffer)->b_data[0] & 4) != 0)) {
+		*block = *partition = 0;
+                DEBC(printk(ST_DEB_MSG "%s: Can't read tape position.\n", name));
+		result = (-EIO);
+	} else {
+		result = 0;
+		if ((STp->device)->scsi_level < SCSI_2) {
+			*block = ((STp->buffer)->b_data[0] << 16)
+			    + ((STp->buffer)->b_data[1] << 8)
+			    + (STp->buffer)->b_data[2];
+			*partition = 0;
+		} else {
+			*block = ((STp->buffer)->b_data[4] << 24)
+			    + ((STp->buffer)->b_data[5] << 16)
+			    + ((STp->buffer)->b_data[6] << 8)
+			    + (STp->buffer)->b_data[7];
+			*partition = (STp->buffer)->b_data[1];
+			if (((STp->buffer)->b_data[0] & 0x80) &&
+			    (STp->buffer)->b_data[1] == 0)	/* BOP of partition 0 */
+				STp->ps[0].drv_block = STp->ps[0].drv_file = 0;
+		}
+                DEBC(printk(ST_DEB_MSG "%s: Got tape pos. blk %d part %d.\n", name,
+                            *block, *partition));
+	}
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+
+	return result;
+}
+
+
+/* Set the tape block and partition. Negative partition means that only the
+   block should be set in vendor specific way. */
+static int set_location(struct scsi_tape *STp, unsigned int block, int partition,
+			int logical)
+{
+	struct st_partstat *STps;
+	int result, p;
+	unsigned int blk;
+	int timeout;
+	unsigned char scmd[MAX_COMMAND_SIZE];
+	struct scsi_request *SRpnt;
+	DEB( char *name = tape_name(STp); )
+
+	if (STp->ready != ST_READY)
+		return (-EIO);
+	timeout = STp->long_timeout;
+	STps = &(STp->ps[STp->partition]);
+
+        DEBC(printk(ST_DEB_MSG "%s: Setting block to %d and partition to %d.\n",
+                    name, block, partition));
+	DEB(if (partition < 0)
+		return (-EIO); )
+
+	/* Update the location at the partition we are leaving */
+	if ((!STp->can_partitions && partition != 0) ||
+	    partition >= ST_NBR_PARTITIONS)
+		return (-EINVAL);
+	if (partition != STp->partition) {
+		if (get_location(STp, &blk, &p, 1))
+			STps->last_block_valid = 0;
+		else {
+			STps->last_block_valid = 1;
+			STps->last_block_visited = blk;
+                        DEBC(printk(ST_DEB_MSG
+                                    "%s: Visited block %d for partition %d saved.\n",
+                                    name, blk, STp->partition));
+		}
+	}
+
+	memset(scmd, 0, MAX_COMMAND_SIZE);
+	if ((STp->device)->scsi_level < SCSI_2) {
+		scmd[0] = QFA_SEEK_BLOCK;
+		scmd[2] = (block >> 16);
+		scmd[3] = (block >> 8);
+		scmd[4] = block;
+		scmd[5] = 0;
+	} else {
+		scmd[0] = SEEK_10;
+		scmd[3] = (block >> 24);
+		scmd[4] = (block >> 16);
+		scmd[5] = (block >> 8);
+		scmd[6] = block;
+		if (!logical && !STp->scsi2_logical)
+			scmd[1] = 4;
+		if (STp->partition != partition) {
+			scmd[1] |= 2;
+			scmd[8] = partition;
+                        DEBC(printk(ST_DEB_MSG
+                                    "%s: Trying to change partition from %d to %d\n",
+                                    name, STp->partition, partition));
+		}
+	}
+	if (STp->immediate) {
+		scmd[1] |= 1;		/* Don't wait for completion */
+		timeout = STp->device->timeout;
+	}
+
+	SRpnt = st_do_scsi(NULL, STp, scmd, 0, DMA_NONE,
+			   timeout, MAX_READY_RETRIES, 1);
+	if (!SRpnt)
+		return (STp->buffer)->syscall_result;
+
+	STps->drv_block = STps->drv_file = (-1);
+	STps->eof = ST_NOEOF;
+	if ((STp->buffer)->syscall_result != 0) {
+		result = (-EIO);
+		if (STp->can_partitions &&
+		    (STp->device)->scsi_level >= SCSI_2 &&
+		    (p = find_partition(STp)) >= 0)
+			STp->partition = p;
+	} else {
+		if (STp->can_partitions) {
+			STp->partition = partition;
+			STps = &(STp->ps[partition]);
+			if (!STps->last_block_valid ||
+			    STps->last_block_visited != block) {
+				STps->at_sm = 0;
+				STps->rw = ST_IDLE;
+			}
+		} else
+			STps->at_sm = 0;
+		if (block == 0)
+			STps->drv_block = STps->drv_file = 0;
+		result = 0;
+	}
+
+	scsi_release_request(SRpnt);
+	SRpnt = NULL;
+
+	return result;
+}
+
+
+/* Find the current partition number for the drive status. Called from open and
+   returns either partition number of negative error code. */
+static int find_partition(struct scsi_tape *STp)
+{
+	int i, partition;
+	unsigned int block;
+
+	if ((i = get_location(STp, &block, &partition, 1)) < 0)
+		return i;
+	if (partition >= ST_NBR_PARTITIONS)
+		return (-EIO);
+	return partition;
+}
+
+
+/* Change the partition if necessary */
+static int switch_partition(struct scsi_tape *STp)
+{
+	struct st_partstat *STps;
+
+	if (STp->partition == STp->new_partition)
+		return 0;
+	STps = &(STp->ps[STp->new_partition]);
+	if (!STps->last_block_valid)
+		STps->last_block_visited = 0;
+	return set_location(STp, STps->last_block_visited, STp->new_partition, 1);
+}
+
+/* Functions for reading and writing the medium partition mode page. */
+
+#define PART_PAGE   0x11
+#define PART_PAGE_FIXED_LENGTH 8
+
+#define PP_OFF_MAX_ADD_PARTS   2
+#define PP_OFF_NBR_ADD_PARTS   3
+#define PP_OFF_FLAGS           4
+#define PP_OFF_PART_UNITS      6
+#define PP_OFF_RESERVED        7
+
+#define PP_BIT_IDP             0x20
+#define PP_MSK_PSUM_MB         0x10
+
+/* Get the number of partitions on the tape. As a side effect reads the
+   mode page into the tape buffer. */
+static int nbr_partitions(struct scsi_tape *STp)
+{
+	int result;
+	DEB( char *name = tape_name(STp); )
+
+	if (STp->ready != ST_READY)
+		return (-EIO);
+
+	result = read_mode_page(STp, PART_PAGE, 1);
+
+	if (result) {
+                DEBC(printk(ST_DEB_MSG "%s: Can't read medium partition page.\n",
+                            name));
+		result = (-EIO);
+	} else {
+		result = (STp->buffer)->b_data[MODE_HEADER_LENGTH +
+					      PP_OFF_NBR_ADD_PARTS] + 1;
+                DEBC(printk(ST_DEB_MSG "%s: Number of partitions %d.\n", name, result));
+	}
+
+	return result;
+}
+
+
+/* Partition the tape into two partitions if size > 0 or one partition if
+   size == 0.
+
+   The block descriptors are read and written because Sony SDT-7000 does not
+   work without this (suggestion from Michael Schaefer <Michael.Schaefer@dlr.de>).
+
+   My HP C1533A drive returns only one partition size field. This is used to
+   set the size of partition 1. There is no size field for the default partition.
+   Michael Schaefer's Sony SDT-7000 returns two descriptors and the second is
+   used to set the size of partition 1 (this is what the SCSI-3 standard specifies).
+   The following algorithm is used to accommodate both drives: if the number of
+   partition size fields is greater than the maximum number of additional partitions
+   in the mode page, the second field is used. Otherwise the first field is used.
+
+   For Seagate DDS drives the page length must be 8 when no partitions is defined
+   and 10 when 1 partition is defined (information from Eric Lee Green). This is
+   is acceptable also to some other old drives and enforced if the first partition
+   size field is used for the first additional partition size.
+ */
+static int partition_tape(struct scsi_tape *STp, int size)
+{
+	char *name = tape_name(STp);
+	int result;
+	int pgo, psd_cnt, psdo;
+	unsigned char *bp;
+
+	result = read_mode_page(STp, PART_PAGE, 0);
+	if (result) {
+		DEBC(printk(ST_DEB_MSG "%s: Can't read partition mode page.\n", name));
+		return result;
+	}
+	/* The mode page is in the buffer. Let's modify it and write it. */
+	bp = (STp->buffer)->b_data;
+	pgo = MODE_HEADER_LENGTH + bp[MH_OFF_BDESCS_LENGTH];
+	DEBC(printk(ST_DEB_MSG "%s: Partition page length is %d bytes.\n",
+		    name, bp[pgo + MP_OFF_PAGE_LENGTH] + 2));
+
+	psd_cnt = (bp[pgo + MP_OFF_PAGE_LENGTH] + 2 - PART_PAGE_FIXED_LENGTH) / 2;
+	psdo = pgo + PART_PAGE_FIXED_LENGTH;
+	if (psd_cnt > bp[pgo + PP_OFF_MAX_ADD_PARTS]) {
+		bp[psdo] = bp[psdo + 1] = 0xff;  /* Rest of the tape */
+		psdo += 2;
+	}
+	memset(bp + psdo, 0, bp[pgo + PP_OFF_NBR_ADD_PARTS] * 2);
+
+	DEBC(printk("%s: psd_cnt %d, max.parts %d, nbr_parts %d\n", name,
+		    psd_cnt, bp[pgo + PP_OFF_MAX_ADD_PARTS],
+		    bp[pgo + PP_OFF_NBR_ADD_PARTS]));
+
+	if (size <= 0) {
+		bp[pgo + PP_OFF_NBR_ADD_PARTS] = 0;
+		if (psd_cnt <= bp[pgo + PP_OFF_MAX_ADD_PARTS])
+		    bp[pgo + MP_OFF_PAGE_LENGTH] = 6;
+                DEBC(printk(ST_DEB_MSG "%s: Formatting tape with one partition.\n",
+                            name));
+	} else {
+		bp[psdo] = (size >> 8) & 0xff;
+		bp[psdo + 1] = size & 0xff;
+		bp[pgo + 3] = 1;
+		if (bp[pgo + MP_OFF_PAGE_LENGTH] < 8)
+		    bp[pgo + MP_OFF_PAGE_LENGTH] = 8;
+                DEBC(printk(ST_DEB_MSG
+                            "%s: Formatting tape with two partitions (1 = %d MB).\n",
+                            name, size));
+	}
+	bp[pgo + PP_OFF_PART_UNITS] = 0;
+	bp[pgo + PP_OFF_RESERVED] = 0;
+	bp[pgo + PP_OFF_FLAGS] = PP_BIT_IDP | PP_MSK_PSUM_MB;
+
+	result = write_mode_page(STp, PART_PAGE, 1);
+	if (result) {
+		printk(KERN_INFO "%s: Partitioning of tape failed.\n", name);
+		result = (-EIO);
+	}
+
+	return result;
+}
+
+
+
+/* The ioctl command */
+static int st_ioctl(struct inode *inode, struct file *file,
+		    unsigned int cmd_in, unsigned long arg)
+{
+	int i, cmd_nr, cmd_type, bt;
+	int retval = 0;
+	unsigned int blk;
+	struct scsi_tape *STp = file->private_data;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	char *name = tape_name(STp);
+	void __user *p = (void __user *)arg;
+
+	if (down_interruptible(&STp->lock))
+		return -ERESTARTSYS;
+
+        DEB(
+	if (debugging && !STp->in_use) {
+		printk(ST_DEB_MSG "%s: Incorrect device.\n", name);
+		retval = (-EIO);
+		goto out;
+	} ) /* end DEB */
+
+	STm = &(STp->modes[STp->current_mode]);
+	STps = &(STp->ps[STp->partition]);
+
+	/*
+	 * If we are in the middle of error recovery, don't let anyone
+	 * else try and use this device.  Also, if error recovery fails, it
+	 * may try and take the device offline, in which case all further
+	 * access to the device is prohibited.
+	 */
+	retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p, file);
+	if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)
+		goto out;
+	retval = 0;
+
+	cmd_type = _IOC_TYPE(cmd_in);
+	cmd_nr = _IOC_NR(cmd_in);
+
+	if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) {
+		struct mtop mtc;
+
+		if (_IOC_SIZE(cmd_in) != sizeof(mtc)) {
+			retval = (-EINVAL);
+			goto out;
+		}
+
+		i = copy_from_user(&mtc, p, sizeof(struct mtop));
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
+
+		if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) {
+			printk(KERN_WARNING
+                               "%s: MTSETDRVBUFFER only allowed for root.\n", name);
+			retval = (-EPERM);
+			goto out;
+		}
+		if (!STm->defined &&
+		    (mtc.mt_op != MTSETDRVBUFFER &&
+		     (mtc.mt_count & MT_ST_OPTIONS) == 0)) {
+			retval = (-ENXIO);
+			goto out;
+		}
+
+		if (!STp->pos_unknown) {
+
+			if (STps->eof == ST_FM_HIT) {
+				if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
+                                    mtc.mt_op == MTEOM) {
+					mtc.mt_count -= 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				} else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) {
+					mtc.mt_count += 1;
+					if (STps->drv_file >= 0)
+						STps->drv_file += 1;
+				}
+			}
+
+			if (mtc.mt_op == MTSEEK) {
+				/* Old position must be restored if partition will be
+                                   changed */
+				i = !STp->can_partitions ||
+				    (STp->new_partition != STp->partition);
+			} else {
+				i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+				    mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
+				    mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+				    mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM ||
+				    mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM ||
+				    mtc.mt_op == MTCOMPRESSION;
+			}
+			i = flush_buffer(STp, i);
+			if (i < 0) {
+				retval = i;
+				goto out;
+			}
+			if (STps->rw == ST_WRITING &&
+			    (mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+			     mtc.mt_op == MTSEEK ||
+			     mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)) {
+				i = st_int_ioctl(STp, MTWEOF, 1);
+				if (i < 0) {
+					retval = i;
+					goto out;
+				}
+				if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM)
+					mtc.mt_count++;
+				STps->rw = ST_IDLE;
+			     }
+
+		} else {
+			/*
+			 * If there was a bus reset, block further access
+			 * to this device.  If the user wants to rewind the tape,
+			 * then reset the flag and allow access again.
+			 */
+			if (mtc.mt_op != MTREW &&
+			    mtc.mt_op != MTOFFL &&
+			    mtc.mt_op != MTRETEN &&
+			    mtc.mt_op != MTERASE &&
+			    mtc.mt_op != MTSEEK &&
+			    mtc.mt_op != MTEOM) {
+				retval = (-EIO);
+				goto out;
+			}
+			reset_state(STp);
+			/* remove this when the midlevel properly clears was_reset */
+			STp->device->was_reset = 0;
+		}
+
+		if (mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK &&
+		    mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTWSM &&
+		    mtc.mt_op != MTSETDRVBUFFER && mtc.mt_op != MTSETPART)
+			STps->rw = ST_IDLE;	/* Prevent automatic WEOF and fsf */
+
+		if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
+			do_door_lock(STp, 0);	/* Ignore result! */
+
+		if (mtc.mt_op == MTSETDRVBUFFER &&
+		    (mtc.mt_count & MT_ST_OPTIONS) != 0) {
+			retval = st_set_options(STp, mtc.mt_count);
+			goto out;
+		}
+
+		if (mtc.mt_op == MTSETPART) {
+			if (!STp->can_partitions ||
+			    mtc.mt_count < 0 || mtc.mt_count >= ST_NBR_PARTITIONS) {
+				retval = (-EINVAL);
+				goto out;
+			}
+			if (mtc.mt_count >= STp->nbr_partitions &&
+			    (STp->nbr_partitions = nbr_partitions(STp)) < 0) {
+				retval = (-EIO);
+				goto out;
+			}
+			if (mtc.mt_count >= STp->nbr_partitions) {
+				retval = (-EINVAL);
+				goto out;
+			}
+			STp->new_partition = mtc.mt_count;
+			retval = 0;
+			goto out;
+		}
+
+		if (mtc.mt_op == MTMKPART) {
+			if (!STp->can_partitions) {
+				retval = (-EINVAL);
+				goto out;
+			}
+			if ((i = st_int_ioctl(STp, MTREW, 0)) < 0 ||
+			    (i = partition_tape(STp, mtc.mt_count)) < 0) {
+				retval = i;
+				goto out;
+			}
+			for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+				STp->ps[i].rw = ST_IDLE;
+				STp->ps[i].at_sm = 0;
+				STp->ps[i].last_block_valid = 0;
+			}
+			STp->partition = STp->new_partition = 0;
+			STp->nbr_partitions = 1;	/* Bad guess ?-) */
+			STps->drv_block = STps->drv_file = 0;
+			retval = 0;
+			goto out;
+		}
+
+		if (mtc.mt_op == MTSEEK) {
+			i = set_location(STp, mtc.mt_count, STp->new_partition, 0);
+			if (!STp->can_partitions)
+				STp->ps[0].rw = ST_IDLE;
+			retval = i;
+			goto out;
+		}
+
+		if (mtc.mt_op == MTUNLOAD || mtc.mt_op == MTOFFL) {
+			retval = do_load_unload(STp, file, 0);
+			goto out;
+		}
+
+		if (mtc.mt_op == MTLOAD) {
+			retval = do_load_unload(STp, file, max(1, mtc.mt_count));
+			goto out;
+		}
+
+		if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
+			retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
+			goto out;
+		}
+
+		if (STp->can_partitions && STp->ready == ST_READY &&
+		    (i = switch_partition(STp)) < 0) {
+			retval = i;
+			goto out;
+		}
+
+		if (mtc.mt_op == MTCOMPRESSION)
+			retval = st_compression(STp, (mtc.mt_count & 1));
+		else
+			retval = st_int_ioctl(STp, mtc.mt_op, mtc.mt_count);
+		goto out;
+	}
+	if (!STm->defined) {
+		retval = (-ENXIO);
+		goto out;
+	}
+
+	if ((i = flush_buffer(STp, 0)) < 0) {
+		retval = i;
+		goto out;
+	}
+	if (STp->can_partitions &&
+	    (i = switch_partition(STp)) < 0) {
+		retval = i;
+		goto out;
+	}
+
+	if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) {
+		struct mtget mt_status;
+
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) {
+			 retval = (-EINVAL);
+			 goto out;
+		}
+
+		mt_status.mt_type = STp->tape_type;
+		mt_status.mt_dsreg =
+		    ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) |
+		    ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK);
+		mt_status.mt_blkno = STps->drv_block;
+		mt_status.mt_fileno = STps->drv_file;
+		if (STp->block_size != 0) {
+			if (STps->rw == ST_WRITING)
+				mt_status.mt_blkno +=
+				    (STp->buffer)->buffer_bytes / STp->block_size;
+			else if (STps->rw == ST_READING)
+				mt_status.mt_blkno -=
+                                        ((STp->buffer)->buffer_bytes +
+                                         STp->block_size - 1) / STp->block_size;
+		}
+
+		mt_status.mt_gstat = 0;
+		if (STp->drv_write_prot)
+			mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff);
+		if (mt_status.mt_blkno == 0) {
+			if (mt_status.mt_fileno == 0)
+				mt_status.mt_gstat |= GMT_BOT(0xffffffff);
+			else
+				mt_status.mt_gstat |= GMT_EOF(0xffffffff);
+		}
+		mt_status.mt_erreg = (STp->recover_reg << MT_ST_SOFTERR_SHIFT);
+		mt_status.mt_resid = STp->partition;
+		if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR)
+			mt_status.mt_gstat |= GMT_EOT(0xffffffff);
+		else if (STps->eof >= ST_EOM_OK)
+			mt_status.mt_gstat |= GMT_EOD(0xffffffff);
+		if (STp->density == 1)
+			mt_status.mt_gstat |= GMT_D_800(0xffffffff);
+		else if (STp->density == 2)
+			mt_status.mt_gstat |= GMT_D_1600(0xffffffff);
+		else if (STp->density == 3)
+			mt_status.mt_gstat |= GMT_D_6250(0xffffffff);
+		if (STp->ready == ST_READY)
+			mt_status.mt_gstat |= GMT_ONLINE(0xffffffff);
+		if (STp->ready == ST_NO_TAPE)
+			mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff);
+		if (STps->at_sm)
+			mt_status.mt_gstat |= GMT_SM(0xffffffff);
+		if (STm->do_async_writes ||
+                    (STm->do_buffer_writes && STp->block_size != 0) ||
+		    STp->drv_buffer != 0)
+			mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff);
+		if (STp->cleaning_req)
+			mt_status.mt_gstat |= GMT_CLN(0xffffffff);
+
+		i = copy_to_user(p, &mt_status, sizeof(struct mtget));
+		if (i) {
+			retval = (-EFAULT);
+			goto out;
+		}
+
+		STp->recover_reg = 0;		/* Clear after read */
+		retval = 0;
+		goto out;
+	}			/* End of MTIOCGET */
+	if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) {
+		struct mtpos mt_pos;
+		if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) {
+			 retval = (-EINVAL);
+			 goto out;
+		}
+		if ((i = get_location(STp, &blk, &bt, 0)) < 0) {
+			retval = i;
+			goto out;
+		}
+		mt_pos.mt_blkno = blk;
+		i = copy_to_user(p, &mt_pos, sizeof(struct mtpos));
+		if (i)
+			retval = (-EFAULT);
+		goto out;
+	}
+	up(&STp->lock);
+	switch (cmd_in) {
+		case SCSI_IOCTL_GET_IDLUN:
+		case SCSI_IOCTL_GET_BUS_NUMBER:
+			break;
+		default:
+			if (!capable(CAP_SYS_ADMIN))
+				i = -EPERM;
+			else
+				i = scsi_cmd_ioctl(file, STp->disk, cmd_in, p);
+			if (i != -ENOTTY)
+				return i;
+			break;
+	}
+	if (!capable(CAP_SYS_ADMIN) &&
+	    (cmd_in == SCSI_IOCTL_START_UNIT || cmd_in == SCSI_IOCTL_STOP_UNIT))
+		return -EPERM;
+	return scsi_ioctl(STp->device, cmd_in, p);
+
+ out:
+	up(&STp->lock);
+	return retval;
+}
+
+#ifdef CONFIG_COMPAT
+static long st_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct scsi_tape *STp = file->private_data;
+	struct scsi_device *sdev = STp->device;
+	int ret = -ENOIOCTLCMD;
+	if (sdev->host->hostt->compat_ioctl) { 
+
+		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
+
+	}
+	return ret;
+}
+#endif
+
+
+
+/* Try to allocate a new tape buffer. Calling function must not hold
+   dev_arr_lock. */
+static struct st_buffer *
+ new_tape_buffer(int from_initialization, int need_dma, int max_sg)
+{
+	int i, priority, got = 0, segs = 0;
+	struct st_buffer *tb;
+
+	if (from_initialization)
+		priority = GFP_ATOMIC;
+	else
+		priority = GFP_KERNEL;
+
+	i = sizeof(struct st_buffer) + (max_sg - 1) * sizeof(struct scatterlist) +
+		max_sg * sizeof(struct st_buf_fragment);
+	tb = kmalloc(i, priority);
+	if (!tb) {
+		printk(KERN_NOTICE "st: Can't allocate new tape buffer.\n");
+		return NULL;
+	}
+	memset(tb, 0, i);
+	tb->frp_segs = tb->orig_frp_segs = segs;
+	tb->use_sg = max_sg;
+	if (segs > 0)
+		tb->b_data = page_address(tb->sg[0].page);
+	tb->frp = (struct st_buf_fragment *)(&(tb->sg[0]) + max_sg);
+
+	tb->in_use = 1;
+	tb->dma = need_dma;
+	tb->buffer_size = got;
+
+	return tb;
+}
+
+
+/* Try to allocate enough space in the tape buffer */
+static int enlarge_buffer(struct st_buffer * STbuffer, int new_size, int need_dma)
+{
+	int segs, nbr, max_segs, b_size, priority, order, got;
+
+	if (new_size <= STbuffer->buffer_size)
+		return 1;
+
+	if (STbuffer->buffer_size <= PAGE_SIZE)
+		normalize_buffer(STbuffer);  /* Avoid extra segment */
+
+	max_segs = STbuffer->use_sg;
+	nbr = max_segs - STbuffer->frp_segs;
+	if (nbr <= 0)
+		return 0;
+
+	priority = GFP_KERNEL | __GFP_NOWARN;
+	if (need_dma)
+		priority |= GFP_DMA;
+	for (b_size = PAGE_SIZE, order=0;
+	     b_size < new_size - STbuffer->buffer_size;
+	     order++, b_size *= 2)
+		;  /* empty */
+
+	for (segs = STbuffer->frp_segs, got = STbuffer->buffer_size;
+	     segs < max_segs && got < new_size;) {
+		STbuffer->frp[segs].page = alloc_pages(priority, order);
+		if (STbuffer->frp[segs].page == NULL) {
+			if (new_size - got <= (max_segs - segs) * b_size / 2) {
+				b_size /= 2; /* Large enough for the rest of the buffers */
+				order--;
+				continue;
+			}
+			DEB(STbuffer->buffer_size = got);
+			normalize_buffer(STbuffer);
+			return 0;
+		}
+		STbuffer->frp[segs].length = b_size;
+		STbuffer->frp_segs += 1;
+		got += b_size;
+		STbuffer->buffer_size = got;
+		segs++;
+	}
+	STbuffer->b_data = page_address(STbuffer->frp[0].page);
+
+	return 1;
+}
+
+
+/* Release the extra buffer */
+static void normalize_buffer(struct st_buffer * STbuffer)
+{
+	int i, order;
+
+	for (i = STbuffer->orig_frp_segs; i < STbuffer->frp_segs; i++) {
+		order = get_order(STbuffer->frp[i].length);
+		__free_pages(STbuffer->frp[i].page, order);
+		STbuffer->buffer_size -= STbuffer->frp[i].length;
+	}
+	STbuffer->frp_segs = STbuffer->orig_frp_segs;
+	STbuffer->frp_sg_current = 0;
+}
+
+
+/* Move data from the user buffer to the tape buffer. Returns zero (success) or
+   negative error code. */
+static int append_to_buffer(const char __user *ubp, struct st_buffer * st_bp, int do_count)
+{
+	int i, cnt, res, offset;
+
+	for (i = 0, offset = st_bp->buffer_bytes;
+	     i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++)
+		offset -= st_bp->frp[i].length;
+	if (i == st_bp->frp_segs) {	/* Should never happen */
+		printk(KERN_WARNING "st: append_to_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (; i < st_bp->frp_segs && do_count > 0; i++) {
+		cnt = st_bp->frp[i].length - offset < do_count ?
+		    st_bp->frp[i].length - offset : do_count;
+		res = copy_from_user(page_address(st_bp->frp[i].page) + offset, ubp, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) /* Should never happen */
+		return (-EIO);
+
+	return 0;
+}
+
+
+/* Move data from the tape buffer to the user buffer. Returns zero (success) or
+   negative error code. */
+static int from_buffer(struct st_buffer * st_bp, char __user *ubp, int do_count)
+{
+	int i, cnt, res, offset;
+
+	for (i = 0, offset = st_bp->read_pointer;
+	     i < st_bp->frp_segs && offset >= st_bp->frp[i].length; i++)
+		offset -= st_bp->frp[i].length;
+	if (i == st_bp->frp_segs) {	/* Should never happen */
+		printk(KERN_WARNING "st: from_buffer offset overflow.\n");
+		return (-EIO);
+	}
+	for (; i < st_bp->frp_segs && do_count > 0; i++) {
+		cnt = st_bp->frp[i].length - offset < do_count ?
+		    st_bp->frp[i].length - offset : do_count;
+		res = copy_to_user(ubp, page_address(st_bp->frp[i].page) + offset, cnt);
+		if (res)
+			return (-EFAULT);
+		do_count -= cnt;
+		st_bp->buffer_bytes -= cnt;
+		st_bp->read_pointer += cnt;
+		ubp += cnt;
+		offset = 0;
+	}
+	if (do_count) /* Should never happen */
+		return (-EIO);
+
+	return 0;
+}
+
+
+/* Move data towards start of buffer */
+static void move_buffer_data(struct st_buffer * st_bp, int offset)
+{
+	int src_seg, dst_seg, src_offset = 0, dst_offset;
+	int count, total;
+
+	if (offset == 0)
+		return;
+
+	total=st_bp->buffer_bytes - offset;
+	for (src_seg=0; src_seg < st_bp->frp_segs; src_seg++) {
+		src_offset = offset;
+		if (src_offset < st_bp->frp[src_seg].length)
+			break;
+		offset -= st_bp->frp[src_seg].length;
+	}
+
+	st_bp->buffer_bytes = st_bp->read_pointer = total;
+	for (dst_seg=dst_offset=0; total > 0; ) {
+		count = min(st_bp->frp[dst_seg].length - dst_offset,
+			    st_bp->frp[src_seg].length - src_offset);
+		memmove(page_address(st_bp->frp[dst_seg].page) + dst_offset,
+			page_address(st_bp->frp[src_seg].page) + src_offset, count);
+		src_offset += count;
+		if (src_offset >= st_bp->frp[src_seg].length) {
+			src_seg++;
+			src_offset = 0;
+		}
+		dst_offset += count;
+		if (dst_offset >= st_bp->frp[dst_seg].length) {
+			dst_seg++;
+			dst_offset = 0;
+		}
+		total -= count;
+	}
+}
+
+
+/* Fill the s/g list up to the length required for this transfer */
+static void buf_to_sg(struct st_buffer *STbp, unsigned int length)
+{
+	int i;
+	unsigned int count;
+	struct scatterlist *sg;
+	struct st_buf_fragment *frp;
+
+	if (length == STbp->frp_sg_current)
+		return;   /* work already done */
+
+	sg = &(STbp->sg[0]);
+	frp = STbp->frp;
+	for (i=count=0; count < length; i++) {
+		sg[i].page = frp[i].page;
+		if (length - count > frp[i].length)
+			sg[i].length = frp[i].length;
+		else
+			sg[i].length = length - count;
+		count += sg[i].length;
+		sg[i].offset = 0;
+	}
+	STbp->sg_segs = i;
+	STbp->frp_sg_current = length;
+}
+
+
+/* Validate the options from command line or module parameters */
+static void validate_options(void)
+{
+	if (buffer_kbs > 0)
+		st_fixed_buffer_size = buffer_kbs * ST_KILOBYTE;
+	if (max_sg_segs >= ST_FIRST_SG)
+		st_max_sg_segs = max_sg_segs;
+}
+
+#ifndef MODULE
+/* Set the boot options. Syntax is defined in Documenation/scsi/st.txt.
+ */
+static int __init st_setup(char *str)
+{
+	int i, len, ints[5];
+	char *stp;
+
+	stp = get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (ints[0] > 0) {
+		for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++)
+			if (parms[i].val)
+				*parms[i].val = ints[i + 1];
+	} else {
+		while (stp != NULL) {
+			for (i = 0; i < ARRAY_SIZE(parms); i++) {
+				len = strlen(parms[i].name);
+				if (!strncmp(stp, parms[i].name, len) &&
+				    (*(stp + len) == ':' || *(stp + len) == '=')) {
+					if (parms[i].val)
+						*parms[i].val =
+							simple_strtoul(stp + len + 1, NULL, 0);
+					else
+						printk(KERN_WARNING "st: Obsolete parameter %s\n",
+						       parms[i].name);
+					break;
+				}
+			}
+			if (i >= sizeof(parms) / sizeof(struct st_dev_parm))
+				 printk(KERN_WARNING "st: invalid parameter in '%s'\n",
+					stp);
+			stp = strchr(stp, ',');
+			if (stp)
+				stp++;
+		}
+	}
+
+	validate_options();
+
+	return 1;
+}
+
+__setup("st=", st_setup);
+
+#endif
+
+static struct file_operations st_fops =
+{
+	.owner =	THIS_MODULE,
+	.read =		st_read,
+	.write =	st_write,
+	.ioctl =	st_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl = st_compat_ioctl,
+#endif
+	.open =		st_open,
+	.flush =	st_flush,
+	.release =	st_release,
+};
+
+static int st_probe(struct device *dev)
+{
+	struct scsi_device *SDp = to_scsi_device(dev);
+	struct gendisk *disk = NULL;
+	struct cdev *cdev = NULL;
+	struct scsi_tape *tpnt = NULL;
+	struct st_modedef *STm;
+	struct st_partstat *STps;
+	struct st_buffer *buffer;
+	int i, j, mode, dev_num, error;
+	char *stp;
+	u64 bounce_limit;
+
+	if (SDp->type != TYPE_TAPE)
+		return -ENODEV;
+	if ((stp = st_incompatible(SDp))) {
+		printk(KERN_INFO
+		       "st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n",
+		       SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+		printk(KERN_INFO "st: The suggested driver is %s.\n", stp);
+		return -ENODEV;
+	}
+
+	i = SDp->host->sg_tablesize;
+	if (st_max_sg_segs < i)
+		i = st_max_sg_segs;
+	buffer = new_tape_buffer(1, (SDp->host)->unchecked_isa_dma, i);
+	if (buffer == NULL) {
+		printk(KERN_ERR
+		       "st: Can't allocate new tape buffer. Device not attached.\n");
+		goto out;
+	}
+
+	disk = alloc_disk(1);
+	if (!disk) {
+		printk(KERN_ERR "st: out of memory. Device not attached.\n");
+		goto out_buffer_free;
+	}
+
+	write_lock(&st_dev_arr_lock);
+	if (st_nr_dev >= st_dev_max) {
+		struct scsi_tape **tmp_da;
+		int tmp_dev_max;
+
+		tmp_dev_max = max(st_nr_dev * 2, 8);
+		if (tmp_dev_max > ST_MAX_TAPES)
+			tmp_dev_max = ST_MAX_TAPES;
+		if (tmp_dev_max <= st_nr_dev) {
+			write_unlock(&st_dev_arr_lock);
+			printk(KERN_ERR "st: Too many tape devices (max. %d).\n",
+			       ST_MAX_TAPES);
+			goto out_put_disk;
+		}
+
+		tmp_da = kmalloc(tmp_dev_max * sizeof(struct scsi_tape *), GFP_ATOMIC);
+		if (tmp_da == NULL) {
+			write_unlock(&st_dev_arr_lock);
+			printk(KERN_ERR "st: Can't extend device array.\n");
+			goto out_put_disk;
+		}
+
+		memset(tmp_da, 0, tmp_dev_max * sizeof(struct scsi_tape *));
+		if (scsi_tapes != NULL) {
+			memcpy(tmp_da, scsi_tapes,
+			       st_dev_max * sizeof(struct scsi_tape *));
+			kfree(scsi_tapes);
+		}
+		scsi_tapes = tmp_da;
+
+		st_dev_max = tmp_dev_max;
+	}
+
+	for (i = 0; i < st_dev_max; i++)
+		if (scsi_tapes[i] == NULL)
+			break;
+	if (i >= st_dev_max)
+		panic("scsi_devices corrupt (st)");
+
+	tpnt = kmalloc(sizeof(struct scsi_tape), GFP_ATOMIC);
+	if (tpnt == NULL) {
+		write_unlock(&st_dev_arr_lock);
+		printk(KERN_ERR "st: Can't allocate device descriptor.\n");
+		goto out_put_disk;
+	}
+	memset(tpnt, 0, sizeof(struct scsi_tape));
+	tpnt->disk = disk;
+	sprintf(disk->disk_name, "st%d", i);
+	disk->private_data = &tpnt->driver;
+	disk->queue = SDp->request_queue;
+	tpnt->driver = &st_template;
+	scsi_tapes[i] = tpnt;
+	dev_num = i;
+
+	tpnt->device = SDp;
+	if (SDp->scsi_level <= 2)
+		tpnt->tape_type = MT_ISSCSI1;
+	else
+		tpnt->tape_type = MT_ISSCSI2;
+
+	tpnt->buffer = buffer;
+
+	tpnt->inited = 0;
+	tpnt->dirty = 0;
+	tpnt->in_use = 0;
+	tpnt->drv_buffer = 1;	/* Try buffering if no mode sense */
+	tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
+	tpnt->use_pf = (SDp->scsi_level >= SCSI_2);
+	tpnt->density = 0;
+	tpnt->do_auto_lock = ST_AUTO_LOCK;
+	tpnt->can_bsr = (SDp->scsi_level > 2 ? 1 : ST_IN_FILE_POS); /* BSR mandatory in SCSI3 */
+	tpnt->can_partitions = 0;
+	tpnt->two_fm = ST_TWO_FM;
+	tpnt->fast_mteom = ST_FAST_MTEOM;
+	tpnt->scsi2_logical = ST_SCSI2LOGICAL;
+	tpnt->immediate = ST_NOWAIT;
+	tpnt->default_drvbuffer = 0xff;		/* No forced buffering */
+	tpnt->partition = 0;
+	tpnt->new_partition = 0;
+	tpnt->nbr_partitions = 0;
+	tpnt->device->timeout = ST_TIMEOUT;
+	tpnt->long_timeout = ST_LONG_TIMEOUT;
+	tpnt->try_dio = try_direct_io && !SDp->host->unchecked_isa_dma;
+
+	bounce_limit = scsi_calculate_bounce_limit(SDp->host) >> PAGE_SHIFT;
+	if (bounce_limit > ULONG_MAX)
+		bounce_limit = ULONG_MAX;
+	tpnt->max_pfn = bounce_limit;
+
+	for (i = 0; i < ST_NBR_MODES; i++) {
+		STm = &(tpnt->modes[i]);
+		STm->defined = 0;
+		STm->sysv = ST_SYSV;
+		STm->defaults_for_writes = 0;
+		STm->do_async_writes = ST_ASYNC_WRITES;
+		STm->do_buffer_writes = ST_BUFFER_WRITES;
+		STm->do_read_ahead = ST_READ_AHEAD;
+		STm->default_compression = ST_DONT_TOUCH;
+		STm->default_blksize = (-1);	/* No forced size */
+		STm->default_density = (-1);	/* No forced density */
+	}
+
+	for (i = 0; i < ST_NBR_PARTITIONS; i++) {
+		STps = &(tpnt->ps[i]);
+		STps->rw = ST_IDLE;
+		STps->eof = ST_NOEOF;
+		STps->at_sm = 0;
+		STps->last_block_valid = 0;
+		STps->drv_block = (-1);
+		STps->drv_file = (-1);
+	}
+
+	tpnt->current_mode = 0;
+	tpnt->modes[0].defined = 1;
+
+	tpnt->density_changed = tpnt->compression_changed =
+	    tpnt->blksize_changed = 0;
+	init_MUTEX(&tpnt->lock);
+
+	st_nr_dev++;
+	write_unlock(&st_dev_arr_lock);
+
+	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+		STm = &(tpnt->modes[mode]);
+		for (j=0; j < 2; j++) {
+			cdev = cdev_alloc();
+			if (!cdev) {
+				printk(KERN_ERR
+				       "st%d: out of memory. Device not attached.\n",
+				       dev_num);
+				goto out_free_tape;
+			}
+			cdev->owner = THIS_MODULE;
+			cdev->ops = &st_fops;
+
+			error = cdev_add(cdev,
+					 MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, j)),
+					 1);
+			if (error) {
+				printk(KERN_ERR "st%d: Can't add %s-rewind mode %d\n",
+				       dev_num, j ? "non" : "auto", mode);
+				printk(KERN_ERR "st%d: Device not attached.\n", dev_num);
+				goto out_free_tape;
+			}
+			STm->cdevs[j] = cdev;
+
+		}
+		do_create_class_files(tpnt, dev_num, mode);
+	}
+
+	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+		/* Make sure that the minor numbers corresponding to the four
+		   first modes always get the same names */
+		i = mode << (4 - ST_NBR_MODE_BITS);
+		/*  Rewind entry  */
+		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 0)),
+			      S_IFCHR | S_IRUGO | S_IWUGO,
+			      "%s/mt%s", SDp->devfs_name, st_formats[i]);
+		/*  No-rewind entry  */
+		devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, TAPE_MINOR(dev_num, mode, 1)),
+			      S_IFCHR | S_IRUGO | S_IWUGO,
+			      "%s/mt%sn", SDp->devfs_name, st_formats[i]);
+	}
+	disk->number = devfs_register_tape(SDp->devfs_name);
+
+	printk(KERN_WARNING
+	"Attached scsi tape %s at scsi%d, channel %d, id %d, lun %d\n",
+	       tape_name(tpnt), SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+	printk(KERN_WARNING "%s: try direct i/o: %s (alignment %d B), max page reachable by HBA %lu\n",
+	       tape_name(tpnt), tpnt->try_dio ? "yes" : "no",
+	       queue_dma_alignment(SDp->request_queue) + 1, tpnt->max_pfn);
+
+	return 0;
+
+out_free_tape:
+	for (mode=0; mode < ST_NBR_MODES; mode++) {
+		STm = &(tpnt->modes[mode]);
+		sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
+				  "tape");
+		for (j=0; j < 2; j++) {
+			if (STm->cdevs[j]) {
+				if (cdev == STm->cdevs[j])
+					cdev = NULL;
+				class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
+								 TAPE_MINOR(i, mode, j)));
+				cdev_del(STm->cdevs[j]);
+			}
+		}
+	}
+	if (cdev)
+		cdev_del(cdev);
+	write_lock(&st_dev_arr_lock);
+	scsi_tapes[dev_num] = NULL;
+	st_nr_dev--;
+	write_unlock(&st_dev_arr_lock);
+out_put_disk:
+	put_disk(disk);
+	if (tpnt)
+		kfree(tpnt);
+out_buffer_free:
+	kfree(buffer);
+out:
+	return -ENODEV;
+};
+
+
+static int st_remove(struct device *dev)
+{
+	struct scsi_device *SDp = to_scsi_device(dev);
+	struct scsi_tape *tpnt;
+	int i, j, mode;
+
+	write_lock(&st_dev_arr_lock);
+	for (i = 0; i < st_dev_max; i++) {
+		tpnt = scsi_tapes[i];
+		if (tpnt != NULL && tpnt->device == SDp) {
+			scsi_tapes[i] = NULL;
+			st_nr_dev--;
+			write_unlock(&st_dev_arr_lock);
+			devfs_unregister_tape(tpnt->disk->number);
+			sysfs_remove_link(&tpnt->device->sdev_gendev.kobj,
+					  "tape");
+			for (mode = 0; mode < ST_NBR_MODES; ++mode) {
+				j = mode << (4 - ST_NBR_MODE_BITS);
+				devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[j]);
+				devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[j]);
+				for (j=0; j < 2; j++) {
+					class_simple_device_remove(MKDEV(SCSI_TAPE_MAJOR,
+									 TAPE_MINOR(i, mode, j)));
+					cdev_del(tpnt->modes[mode].cdevs[j]);
+					tpnt->modes[mode].cdevs[j] = NULL;
+				}
+			}
+			tpnt->device = NULL;
+
+			if (tpnt->buffer) {
+				tpnt->buffer->orig_frp_segs = 0;
+				normalize_buffer(tpnt->buffer);
+				kfree(tpnt->buffer);
+			}
+			put_disk(tpnt->disk);
+			kfree(tpnt);
+			return 0;
+		}
+	}
+
+	write_unlock(&st_dev_arr_lock);
+	return 0;
+}
+
+static void st_intr(struct scsi_cmnd *SCpnt)
+{
+	scsi_io_completion(SCpnt, (SCpnt->result ? 0: SCpnt->bufflen), 1);
+}
+
+/*
+ * st_init_command: only called via the scsi_cmd_ioctl (block SG_IO)
+ * interface for REQ_BLOCK_PC commands.
+ */
+static int st_init_command(struct scsi_cmnd *SCpnt)
+{
+	struct request *rq;
+
+	if (!(SCpnt->request->flags & REQ_BLOCK_PC))
+		return 0;
+
+	rq = SCpnt->request;
+	if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))
+		return 0;
+
+	memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));
+
+	if (rq_data_dir(rq) == WRITE)
+		SCpnt->sc_data_direction = DMA_TO_DEVICE;
+	else if (rq->data_len)
+		SCpnt->sc_data_direction = DMA_FROM_DEVICE;
+	else
+		SCpnt->sc_data_direction = DMA_NONE;
+
+	SCpnt->timeout_per_command = rq->timeout;
+	SCpnt->transfersize = rq->data_len;
+	SCpnt->done = st_intr;
+	return 1;
+}
+
+static int __init init_st(void)
+{
+	validate_options();
+
+	printk(KERN_INFO
+		"st: Version %s, fixed bufsize %d, s/g segs %d\n",
+		verstr, st_fixed_buffer_size, st_max_sg_segs);
+
+	st_sysfs_class = class_simple_create(THIS_MODULE, "scsi_tape");
+	if (IS_ERR(st_sysfs_class)) {
+		st_sysfs_class = NULL;
+		printk(KERN_ERR "Unable create sysfs class for SCSI tapes\n");
+		return 1;
+	}
+
+	if (!register_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+				    ST_MAX_TAPE_ENTRIES, "st")) {
+		if (scsi_register_driver(&st_template.gendrv) == 0) {
+			do_create_driverfs_files();
+			return 0;
+		}
+		if (st_sysfs_class)
+			class_simple_destroy(st_sysfs_class);		
+		unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+
+					 ST_MAX_TAPE_ENTRIES);
+	}
+
+	printk(KERN_ERR "Unable to get major %d for SCSI tapes\n", SCSI_TAPE_MAJOR);
+	return 1;
+}
+
+static void __exit exit_st(void)
+{
+	if (st_sysfs_class)
+		class_simple_destroy(st_sysfs_class);
+	st_sysfs_class = NULL;
+	do_remove_driverfs_files();
+	scsi_unregister_driver(&st_template.gendrv);
+	unregister_chrdev_region(MKDEV(SCSI_TAPE_MAJOR, 0),
+				 ST_MAX_TAPE_ENTRIES);
+	kfree(scsi_tapes);
+	printk(KERN_INFO "st: Unloaded.\n");
+}
+
+module_init(init_st);
+module_exit(exit_st);
+
+
+/* The sysfs driver interface. Read-only at the moment */
+static ssize_t st_try_direct_io_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", try_direct_io);
+}
+static DRIVER_ATTR(try_direct_io, S_IRUGO, st_try_direct_io_show, NULL);
+
+static ssize_t st_fixed_buffer_size_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", st_fixed_buffer_size);
+}
+static DRIVER_ATTR(fixed_buffer_size, S_IRUGO, st_fixed_buffer_size_show, NULL);
+
+static ssize_t st_max_sg_segs_show(struct device_driver *ddp, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "%d\n", st_max_sg_segs);
+}
+static DRIVER_ATTR(max_sg_segs, S_IRUGO, st_max_sg_segs_show, NULL);
+
+static ssize_t st_version_show(struct device_driver *ddd, char *buf)
+{
+	return snprintf(buf, PAGE_SIZE, "[%s]\n", verstr);
+}
+static DRIVER_ATTR(version, S_IRUGO, st_version_show, NULL);
+
+static void do_create_driverfs_files(void)
+{
+	struct device_driver *driverfs = &st_template.gendrv;
+
+	driver_create_file(driverfs, &driver_attr_try_direct_io);
+	driver_create_file(driverfs, &driver_attr_fixed_buffer_size);
+	driver_create_file(driverfs, &driver_attr_max_sg_segs);
+	driver_create_file(driverfs, &driver_attr_version);
+}
+
+static void do_remove_driverfs_files(void)
+{
+	struct device_driver *driverfs = &st_template.gendrv;
+
+	driver_remove_file(driverfs, &driver_attr_version);
+	driver_remove_file(driverfs, &driver_attr_max_sg_segs);
+	driver_remove_file(driverfs, &driver_attr_fixed_buffer_size);
+	driver_remove_file(driverfs, &driver_attr_try_direct_io);
+}
+
+
+/* The sysfs simple class interface */
+static ssize_t st_defined_show(struct class_device *class_dev, char *buf)
+{
+	struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+	ssize_t l = 0;
+
+	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->defined);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(defined, S_IRUGO, st_defined_show, NULL);
+
+static ssize_t st_defblk_show(struct class_device *class_dev, char *buf)
+{
+	struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+	ssize_t l = 0;
+
+	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_blksize);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(default_blksize, S_IRUGO, st_defblk_show, NULL);
+
+static ssize_t st_defdensity_show(struct class_device *class_dev, char *buf)
+{
+	struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+	ssize_t l = 0;
+	char *fmt;
+
+	fmt = STm->default_density >= 0 ? "0x%02x\n" : "%d\n";
+	l = snprintf(buf, PAGE_SIZE, fmt, STm->default_density);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(default_density, S_IRUGO, st_defdensity_show, NULL);
+
+static ssize_t st_defcompression_show(struct class_device *class_dev, char *buf)
+{
+	struct st_modedef *STm = (struct st_modedef *)class_get_devdata(class_dev);
+	ssize_t l = 0;
+
+	l = snprintf(buf, PAGE_SIZE, "%d\n", STm->default_compression - 1);
+	return l;
+}
+
+CLASS_DEVICE_ATTR(default_compression, S_IRUGO, st_defcompression_show, NULL);
+
+static void do_create_class_files(struct scsi_tape *STp, int dev_num, int mode)
+{
+	int i, rew, error;
+	char name[10];
+	struct class_device *st_class_member;
+
+	if (!st_sysfs_class)
+		return;
+
+	for (rew=0; rew < 2; rew++) {
+		/* Make sure that the minor numbers corresponding to the four
+		   first modes always get the same names */
+		i = mode << (4 - ST_NBR_MODE_BITS);
+		snprintf(name, 10, "%s%s%s", rew ? "n" : "",
+			 STp->disk->disk_name, st_formats[i]);
+		st_class_member =
+			class_simple_device_add(st_sysfs_class,
+						MKDEV(SCSI_TAPE_MAJOR,
+						      TAPE_MINOR(dev_num, mode, rew)),
+						&STp->device->sdev_gendev, "%s", name);
+		if (IS_ERR(st_class_member)) {
+			printk(KERN_WARNING "st%d: class_simple_device_add failed\n",
+			       dev_num);
+			goto out;
+		}
+		class_set_devdata(st_class_member, &STp->modes[mode]);
+
+		class_device_create_file(st_class_member,
+					 &class_device_attr_defined);
+		class_device_create_file(st_class_member,
+					 &class_device_attr_default_blksize);
+		class_device_create_file(st_class_member,
+					 &class_device_attr_default_density);
+		class_device_create_file(st_class_member,
+					 &class_device_attr_default_compression);
+		if (mode == 0 && rew == 0) {
+			error = sysfs_create_link(&STp->device->sdev_gendev.kobj,
+						  &st_class_member->kobj,
+						  "tape");
+			if (error) {
+				printk(KERN_ERR
+				       "st%d: Can't create sysfs link from SCSI device.\n",
+				       dev_num);
+			}
+		}
+	}
+ out:
+	return;
+}
+
+
+/* Pin down user pages and put them into a scatter gather list. Returns <= 0 if
+   - mapping of all pages not successful
+   - any page is above max_pfn
+   (i.e., either completely successful or fails)
+*/
+static int st_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+			     unsigned long uaddr, size_t count, int rw,
+			     unsigned long max_pfn)
+{
+	int i, nr_pages;
+
+	nr_pages = sgl_map_user_pages(sgl, max_pages, uaddr, count, rw);
+	if (nr_pages <= 0)
+		return nr_pages;
+
+	for (i=0; i < nr_pages; i++) {
+		if (page_to_pfn(sgl[i].page) > max_pfn)
+			goto out_unmap;
+	}
+	return nr_pages;
+
+ out_unmap:
+	sgl_unmap_user_pages(sgl, nr_pages, 0);
+	return 0;
+}
+
+
+/* The following functions may be useful for a larger audience. */
+static int sgl_map_user_pages(struct scatterlist *sgl, const unsigned int max_pages, 
+			      unsigned long uaddr, size_t count, int rw)
+{
+	int res, i, j;
+	unsigned int nr_pages;
+	struct page **pages;
+
+	nr_pages = ((uaddr & ~PAGE_MASK) + count + ~PAGE_MASK) >> PAGE_SHIFT;
+
+	/* User attempted Overflow! */
+	if ((uaddr + count) < uaddr)
+		return -EINVAL;
+
+	/* Too big */
+        if (nr_pages > max_pages)
+		return -ENOMEM;
+
+	/* Hmm? */
+	if (count == 0)
+		return 0;
+
+	if ((pages = kmalloc(max_pages * sizeof(*pages), GFP_KERNEL)) == NULL)
+		return -ENOMEM;
+
+        /* Try to fault in all of the necessary pages */
+	down_read(&current->mm->mmap_sem);
+        /* rw==READ means read from drive, write into memory area */
+	res = get_user_pages(
+		current,
+		current->mm,
+		uaddr,
+		nr_pages,
+		rw == READ,
+		0, /* don't force */
+		pages,
+		NULL);
+	up_read(&current->mm->mmap_sem);
+
+	/* Errors and no page mapped should return here */
+	if (res < nr_pages)
+		goto out_unmap;
+
+        for (i=0; i < nr_pages; i++) {
+                /* FIXME: flush superflous for rw==READ,
+                 * probably wrong function for rw==WRITE
+                 */
+		flush_dcache_page(pages[i]);
+        }
+
+	/* Populate the scatter/gather list */
+	sgl[0].page = pages[0]; 
+	sgl[0].offset = uaddr & ~PAGE_MASK;
+	if (nr_pages > 1) {
+		sgl[0].length = PAGE_SIZE - sgl[0].offset;
+		count -= sgl[0].length;
+		for (i=1; i < nr_pages ; i++) {
+			sgl[i].offset = 0;
+			sgl[i].page = pages[i]; 
+			sgl[i].length = count < PAGE_SIZE ? count : PAGE_SIZE;
+			count -= PAGE_SIZE;
+		}
+	}
+	else {
+		sgl[0].length = count;
+	}
+
+	kfree(pages);
+	return nr_pages;
+
+ out_unmap:
+	if (res > 0) {
+		for (j=0; j < res; j++)
+			page_cache_release(pages[j]);
+	}
+	kfree(pages);
+	return res;
+}
+
+
+/* And unmap them... */
+static int sgl_unmap_user_pages(struct scatterlist *sgl, const unsigned int nr_pages,
+				int dirtied)
+{
+	int i;
+
+	for (i=0; i < nr_pages; i++) {
+		if (dirtied && !PageReserved(sgl[i].page))
+			SetPageDirty(sgl[i].page);
+		/* FIXME: cache flush missing for rw==READ
+		 * FIXME: call the correct reference counting function
+		 */
+		page_cache_release(sgl[i].page);
+	}
+
+	return 0;
+}
diff --git a/drivers/scsi/st.h b/drivers/scsi/st.h
new file mode 100644
index 0000000..061da11
--- /dev/null
+++ b/drivers/scsi/st.h
@@ -0,0 +1,212 @@
+
+#ifndef _ST_H
+#define _ST_H
+
+#include <linux/completion.h>
+
+
+/* Descriptor for analyzed sense data */
+struct st_cmdstatus {
+	int midlevel_result;
+	struct scsi_sense_hdr sense_hdr;
+	int have_sense;
+	u64 uremainder64;
+	u8 flags;
+	u8 remainder_valid;
+	u8 fixed_format;
+	u8 deferred;
+};
+
+/* The tape buffer descriptor. */
+struct st_buffer {
+	unsigned char in_use;
+	unsigned char dma;	/* DMA-able buffer */
+	unsigned char do_dio;   /* direct i/o set up? */
+	int buffer_size;
+	int buffer_blocks;
+	int buffer_bytes;
+	int read_pointer;
+	int writing;
+	int syscall_result;
+	struct scsi_request *last_SRpnt;
+	struct st_cmdstatus cmdstat;
+	unsigned char *b_data;
+	unsigned short use_sg;	/* zero or max number of s/g segments for this adapter */
+	unsigned short sg_segs;		/* number of segments in s/g list */
+	unsigned short orig_frp_segs;	/* number of segments allocated at first try */
+	unsigned short frp_segs;	/* number of buffer segments */
+	unsigned int frp_sg_current;	/* driver buffer length currently in s/g list */
+	struct st_buf_fragment *frp;	/* the allocated buffer fragment list */
+	struct scatterlist sg[1];	/* MUST BE last item */
+};
+
+/* The tape buffer fragment descriptor */
+struct st_buf_fragment {
+	struct page *page;
+	unsigned int length;
+};
+
+/* The tape mode definition */
+struct st_modedef {
+	unsigned char defined;
+	unsigned char sysv;	/* SYS V semantics? */
+	unsigned char do_async_writes;
+	unsigned char do_buffer_writes;
+	unsigned char do_read_ahead;
+	unsigned char defaults_for_writes;
+	unsigned char default_compression;	/* 0 = don't touch, etc */
+	short default_density;	/* Forced density, -1 = no value */
+	int default_blksize;	/* Forced blocksize, -1 = no value */
+	struct cdev *cdevs[2];  /* Auto-rewind and non-rewind devices */
+};
+
+/* Number of modes can be changed by changing ST_NBR_MODE_BITS. The maximum
+   number of modes is 16 (ST_NBR_MODE_BITS 4) */
+#define ST_NBR_MODE_BITS 2
+#define ST_NBR_MODES (1 << ST_NBR_MODE_BITS)
+#define ST_MODE_SHIFT (7 - ST_NBR_MODE_BITS)
+#define ST_MODE_MASK ((ST_NBR_MODES - 1) << ST_MODE_SHIFT)
+
+#define ST_MAX_TAPES 128
+#define ST_MAX_TAPE_ENTRIES  (ST_MAX_TAPES << (ST_NBR_MODE_BITS + 1))
+
+/* The status related to each partition */
+struct st_partstat {
+	unsigned char rw;
+	unsigned char eof;
+	unsigned char at_sm;
+	unsigned char last_block_valid;
+	u32 last_block_visited;
+	int drv_block;		/* The block where the drive head is */
+	int drv_file;
+};
+
+#define ST_NBR_PARTITIONS 4
+
+/* The tape drive descriptor */
+struct scsi_tape {
+	struct scsi_driver *driver;
+	struct scsi_device *device;
+	struct semaphore lock;	/* For serialization */
+	struct completion wait;	/* For SCSI commands */
+	struct st_buffer *buffer;
+
+	/* Drive characteristics */
+	unsigned char omit_blklims;
+	unsigned char do_auto_lock;
+	unsigned char can_bsr;
+	unsigned char can_partitions;
+	unsigned char two_fm;
+	unsigned char fast_mteom;
+	unsigned char immediate;
+	unsigned char restr_dma;
+	unsigned char scsi2_logical;
+	unsigned char default_drvbuffer;	/* 0xff = don't touch, value 3 bits */
+	unsigned char cln_mode;			/* 0 = none, otherwise sense byte nbr */
+	unsigned char cln_sense_value;
+	unsigned char cln_sense_mask;
+	unsigned char use_pf;			/* Set Page Format bit in all mode selects? */
+	unsigned char try_dio;			/* try direct i/o? */
+	unsigned char c_algo;			/* compression algorithm */
+	unsigned char pos_unknown;			/* after reset position unknown */
+	int tape_type;
+	int long_timeout;	/* timeout for commands known to take long time */
+
+	unsigned long max_pfn;	/* the maximum page number reachable by the HBA */
+
+	/* Mode characteristics */
+	struct st_modedef modes[ST_NBR_MODES];
+	int current_mode;
+
+	/* Status variables */
+	int partition;
+	int new_partition;
+	int nbr_partitions;	/* zero until partition support enabled */
+	struct st_partstat ps[ST_NBR_PARTITIONS];
+	unsigned char dirty;
+	unsigned char ready;
+	unsigned char write_prot;
+	unsigned char drv_write_prot;
+	unsigned char in_use;
+	unsigned char blksize_changed;
+	unsigned char density_changed;
+	unsigned char compression_changed;
+	unsigned char drv_buffer;
+	unsigned char density;
+	unsigned char door_locked;
+	unsigned char autorew_dev;   /* auto-rewind device */
+	unsigned char rew_at_close;  /* rewind necessary at close */
+	unsigned char inited;
+	unsigned char cleaning_req;  /* cleaning requested? */
+	int block_size;
+	int min_block;
+	int max_block;
+	int recover_count;     /* From tape opening */
+	int recover_reg;       /* From last status call */
+
+#if DEBUG
+	unsigned char write_pending;
+	int nbr_finished;
+	int nbr_waits;
+	int nbr_requests;
+	int nbr_dio;
+	int nbr_pages;
+	int nbr_combinable;
+	unsigned char last_cmnd[6];
+	unsigned char last_sense[16];
+#endif
+	struct gendisk *disk;
+};
+
+/* Bit masks for use_pf */
+#define USE_PF      1
+#define PF_TESTED   2
+
+/* Values of eof */
+#define	ST_NOEOF	0
+#define ST_FM_HIT       1
+#define ST_FM           2
+#define ST_EOM_OK       3
+#define ST_EOM_ERROR	4
+#define	ST_EOD_1        5
+#define ST_EOD_2        6
+#define ST_EOD		7
+/* EOD hit while reading => ST_EOD_1 => return zero => ST_EOD_2 =>
+   return zero => ST_EOD, return ENOSPC */
+/* When writing: ST_EOM_OK == early warning found, write OK
+		 ST_EOD_1  == allow trying new write after early warning
+		 ST_EOM_ERROR == early warning found, not able to write all */
+
+/* Values of rw */
+#define	ST_IDLE		0
+#define	ST_READING	1
+#define	ST_WRITING	2
+
+/* Values of ready state */
+#define ST_READY	0
+#define ST_NOT_READY	1
+#define ST_NO_TAPE	2
+
+/* Values for door lock state */
+#define ST_UNLOCKED	0
+#define ST_LOCKED_EXPLICIT 1
+#define ST_LOCKED_AUTO  2
+#define ST_LOCK_FAILS   3
+
+/* Positioning SCSI-commands for Tandberg, etc. drives */
+#define	QFA_REQUEST_BLOCK	0x02
+#define	QFA_SEEK_BLOCK		0x0c
+
+/* Setting the binary options */
+#define ST_DONT_TOUCH  0
+#define ST_NO          1
+#define ST_YES         2
+
+#define EXTENDED_SENSE_START  18
+
+/* Masks for some conditions in the sense data */
+#define SENSE_FMK   0x80
+#define SENSE_EOM   0x40
+#define SENSE_ILI   0x20
+
+#endif
diff --git a/drivers/scsi/st_options.h b/drivers/scsi/st_options.h
new file mode 100644
index 0000000..b6b5c9c
--- /dev/null
+++ b/drivers/scsi/st_options.h
@@ -0,0 +1,100 @@
+/*
+   The compile-time configurable defaults for the Linux SCSI tape driver.
+
+   Copyright 1995-2003 Kai Makisara.
+
+   Last modified: Mon Apr  7 22:49:18 2003 by makisara
+*/
+
+#ifndef _ST_OPTIONS_H
+#define _ST_OPTIONS_H
+
+/* If TRY_DIRECT_IO is non-zero, the driver tries to transfer data directly
+   between the user buffer and tape drive. If this is not possible, driver
+   buffer is used. If TRY_DIRECT_IO is zero, driver buffer is always used. */
+#define TRY_DIRECT_IO 1
+
+/* The driver does not wait for some operations to finish before returning
+   to the user program if ST_NOWAIT is non-zero. This helps if the SCSI
+   adapter does not support multiple outstanding commands. However, the user
+   should not give a new tape command before the previous one has finished. */
+#define ST_NOWAIT 0
+
+/* If ST_IN_FILE_POS is nonzero, the driver positions the tape after the
+   record been read by the user program even if the tape has moved further
+   because of buffered reads. Should be set to zero to support also drives
+   that can't space backwards over records. NOTE: The tape will be
+   spaced backwards over an "accidentally" crossed filemark in any case. */
+#define ST_IN_FILE_POS 0
+
+/* If ST_RECOVERED_WRITE_FATAL is non-zero, recovered errors while writing
+   are considered "hard errors". */
+#define ST_RECOVERED_WRITE_FATAL 0
+
+/* The "guess" for the block size for devices that don't support MODE
+   SENSE. */
+#define ST_DEFAULT_BLOCK 0
+
+/* The minimum tape driver buffer size in kilobytes in fixed block mode.
+   Must be non-zero. */
+#define ST_FIXED_BUFFER_BLOCKS 32
+
+/* Maximum number of scatter/gather segments */
+#define ST_MAX_SG      256
+
+/* The number of scatter/gather segments to allocate at first try (must be
+   smaller or equal to the maximum). */
+#define ST_FIRST_SG    8
+
+/* The size of the first scatter/gather segments (determines the maximum block
+   size for SCSI adapters not supporting scatter/gather). The default is set
+   to try to allocate the buffer as one chunk. */
+#define ST_FIRST_ORDER  5
+
+
+/* The following lines define defaults for properties that can be set
+   separately for each drive using the MTSTOPTIONS ioctl. */
+
+/* If ST_TWO_FM is non-zero, the driver writes two filemarks after a
+   file being written. Some drives can't handle two filemarks at the
+   end of data. */
+#define ST_TWO_FM 0
+
+/* If ST_BUFFER_WRITES is non-zero, writes in fixed block mode are
+   buffered until the driver buffer is full or asynchronous write is
+   triggered. May make detection of End-Of-Medium early enough fail. */
+#define ST_BUFFER_WRITES 1
+
+/* If ST_ASYNC_WRITES is non-zero, the SCSI write command may be started
+   without waiting for it to finish. May cause problems in multiple
+   tape backups. */
+#define ST_ASYNC_WRITES 1
+
+/* If ST_READ_AHEAD is non-zero, blocks are read ahead in fixed block
+   mode. */
+#define ST_READ_AHEAD 1
+
+/* If ST_AUTO_LOCK is non-zero, the drive door is locked at the first
+   read or write command after the device is opened. The door is opened
+   when the device is closed. */
+#define ST_AUTO_LOCK 0
+
+/* If ST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the
+   direct SCSI command. The file number status is lost but this method
+   is fast with some drives. Otherwise MTEOM is done by spacing over
+   files and the file number status is retained. */
+#define ST_FAST_MTEOM 0
+
+/* If ST_SCSI2LOGICAL is nonzero, the logical block addresses are used for
+   MTIOCPOS and MTSEEK by default. Vendor addresses are used if ST_SCSI2LOGICAL
+   is zero. */
+#define ST_SCSI2LOGICAL 0
+
+/* If ST_SYSV is non-zero, the tape behaves according to the SYS V semantics.
+   The default is BSD semantics. */
+#define ST_SYSV 0
+
+/* Time to wait for the drive to become ready if blocking open */
+#define ST_BLOCK_SECONDS     120
+
+#endif
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
new file mode 100644
index 0000000..9081139
--- /dev/null
+++ b/drivers/scsi/sun3_NCR5380.c
@@ -0,0 +1,3009 @@
+/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by 
+   Sam Creasey. */ 
+/* 
+ * NCR 5380 generic driver routines.  These should make it *trivial*
+ * 	to implement 5380 SCSI drivers under Linux with a non-trantor
+ *	architecture.
+ *
+ *	Note that these routines also work with NR53c400 family chips.
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing 
+ *	(Unix and Linux consulting and custom programming)
+ * 	drew@colorado.edu
+ *	+1 (303) 666-5836
+ *
+ * DISTRIBUTION RELEASE 6. 
+ *
+ * For more information, please consult 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
+ * this file, too:
+ *
+ *  - Some of the debug statements were incorrect (undefined variables and the
+ *    like). I fixed that.
+ *
+ *  - In information_transfer(), I think a #ifdef was wrong. Looking at the
+ *    possible DMA transfer size should also happen for REAL_DMA. I added this
+ *    in the #if statement.
+ *
+ *  - When using real DMA, information_transfer() should return in a DATAOUT
+ *    phase after starting the DMA. It has nothing more to do.
+ *
+ *  - The interrupt service routine should run main after end of DMA, too (not
+ *    only after RESELECTION interrupts). Additionally, it should _not_ test
+ *    for more interrupts after running main, since a DMA process may have
+ *    been started and interrupts are turned on now. The new int could happen
+ *    inside the execution of NCR5380_intr(), leading to recursive
+ *    calls.
+ *
+ *  - I've added a function merge_contiguous_buffers() that tries to
+ *    merge scatter-gather buffers that are located at contiguous
+ *    physical addresses and can be processed with the same DMA setup.
+ *    Since most scatter-gather operations work on a page (4K) of
+ *    4 buffers (1K), in more than 90% of all cases three interrupts and
+ *    DMA setup actions are saved.
+ *
+ * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
+ *    and USLEEP, because these were messing up readability and will never be
+ *    needed for Atari SCSI.
+ * 
+ * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
+ *   stuff), and 'main' is executed in a bottom half if awoken by an
+ *   interrupt.
+ *
+ * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
+ *   constructs. In my eyes, this made the source rather unreadable, so I
+ *   finally replaced that by the *_PRINTK() macros.
+ *
+ */
+
+/*
+ * Further development / testing that should be done : 
+ * 1.  Test linked command handling code after Eric is ready with 
+ *     the high level code.
+ */
+
+#if (NDEBUG & NDEBUG_LISTS)
+#define LIST(x,y) \
+  { printk("LINE:%d   Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
+    if ((x)==(y)) udelay(5); }
+#define REMOVE(w,x,y,z) \
+  { printk("LINE:%d   Removing: %p->%p  %p->%p \n", __LINE__, \
+	   (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
+    if ((x)==(y)) udelay(5); }
+#else
+#define LIST(x,y)
+#define REMOVE(w,x,y,z)
+#endif
+
+#ifndef notyet
+#undef LINKED
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip.  This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queuing
+ * routines were implemented, meaning their implementations of queued 
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that 
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what 
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver.  To use it on a different platform, 
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use 
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for 
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing.  This means that an 
+ * unlimited number of commands may be queued, letting 
+ * more commands propagate from the higher driver levels giving higher 
+ * throughput.  Note that both I_T_L and I_T_L_Q nexuses are supported, 
+ * allowing multiple commands to propagate all the way to a SCSI-II device 
+ * while a command is already executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem, 
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system.  So, multiple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.  
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the 
+ * NCR5380_print_options command, which should be called from the 
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 : 
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead 
+ * piece of hardware that requires you to sit in a loop polling for 
+ * the REQ signal as long as you are connected.  Some devices are 
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect 
+ * while doing long seek operations.
+ * 
+ * The workaround for this is to keep track of devices that have
+ * disconnected.  If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like 
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ * 
+ * Some tweaking of N and M needs to be done.  An algorithm based 
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these 
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optimizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a coroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function.  It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the 
+ * issue queue and calling NCR5380_select() if a nexus 
+ * is not established. 
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work.  If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr()  which will in turn call NCR5380_reselect
+ * to reestablish a nexus.  This will run main if necessary.
+ *
+ * On command termination, the done function will be called as 
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command 
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips.  To use it, you write an architecture specific functions 
+ * and macros and include this file in your driver.
+ *
+ * These macros control options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *	for commands that return with a CHECK CONDITION status. 
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
+ *
+ * These macros MUST be defined :
+ * 
+ * NCR5380_read(register)  - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register 
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions : 
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * Note that the DMA setup functions should return the number of bytes 
+ *	that they were able to program the controller for.
+ *
+ * Also note that generic i386/PC versions of these macros are 
+ *	available as NCR5380_i386_dma_write_setup,
+ *	NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
+ *
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(instance); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define 
+ *  
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ * NCR5380_proc_info
+ *
+ * to be the global entry points into the specific driver, ie 
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessible wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID.  If the 
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used.  Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/* Macros ease life... :-) */
+#define	SETUP_HOSTDATA(in)				\
+    struct NCR5380_hostdata *hostdata =			\
+	(struct NCR5380_hostdata *)(in)->hostdata
+#define	HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
+
+#define	NEXT(cmd)	((Scsi_Cmnd *)((cmd)->host_scribble))
+#define	NEXTADDR(cmd)	((Scsi_Cmnd **)&((cmd)->host_scribble))
+
+#define	HOSTNO		instance->host_no
+#define	H_NO(cmd)	(cmd)->device->host->host_no
+
+#define SGADDR(buffer) (void *)(((unsigned long)page_address((buffer)->page)) + \
+			(buffer)->offset)
+
+#ifdef SUPPORT_TAGS
+
+/*
+ * Functions for handling tagged queuing
+ * =====================================
+ *
+ * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
+ *
+ * Using consecutive numbers for the tags is no good idea in my eyes. There
+ * could be wrong re-usings if the counter (8 bit!) wraps and some early
+ * command has been preempted for a long time. My solution: a bitfield for
+ * remembering used tags.
+ *
+ * There's also the problem that each target has a certain queue size, but we
+ * cannot know it in advance :-( We just see a QUEUE_FULL status being
+ * returned. So, in this case, the driver internal queue size assumption is
+ * reduced to the number of active tags if QUEUE_FULL is returned by the
+ * target. The command is returned to the mid-level, but with status changed
+ * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
+ * correctly.
+ *
+ * We're also not allowed running tagged commands as long as an untagged
+ * command is active. And REQUEST SENSE commands after a contingent allegiance
+ * condition _must_ be untagged. To keep track whether an untagged command has
+ * been issued, the host->busy array is still employed, as it is without
+ * support for tagged queuing.
+ *
+ * One could suspect that there are possible race conditions between
+ * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
+ * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
+ * which already guaranteed to be running at most once. It is also the only
+ * place where tags/LUNs are allocated. So no other allocation can slip
+ * between that pair, there could only happen a reselection, which can free a
+ * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
+ * important: the tag bit must be cleared before 'nr_allocated' is decreased.
+ */
+
+/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
+#undef TAG_NONE
+#define TAG_NONE 0xff
+
+/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
+#if (MAX_TAGS % 32) != 0
+#error "MAX_TAGS must be a multiple of 32!"
+#endif
+
+typedef struct {
+    char	allocated[MAX_TAGS/8];
+    int		nr_allocated;
+    int		queue_size;
+} TAG_ALLOC;
+
+static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+
+
+static void __init init_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+    
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	    /* At the beginning, assume the maximum queue size we could
+	     * support (MAX_TAGS). This value will be decreased if the target
+	     * returns QUEUE_FULL status.
+	     */
+	    ta->queue_size = MAX_TAGS;
+	}
+    }
+}
+
+
+/* Check if we can issue a command to this LUN: First see if the LUN is marked
+ * busy by an untagged command. If the command should use tagged queuing, also
+ * check that there is a free tag and the target's queue won't overflow. This
+ * function should be called with interrupts disabled to avoid race
+ * conditions.
+ */ 
+
+static int is_lun_busy( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    if (hostdata->busy[cmd->device->id] & (1 << cmd->device->lun))
+	return( 1 );
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported)
+	return( 0 );
+    if (TagAlloc[cmd->device->id][cmd->device->lun].nr_allocated >=
+	TagAlloc[cmd->device->id][cmd->device->lun].queue_size ) {
+	TAG_PRINTK( "scsi%d: target %d lun %d: no free tags\n",
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
+	return( 1 );
+    }
+    return( 0 );
+}
+
+
+/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
+ * must be called before!), or reserve the LUN in 'busy' if the command is
+ * untagged.
+ */
+
+static void cmd_get_tag( Scsi_Cmnd *cmd, int should_be_tagged )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    /* If we or the target don't support tagged queuing, allocate the LUN for
+     * an untagged command.
+     */
+    if (!should_be_tagged ||
+	!setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+	cmd->tag = TAG_NONE;
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d now allocated by untagged "
+		    "command\n", H_NO(cmd), cmd->device->id, cmd->device->lun );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+
+	cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
+	set_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated++;
+	TAG_PRINTK( "scsi%d: using tag %d for target %d lun %d "
+		    "(now %d tags in use)\n",
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun,
+		    ta->nr_allocated );
+    }
+}
+
+
+/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
+ * unlock the LUN.
+ */
+
+static void cmd_free_tag( Scsi_Cmnd *cmd )
+{
+    SETUP_HOSTDATA(cmd->device->host);
+
+    if (cmd->tag == TAG_NONE) {
+	hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+	TAG_PRINTK( "scsi%d: target %d lun %d untagged cmd finished\n",
+		    H_NO(cmd), cmd->device->id, cmd->device->lun );
+    }
+    else if (cmd->tag >= MAX_TAGS) {
+	printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
+		H_NO(cmd), cmd->tag );
+    }
+    else {
+	TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+	clear_bit( cmd->tag, &ta->allocated );
+	ta->nr_allocated--;
+	TAG_PRINTK( "scsi%d: freed tag %d for target %d lun %d\n",
+		    H_NO(cmd), cmd->tag, cmd->device->id, cmd->device->lun );
+    }
+}
+
+
+static void free_all_tags( void )
+{
+    int target, lun;
+    TAG_ALLOC *ta;
+
+    if (!setup_use_tagged_queuing)
+	return;
+    
+    for( target = 0; target < 8; ++target ) {
+	for( lun = 0; lun < 8; ++lun ) {
+	    ta = &TagAlloc[target][lun];
+	    memset( &ta->allocated, 0, MAX_TAGS/8 );
+	    ta->nr_allocated = 0;
+	}
+    }
+}
+
+#endif /* SUPPORT_TAGS */
+
+
+/*
+ * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ *
+ * Purpose: Try to merge several scatter-gather requests into one DMA
+ *    transfer. This is possible if the scatter buffers lie on
+ *    physical contiguous addresses.
+ *
+ * Parameters: Scsi_Cmnd *cmd
+ *    The command to work on. The first scatter buffer's data are
+ *    assumed to be already transfered into ptr/this_residual.
+ */
+
+static void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+{
+    unsigned long endaddr;
+#if (NDEBUG & NDEBUG_MERGING)
+    unsigned long oldlen = cmd->SCp.this_residual;
+    int		  cnt = 1;
+#endif
+
+    for (endaddr = virt_to_phys(cmd->SCp.ptr + cmd->SCp.this_residual - 1) + 1;
+	 cmd->SCp.buffers_residual &&
+	 virt_to_phys(SGADDR(&(cmd->SCp.buffer[1]))) == endaddr; ) {
+	
+	MER_PRINTK("VTOP(%p) == %08lx -> merging\n",
+		   SGADDR(&(cmd->SCp.buffer[1])), endaddr);
+#if (NDEBUG & NDEBUG_MERGING)
+	++cnt;
+#endif
+	++cmd->SCp.buffer;
+	--cmd->SCp.buffers_residual;
+	cmd->SCp.this_residual += cmd->SCp.buffer->length;
+	endaddr += cmd->SCp.buffer->length;
+    }
+#if (NDEBUG & NDEBUG_MERGING)
+    if (oldlen != cmd->SCp.this_residual)
+	MER_PRINTK("merged %d buffers from %p, new length %08x\n",
+		   cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
+#endif
+}
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the 
+ *	start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd)
+{
+    /* 
+     * Initialize the Scsi Pointer field so that all of the commands in the 
+     * various queues are valid.
+     */
+
+    if (cmd->use_sg) {
+	cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+	cmd->SCp.buffers_residual = cmd->use_sg - 1;
+	cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
+	cmd->SCp.this_residual = cmd->SCp.buffer->length;
+
+	/* ++roman: Try to merge some scatter-buffers if they are at
+	 * contiguous physical addresses.
+	 */
+//	merge_contiguous_buffers( cmd );
+    } else {
+	cmd->SCp.buffer = NULL;
+	cmd->SCp.buffers_residual = 0;
+	cmd->SCp.ptr = (char *) cmd->request_buffer;
+	cmd->SCp.this_residual = cmd->request_bufflen;
+    }
+    
+}
+
+#include <linux/config.h>
+#include <linux/delay.h>
+
+#if 1
+static struct {
+    unsigned char mask;
+    const char * name;} 
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" }, 
+    { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD,  "CD" }, { SR_IO, "IO" }, 
+    { SR_SEL, "SEL" }, {0, NULL}}, 
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+    {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"}, 
+    {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"}, 
+    {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"}, 
+    {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR, 
+    "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
+    {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+    {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"}, 
+    {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+    unsigned char status, data, basr, mr, icr, i;
+    unsigned long flags;
+
+    local_irq_save(flags);
+    data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+    status = NCR5380_read(STATUS_REG);
+    mr = NCR5380_read(MODE_REG);
+    icr = NCR5380_read(INITIATOR_COMMAND_REG);
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    local_irq_restore(flags);
+    printk("STATUS_REG: %02x ", status);
+    for (i = 0; signals[i].mask ; ++i) 
+	if (status & signals[i].mask)
+	    printk(",%s", signals[i].name);
+    printk("\nBASR: %02x ", basr);
+    for (i = 0; basrs[i].mask ; ++i) 
+	if (basr & basrs[i].mask)
+	    printk(",%s", basrs[i].name);
+    printk("\nICR: %02x ", icr);
+    for (i = 0; icrs[i].mask; ++i) 
+	if (icr & icrs[i].mask)
+	    printk(",%s", icrs[i].name);
+    printk("\nMODE: %02x ", mr);
+    for (i = 0; mrs[i].mask; ++i) 
+	if (mr & mrs[i].mask)
+	    printk(",%s", mrs[i].name);
+    printk("\n");
+}
+
+static struct {
+    unsigned char value;
+    const char *name;
+} phases[] = {
+    {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+    {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+    {PHASE_UNKNOWN, "UNKNOWN"}};
+
+/* 
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance)
+{
+    unsigned char status;
+    int i;
+
+    status = NCR5380_read(STATUS_REG);
+    if (!(status & SR_REQ)) 
+	printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
+    else {
+	for (i = 0; (phases[i].value != PHASE_UNKNOWN) && 
+	    (phases[i].value != (status & PHASE_MASK)); ++i); 
+	printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
+    }
+}
+
+#else /* !NDEBUG */
+
+/* dummies... */
+__inline__ void NCR5380_print(struct Scsi_Host *instance) { };
+__inline__ void NCR5380_print_phase(struct Scsi_Host *instance) { };
+
+#endif
+
+/*
+ * ++roman: New scheme of calling NCR5380_main()
+ * 
+ * If we're not in an interrupt, we can call our main directly, it cannot be
+ * already running. Else, we queue it on a task queue, if not 'main_running'
+ * tells us that a lower level is already executing it. This way,
+ * 'main_running' needs not be protected in a special way.
+ *
+ * queue_main() is a utility function for putting our main onto the task
+ * queue, if main_running is false. It should be called only from a
+ * interrupt or bottom half.
+ */
+
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+
+static volatile int main_running = 0;
+static DECLARE_WORK(NCR5380_tqueue, (void (*)(void*))NCR5380_main, NULL);
+
+static __inline__ void queue_main(void)
+{
+    if (!main_running) {
+	/* If in interrupt and NCR5380_main() not already running,
+	   queue it on the 'immediate' task queue, to be processed
+	   immediately after the current interrupt processing has
+	   finished. */
+	schedule_work(&NCR5380_tqueue);
+    }
+    /* else: nothing to do: the running NCR5380_main() will pick up
+       any newly queued command. */
+}
+
+
+static inline void NCR5380_all_init (void)
+{
+    static int done = 0;
+    if (!done) {
+	INI_PRINTK("scsi : NCR5380_all_init()\n");
+	done = 1;
+    }
+}
+
+ 
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ *	     options that were selected.
+ *
+ * Inputs : instance, pointer to this instance.  Unused.
+ */
+
+static void __init NCR5380_print_options (struct Scsi_Host *instance)
+{
+    printk(" generic options"
+#ifdef AUTOSENSE 
+    " AUTOSENSE"
+#endif
+#ifdef REAL_DMA
+    " REAL DMA"
+#endif
+#ifdef PARITY
+    " PARITY"
+#endif
+#ifdef SUPPORT_TAGS
+    " SCSI-2 TAGGED QUEUING"
+#endif
+    );
+    printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+/*
+ * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+ *
+ * Purpose : print commands in the various queues, called from
+ *	NCR5380_abort and NCR5380_debug to aid debugging.
+ *
+ * Inputs : instance, pointer to this instance.  
+ */
+
+static void NCR5380_print_status (struct Scsi_Host *instance)
+{
+    char *pr_bfr;
+    char *start;
+    int len;
+
+    NCR_PRINT(NDEBUG_ANY);
+    NCR_PRINT_PHASE(NDEBUG_ANY);
+
+    pr_bfr = (char *) __get_free_page(GFP_ATOMIC);
+    if (!pr_bfr) {
+	printk("NCR5380_print_status: no memory for print buffer\n");
+	return;
+    }
+    len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0);
+    pr_bfr[len] = 0;
+    printk("\n%s\n", pr_bfr);
+    free_page((unsigned long) pr_bfr);
+}
+
+
+/******************************************/
+/*
+ * /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
+ *
+ * *buffer: I/O buffer
+ * **start: if inout == FALSE pointer into buffer where user read should start
+ * offset: current offset
+ * length: length of buffer
+ * hostno: Scsi_Host host_no
+ * inout: TRUE - user is writing; FALSE - user is reading
+ *
+ * Return the number of bytes read from or written
+*/
+
+#undef SPRINTF
+#define SPRINTF(fmt,args...) \
+  do { if (pos + strlen(fmt) + 20 /* slop */ < buffer + length) \
+	 pos += sprintf(pos, fmt , ## args); } while(0)
+static
+char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length);
+
+static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start,
+		       off_t offset, int length, int inout)
+{
+    char *pos = buffer;
+    struct NCR5380_hostdata *hostdata;
+    Scsi_Cmnd *ptr;
+    unsigned long flags;
+    off_t begin = 0;
+#define check_offset()				\
+    do {					\
+	if (pos - buffer < offset - begin) {	\
+	    begin += pos - buffer;		\
+	    pos = buffer;			\
+	}					\
+    } while (0)
+
+    hostdata = (struct NCR5380_hostdata *)instance->hostdata;
+
+    if (inout) { /* Has data been written to the file ? */
+	return(-ENOSYS);  /* Currently this is a no-op */
+    }
+    SPRINTF("NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
+    check_offset();
+    local_irq_save(flags);
+    SPRINTF("NCR5380: coroutine is%s running.\n", main_running ? "" : "n't");
+    check_offset();
+    if (!hostdata->connected)
+	SPRINTF("scsi%d: no currently connected command\n", HOSTNO);
+    else
+	pos = lprint_Scsi_Cmnd ((Scsi_Cmnd *) hostdata->connected,
+				pos, buffer, length);
+    SPRINTF("scsi%d: issue_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    SPRINTF("scsi%d: disconnected_queue\n", HOSTNO);
+    check_offset();
+    for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+	 ptr = NEXT(ptr)) {
+	pos = lprint_Scsi_Cmnd (ptr, pos, buffer, length);
+	check_offset();
+    }
+
+    local_irq_restore(flags);
+    *start = buffer + (offset - begin);
+    if (pos - buffer < offset - begin)
+	return 0;
+    else if (pos - buffer - (offset - begin) < length)
+	return pos - buffer - (offset - begin);
+    return length;
+}
+
+static char *
+lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length)
+{
+    int i, s;
+    unsigned char *command;
+    SPRINTF("scsi%d: destination target %d, lun %d\n",
+	    H_NO(cmd), cmd->device->id, cmd->device->lun);
+    SPRINTF("        command = ");
+    command = cmd->cmnd;
+    SPRINTF("%2d (0x%02x)", command[0], command[0]);
+    for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+	SPRINTF(" %02x", command[i]);
+    SPRINTF("\n");
+    return pos;
+}
+
+
+/* 
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializes *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.  
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * 	set correctly.  I don't care about the irq and other fields. 
+ * 
+ */
+
+static int NCR5380_init (struct Scsi_Host *instance, int flags)
+{
+    int i;
+    SETUP_HOSTDATA(instance);
+
+    NCR5380_all_init();
+
+    hostdata->aborted = 0;
+    hostdata->id_mask = 1 << instance->this_id;
+    hostdata->id_higher_mask = 0;
+    for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+	if (i > hostdata->id_mask)
+	    hostdata->id_higher_mask |= i;
+    for (i = 0; i < 8; ++i)
+	hostdata->busy[i] = 0;
+#ifdef SUPPORT_TAGS
+    init_tags();
+#endif
+#if defined (REAL_DMA)
+    hostdata->dma_len = 0;
+#endif
+    hostdata->targets_present = 0;
+    hostdata->connected = NULL;
+    hostdata->issue_queue = NULL;
+    hostdata->disconnected_queue = NULL;
+    hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+
+    if (!the_template) {
+	the_template = instance->hostt;
+	first_instance = instance;
+    }
+	
+
+#ifndef AUTOSENSE
+    if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
+	 printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
+	        "        without AUTOSENSE option, contingent allegiance conditions may\n"
+	        "        be incorrectly cleared.\n", HOSTNO);
+#endif /* def AUTOSENSE */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd, 
+ *	void (*done)(Scsi_Cmnd *)) 
+ *
+ * Purpose :  enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ *	a pointer to the command descriptor.
+ * 
+ * Returns : 0
+ *
+ * Side effects : 
+ *      cmd is added to the per instance issue_queue, with minor 
+ *	twiddling done to the host specific fields of cmd.  If the 
+ *	main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+static int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+{
+    SETUP_HOSTDATA(cmd->device->host);
+    Scsi_Cmnd *tmp;
+    unsigned long flags;
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+    switch (cmd->cmnd[0]) {
+    case WRITE_6:
+    case WRITE_10:
+	printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
+	       H_NO(cmd));
+	cmd->result = (DID_ERROR << 16);
+	done(cmd);
+	return 0;
+    }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+#ifdef NCR5380_STATS
+# if 0
+    if (!hostdata->connected && !hostdata->issue_queue &&
+	!hostdata->disconnected_queue) {
+	hostdata->timebase = jiffies;
+    }
+# endif
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;
+		hostdata->pendingw++;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
+		hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;
+		hostdata->pendingr++;
+		break;
+	}
+#endif
+
+    /* 
+     * We use the host_scribble field as a pointer to the next command  
+     * in a queue 
+     */
+
+    NEXT(cmd) = NULL;
+    cmd->scsi_done = done;
+
+    cmd->result = 0;
+
+
+    /* 
+     * Insert the cmd into the issue queue. Note that REQUEST SENSE 
+     * commands are added to the head of the queue since any command will
+     * clear the contingent allegiance condition that exists and the 
+     * sense data is only guaranteed to be valid while the condition exists.
+     */
+
+    local_irq_save(flags);
+    /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
+     * Otherwise a running NCR5380_main may steal the lock.
+     * Lock before actually inserting due to fairness reasons explained in
+     * atari_scsi.c. If we insert first, then it's impossible for this driver
+     * to release the lock.
+     * Stop timer for this command while waiting for the lock, or timeouts
+     * may happen (and they really do), and it's no good if the command doesn't
+     * appear in any of the queues.
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which would
+     * alter queues and touch the lock.
+     */
+    if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+	LIST(cmd, hostdata->issue_queue);
+	NEXT(cmd) = hostdata->issue_queue;
+	hostdata->issue_queue = cmd;
+    } else {
+	for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+	     NEXT(tmp); tmp = NEXT(tmp))
+	    ;
+	LIST(cmd, tmp);
+	NEXT(tmp) = cmd;
+    }
+
+    local_irq_restore(flags);
+
+    QU_PRINTK("scsi%d: command added to %s of queue\n", H_NO(cmd),
+	      (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+
+    /* If queue_command() is called from an interrupt (real one or bottom
+     * half), we let queue_main() do the job of taking care about main. If it
+     * is already running, this is a no-op, else main will be queued.
+     *
+     * If we're not in an interrupt, we can call NCR5380_main()
+     * unconditionally, because it cannot be already running.
+     */
+    if (in_interrupt() || ((flags >> 8) & 7) >= 6)
+	queue_main();
+    else
+	NCR5380_main(NULL);
+    return 0;
+}
+
+/*
+ * Function : NCR5380_main (void) 
+ *
+ * Purpose : NCR5380_main is a coroutine that runs as long as more work can 
+ *	be done on the NCR5380 host adapters in a system.  Both 
+ *	NCR5380_queue_command() and NCR5380_intr() will try to start it 
+ *	in case it is not running.
+ * 
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should 
+ *  reenable them.  This prevents reentrancy and kernel stack overflow.
+ */ 	
+    
+static void NCR5380_main (void *bl)
+{
+    Scsi_Cmnd *tmp, *prev;
+    struct Scsi_Host *instance = first_instance;
+    struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+    int done;
+    unsigned long flags;
+    
+    /*
+     * We run (with interrupts disabled) until we're sure that none of 
+     * the host adapters have anything that can be done, at which point 
+     * we set main_running to 0 and exit.
+     *
+     * Interrupts are enabled before doing various other internal 
+     * instructions, after we've decided that we need to run through
+     * the loop again.
+     *
+     * this should prevent any race conditions.
+     * 
+     * ++roman: Just disabling the NCR interrupt isn't sufficient here,
+     * because also a timer int can trigger an abort or reset, which can
+     * alter queues and touch the Falcon lock.
+     */
+
+    /* Tell int handlers main() is now already executing.  Note that
+       no races are possible here. If an int comes in before
+       'main_running' is set here, and queues/executes main via the
+       task queue, it doesn't do any harm, just this instance of main
+       won't find any work left to do. */
+    if (main_running)
+    	return;
+    main_running = 1;
+
+    local_save_flags(flags);
+    do {
+	local_irq_disable(); /* Freeze request queues */
+	done = 1;
+	
+	if (!hostdata->connected) {
+	    MAIN_PRINTK( "scsi%d: not connected\n", HOSTNO );
+	    /*
+	     * Search through the issue_queue for a command destined
+	     * for a target that's not busy.
+	     */
+#if (NDEBUG & NDEBUG_LISTS)
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+		 tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
+		;
+	    if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
+#endif
+	    for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, 
+		 prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
+
+#if (NDEBUG & NDEBUG_LISTS)
+		if (prev != tmp)
+		    printk("MAIN tmp=%p   target=%d   busy=%d lun=%d\n",
+			   tmp, tmp->target, hostdata->busy[tmp->target],
+			   tmp->lun);
+#endif
+		/*  When we find one, remove it from the issue queue. */
+		/* ++guenther: possible race with Falcon locking */
+		if (
+#ifdef SUPPORT_TAGS
+		    !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
+#else
+		    !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
+#endif
+		    ) {
+		    /* ++guenther: just to be sure, this must be atomic */
+		    local_irq_disable();
+		    if (prev) {
+		        REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+			NEXT(prev) = NEXT(tmp);
+		    } else {
+		        REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
+			hostdata->issue_queue = NEXT(tmp);
+		    }
+		    NEXT(tmp) = NULL;
+		    
+		    /* reenable interrupts after finding one */
+		    local_irq_restore(flags);
+		    
+		    /* 
+		     * Attempt to establish an I_T_L nexus here. 
+		     * On success, instance->hostdata->connected is set.
+		     * On failure, we must add the command back to the
+		     *   issue queue so we can keep trying.	
+		     */
+		    MAIN_PRINTK("scsi%d: main(): command for target %d "
+				"lun %d removed from issue_queue\n",
+				HOSTNO, tmp->target, tmp->lun);
+		    /* 
+		     * REQUEST SENSE commands are issued without tagged
+		     * queueing, even on SCSI-II devices because the 
+		     * contingent allegiance condition exists for the 
+		     * entire unit.
+		     */
+		    /* ++roman: ...and the standard also requires that
+		     * REQUEST SENSE command are untagged.
+		     */
+		    
+#ifdef SUPPORT_TAGS
+		    cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
+#endif
+		    if (!NCR5380_select(instance, tmp, 
+			    (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : 
+			    TAG_NEXT)) {
+			break;
+		    } else {
+			local_irq_disable();
+			LIST(tmp, hostdata->issue_queue);
+			NEXT(tmp) = hostdata->issue_queue;
+			hostdata->issue_queue = tmp;
+#ifdef SUPPORT_TAGS
+			cmd_free_tag( tmp );
+#endif
+			local_irq_restore(flags);
+			MAIN_PRINTK("scsi%d: main(): select() failed, "
+				    "returned to issue_queue\n", HOSTNO);
+			if (hostdata->connected)
+			    break;
+		    }
+		} /* if target/lun/target queue is not busy */
+	    } /* for issue_queue */
+	} /* if (!hostdata->connected) */
+	if (hostdata->connected 
+#ifdef REAL_DMA
+	    && !hostdata->dma_len
+#endif
+	    ) {
+	    local_irq_restore(flags);
+	    MAIN_PRINTK("scsi%d: main: performing information transfer\n",
+			HOSTNO);
+	    NCR5380_information_transfer(instance);
+	    MAIN_PRINTK("scsi%d: main: done set false\n", HOSTNO);
+	    done = 0;
+	}
+    } while (!done);
+
+    /* Better allow ints _after_ 'main_running' has been cleared, else
+       an interrupt could believe we'll pick up the work it left for
+       us, but we won't see it anymore here... */
+    main_running = 0;
+    local_irq_restore(flags);
+}
+
+
+#ifdef REAL_DMA
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : Called by interrupt handler when DMA finishes or a phase
+ *	mismatch occurs (which would finish the DMA transfer).  
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+static void NCR5380_dma_complete( struct Scsi_Host *instance )
+{
+    SETUP_HOSTDATA(instance);
+    int           transfered;
+    unsigned char **data;
+    volatile int  *count;
+
+    if (!hostdata->connected) {
+	printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
+	       "no connected cmd\n", HOSTNO);
+	return;
+    }
+
+    DMA_PRINTK("scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
+	       HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
+	       NCR5380_read(STATUS_REG));
+
+    if((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
+	    printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
+	    printk("please e-mail sammy@sammy.net with a description of how this\n");
+	    printk("error was produced.\n");
+	    BUG();
+    }
+
+    /* make sure we're not stuck in a data phase */
+    if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH |
+					    BASR_ACK)) ==
+       (BASR_PHASE_MATCH | BASR_ACK)) {
+	    printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
+	    printk("scsi%d: bus stuck in data phase -- probably a single byte "
+		   "overrun!\n", HOSTNO);
+	    printk("not prepared for this error!\n");
+	    printk("please e-mail sammy@sammy.net with a description of how this\n");
+	    printk("error was produced.\n");
+	    BUG();
+    }
+
+
+
+    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+    NCR5380_write(MODE_REG, MR_BASE);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+    hostdata->dma_len = 0;
+
+    data = (unsigned char **) &(hostdata->connected->SCp.ptr);
+    count = &(hostdata->connected->SCp.this_residual);
+    *data += transfered;
+    *count -= transfered;
+
+}
+#endif /* REAL_DMA */
+
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ * 
+ * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ *	from the disconnected queue, and restarting NCR5380_main() 
+ *	as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static irqreturn_t NCR5380_intr (int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct Scsi_Host *instance = first_instance;
+    int done = 1, handled = 0;
+    unsigned char basr;
+
+    INT_PRINTK("scsi%d: NCR5380 irq triggered\n", HOSTNO);
+
+    /* Look for pending interrupts */
+    basr = NCR5380_read(BUS_AND_STATUS_REG);
+    INT_PRINTK("scsi%d: BASR=%02x\n", HOSTNO, basr);
+    /* dispatch to appropriate routine if found and done=0 */
+    if (basr & BASR_IRQ) {
+	NCR_PRINT(NDEBUG_INTR);
+	if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
+	    done = 0;
+	    ENABLE_IRQ();
+	    INT_PRINTK("scsi%d: SEL interrupt\n", HOSTNO);
+	    NCR5380_reselect(instance);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if (basr & BASR_PARITY_ERROR) {
+	    INT_PRINTK("scsi%d: PARITY interrupt\n", HOSTNO);
+	    (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
+	    INT_PRINTK("scsi%d: RESET interrupt\n", HOSTNO);
+	    (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	}
+	else {
+	    /*  
+	     * The rest of the interrupt conditions can occur only during a
+	     * DMA transfer
+	     */
+
+#if defined(REAL_DMA)
+	    /*
+	     * We should only get PHASE MISMATCH and EOP interrupts if we have
+	     * DMA enabled, so do a sanity check based on the current setting
+	     * of the MODE register.
+	     */
+
+	    if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
+		((basr & BASR_END_DMA_TRANSFER) || 
+		 !(basr & BASR_PHASE_MATCH))) {
+		    
+		INT_PRINTK("scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
+		NCR5380_dma_complete( instance );
+		done = 0;
+		ENABLE_IRQ();
+	    } else
+#endif /* REAL_DMA */
+	    {
+/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
+		if (basr & BASR_PHASE_MATCH)
+		   INT_PRINTK("scsi%d: unknown interrupt, "
+			   "BASR 0x%x, MR 0x%x, SR 0x%x\n",
+			   HOSTNO, basr, NCR5380_read(MODE_REG),
+			   NCR5380_read(STATUS_REG));
+		(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_DMA_ENABLE;
+#endif
+	    }
+	} /* if !(SELECTION || PARITY) */
+	handled = 1;
+    } /* BASR & IRQ */
+    else {
+
+	printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
+	       "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
+	       NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
+	(void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_DMA_ENABLE;
+#endif
+    }
+    
+    if (!done) {
+	INT_PRINTK("scsi%d: in int routine, calling main\n", HOSTNO);
+	/* Put a call to NCR5380_main() on the queue... */
+	queue_main();
+    }
+    return IRQ_RETVAL(handled);
+}
+
+#ifdef NCR5380_STATS
+static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd* cmd)
+{
+# ifdef NCR5380_STAT_LIMIT
+    if (cmd->request_bufflen > NCR5380_STAT_LIMIT)
+# endif
+	switch (cmd->cmnd[0])
+	{
+	    case WRITE:
+	    case WRITE_6:
+	    case WRITE_10:
+		hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_write[cmd->device->id] += cmd->request_bufflen;*/
+		hostdata->pendingw--;
+		break;
+	    case READ:
+	    case READ_6:
+	    case READ_10:
+		hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
+		/*hostdata->bytes_read[cmd->device->id] += cmd->request_bufflen;*/
+		hostdata->pendingr--;
+		break;
+	}
+}
+#endif
+
+/* 
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, 
+ *	int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ *	including ARBITRATION, SELECTION, and initial message out for 
+ *	IDENTIFY and queue messages. 
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this 
+ * 	target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for 
+ *	new tag, TAG_NONE for untagged queueing, otherwise set to the tag for 
+ *	the command that is presently connected.
+ * 
+ * Returns : -1 if selection could not execute for some reason,
+ *	0 if selection succeeded or failed because the target 
+ * 	did not respond.
+ *
+ * Side effects : 
+ * 	If bus busy, arbitration failed, etc, NCR5380_select() will exit 
+ *		with registers as they should have been on entry - ie
+ *		SELECT_ENABLE will be set appropriately, the NCR5380
+ *		will cease to drive any SCSI bus signals.
+ *
+ *	If successful : I_T_L or I_T_L_Q nexus will be established, 
+ *		instance->connected will be set to cmd.  
+ * 		SELECT interrupt will be disabled.
+ *
+ *	If failed (no target) : cmd->scsi_done() will be called, and the 
+ *		cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char tmp[3], phase;
+    unsigned char *data;
+    int len;
+    unsigned long timeout;
+    unsigned long flags;
+
+    hostdata->restart_select = 0;
+    NCR_PRINT(NDEBUG_ARBITRATION);
+    ARB_PRINTK("scsi%d: starting arbitration, id = %d\n", HOSTNO,
+	       instance->this_id);
+
+    /* 
+     * Set the phase bits to 0, otherwise the NCR5380 won't drive the 
+     * data bus during SELECTION.
+     */
+
+    local_irq_save(flags);
+    if (hostdata->connected) {
+	local_irq_restore(flags);
+	return -1;
+    }
+    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+
+    /* 
+     * Start arbitration.
+     */
+    
+    NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+    NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+    local_irq_restore(flags);
+
+    /* Wait for arbitration logic to complete */
+#if NCR_TIMEOUT
+    {
+      unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
+
+      while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	   && time_before(jiffies, timeout) && !hostdata->connected)
+	;
+      if (time_after_eq(jiffies, timeout))
+      {
+	printk("scsi : arbitration timeout at %d\n", __LINE__);
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return -1;
+      }
+    }
+#else /* NCR_TIMEOUT */
+    while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
+	 && !hostdata->connected);
+#endif
+
+    ARB_PRINTK("scsi%d: arbitration complete\n", HOSTNO);
+
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	return -1;
+    }
+    /* 
+     * The arbitration delay is 2.2us, but this is a minimum and there is 
+     * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
+     * the integral nature of udelay().
+     *
+     */
+
+    udelay(3);
+
+    /* Check for lost arbitration */
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	(NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+	(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE); 
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
+		   HOSTNO);
+	return -1;
+    }
+
+     /* after/during arbitration, BSY should be asserted.
+	IBM DPES-31080 Version S31Q works now */
+     /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
+					 ICR_ASSERT_BSY ) ;
+    
+    if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+	hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	ARB_PRINTK("scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
+		   HOSTNO);
+	return -1;
+    }
+
+    /* 
+     * Again, bus clear + bus settle time is 1.2us, however, this is 
+     * a minimum so we'll udelay ceil(1.2)
+     */
+
+#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
+    /* ++roman: But some targets (see above :-) seem to need a bit more... */
+    udelay(15);
+#else
+    udelay(2);
+#endif
+    
+    if (hostdata->connected) {
+	NCR5380_write(MODE_REG, MR_BASE);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    ARB_PRINTK("scsi%d: won arbitration\n", HOSTNO);
+
+    /* 
+     * Now that we have won arbitration, start Selection process, asserting 
+     * the host and target ID's on the SCSI bus.
+     */
+
+    NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
+
+    /* 
+     * Raise ATN while SEL is true before BSY goes false from arbitration,
+     * since this is the only way to guarantee that we'll get a MESSAGE OUT
+     * phase immediately after selection.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY | 
+	ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+    NCR5380_write(MODE_REG, MR_BASE);
+
+    /* 
+     * Reselect interrupts must be turned off prior to the dropping of BSY,
+     * otherwise we will trigger an interrupt.
+     */
+
+    if (hostdata->connected) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	return -1;
+    }
+
+    NCR5380_write(SELECT_ENABLE_REG, 0);
+
+    /*
+     * The initiator shall then wait at least two deskew delays and release 
+     * the BSY signal.
+     */
+    udelay(1);        /* wingel -- wait two bus deskew delay >2*45ns */
+
+    /* Reset BSY */
+    NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA | 
+	ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+    /* 
+     * Something weird happens when we cease to drive BSY - looks
+     * like the board/chip is letting us do another read before the 
+     * appropriate propagation delay has expired, and we're confusing
+     * a BSY signal from ourselves as the target's response to SELECTION.
+     *
+     * A small delay (the 'C++' frontend breaks the pipeline with an
+     * unnecessary jump, making it work on my 386-33/Trantor T128, the
+     * tighter 'C' code breaks and requires this) solves the problem - 
+     * the 1 us delay is arbitrary, and only used because this delay will 
+     * be the same on other platforms and since it works here, it should 
+     * work there.
+     *
+     * wingel suggests that this could be due to failing to wait
+     * one deskew delay.
+     */
+
+    udelay(1);
+
+    SEL_PRINTK("scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
+
+    /* 
+     * The SCSI specification calls for a 250 ms timeout for the actual 
+     * selection.
+     */
+
+    timeout = jiffies + 25; 
+
+    /* 
+     * XXX very interesting - we're seeing a bounce where the BSY we 
+     * asserted is being reflected / still asserted (propagation delay?)
+     * and it's detecting as true.  Sigh.
+     */
+
+#if 0
+    /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
+     * IO while SEL is true. But again, there are some disks out the in the
+     * world that do that nevertheless. (Somebody claimed that this announces
+     * reselection capability of the target.) So we better skip that test and
+     * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
+     */
+
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & 
+	(SR_BSY | SR_IO)));
+
+    if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) == 
+	    (SR_SEL | SR_IO)) {
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	    NCR5380_reselect(instance);
+	    printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
+		    HOSTNO);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+    }
+#else
+    while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+#endif
+
+    /* 
+     * No less than two deskew delays after the initiator detects the 
+     * BSY signal is true, it shall release the SEL signal and may 
+     * change the DATA BUS.                                     -wingel
+     */
+
+    udelay(1);
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	if (hostdata->targets_present & (1 << cmd->device->id)) {
+	    printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
+	    if (hostdata->restart_select)
+		printk(KERN_NOTICE "\trestart select\n");
+	    NCR_PRINT(NDEBUG_ANY);
+	    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	    return -1;
+	}
+	cmd->result = DID_BAD_TARGET << 16;
+#ifdef NCR5380_STATS
+	collect_stats(hostdata, cmd);
+#endif
+#ifdef SUPPORT_TAGS
+	cmd_free_tag( cmd );
+#endif
+	cmd->scsi_done(cmd);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	SEL_PRINTK("scsi%d: target did not respond within 250ms\n", HOSTNO);
+	NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+	return 0;
+    } 
+
+    hostdata->targets_present |= (1 << cmd->device->id);
+
+    /*
+     * Since we followed the SCSI spec, and raised ATN while SEL 
+     * was true but before BSY was false during selection, the information
+     * transfer phase should be a MESSAGE OUT phase so that we can send the
+     * IDENTIFY message.
+     * 
+     * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
+     * message (2 bytes) with a tag ID that we increment with every command
+     * until it wraps back to 0.
+     *
+     * XXX - it turns out that there are some broken SCSI-II devices,
+     *	     which claim to support tagged queuing but fail when more than
+     *	     some number of commands are issued at once.
+     */
+
+    /* Wait for start of REQ/ACK handshake */
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+    SEL_PRINTK("scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
+	       HOSTNO, cmd->device->id);
+    tmp[0] = IDENTIFY(1, cmd->device->lun);
+
+#ifdef SUPPORT_TAGS
+    if (cmd->tag != TAG_NONE) {
+	tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
+	tmp[2] = cmd->tag;
+	len = 3;
+    } else 
+	len = 1;
+#else
+    len = 1;
+    cmd->tag=0;
+#endif /* SUPPORT_TAGS */
+
+    /* Send message(s) */
+    data = tmp;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio(instance, &phase, &len, &data);
+    SEL_PRINTK("scsi%d: nexus established.\n", HOSTNO);
+    /* XXX need to handle errors here */
+    hostdata->connected = cmd;
+#ifndef SUPPORT_TAGS
+    hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+#endif    
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_INTR;
+#endif
+    initialize_SCp(cmd);
+
+
+    return 0;
+}
+
+/* 
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes are transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it 
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    register unsigned char p = *phase, tmp;
+    register int c = *count;
+    register unsigned char *d = *data;
+
+    /* 
+     * The NCR5380 chip will only drive the SCSI bus when the 
+     * phase specified in the appropriate bits of the TARGET COMMAND
+     * REGISTER match the STATUS REGISTER
+     */
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+    do {
+	/* 
+	 * Wait for assertion of REQ, after which the phase bits will be 
+	 * valid 
+	 */
+	while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+	HSH_PRINTK("scsi%d: REQ detected\n", HOSTNO);
+
+	/* Check for phase mismatch */	
+	if ((tmp & PHASE_MASK) != p) {
+	    PIO_PRINTK("scsi%d: phase mismatch\n", HOSTNO);
+	    NCR_PRINT_PHASE(NDEBUG_PIO);
+	    break;
+	}
+
+	/* Do actual transfer from SCSI bus to / from memory */
+	if (!(p & SR_IO)) 
+	    NCR5380_write(OUTPUT_DATA_REG, *d);
+	else 
+	    *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+	++d;
+
+	/* 
+	 * The SCSI standard suggests that in MSGOUT phase, the initiator
+	 * should drop ATN on the last byte of the message phase
+	 * after REQ has been asserted for the handshake but before
+	 * the initiator raises ACK.
+	 */
+
+	if (!(p & SR_IO)) {
+	    if (!((p & SR_MSG) && c > 1)) {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+	    } else {
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+		NCR_PRINT(NDEBUG_PIO);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+	    }
+	} else {
+	    NCR_PRINT(NDEBUG_PIO);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+	}
+
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+	HSH_PRINTK("scsi%d: req false, handshake complete\n", HOSTNO);
+
+/*
+ * We have several special cases to consider during REQ/ACK handshaking : 
+ * 1.  We were in MSGOUT phase, and we are on the last byte of the 
+ *	message.  ATN must be dropped as ACK is dropped.
+ *
+ * 2.  We are in a MSGIN phase, and we are on the last byte of the  
+ *	message.  We must exit with ACK asserted, so that the calling
+ *	code may raise ATN before dropping ACK to reject the message.
+ *
+ * 3.  ACK and ATN are clear and the target may proceed as normal.
+ */
+	if (!(p == PHASE_MSGIN && c == 1)) {  
+	    if (p == PHASE_MSGOUT && c > 1)
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+	    else
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+	} 
+    } while (--c);
+
+    PIO_PRINTK("scsi%d: residual %d\n", HOSTNO, c);
+
+    *count = c;
+    *data = d;
+    tmp = NCR5380_read(STATUS_REG);
+    /* The phase read from the bus is valid if either REQ is (already)
+     * asserted or if ACK hasn't been released yet. The latter is the case if
+     * we're in MSGIN and all wanted bytes have been received. */
+    if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
+	*phase = tmp & PHASE_MASK;
+    else 
+	*phase = PHASE_UNKNOWN;
+
+    if (!c || (*phase == p))
+	return 0;
+    else 
+	return -1;
+}
+
+/*
+ * Function : do_abort (Scsi_Host *host)
+ * 
+ * Purpose : abort the currently established nexus.  Should only be 
+ * 	called from a routine which can drop into a 
+ * 
+ * Returns : 0 on success, -1 on failure.
+ */
+
+static int do_abort (struct Scsi_Host *host) 
+{
+    unsigned char tmp, *msgptr, phase;
+    int len;
+
+    /* Request message out phase */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+    /* 
+     * Wait for the target to indicate a valid phase by asserting 
+     * REQ.  Once this happens, we'll have either a MSGOUT phase 
+     * and can immediately send the ABORT message, or we'll have some 
+     * other phase and will have to source/sink data.
+     * 
+     * We really don't care what value was on the bus or what value
+     * the target sees, so we just handshake.
+     */
+    
+    while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ);
+
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+    if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		      ICR_ASSERT_ACK);
+	while (NCR5380_read(STATUS_REG) & SR_REQ);
+	NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+    }
+   
+    tmp = ABORT;
+    msgptr = &tmp;
+    len = 1;
+    phase = PHASE_MSGOUT;
+    NCR5380_transfer_pio (host, &phase, &len, &msgptr);
+
+    /*
+     * If we got here, and the command completed successfully,
+     * we're about to go into bus free state.
+     */
+
+    return len ? -1 : 0;
+}
+
+#if defined(REAL_DMA)
+/* 
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance, 
+ *      unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ *	or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to 
+ *	what phase is expected, *count - pointer to number of 
+ *	bytes to transfer, **data - pointer to data pointer.
+ * 
+ * Returns : -1 when different phase is entered without transferring
+ *	maximum number of bytes, 0 if all bytes or transfered or exit
+ *	is in same phase.
+ *
+ * 	Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma( struct Scsi_Host *instance, 
+				 unsigned char *phase, int *count,
+				 unsigned char **data)
+{
+    SETUP_HOSTDATA(instance);
+    register int c = *count;
+    register unsigned char p = *phase;
+    unsigned long flags;
+
+    /* sanity check */
+    if(!sun3_dma_setup_done) {
+	 printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
+	 BUG();
+    }
+    hostdata->dma_len = c;
+
+    DMA_PRINTK("scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+	       HOSTNO, (p & SR_IO) ? "reading" : "writing",
+	       c, (p & SR_IO) ? "to" : "from", *data);
+
+    /* netbsd turns off ints here, why not be safe and do it too */
+    local_irq_save(flags);
+    
+    /* send start chain */
+    sun3scsi_dma_start(c, *data);
+    
+    if (p & SR_IO) {
+	    NCR5380_write(TARGET_COMMAND_REG, 1);
+	    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    NCR5380_write(INITIATOR_COMMAND_REG, 0);
+	    NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+	    NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+    } else {
+	    NCR5380_write(TARGET_COMMAND_REG, 0);
+	    NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+	    NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
+	    NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+	    NCR5380_write(START_DMA_SEND_REG, 0);
+    }
+
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_DMA_ENABLE;
+#endif
+
+    local_irq_restore(flags);
+
+    sun3_dma_active = 1;
+    return 0;
+}
+#endif /* defined(REAL_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target 
+ * 	directs us to.  Operates on the currently connected command, 
+ *	instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be 
+ *	modified if a command disconnects, *instance->connected will
+ *	change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here 
+ * 	to recover from an unexpected bus free condition.
+ */
+ 
+static void NCR5380_information_transfer (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned long flags;
+    unsigned char msgout = NOP;
+    int sink = 0;
+    int len;
+#if defined(REAL_DMA)
+    int transfersize;
+#endif
+    unsigned char *data;
+    unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
+    Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+
+#ifdef SUN3_SCSI_VME
+    dregs->csr |= CSR_INTR;
+#endif
+
+    while (1) {
+	tmp = NCR5380_read(STATUS_REG);
+	/* We only have a valid SCSI phase when REQ is asserted */
+	if (tmp & SR_REQ) {
+	    phase = (tmp & PHASE_MASK); 
+ 	    if (phase != old_phase) {
+		old_phase = phase;
+		NCR_PRINT_PHASE(NDEBUG_INFORMATION);
+	    }
+
+	    if(phase == PHASE_CMDOUT) {
+		    void *d;
+		    unsigned long count;
+
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+			count = cmd->SCp.buffer->length;
+			d = SGADDR(cmd->SCp.buffer);
+		} else {
+			count = cmd->SCp.this_residual;
+			d = cmd->SCp.ptr;
+		}
+#ifdef REAL_DMA
+		/* this command setup for dma yet? */
+		if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
+						  != cmd))
+		{
+			if(cmd->request->flags & REQ_CMD) {
+				sun3scsi_dma_setup(d, count,
+						   rq_data_dir(cmd->request));
+				sun3_dma_setup_done = cmd;
+			}
+		}
+#endif
+#ifdef SUN3_SCSI_VME
+		dregs->csr |= CSR_INTR;
+#endif
+	    }
+
+	    
+	    if (sink && (phase != PHASE_MSGOUT)) {
+		NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
+
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN | 
+		    ICR_ASSERT_ACK);
+		while (NCR5380_read(STATUS_REG) & SR_REQ);
+		NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+		    ICR_ASSERT_ATN);
+		sink = 0;
+		continue;
+	    }
+
+	    switch (phase) {
+	    case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+		printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
+		       "aborted\n", HOSTNO);
+		sink = 1;
+		do_abort(instance);
+		cmd->result = DID_ERROR  << 16;
+		cmd->done(cmd);
+		return;
+#endif
+	    case PHASE_DATAIN:
+		/* 
+		 * If there is no room left in the current buffer in the
+		 * scatter-gather list, move onto the next one.
+		 */
+		if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		    ++cmd->SCp.buffer;
+		    --cmd->SCp.buffers_residual;
+		    cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		    cmd->SCp.ptr = SGADDR(cmd->SCp.buffer);
+
+		    /* ++roman: Try to merge some scatter-buffers if
+		     * they are at contiguous physical addresses.
+		     */
+//		    merge_contiguous_buffers( cmd );
+		    INF_PRINTK("scsi%d: %d bytes and %d buffers left\n",
+			       HOSTNO, cmd->SCp.this_residual,
+			       cmd->SCp.buffers_residual);
+		}
+
+		/*
+		 * The preferred transfer method is going to be 
+		 * PSEUDO-DMA for systems that are strictly PIO,
+		 * since we can let the hardware do the handshaking.
+		 *
+		 * For this to work, we need to know the transfersize
+		 * ahead of time, since the pseudo-DMA code will sit
+		 * in an unconditional loop.
+		 */
+
+/* ++roman: I suggest, this should be
+ *   #if def(REAL_DMA)
+ * instead of leaving REAL_DMA out.
+ */
+
+#if defined(REAL_DMA)
+//		if (!cmd->device->borken &&
+		if((transfersize =
+		    NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) {
+		    len = transfersize;
+		    cmd->SCp.phase = phase;
+
+		    if (NCR5380_transfer_dma(instance, &phase,
+			&len, (unsigned char **) &cmd->SCp.ptr)) {
+			/*
+			 * If the watchdog timer fires, all future
+			 * accesses to this device will use the
+			 * polled-IO. */ 
+			printk(KERN_NOTICE "scsi%d: switching target %d "
+			       "lun %d to slow handshake\n", HOSTNO,
+			       cmd->device->id, cmd->device->lun);
+			cmd->device->borken = 1;
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			    ICR_ASSERT_ATN);
+			sink = 1;
+			do_abort(instance);
+			cmd->result = DID_ERROR  << 16;
+			cmd->done(cmd);
+			/* XXX - need to source or sink data here, as appropriate */
+		    } else {
+#ifdef REAL_DMA
+			/* ++roman: When using real DMA,
+			 * information_transfer() should return after
+			 * starting DMA since it has nothing more to
+			 * do.
+			 */
+				    return;
+#else			
+			cmd->SCp.this_residual -= transfersize - len;
+#endif
+		    }
+		} else 
+#endif /* defined(REAL_DMA) */
+		  NCR5380_transfer_pio(instance, &phase, 
+		    (int *) &cmd->SCp.this_residual, (unsigned char **)
+		    &cmd->SCp.ptr);
+#ifdef REAL_DMA
+		/* if we had intended to dma that command clear it */
+		if(sun3_dma_setup_done == cmd)
+			sun3_dma_setup_done = NULL;
+#endif
+
+		break;
+	    case PHASE_MSGIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_write(SELECT_ENABLE_REG, 0); 	/* disable reselects */
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Message = tmp;
+		
+		switch (tmp) {
+		/*
+		 * Linking lets us reduce the time required to get the 
+		 * next command out to the device, hopefully this will
+		 * mean we don't waste another revolution due to the delays
+		 * required by ARBITRATION and another SELECTION.
+		 *
+		 * In the current implementation proposal, low level drivers
+		 * merely have to start the next command, pointed to by 
+		 * next_link, done() is called as with unlinked commands.
+		 */
+#ifdef LINKED
+		case LINKED_CMD_COMPLETE:
+		case LINKED_FLG_CMD_COMPLETE:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    
+		    LNK_PRINTK("scsi%d: target %d lun %d linked command "
+			       "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /*
+		     * Sanity check : A linked command should only terminate
+		     * with one of these messages if there are more linked
+		     * commands available.
+		     */
+
+		    if (!cmd->next_link) {
+			 printk(KERN_NOTICE "scsi%d: target %d lun %d "
+				"linked command complete, no next_link\n",
+				HOSTNO, cmd->device->id, cmd->device->lun);
+			    sink = 1;
+			    do_abort (instance);
+			    return;
+		    }
+
+		    initialize_SCp(cmd->next_link);
+		    /* The next command is still part of this process; copy it
+		     * and don't free it! */
+		    cmd->next_link->tag = cmd->tag;
+		    cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    LNK_PRINTK("scsi%d: target %d lun %d linked request "
+			       "done, calling scsi_done().\n",
+			       HOSTNO, cmd->device->id, cmd->device->lun);
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    cmd = hostdata->connected;
+		    break;
+#endif /* def LINKED */
+		case ABORT:
+		case COMMAND_COMPLETE: 
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    hostdata->connected = NULL;
+		    QU_PRINTK("scsi%d: command for target %d, lun %d "
+			      "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+		    if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
+			/* Turn a QUEUE FULL status into BUSY, I think the
+			 * mid level cannot handle QUEUE FULL :-( (The
+			 * command is retried after BUSY). Also update our
+			 * queue size to the number of currently issued
+			 * commands now.
+			 */
+			/* ++Andreas: the mid level code knows about
+			   QUEUE_FULL now. */
+			TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+			TAG_PRINTK("scsi%d: target %d lun %d returned "
+				   "QUEUE_FULL after %d commands\n",
+				   HOSTNO, cmd->device->id, cmd->device->lun,
+				   ta->nr_allocated);
+			if (ta->queue_size > ta->nr_allocated)
+			    ta->nr_allocated = ta->queue_size;
+		    }
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+
+		    /* 
+		     * I'm not sure what the correct thing to do here is : 
+		     * 
+		     * If the command that just executed is NOT a request 
+		     * sense, the obvious thing to do is to set the result
+		     * code to the values of the stored parameters.
+		     * 
+		     * If it was a REQUEST SENSE command, we need some way to
+		     * differentiate between the failure code of the original
+		     * and the failure code of the REQUEST sense - the obvious
+		     * case is success, where we fall through and leave the
+		     * result code unchanged.
+		     * 
+		     * The non-obvious place is where the REQUEST SENSE failed
+		     */
+
+		    if (cmd->cmnd[0] != REQUEST_SENSE) 
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); 
+		    else if (status_byte(cmd->SCp.Status) != GOOD)
+			cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		    
+#ifdef AUTOSENSE
+		    if ((cmd->cmnd[0] != REQUEST_SENSE) && 
+			(status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
+			ASEN_PRINTK("scsi%d: performing request sense\n",
+				    HOSTNO);
+			cmd->cmnd[0] = REQUEST_SENSE;
+			cmd->cmnd[1] &= 0xe0;
+			cmd->cmnd[2] = 0;
+			cmd->cmnd[3] = 0;
+			cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+			cmd->cmnd[5] = 0;
+			cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+
+			cmd->use_sg = 0;
+			/* this is initialized from initialize_SCp 
+			cmd->SCp.buffer = NULL;
+			cmd->SCp.buffers_residual = 0;
+			*/
+			cmd->request_buffer = (char *) cmd->sense_buffer;
+			cmd->request_bufflen = sizeof(cmd->sense_buffer);
+
+			local_irq_save(flags);
+			LIST(cmd,hostdata->issue_queue);
+			NEXT(cmd) = hostdata->issue_queue;
+		        hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+		        local_irq_restore(flags);
+			QU_PRINTK("scsi%d: REQUEST SENSE added to head of "
+				  "issue queue\n", H_NO(cmd));
+		   } else
+#endif /* def AUTOSENSE */
+		   {
+#ifdef NCR5380_STATS
+		       collect_stats(hostdata, cmd);
+#endif
+		       cmd->scsi_done(cmd);
+		    }
+
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+		    
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+			barrier();
+
+		    return;
+		case MESSAGE_REJECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    switch (hostdata->last_message) {
+		    case HEAD_OF_QUEUE_TAG:
+		    case ORDERED_QUEUE_TAG:
+		    case SIMPLE_QUEUE_TAG:
+			/* The target obviously doesn't support tagged
+			 * queuing, even though it announced this ability in
+			 * its INQUIRY data ?!? (maybe only this LUN?) Ok,
+			 * clear 'tagged_supported' and lock the LUN, since
+			 * the command is treated as untagged further on.
+			 */
+			cmd->device->tagged_supported = 0;
+			hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+			cmd->tag = TAG_NONE;
+			TAG_PRINTK("scsi%d: target %d lun %d rejected "
+				   "QUEUE_TAG message; tagged queuing "
+				   "disabled\n",
+				   HOSTNO, cmd->device->id, cmd->device->lun);
+			break;
+		    }
+		    break;
+		case DISCONNECT:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    local_irq_save(flags);
+		    cmd->device->disconnect = 1;
+		    LIST(cmd,hostdata->disconnected_queue);
+		    NEXT(cmd) = hostdata->disconnected_queue;
+		    hostdata->connected = NULL;
+		    hostdata->disconnected_queue = cmd;
+		    local_irq_restore(flags);
+		    QU_PRINTK("scsi%d: command for target %d lun %d was "
+			      "moved from connected to the "
+			      "disconnected_queue\n", HOSTNO, 
+			      cmd->device->id, cmd->device->lun);
+		    /* 
+		     * Restore phase bits to 0 so an interrupted selection, 
+		     * arbitration can resume.
+		     */
+		    NCR5380_write(TARGET_COMMAND_REG, 0);
+
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    /* Wait for bus free to avoid nasty timeouts */
+		    while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
+		    	barrier();
+#ifdef SUN3_SCSI_VME
+		    dregs->csr |= CSR_DMA_ENABLE;
+#endif
+		    return;
+		/* 
+		 * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+		 * operation, in violation of the SCSI spec so we can safely 
+		 * ignore SAVE/RESTORE pointers calls.
+		 *
+		 * Unfortunately, some disks violate the SCSI spec and 
+		 * don't issue the required SAVE_POINTERS message before
+		 * disconnecting, and we have to break spec to remain 
+		 * compatible.
+		 */
+		case SAVE_POINTERS:
+		case RESTORE_POINTERS:
+		    /* Accept message by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+		    /* Enable reselect interrupts */
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    break;
+		case EXTENDED_MESSAGE:
+/* 
+ * Extended messages are sent in the following format :
+ * Byte 	
+ * 0		EXTENDED_MESSAGE == 1
+ * 1		length (includes one byte for code, doesn't 
+ *		include first two bytes)
+ * 2 		code
+ * 3..length+1	arguments
+ *
+ * Start the extended message buffer with the EXTENDED_MESSAGE
+ * byte, since print_msg() wants the whole thing.  
+ */
+		    extended_msg[0] = EXTENDED_MESSAGE;
+		    /* Accept first byte by clearing ACK */
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+		    EXT_PRINTK("scsi%d: receiving extended message\n", HOSTNO);
+
+		    len = 2;
+		    data = extended_msg + 1;
+		    phase = PHASE_MSGIN;
+		    NCR5380_transfer_pio(instance, &phase, &len, &data);
+		    EXT_PRINTK("scsi%d: length=%d, code=0x%02x\n", HOSTNO,
+			       (int)extended_msg[1], (int)extended_msg[2]);
+
+		    if (!len && extended_msg[1] <= 
+			(sizeof (extended_msg) - 1)) {
+			/* Accept third byte by clearing ACK */
+			NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+			len = extended_msg[1] - 1;
+			data = extended_msg + 3;
+			phase = PHASE_MSGIN;
+
+			NCR5380_transfer_pio(instance, &phase, &len, &data);
+			EXT_PRINTK("scsi%d: message received, residual %d\n",
+				   HOSTNO, len);
+
+			switch (extended_msg[2]) {
+			case EXTENDED_SDTR:
+			case EXTENDED_WDTR:
+			case EXTENDED_MODIFY_DATA_POINTER:
+			case EXTENDED_EXTENDED_IDENTIFY:
+			    tmp = 0;
+			}
+		    } else if (len) {
+			printk(KERN_NOTICE "scsi%d: error receiving "
+			       "extended message\n", HOSTNO);
+			tmp = 0;
+		    } else {
+			printk(KERN_NOTICE "scsi%d: extended message "
+			       "code %02x length %d is too long\n",
+			       HOSTNO, extended_msg[2], extended_msg[1]);
+			tmp = 0;
+		    }
+		/* Fall through to reject message */
+
+		/* 
+  		 * If we get something weird that we aren't expecting, 
+ 		 * reject it.
+		 */
+		default:
+		    if (!tmp) {
+			printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+			print_msg (extended_msg);
+			printk("\n");
+		    } else if (tmp != EXTENDED_MESSAGE)
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "message %02x from target %d, lun %d\n",
+			       HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+		    else
+			printk(KERN_DEBUG "scsi%d: rejecting unknown "
+			       "extended message "
+			       "code %02x, length %d from target %d, lun %d\n",
+			       HOSTNO, extended_msg[1], extended_msg[0],
+			       cmd->device->id, cmd->device->lun);
+   
+
+		    msgout = MESSAGE_REJECT;
+		    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | 
+			ICR_ASSERT_ATN);
+		    break;
+		} /* switch (tmp) */
+		break;
+	    case PHASE_MSGOUT:
+		len = 1;
+		data = &msgout;
+		hostdata->last_message = msgout;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		if (msgout == ABORT) {
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( cmd );
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    hostdata->connected = NULL;
+		    cmd->result = DID_ERROR << 16;
+#ifdef NCR5380_STATS
+		    collect_stats(hostdata, cmd);
+#endif
+		    cmd->scsi_done(cmd);
+		    NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+		    return;
+		}
+		msgout = NOP;
+		break;
+	    case PHASE_CMDOUT:
+		len = cmd->cmd_len;
+		data = cmd->cmnd;
+		/* 
+		 * XXX for performance reasons, on machines with a 
+		 * PSEUDO-DMA architecture we should probably 
+		 * use the dma transfer function.  
+		 */
+		NCR5380_transfer_pio(instance, &phase, &len, 
+		    &data);
+		break;
+	    case PHASE_STATIN:
+		len = 1;
+		data = &tmp;
+		NCR5380_transfer_pio(instance, &phase, &len, &data);
+		cmd->SCp.Status = tmp;
+		break;
+	    default:
+		printk("scsi%d: unknown phase\n", HOSTNO);
+		NCR_PRINT(NDEBUG_ANY);
+	    } /* switch(phase) */
+	} /* if (tmp * SR_REQ) */ 
+    } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected 
+ *	field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q 
+ *	nexus has been reestablished,
+ *	
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+/* it might eventually prove necessary to do a dma setup on
+   reselection, but it doesn't seem to be needed now -- sam */
+
+static void NCR5380_reselect (struct Scsi_Host *instance)
+{
+    SETUP_HOSTDATA(instance);
+    unsigned char target_mask;
+    unsigned char lun;
+#ifdef SUPPORT_TAGS
+    unsigned char tag;
+#endif
+    unsigned char msg[3];
+    Scsi_Cmnd *tmp = NULL, *prev;
+/*    unsigned long flags; */
+
+    /*
+     * Disable arbitration, etc. since the host adapter obviously
+     * lost, and tell an interrupted NCR5380_select() to restart.
+     */
+
+    NCR5380_write(MODE_REG, MR_BASE);
+    hostdata->restart_select = 1;
+
+    target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+    RSL_PRINTK("scsi%d: reselect\n", HOSTNO);
+
+    /* 
+     * At this point, we have detected that our SCSI ID is on the bus,
+     * SEL is true and BSY was false for at least one bus settle delay
+     * (400 ns).
+     *
+     * We must assert BSY ourselves, until the target drops the SEL
+     * signal.
+     */
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+    
+    while (NCR5380_read(STATUS_REG) & SR_SEL);
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+    /*
+     * Wait for target to go into MSGIN.
+     */
+
+    while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if 1
+    // acknowledge toggle to MSGIN
+    NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
+
+    // peek at the byte without really hitting the bus
+    msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
+#endif
+
+    if (!(msg[0] & 0x80)) {
+	printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
+	print_msg(msg);
+	do_abort(instance);
+	return;
+    }
+    lun = (msg[0] & 0x07);
+
+    /* 
+     * Find the command corresponding to the I_T_L or I_T_L_Q  nexus we 
+     * just reestablished, and remove it from the disconnected queue.
+     */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; 
+	 tmp; prev = tmp, tmp = NEXT(tmp) ) {
+	if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
+#ifdef SUPPORT_TAGS
+	    && (tag == tmp->tag) 
+#endif
+	    ) {
+	    if (prev) {
+		REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
+		NEXT(prev) = NEXT(tmp);
+	    } else {
+		REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
+		hostdata->disconnected_queue = NEXT(tmp);
+	    }
+	    NEXT(tmp) = NULL;
+	    break;
+	}
+    }
+    
+    if (!tmp) {
+	printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
+#ifdef SUPPORT_TAGS
+		"tag %d "
+#endif
+		"not in disconnected_queue.\n",
+		HOSTNO, target_mask, lun
+#ifdef SUPPORT_TAGS
+		, tag
+#endif
+		);
+	/* 
+	 * Since we have an established nexus that we can't do anything
+	 * with, we must abort it.  
+	 */
+	do_abort(instance);
+	return;
+    }
+#if 1
+    /* engage dma setup for the command we just saw */
+    {
+	    void *d;
+	    unsigned long count;
+
+	    if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
+		    count = tmp->SCp.buffer->length;
+		    d = SGADDR(tmp->SCp.buffer);
+	    } else {
+		    count = tmp->SCp.this_residual;
+		    d = tmp->SCp.ptr;
+	    }
+#ifdef REAL_DMA
+	    /* setup this command for dma if not already */
+	    if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != tmp))
+	    {
+		    sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
+		    sun3_dma_setup_done = tmp;
+	    }
+#endif
+    }
+#endif
+
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+    /* Accept message by clearing ACK */
+    NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+#ifdef SUPPORT_TAGS
+    /* If the phase is still MSGIN, the target wants to send some more
+     * messages. In case it supports tagged queuing, this is probably a
+     * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+     */
+    tag = TAG_NONE;
+    if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+	/* Accept previous IDENTIFY message by clearing ACK */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	len = 2;
+	data = msg+1;
+	if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+	    msg[1] == SIMPLE_QUEUE_TAG)
+	    tag = msg[2];
+	TAG_PRINTK("scsi%d: target mask %02x, lun %d sent tag %d at "
+		   "reselection\n", HOSTNO, target_mask, lun, tag);
+    }
+#endif
+    
+    hostdata->connected = tmp;
+    RSL_PRINTK("scsi%d: nexus established, target = %d, lun = %d, tag = %d\n",
+	       HOSTNO, tmp->target, tmp->lun, tmp->tag);
+}
+
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the 
+ * 	host byte of the result field to, if zero DID_ABORTED is 
+ *	used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently 
+ * 	 connected, you have to wait for it to complete.  If this is 
+ *	 a problem, we could implement longjmp() / setjmp(), setjmp()
+ * 	 called where the loop started in NCR5380_main().
+ */
+
+static int NCR5380_abort (Scsi_Cmnd *cmd)
+{
+    struct Scsi_Host *instance = cmd->device->host;
+    SETUP_HOSTDATA(instance);
+    Scsi_Cmnd *tmp, **prev;
+    unsigned long flags;
+
+    printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
+    print_Scsi_Cmnd (cmd);
+
+    NCR5380_print_status (instance);
+
+    local_irq_save(flags);
+    
+    ABRT_PRINTK("scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
+		NCR5380_read(BUS_AND_STATUS_REG),
+		NCR5380_read(STATUS_REG));
+
+#if 1
+/* 
+ * Case 1 : If the command is the currently executing command, 
+ * we'll set the aborted flag and return control so that 
+ * information transfer routine can exit cleanly.
+ */
+
+    if (hostdata->connected == cmd) {
+
+	ABRT_PRINTK("scsi%d: aborting connected command\n", HOSTNO);
+/*
+ * We should perform BSY checking, and make sure we haven't slipped
+ * into BUS FREE.
+ */
+
+/*	NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
+/* 
+ * Since we can't change phases until we've completed the current 
+ * handshake, we have to source or sink a byte of data if the current
+ * phase is not MSGOUT.
+ */
+
+/* 
+ * Return control to the executing NCR drive so we can clear the
+ * aborted flag and get back into our main loop.
+ */ 
+
+	if (do_abort(instance) == 0) {
+	  hostdata->aborted = 1;
+	  hostdata->connected = NULL;
+	  cmd->result = DID_ABORT << 16;
+#ifdef SUPPORT_TAGS
+	  cmd_free_tag( cmd );
+#else
+	  hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+	  local_irq_restore(flags);
+	  cmd->scsi_done(cmd);
+	  return SCSI_ABORT_SUCCESS;
+	} else {
+/*	  local_irq_restore(flags); */
+	  printk("scsi%d: abort of connected command failed!\n", HOSTNO);
+	  return SCSI_ABORT_ERROR;
+	} 
+   }
+#endif
+
+/* 
+ * Case 2 : If the command hasn't been issued yet, we simply remove it 
+ * 	    from the issue queue.
+ */
+    for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue), 
+	tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+	tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+	if (cmd == tmp) {
+	    REMOVE(5, *prev, tmp, NEXT(tmp));
+	    (*prev) = NEXT(tmp);
+	    NEXT(tmp) = NULL;
+	    tmp->result = DID_ABORT << 16;
+	    local_irq_restore(flags);
+	    ABRT_PRINTK("scsi%d: abort removed command from issue queue.\n",
+			HOSTNO);
+	    /* Tagged queuing note: no tag to free here, hasn't been assigned
+	     * yet... */
+	    tmp->scsi_done(tmp);
+	    return SCSI_ABORT_SUCCESS;
+	}
+
+/* 
+ * Case 3 : If any commands are connected, we're going to fail the abort
+ *	    and let the high level SCSI driver retry at a later time or 
+ *	    issue a reset.
+ *
+ *	    Timeouts, and therefore aborted commands, will be highly unlikely
+ *          and handling them cleanly in this situation would make the common
+ *	    case of noresets less efficient, and would pollute our code.  So,
+ *	    we fail.
+ */
+
+    if (hostdata->connected) {
+	local_irq_restore(flags);
+	ABRT_PRINTK("scsi%d: abort failed, command connected.\n", HOSTNO);
+        return SCSI_ABORT_SNOOZE;
+    }
+
+/*
+ * Case 4: If the command is currently disconnected from the bus, and 
+ * 	there are no connected commands, we reconnect the I_T_L or 
+ *	I_T_L_Q nexus associated with it, go into message out, and send 
+ *      an abort message.
+ *
+ * This case is especially ugly. In order to reestablish the nexus, we
+ * need to call NCR5380_select().  The easiest way to implement this 
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we 
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that 
+ * device reselected.
+ * 
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+    for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+	 tmp = NEXT(tmp)) 
+        if (cmd == tmp) {
+            local_irq_restore(flags);
+	    ABRT_PRINTK("scsi%d: aborting disconnected command.\n", HOSTNO);
+  
+            if (NCR5380_select (instance, cmd, (int) cmd->tag)) 
+		return SCSI_ABORT_BUSY;
+
+	    ABRT_PRINTK("scsi%d: nexus reestablished.\n", HOSTNO);
+
+	    do_abort (instance);
+
+	    local_irq_save(flags);
+	    for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue), 
+		tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+		tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
+		    if (cmd == tmp) {
+		    REMOVE(5, *prev, tmp, NEXT(tmp));
+		    *prev = NEXT(tmp);
+		    NEXT(tmp) = NULL;
+		    tmp->result = DID_ABORT << 16;
+		    /* We must unlock the tag/LUN immediately here, since the
+		     * target goes to BUS FREE and doesn't send us another
+		     * message (COMMAND_COMPLETE or the like)
+		     */
+#ifdef SUPPORT_TAGS
+		    cmd_free_tag( tmp );
+#else
+		    hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+#endif
+		    local_irq_restore(flags);
+		    tmp->scsi_done(tmp);
+		    return SCSI_ABORT_SUCCESS;
+		}
+	}
+
+/*
+ * Case 5 : If we reached this point, the command was not found in any of 
+ *	    the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+    local_irq_restore(flags);
+    printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully\n"
+           KERN_INFO "        before abortion\n", HOSTNO); 
+
+    return SCSI_ABORT_NOT_RUNNING;
+}
+
+
+/* 
+ * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
+ * 
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : SCSI_RESET_WAKEUP
+ *
+ */ 
+
+static int NCR5380_bus_reset( Scsi_Cmnd *cmd)
+{
+    SETUP_HOSTDATA(cmd->device->host);
+    int           i;
+    unsigned long flags;
+#if 1
+    Scsi_Cmnd *connected, *disconnected_queue;
+#endif
+
+
+    NCR5380_print_status (cmd->device->host);
+
+    /* get in phase */
+    NCR5380_write( TARGET_COMMAND_REG,
+		   PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+    /* assert RST */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+    udelay (40);
+    /* reset NCR registers */
+    NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+    NCR5380_write( MODE_REG, MR_BASE );
+    NCR5380_write( TARGET_COMMAND_REG, 0 );
+    NCR5380_write( SELECT_ENABLE_REG, 0 );
+    /* ++roman: reset interrupt condition! otherwise no interrupts don't get
+     * through anymore ... */
+    (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+#if 1 /* XXX Should now be done by midlevel code, but it's broken XXX */
+      /* XXX see below                                            XXX */
+
+    /* MSch: old-style reset: actually abort all command processing here */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; to avoid problems with re-inserting the commands
+     * into the issue_queue (via scsi_done()), the aborted commands are
+     * remembered in local variables first.
+     */
+    local_irq_save(flags);
+    connected = (Scsi_Cmnd *)hostdata->connected;
+    hostdata->connected = NULL;
+    disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    local_irq_restore(flags);
+
+    /* In order to tell the mid-level code which commands were aborted, 
+     * set the command status to DID_RESET and call scsi_done() !!!
+     * This ultimately aborts processing of these commands in the mid-level.
+     */
+
+    if ((cmd = connected)) {
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+
+    for (i = 0; (cmd = disconnected_queue); ++i) {
+	disconnected_queue = NEXT(cmd);
+	NEXT(cmd) = NULL;
+	cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
+	cmd->scsi_done( cmd );
+    }
+    if (i > 0)
+	ABRT_PRINTK("scsi: reset aborted %d disconnected command(s)\n", i);
+
+
+    /* since all commands have been explicitly terminated, we need to tell
+     * the midlevel code that the reset was SUCCESSFUL, and there is no 
+     * need to 'wake up' the commands by a request_sense
+     */
+    return SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET;
+#else /* 1 */
+
+    /* MSch: new-style reset handling: let the mid-level do what it can */
+
+    /* ++guenther: MID-LEVEL IS STILL BROKEN.
+     * Mid-level is supposed to requeue all commands that were active on the
+     * various low-level queues. In fact it does this, but that's not enough
+     * because all these commands are subject to timeout. And if a timeout
+     * happens for any removed command, *_abort() is called but all queues
+     * are now empty. Abort then gives up the falcon lock, which is fatal,
+     * since the mid-level will queue more commands and must have the lock
+     * (it's all happening inside timer interrupt handler!!).
+     * Even worse, abort will return NOT_RUNNING for all those commands not
+     * on any queue, so they won't be retried ...
+     *
+     * Conclusion: either scsi.c disables timeout for all resetted commands
+     * immediately, or we lose!  As of linux-2.0.20 it doesn't.
+     */
+
+    /* After the reset, there are no more connected or disconnected commands
+     * and no busy units; so clear the low-level status here to avoid 
+     * conflicts when the mid-level code tries to wake up the affected 
+     * commands!
+     */
+
+    if (hostdata->issue_queue)
+	ABRT_PRINTK("scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
+    if (hostdata->connected) 
+	ABRT_PRINTK("scsi%d: reset aborted a connected command\n", H_NO(cmd));
+    if (hostdata->disconnected_queue)
+	ABRT_PRINTK("scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
+
+    local_irq_save(flags);
+    hostdata->issue_queue = NULL;
+    hostdata->connected = NULL;
+    hostdata->disconnected_queue = NULL;
+#ifdef SUPPORT_TAGS
+    free_all_tags();
+#endif
+    for( i = 0; i < 8; ++i )
+	hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+    hostdata->dma_len = 0;
+#endif
+    local_irq_restore(flags);
+
+    /* we did no complete reset of all commands, so a wakeup is required */
+    return SCSI_RESET_WAKEUP | SCSI_RESET_BUS_RESET;
+#endif /* 1 */
+}
+
+/* Local Variables: */
+/* tab-width: 8     */
+/* End:             */
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
new file mode 100644
index 0000000..e3ea99f
--- /dev/null
+++ b/drivers/scsi/sun3_scsi.c
@@ -0,0 +1,642 @@
+/*
+ * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
+ *
+ * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
+ *
+ * Adapted from mac_scsinew.c:
+ */
+/*
+ * Generic Macintosh NCR5380 driver
+ *
+ * Copyright 1998, Michael Schmitz <mschmitz@lbl.gov>
+ *
+ * derived in part from:
+ */
+/*
+ * Generic Generic NCR5380 driver
+ *
+ * Copyright 1995, Russell King
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+
+/*
+ * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :)
+ *
+ * Options :
+ *
+ * PARITY - enable parity checking.  Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
+ *
+ * USLEEP - enable support for devices that don't disconnect.  Untested.
+ */
+
+/*
+ * $Log: sun3_NCR5380.c,v $
+ */
+
+#define AUTOSENSE
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/sun3ints.h>
+#include <asm/dvma.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+/* dma on! */
+#define REAL_DMA
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "sun3_scsi.h"
+#include "NCR5380.h"
+
+static void NCR5380_print(struct Scsi_Host *instance);
+
+/* #define OLDDMA */
+
+#define USE_WRAPPER
+/*#define RESET_BOOT */
+#define DRIVER_SETUP
+
+#define NDEBUG 0
+
+/*
+ * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
+ */
+#ifdef BUG
+#undef RESET_BOOT
+#undef DRIVER_SETUP
+#endif
+
+/* #define SUPPORT_TAGS */
+
+#define	ENABLE_IRQ()	enable_irq( IRQ_SUN3_SCSI ); 
+
+
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
+
+static int setup_can_queue = -1;
+module_param(setup_can_queue, int, 0);
+static int setup_cmd_per_lun = -1;
+module_param(setup_cmd_per_lun, int, 0);
+static int setup_sg_tablesize = -1;
+module_param(setup_sg_tablesize, int, 0);
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+module_param(setup_use_tagged_queuing, int, 0);
+#endif
+static int setup_hostid = -1;
+module_param(setup_hostid, int, 0);
+
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
+
+#define	AFTER_RESET_DELAY	(HZ/2)
+
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 10
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to do dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+#ifdef OLDDMA
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+#endif
+static struct sun3_udc_regs *udc_regs = NULL;
+static unsigned char *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
+static unsigned long last_residual = 0;
+
+/*
+ * NCR 5380 register access functions
+ */
+
+static inline unsigned char sun3scsi_read(int reg)
+{
+	return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+	sun3_scsi_regp[reg] = value;
+}
+
+/* dma controller register access functions */
+
+static inline unsigned short sun3_udc_read(unsigned char reg)
+{
+	unsigned short ret;
+
+	dregs->udc_addr = UDC_CSR;
+	udelay(SUN3_DMA_DELAY);
+	ret = dregs->udc_data;
+	udelay(SUN3_DMA_DELAY);
+	
+	return ret;
+}
+
+static inline void sun3_udc_write(unsigned short val, unsigned char reg)
+{
+	dregs->udc_addr = reg;
+	udelay(SUN3_DMA_DELAY);
+	dregs->udc_data = val;
+	udelay(SUN3_DMA_DELAY);
+}
+
+/*
+ * XXX: status debug
+ */
+static struct Scsi_Host *default_instance;
+
+/*
+ * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : initializes mac NCR5380 driver based on the
+ *	command line / compile time port and irq definitions.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+ 
+int sun3scsi_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned long ioaddr;
+	static int called = 0;
+	struct Scsi_Host *instance;
+
+	/* check that this machine has an onboard 5380 */
+	switch(idprom->id_machtype) {
+	case SM_SUN3|SM_3_50:
+	case SM_SUN3|SM_3_60:
+		break;
+
+	default:
+		return 0;
+	}
+
+	if(called)
+		return 0;
+
+	tpnt->proc_name = "Sun3 5380 SCSI";
+
+	/* setup variables */
+	tpnt->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+	tpnt->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+	tpnt->sg_tablesize = 
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+
+	if (setup_hostid >= 0)
+		tpnt->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		tpnt->this_id = 7;
+	}
+
+	ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
+	sun3_scsi_regp = (unsigned char *)ioaddr;
+
+	dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+
+	if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
+	   == NULL) {
+	     printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+	     return 0;
+	}
+#ifdef OLDDMA
+	if((dmabuf = dvma_malloc_align(SUN3_DVMA_BUFSIZE, 0x10000)) == NULL) {
+	     printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
+	     return 0;
+	}
+#endif
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = USE_TAGGED_QUEUING;
+#endif
+
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if(instance == NULL)
+		return 0;
+		
+	default_instance = instance;
+
+        instance->io_port = (unsigned long) ioaddr;
+	instance->irq = IRQ_SUN3_SCSI;
+
+	NCR5380_init(instance, 0);
+
+	instance->n_io_port = 32;
+
+        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+
+	if (request_irq(instance->irq, scsi_sun3_intr,
+			     0, "Sun3SCSI-5380", NULL)) {
+#ifndef REAL_DMA
+		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+		       instance->host_no, instance->irq);
+		instance->irq = SCSI_IRQ_NONE;
+#else
+		printk("scsi%d: IRQ%d not free, bailing out\n",
+		       instance->host_no, instance->irq);
+		return 0;
+#endif
+	}
+	
+	printk("scsi%d: Sun3 5380 at port %lX irq", instance->host_no, instance->io_port);
+	if (instance->irq == SCSI_IRQ_NONE)
+		printk ("s disabled");
+	else
+		printk (" %d", instance->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	       instance->can_queue, instance->cmd_per_lun,
+	       SUN3SCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", instance->host_no);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	dregs->csr = 0;
+	udelay(SUN3_DMA_DELAY);
+	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+	udelay(SUN3_DMA_DELAY);
+	dregs->fifo_count = 0;
+
+	called = 1;
+
+#ifdef RESET_BOOT
+	sun3_scsi_reset_boot(instance);
+#endif
+
+	return 1;
+}
+
+int sun3scsi_release (struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq != SCSI_IRQ_NONE)
+		free_irq (shpnt->irq, NULL);
+
+	iounmap((void *)sun3_scsi_regp);
+
+	return 0;
+}
+
+#ifdef RESET_BOOT
+/*
+ * Our 'bus reset on boot' function
+ */
+
+static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
+{
+	unsigned long end;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No
+	 * messing with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Sun3 SCSI: resetting the SCSI bus..." );
+
+	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
+//       	sun3_disable_irq( IRQ_SUN3_SCSI );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
+		barrier();
+
+	/* switch on SCSI IRQ again */
+//       	sun3_enable_irq( IRQ_SUN3_SCSI );
+
+	printk( " done\n" );
+}
+#endif
+
+const char * sun3scsi_info (struct Scsi_Host *spnt) {
+    return "";
+}
+
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
+
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned short csr = dregs->csr;
+	int handled = 0;
+
+	if(csr & ~CSR_GOOD) {
+		if(csr & CSR_DMA_BUSERR) {
+			printk("scsi%d: bus error in dma\n", default_instance->host_no);
+		}
+
+		if(csr & CSR_DMA_CONFLICT) {
+			printk("scsi%d: dma conflict\n", default_instance->host_no);
+		}
+		handled = 1;
+	}
+
+	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
+		NCR5380_intr(irq, dummy, fp);
+		handled = 1;
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+/*
+ * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
+ * reentering NCR5380_print_status seems to have ugly side effects
+ */
+
+/* this doesn't seem to get used at all -- sam */
+#if 0
+void sun3_sun3_debug (void)
+{
+	unsigned long flags;
+	NCR5380_local_declare();
+
+	if (default_instance) {
+			local_irq_save(flags);
+			NCR5380_print_status(default_instance);
+			local_irq_restore(flags);
+	}
+}
+#endif
+
+
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+{
+#ifdef OLDDMA
+	if(write_flag) 
+		memcpy(dmabuf, data, count);
+	else {
+		sun3_dma_orig_addr = data;
+		sun3_dma_orig_count = count;
+	}
+#else
+	void *addr;
+
+	if(sun3_dma_orig_addr != NULL)
+		dvma_unmap(sun3_dma_orig_addr);
+
+//	addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
+	addr = (void *)dvma_map((unsigned long) data, count);
+		
+	sun3_dma_orig_addr = addr;
+	sun3_dma_orig_count = count;
+#endif
+	dregs->fifo_count = 0;
+	sun3_udc_write(UDC_RESET, UDC_CSR);
+	
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+	/* set direction */
+	if(write_flag)
+		dregs->csr |= CSR_SEND;
+	else
+		dregs->csr &= ~CSR_SEND;
+	
+	/* byte count for fifo */
+	dregs->fifo_count = count;
+
+	sun3_udc_write(UDC_RESET, UDC_CSR);
+	
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+	if(dregs->fifo_count != count) { 
+		printk("scsi%d: fifo_mismatch %04x not %04x\n",
+		       default_instance->host_no, dregs->fifo_count,
+		       (unsigned int) count);
+		NCR5380_print(default_instance);
+	}
+
+	/* setup udc */
+#ifdef OLDDMA
+	udc_regs->addr_hi = ((dvma_vtob(dmabuf) & 0xff0000) >> 8);
+	udc_regs->addr_lo = (dvma_vtob(dmabuf) & 0xffff);
+#else
+	udc_regs->addr_hi = (((unsigned long)(addr) & 0xff0000) >> 8);
+	udc_regs->addr_lo = ((unsigned long)(addr) & 0xffff);
+#endif
+	udc_regs->count = count/2; /* count in words */
+	udc_regs->mode_hi = UDC_MODE_HIWORD;
+	if(write_flag) {
+		if(count & 1)
+			udc_regs->count++;
+		udc_regs->mode_lo = UDC_MODE_LSEND;
+		udc_regs->rsel = UDC_RSEL_SEND;
+	} else {
+		udc_regs->mode_lo = UDC_MODE_LRECV;
+		udc_regs->rsel = UDC_RSEL_RECV;
+	}
+	
+	/* announce location of regs block */
+	sun3_udc_write(((dvma_vtob(udc_regs) & 0xff0000) >> 8),
+		       UDC_CHN_HI); 
+
+	sun3_udc_write((dvma_vtob(udc_regs) & 0xffff), UDC_CHN_LO);
+
+	/* set dma master on */
+	sun3_udc_write(0xd, UDC_MODE);
+
+	/* interrupt enable */
+	sun3_udc_write(UDC_INT_ENABLE, UDC_CSR);
+	
+       	return count;
+
+}
+
+static inline unsigned long sun3scsi_dma_count(struct Scsi_Host *instance)
+{
+	unsigned short resid;
+
+	dregs->udc_addr = 0x32; 
+	udelay(SUN3_DMA_DELAY);
+	resid = dregs->udc_data;
+	udelay(SUN3_DMA_DELAY);
+	resid *= 2;
+
+	return (unsigned long) resid;
+}
+
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+	return last_residual;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+				    int write_flag)
+{
+	if(cmd->request->flags & REQ_CMD)
+ 		return wanted;
+	else
+		return 0;
+}
+
+static inline int sun3scsi_dma_start(unsigned long count, unsigned char *data)
+{
+
+    sun3_udc_write(UDC_CHN_START, UDC_CSR);
+    
+    return 0;
+}
+
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(int write_flag)
+{
+	unsigned short count;
+	unsigned short fifo;
+	int ret = 0;
+	
+	sun3_dma_active = 0;
+#if 1
+	// check to empty the fifo on a read
+	if(!write_flag) {
+		int tmo = 20000; /* .2 sec */
+		
+		while(1) {
+			if(dregs->csr & CSR_FIFO_EMPTY)
+				break;
+
+			if(--tmo <= 0) {
+				printk("sun3scsi: fifo failed to empty!\n");
+				return 1;
+			}
+			udelay(10);
+		}
+	}
+		
+#endif
+
+	count = sun3scsi_dma_count(default_instance);
+#ifdef OLDDMA
+
+	/* if we've finished a read, copy out the data we read */
+ 	if(sun3_dma_orig_addr) {
+		/* check for residual bytes after dma end */
+		if(count && (NCR5380_read(BUS_AND_STATUS_REG) &
+			     (BASR_PHASE_MATCH | BASR_ACK))) {
+			printk("scsi%d: sun3_scsi_finish: read overrun baby... ", default_instance->host_no);
+			printk("basr now %02x\n", NCR5380_read(BUS_AND_STATUS_REG));
+			ret = count;
+		}
+		
+		/* copy in what we dma'd no matter what */
+		memcpy(sun3_dma_orig_addr, dmabuf, sun3_dma_orig_count);
+		sun3_dma_orig_addr = NULL;
+
+	}
+#else
+
+	fifo = dregs->fifo_count;
+	last_residual = fifo;
+
+	/* empty bytes from the fifo which didn't make it */
+	if((!write_flag) && (count - fifo) == 2) {
+		unsigned short data;
+		unsigned char *vaddr;
+
+		data = dregs->fifo_data;
+		vaddr = (unsigned char *)dvma_btov(sun3_dma_orig_addr);
+		
+		vaddr += (sun3_dma_orig_count - fifo);
+
+		vaddr[-2] = (data & 0xff00) >> 8;
+		vaddr[-1] = (data & 0xff);
+	}
+
+	dvma_unmap(sun3_dma_orig_addr);
+	sun3_dma_orig_addr = NULL;
+#endif
+	sun3_udc_write(UDC_RESET, UDC_CSR);
+	dregs->fifo_count = 0;
+	dregs->csr &= ~CSR_SEND;
+
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+	
+	sun3_dma_setup_done = NULL;
+
+	return ret;
+
+}
+	
+#include "sun3_NCR5380.c"
+
+static Scsi_Host_Template driver_template = {
+	.name			= SUN3_SCSI_NAME,
+	.detect			= sun3scsi_detect,
+	.release		= sun3scsi_release,
+	.info			= sun3scsi_info,
+	.queuecommand		= sun3scsi_queue_command,
+	.eh_abort_handler      	= sun3scsi_abort,
+	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_TABLESIZE,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
new file mode 100644
index 0000000..155282b
--- /dev/null
+++ b/drivers/scsi/sun3_scsi.h
@@ -0,0 +1,379 @@
+/*
+ * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
+ *
+ * Sun3 DMA additions by Sam Creasey (sammy@sammy.net)
+ *
+ * Adapted from mac_scsinew.h:
+ */
+/*
+ * Cumana Generic NCR5380 driver defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: cumana_NCR5380.h,v $
+ */
+
+#ifndef SUN3_NCR5380_H
+#define SUN3_NCR5380_H
+
+#define SUN3SCSI_PUBLIC_RELEASE 1
+
+/*
+ * Int: level 2 autovector
+ * IO: type 1, base 0x00140000, 5 bits phys space: A<4..0>
+ */
+#define IRQ_SUN3_SCSI 2
+#define IOBASE_SUN3_SCSI 0x00140000
+
+#define IOBASE_SUN3_VMESCSI 0xff200000
+
+static int sun3scsi_abort (Scsi_Cmnd *);
+static int sun3scsi_detect (Scsi_Host_Template *);
+static const char *sun3scsi_info (struct Scsi_Host *);
+static int sun3scsi_bus_reset(Scsi_Cmnd *);
+static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sun3scsi_release (struct Scsi_Host *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifndef SG_TABLESIZE
+#define SG_TABLESIZE SG_NONE
+#endif
+
+#ifndef MAX_TAGS
+#define MAX_TAGS 32
+#endif
+
+#ifndef USE_TAGGED_QUEUING
+#define	USE_TAGGED_QUEUING 1
+#endif
+
+#include <scsi/scsicam.h>
+
+#ifdef SUN3_SCSI_VME
+#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI"
+#else
+#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
+#endif
+
+#ifndef HOSTS_C
+
+#define NCR5380_implementation_fields \
+    int port, ctrl
+
+#define NCR5380_local_declare() \
+        struct Scsi_Host *_instance
+
+#define NCR5380_setup(instance) \
+        _instance = instance
+
+#define NCR5380_read(reg) sun3scsi_read(reg)
+#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
+
+#define NCR5380_intr sun3scsi_intr
+#define NCR5380_queue_command sun3scsi_queue_command
+#define NCR5380_bus_reset sun3scsi_bus_reset
+#define NCR5380_abort sun3scsi_abort
+#define NCR5380_proc_info sun3scsi_proc_info
+#define NCR5380_dma_xfer_len(i, cmd, phase) \
+        sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
+
+#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1)
+#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0)
+#define NCR5380_dma_residual sun3scsi_dma_residual
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+/* additional registers - mainly DMA control regs */
+/* these start at regbase + 8 -- directly after the NCR regs */
+struct sun3_dma_regs {
+	unsigned short dma_addr_hi; /* vme only */
+	unsigned short dma_addr_lo; /* vme only */
+	unsigned short dma_count_hi; /* vme only */
+	unsigned short dma_count_lo; /* vme only */
+	unsigned short udc_data; /* udc dma data reg (obio only) */
+	unsigned short udc_addr; /* uda dma addr reg (obio only) */
+	unsigned short fifo_data; /* fifo data reg, holds extra byte on
+				     odd dma reads */
+	unsigned short fifo_count; 
+	unsigned short csr; /* control/status reg */
+	unsigned short bpack_hi; /* vme only */
+	unsigned short bpack_lo; /* vme only */
+	unsigned short ivect; /* vme only */
+	unsigned short fifo_count_hi; /* vme only */
+};
+
+/* ucd chip specific regs - live in dvma space */
+struct sun3_udc_regs {
+     unsigned short rsel; /* select regs to load */
+     unsigned short addr_hi; /* high word of addr */
+     unsigned short addr_lo; /* low word */
+     unsigned short count; /* words to be xfer'd */
+     unsigned short mode_hi; /* high word of channel mode */
+     unsigned short mode_lo; /* low word of channel mode */
+};
+
+/* addresses of the udc registers */
+#define UDC_MODE 0x38 
+#define UDC_CSR 0x2e /* command/status */
+#define UDC_CHN_HI 0x26 /* chain high word */
+#define UDC_CHN_LO 0x22 /* chain lo word */
+#define UDC_CURA_HI 0x1a /* cur reg A high */
+#define UDC_CURA_LO 0x0a /* cur reg A low */
+#define UDC_CURB_HI 0x12 /* cur reg B high */
+#define UDC_CURB_LO 0x02 /* cur reg B low */
+#define UDC_MODE_HI 0x56 /* mode reg high */
+#define UDC_MODE_LO 0x52 /* mode reg low */
+#define UDC_COUNT 0x32 /* words to xfer */
+
+/* some udc commands */
+#define UDC_RESET 0
+#define UDC_CHN_START 0xa0 /* start chain */
+#define UDC_INT_ENABLE 0x32 /* channel 1 int on */
+
+/* udc mode words */
+#define UDC_MODE_HIWORD 0x40
+#define UDC_MODE_LSEND 0xc2
+#define UDC_MODE_LRECV 0xd2
+
+/* udc reg selections */
+#define UDC_RSEL_SEND 0x282
+#define UDC_RSEL_RECV 0x182
+
+/* bits in csr reg */
+#define CSR_DMA_ACTIVE 0x8000
+#define CSR_DMA_CONFLICT 0x4000
+#define CSR_DMA_BUSERR 0x2000
+
+#define CSR_FIFO_EMPTY 0x400 /* fifo flushed? */
+#define CSR_SDB_INT 0x200 /* sbc interrupt pending */
+#define CSR_DMA_INT 0x100 /* dma interrupt pending */
+
+#define CSR_LEFT 0xc0
+#define CSR_LEFT_3 0xc0
+#define CSR_LEFT_2 0x80
+#define CSR_LEFT_1 0x40
+#define CSR_PACK_ENABLE 0x20
+
+#define CSR_DMA_ENABLE 0x10
+
+#define CSR_SEND 0x8 /* 1 = send  0 = recv */
+#define CSR_FIFO 0x2 /* reset fifo */
+#define CSR_INTR 0x4 /* interrupt enable */
+#define CSR_SCSI 0x1 
+
+#define VME_DATA24 0x3d00
+
+// debugging printk's, taken from atari_scsi.h 
+/* Debugging printk definitions:
+ *
+ *  ARB  -> arbitration
+ *  ASEN -> auto-sense
+ *  DMA  -> DMA
+ *  HSH  -> PIO handshake
+ *  INF  -> information transfer
+ *  INI  -> initialization
+ *  INT  -> interrupt
+ *  LNK  -> linked commands
+ *  MAIN -> NCR5380_main() control flow
+ *  NDAT -> no data-out phase
+ *  NWR  -> no write commands
+ *  PIO  -> PIO transfers
+ *  PDMA -> pseudo DMA (unused on Atari)
+ *  QU   -> queues
+ *  RSL  -> reselections
+ *  SEL  -> selections
+ *  USL  -> usleep cpde (unused on Atari)
+ *  LBS  -> last byte sent (unused on Atari)
+ *  RSS  -> restarting of selections
+ *  EXT  -> extended messages
+ *  ABRT -> aborting and resetting
+ *  TAG  -> queue tag handling
+ *  MER  -> merging of consec. buffers
+ *
+ */
+
+
+
+#if NDEBUG & NDEBUG_ARBITRATION
+#define ARB_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ARB_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_AUTOSENSE
+#define ASEN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ASEN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_DMA
+#define DMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define DMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_HANDSHAKE
+#define HSH_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define HSH_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INFORMATION
+#define INF_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INF_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INIT
+#define INI_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INI_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_INTR
+#define INT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define INT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LINKED
+#define LNK_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LNK_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MAIN
+#define MAIN_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MAIN_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_DATAOUT
+#define NDAT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NDAT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_NO_WRITE
+#define NWR_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define NWR_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PIO
+#define PIO_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PIO_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_PSEUDO_DMA
+#define PDMA_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define PDMA_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_QUEUES
+#define QU_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define QU_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESELECTION
+#define RSL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_SELECTION
+#define SEL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define SEL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_USLEEP
+#define USL_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define USL_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_LAST_BYTE_SENT
+#define LBS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define LBS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_RESTART_SELECT
+#define RSS_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define RSS_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_EXTENDED
+#define EXT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define EXT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_ABORT
+#define ABRT_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define ABRT_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_TAGS
+#define TAG_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define TAG_PRINTK(format, args...)
+#endif
+#if NDEBUG & NDEBUG_MERGING
+#define MER_PRINTK(format, args...) \
+	printk(KERN_DEBUG format , ## args)
+#else
+#define MER_PRINTK(format, args...)
+#endif
+
+/* conditional macros for NCR5380_print_{,phase,status} */
+
+#define NCR_PRINT(mask)	\
+	((NDEBUG & (mask)) ? NCR5380_print(instance) : (void)0)
+
+#define NCR_PRINT_PHASE(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_phase(instance) : (void)0)
+
+#define NCR_PRINT_STATUS(mask) \
+	((NDEBUG & (mask)) ? NCR5380_print_status(instance) : (void)0)
+
+
+
+#endif /* ndef HOSTS_C */
+#endif /* SUN3_NCR5380_H */
+
diff --git a/drivers/scsi/sun3_scsi_vme.c b/drivers/scsi/sun3_scsi_vme.c
new file mode 100644
index 0000000..9acb5dd
--- /dev/null
+++ b/drivers/scsi/sun3_scsi_vme.c
@@ -0,0 +1,584 @@
+ /*
+ * Sun3 SCSI stuff by Erik Verbruggen (erik@bigmama.xtdnet.nl)
+ *
+ * Sun3 DMA routines added by Sam Creasey (sammy@sammy.net)
+ *
+ * VME support added by Sam Creasey
+ *
+ * Adapted from sun3_scsi.c -- see there for other headers
+ *
+ * TODO: modify this driver to support multiple Sun3 SCSI VME boards
+ *
+ */
+
+#define AUTOSENSE
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/ctype.h>
+#include <linux/delay.h>
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <asm/sun3ints.h>
+#include <asm/dvma.h>
+#include <asm/idprom.h>
+#include <asm/machines.h>
+
+#define SUN3_SCSI_VME
+
+#undef SUN3_SCSI_DEBUG
+
+/* dma on! */
+#define REAL_DMA
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "sun3_scsi.h"
+#include "NCR5380.h"
+
+extern int sun3_map_test(unsigned long, char *);
+
+#define USE_WRAPPER
+/*#define RESET_BOOT */
+#define DRIVER_SETUP
+
+#define NDEBUG 0
+
+/*
+ * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
+ */
+#ifdef BUG
+#undef RESET_BOOT
+#undef DRIVER_SETUP
+#endif
+
+/* #define SUPPORT_TAGS */
+
+//#define	ENABLE_IRQ()	enable_irq( SUN3_VEC_VMESCSI0 ); 
+#define ENABLE_IRQ()
+
+
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp);
+static inline unsigned char sun3scsi_read(int reg);
+static inline void sun3scsi_write(int reg, int value);
+
+static int setup_can_queue = -1;
+module_param(setup_can_queue, int, 0);
+static int setup_cmd_per_lun = -1;
+module_param(setup_cmd_per_lun, int, 0);
+static int setup_sg_tablesize = -1;
+module_param(setup_sg_tablesize, int, 0);
+#ifdef SUPPORT_TAGS
+static int setup_use_tagged_queuing = -1;
+module_param(setup_use_tagged_queuing, int, 0);
+#endif
+static int setup_hostid = -1;
+module_param(setup_hostid, int, 0);
+
+static Scsi_Cmnd *sun3_dma_setup_done = NULL;
+
+#define	AFTER_RESET_DELAY	(HZ/2)
+
+/* ms to wait after hitting dma regs */
+#define SUN3_DMA_DELAY 10
+
+/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
+#define SUN3_DVMA_BUFSIZE 0xe000
+
+/* minimum number of bytes to do dma on */
+#define SUN3_DMA_MINSIZE 128
+
+static volatile unsigned char *sun3_scsi_regp;
+static volatile struct sun3_dma_regs *dregs;
+#ifdef OLDDMA
+static unsigned char *dmabuf = NULL; /* dma memory buffer */
+#endif
+static unsigned char *sun3_dma_orig_addr = NULL;
+static unsigned long sun3_dma_orig_count = 0;
+static int sun3_dma_active = 0;
+static unsigned long last_residual = 0;
+
+/*
+ * NCR 5380 register access functions
+ */
+
+static inline unsigned char sun3scsi_read(int reg)
+{
+	return( sun3_scsi_regp[reg] );
+}
+
+static inline void sun3scsi_write(int reg, int value)
+{
+	sun3_scsi_regp[reg] = value;
+}
+
+/*
+ * XXX: status debug
+ */
+static struct Scsi_Host *default_instance;
+
+/*
+ * Function : int sun3scsi_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : initializes mac NCR5380 driver based on the
+ *	command line / compile time port and irq definitions.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+ 
+static int sun3scsi_detect(Scsi_Host_Template * tpnt)
+{
+	unsigned long ioaddr, irq = 0;
+	static int called = 0;
+	struct Scsi_Host *instance;
+	int i;
+	unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI, 
+				   IOBASE_SUN3_VMESCSI + 0x4000,
+				   0 };
+	unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
+				  SUN3_VEC_VMESCSI1,
+				  0 };
+	/* check that this machine has an onboard 5380 */
+	switch(idprom->id_machtype) {
+	case SM_SUN3|SM_3_160:
+	case SM_SUN3|SM_3_260:
+		break;
+
+	default:
+		return 0;
+	}
+
+	if(called)
+		return 0;
+
+	tpnt->proc_name = "Sun3 5380 VME SCSI";
+
+	/* setup variables */
+	tpnt->can_queue =
+		(setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
+	tpnt->cmd_per_lun =
+		(setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
+	tpnt->sg_tablesize = 
+		(setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
+	
+	if (setup_hostid >= 0)
+		tpnt->this_id = setup_hostid;
+	else {
+		/* use 7 as default */
+		tpnt->this_id = 7;
+	}
+	
+	ioaddr = 0;
+	for(i = 0; addrs[i] != 0; i++) {
+		unsigned char x;
+		
+		ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
+						     SUN3_PAGE_TYPE_VME16);
+		irq = vecs[i];
+		sun3_scsi_regp = (unsigned char *)ioaddr;
+		
+		dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
+		
+		if(sun3_map_test((unsigned long)dregs, &x)) {
+			unsigned short oldcsr;
+
+			oldcsr = dregs->csr;
+			dregs->csr = 0;
+			udelay(SUN3_DMA_DELAY);
+			if(dregs->csr == 0x1400)
+				break;
+			
+			dregs->csr = oldcsr;
+		}
+
+		iounmap((void *)ioaddr);
+		ioaddr = 0;
+	}
+
+	if(!ioaddr)
+		return 0;
+	
+#ifdef SUPPORT_TAGS
+	if (setup_use_tagged_queuing < 0)
+		setup_use_tagged_queuing = USE_TAGGED_QUEUING;
+#endif
+
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if(instance == NULL)
+		return 0;
+		
+	default_instance = instance;
+
+        instance->io_port = (unsigned long) ioaddr;
+	instance->irq = irq;
+
+	NCR5380_init(instance, 0);
+
+	instance->n_io_port = 32;
+
+        ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
+
+	if (request_irq(instance->irq, scsi_sun3_intr,
+			     0, "Sun3SCSI-5380VME", NULL)) {
+#ifndef REAL_DMA
+		printk("scsi%d: IRQ%d not free, interrupts disabled\n",
+		       instance->host_no, instance->irq);
+		instance->irq = SCSI_IRQ_NONE;
+#else
+		printk("scsi%d: IRQ%d not free, bailing out\n",
+		       instance->host_no, instance->irq);
+		return 0;
+#endif
+	}
+
+	printk("scsi%d: Sun3 5380 VME at port %lX irq", instance->host_no, instance->io_port);
+	if (instance->irq == SCSI_IRQ_NONE)
+		printk ("s disabled");
+	else
+		printk (" %d", instance->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+	       instance->can_queue, instance->cmd_per_lun,
+	       SUN3SCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", instance->host_no);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	dregs->csr = 0;
+	udelay(SUN3_DMA_DELAY);
+	dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+	udelay(SUN3_DMA_DELAY);
+	dregs->fifo_count = 0;
+	dregs->fifo_count_hi = 0;
+	dregs->dma_addr_hi = 0;
+	dregs->dma_addr_lo = 0;
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+
+	dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
+
+	called = 1;
+
+#ifdef RESET_BOOT
+	sun3_scsi_reset_boot(instance);
+#endif
+
+	return 1;
+}
+
+int sun3scsi_release (struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq != SCSI_IRQ_NONE)
+		free_irq (shpnt->irq, NULL);
+
+	iounmap((void *)sun3_scsi_regp);
+
+	return 0;
+}
+
+#ifdef RESET_BOOT
+/*
+ * Our 'bus reset on boot' function
+ */
+
+static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
+{
+	unsigned long end;
+
+	NCR5380_local_declare();
+	NCR5380_setup(instance);
+	
+	/*
+	 * Do a SCSI reset to clean up the bus during initialization. No
+	 * messing with the queues, interrupts, or locks necessary here.
+	 */
+
+	printk( "Sun3 SCSI: resetting the SCSI bus..." );
+
+	/* switch off SCSI IRQ - catch an interrupt without IRQ bit set else */
+//       	sun3_disable_irq( IRQ_SUN3_SCSI );
+
+	/* get in phase */
+	NCR5380_write( TARGET_COMMAND_REG,
+		      PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
+
+	/* assert RST */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
+
+	/* The min. reset hold time is 25us, so 40us should be enough */
+	udelay( 50 );
+
+	/* reset RST and interrupt */
+	NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
+	NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+	for( end = jiffies + AFTER_RESET_DELAY; time_before(jiffies, end); )
+		barrier();
+
+	/* switch on SCSI IRQ again */
+//       	sun3_enable_irq( IRQ_SUN3_SCSI );
+
+	printk( " done\n" );
+}
+#endif
+
+static const char * sun3scsi_info (struct Scsi_Host *spnt) {
+    return "";
+}
+
+// safe bits for the CSR
+#define CSR_GOOD 0x060f
+
+static irqreturn_t scsi_sun3_intr(int irq, void *dummy, struct pt_regs *fp)
+{
+	unsigned short csr = dregs->csr;
+	int handled = 0;
+
+	dregs->csr &= ~CSR_DMA_ENABLE;
+
+
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi_intr csr %x\n", csr);
+#endif
+
+	if(csr & ~CSR_GOOD) {
+		if(csr & CSR_DMA_BUSERR) {
+			printk("scsi%d: bus error in dma\n", default_instance->host_no);
+#ifdef SUN3_SCSI_DEBUG
+			printk("scsi: residual %x count %x addr %p dmaaddr %x\n", 
+			       dregs->fifo_count,
+			       dregs->dma_count_lo | (dregs->dma_count_hi << 16),
+			       sun3_dma_orig_addr,
+			       dregs->dma_addr_lo | (dregs->dma_addr_hi << 16));
+#endif
+		}
+
+		if(csr & CSR_DMA_CONFLICT) {
+			printk("scsi%d: dma conflict\n", default_instance->host_no);
+		}
+		handled = 1;
+	}
+
+	if(csr & (CSR_SDB_INT | CSR_DMA_INT)) {
+		NCR5380_intr(irq, dummy, fp);
+		handled = 1;
+	}
+
+	return IRQ_RETVAL(handled);
+}
+
+/*
+ * Debug stuff - to be called on NMI, or sysrq key. Use at your own risk; 
+ * reentering NCR5380_print_status seems to have ugly side effects
+ */
+
+/* this doesn't seem to get used at all -- sam */
+#if 0
+void sun3_sun3_debug (void)
+{
+	unsigned long flags;
+	NCR5380_local_declare();
+
+	if (default_instance) {
+			local_irq_save(flags);
+			NCR5380_print_status(default_instance);
+			local_irq_restore(flags);
+	}
+}
+#endif
+
+
+/* sun3scsi_dma_setup() -- initialize the dma controller for a read/write */
+static unsigned long sun3scsi_dma_setup(void *data, unsigned long count, int write_flag)
+{
+	void *addr;
+
+	if(sun3_dma_orig_addr != NULL)
+		dvma_unmap(sun3_dma_orig_addr);
+
+//	addr = sun3_dvma_page((unsigned long)data, (unsigned long)dmabuf);
+	addr = (void *)dvma_map_vme((unsigned long) data, count);
+		
+	sun3_dma_orig_addr = addr;
+	sun3_dma_orig_count = count;
+	
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_setup addr %p count %x\n", addr, count);
+#endif
+
+//	dregs->fifo_count = 0;
+#if 0	
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+#endif	
+	/* set direction */
+	if(write_flag)
+		dregs->csr |= CSR_SEND;
+	else
+		dregs->csr &= ~CSR_SEND;
+	
+	/* reset fifo */
+//	dregs->csr &= ~CSR_FIFO;
+//	dregs->csr |= CSR_FIFO;
+
+	dregs->csr |= CSR_PACK_ENABLE;
+
+	dregs->dma_addr_hi = ((unsigned long)addr >> 16);
+	dregs->dma_addr_lo = ((unsigned long)addr & 0xffff);
+	
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+	dregs->fifo_count_hi = 0;
+	dregs->fifo_count = 0;
+		
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_setup done csr %x\n", dregs->csr);
+#endif
+       	return count;
+
+}
+
+static inline unsigned long sun3scsi_dma_residual(struct Scsi_Host *instance)
+{
+	return last_residual;
+}
+
+static inline unsigned long sun3scsi_dma_xfer_len(unsigned long wanted, Scsi_Cmnd *cmd,
+				    int write_flag)
+{
+	if(cmd->request->flags & REQ_CMD)
+ 		return wanted;
+	else
+		return 0;
+}
+
+static int sun3scsi_dma_start(unsigned long count, char *data)
+{
+	
+	unsigned short csr;
+
+	csr = dregs->csr;
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: dma_start data %p count %x csr %x fifo %x\n", data, count, csr, dregs->fifo_count);
+#endif
+	
+	dregs->dma_count_hi = (sun3_dma_orig_count >> 16);
+	dregs->dma_count_lo = (sun3_dma_orig_count & 0xffff);
+
+	dregs->fifo_count_hi = (sun3_dma_orig_count >> 16);
+	dregs->fifo_count = (sun3_dma_orig_count & 0xffff);
+
+//	if(!(csr & CSR_DMA_ENABLE))
+//		dregs->csr |= CSR_DMA_ENABLE;
+
+	return 0;
+}
+
+/* clean up after our dma is done */
+static int sun3scsi_dma_finish(int write_flag)
+{
+	unsigned short fifo;
+	int ret = 0;
+	
+	sun3_dma_active = 0;
+
+	dregs->csr &= ~CSR_DMA_ENABLE;
+	
+	fifo = dregs->fifo_count;
+	if(write_flag) {
+		if((fifo > 0) && (fifo < sun3_dma_orig_count))
+			fifo++;
+	}
+
+	last_residual = fifo;
+#ifdef SUN3_SCSI_DEBUG
+	printk("scsi: residual %x total %x\n", fifo, sun3_dma_orig_count);
+#endif
+	/* empty bytes from the fifo which didn't make it */
+	if((!write_flag) && (dregs->csr & CSR_LEFT)) {
+		unsigned char *vaddr;
+
+#ifdef SUN3_SCSI_DEBUG
+		printk("scsi: got left over bytes\n");
+#endif
+
+		vaddr = (unsigned char *)dvma_vmetov(sun3_dma_orig_addr);
+		
+		vaddr += (sun3_dma_orig_count - fifo);
+		vaddr--;
+		
+		switch(dregs->csr & CSR_LEFT) {
+		case CSR_LEFT_3:
+			*vaddr = (dregs->bpack_lo & 0xff00) >> 8;
+			vaddr--;
+			
+		case CSR_LEFT_2:
+			*vaddr = (dregs->bpack_hi & 0x00ff);
+			vaddr--;
+			
+		case CSR_LEFT_1:
+			*vaddr = (dregs->bpack_hi & 0xff00) >> 8;
+			break;
+		}
+		
+		
+	}
+
+	dvma_unmap(sun3_dma_orig_addr);
+	sun3_dma_orig_addr = NULL;
+
+	dregs->dma_addr_hi = 0;
+	dregs->dma_addr_lo = 0;
+	dregs->dma_count_hi = 0;
+	dregs->dma_count_lo = 0;
+
+	dregs->fifo_count = 0;
+	dregs->fifo_count_hi = 0;
+
+	dregs->csr &= ~CSR_SEND;
+	
+//	dregs->csr |= CSR_DMA_ENABLE;
+	
+#if 0
+	/* reset fifo */
+	dregs->csr &= ~CSR_FIFO;
+	dregs->csr |= CSR_FIFO;
+#endif	
+	sun3_dma_setup_done = NULL;
+
+	return ret;
+
+}
+
+#include "sun3_NCR5380.c"
+
+static Scsi_Host_Template driver_template = {
+	.name			= SUN3_SCSI_NAME,
+	.detect			= sun3scsi_detect,
+	.release		= sun3scsi_release,
+	.info			= sun3scsi_info,
+	.queuecommand		= sun3scsi_queue_command,
+	.eh_abort_handler      	= sun3scsi_abort,
+	.eh_bus_reset_handler  	= sun3scsi_bus_reset,
+	.can_queue		= CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SG_TABLESIZE,
+	.cmd_per_lun		= CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING
+};
+
+
+#include "scsi_module.c"
+
diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c
new file mode 100644
index 0000000..5d1dc0e
--- /dev/null
+++ b/drivers/scsi/sun3x_esp.c
@@ -0,0 +1,394 @@
+/* sun3x_esp.c:  EnhancedScsiProcessor Sun3x SCSI driver code.
+ *
+ * (C) 1999 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
+ *
+ * Based on David S. Miller's esp driver
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/blkdev.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "NCR53C9x.h"
+
+#include <asm/sun3x.h>
+#include <asm/dvma.h>
+#include <asm/irq.h>
+
+extern struct NCR_ESP *espchain;
+
+static void dma_barrier(struct NCR_ESP *esp);
+static int  dma_bytes_sent(struct NCR_ESP *esp, int fifo_count);
+static int  dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_drain(struct NCR_ESP *esp);
+static void dma_invalidate(struct NCR_ESP *esp);
+static void dma_dump_state(struct NCR_ESP *esp);
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length);
+static void dma_ints_off(struct NCR_ESP *esp);
+static void dma_ints_on(struct NCR_ESP *esp);
+static int  dma_irq_p(struct NCR_ESP *esp);
+static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr);
+static int  dma_ports_p(struct NCR_ESP *esp);
+static void dma_reset(struct NCR_ESP *esp);
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write);
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp);
+static void dma_advance_sg (Scsi_Cmnd *sp);
+
+/* Detecting ESP chips on the machine.  This is the simple and easy
+ * version.
+ */
+int sun3x_esp_detect(Scsi_Host_Template *tpnt)
+{
+	struct NCR_ESP *esp;
+	struct ConfigDev *esp_dev;
+
+	esp_dev = 0;
+	esp = esp_allocate(tpnt, (void *) esp_dev);
+
+	/* Do command transfer with DMA */
+	esp->do_pio_cmds = 0;
+
+	/* Required functions */
+	esp->dma_bytes_sent = &dma_bytes_sent;
+	esp->dma_can_transfer = &dma_can_transfer;
+	esp->dma_dump_state = &dma_dump_state;
+	esp->dma_init_read = &dma_init_read;
+	esp->dma_init_write = &dma_init_write;
+	esp->dma_ints_off = &dma_ints_off;
+	esp->dma_ints_on = &dma_ints_on;
+	esp->dma_irq_p = &dma_irq_p;
+	esp->dma_ports_p = &dma_ports_p;
+	esp->dma_setup = &dma_setup;
+
+	/* Optional functions */
+	esp->dma_barrier = &dma_barrier;
+	esp->dma_invalidate = &dma_invalidate;
+	esp->dma_drain = &dma_drain;
+	esp->dma_irq_entry = 0;
+	esp->dma_irq_exit = 0;
+	esp->dma_led_on = 0;
+	esp->dma_led_off = 0;
+	esp->dma_poll = &dma_poll;
+	esp->dma_reset = &dma_reset;
+
+        /* virtual DMA functions */
+        esp->dma_mmu_get_scsi_one = &dma_mmu_get_scsi_one;
+        esp->dma_mmu_get_scsi_sgl = &dma_mmu_get_scsi_sgl;
+        esp->dma_mmu_release_scsi_one = &dma_mmu_release_scsi_one;
+        esp->dma_mmu_release_scsi_sgl = &dma_mmu_release_scsi_sgl;
+        esp->dma_advance_sg = &dma_advance_sg;
+	    
+	/* SCSI chip speed */
+	esp->cfreq = 20000000;
+	esp->eregs = (struct ESP_regs *)(SUN3X_ESP_BASE);
+	esp->dregs = (void *)SUN3X_ESP_DMA;
+
+	esp->esp_command = (volatile unsigned char *)dvma_malloc(DVMA_PAGE_SIZE);
+	esp->esp_command_dvma = dvma_vtob((unsigned long)esp->esp_command);
+
+	esp->irq = 2;
+	if (request_irq(esp->irq, esp_intr, SA_INTERRUPT, 
+			"SUN3X SCSI", esp->ehost)) {
+		esp_deallocate(esp);
+		return 0;
+	}
+
+	esp->scsi_id = 7;
+	esp->diff = 0;
+
+	esp_initialize(esp);
+
+ 	/* for reasons beyond my knowledge (and which should likely be fixed)
+ 	   sync mode doesn't work on a 3/80 at 5mhz.  but it does at 4. */
+ 	esp->sync_defp = 0x3f;
+
+	printk("ESP: Total of %d ESP hosts found, %d actually in use.\n", nesps,
+	       esps_in_use);
+	esps_running = esps_in_use;
+	return esps_in_use;
+}
+
+static void dma_do_drain(struct NCR_ESP *esp)
+{
+ 	struct sparc_dma_registers *dregs =
+ 		(struct sparc_dma_registers *) esp->dregs;
+ 	
+ 	int count = 500000;
+ 
+ 	while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0)) 
+ 		udelay(1);
+ 
+ 	if(!count) {
+ 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
+ 	}
+ 
+ 	dregs->cond_reg |= DMA_FIFO_STDRAIN;
+ 	
+ 	count = 500000;
+ 
+ 	while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0)) 
+ 		udelay(1);
+ 
+ 	if(!count) {
+ 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
+ 	}
+ 
+}
+ 
+static void dma_barrier(struct NCR_ESP *esp)
+{
+  	struct sparc_dma_registers *dregs =
+  		(struct sparc_dma_registers *) esp->dregs;
+ 	int count = 500000;
+  
+ 	while((dregs->cond_reg & DMA_PEND_READ) && (--count > 0))
+  		udelay(1);
+ 
+ 	if(!count) {
+ 		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
+ 	}
+ 
+  	dregs->cond_reg &= ~(DMA_ENABLE);
+}
+
+/* This uses various DMA csr fields and the fifo flags count value to
+ * determine how many bytes were successfully sent/received by the ESP.
+ */
+static int dma_bytes_sent(struct NCR_ESP *esp, int fifo_count)
+{
+	struct sparc_dma_registers *dregs = 
+		(struct sparc_dma_registers *) esp->dregs;
+
+	int rval = dregs->st_addr - esp->esp_command_dvma;
+
+	return rval - fifo_count;
+}
+
+static int dma_can_transfer(struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+	return sp->SCp.this_residual;
+}
+
+static void dma_drain(struct NCR_ESP *esp)
+{
+	struct sparc_dma_registers *dregs =
+		(struct sparc_dma_registers *) esp->dregs;
+	int count = 500000;
+
+	if(dregs->cond_reg & DMA_FIFO_ISDRAIN) {
+		dregs->cond_reg |= DMA_FIFO_STDRAIN;
+		while((dregs->cond_reg & DMA_FIFO_ISDRAIN) && (--count > 0))
+			udelay(1);
+		if(!count) {
+			printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
+		}
+
+	}
+}
+
+static void dma_invalidate(struct NCR_ESP *esp)
+{
+	struct sparc_dma_registers *dregs =
+		(struct sparc_dma_registers *) esp->dregs;
+
+	__u32 tmp;
+	int count = 500000;
+
+	while(((tmp = dregs->cond_reg) & DMA_PEND_READ) && (--count > 0)) 
+		udelay(1);
+
+	if(!count) {
+		printk("%s:%d timeout CSR %08lx\n", __FILE__, __LINE__, dregs->cond_reg);
+	}
+
+	dregs->cond_reg = tmp | DMA_FIFO_INV;
+	dregs->cond_reg &= ~DMA_FIFO_INV;
+
+}
+
+static void dma_dump_state(struct NCR_ESP *esp)
+{
+	struct sparc_dma_registers *dregs =
+		(struct sparc_dma_registers *) esp->dregs;
+
+	ESPLOG(("esp%d: dma -- cond_reg<%08lx> addr<%08lx>\n",
+		esp->esp_id, dregs->cond_reg, dregs->st_addr));
+}
+
+static void dma_init_read(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	struct sparc_dma_registers *dregs = 
+		(struct sparc_dma_registers *) esp->dregs;
+
+	dregs->st_addr = vaddress;
+	dregs->cond_reg |= (DMA_ST_WRITE | DMA_ENABLE);
+}
+
+static void dma_init_write(struct NCR_ESP *esp, __u32 vaddress, int length)
+{
+	struct sparc_dma_registers *dregs = 
+		(struct sparc_dma_registers *) esp->dregs;
+
+	/* Set up the DMA counters */
+
+	dregs->st_addr = vaddress;
+	dregs->cond_reg = ((dregs->cond_reg & ~(DMA_ST_WRITE)) | DMA_ENABLE);
+}
+
+static void dma_ints_off(struct NCR_ESP *esp)
+{
+	DMA_INTSOFF((struct sparc_dma_registers *) esp->dregs);
+}
+
+static void dma_ints_on(struct NCR_ESP *esp)
+{
+	DMA_INTSON((struct sparc_dma_registers *) esp->dregs);
+}
+
+static int dma_irq_p(struct NCR_ESP *esp)
+{
+	return DMA_IRQ_P((struct sparc_dma_registers *) esp->dregs);
+}
+
+static void dma_poll(struct NCR_ESP *esp, unsigned char *vaddr)
+{
+	int count = 50;
+	dma_do_drain(esp);
+
+	/* Wait till the first bits settle. */
+	while((*(volatile unsigned char *)vaddr == 0xff) && (--count > 0))
+		udelay(1);
+
+	if(!count) {
+//		printk("%s:%d timeout expire (data %02x)\n", __FILE__, __LINE__,
+//		       esp_read(esp->eregs->esp_fdata));
+		//mach_halt();
+		vaddr[0] = esp_read(esp->eregs->esp_fdata);
+		vaddr[1] = esp_read(esp->eregs->esp_fdata);
+	}
+
+}	
+
+static int dma_ports_p(struct NCR_ESP *esp)
+{
+	return (((struct sparc_dma_registers *) esp->dregs)->cond_reg 
+			& DMA_INT_ENAB);
+}
+
+/* Resetting various pieces of the ESP scsi driver chipset/buses. */
+static void dma_reset(struct NCR_ESP *esp)
+{
+	struct sparc_dma_registers *dregs =
+		(struct sparc_dma_registers *)esp->dregs;
+
+	/* Punt the DVMA into a known state. */
+	dregs->cond_reg |= DMA_RST_SCSI;
+	dregs->cond_reg &= ~(DMA_RST_SCSI);
+	DMA_INTSON(dregs);
+}
+
+static void dma_setup(struct NCR_ESP *esp, __u32 addr, int count, int write)
+{
+	struct sparc_dma_registers *dregs = 
+		(struct sparc_dma_registers *) esp->dregs;
+	unsigned long nreg = dregs->cond_reg;
+
+//	printk("dma_setup %c addr %08x cnt %08x\n",
+//	       write ? 'W' : 'R', addr, count);
+
+	dma_do_drain(esp);
+
+	if(write)
+		nreg |= DMA_ST_WRITE;
+	else {
+		nreg &= ~(DMA_ST_WRITE);
+	}
+		
+	nreg |= DMA_ENABLE;
+	dregs->cond_reg = nreg;
+	dregs->st_addr = addr;
+}
+
+static void dma_mmu_get_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+    sp->SCp.have_data_in = dvma_map((unsigned long)sp->SCp.buffer,
+				       sp->SCp.this_residual);
+    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.have_data_in);
+}
+
+static void dma_mmu_get_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+    int sz = sp->SCp.buffers_residual;
+    struct scatterlist *sg = sp->SCp.buffer;
+
+    while (sz >= 0) {
+	    sg[sz].dvma_address = dvma_map((unsigned long)page_address(sg[sz].page) +
+					   sg[sz].offset, sg[sz].length);
+	    sz--;
+    }
+    sp->SCp.ptr=(char *)((unsigned long)sp->SCp.buffer->dvma_address);
+}
+
+static void dma_mmu_release_scsi_one (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+    dvma_unmap((char *)sp->SCp.have_data_in);
+}
+
+static void dma_mmu_release_scsi_sgl (struct NCR_ESP *esp, Scsi_Cmnd *sp)
+{
+    int sz = sp->use_sg - 1;
+    struct scatterlist *sg = (struct scatterlist *)sp->buffer;
+                        
+    while(sz >= 0) {
+        dvma_unmap((char *)sg[sz].dvma_address);
+        sz--;
+    }
+}
+
+static void dma_advance_sg (Scsi_Cmnd *sp)
+{
+    sp->SCp.ptr = (char *)((unsigned long)sp->SCp.buffer->dvma_address);
+}
+
+static int sun3x_esp_release(struct Scsi_Host *instance)
+{
+	/* this code does not support being compiled as a module */	 
+	return 1;
+
+}
+
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "sun3x_esp",
+	.proc_info		= &esp_proc_info,
+	.name			= "Sun ESP 100/100a/200",
+	.detect			= sun3x_esp_detect,
+	.release                = sun3x_esp_release,
+	.slave_alloc		= esp_slave_alloc,
+	.slave_destroy		= esp_slave_destroy,
+	.info			= esp_info,
+	.queuecommand		= esp_queue,
+	.eh_abort_handler	= esp_abort,
+	.eh_bus_reset_handler	= esp_reset,
+	.can_queue		= 7,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+
+#include "scsi_module.c"
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
new file mode 100644
index 0000000..f26c3a2
--- /dev/null
+++ b/drivers/scsi/sym53c416.c
@@ -0,0 +1,881 @@
+/*
+ *  sym53c416.c
+ *  Low-level SCSI driver for sym53c416 chip.
+ *  Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com)
+ * 
+ *  Changes : 
+ * 
+ *  Marcelo Tosatti <marcelo@conectiva.com.br> : Added io_request_lock locking
+ *  Alan Cox <alan@redhat.com> : Cleaned up code formatting
+ *				 Fixed an irq locking bug
+ *				 Added ISAPnP support
+ *  Bjoern A. Zeeb <bzeeb@zabbadoz.net> : Initial irq locking updates
+ *					  Added another card with ISAPnP support
+ * 
+ *  LILO command line usage: sym53c416=<PORTBASE>[,<IRQ>]
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2, or (at your option) any
+ *  later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <asm/dma.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/blkdev.h>
+#include <linux/isapnp.h>
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "sym53c416.h"
+
+#define VERSION_STRING        "Version 1.0.0-ac"
+
+#define TC_LOW       0x00     /* Transfer counter low        */
+#define TC_MID       0x01     /* Transfer counter mid        */
+#define SCSI_FIFO    0x02     /* SCSI FIFO register          */
+#define COMMAND_REG  0x03     /* Command Register            */
+#define STATUS_REG   0x04     /* Status Register (READ)      */
+#define DEST_BUS_ID  0x04     /* Destination Bus ID (WRITE)  */
+#define INT_REG      0x05     /* Interrupt Register (READ)   */
+#define TOM          0x05     /* Time out multiplier (WRITE) */
+#define STP          0x06     /* Synchronous Transfer period */
+#define SYNC_OFFSET  0x07     /* Synchronous Offset          */
+#define CONF_REG_1   0x08     /* Configuration register 1    */
+#define CONF_REG_2   0x0B     /* Configuration register 2    */
+#define CONF_REG_3   0x0C     /* Configuration register 3    */
+#define CONF_REG_4   0x0D     /* Configuration register 4    */
+#define TC_HIGH      0x0E     /* Transfer counter high       */
+#define PIO_FIFO_1   0x10     /* PIO FIFO register 1         */
+#define PIO_FIFO_2   0x11     /* PIO FIFO register 2         */
+#define PIO_FIFO_3   0x12     /* PIO FIFO register 3         */
+#define PIO_FIFO_4   0x13     /* PIO FIFO register 4         */
+#define PIO_FIFO_CNT 0x14     /* PIO FIFO count              */
+#define PIO_INT_REG  0x15     /* PIO interrupt register      */
+#define CONF_REG_5   0x16     /* Configuration register 5    */
+#define FEATURE_EN   0x1D     /* Feature Enable register     */
+
+/* Configuration register 1 entries: */
+/* Bits 2-0: SCSI ID of host adapter */
+#define SCM    0x80                     /* Slow Cable Mode              */
+#define SRID   0x40                     /* SCSI Reset Interrupt Disable */
+#define PTM    0x20                     /* Parity Test Mode             */
+#define EPC    0x10                     /* Enable Parity Checking       */
+#define CTME   0x08                     /* Special Test Mode            */
+
+/* Configuration register 2 entries: */
+#define FE     0x40                     /* Features Enable              */
+#define SCSI2  0x08                     /* SCSI 2 Enable                */
+#define TBPA   0x04                     /* Target Bad Parity Abort      */
+
+/* Configuration register 3 entries: */
+#define IDMRC  0x80                     /* ID Message Reserved Check    */
+#define QTE    0x40                     /* Queue Tag Enable             */
+#define CDB10  0x20                     /* Command Descriptor Block 10  */
+#define FSCSI  0x10                     /* FastSCSI                     */
+#define FCLK   0x08                     /* FastClock                    */
+
+/* Configuration register 4 entries: */
+#define RBS    0x08                     /* Register bank select         */
+#define EAN    0x04                     /* Enable Active Negotiation    */
+
+/* Configuration register 5 entries: */
+#define LPSR   0x80                     /* Lower Power SCSI Reset       */
+#define IE     0x20                     /* Interrupt Enable             */
+#define LPM    0x02                     /* Low Power Mode               */
+#define WSE0   0x01                     /* 0WS Enable                   */
+
+/* Interrupt register entries: */
+#define SRST   0x80                     /* SCSI Reset                   */
+#define ILCMD  0x40                     /* Illegal Command              */
+#define DIS    0x20                     /* Disconnect                   */
+#define BS     0x10                     /* Bus Service                  */
+#define FC     0x08                     /* Function Complete            */
+#define RESEL  0x04                     /* Reselected                   */
+#define SI     0x03                     /* Selection Interrupt          */
+
+/* Status Register Entries: */
+#define SCI    0x80                     /* SCSI Core Int                */
+#define GE     0x40                     /* Gross Error                  */
+#define PE     0x20                     /* Parity Error                 */
+#define TC     0x10                     /* Terminal Count               */
+#define VGC    0x08                     /* Valid Group Code             */
+#define PHBITS 0x07                     /* Phase bits                   */
+
+/* PIO Interrupt Register Entries: */
+#define SCI    0x80                     /* SCSI Core Int                */
+#define PFI    0x40                     /* PIO FIFO Interrupt           */
+#define FULL   0x20                     /* PIO FIFO Full                */
+#define EMPTY  0x10                     /* PIO FIFO Empty               */
+#define CE     0x08                     /* Collision Error              */
+#define OUE    0x04                     /* Overflow / Underflow error   */
+#define FIE    0x02                     /* Full Interrupt Enable        */
+#define EIE    0x01                     /* Empty Interrupt Enable       */
+
+/* SYM53C416 SCSI phases (lower 3 bits of SYM53C416_STATUS_REG) */
+#define PHASE_DATA_OUT    0x00
+#define PHASE_DATA_IN     0x01
+#define PHASE_COMMAND     0x02
+#define PHASE_STATUS      0x03
+#define PHASE_RESERVED_1  0x04
+#define PHASE_RESERVED_2  0x05
+#define PHASE_MESSAGE_OUT 0x06
+#define PHASE_MESSAGE_IN  0x07
+
+/* SYM53C416 core commands */
+#define NOOP                      0x00
+#define FLUSH_FIFO                0x01
+#define RESET_CHIP                0x02
+#define RESET_SCSI_BUS            0x03
+#define DISABLE_SEL_RESEL         0x45
+#define RESEL_SEQ                 0x40
+#define SEL_WITHOUT_ATN_SEQ       0x41
+#define SEL_WITH_ATN_SEQ          0x42
+#define SEL_WITH_ATN_AND_STOP_SEQ 0x43
+#define ENABLE_SEL_RESEL          0x44
+#define SEL_WITH_ATN3_SEQ         0x46
+#define RESEL3_SEQ                0x47
+#define SND_MSG                   0x20
+#define SND_STAT                  0x21
+#define SND_DATA                  0x22
+#define DISCONNECT_SEQ            0x23
+#define TERMINATE_SEQ             0x24
+#define TARGET_COMM_COMPLETE_SEQ  0x25
+#define DISCONN                   0x27
+#define RECV_MSG_SEQ              0x28
+#define RECV_CMD                  0x29
+#define RECV_DATA                 0x2A
+#define RECV_CMD_SEQ              0x2B
+#define TARGET_ABORT_PIO          0x04
+#define TRANSFER_INFORMATION      0x10
+#define INIT_COMM_COMPLETE_SEQ    0x11
+#define MSG_ACCEPTED              0x12
+#define TRANSFER_PAD              0x18
+#define SET_ATN                   0x1A
+#define RESET_ATN                 0x1B
+#define ILLEGAL                   0xFF
+
+#define PIO_MODE                  0x80
+
+#define IO_RANGE 0x20         /* 0x00 - 0x1F                   */
+#define ID       "sym53c416"	/* Attention: copied to the sym53c416.h */
+#define PIO_SIZE 128          /* Size of PIO fifo is 128 bytes */
+
+#define READ_TIMEOUT              150
+#define WRITE_TIMEOUT             150
+
+#ifdef MODULE
+
+#define sym53c416_base sym53c416
+#define sym53c416_base_1 sym53c416_1
+#define sym53c416_base_2 sym53c416_2
+#define sym53c416_base_3 sym53c416_3
+
+static unsigned int sym53c416_base[2] = {0,0};
+static unsigned int sym53c416_base_1[2] = {0,0};
+static unsigned int sym53c416_base_2[2] = {0,0};
+static unsigned int sym53c416_base_3[2] = {0,0};
+
+#endif
+
+#define MAXHOSTS 4
+
+#define SG_ADDRESS(buffer)     ((char *) (page_address((buffer)->page)+(buffer)->offset))
+
+enum phases
+{
+	idle,
+	data_out,
+	data_in,
+	command_ph,
+	status_ph,
+	message_out,
+	message_in
+};
+
+typedef struct
+{
+	int base;
+	int irq;
+	int scsi_id;
+} host;
+
+static host hosts[MAXHOSTS] = {
+                       {0, 0, SYM53C416_SCSI_ID},
+                       {0, 0, SYM53C416_SCSI_ID},
+                       {0, 0, SYM53C416_SCSI_ID},
+                       {0, 0, SYM53C416_SCSI_ID}
+                       };
+
+static int host_index = 0;
+static char info[120];
+static Scsi_Cmnd *current_command = NULL;
+static int fastpio = 1;
+
+static int probeaddrs[] = {0x200, 0x220, 0x240, 0};
+
+static void sym53c416_set_transfer_counter(int base, unsigned int len)
+{
+	/* Program Transfer Counter */
+	outb(len & 0x0000FF, base + TC_LOW);
+	outb((len & 0x00FF00) >> 8, base + TC_MID);
+	outb((len & 0xFF0000) >> 16, base + TC_HIGH);
+}
+
+static DEFINE_SPINLOCK(sym53c416_lock);
+
+/* Returns the number of bytes read */
+static __inline__ unsigned int sym53c416_read(int base, unsigned char *buffer, unsigned int len)
+{
+	unsigned int orig_len = len;
+	unsigned long flags = 0;
+	unsigned int bytes_left;
+	unsigned long i;
+	int timeout = READ_TIMEOUT;
+
+	/* Do transfer */
+	spin_lock_irqsave(&sym53c416_lock, flags);
+	while(len && timeout)
+	{
+		bytes_left = inb(base + PIO_FIFO_CNT); /* Number of bytes in the PIO FIFO */
+		if(fastpio && bytes_left > 3)
+		{
+			insl(base + PIO_FIFO_1, buffer, bytes_left >> 2);
+			buffer += bytes_left & 0xFC;
+			len -= bytes_left & 0xFC;
+		}
+		else if(bytes_left > 0)
+		{
+			len -= bytes_left;
+			for(; bytes_left > 0; bytes_left--)
+				*(buffer++) = inb(base + PIO_FIFO_1);
+		}
+		else
+		{
+			i = jiffies + timeout;
+			spin_unlock_irqrestore(&sym53c416_lock, flags);
+			while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & EMPTY) && timeout)
+				if(inb(base + PIO_INT_REG) & SCI)
+					timeout = 0;
+			spin_lock_irqsave(&sym53c416_lock, flags);
+			if(inb(base + PIO_INT_REG) & EMPTY)
+				timeout = 0;
+		}
+	}
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
+	return orig_len - len;
+}
+
+/* Returns the number of bytes written */
+static __inline__ unsigned int sym53c416_write(int base, unsigned char *buffer, unsigned int len)
+{
+	unsigned int orig_len = len;
+	unsigned long flags = 0;
+	unsigned int bufferfree;
+	unsigned long i;
+	unsigned int timeout = WRITE_TIMEOUT;
+
+	/* Do transfer */
+	spin_lock_irqsave(&sym53c416_lock, flags);
+	while(len && timeout)
+	{
+		bufferfree = PIO_SIZE - inb(base + PIO_FIFO_CNT);
+		if(bufferfree > len)
+			bufferfree = len;
+		if(fastpio && bufferfree > 3)
+		{
+			outsl(base + PIO_FIFO_1, buffer, bufferfree >> 2);
+			buffer += bufferfree & 0xFC;
+			len -= bufferfree & 0xFC;
+		}
+		else if(bufferfree > 0)
+		{
+			len -= bufferfree;
+			for(; bufferfree > 0; bufferfree--)
+				outb(*(buffer++), base + PIO_FIFO_1);
+		}
+		else
+		{
+			i = jiffies + timeout;
+			spin_unlock_irqrestore(&sym53c416_lock, flags);
+			while(time_before(jiffies, i) && (inb(base + PIO_INT_REG) & FULL) && timeout)
+				;
+			spin_lock_irqsave(&sym53c416_lock, flags);
+			if(inb(base + PIO_INT_REG) & FULL)
+				timeout = 0;
+		}
+	}
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
+	return orig_len - len;
+}
+
+static irqreturn_t sym53c416_intr_handle(int irq, void *dev_id,
+					struct pt_regs *regs)
+{
+	struct Scsi_Host *dev = dev_id;
+	int base = 0;
+	int i;
+	unsigned long flags = 0;
+	unsigned char status_reg, pio_int_reg, int_reg;
+	struct scatterlist *sglist;
+	unsigned int sgcount;
+	unsigned int tot_trans = 0;
+
+	/* We search the base address of the host adapter which caused the interrupt */
+	/* FIXME: should pass dev_id sensibly as hosts[i] */
+	for(i = 0; i < host_index && !base; i++)
+		if(irq == hosts[i].irq)
+			base = hosts[i].base;
+	/* If no adapter found, we cannot handle the interrupt. Leave a message */
+	/* and continue. This should never happen...                            */
+	if(!base)
+	{
+		printk(KERN_ERR "sym53c416: No host adapter defined for interrupt %d\n", irq);
+		return IRQ_NONE;
+	}
+	/* Now we have the base address and we can start handling the interrupt */
+
+	spin_lock_irqsave(dev->host_lock,flags);
+	status_reg = inb(base + STATUS_REG);
+	pio_int_reg = inb(base + PIO_INT_REG);
+	int_reg = inb(base + INT_REG);
+	spin_unlock_irqrestore(dev->host_lock, flags);
+
+	/* First, we handle error conditions */
+	if(int_reg & SCI)         /* SCSI Reset */
+	{
+		printk(KERN_DEBUG "sym53c416: Reset received\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_RESET << 16;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	if(int_reg & ILCMD)       /* Illegal Command */
+	{
+		printk(KERN_WARNING "sym53c416: Illegal Command: 0x%02x.\n", inb(base + COMMAND_REG));
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	if(status_reg & GE)         /* Gross Error */
+	{
+		printk(KERN_WARNING "sym53c416: Controller reports gross error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	if(status_reg & PE)         /* Parity Error */
+	{
+		printk(KERN_WARNING "sym53c416:SCSI parity error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_PARITY << 16;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	if(pio_int_reg & (CE | OUE))
+	{
+		printk(KERN_WARNING "sym53c416: PIO interrupt error.\n");
+		current_command->SCp.phase = idle;
+		current_command->result = DID_ERROR << 16;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	if(int_reg & DIS)           /* Disconnect */
+	{
+		if(current_command->SCp.phase != message_in)
+			current_command->result = DID_NO_CONNECT << 16;
+		else
+			current_command->result = (current_command->SCp.Status & 0xFF) | ((current_command->SCp.Message & 0xFF) << 8) | (DID_OK << 16);
+		current_command->SCp.phase = idle;
+		spin_lock_irqsave(dev->host_lock, flags);
+		current_command->scsi_done(current_command);
+		spin_unlock_irqrestore(dev->host_lock, flags);
+		goto out;
+	}
+	/* Now we handle SCSI phases         */
+
+	switch(status_reg & PHBITS)       /* Filter SCSI phase out of status reg */
+	{
+		case PHASE_DATA_OUT:
+		{
+			if(int_reg & BS)
+			{
+				current_command->SCp.phase = data_out;
+				outb(FLUSH_FIFO, base + COMMAND_REG);
+				sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+				outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+				if(!current_command->use_sg)
+					tot_trans = sym53c416_write(base, current_command->request_buffer, current_command->request_bufflen);
+				else
+				{
+					sgcount = current_command->use_sg;
+					sglist = current_command->request_buffer;
+					while(sgcount--)
+					{
+						tot_trans += sym53c416_write(base, SG_ADDRESS(sglist), sglist->length);
+						sglist++;
+					}
+				}
+				if(tot_trans < current_command->underflow)
+					printk(KERN_WARNING "sym53c416: Underflow, wrote %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+			}
+			break;
+		}
+
+		case PHASE_DATA_IN:
+		{
+			if(int_reg & BS)
+			{
+				current_command->SCp.phase = data_in;
+				outb(FLUSH_FIFO, base + COMMAND_REG);
+				sym53c416_set_transfer_counter(base, current_command->request_bufflen);
+				outb(TRANSFER_INFORMATION | PIO_MODE, base + COMMAND_REG);
+				if(!current_command->use_sg)
+					tot_trans = sym53c416_read(base, current_command->request_buffer, current_command->request_bufflen);
+				else
+				{
+					sgcount = current_command->use_sg;
+					sglist = current_command->request_buffer;
+					while(sgcount--)
+					{
+						tot_trans += sym53c416_read(base, SG_ADDRESS(sglist), sglist->length);
+						sglist++;
+					}
+				}
+				if(tot_trans < current_command->underflow)
+					printk(KERN_WARNING "sym53c416: Underflow, read %d bytes, request for %d bytes.\n", tot_trans, current_command->underflow);
+			}
+			break;
+		}
+
+		case PHASE_COMMAND:
+		{
+			current_command->SCp.phase = command_ph;
+			printk(KERN_ERR "sym53c416: Unknown interrupt in command phase.\n");
+			break;
+		}
+
+		case PHASE_STATUS:
+		{
+			current_command->SCp.phase = status_ph;
+			outb(FLUSH_FIFO, base + COMMAND_REG);
+			outb(INIT_COMM_COMPLETE_SEQ, base + COMMAND_REG);
+			break;
+		}
+		
+		case PHASE_RESERVED_1:
+		case PHASE_RESERVED_2:
+		{
+			printk(KERN_ERR "sym53c416: Reserved phase occurred.\n");
+			break;
+		}
+
+		case PHASE_MESSAGE_OUT:
+		{
+			current_command->SCp.phase = message_out;
+			outb(SET_ATN, base + COMMAND_REG);
+			outb(MSG_ACCEPTED, base + COMMAND_REG);
+			break;
+		}
+
+		case PHASE_MESSAGE_IN:
+		{
+			current_command->SCp.phase = message_in;
+			current_command->SCp.Status = inb(base + SCSI_FIFO);
+			current_command->SCp.Message = inb(base + SCSI_FIFO);
+			if(current_command->SCp.Message == SAVE_POINTERS || current_command->SCp.Message == DISCONNECT)
+				outb(SET_ATN, base + COMMAND_REG);
+			outb(MSG_ACCEPTED, base + COMMAND_REG);
+			break;
+		}
+	}
+out:
+	return IRQ_HANDLED;
+}
+
+static void sym53c416_init(int base, int scsi_id)
+{
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP, base + COMMAND_REG);
+	outb(0x99, base + TOM); /* Time out of 250 ms */
+	outb(0x05, base + STP);
+	outb(0x00, base + SYNC_OFFSET);
+	outb(EPC | scsi_id, base + CONF_REG_1);
+	outb(FE | SCSI2 | TBPA, base + CONF_REG_2);
+	outb(IDMRC | QTE | CDB10 | FSCSI | FCLK, base + CONF_REG_3);
+	outb(0x83 | EAN, base + CONF_REG_4);
+	outb(IE | WSE0, base + CONF_REG_5);
+	outb(0, base + FEATURE_EN);
+}
+
+static int sym53c416_probeirq(int base, int scsi_id)
+{
+	int irq, irqs;
+	unsigned long i;
+
+	/* Clear interrupt register */
+	inb(base + INT_REG);
+	/* Start probing for irq's */
+	irqs = probe_irq_on();
+	/* Reinit chip */
+	sym53c416_init(base, scsi_id);
+	/* Cause interrupt */
+	outb(NOOP, base + COMMAND_REG);
+	outb(ILLEGAL, base + COMMAND_REG);
+	outb(0x07, base + DEST_BUS_ID);
+	outb(0x00, base + DEST_BUS_ID);
+	/* Wait for interrupt to occur */
+	i = jiffies + 20;
+	while(time_before(jiffies, i) && !(inb(base + STATUS_REG) & SCI))
+		barrier();
+	if(time_before_eq(i, jiffies))	/* timed out */
+		return 0;
+	/* Get occurred irq */
+	irq = probe_irq_off(irqs);
+	sym53c416_init(base, scsi_id);
+	return irq;
+}
+
+/* Setup: sym53c416=base,irq */
+void sym53c416_setup(char *str, int *ints)
+{
+	int i;
+
+	if(host_index >= MAXHOSTS)
+	{
+		printk(KERN_WARNING "sym53c416: Too many hosts defined\n");
+		return;
+	}
+	if(ints[0] < 1 || ints[0] > 2)
+	{
+		printk(KERN_ERR "sym53c416: Wrong number of parameters:\n");
+		printk(KERN_ERR "sym53c416: usage: sym53c416=<base>[,<irq>]\n");
+		return;
+	}
+	for(i = 0; i < host_index && i >= 0; i++)
+	        if(hosts[i].base == ints[1])
+        		i = -2;
+	if(i >= 0)
+	{
+        	hosts[host_index].base = ints[1];
+        	hosts[host_index].irq = (ints[0] == 2)? ints[2] : 0;
+        	host_index++;
+	}
+}
+
+static int sym53c416_test(int base)
+{
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP, base + COMMAND_REG);
+	if(inb(base + COMMAND_REG) != NOOP)
+		return 0;
+	if(!inb(base + TC_HIGH) || inb(base + TC_HIGH) == 0xFF)
+		return 0;
+	if((inb(base + PIO_INT_REG) & (FULL | EMPTY | CE | OUE | FIE | EIE)) != EMPTY)
+		return 0;
+	return 1;
+}
+
+
+static struct isapnp_device_id id_table[] __devinitdata = {
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4161), 0 },
+	{	ISAPNP_ANY_ID, ISAPNP_ANY_ID,
+		ISAPNP_VENDOR('S','L','I'), ISAPNP_FUNCTION(0x4163), 0 },
+	{	ISAPNP_DEVICE_SINGLE_END }
+};
+
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+static void sym53c416_probe(void)
+{
+	int *base = probeaddrs;
+	int ints[2];
+
+	ints[0] = 1;
+	for(; *base; base++) {
+		if (request_region(*base, IO_RANGE, ID)) {
+			if (sym53c416_test(*base)) {
+				ints[1] = *base;
+				sym53c416_setup(NULL, ints);
+			}
+			release_region(*base, IO_RANGE);
+		}
+	}
+}
+
+int __init sym53c416_detect(Scsi_Host_Template *tpnt)
+{
+	unsigned long flags;
+	struct Scsi_Host * shpnt = NULL;
+	int i;
+	int count;
+	struct pnp_dev *idev = NULL;
+	
+#ifdef MODULE
+	int ints[3];
+
+	ints[0] = 2;
+	if(sym53c416_base)
+	{
+		ints[1] = sym53c416_base[0];
+		ints[2] = sym53c416_base[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_1)
+	{
+		ints[1] = sym53c416_base_1[0];
+		ints[2] = sym53c416_base_1[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_2)
+	{
+		ints[1] = sym53c416_base_2[0];
+		ints[2] = sym53c416_base_2[1];
+		sym53c416_setup(NULL, ints);
+	}
+	if(sym53c416_base_3)
+	{
+		ints[1] = sym53c416_base_3[0];
+		ints[2] = sym53c416_base_3[1];
+		sym53c416_setup(NULL, ints);
+	}
+#endif
+	printk(KERN_INFO "sym53c416.c: %s\n", VERSION_STRING);
+
+	for (i=0; id_table[i].vendor != 0; i++) {
+		while((idev=pnp_find_dev(NULL, id_table[i].vendor,
+					id_table[i].function, idev))!=NULL)
+		{
+			int i[3];
+
+			if(pnp_device_attach(idev)<0)
+			{
+				printk(KERN_WARNING "sym53c416: unable to attach PnP device.\n");
+				continue;
+			}
+			if(pnp_activate_dev(idev) < 0)
+			{
+				printk(KERN_WARNING "sym53c416: unable to activate PnP device.\n");
+				pnp_device_detach(idev);
+				continue;
+			
+			}
+
+			i[0] = 2;
+			i[1] = pnp_port_start(idev, 0);
+ 			i[2] = pnp_irq(idev, 0);
+
+			printk(KERN_INFO "sym53c416: ISAPnP card found and configured at 0x%X, IRQ %d.\n",
+				i[1], i[2]);
+ 			sym53c416_setup(NULL, i);
+ 		}
+	}
+	sym53c416_probe();
+
+	/* Now we register and set up each host adapter found... */
+	for(count = 0, i = 0; i < host_index; i++) {
+		if (!request_region(hosts[i].base, IO_RANGE, ID))
+			continue;
+		if (!sym53c416_test(hosts[i].base)) {
+			printk(KERN_WARNING "No sym53c416 found at address 0x%03x\n", hosts[i].base);
+			goto fail_release_region;
+		}
+
+		/* We don't have an irq yet, so we should probe for one */
+		if (!hosts[i].irq)
+			hosts[i].irq = sym53c416_probeirq(hosts[i].base, hosts[i].scsi_id);
+		if (!hosts[i].irq)
+			goto fail_release_region;
+	
+		shpnt = scsi_register(tpnt, 0);
+		if (!shpnt)
+			goto fail_release_region;
+		/* Request for specified IRQ */
+		if (request_irq(hosts[i].irq, sym53c416_intr_handle, 0, ID, shpnt))
+			goto fail_free_host;
+
+		spin_lock_irqsave(&sym53c416_lock, flags);
+		shpnt->unique_id = hosts[i].base;
+		shpnt->io_port = hosts[i].base;
+		shpnt->n_io_port = IO_RANGE;
+		shpnt->irq = hosts[i].irq;
+		shpnt->this_id = hosts[i].scsi_id;
+		sym53c416_init(hosts[i].base, hosts[i].scsi_id);
+		count++;
+		spin_unlock_irqrestore(&sym53c416_lock, flags);
+		continue;
+
+ fail_free_host:
+		scsi_unregister(shpnt);
+ fail_release_region:
+		release_region(hosts[i].base, IO_RANGE);
+	}
+	return count;
+}
+
+const char *sym53c416_info(struct Scsi_Host *SChost)
+{
+	int i;
+	int base = SChost->io_port;
+	int irq = SChost->irq;
+	int scsi_id = 0;
+	int rev = inb(base + TC_HIGH);
+
+	for(i = 0; i < host_index; i++)
+		if(hosts[i].base == base)
+			scsi_id = hosts[i].scsi_id;
+	sprintf(info, "Symbios Logic 53c416 (rev. %d) at 0x%03x, irq %d, SCSI-ID %d, %s pio", rev, base, irq, scsi_id, (fastpio)? "fast" : "slow");
+	return info;
+}
+
+int sym53c416_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	int base;
+	unsigned long flags = 0;
+	int i;
+
+	/* Store base register as we can have more than one controller in the system */
+	base = SCpnt->device->host->io_port;
+	current_command = SCpnt;                  /* set current command                */
+	current_command->scsi_done = done;        /* set ptr to done function           */
+	current_command->SCp.phase = command_ph;  /* currect phase is the command phase */
+	current_command->SCp.Status = 0;
+	current_command->SCp.Message = 0;
+
+	spin_lock_irqsave(&sym53c416_lock, flags);
+	outb(SCpnt->device->id, base + DEST_BUS_ID); /* Set scsi id target        */
+	outb(FLUSH_FIFO, base + COMMAND_REG);    /* Flush SCSI and PIO FIFO's */
+	/* Write SCSI command into the SCSI fifo */
+	for(i = 0; i < SCpnt->cmd_len; i++)
+		outb(SCpnt->cmnd[i], base + SCSI_FIFO);
+	/* Start selection sequence */
+	outb(SEL_WITHOUT_ATN_SEQ, base + COMMAND_REG);
+	/* Now an interrupt will be generated which we will catch in out interrupt routine */
+	spin_unlock_irqrestore(&sym53c416_lock, flags);
+	return 0;
+}
+
+static int sym53c416_abort(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int sym53c416_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int sym53c416_device_reset(Scsi_Cmnd *SCpnt)
+{
+	return FAILED;
+}
+
+static int sym53c416_host_reset(Scsi_Cmnd *SCpnt)
+{
+	int base;
+	int scsi_id = -1;	
+	int i;
+
+	/* printk("sym53c416_reset\n"); */
+	base = SCpnt->device->host->io_port;
+	/* search scsi_id - fixme, we shouldnt need to iterate for this! */
+	for(i = 0; i < host_index && scsi_id != -1; i++)
+		if(hosts[i].base == base)
+			scsi_id = hosts[i].scsi_id;
+	outb(RESET_CHIP, base + COMMAND_REG);
+	outb(NOOP | PIO_MODE, base + COMMAND_REG);
+	outb(RESET_SCSI_BUS, base + COMMAND_REG);
+	sym53c416_init(base, scsi_id);
+	return SUCCESS;
+}
+
+static int sym53c416_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, shost);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	return 0;
+}
+
+static int sym53c416_bios_param(struct scsi_device *sdev,
+		struct block_device *dev,
+		sector_t capacity, int *ip)
+{
+	int size;
+
+	size = capacity;
+	ip[0] = 64;				/* heads                        */
+	ip[1] = 32;				/* sectors                      */
+	if((ip[2] = size >> 11) > 1024)		/* cylinders, test for big disk */
+	{
+		ip[0] = 255;			/* heads                        */
+		ip[1] = 63;			/* sectors                      */
+		ip[2] = size / (255 * 63);	/* cylinders                    */
+	}
+	return 0;
+}
+
+/* Loadable module support */
+#ifdef MODULE
+
+MODULE_AUTHOR("Lieven Willems");
+MODULE_LICENSE("GPL");
+
+module_param_array(sym53c416, uint, NULL, 0);
+module_param_array(sym53c416_1, uint, NULL, 0);
+module_param_array(sym53c416_2, uint, NULL, 0);
+module_param_array(sym53c416_3, uint, NULL, 0);
+
+#endif
+
+static Scsi_Host_Template driver_template = {
+	.proc_name =		"sym53c416",
+	.name =			"Symbios Logic 53c416",
+	.detect =		sym53c416_detect,
+	.info =			sym53c416_info,	
+	.queuecommand =		sym53c416_queuecommand,
+	.eh_abort_handler =	sym53c416_abort,
+	.eh_host_reset_handler =sym53c416_host_reset,
+	.eh_bus_reset_handler = sym53c416_bus_reset,
+	.eh_device_reset_handler =sym53c416_device_reset,
+	.release = 		sym53c416_release,
+	.bios_param =		sym53c416_bios_param,
+	.can_queue =		1,
+	.this_id =		SYM53C416_SCSI_ID,
+	.sg_tablesize =		32,
+	.cmd_per_lun =		1,
+	.unchecked_isa_dma =	1,
+	.use_clustering =	ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
new file mode 100644
index 0000000..3c0e3f8
--- /dev/null
+++ b/drivers/scsi/sym53c416.h
@@ -0,0 +1,36 @@
+/*
+ *  sym53c416.h
+ * 
+ *  Copyright (C) 1998 Lieven Willems (lw_linux@hotmail.com)
+ *
+ *  This program is free software; you can redistribute it and/or modify it
+ *  under the terms of the GNU General Public License as published by the
+ *  Free Software Foundation; either version 2, or (at your option) any
+ *  later version.
+ *
+ *  This program is distributed in the hope that it will be useful, but
+ *  WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  General Public License for more details.
+ *
+ */
+
+#ifndef _SYM53C416_H
+#define _SYM53C416_H
+
+#include <linux/types.h>
+
+#define SYM53C416_SCSI_ID 7
+
+static int sym53c416_detect(Scsi_Host_Template *);
+static const char *sym53c416_info(struct Scsi_Host *);
+static int sym53c416_release(struct Scsi_Host *);
+static int sym53c416_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int sym53c416_abort(Scsi_Cmnd *);
+static int sym53c416_host_reset(Scsi_Cmnd *);
+static int sym53c416_bus_reset(Scsi_Cmnd *);
+static int sym53c416_device_reset(Scsi_Cmnd *);
+static int sym53c416_bios_param(struct scsi_device *, struct block_device *,
+		sector_t, int *);
+static void sym53c416_setup(char *str, int *ints);
+#endif
diff --git a/drivers/scsi/sym53c8xx_2/Makefile b/drivers/scsi/sym53c8xx_2/Makefile
new file mode 100644
index 0000000..873e8ce
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/Makefile
@@ -0,0 +1,4 @@
+# Makefile for the NCR/SYMBIOS/LSI 53C8XX PCI SCSI controllers driver.
+
+sym53c8xx-objs := sym_fw.o sym_glue.o sym_hipd.o sym_malloc.o sym_nvram.o
+obj-$(CONFIG_SCSI_SYM53C8XX_2) := sym53c8xx.o
diff --git a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
new file mode 100644
index 0000000..4811037
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
@@ -0,0 +1,217 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM53C8XX_H
+#define SYM53C8XX_H
+
+#include <linux/config.h>
+
+/*
+ *  DMA addressing mode.
+ *
+ *  0 : 32 bit addressing for all chips.
+ *  1 : 40 bit addressing when supported by chip.
+ *  2 : 64 bit addressing when supported by chip,
+ *      limited to 16 segments of 4 GB -> 64 GB max.
+ */
+#define	SYM_CONF_DMA_ADDRESSING_MODE CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE
+
+/*
+ *  NVRAM support.
+ */
+#if 1
+#define SYM_CONF_NVRAM_SUPPORT		(1)
+#endif
+
+/*
+ *  These options are not tunable from 'make config'
+ */
+#if 1
+#define	SYM_LINUX_PROC_INFO_SUPPORT
+#define SYM_LINUX_USER_COMMAND_SUPPORT
+#define SYM_LINUX_USER_INFO_SUPPORT
+#define SYM_LINUX_DEBUG_CONTROL_SUPPORT
+#endif
+
+/*
+ *  Also handle old NCR chips if not (0).
+ */
+#define SYM_CONF_GENERIC_SUPPORT	(1)
+
+/*
+ *  Allow tags from 2 to 256, default 8
+ */
+#ifndef CONFIG_SCSI_SYM53C8XX_MAX_TAGS
+#define CONFIG_SCSI_SYM53C8XX_MAX_TAGS	(8)
+#endif
+
+#if	CONFIG_SCSI_SYM53C8XX_MAX_TAGS < 2
+#define SYM_CONF_MAX_TAG	(2)
+#elif	CONFIG_SCSI_SYM53C8XX_MAX_TAGS > 256
+#define SYM_CONF_MAX_TAG	(256)
+#else
+#define	SYM_CONF_MAX_TAG	CONFIG_SCSI_SYM53C8XX_MAX_TAGS
+#endif
+
+#ifndef	CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS
+#define	CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS	SYM_CONF_MAX_TAG
+#endif
+
+/*
+ *  Anyway, we configure the driver for at least 64 tags per LUN. :)
+ */
+#if	SYM_CONF_MAX_TAG <= 64
+#define SYM_CONF_MAX_TAG_ORDER	(6)
+#elif	SYM_CONF_MAX_TAG <= 128
+#define SYM_CONF_MAX_TAG_ORDER	(7)
+#else
+#define SYM_CONF_MAX_TAG_ORDER	(8)
+#endif
+
+/*
+ *  Max number of SG entries.
+ */
+#define SYM_CONF_MAX_SG		(96)
+
+/*
+ *  Driver setup structure.
+ *
+ *  This structure is initialized from linux config options.
+ *  It can be overridden at boot-up by the boot command line.
+ */
+struct sym_driver_setup {
+	u_short	max_tag;
+	u_char	burst_order;
+	u_char	scsi_led;
+	u_char	scsi_diff;
+	u_char	irq_mode;
+	u_char	scsi_bus_check;
+	u_char	host_id;
+
+	u_char	verbose;
+	u_char	settle_delay;
+	u_char	use_nvram;
+	u_long	excludes[8];
+	char	tag_ctrl[100];
+};
+
+#define SYM_SETUP_MAX_TAG		sym_driver_setup.max_tag
+#define SYM_SETUP_BURST_ORDER		sym_driver_setup.burst_order
+#define SYM_SETUP_SCSI_LED		sym_driver_setup.scsi_led
+#define SYM_SETUP_SCSI_DIFF		sym_driver_setup.scsi_diff
+#define SYM_SETUP_IRQ_MODE		sym_driver_setup.irq_mode
+#define SYM_SETUP_SCSI_BUS_CHECK	sym_driver_setup.scsi_bus_check
+#define SYM_SETUP_HOST_ID		sym_driver_setup.host_id
+#define boot_verbose			sym_driver_setup.verbose
+
+/*
+ *  Initial setup.
+ *
+ *  Can be overriden at startup by a command line.
+ */
+#define SYM_LINUX_DRIVER_SETUP	{				\
+	.max_tag	= CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS,	\
+	.burst_order	= 7,					\
+	.scsi_led	= 1,					\
+	.scsi_diff	= 1,					\
+	.irq_mode	= 0,					\
+	.scsi_bus_check	= 1,					\
+	.host_id	= 7,					\
+	.verbose	= 0,					\
+	.settle_delay	= 3,					\
+	.use_nvram	= 1,					\
+}
+
+extern struct sym_driver_setup sym_driver_setup;
+extern unsigned int sym_debug_flags;
+#define DEBUG_FLAGS	sym_debug_flags
+
+/*
+ *  Max number of targets.
+ *  Maximum is 16 and you are advised not to change this value.
+ */
+#ifndef SYM_CONF_MAX_TARGET
+#define SYM_CONF_MAX_TARGET	(16)
+#endif
+
+/*
+ *  Max number of logical units.
+ *  SPI-2 allows up to 64 logical units, but in real life, target
+ *  that implements more that 7 logical units are pretty rare.
+ *  Anyway, the cost of accepting up to 64 logical unit is low in 
+ *  this driver, thus going with the maximum is acceptable.
+ */
+#ifndef SYM_CONF_MAX_LUN
+#define SYM_CONF_MAX_LUN	(64)
+#endif
+
+/*
+ *  Max number of IO control blocks queued to the controller.
+ *  Each entry needs 8 bytes and the queues are allocated contiguously.
+ *  Since we donnot want to allocate more than a page, the theorical 
+ *  maximum is PAGE_SIZE/8. For safety, we announce a bit less to the 
+ *  access method. :)
+ *  When not supplied, as it is suggested, the driver compute some 
+ *  good value for this parameter.
+ */
+/* #define SYM_CONF_MAX_START	(PAGE_SIZE/8 - 16) */
+
+/*
+ *  Support for Immediate Arbitration.
+ *  Not advised.
+ */
+/* #define SYM_CONF_IARB_SUPPORT */
+
+/*
+ *  Only relevant if IARB support configured.
+ *  - Max number of successive settings of IARB hints.
+ *  - Set IARB on arbitration lost.
+ */
+#define SYM_CONF_IARB_MAX 3
+#define SYM_CONF_SET_IARB_ON_ARB_LOST 1
+
+/*
+ *  Returning wrong residuals may make problems.
+ *  When zero, this define tells the driver to 
+ *  always return 0 as transfer residual.
+ *  Btw, all my testings of residuals have succeeded.
+ */
+#define SYM_SETUP_RESIDUAL_SUPPORT 1
+
+#endif /* SYM53C8XX_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_defs.h b/drivers/scsi/sym53c8xx_2/sym_defs.h
new file mode 100644
index 0000000..15bb891
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_defs.h
@@ -0,0 +1,792 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM_DEFS_H
+#define SYM_DEFS_H
+
+#define SYM_VERSION "2.2.0"
+#define SYM_DRIVER_NAME	"sym-" SYM_VERSION
+
+/*
+ *	SYM53C8XX device features descriptor.
+ */
+struct sym_chip {
+	u_short	device_id;
+	u_short	revision_id;
+	char	*name;
+	u_char	burst_max;	/* log-base-2 of max burst */
+	u_char	offset_max;
+	u_char	nr_divisor;
+	u_char	lp_probe_bit;
+	u_int	features;
+#define FE_LED0		(1<<0)
+#define FE_WIDE		(1<<1)    /* Wide data transfers */
+#define FE_ULTRA	(1<<2)	  /* Ultra speed 20Mtrans/sec */
+#define FE_ULTRA2	(1<<3)	  /* Ultra 2 - 40 Mtrans/sec */
+#define FE_DBLR		(1<<4)	  /* Clock doubler present */
+#define FE_QUAD		(1<<5)	  /* Clock quadrupler present */
+#define FE_ERL		(1<<6)    /* Enable read line */
+#define FE_CLSE		(1<<7)    /* Cache line size enable */
+#define FE_WRIE		(1<<8)    /* Write & Invalidate enable */
+#define FE_ERMP		(1<<9)    /* Enable read multiple */
+#define FE_BOF		(1<<10)   /* Burst opcode fetch */
+#define FE_DFS		(1<<11)   /* DMA fifo size */
+#define FE_PFEN		(1<<12)   /* Prefetch enable */
+#define FE_LDSTR	(1<<13)   /* Load/Store supported */
+#define FE_RAM		(1<<14)   /* On chip RAM present */
+#define FE_VARCLK	(1<<15)   /* Clock frequency may vary */
+#define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
+#define FE_64BIT	(1<<17)   /* 64-bit PCI BUS interface */
+#define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
+#define FE_NOPM		(1<<19)   /* Scripts handles phase mismatch */
+#define FE_LEDC		(1<<20)   /* Hardware control of LED */
+#define FE_ULTRA3	(1<<21)	  /* Ultra 3 - 80 Mtrans/sec DT */
+#define FE_66MHZ	(1<<22)	  /* 66MHz PCI support */
+#define FE_CRC		(1<<23)	  /* CRC support */
+#define FE_DIFF		(1<<24)	  /* SCSI HVD support */
+#define FE_DFBC		(1<<25)	  /* Have DFBC register */
+#define FE_LCKFRQ	(1<<26)	  /* Have LCKFRQ */
+#define FE_C10		(1<<27)	  /* Various C10 core (mis)features */
+#define FE_U3EN		(1<<28)	  /* U3EN bit usable */
+#define FE_DAC		(1<<29)	  /* Support PCI DAC (64 bit addressing) */
+#define FE_ISTAT1 	(1<<30)   /* Have ISTAT1, MBOX0, MBOX1 registers */
+
+#define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
+#define FE_CACHE0_SET	(FE_CACHE_SET & ~FE_ERL)
+};
+
+/*
+ *	SYM53C8XX IO register data structure.
+ */
+struct sym_reg {
+/*00*/  u8	nc_scntl0;	/* full arb., ena parity, par->ATN  */
+
+/*01*/  u8	nc_scntl1;	/* no reset                         */
+        #define   ISCON   0x10  /* connected to scsi		    */
+        #define   CRST    0x08  /* force reset                      */
+        #define   IARB    0x02  /* immediate arbitration            */
+
+/*02*/  u8	nc_scntl2;	/* no disconnect expected           */
+	#define   SDU     0x80  /* cmd: disconnect will raise error */
+	#define   CHM     0x40  /* sta: chained mode                */
+	#define   WSS     0x08  /* sta: wide scsi send           [W]*/
+	#define   WSR     0x01  /* sta: wide scsi received       [W]*/
+
+/*03*/  u8	nc_scntl3;	/* cnf system clock dependent       */
+	#define   EWS     0x08  /* cmd: enable wide scsi         [W]*/
+	#define   ULTRA   0x80  /* cmd: ULTRA enable                */
+				/* bits 0-2, 7 rsvd for C1010       */
+
+/*04*/  u8	nc_scid;	/* cnf host adapter scsi address    */
+	#define   RRE     0x40  /* r/w:e enable response to resel.  */
+	#define   SRE     0x20  /* r/w:e enable response to select  */
+
+/*05*/  u8	nc_sxfer;	/* ### Sync speed and count         */
+				/* bits 6-7 rsvd for C1010          */
+
+/*06*/  u8	nc_sdid;	/* ### Destination-ID               */
+
+/*07*/  u8	nc_gpreg;	/* ??? IO-Pins                      */
+
+/*08*/  u8	nc_sfbr;	/* ### First byte received          */
+
+/*09*/  u8	nc_socl;
+	#define   CREQ	  0x80	/* r/w: SCSI-REQ                    */
+	#define   CACK	  0x40	/* r/w: SCSI-ACK                    */
+	#define   CBSY	  0x20	/* r/w: SCSI-BSY                    */
+	#define   CSEL	  0x10	/* r/w: SCSI-SEL                    */
+	#define   CATN	  0x08	/* r/w: SCSI-ATN                    */
+	#define   CMSG	  0x04	/* r/w: SCSI-MSG                    */
+	#define   CC_D	  0x02	/* r/w: SCSI-C_D                    */
+	#define   CI_O	  0x01	/* r/w: SCSI-I_O                    */
+
+/*0a*/  u8	nc_ssid;
+
+/*0b*/  u8	nc_sbcl;
+
+/*0c*/  u8	nc_dstat;
+        #define   DFE     0x80  /* sta: dma fifo empty              */
+        #define   MDPE    0x40  /* int: master data parity error    */
+        #define   BF      0x20  /* int: script: bus fault           */
+        #define   ABRT    0x10  /* int: script: command aborted     */
+        #define   SSI     0x08  /* int: script: single step         */
+        #define   SIR     0x04  /* int: script: interrupt instruct. */
+        #define   IID     0x01  /* int: script: illegal instruct.   */
+
+/*0d*/  u8	nc_sstat0;
+        #define   ILF     0x80  /* sta: data in SIDL register lsb   */
+        #define   ORF     0x40  /* sta: data in SODR register lsb   */
+        #define   OLF     0x20  /* sta: data in SODL register lsb   */
+        #define   AIP     0x10  /* sta: arbitration in progress     */
+        #define   LOA     0x08  /* sta: arbitration lost            */
+        #define   WOA     0x04  /* sta: arbitration won             */
+        #define   IRST    0x02  /* sta: scsi reset signal           */
+        #define   SDP     0x01  /* sta: scsi parity signal          */
+
+/*0e*/  u8	nc_sstat1;
+	#define   FF3210  0xf0	/* sta: bytes in the scsi fifo      */
+
+/*0f*/  u8	nc_sstat2;
+        #define   ILF1    0x80  /* sta: data in SIDL register msb[W]*/
+        #define   ORF1    0x40  /* sta: data in SODR register msb[W]*/
+        #define   OLF1    0x20  /* sta: data in SODL register msb[W]*/
+        #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
+        #define   LDSC    0x02  /* sta: disconnect & reconnect      */
+
+/*10*/  u8	nc_dsa;		/* --> Base page                    */
+/*11*/  u8	nc_dsa1;
+/*12*/  u8	nc_dsa2;
+/*13*/  u8	nc_dsa3;
+
+/*14*/  u8	nc_istat;	/* --> Main Command and status      */
+        #define   CABRT   0x80  /* cmd: abort current operation     */
+        #define   SRST    0x40  /* mod: reset chip                  */
+        #define   SIGP    0x20  /* r/w: message from host to script */
+        #define   SEM     0x10  /* r/w: message between host + script  */
+        #define   CON     0x08  /* sta: connected to scsi           */
+        #define   INTF    0x04  /* sta: int on the fly (reset by wr)*/
+        #define   SIP     0x02  /* sta: scsi-interrupt              */
+        #define   DIP     0x01  /* sta: host/script interrupt       */
+
+/*15*/  u8	nc_istat1;	/* 896 only */
+        #define   FLSH    0x04  /* sta: chip is flushing            */
+        #define   SCRUN   0x02  /* sta: scripts are running         */
+        #define   SIRQD   0x01  /* r/w: disable INT pin             */
+
+/*16*/  u8	nc_mbox0;	/* 896 only */
+/*17*/  u8	nc_mbox1;	/* 896 only */
+
+/*18*/	u8	nc_ctest0;
+/*19*/  u8	nc_ctest1;
+
+/*1a*/  u8	nc_ctest2;
+	#define   CSIGP   0x40
+				/* bits 0-2,7 rsvd for C1010        */
+
+/*1b*/  u8	nc_ctest3;
+	#define   FLF     0x08  /* cmd: flush dma fifo              */
+	#define   CLF	  0x04	/* cmd: clear dma fifo		    */
+	#define   FM      0x02  /* mod: fetch pin mode              */
+	#define   WRIE    0x01  /* mod: write and invalidate enable */
+				/* bits 4-7 rsvd for C1010          */
+
+/*1c*/  u32	nc_temp;	/* ### Temporary stack              */
+
+/*20*/	u8	nc_dfifo;
+/*21*/  u8	nc_ctest4;
+	#define   BDIS    0x80  /* mod: burst disable               */
+	#define   MPEE    0x08  /* mod: master parity error enable  */
+
+/*22*/  u8	nc_ctest5;
+	#define   DFS     0x20  /* mod: dma fifo size               */
+				/* bits 0-1, 3-7 rsvd for C1010     */
+
+/*23*/  u8	nc_ctest6;
+
+/*24*/  u32	nc_dbc;		/* ### Byte count and command       */
+/*28*/  u32	nc_dnad;	/* ### Next command register        */
+/*2c*/  u32	nc_dsp;		/* --> Script Pointer               */
+/*30*/  u32	nc_dsps;	/* --> Script pointer save/opcode#2 */
+
+/*34*/  u8	nc_scratcha;	/* Temporary register a            */
+/*35*/  u8	nc_scratcha1;
+/*36*/  u8	nc_scratcha2;
+/*37*/  u8	nc_scratcha3;
+
+/*38*/  u8	nc_dmode;
+	#define   BL_2    0x80  /* mod: burst length shift value +2 */
+	#define   BL_1    0x40  /* mod: burst length shift value +1 */
+	#define   ERL     0x08  /* mod: enable read line            */
+	#define   ERMP    0x04  /* mod: enable read multiple        */
+	#define   BOF     0x02  /* mod: burst op code fetch         */
+
+/*39*/  u8	nc_dien;
+/*3a*/  u8	nc_sbr;
+
+/*3b*/  u8	nc_dcntl;	/* --> Script execution control     */
+	#define   CLSE    0x80  /* mod: cache line size enable      */
+	#define   PFF     0x40  /* cmd: pre-fetch flush             */
+	#define   PFEN    0x20  /* mod: pre-fetch enable            */
+	#define   SSM     0x10  /* mod: single step mode            */
+	#define   IRQM    0x08  /* mod: irq mode (1 = totem pole !) */
+	#define   STD     0x04  /* cmd: start dma mode              */
+	#define   IRQD    0x02  /* mod: irq disable                 */
+ 	#define	  NOCOM   0x01	/* cmd: protect sfbr while reselect */
+				/* bits 0-1 rsvd for C1010          */
+
+/*3c*/  u32	nc_adder;
+
+/*40*/  u16	nc_sien;	/* -->: interrupt enable            */
+/*42*/  u16	nc_sist;	/* <--: interrupt status            */
+        #define   SBMC    0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
+        #define   STO     0x0400/* sta: timeout (select)            */
+        #define   GEN     0x0200/* sta: timeout (general)           */
+        #define   HTH     0x0100/* sta: timeout (handshake)         */
+        #define   MA      0x80  /* sta: phase mismatch              */
+        #define   CMP     0x40  /* sta: arbitration complete        */
+        #define   SEL     0x20  /* sta: selected by another device  */
+        #define   RSL     0x10  /* sta: reselected by another device*/
+        #define   SGE     0x08  /* sta: gross error (over/underflow)*/
+        #define   UDC     0x04  /* sta: unexpected disconnect       */
+        #define   RST     0x02  /* sta: scsi bus reset detected     */
+        #define   PAR     0x01  /* sta: scsi parity error           */
+
+/*44*/  u8	nc_slpar;
+/*45*/  u8	nc_swide;
+/*46*/  u8	nc_macntl;
+/*47*/  u8	nc_gpcntl;
+/*48*/  u8	nc_stime0;	/* cmd: timeout for select&handshake*/
+/*49*/  u8	nc_stime1;	/* cmd: timeout user defined        */
+/*4a*/  u16	nc_respid;	/* sta: Reselect-IDs                */
+
+/*4c*/  u8	nc_stest0;
+
+/*4d*/  u8	nc_stest1;
+	#define   SCLK    0x80	/* Use the PCI clock as SCSI clock	*/
+	#define   DBLEN   0x08	/* clock doubler running		*/
+	#define   DBLSEL  0x04	/* clock doubler selected		*/
+  
+
+/*4e*/  u8	nc_stest2;
+	#define   ROF     0x40	/* reset scsi offset (after gross error!) */
+	#define   EXT     0x02  /* extended filtering                     */
+
+/*4f*/  u8	nc_stest3;
+	#define   TE     0x80	/* c: tolerAnt enable */
+	#define   HSC    0x20	/* c: Halt SCSI Clock */
+	#define   CSF    0x02	/* c: clear scsi fifo */
+
+/*50*/  u16	nc_sidl;	/* Lowlevel: latched from scsi data */
+/*52*/  u8	nc_stest4;
+	#define   SMODE  0xc0	/* SCSI bus mode      (895/6 only) */
+	#define    SMODE_HVD 0x40	/* High Voltage Differential       */
+	#define    SMODE_SE  0x80	/* Single Ended                    */
+	#define    SMODE_LVD 0xc0	/* Low Voltage Differential        */
+	#define   LCKFRQ 0x20	/* Frequency Lock (895/6 only)     */
+				/* bits 0-5 rsvd for C1010         */
+
+/*53*/  u8	nc_53_;
+/*54*/  u16	nc_sodl;	/* Lowlevel: data out to scsi data  */
+/*56*/	u8	nc_ccntl0;	/* Chip Control 0 (896)             */
+	#define   ENPMJ  0x80	/* Enable Phase Mismatch Jump       */
+	#define   PMJCTL 0x40	/* Phase Mismatch Jump Control      */
+	#define   ENNDJ  0x20	/* Enable Non Data PM Jump          */
+	#define   DISFC  0x10	/* Disable Auto FIFO Clear          */
+	#define   DILS   0x02	/* Disable Internal Load/Store      */
+	#define   DPR    0x01	/* Disable Pipe Req                 */
+
+/*57*/	u8	nc_ccntl1;	/* Chip Control 1 (896)             */
+	#define   ZMOD   0x80	/* High Impedance Mode              */
+	#define   DDAC   0x08	/* Disable Dual Address Cycle       */
+	#define   XTIMOD 0x04	/* 64-bit Table Ind. Indexing Mode  */
+	#define   EXTIBMV 0x02	/* Enable 64-bit Table Ind. BMOV    */
+	#define   EXDBMV 0x01	/* Enable 64-bit Direct BMOV        */
+
+/*58*/  u16	nc_sbdl;	/* Lowlevel: data from scsi data    */
+/*5a*/  u16	nc_5a_;
+
+/*5c*/  u8	nc_scr0;	/* Working register B               */
+/*5d*/  u8	nc_scr1;
+/*5e*/  u8	nc_scr2;
+/*5f*/  u8	nc_scr3;
+
+/*60*/  u8	nc_scrx[64];	/* Working register C-R             */
+/*a0*/	u32	nc_mmrs;	/* Memory Move Read Selector        */
+/*a4*/	u32	nc_mmws;	/* Memory Move Write Selector       */
+/*a8*/	u32	nc_sfs;		/* Script Fetch Selector            */
+/*ac*/	u32	nc_drs;		/* DSA Relative Selector            */
+/*b0*/	u32	nc_sbms;	/* Static Block Move Selector       */
+/*b4*/	u32	nc_dbms;	/* Dynamic Block Move Selector      */
+/*b8*/	u32	nc_dnad64;	/* DMA Next Address 64              */
+/*bc*/	u16	nc_scntl4;	/* C1010 only                       */
+	#define   U3EN    0x80	/* Enable Ultra 3                   */
+	#define   AIPCKEN 0x40  /* AIP checking enable              */
+				/* Also enable AIP generation on C10-33*/
+	#define   XCLKH_DT 0x08 /* Extra clock of data hold on DT edge */
+	#define   XCLKH_ST 0x04 /* Extra clock of data hold on ST edge */
+	#define   XCLKS_DT 0x02 /* Extra clock of data set  on DT edge */
+	#define   XCLKS_ST 0x01 /* Extra clock of data set  on ST edge */
+/*be*/	u8	nc_aipcntl0;	/* AIP Control 0 C1010 only         */
+/*bf*/	u8	nc_aipcntl1;	/* AIP Control 1 C1010 only         */
+	#define DISAIP  0x08	/* Disable AIP generation C10-66 only  */
+/*c0*/	u32	nc_pmjad1;	/* Phase Mismatch Jump Address 1    */
+/*c4*/	u32	nc_pmjad2;	/* Phase Mismatch Jump Address 2    */
+/*c8*/	u8	nc_rbc;		/* Remaining Byte Count             */
+/*c9*/	u8	nc_rbc1;
+/*ca*/	u8	nc_rbc2;
+/*cb*/	u8	nc_rbc3;
+
+/*cc*/	u8	nc_ua;		/* Updated Address                  */
+/*cd*/	u8	nc_ua1;
+/*ce*/	u8	nc_ua2;
+/*cf*/	u8	nc_ua3;
+/*d0*/	u32	nc_esa;		/* Entry Storage Address            */
+/*d4*/	u8	nc_ia;		/* Instruction Address              */
+/*d5*/	u8	nc_ia1;
+/*d6*/	u8	nc_ia2;
+/*d7*/	u8	nc_ia3;
+/*d8*/	u32	nc_sbc;		/* SCSI Byte Count (3 bytes only)   */
+/*dc*/	u32	nc_csbc;	/* Cumulative SCSI Byte Count       */
+                                /* Following for C1010 only         */
+/*e0*/	u16    nc_crcpad;	/* CRC Value                        */
+/*e2*/	u8     nc_crccntl0;	/* CRC control register             */
+	#define   SNDCRC  0x10	/* Send CRC Request                 */
+/*e3*/	u8     nc_crccntl1;	/* CRC control register             */
+/*e4*/	u32    nc_crcdata;	/* CRC data register                */
+/*e8*/	u32    nc_e8_;
+/*ec*/	u32    nc_ec_;
+/*f0*/	u16    nc_dfbc;		/* DMA FIFO byte count              */ 
+};
+
+/*-----------------------------------------------------------
+ *
+ *	Utility macros for the script.
+ *
+ *-----------------------------------------------------------
+ */
+
+#define REGJ(p,r) (offsetof(struct sym_reg, p ## r))
+#define REG(r) REGJ (nc_, r)
+
+/*-----------------------------------------------------------
+ *
+ *	SCSI phases
+ *
+ *-----------------------------------------------------------
+ */
+
+#define	SCR_DATA_OUT	0x00000000
+#define	SCR_DATA_IN	0x01000000
+#define	SCR_COMMAND	0x02000000
+#define	SCR_STATUS	0x03000000
+#define	SCR_DT_DATA_OUT	0x04000000
+#define	SCR_DT_DATA_IN	0x05000000
+#define SCR_MSG_OUT	0x06000000
+#define SCR_MSG_IN      0x07000000
+/* DT phases are illegal for non Ultra3 mode */
+#define SCR_ILG_OUT	0x04000000
+#define SCR_ILG_IN	0x05000000
+
+/*-----------------------------------------------------------
+ *
+ *	Data transfer via SCSI.
+ *
+ *-----------------------------------------------------------
+ *
+ *	MOVE_ABS (LEN)
+ *	<<start address>>
+ *
+ *	MOVE_IND (LEN)
+ *	<<dnad_offset>>
+ *
+ *	MOVE_TBL
+ *	<<dnad_offset>>
+ *
+ *-----------------------------------------------------------
+ */
+
+#define OPC_MOVE          0x08000000
+
+#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
+/* #define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l)) */
+#define SCR_MOVE_TBL     (0x10000000 | OPC_MOVE)
+
+#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
+/* #define SCR_CHMOV_IND(l) ((0x20000000) | (l)) */
+#define SCR_CHMOV_TBL     (0x10000000)
+
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+/* We steal the `indirect addressing' flag for target mode MOVE in scripts */
+
+#define OPC_TCHMOVE        0x08000000
+
+#define SCR_TCHMOVE_ABS(l) ((0x20000000 | OPC_TCHMOVE) | (l))
+#define SCR_TCHMOVE_TBL     (0x30000000 | OPC_TCHMOVE)
+
+#define SCR_TMOV_ABS(l)    ((0x20000000) | (l))
+#define SCR_TMOV_TBL        (0x30000000)
+#endif
+
+struct sym_tblmove {
+        u32  size;
+        u32  addr;
+};
+
+/*-----------------------------------------------------------
+ *
+ *	Selection
+ *
+ *-----------------------------------------------------------
+ *
+ *	SEL_ABS | SCR_ID (0..15)    [ | REL_JMP]
+ *	<<alternate_address>>
+ *
+ *	SEL_TBL | << dnad_offset>>  [ | REL_JMP]
+ *	<<alternate_address>>
+ *
+ *-----------------------------------------------------------
+ */
+
+#define	SCR_SEL_ABS	0x40000000
+#define	SCR_SEL_ABS_ATN	0x41000000
+#define	SCR_SEL_TBL	0x42000000
+#define	SCR_SEL_TBL_ATN	0x43000000
+
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+#define	SCR_RESEL_ABS     0x40000000
+#define	SCR_RESEL_ABS_ATN 0x41000000
+#define	SCR_RESEL_TBL     0x42000000
+#define	SCR_RESEL_TBL_ATN 0x43000000
+#endif
+
+struct sym_tblsel {
+        u_char  sel_scntl4;	/* C1010 only */
+        u_char  sel_sxfer;
+        u_char  sel_id;
+        u_char  sel_scntl3;
+};
+
+#define SCR_JMP_REL     0x04000000
+#define SCR_ID(id)	(((u32)(id)) << 16)
+
+/*-----------------------------------------------------------
+ *
+ *	Waiting for Disconnect or Reselect
+ *
+ *-----------------------------------------------------------
+ *
+ *	WAIT_DISC
+ *	dummy: <<alternate_address>>
+ *
+ *	WAIT_RESEL
+ *	<<alternate_address>>
+ *
+ *-----------------------------------------------------------
+ */
+
+#define	SCR_WAIT_DISC	0x48000000
+#define SCR_WAIT_RESEL  0x50000000
+
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+#define	SCR_DISCONNECT	0x48000000
+#endif
+
+/*-----------------------------------------------------------
+ *
+ *	Bit Set / Reset
+ *
+ *-----------------------------------------------------------
+ *
+ *	SET (flags {|.. })
+ *
+ *	CLR (flags {|.. })
+ *
+ *-----------------------------------------------------------
+ */
+
+#define SCR_SET(f)     (0x58000000 | (f))
+#define SCR_CLR(f)     (0x60000000 | (f))
+
+#define	SCR_CARRY	0x00000400
+#define	SCR_TRG		0x00000200
+#define	SCR_ACK		0x00000040
+#define	SCR_ATN		0x00000008
+
+
+/*-----------------------------------------------------------
+ *
+ *	Memory to memory move
+ *
+ *-----------------------------------------------------------
+ *
+ *	COPY (bytecount)
+ *	<< source_address >>
+ *	<< destination_address >>
+ *
+ *	SCR_COPY   sets the NO FLUSH option by default.
+ *	SCR_COPY_F does not set this option.
+ *
+ *	For chips which do not support this option,
+ *	sym_fw_bind_script() will remove this bit.
+ *
+ *-----------------------------------------------------------
+ */
+
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
+
+/*-----------------------------------------------------------
+ *
+ *	Register move and binary operations
+ *
+ *-----------------------------------------------------------
+ *
+ *	SFBR_REG (reg, op, data)        reg  = SFBR op data
+ *	<< 0 >>
+ *
+ *	REG_SFBR (reg, op, data)        SFBR = reg op data
+ *	<< 0 >>
+ *
+ *	REG_REG  (reg, op, data)        reg  = reg op data
+ *	<< 0 >>
+ *
+ *-----------------------------------------------------------
+ *
+ *	On 825A, 875, 895 and 896 chips the content 
+ *	of SFBR register can be used as data (SCR_SFBR_DATA).
+ *	The 896 has additionnal IO registers starting at 
+ *	offset 0x80. Bit 7 of register offset is stored in 
+ *	bit 7 of the SCRIPTS instruction first DWORD.
+ *
+ *-----------------------------------------------------------
+ */
+
+#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80)) 
+
+#define SCR_SFBR_REG(reg,op,data) \
+        (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+#define SCR_REG_SFBR(reg,op,data) \
+        (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+#define SCR_REG_REG(reg,op,data) \
+        (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+
+#define      SCR_LOAD   0x00000000
+#define      SCR_SHL    0x01000000
+#define      SCR_OR     0x02000000
+#define      SCR_XOR    0x03000000
+#define      SCR_AND    0x04000000
+#define      SCR_SHR    0x05000000
+#define      SCR_ADD    0x06000000
+#define      SCR_ADDC   0x07000000
+
+#define      SCR_SFBR_DATA   (0x00800000>>8ul)	/* Use SFBR as data */
+
+/*-----------------------------------------------------------
+ *
+ *	FROM_REG (reg)		  SFBR = reg
+ *	<< 0 >>
+ *
+ *	TO_REG	 (reg)		  reg  = SFBR
+ *	<< 0 >>
+ *
+ *	LOAD_REG (reg, data)	  reg  = <data>
+ *	<< 0 >>
+ *
+ *	LOAD_SFBR(data) 	  SFBR = <data>
+ *	<< 0 >>
+ *
+ *-----------------------------------------------------------
+ */
+
+#define	SCR_FROM_REG(reg) \
+	SCR_REG_SFBR(reg,SCR_OR,0)
+
+#define	SCR_TO_REG(reg) \
+	SCR_SFBR_REG(reg,SCR_OR,0)
+
+#define	SCR_LOAD_REG(reg,data) \
+	SCR_REG_REG(reg,SCR_LOAD,data)
+
+#define SCR_LOAD_SFBR(data) \
+        (SCR_REG_SFBR (gpreg, SCR_LOAD, data))
+
+/*-----------------------------------------------------------
+ *
+ *	LOAD  from memory   to register.
+ *	STORE from register to memory.
+ *
+ *	Only supported by 810A, 860, 825A, 875, 895 and 896.
+ *
+ *-----------------------------------------------------------
+ *
+ *	LOAD_ABS (LEN)
+ *	<<start address>>
+ *
+ *	LOAD_REL (LEN)        (DSA relative)
+ *	<<dsa_offset>>
+ *
+ *-----------------------------------------------------------
+ */
+
+#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul)
+#define SCR_NO_FLUSH2	0x02000000
+#define SCR_DSA_REL2	0x10000000
+
+#define SCR_LOAD_R(reg, how, n) \
+        (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
+
+#define SCR_STORE_R(reg, how, n) \
+        (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
+
+#define SCR_LOAD_ABS(reg, n)	SCR_LOAD_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_LOAD_REL(reg, n)	SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n)
+#define SCR_LOAD_ABS_F(reg, n)	SCR_LOAD_R(reg, 0, n)
+#define SCR_LOAD_REL_F(reg, n)	SCR_LOAD_R(reg, SCR_DSA_REL2, n)
+
+#define SCR_STORE_ABS(reg, n)	SCR_STORE_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_STORE_REL(reg, n)	SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n)
+#define SCR_STORE_ABS_F(reg, n)	SCR_STORE_R(reg, 0, n)
+#define SCR_STORE_REL_F(reg, n)	SCR_STORE_R(reg, SCR_DSA_REL2, n)
+
+
+/*-----------------------------------------------------------
+ *
+ *	Waiting for Disconnect or Reselect
+ *
+ *-----------------------------------------------------------
+ *
+ *	JUMP            [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<address>>
+ *
+ *	JUMPR           [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<distance>>
+ *
+ *	CALL            [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<address>>
+ *
+ *	CALLR           [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<distance>>
+ *
+ *	RETURN          [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<dummy>>
+ *
+ *	INT             [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<ident>>
+ *
+ *	INT_FLY         [ | IFTRUE/IFFALSE ( ... ) ]
+ *	<<ident>>
+ *
+ *	Conditions:
+ *	     WHEN (phase)
+ *	     IF   (phase)
+ *	     CARRYSET
+ *	     DATA (data, mask)
+ *
+ *-----------------------------------------------------------
+ */
+
+#define SCR_NO_OP       0x80000000
+#define SCR_JUMP        0x80080000
+#define SCR_JUMP64      0x80480000
+#define SCR_JUMPR       0x80880000
+#define SCR_CALL        0x88080000
+#define SCR_CALLR       0x88880000
+#define SCR_RETURN      0x90080000
+#define SCR_INT         0x98080000
+#define SCR_INT_FLY     0x98180000
+
+#define IFFALSE(arg)   (0x00080000 | (arg))
+#define IFTRUE(arg)    (0x00000000 | (arg))
+
+#define WHEN(phase)    (0x00030000 | (phase))
+#define IF(phase)      (0x00020000 | (phase))
+
+#define DATA(D)        (0x00040000 | ((D) & 0xff))
+#define MASK(D,M)      (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
+
+#define CARRYSET       (0x00200000)
+
+/*-----------------------------------------------------------
+ *
+ *	SCSI  constants.
+ *
+ *-----------------------------------------------------------
+ */
+
+/*
+ *	Messages
+ */
+
+#define	M_COMPLETE	COMMAND_COMPLETE
+#define	M_EXTENDED	EXTENDED_MESSAGE
+#define	M_SAVE_DP	SAVE_POINTERS
+#define	M_RESTORE_DP	RESTORE_POINTERS
+#define	M_DISCONNECT	DISCONNECT
+#define	M_ID_ERROR	INITIATOR_ERROR
+#define	M_ABORT		ABORT_TASK_SET
+#define	M_REJECT	MESSAGE_REJECT
+#define	M_NOOP		NOP
+#define	M_PARITY	MSG_PARITY_ERROR
+#define	M_LCOMPLETE	LINKED_CMD_COMPLETE
+#define	M_FCOMPLETE	LINKED_FLG_CMD_COMPLETE
+#define	M_RESET		TARGET_RESET
+#define	M_ABORT_TAG	ABORT_TASK
+#define	M_CLEAR_QUEUE	CLEAR_TASK_SET
+#define	M_INIT_REC	INITIATE_RECOVERY
+#define	M_REL_REC	RELEASE_RECOVERY
+#define	M_TERMINATE	(0x11)
+#define	M_SIMPLE_TAG	SIMPLE_QUEUE_TAG
+#define	M_HEAD_TAG	HEAD_OF_QUEUE_TAG
+#define	M_ORDERED_TAG	ORDERED_QUEUE_TAG
+#define	M_IGN_RESIDUE	IGNORE_WIDE_RESIDUE
+
+#define	M_X_MODIFY_DP	EXTENDED_MODIFY_DATA_POINTER
+#define	M_X_SYNC_REQ	EXTENDED_SDTR
+#define	M_X_WIDE_REQ	EXTENDED_WDTR
+#define	M_X_PPR_REQ	EXTENDED_PPR
+
+/*
+ *	PPR protocol options
+ */
+#define	PPR_OPT_IU	(0x01)
+#define	PPR_OPT_DT	(0x02)
+#define	PPR_OPT_QAS	(0x04)
+#define PPR_OPT_MASK	(0x07)
+
+/*
+ *	Status
+ */
+
+#define	S_GOOD		SAM_STAT_GOOD
+#define	S_CHECK_COND	SAM_STAT_CHECK_CONDITION
+#define	S_COND_MET	SAM_STAT_CONDITION_MET
+#define	S_BUSY		SAM_STAT_BUSY
+#define	S_INT		SAM_STAT_INTERMEDIATE
+#define	S_INT_COND_MET	SAM_STAT_INTERMEDIATE_CONDITION_MET
+#define	S_CONFLICT	SAM_STAT_RESERVATION_CONFLICT
+#define	S_TERMINATED	SAM_STAT_COMMAND_TERMINATED
+#define	S_QUEUE_FULL	SAM_STAT_TASK_SET_FULL
+#define	S_ILLEGAL	(0xff)
+
+#endif /* defined SYM_DEFS_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.c b/drivers/scsi/sym53c8xx_2/sym_fw.c
new file mode 100644
index 0000000..fd36cf9
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.c
@@ -0,0 +1,568 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef __FreeBSD__
+#include <dev/sym/sym_glue.h>
+#else
+#include "sym_glue.h"
+#endif
+
+/*
+ *  Macros used for all firmwares.
+ */
+#define	SYM_GEN_A(s, label)	((short) offsetof(s, label)),
+#define	SYM_GEN_B(s, label)	((short) offsetof(s, label)),
+#define	SYM_GEN_Z(s, label)	((short) offsetof(s, label)),
+#define	PADDR_A(label)		SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
+#define	PADDR_B(label)		SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
+
+
+#if	SYM_CONF_GENERIC_SUPPORT
+/*
+ *  Allocate firmware #1 script area.
+ */
+#define	SYM_FWA_SCR		sym_fw1a_scr
+#define	SYM_FWB_SCR		sym_fw1b_scr
+#define	SYM_FWZ_SCR		sym_fw1z_scr
+#ifdef __FreeBSD__
+#include <dev/sym/sym_fw1.h>
+#else
+#include "sym_fw1.h"
+#endif
+static struct sym_fwa_ofs sym_fw1a_ofs = {
+	SYM_GEN_FW_A(struct SYM_FWA_SCR)
+};
+static struct sym_fwb_ofs sym_fw1b_ofs = {
+	SYM_GEN_FW_B(struct SYM_FWB_SCR)
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	SYM_GEN_B(struct SYM_FWB_SCR, data_io)
+#endif
+};
+static struct sym_fwz_ofs sym_fw1z_ofs = {
+	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
+};
+#undef	SYM_FWA_SCR
+#undef	SYM_FWB_SCR
+#undef	SYM_FWZ_SCR
+#endif	/* SYM_CONF_GENERIC_SUPPORT */
+
+/*
+ *  Allocate firmware #2 script area.
+ */
+#define	SYM_FWA_SCR		sym_fw2a_scr
+#define	SYM_FWB_SCR		sym_fw2b_scr
+#define	SYM_FWZ_SCR		sym_fw2z_scr
+#ifdef __FreeBSD__
+#include <dev/sym/sym_fw2.h>
+#else
+#include "sym_fw2.h"
+#endif
+static struct sym_fwa_ofs sym_fw2a_ofs = {
+	SYM_GEN_FW_A(struct SYM_FWA_SCR)
+};
+static struct sym_fwb_ofs sym_fw2b_ofs = {
+	SYM_GEN_FW_B(struct SYM_FWB_SCR)
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	SYM_GEN_B(struct SYM_FWB_SCR, data_io)
+#endif
+	SYM_GEN_B(struct SYM_FWB_SCR, start64)
+	SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
+};
+static struct sym_fwz_ofs sym_fw2z_ofs = {
+	SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
+};
+#undef	SYM_FWA_SCR
+#undef	SYM_FWB_SCR
+#undef	SYM_FWZ_SCR
+
+#undef	SYM_GEN_A
+#undef	SYM_GEN_B
+#undef	SYM_GEN_Z
+#undef	PADDR_A
+#undef	PADDR_B
+
+#if	SYM_CONF_GENERIC_SUPPORT
+/*
+ *  Patch routine for firmware #1.
+ */
+static void
+sym_fw1_patch(struct sym_hcb *np)
+{
+	struct sym_fw1a_scr *scripta0;
+	struct sym_fw1b_scr *scriptb0;
+
+	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
+	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
+
+	/*
+	 *  Remove LED support if not needed.
+	 */
+	if (!(np->features & FE_LED0)) {
+		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
+		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
+		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
+	}
+
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *    If user does not want to use IMMEDIATE ARBITRATION
+	 *    when we are reselected while attempting to arbitrate,
+	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
+	 */
+	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
+		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+#endif
+	/*
+	 *  Patch some data in SCRIPTS.
+	 *  - start and done queue initial bus address.
+	 *  - target bus address table bus address.
+	 */
+	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
+	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
+	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
+}
+#endif	/* SYM_CONF_GENERIC_SUPPORT */
+
+/*
+ *  Patch routine for firmware #2.
+ */
+static void
+sym_fw2_patch(struct sym_hcb *np)
+{
+	struct sym_fw2a_scr *scripta0;
+	struct sym_fw2b_scr *scriptb0;
+
+	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
+	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
+
+	/*
+	 *  Remove LED support if not needed.
+	 */
+	if (!(np->features & FE_LED0)) {
+		scripta0->idle[0]	= cpu_to_scr(SCR_NO_OP);
+		scripta0->reselected[0]	= cpu_to_scr(SCR_NO_OP);
+		scripta0->start[0]	= cpu_to_scr(SCR_NO_OP);
+	}
+
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 2
+	/*
+	 *  Remove useless 64 bit DMA specific SCRIPTS, 
+	 *  when this feature is not available.
+	 */
+	if (!np->use_dac) {
+		scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
+		scripta0->is_dmap_dirty[1] = 0;
+		scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
+		scripta0->is_dmap_dirty[3] = 0;
+	}
+#endif
+
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *    If user does not want to use IMMEDIATE ARBITRATION
+	 *    when we are reselected while attempting to arbitrate,
+	 *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
+	 */
+	if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
+		scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+#endif
+	/*
+	 *  Patch some variable in SCRIPTS.
+	 *  - start and done queue initial bus address.
+	 *  - target bus address table bus address.
+	 */
+	scriptb0->startpos[0]	= cpu_to_scr(np->squeue_ba);
+	scriptb0->done_pos[0]	= cpu_to_scr(np->dqueue_ba);
+	scriptb0->targtbl[0]	= cpu_to_scr(np->targtbl_ba);
+
+	/*
+	 *  Remove the load of SCNTL4 on reselection if not a C10.
+	 */
+	if (!(np->features & FE_C10)) {
+		scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
+		scripta0->resel_scntl4[1] = cpu_to_scr(0);
+	}
+
+	/*
+	 *  Remove a couple of work-arounds specific to C1010 if 
+	 *  they are not desirable. See `sym_fw2.h' for more details.
+	 */
+	if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_66 &&
+	      np->revision_id < 0x1 &&
+	      np->pciclk_khz < 60000)) {
+		scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
+		scripta0->datao_phase[1] = cpu_to_scr(0);
+	}
+	if (!(np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
+	      /* np->revision_id < 0xff */ 1)) {
+		scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
+		scripta0->sel_done[1] = cpu_to_scr(0);
+	}
+
+	/*
+	 *  Patch some other variables in SCRIPTS.
+	 *  These ones are loaded by the SCRIPTS processor.
+	 */
+	scriptb0->pm0_data_addr[0] =
+		cpu_to_scr(np->scripta_ba + 
+			   offsetof(struct sym_fw2a_scr, pm0_data));
+	scriptb0->pm1_data_addr[0] =
+		cpu_to_scr(np->scripta_ba + 
+			   offsetof(struct sym_fw2a_scr, pm1_data));
+}
+
+/*
+ *  Fill the data area in scripts.
+ *  To be done for all firmwares.
+ */
+static void
+sym_fw_fill_data (u32 *in, u32 *out)
+{
+	int	i;
+
+	for (i = 0; i < SYM_CONF_MAX_SG; i++) {
+		*in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;
+		*in++  = offsetof (struct sym_dsb, data[i]);
+		*out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
+		*out++ = offsetof (struct sym_dsb, data[i]);
+	}
+}
+
+/*
+ *  Setup useful script bus addresses.
+ *  To be done for all firmwares.
+ */
+static void 
+sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
+{
+	u32 *pa;
+	u_short *po;
+	int i;
+
+	/*
+	 *  Build the bus address table for script A 
+	 *  from the script A offset table.
+	 */
+	po = (u_short *) fw->a_ofs;
+	pa = (u32 *) &np->fwa_bas;
+	for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
+		pa[i] = np->scripta_ba + po[i];
+
+	/*
+	 *  Same for script B.
+	 */
+	po = (u_short *) fw->b_ofs;
+	pa = (u32 *) &np->fwb_bas;
+	for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
+		pa[i] = np->scriptb_ba + po[i];
+
+	/*
+	 *  Same for script Z.
+	 */
+	po = (u_short *) fw->z_ofs;
+	pa = (u32 *) &np->fwz_bas;
+	for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
+		pa[i] = np->scriptz_ba + po[i];
+}
+
+#if	SYM_CONF_GENERIC_SUPPORT
+/*
+ *  Setup routine for firmware #1.
+ */
+static void 
+sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
+{
+	struct sym_fw1a_scr *scripta0;
+	struct sym_fw1b_scr *scriptb0;
+
+	scripta0 = (struct sym_fw1a_scr *) np->scripta0;
+	scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
+
+	/*
+	 *  Fill variable parts in scripts.
+	 */
+	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
+
+	/*
+	 *  Setup bus addresses used from the C code..
+	 */
+	sym_fw_setup_bus_addresses(np, fw);
+}
+#endif	/* SYM_CONF_GENERIC_SUPPORT */
+
+/*
+ *  Setup routine for firmware #2.
+ */
+static void 
+sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
+{
+	struct sym_fw2a_scr *scripta0;
+	struct sym_fw2b_scr *scriptb0;
+
+	scripta0 = (struct sym_fw2a_scr *) np->scripta0;
+	scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
+
+	/*
+	 *  Fill variable parts in scripts.
+	 */
+	sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
+
+	/*
+	 *  Setup bus addresses used from the C code..
+	 */
+	sym_fw_setup_bus_addresses(np, fw);
+}
+
+/*
+ *  Allocate firmware descriptors.
+ */
+#if	SYM_CONF_GENERIC_SUPPORT
+static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
+#endif	/* SYM_CONF_GENERIC_SUPPORT */
+static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
+
+/*
+ *  Find the most appropriate firmware for a chip.
+ */
+struct sym_fw * 
+sym_find_firmware(struct sym_chip *chip)
+{
+	if (chip->features & FE_LDSTR)
+		return &sym_fw2;
+#if	SYM_CONF_GENERIC_SUPPORT
+	else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
+		return &sym_fw1;
+#endif
+	else
+		return NULL;
+}
+
+/*
+ *  Bind a script to physical addresses.
+ */
+void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
+{
+	u32 opcode, new, old, tmp1, tmp2;
+	u32 *end, *cur;
+	int relocs;
+
+	cur = start;
+	end = start + len/4;
+
+	while (cur < end) {
+
+		opcode = *cur;
+
+		/*
+		 *  If we forget to change the length
+		 *  in scripts, a field will be
+		 *  padded with 0. This is an illegal
+		 *  command.
+		 */
+		if (opcode == 0) {
+			printf ("%s: ERROR0 IN SCRIPT at %d.\n",
+				sym_name(np), (int) (cur-start));
+			++cur;
+			continue;
+		};
+
+		/*
+		 *  We use the bogus value 0xf00ff00f ;-)
+		 *  to reserve data area in SCRIPTS.
+		 */
+		if (opcode == SCR_DATA_ZERO) {
+			*cur++ = 0;
+			continue;
+		}
+
+		if (DEBUG_FLAGS & DEBUG_SCRIPT)
+			printf ("%d:  <%x>\n", (int) (cur-start),
+				(unsigned)opcode);
+
+		/*
+		 *  We don't have to decode ALL commands
+		 */
+		switch (opcode >> 28) {
+		case 0xf:
+			/*
+			 *  LOAD / STORE DSA relative, don't relocate.
+			 */
+			relocs = 0;
+			break;
+		case 0xe:
+			/*
+			 *  LOAD / STORE absolute.
+			 */
+			relocs = 1;
+			break;
+		case 0xc:
+			/*
+			 *  COPY has TWO arguments.
+			 */
+			relocs = 2;
+			tmp1 = cur[1];
+			tmp2 = cur[2];
+			if ((tmp1 ^ tmp2) & 3) {
+				printf ("%s: ERROR1 IN SCRIPT at %d.\n",
+					sym_name(np), (int) (cur-start));
+			}
+			/*
+			 *  If PREFETCH feature not enabled, remove 
+			 *  the NO FLUSH bit if present.
+			 */
+			if ((opcode & SCR_NO_FLUSH) &&
+			    !(np->features & FE_PFEN)) {
+				opcode = (opcode & ~SCR_NO_FLUSH);
+			}
+			break;
+		case 0x0:
+			/*
+			 *  MOVE/CHMOV (absolute address)
+			 */
+			if (!(np->features & FE_WIDE))
+				opcode = (opcode | OPC_MOVE);
+			relocs = 1;
+			break;
+		case 0x1:
+			/*
+			 *  MOVE/CHMOV (table indirect)
+			 */
+			if (!(np->features & FE_WIDE))
+				opcode = (opcode | OPC_MOVE);
+			relocs = 0;
+			break;
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+		case 0x2:
+			/*
+			 *  MOVE/CHMOV in target role (absolute address)
+			 */
+			opcode &= ~0x20000000;
+			if (!(np->features & FE_WIDE))
+				opcode = (opcode & ~OPC_TCHMOVE);
+			relocs = 1;
+			break;
+		case 0x3:
+			/*
+			 *  MOVE/CHMOV in target role (table indirect)
+			 */
+			opcode &= ~0x20000000;
+			if (!(np->features & FE_WIDE))
+				opcode = (opcode & ~OPC_TCHMOVE);
+			relocs = 0;
+			break;
+#endif
+		case 0x8:
+			/*
+			 *  JUMP / CALL
+			 *  don't relocate if relative :-)
+			 */
+			if (opcode & 0x00800000)
+				relocs = 0;
+			else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
+				relocs = 2;
+			else
+				relocs = 1;
+			break;
+		case 0x4:
+		case 0x5:
+		case 0x6:
+		case 0x7:
+			relocs = 1;
+			break;
+		default:
+			relocs = 0;
+			break;
+		};
+
+		/*
+		 *  Scriptify:) the opcode.
+		 */
+		*cur++ = cpu_to_scr(opcode);
+
+		/*
+		 *  If no relocation, assume 1 argument 
+		 *  and just scriptize:) it.
+		 */
+		if (!relocs) {
+			*cur = cpu_to_scr(*cur);
+			++cur;
+			continue;
+		}
+
+		/*
+		 *  Otherwise performs all needed relocations.
+		 */
+		while (relocs--) {
+			old = *cur;
+
+			switch (old & RELOC_MASK) {
+			case RELOC_REGISTER:
+				new = (old & ~RELOC_MASK) + np->mmio_ba;
+				break;
+			case RELOC_LABEL_A:
+				new = (old & ~RELOC_MASK) + np->scripta_ba;
+				break;
+			case RELOC_LABEL_B:
+				new = (old & ~RELOC_MASK) + np->scriptb_ba;
+				break;
+			case RELOC_SOFTC:
+				new = (old & ~RELOC_MASK) + np->hcb_ba;
+				break;
+			case 0:
+				/*
+				 *  Don't relocate a 0 address.
+				 *  They are mostly used for patched or 
+				 *  script self-modified areas.
+				 */
+				if (old == 0) {
+					new = old;
+					break;
+				}
+				/* fall through */
+			default:
+				new = 0;
+				panic("sym_fw_bind_script: "
+				      "weird relocation %x\n", old);
+				break;
+			}
+
+			*cur++ = cpu_to_scr(new);
+		}
+	};
+}
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw.h b/drivers/scsi/sym53c8xx_2/sym_fw.h
new file mode 100644
index 0000000..43f6810
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_fw.h
@@ -0,0 +1,211 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef	SYM_FW_H
+#define	SYM_FW_H
+/*
+ *  Macro used to generate interfaces for script A.
+ */
+#define SYM_GEN_FW_A(s)							\
+	SYM_GEN_A(s, start)		SYM_GEN_A(s, getjob_begin)	\
+	SYM_GEN_A(s, getjob_end)					\
+	SYM_GEN_A(s, select)		SYM_GEN_A(s, wf_sel_done)	\
+	SYM_GEN_A(s, send_ident)					\
+	SYM_GEN_A(s, dispatch)		SYM_GEN_A(s, init)		\
+	SYM_GEN_A(s, clrack)		SYM_GEN_A(s, complete_error)	\
+	SYM_GEN_A(s, done)		SYM_GEN_A(s, done_end)		\
+	SYM_GEN_A(s, idle)		SYM_GEN_A(s, ungetjob)		\
+	SYM_GEN_A(s, reselect)						\
+	SYM_GEN_A(s, resel_tag)		SYM_GEN_A(s, resel_dsa)		\
+	SYM_GEN_A(s, resel_no_tag)					\
+	SYM_GEN_A(s, data_in)		SYM_GEN_A(s, data_in2)		\
+	SYM_GEN_A(s, data_out)		SYM_GEN_A(s, data_out2)		\
+	SYM_GEN_A(s, pm0_data)		SYM_GEN_A(s, pm1_data)
+
+/*
+ *  Macro used to generate interfaces for script B.
+ */
+#define SYM_GEN_FW_B(s)							\
+	SYM_GEN_B(s, no_data)						\
+	SYM_GEN_B(s, sel_for_abort)	SYM_GEN_B(s, sel_for_abort_1)	\
+	SYM_GEN_B(s, msg_bad)		SYM_GEN_B(s, msg_weird)		\
+	SYM_GEN_B(s, wdtr_resp)		SYM_GEN_B(s, send_wdtr)		\
+	SYM_GEN_B(s, sdtr_resp)		SYM_GEN_B(s, send_sdtr)		\
+	SYM_GEN_B(s, ppr_resp)		SYM_GEN_B(s, send_ppr)		\
+	SYM_GEN_B(s, nego_bad_phase)					\
+	SYM_GEN_B(s, ident_break) 	SYM_GEN_B(s, ident_break_atn)	\
+	SYM_GEN_B(s, sdata_in)		SYM_GEN_B(s, resel_bad_lun)	\
+	SYM_GEN_B(s, bad_i_t_l)		SYM_GEN_B(s, bad_i_t_l_q)	\
+	SYM_GEN_B(s, wsr_ma_helper)
+
+/*
+ *  Macro used to generate interfaces for script Z.
+ */
+#define SYM_GEN_FW_Z(s)							\
+	SYM_GEN_Z(s, snooptest)		SYM_GEN_Z(s, snoopend)
+
+/*
+ *  Generates structure interface that contains 
+ *  offsets within script A, B and Z.
+ */
+#define	SYM_GEN_A(s, label)	s label;
+#define	SYM_GEN_B(s, label)	s label;
+#define	SYM_GEN_Z(s, label)	s label;
+struct sym_fwa_ofs {
+	SYM_GEN_FW_A(u_short)
+};
+struct sym_fwb_ofs {
+	SYM_GEN_FW_B(u_short)
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	SYM_GEN_B(u_short, data_io)
+#endif
+	SYM_GEN_B(u_short, start64)
+	SYM_GEN_B(u_short, pm_handle)
+};
+struct sym_fwz_ofs {
+	SYM_GEN_FW_Z(u_short)
+};
+
+/*
+ *  Generates structure interface that contains 
+ *  bus addresses within script A, B and Z.
+ */
+struct sym_fwa_ba {
+	SYM_GEN_FW_A(u32)
+};
+struct sym_fwb_ba {
+	SYM_GEN_FW_B(u32)
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	SYM_GEN_B(u32, data_io)
+#endif
+	SYM_GEN_B(u32, start64);
+	SYM_GEN_B(u32, pm_handle);
+};
+struct sym_fwz_ba {
+	SYM_GEN_FW_Z(u32)
+};
+#undef	SYM_GEN_A
+#undef	SYM_GEN_B
+#undef	SYM_GEN_Z
+
+/*
+ *  Let cc know about the name of the controller data structure.
+ *  We need this for function prototype declarations just below.
+ */
+struct sym_hcb;
+
+/*
+ *  Generic structure that defines a firmware.
+ */ 
+struct sym_fw {
+	char	*name;		/* Name we want to print out	*/
+	u32	*a_base;	/* Pointer to script A template	*/
+	int	a_size;		/* Size of script A		*/
+	struct	sym_fwa_ofs
+		*a_ofs;		/* Useful offsets in script A	*/
+	u32	*b_base;	/* Pointer to script B template	*/
+	int	b_size;		/* Size of script B		*/
+	struct	sym_fwb_ofs
+		*b_ofs;		/* Useful offsets in script B	*/
+	u32	*z_base;	/* Pointer to script Z template	*/
+	int	z_size;		/* Size of script Z		*/
+	struct	sym_fwz_ofs
+		*z_ofs;		/* Useful offsets in script Z	*/
+	/* Setup and patch methods for this firmware */
+	void	(*setup)(struct sym_hcb *, struct sym_fw *);
+	void	(*patch)(struct sym_hcb *);
+};
+
+/*
+ *  Macro used to declare a firmware.
+ */
+#define SYM_FW_ENTRY(fw, name)					\
+{								\
+	name,							\
+	(u32 *) &fw##a_scr, sizeof(fw##a_scr), &fw##a_ofs,	\
+	(u32 *) &fw##b_scr, sizeof(fw##b_scr), &fw##b_ofs,	\
+	(u32 *) &fw##z_scr, sizeof(fw##z_scr), &fw##z_ofs,	\
+	fw##_setup, fw##_patch					\
+}
+
+/*
+ *  Macros used from the C code to get useful
+ *  SCRIPTS bus addresses.
+ */
+#define SCRIPTA_BA(np, label)	(np->fwa_bas.label)
+#define SCRIPTB_BA(np, label)	(np->fwb_bas.label)
+#define SCRIPTZ_BA(np, label)	(np->fwz_bas.label)
+
+/*
+ *  Macros used by scripts definitions.
+ *
+ *  HADDR_1 generates a reference to a field of the controller data.
+ *  HADDR_2 generates a reference to a field of the controller data
+ *          with offset.
+ *  RADDR_1 generates a reference to a script processor register.
+ *  RADDR_2 generates a reference to a script processor register
+ *          with offset.
+ *  PADDR_A generates a reference to another part of script A.
+ *  PADDR_B generates a reference to another part of script B.
+ *
+ *  SYM_GEN_PADDR_A and SYM_GEN_PADDR_B are used to define respectively 
+ *  the PADDR_A and PADDR_B macros for each firmware by setting argument 
+ *  `s' to the name of the corresponding structure.
+ *
+ *  SCR_DATA_ZERO is used to allocate a DWORD of data in scripts areas.
+ */
+
+#define	RELOC_SOFTC	0x40000000
+#define	RELOC_LABEL_A	0x50000000
+#define	RELOC_REGISTER	0x60000000
+#define	RELOC_LABEL_B	0x80000000
+#define	RELOC_MASK	0xf0000000
+
+#define	HADDR_1(label)	   (RELOC_SOFTC    | offsetof(struct sym_hcb, label))
+#define	HADDR_2(label,ofs) (RELOC_SOFTC    | \
+				(offsetof(struct sym_hcb, label)+(ofs)))
+#define	RADDR_1(label)	   (RELOC_REGISTER | REG(label))
+#define	RADDR_2(label,ofs) (RELOC_REGISTER | ((REG(label))+(ofs)))
+
+#define SYM_GEN_PADDR_A(s, label) (RELOC_LABEL_A  | offsetof(s, label))
+#define SYM_GEN_PADDR_B(s, label) (RELOC_LABEL_B  | offsetof(s, label))
+
+#define SCR_DATA_ZERO	0xf00ff00f
+
+#endif	/* SYM_FW_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw1.h b/drivers/scsi/sym53c8xx_2/sym_fw1.h
new file mode 100644
index 0000000..cdd92d8
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_fw1.h
@@ -0,0 +1,1838 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *  Scripts for SYMBIOS-Processor
+ *
+ *  We have to know the offsets of all labels before we reach 
+ *  them (for forward jumps). Therefore we declare a struct 
+ *  here. If you make changes inside the script,
+ *
+ *  DONT FORGET TO CHANGE THE LENGTHS HERE!
+ */
+
+/*
+ *  Script fragments which are loaded into the on-chip RAM 
+ *  of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
+ *  Must not exceed 4K bytes.
+ */
+struct SYM_FWA_SCR {
+	u32 start		[ 11];
+	u32 getjob_begin	[  4];
+	u32 _sms_a10		[  5];
+	u32 getjob_end		[  4];
+	u32 _sms_a20		[  4];
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 select		[  8];
+#else
+	u32 select		[  6];
+#endif
+	u32 _sms_a30		[  5];
+	u32 wf_sel_done		[  2];
+	u32 send_ident		[  2];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 select2		[  8];
+#else
+	u32 select2		[  2];
+#endif
+	u32 command		[  2];
+	u32 dispatch		[ 28];
+	u32 sel_no_cmd		[ 10];
+	u32 init		[  6];
+	u32 clrack		[  4];
+	u32 datai_done		[ 11];
+	u32 datai_done_wsr	[ 20];
+	u32 datao_done		[ 11];
+	u32 datao_done_wss	[  6];
+	u32 datai_phase		[  5];
+	u32 datao_phase		[  5];
+	u32 msg_in		[  2];
+	u32 msg_in2		[ 10];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 status		[ 14];
+#else
+	u32 status		[ 10];
+#endif
+	u32 complete		[  6];
+	u32 complete2		[  8];
+	u32 _sms_a40		[ 12];
+	u32 done		[  5];
+	u32 _sms_a50		[  5];
+	u32 _sms_a60		[  2];
+	u32 done_end		[  4];
+	u32 complete_error	[  5];
+	u32 save_dp		[ 11];
+	u32 restore_dp		[  7];
+	u32 disconnect		[ 11];
+	u32 disconnect2		[  5];
+	u32 _sms_a65		[  3];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 idle		[  4];
+#else
+	u32 idle		[  2];
+#endif
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 ungetjob		[  7];
+#else
+	u32 ungetjob		[  5];
+#endif
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 reselect		[  4];
+#else
+	u32 reselect		[  2];
+#endif
+	u32 reselected		[ 19];
+	u32 _sms_a70		[  6];
+	u32 _sms_a80		[  4];
+	u32 reselected1		[ 25];
+	u32 _sms_a90		[  4];
+	u32 resel_lun0		[  7];
+	u32 _sms_a100		[  4];
+	u32 resel_tag		[  8];
+#if   SYM_CONF_MAX_TASK*4 > 512
+	u32 _sms_a110		[ 23];
+#elif SYM_CONF_MAX_TASK*4 > 256
+	u32 _sms_a110		[ 17];
+#else
+	u32 _sms_a110		[ 13];
+#endif
+	u32 _sms_a120		[  2];
+	u32 resel_go		[  4];
+	u32 _sms_a130		[  7];
+	u32 resel_dsa		[  2];
+	u32 resel_dsa1		[  4];
+	u32 _sms_a140		[  7];
+	u32 resel_no_tag	[  4];
+	u32 _sms_a145		[  7];
+	u32 data_in		[SYM_CONF_MAX_SG * 2];
+	u32 data_in2		[  4];
+	u32 data_out		[SYM_CONF_MAX_SG * 2];
+	u32 data_out2		[  4];
+	u32 pm0_data		[ 12];
+	u32 pm0_data_out	[  6];
+	u32 pm0_data_end	[  7];
+	u32 pm_data_end		[  4];
+	u32 _sms_a150		[  4];
+	u32 pm1_data		[ 12];
+	u32 pm1_data_out	[  6];
+	u32 pm1_data_end	[  9];
+};
+
+/*
+ *  Script fragments which stay in main memory for all chips 
+ *  except for chips that support 8K on-chip RAM.
+ */
+struct SYM_FWB_SCR {
+	u32 no_data		[  2];
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 sel_for_abort	[ 18];
+#else
+	u32 sel_for_abort	[ 16];
+#endif
+	u32 sel_for_abort_1	[  2];
+	u32 msg_in_etc		[ 12];
+	u32 msg_received	[  5];
+	u32 msg_weird_seen	[  5];
+	u32 msg_extended	[ 17];
+	u32 _sms_b10		[  4];
+	u32 msg_bad		[  6];
+	u32 msg_weird		[  4];
+	u32 msg_weird1		[  8];
+	u32 wdtr_resp		[  6];
+	u32 send_wdtr		[  4];
+	u32 sdtr_resp		[  6];
+	u32 send_sdtr		[  4];
+	u32 ppr_resp		[  6];
+	u32 send_ppr		[  4];
+	u32 nego_bad_phase	[  4];
+	u32 msg_out		[  4];
+	u32 msg_out_done	[  4];
+	u32 data_ovrun		[  3];
+	u32 data_ovrun1		[ 22];
+	u32 data_ovrun2		[  8];
+	u32 abort_resel		[ 16];
+	u32 resend_ident	[  4];
+	u32 ident_break		[  4];
+	u32 ident_break_atn	[  4];
+	u32 sdata_in		[  6];
+	u32 resel_bad_lun	[  4];
+	u32 bad_i_t_l		[  4];
+	u32 bad_i_t_l_q		[  4];
+	u32 bad_status		[  7];
+	u32 wsr_ma_helper	[  4];
+
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	/* Unknown direction handling */
+	u32 data_io		[  2];
+	u32 data_io_com		[  8];
+	u32 data_io_out		[  7];
+#endif
+	/* Data area */
+	u32 zero		[  1];
+	u32 scratch		[  1];
+	u32 scratch1		[  1];
+	u32 prev_done		[  1];
+	u32 done_pos		[  1];
+	u32 nextjob		[  1];
+	u32 startpos		[  1];
+	u32 targtbl		[  1];
+};
+
+/*
+ *  Script fragments used at initialisations.
+ *  Only runs out of main memory.
+ */
+struct SYM_FWZ_SCR {
+	u32 snooptest		[  9];
+	u32 snoopend		[  2];
+};
+
+static struct SYM_FWA_SCR SYM_FWA_SCR = {
+/*--------------------------< START >----------------------------*/ {
+	/*
+	 *  Switch the LED on.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+		0,
+	/*
+	 *      Clear SIGP.
+	 */
+	SCR_FROM_REG (ctest2),
+		0,
+	/*
+	 *  Stop here if the C code wants to perform 
+	 *  some error recovery procedure manually.
+	 *  (Indicate this by setting SEM in ISTAT)
+	 */
+	SCR_FROM_REG (istat),
+		0,
+	/*
+	 *  Report to the C code the next position in 
+	 *  the start queue the SCRIPTS will schedule.
+	 *  The C code must not change SCRATCHA.
+	 */
+	SCR_COPY (4),
+		PADDR_B (startpos),
+		RADDR_1 (scratcha),
+	SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
+		SIR_SCRIPT_STOPPED,
+	/*
+	 *  Start the next job.
+	 *
+	 *  @DSA     = start point for this job.
+	 *  SCRATCHA = address of this job in the start queue.
+	 *
+	 *  We will restore startpos with SCRATCHA if we fails the 
+	 *  arbitration or if it is the idle job.
+	 *
+	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
+	 *  is a critical path. If it is partially executed, it then 
+	 *  may happen that the job address is not yet in the DSA 
+	 *  and the next queue position points to the next JOB.
+	 */
+}/*-------------------------< GETJOB_BEGIN >---------------------*/,{
+	/*
+	 *  Copy to a fixed location both the next STARTPOS 
+	 *  and the current JOB address, using self modifying 
+	 *  SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (scratcha),
+		PADDR_A (_sms_a10),
+	SCR_COPY (8),
+}/*-------------------------< _SMS_A10 >-------------------------*/,{
+		0,
+		PADDR_B (nextjob),
+	/*
+	 *  Move the start address to TEMP using self-
+	 *  modifying SCRIPTS and jump indirectly to 
+	 *  that address.
+	 */
+	SCR_COPY (4),
+		PADDR_B (nextjob),
+		RADDR_1 (dsa),
+}/*-------------------------< GETJOB_END >-----------------------*/,{
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a20),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A20 >-------------------------*/,{
+		0,
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< SELECT >---------------------------*/,{
+	/*
+	 *  DSA	contains the address of a scheduled
+	 *  	data structure.
+	 *
+	 *  SCRATCHA contains the address of the start queue  
+	 *  	entry which points to the next job.
+	 *
+	 *  Set Initiator mode.
+	 *
+	 *  (Target mode is left as an exercise for the reader)
+	 */
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *      And try to select this target.
+	 */
+	SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select),
+		PADDR_A (ungetjob),
+	/*
+	 *  Now there are 4 possibilities:
+	 *
+	 *  (1) The chip loses arbitration.
+	 *  This is ok, because it will try again,
+	 *  when the bus becomes idle.
+	 *  (But beware of the timeout function!)
+	 *
+	 *  (2) The chip is reselected.
+	 *  Then the script processor takes the jump
+	 *  to the RESELECT label.
+	 *
+	 *  (3) The chip wins arbitration.
+	 *  Then it will execute SCRIPTS instruction until 
+	 *  the next instruction that checks SCSI phase.
+	 *  Then will stop and wait for selection to be 
+	 *  complete or selection time-out to occur.
+	 *
+	 *  After having won arbitration, the SCRIPTS  
+	 *  processor is able to execute instructions while 
+	 *  the SCSI core is performing SCSI selection.
+	 */
+
+	/*
+	 *  Copy the CCB header to a fixed location 
+	 *  in the HCB using self-modifying SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a30),
+	SCR_COPY (sizeof(struct sym_ccbh)),
+}/*-------------------------< _SMS_A30 >-------------------------*/,{
+		0,
+		HADDR_1 (ccb_head),
+	/*
+	 *  Initialize the status register
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.status),
+		RADDR_1 (scr0),
+}/*-------------------------< WF_SEL_DONE >----------------------*/,{
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		SIR_SEL_ATN_NO_MSG_OUT,
+}/*-------------------------< SEND_IDENT >-----------------------*/,{
+	/*
+	 *  Selection complete.
+	 *  Send the IDENTIFY and possibly the TAG message 
+	 *  and negotiation message if present.
+	 */
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct sym_dsb, smsg),
+}/*-------------------------< SELECT2 >--------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  Set IMMEDIATE ARBITRATION if we have been given 
+	 *  a hint to do so. (Some job to do after this one).
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+		8,
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	 *  Anticipate the COMMAND phase.
+	 *  This is the PHASE we expect at this point.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
+		PADDR_A (sel_no_cmd),
+}/*-------------------------< COMMAND >--------------------------*/,{
+	/*
+	 *  ... and send the command
+	 */
+	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct sym_dsb, cmd),
+}/*-------------------------< DISPATCH >-------------------------*/,{
+	/*
+	 *  MSG_IN is the only phase that shall be 
+	 *  entered at least once for each (re)selection.
+	 *  So we test it first.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
+		PADDR_A (datao_phase),
+	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
+		PADDR_A (datai_phase),
+	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+		PADDR_A (command),
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+		PADDR_B (msg_out),
+	/*
+	 *  Discard as many illegal phases as 
+	 *  required and tell the C code about.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+		16,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+		HADDR_1 (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+		-16,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+		16,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+		HADDR_1 (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+		-16,
+	SCR_INT,
+		SIR_BAD_PHASE,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< SEL_NO_CMD >-----------------------*/,{
+	/*
+	 *  The target does not switch to command 
+	 *  phase after IDENTIFY has been sent.
+	 *
+	 *  If it stays in MSG OUT phase send it 
+	 *  the IDENTIFY again.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (resend_ident),
+	/*
+	 *  If target does not switch to MSG IN phase 
+	 *  and we sent a negotiation, assert the 
+	 *  failure immediately.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+	/*
+	 *  Jump to dispatcher.
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< INIT >-----------------------------*/,{
+	/*
+	 *  Wait for the SCSI RESET signal to be 
+	 *  inactive before restarting operations, 
+	 *  since the chip may hang on SEL_ATN 
+	 *  if SCSI RESET is active.
+	 */
+	SCR_FROM_REG (sstat0),
+		0,
+	SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
+		-16,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< CLRACK >---------------------------*/,{
+	/*
+	 *  Terminate possible pending message phase.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE >-----------------------*/,{
+	/*
+	 *  Save current pointer to LASTP.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (temp),
+		HADDR_1 (ccb_head.lastp),
+	/*
+	 *  If the SWIDE is not full, jump to dispatcher.
+	 *  We anticipate a STATUS phase.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (WSR, WSR)),
+		PADDR_A (datai_done_wsr),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE_WSR >-------------------*/,{
+	/*
+	 *  The SWIDE is full.
+	 *  Clear this condition.
+	 */
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+	 *  We are expecting an IGNORE RESIDUE message 
+	 *  from the device, otherwise we are in data 
+	 *  overrun condition. Check against MSG_IN phase.
+	 */
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	/*
+	 *  We are in MSG_IN phase,
+	 *  Read the first byte of the message.
+	 *  If it is not an IGNORE RESIDUE message,
+	 *  signal overrun and jump to message 
+	 *  processing.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[0]),
+	SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR_A (msg_in2),
+	/*
+	 *  We got the message we expected.
+	 *  Read the 2nd byte, and jump to dispatcher.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAO_DONE >-----------------------*/,{
+	/*
+	 *  Save current pointer to LASTP.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (temp),
+		HADDR_1 (ccb_head.lastp),
+	/*
+	 *  If the SODL is not full jump to dispatcher.
+	 *  We anticipate a STATUS phase.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (WSS, WSS)),
+		PADDR_A (datao_done_wss),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAO_DONE_WSS >-------------------*/,{
+	/*
+	 *  The SODL is full, clear this condition.
+	 */
+	SCR_REG_REG (scntl2, SCR_OR, WSS),
+		0,
+	/*
+	 *  And signal a DATA UNDERRUN condition 
+	 *  to the C code.
+	 */
+	SCR_INT,
+		SIR_SODL_UNDERRUN,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_PHASE >----------------------*/,{
+	/*
+	 *  Jump to current pointer.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.lastp),
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< DATAO_PHASE >----------------------*/,{
+	/*
+	 *  Jump to current pointer.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.lastp),
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< MSG_IN >---------------------------*/,{
+	/*
+	 *  Get the first byte of the message.
+	 *
+	 *  The script processor doesn't negate the
+	 *  ACK signal after this transfer.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------------*/,{
+	/*
+	 *  Check first against 1 byte messages 
+	 *  that we handle from SCRIPTS.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+		PADDR_A (complete),
+	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+		PADDR_A (disconnect),
+	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+		PADDR_A (save_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+		PADDR_A (restore_dp),
+	/*
+	 *  We handle all other messages from the 
+	 *  C code, so no need to waste on-chip RAM 
+	 *  for those ones.
+	 */
+	SCR_JUMP,
+		PADDR_B (msg_in_etc),
+}/*-------------------------< STATUS >---------------------------*/,{
+	/*
+	 *  get the status
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		HADDR_1 (scratch),
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, 
+	 *  since we may have to tamper the start queue from 
+	 *  the C code.
+	 */
+	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+		8,
+	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+		0,
+#endif
+	/*
+	 *  save status to scsi_status.
+	 *  mark as complete.
+	 */
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	/*
+	 *  Anticipate the MESSAGE PHASE for 
+	 *  the TASK COMPLETE message.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< COMPLETE >-------------------------*/,{
+	/*
+	 *  Complete message.
+	 *
+	 *  When we terminate the cycle by clearing ACK,
+	 *  the target may disconnect immediately.
+	 *
+	 *  We don't want to be told of an "unexpected disconnect",
+	 *  so we disable this feature.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	/*
+	 *  Terminate cycle ...
+	 */
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	 *  ... and wait for the disconnect.
+	 */
+	SCR_WAIT_DISC,
+		0,
+}/*-------------------------< COMPLETE2 >------------------------*/,{
+	/*
+	 *  Save host status.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (scr0),
+		HADDR_1 (ccb_head.status),
+	/*
+	 *  Move back the CCB header using self-modifying 
+	 *  SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a40),
+	SCR_COPY (sizeof(struct sym_ccbh)),
+		HADDR_1 (ccb_head),
+}/*-------------------------< _SMS_A40 >-------------------------*/,{
+		0,
+	/*
+	 *  Some bridges may reorder DMA writes to memory.
+	 *  We donnot want the CPU to deal with completions  
+	 *  without all the posted write having been flushed 
+	 *  to memory. This DUMMY READ should flush posted 
+	 *  buffers prior to the CPU having to deal with 
+	 *  completions.
+	 */
+	SCR_COPY (4),			/* DUMMY READ */
+		HADDR_1 (ccb_head.status),
+		RADDR_1 (scr0),
+	/*
+	 *  If command resulted in not GOOD status,
+	 *  call the C code if needed.
+	 */
+	SCR_FROM_REG (SS_REG),
+		0,
+	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+		PADDR_B (bad_status),
+	/*
+	 *  If we performed an auto-sense, call 
+	 *  the C code to synchronyze task aborts 
+	 *  with UNIT ATTENTION conditions.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
+		PADDR_A (complete_error),
+}/*-------------------------< DONE >-----------------------------*/,{
+	/*
+	 *  Copy the DSA to the DONE QUEUE and 
+	 *  signal completion to the host.
+	 *  If we are interrupted between DONE 
+	 *  and DONE_END, we must reset, otherwise 
+	 *  the completed CCB may be lost.
+	 */
+	SCR_COPY (4),
+		PADDR_B (done_pos),
+		PADDR_A (_sms_a50),
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+}/*-------------------------< _SMS_A50 >-------------------------*/,{
+		0,
+	SCR_COPY (4),
+		PADDR_B (done_pos),
+		PADDR_A (_sms_a60),
+	/*
+	 *  The instruction below reads the DONE QUEUE next 
+	 *  free position from memory.
+	 *  In addition it ensures that all PCI posted writes  
+	 *  are flushed and so the DSA value of the done 
+	 *  CCB is visible by the CPU before INTFLY is raised.
+	 */
+	SCR_COPY (8),
+}/*-------------------------< _SMS_A60 >-------------------------*/,{
+		0,
+		PADDR_B (prev_done),
+}/*-------------------------< DONE_END >-------------------------*/,{
+	SCR_INT_FLY,
+		0,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< COMPLETE_ERROR >-------------------*/,{
+	SCR_COPY (4),
+		PADDR_B (startpos),
+		RADDR_1 (scratcha),
+	SCR_INT,
+		SIR_COMPLETE_ERROR,
+}/*-------------------------< SAVE_DP >--------------------------*/,{
+	/*
+	 *  Clear ACK immediately.
+	 *  No need to delay it.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  Keep track we received a SAVE DP, so 
+	 *  we will switch to the other PM context 
+	 *  on the next PM since the DP may point 
+	 *  to the current PM context.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+		0,
+	/*
+	 *  SAVE_DP message:
+	 *  Copy LASTP to SAVEP.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.lastp),
+		HADDR_1 (ccb_head.savep),
+	/*
+	 *  Anticipate the MESSAGE PHASE for 
+	 *  the DISCONNECT message.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< RESTORE_DP >-----------------------*/,{
+	/*
+	 *  Clear ACK immediately.
+	 *  No need to delay it.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  Copy SAVEP to LASTP.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.savep),
+		HADDR_1 (ccb_head.lastp),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DISCONNECT >-----------------------*/,{
+	/*
+	 *  DISCONNECTing  ...
+	 *
+	 *  disable the "unexpected disconnect" feature,
+	 *  and remove the ACK signal.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	 *  Wait for the disconnect.
+	 */
+	SCR_WAIT_DISC,
+		0,
+	/*
+	 *  Status is: DISCONNECTED.
+	 */
+	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+		0,
+	/*
+	 *  Save host status.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (scr0),
+		HADDR_1 (ccb_head.status),
+}/*-------------------------< DISCONNECT2 >----------------------*/,{
+	/*
+	 *  Move back the CCB header using self-modifying 
+	 *  SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a65),
+	SCR_COPY (sizeof(struct sym_ccbh)),
+		HADDR_1 (ccb_head),
+}/*-------------------------< _SMS_A65 >-------------------------*/,{
+		0,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< IDLE >-----------------------------*/,{
+	/*
+	 *  Nothing to do?
+	 *  Switch the LED off and wait for reselect.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_OR, 0x01),
+		0,
+#ifdef SYM_CONF_IARB_SUPPORT
+	SCR_JUMPR,
+		8,
+#endif
+}/*-------------------------< UNGETJOB >-------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  Set IMMEDIATE ARBITRATION, for the next time.
+	 *  This will give us better chance to win arbitration 
+	 *  for the job we just wanted to do.
+	 */
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	 *  We are not able to restart the SCRIPTS if we are 
+	 *  interrupted and these instruction haven't been 
+	 *  all executed. BTW, this is very unlikely to 
+	 *  happen, but we check that from the C code.
+	 */
+	SCR_LOAD_REG (dsa, 0xff),
+		0,
+	SCR_COPY (4),
+		RADDR_1 (scratcha),
+		PADDR_B (startpos),
+}/*-------------------------< RESELECT >-------------------------*/,{
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	/*
+	 *  Make sure we are in initiator mode.
+	 */
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *  Sleep waiting for a reselection.
+	 */
+	SCR_WAIT_RESEL,
+		PADDR_A(start),
+}/*-------------------------< RESELECTED >-----------------------*/,{
+	/*
+	 *  Switch the LED on.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+		0,
+	/*
+	 *  load the target id into the sdid
+	 */
+	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+		0,
+	SCR_TO_REG (sdid),
+		0,
+	/*
+	 *  Load the target control block address
+	 */
+	SCR_COPY (4),
+		PADDR_B (targtbl),
+		RADDR_1 (dsa),
+	SCR_SFBR_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_AND, 0x3c),
+		0,
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a70),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A70 >-------------------------*/,{
+		0,
+		RADDR_1 (dsa),
+	/*
+	 *  Copy the TCB header to a fixed place in 
+	 *  the HCB.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a80),
+	SCR_COPY (sizeof(struct sym_tcbh)),
+}/*-------------------------< _SMS_A80 >-------------------------*/,{
+		0,
+		HADDR_1 (tcb_head),
+	/*
+	 *  We expect MESSAGE IN phase.
+	 *  If not, get help from the C code.
+	 */
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_RESEL_NO_MSG_IN,
+}/*-------------------------< RESELECTED1 >----------------------*/,{
+	/*
+	 *  Load the synchronous transfer registers.
+	 */
+	SCR_COPY (1),
+		HADDR_1 (tcb_head.wval),
+		RADDR_1 (scntl3),
+	SCR_COPY (1),
+		HADDR_1 (tcb_head.sval),
+		RADDR_1 (sxfer),
+	/*
+	 *  Get the IDENTIFY message.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin),
+	/*
+	 *  If IDENTIFY LUN #0, use a faster path 
+	 *  to find the LCB structure.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)),
+		PADDR_A (resel_lun0),
+	/*
+	 *  If message isn't an IDENTIFY, 
+	 *  tell the C code about.
+	 */
+	SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
+		SIR_RESEL_NO_IDENTIFY,
+	/*
+	 *  It is an IDENTIFY message,
+	 *  Load the LUN control block address.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (tcb_head.luntbl_sa),
+		RADDR_1 (dsa),
+	SCR_SFBR_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_AND, 0xfc),
+		0,
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a90),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A90 >-------------------------*/,{
+		0,
+		RADDR_1 (dsa),
+	SCR_JUMPR,
+		12,
+}/*-------------------------< RESEL_LUN0 >-----------------------*/,{
+	/*
+	 *  LUN 0 special case (but usual one :))
+	 */
+	SCR_COPY (4),
+		HADDR_1 (tcb_head.lun0_sa),
+		RADDR_1 (dsa),
+	/*
+	 *  Jump indirectly to the reselect action for this LUN.
+	 *  (lcb.head.resel_sa assumed at offset zero of lcb).
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a100),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A100 >------------------------*/,{
+		0,
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+	/* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
+}/*-------------------------< RESEL_TAG >------------------------*/,{
+	/*
+	 *  ACK the IDENTIFY previously received.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  It shall be a tagged command.
+	 *  Read SIMPLE+TAG.
+	 *  The C code will deal with errors.
+	 *  Agressive optimization, is'nt it? :)
+	 */
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		HADDR_1 (msgin),
+	/*
+	 *  Copy the LCB header to a fixed place in 
+	 *  the HCB using self-modifying SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a110),
+	SCR_COPY (sizeof(struct sym_lcbh)),
+}/*-------------------------< _SMS_A110 >------------------------*/,{
+		0,
+		HADDR_1 (lcb_head),
+	/*
+	 *  Load the pointer to the tagged task 
+	 *  table for this LUN.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (lcb_head.itlq_tbl_sa),
+		RADDR_1 (dsa),
+	/*
+	 *  The SIDL still contains the TAG value.
+	 *  Agressive optimization, isn't it? :):)
+	 */
+	SCR_REG_SFBR (sidl, SCR_SHL, 0),
+		0,
+#if SYM_CONF_MAX_TASK*4 > 512
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 2),
+		0,
+	SCR_REG_REG (sfbr, SCR_SHL, 0),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#elif SYM_CONF_MAX_TASK*4 > 256
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#endif
+	/*
+	 *  Retrieve the DSA of this task.
+	 *  JUMP indirectly to the restart point of the CCB.
+	 */
+	SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
+		0,
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a120),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A120 >------------------------*/,{
+		0,
+		RADDR_1 (dsa),
+}/*-------------------------< RESEL_GO >-------------------------*/,{
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a130),
+	/*
+	 *  Move 'ccb.phys.head.go' action to 
+	 *  scratch/scratch1. So scratch1 will 
+	 *  contain the 'restart' field of the 
+	 *  'go' structure.
+	 */
+	SCR_COPY (8),
+}/*-------------------------< _SMS_A130 >------------------------*/,{
+		0,
+		PADDR_B (scratch),
+	SCR_COPY (4),
+		PADDR_B (scratch1), /* phys.head.go.restart */
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+	/* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< RESEL_DSA >------------------------*/,{
+	/*
+	 *  ACK the IDENTIFY or TAG previously received.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+}/*-------------------------< RESEL_DSA1 >-----------------------*/,{
+	/*
+	 *  Copy the CCB header to a fixed location 
+	 *  in the HCB using self-modifying SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a140),
+	SCR_COPY (sizeof(struct sym_ccbh)),
+}/*-------------------------< _SMS_A140 >------------------------*/,{
+		0,
+		HADDR_1 (ccb_head),
+	/*
+	 *  Initialize the status register
+	 */
+	SCR_COPY (4),
+		HADDR_1 (ccb_head.status),
+		RADDR_1 (scr0),
+	/*
+	 *  Jump to dispatcher.
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< RESEL_NO_TAG >---------------------*/,{
+	/*
+	 *  Copy the LCB header to a fixed place in 
+	 *  the HCB using self-modifying SCRIPTS.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		PADDR_A (_sms_a145),
+	SCR_COPY (sizeof(struct sym_lcbh)),
+}/*-------------------------< _SMS_A145 >------------------------*/,{
+		0,
+		HADDR_1 (lcb_head),
+	/*
+	 *  Load the DSA with the unique ITL task.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (lcb_head.itl_task_sa),
+		RADDR_1 (dsa),
+	SCR_JUMP,
+		PADDR_A (resel_go),
+}/*-------------------------< DATA_IN >--------------------------*/,{
+/*
+ *  Because the size depends on the
+ *  #define SYM_CONF_MAX_SG parameter,
+ *  it is filled in at runtime.
+ *
+ *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ *  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ *  ||		offsetof (struct sym_dsb, data[ i]),
+ *  ##==========================================
+ */
+0
+}/*-------------------------< DATA_IN2 >-------------------------*/,{
+	SCR_CALL,
+		PADDR_A (datai_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< DATA_OUT >-------------------------*/,{
+/*
+ *  Because the size depends on the
+ *  #define SYM_CONF_MAX_SG parameter,
+ *  it is filled in at runtime.
+ *
+ *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ *  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ *  ||		offsetof (struct sym_dsb, data[ i]),
+ *  ##==========================================
+ */
+0
+}/*-------------------------< DATA_OUT2 >------------------------*/,{
+	SCR_CALL,
+		PADDR_A (datao_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< PM0_DATA >-------------------------*/,{
+	/*
+	 *  Read our host flags to SFBR, so we will be able 
+	 *  to check against the data direction we expect.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	 *  Check against actual DATA PHASE.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR_A (pm0_data_out),
+	/*
+	 *  Actual phase is DATA IN.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+		0,
+	/*
+	 *  Move the data to memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.pm0.sg),
+	SCR_JUMP,
+		PADDR_A (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >---------------------*/,{
+	/*
+	 *  Actual phase is DATA OUT.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+		0,
+	/*
+	 *  Move the data from memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+		offsetof (struct sym_ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >---------------------*/,{
+	/*
+	 *  Clear the flag that told we were moving  
+	 *  data from the PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
+		0,
+	/*
+	 *  Return to the previous DATA script which 
+	 *  is guaranteed by design (if no bug) to be 
+	 *  the main DATA script for this transfer.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		RADDR_1 (scratcha),
+	SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm0.ret)),
+		0,
+}/*-------------------------< PM_DATA_END >----------------------*/,{
+	SCR_COPY (4),
+		RADDR_1 (scratcha),
+		PADDR_A (_sms_a150),
+	SCR_COPY (4),
+}/*-------------------------< _SMS_A150 >------------------------*/,{
+		0,
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< PM1_DATA >-------------------------*/,{
+	/*
+	 *  Read our host flags to SFBR, so we will be able 
+	 *  to check against the data direction we expect.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	 *  Check against actual DATA PHASE.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR_A (pm1_data_out),
+	/*
+	 *  Actual phase is DATA IN.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+		0,
+	/*
+	 *  Move the data to memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.pm1.sg),
+	SCR_JUMP,
+		PADDR_A (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >---------------------*/,{
+	/*
+	 *  Actual phase is DATA OUT.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+		0,
+	/*
+	 *  Move the data from memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+		offsetof (struct sym_ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >---------------------*/,{
+	/*
+	 *  Clear the flag that told we were moving  
+	 *  data from the PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
+		0,
+	/*
+	 *  Return to the previous DATA script which 
+	 *  is guaranteed by design (if no bug) to be 
+	 *  the main DATA script for this transfer.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (dsa),
+		RADDR_1 (scratcha),
+	SCR_REG_REG (scratcha, SCR_ADD, offsetof (struct sym_ccb,phys.pm1.ret)),
+		0,
+	SCR_JUMP,
+		PADDR_A (pm_data_end),
+}/*--------------------------<>----------------------------------*/
+};
+
+static struct SYM_FWB_SCR SYM_FWB_SCR = {
+/*-------------------------< NO_DATA >--------------------------*/ {
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{
+	/*
+	 *  We are jumped here by the C code, if we have 
+	 *  some target to reset or some disconnected 
+	 *  job to abort. Since error recovery is a serious 
+	 *  busyness, we will really reset the SCSI BUS, if 
+	 *  case of a SCSI interrupt occurring in this path.
+	 */
+
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	/*
+	 *  Set initiator mode.
+	 */
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *      And try to select this target.
+	 */
+	SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
+		PADDR_A (reselect),
+	/*
+	 *  Wait for the selection to complete or 
+	 *  the selection to time out.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		-8,
+	/*
+	 *  Call the C code.
+	 */
+	SCR_INT,
+		SIR_TARGET_SELECTED,
+	/*
+	 *  The C code should let us continue here. 
+	 *  Send the 'kiss of death' message.
+	 *  We expect an immediate disconnect once 
+	 *  the target has eaten the message.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct sym_hcb, abrt_tbl),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	 *  Tell the C code that we are done.
+	 */
+	SCR_INT,
+		SIR_ABORT_SENT,
+}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{
+	/*
+	 *  Jump at scheduler.
+	 */
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< MSG_IN_ETC >-----------------------*/,{
+	/*
+	 *  If it is an EXTENDED (variable size message)
+	 *  Handle it.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDR_B (msg_extended),
+	/*
+	 *  Let the C code handle any other 
+	 *  1 byte message.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+		PADDR_B (msg_received),
+	SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+		PADDR_B (msg_received),
+	/*
+	 *  We donnot handle 2 bytes messages from SCRIPTS.
+	 *  So, let the C code deal with these ones too.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+		PADDR_B (msg_weird_seen),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+}/*-------------------------< MSG_RECEIVED >---------------------*/,{
+	SCR_COPY (4),			/* DUMMY READ */
+		HADDR_1 (scratch),
+		RADDR_1 (scratcha),
+	SCR_INT,
+		SIR_MSG_RECEIVED,
+}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{
+	SCR_COPY (4),			/* DUMMY READ */
+		HADDR_1 (scratch),
+		RADDR_1 (scratcha),
+	SCR_INT,
+		SIR_MSG_WEIRD,
+}/*-------------------------< MSG_EXTENDED >---------------------*/,{
+	/*
+	 *  Clear ACK and get the next byte 
+	 *  assumed to be the message length.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+	/*
+	 *  Try to catch some unlikely situations as 0 length 
+	 *  or too large the length.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (0)),
+		PADDR_B (msg_weird_seen),
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+		0,
+	SCR_JUMP ^ IFTRUE (CARRYSET),
+		PADDR_B (msg_weird_seen),
+	/*
+	 *  We donnot handle extended messages from SCRIPTS.
+	 *  Read the amount of data correponding to the 
+	 *  message length and call the C code.
+	 */
+	SCR_COPY (1),
+		RADDR_1 (scratcha),
+		PADDR_B (_sms_b10),
+	SCR_CLR (SCR_ACK),
+		0,
+}/*-------------------------< _SMS_B10 >-------------------------*/,{
+	SCR_MOVE_ABS (0) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[2]),
+	SCR_JUMP,
+		PADDR_B (msg_received),
+}/*-------------------------< MSG_BAD >--------------------------*/,{
+	/*
+	 *  unimplemented message - reject it.
+	 */
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (clrack),
+}/*-------------------------< MSG_WEIRD >------------------------*/,{
+	/*
+	 *  weird message received
+	 *  ignore all MSG IN phases and reject it.
+	 */
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
+}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (scratch),
+	SCR_JUMP,
+		PADDR_B (msg_weird1),
+}/*-------------------------< WDTR_RESP >------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_WDTR >------------------------*/,{
+	/*
+	 *  Send the M_X_WIDE_REQ
+	 */
+	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< SDTR_RESP >------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_SDTR >------------------------*/,{
+	/*
+	 *  Send the M_X_SYNC_REQ
+	 */
+	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< PPR_RESP >-------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_PPR >-------------------------*/,{
+	/*
+	 *  Send the M_X_PPR_REQ
+	 */
+	SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{
+	SCR_INT,
+		SIR_NEGO_PROTO,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< MSG_OUT >--------------------------*/,{
+	/*
+	 *  The target requests a message.
+	 *  We donnot send messages that may 
+	 *  require the device to go to bus free.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	/*
+	 *  ... wait for the next phase
+	 *  if it's a message out, send it again, ...
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (msg_out),
+}/*-------------------------< MSG_OUT_DONE >---------------------*/,{
+	/*
+	 *  Let the C code be aware of the 
+	 *  sent message and clear the message.
+	 */
+	SCR_INT,
+		SIR_MSG_OUT_DONE,
+	/*
+	 *  ... and process the next phase
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
+	/*
+	 *  Zero scratcha that will count the 
+	 *  extras bytes.
+	 */
+	SCR_COPY (4),
+		PADDR_B (zero),
+		RADDR_1 (scratcha),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
+	/*
+	 *  The target may want to transfer too much data.
+	 *
+	 *  If phase is DATA OUT write 1 byte and count it.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+		16,
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
+		HADDR_1 (scratch),
+	SCR_JUMP,
+		PADDR_B (data_ovrun2),
+	/*
+	 *  If WSR is set, clear this condition, and 
+	 *  count this byte.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+		16,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	SCR_JUMP,
+		PADDR_B (data_ovrun2),
+	/*
+	 *  Finally check against DATA IN phase.
+	 *  Signal data overrun to the C code 
+	 *  and jump to dispatcher if not so.
+	 *  Read 1 byte otherwise and count it.
+	 */
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		16,
+	SCR_INT,
+		SIR_DATA_OVERRUN,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+		HADDR_1 (scratch),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
+	/*
+	 *  Count this byte.
+	 *  This will allow to return a negative 
+	 *  residual to user.
+	 */
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	/*
+	 *  .. and repeat as required.
+	 */
+	SCR_JUMP,
+		PADDR_B (data_ovrun1),
+}/*-------------------------< ABORT_RESEL >----------------------*/,{
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  send the abort/abortag/reset message
+	 *  we expect an immediate disconnect
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	SCR_INT,
+		SIR_RESEL_ABORTED,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< RESEND_IDENT >---------------------*/,{
+	/*
+	 *  The target stays in MSG OUT phase after having acked 
+	 *  Identify [+ Tag [+ Extended message ]]. Targets shall
+	 *  behave this way on parity error.
+	 *  We must send it again all the messages.
+	 */
+	SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the  */
+		0,         /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
+	SCR_JUMP,
+		PADDR_A (send_ident),
+}/*-------------------------< IDENT_BREAK >----------------------*/,{
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (select2),
+}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (select2),
+}/*-------------------------< SDATA_IN >-------------------------*/,{
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_dsb, sense),
+	SCR_CALL,
+		PADDR_A (datai_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{
+	/*
+	 *  Message is an IDENTIFY, but lun is unknown.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORT to clear all pending tasks.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_LUN,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L >------------------------*/,{
+	/*
+	 *  We donnot have a task for that I_T_L.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORT message.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{
+	/*
+	 *  We donnot have a task that matches the tag.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORTTAG message.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L_Q,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_STATUS >-----------------------*/,{
+	/*
+	 *  Anything different from INTERMEDIATE 
+	 *  CONDITION MET should be a bad SCSI status, 
+	 *  given that GOOD status has already been tested.
+	 *  Call the C code.
+	 */
+	SCR_COPY (4),
+		PADDR_B (startpos),
+		RADDR_1 (scratcha),
+	SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
+		SIR_BAD_SCSI_STATUS,
+	SCR_RETURN,
+		0,
+}/*-------------------------< WSR_MA_HELPER >--------------------*/,{
+	/*
+	 *  Helper for the C code when WSR bit is set.
+	 *  Perform the move of the residual byte.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.wresid),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+}/*-------------------------< DATA_IO >--------------------------*/,{
+	/*
+	 *  We jump here if the data direction was unknown at the 
+	 *  time we had to queue the command to the scripts processor.
+	 *  Pointers had been set as follow in this situation:
+	 *    savep   -->   DATA_IO
+	 *    lastp   -->   start pointer when DATA_IN
+	 *    wlastp  -->   start pointer when DATA_OUT
+	 *  This script sets savep and lastp according to the 
+	 *  direction chosen by the target.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		PADDR_B (data_io_out),
+}/*-------------------------< DATA_IO_COM >----------------------*/,{
+	/*
+	 *  Direction is DATA IN.
+	 */
+	SCR_COPY  (4),
+		HADDR_1 (ccb_head.lastp),
+		HADDR_1 (ccb_head.savep),
+	/*
+	 *  Jump to the SCRIPTS according to actual direction.
+	 */
+	SCR_COPY  (4),
+		HADDR_1 (ccb_head.savep),
+		RADDR_1 (temp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< DATA_IO_OUT >----------------------*/,{
+	/*
+	 *  Direction is DATA OUT.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)),
+		0,
+	SCR_COPY  (4),
+		HADDR_1 (ccb_head.wlastp),
+		HADDR_1 (ccb_head.lastp),
+	SCR_JUMP,
+		PADDR_B(data_io_com),
+#endif /* SYM_OPT_HANDLE_DIR_UNKNOWN */
+
+}/*-------------------------< ZERO >-----------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >--------------------------*/,{
+	SCR_DATA_ZERO, /* MUST BE BEFORE SCRATCH1 */
+}/*-------------------------< SCRATCH1 >-------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PREV_DONE >------------------------*/,{
+	SCR_DATA_ZERO, /* MUST BE BEFORE DONE_POS ! */
+}/*-------------------------< DONE_POS >-------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< NEXTJOB >--------------------------*/,{
+	SCR_DATA_ZERO, /* MUST BE BEFORE STARTPOS ! */
+}/*-------------------------< STARTPOS >-------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >--------------------------*/,{
+	SCR_DATA_ZERO,
+}/*--------------------------<>----------------------------------*/
+};
+
+static struct SYM_FWZ_SCR SYM_FWZ_SCR = {
+ /*-------------------------< SNOOPTEST >------------------------*/{
+	/*
+	 *  Read the variable.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (scratch),
+		RADDR_1 (scratcha),
+	/*
+	 *  Write the variable.
+	 */
+	SCR_COPY (4),
+		RADDR_1 (temp),
+		HADDR_1 (scratch),
+	/*
+	 *  Read back the variable.
+	 */
+	SCR_COPY (4),
+		HADDR_1 (scratch),
+		RADDR_1 (temp),
+}/*-------------------------< SNOOPEND >-------------------------*/,{
+	/*
+	 *  And stop.
+	 */
+	SCR_INT,
+		99,
+}/*--------------------------<>----------------------------------*/
+};
diff --git a/drivers/scsi/sym53c8xx_2/sym_fw2.h b/drivers/scsi/sym53c8xx_2/sym_fw2.h
new file mode 100644
index 0000000..7ea7151
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_fw2.h
@@ -0,0 +1,1927 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/*
+ *  Scripts for SYMBIOS-Processor
+ *
+ *  We have to know the offsets of all labels before we reach 
+ *  them (for forward jumps). Therefore we declare a struct 
+ *  here. If you make changes inside the script,
+ *
+ *  DONT FORGET TO CHANGE THE LENGTHS HERE!
+ */
+
+/*
+ *  Script fragments which are loaded into the on-chip RAM 
+ *  of 825A, 875, 876, 895, 895A, 896 and 1010 chips.
+ *  Must not exceed 4K bytes.
+ */
+struct SYM_FWA_SCR {
+	u32 start		[ 14];
+	u32 getjob_begin	[  4];
+	u32 getjob_end		[  4];
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 select		[  6];
+#else
+	u32 select		[  4];
+#endif
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+	u32 is_dmap_dirty	[  4];
+#endif
+	u32 wf_sel_done		[  2];
+	u32 sel_done		[  2];
+	u32 send_ident		[  2];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 select2		[  8];
+#else
+	u32 select2		[  2];
+#endif
+	u32 command		[  2];
+	u32 dispatch		[ 28];
+	u32 sel_no_cmd		[ 10];
+	u32 init		[  6];
+	u32 clrack		[  4];
+	u32 datai_done		[ 10];
+	u32 datai_done_wsr	[ 20];
+	u32 datao_done		[ 10];
+	u32 datao_done_wss	[  6];
+	u32 datai_phase		[  4];
+	u32 datao_phase		[  6];
+	u32 msg_in		[  2];
+	u32 msg_in2		[ 10];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 status		[ 14];
+#else
+	u32 status		[ 10];
+#endif
+	u32 complete		[  6];
+	u32 complete2		[ 12];
+	u32 done		[ 14];
+	u32 done_end		[  2];
+	u32 complete_error	[  4];
+	u32 save_dp		[ 12];
+	u32 restore_dp		[  8];
+	u32 disconnect		[ 12];
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 idle		[  4];
+#else
+	u32 idle		[  2];
+#endif
+#ifdef SYM_CONF_IARB_SUPPORT
+	u32 ungetjob		[  6];
+#else
+	u32 ungetjob		[  4];
+#endif
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 reselect		[  4];
+#else
+	u32 reselect		[  2];
+#endif
+	u32 reselected		[ 22];
+	u32 resel_scntl4	[ 20];
+	u32 resel_lun0		[  6];
+#if   SYM_CONF_MAX_TASK*4 > 512
+	u32 resel_tag		[ 26];
+#elif SYM_CONF_MAX_TASK*4 > 256
+	u32 resel_tag		[ 20];
+#else
+	u32 resel_tag		[ 16];
+#endif
+	u32 resel_dsa		[  2];
+	u32 resel_dsa1		[  4];
+	u32 resel_no_tag	[  6];
+	u32 data_in		[SYM_CONF_MAX_SG * 2];
+	u32 data_in2		[  4];
+	u32 data_out		[SYM_CONF_MAX_SG * 2];
+	u32 data_out2		[  4];
+	u32 pm0_data		[ 12];
+	u32 pm0_data_out	[  6];
+	u32 pm0_data_end	[  6];
+	u32 pm1_data		[ 12];
+	u32 pm1_data_out	[  6];
+	u32 pm1_data_end	[  6];
+};
+
+/*
+ *  Script fragments which stay in main memory for all chips 
+ *  except for chips that support 8K on-chip RAM.
+ */
+struct SYM_FWB_SCR {
+	u32 start64		[  2];
+	u32 no_data		[  2];
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	u32 sel_for_abort	[ 18];
+#else
+	u32 sel_for_abort	[ 16];
+#endif
+	u32 sel_for_abort_1	[  2];
+	u32 msg_in_etc		[ 12];
+	u32 msg_received	[  4];
+	u32 msg_weird_seen	[  4];
+	u32 msg_extended	[ 20];
+	u32 msg_bad		[  6];
+	u32 msg_weird		[  4];
+	u32 msg_weird1		[  8];
+
+	u32 wdtr_resp		[  6];
+	u32 send_wdtr		[  4];
+	u32 sdtr_resp		[  6];
+	u32 send_sdtr		[  4];
+	u32 ppr_resp		[  6];
+	u32 send_ppr		[  4];
+	u32 nego_bad_phase	[  4];
+	u32 msg_out		[  4];
+	u32 msg_out_done	[  4];
+	u32 data_ovrun		[  2];
+	u32 data_ovrun1		[ 22];
+	u32 data_ovrun2		[  8];
+	u32 abort_resel		[ 16];
+	u32 resend_ident	[  4];
+	u32 ident_break		[  4];
+	u32 ident_break_atn	[  4];
+	u32 sdata_in		[  6];
+	u32 resel_bad_lun	[  4];
+	u32 bad_i_t_l		[  4];
+	u32 bad_i_t_l_q		[  4];
+	u32 bad_status		[  6];
+	u32 pm_handle		[ 20];
+	u32 pm_handle1		[  4];
+	u32 pm_save		[  4];
+	u32 pm0_save		[ 12];
+	u32 pm_save_end		[  4];
+	u32 pm1_save		[ 14];
+
+	/* WSR handling */
+	u32 pm_wsr_handle	[ 38];
+	u32 wsr_ma_helper	[  4];
+
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+	/* Unknown direction handling */
+	u32 data_io		[  2];
+	u32 data_io_in		[  2];
+	u32 data_io_com		[  6];
+	u32 data_io_out		[  8];
+#endif
+	/* Data area */
+	u32 zero		[  1];
+	u32 scratch		[  1];
+	u32 pm0_data_addr	[  1];
+	u32 pm1_data_addr	[  1];
+	u32 done_pos		[  1];
+	u32 startpos		[  1];
+	u32 targtbl		[  1];
+};
+
+/*
+ *  Script fragments used at initialisations.
+ *  Only runs out of main memory.
+ */
+struct SYM_FWZ_SCR {
+	u32 snooptest		[  6];
+	u32 snoopend		[  2];
+};
+
+static struct SYM_FWA_SCR SYM_FWA_SCR = {
+/*--------------------------< START >----------------------------*/ {
+	/*
+	 *  Switch the LED on.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+		0,
+	/*
+	 *      Clear SIGP.
+	 */
+	SCR_FROM_REG (ctest2),
+		0,
+	/*
+	 *  Stop here if the C code wants to perform 
+	 *  some error recovery procedure manually.
+	 *  (Indicate this by setting SEM in ISTAT)
+	 */
+	SCR_FROM_REG (istat),
+		0,
+	/*
+	 *  Report to the C code the next position in 
+	 *  the start queue the SCRIPTS will schedule.
+	 *  The C code must not change SCRATCHA.
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (startpos),
+	SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
+		SIR_SCRIPT_STOPPED,
+	/*
+	 *  Start the next job.
+	 *
+	 *  @DSA     = start point for this job.
+	 *  SCRATCHA = address of this job in the start queue.
+	 *
+	 *  We will restore startpos with SCRATCHA if we fails the 
+	 *  arbitration or if it is the idle job.
+	 *
+	 *  The below GETJOB_BEGIN to GETJOB_END section of SCRIPTS 
+	 *  is a critical path. If it is partially executed, it then 
+	 *  may happen that the job address is not yet in the DSA 
+	 *  and the next queue position points to the next JOB.
+	 */
+	SCR_LOAD_ABS (dsa, 4),
+		PADDR_B (startpos),
+	SCR_LOAD_REL (temp, 4),
+		4,
+}/*-------------------------< GETJOB_BEGIN >---------------------*/,{
+	SCR_STORE_ABS (temp, 4),
+		PADDR_B (startpos),
+	SCR_LOAD_REL (dsa, 4),
+		0,
+}/*-------------------------< GETJOB_END >-----------------------*/,{
+	SCR_LOAD_REL (temp, 4),
+		0,
+	SCR_RETURN,
+		0,
+}/*-------------------------< SELECT >---------------------------*/,{
+	/*
+	 *  DSA	contains the address of a scheduled
+	 *  	data structure.
+	 *
+	 *  SCRATCHA contains the address of the start queue  
+	 *  	entry which points to the next job.
+	 *
+	 *  Set Initiator mode.
+	 *
+	 *  (Target mode is left as an exercise for the reader)
+	 */
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *      And try to select this target.
+	 */
+	SCR_SEL_TBL_ATN ^ offsetof (struct sym_dsb, select),
+		PADDR_A (ungetjob),
+	/*
+	 *  Now there are 4 possibilities:
+	 *
+	 *  (1) The chip loses arbitration.
+	 *  This is ok, because it will try again,
+	 *  when the bus becomes idle.
+	 *  (But beware of the timeout function!)
+	 *
+	 *  (2) The chip is reselected.
+	 *  Then the script processor takes the jump
+	 *  to the RESELECT label.
+	 *
+	 *  (3) The chip wins arbitration.
+	 *  Then it will execute SCRIPTS instruction until 
+	 *  the next instruction that checks SCSI phase.
+	 *  Then will stop and wait for selection to be 
+	 *  complete or selection time-out to occur.
+	 *
+	 *  After having won arbitration, the SCRIPTS  
+	 *  processor is able to execute instructions while 
+	 *  the SCSI core is performing SCSI selection.
+	 */
+	/*
+	 *      Initialize the status registers
+	 */
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct sym_ccb, phys.head.status),
+	/*
+	 *  We may need help from CPU if the DMA segment 
+	 *  registers aren't up-to-date for this IO.
+	 *  Patched with NOOP for chips that donnot 
+	 *  support DAC addressing.
+	 */
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+}/*-------------------------< IS_DMAP_DIRTY >--------------------*/,{
+	SCR_FROM_REG (HX_REG),
+		0,
+	SCR_INT ^ IFTRUE (MASK (HX_DMAP_DIRTY, HX_DMAP_DIRTY)),
+		SIR_DMAP_DIRTY,
+#endif
+}/*-------------------------< WF_SEL_DONE >----------------------*/,{
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		SIR_SEL_ATN_NO_MSG_OUT,
+}/*-------------------------< SEL_DONE >-------------------------*/,{
+	/*
+	 *  C1010-33 errata work-around.
+	 *  Due to a race, the SCSI core may not have 
+	 *  loaded SCNTL3 on SEL_TBL instruction.
+	 *  We reload it once phase is stable.
+	 *  Patched with a NOOP for other chips.
+	 */
+	SCR_LOAD_REL (scntl3, 1),
+		offsetof(struct sym_dsb, select.sel_scntl3),
+}/*-------------------------< SEND_IDENT >-----------------------*/,{
+	/*
+	 *  Selection complete.
+	 *  Send the IDENTIFY and possibly the TAG message 
+	 *  and negotiation message if present.
+	 */
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct sym_dsb, smsg),
+}/*-------------------------< SELECT2 >--------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  Set IMMEDIATE ARBITRATION if we have been given 
+	 *  a hint to do so. (Some job to do after this one).
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+		8,
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	 *  Anticipate the COMMAND phase.
+	 *  This is the PHASE we expect at this point.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)),
+		PADDR_A (sel_no_cmd),
+}/*-------------------------< COMMAND >--------------------------*/,{
+	/*
+	 *  ... and send the command
+	 */
+	SCR_MOVE_TBL ^ SCR_COMMAND,
+		offsetof (struct sym_dsb, cmd),
+}/*-------------------------< DISPATCH >-------------------------*/,{
+	/*
+	 *  MSG_IN is the only phase that shall be 
+	 *  entered at least once for each (re)selection.
+	 *  So we test it first.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_OUT)),
+		PADDR_A (datao_phase),
+	SCR_JUMP ^ IFTRUE (IF (SCR_DATA_IN)),
+		PADDR_A (datai_phase),
+	SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)),
+		PADDR_A (command),
+	SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
+		PADDR_B (msg_out),
+	/*
+	 *  Discard as many illegal phases as 
+	 *  required and tell the C code about.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_OUT)),
+		16,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
+		HADDR_1 (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_OUT)),
+		-16,
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_ILG_IN)),
+		16,
+	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
+		HADDR_1 (scratch),
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_ILG_IN)),
+		-16,
+	SCR_INT,
+		SIR_BAD_PHASE,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< SEL_NO_CMD >-----------------------*/,{
+	/*
+	 *  The target does not switch to command 
+	 *  phase after IDENTIFY has been sent.
+	 *
+	 *  If it stays in MSG OUT phase send it 
+	 *  the IDENTIFY again.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (resend_ident),
+	/*
+	 *  If target does not switch to MSG IN phase 
+	 *  and we sent a negotiation, assert the 
+	 *  failure immediately.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	SCR_FROM_REG (HS_REG),
+		0,
+	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
+		SIR_NEGO_FAILED,
+	/*
+	 *  Jump to dispatcher.
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< INIT >-----------------------------*/,{
+	/*
+	 *  Wait for the SCSI RESET signal to be 
+	 *  inactive before restarting operations, 
+	 *  since the chip may hang on SEL_ATN 
+	 *  if SCSI RESET is active.
+	 */
+	SCR_FROM_REG (sstat0),
+		0,
+	SCR_JUMPR ^ IFTRUE (MASK (IRST, IRST)),
+		-16,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< CLRACK >---------------------------*/,{
+	/*
+	 *  Terminate possible pending message phase.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE >-----------------------*/,{
+	/*
+	 *  Save current pointer to LASTP.
+	 */
+	SCR_STORE_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	/*
+	 *  If the SWIDE is not full, jump to dispatcher.
+	 *  We anticipate a STATUS phase.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (WSR, WSR)),
+		PADDR_A (datai_done_wsr),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_DONE_WSR >-------------------*/,{
+	/*
+	 *  The SWIDE is full.
+	 *  Clear this condition.
+	 */
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+	 *  We are expecting an IGNORE RESIDUE message 
+	 *  from the device, otherwise we are in data 
+	 *  overrun condition. Check against MSG_IN phase.
+	 */
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	/*
+	 *  We are in MSG_IN phase,
+	 *  Read the first byte of the message.
+	 *  If it is not an IGNORE RESIDUE message,
+	 *  signal overrun and jump to message 
+	 *  processing.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[0]),
+	SCR_INT ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR_A (msg_in2),
+	/*
+	 *  We got the message we expected.
+	 *  Read the 2nd byte, and jump to dispatcher.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAO_DONE >-----------------------*/,{
+	/*
+	 *  Save current pointer to LASTP.
+	 */
+	SCR_STORE_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	/*
+	 *  If the SODL is not full jump to dispatcher.
+	 *  We anticipate a STATUS phase.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMP ^ IFTRUE (MASK (WSS, WSS)),
+		PADDR_A (datao_done_wss),
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR_A (status),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAO_DONE_WSS >-------------------*/,{
+	/*
+	 *  The SODL is full, clear this condition.
+	 */
+	SCR_REG_REG (scntl2, SCR_OR, WSS),
+		0,
+	/*
+	 *  And signal a DATA UNDERRUN condition 
+	 *  to the C code.
+	 */
+	SCR_INT,
+		SIR_SODL_UNDERRUN,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATAI_PHASE >----------------------*/,{
+	/*
+	 *  Jump to current pointer.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< DATAO_PHASE >----------------------*/,{
+	/*
+	 *  C1010-66 errata work-around.
+	 *  Extra clocks of data hold must be inserted 
+	 *  in DATA OUT phase on 33 MHz PCI BUS.
+	 *  Patched with a NOOP for other chips.
+	 */
+	SCR_REG_REG (scntl4, SCR_OR, (XCLKH_DT|XCLKH_ST)),
+		0,
+	/*
+	 *  Jump to current pointer.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	SCR_RETURN,
+		0,
+}/*-------------------------< MSG_IN >---------------------------*/,{
+	/*
+	 *  Get the first byte of the message.
+	 *
+	 *  The script processor doesn't negate the
+	 *  ACK signal after this transfer.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[0]),
+}/*-------------------------< MSG_IN2 >--------------------------*/,{
+	/*
+	 *  Check first against 1 byte messages 
+	 *  that we handle from SCRIPTS.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
+		PADDR_A (complete),
+	SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)),
+		PADDR_A (disconnect),
+	SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)),
+		PADDR_A (save_dp),
+	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
+		PADDR_A (restore_dp),
+	/*
+	 *  We handle all other messages from the 
+	 *  C code, so no need to waste on-chip RAM 
+	 *  for those ones.
+	 */
+	SCR_JUMP,
+		PADDR_B (msg_in_etc),
+}/*-------------------------< STATUS >---------------------------*/,{
+	/*
+	 *  get the status
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		HADDR_1 (scratch),
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, 
+	 *  since we may have to tamper the start queue from 
+	 *  the C code.
+	 */
+	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+		8,
+	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+		0,
+#endif
+	/*
+	 *  save status to scsi_status.
+	 *  mark as complete.
+	 */
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+		0,
+	/*
+	 *  Anticipate the MESSAGE PHASE for 
+	 *  the TASK COMPLETE message.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< COMPLETE >-------------------------*/,{
+	/*
+	 *  Complete message.
+	 *
+	 *  When we terminate the cycle by clearing ACK,
+	 *  the target may disconnect immediately.
+	 *
+	 *  We don't want to be told of an "unexpected disconnect",
+	 *  so we disable this feature.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	/*
+	 *  Terminate cycle ...
+	 */
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	 *  ... and wait for the disconnect.
+	 */
+	SCR_WAIT_DISC,
+		0,
+}/*-------------------------< COMPLETE2 >------------------------*/,{
+	/*
+	 *  Save host status.
+	 */
+	SCR_STORE_REL (scr0, 4),
+		offsetof (struct sym_ccb, phys.head.status),
+	/*
+	 *  Some bridges may reorder DMA writes to memory.
+	 *  We donnot want the CPU to deal with completions  
+	 *  without all the posted write having been flushed 
+	 *  to memory. This DUMMY READ should flush posted 
+	 *  buffers prior to the CPU having to deal with 
+	 *  completions.
+	 */
+	SCR_LOAD_REL (scr0, 4),	/* DUMMY READ */
+		offsetof (struct sym_ccb, phys.head.status),
+
+	/*
+	 *  If command resulted in not GOOD status,
+	 *  call the C code if needed.
+	 */
+	SCR_FROM_REG (SS_REG),
+		0,
+	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
+		PADDR_B (bad_status),
+	/*
+	 *  If we performed an auto-sense, call 
+	 *  the C code to synchronyze task aborts 
+	 *  with UNIT ATTENTION conditions.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (0 ,(HF_SENSE|HF_EXT_ERR))),
+		PADDR_A (complete_error),
+}/*-------------------------< DONE >-----------------------------*/,{
+	/*
+	 *  Copy the DSA to the DONE QUEUE and 
+	 *  signal completion to the host.
+	 *  If we are interrupted between DONE 
+	 *  and DONE_END, we must reset, otherwise 
+	 *  the completed CCB may be lost.
+	 */
+	SCR_STORE_ABS (dsa, 4),
+		PADDR_B (scratch),
+	SCR_LOAD_ABS (dsa, 4),
+		PADDR_B (done_pos),
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (scratch),
+	SCR_STORE_REL (scratcha, 4),
+		0,
+	/*
+	 *  The instruction below reads the DONE QUEUE next 
+	 *  free position from memory.
+	 *  In addition it ensures that all PCI posted writes  
+	 *  are flushed and so the DSA value of the done 
+	 *  CCB is visible by the CPU before INTFLY is raised.
+	 */
+	SCR_LOAD_REL (scratcha, 4),
+		4,
+	SCR_INT_FLY,
+		0,
+	SCR_STORE_ABS (scratcha, 4),
+		PADDR_B (done_pos),
+}/*-------------------------< DONE_END >-------------------------*/,{
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< COMPLETE_ERROR >-------------------*/,{
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (startpos),
+	SCR_INT,
+		SIR_COMPLETE_ERROR,
+}/*-------------------------< SAVE_DP >--------------------------*/,{
+	/*
+	 *  Clear ACK immediately.
+	 *  No need to delay it.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  Keep track we received a SAVE DP, so 
+	 *  we will switch to the other PM context 
+	 *  on the next PM since the DP may point 
+	 *  to the current PM context.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_DP_SAVED),
+		0,
+	/*
+	 *  SAVE_DP message:
+	 *  Copy LASTP to SAVEP.
+	 */
+	SCR_LOAD_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.savep),
+	/*
+	 *  Anticipate the MESSAGE PHASE for 
+	 *  the DISCONNECT message.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR_A (msg_in),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< RESTORE_DP >-----------------------*/,{
+	/*
+	 *  Clear ACK immediately.
+	 *  No need to delay it.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  Copy SAVEP to LASTP.
+	 */
+	SCR_LOAD_REL  (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.savep),
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DISCONNECT >-----------------------*/,{
+	/*
+	 *  DISCONNECTing  ...
+	 *
+	 *  disable the "unexpected disconnect" feature,
+	 *  and remove the ACK signal.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	/*
+	 *  Wait for the disconnect.
+	 */
+	SCR_WAIT_DISC,
+		0,
+	/*
+	 *  Status is: DISCONNECTED.
+	 */
+	SCR_LOAD_REG (HS_REG, HS_DISCONNECT),
+		0,
+	/*
+	 *  Save host status.
+	 */
+	SCR_STORE_REL (scr0, 4),
+		offsetof (struct sym_ccb, phys.head.status),
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< IDLE >-----------------------------*/,{
+	/*
+	 *  Nothing to do?
+	 *  Switch the LED off and wait for reselect.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_OR, 0x01),
+		0,
+#ifdef SYM_CONF_IARB_SUPPORT
+	SCR_JUMPR,
+		8,
+#endif
+}/*-------------------------< UNGETJOB >-------------------------*/,{
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  Set IMMEDIATE ARBITRATION, for the next time.
+	 *  This will give us better chance to win arbitration 
+	 *  for the job we just wanted to do.
+	 */
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
+	/*
+	 *  We are not able to restart the SCRIPTS if we are 
+	 *  interrupted and these instruction haven't been 
+	 *  all executed. BTW, this is very unlikely to 
+	 *  happen, but we check that from the C code.
+	 */
+	SCR_LOAD_REG (dsa, 0xff),
+		0,
+	SCR_STORE_ABS (scratcha, 4),
+		PADDR_B (startpos),
+}/*-------------------------< RESELECT >-------------------------*/,{
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	/*
+	 *  Make sure we are in initiator mode.
+	 */
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *  Sleep waiting for a reselection.
+	 */
+	SCR_WAIT_RESEL,
+		PADDR_A(start),
+}/*-------------------------< RESELECTED >-----------------------*/,{
+	/*
+	 *  Switch the LED on.
+	 *  Will be patched with a NO_OP if LED
+	 *  not needed or not desired.
+	 */
+	SCR_REG_REG (gpreg, SCR_AND, 0xfe),
+		0,
+	/*
+	 *  load the target id into the sdid
+	 */
+	SCR_REG_SFBR (ssid, SCR_AND, 0x8F),
+		0,
+	SCR_TO_REG (sdid),
+		0,
+	/*
+	 *  Load the target control block address
+	 */
+	SCR_LOAD_ABS (dsa, 4),
+		PADDR_B (targtbl),
+	SCR_SFBR_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_AND, 0x3c),
+		0,
+	SCR_LOAD_REL (dsa, 4),
+		0,
+	/*
+	 *  We expect MESSAGE IN phase.
+	 *  If not, get help from the C code.
+	 */
+	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		SIR_RESEL_NO_MSG_IN,
+	/*
+	 *  Load the legacy synchronous transfer registers.
+	 */
+	SCR_LOAD_REL (scntl3, 1),
+		offsetof(struct sym_tcb, head.wval),
+	SCR_LOAD_REL (sxfer, 1),
+		offsetof(struct sym_tcb, head.sval),
+}/*-------------------------< RESEL_SCNTL4 >---------------------*/,{
+	/*
+	 *  The C1010 uses a new synchronous timing scheme.
+	 *  Will be patched with a NO_OP if not a C1010.
+	 */
+	SCR_LOAD_REL (scntl4, 1),
+		offsetof(struct sym_tcb, head.uval),
+	/*
+	 *  Get the IDENTIFY message.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin),
+	/*
+	 *  If IDENTIFY LUN #0, use a faster path 
+	 *  to find the LCB structure.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0x80, 0xbf)),
+		PADDR_A (resel_lun0),
+	/*
+	 *  If message isn't an IDENTIFY, 
+	 *  tell the C code about.
+	 */
+	SCR_INT ^ IFFALSE (MASK (0x80, 0x80)),
+		SIR_RESEL_NO_IDENTIFY,
+	/*
+	 *  It is an IDENTIFY message,
+	 *  Load the LUN control block address.
+	 */
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct sym_tcb, head.luntbl_sa),
+	SCR_SFBR_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_SHL, 0),
+		0,
+	SCR_REG_REG (dsa, SCR_AND, 0xfc),
+		0,
+	SCR_LOAD_REL (dsa, 4),
+		0,
+	SCR_JUMPR,
+		8,
+}/*-------------------------< RESEL_LUN0 >-----------------------*/,{
+	/*
+	 *  LUN 0 special case (but usual one :))
+	 */
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct sym_tcb, head.lun0_sa),
+	/*
+	 *  Jump indirectly to the reselect action for this LUN.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof(struct sym_lcb, head.resel_sa),
+	SCR_RETURN,
+		0,
+	/* In normal situations, we jump to RESEL_TAG or RESEL_NO_TAG */
+}/*-------------------------< RESEL_TAG >------------------------*/,{
+	/*
+	 *  ACK the IDENTIFY previously received.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  It shall be a tagged command.
+	 *  Read SIMPLE+TAG.
+	 *  The C code will deal with errors.
+	 *  Agressive optimization, is'nt it? :)
+	 */
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		HADDR_1 (msgin),
+	/*
+	 *  Load the pointer to the tagged task 
+	 *  table for this LUN.
+	 */
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct sym_lcb, head.itlq_tbl_sa),
+	/*
+	 *  The SIDL still contains the TAG value.
+	 *  Agressive optimization, isn't it? :):)
+	 */
+	SCR_REG_SFBR (sidl, SCR_SHL, 0),
+		0,
+#if SYM_CONF_MAX_TASK*4 > 512
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 2),
+		0,
+	SCR_REG_REG (sfbr, SCR_SHL, 0),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#elif SYM_CONF_MAX_TASK*4 > 256
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#endif
+	/*
+	 *  Retrieve the DSA of this task.
+	 *  JUMP indirectly to the restart point of the CCB.
+	 */
+	SCR_SFBR_REG (dsa, SCR_AND, 0xfc),
+		0,
+	SCR_LOAD_REL (dsa, 4),
+		0,
+	SCR_LOAD_REL (temp, 4),
+		offsetof(struct sym_ccb, phys.head.go.restart),
+	SCR_RETURN,
+		0,
+	/* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< RESEL_DSA >------------------------*/,{
+	/*
+	 *  ACK the IDENTIFY or TAG previously received.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+}/*-------------------------< RESEL_DSA1 >-----------------------*/,{
+	/*
+	 *      Initialize the status registers
+	 */
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct sym_ccb, phys.head.status),
+	/*
+	 *  Jump to dispatcher.
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< RESEL_NO_TAG >---------------------*/,{
+	/*
+	 *  Load the DSA with the unique ITL task.
+	 */
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct sym_lcb, head.itl_task_sa),
+	/*
+	 *  JUMP indirectly to the restart point of the CCB.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof(struct sym_ccb, phys.head.go.restart),
+	SCR_RETURN,
+		0,
+	/* In normal situations we branch to RESEL_DSA */
+}/*-------------------------< DATA_IN >--------------------------*/,{
+/*
+ *  Because the size depends on the
+ *  #define SYM_CONF_MAX_SG parameter,
+ *  it is filled in at runtime.
+ *
+ *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ *  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+ *  ||		offsetof (struct sym_dsb, data[ i]),
+ *  ##==========================================
+ */
+0
+}/*-------------------------< DATA_IN2 >-------------------------*/,{
+	SCR_CALL,
+		PADDR_A (datai_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< DATA_OUT >-------------------------*/,{
+/*
+ *  Because the size depends on the
+ *  #define SYM_CONF_MAX_SG parameter,
+ *  it is filled in at runtime.
+ *
+ *  ##===========< i=0; i<SYM_CONF_MAX_SG >=========
+ *  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+ *  ||		offsetof (struct sym_dsb, data[ i]),
+ *  ##==========================================
+ */
+0
+}/*-------------------------< DATA_OUT2 >------------------------*/,{
+	SCR_CALL,
+		PADDR_A (datao_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< PM0_DATA >-------------------------*/,{
+	/*
+	 *  Read our host flags to SFBR, so we will be able 
+	 *  to check against the data direction we expect.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	 *  Check against actual DATA PHASE.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR_A (pm0_data_out),
+	/*
+	 *  Actual phase is DATA IN.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+		0,
+	/*
+	 *  Move the data to memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.pm0.sg),
+	SCR_JUMP,
+		PADDR_A (pm0_data_end),
+}/*-------------------------< PM0_DATA_OUT >---------------------*/,{
+	/*
+	 *  Actual phase is DATA OUT.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM0),
+		0,
+	/*
+	 *  Move the data from memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+		offsetof (struct sym_ccb, phys.pm0.sg),
+}/*-------------------------< PM0_DATA_END >---------------------*/,{
+	/*
+	 *  Clear the flag that told we were moving  
+	 *  data from the PM0 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM0)),
+		0,
+	/*
+	 *  Return to the previous DATA script which 
+	 *  is guaranteed by design (if no bug) to be 
+	 *  the main DATA script for this transfer.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.pm0.ret),
+	SCR_RETURN,
+		0,
+}/*-------------------------< PM1_DATA >-------------------------*/,{
+	/*
+	 *  Read our host flags to SFBR, so we will be able 
+	 *  to check against the data direction we expect.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	 *  Check against actual DATA PHASE.
+	 */
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		PADDR_A (pm1_data_out),
+	/*
+	 *  Actual phase is DATA IN.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+		0,
+	/*
+	 *  Move the data to memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.pm1.sg),
+	SCR_JUMP,
+		PADDR_A (pm1_data_end),
+}/*-------------------------< PM1_DATA_OUT >---------------------*/,{
+	/*
+	 *  Actual phase is DATA OUT.
+	 *  Check against expected direction.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (HF_DATA_IN, HF_DATA_IN)),
+		PADDR_B (data_ovrun),
+	/*
+	 *  Keep track we are moving data from the 
+	 *  PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_OR, HF_IN_PM1),
+		0,
+	/*
+	 *  Move the data from memory.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
+		offsetof (struct sym_ccb, phys.pm1.sg),
+}/*-------------------------< PM1_DATA_END >---------------------*/,{
+	/*
+	 *  Clear the flag that told we were moving  
+	 *  data from the PM1 DATA mini-script.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_IN_PM1)),
+		0,
+	/*
+	 *  Return to the previous DATA script which 
+	 *  is guaranteed by design (if no bug) to be 
+	 *  the main DATA script for this transfer.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct sym_ccb, phys.pm1.ret),
+	SCR_RETURN,
+		0,
+}/*-------------------------<>-----------------------------------*/
+};
+
+static struct SYM_FWB_SCR SYM_FWB_SCR = {
+/*--------------------------< START64 >--------------------------*/ {
+	/*
+	 *  SCRIPT entry point for the 895A, 896 and 1010.
+	 *  For now, there is no specific stuff for those 
+	 *  chips at this point, but this may come.
+	 */
+	SCR_JUMP,
+		PADDR_A (init),
+}/*-------------------------< NO_DATA >--------------------------*/,{
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< SEL_FOR_ABORT >--------------------*/,{
+	/*
+	 *  We are jumped here by the C code, if we have 
+	 *  some target to reset or some disconnected 
+	 *  job to abort. Since error recovery is a serious 
+	 *  busyness, we will really reset the SCSI BUS, if 
+	 *  case of a SCSI interrupt occurring in this path.
+	 */
+#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
+	/*
+	 *  Set initiator mode.
+	 */
+	SCR_CLR (SCR_TRG),
+		0,
+#endif
+	/*
+	 *      And try to select this target.
+	 */
+	SCR_SEL_TBL_ATN ^ offsetof (struct sym_hcb, abrt_sel),
+		PADDR_A (reselect),
+	/*
+	 *  Wait for the selection to complete or 
+	 *  the selection to time out.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		-8,
+	/*
+	 *  Call the C code.
+	 */
+	SCR_INT,
+		SIR_TARGET_SELECTED,
+	/*
+	 *  The C code should let us continue here. 
+	 *  Send the 'kiss of death' message.
+	 *  We expect an immediate disconnect once 
+	 *  the target has eaten the message.
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct sym_hcb, abrt_tbl),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	 *  Tell the C code that we are done.
+	 */
+	SCR_INT,
+		SIR_ABORT_SENT,
+}/*-------------------------< SEL_FOR_ABORT_1 >------------------*/,{
+	/*
+	 *  Jump at scheduler.
+	 */
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< MSG_IN_ETC >-----------------------*/,{
+	/*
+	 *  If it is an EXTENDED (variable size message)
+	 *  Handle it.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDR_B (msg_extended),
+	/*
+	 *  Let the C code handle any other 
+	 *  1 byte message.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+		PADDR_B (msg_received),
+	SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+		PADDR_B (msg_received),
+	/*
+	 *  We donnot handle 2 bytes messages from SCRIPTS.
+	 *  So, let the C code deal with these ones too.
+	 */
+	SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+		PADDR_B (msg_weird_seen),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+}/*-------------------------< MSG_RECEIVED >---------------------*/,{
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_RECEIVED,
+}/*-------------------------< MSG_WEIRD_SEEN >-------------------*/,{
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_WEIRD,
+}/*-------------------------< MSG_EXTENDED >---------------------*/,{
+	/*
+	 *  Clear ACK and get the next byte 
+	 *  assumed to be the message length.
+	 */
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (msgin[1]),
+	/*
+	 *  Try to catch some unlikely situations as 0 length 
+	 *  or too large the length.
+	 */
+	SCR_JUMP ^ IFTRUE (DATA (0)),
+		PADDR_B (msg_weird_seen),
+	SCR_TO_REG (scratcha),
+		0,
+	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+		0,
+	SCR_JUMP ^ IFTRUE (CARRYSET),
+		PADDR_B (msg_weird_seen),
+	/*
+	 *  We donnot handle extended messages from SCRIPTS.
+	 *  Read the amount of data correponding to the 
+	 *  message length and call the C code.
+	 */
+	SCR_STORE_REL (scratcha, 1),
+		offsetof (struct sym_dsb, smsg_ext.size),
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_IN,
+		offsetof (struct sym_dsb, smsg_ext),
+	SCR_JUMP,
+		PADDR_B (msg_received),
+}/*-------------------------< MSG_BAD >--------------------------*/,{
+	/*
+	 *  unimplemented message - reject it.
+	 */
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (clrack),
+}/*-------------------------< MSG_WEIRD >------------------------*/,{
+	/*
+	 *  weird message received
+	 *  ignore all MSG IN phases and reject it.
+	 */
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
+}/*-------------------------< MSG_WEIRD1 >-----------------------*/,{
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR_A (dispatch),
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		HADDR_1 (scratch),
+	SCR_JUMP,
+		PADDR_B (msg_weird1),
+}/*-------------------------< WDTR_RESP >------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_WDTR >------------------------*/,{
+	/*
+	 *  Send the M_X_WIDE_REQ
+	 */
+	SCR_MOVE_ABS (4) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< SDTR_RESP >------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_SDTR >------------------------*/,{
+	/*
+	 *  Send the M_X_SYNC_REQ
+	 */
+	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< PPR_RESP >-------------------------*/,{
+	/*
+	 *  let the target fetch our answer.
+	 */
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (nego_bad_phase),
+}/*-------------------------< SEND_PPR >-------------------------*/,{
+	/*
+	 *  Send the M_X_PPR_REQ
+	 */
+	SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_JUMP,
+		PADDR_B (msg_out_done),
+}/*-------------------------< NEGO_BAD_PHASE >-------------------*/,{
+	SCR_INT,
+		SIR_NEGO_PROTO,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< MSG_OUT >--------------------------*/,{
+	/*
+	 *  The target requests a message.
+	 *  We donnot send messages that may 
+	 *  require the device to go to bus free.
+	 */
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	/*
+	 *  ... wait for the next phase
+	 *  if it's a message out, send it again, ...
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)),
+		PADDR_B (msg_out),
+}/*-------------------------< MSG_OUT_DONE >---------------------*/,{
+	/*
+	 *  Let the C code be aware of the 
+	 *  sent message and clear the message.
+	 */
+	SCR_INT,
+		SIR_MSG_OUT_DONE,
+	/*
+	 *  ... and process the next phase
+	 */
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< DATA_OVRUN >-----------------------*/,{
+	/*
+	 *  Use scratcha to count the extra bytes.
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (zero),
+}/*-------------------------< DATA_OVRUN1 >----------------------*/,{
+	/*
+	 *  The target may want to transfer too much data.
+	 *
+	 *  If phase is DATA OUT write 1 byte and count it.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+		16,
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_OUT,
+		HADDR_1 (scratch),
+	SCR_JUMP,
+		PADDR_B (data_ovrun2),
+	/*
+	 *  If WSR is set, clear this condition, and 
+	 *  count this byte.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
+		16,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	SCR_JUMP,
+		PADDR_B (data_ovrun2),
+	/*
+	 *  Finally check against DATA IN phase.
+	 *  Signal data overrun to the C code 
+	 *  and jump to dispatcher if not so.
+	 *  Read 1 byte otherwise and count it.
+	 */
+	SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_IN)),
+		16,
+	SCR_INT,
+		SIR_DATA_OVERRUN,
+	SCR_JUMP,
+		PADDR_A (dispatch),
+	SCR_CHMOV_ABS (1) ^ SCR_DATA_IN,
+		HADDR_1 (scratch),
+}/*-------------------------< DATA_OVRUN2 >----------------------*/,{
+	/*
+	 *  Count this byte.
+	 *  This will allow to return a negative 
+	 *  residual to user.
+	 */
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	/*
+	 *  .. and repeat as required.
+	 */
+	SCR_JUMP,
+		PADDR_B (data_ovrun1),
+}/*-------------------------< ABORT_RESEL >----------------------*/,{
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	 *  send the abort/abortag/reset message
+	 *  we expect an immediate disconnect
+	 */
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_OUT,
+		HADDR_1 (msgout),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	SCR_INT,
+		SIR_RESEL_ABORTED,
+	SCR_JUMP,
+		PADDR_A (start),
+}/*-------------------------< RESEND_IDENT >---------------------*/,{
+	/*
+	 *  The target stays in MSG OUT phase after having acked 
+	 *  Identify [+ Tag [+ Extended message ]]. Targets shall
+	 *  behave this way on parity error.
+	 *  We must send it again all the messages.
+	 */
+	SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the  */
+		0,         /* 1rst ACK = 90 ns. Hope the chip isn't too fast */
+	SCR_JUMP,
+		PADDR_A (send_ident),
+}/*-------------------------< IDENT_BREAK >----------------------*/,{
+	SCR_CLR (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (select2),
+}/*-------------------------< IDENT_BREAK_ATN >------------------*/,{
+	SCR_SET (SCR_ATN),
+		0,
+	SCR_JUMP,
+		PADDR_A (select2),
+}/*-------------------------< SDATA_IN >-------------------------*/,{
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_dsb, sense),
+	SCR_CALL,
+		PADDR_A (datai_done),
+	SCR_JUMP,
+		PADDR_B (data_ovrun),
+}/*-------------------------< RESEL_BAD_LUN >--------------------*/,{
+	/*
+	 *  Message is an IDENTIFY, but lun is unknown.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORT to clear all pending tasks.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_LUN,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L >------------------------*/,{
+	/*
+	 *  We donnot have a task for that I_T_L.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORT message.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_I_T_L_Q >----------------------*/,{
+	/*
+	 *  We donnot have a task that matches the tag.
+	 *  Signal problem to C code for logging the event.
+	 *  Send a M_ABORTTAG message.
+	 */
+	SCR_INT,
+		SIR_RESEL_BAD_I_T_L_Q,
+	SCR_JUMP,
+		PADDR_B (abort_resel),
+}/*-------------------------< BAD_STATUS >-----------------------*/,{
+	/*
+	 *  Anything different from INTERMEDIATE 
+	 *  CONDITION MET should be a bad SCSI status, 
+	 *  given that GOOD status has already been tested.
+	 *  Call the C code.
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (startpos),
+	SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
+		SIR_BAD_SCSI_STATUS,
+	SCR_RETURN,
+		0,
+}/*-------------------------< PM_HANDLE >------------------------*/,{
+	/*
+	 *  Phase mismatch handling.
+	 *
+	 *  Since we have to deal with 2 SCSI data pointers  
+	 *  (current and saved), we need at least 2 contexts.
+	 *  Each context (pm0 and pm1) has a saved area, a 
+	 *  SAVE mini-script and a DATA phase mini-script.
+	 */
+	/*
+	 *  Get the PM handling flags.
+	 */
+	SCR_FROM_REG (HF_REG),
+		0,
+	/*
+	 *  If no flags (1rst PM for example), avoid 
+	 *  all the below heavy flags testing.
+	 *  This makes the normal case a bit faster.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED))),
+		PADDR_B (pm_handle1),
+	/*
+	 *  If we received a SAVE DP, switch to the 
+	 *  other PM context since the savep may point 
+	 *  to the current PM context.
+	 */
+	SCR_JUMPR ^ IFFALSE (MASK (HF_DP_SAVED, HF_DP_SAVED)),
+		8,
+	SCR_REG_REG (sfbr, SCR_XOR, HF_ACT_PM),
+		0,
+	/*
+	 *  If we have been interrupt in a PM DATA mini-script,
+	 *  we take the return address from the corresponding 
+	 *  saved area.
+	 *  This ensure the return address always points to the 
+	 *  main DATA script for this transfer.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (0, (HF_IN_PM0 | HF_IN_PM1))),
+		PADDR_B (pm_handle1),
+	SCR_JUMPR ^ IFFALSE (MASK (HF_IN_PM0, HF_IN_PM0)),
+		16,
+	SCR_LOAD_REL (ia, 4),
+		offsetof(struct sym_ccb, phys.pm0.ret),
+	SCR_JUMP,
+		PADDR_B (pm_save),
+	SCR_LOAD_REL (ia, 4),
+		offsetof(struct sym_ccb, phys.pm1.ret),
+	SCR_JUMP,
+		PADDR_B (pm_save),
+}/*-------------------------< PM_HANDLE1 >-----------------------*/,{
+	/*
+	 *  Normal case.
+	 *  Update the return address so that it 
+	 *  will point after the interrupted MOVE.
+	 */
+	SCR_REG_REG (ia, SCR_ADD, 8),
+		0,
+	SCR_REG_REG (ia1, SCR_ADDC, 0),
+		0,
+}/*-------------------------< PM_SAVE >--------------------------*/,{
+	/*
+	 *  Clear all the flags that told us if we were 
+	 *  interrupted in a PM DATA mini-script and/or 
+	 *  we received a SAVE DP.
+	 */
+	SCR_SFBR_REG (HF_REG, SCR_AND, (~(HF_IN_PM0|HF_IN_PM1|HF_DP_SAVED))),
+		0,
+	/*
+	 *  Choose the current PM context.
+	 */
+	SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
+		PADDR_B (pm1_save),
+}/*-------------------------< PM0_SAVE >-------------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct sym_ccb, phys.pm0.ret),
+	/*
+	 *  If WSR bit is set, either UA and RBC may 
+	 *  have to be changed whether the device wants 
+	 *  to ignore this residue or not.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDR_B (pm_wsr_handle),
+	/*
+	 *  Save the remaining byte count, the updated 
+	 *  address and the return address.
+	 */
+	SCR_STORE_REL (rbc, 4),
+		offsetof(struct sym_ccb, phys.pm0.sg.size),
+	SCR_STORE_REL (ua, 4),
+		offsetof(struct sym_ccb, phys.pm0.sg.addr),
+	/*
+	 *  Set the current pointer at the PM0 DATA mini-script.
+	 */
+	SCR_LOAD_ABS (ia, 4),
+		PADDR_B (pm0_data_addr),
+}/*-------------------------< PM_SAVE_END >----------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct sym_ccb, phys.head.lastp),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+}/*-------------------------< PM1_SAVE >-------------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct sym_ccb, phys.pm1.ret),
+	/*
+	 *  If WSR bit is set, either UA and RBC may 
+	 *  have to be changed whether the device wants 
+	 *  to ignore this residue or not.
+	 */
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDR_B (pm_wsr_handle),
+	/*
+	 *  Save the remaining byte count, the updated 
+	 *  address and the return address.
+	 */
+	SCR_STORE_REL (rbc, 4),
+		offsetof(struct sym_ccb, phys.pm1.sg.size),
+	SCR_STORE_REL (ua, 4),
+		offsetof(struct sym_ccb, phys.pm1.sg.addr),
+	/*
+	 *  Set the current pointer at the PM1 DATA mini-script.
+	 */
+	SCR_LOAD_ABS (ia, 4),
+		PADDR_B (pm1_data_addr),
+	SCR_JUMP,
+		PADDR_B (pm_save_end),
+}/*-------------------------< PM_WSR_HANDLE >--------------------*/,{
+	/*
+	 *  Phase mismatch handling from SCRIPT with WSR set.
+	 *  Such a condition can occur if the chip wants to 
+	 *  execute a CHMOV(size > 1) when the WSR bit is 
+	 *  set and the target changes PHASE.
+	 *
+	 *  We must move the residual byte to memory.
+	 *
+	 *  UA contains bit 0..31 of the address to 
+	 *  move the residual byte.
+	 *  Move it to the table indirect.
+	 */
+	SCR_STORE_REL (ua, 4),
+		offsetof (struct sym_ccb, phys.wresid.addr),
+	/*
+	 *  Increment UA (move address to next position).
+	 */
+	SCR_REG_REG (ua, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (ua1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua2, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua3, SCR_ADDC, 0),
+		0,
+	/*
+	 *  Compute SCRATCHA as:
+	 *  - size to transfer = 1 byte.
+	 *  - bit 24..31 = high address bit [32...39].
+	 */
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDR_B (zero),
+	SCR_REG_REG (scratcha, SCR_OR, 1),
+		0,
+	SCR_FROM_REG (rbc3),
+		0,
+	SCR_TO_REG (scratcha3),
+		0,
+	/*
+	 *  Move this value to the table indirect.
+	 */
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.wresid.size),
+	/*
+	 *  Wait for a valid phase.
+	 *  While testing with bogus QUANTUM drives, the C1010 
+	 *  sometimes raised a spurious phase mismatch with 
+	 *  WSR and the CHMOV(1) triggered another PM.
+	 *  Waiting explicitely for the PHASE seemed to avoid 
+	 *  the nested phase mismatch. Btw, this didn't happen 
+	 *  using my IBM drives.
+	 */
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
+		0,
+	/*
+	 *  Perform the move of the residual byte.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.wresid),
+	/*
+	 *  We can now handle the phase mismatch with UA fixed.
+	 *  RBC[0..23]=0 is a special case that does not require 
+	 *  a PM context. The C code also checks against this.
+	 */
+	SCR_FROM_REG (rbc),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc1),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc2),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	/*
+	 *  RBC[0..23]=0.
+	 *  Not only we donnot need a PM context, but this would 
+	 *  lead to a bogus CHMOV(0). This condition means that 
+	 *  the residual was the last byte to move from this CHMOV.
+	 *  So, we just have to move the current data script pointer 
+	 *  (i.e. TEMP) to the SCRIPTS address following the 
+	 *  interrupted CHMOV and jump to dispatcher.
+	 *  IA contains the data pointer to save.
+	 */
+	SCR_JUMP,
+		PADDR_B (pm_save_end),
+}/*-------------------------< WSR_MA_HELPER >--------------------*/,{
+	/*
+	 *  Helper for the C code when WSR bit is set.
+	 *  Perform the move of the residual byte.
+	 */
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
+		offsetof (struct sym_ccb, phys.wresid),
+	SCR_JUMP,
+		PADDR_A (dispatch),
+
+#ifdef SYM_OPT_HANDLE_DIR_UNKNOWN
+}/*-------------------------< DATA_IO >--------------------------*/,{
+	/*
+	 *  We jump here if the data direction was unknown at the 
+	 *  time we had to queue the command to the scripts processor.
+	 *  Pointers had been set as follow in this situation:
+	 *    savep   -->   DATA_IO
+	 *    lastp   -->   start pointer when DATA_IN
+	 *    wlastp  -->   start pointer when DATA_OUT
+	 *  This script sets savep and lastp according to the 
+	 *  direction chosen by the target.
+	 */
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_DATA_OUT)),
+		PADDR_B (data_io_out),
+}/*-------------------------< DATA_IO_IN >-----------------------*/,{
+	/*
+	 *  Direction is DATA IN.
+	 */
+	SCR_LOAD_REL  (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+}/*-------------------------< DATA_IO_COM >----------------------*/,{
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.savep),
+
+	/*
+	 *  Jump to the SCRIPTS according to actual direction.
+	 */
+	SCR_LOAD_REL  (temp, 4),
+		offsetof (struct sym_ccb, phys.head.savep),
+	SCR_RETURN,
+		0,
+}/*-------------------------< DATA_IO_OUT >----------------------*/,{
+	/*
+	 *  Direction is DATA OUT.
+	 */
+	SCR_REG_REG (HF_REG, SCR_AND, (~HF_DATA_IN)),
+		0,
+	SCR_LOAD_REL  (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.wlastp),
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct sym_ccb, phys.head.lastp),
+	SCR_JUMP,
+		PADDR_B(data_io_com),
+#endif /* SYM_OPT_HANDLE_DIR_UNKNOWN */
+
+}/*-------------------------< ZERO >-----------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >--------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM0_DATA_ADDR >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM1_DATA_ADDR >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >-------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >-------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >--------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------<>-----------------------------------*/
+};
+
+static struct SYM_FWZ_SCR SYM_FWZ_SCR = {
+ /*-------------------------< SNOOPTEST >------------------------*/{
+	/*
+	 *  Read the variable from memory.
+	 */
+	SCR_LOAD_REL (scratcha, 4),
+		offsetof(struct sym_hcb, scratch),
+	/*
+	 *  Write the variable to memory.
+	 */
+	SCR_STORE_REL (temp, 4),
+		offsetof(struct sym_hcb, scratch),
+	/*
+	 *  Read back the variable from memory.
+	 */
+	SCR_LOAD_REL (temp, 4),
+		offsetof(struct sym_hcb, scratch),
+}/*-------------------------< SNOOPEND >-------------------------*/,{
+	/*
+	 *  And stop.
+	 */
+	SCR_INT,
+		99,
+}/*-------------------------<>-----------------------------------*/
+};
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
new file mode 100644
index 0000000..a1dff6d
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -0,0 +1,2196 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ * Copyright (c) 2003-2005  Matthew Wilcox <matthew@wil.cx>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <scsi/scsi.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport.h>
+
+#include "sym_glue.h"
+#include "sym_nvram.h"
+
+#define NAME53C		"sym53c"
+#define NAME53C8XX	"sym53c8xx"
+
+/* SPARC just has to be different ... */
+#ifdef __sparc__
+#define IRQ_FMT "%s"
+#define IRQ_PRM(x) __irq_itoa(x)
+#else
+#define IRQ_FMT "%d"
+#define IRQ_PRM(x) (x)
+#endif
+
+struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP;
+unsigned int sym_debug_flags = 0;
+
+static char *excl_string;
+static char *safe_string;
+module_param_named(cmd_per_lun, sym_driver_setup.max_tag, ushort, 0);
+module_param_string(tag_ctrl, sym_driver_setup.tag_ctrl, 100, 0);
+module_param_named(burst, sym_driver_setup.burst_order, byte, 0);
+module_param_named(led, sym_driver_setup.scsi_led, byte, 0);
+module_param_named(diff, sym_driver_setup.scsi_diff, byte, 0);
+module_param_named(irqm, sym_driver_setup.irq_mode, byte, 0);
+module_param_named(buschk, sym_driver_setup.scsi_bus_check, byte, 0);
+module_param_named(hostid, sym_driver_setup.host_id, byte, 0);
+module_param_named(verb, sym_driver_setup.verbose, byte, 0);
+module_param_named(debug, sym_debug_flags, uint, 0);
+module_param_named(settle, sym_driver_setup.settle_delay, byte, 0);
+module_param_named(nvram, sym_driver_setup.use_nvram, byte, 0);
+module_param_named(excl, excl_string, charp, 0);
+module_param_named(safe, safe_string, charp, 0);
+
+MODULE_PARM_DESC(cmd_per_lun, "The maximum number of tags to use by default");
+MODULE_PARM_DESC(tag_ctrl, "More detailed control over tags per LUN");
+MODULE_PARM_DESC(burst, "Maximum burst.  0 to disable, 255 to read from registers");
+MODULE_PARM_DESC(led, "Set to 1 to enable LED support");
+MODULE_PARM_DESC(diff, "0 for no differential mode, 1 for BIOS, 2 for always, 3 for not GPIO3");
+MODULE_PARM_DESC(irqm, "0 for open drain, 1 to leave alone, 2 for totem pole");
+MODULE_PARM_DESC(buschk, "0 to not check, 1 for detach on error, 2 for warn on error");
+MODULE_PARM_DESC(hostid, "The SCSI ID to use for the host adapters");
+MODULE_PARM_DESC(verb, "0 for minimal verbosity, 1 for normal, 2 for excessive");
+MODULE_PARM_DESC(debug, "Set bits to enable debugging");
+MODULE_PARM_DESC(settle, "Settle delay in seconds.  Default 3");
+MODULE_PARM_DESC(nvram, "Option currently not used");
+MODULE_PARM_DESC(excl, "List ioport addresses here to prevent controllers from being attached");
+MODULE_PARM_DESC(safe, "Set other settings to a \"safe mode\"");
+
+MODULE_LICENSE("GPL");
+MODULE_VERSION(SYM_VERSION);
+MODULE_AUTHOR("Matthew Wilcox <matthew@wil.cx>");
+MODULE_DESCRIPTION("NCR, Symbios and LSI 8xx and 1010 PCI SCSI adapters");
+
+static void sym2_setup_params(void)
+{
+	char *p = excl_string;
+	int xi = 0;
+
+	while (p && (xi < 8)) {
+		char *next_p;
+		int val = (int) simple_strtoul(p, &next_p, 0);
+		sym_driver_setup.excludes[xi++] = val;
+		p = next_p;
+	}
+
+	if (safe_string) {
+		if (*safe_string == 'y') {
+			sym_driver_setup.max_tag = 0;
+			sym_driver_setup.burst_order = 0;
+			sym_driver_setup.scsi_led = 0;
+			sym_driver_setup.scsi_diff = 1;
+			sym_driver_setup.irq_mode = 0;
+			sym_driver_setup.scsi_bus_check = 2;
+			sym_driver_setup.host_id = 7;
+			sym_driver_setup.verbose = 2;
+			sym_driver_setup.settle_delay = 10;
+			sym_driver_setup.use_nvram = 1;
+		} else if (*safe_string != 'n') {
+			printk(KERN_WARNING NAME53C8XX "Ignoring parameter %s"
+					" passed to safe option", safe_string);
+		}
+	}
+}
+
+/*
+ * We used to try to deal with 64-bit BARs here, but don't any more.
+ * There are many parts of this driver which would need to be modified
+ * to handle a 64-bit base address, including scripts.  I'm uncomfortable
+ * with making those changes when I have no way of testing it, so I'm
+ * just going to disable it.
+ *
+ * Note that some machines (eg HP rx8620 and Superdome) have bus addresses
+ * below 4GB and physical addresses above 4GB.  These will continue to work.
+ */
+static int __devinit
+pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep)
+{
+	u32 tmp;
+	unsigned long base;
+#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2))
+
+	pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
+	base = tmp;
+	if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp);
+		if (tmp > 0)
+			dev_err(&pdev->dev,
+				"BAR %d is 64-bit, disabling\n", index - 1);
+		base = 0;
+	}
+
+	if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) {
+		base &= PCI_BASE_ADDRESS_IO_MASK;
+	} else {
+		base &= PCI_BASE_ADDRESS_MEM_MASK;
+	}
+
+	*basep = base;
+	return index;
+#undef PCI_BAR_OFFSET
+}
+
+static struct scsi_transport_template *sym2_transport_template = NULL;
+
+/*
+ *  Used by the eh thread to wait for command completion.
+ *  It is allocated on the eh thread stack.
+ */
+struct sym_eh_wait {
+	struct completion done;
+	struct timer_list timer;
+	void (*old_done)(struct scsi_cmnd *);
+	int to_do;
+	int timed_out;
+};
+
+/*
+ *  Driver private area in the SCSI command structure.
+ */
+struct sym_ucmd {		/* Override the SCSI pointer structure */
+	dma_addr_t data_mapping;
+	u_char	data_mapped;
+	struct sym_eh_wait *eh_wait;
+};
+
+#define SYM_UCMD_PTR(cmd)  ((struct sym_ucmd *)(&(cmd)->SCp))
+#define SYM_SOFTC_PTR(cmd) sym_get_hcb(cmd->device->host)
+
+static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	int dma_dir = cmd->sc_data_direction;
+
+	switch(SYM_UCMD_PTR(cmd)->data_mapped) {
+	case 2:
+		pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+		break;
+	case 1:
+		pci_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
+				 cmd->request_bufflen, dma_dir);
+		break;
+	}
+	SYM_UCMD_PTR(cmd)->data_mapped = 0;
+}
+
+static dma_addr_t __map_scsi_single_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	dma_addr_t mapping;
+	int dma_dir = cmd->sc_data_direction;
+
+	mapping = pci_map_single(pdev, cmd->request_buffer,
+				 cmd->request_bufflen, dma_dir);
+	if (mapping) {
+		SYM_UCMD_PTR(cmd)->data_mapped  = 1;
+		SYM_UCMD_PTR(cmd)->data_mapping = mapping;
+	}
+
+	return mapping;
+}
+
+static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
+{
+	int use_sg;
+	int dma_dir = cmd->sc_data_direction;
+
+	use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+	if (use_sg > 0) {
+		SYM_UCMD_PTR(cmd)->data_mapped  = 2;
+		SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
+	}
+
+	return use_sg;
+}
+
+#define unmap_scsi_data(np, cmd)	\
+		__unmap_scsi_data(np->s.device, cmd)
+#define map_scsi_single_data(np, cmd)	\
+		__map_scsi_single_data(np->s.device, cmd)
+#define map_scsi_sg_data(np, cmd)	\
+		__map_scsi_sg_data(np->s.device, cmd)
+/*
+ *  Complete a pending CAM CCB.
+ */
+void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *cmd)
+{
+	unmap_scsi_data(np, cmd);
+	cmd->scsi_done(cmd);
+}
+
+static void sym_xpt_done2(struct sym_hcb *np, struct scsi_cmnd *cmd, int cam_status)
+{
+	sym_set_cam_status(cmd, cam_status);
+	sym_xpt_done(np, cmd);
+}
+
+
+/*
+ *  Tell the SCSI layer about a BUS RESET.
+ */
+void sym_xpt_async_bus_reset(struct sym_hcb *np)
+{
+	printf_notice("%s: SCSI BUS has been reset.\n", sym_name(np));
+	np->s.settle_time = jiffies + sym_driver_setup.settle_delay * HZ;
+	np->s.settle_time_valid = 1;
+	if (sym_verbose >= 2)
+		printf_info("%s: command processing suspended for %d seconds\n",
+			    sym_name(np), sym_driver_setup.settle_delay);
+}
+
+/*
+ *  Tell the SCSI layer about a BUS DEVICE RESET message sent.
+ */
+void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target)
+{
+	printf_notice("%s: TARGET %d has been reset.\n", sym_name(np), target);
+}
+
+/*
+ *  Choose the more appropriate CAM status if 
+ *  the IO encountered an extended error.
+ */
+static int sym_xerr_cam_status(int cam_status, int x_status)
+{
+	if (x_status) {
+		if	(x_status & XE_PARITY_ERR)
+			cam_status = DID_PARITY;
+		else if	(x_status &(XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN))
+			cam_status = DID_ERROR;
+		else if	(x_status & XE_BAD_PHASE)
+			cam_status = DID_ERROR;
+		else
+			cam_status = DID_ERROR;
+	}
+	return cam_status;
+}
+
+/*
+ *  Build CAM result for a failed or auto-sensed IO.
+ */
+void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid)
+{
+	struct scsi_cmnd *cmd = cp->cmd;
+	u_int cam_status, scsi_status, drv_status;
+
+	drv_status  = 0;
+	cam_status  = DID_OK;
+	scsi_status = cp->ssss_status;
+
+	if (cp->host_flags & HF_SENSE) {
+		scsi_status = cp->sv_scsi_status;
+		resid = cp->sv_resid;
+		if (sym_verbose && cp->sv_xerr_status)
+			sym_print_xerr(cmd, cp->sv_xerr_status);
+		if (cp->host_status == HS_COMPLETE &&
+		    cp->ssss_status == S_GOOD &&
+		    cp->xerr_status == 0) {
+			cam_status = sym_xerr_cam_status(DID_OK,
+							 cp->sv_xerr_status);
+			drv_status = DRIVER_SENSE;
+			/*
+			 *  Bounce back the sense data to user.
+			 */
+			memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+			memcpy(cmd->sense_buffer, cp->sns_bbuf,
+			      min(sizeof(cmd->sense_buffer),
+				  (size_t)SYM_SNS_BBUF_LEN));
+#if 0
+			/*
+			 *  If the device reports a UNIT ATTENTION condition 
+			 *  due to a RESET condition, we should consider all 
+			 *  disconnect CCBs for this unit as aborted.
+			 */
+			if (1) {
+				u_char *p;
+				p  = (u_char *) cmd->sense_data;
+				if (p[0]==0x70 && p[2]==0x6 && p[12]==0x29)
+					sym_clear_tasks(np, DID_ABORT,
+							cp->target,cp->lun, -1);
+			}
+#endif
+		} else {
+			/*
+			 * Error return from our internal request sense.  This
+			 * is bad: we must clear the contingent allegiance
+			 * condition otherwise the device will always return
+			 * BUSY.  Use a big stick.
+			 */
+			sym_reset_scsi_target(np, cmd->device->id);
+			cam_status = DID_ERROR;
+		}
+	} else if (cp->host_status == HS_COMPLETE) 	/* Bad SCSI status */
+		cam_status = DID_OK;
+	else if (cp->host_status == HS_SEL_TIMEOUT)	/* Selection timeout */
+		cam_status = DID_NO_CONNECT;
+	else if (cp->host_status == HS_UNEXPECTED)	/* Unexpected BUS FREE*/
+		cam_status = DID_ERROR;
+	else {						/* Extended error */
+		if (sym_verbose) {
+			sym_print_addr(cmd, "COMMAND FAILED (%x %x %x).\n",
+				cp->host_status, cp->ssss_status,
+				cp->xerr_status);
+		}
+		/*
+		 *  Set the most appropriate value for CAM status.
+		 */
+		cam_status = sym_xerr_cam_status(DID_ERROR, cp->xerr_status);
+	}
+	cmd->resid = resid;
+	cmd->result = (drv_status << 24) + (cam_status << 16) + scsi_status;
+}
+
+
+/*
+ *  Build the scatter/gather array for an I/O.
+ */
+
+static int sym_scatter_no_sglist(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
+{
+	struct sym_tblmove *data = &cp->phys.data[SYM_CONF_MAX_SG-1];
+	int segment;
+
+	cp->data_len = cmd->request_bufflen;
+
+	if (cmd->request_bufflen) {
+		dma_addr_t baddr = map_scsi_single_data(np, cmd);
+		if (baddr) {
+			sym_build_sge(np, data, baddr, cmd->request_bufflen);
+			segment = 1;
+		} else {
+			segment = -2;
+		}
+	} else {
+		segment = 0;
+	}
+
+	return segment;
+}
+
+static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd *cmd)
+{
+	int segment;
+	int use_sg = (int) cmd->use_sg;
+
+	cp->data_len = 0;
+
+	if (!use_sg)
+		segment = sym_scatter_no_sglist(np, cp, cmd);
+	else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
+		struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+		struct sym_tblmove *data;
+
+		if (use_sg > SYM_CONF_MAX_SG) {
+			unmap_scsi_data(np, cmd);
+			return -1;
+		}
+
+		data = &cp->phys.data[SYM_CONF_MAX_SG - use_sg];
+
+		for (segment = 0; segment < use_sg; segment++) {
+			dma_addr_t baddr = sg_dma_address(&scatter[segment]);
+			unsigned int len = sg_dma_len(&scatter[segment]);
+
+			sym_build_sge(np, &data[segment], baddr, len);
+			cp->data_len += len;
+		}
+	} else {
+		segment = -2;
+	}
+
+	return segment;
+}
+
+/*
+ *  Queue a SCSI command.
+ */
+static int sym_queue_command(struct sym_hcb *np, struct scsi_cmnd *cmd)
+{
+	struct scsi_device *sdev = cmd->device;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	struct sym_ccb *cp;
+	int	order;
+
+	/*
+	 *  Minimal checkings, so that we will not 
+	 *  go outside our tables.
+	 */
+	if (sdev->id == np->myaddr ||
+	    sdev->id >= SYM_CONF_MAX_TARGET ||
+	    sdev->lun >= SYM_CONF_MAX_LUN) {
+		sym_xpt_done2(np, cmd, CAM_DEV_NOT_THERE);
+		return 0;
+	}
+
+	/*
+	 *  Retrieve the target descriptor.
+	 */
+	tp = &np->target[sdev->id];
+
+	/*
+	 *  Complete the 1st INQUIRY command with error 
+	 *  condition if the device is flagged NOSCAN 
+	 *  at BOOT in the NVRAM. This may speed up 
+	 *  the boot and maintain coherency with BIOS 
+	 *  device numbering. Clearing the flag allows 
+	 *  user to rescan skipped devices later.
+	 *  We also return error for devices not flagged 
+	 *  for SCAN LUNS in the NVRAM since some mono-lun 
+	 *  devices behave badly when asked for some non 
+	 *  zero LUN. Btw, this is an absolute hack.:-)
+	 */
+	if (cmd->cmnd[0] == 0x12 || cmd->cmnd[0] == 0x0) {
+		if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||
+		    ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && 
+		     sdev->lun != 0)) {
+			tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
+			sym_xpt_done2(np, cmd, CAM_DEV_NOT_THERE);
+			return 0;
+		}
+	}
+
+	/*
+	 *  Select tagged/untagged.
+	 */
+	lp = sym_lp(tp, sdev->lun);
+	order = (lp && lp->s.reqtags) ? M_SIMPLE_TAG : 0;
+
+	/*
+	 *  Queue the SCSI IO.
+	 */
+	cp = sym_get_ccb(np, cmd, order);
+	if (!cp)
+		return 1;	/* Means resource shortage */
+	sym_queue_scsiio(np, cmd, cp);
+	return 0;
+}
+
+/*
+ *  Setup buffers and pointers that address the CDB.
+ */
+static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
+{
+	u32	cmd_ba;
+	int	cmd_len;
+
+	/*
+	 *  CDB is 16 bytes max.
+	 */
+	if (cmd->cmd_len > sizeof(cp->cdb_buf)) {
+		sym_set_cam_status(cp->cmd, CAM_REQ_INVALID);
+		return -1;
+	}
+
+	memcpy(cp->cdb_buf, cmd->cmnd, cmd->cmd_len);
+	cmd_ba  = CCB_BA (cp, cdb_buf[0]);
+	cmd_len = cmd->cmd_len;
+
+	cp->phys.cmd.addr	= cpu_to_scr(cmd_ba);
+	cp->phys.cmd.size	= cpu_to_scr(cmd_len);
+
+	return 0;
+}
+
+/*
+ *  Setup pointers that address the data and start the I/O.
+ */
+int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
+{
+	int dir;
+	struct sym_tcb *tp = &np->target[cp->target];
+	struct sym_lcb *lp = sym_lp(tp, cp->lun);
+
+	/*
+	 *  Build the CDB.
+	 */
+	if (sym_setup_cdb(np, cmd, cp))
+		goto out_abort;
+
+	/*
+	 *  No direction means no data.
+	 */
+	dir = cmd->sc_data_direction;
+	if (dir != DMA_NONE) {
+		cp->segments = sym_scatter(np, cp, cmd);
+		if (cp->segments < 0) {
+			if (cp->segments == -2)
+				sym_set_cam_status(cmd, CAM_RESRC_UNAVAIL);
+			else
+				sym_set_cam_status(cmd, CAM_REQ_TOO_BIG);
+			goto out_abort;
+		}
+	} else {
+		cp->data_len = 0;
+		cp->segments = 0;
+	}
+
+	/*
+	 *  Set data pointers.
+	 */
+	sym_setup_data_pointers(np, cp, dir);
+
+	/*
+	 *  When `#ifed 1', the code below makes the driver 
+	 *  panic on the first attempt to write to a SCSI device.
+	 *  It is the first test we want to do after a driver 
+	 *  change that does not seem obviously safe. :)
+	 */
+#if 0
+	switch (cp->cdb_buf[0]) {
+	case 0x0A: case 0x2A: case 0xAA:
+		panic("XXXXXXXXXXXXX WRITE NOT YET ALLOWED XXXXXXXXXXXXXX\n");
+		break;
+	default:
+		break;
+	}
+#endif
+
+	/*
+	 *	activate this job.
+	 */
+	if (lp)
+		sym_start_next_ccbs(np, lp, 2);
+	else
+		sym_put_start_queue(np, cp);
+	return 0;
+
+out_abort:
+	sym_free_ccb(np, cp);
+	sym_xpt_done(np, cmd);
+	return 0;
+}
+
+
+/*
+ *  timer daemon.
+ *
+ *  Misused to keep the driver running when
+ *  interrupts are not configured correctly.
+ */
+static void sym_timer(struct sym_hcb *np)
+{
+	unsigned long thistime = jiffies;
+
+	/*
+	 *  Restart the timer.
+	 */
+	np->s.timer.expires = thistime + SYM_CONF_TIMER_INTERVAL;
+	add_timer(&np->s.timer);
+
+	/*
+	 *  If we are resetting the ncr, wait for settle_time before 
+	 *  clearing it. Then command processing will be resumed.
+	 */
+	if (np->s.settle_time_valid) {
+		if (time_before_eq(np->s.settle_time, thistime)) {
+			if (sym_verbose >= 2 )
+				printk("%s: command processing resumed\n",
+				       sym_name(np));
+			np->s.settle_time_valid = 0;
+		}
+		return;
+	}
+
+	/*
+	 *	Nothing to do for now, but that may come.
+	 */
+	if (np->s.lasttime + 4*HZ < thistime) {
+		np->s.lasttime = thistime;
+	}
+
+#ifdef SYM_CONF_PCIQ_MAY_MISS_COMPLETIONS
+	/*
+	 *  Some way-broken PCI bridges may lead to 
+	 *  completions being lost when the clearing 
+	 *  of the INTFLY flag by the CPU occurs 
+	 *  concurrently with the chip raising this flag.
+	 *  If this ever happen, lost completions will 
+	 * be reaped here.
+	 */
+	sym_wakeup_done(np);
+#endif
+}
+
+
+/*
+ *  PCI BUS error handler.
+ */
+void sym_log_bus_error(struct sym_hcb *np)
+{
+	u_short pci_sts;
+	pci_read_config_word(np->s.device, PCI_STATUS, &pci_sts);
+	if (pci_sts & 0xf900) {
+		pci_write_config_word(np->s.device, PCI_STATUS, pci_sts);
+		printf("%s: PCI STATUS = 0x%04x\n",
+			sym_name(np), pci_sts & 0xf900);
+	}
+}
+
+/*
+ * queuecommand method.  Entered with the host adapter lock held and
+ * interrupts disabled.
+ */
+static int sym53c8xx_queue_command(struct scsi_cmnd *cmd,
+					void (*done)(struct scsi_cmnd *))
+{
+	struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
+	struct sym_ucmd *ucp = SYM_UCMD_PTR(cmd);
+	int sts = 0;
+
+	cmd->scsi_done     = done;
+	memset(ucp, 0, sizeof(*ucp));
+
+	/*
+	 *  Shorten our settle_time if needed for 
+	 *  this command not to time out.
+	 */
+	if (np->s.settle_time_valid && cmd->timeout_per_command) {
+		unsigned long tlimit = jiffies + cmd->timeout_per_command;
+		tlimit -= SYM_CONF_TIMER_INTERVAL*2;
+		if (time_after(np->s.settle_time, tlimit)) {
+			np->s.settle_time = tlimit;
+		}
+	}
+
+	if (np->s.settle_time_valid)
+		return SCSI_MLQUEUE_HOST_BUSY;
+
+	sts = sym_queue_command(np, cmd);
+	if (sts)
+		return SCSI_MLQUEUE_HOST_BUSY;
+	return 0;
+}
+
+/*
+ *  Linux entry point of the interrupt handler.
+ */
+static irqreturn_t sym53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs)
+{
+	unsigned long flags;
+	struct sym_hcb *np = (struct sym_hcb *)dev_id;
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("[");
+
+	spin_lock_irqsave(np->s.host->host_lock, flags);
+	sym_interrupt(np);
+	spin_unlock_irqrestore(np->s.host->host_lock, flags);
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printf_debug ("]\n");
+
+	return IRQ_HANDLED;
+}
+
+/*
+ *  Linux entry point of the timer handler
+ */
+static void sym53c8xx_timer(unsigned long npref)
+{
+	struct sym_hcb *np = (struct sym_hcb *)npref;
+	unsigned long flags;
+
+	spin_lock_irqsave(np->s.host->host_lock, flags);
+	sym_timer(np);
+	spin_unlock_irqrestore(np->s.host->host_lock, flags);
+}
+
+
+/*
+ *  What the eh thread wants us to perform.
+ */
+#define SYM_EH_ABORT		0
+#define SYM_EH_DEVICE_RESET	1
+#define SYM_EH_BUS_RESET	2
+#define SYM_EH_HOST_RESET	3
+
+/*
+ *  What we will do regarding the involved SCSI command.
+ */
+#define SYM_EH_DO_IGNORE	0
+#define SYM_EH_DO_COMPLETE	1
+#define SYM_EH_DO_WAIT		2
+
+/*
+ *  Our general completion handler.
+ */
+static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out)
+{
+	struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait;
+	if (!ep)
+		return;
+
+	/* Try to avoid a race here (not 100% safe) */
+	if (!timed_out) {
+		ep->timed_out = 0;
+		if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer))
+			return;
+	}
+
+	/* Revert everything */
+	SYM_UCMD_PTR(cmd)->eh_wait = NULL;
+	cmd->scsi_done = ep->old_done;
+
+	/* Wake up the eh thread if it wants to sleep */
+	if (ep->to_do == SYM_EH_DO_WAIT)
+		complete(&ep->done);
+}
+
+/*
+ *  scsi_done() alias when error recovery is in progress. 
+ */
+static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); }
+
+/*
+ *  Some timeout handler to avoid waiting too long.
+ */
+static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); }
+
+/*
+ *  Generic method for our eh processing.
+ *  The 'op' argument tells what we have to do.
+ */
+static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd)
+{
+	struct sym_hcb *np = SYM_SOFTC_PTR(cmd);
+	SYM_QUEHEAD *qp;
+	int to_do = SYM_EH_DO_IGNORE;
+	int sts = -1;
+	struct sym_eh_wait eh, *ep = &eh;
+
+	dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
+
+#if 0
+	/* This one should be the result of some race, thus to ignore */
+	if (cmd->serial_number != cmd->serial_number_at_timeout)
+		goto prepare;
+#endif
+
+	/* This one is queued in some place -> to wait for completion */
+	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+		struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		if (cp->cmd == cmd) {
+			to_do = SYM_EH_DO_WAIT;
+			goto prepare;
+		}
+	}
+
+prepare:
+	/* Prepare stuff to either ignore, complete or wait for completion */
+	switch(to_do) {
+	default:
+	case SYM_EH_DO_IGNORE:
+		break;
+	case SYM_EH_DO_WAIT:
+		init_completion(&ep->done);
+		/* fall through */
+	case SYM_EH_DO_COMPLETE:
+		ep->old_done = cmd->scsi_done;
+		cmd->scsi_done = sym_eh_done;
+		SYM_UCMD_PTR(cmd)->eh_wait = ep;
+	}
+
+	/* Try to proceed the operation we have been asked for */
+	sts = -1;
+	switch(op) {
+	case SYM_EH_ABORT:
+		sts = sym_abort_scsiio(np, cmd, 1);
+		break;
+	case SYM_EH_DEVICE_RESET:
+		sts = sym_reset_scsi_target(np, cmd->device->id);
+		break;
+	case SYM_EH_BUS_RESET:
+		sym_reset_scsi_bus(np, 1);
+		sts = 0;
+		break;
+	case SYM_EH_HOST_RESET:
+		sym_reset_scsi_bus(np, 0);
+		sym_start_up (np, 1);
+		sts = 0;
+		break;
+	default:
+		break;
+	}
+
+	/* On error, restore everything and cross fingers :) */
+	if (sts) {
+		SYM_UCMD_PTR(cmd)->eh_wait = NULL;
+		cmd->scsi_done = ep->old_done;
+		to_do = SYM_EH_DO_IGNORE;
+	}
+
+	ep->to_do = to_do;
+	/* Complete the command with locks held as required by the driver */
+	if (to_do == SYM_EH_DO_COMPLETE)
+		sym_xpt_done2(np, cmd, CAM_REQ_ABORTED);
+
+	/* Wait for completion with locks released, as required by kernel */
+	if (to_do == SYM_EH_DO_WAIT) {
+		init_timer(&ep->timer);
+		ep->timer.expires = jiffies + (5*HZ);
+		ep->timer.function = sym_eh_timeout;
+		ep->timer.data = (u_long)cmd;
+		ep->timed_out = 1;	/* Be pessimistic for once :) */
+		add_timer(&ep->timer);
+		spin_unlock_irq(np->s.host->host_lock);
+		wait_for_completion(&ep->done);
+		spin_lock_irq(np->s.host->host_lock);
+		if (ep->timed_out)
+			sts = -2;
+	}
+	dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
+			sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
+	return sts ? SCSI_FAILED : SCSI_SUCCESS;
+}
+
+
+/*
+ * Error handlers called from the eh thread (one thread per HBA).
+ */
+static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd)
+{
+	return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd);
+}
+
+static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd)
+{
+	return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd);
+}
+
+static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd)
+{
+	return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd);
+}
+
+static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd)
+{
+	return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd);
+}
+
+/*
+ *  Tune device queuing depth, according to various limits.
+ */
+static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags)
+{
+	struct sym_lcb *lp = sym_lp(tp, lun);
+	u_short	oldtags;
+
+	if (!lp)
+		return;
+
+	oldtags = lp->s.reqtags;
+
+	if (reqtags > lp->s.scdev_depth)
+		reqtags = lp->s.scdev_depth;
+
+	lp->started_limit = reqtags ? reqtags : 2;
+	lp->started_max   = 1;
+	lp->s.reqtags     = reqtags;
+
+	if (reqtags != oldtags) {
+		dev_info(&tp->sdev->sdev_target->dev,
+		         "tagged command queuing %s, command queue depth %d.\n",
+		          lp->s.reqtags ? "enabled" : "disabled",
+ 		          lp->started_limit);
+	}
+}
+
+/*
+ *  Linux select queue depths function
+ */
+#define DEF_DEPTH	(sym_driver_setup.max_tag)
+#define ALL_TARGETS	-2
+#define NO_TARGET	-1
+#define ALL_LUNS	-2
+#define NO_LUN		-1
+
+static int device_queue_depth(struct sym_hcb *np, int target, int lun)
+{
+	int c, h, t, u, v;
+	char *p = sym_driver_setup.tag_ctrl;
+	char *ep;
+
+	h = -1;
+	t = NO_TARGET;
+	u = NO_LUN;
+	while ((c = *p++) != 0) {
+		v = simple_strtoul(p, &ep, 0);
+		switch(c) {
+		case '/':
+			++h;
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		case 't':
+			if (t != target)
+				t = (target == v) ? v : NO_TARGET;
+			u = ALL_LUNS;
+			break;
+		case 'u':
+			if (u != lun)
+				u = (lun == v) ? v : NO_LUN;
+			break;
+		case 'q':
+			if (h == np->s.unit &&
+				(t == ALL_TARGETS || t == target) &&
+				(u == ALL_LUNS    || u == lun))
+				return v;
+			break;
+		case '-':
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		default:
+			break;
+		}
+		p = ep;
+	}
+	return DEF_DEPTH;
+}
+
+static int sym53c8xx_slave_alloc(struct scsi_device *device)
+{
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
+	if (!tp->sdev)
+		tp->sdev = device;
+
+	return 0;
+}
+
+static void sym53c8xx_slave_destroy(struct scsi_device *device)
+{
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
+	if (tp->sdev == device)
+		tp->sdev = NULL;
+}
+
+/*
+ * Linux entry point for device queue sizing.
+ */
+static int sym53c8xx_slave_configure(struct scsi_device *device)
+{
+	struct sym_hcb *np = sym_get_hcb(device->host);
+	struct sym_tcb *tp = &np->target[device->id];
+	struct sym_lcb *lp;
+	int reqtags, depth_to_use;
+
+	/*
+	 *  Allocate the LCB if not yet.
+	 *  If it fail, we may well be in the sh*t. :)
+	 */
+	lp = sym_alloc_lcb(np, device->id, device->lun);
+	if (!lp)
+		return -ENOMEM;
+
+	/*
+	 *  Get user flags.
+	 */
+	lp->curr_flags = lp->user_flags;
+
+	/*
+	 *  Select queue depth from driver setup.
+	 *  Donnot use more than configured by user.
+	 *  Use at least 2.
+	 *  Donnot use more than our maximum.
+	 */
+	reqtags = device_queue_depth(np, device->id, device->lun);
+	if (reqtags > tp->usrtags)
+		reqtags = tp->usrtags;
+	if (!device->tagged_supported)
+		reqtags = 0;
+#if 1 /* Avoid to locally queue commands for no good reasons */
+	if (reqtags > SYM_CONF_MAX_TAG)
+		reqtags = SYM_CONF_MAX_TAG;
+	depth_to_use = (reqtags ? reqtags : 2);
+#else
+	depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
+#endif
+	scsi_adjust_queue_depth(device,
+				(device->tagged_supported ?
+				 MSG_SIMPLE_TAG : 0),
+				depth_to_use);
+	lp->s.scdev_depth = depth_to_use;
+	sym_tune_dev_queuing(tp, device->lun, reqtags);
+
+	if (!spi_initial_dv(device->sdev_target))
+		spi_dv_device(device);
+
+	return 0;
+}
+
+/*
+ *  Linux entry point for info() function
+ */
+static const char *sym53c8xx_info (struct Scsi_Host *host)
+{
+	return SYM_DRIVER_NAME;
+}
+
+
+#ifdef SYM_LINUX_PROC_INFO_SUPPORT
+/*
+ *  Proc file system stuff
+ *
+ *  A read operation returns adapter information.
+ *  A write operation is a control command.
+ *  The string is parsed in the driver code and the command is passed 
+ *  to the sym_usercmd() function.
+ */
+
+#ifdef SYM_LINUX_USER_COMMAND_SUPPORT
+
+struct	sym_usrcmd {
+	u_long	target;
+	u_long	lun;
+	u_long	data;
+	u_long	cmd;
+};
+
+#define UC_SETSYNC      10
+#define UC_SETTAGS	11
+#define UC_SETDEBUG	12
+#define UC_SETWIDE	14
+#define UC_SETFLAG	15
+#define UC_SETVERBOSE	17
+#define UC_RESETDEV	18
+#define UC_CLEARDEV	19
+
+static void sym_exec_user_command (struct sym_hcb *np, struct sym_usrcmd *uc)
+{
+	struct sym_tcb *tp;
+	int t, l;
+
+	switch (uc->cmd) {
+	case 0: return;
+
+#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
+	case UC_SETDEBUG:
+		sym_debug_flags = uc->data;
+		break;
+#endif
+	case UC_SETVERBOSE:
+		np->verbose = uc->data;
+		break;
+	default:
+		/*
+		 * We assume that other commands apply to targets.
+		 * This should always be the case and avoid the below 
+		 * 4 lines to be repeated 6 times.
+		 */
+		for (t = 0; t < SYM_CONF_MAX_TARGET; t++) {
+			if (!((uc->target >> t) & 1))
+				continue;
+			tp = &np->target[t];
+
+			switch (uc->cmd) {
+
+			case UC_SETSYNC:
+				if (!uc->data || uc->data >= 255) {
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 0;
+					tp->tgoal.offset = 0;
+				} else if (uc->data <= 9 && np->minsync_dt) {
+					if (uc->data < np->minsync_dt)
+						uc->data = np->minsync_dt;
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 1;
+					tp->tgoal.width = 1;
+					tp->tgoal.period = uc->data;
+					tp->tgoal.offset = np->maxoffs_dt;
+				} else {
+					if (uc->data < np->minsync)
+						uc->data = np->minsync;
+					tp->tgoal.iu = tp->tgoal.dt =
+						tp->tgoal.qas = 0;
+					tp->tgoal.period = uc->data;
+					tp->tgoal.offset = np->maxoffs;
+				}
+				tp->tgoal.check_nego = 1;
+				break;
+			case UC_SETWIDE:
+				tp->tgoal.width = uc->data ? 1 : 0;
+				tp->tgoal.check_nego = 1;
+				break;
+			case UC_SETTAGS:
+				for (l = 0; l < SYM_CONF_MAX_LUN; l++)
+					sym_tune_dev_queuing(tp, l, uc->data);
+				break;
+			case UC_RESETDEV:
+				tp->to_reset = 1;
+				np->istat_sem = SEM;
+				OUTB(np, nc_istat, SIGP|SEM);
+				break;
+			case UC_CLEARDEV:
+				for (l = 0; l < SYM_CONF_MAX_LUN; l++) {
+					struct sym_lcb *lp = sym_lp(tp, l);
+					if (lp) lp->to_clear = 1;
+				}
+				np->istat_sem = SEM;
+				OUTB(np, nc_istat, SIGP|SEM);
+				break;
+			case UC_SETFLAG:
+				tp->usrflags = uc->data;
+				break;
+			}
+		}
+		break;
+	}
+}
+
+static int skip_spaces(char *ptr, int len)
+{
+	int cnt, c;
+
+	for (cnt = len; cnt > 0 && (c = *ptr++) && isspace(c); cnt--);
+
+	return (len - cnt);
+}
+
+static int get_int_arg(char *ptr, int len, u_long *pv)
+{
+	char *end;
+
+	*pv = simple_strtoul(ptr, &end, 10);
+	return (end - ptr);
+}
+
+static int is_keyword(char *ptr, int len, char *verb)
+{
+	int verb_len = strlen(verb);
+
+	if (len >= verb_len && !memcmp(verb, ptr, verb_len))
+		return verb_len;
+	else
+		return 0;
+}
+
+#define SKIP_SPACES(ptr, len)						\
+	if ((arg_len = skip_spaces(ptr, len)) < 1)			\
+		return -EINVAL;						\
+	ptr += arg_len; len -= arg_len;
+
+#define GET_INT_ARG(ptr, len, v)					\
+	if (!(arg_len = get_int_arg(ptr, len, &(v))))			\
+		return -EINVAL;						\
+	ptr += arg_len; len -= arg_len;
+
+
+/*
+ * Parse a control command
+ */
+
+static int sym_user_command(struct sym_hcb *np, char *buffer, int length)
+{
+	char *ptr	= buffer;
+	int len		= length;
+	struct sym_usrcmd cmd, *uc = &cmd;
+	int		arg_len;
+	u_long 		target;
+
+	memset(uc, 0, sizeof(*uc));
+
+	if (len > 0 && ptr[len-1] == '\n')
+		--len;
+
+	if	((arg_len = is_keyword(ptr, len, "setsync")) != 0)
+		uc->cmd = UC_SETSYNC;
+	else if	((arg_len = is_keyword(ptr, len, "settags")) != 0)
+		uc->cmd = UC_SETTAGS;
+	else if	((arg_len = is_keyword(ptr, len, "setverbose")) != 0)
+		uc->cmd = UC_SETVERBOSE;
+	else if	((arg_len = is_keyword(ptr, len, "setwide")) != 0)
+		uc->cmd = UC_SETWIDE;
+#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
+	else if	((arg_len = is_keyword(ptr, len, "setdebug")) != 0)
+		uc->cmd = UC_SETDEBUG;
+#endif
+	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
+		uc->cmd = UC_SETFLAG;
+	else if	((arg_len = is_keyword(ptr, len, "resetdev")) != 0)
+		uc->cmd = UC_RESETDEV;
+	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
+		uc->cmd = UC_CLEARDEV;
+	else
+		arg_len = 0;
+
+#ifdef DEBUG_PROC_INFO
+printk("sym_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd);
+#endif
+
+	if (!arg_len)
+		return -EINVAL;
+	ptr += arg_len; len -= arg_len;
+
+	switch(uc->cmd) {
+	case UC_SETSYNC:
+	case UC_SETTAGS:
+	case UC_SETWIDE:
+	case UC_SETFLAG:
+	case UC_RESETDEV:
+	case UC_CLEARDEV:
+		SKIP_SPACES(ptr, len);
+		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
+			ptr += arg_len; len -= arg_len;
+			uc->target = ~0;
+		} else {
+			GET_INT_ARG(ptr, len, target);
+			uc->target = (1<<target);
+#ifdef DEBUG_PROC_INFO
+printk("sym_user_command: target=%ld\n", target);
+#endif
+		}
+		break;
+	}
+
+	switch(uc->cmd) {
+	case UC_SETVERBOSE:
+	case UC_SETSYNC:
+	case UC_SETTAGS:
+	case UC_SETWIDE:
+		SKIP_SPACES(ptr, len);
+		GET_INT_ARG(ptr, len, uc->data);
+#ifdef DEBUG_PROC_INFO
+printk("sym_user_command: data=%ld\n", uc->data);
+#endif
+		break;
+#ifdef SYM_LINUX_DEBUG_CONTROL_SUPPORT
+	case UC_SETDEBUG:
+		while (len > 0) {
+			SKIP_SPACES(ptr, len);
+			if	((arg_len = is_keyword(ptr, len, "alloc")))
+				uc->data |= DEBUG_ALLOC;
+			else if	((arg_len = is_keyword(ptr, len, "phase")))
+				uc->data |= DEBUG_PHASE;
+			else if	((arg_len = is_keyword(ptr, len, "queue")))
+				uc->data |= DEBUG_QUEUE;
+			else if	((arg_len = is_keyword(ptr, len, "result")))
+				uc->data |= DEBUG_RESULT;
+			else if	((arg_len = is_keyword(ptr, len, "scatter")))
+				uc->data |= DEBUG_SCATTER;
+			else if	((arg_len = is_keyword(ptr, len, "script")))
+				uc->data |= DEBUG_SCRIPT;
+			else if	((arg_len = is_keyword(ptr, len, "tiny")))
+				uc->data |= DEBUG_TINY;
+			else if	((arg_len = is_keyword(ptr, len, "timing")))
+				uc->data |= DEBUG_TIMING;
+			else if	((arg_len = is_keyword(ptr, len, "nego")))
+				uc->data |= DEBUG_NEGO;
+			else if	((arg_len = is_keyword(ptr, len, "tags")))
+				uc->data |= DEBUG_TAGS;
+			else if	((arg_len = is_keyword(ptr, len, "pointer")))
+				uc->data |= DEBUG_POINTER;
+			else
+				return -EINVAL;
+			ptr += arg_len; len -= arg_len;
+		}
+#ifdef DEBUG_PROC_INFO
+printk("sym_user_command: data=%ld\n", uc->data);
+#endif
+		break;
+#endif /* SYM_LINUX_DEBUG_CONTROL_SUPPORT */
+	case UC_SETFLAG:
+		while (len > 0) {
+			SKIP_SPACES(ptr, len);
+			if	((arg_len = is_keyword(ptr, len, "no_disc")))
+				uc->data &= ~SYM_DISC_ENABLED;
+			else
+				return -EINVAL;
+			ptr += arg_len; len -= arg_len;
+		}
+		break;
+	default:
+		break;
+	}
+
+	if (len)
+		return -EINVAL;
+	else {
+		unsigned long flags;
+
+		spin_lock_irqsave(np->s.host->host_lock, flags);
+		sym_exec_user_command (np, uc);
+		spin_unlock_irqrestore(np->s.host->host_lock, flags);
+	}
+	return length;
+}
+
+#endif	/* SYM_LINUX_USER_COMMAND_SUPPORT */
+
+
+#ifdef SYM_LINUX_USER_INFO_SUPPORT
+/*
+ *  Informations through the proc file system.
+ */
+struct info_str {
+	char *buffer;
+	int length;
+	int offset;
+	int pos;
+};
+
+static void copy_mem_info(struct info_str *info, char *data, int len)
+{
+	if (info->pos + len > info->length)
+		len = info->length - info->pos;
+
+	if (info->pos + len < info->offset) {
+		info->pos += len;
+		return;
+	}
+	if (info->pos < info->offset) {
+		data += (info->offset - info->pos);
+		len  -= (info->offset - info->pos);
+	}
+
+	if (len > 0) {
+		memcpy(info->buffer + info->pos, data, len);
+		info->pos += len;
+	}
+}
+
+static int copy_info(struct info_str *info, char *fmt, ...)
+{
+	va_list args;
+	char buf[81];
+	int len;
+
+	va_start(args, fmt);
+	len = vsprintf(buf, fmt, args);
+	va_end(args);
+
+	copy_mem_info(info, buf, len);
+	return len;
+}
+
+/*
+ *  Copy formatted information into the input buffer.
+ */
+static int sym_host_info(struct sym_hcb *np, char *ptr, off_t offset, int len)
+{
+	struct info_str info;
+
+	info.buffer	= ptr;
+	info.length	= len;
+	info.offset	= offset;
+	info.pos	= 0;
+
+	copy_info(&info, "Chip " NAME53C "%s, device id 0x%x, "
+			 "revision id 0x%x\n",
+			 np->s.chip_name, np->device_id, np->revision_id);
+	copy_info(&info, "At PCI address %s, IRQ " IRQ_FMT "\n",
+		pci_name(np->s.device), IRQ_PRM(np->s.irq));
+	copy_info(&info, "Min. period factor %d, %s SCSI BUS%s\n",
+			 (int) (np->minsync_dt ? np->minsync_dt : np->minsync),
+			 np->maxwide ? "Wide" : "Narrow",
+			 np->minsync_dt ? ", DT capable" : "");
+
+	copy_info(&info, "Max. started commands %d, "
+			 "max. commands per LUN %d\n",
+			 SYM_CONF_MAX_START, SYM_CONF_MAX_TAG);
+
+	return info.pos > info.offset? info.pos - info.offset : 0;
+}
+#endif /* SYM_LINUX_USER_INFO_SUPPORT */
+
+/*
+ *  Entry point of the scsi proc fs of the driver.
+ *  - func = 0 means read  (returns adapter infos)
+ *  - func = 1 means write (not yet merget from sym53c8xx)
+ */
+static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer,
+			char **start, off_t offset, int length, int func)
+{
+	struct sym_hcb *np = sym_get_hcb(host);
+	int retv;
+
+	if (func) {
+#ifdef	SYM_LINUX_USER_COMMAND_SUPPORT
+		retv = sym_user_command(np, buffer, length);
+#else
+		retv = -EINVAL;
+#endif
+	} else {
+		if (start)
+			*start = buffer;
+#ifdef SYM_LINUX_USER_INFO_SUPPORT
+		retv = sym_host_info(np, buffer, offset, length);
+#else
+		retv = -EINVAL;
+#endif
+	}
+
+	return retv;
+}
+#endif /* SYM_LINUX_PROC_INFO_SUPPORT */
+
+/*
+ *	Free controller resources.
+ */
+static void sym_free_resources(struct sym_hcb *np, struct pci_dev *pdev)
+{
+	/*
+	 *  Free O/S specific resources.
+	 */
+	if (np->s.irq)
+		free_irq(np->s.irq, np);
+	if (np->s.ioaddr)
+		pci_iounmap(pdev, np->s.ioaddr);
+	if (np->s.ramaddr)
+		pci_iounmap(pdev, np->s.ramaddr);
+	/*
+	 *  Free O/S independent resources.
+	 */
+	sym_hcb_free(np);
+
+	sym_mfree_dma(np, sizeof(*np), "HCB");
+}
+
+/*
+ *  Ask/tell the system about DMA addressing.
+ */
+static int sym_setup_bus_dma_mask(struct sym_hcb *np)
+{
+#if SYM_CONF_DMA_ADDRESSING_MODE > 0
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 1
+#define	DMA_DAC_MASK	0x000000ffffffffffULL /* 40-bit */
+#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
+#define	DMA_DAC_MASK	DMA_64BIT_MASK
+#endif
+	if ((np->features & FE_DAC) &&
+			!pci_set_dma_mask(np->s.device, DMA_DAC_MASK)) {
+		np->use_dac = 1;
+		return 0;
+	}
+#endif
+
+	if (!pci_set_dma_mask(np->s.device, DMA_32BIT_MASK))
+		return 0;
+
+	printf_warning("%s: No suitable DMA available\n", sym_name(np));
+	return -1;
+}
+
+/*
+ *  Host attach and initialisations.
+ *
+ *  Allocate host data and ncb structure.
+ *  Remap MMIO region.
+ *  Do chip initialization.
+ *  If all is OK, install interrupt handling and
+ *  start the timer daemon.
+ */
+static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
+		int unit, struct sym_device *dev)
+{
+	struct host_data *host_data;
+	struct sym_hcb *np = NULL;
+	struct Scsi_Host *instance = NULL;
+	struct pci_dev *pdev = dev->pdev;
+	unsigned long flags;
+	struct sym_fw *fw;
+
+	printk(KERN_INFO
+		"sym%d: <%s> rev 0x%x at pci %s irq " IRQ_FMT "\n",
+		unit, dev->chip.name, dev->chip.revision_id,
+		pci_name(pdev), IRQ_PRM(pdev->irq));
+
+	/*
+	 *  Get the firmware for this chip.
+	 */
+	fw = sym_find_firmware(&dev->chip);
+	if (!fw)
+		goto attach_failed;
+
+	/*
+	 *	Allocate host_data structure
+	 */
+	instance = scsi_host_alloc(tpnt, sizeof(*host_data));
+	if (!instance)
+		goto attach_failed;
+	host_data = (struct host_data *) instance->hostdata;
+
+	/*
+	 *  Allocate immediately the host control block, 
+	 *  since we are only expecting to succeed. :)
+	 *  We keep track in the HCB of all the resources that 
+	 *  are to be released on error.
+	 */
+	np = __sym_calloc_dma(&pdev->dev, sizeof(*np), "HCB");
+	if (!np)
+		goto attach_failed;
+	np->s.device = pdev;
+	np->bus_dmat = &pdev->dev; /* Result in 1 DMA pool per HBA */
+	host_data->ncb = np;
+	np->s.host = instance;
+
+	pci_set_drvdata(pdev, np);
+
+	/*
+	 *  Copy some useful infos to the HCB.
+	 */
+	np->hcb_ba	= vtobus(np);
+	np->verbose	= sym_driver_setup.verbose;
+	np->s.device	= pdev;
+	np->s.unit	= unit;
+	np->device_id	= dev->chip.device_id;
+	np->revision_id	= dev->chip.revision_id;
+	np->features	= dev->chip.features;
+	np->clock_divn	= dev->chip.nr_divisor;
+	np->maxoffs	= dev->chip.offset_max;
+	np->maxburst	= dev->chip.burst_max;
+	np->myaddr	= dev->host_id;
+
+	/*
+	 *  Edit its name.
+	 */
+	strlcpy(np->s.chip_name, dev->chip.name, sizeof(np->s.chip_name));
+	sprintf(np->s.inst_name, "sym%d", np->s.unit);
+
+	if (sym_setup_bus_dma_mask(np))
+		goto attach_failed;
+
+	/*
+	 *  Try to map the controller chip to
+	 *  virtual and physical memory.
+	 */
+	np->mmio_ba = (u32)dev->mmio_base;
+	np->s.ioaddr	= dev->s.ioaddr;
+	np->s.ramaddr	= dev->s.ramaddr;
+	np->s.io_ws = (np->features & FE_IO256) ? 256 : 128;
+
+	/*
+	 *  Map on-chip RAM if present and supported.
+	 */
+	if (!(np->features & FE_RAM))
+		dev->ram_base = 0;
+	if (dev->ram_base) {
+		np->ram_ba = (u32)dev->ram_base;
+		np->ram_ws = (np->features & FE_RAM8K) ? 8192 : 4096;
+	}
+
+	if (sym_hcb_attach(instance, fw, dev->nvram))
+		goto attach_failed;
+
+	/*
+	 *  Install the interrupt handler.
+	 *  If we synchonize the C code with SCRIPTS on interrupt, 
+	 *  we do not want to share the INTR line at all.
+	 */
+	if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) {
+		printf_err("%s: request irq %d failure\n",
+			sym_name(np), pdev->irq);
+		goto attach_failed;
+	}
+	np->s.irq = pdev->irq;
+
+	/*
+	 *  After SCSI devices have been opened, we cannot
+	 *  reset the bus safely, so we do it here.
+	 */
+	spin_lock_irqsave(instance->host_lock, flags);
+	if (sym_reset_scsi_bus(np, 0))
+		goto reset_failed;
+
+	/*
+	 *  Start the SCRIPTS.
+	 */
+	sym_start_up (np, 1);
+
+	/*
+	 *  Start the timer daemon
+	 */
+	init_timer(&np->s.timer);
+	np->s.timer.data     = (unsigned long) np;
+	np->s.timer.function = sym53c8xx_timer;
+	np->s.lasttime=0;
+	sym_timer (np);
+
+	/*
+	 *  Fill Linux host instance structure
+	 *  and return success.
+	 */
+	instance->max_channel	= 0;
+	instance->this_id	= np->myaddr;
+	instance->max_id	= np->maxwide ? 16 : 8;
+	instance->max_lun	= SYM_CONF_MAX_LUN;
+	instance->unique_id	= pci_resource_start(pdev, 0);
+	instance->cmd_per_lun	= SYM_CONF_MAX_TAG;
+	instance->can_queue	= (SYM_CONF_MAX_START-2);
+	instance->sg_tablesize	= SYM_CONF_MAX_SG;
+	instance->max_cmd_len	= 16;
+	BUG_ON(sym2_transport_template == NULL);
+	instance->transportt	= sym2_transport_template;
+
+	spin_unlock_irqrestore(instance->host_lock, flags);
+
+	return instance;
+
+ reset_failed:
+	printf_err("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, "
+		   "TERMINATION, DEVICE POWER etc.!\n", sym_name(np));
+	spin_unlock_irqrestore(instance->host_lock, flags);
+ attach_failed:
+	if (!instance)
+		return NULL;
+	printf_info("%s: giving up ...\n", sym_name(np));
+	if (np)
+		sym_free_resources(np, pdev);
+	scsi_host_put(instance);
+
+	return NULL;
+ }
+
+
+/*
+ *    Detect and try to read SYMBIOS and TEKRAM NVRAM.
+ */
+#if SYM_CONF_NVRAM_SUPPORT
+static void __devinit sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
+{
+	devp->nvram = nvp;
+	devp->device_id = devp->chip.device_id;
+	nvp->type = 0;
+
+	sym_read_nvram(devp, nvp);
+}
+#else
+static inline void sym_get_nvram(struct sym_device *devp, struct sym_nvram *nvp)
+{
+}
+#endif	/* SYM_CONF_NVRAM_SUPPORT */
+
+static int __devinit sym_check_supported(struct sym_device *device)
+{
+	struct sym_chip *chip;
+	struct pci_dev *pdev = device->pdev;
+	u_char revision;
+	unsigned long io_port = pci_resource_start(pdev, 0);
+	int i;
+
+	/*
+	 *  If user excluded this chip, do not initialize it.
+	 *  I hate this code so much.  Must kill it.
+	 */
+	if (io_port) {
+		for (i = 0 ; i < 8 ; i++) {
+			if (sym_driver_setup.excludes[i] == io_port)
+				return -ENODEV;
+		}
+	}
+
+	/*
+	 * Check if the chip is supported.  Then copy the chip description
+	 * to our device structure so we can make it match the actual device
+	 * and options.
+	 */
+	pci_read_config_byte(pdev, PCI_CLASS_REVISION, &revision);
+	chip = sym_lookup_chip_table(pdev->device, revision);
+	if (!chip) {
+		dev_info(&pdev->dev, "device not supported\n");
+		return -ENODEV;
+	}
+	memcpy(&device->chip, chip, sizeof(device->chip));
+	device->chip.revision_id = revision;
+
+	return 0;
+}
+
+/*
+ * Ignore Symbios chips controlled by various RAID controllers.
+ * These controllers set value 0x52414944 at RAM end - 16.
+ */
+static int __devinit sym_check_raid(struct sym_device *device)
+{
+	unsigned int ram_size, ram_val;
+
+	if (!device->s.ramaddr)
+		return 0;
+
+	if (device->chip.features & FE_RAM8K)
+		ram_size = 8192;
+	else
+		ram_size = 4096;
+
+	ram_val = readl(device->s.ramaddr + ram_size - 16);
+	if (ram_val != 0x52414944)
+		return 0;
+
+	dev_info(&device->pdev->dev,
+			"not initializing, driven by RAID controller.\n");
+	return -ENODEV;
+}
+
+static int __devinit sym_set_workarounds(struct sym_device *device)
+{
+	struct sym_chip *chip = &device->chip;
+	struct pci_dev *pdev = device->pdev;
+	u_short status_reg;
+
+	/*
+	 *  (ITEM 12 of a DEL about the 896 I haven't yet).
+	 *  We must ensure the chip will use WRITE AND INVALIDATE.
+	 *  The revision number limit is for now arbitrary.
+	 */
+	if (pdev->device == PCI_DEVICE_ID_NCR_53C896 && chip->revision_id < 0x4) {
+		chip->features	|= (FE_WRIE | FE_CLSE);
+	}
+
+	/* If the chip can do Memory Write Invalidate, enable it */
+	if (chip->features & FE_WRIE) {
+		if (pci_set_mwi(pdev))
+			return -ENODEV;
+	}
+
+	/*
+	 *  Work around for errant bit in 895A. The 66Mhz
+	 *  capable bit is set erroneously. Clear this bit.
+	 *  (Item 1 DEL 533)
+	 *
+	 *  Make sure Config space and Features agree.
+	 *
+	 *  Recall: writes are not normal to status register -
+	 *  write a 1 to clear and a 0 to leave unchanged.
+	 *  Can only reset bits.
+	 */
+	pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+	if (chip->features & FE_66MHZ) {
+		if (!(status_reg & PCI_STATUS_66MHZ))
+			chip->features &= ~FE_66MHZ;
+	} else {
+		if (status_reg & PCI_STATUS_66MHZ) {
+			status_reg = PCI_STATUS_66MHZ;
+			pci_write_config_word(pdev, PCI_STATUS, status_reg);
+			pci_read_config_word(pdev, PCI_STATUS, &status_reg);
+		}
+	}
+
+	return 0;
+}
+
+/*
+ *  Read and check the PCI configuration for any detected NCR 
+ *  boards and save data for attaching after all boards have 
+ *  been detected.
+ */
+static void __devinit
+sym_init_device(struct pci_dev *pdev, struct sym_device *device)
+{
+	int i;
+
+	device->host_id = SYM_SETUP_HOST_ID;
+	device->pdev = pdev;
+
+	i = pci_get_base_address(pdev, 1, &device->mmio_base);
+	pci_get_base_address(pdev, i, &device->ram_base);
+
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
+	if (device->mmio_base)
+		device->s.ioaddr = pci_iomap(pdev, 1,
+						pci_resource_len(pdev, 1));
+#endif
+	if (!device->s.ioaddr)
+		device->s.ioaddr = pci_iomap(pdev, 0,
+						pci_resource_len(pdev, 0));
+	if (device->ram_base)
+		device->s.ramaddr = pci_iomap(pdev, i,
+						pci_resource_len(pdev, i));
+}
+
+/*
+ * The NCR PQS and PDS cards are constructed as a DEC bridge
+ * behind which sits a proprietary NCR memory controller and
+ * either four or two 53c875s as separate devices.  We can tell
+ * if an 875 is part of a PQS/PDS or not since if it is, it will
+ * be on the same bus as the memory controller.  In its usual
+ * mode of operation, the 875s are slaved to the memory
+ * controller for all transfers.  To operate with the Linux
+ * driver, the memory controller is disabled and the 875s
+ * freed to function independently.  The only wrinkle is that
+ * the preset SCSI ID (which may be zero) must be read in from
+ * a special configuration space register of the 875.
+ */
+static void sym_config_pqs(struct pci_dev *pdev, struct sym_device *sym_dev)
+{
+	int slot;
+	u8 tmp;
+
+	for (slot = 0; slot < 256; slot++) {
+		struct pci_dev *memc = pci_get_slot(pdev->bus, slot);
+
+		if (!memc || memc->vendor != 0x101a || memc->device == 0x0009) {
+			pci_dev_put(memc);
+			continue;
+		}
+
+		/* bit 1: allow individual 875 configuration */
+		pci_read_config_byte(memc, 0x44, &tmp);
+		if ((tmp & 0x2) == 0) {
+			tmp |= 0x2;
+			pci_write_config_byte(memc, 0x44, tmp);
+		}
+
+		/* bit 2: drive individual 875 interrupts to the bus */
+		pci_read_config_byte(memc, 0x45, &tmp);
+		if ((tmp & 0x4) == 0) {
+			tmp |= 0x4;
+			pci_write_config_byte(memc, 0x45, tmp);
+		}
+
+		pci_dev_put(memc);
+		break;
+	}
+
+	pci_read_config_byte(pdev, 0x84, &tmp);
+	sym_dev->host_id = tmp;
+}
+
+/*
+ *  Called before unloading the module.
+ *  Detach the host.
+ *  We have to free resources and halt the NCR chip.
+ */
+static int sym_detach(struct sym_hcb *np, struct pci_dev *pdev)
+{
+	printk("%s: detaching ...\n", sym_name(np));
+
+	del_timer_sync(&np->s.timer);
+
+	/*
+	 * Reset NCR chip.
+	 * We should use sym_soft_reset(), but we don't want to do 
+	 * so, since we may not be safe if interrupts occur.
+	 */
+	printk("%s: resetting chip\n", sym_name(np));
+	OUTB(np, nc_istat, SRST);
+	udelay(10);
+	OUTB(np, nc_istat, 0);
+
+	sym_free_resources(np, pdev);
+
+	return 1;
+}
+
+/*
+ * Driver host template.
+ */
+static struct scsi_host_template sym2_template = {
+	.module			= THIS_MODULE,
+	.name			= "sym53c8xx",
+	.info			= sym53c8xx_info, 
+	.queuecommand		= sym53c8xx_queue_command,
+	.slave_alloc		= sym53c8xx_slave_alloc,
+	.slave_configure	= sym53c8xx_slave_configure,
+	.slave_destroy		= sym53c8xx_slave_destroy,
+	.eh_abort_handler	= sym53c8xx_eh_abort_handler,
+	.eh_device_reset_handler = sym53c8xx_eh_device_reset_handler,
+	.eh_bus_reset_handler	= sym53c8xx_eh_bus_reset_handler,
+	.eh_host_reset_handler	= sym53c8xx_eh_host_reset_handler,
+	.this_id		= 7,
+	.use_clustering		= DISABLE_CLUSTERING,
+#ifdef SYM_LINUX_PROC_INFO_SUPPORT
+	.proc_info		= sym53c8xx_proc_info,
+	.proc_name		= NAME53C8XX,
+#endif
+};
+
+static int attach_count;
+
+static int __devinit sym2_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
+{
+	struct sym_device sym_dev;
+	struct sym_nvram nvram;
+	struct Scsi_Host *instance;
+
+	memset(&sym_dev, 0, sizeof(sym_dev));
+	memset(&nvram, 0, sizeof(nvram));
+
+	if (pci_enable_device(pdev))
+		goto leave;
+
+	pci_set_master(pdev);
+
+	if (pci_request_regions(pdev, NAME53C8XX))
+		goto disable;
+
+	sym_init_device(pdev, &sym_dev);
+	if (sym_check_supported(&sym_dev))
+		goto free;
+
+	if (sym_check_raid(&sym_dev))
+		goto leave;	/* Don't disable the device */
+
+	if (sym_set_workarounds(&sym_dev))
+		goto free;
+
+	sym_config_pqs(pdev, &sym_dev);
+
+	sym_get_nvram(&sym_dev, &nvram);
+
+	instance = sym_attach(&sym2_template, attach_count, &sym_dev);
+	if (!instance)
+		goto free;
+
+	if (scsi_add_host(instance, &pdev->dev))
+		goto detach;
+	scsi_scan_host(instance);
+
+	attach_count++;
+
+	return 0;
+
+ detach:
+	sym_detach(pci_get_drvdata(pdev), pdev);
+ free:
+	pci_release_regions(pdev);
+ disable:
+	pci_disable_device(pdev);
+ leave:
+	return -ENODEV;
+}
+
+static void __devexit sym2_remove(struct pci_dev *pdev)
+{
+	struct sym_hcb *np = pci_get_drvdata(pdev);
+	struct Scsi_Host *host = np->s.host;
+
+	scsi_remove_host(host);
+	scsi_host_put(host);
+
+	sym_detach(np, pdev);
+
+	pci_release_regions(pdev);
+	pci_disable_device(pdev);
+
+	attach_count--;
+}
+
+static void sym2_get_signalling(struct Scsi_Host *shost)
+{
+	struct sym_hcb *np = sym_get_hcb(shost);
+	enum spi_signal_type type;
+
+	switch (np->scsi_mode) {
+	case SMODE_SE:
+		type = SPI_SIGNAL_SE;
+		break;
+	case SMODE_LVD:
+		type = SPI_SIGNAL_LVD;
+		break;
+	case SMODE_HVD:
+		type = SPI_SIGNAL_HVD;
+		break;
+	default:
+		type = SPI_SIGNAL_UNKNOWN;
+		break;
+	}
+	spi_signalling(shost) = type;
+}
+
+static void sym2_set_offset(struct scsi_target *starget, int offset)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	tp->tgoal.offset = offset;
+	tp->tgoal.check_nego = 1;
+}
+
+static void sym2_set_period(struct scsi_target *starget, int period)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	/* have to have DT for these transfers */
+	if (period <= np->minsync)
+		tp->tgoal.dt = 1;
+
+	tp->tgoal.period = period;
+	tp->tgoal.check_nego = 1;
+}
+
+static void sym2_set_width(struct scsi_target *starget, int width)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	/* It is illegal to have DT set on narrow transfers.  If DT is
+	 * clear, we must also clear IU and QAS.  */
+	if (width == 0)
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+
+	tp->tgoal.width = width;
+	tp->tgoal.check_nego = 1;
+}
+
+static void sym2_set_dt(struct scsi_target *starget, int dt)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	/* We must clear QAS and IU if DT is clear */
+	if (dt)
+		tp->tgoal.dt = 1;
+	else
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+	tp->tgoal.check_nego = 1;
+}
+
+static void sym2_set_iu(struct scsi_target *starget, int iu)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	if (iu)
+		tp->tgoal.iu = tp->tgoal.dt = 1;
+	else
+		tp->tgoal.iu = 0;
+	tp->tgoal.check_nego = 1;
+}
+
+static void sym2_set_qas(struct scsi_target *starget, int qas)
+{
+	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
+	struct sym_hcb *np = sym_get_hcb(shost);
+	struct sym_tcb *tp = &np->target[starget->id];
+
+	if (qas)
+		tp->tgoal.dt = tp->tgoal.qas = 1;
+	else
+		tp->tgoal.qas = 0;
+	tp->tgoal.check_nego = 1;
+}
+
+
+static struct spi_function_template sym2_transport_functions = {
+	.set_offset	= sym2_set_offset,
+	.show_offset	= 1,
+	.set_period	= sym2_set_period,
+	.show_period	= 1,
+	.set_width	= sym2_set_width,
+	.show_width	= 1,
+	.set_dt		= sym2_set_dt,
+	.show_dt	= 1,
+	.set_iu		= sym2_set_iu,
+	.show_iu	= 1,
+	.set_qas	= sym2_set_qas,
+	.show_qas	= 1,
+	.get_signalling	= sym2_get_signalling,
+};
+
+static struct pci_device_id sym2_id_table[] __devinitdata = {
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C810,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C820,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C825,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C815,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C810AP,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C860,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1510,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C896,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C895,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C885,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C1510,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, /* new */
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C895A,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C875A,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_33,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_LSI_53C1010_66,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_LSI_LOGIC, PCI_DEVICE_ID_NCR_53C875J,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, sym2_id_table);
+
+static struct pci_driver sym2_driver = {
+	.name		= NAME53C8XX,
+	.id_table	= sym2_id_table,
+	.probe		= sym2_probe,
+	.remove		= __devexit_p(sym2_remove),
+};
+
+static int __init sym2_init(void)
+{
+	int error;
+
+	sym2_setup_params();
+	sym2_transport_template = spi_attach_transport(&sym2_transport_functions);
+	if (!sym2_transport_template)
+		return -ENODEV;
+
+	error = pci_register_driver(&sym2_driver);
+	if (error)
+		spi_release_transport(sym2_transport_template);
+	return error;
+}
+
+static void __exit sym2_exit(void)
+{
+	pci_unregister_driver(&sym2_driver);
+	spi_release_transport(sym2_transport_template);
+}
+
+module_init(sym2_init);
+module_exit(sym2_exit);
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h
new file mode 100644
index 0000000..e943f16
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.h
@@ -0,0 +1,300 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM_GLUE_H
+#define SYM_GLUE_H
+
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/types.h>
+
+#include <asm/io.h>
+#ifdef __sparc__
+#  include <asm/irq.h>
+#endif
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_host.h>
+
+#include "sym53c8xx.h"
+#include "sym_defs.h"
+#include "sym_misc.h"
+
+/*
+ * Configuration addendum for Linux.
+ */
+#define	SYM_CONF_TIMER_INTERVAL		((HZ+1)/2)
+
+#define SYM_OPT_HANDLE_DIR_UNKNOWN
+#define SYM_OPT_HANDLE_DEVICE_QUEUEING
+#define SYM_OPT_LIMIT_COMMAND_REORDERING
+
+/*
+ *  Print a message with severity.
+ */
+#define printf_emerg(args...)	printk(KERN_EMERG args)
+#define	printf_alert(args...)	printk(KERN_ALERT args)
+#define	printf_crit(args...)	printk(KERN_CRIT args)
+#define	printf_err(args...)	printk(KERN_ERR	args)
+#define	printf_warning(args...)	printk(KERN_WARNING args)
+#define	printf_notice(args...)	printk(KERN_NOTICE args)
+#define	printf_info(args...)	printk(KERN_INFO args)
+#define	printf_debug(args...)	printk(KERN_DEBUG args)
+#define	printf(args...)		printk(args)
+
+/*
+ *  A 'read barrier' flushes any data that have been prefetched 
+ *  by the processor due to out of order execution. Such a barrier 
+ *  must notably be inserted prior to looking at data that have 
+ *  been DMAed, assuming that program does memory READs in proper 
+ *  order and that the device ensured proper ordering of WRITEs.
+ *
+ *  A 'write barrier' prevents any previous WRITEs to pass further 
+ *  WRITEs. Such barriers must be inserted each time another agent 
+ *  relies on ordering of WRITEs.
+ *
+ *  Note that, due to posting of PCI memory writes, we also must 
+ *  insert dummy PCI read transactions when some ordering involving 
+ *  both directions over the PCI does matter. PCI transactions are 
+ *  fully ordered in each direction.
+ */
+
+#define MEMORY_READ_BARRIER()	rmb()
+#define MEMORY_WRITE_BARRIER()	wmb()
+
+/*
+ *  IO functions definition for big/little endian CPU support.
+ *  For now, PCI chips are only supported in little endian addressing mode, 
+ */
+
+#ifdef	__BIG_ENDIAN
+
+#define	readw_l2b	readw
+#define	readl_l2b	readl
+#define	writew_b2l	writew
+#define	writel_b2l	writel
+
+#else	/* little endian */
+
+#define	readw_raw	readw
+#define	readl_raw	readl
+#define	writew_raw	writew
+#define	writel_raw	writel
+
+#endif /* endian */
+
+#ifdef	SYM_CONF_CHIP_BIG_ENDIAN
+#error	"Chips in BIG ENDIAN addressing mode are not (yet) supported"
+#endif
+
+/*
+ *  If the CPU and the chip use same endian-ness addressing,
+ *  no byte reordering is needed for script patching.
+ *  Macro cpu_to_scr() is to be used for script patching.
+ *  Macro scr_to_cpu() is to be used for getting a DWORD 
+ *  from the script.
+ */
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+/*
+ *  Remap some status field values.
+ */
+#define CAM_REQ_CMP		DID_OK
+#define CAM_SEL_TIMEOUT		DID_NO_CONNECT
+#define CAM_CMD_TIMEOUT		DID_TIME_OUT
+#define CAM_REQ_ABORTED		DID_ABORT
+#define CAM_UNCOR_PARITY	DID_PARITY
+#define CAM_SCSI_BUS_RESET	DID_RESET	
+#define CAM_REQUEUE_REQ		DID_SOFT_ERROR
+#define	CAM_UNEXP_BUSFREE	DID_ERROR
+#define	CAM_SCSI_BUSY		DID_BUS_BUSY
+
+#define	CAM_DEV_NOT_THERE	DID_NO_CONNECT
+#define	CAM_REQ_INVALID		DID_ERROR
+#define	CAM_REQ_TOO_BIG		DID_ERROR
+
+#define	CAM_RESRC_UNAVAIL	DID_ERROR
+
+/*
+ *  Remap data direction values.
+ */
+#define CAM_DIR_NONE		DMA_NONE
+#define CAM_DIR_IN		DMA_FROM_DEVICE
+#define CAM_DIR_OUT		DMA_TO_DEVICE
+#define CAM_DIR_UNKNOWN		DMA_BIDIRECTIONAL
+
+/*
+ *  These ones are used as return code from 
+ *  error recovery handlers under Linux.
+ */
+#define SCSI_SUCCESS	SUCCESS
+#define SCSI_FAILED	FAILED
+
+/*
+ *  System specific target data structure.
+ *  None for now, under Linux.
+ */
+/* #define SYM_HAVE_STCB */
+
+/*
+ *  System specific lun data structure.
+ */
+#define SYM_HAVE_SLCB
+struct sym_slcb {
+	u_short	reqtags;	/* Number of tags requested by user */
+	u_short scdev_depth;	/* Queue depth set in select_queue_depth() */
+};
+
+/*
+ *  System specific command data structure.
+ *  Not needed under Linux.
+ */
+/* struct sym_sccb */
+
+/*
+ *  System specific host data structure.
+ */
+struct sym_shcb {
+	/*
+	 *  Chip and controller indentification.
+	 */
+	int		unit;
+	char		inst_name[16];
+	char		chip_name[8];
+	struct pci_dev	*device;
+
+	struct Scsi_Host *host;
+
+	void __iomem *	ioaddr;		/* MMIO kernel io address	*/
+	void __iomem *	ramaddr;	/* RAM  kernel io address	*/
+	u_short		io_ws;		/* IO window size		*/
+	int		irq;		/* IRQ number			*/
+
+	struct timer_list timer;	/* Timer handler link header	*/
+	u_long		lasttime;
+	u_long		settle_time;	/* Resetting the SCSI BUS	*/
+	u_char		settle_time_valid;
+};
+
+/*
+ *  Return the name of the controller.
+ */
+#define sym_name(np) (np)->s.inst_name
+
+struct sym_nvram;
+
+/*
+ * The IO macros require a struct called 's' and are abused in sym_nvram.c
+ */
+struct sym_device {
+	struct pci_dev *pdev;
+	unsigned long mmio_base;
+	unsigned long ram_base;
+	struct {
+		void __iomem *ioaddr;
+		void __iomem *ramaddr;
+	} s;
+	struct sym_chip chip;
+	struct sym_nvram *nvram;
+	u_short device_id;
+	u_char host_id;
+};
+
+/*
+ *  Driver host data structure.
+ */
+struct host_data {
+	struct sym_hcb *ncb;
+};
+
+static inline struct sym_hcb * sym_get_hcb(struct Scsi_Host *host)
+{
+	return ((struct host_data *)host->hostdata)->ncb;
+}
+
+#include "sym_fw.h"
+#include "sym_hipd.h"
+
+/*
+ *  Set the status field of a CAM CCB.
+ */
+static __inline void 
+sym_set_cam_status(struct scsi_cmnd *cmd, int status)
+{
+	cmd->result &= ~(0xff  << 16);
+	cmd->result |= (status << 16);
+}
+
+/*
+ *  Get the status field of a CAM CCB.
+ */
+static __inline int 
+sym_get_cam_status(struct scsi_cmnd *cmd)
+{
+	return host_byte(cmd->result);
+}
+
+/*
+ *  Build CAM result for a successful IO and for a failed IO.
+ */
+static __inline void sym_set_cam_result_ok(struct sym_ccb *cp, struct scsi_cmnd *cmd, int resid)
+{
+	cmd->resid = resid;
+	cmd->result = (((DID_OK) << 16) + ((cp->ssss_status) & 0x7f));
+}
+void sym_set_cam_result_error(struct sym_hcb *np, struct sym_ccb *cp, int resid);
+
+void sym_xpt_done(struct sym_hcb *np, struct scsi_cmnd *ccb);
+#define sym_print_addr(cmd, arg...) dev_info(&cmd->device->sdev_gendev , ## arg)
+void sym_xpt_async_bus_reset(struct sym_hcb *np);
+void sym_xpt_async_sent_bdr(struct sym_hcb *np, int target);
+int  sym_setup_data_and_start (struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
+void sym_log_bus_error(struct sym_hcb *np);
+void sym_sniff_inquiry(struct sym_hcb *np, struct scsi_cmnd *cmd, int resid);
+
+#endif /* SYM_GLUE_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c
new file mode 100644
index 0000000..50a176b
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c
@@ -0,0 +1,5865 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ * Copyright (c) 2003-2005  Matthew Wilcox <matthew@wil.cx>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#include "sym_glue.h"
+#include "sym_nvram.h"
+
+#if 0
+#define SYM_DEBUG_GENERIC_SUPPORT
+#endif
+
+/*
+ *  Needed function prototypes.
+ */
+static void sym_int_ma (struct sym_hcb *np);
+static void sym_int_sir (struct sym_hcb *np);
+static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np);
+static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa);
+static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln);
+static void sym_complete_error (struct sym_hcb *np, struct sym_ccb *cp);
+static void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp);
+static int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp);
+
+/*
+ *  Print a buffer in hexadecimal format with a ".\n" at end.
+ */
+static void sym_printl_hex(u_char *p, int n)
+{
+	while (n-- > 0)
+		printf (" %x", *p++);
+	printf (".\n");
+}
+
+/*
+ *  Print out the content of a SCSI message.
+ */
+static int sym_show_msg (u_char * msg)
+{
+	u_char i;
+	printf ("%x",*msg);
+	if (*msg==M_EXTENDED) {
+		for (i=1;i<8;i++) {
+			if (i-1>msg[1]) break;
+			printf ("-%x",msg[i]);
+		}
+		return (i+1);
+	} else if ((*msg & 0xf0) == 0x20) {
+		printf ("-%x",msg[1]);
+		return (2);
+	}
+	return (1);
+}
+
+static void sym_print_msg(struct sym_ccb *cp, char *label, u_char *msg)
+{
+	sym_print_addr(cp->cmd, "%s: ", label);
+
+	sym_show_msg(msg);
+	printf(".\n");
+}
+
+static void sym_print_nego_msg(struct sym_hcb *np, int target, char *label, u_char *msg)
+{
+	struct sym_tcb *tp = &np->target[target];
+	dev_info(&tp->sdev->sdev_target->dev, "%s: ", label);
+
+	sym_show_msg(msg);
+	printf(".\n");
+}
+
+/*
+ *  Print something that tells about extended errors.
+ */
+void sym_print_xerr(struct scsi_cmnd *cmd, int x_status)
+{
+	if (x_status & XE_PARITY_ERR) {
+		sym_print_addr(cmd, "unrecovered SCSI parity error.\n");
+	}
+	if (x_status & XE_EXTRA_DATA) {
+		sym_print_addr(cmd, "extraneous data discarded.\n");
+	}
+	if (x_status & XE_BAD_PHASE) {
+		sym_print_addr(cmd, "illegal scsi phase (4/5).\n");
+	}
+	if (x_status & XE_SODL_UNRUN) {
+		sym_print_addr(cmd, "ODD transfer in DATA OUT phase.\n");
+	}
+	if (x_status & XE_SWIDE_OVRUN) {
+		sym_print_addr(cmd, "ODD transfer in DATA IN phase.\n");
+	}
+}
+
+/*
+ *  Return a string for SCSI BUS mode.
+ */
+static char *sym_scsi_bus_mode(int mode)
+{
+	switch(mode) {
+	case SMODE_HVD:	return "HVD";
+	case SMODE_SE:	return "SE";
+	case SMODE_LVD: return "LVD";
+	}
+	return "??";
+}
+
+/*
+ *  Soft reset the chip.
+ *
+ *  Raising SRST when the chip is running may cause 
+ *  problems on dual function chips (see below).
+ *  On the other hand, LVD devices need some delay 
+ *  to settle and report actual BUS mode in STEST4.
+ */
+static void sym_chip_reset (struct sym_hcb *np)
+{
+	OUTB(np, nc_istat, SRST);
+	udelay(10);
+	OUTB(np, nc_istat, 0);
+	udelay(2000);	/* For BUS MODE to settle */
+}
+
+/*
+ *  Really soft reset the chip.:)
+ *
+ *  Some 896 and 876 chip revisions may hang-up if we set 
+ *  the SRST (soft reset) bit at the wrong time when SCRIPTS 
+ *  are running.
+ *  So, we need to abort the current operation prior to 
+ *  soft resetting the chip.
+ */
+static void sym_soft_reset (struct sym_hcb *np)
+{
+	u_char istat = 0;
+	int i;
+
+	if (!(np->features & FE_ISTAT1) || !(INB(np, nc_istat1) & SCRUN))
+		goto do_chip_reset;
+
+	OUTB(np, nc_istat, CABRT);
+	for (i = 100000 ; i ; --i) {
+		istat = INB(np, nc_istat);
+		if (istat & SIP) {
+			INW(np, nc_sist);
+		}
+		else if (istat & DIP) {
+			if (INB(np, nc_dstat) & ABRT)
+				break;
+		}
+		udelay(5);
+	}
+	OUTB(np, nc_istat, 0);
+	if (!i)
+		printf("%s: unable to abort current chip operation, "
+		       "ISTAT=0x%02x.\n", sym_name(np), istat);
+do_chip_reset:
+	sym_chip_reset(np);
+}
+
+/*
+ *  Start reset process.
+ *
+ *  The interrupt handler will reinitialize the chip.
+ */
+static void sym_start_reset(struct sym_hcb *np)
+{
+	sym_reset_scsi_bus(np, 1);
+}
+ 
+int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int)
+{
+	u32 term;
+	int retv = 0;
+
+	sym_soft_reset(np);	/* Soft reset the chip */
+	if (enab_int)
+		OUTW(np, nc_sien, RST);
+	/*
+	 *  Enable Tolerant, reset IRQD if present and 
+	 *  properly set IRQ mode, prior to resetting the bus.
+	 */
+	OUTB(np, nc_stest3, TE);
+	OUTB(np, nc_dcntl, (np->rv_dcntl & IRQM));
+	OUTB(np, nc_scntl1, CRST);
+	udelay(200);
+
+	if (!SYM_SETUP_SCSI_BUS_CHECK)
+		goto out;
+	/*
+	 *  Check for no terminators or SCSI bus shorts to ground.
+	 *  Read SCSI data bus, data parity bits and control signals.
+	 *  We are expecting RESET to be TRUE and other signals to be 
+	 *  FALSE.
+	 */
+	term =	INB(np, nc_sstat0);
+	term =	((term & 2) << 7) + ((term & 1) << 17);	/* rst sdp0 */
+	term |= ((INB(np, nc_sstat2) & 0x01) << 26) |	/* sdp1     */
+		((INW(np, nc_sbdl) & 0xff)   << 9)  |	/* d7-0     */
+		((INW(np, nc_sbdl) & 0xff00) << 10) |	/* d15-8    */
+		INB(np, nc_sbcl);	/* req ack bsy sel atn msg cd io    */
+
+	if (!np->maxwide)
+		term &= 0x3ffff;
+
+	if (term != (2<<7)) {
+		printf("%s: suspicious SCSI data while resetting the BUS.\n",
+			sym_name(np));
+		printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+			"0x%lx, expecting 0x%lx\n",
+			sym_name(np),
+			(np->features & FE_WIDE) ? "dp1,d15-8," : "",
+			(u_long)term, (u_long)(2<<7));
+		if (SYM_SETUP_SCSI_BUS_CHECK == 1)
+			retv = 1;
+	}
+out:
+	OUTB(np, nc_scntl1, 0);
+	return retv;
+}
+
+/*
+ *  Select SCSI clock frequency
+ */
+static void sym_selectclock(struct sym_hcb *np, u_char scntl3)
+{
+	/*
+	 *  If multiplier not present or not selected, leave here.
+	 */
+	if (np->multiplier <= 1) {
+		OUTB(np, nc_scntl3, scntl3);
+		return;
+	}
+
+	if (sym_verbose >= 2)
+		printf ("%s: enabling clock multiplier\n", sym_name(np));
+
+	OUTB(np, nc_stest1, DBLEN);	   /* Enable clock multiplier */
+	/*
+	 *  Wait for the LCKFRQ bit to be set if supported by the chip.
+	 *  Otherwise wait 50 micro-seconds (at least).
+	 */
+	if (np->features & FE_LCKFRQ) {
+		int i = 20;
+		while (!(INB(np, nc_stest4) & LCKFRQ) && --i > 0)
+			udelay(20);
+		if (!i)
+			printf("%s: the chip cannot lock the frequency\n",
+				sym_name(np));
+	} else
+		udelay((50+10));
+	OUTB(np, nc_stest3, HSC);		/* Halt the scsi clock	*/
+	OUTB(np, nc_scntl3, scntl3);
+	OUTB(np, nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
+	OUTB(np, nc_stest3, 0x00);		/* Restart scsi clock 	*/
+}
+
+
+/*
+ *  Determine the chip's clock frequency.
+ *
+ *  This is essential for the negotiation of the synchronous 
+ *  transfer rate.
+ *
+ *  Note: we have to return the correct value.
+ *  THERE IS NO SAFE DEFAULT VALUE.
+ *
+ *  Most NCR/SYMBIOS boards are delivered with a 40 Mhz clock.
+ *  53C860 and 53C875 rev. 1 support fast20 transfers but 
+ *  do not have a clock doubler and so are provided with a 
+ *  80 MHz clock. All other fast20 boards incorporate a doubler 
+ *  and so should be delivered with a 40 MHz clock.
+ *  The recent fast40 chips (895/896/895A/1010) use a 40 Mhz base 
+ *  clock and provide a clock quadrupler (160 Mhz).
+ */
+
+/*
+ *  calculate SCSI clock frequency (in KHz)
+ */
+static unsigned getfreq (struct sym_hcb *np, int gen)
+{
+	unsigned int ms = 0;
+	unsigned int f;
+
+	/*
+	 * Measure GEN timer delay in order 
+	 * to calculate SCSI clock frequency
+	 *
+	 * This code will never execute too
+	 * many loop iterations (if DELAY is 
+	 * reasonably correct). It could get
+	 * too low a delay (too high a freq.)
+	 * if the CPU is slow executing the 
+	 * loop for some reason (an NMI, for
+	 * example). For this reason we will
+	 * if multiple measurements are to be 
+	 * performed trust the higher delay 
+	 * (lower frequency returned).
+	 */
+	OUTW(np, nc_sien, 0);	/* mask all scsi interrupts */
+	INW(np, nc_sist);	/* clear pending scsi interrupt */
+	OUTB(np, nc_dien, 0);	/* mask all dma interrupts */
+	INW(np, nc_sist);	/* another one, just to be sure :) */
+	/*
+	 * The C1010-33 core does not report GEN in SIST,
+	 * if this interrupt is masked in SIEN.
+	 * I don't know yet if the C1010-66 behaves the same way.
+	 */
+	if (np->features & FE_C10) {
+		OUTW(np, nc_sien, GEN);
+		OUTB(np, nc_istat1, SIRQD);
+	}
+	OUTB(np, nc_scntl3, 4);	   /* set pre-scaler to divide by 3 */
+	OUTB(np, nc_stime1, 0);	   /* disable general purpose timer */
+	OUTB(np, nc_stime1, gen);  /* set to nominal delay of 1<<gen * 125us */
+	while (!(INW(np, nc_sist) & GEN) && ms++ < 100000)
+		udelay(1000/4);    /* count in 1/4 of ms */
+	OUTB(np, nc_stime1, 0);    /* disable general purpose timer */
+	/*
+	 * Undo C1010-33 specific settings.
+	 */
+	if (np->features & FE_C10) {
+		OUTW(np, nc_sien, 0);
+		OUTB(np, nc_istat1, 0);
+	}
+ 	/*
+ 	 * set prescaler to divide by whatever 0 means
+ 	 * 0 ought to choose divide by 2, but appears
+ 	 * to set divide by 3.5 mode in my 53c810 ...
+ 	 */
+ 	OUTB(np, nc_scntl3, 0);
+
+  	/*
+ 	 * adjust for prescaler, and convert into KHz 
+  	 */
+	f = ms ? ((1 << gen) * (4340*4)) / ms : 0;
+
+	/*
+	 * The C1010-33 result is biased by a factor 
+	 * of 2/3 compared to earlier chips.
+	 */
+	if (np->features & FE_C10)
+		f = (f * 2) / 3;
+
+	if (sym_verbose >= 2)
+		printf ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
+			sym_name(np), gen, ms/4, f);
+
+	return f;
+}
+
+static unsigned sym_getfreq (struct sym_hcb *np)
+{
+	u_int f1, f2;
+	int gen = 8;
+
+	getfreq (np, gen);	/* throw away first result */
+	f1 = getfreq (np, gen);
+	f2 = getfreq (np, gen);
+	if (f1 > f2) f1 = f2;		/* trust lower result	*/
+	return f1;
+}
+
+/*
+ *  Get/probe chip SCSI clock frequency
+ */
+static void sym_getclock (struct sym_hcb *np, int mult)
+{
+	unsigned char scntl3 = np->sv_scntl3;
+	unsigned char stest1 = np->sv_stest1;
+	unsigned f1;
+
+	np->multiplier = 1;
+	f1 = 40000;
+	/*
+	 *  True with 875/895/896/895A with clock multiplier selected
+	 */
+	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
+		if (sym_verbose >= 2)
+			printf ("%s: clock multiplier found\n", sym_name(np));
+		np->multiplier = mult;
+	}
+
+	/*
+	 *  If multiplier not found or scntl3 not 7,5,3,
+	 *  reset chip and get frequency from general purpose timer.
+	 *  Otherwise trust scntl3 BIOS setting.
+	 */
+	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+		OUTB(np, nc_stest1, 0);		/* make sure doubler is OFF */
+		f1 = sym_getfreq (np);
+
+		if (sym_verbose)
+			printf ("%s: chip clock is %uKHz\n", sym_name(np), f1);
+
+		if	(f1 <	45000)		f1 =  40000;
+		else if (f1 <	55000)		f1 =  50000;
+		else				f1 =  80000;
+
+		if (f1 < 80000 && mult > 1) {
+			if (sym_verbose >= 2)
+				printf ("%s: clock multiplier assumed\n",
+					sym_name(np));
+			np->multiplier	= mult;
+		}
+	} else {
+		if	((scntl3 & 7) == 3)	f1 =  40000;
+		else if	((scntl3 & 7) == 5)	f1 =  80000;
+		else 				f1 = 160000;
+
+		f1 /= np->multiplier;
+	}
+
+	/*
+	 *  Compute controller synchronous parameters.
+	 */
+	f1		*= np->multiplier;
+	np->clock_khz	= f1;
+}
+
+/*
+ *  Get/probe PCI clock frequency
+ */
+static int sym_getpciclock (struct sym_hcb *np)
+{
+	int f = 0;
+
+	/*
+	 *  For now, we only need to know about the actual 
+	 *  PCI BUS clock frequency for C1010-66 chips.
+	 */
+#if 1
+	if (np->features & FE_66MHZ) {
+#else
+	if (1) {
+#endif
+		OUTB(np, nc_stest1, SCLK); /* Use the PCI clock as SCSI clock */
+		f = sym_getfreq(np);
+		OUTB(np, nc_stest1, 0);
+	}
+	np->pciclk_khz = f;
+
+	return f;
+}
+
+/*
+ *  SYMBIOS chip clock divisor table.
+ *
+ *  Divisors are multiplied by 10,000,000 in order to make 
+ *  calculations more simple.
+ */
+#define _5M 5000000
+static u32 div_10M[] = {2*_5M, 3*_5M, 4*_5M, 6*_5M, 8*_5M, 12*_5M, 16*_5M};
+
+/*
+ *  Get clock factor and sync divisor for a given 
+ *  synchronous factor period.
+ */
+static int 
+sym_getsync(struct sym_hcb *np, u_char dt, u_char sfac, u_char *divp, u_char *fakp)
+{
+	u32	clk = np->clock_khz;	/* SCSI clock frequency in kHz	*/
+	int	div = np->clock_divn;	/* Number of divisors supported	*/
+	u32	fak;			/* Sync factor in sxfer		*/
+	u32	per;			/* Period in tenths of ns	*/
+	u32	kpc;			/* (per * clk)			*/
+	int	ret;
+
+	/*
+	 *  Compute the synchronous period in tenths of nano-seconds
+	 */
+	if (dt && sfac <= 9)	per = 125;
+	else if	(sfac <= 10)	per = 250;
+	else if	(sfac == 11)	per = 303;
+	else if	(sfac == 12)	per = 500;
+	else			per = 40 * sfac;
+	ret = per;
+
+	kpc = per * clk;
+	if (dt)
+		kpc <<= 1;
+
+	/*
+	 *  For earliest C10 revision 0, we cannot use extra 
+	 *  clocks for the setting of the SCSI clocking.
+	 *  Note that this limits the lowest sync data transfer 
+	 *  to 5 Mega-transfers per second and may result in
+	 *  using higher clock divisors.
+	 */
+#if 1
+	if ((np->features & (FE_C10|FE_U3EN)) == FE_C10) {
+		/*
+		 *  Look for the lowest clock divisor that allows an 
+		 *  output speed not faster than the period.
+		 */
+		while (div > 0) {
+			--div;
+			if (kpc > (div_10M[div] << 2)) {
+				++div;
+				break;
+			}
+		}
+		fak = 0;			/* No extra clocks */
+		if (div == np->clock_divn) {	/* Are we too fast ? */
+			ret = -1;
+		}
+		*divp = div;
+		*fakp = fak;
+		return ret;
+	}
+#endif
+
+	/*
+	 *  Look for the greatest clock divisor that allows an 
+	 *  input speed faster than the period.
+	 */
+	while (div-- > 0)
+		if (kpc >= (div_10M[div] << 2)) break;
+
+	/*
+	 *  Calculate the lowest clock factor that allows an output 
+	 *  speed not faster than the period, and the max output speed.
+	 *  If fak >= 1 we will set both XCLKH_ST and XCLKH_DT.
+	 *  If fak >= 2 we will also set XCLKS_ST and XCLKS_DT.
+	 */
+	if (dt) {
+		fak = (kpc - 1) / (div_10M[div] << 1) + 1 - 2;
+		/* ret = ((2+fak)*div_10M[div])/np->clock_khz; */
+	} else {
+		fak = (kpc - 1) / div_10M[div] + 1 - 4;
+		/* ret = ((4+fak)*div_10M[div])/np->clock_khz; */
+	}
+
+	/*
+	 *  Check against our hardware limits, or bugs :).
+	 */
+	if (fak > 2) {
+		fak = 2;
+		ret = -1;
+	}
+
+	/*
+	 *  Compute and return sync parameters.
+	 */
+	*divp = div;
+	*fakp = fak;
+
+	return ret;
+}
+
+/*
+ *  SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
+ *  128 transfers. All chips support at least 16 transfers 
+ *  bursts. The 825A, 875 and 895 chips support bursts of up 
+ *  to 128 transfers and the 895A and 896 support bursts of up
+ *  to 64 transfers. All other chips support up to 16 
+ *  transfers bursts.
+ *
+ *  For PCI 32 bit data transfers each transfer is a DWORD.
+ *  It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
+ *
+ *  We use log base 2 (burst length) as internal code, with 
+ *  value 0 meaning "burst disabled".
+ */
+
+/*
+ *  Burst length from burst code.
+ */
+#define burst_length(bc) (!(bc))? 0 : 1 << (bc)
+
+/*
+ *  Burst code from io register bits.
+ */
+#define burst_code(dmode, ctest4, ctest5) \
+	(ctest4) & 0x80? 0 : (((dmode) & 0xc0) >> 6) + ((ctest5) & 0x04) + 1
+
+/*
+ *  Set initial io register bits from burst code.
+ */
+static __inline void sym_init_burst(struct sym_hcb *np, u_char bc)
+{
+	np->rv_ctest4	&= ~0x80;
+	np->rv_dmode	&= ~(0x3 << 6);
+	np->rv_ctest5	&= ~0x4;
+
+	if (!bc) {
+		np->rv_ctest4	|= 0x80;
+	}
+	else {
+		--bc;
+		np->rv_dmode	|= ((bc & 0x3) << 6);
+		np->rv_ctest5	|= (bc & 0x4);
+	}
+}
+
+
+/*
+ * Print out the list of targets that have some flag disabled by user.
+ */
+static void sym_print_targets_flag(struct sym_hcb *np, int mask, char *msg)
+{
+	int cnt;
+	int i;
+
+	for (cnt = 0, i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
+		if (i == np->myaddr)
+			continue;
+		if (np->target[i].usrflags & mask) {
+			if (!cnt++)
+				printf("%s: %s disabled for targets",
+					sym_name(np), msg);
+			printf(" %d", i);
+		}
+	}
+	if (cnt)
+		printf(".\n");
+}
+
+/*
+ *  Save initial settings of some IO registers.
+ *  Assumed to have been set by BIOS.
+ *  We cannot reset the chip prior to reading the 
+ *  IO registers, since informations will be lost.
+ *  Since the SCRIPTS processor may be running, this 
+ *  is not safe on paper, but it seems to work quite 
+ *  well. :)
+ */
+static void sym_save_initial_setting (struct sym_hcb *np)
+{
+	np->sv_scntl0	= INB(np, nc_scntl0) & 0x0a;
+	np->sv_scntl3	= INB(np, nc_scntl3) & 0x07;
+	np->sv_dmode	= INB(np, nc_dmode)  & 0xce;
+	np->sv_dcntl	= INB(np, nc_dcntl)  & 0xa8;
+	np->sv_ctest3	= INB(np, nc_ctest3) & 0x01;
+	np->sv_ctest4	= INB(np, nc_ctest4) & 0x80;
+	np->sv_gpcntl	= INB(np, nc_gpcntl);
+	np->sv_stest1	= INB(np, nc_stest1);
+	np->sv_stest2	= INB(np, nc_stest2) & 0x20;
+	np->sv_stest4	= INB(np, nc_stest4);
+	if (np->features & FE_C10) {	/* Always large DMA fifo + ultra3 */
+		np->sv_scntl4	= INB(np, nc_scntl4);
+		np->sv_ctest5	= INB(np, nc_ctest5) & 0x04;
+	}
+	else
+		np->sv_ctest5	= INB(np, nc_ctest5) & 0x24;
+}
+
+/*
+ *  Prepare io register values used by sym_start_up() 
+ *  according to selected and supported features.
+ */
+static int sym_prepare_setting(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
+{
+	u_char	burst_max;
+	u32	period;
+	int i;
+
+	/*
+	 *  Wide ?
+	 */
+	np->maxwide	= (np->features & FE_WIDE)? 1 : 0;
+
+	/*
+	 *  Guess the frequency of the chip's clock.
+	 */
+	if	(np->features & (FE_ULTRA3 | FE_ULTRA2))
+		np->clock_khz = 160000;
+	else if	(np->features & FE_ULTRA)
+		np->clock_khz = 80000;
+	else
+		np->clock_khz = 40000;
+
+	/*
+	 *  Get the clock multiplier factor.
+ 	 */
+	if	(np->features & FE_QUAD)
+		np->multiplier	= 4;
+	else if	(np->features & FE_DBLR)
+		np->multiplier	= 2;
+	else
+		np->multiplier	= 1;
+
+	/*
+	 *  Measure SCSI clock frequency for chips 
+	 *  it may vary from assumed one.
+	 */
+	if (np->features & FE_VARCLK)
+		sym_getclock(np, np->multiplier);
+
+	/*
+	 * Divisor to be used for async (timer pre-scaler).
+	 */
+	i = np->clock_divn - 1;
+	while (--i >= 0) {
+		if (10ul * SYM_CONF_MIN_ASYNC * np->clock_khz > div_10M[i]) {
+			++i;
+			break;
+		}
+	}
+	np->rv_scntl3 = i+1;
+
+	/*
+	 * The C1010 uses hardwired divisors for async.
+	 * So, we just throw away, the async. divisor.:-)
+	 */
+	if (np->features & FE_C10)
+		np->rv_scntl3 = 0;
+
+	/*
+	 * Minimum synchronous period factor supported by the chip.
+	 * Btw, 'period' is in tenths of nanoseconds.
+	 */
+	period = (4 * div_10M[0] + np->clock_khz - 1) / np->clock_khz;
+
+	if	(period <= 250)		np->minsync = 10;
+	else if	(period <= 303)		np->minsync = 11;
+	else if	(period <= 500)		np->minsync = 12;
+	else				np->minsync = (period + 40 - 1) / 40;
+
+	/*
+	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+	 */
+	if	(np->minsync < 25 &&
+		 !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3)))
+		np->minsync = 25;
+	else if	(np->minsync < 12 &&
+		 !(np->features & (FE_ULTRA2|FE_ULTRA3)))
+		np->minsync = 12;
+
+	/*
+	 * Maximum synchronous period factor supported by the chip.
+	 */
+	period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
+	np->maxsync = period > 2540 ? 254 : period / 10;
+
+	/*
+	 * If chip is a C1010, guess the sync limits in DT mode.
+	 */
+	if ((np->features & (FE_C10|FE_ULTRA3)) == (FE_C10|FE_ULTRA3)) {
+		if (np->clock_khz == 160000) {
+			np->minsync_dt = 9;
+			np->maxsync_dt = 50;
+			np->maxoffs_dt = nvram->type ? 62 : 31;
+		}
+	}
+	
+	/*
+	 *  64 bit addressing  (895A/896/1010) ?
+	 */
+	if (np->features & FE_DAC) {
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 0
+		np->rv_ccntl1	|= (DDAC);
+#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
+		if (!np->use_dac)
+			np->rv_ccntl1	|= (DDAC);
+		else
+			np->rv_ccntl1	|= (XTIMOD | EXTIBMV);
+#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
+		if (!np->use_dac)
+			np->rv_ccntl1	|= (DDAC);
+		else
+			np->rv_ccntl1	|= (0 | EXTIBMV);
+#endif
+	}
+
+	/*
+	 *  Phase mismatch handled by SCRIPTS (895A/896/1010) ?
+  	 */
+	if (np->features & FE_NOPM)
+		np->rv_ccntl0	|= (ENPMJ);
+
+ 	/*
+	 *  C1010-33 Errata: Part Number:609-039638 (rev. 1) is fixed.
+	 *  In dual channel mode, contention occurs if internal cycles
+	 *  are used. Disable internal cycles.
+	 */
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
+	    np->revision_id < 0x1)
+		np->rv_ccntl0	|=  DILS;
+
+	/*
+	 *  Select burst length (dwords)
+	 */
+	burst_max	= SYM_SETUP_BURST_ORDER;
+	if (burst_max == 255)
+		burst_max = burst_code(np->sv_dmode, np->sv_ctest4,
+				       np->sv_ctest5);
+	if (burst_max > 7)
+		burst_max = 7;
+	if (burst_max > np->maxburst)
+		burst_max = np->maxburst;
+
+	/*
+	 *  DEL 352 - 53C810 Rev x11 - Part Number 609-0392140 - ITEM 2.
+	 *  This chip and the 860 Rev 1 may wrongly use PCI cache line 
+	 *  based transactions on LOAD/STORE instructions. So we have 
+	 *  to prevent these chips from using such PCI transactions in 
+	 *  this driver. The generic ncr driver that does not use 
+	 *  LOAD/STORE instructions does not need this work-around.
+	 */
+	if ((np->device_id == PCI_DEVICE_ID_NCR_53C810 &&
+	     np->revision_id >= 0x10 && np->revision_id <= 0x11) ||
+	    (np->device_id == PCI_DEVICE_ID_NCR_53C860 &&
+	     np->revision_id <= 0x1))
+		np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
+
+	/*
+	 *  Select all supported special features.
+	 *  If we are using on-board RAM for scripts, prefetch (PFEN) 
+	 *  does not help, but burst op fetch (BOF) does.
+	 *  Disabling PFEN makes sure BOF will be used.
+	 */
+	if (np->features & FE_ERL)
+		np->rv_dmode	|= ERL;		/* Enable Read Line */
+	if (np->features & FE_BOF)
+		np->rv_dmode	|= BOF;		/* Burst Opcode Fetch */
+	if (np->features & FE_ERMP)
+		np->rv_dmode	|= ERMP;	/* Enable Read Multiple */
+#if 1
+	if ((np->features & FE_PFEN) && !np->ram_ba)
+#else
+	if (np->features & FE_PFEN)
+#endif
+		np->rv_dcntl	|= PFEN;	/* Prefetch Enable */
+	if (np->features & FE_CLSE)
+		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
+	if (np->features & FE_WRIE)
+		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
+	if (np->features & FE_DFS)
+		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+
+	/*
+	 *  Select some other
+	 */
+	np->rv_ctest4	|= MPEE; /* Master parity checking */
+	np->rv_scntl0	|= 0x0a; /*  full arb., ena parity, par->ATN  */
+
+	/*
+	 *  Get parity checking, host ID and verbose mode from NVRAM
+	 */
+	np->myaddr = 255;
+	sym_nvram_setup_host(shost, np, nvram);
+
+	/*
+	 *  Get SCSI addr of host adapter (set by bios?).
+	 */
+	if (np->myaddr == 255) {
+		np->myaddr = INB(np, nc_scid) & 0x07;
+		if (!np->myaddr)
+			np->myaddr = SYM_SETUP_HOST_ID;
+	}
+
+	/*
+	 *  Prepare initial io register bits for burst length
+	 */
+	sym_init_burst(np, burst_max);
+
+	/*
+	 *  Set SCSI BUS mode.
+	 *  - LVD capable chips (895/895A/896/1010) report the 
+	 *    current BUS mode through the STEST4 IO register.
+	 *  - For previous generation chips (825/825A/875), 
+	 *    user has to tell us how to check against HVD, 
+	 *    since a 100% safe algorithm is not possible.
+	 */
+	np->scsi_mode = SMODE_SE;
+	if (np->features & (FE_ULTRA2|FE_ULTRA3))
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
+		if (SYM_SETUP_SCSI_DIFF == 1) {
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+			}
+			else if (nvram->type == SYM_SYMBIOS_NVRAM) {
+				if (!(INB(np, nc_gpreg) & 0x08))
+					np->scsi_mode = SMODE_HVD;
+			}
+		}
+		else if	(SYM_SETUP_SCSI_DIFF == 2)
+			np->scsi_mode = SMODE_HVD;
+	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	 *  Set LED support from SCRIPTS.
+	 *  Ignore this feature for boards known to use a 
+	 *  specific GPIO wiring and for the 895A, 896 
+	 *  and 1010 that drive the LED directly.
+	 */
+	if ((SYM_SETUP_SCSI_LED || 
+	     (nvram->type == SYM_SYMBIOS_NVRAM ||
+	      (nvram->type == SYM_TEKRAM_NVRAM &&
+	       np->device_id == PCI_DEVICE_ID_NCR_53C895))) &&
+	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
+		np->features |= FE_LED0;
+
+	/*
+	 *  Set irq mode.
+	 */
+	switch(SYM_SETUP_IRQ_MODE & 3) {
+	case 2:
+		np->rv_dcntl	|= IRQM;
+		break;
+	case 1:
+		np->rv_dcntl	|= (np->sv_dcntl & IRQM);
+		break;
+	default:
+		break;
+	}
+
+	/*
+	 *  Configure targets according to driver setup.
+	 *  If NVRAM present get targets setup from NVRAM.
+	 */
+	for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
+		struct sym_tcb *tp = &np->target[i];
+
+		tp->usrflags |= (SYM_DISC_ENABLED | SYM_TAGS_ENABLED);
+		tp->usrtags = SYM_SETUP_MAX_TAG;
+
+		sym_nvram_setup_target(np, i, nvram);
+
+		if (!tp->usrtags)
+			tp->usrflags &= ~SYM_TAGS_ENABLED;
+	}
+
+	/*
+	 *  Let user know about the settings.
+	 */
+	printf("%s: %s, ID %d, Fast-%d, %s, %s\n", sym_name(np),
+		sym_nvram_type(nvram), np->myaddr,
+		(np->features & FE_ULTRA3) ? 80 : 
+		(np->features & FE_ULTRA2) ? 40 : 
+		(np->features & FE_ULTRA)  ? 20 : 10,
+		sym_scsi_bus_mode(np->scsi_mode),
+		(np->rv_scntl0 & 0xa)	? "parity checking" : "NO parity");
+	/*
+	 *  Tell him more on demand.
+	 */
+	if (sym_verbose) {
+		printf("%s: %s IRQ line driver%s\n",
+			sym_name(np),
+			np->rv_dcntl & IRQM ? "totem pole" : "open drain",
+			np->ram_ba ? ", using on-chip SRAM" : "");
+		printf("%s: using %s firmware.\n", sym_name(np), np->fw_name);
+		if (np->features & FE_NOPM)
+			printf("%s: handling phase mismatch from SCRIPTS.\n", 
+			       sym_name(np));
+	}
+	/*
+	 *  And still more.
+	 */
+	if (sym_verbose >= 2) {
+		printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			sym_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl,
+			np->sv_ctest3, np->sv_ctest4, np->sv_ctest5);
+
+		printf ("%s: final   SCNTL3/DMODE/DCNTL/CTEST3/4/5 = "
+			"(hex) %02x/%02x/%02x/%02x/%02x/%02x\n",
+			sym_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl,
+			np->rv_ctest3, np->rv_ctest4, np->rv_ctest5);
+	}
+	/*
+	 *  Let user be aware of targets that have some disable flags set.
+	 */
+	sym_print_targets_flag(np, SYM_SCAN_BOOT_DISABLED, "SCAN AT BOOT");
+	if (sym_verbose)
+		sym_print_targets_flag(np, SYM_SCAN_LUNS_DISABLED,
+				       "SCAN FOR LUNS");
+
+	return 0;
+}
+
+/*
+ *  Test the pci bus snoop logic :-(
+ *
+ *  Has to be called with interrupts disabled.
+ */
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
+static int sym_regtest (struct sym_hcb *np)
+{
+	register volatile u32 data;
+	/*
+	 *  chip registers may NOT be cached.
+	 *  write 0xffffffff to a read only register area,
+	 *  and try to read it back.
+	 */
+	data = 0xffffffff;
+	OUTL(np, nc_dstat, data);
+	data = INL(np, nc_dstat);
+#if 1
+	if (data == 0xffffffff) {
+#else
+	if ((data & 0xe2f0fffd) != 0x02000080) {
+#endif
+		printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n",
+			(unsigned) data);
+		return (0x10);
+	}
+	return (0);
+}
+#endif
+
+static int sym_snooptest (struct sym_hcb *np)
+{
+	u32	sym_rd, sym_wr, sym_bk, host_rd, host_wr, pc, dstat;
+	int	i, err=0;
+#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED
+	err |= sym_regtest (np);
+	if (err) return (err);
+#endif
+restart_test:
+	/*
+	 *  Enable Master Parity Checking as we intend 
+	 *  to enable it for normal operations.
+	 */
+	OUTB(np, nc_ctest4, (np->rv_ctest4 & MPEE));
+	/*
+	 *  init
+	 */
+	pc  = SCRIPTZ_BA(np, snooptest);
+	host_wr = 1;
+	sym_wr  = 2;
+	/*
+	 *  Set memory and register.
+	 */
+	np->scratch = cpu_to_scr(host_wr);
+	OUTL(np, nc_temp, sym_wr);
+	/*
+	 *  Start script (exchange values)
+	 */
+	OUTL(np, nc_dsa, np->hcb_ba);
+	OUTL_DSP(np, pc);
+	/*
+	 *  Wait 'til done (with timeout)
+	 */
+	for (i=0; i<SYM_SNOOP_TIMEOUT; i++)
+		if (INB(np, nc_istat) & (INTF|SIP|DIP))
+			break;
+	if (i>=SYM_SNOOP_TIMEOUT) {
+		printf ("CACHE TEST FAILED: timeout.\n");
+		return (0x20);
+	}
+	/*
+	 *  Check for fatal DMA errors.
+	 */
+	dstat = INB(np, nc_dstat);
+#if 1	/* Band aiding for broken hardwares that fail PCI parity */
+	if ((dstat & MDPE) && (np->rv_ctest4 & MPEE)) {
+		printf ("%s: PCI DATA PARITY ERROR DETECTED - "
+			"DISABLING MASTER DATA PARITY CHECKING.\n",
+			sym_name(np));
+		np->rv_ctest4 &= ~MPEE;
+		goto restart_test;
+	}
+#endif
+	if (dstat & (MDPE|BF|IID)) {
+		printf ("CACHE TEST FAILED: DMA error (dstat=0x%02x).", dstat);
+		return (0x80);
+	}
+	/*
+	 *  Save termination position.
+	 */
+	pc = INL(np, nc_dsp);
+	/*
+	 *  Read memory and register.
+	 */
+	host_rd = scr_to_cpu(np->scratch);
+	sym_rd  = INL(np, nc_scratcha);
+	sym_bk  = INL(np, nc_temp);
+	/*
+	 *  Check termination position.
+	 */
+	if (pc != SCRIPTZ_BA(np, snoopend)+8) {
+		printf ("CACHE TEST FAILED: script execution failed.\n");
+		printf ("start=%08lx, pc=%08lx, end=%08lx\n", 
+			(u_long) SCRIPTZ_BA(np, snooptest), (u_long) pc,
+			(u_long) SCRIPTZ_BA(np, snoopend) +8);
+		return (0x40);
+	}
+	/*
+	 *  Show results.
+	 */
+	if (host_wr != sym_rd) {
+		printf ("CACHE TEST FAILED: host wrote %d, chip read %d.\n",
+			(int) host_wr, (int) sym_rd);
+		err |= 1;
+	}
+	if (host_rd != sym_wr) {
+		printf ("CACHE TEST FAILED: chip wrote %d, host read %d.\n",
+			(int) sym_wr, (int) host_rd);
+		err |= 2;
+	}
+	if (sym_bk != sym_wr) {
+		printf ("CACHE TEST FAILED: chip wrote %d, read back %d.\n",
+			(int) sym_wr, (int) sym_bk);
+		err |= 4;
+	}
+
+	return (err);
+}
+
+/*
+ *  log message for real hard errors
+ *
+ *  sym0 targ 0?: ERROR (ds:si) (so-si-sd) (sx/s3/s4) @ name (dsp:dbc).
+ *  	      reg: r0 r1 r2 r3 r4 r5 r6 ..... rf.
+ *
+ *  exception register:
+ *  	ds:	dstat
+ *  	si:	sist
+ *
+ *  SCSI bus lines:
+ *  	so:	control lines as driven by chip.
+ *  	si:	control lines as seen by chip.
+ *  	sd:	scsi data lines as seen by chip.
+ *
+ *  wide/fastmode:
+ *  	sx:	sxfer  (see the manual)
+ *  	s3:	scntl3 (see the manual)
+ *  	s4:	scntl4 (see the manual)
+ *
+ *  current script command:
+ *  	dsp:	script address (relative to start of script).
+ *  	dbc:	first word of script command.
+ *
+ *  First 24 register of the chip:
+ *  	r0..rf
+ */
+static void sym_log_hard_error(struct sym_hcb *np, u_short sist, u_char dstat)
+{
+	u32	dsp;
+	int	script_ofs;
+	int	script_size;
+	char	*script_name;
+	u_char	*script_base;
+	int	i;
+
+	dsp	= INL(np, nc_dsp);
+
+	if	(dsp > np->scripta_ba &&
+		 dsp <= np->scripta_ba + np->scripta_sz) {
+		script_ofs	= dsp - np->scripta_ba;
+		script_size	= np->scripta_sz;
+		script_base	= (u_char *) np->scripta0;
+		script_name	= "scripta";
+	}
+	else if (np->scriptb_ba < dsp && 
+		 dsp <= np->scriptb_ba + np->scriptb_sz) {
+		script_ofs	= dsp - np->scriptb_ba;
+		script_size	= np->scriptb_sz;
+		script_base	= (u_char *) np->scriptb0;
+		script_name	= "scriptb";
+	} else {
+		script_ofs	= dsp;
+		script_size	= 0;
+		script_base	= NULL;
+		script_name	= "mem";
+	}
+
+	printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x/%x) @ (%s %x:%08x).\n",
+		sym_name(np), (unsigned)INB(np, nc_sdid)&0x0f, dstat, sist,
+		(unsigned)INB(np, nc_socl), (unsigned)INB(np, nc_sbcl),
+		(unsigned)INB(np, nc_sbdl), (unsigned)INB(np, nc_sxfer),
+		(unsigned)INB(np, nc_scntl3),
+		(np->features & FE_C10) ?  (unsigned)INB(np, nc_scntl4) : 0,
+		script_name, script_ofs,   (unsigned)INL(np, nc_dbc));
+
+	if (((script_ofs & 3) == 0) &&
+	    (unsigned)script_ofs < script_size) {
+		printf ("%s: script cmd = %08x\n", sym_name(np),
+			scr_to_cpu((int) *(u32 *)(script_base + script_ofs)));
+	}
+
+        printf ("%s: regdump:", sym_name(np));
+        for (i=0; i<24;i++)
+            printf (" %02x", (unsigned)INB_OFF(np, i));
+        printf (".\n");
+
+	/*
+	 *  PCI BUS error.
+	 */
+	if (dstat & (MDPE|BF))
+		sym_log_bus_error(np);
+}
+
+static struct sym_chip sym_dev_table[] = {
+ {PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, 64,
+ FE_ERL}
+ ,
+#ifdef SYM_DEBUG_GENERIC_SUPPORT
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4,  8, 4, 1,
+ FE_BOF}
+ ,
+#else
+ {PCI_DEVICE_ID_NCR_53C810, 0xff, "810a", 4,  8, 4, 1,
+ FE_CACHE_SET|FE_LDSTR|FE_PFEN|FE_BOF}
+ ,
+#endif
+ {PCI_DEVICE_ID_NCR_53C815, 0xff, "815", 4,  8, 4, 64,
+ FE_BOF|FE_ERL}
+ ,
+ {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 6,  8, 4, 64,
+ FE_WIDE|FE_BOF|FE_ERL|FE_DIFF}
+ ,
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6,  8, 4, 2,
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF}
+ ,
+ {PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4,  8, 5, 1,
+ FE_ULTRA|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}
+ ,
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, 2,
+ FE_WIDE|FE_ULTRA|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_DIFF|FE_VARCLK}
+ ,
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, 2,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_DIFF|FE_VARCLK}
+ ,
+ {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 6, 16, 5, 2,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_DIFF|FE_VARCLK}
+ ,
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, 2,
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_DIFF|FE_VARCLK}
+ ,
+#ifdef SYM_DEBUG_GENERIC_SUPPORT
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|
+ FE_RAM|FE_LCKFRQ}
+ ,
+#else
+ {PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 6, 31, 7, 2,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_LCKFRQ}
+ ,
+#endif
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896", 6, 31, 7, 4,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
+ ,
+ {PCI_DEVICE_ID_LSI_53C895A, 0xff, "895a", 6, 31, 7, 4,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_RAM8K|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
+ ,
+ {PCI_DEVICE_ID_LSI_53C875A, 0xff, "875a", 6, 31, 7, 4,
+ FE_WIDE|FE_ULTRA|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_LCKFRQ}
+ ,
+ {PCI_DEVICE_ID_LSI_53C1010_33, 0x00, "1010-33", 6, 31, 7, 8,
+ FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC|
+ FE_C10}
+ ,
+ {PCI_DEVICE_ID_LSI_53C1010_33, 0xff, "1010-33", 6, 31, 7, 8,
+ FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_CRC|
+ FE_C10|FE_U3EN}
+ ,
+ {PCI_DEVICE_ID_LSI_53C1010_66, 0xff, "1010-66", 6, 31, 7, 8,
+ FE_WIDE|FE_ULTRA3|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFBC|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_DAC|FE_IO256|FE_NOPM|FE_LEDC|FE_66MHZ|FE_CRC|
+ FE_C10|FE_U3EN}
+ ,
+ {PCI_DEVICE_ID_LSI_53C1510, 0xff, "1510d", 6, 31, 7, 4,
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|
+ FE_RAM|FE_IO256|FE_LEDC}
+};
+
+#define sym_num_devs \
+	(sizeof(sym_dev_table) / sizeof(sym_dev_table[0]))
+
+/*
+ *  Look up the chip table.
+ *
+ *  Return a pointer to the chip entry if found, 
+ *  zero otherwise.
+ */
+struct sym_chip *
+sym_lookup_chip_table (u_short device_id, u_char revision)
+{
+	struct	sym_chip *chip;
+	int	i;
+
+	for (i = 0; i < sym_num_devs; i++) {
+		chip = &sym_dev_table[i];
+		if (device_id != chip->device_id)
+			continue;
+		if (revision > chip->revision_id)
+			continue;
+		return chip;
+	}
+
+	return NULL;
+}
+
+#if SYM_CONF_DMA_ADDRESSING_MODE == 2
+/*
+ *  Lookup the 64 bit DMA segments map.
+ *  This is only used if the direct mapping 
+ *  has been unsuccessful.
+ */
+int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s)
+{
+	int i;
+
+	if (!np->use_dac)
+		goto weird;
+
+	/* Look up existing mappings */
+	for (i = SYM_DMAP_SIZE-1; i > 0; i--) {
+		if (h == np->dmap_bah[i])
+			return i;
+	}
+	/* If direct mapping is free, get it */
+	if (!np->dmap_bah[s])
+		goto new;
+	/* Collision -> lookup free mappings */
+	for (s = SYM_DMAP_SIZE-1; s > 0; s--) {
+		if (!np->dmap_bah[s])
+			goto new;
+	}
+weird:
+	panic("sym: ran out of 64 bit DMA segment registers");
+	return -1;
+new:
+	np->dmap_bah[s] = h;
+	np->dmap_dirty = 1;
+	return s;
+}
+
+/*
+ *  Update IO registers scratch C..R so they will be 
+ *  in sync. with queued CCB expectations.
+ */
+static void sym_update_dmap_regs(struct sym_hcb *np)
+{
+	int o, i;
+
+	if (!np->dmap_dirty)
+		return;
+	o = offsetof(struct sym_reg, nc_scrx[0]);
+	for (i = 0; i < SYM_DMAP_SIZE; i++) {
+		OUTL_OFF(np, o, np->dmap_bah[i]);
+		o += 4;
+	}
+	np->dmap_dirty = 0;
+}
+#endif
+
+/* Enforce all the fiddly SPI rules and the chip limitations */
+static void sym_check_goals(struct sym_hcb *np, struct scsi_target *starget,
+		struct sym_trans *goal)
+{
+	if (!spi_support_wide(starget))
+		goal->width = 0;
+
+	if (!spi_support_sync(starget)) {
+		goal->iu = 0;
+		goal->dt = 0;
+		goal->qas = 0;
+		goal->period = 0;
+		goal->offset = 0;
+		return;
+	}
+
+	if (spi_support_dt(starget)) {
+		if (spi_support_dt_only(starget))
+			goal->dt = 1;
+
+		if (goal->offset == 0)
+			goal->dt = 0;
+	} else {
+		goal->dt = 0;
+	}
+
+	/* Some targets fail to properly negotiate DT in SE mode */
+	if ((np->scsi_mode != SMODE_LVD) || !(np->features & FE_U3EN))
+		goal->dt = 0;
+
+	if (goal->dt) {
+		/* all DT transfers must be wide */
+		goal->width = 1;
+		if (goal->offset > np->maxoffs_dt)
+			goal->offset = np->maxoffs_dt;
+		if (goal->period < np->minsync_dt)
+			goal->period = np->minsync_dt;
+		if (goal->period > np->maxsync_dt)
+			goal->period = np->maxsync_dt;
+	} else {
+		goal->iu = goal->qas = 0;
+		if (goal->offset > np->maxoffs)
+			goal->offset = np->maxoffs;
+		if (goal->period < np->minsync)
+			goal->period = np->minsync;
+		if (goal->period > np->maxsync)
+			goal->period = np->maxsync;
+	}
+}
+
+/*
+ *  Prepare the next negotiation message if needed.
+ *
+ *  Fill in the part of message buffer that contains the 
+ *  negotiation and the nego_status field of the CCB.
+ *  Returns the size of the message in bytes.
+ */
+static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgptr)
+{
+	struct sym_tcb *tp = &np->target[cp->target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+	struct sym_trans *goal = &tp->tgoal;
+	int msglen = 0;
+	int nego;
+
+	sym_check_goals(np, starget, goal);
+
+	/*
+	 * Many devices implement PPR in a buggy way, so only use it if we
+	 * really want to.
+	 */
+	if (goal->iu || goal->dt || goal->qas || (goal->period < 0xa)) {
+		nego = NS_PPR;
+	} else if (spi_width(starget) != goal->width) {
+		nego = NS_WIDE;
+	} else if (spi_period(starget) != goal->period ||
+		   spi_offset(starget) != goal->offset) {
+		nego = NS_SYNC;
+	} else {
+		goal->check_nego = 0;
+		nego = 0;
+	}
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = goal->period;
+		msgptr[msglen++] = goal->offset;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = goal->width;
+		break;
+	case NS_PPR:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 6;
+		msgptr[msglen++] = M_X_PPR_REQ;
+		msgptr[msglen++] = goal->period;
+		msgptr[msglen++] = 0;
+		msgptr[msglen++] = goal->offset;
+		msgptr[msglen++] = goal->width;
+		msgptr[msglen++] = (goal->iu ? PPR_OPT_IU : 0) |
+					(goal->dt ? PPR_OPT_DT : 0) |
+					(goal->qas ? PPR_OPT_QAS : 0);
+		break;
+	}
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp; /* Keep track a nego will be performed */
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			sym_print_nego_msg(np, cp->target, 
+					  nego == NS_SYNC ? "sync msgout" :
+					  nego == NS_WIDE ? "wide msgout" :
+					  "ppr msgout", msgptr);
+		}
+	}
+
+	return msglen;
+}
+
+/*
+ *  Insert a job into the start queue.
+ */
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp)
+{
+	u_short	qidx;
+
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  If the previously queued CCB is not yet done, 
+	 *  set the IARB hint. The SCRIPTS will go with IARB 
+	 *  for this job when starting the previous one.
+	 *  We leave devices a chance to win arbitration by 
+	 *  not using more than 'iarb_max' consecutive 
+	 *  immediate arbitrations.
+	 */
+	if (np->last_cp && np->iarb_count < np->iarb_max) {
+		np->last_cp->host_flags |= HF_HINT_IARB;
+		++np->iarb_count;
+	}
+	else
+		np->iarb_count = 0;
+	np->last_cp = cp;
+#endif
+
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 2
+	/*
+	 *  Make SCRIPTS aware of the 64 bit DMA 
+	 *  segment registers not being up-to-date.
+	 */
+	if (np->dmap_dirty)
+		cp->host_xflags |= HX_DMAP_DIRTY;
+#endif
+
+	/*
+	 *  Insert first the idle task and then our job.
+	 *  The MBs should ensure proper ordering.
+	 */
+	qidx = np->squeueput + 2;
+	if (qidx >= MAX_QUEUE*2) qidx = 0;
+
+	np->squeue [qidx]	   = cpu_to_scr(np->idletask_ba);
+	MEMORY_WRITE_BARRIER();
+	np->squeue [np->squeueput] = cpu_to_scr(cp->ccb_ba);
+
+	np->squeueput = qidx;
+
+	if (DEBUG_FLAGS & DEBUG_QUEUE)
+		printf ("%s: queuepos=%d.\n", sym_name (np), np->squeueput);
+
+	/*
+	 *  Script processor may be waiting for reselect.
+	 *  Wake it up.
+	 */
+	MEMORY_WRITE_BARRIER();
+	OUTB(np, nc_istat, SIGP|np->istat_sem);
+}
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+/*
+ *  Start next ready-to-start CCBs.
+ */
+void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn)
+{
+	SYM_QUEHEAD *qp;
+	struct sym_ccb *cp;
+
+	/* 
+	 *  Paranoia, as usual. :-)
+	 */
+	assert(!lp->started_tags || !lp->started_no_tag);
+
+	/*
+	 *  Try to start as many commands as asked by caller.
+	 *  Prevent from having both tagged and untagged 
+	 *  commands queued to the device at the same time.
+	 */
+	while (maxn--) {
+		qp = sym_remque_head(&lp->waiting_ccbq);
+		if (!qp)
+			break;
+		cp = sym_que_entry(qp, struct sym_ccb, link2_ccbq);
+		if (cp->tag != NO_TAG) {
+			if (lp->started_no_tag ||
+			    lp->started_tags >= lp->started_max) {
+				sym_insque_head(qp, &lp->waiting_ccbq);
+				break;
+			}
+			lp->itlq_tbl[cp->tag] = cpu_to_scr(cp->ccb_ba);
+			lp->head.resel_sa =
+				cpu_to_scr(SCRIPTA_BA(np, resel_tag));
+			++lp->started_tags;
+		} else {
+			if (lp->started_no_tag || lp->started_tags) {
+				sym_insque_head(qp, &lp->waiting_ccbq);
+				break;
+			}
+			lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba);
+			lp->head.resel_sa =
+			      cpu_to_scr(SCRIPTA_BA(np, resel_no_tag));
+			++lp->started_no_tag;
+		}
+		cp->started = 1;
+		sym_insque_tail(qp, &lp->started_ccbq);
+		sym_put_start_queue(np, cp);
+	}
+}
+#endif /* SYM_OPT_HANDLE_DEVICE_QUEUEING */
+
+/*
+ *  The chip may have completed jobs. Look at the DONE QUEUE.
+ *
+ *  On paper, memory read barriers may be needed here to 
+ *  prevent out of order LOADs by the CPU from having 
+ *  prefetched stale data prior to DMA having occurred.
+ */
+static int sym_wakeup_done (struct sym_hcb *np)
+{
+	struct sym_ccb *cp;
+	int i, n;
+	u32 dsa;
+
+	n = 0;
+	i = np->dqueueget;
+
+	/* MEMORY_READ_BARRIER(); */
+	while (1) {
+		dsa = scr_to_cpu(np->dqueue[i]);
+		if (!dsa)
+			break;
+		np->dqueue[i] = 0;
+		if ((i = i+2) >= MAX_QUEUE*2)
+			i = 0;
+
+		cp = sym_ccb_from_dsa(np, dsa);
+		if (cp) {
+			MEMORY_READ_BARRIER();
+			sym_complete_ok (np, cp);
+			++n;
+		}
+		else
+			printf ("%s: bad DSA (%x) in done queue.\n",
+				sym_name(np), (u_int) dsa);
+	}
+	np->dqueueget = i;
+
+	return n;
+}
+
+/*
+ *  Complete all CCBs queued to the COMP queue.
+ *
+ *  These CCBs are assumed:
+ *  - Not to be referenced either by devices or 
+ *    SCRIPTS-related queues and datas.
+ *  - To have to be completed with an error condition 
+ *    or requeued.
+ *
+ *  The device queue freeze count is incremented 
+ *  for each CCB that does not prevent this.
+ *  This function is called when all CCBs involved 
+ *  in error handling/recovery have been reaped.
+ */
+static void sym_flush_comp_queue(struct sym_hcb *np, int cam_status)
+{
+	SYM_QUEHEAD *qp;
+	struct sym_ccb *cp;
+
+	while ((qp = sym_remque_head(&np->comp_ccbq)) != 0) {
+		struct scsi_cmnd *cmd;
+		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
+		/* Leave quiet CCBs waiting for resources */
+		if (cp->host_status == HS_WAIT)
+			continue;
+		cmd = cp->cmd;
+		if (cam_status)
+			sym_set_cam_status(cmd, cam_status);
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+		if (sym_get_cam_status(cmd) == CAM_REQUEUE_REQ) {
+			struct sym_tcb *tp = &np->target[cp->target];
+			struct sym_lcb *lp = sym_lp(tp, cp->lun);
+			if (lp) {
+				sym_remque(&cp->link2_ccbq);
+				sym_insque_tail(&cp->link2_ccbq,
+				                &lp->waiting_ccbq);
+				if (cp->started) {
+					if (cp->tag != NO_TAG)
+						--lp->started_tags;
+					else
+						--lp->started_no_tag;
+				}
+			}
+			cp->started = 0;
+			continue;
+		}
+#endif
+		sym_free_ccb(np, cp);
+		sym_xpt_done(np, cmd);
+	}
+}
+
+/*
+ *  Complete all active CCBs with error.
+ *  Used on CHIP/SCSI RESET.
+ */
+static void sym_flush_busy_queue (struct sym_hcb *np, int cam_status)
+{
+	/*
+	 *  Move all active CCBs to the COMP queue 
+	 *  and flush this queue.
+	 */
+	sym_que_splice(&np->busy_ccbq, &np->comp_ccbq);
+	sym_que_init(&np->busy_ccbq);
+	sym_flush_comp_queue(np, cam_status);
+}
+
+/*
+ *  Start chip.
+ *
+ *  'reason' means:
+ *     0: initialisation.
+ *     1: SCSI BUS RESET delivered or received.
+ *     2: SCSI BUS MODE changed.
+ */
+void sym_start_up (struct sym_hcb *np, int reason)
+{
+ 	int	i;
+	u32	phys;
+
+ 	/*
+	 *  Reset chip if asked, otherwise just clear fifos.
+ 	 */
+	if (reason == 1)
+		sym_soft_reset(np);
+	else {
+		OUTB(np, nc_stest3, TE|CSF);
+		OUTONB(np, nc_ctest3, CLF);
+	}
+ 
+	/*
+	 *  Clear Start Queue
+	 */
+	phys = np->squeue_ba;
+	for (i = 0; i < MAX_QUEUE*2; i += 2) {
+		np->squeue[i]   = cpu_to_scr(np->idletask_ba);
+		np->squeue[i+1] = cpu_to_scr(phys + (i+2)*4);
+	}
+	np->squeue[MAX_QUEUE*2-1] = cpu_to_scr(phys);
+
+	/*
+	 *  Start at first entry.
+	 */
+	np->squeueput = 0;
+
+	/*
+	 *  Clear Done Queue
+	 */
+	phys = np->dqueue_ba;
+	for (i = 0; i < MAX_QUEUE*2; i += 2) {
+		np->dqueue[i]   = 0;
+		np->dqueue[i+1] = cpu_to_scr(phys + (i+2)*4);
+	}
+	np->dqueue[MAX_QUEUE*2-1] = cpu_to_scr(phys);
+
+	/*
+	 *  Start at first entry.
+	 */
+	np->dqueueget = 0;
+
+	/*
+	 *  Install patches in scripts.
+	 *  This also let point to first position the start 
+	 *  and done queue pointers used from SCRIPTS.
+	 */
+	np->fw_patch(np);
+
+	/*
+	 *  Wakeup all pending jobs.
+	 */
+	sym_flush_busy_queue(np, CAM_SCSI_BUS_RESET);
+
+	/*
+	 *  Init chip.
+	 */
+	OUTB(np, nc_istat,  0x00);			/*  Remove Reset, abort */
+	udelay(2000); /* The 895 needs time for the bus mode to settle */
+
+	OUTB(np, nc_scntl0, np->rv_scntl0 | 0xc0);
+					/*  full arb., ena parity, par->ATN  */
+	OUTB(np, nc_scntl1, 0x00);		/*  odd parity, and remove CRST!! */
+
+	sym_selectclock(np, np->rv_scntl3);	/* Select SCSI clock */
+
+	OUTB(np, nc_scid  , RRE|np->myaddr);	/* Adapter SCSI address */
+	OUTW(np, nc_respid, 1ul<<np->myaddr);	/* Id to respond to */
+	OUTB(np, nc_istat , SIGP	);		/*  Signal Process */
+	OUTB(np, nc_dmode , np->rv_dmode);		/* Burst length, dma mode */
+	OUTB(np, nc_ctest5, np->rv_ctest5);	/* Large fifo + large burst */
+
+	OUTB(np, nc_dcntl , NOCOM|np->rv_dcntl);	/* Protect SFBR */
+	OUTB(np, nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
+	OUTB(np, nc_ctest4, np->rv_ctest4);	/* Master parity checking */
+
+	/* Extended Sreq/Sack filtering not supported on the C10 */
+	if (np->features & FE_C10)
+		OUTB(np, nc_stest2, np->rv_stest2);
+	else
+		OUTB(np, nc_stest2, EXT|np->rv_stest2);
+
+	OUTB(np, nc_stest3, TE);			/* TolerANT enable */
+	OUTB(np, nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
+
+	/*
+	 *  For now, disable AIP generation on C1010-66.
+	 */
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_66)
+		OUTB(np, nc_aipcntl1, DISAIP);
+
+	/*
+	 *  C10101 rev. 0 errata.
+	 *  Errant SGE's when in narrow. Write bits 4 & 5 of
+	 *  STEST1 register to disable SGE. We probably should do 
+	 *  that from SCRIPTS for each selection/reselection, but 
+	 *  I just don't want. :)
+	 */
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010_33 &&
+	    np->revision_id < 1)
+		OUTB(np, nc_stest1, INB(np, nc_stest1) | 0x30);
+
+	/*
+	 *  DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
+	 *  Disable overlapped arbitration for some dual function devices, 
+	 *  regardless revision id (kind of post-chip-design feature. ;-))
+	 */
+	if (np->device_id == PCI_DEVICE_ID_NCR_53C875)
+		OUTB(np, nc_ctest0, (1<<5));
+	else if (np->device_id == PCI_DEVICE_ID_NCR_53C896)
+		np->rv_ccntl0 |= DPR;
+
+	/*
+	 *  Write CCNTL0/CCNTL1 for chips capable of 64 bit addressing 
+	 *  and/or hardware phase mismatch, since only such chips 
+	 *  seem to support those IO registers.
+	 */
+	if (np->features & (FE_DAC|FE_NOPM)) {
+		OUTB(np, nc_ccntl0, np->rv_ccntl0);
+		OUTB(np, nc_ccntl1, np->rv_ccntl1);
+	}
+
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+	/*
+	 *  Set up scratch C and DRS IO registers to map the 32 bit 
+	 *  DMA address range our data structures are located in.
+	 */
+	if (np->use_dac) {
+		np->dmap_bah[0] = 0;	/* ??? */
+		OUTL(np, nc_scrx[0], np->dmap_bah[0]);
+		OUTL(np, nc_drs, np->dmap_bah[0]);
+	}
+#endif
+
+	/*
+	 *  If phase mismatch handled by scripts (895A/896/1010),
+	 *  set PM jump addresses.
+	 */
+	if (np->features & FE_NOPM) {
+		OUTL(np, nc_pmjad1, SCRIPTB_BA(np, pm_handle));
+		OUTL(np, nc_pmjad2, SCRIPTB_BA(np, pm_handle));
+	}
+
+	/*
+	 *    Enable GPIO0 pin for writing if LED support from SCRIPTS.
+	 *    Also set GPIO5 and clear GPIO6 if hardware LED control.
+	 */
+	if (np->features & FE_LED0)
+		OUTB(np, nc_gpcntl, INB(np, nc_gpcntl) & ~0x01);
+	else if (np->features & FE_LEDC)
+		OUTB(np, nc_gpcntl, (INB(np, nc_gpcntl) & ~0x41) | 0x20);
+
+	/*
+	 *      enable ints
+	 */
+	OUTW(np, nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR);
+	OUTB(np, nc_dien , MDPE|BF|SSI|SIR|IID);
+
+	/*
+	 *  For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+	 *  Try to eat the spurious SBMC interrupt that may occur when 
+	 *  we reset the chip but not the SCSI BUS (at initialization).
+	 */
+	if (np->features & (FE_ULTRA2|FE_ULTRA3)) {
+		OUTONW(np, nc_sien, SBMC);
+		if (reason == 0) {
+			mdelay(100);
+			INW(np, nc_sist);
+		}
+		np->scsi_mode = INB(np, nc_stest4) & SMODE;
+	}
+
+	/*
+	 *  Fill in target structure.
+	 *  Reinitialize usrsync.
+	 *  Reinitialize usrwide.
+	 *  Prepare sync negotiation according to actual SCSI bus mode.
+	 */
+	for (i=0;i<SYM_CONF_MAX_TARGET;i++) {
+		struct sym_tcb *tp = &np->target[i];
+
+		tp->to_reset  = 0;
+		tp->head.sval = 0;
+		tp->head.wval = np->rv_scntl3;
+		tp->head.uval = 0;
+	}
+
+	/*
+	 *  Download SCSI SCRIPTS to on-chip RAM if present,
+	 *  and start script processor.
+	 *  We do the download preferently from the CPU.
+	 *  For platforms that may not support PCI memory mapping,
+	 *  we use simple SCRIPTS that performs MEMORY MOVEs.
+	 */
+	phys = SCRIPTA_BA(np, init);
+	if (np->ram_ba) {
+		if (sym_verbose >= 2)
+			printf("%s: Downloading SCSI SCRIPTS.\n", sym_name(np));
+		memcpy_toio(np->s.ramaddr, np->scripta0, np->scripta_sz);
+		if (np->ram_ws == 8192) {
+			memcpy_toio(np->s.ramaddr + 4096, np->scriptb0, np->scriptb_sz);
+			phys = scr_to_cpu(np->scr_ram_seg);
+			OUTL(np, nc_mmws, phys);
+			OUTL(np, nc_mmrs, phys);
+			OUTL(np, nc_sfs,  phys);
+			phys = SCRIPTB_BA(np, start64);
+		}
+	}
+
+	np->istat_sem = 0;
+
+	OUTL(np, nc_dsa, np->hcb_ba);
+	OUTL_DSP(np, phys);
+
+	/*
+	 *  Notify the XPT about the RESET condition.
+	 */
+	if (reason != 0)
+		sym_xpt_async_bus_reset(np);
+}
+
+/*
+ *  Switch trans mode for current job and its target.
+ */
+static void sym_settrans(struct sym_hcb *np, int target, u_char opts, u_char ofs,
+			 u_char per, u_char wide, u_char div, u_char fak)
+{
+	SYM_QUEHEAD *qp;
+	u_char sval, wval, uval;
+	struct sym_tcb *tp = &np->target[target];
+
+	assert(target == (INB(np, nc_sdid) & 0x0f));
+
+	sval = tp->head.sval;
+	wval = tp->head.wval;
+	uval = tp->head.uval;
+
+#if 0
+	printf("XXXX sval=%x wval=%x uval=%x (%x)\n", 
+		sval, wval, uval, np->rv_scntl3);
+#endif
+	/*
+	 *  Set the offset.
+	 */
+	if (!(np->features & FE_C10))
+		sval = (sval & ~0x1f) | ofs;
+	else
+		sval = (sval & ~0x3f) | ofs;
+
+	/*
+	 *  Set the sync divisor and extra clock factor.
+	 */
+	if (ofs != 0) {
+		wval = (wval & ~0x70) | ((div+1) << 4);
+		if (!(np->features & FE_C10))
+			sval = (sval & ~0xe0) | (fak << 5);
+		else {
+			uval = uval & ~(XCLKH_ST|XCLKH_DT|XCLKS_ST|XCLKS_DT);
+			if (fak >= 1) uval |= (XCLKH_ST|XCLKH_DT);
+			if (fak >= 2) uval |= (XCLKS_ST|XCLKS_DT);
+		}
+	}
+
+	/*
+	 *  Set the bus width.
+	 */
+	wval = wval & ~EWS;
+	if (wide != 0)
+		wval |= EWS;
+
+	/*
+	 *  Set misc. ultra enable bits.
+	 */
+	if (np->features & FE_C10) {
+		uval = uval & ~(U3EN|AIPCKEN);
+		if (opts)	{
+			assert(np->features & FE_U3EN);
+			uval |= U3EN;
+		}
+	} else {
+		wval = wval & ~ULTRA;
+		if (per <= 12)	wval |= ULTRA;
+	}
+
+	/*
+	 *   Stop there if sync parameters are unchanged.
+	 */
+	if (tp->head.sval == sval && 
+	    tp->head.wval == wval &&
+	    tp->head.uval == uval)
+		return;
+	tp->head.sval = sval;
+	tp->head.wval = wval;
+	tp->head.uval = uval;
+
+	/*
+	 *  Disable extended Sreq/Sack filtering if per < 50.
+	 *  Not supported on the C1010.
+	 */
+	if (per < 50 && !(np->features & FE_C10))
+		OUTOFFB(np, nc_stest2, EXT);
+
+	/*
+	 *  set actual value and sync_status
+	 */
+	OUTB(np, nc_sxfer,  tp->head.sval);
+	OUTB(np, nc_scntl3, tp->head.wval);
+
+	if (np->features & FE_C10) {
+		OUTB(np, nc_scntl4, tp->head.uval);
+	}
+
+	/*
+	 *  patch ALL busy ccbs of this target.
+	 */
+	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+		struct sym_ccb *cp;
+		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		if (cp->target != target)
+			continue;
+		cp->phys.select.sel_scntl3 = tp->head.wval;
+		cp->phys.select.sel_sxfer  = tp->head.sval;
+		if (np->features & FE_C10) {
+			cp->phys.select.sel_scntl4 = tp->head.uval;
+		}
+	}
+}
+
+/*
+ *  We received a WDTR.
+ *  Let everything be aware of the changes.
+ */
+static void sym_setwide(struct sym_hcb *np, int target, u_char wide)
+{
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+
+	if (spi_width(starget) == wide)
+		return;
+
+	sym_settrans(np, target, 0, 0, 0, wide, 0, 0);
+
+	tp->tgoal.width = wide;
+	spi_offset(starget) = 0;
+	spi_period(starget) = 0;
+	spi_width(starget) = wide;
+	spi_iu(starget) = 0;
+	spi_dt(starget) = 0;
+	spi_qas(starget) = 0;
+
+	if (sym_verbose >= 3)
+		spi_display_xfer_agreement(starget);
+}
+
+/*
+ *  We received a SDTR.
+ *  Let everything be aware of the changes.
+ */
+static void
+sym_setsync(struct sym_hcb *np, int target,
+            u_char ofs, u_char per, u_char div, u_char fak)
+{
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+	u_char wide = (tp->head.wval & EWS) ? BUS_16_BIT : BUS_8_BIT;
+
+	sym_settrans(np, target, 0, ofs, per, wide, div, fak);
+
+	spi_period(starget) = per;
+	spi_offset(starget) = ofs;
+	spi_iu(starget) = spi_dt(starget) = spi_qas(starget) = 0;
+
+	if (!tp->tgoal.dt && !tp->tgoal.iu && !tp->tgoal.qas) {
+		tp->tgoal.period = per;
+		tp->tgoal.offset = ofs;
+		tp->tgoal.check_nego = 0;
+	}
+
+	spi_display_xfer_agreement(starget);
+}
+
+/*
+ *  We received a PPR.
+ *  Let everything be aware of the changes.
+ */
+static void 
+sym_setpprot(struct sym_hcb *np, int target, u_char opts, u_char ofs,
+             u_char per, u_char wide, u_char div, u_char fak)
+{
+	struct sym_tcb *tp = &np->target[target];
+	struct scsi_target *starget = tp->sdev->sdev_target;
+
+	sym_settrans(np, target, opts, ofs, per, wide, div, fak);
+
+	spi_width(starget) = tp->tgoal.width = wide;
+	spi_period(starget) = tp->tgoal.period = per;
+	spi_offset(starget) = tp->tgoal.offset = ofs;
+	spi_iu(starget) = tp->tgoal.iu = !!(opts & PPR_OPT_IU);
+	spi_dt(starget) = tp->tgoal.dt = !!(opts & PPR_OPT_DT);
+	spi_qas(starget) = tp->tgoal.qas = !!(opts & PPR_OPT_QAS);
+	tp->tgoal.check_nego = 0;
+
+	spi_display_xfer_agreement(starget);
+}
+
+/*
+ *  generic recovery from scsi interrupt
+ *
+ *  The doc says that when the chip gets an SCSI interrupt,
+ *  it tries to stop in an orderly fashion, by completing 
+ *  an instruction fetch that had started or by flushing 
+ *  the DMA fifo for a write to memory that was executing.
+ *  Such a fashion is not enough to know if the instruction 
+ *  that was just before the current DSP value has been 
+ *  executed or not.
+ *
+ *  There are some small SCRIPTS sections that deal with 
+ *  the start queue and the done queue that may break any 
+ *  assomption from the C code if we are interrupted 
+ *  inside, so we reset if this happens. Btw, since these 
+ *  SCRIPTS sections are executed while the SCRIPTS hasn't 
+ *  started SCSI operations, it is very unlikely to happen.
+ *
+ *  All the driver data structures are supposed to be 
+ *  allocated from the same 4 GB memory window, so there 
+ *  is a 1 to 1 relationship between DSA and driver data 
+ *  structures. Since we are careful :) to invalidate the 
+ *  DSA when we complete a command or when the SCRIPTS 
+ *  pushes a DSA into a queue, we can trust it when it 
+ *  points to a CCB.
+ */
+static void sym_recover_scsi_int (struct sym_hcb *np, u_char hsts)
+{
+	u32	dsp	= INL(np, nc_dsp);
+	u32	dsa	= INL(np, nc_dsa);
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
+
+	/*
+	 *  If we haven't been interrupted inside the SCRIPTS 
+	 *  critical pathes, we can safely restart the SCRIPTS 
+	 *  and trust the DSA value if it matches a CCB.
+	 */
+	if ((!(dsp > SCRIPTA_BA(np, getjob_begin) &&
+	       dsp < SCRIPTA_BA(np, getjob_end) + 1)) &&
+	    (!(dsp > SCRIPTA_BA(np, ungetjob) &&
+	       dsp < SCRIPTA_BA(np, reselect) + 1)) &&
+	    (!(dsp > SCRIPTB_BA(np, sel_for_abort) &&
+	       dsp < SCRIPTB_BA(np, sel_for_abort_1) + 1)) &&
+	    (!(dsp > SCRIPTA_BA(np, done) &&
+	       dsp < SCRIPTA_BA(np, done_end) + 1))) {
+		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF); /* clear dma fifo  */
+		OUTB(np, nc_stest3, TE|CSF);		/* clear scsi fifo */
+		/*
+		 *  If we have a CCB, let the SCRIPTS call us back for 
+		 *  the handling of the error with SCRATCHA filled with 
+		 *  STARTPOS. This way, we will be able to freeze the 
+		 *  device queue and requeue awaiting IOs.
+		 */
+		if (cp) {
+			cp->host_status = hsts;
+			OUTL_DSP(np, SCRIPTA_BA(np, complete_error));
+		}
+		/*
+		 *  Otherwise just restart the SCRIPTS.
+		 */
+		else {
+			OUTL(np, nc_dsa, 0xffffff);
+			OUTL_DSP(np, SCRIPTA_BA(np, start));
+		}
+	}
+	else
+		goto reset_all;
+
+	return;
+
+reset_all:
+	sym_start_reset(np);
+}
+
+/*
+ *  chip exception handler for selection timeout
+ */
+static void sym_int_sto (struct sym_hcb *np)
+{
+	u32 dsp	= INL(np, nc_dsp);
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printf ("T");
+
+	if (dsp == SCRIPTA_BA(np, wf_sel_done) + 8)
+		sym_recover_scsi_int(np, HS_SEL_TIMEOUT);
+	else
+		sym_start_reset(np);
+}
+
+/*
+ *  chip exception handler for unexpected disconnect
+ */
+static void sym_int_udc (struct sym_hcb *np)
+{
+	printf ("%s: unexpected disconnect\n", sym_name(np));
+	sym_recover_scsi_int(np, HS_UNEXPECTED);
+}
+
+/*
+ *  chip exception handler for SCSI bus mode change
+ *
+ *  spi2-r12 11.2.3 says a transceiver mode change must 
+ *  generate a reset event and a device that detects a reset 
+ *  event shall initiate a hard reset. It says also that a
+ *  device that detects a mode change shall set data transfer 
+ *  mode to eight bit asynchronous, etc...
+ *  So, just reinitializing all except chip should be enough.
+ */
+static void sym_int_sbmc (struct sym_hcb *np)
+{
+	u_char scsi_mode = INB(np, nc_stest4) & SMODE;
+
+	/*
+	 *  Notify user.
+	 */
+	printf("%s: SCSI BUS mode change from %s to %s.\n", sym_name(np),
+		sym_scsi_bus_mode(np->scsi_mode), sym_scsi_bus_mode(scsi_mode));
+
+	/*
+	 *  Should suspend command processing for a few seconds and 
+	 *  reinitialize all except the chip.
+	 */
+	sym_start_up (np, 2);
+}
+
+/*
+ *  chip exception handler for SCSI parity error.
+ *
+ *  When the chip detects a SCSI parity error and is 
+ *  currently executing a (CH)MOV instruction, it does 
+ *  not interrupt immediately, but tries to finish the 
+ *  transfer of the current scatter entry before 
+ *  interrupting. The following situations may occur:
+ *
+ *  - The complete scatter entry has been transferred 
+ *    without the device having changed phase.
+ *    The chip will then interrupt with the DSP pointing 
+ *    to the instruction that follows the MOV.
+ *
+ *  - A phase mismatch occurs before the MOV finished 
+ *    and phase errors are to be handled by the C code.
+ *    The chip will then interrupt with both PAR and MA 
+ *    conditions set.
+ *
+ *  - A phase mismatch occurs before the MOV finished and 
+ *    phase errors are to be handled by SCRIPTS.
+ *    The chip will load the DSP with the phase mismatch 
+ *    JUMP address and interrupt the host processor.
+ */
+static void sym_int_par (struct sym_hcb *np, u_short sist)
+{
+	u_char	hsts	= INB(np, HS_PRT);
+	u32	dsp	= INL(np, nc_dsp);
+	u32	dbc	= INL(np, nc_dbc);
+	u32	dsa	= INL(np, nc_dsa);
+	u_char	sbcl	= INB(np, nc_sbcl);
+	u_char	cmd	= dbc >> 24;
+	int phase	= cmd & 7;
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
+
+	printf("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
+		sym_name(np), hsts, dbc, sbcl);
+
+	/*
+	 *  Check that the chip is connected to the SCSI BUS.
+	 */
+	if (!(INB(np, nc_scntl1) & ISCON)) {
+		sym_recover_scsi_int(np, HS_UNEXPECTED);
+		return;
+	}
+
+	/*
+	 *  If the nexus is not clearly identified, reset the bus.
+	 *  We will try to do better later.
+	 */
+	if (!cp)
+		goto reset_all;
+
+	/*
+	 *  Check instruction was a MOV, direction was INPUT and 
+	 *  ATN is asserted.
+	 */
+	if ((cmd & 0xc0) || !(phase & 1) || !(sbcl & 0x8))
+		goto reset_all;
+
+	/*
+	 *  Keep track of the parity error.
+	 */
+	OUTONB(np, HF_PRT, HF_EXT_ERR);
+	cp->xerr_status |= XE_PARITY_ERR;
+
+	/*
+	 *  Prepare the message to send to the device.
+	 */
+	np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;
+
+	/*
+	 *  If the old phase was DATA IN phase, we have to deal with
+	 *  the 3 situations described above.
+	 *  For other input phases (MSG IN and STATUS), the device 
+	 *  must resend the whole thing that failed parity checking 
+	 *  or signal error. So, jumping to dispatcher should be OK.
+	 */
+	if (phase == 1 || phase == 5) {
+		/* Phase mismatch handled by SCRIPTS */
+		if (dsp == SCRIPTB_BA(np, pm_handle))
+			OUTL_DSP(np, dsp);
+		/* Phase mismatch handled by the C code */
+		else if (sist & MA)
+			sym_int_ma (np);
+		/* No phase mismatch occurred */
+		else {
+			sym_set_script_dp (np, cp, dsp);
+			OUTL_DSP(np, SCRIPTA_BA(np, dispatch));
+		}
+	}
+	else if (phase == 7)	/* We definitely cannot handle parity errors */
+#if 1				/* in message-in phase due to the relection  */
+		goto reset_all; /* path and various message anticipations.   */
+#else
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+#endif
+	else
+		OUTL_DSP(np, SCRIPTA_BA(np, dispatch));
+	return;
+
+reset_all:
+	sym_start_reset(np);
+	return;
+}
+
+/*
+ *  chip exception handler for phase errors.
+ *
+ *  We have to construct a new transfer descriptor,
+ *  to transfer the rest of the current block.
+ */
+static void sym_int_ma (struct sym_hcb *np)
+{
+	u32	dbc;
+	u32	rest;
+	u32	dsp;
+	u32	dsa;
+	u32	nxtdsp;
+	u32	*vdsp;
+	u32	oadr, olen;
+	u32	*tblp;
+        u32	newcmd;
+	u_int	delta;
+	u_char	cmd;
+	u_char	hflags, hflags0;
+	struct	sym_pmc *pm;
+	struct sym_ccb *cp;
+
+	dsp	= INL(np, nc_dsp);
+	dbc	= INL(np, nc_dbc);
+	dsa	= INL(np, nc_dsa);
+
+	cmd	= dbc >> 24;
+	rest	= dbc & 0xffffff;
+	delta	= 0;
+
+	/*
+	 *  locate matching cp if any.
+	 */
+	cp = sym_ccb_from_dsa(np, dsa);
+
+	/*
+	 *  Donnot take into account dma fifo and various buffers in 
+	 *  INPUT phase since the chip flushes everything before 
+	 *  raising the MA interrupt for interrupted INPUT phases.
+	 *  For DATA IN phase, we will check for the SWIDE later.
+	 */
+	if ((cmd & 7) != 1 && (cmd & 7) != 5) {
+		u_char ss0, ss2;
+
+		if (np->features & FE_DFBC)
+			delta = INW(np, nc_dfbc);
+		else {
+			u32 dfifo;
+
+			/*
+			 * Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
+			 */
+			dfifo = INL(np, nc_dfifo);
+
+			/*
+			 *  Calculate remaining bytes in DMA fifo.
+			 *  (CTEST5 = dfifo >> 16)
+			 */
+			if (dfifo & (DFS << 16))
+				delta = ((((dfifo >> 8) & 0x300) |
+				          (dfifo & 0xff)) - rest) & 0x3ff;
+			else
+				delta = ((dfifo & 0xff) - rest) & 0x7f;
+		}
+
+		/*
+		 *  The data in the dma fifo has not been transfered to
+		 *  the target -> add the amount to the rest
+		 *  and clear the data.
+		 *  Check the sstat2 register in case of wide transfer.
+		 */
+		rest += delta;
+		ss0  = INB(np, nc_sstat0);
+		if (ss0 & OLF) rest++;
+		if (!(np->features & FE_C10))
+			if (ss0 & ORF) rest++;
+		if (cp && (cp->phys.select.sel_scntl3 & EWS)) {
+			ss2 = INB(np, nc_sstat2);
+			if (ss2 & OLF1) rest++;
+			if (!(np->features & FE_C10))
+				if (ss2 & ORF1) rest++;
+		}
+
+		/*
+		 *  Clear fifos.
+		 */
+		OUTB(np, nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
+		OUTB(np, nc_stest3, TE|CSF);		/* scsi fifo */
+	}
+
+	/*
+	 *  log the information
+	 */
+	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE))
+		printf ("P%x%x RL=%d D=%d ", cmd&7, INB(np, nc_sbcl)&7,
+			(unsigned) rest, (unsigned) delta);
+
+	/*
+	 *  try to find the interrupted script command,
+	 *  and the address at which to continue.
+	 */
+	vdsp	= NULL;
+	nxtdsp	= 0;
+	if	(dsp >  np->scripta_ba &&
+		 dsp <= np->scripta_ba + np->scripta_sz) {
+		vdsp = (u32 *)((char*)np->scripta0 + (dsp-np->scripta_ba-8));
+		nxtdsp = dsp;
+	}
+	else if	(dsp >  np->scriptb_ba &&
+		 dsp <= np->scriptb_ba + np->scriptb_sz) {
+		vdsp = (u32 *)((char*)np->scriptb0 + (dsp-np->scriptb_ba-8));
+		nxtdsp = dsp;
+	}
+
+	/*
+	 *  log the information
+	 */
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		printf ("\nCP=%p DSP=%x NXT=%x VDSP=%p CMD=%x ",
+			cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd);
+	}
+
+	if (!vdsp) {
+		printf ("%s: interrupted SCRIPT address not found.\n", 
+			sym_name (np));
+		goto reset_all;
+	}
+
+	if (!cp) {
+		printf ("%s: SCSI phase error fixup: CCB already dequeued.\n", 
+			sym_name (np));
+		goto reset_all;
+	}
+
+	/*
+	 *  get old startaddress and old length.
+	 */
+	oadr = scr_to_cpu(vdsp[1]);
+
+	if (cmd & 0x10) {	/* Table indirect */
+		tblp = (u32 *) ((char*) &cp->phys + oadr);
+		olen = scr_to_cpu(tblp[0]);
+		oadr = scr_to_cpu(tblp[1]);
+	} else {
+		tblp = (u32 *) 0;
+		olen = scr_to_cpu(vdsp[0]) & 0xffffff;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n",
+			(unsigned) (scr_to_cpu(vdsp[0]) >> 24),
+			tblp,
+			(unsigned) olen,
+			(unsigned) oadr);
+	}
+
+	/*
+	 *  check cmd against assumed interrupted script command.
+	 *  If dt data phase, the MOVE instruction hasn't bit 4 of 
+	 *  the phase.
+	 */
+	if (((cmd & 2) ? cmd : (cmd & ~4)) != (scr_to_cpu(vdsp[0]) >> 24)) {
+		sym_print_addr(cp->cmd,
+			"internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n",
+			cmd, scr_to_cpu(vdsp[0]) >> 24);
+
+		goto reset_all;
+	}
+
+	/*
+	 *  if old phase not dataphase, leave here.
+	 */
+	if (cmd & 2) {
+		sym_print_addr(cp->cmd,
+			"phase change %x-%x %d@%08x resid=%d.\n",
+			cmd&7, INB(np, nc_sbcl)&7, (unsigned)olen,
+			(unsigned)oadr, (unsigned)rest);
+		goto unexpected_phase;
+	}
+
+	/*
+	 *  Choose the correct PM save area.
+	 *
+	 *  Look at the PM_SAVE SCRIPT if you want to understand 
+	 *  this stuff. The equivalent code is implemented in 
+	 *  SCRIPTS for the 895A, 896 and 1010 that are able to 
+	 *  handle PM from the SCRIPTS processor.
+	 */
+	hflags0 = INB(np, HF_PRT);
+	hflags = hflags0;
+
+	if (hflags & (HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED)) {
+		if (hflags & HF_IN_PM0)
+			nxtdsp = scr_to_cpu(cp->phys.pm0.ret);
+		else if	(hflags & HF_IN_PM1)
+			nxtdsp = scr_to_cpu(cp->phys.pm1.ret);
+
+		if (hflags & HF_DP_SAVED)
+			hflags ^= HF_ACT_PM;
+	}
+
+	if (!(hflags & HF_ACT_PM)) {
+		pm = &cp->phys.pm0;
+		newcmd = SCRIPTA_BA(np, pm0_data);
+	}
+	else {
+		pm = &cp->phys.pm1;
+		newcmd = SCRIPTA_BA(np, pm1_data);
+	}
+
+	hflags &= ~(HF_IN_PM0 | HF_IN_PM1 | HF_DP_SAVED);
+	if (hflags != hflags0)
+		OUTB(np, HF_PRT, hflags);
+
+	/*
+	 *  fillin the phase mismatch context
+	 */
+	pm->sg.addr = cpu_to_scr(oadr + olen - rest);
+	pm->sg.size = cpu_to_scr(rest);
+	pm->ret     = cpu_to_scr(nxtdsp);
+
+	/*
+	 *  If we have a SWIDE,
+	 *  - prepare the address to write the SWIDE from SCRIPTS,
+	 *  - compute the SCRIPTS address to restart from,
+	 *  - move current data pointer context by one byte.
+	 */
+	nxtdsp = SCRIPTA_BA(np, dispatch);
+	if ((cmd & 7) == 1 && cp && (cp->phys.select.sel_scntl3 & EWS) &&
+	    (INB(np, nc_scntl2) & WSR)) {
+		u32 tmp;
+
+		/*
+		 *  Set up the table indirect for the MOVE
+		 *  of the residual byte and adjust the data 
+		 *  pointer context.
+		 */
+		tmp = scr_to_cpu(pm->sg.addr);
+		cp->phys.wresid.addr = cpu_to_scr(tmp);
+		pm->sg.addr = cpu_to_scr(tmp + 1);
+		tmp = scr_to_cpu(pm->sg.size);
+		cp->phys.wresid.size = cpu_to_scr((tmp&0xff000000) | 1);
+		pm->sg.size = cpu_to_scr(tmp - 1);
+
+		/*
+		 *  If only the residual byte is to be moved, 
+		 *  no PM context is needed.
+		 */
+		if ((tmp&0xffffff) == 1)
+			newcmd = pm->ret;
+
+		/*
+		 *  Prepare the address of SCRIPTS that will 
+		 *  move the residual byte to memory.
+		 */
+		nxtdsp = SCRIPTB_BA(np, wsr_ma_helper);
+	}
+
+	if (DEBUG_FLAGS & DEBUG_PHASE) {
+		sym_print_addr(cp->cmd, "PM %x %x %x / %x %x %x.\n",
+			hflags0, hflags, newcmd,
+			(unsigned)scr_to_cpu(pm->sg.addr),
+			(unsigned)scr_to_cpu(pm->sg.size),
+			(unsigned)scr_to_cpu(pm->ret));
+	}
+
+	/*
+	 *  Restart the SCRIPTS processor.
+	 */
+	sym_set_script_dp (np, cp, newcmd);
+	OUTL_DSP(np, nxtdsp);
+	return;
+
+	/*
+	 *  Unexpected phase changes that occurs when the current phase 
+	 *  is not a DATA IN or DATA OUT phase are due to error conditions.
+	 *  Such event may only happen when the SCRIPTS is using a 
+	 *  multibyte SCSI MOVE.
+	 *
+	 *  Phase change		Some possible cause
+	 *
+	 *  COMMAND  --> MSG IN	SCSI parity error detected by target.
+	 *  COMMAND  --> STATUS	Bad command or refused by target.
+	 *  MSG OUT  --> MSG IN     Message rejected by target.
+	 *  MSG OUT  --> COMMAND    Bogus target that discards extended
+	 *  			negotiation messages.
+	 *
+	 *  The code below does not care of the new phase and so 
+	 *  trusts the target. Why to annoy it ?
+	 *  If the interrupted phase is COMMAND phase, we restart at
+	 *  dispatcher.
+	 *  If a target does not get all the messages after selection, 
+	 *  the code assumes blindly that the target discards extended 
+	 *  messages and clears the negotiation status.
+	 *  If the target does not want all our response to negotiation,
+	 *  we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids 
+	 *  bloat for such a should_not_happen situation).
+	 *  In all other situation, we reset the BUS.
+	 *  Are these assumptions reasonnable ? (Wait and see ...)
+	 */
+unexpected_phase:
+	dsp -= 8;
+	nxtdsp = 0;
+
+	switch (cmd & 7) {
+	case 2:	/* COMMAND phase */
+		nxtdsp = SCRIPTA_BA(np, dispatch);
+		break;
+#if 0
+	case 3:	/* STATUS  phase */
+		nxtdsp = SCRIPTA_BA(np, dispatch);
+		break;
+#endif
+	case 6:	/* MSG OUT phase */
+		/*
+		 *  If the device may want to use untagged when we want 
+		 *  tagged, we prepare an IDENTIFY without disc. granted, 
+		 *  since we will not be able to handle reselect.
+		 *  Otherwise, we just don't care.
+		 */
+		if	(dsp == SCRIPTA_BA(np, send_ident)) {
+			if (cp->tag != NO_TAG && olen - rest <= 3) {
+				cp->host_status = HS_BUSY;
+				np->msgout[0] = IDENTIFY(0, cp->lun);
+				nxtdsp = SCRIPTB_BA(np, ident_break_atn);
+			}
+			else
+				nxtdsp = SCRIPTB_BA(np, ident_break);
+		}
+		else if	(dsp == SCRIPTB_BA(np, send_wdtr) ||
+			 dsp == SCRIPTB_BA(np, send_sdtr) ||
+			 dsp == SCRIPTB_BA(np, send_ppr)) {
+			nxtdsp = SCRIPTB_BA(np, nego_bad_phase);
+			if (dsp == SCRIPTB_BA(np, send_ppr)) {
+				struct scsi_device *dev = cp->cmd->device;
+				dev->ppr = 0;
+			}
+		}
+		break;
+#if 0
+	case 7:	/* MSG IN  phase */
+		nxtdsp = SCRIPTA_BA(np, clrack);
+		break;
+#endif
+	}
+
+	if (nxtdsp) {
+		OUTL_DSP(np, nxtdsp);
+		return;
+	}
+
+reset_all:
+	sym_start_reset(np);
+}
+
+/*
+ *  chip interrupt handler
+ *
+ *  In normal situations, interrupt conditions occur one at 
+ *  a time. But when something bad happens on the SCSI BUS, 
+ *  the chip may raise several interrupt flags before 
+ *  stopping and interrupting the CPU. The additionnal 
+ *  interrupt flags are stacked in some extra registers 
+ *  after the SIP and/or DIP flag has been raised in the 
+ *  ISTAT. After the CPU has read the interrupt condition 
+ *  flag from SIST or DSTAT, the chip unstacks the other 
+ *  interrupt flags and sets the corresponding bits in 
+ *  SIST or DSTAT. Since the chip starts stacking once the 
+ *  SIP or DIP flag is set, there is a small window of time 
+ *  where the stacking does not occur.
+ *
+ *  Typically, multiple interrupt conditions may happen in 
+ *  the following situations:
+ *
+ *  - SCSI parity error + Phase mismatch  (PAR|MA)
+ *    When an parity error is detected in input phase 
+ *    and the device switches to msg-in phase inside a 
+ *    block MOV.
+ *  - SCSI parity error + Unexpected disconnect (PAR|UDC)
+ *    When a stupid device does not want to handle the 
+ *    recovery of an SCSI parity error.
+ *  - Some combinations of STO, PAR, UDC, ...
+ *    When using non compliant SCSI stuff, when user is 
+ *    doing non compliant hot tampering on the BUS, when 
+ *    something really bad happens to a device, etc ...
+ *
+ *  The heuristic suggested by SYMBIOS to handle 
+ *  multiple interrupts is to try unstacking all 
+ *  interrupts conditions and to handle them on some 
+ *  priority based on error severity.
+ *  This will work when the unstacking has been 
+ *  successful, but we cannot be 100 % sure of that, 
+ *  since the CPU may have been faster to unstack than 
+ *  the chip is able to stack. Hmmm ... But it seems that 
+ *  such a situation is very unlikely to happen.
+ *
+ *  If this happen, for example STO caught by the CPU 
+ *  then UDC happenning before the CPU have restarted 
+ *  the SCRIPTS, the driver may wrongly complete the 
+ *  same command on UDC, since the SCRIPTS didn't restart 
+ *  and the DSA still points to the same command.
+ *  We avoid this situation by setting the DSA to an 
+ *  invalid value when the CCB is completed and before 
+ *  restarting the SCRIPTS.
+ *
+ *  Another issue is that we need some section of our 
+ *  recovery procedures to be somehow uninterruptible but 
+ *  the SCRIPTS processor does not provides such a 
+ *  feature. For this reason, we handle recovery preferently 
+ *  from the C code and check against some SCRIPTS critical 
+ *  sections from the C code.
+ *
+ *  Hopefully, the interrupt handling of the driver is now 
+ *  able to resist to weird BUS error conditions, but donnot 
+ *  ask me for any guarantee that it will never fail. :-)
+ *  Use at your own decision and risk.
+ */
+
+void sym_interrupt (struct sym_hcb *np)
+{
+	u_char	istat, istatc;
+	u_char	dstat;
+	u_short	sist;
+
+	/*
+	 *  interrupt on the fly ?
+	 *  (SCRIPTS may still be running)
+	 *
+	 *  A `dummy read' is needed to ensure that the 
+	 *  clear of the INTF flag reaches the device 
+	 *  and that posted writes are flushed to memory
+	 *  before the scanning of the DONE queue.
+	 *  Note that SCRIPTS also (dummy) read to memory 
+	 *  prior to deliver the INTF interrupt condition.
+	 */
+	istat = INB(np, nc_istat);
+	if (istat & INTF) {
+		OUTB(np, nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+		istat = INB(np, nc_istat);		/* DUMMY READ */
+		if (DEBUG_FLAGS & DEBUG_TINY) printf ("F ");
+		sym_wakeup_done(np);
+	}
+
+	if (!(istat & (SIP|DIP)))
+		return;
+
+#if 0	/* We should never get this one */
+	if (istat & CABRT)
+		OUTB(np, nc_istat, CABRT);
+#endif
+
+	/*
+	 *  PAR and MA interrupts may occur at the same time,
+	 *  and we need to know of both in order to handle 
+	 *  this situation properly. We try to unstack SCSI 
+	 *  interrupts for that reason. BTW, I dislike a LOT 
+	 *  such a loop inside the interrupt routine.
+	 *  Even if DMA interrupt stacking is very unlikely to 
+	 *  happen, we also try unstacking these ones, since 
+	 *  this has no performance impact.
+	 */
+	sist	= 0;
+	dstat	= 0;
+	istatc	= istat;
+	do {
+		if (istatc & SIP)
+			sist  |= INW(np, nc_sist);
+		if (istatc & DIP)
+			dstat |= INB(np, nc_dstat);
+		istatc = INB(np, nc_istat);
+		istat |= istatc;
+	} while (istatc & (SIP|DIP));
+
+	if (DEBUG_FLAGS & DEBUG_TINY)
+		printf ("<%d|%x:%x|%x:%x>",
+			(int)INB(np, nc_scr0),
+			dstat,sist,
+			(unsigned)INL(np, nc_dsp),
+			(unsigned)INL(np, nc_dbc));
+	/*
+	 *  On paper, a memory read barrier may be needed here to 
+	 *  prevent out of order LOADs by the CPU from having 
+	 *  prefetched stale data prior to DMA having occurred.
+	 *  And since we are paranoid ... :)
+	 */
+	MEMORY_READ_BARRIER();
+
+	/*
+	 *  First, interrupts we want to service cleanly.
+	 *
+	 *  Phase mismatch (MA) is the most frequent interrupt 
+	 *  for chip earlier than the 896 and so we have to service 
+	 *  it as quickly as possible.
+	 *  A SCSI parity error (PAR) may be combined with a phase 
+	 *  mismatch condition (MA).
+	 *  Programmed interrupts (SIR) are used to call the C code 
+	 *  from SCRIPTS.
+	 *  The single step interrupt (SSI) is not used in this 
+	 *  driver.
+	 */
+	if (!(sist  & (STO|GEN|HTH|SGE|UDC|SBMC|RST)) &&
+	    !(dstat & (MDPE|BF|ABRT|IID))) {
+		if	(sist & PAR)	sym_int_par (np, sist);
+		else if (sist & MA)	sym_int_ma (np);
+		else if (dstat & SIR)	sym_int_sir (np);
+		else if (dstat & SSI)	OUTONB_STD();
+		else			goto unknown_int;
+		return;
+	}
+
+	/*
+	 *  Now, interrupts that donnot happen in normal 
+	 *  situations and that we may need to recover from.
+	 *
+	 *  On SCSI RESET (RST), we reset everything.
+	 *  On SCSI BUS MODE CHANGE (SBMC), we complete all 
+	 *  active CCBs with RESET status, prepare all devices 
+	 *  for negotiating again and restart the SCRIPTS.
+	 *  On STO and UDC, we complete the CCB with the corres- 
+	 *  ponding status and restart the SCRIPTS.
+	 */
+	if (sist & RST) {
+		printf("%s: SCSI BUS reset detected.\n", sym_name(np));
+		sym_start_up (np, 1);
+		return;
+	}
+
+	OUTB(np, nc_ctest3, np->rv_ctest3 | CLF);	/* clear dma fifo  */
+	OUTB(np, nc_stest3, TE|CSF);		/* clear scsi fifo */
+
+	if (!(sist  & (GEN|HTH|SGE)) &&
+	    !(dstat & (MDPE|BF|ABRT|IID))) {
+		if	(sist & SBMC)	sym_int_sbmc (np);
+		else if (sist & STO)	sym_int_sto (np);
+		else if (sist & UDC)	sym_int_udc (np);
+		else			goto unknown_int;
+		return;
+	}
+
+	/*
+	 *  Now, interrupts we are not able to recover cleanly.
+	 *
+	 *  Log message for hard errors.
+	 *  Reset everything.
+	 */
+
+	sym_log_hard_error(np, sist, dstat);
+
+	if ((sist & (GEN|HTH|SGE)) ||
+		(dstat & (MDPE|BF|ABRT|IID))) {
+		sym_start_reset(np);
+		return;
+	}
+
+unknown_int:
+	/*
+	 *  We just miss the cause of the interrupt. :(
+	 *  Print a message. The timeout will do the real work.
+	 */
+	printf(	"%s: unknown interrupt(s) ignored, "
+		"ISTAT=0x%x DSTAT=0x%x SIST=0x%x\n",
+		sym_name(np), istat, dstat, sist);
+}
+
+/*
+ *  Dequeue from the START queue all CCBs that match 
+ *  a given target/lun/task condition (-1 means all),
+ *  and move them from the BUSY queue to the COMP queue 
+ *  with CAM_REQUEUE_REQ status condition.
+ *  This function is used during error handling/recovery.
+ *  It is called with SCRIPTS not running.
+ */
+static int 
+sym_dequeue_from_squeue(struct sym_hcb *np, int i, int target, int lun, int task)
+{
+	int j;
+	struct sym_ccb *cp;
+
+	/*
+	 *  Make sure the starting index is within range.
+	 */
+	assert((i >= 0) && (i < 2*MAX_QUEUE));
+
+	/*
+	 *  Walk until end of START queue and dequeue every job 
+	 *  that matches the target/lun/task condition.
+	 */
+	j = i;
+	while (i != np->squeueput) {
+		cp = sym_ccb_from_dsa(np, scr_to_cpu(np->squeue[i]));
+		assert(cp);
+#ifdef SYM_CONF_IARB_SUPPORT
+		/* Forget hints for IARB, they may be no longer relevant */
+		cp->host_flags &= ~HF_HINT_IARB;
+#endif
+		if ((target == -1 || cp->target == target) &&
+		    (lun    == -1 || cp->lun    == lun)    &&
+		    (task   == -1 || cp->tag    == task)) {
+			sym_set_cam_status(cp->cmd, CAM_REQUEUE_REQ);
+			sym_remque(&cp->link_ccbq);
+			sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
+		}
+		else {
+			if (i != j)
+				np->squeue[j] = np->squeue[i];
+			if ((j += 2) >= MAX_QUEUE*2) j = 0;
+		}
+		if ((i += 2) >= MAX_QUEUE*2) i = 0;
+	}
+	if (i != j)		/* Copy back the idle task if needed */
+		np->squeue[j] = np->squeue[i];
+	np->squeueput = j;	/* Update our current start queue pointer */
+
+	return (i - j) / 2;
+}
+
+/*
+ *  chip handler for bad SCSI status condition
+ *
+ *  In case of bad SCSI status, we unqueue all the tasks 
+ *  currently queued to the controller but not yet started 
+ *  and then restart the SCRIPTS processor immediately.
+ *
+ *  QUEUE FULL and BUSY conditions are handled the same way.
+ *  Basically all the not yet started tasks are requeued in 
+ *  device queue and the queue is frozen until a completion.
+ *
+ *  For CHECK CONDITION and COMMAND TERMINATED status, we use 
+ *  the CCB of the failed command to prepare a REQUEST SENSE 
+ *  SCSI command and queue it to the controller queue.
+ *
+ *  SCRATCHA is assumed to have been loaded with STARTPOS 
+ *  before the SCRIPTS called the C code.
+ */
+static void sym_sir_bad_scsi_status(struct sym_hcb *np, int num, struct sym_ccb *cp)
+{
+	u32		startp;
+	u_char		s_status = cp->ssss_status;
+	u_char		h_flags  = cp->host_flags;
+	int		msglen;
+	int		i;
+
+	/*
+	 *  Compute the index of the next job to start from SCRIPTS.
+	 */
+	i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+
+	/*
+	 *  The last CCB queued used for IARB hint may be 
+	 *  no longer relevant. Forget it.
+	 */
+#ifdef SYM_CONF_IARB_SUPPORT
+	if (np->last_cp)
+		np->last_cp = 0;
+#endif
+
+	/*
+	 *  Now deal with the SCSI status.
+	 */
+	switch(s_status) {
+	case S_BUSY:
+	case S_QUEUE_FULL:
+		if (sym_verbose >= 2) {
+			sym_print_addr(cp->cmd, "%s\n",
+			        s_status == S_BUSY ? "BUSY" : "QUEUE FULL\n");
+		}
+	default:	/* S_INT, S_INT_COND_MET, S_CONFLICT */
+		sym_complete_error (np, cp);
+		break;
+	case S_TERMINATED:
+	case S_CHECK_COND:
+		/*
+		 *  If we get an SCSI error when requesting sense, give up.
+		 */
+		if (h_flags & HF_SENSE) {
+			sym_complete_error (np, cp);
+			break;
+		}
+
+		/*
+		 *  Dequeue all queued CCBs for that device not yet started,
+		 *  and restart the SCRIPTS processor immediately.
+		 */
+		sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
+		OUTL_DSP(np, SCRIPTA_BA(np, start));
+
+ 		/*
+		 *  Save some info of the actual IO.
+		 *  Compute the data residual.
+		 */
+		cp->sv_scsi_status = cp->ssss_status;
+		cp->sv_xerr_status = cp->xerr_status;
+		cp->sv_resid = sym_compute_residual(np, cp);
+
+		/*
+		 *  Prepare all needed data structures for 
+		 *  requesting sense data.
+		 */
+
+		cp->scsi_smsg2[0] = IDENTIFY(0, cp->lun);
+		msglen = 1;
+
+		/*
+		 *  If we are currently using anything different from 
+		 *  async. 8 bit data transfers with that target,
+		 *  start a negotiation, since the device may want 
+		 *  to report us a UNIT ATTENTION condition due to 
+		 *  a cause we currently ignore, and we donnot want 
+		 *  to be stuck with WIDE and/or SYNC data transfer.
+		 *
+		 *  cp->nego_status is filled by sym_prepare_nego().
+		 */
+		cp->nego_status = 0;
+		msglen += sym_prepare_nego(np, cp, &cp->scsi_smsg2[msglen]);
+		/*
+		 *  Message table indirect structure.
+		 */
+		cp->phys.smsg.addr	= cpu_to_scr(CCB_BA(cp, scsi_smsg2));
+		cp->phys.smsg.size	= cpu_to_scr(msglen);
+
+		/*
+		 *  sense command
+		 */
+		cp->phys.cmd.addr	= cpu_to_scr(CCB_BA(cp, sensecmd));
+		cp->phys.cmd.size	= cpu_to_scr(6);
+
+		/*
+		 *  patch requested size into sense command
+		 */
+		cp->sensecmd[0]		= REQUEST_SENSE;
+		cp->sensecmd[1]		= 0;
+		if (cp->cmd->device->scsi_level <= SCSI_2 && cp->lun <= 7)
+			cp->sensecmd[1]	= cp->lun << 5;
+		cp->sensecmd[4]		= SYM_SNS_BBUF_LEN;
+		cp->data_len		= SYM_SNS_BBUF_LEN;
+
+		/*
+		 *  sense data
+		 */
+		memset(cp->sns_bbuf, 0, SYM_SNS_BBUF_LEN);
+		cp->phys.sense.addr	= cpu_to_scr(CCB_BA(cp, sns_bbuf));
+		cp->phys.sense.size	= cpu_to_scr(SYM_SNS_BBUF_LEN);
+
+		/*
+		 *  requeue the command.
+		 */
+		startp = SCRIPTB_BA(np, sdata_in);
+
+		cp->phys.head.savep	= cpu_to_scr(startp);
+		cp->phys.head.lastp	= cpu_to_scr(startp);
+		cp->startp		= cpu_to_scr(startp);
+		cp->goalp		= cpu_to_scr(startp + 16);
+
+		cp->host_xflags = 0;
+		cp->host_status	= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+		cp->ssss_status = S_ILLEGAL;
+		cp->host_flags	= (HF_SENSE|HF_DATA_IN);
+		cp->xerr_status = 0;
+		cp->extra_bytes = 0;
+
+		cp->phys.head.go.start = cpu_to_scr(SCRIPTA_BA(np, select));
+
+		/*
+		 *  Requeue the command.
+		 */
+		sym_put_start_queue(np, cp);
+
+		/*
+		 *  Give back to upper layer everything we have dequeued.
+		 */
+		sym_flush_comp_queue(np, 0);
+		break;
+	}
+}
+
+/*
+ *  After a device has accepted some management message 
+ *  as BUS DEVICE RESET, ABORT TASK, etc ..., or when 
+ *  a device signals a UNIT ATTENTION condition, some 
+ *  tasks are thrown away by the device. We are required 
+ *  to reflect that on our tasks list since the device 
+ *  will never complete these tasks.
+ *
+ *  This function move from the BUSY queue to the COMP 
+ *  queue all disconnected CCBs for a given target that 
+ *  match the following criteria:
+ *  - lun=-1  means any logical UNIT otherwise a given one.
+ *  - task=-1 means any task, otherwise a given one.
+ */
+int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task)
+{
+	SYM_QUEHEAD qtmp, *qp;
+	int i = 0;
+	struct sym_ccb *cp;
+
+	/*
+	 *  Move the entire BUSY queue to our temporary queue.
+	 */
+	sym_que_init(&qtmp);
+	sym_que_splice(&np->busy_ccbq, &qtmp);
+	sym_que_init(&np->busy_ccbq);
+
+	/*
+	 *  Put all CCBs that matches our criteria into 
+	 *  the COMP queue and put back other ones into 
+	 *  the BUSY queue.
+	 */
+	while ((qp = sym_remque_head(&qtmp)) != 0) {
+		struct scsi_cmnd *cmd;
+		cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		cmd = cp->cmd;
+		if (cp->host_status != HS_DISCONNECT ||
+		    cp->target != target	     ||
+		    (lun  != -1 && cp->lun != lun)   ||
+		    (task != -1 && 
+			(cp->tag != NO_TAG && cp->scsi_smsg[2] != task))) {
+			sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
+			continue;
+		}
+		sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
+
+		/* Preserve the software timeout condition */
+		if (sym_get_cam_status(cmd) != CAM_CMD_TIMEOUT)
+			sym_set_cam_status(cmd, cam_status);
+		++i;
+#if 0
+printf("XXXX TASK @%p CLEARED\n", cp);
+#endif
+	}
+	return i;
+}
+
+/*
+ *  chip handler for TASKS recovery
+ *
+ *  We cannot safely abort a command, while the SCRIPTS 
+ *  processor is running, since we just would be in race 
+ *  with it.
+ *
+ *  As long as we have tasks to abort, we keep the SEM 
+ *  bit set in the ISTAT. When this bit is set, the 
+ *  SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 
+ *  each time it enters the scheduler.
+ *
+ *  If we have to reset a target, clear tasks of a unit,
+ *  or to perform the abort of a disconnected job, we 
+ *  restart the SCRIPTS for selecting the target. Once 
+ *  selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
+ *  If it loses arbitration, the SCRIPTS will interrupt again 
+ *  the next time it will enter its scheduler, and so on ...
+ *
+ *  On SIR_TARGET_SELECTED, we scan for the more 
+ *  appropriate thing to do:
+ *
+ *  - If nothing, we just sent a M_ABORT message to the 
+ *    target to get rid of the useless SCSI bus ownership.
+ *    According to the specs, no tasks shall be affected.
+ *  - If the target is to be reset, we send it a M_RESET 
+ *    message.
+ *  - If a logical UNIT is to be cleared , we send the 
+ *    IDENTIFY(lun) + M_ABORT.
+ *  - If an untagged task is to be aborted, we send the 
+ *    IDENTIFY(lun) + M_ABORT.
+ *  - If a tagged task is to be aborted, we send the 
+ *    IDENTIFY(lun) + task attributes + M_ABORT_TAG.
+ *
+ *  Once our 'kiss of death' :) message has been accepted 
+ *  by the target, the SCRIPTS interrupts again 
+ *  (SIR_ABORT_SENT). On this interrupt, we complete 
+ *  all the CCBs that should have been aborted by the 
+ *  target according to our message.
+ */
+static void sym_sir_task_recovery(struct sym_hcb *np, int num)
+{
+	SYM_QUEHEAD *qp;
+	struct sym_ccb *cp;
+	struct sym_tcb *tp = NULL; /* gcc isn't quite smart enough yet */
+	struct scsi_target *starget;
+	int target=-1, lun=-1, task;
+	int i, k;
+
+	switch(num) {
+	/*
+	 *  The SCRIPTS processor stopped before starting
+	 *  the next command in order to allow us to perform 
+	 *  some task recovery.
+	 */
+	case SIR_SCRIPT_STOPPED:
+		/*
+		 *  Do we have any target to reset or unit to clear ?
+		 */
+		for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
+			tp = &np->target[i];
+			if (tp->to_reset || 
+			    (tp->lun0p && tp->lun0p->to_clear)) {
+				target = i;
+				break;
+			}
+			if (!tp->lunmp)
+				continue;
+			for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) {
+				if (tp->lunmp[k] && tp->lunmp[k]->to_clear) {
+					target	= i;
+					break;
+				}
+			}
+			if (target != -1)
+				break;
+		}
+
+		/*
+		 *  If not, walk the busy queue for any 
+		 *  disconnected CCB to be aborted.
+		 */
+		if (target == -1) {
+			FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+				cp = sym_que_entry(qp,struct sym_ccb,link_ccbq);
+				if (cp->host_status != HS_DISCONNECT)
+					continue;
+				if (cp->to_abort) {
+					target = cp->target;
+					break;
+				}
+			}
+		}
+
+		/*
+		 *  If some target is to be selected, 
+		 *  prepare and start the selection.
+		 */
+		if (target != -1) {
+			tp = &np->target[target];
+			np->abrt_sel.sel_id	= target;
+			np->abrt_sel.sel_scntl3 = tp->head.wval;
+			np->abrt_sel.sel_sxfer  = tp->head.sval;
+			OUTL(np, nc_dsa, np->hcb_ba);
+			OUTL_DSP(np, SCRIPTB_BA(np, sel_for_abort));
+			return;
+		}
+
+		/*
+		 *  Now look for a CCB to abort that haven't started yet.
+		 *  Btw, the SCRIPTS processor is still stopped, so 
+		 *  we are not in race.
+		 */
+		i = 0;
+		cp = NULL;
+		FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+			if (cp->host_status != HS_BUSY &&
+			    cp->host_status != HS_NEGOTIATE)
+				continue;
+			if (!cp->to_abort)
+				continue;
+#ifdef SYM_CONF_IARB_SUPPORT
+			/*
+			 *    If we are using IMMEDIATE ARBITRATION, we donnot 
+			 *    want to cancel the last queued CCB, since the 
+			 *    SCRIPTS may have anticipated the selection.
+			 */
+			if (cp == np->last_cp) {
+				cp->to_abort = 0;
+				continue;
+			}
+#endif
+			i = 1;	/* Means we have found some */
+			break;
+		}
+		if (!i) {
+			/*
+			 *  We are done, so we donnot need 
+			 *  to synchronize with the SCRIPTS anylonger.
+			 *  Remove the SEM flag from the ISTAT.
+			 */
+			np->istat_sem = 0;
+			OUTB(np, nc_istat, SIGP);
+			break;
+		}
+		/*
+		 *  Compute index of next position in the start 
+		 *  queue the SCRIPTS intends to start and dequeue 
+		 *  all CCBs for that device that haven't been started.
+		 */
+		i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+		i = sym_dequeue_from_squeue(np, i, cp->target, cp->lun, -1);
+
+		/*
+		 *  Make sure at least our IO to abort has been dequeued.
+		 */
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+		assert(i && sym_get_cam_status(cp->cmd) == CAM_REQUEUE_REQ);
+#else
+		sym_remque(&cp->link_ccbq);
+		sym_insque_tail(&cp->link_ccbq, &np->comp_ccbq);
+#endif
+		/*
+		 *  Keep track in cam status of the reason of the abort.
+		 */
+		if (cp->to_abort == 2)
+			sym_set_cam_status(cp->cmd, CAM_CMD_TIMEOUT);
+		else
+			sym_set_cam_status(cp->cmd, CAM_REQ_ABORTED);
+
+		/*
+		 *  Complete with error everything that we have dequeued.
+	 	 */
+		sym_flush_comp_queue(np, 0);
+		break;
+	/*
+	 *  The SCRIPTS processor has selected a target 
+	 *  we may have some manual recovery to perform for.
+	 */
+	case SIR_TARGET_SELECTED:
+		target = INB(np, nc_sdid) & 0xf;
+		tp = &np->target[target];
+
+		np->abrt_tbl.addr = cpu_to_scr(vtobus(np->abrt_msg));
+
+		/*
+		 *  If the target is to be reset, prepare a 
+		 *  M_RESET message and clear the to_reset flag 
+		 *  since we donnot expect this operation to fail.
+		 */
+		if (tp->to_reset) {
+			np->abrt_msg[0] = M_RESET;
+			np->abrt_tbl.size = 1;
+			tp->to_reset = 0;
+			break;
+		}
+
+		/*
+		 *  Otherwise, look for some logical unit to be cleared.
+		 */
+		if (tp->lun0p && tp->lun0p->to_clear)
+			lun = 0;
+		else if (tp->lunmp) {
+			for (k = 1 ; k < SYM_CONF_MAX_LUN ; k++) {
+				if (tp->lunmp[k] && tp->lunmp[k]->to_clear) {
+					lun = k;
+					break;
+				}
+			}
+		}
+
+		/*
+		 *  If a logical unit is to be cleared, prepare 
+		 *  an IDENTIFY(lun) + ABORT MESSAGE.
+		 */
+		if (lun != -1) {
+			struct sym_lcb *lp = sym_lp(tp, lun);
+			lp->to_clear = 0; /* We don't expect to fail here */
+			np->abrt_msg[0] = IDENTIFY(0, lun);
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+			break;
+		}
+
+		/*
+		 *  Otherwise, look for some disconnected job to 
+		 *  abort for this target.
+		 */
+		i = 0;
+		cp = NULL;
+		FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+			if (cp->host_status != HS_DISCONNECT)
+				continue;
+			if (cp->target != target)
+				continue;
+			if (!cp->to_abort)
+				continue;
+			i = 1;	/* Means we have some */
+			break;
+		}
+
+		/*
+		 *  If we have none, probably since the device has 
+		 *  completed the command before we won abitration,
+		 *  send a M_ABORT message without IDENTIFY.
+		 *  According to the specs, the device must just 
+		 *  disconnect the BUS and not abort any task.
+		 */
+		if (!i) {
+			np->abrt_msg[0] = M_ABORT;
+			np->abrt_tbl.size = 1;
+			break;
+		}
+
+		/*
+		 *  We have some task to abort.
+		 *  Set the IDENTIFY(lun)
+		 */
+		np->abrt_msg[0] = IDENTIFY(0, cp->lun);
+
+		/*
+		 *  If we want to abort an untagged command, we 
+		 *  will send a IDENTIFY + M_ABORT.
+		 *  Otherwise (tagged command), we will send 
+		 *  a IDENTITFY + task attributes + ABORT TAG.
+		 */
+		if (cp->tag == NO_TAG) {
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+		} else {
+			np->abrt_msg[1] = cp->scsi_smsg[1];
+			np->abrt_msg[2] = cp->scsi_smsg[2];
+			np->abrt_msg[3] = M_ABORT_TAG;
+			np->abrt_tbl.size = 4;
+		}
+		/*
+		 *  Keep track of software timeout condition, since the 
+		 *  peripheral driver may not count retries on abort 
+		 *  conditions not due to timeout.
+		 */
+		if (cp->to_abort == 2)
+			sym_set_cam_status(cp->cmd, CAM_CMD_TIMEOUT);
+		cp->to_abort = 0; /* We donnot expect to fail here */
+		break;
+
+	/*
+	 *  The target has accepted our message and switched 
+	 *  to BUS FREE phase as we expected.
+	 */
+	case SIR_ABORT_SENT:
+		target = INB(np, nc_sdid) & 0xf;
+		tp = &np->target[target];
+		starget = tp->sdev->sdev_target;
+		
+		/*
+		**  If we didn't abort anything, leave here.
+		*/
+		if (np->abrt_msg[0] == M_ABORT)
+			break;
+
+		/*
+		 *  If we sent a M_RESET, then a hardware reset has 
+		 *  been performed by the target.
+		 *  - Reset everything to async 8 bit
+		 *  - Tell ourself to negotiate next time :-)
+		 *  - Prepare to clear all disconnected CCBs for 
+		 *    this target from our task list (lun=task=-1)
+		 */
+		lun = -1;
+		task = -1;
+		if (np->abrt_msg[0] == M_RESET) {
+			tp->head.sval = 0;
+			tp->head.wval = np->rv_scntl3;
+			tp->head.uval = 0;
+			spi_period(starget) = 0;
+			spi_offset(starget) = 0;
+			spi_width(starget) = 0;
+			spi_iu(starget) = 0;
+			spi_dt(starget) = 0;
+			spi_qas(starget) = 0;
+			tp->tgoal.check_nego = 1;
+		}
+
+		/*
+		 *  Otherwise, check for the LUN and TASK(s) 
+		 *  concerned by the cancelation.
+		 *  If it is not ABORT_TAG then it is CLEAR_QUEUE 
+		 *  or an ABORT message :-)
+		 */
+		else {
+			lun = np->abrt_msg[0] & 0x3f;
+			if (np->abrt_msg[1] == M_ABORT_TAG)
+				task = np->abrt_msg[2];
+		}
+
+		/*
+		 *  Complete all the CCBs the device should have 
+		 *  aborted due to our 'kiss of death' message.
+		 */
+		i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+		sym_dequeue_from_squeue(np, i, target, lun, -1);
+		sym_clear_tasks(np, CAM_REQ_ABORTED, target, lun, task);
+		sym_flush_comp_queue(np, 0);
+
+ 		/*
+		 *  If we sent a BDR, make upper layer aware of that.
+ 		 */
+		if (np->abrt_msg[0] == M_RESET)
+			sym_xpt_async_sent_bdr(np, target);
+		break;
+	}
+
+	/*
+	 *  Print to the log the message we intend to send.
+	 */
+	if (num == SIR_TARGET_SELECTED) {
+		dev_info(&tp->sdev->sdev_target->dev, "control msgout:");
+		sym_printl_hex(np->abrt_msg, np->abrt_tbl.size);
+		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
+	}
+
+	/*
+	 *  Let the SCRIPTS processor continue.
+	 */
+	OUTONB_STD();
+}
+
+/*
+ *  Gerard's alchemy:) that deals with with the data 
+ *  pointer for both MDP and the residual calculation.
+ *
+ *  I didn't want to bloat the code by more than 200 
+ *  lines for the handling of both MDP and the residual.
+ *  This has been achieved by using a data pointer 
+ *  representation consisting in an index in the data 
+ *  array (dp_sg) and a negative offset (dp_ofs) that 
+ *  have the following meaning:
+ *
+ *  - dp_sg = SYM_CONF_MAX_SG
+ *    we are at the end of the data script.
+ *  - dp_sg < SYM_CONF_MAX_SG
+ *    dp_sg points to the next entry of the scatter array 
+ *    we want to transfer.
+ *  - dp_ofs < 0
+ *    dp_ofs represents the residual of bytes of the 
+ *    previous entry scatter entry we will send first.
+ *  - dp_ofs = 0
+ *    no residual to send first.
+ *
+ *  The function sym_evaluate_dp() accepts an arbitray 
+ *  offset (basically from the MDP message) and returns 
+ *  the corresponding values of dp_sg and dp_ofs.
+ */
+
+static int sym_evaluate_dp(struct sym_hcb *np, struct sym_ccb *cp, u32 scr, int *ofs)
+{
+	u32	dp_scr;
+	int	dp_ofs, dp_sg, dp_sgmin;
+	int	tmp;
+	struct sym_pmc *pm;
+
+	/*
+	 *  Compute the resulted data pointer in term of a script 
+	 *  address within some DATA script and a signed byte offset.
+	 */
+	dp_scr = scr;
+	dp_ofs = *ofs;
+	if	(dp_scr == SCRIPTA_BA(np, pm0_data))
+		pm = &cp->phys.pm0;
+	else if (dp_scr == SCRIPTA_BA(np, pm1_data))
+		pm = &cp->phys.pm1;
+	else
+		pm = NULL;
+
+	if (pm) {
+		dp_scr  = scr_to_cpu(pm->ret);
+		dp_ofs -= scr_to_cpu(pm->sg.size);
+	}
+
+	/*
+	 *  If we are auto-sensing, then we are done.
+	 */
+	if (cp->host_flags & HF_SENSE) {
+		*ofs = dp_ofs;
+		return 0;
+	}
+
+	/*
+	 *  Deduce the index of the sg entry.
+	 *  Keep track of the index of the first valid entry.
+	 *  If result is dp_sg = SYM_CONF_MAX_SG, then we are at the 
+	 *  end of the data.
+	 */
+	tmp = scr_to_cpu(sym_goalp(cp));
+	dp_sg = SYM_CONF_MAX_SG;
+	if (dp_scr != tmp)
+		dp_sg -= (tmp - 8 - (int)dp_scr) / (2*4);
+	dp_sgmin = SYM_CONF_MAX_SG - cp->segments;
+
+	/*
+	 *  Move to the sg entry the data pointer belongs to.
+	 *
+	 *  If we are inside the data area, we expect result to be:
+	 *
+	 *  Either,
+	 *      dp_ofs = 0 and dp_sg is the index of the sg entry
+	 *      the data pointer belongs to (or the end of the data)
+	 *  Or,
+	 *      dp_ofs < 0 and dp_sg is the index of the sg entry 
+	 *      the data pointer belongs to + 1.
+	 */
+	if (dp_ofs < 0) {
+		int n;
+		while (dp_sg > dp_sgmin) {
+			--dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			n = dp_ofs + (tmp & 0xffffff);
+			if (n > 0) {
+				++dp_sg;
+				break;
+			}
+			dp_ofs = n;
+		}
+	}
+	else if (dp_ofs > 0) {
+		while (dp_sg < SYM_CONF_MAX_SG) {
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			dp_ofs -= (tmp & 0xffffff);
+			++dp_sg;
+			if (dp_ofs <= 0)
+				break;
+		}
+	}
+
+	/*
+	 *  Make sure the data pointer is inside the data area.
+	 *  If not, return some error.
+	 */
+	if	(dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
+		goto out_err;
+	else if	(dp_sg > SYM_CONF_MAX_SG ||
+		 (dp_sg == SYM_CONF_MAX_SG && dp_ofs > 0))
+		goto out_err;
+
+	/*
+	 *  Save the extreme pointer if needed.
+	 */
+	if (dp_sg > cp->ext_sg ||
+            (dp_sg == cp->ext_sg && dp_ofs > cp->ext_ofs)) {
+		cp->ext_sg  = dp_sg;
+		cp->ext_ofs = dp_ofs;
+	}
+
+	/*
+	 *  Return data.
+	 */
+	*ofs = dp_ofs;
+	return dp_sg;
+
+out_err:
+	return -1;
+}
+
+/*
+ *  chip handler for MODIFY DATA POINTER MESSAGE
+ *
+ *  We also call this function on IGNORE WIDE RESIDUE 
+ *  messages that do not match a SWIDE full condition.
+ *  Btw, we assume in that situation that such a message 
+ *  is equivalent to a MODIFY DATA POINTER (offset=-1).
+ */
+
+static void sym_modify_dp(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp, int ofs)
+{
+	int dp_ofs	= ofs;
+	u32	dp_scr	= sym_get_script_dp (np, cp);
+	u32	dp_ret;
+	u32	tmp;
+	u_char	hflags;
+	int	dp_sg;
+	struct	sym_pmc *pm;
+
+	/*
+	 *  Not supported for auto-sense.
+	 */
+	if (cp->host_flags & HF_SENSE)
+		goto out_reject;
+
+	/*
+	 *  Apply our alchemy:) (see comments in sym_evaluate_dp()), 
+	 *  to the resulted data pointer.
+	 */
+	dp_sg = sym_evaluate_dp(np, cp, dp_scr, &dp_ofs);
+	if (dp_sg < 0)
+		goto out_reject;
+
+	/*
+	 *  And our alchemy:) allows to easily calculate the data 
+	 *  script address we want to return for the next data phase.
+	 */
+	dp_ret = cpu_to_scr(sym_goalp(cp));
+	dp_ret = dp_ret - 8 - (SYM_CONF_MAX_SG - dp_sg) * (2*4);
+
+	/*
+	 *  If offset / scatter entry is zero we donnot need 
+	 *  a context for the new current data pointer.
+	 */
+	if (dp_ofs == 0) {
+		dp_scr = dp_ret;
+		goto out_ok;
+	}
+
+	/*
+	 *  Get a context for the new current data pointer.
+	 */
+	hflags = INB(np, HF_PRT);
+
+	if (hflags & HF_DP_SAVED)
+		hflags ^= HF_ACT_PM;
+
+	if (!(hflags & HF_ACT_PM)) {
+		pm  = &cp->phys.pm0;
+		dp_scr = SCRIPTA_BA(np, pm0_data);
+	}
+	else {
+		pm = &cp->phys.pm1;
+		dp_scr = SCRIPTA_BA(np, pm1_data);
+	}
+
+	hflags &= ~(HF_DP_SAVED);
+
+	OUTB(np, HF_PRT, hflags);
+
+	/*
+	 *  Set up the new current data pointer.
+	 *  ofs < 0 there, and for the next data phase, we 
+	 *  want to transfer part of the data of the sg entry 
+	 *  corresponding to index dp_sg-1 prior to returning 
+	 *  to the main data script.
+	 */
+	pm->ret = cpu_to_scr(dp_ret);
+	tmp  = scr_to_cpu(cp->phys.data[dp_sg-1].addr);
+	tmp += scr_to_cpu(cp->phys.data[dp_sg-1].size) + dp_ofs;
+	pm->sg.addr = cpu_to_scr(tmp);
+	pm->sg.size = cpu_to_scr(-dp_ofs);
+
+out_ok:
+	sym_set_script_dp (np, cp, dp_scr);
+	OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	return;
+
+out_reject:
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
+}
+
+
+/*
+ *  chip calculation of the data residual.
+ *
+ *  As I used to say, the requirement of data residual 
+ *  in SCSI is broken, useless and cannot be achieved 
+ *  without huge complexity.
+ *  But most OSes and even the official CAM require it.
+ *  When stupidity happens to be so widely spread inside 
+ *  a community, it gets hard to convince.
+ *
+ *  Anyway, I don't care, since I am not going to use 
+ *  any software that considers this data residual as 
+ *  a relevant information. :)
+ */
+
+int sym_compute_residual(struct sym_hcb *np, struct sym_ccb *cp)
+{
+	int dp_sg, dp_sgmin, resid = 0;
+	int dp_ofs = 0;
+
+	/*
+	 *  Check for some data lost or just thrown away.
+	 *  We are not required to be quite accurate in this 
+	 *  situation. Btw, if we are odd for output and the 
+	 *  device claims some more data, it may well happen 
+	 *  than our residual be zero. :-)
+	 */
+	if (cp->xerr_status & (XE_EXTRA_DATA|XE_SODL_UNRUN|XE_SWIDE_OVRUN)) {
+		if (cp->xerr_status & XE_EXTRA_DATA)
+			resid -= cp->extra_bytes;
+		if (cp->xerr_status & XE_SODL_UNRUN)
+			++resid;
+		if (cp->xerr_status & XE_SWIDE_OVRUN)
+			--resid;
+	}
+
+	/*
+	 *  If all data has been transferred,
+	 *  there is no residual.
+	 */
+	if (cp->phys.head.lastp == sym_goalp(cp))
+		return resid;
+
+	/*
+	 *  If no data transfer occurs, or if the data
+	 *  pointer is weird, return full residual.
+	 */
+	if (cp->startp == cp->phys.head.lastp ||
+	    sym_evaluate_dp(np, cp, scr_to_cpu(cp->phys.head.lastp),
+			    &dp_ofs) < 0) {
+		return cp->data_len;
+	}
+
+	/*
+	 *  If we were auto-sensing, then we are done.
+	 */
+	if (cp->host_flags & HF_SENSE) {
+		return -dp_ofs;
+	}
+
+	/*
+	 *  We are now full comfortable in the computation 
+	 *  of the data residual (2's complement).
+	 */
+	dp_sgmin = SYM_CONF_MAX_SG - cp->segments;
+	resid = -cp->ext_ofs;
+	for (dp_sg = cp->ext_sg; dp_sg < SYM_CONF_MAX_SG; ++dp_sg) {
+		u_int tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+		resid += (tmp & 0xffffff);
+	}
+
+	/*
+	 *  Hopefully, the result is not too wrong.
+	 */
+	return resid;
+}
+
+/*
+ *  Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
+ *
+ *  When we try to negotiate, we append the negotiation message
+ *  to the identify and (maybe) simple tag message.
+ *  The host status field is set to HS_NEGOTIATE to mark this
+ *  situation.
+ *
+ *  If the target doesn't answer this message immediately
+ *  (as required by the standard), the SIR_NEGO_FAILED interrupt
+ *  will be raised eventually.
+ *  The handler removes the HS_NEGOTIATE status, and sets the
+ *  negotiated value to the default (async / nowide).
+ *
+ *  If we receive a matching answer immediately, we check it
+ *  for validity, and set the values.
+ *
+ *  If we receive a Reject message immediately, we assume the
+ *  negotiation has failed, and fall back to standard values.
+ *
+ *  If we receive a negotiation message while not in HS_NEGOTIATE
+ *  state, it's a target initiated negotiation. We prepare a
+ *  (hopefully) valid answer, set our parameters, and send back 
+ *  this answer to the target.
+ *
+ *  If the target doesn't fetch the answer (no message out phase),
+ *  we assume the negotiation has failed, and fall back to default
+ *  settings (SIR_NEGO_PROTO interrupt).
+ *
+ *  When we set the values, we adjust them in all ccbs belonging 
+ *  to this target, in the controller's register, and in the "phys"
+ *  field of the controller's struct sym_hcb.
+ */
+
+/*
+ *  chip handler for SYNCHRONOUS DATA TRANSFER REQUEST (SDTR) message.
+ */
+static int  
+sym_sync_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp)
+{
+	int target = cp->target;
+	u_char	chg, ofs, per, fak, div;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "sync msgin", np->msgin);
+	}
+
+	/*
+	 *  Get requested values.
+	 */
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[4];
+
+	/*
+	 *  Check values against our limits.
+	 */
+	if (ofs) {
+		if (ofs > np->maxoffs)
+			{chg = 1; ofs = np->maxoffs;}
+	}
+
+	if (ofs) {
+		if (per < np->minsync)
+			{chg = 1; per = np->minsync;}
+	}
+
+	/*
+	 *  Get new chip synchronous parameters value.
+	 */
+	div = fak = 0;
+	if (ofs && sym_getsync(np, 0, per, &div, &fak) < 0)
+		goto reject_it;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_addr(cp->cmd,
+				"sdtr: ofs=%d per=%d div=%d fak=%d chg=%d.\n",
+				ofs, per, div, fak, chg);
+	}
+
+	/*
+	 *  If it was an answer we want to change, 
+	 *  then it isn't acceptable. Reject it.
+	 */
+	if (!req && chg)
+		goto reject_it;
+
+	/*
+	 *  Apply new values.
+	 */
+	sym_setsync (np, target, ofs, per, div, fak);
+
+	/*
+	 *  It was an answer. We are done.
+	 */
+	if (!req)
+		return 0;
+
+	/*
+	 *  It was a request. Prepare an answer message.
+	 */
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 3;
+	np->msgout[2] = M_X_SYNC_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = ofs;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "sync msgout", np->msgout);
+	}
+
+	np->msgin [0] = M_NOOP;
+
+	return 0;
+
+reject_it:
+	sym_setsync (np, target, 0, 0, 0, 0);
+	return -1;
+}
+
+static void sym_sync_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
+{
+	int req = 1;
+	int result;
+
+	/*
+	 *  Request or answer ?
+	 */
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
+		if (cp->nego_status && cp->nego_status != NS_SYNC)
+			goto reject_it;
+		req = 0;
+	}
+
+	/*
+	 *  Check and apply new values.
+	 */
+	result = sym_sync_nego_check(np, req, cp);
+	if (result)	/* Not acceptable, reject it */
+		goto reject_it;
+	if (req) {	/* Was a request, send response. */
+		cp->nego_status = NS_SYNC;
+		OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp));
+	}
+	else		/* Was a response, we are done. */
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	return;
+
+reject_it:
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
+}
+
+/*
+ *  chip handler for PARALLEL PROTOCOL REQUEST (PPR) message.
+ */
+static int 
+sym_ppr_nego_check(struct sym_hcb *np, int req, int target)
+{
+	struct sym_tcb *tp = &np->target[target];
+	unsigned char fak, div;
+	int dt, chg = 0;
+
+	unsigned char per = np->msgin[3];
+	unsigned char ofs = np->msgin[5];
+	unsigned char wide = np->msgin[6];
+	unsigned char opts = np->msgin[7] & PPR_OPT_MASK;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "ppr msgin", np->msgin);
+	}
+
+	/*
+	 *  Check values against our limits.
+	 */
+	if (wide > np->maxwide) {
+		chg = 1;
+		wide = np->maxwide;
+	}
+	if (!wide || !(np->features & FE_U3EN))
+		opts = 0;
+
+	if (opts != (np->msgin[7] & PPR_OPT_MASK))
+		chg = 1;
+
+	dt = opts & PPR_OPT_DT;
+
+	if (ofs) {
+		unsigned char maxoffs = dt ? np->maxoffs_dt : np->maxoffs;
+		if (ofs > maxoffs) {
+			chg = 1;
+			ofs = maxoffs;
+		}
+	}
+
+	if (ofs) {
+		unsigned char minsync = dt ? np->minsync_dt : np->minsync;
+		if (per < minsync) {
+			chg = 1;
+			per = minsync;
+		}
+	}
+
+	/*
+	 *  Get new chip synchronous parameters value.
+	 */
+	div = fak = 0;
+	if (ofs && sym_getsync(np, dt, per, &div, &fak) < 0)
+		goto reject_it;
+
+	/*
+	 *  If it was an answer we want to change, 
+	 *  then it isn't acceptable. Reject it.
+	 */
+	if (!req && chg)
+		goto reject_it;
+
+	/*
+	 *  Apply new values.
+	 */
+	sym_setpprot(np, target, opts, ofs, per, wide, div, fak);
+
+	/*
+	 *  It was an answer. We are done.
+	 */
+	if (!req)
+		return 0;
+
+	/*
+	 *  It was a request. Prepare an answer message.
+	 */
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 6;
+	np->msgout[2] = M_X_PPR_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = 0;
+	np->msgout[5] = ofs;
+	np->msgout[6] = wide;
+	np->msgout[7] = opts;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "ppr msgout", np->msgout);
+	}
+
+	np->msgin [0] = M_NOOP;
+
+	return 0;
+
+reject_it:
+	sym_setpprot (np, target, 0, 0, 0, 0, 0, 0);
+	/*
+	 *  If it is a device response that should result in  
+	 *  ST, we may want to try a legacy negotiation later.
+	 */
+	if (!req && !opts) {
+		tp->tgoal.period = per;
+		tp->tgoal.offset = ofs;
+		tp->tgoal.width = wide;
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+		tp->tgoal.check_nego = 1;
+	}
+	return -1;
+}
+
+static void sym_ppr_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
+{
+	int req = 1;
+	int result;
+
+	/*
+	 *  Request or answer ?
+	 */
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
+		if (cp->nego_status && cp->nego_status != NS_PPR)
+			goto reject_it;
+		req = 0;
+	}
+
+	/*
+	 *  Check and apply new values.
+	 */
+	result = sym_ppr_nego_check(np, req, cp->target);
+	if (result)	/* Not acceptable, reject it */
+		goto reject_it;
+	if (req) {	/* Was a request, send response. */
+		cp->nego_status = NS_PPR;
+		OUTL_DSP(np, SCRIPTB_BA(np, ppr_resp));
+	}
+	else		/* Was a response, we are done. */
+		OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	return;
+
+reject_it:
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
+}
+
+/*
+ *  chip handler for WIDE DATA TRANSFER REQUEST (WDTR) message.
+ */
+static int  
+sym_wide_nego_check(struct sym_hcb *np, int req, struct sym_ccb *cp)
+{
+	int target = cp->target;
+	u_char	chg, wide;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "wide msgin", np->msgin);
+	}
+
+	/*
+	 *  Get requested values.
+	 */
+	chg  = 0;
+	wide = np->msgin[3];
+
+	/*
+	 *  Check values against our limits.
+	 */
+	if (wide > np->maxwide) {
+		chg = 1;
+		wide = np->maxwide;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_addr(cp->cmd, "wdtr: wide=%d chg=%d.\n",
+				wide, chg);
+	}
+
+	/*
+	 *  If it was an answer we want to change, 
+	 *  then it isn't acceptable. Reject it.
+	 */
+	if (!req && chg)
+		goto reject_it;
+
+	/*
+	 *  Apply new values.
+	 */
+	sym_setwide (np, target, wide);
+
+	/*
+	 *  It was an answer. We are done.
+	 */
+	if (!req)
+		return 0;
+
+	/*
+	 *  It was a request. Prepare an answer message.
+	 */
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 2;
+	np->msgout[2] = M_X_WIDE_REQ;
+	np->msgout[3] = wide;
+
+	np->msgin [0] = M_NOOP;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		sym_print_nego_msg(np, target, "wide msgout", np->msgout);
+	}
+
+	return 0;
+
+reject_it:
+	return -1;
+}
+
+static void sym_wide_nego(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
+{
+	int req = 1;
+	int result;
+
+	/*
+	 *  Request or answer ?
+	 */
+	if (INB(np, HS_PRT) == HS_NEGOTIATE) {
+		OUTB(np, HS_PRT, HS_BUSY);
+		if (cp->nego_status && cp->nego_status != NS_WIDE)
+			goto reject_it;
+		req = 0;
+	}
+
+	/*
+	 *  Check and apply new values.
+	 */
+	result = sym_wide_nego_check(np, req, cp);
+	if (result)	/* Not acceptable, reject it */
+		goto reject_it;
+	if (req) {	/* Was a request, send response. */
+		cp->nego_status = NS_WIDE;
+		OUTL_DSP(np, SCRIPTB_BA(np, wdtr_resp));
+	} else {		/* Was a response. */
+		/*
+		 * Negotiate for SYNC immediately after WIDE response.
+		 * This allows to negotiate for both WIDE and SYNC on 
+		 * a single SCSI command (Suggested by Justin Gibbs).
+		 */
+		if (tp->tgoal.offset) {
+			np->msgout[0] = M_EXTENDED;
+			np->msgout[1] = 3;
+			np->msgout[2] = M_X_SYNC_REQ;
+			np->msgout[3] = tp->tgoal.period;
+			np->msgout[4] = tp->tgoal.offset;
+
+			if (DEBUG_FLAGS & DEBUG_NEGO) {
+				sym_print_nego_msg(np, cp->target,
+				                   "sync msgout", np->msgout);
+			}
+
+			cp->nego_status = NS_SYNC;
+			OUTB(np, HS_PRT, HS_NEGOTIATE);
+			OUTL_DSP(np, SCRIPTB_BA(np, sdtr_resp));
+			return;
+		} else
+			OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	}
+
+	return;
+
+reject_it:
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
+}
+
+/*
+ *  Reset DT, SYNC or WIDE to default settings.
+ *
+ *  Called when a negotiation does not succeed either 
+ *  on rejection or on protocol error.
+ *
+ *  A target that understands a PPR message should never 
+ *  reject it, and messing with it is very unlikely.
+ *  So, if a PPR makes problems, we may just want to 
+ *  try a legacy negotiation later.
+ */
+static void sym_nego_default(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
+{
+	switch (cp->nego_status) {
+	case NS_PPR:
+#if 0
+		sym_setpprot (np, cp->target, 0, 0, 0, 0, 0, 0);
+#else
+		if (tp->tgoal.period < np->minsync)
+			tp->tgoal.period = np->minsync;
+		if (tp->tgoal.offset > np->maxoffs)
+			tp->tgoal.offset = np->maxoffs;
+		tp->tgoal.iu = tp->tgoal.dt = tp->tgoal.qas = 0;
+		tp->tgoal.check_nego = 1;
+#endif
+		break;
+	case NS_SYNC:
+		sym_setsync (np, cp->target, 0, 0, 0, 0);
+		break;
+	case NS_WIDE:
+		sym_setwide (np, cp->target, 0);
+		break;
+	}
+	np->msgin [0] = M_NOOP;
+	np->msgout[0] = M_NOOP;
+	cp->nego_status = 0;
+}
+
+/*
+ *  chip handler for MESSAGE REJECT received in response to 
+ *  PPR, WIDE or SYNCHRONOUS negotiation.
+ */
+static void sym_nego_rejected(struct sym_hcb *np, struct sym_tcb *tp, struct sym_ccb *cp)
+{
+	sym_nego_default(np, tp, cp);
+	OUTB(np, HS_PRT, HS_BUSY);
+}
+
+/*
+ *  chip exception handler for programmed interrupts.
+ */
+static void sym_int_sir (struct sym_hcb *np)
+{
+	u_char	num	= INB(np, nc_dsps);
+	u32	dsa	= INL(np, nc_dsa);
+	struct sym_ccb *cp	= sym_ccb_from_dsa(np, dsa);
+	u_char	target	= INB(np, nc_sdid) & 0x0f;
+	struct sym_tcb *tp	= &np->target[target];
+	int	tmp;
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num);
+
+	switch (num) {
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 2
+	/*
+	 *  SCRIPTS tell us that we may have to update 
+	 *  64 bit DMA segment registers.
+	 */
+	case SIR_DMAP_DIRTY:
+		sym_update_dmap_regs(np);
+		goto out;
+#endif
+	/*
+	 *  Command has been completed with error condition 
+	 *  or has been auto-sensed.
+	 */
+	case SIR_COMPLETE_ERROR:
+		sym_complete_error(np, cp);
+		return;
+	/*
+	 *  The C code is currently trying to recover from something.
+	 *  Typically, user want to abort some command.
+	 */
+	case SIR_SCRIPT_STOPPED:
+	case SIR_TARGET_SELECTED:
+	case SIR_ABORT_SENT:
+		sym_sir_task_recovery(np, num);
+		return;
+	/*
+	 *  The device didn't go to MSG OUT phase after having 
+	 *  been selected with ATN. We donnot want to handle 
+	 *  that.
+	 */
+	case SIR_SEL_ATN_NO_MSG_OUT:
+		printf ("%s:%d: No MSG OUT phase after selection with ATN.\n",
+			sym_name (np), target);
+		goto out_stuck;
+	/*
+	 *  The device didn't switch to MSG IN phase after 
+	 *  having reseleted the initiator.
+	 */
+	case SIR_RESEL_NO_MSG_IN:
+		printf ("%s:%d: No MSG IN phase after reselection.\n",
+			sym_name (np), target);
+		goto out_stuck;
+	/*
+	 *  After reselection, the device sent a message that wasn't 
+	 *  an IDENTIFY.
+	 */
+	case SIR_RESEL_NO_IDENTIFY:
+		printf ("%s:%d: No IDENTIFY after reselection.\n",
+			sym_name (np), target);
+		goto out_stuck;
+	/*
+	 *  The device reselected a LUN we donnot know about.
+	 */
+	case SIR_RESEL_BAD_LUN:
+		np->msgout[0] = M_RESET;
+		goto out;
+	/*
+	 *  The device reselected for an untagged nexus and we 
+	 *  haven't any.
+	 */
+	case SIR_RESEL_BAD_I_T_L:
+		np->msgout[0] = M_ABORT;
+		goto out;
+	/*
+	 *  The device reselected for a tagged nexus that we donnot 
+	 *  have.
+	 */
+	case SIR_RESEL_BAD_I_T_L_Q:
+		np->msgout[0] = M_ABORT_TAG;
+		goto out;
+	/*
+	 *  The SCRIPTS let us know that the device has grabbed 
+	 *  our message and will abort the job.
+	 */
+	case SIR_RESEL_ABORTED:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		printf ("%s:%d: message %x sent on bad reselection.\n",
+			sym_name (np), target, np->lastmsg);
+		goto out;
+	/*
+	 *  The SCRIPTS let us know that a message has been 
+	 *  successfully sent to the device.
+	 */
+	case SIR_MSG_OUT_DONE:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		/* Should we really care of that */
+		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
+			if (cp) {
+				cp->xerr_status &= ~XE_PARITY_ERR;
+				if (!cp->xerr_status)
+					OUTOFFB(np, HF_PRT, HF_EXT_ERR);
+			}
+		}
+		goto out;
+	/*
+	 *  The device didn't send a GOOD SCSI status.
+	 *  We may have some work to do prior to allow 
+	 *  the SCRIPTS processor to continue.
+	 */
+	case SIR_BAD_SCSI_STATUS:
+		if (!cp)
+			goto out;
+		sym_sir_bad_scsi_status(np, num, cp);
+		return;
+	/*
+	 *  We are asked by the SCRIPTS to prepare a 
+	 *  REJECT message.
+	 */
+	case SIR_REJECT_TO_SEND:
+		sym_print_msg(cp, "M_REJECT to send for ", np->msgin);
+		np->msgout[0] = M_REJECT;
+		goto out;
+	/*
+	 *  We have been ODD at the end of a DATA IN 
+	 *  transfer and the device didn't send a 
+	 *  IGNORE WIDE RESIDUE message.
+	 *  It is a data overrun condition.
+	 */
+	case SIR_SWIDE_OVERRUN:
+		if (cp) {
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_SWIDE_OVRUN;
+		}
+		goto out;
+	/*
+	 *  We have been ODD at the end of a DATA OUT 
+	 *  transfer.
+	 *  It is a data underrun condition.
+	 */
+	case SIR_SODL_UNDERRUN:
+		if (cp) {
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_SODL_UNRUN;
+		}
+		goto out;
+	/*
+	 *  The device wants us to tranfer more data than 
+	 *  expected or in the wrong direction.
+	 *  The number of extra bytes is in scratcha.
+	 *  It is a data overrun condition.
+	 */
+	case SIR_DATA_OVERRUN:
+		if (cp) {
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_EXTRA_DATA;
+			cp->extra_bytes += INL(np, nc_scratcha);
+		}
+		goto out;
+	/*
+	 *  The device switched to an illegal phase (4/5).
+	 */
+	case SIR_BAD_PHASE:
+		if (cp) {
+			OUTONB(np, HF_PRT, HF_EXT_ERR);
+			cp->xerr_status |= XE_BAD_PHASE;
+		}
+		goto out;
+	/*
+	 *  We received a message.
+	 */
+	case SIR_MSG_RECEIVED:
+		if (!cp)
+			goto out_stuck;
+		switch (np->msgin [0]) {
+		/*
+		 *  We received an extended message.
+		 *  We handle MODIFY DATA POINTER, SDTR, WDTR 
+		 *  and reject all other extended messages.
+		 */
+		case M_EXTENDED:
+			switch (np->msgin [2]) {
+			case M_X_MODIFY_DP:
+				if (DEBUG_FLAGS & DEBUG_POINTER)
+					sym_print_msg(cp,"modify DP",np->msgin);
+				tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 
+				      (np->msgin[5]<<8)  + (np->msgin[6]);
+				sym_modify_dp(np, tp, cp, tmp);
+				return;
+			case M_X_SYNC_REQ:
+				sym_sync_nego(np, tp, cp);
+				return;
+			case M_X_PPR_REQ:
+				sym_ppr_nego(np, tp, cp);
+				return;
+			case M_X_WIDE_REQ:
+				sym_wide_nego(np, tp, cp);
+				return;
+			default:
+				goto out_reject;
+			}
+			break;
+		/*
+		 *  We received a 1/2 byte message not handled from SCRIPTS.
+		 *  We are only expecting MESSAGE REJECT and IGNORE WIDE 
+		 *  RESIDUE messages that haven't been anticipated by 
+		 *  SCRIPTS on SWIDE full condition. Unanticipated IGNORE 
+		 *  WIDE RESIDUE messages are aliased as MODIFY DP (-1).
+		 */
+		case M_IGN_RESIDUE:
+			if (DEBUG_FLAGS & DEBUG_POINTER)
+				sym_print_msg(cp,"ign wide residue", np->msgin);
+			if (cp->host_flags & HF_SENSE)
+				OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+			else
+				sym_modify_dp(np, tp, cp, -1);
+			return;
+		case M_REJECT:
+			if (INB(np, HS_PRT) == HS_NEGOTIATE)
+				sym_nego_rejected(np, tp, cp);
+			else {
+				sym_print_addr(cp->cmd,
+					"M_REJECT received (%x:%x).\n",
+					scr_to_cpu(np->lastmsg), np->msgout[0]);
+			}
+			goto out_clrack;
+			break;
+		default:
+			goto out_reject;
+		}
+		break;
+	/*
+	 *  We received an unknown message.
+	 *  Ignore all MSG IN phases and reject it.
+	 */
+	case SIR_MSG_WEIRD:
+		sym_print_msg(cp, "WEIRD message received", np->msgin);
+		OUTL_DSP(np, SCRIPTB_BA(np, msg_weird));
+		return;
+	/*
+	 *  Negotiation failed.
+	 *  Target does not send us the reply.
+	 *  Remove the HS_NEGOTIATE status.
+	 */
+	case SIR_NEGO_FAILED:
+		OUTB(np, HS_PRT, HS_BUSY);
+	/*
+	 *  Negotiation failed.
+	 *  Target does not want answer message.
+	 */
+	case SIR_NEGO_PROTO:
+		sym_nego_default(np, tp, cp);
+		goto out;
+	}
+
+out:
+	OUTONB_STD();
+	return;
+out_reject:
+	OUTL_DSP(np, SCRIPTB_BA(np, msg_bad));
+	return;
+out_clrack:
+	OUTL_DSP(np, SCRIPTA_BA(np, clrack));
+	return;
+out_stuck:
+	return;
+}
+
+/*
+ *  Acquire a control block
+ */
+struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order)
+{
+	u_char tn = cmd->device->id;
+	u_char ln = cmd->device->lun;
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
+	u_short tag = NO_TAG;
+	SYM_QUEHEAD *qp;
+	struct sym_ccb *cp = NULL;
+
+	/*
+	 *  Look for a free CCB
+	 */
+	if (sym_que_empty(&np->free_ccbq))
+		sym_alloc_ccb(np);
+	qp = sym_remque_head(&np->free_ccbq);
+	if (!qp)
+		goto out;
+	cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  If the LCB is not yet available and the LUN
+	 *  has been probed ok, try to allocate the LCB.
+	 */
+	if (!lp && sym_is_bit(tp->lun_map, ln)) {
+		lp = sym_alloc_lcb(np, tn, ln);
+		if (!lp)
+			goto out_free;
+	}
+#endif
+
+	/*
+	 *  If the LCB is not available here, then the 
+	 *  logical unit is not yet discovered. For those 
+	 *  ones only accept 1 SCSI IO per logical unit, 
+	 *  since we cannot allow disconnections.
+	 */
+	if (!lp) {
+		if (!sym_is_bit(tp->busy0_map, ln))
+			sym_set_bit(tp->busy0_map, ln);
+		else
+			goto out_free;
+	} else {
+		/*
+		 *  If we have been asked for a tagged command.
+		 */
+		if (tag_order) {
+			/*
+			 *  Debugging purpose.
+			 */
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+			assert(lp->busy_itl == 0);
+#endif
+			/*
+			 *  Allocate resources for tags if not yet.
+			 */
+			if (!lp->cb_tags) {
+				sym_alloc_lcb_tags(np, tn, ln);
+				if (!lp->cb_tags)
+					goto out_free;
+			}
+			/*
+			 *  Get a tag for this SCSI IO and set up
+			 *  the CCB bus address for reselection, 
+			 *  and count it for this LUN.
+			 *  Toggle reselect path to tagged.
+			 */
+			if (lp->busy_itlq < SYM_CONF_MAX_TASK) {
+				tag = lp->cb_tags[lp->ia_tag];
+				if (++lp->ia_tag == SYM_CONF_MAX_TASK)
+					lp->ia_tag = 0;
+				++lp->busy_itlq;
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+				lp->itlq_tbl[tag] = cpu_to_scr(cp->ccb_ba);
+				lp->head.resel_sa =
+					cpu_to_scr(SCRIPTA_BA(np, resel_tag));
+#endif
+#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
+				cp->tags_si = lp->tags_si;
+				++lp->tags_sum[cp->tags_si];
+				++lp->tags_since;
+#endif
+			}
+			else
+				goto out_free;
+		}
+		/*
+		 *  This command will not be tagged.
+		 *  If we already have either a tagged or untagged 
+		 *  one, refuse to overlap this untagged one.
+		 */
+		else {
+			/*
+			 *  Debugging purpose.
+			 */
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+			assert(lp->busy_itl == 0 && lp->busy_itlq == 0);
+#endif
+			/*
+			 *  Count this nexus for this LUN.
+			 *  Set up the CCB bus address for reselection.
+			 *  Toggle reselect path to untagged.
+			 */
+			++lp->busy_itl;
+#ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING
+			if (lp->busy_itl == 1) {
+				lp->head.itl_task_sa = cpu_to_scr(cp->ccb_ba);
+				lp->head.resel_sa =
+				      cpu_to_scr(SCRIPTA_BA(np, resel_no_tag));
+			}
+			else
+				goto out_free;
+#endif
+		}
+	}
+	/*
+	 *  Put the CCB into the busy queue.
+	 */
+	sym_insque_tail(&cp->link_ccbq, &np->busy_ccbq);
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	if (lp) {
+		sym_remque(&cp->link2_ccbq);
+		sym_insque_tail(&cp->link2_ccbq, &lp->waiting_ccbq);
+	}
+
+#endif
+	/*
+	 *  Remember all informations needed to free this CCB.
+	 */
+	cp->to_abort = 0;
+	cp->tag	   = tag;
+	cp->order  = tag_order;
+	cp->target = tn;
+	cp->lun    = ln;
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		sym_print_addr(cmd, "ccb @%p using tag %d.\n", cp, tag);
+	}
+
+out:
+	return cp;
+out_free:
+	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
+	return NULL;
+}
+
+/*
+ *  Release one control block
+ */
+void sym_free_ccb (struct sym_hcb *np, struct sym_ccb *cp)
+{
+	struct sym_tcb *tp = &np->target[cp->target];
+	struct sym_lcb *lp = sym_lp(tp, cp->lun);
+
+	if (DEBUG_FLAGS & DEBUG_TAGS) {
+		sym_print_addr(cp->cmd, "ccb @%p freeing tag %d.\n",
+				cp, cp->tag);
+	}
+
+	/*
+	 *  If LCB available,
+	 */
+	if (lp) {
+		/*
+		 *  If tagged, release the tag, set the relect path 
+		 */
+		if (cp->tag != NO_TAG) {
+#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
+			--lp->tags_sum[cp->tags_si];
+#endif
+			/*
+			 *  Free the tag value.
+			 */
+			lp->cb_tags[lp->if_tag] = cp->tag;
+			if (++lp->if_tag == SYM_CONF_MAX_TASK)
+				lp->if_tag = 0;
+			/*
+			 *  Make the reselect path invalid, 
+			 *  and uncount this CCB.
+			 */
+			lp->itlq_tbl[cp->tag] = cpu_to_scr(np->bad_itlq_ba);
+			--lp->busy_itlq;
+		} else {	/* Untagged */
+			/*
+			 *  Make the reselect path invalid, 
+			 *  and uncount this CCB.
+			 */
+			lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba);
+			--lp->busy_itl;
+		}
+		/*
+		 *  If no JOB active, make the LUN reselect path invalid.
+		 */
+		if (lp->busy_itlq == 0 && lp->busy_itl == 0)
+			lp->head.resel_sa =
+				cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
+	}
+	/*
+	 *  Otherwise, we only accept 1 IO per LUN.
+	 *  Clear the bit that keeps track of this IO.
+	 */
+	else
+		sym_clr_bit(tp->busy0_map, cp->lun);
+
+	/*
+	 *  We donnot queue more than 1 ccb per target 
+	 *  with negotiation at any time. If this ccb was 
+	 *  used for negotiation, clear this info in the tcb.
+	 */
+	if (cp == tp->nego_cp)
+		tp->nego_cp = NULL;
+
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *  If we just complete the last queued CCB,
+	 *  clear this info that is no longer relevant.
+	 */
+	if (cp == np->last_cp)
+		np->last_cp = 0;
+#endif
+
+	/*
+	 *  Make this CCB available.
+	 */
+	cp->cmd = NULL;
+	cp->host_status = HS_IDLE;
+	sym_remque(&cp->link_ccbq);
+	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	if (lp) {
+		sym_remque(&cp->link2_ccbq);
+		sym_insque_tail(&cp->link2_ccbq, &np->dummy_ccbq);
+		if (cp->started) {
+			if (cp->tag != NO_TAG)
+				--lp->started_tags;
+			else
+				--lp->started_no_tag;
+		}
+	}
+	cp->started = 0;
+#endif
+}
+
+/*
+ *  Allocate a CCB from memory and initialize its fixed part.
+ */
+static struct sym_ccb *sym_alloc_ccb(struct sym_hcb *np)
+{
+	struct sym_ccb *cp = NULL;
+	int hcode;
+
+	/*
+	 *  Prevent from allocating more CCBs than we can 
+	 *  queue to the controller.
+	 */
+	if (np->actccbs >= SYM_CONF_MAX_START)
+		return NULL;
+
+	/*
+	 *  Allocate memory for this CCB.
+	 */
+	cp = sym_calloc_dma(sizeof(struct sym_ccb), "CCB");
+	if (!cp)
+		goto out_free;
+
+	/*
+	 *  Count it.
+	 */
+	np->actccbs++;
+
+	/*
+	 *  Compute the bus address of this ccb.
+	 */
+	cp->ccb_ba = vtobus(cp);
+
+	/*
+	 *  Insert this ccb into the hashed list.
+	 */
+	hcode = CCB_HASH_CODE(cp->ccb_ba);
+	cp->link_ccbh = np->ccbh[hcode];
+	np->ccbh[hcode] = cp;
+
+	/*
+	 *  Initialyze the start and restart actions.
+	 */
+	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA(np, idle));
+	cp->phys.head.go.restart = cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
+
+ 	/*
+	 *  Initilialyze some other fields.
+	 */
+	cp->phys.smsg_ext.addr = cpu_to_scr(HCB_BA(np, msgin[2]));
+
+	/*
+	 *  Chain into free ccb queue.
+	 */
+	sym_insque_head(&cp->link_ccbq, &np->free_ccbq);
+
+	/*
+	 *  Chain into optionnal lists.
+	 */
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	sym_insque_head(&cp->link2_ccbq, &np->dummy_ccbq);
+#endif
+	return cp;
+out_free:
+	if (cp)
+		sym_mfree_dma(cp, sizeof(*cp), "CCB");
+	return NULL;
+}
+
+/*
+ *  Look up a CCB from a DSA value.
+ */
+static struct sym_ccb *sym_ccb_from_dsa(struct sym_hcb *np, u32 dsa)
+{
+	int hcode;
+	struct sym_ccb *cp;
+
+	hcode = CCB_HASH_CODE(dsa);
+	cp = np->ccbh[hcode];
+	while (cp) {
+		if (cp->ccb_ba == dsa)
+			break;
+		cp = cp->link_ccbh;
+	}
+
+	return cp;
+}
+
+/*
+ *  Target control block initialisation.
+ *  Nothing important to do at the moment.
+ */
+static void sym_init_tcb (struct sym_hcb *np, u_char tn)
+{
+#if 0	/*  Hmmm... this checking looks paranoid. */
+	/*
+	 *  Check some alignments required by the chip.
+	 */	
+	assert (((offsetof(struct sym_reg, nc_sxfer) ^
+		offsetof(struct sym_tcb, head.sval)) &3) == 0);
+	assert (((offsetof(struct sym_reg, nc_scntl3) ^
+		offsetof(struct sym_tcb, head.wval)) &3) == 0);
+#endif
+}
+
+/*
+ *  Lun control block allocation and initialization.
+ */
+struct sym_lcb *sym_alloc_lcb (struct sym_hcb *np, u_char tn, u_char ln)
+{
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
+
+	/*
+	 *  Already done, just return.
+	 */
+	if (lp)
+		return lp;
+
+	/*
+	 *  Donnot allow LUN control block 
+	 *  allocation for not probed LUNs.
+	 */
+	if (!sym_is_bit(tp->lun_map, ln))
+		return NULL;
+
+	/*
+	 *  Initialize the target control block if not yet.
+	 */
+	sym_init_tcb (np, tn);
+
+	/*
+	 *  Allocate the LCB bus address array.
+	 *  Compute the bus address of this table.
+	 */
+	if (ln && !tp->luntbl) {
+		int i;
+
+		tp->luntbl = sym_calloc_dma(256, "LUNTBL");
+		if (!tp->luntbl)
+			goto fail;
+		for (i = 0 ; i < 64 ; i++)
+			tp->luntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
+		tp->head.luntbl_sa = cpu_to_scr(vtobus(tp->luntbl));
+	}
+
+	/*
+	 *  Allocate the table of pointers for LUN(s) > 0, if needed.
+	 */
+	if (ln && !tp->lunmp) {
+		tp->lunmp = kcalloc(SYM_CONF_MAX_LUN, sizeof(struct sym_lcb *),
+				GFP_KERNEL);
+		if (!tp->lunmp)
+			goto fail;
+	}
+
+	/*
+	 *  Allocate the lcb.
+	 *  Make it available to the chip.
+	 */
+	lp = sym_calloc_dma(sizeof(struct sym_lcb), "LCB");
+	if (!lp)
+		goto fail;
+	if (ln) {
+		tp->lunmp[ln] = lp;
+		tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	}
+	else {
+		tp->lun0p = lp;
+		tp->head.lun0_sa = cpu_to_scr(vtobus(lp));
+	}
+
+	/*
+	 *  Let the itl task point to error handling.
+	 */
+	lp->head.itl_task_sa = cpu_to_scr(np->bad_itl_ba);
+
+	/*
+	 *  Set the reselect pattern to our default. :)
+	 */
+	lp->head.resel_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
+
+	/*
+	 *  Set user capabilities.
+	 */
+	lp->user_flags = tp->usrflags & (SYM_DISC_ENABLED | SYM_TAGS_ENABLED);
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  Initialize device queueing.
+	 */
+	sym_que_init(&lp->waiting_ccbq);
+	sym_que_init(&lp->started_ccbq);
+	lp->started_max   = SYM_CONF_MAX_TASK;
+	lp->started_limit = SYM_CONF_MAX_TASK;
+#endif
+	/*
+	 *  If we are busy, count the IO.
+	 */
+	if (sym_is_bit(tp->busy0_map, ln)) {
+		lp->busy_itl = 1;
+		sym_clr_bit(tp->busy0_map, ln);
+	}
+fail:
+	return lp;
+}
+
+/*
+ *  Allocate LCB resources for tagged command queuing.
+ */
+static void sym_alloc_lcb_tags (struct sym_hcb *np, u_char tn, u_char ln)
+{
+	struct sym_tcb *tp = &np->target[tn];
+	struct sym_lcb *lp = sym_lp(tp, ln);
+	int i;
+
+	/*
+	 *  If LCB not available, try to allocate it.
+	 */
+	if (!lp && !(lp = sym_alloc_lcb(np, tn, ln)))
+		goto fail;
+
+	/*
+	 *  Allocate the task table and and the tag allocation 
+	 *  circular buffer. We want both or none.
+	 */
+	lp->itlq_tbl = sym_calloc_dma(SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
+	if (!lp->itlq_tbl)
+		goto fail;
+	lp->cb_tags = kcalloc(SYM_CONF_MAX_TASK, 1, GFP_KERNEL);
+	if (!lp->cb_tags) {
+		sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4, "ITLQ_TBL");
+		lp->itlq_tbl = NULL;
+		goto fail;
+	}
+
+	/*
+	 *  Initialize the task table with invalid entries.
+	 */
+	for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++)
+		lp->itlq_tbl[i] = cpu_to_scr(np->notask_ba);
+
+	/*
+	 *  Fill up the tag buffer with tag numbers.
+	 */
+	for (i = 0 ; i < SYM_CONF_MAX_TASK ; i++)
+		lp->cb_tags[i] = i;
+
+	/*
+	 *  Make the task table available to SCRIPTS, 
+	 *  And accept tagged commands now.
+	 */
+	lp->head.itlq_tbl_sa = cpu_to_scr(vtobus(lp->itlq_tbl));
+
+	return;
+fail:
+	return;
+}
+
+/*
+ *  Queue a SCSI IO to the controller.
+ */
+int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
+{
+	struct scsi_device *sdev = cmd->device;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	u_char	*msgptr;
+	u_int   msglen;
+	int can_disconnect;
+
+	/*
+	 *  Keep track of the IO in our CCB.
+	 */
+	cp->cmd = cmd;
+
+	/*
+	 *  Retrieve the target descriptor.
+	 */
+	tp = &np->target[cp->target];
+
+	/*
+	 *  Retrieve the lun descriptor.
+	 */
+	lp = sym_lp(tp, sdev->lun);
+
+	can_disconnect = (cp->tag != NO_TAG) ||
+		(lp && (lp->curr_flags & SYM_DISC_ENABLED));
+
+	msgptr = cp->scsi_smsg;
+	msglen = 0;
+	msgptr[msglen++] = IDENTIFY(can_disconnect, sdev->lun);
+
+	/*
+	 *  Build the tag message if present.
+	 */
+	if (cp->tag != NO_TAG) {
+		u_char order = cp->order;
+
+		switch(order) {
+		case M_ORDERED_TAG:
+			break;
+		case M_HEAD_TAG:
+			break;
+		default:
+			order = M_SIMPLE_TAG;
+		}
+#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
+		/*
+		 *  Avoid too much reordering of SCSI commands.
+		 *  The algorithm tries to prevent completion of any 
+		 *  tagged command from being delayed against more 
+		 *  than 3 times the max number of queued commands.
+		 */
+		if (lp && lp->tags_since > 3*SYM_CONF_MAX_TAG) {
+			lp->tags_si = !(lp->tags_si);
+			if (lp->tags_sum[lp->tags_si]) {
+				order = M_ORDERED_TAG;
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||sym_verbose>1) {
+					sym_print_addr(cmd,
+						"ordered tag forced.\n");
+				}
+			}
+			lp->tags_since = 0;
+		}
+#endif
+		msgptr[msglen++] = order;
+
+		/*
+		 *  For less than 128 tags, actual tags are numbered 
+		 *  1,3,5,..2*MAXTAGS+1,since we may have to deal 
+		 *  with devices that have problems with #TAG 0 or too 
+		 *  great #TAG numbers. For more tags (up to 256), 
+		 *  we use directly our tag number.
+		 */
+#if SYM_CONF_MAX_TASK > (512/4)
+		msgptr[msglen++] = cp->tag;
+#else
+		msgptr[msglen++] = (cp->tag << 1) + 1;
+#endif
+	}
+
+	/*
+	 *  Build a negotiation message if needed.
+	 *  (nego_status is filled by sym_prepare_nego())
+	 */
+	cp->nego_status = 0;
+	if (tp->tgoal.check_nego && !tp->nego_cp && lp) {
+		msglen += sym_prepare_nego(np, cp, msgptr + msglen);
+	}
+
+	/*
+	 *  Startqueue
+	 */
+	cp->phys.head.go.start   = cpu_to_scr(SCRIPTA_BA(np, select));
+	cp->phys.head.go.restart = cpu_to_scr(SCRIPTA_BA(np, resel_dsa));
+
+	/*
+	 *  select
+	 */
+	cp->phys.select.sel_id		= cp->target;
+	cp->phys.select.sel_scntl3	= tp->head.wval;
+	cp->phys.select.sel_sxfer	= tp->head.sval;
+	cp->phys.select.sel_scntl4	= tp->head.uval;
+
+	/*
+	 *  message
+	 */
+	cp->phys.smsg.addr	= cpu_to_scr(CCB_BA(cp, scsi_smsg));
+	cp->phys.smsg.size	= cpu_to_scr(msglen);
+
+	/*
+	 *  status
+	 */
+	cp->host_xflags		= 0;
+	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+	cp->ssss_status		= S_ILLEGAL;
+	cp->xerr_status		= 0;
+	cp->host_flags		= 0;
+	cp->extra_bytes		= 0;
+
+	/*
+	 *  extreme data pointer.
+	 *  shall be positive, so -1 is lower than lowest.:)
+	 */
+	cp->ext_sg  = -1;
+	cp->ext_ofs = 0;
+
+	/*
+	 *  Build the CDB and DATA descriptor block 
+	 *  and start the IO.
+	 */
+	return sym_setup_data_and_start(np, cmd, cp);
+}
+
+/*
+ *  Reset a SCSI target (all LUNs of this target).
+ */
+int sym_reset_scsi_target(struct sym_hcb *np, int target)
+{
+	struct sym_tcb *tp;
+
+	if (target == np->myaddr || (u_int)target >= SYM_CONF_MAX_TARGET)
+		return -1;
+
+	tp = &np->target[target];
+	tp->to_reset = 1;
+
+	np->istat_sem = SEM;
+	OUTB(np, nc_istat, SIGP|SEM);
+
+	return 0;
+}
+
+/*
+ *  Abort a SCSI IO.
+ */
+static int sym_abort_ccb(struct sym_hcb *np, struct sym_ccb *cp, int timed_out)
+{
+	/*
+	 *  Check that the IO is active.
+	 */
+	if (!cp || !cp->host_status || cp->host_status == HS_WAIT)
+		return -1;
+
+	/*
+	 *  If a previous abort didn't succeed in time,
+	 *  perform a BUS reset.
+	 */
+	if (cp->to_abort) {
+		sym_reset_scsi_bus(np, 1);
+		return 0;
+	}
+
+	/*
+	 *  Mark the CCB for abort and allow time for.
+	 */
+	cp->to_abort = timed_out ? 2 : 1;
+
+	/*
+	 *  Tell the SCRIPTS processor to stop and synchronize with us.
+	 */
+	np->istat_sem = SEM;
+	OUTB(np, nc_istat, SIGP|SEM);
+	return 0;
+}
+
+int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *cmd, int timed_out)
+{
+	struct sym_ccb *cp;
+	SYM_QUEHEAD *qp;
+
+	/*
+	 *  Look up our CCB control block.
+	 */
+	cp = NULL;
+	FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) {
+		struct sym_ccb *cp2 = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+		if (cp2->cmd == cmd) {
+			cp = cp2;
+			break;
+		}
+	}
+
+	return sym_abort_ccb(np, cp, timed_out);
+}
+
+/*
+ *  Complete execution of a SCSI command with extented 
+ *  error, SCSI status error, or having been auto-sensed.
+ *
+ *  The SCRIPTS processor is not running there, so we 
+ *  can safely access IO registers and remove JOBs from  
+ *  the START queue.
+ *  SCRATCHA is assumed to have been loaded with STARTPOS 
+ *  before the SCRIPTS called the C code.
+ */
+void sym_complete_error(struct sym_hcb *np, struct sym_ccb *cp)
+{
+	struct scsi_device *sdev;
+	struct scsi_cmnd *cmd;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	int resid;
+	int i;
+
+	/*
+	 *  Paranoid check. :)
+	 */
+	if (!cp || !cp->cmd)
+		return;
+
+	cmd = cp->cmd;
+	sdev = cmd->device;
+	if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_RESULT)) {
+		dev_info(&sdev->sdev_gendev, "CCB=%p STAT=%x/%x/%x\n", cp,
+			cp->host_status, cp->ssss_status, cp->host_flags);
+	}
+
+	/*
+	 *  Get target and lun pointers.
+	 */
+	tp = &np->target[cp->target];
+	lp = sym_lp(tp, sdev->lun);
+
+	/*
+	 *  Check for extended errors.
+	 */
+	if (cp->xerr_status) {
+		if (sym_verbose)
+			sym_print_xerr(cmd, cp->xerr_status);
+		if (cp->host_status == HS_COMPLETE)
+			cp->host_status = HS_COMP_ERR;
+	}
+
+	/*
+	 *  Calculate the residual.
+	 */
+	resid = sym_compute_residual(np, cp);
+
+	if (!SYM_SETUP_RESIDUAL_SUPPORT) {/* If user does not want residuals */
+		resid  = 0;		 /* throw them away. :)		    */
+		cp->sv_resid = 0;
+	}
+#ifdef DEBUG_2_0_X
+if (resid)
+	printf("XXXX RESID= %d - 0x%x\n", resid, resid);
+#endif
+
+	/*
+	 *  Dequeue all queued CCBs for that device 
+	 *  not yet started by SCRIPTS.
+	 */
+	i = (INL(np, nc_scratcha) - np->squeue_ba) / 4;
+	i = sym_dequeue_from_squeue(np, i, cp->target, sdev->lun, -1);
+
+	/*
+	 *  Restart the SCRIPTS processor.
+	 */
+	OUTL_DSP(np, SCRIPTA_BA(np, start));
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	if (cp->host_status == HS_COMPLETE &&
+	    cp->ssss_status == S_QUEUE_FULL) {
+		if (!lp || lp->started_tags - i < 2)
+			goto weirdness;
+		/*
+		 *  Decrease queue depth as needed.
+		 */
+		lp->started_max = lp->started_tags - i - 1;
+		lp->num_sgood = 0;
+
+		if (sym_verbose >= 2) {
+			sym_print_addr(cmd, " queue depth is now %d\n",
+					lp->started_max);
+		}
+
+		/*
+		 *  Repair the CCB.
+		 */
+		cp->host_status = HS_BUSY;
+		cp->ssss_status = S_ILLEGAL;
+
+		/*
+		 *  Let's requeue it to device.
+		 */
+		sym_set_cam_status(cmd, CAM_REQUEUE_REQ);
+		goto finish;
+	}
+weirdness:
+#endif
+	/*
+	 *  Build result in CAM ccb.
+	 */
+	sym_set_cam_result_error(np, cp, resid);
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+finish:
+#endif
+	/*
+	 *  Add this one to the COMP queue.
+	 */
+	sym_remque(&cp->link_ccbq);
+	sym_insque_head(&cp->link_ccbq, &np->comp_ccbq);
+
+	/*
+	 *  Complete all those commands with either error 
+	 *  or requeue condition.
+	 */
+	sym_flush_comp_queue(np, 0);
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  Donnot start more than 1 command after an error.
+	 */
+	if (lp)
+		sym_start_next_ccbs(np, lp, 1);
+#endif
+}
+
+/*
+ *  Complete execution of a successful SCSI command.
+ *
+ *  Only successful commands go to the DONE queue, 
+ *  since we need to have the SCRIPTS processor 
+ *  stopped on any error condition.
+ *  The SCRIPTS processor is running while we are 
+ *  completing successful commands.
+ */
+void sym_complete_ok (struct sym_hcb *np, struct sym_ccb *cp)
+{
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	struct scsi_cmnd *cmd;
+	int resid;
+
+	/*
+	 *  Paranoid check. :)
+	 */
+	if (!cp || !cp->cmd)
+		return;
+	assert (cp->host_status == HS_COMPLETE);
+
+	/*
+	 *  Get user command.
+	 */
+	cmd = cp->cmd;
+
+	/*
+	 *  Get target and lun pointers.
+	 */
+	tp = &np->target[cp->target];
+	lp = sym_lp(tp, cp->lun);
+
+	/*
+	 *  Assume device discovered on first success.
+	 */
+	if (!lp)
+		sym_set_bit(tp->lun_map, cp->lun);
+
+	/*
+	 *  If all data have been transferred, given than no
+	 *  extended error did occur, there is no residual.
+	 */
+	resid = 0;
+	if (cp->phys.head.lastp != sym_goalp(cp))
+		resid = sym_compute_residual(np, cp);
+
+	/*
+	 *  Wrong transfer residuals may be worse than just always 
+	 *  returning zero. User can disable this feature in 
+	 *  sym53c8xx.h. Residual support is enabled by default.
+	 */
+	if (!SYM_SETUP_RESIDUAL_SUPPORT)
+		resid  = 0;
+#ifdef DEBUG_2_0_X
+if (resid)
+	printf("XXXX RESID= %d - 0x%x\n", resid, resid);
+#endif
+
+	/*
+	 *  Build result in CAM ccb.
+	 */
+	sym_set_cam_result_ok(cp, cmd, resid);
+
+#ifdef	SYM_OPT_SNIFF_INQUIRY
+	/*
+	 *  On standard INQUIRY response (EVPD and CmDt 
+	 *  not set), sniff out device capabilities.
+	 */
+	if (cp->cdb_buf[0] == INQUIRY && !(cp->cdb_buf[1] & 0x3))
+		sym_sniff_inquiry(np, cmd, resid);
+#endif
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  If max number of started ccbs had been reduced,
+	 *  increase it if 200 good status received.
+	 */
+	if (lp && lp->started_max < lp->started_limit) {
+		++lp->num_sgood;
+		if (lp->num_sgood >= 200) {
+			lp->num_sgood = 0;
+			++lp->started_max;
+			if (sym_verbose >= 2) {
+				sym_print_addr(cmd, " queue depth is now %d\n",
+				       lp->started_max);
+			}
+		}
+	}
+#endif
+
+	/*
+	 *  Free our CCB.
+	 */
+	sym_free_ccb (np, cp);
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  Requeue a couple of awaiting scsi commands.
+	 */
+	if (lp && !sym_que_empty(&lp->waiting_ccbq))
+		sym_start_next_ccbs(np, lp, 2);
+#endif
+	/*
+	 *  Complete the command.
+	 */
+	sym_xpt_done(np, cmd);
+}
+
+/*
+ *  Soft-attach the controller.
+ */
+int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram)
+{
+	struct sym_hcb *np = sym_get_hcb(shost);
+	int i;
+
+	/*
+	 *  Get some info about the firmware.
+	 */
+	np->scripta_sz	 = fw->a_size;
+	np->scriptb_sz	 = fw->b_size;
+	np->scriptz_sz	 = fw->z_size;
+	np->fw_setup	 = fw->setup;
+	np->fw_patch	 = fw->patch;
+	np->fw_name	 = fw->name;
+
+	/*
+	 *  Save setting of some IO registers, so we will 
+	 *  be able to probe specific implementations.
+	 */
+	sym_save_initial_setting (np);
+
+	/*
+	 *  Reset the chip now, since it has been reported 
+	 *  that SCSI clock calibration may not work properly 
+	 *  if the chip is currently active.
+	 */
+	sym_chip_reset(np);
+
+	/*
+	 *  Prepare controller and devices settings, according 
+	 *  to chip features, user set-up and driver set-up.
+	 */
+	sym_prepare_setting(shost, np, nvram);
+
+	/*
+	 *  Check the PCI clock frequency.
+	 *  Must be performed after prepare_setting since it destroys 
+	 *  STEST1 that is used to probe for the clock doubler.
+	 */
+	i = sym_getpciclock(np);
+	if (i > 37000 && !(np->features & FE_66MHZ))
+		printf("%s: PCI BUS clock seems too high: %u KHz.\n",
+			sym_name(np), i);
+
+	/*
+	 *  Allocate the start queue.
+	 */
+	np->squeue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"SQUEUE");
+	if (!np->squeue)
+		goto attach_failed;
+	np->squeue_ba = vtobus(np->squeue);
+
+	/*
+	 *  Allocate the done queue.
+	 */
+	np->dqueue = sym_calloc_dma(sizeof(u32)*(MAX_QUEUE*2),"DQUEUE");
+	if (!np->dqueue)
+		goto attach_failed;
+	np->dqueue_ba = vtobus(np->dqueue);
+
+	/*
+	 *  Allocate the target bus address array.
+	 */
+	np->targtbl = sym_calloc_dma(256, "TARGTBL");
+	if (!np->targtbl)
+		goto attach_failed;
+	np->targtbl_ba = vtobus(np->targtbl);
+
+	/*
+	 *  Allocate SCRIPTS areas.
+	 */
+	np->scripta0 = sym_calloc_dma(np->scripta_sz, "SCRIPTA0");
+	np->scriptb0 = sym_calloc_dma(np->scriptb_sz, "SCRIPTB0");
+	np->scriptz0 = sym_calloc_dma(np->scriptz_sz, "SCRIPTZ0");
+	if (!np->scripta0 || !np->scriptb0 || !np->scriptz0)
+		goto attach_failed;
+
+	/*
+	 *  Allocate the array of lists of CCBs hashed by DSA.
+	 */
+	np->ccbh = kcalloc(sizeof(struct sym_ccb **), CCB_HASH_SIZE, GFP_KERNEL);
+	if (!np->ccbh)
+		goto attach_failed;
+
+	/*
+	 *  Initialyze the CCB free and busy queues.
+	 */
+	sym_que_init(&np->free_ccbq);
+	sym_que_init(&np->busy_ccbq);
+	sym_que_init(&np->comp_ccbq);
+
+	/*
+	 *  Initialization for optional handling 
+	 *  of device queueing.
+	 */
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	sym_que_init(&np->dummy_ccbq);
+#endif
+	/*
+	 *  Allocate some CCB. We need at least ONE.
+	 */
+	if (!sym_alloc_ccb(np))
+		goto attach_failed;
+
+	/*
+	 *  Calculate BUS addresses where we are going 
+	 *  to load the SCRIPTS.
+	 */
+	np->scripta_ba	= vtobus(np->scripta0);
+	np->scriptb_ba	= vtobus(np->scriptb0);
+	np->scriptz_ba	= vtobus(np->scriptz0);
+
+	if (np->ram_ba) {
+		np->scripta_ba	= np->ram_ba;
+		if (np->features & FE_RAM8K) {
+			np->ram_ws = 8192;
+			np->scriptb_ba = np->scripta_ba + 4096;
+#if 0	/* May get useful for 64 BIT PCI addressing */
+			np->scr_ram_seg = cpu_to_scr(np->scripta_ba >> 32);
+#endif
+		}
+		else
+			np->ram_ws = 4096;
+	}
+
+	/*
+	 *  Copy scripts to controller instance.
+	 */
+	memcpy(np->scripta0, fw->a_base, np->scripta_sz);
+	memcpy(np->scriptb0, fw->b_base, np->scriptb_sz);
+	memcpy(np->scriptz0, fw->z_base, np->scriptz_sz);
+
+	/*
+	 *  Setup variable parts in scripts and compute
+	 *  scripts bus addresses used from the C code.
+	 */
+	np->fw_setup(np, fw);
+
+	/*
+	 *  Bind SCRIPTS with physical addresses usable by the 
+	 *  SCRIPTS processor (as seen from the BUS = BUS addresses).
+	 */
+	sym_fw_bind_script(np, (u32 *) np->scripta0, np->scripta_sz);
+	sym_fw_bind_script(np, (u32 *) np->scriptb0, np->scriptb_sz);
+	sym_fw_bind_script(np, (u32 *) np->scriptz0, np->scriptz_sz);
+
+#ifdef SYM_CONF_IARB_SUPPORT
+	/*
+	 *    If user wants IARB to be set when we win arbitration 
+	 *    and have other jobs, compute the max number of consecutive 
+	 *    settings of IARB hints before we leave devices a chance to 
+	 *    arbitrate for reselection.
+	 */
+#ifdef	SYM_SETUP_IARB_MAX
+	np->iarb_max = SYM_SETUP_IARB_MAX;
+#else
+	np->iarb_max = 4;
+#endif
+#endif
+
+	/*
+	 *  Prepare the idle and invalid task actions.
+	 */
+	np->idletask.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->idletask.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
+	np->idletask_ba		= vtobus(&np->idletask);
+
+	np->notask.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->notask.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
+	np->notask_ba		= vtobus(&np->notask);
+
+	np->bad_itl.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->bad_itl.restart	= cpu_to_scr(SCRIPTB_BA(np, bad_i_t_l));
+	np->bad_itl_ba		= vtobus(&np->bad_itl);
+
+	np->bad_itlq.start	= cpu_to_scr(SCRIPTA_BA(np, idle));
+	np->bad_itlq.restart	= cpu_to_scr(SCRIPTB_BA(np,bad_i_t_l_q));
+	np->bad_itlq_ba		= vtobus(&np->bad_itlq);
+
+	/*
+	 *  Allocate and prepare the lun JUMP table that is used 
+	 *  for a target prior the probing of devices (bad lun table).
+	 *  A private table will be allocated for the target on the 
+	 *  first INQUIRY response received.
+	 */
+	np->badluntbl = sym_calloc_dma(256, "BADLUNTBL");
+	if (!np->badluntbl)
+		goto attach_failed;
+
+	np->badlun_sa = cpu_to_scr(SCRIPTB_BA(np, resel_bad_lun));
+	for (i = 0 ; i < 64 ; i++)	/* 64 luns/target, no less */
+		np->badluntbl[i] = cpu_to_scr(vtobus(&np->badlun_sa));
+
+	/*
+	 *  Prepare the bus address array that contains the bus 
+	 *  address of each target control block.
+	 *  For now, assume all logical units are wrong. :)
+	 */
+	for (i = 0 ; i < SYM_CONF_MAX_TARGET ; i++) {
+		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
+		np->target[i].head.luntbl_sa =
+				cpu_to_scr(vtobus(np->badluntbl));
+		np->target[i].head.lun0_sa =
+				cpu_to_scr(vtobus(&np->badlun_sa));
+	}
+
+	/*
+	 *  Now check the cache handling of the pci chipset.
+	 */
+	if (sym_snooptest (np)) {
+		printf("%s: CACHE INCORRECTLY CONFIGURED.\n", sym_name(np));
+		goto attach_failed;
+	}
+
+	/*
+	 *  Sigh! we are done.
+	 */
+	return 0;
+
+attach_failed:
+	return -ENXIO;
+}
+
+/*
+ *  Free everything that has been allocated for this device.
+ */
+void sym_hcb_free(struct sym_hcb *np)
+{
+	SYM_QUEHEAD *qp;
+	struct sym_ccb *cp;
+	struct sym_tcb *tp;
+	struct sym_lcb *lp;
+	int target, lun;
+
+	if (np->scriptz0)
+		sym_mfree_dma(np->scriptz0, np->scriptz_sz, "SCRIPTZ0");
+	if (np->scriptb0)
+		sym_mfree_dma(np->scriptb0, np->scriptb_sz, "SCRIPTB0");
+	if (np->scripta0)
+		sym_mfree_dma(np->scripta0, np->scripta_sz, "SCRIPTA0");
+	if (np->squeue)
+		sym_mfree_dma(np->squeue, sizeof(u32)*(MAX_QUEUE*2), "SQUEUE");
+	if (np->dqueue)
+		sym_mfree_dma(np->dqueue, sizeof(u32)*(MAX_QUEUE*2), "DQUEUE");
+
+	if (np->actccbs) {
+		while ((qp = sym_remque_head(&np->free_ccbq)) != 0) {
+			cp = sym_que_entry(qp, struct sym_ccb, link_ccbq);
+			sym_mfree_dma(cp, sizeof(*cp), "CCB");
+		}
+	}
+	kfree(np->ccbh);
+
+	if (np->badluntbl)
+		sym_mfree_dma(np->badluntbl, 256,"BADLUNTBL");
+
+	for (target = 0; target < SYM_CONF_MAX_TARGET ; target++) {
+		tp = &np->target[target];
+		for (lun = 0 ; lun < SYM_CONF_MAX_LUN ; lun++) {
+			lp = sym_lp(tp, lun);
+			if (!lp)
+				continue;
+			if (lp->itlq_tbl)
+				sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK*4,
+				       "ITLQ_TBL");
+			kfree(lp->cb_tags);
+			sym_mfree_dma(lp, sizeof(*lp), "LCB");
+		}
+#if SYM_CONF_MAX_LUN > 1
+		kfree(tp->lunmp);
+#endif 
+	}
+	if (np->targtbl)
+		sym_mfree_dma(np->targtbl, 256, "TARGTBL");
+}
diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h
new file mode 100644
index 0000000..a95cbe4
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h
@@ -0,0 +1,1304 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM_HIPD_H
+#define SYM_HIPD_H
+
+/*
+ *  Generic driver options.
+ *
+ *  They may be defined in platform specific headers, if they 
+ *  are useful.
+ *
+ *    SYM_OPT_HANDLE_DIR_UNKNOWN
+ *        When this option is set, the SCRIPTS used by the driver 
+ *        are able to handle SCSI transfers with direction not 
+ *        supplied by user.
+ *        (set for Linux-2.0.X)
+ *
+ *    SYM_OPT_HANDLE_DEVICE_QUEUEING
+ *        When this option is set, the driver will use a queue per 
+ *        device and handle QUEUE FULL status requeuing internally.
+ *
+ *    SYM_OPT_LIMIT_COMMAND_REORDERING
+ *        When this option is set, the driver tries to limit tagged 
+ *        command reordering to some reasonnable value.
+ *        (set for Linux)
+ */
+#if 0
+#define SYM_OPT_HANDLE_DIR_UNKNOWN
+#define SYM_OPT_HANDLE_DEVICE_QUEUEING
+#define SYM_OPT_LIMIT_COMMAND_REORDERING
+#endif
+
+/*
+ *  Active debugging tags and verbosity.
+ *  Both DEBUG_FLAGS and sym_verbose can be redefined 
+ *  by the platform specific code to something else.
+ */
+#define DEBUG_ALLOC	(0x0001)
+#define DEBUG_PHASE	(0x0002)
+#define DEBUG_POLL	(0x0004)
+#define DEBUG_QUEUE	(0x0008)
+#define DEBUG_RESULT	(0x0010)
+#define DEBUG_SCATTER	(0x0020)
+#define DEBUG_SCRIPT	(0x0040)
+#define DEBUG_TINY	(0x0080)
+#define DEBUG_TIMING	(0x0100)
+#define DEBUG_NEGO	(0x0200)
+#define DEBUG_TAGS	(0x0400)
+#define DEBUG_POINTER	(0x0800)
+
+#ifndef DEBUG_FLAGS
+#define DEBUG_FLAGS	(0x0000)
+#endif
+
+#ifndef sym_verbose
+#define sym_verbose	(np->verbose)
+#endif
+
+/*
+ *  These ones should have been already defined.
+ */
+#ifndef assert
+#define	assert(expression) { \
+	if (!(expression)) { \
+		(void)panic( \
+			"assertion \"%s\" failed: file \"%s\", line %d\n", \
+			#expression, \
+			__FILE__, __LINE__); \
+	} \
+}
+#endif
+
+/*
+ *  Number of tasks per device we want to handle.
+ */
+#if	SYM_CONF_MAX_TAG_ORDER > 8
+#error	"more than 256 tags per logical unit not allowed."
+#endif
+#define	SYM_CONF_MAX_TASK	(1<<SYM_CONF_MAX_TAG_ORDER)
+
+/*
+ *  Donnot use more tasks that we can handle.
+ */
+#ifndef	SYM_CONF_MAX_TAG
+#define	SYM_CONF_MAX_TAG	SYM_CONF_MAX_TASK
+#endif
+#if	SYM_CONF_MAX_TAG > SYM_CONF_MAX_TASK
+#undef	SYM_CONF_MAX_TAG
+#define	SYM_CONF_MAX_TAG	SYM_CONF_MAX_TASK
+#endif
+
+/*
+ *    This one means 'NO TAG for this job'
+ */
+#define NO_TAG	(256)
+
+/*
+ *  Number of SCSI targets.
+ */
+#if	SYM_CONF_MAX_TARGET > 16
+#error	"more than 16 targets not allowed."
+#endif
+
+/*
+ *  Number of logical units per target.
+ */
+#if	SYM_CONF_MAX_LUN > 64
+#error	"more than 64 logical units per target not allowed."
+#endif
+
+/*
+ *    Asynchronous pre-scaler (ns). Shall be 40 for 
+ *    the SCSI timings to be compliant.
+ */
+#define	SYM_CONF_MIN_ASYNC (40)
+
+/*
+ *  Shortest memory chunk is (1<<SYM_MEM_SHIFT), currently 16.
+ *  Actual allocations happen as SYM_MEM_CLUSTER_SIZE sized.
+ *  (1 PAGE at a time is just fine).
+ */
+#define SYM_MEM_SHIFT	4
+#define SYM_MEM_CLUSTER_SIZE	(1UL << SYM_MEM_CLUSTER_SHIFT)
+#define SYM_MEM_CLUSTER_MASK	(SYM_MEM_CLUSTER_SIZE-1)
+
+/*
+ *  Number of entries in the START and DONE queues.
+ *
+ *  We limit to 1 PAGE in order to succeed allocation of 
+ *  these queues. Each entry is 8 bytes long (2 DWORDS).
+ */
+#ifdef	SYM_CONF_MAX_START
+#define	SYM_CONF_MAX_QUEUE (SYM_CONF_MAX_START+2)
+#else
+#define	SYM_CONF_MAX_QUEUE (7*SYM_CONF_MAX_TASK+2)
+#define	SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2)
+#endif
+
+#if	SYM_CONF_MAX_QUEUE > SYM_MEM_CLUSTER_SIZE/8
+#undef	SYM_CONF_MAX_QUEUE
+#define	SYM_CONF_MAX_QUEUE (SYM_MEM_CLUSTER_SIZE/8)
+#undef	SYM_CONF_MAX_START
+#define	SYM_CONF_MAX_START (SYM_CONF_MAX_QUEUE-2)
+#endif
+
+/*
+ *  For this one, we want a short name :-)
+ */
+#define MAX_QUEUE	SYM_CONF_MAX_QUEUE
+
+/*
+ *  Common definitions for both bus space based and legacy IO methods.
+ */
+
+#define INB_OFF(np, o)		ioread8(np->s.ioaddr + (o))
+#define INW_OFF(np, o)		ioread16(np->s.ioaddr + (o))
+#define INL_OFF(np, o)		ioread32(np->s.ioaddr + (o))
+
+#define OUTB_OFF(np, o, val)	iowrite8((val), np->s.ioaddr + (o))
+#define OUTW_OFF(np, o, val)	iowrite16((val), np->s.ioaddr + (o))
+#define OUTL_OFF(np, o, val)	iowrite32((val), np->s.ioaddr + (o))
+
+#define INB(np, r)		INB_OFF(np, offsetof(struct sym_reg, r))
+#define INW(np, r)		INW_OFF(np, offsetof(struct sym_reg, r))
+#define INL(np, r)		INL_OFF(np, offsetof(struct sym_reg, r))
+
+#define OUTB(np, r, v)		OUTB_OFF(np, offsetof(struct sym_reg, r), (v))
+#define OUTW(np, r, v)		OUTW_OFF(np, offsetof(struct sym_reg, r), (v))
+#define OUTL(np, r, v)		OUTL_OFF(np, offsetof(struct sym_reg, r), (v))
+
+#define OUTONB(np, r, m)	OUTB(np, r, INB(np, r) | (m))
+#define OUTOFFB(np, r, m)	OUTB(np, r, INB(np, r) & ~(m))
+#define OUTONW(np, r, m)	OUTW(np, r, INW(np, r) | (m))
+#define OUTOFFW(np, r, m)	OUTW(np, r, INW(np, r) & ~(m))
+#define OUTONL(np, r, m)	OUTL(np, r, INL(np, r) | (m))
+#define OUTOFFL(np, r, m)	OUTL(np, r, INL(np, r) & ~(m))
+
+/*
+ *  We normally want the chip to have a consistent view
+ *  of driver internal data structures when we restart it.
+ *  Thus these macros.
+ */
+#define OUTL_DSP(np, v)				\
+	do {					\
+		MEMORY_WRITE_BARRIER();		\
+		OUTL(np, nc_dsp, (v));		\
+	} while (0)
+
+#define OUTONB_STD()				\
+	do {					\
+		MEMORY_WRITE_BARRIER();		\
+		OUTONB(np, nc_dcntl, (STD|NOCOM));	\
+	} while (0)
+
+/*
+ *  Command control block states.
+ */
+#define HS_IDLE		(0)
+#define HS_BUSY		(1)
+#define HS_NEGOTIATE	(2)	/* sync/wide data transfer*/
+#define HS_DISCONNECT	(3)	/* Disconnected by target */
+#define HS_WAIT		(4)	/* waiting for resource	  */
+
+#define HS_DONEMASK	(0x80)
+#define HS_COMPLETE	(4|HS_DONEMASK)
+#define HS_SEL_TIMEOUT	(5|HS_DONEMASK)	/* Selection timeout      */
+#define HS_UNEXPECTED	(6|HS_DONEMASK)	/* Unexpected disconnect  */
+#define HS_COMP_ERR	(7|HS_DONEMASK)	/* Completed with error	  */
+
+/*
+ *  Software Interrupt Codes
+ */
+#define	SIR_BAD_SCSI_STATUS	(1)
+#define	SIR_SEL_ATN_NO_MSG_OUT	(2)
+#define	SIR_MSG_RECEIVED	(3)
+#define	SIR_MSG_WEIRD		(4)
+#define	SIR_NEGO_FAILED		(5)
+#define	SIR_NEGO_PROTO		(6)
+#define	SIR_SCRIPT_STOPPED	(7)
+#define	SIR_REJECT_TO_SEND	(8)
+#define	SIR_SWIDE_OVERRUN	(9)
+#define	SIR_SODL_UNDERRUN	(10)
+#define	SIR_RESEL_NO_MSG_IN	(11)
+#define	SIR_RESEL_NO_IDENTIFY	(12)
+#define	SIR_RESEL_BAD_LUN	(13)
+#define	SIR_TARGET_SELECTED	(14)
+#define	SIR_RESEL_BAD_I_T_L	(15)
+#define	SIR_RESEL_BAD_I_T_L_Q	(16)
+#define	SIR_ABORT_SENT		(17)
+#define	SIR_RESEL_ABORTED	(18)
+#define	SIR_MSG_OUT_DONE	(19)
+#define	SIR_COMPLETE_ERROR	(20)
+#define	SIR_DATA_OVERRUN	(21)
+#define	SIR_BAD_PHASE		(22)
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+#define	SIR_DMAP_DIRTY		(23)
+#define	SIR_MAX			(23)
+#else
+#define	SIR_MAX			(22)
+#endif
+
+/*
+ *  Extended error bit codes.
+ *  xerr_status field of struct sym_ccb.
+ */
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase	 */
+#define	XE_BAD_PHASE	(1<<1)	/* illegal phase (4/5)		 */
+#define	XE_PARITY_ERR	(1<<2)	/* unrecovered SCSI parity error */
+#define	XE_SODL_UNRUN	(1<<3)	/* ODD transfer in DATA OUT phase */
+#define	XE_SWIDE_OVRUN	(1<<4)	/* ODD transfer in DATA IN phase */
+
+/*
+ *  Negotiation status.
+ *  nego_status field of struct sym_ccb.
+ */
+#define NS_SYNC		(1)
+#define NS_WIDE		(2)
+#define NS_PPR		(3)
+
+/*
+ *  A CCB hashed table is used to retrieve CCB address 
+ *  from DSA value.
+ */
+#define CCB_HASH_SHIFT		8
+#define CCB_HASH_SIZE		(1UL << CCB_HASH_SHIFT)
+#define CCB_HASH_MASK		(CCB_HASH_SIZE-1)
+#if 1
+#define CCB_HASH_CODE(dsa)	\
+	(((dsa) >> (_LGRU16_(sizeof(struct sym_ccb)))) & CCB_HASH_MASK)
+#else
+#define CCB_HASH_CODE(dsa)	(((dsa) >> 9) & CCB_HASH_MASK)
+#endif
+
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+/*
+ *  We may want to use segment registers for 64 bit DMA.
+ *  16 segments registers -> up to 64 GB addressable.
+ */
+#define SYM_DMAP_SHIFT	(4)
+#define SYM_DMAP_SIZE	(1u<<SYM_DMAP_SHIFT)
+#define SYM_DMAP_MASK	(SYM_DMAP_SIZE-1)
+#endif
+
+/*
+ *  Device flags.
+ */
+#define SYM_DISC_ENABLED	(1)
+#define SYM_TAGS_ENABLED	(1<<1)
+#define SYM_SCAN_BOOT_DISABLED	(1<<2)
+#define SYM_SCAN_LUNS_DISABLED	(1<<3)
+
+/*
+ *  Host adapter miscellaneous flags.
+ */
+#define SYM_AVOID_BUS_RESET	(1)
+
+/*
+ *  Misc.
+ */
+#define SYM_SNOOP_TIMEOUT (10000000)
+#define BUS_8_BIT	0
+#define BUS_16_BIT	1
+
+/*
+ *  Gather negotiable parameters value
+ */
+struct sym_trans {
+	u8 period;
+	u8 offset;
+	unsigned int width:1;
+	unsigned int iu:1;
+	unsigned int dt:1;
+	unsigned int qas:1;
+	unsigned int check_nego:1;
+};
+
+/*
+ *  Global TCB HEADER.
+ *
+ *  Due to lack of indirect addressing on earlier NCR chips,
+ *  this substructure is copied from the TCB to a global 
+ *  address after selection.
+ *  For SYMBIOS chips that support LOAD/STORE this copy is 
+ *  not needed and thus not performed.
+ */
+struct sym_tcbh {
+	/*
+	 *  Scripts bus addresses of LUN table accessed from scripts.
+	 *  LUN #0 is a special case, since multi-lun devices are rare, 
+	 *  and we we want to speed-up the general case and not waste 
+	 *  resources.
+	 */
+	u32	luntbl_sa;	/* bus address of this table	*/
+	u32	lun0_sa;	/* bus address of LCB #0	*/
+	/*
+	 *  Actual SYNC/WIDE IO registers value for this target.
+	 *  'sval', 'wval' and 'uval' are read from SCRIPTS and 
+	 *  so have alignment constraints.
+	 */
+/*0*/	u_char	uval;		/* -> SCNTL4 register		*/
+/*1*/	u_char	sval;		/* -> SXFER  io register	*/
+/*2*/	u_char	filler1;
+/*3*/	u_char	wval;		/* -> SCNTL3 io register	*/
+};
+
+/*
+ *  Target Control Block
+ */
+struct sym_tcb {
+	/*
+	 *  TCB header.
+	 *  Assumed at offset 0.
+	 */
+/*0*/	struct sym_tcbh head;
+
+	/*
+	 *  LUN table used by the SCRIPTS processor.
+	 *  An array of bus addresses is used on reselection.
+	 */
+	u32	*luntbl;	/* LCBs bus address table	*/
+
+	/*
+	 *  LUN table used by the C code.
+	 */
+	struct sym_lcb *lun0p;		/* LCB of LUN #0 (usual case)	*/
+#if SYM_CONF_MAX_LUN > 1
+	struct sym_lcb **lunmp;		/* Other LCBs [1..MAX_LUN]	*/
+#endif
+
+	/*
+	 *  Bitmap that tells about LUNs that succeeded at least 
+	 *  1 IO and therefore assumed to be a real device.
+	 *  Avoid useless allocation of the LCB structure.
+	 */
+	u32	lun_map[(SYM_CONF_MAX_LUN+31)/32];
+
+	/*
+	 *  Bitmap that tells about LUNs that haven't yet an LCB 
+	 *  allocated (not discovered or LCB allocation failed).
+	 */
+	u32	busy0_map[(SYM_CONF_MAX_LUN+31)/32];
+
+#ifdef	SYM_HAVE_STCB
+	/*
+	 *  O/S specific data structure.
+	 */
+	struct sym_stcb s;
+#endif
+
+	/* Transfer goal */
+	struct sym_trans tgoal;
+
+	/*
+	 * Keep track of the CCB used for the negotiation in order
+	 * to ensure that only 1 negotiation is queued at a time.
+	 */
+	struct sym_ccb *  nego_cp;	/* CCB used for the nego		*/
+
+	/*
+	 *  Set when we want to reset the device.
+	 */
+	u_char	to_reset;
+
+	/*
+	 *  Other user settable limits and options.
+	 *  These limits are read from the NVRAM if present.
+	 */
+	u_char	usrflags;
+	u_short	usrtags;
+	struct scsi_device *sdev;
+};
+
+/*
+ *  Global LCB HEADER.
+ *
+ *  Due to lack of indirect addressing on earlier NCR chips,
+ *  this substructure is copied from the LCB to a global 
+ *  address after selection.
+ *  For SYMBIOS chips that support LOAD/STORE this copy is 
+ *  not needed and thus not performed.
+ */
+struct sym_lcbh {
+	/*
+	 *  SCRIPTS address jumped by SCRIPTS on reselection.
+	 *  For not probed logical units, this address points to 
+	 *  SCRIPTS that deal with bad LU handling (must be at 
+	 *  offset zero of the LCB for that reason).
+	 */
+/*0*/	u32	resel_sa;
+
+	/*
+	 *  Task (bus address of a CCB) read from SCRIPTS that points 
+	 *  to the unique ITL nexus allowed to be disconnected.
+	 */
+	u32	itl_task_sa;
+
+	/*
+	 *  Task table bus address (read from SCRIPTS).
+	 */
+	u32	itlq_tbl_sa;
+};
+
+/*
+ *  Logical Unit Control Block
+ */
+struct sym_lcb {
+	/*
+	 *  TCB header.
+	 *  Assumed at offset 0.
+	 */
+/*0*/	struct sym_lcbh head;
+
+	/*
+	 *  Task table read from SCRIPTS that contains pointers to 
+	 *  ITLQ nexuses. The bus address read from SCRIPTS is 
+	 *  inside the header.
+	 */
+	u32	*itlq_tbl;	/* Kernel virtual address	*/
+
+	/*
+	 *  Busy CCBs management.
+	 */
+	u_short	busy_itlq;	/* Number of busy tagged CCBs	*/
+	u_short	busy_itl;	/* Number of busy untagged CCBs	*/
+
+	/*
+	 *  Circular tag allocation buffer.
+	 */
+	u_short	ia_tag;		/* Tag allocation index		*/
+	u_short	if_tag;		/* Tag release index		*/
+	u_char	*cb_tags;	/* Circular tags buffer		*/
+
+	/*
+	 *  O/S specific data structure.
+	 */
+#ifdef	SYM_HAVE_SLCB
+	struct sym_slcb s;
+#endif
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	/*
+	 *  Optionnaly the driver can handle device queueing, 
+	 *  and requeues internally command to redo.
+	 */
+	SYM_QUEHEAD waiting_ccbq;
+	SYM_QUEHEAD started_ccbq;
+	int	num_sgood;
+	u_short	started_tags;
+	u_short	started_no_tag;
+	u_short	started_max;
+	u_short	started_limit;
+#endif
+
+#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
+	/*
+	 *  Optionally the driver can try to prevent SCSI 
+	 *  IOs from being reordered too much.
+	 */
+	u_char		tags_si;	/* Current index to tags sum	*/
+	u_short		tags_sum[2];	/* Tags sum counters		*/
+	u_short		tags_since;	/* # of tags since last switch	*/
+#endif
+
+	/*
+	 *  Set when we want to clear all tasks.
+	 */
+	u_char to_clear;
+
+	/*
+	 *  Capabilities.
+	 */
+	u_char	user_flags;
+	u_char	curr_flags;
+};
+
+/*
+ *  Action from SCRIPTS on a task.
+ *  Is part of the CCB, but is also used separately to plug 
+ *  error handling action to perform from SCRIPTS.
+ */
+struct sym_actscr {
+	u32	start;		/* Jumped by SCRIPTS after selection	*/
+	u32	restart;	/* Jumped by SCRIPTS on relection	*/
+};
+
+/*
+ *  Phase mismatch context.
+ *
+ *  It is part of the CCB and is used as parameters for the 
+ *  DATA pointer. We need two contexts to handle correctly the 
+ *  SAVED DATA POINTER.
+ */
+struct sym_pmc {
+	struct	sym_tblmove sg;	/* Updated interrupted SG block	*/
+	u32	ret;		/* SCRIPT return address	*/
+};
+
+/*
+ *  LUN control block lookup.
+ *  We use a direct pointer for LUN #0, and a table of 
+ *  pointers which is only allocated for devices that support 
+ *  LUN(s) > 0.
+ */
+#if SYM_CONF_MAX_LUN <= 1
+#define sym_lp(tp, lun) (!lun) ? (tp)->lun0p : NULL
+#else
+#define sym_lp(tp, lun) \
+	(!lun) ? (tp)->lun0p : (tp)->lunmp ? (tp)->lunmp[(lun)] : NULL
+#endif
+
+/*
+ *  Status are used by the host and the script processor.
+ *
+ *  The last four bytes (status[4]) are copied to the 
+ *  scratchb register (declared as scr0..scr3) just after the 
+ *  select/reselect, and copied back just after disconnecting.
+ *  Inside the script the XX_REG are used.
+ */
+
+/*
+ *  Last four bytes (script)
+ */
+#define  HX_REG	scr0
+#define  HX_PRT	nc_scr0
+#define  HS_REG	scr1
+#define  HS_PRT	nc_scr1
+#define  SS_REG	scr2
+#define  SS_PRT	nc_scr2
+#define  HF_REG	scr3
+#define  HF_PRT	nc_scr3
+
+/*
+ *  Last four bytes (host)
+ */
+#define  host_xflags   phys.head.status[0]
+#define  host_status   phys.head.status[1]
+#define  ssss_status   phys.head.status[2]
+#define  host_flags    phys.head.status[3]
+
+/*
+ *  Host flags
+ */
+#define HF_IN_PM0	1u
+#define HF_IN_PM1	(1u<<1)
+#define HF_ACT_PM	(1u<<2)
+#define HF_DP_SAVED	(1u<<3)
+#define HF_SENSE	(1u<<4)
+#define HF_EXT_ERR	(1u<<5)
+#define HF_DATA_IN	(1u<<6)
+#ifdef SYM_CONF_IARB_SUPPORT
+#define HF_HINT_IARB	(1u<<7)
+#endif
+
+/*
+ *  More host flags
+ */
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+#define	HX_DMAP_DIRTY	(1u<<7)
+#endif
+
+/*
+ *  Global CCB HEADER.
+ *
+ *  Due to lack of indirect addressing on earlier NCR chips,
+ *  this substructure is copied from the ccb to a global 
+ *  address after selection (or reselection) and copied back 
+ *  before disconnect.
+ *  For SYMBIOS chips that support LOAD/STORE this copy is 
+ *  not needed and thus not performed.
+ */
+
+struct sym_ccbh {
+	/*
+	 *  Start and restart SCRIPTS addresses (must be at 0).
+	 */
+/*0*/	struct sym_actscr go;
+
+	/*
+	 *  SCRIPTS jump address that deal with data pointers.
+	 *  'savep' points to the position in the script responsible 
+	 *  for the actual transfer of data.
+	 *  It's written on reception of a SAVE_DATA_POINTER message.
+	 */
+	u32	savep;		/* Jump address to saved data pointer	*/
+	u32	lastp;		/* SCRIPTS address at end of data	*/
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+	u32	wlastp;
+#endif
+
+	/*
+	 *  Status fields.
+	 */
+	u8	status[4];
+};
+
+/*
+ *  GET/SET the value of the data pointer used by SCRIPTS.
+ *
+ *  We must distinguish between the LOAD/STORE-based SCRIPTS 
+ *  that use directly the header in the CCB, and the NCR-GENERIC 
+ *  SCRIPTS that use the copy of the header in the HCB.
+ */
+#if	SYM_CONF_GENERIC_SUPPORT
+#define sym_set_script_dp(np, cp, dp)				\
+	do {							\
+		if (np->features & FE_LDSTR)			\
+			cp->phys.head.lastp = cpu_to_scr(dp);	\
+		else						\
+			np->ccb_head.lastp = cpu_to_scr(dp);	\
+	} while (0)
+#define sym_get_script_dp(np, cp) 				\
+	scr_to_cpu((np->features & FE_LDSTR) ?			\
+		cp->phys.head.lastp : np->ccb_head.lastp)
+#else
+#define sym_set_script_dp(np, cp, dp)				\
+	do {							\
+		cp->phys.head.lastp = cpu_to_scr(dp);		\
+	} while (0)
+
+#define sym_get_script_dp(np, cp) (cp->phys.head.lastp)
+#endif
+
+/*
+ *  Data Structure Block
+ *
+ *  During execution of a ccb by the script processor, the 
+ *  DSA (data structure address) register points to this 
+ *  substructure of the ccb.
+ */
+struct sym_dsb {
+	/*
+	 *  CCB header.
+	 *  Also assumed at offset 0 of the sym_ccb structure.
+	 */
+/*0*/	struct sym_ccbh head;
+
+	/*
+	 *  Phase mismatch contexts.
+	 *  We need two to handle correctly the SAVED DATA POINTER.
+	 *  MUST BOTH BE AT OFFSET < 256, due to using 8 bit arithmetic 
+	 *  for address calculation from SCRIPTS.
+	 */
+	struct sym_pmc pm0;
+	struct sym_pmc pm1;
+
+	/*
+	 *  Table data for Script
+	 */
+	struct sym_tblsel  select;
+	struct sym_tblmove smsg;
+	struct sym_tblmove smsg_ext;
+	struct sym_tblmove cmd;
+	struct sym_tblmove sense;
+	struct sym_tblmove wresid;
+	struct sym_tblmove data [SYM_CONF_MAX_SG];
+};
+
+/*
+ *  Our Command Control Block
+ */
+struct sym_ccb {
+	/*
+	 *  This is the data structure which is pointed by the DSA 
+	 *  register when it is executed by the script processor.
+	 *  It must be the first entry.
+	 */
+	struct sym_dsb phys;
+
+	/*
+	 *  Pointer to CAM ccb and related stuff.
+	 */
+	struct scsi_cmnd *cmd;	/* CAM scsiio ccb		*/
+	u8	cdb_buf[16];	/* Copy of CDB			*/
+#define	SYM_SNS_BBUF_LEN 32
+	u8	sns_bbuf[SYM_SNS_BBUF_LEN]; /* Bounce buffer for sense data */
+	int	data_len;	/* Total data length		*/
+	int	segments;	/* Number of SG segments	*/
+
+	u8	order;		/* Tag type (if tagged command)	*/
+
+	/*
+	 *  Miscellaneous status'.
+	 */
+	u_char	nego_status;	/* Negotiation status		*/
+	u_char	xerr_status;	/* Extended error flags		*/
+	u32	extra_bytes;	/* Extraneous bytes transferred	*/
+
+	/*
+	 *  Message areas.
+	 *  We prepare a message to be sent after selection.
+	 *  We may use a second one if the command is rescheduled 
+	 *  due to CHECK_CONDITION or COMMAND TERMINATED.
+	 *  Contents are IDENTIFY and SIMPLE_TAG.
+	 *  While negotiating sync or wide transfer,
+	 *  a SDTR or WDTR message is appended.
+	 */
+	u_char	scsi_smsg [12];
+	u_char	scsi_smsg2[12];
+
+	/*
+	 *  Auto request sense related fields.
+	 */
+	u_char	sensecmd[6];	/* Request Sense command	*/
+	u_char	sv_scsi_status;	/* Saved SCSI status 		*/
+	u_char	sv_xerr_status;	/* Saved extended status	*/
+	int	sv_resid;	/* Saved residual		*/
+
+	/*
+	 *  Other fields.
+	 */
+	u32	ccb_ba;		/* BUS address of this CCB	*/
+	u_short	tag;		/* Tag for this transfer	*/
+				/*  NO_TAG means no tag		*/
+	u_char	target;
+	u_char	lun;
+	struct sym_ccb *link_ccbh;	/* Host adapter CCB hash chain	*/
+	SYM_QUEHEAD link_ccbq;	/* Link to free/busy CCB queue	*/
+	u32	startp;		/* Initial data pointer		*/
+	u32	goalp;		/* Expected last data pointer	*/
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+	u32	wgoalp;
+#endif
+	int	ext_sg;		/* Extreme data pointer, used	*/
+	int	ext_ofs;	/*  to calculate the residual.	*/
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	SYM_QUEHEAD link2_ccbq;	/* Link for device queueing	*/
+	u_char	started;	/* CCB queued to the squeue	*/
+#endif
+	u_char	to_abort;	/* Want this IO to be aborted	*/
+#ifdef SYM_OPT_LIMIT_COMMAND_REORDERING
+	u_char	tags_si;	/* Lun tags sum index (0,1)	*/
+#endif
+};
+
+#define CCB_BA(cp,lbl)	(cp->ccb_ba + offsetof(struct sym_ccb, lbl))
+
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+#define	sym_goalp(cp) ((cp->host_flags & HF_DATA_IN) ? cp->goalp : cp->wgoalp)
+#else
+#define	sym_goalp(cp) (cp->goalp)
+#endif
+
+typedef struct device *m_pool_ident_t;
+
+/*
+ *  Host Control Block
+ */
+struct sym_hcb {
+	/*
+	 *  Global headers.
+	 *  Due to poorness of addressing capabilities, earlier 
+	 *  chips (810, 815, 825) copy part of the data structures 
+	 *  (CCB, TCB and LCB) in fixed areas.
+	 */
+#if	SYM_CONF_GENERIC_SUPPORT
+	struct sym_ccbh	ccb_head;
+	struct sym_tcbh	tcb_head;
+	struct sym_lcbh	lcb_head;
+#endif
+	/*
+	 *  Idle task and invalid task actions and 
+	 *  their bus addresses.
+	 */
+	struct sym_actscr idletask, notask, bad_itl, bad_itlq;
+	u32 idletask_ba, notask_ba, bad_itl_ba, bad_itlq_ba;
+
+	/*
+	 *  Dummy lun table to protect us against target 
+	 *  returning bad lun number on reselection.
+	 */
+	u32	*badluntbl;	/* Table physical address	*/
+	u32	badlun_sa;	/* SCRIPT handler BUS address	*/
+
+	/*
+	 *  Bus address of this host control block.
+	 */
+	u32	hcb_ba;
+
+	/*
+	 *  Bit 32-63 of the on-chip RAM bus address in LE format.
+	 *  The START_RAM64 script loads the MMRS and MMWS from this 
+	 *  field.
+	 */
+	u32	scr_ram_seg;
+
+	/*
+	 *  Initial value of some IO register bits.
+	 *  These values are assumed to have been set by BIOS, and may 
+	 *  be used to probe adapter implementation differences.
+	 */
+	u_char	sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
+		sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4,
+		sv_stest1;
+
+	/*
+	 *  Actual initial value of IO register bits used by the 
+	 *  driver. They are loaded at initialisation according to  
+	 *  features that are to be enabled/disabled.
+	 */
+	u_char	rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, 
+		rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4;
+
+	/*
+	 *  Target data.
+	 */
+	struct sym_tcb	target[SYM_CONF_MAX_TARGET];
+
+	/*
+	 *  Target control block bus address array used by the SCRIPT 
+	 *  on reselection.
+	 */
+	u32		*targtbl;
+	u32		targtbl_ba;
+
+	/*
+	 *  DMA pool handle for this HBA.
+	 */
+	m_pool_ident_t	bus_dmat;
+
+	/*
+	 *  O/S specific data structure
+	 */
+	struct sym_shcb s;
+
+	/*
+	 *  Physical bus addresses of the chip.
+	 */
+	u32		mmio_ba;	/* MMIO 32 bit BUS address	*/
+	int		mmio_ws;	/* MMIO Window size		*/
+
+	u32		ram_ba;		/* RAM 32 bit BUS address	*/
+	int		ram_ws;		/* RAM window size		*/
+
+	/*
+	 *  SCRIPTS virtual and physical bus addresses.
+	 *  'script'  is loaded in the on-chip RAM if present.
+	 *  'scripth' stays in main memory for all chips except the 
+	 *  53C895A, 53C896 and 53C1010 that provide 8K on-chip RAM.
+	 */
+	u_char		*scripta0;	/* Copy of scripts A, B, Z	*/
+	u_char		*scriptb0;
+	u_char		*scriptz0;
+	u32		scripta_ba;	/* Actual scripts A, B, Z	*/
+	u32		scriptb_ba;	/* 32 bit bus addresses.	*/
+	u32		scriptz_ba;
+	u_short		scripta_sz;	/* Actual size of script A, B, Z*/
+	u_short		scriptb_sz;
+	u_short		scriptz_sz;
+
+	/*
+	 *  Bus addresses, setup and patch methods for 
+	 *  the selected firmware.
+	 */
+	struct sym_fwa_ba fwa_bas;	/* Useful SCRIPTA bus addresses	*/
+	struct sym_fwb_ba fwb_bas;	/* Useful SCRIPTB bus addresses	*/
+	struct sym_fwz_ba fwz_bas;	/* Useful SCRIPTZ bus addresses	*/
+	void		(*fw_setup)(struct sym_hcb *np, struct sym_fw *fw);
+	void		(*fw_patch)(struct sym_hcb *np);
+	char		*fw_name;
+
+	/*
+	 *  General controller parameters and configuration.
+	 */
+	u_short	device_id;	/* PCI device id		*/
+	u_char	revision_id;	/* PCI device revision id	*/
+	u_int	features;	/* Chip features map		*/
+	u_char	myaddr;		/* SCSI id of the adapter	*/
+	u_char	maxburst;	/* log base 2 of dwords burst	*/
+	u_char	maxwide;	/* Maximum transfer width	*/
+	u_char	minsync;	/* Min sync period factor (ST)	*/
+	u_char	maxsync;	/* Max sync period factor (ST)	*/
+	u_char	maxoffs;	/* Max scsi offset        (ST)	*/
+	u_char	minsync_dt;	/* Min sync period factor (DT)	*/
+	u_char	maxsync_dt;	/* Max sync period factor (DT)	*/
+	u_char	maxoffs_dt;	/* Max scsi offset        (DT)	*/
+	u_char	multiplier;	/* Clock multiplier (1,2,4)	*/
+	u_char	clock_divn;	/* Number of clock divisors	*/
+	u32	clock_khz;	/* SCSI clock frequency in KHz	*/
+	u32	pciclk_khz;	/* Estimated PCI clock  in KHz	*/
+	/*
+	 *  Start queue management.
+	 *  It is filled up by the host processor and accessed by the 
+	 *  SCRIPTS processor in order to start SCSI commands.
+	 */
+	volatile		/* Prevent code optimizations	*/
+	u32	*squeue;	/* Start queue virtual address	*/
+	u32	squeue_ba;	/* Start queue BUS address	*/
+	u_short	squeueput;	/* Next free slot of the queue	*/
+	u_short	actccbs;	/* Number of allocated CCBs	*/
+
+	/*
+	 *  Command completion queue.
+	 *  It is the same size as the start queue to avoid overflow.
+	 */
+	u_short	dqueueget;	/* Next position to scan	*/
+	volatile		/* Prevent code optimizations	*/
+	u32	*dqueue;	/* Completion (done) queue	*/
+	u32	dqueue_ba;	/* Done queue BUS address	*/
+
+	/*
+	 *  Miscellaneous buffers accessed by the scripts-processor.
+	 *  They shall be DWORD aligned, because they may be read or 
+	 *  written with a script command.
+	 */
+	u_char		msgout[8];	/* Buffer for MESSAGE OUT 	*/
+	u_char		msgin [8];	/* Buffer for MESSAGE IN	*/
+	u32		lastmsg;	/* Last SCSI message sent	*/
+	u32		scratch;	/* Scratch for SCSI receive	*/
+					/* Also used for cache test 	*/
+	/*
+	 *  Miscellaneous configuration and status parameters.
+	 */
+	u_char		usrflags;	/* Miscellaneous user flags	*/
+	u_char		scsi_mode;	/* Current SCSI BUS mode	*/
+	u_char		verbose;	/* Verbosity for this controller*/
+
+	/*
+	 *  CCB lists and queue.
+	 */
+	struct sym_ccb **ccbh;			/* CCBs hashed by DSA value	*/
+					/* CCB_HASH_SIZE lists of CCBs	*/
+	SYM_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
+	SYM_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
+
+	/*
+	 *  During error handling and/or recovery,
+	 *  active CCBs that are to be completed with 
+	 *  error or requeued are moved from the busy_ccbq
+	 *  to the comp_ccbq prior to completion.
+	 */
+	SYM_QUEHEAD	comp_ccbq;
+
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+	SYM_QUEHEAD	dummy_ccbq;
+#endif
+
+	/*
+	 *  IMMEDIATE ARBITRATION (IARB) control.
+	 *
+	 *  We keep track in 'last_cp' of the last CCB that has been 
+	 *  queued to the SCRIPTS processor and clear 'last_cp' when 
+	 *  this CCB completes. If last_cp is not zero at the moment 
+	 *  we queue a new CCB, we set a flag in 'last_cp' that is 
+	 *  used by the SCRIPTS as a hint for setting IARB.
+	 *  We donnot set more than 'iarb_max' consecutive hints for 
+	 *  IARB in order to leave devices a chance to reselect.
+	 *  By the way, any non zero value of 'iarb_max' is unfair. :)
+	 */
+#ifdef SYM_CONF_IARB_SUPPORT
+	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
+	u_short		iarb_count;	/* Actual # of these hints	*/
+	struct sym_ccb *	last_cp;
+#endif
+
+	/*
+	 *  Command abort handling.
+	 *  We need to synchronize tightly with the SCRIPTS 
+	 *  processor in order to handle things correctly.
+	 */
+	u_char		abrt_msg[4];	/* Message to send buffer	*/
+	struct sym_tblmove abrt_tbl;	/* Table for the MOV of it 	*/
+	struct sym_tblsel  abrt_sel;	/* Sync params for selection	*/
+	u_char		istat_sem;	/* Tells the chip to stop (SEM)	*/
+
+	/*
+	 *  64 bit DMA handling.
+	 */
+#if	SYM_CONF_DMA_ADDRESSING_MODE != 0
+	u_char	use_dac;		/* Use PCI DAC cycles		*/
+#if	SYM_CONF_DMA_ADDRESSING_MODE == 2
+	u_char	dmap_dirty;		/* Dma segments registers dirty	*/
+	u32	dmap_bah[SYM_DMAP_SIZE];/* Segment registers map	*/
+#endif
+#endif
+};
+
+#define HCB_BA(np, lbl)	(np->hcb_ba + offsetof(struct sym_hcb, lbl))
+
+
+/*
+ *  FIRMWARES (sym_fw.c)
+ */
+struct sym_fw * sym_find_firmware(struct sym_chip *chip);
+void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len);
+
+/*
+ *  Driver methods called from O/S specific code.
+ */
+char *sym_driver_name(void);
+void sym_print_xerr(struct scsi_cmnd *cmd, int x_status);
+int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int);
+struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision);
+void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp);
+#ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING
+void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn);
+#endif
+void sym_start_up(struct sym_hcb *np, int reason);
+void sym_interrupt(struct sym_hcb *np);
+int sym_clear_tasks(struct sym_hcb *np, int cam_status, int target, int lun, int task);
+struct sym_ccb *sym_get_ccb(struct sym_hcb *np, struct scsi_cmnd *cmd, u_char tag_order);
+void sym_free_ccb(struct sym_hcb *np, struct sym_ccb *cp);
+struct sym_lcb *sym_alloc_lcb(struct sym_hcb *np, u_char tn, u_char ln);
+int sym_queue_scsiio(struct sym_hcb *np, struct scsi_cmnd *csio, struct sym_ccb *cp);
+int sym_abort_scsiio(struct sym_hcb *np, struct scsi_cmnd *ccb, int timed_out);
+int sym_reset_scsi_target(struct sym_hcb *np, int target);
+void sym_hcb_free(struct sym_hcb *np);
+int sym_hcb_attach(struct Scsi_Host *shost, struct sym_fw *fw, struct sym_nvram *nvram);
+
+/*
+ *  Build a scatter/gather entry.
+ *
+ *  For 64 bit systems, we use the 8 upper bits of the size field 
+ *  to provide bus address bits 32-39 to the SCRIPTS processor.
+ *  This allows the 895A, 896, 1010 to address up to 1 TB of memory.
+ */
+
+#if   SYM_CONF_DMA_ADDRESSING_MODE == 0
+#define sym_build_sge(np, data, badd, len)	\
+do {						\
+	(data)->addr = cpu_to_scr(badd);	\
+	(data)->size = cpu_to_scr(len);		\
+} while (0)
+#elif SYM_CONF_DMA_ADDRESSING_MODE == 1
+#define sym_build_sge(np, data, badd, len)				\
+do {									\
+	(data)->addr = cpu_to_scr(badd);				\
+	(data)->size = cpu_to_scr((((badd) >> 8) & 0xff000000) + len);	\
+} while (0)
+#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
+int sym_lookup_dmap(struct sym_hcb *np, u32 h, int s);
+static __inline void 
+sym_build_sge(struct sym_hcb *np, struct sym_tblmove *data, u64 badd, int len)
+{
+	u32 h = (badd>>32);
+	int s = (h&SYM_DMAP_MASK);
+
+	if (h != np->dmap_bah[s])
+		goto bad;
+good:
+	(data)->addr = cpu_to_scr(badd);
+	(data)->size = cpu_to_scr((s<<24) + len);
+	return;
+bad:
+	s = sym_lookup_dmap(np, h, s);
+	goto good;
+}
+#else
+#error "Unsupported DMA addressing mode"
+#endif
+
+/*
+ *  Set up data pointers used by SCRIPTS.
+ *  Called from O/S specific code.
+ */
+static inline void sym_setup_data_pointers(struct sym_hcb *np,
+		struct sym_ccb *cp, int dir)
+{
+	u32 lastp, goalp;
+
+	/*
+	 *  No segments means no data.
+	 */
+	if (!cp->segments)
+		dir = CAM_DIR_NONE;
+
+	/*
+	 *  Set the data pointer.
+	 */
+	switch(dir) {
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+	case CAM_DIR_UNKNOWN:
+#endif
+	case CAM_DIR_OUT:
+		goalp = SCRIPTA_BA(np, data_out2) + 8;
+		lastp = goalp - 8 - (cp->segments * (2*4));
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+		cp->wgoalp = cpu_to_scr(goalp);
+		if (dir != CAM_DIR_UNKNOWN)
+			break;
+		cp->phys.head.wlastp = cpu_to_scr(lastp);
+		/* fall through */
+#else
+		break;
+#endif
+	case CAM_DIR_IN:
+		cp->host_flags |= HF_DATA_IN;
+		goalp = SCRIPTA_BA(np, data_in2) + 8;
+		lastp = goalp - 8 - (cp->segments * (2*4));
+		break;
+	case CAM_DIR_NONE:
+	default:
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+		cp->host_flags |= HF_DATA_IN;
+#endif
+		lastp = goalp = SCRIPTB_BA(np, no_data);
+		break;
+	}
+
+	/*
+	 *  Set all pointers values needed by SCRIPTS.
+	 */
+	cp->phys.head.lastp = cpu_to_scr(lastp);
+	cp->phys.head.savep = cpu_to_scr(lastp);
+	cp->startp	    = cp->phys.head.savep;
+	cp->goalp	    = cpu_to_scr(goalp);
+
+#ifdef	SYM_OPT_HANDLE_DIR_UNKNOWN
+	/*
+	 *  If direction is unknown, start at data_io.
+	 */
+	if (dir == CAM_DIR_UNKNOWN)
+		cp->phys.head.savep = cpu_to_scr(SCRIPTB_BA(np, data_io));
+#endif
+}
+
+/*
+ *  MEMORY ALLOCATOR.
+ */
+
+#define SYM_MEM_PAGE_ORDER 0	/* 1 PAGE  maximum */
+#define SYM_MEM_CLUSTER_SHIFT	(PAGE_SHIFT+SYM_MEM_PAGE_ORDER)
+#define SYM_MEM_FREE_UNUSED	/* Free unused pages immediately */
+
+#define SYM_MEM_WARN	1	/* Warn on failed operations */
+
+#define sym_get_mem_cluster()	\
+	(void *) __get_free_pages(GFP_ATOMIC, SYM_MEM_PAGE_ORDER)
+#define sym_free_mem_cluster(p)	\
+	free_pages((unsigned long)p, SYM_MEM_PAGE_ORDER)
+
+/*
+ *  Link between free memory chunks of a given size.
+ */
+typedef struct sym_m_link {
+	struct sym_m_link *next;
+} *m_link_p;
+
+/*
+ *  Virtual to bus physical translation for a given cluster.
+ *  Such a structure is only useful with DMA abstraction.
+ */
+typedef struct sym_m_vtob {	/* Virtual to Bus address translation */
+	struct sym_m_vtob *next;
+	void *vaddr;		/* Virtual address */
+	dma_addr_t baddr;	/* Bus physical address */
+} *m_vtob_p;
+
+/* Hash this stuff a bit to speed up translations */
+#define VTOB_HASH_SHIFT		5
+#define VTOB_HASH_SIZE		(1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK		(VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m)	\
+	((((unsigned long)(m)) >> SYM_MEM_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+
+/*
+ *  Memory pool of a given kind.
+ *  Ideally, we want to use:
+ *  1) 1 pool for memory we donnot need to involve in DMA.
+ *  2) The same pool for controllers that require same DMA 
+ *     constraints and features.
+ *     The OS specific m_pool_id_t thing and the sym_m_pool_match() 
+ *     method are expected to tell the driver about.
+ */
+typedef struct sym_m_pool {
+	m_pool_ident_t	dev_dmat;	/* Identifies the pool (see above) */
+	void * (*get_mem_cluster)(struct sym_m_pool *);
+#ifdef	SYM_MEM_FREE_UNUSED
+	void (*free_mem_cluster)(struct sym_m_pool *, void *);
+#endif
+#define M_GET_MEM_CLUSTER()		mp->get_mem_cluster(mp)
+#define M_FREE_MEM_CLUSTER(p)		mp->free_mem_cluster(mp, p)
+	int nump;
+	m_vtob_p vtob[VTOB_HASH_SIZE];
+	struct sym_m_pool *next;
+	struct sym_m_link h[SYM_MEM_CLUSTER_SHIFT - SYM_MEM_SHIFT + 1];
+} *m_pool_p;
+
+/*
+ *  Alloc, free and translate addresses to bus physical 
+ *  for DMAable memory.
+ */
+void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name);
+void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name);
+dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m);
+
+/*
+ * Verbs used by the driver code for DMAable memory handling.
+ * The _uvptv_ macro avoids a nasty warning about pointer to volatile 
+ * being discarded.
+ */
+#define _uvptv_(p) ((void *)((u_long)(p)))
+
+#define _sym_calloc_dma(np, l, n)	__sym_calloc_dma(np->bus_dmat, l, n)
+#define _sym_mfree_dma(np, p, l, n)	\
+			__sym_mfree_dma(np->bus_dmat, _uvptv_(p), l, n)
+#define sym_calloc_dma(l, n)		_sym_calloc_dma(np, l, n)
+#define sym_mfree_dma(p, l, n)		_sym_mfree_dma(np, p, l, n)
+#define vtobus(p)			__vtobus(np->bus_dmat, _uvptv_(p))
+
+/*
+ *  We have to provide the driver memory allocator with methods for 
+ *  it to maintain virtual to bus physical address translations.
+ */
+
+#define sym_m_pool_match(mp_id1, mp_id2)	(mp_id1 == mp_id2)
+
+static __inline void *sym_m_get_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+{
+	void *vaddr = NULL;
+	dma_addr_t baddr = 0;
+
+	vaddr = dma_alloc_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, &baddr,
+			GFP_ATOMIC);
+	if (vaddr) {
+		vbp->vaddr = vaddr;
+		vbp->baddr = baddr;
+	}
+	return vaddr;
+}
+
+static __inline void sym_m_free_dma_mem_cluster(m_pool_p mp, m_vtob_p vbp)
+{
+	dma_free_coherent(mp->dev_dmat, SYM_MEM_CLUSTER_SIZE, vbp->vaddr,
+			vbp->baddr);
+}
+
+#endif /* SYM_HIPD_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_malloc.c b/drivers/scsi/sym53c8xx_2/sym_malloc.c
new file mode 100644
index 0000000..a34d403
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_malloc.c
@@ -0,0 +1,382 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifdef __FreeBSD__
+#include <dev/sym/sym_glue.h>
+#else
+#include "sym_glue.h"
+#endif
+
+/*
+ *  Simple power of two buddy-like generic allocator.
+ *  Provides naturally aligned memory chunks.
+ *
+ *  This simple code is not intended to be fast, but to 
+ *  provide power of 2 aligned memory allocations.
+ *  Since the SCRIPTS processor only supplies 8 bit arithmetic, 
+ *  this allocator allows simple and fast address calculations  
+ *  from the SCRIPTS code. In addition, cache line alignment 
+ *  is guaranteed for power of 2 cache line size.
+ *
+ *  This allocator has been developped for the Linux sym53c8xx  
+ *  driver, since this O/S does not provide naturally aligned 
+ *  allocations.
+ *  It has the advantage of allowing the driver to use private 
+ *  pages of memory that will be useful if we ever need to deal 
+ *  with IO MMUs for PCI.
+ */
+static void *___sym_malloc(m_pool_p mp, int size)
+{
+	int i = 0;
+	int s = (1 << SYM_MEM_SHIFT);
+	int j;
+	void *a;
+	m_link_p h = mp->h;
+
+	if (size > SYM_MEM_CLUSTER_SIZE)
+		return NULL;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	j = i;
+	while (!h[j].next) {
+		if (s == SYM_MEM_CLUSTER_SIZE) {
+			h[j].next = (m_link_p) M_GET_MEM_CLUSTER();
+			if (h[j].next)
+				h[j].next->next = NULL;
+			break;
+		}
+		++j;
+		s <<= 1;
+	}
+	a = h[j].next;
+	if (a) {
+		h[j].next = h[j].next->next;
+		while (j > i) {
+			j -= 1;
+			s >>= 1;
+			h[j].next = (m_link_p) (a+s);
+			h[j].next->next = NULL;
+		}
+	}
+#ifdef DEBUG
+	printf("___sym_malloc(%d) = %p\n", size, (void *) a);
+#endif
+	return a;
+}
+
+/*
+ *  Counter-part of the generic allocator.
+ */
+static void ___sym_mfree(m_pool_p mp, void *ptr, int size)
+{
+	int i = 0;
+	int s = (1 << SYM_MEM_SHIFT);
+	m_link_p q;
+	unsigned long a, b;
+	m_link_p h = mp->h;
+
+#ifdef DEBUG
+	printf("___sym_mfree(%p, %d)\n", ptr, size);
+#endif
+
+	if (size > SYM_MEM_CLUSTER_SIZE)
+		return;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	a = (unsigned long)ptr;
+
+	while (1) {
+		if (s == SYM_MEM_CLUSTER_SIZE) {
+#ifdef SYM_MEM_FREE_UNUSED
+			M_FREE_MEM_CLUSTER((void *)a);
+#else
+			((m_link_p) a)->next = h[i].next;
+			h[i].next = (m_link_p) a;
+#endif
+			break;
+		}
+		b = a ^ s;
+		q = &h[i];
+		while (q->next && q->next != (m_link_p) b) {
+			q = q->next;
+		}
+		if (!q->next) {
+			((m_link_p) a)->next = h[i].next;
+			h[i].next = (m_link_p) a;
+			break;
+		}
+		q->next = q->next->next;
+		a = a & b;
+		s <<= 1;
+		++i;
+	}
+}
+
+/*
+ *  Verbose and zeroing allocator that wrapps to the generic allocator.
+ */
+static void *__sym_calloc2(m_pool_p mp, int size, char *name, int uflags)
+{
+	void *p;
+
+	p = ___sym_malloc(mp, size);
+
+	if (DEBUG_FLAGS & DEBUG_ALLOC) {
+		printf ("new %-10s[%4d] @%p.\n", name, size, p);
+	}
+
+	if (p)
+		memset(p, 0, size);
+	else if (uflags & SYM_MEM_WARN)
+		printf ("__sym_calloc2: failed to allocate %s[%d]\n", name, size);
+	return p;
+}
+#define __sym_calloc(mp, s, n)	__sym_calloc2(mp, s, n, SYM_MEM_WARN)
+
+/*
+ *  Its counter-part.
+ */
+static void __sym_mfree(m_pool_p mp, void *ptr, int size, char *name)
+{
+	if (DEBUG_FLAGS & DEBUG_ALLOC)
+		printf ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+
+	___sym_mfree(mp, ptr, size);
+}
+
+/*
+ *  Default memory pool we donnot need to involve in DMA.
+ *
+ *  With DMA abstraction, we use functions (methods), to 
+ *  distinguish between non DMAable memory and DMAable memory.
+ */
+static void *___mp0_get_mem_cluster(m_pool_p mp)
+{
+	void *m = sym_get_mem_cluster();
+	if (m)
+		++mp->nump;
+	return m;
+}
+
+#ifdef	SYM_MEM_FREE_UNUSED
+static void ___mp0_free_mem_cluster(m_pool_p mp, void *m)
+{
+	sym_free_mem_cluster(m);
+	--mp->nump;
+}
+#else
+#define ___mp0_free_mem_cluster NULL
+#endif
+
+static struct sym_m_pool mp0 = {
+	NULL,
+	___mp0_get_mem_cluster,
+	___mp0_free_mem_cluster
+};
+
+/*
+ *  Methods that maintains DMAable pools according to user allocations.
+ *  New pools are created on the fly when a new pool id is provided.
+ *  They are deleted on the fly when they get emptied.
+ */
+/* Get a memory cluster that matches the DMA constraints of a given pool */
+static void * ___get_dma_mem_cluster(m_pool_p mp)
+{
+	m_vtob_p vbp;
+	void *vaddr;
+
+	vbp = __sym_calloc(&mp0, sizeof(*vbp), "VTOB");
+	if (!vbp)
+		goto out_err;
+
+	vaddr = sym_m_get_dma_mem_cluster(mp, vbp);
+	if (vaddr) {
+		int hc = VTOB_HASH_CODE(vaddr);
+		vbp->next = mp->vtob[hc];
+		mp->vtob[hc] = vbp;
+		++mp->nump;
+	}
+	return vaddr;
+out_err:
+	return NULL;
+}
+
+#ifdef	SYM_MEM_FREE_UNUSED
+/* Free a memory cluster and associated resources for DMA */
+static void ___free_dma_mem_cluster(m_pool_p mp, void *m)
+{
+	m_vtob_p *vbpp, vbp;
+	int hc = VTOB_HASH_CODE(m);
+
+	vbpp = &mp->vtob[hc];
+	while (*vbpp && (*vbpp)->vaddr != m)
+		vbpp = &(*vbpp)->next;
+	if (*vbpp) {
+		vbp = *vbpp;
+		*vbpp = (*vbpp)->next;
+		sym_m_free_dma_mem_cluster(mp, vbp);
+		__sym_mfree(&mp0, vbp, sizeof(*vbp), "VTOB");
+		--mp->nump;
+	}
+}
+#endif
+
+/* Fetch the memory pool for a given pool id (i.e. DMA constraints) */
+static __inline m_pool_p ___get_dma_pool(m_pool_ident_t dev_dmat)
+{
+	m_pool_p mp;
+	for (mp = mp0.next;
+		mp && !sym_m_pool_match(mp->dev_dmat, dev_dmat);
+			mp = mp->next);
+	return mp;
+}
+
+/* Create a new memory DMAable pool (when fetch failed) */
+static m_pool_p ___cre_dma_pool(m_pool_ident_t dev_dmat)
+{
+	m_pool_p mp = __sym_calloc(&mp0, sizeof(*mp), "MPOOL");
+	if (mp) {
+		mp->dev_dmat = dev_dmat;
+		mp->get_mem_cluster = ___get_dma_mem_cluster;
+#ifdef	SYM_MEM_FREE_UNUSED
+		mp->free_mem_cluster = ___free_dma_mem_cluster;
+#endif
+		mp->next = mp0.next;
+		mp0.next = mp;
+		return mp;
+	}
+	return NULL;
+}
+
+#ifdef	SYM_MEM_FREE_UNUSED
+/* Destroy a DMAable memory pool (when got emptied) */
+static void ___del_dma_pool(m_pool_p p)
+{
+	m_pool_p *pp = &mp0.next;
+
+	while (*pp && *pp != p)
+		pp = &(*pp)->next;
+	if (*pp) {
+		*pp = (*pp)->next;
+		__sym_mfree(&mp0, p, sizeof(*p), "MPOOL");
+	}
+}
+#endif
+
+/* This lock protects only the memory allocation/free.  */
+static DEFINE_SPINLOCK(sym53c8xx_lock);
+
+/*
+ *  Actual allocator for DMAable memory.
+ */
+void *__sym_calloc_dma(m_pool_ident_t dev_dmat, int size, char *name)
+{
+	unsigned long flags;
+	m_pool_p mp;
+	void *m = NULL;
+
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
+	mp = ___get_dma_pool(dev_dmat);
+	if (!mp)
+		mp = ___cre_dma_pool(dev_dmat);
+	if (!mp)
+		goto out;
+	m = __sym_calloc(mp, size, name);
+#ifdef	SYM_MEM_FREE_UNUSED
+	if (!mp->nump)
+		___del_dma_pool(mp);
+#endif
+
+ out:
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
+	return m;
+}
+
+void __sym_mfree_dma(m_pool_ident_t dev_dmat, void *m, int size, char *name)
+{
+	unsigned long flags;
+	m_pool_p mp;
+
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
+	mp = ___get_dma_pool(dev_dmat);
+	if (!mp)
+		goto out;
+	__sym_mfree(mp, m, size, name);
+#ifdef	SYM_MEM_FREE_UNUSED
+	if (!mp->nump)
+		___del_dma_pool(mp);
+#endif
+ out:
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
+}
+
+/*
+ *  Actual virtual to bus physical address translator 
+ *  for 32 bit addressable DMAable memory.
+ */
+dma_addr_t __vtobus(m_pool_ident_t dev_dmat, void *m)
+{
+	unsigned long flags;
+	m_pool_p mp;
+	int hc = VTOB_HASH_CODE(m);
+	m_vtob_p vp = NULL;
+	void *a = (void *)((unsigned long)m & ~SYM_MEM_CLUSTER_MASK);
+	dma_addr_t b;
+
+	spin_lock_irqsave(&sym53c8xx_lock, flags);
+	mp = ___get_dma_pool(dev_dmat);
+	if (mp) {
+		vp = mp->vtob[hc];
+		while (vp && vp->vaddr != a)
+			vp = vp->next;
+	}
+	if (!vp)
+		panic("sym: VTOBUS FAILED!\n");
+	b = vp->baddr + (m - a);
+	spin_unlock_irqrestore(&sym53c8xx_lock, flags);
+	return b;
+}
diff --git a/drivers/scsi/sym53c8xx_2/sym_misc.h b/drivers/scsi/sym53c8xx_2/sym_misc.h
new file mode 100644
index 0000000..0433d5d
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_misc.h
@@ -0,0 +1,192 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM_MISC_H
+#define SYM_MISC_H
+
+/*
+ *  A la VMS/CAM-3 queue management.
+ */
+typedef struct sym_quehead {
+	struct sym_quehead *flink;	/* Forward  pointer */
+	struct sym_quehead *blink;	/* Backward pointer */
+} SYM_QUEHEAD;
+
+#define sym_que_init(ptr) do { \
+	(ptr)->flink = (ptr); (ptr)->blink = (ptr); \
+} while (0)
+
+static __inline struct sym_quehead *sym_que_first(struct sym_quehead *head)
+{
+	return (head->flink == head) ? 0 : head->flink;
+}
+
+static __inline struct sym_quehead *sym_que_last(struct sym_quehead *head)
+{
+	return (head->blink == head) ? 0 : head->blink;
+}
+
+static __inline void __sym_que_add(struct sym_quehead * new,
+	struct sym_quehead * blink,
+	struct sym_quehead * flink)
+{
+	flink->blink	= new;
+	new->flink	= flink;
+	new->blink	= blink;
+	blink->flink	= new;
+}
+
+static __inline void __sym_que_del(struct sym_quehead * blink,
+	struct sym_quehead * flink)
+{
+	flink->blink = blink;
+	blink->flink = flink;
+}
+
+static __inline int sym_que_empty(struct sym_quehead *head)
+{
+	return head->flink == head;
+}
+
+static __inline void sym_que_splice(struct sym_quehead *list,
+	struct sym_quehead *head)
+{
+	struct sym_quehead *first = list->flink;
+
+	if (first != list) {
+		struct sym_quehead *last = list->blink;
+		struct sym_quehead *at   = head->flink;
+
+		first->blink = head;
+		head->flink  = first;
+
+		last->flink = at;
+		at->blink   = last;
+	}
+}
+
+static __inline void sym_que_move(struct sym_quehead *orig,
+	struct sym_quehead *dest)
+{
+	struct sym_quehead *first, *last;
+
+	first = orig->flink;
+	if (first != orig) {
+		first->blink = dest;
+		dest->flink  = first;
+		last = orig->blink;
+		last->flink  = dest;
+		dest->blink  = last;
+		orig->flink  = orig;
+		orig->blink  = orig;
+	} else {
+		dest->flink  = dest;
+		dest->blink  = dest;
+	}
+}
+
+#define sym_que_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(unsigned int)(&((type *)0)->member)))
+
+
+#define sym_insque(new, pos)		__sym_que_add(new, pos, (pos)->flink)
+
+#define sym_remque(el)			__sym_que_del((el)->blink, (el)->flink)
+
+#define sym_insque_head(new, head)	__sym_que_add(new, head, (head)->flink)
+
+static __inline struct sym_quehead *sym_remque_head(struct sym_quehead *head)
+{
+	struct sym_quehead *elem = head->flink;
+
+	if (elem != head)
+		__sym_que_del(head, elem->flink);
+	else
+		elem = NULL;
+	return elem;
+}
+
+#define sym_insque_tail(new, head)	__sym_que_add(new, (head)->blink, head)
+
+static __inline struct sym_quehead *sym_remque_tail(struct sym_quehead *head)
+{
+	struct sym_quehead *elem = head->blink;
+
+	if (elem != head)
+		__sym_que_del(elem->blink, head);
+	else
+		elem = 0;
+	return elem;
+}
+
+/*
+ *  This one may be useful.
+ */
+#define FOR_EACH_QUEUED_ELEMENT(head, qp) \
+	for (qp = (head)->flink; qp != (head); qp = qp->flink)
+/*
+ *  FreeBSD does not offer our kind of queue in the CAM CCB.
+ *  So, we have to cast.
+ */
+#define sym_qptr(p)	((struct sym_quehead *) (p))
+
+/*
+ *  Simple bitmap operations.
+ */ 
+#define sym_set_bit(p, n)	(((u32 *)(p))[(n)>>5] |=  (1<<((n)&0x1f)))
+#define sym_clr_bit(p, n)	(((u32 *)(p))[(n)>>5] &= ~(1<<((n)&0x1f)))
+#define sym_is_bit(p, n)	(((u32 *)(p))[(n)>>5] &   (1<<((n)&0x1f)))
+
+/*
+ * The below round up/down macros are to be used with a constant 
+ * as argument (sizeof(...) for example), for the compiler to 
+ * optimize the whole thing.
+ */
+#define _U_(a,m)	(a)<=(1<<m)?m:
+
+/*
+ * Round up logarithm to base 2 of a 16 bit constant.
+ */
+#define _LGRU16_(a) \
+( \
+ _U_(a, 0)_U_(a, 1)_U_(a, 2)_U_(a, 3)_U_(a, 4)_U_(a, 5)_U_(a, 6)_U_(a, 7) \
+ _U_(a, 8)_U_(a, 9)_U_(a,10)_U_(a,11)_U_(a,12)_U_(a,13)_U_(a,14)_U_(a,15) \
+ 16)
+
+#endif /* SYM_MISC_H */
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.c b/drivers/scsi/sym53c8xx_2/sym_nvram.c
new file mode 100644
index 0000000..1b721e3
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.c
@@ -0,0 +1,771 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include "sym_glue.h"
+#include "sym_nvram.h"
+
+#ifdef	SYM_CONF_DEBUG_NVRAM
+static u_char Tekram_boot_delay[7] = {3, 5, 10, 20, 30, 60, 120};
+#endif
+
+/*
+ *  Get host setup from NVRAM.
+ */
+void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram)
+{
+	/*
+	 *  Get parity checking, host ID, verbose mode 
+	 *  and miscellaneous host flags from NVRAM.
+	 */
+	switch (nvram->type) {
+	case SYM_SYMBIOS_NVRAM:
+		if (!(nvram->data.Symbios.flags & SYMBIOS_PARITY_ENABLE))
+			np->rv_scntl0  &= ~0x0a;
+		np->myaddr = nvram->data.Symbios.host_id & 0x0f;
+		if (nvram->data.Symbios.flags & SYMBIOS_VERBOSE_MSGS)
+			np->verbose += 1;
+		if (nvram->data.Symbios.flags1 & SYMBIOS_SCAN_HI_LO)
+			shost->reverse_ordering = 1;
+		if (nvram->data.Symbios.flags2 & SYMBIOS_AVOID_BUS_RESET)
+			np->usrflags |= SYM_AVOID_BUS_RESET;
+		break;
+	case SYM_TEKRAM_NVRAM:
+		np->myaddr = nvram->data.Tekram.host_id & 0x0f;
+		break;
+#ifdef CONFIG_PARISC
+	case SYM_PARISC_PDC:
+		if (nvram->data.parisc.host_id != -1)
+			np->myaddr = nvram->data.parisc.host_id;
+		if (nvram->data.parisc.factor != -1)
+			np->minsync = nvram->data.parisc.factor;
+		if (nvram->data.parisc.width != -1)
+			np->maxwide = nvram->data.parisc.width;
+		switch (nvram->data.parisc.mode) {
+			case 0: np->scsi_mode = SMODE_SE; break;
+			case 1: np->scsi_mode = SMODE_HVD; break;
+			case 2: np->scsi_mode = SMODE_LVD; break;
+			default: break;
+		}
+#endif
+	default:
+		break;
+	}
+}
+
+/*
+ *  Get target set-up from Symbios format NVRAM.
+ */
+static void
+sym_Symbios_setup_target(struct sym_hcb *np, int target, Symbios_nvram *nvram)
+{
+	struct sym_tcb *tp = &np->target[target];
+	Symbios_target *tn = &nvram->target[target];
+
+	tp->usrtags =
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SYM_SETUP_MAX_TAG : 0;
+
+	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
+		tp->usrflags &= ~SYM_DISC_ENABLED;
+	if (!(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME))
+		tp->usrflags |= SYM_SCAN_BOOT_DISABLED;
+	if (!(tn->flags & SYMBIOS_SCAN_LUNS))
+		tp->usrflags |= SYM_SCAN_LUNS_DISABLED;
+}
+
+/*
+ *  Get target set-up from Tekram format NVRAM.
+ */
+static void
+sym_Tekram_setup_target(struct sym_hcb *np, int target, Tekram_nvram *nvram)
+{
+	struct sym_tcb *tp = &np->target[target];
+	struct Tekram_target *tn = &nvram->target[target];
+
+	if (tn->flags & TEKRAM_TAGGED_COMMANDS) {
+		tp->usrtags = 2 << nvram->max_tags_index;
+	}
+
+	if (tn->flags & TEKRAM_DISCONNECT_ENABLE)
+		tp->usrflags |= SYM_DISC_ENABLED;
+ 
+	/* If any device does not support parity, we will not use this option */
+	if (!(tn->flags & TEKRAM_PARITY_CHECK))
+		np->rv_scntl0  &= ~0x0a; /* SCSI parity checking disabled */
+}
+
+/*
+ *  Get target setup from NVRAM.
+ */
+void sym_nvram_setup_target(struct sym_hcb *np, int target, struct sym_nvram *nvp)
+{
+	switch (nvp->type) {
+	case SYM_SYMBIOS_NVRAM:
+		sym_Symbios_setup_target(np, target, &nvp->data.Symbios);
+		break;
+	case SYM_TEKRAM_NVRAM:
+		sym_Tekram_setup_target(np, target, &nvp->data.Tekram);
+		break;
+	default:
+		break;
+	}
+}
+
+#ifdef	SYM_CONF_DEBUG_NVRAM
+/*
+ *  Dump Symbios format NVRAM for debugging purpose.
+ */
+static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
+{
+	int i;
+
+	/* display Symbios nvram host data */
+	printf("%s: HOST ID=%d%s%s%s%s%s%s\n",
+		sym_name(np), nvram->host_id & 0x0f,
+		(nvram->flags  & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags  & SYMBIOS_PARITY_ENABLE)	? " PARITY"	:"",
+		(nvram->flags  & SYMBIOS_VERBOSE_MSGS)	? " VERBOSE"	:"", 
+		(nvram->flags  & SYMBIOS_CHS_MAPPING)	? " CHS_ALT"	:"", 
+		(nvram->flags2 & SYMBIOS_AVOID_BUS_RESET)?" NO_RESET"	:"",
+		(nvram->flags1 & SYMBIOS_SCAN_HI_LO)	? " HI_LO"	:"");
+
+	/* display Symbios nvram drive data */
+	for (i = 0 ; i < 15 ; i++) {
+		struct Symbios_target *tn = &nvram->target[i];
+		printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n",
+		sym_name(np), i,
+		(tn->flags & SYMBIOS_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME)	? " SCAN_BOOT"	: "",
+		(tn->flags & SYMBIOS_SCAN_LUNS)		? " SCAN_LUNS"	: "",
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? " TCQ"	: "",
+		tn->bus_width,
+		tn->sync_period / 4,
+		tn->timeout);
+	}
+}
+
+/*
+ *  Dump TEKRAM format NVRAM for debugging purpose.
+ */
+static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram)
+{
+	int i, tags, boot_delay;
+	char *rem;
+
+	/* display Tekram nvram host data */
+	tags = 2 << nvram->max_tags_index;
+	boot_delay = 0;
+	if (nvram->boot_delay_index < 6)
+		boot_delay = Tekram_boot_delay[nvram->boot_delay_index];
+	switch ((nvram->flags & TEKRAM_REMOVABLE_FLAGS) >> 6) {
+	default:
+	case 0:	rem = "";			break;
+	case 1: rem = " REMOVABLE=boot device";	break;
+	case 2: rem = " REMOVABLE=all";		break;
+	}
+
+	printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n",
+		sym_name(np), nvram->host_id & 0x0f,
+		(nvram->flags1 & SYMBIOS_SCAM_ENABLE)	? " SCAM"	:"",
+		(nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES":"",
+		(nvram->flags & TEKRAM_DRIVES_SUP_1GB)	? " >1GB"	:"",
+		(nvram->flags & TEKRAM_RESET_ON_POWER_ON) ? " RESET"	:"",
+		(nvram->flags & TEKRAM_ACTIVE_NEGATION)	? " ACT_NEG"	:"",
+		(nvram->flags & TEKRAM_IMMEDIATE_SEEK)	? " IMM_SEEK"	:"",
+		(nvram->flags & TEKRAM_SCAN_LUNS)	? " SCAN_LUNS"	:"",
+		(nvram->flags1 & TEKRAM_F2_F6_ENABLED)	? " F2_F6"	:"",
+		rem, boot_delay, tags);
+
+	/* display Tekram nvram drive data */
+	for (i = 0; i <= 15; i++) {
+		int sync, j;
+		struct Tekram_target *tn = &nvram->target[i];
+		j = tn->sync_index & 0xf;
+		sync = Tekram_sync[j];
+		printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n",
+		sym_name(np), i,
+		(tn->flags & TEKRAM_PARITY_CHECK)	? " PARITY"	: "",
+		(tn->flags & TEKRAM_SYNC_NEGO)		? " SYNC"	: "",
+		(tn->flags & TEKRAM_DISCONNECT_ENABLE)	? " DISC"	: "",
+		(tn->flags & TEKRAM_START_CMD)		? " START"	: "",
+		(tn->flags & TEKRAM_TAGGED_COMMANDS)	? " TCQ"	: "",
+		(tn->flags & TEKRAM_WIDE_NEGO)		? " WIDE"	: "",
+		sync);
+	}
+}
+#else
+static void sym_display_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram) { (void)np; (void)nvram; }
+static void sym_display_Tekram_nvram(struct sym_device *np, Tekram_nvram *nvram) { (void)np; (void)nvram; }
+#endif	/* SYM_CONF_DEBUG_NVRAM */
+
+
+/*
+ *  24C16 EEPROM reading.
+ *
+ *  GPOI0 - data in/data out
+ *  GPIO1 - clock
+ *  Symbios NVRAM wiring now also used by Tekram.
+ */
+
+#define SET_BIT 0
+#define CLR_BIT 1
+#define SET_CLK 2
+#define CLR_CLK 3
+
+/*
+ *  Set/clear data/clock bit in GPIO0
+ */
+static void S24C16_set_bit(struct sym_device *np, u_char write_bit, u_char *gpreg, 
+			  int bit_mode)
+{
+	udelay(5);
+	switch (bit_mode) {
+	case SET_BIT:
+		*gpreg |= write_bit;
+		break;
+	case CLR_BIT:
+		*gpreg &= 0xfe;
+		break;
+	case SET_CLK:
+		*gpreg |= 0x02;
+		break;
+	case CLR_CLK:
+		*gpreg &= 0xfd;
+		break;
+
+	}
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(5);
+}
+
+/*
+ *  Send START condition to NVRAM to wake it up.
+ */
+static void S24C16_start(struct sym_device *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+}
+
+/*
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
+ */
+static void S24C16_stop(struct sym_device *np, u_char *gpreg)
+{
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	S24C16_set_bit(np, 1, gpreg, SET_BIT);
+}
+
+/*
+ *  Read or write a bit to the NVRAM,
+ *  read if GPIO0 input else write if GPIO0 output
+ */
+static void S24C16_do_bit(struct sym_device *np, u_char *read_bit, u_char write_bit, 
+			 u_char *gpreg)
+{
+	S24C16_set_bit(np, write_bit, gpreg, SET_BIT);
+	S24C16_set_bit(np, 0, gpreg, SET_CLK);
+	if (read_bit)
+		*read_bit = INB(np, nc_gpreg);
+	S24C16_set_bit(np, 0, gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, gpreg, CLR_BIT);
+}
+
+/*
+ *  Output an ACK to the NVRAM after reading,
+ *  change GPIO0 to output and when done back to an input
+ */
+static void S24C16_write_ack(struct sym_device *np, u_char write_bit, u_char *gpreg, 
+			    u_char *gpcntl)
+{
+	OUTB(np, nc_gpcntl, *gpcntl & 0xfe);
+	S24C16_do_bit(np, NULL, write_bit, gpreg);
+	OUTB(np, nc_gpcntl, *gpcntl);
+}
+
+/*
+ *  Input an ACK from NVRAM after writing,
+ *  change GPIO0 to input and when done back to an output
+ */
+static void S24C16_read_ack(struct sym_device *np, u_char *read_bit, u_char *gpreg, 
+			   u_char *gpcntl)
+{
+	OUTB(np, nc_gpcntl, *gpcntl | 0x01);
+	S24C16_do_bit(np, read_bit, 1, gpreg);
+	OUTB(np, nc_gpcntl, *gpcntl);
+}
+
+/*
+ *  WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
+ *  GPIO0 must already be set as an output
+ */
+static void S24C16_write_byte(struct sym_device *np, u_char *ack_data, u_char write_data, 
+			     u_char *gpreg, u_char *gpcntl)
+{
+	int x;
+	
+	for (x = 0; x < 8; x++)
+		S24C16_do_bit(np, NULL, (write_data >> (7 - x)) & 0x01, gpreg);
+		
+	S24C16_read_ack(np, ack_data, gpreg, gpcntl);
+}
+
+/*
+ *  READ a byte from the NVRAM and then send an ACK to say we have got it,
+ *  GPIO0 must already be set as an input
+ */
+static void S24C16_read_byte(struct sym_device *np, u_char *read_data, u_char ack_data, 
+			    u_char *gpreg, u_char *gpcntl)
+{
+	int x;
+	u_char read_bit;
+
+	*read_data = 0;
+	for (x = 0; x < 8; x++) {
+		S24C16_do_bit(np, &read_bit, 1, gpreg);
+		*read_data |= ((read_bit & 0x01) << (7 - x));
+	}
+
+	S24C16_write_ack(np, ack_data, gpreg, gpcntl);
+}
+
+#if SYM_CONF_NVRAM_WRITE_SUPPORT
+/*
+ *  Write 'len' bytes starting at 'offset'.
+ */
+static int sym_write_S24C16_nvram(struct sym_device *np, int offset,
+		u_char *data, int len)
+{
+	u_char	gpcntl, gpreg;
+	u_char	old_gpcntl, old_gpreg;
+	u_char	ack_data;
+	int	x;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
+	gpcntl		= old_gpcntl & 0x1c;
+
+	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+	OUTB(np, nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, gpcntl);
+
+	/* this is to set NVRAM into a known state with GPIO0/1 both low */
+	gpreg = old_gpreg;
+	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
+		
+	/* now set NVRAM inactive with GPIO0/1 both high */
+	S24C16_stop(np, &gpreg);
+
+	/* NVRAM has to be written in segments of 16 bytes */
+	for (x = 0; x < len ; x += 16) {
+		do {
+			S24C16_start(np, &gpreg);
+			S24C16_write_byte(np, &ack_data,
+					  0xa0 | (((offset+x) >> 7) & 0x0e),
+					  &gpreg, &gpcntl);
+		} while (ack_data & 0x01);
+
+		S24C16_write_byte(np, &ack_data, (offset+x) & 0xff, 
+				  &gpreg, &gpcntl);
+
+		for (y = 0; y < 16; y++)
+			S24C16_write_byte(np, &ack_data, data[x+y], 
+					  &gpreg, &gpcntl);
+		S24C16_stop(np, &gpreg);
+	}
+
+	/* return GPIO0/1 to original states after having accessed NVRAM */
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
+
+	return 0;
+}
+#endif /* SYM_CONF_NVRAM_WRITE_SUPPORT */
+
+/*
+ *  Read 'len' bytes starting at 'offset'.
+ */
+static int sym_read_S24C16_nvram(struct sym_device *np, int offset, u_char *data, int len)
+{
+	u_char	gpcntl, gpreg;
+	u_char	old_gpcntl, old_gpreg;
+	u_char	ack_data;
+	int	retv = 1;
+	int	x;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
+	gpcntl		= old_gpcntl & 0x1c;
+
+	/* set up GPREG & GPCNTL to set GPIO0 and GPIO1 in to known state */
+	OUTB(np, nc_gpreg,  old_gpreg);
+	OUTB(np, nc_gpcntl, gpcntl);
+
+	/* this is to set NVRAM into a known state with GPIO0/1 both low */
+	gpreg = old_gpreg;
+	S24C16_set_bit(np, 0, &gpreg, CLR_CLK);
+	S24C16_set_bit(np, 0, &gpreg, CLR_BIT);
+		
+	/* now set NVRAM inactive with GPIO0/1 both high */
+	S24C16_stop(np, &gpreg);
+	
+	/* activate NVRAM */
+	S24C16_start(np, &gpreg);
+
+	/* write device code and random address MSB */
+	S24C16_write_byte(np, &ack_data,
+		0xa0 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* write random address LSB */
+	S24C16_write_byte(np, &ack_data,
+		offset & 0xff, &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* regenerate START state to set up for reading */
+	S24C16_start(np, &gpreg);
+	
+	/* rewrite device code and address MSB with read bit set (lsb = 0x01) */
+	S24C16_write_byte(np, &ack_data,
+		0xa1 | ((offset >> 7) & 0x0e), &gpreg, &gpcntl);
+	if (ack_data & 0x01)
+		goto out;
+
+	/* now set up GPIO0 for inputting data */
+	gpcntl |= 0x01;
+	OUTB(np, nc_gpcntl, gpcntl);
+		
+	/* input all requested data - only part of total NVRAM */
+	for (x = 0; x < len; x++) 
+		S24C16_read_byte(np, &data[x], (x == (len-1)), &gpreg, &gpcntl);
+
+	/* finally put NVRAM back in inactive mode */
+	gpcntl &= 0xfe;
+	OUTB(np, nc_gpcntl, gpcntl);
+	S24C16_stop(np, &gpreg);
+	retv = 0;
+out:
+	/* return GPIO0/1 to original states after having accessed NVRAM */
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
+
+	return retv;
+}
+
+#undef SET_BIT
+#undef CLR_BIT
+#undef SET_CLK
+#undef CLR_CLK
+
+/*
+ *  Try reading Symbios NVRAM.
+ *  Return 0 if OK.
+ */
+static int sym_read_Symbios_nvram(struct sym_device *np, Symbios_nvram *nvram)
+{
+	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
+	u_char *data = (u_char *) nvram;
+	int len  = sizeof(*nvram);
+	u_short	csum;
+	int x;
+
+	/* probe the 24c16 and read the SYMBIOS 24c16 area */
+	if (sym_read_S24C16_nvram (np, SYMBIOS_NVRAM_ADDRESS, data, len))
+		return 1;
+
+	/* check valid NVRAM signature, verify byte count and checksum */
+	if (nvram->type != 0 ||
+	    memcmp(nvram->trailer, Symbios_trailer, 6) ||
+	    nvram->byte_count != len - 12)
+		return 1;
+
+	/* verify checksum */
+	for (x = 6, csum = 0; x < len - 6; x++)
+		csum += data[x];
+	if (csum != nvram->checksum)
+		return 1;
+
+	return 0;
+}
+
+/*
+ *  93C46 EEPROM reading.
+ *
+ *  GPOI0 - data in
+ *  GPIO1 - data out
+ *  GPIO2 - clock
+ *  GPIO4 - chip select
+ *
+ *  Used by Tekram.
+ */
+
+/*
+ *  Pulse clock bit in GPIO0
+ */
+static void T93C46_Clk(struct sym_device *np, u_char *gpreg)
+{
+	OUTB(np, nc_gpreg, *gpreg | 0x04);
+	udelay(2);
+	OUTB(np, nc_gpreg, *gpreg);
+}
+
+/* 
+ *  Read bit from NVRAM
+ */
+static void T93C46_Read_Bit(struct sym_device *np, u_char *read_bit, u_char *gpreg)
+{
+	udelay(2);
+	T93C46_Clk(np, gpreg);
+	*read_bit = INB(np, nc_gpreg);
+}
+
+/*
+ *  Write bit to GPIO0
+ */
+static void T93C46_Write_Bit(struct sym_device *np, u_char write_bit, u_char *gpreg)
+{
+	if (write_bit & 0x01)
+		*gpreg |= 0x02;
+	else
+		*gpreg &= 0xfd;
+		
+	*gpreg |= 0x10;
+		
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(2);
+
+	T93C46_Clk(np, gpreg);
+}
+
+/*
+ *  Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
+ */
+static void T93C46_Stop(struct sym_device *np, u_char *gpreg)
+{
+	*gpreg &= 0xef;
+	OUTB(np, nc_gpreg, *gpreg);
+	udelay(2);
+
+	T93C46_Clk(np, gpreg);
+}
+
+/*
+ *  Send read command and address to NVRAM
+ */
+static void T93C46_Send_Command(struct sym_device *np, u_short write_data, 
+				u_char *read_bit, u_char *gpreg)
+{
+	int x;
+
+	/* send 9 bits, start bit (1), command (2), address (6)  */
+	for (x = 0; x < 9; x++)
+		T93C46_Write_Bit(np, (u_char) (write_data >> (8 - x)), gpreg);
+
+	*read_bit = INB(np, nc_gpreg);
+}
+
+/*
+ *  READ 2 bytes from the NVRAM
+ */
+static void T93C46_Read_Word(struct sym_device *np,
+		unsigned short *nvram_data, unsigned char *gpreg)
+{
+	int x;
+	u_char read_bit;
+
+	*nvram_data = 0;
+	for (x = 0; x < 16; x++) {
+		T93C46_Read_Bit(np, &read_bit, gpreg);
+
+		if (read_bit & 0x01)
+			*nvram_data |=  (0x01 << (15 - x));
+		else
+			*nvram_data &= ~(0x01 << (15 - x));
+	}
+}
+
+/*
+ *  Read Tekram NvRAM data.
+ */
+static int T93C46_Read_Data(struct sym_device *np, unsigned short *data,
+		int len, unsigned char *gpreg)
+{
+	int x;
+
+	for (x = 0; x < len; x++)  {
+		unsigned char read_bit;
+		/* output read command and address */
+		T93C46_Send_Command(np, 0x180 | x, &read_bit, gpreg);
+		if (read_bit & 0x01)
+			return 1; /* Bad */
+		T93C46_Read_Word(np, &data[x], gpreg);
+		T93C46_Stop(np, gpreg);
+	}
+
+	return 0;
+}
+
+/*
+ *  Try reading 93C46 Tekram NVRAM.
+ */
+static int sym_read_T93C46_nvram(struct sym_device *np, Tekram_nvram *nvram)
+{
+	u_char gpcntl, gpreg;
+	u_char old_gpcntl, old_gpreg;
+	int retv = 1;
+
+	/* save current state of GPCNTL and GPREG */
+	old_gpreg	= INB(np, nc_gpreg);
+	old_gpcntl	= INB(np, nc_gpcntl);
+
+	/* set up GPREG & GPCNTL to set GPIO0/1/2/4 in to known state, 0 in,
+	   1/2/4 out */
+	gpreg = old_gpreg & 0xe9;
+	OUTB(np, nc_gpreg, gpreg);
+	gpcntl = (old_gpcntl & 0xe9) | 0x09;
+	OUTB(np, nc_gpcntl, gpcntl);
+
+	/* input all of NVRAM, 64 words */
+	retv = T93C46_Read_Data(np, (u_short *) nvram,
+				sizeof(*nvram) / sizeof(short), &gpreg);
+	
+	/* return GPIO0/1/2/4 to original states after having accessed NVRAM */
+	OUTB(np, nc_gpcntl, old_gpcntl);
+	OUTB(np, nc_gpreg,  old_gpreg);
+
+	return retv;
+}
+
+/*
+ *  Try reading Tekram NVRAM.
+ *  Return 0 if OK.
+ */
+static int sym_read_Tekram_nvram (struct sym_device *np, Tekram_nvram *nvram)
+{
+	u_char *data = (u_char *) nvram;
+	int len = sizeof(*nvram);
+	u_short	csum;
+	int x;
+
+	switch (np->device_id) {
+	case PCI_DEVICE_ID_NCR_53C885:
+	case PCI_DEVICE_ID_NCR_53C895:
+	case PCI_DEVICE_ID_NCR_53C896:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		break;
+	case PCI_DEVICE_ID_NCR_53C875:
+		x = sym_read_S24C16_nvram(np, TEKRAM_24C16_NVRAM_ADDRESS,
+					  data, len);
+		if (!x)
+			break;
+	default:
+		x = sym_read_T93C46_nvram(np, nvram);
+		break;
+	}
+	if (x)
+		return 1;
+
+	/* verify checksum */
+	for (x = 0, csum = 0; x < len - 1; x += 2)
+		csum += data[x] + (data[x+1] << 8);
+	if (csum != 0x1234)
+		return 1;
+
+	return 0;
+}
+
+#ifdef CONFIG_PARISC
+/*
+ * Host firmware (PDC) keeps a table for altering SCSI capabilities.
+ * Many newer machines export one channel of 53c896 chip as SE, 50-pin HD.
+ * Also used for Multi-initiator SCSI clusters to set the SCSI Initiator ID.
+ */
+static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *pdc)
+{
+	struct hardware_path hwpath;
+	get_pci_node_path(np->pdev, &hwpath);
+	if (!pdc_get_initiator(&hwpath, pdc))
+		return 0;
+
+	return SYM_PARISC_PDC;
+}
+#else
+static int sym_read_parisc_pdc(struct sym_device *np, struct pdc_initiator *x)
+{
+	return 0;
+}
+#endif
+
+/*
+ *  Try reading Symbios or Tekram NVRAM
+ */
+int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
+{
+	if (!sym_read_Symbios_nvram(np, &nvp->data.Symbios)) {
+		nvp->type = SYM_SYMBIOS_NVRAM;
+		sym_display_Symbios_nvram(np, &nvp->data.Symbios);
+	} else if (!sym_read_Tekram_nvram(np, &nvp->data.Tekram)) {
+		nvp->type = SYM_TEKRAM_NVRAM;
+		sym_display_Tekram_nvram(np, &nvp->data.Tekram);
+	} else {
+		nvp->type = sym_read_parisc_pdc(np, &nvp->data.parisc);
+	}
+	return nvp->type;
+}
+
+char *sym_nvram_type(struct sym_nvram *nvp)
+{
+	switch (nvp->type) {
+	case SYM_SYMBIOS_NVRAM:
+		return "Symbios NVRAM";
+	case SYM_TEKRAM_NVRAM:
+		return "Tekram NVRAM";
+	case SYM_PARISC_PDC:
+		return "PA-RISC Firmware";
+	default:
+		return "No NVRAM";
+	}
+}
diff --git a/drivers/scsi/sym53c8xx_2/sym_nvram.h b/drivers/scsi/sym53c8xx_2/sym_nvram.h
new file mode 100644
index 0000000..1538bed
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_2/sym_nvram.h
@@ -0,0 +1,214 @@
+/*
+ * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
+ * of PCI-SCSI IO processors.
+ *
+ * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
+ *
+ * This driver is derived from the Linux sym53c8xx driver.
+ * Copyright (C) 1998-2000  Gerard Roudier
+ *
+ * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
+ * a port of the FreeBSD ncr driver to Linux-1.2.13.
+ *
+ * The original ncr driver has been written for 386bsd and FreeBSD by
+ *         Wolfgang Stanglmeier        <wolf@cologne.de>
+ *         Stefan Esser                <se@mi.Uni-Koeln.de>
+ * Copyright (C) 1994  Wolfgang Stanglmeier
+ *
+ * Other major contributions:
+ *
+ * NVRAM detection and reading.
+ * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+ *
+ *-----------------------------------------------------------------------------
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef SYM_NVRAM_H
+#define SYM_NVRAM_H
+
+#include "sym53c8xx.h"
+
+/*
+ *	Symbios NVRAM data format
+ */
+#define SYMBIOS_NVRAM_SIZE 368
+#define SYMBIOS_NVRAM_ADDRESS 0x100
+
+struct Symbios_nvram {
+/* Header 6 bytes */
+	u_short type;		/* 0x0000 */
+	u_short byte_count;	/* excluding header/trailer */
+	u_short checksum;
+
+/* Controller set up 20 bytes */
+	u_char	v_major;	/* 0x00 */
+	u_char	v_minor;	/* 0x30 */
+	u32	boot_crc;
+	u_short	flags;
+#define SYMBIOS_SCAM_ENABLE	(1)
+#define SYMBIOS_PARITY_ENABLE	(1<<1)
+#define SYMBIOS_VERBOSE_MSGS	(1<<2)
+#define SYMBIOS_CHS_MAPPING	(1<<3)
+#define SYMBIOS_NO_NVRAM	(1<<3)	/* ??? */
+	u_short	flags1;
+#define SYMBIOS_SCAN_HI_LO	(1)
+	u_short	term_state;
+#define SYMBIOS_TERM_CANT_PROGRAM	(0)
+#define SYMBIOS_TERM_ENABLED		(1)
+#define SYMBIOS_TERM_DISABLED		(2)
+	u_short	rmvbl_flags;
+#define SYMBIOS_RMVBL_NO_SUPPORT	(0)
+#define SYMBIOS_RMVBL_BOOT_DEVICE	(1)
+#define SYMBIOS_RMVBL_MEDIA_INSTALLED	(2)
+	u_char	host_id;
+	u_char	num_hba;	/* 0x04 */
+	u_char	num_devices;	/* 0x10 */
+	u_char	max_scam_devices;	/* 0x04 */
+	u_char	num_valid_scam_devices;	/* 0x00 */
+	u_char	flags2;
+#define SYMBIOS_AVOID_BUS_RESET		(1<<2)
+
+/* Boot order 14 bytes * 4 */
+	struct Symbios_host{
+		u_short	type;		/* 4:8xx / 0:nok */
+		u_short	device_id;	/* PCI device id */
+		u_short	vendor_id;	/* PCI vendor id */
+		u_char	bus_nr;		/* PCI bus number */
+		u_char	device_fn;	/* PCI device/function number << 3*/
+		u_short	word8;
+		u_short	flags;
+#define	SYMBIOS_INIT_SCAN_AT_BOOT	(1)
+		u_short	io_port;	/* PCI io_port address */
+	} host[4];
+
+/* Targets 8 bytes * 16 */
+	struct Symbios_target {
+		u_char	flags;
+#define SYMBIOS_DISCONNECT_ENABLE	(1)
+#define SYMBIOS_SCAN_AT_BOOT_TIME	(1<<1)
+#define SYMBIOS_SCAN_LUNS		(1<<2)
+#define SYMBIOS_QUEUE_TAGS_ENABLED	(1<<3)
+		u_char	rsvd;
+		u_char	bus_width;	/* 0x08/0x10 */
+		u_char	sync_offset;
+		u_short	sync_period;	/* 4*period factor */
+		u_short	timeout;
+	} target[16];
+/* Scam table 8 bytes * 4 */
+	struct Symbios_scam {
+		u_short	id;
+		u_short	method;
+#define SYMBIOS_SCAM_DEFAULT_METHOD	(0)
+#define SYMBIOS_SCAM_DONT_ASSIGN	(1)
+#define SYMBIOS_SCAM_SET_SPECIFIC_ID	(2)
+#define SYMBIOS_SCAM_USE_ORDER_GIVEN	(3)
+		u_short status;
+#define SYMBIOS_SCAM_UNKNOWN		(0)
+#define SYMBIOS_SCAM_DEVICE_NOT_FOUND	(1)
+#define SYMBIOS_SCAM_ID_NOT_SET		(2)
+#define SYMBIOS_SCAM_ID_VALID		(3)
+		u_char	target_id;
+		u_char	rsvd;
+	} scam[4];
+
+	u_char	spare_devices[15*8];
+	u_char	trailer[6];		/* 0xfe 0xfe 0x00 0x00 0x00 0x00 */
+};
+typedef struct Symbios_nvram	Symbios_nvram;
+typedef struct Symbios_host	Symbios_host;
+typedef struct Symbios_target	Symbios_target;
+typedef struct Symbios_scam	Symbios_scam;
+
+/*
+ *	Tekram NvRAM data format.
+ */
+#define TEKRAM_NVRAM_SIZE 64
+#define TEKRAM_93C46_NVRAM_ADDRESS 0
+#define TEKRAM_24C16_NVRAM_ADDRESS 0x40
+
+struct Tekram_nvram {
+	struct Tekram_target {
+		u_char	flags;
+#define	TEKRAM_PARITY_CHECK		(1)
+#define TEKRAM_SYNC_NEGO		(1<<1)
+#define TEKRAM_DISCONNECT_ENABLE	(1<<2)
+#define	TEKRAM_START_CMD		(1<<3)
+#define TEKRAM_TAGGED_COMMANDS		(1<<4)
+#define TEKRAM_WIDE_NEGO		(1<<5)
+		u_char	sync_index;
+		u_short	word2;
+	} target[16];
+	u_char	host_id;
+	u_char	flags;
+#define TEKRAM_MORE_THAN_2_DRIVES	(1)
+#define TEKRAM_DRIVES_SUP_1GB		(1<<1)
+#define	TEKRAM_RESET_ON_POWER_ON	(1<<2)
+#define TEKRAM_ACTIVE_NEGATION		(1<<3)
+#define TEKRAM_IMMEDIATE_SEEK		(1<<4)
+#define	TEKRAM_SCAN_LUNS		(1<<5)
+#define	TEKRAM_REMOVABLE_FLAGS		(3<<6)	/* 0: disable; */
+						/* 1: boot device; 2:all */
+	u_char	boot_delay_index;
+	u_char	max_tags_index;
+	u_short	flags1;
+#define TEKRAM_F2_F6_ENABLED		(1)
+	u_short	spare[29];
+};
+typedef struct Tekram_nvram	Tekram_nvram;
+typedef struct Tekram_target	Tekram_target;
+
+#ifndef CONFIG_PARISC
+struct pdc_initiator { int dummy; };
+#endif
+
+/*
+ *  Union of supported NVRAM formats.
+ */
+struct sym_nvram {
+	int type;
+#define	SYM_SYMBIOS_NVRAM	(1)
+#define	SYM_TEKRAM_NVRAM	(2)
+#define SYM_PARISC_PDC		(3)
+#if SYM_CONF_NVRAM_SUPPORT
+	union {
+		Symbios_nvram Symbios;
+		Tekram_nvram Tekram;
+		struct pdc_initiator parisc;
+	} data;
+#endif
+};
+
+#if SYM_CONF_NVRAM_SUPPORT
+void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram);
+void sym_nvram_setup_target (struct sym_hcb *np, int target, struct sym_nvram *nvp);
+int sym_read_nvram (struct sym_device *np, struct sym_nvram *nvp);
+char *sym_nvram_type(struct sym_nvram *nvp);
+#else
+static inline void sym_nvram_setup_host(struct Scsi_Host *shost, struct sym_hcb *np, struct sym_nvram *nvram) { }
+static inline void sym_nvram_setup_target(struct sym_hcb *np, struct sym_nvram *nvram) { }
+static inline int sym_read_nvram(struct sym_device *np, struct sym_nvram *nvp)
+{
+	nvp->type = 0;
+	return 0;
+}
+static inline char *sym_nvram_type(struct sym_nvram *nvp)
+{
+	return "No NVRAM";
+}
+#endif
+
+#endif /* SYM_NVRAM_H */
diff --git a/drivers/scsi/sym53c8xx_comm.h b/drivers/scsi/sym53c8xx_comm.h
new file mode 100644
index 0000000..20ae2b1
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_comm.h
@@ -0,0 +1,792 @@
+/******************************************************************************
+**  High Performance device driver for the Symbios 53C896 controller.
+**
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
+**
+**  This driver also supports all the Symbios 53C8XX controller family, 
+**  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
+**  revisions of 53C815 controllers.
+**
+**  This driver is based on the Linux port of the FreeBSD ncr driver.
+** 
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**  
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  The Linux port of the FreeBSD ncr driver has been achieved in 
+**  november 1995 by:
+**
+**          Gerard Roudier              <groudier@free.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**-----------------------------------------------------------------------------
+**
+**  Major contributions:
+**  --------------------
+**
+**  NVRAM detection and reading.
+**    Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+**
+*******************************************************************************
+*/
+
+/*==========================================================
+**
+**	Debugging tags
+**
+**==========================================================
+*/
+
+#define DEBUG_ALLOC    (0x0001)
+#define DEBUG_PHASE    (0x0002)
+#define DEBUG_QUEUE    (0x0008)
+#define DEBUG_RESULT   (0x0010)
+#define DEBUG_POINTER  (0x0020)
+#define DEBUG_SCRIPT   (0x0040)
+#define DEBUG_TINY     (0x0080)
+#define DEBUG_TIMING   (0x0100)
+#define DEBUG_NEGO     (0x0200)
+#define DEBUG_TAGS     (0x0400)
+#define DEBUG_SCATTER  (0x0800)
+#define DEBUG_IC        (0x1000)
+
+/*
+**    Enable/Disable debug messages.
+**    Can be changed at runtime too.
+*/
+
+#ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
+static int ncr_debug = SCSI_NCR_DEBUG_FLAGS;
+	#define DEBUG_FLAGS ncr_debug
+#else
+	#define DEBUG_FLAGS	SCSI_NCR_DEBUG_FLAGS
+#endif
+
+static inline struct list_head *ncr_list_pop(struct list_head *head)
+{
+	if (!list_empty(head)) {
+		struct list_head *elem = head->next;
+
+		list_del(elem);
+		return elem;
+	}
+
+	return NULL;
+}
+
+#ifdef __sparc__
+#include <asm/irq.h>
+#endif
+
+/*==========================================================
+**
+**	Simple power of two buddy-like allocator.
+**
+**	This simple code is not intended to be fast, but to 
+**	provide power of 2 aligned memory allocations.
+**	Since the SCRIPTS processor only supplies 8 bit 
+**	arithmetic, this allocator allows simple and fast 
+**	address calculations  from the SCRIPTS code.
+**	In addition, cache line alignment is guaranteed for 
+**	power of 2 cache line size.
+**	Enhanced in linux-2.3.44 to provide a memory pool 
+**	per pcidev to support dynamic dma mapping. (I would 
+**	have preferred a real bus astraction, btw).
+**
+**==========================================================
+*/
+
+#define MEMO_SHIFT	4	/* 16 bytes minimum memory chunk */
+#if PAGE_SIZE >= 8192
+#define MEMO_PAGE_ORDER	0	/* 1 PAGE  maximum */
+#else
+#define MEMO_PAGE_ORDER	1	/* 2 PAGES maximum */
+#endif
+#define MEMO_FREE_UNUSED	/* Free unused pages immediately */
+#define MEMO_WARN	1
+#define MEMO_GFP_FLAGS	GFP_ATOMIC
+#define MEMO_CLUSTER_SHIFT	(PAGE_SHIFT+MEMO_PAGE_ORDER)
+#define MEMO_CLUSTER_SIZE	(1UL << MEMO_CLUSTER_SHIFT)
+#define MEMO_CLUSTER_MASK	(MEMO_CLUSTER_SIZE-1)
+
+typedef u_long m_addr_t;	/* Enough bits to bit-hack addresses */
+typedef struct device *m_bush_t;	/* Something that addresses DMAable */
+
+typedef struct m_link {		/* Link between free memory chunks */
+	struct m_link *next;
+} m_link_s;
+
+typedef struct m_vtob {		/* Virtual to Bus address translation */
+	struct m_vtob *next;
+	m_addr_t vaddr;
+	m_addr_t baddr;
+} m_vtob_s;
+#define VTOB_HASH_SHIFT		5
+#define VTOB_HASH_SIZE		(1UL << VTOB_HASH_SHIFT)
+#define VTOB_HASH_MASK		(VTOB_HASH_SIZE-1)
+#define VTOB_HASH_CODE(m)	\
+	((((m_addr_t) (m)) >> MEMO_CLUSTER_SHIFT) & VTOB_HASH_MASK)
+
+typedef struct m_pool {		/* Memory pool of a given kind */
+	m_bush_t bush;
+	m_addr_t (*getp)(struct m_pool *);
+	void (*freep)(struct m_pool *, m_addr_t);
+	int nump;
+	m_vtob_s *(vtob[VTOB_HASH_SIZE]);
+	struct m_pool *next;
+	struct m_link h[PAGE_SHIFT-MEMO_SHIFT+MEMO_PAGE_ORDER+1];
+} m_pool_s;
+
+static void *___m_alloc(m_pool_s *mp, int size)
+{
+	int i = 0;
+	int s = (1 << MEMO_SHIFT);
+	int j;
+	m_addr_t a;
+	m_link_s *h = mp->h;
+
+	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+		return NULL;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	j = i;
+	while (!h[j].next) {
+		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+			h[j].next = (m_link_s *)mp->getp(mp);
+			if (h[j].next)
+				h[j].next->next = NULL;
+			break;
+		}
+		++j;
+		s <<= 1;
+	}
+	a = (m_addr_t) h[j].next;
+	if (a) {
+		h[j].next = h[j].next->next;
+		while (j > i) {
+			j -= 1;
+			s >>= 1;
+			h[j].next = (m_link_s *) (a+s);
+			h[j].next->next = NULL;
+		}
+	}
+#ifdef DEBUG
+	printk("___m_alloc(%d) = %p\n", size, (void *) a);
+#endif
+	return (void *) a;
+}
+
+static void ___m_free(m_pool_s *mp, void *ptr, int size)
+{
+	int i = 0;
+	int s = (1 << MEMO_SHIFT);
+	m_link_s *q;
+	m_addr_t a, b;
+	m_link_s *h = mp->h;
+
+#ifdef DEBUG
+	printk("___m_free(%p, %d)\n", ptr, size);
+#endif
+
+	if (size > (PAGE_SIZE << MEMO_PAGE_ORDER))
+		return;
+
+	while (size > s) {
+		s <<= 1;
+		++i;
+	}
+
+	a = (m_addr_t) ptr;
+
+	while (1) {
+#ifdef MEMO_FREE_UNUSED
+		if (s == (PAGE_SIZE << MEMO_PAGE_ORDER)) {
+			mp->freep(mp, a);
+			break;
+		}
+#endif
+		b = a ^ s;
+		q = &h[i];
+		while (q->next && q->next != (m_link_s *) b) {
+			q = q->next;
+		}
+		if (!q->next) {
+			((m_link_s *) a)->next = h[i].next;
+			h[i].next = (m_link_s *) a;
+			break;
+		}
+		q->next = q->next->next;
+		a = a & b;
+		s <<= 1;
+		++i;
+	}
+}
+
+static DEFINE_SPINLOCK(ncr53c8xx_lock);
+
+static void *__m_calloc2(m_pool_s *mp, int size, char *name, int uflags)
+{
+	void *p;
+
+	p = ___m_alloc(mp, size);
+
+	if (DEBUG_FLAGS & DEBUG_ALLOC)
+		printk ("new %-10s[%4d] @%p.\n", name, size, p);
+
+	if (p)
+		memset(p, 0, size);
+	else if (uflags & MEMO_WARN)
+		printk (NAME53C8XX ": failed to allocate %s[%d]\n", name, size);
+
+	return p;
+}
+
+#define __m_calloc(mp, s, n)	__m_calloc2(mp, s, n, MEMO_WARN)
+
+static void __m_free(m_pool_s *mp, void *ptr, int size, char *name)
+{
+	if (DEBUG_FLAGS & DEBUG_ALLOC)
+		printk ("freeing %-10s[%4d] @%p.\n", name, size, ptr);
+
+	___m_free(mp, ptr, size);
+
+}
+
+/*
+ * With pci bus iommu support, we use a default pool of unmapped memory 
+ * for memory we donnot need to DMA from/to and one pool per pcidev for 
+ * memory accessed by the PCI chip. `mp0' is the default not DMAable pool.
+ */
+
+static m_addr_t ___mp0_getp(m_pool_s *mp)
+{
+	m_addr_t m = __get_free_pages(MEMO_GFP_FLAGS, MEMO_PAGE_ORDER);
+	if (m)
+		++mp->nump;
+	return m;
+}
+
+static void ___mp0_freep(m_pool_s *mp, m_addr_t m)
+{
+	free_pages(m, MEMO_PAGE_ORDER);
+	--mp->nump;
+}
+
+static m_pool_s mp0 = {NULL, ___mp0_getp, ___mp0_freep};
+
+/*
+ * DMAable pools.
+ */
+
+/*
+ * With pci bus iommu support, we maintain one pool per pcidev and a 
+ * hashed reverse table for virtual to bus physical address translations.
+ */
+static m_addr_t ___dma_getp(m_pool_s *mp)
+{
+	m_addr_t vp;
+	m_vtob_s *vbp;
+
+	vbp = __m_calloc(&mp0, sizeof(*vbp), "VTOB");
+	if (vbp) {
+		dma_addr_t daddr;
+		vp = (m_addr_t) dma_alloc_coherent(mp->bush,
+						PAGE_SIZE<<MEMO_PAGE_ORDER,
+						&daddr, GFP_ATOMIC);
+		if (vp) {
+			int hc = VTOB_HASH_CODE(vp);
+			vbp->vaddr = vp;
+			vbp->baddr = daddr;
+			vbp->next = mp->vtob[hc];
+			mp->vtob[hc] = vbp;
+			++mp->nump;
+			return vp;
+		}
+	}
+	if (vbp)
+		__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+	return 0;
+}
+
+static void ___dma_freep(m_pool_s *mp, m_addr_t m)
+{
+	m_vtob_s **vbpp, *vbp;
+	int hc = VTOB_HASH_CODE(m);
+
+	vbpp = &mp->vtob[hc];
+	while (*vbpp && (*vbpp)->vaddr != m)
+		vbpp = &(*vbpp)->next;
+	if (*vbpp) {
+		vbp = *vbpp;
+		*vbpp = (*vbpp)->next;
+		dma_free_coherent(mp->bush, PAGE_SIZE<<MEMO_PAGE_ORDER,
+				  (void *)vbp->vaddr, (dma_addr_t)vbp->baddr);
+		__m_free(&mp0, vbp, sizeof(*vbp), "VTOB");
+		--mp->nump;
+	}
+}
+
+static inline m_pool_s *___get_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	for (mp = mp0.next; mp && mp->bush != bush; mp = mp->next);
+	return mp;
+}
+
+static m_pool_s *___cre_dma_pool(m_bush_t bush)
+{
+	m_pool_s *mp;
+	mp = __m_calloc(&mp0, sizeof(*mp), "MPOOL");
+	if (mp) {
+		memset(mp, 0, sizeof(*mp));
+		mp->bush = bush;
+		mp->getp = ___dma_getp;
+		mp->freep = ___dma_freep;
+		mp->next = mp0.next;
+		mp0.next = mp;
+	}
+	return mp;
+}
+
+static void ___del_dma_pool(m_pool_s *p)
+{
+	struct m_pool **pp = &mp0.next;
+
+	while (*pp && *pp != p)
+		pp = &(*pp)->next;
+	if (*pp) {
+		*pp = (*pp)->next;
+		__m_free(&mp0, p, sizeof(*p), "MPOOL");
+	}
+}
+
+static void *__m_calloc_dma(m_bush_t bush, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+	void *m = NULL;
+
+	spin_lock_irqsave(&ncr53c8xx_lock, flags);
+	mp = ___get_dma_pool(bush);
+	if (!mp)
+		mp = ___cre_dma_pool(bush);
+	if (mp)
+		m = __m_calloc(mp, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
+
+	return m;
+}
+
+static void __m_free_dma(m_bush_t bush, void *m, int size, char *name)
+{
+	u_long flags;
+	struct m_pool *mp;
+
+	spin_lock_irqsave(&ncr53c8xx_lock, flags);
+	mp = ___get_dma_pool(bush);
+	if (mp)
+		__m_free(mp, m, size, name);
+	if (mp && !mp->nump)
+		___del_dma_pool(mp);
+	spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
+}
+
+static m_addr_t __vtobus(m_bush_t bush, void *m)
+{
+	u_long flags;
+	m_pool_s *mp;
+	int hc = VTOB_HASH_CODE(m);
+	m_vtob_s *vp = NULL;
+	m_addr_t a = ((m_addr_t) m) & ~MEMO_CLUSTER_MASK;
+
+	spin_lock_irqsave(&ncr53c8xx_lock, flags);
+	mp = ___get_dma_pool(bush);
+	if (mp) {
+		vp = mp->vtob[hc];
+		while (vp && (m_addr_t) vp->vaddr != a)
+			vp = vp->next;
+	}
+	spin_unlock_irqrestore(&ncr53c8xx_lock, flags);
+	return vp ? vp->baddr + (((m_addr_t) m) - a) : 0;
+}
+
+#define _m_calloc_dma(np, s, n)		__m_calloc_dma(np->dev, s, n)
+#define _m_free_dma(np, p, s, n)	__m_free_dma(np->dev, p, s, n)
+#define m_calloc_dma(s, n)		_m_calloc_dma(np, s, n)
+#define m_free_dma(p, s, n)		_m_free_dma(np, p, s, n)
+#define _vtobus(np, p)			__vtobus(np->dev, p)
+#define vtobus(p)			_vtobus(np, p)
+
+/*
+ *  Deal with DMA mapping/unmapping.
+ */
+
+/* To keep track of the dma mapping (sg/single) that has been set */
+#define __data_mapped	SCp.phase
+#define __data_mapping	SCp.have_data_in
+
+static void __unmap_scsi_data(struct device *dev, struct scsi_cmnd *cmd)
+{
+	switch(cmd->__data_mapped) {
+	case 2:
+		dma_unmap_sg(dev, cmd->buffer, cmd->use_sg,
+				cmd->sc_data_direction);
+		break;
+	case 1:
+		dma_unmap_single(dev, cmd->__data_mapping,
+				 cmd->request_bufflen,
+				 cmd->sc_data_direction);
+		break;
+	}
+	cmd->__data_mapped = 0;
+}
+
+static u_long __map_scsi_single_data(struct device *dev, struct scsi_cmnd *cmd)
+{
+	dma_addr_t mapping;
+
+	if (cmd->request_bufflen == 0)
+		return 0;
+
+	mapping = dma_map_single(dev, cmd->request_buffer,
+				 cmd->request_bufflen,
+				 cmd->sc_data_direction);
+	cmd->__data_mapped = 1;
+	cmd->__data_mapping = mapping;
+
+	return mapping;
+}
+
+static int __map_scsi_sg_data(struct device *dev, struct scsi_cmnd *cmd)
+{
+	int use_sg;
+
+	if (cmd->use_sg == 0)
+		return 0;
+
+	use_sg = dma_map_sg(dev, cmd->buffer, cmd->use_sg,
+			cmd->sc_data_direction);
+	cmd->__data_mapped = 2;
+	cmd->__data_mapping = use_sg;
+
+	return use_sg;
+}
+
+#define unmap_scsi_data(np, cmd)	__unmap_scsi_data(np->dev, cmd)
+#define map_scsi_single_data(np, cmd)	__map_scsi_single_data(np->dev, cmd)
+#define map_scsi_sg_data(np, cmd)	__map_scsi_sg_data(np->dev, cmd)
+
+/*==========================================================
+**
+**	Driver setup.
+**
+**	This structure is initialized from linux config 
+**	options. It can be overridden at boot-up by the boot 
+**	command line.
+**
+**==========================================================
+*/
+static struct ncr_driver_setup
+	driver_setup			= SCSI_NCR_DRIVER_SETUP;
+
+#ifdef	SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+static struct ncr_driver_setup
+	driver_safe_setup __initdata	= SCSI_NCR_DRIVER_SAFE_SETUP;
+#endif
+
+#define initverbose (driver_setup.verbose)
+#define bootverbose (np->verbose)
+
+
+/*===================================================================
+**
+**	Driver setup from the boot command line
+**
+**===================================================================
+*/
+
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
+
+#define OPT_TAGS		1
+#define OPT_MASTER_PARITY	2
+#define OPT_SCSI_PARITY		3
+#define OPT_DISCONNECTION	4
+#define OPT_SPECIAL_FEATURES	5
+#define OPT_UNUSED_1		6
+#define OPT_FORCE_SYNC_NEGO	7
+#define OPT_REVERSE_PROBE	8
+#define OPT_DEFAULT_SYNC	9
+#define OPT_VERBOSE		10
+#define OPT_DEBUG		11
+#define OPT_BURST_MAX		12
+#define OPT_LED_PIN		13
+#define OPT_MAX_WIDE		14
+#define OPT_SETTLE_DELAY	15
+#define OPT_DIFF_SUPPORT	16
+#define OPT_IRQM		17
+#define OPT_PCI_FIX_UP		18
+#define OPT_BUS_CHECK		19
+#define OPT_OPTIMIZE		20
+#define OPT_RECOVERY		21
+#define OPT_SAFE_SETUP		22
+#define OPT_USE_NVRAM		23
+#define OPT_EXCLUDE		24
+#define OPT_HOST_ID		25
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB		26
+#endif
+
+static char setup_token[] __initdata = 
+	"tags:"   "mpar:"
+	"spar:"   "disc:"
+	"specf:"  "ultra:"
+	"fsn:"    "revprob:"
+	"sync:"   "verb:"
+	"debug:"  "burst:"
+	"led:"    "wide:"
+	"settle:" "diff:"
+	"irqm:"   "pcifix:"
+	"buschk:" "optim:"
+	"recovery:"
+	"safe:"   "nvram:"
+	"excl:"   "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+	"iarb:"
+#endif
+	;	/* DONNOT REMOVE THIS ';' */
+
+#ifdef MODULE
+#define	ARG_SEP	' '
+#else
+#define	ARG_SEP	','
+#endif
+
+static int __init get_setup_token(char *p)
+{
+	char *cur = setup_token;
+	char *pc;
+	int i = 0;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		++pc;
+		++i;
+		if (!strncmp(p, cur, pc - cur))
+			return i;
+		cur = pc;
+	}
+	return 0;
+}
+
+
+static int __init sym53c8xx__setup(char *str)
+{
+#ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+	char *cur = str;
+	char *pc, *pv;
+	int i, val, c;
+	int xi = 0;
+
+	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
+		char *pe;
+
+		val = 0;
+		pv = pc;
+		c = *++pv;
+
+		if	(c == 'n')
+			val = 0;
+		else if	(c == 'y')
+			val = 1;
+		else
+			val = (int) simple_strtoul(pv, &pe, 0);
+
+		switch (get_setup_token(cur)) {
+		case OPT_TAGS:
+			driver_setup.default_tags = val;
+			if (pe && *pe == '/') {
+				i = 0;
+				while (*pe && *pe != ARG_SEP && 
+					i < sizeof(driver_setup.tag_ctrl)-1) {
+					driver_setup.tag_ctrl[i++] = *pe++;
+				}
+				driver_setup.tag_ctrl[i] = '\0';
+			}
+			break;
+		case OPT_MASTER_PARITY:
+			driver_setup.master_parity = val;
+			break;
+		case OPT_SCSI_PARITY:
+			driver_setup.scsi_parity = val;
+			break;
+		case OPT_DISCONNECTION:
+			driver_setup.disconnection = val;
+			break;
+		case OPT_SPECIAL_FEATURES:
+			driver_setup.special_features = val;
+			break;
+		case OPT_FORCE_SYNC_NEGO:
+			driver_setup.force_sync_nego = val;
+			break;
+		case OPT_REVERSE_PROBE:
+			driver_setup.reverse_probe = val;
+			break;
+		case OPT_DEFAULT_SYNC:
+			driver_setup.default_sync = val;
+			break;
+		case OPT_VERBOSE:
+			driver_setup.verbose = val;
+			break;
+		case OPT_DEBUG:
+			driver_setup.debug = val;
+			break;
+		case OPT_BURST_MAX:
+			driver_setup.burst_max = val;
+			break;
+		case OPT_LED_PIN:
+			driver_setup.led_pin = val;
+			break;
+		case OPT_MAX_WIDE:
+			driver_setup.max_wide = val? 1:0;
+			break;
+		case OPT_SETTLE_DELAY:
+			driver_setup.settle_delay = val;
+			break;
+		case OPT_DIFF_SUPPORT:
+			driver_setup.diff_support = val;
+			break;
+		case OPT_IRQM:
+			driver_setup.irqm = val;
+			break;
+		case OPT_PCI_FIX_UP:
+			driver_setup.pci_fix_up	= val;
+			break;
+		case OPT_BUS_CHECK:
+			driver_setup.bus_check = val;
+			break;
+		case OPT_OPTIMIZE:
+			driver_setup.optimize = val;
+			break;
+		case OPT_RECOVERY:
+			driver_setup.recovery = val;
+			break;
+		case OPT_USE_NVRAM:
+			driver_setup.use_nvram = val;
+			break;
+		case OPT_SAFE_SETUP:
+			memcpy(&driver_setup, &driver_safe_setup,
+				sizeof(driver_setup));
+			break;
+		case OPT_EXCLUDE:
+			if (xi < SCSI_NCR_MAX_EXCLUDES)
+				driver_setup.excludes[xi++] = val;
+			break;
+		case OPT_HOST_ID:
+			driver_setup.host_id = val;
+			break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+		case OPT_IARB:
+			driver_setup.iarb = val;
+			break;
+#endif
+		default:
+			printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
+			break;
+		}
+
+		if ((cur = strchr(cur, ARG_SEP)) != NULL)
+			++cur;
+	}
+#endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 1;
+}
+
+/*===================================================================
+**
+**	Get device queue depth from boot command line.
+**
+**===================================================================
+*/
+#define DEF_DEPTH	(driver_setup.default_tags)
+#define ALL_TARGETS	-2
+#define NO_TARGET	-1
+#define ALL_LUNS	-2
+#define NO_LUN		-1
+
+static int device_queue_depth(int unit, int target, int lun)
+{
+	int c, h, t, u, v;
+	char *p = driver_setup.tag_ctrl;
+	char *ep;
+
+	h = -1;
+	t = NO_TARGET;
+	u = NO_LUN;
+	while ((c = *p++) != 0) {
+		v = simple_strtoul(p, &ep, 0);
+		switch(c) {
+		case '/':
+			++h;
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		case 't':
+			if (t != target)
+				t = (target == v) ? v : NO_TARGET;
+			u = ALL_LUNS;
+			break;
+		case 'u':
+			if (u != lun)
+				u = (lun == v) ? v : NO_LUN;
+			break;
+		case 'q':
+			if (h == unit &&
+				(t == ALL_TARGETS || t == target) &&
+				(u == ALL_LUNS    || u == lun))
+				return v;
+			break;
+		case '-':
+			t = ALL_TARGETS;
+			u = ALL_LUNS;
+			break;
+		default:
+			break;
+		}
+		p = ep;
+	}
+	return DEF_DEPTH;
+}
diff --git a/drivers/scsi/sym53c8xx_defs.h b/drivers/scsi/sym53c8xx_defs.h
new file mode 100644
index 0000000..4c4ae7d
--- /dev/null
+++ b/drivers/scsi/sym53c8xx_defs.h
@@ -0,0 +1,1333 @@
+/******************************************************************************
+**  High Performance device driver for the Symbios 53C896 controller.
+**
+**  Copyright (C) 1998-2001  Gerard Roudier <groudier@free.fr>
+**
+**  This driver also supports all the Symbios 53C8XX controller family, 
+**  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
+**  revisions of 53C815 controllers.
+**
+**  This driver is based on the Linux port of the FreeBSD ncr driver.
+** 
+**  Copyright (C) 1994  Wolfgang Stanglmeier
+**  
+**-----------------------------------------------------------------------------
+**  
+**  This program is free software; you can redistribute it and/or modify
+**  it under the terms of the GNU General Public License as published by
+**  the Free Software Foundation; either version 2 of the License, or
+**  (at your option) any later version.
+**
+**  This program is distributed in the hope that it will be useful,
+**  but WITHOUT ANY WARRANTY; without even the implied warranty of
+**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+**  GNU General Public License for more details.
+**
+**  You should have received a copy of the GNU General Public License
+**  along with this program; if not, write to the Free Software
+**  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+**
+**-----------------------------------------------------------------------------
+**
+**  The Linux port of the FreeBSD ncr driver has been achieved in 
+**  november 1995 by:
+**
+**          Gerard Roudier              <groudier@free.fr>
+**
+**  Being given that this driver originates from the FreeBSD version, and
+**  in order to keep synergy on both, any suggested enhancements and corrections
+**  received on Linux are automatically a potential candidate for the FreeBSD 
+**  version.
+**
+**  The original driver has been written for 386bsd and FreeBSD by
+**          Wolfgang Stanglmeier        <wolf@cologne.de>
+**          Stefan Esser                <se@mi.Uni-Koeln.de>
+**
+**-----------------------------------------------------------------------------
+**
+**  Major contributions:
+**  --------------------
+**
+**  NVRAM detection and reading.
+**    Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
+**
+**  Added support for MIPS big endian systems.
+**    Carsten Langgaard, carstenl@mips.com
+**    Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+**
+**  Added support for HP PARISC big endian systems.
+**    Copyright (C) 2000 MIPS Technologies, Inc.  All rights reserved.
+**
+*******************************************************************************
+*/
+
+#ifndef SYM53C8XX_DEFS_H
+#define SYM53C8XX_DEFS_H
+
+#include <linux/config.h>
+
+/*
+**	If you want a driver as small as possible, donnot define the 
+**	following options.
+*/
+#define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
+#define SCSI_NCR_DEBUG_INFO_SUPPORT
+
+/*
+**	To disable integrity checking, do not define the 
+**	following option.
+*/
+#ifdef	CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK
+#	define SCSI_NCR_ENABLE_INTEGRITY_CHECK
+#endif
+
+/* ---------------------------------------------------------------------
+** Take into account kernel configured parameters.
+** Most of these options can be overridden at startup by a command line.
+** ---------------------------------------------------------------------
+*/
+
+/*
+ * For Ultra2 and Ultra3 SCSI support option, use special features. 
+ *
+ * Value (default) means:
+ *	bit 0 : all features enabled, except:
+ *		bit 1 : PCI Write And Invalidate.
+ *		bit 2 : Data Phase Mismatch handling from SCRIPTS.
+ *
+ * Use boot options ncr53c8xx=specf:1 if you want all chip features to be 
+ * enabled by the driver.
+ */
+#define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(3)
+
+#define SCSI_NCR_MAX_SYNC			(80)
+
+/*
+ * Allow tags from 2 to 256, default 8
+ */
+#ifdef	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+#if	CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
+#define SCSI_NCR_MAX_TAGS	(2)
+#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 256
+#define SCSI_NCR_MAX_TAGS	(256)
+#else
+#define	SCSI_NCR_MAX_TAGS	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
+#endif
+#else
+#define SCSI_NCR_MAX_TAGS	(8)
+#endif
+
+/*
+ * Allow tagged command queuing support if configured with default number 
+ * of tags set to max (see above).
+ */
+#ifdef	CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+#define	SCSI_NCR_SETUP_DEFAULT_TAGS	CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS
+#elif	defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE
+#define	SCSI_NCR_SETUP_DEFAULT_TAGS	SCSI_NCR_MAX_TAGS
+#else
+#define	SCSI_NCR_SETUP_DEFAULT_TAGS	(0)
+#endif
+
+/*
+ * Immediate arbitration
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IARB)
+#define SCSI_NCR_IARB_SUPPORT
+#endif
+
+/*
+ * Sync transfer frequency at startup.
+ * Allow from 5Mhz to 80Mhz default 20 Mhz.
+ */
+#ifndef	CONFIG_SCSI_NCR53C8XX_SYNC
+#define	CONFIG_SCSI_NCR53C8XX_SYNC	(20)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC
+#undef	CONFIG_SCSI_NCR53C8XX_SYNC
+#define	CONFIG_SCSI_NCR53C8XX_SYNC	SCSI_NCR_MAX_SYNC
+#endif
+
+#if	CONFIG_SCSI_NCR53C8XX_SYNC == 0
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(255)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 5
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(50)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 20
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(250/(CONFIG_SCSI_NCR53C8XX_SYNC))
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 33
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(11)
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 40
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC	(10)
+#else
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC 	(9)
+#endif
+
+/*
+ * Disallow disconnections at boot-up
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
+#define SCSI_NCR_SETUP_DISCONNECTION	(0)
+#else
+#define SCSI_NCR_SETUP_DISCONNECTION	(1)
+#endif
+
+/*
+ * Force synchronous negotiation for all targets
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_FORCE_SYNC_NEGO
+#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO	(1)
+#else
+#define SCSI_NCR_SETUP_FORCE_SYNC_NEGO	(0)
+#endif
+
+/*
+ * Disable master parity checking (flawed hardwares need that)
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK
+#define SCSI_NCR_SETUP_MASTER_PARITY	(0)
+#else
+#define SCSI_NCR_SETUP_MASTER_PARITY	(1)
+#endif
+
+/*
+ * Disable scsi parity checking (flawed devices may need that)
+ */
+#ifdef CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK
+#define SCSI_NCR_SETUP_SCSI_PARITY	(0)
+#else
+#define SCSI_NCR_SETUP_SCSI_PARITY	(1)
+#endif
+
+/*
+ * Settle time after reset at boot-up
+ */
+#define SCSI_NCR_SETUP_SETTLE_TIME	(2)
+
+/*
+**	Bridge quirks work-around option defaulted to 1.
+*/
+#ifndef	SCSI_NCR_PCIQ_WORK_AROUND_OPT
+#define	SCSI_NCR_PCIQ_WORK_AROUND_OPT	1
+#endif
+
+/*
+**	Work-around common bridge misbehaviour.
+**
+**	- Do not flush posted writes in the opposite 
+**	  direction on read.
+**	- May reorder DMA writes to memory.
+**
+**	This option should not affect performances 
+**	significantly, so it is the default.
+*/
+#if	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 1
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+
+/*
+**	Same as option 1, but also deal with 
+**	misconfigured interrupts.
+**
+**	- Edge triggerred instead of level sensitive.
+**	- No interrupt line connected.
+**	- IRQ number misconfigured.
+**	
+**	If no interrupt is delivered, the driver will 
+**	catch the interrupt conditions 10 times per 
+**	second. No need to say that this option is 
+**	not recommended.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 2
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+#define	SCSI_NCR_PCIQ_BROKEN_INTR
+
+/*
+**	Some bridge designers decided to flush 
+**	everything prior to deliver the interrupt.
+**	This option tries to deal with such a 
+**	behaviour.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 3
+#define	SCSI_NCR_PCIQ_SYNC_ON_INTR
+#endif
+
+/*
+**	Other parameters not configurable with "make config"
+**	Avoid to change these constants, unless you know what you are doing.
+*/
+
+#define SCSI_NCR_ALWAYS_SIMPLE_TAG
+#define SCSI_NCR_MAX_SCATTER	(127)
+#define SCSI_NCR_MAX_TARGET	(16)
+
+/*
+**   Compute some desirable value for CAN_QUEUE 
+**   and CMD_PER_LUN.
+**   The driver will use lower values if these 
+**   ones appear to be too large.
+*/
+#define SCSI_NCR_CAN_QUEUE	(8*SCSI_NCR_MAX_TAGS + 2*SCSI_NCR_MAX_TARGET)
+#define SCSI_NCR_CMD_PER_LUN	(SCSI_NCR_MAX_TAGS)
+
+#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
+#define SCSI_NCR_TIMER_INTERVAL	(HZ)
+
+#if 1 /* defined CONFIG_SCSI_MULTI_LUN */
+#define SCSI_NCR_MAX_LUN	(16)
+#else
+#define SCSI_NCR_MAX_LUN	(1)
+#endif
+
+/*
+**	These simple macros limit expression involving 
+**	kernel time values (jiffies) to some that have 
+**	chance not to be too much incorrect. :-)
+*/
+#define ktime_get(o)		(jiffies + (u_long) o)
+#define ktime_exp(b)		((long)(jiffies) - (long)(b) >= 0)
+#define ktime_dif(a, b)		((long)(a) - (long)(b))
+/* These ones are not used in this driver */
+#define ktime_add(a, o)		((a) + (u_long)(o))
+#define ktime_sub(a, o)		((a) - (u_long)(o))
+
+
+/*
+ *  IO functions definition for big/little endian CPU support.
+ *  For now, the NCR is only supported in little endian addressing mode, 
+ */
+
+#ifdef	__BIG_ENDIAN
+
+#define	inw_l2b		inw
+#define	inl_l2b		inl
+#define	outw_b2l	outw
+#define	outl_b2l	outl
+
+#define	readb_raw	readb
+#define	writeb_raw	writeb
+
+#if defined(SCSI_NCR_BIG_ENDIAN)
+#define	readw_l2b	__raw_readw
+#define	readl_l2b	__raw_readl
+#define	writew_b2l	__raw_writew
+#define	writel_b2l	__raw_writel
+#define	readw_raw	__raw_readw
+#define	readl_raw	__raw_readl
+#define	writew_raw	__raw_writew
+#define	writel_raw	__raw_writel
+#else	/* Other big-endian */
+#define	readw_l2b	readw
+#define	readl_l2b	readl
+#define	writew_b2l	writew
+#define	writel_b2l	writel
+#define	readw_raw	readw
+#define	readl_raw	readl
+#define	writew_raw	writew
+#define	writel_raw	writel
+#endif
+
+#else	/* little endian */
+
+#define	inw_raw		inw
+#define	inl_raw		inl
+#define	outw_raw	outw
+#define	outl_raw	outl
+
+#define	readb_raw	readb
+#define	readw_raw	readw
+#define	readl_raw	readl
+#define	writeb_raw	writeb
+#define	writew_raw	writew
+#define	writel_raw	writel
+
+#endif
+
+#if !defined(__hppa__) && !defined(__mips__)
+#ifdef	SCSI_NCR_BIG_ENDIAN
+#error	"The NCR in BIG ENDIAN addressing mode is not (yet) supported"
+#endif
+#endif
+
+#define MEMORY_BARRIER()	mb()
+
+
+/*
+ *  If the NCR uses big endian addressing mode over the 
+ *  PCI, actual io register addresses for byte and word 
+ *  accesses must be changed according to lane routing.
+ *  Btw, ncr_offb() and ncr_offw() macros only apply to 
+ *  constants and so donnot generate bloated code.
+ */
+
+#if	defined(SCSI_NCR_BIG_ENDIAN)
+
+#define ncr_offb(o)	(((o)&~3)+((~((o)&3))&3))
+#define ncr_offw(o)	(((o)&~3)+((~((o)&3))&2))
+
+#else
+
+#define ncr_offb(o)	(o)
+#define ncr_offw(o)	(o)
+
+#endif
+
+/*
+ *  If the CPU and the NCR use same endian-ness addressing,
+ *  no byte reordering is needed for script patching.
+ *  Macro cpu_to_scr() is to be used for script patching.
+ *  Macro scr_to_cpu() is to be used for getting a DWORD 
+ *  from the script.
+ */
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_le32(dw)
+#define scr_to_cpu(dw)	le32_to_cpu(dw)
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define cpu_to_scr(dw)	cpu_to_be32(dw)
+#define scr_to_cpu(dw)	be32_to_cpu(dw)
+
+#else
+
+#define cpu_to_scr(dw)	(dw)
+#define scr_to_cpu(dw)	(dw)
+
+#endif
+
+/*
+ *  Access to the controller chip.
+ *
+ *  If the CPU and the NCR use same endian-ness addressing,
+ *  no byte reordering is needed for accessing chip io 
+ *  registers. Functions suffixed by '_raw' are assumed 
+ *  to access the chip over the PCI without doing byte 
+ *  reordering. Functions suffixed by '_l2b' are 
+ *  assumed to perform little-endian to big-endian byte 
+ *  reordering, those suffixed by '_b2l' blah, blah,
+ *  blah, ...
+ */
+
+/*
+ *  MEMORY mapped IO input / output
+ */
+
+#define INB_OFF(o)		readb_raw((char __iomem *)np->reg + ncr_offb(o))
+#define OUTB_OFF(o, val)	writeb_raw((val), (char __iomem *)np->reg + ncr_offb(o))
+
+#if	defined(__BIG_ENDIAN) && !defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_l2b((char __iomem *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_l2b((char __iomem *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_b2l((val), (char __iomem *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_b2l((val), (char __iomem *)np->reg + (o))
+
+#elif	defined(__LITTLE_ENDIAN) && defined(SCSI_NCR_BIG_ENDIAN)
+
+#define INW_OFF(o)		readw_b2l((char __iomem *)np->reg + ncr_offw(o))
+#define INL_OFF(o)		readl_b2l((char __iomem *)np->reg + (o))
+
+#define OUTW_OFF(o, val)	writew_l2b((val), (char __iomem *)np->reg + ncr_offw(o))
+#define OUTL_OFF(o, val)	writel_l2b((val), (char __iomem *)np->reg + (o))
+
+#else
+
+#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS
+/* Only 8 or 32 bit transfers allowed */
+#define INW_OFF(o)		(readb((char __iomem *)np->reg + ncr_offw(o)) << 8 | readb((char __iomem *)np->reg + ncr_offw(o) + 1))
+#else
+#define INW_OFF(o)		readw_raw((char __iomem *)np->reg + ncr_offw(o))
+#endif
+#define INL_OFF(o)		readl_raw((char __iomem *)np->reg + (o))
+
+#ifdef CONFIG_SCSI_NCR53C8XX_NO_WORD_TRANSFERS
+/* Only 8 or 32 bit transfers allowed */
+#define OUTW_OFF(o, val)	do { writeb((char)((val) >> 8), (char __iomem *)np->reg + ncr_offw(o)); writeb((char)(val), (char __iomem *)np->reg + ncr_offw(o) + 1); } while (0)
+#else
+#define OUTW_OFF(o, val)	writew_raw((val), (char __iomem *)np->reg + ncr_offw(o))
+#endif
+#define OUTL_OFF(o, val)	writel_raw((val), (char __iomem *)np->reg + (o))
+
+#endif
+
+#define INB(r)		INB_OFF (offsetof(struct ncr_reg,r))
+#define INW(r)		INW_OFF (offsetof(struct ncr_reg,r))
+#define INL(r)		INL_OFF (offsetof(struct ncr_reg,r))
+
+#define OUTB(r, val)	OUTB_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTW(r, val)	OUTW_OFF (offsetof(struct ncr_reg,r), (val))
+#define OUTL(r, val)	OUTL_OFF (offsetof(struct ncr_reg,r), (val))
+
+/*
+ *  Set bit field ON, OFF 
+ */
+
+#define OUTONB(r, m)	OUTB(r, INB(r) | (m))
+#define OUTOFFB(r, m)	OUTB(r, INB(r) & ~(m))
+#define OUTONW(r, m)	OUTW(r, INW(r) | (m))
+#define OUTOFFW(r, m)	OUTW(r, INW(r) & ~(m))
+#define OUTONL(r, m)	OUTL(r, INL(r) | (m))
+#define OUTOFFL(r, m)	OUTL(r, INL(r) & ~(m))
+
+/*
+ *  We normally want the chip to have a consistent view
+ *  of driver internal data structures when we restart it.
+ *  Thus these macros.
+ */
+#define OUTL_DSP(v)				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTL (nc_dsp, (v));		\
+	} while (0)
+
+#define OUTONB_STD()				\
+	do {					\
+		MEMORY_BARRIER();		\
+		OUTONB (nc_dcntl, (STD|NOCOM));	\
+	} while (0)
+
+
+/*
+**   NCR53C8XX devices features table.
+*/
+struct ncr_chip {
+	unsigned short	revision_id;
+	unsigned char	burst_max;	/* log-base-2 of max burst */
+	unsigned char	offset_max;
+	unsigned char	nr_divisor;
+	unsigned int	features;
+#define FE_LED0		(1<<0)
+#define FE_WIDE		(1<<1)    /* Wide data transfers */
+#define FE_ULTRA	(1<<2)	  /* Ultra speed 20Mtrans/sec */
+#define FE_DBLR		(1<<4)	  /* Clock doubler present */
+#define FE_QUAD		(1<<5)	  /* Clock quadrupler present */
+#define FE_ERL		(1<<6)    /* Enable read line */
+#define FE_CLSE		(1<<7)    /* Cache line size enable */
+#define FE_WRIE		(1<<8)    /* Write & Invalidate enable */
+#define FE_ERMP		(1<<9)    /* Enable read multiple */
+#define FE_BOF		(1<<10)   /* Burst opcode fetch */
+#define FE_DFS		(1<<11)   /* DMA fifo size */
+#define FE_PFEN		(1<<12)   /* Prefetch enable */
+#define FE_LDSTR	(1<<13)   /* Load/Store supported */
+#define FE_RAM		(1<<14)   /* On chip RAM present */
+#define FE_VARCLK	(1<<15)   /* SCSI clock may vary */
+#define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
+#define FE_64BIT	(1<<17)   /* Have a 64-bit PCI interface */
+#define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
+#define FE_NOPM		(1<<19)   /* Scripts handles phase mismatch */
+#define FE_LEDC		(1<<20)   /* Hardware control of LED */
+#define FE_DIFF		(1<<21)   /* Support Differential SCSI */
+#define FE_66MHZ 	(1<<23)   /* 66MHz PCI Support */
+#define FE_DAC	 	(1<<24)   /* Support DAC cycles (64 bit addressing) */
+#define FE_ISTAT1 	(1<<25)   /* Have ISTAT1, MBOX0, MBOX1 registers */
+#define FE_DAC_IN_USE	(1<<26)	  /* Platform does DAC cycles */
+#define FE_EHP		(1<<27)   /* 720: Even host parity */
+#define FE_MUX		(1<<28)   /* 720: Multiplexed bus */
+#define FE_EA		(1<<29)   /* 720: Enable Ack */
+
+#define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
+#define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_DBLR|FE_QUAD|F_CLK80)
+#define FE_SPECIAL_SET	(FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
+};
+
+
+/*
+**	Driver setup structure.
+**
+**	This structure is initialized from linux config options.
+**	It can be overridden at boot-up by the boot command line.
+*/
+#define SCSI_NCR_MAX_EXCLUDES 8
+struct ncr_driver_setup {
+	u8	master_parity;
+	u8	scsi_parity;
+	u8	disconnection;
+	u8	special_features;
+	u8	force_sync_nego;
+	u8	reverse_probe;
+	u8	pci_fix_up;
+	u8	use_nvram;
+	u8	verbose;
+	u8	default_tags;
+	u16	default_sync;
+	u16	debug;
+	u8	burst_max;
+	u8	led_pin;
+	u8	max_wide;
+	u8	settle_delay;
+	u8	diff_support;
+	u8	irqm;
+	u8	bus_check;
+	u8	optimize;
+	u8	recovery;
+	u8	host_id;
+	u16	iarb;
+	u32	excludes[SCSI_NCR_MAX_EXCLUDES];
+	char	tag_ctrl[100];
+};
+
+/*
+**	Initial setup.
+**	Can be overriden at startup by a command line.
+*/
+#define SCSI_NCR_DRIVER_SETUP			\
+{						\
+	SCSI_NCR_SETUP_MASTER_PARITY,		\
+	SCSI_NCR_SETUP_SCSI_PARITY,		\
+	SCSI_NCR_SETUP_DISCONNECTION,		\
+	SCSI_NCR_SETUP_SPECIAL_FEATURES,	\
+	SCSI_NCR_SETUP_FORCE_SYNC_NEGO,		\
+	0,					\
+	0,					\
+	1,					\
+	0,					\
+	SCSI_NCR_SETUP_DEFAULT_TAGS,		\
+	SCSI_NCR_SETUP_DEFAULT_SYNC,		\
+	0x00,					\
+	7,					\
+	0,					\
+	1,					\
+	SCSI_NCR_SETUP_SETTLE_TIME,		\
+	0,					\
+	0,					\
+	1,					\
+	0,					\
+	0,					\
+	255,					\
+	0x00					\
+}
+
+/*
+**	Boot fail safe setup.
+**	Override initial setup from boot command line:
+**	ncr53c8xx=safe:y
+*/
+#define SCSI_NCR_DRIVER_SAFE_SETUP		\
+{						\
+	0,					\
+	1,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	0,					\
+	1,					\
+	2,					\
+	0,					\
+	255,					\
+	0x00,					\
+	255,					\
+	0,					\
+	0,					\
+	10,					\
+	1,					\
+	1,					\
+	1,					\
+	0,					\
+	0,					\
+	255					\
+}
+
+/**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/
+
+/*-----------------------------------------------------------------
+**
+**	The ncr 53c810 register structure.
+**
+**-----------------------------------------------------------------
+*/
+
+struct ncr_reg {
+/*00*/  u8	nc_scntl0;    /* full arb., ena parity, par->ATN  */
+
+/*01*/  u8	nc_scntl1;    /* no reset                         */
+        #define   ISCON   0x10  /* connected to scsi		    */
+        #define   CRST    0x08  /* force reset                      */
+        #define   IARB    0x02  /* immediate arbitration            */
+
+/*02*/  u8	nc_scntl2;    /* no disconnect expected           */
+	#define   SDU     0x80  /* cmd: disconnect will raise error */
+	#define   CHM     0x40  /* sta: chained mode                */
+	#define   WSS     0x08  /* sta: wide scsi send           [W]*/
+	#define   WSR     0x01  /* sta: wide scsi received       [W]*/
+
+/*03*/  u8	nc_scntl3;    /* cnf system clock dependent       */
+	#define   EWS     0x08  /* cmd: enable wide scsi         [W]*/
+	#define   ULTRA   0x80  /* cmd: ULTRA enable                */
+				/* bits 0-2, 7 rsvd for C1010       */
+
+/*04*/  u8	nc_scid;	/* cnf host adapter scsi address    */
+	#define   RRE     0x40  /* r/w:e enable response to resel.  */
+	#define   SRE     0x20  /* r/w:e enable response to select  */
+
+/*05*/  u8	nc_sxfer;	/* ### Sync speed and count         */
+				/* bits 6-7 rsvd for C1010          */
+
+/*06*/  u8	nc_sdid;	/* ### Destination-ID               */
+
+/*07*/  u8	nc_gpreg;	/* ??? IO-Pins                      */
+
+/*08*/  u8	nc_sfbr;	/* ### First byte in phase          */
+
+/*09*/  u8	nc_socl;
+	#define   CREQ	  0x80	/* r/w: SCSI-REQ                    */
+	#define   CACK	  0x40	/* r/w: SCSI-ACK                    */
+	#define   CBSY	  0x20	/* r/w: SCSI-BSY                    */
+	#define   CSEL	  0x10	/* r/w: SCSI-SEL                    */
+	#define   CATN	  0x08	/* r/w: SCSI-ATN                    */
+	#define   CMSG	  0x04	/* r/w: SCSI-MSG                    */
+	#define   CC_D	  0x02	/* r/w: SCSI-C_D                    */
+	#define   CI_O	  0x01	/* r/w: SCSI-I_O                    */
+
+/*0a*/  u8	nc_ssid;
+
+/*0b*/  u8	nc_sbcl;
+
+/*0c*/  u8	nc_dstat;
+        #define   DFE     0x80  /* sta: dma fifo empty              */
+        #define   MDPE    0x40  /* int: master data parity error    */
+        #define   BF      0x20  /* int: script: bus fault           */
+        #define   ABRT    0x10  /* int: script: command aborted     */
+        #define   SSI     0x08  /* int: script: single step         */
+        #define   SIR     0x04  /* int: script: interrupt instruct. */
+        #define   IID     0x01  /* int: script: illegal instruct.   */
+
+/*0d*/  u8	nc_sstat0;
+        #define   ILF     0x80  /* sta: data in SIDL register lsb   */
+        #define   ORF     0x40  /* sta: data in SODR register lsb   */
+        #define   OLF     0x20  /* sta: data in SODL register lsb   */
+        #define   AIP     0x10  /* sta: arbitration in progress     */
+        #define   LOA     0x08  /* sta: arbitration lost            */
+        #define   WOA     0x04  /* sta: arbitration won             */
+        #define   IRST    0x02  /* sta: scsi reset signal           */
+        #define   SDP     0x01  /* sta: scsi parity signal          */
+
+/*0e*/  u8	nc_sstat1;
+	#define   FF3210  0xf0	/* sta: bytes in the scsi fifo      */
+
+/*0f*/  u8	nc_sstat2;
+        #define   ILF1    0x80  /* sta: data in SIDL register msb[W]*/
+        #define   ORF1    0x40  /* sta: data in SODR register msb[W]*/
+        #define   OLF1    0x20  /* sta: data in SODL register msb[W]*/
+        #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
+        #define   LDSC    0x02  /* sta: disconnect & reconnect      */
+
+/*10*/  u8	nc_dsa;	/* --> Base page                    */
+/*11*/  u8	nc_dsa1;
+/*12*/  u8	nc_dsa2;
+/*13*/  u8	nc_dsa3;
+
+/*14*/  u8	nc_istat;	/* --> Main Command and status      */
+        #define   CABRT   0x80  /* cmd: abort current operation     */
+        #define   SRST    0x40  /* mod: reset chip                  */
+        #define   SIGP    0x20  /* r/w: message from host to ncr    */
+        #define   SEM     0x10  /* r/w: message between host + ncr  */
+        #define   CON     0x08  /* sta: connected to scsi           */
+        #define   INTF    0x04  /* sta: int on the fly (reset by wr)*/
+        #define   SIP     0x02  /* sta: scsi-interrupt              */
+        #define   DIP     0x01  /* sta: host/script interrupt       */
+
+/*15*/  u8	nc_istat1;	/* 896 and later cores only */
+        #define   FLSH    0x04  /* sta: chip is flushing            */
+        #define   SRUN    0x02  /* sta: scripts are running         */
+        #define   SIRQD   0x01  /* r/w: disable INT pin             */
+
+/*16*/  u8	nc_mbox0;	/* 896 and later cores only */
+/*17*/  u8	nc_mbox1;	/* 896 and later cores only */
+
+/*18*/	u8	nc_ctest0;
+	#define   EHP     0x04	/* 720 even host parity             */
+/*19*/  u8	nc_ctest1;
+
+/*1a*/  u8	nc_ctest2;
+	#define   CSIGP   0x40
+				/* bits 0-2,7 rsvd for C1010        */
+
+/*1b*/  u8	nc_ctest3;
+	#define   FLF     0x08  /* cmd: flush dma fifo              */
+	#define   CLF	  0x04	/* cmd: clear dma fifo		    */
+	#define   FM      0x02  /* mod: fetch pin mode              */
+	#define   WRIE    0x01  /* mod: write and invalidate enable */
+				/* bits 4-7 rsvd for C1010          */
+
+/*1c*/  u32    nc_temp;	/* ### Temporary stack              */
+
+/*20*/	u8	nc_dfifo;
+/*21*/  u8	nc_ctest4;
+	#define   MUX     0x80  /* 720 host bus multiplex mode      */
+	#define   BDIS    0x80  /* mod: burst disable               */
+	#define   MPEE    0x08  /* mod: master parity error enable  */
+
+/*22*/  u8	nc_ctest5;
+	#define   DFS     0x20  /* mod: dma fifo size               */
+				/* bits 0-1, 3-7 rsvd for C1010          */
+/*23*/  u8	nc_ctest6;
+
+/*24*/  u32    nc_dbc;	/* ### Byte count and command       */
+/*28*/  u32    nc_dnad;	/* ### Next command register        */
+/*2c*/  u32    nc_dsp;	/* --> Script Pointer               */
+/*30*/  u32    nc_dsps;	/* --> Script pointer save/opcode#2 */
+
+/*34*/  u8	nc_scratcha;  /* Temporary register a            */
+/*35*/  u8	nc_scratcha1;
+/*36*/  u8	nc_scratcha2;
+/*37*/  u8	nc_scratcha3;
+
+/*38*/  u8	nc_dmode;
+	#define   BL_2    0x80  /* mod: burst length shift value +2 */
+	#define   BL_1    0x40  /* mod: burst length shift value +1 */
+	#define   ERL     0x08  /* mod: enable read line            */
+	#define   ERMP    0x04  /* mod: enable read multiple        */
+	#define   BOF     0x02  /* mod: burst op code fetch         */
+
+/*39*/  u8	nc_dien;
+/*3a*/  u8	nc_sbr;
+
+/*3b*/  u8	nc_dcntl;	/* --> Script execution control     */
+	#define   CLSE    0x80  /* mod: cache line size enable      */
+	#define   PFF     0x40  /* cmd: pre-fetch flush             */
+	#define   PFEN    0x20  /* mod: pre-fetch enable            */
+	#define   EA      0x20  /* mod: 720 enable-ack              */
+	#define   SSM     0x10  /* mod: single step mode            */
+	#define   IRQM    0x08  /* mod: irq mode (1 = totem pole !) */
+	#define   STD     0x04  /* cmd: start dma mode              */
+	#define   IRQD    0x02  /* mod: irq disable                 */
+ 	#define	  NOCOM   0x01	/* cmd: protect sfbr while reselect */
+				/* bits 0-1 rsvd for C1010          */
+
+/*3c*/  u32	nc_adder;
+
+/*40*/  u16	nc_sien;	/* -->: interrupt enable            */
+/*42*/  u16	nc_sist;	/* <--: interrupt status            */
+        #define   SBMC    0x1000/* sta: SCSI Bus Mode Change (895/6 only) */
+        #define   STO     0x0400/* sta: timeout (select)            */
+        #define   GEN     0x0200/* sta: timeout (general)           */
+        #define   HTH     0x0100/* sta: timeout (handshake)         */
+        #define   MA      0x80  /* sta: phase mismatch              */
+        #define   CMP     0x40  /* sta: arbitration complete        */
+        #define   SEL     0x20  /* sta: selected by another device  */
+        #define   RSL     0x10  /* sta: reselected by another device*/
+        #define   SGE     0x08  /* sta: gross error (over/underflow)*/
+        #define   UDC     0x04  /* sta: unexpected disconnect       */
+        #define   RST     0x02  /* sta: scsi bus reset detected     */
+        #define   PAR     0x01  /* sta: scsi parity error           */
+
+/*44*/  u8	nc_slpar;
+/*45*/  u8	nc_swide;
+/*46*/  u8	nc_macntl;
+/*47*/  u8	nc_gpcntl;
+/*48*/  u8	nc_stime0;    /* cmd: timeout for select&handshake*/
+/*49*/  u8	nc_stime1;    /* cmd: timeout user defined        */
+/*4a*/  u16   nc_respid;    /* sta: Reselect-IDs                */
+
+/*4c*/  u8	nc_stest0;
+
+/*4d*/  u8	nc_stest1;
+	#define   SCLK    0x80	/* Use the PCI clock as SCSI clock	*/
+	#define   DBLEN   0x08	/* clock doubler running		*/
+	#define   DBLSEL  0x04	/* clock doubler selected		*/
+  
+
+/*4e*/  u8	nc_stest2;
+	#define   ROF     0x40	/* reset scsi offset (after gross error!) */
+	#define   DIF     0x20  /* 720 SCSI differential mode             */
+	#define   EXT     0x02  /* extended filtering                     */
+
+/*4f*/  u8	nc_stest3;
+	#define   TE     0x80	/* c: tolerAnt enable */
+	#define   HSC    0x20	/* c: Halt SCSI Clock */
+	#define   CSF    0x02	/* c: clear scsi fifo */
+
+/*50*/  u16   nc_sidl;	/* Lowlevel: latched from scsi data */
+/*52*/  u8	nc_stest4;
+	#define   SMODE  0xc0	/* SCSI bus mode      (895/6 only) */
+	#define    SMODE_HVD 0x40	/* High Voltage Differential       */
+	#define    SMODE_SE  0x80	/* Single Ended                    */
+	#define    SMODE_LVD 0xc0	/* Low Voltage Differential        */
+	#define   LCKFRQ 0x20	/* Frequency Lock (895/6 only)     */
+				/* bits 0-5 rsvd for C1010          */
+
+/*53*/  u8	nc_53_;
+/*54*/  u16	nc_sodl;	/* Lowlevel: data out to scsi data  */
+/*56*/	u8	nc_ccntl0;	/* Chip Control 0 (896)             */
+	#define   ENPMJ  0x80	/* Enable Phase Mismatch Jump       */
+	#define   PMJCTL 0x40	/* Phase Mismatch Jump Control      */
+	#define   ENNDJ  0x20	/* Enable Non Data PM Jump          */
+	#define   DISFC  0x10	/* Disable Auto FIFO Clear          */
+	#define   DILS   0x02	/* Disable Internal Load/Store      */
+	#define   DPR    0x01	/* Disable Pipe Req                 */
+
+/*57*/	u8	nc_ccntl1;	/* Chip Control 1 (896)             */
+	#define   ZMOD   0x80	/* High Impedance Mode              */
+	#define	  DIC	 0x10	/* Disable Internal Cycles	    */
+	#define   DDAC   0x08	/* Disable Dual Address Cycle       */
+	#define   XTIMOD 0x04	/* 64-bit Table Ind. Indexing Mode  */
+	#define   EXTIBMV 0x02	/* Enable 64-bit Table Ind. BMOV    */
+	#define   EXDBMV 0x01	/* Enable 64-bit Direct BMOV        */
+
+/*58*/  u16	nc_sbdl;	/* Lowlevel: data from scsi data    */
+/*5a*/  u16	nc_5a_;
+
+/*5c*/  u8	nc_scr0;	/* Working register B               */
+/*5d*/  u8	nc_scr1;	/*                                  */
+/*5e*/  u8	nc_scr2;	/*                                  */
+/*5f*/  u8	nc_scr3;	/*                                  */
+
+/*60*/  u8	nc_scrx[64];	/* Working register C-R             */
+/*a0*/	u32	nc_mmrs;	/* Memory Move Read Selector        */
+/*a4*/	u32	nc_mmws;	/* Memory Move Write Selector       */
+/*a8*/	u32	nc_sfs;		/* Script Fetch Selector            */
+/*ac*/	u32	nc_drs;		/* DSA Relative Selector            */
+/*b0*/	u32	nc_sbms;	/* Static Block Move Selector       */
+/*b4*/	u32	nc_dbms;	/* Dynamic Block Move Selector      */
+/*b8*/	u32	nc_dnad64;	/* DMA Next Address 64              */
+/*bc*/	u16	nc_scntl4;	/* C1010 only                       */
+	#define   U3EN   0x80	/* Enable Ultra 3                   */
+	#define   AIPEN	 0x40   /* Allow check upper byte lanes     */
+	#define   XCLKH_DT 0x08 /* Extra clock of data hold on DT
+					transfer edge	            */
+	#define   XCLKH_ST 0x04 /* Extra clock of data hold on ST
+					transfer edge	            */
+
+/*be*/  u8	nc_aipcntl0;	/* Epat Control 1 C1010 only        */
+/*bf*/  u8	nc_aipcntl1;	/* AIP Control C1010_66 Only        */
+
+/*c0*/	u32	nc_pmjad1;	/* Phase Mismatch Jump Address 1    */
+/*c4*/	u32	nc_pmjad2;	/* Phase Mismatch Jump Address 2    */
+/*c8*/	u8	nc_rbc;		/* Remaining Byte Count             */
+/*c9*/	u8	nc_rbc1;	/*                                  */
+/*ca*/	u8	nc_rbc2;	/*                                  */
+/*cb*/	u8	nc_rbc3;	/*                                  */
+
+/*cc*/	u8	nc_ua;		/* Updated Address                  */
+/*cd*/	u8	nc_ua1;		/*                                  */
+/*ce*/	u8	nc_ua2;		/*                                  */
+/*cf*/	u8	nc_ua3;		/*                                  */
+/*d0*/	u32	nc_esa;		/* Entry Storage Address            */
+/*d4*/	u8	nc_ia;		/* Instruction Address              */
+/*d5*/	u8	nc_ia1;
+/*d6*/	u8	nc_ia2;
+/*d7*/	u8	nc_ia3;
+/*d8*/	u32	nc_sbc;		/* SCSI Byte Count (3 bytes only)   */
+/*dc*/	u32	nc_csbc;	/* Cumulative SCSI Byte Count       */
+
+				/* Following for C1010 only         */
+/*e0*/  u16	nc_crcpad;	/* CRC Value                        */
+/*e2*/  u8	nc_crccntl0;	/* CRC control register             */
+	#define   SNDCRC  0x10	/* Send CRC Request                 */
+/*e3*/  u8	nc_crccntl1;	/* CRC control register             */
+/*e4*/  u32	nc_crcdata;	/* CRC data register                */ 
+/*e8*/  u32	nc_e8_;		/* rsvd 			    */
+/*ec*/  u32	nc_ec_;		/* rsvd 			    */
+/*f0*/  u16	nc_dfbc;	/* DMA FIFO byte count              */ 
+
+};
+
+/*-----------------------------------------------------------
+**
+**	Utility macros for the script.
+**
+**-----------------------------------------------------------
+*/
+
+#define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
+#define REG(r) REGJ (nc_, r)
+
+typedef u32 ncrcmd;
+
+/*-----------------------------------------------------------
+**
+**	SCSI phases
+**
+**	DT phases illegal for ncr driver.
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_DATA_OUT	0x00000000
+#define	SCR_DATA_IN	0x01000000
+#define	SCR_COMMAND	0x02000000
+#define	SCR_STATUS	0x03000000
+#define SCR_DT_DATA_OUT	0x04000000
+#define SCR_DT_DATA_IN	0x05000000
+#define SCR_MSG_OUT	0x06000000
+#define SCR_MSG_IN      0x07000000
+
+#define SCR_ILG_OUT	0x04000000
+#define SCR_ILG_IN	0x05000000
+
+/*-----------------------------------------------------------
+**
+**	Data transfer via SCSI.
+**
+**-----------------------------------------------------------
+**
+**	MOVE_ABS (LEN)
+**	<<start address>>
+**
+**	MOVE_IND (LEN)
+**	<<dnad_offset>>
+**
+**	MOVE_TBL
+**	<<dnad_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define OPC_MOVE          0x08000000
+
+#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_TBL     (0x10000000 | OPC_MOVE)
+
+#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
+#define SCR_CHMOV_IND(l) ((0x20000000) | (l))
+#define SCR_CHMOV_TBL     (0x10000000)
+
+struct scr_tblmove {
+        u32  size;
+        u32  addr;
+};
+
+/*-----------------------------------------------------------
+**
+**	Selection
+**
+**-----------------------------------------------------------
+**
+**	SEL_ABS | SCR_ID (0..15)    [ | REL_JMP]
+**	<<alternate_address>>
+**
+**	SEL_TBL | << dnad_offset>>  [ | REL_JMP]
+**	<<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_SEL_ABS	0x40000000
+#define	SCR_SEL_ABS_ATN	0x41000000
+#define	SCR_SEL_TBL	0x42000000
+#define	SCR_SEL_TBL_ATN	0x43000000
+
+
+#ifdef SCSI_NCR_BIG_ENDIAN
+struct scr_tblsel {
+        u8	sel_scntl3;
+        u8	sel_id;
+        u8	sel_sxfer;
+        u8	sel_scntl4;	
+};
+#else
+struct scr_tblsel {
+        u8	sel_scntl4;	
+        u8	sel_sxfer;
+        u8	sel_id;
+        u8	sel_scntl3;
+};
+#endif
+
+#define SCR_JMP_REL     0x04000000
+#define SCR_ID(id)	(((u32)(id)) << 16)
+
+/*-----------------------------------------------------------
+**
+**	Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+**	WAIT_DISC
+**	dummy: <<alternate_address>>
+**
+**	WAIT_RESEL
+**	<<alternate_address>>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_WAIT_DISC	0x48000000
+#define SCR_WAIT_RESEL  0x50000000
+
+/*-----------------------------------------------------------
+**
+**	Bit Set / Reset
+**
+**-----------------------------------------------------------
+**
+**	SET (flags {|.. })
+**
+**	CLR (flags {|.. })
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_SET(f)     (0x58000000 | (f))
+#define SCR_CLR(f)     (0x60000000 | (f))
+
+#define	SCR_CARRY	0x00000400
+#define	SCR_TRG		0x00000200
+#define	SCR_ACK		0x00000040
+#define	SCR_ATN		0x00000008
+
+
+
+
+/*-----------------------------------------------------------
+**
+**	Memory to memory move
+**
+**-----------------------------------------------------------
+**
+**	COPY (bytecount)
+**	<< source_address >>
+**	<< destination_address >>
+**
+**	SCR_COPY   sets the NO FLUSH option by default.
+**	SCR_COPY_F does not set this option.
+**
+**	For chips which do not support this option,
+**	ncr_copy_and_bind() will remove this bit.
+**-----------------------------------------------------------
+*/
+
+#define SCR_NO_FLUSH 0x01000000
+
+#define SCR_COPY(n) (0xc0000000 | SCR_NO_FLUSH | (n))
+#define SCR_COPY_F(n) (0xc0000000 | (n))
+
+/*-----------------------------------------------------------
+**
+**	Register move and binary operations
+**
+**-----------------------------------------------------------
+**
+**	SFBR_REG (reg, op, data)        reg  = SFBR op data
+**	<< 0 >>
+**
+**	REG_SFBR (reg, op, data)        SFBR = reg op data
+**	<< 0 >>
+**
+**	REG_REG  (reg, op, data)        reg  = reg op data
+**	<< 0 >>
+**
+**-----------------------------------------------------------
+**	On 810A, 860, 825A, 875, 895 and 896 chips the content 
+**	of SFBR register can be used as data (SCR_SFBR_DATA).
+**	The 896 has additionnal IO registers starting at 
+**	offset 0x80. Bit 7 of register offset is stored in 
+**	bit 7 of the SCRIPTS instruction first DWORD.
+**-----------------------------------------------------------
+*/
+
+#define SCR_REG_OFS(ofs) ((((ofs) & 0x7f) << 16ul) + ((ofs) & 0x80)) 
+
+#define SCR_SFBR_REG(reg,op,data) \
+        (0x68000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+#define SCR_REG_SFBR(reg,op,data) \
+        (0x70000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+#define SCR_REG_REG(reg,op,data) \
+        (0x78000000 | (SCR_REG_OFS(REG(reg))) | (op) | (((data)&0xff)<<8ul))
+
+
+#define      SCR_LOAD   0x00000000
+#define      SCR_SHL    0x01000000
+#define      SCR_OR     0x02000000
+#define      SCR_XOR    0x03000000
+#define      SCR_AND    0x04000000
+#define      SCR_SHR    0x05000000
+#define      SCR_ADD    0x06000000
+#define      SCR_ADDC   0x07000000
+
+#define      SCR_SFBR_DATA   (0x00800000>>8ul)	/* Use SFBR as data */
+
+/*-----------------------------------------------------------
+**
+**	FROM_REG (reg)		  SFBR = reg
+**	<< 0 >>
+**
+**	TO_REG	 (reg)		  reg  = SFBR
+**	<< 0 >>
+**
+**	LOAD_REG (reg, data)	  reg  = <data>
+**	<< 0 >>
+**
+**	LOAD_SFBR(data) 	  SFBR = <data>
+**	<< 0 >>
+**
+**-----------------------------------------------------------
+*/
+
+#define	SCR_FROM_REG(reg) \
+	SCR_REG_SFBR(reg,SCR_OR,0)
+
+#define	SCR_TO_REG(reg) \
+	SCR_SFBR_REG(reg,SCR_OR,0)
+
+#define	SCR_LOAD_REG(reg,data) \
+	SCR_REG_REG(reg,SCR_LOAD,data)
+
+#define SCR_LOAD_SFBR(data) \
+        (SCR_REG_SFBR (gpreg, SCR_LOAD, data))
+
+/*-----------------------------------------------------------
+**
+**	LOAD  from memory   to register.
+**	STORE from register to memory.
+**
+**	Only supported by 810A, 860, 825A, 875, 895 and 896.
+**
+**-----------------------------------------------------------
+**
+**	LOAD_ABS (LEN)
+**	<<start address>>
+**
+**	LOAD_REL (LEN)        (DSA relative)
+**	<<dsa_offset>>
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_REG_OFS2(ofs) (((ofs) & 0xff) << 16ul)
+#define SCR_NO_FLUSH2	0x02000000
+#define SCR_DSA_REL2	0x10000000
+
+#define SCR_LOAD_R(reg, how, n) \
+        (0xe1000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
+
+#define SCR_STORE_R(reg, how, n) \
+        (0xe0000000 | how | (SCR_REG_OFS2(REG(reg))) | (n))
+
+#define SCR_LOAD_ABS(reg, n)	SCR_LOAD_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_LOAD_REL(reg, n)	SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n)
+#define SCR_LOAD_ABS_F(reg, n)	SCR_LOAD_R(reg, 0, n)
+#define SCR_LOAD_REL_F(reg, n)	SCR_LOAD_R(reg, SCR_DSA_REL2, n)
+
+#define SCR_STORE_ABS(reg, n)	SCR_STORE_R(reg, SCR_NO_FLUSH2, n)
+#define SCR_STORE_REL(reg, n)	SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n)
+#define SCR_STORE_ABS_F(reg, n)	SCR_STORE_R(reg, 0, n)
+#define SCR_STORE_REL_F(reg, n)	SCR_STORE_R(reg, SCR_DSA_REL2, n)
+
+
+/*-----------------------------------------------------------
+**
+**	Waiting for Disconnect or Reselect
+**
+**-----------------------------------------------------------
+**
+**	JUMP            [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<address>>
+**
+**	JUMPR           [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<distance>>
+**
+**	CALL            [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<address>>
+**
+**	CALLR           [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<distance>>
+**
+**	RETURN          [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<dummy>>
+**
+**	INT             [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<ident>>
+**
+**	INT_FLY         [ | IFTRUE/IFFALSE ( ... ) ]
+**	<<ident>>
+**
+**	Conditions:
+**	     WHEN (phase)
+**	     IF   (phase)
+**	     CARRYSET
+**	     DATA (data, mask)
+**
+**-----------------------------------------------------------
+*/
+
+#define SCR_NO_OP       0x80000000
+#define SCR_JUMP        0x80080000
+#define SCR_JUMP64      0x80480000
+#define SCR_JUMPR       0x80880000
+#define SCR_CALL        0x88080000
+#define SCR_CALLR       0x88880000
+#define SCR_RETURN      0x90080000
+#define SCR_INT         0x98080000
+#define SCR_INT_FLY     0x98180000
+
+#define IFFALSE(arg)   (0x00080000 | (arg))
+#define IFTRUE(arg)    (0x00000000 | (arg))
+
+#define WHEN(phase)    (0x00030000 | (phase))
+#define IF(phase)      (0x00020000 | (phase))
+
+#define DATA(D)        (0x00040000 | ((D) & 0xff))
+#define MASK(D,M)      (0x00040000 | (((M ^ 0xff) & 0xff) << 8ul)|((D) & 0xff))
+
+#define CARRYSET       (0x00200000)
+
+/*-----------------------------------------------------------
+**
+**	SCSI  constants.
+**
+**-----------------------------------------------------------
+*/
+
+/*
+**	Messages
+*/
+
+#define	M_COMPLETE	COMMAND_COMPLETE
+#define	M_EXTENDED	EXTENDED_MESSAGE
+#define	M_SAVE_DP	SAVE_POINTERS
+#define	M_RESTORE_DP	RESTORE_POINTERS
+#define	M_DISCONNECT	DISCONNECT
+#define	M_ID_ERROR	INITIATOR_ERROR
+#define	M_ABORT		ABORT_TASK_SET
+#define	M_REJECT	MESSAGE_REJECT
+#define	M_NOOP		NOP
+#define	M_PARITY	MSG_PARITY_ERROR
+#define	M_LCOMPLETE	LINKED_CMD_COMPLETE
+#define	M_FCOMPLETE	LINKED_FLG_CMD_COMPLETE
+#define	M_RESET		TARGET_RESET
+#define	M_ABORT_TAG	ABORT_TASK
+#define	M_CLEAR_QUEUE	CLEAR_TASK_SET
+#define	M_INIT_REC	INITIATE_RECOVERY
+#define	M_REL_REC	RELEASE_RECOVERY
+#define	M_TERMINATE	(0x11)
+#define	M_SIMPLE_TAG	SIMPLE_QUEUE_TAG
+#define	M_HEAD_TAG	HEAD_OF_QUEUE_TAG
+#define	M_ORDERED_TAG	ORDERED_QUEUE_TAG
+#define	M_IGN_RESIDUE	IGNORE_WIDE_RESIDUE
+#define	M_IDENTIFY   	(0x80)
+
+#define	M_X_MODIFY_DP	EXTENDED_MODIFY_DATA_POINTER
+#define	M_X_SYNC_REQ	EXTENDED_SDTR
+#define	M_X_WIDE_REQ	EXTENDED_WDTR
+#define	M_X_PPR_REQ	EXTENDED_PPR
+
+/*
+**	Status
+*/
+
+#define	S_GOOD		(0x00)
+#define	S_CHECK_COND	(0x02)
+#define	S_COND_MET	(0x04)
+#define	S_BUSY		(0x08)
+#define	S_INT		(0x10)
+#define	S_INT_COND_MET	(0x14)
+#define	S_CONFLICT	(0x18)
+#define	S_TERMINATED	(0x20)
+#define	S_QUEUE_FULL	(0x28)
+#define	S_ILLEGAL	(0xff)
+#define	S_SENSE		(0x80)
+
+/*
+ * End of ncrreg from FreeBSD
+ */
+
+#endif /* defined SYM53C8XX_DEFS_H */
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
new file mode 100644
index 0000000..6dc2897
--- /dev/null
+++ b/drivers/scsi/t128.c
@@ -0,0 +1,449 @@
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+/*
+ * Trantor T128/T128F/T228 driver
+ *	Note : architecturally, the T100 and T130 are different and won't 
+ * 	work
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 3.
+ *
+ * For more information, please consult 
+ *
+ * Trantor Systems, Ltd.
+ * T128/T128F/T228 SCSI Host Adapter
+ * Hardware Specifications
+ * 
+ * Trantor Systems, Ltd. 
+ * 5415 Randall Place
+ * Fremont, CA 94538
+ * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * Options : 
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ *      for commands that return with a CHECK CONDITION status. 
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking.  Not supported.
+ * 
+ * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
+ *
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.  You
+ *          only really want to use this if you're having a problem with
+ *          dropped characters during high speed communications, and even
+ *          then, you're going to be better off twiddling with transfersize.
+ *
+ * USLEEP - enable support for devices that don't disconnect.  Untested.
+ *
+ * The card is detected and initialized in one of several ways : 
+ * 1.  Autoprobe (default) - since the board is memory mapped, 
+ *     a BIOS signature is scanned for to locate the registers.
+ *     An interrupt is triggered to autoprobe for the interrupt
+ *     line.
+ *
+ * 2.  With command line overrides - t128=address,irq may be 
+ *     used on the LILO command line to override the defaults.
+ *
+ * 3.  With the T128_OVERRIDE compile time define.  This is 
+ *     specified as an array of address, irq tuples.  Ie, for
+ *     one board at the default 0xcc000 address, IRQ5, I could say 
+ *     -DT128_OVERRIDE={{0xcc000, 5}}
+ *	
+ *     Note that if the override methods are used, place holders must
+ *     be specified for other boards in the system.
+ * 
+ * T128/T128F jumper/dipswitch settings (note : on my sample, the switches 
+ * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) :
+ *
+ * T128    Sw7 Sw8 Sw6 = 0ws Sw5 = boot 
+ * T128F   Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable
+ * cc000   off off      
+ * c8000   off on
+ * dc000   on  off
+ * d8000   on  on
+ *
+ * 
+ * Interrupts 
+ * There is a 12 pin jumper block, jp1, numbered as follows : 
+ *   T128 (JP1)  	 T128F (J5)
+ * 2 4 6 8 10 12	11 9  7 5 3 1
+ * 1 3 5 7 9  11	12 10 8 6 4 2
+ *
+ * 3   2-4
+ * 5   1-3
+ * 7   3-5
+ * T128F only 
+ * 10 8-10
+ * 12 7-9
+ * 14 10-12
+ * 15 9-11
+ */
+ 
+/*
+ * $Log: t128.c,v $
+ */
+
+#include <asm/system.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "t128.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+
+static struct override {
+    unsigned long address;
+    int irq;
+} overrides 
+#ifdef T128_OVERRIDE
+    [] __initdata = T128_OVERRIDE;
+#else
+    [4] __initdata = {{0, IRQ_AUTO}, {0, IRQ_AUTO}, 
+        {0 ,IRQ_AUTO}, {0, IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+    unsigned int address;
+    int noauto;
+} bases[] __initdata = {
+    { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0}
+};
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+static struct signature {
+    const char *string;
+    int offset;
+} signatures[] __initdata = {
+{"TSROM: SCSI BIOS, Version 1.12", 0x36},
+};
+
+#define NO_SIGNATURES (sizeof (signatures) /  sizeof (struct signature))
+
+/*
+ * Function : t128_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ * 
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ */
+
+void __init t128_setup(char *str, int *ints){
+    static int commandline_current = 0;
+    int i;
+    if (ints[0] != 2) 
+	printk("t128_setup : usage t128=address,irq\n");
+    else 
+	if (commandline_current < NO_OVERRIDES) {
+	    overrides[commandline_current].address = ints[1];
+	    overrides[commandline_current].irq = ints[2];
+	    for (i = 0; i < NO_BASES; ++i)
+		if (bases[i].address == ints[1]) {
+		    bases[i].noauto = 1;
+		    break;
+		}
+	    ++commandline_current;
+	}
+}
+
+/* 
+ * Function : int t128_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : detects and initializes T128,T128F, or T228 controllers
+ *	that were autoprobed, overridden on the LILO command line, 
+ *	or specified at compile time.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ * 
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int __init t128_detect(Scsi_Host_Template * tpnt){
+    static int current_override = 0, current_base = 0;
+    struct Scsi_Host *instance;
+    unsigned long base;
+    void __iomem *p;
+    int sig, count;
+
+    tpnt->proc_name = "t128";
+    tpnt->proc_info = &t128_proc_info;
+
+    for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+	base = 0;
+	p = NULL;
+
+	if (overrides[current_override].address) {
+	    base = overrides[current_override].address;
+	    p = ioremap(bases[current_base].address, 0x2000);
+	    if (!p)
+		base = 0;
+	} else 
+	    for (; !base && (current_base < NO_BASES); ++current_base) {
+#if (TDEBUG & TDEBUG_INIT)
+    printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
+#endif
+		if (bases[current_base].noauto)
+			continue;
+		p = ioremap(bases[current_base].address, 0x2000);
+		if (!p)
+			continue;
+		for (sig = 0; sig < NO_SIGNATURES; ++sig) 
+		    if (check_signature(p + signatures[sig].offset,
+					signatures[sig].string,
+					strlen(signatures[sig].string))) {
+			base = bases[current_base].address;
+#if (TDEBUG & TDEBUG_INIT)
+			printk("scsi-t128 : detected board.\n");
+#endif
+			goto found;
+		    }
+		iounmap(p);
+	    }
+
+#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
+	printk("scsi-t128 : base = %08x\n", (unsigned int) base);
+#endif
+
+	if (!base)
+	    break;
+
+found:
+	instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if(instance == NULL)
+		break;
+		
+	instance->base = base;
+	((struct NCR5380_hostdata *)instance->hostdata)->base = p;
+
+	NCR5380_init(instance, 0);
+
+	if (overrides[current_override].irq != IRQ_AUTO)
+	    instance->irq = overrides[current_override].irq;
+	else 
+	    instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
+
+	if (instance->irq != SCSI_IRQ_NONE) 
+	    if (request_irq(instance->irq, t128_intr, SA_INTERRUPT, "t128", instance)) {
+		printk("scsi%d : IRQ%d not free, interrupts disabled\n", 
+		    instance->host_no, instance->irq);
+		instance->irq = SCSI_IRQ_NONE;
+	    } 
+
+	if (instance->irq == SCSI_IRQ_NONE) {
+	    printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
+	    printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
+	}
+
+#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
+	printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
+#endif
+
+	printk("scsi%d : at 0x%08lx", instance->host_no, instance->base);
+	if (instance->irq == SCSI_IRQ_NONE)
+	    printk (" interrupts disabled");
+	else 
+	    printk (" irq %d", instance->irq);
+	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
+	    CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
+	NCR5380_print_options(instance);
+	printk("\n");
+
+	++current_override;
+	++count;
+    }
+    return count;
+}
+
+static int t128_release(struct Scsi_Host *shost)
+{
+	NCR5380_local_declare();
+	NCR5380_setup(shost);
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	NCR5380_exit(shost);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	iounmap(base);
+	return 0;
+}
+
+/*
+ * Function : int t128_biosparam(Disk * disk, struct block_device *dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatible H-C-S mapping for 
+ *	the specified device / size.
+ * 
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ *	major / minor, ip[] = {heads, sectors, cylinders}  
+ *
+ * Returns : always 0 (success), initializes ip
+ *	
+ */
+
+/* 
+ * XXX Most SCSI boards use this mapping, I could be incorrect.  Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+ */
+
+int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int * ip)
+{
+  ip[0] = 64;
+  ip[1] = 32;
+  ip[2] = capacity >> 11;
+  return 0;
+}
+
+/*
+ * Function : int NCR5380_pread (struct Scsi_Host *instance, 
+ *	unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to 
+ *	dst
+ * 
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+ */
+
+static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
+    int len) {
+    NCR5380_local_declare();
+    void __iomem *reg;
+    unsigned char *d = dst;
+    register int i = len;
+
+    NCR5380_setup(instance);
+    reg = base + T_DATA_REG_OFFSET;
+
+#if 0
+    for (; i; --i) {
+	while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
+#else
+    while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
+    for (; i; --i) {
+#endif
+	*d++ = readb(reg);
+    }
+
+    if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+	unsigned char tmp;
+	void __iomem *foo = base + T_CONTROL_REG_OFFSET;
+	tmp = readb(foo);
+	writeb(tmp | T_CR_CT, foo);
+	writeb(tmp, foo);
+	printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
+	    instance->host_no);
+	return -1;
+    } else
+	return 0;
+}
+
+/*
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance, 
+ *	unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ *	src
+ * 
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog 
+ * 	timeout.
+ */
+
+static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
+    int len) {
+    NCR5380_local_declare();
+    void __iomem *reg;
+    unsigned char *s = src;
+    register int i = len;
+
+    NCR5380_setup(instance);
+    reg = base + T_DATA_REG_OFFSET;
+
+#if 0
+    for (; i; --i) {
+	while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
+#else
+    while (!(readb(base+T_STATUS_REG_OFFSET) & T_ST_RDY)) barrier();
+    for (; i; --i) {
+#endif
+	writeb(*s++, reg);
+    }
+
+    if (readb(base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+	unsigned char tmp;
+	void __iomem *foo = base + T_CONTROL_REG_OFFSET;
+	tmp = readb(foo);
+	writeb(tmp | T_CR_CT, foo);
+	writeb(tmp, foo);
+	printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
+	    instance->host_no);
+	return -1;
+    } else 
+	return 0;
+}
+
+MODULE_LICENSE("GPL");
+
+#include "NCR5380.c"
+
+static Scsi_Host_Template driver_template = {
+	.name           = "Trantor T128/T128F/T228",
+	.detect         = t128_detect,
+	.release        = t128_release,
+	.queuecommand   = t128_queue_command,
+	.eh_abort_handler = t128_abort,
+	.eh_bus_reset_handler    = t128_bus_reset,
+	.eh_host_reset_handler   = t128_host_reset,
+	.eh_device_reset_handler = t128_device_reset,
+	.bios_param     = t128_biosparam,
+	.can_queue      = CAN_QUEUE,
+        .this_id        = 7,
+	.sg_tablesize   = SG_ALL,
+	.cmd_per_lun    = CMD_PER_LUN,
+	.use_clustering = DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
new file mode 100644
index 0000000..161ba53
--- /dev/null
+++ b/drivers/scsi/t128.h
@@ -0,0 +1,155 @@
+/*
+ * Trantor T128/T128F/T228 defines
+ *	Note : architecturally, the T100 and T128 are different and won't work
+ *
+ * Copyright 1993, Drew Eckhardt
+ *	Visionary Computing
+ *	(Unix and Linux consulting and custom programming)
+ *	drew@colorado.edu
+ *      +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 3. 
+ *
+ * For more information, please consult 
+ *
+ * Trantor Systems, Ltd.
+ * T128/T128F/T228 SCSI Host Adapter
+ * Hardware Specifications
+ * 
+ * Trantor Systems, Ltd. 
+ * 5415 Randall Place
+ * Fremont, CA 94538
+ * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
+ * 
+ * and 
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: t128.h,v $
+ */
+
+#ifndef T128_H
+#define T128_H
+
+#define T128_PUBLIC_RELEASE 3
+
+#define TDEBUG_INIT	0x1
+#define TDEBUG_TRANSFER 0x2
+
+/*
+ * The trantor boards are memory mapped. They use an NCR5380 or 
+ * equivalent (my sample board had part second sourced from ZILOG).
+ * NCR's recommended "Pseudo-DMA" architecture is used, where 
+ * a PAL drives the DMA signals on the 5380 allowing fast, blind
+ * transfers with proper handshaking. 
+ */
+
+/*
+ * Note : a boot switch is provided for the purpose of informing the 
+ * firmware to boot or not boot from attached SCSI devices.  So, I imagine
+ * there are fewer people who've yanked the ROM like they do on the Seagate
+ * to make bootup faster, and I'll probably use this for autodetection.
+ */
+#define T_ROM_OFFSET		0
+
+/*
+ * Note : my sample board *WAS NOT* populated with the SRAM, so this
+ * can't be used for autodetection without a ROM present.
+ */
+#define T_RAM_OFFSET		0x1800
+
+/*
+ * All of the registers are allocated 32 bytes of address space, except
+ * for the data register (read/write to/from the 5380 in pseudo-DMA mode)
+ */ 
+#define T_CONTROL_REG_OFFSET	0x1c00	/* rw */
+#define T_CR_INT		0x10	/* Enable interrupts */
+#define T_CR_CT			0x02	/* Reset watchdog timer */
+
+#define T_STATUS_REG_OFFSET	0x1c20	/* ro */
+#define T_ST_BOOT		0x80	/* Boot switch */
+#define T_ST_S3			0x40	/* User settable switches, */
+#define T_ST_S2			0x20	/* read 0 when switch is on, 1 off */
+#define T_ST_S1			0x10
+#define T_ST_PS2		0x08	/* Set for Microchannel 228 */
+#define T_ST_RDY		0x04	/* 5380 DRQ */
+#define T_ST_TIM		0x02	/* indicates 40us watchdog timer fired */
+#define T_ST_ZERO		0x01	/* Always zero */
+
+#define T_5380_OFFSET		0x1d00	/* 8 registers here, see NCR5380.h */
+
+#define T_DATA_REG_OFFSET	0x1e00	/* rw 512 bytes long */
+
+#ifndef ASM
+static int t128_abort(Scsi_Cmnd *);
+static int t128_biosparam(struct scsi_device *, struct block_device *,
+			  sector_t, int*);
+static int t128_detect(Scsi_Host_Template *);
+static int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int t128_host_reset(Scsi_Cmnd *);
+static int t128_bus_reset(Scsi_Cmnd *);
+static int t128_device_reset(Scsi_Cmnd *);
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32 
+#endif
+
+#ifndef HOSTS_C
+
+#define NCR5380_implementation_fields \
+    void __iomem *base
+
+#define NCR5380_local_declare() \
+    void __iomem *base
+
+#define NCR5380_setup(instance) \
+    base = ((struct NCR5380_hostdata *)(instance->hostdata))->base
+
+#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
+
+#if !(TDEBUG & TDEBUG_TRANSFER) 
+#define NCR5380_read(reg) readb(T128_address(reg))
+#define NCR5380_write(reg, value) writeb((value),(T128_address(reg)))
+#else
+#define NCR5380_read(reg)						\
+    (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
+    , instance->hostno, (reg), T128_address(reg))), readb(T128_address(reg)))
+
+#define NCR5380_write(reg, value) {					\
+    printk("scsi%d : write %02x to register %d at address %08x\n", 	\
+	    instance->hostno, (value), (reg), T128_address(reg));	\
+    writeb((value), (T128_address(reg)));				\
+}
+#endif
+
+#define NCR5380_intr t128_intr
+#define do_NCR5380_intr do_t128_intr
+#define NCR5380_queue_command t128_queue_command
+#define NCR5380_abort t128_abort
+#define NCR5380_host_reset t128_host_reset
+#define NCR5380_device_reset t128_device_reset
+#define NCR5380_bus_reset t128_bus_reset
+#define NCR5380_proc_info t128_proc_info
+
+/* 15 14 12 10 7 5 3 
+   1101 0100 1010 1000 */
+   
+#define T128_IRQS 0xc4a8 
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* T128_H */
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
new file mode 100644
index 0000000..ee9df02
--- /dev/null
+++ b/drivers/scsi/tmscsim.c
@@ -0,0 +1,2693 @@
+/************************************************************************
+ *	FILE NAME : TMSCSIM.C						*
+ *	     BY   : C.L. Huang,  ching@tekram.com.tw			*
+ *	Description: Device Driver for Tekram DC-390(T) PCI SCSI	*
+ *		     Bus Master Host Adapter				*
+ * (C)Copyright 1995-1996 Tekram Technology Co., Ltd.			*
+ ************************************************************************
+ * (C) Copyright: put under GNU GPL in 10/96				*
+ *				(see Documentation/scsi/tmscsim.txt)	*
+ ************************************************************************
+ * $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $		*
+ *	Enhancements and bugfixes by					*
+ *	Kurt Garloff <kurt@garloff.de>	<garloff@suse.de>		*
+ ************************************************************************
+ *	HISTORY:							*
+ *									*
+ *	REV#	DATE	NAME	DESCRIPTION				*
+ *	1.00  96/04/24	CLH	First release				*
+ *	1.01  96/06/12	CLH	Fixed bug of Media Change for Removable *
+ *				Device, scan all LUN. Support Pre2.0.10 *
+ *	1.02  96/06/18	CLH	Fixed bug of Command timeout ...	*
+ *	1.03  96/09/25	KG	Added tmscsim_proc_info()		*
+ *	1.04  96/10/11	CLH	Updating for support KV 2.0.x		*
+ *	1.05  96/10/18	KG	Fixed bug in DC390_abort(null ptr deref)*
+ *	1.06  96/10/25	KG	Fixed module support			*
+ *	1.07  96/11/09	KG	Fixed tmscsim_proc_info()		*
+ *	1.08  96/11/18	KG	Fixed null ptr in DC390_Disconnect()	*
+ *	1.09  96/11/30	KG	Added register the allocated IO space	*
+ *	1.10  96/12/05	CLH	Modified tmscsim_proc_info(), and reset *
+ *				pending interrupt in DC390_detect()	*
+ *	1.11  97/02/05	KG/CLH	Fixeds problem with partitions greater	*
+ *				than 1GB				*
+ *	1.12  98/02/15  MJ      Rewritten PCI probing			*
+ *	1.13  98/04/08	KG	Support for non DC390, __initfunc decls,*
+ *				changed max devs from 10 to 16		*
+ *	1.14a 98/05/05	KG	Dynamic DCB allocation, add-single-dev	*
+ *				for LUNs if LUN_SCAN (BIOS) not set	*
+ *				runtime config using /proc interface	*
+ *	1.14b 98/05/06	KG	eliminated cli (); sti (); spinlocks	*
+ *	1.14c 98/05/07	KG	2.0.x compatibility			*
+ *	1.20a 98/05/07	KG	changed names of funcs to be consistent *
+ *				DC390_ (entry points), dc390_ (internal)*
+ *				reworked locking			*
+ *	1.20b 98/05/12	KG	bugs: version, kfree, _ctmp		*
+ *				debug output				*
+ *	1.20c 98/05/12	KG	bugs: kfree, parsing, EEpromDefaults	*
+ *	1.20d 98/05/14	KG	bugs: list linkage, clear flag after  	*
+ *				reset on startup, code cleanup		*
+ *	1.20e 98/05/15	KG	spinlock comments, name space cleanup	*
+ *				pLastDCB now part of ACB structure	*
+ *				added stats, timeout for 2.1, TagQ bug	*
+ *				RESET and INQUIRY interface commands	*
+ *	1.20f 98/05/18	KG	spinlocks fixes, max_lun fix, free DCBs	*
+ *				for missing LUNs, pending int		*
+ *	1.20g 98/05/19	KG	Clean up: Avoid short			*
+ *	1.20h 98/05/21	KG	Remove AdaptSCSIID, max_lun ...		*
+ *	1.20i 98/05/21	KG	Aiiie: Bug with TagQMask       		*
+ *	1.20j 98/05/24	KG	Handle STAT_BUSY, handle pACB->pLinkDCB	*
+ *				== 0 in remove_dev and DoingSRB_Done	*
+ *	1.20k 98/05/25	KG	DMA_INT	(experimental)	       		*
+ *	1.20l 98/05/27	KG	remove DMA_INT; DMA_IDLE cmds added;	*
+ *	1.20m 98/06/10	KG	glitch configurable; made some global	*
+ *				vars part of ACB; use DC390_readX	*
+ *	1.20n 98/06/11	KG	startup params				*
+ *	1.20o 98/06/15	KG	added TagMaxNum to boot/module params	*
+ *				Device Nr -> Idx, TagMaxNum power of 2  *
+ *	1.20p 98/06/17	KG	Docu updates. Reset depends on settings *
+ *				pci_set_master added; 2.0.xx: pcibios_*	*
+ *				used instead of MechNum things ...	*
+ *	1.20q 98/06/23	KG	Changed defaults. Added debug code for	*
+ *				removable media and fixed it. TagMaxNum	*
+ *				fixed for DC390. Locking: ACB, DRV for	*
+ *				better IRQ sharing. Spelling: Queueing	*
+ *				Parsing and glitch_cfg changes. Display	*
+ *				real SyncSpeed value. Made DisConn	*
+ *				functional (!)				*
+ *	1.20r 98/06/30	KG	Debug macros, allow disabling DsCn, set	*
+ *				BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module	*
+ *				param -1 fixed.				*
+ *	1.20s 98/08/20	KG	Debug info on abort(), try to check PCI,*
+ *				phys_to_bus instead of phys_to_virt,	*
+ *				fixed sel. process, fixed locking,	*
+ *				added MODULE_XXX infos, changed IRQ	*
+ *				request flags, disable DMA_INT		*
+ *	1.20t 98/09/07	KG	TagQ report fixed; Write Erase DMA Stat;*
+ *				initfunc -> __init; better abort;	*
+ *				Timeout for XFER_DONE & BLAST_COMPLETE;	*
+ *				Allow up to 33 commands being processed *
+ *	2.0a  98/10/14	KG	Max Cmnds back to 17. DMA_Stat clearing *
+ *				all flags. Clear within while() loops	*
+ *				in DataIn_0/Out_0. Null ptr in dumpinfo	*
+ *				for pSRB==0. Better locking during init.*
+ *				bios_param() now respects part. table.	*
+ *	2.0b  98/10/24	KG	Docu fixes. Timeout Msg in DMA Blast.	*
+ *				Disallow illegal idx in INQUIRY/REMOVE	*
+ *	2.0c  98/11/19	KG	Cleaned up detect/init for SMP boxes, 	*
+ *				Write Erase DMA (1.20t) caused problems	*
+ *	2.0d  98/12/25	KG	Christmas release ;-) Message handling  *
+ *				completely reworked. Handle target ini-	*
+ *				tiated SDTR correctly.			*
+ *	2.0d1 99/01/25	KG	Try to handle RESTORE_PTR		*
+ *	2.0d2 99/02/08	KG	Check for failure of kmalloc, correct 	*
+ *				inclusion of scsicam.h, DelayReset	*
+ *	2.0d3 99/05/31	KG	DRIVER_OK -> DID_OK, DID_NO_CONNECT,	*
+ *				detect Target mode and warn.		*
+ *				pcmd->result handling cleaned up.	*
+ *	2.0d4 99/06/01	KG	Cleaned selection process. Found bug	*
+ *				which prevented more than 16 tags. Now:	*
+ *				24. SDTR cleanup. Cleaner multi-LUN	*
+ *				handling. Don't modify ControlRegs/FIFO	*
+ *				when connected.				*
+ *	2.0d5 99/06/01	KG	Clear DevID, Fix INQUIRY after cfg chg.	*
+ *	2.0d6 99/06/02	KG	Added ADD special command to allow cfg.	*
+ *				before detection. Reset SYNC_NEGO_DONE	*
+ *				after a bus reset.			*
+ *	2.0d7 99/06/03	KG	Fixed bugs wrt add,remove commands	*
+ *	2.0d8 99/06/04	KG	Removed copying of cmnd into CmdBlock.	*
+ *				Fixed Oops in _release().		*
+ *	2.0d9 99/06/06	KG	Also tag queue INQUIRY, T_U_R, ...	*
+ *				Allow arb. no. of Tagged Cmnds. Max 32	*
+ *	2.0d1099/06/20	KG	TagMaxNo changes now honoured! Queueing *
+ *				clearified (renamed ..) TagMask handling*
+ *				cleaned.				*
+ *	2.0d1199/06/28	KG	cmd->result now identical to 2.0d2	*
+ *	2.0d1299/07/04	KG	Changed order of processing in IRQ	*
+ *	2.0d1399/07/05	KG	Don't update DCB fields if removed	*
+ *	2.0d1499/07/05	KG	remove_dev: Move kfree() to the end	*
+ *	2.0d1599/07/12	KG	use_new_eh_code: 0, ULONG -> UINT where	*
+ *				appropriate				*
+ *	2.0d1699/07/13	KG	Reenable StartSCSI interrupt, Retry msg	*
+ *	2.0d1799/07/15	KG	Remove debug msg. Disable recfg. when	*
+ *				there are queued cmnds			*
+ *	2.0d1899/07/18	KG	Selection timeout: Don't requeue	*
+ *	2.0d1999/07/18	KG	Abort: Only call scsi_done if dequeued	*
+ *	2.0d2099/07/19	KG	Rst_Detect: DoingSRB_Done		*
+ *	2.0d2199/08/15	KG	dev_id for request/free_irq, cmnd[0] for*
+ *				RETRY, SRBdone does DID_ABORT for the 	*
+ *				cmd passed by DC390_reset()		*
+ *	2.0d2299/08/25	KG	dev_id fixed. can_queue: 42		*
+ *	2.0d2399/08/25	KG	Removed some debugging code. dev_id 	*
+ *				now is set to pACB. Use u8,u16,u32. 	*
+ *	2.0d2499/11/14	KG	Unreg. I/O if failed IRQ alloc. Call	*
+ * 				done () w/ DID_BAD_TARGET in case of	*
+ *				missing DCB. We	are old EH!!		*
+ *	2.0d2500/01/15	KG	2.3.3x compat from Andreas Schultz	*
+ *				set unique_id. Disable RETRY message.	*
+ *	2.0d2600/01/29	KG	Go to new EH.				*
+ *	2.0d2700/01/31	KG	... but maintain 2.0 compat.		*
+ *				and fix DCB freeing			*
+ *	2.0d2800/02/14	KG	Queue statistics fixed, dump special cmd*
+ *				Waiting_Timer for failed StartSCSI	*
+ *				New EH: Don't return cmnds to ML on RST *
+ *				Use old EH (don't have new EH fns yet)	*
+ * 				Reset: Unlock, but refuse to queue	*
+ * 				2.3 __setup function			*
+ *	2.0e  00/05/22	KG	Return residual for 2.3			*
+ *	2.0e1 00/05/25	KG	Compile fixes for 2.3.99		*
+ *	2.0e2 00/05/27	KG	Jeff Garzik's pci_enable_device()	*
+ *	2.0e3 00/09/29	KG	Some 2.4 changes. Don't try Sync Nego	*
+ *				before INQUIRY has reported ability. 	*
+ *				Recognise INQUIRY as scanning command.	*
+ *	2.0e4 00/10/13	KG	Allow compilation into 2.4 kernel	*
+ *	2.0e5 00/11/17	KG	Store Inq.flags in DCB			*
+ *	2.0e6 00/11/22  KG	2.4 init function (Thx to O.Schumann)	*
+ * 				2.4 PCI device table (Thx to A.Richter)	*
+ *	2.0e7 00/11/28	KG	Allow overriding of BIOS settings	*
+ *	2.0f  00/12/20	KG	Handle failed INQUIRYs during scan	*
+ *	2.1a  03/11/29  GL, KG	Initial fixing for 2.6. Convert to	*
+ *				use the current PCI-mapping API, update	*
+ *				command-queuing.			*
+ *	2.1b  04/04/13  GL	Fix for 64-bit platforms		*
+ *	2.1b1 04/01/31	GL	(applied 05.04) Remove internal		*
+ *				command-queuing.			*
+ *	2.1b2 04/02/01	CH	(applied 05.04) Fix error-handling	*
+ *	2.1c  04/05/23  GL	Update to use the new pci_driver API,	*
+ *				some scsi EH updates, more cleanup.	*
+ *	2.1d  04/05/27	GL	Moved setting of scan_devices to	*
+ *				slave_alloc/_configure/_destroy, as	*
+ *				suggested by CH.			*
+ ***********************************************************************/
+
+/* DEBUG options */
+//#define DC390_DEBUG0
+//#define DC390_DEBUG1
+//#define DC390_DCBDEBUG
+//#define DC390_PARSEDEBUG
+//#define DC390_REMOVABLEDEBUG
+//#define DC390_LOCKDEBUG
+
+//#define NOP do{}while(0)
+#define C_NOP
+
+/* Debug definitions */
+#ifdef DC390_DEBUG0
+# define DEBUG0(x) x
+#else
+# define DEBUG0(x) C_NOP
+#endif
+#ifdef DC390_DEBUG1
+# define DEBUG1(x) x
+#else
+# define DEBUG1(x) C_NOP
+#endif
+#ifdef DC390_DCBDEBUG
+# define DCBDEBUG(x) x
+#else
+# define DCBDEBUG(x) C_NOP
+#endif
+#ifdef DC390_PARSEDEBUG
+# define PARSEDEBUG(x) x
+#else
+# define PARSEDEBUG(x) C_NOP
+#endif
+#ifdef DC390_REMOVABLEDEBUG
+# define REMOVABLEDEBUG(x) x
+#else
+# define REMOVABLEDEBUG(x) C_NOP
+#endif
+#define DCBDEBUG1(x) C_NOP
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/blkdev.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsicam.h>
+#include <scsi/scsi_tcq.h>
+
+
+#define DC390_BANNER "Tekram DC390/AM53C974"
+#define DC390_VERSION "2.1d 2004-05-27"
+
+#define PCI_DEVICE_ID_AMD53C974 	PCI_DEVICE_ID_AMD_SCSI
+
+#include "tmscsim.h"
+
+
+static void dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+static void dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
+
+static void dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB );
+static void dc390_Disconnect( struct dc390_acb* pACB );
+static void dc390_Reselect( struct dc390_acb* pACB );
+static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB );
+static void dc390_ScsiRstDetect( struct dc390_acb* pACB );
+static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*);
+static void dc390_dumpinfo(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB);
+static void dc390_ResetDevParam(struct dc390_acb* pACB);
+
+static u32	dc390_laststatus = 0;
+static u8	dc390_adapterCnt = 0;
+
+/* Startup values, to be overriden on the commandline */
+static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
+
+module_param_array(tmscsim, int, NULL, 0);
+MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
+MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
+MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
+
+static void *dc390_phase0[]={
+       dc390_DataOut_0,
+       dc390_DataIn_0,
+       dc390_Command_0,
+       dc390_Status_0,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOut_0,
+       dc390_MsgIn_0,
+       dc390_Nop_1
+       };
+
+static void *dc390_phase1[]={
+       dc390_DataOutPhase,
+       dc390_DataInPhase,
+       dc390_CommandPhase,
+       dc390_StatusPhase,
+       dc390_Nop_0,
+       dc390_Nop_0,
+       dc390_MsgOutPhase,
+       dc390_MsgInPhase,
+       dc390_Nop_1
+       };
+
+#ifdef DC390_DEBUG1
+static char* dc390_p0_str[] = {
+       "dc390_DataOut_0",
+       "dc390_DataIn_0",
+       "dc390_Command_0",
+       "dc390_Status_0",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOut_0",
+       "dc390_MsgIn_0",
+       "dc390_Nop_1"
+       };
+     
+static char* dc390_p1_str[] = {
+       "dc390_DataOutPhase",
+       "dc390_DataInPhase",
+       "dc390_CommandPhase",
+       "dc390_StatusPhase",
+       "dc390_Nop_0",
+       "dc390_Nop_0",
+       "dc390_MsgOutPhase",
+       "dc390_MsgInPhase",
+       "dc390_Nop_1"
+       };
+#endif   
+
+static u8  dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
+static u8  dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
+static u8  dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
+
+/***********************************************************************
+ * Functions for the management of the internal structures 
+ * (DCBs, SRBs, Queueing)
+ *
+ **********************************************************************/
+static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
+{
+   struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
+   while (pDCB->TargetID != id || pDCB->TargetLUN != lun)
+     {
+	pDCB = pDCB->pNextDCB;
+	if (pDCB == pACB->pLinkDCB)
+	     return NULL;
+     }
+   DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n",	\
+		      pDCB, pDCB->TargetID, pDCB->TargetLUN));
+   return pDCB;
+}
+
+/* Insert SRB oin top of free list */
+static __inline__ void dc390_Free_insert (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+    DEBUG0(printk ("DC390: Free SRB %p\n", pSRB));
+    pSRB->pNextSRB = pACB->pFreeSRB;
+    pACB->pFreeSRB = pSRB;
+}
+
+static __inline__ void dc390_Going_append (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+    pDCB->GoingSRBCnt++;
+    DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB));
+    /* Append to the list of Going commands */
+    if( pDCB->pGoingSRB )
+	pDCB->pGoingLast->pNextSRB = pSRB;
+    else
+	pDCB->pGoingSRB = pSRB;
+
+    pDCB->pGoingLast = pSRB;
+    /* No next one in sent list */
+    pSRB->pNextSRB = NULL;
+}
+
+static __inline__ void dc390_Going_remove (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+	DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB));
+   if (pSRB == pDCB->pGoingSRB)
+	pDCB->pGoingSRB = pSRB->pNextSRB;
+   else
+     {
+	struct dc390_srb* psrb = pDCB->pGoingSRB;
+	while (psrb && psrb->pNextSRB != pSRB)
+	  psrb = psrb->pNextSRB;
+	if (!psrb) 
+	  { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; }
+	psrb->pNextSRB = pSRB->pNextSRB;
+	if (pSRB == pDCB->pGoingLast)
+	  pDCB->pGoingLast = psrb;
+     }
+   pDCB->GoingSRBCnt--;
+}
+
+static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length)
+{
+	memset(sg, 0, sizeof(struct scatterlist));
+	sg->page	= virt_to_page(addr);
+	sg->length	= length;
+	sg->offset	= (unsigned long)addr & ~PAGE_MASK;
+	return sg;
+}
+
+/* Create pci mapping */
+static int dc390_pci_map (struct dc390_srb* pSRB)
+{
+	int error = 0;
+	struct scsi_cmnd *pcmd = pSRB->pcmd;
+	struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev;
+	dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp));
+
+	/* Map sense buffer */
+	if (pSRB->SRBFlag & AUTO_REQSENSE) {
+		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, sizeof(pcmd->sense_buffer));
+		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, 1,
+						     DMA_FROM_DEVICE);
+		cmdp->saved_dma_handle	= sg_dma_address(pSRB->pSegmentList);
+
+		/* TODO: error handling */
+		if (pSRB->SGcount != 1)
+			error = 1;
+		DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __FUNCTION__, pcmd->sense_buffer, cmdp->saved_dma_handle));
+	/* Map SG list */
+	} else if (pcmd->use_sg) {
+		pSRB->pSegmentList	= (struct scatterlist *) pcmd->request_buffer;
+		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, pcmd->use_sg,
+						     pcmd->sc_data_direction);
+		/* TODO: error handling */
+		if (!pSRB->SGcount)
+			error = 1;
+		DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
+			      __FUNCTION__, pcmd->request_buffer, pSRB->SGcount, pcmd->use_sg));
+	/* Map single segment */
+	} else if (pcmd->request_buffer && pcmd->request_bufflen) {
+		pSRB->pSegmentList	= dc390_sg_build_single(&pSRB->Segmentx, pcmd->request_buffer, pcmd->request_bufflen);
+		pSRB->SGcount		= pci_map_sg(pdev, pSRB->pSegmentList, 1,
+						     pcmd->sc_data_direction);
+		cmdp->saved_dma_handle	= sg_dma_address(pSRB->pSegmentList);
+
+		/* TODO: error handling */
+		if (pSRB->SGcount != 1)
+			error = 1;
+		DEBUG1(printk("%s(): Mapped request buffer %p at %x\n", __FUNCTION__, pcmd->request_buffer, cmdp->saved_dma_handle));
+	/* No mapping !? */	
+    	} else
+		pSRB->SGcount = 0;
+
+	return error;
+}
+
+/* Remove pci mapping */
+static void dc390_pci_unmap (struct dc390_srb* pSRB)
+{
+	struct scsi_cmnd *pcmd = pSRB->pcmd;
+	struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev;
+	DEBUG1(dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp)));
+
+	if (pSRB->SRBFlag) {
+		pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
+		DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
+	} else if (pcmd->use_sg) {
+		pci_unmap_sg(pdev, pcmd->request_buffer, pcmd->use_sg, pcmd->sc_data_direction);
+		DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n", __FUNCTION__, pcmd->request_buffer, pcmd->use_sg));
+	} else if (pcmd->request_buffer && pcmd->request_bufflen) {
+		pci_unmap_sg(pdev, &pSRB->Segmentx, 1, pcmd->sc_data_direction);
+		DEBUG1(printk("%s(): Unmapped request buffer at %x\n", __FUNCTION__, cmdp->saved_dma_handle));
+	}
+}
+
+static void __inline__
+dc390_freetag (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+	if (pSRB->TagNumber != SCSI_NO_TAG) {
+		pDCB->TagMask &= ~(1 << pSRB->TagNumber);   /* free tag mask */
+		pSRB->TagNumber = SCSI_NO_TAG;
+	}
+}
+
+
+static int
+dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
+{
+    struct scsi_cmnd *scmd = pSRB->pcmd;
+    struct scsi_device *sdev = scmd->device;
+    u8 cmd, disc_allowed, try_sync_nego;
+    char tag[2];
+
+    pSRB->ScsiPhase = SCSI_NOP0;
+
+    if (pACB->Connected)
+    {
+	// Should not happen normally
+	printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n",
+		pSRB->SRBState, pSRB->SRBFlag);
+	pSRB->SRBState = SRB_READY;
+	pACB->SelConn++;
+	return 1;
+    }
+    if (time_before (jiffies, pACB->pScsiHost->last_reset))
+    {
+	DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n"));
+	return 1;
+    }
+    /* KG: Moved pci mapping here */
+    dc390_pci_map(pSRB);
+    /* TODO: error handling */
+    DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);		/* Flush FIFO */
+    DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
+            scmd->cmnd[0], pDCB->SyncMode));
+
+    /* Don't disconnect on AUTO_REQSENSE, cause it might be an
+     * Contingent Allegiance Condition (6.6), where no tags should be used.
+     * All other have to be allowed to disconnect to prevent Incorrect 
+     * Initiator Connection (6.8.2/6.5.2) */
+    /* Changed KG, 99/06/06 */
+    if (! (pSRB->SRBFlag & AUTO_REQSENSE))
+	disc_allowed = pDCB->DevMode & EN_DISCONNECT_;
+    else
+	disc_allowed = 0;
+
+    if ((pDCB->SyncMode & SYNC_ENABLE) && pDCB->TargetLUN == 0 && sdev->sdtr &&
+	(((scmd->cmnd[0] == REQUEST_SENSE || (pSRB->SRBFlag & AUTO_REQSENSE)) &&
+	  !(pDCB->SyncMode & SYNC_NEGO_DONE)) || scmd->cmnd[0] == INQUIRY))
+      try_sync_nego = 1;
+    else
+      try_sync_nego = 0;
+
+    pSRB->MsgCnt = 0;
+    cmd = SEL_W_ATN;
+    DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN));
+    /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */
+    if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed && scsi_populate_tag_msg(scmd, tag)) {
+	DC390_write8(ScsiFifo, tag[0]);
+	pDCB->TagMask |= 1 << tag[1];
+	pSRB->TagNumber = tag[1];
+	DC390_write8(ScsiFifo, tag[1]);
+	DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for Cmd %li (SRB %p), block tag %02x\n", scmd->pid, pSRB, tag[1]));
+	cmd = SEL_W_ATN3;
+    } else {
+	/* No TagQ */
+//no_tag:
+	DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for Cmd %li (SRB %p), No TagQ\n", disc_allowed ? "" : "o", scmd->pid, pSRB));
+    }
+
+    pSRB->SRBState = SRB_START_;
+
+    if (try_sync_nego)
+      { 
+	u8 Sync_Off = pDCB->SyncOffset;
+        DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN));
+	pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE;
+	pSRB->MsgOutBuf[1] = 3;
+	pSRB->MsgOutBuf[2] = EXTENDED_SDTR;
+	pSRB->MsgOutBuf[3] = pDCB->NegoPeriod;
+	if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET;
+	pSRB->MsgOutBuf[4] = Sync_Off;
+	pSRB->MsgCnt = 5;
+	//pSRB->SRBState = SRB_MSGOUT_;
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	cmd = SEL_W_ATN_STOP;
+      }
+
+    /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
+    if (cmd != SEL_W_ATN_STOP)
+      {
+	if( pSRB->SRBFlag & AUTO_REQSENSE )
+	  {
+	    DC390_write8 (ScsiFifo, REQUEST_SENSE);
+	    DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+	    DC390_write8 (ScsiFifo, 0);
+	    DC390_write8 (ScsiFifo, 0);
+	    DC390_write8 (ScsiFifo, sizeof(scmd->sense_buffer));
+	    DC390_write8 (ScsiFifo, 0);
+	    DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
+	  }
+	else	/* write cmnd to bus */ 
+	  {
+	    u8 *ptr; u8 i;
+	    ptr = (u8 *)scmd->cmnd;
+	    for (i = 0; i < scmd->cmd_len; i++)
+	      DC390_write8 (ScsiFifo, *(ptr++));
+	  }
+      }
+    DEBUG0(if (pACB->pActiveDCB)	\
+	   printk (KERN_WARNING "DC390: ActiveDCB != 0\n"));
+    DEBUG0(if (pDCB->pActiveSRB)	\
+	   printk (KERN_WARNING "DC390: ActiveSRB != 0\n"));
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    if (DC390_read8 (Scsi_Status) & INTERRUPT)
+    {
+	dc390_freetag (pDCB, pSRB);
+	DEBUG0(printk ("DC390: Interrupt during Start SCSI (pid %li, target %02i-%02i)\n",
+		scmd->pid, scmd->device->id, scmd->device->lun));
+	pSRB->SRBState = SRB_READY;
+	//DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	pACB->SelLost++;
+	return 1;
+    }
+    DC390_write8 (ScsiCmd, cmd);
+    pACB->pActiveDCB = pDCB;
+    pDCB->pActiveSRB = pSRB;
+    pACB->Connected = 1;
+    pSRB->ScsiPhase = SCSI_NOP1;
+    return 0;
+}
+
+//#define DMA_INT EN_DMA_INT /*| EN_PAGE_INT*/
+#define DMA_INT 0
+
+#if DMA_INT
+/* This is similar to AM53C974.c ... */
+static u8 
+dc390_dma_intr (struct dc390_acb* pACB)
+{
+  struct dc390_srb* pSRB;
+  u8 dstate;
+  DEBUG0(u16 pstate; struct pci_dev *pdev = pACB->pdev);
+  
+  DEBUG0(pci_read_config_word(pdev, PCI_STATUS, &pstate));
+  DEBUG0(if (pstate & (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY))\
+	{ printk(KERN_WARNING "DC390: PCI state = %04x!\n", pstate); \
+	  pci_write_config_word(pdev, PCI_STATUS, (PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY));});
+
+  dstate = DC390_read8 (DMA_Status); 
+
+  if (! pACB->pActiveDCB || ! pACB->pActiveDCB->pActiveSRB) return dstate;
+  else pSRB  = pACB->pActiveDCB->pActiveSRB;
+  
+  if (dstate & (DMA_XFER_ABORT | DMA_XFER_ERROR | POWER_DOWN | PCI_MS_ABORT))
+    {
+	printk (KERN_ERR "DC390: DMA error (%02x)!\n", dstate);
+	return dstate;
+    }
+  if (dstate & DMA_XFER_DONE)
+    {
+	u32 residual, xferCnt; int ctr = 6000000;
+	if (! (DC390_read8 (DMA_Cmd) & READ_DIRECTION))
+	  {
+	    do
+	      {
+		DEBUG1(printk (KERN_DEBUG "DC390: read residual bytes ... \n"));
+		dstate = DC390_read8 (DMA_Status);
+		residual = DC390_read8 (CtcReg_Low) | DC390_read8 (CtcReg_Mid) << 8 |
+		  DC390_read8 (CtcReg_High) << 16;
+		residual += DC390_read8 (Current_Fifo) & 0x1f;
+	      } while (residual && ! (dstate & SCSI_INTERRUPT) && --ctr);
+	    if (!ctr) printk (KERN_CRIT "DC390: dma_intr: DMA aborted unfinished: %06x bytes remain!!\n", DC390_read32 (DMA_Wk_ByteCntr));
+	    /* residual =  ... */
+	  }
+	else
+	    residual = 0;
+	
+	/* ??? */
+	
+	xferCnt = pSRB->SGToBeXferLen - residual;
+	pSRB->SGBusAddr += xferCnt;
+	pSRB->TotalXferredLen += xferCnt;
+	pSRB->SGToBeXferLen = residual;
+# ifdef DC390_DEBUG0
+	printk (KERN_INFO "DC390: DMA: residual = %i, xfer = %i\n", 
+		(unsigned int)residual, (unsigned int)xferCnt);
+# endif
+	
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    }
+  dc390_laststatus &= ~0xff000000; dc390_laststatus |= dstate << 24;
+  return dstate;
+}
+#endif
+
+
+static void __inline__
+dc390_InvalidCmd(struct dc390_acb* pACB)
+{
+	if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT))
+		DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+}
+
+
+static irqreturn_t __inline__
+DC390_Interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct dc390_acb *pACB = (struct dc390_acb*)dev_id;
+    struct dc390_dcb *pDCB;
+    struct dc390_srb *pSRB;
+    u8  sstatus=0;
+    u8  phase;
+    void   (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
+    u8  istate, istatus;
+#if DMA_INT
+    u8  dstatus;
+#endif
+
+    sstatus = DC390_read8 (Scsi_Status);
+    if( !(sstatus & INTERRUPT) )
+	return IRQ_NONE;
+
+    DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
+
+#if DMA_INT
+    spin_lock_irq(pACB->pScsiHost->host_lock);
+    dstatus = dc390_dma_intr (pACB);
+    spin_unlock_irq(pACB->pScsiHost->host_lock);
+
+    DEBUG1(printk (KERN_DEBUG "dstatus=%02x,", dstatus));
+    if (! (dstatus & SCSI_INTERRUPT))
+      {
+	DEBUG0(printk (KERN_WARNING "DC390 Int w/o SCSI actions (only DMA?)\n"));
+	return IRQ_NONE;
+      }
+#else
+    //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    //dstatus = DC390_read8 (DMA_Status);
+    //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+#endif
+
+    spin_lock_irq(pACB->pScsiHost->host_lock);
+
+    istate = DC390_read8 (Intern_State);
+    istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
+
+    DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus));
+    dc390_laststatus &= ~0x00ffffff;
+    dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus;
+
+    if (sstatus & ILLEGAL_OP_ERR)
+    {
+	printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus);
+	dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
+    }
+	
+    else if (istatus &  INVALID_CMD)
+    {
+	printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus);
+	dc390_InvalidCmd( pACB );
+	goto unlock;
+    }
+
+    if (istatus &  SCSI_RESET)
+    {
+	dc390_ScsiRstDetect( pACB );
+	goto unlock;
+    }
+
+    if (istatus &  DISCONNECTED)
+    {
+	dc390_Disconnect( pACB );
+	goto unlock;
+    }
+
+    if (istatus &  RESELECTED)
+    {
+	dc390_Reselect( pACB );
+	goto unlock;
+    }
+
+    else if (istatus & (SELECTED | SEL_ATTENTION))
+    {
+	printk (KERN_ERR "DC390: Target mode not supported!\n");
+	goto unlock;
+    }
+
+    if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
+    {
+	pDCB = pACB->pActiveDCB;
+	if (!pDCB)
+	{
+		printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
+		goto unlock;
+	}
+	pSRB = pDCB->pActiveSRB;
+	if( pDCB->DCBFlag & ABORT_DEV_ )
+	  dc390_EnableMsgOut_Abort (pACB, pSRB);
+
+	phase = pSRB->ScsiPhase;
+	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus));
+	stateV = (void *) dc390_phase0[phase];
+	( *stateV )( pACB, pSRB, &sstatus );
+
+	pSRB->ScsiPhase = sstatus & 7;
+	phase = (u8) sstatus & 7;
+	DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus));
+	stateV = (void *) dc390_phase1[phase];
+	( *stateV )( pACB, pSRB, &sstatus );
+    }
+
+ unlock:
+    spin_unlock_irq(pACB->pScsiHost->host_lock);
+    return IRQ_HANDLED;
+}
+
+static irqreturn_t do_DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
+{
+    irqreturn_t ret;
+    DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
+    /* Locking is done in DC390_Interrupt */
+    ret = DC390_Interrupt(irq, dev_id, regs);
+    DEBUG1(printk (".. IRQ returned\n"));
+    return ret;
+}
+
+static void
+dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    u8   sstatus;
+    struct scatterlist *psgl;
+    u32    ResidCnt, xferCnt;
+    u8   dstate = 0;
+
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    unsigned long timeout = jiffies + HZ;
+
+	    /* Function called from the ISR with the host_lock held and interrupts disabled */
+	    if (pSRB->SGToBeXferLen)
+		while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) {
+		    spin_unlock_irq(pACB->pScsiHost->host_lock);
+		    udelay(50);
+		    spin_lock_irq(pACB->pScsiHost->host_lock);
+		}
+	    if (!time_before(jiffies, timeout))
+		printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n",
+			DC390_read32 (DMA_Wk_ByteCntr));
+	    dc390_laststatus &= ~0xff000000;
+	    dc390_laststatus |= dstate << 24;
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else
+	{
+	    ResidCnt  = (u32) DC390_read8 (Current_Fifo) & 0x1f;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_High) << 16;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid) << 8; 
+	    ResidCnt += (u32) DC390_read8 (CtcReg_Low);
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGBusAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+	}
+    }
+    if ((*psstatus & 7) != SCSI_DATA_OUT)
+    {
+	    DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    }	    
+}
+
+static void
+dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    u8   sstatus, residual, bval;
+    struct scatterlist *psgl;
+    u32    ResidCnt, i;
+    unsigned long   xferCnt;
+    u8      *ptr;
+
+    sstatus = *psstatus;
+
+    if( !(pSRB->SRBState & SRB_XFERPAD) )
+    {
+	if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
+	    pSRB->SRBStatus |= PARITY_ERROR;
+
+	if( sstatus & COUNT_2_ZERO )
+	{
+	    int dstate = 0;
+	    unsigned long timeout = jiffies + HZ;
+
+	    /* Function called from the ISR with the host_lock held and interrupts disabled */
+	    if (pSRB->SGToBeXferLen)
+		while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) {
+		    spin_unlock_irq(pACB->pScsiHost->host_lock);
+		    udelay(50);
+		    spin_lock_irq(pACB->pScsiHost->host_lock);
+		}
+	    if (!time_before(jiffies, timeout)) {
+		printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n",
+			DC390_read32 (DMA_Wk_ByteCntr));
+		printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
+	    }
+	    dc390_laststatus &= ~0xff000000;
+	    dc390_laststatus |= dstate << 24;
+	    DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16)	\
+		+ ((unsigned long) DC390_read8 (CtcReg_Mid) << 8)		\
+		+ ((unsigned long) DC390_read8 (CtcReg_Low)));
+	    DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%i,ToBeXfer=%li),", ResidCnt, pSRB->SGToBeXferLen));
+
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+
+	    pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+
+		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	else	/* phase changed */
+	{
+	    residual = 0;
+	    bval = DC390_read8 (Current_Fifo);
+	    while( bval & 0x1f )
+	    {
+		DEBUG1(printk (KERN_DEBUG "Check for residuals,"));
+		if( (bval & 0x1f) == 1 )
+		{
+		    for(i=0; i < 0x100; i++)
+		    {
+			bval = DC390_read8 (Current_Fifo);
+			if( !(bval & 0x1f) )
+			    goto din_1;
+			else if( i == 0x0ff )
+			{
+			    residual = 1;   /* ;1 residual byte */
+			    goto din_1;
+			}
+		    }
+		}
+		else
+		    bval = DC390_read8 (Current_Fifo);
+	    }
+din_1:
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
+	    for (i = 0xa000; i; i--)
+	    {
+		bval = DC390_read8 (DMA_Status);
+		if (bval & BLAST_COMPLETE)
+		    break;
+	    }
+	    /* It seems a DMA Blast abort isn't that bad ... */
+	    if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
+	    //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+	    dc390_laststatus &= ~0xff000000; dc390_laststatus |= bval << 24;
+
+	    DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
+	    ResidCnt = (u32) DC390_read8 (CtcReg_High);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_Mid);
+	    ResidCnt <<= 8;
+	    ResidCnt |= (u32) DC390_read8 (CtcReg_Low);
+
+	    xferCnt = pSRB->SGToBeXferLen - ResidCnt;
+	    pSRB->SGBusAddr += xferCnt;
+	    pSRB->TotalXferredLen += xferCnt;
+	    pSRB->SGToBeXferLen = ResidCnt;
+
+	    if( residual )
+	    {
+		bval = DC390_read8 (ScsiFifo);	    /* get one residual byte */
+		ptr = (u8 *) bus_to_virt( pSRB->SGBusAddr );
+		*ptr = bval;
+		pSRB->SGBusAddr++; xferCnt++;
+		pSRB->TotalXferredLen++;
+		pSRB->SGToBeXferLen--;
+	    }
+	    DEBUG1(printk (KERN_DEBUG "Xfered: %li, Total: %li, Remaining: %li\n", xferCnt,\
+			   pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
+
+	}
+    }
+    if ((*psstatus & 7) != SCSI_DATA_IN)
+    {
+	    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+	    DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD); /* | DMA_INT */
+    }
+}
+
+static void
+dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+static void
+dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+
+    pSRB->TargetStatus = DC390_read8 (ScsiFifo);
+    //udelay (1);
+    pSRB->EndMessage = DC390_read8 (ScsiFifo);	/* get message */
+
+    *psstatus = SCSI_NOP0;
+    pSRB->SRBState = SRB_COMPLETED;
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+}
+
+static void
+dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
+	*psstatus = SCSI_NOP0;
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+
+static void __inline__
+dc390_reprog (struct dc390_acb* pACB, struct dc390_dcb* pDCB)
+{
+  DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+  DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+  DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+  DC390_write8 (CtrlReg4, pDCB->CtrlR4);
+  dc390_SetXferRate (pACB, pDCB);
+}
+
+
+#ifdef DC390_DEBUG0
+static void
+dc390_printMsg (u8 *MsgBuf, u8 len)
+{
+  int i;
+  printk (" %02x", MsgBuf[0]);
+  for (i = 1; i < len; i++)
+    printk (" %02x", MsgBuf[i]);
+  printk ("\n");
+}
+#endif
+
+#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
+
+/* reject_msg */
+static void __inline__
+dc390_MsgIn_reject (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  pSRB->MsgOutBuf[0] = MESSAGE_REJECT;
+  pSRB->MsgCnt = 1;
+  DC390_ENABLE_MSGOUT;
+  DEBUG0 (printk (KERN_INFO "DC390: Reject message\n"));
+}
+
+/* abort command */
+static void
+dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB )
+{
+    pSRB->MsgOutBuf[0] = ABORT; 
+    pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
+}
+
+static struct dc390_srb*
+dc390_MsgIn_QTag (struct dc390_acb* pACB, struct dc390_dcb* pDCB, s8 tag)
+{
+  struct dc390_srb* pSRB = pDCB->pGoingSRB;
+
+  if (pSRB)
+    {
+	struct scsi_cmnd *scmd = scsi_find_tag(pSRB->pcmd->device, tag);
+	pSRB = (struct dc390_srb *)scmd->host_scribble;
+
+	if (pDCB->DCBFlag & ABORT_DEV_)
+	{
+	  pSRB->SRBState = SRB_ABORT_SENT;
+	  dc390_EnableMsgOut_Abort( pACB, pSRB );
+	}
+
+	if (!(pSRB->SRBState & SRB_DISCONNECT))
+		goto mingx0;
+
+	pDCB->pActiveSRB = pSRB;
+	pSRB->SRBState = SRB_DATA_XFER;
+    }
+  else
+    {
+    mingx0:
+      pSRB = pACB->pTmpSRB;
+      pSRB->SRBState = SRB_UNEXPECT_RESEL;
+      pDCB->pActiveSRB = pSRB;
+      pSRB->MsgOutBuf[0] = ABORT_TAG;
+      pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
+    }
+  return pSRB;
+}
+
+
+/* set async transfer mode */
+static void 
+dc390_MsgIn_set_async (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  struct dc390_dcb* pDCB = pSRB->pSRBDCB;
+  if (!(pSRB->SRBState & DO_SYNC_NEGO)) 
+    printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID);
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
+  pDCB->SyncPeriod = 0;
+  pDCB->SyncOffset = 0;
+  //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+  pDCB->CtrlR3 = FAST_CLK;	/* fast clock / normal scsi */
+  pDCB->CtrlR4 &= 0x3f;
+  pDCB->CtrlR4 |= pACB->glitch_cfg;	/* glitch eater */
+  dc390_reprog (pACB, pDCB);
+}
+
+/* set sync transfer mode */
+static void
+dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+  u8 bval;
+  u16 wval, wval1;
+  struct dc390_dcb* pDCB = pSRB->pSRBDCB;
+  u8 oldsyncperiod = pDCB->SyncPeriod;
+  u8 oldsyncoffset = pDCB->SyncOffset;
+  
+  if (!(pSRB->SRBState & DO_SYNC_NEGO))
+    {
+      printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n", 
+	      pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
+
+      /* reject */
+      //dc390_MsgIn_reject (pACB, pSRB);
+      //return dc390_MsgIn_set_async (pACB, pSRB);
+
+      /* Reply with corrected SDTR Message */
+      if (pSRB->MsgInBuf[4] > 15)
+	{ 
+	  printk (KERN_INFO "DC390: Lower Sync Offset to 15\n");
+	  pSRB->MsgInBuf[4] = 15;
+	}
+      if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
+	{
+	  printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
+	  pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
+	}
+      memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
+      pSRB->MsgCnt = 5;
+      DC390_ENABLE_MSGOUT;
+    }
+
+  pSRB->SRBState &= ~DO_SYNC_NEGO;
+  pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
+  pDCB->SyncOffset &= 0x0f0;
+  pDCB->SyncOffset |= pSRB->MsgInBuf[4];
+  pDCB->NegoPeriod = pSRB->MsgInBuf[3];
+
+  wval = (u16) pSRB->MsgInBuf[3];
+  wval = wval << 2; wval -= 3; wval1 = wval / 25;	/* compute speed */
+  if( (wval1 * 25) != wval) wval1++;
+  bval = FAST_CLK+FAST_SCSI;	/* fast clock / fast scsi */
+
+  pDCB->CtrlR4 &= 0x3f;		/* Glitch eater: 12ns less than normal */
+  if (pACB->glitch_cfg != NS_TO_GLITCH(0))
+    pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
+  else
+    pDCB->CtrlR4 |= NS_TO_GLITCH(0);
+  if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
+
+  if (wval1 >= 8)
+    {
+      wval1--;	/* Timing computation differs by 1 from FAST_SCSI */
+      bval = FAST_CLK;		/* fast clock / normal scsi */
+      pDCB->CtrlR4 |= pACB->glitch_cfg; 	/* glitch eater */
+    }
+
+  pDCB->CtrlR3 = bval;
+  pDCB->SyncPeriod = (u8)wval1;
+  
+  if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0)
+    {
+      if (! (bval & FAST_SCSI)) wval1++;
+      printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID, 
+	      40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
+    }
+  
+  dc390_reprog (pACB, pDCB);
+}
+
+
+/* handle RESTORE_PTR */
+/* I presume, this command is already mapped, so, have to remap. */
+static void 
+dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
+{
+    struct scsi_cmnd *pcmd = pSRB->pcmd;
+    struct scatterlist *psgl;
+    pSRB->TotalXferredLen = 0;
+    pSRB->SGIndex = 0;
+    if (pcmd->use_sg) {
+	pSRB->pSegmentList = (struct scatterlist *)pcmd->request_buffer;
+	psgl = pSRB->pSegmentList;
+	//dc390_pci_sync(pSRB);
+
+	while (pSRB->TotalXferredLen + (unsigned long) sg_dma_len(psgl) < pSRB->Saved_Ptr)
+	{
+	    pSRB->TotalXferredLen += (unsigned long) sg_dma_len(psgl);
+	    pSRB->SGIndex++;
+	    if( pSRB->SGIndex < pSRB->SGcount )
+	    {
+		pSRB->pSegmentList++;
+		psgl = pSRB->pSegmentList;
+		pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+		pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    }
+	    else
+		pSRB->SGToBeXferLen = 0;
+	}
+	pSRB->SGToBeXferLen -= (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+	pSRB->SGBusAddr += (pSRB->Saved_Ptr - pSRB->TotalXferredLen);
+	printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
+		pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
+
+    } else if(pcmd->request_buffer) {
+	//dc390_pci_sync(pSRB);
+
+	sg_dma_len(&pSRB->Segmentx) = pcmd->request_bufflen - pSRB->Saved_Ptr;
+	pSRB->SGcount = 1;
+	pSRB->pSegmentList = (struct scatterlist *) &pSRB->Segmentx;
+    } else {
+	 pSRB->SGcount = 0;
+	 printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
+    }
+
+  pSRB->TotalXferredLen = pSRB->Saved_Ptr;
+}
+
+
+/* According to the docs, the AM53C974 reads the message and 
+ * generates a Successful Operation IRQ before asserting ACK for
+ * the last byte (how does it know whether it's the last ?) */
+/* The old code handled it in another way, indicating, that on
+ * every message byte an IRQ is generated and every byte has to
+ * be manually ACKed. Hmmm ?  (KG, 98/11/28) */
+/* The old implementation was correct. Sigh! */
+
+/* Check if the message is complete */
+static u8 __inline__
+dc390_MsgIn_complete (u8 *msgbuf, u32 len)
+{ 
+  if (*msgbuf == EXTENDED_MESSAGE)
+  {
+	if (len < 2) return 0;
+	if (len < msgbuf[1] + 2) return 0;
+  }
+  else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
+	if (len < 2) return 0;
+  return 1;
+}
+
+
+
+/* read and eval received messages */
+static void
+dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    struct dc390_dcb*   pDCB = pACB->pActiveDCB;
+
+    /* Read the msg */
+
+    pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
+    //pSRB->SRBState = 0;
+
+    /* Msg complete ? */
+    if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
+      {
+	DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen));
+	/* Now eval the msg */
+	switch (pSRB->MsgInBuf[0]) 
+	  {
+	  case DISCONNECT: 
+	    pSRB->SRBState = SRB_DISCONNECT; break;
+	    
+	  case SIMPLE_QUEUE_TAG:
+	  case HEAD_OF_QUEUE_TAG:
+	  case ORDERED_QUEUE_TAG:
+	    pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
+	    break;
+	    
+	  case MESSAGE_REJECT: 
+	    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+	    pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
+	    if( pSRB->SRBState & DO_SYNC_NEGO)
+	      dc390_MsgIn_set_async (pACB, pSRB);
+	    break;
+	    
+	  case EXTENDED_MESSAGE:
+	    /* reject every extended msg but SDTR */
+	    if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
+	      dc390_MsgIn_reject (pACB, pSRB);
+	    else
+	      {
+		if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
+		  dc390_MsgIn_set_async (pACB, pSRB);
+		else
+		  dc390_MsgIn_set_sync (pACB, pSRB);
+	      }
+	    
+	    // nothing has to be done
+	  case COMMAND_COMPLETE: break;
+	    
+	    // SAVE POINTER may be ignored as we have the struct dc390_srb* associated with the
+	    // scsi command. Thanks, Gerard, for pointing it out.
+	  case SAVE_POINTERS: 
+	    pSRB->Saved_Ptr = pSRB->TotalXferredLen;
+	    break;
+	    // The device might want to restart transfer with a RESTORE
+	  case RESTORE_POINTERS:
+	    DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n"));
+	    dc390_restore_ptr (pACB, pSRB);
+	    break;
+
+	    // reject unknown messages
+	  default: dc390_MsgIn_reject (pACB, pSRB);
+	  }
+	
+	/* Clear counter and MsgIn state */
+	pSRB->SRBState &= ~SRB_MSGIN;
+	pACB->MsgLen = 0;
+      }
+
+    *psstatus = SCSI_NOP0;
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+
+static void
+dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
+{
+    struct scatterlist *psgl;
+    unsigned long  lval;
+    struct dc390_dcb*   pDCB = pACB->pActiveDCB;
+
+    if (pSRB == pACB->pTmpSRB)
+    {
+	if (pDCB)
+		printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN);
+	else
+		printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n");
+
+	/* Try to recover - some broken disks react badly to tagged INQUIRY */
+	if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) {
+		pSRB = pDCB->pGoingSRB;
+		pDCB->pActiveSRB = pSRB;
+	} else {
+		pSRB->pSRBDCB = pDCB;
+		dc390_EnableMsgOut_Abort(pACB, pSRB);
+		if (pDCB)
+			pDCB->DCBFlag |= ABORT_DEV;
+		return;
+	}
+    }
+
+    if( pSRB->SGIndex < pSRB->SGcount )
+    {
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir /* | DMA_INT */);
+	if( !pSRB->SGToBeXferLen )
+	{
+	    psgl = pSRB->pSegmentList;
+	    pSRB->SGBusAddr = cpu_to_le32(pci_dma_lo32(sg_dma_address(psgl)));
+	    pSRB->SGToBeXferLen = cpu_to_le32(sg_dma_len(psgl));
+	    DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
+	}
+	lval = pSRB->SGToBeXferLen;
+	DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr));
+	DC390_write8 (CtcReg_Low, (u8) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_Mid, (u8) lval);
+	lval >>= 8;
+	DC390_write8 (CtcReg_High, (u8) lval);
+
+	DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
+	DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
+
+	//DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); /* | DMA_INT; */
+	pSRB->SRBState = SRB_DATA_XFER;
+
+	DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
+
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
+	//DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
+	//DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
+    }
+    else    /* xfer pad */
+    {
+	if( pSRB->SGcount )
+	{
+	    pSRB->AdaptStatus = H_OVER_UNDER_RUN;
+	    pSRB->SRBStatus |= OVER_RUN;
+	    DEBUG0(printk (KERN_WARNING " DC390: Overrun -"));
+	}
+	DEBUG0(printk (KERN_WARNING " Clear transfer pad \n"));
+	DC390_write8 (CtcReg_Low, 0);
+	DC390_write8 (CtcReg_Mid, 0);
+	DC390_write8 (CtcReg_High, 0);
+
+	pSRB->SRBState |= SRB_XFERPAD;
+	DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
+/*
+	DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir); // | DMA_INT;
+	DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir | DMA_INT);
+*/
+    }
+}
+
+
+static void
+dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
+}
+
+static void
+dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
+}
+
+static void
+dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    struct dc390_dcb*   pDCB;
+    u8  i, cnt;
+    u8     *ptr;
+
+    DC390_write8 (ScsiCmd, RESET_ATN_CMD);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
+    {
+	cnt = (u8) pSRB->pcmd->cmd_len;
+	ptr = (u8 *) pSRB->pcmd->cmnd;
+	for(i=0; i < cnt; i++)
+	    DC390_write8 (ScsiFifo, *(ptr++));
+    }
+    else
+    {
+	DC390_write8 (ScsiFifo, REQUEST_SENSE);
+	pDCB = pACB->pActiveDCB;
+	DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
+	DC390_write8 (ScsiFifo, 0);
+	DC390_write8 (ScsiFifo, 0);
+	DC390_write8 (ScsiFifo, sizeof(pSRB->pcmd->sense_buffer));
+	DC390_write8 (ScsiFifo, 0);
+	DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
+    }
+    pSRB->SRBState = SRB_COMMAND;
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+}
+
+static void
+dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pSRB->SRBState = SRB_STATUS;
+    DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+static void
+dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    u8   bval, i, cnt;
+    u8     *ptr;
+    struct dc390_dcb*    pDCB;
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pDCB = pACB->pActiveDCB;
+    if( !(pSRB->SRBState & SRB_MSGOUT) )
+    {
+	cnt = pSRB->MsgCnt;
+	if( cnt )
+	{
+	    ptr = (u8 *) pSRB->MsgOutBuf;
+	    for(i=0; i < cnt; i++)
+		DC390_write8 (ScsiFifo, *(ptr++));
+	    pSRB->MsgCnt = 0;
+	    if( (pDCB->DCBFlag & ABORT_DEV_) &&
+		(pSRB->MsgOutBuf[0] == ABORT) )
+		pSRB->SRBState = SRB_ABORT_SENT;
+	}
+	else
+	{
+	    bval = ABORT;	/* ??? MSG_NOP */
+	    if( (pSRB->pcmd->cmnd[0] == INQUIRY ) ||
+		(pSRB->pcmd->cmnd[0] == REQUEST_SENSE) ||
+		(pSRB->SRBFlag & AUTO_REQSENSE) )
+	    {
+		if( pDCB->SyncMode & SYNC_ENABLE )
+		    goto  mop1;
+	    }
+	    DC390_write8 (ScsiFifo, bval);
+	}
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    }
+    else
+    {
+mop1:
+        printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);
+	DC390_write8 (ScsiFifo, EXTENDED_MESSAGE);
+	DC390_write8 (ScsiFifo, 3);	/*    ;length of extended msg */
+	DC390_write8 (ScsiFifo, EXTENDED_SDTR);	/*    ; sync nego */
+	DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
+	if (pDCB->SyncOffset & 0x0f)
+		    DC390_write8 (ScsiFifo, pDCB->SyncOffset);
+	else
+		    DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);		    
+	pSRB->SRBState |= DO_SYNC_NEGO;
+	DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    }
+}
+
+static void
+dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    if( !(pSRB->SRBState & SRB_MSGIN) )
+    {
+	pSRB->SRBState &= ~SRB_DISCONNECT;
+	pSRB->SRBState |= SRB_MSGIN;
+    }
+    DC390_write8 (ScsiCmd, INFO_XFER_CMD);
+    //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+}
+
+static void
+dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+static void
+dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
+{
+}
+
+
+static void
+dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB )
+{
+    u8  bval, i, cnt;
+    struct dc390_dcb*   ptr;
+
+    if( !(pDCB->TargetLUN) )
+    {
+	if( !pACB->scan_devices )
+	{
+	    ptr = pACB->pLinkDCB;
+	    cnt = pACB->DCBCnt;
+	    bval = pDCB->TargetID;
+	    for(i=0; i<cnt; i++)
+	    {
+		if( ptr->TargetID == bval )
+		{
+		    ptr->SyncPeriod = pDCB->SyncPeriod;
+		    ptr->SyncOffset = pDCB->SyncOffset;
+		    ptr->CtrlR3 = pDCB->CtrlR3;
+		    ptr->CtrlR4 = pDCB->CtrlR4;
+		    ptr->SyncMode = pDCB->SyncMode;
+		}
+		ptr = ptr->pNextDCB;
+	    }
+	}
+    }
+    return;
+}
+
+
+static void
+dc390_Disconnect( struct dc390_acb* pACB )
+{
+    struct dc390_dcb *pDCB;
+    struct dc390_srb *pSRB, *psrb;
+    u8  i, cnt;
+
+    DEBUG0(printk(KERN_INFO "DISC,"));
+
+    if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n");
+    pACB->Connected = 0;
+    pDCB = pACB->pActiveDCB;
+    if (!pDCB)
+     {
+	DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\
+	       pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel));
+	mdelay(400);
+	DC390_read8 (INT_Status);	/* Reset Pending INT */
+	DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+	return;
+     }
+    DC390_write8 (ScsiCmd, EN_SEL_RESEL);
+    pSRB = pDCB->pActiveSRB;
+    pACB->pActiveDCB = NULL;
+    pSRB->ScsiPhase = SCSI_NOP0;
+    if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
+	pSRB->SRBState = 0;
+    else if( pSRB->SRBState & SRB_ABORT_SENT )
+    {
+	pDCB->TagMask = 0;
+	pDCB->DCBFlag = 0;
+	cnt = pDCB->GoingSRBCnt;
+	pDCB->GoingSRBCnt = 0;
+	pSRB = pDCB->pGoingSRB;
+	for( i=0; i < cnt; i++)
+	{
+	    psrb = pSRB->pNextSRB;
+	    dc390_Free_insert (pACB, pSRB);
+	    pSRB = psrb;
+	}
+	pDCB->pGoingSRB = NULL;
+    }
+    else
+    {
+	if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
+	   !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
+	{	/* Selection time out */
+		pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT;
+		goto  disc1;
+	}
+	else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED))
+	{
+disc1:
+	    dc390_freetag (pDCB, pSRB);
+	    pDCB->pActiveSRB = NULL;
+	    pSRB->SRBState = SRB_FREE;
+	    dc390_SRBdone( pACB, pDCB, pSRB);
+	}
+    }
+    pACB->MsgLen = 0;
+}
+
+
+static void
+dc390_Reselect( struct dc390_acb* pACB )
+{
+    struct dc390_dcb*   pDCB;
+    struct dc390_srb*   pSRB;
+    u8  id, lun;
+
+    DEBUG0(printk(KERN_INFO "RSEL,"));
+    pACB->Connected = 1;
+    pDCB = pACB->pActiveDCB;
+    if( pDCB )
+    {	/* Arbitration lost but Reselection won */
+	DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n"));
+	pSRB = pDCB->pActiveSRB;
+	if( !( pACB->scan_devices ) )
+	{
+	    struct scsi_cmnd *pcmd = pSRB->pcmd;
+	    pcmd->resid = pcmd->request_bufflen;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    dc390_Going_remove(pDCB, pSRB);
+	    dc390_Free_insert(pACB, pSRB);
+	    pcmd->scsi_done (pcmd);
+	    DEBUG0(printk(KERN_DEBUG"DC390: Return SRB %p to free\n", pSRB));
+	}
+    }
+    /* Get ID */
+    lun = DC390_read8 (ScsiFifo);
+    DEBUG0(printk ("Dev %02x,", lun));
+    if (!(lun & (1 << pACB->pScsiHost->this_id)))
+      printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun);
+    else
+      lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
+    id = 0; while (lun >>= 1) id++;
+    /* Get LUN */
+    lun = DC390_read8 (ScsiFifo);
+    if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n");
+    lun &= 7;
+    DEBUG0(printk ("(%02i-%i),", id, lun));
+    pDCB = dc390_findDCB (pACB, id, lun);
+    if (!pDCB)
+    {
+	printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n",
+		    id, lun);
+	return;
+    }
+    pACB->pActiveDCB = pDCB;
+    /* TagQ: We expect a message soon, so never mind the exact SRB */
+    if( pDCB->SyncMode & EN_TAG_QUEUEING )
+    {
+	pSRB = pACB->pTmpSRB;
+	pDCB->pActiveSRB = pSRB;
+    }
+    else
+    {
+	pSRB = pDCB->pActiveSRB;
+	if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
+	{
+	    pSRB= pACB->pTmpSRB;
+	    pSRB->SRBState = SRB_UNEXPECT_RESEL;
+	    printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n",
+		    id, lun);
+	    pDCB->pActiveSRB = pSRB;
+	    dc390_EnableMsgOut_Abort ( pACB, pSRB );
+	}
+	else
+	{
+	    if( pDCB->DCBFlag & ABORT_DEV_ )
+	    {
+		pSRB->SRBState = SRB_ABORT_SENT;
+		printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n",
+			id, lun);
+		dc390_EnableMsgOut_Abort( pACB, pSRB );
+	    }
+	    else
+		pSRB->SRBState = SRB_DATA_XFER;
+	}
+    }
+
+    DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber));
+    pSRB->ScsiPhase = SCSI_NOP0;
+    DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
+    DC390_write8 (Sync_Period, pDCB->SyncPeriod);
+    DC390_write8 (Sync_Offset, pDCB->SyncOffset);
+    DC390_write8 (CtrlReg1, pDCB->CtrlR1);
+    DC390_write8 (CtrlReg3, pDCB->CtrlR3);
+    DC390_write8 (CtrlReg4, pDCB->CtrlR4);	/* ; Glitch eater */
+    DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);	/* ;to release the /ACK signal */
+}
+
+static int __inline__
+dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+	struct scsi_cmnd *pcmd;
+
+	pcmd = pSRB->pcmd;
+
+	REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\
+			      pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN));
+
+	pSRB->SRBFlag |= AUTO_REQSENSE;
+	pSRB->SavedSGCount = pcmd->use_sg;
+	pSRB->SavedTotXLen = pSRB->TotalXferredLen;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
+
+	/* We are called from SRBdone, original PCI mapping has been removed
+	 * already, new one is set up from StartSCSI */
+	pSRB->SGIndex = 0;
+
+	pSRB->TotalXferredLen = 0;
+	pSRB->SGToBeXferLen = 0;
+	return dc390_StartSCSI(pACB, pDCB, pSRB);
+}
+
+
+static void
+dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
+{
+    u8 status;
+    struct scsi_cmnd *pcmd;
+
+    pcmd = pSRB->pcmd;
+    /* KG: Moved pci_unmap here */
+    dc390_pci_unmap(pSRB);
+
+    status = pSRB->TargetStatus;
+
+    DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p, pid %li\n", status, pcmd->result,\
+		pSRB, pcmd->pid));
+    if(pSRB->SRBFlag & AUTO_REQSENSE)
+    {	/* Last command was a Request Sense */
+	pSRB->SRBFlag &= ~AUTO_REQSENSE;
+	pSRB->AdaptStatus = 0;
+	pSRB->TargetStatus = CHECK_CONDITION << 1;
+
+	//pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
+	if (status == (CHECK_CONDITION << 1))
+	    pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0);
+	else /* Retry */
+	{
+	    if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
+	    {
+		/* Don't retry on TEST_UNIT_READY */
+		pcmd->result = MK_RES_LNX(DRIVER_SENSE,DID_OK,0,CHECK_CONDITION);
+		REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
+		       (u32) pcmd->result, (u32) pSRB->TotalXferredLen));
+	    } else {
+		SET_RES_DRV(pcmd->result, DRIVER_SENSE);
+		pcmd->use_sg = pSRB->SavedSGCount;
+		//pSRB->ScsiCmdLen	 = (u8) (pSRB->Segment1[0] >> 8);
+		DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+		pSRB->TotalXferredLen = 0;
+		SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    }
+	}
+	goto cmd_done;
+    }
+    if( status )
+    {
+	if( status_byte(status) == CHECK_CONDITION )
+	{
+	    if (dc390_RequestSense(pACB, pDCB, pSRB)) {
+		SET_RES_DID(pcmd->result, DID_ERROR);
+		goto cmd_done;
+	    }
+	    return;
+	}
+	else if( status_byte(status) == QUEUE_FULL )
+	{
+	    scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
+	    pcmd->use_sg = pSRB->SavedSGCount;
+	    DEBUG0 (printk ("DC390: RETRY pid %li (%02x), target %02i-%02i\n", pcmd->pid, pcmd->cmnd[0], pcmd->device->id, pcmd->device->lun));
+	    pSRB->TotalXferredLen = 0;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	}
+	else if(status == SCSI_STAT_SEL_TIMEOUT)
+	{
+	    pSRB->AdaptStatus = H_SEL_TIMEOUT;
+	    pSRB->TargetStatus = 0;
+	    pcmd->result = MK_RES(0,DID_NO_CONNECT,0,0);
+	    /* Devices are removed below ... */
+	}
+	else if (status_byte(status) == BUSY && 
+		 (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
+		 pACB->scan_devices)
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = status;
+	    pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0);
+	}
+	else
+	{   /* Another error */
+	    pSRB->TotalXferredLen = 0;
+	    SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
+	    goto cmd_done;
+	}
+    }
+    else
+    {	/*  Target status == 0 */
+	status = pSRB->AdaptStatus;
+	if(status & H_OVER_UNDER_RUN)
+	{
+	    pSRB->TargetStatus = 0;
+	    SET_RES_DID(pcmd->result,DID_OK);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
+	}
+	else if( pSRB->SRBStatus & PARITY_ERROR)
+	{
+	    //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
+	    SET_RES_DID(pcmd->result,DID_PARITY);
+	    SET_RES_MSG(pcmd->result,pSRB->EndMessage);
+	}
+	else		       /* No error */
+	{
+	    pSRB->AdaptStatus = 0;
+	    pSRB->TargetStatus = 0;
+	    SET_RES_DID(pcmd->result,DID_OK);
+	}
+    }
+
+cmd_done:
+    pcmd->resid = pcmd->request_bufflen - pSRB->TotalXferredLen;
+
+    dc390_Going_remove (pDCB, pSRB);
+    /* Add to free list */
+    dc390_Free_insert (pACB, pSRB);
+
+    DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done pid %li\n", pcmd->pid));
+    pcmd->scsi_done (pcmd);
+
+    return;
+}
+
+
+/* Remove all SRBs from Going list and inform midlevel */
+static void
+dc390_DoingSRB_Done(struct dc390_acb* pACB, struct scsi_cmnd *cmd)
+{
+    struct dc390_dcb *pDCB, *pdcb;
+    struct dc390_srb *psrb, *psrb2;
+    int i;
+    struct scsi_cmnd *pcmd;
+
+    pDCB = pACB->pLinkDCB;
+    pdcb = pDCB;
+    if (! pdcb) return;
+    do
+    {
+	psrb = pdcb->pGoingSRB;
+	for (i = 0; i < pdcb->GoingSRBCnt; i++)
+	{
+	    psrb2 = psrb->pNextSRB;
+	    pcmd = psrb->pcmd;
+	    dc390_Free_insert (pACB, psrb);
+	    psrb  = psrb2;
+	}
+	pdcb->GoingSRBCnt = 0;
+	pdcb->pGoingSRB = NULL;
+	pdcb->TagMask = 0;
+	pdcb = pdcb->pNextDCB;
+    } while( pdcb != pDCB );
+}
+
+
+static void
+dc390_ResetSCSIBus( struct dc390_acb* pACB )
+{
+    //DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
+    //udelay (250);
+    //DC390_write8 (ScsiCmd, NOP_CMD);
+
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
+    pACB->Connected = 0;
+
+    return;
+}
+
+static void
+dc390_ScsiRstDetect( struct dc390_acb* pACB )
+{
+    printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus);
+    //DEBUG0(printk(KERN_INFO "RST_DETECT,"));
+
+    DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
+    /* Unlock before ? */
+    /* delay half a second */
+    udelay (1000);
+    DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
+    pACB->pScsiHost->last_reset = jiffies + 5*HZ/2
+		    + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+    pACB->Connected = 0;
+
+    if( pACB->ACBFlag & RESET_DEV )
+	pACB->ACBFlag |= RESET_DONE;
+    else
+    {   /* Reset was issued by sb else */
+	pACB->ACBFlag |= RESET_DETECT;
+
+	dc390_ResetDevParam( pACB );
+	dc390_DoingSRB_Done( pACB, NULL);
+	//dc390_RecoverSRB( pACB );
+	pACB->pActiveDCB = NULL;
+	pACB->ACBFlag = 0;
+    }
+    return;
+}
+
+static int DC390_queuecommand(struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	struct scsi_device *sdev = cmd->device;
+	struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata;
+	struct dc390_dcb *dcb = sdev->hostdata;
+	struct dc390_srb *srb;
+
+	if (sdev->queue_depth <= dcb->GoingSRBCnt)
+		goto device_busy;
+	if (acb->pActiveDCB)
+		goto host_busy;
+	if (acb->ACBFlag & (RESET_DETECT|RESET_DONE|RESET_DEV))
+		goto host_busy;
+
+	srb = acb->pFreeSRB;
+	if (unlikely(srb == NULL))
+		goto host_busy;
+
+	cmd->scsi_done = done;
+	cmd->result = 0;
+	acb->Cmds++;
+
+	acb->pFreeSRB = srb->pNextSRB;
+	srb->pNextSRB = NULL;
+
+	srb->pSRBDCB = dcb;
+	srb->pcmd = cmd;
+	cmd->host_scribble = (char *)srb;
+    
+	srb->SGIndex = 0;
+	srb->AdaptStatus = 0;
+	srb->TargetStatus = 0;
+	srb->MsgCnt = 0;
+
+	srb->SRBStatus = 0;
+	srb->SRBFlag = 0;
+	srb->SRBState = 0;
+	srb->TotalXferredLen = 0;
+	srb->SGBusAddr = 0;
+	srb->SGToBeXferLen = 0;
+	srb->ScsiPhase = 0;
+	srb->EndMessage = 0;
+	srb->TagNumber = SCSI_NO_TAG;
+
+	if (dc390_StartSCSI(acb, dcb, srb)) {
+		dc390_Free_insert(acb, srb);
+		goto host_busy;
+	}
+
+	dc390_Going_append(dcb, srb);
+
+	return 0;
+
+ host_busy:
+	return SCSI_MLQUEUE_HOST_BUSY;
+
+ device_busy:
+	return SCSI_MLQUEUE_DEVICE_BUSY;
+}
+
+static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
+{
+    struct pci_dev *pdev;
+    u16 pstat;
+
+    if (!pDCB) pDCB = pACB->pActiveDCB;
+    if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB;
+
+    if (pSRB) 
+    {
+	printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n",
+		pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
+		pSRB->ScsiPhase);
+	printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
+    }
+    printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus);
+    printk ("DC390: Register dump: SCSI block:\n");
+    printk ("DC390: XferCnt  Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
+    printk ("DC390:  %06x   %02x   %02x   %02x",
+	    DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
+	    DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
+    printk ("   %02x   %02x   %02x   %02x   %02x   %02x\n",
+	    DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
+	    DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
+    DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
+    if (DC390_read8(Current_Fifo) & 0x1f)
+      {
+	printk ("DC390: FIFO:");
+	while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo));
+	printk ("\n");
+      }
+    printk ("DC390: Register dump: DMA engine:\n");
+    printk ("DC390: Cmd   STrCnt    SBusA    WrkBC    WrkAC Stat SBusCtrl\n");
+    printk ("DC390:  %02x %08x %08x %08x %08x   %02x %08x\n",
+	    DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
+	    DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
+	    DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
+    DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+
+    pdev = pACB->pdev;
+    pci_read_config_word(pdev, PCI_STATUS, &pstat);
+    printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
+    printk ("DC390: In case of driver trouble read Documentation/scsi/tmscsim.txt\n");
+}
+
+
+static int DC390_abort(struct scsi_cmnd *cmd)
+{
+	struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata;
+	struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata;
+
+	printk("DC390: Abort command (pid %li, Device %02i-%02i)\n",
+	       cmd->pid, cmd->device->id, cmd->device->lun);
+
+	/* abort() is too stupid for already sent commands at the moment. 
+	 * If it's called we are in trouble anyway, so let's dump some info 
+	 * into the syslog at least. (KG, 98/08/20,99/06/20) */
+	dc390_dumpinfo(pACB, pDCB, NULL);
+
+	pDCB->DCBFlag |= ABORT_DEV_;
+	printk(KERN_INFO "DC390: Aborted pid %li\n", cmd->pid);
+
+	return FAILED;
+}
+
+
+static void dc390_ResetDevParam( struct dc390_acb* pACB )
+{
+    struct dc390_dcb *pDCB, *pdcb;
+
+    pDCB = pACB->pLinkDCB;
+    if (! pDCB) return;
+    pdcb = pDCB;
+    do
+    {
+	pDCB->SyncMode &= ~SYNC_NEGO_DONE;
+	pDCB->SyncPeriod = 0;
+	pDCB->SyncOffset = 0;
+	pDCB->TagMask = 0;
+	pDCB->CtrlR3 = FAST_CLK;
+	pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
+	pDCB->CtrlR4 |= pACB->glitch_cfg;
+	pDCB = pDCB->pNextDCB;
+    }
+    while( pdcb != pDCB );
+    pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT);
+
+}
+
+static int DC390_bus_reset (struct scsi_cmnd *cmd)
+{
+	struct dc390_acb*    pACB = (struct dc390_acb*) cmd->device->host->hostdata;
+	u8   bval;
+
+	bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST;
+	DC390_write8(CtrlReg1, bval);	/* disable IRQ on bus reset */
+
+	pACB->ACBFlag |= RESET_DEV;
+	dc390_ResetSCSIBus(pACB);
+
+	dc390_ResetDevParam(pACB);
+	udelay(1000);
+	pACB->pScsiHost->last_reset = jiffies + 3*HZ/2 
+		+ HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+    
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	DC390_read8(INT_Status);		/* Reset Pending INT */
+
+	dc390_DoingSRB_Done(pACB, cmd);
+
+	pACB->pActiveDCB = NULL;
+	pACB->ACBFlag = 0;
+
+	bval = DC390_read8(CtrlReg1) & ~DIS_INT_ON_SCSI_RST;
+	DC390_write8(CtrlReg1, bval);	/* re-enable interrupt */
+
+	return SUCCESS;
+}
+
+/**
+ * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new
+ * scsi device that we need to deal with.
+ *
+ * @scsi_device: The new scsi device that we need to handle.
+ */
+static int dc390_slave_alloc(struct scsi_device *scsi_device)
+{
+	struct dc390_acb *pACB = (struct dc390_acb*) scsi_device->host->hostdata;
+	struct dc390_dcb *pDCB, *pDCB2 = NULL;
+	uint id = scsi_device->id;
+	uint lun = scsi_device->lun;
+
+	pDCB = kmalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
+	if (!pDCB)
+		return -ENOMEM;
+	memset(pDCB, 0, sizeof(struct dc390_dcb));
+
+	if (!pACB->DCBCnt++) {
+		pACB->pLinkDCB = pDCB;
+		pACB->pDCBRunRobin = pDCB;
+	} else {
+		pACB->pLastDCB->pNextDCB = pDCB;
+	}
+   
+	pDCB->pNextDCB = pACB->pLinkDCB;
+	pACB->pLastDCB = pDCB;
+
+	pDCB->pDCBACB = pACB;
+	pDCB->TargetID = id;
+	pDCB->TargetLUN = lun;
+
+	/*
+	 * Some values are for all LUNs: Copy them 
+	 * In a clean way: We would have an own structure for a SCSI-ID 
+	 */
+	if (lun && (pDCB2 = dc390_findDCB(pACB, id, 0))) {
+		pDCB->DevMode = pDCB2->DevMode;
+		pDCB->SyncMode = pDCB2->SyncMode & SYNC_NEGO_DONE;
+		pDCB->SyncPeriod = pDCB2->SyncPeriod;
+		pDCB->SyncOffset = pDCB2->SyncOffset;
+		pDCB->NegoPeriod = pDCB2->NegoPeriod;
+      
+		pDCB->CtrlR3 = pDCB2->CtrlR3;
+		pDCB->CtrlR4 = pDCB2->CtrlR4;
+	} else {
+		u8 index = pACB->AdapterIndex;
+		PEEprom prom = (PEEprom) &dc390_eepromBuf[index][id << 2];
+
+		pDCB->DevMode = prom->EE_MODE1;
+		pDCB->NegoPeriod =
+			(dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
+		pDCB->CtrlR3 = FAST_CLK;
+		pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
+		if (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
+			pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
+	}
+
+	if (pDCB->DevMode & SYNC_NEGO_)
+		pDCB->SyncMode |= SYNC_ENABLE;
+	else {
+		pDCB->SyncMode = 0;
+		pDCB->SyncOffset &= ~0x0f;
+	}
+
+	pDCB->CtrlR1 = pACB->pScsiHost->this_id;
+	if (pDCB->DevMode & PARITY_CHK_)
+		pDCB->CtrlR1 |= PARITY_ERR_REPO;
+
+	pACB->scan_devices = 1;
+	scsi_device->hostdata = pDCB;
+	return 0;
+}
+
+/**
+ * dc390_slave_destroy - Called by the scsi mid layer to tell us about a
+ * device that is going away.
+ *
+ * @scsi_device: The scsi device that we need to remove.
+ */
+static void dc390_slave_destroy(struct scsi_device *scsi_device)
+{
+	struct dc390_acb* pACB = (struct dc390_acb*) scsi_device->host->hostdata;
+	struct dc390_dcb* pDCB = (struct dc390_dcb*) scsi_device->hostdata;
+	struct dc390_dcb* pPrevDCB = pACB->pLinkDCB;
+
+	pACB->scan_devices = 0;
+
+	BUG_ON(pDCB->GoingSRBCnt > 1);
+	
+	if (pDCB == pACB->pLinkDCB) {
+		if (pACB->pLastDCB == pDCB) {
+			pDCB->pNextDCB = NULL;
+			pACB->pLastDCB = NULL;
+		}
+		pACB->pLinkDCB = pDCB->pNextDCB;
+	} else {
+		while (pPrevDCB->pNextDCB != pDCB)
+			pPrevDCB = pPrevDCB->pNextDCB;
+		pPrevDCB->pNextDCB = pDCB->pNextDCB;
+		if (pDCB == pACB->pLastDCB)
+			pACB->pLastDCB = pPrevDCB;
+	}
+
+	if (pDCB == pACB->pActiveDCB)
+		pACB->pActiveDCB = NULL;
+	if (pDCB == pACB->pLinkDCB)
+		pACB->pLinkDCB = pDCB->pNextDCB;
+	if (pDCB == pACB->pDCBRunRobin)
+		pACB->pDCBRunRobin = pDCB->pNextDCB;
+	kfree(pDCB); 
+	
+	pACB->DCBCnt--;
+}
+
+static int dc390_slave_configure(struct scsi_device *sdev)
+{
+	struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata;
+	struct dc390_dcb *dcb = (struct dc390_dcb *)sdev->hostdata;
+
+	acb->scan_devices = 0;
+	if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) {
+		dcb->SyncMode |= EN_TAG_QUEUEING;
+		scsi_activate_tcq(sdev, acb->TagMaxNum);
+	}
+
+	return 0;
+}
+
+static struct scsi_host_template driver_template = {
+	.module			= THIS_MODULE,
+	.proc_name		= "tmscsim", 
+	.name			= DC390_BANNER " V" DC390_VERSION,
+	.slave_alloc		= dc390_slave_alloc,
+	.slave_configure	= dc390_slave_configure,
+	.slave_destroy		= dc390_slave_destroy,
+	.queuecommand		= DC390_queuecommand,
+	.eh_abort_handler	= DC390_abort,
+	.eh_bus_reset_handler	= DC390_bus_reset,
+	.can_queue		= 1,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
+/***********************************************************************
+ * Functions for access to DC390 EEPROM
+ * and some to emulate it
+ *
+ **********************************************************************/
+
+static void __devinit dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
+{
+	u8 carryFlag = 1, j = 0x80, bval;
+	int i;
+
+	for (i = 0; i < 9; i++) {
+		if (carryFlag) {
+			pci_write_config_byte(pdev, 0x80, 0x40);
+			bval = 0xc0;
+		} else
+			bval = 0x80;
+
+		udelay(160);
+		pci_write_config_byte(pdev, 0x80, bval);
+		udelay(160);
+		pci_write_config_byte(pdev, 0x80, 0);
+		udelay(160);
+
+		carryFlag = (cmd & j) ? 1 : 0;
+		j >>= 1;
+	}
+}
+
+static u16 __devinit dc390_eeprom_get_data(struct pci_dev *pdev)
+{
+	int i;
+	u16 wval = 0;
+	u8 bval;
+
+	for (i = 0; i < 16; i++) {
+		wval <<= 1;
+
+		pci_write_config_byte(pdev, 0x80, 0x80);
+		udelay(160);
+		pci_write_config_byte(pdev, 0x80, 0x40);
+		udelay(160);
+		pci_read_config_byte(pdev, 0x00, &bval);
+
+		if (bval == 0x22)
+			wval |= 1;
+	}
+
+	return wval;
+}
+
+static void __devinit dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
+{
+	u8 cmd = EEPROM_READ, i;
+
+	for (i = 0; i < 0x40; i++) {
+		pci_write_config_byte(pdev, 0xc0, 0);
+		udelay(160);
+
+		dc390_eeprom_prepare_read(pdev, cmd++);
+		*ptr++ = dc390_eeprom_get_data(pdev);
+
+		pci_write_config_byte(pdev, 0x80, 0);
+		pci_write_config_byte(pdev, 0x80, 0);
+		udelay(160);
+	}
+}
+
+/* Override EEprom values with explicitly set values */
+static void __devinit dc390_eeprom_override(u8 index)
+{
+	u8 *ptr = (u8 *) dc390_eepromBuf[index], id;
+
+	/* Adapter Settings */
+	if (tmscsim[0] != -2)
+		ptr[EE_ADAPT_SCSI_ID] = (u8)tmscsim[0];	/* Adapter ID */
+	if (tmscsim[3] != -2)
+		ptr[EE_MODE2] = (u8)tmscsim[3];
+	if (tmscsim[5] != -2)
+		ptr[EE_DELAY] = tmscsim[5];		/* Reset delay */
+	if (tmscsim[4] != -2)
+		ptr[EE_TAG_CMD_NUM] = (u8)tmscsim[4];	/* Tagged Cmds */
+
+	/* Device Settings */
+	for (id = 0; id < MAX_SCSI_ID; id++) {
+		if (tmscsim[2] != -2)
+			ptr[id << 2] = (u8)tmscsim[2];		/* EE_MODE1 */
+		if (tmscsim[1] != -2)
+			ptr[(id << 2) + 1] = (u8)tmscsim[1];	/* EE_Speed */
+	}
+}
+
+static int __devinitdata tmscsim_def[] = {
+	7,
+	0 /* 10MHz */,
+	PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ | SYNC_NEGO_ | TAG_QUEUEING_,
+	MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION | LUN_CHECK,
+	3 /* 16 Tags per LUN */,
+	1 /* s delay after Reset */,
+};
+
+/* Copy defaults over set values where missing */
+static void __devinit dc390_fill_with_defaults (void)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		if (tmscsim[i] < 0 || tmscsim[i] > 255)
+			tmscsim[i] = tmscsim_def[i];
+	}
+
+	/* Sanity checks */
+	if (tmscsim[0] > 7)
+		tmscsim[0] = 7;
+	if (tmscsim[1] > 7)
+		tmscsim[1] = 4;
+	if (tmscsim[4] > 5)
+		tmscsim[4] = 4;
+	if (tmscsim[5] > 180)
+		tmscsim[5] = 180;
+}
+
+static void __devinit dc390_check_eeprom(struct pci_dev *pdev, u8 index)
+{
+	u8 interpd[] = {1, 3, 5, 10, 16, 30, 60, 120};
+	u8 EEbuf[128];
+	u16 *ptr = (u16 *)EEbuf, wval = 0;
+	int i;
+
+	dc390_read_eeprom(pdev, ptr);
+	memcpy(dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
+	memcpy(&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID], 
+	       &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
+
+	dc390_eepromBuf[index][EE_DELAY] = interpd[dc390_eepromBuf[index][EE_DELAY]];
+
+	for (i = 0; i < 0x40; i++, ptr++)
+		wval += *ptr;
+
+	/* no Tekram EEprom found */
+	if (wval != 0x1234) {
+		int speed;
+
+		printk(KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n");
+
+		/*
+		 * XXX(hch): bogus, because we might have tekram and
+		 *           non-tekram hbas in a single machine.
+		 */
+		dc390_fill_with_defaults();
+
+		speed = dc390_clock_speed[tmscsim[1]];
+		printk(KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz), "
+		       "DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n", 
+		       tmscsim[0], tmscsim[1], speed / 10, speed % 10,
+		       (u8)tmscsim[2], (u8)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]);
+	}
+}
+
+static void __devinit dc390_init_hw(struct dc390_acb *pACB, u8 index)
+{
+	struct Scsi_Host *shost = pACB->pScsiHost;
+	u8 dstate;
+
+	/* Disable SCSI bus reset interrupt */
+	DC390_write8(CtrlReg1, DIS_INT_ON_SCSI_RST | shost->this_id);
+
+	if (pACB->Gmode2 & RST_SCSI_BUS) {
+		dc390_ResetSCSIBus(pACB);
+		udelay(1000);
+		shost->last_reset = jiffies + HZ/2 +
+			HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
+	}
+
+	pACB->ACBFlag = 0;
+
+	/* Reset Pending INT */
+	DC390_read8(INT_Status);
+	
+	/* 250ms selection timeout */
+	DC390_write8(Scsi_TimeOut, SEL_TIMEOUT);
+	
+	/* Conversion factor = 0 , 40MHz clock */
+	DC390_write8(Clk_Factor, CLK_FREQ_40MHZ);
+	
+	/* NOP cmd - clear command register */
+	DC390_write8(ScsiCmd, NOP_CMD);
+	
+	/* Enable Feature and SCSI-2 */
+	DC390_write8(CtrlReg2, EN_FEATURE+EN_SCSI2_CMD);
+	
+	/* Fast clock */
+	DC390_write8(CtrlReg3, FAST_CLK);
+
+	/* Negation */
+	DC390_write8(CtrlReg4, pACB->glitch_cfg | /* glitch eater */
+		(dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ?
+		 NEGATE_REQACKDATA : 0);
+	
+	/* Clear Transfer Count High: ID */
+	DC390_write8(CtcReg_High, 0);
+	DC390_write8(DMA_Cmd, DMA_IDLE_CMD);
+	DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
+	DC390_write32(DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
+
+	dstate = DC390_read8(DMA_Status);
+	DC390_write8(DMA_Status, dstate);
+}
+
+static int __devinit dc390_probe_one(struct pci_dev *pdev,
+				    const struct pci_device_id *id)
+{
+	struct dc390_acb *pACB;
+	struct Scsi_Host *shost;
+	unsigned long io_port;
+	int error = -ENODEV, i;
+
+	if (pci_enable_device(pdev))
+		goto out;
+
+	pci_set_master(pdev);
+
+	error = -ENOMEM;
+	shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
+	if (!shost)
+		goto out_disable_device;
+
+	pACB = (struct dc390_acb *)shost->hostdata;
+	memset(pACB, 0, sizeof(struct dc390_acb));
+
+	dc390_check_eeprom(pdev, dc390_adapterCnt);
+	dc390_eeprom_override(dc390_adapterCnt);
+
+	io_port = pci_resource_start(pdev, 0);
+
+	shost->this_id = dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID];
+	shost->io_port = io_port;
+	shost->n_io_port = 0x80;
+	shost->irq = pdev->irq;
+	shost->base = io_port;
+	shost->unique_id = io_port;
+	shost->last_reset = jiffies;
+	
+	pACB->pScsiHost = shost;
+	pACB->IOPortBase = (u16) io_port;
+	pACB->IRQLevel = pdev->irq;
+	
+	shost->max_id = 8;
+
+	if (shost->max_id - 1 ==
+	    dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID])
+		shost->max_id--;
+
+	if (dc390_eepromBuf[dc390_adapterCnt][EE_MODE2] & LUN_CHECK)
+		shost->max_lun = 8;
+	else
+		shost->max_lun = 1;
+
+	pACB->pFreeSRB = pACB->SRB_array;
+	pACB->SRBCount = MAX_SRB_CNT;
+	pACB->AdapterIndex = dc390_adapterCnt;
+	pACB->TagMaxNum =
+		2 << dc390_eepromBuf[dc390_adapterCnt][EE_TAG_CMD_NUM];
+	pACB->Gmode2 = dc390_eepromBuf[dc390_adapterCnt][EE_MODE2];
+
+	for (i = 0; i < pACB->SRBCount-1; i++)
+		pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
+	pACB->SRB_array[pACB->SRBCount-1].pNextSRB = NULL;
+	pACB->pTmpSRB = &pACB->TmpSRB;
+
+	pACB->sel_timeout = SEL_TIMEOUT;
+	pACB->glitch_cfg = EATER_25NS;
+	pACB->pdev = pdev;
+
+	if (!request_region(io_port, shost->n_io_port, "tmscsim")) {
+		printk(KERN_ERR "DC390: register IO ports error!\n");
+		goto out_host_put;
+	}
+
+	/* Reset Pending INT */
+	DC390_read8_(INT_Status, io_port);
+
+	if (request_irq(pdev->irq, do_DC390_Interrupt, SA_SHIRQ,
+				"tmscsim", pACB)) {
+		printk(KERN_ERR "DC390: register IRQ error!\n");
+		goto out_release_region;
+	}
+
+	dc390_init_hw(pACB, dc390_adapterCnt);
+	
+	dc390_adapterCnt++;
+
+	pci_set_drvdata(pdev, shost);
+
+	error = scsi_add_host(shost, &pdev->dev);
+	if (error)
+		goto out_free_irq;
+	scsi_scan_host(shost);
+	return 0;
+
+ out_free_irq:
+	free_irq(pdev->irq, pACB);
+ out_release_region:
+	release_region(io_port, shost->n_io_port);
+ out_host_put:
+	scsi_host_put(shost);
+ out_disable_device:
+	pci_disable_device(pdev);
+ out:
+	return error;
+}
+
+/**
+ * dc390_remove_one - Called to remove a single instance of the adapter.
+ *
+ * @dev: The PCI device to remove.
+ */
+static void __devexit dc390_remove_one(struct pci_dev *dev)
+{
+	struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
+	unsigned long iflags;
+	struct dc390_acb* pACB = (struct dc390_acb*) scsi_host->hostdata;
+	u8 bval;
+
+	scsi_remove_host(scsi_host);
+
+	spin_lock_irqsave(scsi_host->host_lock, iflags);
+	pACB->ACBFlag = RESET_DEV;
+	bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST;
+	DC390_write8 (CtrlReg1, bval);	/* disable interrupt */
+	if (pACB->Gmode2 & RST_SCSI_BUS)
+		dc390_ResetSCSIBus(pACB);
+	spin_unlock_irqrestore(scsi_host->host_lock, iflags);
+
+	free_irq(scsi_host->irq, pACB);
+	release_region(scsi_host->io_port, scsi_host->n_io_port);
+
+	pci_disable_device(dev);
+	scsi_host_put(scsi_host);
+	pci_set_drvdata(dev, NULL);
+}
+
+static struct pci_device_id tmscsim_pci_tbl[] = {
+	{ PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974,
+		PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl);
+
+static struct pci_driver dc390_driver = {
+	.name           = "tmscsim",
+	.id_table       = tmscsim_pci_tbl,
+	.probe          = dc390_probe_one,
+	.remove         = __devexit_p(dc390_remove_one),
+};
+
+static int __init dc390_module_init(void)
+{
+	if (tmscsim[0] == -1 || tmscsim[0] > 15) {
+		tmscsim[0] = 7;
+		tmscsim[1] = 4;
+		tmscsim[2] = PARITY_CHK_ | TAG_QUEUEING_;
+		tmscsim[3] = MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION;
+		tmscsim[4] = 2;
+		tmscsim[5] = 10;
+		printk (KERN_INFO "DC390: Using safe settings.\n");
+	}
+
+	return pci_module_init(&dc390_driver);
+}
+
+static void __exit dc390_module_exit(void)
+{
+	pci_unregister_driver(&dc390_driver);
+}
+
+module_init(dc390_module_init);
+module_exit(dc390_module_exit);
+
+#ifndef MODULE
+static int __init dc390_setup (char *str)
+{	
+	int ints[8],i, im;
+
+	get_options(str, ARRAY_SIZE(ints), ints);
+	im = ints[0];
+
+	if (im > 6) {
+		printk (KERN_NOTICE "DC390: ignore extra params!\n");
+		im = 6;
+	}
+
+	for (i = 0; i < im; i++)
+		tmscsim[i] = ints[i+1];
+	/* dc390_checkparams (); */
+	return 1;
+}
+
+__setup("tmscsim=", dc390_setup);
+#endif
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
new file mode 100644
index 0000000..d449527
--- /dev/null
+++ b/drivers/scsi/tmscsim.h
@@ -0,0 +1,565 @@
+/***********************************************************************
+;*	File Name : TMSCSIM.H					       *
+;*		    TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter  *
+;*		    Device Driver				       *
+;***********************************************************************/
+/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */
+
+#ifndef _TMSCSIM_H
+#define _TMSCSIM_H
+
+#include <linux/types.h>
+#include <linux/config.h>
+
+#define SCSI_IRQ_NONE 255
+
+#define MAX_ADAPTER_NUM 	4
+#define MAX_SG_LIST_BUF 	16	/* Not used */
+#define MAX_SCSI_ID		8
+#define MAX_SRB_CNT		50	/* Max number of started commands */
+
+#define SEL_TIMEOUT		153	/* 250 ms selection timeout (@ 40 MHz) */
+
+#define pci_dma_lo32(a)			(a & 0xffffffff)
+
+typedef u8		UCHAR;	/*  8 bits */
+typedef u16		USHORT;	/* 16 bits */
+typedef u32		UINT;	/* 32 bits */
+typedef unsigned long	ULONG;	/* 32/64 bits */
+
+
+/*
+;-----------------------------------------------------------------------
+; SCSI Request Block
+;-----------------------------------------------------------------------
+*/
+struct dc390_srb
+{
+//u8		CmdBlock[12];
+
+struct dc390_srb	*pNextSRB;
+struct dc390_dcb	*pSRBDCB;
+struct scsi_cmnd	*pcmd;
+struct scatterlist	*pSegmentList;
+
+struct scatterlist Segmentx;	/* make a one entry of S/G list table */
+
+unsigned long	SGBusAddr;	/*;a segment starting address as seen by AM53C974A*/
+unsigned long	SGToBeXferLen;	/*; to be xfer length */
+unsigned long	TotalXferredLen;
+unsigned long	SavedTotXLen;
+unsigned long	Saved_Ptr;
+u32		SRBState;
+
+u8		SRBStatus;
+u8		SRBFlag;	/*; b0-AutoReqSense,b6-Read,b7-write */
+				/*; b4-settimeout,b5-Residual valid */
+u8		AdaptStatus;
+u8		TargetStatus;
+
+u8		ScsiPhase;
+s8		TagNumber;
+u8		SGIndex;
+u8		SGcount;
+
+u8		MsgCnt;
+u8		EndMessage;
+u8		SavedSGCount;			
+
+u8		MsgInBuf[6];
+u8		MsgOutBuf[6];
+
+//u8		IORBFlag;	/*;81h-Reset, 2-retry */
+};
+
+
+/*
+;-----------------------------------------------------------------------
+; Device Control Block
+;-----------------------------------------------------------------------
+*/
+struct dc390_dcb
+{
+struct dc390_dcb	*pNextDCB;
+struct dc390_acb	*pDCBACB;
+
+/* Queued SRBs */
+struct dc390_srb	*pGoingSRB;
+struct dc390_srb	*pGoingLast;
+struct dc390_srb	*pActiveSRB;
+u8		GoingSRBCnt;
+
+u32		TagMask;
+
+u8		TargetID;	/*; SCSI Target ID  (SCSI Only) */
+u8		TargetLUN;	/*; SCSI Log.  Unit (SCSI Only) */
+u8		DevMode;
+u8		DCBFlag;
+
+u8		CtrlR1;
+u8		CtrlR3;
+u8		CtrlR4;
+
+u8		SyncMode;	/*; 0:async mode */
+u8		NegoPeriod;	/*;for nego. */
+u8		SyncPeriod;	/*;for reg. */
+u8		SyncOffset;	/*;for reg. and nego.(low nibble) */
+};
+
+
+/*
+;-----------------------------------------------------------------------
+; Adapter Control Block
+;-----------------------------------------------------------------------
+*/
+struct dc390_acb
+{
+struct Scsi_Host *pScsiHost;
+u16		IOPortBase;
+u8		IRQLevel;
+u8		status;
+
+u8		SRBCount;
+u8		AdapterIndex;	/*; nth Adapter this driver */
+u8		DCBCnt;
+
+u8		TagMaxNum;
+u8		ACBFlag;
+u8		Gmode2;
+u8		scan_devices;
+
+struct dc390_dcb	*pLinkDCB;
+struct dc390_dcb	*pLastDCB;
+struct dc390_dcb	*pDCBRunRobin;
+
+struct dc390_dcb	*pActiveDCB;
+struct dc390_srb	*pFreeSRB;
+struct dc390_srb	*pTmpSRB;
+
+u8		msgin123[4];
+u8		Connected;
+u8		pad;
+
+#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
+spinlock_t	lock;
+#endif
+u8		sel_timeout;
+u8		glitch_cfg;
+
+u8		MsgLen;
+u8		Ignore_IRQ;	/* Not used */
+
+struct pci_dev	*pdev;
+
+unsigned long	Cmds;
+u32		SelLost;
+u32		SelConn;
+u32		CmdInQ;
+u32		CmdOutOfSRB;
+
+struct dc390_srb	TmpSRB;
+struct dc390_srb	SRB_array[MAX_SRB_CNT]; 	/* 50 SRBs */
+};
+
+
+/*;-----------------------------------------------------------------------*/
+
+
+#define BIT31	0x80000000
+#define BIT30	0x40000000
+#define BIT29	0x20000000
+#define BIT28	0x10000000
+#define BIT27	0x08000000
+#define BIT26	0x04000000
+#define BIT25	0x02000000
+#define BIT24	0x01000000
+#define BIT23	0x00800000
+#define BIT22	0x00400000
+#define BIT21	0x00200000
+#define BIT20	0x00100000
+#define BIT19	0x00080000
+#define BIT18	0x00040000
+#define BIT17	0x00020000
+#define BIT16	0x00010000
+#define BIT15	0x00008000
+#define BIT14	0x00004000
+#define BIT13	0x00002000
+#define BIT12	0x00001000
+#define BIT11	0x00000800
+#define BIT10	0x00000400
+#define BIT9	0x00000200
+#define BIT8	0x00000100
+#define BIT7	0x00000080
+#define BIT6	0x00000040
+#define BIT5	0x00000020
+#define BIT4	0x00000010
+#define BIT3	0x00000008
+#define BIT2	0x00000004
+#define BIT1	0x00000002
+#define BIT0	0x00000001
+
+/*;---UnitCtrlFlag */
+#define UNIT_ALLOCATED	BIT0
+#define UNIT_INFO_CHANGED BIT1
+#define FORMATING_MEDIA BIT2
+#define UNIT_RETRY	BIT3
+
+/*;---UnitFlags */
+#define DASD_SUPPORT	BIT0
+#define SCSI_SUPPORT	BIT1
+#define ASPI_SUPPORT	BIT2
+
+/*;----SRBState machine definition */
+#define SRB_FREE	0
+#define SRB_WAIT	BIT0
+#define SRB_READY	BIT1
+#define SRB_MSGOUT	BIT2	/*;arbitration+msg_out 1st byte*/
+#define SRB_MSGIN	BIT3
+#define SRB_MSGIN_MULTI BIT4
+#define SRB_COMMAND	BIT5
+#define SRB_START_	BIT6	/*;arbitration+msg_out+command_out*/
+#define SRB_DISCONNECT	BIT7
+#define SRB_DATA_XFER	BIT8
+#define SRB_XFERPAD	BIT9
+#define SRB_STATUS	BIT10
+#define SRB_COMPLETED	BIT11
+#define SRB_ABORT_SENT	BIT12
+#define DO_SYNC_NEGO	BIT13
+#define SRB_UNEXPECT_RESEL BIT14
+
+/*;---SRBstatus */
+#define SRB_OK		BIT0
+#define ABORTION	BIT1
+#define OVER_RUN	BIT2
+#define UNDER_RUN	BIT3
+#define PARITY_ERROR	BIT4
+#define SRB_ERROR	BIT5
+
+/*;---ACBFlag */
+#define RESET_DEV	BIT0
+#define RESET_DETECT	BIT1
+#define RESET_DONE	BIT2
+
+/*;---DCBFlag */
+#define ABORT_DEV_	BIT0
+
+/*;---SRBFlag */
+#define DATAOUT 	BIT7
+#define DATAIN		BIT6
+#define RESIDUAL_VALID	BIT5
+#define ENABLE_TIMER	BIT4
+#define RESET_DEV0	BIT2
+#define ABORT_DEV	BIT1
+#define AUTO_REQSENSE	BIT0
+
+/*;---Adapter status */
+#define H_STATUS_GOOD	 0
+#define H_SEL_TIMEOUT	 0x11
+#define H_OVER_UNDER_RUN 0x12
+#define H_UNEXP_BUS_FREE 0x13
+#define H_TARGET_PHASE_F 0x14
+#define H_INVALID_CCB_OP 0x16
+#define H_LINK_CCB_BAD	 0x17
+#define H_BAD_TARGET_DIR 0x18
+#define H_DUPLICATE_CCB  0x19
+#define H_BAD_CCB_OR_SG  0x1A
+#define H_ABORT 	 0x0FF
+
+/*; SCSI Status byte codes*/ 
+/* The values defined in include/scsi/scsi.h, to be shifted << 1 */
+
+#define SCSI_STAT_UNEXP_BUS_F	0xFD	/*;  Unexpect Bus Free */
+#define SCSI_STAT_BUS_RST_DETECT 0xFE	/*;  Scsi Bus Reset detected */
+#define SCSI_STAT_SEL_TIMEOUT	0xFF	/*;  Selection Time out */
+
+/* cmd->result */
+#define RES_TARGET		0x000000FF	/* Target State */
+#define RES_TARGET_LNX		STATUS_MASK	/* Only official ... */
+#define RES_ENDMSG		0x0000FF00	/* End Message */
+#define RES_DID			0x00FF0000	/* DID_ codes */
+#define RES_DRV			0xFF000000	/* DRIVER_ codes */
+
+#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
+#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt)<<1)
+
+#define SET_RES_TARGET(who, tgt) do { who &= ~RES_TARGET; who |= (int)(tgt); } while (0)
+#define SET_RES_TARGET_LNX(who, tgt) do { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } while (0)
+#define SET_RES_MSG(who, msg) do { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } while (0)
+#define SET_RES_DID(who, did) do { who &= ~RES_DID; who |= (int)(did) << 16; } while (0)
+#define SET_RES_DRV(who, drv) do { who &= ~RES_DRV; who |= (int)(drv) << 24; } while (0)
+
+/*;---Sync_Mode */
+#define SYNC_DISABLE	0
+#define SYNC_ENABLE	BIT0
+#define SYNC_NEGO_DONE	BIT1
+#define WIDE_ENABLE	BIT2	/* Not used ;-) */
+#define WIDE_NEGO_DONE	BIT3	/* Not used ;-) */
+#define EN_TAG_QUEUEING	BIT4
+#define EN_ATN_STOP	BIT5
+
+#define SYNC_NEGO_OFFSET 15
+
+/*;---SCSI bus phase*/
+#define SCSI_DATA_OUT	0
+#define SCSI_DATA_IN	1
+#define SCSI_COMMAND	2
+#define SCSI_STATUS_	3
+#define SCSI_NOP0	4
+#define SCSI_NOP1	5
+#define SCSI_MSG_OUT	6
+#define SCSI_MSG_IN	7
+
+/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */
+#define ABORT_TAG	0x0d
+
+/*
+ *	SISC query queue
+ */
+typedef struct {
+	dma_addr_t		saved_dma_handle;
+} dc390_cmd_scp_t;
+
+/*
+;==========================================================
+; EEPROM byte offset
+;==========================================================
+*/
+typedef  struct  _EEprom
+{
+u8	EE_MODE1;
+u8	EE_SPEED;
+u8	xx1;
+u8	xx2;
+} EEprom, *PEEprom;
+
+#define REAL_EE_ADAPT_SCSI_ID 64
+#define REAL_EE_MODE2	65
+#define REAL_EE_DELAY	66
+#define REAL_EE_TAG_CMD_NUM	67
+
+#define EE_ADAPT_SCSI_ID 32
+#define EE_MODE2	33
+#define EE_DELAY	34
+#define EE_TAG_CMD_NUM	35
+
+#define EE_LEN		40
+
+/*; EE_MODE1 bits definition*/
+#define PARITY_CHK_	BIT0
+#define SYNC_NEGO_	BIT1
+#define EN_DISCONNECT_	BIT2
+#define SEND_START_	BIT3
+#define TAG_QUEUEING_	BIT4
+
+/*; EE_MODE2 bits definition*/
+#define MORE2_DRV	BIT0
+#define GREATER_1G	BIT1
+#define RST_SCSI_BUS	BIT2
+#define ACTIVE_NEGATION BIT3
+#define NO_SEEK 	BIT4
+#define LUN_CHECK	BIT5
+
+#define ENABLE_CE	1
+#define DISABLE_CE	0
+#define EEPROM_READ	0x80
+
+/*
+;==========================================================
+;	AMD 53C974 Registers bit Definition
+;==========================================================
+*/
+/*
+;====================
+; SCSI Register
+;====================
+*/
+
+/*; Command Reg.(+0CH) (rw) */
+#define DMA_COMMAND		BIT7
+#define NOP_CMD 		0
+#define CLEAR_FIFO_CMD		1
+#define RST_DEVICE_CMD		2
+#define RST_SCSI_BUS_CMD	3
+
+#define INFO_XFER_CMD		0x10
+#define INITIATOR_CMD_CMPLTE	0x11
+#define MSG_ACCEPTED_CMD	0x12
+#define XFER_PAD_BYTE		0x18
+#define SET_ATN_CMD		0x1A
+#define RESET_ATN_CMD		0x1B
+
+#define SEL_WO_ATN		0x41	/* currently not used */
+#define SEL_W_ATN		0x42
+#define SEL_W_ATN_STOP		0x43
+#define SEL_W_ATN3		0x46
+#define EN_SEL_RESEL		0x44
+#define DIS_SEL_RESEL		0x45	/* currently not used */
+#define RESEL			0x40	/* " */
+#define RESEL_ATN3		0x47	/* " */
+
+#define DATA_XFER_CMD		INFO_XFER_CMD
+
+
+/*; SCSI Status Reg.(+10H) (r) */
+#define INTERRUPT		BIT7
+#define ILLEGAL_OP_ERR		BIT6
+#define PARITY_ERR		BIT5
+#define COUNT_2_ZERO		BIT4
+#define GROUP_CODE_VALID	BIT3
+#define SCSI_PHASE_MASK 	(BIT2+BIT1+BIT0) 
+/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
+
+/*; Interrupt Status Reg.(+14H) (r) */
+#define SCSI_RESET		BIT7
+#define INVALID_CMD		BIT6
+#define DISCONNECTED		BIT5
+#define SERVICE_REQUEST 	BIT4
+#define SUCCESSFUL_OP		BIT3
+#define RESELECTED		BIT2
+#define SEL_ATTENTION		BIT1
+#define SELECTED		BIT0
+
+/*; Internal State Reg.(+18H) (r) */
+#define SYNC_OFFSET_FLAG	BIT3
+#define INTRN_STATE_MASK	(BIT2+BIT1+BIT0)
+/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
+
+/*; Clock Factor Reg.(+24H) (w) */
+#define CLK_FREQ_40MHZ		0
+#define CLK_FREQ_35MHZ		(BIT2+BIT1+BIT0)
+#define CLK_FREQ_30MHZ		(BIT2+BIT1)
+#define CLK_FREQ_25MHZ		(BIT2+BIT0)
+#define CLK_FREQ_20MHZ		BIT2
+#define CLK_FREQ_15MHZ		(BIT1+BIT0)
+#define CLK_FREQ_10MHZ		BIT1
+
+/*; Control Reg. 1(+20H) (rw) */
+#define EXTENDED_TIMING 	BIT7
+#define DIS_INT_ON_SCSI_RST	BIT6
+#define PARITY_ERR_REPO 	BIT4
+#define SCSI_ID_ON_BUS		(BIT2+BIT1+BIT0) /* host adapter ID */
+
+/*; Control Reg. 2(+2CH) (rw) */
+#define EN_FEATURE		BIT6
+#define EN_SCSI2_CMD		BIT3
+
+/*; Control Reg. 3(+30H) (rw) */
+#define ID_MSG_CHECK		BIT7
+#define EN_QTAG_MSG		BIT6
+#define EN_GRP2_CMD		BIT5
+#define FAST_SCSI		BIT4	/* ;10MB/SEC */
+#define FAST_CLK		BIT3	/* ;25 - 40 MHZ */
+
+/*; Control Reg. 4(+34H) (rw) */
+#define EATER_12NS		0
+#define EATER_25NS		BIT7
+#define EATER_35NS		BIT6
+#define EATER_0NS		(BIT7+BIT6)
+#define REDUCED_POWER		BIT5
+#define CTRL4_RESERVED		BIT4	/* must be 1 acc. to AM53C974.c */
+#define NEGATE_REQACKDATA	BIT2
+#define NEGATE_REQACK		BIT3
+
+#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
+#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
+
+/*
+;====================
+; DMA Register
+;====================
+*/
+/*; DMA Command Reg.(+40H) (rw) */
+#define READ_DIRECTION		BIT7
+#define WRITE_DIRECTION 	0
+#define EN_DMA_INT		BIT6
+#define EN_PAGE_INT		BIT5	/* page transfer interrupt enable */
+#define MAP_TO_MDL		BIT4
+#define DIAGNOSTIC		BIT2
+#define DMA_IDLE_CMD		0
+#define DMA_BLAST_CMD		BIT0
+#define DMA_ABORT_CMD		BIT1
+#define DMA_START_CMD		(BIT1+BIT0)
+
+/*; DMA Status Reg.(+54H) (r) */
+#define PCI_MS_ABORT		BIT6
+#define BLAST_COMPLETE		BIT5
+#define SCSI_INTERRUPT		BIT4
+#define DMA_XFER_DONE		BIT3
+#define DMA_XFER_ABORT		BIT2
+#define DMA_XFER_ERROR		BIT1
+#define POWER_DOWN		BIT0
+
+/*; DMA SCSI Bus and Ctrl.(+70H) */
+#define EN_INT_ON_PCI_ABORT	BIT25
+#define WRT_ERASE_DMA_STAT	BIT24
+#define PW_DOWN_CTRL		BIT21
+#define SCSI_BUSY		BIT20
+#define SCLK			BIT19
+#define SCAM			BIT18
+#define SCSI_LINES		0x0003ffff
+
+/*
+;==========================================================
+; SCSI Chip register address offset
+;==========================================================
+;Registers are rw unless declared otherwise 
+*/
+#define CtcReg_Low	0x00	/* r	curr. transfer count */
+#define CtcReg_Mid	0x04	/* r */
+#define CtcReg_High	0x38	/* r */
+#define ScsiFifo	0x08
+#define ScsiCmd 	0x0C
+#define Scsi_Status	0x10	/* r */
+#define INT_Status	0x14	/* r */
+#define Sync_Period	0x18	/* w */
+#define Sync_Offset	0x1C	/* w */
+#define Clk_Factor	0x24	/* w */
+#define CtrlReg1	0x20	
+#define CtrlReg2	0x2C
+#define CtrlReg3	0x30
+#define CtrlReg4	0x34
+#define DMA_Cmd 	0x40
+#define DMA_XferCnt	0x44	/* rw	starting transfer count (32 bit) */
+#define DMA_XferAddr	0x48	/* rw	starting physical address (32 bit) */
+#define DMA_Wk_ByteCntr 0x4C	/* r	working byte counter */
+#define DMA_Wk_AddrCntr 0x50	/* r	working address counter */
+#define DMA_Status	0x54	/* r */
+#define DMA_MDL_Addr	0x58	/* rw	starting MDL address */
+#define DMA_Wk_MDL_Cntr 0x5C	/* r	working MDL counter */
+#define DMA_ScsiBusCtrl 0x70	/* rw	SCSI Bus, PCI/DMA Ctrl */
+
+#define StcReg_Low	CtcReg_Low	/* w	start transfer count */
+#define StcReg_Mid	CtcReg_Mid	/* w */
+#define StcReg_High	CtcReg_High	/* w */
+#define Scsi_Dest_ID	Scsi_Status	/* w */
+#define Scsi_TimeOut	INT_Status	/* w */
+#define Intern_State	Sync_Period	/* r */
+#define Current_Fifo	Sync_Offset	/* r	Curr. FIFO / int. state */
+
+
+#define DC390_read8(address)			\
+	(inb (pACB->IOPortBase + (address)))
+
+#define DC390_read8_(address, base)		\
+	(inb ((u16)(base) + (address)))
+
+#define DC390_read16(address)			\
+	(inw (pACB->IOPortBase + (address)))
+
+#define DC390_read32(address)			\
+	(inl (pACB->IOPortBase + (address)))
+
+#define DC390_write8(address,value)		\
+	outb ((value), pACB->IOPortBase + (address))
+
+#define DC390_write8_(address,value,base)	\
+	outb ((value), (u16)(base) + (address))
+
+#define DC390_write16(address,value)		\
+	outw ((value), pACB->IOPortBase + (address))
+
+#define DC390_write32(address,value)		\
+	outl ((value), pACB->IOPortBase + (address))
+
+
+#endif /* _TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
new file mode 100644
index 0000000..dca2154
--- /dev/null
+++ b/drivers/scsi/u14-34f.c
@@ -0,0 +1,1987 @@
+/*
+ *      u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
+ *
+ *      03 Jun 2003 Rev. 8.10 for linux-2.5.70
+ *        + Update for new IRQ API.
+ *        + Use "goto" when appropriate.
+ *        + Drop u14-34f.h.
+ *        + Update for new module_param API.
+ *        + Module parameters  can now be specified only in the
+ *          same format as the kernel boot options.
+ *
+ *             boot option    old module param 
+ *             -----------    ------------------
+ *             addr,...       io_port=addr,...
+ *             lc:[y|n]       linked_comm=[1|0]
+ *             mq:xx          max_queue_depth=xx
+ *             tm:[0|1|2]     tag_mode=[0|1|2]
+ *             et:[y|n]       ext_tran=[1|0]
+ *             of:[y|n]       have_old_firmware=[1|0]
+ *
+ *          A valid example using the new parameter format is:
+ *          modprobe u14-34f "u14-34f=0x340,0x330,lc:y,tm:0,mq:4"
+ *
+ *          which is equivalent to the old format:
+ *          modprobe u14-34f io_port=0x340,0x330 linked_comm=1 tag_mode=0 \
+ *                        max_queue_depth=4
+ *
+ *          With actual module code, u14-34f and u14_34f are equivalent
+ *          as module parameter names.
+ *
+ *      12 Feb 2003 Rev. 8.04 for linux 2.5.60
+ *        + Release irq before calling scsi_register.
+ *
+ *      12 Nov 2002 Rev. 8.02 for linux 2.5.47
+ *        + Release driver_lock before calling scsi_register.
+ *
+ *      11 Nov 2002 Rev. 8.01 for linux 2.5.47
+ *        + Fixed bios_param and scsicam_bios_param calling parameters.
+ *
+ *      28 Oct 2002 Rev. 8.00 for linux 2.5.44-ac4
+ *        + Use new tcq and adjust_queue_depth api.
+ *        + New command line option (tm:[0-2]) to choose the type of tags:
+ *          0 -> disable tagging ; 1 -> simple tags  ; 2 -> ordered tags.
+ *          Default is tm:0 (tagged commands disabled).
+ *          For compatibility the "tc:" option is an alias of the "tm:"
+ *          option; tc:n is equivalent to tm:0 and tc:y is equivalent to
+ *          tm:1.
+ *
+ *      10 Oct 2002 Rev. 7.70 for linux 2.5.42
+ *        + Foreport from revision 6.70.
+ *
+ *      25 Jun 2002 Rev. 6.70 for linux 2.4.19
+ *        + Fixed endian-ness problem due to bitfields.
+ *
+ *      21 Feb 2002 Rev. 6.52 for linux 2.4.18
+ *        + Backport from rev. 7.22 (use io_request_lock).
+ *
+ *      20 Feb 2002 Rev. 7.22 for linux 2.5.5
+ *        + Remove any reference to virt_to_bus().
+ *        + Fix pio hang while detecting multiple HBAs.
+ *
+ *      01 Jan 2002 Rev. 7.20 for linux 2.5.1
+ *        + Use the dynamic DMA mapping API.
+ *
+ *      19 Dec 2001 Rev. 7.02 for linux 2.5.1
+ *        + Use SCpnt->sc_data_direction if set.
+ *        + Use sglist.page instead of sglist.address.
+ *
+ *      11 Dec 2001 Rev. 7.00 for linux 2.5.1
+ *        + Use host->host_lock instead of io_request_lock.
+ *
+ *       1 May 2001 Rev. 6.05 for linux 2.4.4
+ *        + Fix data transfer direction for opcode SEND_CUE_SHEET (0x5d)
+ *
+ *      25 Jan 2001 Rev. 6.03 for linux 2.4.0
+ *        + "check_region" call replaced by "request_region".
+ *
+ *      22 Nov 2000 Rev. 6.02 for linux 2.4.0-test11
+ *        + Removed old scsi error handling support.
+ *        + The obsolete boot option flag eh:n is silently ignored.
+ *        + Removed error messages while a disk drive is powered up at
+ *          boot time.
+ *        + Improved boot messages: all tagged capable device are
+ *          indicated as "tagged".
+ *
+ *      16 Sep 1999 Rev. 5.11 for linux 2.2.12 and 2.3.18
+ *        + Updated to the new __setup interface for boot command line options.
+ *        + When loaded as a module, accepts the new parameter boot_options
+ *          which value is a string with the same format of the kernel boot
+ *          command line options. A valid example is:
+ *          modprobe u14-34f 'boot_options="0x230,0x340,lc:y,mq:4"'
+ *
+ *      22 Jul 1999 Rev. 5.00 for linux 2.2.10 and 2.3.11
+ *        + Removed pre-2.2 source code compatibility.
+ *
+ *      26 Jul 1998 Rev. 4.33 for linux 2.0.35 and 2.1.111
+ *          Added command line option (et:[y|n]) to use the existing
+ *          translation (returned by scsicam_bios_param) as disk geometry.
+ *          The default is et:n, which uses the disk geometry jumpered
+ *          on the board.
+ *          The default value et:n is compatible with all previous revisions
+ *          of this driver.
+ *
+ *      28 May 1998 Rev. 4.32 for linux 2.0.33 and 2.1.104
+ *          Increased busy timeout from 10 msec. to 200 msec. while
+ *          processing interrupts.
+ *
+ *      18 May 1998 Rev. 4.31 for linux 2.0.33 and 2.1.102
+ *          Improved abort handling during the eh recovery process.
+ *
+ *      13 May 1998 Rev. 4.30 for linux 2.0.33 and 2.1.101
+ *          The driver is now fully SMP safe, including the
+ *          abort and reset routines.
+ *          Added command line options (eh:[y|n]) to choose between
+ *          new_eh_code and the old scsi code.
+ *          If linux version >= 2.1.101 the default is eh:y, while the eh
+ *          option is ignored for previous releases and the old scsi code
+ *          is used.
+ *
+ *      18 Apr 1998 Rev. 4.20 for linux 2.0.33 and 2.1.97
+ *          Reworked interrupt handler.
+ *
+ *      11 Apr 1998 rev. 4.05 for linux 2.0.33 and 2.1.95
+ *          Major reliability improvement: when a batch with overlapping
+ *          requests is detected, requests are queued one at a time
+ *          eliminating any possible board or drive reordering.
+ *
+ *      10 Apr 1998 rev. 4.04 for linux 2.0.33 and 2.1.95
+ *          Improved SMP support (if linux version >= 2.1.95).
+ *
+ *       9 Apr 1998 rev. 4.03 for linux 2.0.33 and 2.1.94
+ *          Performance improvement: when sequential i/o is detected,
+ *          always use direct sort instead of reverse sort.
+ *
+ *       4 Apr 1998 rev. 4.02 for linux 2.0.33 and 2.1.92
+ *          io_port is now unsigned long.
+ *
+ *      17 Mar 1998 rev. 4.01 for linux 2.0.33 and 2.1.88
+ *          Use new scsi error handling code (if linux version >= 2.1.88).
+ *          Use new interrupt code.
+ *
+ *      12 Sep 1997 rev. 3.11 for linux 2.0.30 and 2.1.55
+ *          Use of udelay inside the wait loops to avoid timeout
+ *          problems with fast cpus.
+ *          Removed check about useless calls to the interrupt service
+ *          routine (reported on SMP systems only).
+ *          At initialization time "sorted/unsorted" is displayed instead
+ *          of "linked/unlinked" to reinforce the fact that "linking" is
+ *          nothing but "elevator sorting" in the actual implementation.
+ *
+ *      17 May 1997 rev. 3.10 for linux 2.0.30 and 2.1.38
+ *          Use of serial_number_at_timeout in abort and reset processing.
+ *          Use of the __initfunc and __initdata macro in setup code.
+ *          Minor cleanups in the list_statistics code.
+ *
+ *      24 Feb 1997 rev. 3.00 for linux 2.0.29 and 2.1.26
+ *          When loading as a module, parameter passing is now supported
+ *          both in 2.0 and in 2.1 style.
+ *          Fixed data transfer direction for some SCSI opcodes.
+ *          Immediate acknowledge to request sense commands.
+ *          Linked commands to each disk device are now reordered by elevator
+ *          sorting. Rare cases in which reordering of write requests could
+ *          cause wrong results are managed.
+ *
+ *      18 Jan 1997 rev. 2.60 for linux 2.1.21 and 2.0.28
+ *          Added command line options to enable/disable linked commands
+ *          (lc:[y|n]), old firmware support (of:[y|n]) and to set the max
+ *          queue depth (mq:xx). Default is "u14-34f=lc:n,of:n,mq:8".
+ *          Improved command linking.
+ *
+ *       8 Jan 1997 rev. 2.50 for linux 2.1.20 and 2.0.27
+ *          Added linked command support.
+ *
+ *       3 Dec 1996 rev. 2.40 for linux 2.1.14 and 2.0.27
+ *          Added queue depth adjustment.
+ *
+ *      22 Nov 1996 rev. 2.30 for linux 2.1.12 and 2.0.26
+ *          The list of i/o ports to be probed can be overwritten by the
+ *          "u14-34f=port0,port1,...." boot command line option.
+ *          Scatter/gather lists are now allocated by a number of kmalloc
+ *          calls, in order to avoid the previous size limit of 64Kb.
+ *
+ *      16 Nov 1996 rev. 2.20 for linux 2.1.10 and 2.0.25
+ *          Added multichannel support.
+ *
+ *      27 Sep 1996 rev. 2.12 for linux 2.1.0
+ *          Portability cleanups (virtual/bus addressing, little/big endian
+ *          support).
+ *
+ *      09 Jul 1996 rev. 2.11 for linux 2.0.4
+ *          "Data over/under-run" no longer implies a redo on all targets.
+ *          Number of internal retries is now limited.
+ *
+ *      16 Apr 1996 rev. 2.10 for linux 1.3.90
+ *          New argument "reset_flags" to the reset routine.
+ *
+ *      21 Jul 1995 rev. 2.02 for linux 1.3.11
+ *          Fixed Data Transfer Direction for some SCSI commands.
+ *
+ *      13 Jun 1995 rev. 2.01 for linux 1.2.10
+ *          HAVE_OLD_UX4F_FIRMWARE should be defined for U34F boards when
+ *          the firmware prom is not the latest one (28008-006).
+ *
+ *      11 Mar 1995 rev. 2.00 for linux 1.2.0
+ *          Fixed a bug which prevented media change detection for removable
+ *          disk drives.
+ *
+ *      23 Feb 1995 rev. 1.18 for linux 1.1.94
+ *          Added a check for scsi_register returning NULL.
+ *
+ *      11 Feb 1995 rev. 1.17 for linux 1.1.91
+ *          U14F qualified to run with 32 sglists.
+ *          Now DEBUG_RESET is disabled by default.
+ *
+ *       9 Feb 1995 rev. 1.16 for linux 1.1.90
+ *          Use host->wish_block instead of host->block.
+ *
+ *       8 Feb 1995 rev. 1.15 for linux 1.1.89
+ *          Cleared target_time_out counter while performing a reset.
+ *
+ *      28 Jan 1995 rev. 1.14 for linux 1.1.86
+ *          Added module support.
+ *          Log and do a retry when a disk drive returns a target status
+ *          different from zero on a recovered error.
+ *          Auto detects if U14F boards have an old firmware revision.
+ *          Max number of scatter/gather lists set to 16 for all boards
+ *          (most installation run fine using 33 sglists, while other
+ *          has problems when using more than 16).
+ *
+ *      16 Jan 1995 rev. 1.13 for linux 1.1.81
+ *          Display a message if check_region detects a port address
+ *          already in use.
+ *
+ *      15 Dec 1994 rev. 1.12 for linux 1.1.74
+ *          The host->block flag is set for all the detected ISA boards.
+ *
+ *      30 Nov 1994 rev. 1.11 for linux 1.1.68
+ *          Redo i/o on target status CHECK_CONDITION for TYPE_DISK only.
+ *          Added optional support for using a single board at a time.
+ *
+ *      14 Nov 1994 rev. 1.10 for linux 1.1.63
+ *
+ *      28 Oct 1994 rev. 1.09 for linux 1.1.58  Final BETA release.
+ *      16 Jul 1994 rev. 1.00 for linux 1.1.29  Initial ALPHA release.
+ *
+ *          This driver is a total replacement of the original UltraStor
+ *          scsi driver, but it supports ONLY the 14F and 34F boards.
+ *          It can be configured in the same kernel in which the original
+ *          ultrastor driver is configured to allow the original U24F
+ *          support.
+ *
+ *          Multiple U14F and/or U34F host adapters are supported.
+ *
+ *  Copyright (C) 1994-2003 Dario Ballabio (ballabio_dario@emc.com)
+ *
+ *  Alternate email: dario.ballabio@inwind.it, dario.ballabio@tiscalinet.it
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that redistributions of source
+ *  code retain the above copyright notice and this comment without
+ *  modification.
+ *
+ *      WARNING: if your 14/34F board has an old firmware revision (see below)
+ *               you must change "#undef" into "#define" in the following
+ *               statement.
+ */
+#undef HAVE_OLD_UX4F_FIRMWARE
+/*
+ *  The UltraStor 14F, 24F, and 34F are a family of intelligent, high
+ *  performance SCSI-2 host adapters.
+ *  Here is the scoop on the various models:
+ *
+ *  14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
+ *  24F - EISA Bus Master HA with floppy support and WD1003 emulation.
+ *  34F - VESA Local-Bus Bus Master HA (no WD1003 emulation).
+ *
+ *  This code has been tested with up to two U14F boards, using both
+ *  firmware 28004-005/38004-004 (BIOS rev. 2.00) and the latest firmware
+ *  28004-006/38004-005 (BIOS rev. 2.01).
+ *
+ *  The latest firmware is required in order to get reliable operations when
+ *  clustering is enabled. ENABLE_CLUSTERING provides a performance increase
+ *  up to 50% on sequential access.
+ *
+ *  Since the Scsi_Host_Template structure is shared among all 14F and 34F,
+ *  the last setting of use_clustering is in effect for all of these boards.
+ *
+ *  Here a sample configuration using two U14F boards:
+ *
+ U14F0: ISA 0x330, BIOS 0xc8000, IRQ 11, DMA 5, SG 32, MB 16, of:n, lc:y, mq:8.
+ U14F1: ISA 0x340, BIOS 0x00000, IRQ 10, DMA 6, SG 32, MB 16, of:n, lc:y, mq:8.
+ *
+ *  The boot controller must have its BIOS enabled, while other boards can
+ *  have their BIOS disabled, or enabled to an higher address.
+ *  Boards are named Ux4F0, Ux4F1..., according to the port address order in
+ *  the io_port[] array.
+ *
+ *  The following facts are based on real testing results (not on
+ *  documentation) on the above U14F board.
+ *
+ *  - The U14F board should be jumpered for bus on time less or equal to 7
+ *    microseconds, while the default is 11 microseconds. This is order to
+ *    get acceptable performance while using floppy drive and hard disk
+ *    together. The jumpering for 7 microseconds is: JP13 pin 15-16,
+ *    JP14 pin 7-8 and pin 9-10.
+ *    The reduction has a little impact on scsi performance.
+ *
+ *  - If scsi bus length exceeds 3m., the scsi bus speed needs to be reduced
+ *    from 10Mhz to 5Mhz (do this by inserting a jumper on JP13 pin 7-8).
+ *
+ *  - If U14F on board firmware is older than 28004-006/38004-005,
+ *    the U14F board is unable to provide reliable operations if the scsi
+ *    request length exceeds 16Kbyte. When this length is exceeded the
+ *    behavior is:
+ *    - adapter_status equal 0x96 or 0xa3 or 0x93 or 0x94;
+ *    - adapter_status equal 0 and target_status equal 2 on for all targets
+ *      in the next operation following the reset.
+ *    This sequence takes a long time (>3 seconds), so in the meantime
+ *    the SD_TIMEOUT in sd.c could expire giving rise to scsi aborts
+ *    (SD_TIMEOUT has been increased from 3 to 6 seconds in 1.1.31).
+ *    Because of this I had to DISABLE_CLUSTERING and to work around the
+ *    bus reset in the interrupt service routine, returning DID_BUS_BUSY
+ *    so that the operations are retried without complains from the scsi.c
+ *    code.
+ *    Any reset of the scsi bus is going to kill tape operations, since
+ *    no retry is allowed for tapes. Bus resets are more likely when the
+ *    scsi bus is under heavy load.
+ *    Requests using scatter/gather have a maximum length of 16 x 1024 bytes
+ *    when DISABLE_CLUSTERING is in effect, but unscattered requests could be
+ *    larger than 16Kbyte.
+ *
+ *    The new firmware has fixed all the above problems.
+ *
+ *  For U34F boards the latest bios prom is 38008-002 (BIOS rev. 2.01),
+ *  the latest firmware prom is 28008-006. Older firmware 28008-005 has
+ *  problems when using more than 16 scatter/gather lists.
+ *
+ *  The list of i/o ports to be probed can be totally replaced by the
+ *  boot command line option: "u14-34f=port0,port1,port2,...", where the
+ *  port0, port1... arguments are ISA/VESA addresses to be probed.
+ *  For example using "u14-34f=0x230,0x340", the driver probes only the two
+ *  addresses 0x230 and 0x340 in this order; "u14-34f=0" totally disables
+ *  this driver.
+ *
+ *  After the optional list of detection probes, other possible command line
+ *  options are:
+ *
+ *  et:y  use disk geometry returned by scsicam_bios_param;
+ *  et:n  use disk geometry jumpered on the board;
+ *  lc:y  enables linked commands;
+ *  lc:n  disables linked commands;
+ *  tm:0  disables tagged commands (same as tc:n);
+ *  tm:1  use simple queue tags (same as tc:y);
+ *  tm:2  use ordered queue tags (same as tc:2);
+ *  of:y  enables old firmware support;
+ *  of:n  disables old firmware support;
+ *  mq:xx set the max queue depth to the value xx (2 <= xx <= 8).
+ *
+ *  The default value is: "u14-34f=lc:n,of:n,mq:8,tm:0,et:n".
+ *  An example using the list of detection probes could be:
+ *  "u14-34f=0x230,0x340,lc:y,tm:2,of:n,mq:4,et:n".
+ *
+ *  When loading as a module, parameters can be specified as well.
+ *  The above example would be (use 1 in place of y and 0 in place of n):
+ *
+ *  modprobe u14-34f io_port=0x230,0x340 linked_comm=1 have_old_firmware=0 \
+ *                max_queue_depth=4 ext_tran=0 tag_mode=2
+ *
+ *  ----------------------------------------------------------------------------
+ *  In this implementation, linked commands are designed to work with any DISK
+ *  or CD-ROM, since this linking has only the intent of clustering (time-wise)
+ *  and reordering by elevator sorting commands directed to each device,
+ *  without any relation with the actual SCSI protocol between the controller
+ *  and the device.
+ *  If Q is the queue depth reported at boot time for each device (also named
+ *  cmds/lun) and Q > 2, whenever there is already an active command to the
+ *  device all other commands to the same device  (up to Q-1) are kept waiting
+ *  in the elevator sorting queue. When the active command completes, the
+ *  commands in this queue are sorted by sector address. The sort is chosen
+ *  between increasing or decreasing by minimizing the seek distance between
+ *  the sector of the commands just completed and the sector of the first
+ *  command in the list to be sorted.
+ *  Trivial math assures that the unsorted average seek distance when doing
+ *  random seeks over S sectors is S/3.
+ *  When (Q-1) requests are uniformly distributed over S sectors, the average
+ *  distance between two adjacent requests is S/((Q-1) + 1), so the sorted
+ *  average seek distance for (Q-1) random requests over S sectors is S/Q.
+ *  The elevator sorting hence divides the seek distance by a factor Q/3.
+ *  The above pure geometric remarks are valid in all cases and the
+ *  driver effectively reduces the seek distance by the predicted factor
+ *  when there are Q concurrent read i/o operations on the device, but this
+ *  does not necessarily results in a noticeable performance improvement:
+ *  your mileage may vary....
+ *
+ *  Note: command reordering inside a batch of queued commands could cause
+ *        wrong results only if there is at least one write request and the
+ *        intersection (sector-wise) of all requests is not empty.
+ *        When the driver detects a batch including overlapping requests
+ *        (a really rare event) strict serial (pid) order is enforced.
+ *  ----------------------------------------------------------------------------
+ *
+ *  The boards are named Ux4F0, Ux4F1,... according to the detection order.
+ *
+ *  In order to support multiple ISA boards in a reliable way,
+ *  the driver sets host->wish_block = TRUE for all ISA boards.
+ */
+
+#include <linux/config.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/stat.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/ctype.h>
+#include <linux/spinlock.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_tcq.h>
+#include <scsi/scsicam.h>
+
+static int u14_34f_detect(struct scsi_host_template *);
+static int u14_34f_release(struct Scsi_Host *);
+static int u14_34f_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *));
+static int u14_34f_eh_abort(struct scsi_cmnd *);
+static int u14_34f_eh_host_reset(struct scsi_cmnd *);
+static int u14_34f_bios_param(struct scsi_device *, struct block_device *,
+                              sector_t, int *);
+static int u14_34f_slave_configure(struct scsi_device *);
+
+static struct scsi_host_template driver_template = {
+                .name                    = "UltraStor 14F/34F rev. 8.10.00 ",
+                .detect                  = u14_34f_detect,
+                .release                 = u14_34f_release,
+                .queuecommand            = u14_34f_queuecommand,
+                .eh_abort_handler        = u14_34f_eh_abort,
+                .eh_device_reset_handler = NULL,
+                .eh_bus_reset_handler    = NULL,
+                .eh_host_reset_handler   = u14_34f_eh_host_reset,
+                .bios_param              = u14_34f_bios_param,
+                .slave_configure         = u14_34f_slave_configure,
+                .this_id                 = 7,
+                .unchecked_isa_dma       = 1,
+                .use_clustering          = ENABLE_CLUSTERING
+                };
+
+#if !defined(__BIG_ENDIAN_BITFIELD) && !defined(__LITTLE_ENDIAN_BITFIELD)
+#error "Adjust your <asm/byteorder.h> defines"
+#endif
+
+/* Values for the PRODUCT_ID ports for the 14/34F */
+#define PRODUCT_ID1  0x56
+#define PRODUCT_ID2  0x40        /* NOTE: Only upper nibble is used */
+
+/* Subversion values */
+#define ISA  0
+#define ESA 1
+
+#define OP_HOST_ADAPTER   0x1
+#define OP_SCSI           0x2
+#define OP_RESET          0x4
+#define DTD_SCSI          0x0
+#define DTD_IN            0x1
+#define DTD_OUT           0x2
+#define DTD_NONE          0x3
+#define HA_CMD_INQUIRY    0x1
+#define HA_CMD_SELF_DIAG  0x2
+#define HA_CMD_READ_BUFF  0x3
+#define HA_CMD_WRITE_BUFF 0x4
+
+#undef  DEBUG_LINKED_COMMANDS
+#undef  DEBUG_DETECT
+#undef  DEBUG_INTERRUPT
+#undef  DEBUG_RESET
+#undef  DEBUG_GENERATE_ERRORS
+#undef  DEBUG_GENERATE_ABORTS
+#undef  DEBUG_GEOMETRY
+
+#define MAX_ISA 3
+#define MAX_VESA 1
+#define MAX_EISA 0
+#define MAX_PCI 0
+#define MAX_BOARDS (MAX_ISA + MAX_VESA + MAX_EISA + MAX_PCI)
+#define MAX_CHANNEL 1
+#define MAX_LUN 8
+#define MAX_TARGET 8
+#define MAX_MAILBOXES 16
+#define MAX_SGLIST 32
+#define MAX_SAFE_SGLIST 16
+#define MAX_INTERNAL_RETRIES 64
+#define MAX_CMD_PER_LUN 2
+#define MAX_TAGGED_CMD_PER_LUN (MAX_MAILBOXES - MAX_CMD_PER_LUN)
+
+#define SKIP ULONG_MAX
+#define FALSE 0
+#define TRUE 1
+#define FREE 0
+#define IN_USE   1
+#define LOCKED   2
+#define IN_RESET 3
+#define IGNORE   4
+#define READY    5
+#define ABORTING 6
+#define NO_DMA  0xff
+#define MAXLOOP  10000
+#define TAG_DISABLED 0
+#define TAG_SIMPLE   1
+#define TAG_ORDERED  2
+
+#define REG_LCL_MASK      0
+#define REG_LCL_INTR      1
+#define REG_SYS_MASK      2
+#define REG_SYS_INTR      3
+#define REG_PRODUCT_ID1   4
+#define REG_PRODUCT_ID2   5
+#define REG_CONFIG1       6
+#define REG_CONFIG2       7
+#define REG_OGM           8
+#define REG_ICM           12
+#define REGION_SIZE       13UL
+#define BSY_ASSERTED      0x01
+#define IRQ_ASSERTED      0x01
+#define CMD_RESET         0xc0
+#define CMD_OGM_INTR      0x01
+#define CMD_CLR_INTR      0x01
+#define CMD_ENA_INTR      0x81
+#define ASOK              0x00
+#define ASST              0x91
+
+#define YESNO(a) ((a) ? 'y' : 'n')
+#define TLDEV(type) ((type) == TYPE_DISK || (type) == TYPE_ROM)
+
+#define PACKED          __attribute__((packed))
+
+struct sg_list {
+   unsigned int address;                /* Segment Address */
+   unsigned int num_bytes;              /* Segment Length */
+   };
+
+/* MailBox SCSI Command Packet */
+struct mscp {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+   unsigned char sg:1, ca:1, dcn:1, xdir:2, opcode:3;
+   unsigned char lun: 3, channel:2, target:3;
+#else
+   unsigned char opcode: 3,             /* type of command */
+                 xdir: 2,               /* data transfer direction */
+                 dcn: 1,                /* disable disconnect */
+                 ca: 1,                 /* use cache (if available) */
+                 sg: 1;                 /* scatter/gather operation */
+   unsigned char target: 3,             /* SCSI target id */
+                 channel: 2,            /* SCSI channel number */
+                 lun: 3;                /* SCSI logical unit number */
+#endif
+
+   unsigned int data_address PACKED;    /* transfer data pointer */
+   unsigned int data_len PACKED;        /* length in bytes */
+   unsigned int link_address PACKED;    /* for linking command chains */
+   unsigned char clink_id;              /* identifies command in chain */
+   unsigned char use_sg;                /* (if sg is set) 8 bytes per list */
+   unsigned char sense_len;
+   unsigned char cdb_len;               /* 6, 10, or 12 */
+   unsigned char cdb[12];               /* SCSI Command Descriptor Block */
+   unsigned char adapter_status;        /* non-zero indicates HA error */
+   unsigned char target_status;         /* non-zero indicates target error */
+   unsigned int sense_addr PACKED;
+
+   /* Additional fields begin here. */
+   struct scsi_cmnd *SCpnt;
+   unsigned int cpp_index;              /* cp index */
+
+   /* All the cp structure is zero filled by queuecommand except the
+      following CP_TAIL_SIZE bytes, initialized by detect */
+   dma_addr_t cp_dma_addr; /* dma handle for this cp structure */
+   struct sg_list *sglist; /* pointer to the allocated SG list */
+   };
+
+#define CP_TAIL_SIZE (sizeof(struct sglist *) + sizeof(dma_addr_t))
+
+struct hostdata {
+   struct mscp cp[MAX_MAILBOXES];       /* Mailboxes for this board */
+   unsigned int cp_stat[MAX_MAILBOXES]; /* FREE, IN_USE, LOCKED, IN_RESET */
+   unsigned int last_cp_used;           /* Index of last mailbox used */
+   unsigned int iocount;                /* Total i/o done for this board */
+   int board_number;                    /* Number of this board */
+   char board_name[16];                 /* Name of this board */
+   int in_reset;                        /* True if board is doing a reset */
+   int target_to[MAX_TARGET][MAX_CHANNEL]; /* N. of timeout errors on target */
+   int target_redo[MAX_TARGET][MAX_CHANNEL]; /* If TRUE redo i/o on target */
+   unsigned int retries;                /* Number of internal retries */
+   unsigned long last_retried_pid;      /* Pid of last retried command */
+   unsigned char subversion;            /* Bus type, either ISA or ESA */
+   struct pci_dev *pdev;                /* Always NULL */
+   unsigned char heads;
+   unsigned char sectors;
+   char board_id[256];                  /* data from INQUIRY on this board */
+   };
+
+static struct Scsi_Host *sh[MAX_BOARDS + 1];
+static const char *driver_name = "Ux4F";
+static char sha[MAX_BOARDS];
+static DEFINE_SPINLOCK(driver_lock);
+
+/* Initialize num_boards so that ihdlr can work while detect is in progress */
+static unsigned int num_boards = MAX_BOARDS;
+
+static unsigned long io_port[] = {
+
+   /* Space for MAX_INT_PARAM ports usable while loading as a module */
+   SKIP,    SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,   SKIP,
+   SKIP,    SKIP,
+
+   /* Possible ISA/VESA ports */
+   0x330, 0x340, 0x230, 0x240, 0x210, 0x130, 0x140,
+
+   /* End of list */
+   0x0
+   };
+
+#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
+#define BN(board) (HD(board)->board_name)
+
+/* Device is Little Endian */
+#define H2DEV(x) cpu_to_le32(x)
+#define DEV2H(x) le32_to_cpu(x)
+
+static irqreturn_t do_interrupt_handler(int, void *, struct pt_regs *);
+static void flush_dev(struct scsi_device *, unsigned long, unsigned int, unsigned int);
+static int do_trace = FALSE;
+static int setup_done = FALSE;
+static int link_statistics;
+static int ext_tran = FALSE;
+
+#if defined(HAVE_OLD_UX4F_FIRMWARE)
+static int have_old_firmware = TRUE;
+#else
+static int have_old_firmware = FALSE;
+#endif
+
+#if defined(CONFIG_SCSI_U14_34F_TAGGED_QUEUE)
+static int tag_mode = TAG_SIMPLE;
+#else
+static int tag_mode = TAG_DISABLED;
+#endif
+
+#if defined(CONFIG_SCSI_U14_34F_LINKED_COMMANDS)
+static int linked_comm = TRUE;
+#else
+static int linked_comm = FALSE;
+#endif
+
+#if defined(CONFIG_SCSI_U14_34F_MAX_TAGS)
+static int max_queue_depth = CONFIG_SCSI_U14_34F_MAX_TAGS;
+#else
+static int max_queue_depth = MAX_CMD_PER_LUN;
+#endif
+
+#define MAX_INT_PARAM 10
+#define MAX_BOOT_OPTIONS_SIZE 256
+static char boot_options[MAX_BOOT_OPTIONS_SIZE];
+
+#if defined(MODULE)
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+module_param_string(u14_34f, boot_options, MAX_BOOT_OPTIONS_SIZE, 0);
+MODULE_PARM_DESC(u14_34f, " equivalent to the \"u14-34f=...\" kernel boot " \
+"option." \
+"      Example: modprobe u14-34f \"u14_34f=0x340,0x330,lc:y,tm:0,mq:4\"");
+MODULE_AUTHOR("Dario Ballabio");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("UltraStor 14F/34F SCSI Driver");
+
+#endif
+
+static int u14_34f_slave_configure(struct scsi_device *dev) {
+   int j, tqd, utqd;
+   char *tag_suffix, *link_suffix;
+   struct Scsi_Host *host = dev->host;
+
+   j = ((struct hostdata *) host->hostdata)->board_number;
+
+   utqd = MAX_CMD_PER_LUN;
+   tqd = max_queue_depth;
+
+   if (TLDEV(dev->type) && dev->tagged_supported)
+
+      if (tag_mode == TAG_SIMPLE) {
+         scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
+         tag_suffix = ", simple tags";
+         }
+      else if (tag_mode == TAG_ORDERED) {
+         scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);
+         tag_suffix = ", ordered tags";
+         }
+      else {
+         scsi_adjust_queue_depth(dev, 0, tqd);
+         tag_suffix = ", no tags";
+         }
+
+   else if (TLDEV(dev->type) && linked_comm) {
+      scsi_adjust_queue_depth(dev, 0, tqd);
+      tag_suffix = ", untagged";
+      }
+
+   else {
+      scsi_adjust_queue_depth(dev, 0, utqd);
+      tag_suffix = "";
+      }
+
+   if (TLDEV(dev->type) && linked_comm && dev->queue_depth > 2)
+      link_suffix = ", sorted";
+   else if (TLDEV(dev->type))
+      link_suffix = ", unsorted";
+   else
+      link_suffix = "";
+
+   printk("%s: scsi%d, channel %d, id %d, lun %d, cmds/lun %d%s%s.\n",
+          BN(j), host->host_no, dev->channel, dev->id, dev->lun,
+          dev->queue_depth, link_suffix, tag_suffix);
+
+   return FALSE;
+}
+
+static int wait_on_busy(unsigned long iobase, unsigned int loop) {
+
+   while (inb(iobase + REG_LCL_INTR) & BSY_ASSERTED) {
+      udelay(1L);
+      if (--loop == 0) return TRUE;
+      }
+
+   return FALSE;
+}
+
+static int board_inquiry(unsigned int j) {
+   struct mscp *cpp;
+   dma_addr_t id_dma_addr;
+   unsigned int time, limit = 0;
+
+   id_dma_addr = pci_map_single(HD(j)->pdev, HD(j)->board_id,
+                    sizeof(HD(j)->board_id), PCI_DMA_BIDIRECTIONAL);
+   cpp = &HD(j)->cp[0];
+   cpp->cp_dma_addr = pci_map_single(HD(j)->pdev, cpp, sizeof(struct mscp),
+                                     PCI_DMA_BIDIRECTIONAL);
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
+   cpp->opcode = OP_HOST_ADAPTER;
+   cpp->xdir = DTD_IN;
+   cpp->data_address = H2DEV(id_dma_addr);
+   cpp->data_len = H2DEV(sizeof(HD(j)->board_id));
+   cpp->cdb_len = 6;
+   cpp->cdb[0] = HA_CMD_INQUIRY;
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: board_inquiry, adapter busy.\n", BN(j));
+      return TRUE;
+      }
+
+   HD(j)->cp_stat[0] = IGNORE;
+
+   /* Clear the interrupt indication */
+   outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+
+   /* Store pointer in OGM address bytes */
+   outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
+
+   /* Issue OGM interrupt */
+   outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
+
+   spin_unlock_irq(&driver_lock);
+   time = jiffies;
+   while ((jiffies - time) < HZ && limit++ < 20000) udelay(100L);
+   spin_lock_irq(&driver_lock);
+
+   if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
+      HD(j)->cp_stat[0] = FREE;
+      printk("%s: board_inquiry, err 0x%x.\n", BN(j), cpp->adapter_status);
+      return TRUE;
+      }
+
+   pci_unmap_single(HD(j)->pdev, cpp->cp_dma_addr, sizeof(struct mscp),
+                    PCI_DMA_BIDIRECTIONAL);
+   pci_unmap_single(HD(j)->pdev, id_dma_addr, sizeof(HD(j)->board_id),
+                    PCI_DMA_BIDIRECTIONAL);
+   return FALSE;
+}
+
+static int port_detect \
+      (unsigned long port_base, unsigned int j, struct scsi_host_template *tpnt) {
+   unsigned char irq, dma_channel, subversion, i;
+   unsigned char in_byte;
+   char *bus_type, dma_name[16];
+
+   /* Allowed BIOS base addresses (NULL indicates reserved) */
+   unsigned long bios_segment_table[8] = {
+      0,
+      0xc4000, 0xc8000, 0xcc000, 0xd0000,
+      0xd4000, 0xd8000, 0xdc000
+      };
+
+   /* Allowed IRQs */
+   unsigned char interrupt_table[4] = { 15, 14, 11, 10 };
+
+   /* Allowed DMA channels for ISA (0 indicates reserved) */
+   unsigned char dma_channel_table[4] = { 5, 6, 7, 0 };
+
+   /* Head/sector mappings */
+   struct {
+      unsigned char heads;
+      unsigned char sectors;
+      } mapping_table[4] = {
+           { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
+           };
+
+   struct config_1 {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+      unsigned char dma_channel: 2, interrupt:2,
+                    removable_disks_as_fixed:1, bios_segment: 3;
+#else
+      unsigned char bios_segment: 3, removable_disks_as_fixed: 1,
+                    interrupt: 2, dma_channel: 2;
+#endif
+
+      } config_1;
+
+   struct config_2 {
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+      unsigned char tfr_port: 2, bios_drive_number: 1,
+                    mapping_mode: 2, ha_scsi_id: 3;
+#else
+      unsigned char ha_scsi_id: 3, mapping_mode: 2,
+                    bios_drive_number: 1, tfr_port: 2;
+#endif
+
+      } config_2;
+
+   char name[16];
+
+   sprintf(name, "%s%d", driver_name, j);
+
+   if (!request_region(port_base, REGION_SIZE, driver_name)) {
+#if defined(DEBUG_DETECT)
+      printk("%s: address 0x%03lx in use, skipping probe.\n", name, port_base);
+#endif
+      goto fail;
+      }
+
+   spin_lock_irq(&driver_lock);
+
+   if (inb(port_base + REG_PRODUCT_ID1) != PRODUCT_ID1) goto freelock;
+
+   in_byte = inb(port_base + REG_PRODUCT_ID2);
+
+   if ((in_byte & 0xf0) != PRODUCT_ID2) goto freelock;
+
+   *(char *)&config_1 = inb(port_base + REG_CONFIG1);
+   *(char *)&config_2 = inb(port_base + REG_CONFIG2);
+
+   irq = interrupt_table[config_1.interrupt];
+   dma_channel = dma_channel_table[config_1.dma_channel];
+   subversion = (in_byte & 0x0f);
+
+   /* Board detected, allocate its IRQ */
+   if (request_irq(irq, do_interrupt_handler,
+             SA_INTERRUPT | ((subversion == ESA) ? SA_SHIRQ : 0),
+             driver_name, (void *) &sha[j])) {
+      printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
+      goto freelock;
+      }
+
+   if (subversion == ISA && request_dma(dma_channel, driver_name)) {
+      printk("%s: unable to allocate DMA channel %u, detaching.\n",
+             name, dma_channel);
+      goto freeirq;
+      }
+
+   if (have_old_firmware) tpnt->use_clustering = DISABLE_CLUSTERING;
+
+   spin_unlock_irq(&driver_lock);
+   sh[j] = scsi_register(tpnt, sizeof(struct hostdata));
+   spin_lock_irq(&driver_lock);
+
+   if (sh[j] == NULL) {
+      printk("%s: unable to register host, detaching.\n", name);
+      goto freedma;
+      }
+
+   sh[j]->io_port = port_base;
+   sh[j]->unique_id = port_base;
+   sh[j]->n_io_port = REGION_SIZE;
+   sh[j]->base = bios_segment_table[config_1.bios_segment];
+   sh[j]->irq = irq;
+   sh[j]->sg_tablesize = MAX_SGLIST;
+   sh[j]->this_id = config_2.ha_scsi_id;
+   sh[j]->can_queue = MAX_MAILBOXES;
+   sh[j]->cmd_per_lun = MAX_CMD_PER_LUN;
+
+#if defined(DEBUG_DETECT)
+   {
+   unsigned char sys_mask, lcl_mask;
+
+   sys_mask = inb(sh[j]->io_port + REG_SYS_MASK);
+   lcl_mask = inb(sh[j]->io_port + REG_LCL_MASK);
+   printk("SYS_MASK 0x%x, LCL_MASK 0x%x.\n", sys_mask, lcl_mask);
+   }
+#endif
+
+   /* Probably a bogus host scsi id, set it to the dummy value */
+   if (sh[j]->this_id == 0) sh[j]->this_id = -1;
+
+   /* If BIOS is disabled, force enable interrupts */
+   if (sh[j]->base == 0) outb(CMD_ENA_INTR, sh[j]->io_port + REG_SYS_MASK);
+
+   memset(HD(j), 0, sizeof(struct hostdata));
+   HD(j)->heads = mapping_table[config_2.mapping_mode].heads;
+   HD(j)->sectors = mapping_table[config_2.mapping_mode].sectors;
+   HD(j)->subversion = subversion;
+   HD(j)->pdev = NULL;
+   HD(j)->board_number = j;
+
+   if (have_old_firmware) sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+
+   if (HD(j)->subversion == ESA) {
+      sh[j]->unchecked_isa_dma = FALSE;
+      sh[j]->dma_channel = NO_DMA;
+      sprintf(BN(j), "U34F%d", j);
+      bus_type = "VESA";
+      }
+   else {
+      unsigned long flags;
+      sh[j]->unchecked_isa_dma = TRUE;
+
+      flags=claim_dma_lock();
+      disable_dma(dma_channel);
+      clear_dma_ff(dma_channel);
+      set_dma_mode(dma_channel, DMA_MODE_CASCADE);
+      enable_dma(dma_channel);
+      release_dma_lock(flags);
+
+      sh[j]->dma_channel = dma_channel;
+      sprintf(BN(j), "U14F%d", j);
+      bus_type = "ISA";
+      }
+
+   sh[j]->max_channel = MAX_CHANNEL - 1;
+   sh[j]->max_id = MAX_TARGET;
+   sh[j]->max_lun = MAX_LUN;
+
+   if (HD(j)->subversion == ISA && !board_inquiry(j)) {
+      HD(j)->board_id[40] = 0;
+
+      if (strcmp(&HD(j)->board_id[32], "06000600")) {
+         printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+         printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
+                BN(j), &HD(j)->board_id[32]);
+         sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+         sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+         }
+      }
+
+   if (dma_channel == NO_DMA) sprintf(dma_name, "%s", "BMST");
+   else                       sprintf(dma_name, "DMA %u", dma_channel);
+
+   spin_unlock_irq(&driver_lock);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      HD(j)->cp[i].cp_dma_addr = pci_map_single(HD(j)->pdev,
+            &HD(j)->cp[i], sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (! ((&HD(j)->cp[i])->sglist = kmalloc(
+            sh[j]->sg_tablesize * sizeof(struct sg_list),
+            (sh[j]->unchecked_isa_dma ? GFP_DMA : 0) | GFP_ATOMIC))) {
+         printk("%s: kmalloc SGlist failed, mbox %d, detaching.\n", BN(j), i);
+         goto release;
+         }
+
+   if (max_queue_depth > MAX_TAGGED_CMD_PER_LUN)
+       max_queue_depth = MAX_TAGGED_CMD_PER_LUN;
+
+   if (max_queue_depth < MAX_CMD_PER_LUN) max_queue_depth = MAX_CMD_PER_LUN;
+
+   if (tag_mode != TAG_DISABLED && tag_mode != TAG_SIMPLE)
+      tag_mode = TAG_ORDERED;
+
+   if (j == 0) {
+      printk("UltraStor 14F/34F: Copyright (C) 1994-2003 Dario Ballabio.\n");
+      printk("%s config options -> of:%c, tm:%d, lc:%c, mq:%d, et:%c.\n",
+             driver_name, YESNO(have_old_firmware), tag_mode,
+             YESNO(linked_comm), max_queue_depth, YESNO(ext_tran));
+      }
+
+   printk("%s: %s 0x%03lx, BIOS 0x%05x, IRQ %u, %s, SG %d, MB %d.\n",
+          BN(j), bus_type, (unsigned long)sh[j]->io_port, (int)sh[j]->base,
+          sh[j]->irq, dma_name, sh[j]->sg_tablesize, sh[j]->can_queue);
+
+   if (sh[j]->max_id > 8 || sh[j]->max_lun > 8)
+      printk("%s: wide SCSI support enabled, max_id %u, max_lun %u.\n",
+             BN(j), sh[j]->max_id, sh[j]->max_lun);
+
+   for (i = 0; i <= sh[j]->max_channel; i++)
+      printk("%s: SCSI channel %u enabled, host target ID %d.\n",
+             BN(j), i, sh[j]->this_id);
+
+   return TRUE;
+
+freedma:
+   if (subversion == ISA) free_dma(dma_channel);
+freeirq:
+   free_irq(irq, &sha[j]);
+freelock:
+   spin_unlock_irq(&driver_lock);
+   release_region(port_base, REGION_SIZE);
+fail:
+   return FALSE;
+
+release:
+   u14_34f_release(sh[j]);
+   return FALSE;
+}
+
+static void internal_setup(char *str, int *ints) {
+   int i, argc = ints[0];
+   char *cur = str, *pc;
+
+   if (argc > 0) {
+
+      if (argc > MAX_INT_PARAM) argc = MAX_INT_PARAM;
+
+      for (i = 0; i < argc; i++) io_port[i] = ints[i + 1];
+
+      io_port[i] = 0;
+      setup_done = TRUE;
+      }
+
+   while (cur && (pc = strchr(cur, ':'))) {
+      int val = 0, c = *++pc;
+
+      if (c == 'n' || c == 'N') val = FALSE;
+      else if (c == 'y' || c == 'Y') val = TRUE;
+      else val = (int) simple_strtoul(pc, NULL, 0);
+
+      if (!strncmp(cur, "lc:", 3)) linked_comm = val;
+      else if (!strncmp(cur, "of:", 3)) have_old_firmware = val;
+      else if (!strncmp(cur, "tm:", 3)) tag_mode = val;
+      else if (!strncmp(cur, "tc:", 3)) tag_mode = val;
+      else if (!strncmp(cur, "mq:", 3))  max_queue_depth = val;
+      else if (!strncmp(cur, "ls:", 3))  link_statistics = val;
+      else if (!strncmp(cur, "et:", 3))  ext_tran = val;
+
+      if ((cur = strchr(cur, ','))) ++cur;
+      }
+
+   return;
+}
+
+static int option_setup(char *str) {
+   int ints[MAX_INT_PARAM];
+   char *cur = str;
+   int i = 1;
+
+   while (cur && isdigit(*cur) && i <= MAX_INT_PARAM) {
+      ints[i++] = simple_strtoul(cur, NULL, 0);
+
+      if ((cur = strchr(cur, ',')) != NULL) cur++;
+   }
+
+   ints[0] = i - 1;
+   internal_setup(cur, ints);
+   return 1;
+}
+
+static int u14_34f_detect(struct scsi_host_template *tpnt) {
+   unsigned int j = 0, k;
+
+   tpnt->proc_name = "u14-34f";
+
+   if(strlen(boot_options)) option_setup(boot_options);
+
+#if defined(MODULE)
+   /* io_port could have been modified when loading as a module */
+   if(io_port[0] != SKIP) {
+      setup_done = TRUE;
+      io_port[MAX_INT_PARAM] = 0;
+      }
+#endif
+
+   for (k = 0; k < MAX_BOARDS + 1; k++) sh[k] = NULL;
+
+   for (k = 0; io_port[k]; k++) {
+
+      if (io_port[k] == SKIP) continue;
+
+      if (j < MAX_BOARDS && port_detect(io_port[k], j, tpnt)) j++;
+      }
+
+   num_boards = j;
+   return j;
+}
+
+static void map_dma(unsigned int i, unsigned int j) {
+   unsigned int data_len = 0;
+   unsigned int k, count, pci_dir;
+   struct scatterlist *sgpnt;
+   struct mscp *cpp;
+   struct scsi_cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = SCpnt->sc_data_direction;
+
+   if (SCpnt->sense_buffer)
+      cpp->sense_addr = H2DEV(pci_map_single(HD(j)->pdev, SCpnt->sense_buffer,
+                           sizeof SCpnt->sense_buffer, PCI_DMA_FROMDEVICE));
+
+   cpp->sense_len = sizeof SCpnt->sense_buffer;
+
+   if (!SCpnt->use_sg) {
+
+      /* If we get here with PCI_DMA_NONE, pci_map_single triggers a BUG() */
+      if (!SCpnt->request_bufflen) pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+      if (SCpnt->request_buffer)
+         cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev,
+                  SCpnt->request_buffer, SCpnt->request_bufflen, pci_dir));
+
+      cpp->data_len = H2DEV(SCpnt->request_bufflen);
+      return;
+      }
+
+   sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+   count = pci_map_sg(HD(j)->pdev, sgpnt, SCpnt->use_sg, pci_dir);
+
+   for (k = 0; k < count; k++) {
+      cpp->sglist[k].address = H2DEV(sg_dma_address(&sgpnt[k]));
+      cpp->sglist[k].num_bytes = H2DEV(sg_dma_len(&sgpnt[k]));
+      data_len += sgpnt[k].length;
+      }
+
+   cpp->sg = TRUE;
+   cpp->use_sg = SCpnt->use_sg;
+   cpp->data_address = H2DEV(pci_map_single(HD(j)->pdev, cpp->sglist,
+                             SCpnt->use_sg * sizeof(struct sg_list), pci_dir));
+   cpp->data_len = H2DEV(data_len);
+}
+
+static void unmap_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
+   struct mscp *cpp;
+   struct scsi_cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = SCpnt->sc_data_direction;
+
+   if (DEV2H(cpp->sense_addr))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                       DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg)
+      pci_unmap_sg(HD(j)->pdev, SCpnt->request_buffer, SCpnt->use_sg, pci_dir);
+
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+   if (DEV2H(cpp->data_address))
+      pci_unmap_single(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
+}
+
+static void sync_dma(unsigned int i, unsigned int j) {
+   unsigned int pci_dir;
+   struct mscp *cpp;
+   struct scsi_cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+   pci_dir = SCpnt->sc_data_direction;
+
+   if (DEV2H(cpp->sense_addr))
+      pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->sense_addr),
+                          DEV2H(cpp->sense_len), PCI_DMA_FROMDEVICE);
+
+   if (SCpnt->use_sg)
+      pci_dma_sync_sg_for_cpu(HD(j)->pdev, SCpnt->request_buffer,
+                         SCpnt->use_sg, pci_dir);
+
+   if (!DEV2H(cpp->data_len)) pci_dir = PCI_DMA_BIDIRECTIONAL;
+
+   if (DEV2H(cpp->data_address))
+      pci_dma_sync_single_for_cpu(HD(j)->pdev, DEV2H(cpp->data_address),
+                       DEV2H(cpp->data_len), pci_dir);
+}
+
+static void scsi_to_dev_dir(unsigned int i, unsigned int j) {
+   unsigned int k;
+
+   static const unsigned char data_out_cmds[] = {
+      0x0a, 0x2a, 0x15, 0x55, 0x04, 0x07, 0x18, 0x1d, 0x24, 0x2e,
+      0x30, 0x31, 0x32, 0x38, 0x39, 0x3a, 0x3b, 0x3d, 0x3f, 0x40,
+      0x41, 0x4c, 0xaa, 0xae, 0xb0, 0xb1, 0xb2, 0xb6, 0xea, 0x1b, 0x5d
+      };
+
+   static const unsigned char data_none_cmds[] = {
+      0x01, 0x0b, 0x10, 0x11, 0x13, 0x16, 0x17, 0x19, 0x2b, 0x1e,
+      0x2c, 0xac, 0x2f, 0xaf, 0x33, 0xb3, 0x35, 0x36, 0x45, 0x47,
+      0x48, 0x49, 0xa9, 0x4b, 0xa5, 0xa6, 0xb5, 0x00
+      };
+
+   struct mscp *cpp;
+   struct scsi_cmnd *SCpnt;
+
+   cpp = &HD(j)->cp[i]; SCpnt = cpp->SCpnt;
+
+   if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
+      cpp->xdir = DTD_IN;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == DMA_FROM_DEVICE) {
+      cpp->xdir = DTD_OUT;
+      return;
+      }
+   else if (SCpnt->sc_data_direction == DMA_NONE) {
+      cpp->xdir = DTD_NONE;
+      return;
+      }
+
+   if (SCpnt->sc_data_direction != DMA_BIDIRECTIONAL)
+      panic("%s: qcomm, invalid SCpnt->sc_data_direction.\n", BN(j));
+
+   cpp->xdir = DTD_IN;
+
+   for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
+      if (SCpnt->cmnd[0] == data_out_cmds[k]) {
+         cpp->xdir = DTD_OUT;
+         break;
+         }
+
+   if (cpp->xdir == DTD_IN)
+      for (k = 0; k < ARRAY_SIZE(data_none_cmds); k++)
+         if (SCpnt->cmnd[0] == data_none_cmds[k]) {
+            cpp->xdir = DTD_NONE;
+            break;
+            }
+
+}
+
+static int u14_34f_queuecommand(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)) {
+   unsigned int i, j, k;
+   struct mscp *cpp;
+
+   /* j is the board number */
+   j = ((struct hostdata *) SCpnt->device->host->hostdata)->board_number;
+
+   if (SCpnt->host_scribble)
+      panic("%s: qcomm, pid %ld, SCpnt %p already active.\n",
+            BN(j), SCpnt->pid, SCpnt);
+
+   /* i is the mailbox number, look for the first free mailbox
+      starting from last_cp_used */
+   i = HD(j)->last_cp_used + 1;
+
+   for (k = 0; k < sh[j]->can_queue; k++, i++) {
+
+      if (i >= sh[j]->can_queue) i = 0;
+
+      if (HD(j)->cp_stat[i] == FREE) {
+         HD(j)->last_cp_used = i;
+         break;
+         }
+      }
+
+   if (k == sh[j]->can_queue) {
+      printk("%s: qcomm, no free mailbox.\n", BN(j));
+      return 1;
+      }
+
+   /* Set pointer to control packet structure */
+   cpp = &HD(j)->cp[i];
+
+   memset(cpp, 0, sizeof(struct mscp) - CP_TAIL_SIZE);
+   SCpnt->scsi_done = done;
+   cpp->cpp_index = i;
+   SCpnt->host_scribble = (unsigned char *) &cpp->cpp_index;
+
+   if (do_trace) printk("%s: qcomm, mbox %d, target %d.%d:%d, pid %ld.\n",
+                        BN(j), i, SCpnt->device->channel, SCpnt->device->id,
+                        SCpnt->device->lun, SCpnt->pid);
+
+   cpp->opcode = OP_SCSI;
+   cpp->channel = SCpnt->device->channel;
+   cpp->target = SCpnt->device->id;
+   cpp->lun = SCpnt->device->lun;
+   cpp->SCpnt = SCpnt;
+   cpp->cdb_len = SCpnt->cmd_len;
+   memcpy(cpp->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+
+   /* Use data transfer direction SCpnt->sc_data_direction */
+   scsi_to_dev_dir(i, j);
+
+   /* Map DMA buffers and SG list */
+   map_dma(i, j);
+
+   if (linked_comm && SCpnt->device->queue_depth > 2
+                                     && TLDEV(SCpnt->device->type)) {
+      HD(j)->cp_stat[i] = READY;
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, FALSE);
+      return 0;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      unmap_dma(i, j);
+      SCpnt->host_scribble = NULL;
+      printk("%s: qcomm, target %d.%d:%d, pid %ld, adapter busy.\n",
+             BN(j), SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid);
+      return 1;
+      }
+
+   /* Store pointer in OGM address bytes */
+   outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
+
+   /* Issue OGM interrupt */
+   outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
+
+   HD(j)->cp_stat[i] = IN_USE;
+   return 0;
+}
+
+static int u14_34f_eh_abort(struct scsi_cmnd *SCarg) {
+   unsigned int i, j;
+
+   j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
+
+   if (SCarg->host_scribble == NULL) {
+      printk("%s: abort, target %d.%d:%d, pid %ld inactive.\n",
+             BN(j), SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid);
+      return SUCCESS;
+      }
+
+   i = *(unsigned int *)SCarg->host_scribble;
+   printk("%s: abort, mbox %d, target %d.%d:%d, pid %ld.\n",
+          BN(j), i, SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid);
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: abort, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: abort, mbox %d is free.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_USE) {
+      printk("%s: abort, mbox %d is in use.\n", BN(j), i);
+
+      if (SCarg != HD(j)->cp[i].SCpnt)
+         panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+               BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+
+      if (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED)
+         printk("%s: abort, mbox %d, interrupt pending.\n", BN(j), i);
+
+      if (SCarg->eh_state == SCSI_STATE_TIMEOUT) {
+         unmap_dma(i, j);
+         SCarg->host_scribble = NULL;
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s, abort, mbox %d, eh_state timeout, pid %ld.\n",
+                BN(j), i, SCarg->pid);
+         return SUCCESS;
+         }
+
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == IN_RESET) {
+      printk("%s: abort, mbox %d is in reset.\n", BN(j), i);
+      return FAILED;
+      }
+
+   if (HD(j)->cp_stat[i] == LOCKED) {
+      printk("%s: abort, mbox %d is locked.\n", BN(j), i);
+      return SUCCESS;
+      }
+
+   if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+      unmap_dma(i, j);
+      SCarg->result = DID_ABORT << 16;
+      SCarg->host_scribble = NULL;
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s, abort, mbox %d ready, DID_ABORT, pid %ld done.\n",
+             BN(j), i, SCarg->pid);
+      SCarg->scsi_done(SCarg);
+      return SUCCESS;
+      }
+
+   panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
+}
+
+static int u14_34f_eh_host_reset(struct scsi_cmnd *SCarg) {
+   unsigned int i, j, time, k, c, limit = 0;
+   int arg_done = FALSE;
+   struct scsi_cmnd *SCpnt;
+
+   j = ((struct hostdata *) SCarg->device->host->hostdata)->board_number;
+   printk("%s: reset, enter, target %d.%d:%d, pid %ld.\n",
+          BN(j), SCarg->device->channel, SCarg->device->id, SCarg->device->lun, SCarg->pid);
+
+   if (SCarg->host_scribble == NULL)
+      printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
+
+   if (HD(j)->in_reset) {
+      printk("%s: reset, exit, already in reset.\n", BN(j));
+      return FAILED;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, exit, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   HD(j)->retries = 0;
+
+   for (c = 0; c <= sh[j]->max_channel; c++)
+      for (k = 0; k < sh[j]->max_id; k++) {
+         HD(j)->target_redo[k][c] = TRUE;
+         HD(j)->target_to[k][c] = 0;
+         }
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == FREE) continue;
+
+      if (HD(j)->cp_stat[i] == LOCKED) {
+         HD(j)->cp_stat[i] = FREE;
+         printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+         continue;
+         }
+
+      if (!(SCpnt = HD(j)->cp[i].SCpnt))
+         panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+      if (HD(j)->cp_stat[i] == READY || HD(j)->cp_stat[i] == ABORTING) {
+         HD(j)->cp_stat[i] = ABORTING;
+         printk("%s: reset, mbox %d aborting, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else {
+         HD(j)->cp_stat[i] = IN_RESET;
+         printk("%s: reset, mbox %d in reset, pid %ld.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      if (SCpnt->host_scribble == NULL)
+         panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+
+      if (*(unsigned int *)SCpnt->host_scribble != i)
+         panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+
+      if (SCpnt->scsi_done == NULL)
+         panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+
+      if (SCpnt == SCarg) arg_done = TRUE;
+      }
+
+   if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+      printk("%s: reset, cannot reset, timeout error.\n", BN(j));
+      return FAILED;
+      }
+
+   outb(CMD_RESET, sh[j]->io_port + REG_LCL_INTR);
+   printk("%s: reset, board reset done, enabling interrupts.\n", BN(j));
+
+#if defined(DEBUG_RESET)
+   do_trace = TRUE;
+#endif
+
+   HD(j)->in_reset = TRUE;
+
+   spin_unlock_irq(sh[j]->host_lock);
+   time = jiffies;
+   while ((jiffies - time) < (10 * HZ) && limit++ < 200000) udelay(100L);
+   spin_lock_irq(sh[j]->host_lock);
+
+   printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
+
+   for (i = 0; i < sh[j]->can_queue; i++) {
+
+      if (HD(j)->cp_stat[i] == IN_RESET) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox is still waiting for its interrupt */
+         HD(j)->cp_stat[i] = LOCKED;
+
+         printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else if (HD(j)->cp_stat[i] == ABORTING) {
+         SCpnt = HD(j)->cp[i].SCpnt;
+         unmap_dma(i, j);
+         SCpnt->result = DID_RESET << 16;
+         SCpnt->host_scribble = NULL;
+
+         /* This mailbox was never queued to the adapter */
+         HD(j)->cp_stat[i] = FREE;
+
+         printk("%s, reset, mbox %d aborting, DID_RESET, pid %ld done.\n",
+                BN(j), i, SCpnt->pid);
+         }
+
+      else
+
+         /* Any other mailbox has already been set free by interrupt */
+         continue;
+
+      SCpnt->scsi_done(SCpnt);
+      }
+
+   HD(j)->in_reset = FALSE;
+   do_trace = FALSE;
+
+   if (arg_done) printk("%s: reset, exit, pid %ld done.\n", BN(j), SCarg->pid);
+   else          printk("%s: reset, exit.\n", BN(j));
+
+   return SUCCESS;
+}
+
+static int u14_34f_bios_param(struct scsi_device *disk,
+                 struct block_device *bdev, sector_t capacity, int *dkinfo) {
+   unsigned int j = 0;
+   unsigned int size = capacity;
+
+   dkinfo[0] = HD(j)->heads;
+   dkinfo[1] = HD(j)->sectors;
+   dkinfo[2] = size / (HD(j)->heads * HD(j)->sectors);
+
+   if (ext_tran && (scsicam_bios_param(bdev, capacity, dkinfo) < 0)) {
+      dkinfo[0] = 255;
+      dkinfo[1] = 63;
+      dkinfo[2] = size / (dkinfo[0] * dkinfo[1]);
+      }
+
+#if defined (DEBUG_GEOMETRY)
+   printk ("%s: bios_param, head=%d, sec=%d, cyl=%d.\n", driver_name,
+           dkinfo[0], dkinfo[1], dkinfo[2]);
+#endif
+
+   return FALSE;
+}
+
+static void sort(unsigned long sk[], unsigned int da[], unsigned int n,
+                 unsigned int rev) {
+   unsigned int i, j, k, y;
+   unsigned long x;
+
+   for (i = 0; i < n - 1; i++) {
+      k = i;
+
+      for (j = k + 1; j < n; j++)
+         if (rev) {
+            if (sk[j] > sk[k]) k = j;
+            }
+         else {
+            if (sk[j] < sk[k]) k = j;
+            }
+
+      if (k != i) {
+         x = sk[k]; sk[k] = sk[i]; sk[i] = x;
+         y = da[k]; da[k] = da[i]; da[i] = y;
+         }
+      }
+
+   return;
+   }
+
+static int reorder(unsigned int j, unsigned long cursec,
+                 unsigned int ihdlr, unsigned int il[], unsigned int n_ready) {
+   struct scsi_cmnd *SCpnt;
+   struct mscp *cpp;
+   unsigned int k, n;
+   unsigned int rev = FALSE, s = TRUE, r = TRUE;
+   unsigned int input_only = TRUE, overlap = FALSE;
+   unsigned long sl[n_ready], pl[n_ready], ll[n_ready];
+   unsigned long maxsec = 0, minsec = ULONG_MAX, seek = 0, iseek = 0;
+   unsigned long ioseek = 0;
+
+   static unsigned int flushcount = 0, batchcount = 0, sortcount = 0;
+   static unsigned int readycount = 0, ovlcount = 0, inputcount = 0;
+   static unsigned int readysorted = 0, revcount = 0;
+   static unsigned long seeksorted = 0, seeknosort = 0;
+
+   if (link_statistics && !(++flushcount % link_statistics))
+      printk("fc %d bc %d ic %d oc %d rc %d rs %d sc %d re %d"\
+             " av %ldK as %ldK.\n", flushcount, batchcount, inputcount,
+             ovlcount, readycount, readysorted, sortcount, revcount,
+             seeknosort / (readycount + 1),
+             seeksorted / (readycount + 1));
+
+   if (n_ready <= 1) return FALSE;
+
+   for (n = 0; n < n_ready; n++) {
+      k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
+
+      if (!(cpp->xdir == DTD_IN)) input_only = FALSE;
+
+      if (SCpnt->request->sector < minsec) minsec = SCpnt->request->sector;
+      if (SCpnt->request->sector > maxsec) maxsec = SCpnt->request->sector;
+
+      sl[n] = SCpnt->request->sector;
+      ioseek += SCpnt->request->nr_sectors;
+
+      if (!n) continue;
+
+      if (sl[n] < sl[n - 1]) s = FALSE;
+      if (sl[n] > sl[n - 1]) r = FALSE;
+
+      if (link_statistics) {
+         if (sl[n] > sl[n - 1])
+            seek += sl[n] - sl[n - 1];
+         else
+            seek += sl[n - 1] - sl[n];
+         }
+
+      }
+
+   if (link_statistics) {
+      if (cursec > sl[0]) seek += cursec - sl[0]; else seek += sl[0] - cursec;
+      }
+
+   if (cursec > ((maxsec + minsec) / 2)) rev = TRUE;
+
+   if (ioseek > ((maxsec - minsec) / 2)) rev = FALSE;
+
+   if (!((rev && r) || (!rev && s))) sort(sl, il, n_ready, rev);
+
+   if (!input_only) for (n = 0; n < n_ready; n++) {
+      k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
+      ll[n] = SCpnt->request->nr_sectors; pl[n] = SCpnt->pid;
+
+      if (!n) continue;
+
+      if ((sl[n] == sl[n - 1]) || (!rev && ((sl[n - 1] + ll[n - 1]) > sl[n]))
+          || (rev && ((sl[n] + ll[n]) > sl[n - 1]))) overlap = TRUE;
+      }
+
+   if (overlap) sort(pl, il, n_ready, FALSE);
+
+   if (link_statistics) {
+      if (cursec > sl[0]) iseek = cursec - sl[0]; else iseek = sl[0] - cursec;
+      batchcount++; readycount += n_ready; seeknosort += seek / 1024;
+      if (input_only) inputcount++;
+      if (overlap) { ovlcount++; seeksorted += iseek / 1024; }
+      else seeksorted += (iseek + maxsec - minsec) / 1024;
+      if (rev && !r)     {  revcount++; readysorted += n_ready; }
+      if (!rev && !s)    { sortcount++; readysorted += n_ready; }
+      }
+
+#if defined(DEBUG_LINKED_COMMANDS)
+   if (link_statistics && (overlap || !(flushcount % link_statistics)))
+      for (n = 0; n < n_ready; n++) {
+         k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
+         printk("%s %d.%d:%d pid %ld mb %d fc %d nr %d sec %ld ns %ld"\
+                " cur %ld s:%c r:%c rev:%c in:%c ov:%c xd %d.\n",
+                (ihdlr ? "ihdlr" : "qcomm"), SCpnt->channel, SCpnt->target,
+                SCpnt->lun, SCpnt->pid, k, flushcount, n_ready,
+                SCpnt->request->sector, SCpnt->request->nr_sectors, cursec,
+                YESNO(s), YESNO(r), YESNO(rev), YESNO(input_only),
+                YESNO(overlap), cpp->xdir);
+         }
+#endif
+   return overlap;
+}
+
+static void flush_dev(struct scsi_device *dev, unsigned long cursec, unsigned int j,
+                      unsigned int ihdlr) {
+   struct scsi_cmnd *SCpnt;
+   struct mscp *cpp;
+   unsigned int k, n, n_ready = 0, il[MAX_MAILBOXES];
+
+   for (k = 0; k < sh[j]->can_queue; k++) {
+
+      if (HD(j)->cp_stat[k] != READY && HD(j)->cp_stat[k] != IN_USE) continue;
+
+      cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
+
+      if (SCpnt->device != dev) continue;
+
+      if (HD(j)->cp_stat[k] == IN_USE) return;
+
+      il[n_ready++] = k;
+      }
+
+   if (reorder(j, cursec, ihdlr, il, n_ready)) n_ready = 1;
+
+   for (n = 0; n < n_ready; n++) {
+      k = il[n]; cpp = &HD(j)->cp[k]; SCpnt = cpp->SCpnt;
+
+      if (wait_on_busy(sh[j]->io_port, MAXLOOP)) {
+         printk("%s: %s, target %d.%d:%d, pid %ld, mbox %d, adapter"\
+                " busy, will abort.\n", BN(j), (ihdlr ? "ihdlr" : "qcomm"),
+                SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid, k);
+         HD(j)->cp_stat[k] = ABORTING;
+         continue;
+         }
+
+      outl(H2DEV(cpp->cp_dma_addr), sh[j]->io_port + REG_OGM);
+      outb(CMD_OGM_INTR, sh[j]->io_port + REG_LCL_INTR);
+      HD(j)->cp_stat[k] = IN_USE;
+      }
+
+}
+
+static irqreturn_t ihdlr(int irq, unsigned int j) {
+   struct scsi_cmnd *SCpnt;
+   unsigned int i, k, c, status, tstatus, reg, ret;
+   struct mscp *spp, *cpp;
+
+   if (sh[j]->irq != irq)
+       panic("%s: ihdlr, irq %d, sh[j]->irq %d.\n", BN(j), irq, sh[j]->irq);
+
+   /* Check if this board need to be serviced */
+   if (!((reg = inb(sh[j]->io_port + REG_SYS_INTR)) & IRQ_ASSERTED)) goto none;
+
+   HD(j)->iocount++;
+
+   if (do_trace) printk("%s: ihdlr, enter, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
+
+   /* Check if this board is still busy */
+   if (wait_on_busy(sh[j]->io_port, 20 * MAXLOOP)) {
+      outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+      printk("%s: ihdlr, busy timeout error,  irq %d, reg 0x%x, count %d.\n",
+             BN(j), irq, reg, HD(j)->iocount);
+      goto none;
+      }
+
+   ret = inl(sh[j]->io_port + REG_ICM);
+
+   /* Clear interrupt pending flag */
+   outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+
+   /* Find the mailbox to be serviced on this board */
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if (H2DEV(HD(j)->cp[i].cp_dma_addr) == ret) break;
+
+   if (i >= sh[j]->can_queue)
+      panic("%s: ihdlr, invalid mscp bus address %p, cp0 %p.\n", BN(j),
+            (void *)ret, (void *)H2DEV(HD(j)->cp[0].cp_dma_addr));
+
+   cpp = &(HD(j)->cp[i]);
+   spp = cpp;
+
+#if defined(DEBUG_GENERATE_ABORTS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 500) < 3)) goto handled;
+#endif
+
+   if (HD(j)->cp_stat[i] == IGNORE) {
+      HD(j)->cp_stat[i] = FREE;
+      goto handled;
+      }
+   else if (HD(j)->cp_stat[i] == LOCKED) {
+      HD(j)->cp_stat[i] = FREE;
+      printk("%s: ihdlr, mbox %d unlocked, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      goto handled;
+      }
+   else if (HD(j)->cp_stat[i] == FREE) {
+      printk("%s: ihdlr, mbox %d is free, count %d.\n", BN(j), i,
+             HD(j)->iocount);
+      goto handled;
+      }
+   else if (HD(j)->cp_stat[i] == IN_RESET)
+      printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+   else if (HD(j)->cp_stat[i] != IN_USE)
+      panic("%s: ihdlr, mbox %d, invalid cp_stat: %d.\n",
+            BN(j), i, HD(j)->cp_stat[i]);
+
+   HD(j)->cp_stat[i] = FREE;
+   SCpnt = cpp->SCpnt;
+
+   if (SCpnt == NULL) panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+   if (SCpnt->host_scribble == NULL)
+      panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n", BN(j), i,
+            SCpnt->pid, SCpnt);
+
+   if (*(unsigned int *)SCpnt->host_scribble != i)
+      panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d.\n",
+            BN(j), i, SCpnt->pid, *(unsigned int *)SCpnt->host_scribble);
+
+   sync_dma(i, j);
+
+   if (linked_comm && SCpnt->device->queue_depth > 2
+                                     && TLDEV(SCpnt->device->type))
+      flush_dev(SCpnt->device, SCpnt->request->sector, j, TRUE);
+
+   tstatus = status_byte(spp->target_status);
+
+#if defined(DEBUG_GENERATE_ERRORS)
+   if ((HD(j)->iocount > 500) && ((HD(j)->iocount % 200) < 2))
+                                           spp->adapter_status = 0x01;
+#endif
+
+   switch (spp->adapter_status) {
+      case ASOK:     /* status OK */
+
+         /* Forces a reset if a disk drive keeps returning BUSY */
+         if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+            status = DID_ERROR << 16;
+
+         /* If there was a bus reset, redo operation on each target */
+         else if (tstatus != GOOD && SCpnt->device->type == TYPE_DISK
+                  && HD(j)->target_redo[SCpnt->device->id][SCpnt->device->channel])
+            status = DID_BUS_BUSY << 16;
+
+         /* Works around a flaw in scsi.c */
+         else if (tstatus == CHECK_CONDITION
+                  && SCpnt->device->type == TYPE_DISK
+                  && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+            status = DID_BUS_BUSY << 16;
+
+         else
+            status = DID_OK << 16;
+
+         if (tstatus == GOOD)
+            HD(j)->target_redo[SCpnt->device->id][SCpnt->device->channel] = FALSE;
+
+         if (spp->target_status && SCpnt->device->type == TYPE_DISK &&
+             (!(tstatus == CHECK_CONDITION && HD(j)->iocount <= 1000 &&
+               (SCpnt->sense_buffer[2] & 0xf) == NOT_READY)))
+            printk("%s: ihdlr, target %d.%d:%d, pid %ld, "\
+                   "target_status 0x%x, sense key 0x%x.\n", BN(j),
+                   SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun,
+                   SCpnt->pid, spp->target_status,
+                   SCpnt->sense_buffer[2]);
+
+         HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel] = 0;
+
+         if (HD(j)->last_retried_pid == SCpnt->pid) HD(j)->retries = 0;
+
+         break;
+      case ASST:     /* Selection Time Out */
+
+         if (HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel] > 1)
+            status = DID_ERROR << 16;
+         else {
+            status = DID_TIME_OUT << 16;
+            HD(j)->target_to[SCpnt->device->id][SCpnt->device->channel]++;
+            }
+
+         break;
+
+      /* Perform a limited number of internal retries */
+      case 0x93:     /* Unexpected bus free */
+      case 0x94:     /* Target bus phase sequence failure */
+      case 0x96:     /* Illegal SCSI command */
+      case 0xa3:     /* SCSI bus reset error */
+
+         for (c = 0; c <= sh[j]->max_channel; c++)
+            for (k = 0; k < sh[j]->max_id; k++)
+               HD(j)->target_redo[k][c] = TRUE;
+
+
+      case 0x92:     /* Data over/under-run */
+
+         if (SCpnt->device->type != TYPE_TAPE
+             && HD(j)->retries < MAX_INTERNAL_RETRIES) {
+
+#if defined(DID_SOFT_ERROR)
+            status = DID_SOFT_ERROR << 16;
+#else
+            status = DID_BUS_BUSY << 16;
+#endif
+
+            HD(j)->retries++;
+            HD(j)->last_retried_pid = SCpnt->pid;
+            }
+         else
+            status = DID_ERROR << 16;
+
+         break;
+      case 0x01:     /* Invalid command */
+      case 0x02:     /* Invalid parameters */
+      case 0x03:     /* Invalid data list */
+      case 0x84:     /* SCSI bus abort error */
+      case 0x9b:     /* Auto request sense error */
+      case 0x9f:     /* Unexpected command complete message error */
+      case 0xff:     /* Invalid parameter in the S/G list */
+      default:
+         status = DID_ERROR << 16;
+         break;
+      }
+
+   SCpnt->result = status | spp->target_status;
+
+#if defined(DEBUG_INTERRUPT)
+   if (SCpnt->result || do_trace)
+#else
+   if ((spp->adapter_status != ASOK && HD(j)->iocount >  1000) ||
+       (spp->adapter_status != ASOK &&
+        spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+        do_trace || msg_byte(spp->target_status))
+#endif
+      printk("%s: ihdlr, mbox %2d, err 0x%x:%x,"\
+             " target %d.%d:%d, pid %ld, reg 0x%x, count %d.\n",
+             BN(j), i, spp->adapter_status, spp->target_status,
+             SCpnt->device->channel, SCpnt->device->id, SCpnt->device->lun, SCpnt->pid,
+             reg, HD(j)->iocount);
+
+   unmap_dma(i, j);
+
+   /* Set the command state to inactive */
+   SCpnt->host_scribble = NULL;
+
+   SCpnt->scsi_done(SCpnt);
+
+   if (do_trace) printk("%s: ihdlr, exit, irq %d, count %d.\n", BN(j), irq,
+                        HD(j)->iocount);
+
+handled:
+   return IRQ_HANDLED;
+none:
+   return IRQ_NONE;
+}
+
+static irqreturn_t do_interrupt_handler(int irq, void *shap,
+                                        struct pt_regs *regs) {
+   unsigned int j;
+   unsigned long spin_flags;
+   irqreturn_t ret;
+
+   /* Check if the interrupt must be processed by this handler */
+   if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return IRQ_NONE;
+
+   spin_lock_irqsave(sh[j]->host_lock, spin_flags);
+   ret = ihdlr(irq, j);
+   spin_unlock_irqrestore(sh[j]->host_lock, spin_flags);
+   return ret;
+}
+
+static int u14_34f_release(struct Scsi_Host *shpnt) {
+   unsigned int i, j;
+
+   for (j = 0; sh[j] != NULL && sh[j] != shpnt; j++);
+
+   if (sh[j] == NULL) panic("%s: release, invalid Scsi_Host pointer.\n",
+                            driver_name);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      if ((&HD(j)->cp[i])->sglist) kfree((&HD(j)->cp[i])->sglist);
+
+   for (i = 0; i < sh[j]->can_queue; i++)
+      pci_unmap_single(HD(j)->pdev, HD(j)->cp[i].cp_dma_addr,
+                     sizeof(struct mscp), PCI_DMA_BIDIRECTIONAL);
+
+   free_irq(sh[j]->irq, &sha[j]);
+
+   if (sh[j]->dma_channel != NO_DMA) free_dma(sh[j]->dma_channel);
+
+   release_region(sh[j]->io_port, sh[j]->n_io_port);
+   scsi_unregister(sh[j]);
+   return FALSE;
+}
+
+#include "scsi_module.c"
+
+#ifndef MODULE
+__setup("u14-34f=", option_setup);
+#endif /* end MODULE */
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
new file mode 100644
index 0000000..7484916
--- /dev/null
+++ b/drivers/scsi/ultrastor.c
@@ -0,0 +1,1204 @@
+/*
+ *	ultrastor.c	Copyright (C) 1992 David B. Gentzel
+ *	Low-level SCSI driver for UltraStor 14F, 24F, and 34F
+ *	by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *	    (gentzel@nova.enet.dec.com)
+ *  scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
+ *  24F and multiple command support by John F. Carr (jfc@athena.mit.edu)
+ *    John's work modified by Caleb Epstein (cae@jpmorgan.com) and 
+ *    Eric Youngdale (ericy@cais.com).
+ *	Thanks to UltraStor for providing the necessary documentation
+ *
+ *  This is an old driver, for the 14F and 34F you should be using the
+ *  u14-34f driver instead.
+ */
+
+/*
+ * TODO:
+ *	1. Find out why scatter/gather is limited to 16 requests per command.
+ *         This is fixed, at least on the 24F, as of version 1.12 - CAE.
+ *	2. Look at command linking (mscp.command_link and
+ *	   mscp.command_link_id).  (Does not work with many disks, 
+ *				and no performance increase.  ERY).
+ *	3. Allow multiple adapters.
+ */
+
+/*
+ * NOTES:
+ *    The UltraStor 14F, 24F, and 34F are a family of intelligent, high
+ *    performance SCSI-2 host adapters.  They all support command queueing
+ *    and scatter/gather I/O.  Some of them can also emulate the standard
+ *    WD1003 interface for use with OS's which don't support SCSI.  Here
+ *    is the scoop on the various models:
+ *	14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
+ *	14N - ISA HA with floppy support.  I think that this is a non-DMA
+ *	      HA.  Nothing further known.
+ *	24F - EISA Bus Master HA with floppy support and WD1003 emulation.
+ *	34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
+ *
+ *    The 14F, 24F, and 34F are supported by this driver.
+ *
+ *    Places flagged with a triple question-mark are things which are either
+ *    unfinished, questionable, or wrong.
+ */
+
+/* Changes from version 1.11 alpha to 1.12
+ *
+ * Increased the size of the scatter-gather list to 33 entries for
+ * the 24F adapter (it was 16).  I don't have the specs for the 14F
+ * or the 34F, so they may support larger s-g lists as well.
+ *
+ * Caleb Epstein <cae@jpmorgan.com>
+ */
+
+/* Changes from version 1.9 to 1.11
+ *
+ * Patches to bring this driver up to speed with the default kernel
+ * driver which supports only the 14F and 34F adapters.  This version
+ * should compile cleanly into 0.99.13, 0.99.12 and probably 0.99.11.
+ *
+ * Fixes from Eric Youngdale to fix a few possible race conditions and
+ * several problems with bit testing operations (insufficient
+ * parentheses).
+ *
+ * Removed the ultrastor_abort() and ultrastor_reset() functions
+ * (enclosed them in #if 0 / #endif).  These functions, at least on
+ * the 24F, cause the SCSI bus to do odd things and generally lead to
+ * kernel panics and machine hangs.  This is like the Adaptec code.
+ *
+ * Use check/snarf_region for 14f, 34f to avoid I/O space address conflicts.
+ */
+
+/* Changes from version 1.8 to version 1.9
+ *
+ *  0.99.11 patches (cae@jpmorgan.com) */
+
+/* Changes from version 1.7 to version 1.8
+ *
+ * Better error reporting.
+ */
+
+/* Changes from version 1.6 to version 1.7
+ *
+ * Removed CSIR command code.
+ *
+ * Better race condition avoidance (xchgb function added).
+ *
+ * Set ICM and OGM status to zero at probe (24F)
+ *
+ * reset sends soft reset to UltraStor adapter
+ *
+ * reset adapter if adapter interrupts with an invalid MSCP address
+ *
+ * handle aborted command interrupt (24F)
+ *
+ */
+
+/* Changes from version 1.5 to version 1.6:
+ *
+ * Read MSCP address from ICM _before_ clearing the interrupt flag.
+ * This fixes a race condition.
+ */
+
+/* Changes from version 1.4 to version 1.5:
+ *
+ * Abort now calls done when multiple commands are enabled.
+ *
+ * Clear busy when aborted command finishes, not when abort is called.
+ *
+ * More debugging messages for aborts.
+ */
+
+/* Changes from version 1.3 to version 1.4:
+ *
+ * Enable automatic request of sense data on error (requires newer version
+ * of scsi.c to be useful).
+ *
+ * Fix PORT_OVERRIDE for 14F.
+ *
+ * Fix abort and reset to work properly (config.aborted wasn't cleared
+ * after it was tested, so after a command abort no further commands would
+ * work).
+ *
+ * Boot time test to enable SCSI bus reset (defaults to not allowing reset).
+ *
+ * Fix test for OGM busy -- the busy bit is in different places on the 24F.
+ *
+ * Release ICM slot by clearing first byte on 24F.
+ */
+
+#include <linux/module.h>
+#include <linux/blkdev.h>
+#include <linux/interrupt.h>
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+#include <linux/stat.h>
+#include <linux/bitops.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+
+#define ULTRASTOR_PRIVATE	/* Get the private stuff from ultrastor.h */
+#include "scsi.h"
+#include <scsi/scsi_host.h>
+#include "ultrastor.h"
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef ULTRASTOR_DEBUG
+#define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET)
+#endif
+
+#define VERSION "1.12"
+
+#define PACKED		__attribute__((packed))
+#define ALIGNED(x)	__attribute__((aligned(x)))
+
+
+/* The 14F uses an array of 4-byte ints for its scatter/gather list.
+   The data can be unaligned, but need not be.  It's easier to give
+   the list normal alignment since it doesn't need to fit into a
+   packed structure.  */
+
+typedef struct {
+  u32 address;
+  u32 num_bytes;
+} ultrastor_sg_list;
+
+
+/* MailBox SCSI Command Packet.  Basic command structure for communicating
+   with controller. */
+struct mscp {
+  unsigned char opcode: 3;		/* type of command */
+  unsigned char xdir: 2;		/* data transfer direction */
+  unsigned char dcn: 1;		/* disable disconnect */
+  unsigned char ca: 1;		/* use cache (if available) */
+  unsigned char sg: 1;		/* scatter/gather operation */
+  unsigned char target_id: 3;		/* target SCSI id */
+  unsigned char ch_no: 2;		/* SCSI channel (always 0 for 14f) */
+  unsigned char lun: 3;		/* logical unit number */
+  unsigned int transfer_data PACKED;	/* transfer data pointer */
+  unsigned int transfer_data_length PACKED;	/* length in bytes */
+  unsigned int command_link PACKED;	/* for linking command chains */
+  unsigned char scsi_command_link_id;	/* identifies command in chain */
+  unsigned char number_of_sg_list;	/* (if sg is set) 8 bytes per list */
+  unsigned char length_of_sense_byte;
+  unsigned char length_of_scsi_cdbs;	/* 6, 10, or 12 */
+  unsigned char scsi_cdbs[12];	/* SCSI commands */
+  unsigned char adapter_status;	/* non-zero indicates HA error */
+  unsigned char target_status;	/* non-zero indicates target error */
+  u32 sense_data PACKED;
+  /* The following fields are for software only.  They are included in
+     the MSCP structure because they are associated with SCSI requests.  */
+  void (*done)(Scsi_Cmnd *);
+  Scsi_Cmnd *SCint;
+  ultrastor_sg_list sglist[ULTRASTOR_24F_MAX_SG]; /* use larger size for 24F */
+};
+
+
+/* Port addresses (relative to the base address) */
+#define U14F_PRODUCT_ID(port) ((port) + 0x4)
+#define CONFIG(port) ((port) + 0x6)
+
+/* Port addresses relative to the doorbell base address.  */
+#define LCL_DOORBELL_MASK(port) ((port) + 0x0)
+#define LCL_DOORBELL_INTR(port) ((port) + 0x1)
+#define SYS_DOORBELL_MASK(port) ((port) + 0x2)
+#define SYS_DOORBELL_INTR(port) ((port) + 0x3)
+
+
+/* Used to store configuration info read from config i/o registers.  Most of
+   this is not used yet, but might as well save it.
+   
+   This structure also holds port addresses that are not at the same offset
+   on the 14F and 24F.
+   
+   This structure holds all data that must be duplicated to support multiple
+   adapters.  */
+
+static struct ultrastor_config
+{
+  unsigned short port_address;		/* base address of card */
+  unsigned short doorbell_address;	/* base address of doorbell CSRs */
+  unsigned short ogm_address;		/* base address of OGM */
+  unsigned short icm_address;		/* base address of ICM */
+  const void *bios_segment;
+  unsigned char interrupt: 4;
+  unsigned char dma_channel: 3;
+  unsigned char bios_drive_number: 1;
+  unsigned char heads;
+  unsigned char sectors;
+  unsigned char ha_scsi_id: 3;
+  unsigned char subversion: 4;
+  unsigned char revision;
+  /* The slot number is used to distinguish the 24F (slot != 0) from
+     the 14F and 34F (slot == 0). */
+  unsigned char slot;
+
+#ifdef PRINT_U24F_VERSION
+  volatile int csir_done;
+#endif
+
+  /* A pool of MSCP structures for this adapter, and a bitmask of
+     busy structures.  (If ULTRASTOR_14F_MAX_CMDS == 1, a 1 byte
+     busy flag is used instead.)  */
+
+#if ULTRASTOR_MAX_CMDS == 1
+  unsigned char mscp_busy;
+#else
+  unsigned long mscp_free;
+#endif
+  volatile unsigned char aborted[ULTRASTOR_MAX_CMDS];
+  struct mscp mscp[ULTRASTOR_MAX_CMDS];
+} config = {0};
+
+/* Set this to 1 to reset the SCSI bus on error.  */
+static int ultrastor_bus_reset;
+
+
+/* Allowed BIOS base addresses (NULL indicates reserved) */
+static const void *const bios_segment_table[8] = {
+  NULL,	     (void *)0xC4000, (void *)0xC8000, (void *)0xCC000,
+  (void *)0xD0000, (void *)0xD4000, (void *)0xD8000, (void *)0xDC000,
+};
+
+/* Allowed IRQs for 14f */
+static const unsigned char interrupt_table_14f[4] = { 15, 14, 11, 10 };
+
+/* Allowed DMA channels for 14f (0 indicates reserved) */
+static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
+
+/* Head/sector mappings allowed by 14f */
+static const struct {
+  unsigned char heads;
+  unsigned char sectors;
+} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } };
+
+#ifndef PORT_OVERRIDE
+/* ??? A probe of address 0x310 screws up NE2000 cards */
+static const unsigned short ultrastor_ports_14f[] = {
+  0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
+};
+#endif
+
+static void ultrastor_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t do_ultrastor_interrupt(int, void *, struct pt_regs *);
+static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
+
+
+/* Always called with host lock held */
+
+static inline int find_and_clear_bit_16(unsigned long *field)
+{
+  int rv;
+
+  if (*field == 0) panic("No free mscp");
+  asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
+      : "=&r" (rv), "=m" (*field) : "1" (*field));
+  return rv;
+}
+
+/* This has been re-implemented with the help of Richard Earnshaw,
+   <rwe@pegasus.esprit.ec.org> and works with gcc-2.5.8 and gcc-2.6.0.
+   The instability noted by jfc below appears to be a bug in
+   gcc-2.5.x when compiling w/o optimization.  --Caleb
+
+   This asm is fragile: it doesn't work without the casts and it may
+   not work without optimization.  Maybe I should add a swap builtin
+   to gcc.  --jfc  */
+static inline unsigned char xchgb(unsigned char reg,
+				  volatile unsigned char *mem)
+{
+  __asm__ ("xchgb %0,%1" : "=q" (reg), "=m" (*mem) : "0" (reg));
+  return reg;
+}
+
+#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
+
+/* Always called with the host lock held */
+static void log_ultrastor_abort(struct ultrastor_config *config,
+				int command)
+{
+  static char fmt[80] = "abort %d (%x); MSCP free pool: %x;";
+  int i;
+
+  for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
+    {
+      fmt[20 + i*2] = ' ';
+      if (! (config->mscp_free & (1 << i)))
+	fmt[21 + i*2] = '0' + config->mscp[i].target_id;
+      else
+	fmt[21 + i*2] = '-';
+    }
+  fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n';
+  fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0;
+  printk(fmt, command, &config->mscp[command], config->mscp_free);
+
+}
+#endif
+
+static int ultrastor_14f_detect(Scsi_Host_Template * tpnt)
+{
+    size_t i;
+    unsigned char in_byte, version_byte = 0;
+    struct config_1 {
+      unsigned char bios_segment: 3;
+      unsigned char removable_disks_as_fixed: 1;
+      unsigned char interrupt: 2;
+    unsigned char dma_channel: 2;
+    } config_1;
+    struct config_2 {
+      unsigned char ha_scsi_id: 3;
+      unsigned char mapping_mode: 2;
+      unsigned char bios_drive_number: 1;
+      unsigned char tfr_port: 2;
+    } config_2;
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+    printk("US14F: detect: called\n");
+#endif
+
+    /* If a 24F has already been configured, don't look for a 14F.  */
+    if (config.bios_segment)
+	return FALSE;
+
+#ifdef PORT_OVERRIDE
+    if(!request_region(PORT_OVERRIDE, 0xc, "ultrastor")) {
+      printk("Ultrastor I/O space already in use\n");
+      return FALSE;
+    };
+    config.port_address = PORT_OVERRIDE;
+#else
+    for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
+      if(!request_region(ultrastor_ports_14f[i], 0x0c, "ultrastor")) continue;
+      config.port_address = ultrastor_ports_14f[i];
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+	printk("US14F: detect: testing port address %03X\n", config.port_address);
+#endif
+
+	in_byte = inb(U14F_PRODUCT_ID(config.port_address));
+	if (in_byte != US14F_PRODUCT_ID_0) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+	    printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
+# else
+	    printk("US14F: detect: no adapter at port %03X\n", config.port_address);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+	    goto out_release_port;
+#else
+	    release_region(config.port_address, 0x0c);
+	    continue;
+#endif
+	}
+	in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1);
+	/* Only upper nibble is significant for Product ID 1 */
+	if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+	    printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
+# else
+	    printk("US14F: detect: no adapter at port %03X\n", config.port_address);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+	    goto out_release_port;
+#else
+	    release_region(config.port_address, 0x0c);
+	    continue;
+#endif
+	}
+	version_byte = in_byte;
+#ifndef PORT_OVERRIDE
+	break;
+    }
+    if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
+# if (ULTRASTOR_DEBUG & UD_DETECT)
+	printk("US14F: detect: no port address found!\n");
+# endif
+	/* all ports probed already released - we can just go straight out */
+	return FALSE;
+    }
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+    printk("US14F: detect: adapter found at port address %03X\n",
+	   config.port_address);
+#endif
+
+    /* Set local doorbell mask to disallow bus reset unless
+       ultrastor_bus_reset is true.  */
+    outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address));
+
+    /* All above tests passed, must be the right thing.  Get some useful
+       info. */
+
+    /* Register the I/O space that we use */
+
+    *(char *)&config_1 = inb(CONFIG(config.port_address + 0));
+    *(char *)&config_2 = inb(CONFIG(config.port_address + 1));
+    config.bios_segment = bios_segment_table[config_1.bios_segment];
+    config.doorbell_address = config.port_address;
+    config.ogm_address = config.port_address + 0x8;
+    config.icm_address = config.port_address + 0xC;
+    config.interrupt = interrupt_table_14f[config_1.interrupt];
+    config.ha_scsi_id = config_2.ha_scsi_id;
+    config.heads = mapping_table[config_2.mapping_mode].heads;
+    config.sectors = mapping_table[config_2.mapping_mode].sectors;
+    config.bios_drive_number = config_2.bios_drive_number;
+    config.subversion = (version_byte & 0x0F);
+    if (config.subversion == U34F)
+	config.dma_channel = 0;
+    else
+	config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
+
+    if (!config.bios_segment) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+	printk("US14F: detect: not detected.\n");
+#endif
+	goto out_release_port;
+    }
+
+    /* Final consistency check, verify previous info. */
+    if (config.subversion != U34F)
+	if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+	    printk("US14F: detect: consistency check failed\n");
+#endif
+           goto out_release_port;
+	}
+
+    /* If we were TRULY paranoid, we could issue a host adapter inquiry
+       command here and verify the data returned.  But frankly, I'm
+       exhausted! */
+
+    /* Finally!  Now I'm satisfied... */
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+    printk("US14F: detect: detect succeeded\n"
+	   "  Port address: %03X\n"
+	   "  BIOS segment: %05X\n"
+	   "  Interrupt: %u\n"
+	   "  DMA channel: %u\n"
+	   "  H/A SCSI ID: %u\n"
+	   "  Subversion: %u\n",
+	   config.port_address, config.bios_segment, config.interrupt,
+	   config.dma_channel, config.ha_scsi_id, config.subversion);
+#endif
+    tpnt->this_id = config.ha_scsi_id;
+    tpnt->unchecked_isa_dma = (config.subversion != U34F);
+
+#if ULTRASTOR_MAX_CMDS > 1
+    config.mscp_free = ~0;
+#endif
+
+    /*
+     * Brrr, &config.mscp[0].SCint->host) it is something magical....
+     * XXX and FIXME
+     */
+    if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", &config.mscp[0].SCint->device->host)) {
+	printk("Unable to allocate IRQ%u for UltraStor controller.\n",
+	       config.interrupt);
+	goto out_release_port;
+    }
+    if (config.dma_channel && request_dma(config.dma_channel,"Ultrastor")) {
+	printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
+	       config.dma_channel);
+	free_irq(config.interrupt, NULL);
+	goto out_release_port;
+    }
+    tpnt->sg_tablesize = ULTRASTOR_14F_MAX_SG;
+    printk("UltraStor driver version" VERSION ".  Using %d SG lists.\n",
+	   ULTRASTOR_14F_MAX_SG);
+
+    return TRUE;
+out_release_port:
+    release_region(config.port_address, 0x0c);
+    return FALSE;
+}
+
+static int ultrastor_24f_detect(Scsi_Host_Template * tpnt)
+{
+  int i;
+  struct Scsi_Host * shpnt = NULL;
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+  printk("US24F: detect");
+#endif
+
+  /* probe each EISA slot at slot address C80 */
+  for (i = 1; i < 15; i++)
+    {
+      unsigned char config_1, config_2;
+      unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT;
+
+      if (inb(addr) != US24F_PRODUCT_ID_0 &&
+	  inb(addr+1) != US24F_PRODUCT_ID_1 &&
+	  inb(addr+2) != US24F_PRODUCT_ID_2)
+	continue;
+
+      config.revision = inb(addr+3);
+      config.slot = i;
+      if (! (inb(addr+4) & 1))
+	{
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+	  printk("U24F: found disabled card in slot %u\n", i);
+#endif
+	  continue;
+	}
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+      printk("U24F: found card in slot %u\n", i);
+#endif
+      config_1 = inb(addr + 5);
+      config.bios_segment = bios_segment_table[config_1 & 7];
+      switch(config_1 >> 4)
+	{
+	case 1:
+	  config.interrupt = 15;
+	  break;
+	case 2:
+	  config.interrupt = 14;
+	  break;
+	case 4:
+	  config.interrupt = 11;
+	  break;
+	case 8:
+	  config.interrupt = 10;
+	  break;
+	default:
+	  printk("U24F: invalid IRQ\n");
+	  return FALSE;
+	}
+
+      /* BIOS addr set */
+      /* base port set */
+      config.port_address = addr;
+      config.doorbell_address = addr + 12;
+      config.ogm_address = addr + 0x17;
+      config.icm_address = addr + 0x1C;
+      config_2 = inb(addr + 7);
+      config.ha_scsi_id = config_2 & 7;
+      config.heads = mapping_table[(config_2 >> 3) & 3].heads;
+      config.sectors = mapping_table[(config_2 >> 3) & 3].sectors;
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+      printk("US24F: detect: detect succeeded\n"
+	     "  Port address: %03X\n"
+	     "  BIOS segment: %05X\n"
+	     "  Interrupt: %u\n"
+	     "  H/A SCSI ID: %u\n",
+	     config.port_address, config.bios_segment,
+	     config.interrupt, config.ha_scsi_id);
+#endif
+      tpnt->this_id = config.ha_scsi_id;
+      tpnt->unchecked_isa_dma = 0;
+      tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
+
+      shpnt = scsi_register(tpnt, 0);
+      if (!shpnt) {
+             printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");
+             free_irq(config.interrupt, do_ultrastor_interrupt);
+             return FALSE;
+      }
+      
+      if (request_irq(config.interrupt, do_ultrastor_interrupt, 0, "Ultrastor", shpnt))
+	{
+	  printk("Unable to allocate IRQ%u for UltraStor controller.\n",
+		 config.interrupt);
+	  return FALSE;
+	}
+
+      shpnt->irq = config.interrupt;
+      shpnt->dma_channel = config.dma_channel;
+      shpnt->io_port = config.port_address;
+
+#if ULTRASTOR_MAX_CMDS > 1
+      config.mscp_free = ~0;
+#endif
+      /* Mark ICM and OGM free */
+      outb(0, addr + 0x16);
+      outb(0, addr + 0x1B);
+
+      /* Set local doorbell mask to disallow bus reset unless
+	 ultrastor_bus_reset is true.  */
+      outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12));
+      outb(0x02, SYS_DOORBELL_MASK(addr+12));
+      printk("UltraStor driver version " VERSION ".  Using %d SG lists.\n",
+	     tpnt->sg_tablesize);
+      return TRUE;
+    }
+  return FALSE;
+}
+
+static int ultrastor_detect(Scsi_Host_Template * tpnt)
+{
+	tpnt->proc_name = "ultrastor";
+	return ultrastor_14f_detect(tpnt) || ultrastor_24f_detect(tpnt);
+}
+
+static int ultrastor_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->dma_channel != 0xff)
+		free_dma(shost->dma_channel);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+static const char *ultrastor_info(struct Scsi_Host * shpnt)
+{
+    static char buf[64];
+
+    if (config.slot)
+      sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u",
+	      config.slot, config.interrupt);
+    else if (config.subversion)
+      sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u",
+	      config.port_address, (int)config.bios_segment,
+	      config.interrupt);
+    else
+      sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u",
+	      config.port_address, (int)config.bios_segment,
+	      config.interrupt, config.dma_channel);
+    return buf;
+}
+
+static inline void build_sg_list(struct mscp *mscp, Scsi_Cmnd *SCpnt)
+{
+	struct scatterlist *sl;
+	long transfer_length = 0;
+	int i, max;
+
+	sl = (struct scatterlist *) SCpnt->request_buffer;
+	max = SCpnt->use_sg;
+	for (i = 0; i < max; i++) {
+		mscp->sglist[i].address = isa_page_to_bus(sl[i].page) + sl[i].offset;
+		mscp->sglist[i].num_bytes = sl[i].length;
+		transfer_length += sl[i].length;
+	}
+	mscp->number_of_sg_list = max;
+	mscp->transfer_data = isa_virt_to_bus(mscp->sglist);
+	/* ??? May not be necessary.  Docs are unclear as to whether transfer
+	   length field is ignored or whether it should be set to the total
+	   number of bytes of the transfer.  */
+	mscp->transfer_data_length = transfer_length;
+}
+
+static int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+    struct mscp *my_mscp;
+#if ULTRASTOR_MAX_CMDS > 1
+    int mscp_index;
+#endif
+    unsigned int status;
+
+    /* Next test is for debugging; "can't happen" */
+    if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0)
+	panic("ultrastor_queuecommand: no free MSCP\n");
+    mscp_index = find_and_clear_bit_16(&config.mscp_free);
+
+    /* Has the command been aborted?  */
+    if (xchgb(0xff, &config.aborted[mscp_index]) != 0)
+      {
+	status = DID_ABORT << 16;
+	goto aborted;
+      }
+
+    my_mscp = &config.mscp[mscp_index];
+
+    *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);
+
+    /* Tape drives don't work properly if the cache is used.  The SCSI
+       READ command for a tape doesn't have a block offset, and the adapter
+       incorrectly assumes that all reads from the tape read the same
+       blocks.  Results will depend on read buffer size and other disk
+       activity. 
+
+       ???  Which other device types should never use the cache?   */
+    my_mscp->ca = SCpnt->device->type != TYPE_TAPE;
+    my_mscp->target_id = SCpnt->device->id;
+    my_mscp->ch_no = 0;
+    my_mscp->lun = SCpnt->device->lun;
+    if (SCpnt->use_sg) {
+	/* Set scatter/gather flag in SCSI command packet */
+	my_mscp->sg = TRUE;
+	build_sg_list(my_mscp, SCpnt);
+    } else {
+	/* Unset scatter/gather flag in SCSI command packet */
+	my_mscp->sg = FALSE;
+	my_mscp->transfer_data = isa_virt_to_bus(SCpnt->request_buffer);
+	my_mscp->transfer_data_length = SCpnt->request_bufflen;
+    }
+    my_mscp->command_link = 0;		/*???*/
+    my_mscp->scsi_command_link_id = 0;	/*???*/
+    my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
+    my_mscp->length_of_scsi_cdbs = SCpnt->cmd_len;
+    memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
+    my_mscp->adapter_status = 0;
+    my_mscp->target_status = 0;
+    my_mscp->sense_data = isa_virt_to_bus(&SCpnt->sense_buffer);
+    my_mscp->done = done;
+    my_mscp->SCint = SCpnt;
+    SCpnt->host_scribble = (unsigned char *)my_mscp;
+
+    /* Find free OGM slot.  On 24F, look for OGM status byte == 0.
+       On 14F and 34F, wait for local interrupt pending flag to clear. 
+       
+       FIXME: now we are using new_eh we should punt here and let the
+       midlayer sort it out */
+
+retry:
+    if (config.slot)
+	while (inb(config.ogm_address - 1) != 0 && config.aborted[mscp_index] == 0xff)
+		barrier();
+
+    /* else??? */
+
+    while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))  && config.aborted[mscp_index] == 0xff)
+    	barrier();
+
+    /* To avoid race conditions, keep the code to write to the adapter
+       atomic.  This simplifies the abort code.  Right now the
+       scsi mid layer has the host_lock already held
+     */
+
+    if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) & (config.slot ? 2 : 1))
+      goto retry;
+
+    status = xchgb(0, &config.aborted[mscp_index]);
+    if (status != 0xff) {
+
+#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
+	printk("USx4F: queuecommand: aborted\n");
+#if ULTRASTOR_MAX_CMDS > 1
+	log_ultrastor_abort(&config, mscp_index);
+#endif
+#endif
+	status <<= 16;
+
+      aborted:
+	set_bit(mscp_index, &config.mscp_free);
+	/* If the driver queues commands, call the done proc here.  Otherwise
+	   return an error.  */
+#if ULTRASTOR_MAX_CMDS > 1
+	SCpnt->result = status;
+	done(SCpnt);
+	return 0;
+#else
+	return status;
+#endif
+    }
+
+    /* Store pointer in OGM address bytes */
+    outl(isa_virt_to_bus(my_mscp), config.ogm_address);
+
+    /* Issue OGM interrupt */
+    if (config.slot) {
+	/* Write OGM command register on 24F */
+	outb(1, config.ogm_address - 1);
+	outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
+    } else {
+	outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
+    }
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+    printk("USx4F: queuecommand: returning\n");
+#endif
+
+    return 0;
+}
+
+/* This code must deal with 2 cases:
+
+   1. The command has not been written to the OGM.  In this case, set
+   the abort flag and return.
+
+   2. The command has been written to the OGM and is stuck somewhere in
+   the adapter.
+
+   2a.  On a 24F, ask the adapter to abort the command.  It will interrupt
+   when it does.
+
+   2b.  Call the command's done procedure.
+
+ */
+
+static int ultrastor_abort(Scsi_Cmnd *SCpnt)
+{
+#if ULTRASTOR_DEBUG & UD_ABORT
+    char out[108];
+    unsigned char icm_status = 0, ogm_status = 0;
+    unsigned int icm_addr = 0, ogm_addr = 0;
+#endif
+    unsigned int mscp_index;
+    unsigned char old_aborted;
+    unsigned long flags;
+    void (*done)(Scsi_Cmnd *);
+    struct Scsi_Host *host = SCpnt->device->host;
+
+    if(config.slot) 
+      return FAILED;  /* Do not attempt an abort for the 24f */
+      
+    /* Simple consistency checking */
+    if(!SCpnt->host_scribble)
+      return FAILED;
+
+    mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
+    if (mscp_index >= ULTRASTOR_MAX_CMDS)
+	panic("Ux4F aborting invalid MSCP");
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+    if (config.slot)
+      {
+	int port0 = (config.slot << 12) | 0xc80;
+	int i;
+	unsigned long flags;
+	
+	spin_lock_irqsave(host->host_lock, flags);
+	strcpy(out, "OGM %d:%x ICM %d:%x ports:  ");
+	for (i = 0; i < 16; i++)
+	  {
+	    unsigned char p = inb(port0 + i);
+	    out[28 + i * 3] = "0123456789abcdef"[p >> 4];
+	    out[29 + i * 3] = "0123456789abcdef"[p & 15];
+	    out[30 + i * 3] = ' ';
+	  }
+	out[28 + i * 3] = '\n';
+	out[29 + i * 3] = 0;
+	ogm_status = inb(port0 + 22);
+	ogm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 23));
+	icm_status = inb(port0 + 27);
+	icm_addr = (unsigned int)isa_bus_to_virt(inl(port0 + 28));
+	spin_lock_irqsave(host->host_lock, flags);
+      }
+
+    /* First check to see if an interrupt is pending.  I suspect the SiS
+       chipset loses interrupts.  (I also suspect is mangles data, but
+       one bug at a time... */
+    if (config.slot ? inb(config.icm_address - 1) == 2 :
+	(inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+      {
+	printk("Ux4F: abort while completed command pending\n");
+	
+	spin_lock_irqsave(host->host_lock, flags);
+	/* FIXME: Ewww... need to think about passing host around properly */
+	ultrastor_interrupt(0, NULL, NULL);
+	spin_unlock_irqrestore(host->host_lock, flags);
+	return SUCCESS;
+      }
+#endif
+
+    old_aborted = xchgb(DID_ABORT, &config.aborted[mscp_index]);
+
+    /* aborted == 0xff is the signal that queuecommand has not yet sent
+       the command.  It will notice the new abort flag and fail.  */
+    if (old_aborted == 0xff)
+	return SUCCESS;
+
+    /* On 24F, send an abort MSCP request.  The adapter will interrupt
+       and the interrupt handler will call done.  */
+    if (config.slot && inb(config.ogm_address - 1) == 0)
+      {
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	outl(isa_virt_to_bus(&config.mscp[mscp_index]), config.ogm_address);
+	udelay(8);
+	outb(0x80, config.ogm_address - 1);
+	outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
+#if ULTRASTOR_DEBUG & UD_ABORT
+	log_ultrastor_abort(&config, mscp_index);
+	printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
+#endif
+	spin_unlock_irqrestore(host->host_lock, flags);
+	/* FIXME: add a wait for the abort to complete */
+	return SUCCESS;
+      }
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+    log_ultrastor_abort(&config, mscp_index);
+#endif
+
+    /* Can't request a graceful abort.  Either this is not a 24F or
+       the OGM is busy.  Don't free the command -- the adapter might
+       still be using it.  Setting SCint = 0 causes the interrupt
+       handler to ignore the command.  */
+
+    /* FIXME - devices that implement soft resets will still be running
+       the command after a bus reset.  We would probably rather leave
+       the command in the queue.  The upper level code will automatically
+       leave the command in the active state instead of requeueing it. ERY */
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+    if (config.mscp[mscp_index].SCint != SCpnt)
+	printk("abort: command mismatch, %p != %p\n",
+	       config.mscp[mscp_index].SCint, SCpnt);
+#endif
+    if (config.mscp[mscp_index].SCint == 0)
+	return SCSI_ABORT_NOT_RUNNING;
+
+    if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
+    config.mscp[mscp_index].SCint = NULL;
+    done = config.mscp[mscp_index].done;
+    config.mscp[mscp_index].done = NULL;
+    SCpnt->result = DID_ABORT << 16;
+    
+    /* Take the host lock to guard against scsi layer re-entry */
+    spin_lock_irqsave(host->host_lock, flags);
+    done(SCpnt);
+    spin_unlock_irqrestore(host->host_lock, flags);
+
+    /* Need to set a timeout here in case command never completes.  */
+    return SUCCESS;
+}
+
+static int ultrastor_host_reset(Scsi_Cmnd * SCpnt)
+{
+    unsigned long flags;
+    int i;
+    struct Scsi_Host *host = SCpnt->device->host;
+    
+#if (ULTRASTOR_DEBUG & UD_RESET)
+    printk("US14F: reset: called\n");
+#endif
+
+    if(config.slot)
+    	return FAILED;
+
+    spin_lock_irqsave(host->host_lock, flags);
+    /* Reset the adapter and SCSI bus.  The SCSI bus reset can be
+       inhibited by clearing ultrastor_bus_reset before probe.  */
+    outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address));
+    if (config.slot)
+      {
+	outb(0, config.ogm_address - 1);
+	outb(0, config.icm_address - 1);
+      }
+
+#if ULTRASTOR_MAX_CMDS == 1
+    if (config.mscp_busy && config.mscp->done && config.mscp->SCint)
+      {
+	config.mscp->SCint->result = DID_RESET << 16;
+	config.mscp->done(config.mscp->SCint);
+      }
+    config.mscp->SCint = 0;
+#else
+    for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
+      {
+	if (! (config.mscp_free & (1 << i)) &&
+	    config.mscp[i].done && config.mscp[i].SCint)
+	  {
+	    config.mscp[i].SCint->result = DID_RESET << 16;
+	    config.mscp[i].done(config.mscp[i].SCint);
+	    config.mscp[i].done = NULL;
+	  }
+	config.mscp[i].SCint = NULL;
+      }
+#endif
+
+    /* FIXME - if the device implements soft resets, then the command
+       will still be running.  ERY  
+       
+       Even bigger deal with new_eh! 
+     */
+
+    memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
+#if ULTRASTOR_MAX_CMDS == 1
+    config.mscp_busy = 0;
+#else
+    config.mscp_free = ~0;
+#endif
+
+    spin_unlock_irqrestore(host->host_lock, flags);
+    return SCSI_RESET_SUCCESS;
+
+}
+
+int ultrastor_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+		sector_t capacity, int * dkinfo)
+{
+    int size = capacity;
+    unsigned int s = config.heads * config.sectors;
+
+    dkinfo[0] = config.heads;
+    dkinfo[1] = config.sectors;
+    dkinfo[2] = size / s;	/* Ignore partial cylinders */
+#if 0
+    if (dkinfo[2] > 1024)
+	dkinfo[2] = 1024;
+#endif
+    return 0;
+}
+
+static void ultrastor_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    unsigned int status;
+#if ULTRASTOR_MAX_CMDS > 1
+    unsigned int mscp_index;
+#endif
+    struct mscp *mscp;
+    void (*done)(Scsi_Cmnd *);
+    Scsi_Cmnd *SCtmp;
+
+#if ULTRASTOR_MAX_CMDS == 1
+    mscp = &config.mscp[0];
+#else
+    mscp = (struct mscp *)isa_bus_to_virt(inl(config.icm_address));
+    mscp_index = mscp - config.mscp;
+    if (mscp_index >= ULTRASTOR_MAX_CMDS) {
+	printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
+	/* A command has been lost.  Reset and report an error
+	   for all commands.  */
+	ultrastor_host_reset(dev_id);
+	return;
+    }
+#endif
+
+    /* Clean ICM slot (set ICMINT bit to 0) */
+    if (config.slot) {
+	unsigned char icm_status = inb(config.icm_address - 1);
+#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT)
+	if (icm_status != 1 && icm_status != 2)
+	    printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status,
+		   mscp_index, (unsigned int) mscp);
+#endif
+	/* The manual says clear interrupt then write 0 to ICM status.
+	   This seems backwards, but I'll do it anyway.  --jfc */
+	outb(2, SYS_DOORBELL_INTR(config.doorbell_address));
+	outb(0, config.icm_address - 1);
+	if (icm_status == 4) {
+	    printk("UltraStor abort command failed\n");
+	    return;
+	}
+	if (icm_status == 3) {
+	    void (*done)(Scsi_Cmnd *) = mscp->done;
+	    if (done) {
+		mscp->done = NULL;
+		mscp->SCint->result = DID_ABORT << 16;
+		done(mscp->SCint);
+	    }
+	    return;
+	}
+    } else {
+	outb(1, SYS_DOORBELL_INTR(config.doorbell_address));
+    }
+
+    SCtmp = mscp->SCint;
+    mscp->SCint = NULL;
+
+    if (SCtmp == 0)
+      {
+#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
+	printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
+#endif	
+#if ULTRASTOR_MAX_CMDS == 1
+	config.mscp_busy = FALSE;
+#else
+	set_bit(mscp_index, &config.mscp_free);
+#endif
+	config.aborted[mscp_index] = 0;
+	return;
+      }
+
+    /* Save done locally and zero before calling.  This is needed as
+       once we call done, we may get another command queued before this
+       interrupt service routine can return. */
+    done = mscp->done;
+    mscp->done = NULL;
+
+    /* Let the higher levels know that we're done */
+    switch (mscp->adapter_status)
+      {
+      case 0:
+	status = DID_OK << 16;
+	break;
+      case 0x01:	/* invalid command */
+      case 0x02:	/* invalid parameters */
+      case 0x03:	/* invalid data list */
+      default:
+	status = DID_ERROR << 16;
+	break;
+      case 0x84:	/* SCSI bus abort */
+	status = DID_ABORT << 16;
+	break;
+      case 0x91:
+	status = DID_TIME_OUT << 16;
+	break;
+      }
+
+    SCtmp->result = status | mscp->target_status;
+
+    SCtmp->host_scribble = NULL;
+
+    /* Free up mscp block for next command */
+#if ULTRASTOR_MAX_CMDS == 1
+    config.mscp_busy = FALSE;
+#else
+    set_bit(mscp_index, &config.mscp_free);
+#endif
+
+#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
+    if (config.aborted[mscp_index])
+	printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n",
+	       mscp_index, (unsigned int) mscp, config.aborted[mscp_index]);
+#endif
+    config.aborted[mscp_index] = 0;
+
+    if (done)
+	done(SCtmp);
+    else
+	printk("US14F: interrupt: unexpected interrupt\n");
+
+    if (config.slot ? inb(config.icm_address - 1) :
+       (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+#if (ULTRASTOR_DEBUG & UD_MULTI_CMD)
+      printk("Ux4F: multiple commands completed\n");
+#else
+      ;
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
+    printk("USx4F: interrupt: returning\n");
+#endif
+}
+
+static irqreturn_t do_ultrastor_interrupt(int irq, void *dev_id,
+						struct pt_regs *regs)
+{
+    unsigned long flags;
+    struct Scsi_Host *dev = dev_id;
+    
+    spin_lock_irqsave(dev->host_lock, flags);
+    ultrastor_interrupt(irq, dev_id, regs);
+    spin_unlock_irqrestore(dev->host_lock, flags);
+    return IRQ_HANDLED;
+}
+
+MODULE_LICENSE("GPL");
+
+static Scsi_Host_Template driver_template = {
+	.name              = "UltraStor 14F/24F/34F",
+	.detect            = ultrastor_detect,
+	.release	   = ultrastor_release,
+	.info              = ultrastor_info,
+	.queuecommand      = ultrastor_queuecommand,
+	.eh_abort_handler  = ultrastor_abort,
+	.eh_host_reset_handler  = ultrastor_host_reset,	
+	.bios_param        = ultrastor_biosparam,
+	.can_queue         = ULTRASTOR_MAX_CMDS,
+	.sg_tablesize      = ULTRASTOR_14F_MAX_SG,
+	.cmd_per_lun       = ULTRASTOR_MAX_CMDS_PER_LUN,
+	.unchecked_isa_dma = 1,
+	.use_clustering    = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
new file mode 100644
index 0000000..0a0f8df
--- /dev/null
+++ b/drivers/scsi/ultrastor.h
@@ -0,0 +1,79 @@
+/*
+ *	ultrastor.c	(C) 1991 David B. Gentzel
+ *	Low-level scsi driver for UltraStor 14F
+ *	by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ *	    (gentzel@nova.enet.dec.com)
+ *  scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
+ *  24F support by John F. Carr (jfc@athena.mit.edu)
+ *    John's work modified by Caleb Epstein (cae@jpmorgan.com) and 
+ *    Eric Youngdale (eric@tantalus.nrl.navy.mil).
+ *	Thanks to UltraStor for providing the necessary documentation
+ */
+
+#ifndef _ULTRASTOR_H
+#define _ULTRASTOR_H
+
+static int ultrastor_detect(Scsi_Host_Template *);
+static const char *ultrastor_info(struct Scsi_Host * shpnt);
+static int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+static int ultrastor_abort(Scsi_Cmnd *);
+static int ultrastor_host_reset(Scsi_Cmnd *);
+static int ultrastor_biosparam(struct scsi_device *, struct block_device *, sector_t, int *);
+
+
+#define ULTRASTOR_14F_MAX_SG 16
+#define ULTRASTOR_24F_MAX_SG 33
+
+#define ULTRASTOR_MAX_CMDS_PER_LUN 5
+#define ULTRASTOR_MAX_CMDS 16
+
+#define ULTRASTOR_24F_PORT 0xC80
+
+
+#ifdef ULTRASTOR_PRIVATE
+
+#define UD_ABORT	0x0001
+#define UD_COMMAND	0x0002
+#define UD_DETECT	0x0004
+#define UD_INTERRUPT	0x0008
+#define UD_RESET	0x0010
+#define UD_MULTI_CMD	0x0020
+#define UD_CSIR		0x0040
+#define UD_ERROR	0x0080
+
+/* #define PORT_OVERRIDE 0x330 */
+
+/* Values for the PRODUCT_ID ports for the 14F */
+#define US14F_PRODUCT_ID_0 0x56
+#define US14F_PRODUCT_ID_1 0x40		/* NOTE: Only upper nibble is used */
+
+#define US24F_PRODUCT_ID_0 0x56
+#define US24F_PRODUCT_ID_1 0x63
+#define US24F_PRODUCT_ID_2 0x02
+
+/* Subversion values */
+#define U14F 0
+#define U34F 1
+
+/* MSCP field values */
+
+/* Opcode */
+#define OP_HOST_ADAPTER 0x1
+#define OP_SCSI 0x2
+#define OP_RESET 0x4
+
+/* Date Transfer Direction */
+#define DTD_SCSI 0x0
+#define DTD_IN 0x1
+#define DTD_OUT 0x2
+#define DTD_NONE 0x3
+
+/* Host Adapter command subcodes */
+#define HA_CMD_INQUIRY 0x1
+#define HA_CMD_SELF_DIAG 0x2
+#define HA_CMD_READ_BUFF 0x3
+#define HA_CMD_WRITE_BUFF 0x4
+
+#endif
+
+#endif
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
new file mode 100644
index 0000000..5754445
--- /dev/null
+++ b/drivers/scsi/wd33c93.c
@@ -0,0 +1,2077 @@
+/*
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+/*
+ * Drew Eckhardt's excellent 'Generic NCR5380' sources from Linux-PC
+ * provided much of the inspiration and some of the code for this
+ * driver. Everything I know about Amiga DMA was gleaned from careful
+ * reading of Hamish Mcdonald's original wd33c93 driver; in fact, I
+ * borrowed shamelessly from all over that source. Thanks Hamish!
+ *
+ * _This_ driver is (I feel) an improvement over the old one in
+ * several respects:
+ *
+ *    -  Target Disconnection/Reconnection  is now supported. Any
+ *          system with more than one device active on the SCSI bus
+ *          will benefit from this. The driver defaults to what I
+ *          call 'adaptive disconnect' - meaning that each command
+ *          is evaluated individually as to whether or not it should
+ *          be run with the option to disconnect/reselect (if the
+ *          device chooses), or as a "SCSI-bus-hog".
+ *
+ *    -  Synchronous data transfers are now supported. Because of
+ *          a few devices that choke after telling the driver that
+ *          they can do sync transfers, we don't automatically use
+ *          this faster protocol - it can be enabled via the command-
+ *          line on a device-by-device basis.
+ *
+ *    -  Runtime operating parameters can now be specified through
+ *       the 'amiboot' or the 'insmod' command line. For amiboot do:
+ *          "amiboot [usual stuff] wd33c93=blah,blah,blah"
+ *       The defaults should be good for most people. See the comment
+ *       for 'setup_strings' below for more details.
+ *
+ *    -  The old driver relied exclusively on what the Western Digital
+ *          docs call "Combination Level 2 Commands", which are a great
+ *          idea in that the CPU is relieved of a lot of interrupt
+ *          overhead. However, by accepting a certain (user-settable)
+ *          amount of additional interrupts, this driver achieves
+ *          better control over the SCSI bus, and data transfers are
+ *          almost as fast while being much easier to define, track,
+ *          and debug.
+ *
+ *
+ * TODO:
+ *       more speed. linked commands.
+ *
+ *
+ * People with bug reports, wish-lists, complaints, comments,
+ * or improvements are asked to pah-leeez email me (John Shifflett)
+ * at john@geolog.com or jshiffle@netcom.com! I'm anxious to get
+ * this thing into as good a shape as possible, and I'm positive
+ * there are lots of lurking bugs and "Stupid Places".
+ *
+ * Updates:
+ *
+ * Added support for pre -A chips, which don't have advanced features
+ * and will generate CSR_RESEL rather than CSR_RESEL_AM.
+ *	Richard Hirst <richard@sleepie.demon.co.uk>  August 2000
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/blkdev.h>
+#include <asm/irq.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+
+#include "wd33c93.h"
+
+
+#define WD33C93_VERSION    "1.26"
+#define WD33C93_DATE       "22/Feb/2003"
+
+MODULE_AUTHOR("John Shifflett");
+MODULE_DESCRIPTION("Generic WD33C93 SCSI driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * 'setup_strings' is a single string used to pass operating parameters and
+ * settings from the kernel/module command-line to the driver. 'setup_args[]'
+ * is an array of strings that define the compile-time default values for
+ * these settings. If Linux boots with an amiboot or insmod command-line,
+ * those settings are combined with 'setup_args[]'. Note that amiboot
+ * command-lines are prefixed with "wd33c93=" while insmod uses a
+ * "setup_strings=" prefix. The driver recognizes the following keywords
+ * (lower case required) and arguments:
+ *
+ * -  nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with
+ *                    the 7 possible SCSI devices. Set a bit to negotiate for
+ *                    asynchronous transfers on that device. To maintain
+ *                    backwards compatibility, a command-line such as
+ *                    "wd33c93=255" will be automatically translated to
+ *                    "wd33c93=nosync:0xff".
+ * -  nodma:x        -x = 1 to disable DMA, x = 0 to enable it. Argument is
+ *                    optional - if not present, same as "nodma:1".
+ * -  period:ns      -ns is the minimum # of nanoseconds in a SCSI data transfer
+ *                    period. Default is 500; acceptable values are 250 - 1000.
+ * -  disconnect:x   -x = 0 to never allow disconnects, 2 to always allow them.
+ *                    x = 1 does 'adaptive' disconnects, which is the default
+ *                    and generally the best choice.
+ * -  debug:x        -If 'DEBUGGING_ON' is defined, x is a bit mask that causes
+ *                    various types of debug output to printed - see the DB_xxx
+ *                    defines in wd33c93.h
+ * -  clock:x        -x = clock input in MHz for WD33c93 chip. Normal values
+ *                    would be from 8 through 20. Default is 8.
+ * -  next           -No argument. Used to separate blocks of keywords when
+ *                    there's more than one host adapter in the system.
+ *
+ * Syntax Notes:
+ * -  Numeric arguments can be decimal or the '0x' form of hex notation. There
+ *    _must_ be a colon between a keyword and its numeric argument, with no
+ *    spaces.
+ * -  Keywords are separated by commas, no spaces, in the standard kernel
+ *    command-line manner.
+ * -  A keyword in the 'nth' comma-separated command-line member will overwrite
+ *    the 'nth' element of setup_args[]. A blank command-line member (in
+ *    other words, a comma with no preceding keyword) will _not_ overwrite
+ *    the corresponding setup_args[] element.
+ * -  If a keyword is used more than once, the first one applies to the first
+ *    SCSI host found, the second to the second card, etc, unless the 'next'
+ *    keyword is used to change the order.
+ *
+ * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'):
+ * -  wd33c93=nosync:255
+ * -  wd33c93=nodma
+ * -  wd33c93=nodma:1
+ * -  wd33c93=disconnect:2,nosync:0x08,period:250
+ * -  wd33c93=debug:0x1c
+ */
+
+/* Normally, no defaults are specified */
+static char *setup_args[] = { "", "", "", "", "", "", "", "", "" };
+
+static char *setup_strings;
+module_param(setup_strings, charp, 0);
+
+static void wd33c93_execute(struct Scsi_Host *instance);
+
+#ifdef CONFIG_WD33C93_PIO
+static inline uchar
+read_wd33c93(const wd33c93_regs regs, uchar reg_num)
+{
+	uchar data;
+
+	outb(reg_num, regs.SASR);
+	data = inb(regs.SCMD);
+	return data;
+}
+
+static inline unsigned long
+read_wd33c93_count(const wd33c93_regs regs)
+{
+	unsigned long value;
+
+	outb(WD_TRANSFER_COUNT_MSB, regs.SASR);
+	value = inb(regs.SCMD) << 16;
+	value |= inb(regs.SCMD) << 8;
+	value |= inb(regs.SCMD);
+	return value;
+}
+
+static inline uchar
+read_aux_stat(const wd33c93_regs regs)
+{
+	return inb(regs.SASR);
+}
+
+static inline void
+write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
+{
+      outb(reg_num, regs.SASR);
+      outb(value, regs.SCMD);
+}
+
+static inline void
+write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
+{
+	outb(WD_TRANSFER_COUNT_MSB, regs.SASR);
+	outb((value >> 16) & 0xff, regs.SCMD);
+	outb((value >> 8) & 0xff, regs.SCMD);
+	outb( value & 0xff, regs.SCMD);
+}
+
+#define write_wd33c93_cmd(regs, cmd) \
+	write_wd33c93((regs), WD_COMMAND, (cmd))
+
+static inline void
+write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
+{
+	int i;
+
+	outb(WD_CDB_1, regs.SASR);
+	for (i=0; i<len; i++)
+		outb(cmnd[i], regs.SCMD);
+}
+
+#else /* CONFIG_WD33C93_PIO */
+static inline uchar
+read_wd33c93(const wd33c93_regs regs, uchar reg_num)
+{
+	*regs.SASR = reg_num;
+	mb();
+	return (*regs.SCMD);
+}
+
+static unsigned long
+read_wd33c93_count(const wd33c93_regs regs)
+{
+	unsigned long value;
+
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	mb();
+	value = *regs.SCMD << 16;
+	value |= *regs.SCMD << 8;
+	value |= *regs.SCMD;
+	mb();
+	return value;
+}
+
+static inline uchar
+read_aux_stat(const wd33c93_regs regs)
+{
+	return *regs.SASR;
+}
+
+static inline void
+write_wd33c93(const wd33c93_regs regs, uchar reg_num, uchar value)
+{
+	*regs.SASR = reg_num;
+	mb();
+	*regs.SCMD = value;
+	mb();
+}
+
+static void
+write_wd33c93_count(const wd33c93_regs regs, unsigned long value)
+{
+	*regs.SASR = WD_TRANSFER_COUNT_MSB;
+	mb();
+	*regs.SCMD = value >> 16;
+	*regs.SCMD = value >> 8;
+	*regs.SCMD = value;
+	mb();
+}
+
+static inline void
+write_wd33c93_cmd(const wd33c93_regs regs, uchar cmd)
+{
+	*regs.SASR = WD_COMMAND;
+	mb();
+	*regs.SCMD = cmd;
+	mb();
+}
+
+static inline void
+write_wd33c93_cdb(const wd33c93_regs regs, uint len, uchar cmnd[])
+{
+	int i;
+
+	*regs.SASR = WD_CDB_1;
+	for (i = 0; i < len; i++)
+		*regs.SCMD = cmnd[i];
+}
+#endif /* CONFIG_WD33C93_PIO */
+
+static inline uchar
+read_1_byte(const wd33c93_regs regs)
+{
+	uchar asr;
+	uchar x = 0;
+
+	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO | 0x80);
+	do {
+		asr = read_aux_stat(regs);
+		if (asr & ASR_DBR)
+			x = read_wd33c93(regs, WD_DATA);
+	} while (!(asr & ASR_INT));
+	return x;
+}
+
+static struct sx_period sx_table[] = {
+	{1, 0x20},
+	{252, 0x20},
+	{376, 0x30},
+	{500, 0x40},
+	{624, 0x50},
+	{752, 0x60},
+	{876, 0x70},
+	{1000, 0x00},
+	{0, 0}
+};
+
+static int
+round_period(unsigned int period)
+{
+	int x;
+
+	for (x = 1; sx_table[x].period_ns; x++) {
+		if ((period <= sx_table[x - 0].period_ns) &&
+		    (period > sx_table[x - 1].period_ns)) {
+			return x;
+		}
+	}
+	return 7;
+}
+
+static uchar
+calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+	uchar result;
+
+	period *= 4;		/* convert SDTR code to ns */
+	result = sx_table[round_period(period)].reg_value;
+	result |= (offset < OPTIMUM_SX_OFF) ? offset : OPTIMUM_SX_OFF;
+	return result;
+}
+
+int
+wd33c93_queuecommand(struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *))
+{
+	struct WD33C93_hostdata *hostdata;
+	struct scsi_cmnd *tmp;
+
+	hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
+
+	DB(DB_QUEUE_COMMAND,
+	   printk("Q-%d-%02x-%ld( ", cmd->device->id, cmd->cmnd[0], cmd->pid))
+
+/* Set up a few fields in the scsi_cmnd structure for our own use:
+ *  - host_scribble is the pointer to the next cmd in the input queue
+ *  - scsi_done points to the routine we call when a cmd is finished
+ *  - result is what you'd expect
+ */
+	cmd->host_scribble = NULL;
+	cmd->scsi_done = done;
+	cmd->result = 0;
+
+/* We use the Scsi_Pointer structure that's included with each command
+ * as a scratchpad (as it's intended to be used!). The handy thing about
+ * the SCp.xxx fields is that they're always associated with a given
+ * cmd, and are preserved across disconnect-reselect. This means we
+ * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages
+ * if we keep all the critical pointers and counters in SCp:
+ *  - SCp.ptr is the pointer into the RAM buffer
+ *  - SCp.this_residual is the size of that buffer
+ *  - SCp.buffer points to the current scatter-gather buffer
+ *  - SCp.buffers_residual tells us how many S.G. buffers there are
+ *  - SCp.have_data_in is not used
+ *  - SCp.sent_command is not used
+ *  - SCp.phase records this command's SRCID_ER bit setting
+ */
+
+	if (cmd->use_sg) {
+		cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+		cmd->SCp.buffers_residual = cmd->use_sg - 1;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
+		    cmd->SCp.buffer->offset;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+	} else {
+		cmd->SCp.buffer = NULL;
+		cmd->SCp.buffers_residual = 0;
+		cmd->SCp.ptr = (char *) cmd->request_buffer;
+		cmd->SCp.this_residual = cmd->request_bufflen;
+	}
+
+/* WD docs state that at the conclusion of a "LEVEL2" command, the
+ * status byte can be retrieved from the LUN register. Apparently,
+ * this is the case only for *uninterrupted* LEVEL2 commands! If
+ * there are any unexpected phases entered, even if they are 100%
+ * legal (different devices may choose to do things differently),
+ * the LEVEL2 command sequence is exited. This often occurs prior
+ * to receiving the status byte, in which case the driver does a
+ * status phase interrupt and gets the status byte on its own.
+ * While such a command can then be "resumed" (ie restarted to
+ * finish up as a LEVEL2 command), the LUN register will NOT be
+ * a valid status byte at the command's conclusion, and we must
+ * use the byte obtained during the earlier interrupt. Here, we
+ * preset SCp.Status to an illegal value (0xff) so that when
+ * this command finally completes, we can tell where the actual
+ * status byte is stored.
+ */
+
+	cmd->SCp.Status = ILLEGAL_STATUS_BYTE;
+
+	/*
+	 * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE
+	 * commands are added to the head of the queue so that the desired
+	 * sense data is not lost before REQUEST_SENSE executes.
+	 */
+
+	spin_lock_irq(&hostdata->lock);
+
+	if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+		cmd->host_scribble = (uchar *) hostdata->input_Q;
+		hostdata->input_Q = cmd;
+	} else {		/* find the end of the queue */
+		for (tmp = (struct scsi_cmnd *) hostdata->input_Q;
+		     tmp->host_scribble;
+		     tmp = (struct scsi_cmnd *) tmp->host_scribble) ;
+		tmp->host_scribble = (uchar *) cmd;
+	}
+
+/* We know that there's at least one command in 'input_Q' now.
+ * Go see if any of them are runnable!
+ */
+
+	wd33c93_execute(cmd->device->host);
+
+	DB(DB_QUEUE_COMMAND, printk(")Q-%ld ", cmd->pid))
+
+	spin_unlock_irq(&hostdata->lock);
+	return 0;
+}
+
+/*
+ * This routine attempts to start a scsi command. If the host_card is
+ * already connected, we give up immediately. Otherwise, look through
+ * the input_Q, using the first command we find that's intended
+ * for a currently non-busy target/lun.
+ *
+ * wd33c93_execute() is always called with interrupts disabled or from
+ * the wd33c93_intr itself, which means that a wd33c93 interrupt
+ * cannot occur while we are in here.
+ */
+static void
+wd33c93_execute(struct Scsi_Host *instance)
+{
+	struct WD33C93_hostdata *hostdata =
+	    (struct WD33C93_hostdata *) instance->hostdata;
+	const wd33c93_regs regs = hostdata->regs;
+	struct scsi_cmnd *cmd, *prev;
+
+	DB(DB_EXECUTE, printk("EX("))
+	if (hostdata->selecting || hostdata->connected) {
+		DB(DB_EXECUTE, printk(")EX-0 "))
+		return;
+	}
+
+	/*
+	 * Search through the input_Q for a command destined
+	 * for an idle target/lun.
+	 */
+
+	cmd = (struct scsi_cmnd *) hostdata->input_Q;
+	prev = 0;
+	while (cmd) {
+		if (!(hostdata->busy[cmd->device->id] & (1 << cmd->device->lun)))
+			break;
+		prev = cmd;
+		cmd = (struct scsi_cmnd *) cmd->host_scribble;
+	}
+
+	/* quit if queue empty or all possible targets are busy */
+
+	if (!cmd) {
+		DB(DB_EXECUTE, printk(")EX-1 "))
+		return;
+	}
+
+	/*  remove command from queue */
+
+	if (prev)
+		prev->host_scribble = cmd->host_scribble;
+	else
+		hostdata->input_Q = (struct scsi_cmnd *) cmd->host_scribble;
+
+#ifdef PROC_STATISTICS
+	hostdata->cmd_cnt[cmd->device->id]++;
+#endif
+
+	/*
+	 * Start the selection process
+	 */
+
+	if (cmd->sc_data_direction == DMA_TO_DEVICE)
+		write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
+	else
+		write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id | DSTID_DPD);
+
+/* Now we need to figure out whether or not this command is a good
+ * candidate for disconnect/reselect. We guess to the best of our
+ * ability, based on a set of hierarchical rules. When several
+ * devices are operating simultaneously, disconnects are usually
+ * an advantage. In a single device system, or if only 1 device
+ * is being accessed, transfers usually go faster if disconnects
+ * are not allowed:
+ *
+ * + Commands should NEVER disconnect if hostdata->disconnect =
+ *   DIS_NEVER (this holds for tape drives also), and ALWAYS
+ *   disconnect if hostdata->disconnect = DIS_ALWAYS.
+ * + Tape drive commands should always be allowed to disconnect.
+ * + Disconnect should be allowed if disconnected_Q isn't empty.
+ * + Commands should NOT disconnect if input_Q is empty.
+ * + Disconnect should be allowed if there are commands in input_Q
+ *   for a different target/lun. In this case, the other commands
+ *   should be made disconnect-able, if not already.
+ *
+ * I know, I know - this code would flunk me out of any
+ * "C Programming 101" class ever offered. But it's easy
+ * to change around and experiment with for now.
+ */
+
+	cmd->SCp.phase = 0;	/* assume no disconnect */
+	if (hostdata->disconnect == DIS_NEVER)
+		goto no;
+	if (hostdata->disconnect == DIS_ALWAYS)
+		goto yes;
+	if (cmd->device->type == 1)	/* tape drive? */
+		goto yes;
+	if (hostdata->disconnected_Q)	/* other commands disconnected? */
+		goto yes;
+	if (!(hostdata->input_Q))	/* input_Q empty? */
+		goto no;
+	for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev;
+	     prev = (struct scsi_cmnd *) prev->host_scribble) {
+		if ((prev->device->id != cmd->device->id) ||
+		    (prev->device->lun != cmd->device->lun)) {
+			for (prev = (struct scsi_cmnd *) hostdata->input_Q; prev;
+			     prev = (struct scsi_cmnd *) prev->host_scribble)
+				prev->SCp.phase = 1;
+			goto yes;
+		}
+	}
+
+	goto no;
+
+ yes:
+	cmd->SCp.phase = 1;
+
+#ifdef PROC_STATISTICS
+	hostdata->disc_allowed_cnt[cmd->device->id]++;
+#endif
+
+ no:
+
+	write_wd33c93(regs, WD_SOURCE_ID, ((cmd->SCp.phase) ? SRCID_ER : 0));
+
+	write_wd33c93(regs, WD_TARGET_LUN, cmd->device->lun);
+	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
+		      hostdata->sync_xfer[cmd->device->id]);
+	hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
+
+	if ((hostdata->level2 == L2_NONE) ||
+	    (hostdata->sync_stat[cmd->device->id] == SS_UNSET)) {
+
+		/*
+		 * Do a 'Select-With-ATN' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    CSR_SELECT:    success - proceed.
+		 */
+
+		hostdata->selecting = cmd;
+
+/* Every target has its own synchronous transfer setting, kept in the
+ * sync_xfer array, and a corresponding status byte in sync_stat[].
+ * Each target's sync_stat[] entry is initialized to SX_UNSET, and its
+ * sync_xfer[] entry is initialized to the default/safe value. SS_UNSET
+ * means that the parameters are undetermined as yet, and that we
+ * need to send an SDTR message to this device after selection is
+ * complete: We set SS_FIRST to tell the interrupt routine to do so.
+ * If we've been asked not to try synchronous transfers on this
+ * target (and _all_ luns within it), we'll still send the SDTR message
+ * later, but at that time we'll negotiate for async by specifying a
+ * sync fifo depth of 0.
+ */
+		if (hostdata->sync_stat[cmd->device->id] == SS_UNSET)
+			hostdata->sync_stat[cmd->device->id] = SS_FIRST;
+		hostdata->state = S_SELECTING;
+		write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
+		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN);
+	} else {
+
+		/*
+		 * Do a 'Select-With-ATN-Xfer' command. This will end with
+		 * one of the following interrupts:
+		 *    CSR_RESEL_AM:  failure - can try again later.
+		 *    CSR_TIMEOUT:   failure - give up.
+		 *    anything else: success - proceed.
+		 */
+
+		hostdata->connected = cmd;
+		write_wd33c93(regs, WD_COMMAND_PHASE, 0);
+
+		/* copy command_descriptor_block into WD chip
+		 * (take advantage of auto-incrementing)
+		 */
+
+		write_wd33c93_cdb(regs, cmd->cmd_len, cmd->cmnd);
+
+		/* The wd33c93 only knows about Group 0, 1, and 5 commands when
+		 * it's doing a 'select-and-transfer'. To be safe, we write the
+		 * size of the CDB into the OWN_ID register for every case. This
+		 * way there won't be problems with vendor-unique, audio, etc.
+		 */
+
+		write_wd33c93(regs, WD_OWN_ID, cmd->cmd_len);
+
+		/* When doing a non-disconnect command with DMA, we can save
+		 * ourselves a DATA phase interrupt later by setting everything
+		 * up ahead of time.
+		 */
+
+		if ((cmd->SCp.phase == 0) && (hostdata->no_dma == 0)) {
+			if (hostdata->dma_setup(cmd,
+			    (cmd->sc_data_direction == DMA_TO_DEVICE) ?
+			     DATA_OUT_DIR : DATA_IN_DIR))
+				write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
+			else {
+				write_wd33c93_count(regs,
+						    cmd->SCp.this_residual);
+				write_wd33c93(regs, WD_CONTROL,
+					      CTRL_IDI | CTRL_EDI | CTRL_DMA);
+				hostdata->dma = D_DMA_RUNNING;
+			}
+		} else
+			write_wd33c93_count(regs, 0);	/* guarantee a DATA_PHASE interrupt */
+
+		hostdata->state = S_RUNNING_LEVEL2;
+		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+	}
+
+	/*
+	 * Since the SCSI bus can handle only 1 connection at a time,
+	 * we get out of here now. If the selection fails, or when
+	 * the command disconnects, we'll come back to this routine
+	 * to search the input_Q again...
+	 */
+
+	DB(DB_EXECUTE,
+	   printk("%s%ld)EX-2 ", (cmd->SCp.phase) ? "d:" : "", cmd->pid))
+}
+
+static void
+transfer_pio(const wd33c93_regs regs, uchar * buf, int cnt,
+	     int data_in_dir, struct WD33C93_hostdata *hostdata)
+{
+	uchar asr;
+
+	DB(DB_TRANSFER,
+	   printk("(%p,%d,%s:", buf, cnt, data_in_dir ? "in" : "out"))
+
+	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_wd33c93_count(regs, cnt);
+	write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
+	if (data_in_dir) {
+		do {
+			asr = read_aux_stat(regs);
+			if (asr & ASR_DBR)
+				*buf++ = read_wd33c93(regs, WD_DATA);
+		} while (!(asr & ASR_INT));
+	} else {
+		do {
+			asr = read_aux_stat(regs);
+			if (asr & ASR_DBR)
+				write_wd33c93(regs, WD_DATA, *buf++);
+		} while (!(asr & ASR_INT));
+	}
+
+	/* Note: we are returning with the interrupt UN-cleared.
+	 * Since (presumably) an entire I/O operation has
+	 * completed, the bus phase is probably different, and
+	 * the interrupt routine will discover this when it
+	 * responds to the uncleared int.
+	 */
+
+}
+
+static void
+transfer_bytes(const wd33c93_regs regs, struct scsi_cmnd *cmd,
+		int data_in_dir)
+{
+	struct WD33C93_hostdata *hostdata;
+	unsigned long length;
+
+	hostdata = (struct WD33C93_hostdata *) cmd->device->host->hostdata;
+
+/* Normally, you'd expect 'this_residual' to be non-zero here.
+ * In a series of scatter-gather transfers, however, this
+ * routine will usually be called with 'this_residual' equal
+ * to 0 and 'buffers_residual' non-zero. This means that a
+ * previous transfer completed, clearing 'this_residual', and
+ * now we need to setup the next scatter-gather buffer as the
+ * source or destination for THIS transfer.
+ */
+	if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+		++cmd->SCp.buffer;
+		--cmd->SCp.buffers_residual;
+		cmd->SCp.this_residual = cmd->SCp.buffer->length;
+		cmd->SCp.ptr = page_address(cmd->SCp.buffer->page) +
+		    cmd->SCp.buffer->offset;
+	}
+
+	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
+		      hostdata->sync_xfer[cmd->device->id]);
+
+/* 'hostdata->no_dma' is TRUE if we don't even want to try DMA.
+ * Update 'this_residual' and 'ptr' after 'transfer_pio()' returns.
+ */
+
+	if (hostdata->no_dma || hostdata->dma_setup(cmd, data_in_dir)) {
+#ifdef PROC_STATISTICS
+		hostdata->pio_cnt++;
+#endif
+		transfer_pio(regs, (uchar *) cmd->SCp.ptr,
+			     cmd->SCp.this_residual, data_in_dir, hostdata);
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_wd33c93_count(regs);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+	}
+
+/* We are able to do DMA (in fact, the Amiga hardware is
+ * already going!), so start up the wd33c93 in DMA mode.
+ * We set 'hostdata->dma' = D_DMA_RUNNING so that when the
+ * transfer completes and causes an interrupt, we're
+ * reminded to tell the Amiga to shut down its end. We'll
+ * postpone the updating of 'this_residual' and 'ptr'
+ * until then.
+ */
+
+	else {
+#ifdef PROC_STATISTICS
+		hostdata->dma_cnt++;
+#endif
+		write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA);
+		write_wd33c93_count(regs, cmd->SCp.this_residual);
+
+		if ((hostdata->level2 >= L2_DATA) ||
+		    (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) {
+			write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
+			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			write_wd33c93_cmd(regs, WD_CMD_TRANS_INFO);
+
+		hostdata->dma = D_DMA_RUNNING;
+	}
+}
+
+void
+wd33c93_intr(struct Scsi_Host *instance)
+{
+	struct WD33C93_hostdata *hostdata =
+	    (struct WD33C93_hostdata *) instance->hostdata;
+	const wd33c93_regs regs = hostdata->regs;
+	struct scsi_cmnd *patch, *cmd;
+	uchar asr, sr, phs, id, lun, *ucp, msg;
+	unsigned long length, flags;
+
+	asr = read_aux_stat(regs);
+	if (!(asr & ASR_INT) || (asr & ASR_BSY))
+		return;
+
+	spin_lock_irqsave(&hostdata->lock, flags);
+
+#ifdef PROC_STATISTICS
+	hostdata->int_cnt++;
+#endif
+
+	cmd = (struct scsi_cmnd *) hostdata->connected;	/* assume we're connected */
+	sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear the interrupt */
+	phs = read_wd33c93(regs, WD_COMMAND_PHASE);
+
+	DB(DB_INTR, printk("{%02x:%02x-", asr, sr))
+
+/* After starting a DMA transfer, the next interrupt
+ * is guaranteed to be in response to completion of
+ * the transfer. Since the Amiga DMA hardware runs in
+ * in an open-ended fashion, it needs to be told when
+ * to stop; do that here if D_DMA_RUNNING is true.
+ * Also, we have to update 'this_residual' and 'ptr'
+ * based on the contents of the TRANSFER_COUNT register,
+ * in case the device decided to do an intermediate
+ * disconnect (a device may do this if it has to do a
+ * seek, or just to be nice and let other devices have
+ * some bus time during long transfers). After doing
+ * whatever is needed, we go on and service the WD3393
+ * interrupt normally.
+ */
+	    if (hostdata->dma == D_DMA_RUNNING) {
+		DB(DB_TRANSFER,
+		   printk("[%p/%d:", cmd->SCp.ptr, cmd->SCp.this_residual))
+		    hostdata->dma_stop(cmd->device->host, cmd, 1);
+		hostdata->dma = D_DMA_OFF;
+		length = cmd->SCp.this_residual;
+		cmd->SCp.this_residual = read_wd33c93_count(regs);
+		cmd->SCp.ptr += (length - cmd->SCp.this_residual);
+		DB(DB_TRANSFER,
+		   printk("%p/%d]", cmd->SCp.ptr, cmd->SCp.this_residual))
+	}
+
+/* Respond to the specific WD3393 interrupt - there are quite a few! */
+	switch (sr) {
+	case CSR_TIMEOUT:
+		DB(DB_INTR, printk("TIMEOUT"))
+
+		    if (hostdata->state == S_RUNNING_LEVEL2)
+			hostdata->connected = NULL;
+		else {
+			cmd = (struct scsi_cmnd *) hostdata->selecting;	/* get a valid cmd */
+			hostdata->selecting = NULL;
+		}
+
+		cmd->result = DID_NO_CONNECT << 16;
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->state = S_UNCONNECTED;
+		cmd->scsi_done(cmd);
+
+		/* From esp.c:
+		 * There is a window of time within the scsi_done() path
+		 * of execution where interrupts are turned back on full
+		 * blast and left that way.  During that time we could
+		 * reconnect to a disconnected command, then we'd bomb
+		 * out below.  We could also end up executing two commands
+		 * at _once_.  ...just so you know why the restore_flags()
+		 * is here...
+		 */
+
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+
+/* We are not connected to a target - check to see if there
+ * are commands waiting to be executed.
+ */
+
+		wd33c93_execute(instance);
+		break;
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+	case CSR_SELECT:
+		DB(DB_INTR, printk("SELECT"))
+		    hostdata->connected = cmd =
+		    (struct scsi_cmnd *) hostdata->selecting;
+		hostdata->selecting = NULL;
+
+		/* construct an IDENTIFY message with correct disconnect bit */
+
+		hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->device->lun);
+		if (cmd->SCp.phase)
+			hostdata->outgoing_msg[0] |= 0x40;
+
+		if (hostdata->sync_stat[cmd->device->id] == SS_FIRST) {
+#ifdef SYNC_DEBUG
+			printk(" sending SDTR ");
+#endif
+
+			hostdata->sync_stat[cmd->device->id] = SS_WAITING;
+
+/* Tack on a 2nd message to ask about synchronous transfers. If we've
+ * been asked to do only asynchronous transfers on this device, we
+ * request a fifo depth of 0, which is equivalent to async - should
+ * solve the problems some people have had with GVP's Guru ROM.
+ */
+
+			hostdata->outgoing_msg[1] = EXTENDED_MESSAGE;
+			hostdata->outgoing_msg[2] = 3;
+			hostdata->outgoing_msg[3] = EXTENDED_SDTR;
+			if (hostdata->no_sync & (1 << cmd->device->id)) {
+				hostdata->outgoing_msg[4] =
+				    hostdata->default_sx_per / 4;
+				hostdata->outgoing_msg[5] = 0;
+			} else {
+				hostdata->outgoing_msg[4] = OPTIMUM_SX_PER / 4;
+				hostdata->outgoing_msg[5] = OPTIMUM_SX_OFF;
+			}
+			hostdata->outgoing_len = 6;
+		} else
+			hostdata->outgoing_len = 1;
+
+		hostdata->state = S_CONNECTED;
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_XFER_DONE | PHS_DATA_IN:
+	case CSR_UNEXP | PHS_DATA_IN:
+	case CSR_SRV_REQ | PHS_DATA_IN:
+		DB(DB_INTR,
+		   printk("IN-%d.%d", cmd->SCp.this_residual,
+			  cmd->SCp.buffers_residual))
+		    transfer_bytes(regs, cmd, DATA_IN_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_XFER_DONE | PHS_DATA_OUT:
+	case CSR_UNEXP | PHS_DATA_OUT:
+	case CSR_SRV_REQ | PHS_DATA_OUT:
+		DB(DB_INTR,
+		   printk("OUT-%d.%d", cmd->SCp.this_residual,
+			  cmd->SCp.buffers_residual))
+		    transfer_bytes(regs, cmd, DATA_OUT_DIR);
+		if (hostdata->state != S_RUNNING_LEVEL2)
+			hostdata->state = S_CONNECTED;
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+/* Note: this interrupt should not occur in a LEVEL2 command */
+
+	case CSR_XFER_DONE | PHS_COMMAND:
+	case CSR_UNEXP | PHS_COMMAND:
+	case CSR_SRV_REQ | PHS_COMMAND:
+		DB(DB_INTR, printk("CMND-%02x,%ld", cmd->cmnd[0], cmd->pid))
+		    transfer_pio(regs, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR,
+				 hostdata);
+		hostdata->state = S_CONNECTED;
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_XFER_DONE | PHS_STATUS:
+	case CSR_UNEXP | PHS_STATUS:
+	case CSR_SRV_REQ | PHS_STATUS:
+		DB(DB_INTR, printk("STATUS="))
+		cmd->SCp.Status = read_1_byte(regs);
+		DB(DB_INTR, printk("%02x", cmd->SCp.Status))
+		    if (hostdata->level2 >= L2_BASIC) {
+			sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */
+			hostdata->state = S_RUNNING_LEVEL2;
+			write_wd33c93(regs, WD_COMMAND_PHASE, 0x50);
+			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+		} else {
+			hostdata->state = S_CONNECTED;
+		}
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_XFER_DONE | PHS_MESS_IN:
+	case CSR_UNEXP | PHS_MESS_IN:
+	case CSR_SRV_REQ | PHS_MESS_IN:
+		DB(DB_INTR, printk("MSG_IN="))
+
+		msg = read_1_byte(regs);
+		sr = read_wd33c93(regs, WD_SCSI_STATUS);	/* clear interrupt */
+
+		hostdata->incoming_msg[hostdata->incoming_ptr] = msg;
+		if (hostdata->incoming_msg[0] == EXTENDED_MESSAGE)
+			msg = EXTENDED_MESSAGE;
+		else
+			hostdata->incoming_ptr = 0;
+
+		cmd->SCp.Message = msg;
+		switch (msg) {
+
+		case COMMAND_COMPLETE:
+			DB(DB_INTR, printk("CCMP-%ld", cmd->pid))
+			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_CMP_DISC;
+			break;
+
+		case SAVE_POINTERS:
+			DB(DB_INTR, printk("SDP"))
+			    write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
+
+		case RESTORE_POINTERS:
+			DB(DB_INTR, printk("RDP"))
+			    if (hostdata->level2 >= L2_BASIC) {
+				write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
+				write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+				hostdata->state = S_RUNNING_LEVEL2;
+			} else {
+				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		case DISCONNECT:
+			DB(DB_INTR, printk("DIS"))
+			    cmd->device->disconnect = 1;
+			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_PRE_TMP_DISC;
+			break;
+
+		case MESSAGE_REJECT:
+			DB(DB_INTR, printk("REJ"))
+#ifdef SYNC_DEBUG
+			    printk("-REJ-");
+#endif
+			if (hostdata->sync_stat[cmd->device->id] == SS_WAITING)
+				hostdata->sync_stat[cmd->device->id] = SS_SET;
+			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+			break;
+
+		case EXTENDED_MESSAGE:
+			DB(DB_INTR, printk("EXT"))
+
+			    ucp = hostdata->incoming_msg;
+
+#ifdef SYNC_DEBUG
+			printk("%02x", ucp[hostdata->incoming_ptr]);
+#endif
+			/* Is this the last byte of the extended message? */
+
+			if ((hostdata->incoming_ptr >= 2) &&
+			    (hostdata->incoming_ptr == (ucp[1] + 1))) {
+
+				switch (ucp[2]) {	/* what's the EXTENDED code? */
+				case EXTENDED_SDTR:
+					id = calc_sync_xfer(ucp[3], ucp[4]);
+					if (hostdata->sync_stat[cmd->device->id] !=
+					    SS_WAITING) {
+
+/* A device has sent an unsolicited SDTR message; rather than go
+ * through the effort of decoding it and then figuring out what
+ * our reply should be, we're just gonna say that we have a
+ * synchronous fifo depth of 0. This will result in asynchronous
+ * transfers - not ideal but so much easier.
+ * Actually, this is OK because it assures us that if we don't
+ * specifically ask for sync transfers, we won't do any.
+ */
+
+						write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+						hostdata->outgoing_msg[0] =
+						    EXTENDED_MESSAGE;
+						hostdata->outgoing_msg[1] = 3;
+						hostdata->outgoing_msg[2] =
+						    EXTENDED_SDTR;
+						hostdata->outgoing_msg[3] =
+						    hostdata->default_sx_per /
+						    4;
+						hostdata->outgoing_msg[4] = 0;
+						hostdata->outgoing_len = 5;
+						hostdata->sync_xfer[cmd->device->id] =
+						    calc_sync_xfer(hostdata->
+								   default_sx_per
+								   / 4, 0);
+					} else {
+						hostdata->sync_xfer[cmd->device->id] = id;
+					}
+#ifdef SYNC_DEBUG
+					printk("sync_xfer=%02x",
+					       hostdata->sync_xfer[cmd->device->id]);
+#endif
+					hostdata->sync_stat[cmd->device->id] =
+					    SS_SET;
+					write_wd33c93_cmd(regs,
+							  WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				case EXTENDED_WDTR:
+					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk("sending WDTR ");
+					hostdata->outgoing_msg[0] =
+					    EXTENDED_MESSAGE;
+					hostdata->outgoing_msg[1] = 2;
+					hostdata->outgoing_msg[2] =
+					    EXTENDED_WDTR;
+					hostdata->outgoing_msg[3] = 0;	/* 8 bit transfer width */
+					hostdata->outgoing_len = 4;
+					write_wd33c93_cmd(regs,
+							  WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				default:
+					write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+					printk
+					    ("Rejecting Unknown Extended Message(%02x). ",
+					     ucp[2]);
+					hostdata->outgoing_msg[0] =
+					    MESSAGE_REJECT;
+					hostdata->outgoing_len = 1;
+					write_wd33c93_cmd(regs,
+							  WD_CMD_NEGATE_ACK);
+					hostdata->state = S_CONNECTED;
+					break;
+				}
+				hostdata->incoming_ptr = 0;
+			}
+
+			/* We need to read more MESS_IN bytes for the extended message */
+
+			else {
+				hostdata->incoming_ptr++;
+				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+				hostdata->state = S_CONNECTED;
+			}
+			break;
+
+		default:
+			printk("Rejecting Unknown Message(%02x) ", msg);
+			write_wd33c93_cmd(regs, WD_CMD_ASSERT_ATN);	/* want MESS_OUT */
+			hostdata->outgoing_msg[0] = MESSAGE_REJECT;
+			hostdata->outgoing_len = 1;
+			write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			hostdata->state = S_CONNECTED;
+		}
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+	case CSR_SEL_XFER_DONE:
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
+		if (phs == 0x60) {
+			DB(DB_INTR, printk("SX-DONE-%ld", cmd->pid))
+			    cmd->SCp.Message = COMMAND_COMPLETE;
+			lun = read_wd33c93(regs, WD_TARGET_LUN);
+			DB(DB_INTR, printk(":%d.%d", cmd->SCp.Status, lun))
+			    hostdata->connected = NULL;
+			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+			hostdata->state = S_UNCONNECTED;
+			if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE)
+				cmd->SCp.Status = lun;
+			if (cmd->cmnd[0] == REQUEST_SENSE
+			    && cmd->SCp.Status != GOOD)
+				cmd->result =
+				    (cmd->
+				     result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result =
+				    cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
+
+/* We are no longer  connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+			spin_unlock_irqrestore(&hostdata->lock, flags);
+			wd33c93_execute(instance);
+		} else {
+			printk
+			    ("%02x:%02x:%02x-%ld: Unknown SEL_XFER_DONE phase!!---",
+			     asr, sr, phs, cmd->pid);
+			spin_unlock_irqrestore(&hostdata->lock, flags);
+		}
+		break;
+
+/* Note: this interrupt will occur only after a LEVEL2 command */
+
+	case CSR_SDP:
+		DB(DB_INTR, printk("SDP"))
+		    hostdata->state = S_RUNNING_LEVEL2;
+		write_wd33c93(regs, WD_COMMAND_PHASE, 0x41);
+		write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_XFER_DONE | PHS_MESS_OUT:
+	case CSR_UNEXP | PHS_MESS_OUT:
+	case CSR_SRV_REQ | PHS_MESS_OUT:
+		DB(DB_INTR, printk("MSG_OUT="))
+
+/* To get here, we've probably requested MESSAGE_OUT and have
+ * already put the correct bytes in outgoing_msg[] and filled
+ * in outgoing_len. We simply send them out to the SCSI bus.
+ * Sometimes we get MESSAGE_OUT phase when we're not expecting
+ * it - like when our SDTR message is rejected by a target. Some
+ * targets send the REJECT before receiving all of the extended
+ * message, and then seem to go back to MESSAGE_OUT for a byte
+ * or two. Not sure why, or if I'm doing something wrong to
+ * cause this to happen. Regardless, it seems that sending
+ * NOP messages in these situations results in no harm and
+ * makes everyone happy.
+ */
+		    if (hostdata->outgoing_len == 0) {
+			hostdata->outgoing_len = 1;
+			hostdata->outgoing_msg[0] = NOP;
+		}
+		transfer_pio(regs, hostdata->outgoing_msg,
+			     hostdata->outgoing_len, DATA_OUT_DIR, hostdata);
+		DB(DB_INTR, printk("%02x", hostdata->outgoing_msg[0]))
+		    hostdata->outgoing_len = 0;
+		hostdata->state = S_CONNECTED;
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	case CSR_UNEXP_DISC:
+
+/* I think I've seen this after a request-sense that was in response
+ * to an error condition, but not sure. We certainly need to do
+ * something when we get this interrupt - the question is 'what?'.
+ * Let's think positively, and assume some command has finished
+ * in a legal manner (like a command that provokes a request-sense),
+ * so we treat it as a normal command-complete-disconnect.
+ */
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
+		if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
+			spin_unlock_irqrestore(&hostdata->lock, flags);
+			return;
+		}
+		DB(DB_INTR, printk("UNEXP_DISC-%ld", cmd->pid))
+		    hostdata->connected = NULL;
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->state = S_UNCONNECTED;
+		if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD)
+			cmd->result =
+			    (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+		else
+			cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+		cmd->scsi_done(cmd);
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+		/* look above for comments on scsi_done() */
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		wd33c93_execute(instance);
+		break;
+
+	case CSR_DISC:
+
+/* Make sure that reselection is enabled at this point - it may
+ * have been turned off for the command that just completed.
+ */
+
+		write_wd33c93(regs, WD_SOURCE_ID, SRCID_ER);
+		DB(DB_INTR, printk("DISC-%ld", cmd->pid))
+		    if (cmd == NULL) {
+			printk(" - Already disconnected! ");
+			hostdata->state = S_UNCONNECTED;
+		}
+		switch (hostdata->state) {
+		case S_PRE_CMP_DISC:
+			hostdata->connected = NULL;
+			hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+			hostdata->state = S_UNCONNECTED;
+			DB(DB_INTR, printk(":%d", cmd->SCp.Status))
+			    if (cmd->cmnd[0] == REQUEST_SENSE
+				&& cmd->SCp.Status != GOOD)
+				cmd->result =
+				    (cmd->
+				     result & 0x00ffff) | (DID_ERROR << 16);
+			else
+				cmd->result =
+				    cmd->SCp.Status | (cmd->SCp.Message << 8);
+			cmd->scsi_done(cmd);
+			break;
+		case S_PRE_TMP_DISC:
+		case S_RUNNING_LEVEL2:
+			cmd->host_scribble = (uchar *) hostdata->disconnected_Q;
+			hostdata->disconnected_Q = cmd;
+			hostdata->connected = NULL;
+			hostdata->state = S_UNCONNECTED;
+
+#ifdef PROC_STATISTICS
+			hostdata->disc_done_cnt[cmd->device->id]++;
+#endif
+
+			break;
+		default:
+			printk("*** Unexpected DISCONNECT interrupt! ***");
+			hostdata->state = S_UNCONNECTED;
+		}
+
+/* We are no longer connected to a target - check to see if
+ * there are commands waiting to be executed.
+ */
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+		wd33c93_execute(instance);
+		break;
+
+	case CSR_RESEL_AM:
+	case CSR_RESEL:
+		DB(DB_INTR, printk("RESEL%s", sr == CSR_RESEL_AM ? "_AM" : ""))
+
+		    /* Old chips (pre -A ???) don't have advanced features and will
+		     * generate CSR_RESEL.  In that case we have to extract the LUN the
+		     * hard way (see below).
+		     * First we have to make sure this reselection didn't
+		     * happen during Arbitration/Selection of some other device.
+		     * If yes, put losing command back on top of input_Q.
+		     */
+		    if (hostdata->level2 <= L2_NONE) {
+
+			if (hostdata->selecting) {
+				cmd = (struct scsi_cmnd *) hostdata->selecting;
+				hostdata->selecting = NULL;
+				hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+				cmd->host_scribble =
+				    (uchar *) hostdata->input_Q;
+				hostdata->input_Q = cmd;
+			}
+		}
+
+		else {
+
+			if (cmd) {
+				if (phs == 0x00) {
+					hostdata->busy[cmd->device->id] &=
+					    ~(1 << cmd->device->lun);
+					cmd->host_scribble =
+					    (uchar *) hostdata->input_Q;
+					hostdata->input_Q = cmd;
+				} else {
+					printk
+					    ("---%02x:%02x:%02x-TROUBLE: Intrusive ReSelect!---",
+					     asr, sr, phs);
+					while (1)
+						printk("\r");
+				}
+			}
+
+		}
+
+		/* OK - find out which device reselected us. */
+
+		id = read_wd33c93(regs, WD_SOURCE_ID);
+		id &= SRCID_MASK;
+
+		/* and extract the lun from the ID message. (Note that we don't
+		 * bother to check for a valid message here - I guess this is
+		 * not the right way to go, but...)
+		 */
+
+		if (sr == CSR_RESEL_AM) {
+			lun = read_wd33c93(regs, WD_DATA);
+			if (hostdata->level2 < L2_RESELECT)
+				write_wd33c93_cmd(regs, WD_CMD_NEGATE_ACK);
+			lun &= 7;
+		} else {
+			/* Old chip; wait for msgin phase to pick up the LUN. */
+			for (lun = 255; lun; lun--) {
+				if ((asr = read_aux_stat(regs)) & ASR_INT)
+					break;
+				udelay(10);
+			}
+			if (!(asr & ASR_INT)) {
+				printk
+				    ("wd33c93: Reselected without IDENTIFY\n");
+				lun = 0;
+			} else {
+				/* Verify this is a change to MSG_IN and read the message */
+				sr = read_wd33c93(regs, WD_SCSI_STATUS);
+				if (sr == (CSR_ABORT | PHS_MESS_IN) ||
+				    sr == (CSR_UNEXP | PHS_MESS_IN) ||
+				    sr == (CSR_SRV_REQ | PHS_MESS_IN)) {
+					/* Got MSG_IN, grab target LUN */
+					lun = read_1_byte(regs);
+					/* Now we expect a 'paused with ACK asserted' int.. */
+					asr = read_aux_stat(regs);
+					if (!(asr & ASR_INT)) {
+						udelay(10);
+						asr = read_aux_stat(regs);
+						if (!(asr & ASR_INT))
+							printk
+							    ("wd33c93: No int after LUN on RESEL (%02x)\n",
+							     asr);
+					}
+					sr = read_wd33c93(regs, WD_SCSI_STATUS);
+					if (sr != CSR_MSGIN)
+						printk
+						    ("wd33c93: Not paused with ACK on RESEL (%02x)\n",
+						     sr);
+					lun &= 7;
+					write_wd33c93_cmd(regs,
+							  WD_CMD_NEGATE_ACK);
+				} else {
+					printk
+					    ("wd33c93: Not MSG_IN on reselect (%02x)\n",
+					     sr);
+					lun = 0;
+				}
+			}
+		}
+
+		/* Now we look for the command that's reconnecting. */
+
+		cmd = (struct scsi_cmnd *) hostdata->disconnected_Q;
+		patch = NULL;
+		while (cmd) {
+			if (id == cmd->device->id && lun == cmd->device->lun)
+				break;
+			patch = cmd;
+			cmd = (struct scsi_cmnd *) cmd->host_scribble;
+		}
+
+		/* Hmm. Couldn't find a valid command.... What to do? */
+
+		if (!cmd) {
+			printk
+			    ("---TROUBLE: target %d.%d not in disconnect queue---",
+			     id, lun);
+			spin_unlock_irqrestore(&hostdata->lock, flags);
+			return;
+		}
+
+		/* Ok, found the command - now start it up again. */
+
+		if (patch)
+			patch->host_scribble = cmd->host_scribble;
+		else
+			hostdata->disconnected_Q =
+			    (struct scsi_cmnd *) cmd->host_scribble;
+		hostdata->connected = cmd;
+
+		/* We don't need to worry about 'initialize_SCp()' or 'hostdata->busy[]'
+		 * because these things are preserved over a disconnect.
+		 * But we DO need to fix the DPD bit so it's correct for this command.
+		 */
+
+		if (cmd->sc_data_direction == DMA_TO_DEVICE)
+			write_wd33c93(regs, WD_DESTINATION_ID, cmd->device->id);
+		else
+			write_wd33c93(regs, WD_DESTINATION_ID,
+				      cmd->device->id | DSTID_DPD);
+		if (hostdata->level2 >= L2_RESELECT) {
+			write_wd33c93_count(regs, 0);	/* we want a DATA_PHASE interrupt */
+			write_wd33c93(regs, WD_COMMAND_PHASE, 0x45);
+			write_wd33c93_cmd(regs, WD_CMD_SEL_ATN_XFER);
+			hostdata->state = S_RUNNING_LEVEL2;
+		} else
+			hostdata->state = S_CONNECTED;
+
+		DB(DB_INTR, printk("-%ld", cmd->pid))
+		    spin_unlock_irqrestore(&hostdata->lock, flags);
+		break;
+
+	default:
+		printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--", asr, sr, phs);
+		spin_unlock_irqrestore(&hostdata->lock, flags);
+	}
+
+	DB(DB_INTR, printk("} "))
+
+}
+
+static void
+reset_wd33c93(struct Scsi_Host *instance)
+{
+	struct WD33C93_hostdata *hostdata =
+	    (struct WD33C93_hostdata *) instance->hostdata;
+	const wd33c93_regs regs = hostdata->regs;
+	uchar sr;
+
+#ifdef CONFIG_SGI_IP22
+	{
+		int busycount = 0;
+		extern void sgiwd93_reset(unsigned long);
+		/* wait 'til the chip gets some time for us */
+		while ((read_aux_stat(regs) & ASR_BSY) && busycount++ < 100)
+			udelay (10);
+	/*
+ 	 * there are scsi devices out there, which manage to lock up
+	 * the wd33c93 in a busy condition. In this state it won't
+	 * accept the reset command. The only way to solve this is to
+ 	 * give the chip a hardware reset (if possible). The code below
+	 * does this for the SGI Indy, where this is possible
+	 */
+	/* still busy ? */
+	if (read_aux_stat(regs) & ASR_BSY)
+		sgiwd93_reset(instance->base); /* yeah, give it the hard one */
+	}
+#endif
+
+	write_wd33c93(regs, WD_OWN_ID, OWNID_EAF | OWNID_RAF |
+		      instance->this_id | hostdata->clock_freq);
+	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+	write_wd33c93(regs, WD_SYNCHRONOUS_TRANSFER,
+		      calc_sync_xfer(hostdata->default_sx_per / 4,
+				     DEFAULT_SX_OFF));
+	write_wd33c93(regs, WD_COMMAND, WD_CMD_RESET);
+
+
+#ifdef CONFIG_MVME147_SCSI
+	udelay(25);		/* The old wd33c93 on MVME147 needs this, at least */
+#endif
+
+	while (!(read_aux_stat(regs) & ASR_INT))
+		;
+	sr = read_wd33c93(regs, WD_SCSI_STATUS);
+
+	hostdata->microcode = read_wd33c93(regs, WD_CDB_1);
+	if (sr == 0x00)
+		hostdata->chip = C_WD33C93;
+	else if (sr == 0x01) {
+		write_wd33c93(regs, WD_QUEUE_TAG, 0xa5);	/* any random number */
+		sr = read_wd33c93(regs, WD_QUEUE_TAG);
+		if (sr == 0xa5) {
+			hostdata->chip = C_WD33C93B;
+			write_wd33c93(regs, WD_QUEUE_TAG, 0);
+		} else
+			hostdata->chip = C_WD33C93A;
+	} else
+		hostdata->chip = C_UNKNOWN_CHIP;
+
+	write_wd33c93(regs, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE);
+	write_wd33c93(regs, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+}
+
+int
+wd33c93_host_reset(struct scsi_cmnd * SCpnt)
+{
+	struct Scsi_Host *instance;
+	struct WD33C93_hostdata *hostdata;
+	int i;
+
+	instance = SCpnt->device->host;
+	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
+
+	printk("scsi%d: reset. ", instance->host_no);
+	disable_irq(instance->irq);
+
+	hostdata->dma_stop(instance, NULL, 0);
+	for (i = 0; i < 8; i++) {
+		hostdata->busy[i] = 0;
+		hostdata->sync_xfer[i] =
+		    calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+		hostdata->sync_stat[i] = SS_UNSET;	/* using default sync values */
+	}
+	hostdata->input_Q = NULL;
+	hostdata->selecting = NULL;
+	hostdata->connected = NULL;
+	hostdata->disconnected_Q = NULL;
+	hostdata->state = S_UNCONNECTED;
+	hostdata->dma = D_DMA_OFF;
+	hostdata->incoming_ptr = 0;
+	hostdata->outgoing_len = 0;
+
+	reset_wd33c93(instance);
+	SCpnt->result = DID_RESET << 16;
+	enable_irq(instance->irq);
+	return SUCCESS;
+}
+
+int
+wd33c93_abort(struct scsi_cmnd * cmd)
+{
+	struct Scsi_Host *instance;
+	struct WD33C93_hostdata *hostdata;
+	wd33c93_regs regs;
+	struct scsi_cmnd *tmp, *prev;
+
+	disable_irq(cmd->device->host->irq);
+
+	instance = cmd->device->host;
+	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
+	regs = hostdata->regs;
+
+/*
+ * Case 1 : If the command hasn't been issued yet, we simply remove it
+ *     from the input_Q.
+ */
+
+	tmp = (struct scsi_cmnd *) hostdata->input_Q;
+	prev = 0;
+	while (tmp) {
+		if (tmp == cmd) {
+			if (prev)
+				prev->host_scribble = cmd->host_scribble;
+			else
+				hostdata->input_Q =
+				    (struct scsi_cmnd *) cmd->host_scribble;
+			cmd->host_scribble = NULL;
+			cmd->result = DID_ABORT << 16;
+			printk
+			    ("scsi%d: Abort - removing command %ld from input_Q. ",
+			     instance->host_no, cmd->pid);
+			enable_irq(cmd->device->host->irq);
+			cmd->scsi_done(cmd);
+			return SUCCESS;
+		}
+		prev = tmp;
+		tmp = (struct scsi_cmnd *) tmp->host_scribble;
+	}
+
+/*
+ * Case 2 : If the command is connected, we're going to fail the abort
+ *     and let the high level SCSI driver retry at a later time or
+ *     issue a reset.
+ *
+ *     Timeouts, and therefore aborted commands, will be highly unlikely
+ *     and handling them cleanly in this situation would make the common
+ *     case of noresets less efficient, and would pollute our code.  So,
+ *     we fail.
+ */
+
+	if (hostdata->connected == cmd) {
+		uchar sr, asr;
+		unsigned long timeout;
+
+		printk("scsi%d: Aborting connected command %ld - ",
+		       instance->host_no, cmd->pid);
+
+		printk("stopping DMA - ");
+		if (hostdata->dma == D_DMA_RUNNING) {
+			hostdata->dma_stop(instance, cmd, 0);
+			hostdata->dma = D_DMA_OFF;
+		}
+
+		printk("sending wd33c93 ABORT command - ");
+		write_wd33c93(regs, WD_CONTROL,
+			      CTRL_IDI | CTRL_EDI | CTRL_POLLED);
+		write_wd33c93_cmd(regs, WD_CMD_ABORT);
+
+/* Now we have to attempt to flush out the FIFO... */
+
+		printk("flushing fifo - ");
+		timeout = 1000000;
+		do {
+			asr = read_aux_stat(regs);
+			if (asr & ASR_DBR)
+				read_wd33c93(regs, WD_DATA);
+		} while (!(asr & ASR_INT) && timeout-- > 0);
+		sr = read_wd33c93(regs, WD_SCSI_STATUS);
+		printk
+		    ("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ",
+		     asr, sr, read_wd33c93_count(regs), timeout);
+
+		/*
+		 * Abort command processed.
+		 * Still connected.
+		 * We must disconnect.
+		 */
+
+		printk("sending wd33c93 DISCONNECT command - ");
+		write_wd33c93_cmd(regs, WD_CMD_DISCONNECT);
+
+		timeout = 1000000;
+		asr = read_aux_stat(regs);
+		while ((asr & ASR_CIP) && timeout-- > 0)
+			asr = read_aux_stat(regs);
+		sr = read_wd33c93(regs, WD_SCSI_STATUS);
+		printk("asr=%02x, sr=%02x.", asr, sr);
+
+		hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
+		hostdata->connected = NULL;
+		hostdata->state = S_UNCONNECTED;
+		cmd->result = DID_ABORT << 16;
+
+/*      sti();*/
+		wd33c93_execute(instance);
+
+		enable_irq(cmd->device->host->irq);
+		cmd->scsi_done(cmd);
+		return SUCCESS;
+	}
+
+/*
+ * Case 3: If the command is currently disconnected from the bus,
+ * we're not going to expend much effort here: Let's just return
+ * an ABORT_SNOOZE and hope for the best...
+ */
+
+	tmp = (struct scsi_cmnd *) hostdata->disconnected_Q;
+	while (tmp) {
+		if (tmp == cmd) {
+			printk
+			    ("scsi%d: Abort - command %ld found on disconnected_Q - ",
+			     instance->host_no, cmd->pid);
+			printk("Abort SNOOZE. ");
+			enable_irq(cmd->device->host->irq);
+			return FAILED;
+		}
+		tmp = (struct scsi_cmnd *) tmp->host_scribble;
+	}
+
+/*
+ * Case 4 : If we reached this point, the command was not found in any of
+ *     the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case something really
+ * broke.
+ */
+
+/*   sti();*/
+	wd33c93_execute(instance);
+
+	enable_irq(cmd->device->host->irq);
+	printk("scsi%d: warning : SCSI command probably completed successfully"
+	       "         before abortion. ", instance->host_no);
+	return FAILED;
+}
+
+#define MAX_WD33C93_HOSTS 4
+#define MAX_SETUP_ARGS ((int)(sizeof(setup_args) / sizeof(char *)))
+#define SETUP_BUFFER_SIZE 200
+static char setup_buffer[SETUP_BUFFER_SIZE];
+static char setup_used[MAX_SETUP_ARGS];
+static int done_setup = 0;
+
+int
+wd33c93_setup(char *str)
+{
+	int i;
+	char *p1, *p2;
+
+	/* The kernel does some processing of the command-line before calling
+	 * this function: If it begins with any decimal or hex number arguments,
+	 * ints[0] = how many numbers found and ints[1] through [n] are the values
+	 * themselves. str points to where the non-numeric arguments (if any)
+	 * start: We do our own parsing of those. We construct synthetic 'nosync'
+	 * keywords out of numeric args (to maintain compatibility with older
+	 * versions) and then add the rest of the arguments.
+	 */
+
+	p1 = setup_buffer;
+	*p1 = '\0';
+	if (str)
+		strncpy(p1, str, SETUP_BUFFER_SIZE - strlen(setup_buffer));
+	setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0';
+	p1 = setup_buffer;
+	i = 0;
+	while (*p1 && (i < MAX_SETUP_ARGS)) {
+		p2 = strchr(p1, ',');
+		if (p2) {
+			*p2 = '\0';
+			if (p1 != p2)
+				setup_args[i] = p1;
+			p1 = p2 + 1;
+			i++;
+		} else {
+			setup_args[i] = p1;
+			break;
+		}
+	}
+	for (i = 0; i < MAX_SETUP_ARGS; i++)
+		setup_used[i] = 0;
+	done_setup = 1;
+
+	return 1;
+}
+__setup("wd33c93=", wd33c93_setup);
+
+/* check_setup_args() returns index if key found, 0 if not
+ */
+static int
+check_setup_args(char *key, int *flags, int *val, char *buf)
+{
+	int x;
+	char *cp;
+
+	for (x = 0; x < MAX_SETUP_ARGS; x++) {
+		if (setup_used[x])
+			continue;
+		if (!strncmp(setup_args[x], key, strlen(key)))
+			break;
+		if (!strncmp(setup_args[x], "next", strlen("next")))
+			return 0;
+	}
+	if (x == MAX_SETUP_ARGS)
+		return 0;
+	setup_used[x] = 1;
+	cp = setup_args[x] + strlen(key);
+	*val = -1;
+	if (*cp != ':')
+		return ++x;
+	cp++;
+	if ((*cp >= '0') && (*cp <= '9')) {
+		*val = simple_strtoul(cp, NULL, 0);
+	}
+	return ++x;
+}
+
+void
+wd33c93_init(struct Scsi_Host *instance, const wd33c93_regs regs,
+	     dma_setup_t setup, dma_stop_t stop, int clock_freq)
+{
+	struct WD33C93_hostdata *hostdata;
+	int i;
+	int flags;
+	int val;
+	char buf[32];
+
+	if (!done_setup && setup_strings)
+		wd33c93_setup(setup_strings);
+
+	hostdata = (struct WD33C93_hostdata *) instance->hostdata;
+
+	hostdata->regs = regs;
+	hostdata->clock_freq = clock_freq;
+	hostdata->dma_setup = setup;
+	hostdata->dma_stop = stop;
+	hostdata->dma_bounce_buffer = NULL;
+	hostdata->dma_bounce_len = 0;
+	for (i = 0; i < 8; i++) {
+		hostdata->busy[i] = 0;
+		hostdata->sync_xfer[i] =
+		    calc_sync_xfer(DEFAULT_SX_PER / 4, DEFAULT_SX_OFF);
+		hostdata->sync_stat[i] = SS_UNSET;	/* using default sync values */
+#ifdef PROC_STATISTICS
+		hostdata->cmd_cnt[i] = 0;
+		hostdata->disc_allowed_cnt[i] = 0;
+		hostdata->disc_done_cnt[i] = 0;
+#endif
+	}
+	hostdata->input_Q = NULL;
+	hostdata->selecting = NULL;
+	hostdata->connected = NULL;
+	hostdata->disconnected_Q = NULL;
+	hostdata->state = S_UNCONNECTED;
+	hostdata->dma = D_DMA_OFF;
+	hostdata->level2 = L2_BASIC;
+	hostdata->disconnect = DIS_ADAPTIVE;
+	hostdata->args = DEBUG_DEFAULTS;
+	hostdata->incoming_ptr = 0;
+	hostdata->outgoing_len = 0;
+	hostdata->default_sx_per = DEFAULT_SX_PER;
+	hostdata->no_sync = 0xff;	/* sync defaults to off */
+	hostdata->no_dma = 0;	/* default is DMA enabled */
+
+#ifdef PROC_INTERFACE
+	hostdata->proc = PR_VERSION | PR_INFO | PR_STATISTICS |
+	    PR_CONNECTED | PR_INPUTQ | PR_DISCQ | PR_STOP;
+#ifdef PROC_STATISTICS
+	hostdata->dma_cnt = 0;
+	hostdata->pio_cnt = 0;
+	hostdata->int_cnt = 0;
+#endif
+#endif
+
+	if (check_setup_args("nosync", &flags, &val, buf))
+		hostdata->no_sync = val;
+
+	if (check_setup_args("nodma", &flags, &val, buf))
+		hostdata->no_dma = (val == -1) ? 1 : val;
+
+	if (check_setup_args("period", &flags, &val, buf))
+		hostdata->default_sx_per =
+		    sx_table[round_period((unsigned int) val)].period_ns;
+
+	if (check_setup_args("disconnect", &flags, &val, buf)) {
+		if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS))
+			hostdata->disconnect = val;
+		else
+			hostdata->disconnect = DIS_ADAPTIVE;
+	}
+
+	if (check_setup_args("level2", &flags, &val, buf))
+		hostdata->level2 = val;
+
+	if (check_setup_args("debug", &flags, &val, buf))
+		hostdata->args = val & DB_MASK;
+
+	if (check_setup_args("clock", &flags, &val, buf)) {
+		if (val > 7 && val < 11)
+			val = WD33C93_FS_8_10;
+		else if (val > 11 && val < 16)
+			val = WD33C93_FS_12_15;
+		else if (val > 15 && val < 21)
+			val = WD33C93_FS_16_20;
+		else
+			val = WD33C93_FS_8_10;
+		hostdata->clock_freq = val;
+	}
+
+	if ((i = check_setup_args("next", &flags, &val, buf))) {
+		while (i)
+			setup_used[--i] = 1;
+	}
+#ifdef PROC_INTERFACE
+	if (check_setup_args("proc", &flags, &val, buf))
+		hostdata->proc = val;
+#endif
+
+	spin_lock_irq(&hostdata->lock);
+	reset_wd33c93(instance);
+	spin_unlock_irq(&hostdata->lock);
+
+	printk("wd33c93-%d: chip=%s/%d no_sync=0x%x no_dma=%d",
+	       instance->host_no,
+	       (hostdata->chip == C_WD33C93) ? "WD33c93" : (hostdata->chip ==
+							    C_WD33C93A) ?
+	       "WD33c93A" : (hostdata->chip ==
+			     C_WD33C93B) ? "WD33c93B" : "unknown",
+	       hostdata->microcode, hostdata->no_sync, hostdata->no_dma);
+#ifdef DEBUGGING_ON
+	printk(" debug_flags=0x%02x\n", hostdata->args);
+#else
+	printk(" debugging=OFF\n");
+#endif
+	printk("           setup_args=");
+	for (i = 0; i < MAX_SETUP_ARGS; i++)
+		printk("%s,", setup_args[i]);
+	printk("\n");
+	printk("           Version %s - %s, Compiled %s at %s\n",
+	       WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
+}
+
+int
+wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in)
+{
+
+#ifdef PROC_INTERFACE
+
+	char *bp;
+	char tbuf[128];
+	struct WD33C93_hostdata *hd;
+	struct scsi_cmnd *cmd;
+	int x, i;
+	static int stop = 0;
+
+	hd = (struct WD33C93_hostdata *) instance->hostdata;
+
+/* If 'in' is TRUE we need to _read_ the proc file. We accept the following
+ * keywords (same format as command-line, but only ONE per read):
+ *    debug
+ *    disconnect
+ *    period
+ *    resync
+ *    proc
+ *    nodma
+ */
+
+	if (in) {
+		buf[len] = '\0';
+		bp = buf;
+		if (!strncmp(bp, "debug:", 6)) {
+			bp += 6;
+			hd->args = simple_strtoul(bp, NULL, 0) & DB_MASK;
+		} else if (!strncmp(bp, "disconnect:", 11)) {
+			bp += 11;
+			x = simple_strtoul(bp, NULL, 0);
+			if (x < DIS_NEVER || x > DIS_ALWAYS)
+				x = DIS_ADAPTIVE;
+			hd->disconnect = x;
+		} else if (!strncmp(bp, "period:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			hd->default_sx_per =
+			    sx_table[round_period((unsigned int) x)].period_ns;
+		} else if (!strncmp(bp, "resync:", 7)) {
+			bp += 7;
+			x = simple_strtoul(bp, NULL, 0);
+			for (i = 0; i < 7; i++)
+				if (x & (1 << i))
+					hd->sync_stat[i] = SS_UNSET;
+		} else if (!strncmp(bp, "proc:", 5)) {
+			bp += 5;
+			hd->proc = simple_strtoul(bp, NULL, 0);
+		} else if (!strncmp(bp, "nodma:", 6)) {
+			bp += 6;
+			hd->no_dma = simple_strtoul(bp, NULL, 0);
+		} else if (!strncmp(bp, "level2:", 7)) {
+			bp += 7;
+			hd->level2 = simple_strtoul(bp, NULL, 0);
+		}
+		return len;
+	}
+
+	spin_lock_irq(&hd->lock);
+	bp = buf;
+	*bp = '\0';
+	if (hd->proc & PR_VERSION) {
+		sprintf(tbuf, "\nVersion %s - %s. Compiled %s %s",
+			WD33C93_VERSION, WD33C93_DATE, __DATE__, __TIME__);
+		strcat(bp, tbuf);
+	}
+	if (hd->proc & PR_INFO) {
+		sprintf(tbuf, "\nclock_freq=%02x no_sync=%02x no_dma=%d",
+			hd->clock_freq, hd->no_sync, hd->no_dma);
+		strcat(bp, tbuf);
+		strcat(bp, "\nsync_xfer[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_xfer[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\nsync_stat[] =       ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%02x", hd->sync_stat[x]);
+			strcat(bp, tbuf);
+		}
+	}
+#ifdef PROC_STATISTICS
+	if (hd->proc & PR_STATISTICS) {
+		strcat(bp, "\ncommands issued:    ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->cmd_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects allowed:");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_allowed_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		strcat(bp, "\ndisconnects done:   ");
+		for (x = 0; x < 7; x++) {
+			sprintf(tbuf, "\t%ld", hd->disc_done_cnt[x]);
+			strcat(bp, tbuf);
+		}
+		sprintf(tbuf,
+			"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO",
+			hd->int_cnt, hd->dma_cnt, hd->pio_cnt);
+		strcat(bp, tbuf);
+	}
+#endif
+	if (hd->proc & PR_CONNECTED) {
+		strcat(bp, "\nconnected:     ");
+		if (hd->connected) {
+			cmd = (struct scsi_cmnd *) hd->connected;
+			sprintf(tbuf, " %ld-%d:%d(%02x)",
+				cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+		}
+	}
+	if (hd->proc & PR_INPUTQ) {
+		strcat(bp, "\ninput_Q:       ");
+		cmd = (struct scsi_cmnd *) hd->input_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)",
+				cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (struct scsi_cmnd *) cmd->host_scribble;
+		}
+	}
+	if (hd->proc & PR_DISCQ) {
+		strcat(bp, "\ndisconnected_Q:");
+		cmd = (struct scsi_cmnd *) hd->disconnected_Q;
+		while (cmd) {
+			sprintf(tbuf, " %ld-%d:%d(%02x)",
+				cmd->pid, cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
+			strcat(bp, tbuf);
+			cmd = (struct scsi_cmnd *) cmd->host_scribble;
+		}
+	}
+	strcat(bp, "\n");
+	spin_unlock_irq(&hd->lock);
+	*start = buf;
+	if (stop) {
+		stop = 0;
+		return 0;
+	}
+	if (off > 0x40000)	/* ALWAYS stop after 256k bytes have been read */
+		stop = 1;
+	if (hd->proc & PR_STOP)	/* stop every other time */
+		stop = 1;
+	return strlen(bp);
+
+#else				/* PROC_INTERFACE */
+
+	return 0;
+
+#endif				/* PROC_INTERFACE */
+
+}
+
+void
+wd33c93_release(void)
+{
+}
+
+EXPORT_SYMBOL(wd33c93_host_reset);
+EXPORT_SYMBOL(wd33c93_init);
+EXPORT_SYMBOL(wd33c93_release);
+EXPORT_SYMBOL(wd33c93_abort);
+EXPORT_SYMBOL(wd33c93_queuecommand);
+EXPORT_SYMBOL(wd33c93_intr);
+EXPORT_SYMBOL(wd33c93_proc_info);
diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h
new file mode 100644
index 0000000..193ec51
--- /dev/null
+++ b/drivers/scsi/wd33c93.h
@@ -0,0 +1,348 @@
+/*
+ *    wd33c93.h -  Linux device driver definitions for the
+ *                 Commodore Amiga A2091/590 SCSI controller card
+ *
+ *    IMPORTANT: This file is for version 1.25 - 09/Jul/1997
+ *
+ * Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *    john@geolog.com
+ *    jshiffle@netcom.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ */
+#ifndef WD33C93_H
+#define WD33C93_H
+
+#include <linux/config.h>
+
+#define PROC_INTERFACE     /* add code for /proc/scsi/wd33c93/xxx interface */
+#ifdef  PROC_INTERFACE
+#define PROC_STATISTICS    /* add code for keeping various real time stats */
+#endif
+
+#define SYNC_DEBUG         /* extra info on sync negotiation printed */
+#define DEBUGGING_ON       /* enable command-line debugging bitmask */
+#define DEBUG_DEFAULTS 0   /* default debugging bitmask */
+
+
+#ifdef DEBUGGING_ON
+#define DB(f,a) if (hostdata->args & (f)) a;
+#else
+#define DB(f,a)
+#endif
+
+#define uchar unsigned char
+
+
+/* wd register names */
+#define WD_OWN_ID    0x00
+#define WD_CONTROL      0x01
+#define WD_TIMEOUT_PERIOD  0x02
+#define WD_CDB_1     0x03
+#define WD_CDB_2     0x04
+#define WD_CDB_3     0x05
+#define WD_CDB_4     0x06
+#define WD_CDB_5     0x07
+#define WD_CDB_6     0x08
+#define WD_CDB_7     0x09
+#define WD_CDB_8     0x0a
+#define WD_CDB_9     0x0b
+#define WD_CDB_10    0x0c
+#define WD_CDB_11    0x0d
+#define WD_CDB_12    0x0e
+#define WD_TARGET_LUN      0x0f
+#define WD_COMMAND_PHASE   0x10
+#define WD_SYNCHRONOUS_TRANSFER 0x11
+#define WD_TRANSFER_COUNT_MSB 0x12
+#define WD_TRANSFER_COUNT  0x13
+#define WD_TRANSFER_COUNT_LSB 0x14
+#define WD_DESTINATION_ID  0x15
+#define WD_SOURCE_ID    0x16
+#define WD_SCSI_STATUS     0x17
+#define WD_COMMAND      0x18
+#define WD_DATA      0x19
+#define WD_QUEUE_TAG    0x1a
+#define WD_AUXILIARY_STATUS   0x1f
+
+/* WD commands */
+#define WD_CMD_RESET    0x00
+#define WD_CMD_ABORT    0x01
+#define WD_CMD_ASSERT_ATN  0x02
+#define WD_CMD_NEGATE_ACK  0x03
+#define WD_CMD_DISCONNECT  0x04
+#define WD_CMD_RESELECT    0x05
+#define WD_CMD_SEL_ATN     0x06
+#define WD_CMD_SEL      0x07
+#define WD_CMD_SEL_ATN_XFER   0x08
+#define WD_CMD_SEL_XFER    0x09
+#define WD_CMD_RESEL_RECEIVE  0x0a
+#define WD_CMD_RESEL_SEND  0x0b
+#define WD_CMD_WAIT_SEL_RECEIVE 0x0c
+#define WD_CMD_TRANS_ADDR  0x18
+#define WD_CMD_TRANS_INFO  0x20
+#define WD_CMD_TRANSFER_PAD   0x21
+#define WD_CMD_SBT_MODE    0x80
+
+/* ASR register */
+#define ASR_INT         (0x80)
+#define ASR_LCI         (0x40)
+#define ASR_BSY         (0x20)
+#define ASR_CIP         (0x10)
+#define ASR_PE          (0x02)
+#define ASR_DBR         (0x01)
+
+/* SCSI Bus Phases */
+#define PHS_DATA_OUT    0x00
+#define PHS_DATA_IN     0x01
+#define PHS_COMMAND     0x02
+#define PHS_STATUS      0x03
+#define PHS_MESS_OUT    0x06
+#define PHS_MESS_IN     0x07
+
+/* Command Status Register definitions */
+
+  /* reset state interrupts */
+#define CSR_RESET    0x00
+#define CSR_RESET_AF    0x01
+
+  /* successful completion interrupts */
+#define CSR_RESELECT    0x10
+#define CSR_SELECT      0x11
+#define CSR_SEL_XFER_DONE  0x16
+#define CSR_XFER_DONE      0x18
+
+  /* paused or aborted interrupts */
+#define CSR_MSGIN    0x20
+#define CSR_SDP         0x21
+#define CSR_SEL_ABORT      0x22
+#define CSR_RESEL_ABORT    0x25
+#define CSR_RESEL_ABORT_AM 0x27
+#define CSR_ABORT    0x28
+
+  /* terminated interrupts */
+#define CSR_INVALID     0x40
+#define CSR_UNEXP_DISC     0x41
+#define CSR_TIMEOUT     0x42
+#define CSR_PARITY      0x43
+#define CSR_PARITY_ATN     0x44
+#define CSR_BAD_STATUS     0x45
+#define CSR_UNEXP    0x48
+
+  /* service required interrupts */
+#define CSR_RESEL    0x80
+#define CSR_RESEL_AM    0x81
+#define CSR_DISC     0x85
+#define CSR_SRV_REQ     0x88
+
+   /* Own ID/CDB Size register */
+#define OWNID_EAF    0x08
+#define OWNID_EHP    0x10
+#define OWNID_RAF    0x20
+#define OWNID_FS_8   0x00
+#define OWNID_FS_12  0x40
+#define OWNID_FS_16  0x80
+
+   /* define these so we don't have to change a2091.c, etc. */
+#define WD33C93_FS_8_10  OWNID_FS_8
+#define WD33C93_FS_12_15 OWNID_FS_12
+#define WD33C93_FS_16_20 OWNID_FS_16
+
+   /* Control register */
+#define CTRL_HSP     0x01
+#define CTRL_HA      0x02
+#define CTRL_IDI     0x04
+#define CTRL_EDI     0x08
+#define CTRL_HHP     0x10
+#define CTRL_POLLED  0x00
+#define CTRL_BURST   0x20
+#define CTRL_BUS     0x40
+#define CTRL_DMA     0x80
+
+   /* Timeout Period register */
+#define TIMEOUT_PERIOD_VALUE  20    /* 20 = 200 ms */
+
+   /* Synchronous Transfer Register */
+#define STR_FSS      0x80
+
+   /* Destination ID register */
+#define DSTID_DPD    0x40
+#define DATA_OUT_DIR 0
+#define DATA_IN_DIR  1
+#define DSTID_SCC    0x80
+
+   /* Source ID register */
+#define SRCID_MASK   0x07
+#define SRCID_SIV    0x08
+#define SRCID_DSP    0x20
+#define SRCID_ES     0x40
+#define SRCID_ER     0x80
+
+   /* This is what the 3393 chip looks like to us */
+typedef struct {
+#ifdef CONFIG_WD33C93_PIO
+   unsigned int   SASR;
+   unsigned int   SCMD;
+#else
+   volatile unsigned char  *SASR;
+   volatile unsigned char  *SCMD;
+#endif
+} wd33c93_regs;
+
+
+typedef int (*dma_setup_t) (struct scsi_cmnd *SCpnt, int dir_in);
+typedef void (*dma_stop_t) (struct Scsi_Host *instance,
+		struct scsi_cmnd *SCpnt, int status);
+
+
+#define ILLEGAL_STATUS_BYTE   0xff
+
+#define DEFAULT_SX_PER   376     /* (ns) fairly safe */
+#define DEFAULT_SX_OFF   0       /* aka async */
+
+#define OPTIMUM_SX_PER   252     /* (ns) best we can do (mult-of-4) */
+#define OPTIMUM_SX_OFF   12      /* size of wd3393 fifo */
+
+struct sx_period {
+   unsigned int   period_ns;
+   uchar          reg_value;
+   };
+
+/* FEF: defines for hostdata->dma_buffer_pool */
+
+#define BUF_CHIP_ALLOCED 0
+#define BUF_SCSI_ALLOCED 1
+
+struct WD33C93_hostdata {
+    struct Scsi_Host *next;
+    wd33c93_regs     regs;
+    spinlock_t       lock;
+    uchar            clock_freq;
+    uchar            chip;             /* what kind of wd33c93? */
+    uchar            microcode;        /* microcode rev */
+    uchar            dma_buffer_pool;  /* FEF: buffer from chip_ram? */
+    int              dma_dir;          /* data transfer dir. */
+    dma_setup_t      dma_setup;
+    dma_stop_t       dma_stop;
+    unsigned int     dma_xfer_mask;
+    uchar            *dma_bounce_buffer;
+    unsigned int     dma_bounce_len;
+    volatile uchar   busy[8];          /* index = target, bit = lun */
+    volatile struct scsi_cmnd *input_Q;       /* commands waiting to be started */
+    volatile struct scsi_cmnd *selecting;     /* trying to select this command */
+    volatile struct scsi_cmnd *connected;     /* currently connected command */
+    volatile struct scsi_cmnd *disconnected_Q;/* commands waiting for reconnect */
+    uchar            state;            /* what we are currently doing */
+    uchar            dma;              /* current state of DMA (on/off) */
+    uchar            level2;           /* extent to which Level-2 commands are used */
+    uchar            disconnect;       /* disconnect/reselect policy */
+    unsigned int     args;             /* set from command-line argument */
+    uchar            incoming_msg[8];  /* filled during message_in phase */
+    int              incoming_ptr;     /* mainly used with EXTENDED messages */
+    uchar            outgoing_msg[8];  /* send this during next message_out */
+    int              outgoing_len;     /* length of outgoing message */
+    unsigned int     default_sx_per;   /* default transfer period for SCSI bus */
+    uchar            sync_xfer[8];     /* sync_xfer reg settings per target */
+    uchar            sync_stat[8];     /* status of sync negotiation per target */
+    uchar            no_sync;          /* bitmask: don't do sync on these targets */
+    uchar            no_dma;           /* set this flag to disable DMA */
+#ifdef PROC_INTERFACE
+    uchar            proc;             /* bitmask: what's in proc output */
+#ifdef PROC_STATISTICS
+    unsigned long    cmd_cnt[8];       /* # of commands issued per target */
+    unsigned long    int_cnt;          /* # of interrupts serviced */
+    unsigned long    pio_cnt;          /* # of pio data transfers */
+    unsigned long    dma_cnt;          /* # of DMA data transfers */
+    unsigned long    disc_allowed_cnt[8]; /* # of disconnects allowed per target */
+    unsigned long    disc_done_cnt[8]; /* # of disconnects done per target*/
+#endif
+#endif
+    };
+
+
+/* defines for hostdata->chip */
+
+#define C_WD33C93       0
+#define C_WD33C93A      1
+#define C_WD33C93B      2
+#define C_UNKNOWN_CHIP  100
+
+/* defines for hostdata->state */
+
+#define S_UNCONNECTED         0
+#define S_SELECTING           1
+#define S_RUNNING_LEVEL2      2
+#define S_CONNECTED           3
+#define S_PRE_TMP_DISC        4
+#define S_PRE_CMP_DISC        5
+
+/* defines for hostdata->dma */
+
+#define D_DMA_OFF          0
+#define D_DMA_RUNNING      1
+
+/* defines for hostdata->level2 */
+/* NOTE: only the first 3 are implemented so far */
+
+#define L2_NONE      1  /* no combination commands - we get lots of ints */
+#define L2_SELECT    2  /* start with SEL_ATN_XFER, but never resume it */
+#define L2_BASIC     3  /* resume after STATUS ints & RDP messages */
+#define L2_DATA      4  /* resume after DATA_IN/OUT ints */
+#define L2_MOST      5  /* resume after anything except a RESELECT int */
+#define L2_RESELECT  6  /* resume after everything, including RESELECT ints */
+#define L2_ALL       7  /* always resume */
+
+/* defines for hostdata->disconnect */
+
+#define DIS_NEVER    0
+#define DIS_ADAPTIVE 1
+#define DIS_ALWAYS   2
+
+/* defines for hostdata->args */
+
+#define DB_TEST1              1<<0
+#define DB_TEST2              1<<1
+#define DB_QUEUE_COMMAND      1<<2
+#define DB_EXECUTE            1<<3
+#define DB_INTR               1<<4
+#define DB_TRANSFER           1<<5
+#define DB_MASK               0x3f
+
+/* defines for hostdata->sync_stat[] */
+
+#define SS_UNSET     0
+#define SS_FIRST     1
+#define SS_WAITING   2
+#define SS_SET       3
+
+/* defines for hostdata->proc */
+
+#define PR_VERSION   1<<0
+#define PR_INFO      1<<1
+#define PR_STATISTICS 1<<2
+#define PR_CONNECTED 1<<3
+#define PR_INPUTQ    1<<4
+#define PR_DISCQ     1<<5
+#define PR_TEST      1<<6
+#define PR_STOP      1<<7
+
+
+void wd33c93_init (struct Scsi_Host *instance, const wd33c93_regs regs,
+         dma_setup_t setup, dma_stop_t stop, int clock_freq);
+int wd33c93_abort (struct scsi_cmnd *cmd);
+int wd33c93_queuecommand (struct scsi_cmnd *cmd,
+		void (*done)(struct scsi_cmnd *));
+void wd33c93_intr (struct Scsi_Host *instance);
+int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int);
+int wd33c93_host_reset (struct scsi_cmnd *);
+void wd33c93_release(void);
+
+#endif /* WD33C93_H */
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
new file mode 100644
index 0000000..bf4a758
--- /dev/null
+++ b/drivers/scsi/wd7000.c
@@ -0,0 +1,1667 @@
+/* $Id: $
+ *  linux/drivers/scsi/wd7000.c
+ *
+ *  Copyright (C) 1992  Thomas Wuensche
+ *	closely related to the aha1542 driver from Tommy Thorn
+ *	( as close as different hardware allows on a lowlevel-driver :-) )
+ *
+ *  Revised (and renamed) by John Boyd <boyd@cis.ohio-state.edu> to
+ *  accommodate Eric Youngdale's modifications to scsi.c.  Nov 1992.
+ *
+ *  Additional changes to support scatter/gather.  Dec. 1992.  tw/jb
+ *
+ *  No longer tries to reset SCSI bus at boot (it wasn't working anyway).
+ *  Rewritten to support multiple host adapters.
+ *  Miscellaneous cleanup.
+ *  So far, still doesn't do reset or abort correctly, since I have no idea
+ *  how to do them with this board (8^(.                      Jan 1994 jb
+ *
+ * This driver now supports both of the two standard configurations (per
+ * the 3.36 Owner's Manual, my latest reference) by the same method as
+ * before; namely, by looking for a BIOS signature.  Thus, the location of
+ * the BIOS signature determines the board configuration.  Until I have
+ * time to do something more flexible, users should stick to one of the
+ * following:
+ *
+ * Standard configuration for single-adapter systems:
+ *    - BIOS at CE00h
+ *    - I/O base address 350h
+ *    - IRQ level 15
+ *    - DMA channel 6
+ * Standard configuration for a second adapter in a system:
+ *    - BIOS at C800h
+ *    - I/O base address 330h
+ *    - IRQ level 11
+ *    - DMA channel 5
+ *
+ * Anyone who can recompile the kernel is welcome to add others as need
+ * arises, but unpredictable results may occur if there are conflicts.
+ * In any event, if there are multiple adapters in a system, they MUST
+ * use different I/O bases, IRQ levels, and DMA channels, since they will be
+ * indistinguishable (and in direct conflict) otherwise.
+ *
+ *   As a point of information, the NO_OP command toggles the CMD_RDY bit
+ * of the status port, and this fact could be used as a test for the I/O
+ * base address (or more generally, board detection).  There is an interrupt
+ * status port, so IRQ probing could also be done.  I suppose the full
+ * DMA diagnostic could be used to detect the DMA channel being used.  I
+ * haven't done any of this, though, because I think there's too much of
+ * a chance that such explorations could be destructive, if some other
+ * board's resources are used inadvertently.  So, call me a wimp, but I
+ * don't want to try it.  The only kind of exploration I trust is memory
+ * exploration, since it's more certain that reading memory won't be
+ * destructive.
+ *
+ * More to my liking would be a LILO boot command line specification, such
+ * as is used by the aha152x driver (and possibly others).  I'll look into
+ * it, as I have time...
+ *
+ *   I get mail occasionally from people who either are using or are
+ * considering using a WD7000 with Linux.  There is a variety of
+ * nomenclature describing WD7000's.  To the best of my knowledge, the
+ * following is a brief summary (from an old WD doc - I don't work for
+ * them or anything like that):
+ *
+ * WD7000-FASST2: This is a WD7000 board with the real-mode SST ROM BIOS
+ *        installed.  Last I heard, the BIOS was actually done by Columbia
+ *        Data Products.  The BIOS is only used by this driver (and thus
+ *        by Linux) to identify the board; none of it can be executed under
+ *        Linux.
+ *
+ * WD7000-ASC: This is the original adapter board, with or without BIOS.
+ *        The board uses a WD33C93 or WD33C93A SBIC, which in turn is
+ *        controlled by an onboard Z80 processor.  The board interface
+ *        visible to the host CPU is defined effectively by the Z80's
+ *        firmware, and it is this firmware's revision level that is
+ *        determined and reported by this driver.  (The version of the
+ *        on-board BIOS is of no interest whatsoever.)  The host CPU has
+ *        no access to the SBIC; hence the fact that it is a WD33C93 is
+ *        also of no interest to this driver.
+ *
+ * WD7000-AX:
+ * WD7000-MX:
+ * WD7000-EX: These are newer versions of the WD7000-ASC.  The -ASC is
+ *        largely built from discrete components; these boards use more
+ *        integration.  The -AX is an ISA bus board (like the -ASC),
+ *        the -MX is an MCA (i.e., PS/2) bus board), and the -EX is an
+ *        EISA bus board.
+ *
+ *  At the time of my documentation, the -?X boards were "future" products,
+ *  and were not yet available.  However, I vaguely recall that Thomas
+ *  Wuensche had an -AX, so I believe at least it is supported by this
+ *  driver.  I have no personal knowledge of either -MX or -EX boards.
+ *
+ *  P.S. Just recently, I've discovered (directly from WD and Future
+ *  Domain) that all but the WD7000-EX have been out of production for
+ *  two years now.  FD has production rights to the 7000-EX, and are
+ *  producing it under a new name, and with a new BIOS.  If anyone has
+ *  one of the FD boards, it would be nice to come up with a signature
+ *  for it.
+ *                                                           J.B. Jan 1994.
+ *
+ *
+ *  Revisions by Miroslav Zagorac <zaga@fly.cc.fer.hr>
+ *
+ *  08/24/1996.
+ *
+ *  Enhancement for wd7000_detect function has been made, so you don't have
+ *  to enter BIOS ROM address in initialisation data (see struct Config).
+ *  We cannot detect IRQ, DMA and I/O base address for now, so we have to
+ *  enter them as arguments while wd_7000 is detected. If someone has IRQ,
+ *  DMA or I/O base address set to some other value, he can enter them in
+ *  configuration without any problem. Also I wrote a function wd7000_setup,
+ *  so now you can enter WD-7000 definition as kernel arguments,
+ *  as in lilo.conf:
+ *
+ *     append="wd7000=IRQ,DMA,IO"
+ *
+ *  PS: If card BIOS ROM is disabled, function wd7000_detect now will recognize
+ *      adapter, unlike the old one. Anyway, BIOS ROM from WD7000 adapter is
+ *      useless for Linux. B^)
+ *
+ *
+ *  09/06/1996.
+ *
+ *  Autodetecting of I/O base address from wd7000_detect function is removed,
+ *  some little bugs removed, etc...
+ *
+ *  Thanks to Roger Scott for driver debugging.
+ *
+ *  06/07/1997
+ *
+ *  Added support for /proc file system (/proc/scsi/wd7000/[0...] files).
+ *  Now, driver can handle hard disks with capacity >1GB.
+ *
+ *  01/15/1998
+ *
+ *  Added support for BUS_ON and BUS_OFF parameters in config line.
+ *  Miscellaneous cleanup.
+ *
+ *  03/01/1998
+ *
+ *  WD7000 driver now work on kernels >= 2.1.x
+ *
+ *
+ * 12/31/2001 - Arnaldo Carvalho de Melo <acme@conectiva.com.br>
+ *
+ * use host->host_lock, not io_request_lock, cleanups
+ *
+ * 2002/10/04 - Alan Cox <alan@redhat.com>
+ *
+ * Use dev_id for interrupts, kill __FUNCTION__ pasting
+ * Add a lock for the scb pool, clean up all other cli/sti usage stuff
+ * Use the adapter lock for the other places we had the cli's
+ *
+ * 2002/10/06 - Alan Cox <alan@redhat.com>
+ *
+ * Switch to new style error handling
+ * Clean up delay to udelay, and yielding sleeps
+ * Make host reset actually reset the card
+ * Make everything static
+ *
+ * 2003/02/12 - Christoph Hellwig <hch@infradead.org>
+ *
+ * Cleaned up host template defintion
+ * Removed now obsolete wd7000.h
+ */
+
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/stat.h>
+
+#include <asm/system.h>
+#include <asm/dma.h>
+#include <asm/io.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsicam.h>
+
+
+#undef  WD7000_DEBUG		/* general debug                */
+#ifdef WD7000_DEBUG
+#define dprintk printk
+#else
+#define dprintk(format,args...)
+#endif
+
+/*
+ *  Mailbox structure sizes.
+ *  I prefer to keep the number of ICMBs much larger than the number of
+ *  OGMBs.  OGMBs are used very quickly by the driver to start one or
+ *  more commands, while ICMBs are used by the host adapter per command.
+ */
+#define OGMB_CNT	16
+#define ICMB_CNT	32
+
+/*
+ *  Scb's are shared by all active adapters.  So, if they all become busy,
+ *  callers may be made to wait in alloc_scbs for them to free.  That can
+ *  be avoided by setting MAX_SCBS to NUM_CONFIG * WD7000_Q.  If you'd
+ *  rather conserve memory, use a smaller number (> 0, of course) - things
+ *  will should still work OK.
+ */
+#define MAX_SCBS        32
+
+/*
+ *  In this version, sg_tablesize now defaults to WD7000_SG, and will
+ *  be set to SG_NONE for older boards.  This is the reverse of the
+ *  previous default, and was changed so that the driver-level
+ *  scsi_host_template would reflect the driver's support for scatter/
+ *  gather.
+ *
+ *  Also, it has been reported that boards at Revision 6 support scatter/
+ *  gather, so the new definition of an "older" board has been changed
+ *  accordingly.
+ */
+#define WD7000_Q	16
+#define WD7000_SG	16
+
+
+/*
+ *  WD7000-specific mailbox structure
+ *
+ */
+typedef volatile struct mailbox {
+	unchar status;
+	unchar scbptr[3];	/* SCSI-style - MSB first (big endian) */
+} Mailbox;
+
+/*
+ *  This structure should contain all per-adapter global data.  I.e., any
+ *  new global per-adapter data should put in here.
+ */
+typedef struct adapter {
+	struct Scsi_Host *sh;	/* Pointer to Scsi_Host structure    */
+	int iobase;		/* This adapter's I/O base address   */
+	int irq;		/* This adapter's IRQ level          */
+	int dma;		/* This adapter's DMA channel        */
+	int int_counter;	/* This adapter's interrupt counter  */
+	int bus_on;		/* This adapter's BUS_ON time        */
+	int bus_off;		/* This adapter's BUS_OFF time       */
+	struct {		/* This adapter's mailboxes          */
+		Mailbox ogmb[OGMB_CNT];	/* Outgoing mailboxes                */
+		Mailbox icmb[ICMB_CNT];	/* Incoming mailboxes                */
+	} mb;
+	int next_ogmb;		/* to reduce contention at mailboxes */
+	unchar control;		/* shadows CONTROL port value        */
+	unchar rev1, rev2;	/* filled in by wd7000_revision      */
+} Adapter;
+
+/*
+ * (linear) base address for ROM BIOS
+ */
+static const long wd7000_biosaddr[] = {
+	0xc0000, 0xc2000, 0xc4000, 0xc6000, 0xc8000, 0xca000, 0xcc000, 0xce000,
+	0xd0000, 0xd2000, 0xd4000, 0xd6000, 0xd8000, 0xda000, 0xdc000, 0xde000
+};
+#define NUM_ADDRS (sizeof(wd7000_biosaddr)/sizeof(long))
+
+static const unsigned short wd7000_iobase[] = {
+	0x0300, 0x0308, 0x0310, 0x0318, 0x0320, 0x0328, 0x0330, 0x0338,
+	0x0340, 0x0348, 0x0350, 0x0358, 0x0360, 0x0368, 0x0370, 0x0378,
+	0x0380, 0x0388, 0x0390, 0x0398, 0x03a0, 0x03a8, 0x03b0, 0x03b8,
+	0x03c0, 0x03c8, 0x03d0, 0x03d8, 0x03e0, 0x03e8, 0x03f0, 0x03f8
+};
+#define NUM_IOPORTS (sizeof(wd7000_iobase)/sizeof(unsigned short))
+
+static const short wd7000_irq[] = { 3, 4, 5, 7, 9, 10, 11, 12, 14, 15 };
+#define NUM_IRQS (sizeof(wd7000_irq)/sizeof(short))
+
+static const short wd7000_dma[] = { 5, 6, 7 };
+#define NUM_DMAS (sizeof(wd7000_dma)/sizeof(short))
+
+/*
+ * The following is set up by wd7000_detect, and used thereafter for
+ * proc and other global ookups
+ */
+
+#define UNITS	8
+static struct Scsi_Host *wd7000_host[UNITS];
+
+#define BUS_ON    64		/* x 125ns = 8000ns (BIOS default) */
+#define BUS_OFF   15		/* x 125ns = 1875ns (BIOS default) */
+
+/*
+ *  Standard Adapter Configurations - used by wd7000_detect
+ */
+typedef struct {
+	short irq;		/* IRQ level                                  */
+	short dma;		/* DMA channel                                */
+	unsigned iobase;	/* I/O base address                           */
+	short bus_on;		/* Time that WD7000 spends on the AT-bus when */
+	/* transferring data. BIOS default is 8000ns. */
+	short bus_off;		/* Time that WD7000 spends OFF THE BUS after  */
+	/* while it is transferring data.             */
+	/* BIOS default is 1875ns                     */
+} Config;
+
+/*
+ * Add here your configuration...
+ */
+static Config configs[] = {
+	{15, 6, 0x350, BUS_ON, BUS_OFF},	/* defaults for single adapter */
+	{11, 5, 0x320, BUS_ON, BUS_OFF},	/* defaults for second adapter */
+	{7, 6, 0x350, BUS_ON, BUS_OFF},	/* My configuration (Zaga)     */
+	{-1, -1, 0x0, BUS_ON, BUS_OFF}	/* Empty slot                  */
+};
+#define NUM_CONFIGS (sizeof(configs)/sizeof(Config))
+
+/*
+ *  The following list defines strings to look for in the BIOS that identify
+ *  it as the WD7000-FASST2 SST BIOS.  I suspect that something should be
+ *  added for the Future Domain version.
+ */
+typedef struct signature {
+	const char *sig;	/* String to look for            */
+	unsigned long ofs;	/* offset from BIOS base address */
+	unsigned len;		/* length of string              */
+} Signature;
+
+static const Signature signatures[] = {
+	{"SSTBIOS", 0x0000d, 7}	/* "SSTBIOS" @ offset 0x0000d */
+};
+#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature))
+
+
+/*
+ *  I/O Port Offsets and Bit Definitions
+ *  4 addresses are used.  Those not defined here are reserved.
+ */
+#define ASC_STAT        0	/* Status,  Read          */
+#define ASC_COMMAND     0	/* Command, Write         */
+#define ASC_INTR_STAT   1	/* Interrupt Status, Read */
+#define ASC_INTR_ACK    1	/* Acknowledge, Write     */
+#define ASC_CONTROL     2	/* Control, Write         */
+
+/*
+ * ASC Status Port
+ */
+#define INT_IM		0x80	/* Interrupt Image Flag           */
+#define CMD_RDY		0x40	/* Command Port Ready             */
+#define CMD_REJ		0x20	/* Command Port Byte Rejected     */
+#define ASC_INIT        0x10	/* ASC Initialized Flag           */
+#define ASC_STATMASK    0xf0	/* The lower 4 Bytes are reserved */
+
+/*
+ * COMMAND opcodes
+ *
+ *  Unfortunately, I have no idea how to properly use some of these commands,
+ *  as the OEM manual does not make it clear.  I have not been able to use
+ *  enable/disable unsolicited interrupts or the reset commands with any
+ *  discernible effect whatsoever.  I think they may be related to certain
+ *  ICB commands, but again, the OEM manual doesn't make that clear.
+ */
+#define NO_OP             0	/* NO-OP toggles CMD_RDY bit in ASC_STAT  */
+#define INITIALIZATION    1	/* initialization (10 bytes)              */
+#define DISABLE_UNS_INTR  2	/* disable unsolicited interrupts         */
+#define ENABLE_UNS_INTR   3	/* enable unsolicited interrupts          */
+#define INTR_ON_FREE_OGMB 4	/* interrupt on free OGMB                 */
+#define SOFT_RESET        5	/* SCSI bus soft reset                    */
+#define HARD_RESET_ACK    6	/* SCSI bus hard reset acknowledge        */
+#define START_OGMB        0x80	/* start command in OGMB (n)              */
+#define SCAN_OGMBS        0xc0	/* start multiple commands, signature (n) */
+				/*    where (n) = lower 6 bits            */
+/*
+ * For INITIALIZATION:
+ */
+typedef struct initCmd {
+	unchar op;		/* command opcode (= 1)                    */
+	unchar ID;		/* Adapter's SCSI ID                       */
+	unchar bus_on;		/* Bus on time, x 125ns (see below)        */
+	unchar bus_off;		/* Bus off time, ""         ""             */
+	unchar rsvd;		/* Reserved                                */
+	unchar mailboxes[3];	/* Address of Mailboxes, MSB first         */
+	unchar ogmbs;		/* Number of outgoing MBs, max 64, 0,1 = 1 */
+	unchar icmbs;		/* Number of incoming MBs,   ""       ""   */
+} InitCmd;
+
+/*
+ * Interrupt Status Port - also returns diagnostic codes at ASC reset
+ *
+ * if msb is zero, the lower bits are diagnostic status
+ * Diagnostics:
+ * 01   No diagnostic error occurred
+ * 02   RAM failure
+ * 03   FIFO R/W failed
+ * 04   SBIC register read/write failed
+ * 05   Initialization D-FF failed
+ * 06   Host IRQ D-FF failed
+ * 07   ROM checksum error
+ * Interrupt status (bitwise):
+ * 10NNNNNN   outgoing mailbox NNNNNN is free
+ * 11NNNNNN   incoming mailbox NNNNNN needs service
+ */
+#define MB_INTR    0xC0		/* Mailbox Service possible/required */
+#define IMB_INTR   0x40		/* 1 Incoming / 0 Outgoing           */
+#define MB_MASK    0x3f		/* mask for mailbox number           */
+
+/*
+ * CONTROL port bits
+ */
+#define INT_EN     0x08		/* Interrupt Enable */
+#define DMA_EN     0x04		/* DMA Enable       */
+#define SCSI_RES   0x02		/* SCSI Reset       */
+#define ASC_RES    0x01		/* ASC Reset        */
+
+/*
+ * Driver data structures:
+ *   - mb and scbs are required for interfacing with the host adapter.
+ *     An SCB has extra fields not visible to the adapter; mb's
+ *     _cannot_ do this, since the adapter assumes they are contiguous in
+ *     memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact
+ *     to access them.
+ *   - An icb is for host-only (non-SCSI) commands.  ICBs are 16 bytes each;
+ *     the additional bytes are used only by the driver.
+ *   - For now, a pool of SCBs are kept in global storage by this driver,
+ *     and are allocated and freed as needed.
+ *
+ *  The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command,
+ *  not when it has finished.  Since the SCB must be around for completion,
+ *  problems arise when SCBs correspond to OGMBs, which may be reallocated
+ *  earlier (or delayed unnecessarily until a command completes).
+ *  Mailboxes are used as transient data structures, simply for
+ *  carrying SCB addresses to/from the 7000-FASST2.
+ *
+ *  Note also since SCBs are not "permanently" associated with mailboxes,
+ *  there is no need to keep a global list of scsi_cmnd pointers indexed
+ *  by OGMB.   Again, SCBs reference their scsi_cmnds directly, so mailbox
+ *  indices need not be involved.
+ */
+
+/*
+ *  WD7000-specific scatter/gather element structure
+ */
+typedef struct sgb {
+	unchar len[3];
+	unchar ptr[3];		/* Also SCSI-style - MSB first */
+} Sgb;
+
+typedef struct scb {		/* Command Control Block 5.4.1               */
+	unchar op;		/* Command Control Block Operation Code      */
+	unchar idlun;		/* op=0,2:Target Id, op=1:Initiator Id       */
+	/* Outbound data transfer, length is checked */
+	/* Inbound data transfer, length is checked  */
+	/* Logical Unit Number                       */
+	unchar cdb[12];		/* SCSI Command Block                        */
+	volatile unchar status;	/* SCSI Return Status                        */
+	volatile unchar vue;	/* Vendor Unique Error Code                  */
+	unchar maxlen[3];	/* Maximum Data Transfer Length              */
+	unchar dataptr[3];	/* SCSI Data Block Pointer                   */
+	unchar linkptr[3];	/* Next Command Link Pointer                 */
+	unchar direc;		/* Transfer Direction                        */
+	unchar reserved2[6];	/* SCSI Command Descriptor Block             */
+	/* end of hardware SCB                       */
+	struct scsi_cmnd *SCpnt;/* scsi_cmnd using this SCB                  */
+	Sgb sgb[WD7000_SG];	/* Scatter/gather list for this SCB          */
+	Adapter *host;		/* host adapter                              */
+	struct scb *next;	/* for lists of scbs                         */
+} Scb;
+
+/*
+ *  This driver is written to allow host-only commands to be executed.
+ *  These use a 16-byte block called an ICB.  The format is extended by the
+ *  driver to 18 bytes, to support the status returned in the ICMB and
+ *  an execution phase code.
+ *
+ *  There are other formats besides these; these are the ones I've tried
+ *  to use.  Formats for some of the defined ICB opcodes are not defined
+ *  (notably, get/set unsolicited interrupt status) in my copy of the OEM
+ *  manual, and others are ambiguous/hard to follow.
+ */
+#define ICB_OP_MASK           0x80	/* distinguishes scbs from icbs        */
+#define ICB_OP_OPEN_RBUF      0x80	/* open receive buffer                 */
+#define ICB_OP_RECV_CMD       0x81	/* receive command from initiator      */
+#define ICB_OP_RECV_DATA      0x82	/* receive data from initiator         */
+#define ICB_OP_RECV_SDATA     0x83	/* receive data with status from init. */
+#define ICB_OP_SEND_DATA      0x84	/* send data with status to initiator  */
+#define ICB_OP_SEND_STAT      0x86	/* send command status to initiator    */
+					/* 0x87 is reserved                    */
+#define ICB_OP_READ_INIT      0x88	/* read initialization bytes           */
+#define ICB_OP_READ_ID        0x89	/* read adapter's SCSI ID              */
+#define ICB_OP_SET_UMASK      0x8A	/* set unsolicited interrupt mask      */
+#define ICB_OP_GET_UMASK      0x8B	/* read unsolicited interrupt mask     */
+#define ICB_OP_GET_REVISION   0x8C	/* read firmware revision level        */
+#define ICB_OP_DIAGNOSTICS    0x8D	/* execute diagnostics                 */
+#define ICB_OP_SET_EPARMS     0x8E	/* set execution parameters            */
+#define ICB_OP_GET_EPARMS     0x8F	/* read execution parameters           */
+
+typedef struct icbRecvCmd {
+	unchar op;
+	unchar IDlun;		/* Initiator SCSI ID/lun     */
+	unchar len[3];		/* command buffer length     */
+	unchar ptr[3];		/* command buffer address    */
+	unchar rsvd[7];		/* reserved                  */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
+} IcbRecvCmd;
+
+typedef struct icbSendStat {
+	unchar op;
+	unchar IDlun;		/* Target SCSI ID/lun                  */
+	unchar stat;		/* (outgoing) completion status byte 1 */
+	unchar rsvd[12];	/* reserved                            */
+	volatile unchar vue;	/* vendor-unique error code            */
+	volatile unchar status;	/* returned (icmb) status              */
+	volatile unchar phase;	/* used by interrupt handler           */
+} IcbSendStat;
+
+typedef struct icbRevLvl {
+	unchar op;
+	volatile unchar primary;	/* primary revision level (returned)   */
+	volatile unchar secondary;	/* secondary revision level (returned) */
+	unchar rsvd[12];	/* reserved                            */
+	volatile unchar vue;	/* vendor-unique error code            */
+	volatile unchar status;	/* returned (icmb) status              */
+	volatile unchar phase;	/* used by interrupt handler           */
+} IcbRevLvl;
+
+typedef struct icbUnsMask {	/* I'm totally guessing here */
+	unchar op;
+	volatile unchar mask[14];	/* mask bits                 */
+#if 0
+	unchar rsvd[12];	/* reserved                  */
+#endif
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
+} IcbUnsMask;
+
+typedef struct icbDiag {
+	unchar op;
+	unchar type;		/* diagnostics type code (0-3) */
+	unchar len[3];		/* buffer length               */
+	unchar ptr[3];		/* buffer address              */
+	unchar rsvd[7];		/* reserved                    */
+	volatile unchar vue;	/* vendor-unique error code    */
+	volatile unchar status;	/* returned (icmb) status      */
+	volatile unchar phase;	/* used by interrupt handler   */
+} IcbDiag;
+
+#define ICB_DIAG_POWERUP   0	/* Power-up diags only       */
+#define ICB_DIAG_WALKING   1	/* walking 1's pattern       */
+#define ICB_DIAG_DMA       2	/* DMA - system memory diags */
+#define ICB_DIAG_FULL      3	/* do both 1 & 2             */
+
+typedef struct icbParms {
+	unchar op;
+	unchar rsvd1;		/* reserved                  */
+	unchar len[3];		/* parms buffer length       */
+	unchar ptr[3];		/* parms buffer address      */
+	unchar idx[2];		/* index (MSB-LSB)           */
+	unchar rsvd2[5];	/* reserved                  */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
+} IcbParms;
+
+typedef struct icbAny {
+	unchar op;
+	unchar data[14];	/* format-specific data      */
+	volatile unchar vue;	/* vendor-unique error code  */
+	volatile unchar status;	/* returned (icmb) status    */
+	volatile unchar phase;	/* used by interrupt handler */
+} IcbAny;
+
+typedef union icb {
+	unchar op;		/* ICB opcode                     */
+	IcbRecvCmd recv_cmd;	/* format for receive command     */
+	IcbSendStat send_stat;	/* format for send status         */
+	IcbRevLvl rev_lvl;	/* format for get revision level  */
+	IcbDiag diag;		/* format for execute diagnostics */
+	IcbParms eparms;	/* format for get/set exec parms  */
+	IcbAny icb;		/* generic format                 */
+	unchar data[18];
+} Icb;
+
+#ifdef MODULE
+static char *wd7000;
+module_param(wd7000, charp, 0);
+#endif
+
+/*
+ *  Driver SCB structure pool.
+ *
+ *  The SCBs declared here are shared by all host adapters; hence, this
+ *  structure is not part of the Adapter structure.
+ */
+static Scb scbs[MAX_SCBS];
+static Scb *scbfree;		/* free list         */
+static int freescbs = MAX_SCBS;	/* free list counter */
+static spinlock_t scbpool_lock;	/* guards the scb free list and count */
+
+/*
+ *  END of data/declarations - code follows.
+ */
+static void __init setup_error(char *mesg, int *ints)
+{
+	if (ints[0] == 3)
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x\" -> %s\n", ints[1], ints[2], ints[3], mesg);
+	else if (ints[0] == 4)
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], mesg);
+	else
+		printk(KERN_ERR "wd7000_setup: \"wd7000=%d,%d,0x%x,%d,%d\" -> %s\n", ints[1], ints[2], ints[3], ints[4], ints[5], mesg);
+}
+
+
+/*
+ * Note: You can now set these options from the kernel's "command line".
+ * The syntax is:
+ *
+ *     wd7000=<IRQ>,<DMA>,<IO>[,<BUS_ON>[,<BUS_OFF>]]
+ *
+ * , where BUS_ON and BUS_OFF are in nanoseconds. BIOS default values
+ * are 8000ns for BUS_ON and 1875ns for BUS_OFF.
+ * eg:
+ *     wd7000=7,6,0x350
+ *
+ * will configure the driver for a WD-7000 controller
+ * using IRQ 15 with a DMA channel 6, at IO base address 0x350.
+ */
+static int __init wd7000_setup(char *str)
+{
+	static short wd7000_card_num;	/* .bss will zero this */
+	short i;
+	int ints[6];
+
+	(void) get_options(str, ARRAY_SIZE(ints), ints);
+
+	if (wd7000_card_num >= NUM_CONFIGS) {
+		printk(KERN_ERR "%s: Too many \"wd7000=\" configurations in " "command line!\n", __FUNCTION__);
+		return 0;
+	}
+
+	if ((ints[0] < 3) || (ints[0] > 5)) {
+		printk(KERN_ERR "%s: Error in command line!  " "Usage: wd7000=<IRQ>,<DMA>,IO>[,<BUS_ON>" "[,<BUS_OFF>]]\n", __FUNCTION__);
+	} else {
+		for (i = 0; i < NUM_IRQS; i++)
+			if (ints[1] == wd7000_irq[i])
+				break;
+
+		if (i == NUM_IRQS) {
+			setup_error("invalid IRQ.", ints);
+			return 0;
+		} else
+			configs[wd7000_card_num].irq = ints[1];
+
+		for (i = 0; i < NUM_DMAS; i++)
+			if (ints[2] == wd7000_dma[i])
+				break;
+
+		if (i == NUM_DMAS) {
+			setup_error("invalid DMA channel.", ints);
+			return 0;
+		} else
+			configs[wd7000_card_num].dma = ints[2];
+
+		for (i = 0; i < NUM_IOPORTS; i++)
+			if (ints[3] == wd7000_iobase[i])
+				break;
+
+		if (i == NUM_IOPORTS) {
+			setup_error("invalid I/O base address.", ints);
+			return 0;
+		} else
+			configs[wd7000_card_num].iobase = ints[3];
+
+		if (ints[0] > 3) {
+			if ((ints[4] < 500) || (ints[4] > 31875)) {
+				setup_error("BUS_ON value is out of range (500" " to 31875 nanoseconds)!", ints);
+				configs[wd7000_card_num].bus_on = BUS_ON;
+			} else
+				configs[wd7000_card_num].bus_on = ints[4] / 125;
+		} else
+			configs[wd7000_card_num].bus_on = BUS_ON;
+
+		if (ints[0] > 4) {
+			if ((ints[5] < 500) || (ints[5] > 31875)) {
+				setup_error("BUS_OFF value is out of range (500" " to 31875 nanoseconds)!", ints);
+				configs[wd7000_card_num].bus_off = BUS_OFF;
+			} else
+				configs[wd7000_card_num].bus_off = ints[5] / 125;
+		} else
+			configs[wd7000_card_num].bus_off = BUS_OFF;
+
+		if (wd7000_card_num) {
+			for (i = 0; i < (wd7000_card_num - 1); i++) {
+				int j = i + 1;
+
+				for (; j < wd7000_card_num; j++)
+					if (configs[i].irq == configs[j].irq) {
+						setup_error("duplicated IRQ!", ints);
+						return 0;
+					}
+				if (configs[i].dma == configs[j].dma) {
+					setup_error("duplicated DMA " "channel!", ints);
+					return 0;
+				}
+				if (configs[i].iobase == configs[j].iobase) {
+					setup_error("duplicated I/O " "base address!", ints);
+					return 0;
+				}
+			}
+		}
+
+		dprintk(KERN_DEBUG "wd7000_setup: IRQ=%d, DMA=%d, I/O=0x%x, "
+			"BUS_ON=%dns, BUS_OFF=%dns\n", configs[wd7000_card_num].irq, configs[wd7000_card_num].dma, configs[wd7000_card_num].iobase, configs[wd7000_card_num].bus_on * 125, configs[wd7000_card_num].bus_off * 125);
+
+		wd7000_card_num++;
+	}
+	return 1;
+}
+
+__setup("wd7000=", wd7000_setup);
+
+static inline void any2scsi(unchar * scsi, int any)
+{
+	*scsi++ = (unsigned)any >> 16;
+	*scsi++ = (unsigned)any >> 8;
+	*scsi++ = any;
+}
+
+static inline int scsi2int(unchar * scsi)
+{
+	return (scsi[0] << 16) | (scsi[1] << 8) | scsi[2];
+}
+
+static inline void wd7000_enable_intr(Adapter * host)
+{
+	host->control |= INT_EN;
+	outb(host->control, host->iobase + ASC_CONTROL);
+}
+
+
+static inline void wd7000_enable_dma(Adapter * host)
+{
+	unsigned long flags;
+	host->control |= DMA_EN;
+	outb(host->control, host->iobase + ASC_CONTROL);
+
+	flags = claim_dma_lock();
+	set_dma_mode(host->dma, DMA_MODE_CASCADE);
+	enable_dma(host->dma);
+	release_dma_lock(flags);
+
+}
+
+
+#define WAITnexttimeout 200	/* 2 seconds */
+
+static inline short WAIT(unsigned port, unsigned mask, unsigned allof, unsigned noneof)
+{
+	unsigned WAITbits;
+	unsigned long WAITtimeout = jiffies + WAITnexttimeout;
+
+	while (time_before_eq(jiffies, WAITtimeout)) {
+		WAITbits = inb(port) & mask;
+
+		if (((WAITbits & allof) == allof) && ((WAITbits & noneof) == 0))
+			return (0);
+	}
+
+	return (1);
+}
+
+
+static inline int command_out(Adapter * host, unchar * cmd, int len)
+{
+	if (!WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		while (len--) {
+			do {
+				outb(*cmd, host->iobase + ASC_COMMAND);
+				WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
+			} while (inb(host->iobase + ASC_STAT) & CMD_REJ);
+
+			cmd++;
+		}
+
+		return (1);
+	}
+
+	printk(KERN_WARNING "wd7000 command_out: WAIT failed(%d)\n", len + 1);
+
+	return (0);
+}
+
+
+/*
+ *  This version of alloc_scbs is in preparation for supporting multiple
+ *  commands per lun and command chaining, by queueing pending commands.
+ *  We will need to allocate Scbs in blocks since they will wait to be
+ *  executed so there is the possibility of deadlock otherwise.
+ *  Also, to keep larger requests from being starved by smaller requests,
+ *  we limit access to this routine with an internal busy flag, so that
+ *  the satisfiability of a request is not dependent on the size of the
+ *  request.
+ */
+static inline Scb *alloc_scbs(struct Scsi_Host *host, int needed)
+{
+	Scb *scb, *p = NULL;
+	unsigned long flags;
+	unsigned long timeout = jiffies + WAITnexttimeout;
+	unsigned long now;
+	int i;
+
+	if (needed <= 0)
+		return (NULL);	/* sanity check */
+
+	spin_unlock_irq(host->host_lock);
+
+      retry:
+	while (freescbs < needed) {
+		timeout = jiffies + WAITnexttimeout;
+		do {
+			/* FIXME: can we actually just yield here ?? */
+			for (now = jiffies; now == jiffies;)
+				cpu_relax();	/* wait a jiffy */
+		} while (freescbs < needed && time_before_eq(jiffies, timeout));
+		/*
+		 *  If we get here with enough free Scbs, we can take them.
+		 *  Otherwise, we timed out and didn't get enough.
+		 */
+		if (freescbs < needed) {
+			printk(KERN_ERR "wd7000: can't get enough free SCBs.\n");
+			return (NULL);
+		}
+	}
+
+	/* Take the lock, then check we didnt get beaten, if so try again */
+	spin_lock_irqsave(&scbpool_lock, flags);
+	if (freescbs < needed) {
+		spin_unlock_irqrestore(&scbpool_lock, flags);
+		goto retry;
+	}
+
+	scb = scbfree;
+	freescbs -= needed;
+	for (i = 0; i < needed; i++) {
+		p = scbfree;
+		scbfree = p->next;
+	}
+	p->next = NULL;
+
+	spin_unlock_irqrestore(&scbpool_lock, flags);
+
+	spin_lock_irq(host->host_lock);
+	return (scb);
+}
+
+
+static inline void free_scb(Scb * scb)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&scbpool_lock, flags);
+
+	memset(scb, 0, sizeof(Scb));
+	scb->next = scbfree;
+	scbfree = scb;
+	freescbs++;
+
+	spin_unlock_irqrestore(&scbpool_lock, flags);
+}
+
+
+static inline void init_scbs(void)
+{
+	int i;
+
+	spin_lock_init(&scbpool_lock);
+
+	/* This is only ever called before the SCB pool is active */
+
+	scbfree = &(scbs[0]);
+	memset(scbs, 0, sizeof(scbs));
+	for (i = 0; i < MAX_SCBS - 1; i++) {
+		scbs[i].next = &(scbs[i + 1]);
+		scbs[i].SCpnt = NULL;
+	}
+	scbs[MAX_SCBS - 1].next = NULL;
+	scbs[MAX_SCBS - 1].SCpnt = NULL;
+}
+
+
+static int mail_out(Adapter * host, Scb * scbptr)
+/*
+ *  Note: this can also be used for ICBs; just cast to the parm type.
+ */
+{
+	int i, ogmb;
+	unsigned long flags;
+	unchar start_ogmb;
+	Mailbox *ogmbs = host->mb.ogmb;
+	int *next_ogmb = &(host->next_ogmb);
+
+	dprintk("wd7000_mail_out: 0x%06lx", (long) scbptr);
+
+	/* We first look for a free outgoing mailbox */
+	spin_lock_irqsave(host->sh->host_lock, flags);
+	ogmb = *next_ogmb;
+	for (i = 0; i < OGMB_CNT; i++) {
+		if (ogmbs[ogmb].status == 0) {
+			dprintk(" using OGMB 0x%x", ogmb);
+			ogmbs[ogmb].status = 1;
+			any2scsi((unchar *) ogmbs[ogmb].scbptr, (int) scbptr);
+
+			*next_ogmb = (ogmb + 1) % OGMB_CNT;
+			break;
+		} else
+			ogmb = (ogmb + 1) % OGMB_CNT;
+	}
+	spin_unlock_irqrestore(host->sh->host_lock, flags);
+
+	dprintk(", scb is 0x%06lx", (long) scbptr);
+
+	if (i >= OGMB_CNT) {
+		/*
+		 *  Alternatively, we might issue the "interrupt on free OGMB",
+		 *  and sleep, but it must be ensured that it isn't the init
+		 *  task running.  Instead, this version assumes that the caller
+		 *  will be persistent, and try again.  Since it's the adapter
+		 *  that marks OGMB's free, waiting even with interrupts off
+		 *  should work, since they are freed very quickly in most cases.
+		 */
+		dprintk(", no free OGMBs.\n");
+		return (0);
+	}
+
+	wd7000_enable_intr(host);
+
+	start_ogmb = START_OGMB | ogmb;
+	command_out(host, &start_ogmb, 1);
+
+	dprintk(", awaiting interrupt.\n");
+
+	return (1);
+}
+
+
+static int make_code(unsigned hosterr, unsigned scsierr)
+{
+#ifdef WD7000_DEBUG
+	int in_error = hosterr;
+#endif
+
+	switch ((hosterr >> 8) & 0xff) {
+	case 0:		/* Reserved */
+		hosterr = DID_ERROR;
+		break;
+	case 1:		/* Command Complete, no errors */
+		hosterr = DID_OK;
+		break;
+	case 2:		/* Command complete, error logged in scb status (scsierr) */
+		hosterr = DID_OK;
+		break;
+	case 4:		/* Command failed to complete - timeout */
+		hosterr = DID_TIME_OUT;
+		break;
+	case 5:		/* Command terminated; Bus reset by external device */
+		hosterr = DID_RESET;
+		break;
+	case 6:		/* Unexpected Command Received w/ host as target */
+		hosterr = DID_BAD_TARGET;
+		break;
+	case 80:		/* Unexpected Reselection */
+	case 81:		/* Unexpected Selection */
+		hosterr = DID_BAD_INTR;
+		break;
+	case 82:		/* Abort Command Message  */
+		hosterr = DID_ABORT;
+		break;
+	case 83:		/* SCSI Bus Software Reset */
+	case 84:		/* SCSI Bus Hardware Reset */
+		hosterr = DID_RESET;
+		break;
+	default:		/* Reserved */
+		hosterr = DID_ERROR;
+	}
+#ifdef WD7000_DEBUG
+	if (scsierr || hosterr)
+		dprintk("\nSCSI command error: SCSI 0x%02x host 0x%04x return %d\n", scsierr, in_error, hosterr);
+#endif
+	return (scsierr | (hosterr << 16));
+}
+
+#define wd7000_intr_ack(host)   outb (0, host->iobase + ASC_INTR_ACK)
+
+
+static irqreturn_t wd7000_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	Adapter *host = (Adapter *) dev_id;
+	int flag, icmb, errstatus, icmb_status;
+	int host_error, scsi_error;
+	Scb *scb;	/* for SCSI commands */
+	IcbAny *icb;	/* for host commands */
+	struct scsi_cmnd *SCpnt;
+	Mailbox *icmbs = host->mb.icmb;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->sh->host_lock, flags);
+	host->int_counter++;
+
+	dprintk("wd7000_intr: irq = %d, host = 0x%06lx\n", irq, (long) host);
+
+	flag = inb(host->iobase + ASC_INTR_STAT);
+
+	dprintk("wd7000_intr: intr stat = 0x%02x\n", flag);
+
+	if (!(inb(host->iobase + ASC_STAT) & INT_IM)) {
+		/* NB: these are _very_ possible if IRQ 15 is being used, since
+		 * it's the "garbage collector" on the 2nd 8259 PIC.  Specifically,
+		 * any interrupt signal into the 8259 which can't be identified
+		 * comes out as 7 from the 8259, which is 15 to the host.  Thus, it
+		 * is a good thing the WD7000 has an interrupt status port, so we
+		 * can sort these out.  Otherwise, electrical noise and other such
+		 * problems would be indistinguishable from valid interrupts...
+		 */
+		dprintk("wd7000_intr: phantom interrupt...\n");
+		goto ack;
+	}
+
+	if (!(flag & MB_INTR))
+		goto ack;
+
+	/* The interrupt is for a mailbox */
+	if (!(flag & IMB_INTR)) {
+		dprintk("wd7000_intr: free outgoing mailbox\n");
+		/*
+		 * If sleep_on() and the "interrupt on free OGMB" command are
+		 * used in mail_out(), wake_up() should correspondingly be called
+		 * here.  For now, we don't need to do anything special.
+		 */
+		goto ack;
+	}
+
+	/* The interrupt is for an incoming mailbox */
+	icmb = flag & MB_MASK;
+	icmb_status = icmbs[icmb].status;
+	if (icmb_status & 0x80) {	/* unsolicited - result in ICMB */
+		dprintk("wd7000_intr: unsolicited interrupt 0x%02x\n", icmb_status);
+		goto ack;
+	}
+
+	/* Aaaargh! (Zaga) */
+	scb = isa_bus_to_virt(scsi2int((unchar *) icmbs[icmb].scbptr));
+	icmbs[icmb].status = 0;
+	if (scb->op & ICB_OP_MASK) {	/* an SCB is done */
+		icb = (IcbAny *) scb;
+		icb->status = icmb_status;
+		icb->phase = 0;
+		goto ack;
+	}
+
+	SCpnt = scb->SCpnt;
+	if (--(SCpnt->SCp.phase) <= 0) {	/* all scbs are done */
+		host_error = scb->vue | (icmb_status << 8);
+		scsi_error = scb->status;
+		errstatus = make_code(host_error, scsi_error);
+		SCpnt->result = errstatus;
+
+		free_scb(scb);
+
+		SCpnt->scsi_done(SCpnt);
+	}
+
+ ack:
+	dprintk("wd7000_intr: return from interrupt handler\n");
+	wd7000_intr_ack(host);
+
+	spin_unlock_irqrestore(host->sh->host_lock, flags);
+	return IRQ_HANDLED;
+}
+
+static int wd7000_queuecommand(struct scsi_cmnd *SCpnt,
+		void (*done)(struct scsi_cmnd *))
+{
+	Scb *scb;
+	Sgb *sgb;
+	unchar *cdb = (unchar *) SCpnt->cmnd;
+	unchar idlun;
+	short cdblen;
+	Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+
+	cdblen = SCpnt->cmd_len;
+	idlun = ((SCpnt->device->id << 5) & 0xe0) | (SCpnt->device->lun & 7);
+	SCpnt->scsi_done = done;
+	SCpnt->SCp.phase = 1;
+	scb = alloc_scbs(SCpnt->device->host, 1);
+	scb->idlun = idlun;
+	memcpy(scb->cdb, cdb, cdblen);
+	scb->direc = 0x40;	/* Disable direction check */
+
+	scb->SCpnt = SCpnt;	/* so we can find stuff later */
+	SCpnt->host_scribble = (unchar *) scb;
+	scb->host = host;
+
+	if (SCpnt->use_sg) {
+		struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+		unsigned i;
+
+		if (SCpnt->device->host->sg_tablesize == SG_NONE) {
+			panic("wd7000_queuecommand: scatter/gather not supported.\n");
+		}
+		dprintk("Using scatter/gather with %d elements.\n", SCpnt->use_sg);
+
+		sgb = scb->sgb;
+		scb->op = 1;
+		any2scsi(scb->dataptr, (int) sgb);
+		any2scsi(scb->maxlen, SCpnt->use_sg * sizeof(Sgb));
+
+		for (i = 0; i < SCpnt->use_sg; i++) {
+			any2scsi(sgb[i].ptr, isa_page_to_bus(sg[i].page) + sg[i].offset);
+			any2scsi(sgb[i].len, sg[i].length);
+		}
+	} else {
+		scb->op = 0;
+		any2scsi(scb->dataptr, isa_virt_to_bus(SCpnt->request_buffer));
+		any2scsi(scb->maxlen, SCpnt->request_bufflen);
+	}
+
+	/* FIXME: drop lock and yield here ? */
+
+	while (!mail_out(host, scb))
+		cpu_relax();	/* keep trying */
+
+	return 0;
+}
+
+static int wd7000_diagnostics(Adapter * host, int code)
+{
+	static IcbDiag icb = { ICB_OP_DIAGNOSTICS };
+	static unchar buf[256];
+	unsigned long timeout;
+
+	icb.type = code;
+	any2scsi(icb.len, sizeof(buf));
+	any2scsi(icb.ptr, (int) &buf);
+	icb.phase = 1;
+	/*
+	 * This routine is only called at init, so there should be OGMBs
+	 * available.  I'm assuming so here.  If this is going to
+	 * fail, I can just let the timeout catch the failure.
+	 */
+	mail_out(host, (struct scb *) &icb);
+	timeout = jiffies + WAITnexttimeout;	/* wait up to 2 seconds */
+	while (icb.phase && time_before(jiffies, timeout)) {
+		cpu_relax();	/* wait for completion */
+		barrier();
+	}
+
+	if (icb.phase) {
+		printk("wd7000_diagnostics: timed out.\n");
+		return (0);
+	}
+	if (make_code(icb.vue | (icb.status << 8), 0)) {
+		printk("wd7000_diagnostics: failed (0x%02x,0x%02x)\n", icb.vue, icb.status);
+		return (0);
+	}
+
+	return (1);
+}
+
+
+static int wd7000_adapter_reset(Adapter * host)
+{
+	InitCmd init_cmd = {
+		INITIALIZATION,
+		7,
+		host->bus_on,
+		host->bus_off,
+		0,
+		{0, 0, 0},
+		OGMB_CNT,
+		ICMB_CNT
+	};
+	int diag;
+	/*
+	 *  Reset the adapter - only.  The SCSI bus was initialized at power-up,
+	 *  and we need to do this just so we control the mailboxes, etc.
+	 */
+	outb(ASC_RES, host->iobase + ASC_CONTROL);
+	udelay(40);		/* reset pulse: this is 40us, only need 25us */
+	outb(0, host->iobase + ASC_CONTROL);
+	host->control = 0;	/* this must always shadow ASC_CONTROL */
+
+	if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+		printk(KERN_ERR "wd7000_init: WAIT timed out.\n");
+		return -1;	/* -1 = not ok */
+	}
+
+	if ((diag = inb(host->iobase + ASC_INTR_STAT)) != 1) {
+		printk("wd7000_init: ");
+
+		switch (diag) {
+		case 2:
+			printk(KERN_ERR "RAM failure.\n");
+			break;
+		case 3:
+			printk(KERN_ERR "FIFO R/W failed\n");
+			break;
+		case 4:
+			printk(KERN_ERR "SBIC register R/W failed\n");
+			break;
+		case 5:
+			printk(KERN_ERR "Initialization D-FF failed.\n");
+			break;
+		case 6:
+			printk(KERN_ERR "Host IRQ D-FF failed.\n");
+			break;
+		case 7:
+			printk(KERN_ERR "ROM checksum error.\n");
+			break;
+		default:
+			printk(KERN_ERR "diagnostic code 0x%02Xh received.\n", diag);
+		}
+		return -1;
+	}
+	/* Clear mailboxes */
+	memset(&(host->mb), 0, sizeof(host->mb));
+
+	/* Execute init command */
+	any2scsi((unchar *) & (init_cmd.mailboxes), (int) &(host->mb));
+	if (!command_out(host, (unchar *) & init_cmd, sizeof(init_cmd))) {
+		printk(KERN_ERR "wd7000_adapter_reset: adapter initialization failed.\n");
+		return -1;
+	}
+
+	if (WAIT(host->iobase + ASC_STAT, ASC_STATMASK, ASC_INIT, 0)) {
+		printk("wd7000_adapter_reset: WAIT timed out.\n");
+		return -1;
+	}
+	return 0;
+}
+
+static int wd7000_init(Adapter * host)
+{
+	if (wd7000_adapter_reset(host) == -1)
+		return 0;
+
+
+	if (request_irq(host->irq, wd7000_intr, SA_INTERRUPT, "wd7000", host)) {
+		printk("wd7000_init: can't get IRQ %d.\n", host->irq);
+		return (0);
+	}
+	if (request_dma(host->dma, "wd7000")) {
+		printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
+		free_irq(host->irq, host);
+		return (0);
+	}
+	wd7000_enable_dma(host);
+	wd7000_enable_intr(host);
+
+	if (!wd7000_diagnostics(host, ICB_DIAG_FULL)) {
+		free_dma(host->dma);
+		free_irq(host->irq, NULL);
+		return (0);
+	}
+
+	return (1);
+}
+
+
+static void wd7000_revision(Adapter * host)
+{
+	static IcbRevLvl icb = { ICB_OP_GET_REVISION };
+
+	icb.phase = 1;
+	/*
+	 * Like diagnostics, this is only done at init time, in fact, from
+	 * wd7000_detect, so there should be OGMBs available.  If it fails,
+	 * the only damage will be that the revision will show up as 0.0,
+	 * which in turn means that scatter/gather will be disabled.
+	 */
+	mail_out(host, (struct scb *) &icb);
+	while (icb.phase) {
+		cpu_relax();	/* wait for completion */
+		barrier();
+	}
+	host->rev1 = icb.primary;
+	host->rev2 = icb.secondary;
+}
+
+
+#undef SPRINTF
+#define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); }
+
+static int wd7000_set_info(char *buffer, int length, struct Scsi_Host *host)
+{
+	dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
+
+	/*
+	 * Currently this is a no-op
+	 */
+	dprintk("Sorry, this function is currently out of order...\n");
+	return (length);
+}
+
+
+static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length,  int inout)
+{
+	Adapter *adapter = (Adapter *)host->hostdata;
+	unsigned long flags;
+	char *pos = buffer;
+#ifdef WD7000_DEBUG
+	Mailbox *ogmbs, *icmbs;
+	short count;
+#endif
+
+	/*
+	 * Has data been written to the file ?
+	 */
+	if (inout)
+		return (wd7000_set_info(buffer, length, host));
+
+	spin_lock_irqsave(host->host_lock, flags);
+	SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
+	SPRINTF("  IO base:      0x%x\n", adapter->iobase);
+	SPRINTF("  IRQ:          %d\n", adapter->irq);
+	SPRINTF("  DMA channel:  %d\n", adapter->dma);
+	SPRINTF("  Interrupts:   %d\n", adapter->int_counter);
+	SPRINTF("  BUS_ON time:  %d nanoseconds\n", adapter->bus_on * 125);
+	SPRINTF("  BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
+
+#ifdef WD7000_DEBUG
+	ogmbs = adapter->mb.ogmb;
+	icmbs = adapter->mb.icmb;
+
+	SPRINTF("\nControl port value: 0x%x\n", adapter->control);
+	SPRINTF("Incoming mailbox:\n");
+	SPRINTF("  size: %d\n", ICMB_CNT);
+	SPRINTF("  queued messages: ");
+
+	for (i = count = 0; i < ICMB_CNT; i++)
+		if (icmbs[i].status) {
+			count++;
+			SPRINTF("0x%x ", i);
+		}
+
+	SPRINTF(count ? "\n" : "none\n");
+
+	SPRINTF("Outgoing mailbox:\n");
+	SPRINTF("  size: %d\n", OGMB_CNT);
+	SPRINTF("  next message: 0x%x\n", adapter->next_ogmb);
+	SPRINTF("  queued messages: ");
+
+	for (i = count = 0; i < OGMB_CNT; i++)
+		if (ogmbs[i].status) {
+			count++;
+			SPRINTF("0x%x ", i);
+		}
+
+	SPRINTF(count ? "\n" : "none\n");
+#endif
+
+	spin_unlock_irqrestore(host->host_lock, flags);
+
+	/*
+	 * Calculate start of next buffer, and return value.
+	 */
+	*start = buffer + offset;
+
+	if ((pos - buffer) < offset)
+		return (0);
+	else if ((pos - buffer - offset) < length)
+		return (pos - buffer - offset);
+	else
+		return (length);
+}
+
+
+/*
+ *  Returns the number of adapters this driver is supporting.
+ *
+ *  The source for hosts.c says to wait to call scsi_register until 100%
+ *  sure about an adapter.  We need to do it a little sooner here; we
+ *  need the storage set up by scsi_register before wd7000_init, and
+ *  changing the location of an Adapter structure is more trouble than
+ *  calling scsi_unregister.
+ *
+ */
+
+static int wd7000_detect(struct scsi_host_template *tpnt)
+{
+	short present = 0, biosaddr_ptr, sig_ptr, i, pass;
+	short biosptr[NUM_CONFIGS];
+	unsigned iobase;
+	Adapter *host = NULL;
+	struct Scsi_Host *sh;
+	int unit = 0;
+
+	dprintk("wd7000_detect: started\n");
+
+#ifdef MODULE
+	if (wd7000)
+		wd7000_setup(wd7000);
+#endif
+
+	for (i = 0; i < UNITS; wd7000_host[i++] = NULL);
+	for (i = 0; i < NUM_CONFIGS; biosptr[i++] = -1);
+
+	tpnt->proc_name = "wd7000";
+	tpnt->proc_info = &wd7000_proc_info;
+
+	/*
+	 * Set up SCB free list, which is shared by all adapters
+	 */
+	init_scbs();
+
+	for (pass = 0; pass < NUM_CONFIGS; pass++) {
+		/*
+		 * First, search for BIOS SIGNATURE...
+		 */
+		for (biosaddr_ptr = 0; biosaddr_ptr < NUM_ADDRS; biosaddr_ptr++)
+			for (sig_ptr = 0; sig_ptr < NUM_SIGNATURES; sig_ptr++) {
+				for (i = 0; i < pass; i++)
+					if (biosptr[i] == biosaddr_ptr)
+						break;
+
+				if (i == pass) {
+					void __iomem *biosaddr = ioremap(wd7000_biosaddr[biosaddr_ptr] + signatures[sig_ptr].ofs,
+								 signatures[sig_ptr].len);
+					short bios_match = 1;
+
+					if (biosaddr)
+						bios_match = check_signature(biosaddr, signatures[sig_ptr].sig, signatures[sig_ptr].len);
+
+					iounmap(biosaddr);
+
+					if (bios_match)
+						goto bios_matched;
+				}
+			}
+
+	      bios_matched:
+		/*
+		 * BIOS SIGNATURE has been found.
+		 */
+#ifdef WD7000_DEBUG
+		dprintk("wd7000_detect: pass %d\n", pass + 1);
+
+		if (biosaddr_ptr == NUM_ADDRS)
+			dprintk("WD-7000 SST BIOS not detected...\n");
+		else
+			dprintk("WD-7000 SST BIOS detected at 0x%lx: checking...\n", wd7000_biosaddr[biosaddr_ptr]);
+#endif
+
+		if (configs[pass].irq < 0)
+			continue;
+
+		if (unit == UNITS)
+			continue;
+
+		iobase = configs[pass].iobase;
+
+		dprintk("wd7000_detect: check IO 0x%x region...\n", iobase);
+
+		if (request_region(iobase, 4, "wd7000")) {
+
+			dprintk("wd7000_detect: ASC reset (IO 0x%x) ...", iobase);
+			/*
+			 * ASC reset...
+			 */
+			outb(ASC_RES, iobase + ASC_CONTROL);
+			msleep(10);
+			outb(0, iobase + ASC_CONTROL);
+
+			if (WAIT(iobase + ASC_STAT, ASC_STATMASK, CMD_RDY, 0)) {
+				dprintk("failed!\n");
+				goto err_release;
+			} else
+				dprintk("ok!\n");
+
+			if (inb(iobase + ASC_INTR_STAT) == 1) {
+				/*
+				 *  We register here, to get a pointer to the extra space,
+				 *  which we'll use as the Adapter structure (host) for
+				 *  this adapter.  It is located just after the registered
+				 *  Scsi_Host structure (sh), and is located by the empty
+				 *  array hostdata.
+				 */
+				sh = scsi_register(tpnt, sizeof(Adapter));
+				if (sh == NULL)
+					goto err_release;
+
+				host = (Adapter *) sh->hostdata;
+
+				dprintk("wd7000_detect: adapter allocated at 0x%x\n", (int) host);
+				memset(host, 0, sizeof(Adapter));
+
+				host->irq = configs[pass].irq;
+				host->dma = configs[pass].dma;
+				host->iobase = iobase;
+				host->int_counter = 0;
+				host->bus_on = configs[pass].bus_on;
+				host->bus_off = configs[pass].bus_off;
+				host->sh = wd7000_host[unit] = sh;
+				unit++;
+
+				dprintk("wd7000_detect: Trying init WD-7000 card at IO " "0x%x, IRQ %d, DMA %d...\n", host->iobase, host->irq, host->dma);
+
+				if (!wd7000_init(host))	/* Initialization failed */
+					goto err_unregister;
+
+				/*
+				 *  OK from here - we'll use this adapter/configuration.
+				 */
+				wd7000_revision(host);	/* important for scatter/gather */
+
+				/*
+				 *  For boards before rev 6.0, scatter/gather isn't supported.
+				 */
+				if (host->rev1 < 6)
+					sh->sg_tablesize = SG_NONE;
+
+				present++;	/* count it */
+
+				if (biosaddr_ptr != NUM_ADDRS)
+					biosptr[pass] = biosaddr_ptr;
+
+				printk(KERN_INFO "Western Digital WD-7000 (rev %d.%d) ", host->rev1, host->rev2);
+				printk("using IO 0x%x, IRQ %d, DMA %d.\n", host->iobase, host->irq, host->dma);
+				printk("  BUS_ON time: %dns, BUS_OFF time: %dns\n", host->bus_on * 125, host->bus_off * 125);
+			}
+		} else
+			dprintk("wd7000_detect: IO 0x%x region already allocated!\n", iobase);
+
+		continue;
+
+	      err_unregister:
+		scsi_unregister(sh);
+	      err_release:
+		release_region(iobase, 4);
+
+	}
+
+	if (!present)
+		printk("Failed initialization of WD-7000 SCSI card!\n");
+
+	return (present);
+}
+
+static int wd7000_release(struct Scsi_Host *shost)
+{
+	if (shost->irq)
+		free_irq(shost->irq, NULL);
+	if (shost->io_port && shost->n_io_port)
+		release_region(shost->io_port, shost->n_io_port);
+	scsi_unregister(shost);
+	return 0;
+}
+
+#if 0
+/*
+ *  I have absolutely NO idea how to do an abort with the WD7000...
+ */
+static int wd7000_abort(Scsi_Cmnd * SCpnt)
+{
+	Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+
+	if (inb(host->iobase + ASC_STAT) & INT_IM) {
+		printk("wd7000_abort: lost interrupt\n");
+		wd7000_intr_handle(host->irq, NULL, NULL);
+		return FAILED;
+	}
+	return FAILED;
+}
+#endif
+
+/*
+ *  Last resort. Reinitialize the board.
+ */
+
+static int wd7000_host_reset(struct scsi_cmnd *SCpnt)
+{
+	Adapter *host = (Adapter *) SCpnt->device->host->hostdata;
+
+	if (wd7000_adapter_reset(host) < 0)
+		return FAILED;
+	wd7000_enable_intr(host);
+	return SUCCESS;
+}
+
+/*
+ *  This was borrowed directly from aha1542.c. (Zaga)
+ */
+
+static int wd7000_biosparam(struct scsi_device *sdev,
+		struct block_device *bdev, sector_t capacity, int *ip)
+{
+	char b[BDEVNAME_SIZE];
+
+	dprintk("wd7000_biosparam: dev=%s, size=%d, ",
+		bdevname(bdev, b), capacity);
+	(void)b;	/* unused var warning? */
+
+	/*
+	 * try default translation
+	 */
+	ip[0] = 64;
+	ip[1] = 32;
+	ip[2] = capacity >> 11;
+
+	/*
+	 * for disks >1GB do some guessing
+	 */
+	if (ip[2] >= 1024) {
+		int info[3];
+
+		/*
+		 * try to figure out the geometry from the partition table
+		 */
+		if ((scsicam_bios_param(bdev, capacity, info) < 0) || !(((info[0] == 64) && (info[1] == 32)) || ((info[0] == 255) && (info[1] == 63)))) {
+			printk("wd7000_biosparam: unable to verify geometry for disk with >1GB.\n" "                  using extended translation.\n");
+
+			ip[0] = 255;
+			ip[1] = 63;
+			ip[2] = (unsigned long) capacity / (255 * 63);
+		} else {
+			ip[0] = info[0];
+			ip[1] = info[1];
+			ip[2] = info[2];
+
+			if (info[0] == 255)
+				printk(KERN_INFO "%s: current partition table is " "using extended translation.\n", __FUNCTION__);
+		}
+	}
+
+	dprintk("bios geometry: head=%d, sec=%d, cyl=%d\n", ip[0], ip[1], ip[2]);
+	dprintk("WARNING: check, if the bios geometry is correct.\n");
+
+	return (0);
+}
+
+MODULE_AUTHOR("Thomas Wuensche, John Boyd, Miroslav Zagorac");
+MODULE_DESCRIPTION("Driver for the WD7000 series ISA controllers");
+MODULE_LICENSE("GPL");
+
+static struct scsi_host_template driver_template = {
+	.proc_name		= "wd7000",
+	.proc_info		= wd7000_proc_info,
+	.name			= "Western Digital WD-7000",
+	.detect			= wd7000_detect,
+	.release		= wd7000_release,
+	.queuecommand		= wd7000_queuecommand,
+	.eh_host_reset_handler	= wd7000_host_reset,
+	.bios_param		= wd7000_biosparam,
+	.can_queue		= WD7000_Q,
+	.this_id		= 7,
+	.sg_tablesize		= WD7000_SG,
+	.cmd_per_lun		= 1,
+	.unchecked_isa_dma	= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
+
+#include "scsi_module.c"
diff --git a/drivers/scsi/zalon.c b/drivers/scsi/zalon.c
new file mode 100644
index 0000000..5a51051
--- /dev/null
+++ b/drivers/scsi/zalon.c
@@ -0,0 +1,205 @@
+/*
+ * Zalon 53c7xx device driver.
+ * By Richard Hirst (rhirst@linuxcare.com)
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include "../parisc/gsc.h"
+
+#include "ncr53c8xx.h"
+
+MODULE_AUTHOR("Richard Hirst");
+MODULE_DESCRIPTION("Bluefish/Zalon 720 SCSI Driver");
+MODULE_LICENSE("GPL");
+
+#define GSC_SCSI_ZALON_OFFSET 0x800
+
+#define IO_MODULE_EIM		(1*4)
+#define IO_MODULE_DC_ADATA	(2*4)
+#define IO_MODULE_II_CDATA	(3*4)
+#define IO_MODULE_IO_COMMAND	(12*4)
+#define IO_MODULE_IO_STATUS	(13*4)
+
+#define IOSTATUS_RY		0x40
+#define IOSTATUS_FE		0x80
+#define IOIIDATA_SMINT5L	0x40000000
+#define IOIIDATA_MINT5EN	0x20000000
+#define IOIIDATA_PACKEN		0x10000000
+#define IOIIDATA_PREFETCHEN	0x08000000
+#define IOIIDATA_IOII		0x00000020
+
+#define CMD_RESET		5
+
+static struct ncr_chip zalon720_chip __initdata = {
+	.revision_id =	0x0f,
+	.burst_max =	3,
+	.offset_max =	8,
+	.nr_divisor =	4,
+	.features =	FE_WIDE | FE_DIFF | FE_EHP| FE_MUX | FE_EA,
+};
+
+
+
+#if 0
+/* FIXME:
+ * Is this function dead code? or is someone planning on using it in the
+ * future.  The clock = (int) pdc_result[16] does not look correct to
+ * me ... I think it should be iodc_data[16].  Since this cause a compile
+ * error with the new encapsulated PDC, I'm not compiling in this function.
+ * - RB
+ */
+/* poke SCSI clock out of iodc data */
+
+static u8 iodc_data[32] __attribute__ ((aligned (64)));
+static unsigned long pdc_result[32] __attribute__ ((aligned (16))) ={0,0,0,0};
+
+static int 
+lasi_scsi_clock(void * hpa, int defaultclock)
+{
+	int clock, status;
+
+	status = pdc_iodc_read(&pdc_result, hpa, 0, &iodc_data, 32 );
+	if (status == PDC_RET_OK) {
+		clock = (int) pdc_result[16];
+	} else {
+		printk(KERN_WARNING "%s: pdc_iodc_read returned %d\n", __FUNCTION__, status);
+		clock = defaultclock; 
+	}
+
+	printk(KERN_DEBUG "%s: SCSI clock %d\n", __FUNCTION__, clock);
+ 	return clock;
+}
+#endif
+
+static struct scsi_host_template zalon7xx_template = {
+	.module		= THIS_MODULE,
+	.proc_name	= "zalon7xx",
+};
+
+static int __init
+zalon_probe(struct parisc_device *dev)
+{
+	struct gsc_irq gsc_irq;
+	u32 zalon_vers;
+	int error = -ENODEV;
+	void __iomem *zalon = ioremap(dev->hpa, 4096);
+	void __iomem *io_port = zalon + GSC_SCSI_ZALON_OFFSET;
+	static int unit = 0;
+	struct Scsi_Host *host;
+	struct ncr_device device;
+
+	__raw_writel(CMD_RESET, zalon + IO_MODULE_IO_COMMAND);
+	while (!(__raw_readl(zalon + IO_MODULE_IO_STATUS) & IOSTATUS_RY))
+		cpu_relax();
+	__raw_writel(IOIIDATA_MINT5EN | IOIIDATA_PACKEN | IOIIDATA_PREFETCHEN,
+		zalon + IO_MODULE_II_CDATA);
+
+	/* XXX: Save the Zalon version for bug workarounds? */
+	zalon_vers = (__raw_readl(zalon + IO_MODULE_II_CDATA) >> 24) & 0x07;
+
+	/* Setup the interrupts first.
+	** Later on request_irq() will register the handler.
+	*/
+	dev->irq = gsc_alloc_irq(&gsc_irq);
+
+	printk(KERN_INFO "%s: Zalon version %d, IRQ %d\n", __FUNCTION__,
+		zalon_vers, dev->irq);
+
+	__raw_writel(gsc_irq.txn_addr | gsc_irq.txn_data, zalon + IO_MODULE_EIM);
+
+	if (zalon_vers == 0)
+		printk(KERN_WARNING "%s: Zalon 1.1 or earlier\n", __FUNCTION__);
+
+	memset(&device, 0, sizeof(struct ncr_device));
+
+	/* The following three are needed before any other access. */
+	__raw_writeb(0x20, io_port + 0x38); /* DCNTL_REG,  EA  */
+	__raw_writeb(0x04, io_port + 0x1b); /* CTEST0_REG, EHP */
+	__raw_writeb(0x80, io_port + 0x22); /* CTEST4_REG, MUX */
+
+	/* Initialise ncr_device structure with items required by ncr_attach. */
+	device.chip		= zalon720_chip;
+	device.host_id		= 7;
+	device.dev		= &dev->dev;
+	device.slot.base	= dev->hpa + GSC_SCSI_ZALON_OFFSET;
+	device.slot.base_v	= io_port;
+	device.slot.irq		= dev->irq;
+	device.differential	= 2;
+
+	host = ncr_attach(&zalon7xx_template, unit, &device);
+	if (!host)
+		goto fail;
+
+	if (request_irq(dev->irq, ncr53c8xx_intr, SA_SHIRQ, "zalon", host)) {
+		printk(KERN_ERR "%s: irq problem with %d, detaching\n ",
+			dev->dev.bus_id, dev->irq);
+		goto fail;
+	}
+
+	unit++;
+
+	dev_set_drvdata(&dev->dev, host);
+
+	error = scsi_add_host(host, &dev->dev);
+	if (error)
+		goto fail_free_irq;
+
+	scsi_scan_host(host);
+	return 0;
+
+ fail_free_irq:
+	free_irq(dev->irq, host);
+ fail:
+	ncr53c8xx_release(host);
+	return error;
+}
+
+static struct parisc_device_id zalon_tbl[] = {
+	{ HPHW_A_DMA, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x00089 }, 
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(parisc, zalon_tbl);
+
+static int __exit zalon_remove(struct parisc_device *dev)
+{
+	struct Scsi_Host *host = dev_get_drvdata(&dev->dev);
+
+	scsi_remove_host(host);
+	ncr53c8xx_release(host);
+	free_irq(dev->irq, host);
+
+	return 0;
+}
+
+static struct parisc_driver zalon_driver = {
+	.name =		"zalon",
+	.id_table =	zalon_tbl,
+	.probe =	zalon_probe,
+	.remove =	__devexit_p(zalon_remove),
+};
+
+static int __init zalon7xx_init(void)
+{
+	int ret = ncr53c8xx_init();
+	if (!ret)
+		ret = register_parisc_driver(&zalon_driver);
+	if (ret)
+		ncr53c8xx_exit();
+	return ret;
+}
+
+static void __exit zalon7xx_exit(void)
+{
+	unregister_parisc_driver(&zalon_driver);
+	ncr53c8xx_exit();
+}
+
+module_init(zalon7xx_init);
+module_exit(zalon7xx_exit);